aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/acpi/Kconfig12
-rw-r--r--drivers/acpi/acpi_amba.c14
-rw-r--r--drivers/acpi/acpi_apd.c7
-rw-r--r--drivers/acpi/acpi_cmos_rtc.c5
-rw-r--r--drivers/acpi/acpi_configfs.c11
-rw-r--r--drivers/acpi/acpi_dbg.c5
-rw-r--r--drivers/acpi/acpi_lpit.c7
-rw-r--r--drivers/acpi/acpi_lpss.c120
-rw-r--r--drivers/acpi/acpi_memhotplug.c19
-rw-r--r--drivers/acpi/acpi_pad.c1
-rw-r--r--drivers/acpi/acpi_platform.c5
-rw-r--r--drivers/acpi/acpi_pnp.c5
-rw-r--r--drivers/acpi/acpi_processor.c5
-rw-r--r--drivers/acpi/acpi_video.c37
-rw-r--r--drivers/acpi/acpi_watchdog.c5
-rw-r--r--drivers/acpi/acpica/acevents.h3
-rw-r--r--drivers/acpi/acpica/acglobal.h1
-rw-r--r--drivers/acpi/acpica/acnamesp.h2
-rw-r--r--drivers/acpi/acpica/dsinit.c2
-rw-r--r--drivers/acpi/acpica/evgpe.c8
-rw-r--r--drivers/acpi/acpica/evgpeblk.c2
-rw-r--r--drivers/acpi/acpica/evxface.c2
-rw-r--r--drivers/acpi/acpica/evxfgpe.c2
-rw-r--r--drivers/acpi/acpica/exconfig.c18
-rw-r--r--drivers/acpi/acpica/nsaccess.c54
-rw-r--r--drivers/acpi/acpica/nseval.c190
-rw-r--r--drivers/acpi/acpica/nsinit.c49
-rw-r--r--drivers/acpi/acpica/nsload.c12
-rw-r--r--drivers/acpi/acpica/nsutils.c12
-rw-r--r--drivers/acpi/acpica/tbdata.c13
-rw-r--r--drivers/acpi/acpica/tbxfload.c7
-rw-r--r--drivers/acpi/acpica/utinit.c1
-rw-r--r--drivers/acpi/acpica/utxfinit.c18
-rw-r--r--drivers/acpi/apei/ghes.c2
-rw-r--r--drivers/acpi/arm64/gtdt.c5
-rw-r--r--drivers/acpi/bgrt.c5
-rw-r--r--drivers/acpi/blacklist.c4
-rw-r--r--drivers/acpi/device_pm.c165
-rw-r--r--drivers/acpi/dptf/int340x_thermal.c5
-rw-r--r--drivers/acpi/ec_sys.c3
-rw-r--r--drivers/acpi/internal.h7
-rw-r--r--drivers/acpi/ioapic.c5
-rw-r--r--drivers/acpi/irq.c31
-rw-r--r--drivers/acpi/nfit/core.c4
-rw-r--r--drivers/acpi/osl.c4
-rw-r--r--drivers/acpi/pci_mcfg.c13
-rw-r--r--drivers/acpi/pci_root.c12
-rw-r--r--drivers/acpi/pci_slot.c10
-rw-r--r--drivers/acpi/pmic/intel_pmic.c2
-rw-r--r--drivers/acpi/power.c135
-rw-r--r--drivers/acpi/pptt.c61
-rw-r--r--drivers/acpi/processor_idle.c1
-rw-r--r--drivers/acpi/property.c31
-rw-r--r--drivers/acpi/sleep.c22
-rw-r--r--drivers/acpi/spcr.c6
-rw-r--r--drivers/acpi/tables.c21
-rw-r--r--drivers/acpi/utils.c11
-rw-r--r--drivers/acpi/x86/apple.c5
-rw-r--r--drivers/acpi/x86/utils.c5
-rw-r--r--drivers/amba/bus.c5
-rw-r--r--drivers/amba/tegra-ahb.c4
-rw-r--r--drivers/android/binder.c173
-rw-r--r--drivers/android/binder_alloc.c44
-rw-r--r--drivers/android/binder_alloc.h22
-rw-r--r--drivers/ata/acard-ahci.c1
-rw-r--r--drivers/ata/ahci_seattle.c10
-rw-r--r--drivers/ata/ahci_st.c5
-rw-r--r--drivers/ata/ahci_sunxi.c47
-rw-r--r--drivers/ata/libahci.c1
-rw-r--r--drivers/ata/libata-core.c4
-rw-r--r--drivers/ata/libata-eh.c8
-rw-r--r--drivers/ata/pata_ixp4xx_cf.c6
-rw-r--r--drivers/ata/pata_of_platform.c5
-rw-r--r--drivers/ata/pata_palmld.c6
-rw-r--r--drivers/ata/pata_rb532_cf.c6
-rw-r--r--drivers/ata/pata_samsung_cf.c5
-rw-r--r--drivers/ata/pdc_adma.c1
-rw-r--r--drivers/ata/sata_nv.c2
-rw-r--r--drivers/ata/sata_qstor.c1
-rw-r--r--drivers/ata/sata_sil24.c1
-rw-r--r--drivers/atm/idt77252.c1
-rw-r--r--drivers/auxdisplay/Kconfig2
-rw-r--r--drivers/auxdisplay/cfag12864bfb.c5
-rw-r--r--drivers/auxdisplay/ht16k33.c4
-rw-r--r--drivers/base/arch_topology.c11
-rw-r--r--drivers/base/bus.c6
-rw-r--r--drivers/base/cacheinfo.c8
-rw-r--r--drivers/base/core.c34
-rw-r--r--drivers/base/dd.c55
-rw-r--r--drivers/base/devcon.c28
-rw-r--r--drivers/base/devtmpfs.c3
-rw-r--r--drivers/base/driver.c4
-rw-r--r--drivers/base/firmware_loader/Kconfig18
-rw-r--r--drivers/base/firmware_loader/fallback.c65
-rw-r--r--drivers/base/firmware_loader/fallback_table.c13
-rw-r--r--drivers/base/firmware_loader/firmware.h16
-rw-r--r--drivers/base/firmware_loader/main.c224
-rw-r--r--drivers/base/memory.c219
-rw-r--r--drivers/base/node.c40
-rw-r--r--drivers/base/platform.c2
-rw-r--r--drivers/base/power/clock_ops.c6
-rw-r--r--drivers/base/power/domain.c8
-rw-r--r--drivers/base/power/domain_governor.c4
-rw-r--r--drivers/base/power/main.c36
-rw-r--r--drivers/base/power/qos.c135
-rw-r--r--drivers/base/power/runtime.c2
-rw-r--r--drivers/base/power/wakeup.c6
-rw-r--r--drivers/base/property.c24
-rw-r--r--drivers/base/regmap/Kconfig6
-rw-r--r--drivers/base/regmap/Makefile1
-rw-r--r--drivers/base/regmap/regcache-lzo.c8
-rw-r--r--drivers/base/regmap/regmap-debugfs.c2
-rw-r--r--drivers/base/regmap/regmap-i3c.c60
-rw-r--r--drivers/base/regmap/regmap.c2
-rw-r--r--drivers/base/swnode.c324
-rw-r--r--drivers/base/topology.c22
-rw-r--r--drivers/block/Kconfig10
-rw-r--r--drivers/block/drbd/drbd_debugfs.c64
-rw-r--r--drivers/block/drbd/drbd_debugfs.h4
-rw-r--r--drivers/block/drbd/drbd_int.h2
-rw-r--r--drivers/block/drbd/drbd_main.c5
-rw-r--r--drivers/block/drbd/drbd_nl.c2
-rw-r--r--drivers/block/floppy.c38
-rw-r--r--drivers/block/loop.c16
-rw-r--r--drivers/block/mtip32xx/mtip32xx.c5
-rw-r--r--drivers/block/nbd.c59
-rw-r--r--drivers/block/null_blk.h5
-rw-r--r--drivers/block/null_blk_main.c14
-rw-r--r--drivers/block/null_blk_zoned.c3
-rw-r--r--drivers/block/rbd.c2188
-rw-r--r--drivers/block/rbd_types.h10
-rw-r--r--drivers/block/skd_main.c5
-rw-r--r--drivers/block/skd_s1120.h4
-rw-r--r--drivers/block/xsysace.c5
-rw-r--r--drivers/block/zram/Kconfig6
-rw-r--r--drivers/bluetooth/Kconfig12
-rw-r--r--drivers/bluetooth/bpa10x.c3
-rw-r--r--drivers/bluetooth/btbcm.c1
-rw-r--r--drivers/bluetooth/btmtkuart.c51
-rw-r--r--drivers/bluetooth/btqca.c47
-rw-r--r--drivers/bluetooth/btqca.h10
-rw-r--r--drivers/bluetooth/btrtl.c28
-rw-r--r--drivers/bluetooth/btrtl.h6
-rw-r--r--drivers/bluetooth/btsdio.c1
-rw-r--r--drivers/bluetooth/btusb.c584
-rw-r--r--drivers/bluetooth/hci_bcsp.c5
-rw-r--r--drivers/bluetooth/hci_ldisc.c8
-rw-r--r--drivers/bluetooth/hci_ll.c109
-rw-r--r--drivers/bluetooth/hci_mrvl.c72
-rw-r--r--drivers/bluetooth/hci_qca.c73
-rw-r--r--drivers/bluetooth/hci_uart.h1
-rw-r--r--drivers/bus/da8xx-mstpri.c5
-rw-r--r--drivers/bus/qcom-ebi2.c5
-rw-r--r--drivers/bus/ti-sysc.c23
-rw-r--r--drivers/cdrom/cdrom.c2
-rw-r--r--drivers/char/Kconfig6
-rw-r--r--drivers/char/agp/generic.c3
-rw-r--r--drivers/char/agp/hp-agp.c5
-rw-r--r--drivers/char/agp/parisc-agp.c6
-rw-r--r--drivers/char/bsr.c5
-rw-r--r--drivers/char/hpet.c5
-rw-r--r--drivers/char/hw_random/core.c2
-rw-r--r--drivers/char/hw_random/hisi-rng.c5
-rw-r--r--drivers/char/hw_random/iproc-rng200.c1
-rw-r--r--drivers/char/hw_random/meson-rng.c52
-rw-r--r--drivers/char/hw_random/st-rng.c5
-rw-r--r--drivers/char/hw_random/timeriomem-rng.c5
-rw-r--r--drivers/char/ipmi/Kconfig9
-rw-r--r--drivers/char/ipmi/Makefile1
-rw-r--r--drivers/char/ipmi/ipmb_dev_int.c364
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c8
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c4
-rw-r--r--drivers/char/ipmi/ipmi_si_platform.c9
-rw-r--r--drivers/char/ipmi/ipmi_ssif.c5
-rw-r--r--drivers/char/misc.c3
-rw-r--r--drivers/char/tpm/eventlog/efi.c59
-rw-r--r--drivers/char/tpm/eventlog/tpm2.c47
-rw-r--r--drivers/char/tpm/tpm-chip.c6
-rw-r--r--drivers/char/tpm/tpm1-cmd.c7
-rw-r--r--drivers/char/tpm/tpm2-cmd.c7
-rw-r--r--drivers/char/tpm/tpmrm-dev.c3
-rw-r--r--drivers/char/tpm/xen-tpmfront.c5
-rw-r--r--drivers/clk/Kconfig28
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/at91/sckc.c281
-rw-r--r--drivers/clk/axis/clk-artpec6.c5
-rw-r--r--drivers/clk/bcm/Kconfig24
-rw-r--r--drivers/clk/bcm/Makefile6
-rw-r--r--drivers/clk/bcm/clk-bcm2835.c28
-rw-r--r--drivers/clk/bcm/clk-bcm53573-ilp.c5
-rw-r--r--drivers/clk/bcm/clk-bcm63xx-gate.c238
-rw-r--r--drivers/clk/bcm/clk-raspberrypi.c315
-rw-r--r--drivers/clk/bcm/clk-sr.c13
-rw-r--r--drivers/clk/clk-axm5516.c5
-rw-r--r--drivers/clk/clk-bd718x7.c24
-rw-r--r--drivers/clk/clk-bulk.c23
-rw-r--r--drivers/clk/clk-cdce706.c7
-rw-r--r--drivers/clk/clk-devres.c22
-rw-r--r--drivers/clk/clk-efm32gg.c5
-rw-r--r--drivers/clk/clk-lochnagar.c205
-rw-r--r--drivers/clk/clk-nspire.c6
-rw-r--r--drivers/clk/clk-pwm.c19
-rw-r--r--drivers/clk/clk-qoriq.c17
-rw-r--r--drivers/clk/clk-rk808.c64
-rw-r--r--drivers/clk/clk-si5341.c1346
-rw-r--r--drivers/clk/clk-si544.c102
-rw-r--r--drivers/clk/clk.c65
-rw-r--r--drivers/clk/clk.h4
-rw-r--r--drivers/clk/clkdev.c5
-rw-r--r--drivers/clk/hisilicon/clk-hi6220-stub.c6
-rw-r--r--drivers/clk/hisilicon/clk-hi6220.c5
-rw-r--r--drivers/clk/hisilicon/clkdivider-hi6220.c6
-rw-r--r--drivers/clk/imx/clk-busy.c30
-rw-r--r--drivers/clk/imx/clk-cpu.c22
-rw-r--r--drivers/clk/imx/clk-fixup-div.c15
-rw-r--r--drivers/clk/imx/clk-fixup-mux.c15
-rw-r--r--drivers/clk/imx/clk-gate-exclusive.c22
-rw-r--r--drivers/clk/imx/clk-gate2.c19
-rw-r--r--drivers/clk/imx/clk-imx35.c6
-rw-r--r--drivers/clk/imx/clk-imx5.c6
-rw-r--r--drivers/clk/imx/clk-imx6q.c782
-rw-r--r--drivers/clk/imx/clk-imx6sl.c415
-rw-r--r--drivers/clk/imx/clk-imx6sll.c434
-rw-r--r--drivers/clk/imx/clk-imx6sx.c662
-rw-r--r--drivers/clk/imx/clk-imx6ul.c580
-rw-r--r--drivers/clk/imx/clk-imx7d.c984
-rw-r--r--drivers/clk/imx/clk-imx7ulp.c2
-rw-r--r--drivers/clk/imx/clk-imx8mm.c18
-rw-r--r--drivers/clk/imx/clk-imx8mq.c27
-rw-r--r--drivers/clk/imx/clk-pfd.c14
-rw-r--r--drivers/clk/imx/clk-pllv3.c14
-rw-r--r--drivers/clk/imx/clk.c35
-rw-r--r--drivers/clk/imx/clk.h143
-rw-r--r--drivers/clk/ingenic/Makefile2
-rw-r--r--drivers/clk/ingenic/cgu.c41
-rw-r--r--drivers/clk/ingenic/cgu.h4
-rw-r--r--drivers/clk/ingenic/jz4725b-cgu.c41
-rw-r--r--drivers/clk/ingenic/jz4740-cgu.c105
-rw-r--r--drivers/clk/ingenic/jz4770-cgu.c67
-rw-r--r--drivers/clk/ingenic/jz4780-cgu.c3
-rw-r--r--drivers/clk/ingenic/pm.c45
-rw-r--r--drivers/clk/ingenic/pm.h12
-rw-r--r--drivers/clk/keystone/Kconfig11
-rw-r--r--drivers/clk/keystone/sci-clk.c239
-rw-r--r--drivers/clk/mediatek/Kconfig6
-rw-r--r--drivers/clk/mediatek/Makefile1
-rw-r--r--drivers/clk/mediatek/clk-mt8183.c19
-rw-r--r--drivers/clk/mediatek/clk-mt8516-aud.c65
-rw-r--r--drivers/clk/mediatek/clk-mt8516.c5
-rw-r--r--drivers/clk/meson/axg.c10
-rw-r--r--drivers/clk/meson/clk-mpll.c36
-rw-r--r--drivers/clk/meson/clk-mpll.h3
-rw-r--r--drivers/clk/meson/g12a.c839
-rw-r--r--drivers/clk/meson/g12a.h43
-rw-r--r--drivers/clk/meson/gxbb.c5
-rw-r--r--drivers/clk/meson/meson-eeclk.c3
-rw-r--r--drivers/clk/meson/meson-eeclk.h2
-rw-r--r--drivers/clk/meson/meson8b.c164
-rw-r--r--drivers/clk/meson/meson8b.h8
-rw-r--r--drivers/clk/mmp/clk-frac.c3
-rw-r--r--drivers/clk/mvebu/kirkwood.c17
-rw-r--r--drivers/clk/qcom/gcc-msm8996.c36
-rw-r--r--drivers/clk/qcom/gcc-qcs404.c7
-rw-r--r--drivers/clk/qcom/gdsc.c4
-rw-r--r--drivers/clk/renesas/clk-div6.c19
-rw-r--r--drivers/clk/renesas/clk-mstp.c20
-rw-r--r--drivers/clk/renesas/r8a77470-cpg-mssr.c2
-rw-r--r--drivers/clk/renesas/r8a774a1-cpg-mssr.c5
-rw-r--r--drivers/clk/renesas/r8a7795-cpg-mssr.c5
-rw-r--r--drivers/clk/renesas/r8a7796-cpg-mssr.c4
-rw-r--r--drivers/clk/renesas/r8a77965-cpg-mssr.c4
-rw-r--r--drivers/clk/renesas/r8a77990-cpg-mssr.c2
-rw-r--r--drivers/clk/renesas/r8a77995-cpg-mssr.c2
-rw-r--r--drivers/clk/renesas/r9a06g032-clocks.c227
-rw-r--r--drivers/clk/renesas/renesas-cpg-mssr.c37
-rw-r--r--drivers/clk/rockchip/clk-cpu.c5
-rw-r--r--drivers/clk/rockchip/clk-mmc-phase.c14
-rw-r--r--drivers/clk/rockchip/clk-px30.c12
-rw-r--r--drivers/clk/rockchip/clk-rk3228.c3
-rw-r--r--drivers/clk/rockchip/clk-rk3288.c13
-rw-r--r--drivers/clk/rockchip/clk-rk3328.c3
-rw-r--r--drivers/clk/rockchip/clk-rk3368.c12
-rw-r--r--drivers/clk/rockchip/clk-rk3399.c12
-rw-r--r--drivers/clk/rockchip/clk.h4
-rw-r--r--drivers/clk/samsung/clk-cpu.c5
-rw-r--r--drivers/clk/samsung/clk-cpu.h5
-rw-r--r--drivers/clk/samsung/clk-exynos-audss.c5
-rw-r--r--drivers/clk/samsung/clk-exynos-clkout.c5
-rw-r--r--drivers/clk/samsung/clk-exynos3250.c5
-rw-r--r--drivers/clk/samsung/clk-exynos4.c6
-rw-r--r--drivers/clk/samsung/clk-exynos4412-isp.c5
-rw-r--r--drivers/clk/samsung/clk-exynos5250.c5
-rw-r--r--drivers/clk/samsung/clk-exynos5260.c5
-rw-r--r--drivers/clk/samsung/clk-exynos5260.h5
-rw-r--r--drivers/clk/samsung/clk-exynos5410.c5
-rw-r--r--drivers/clk/samsung/clk-exynos5420.c83
-rw-r--r--drivers/clk/samsung/clk-exynos5433.c9
-rw-r--r--drivers/clk/samsung/clk-exynos7.c6
-rw-r--r--drivers/clk/samsung/clk-pll.c5
-rw-r--r--drivers/clk/samsung/clk-pll.h5
-rw-r--r--drivers/clk/samsung/clk-s3c2410-dclk.c5
-rw-r--r--drivers/clk/samsung/clk-s3c2410.c5
-rw-r--r--drivers/clk/samsung/clk-s3c2412.c5
-rw-r--r--drivers/clk/samsung/clk-s3c2443.c5
-rw-r--r--drivers/clk/samsung/clk-s3c64xx.c5
-rw-r--r--drivers/clk/samsung/clk-s5pv210-audss.c5
-rw-r--r--drivers/clk/samsung/clk-s5pv210.c5
-rw-r--r--drivers/clk/samsung/clk.c5
-rw-r--r--drivers/clk/samsung/clk.h5
-rw-r--r--drivers/clk/socfpga/clk-s10.c10
-rw-r--r--drivers/clk/sprd/common.c9
-rw-r--r--drivers/clk/sprd/sc9860-clk.c5
-rw-r--r--drivers/clk/st/clkgen-fsyn.c6
-rw-r--r--drivers/clk/sunxi-ng/ccu-sun4i-a10.c39
-rw-r--r--drivers/clk/sunxi-ng/ccu-sun50i-a64.c41
-rw-r--r--drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c4
-rw-r--r--drivers/clk/sunxi-ng/ccu-sun50i-h6.c69
-rw-r--r--drivers/clk/sunxi-ng/ccu-sun5i.c34
-rw-r--r--drivers/clk/sunxi-ng/ccu-sun6i-a31.c39
-rw-r--r--drivers/clk/sunxi-ng/ccu-sun8i-a23.c34
-rw-r--r--drivers/clk/sunxi-ng/ccu-sun8i-a33.c34
-rw-r--r--drivers/clk/sunxi-ng/ccu-sun8i-h3.c29
-rw-r--r--drivers/clk/sunxi-ng/ccu-sun8i-r.c104
-rw-r--r--drivers/clk/sunxi-ng/ccu-sun8i-r40.c46
-rw-r--r--drivers/clk/sunxi-ng/ccu-sun8i-v3s.c29
-rw-r--r--drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c32
-rw-r--r--drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c29
-rw-r--r--drivers/clk/sunxi-ng/ccu_common.c2
-rw-r--r--drivers/clk/sunxi-ng/ccu_gate.h53
-rw-r--r--drivers/clk/sunxi/clk-factors.c5
-rw-r--r--drivers/clk/sunxi/clk-sunxi.c2
-rw-r--r--drivers/clk/tegra/clk-bpmp.c5
-rw-r--r--drivers/clk/tegra/clk-tegra210.c22
-rw-r--r--drivers/clk/ti/clk-44xx.c5
-rw-r--r--drivers/clk/ti/clk-54xx.c5
-rw-r--r--drivers/clk/ti/clk-7xx-compat.c5
-rw-r--r--drivers/clk/ti/clk-7xx.c5
-rw-r--r--drivers/clk/ti/clkctrl.c7
-rw-r--r--drivers/clk/ti/clkt_dpll.c5
-rw-r--r--drivers/clk/ti/clkt_iclk.c5
-rw-r--r--drivers/clk/ti/divider.c85
-rw-r--r--drivers/clk/ti/dpll3xxx.c5
-rw-r--r--drivers/clk/ti/dpll44xx.c5
-rw-r--r--drivers/clk/ti/gate.c30
-rw-r--r--drivers/clk/ti/mux.c31
-rw-r--r--drivers/clk/versatile/clk-icst.c5
-rw-r--r--drivers/clk/versatile/clk-impd1.c5
-rw-r--r--drivers/clk/versatile/clk-versatile.c5
-rw-r--r--drivers/clk/versatile/icst.c5
-rw-r--r--drivers/clk/versatile/icst.h5
-rw-r--r--drivers/clk/x86/clk-lpt.c5
-rw-r--r--drivers/clk/zte/clk-zx296702.c5
-rw-r--r--drivers/clk/zte/clk-zx296718.c5
-rw-r--r--drivers/clk/zte/clk.c5
-rw-r--r--drivers/clk/zte/clk.h5
-rw-r--r--drivers/clocksource/Kconfig14
-rw-r--r--drivers/clocksource/Makefile5
-rw-r--r--drivers/clocksource/acpi_pm.c3
-rw-r--r--drivers/clocksource/arc_timer.c8
-rw-r--r--drivers/clocksource/arm_arch_timer.c20
-rw-r--r--drivers/clocksource/arm_global_timer.c5
-rw-r--r--drivers/clocksource/dummy_timer.c5
-rw-r--r--drivers/clocksource/dw_apb_timer.c5
-rw-r--r--drivers/clocksource/dw_apb_timer_of.c13
-rw-r--r--drivers/clocksource/exynos_mct.c9
-rw-r--r--drivers/clocksource/hyperv_timer.c339
-rw-r--r--drivers/clocksource/mmio.c5
-rw-r--r--drivers/clocksource/mps2-timer.c6
-rw-r--r--drivers/clocksource/nomadik-mtu.c5
-rw-r--r--drivers/clocksource/samsung_pwm_timer.c5
-rw-r--r--drivers/clocksource/timer-atmel-pit.c5
-rw-r--r--drivers/clocksource/timer-davinci.c369
-rw-r--r--drivers/clocksource/timer-efm32.c5
-rw-r--r--drivers/clocksource/timer-imx-sysctr.c145
-rw-r--r--drivers/clocksource/timer-ixp4xx.c16
-rw-r--r--drivers/clocksource/timer-keystone.c6
-rw-r--r--drivers/clocksource/timer-meson6.c5
-rw-r--r--drivers/clocksource/timer-npcm7xx.c2
-rw-r--r--drivers/clocksource/timer-pxa.c5
-rw-r--r--drivers/clocksource/timer-rockchip.c5
-rw-r--r--drivers/clocksource/timer-tegra.c416
-rw-r--r--drivers/clocksource/timer-tegra20.c379
-rw-r--r--drivers/clocksource/timer-zevio.c6
-rw-r--r--drivers/counter/104-quad-8.c2
-rw-r--r--drivers/counter/Kconfig1
-rw-r--r--drivers/counter/ftm-quaddec.c4
-rw-r--r--drivers/cpufreq/Kconfig.arm17
-rw-r--r--drivers/cpufreq/Makefile2
-rw-r--r--drivers/cpufreq/amd_freq_sensitivity.c5
-rw-r--r--drivers/cpufreq/armada-37xx-cpufreq.c4
-rw-r--r--drivers/cpufreq/bmips-cpufreq.c17
-rw-r--r--drivers/cpufreq/brcmstb-avs-cpufreq.c12
-rw-r--r--drivers/cpufreq/cpufreq-dt-platdev.c10
-rw-r--r--drivers/cpufreq/cpufreq-dt.c5
-rw-r--r--drivers/cpufreq/cpufreq-dt.h5
-rw-r--r--drivers/cpufreq/cpufreq.c328
-rw-r--r--drivers/cpufreq/cpufreq_conservative.c5
-rw-r--r--drivers/cpufreq/cpufreq_governor.c5
-rw-r--r--drivers/cpufreq/cpufreq_governor.h5
-rw-r--r--drivers/cpufreq/cpufreq_governor_attr_set.c5
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c5
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.h5
-rw-r--r--drivers/cpufreq/cpufreq_performance.c7
-rw-r--r--drivers/cpufreq/cpufreq_powersave.c7
-rw-r--r--drivers/cpufreq/cpufreq_stats.c5
-rw-r--r--drivers/cpufreq/cpufreq_userspace.c6
-rw-r--r--drivers/cpufreq/davinci-cpufreq.c8
-rw-r--r--drivers/cpufreq/freq_table.c6
-rw-r--r--drivers/cpufreq/gx-suspmod.c6
-rw-r--r--drivers/cpufreq/highbank-cpufreq.c5
-rw-r--r--drivers/cpufreq/imx-cpufreq-dt.c98
-rw-r--r--drivers/cpufreq/imx6q-cpufreq.c11
-rw-r--r--drivers/cpufreq/intel_pstate.c7
-rw-r--r--drivers/cpufreq/kirkwood-cpufreq.c3
-rw-r--r--drivers/cpufreq/loongson1-cpufreq.c8
-rw-r--r--drivers/cpufreq/loongson2_cpufreq.c3
-rw-r--r--drivers/cpufreq/maple-cpufreq.c8
-rw-r--r--drivers/cpufreq/omap-cpufreq.c20
-rw-r--r--drivers/cpufreq/pasemi-cpufreq.c3
-rw-r--r--drivers/cpufreq/pcc-cpufreq.c4
-rw-r--r--drivers/cpufreq/pmac32-cpufreq.c9
-rw-r--r--drivers/cpufreq/pmac64-cpufreq.c8
-rw-r--r--drivers/cpufreq/qoriq-cpufreq.c5
-rw-r--r--drivers/cpufreq/raspberrypi-cpufreq.c97
-rw-r--r--drivers/cpufreq/s3c2410-cpufreq.c5
-rw-r--r--drivers/cpufreq/s3c2412-cpufreq.c5
-rw-r--r--drivers/cpufreq/s3c2416-cpufreq.c14
-rw-r--r--drivers/cpufreq/s3c2440-cpufreq.c5
-rw-r--r--drivers/cpufreq/s3c24xx-cpufreq-debugfs.c5
-rw-r--r--drivers/cpufreq/s3c24xx-cpufreq.c5
-rw-r--r--drivers/cpufreq/s3c64xx-cpufreq.c20
-rw-r--r--drivers/cpufreq/s5pv210-cpufreq.c10
-rw-r--r--drivers/cpufreq/sa1100-cpufreq.c3
-rw-r--r--drivers/cpufreq/sa1110-cpufreq.c8
-rw-r--r--drivers/cpufreq/sfi-cpufreq.c10
-rw-r--r--drivers/cpufreq/spear-cpufreq.c3
-rw-r--r--drivers/cpufreq/tegra20-cpufreq.c8
-rw-r--r--drivers/cpufreq/unicore2-cpufreq.c5
-rw-r--r--drivers/cpuidle/cpuidle-arm.c5
-rw-r--r--drivers/cpuidle/cpuidle-big_little.c5
-rw-r--r--drivers/cpuidle/cpuidle-exynos.c5
-rw-r--r--drivers/cpuidle/cpuidle-ux500.c5
-rw-r--r--drivers/cpuidle/dt_idle_states.c5
-rw-r--r--drivers/cpuidle/governor.c2
-rw-r--r--drivers/crypto/Kconfig20
-rw-r--r--drivers/crypto/Makefile2
-rw-r--r--drivers/crypto/amcc/crypto4xx_alg.c36
-rw-r--r--drivers/crypto/amcc/crypto4xx_core.c25
-rw-r--r--drivers/crypto/amcc/crypto4xx_core.h10
-rw-r--r--drivers/crypto/amcc/crypto4xx_trng.c1
-rw-r--r--drivers/crypto/atmel-ecc.c403
-rw-r--r--drivers/crypto/atmel-ecc.h116
-rw-r--r--drivers/crypto/atmel-i2c.c364
-rw-r--r--drivers/crypto/atmel-i2c.h197
-rw-r--r--drivers/crypto/atmel-sha204a.c171
-rw-r--r--drivers/crypto/bcm/cipher.c21
-rw-r--r--drivers/crypto/bcm/cipher.h13
-rw-r--r--drivers/crypto/bcm/spu.c13
-rw-r--r--drivers/crypto/bcm/spu.h13
-rw-r--r--drivers/crypto/bcm/spu2.c23
-rw-r--r--drivers/crypto/bcm/spu2.h13
-rw-r--r--drivers/crypto/bcm/spum.h13
-rw-r--r--drivers/crypto/bcm/util.c13
-rw-r--r--drivers/crypto/bcm/util.h13
-rw-r--r--drivers/crypto/caam/Kconfig46
-rw-r--r--drivers/crypto/caam/Makefile18
-rw-r--r--drivers/crypto/caam/caamalg.c338
-rw-r--r--drivers/crypto/caam/caamalg_desc.c147
-rw-r--r--drivers/crypto/caam/caamalg_desc.h4
-rw-r--r--drivers/crypto/caam/caamalg_qi.c267
-rw-r--r--drivers/crypto/caam/caamalg_qi2.c202
-rw-r--r--drivers/crypto/caam/caamhash.c329
-rw-r--r--drivers/crypto/caam/caampkc.c177
-rw-r--r--drivers/crypto/caam/caampkc.h9
-rw-r--r--drivers/crypto/caam/caamrng.c76
-rw-r--r--drivers/crypto/caam/ctrl.c56
-rw-r--r--drivers/crypto/caam/desc_constr.h11
-rw-r--r--drivers/crypto/caam/error.c8
-rw-r--r--drivers/crypto/caam/error.h2
-rw-r--r--drivers/crypto/caam/intern.h102
-rw-r--r--drivers/crypto/caam/jr.c43
-rw-r--r--drivers/crypto/caam/key_gen.c28
-rw-r--r--drivers/crypto/caam/qi.c52
-rw-r--r--drivers/crypto/caam/sg_sw_qm.h18
-rw-r--r--drivers/crypto/caam/sg_sw_qm2.h18
-rw-r--r--drivers/crypto/caam/sg_sw_sec4.h26
-rw-r--r--drivers/crypto/cavium/cpt/cptvf_algs.c1
-rw-r--r--drivers/crypto/cavium/nitrox/nitrox_debugfs.h2
-rw-r--r--drivers/crypto/cavium/nitrox/nitrox_mbx.h2
-rw-r--r--drivers/crypto/ccp/ccp-crypto-aes-cmac.c5
-rw-r--r--drivers/crypto/ccp/ccp-crypto-aes-galois.c5
-rw-r--r--drivers/crypto/ccp/ccp-crypto-aes-xts.c5
-rw-r--r--drivers/crypto/ccp/ccp-crypto-aes.c12
-rw-r--r--drivers/crypto/ccp/ccp-crypto-des3.c5
-rw-r--r--drivers/crypto/ccp/ccp-crypto-main.c5
-rw-r--r--drivers/crypto/ccp/ccp-crypto-rsa.c5
-rw-r--r--drivers/crypto/ccp/ccp-crypto-sha.c5
-rw-r--r--drivers/crypto/ccp/ccp-crypto.h5
-rw-r--r--drivers/crypto/ccp/ccp-debugfs.c5
-rw-r--r--drivers/crypto/ccp/ccp-dev-v3.c5
-rw-r--r--drivers/crypto/ccp/ccp-dev-v5.c5
-rw-r--r--drivers/crypto/ccp/ccp-dev.c101
-rw-r--r--drivers/crypto/ccp/ccp-dev.h7
-rw-r--r--drivers/crypto/ccp/ccp-dmaengine.c5
-rw-r--r--drivers/crypto/ccp/ccp-ops.c40
-rw-r--r--drivers/crypto/ccp/psp-dev.c24
-rw-r--r--drivers/crypto/ccp/psp-dev.h5
-rw-r--r--drivers/crypto/ccp/sp-dev.c5
-rw-r--r--drivers/crypto/ccp/sp-dev.h5
-rw-r--r--drivers/crypto/ccp/sp-pci.c5
-rw-r--r--drivers/crypto/ccp/sp-platform.c5
-rw-r--r--drivers/crypto/ccree/cc_driver.c70
-rw-r--r--drivers/crypto/ccree/cc_driver.h6
-rw-r--r--drivers/crypto/ccree/cc_host_regs.h20
-rw-r--r--drivers/crypto/ccree/cc_pm.c11
-rw-r--r--drivers/crypto/ccree/cc_pm.h7
-rw-r--r--drivers/crypto/chelsio/chtls/chtls.h5
-rw-r--r--drivers/crypto/chelsio/chtls/chtls_cm.c5
-rw-r--r--drivers/crypto/chelsio/chtls/chtls_cm.h5
-rw-r--r--drivers/crypto/chelsio/chtls/chtls_hw.c5
-rw-r--r--drivers/crypto/chelsio/chtls/chtls_io.c5
-rw-r--r--drivers/crypto/chelsio/chtls/chtls_main.c5
-rw-r--r--drivers/crypto/hisilicon/sec/sec_drv.h2
-rw-r--r--drivers/crypto/img-hash.c5
-rw-r--r--drivers/crypto/inside-secure/safexcel.c13
-rw-r--r--drivers/crypto/inside-secure/safexcel.h17
-rw-r--r--drivers/crypto/inside-secure/safexcel_cipher.c116
-rw-r--r--drivers/crypto/inside-secure/safexcel_hash.c92
-rw-r--r--drivers/crypto/inside-secure/safexcel_ring.c3
-rw-r--r--drivers/crypto/ixp4xx_crypto.c15
-rw-r--r--drivers/crypto/marvell/cesa.c5
-rw-r--r--drivers/crypto/marvell/cipher.c5
-rw-r--r--drivers/crypto/marvell/hash.c5
-rw-r--r--drivers/crypto/marvell/tdma.c5
-rw-r--r--drivers/crypto/mediatek/mtk-aes.c5
-rw-r--r--drivers/crypto/mediatek/mtk-platform.c6
-rw-r--r--drivers/crypto/mediatek/mtk-platform.h6
-rw-r--r--drivers/crypto/mediatek/mtk-sha.c5
-rw-r--r--drivers/crypto/mxs-dcp.c5
-rw-r--r--drivers/crypto/nx/nx-842-powernv.c8
-rw-r--r--drivers/crypto/nx/nx-842-pseries.c6
-rw-r--r--drivers/crypto/nx/nx.c4
-rw-r--r--drivers/crypto/nx/nx.h12
-rw-r--r--drivers/crypto/nx/nx_debugfs.c71
-rw-r--r--drivers/crypto/omap-aes-gcm.c6
-rw-r--r--drivers/crypto/omap-aes.c6
-rw-r--r--drivers/crypto/omap-aes.h6
-rw-r--r--drivers/crypto/omap-crypto.c5
-rw-r--r--drivers/crypto/omap-crypto.h5
-rw-r--r--drivers/crypto/omap-des.c6
-rw-r--r--drivers/crypto/omap-sham.c5
-rw-r--r--drivers/crypto/qat/qat_common/qat_algs.c294
-rw-r--r--drivers/crypto/qat/qat_common/qat_crypto.h2
-rw-r--r--drivers/crypto/sahara.c9
-rw-r--r--drivers/crypto/stm32/Makefile2
-rw-r--r--drivers/crypto/stm32/stm32-crc32.c (renamed from drivers/crypto/stm32/stm32_crc32.c)0
-rw-r--r--drivers/crypto/stm32/stm32-hash.c24
-rw-r--r--drivers/crypto/sunxi-ss/sun4i-ss-cipher.c49
-rw-r--r--drivers/crypto/sunxi-ss/sun4i-ss-core.c2
-rw-r--r--drivers/crypto/sunxi-ss/sun4i-ss-hash.c2
-rw-r--r--drivers/crypto/sunxi-ss/sun4i-ss.h2
-rw-r--r--drivers/crypto/talitos.c368
-rw-r--r--drivers/crypto/talitos.h73
-rw-r--r--drivers/crypto/vmx/aes_cbc.c183
-rw-r--r--drivers/crypto/vmx/aes_ctr.c165
-rw-r--r--drivers/crypto/vmx/aes_xts.c175
-rw-r--r--drivers/crypto/vmx/aesp8-ppc.h2
-rw-r--r--drivers/crypto/vmx/aesp8-ppc.pl22
-rw-r--r--drivers/crypto/vmx/vmx.c72
-rw-r--r--drivers/dax/bus.c21
-rw-r--r--drivers/dax/dax-private.h6
-rw-r--r--drivers/dax/device.c41
-rw-r--r--drivers/dax/kmem.c46
-rw-r--r--drivers/dax/pmem/core.c2
-rw-r--r--drivers/dax/super.c42
-rw-r--r--drivers/devfreq/devfreq-event.c5
-rw-r--r--drivers/devfreq/devfreq.c5
-rw-r--r--drivers/devfreq/event/exynos-nocp.c5
-rw-r--r--drivers/devfreq/event/exynos-nocp.h5
-rw-r--r--drivers/devfreq/event/exynos-ppmu.c5
-rw-r--r--drivers/devfreq/event/exynos-ppmu.h5
-rw-r--r--drivers/devfreq/exynos-bus.c5
-rw-r--r--drivers/devfreq/governor.h5
-rw-r--r--drivers/devfreq/governor_passive.c5
-rw-r--r--drivers/devfreq/governor_performance.c5
-rw-r--r--drivers/devfreq/governor_powersave.c5
-rw-r--r--drivers/devfreq/governor_simpleondemand.c5
-rw-r--r--drivers/devfreq/governor_userspace.c5
-rw-r--r--drivers/dma-buf/Kconfig2
-rw-r--r--drivers/dma-buf/dma-buf.c28
-rw-r--r--drivers/dma/Kconfig5
-rw-r--r--drivers/dma/Makefile1
-rw-r--r--drivers/dma/acpi-dma.c5
-rw-r--r--drivers/dma/amba-pl08x.c5
-rw-r--r--drivers/dma/at_xdmac.c24
-rw-r--r--drivers/dma/bcm-sba-raid.c13
-rw-r--r--drivers/dma/bestcomm/bcom_ata_task.c5
-rw-r--r--drivers/dma/bestcomm/bcom_fec_rx_task.c5
-rw-r--r--drivers/dma/bestcomm/bcom_fec_tx_task.c5
-rw-r--r--drivers/dma/bestcomm/bcom_gen_bd_rx_task.c6
-rw-r--r--drivers/dma/bestcomm/bcom_gen_bd_tx_task.c6
-rw-r--r--drivers/dma/bestcomm/gen_bd.c6
-rw-r--r--drivers/dma/coh901318.c6
-rw-r--r--drivers/dma/dma-axi-dmac.c201
-rw-r--r--drivers/dma/dma-jz4780.c12
-rw-r--r--drivers/dma/dmaengine.c14
-rw-r--r--drivers/dma/dmatest.c11
-rw-r--r--drivers/dma/dw-edma/Kconfig19
-rw-r--r--drivers/dma/dw-edma/Makefile7
-rw-r--r--drivers/dma/dw-edma/dw-edma-core.c937
-rw-r--r--drivers/dma/dw-edma/dw-edma-core.h165
-rw-r--r--drivers/dma/dw-edma/dw-edma-pcie.c229
-rw-r--r--drivers/dma/dw-edma/dw-edma-v0-core.c354
-rw-r--r--drivers/dma/dw-edma/dw-edma-v0-core.h28
-rw-r--r--drivers/dma/dw-edma/dw-edma-v0-debugfs.c310
-rw-r--r--drivers/dma/dw-edma/dw-edma-v0-debugfs.h27
-rw-r--r--drivers/dma/dw-edma/dw-edma-v0-regs.h158
-rw-r--r--drivers/dma/dw/pci.c33
-rw-r--r--drivers/dma/fsl-edma-common.c69
-rw-r--r--drivers/dma/fsl-edma-common.h10
-rw-r--r--drivers/dma/fsl-edma.c43
-rw-r--r--drivers/dma/fsl-qdma.c18
-rw-r--r--drivers/dma/hsu/hsu.c9
-rw-r--r--drivers/dma/hsu/hsu.h5
-rw-r--r--drivers/dma/hsu/pci.c5
-rw-r--r--drivers/dma/idma64.c5
-rw-r--r--drivers/dma/idma64.h5
-rw-r--r--drivers/dma/imx-sdma.c61
-rw-r--r--drivers/dma/ipu/ipu_idmac.c5
-rw-r--r--drivers/dma/ipu/ipu_intern.h5
-rw-r--r--drivers/dma/ipu/ipu_irq.c5
-rw-r--r--drivers/dma/k3dma.c5
-rw-r--r--drivers/dma/lpc18xx-dmamux.c6
-rw-r--r--drivers/dma/mcf-edma.c11
-rw-r--r--drivers/dma/mediatek/Kconfig11
-rw-r--r--drivers/dma/mediatek/Makefile1
-rw-r--r--drivers/dma/mediatek/mtk-uart-apdma.c666
-rw-r--r--drivers/dma/mic_x100_dma.c6
-rw-r--r--drivers/dma/mmp_pdma.c5
-rw-r--r--drivers/dma/mmp_tdma.c10
-rw-r--r--drivers/dma/mxs-dma.c33
-rw-r--r--drivers/dma/of-dma.c9
-rw-r--r--drivers/dma/pl330.c40
-rw-r--r--drivers/dma/pxa_dma.c61
-rw-r--r--drivers/dma/qcom/bam_dma.c3
-rw-r--r--drivers/dma/qcom/hidma.h5
-rw-r--r--drivers/dma/qcom/hidma_dbg.c37
-rw-r--r--drivers/dma/sa11x0-dma.c5
-rw-r--r--drivers/dma/sh/Kconfig6
-rw-r--r--drivers/dma/sh/Makefile1
-rw-r--r--drivers/dma/sh/rcar-dmac.c8
-rw-r--r--drivers/dma/sh/sudmac.c414
-rw-r--r--drivers/dma/sh/usb-dmac.c8
-rw-r--r--drivers/dma/stm32-dma.c1
-rw-r--r--drivers/dma/stm32-dmamux.c6
-rw-r--r--drivers/dma/sun6i-dma.c147
-rw-r--r--drivers/dma/tegra20-apb-dma.c12
-rw-r--r--drivers/dma/ti/dma-crossbar.c6
-rw-r--r--drivers/dma/ti/omap-dma.c5
-rw-r--r--drivers/dma/txx9dmac.c5
-rw-r--r--drivers/dma/txx9dmac.h5
-rw-r--r--drivers/dma/virt-dma.c9
-rw-r--r--drivers/dma/virt-dma.h9
-rw-r--r--drivers/dma/xilinx/xilinx_dma.c4
-rw-r--r--drivers/dma/zx_dma.c5
-rw-r--r--drivers/edac/Kconfig6
-rw-r--r--drivers/edac/Makefile1
-rw-r--r--drivers/edac/altera_edac.c43
-rw-r--r--drivers/edac/aspeed_edac.c4
-rw-r--r--drivers/edac/debugfs.c12
-rw-r--r--drivers/edac/edac_mc_sysfs.c34
-rw-r--r--drivers/edac/edac_module.h20
-rw-r--r--drivers/edac/i10nm_base.c10
-rw-r--r--drivers/edac/ie31200_edac.c78
-rw-r--r--drivers/edac/sb_edac.c1
-rw-r--r--drivers/edac/sifive_edac.c119
-rw-r--r--drivers/edac/skx_base.c2
-rw-r--r--drivers/edac/skx_common.c4
-rw-r--r--drivers/edac/skx_common.h2
-rw-r--r--drivers/extcon/Kconfig12
-rw-r--r--drivers/extcon/Makefile1
-rw-r--r--drivers/extcon/extcon-adc-jack.c6
-rw-r--r--drivers/extcon/extcon-arizona.c33
-rw-r--r--drivers/extcon/extcon-fsa9480.c395
-rw-r--r--drivers/extcon/extcon-max3355.c5
-rw-r--r--drivers/firmware/Kconfig4
-rw-r--r--drivers/firmware/arm_scmi/common.h2
-rw-r--r--drivers/firmware/efi/dev-path-parser.c4
-rw-r--r--drivers/firmware/efi/efi-bgrt.c5
-rw-r--r--drivers/firmware/efi/efi.c14
-rw-r--r--drivers/firmware/efi/efibc.c12
-rw-r--r--drivers/firmware/efi/libstub/arm-stub.c5
-rw-r--r--drivers/firmware/efi/libstub/efi-stub-helper.c15
-rw-r--r--drivers/firmware/efi/libstub/efistub.h2
-rw-r--r--drivers/firmware/efi/libstub/fdt.c27
-rw-r--r--drivers/firmware/efi/libstub/tpm.c80
-rw-r--r--drivers/firmware/efi/tpm.c63
-rw-r--r--drivers/firmware/google/coreboot_table.h11
-rw-r--r--drivers/firmware/google/framebuffer-coreboot.c14
-rw-r--r--drivers/firmware/google/memconsole-coreboot.c28
-rw-r--r--drivers/firmware/google/memconsole.c9
-rw-r--r--drivers/firmware/google/vpd.c14
-rw-r--r--drivers/firmware/google/vpd_decode.c2
-rw-r--r--drivers/firmware/imx/imx-scu-irq.c3
-rw-r--r--drivers/firmware/pcdp.c5
-rw-r--r--drivers/firmware/pcdp.h5
-rw-r--r--drivers/firmware/raspberrypi.c10
-rw-r--r--drivers/firmware/ti_sci.c124
-rw-r--r--drivers/firmware/ti_sci.h65
-rw-r--r--drivers/fmc/Kconfig52
-rw-r--r--drivers/fmc/Makefile15
-rw-r--r--drivers/fmc/fmc-chardev.c199
-rw-r--r--drivers/fmc/fmc-core.c388
-rw-r--r--drivers/fmc/fmc-debug.c172
-rw-r--r--drivers/fmc/fmc-dump.c58
-rw-r--r--drivers/fmc/fmc-fakedev.c355
-rw-r--r--drivers/fmc/fmc-match.c113
-rw-r--r--drivers/fmc/fmc-private.h8
-rw-r--r--drivers/fmc/fmc-sdb.c219
-rw-r--r--drivers/fmc/fmc-trivial.c103
-rw-r--r--drivers/fmc/fmc-write-eeprom.c175
-rw-r--r--drivers/fmc/fru-parse.c80
-rw-r--r--drivers/fpga/Kconfig6
-rw-r--r--drivers/fpga/dfl-afu-dma-region.c53
-rw-r--r--drivers/fpga/dfl-fme-mgr.c4
-rw-r--r--drivers/fpga/dfl-fme-pr.c17
-rw-r--r--drivers/fpga/of-fpga-region.c7
-rw-r--r--drivers/fsi/cf-fsi-fw.h2
-rw-r--r--drivers/fsi/fsi-core.c32
-rw-r--r--drivers/fsi/fsi-occ.c15
-rw-r--r--drivers/fsi/fsi-sbefifo.c4
-rw-r--r--drivers/fsi/fsi-scom.c10
-rw-r--r--drivers/gpio/Kconfig33
-rw-r--r--drivers/gpio/Makefile297
-rw-r--r--drivers/gpio/TODO40
-rw-r--r--drivers/gpio/gpio-adnp.c5
-rw-r--r--drivers/gpio/gpio-altera.c65
-rw-r--r--drivers/gpio/gpio-amd-fch.c4
-rw-r--r--drivers/gpio/gpio-amdpt.c15
-rw-r--r--drivers/gpio/gpio-ath79.c71
-rw-r--r--drivers/gpio/gpio-bd70528.c232
-rw-r--r--drivers/gpio/gpio-cs5535.c2
-rw-r--r--drivers/gpio/gpio-davinci.c12
-rw-r--r--drivers/gpio/gpio-dwapb.c5
-rw-r--r--drivers/gpio/gpio-eic-sprd.c9
-rw-r--r--drivers/gpio/gpio-em.c67
-rw-r--r--drivers/gpio/gpio-ep93xx.c7
-rw-r--r--drivers/gpio/gpio-exar.c5
-rw-r--r--drivers/gpio/gpio-ftgpio010.c35
-rw-r--r--drivers/gpio/gpio-grgpio.c4
-rw-r--r--drivers/gpio/gpio-iop.c1
-rw-r--r--drivers/gpio/gpio-ixp4xx.c14
-rw-r--r--drivers/gpio/gpio-janz-ttl.c9
-rw-r--r--drivers/gpio/gpio-madera.c6
-rw-r--r--drivers/gpio/gpio-max3191x.c5
-rw-r--r--drivers/gpio/gpio-max7300.c5
-rw-r--r--drivers/gpio/gpio-max7301.c5
-rw-r--r--drivers/gpio/gpio-max730x.c5
-rw-r--r--drivers/gpio/gpio-max732x.c45
-rw-r--r--drivers/gpio/gpio-mb86s7x.c51
-rw-r--r--drivers/gpio/gpio-mm-lantiq.c4
-rw-r--r--drivers/gpio/gpio-mockup.c21
-rw-r--r--drivers/gpio/gpio-mvebu.c11
-rw-r--r--drivers/gpio/gpio-omap.c514
-rw-r--r--drivers/gpio/gpio-pca953x.c1
-rw-r--r--drivers/gpio/gpio-pl061.c35
-rw-r--r--drivers/gpio/gpio-pxa.c5
-rw-r--r--drivers/gpio/gpio-rcar.c2
-rw-r--r--drivers/gpio/gpio-reg.c5
-rw-r--r--drivers/gpio/gpio-sa1100.c5
-rw-r--r--drivers/gpio/gpio-siox.c51
-rw-r--r--drivers/gpio/gpio-stmpe.c2
-rw-r--r--drivers/gpio/gpio-stp-xway.c38
-rw-r--r--drivers/gpio/gpio-tc3589x.c2
-rw-r--r--drivers/gpio/gpio-tegra.c4
-rw-r--r--drivers/gpio/gpio-tegra186.c5
-rw-r--r--drivers/gpio/gpio-ucb1400.c6
-rw-r--r--drivers/gpio/gpio-vf610.c14
-rw-r--r--drivers/gpio/gpio-vr41xx.c19
-rw-r--r--drivers/gpio/gpio-xgene.c13
-rw-r--r--drivers/gpio/gpio-xilinx.c90
-rw-r--r--drivers/gpio/gpio-zevio.c5
-rw-r--r--drivers/gpio/gpio-zx.c5
-rw-r--r--drivers/gpio/gpiolib-acpi.c6
-rw-r--r--drivers/gpio/gpiolib-of.c44
-rw-r--r--drivers/gpio/gpiolib.c94
-rw-r--r--drivers/gpio/gpiolib.h2
-rw-r--r--drivers/gpu/drm/Kconfig2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/Kconfig3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c2
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_chardev.c2
-rw-r--r--drivers/gpu/drm/armada/armada_510.c5
-rw-r--r--drivers/gpu/drm/armada/armada_crtc.c5
-rw-r--r--drivers/gpu/drm/armada/armada_crtc.h5
-rw-r--r--drivers/gpu/drm/armada/armada_debugfs.c5
-rw-r--r--drivers/gpu/drm/armada/armada_drm.h5
-rw-r--r--drivers/gpu/drm/armada/armada_drv.c5
-rw-r--r--drivers/gpu/drm/armada/armada_fb.c5
-rw-r--r--drivers/gpu/drm/armada/armada_fb.h5
-rw-r--r--drivers/gpu/drm/armada/armada_fbdev.c5
-rw-r--r--drivers/gpu/drm/armada/armada_gem.c5
-rw-r--r--drivers/gpu/drm/armada/armada_gem.h5
-rw-r--r--drivers/gpu/drm/armada/armada_hw.h5
-rw-r--r--drivers/gpu/drm/armada/armada_ioctlP.h5
-rw-r--r--drivers/gpu/drm/armada/armada_overlay.c5
-rw-r--r--drivers/gpu/drm/armada/armada_plane.c5
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c13
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c13
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h13
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c13
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c13
-rw-r--r--drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h5
-rw-r--r--drivers/gpu/drm/bridge/sil-sii8620.c5
-rw-r--r--drivers/gpu/drm/bridge/sil-sii8620.h5
-rw-r--r--drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c5
-rw-r--r--drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c5
-rw-r--r--drivers/gpu/drm/bridge/ti-tfp410.c6
-rw-r--r--drivers/gpu/drm/drm_bufs.c5
-rw-r--r--drivers/gpu/drm/drm_drv.c20
-rw-r--r--drivers/gpu/drm/drm_ioc32.c5
-rw-r--r--drivers/gpu/drm/drm_ioctl.c2
-rw-r--r--drivers/gpu/drm/drm_mipi_dsi.c2
-rw-r--r--drivers/gpu/drm/drm_modeset_lock.c2
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c13
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gpu.c7
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dpi.c5
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dsi.c5
-rw-r--r--drivers/gpu/drm/exynos/regs-fimc.h5
-rw-r--r--drivers/gpu/drm/exynos/regs-gsc.h5
-rw-r--r--drivers/gpu/drm/exynos/regs-hdmi.h5
-rw-r--r--drivers/gpu/drm/exynos/regs-mixer.h5
-rw-r--r--drivers/gpu/drm/exynos/regs-rotator.h5
-rw-r--r--drivers/gpu/drm/exynos/regs-scaler.h5
-rw-r--r--drivers/gpu/drm/exynos/regs-vp.h5
-rw-r--r--drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c6
-rw-r--r--drivers/gpu/drm/hisilicon/kirin/dw_dsi_reg.h6
-rw-r--r--drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h6
-rw-r--r--drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c6
-rw-r--r--drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c6
-rw-r--r--drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h6
-rw-r--r--drivers/gpu/drm/i2c/tda9950.c5
-rw-r--r--drivers/gpu/drm/i2c/tda998x_drv.c13
-rw-r--r--drivers/gpu/drm/i915/.gitignore1
-rw-r--r--drivers/gpu/drm/i915/Makefile.header-test12
-rw-r--r--drivers/gpu/drm/i915/gvt/handlers.c15
-rw-r--r--drivers/gpu/drm/i915/i915_mm.c3
-rw-r--r--drivers/gpu/drm/i915/i915_perf.c8
-rw-r--r--drivers/gpu/drm/i915/intel_runtime_pm.h2
-rw-r--r--drivers/gpu/drm/imx/ipuv3-crtc.c6
-rw-r--r--drivers/gpu/drm/msm/adreno/a3xx_gpu.c13
-rw-r--r--drivers/gpu/drm/msm/adreno/a3xx_gpu.h13
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_device.c13
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_gpu.c13
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_gpu.h13
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c13
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h13
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c13
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h13
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c13
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h13
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c13
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h13
-rw-r--r--drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c13
-rw-r--r--drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c13
-rw-r--r--drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c13
-rw-r--r--drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c13
-rw-r--r--drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c13
-rw-r--r--drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.h13
-rw-r--r--drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c13
-rw-r--r--drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c13
-rw-r--r--drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_pll.c13
-rw-r--r--drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c13
-rw-r--r--drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c13
-rw-r--r--drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c13
-rw-r--r--drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c13
-rw-r--r--drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c13
-rw-r--r--drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.h13
-rw-r--r--drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c13
-rw-r--r--drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.c13
-rw-r--r--drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.h13
-rw-r--r--drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c13
-rw-r--r--drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.h13
-rw-r--r--drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c13
-rw-r--r--drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c13
-rw-r--r--drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.h13
-rw-r--r--drivers/gpu/drm/msm/disp/mdp_format.c13
-rw-r--r--drivers/gpu/drm/msm/disp/mdp_kms.c13
-rw-r--r--drivers/gpu/drm/msm/disp/mdp_kms.h13
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi.c13
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi.h13
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi_audio.c13
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi_bridge.c13
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi_connector.c13
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi_i2c.c13
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c13
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi_phy_8x60.c13
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c13
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c13
-rw-r--r--drivers/gpu/drm/msm/msm_atomic.c13
-rw-r--r--drivers/gpu/drm/msm/msm_debugfs.c13
-rw-r--r--drivers/gpu/drm/msm/msm_debugfs.h13
-rw-r--r--drivers/gpu/drm/msm/msm_drv.c13
-rw-r--r--drivers/gpu/drm/msm/msm_drv.h13
-rw-r--r--drivers/gpu/drm/msm/msm_fb.c13
-rw-r--r--drivers/gpu/drm/msm/msm_fbdev.c13
-rw-r--r--drivers/gpu/drm/msm/msm_fence.c13
-rw-r--r--drivers/gpu/drm/msm/msm_fence.h13
-rw-r--r--drivers/gpu/drm/msm/msm_gem.c13
-rw-r--r--drivers/gpu/drm/msm/msm_gem.h13
-rw-r--r--drivers/gpu/drm/msm/msm_gem_prime.c13
-rw-r--r--drivers/gpu/drm/msm/msm_gem_shrinker.c13
-rw-r--r--drivers/gpu/drm/msm/msm_gem_submit.c13
-rw-r--r--drivers/gpu/drm/msm/msm_gem_vma.c13
-rw-r--r--drivers/gpu/drm/msm/msm_gpu.c13
-rw-r--r--drivers/gpu/drm/msm/msm_gpu.h13
-rw-r--r--drivers/gpu/drm/msm/msm_iommu.c13
-rw-r--r--drivers/gpu/drm/msm/msm_kms.h13
-rw-r--r--drivers/gpu/drm/msm/msm_mmu.h13
-rw-r--r--drivers/gpu/drm/msm/msm_perf.c13
-rw-r--r--drivers/gpu/drm/msm/msm_rd.c13
-rw-r--r--drivers/gpu/drm/msm/msm_ringbuffer.c13
-rw-r--r--drivers/gpu/drm/msm/msm_ringbuffer.h13
-rw-r--r--drivers/gpu/drm/nouveau/Kconfig6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dmem.c103
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_svm.c2
-rw-r--r--drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c5
-rw-r--r--drivers/gpu/drm/omapdrm/displays/connector-hdmi.c5
-rw-r--r--drivers/gpu/drm/omapdrm/displays/encoder-opa362.c5
-rw-r--r--drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c5
-rw-r--r--drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c5
-rw-r--r--drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c5
-rw-r--r--drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c5
-rw-r--r--drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c13
-rw-r--r--drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c13
-rw-r--r--drivers/gpu/drm/omapdrm/dss/core.c13
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dispc.c13
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dispc.h13
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dispc_coefs.c13
-rw-r--r--drivers/gpu/drm/omapdrm/dss/display.c13
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dpi.c13
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dsi.c13
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dss.c13
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dss.h13
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi.h13
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi4.c13
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi4_core.c13
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi4_core.h13
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi5.c13
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi5_core.c13
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi5_core.h13
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi_phy.c5
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi_pll.c5
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi_wp.c5
-rw-r--r--drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c13
-rw-r--r--drivers/gpu/drm/omapdrm/dss/omapdss.h13
-rw-r--r--drivers/gpu/drm/omapdrm/dss/output.c13
-rw-r--r--drivers/gpu/drm/omapdrm/dss/pll.c13
-rw-r--r--drivers/gpu/drm/omapdrm/dss/sdi.c13
-rw-r--r--drivers/gpu/drm/omapdrm/dss/venc.c13
-rw-r--r--drivers/gpu/drm/omapdrm/omap_connector.c13
-rw-r--r--drivers/gpu/drm/omapdrm/omap_connector.h13
-rw-r--r--drivers/gpu/drm/omapdrm/omap_crtc.c13
-rw-r--r--drivers/gpu/drm/omapdrm/omap_crtc.h13
-rw-r--r--drivers/gpu/drm/omapdrm/omap_debugfs.c13
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.c13
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.h13
-rw-r--r--drivers/gpu/drm/omapdrm/omap_encoder.c13
-rw-r--r--drivers/gpu/drm/omapdrm/omap_encoder.h13
-rw-r--r--drivers/gpu/drm/omapdrm/omap_fb.c13
-rw-r--r--drivers/gpu/drm/omapdrm/omap_fb.h13
-rw-r--r--drivers/gpu/drm/omapdrm/omap_fbdev.c13
-rw-r--r--drivers/gpu/drm/omapdrm/omap_fbdev.h13
-rw-r--r--drivers/gpu/drm/omapdrm/omap_gem.c13
-rw-r--r--drivers/gpu/drm/omapdrm/omap_gem.h13
-rw-r--r--drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c13
-rw-r--r--drivers/gpu/drm/omapdrm/omap_irq.c13
-rw-r--r--drivers/gpu/drm/omapdrm/omap_irq.h13
-rw-r--r--drivers/gpu/drm/omapdrm/omap_plane.c13
-rw-r--r--drivers/gpu/drm/omapdrm/omap_plane.h13
-rw-r--r--drivers/gpu/drm/panel/panel-ilitek-ili9322.c5
-rw-r--r--drivers/gpu/drm/panel/panel-jdi-lt070me05000.c13
-rw-r--r--drivers/gpu/drm/panel/panel-lg-lg4573.c5
-rw-r--r--drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c13
-rw-r--r--drivers/gpu/drm/panel/panel-samsung-ld9040.c5
-rw-r--r--drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c5
-rw-r--r--drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c5
-rw-r--r--drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c5
-rw-r--r--drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c5
-rw-r--r--drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c13
-rw-r--r--drivers/gpu/drm/panel/panel-sitronix-st7789v.c5
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_drv.c2
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_gem.c3
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_gem.h1
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_mmu.c8
-rw-r--r--drivers/gpu/drm/pl111/pl111_debugfs.c5
-rw-r--r--drivers/gpu/drm/rockchip/cdn-dp-core.h10
-rw-r--r--drivers/gpu/drm/tegra/dc.c9
-rw-r--r--drivers/gpu/drm/tegra/dc.h5
-rw-r--r--drivers/gpu/drm/tegra/dpaux.c5
-rw-r--r--drivers/gpu/drm/tegra/dpaux.h5
-rw-r--r--drivers/gpu/drm/tegra/drm.c5
-rw-r--r--drivers/gpu/drm/tegra/drm.h5
-rw-r--r--drivers/gpu/drm/tegra/dsi.c5
-rw-r--r--drivers/gpu/drm/tegra/dsi.h5
-rw-r--r--drivers/gpu/drm/tegra/falcon.c5
-rw-r--r--drivers/gpu/drm/tegra/falcon.h5
-rw-r--r--drivers/gpu/drm/tegra/fb.c5
-rw-r--r--drivers/gpu/drm/tegra/gem.c5
-rw-r--r--drivers/gpu/drm/tegra/gem.h5
-rw-r--r--drivers/gpu/drm/tegra/gr2d.c5
-rw-r--r--drivers/gpu/drm/tegra/gr2d.h5
-rw-r--r--drivers/gpu/drm/tegra/gr3d.c5
-rw-r--r--drivers/gpu/drm/tegra/gr3d.h5
-rw-r--r--drivers/gpu/drm/tegra/hdmi.c5
-rw-r--r--drivers/gpu/drm/tegra/hdmi.h5
-rw-r--r--drivers/gpu/drm/tegra/hub.c5
-rw-r--r--drivers/gpu/drm/tegra/hub.h5
-rw-r--r--drivers/gpu/drm/tegra/mipi-phy.c5
-rw-r--r--drivers/gpu/drm/tegra/mipi-phy.h5
-rw-r--r--drivers/gpu/drm/tegra/output.c5
-rw-r--r--drivers/gpu/drm/tegra/plane.c5
-rw-r--r--drivers/gpu/drm/tegra/plane.h5
-rw-r--r--drivers/gpu/drm/tegra/rgb.c5
-rw-r--r--drivers/gpu/drm/tegra/sor.c5
-rw-r--r--drivers/gpu/drm/tegra/sor.h5
-rw-r--r--drivers/gpu/drm/tegra/vic.c5
-rw-r--r--drivers/gpu/drm/tegra/vic.h5
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_crtc.c13
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_drv.c13
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_drv.h13
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_external.c6
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_external.h13
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_panel.c13
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_panel.h13
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_plane.c13
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_regs.h13
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_tfp410.c13
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_tfp410.h13
-rw-r--r--drivers/gpu/drm/vc4/vc4_bo.c5
-rw-r--r--drivers/gpu/drm/vc4/vc4_crtc.c5
-rw-r--r--drivers/gpu/drm/vc4/vc4_debugfs.c5
-rw-r--r--drivers/gpu/drm/vc4/vc4_dpi.c13
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.c5
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.h5
-rw-r--r--drivers/gpu/drm/vc4/vc4_dsi.c13
-rw-r--r--drivers/gpu/drm/vc4/vc4_hdmi.c32
-rw-r--r--drivers/gpu/drm/vc4/vc4_hvs.c5
-rw-r--r--drivers/gpu/drm/vc4/vc4_kms.c5
-rw-r--r--drivers/gpu/drm/vc4/vc4_plane.c5
-rw-r--r--drivers/gpu/drm/vc4/vc4_regs.h5
-rw-r--r--drivers/gpu/drm/vc4/vc4_trace.h5
-rw-r--r--drivers/gpu/drm/vc4/vc4_trace_points.c5
-rw-r--r--drivers/gpu/drm/vc4/vc4_v3d.c13
-rw-r--r--drivers/gpu/drm/vc4/vc4_vec.c13
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_vq.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.c3
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_msg.c146
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c10
-rw-r--r--drivers/gpu/drm/zte/zx_common_regs.h5
-rw-r--r--drivers/gpu/drm/zte/zx_drm_drv.c6
-rw-r--r--drivers/gpu/drm/zte/zx_drm_drv.h6
-rw-r--r--drivers/gpu/drm/zte/zx_hdmi.c6
-rw-r--r--drivers/gpu/drm/zte/zx_hdmi_regs.h6
-rw-r--r--drivers/gpu/drm/zte/zx_plane.c6
-rw-r--r--drivers/gpu/drm/zte/zx_plane.h6
-rw-r--r--drivers/gpu/drm/zte/zx_plane_regs.h6
-rw-r--r--drivers/gpu/drm/zte/zx_tvenc.c6
-rw-r--r--drivers/gpu/drm/zte/zx_tvenc_regs.h6
-rw-r--r--drivers/gpu/drm/zte/zx_vga.c5
-rw-r--r--drivers/gpu/drm/zte/zx_vga_regs.h5
-rw-r--r--drivers/gpu/drm/zte/zx_vou.c6
-rw-r--r--drivers/gpu/drm/zte/zx_vou.h6
-rw-r--r--drivers/gpu/drm/zte/zx_vou_regs.h6
-rw-r--r--drivers/gpu/ipu-v3/ipu-image-convert.c40
-rw-r--r--drivers/hid/hid-asus.c2
-rw-r--r--drivers/hid/hid-cp2112.c7
-rw-r--r--drivers/hid/hid-ids.h5
-rw-r--r--drivers/hid/hid-ite.c5
-rw-r--r--drivers/hid/hid-lg.c2
-rw-r--r--drivers/hid/hid-logitech-dj.c23
-rw-r--r--drivers/hid/hid-logitech-hidpp.c2
-rw-r--r--drivers/hid/hid-multitouch.c4
-rw-r--r--drivers/hid/hid-picolcd_fb.c4
-rw-r--r--drivers/hid/hid-quirks.c24
-rw-r--r--drivers/hid/hid-sensor-custom.c2
-rw-r--r--drivers/hid/hid-uclogic-core.c4
-rw-r--r--drivers/hid/hid-uclogic-params.c4
-rw-r--r--drivers/hid/intel-ish-hid/ipc/pci-ish.c1
-rw-r--r--drivers/hid/intel-ish-hid/ishtp-fw-loader.c2
-rw-r--r--drivers/hid/intel-ish-hid/ishtp-hid-client.c4
-rw-r--r--drivers/hid/intel-ish-hid/ishtp/bus.c15
-rw-r--r--drivers/hid/wacom_sys.c13
-rw-r--r--drivers/hid/wacom_wac.c152
-rw-r--r--drivers/hid/wacom_wac.h3
-rw-r--r--drivers/hv/Kconfig4
-rw-r--r--drivers/hv/hv.c156
-rw-r--r--drivers/hv/hv_util.c1
-rw-r--r--drivers/hv/hyperv_vmbus.h3
-rw-r--r--drivers/hv/vmbus_drv.c49
-rw-r--r--drivers/hwmon/adm1029.c10
-rw-r--r--drivers/hwmon/adt7411.c5
-rw-r--r--drivers/hwmon/adt7475.c5
-rw-r--r--drivers/hwmon/asus_atk0110.c23
-rw-r--r--drivers/hwmon/coretemp.c36
-rw-r--r--drivers/hwmon/gpio-fan.c22
-rw-r--r--drivers/hwmon/hwmon.c6
-rw-r--r--drivers/hwmon/iio_hwmon.c5
-rw-r--r--drivers/hwmon/ina3221.c4
-rw-r--r--drivers/hwmon/lm90.c106
-rw-r--r--drivers/hwmon/max197.c5
-rw-r--r--drivers/hwmon/max6650.c710
-rw-r--r--drivers/hwmon/nct7904.c81
-rw-r--r--drivers/hwmon/occ/common.c10
-rw-r--r--drivers/hwmon/occ/common.h1
-rw-r--r--drivers/hwmon/pmbus/Kconfig18
-rw-r--r--drivers/hwmon/pmbus/Makefile2
-rw-r--r--drivers/hwmon/pmbus/adm1275.c105
-rw-r--r--drivers/hwmon/pmbus/irps5401.c67
-rw-r--r--drivers/hwmon/pmbus/pxe1610.c139
-rw-r--r--drivers/hwmon/pwm-fan.c10
-rw-r--r--drivers/hwmon/scpi-hwmon.c10
-rw-r--r--drivers/hwmon/smsc47m1.c2
-rw-r--r--drivers/hwspinlock/Kconfig2
-rw-r--r--drivers/hwspinlock/hwspinlock_core.c48
-rw-r--r--drivers/hwspinlock/omap_hwspinlock.c4
-rw-r--r--drivers/hwspinlock/stm32_hwspinlock.c7
-rw-r--r--drivers/hwtracing/coresight/Kconfig1
-rw-r--r--drivers/hwtracing/coresight/Makefile3
-rw-r--r--drivers/hwtracing/coresight/coresight-catu.c40
-rw-r--r--drivers/hwtracing/coresight/coresight-catu.h1
-rw-r--r--drivers/hwtracing/coresight/coresight-cpu-debug.c21
-rw-r--r--drivers/hwtracing/coresight/coresight-etb10.c78
-rw-r--r--drivers/hwtracing/coresight/coresight-etm-perf.c8
-rw-r--r--drivers/hwtracing/coresight/coresight-etm.h6
-rw-r--r--drivers/hwtracing/coresight/coresight-etm3x-sysfs.c12
-rw-r--r--drivers/hwtracing/coresight/coresight-etm3x.c49
-rw-r--r--drivers/hwtracing/coresight/coresight-etm4x.c40
-rw-r--r--drivers/hwtracing/coresight/coresight-etm4x.h2
-rw-r--r--drivers/hwtracing/coresight/coresight-funnel.c36
-rw-r--r--drivers/hwtracing/coresight/coresight-platform.c815
-rw-r--r--drivers/hwtracing/coresight/coresight-priv.h4
-rw-r--r--drivers/hwtracing/coresight/coresight-replicator.c43
-rw-r--r--drivers/hwtracing/coresight/coresight-stm.c118
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc-etf.c43
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc-etr.c80
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc.c96
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc.h2
-rw-r--r--drivers/hwtracing/coresight/coresight-tpiu.c24
-rw-r--r--drivers/hwtracing/coresight/coresight.c170
-rw-r--r--drivers/hwtracing/coresight/of_coresight.c297
-rw-r--r--drivers/hwtracing/intel_th/core.c5
-rw-r--r--drivers/hwtracing/intel_th/msu.c150
-rw-r--r--drivers/hwtracing/intel_th/pci.c5
-rw-r--r--drivers/i2c/busses/Kconfig13
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-acorn.c5
-rw-r--r--drivers/i2c/busses/i2c-amd-mp2-pci.c2
-rw-r--r--drivers/i2c/busses/i2c-aspeed.c5
-rw-r--r--drivers/i2c/busses/i2c-axxia.c5
-rw-r--r--drivers/i2c/busses/i2c-bcm-iproc.c117
-rw-r--r--drivers/i2c/busses/i2c-bcm2835.c135
-rw-r--r--drivers/i2c/busses/i2c-cpm.c4
-rw-r--r--drivers/i2c/busses/i2c-digicolor.c5
-rw-r--r--drivers/i2c/busses/i2c-efm32.c5
-rw-r--r--drivers/i2c/busses/i2c-exynos5.c5
-rw-r--r--drivers/i2c/busses/i2c-fsi.c32
-rw-r--r--drivers/i2c/busses/i2c-gpio.c5
-rw-r--r--drivers/i2c/busses/i2c-i801.c206
-rw-r--r--drivers/i2c/busses/i2c-img-scb.c5
-rw-r--r--drivers/i2c/busses/i2c-imx.c11
-rw-r--r--drivers/i2c/busses/i2c-iop3xx.c32
-rw-r--r--drivers/i2c/busses/i2c-iop3xx.h2
-rw-r--r--drivers/i2c/busses/i2c-meson.c5
-rw-r--r--drivers/i2c/busses/i2c-mt7621.c356
-rw-r--r--drivers/i2c/busses/i2c-nomadik.c5
-rw-r--r--drivers/i2c/busses/i2c-nvidia-gpu.c64
-rw-r--r--drivers/i2c/busses/i2c-ocores.c33
-rw-r--r--drivers/i2c/busses/i2c-pca-platform.c4
-rw-r--r--drivers/i2c/busses/i2c-puv3.c5
-rw-r--r--drivers/i2c/busses/i2c-pxa-pci.c2
-rw-r--r--drivers/i2c/busses/i2c-pxa.c5
-rw-r--r--drivers/i2c/busses/i2c-qcom-geni.c17
-rw-r--r--drivers/i2c/busses/i2c-rk3x.c5
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c47
-rw-r--r--drivers/i2c/busses/i2c-simtec.c10
-rw-r--r--drivers/i2c/busses/i2c-st.c5
-rw-r--r--drivers/i2c/busses/i2c-stm32f7.c32
-rw-r--r--drivers/i2c/busses/i2c-tegra.c136
-rw-r--r--drivers/i2c/busses/i2c-versatile.c5
-rw-r--r--drivers/i2c/busses/i2c-zx2967.c5
-rw-r--r--drivers/i2c/i2c-core-acpi.c71
-rw-r--r--drivers/i2c/i2c-core-base.c20
-rw-r--r--drivers/i2c/i2c-core-of.c5
-rw-r--r--drivers/i2c/i2c-core.h9
-rw-r--r--drivers/i2c/i2c-mux.c4
-rw-r--r--drivers/i2c/muxes/i2c-arb-gpio-challenge.c79
-rw-r--r--drivers/i2c/muxes/i2c-mux-gpio.c121
-rw-r--r--drivers/i2c/muxes/i2c-mux-gpmux.c5
-rw-r--r--drivers/i2c/muxes/i2c-mux-pinctrl.c5
-rw-r--r--drivers/i3c/master.c82
-rw-r--r--drivers/i3c/master/dw-i3c-master.c7
-rw-r--r--drivers/i3c/master/i3c-master-cdns.c10
-rw-r--r--drivers/ide/Kconfig20
-rw-r--r--drivers/ide/amd74xx.c6
-rw-r--r--drivers/ide/cs5535.c5
-rw-r--r--drivers/ide/ide-cd.c2
-rw-r--r--drivers/ide/via82cxxx.c6
-rw-r--r--drivers/iio/Kconfig2
-rw-r--r--drivers/iio/accel/adis16201.c4
-rw-r--r--drivers/iio/accel/adis16209.c4
-rw-r--r--drivers/iio/accel/adxl372.c27
-rw-r--r--drivers/iio/accel/adxl372_spi.c9
-rw-r--r--drivers/iio/accel/kxcjk-1013.c1
-rw-r--r--drivers/iio/accel/kxsd9-spi.c9
-rw-r--r--drivers/iio/accel/kxsd9.c5
-rw-r--r--drivers/iio/accel/mma7455.h5
-rw-r--r--drivers/iio/accel/mma7455_core.c5
-rw-r--r--drivers/iio/accel/mma7455_i2c.c5
-rw-r--r--drivers/iio/accel/mma7455_spi.c5
-rw-r--r--drivers/iio/accel/sca3000.c12
-rw-r--r--drivers/iio/accel/st_accel_buffer.c22
-rw-r--r--drivers/iio/adc/Kconfig1
-rw-r--r--drivers/iio/adc/ad7124.c33
-rw-r--r--drivers/iio/adc/ad7606.c97
-rw-r--r--drivers/iio/adc/ad7606.h17
-rw-r--r--drivers/iio/adc/ad799x.c6
-rw-r--r--drivers/iio/adc/ad_sigma_delta.c3
-rw-r--r--drivers/iio/adc/at91-sama5d2_adc.c12
-rw-r--r--drivers/iio/adc/at91_adc.c4
-rw-r--r--drivers/iio/adc/axp20x_adc.c5
-rw-r--r--drivers/iio/adc/bcm_iproc_adc.c13
-rw-r--r--drivers/iio/adc/cc10001_adc.c6
-rw-r--r--drivers/iio/adc/ep93xx_adc.c5
-rw-r--r--drivers/iio/adc/fsl-imx25-gcq.c5
-rw-r--r--drivers/iio/adc/imx7d_adc.c24
-rw-r--r--drivers/iio/adc/lp8788_adc.c5
-rw-r--r--drivers/iio/adc/lpc18xx_adc.c5
-rw-r--r--drivers/iio/adc/ltc2485.c5
-rw-r--r--drivers/iio/adc/max1027.c5
-rw-r--r--drivers/iio/adc/max1363.c5
-rw-r--r--drivers/iio/adc/mcp320x.c5
-rw-r--r--drivers/iio/adc/meson_saradc.c2
-rw-r--r--drivers/iio/adc/mt6577_auxadc.c54
-rw-r--r--drivers/iio/adc/rcar-gyroadc.c4
-rw-r--r--drivers/iio/adc/stm32-adc-core.c21
-rw-r--r--drivers/iio/adc/stm32-dfsdm-adc.c239
-rw-r--r--drivers/iio/adc/stm32-dfsdm-core.c8
-rw-r--r--drivers/iio/adc/stm32-dfsdm.h24
-rw-r--r--drivers/iio/adc/stmpe-adc.c40
-rw-r--r--drivers/iio/adc/sun4i-gpadc-iio.c5
-rw-r--r--drivers/iio/adc/ti-adc081c.c5
-rw-r--r--drivers/iio/adc/ti-adc084s021.c5
-rw-r--r--drivers/iio/adc/ti-ads8688.c5
-rw-r--r--drivers/iio/adc/ti-tlc4541.c5
-rw-r--r--drivers/iio/amplifiers/Kconfig13
-rw-r--r--drivers/iio/amplifiers/ad8366.c146
-rw-r--r--drivers/iio/buffer/industrialio-buffer-cb.c5
-rw-r--r--drivers/iio/buffer/industrialio-triggered-buffer.c5
-rw-r--r--drivers/iio/chemical/ccs811.c5
-rw-r--r--drivers/iio/common/cros_ec_sensors/Kconfig9
-rw-r--r--drivers/iio/common/cros_ec_sensors/Makefile1
-rw-r--r--drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c139
-rw-r--r--drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c14
-rw-r--r--drivers/iio/common/ms_sensors/ms_sensors_i2c.h5
-rw-r--r--drivers/iio/dac/ad5758.c18
-rw-r--r--drivers/iio/dac/ds4424.c11
-rw-r--r--drivers/iio/dac/lpc18xx_dac.c5
-rw-r--r--drivers/iio/dac/max5821.c5
-rw-r--r--drivers/iio/dac/ti-dac082s085.c5
-rw-r--r--drivers/iio/dac/ti-dac5571.c5
-rw-r--r--drivers/iio/dummy/iio_dummy_evgen.c5
-rw-r--r--drivers/iio/dummy/iio_simple_dummy.c5
-rw-r--r--drivers/iio/dummy/iio_simple_dummy.h5
-rw-r--r--drivers/iio/dummy/iio_simple_dummy_buffer.c5
-rw-r--r--drivers/iio/dummy/iio_simple_dummy_events.c5
-rw-r--r--drivers/iio/frequency/Kconfig10
-rw-r--r--drivers/iio/frequency/Makefile1
-rw-r--r--drivers/iio/frequency/ad9523.c8
-rw-r--r--drivers/iio/frequency/adf4371.c632
-rw-r--r--drivers/iio/gyro/itg3200_buffer.c5
-rw-r--r--drivers/iio/gyro/itg3200_core.c5
-rw-r--r--drivers/iio/humidity/dht11.c36
-rw-r--r--drivers/iio/humidity/si7020.c10
-rw-r--r--drivers/iio/iio_core.h5
-rw-r--r--drivers/iio/iio_core_trigger.h5
-rw-r--r--drivers/iio/imu/adis16400.c6
-rw-r--r--drivers/iio/imu/adis16480.c6
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h11
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c78
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c3
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c3
-rw-r--r--drivers/iio/industrialio-buffer.c6
-rw-r--r--drivers/iio/industrialio-configfs.c5
-rw-r--r--drivers/iio/industrialio-core.c46
-rw-r--r--drivers/iio/industrialio-event.c5
-rw-r--r--drivers/iio/industrialio-sw-device.c5
-rw-r--r--drivers/iio/industrialio-sw-trigger.c5
-rw-r--r--drivers/iio/industrialio-trigger.c5
-rw-r--r--drivers/iio/inkern.c7
-rw-r--r--drivers/iio/light/bh1780.c2
-rw-r--r--drivers/iio/light/cm32181.c5
-rw-r--r--drivers/iio/light/cm3232.c5
-rw-r--r--drivers/iio/light/cm36651.c5
-rw-r--r--drivers/iio/light/gp2ap020a00f.c5
-rw-r--r--drivers/iio/light/pa12203001.c4
-rw-r--r--drivers/iio/light/stk3310.c6
-rw-r--r--drivers/iio/light/us5182d.c10
-rw-r--r--drivers/iio/magnetometer/hmc5843.h5
-rw-r--r--drivers/iio/magnetometer/hmc5843_i2c.c5
-rw-r--r--drivers/iio/magnetometer/hmc5843_spi.c5
-rw-r--r--drivers/iio/potentiometer/ds1803.c5
-rw-r--r--drivers/iio/potentiometer/max5481.c6
-rw-r--r--drivers/iio/potentiometer/max5487.c6
-rw-r--r--drivers/iio/potentiometer/mcp4131.c5
-rw-r--r--drivers/iio/pressure/Kconfig11
-rw-r--r--drivers/iio/pressure/Makefile1
-rw-r--r--drivers/iio/pressure/bmp280-core.c5
-rw-r--r--drivers/iio/pressure/dps310.c827
-rw-r--r--drivers/iio/pressure/hp03.c5
-rw-r--r--drivers/iio/proximity/sx9500.c5
-rw-r--r--drivers/iio/resolver/ad2s1200.c5
-rw-r--r--drivers/iio/temperature/maxim_thermocouple.c10
-rw-r--r--drivers/iio/temperature/mlx90632.c9
-rw-r--r--drivers/iio/trigger/iio-trig-hrtimer.c6
-rw-r--r--drivers/iio/trigger/iio-trig-interrupt.c5
-rw-r--r--drivers/infiniband/Kconfig14
-rw-r--r--drivers/infiniband/core/Makefile5
-rw-r--r--drivers/infiniband/core/addr.c2
-rw-r--r--drivers/infiniband/core/core_priv.h10
-rw-r--r--drivers/infiniband/core/counters.c634
-rw-r--r--drivers/infiniband/core/cq.c95
-rw-r--r--drivers/infiniband/core/device.c158
-rw-r--r--drivers/infiniband/core/mr_pool.c8
-rw-r--r--drivers/infiniband/core/nldev.c800
-rw-r--r--drivers/infiniband/core/restrack.c49
-rw-r--r--drivers/infiniband/core/restrack.h3
-rw-r--r--drivers/infiniband/core/roce_gid_mgmt.c5
-rw-r--r--drivers/infiniband/core/rw.c201
-rw-r--r--drivers/infiniband/core/sysfs.c16
-rw-r--r--drivers/infiniband/core/ucm.c1350
-rw-r--r--drivers/infiniband/core/ucma.c114
-rw-r--r--drivers/infiniband/core/umem.c13
-rw-r--r--drivers/infiniband/core/umem_odp.c106
-rw-r--r--drivers/infiniband/core/user_mad.c53
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c28
-rw-r--r--drivers/infiniband/core/uverbs_ioctl.c2
-rw-r--r--drivers/infiniband/core/uverbs_main.c40
-rw-r--r--drivers/infiniband/core/uverbs_std_types_cq.c19
-rw-r--r--drivers/infiniband/core/uverbs_std_types_mr.c1
-rw-r--r--drivers/infiniband/core/uverbs_uapi.c4
-rw-r--r--drivers/infiniband/core/verbs.c165
-rw-r--r--drivers/infiniband/hw/Makefile1
-rw-r--r--drivers/infiniband/hw/bnxt_re/ib_verbs.c66
-rw-r--r--drivers/infiniband/hw/bnxt_re/ib_verbs.h9
-rw-r--r--drivers/infiniband/hw/bnxt_re/main.c8
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_hal.c33
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_hal.h3
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_cm.c2
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.c160
-rw-r--r--drivers/infiniband/hw/cxgb4/cm.c30
-rw-r--r--drivers/infiniband/hw/cxgb4/cq.c55
-rw-r--r--drivers/infiniband/hw/cxgb4/device.c9
-rw-r--r--drivers/infiniband/hw/cxgb4/iw_cxgb4.h11
-rw-r--r--drivers/infiniband/hw/cxgb4/mem.c8
-rw-r--r--drivers/infiniband/hw/cxgb4/provider.c9
-rw-r--r--drivers/infiniband/hw/cxgb4/qp.c95
-rw-r--r--drivers/infiniband/hw/cxgb4/resource.c16
-rw-r--r--drivers/infiniband/hw/efa/efa.h9
-rw-r--r--drivers/infiniband/hw/efa/efa_com.c118
-rw-r--r--drivers/infiniband/hw/efa/efa_com.h1
-rw-r--r--drivers/infiniband/hw/efa/efa_com_cmd.c32
-rw-r--r--drivers/infiniband/hw/efa/efa_main.c10
-rw-r--r--drivers/infiniband/hw/efa/efa_verbs.c269
-rw-r--r--drivers/infiniband/hw/hfi1/Makefile1
-rw-r--r--drivers/infiniband/hw/hfi1/affinity.c6
-rw-r--r--drivers/infiniband/hw/hfi1/aspm.c270
-rw-r--r--drivers/infiniband/hw/hfi1/aspm.h262
-rw-r--r--drivers/infiniband/hw/hfi1/chip.c13
-rw-r--r--drivers/infiniband/hw/hfi1/chip.h1
-rw-r--r--drivers/infiniband/hw/hfi1/debugfs.c5
-rw-r--r--drivers/infiniband/hw/hfi1/fault.c5
-rw-r--r--drivers/infiniband/hw/hfi1/hfi.h31
-rw-r--r--drivers/infiniband/hw/hfi1/mad.c9
-rw-r--r--drivers/infiniband/hw/hfi1/pcie.c6
-rw-r--r--drivers/infiniband/hw/hfi1/pio.c24
-rw-r--r--drivers/infiniband/hw/hfi1/qp.c8
-rw-r--r--drivers/infiniband/hw/hfi1/rc.c82
-rw-r--r--drivers/infiniband/hw/hfi1/sdma.c29
-rw-r--r--drivers/infiniband/hw/hfi1/tid_rdma.c11
-rw-r--r--drivers/infiniband/hw/hfi1/trace_ibhdrs.h2
-rw-r--r--drivers/infiniband/hw/hfi1/uc.c3
-rw-r--r--drivers/infiniband/hw/hfi1/ud.c40
-rw-r--r--drivers/infiniband/hw/hfi1/user_pages.c11
-rw-r--r--drivers/infiniband/hw/hfi1/user_sdma.c12
-rw-r--r--drivers/infiniband/hw/hfi1/user_sdma.h1
-rw-r--r--drivers/infiniband/hw/hfi1/verbs.c20
-rw-r--r--drivers/infiniband/hw/hfi1/verbs.h1
-rw-r--r--drivers/infiniband/hw/hfi1/verbs_txreq.c2
-rw-r--r--drivers/infiniband/hw/hfi1/verbs_txreq.h3
-rw-r--r--drivers/infiniband/hw/hns/Kconfig15
-rw-r--r--drivers/infiniband/hw/hns/Makefile15
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_alloc.c101
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_cmd.c6
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_cq.c81
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_db.c12
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_device.h108
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_hem.c504
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_hem.h16
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_hw_v1.c81
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_hw_v2.c280
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_hw_v2.h23
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_main.c31
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_mr.c166
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_pd.c4
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_qp.c220
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_srq.c40
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_cm.c11
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_main.c6
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_utils.c12
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_verbs.c56
-rw-r--r--drivers/infiniband/hw/mlx4/alias_GUID.c6
-rw-r--r--drivers/infiniband/hw/mlx4/cq.c43
-rw-r--r--drivers/infiniband/hw/mlx4/main.c21
-rw-r--r--drivers/infiniband/hw/mlx4/mlx4_ib.h9
-rw-r--r--drivers/infiniband/hw/mlx4/mr.c16
-rw-r--r--drivers/infiniband/hw/mlx4/qp.c11
-rw-r--r--drivers/infiniband/hw/mlx4/srq.c9
-rw-r--r--drivers/infiniband/hw/mlx5/cq.c69
-rw-r--r--drivers/infiniband/hw/mlx5/devx.c1067
-rw-r--r--drivers/infiniband/hw/mlx5/flow.c13
-rw-r--r--drivers/infiniband/hw/mlx5/ib_rep.c39
-rw-r--r--drivers/infiniband/hw/mlx5/ib_rep.h4
-rw-r--r--drivers/infiniband/hw/mlx5/mad.c60
-rw-r--r--drivers/infiniband/hw/mlx5/main.c236
-rw-r--r--drivers/infiniband/hw/mlx5/mem.c20
-rw-r--r--drivers/infiniband/hw/mlx5/mlx5_ib.h50
-rw-r--r--drivers/infiniband/hw/mlx5/mr.c564
-rw-r--r--drivers/infiniband/hw/mlx5/odp.c56
-rw-r--r--drivers/infiniband/hw/mlx5/qp.c314
-rw-r--r--drivers/infiniband/hw/mthca/mthca_allocator.c2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_memfree.c6
-rw-r--r--drivers/infiniband/hw/mthca/mthca_provider.c52
-rw-r--r--drivers/infiniband/hw/nes/Kconfig16
-rw-r--r--drivers/infiniband/hw/nes/Makefile4
-rw-r--r--drivers/infiniband/hw/nes/nes.c1205
-rw-r--r--drivers/infiniband/hw/nes/nes.h574
-rw-r--r--drivers/infiniband/hw/nes/nes_cm.c3992
-rw-r--r--drivers/infiniband/hw/nes/nes_cm.h470
-rw-r--r--drivers/infiniband/hw/nes/nes_context.h193
-rw-r--r--drivers/infiniband/hw/nes/nes_hw.c3887
-rw-r--r--drivers/infiniband/hw/nes/nes_hw.h1380
-rw-r--r--drivers/infiniband/hw/nes/nes_mgt.c1155
-rw-r--r--drivers/infiniband/hw/nes/nes_mgt.h97
-rw-r--r--drivers/infiniband/hw/nes/nes_nic.c1870
-rw-r--r--drivers/infiniband/hw/nes/nes_utils.c916
-rw-r--r--drivers/infiniband/hw/nes/nes_verbs.c3759
-rw-r--r--drivers/infiniband/hw/nes/nes_verbs.h198
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_hw.c11
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_hw.h2
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_main.c8
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_verbs.c38
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_verbs.h7
-rw-r--r--drivers/infiniband/hw/qedr/main.c33
-rw-r--r--drivers/infiniband/hw/qedr/qedr.h2
-rw-r--r--drivers/infiniband/hw/qedr/verbs.c82
-rw-r--r--drivers/infiniband/hw/qedr/verbs.h7
-rw-r--r--drivers/infiniband/hw/qib/qib_file_ops.c7
-rw-r--r--drivers/infiniband/hw/qib/qib_fs.c26
-rw-r--r--drivers/infiniband/hw/qib/qib_qp.c4
-rw-r--r--drivers/infiniband/hw/qib/qib_rc.c29
-rw-r--r--drivers/infiniband/hw/qib/qib_uc.c3
-rw-r--r--drivers/infiniband/hw/qib/qib_ud.c28
-rw-r--r--drivers/infiniband/hw/qib/qib_user_pages.c11
-rw-r--r--drivers/infiniband/hw/qib/qib_user_sdma.c11
-rw-r--r--drivers/infiniband/hw/qib/qib_verbs.c6
-rw-r--r--drivers/infiniband/hw/usnic/usnic_ib.h4
-rw-r--r--drivers/infiniband/hw/usnic/usnic_ib_main.c23
-rw-r--r--drivers/infiniband/hw/usnic/usnic_ib_verbs.c22
-rw-r--r--drivers/infiniband/hw/usnic/usnic_ib_verbs.h7
-rw-r--r--drivers/infiniband/hw/usnic/usnic_uiom.c7
-rw-r--r--drivers/infiniband/hw/vmw_pvrdma/pvrdma.h2
-rw-r--r--drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c46
-rw-r--r--drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c8
-rw-r--r--drivers/infiniband/hw/vmw_pvrdma/pvrdma_mr.c3
-rw-r--r--drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c16
-rw-r--r--drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.h7
-rw-r--r--drivers/infiniband/sw/Makefile1
-rw-r--r--drivers/infiniband/sw/rdmavt/ah.c6
-rw-r--r--drivers/infiniband/sw/rdmavt/cq.c250
-rw-r--r--drivers/infiniband/sw/rdmavt/cq.h7
-rw-r--r--drivers/infiniband/sw/rdmavt/mr.c6
-rw-r--r--drivers/infiniband/sw/rdmavt/qp.c402
-rw-r--r--drivers/infiniband/sw/rdmavt/qp.h2
-rw-r--r--drivers/infiniband/sw/rdmavt/rc.c41
-rw-r--r--drivers/infiniband/sw/rdmavt/srq.c69
-rw-r--r--drivers/infiniband/sw/rdmavt/trace_mr.h56
-rw-r--r--drivers/infiniband/sw/rdmavt/vt.c7
-rw-r--r--drivers/infiniband/sw/rdmavt/vt.h9
-rw-r--r--drivers/infiniband/sw/rxe/rxe_comp.c2
-rw-r--r--drivers/infiniband/sw/rxe/rxe_mr.c3
-rw-r--r--drivers/infiniband/sw/rxe/rxe_pool.c1
-rw-r--r--drivers/infiniband/sw/rxe/rxe_resp.c5
-rw-r--r--drivers/infiniband/sw/rxe/rxe_verbs.c40
-rw-r--r--drivers/infiniband/sw/rxe/rxe_verbs.h3
-rw-r--r--drivers/infiniband/sw/siw/Kconfig18
-rw-r--r--drivers/infiniband/sw/siw/Makefile11
-rw-r--r--drivers/infiniband/sw/siw/iwarp.h380
-rw-r--r--drivers/infiniband/sw/siw/siw.h745
-rw-r--r--drivers/infiniband/sw/siw/siw_cm.c2070
-rw-r--r--drivers/infiniband/sw/siw/siw_cm.h133
-rw-r--r--drivers/infiniband/sw/siw/siw_cq.c101
-rw-r--r--drivers/infiniband/sw/siw/siw_main.c685
-rw-r--r--drivers/infiniband/sw/siw/siw_mem.c460
-rw-r--r--drivers/infiniband/sw/siw/siw_mem.h74
-rw-r--r--drivers/infiniband/sw/siw/siw_qp.c1322
-rw-r--r--drivers/infiniband/sw/siw/siw_qp_rx.c1458
-rw-r--r--drivers/infiniband/sw/siw/siw_qp_tx.c1269
-rw-r--r--drivers/infiniband/sw/siw/siw_verbs.c1760
-rw-r--r--drivers/infiniband/sw/siw/siw_verbs.h91
-rw-r--r--drivers/infiniband/ulp/ipoib/Kconfig2
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_cm.c1
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ethtool.c3
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c35
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_verbs.c7
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c12
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.h64
-rw-r--r--drivers/infiniband/ulp/iser/iser_initiator.c12
-rw-r--r--drivers/infiniband/ulp/iser/iser_memory.c121
-rw-r--r--drivers/infiniband/ulp/iser/iser_verbs.c156
-rw-r--r--drivers/infiniband/ulp/isert/ib_isert.c19
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c42
-rw-r--r--drivers/input/apm-power.c6
-rw-r--r--drivers/input/evdev.c5
-rw-r--r--drivers/input/gameport/gameport.c6
-rw-r--r--drivers/input/input-compat.c5
-rw-r--r--drivers/input/input-compat.h5
-rw-r--r--drivers/input/input-leds.c5
-rw-r--r--drivers/input/input-mt.c5
-rw-r--r--drivers/input/input-polldev.c5
-rw-r--r--drivers/input/input.c6
-rw-r--r--drivers/input/joydev.c24
-rw-r--r--drivers/input/joystick/iforce/Kconfig8
-rw-r--r--drivers/input/joystick/iforce/Makefile7
-rw-r--r--drivers/input/joystick/iforce/iforce-ff.c18
-rw-r--r--drivers/input/joystick/iforce/iforce-main.c178
-rw-r--r--drivers/input/joystick/iforce/iforce-packets.c215
-rw-r--r--drivers/input/joystick/iforce/iforce-serio.c161
-rw-r--r--drivers/input/joystick/iforce/iforce-usb.c192
-rw-r--r--drivers/input/joystick/iforce/iforce.h55
-rw-r--r--drivers/input/joystick/walkera0701.c6
-rw-r--r--drivers/input/keyboard/adc-keys.c5
-rw-r--r--drivers/input/keyboard/atkbd.c6
-rw-r--r--drivers/input/keyboard/cap11xx.c5
-rw-r--r--drivers/input/keyboard/cros_ec_keyb.c2
-rw-r--r--drivers/input/keyboard/ep93xx_keypad.c5
-rw-r--r--drivers/input/keyboard/gpio_keys.c11
-rw-r--r--drivers/input/keyboard/gpio_keys_polled.c15
-rw-r--r--drivers/input/keyboard/imx_keypad.c22
-rw-r--r--drivers/input/keyboard/ipaq-micro-keys.c5
-rw-r--r--drivers/input/keyboard/jornada680_kbd.c5
-rw-r--r--drivers/input/keyboard/jornada720_kbd.c6
-rw-r--r--drivers/input/keyboard/matrix_keypad.c6
-rw-r--r--drivers/input/keyboard/max7359_keypad.c5
-rw-r--r--drivers/input/keyboard/mpr121_touchkey.c6
-rw-r--r--drivers/input/keyboard/nspire-keypad.c5
-rw-r--r--drivers/input/keyboard/pxa27x_keypad.c5
-rw-r--r--drivers/input/keyboard/pxa930_rotary.c5
-rw-r--r--drivers/input/keyboard/sh_keysc.c5
-rw-r--r--drivers/input/keyboard/st-keyscan.c5
-rw-r--r--drivers/input/keyboard/stmpe-keypad.c2
-rw-r--r--drivers/input/keyboard/tc3589x-keypad.c3
-rw-r--r--drivers/input/keyboard/tca6416-keypad.c5
-rw-r--r--drivers/input/keyboard/tca8418_keypad.c3
-rw-r--r--drivers/input/keyboard/tm2-touchkey.c5
-rw-r--r--drivers/input/misc/apanel.c5
-rw-r--r--drivers/input/misc/arizona-haptics.c5
-rw-r--r--drivers/input/misc/ati_remote2.c5
-rw-r--r--drivers/input/misc/cma3000_d0x.c13
-rw-r--r--drivers/input/misc/cma3000_d0x.h13
-rw-r--r--drivers/input/misc/cma3000_d0x_i2c.c13
-rw-r--r--drivers/input/misc/da9063_onkey.c11
-rw-r--r--drivers/input/misc/gp2ap002a00f.c5
-rw-r--r--drivers/input/misc/ims-pcu.c5
-rw-r--r--drivers/input/misc/ixp4xx-beeper.c6
-rw-r--r--drivers/input/misc/m68kspkr.c7
-rw-r--r--drivers/input/misc/max77650-onkey.c1
-rw-r--r--drivers/input/misc/pcap_keys.c6
-rw-r--r--drivers/input/misc/pcspkr.c7
-rw-r--r--drivers/input/misc/regulator-haptic.c5
-rw-r--r--drivers/input/misc/rotary_encoder.c5
-rw-r--r--drivers/input/misc/uinput.c22
-rw-r--r--drivers/input/mouse/alps.c5
-rw-r--r--drivers/input/mouse/alps.h5
-rw-r--r--drivers/input/mouse/amimouse.c6
-rw-r--r--drivers/input/mouse/atarimouse.c7
-rw-r--r--drivers/input/mouse/byd.c5
-rw-r--r--drivers/input/mouse/cypress_ps2.c5
-rw-r--r--drivers/input/mouse/elan_i2c.h5
-rw-r--r--drivers/input/mouse/elan_i2c_core.c129
-rw-r--r--drivers/input/mouse/elan_i2c_i2c.c5
-rw-r--r--drivers/input/mouse/elan_i2c_smbus.c5
-rw-r--r--drivers/input/mouse/elantech.c325
-rw-r--r--drivers/input/mouse/elantech.h13
-rw-r--r--drivers/input/mouse/gpio_mouse.c5
-rw-r--r--drivers/input/mouse/hgpk.c5
-rw-r--r--drivers/input/mouse/lifebook.c5
-rw-r--r--drivers/input/mouse/lifebook.h5
-rw-r--r--drivers/input/mouse/logips2pp.c5
-rw-r--r--drivers/input/mouse/logips2pp.h5
-rw-r--r--drivers/input/mouse/navpoint.c5
-rw-r--r--drivers/input/mouse/psmouse-base.c6
-rw-r--r--drivers/input/mouse/psmouse-smbus.c5
-rw-r--r--drivers/input/mouse/pxa930_trkball.c5
-rw-r--r--drivers/input/mouse/rpcmouse.c5
-rw-r--r--drivers/input/mouse/synaptics.c8
-rw-r--r--drivers/input/mouse/synaptics.h5
-rw-r--r--drivers/input/mouse/touchkit_ps2.h5
-rw-r--r--drivers/input/mouse/trackpoint.c5
-rw-r--r--drivers/input/mouse/trackpoint.h5
-rw-r--r--drivers/input/mouse/vmmouse.c5
-rw-r--r--drivers/input/mouse/vmmouse.h5
-rw-r--r--drivers/input/mousedev.c7
-rw-r--r--drivers/input/rmi4/rmi_2d_sensor.c5
-rw-r--r--drivers/input/rmi4/rmi_2d_sensor.h5
-rw-r--r--drivers/input/rmi4/rmi_bus.c5
-rw-r--r--drivers/input/rmi4/rmi_bus.h5
-rw-r--r--drivers/input/rmi4/rmi_driver.c5
-rw-r--r--drivers/input/rmi4/rmi_driver.h5
-rw-r--r--drivers/input/rmi4/rmi_f01.c5
-rw-r--r--drivers/input/rmi4/rmi_f03.c5
-rw-r--r--drivers/input/rmi4/rmi_f11.c5
-rw-r--r--drivers/input/rmi4/rmi_f12.c11
-rw-r--r--drivers/input/rmi4/rmi_f30.c5
-rw-r--r--drivers/input/rmi4/rmi_f34.c5
-rw-r--r--drivers/input/rmi4/rmi_f34.h5
-rw-r--r--drivers/input/rmi4/rmi_f34v7.c5
-rw-r--r--drivers/input/rmi4/rmi_f54.c5
-rw-r--r--drivers/input/rmi4/rmi_f55.c5
-rw-r--r--drivers/input/rmi4/rmi_i2c.c5
-rw-r--r--drivers/input/rmi4/rmi_smbus.c5
-rw-r--r--drivers/input/rmi4/rmi_spi.c5
-rw-r--r--drivers/input/serio/altera_ps2.c5
-rw-r--r--drivers/input/serio/ams_delta_serio.c5
-rw-r--r--drivers/input/serio/arc_ps2.c5
-rw-r--r--drivers/input/serio/i8042-io.h6
-rw-r--r--drivers/input/serio/i8042-ip22io.h6
-rw-r--r--drivers/input/serio/i8042-jazzio.h6
-rw-r--r--drivers/input/serio/i8042-ppcio.h6
-rw-r--r--drivers/input/serio/i8042-snirm.h6
-rw-r--r--drivers/input/serio/i8042-unicore32io.h5
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h6
-rw-r--r--drivers/input/serio/i8042.c8
-rw-r--r--drivers/input/serio/i8042.h5
-rw-r--r--drivers/input/serio/libps2.c6
-rw-r--r--drivers/input/serio/maceps2.c5
-rw-r--r--drivers/input/serio/parkbd.c6
-rw-r--r--drivers/input/serio/ps2-gpio.c5
-rw-r--r--drivers/input/serio/ps2mult.c5
-rw-r--r--drivers/input/serio/serio_raw.c5
-rw-r--r--drivers/input/serio/serport.c6
-rw-r--r--drivers/input/sparse-keymap.c5
-rw-r--r--drivers/input/touchscreen/88pm860x-ts.c5
-rw-r--r--drivers/input/touchscreen/ads7846.c5
-rw-r--r--drivers/input/touchscreen/atmel_mxt_ts.c23
-rw-r--r--drivers/input/touchscreen/da9034-ts.c5
-rw-r--r--drivers/input/touchscreen/dynapro.c7
-rw-r--r--drivers/input/touchscreen/edt-ft5x06.c18
-rw-r--r--drivers/input/touchscreen/eeti_ts.c71
-rw-r--r--drivers/input/touchscreen/egalax_ts_serial.c6
-rw-r--r--drivers/input/touchscreen/elants_i2c.c7
-rw-r--r--drivers/input/touchscreen/elo.c6
-rw-r--r--drivers/input/touchscreen/exc3000.c5
-rw-r--r--drivers/input/touchscreen/fujitsu_ts.c6
-rw-r--r--drivers/input/touchscreen/hampshire.c7
-rw-r--r--drivers/input/touchscreen/hideep.c5
-rw-r--r--drivers/input/touchscreen/htcpen.c5
-rw-r--r--drivers/input/touchscreen/imx6ul_tsc.c8
-rw-r--r--drivers/input/touchscreen/inexio.c7
-rw-r--r--drivers/input/touchscreen/ipaq-micro-ts.c5
-rw-r--r--drivers/input/touchscreen/iqs5xx.c26
-rw-r--r--drivers/input/touchscreen/jornada720_ts.c5
-rw-r--r--drivers/input/touchscreen/mc13783_ts.c5
-rw-r--r--drivers/input/touchscreen/mk712.c6
-rw-r--r--drivers/input/touchscreen/mtouch.c6
-rw-r--r--drivers/input/touchscreen/of_touchscreen.c6
-rw-r--r--drivers/input/touchscreen/pcap_ts.c6
-rw-r--r--drivers/input/touchscreen/penmount.c6
-rw-r--r--drivers/input/touchscreen/silead.c1
-rw-r--r--drivers/input/touchscreen/sun4i-ts.c2
-rw-r--r--drivers/input/touchscreen/sur40.c6
-rw-r--r--drivers/input/touchscreen/sx8654.c5
-rw-r--r--drivers/input/touchscreen/touchit213.c6
-rw-r--r--drivers/input/touchscreen/touchright.c6
-rw-r--r--drivers/input/touchscreen/touchwin.c6
-rw-r--r--drivers/input/touchscreen/tsc2007.h5
-rw-r--r--drivers/input/touchscreen/tsc2007_core.c5
-rw-r--r--drivers/input/touchscreen/tsc2007_iio.c5
-rw-r--r--drivers/input/touchscreen/ucb1400_ts.c5
-rw-r--r--drivers/iommu/Kconfig11
-rw-r--r--drivers/iommu/Makefile1
-rw-r--r--drivers/iommu/amd_iommu.c26
-rw-r--r--drivers/iommu/amd_iommu_init.c45
-rw-r--r--drivers/iommu/arm-smmu-v3.c71
-rw-r--r--drivers/iommu/arm-smmu.c6
-rw-r--r--drivers/iommu/dma-iommu.c465
-rw-r--r--drivers/iommu/exynos-iommu.c5
-rw-r--r--drivers/iommu/intel-iommu-debugfs.c137
-rw-r--r--drivers/iommu/intel-iommu.c947
-rw-r--r--drivers/iommu/intel-pasid.c17
-rw-r--r--drivers/iommu/intel-pasid.h26
-rw-r--r--drivers/iommu/intel-svm.c15
-rw-r--r--drivers/iommu/intel_irq_remapping.c4
-rw-r--r--drivers/iommu/io-pgtable-arm-v7s.c30
-rw-r--r--drivers/iommu/io-pgtable-arm.c53
-rw-r--r--drivers/iommu/io-pgtable.c13
-rw-r--r--drivers/iommu/iommu-sysfs.c5
-rw-r--r--drivers/iommu/iommu.c298
-rw-r--r--drivers/iommu/ipmmu-vmsa.c186
-rw-r--r--drivers/iommu/omap-iommu-debug.c40
-rw-r--r--drivers/iommu/omap-iommu.c8
-rw-r--r--drivers/iommu/omap-iommu.h5
-rw-r--r--drivers/iommu/omap-iopgtable.h5
-rw-r--r--drivers/iommu/qcom_iommu.c13
-rw-r--r--drivers/iommu/rockchip-iommu.c5
-rw-r--r--drivers/iommu/tegra-smmu.c5
-rw-r--r--drivers/iommu/virtio-iommu.c1158
-rw-r--r--drivers/ipack/devices/ipoctal.h1
-rw-r--r--drivers/irqchip/Kconfig32
-rw-r--r--drivers/irqchip/Makefile2
-rw-r--r--drivers/irqchip/exynos-combiner.c5
-rw-r--r--drivers/irqchip/irq-al-fic.c278
-rw-r--r--drivers/irqchip/irq-aspeed-i2c-ic.c5
-rw-r--r--drivers/irqchip/irq-ath79-cpu.c5
-rw-r--r--drivers/irqchip/irq-ath79-misc.c5
-rw-r--r--drivers/irqchip/irq-bcm6345-l1.c5
-rw-r--r--drivers/irqchip/irq-bcm7038-l1.c5
-rw-r--r--drivers/irqchip/irq-bcm7120-l2.c5
-rw-r--r--drivers/irqchip/irq-crossbar.c6
-rw-r--r--drivers/irqchip/irq-csky-mpintc.c101
-rw-r--r--drivers/irqchip/irq-gic-common.c13
-rw-r--r--drivers/irqchip/irq-gic-common.h13
-rw-r--r--drivers/irqchip/irq-gic-pm.c13
-rw-r--r--drivers/irqchip/irq-gic-v2m.c90
-rw-r--r--drivers/irqchip/irq-gic-v3-its-pci-msi.c13
-rw-r--r--drivers/irqchip/irq-gic-v3-its-platform-msi.c13
-rw-r--r--drivers/irqchip/irq-gic-v3-its.c50
-rw-r--r--drivers/irqchip/irq-gic-v3.c23
-rw-r--r--drivers/irqchip/irq-gic-v4.c13
-rw-r--r--drivers/irqchip/irq-gic.c5
-rw-r--r--drivers/irqchip/irq-hip04.c5
-rw-r--r--drivers/irqchip/irq-imx-gpcv2.c5
-rw-r--r--drivers/irqchip/irq-ixp4xx.c8
-rw-r--r--drivers/irqchip/irq-ls-scfg-msi.c5
-rw-r--r--drivers/irqchip/irq-mbigen.c16
-rw-r--r--drivers/irqchip/irq-meson-gpio.c16
-rw-r--r--drivers/irqchip/irq-mips-gic.c4
-rw-r--r--drivers/irqchip/irq-mmp.c5
-rw-r--r--drivers/irqchip/irq-nvic.c5
-rw-r--r--drivers/irqchip/irq-partition-percpu.c13
-rw-r--r--drivers/irqchip/irq-renesas-intc-irqpin.c3
-rw-r--r--drivers/irqchip/irq-renesas-irqc.c91
-rw-r--r--drivers/irqchip/irq-renesas-rza1.c284
-rw-r--r--drivers/irqchip/irq-sa11x0.c5
-rw-r--r--drivers/irqchip/irq-sni-exiu.c147
-rw-r--r--drivers/irqchip/irq-st.c5
-rw-r--r--drivers/irqchip/irq-ti-sci-inta.c4
-rw-r--r--drivers/irqchip/irq-vf610-mscm-ir.c6
-rw-r--r--drivers/irqchip/irq-zevio.c6
-rw-r--r--drivers/irqchip/qcom-irq-combiner.c5
-rw-r--r--drivers/isdn/Kconfig51
-rw-r--r--drivers/isdn/Makefile6
-rw-r--r--drivers/isdn/capi/Kconfig29
-rw-r--r--drivers/isdn/capi/Makefile2
-rw-r--r--drivers/isdn/capi/capidrv.c2525
-rw-r--r--drivers/isdn/capi/capidrv.h140
-rw-r--r--drivers/isdn/divert/Makefile10
-rw-r--r--drivers/isdn/divert/divert_init.c82
-rw-r--r--drivers/isdn/divert/divert_procfs.c336
-rw-r--r--drivers/isdn/divert/isdn_divert.c846
-rw-r--r--drivers/isdn/divert/isdn_divert.h132
-rw-r--r--drivers/isdn/gigaset/i4l.c692
-rw-r--r--drivers/isdn/hardware/Kconfig8
-rw-r--r--drivers/isdn/hardware/Makefile1
-rw-r--r--drivers/isdn/hardware/mISDN/Kconfig7
-rw-r--r--drivers/isdn/hardware/mISDN/Makefile2
-rw-r--r--drivers/isdn/hardware/mISDN/hfcsusb.c3
-rw-r--r--drivers/isdn/hardware/mISDN/isdnhdlc.c (renamed from drivers/isdn/i4l/isdnhdlc.c)2
-rw-r--r--drivers/isdn/hardware/mISDN/isdnhdlc.h69
-rw-r--r--drivers/isdn/hardware/mISDN/netjet.c2
-rw-r--r--drivers/isdn/hisax/Kconfig423
-rw-r--r--drivers/isdn/hisax/Makefile60
-rw-r--r--drivers/isdn/hisax/amd7930_fn.c794
-rw-r--r--drivers/isdn/hisax/amd7930_fn.h37
-rw-r--r--drivers/isdn/hisax/arcofi.c131
-rw-r--r--drivers/isdn/hisax/arcofi.h27
-rw-r--r--drivers/isdn/hisax/asuscom.c423
-rw-r--r--drivers/isdn/hisax/avm_a1.c307
-rw-r--r--drivers/isdn/hisax/avm_a1p.c267
-rw-r--r--drivers/isdn/hisax/avm_pci.c904
-rw-r--r--drivers/isdn/hisax/avma1_cs.c162
-rw-r--r--drivers/isdn/hisax/bkm_a4t.c358
-rw-r--r--drivers/isdn/hisax/bkm_a8.c433
-rw-r--r--drivers/isdn/hisax/bkm_ax.h119
-rw-r--r--drivers/isdn/hisax/callc.c1792
-rw-r--r--drivers/isdn/hisax/config.c1993
-rw-r--r--drivers/isdn/hisax/diva.c1282
-rw-r--r--drivers/isdn/hisax/elsa.c1245
-rw-r--r--drivers/isdn/hisax/elsa_cs.c218
-rw-r--r--drivers/isdn/hisax/elsa_ser.c659
-rw-r--r--drivers/isdn/hisax/enternow_pci.c420
-rw-r--r--drivers/isdn/hisax/fsm.c161
-rw-r--r--drivers/isdn/hisax/fsm.h61
-rw-r--r--drivers/isdn/hisax/gazel.c691
-rw-r--r--drivers/isdn/hisax/hfc4s8s_l1.c1584
-rw-r--r--drivers/isdn/hisax/hfc4s8s_l1.h89
-rw-r--r--drivers/isdn/hisax/hfc_2bds0.c1078
-rw-r--r--drivers/isdn/hisax/hfc_2bds0.h128
-rw-r--r--drivers/isdn/hisax/hfc_2bs0.c591
-rw-r--r--drivers/isdn/hisax/hfc_2bs0.h60
-rw-r--r--drivers/isdn/hisax/hfc_pci.c1755
-rw-r--r--drivers/isdn/hisax/hfc_pci.h235
-rw-r--r--drivers/isdn/hisax/hfc_sx.c1517
-rw-r--r--drivers/isdn/hisax/hfc_sx.h196
-rw-r--r--drivers/isdn/hisax/hfc_usb.c1594
-rw-r--r--drivers/isdn/hisax/hfc_usb.h208
-rw-r--r--drivers/isdn/hisax/hfcscard.c261
-rw-r--r--drivers/isdn/hisax/hisax.h1352
-rw-r--r--drivers/isdn/hisax/hisax_cfg.h66
-rw-r--r--drivers/isdn/hisax/hisax_debug.h80
-rw-r--r--drivers/isdn/hisax/hisax_fcpcipnp.c1024
-rw-r--r--drivers/isdn/hisax/hisax_fcpcipnp.h58
-rw-r--r--drivers/isdn/hisax/hisax_if.h66
-rw-r--r--drivers/isdn/hisax/hisax_isac.c895
-rw-r--r--drivers/isdn/hisax/hisax_isac.h46
-rw-r--r--drivers/isdn/hisax/hscx.c277
-rw-r--r--drivers/isdn/hisax/hscx.h41
-rw-r--r--drivers/isdn/hisax/hscx_irq.c294
-rw-r--r--drivers/isdn/hisax/icc.c680
-rw-r--r--drivers/isdn/hisax/icc.h72
-rw-r--r--drivers/isdn/hisax/ipac.h29
-rw-r--r--drivers/isdn/hisax/ipacx.c913
-rw-r--r--drivers/isdn/hisax/ipacx.h162
-rw-r--r--drivers/isdn/hisax/isac.c681
-rw-r--r--drivers/isdn/hisax/isac.h70
-rw-r--r--drivers/isdn/hisax/isar.c1910
-rw-r--r--drivers/isdn/hisax/isar.h222
-rw-r--r--drivers/isdn/hisax/isdnl1.c930
-rw-r--r--drivers/isdn/hisax/isdnl1.h32
-rw-r--r--drivers/isdn/hisax/isdnl2.c1839
-rw-r--r--drivers/isdn/hisax/isdnl2.h25
-rw-r--r--drivers/isdn/hisax/isdnl3.c594
-rw-r--r--drivers/isdn/hisax/isdnl3.h42
-rw-r--r--drivers/isdn/hisax/isurf.c305
-rw-r--r--drivers/isdn/hisax/ix1_micro.c316
-rw-r--r--drivers/isdn/hisax/jade.c305
-rw-r--r--drivers/isdn/hisax/jade.h134
-rw-r--r--drivers/isdn/hisax/jade_irq.c238
-rw-r--r--drivers/isdn/hisax/l3_1tr6.c932
-rw-r--r--drivers/isdn/hisax/l3_1tr6.h164
-rw-r--r--drivers/isdn/hisax/l3dss1.c3227
-rw-r--r--drivers/isdn/hisax/l3dss1.h124
-rw-r--r--drivers/isdn/hisax/l3ni1.c3182
-rw-r--r--drivers/isdn/hisax/l3ni1.h136
-rw-r--r--drivers/isdn/hisax/lmgr.c50
-rw-r--r--drivers/isdn/hisax/mic.c235
-rw-r--r--drivers/isdn/hisax/netjet.c985
-rw-r--r--drivers/isdn/hisax/netjet.h69
-rw-r--r--drivers/isdn/hisax/niccy.c380
-rw-r--r--drivers/isdn/hisax/nj_s.c294
-rw-r--r--drivers/isdn/hisax/nj_u.c258
-rw-r--r--drivers/isdn/hisax/q931.c1513
-rw-r--r--drivers/isdn/hisax/s0box.c260
-rw-r--r--drivers/isdn/hisax/saphir.c296
-rw-r--r--drivers/isdn/hisax/sedlbauer.c873
-rw-r--r--drivers/isdn/hisax/sedlbauer_cs.c209
-rw-r--r--drivers/isdn/hisax/sportster.c267
-rw-r--r--drivers/isdn/hisax/st5481.h529
-rw-r--r--drivers/isdn/hisax/st5481_b.c380
-rw-r--r--drivers/isdn/hisax/st5481_d.c780
-rw-r--r--drivers/isdn/hisax/st5481_init.c221
-rw-r--r--drivers/isdn/hisax/st5481_usb.c659
-rw-r--r--drivers/isdn/hisax/tei.c465
-rw-r--r--drivers/isdn/hisax/teleint.c334
-rw-r--r--drivers/isdn/hisax/teles0.c364
-rw-r--r--drivers/isdn/hisax/teles3.c498
-rw-r--r--drivers/isdn/hisax/teles_cs.c201
-rw-r--r--drivers/isdn/hisax/telespci.c349
-rw-r--r--drivers/isdn/hisax/w6692.c1085
-rw-r--r--drivers/isdn/hisax/w6692.h184
-rw-r--r--drivers/isdn/i4l/Kconfig129
-rw-r--r--drivers/isdn/i4l/Makefile20
-rw-r--r--drivers/isdn/i4l/isdn_audio.c711
-rw-r--r--drivers/isdn/i4l/isdn_audio.h44
-rw-r--r--drivers/isdn/i4l/isdn_bsdcomp.c930
-rw-r--r--drivers/isdn/i4l/isdn_common.c2368
-rw-r--r--drivers/isdn/i4l/isdn_common.h47
-rw-r--r--drivers/isdn/i4l/isdn_concap.c99
-rw-r--r--drivers/isdn/i4l/isdn_concap.h11
-rw-r--r--drivers/isdn/i4l/isdn_net.c3198
-rw-r--r--drivers/isdn/i4l/isdn_net.h151
-rw-r--r--drivers/isdn/i4l/isdn_ppp.c3046
-rw-r--r--drivers/isdn/i4l/isdn_ppp.h41
-rw-r--r--drivers/isdn/i4l/isdn_tty.c3756
-rw-r--r--drivers/isdn/i4l/isdn_tty.h120
-rw-r--r--drivers/isdn/i4l/isdn_ttyfax.c1123
-rw-r--r--drivers/isdn/i4l/isdn_ttyfax.h17
-rw-r--r--drivers/isdn/i4l/isdn_v110.c625
-rw-r--r--drivers/isdn/i4l/isdn_v110.h29
-rw-r--r--drivers/isdn/i4l/isdn_x25iface.c332
-rw-r--r--drivers/isdn/i4l/isdn_x25iface.h30
-rw-r--r--drivers/isdn/isdnloop/Makefile6
-rw-r--r--drivers/isdn/isdnloop/isdnloop.c1528
-rw-r--r--drivers/isdn/isdnloop/isdnloop.h112
-rw-r--r--drivers/isdn/mISDN/dsp_core.c2
-rw-r--r--drivers/leds/Kconfig35
-rw-r--r--drivers/leds/Makefile4
-rw-r--r--drivers/leds/led-class-flash.c5
-rw-r--r--drivers/leds/led-class.c5
-rw-r--r--drivers/leds/led-core.c6
-rw-r--r--drivers/leds/led-triggers.c6
-rw-r--r--drivers/leds/leds-88pm860x.c6
-rw-r--r--drivers/leds/leds-aat1290.c5
-rw-r--r--drivers/leds/leds-asic3.c5
-rw-r--r--drivers/leds/leds-bd2802.c6
-rw-r--r--drivers/leds/leds-da903x.c5
-rw-r--r--drivers/leds/leds-fsg.c6
-rw-r--r--drivers/leds/leds-gpio-register.c5
-rw-r--r--drivers/leds/leds-gpio.c6
-rw-r--r--drivers/leds/leds-hp6xx.c5
-rw-r--r--drivers/leds/leds-ipaq-micro.c4
-rw-r--r--drivers/leds/leds-is31fl32xx.c6
-rw-r--r--drivers/leds/leds-ktd2692.c5
-rw-r--r--drivers/leds/leds-lm355x.c5
-rw-r--r--drivers/leds/leds-lm36274.c172
-rw-r--r--drivers/leds/leds-lm3642.c6
-rw-r--r--drivers/leds/leds-lm3697.c395
-rw-r--r--drivers/leds/leds-locomo.c5
-rw-r--r--drivers/leds/leds-lp3944.c6
-rw-r--r--drivers/leds/leds-lp3952.c6
-rw-r--r--drivers/leds/leds-lp5562.c5
-rw-r--r--drivers/leds/leds-lp55xx-common.c5
-rw-r--r--drivers/leds/leds-lp55xx-common.h5
-rw-r--r--drivers/leds/leds-lp8501.c6
-rw-r--r--drivers/leds/leds-lp8788.c6
-rw-r--r--drivers/leds/leds-lp8860.c6
-rw-r--r--drivers/leds/leds-max77650.c2
-rw-r--r--drivers/leds/leds-max77693.c5
-rw-r--r--drivers/leds/leds-max8997.c6
-rw-r--r--drivers/leds/leds-mc13783.c5
-rw-r--r--drivers/leds/leds-net48xx.c5
-rw-r--r--drivers/leds/leds-pca955x.c2
-rw-r--r--drivers/leds/leds-pwm.c50
-rw-r--r--drivers/leds/leds-regulator.c6
-rw-r--r--drivers/leds/leds-s3c24xx.c5
-rw-r--r--drivers/leds/leds-spi-byte.c161
-rw-r--r--drivers/leds/leds-tca6507.c2
-rw-r--r--drivers/leds/leds-ti-lmu-common.c156
-rw-r--r--drivers/leds/leds-wm831x-status.c6
-rw-r--r--drivers/leds/leds-wm8350.c6
-rw-r--r--drivers/leds/leds-wrap.c5
-rw-r--r--drivers/leds/leds.h6
-rw-r--r--drivers/leds/trigger/Kconfig2
-rw-r--r--drivers/leds/trigger/ledtrig-activity.c7
-rw-r--r--drivers/leds/trigger/ledtrig-backlight.c6
-rw-r--r--drivers/leds/trigger/ledtrig-camera.c5
-rw-r--r--drivers/leds/trigger/ledtrig-cpu.c6
-rw-r--r--drivers/leds/trigger/ledtrig-default-on.c5
-rw-r--r--drivers/leds/trigger/ledtrig-disk.c6
-rw-r--r--drivers/leds/trigger/ledtrig-gpio.c5
-rw-r--r--drivers/leds/trigger/ledtrig-heartbeat.c5
-rw-r--r--drivers/leds/trigger/ledtrig-mtd.c6
-rw-r--r--drivers/leds/trigger/ledtrig-oneshot.c5
-rw-r--r--drivers/leds/trigger/ledtrig-panic.c6
-rw-r--r--drivers/leds/trigger/ledtrig-timer.c5
-rw-r--r--drivers/leds/trigger/ledtrig-transient.c2
-rw-r--r--drivers/lightnvm/core.c2
-rw-r--r--drivers/lightnvm/pblk-core.c18
-rw-r--r--drivers/macintosh/rack-meter.c4
-rw-r--r--drivers/macintosh/smu.c7
-rw-r--r--drivers/macintosh/windfarm.h3
-rw-r--r--drivers/macintosh/windfarm_ad7417_sensor.c3
-rw-r--r--drivers/macintosh/windfarm_core.c3
-rw-r--r--drivers/macintosh/windfarm_fcu_controls.c3
-rw-r--r--drivers/macintosh/windfarm_lm75_sensor.c3
-rw-r--r--drivers/macintosh/windfarm_lm87_sensor.c4
-rw-r--r--drivers/macintosh/windfarm_max6690_sensor.c3
-rw-r--r--drivers/macintosh/windfarm_mpu.h3
-rw-r--r--drivers/macintosh/windfarm_pid.c3
-rw-r--r--drivers/macintosh/windfarm_pid.h3
-rw-r--r--drivers/macintosh/windfarm_pm112.c3
-rw-r--r--drivers/macintosh/windfarm_pm121.c13
-rw-r--r--drivers/macintosh/windfarm_pm72.c3
-rw-r--r--drivers/macintosh/windfarm_pm81.c4
-rw-r--r--drivers/macintosh/windfarm_pm91.c3
-rw-r--r--drivers/macintosh/windfarm_rm31.c3
-rw-r--r--drivers/macintosh/windfarm_smu_controls.c3
-rw-r--r--drivers/macintosh/windfarm_smu_sensors.c3
-rw-r--r--drivers/mailbox/Kconfig2
-rw-r--r--drivers/mailbox/arm_mhu.c11
-rw-r--r--drivers/mailbox/bcm-flexrm-mailbox.c34
-rw-r--r--drivers/mailbox/bcm-pdc-mailbox.c21
-rw-r--r--drivers/mailbox/imx-mailbox.c4
-rw-r--r--drivers/mailbox/mailbox.c11
-rw-r--r--drivers/mailbox/mailbox.h6
-rw-r--r--drivers/mailbox/omap-mailbox.c43
-rw-r--r--drivers/mailbox/stm32-ipcc.c37
-rw-r--r--drivers/mailbox/tegra-hsp.c20
-rw-r--r--drivers/md/Kconfig2
-rw-r--r--drivers/md/bcache/alloc.c9
-rw-r--r--drivers/md/bcache/bcache.h6
-rw-r--r--drivers/md/bcache/bset.c61
-rw-r--r--drivers/md/bcache/btree.c53
-rw-r--r--drivers/md/bcache/btree.h2
-rw-r--r--drivers/md/bcache/io.c12
-rw-r--r--drivers/md/bcache/journal.c141
-rw-r--r--drivers/md/bcache/journal.h4
-rw-r--r--drivers/md/bcache/super.c227
-rw-r--r--drivers/md/bcache/sysfs.c67
-rw-r--r--drivers/md/bcache/util.h2
-rw-r--r--drivers/md/bcache/writeback.c8
-rw-r--r--drivers/md/dm-bufio.c4
-rw-r--r--drivers/md/dm-crypt.c101
-rw-r--r--drivers/md/dm-flakey.c5
-rw-r--r--drivers/md/dm-init.c12
-rw-r--r--drivers/md/dm-integrity.c7
-rw-r--r--drivers/md/dm-kcopyd.c34
-rw-r--r--drivers/md/dm-linear.c5
-rw-r--r--drivers/md/dm-log-writes.c27
-rw-r--r--drivers/md/dm-raid.c2
-rw-r--r--drivers/md/dm-rq.c2
-rw-r--r--drivers/md/dm-snap.c196
-rw-r--r--drivers/md/dm-table.c26
-rw-r--r--drivers/md/dm-thin-metadata.c7
-rw-r--r--drivers/md/dm-verity-target.c4
-rw-r--r--drivers/md/dm-zoned-metadata.c40
-rw-r--r--drivers/md/dm-zoned.h28
-rw-r--r--drivers/md/dm.c11
-rw-r--r--drivers/md/dm.h5
-rw-r--r--drivers/md/md-bitmap.c20
-rw-r--r--drivers/md/md.c168
-rw-r--r--drivers/md/md.h23
-rw-r--r--drivers/md/raid1-10.c30
-rw-r--r--drivers/md/raid1.c119
-rw-r--r--drivers/md/raid10.c86
-rw-r--r--drivers/md/raid5.c12
-rw-r--r--drivers/media/Kconfig37
-rw-r--r--drivers/media/Makefile13
-rw-r--r--drivers/media/cec/cec-adap.c141
-rw-r--r--drivers/media/cec/cec-api.c8
-rw-r--r--drivers/media/cec/cec-core.c8
-rw-r--r--drivers/media/cec/cec-notifier.c112
-rw-r--r--drivers/media/cec/cec-priv.h5
-rw-r--r--drivers/media/common/saa7146/saa7146_fops.c9
-rw-r--r--drivers/media/common/saa7146/saa7146_video.c18
-rw-r--r--drivers/media/common/videobuf2/videobuf2-core.c5
-rw-r--r--drivers/media/common/videobuf2/videobuf2-dma-contig.c3
-rw-r--r--drivers/media/common/videobuf2/videobuf2-dma-sg.c5
-rw-r--r--drivers/media/common/videobuf2/videobuf2-memops.c9
-rw-r--r--drivers/media/common/videobuf2/videobuf2-v4l2.c10
-rw-r--r--drivers/media/common/videobuf2/videobuf2-vmalloc.c3
-rw-r--r--drivers/media/dvb-core/Kconfig3
-rw-r--r--drivers/media/dvb-core/dvb_frontend.c140
-rw-r--r--drivers/media/dvb-frontends/Kconfig3
-rw-r--r--drivers/media/dvb-frontends/dib3000.h6
-rw-r--r--drivers/media/dvb-frontends/dib3000mb.c6
-rw-r--r--drivers/media/dvb-frontends/drxd.h14
-rw-r--r--drivers/media/dvb-frontends/drxd_firm.c14
-rw-r--r--drivers/media/dvb-frontends/drxd_firm.h14
-rw-r--r--drivers/media/dvb-frontends/drxd_hard.c14
-rw-r--r--drivers/media/dvb-frontends/drxd_map_firm.h14
-rw-r--r--drivers/media/dvb-frontends/drxk_hard.c14
-rw-r--r--drivers/media/dvb-frontends/rtl2832_sdr.c5
-rw-r--r--drivers/media/dvb-frontends/si2168.c7
-rw-r--r--drivers/media/dvb-frontends/stv0297.c2
-rw-r--r--drivers/media/dvb-frontends/stv090x.c197
-rw-r--r--drivers/media/dvb-frontends/stv090x.h3
-rw-r--r--drivers/media/dvb-frontends/stv090x_priv.h2
-rw-r--r--drivers/media/dvb-frontends/stv6110x.c135
-rw-r--r--drivers/media/dvb-frontends/stv6110x.h3
-rw-r--r--drivers/media/dvb-frontends/stv6110x_priv.h3
-rw-r--r--drivers/media/dvb-frontends/tda18271c2dd.c15
-rw-r--r--drivers/media/dvb-frontends/tua6100.c22
-rw-r--r--drivers/media/i2c/Kconfig5
-rw-r--r--drivers/media/i2c/Makefile2
-rw-r--r--drivers/media/i2c/adv7511-v4l2.c (renamed from drivers/media/i2c/adv7511.c)5
-rw-r--r--drivers/media/i2c/ak881x.c7
-rw-r--r--drivers/media/i2c/cx25840/cx25840-core.c1409
-rw-r--r--drivers/media/i2c/cx25840/cx25840-core.h30
-rw-r--r--drivers/media/i2c/cx25840/cx25840-vbi.c4
-rw-r--r--drivers/media/i2c/imx214.c2
-rw-r--r--drivers/media/i2c/lm3646.c5
-rw-r--r--drivers/media/i2c/mt9m001.c2
-rw-r--r--drivers/media/i2c/mt9m111.c45
-rw-r--r--drivers/media/i2c/mt9p031.c7
-rw-r--r--drivers/media/i2c/mt9t001.c5
-rw-r--r--drivers/media/i2c/mt9v032.c5
-rw-r--r--drivers/media/i2c/ov13858.c4
-rw-r--r--drivers/media/i2c/ov2640.c7
-rw-r--r--drivers/media/i2c/ov2685.c2
-rw-r--r--drivers/media/i2c/ov5695.c2
-rw-r--r--drivers/media/i2c/ov6650.c6
-rw-r--r--drivers/media/i2c/ov7740.c24
-rw-r--r--drivers/media/i2c/ov8856.c12
-rw-r--r--drivers/media/i2c/ov9640.c4
-rw-r--r--drivers/media/i2c/ov9650.c5
-rw-r--r--drivers/media/i2c/s5k5baf.c5
-rw-r--r--drivers/media/i2c/s5k6a3.c5
-rw-r--r--drivers/media/i2c/smiapp/smiapp-quirk.c2
-rw-r--r--drivers/media/i2c/st-mipid02.c60
-rw-r--r--drivers/media/i2c/tda7432.c3
-rw-r--r--drivers/media/i2c/tvp514x.c11
-rw-r--r--drivers/media/i2c/tvp514x_regs.h11
-rw-r--r--drivers/media/i2c/tw9910.c3
-rw-r--r--drivers/media/i2c/video-i2c.c8
-rw-r--r--drivers/media/mc/Kconfig33
-rw-r--r--drivers/media/mc/Makefile10
-rw-r--r--drivers/media/mc/mc-dev-allocator.c (renamed from drivers/media/media-dev-allocator.c)0
-rw-r--r--drivers/media/mc/mc-device.c (renamed from drivers/media/media-device.c)10
-rw-r--r--drivers/media/mc/mc-devnode.c (renamed from drivers/media/media-devnode.c)0
-rw-r--r--drivers/media/mc/mc-entity.c (renamed from drivers/media/media-entity.c)0
-rw-r--r--drivers/media/mc/mc-request.c (renamed from drivers/media/media-request.c)0
-rw-r--r--drivers/media/pci/bt8xx/bttv-audio-hook.c2
-rw-r--r--drivers/media/pci/bt8xx/bttv-audio-hook.h2
-rw-r--r--drivers/media/pci/bt8xx/bttv-driver.c50
-rw-r--r--drivers/media/pci/cobalt/Kconfig2
-rw-r--r--drivers/media/pci/cobalt/cobalt-v4l2.c14
-rw-r--r--drivers/media/pci/cx18/cx18-ioctl.c5
-rw-r--r--drivers/media/pci/cx18/cx18-streams.c1
-rw-r--r--drivers/media/pci/cx23885/cx23885-417.c13
-rw-r--r--drivers/media/pci/cx23885/cx23885-dvb.c2
-rw-r--r--drivers/media/pci/cx23885/cx23885-video.c22
-rw-r--r--drivers/media/pci/cx25821/cx25821-video.c14
-rw-r--r--drivers/media/pci/cx88/cx88-alsa.c2
-rw-r--r--drivers/media/pci/cx88/cx88-blackbird.c6
-rw-r--r--drivers/media/pci/cx88/cx88-core.c2
-rw-r--r--drivers/media/pci/cx88/cx88-i2c.c1
-rw-r--r--drivers/media/pci/cx88/cx88-input.c4
-rw-r--r--drivers/media/pci/cx88/cx88-video.c34
-rw-r--r--drivers/media/pci/ddbridge/Kconfig1
-rw-r--r--drivers/media/pci/dt3155/Kconfig1
-rw-r--r--drivers/media/pci/dt3155/dt3155.c5
-rw-r--r--drivers/media/pci/intel/ipu3/ipu3-cio2.c2
-rw-r--r--drivers/media/pci/ivtv/Kconfig2
-rw-r--r--drivers/media/pci/ivtv/ivtv-cards.h3
-rw-r--r--drivers/media/pci/ivtv/ivtv-ioctl.c7
-rw-r--r--drivers/media/pci/ivtv/ivtv-streams.c14
-rw-r--r--drivers/media/pci/ivtv/ivtvfb.c10
-rw-r--r--drivers/media/pci/meye/Kconfig3
-rw-r--r--drivers/media/pci/meye/meye.c6
-rw-r--r--drivers/media/pci/ngene/ngene-cards.c15
-rw-r--r--drivers/media/pci/ngene/ngene-core.c15
-rw-r--r--drivers/media/pci/ngene/ngene-dvb.c15
-rw-r--r--drivers/media/pci/ngene/ngene-i2c.c15
-rw-r--r--drivers/media/pci/ngene/ngene.h14
-rw-r--r--drivers/media/pci/saa7134/saa7134-core.c15
-rw-r--r--drivers/media/pci/saa7134/saa7134-empress.c4
-rw-r--r--drivers/media/pci/saa7134/saa7134-video.c46
-rw-r--r--drivers/media/pci/saa7164/saa7164-core.c33
-rw-r--r--drivers/media/pci/saa7164/saa7164-encoder.c15
-rw-r--r--drivers/media/pci/saa7164/saa7164-vbi.c15
-rw-r--r--drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c5
-rw-r--r--drivers/media/pci/solo6x10/solo6x10-v4l2.c5
-rw-r--r--drivers/media/pci/sta2x11/sta2x11_vip.c6
-rw-r--r--drivers/media/pci/ttpci/Kconfig3
-rw-r--r--drivers/media/pci/ttpci/av7110.c14
-rw-r--r--drivers/media/pci/ttpci/av7110.h21
-rw-r--r--drivers/media/pci/ttpci/av7110_ir.c423
-rw-r--r--drivers/media/pci/tw68/tw68-video.c8
-rw-r--r--drivers/media/pci/tw686x/tw686x-video.c5
-rw-r--r--drivers/media/platform/Kconfig12
-rw-r--r--drivers/media/platform/aspeed-video.c156
-rw-r--r--drivers/media/platform/atmel/Makefile4
-rw-r--r--drivers/media/platform/atmel/atmel-isc-base.c (renamed from drivers/media/platform/atmel/atmel-isc.c)783
-rw-r--r--drivers/media/platform/atmel/atmel-isc-regs.h6
-rw-r--r--drivers/media/platform/atmel/atmel-isc.h245
-rw-r--r--drivers/media/platform/atmel/atmel-isi.c5
-rw-r--r--drivers/media/platform/atmel/atmel-isi.h5
-rw-r--r--drivers/media/platform/atmel/atmel-sama5d2-isc.c348
-rw-r--r--drivers/media/platform/cec-gpio/cec-gpio.c28
-rw-r--r--drivers/media/platform/coda/Makefile5
-rw-r--r--drivers/media/platform/coda/coda-bit.c452
-rw-r--r--drivers/media/platform/coda/coda-common.c392
-rw-r--r--drivers/media/platform/coda/coda-h264.c3
-rw-r--r--drivers/media/platform/coda/coda-mpeg2.c87
-rw-r--r--drivers/media/platform/coda/coda-mpeg4.c87
-rw-r--r--drivers/media/platform/coda/coda.h47
-rw-r--r--drivers/media/platform/coda/coda_regs.h20
-rw-r--r--drivers/media/platform/coda/trace.h2
-rw-r--r--drivers/media/platform/davinci/vpif_capture.c16
-rw-r--r--drivers/media/platform/davinci/vpss.c7
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-core.c2
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-core.h6
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-m2m.c14
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-regs.h5
-rw-r--r--drivers/media/platform/exynos4-is/common.c10
-rw-r--r--drivers/media/platform/exynos4-is/common.h8
-rw-r--r--drivers/media/platform/exynos4-is/fimc-capture.c15
-rw-r--r--drivers/media/platform/exynos4-is/fimc-core.h5
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-command.h5
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-errno.c5
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-errno.h5
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-i2c.c5
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-i2c.h5
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-param.c5
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-param.h5
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-regs.c5
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-regs.h5
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-sensor.c5
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-sensor.h5
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is.c5
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is.h5
-rw-r--r--drivers/media/platform/exynos4-is/fimc-isp-video.c14
-rw-r--r--drivers/media/platform/exynos4-is/fimc-isp-video.h5
-rw-r--r--drivers/media/platform/exynos4-is/fimc-isp.c5
-rw-r--r--drivers/media/platform/exynos4-is/fimc-isp.h5
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite-reg.c5
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite-reg.h5
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite.c15
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite.h5
-rw-r--r--drivers/media/platform/exynos4-is/fimc-m2m.c12
-rw-r--r--drivers/media/platform/exynos4-is/fimc-reg.c5
-rw-r--r--drivers/media/platform/exynos4-is/fimc-reg.h5
-rw-r--r--drivers/media/platform/exynos4-is/media-dev.c6
-rw-r--r--drivers/media/platform/exynos4-is/media-dev.h5
-rw-r--r--drivers/media/platform/exynos4-is/mipi-csis.c5
-rw-r--r--drivers/media/platform/exynos4-is/mipi-csis.h5
-rw-r--r--drivers/media/platform/marvell-ccic/Kconfig2
-rw-r--r--drivers/media/platform/marvell-ccic/cafe-driver.c58
-rw-r--r--drivers/media/platform/marvell-ccic/mcam-core.c348
-rw-r--r--drivers/media/platform/marvell-ccic/mcam-core.h12
-rw-r--r--drivers/media/platform/marvell-ccic/mmp-driver.c238
-rw-r--r--drivers/media/platform/meson/ao-cec-g12a.c21
-rw-r--r--drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c6
-rw-r--r--drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c18
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c44
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h2
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c2
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c4
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h2
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h6
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c47
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.h2
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c2
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c2
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.h2
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.c2
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.h2
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c2
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h2
-rw-r--r--drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c23
-rw-r--r--drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c23
-rw-r--r--drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c25
-rw-r--r--drivers/media/platform/mtk-vcodec/vdec_drv_base.h10
-rw-r--r--drivers/media/platform/mtk-vcodec/vdec_drv_if.c22
-rw-r--r--drivers/media/platform/mtk-vcodec/vdec_drv_if.h6
-rw-r--r--drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h2
-rw-r--r--drivers/media/platform/mtk-vcodec/vdec_vpu_if.c2
-rw-r--r--drivers/media/platform/mtk-vcodec/vdec_vpu_if.h2
-rw-r--r--drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c21
-rw-r--r--drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c21
-rw-r--r--drivers/media/platform/mtk-vcodec/venc_drv_base.h10
-rw-r--r--drivers/media/platform/mtk-vcodec/venc_drv_if.c15
-rw-r--r--drivers/media/platform/mtk-vcodec/venc_drv_if.h5
-rw-r--r--drivers/media/platform/mtk-vcodec/venc_ipi_msg.h2
-rw-r--r--drivers/media/platform/mtk-vcodec/venc_vpu_if.c2
-rw-r--r--drivers/media/platform/mtk-vcodec/venc_vpu_if.h2
-rw-r--r--drivers/media/platform/mtk-vpu/mtk_vpu.c2
-rw-r--r--drivers/media/platform/omap/Kconfig1
-rw-r--r--drivers/media/platform/omap3isp/cfa_coef_table.h5
-rw-r--r--drivers/media/platform/omap3isp/gamma_table.h5
-rw-r--r--drivers/media/platform/omap3isp/isp.c23
-rw-r--r--drivers/media/platform/omap3isp/isp.h5
-rw-r--r--drivers/media/platform/omap3isp/ispccdc.c5
-rw-r--r--drivers/media/platform/omap3isp/ispccdc.h5
-rw-r--r--drivers/media/platform/omap3isp/ispccp2.c5
-rw-r--r--drivers/media/platform/omap3isp/ispccp2.h5
-rw-r--r--drivers/media/platform/omap3isp/ispcsi2.c5
-rw-r--r--drivers/media/platform/omap3isp/ispcsi2.h5
-rw-r--r--drivers/media/platform/omap3isp/ispcsiphy.c5
-rw-r--r--drivers/media/platform/omap3isp/ispcsiphy.h5
-rw-r--r--drivers/media/platform/omap3isp/isph3a.h5
-rw-r--r--drivers/media/platform/omap3isp/isph3a_aewb.c29
-rw-r--r--drivers/media/platform/omap3isp/isph3a_af.c29
-rw-r--r--drivers/media/platform/omap3isp/isphist.c16
-rw-r--r--drivers/media/platform/omap3isp/isphist.h5
-rw-r--r--drivers/media/platform/omap3isp/isppreview.c5
-rw-r--r--drivers/media/platform/omap3isp/isppreview.h5
-rw-r--r--drivers/media/platform/omap3isp/ispreg.h5
-rw-r--r--drivers/media/platform/omap3isp/ispresizer.c5
-rw-r--r--drivers/media/platform/omap3isp/ispresizer.h5
-rw-r--r--drivers/media/platform/omap3isp/ispstat.c9
-rw-r--r--drivers/media/platform/omap3isp/ispstat.h5
-rw-r--r--drivers/media/platform/omap3isp/ispvideo.c8
-rw-r--r--drivers/media/platform/omap3isp/ispvideo.h5
-rw-r--r--drivers/media/platform/omap3isp/luma_enhance_table.h5
-rw-r--r--drivers/media/platform/omap3isp/noise_filter_table.h5
-rw-r--r--drivers/media/platform/pxa_camera.c2
-rw-r--r--drivers/media/platform/qcom/camss/camss-video.c2
-rw-r--r--drivers/media/platform/qcom/venus/core.c4
-rw-r--r--drivers/media/platform/qcom/venus/firmware.c6
-rw-r--r--drivers/media/platform/qcom/venus/helpers.c7
-rw-r--r--drivers/media/platform/qcom/venus/hfi_cmds.c2
-rw-r--r--drivers/media/platform/qcom/venus/vdec.c4
-rw-r--r--drivers/media/platform/qcom/venus/vdec_ctrls.c2
-rw-r--r--drivers/media/platform/qcom/venus/venc.c4
-rw-r--r--drivers/media/platform/qcom/venus/venc_ctrls.c23
-rw-r--r--drivers/media/platform/rcar-vin/rcar-csi2.c4
-rw-r--r--drivers/media/platform/rcar-vin/rcar-v4l2.c190
-rw-r--r--drivers/media/platform/rcar_fdp1.c12
-rw-r--r--drivers/media/platform/rcar_jpu.c10
-rw-r--r--drivers/media/platform/renesas-ceu.c2
-rw-r--r--drivers/media/platform/s3c-camif/camif-capture.c5
-rw-r--r--drivers/media/platform/s3c-camif/camif-core.h5
-rw-r--r--drivers/media/platform/s3c-camif/camif-regs.c5
-rw-r--r--drivers/media/platform/s3c-camif/camif-regs.h5
-rw-r--r--drivers/media/platform/s5p-cec/exynos_hdmi_cec.h5
-rw-r--r--drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c5
-rw-r--r--drivers/media/platform/s5p-cec/regs-cec.h5
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-core.c5
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-core.h5
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c5
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.h5
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c5
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.h5
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c5
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h5
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-regs.h5
-rw-r--r--drivers/media/platform/s5p-mfc/regs-mfc-v6.h5
-rw-r--r--drivers/media/platform/s5p-mfc/regs-mfc-v7.h5
-rw-r--r--drivers/media/platform/s5p-mfc/regs-mfc-v8.h5
-rw-r--r--drivers/media/platform/s5p-mfc/regs-mfc.h5
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc.c5
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_debug.h5
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_dec.c19
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_enc.c21
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_intr.c5
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_intr.h5
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr.c5
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr.h5
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c9
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.h5
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c13
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h5
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_pm.c5
-rw-r--r--drivers/media/platform/seco-cec/seco-cec.c2
-rw-r--r--drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c4
-rw-r--r--drivers/media/platform/sti/hva/hva-v4l2.c4
-rw-r--r--drivers/media/platform/stm32/stm32-dcmi.c2
-rw-r--r--drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c1
-rw-r--r--drivers/media/platform/ti-vpe/cal.c5
-rw-r--r--drivers/media/platform/ti-vpe/cal_regs.h5
-rw-r--r--drivers/media/platform/ti-vpe/csc.c5
-rw-r--r--drivers/media/platform/ti-vpe/csc.h5
-rw-r--r--drivers/media/platform/ti-vpe/sc.c5
-rw-r--r--drivers/media/platform/ti-vpe/sc.h5
-rw-r--r--drivers/media/platform/ti-vpe/sc_coeff.h5
-rw-r--r--drivers/media/platform/ti-vpe/vpdma.c5
-rw-r--r--drivers/media/platform/ti-vpe/vpdma.h5
-rw-r--r--drivers/media/platform/ti-vpe/vpdma_priv.h5
-rw-r--r--drivers/media/platform/ti-vpe/vpe.c12
-rw-r--r--drivers/media/platform/ti-vpe/vpe_regs.h5
-rw-r--r--drivers/media/platform/vicodec/Kconfig1
-rw-r--r--drivers/media/platform/vicodec/vicodec-core.c313
-rw-r--r--drivers/media/platform/vim2m.c6
-rw-r--r--drivers/media/platform/vimc/Kconfig1
-rw-r--r--drivers/media/platform/vimc/Makefile12
-rw-r--r--drivers/media/platform/vimc/vimc-capture.c5
-rw-r--r--drivers/media/platform/vimc/vimc-common.c4
-rw-r--r--drivers/media/platform/vimc/vimc-core.c7
-rw-r--r--drivers/media/platform/vimc/vimc-debayer.c11
-rw-r--r--drivers/media/platform/vimc/vimc-scaler.c7
-rw-r--r--drivers/media/platform/vimc/vimc-sensor.c7
-rw-r--r--drivers/media/platform/vimc/vimc-streamer.c26
-rw-r--r--drivers/media/platform/vivid/Kconfig1
-rw-r--r--drivers/media/platform/vivid/vivid-core.c126
-rw-r--r--drivers/media/platform/vivid/vivid-core.h44
-rw-r--r--drivers/media/platform/vivid/vivid-ctrls.c108
-rw-r--r--drivers/media/platform/vivid/vivid-kthread-cap.c8
-rw-r--r--drivers/media/platform/vivid/vivid-osd.c2
-rw-r--r--drivers/media/platform/vivid/vivid-vbi-cap.c16
-rw-r--r--drivers/media/platform/vivid/vivid-vid-cap.c142
-rw-r--r--drivers/media/platform/vivid/vivid-vid-common.c28
-rw-r--r--drivers/media/platform/vivid/vivid-vid-common.h2
-rw-r--r--drivers/media/platform/vivid/vivid-vid-out.c6
-rw-r--r--drivers/media/radio/Kconfig1
-rw-r--r--drivers/media/radio/dsbr100.c3
-rw-r--r--drivers/media/radio/radio-cadet.c5
-rw-r--r--drivers/media/radio/radio-isa.c4
-rw-r--r--drivers/media/radio/radio-keene.c3
-rw-r--r--drivers/media/radio/radio-ma901.c3
-rw-r--r--drivers/media/radio/radio-miropcm20.c4
-rw-r--r--drivers/media/radio/radio-mr800.c5
-rw-r--r--drivers/media/radio/radio-raremono.c33
-rw-r--r--drivers/media/radio/radio-sf16fmi.c3
-rw-r--r--drivers/media/radio/radio-si476x.c21
-rw-r--r--drivers/media/radio/radio-tea5764.c3
-rw-r--r--drivers/media/radio/radio-tea5777.c5
-rw-r--r--drivers/media/radio/radio-timb.c3
-rw-r--r--drivers/media/radio/radio-wl1273.c12
-rw-r--r--drivers/media/radio/si470x/radio-si470x-i2c.c7
-rw-r--r--drivers/media/radio/si470x/radio-si470x-usb.c6
-rw-r--r--drivers/media/radio/si4713/radio-platform-si4713.c4
-rw-r--r--drivers/media/radio/si4713/radio-usb-si4713.c4
-rw-r--r--drivers/media/radio/tea575x.c7
-rw-r--r--drivers/media/radio/wl128x/fmdrv_v4l2.c13
-rw-r--r--drivers/media/rc/bpf-lirc.c30
-rw-r--r--drivers/media/rc/ir-spi.c1
-rw-r--r--drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c20
-rw-r--r--drivers/media/rc/keymaps/rc-alink-dtu-m.c20
-rw-r--r--drivers/media/rc/keymaps/rc-anysee.c20
-rw-r--r--drivers/media/rc/keymaps/rc-apac-viewcomp.c20
-rw-r--r--drivers/media/rc/keymaps/rc-astrometa-t2hybrid.c20
-rw-r--r--drivers/media/rc/keymaps/rc-asus-pc39.c20
-rw-r--r--drivers/media/rc/keymaps/rc-asus-ps3-100.c20
-rw-r--r--drivers/media/rc/keymaps/rc-ati-x10.c20
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-a16d.c20
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-cardbus.c20
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-dvbt.c20
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-m135a.c40
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c20
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-rm-ks.c20
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia.c20
-rw-r--r--drivers/media/rc/keymaps/rc-avertv-303.c20
-rw-r--r--drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c20
-rw-r--r--drivers/media/rc/keymaps/rc-behold-columbus.c20
-rw-r--r--drivers/media/rc/keymaps/rc-behold.c20
-rw-r--r--drivers/media/rc/keymaps/rc-budget-ci-old.c20
-rw-r--r--drivers/media/rc/keymaps/rc-cinergy-1400.c20
-rw-r--r--drivers/media/rc/keymaps/rc-cinergy.c20
-rw-r--r--drivers/media/rc/keymaps/rc-d680-dmb.c20
-rw-r--r--drivers/media/rc/keymaps/rc-delock-61959.c20
-rw-r--r--drivers/media/rc/keymaps/rc-dib0700-nec.c40
-rw-r--r--drivers/media/rc/keymaps/rc-dib0700-rc5.c100
-rw-r--r--drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c20
-rw-r--r--drivers/media/rc/keymaps/rc-digittrade.c20
-rw-r--r--drivers/media/rc/keymaps/rc-dm1105-nec.c20
-rw-r--r--drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c20
-rw-r--r--drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c20
-rw-r--r--drivers/media/rc/keymaps/rc-dtt200u.c20
-rw-r--r--drivers/media/rc/keymaps/rc-dvbsky.c20
-rw-r--r--drivers/media/rc/keymaps/rc-dvico-mce.c20
-rw-r--r--drivers/media/rc/keymaps/rc-dvico-portable.c20
-rw-r--r--drivers/media/rc/keymaps/rc-em-terratec.c20
-rw-r--r--drivers/media/rc/keymaps/rc-encore-enltv-fm53.c20
-rw-r--r--drivers/media/rc/keymaps/rc-encore-enltv.c20
-rw-r--r--drivers/media/rc/keymaps/rc-encore-enltv2.c20
-rw-r--r--drivers/media/rc/keymaps/rc-eztv.c20
-rw-r--r--drivers/media/rc/keymaps/rc-flydvb.c20
-rw-r--r--drivers/media/rc/keymaps/rc-flyvideo.c20
-rw-r--r--drivers/media/rc/keymaps/rc-fusionhdtv-mce.c20
-rw-r--r--drivers/media/rc/keymaps/rc-gadmei-rm008z.c20
-rw-r--r--drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c20
-rw-r--r--drivers/media/rc/keymaps/rc-gotview7135.c20
-rw-r--r--drivers/media/rc/keymaps/rc-hauppauge.c101
-rw-r--r--drivers/media/rc/keymaps/rc-hisi-poplar.c20
-rw-r--r--drivers/media/rc/keymaps/rc-hisi-tv-demo.c20
-rw-r--r--drivers/media/rc/keymaps/rc-iodata-bctv7e.c20
-rw-r--r--drivers/media/rc/keymaps/rc-it913x-v1.c40
-rw-r--r--drivers/media/rc/keymaps/rc-it913x-v2.c40
-rw-r--r--drivers/media/rc/keymaps/rc-kaiomy.c20
-rw-r--r--drivers/media/rc/keymaps/rc-kworld-315u.c20
-rw-r--r--drivers/media/rc/keymaps/rc-kworld-pc150u.c20
-rw-r--r--drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c24
-rw-r--r--drivers/media/rc/keymaps/rc-leadtek-y04g0051.c20
-rw-r--r--drivers/media/rc/keymaps/rc-lme2510.c60
-rw-r--r--drivers/media/rc/keymaps/rc-manli.c20
-rw-r--r--drivers/media/rc/keymaps/rc-medion-x10-digitainer.c20
-rw-r--r--drivers/media/rc/keymaps/rc-medion-x10-or2x.c20
-rw-r--r--drivers/media/rc/keymaps/rc-medion-x10.c20
-rw-r--r--drivers/media/rc/keymaps/rc-msi-digivox-ii.c20
-rw-r--r--drivers/media/rc/keymaps/rc-msi-digivox-iii.c20
-rw-r--r--drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c20
-rw-r--r--drivers/media/rc/keymaps/rc-msi-tvanywhere.c20
-rw-r--r--drivers/media/rc/keymaps/rc-nebula.c20
-rw-r--r--drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c40
-rw-r--r--drivers/media/rc/keymaps/rc-norwood.c20
-rw-r--r--drivers/media/rc/keymaps/rc-npgtech.c20
-rw-r--r--drivers/media/rc/keymaps/rc-pctv-sedna.c20
-rw-r--r--drivers/media/rc/keymaps/rc-pinnacle-color.c20
-rw-r--r--drivers/media/rc/keymaps/rc-pinnacle-grey.c20
-rw-r--r--drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c20
-rw-r--r--drivers/media/rc/keymaps/rc-pixelview-002t.c20
-rw-r--r--drivers/media/rc/keymaps/rc-pixelview-mk12.c20
-rw-r--r--drivers/media/rc/keymaps/rc-pixelview-new.c20
-rw-r--r--drivers/media/rc/keymaps/rc-pixelview.c20
-rw-r--r--drivers/media/rc/keymaps/rc-powercolor-real-angel.c20
-rw-r--r--drivers/media/rc/keymaps/rc-proteus-2309.c20
-rw-r--r--drivers/media/rc/keymaps/rc-purpletv.c20
-rw-r--r--drivers/media/rc/keymaps/rc-pv951.c20
-rw-r--r--drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c20
-rw-r--r--drivers/media/rc/keymaps/rc-reddo.c20
-rw-r--r--drivers/media/rc/keymaps/rc-snapstream-firefly.c20
-rw-r--r--drivers/media/rc/keymaps/rc-su3000.c20
-rw-r--r--drivers/media/rc/keymaps/rc-tango.c25
-rw-r--r--drivers/media/rc/keymaps/rc-tbs-nec.c20
-rw-r--r--drivers/media/rc/keymaps/rc-technisat-ts35.c20
-rw-r--r--drivers/media/rc/keymaps/rc-technisat-usb2.c20
-rw-r--r--drivers/media/rc/keymaps/rc-terratec-cinergy-c-pci.c20
-rw-r--r--drivers/media/rc/keymaps/rc-terratec-cinergy-s2-hd.c20
-rw-r--r--drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c20
-rw-r--r--drivers/media/rc/keymaps/rc-terratec-slim-2.c20
-rw-r--r--drivers/media/rc/keymaps/rc-terratec-slim.c20
-rw-r--r--drivers/media/rc/keymaps/rc-tevii-nec.c20
-rw-r--r--drivers/media/rc/keymaps/rc-total-media-in-hand-02.c20
-rw-r--r--drivers/media/rc/keymaps/rc-total-media-in-hand.c20
-rw-r--r--drivers/media/rc/keymaps/rc-trekstor.c20
-rw-r--r--drivers/media/rc/keymaps/rc-tt-1500.c20
-rw-r--r--drivers/media/rc/keymaps/rc-twinhan-dtv-cab-ci.c20
-rw-r--r--drivers/media/rc/keymaps/rc-twinhan1027.c20
-rw-r--r--drivers/media/rc/keymaps/rc-videomate-m1f.c20
-rw-r--r--drivers/media/rc/keymaps/rc-videomate-s350.c20
-rw-r--r--drivers/media/rc/keymaps/rc-videomate-tv-pvr.c20
-rw-r--r--drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c20
-rw-r--r--drivers/media/rc/keymaps/rc-winfast.c20
-rw-r--r--drivers/media/rc/keymaps/rc-xbox-dvd.c20
-rw-r--r--drivers/media/rc/keymaps/rc-zx-irdec.c25
-rw-r--r--drivers/media/rc/lirc_dev.c2
-rw-r--r--drivers/media/rc/mceusb.c4
-rw-r--r--drivers/media/rc/meson-ir.c6
-rw-r--r--drivers/media/rc/mtk-cir.c4
-rw-r--r--drivers/media/rc/rc-main.c6
-rw-r--r--drivers/media/rc/sunxi-cir.c1
-rw-r--r--drivers/media/rc/zx-irdec.c5
-rw-r--r--drivers/media/spi/Kconfig2
-rw-r--r--drivers/media/tuners/Kconfig2
-rw-r--r--drivers/media/tuners/mt2063.c11
-rw-r--r--drivers/media/tuners/si2157.c6
-rw-r--r--drivers/media/tuners/si2157_priv.h3
-rw-r--r--drivers/media/usb/airspy/airspy.c6
-rw-r--r--drivers/media/usb/au0828/au0828-core.c12
-rw-r--r--drivers/media/usb/au0828/au0828-video.c21
-rw-r--r--drivers/media/usb/cpia2/cpia2_usb.c3
-rw-r--r--drivers/media/usb/cpia2/cpia2_v4l.c9
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-cards.c2
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-dvb.c1
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-video.c28
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9035.c2
-rw-r--r--drivers/media/usb/dvb-usb-v2/anysee.c2
-rw-r--r--drivers/media/usb/dvb-usb-v2/az6007.c10
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c15
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvbsky.c11
-rw-r--r--drivers/media/usb/dvb-usb/Kconfig16
-rw-r--r--drivers/media/usb/dvb-usb/Makefile3
-rw-r--r--drivers/media/usb/dvb-usb/cxusb-analog.c1845
-rw-r--r--drivers/media/usb/dvb-usb/cxusb.c796
-rw-r--r--drivers/media/usb/dvb-usb/cxusb.h158
-rw-r--r--drivers/media/usb/dvb-usb/dibusb-mb.c5
-rw-r--r--drivers/media/usb/dvb-usb/dibusb-mc.c5
-rw-r--r--drivers/media/usb/dvb-usb/dvb-usb-dvb.c5
-rw-r--r--drivers/media/usb/dvb-usb/dvb-usb-init.c20
-rw-r--r--drivers/media/usb/dvb-usb/dvb-usb.h10
-rw-r--r--drivers/media/usb/em28xx/em28xx-input.c35
-rw-r--r--drivers/media/usb/em28xx/em28xx-video.c32
-rw-r--r--drivers/media/usb/go7007/go7007-v4l2.c15
-rw-r--r--drivers/media/usb/gspca/gspca.c6
-rw-r--r--drivers/media/usb/hackrf/hackrf.c14
-rw-r--r--drivers/media/usb/hdpvr/hdpvr-video.c22
-rw-r--r--drivers/media/usb/msi2500/msi2500.c5
-rw-r--r--drivers/media/usb/pvrusb2/Kconfig2
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-audio.c12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-audio.h12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-context.c11
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-context.h11
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.h12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-ctrl.c12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-ctrl.h12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c37
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.h12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-debug.h11
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-debugifc.c12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-debugifc.h12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-devattr.c224
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-devattr.h13
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-dvb.c99
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-dvb.h5
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-eeprom.c12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-eeprom.h12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-encoder.c12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-encoder.h12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h16
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-hdw.c52
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-hdw.h12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c18
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-i2c-core.h12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-io.c12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-io.h12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-ioread.c12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-ioread.h12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-main.c12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-std.c14
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-std.h12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-sysfs.c15
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-sysfs.h12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-util.h12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-v4l2.c29
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-v4l2.h12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-video-v4l.h12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-wm8775.c12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-wm8775.h12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2.h12
-rw-r--r--drivers/media/usb/pwc/pwc-if.c2
-rw-r--r--drivers/media/usb/pwc/pwc-v4l.c3
-rw-r--r--drivers/media/usb/pwc/pwc.h18
-rw-r--r--drivers/media/usb/s2255/Kconfig1
-rw-r--r--drivers/media/usb/s2255/s2255drv.c5
-rw-r--r--drivers/media/usb/stk1160/stk1160-v4l.c7
-rw-r--r--drivers/media/usb/stkwebcam/stk-webcam.c6
-rw-r--r--drivers/media/usb/tm6000/tm6000-video.c20
-rw-r--r--drivers/media/usb/usbtv/usbtv-video.c5
-rw-r--r--drivers/media/usb/usbvision/usbvision-video.c20
-rw-r--r--drivers/media/usb/uvc/uvc_ctrl.c4
-rw-r--r--drivers/media/usb/uvc/uvc_debugfs.c5
-rw-r--r--drivers/media/usb/zr364xx/zr364xx.c10
-rw-r--r--drivers/media/v4l2-core/Kconfig2
-rw-r--r--drivers/media/v4l2-core/v4l2-async.c5
-rw-r--r--drivers/media/v4l2-core/v4l2-clk.c5
-rw-r--r--drivers/media/v4l2-core/v4l2-common.c32
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls.c126
-rw-r--r--drivers/media/v4l2-core/v4l2-dev.c2
-rw-r--r--drivers/media/v4l2-core/v4l2-flash-led-class.c5
-rw-r--r--drivers/media/v4l2-core/v4l2-fwnode.c10
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c27
-rw-r--r--drivers/media/v4l2-core/v4l2-mem2mem.c29
-rw-r--r--drivers/media/v4l2-core/v4l2-subdev.c268
-rw-r--r--drivers/media/v4l2-core/videobuf-core.c5
-rw-r--r--drivers/media/v4l2-core/videobuf-dma-contig.c9
-rw-r--r--drivers/media/v4l2-core/videobuf-dma-sg.c5
-rw-r--r--drivers/media/v4l2-core/videobuf-vmalloc.c7
-rw-r--r--drivers/memory/Kconfig2
-rw-r--r--drivers/memory/brcmstb_dpfe.c4
-rw-r--r--drivers/memory/da8xx-ddrctl.c5
-rw-r--r--drivers/memory/emif.c5
-rw-r--r--drivers/memory/emif.h5
-rw-r--r--drivers/memory/jz4780-nemc.c33
-rw-r--r--drivers/memory/omap-gpmc.c9
-rw-r--r--drivers/memory/tegra/mc.c5
-rw-r--r--drivers/memory/tegra/mc.h5
-rw-r--r--drivers/memory/tegra/tegra114.c5
-rw-r--r--drivers/memory/tegra/tegra124.c5
-rw-r--r--drivers/memory/tegra/tegra186.c5
-rw-r--r--drivers/memory/tegra/tegra20.c5
-rw-r--r--drivers/memory/tegra/tegra210.c5
-rw-r--r--drivers/memory/tegra/tegra30.c5
-rw-r--r--drivers/memory/ti-aemif.c5
-rw-r--r--drivers/memstick/core/memstick.c19
-rw-r--r--drivers/memstick/core/ms_block.c6
-rw-r--r--drivers/memstick/core/ms_block.h6
-rw-r--r--drivers/memstick/core/mspro_block.c6
-rw-r--r--drivers/memstick/host/jmb38x_ms.c6
-rw-r--r--drivers/memstick/host/r592.c5
-rw-r--r--drivers/memstick/host/r592.h5
-rw-r--r--drivers/memstick/host/rtsx_usb_ms.c13
-rw-r--r--drivers/memstick/host/tifm_ms.c6
-rw-r--r--drivers/message/fusion/mptbase.c3
-rw-r--r--drivers/mfd/88pm80x.c5
-rw-r--r--drivers/mfd/88pm860x-core.c5
-rw-r--r--drivers/mfd/88pm860x-i2c.c5
-rw-r--r--drivers/mfd/Kconfig42
-rw-r--r--drivers/mfd/Makefile8
-rw-r--r--drivers/mfd/ac100.c5
-rw-r--r--drivers/mfd/altera-sysmgr.c4
-rw-r--r--drivers/mfd/arizona-core.c7
-rw-r--r--drivers/mfd/arizona-i2c.c5
-rw-r--r--drivers/mfd/arizona-irq.c5
-rw-r--r--drivers/mfd/arizona-spi.c5
-rw-r--r--drivers/mfd/arizona.h5
-rw-r--r--drivers/mfd/asic3.c6
-rw-r--r--drivers/mfd/atmel-flexcom.c13
-rw-r--r--drivers/mfd/atmel-hlcdc.c13
-rw-r--r--drivers/mfd/atmel-smc.c5
-rw-r--r--drivers/mfd/axp20x-i2c.c5
-rw-r--r--drivers/mfd/axp20x-rsb.c5
-rw-r--r--drivers/mfd/axp20x.c5
-rw-r--r--drivers/mfd/cros_ec.c6
-rw-r--r--drivers/mfd/cros_ec_dev.c92
-rw-r--r--drivers/mfd/cs47l15-tables.c1299
-rw-r--r--drivers/mfd/cs47l24-tables.c5
-rw-r--r--drivers/mfd/cs47l35-tables.c60
-rw-r--r--drivers/mfd/cs47l85-tables.c128
-rw-r--r--drivers/mfd/cs47l90-tables.c82
-rw-r--r--drivers/mfd/cs47l92-tables.c1947
-rw-r--r--drivers/mfd/cs5535-mfd.c24
-rw-r--r--drivers/mfd/da903x.c5
-rw-r--r--drivers/mfd/da9052-irq.c5
-rw-r--r--drivers/mfd/ezx-pcap.c6
-rw-r--r--drivers/mfd/fsl-imx25-tsadc.c5
-rw-r--r--drivers/mfd/hi6421-pmic-core.c5
-rw-r--r--drivers/mfd/hi655x-pmic.c7
-rw-r--r--drivers/mfd/intel-lpss-acpi.c5
-rw-r--r--drivers/mfd/intel-lpss-pci.c26
-rw-r--r--drivers/mfd/intel-lpss.c6
-rw-r--r--drivers/mfd/intel-lpss.h5
-rw-r--r--drivers/mfd/ipaq-micro.c5
-rw-r--r--drivers/mfd/lp3943.c5
-rw-r--r--drivers/mfd/lp87565.c4
-rw-r--r--drivers/mfd/lp8788-irq.c6
-rw-r--r--drivers/mfd/lp8788.c6
-rw-r--r--drivers/mfd/madera-core.c129
-rw-r--r--drivers/mfd/madera-i2c.c24
-rw-r--r--drivers/mfd/madera-spi.c24
-rw-r--r--drivers/mfd/madera.h18
-rw-r--r--drivers/mfd/max77620.c5
-rw-r--r--drivers/mfd/max8907.c5
-rw-r--r--drivers/mfd/max8925-core.c5
-rw-r--r--drivers/mfd/max8925-i2c.c5
-rw-r--r--drivers/mfd/mc13xxx-core.c5
-rw-r--r--drivers/mfd/mc13xxx-i2c.c5
-rw-r--r--drivers/mfd/mc13xxx-spi.c5
-rw-r--r--drivers/mfd/mc13xxx.h5
-rw-r--r--drivers/mfd/menelaus.c2
-rw-r--r--drivers/mfd/mfd-core.c7
-rw-r--r--drivers/mfd/motorola-cpcap.c5
-rw-r--r--drivers/mfd/rk808.c257
-rw-r--r--drivers/mfd/rohm-bd70528.c316
-rw-r--r--drivers/mfd/rohm-bd718x7.c80
-rw-r--r--drivers/mfd/sky81452.c13
-rw-r--r--drivers/mfd/sm501.c5
-rw-r--r--drivers/mfd/stmfx.c12
-rw-r--r--drivers/mfd/stmpe-i2c.c2
-rw-r--r--drivers/mfd/stmpe-spi.c2
-rw-r--r--drivers/mfd/stmpe.c2
-rw-r--r--drivers/mfd/stmpe.h2
-rw-r--r--drivers/mfd/sun4i-gpadc.c5
-rw-r--r--drivers/mfd/syscon.c21
-rw-r--r--drivers/mfd/t7l66xb.c5
-rw-r--r--drivers/mfd/tc3589x.c2
-rw-r--r--drivers/mfd/tc6387xb.c6
-rw-r--r--drivers/mfd/tc6393xb.c5
-rw-r--r--drivers/mfd/ti-lmu.c28
-rw-r--r--drivers/mfd/tmio_core.c5
-rw-r--r--drivers/mfd/tps6586x.c5
-rw-r--r--drivers/mfd/ucb1400_core.c5
-rw-r--r--drivers/mfd/ucb1x00-ts.c5
-rw-r--r--drivers/mfd/wm5102-tables.c5
-rw-r--r--drivers/mfd/wm5110-tables.c5
-rw-r--r--drivers/mfd/wm8997-tables.c5
-rw-r--r--drivers/mfd/wm8998-tables.c5
-rw-r--r--drivers/misc/Kconfig32
-rw-r--r--drivers/misc/Makefile2
-rw-r--r--drivers/misc/altera-stapl/Kconfig1
-rw-r--r--drivers/misc/atmel-ssc.c5
-rw-r--r--drivers/misc/c2port/Kconfig2
-rw-r--r--drivers/misc/c2port/c2port-duramar2150.c5
-rw-r--r--drivers/misc/c2port/core.c5
-rw-r--r--drivers/misc/cardreader/rtsx_usb.c13
-rw-r--r--drivers/misc/cb710/Kconfig1
-rw-r--r--drivers/misc/cb710/core.c5
-rw-r--r--drivers/misc/cb710/debug.c5
-rw-r--r--drivers/misc/cb710/sgbuf2.c5
-rw-r--r--drivers/misc/cxl/Kconfig3
-rw-r--r--drivers/misc/cxl/api.c13
-rw-r--r--drivers/misc/cxl/cxl.h15
-rw-r--r--drivers/misc/cxl/debugfs.c36
-rw-r--r--drivers/misc/ds1682.c5
-rw-r--r--drivers/misc/dummy-irq.c6
-rw-r--r--drivers/misc/echo/Kconfig1
-rw-r--r--drivers/misc/eeprom/at24.c86
-rw-r--r--drivers/misc/eeprom/digsy_mtc_eeprom.c5
-rw-r--r--drivers/misc/eeprom/ee1004.c43
-rw-r--r--drivers/misc/eeprom/eeprom_93xx46.c5
-rw-r--r--drivers/misc/eeprom/idt_89hpesx.c6
-rw-r--r--drivers/misc/fsa9480.c550
-rw-r--r--drivers/misc/genwqe/Kconfig1
-rw-r--r--drivers/misc/genwqe/card_base.c5
-rw-r--r--drivers/misc/genwqe/card_base.h2
-rw-r--r--drivers/misc/genwqe/card_debugfs.c165
-rw-r--r--drivers/misc/genwqe/card_dev.c6
-rw-r--r--drivers/misc/habanalabs/asid.c2
-rw-r--r--drivers/misc/habanalabs/command_submission.c10
-rw-r--r--drivers/misc/habanalabs/context.c11
-rw-r--r--drivers/misc/habanalabs/debugfs.c54
-rw-r--r--drivers/misc/habanalabs/device.c189
-rw-r--r--drivers/misc/habanalabs/firmware_if.c51
-rw-r--r--drivers/misc/habanalabs/goya/goya.c635
-rw-r--r--drivers/misc/habanalabs/goya/goyaP.h16
-rw-r--r--drivers/misc/habanalabs/goya/goya_security.c16
-rw-r--r--drivers/misc/habanalabs/habanalabs.h93
-rw-r--r--drivers/misc/habanalabs/habanalabs_drv.c66
-rw-r--r--drivers/misc/habanalabs/habanalabs_ioctl.c13
-rw-r--r--drivers/misc/habanalabs/hw_queue.c2
-rw-r--r--drivers/misc/habanalabs/include/goya/asic_reg/dma_ch_0_masks.h418
-rw-r--r--drivers/misc/habanalabs/include/goya/asic_reg/goya_regs.h1
-rw-r--r--drivers/misc/habanalabs/memory.c13
-rw-r--r--drivers/misc/habanalabs/mmu.c20
-rw-r--r--drivers/misc/habanalabs/pci.c10
-rw-r--r--drivers/misc/habanalabs/sysfs.c4
-rw-r--r--drivers/misc/ibmasm/ibmasmfs.c21
-rw-r--r--drivers/misc/isl29003.c4
-rw-r--r--drivers/misc/lis3lv02d/Kconfig2
-rw-r--r--drivers/misc/lkdtm/Makefile3
-rw-r--r--drivers/misc/lkdtm/bugs.c68
-rw-r--r--drivers/misc/lkdtm/core.c23
-rw-r--r--drivers/misc/lkdtm/heap.c72
-rw-r--r--drivers/misc/lkdtm/lkdtm.h6
-rw-r--r--drivers/misc/mei/debugfs.c223
-rw-r--r--drivers/misc/mei/hdcp/mei_hdcp.c11
-rw-r--r--drivers/misc/mei/main.c8
-rw-r--r--drivers/misc/mei/mei_dev.h7
-rw-r--r--drivers/misc/mic/card/mic_debugfs.c18
-rw-r--r--drivers/misc/mic/cosm/cosm_debugfs.c4
-rw-r--r--drivers/misc/mic/host/mic_debugfs.c4
-rw-r--r--drivers/misc/mic/scif/scif_debugfs.c5
-rw-r--r--drivers/misc/mic/scif/scif_main.c1
-rw-r--r--drivers/misc/mic/vop/vop_debugfs.c4
-rw-r--r--drivers/misc/ocxl/Kconfig1
-rw-r--r--drivers/misc/ocxl/config.c181
-rw-r--r--drivers/misc/ocxl/context.c9
-rw-r--r--drivers/misc/ocxl/link.c28
-rw-r--r--drivers/misc/ocxl/pci.c2
-rw-r--r--drivers/misc/pci_endpoint_test.c2
-rw-r--r--drivers/misc/sgi-xp/xpc_partition.c2
-rw-r--r--drivers/misc/sram.h5
-rw-r--r--drivers/misc/ti-st/st_kim.c4
-rw-r--r--drivers/misc/tifm_7xx1.c6
-rw-r--r--drivers/misc/tifm_core.c6
-rw-r--r--drivers/misc/tsl2550.c2
-rw-r--r--drivers/misc/vmw_balloon.c497
-rw-r--r--drivers/misc/vmw_vmci/vmci_context.c80
-rw-r--r--drivers/misc/vmw_vmci/vmci_handle_array.c38
-rw-r--r--drivers/misc/vmw_vmci/vmci_handle_array.h29
-rw-r--r--drivers/misc/xilinx_sdfec.c345
-rw-r--r--drivers/mmc/core/bus.c5
-rw-r--r--drivers/mmc/core/bus.h5
-rw-r--r--drivers/mmc/core/core.c10
-rw-r--r--drivers/mmc/core/core.h5
-rw-r--r--drivers/mmc/core/debugfs.c61
-rw-r--r--drivers/mmc/core/host.c5
-rw-r--r--drivers/mmc/core/host.h5
-rw-r--r--drivers/mmc/core/mmc.c11
-rw-r--r--drivers/mmc/core/mmc_test.c10
-rw-r--r--drivers/mmc/core/queue.c13
-rw-r--r--drivers/mmc/core/sd.c5
-rw-r--r--drivers/mmc/core/sdio.c105
-rw-r--r--drivers/mmc/core/sdio_io.c77
-rw-r--r--drivers/mmc/core/sdio_irq.c7
-rw-r--r--drivers/mmc/core/slot-gpio.c5
-rw-r--r--drivers/mmc/host/Kconfig2
-rw-r--r--drivers/mmc/host/alcor.c2
-rw-r--r--drivers/mmc/host/android-goldfish.c36
-rw-r--r--drivers/mmc/host/atmel-mci.c43
-rw-r--r--drivers/mmc/host/au1xmmc.c4
-rw-r--r--drivers/mmc/host/cb710-mmc.c5
-rw-r--r--drivers/mmc/host/cb710-mmc.h5
-rw-r--r--drivers/mmc/host/dw_mmc.c36
-rw-r--r--drivers/mmc/host/meson-gx-mmc.c85
-rw-r--r--drivers/mmc/host/mmci.c5
-rw-r--r--drivers/mmc/host/mmci.h5
-rw-r--r--drivers/mmc/host/mtk-sd.c39
-rw-r--r--drivers/mmc/host/mvsdio.c5
-rw-r--r--drivers/mmc/host/mvsdio.h5
-rw-r--r--drivers/mmc/host/mxcmmc.c6
-rw-r--r--drivers/mmc/host/omap.c5
-rw-r--r--drivers/mmc/host/pxamci.c5
-rw-r--r--drivers/mmc/host/renesas_sdhi_core.c24
-rw-r--r--drivers/mmc/host/rtsx_usb_sdmmc.c13
-rw-r--r--drivers/mmc/host/s3cmci.c32
-rw-r--r--drivers/mmc/host/s3cmci.h7
-rw-r--r--drivers/mmc/host/sdhci-cns3xxx.c5
-rw-r--r--drivers/mmc/host/sdhci-msm.c9
-rw-r--r--drivers/mmc/host/sdhci-of-esdhc.c17
-rw-r--r--drivers/mmc/host/sdhci-pci-core.c4
-rw-r--r--drivers/mmc/host/sdhci-pci-o2micro.c17
-rw-r--r--drivers/mmc/host/sdhci-pci.h2
-rw-r--r--drivers/mmc/host/sdhci-pltfm.h5
-rw-r--r--drivers/mmc/host/sdhci-s3c.c5
-rw-r--r--drivers/mmc/host/sdhci-sprd.c249
-rw-r--r--drivers/mmc/host/sdhci-tegra.c5
-rw-r--r--drivers/mmc/host/sdhci.h2
-rw-r--r--drivers/mmc/host/sdhci_am654.c293
-rw-r--r--drivers/mmc/host/tifm_sd.c6
-rw-r--r--drivers/mmc/host/tmio_mmc.c5
-rw-r--r--drivers/mmc/host/tmio_mmc_core.c29
-rw-r--r--drivers/mmc/host/uniphier-sd.c3
-rw-r--r--drivers/mmc/host/wmt-sdmmc.c5
-rw-r--r--drivers/mtd/Kconfig2
-rw-r--r--drivers/mtd/Makefile1
-rw-r--r--drivers/mtd/bcm47xxpart.c6
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0002.c143
-rw-r--r--drivers/mtd/devices/Kconfig2
-rw-r--r--drivers/mtd/hyperbus/Kconfig23
-rw-r--r--drivers/mtd/hyperbus/Makefile4
-rw-r--r--drivers/mtd/hyperbus/hbmc-am654.c147
-rw-r--r--drivers/mtd/hyperbus/hyperbus-core.c153
-rw-r--r--drivers/mtd/maps/impa7.c5
-rw-r--r--drivers/mtd/maps/lantiq-flash.c4
-rw-r--r--drivers/mtd/maps/pci.c5
-rw-r--r--drivers/mtd/maps/pxa2xx-flash.c5
-rw-r--r--drivers/mtd/maps/rbtx4939-flash.c5
-rw-r--r--drivers/mtd/maps/vmu-flash.c4
-rw-r--r--drivers/mtd/mtdconcat.c37
-rw-r--r--drivers/mtd/mtdcore.c3
-rw-r--r--drivers/mtd/nand/onenand/generic.c5
-rw-r--r--drivers/mtd/nand/onenand/onenand_base.c10
-rw-r--r--drivers/mtd/nand/onenand/samsung.c5
-rw-r--r--drivers/mtd/nand/onenand/samsung.h5
-rw-r--r--drivers/mtd/nand/raw/au1550nd.c6
-rw-r--r--drivers/mtd/nand/raw/bcm47xxnflash/main.c6
-rw-r--r--drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c6
-rw-r--r--drivers/mtd/nand/raw/brcmnand/brcmnand.c263
-rw-r--r--drivers/mtd/nand/raw/cmx270_nand.c6
-rw-r--r--drivers/mtd/nand/raw/cs553x_nand.c6
-rw-r--r--drivers/mtd/nand/raw/fsmc_nand.c19
-rw-r--r--drivers/mtd/nand/raw/gpio.c6
-rw-r--r--drivers/mtd/nand/raw/gpmi-nand/Makefile1
-rw-r--r--drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c934
-rw-r--r--drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c1709
-rw-r--r--drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h64
-rw-r--r--drivers/mtd/nand/raw/ingenic/Kconfig2
-rw-r--r--drivers/mtd/nand/raw/ingenic/Makefile4
-rw-r--r--drivers/mtd/nand/raw/ingenic/ingenic_ecc.c9
-rw-r--r--drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c (renamed from drivers/mtd/nand/raw/ingenic/ingenic_nand.c)0
-rw-r--r--drivers/mtd/nand/raw/mtk_ecc.c4
-rw-r--r--drivers/mtd/nand/raw/mtk_ecc.h4
-rw-r--r--drivers/mtd/nand/raw/mtk_nand.c88
-rw-r--r--drivers/mtd/nand/raw/nand_base.c89
-rw-r--r--drivers/mtd/nand/raw/nand_bbt.c6
-rw-r--r--drivers/mtd/nand/raw/nand_bch.c3
-rw-r--r--drivers/mtd/nand/raw/nand_ecc.c2
-rw-r--r--drivers/mtd/nand/raw/nand_ids.c6
-rw-r--r--drivers/mtd/nand/raw/nand_macronix.c45
-rw-r--r--drivers/mtd/nand/raw/nand_timings.c6
-rw-r--r--drivers/mtd/nand/raw/omap2.c5
-rw-r--r--drivers/mtd/nand/raw/oxnas_nand.c6
-rw-r--r--drivers/mtd/nand/raw/plat_nand.c6
-rw-r--r--drivers/mtd/nand/raw/r852.c5
-rw-r--r--drivers/mtd/nand/raw/r852.h5
-rw-r--r--drivers/mtd/nand/raw/sharpsl.c6
-rw-r--r--drivers/mtd/nand/raw/sm_common.c5
-rw-r--r--drivers/mtd/nand/raw/sm_common.h5
-rw-r--r--drivers/mtd/nand/raw/socrates_nand.c7
-rw-r--r--drivers/mtd/nand/raw/stm32_fmc2_nand.c21
-rw-r--r--drivers/mtd/nand/raw/sunxi_nand.c40
-rw-r--r--drivers/mtd/nand/raw/tango_nand.c5
-rw-r--r--drivers/mtd/nand/raw/txx9ndfmc.c5
-rw-r--r--drivers/mtd/nand/raw/xway_nand.c4
-rw-r--r--drivers/mtd/nand/spi/Makefile2
-rw-r--r--drivers/mtd/nand/spi/core.c5
-rw-r--r--drivers/mtd/nand/spi/gigadevice.c81
-rw-r--r--drivers/mtd/nand/spi/macronix.c4
-rw-r--r--drivers/mtd/nand/spi/paragon.c147
-rw-r--r--drivers/mtd/parsers/afs.c3
-rw-r--r--drivers/mtd/parsers/parser_trx.c6
-rw-r--r--drivers/mtd/sm_ftl.c5
-rw-r--r--drivers/mtd/sm_ftl.h5
-rw-r--r--drivers/mtd/spi-nor/Kconfig7
-rw-r--r--drivers/mtd/spi-nor/Makefile1
-rw-r--r--drivers/mtd/spi-nor/cadence-quadspi.c21
-rw-r--r--drivers/mtd/spi-nor/intel-spi-pci.c6
-rw-r--r--drivers/mtd/spi-nor/intel-spi-platform.c5
-rw-r--r--drivers/mtd/spi-nor/intel-spi.c5
-rw-r--r--drivers/mtd/spi-nor/intel-spi.h5
-rw-r--r--drivers/mtd/spi-nor/nxp-spifi.c6
-rw-r--r--drivers/mtd/spi-nor/spi-nor.c156
-rw-r--r--drivers/mtd/spi-nor/stm32-quadspi.c720
-rw-r--r--drivers/mtd/ssfdc.c5
-rw-r--r--drivers/mux/Kconfig12
-rw-r--r--drivers/mux/mmio.c6
-rw-r--r--drivers/net/bonding/bond_3ad.c222
-rw-r--r--drivers/net/bonding/bond_alb.c30
-rw-r--r--drivers/net/bonding/bond_main.c390
-rw-r--r--drivers/net/bonding/bond_netlink.c14
-rw-r--r--drivers/net/bonding/bond_options.c101
-rw-r--r--drivers/net/bonding/bond_procfs.c2
-rw-r--r--drivers/net/bonding/bond_sysfs.c13
-rw-r--r--drivers/net/caif/caif_hsi.c2
-rw-r--r--drivers/net/can/cc770/cc770.c10
-rw-r--r--drivers/net/can/cc770/cc770.h10
-rw-r--r--drivers/net/can/cc770/cc770_isa.c10
-rw-r--r--drivers/net/can/cc770/cc770_platform.c10
-rw-r--r--drivers/net/can/flexcan.c5
-rw-r--r--drivers/net/can/led.c5
-rw-r--r--drivers/net/can/m_can/m_can.c21
-rw-r--r--drivers/net/can/peak_canfd/peak_canfd.c10
-rw-r--r--drivers/net/can/peak_canfd/peak_pciefd_main.c10
-rw-r--r--drivers/net/can/sja1000/ems_pcmcia.c10
-rw-r--r--drivers/net/can/sja1000/peak_pci.c10
-rw-r--r--drivers/net/can/sja1000/peak_pcmcia.c10
-rw-r--r--drivers/net/can/softing/softing_main.c4
-rw-r--r--drivers/net/can/spi/Kconfig5
-rw-r--r--drivers/net/can/spi/hi311x.c5
-rw-r--r--drivers/net/can/spi/mcp251x.c25
-rw-r--r--drivers/net/can/usb/Kconfig6
-rw-r--r--drivers/net/can/xilinx_can.c2
-rw-r--r--drivers/net/dsa/Kconfig24
-rw-r--r--drivers/net/dsa/Makefile8
-rw-r--r--drivers/net/dsa/b53/b53_common.c4
-rw-r--r--drivers/net/dsa/microchip/Kconfig1
-rw-r--r--drivers/net/dsa/microchip/ksz9477.c229
-rw-r--r--drivers/net/dsa/microchip/ksz9477_spi.c114
-rw-r--r--drivers/net/dsa/microchip/ksz_common.c17
-rw-r--r--drivers/net/dsa/microchip/ksz_common.h169
-rw-r--r--drivers/net/dsa/microchip/ksz_priv.h25
-rw-r--r--drivers/net/dsa/microchip/ksz_spi.h69
-rw-r--r--drivers/net/dsa/mt7530.c46
-rw-r--r--drivers/net/dsa/mt7530.h4
-rw-r--r--drivers/net/dsa/mv88e6xxx/chip.c269
-rw-r--r--drivers/net/dsa/mv88e6xxx/chip.h18
-rw-r--r--drivers/net/dsa/mv88e6xxx/global1.c35
-rw-r--r--drivers/net/dsa/mv88e6xxx/global1.h16
-rw-r--r--drivers/net/dsa/mv88e6xxx/global1_atu.c11
-rw-r--r--drivers/net/dsa/mv88e6xxx/global1_vtu.c66
-rw-r--r--drivers/net/dsa/mv88e6xxx/global2.c46
-rw-r--r--drivers/net/dsa/mv88e6xxx/global2.h14
-rw-r--r--drivers/net/dsa/mv88e6xxx/hwtstamp.c28
-rw-r--r--drivers/net/dsa/mv88e6xxx/phy.c4
-rw-r--r--drivers/net/dsa/mv88e6xxx/port.c77
-rw-r--r--drivers/net/dsa/mv88e6xxx/port.h14
-rw-r--r--drivers/net/dsa/mv88e6xxx/ptp.c32
-rw-r--r--drivers/net/dsa/mv88e6xxx/serdes.c24
-rw-r--r--drivers/net/dsa/mv88e6xxx/smi.c25
-rw-r--r--drivers/net/dsa/qca8k.c15
-rw-r--r--drivers/net/dsa/qca8k.h2
-rw-r--r--drivers/net/dsa/realtek-smi-core.c (renamed from drivers/net/dsa/realtek-smi.c)2
-rw-r--r--drivers/net/dsa/realtek-smi-core.h (renamed from drivers/net/dsa/realtek-smi.h)0
-rw-r--r--drivers/net/dsa/rtl8366.c9
-rw-r--r--drivers/net/dsa/rtl8366rb.c2
-rw-r--r--drivers/net/dsa/sja1105/Kconfig9
-rw-r--r--drivers/net/dsa/sja1105/Makefile4
-rw-r--r--drivers/net/dsa/sja1105/sja1105.h54
-rw-r--r--drivers/net/dsa/sja1105/sja1105_clocking.c100
-rw-r--r--drivers/net/dsa/sja1105/sja1105_dynamic_config.c296
-rw-r--r--drivers/net/dsa/sja1105/sja1105_dynamic_config.h11
-rw-r--r--drivers/net/dsa/sja1105/sja1105_main.c868
-rw-r--r--drivers/net/dsa/sja1105/sja1105_ptp.c393
-rw-r--r--drivers/net/dsa/sja1105/sja1105_ptp.h64
-rw-r--r--drivers/net/dsa/sja1105/sja1105_spi.c70
-rw-r--r--drivers/net/dsa/sja1105/sja1105_static_config.c88
-rw-r--r--drivers/net/dsa/sja1105/sja1105_static_config.h37
-rw-r--r--drivers/net/dsa/vitesse-vsc73xx-core.c (renamed from drivers/net/dsa/vitesse-vsc73xx.c)206
-rw-r--r--drivers/net/dsa/vitesse-vsc73xx-platform.c164
-rw-r--r--drivers/net/dsa/vitesse-vsc73xx-spi.c203
-rw-r--r--drivers/net/dsa/vitesse-vsc73xx.h29
-rw-r--r--drivers/net/ethernet/8390/Kconfig2
-rw-r--r--drivers/net/ethernet/8390/ax88796.c5
-rw-r--r--drivers/net/ethernet/8390/etherh.c5
-rw-r--r--drivers/net/ethernet/Kconfig1
-rw-r--r--drivers/net/ethernet/Makefile1
-rw-r--r--drivers/net/ethernet/alacritech/slicoss.c11
-rw-r--r--drivers/net/ethernet/allwinner/sun4i-emac.c5
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_admin_defs.h61
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_com.c145
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_com.h19
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_eth_com.c54
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_eth_com.h73
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_ethtool.c35
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_netdev.c389
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_netdev.h42
-rw-r--r--drivers/net/ethernet/amd/am79c961a.c5
-rw-r--r--drivers/net/ethernet/amd/am79c961a.h5
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_cfg.h7
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_drvinfo.c2
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_drvinfo.h2
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_filters.c12
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_filters.h2
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_main.c34
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_nic.c29
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_nic.h3
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_ring.c4
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_ring.h9
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c2
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c81
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h7
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c16
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h5
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h18
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/ver.h5
-rw-r--r--drivers/net/ethernet/arc/emac_main.c5
-rw-r--r--drivers/net/ethernet/atheros/Kconfig10
-rw-r--r--drivers/net/ethernet/atheros/Makefile1
-rw-r--r--drivers/net/ethernet/atheros/ag71xx.c1901
-rw-r--r--drivers/net/ethernet/atheros/atl1c/atl1c_main.c2
-rw-r--r--drivers/net/ethernet/atheros/atlx/atl1.c2
-rw-r--r--drivers/net/ethernet/atheros/atlx/atl2.c1
-rw-r--r--drivers/net/ethernet/broadcom/Kconfig2
-rw-r--r--drivers/net/ethernet/broadcom/bcm63xx_enet.c1
-rw-r--r--drivers/net/ethernet/broadcom/bcmsysport.c25
-rw-r--r--drivers/net/ethernet/broadcom/bcmsysport.h9
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c7
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c7
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h1
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c33
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h3
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.c134
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.h21
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c2
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_debugfs.c6
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_dim.c9
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c8
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c18
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_tc.h4
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c4
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c29
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c144
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h7
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet.c80
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet.h9
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c5
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmmii.c5
-rw-r--r--drivers/net/ethernet/broadcom/tg3.c2
-rw-r--r--drivers/net/ethernet/cadence/Kconfig10
-rw-r--r--drivers/net/ethernet/cadence/macb.h17
-rw-r--r--drivers/net/ethernet/cadence/macb_main.c150
-rw-r--r--drivers/net/ethernet/cadence/macb_ptp.c7
-rw-r--r--drivers/net/ethernet/calxeda/xgmac.c4
-rw-r--r--drivers/net/ethernet/cavium/liquidio/lio_core.c2
-rw-r--r--drivers/net/ethernet/cavium/liquidio/request_manager.c6
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/Makefile2
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c19
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4.h62
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c49
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.h2
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c240
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_mps.c241
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c22
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h6
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c21
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h2
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/sched.c1
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_hw.c79
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_regs.h4
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h28
-rw-r--r--drivers/net/ethernet/chelsio/libcxgb/libcxgb_ppm.c47
-rw-r--r--drivers/net/ethernet/chelsio/libcxgb/libcxgb_ppm.h7
-rw-r--r--drivers/net/ethernet/dnet.c5
-rw-r--r--drivers/net/ethernet/dnet.h5
-rw-r--r--drivers/net/ethernet/emulex/benet/be_ethtool.c30
-rw-r--r--drivers/net/ethernet/emulex/benet/be_main.c6
-rw-r--r--drivers/net/ethernet/ethoc.c5
-rw-r--r--drivers/net/ethernet/faraday/ftgmac100.c2
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/Kconfig3
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c147
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h9
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.c242
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dprtc-cmd.h48
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dprtc.c191
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dprtc.h62
-rw-r--r--drivers/net/ethernet/freescale/enetc/Kconfig10
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc.c216
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc.h18
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_ethtool.c31
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_hw.h25
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_pf.c2
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_ptp.c5
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_vf.c2
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c18
-rw-r--r--drivers/net/ethernet/freescale/fec_ptp.c2
-rw-r--r--drivers/net/ethernet/freescale/fman/fman_keygen.c3
-rw-r--r--drivers/net/ethernet/google/Kconfig27
-rw-r--r--drivers/net/ethernet/google/Makefile5
-rw-r--r--drivers/net/ethernet/google/gve/Makefile4
-rw-r--r--drivers/net/ethernet/google/gve/gve.h459
-rw-r--r--drivers/net/ethernet/google/gve/gve_adminq.c387
-rw-r--r--drivers/net/ethernet/google/gve/gve_adminq.h217
-rw-r--r--drivers/net/ethernet/google/gve/gve_desc.h113
-rw-r--r--drivers/net/ethernet/google/gve/gve_ethtool.c245
-rw-r--r--drivers/net/ethernet/google/gve/gve_main.c1231
-rw-r--r--drivers/net/ethernet/google/gve/gve_register.h27
-rw-r--r--drivers/net/ethernet/google/gve/gve_rx.c446
-rw-r--r--drivers/net/ethernet/google/gve/gve_tx.c584
-rw-r--r--drivers/net/ethernet/hisilicon/Kconfig10
-rw-r--r--drivers/net/ethernet/hisilicon/hip04_eth.c145
-rw-r--r--drivers/net/ethernet/hisilicon/hisi_femac.c7
-rw-r--r--drivers/net/ethernet/hisilicon/hix5hd2_gmac.c7
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c2
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_enet.c1
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h2
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hnae3.c26
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hnae3.h27
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_dcbnl.c12
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c6
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_enet.c457
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_enet.h27
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c60
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c70
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h43
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c2
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c95
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c799
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h21
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c1348
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h62
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c32
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c15
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c170
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h3
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3vf/Makefile2
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c59
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h14
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c286
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h9
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c3
-rw-r--r--drivers/net/ethernet/hisilicon/hns_mdio.c4
-rw-r--r--drivers/net/ethernet/huawei/hinic/Makefile2
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_dev.h28
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_ethtool.c762
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c12
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h56
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_hw_io.c60
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_hw_qp_ctxt.h5
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_hw_wqe.h53
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_main.c339
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_port.c638
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_port.h371
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_rx.c82
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_rx.h7
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_tx.c25
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_tx.h1
-rw-r--r--drivers/net/ethernet/i825xx/ether1.c5
-rw-r--r--drivers/net/ethernet/i825xx/ether1.h5
-rw-r--r--drivers/net/ethernet/ibm/ibmvnic.c19
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_main.c6
-rw-r--r--drivers/net/ethernet/intel/e1000e/80003es2lan.c2
-rw-r--r--drivers/net/ethernet/intel/e1000e/82571.c2
-rw-r--r--drivers/net/ethernet/intel/e1000e/defines.h3
-rw-r--r--drivers/net/ethernet/intel/e1000e/e1000.h5
-rw-r--r--drivers/net/ethernet/intel/e1000e/ethtool.c14
-rw-r--r--drivers/net/ethernet/intel/e1000e/ich8lan.c20
-rw-r--r--drivers/net/ethernet/intel/e1000e/mac.c2
-rw-r--r--drivers/net/ethernet/intel/e1000e/netdev.c111
-rw-r--r--drivers/net/ethernet/intel/e1000e/nvm.c2
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e.h32
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_adminq.c8
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_common.c43
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_debugfs.c9
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_ethtool.c86
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_main.c672
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_prototype.h4
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_ptp.c3
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_txrx.c2
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c118
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_xsk.c13
-rw-r--r--drivers/net/ethernet/intel/iavf/Makefile2
-rw-r--r--drivers/net/ethernet/intel/iavf/i40e_adminq_cmd.h530
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf.h13
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_adminq.c (renamed from drivers/net/ethernet/intel/iavf/i40e_adminq.c)267
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_adminq.h (renamed from drivers/net/ethernet/intel/iavf/i40e_adminq.h)80
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_adminq_cmd.h528
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_alloc.h17
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_client.c127
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_client.h104
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_common.c499
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_ethtool.c16
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_main.c868
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_osdep.h11
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_prototype.h58
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_status.h136
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_trace.h4
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_txrx.c41
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_type.h4
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_virtchnl.c77
-rw-r--r--drivers/net/ethernet/intel/ice/ice.h63
-rw-r--r--drivers/net/ethernet/intel/ice/ice_adminq_cmd.h49
-rw-r--r--drivers/net/ethernet/intel/ice/ice_common.c250
-rw-r--r--drivers/net/ethernet/intel/ice/ice_common.h11
-rw-r--r--drivers/net/ethernet/intel/ice/ice_controlq.c2
-rw-r--r--drivers/net/ethernet/intel/ice/ice_controlq.h2
-rw-r--r--drivers/net/ethernet/intel/ice/ice_dcb.c35
-rw-r--r--drivers/net/ethernet/intel/ice/ice_dcb.h12
-rw-r--r--drivers/net/ethernet/intel/ice/ice_dcb_lib.c230
-rw-r--r--drivers/net/ethernet/intel/ice/ice_dcb_lib.h5
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ethtool.c1027
-rw-r--r--drivers/net/ethernet/intel/ice/ice_hw_autogen.h4
-rw-r--r--drivers/net/ethernet/intel/ice/ice_lib.c477
-rw-r--r--drivers/net/ethernet/intel/ice/ice_lib.h14
-rw-r--r--drivers/net/ethernet/intel/ice/ice_main.c364
-rw-r--r--drivers/net/ethernet/intel/ice/ice_nvm.c35
-rw-r--r--drivers/net/ethernet/intel/ice/ice_sched.c4
-rw-r--r--drivers/net/ethernet/intel/ice/ice_status.h1
-rw-r--r--drivers/net/ethernet/intel/ice/ice_switch.c9
-rw-r--r--drivers/net/ethernet/intel/ice/ice_switch.h7
-rw-r--r--drivers/net/ethernet/intel/ice/ice_txrx.c16
-rw-r--r--drivers/net/ethernet/intel/ice/ice_txrx.h35
-rw-r--r--drivers/net/ethernet/intel/ice/ice_type.h13
-rw-r--r--drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c301
-rw-r--r--drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h33
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_82575.c2
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_regs.h2
-rw-r--r--drivers/net/ethernet/intel/igb/igb_ethtool.c75
-rw-r--r--drivers/net/ethernet/intel/igb/igb_main.c47
-rw-r--r--drivers/net/ethernet/intel/igc/igc_base.c49
-rw-r--r--drivers/net/ethernet/intel/igc/igc_defines.h18
-rw-r--r--drivers/net/ethernet/intel/igc/igc_hw.h3
-rw-r--r--drivers/net/ethernet/intel/igc/igc_mac.c23
-rw-r--r--drivers/net/ethernet/intel/igc/igc_main.c22
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe.h14
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c3
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c3
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_main.c36
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h1
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c181
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_type.h14
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c97
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/ethtool.c10
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c3
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/vf.c5
-rw-r--r--drivers/net/ethernet/jme.c5
-rw-r--r--drivers/net/ethernet/lantiq_etop.c12
-rw-r--r--drivers/net/ethernet/marvell/mvmdio.c11
-rw-r--r--drivers/net/ethernet/marvell/mvneta.c38
-rw-r--r--drivers/net/ethernet/marvell/mvneta_bm.c4
-rw-r--r--drivers/net/ethernet/marvell/mvpp2/mvpp2.h39
-rw-r--r--drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c400
-rw-r--r--drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.h43
-rw-r--r--drivers/net/ethernet/marvell/mvpp2/mvpp2_debugfs.c3
-rw-r--r--drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c244
-rw-r--r--drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c26
-rw-r--r--drivers/net/ethernet/marvell/skge.c2
-rw-r--r--drivers/net/ethernet/marvell/sky2.c7
-rw-r--r--drivers/net/ethernet/mediatek/Makefile3
-rw-r--r--drivers/net/ethernet/mediatek/mtk_eth_path.c352
-rw-r--r--drivers/net/ethernet/mediatek/mtk_eth_soc.c142
-rw-r--r--drivers/net/ethernet/mediatek/mtk_eth_soc.h199
-rw-r--r--drivers/net/ethernet/mediatek/mtk_sgmii.c105
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/eq.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/Kconfig53
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/Makefile24
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/accel/ipsec.c9
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/accel/ipsec.h7
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/accel/tls.c45
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/accel/tls.h51
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/cmd.c12
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/cq.c21
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/dev.c34
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/devlink.c118
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/devlink.h14
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/diag/crdump.c115
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/diag/fs_tracepoint.h4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c139
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.h20
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/ecpf.c27
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/ecpf.h4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en.h288
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/params.c108
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/params.h118
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c10
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c304
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.h43
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_geneve.c335
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_gre.c95
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_vxlan.c151
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h208
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c231
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h37
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/xsk/Makefile1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.c192
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.h27
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/xsk/setup.c223
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/xsk/setup.h25
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c111
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.h15
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/xsk/umem.c267
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/xsk/umem.h31
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.c93
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.h97
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c448
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls.c17
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls.h11
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls_rxtx.c7
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls_rxtx.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_dim.c14
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c66
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c20
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_main.c862
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_rep.c334
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_rep.h8
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_rx.c139
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_stats.c143
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_stats.h44
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_tc.c145
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_tc.h9
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_tx.c117
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c54
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eq.c507
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eswitch.c239
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eswitch.h114
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c796
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_termtbl.c277
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/events.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c8
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c8
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.h75
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c13
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fs_core.c76
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fs_core.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c10
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fw.c237
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/health.c569
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c9
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c40
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c5
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lag.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c33
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/crypto.c72
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h14
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/geneve.c157
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/geneve.h33
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h8
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c33
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/pci_vsc.c316
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/pci_vsc.h32
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/port_tun.c23
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/main.c114
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h26
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/mr.c27
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c334
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/rdma.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/sriov.c52
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/vport.c43
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/wq.h5
-rw-r--r--drivers/net/ethernet/mellanox/mlxfw/mlxfw.h11
-rw-r--r--drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c57
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/Kconfig2
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/Makefile1
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/cmd.h12
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core.c57
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core.h30
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c18
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h22
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core_env.c27
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c143
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core_thermal.c248
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/i2c.c76
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/minimal.c18
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/pci.c50
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/pci_hw.h3
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/reg.h524
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.c589
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.h36
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c9
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c10
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_dcb.c16
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c10
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c84
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c1111
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.h186
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c346
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/switchx2.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/trap.h6
-rw-r--r--drivers/net/ethernet/micrel/ks8851.c5
-rw-r--r--drivers/net/ethernet/micrel/ks8851.h5
-rw-r--r--drivers/net/ethernet/microchip/encx24j600-regmap.c5
-rw-r--r--drivers/net/ethernet/mscc/Makefile2
-rw-r--r--drivers/net/ethernet/mscc/ocelot.c26
-rw-r--r--drivers/net/ethernet/mscc/ocelot.h11
-rw-r--r--drivers/net/ethernet/mscc/ocelot_ace.c782
-rw-r--r--drivers/net/ethernet/mscc/ocelot_ace.h232
-rw-r--r--drivers/net/ethernet/mscc/ocelot_board.c6
-rw-r--r--drivers/net/ethernet/mscc/ocelot_flower.c363
-rw-r--r--drivers/net/ethernet/mscc/ocelot_police.c227
-rw-r--r--drivers/net/ethernet/mscc/ocelot_police.h22
-rw-r--r--drivers/net/ethernet/mscc/ocelot_regs.c11
-rw-r--r--drivers/net/ethernet/mscc/ocelot_s2.h64
-rw-r--r--drivers/net/ethernet/mscc/ocelot_tc.c197
-rw-r--r--drivers/net/ethernet/mscc/ocelot_tc.h22
-rw-r--r--drivers/net/ethernet/mscc/ocelot_vcap.h403
-rw-r--r--drivers/net/ethernet/neterion/s2io.c1
-rw-r--r--drivers/net/ethernet/netronome/Kconfig1
-rw-r--r--drivers/net/ethernet/netronome/nfp/Makefile6
-rw-r--r--drivers/net/ethernet/netronome/nfp/abm/cls.c22
-rw-r--r--drivers/net/ethernet/netronome/nfp/abm/main.h2
-rw-r--r--drivers/net/ethernet/netronome/nfp/bpf/jit.c115
-rw-r--r--drivers/net/ethernet/netronome/nfp/bpf/main.c30
-rw-r--r--drivers/net/ethernet/netronome/nfp/bpf/main.h2
-rw-r--r--drivers/net/ethernet/netronome/nfp/bpf/verifier.c12
-rw-r--r--drivers/net/ethernet/netronome/nfp/ccm.c3
-rw-r--r--drivers/net/ethernet/netronome/nfp/ccm.h60
-rw-r--r--drivers/net/ethernet/netronome/nfp/ccm_mbox.c743
-rw-r--r--drivers/net/ethernet/netronome/nfp/crypto/crypto.h27
-rw-r--r--drivers/net/ethernet/netronome/nfp/crypto/fw.h84
-rw-r--r--drivers/net/ethernet/netronome/nfp/crypto/tls.c522
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/action.c260
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/cmsg.h57
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/lag_conf.c4
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/main.h18
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/match.c149
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/metadata.c30
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/offload.c351
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c3
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_main.c4
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net.h73
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_common.c213
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.c15
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h21
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c26
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c7
-rw-r--r--drivers/net/ethernet/netx-eth.c13
-rw-r--r--drivers/net/ethernet/ni/nixge.c2
-rw-r--r--drivers/net/ethernet/pasemi/pasemi_mac.c15
-rw-r--r--drivers/net/ethernet/pasemi/pasemi_mac.h13
-rw-r--r--drivers/net/ethernet/pasemi/pasemi_mac_ethtool.c13
-rw-r--r--drivers/net/ethernet/qlogic/Kconfig1
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c3
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c8
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed.h24
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_cxt.c5
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_debug.c2
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_dev.c1276
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_dev_api.h113
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_fcoe.c26
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_hsi.h16
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_hw.c44
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_init_ops.c9
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_int.c8
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_iscsi.c35
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_iwarp.c67
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_iwarp.h4
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_l2.c4
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_ll2.c406
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_main.c157
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_mcp.c65
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_mcp.h16
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_ptp.c11
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_rdma.c75
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_reg_addr.h6
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_sp_commands.c2
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_sriov.c3
-rw-r--r--drivers/net/ethernet/qlogic/qede/qede.h4
-rw-r--r--drivers/net/ethernet/qlogic/qede/qede_ethtool.c1
-rw-r--r--drivers/net/ethernet/qlogic/qede/qede_filter.c2
-rw-r--r--drivers/net/ethernet/qlogic/qede/qede_main.c42
-rw-r--r--drivers/net/ethernet/qlogic/qede/qede_ptp.c37
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c5
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c2
-rw-r--r--drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h25
-rw-r--r--drivers/net/ethernet/realtek/Makefile1
-rw-r--r--drivers/net/ethernet/realtek/r8169_firmware.c231
-rw-r--r--drivers/net/ethernet/realtek/r8169_firmware.h39
-rw-r--r--drivers/net/ethernet/realtek/r8169_main.c (renamed from drivers/net/ethernet/realtek/r8169.c)1349
-rw-r--r--drivers/net/ethernet/rocker/rocker_main.c4
-rw-r--r--drivers/net/ethernet/rocker/rocker_ofdpa.c25
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h5
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_core.c5
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.c5
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.h5
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.c5
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.h5
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c5
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c5
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_mdio.c5
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.c5
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.h5
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c5
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_reg.h5
-rw-r--r--drivers/net/ethernet/seeq/ether3.c5
-rw-r--r--drivers/net/ethernet/seeq/ether3.h5
-rw-r--r--drivers/net/ethernet/sfc/bitfield.h5
-rw-r--r--drivers/net/ethernet/sfc/ef10.c5
-rw-r--r--drivers/net/ethernet/sfc/ef10_regs.h5
-rw-r--r--drivers/net/ethernet/sfc/ef10_sriov.c5
-rw-r--r--drivers/net/ethernet/sfc/ef10_sriov.h5
-rw-r--r--drivers/net/ethernet/sfc/efx.c11
-rw-r--r--drivers/net/ethernet/sfc/efx.h5
-rw-r--r--drivers/net/ethernet/sfc/enum.h5
-rw-r--r--drivers/net/ethernet/sfc/ethtool.c5
-rw-r--r--drivers/net/ethernet/sfc/falcon/bitfield.h5
-rw-r--r--drivers/net/ethernet/sfc/falcon/efx.c5
-rw-r--r--drivers/net/ethernet/sfc/falcon/efx.h5
-rw-r--r--drivers/net/ethernet/sfc/falcon/enum.h5
-rw-r--r--drivers/net/ethernet/sfc/falcon/ethtool.c5
-rw-r--r--drivers/net/ethernet/sfc/falcon/falcon.c5
-rw-r--r--drivers/net/ethernet/sfc/falcon/falcon_boards.c5
-rw-r--r--drivers/net/ethernet/sfc/falcon/farch.c5
-rw-r--r--drivers/net/ethernet/sfc/falcon/farch_regs.h5
-rw-r--r--drivers/net/ethernet/sfc/falcon/filter.h5
-rw-r--r--drivers/net/ethernet/sfc/falcon/io.h5
-rw-r--r--drivers/net/ethernet/sfc/falcon/mdio_10g.c5
-rw-r--r--drivers/net/ethernet/sfc/falcon/mdio_10g.h5
-rw-r--r--drivers/net/ethernet/sfc/falcon/mtd.c5
-rw-r--r--drivers/net/ethernet/sfc/falcon/net_driver.h5
-rw-r--r--drivers/net/ethernet/sfc/falcon/nic.c5
-rw-r--r--drivers/net/ethernet/sfc/falcon/nic.h5
-rw-r--r--drivers/net/ethernet/sfc/falcon/phy.h5
-rw-r--r--drivers/net/ethernet/sfc/falcon/qt202x_phy.c5
-rw-r--r--drivers/net/ethernet/sfc/falcon/rx.c5
-rw-r--r--drivers/net/ethernet/sfc/falcon/selftest.c5
-rw-r--r--drivers/net/ethernet/sfc/falcon/selftest.h5
-rw-r--r--drivers/net/ethernet/sfc/falcon/tenxpress.c5
-rw-r--r--drivers/net/ethernet/sfc/falcon/tx.c5
-rw-r--r--drivers/net/ethernet/sfc/falcon/tx.h5
-rw-r--r--drivers/net/ethernet/sfc/falcon/txc43128_phy.c5
-rw-r--r--drivers/net/ethernet/sfc/falcon/workarounds.h5
-rw-r--r--drivers/net/ethernet/sfc/farch.c5
-rw-r--r--drivers/net/ethernet/sfc/farch_regs.h5
-rw-r--r--drivers/net/ethernet/sfc/filter.h5
-rw-r--r--drivers/net/ethernet/sfc/io.h5
-rw-r--r--drivers/net/ethernet/sfc/mcdi.c5
-rw-r--r--drivers/net/ethernet/sfc/mcdi.h5
-rw-r--r--drivers/net/ethernet/sfc/mcdi_mon.c5
-rw-r--r--drivers/net/ethernet/sfc/mcdi_pcol.h5
-rw-r--r--drivers/net/ethernet/sfc/mcdi_port.c5
-rw-r--r--drivers/net/ethernet/sfc/mtd.c5
-rw-r--r--drivers/net/ethernet/sfc/net_driver.h5
-rw-r--r--drivers/net/ethernet/sfc/nic.c5
-rw-r--r--drivers/net/ethernet/sfc/nic.h5
-rw-r--r--drivers/net/ethernet/sfc/ptp.c5
-rw-r--r--drivers/net/ethernet/sfc/rx.c5
-rw-r--r--drivers/net/ethernet/sfc/selftest.c5
-rw-r--r--drivers/net/ethernet/sfc/selftest.h5
-rw-r--r--drivers/net/ethernet/sfc/siena.c5
-rw-r--r--drivers/net/ethernet/sfc/siena_sriov.c5
-rw-r--r--drivers/net/ethernet/sfc/siena_sriov.h5
-rw-r--r--drivers/net/ethernet/sfc/sriov.c5
-rw-r--r--drivers/net/ethernet/sfc/sriov.h5
-rw-r--r--drivers/net/ethernet/sfc/tx.c5
-rw-r--r--drivers/net/ethernet/sfc/tx.h5
-rw-r--r--drivers/net/ethernet/sfc/tx_tso.c5
-rw-r--r--drivers/net/ethernet/sfc/vfdi.h5
-rw-r--r--drivers/net/ethernet/sfc/workarounds.h5
-rw-r--r--drivers/net/ethernet/sis/sis900.c34
-rw-r--r--drivers/net/ethernet/smsc/Kconfig6
-rw-r--r--drivers/net/ethernet/socionext/Kconfig1
-rw-r--r--drivers/net/ethernet/socionext/netsec.c577
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Kconfig16
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Makefile2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c13
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.h13
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/common.h20
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/descs.h2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c8
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c131
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c46
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac1000.h1
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c22
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c8
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c13
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c8
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4.h7
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c86
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c13
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c9
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h20
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c29
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c41
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/hwif.c9
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/hwif.h25
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/mmc.h4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/mmc_core.c13
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac.h41
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c96
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c838
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c104
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c1
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c26
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c850
-rw-r--r--drivers/net/ethernet/sun/niu.c2
-rw-r--r--drivers/net/ethernet/ti/Kconfig2
-rw-r--r--drivers/net/ethernet/ti/cpsw-phy-sel.c4
-rw-r--r--drivers/net/ethernet/ti/cpsw.c587
-rw-r--r--drivers/net/ethernet/ti/cpsw_ethtool.c97
-rw-r--r--drivers/net/ethernet/ti/cpsw_priv.h8
-rw-r--r--drivers/net/ethernet/ti/cpts.c88
-rw-r--r--drivers/net/ethernet/ti/cpts.h2
-rw-r--r--drivers/net/ethernet/ti/davinci_cpdma.c187
-rw-r--r--drivers/net/ethernet/ti/davinci_cpdma.h9
-rw-r--r--drivers/net/ethernet/ti/davinci_emac.c6
-rw-r--r--drivers/net/ethernet/ti/netcp_ethss.c9
-rw-r--r--drivers/net/ethernet/ti/tlan.c1
-rw-r--r--drivers/net/ethernet/toshiba/ps3_gelic_net.h2
-rw-r--r--drivers/net/ethernet/toshiba/tc35815.c4
-rw-r--r--drivers/net/ethernet/via/via-velocity.h2
-rw-r--r--drivers/net/ethernet/wiznet/w5100-spi.c24
-rw-r--r--drivers/net/ethernet/xilinx/Kconfig6
-rw-r--r--drivers/net/ethernet/xilinx/ll_temac.h5
-rw-r--r--drivers/net/ethernet/xilinx/ll_temac_main.c258
-rw-r--r--drivers/net/ethernet/xilinx/ll_temac_mdio.c20
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet.h35
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet_main.c678
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c111
-rw-r--r--drivers/net/fddi/defza.c1
-rw-r--r--drivers/net/fddi/skfp/drvfbi.c3
-rw-r--r--drivers/net/fddi/skfp/h/skfbi.h231
-rw-r--r--drivers/net/fjes/fjes_debugfs.c15
-rw-r--r--drivers/net/geneve.c7
-rw-r--r--drivers/net/gtp.c37
-rw-r--r--drivers/net/hippi/rrunner.c2
-rw-r--r--drivers/net/hyperv/netvsc_drv.c2
-rw-r--r--drivers/net/loopback.c78
-rw-r--r--drivers/net/macsec.c6
-rw-r--r--drivers/net/macvlan.c2
-rw-r--r--drivers/net/mdio.c5
-rw-r--r--drivers/net/netdevsim/dev.c44
-rw-r--r--drivers/net/netdevsim/netdev.c29
-rw-r--r--drivers/net/netdevsim/netdevsim.h1
-rw-r--r--drivers/net/phy/Kconfig8
-rw-r--r--drivers/net/phy/Makefile3
-rw-r--r--drivers/net/phy/aquantia_main.c8
-rw-r--r--drivers/net/phy/ax88796b.c (renamed from drivers/net/phy/asix.c)0
-rw-r--r--drivers/net/phy/bcm87xx.c20
-rw-r--r--drivers/net/phy/broadcom.c2
-rw-r--r--drivers/net/phy/dp83867.c193
-rw-r--r--drivers/net/phy/lxt.c6
-rw-r--r--drivers/net/phy/nxp-tja11xx.c403
-rw-r--r--drivers/net/phy/phy-core.c4
-rw-r--r--drivers/net/phy/phy.c128
-rw-r--r--drivers/net/phy/phy_device.c115
-rw-r--r--drivers/net/phy/phylink.c288
-rw-r--r--drivers/net/phy/sfp-bus.c14
-rw-r--r--drivers/net/phy/sfp.c72
-rw-r--r--drivers/net/plip/plip.c4
-rw-r--r--drivers/net/ppp/Kconfig3
-rw-r--r--drivers/net/ppp/ppp_deflate.c5
-rw-r--r--drivers/net/ppp/ppp_mppe.c97
-rw-r--r--drivers/net/tap.c5
-rw-r--r--drivers/net/team/team.c27
-rw-r--r--drivers/net/tun.c27
-rw-r--r--drivers/net/usb/asix_devices.c6
-rw-r--r--drivers/net/usb/cdc_mbim.c5
-rw-r--r--drivers/net/usb/huawei_cdc_ncm.c6
-rw-r--r--drivers/net/usb/pegasus.c5
-rw-r--r--drivers/net/usb/pegasus.h5
-rw-r--r--drivers/net/usb/qmi_wwan.c111
-rw-r--r--drivers/net/usb/r8152.c107
-rw-r--r--drivers/net/usb/rtl8150.c5
-rw-r--r--drivers/net/usb/sr9700.h5
-rw-r--r--drivers/net/veth.c61
-rw-r--r--drivers/net/virtio_net.c2
-rw-r--r--drivers/net/vmxnet3/vmxnet3_drv.c21
-rw-r--r--drivers/net/vmxnet3/vmxnet3_ethtool.c10
-rw-r--r--drivers/net/vmxnet3/vmxnet3_int.h7
-rw-r--r--drivers/net/vrf.c7
-rw-r--r--drivers/net/vxlan.c138
-rw-r--r--drivers/net/wan/hdlc_cisco.c11
-rw-r--r--drivers/net/wan/x25_asy.c4
-rw-r--r--drivers/net/wireless/admtek/adm8211.c6
-rw-r--r--drivers/net/wireless/ath/Kconfig2
-rw-r--r--drivers/net/wireless/ath/Makefile2
-rw-r--r--drivers/net/wireless/ath/ar5523/Kconfig2
-rw-r--r--drivers/net/wireless/ath/ar5523/Makefile2
-rw-r--r--drivers/net/wireless/ath/ath10k/Kconfig2
-rw-r--r--drivers/net/wireless/ath/ath10k/ahb.c2
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c80
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h27
-rw-r--r--drivers/net/wireless/ath/ath10k/coredump.c4
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.c58
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.h25
-rw-r--r--drivers/net/wireless/ath/ath10k/debugfs_sta.c7
-rw-r--r--drivers/net/wireless/ath/ath10k/hif.h15
-rw-r--r--drivers/net/wireless/ath/ath10k/htc.c1
-rw-r--r--drivers/net/wireless/ath/ath10k/htt.c2
-rw-r--r--drivers/net/wireless/ath/ath10k/htt.h76
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_rx.c401
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_tx.c38
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.c6
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.h13
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c225
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.c27
-rw-r--r--drivers/net/wireless/ath/ath10k/qmi.c61
-rw-r--r--drivers/net/wireless/ath/ath10k/qmi.h1
-rw-r--r--drivers/net/wireless/ath/ath10k/sdio.c35
-rw-r--r--drivers/net/wireless/ath/ath10k/snoc.c19
-rw-r--r--drivers/net/wireless/ath/ath10k/swap.c4
-rw-r--r--drivers/net/wireless/ath/ath10k/testmode.c17
-rw-r--r--drivers/net/wireless/ath/ath10k/trace.c1
-rw-r--r--drivers/net/wireless/ath/ath10k/trace.h6
-rw-r--r--drivers/net/wireless/ath/ath10k/txrx.c3
-rw-r--r--drivers/net/wireless/ath/ath10k/usb.c4
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.c61
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.h20
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c37
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.h23
-rw-r--r--drivers/net/wireless/ath/ath5k/Kconfig2
-rw-r--r--drivers/net/wireless/ath/ath5k/Makefile2
-rw-r--r--drivers/net/wireless/ath/ath6kl/Kconfig2
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c4
-rw-r--r--drivers/net/wireless/ath/ath6kl/debug.c3
-rw-r--r--drivers/net/wireless/ath/ath6kl/htc_pipe.c3
-rw-r--r--drivers/net/wireless/ath/ath6kl/trace.h2
-rw-r--r--drivers/net/wireless/ath/ath6kl/wmi.c13
-rw-r--r--drivers/net/wireless/ath/ath9k/Kconfig2
-rw-r--r--drivers/net/wireless/ath/ath9k/Makefile2
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.c24
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_4k.c1
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c40
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c6
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c18
-rw-r--r--drivers/net/wireless/ath/carl9170/mac.c2
-rw-r--r--drivers/net/wireless/ath/carl9170/main.c9
-rw-r--r--drivers/net/wireless/ath/carl9170/rx.c2
-rw-r--r--drivers/net/wireless/ath/carl9170/usb.c39
-rw-r--r--drivers/net/wireless/ath/dfs_pattern_detector.c2
-rw-r--r--drivers/net/wireless/ath/regd.h1
-rw-r--r--drivers/net/wireless/ath/wcn36xx/Kconfig2
-rw-r--r--drivers/net/wireless/ath/wcn36xx/Makefile2
-rw-r--r--drivers/net/wireless/ath/wil6210/Kconfig2
-rw-r--r--drivers/net/wireless/ath/wil6210/Makefile2
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c26
-rw-r--r--drivers/net/wireless/ath/wil6210/debugfs.c238
-rw-r--r--drivers/net/wireless/ath/wil6210/fw.h11
-rw-r--r--drivers/net/wireless/ath/wil6210/fw_inc.c148
-rw-r--r--drivers/net/wireless/ath/wil6210/interrupt.c67
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c37
-rw-r--r--drivers/net/wireless/ath/wil6210/pcie_bus.c3
-rw-r--r--drivers/net/wireless/ath/wil6210/rx_reorder.c33
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c35
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx_edma.c26
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx_edma.h2
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h39
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c141
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.h47
-rw-r--r--drivers/net/wireless/broadcom/b43/dma.c69
-rw-r--r--drivers/net/wireless/broadcom/b43/main.c7
-rw-r--r--drivers/net/wireless/broadcom/b43legacy/dma.c57
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/Kconfig52
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/Makefile14
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/Kconfig50
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile14
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c15
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h16
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/commonring.c16
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/commonring.h16
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c16
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h16
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c15
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h14
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c16
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h16
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c16
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.h16
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c30
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/tracepoint.c13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/tracepoint.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.c13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_hal.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_int.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_qmath.c13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_qmath.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_radio.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phyreg_n.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phytbl_lcn.c13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phytbl_lcn.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phytbl_n.c13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phytbl_n.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmutil/Makefile13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmutil/utils.c13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/include/brcmu_d11.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/include/brcmu_utils.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/include/chipcommon.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/include/defs.h13
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/include/soc.h13
-rw-r--r--drivers/net/wireless/cisco/Kconfig2
-rw-r--r--drivers/net/wireless/cisco/airo.c57
-rw-r--r--drivers/net/wireless/intel/ipw2x00/ipw.h5
-rw-r--r--drivers/net/wireless/intel/ipw2x00/ipw2100.c16
-rw-r--r--drivers/net/wireless/intel/ipw2x00/ipw2100.h16
-rw-r--r--drivers/net/wireless/intel/ipw2x00/ipw2200.c16
-rw-r--r--drivers/net/wireless/intel/ipw2x00/ipw2200.h16
-rw-r--r--drivers/net/wireless/intel/ipw2x00/libipw.h6
-rw-r--r--drivers/net/wireless/intel/ipw2x00/libipw_geo.c16
-rw-r--r--drivers/net/wireless/intel/ipw2x00/libipw_module.c16
-rw-r--r--drivers/net/wireless/intel/ipw2x00/libipw_rx.c6
-rw-r--r--drivers/net/wireless/intel/ipw2x00/libipw_tx.c16
-rw-r--r--drivers/net/wireless/intel/ipw2x00/libipw_wx.c16
-rw-r--r--drivers/net/wireless/intel/iwlegacy/3945-rs.c17
-rw-r--r--drivers/net/wireless/intel/iwlegacy/3945.h3
-rw-r--r--drivers/net/wireless/intel/iwlegacy/4965-rs.c35
-rw-r--r--drivers/net/wireless/intel/iwlegacy/Kconfig4
-rw-r--r--drivers/net/wireless/intel/iwlegacy/common.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/Kconfig2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/cfg/22000.c197
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/lib.c3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/rs.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/acpi.c28
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/acpi.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h22
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/location.h11
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/power.h12
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/scan.h15
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/dbg.c466
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/dbg.h135
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/error-dump.h111
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/file.h17
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/init.c7
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/runtime.h28
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/smem.c12
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-config.h21
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-csr.h3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c33
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-drv.c36
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-prph.h22
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-trans.h75
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/constants.h1
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/d3.c36
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c123
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/fw.c93
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c16
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c68
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mvm.h16
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/nvm.c9
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ops.c46
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c28
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rs.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rx.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/scan.c12
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/sta.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tx.c16
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/utils.c24
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c10
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/drv.c264
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/internal.h31
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/rx.c68
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c11
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/trans.c253
-rw-r--r--drivers/net/wireless/intersil/hostap/hostap_hw.c6
-rw-r--r--drivers/net/wireless/intersil/hostap/hostap_main.c6
-rw-r--r--drivers/net/wireless/intersil/p54/eeprom.c5
-rw-r--r--drivers/net/wireless/intersil/p54/eeprom.h5
-rw-r--r--drivers/net/wireless/intersil/p54/fwio.c5
-rw-r--r--drivers/net/wireless/intersil/p54/led.c5
-rw-r--r--drivers/net/wireless/intersil/p54/lmac.h5
-rw-r--r--drivers/net/wireless/intersil/p54/main.c14
-rw-r--r--drivers/net/wireless/intersil/p54/p54.h5
-rw-r--r--drivers/net/wireless/intersil/p54/p54pci.c5
-rw-r--r--drivers/net/wireless/intersil/p54/p54pci.h5
-rw-r--r--drivers/net/wireless/intersil/p54/p54usb.c48
-rw-r--r--drivers/net/wireless/intersil/p54/p54usb.h5
-rw-r--r--drivers/net/wireless/intersil/p54/txrx.c16
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c10
-rw-r--r--drivers/net/wireless/mac80211_hwsim.h5
-rw-r--r--drivers/net/wireless/marvell/libertas/if_usb.c2
-rw-r--r--drivers/net/wireless/marvell/libertas_tf/if_usb.c2
-rw-r--r--drivers/net/wireless/marvell/mwifiex/11n.c53
-rw-r--r--drivers/net/wireless/marvell/mwifiex/11n.h5
-rw-r--r--drivers/net/wireless/marvell/mwifiex/11n_aggr.c26
-rw-r--r--drivers/net/wireless/marvell/mwifiex/11n_aggr.h2
-rw-r--r--drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c125
-rw-r--r--drivers/net/wireless/marvell/mwifiex/cfg80211.c37
-rw-r--r--drivers/net/wireless/marvell/mwifiex/cmdevt.c103
-rw-r--r--drivers/net/wireless/marvell/mwifiex/fw.h12
-rw-r--r--drivers/net/wireless/marvell/mwifiex/ie.c47
-rw-r--r--drivers/net/wireless/marvell/mwifiex/init.c32
-rw-r--r--drivers/net/wireless/marvell/mwifiex/main.c35
-rw-r--r--drivers/net/wireless/marvell/mwifiex/main.h2
-rw-r--r--drivers/net/wireless/marvell/mwifiex/pcie.c5
-rw-r--r--drivers/net/wireless/marvell/mwifiex/scan.c89
-rw-r--r--drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c5
-rw-r--r--drivers/net/wireless/marvell/mwifiex/sta_event.c10
-rw-r--r--drivers/net/wireless/marvell/mwifiex/sta_ioctl.c4
-rw-r--r--drivers/net/wireless/marvell/mwifiex/tdls.c68
-rw-r--r--drivers/net/wireless/marvell/mwifiex/txrx.c5
-rw-r--r--drivers/net/wireless/marvell/mwifiex/uap_txrx.c10
-rw-r--r--drivers/net/wireless/marvell/mwifiex/usb.c10
-rw-r--r--drivers/net/wireless/marvell/mwifiex/util.c15
-rw-r--r--drivers/net/wireless/marvell/mwifiex/wmm.c111
-rw-r--r--drivers/net/wireless/mediatek/mt76/dma.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mac80211.c62
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76.h24
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/core.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c30
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/dma.c29
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/eeprom.h2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/init.c26
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/mac.c191
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/main.c8
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/mcu.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h15
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/regs.h6
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/dma.c23
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c97
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h61
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/init.c77
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mac.c85
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mac.h5
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/main.c52
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mcu.c1265
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mcu.h56
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h16
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/pci.c7
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/init.c5
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/main.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/phy.c13
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/usb.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02.h1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c4
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c10
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c18
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_dfs.h2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_mac.c106
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_mac.h2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c18
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_regs.h3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c9
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c13
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/init.c9
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c16
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c8
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c23
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c7
-rw-r--r--drivers/net/wireless/mediatek/mt76/usb.c66
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/dma.c54
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/tx.c4
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/commands.c5
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800lib.c96
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800lib.h11
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800mmio.c31
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800mmio.h2
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800pci.c3
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800soc.c3
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800usb.c11
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2x00.h10
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2x00debug.c35
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2x00dev.c10
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2x00link.c15
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2x00queue.h6
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2x00usb.c12
-rw-r--r--drivers/net/wireless/realtek/rtl818x/rtl8180/grf5101.c5
-rw-r--r--drivers/net/wireless/realtek/rtl818x/rtl8180/grf5101.h5
-rw-r--r--drivers/net/wireless/realtek/rtl818x/rtl8180/max2820.c5
-rw-r--r--drivers/net/wireless/realtek/rtl818x/rtl8180/max2820.h5
-rw-r--r--drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225.c5
-rw-r--r--drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225se.c5
-rw-r--r--drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225se.h5
-rw-r--r--drivers/net/wireless/realtek/rtl818x/rtl8180/sa2400.c5
-rw-r--r--drivers/net/wireless/realtek/rtl818x/rtl8180/sa2400.h5
-rw-r--r--drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c5
-rw-r--r--drivers/net/wireless/realtek/rtl818x/rtl8187/leds.c5
-rw-r--r--drivers/net/wireless/realtek/rtl818x/rtl8187/leds.h5
-rw-r--r--drivers/net/wireless/realtek/rtl818x/rtl8187/rfkill.c5
-rw-r--r--drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8187.h5
-rw-r--r--drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8225.c5
-rw-r--r--drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8225.h5
-rw-r--r--drivers/net/wireless/realtek/rtl818x/rtl818x.h5
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c35
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h1
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c3
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/efuse.c5
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rc.c3
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c2
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192de/dm.c695
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c8
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c253
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.h708
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/usb.c5
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/wifi.h3
-rw-r--r--drivers/net/wireless/realtek/rtw88/fw.c6
-rw-r--r--drivers/net/wireless/realtek/rtw88/hci.h2
-rw-r--r--drivers/net/wireless/realtek/rtw88/mac.c8
-rw-r--r--drivers/net/wireless/realtek/rtw88/mac80211.c32
-rw-r--r--drivers/net/wireless/realtek/rtw88/main.c39
-rw-r--r--drivers/net/wireless/realtek/rtw88/main.h38
-rw-r--r--drivers/net/wireless/realtek/rtw88/pci.c10
-rw-r--r--drivers/net/wireless/realtek/rtw88/phy.c1273
-rw-r--r--drivers/net/wireless/realtek/rtw88/phy.h18
-rw-r--r--drivers/net/wireless/realtek/rtw88/regd.c69
-rw-r--r--drivers/net/wireless/realtek/rtw88/regd.h4
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8822c.c436
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8822c.h23
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8822c_table.c799
-rw-r--r--drivers/net/wireless/realtek/rtw88/tx.c2
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_sdio.c21
-rw-r--r--drivers/net/wireless/st/cw1200/bh.c5
-rw-r--r--drivers/net/wireless/st/cw1200/bh.h5
-rw-r--r--drivers/net/wireless/st/cw1200/cw1200.h5
-rw-r--r--drivers/net/wireless/st/cw1200/cw1200_sdio.c5
-rw-r--r--drivers/net/wireless/st/cw1200/cw1200_spi.c5
-rw-r--r--drivers/net/wireless/st/cw1200/debug.c5
-rw-r--r--drivers/net/wireless/st/cw1200/debug.h5
-rw-r--r--drivers/net/wireless/st/cw1200/fwio.c5
-rw-r--r--drivers/net/wireless/st/cw1200/fwio.h5
-rw-r--r--drivers/net/wireless/st/cw1200/hwbus.h5
-rw-r--r--drivers/net/wireless/st/cw1200/hwio.c5
-rw-r--r--drivers/net/wireless/st/cw1200/hwio.h5
-rw-r--r--drivers/net/wireless/st/cw1200/main.c5
-rw-r--r--drivers/net/wireless/st/cw1200/pm.c5
-rw-r--r--drivers/net/wireless/st/cw1200/pm.h5
-rw-r--r--drivers/net/wireless/st/cw1200/queue.c5
-rw-r--r--drivers/net/wireless/st/cw1200/queue.h5
-rw-r--r--drivers/net/wireless/st/cw1200/scan.c5
-rw-r--r--drivers/net/wireless/st/cw1200/scan.h5
-rw-r--r--drivers/net/wireless/st/cw1200/sta.c5
-rw-r--r--drivers/net/wireless/st/cw1200/sta.h5
-rw-r--r--drivers/net/wireless/st/cw1200/txrx.c5
-rw-r--r--drivers/net/wireless/st/cw1200/txrx.h5
-rw-r--r--drivers/net/wireless/st/cw1200/wsm.c5
-rw-r--r--drivers/net/wireless/st/cw1200/wsm.h5
-rw-r--r--drivers/net/wireless/ti/wl18xx/main.c38
-rw-r--r--drivers/net/wireless/ti/wlcore/main.c2
-rw-r--r--drivers/net/wireless/ti/wlcore/rx.c2
-rw-r--r--drivers/net/wireless/ti/wlcore/tx.c2
-rw-r--r--drivers/net/wireless/ti/wlcore/vendor_cmd.c5
-rw-r--r--drivers/net/wireless/ti/wlcore/vendor_cmd.h5
-rw-r--r--drivers/net/wireless/virt_wifi.c2
-rw-r--r--drivers/net/wireless/zydas/zd1201.c5
-rw-r--r--drivers/net/wireless/zydas/zd1201.h5
-rw-r--r--drivers/net/xen-netback/interface.c2
-rw-r--r--drivers/nfc/st-nci/i2c.c2
-rw-r--r--drivers/nvdimm/Kconfig2
-rw-r--r--drivers/nvdimm/Makefile1
-rw-r--r--drivers/nvdimm/claim.c6
-rw-r--r--drivers/nvdimm/dax_devs.c2
-rw-r--r--drivers/nvdimm/namespace_devs.c8
-rw-r--r--drivers/nvdimm/nd.h1
-rw-r--r--drivers/nvdimm/nd_virtio.c125
-rw-r--r--drivers/nvdimm/pfn.h15
-rw-r--r--drivers/nvdimm/pfn_devs.c98
-rw-r--r--drivers/nvdimm/pmem.c69
-rw-r--r--drivers/nvdimm/region_devs.c33
-rw-r--r--drivers/nvdimm/virtio_pmem.c122
-rw-r--r--drivers/nvdimm/virtio_pmem.h55
-rw-r--r--drivers/nvme/host/core.c88
-rw-r--r--drivers/nvme/host/fabrics.c2
-rw-r--r--drivers/nvme/host/fault_inject.c41
-rw-r--r--drivers/nvme/host/fc.c64
-rw-r--r--drivers/nvme/host/lightnvm.c2
-rw-r--r--drivers/nvme/host/multipath.c18
-rw-r--r--drivers/nvme/host/nvme.h43
-rw-r--r--drivers/nvme/host/pci.c167
-rw-r--r--drivers/nvme/host/rdma.c9
-rw-r--r--drivers/nvme/host/tcp.c9
-rw-r--r--drivers/nvme/host/trace.c90
-rw-r--r--drivers/nvme/host/trace.h66
-rw-r--r--drivers/nvme/target/Makefile3
-rw-r--r--drivers/nvme/target/admin-cmd.c3
-rw-r--r--drivers/nvme/target/configfs.c4
-rw-r--r--drivers/nvme/target/core.c12
-rw-r--r--drivers/nvme/target/discovery.c4
-rw-r--r--drivers/nvme/target/fabrics-cmd.c2
-rw-r--r--drivers/nvme/target/fc.c13
-rw-r--r--drivers/nvme/target/fcloop.c81
-rw-r--r--drivers/nvme/target/io-cmd-bdev.c39
-rw-r--r--drivers/nvme/target/loop.c4
-rw-r--r--drivers/nvme/target/nvmet.h10
-rw-r--r--drivers/nvme/target/trace.c201
-rw-r--r--drivers/nvme/target/trace.h141
-rw-r--r--drivers/nvmem/Kconfig9
-rw-r--r--drivers/nvmem/Makefile2
-rw-r--r--drivers/nvmem/core.c2
-rw-r--r--drivers/nvmem/imx-iim.c8
-rw-r--r--drivers/nvmem/imx-ocotp-scu.c161
-rw-r--r--drivers/nvmem/imx-ocotp.c60
-rw-r--r--drivers/nvmem/lpc18xx_eeprom.c5
-rw-r--r--drivers/nvmem/lpc18xx_otp.c5
-rw-r--r--drivers/nvmem/snvs_lpgpr.c5
-rw-r--r--drivers/of/base.c10
-rw-r--r--drivers/of/fdt.c141
-rw-r--r--drivers/of/of_mdio.c2
-rw-r--r--drivers/of/of_reserved_mem.c3
-rw-r--r--drivers/of/platform.c5
-rw-r--r--drivers/of/unittest.c2
-rw-r--r--drivers/opp/Kconfig2
-rw-r--r--drivers/opp/core.c179
-rw-r--r--drivers/opp/cpu.c5
-rw-r--r--drivers/opp/debugfs.c5
-rw-r--r--drivers/opp/of.c35
-rw-r--r--drivers/opp/opp.h5
-rw-r--r--drivers/oprofile/oprofilefs.c20
-rw-r--r--drivers/parport/Kconfig2
-rw-r--r--drivers/parport/parport_ax88796.c6
-rw-r--r--drivers/pci/ats.c2
-rw-r--r--drivers/pci/controller/Kconfig4
-rw-r--r--drivers/pci/controller/dwc/Kconfig2
-rw-r--r--drivers/pci/controller/dwc/pci-dra7xx.c1
-rw-r--r--drivers/pci/controller/dwc/pcie-armada8k.c84
-rw-r--r--drivers/pci/controller/dwc/pcie-designware-host.c12
-rw-r--r--drivers/pci/controller/dwc/pcie-designware.c61
-rw-r--r--drivers/pci/controller/dwc/pcie-designware.h39
-rw-r--r--drivers/pci/controller/dwc/pcie-kirin.c2
-rw-r--r--drivers/pci/controller/dwc/pcie-qcom.c115
-rw-r--r--drivers/pci/controller/pci-aardvark.c2
-rw-r--r--drivers/pci/controller/pci-hyperv.c15
-rw-r--r--drivers/pci/controller/pci-tegra.c589
-rw-r--r--drivers/pci/controller/pcie-altera-msi.c10
-rw-r--r--drivers/pci/controller/pcie-altera.c69
-rw-r--r--drivers/pci/controller/pcie-iproc-platform.c2
-rw-r--r--drivers/pci/controller/pcie-iproc.c2
-rw-r--r--drivers/pci/controller/pcie-mobiveil.c525
-rw-r--r--drivers/pci/controller/pcie-xilinx-nwl.c11
-rw-r--r--drivers/pci/controller/vmd.c2
-rw-r--r--drivers/pci/endpoint/functions/pci-epf-test.c35
-rw-r--r--drivers/pci/endpoint/pci-epc-core.c3
-rw-r--r--drivers/pci/iov.c2
-rw-r--r--drivers/pci/mmap.c2
-rw-r--r--drivers/pci/msi.c43
-rw-r--r--drivers/pci/of.c8
-rw-r--r--drivers/pci/p2pdma.c72
-rw-r--r--drivers/pci/pci-acpi.c14
-rw-r--r--drivers/pci/pci-bridge-emul.c2
-rw-r--r--drivers/pci/pci-driver.c137
-rw-r--r--drivers/pci/pci-pf-stub.c2
-rw-r--r--drivers/pci/pci-sysfs.c5
-rw-r--r--drivers/pci/pci.c122
-rw-r--r--drivers/pci/pci.h9
-rw-r--r--drivers/pci/pcie/aer_inject.c2
-rw-r--r--drivers/pci/pcie/aspm.c20
-rw-r--r--drivers/pci/pcie/portdrv_core.c66
-rw-r--r--drivers/pci/probe.c30
-rw-r--r--drivers/pci/proc.c2
-rw-r--r--drivers/pci/quirks.c110
-rw-r--r--drivers/pci/search.c4
-rw-r--r--drivers/pci/setup-bus.c60
-rw-r--r--drivers/pci/slot.c1
-rw-r--r--drivers/pci/switch/Kconfig2
-rw-r--r--drivers/pcmcia/cardbus.c5
-rw-r--r--drivers/pcmcia/cistpl.c5
-rw-r--r--drivers/pcmcia/cs.c5
-rw-r--r--drivers/pcmcia/cs_internal.h6
-rw-r--r--drivers/pcmcia/ds.c7
-rw-r--r--drivers/pcmcia/pcmcia_cis.c6
-rw-r--r--drivers/pcmcia/pcmcia_resource.c6
-rw-r--r--drivers/pcmcia/pxa2xx_balloon3.c5
-rw-r--r--drivers/pcmcia/pxa2xx_cm_x255.c6
-rw-r--r--drivers/pcmcia/pxa2xx_cm_x270.c6
-rw-r--r--drivers/pcmcia/pxa2xx_cm_x2xx.c6
-rw-r--r--drivers/pcmcia/pxa2xx_colibri.c6
-rw-r--r--drivers/pcmcia/pxa2xx_e740.c5
-rw-r--r--drivers/pcmcia/pxa2xx_hx4700.c5
-rw-r--r--drivers/pcmcia/pxa2xx_mainstone.c5
-rw-r--r--drivers/pcmcia/pxa2xx_palmld.c6
-rw-r--r--drivers/pcmcia/pxa2xx_palmtc.c6
-rw-r--r--drivers/pcmcia/pxa2xx_palmtx.c6
-rw-r--r--drivers/pcmcia/pxa2xx_sharpsl.c6
-rw-r--r--drivers/pcmcia/pxa2xx_stargate2.c5
-rw-r--r--drivers/pcmcia/pxa2xx_trizeps4.c5
-rw-r--r--drivers/pcmcia/pxa2xx_vpac270.c6
-rw-r--r--drivers/pcmcia/rsrc_iodyn.c5
-rw-r--r--drivers/pcmcia/rsrc_mgr.c5
-rw-r--r--drivers/pcmcia/rsrc_nonstatic.c5
-rw-r--r--drivers/pcmcia/sa1111_badge4.c6
-rw-r--r--drivers/pcmcia/sa1111_lubbock.c6
-rw-r--r--drivers/pcmcia/socket_sysfs.c5
-rw-r--r--drivers/perf/Kconfig8
-rw-r--r--drivers/perf/Makefile1
-rw-r--r--drivers/perf/arm_dsu_pmu.c5
-rw-r--r--drivers/perf/arm_pmu_acpi.c77
-rw-r--r--drivers/perf/arm_spe_pmu.c25
-rw-r--r--drivers/perf/fsl_imx8_ddr_perf.c554
-rw-r--r--drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c5
-rw-r--r--drivers/perf/hisilicon/hisi_uncore_hha_pmu.c5
-rw-r--r--drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c5
-rw-r--r--drivers/perf/hisilicon/hisi_uncore_pmu.c5
-rw-r--r--drivers/perf/hisilicon/hisi_uncore_pmu.h5
-rw-r--r--drivers/perf/qcom_l3_pmu.c2
-rw-r--r--drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c2
-rw-r--r--drivers/phy/broadcom/phy-bcm-ns-usb2.c6
-rw-r--r--drivers/phy/broadcom/phy-bcm-ns-usb3.c5
-rw-r--r--drivers/phy/broadcom/phy-brcm-usb.c9
-rw-r--r--drivers/phy/freescale/Kconfig10
-rw-r--r--drivers/phy/freescale/Makefile1
-rw-r--r--drivers/phy/freescale/phy-fsl-imx8-mipi-dphy.c497
-rw-r--r--drivers/phy/hisilicon/phy-histb-combphy.c5
-rw-r--r--drivers/phy/lantiq/phy-lantiq-rcu-usb2.c5
-rw-r--r--drivers/phy/phy-lpc18xx-usb-otg.c6
-rw-r--r--drivers/phy/qualcomm/Kconfig8
-rw-r--r--drivers/phy/qualcomm/Makefile1
-rw-r--r--drivers/phy/qualcomm/phy-qcom-pcie2.c331
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp.c5
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qusb2.c2
-rw-r--r--drivers/phy/qualcomm/phy-qcom-usb-hs.c5
-rw-r--r--drivers/phy/qualcomm/phy-qcom-usb-hsic.c5
-rw-r--r--drivers/phy/renesas/phy-rcar-gen2.c2
-rw-r--r--drivers/phy/renesas/phy-rcar-gen3-usb2.c19
-rw-r--r--drivers/phy/rockchip/phy-rockchip-emmc.c10
-rw-r--r--drivers/phy/rockchip/phy-rockchip-pcie.c10
-rw-r--r--drivers/phy/rockchip/phy-rockchip-usb.c10
-rw-r--r--drivers/phy/samsung/phy-exynos-dp-video.c5
-rw-r--r--drivers/phy/samsung/phy-exynos-mipi-video.c5
-rw-r--r--drivers/phy/samsung/phy-exynos-pcie.c5
-rw-r--r--drivers/phy/samsung/phy-exynos4210-usb2.c5
-rw-r--r--drivers/phy/samsung/phy-exynos4x12-usb2.c5
-rw-r--r--drivers/phy/samsung/phy-exynos5-usbdrd.c5
-rw-r--r--drivers/phy/samsung/phy-exynos5250-sata.c5
-rw-r--r--drivers/phy/samsung/phy-exynos5250-usb2.c5
-rw-r--r--drivers/phy/samsung/phy-s5pv210-usb2.c5
-rw-r--r--drivers/phy/samsung/phy-samsung-usb2.c10
-rw-r--r--drivers/phy/samsung/phy-samsung-usb2.h5
-rw-r--r--drivers/phy/st/phy-miphy28lp.c6
-rw-r--r--drivers/phy/st/phy-spear1310-miphy.c6
-rw-r--r--drivers/phy/st/phy-spear1340-miphy.c6
-rw-r--r--drivers/phy/st/phy-stih407-usb.c6
-rw-r--r--drivers/phy/tegra/xusb-tegra124.c9
-rw-r--r--drivers/phy/tegra/xusb-tegra210.c9
-rw-r--r--drivers/phy/ti/phy-am654-serdes.c4
-rw-r--r--drivers/phy/ti/phy-tusb1210.c5
-rw-r--r--drivers/pinctrl/aspeed/Makefile2
-rw-r--r--drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c94
-rw-r--r--drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c127
-rw-r--r--drivers/pinctrl/aspeed/pinctrl-aspeed.c246
-rw-r--r--drivers/pinctrl/aspeed/pinctrl-aspeed.h542
-rw-r--r--drivers/pinctrl/aspeed/pinmux-aspeed.c96
-rw-r--r--drivers/pinctrl/aspeed/pinmux-aspeed.h735
-rw-r--r--drivers/pinctrl/bcm/Kconfig6
-rw-r--r--drivers/pinctrl/bcm/pinctrl-ns2-mux.c2
-rw-r--r--drivers/pinctrl/cirrus/pinctrl-cs47l35.c6
-rw-r--r--drivers/pinctrl/cirrus/pinctrl-cs47l85.c6
-rw-r--r--drivers/pinctrl/cirrus/pinctrl-cs47l90.c6
-rw-r--r--drivers/pinctrl/cirrus/pinctrl-madera-core.c6
-rw-r--r--drivers/pinctrl/cirrus/pinctrl-madera.h6
-rw-r--r--drivers/pinctrl/core.c44
-rw-r--r--drivers/pinctrl/devicetree.c7
-rw-r--r--drivers/pinctrl/freescale/Kconfig7
-rw-r--r--drivers/pinctrl/freescale/Makefile1
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx8mn.c348
-rw-r--r--drivers/pinctrl/intel/pinctrl-baytrail.c322
-rw-r--r--drivers/pinctrl/mediatek/mtk-eint.c34
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8183.c1
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-paris.c19
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-paris.h2
-rw-r--r--drivers/pinctrl/meson/pinctrl-meson-g12a.c36
-rw-r--r--drivers/pinctrl/meson/pinctrl-meson.c350
-rw-r--r--drivers/pinctrl/meson/pinctrl-meson.h18
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-kirkwood.c576
-rw-r--r--drivers/pinctrl/nomadik/pinctrl-ab8500.c5
-rw-r--r--drivers/pinctrl/nomadik/pinctrl-ab8505.c5
-rw-r--r--drivers/pinctrl/nomadik/pinctrl-nomadik.c5
-rw-r--r--drivers/pinctrl/pinconf-generic.c2
-rw-r--r--drivers/pinctrl/pinctrl-bm1880.c733
-rw-r--r--drivers/pinctrl/pinctrl-falcon.c5
-rw-r--r--drivers/pinctrl/pinctrl-mcp23s08.c8
-rw-r--r--drivers/pinctrl/pinctrl-ocelot.c18
-rw-r--r--drivers/pinctrl/pinctrl-rockchip.c1
-rw-r--r--drivers/pinctrl/pinctrl-st.c5
-rw-r--r--drivers/pinctrl/pinctrl-stmfx.c1
-rw-r--r--drivers/pinctrl/pinctrl-tb10x.c12
-rw-r--r--drivers/pinctrl/qcom/Kconfig11
-rw-r--r--drivers/pinctrl/qcom/Makefile1
-rw-r--r--drivers/pinctrl/qcom/pinctrl-msm.c43
-rw-r--r--drivers/pinctrl/qcom/pinctrl-msm.h1
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sdm845.c46
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sm8150.c1548
-rw-r--r--drivers/pinctrl/sh-pfc/core.c60
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-emev2.c70
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a73a4.c2
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7740.c2
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a77470.c2
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7778.c125
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7779.c2
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7790.c36
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7791.c2
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7792.c2
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7794.c2
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7795-es1.c434
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7795.c414
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7796.c414
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a77965.c410
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a77970.c26
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a77980.c2
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a77990.c181
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a77995.c2
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh73a0.c21
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh7734.c2
-rw-r--r--drivers/pinctrl/sh-pfc/pinctrl.c3
-rw-r--r--drivers/pinctrl/sh-pfc/sh_pfc.h90
-rw-r--r--drivers/pinctrl/stm32/pinctrl-stm32.c184
-rw-r--r--drivers/pinctrl/stm32/pinctrl-stm32.h2
-rw-r--r--drivers/pinctrl/stm32/pinctrl-stm32mp157.c5
-rw-r--r--drivers/pinctrl/tegra/Kconfig4
-rw-r--r--drivers/pinctrl/tegra/Makefile1
-rw-r--r--drivers/pinctrl/tegra/pinctrl-tegra.c26
-rw-r--r--drivers/pinctrl/tegra/pinctrl-tegra.h12
-rw-r--r--drivers/pinctrl/tegra/pinctrl-tegra114.c6
-rw-r--r--drivers/pinctrl/tegra/pinctrl-tegra124.c6
-rw-r--r--drivers/pinctrl/tegra/pinctrl-tegra194.c170
-rw-r--r--drivers/pinctrl/tegra/pinctrl-tegra20.c6
-rw-r--r--drivers/pinctrl/tegra/pinctrl-tegra210.c62
-rw-r--r--drivers/pinctrl/tegra/pinctrl-tegra30.c4
-rw-r--r--drivers/pinctrl/zte/pinctrl-zx.c5
-rw-r--r--drivers/pinctrl/zte/pinctrl-zx.h5
-rw-r--r--drivers/pinctrl/zte/pinctrl-zx296718.c5
-rw-r--r--drivers/platform/Kconfig2
-rw-r--r--drivers/platform/Makefile2
-rw-r--r--drivers/platform/chrome/Kconfig42
-rw-r--r--drivers/platform/chrome/Makefile4
-rw-r--r--drivers/platform/chrome/cros_ec_debugfs.c48
-rw-r--r--drivers/platform/chrome/cros_ec_ishtp.c763
-rw-r--r--drivers/platform/chrome/cros_ec_lightbar.c6
-rw-r--r--drivers/platform/chrome/cros_ec_lpc.c165
-rw-r--r--drivers/platform/chrome/cros_ec_lpc_mec.c14
-rw-r--r--drivers/platform/chrome/cros_ec_lpc_reg.c101
-rw-r--r--drivers/platform/chrome/cros_ec_lpc_reg.h45
-rw-r--r--drivers/platform/chrome/cros_ec_spi.c68
-rw-r--r--drivers/platform/chrome/cros_ec_sysfs.c2
-rw-r--r--drivers/platform/chrome/cros_ec_vbc.c2
-rw-r--r--drivers/platform/chrome/wilco_ec/Kconfig18
-rw-r--r--drivers/platform/chrome/wilco_ec/Makefile6
-rw-r--r--drivers/platform/chrome/wilco_ec/core.c26
-rw-r--r--drivers/platform/chrome/wilco_ec/debugfs.c12
-rw-r--r--drivers/platform/chrome/wilco_ec/event.c581
-rw-r--r--drivers/platform/chrome/wilco_ec/mailbox.c21
-rw-r--r--drivers/platform/chrome/wilco_ec/properties.c132
-rw-r--r--drivers/platform/chrome/wilco_ec/sysfs.c156
-rw-r--r--drivers/platform/chrome/wilco_ec/telemetry.c450
-rw-r--r--drivers/platform/olpc/Kconfig29
-rw-r--r--drivers/platform/olpc/Makefile3
-rw-r--r--drivers/platform/olpc/olpc-ec.c174
-rw-r--r--drivers/platform/olpc/olpc-xo175-ec.c753
-rw-r--r--drivers/platform/x86/Kconfig29
-rw-r--r--drivers/platform/x86/Makefile4
-rw-r--r--drivers/platform/x86/acer-wireless.c5
-rw-r--r--drivers/platform/x86/acer-wmi.c33
-rw-r--r--drivers/platform/x86/apple-gmux.c5
-rw-r--r--drivers/platform/x86/asus-nb-wmi.c3
-rw-r--r--drivers/platform/x86/asus-wireless.c5
-rw-r--r--drivers/platform/x86/asus-wmi.c483
-rw-r--r--drivers/platform/x86/dcdbas.c2
-rw-r--r--drivers/platform/x86/dell-laptop.c10
-rw-r--r--drivers/platform/x86/dell-smbios-base.c5
-rw-r--r--drivers/platform/x86/dell-smbios-smm.c5
-rw-r--r--drivers/platform/x86/dell-smbios-wmi.c7
-rw-r--r--drivers/platform/x86/dell-smbios.h5
-rw-r--r--drivers/platform/x86/dell-smo8800.c1
-rw-r--r--drivers/platform/x86/dell-wmi-descriptor.c3
-rw-r--r--drivers/platform/x86/dell-wmi-descriptor.h5
-rw-r--r--drivers/platform/x86/dell-wmi.c2
-rw-r--r--drivers/platform/x86/dell_rbu.c2
-rw-r--r--drivers/platform/x86/hp_accel.c1
-rw-r--r--drivers/platform/x86/huawei-wmi.c2
-rw-r--r--drivers/platform/x86/ideapad-laptop.c36
-rw-r--r--drivers/platform/x86/intel-wmi-thunderbolt.c3
-rw-r--r--drivers/platform/x86/intel_cht_int33fe.c291
-rw-r--r--drivers/platform/x86/intel_int0002_vgpio.c22
-rw-r--r--drivers/platform/x86/intel_menlow.c8
-rw-r--r--drivers/platform/x86/intel_pmc_core.c63
-rw-r--r--drivers/platform/x86/intel_pmc_core_pltdrv.c62
-rw-r--r--drivers/platform/x86/intel_speed_select_if/Kconfig17
-rw-r--r--drivers/platform/x86/intel_speed_select_if/Makefile10
-rw-r--r--drivers/platform/x86/intel_speed_select_if/isst_if_common.c672
-rw-r--r--drivers/platform/x86/intel_speed_select_if/isst_if_common.h69
-rw-r--r--drivers/platform/x86/intel_speed_select_if/isst_if_mbox_msr.c216
-rw-r--r--drivers/platform/x86/intel_speed_select_if/isst_if_mbox_pci.c214
-rw-r--r--drivers/platform/x86/intel_speed_select_if/isst_if_mmio.c180
-rw-r--r--drivers/platform/x86/intel_telemetry_debugfs.c78
-rw-r--r--drivers/platform/x86/mlx-platform.c216
-rw-r--r--drivers/platform/x86/pcengines-apuv2.c4
-rw-r--r--drivers/platform/x86/peaq-wmi.c5
-rw-r--r--drivers/platform/x86/pmc_atom.c51
-rw-r--r--drivers/platform/x86/samsung-laptop.c95
-rw-r--r--drivers/platform/x86/samsung-q10.c6
-rw-r--r--drivers/platform/x86/toshiba_bluetooth.c5
-rw-r--r--drivers/platform/x86/touchscreen_dmi.c28
-rw-r--r--drivers/platform/x86/wmi-bmof.c2
-rw-r--r--drivers/platform/x86/wmi.c44
-rw-r--r--drivers/platform/x86/xiaomi-wmi.c92
-rw-r--r--drivers/pnp/isapnp/Kconfig2
-rw-r--r--drivers/power/avs/smartreflex.c41
-rw-r--r--drivers/power/reset/Kconfig10
-rw-r--r--drivers/power/reset/Makefile1
-rw-r--r--drivers/power/reset/arm-versatile-reboot.c6
-rw-r--r--drivers/power/reset/gpio-poweroff.c6
-rw-r--r--drivers/power/reset/hisi-reboot.c5
-rw-r--r--drivers/power/reset/keystone-reset.c5
-rw-r--r--drivers/power/reset/nvmem-reboot-mode.c76
-rw-r--r--drivers/power/reset/qcom-pon.c12
-rw-r--r--drivers/power/reset/restart-poweroff.c5
-rw-r--r--drivers/power/reset/st-poweroff.c5
-rw-r--r--drivers/power/reset/zx-reboot.c5
-rw-r--r--drivers/power/supply/88pm860x_battery.c5
-rw-r--r--drivers/power/supply/88pm860x_charger.c5
-rw-r--r--drivers/power/supply/Kconfig34
-rw-r--r--drivers/power/supply/Makefile3
-rw-r--r--drivers/power/supply/act8945a_charger.c6
-rw-r--r--drivers/power/supply/bd70528-charger.c743
-rw-r--r--drivers/power/supply/bq24190_charger.c7
-rw-r--r--drivers/power/supply/bq24257_charger.c2
-rw-r--r--drivers/power/supply/bq25890_charger.c2
-rw-r--r--drivers/power/supply/charger-manager.c4
-rw-r--r--drivers/power/supply/collie_battery.c6
-rw-r--r--drivers/power/supply/cros_usbpd-charger.c116
-rw-r--r--drivers/power/supply/da9030_battery.c5
-rw-r--r--drivers/power/supply/ds2780_battery.c6
-rw-r--r--drivers/power/supply/ds2781_battery.c6
-rw-r--r--drivers/power/supply/ds2782_battery.c6
-rw-r--r--drivers/power/supply/ipaq_micro_battery.c5
-rw-r--r--drivers/power/supply/jz4740-battery.c6
-rw-r--r--drivers/power/supply/lp8727_charger.c6
-rw-r--r--drivers/power/supply/lp8788-charger.c6
-rw-r--r--drivers/power/supply/max14656_charger_detector.c8
-rw-r--r--drivers/power/supply/max17040_battery.c2
-rw-r--r--drivers/power/supply/max17042_battery.c2
-rw-r--r--drivers/power/supply/max8925_power.c5
-rw-r--r--drivers/power/supply/olpc_battery.c6
-rw-r--r--drivers/power/supply/pda_power.c5
-rw-r--r--drivers/power/supply/pm2301_charger.c5
-rw-r--r--drivers/power/supply/pmu_battery.c5
-rw-r--r--drivers/power/supply/power_supply_core.c9
-rw-r--r--drivers/power/supply/power_supply_hwmon.c355
-rw-r--r--drivers/power/supply/power_supply_sysfs.c2
-rw-r--r--drivers/power/supply/rt5033_battery.c2
-rw-r--r--drivers/power/supply/rt9455_charger.c2
-rw-r--r--drivers/power/supply/sbs-manager.c7
-rw-r--r--drivers/power/supply/smb347-charger.c5
-rw-r--r--drivers/power/supply/test_power.c5
-rw-r--r--drivers/power/supply/tosa_battery.c6
-rw-r--r--drivers/power/supply/ucs1002_power.c2
-rw-r--r--drivers/power/supply/wilco-charger.c187
-rw-r--r--drivers/power/supply/wm831x_backup.c5
-rw-r--r--drivers/power/supply/wm831x_power.c5
-rw-r--r--drivers/power/supply/wm8350_power.c5
-rw-r--r--drivers/power/supply/wm97xx_battery.c6
-rw-r--r--drivers/power/supply/z2_battery.c6
-rw-r--r--drivers/powercap/Kconfig11
-rw-r--r--drivers/powercap/Makefile3
-rw-r--r--drivers/powercap/intel_rapl_common.c (renamed from drivers/powercap/intel_rapl.c)836
-rw-r--r--drivers/powercap/intel_rapl_msr.c183
-rw-r--r--drivers/pps/pps.c8
-rw-r--r--drivers/ptp/Kconfig2
-rw-r--r--drivers/ptp/ptp_clock.c3
-rw-r--r--drivers/pwm/Kconfig11
-rw-r--r--drivers/pwm/Makefile1
-rw-r--r--drivers/pwm/core.c172
-rw-r--r--drivers/pwm/pwm-atmel-hlcdc.c14
-rw-r--r--drivers/pwm/pwm-bcm2835.c8
-rw-r--r--drivers/pwm/pwm-fsl-ftm.c383
-rw-r--r--drivers/pwm/pwm-jz4740.c49
-rw-r--r--drivers/pwm/pwm-lpss-pci.c5
-rw-r--r--drivers/pwm/pwm-lpss-platform.c5
-rw-r--r--drivers/pwm/pwm-lpss.c5
-rw-r--r--drivers/pwm/pwm-lpss.h5
-rw-r--r--drivers/pwm/pwm-meson.c386
-rw-r--r--drivers/pwm/pwm-omap-dmtimer.c5
-rw-r--r--drivers/pwm/pwm-pca9685.c13
-rw-r--r--drivers/pwm/pwm-puv3.c5
-rw-r--r--drivers/pwm/pwm-pxa.c5
-rw-r--r--drivers/pwm/pwm-rcar.c39
-rw-r--r--drivers/pwm/pwm-rockchip.c5
-rw-r--r--drivers/pwm/pwm-sifive.c339
-rw-r--r--drivers/pwm/pwm-stm32-lp.c25
-rw-r--r--drivers/pwm/pwm-stm32.c2
-rw-r--r--drivers/pwm/pwm-stmpe.c6
-rw-r--r--drivers/pwm/pwm-twl-led.c13
-rw-r--r--drivers/pwm/pwm-twl.c13
-rw-r--r--drivers/pwm/pwm-zx.c5
-rw-r--r--drivers/pwm/sysfs.c102
-rw-r--r--drivers/rapidio/Kconfig2
-rw-r--r--drivers/rapidio/devices/rio_mport_cdev.c2
-rw-r--r--drivers/ras/cec.c132
-rw-r--r--drivers/regulator/88pm800-regulator.c (renamed from drivers/regulator/88pm800.c)5
-rw-r--r--drivers/regulator/88pm8607.c5
-rw-r--r--drivers/regulator/Kconfig43
-rw-r--r--drivers/regulator/Makefile4
-rw-r--r--drivers/regulator/arizona-ldo1.c83
-rw-r--r--drivers/regulator/arizona-micsupp.c72
-rw-r--r--drivers/regulator/bd70528-regulator.c1
-rw-r--r--drivers/regulator/bd718x7-regulator.c26
-rw-r--r--drivers/regulator/core.c280
-rw-r--r--drivers/regulator/cpcap-regulator.c2
-rw-r--r--drivers/regulator/da9062-regulator.c40
-rw-r--r--drivers/regulator/da9063-regulator.c61
-rw-r--r--drivers/regulator/da9211-regulator.c2
-rw-r--r--drivers/regulator/helpers.c11
-rw-r--r--drivers/regulator/lm363x-regulator.c83
-rw-r--r--drivers/regulator/lp3971.c6
-rw-r--r--drivers/regulator/lp3972.c6
-rw-r--r--drivers/regulator/lp872x.c6
-rw-r--r--drivers/regulator/lp8755.c6
-rw-r--r--drivers/regulator/lp87565-regulator.c18
-rw-r--r--drivers/regulator/lp8788-buck.c6
-rw-r--r--drivers/regulator/lp8788-ldo.c6
-rw-r--r--drivers/regulator/max77620-regulator.c28
-rw-r--r--drivers/regulator/max77650-regulator.c170
-rw-r--r--drivers/regulator/max77802-regulator.c2
-rw-r--r--drivers/regulator/max8649.c5
-rw-r--r--drivers/regulator/max8907-regulator.c5
-rw-r--r--drivers/regulator/max8925-regulator.c5
-rw-r--r--drivers/regulator/max8952.c64
-rw-r--r--drivers/regulator/of_regulator.c63
-rw-r--r--drivers/regulator/pwm-regulator.c5
-rw-r--r--drivers/regulator/qcom_spmi-regulator.c252
-rw-r--r--drivers/regulator/rk808-regulator.c646
-rw-r--r--drivers/regulator/s2mps11.c255
-rw-r--r--drivers/regulator/s5m8767.c4
-rw-r--r--drivers/regulator/slg51000-regulator.c523
-rw-r--r--drivers/regulator/slg51000-regulator.h505
-rw-r--r--drivers/regulator/stm32-booster.c132
-rw-r--r--drivers/regulator/tps65090-regulator.c7
-rw-r--r--drivers/regulator/tps6586x-regulator.c5
-rw-r--r--drivers/regulator/wm831x-dcdc.c29
-rw-r--r--drivers/remoteproc/Kconfig18
-rw-r--r--drivers/remoteproc/Makefile1
-rw-r--r--drivers/remoteproc/da8xx_remoteproc.c5
-rw-r--r--drivers/remoteproc/imx_rproc.c13
-rw-r--r--drivers/remoteproc/qcom_q6v5_adsp.c73
-rw-r--r--drivers/remoteproc/qcom_q6v5_mss.c33
-rw-r--r--drivers/remoteproc/remoteproc_core.c15
-rw-r--r--drivers/remoteproc/remoteproc_elf_loader.c3
-rw-r--r--drivers/remoteproc/remoteproc_internal.h11
-rw-r--r--drivers/remoteproc/st_remoteproc.c5
-rw-r--r--drivers/remoteproc/stm32_rproc.c628
-rw-r--r--drivers/reset/hisilicon/hi6220_reset.c5
-rw-r--r--drivers/reset/reset-lantiq.c4
-rw-r--r--drivers/reset/reset-lpc18xx.c6
-rw-r--r--drivers/reset/tegra/reset-bpmp.c5
-rw-r--r--drivers/rpmsg/rpmsg_core.c3
-rw-r--r--drivers/rtc/Kconfig15
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/interface.c2
-rw-r--r--drivers/rtc/rtc-88pm860x.c5
-rw-r--r--drivers/rtc/rtc-bd70528.c500
-rw-r--r--drivers/rtc/rtc-bq32k.c5
-rw-r--r--drivers/rtc/rtc-ds1305.c6
-rw-r--r--drivers/rtc/rtc-ds1307.c134
-rw-r--r--drivers/rtc/rtc-ds1343.c6
-rw-r--r--drivers/rtc/rtc-ds1347.c6
-rw-r--r--drivers/rtc/rtc-ds1390.c5
-rw-r--r--drivers/rtc/rtc-ds1511.c5
-rw-r--r--drivers/rtc/rtc-ds1553.c5
-rw-r--r--drivers/rtc/rtc-ds1685.c5
-rw-r--r--drivers/rtc/rtc-ds1742.c5
-rw-r--r--drivers/rtc/rtc-ds2404.c5
-rw-r--r--drivers/rtc/rtc-em3027.c5
-rw-r--r--drivers/rtc/rtc-fm3130.c13
-rw-r--r--drivers/rtc/rtc-imx-sc.c87
-rw-r--r--drivers/rtc/rtc-isl12022.c5
-rw-r--r--drivers/rtc/rtc-lp8788.c6
-rw-r--r--drivers/rtc/rtc-m41t80.c8
-rw-r--r--drivers/rtc/rtc-m41t93.c5
-rw-r--r--drivers/rtc/rtc-m41t94.c5
-rw-r--r--drivers/rtc/rtc-m48t59.c5
-rw-r--r--drivers/rtc/rtc-m48t86.c5
-rw-r--r--drivers/rtc/rtc-max6902.c6
-rw-r--r--drivers/rtc/rtc-max6916.c6
-rw-r--r--drivers/rtc/rtc-max8907.c5
-rw-r--r--drivers/rtc/rtc-max8925.c5
-rw-r--r--drivers/rtc/rtc-mcp795.c6
-rw-r--r--drivers/rtc/rtc-mpc5121.c5
-rw-r--r--drivers/rtc/rtc-pcf2123.c360
-rw-r--r--drivers/rtc/rtc-pcf2127.c5
-rw-r--r--drivers/rtc/rtc-pcf8523.c5
-rw-r--r--drivers/rtc/rtc-pcf8563.c18
-rw-r--r--drivers/rtc/rtc-pcf8583.c5
-rw-r--r--drivers/rtc/rtc-pl030.c5
-rw-r--r--drivers/rtc/rtc-puv3.c5
-rw-r--r--drivers/rtc/rtc-r9701.c5
-rw-r--r--drivers/rtc/rtc-rk808.c68
-rw-r--r--drivers/rtc/rtc-rs5c348.c5
-rw-r--r--drivers/rtc/rtc-rs5c372.c5
-rw-r--r--drivers/rtc/rtc-rv3029c2.c6
-rw-r--r--drivers/rtc/rtc-rv8803.c2
-rw-r--r--drivers/rtc/rtc-rx4581.c10
-rw-r--r--drivers/rtc/rtc-rx8010.c8
-rw-r--r--drivers/rtc/rtc-rx8025.c7
-rw-r--r--drivers/rtc/rtc-rx8581.c5
-rw-r--r--drivers/rtc/rtc-s35390a.c55
-rw-r--r--drivers/rtc/rtc-s3c.c5
-rw-r--r--drivers/rtc/rtc-s3c.h5
-rw-r--r--drivers/rtc/rtc-st-lpc.c4
-rw-r--r--drivers/rtc/rtc-stk17ta8.c5
-rw-r--r--drivers/rtc/rtc-stm32.c6
-rw-r--r--drivers/rtc/rtc-sun6i.c1
-rw-r--r--drivers/rtc/rtc-tegra.c253
-rw-r--r--drivers/rtc/rtc-test.c1
-rw-r--r--drivers/rtc/rtc-tps65910.c2
-rw-r--r--drivers/rtc/rtc-v3020.c6
-rw-r--r--drivers/rtc/rtc-wm831x.c3
-rw-r--r--drivers/rtc/rtc-x1205.c5
-rw-r--r--drivers/s390/block/Kconfig2
-rw-r--r--drivers/s390/block/dasd.c233
-rw-r--r--drivers/s390/block/dasd_devmap.c72
-rw-r--r--drivers/s390/block/dasd_diag.c22
-rw-r--r--drivers/s390/block/dasd_eckd.c966
-rw-r--r--drivers/s390/block/dasd_eckd.h175
-rw-r--r--drivers/s390/block/dasd_eer.c1
-rw-r--r--drivers/s390/block/dasd_fba.c45
-rw-r--r--drivers/s390/block/dasd_fba.h5
-rw-r--r--drivers/s390/block/dasd_int.h33
-rw-r--r--drivers/s390/block/dasd_ioctl.c56
-rw-r--r--drivers/s390/block/dcssblk.c2
-rw-r--r--drivers/s390/char/Kconfig22
-rw-r--r--drivers/s390/char/Makefile1
-rw-r--r--drivers/s390/char/sclp_async.c189
-rw-r--r--drivers/s390/char/sclp_early.c1
-rw-r--r--drivers/s390/char/zcore.c2
-rw-r--r--drivers/s390/cio/airq.c37
-rw-r--r--drivers/s390/cio/ccwgroup.c6
-rw-r--r--drivers/s390/cio/ccwreq.c9
-rw-r--r--drivers/s390/cio/chsc.c30
-rw-r--r--drivers/s390/cio/chsc_sch.c2
-rw-r--r--drivers/s390/cio/cio.h3
-rw-r--r--drivers/s390/cio/css.c191
-rw-r--r--drivers/s390/cio/device.c78
-rw-r--r--drivers/s390/cio/device_fsm.c49
-rw-r--r--drivers/s390/cio/device_id.c20
-rw-r--r--drivers/s390/cio/device_ops.c21
-rw-r--r--drivers/s390/cio/device_pgid.c22
-rw-r--r--drivers/s390/cio/device_status.c24
-rw-r--r--drivers/s390/cio/io_sch.h20
-rw-r--r--drivers/s390/cio/qdio_main.c1
-rw-r--r--drivers/s390/cio/qdio_setup.c2
-rw-r--r--drivers/s390/cio/qdio_thinint.c6
-rw-r--r--drivers/s390/cio/scm.c4
-rw-r--r--drivers/s390/cio/vfio_ccw_cp.c524
-rw-r--r--drivers/s390/cio/vfio_ccw_cp.h7
-rw-r--r--drivers/s390/cio/vfio_ccw_drv.c14
-rw-r--r--drivers/s390/crypto/ap_bus.c9
-rw-r--r--drivers/s390/crypto/pkey_api.c8
-rw-r--r--drivers/s390/crypto/vfio_ap_drv.c34
-rw-r--r--drivers/s390/crypto/vfio_ap_ops.c379
-rw-r--r--drivers/s390/crypto/vfio_ap_private.h15
-rw-r--r--drivers/s390/crypto/zcrypt_msgtype6.c4
-rw-r--r--drivers/s390/net/Kconfig8
-rw-r--r--drivers/s390/net/qeth_core.h109
-rw-r--r--drivers/s390/net/qeth_core_main.c1013
-rw-r--r--drivers/s390/net/qeth_core_mpc.h51
-rw-r--r--drivers/s390/net/qeth_l2_main.c276
-rw-r--r--drivers/s390/net/qeth_l3_main.c249
-rw-r--r--drivers/s390/scsi/zfcp_fc.c4
-rw-r--r--drivers/s390/virtio/virtio_ccw.c246
-rw-r--r--drivers/scsi/Kconfig61
-rw-r--r--drivers/scsi/Makefile4
-rw-r--r--drivers/scsi/NCR5380.c59
-rw-r--r--drivers/scsi/NCR5380.h2
-rw-r--r--drivers/scsi/advansys.c2
-rw-r--r--drivers/scsi/aha152x.c46
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx.reg2
-rw-r--r--drivers/scsi/aic94xx/Kconfig20
-rw-r--r--drivers/scsi/aic94xx/aic94xx_dev.c4
-rw-r--r--drivers/scsi/arm/acornscsi-io.S5
-rw-r--r--drivers/scsi/arm/acornscsi.c5
-rw-r--r--drivers/scsi/arm/acornscsi.h5
-rw-r--r--drivers/scsi/arm/cumana_2.c5
-rw-r--r--drivers/scsi/arm/eesox.c5
-rw-r--r--drivers/scsi/arm/fas216.c5
-rw-r--r--drivers/scsi/arm/fas216.h5
-rw-r--r--drivers/scsi/arm/msgqueue.c5
-rw-r--r--drivers/scsi/arm/msgqueue.h5
-rw-r--r--drivers/scsi/arm/powertec.c5
-rw-r--r--drivers/scsi/arm/queue.c5
-rw-r--r--drivers/scsi/arm/queue.h5
-rw-r--r--drivers/scsi/arm/scsi.h5
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc.h14
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_els.c60
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_fcoe.c3
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_io.c116
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_tgt.c10
-rw-r--r--drivers/scsi/cxgbi/cxgb3i/cxgb3i.c10
-rw-r--r--drivers/scsi/cxgbi/cxgb4i/cxgb4i.c26
-rw-r--r--drivers/scsi/cxgbi/libcxgbi.c15
-rw-r--r--drivers/scsi/cxgbi/libcxgbi.h9
-rw-r--r--drivers/scsi/cxlflash/ocxl_hw.c23
-rw-r--r--drivers/scsi/esp_scsi.c20
-rw-r--r--drivers/scsi/esp_scsi.h2
-rw-r--r--drivers/scsi/fdomain.c597
-rw-r--r--drivers/scsi/fdomain.h114
-rw-r--r--drivers/scsi/fdomain_isa.c222
-rw-r--r--drivers/scsi/fdomain_pci.c68
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas.h8
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_main.c16
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_v2_hw.c50
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_v3_hw.c50
-rw-r--r--drivers/scsi/hpsa.c284
-rw-r--r--drivers/scsi/hpsa.h6
-rw-r--r--drivers/scsi/hpsa_cmd.h2
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c77
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.h10
-rw-r--r--drivers/scsi/imm.c2
-rw-r--r--drivers/scsi/ipr.c29
-rw-r--r--drivers/scsi/isci/remote_device.c4
-rw-r--r--drivers/scsi/isci/remote_device.h5
-rw-r--r--drivers/scsi/isci/request.c8
-rw-r--r--drivers/scsi/isci/task.c2
-rw-r--r--drivers/scsi/libiscsi_tcp.c2
-rw-r--r--drivers/scsi/libsas/sas_discover.c23
-rw-r--r--drivers/scsi/libsas/sas_event.c18
-rw-r--r--drivers/scsi/libsas/sas_expander.c71
-rw-r--r--drivers/scsi/libsas/sas_init.c2
-rw-r--r--drivers/scsi/libsas/sas_internal.h2
-rw-r--r--drivers/scsi/libsas/sas_phy.c18
-rw-r--r--drivers/scsi/libsas/sas_port.c24
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c2
-rw-r--r--drivers/scsi/lpfc/lpfc.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c94
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.c2
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h7
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c14
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c128
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c35
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c514
-rw-r--r--drivers/scsi/lpfc/lpfc_nvme.c60
-rw-r--r--drivers/scsi/lpfc/lpfc_nvmet.c352
-rw-r--r--drivers/scsi/lpfc/lpfc_nvmet.h1
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c16
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c77
-rw-r--r--drivers/scsi/lpfc/lpfc_sli4.h11
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
-rw-r--r--drivers/scsi/mac_scsi.c421
-rw-r--r--drivers/scsi/megaraid/Kconfig.megaraid1
-rw-r--r--drivers/scsi/megaraid/Makefile2
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h101
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_base.c712
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_debugfs.c179
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fp.c82
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.c551
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.h33
-rw-r--r--drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h2
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_base.c497
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_base.h35
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_config.c73
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_ctl.c234
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_scsih.c52
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_transport.c8
-rw-r--r--drivers/scsi/mvsas/Kconfig20
-rw-r--r--drivers/scsi/mvsas/mv_sas.c2
-rw-r--r--drivers/scsi/mvsas/mv_sas.h3
-rw-r--r--drivers/scsi/mvumi.c11
-rw-r--r--drivers/scsi/osst.c6108
-rw-r--r--drivers/scsi/osst.h651
-rw-r--r--drivers/scsi/osst_detect.h7
-rw-r--r--drivers/scsi/osst_options.h107
-rw-r--r--drivers/scsi/pcmcia/Kconfig10
-rw-r--r--drivers/scsi/pcmcia/Makefile1
-rw-r--r--drivers/scsi/pcmcia/fdomain_cs.c95
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.c4
-rw-r--r--drivers/scsi/pm8001/pm8001_ctl.c52
-rw-r--r--drivers/scsi/pm8001/pm8001_hwi.c4
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.c4
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.h1
-rw-r--r--drivers/scsi/pm8001/pm80xx_hwi.c4
-rw-r--r--drivers/scsi/pmcraid.c14
-rw-r--r--drivers/scsi/ppa.c2
-rw-r--r--drivers/scsi/qedf/qedf_main.c39
-rw-r--r--drivers/scsi/qedi/qedi_main.c37
-rw-r--r--drivers/scsi/qedi/qedi_version.h6
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h5
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c1
-rw-r--r--drivers/scsi/qla2xxx/qla_nvme.c236
-rw-r--r--drivers/scsi/qla2xxx/qla_nvme.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c3
-rw-r--r--drivers/scsi/qla2xxx/qla_target.c16
-rw-r--r--drivers/scsi/scsi.c12
-rw-r--r--drivers/scsi/scsi_debugfs.h1
-rw-r--r--drivers/scsi/scsi_error.c26
-rw-r--r--drivers/scsi/scsi_lib.c39
-rw-r--r--drivers/scsi/scsi_pm.c6
-rw-r--r--drivers/scsi/scsi_priv.h1
-rw-r--r--drivers/scsi/scsi_proc.c2
-rw-r--r--drivers/scsi/scsi_sysfs.c7
-rw-r--r--drivers/scsi/scsi_transport_fc.c3
-rw-r--r--drivers/scsi/scsi_transport_srp.c16
-rw-r--r--drivers/scsi/sd.c111
-rw-r--r--drivers/scsi/sd.h3
-rw-r--r--drivers/scsi/sd_zbc.c108
-rw-r--r--drivers/scsi/ses.c7
-rw-r--r--drivers/scsi/st.c6
-rw-r--r--drivers/scsi/storvsc_drv.c11
-rw-r--r--drivers/scsi/ufs/tc-dwc-g210-pci.c5
-rw-r--r--drivers/scsi/ufs/tc-dwc-g210-pltfrm.c5
-rw-r--r--drivers/scsi/ufs/tc-dwc-g210.c5
-rw-r--r--drivers/scsi/ufs/tc-dwc-g210.h5
-rw-r--r--drivers/scsi/ufs/ufs-hisi.c4
-rw-r--r--drivers/scsi/ufs/ufs-hisi.h4
-rw-r--r--drivers/scsi/ufs/ufs-qcom.c23
-rw-r--r--drivers/scsi/ufs/ufs-sysfs.c6
-rw-r--r--drivers/scsi/ufs/ufs_bsg.c6
-rw-r--r--drivers/scsi/ufs/ufshcd-dwc.c5
-rw-r--r--drivers/scsi/ufs/ufshcd-dwc.h5
-rw-r--r--drivers/scsi/ufs/ufshcd-pci.c2
-rw-r--r--drivers/scsi/ufs/ufshcd-pltfrm.c11
-rw-r--r--drivers/scsi/ufs/ufshcd.c35
-rw-r--r--drivers/scsi/ufs/ufshcd.h5
-rw-r--r--drivers/scsi/ufs/ufshci-dwc.h5
-rw-r--r--drivers/scsi/ufs/ufshci.h6
-rw-r--r--drivers/scsi/virtio_scsi.c5
-rw-r--r--drivers/scsi/vmw_pvscsi.c8
-rw-r--r--drivers/scsi/wd33c93.c2
-rw-r--r--drivers/scsi/wd719x.c42
-rw-r--r--drivers/slimbus/core.c5
-rw-r--r--drivers/slimbus/qcom-ctrl.c4
-rw-r--r--drivers/slimbus/stream.c12
-rw-r--r--drivers/soc/Makefile2
-rw-r--r--drivers/soc/bcm/brcmstb/biuctrl.c6
-rw-r--r--drivers/soc/imx/soc-imx8.c3
-rw-r--r--drivers/soc/ixp4xx/ixp4xx-npe.c4
-rw-r--r--drivers/soc/lantiq/fpi-bus.c4
-rw-r--r--drivers/soc/qcom/mdt_loader.c88
-rw-r--r--drivers/soc/qcom/qcom-geni-se.c21
-rw-r--r--drivers/soc/rockchip/grf.c5
-rw-r--r--drivers/soc/rockchip/pm_domains.c5
-rw-r--r--drivers/soc/tegra/common.c5
-rw-r--r--drivers/soc/tegra/fuse/fuse-tegra20.c2
-rw-r--r--drivers/soc/tegra/pmc.c1
-rw-r--r--drivers/soc/ti/Kconfig4
-rw-r--r--drivers/soc/versatile/soc-integrator.c6
-rw-r--r--drivers/soc/versatile/soc-realview.c6
-rw-r--r--drivers/soundwire/bus.c6
-rw-r--r--drivers/soundwire/cadence_master.c30
-rw-r--r--drivers/soundwire/intel.c21
-rw-r--r--drivers/soundwire/intel.h2
-rw-r--r--drivers/soundwire/intel_init.c25
-rw-r--r--drivers/soundwire/mipi_disco.c35
-rw-r--r--drivers/soundwire/stream.c15
-rw-r--r--drivers/spi/Kconfig14
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/atmel-quadspi.c21
-rw-r--r--drivers/spi/spi-altera.c5
-rw-r--r--drivers/spi/spi-armada-3700.c5
-rw-r--r--drivers/spi/spi-at91-usart.c221
-rw-r--r--drivers/spi/spi-ath79.c6
-rw-r--r--drivers/spi/spi-atmel.c5
-rw-r--r--drivers/spi/spi-bcm-qspi.c13
-rw-r--r--drivers/spi/spi-bcm-qspi.h13
-rw-r--r--drivers/spi/spi-bcm2835.c328
-rw-r--r--drivers/spi/spi-bcm2835aux.c4
-rw-r--r--drivers/spi/spi-brcmstb-qspi.c13
-rw-r--r--drivers/spi/spi-efm32.c5
-rw-r--r--drivers/spi/spi-ep93xx.c5
-rw-r--r--drivers/spi/spi-falcon.c4
-rw-r--r--drivers/spi/spi-meson-spifc.c12
-rw-r--r--drivers/spi/spi-mt65xx.c15
-rw-r--r--drivers/spi/spi-nuc900.c6
-rw-r--r--drivers/spi/spi-oc-tiny.c5
-rw-r--r--drivers/spi/spi-orion.c5
-rw-r--r--drivers/spi/spi-ppc4xx.c5
-rw-r--r--drivers/spi/spi-pxa2xx-dma.c5
-rw-r--r--drivers/spi/spi-pxa2xx.c14
-rw-r--r--drivers/spi/spi-pxa2xx.h5
-rw-r--r--drivers/spi/spi-qup.c55
-rw-r--r--drivers/spi/spi-rb4xx.c6
-rw-r--r--drivers/spi/spi-rockchip.c4
-rw-r--r--drivers/spi/spi-s3c24xx-fiq.S5
-rw-r--r--drivers/spi/spi-s3c24xx-fiq.h5
-rw-r--r--drivers/spi/spi-s3c24xx.c6
-rw-r--r--drivers/spi/spi-sh-msiof.c2
-rw-r--r--drivers/spi/spi-sh-sci.c6
-rw-r--r--drivers/spi/spi-stm32-qspi.c14
-rw-r--r--drivers/spi/spi-synquacer.c828
-rw-r--r--drivers/spi/spi-tegra114.c170
-rw-r--r--drivers/spi/spi-tle62x0.c5
-rw-r--r--drivers/spi/spi-uniphier.c17
-rw-r--r--drivers/spi/spi-xilinx.c4
-rw-r--r--drivers/spi/spi-xlp.c10
-rw-r--r--drivers/spi/spi-xtensa-xtfpga.c5
-rw-r--r--drivers/spi/spi.c234
-rw-r--r--drivers/spi/spidev.c2
-rw-r--r--drivers/ssb/driver_gpio.c6
-rw-r--r--drivers/staging/Kconfig2
-rw-r--r--drivers/staging/Makefile1
-rw-r--r--drivers/staging/android/ion/Kconfig18
-rw-r--r--drivers/staging/android/ion/Makefile2
-rw-r--r--drivers/staging/android/ion/ion_carveout_heap.c133
-rw-r--r--drivers/staging/android/ion/ion_chunk_heap.c146
-rw-r--r--drivers/staging/comedi/comedi_buf.c150
-rw-r--r--drivers/staging/comedi/comedi_fops.c39
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200_common.c16
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci230.c3
-rw-r--r--drivers/staging/comedi/drivers/dt282x.c3
-rw-r--r--drivers/staging/comedi/drivers/mite.c27
-rw-r--r--drivers/staging/comedi/drivers/usbdux.c2
-rw-r--r--drivers/staging/erofs/Makefile4
-rw-r--r--drivers/staging/erofs/compress.h62
-rw-r--r--drivers/staging/erofs/data.c4
-rw-r--r--drivers/staging/erofs/decompressor.c335
-rw-r--r--drivers/staging/erofs/dir.c3
-rw-r--r--drivers/staging/erofs/erofs_fs.h79
-rw-r--r--drivers/staging/erofs/inode.c58
-rw-r--r--drivers/staging/erofs/internal.h60
-rw-r--r--drivers/staging/erofs/namei.c1
-rw-r--r--drivers/staging/erofs/super.c21
-rw-r--r--drivers/staging/erofs/unzip_pagevec.h5
-rw-r--r--drivers/staging/erofs/unzip_vle.c373
-rw-r--r--drivers/staging/erofs/unzip_vle.h44
-rw-r--r--drivers/staging/erofs/unzip_vle_lz4.c229
-rw-r--r--drivers/staging/erofs/utils.c12
-rw-r--r--drivers/staging/erofs/zmap.c463
-rw-r--r--drivers/staging/fieldbus/Documentation/fieldbus_dev.txt4
-rw-r--r--drivers/staging/fieldbus/anybuss/Kconfig1
-rw-r--r--drivers/staging/fieldbus/anybuss/arcx-anybus.c44
-rw-r--r--drivers/staging/fieldbus/dev_core.c6
-rw-r--r--drivers/staging/fsl-dpaa2/Kconfig8
-rw-r--r--drivers/staging/fsl-dpaa2/ethsw/ethsw.c1
-rw-r--r--drivers/staging/gasket/gasket_core.c6
-rw-r--r--drivers/staging/gasket/gasket_ioctl.c3
-rw-r--r--drivers/staging/gasket/gasket_page_table.c14
-rw-r--r--drivers/staging/greybus/tools/loopback_test.c6
-rw-r--r--drivers/staging/iio/accel/adis16203.c12
-rw-r--r--drivers/staging/iio/accel/adis16240.c9
-rw-r--r--drivers/staging/iio/adc/Kconfig3
-rw-r--r--drivers/staging/iio/addac/adt7316-spi.c13
-rw-r--r--drivers/staging/iio/addac/adt7316.c5
-rw-r--r--drivers/staging/iio/cdc/ad7150.c77
-rw-r--r--drivers/staging/iio/cdc/ad7746.c10
-rw-r--r--drivers/staging/iio/frequency/ad9834.c11
-rw-r--r--drivers/staging/iio/resolver/ad2s1210.c3
-rw-r--r--drivers/staging/isdn/Kconfig12
-rw-r--r--drivers/staging/isdn/Makefile8
-rw-r--r--drivers/staging/isdn/TODO22
-rw-r--r--drivers/staging/isdn/avm/Kconfig (renamed from drivers/isdn/hardware/avm/Kconfig)0
-rw-r--r--drivers/staging/isdn/avm/Makefile (renamed from drivers/isdn/hardware/avm/Makefile)0
-rw-r--r--drivers/staging/isdn/avm/avm_cs.c (renamed from drivers/isdn/hardware/avm/avm_cs.c)0
-rw-r--r--drivers/staging/isdn/avm/avmcard.h (renamed from drivers/isdn/hardware/avm/avmcard.h)0
-rw-r--r--drivers/staging/isdn/avm/b1.c (renamed from drivers/isdn/hardware/avm/b1.c)0
-rw-r--r--drivers/staging/isdn/avm/b1dma.c (renamed from drivers/isdn/hardware/avm/b1dma.c)0
-rw-r--r--drivers/staging/isdn/avm/b1isa.c (renamed from drivers/isdn/hardware/avm/b1isa.c)0
-rw-r--r--drivers/staging/isdn/avm/b1pci.c (renamed from drivers/isdn/hardware/avm/b1pci.c)0
-rw-r--r--drivers/staging/isdn/avm/b1pcmcia.c (renamed from drivers/isdn/hardware/avm/b1pcmcia.c)0
-rw-r--r--drivers/staging/isdn/avm/c4.c (renamed from drivers/isdn/hardware/avm/c4.c)0
-rw-r--r--drivers/staging/isdn/avm/t1isa.c (renamed from drivers/isdn/hardware/avm/t1isa.c)0
-rw-r--r--drivers/staging/isdn/avm/t1pci.c (renamed from drivers/isdn/hardware/avm/t1pci.c)0
-rw-r--r--drivers/staging/isdn/gigaset/Kconfig (renamed from drivers/isdn/gigaset/Kconfig)9
-rw-r--r--drivers/staging/isdn/gigaset/Makefile (renamed from drivers/isdn/gigaset/Makefile)10
-rw-r--r--drivers/staging/isdn/gigaset/asyncdata.c (renamed from drivers/isdn/gigaset/asyncdata.c)0
-rw-r--r--drivers/staging/isdn/gigaset/bas-gigaset.c (renamed from drivers/isdn/gigaset/bas-gigaset.c)0
-rw-r--r--drivers/staging/isdn/gigaset/capi.c (renamed from drivers/isdn/gigaset/capi.c)0
-rw-r--r--drivers/staging/isdn/gigaset/common.c (renamed from drivers/isdn/gigaset/common.c)0
-rw-r--r--drivers/staging/isdn/gigaset/dummyll.c (renamed from drivers/isdn/gigaset/dummyll.c)0
-rw-r--r--drivers/staging/isdn/gigaset/ev-layer.c (renamed from drivers/isdn/gigaset/ev-layer.c)0
-rw-r--r--drivers/staging/isdn/gigaset/gigaset.h (renamed from drivers/isdn/gigaset/gigaset.h)0
-rw-r--r--drivers/staging/isdn/gigaset/interface.c (renamed from drivers/isdn/gigaset/interface.c)0
-rw-r--r--drivers/staging/isdn/gigaset/isocdata.c (renamed from drivers/isdn/gigaset/isocdata.c)0
-rw-r--r--drivers/staging/isdn/gigaset/proc.c (renamed from drivers/isdn/gigaset/proc.c)0
-rw-r--r--drivers/staging/isdn/gigaset/ser-gigaset.c (renamed from drivers/isdn/gigaset/ser-gigaset.c)0
-rw-r--r--drivers/staging/isdn/gigaset/usb-gigaset.c (renamed from drivers/isdn/gigaset/usb-gigaset.c)0
-rw-r--r--drivers/staging/isdn/hysdn/Kconfig (renamed from drivers/isdn/hysdn/Kconfig)0
-rw-r--r--drivers/staging/isdn/hysdn/Makefile (renamed from drivers/isdn/hysdn/Makefile)0
-rw-r--r--drivers/staging/isdn/hysdn/boardergo.c (renamed from drivers/isdn/hysdn/boardergo.c)0
-rw-r--r--drivers/staging/isdn/hysdn/boardergo.h (renamed from drivers/isdn/hysdn/boardergo.h)0
-rw-r--r--drivers/staging/isdn/hysdn/hycapi.c (renamed from drivers/isdn/hysdn/hycapi.c)0
-rw-r--r--drivers/staging/isdn/hysdn/hysdn_boot.c (renamed from drivers/isdn/hysdn/hysdn_boot.c)0
-rw-r--r--drivers/staging/isdn/hysdn/hysdn_defs.h (renamed from drivers/isdn/hysdn/hysdn_defs.h)0
-rw-r--r--drivers/staging/isdn/hysdn/hysdn_init.c (renamed from drivers/isdn/hysdn/hysdn_init.c)0
-rw-r--r--drivers/staging/isdn/hysdn/hysdn_net.c (renamed from drivers/isdn/hysdn/hysdn_net.c)6
-rw-r--r--drivers/staging/isdn/hysdn/hysdn_pof.h (renamed from drivers/isdn/hysdn/hysdn_pof.h)0
-rw-r--r--drivers/staging/isdn/hysdn/hysdn_procconf.c (renamed from drivers/isdn/hysdn/hysdn_procconf.c)0
-rw-r--r--drivers/staging/isdn/hysdn/hysdn_proclog.c (renamed from drivers/isdn/hysdn/hysdn_proclog.c)0
-rw-r--r--drivers/staging/isdn/hysdn/hysdn_sched.c (renamed from drivers/isdn/hysdn/hysdn_sched.c)0
-rw-r--r--drivers/staging/isdn/hysdn/ince1pc.h (renamed from drivers/isdn/hysdn/ince1pc.h)0
-rw-r--r--drivers/staging/kpc2000/Kconfig4
-rw-r--r--drivers/staging/kpc2000/Makefile4
-rw-r--r--drivers/staging/kpc2000/TODO6
-rw-r--r--drivers/staging/kpc2000/kpc2000/Makefile2
-rw-r--r--drivers/staging/kpc2000/kpc2000/cell_probe.c750
-rw-r--r--drivers/staging/kpc2000/kpc2000/core.c892
-rw-r--r--drivers/staging/kpc2000/kpc2000/dma_common_defs.h19
-rw-r--r--drivers/staging/kpc2000/kpc2000/fileops.c131
-rw-r--r--drivers/staging/kpc2000/kpc2000/kp2000_module.c54
-rw-r--r--drivers/staging/kpc2000/kpc2000/pcie.h119
-rw-r--r--drivers/staging/kpc2000/kpc2000/uapi.h22
-rw-r--r--drivers/staging/kpc2000/kpc2000_i2c.c651
-rw-r--r--drivers/staging/kpc2000/kpc2000_spi.c520
-rw-r--r--drivers/staging/kpc2000/kpc_dma/dma.c142
-rw-r--r--drivers/staging/kpc2000/kpc_dma/fileops.c269
-rw-r--r--drivers/staging/kpc2000/kpc_dma/kpc_dma_driver.c122
-rw-r--r--drivers/staging/kpc2000/kpc_dma/kpc_dma_driver.h34
-rw-r--r--drivers/staging/kpc2000/kpc_i2c/Makefile4
-rw-r--r--drivers/staging/kpc2000/kpc_i2c/fileops.c181
-rw-r--r--drivers/staging/kpc2000/kpc_i2c/i2c_driver.c699
-rw-r--r--drivers/staging/kpc2000/kpc_spi/Makefile4
-rw-r--r--drivers/staging/kpc2000/kpc_spi/spi_driver.c507
-rw-r--r--drivers/staging/kpc2000/kpc_spi/spi_parts.h48
-rw-r--r--drivers/staging/ks7010/ks7010_sdio.c2
-rw-r--r--drivers/staging/ks7010/ks_hostif.c7
-rw-r--r--drivers/staging/media/Kconfig8
-rw-r--r--drivers/staging/media/Makefile4
-rw-r--r--drivers/staging/media/allegro-dvt/Kconfig16
-rw-r--r--drivers/staging/media/allegro-dvt/Makefile5
-rw-r--r--drivers/staging/media/allegro-dvt/TODO4
-rw-r--r--drivers/staging/media/allegro-dvt/allegro-core.c3014
-rw-r--r--drivers/staging/media/allegro-dvt/nal-h264.c1001
-rw-r--r--drivers/staging/media/allegro-dvt/nal-h264.h208
-rw-r--r--drivers/staging/media/bcm2048/radio-bcm2048.c7
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipe.c25
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_isif.c8
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c8
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_video.c12
-rw-r--r--drivers/staging/media/hantro/Kconfig23
-rw-r--r--drivers/staging/media/hantro/Makefile15
-rw-r--r--drivers/staging/media/hantro/TODO (renamed from drivers/staging/media/rockchip/vpu/TODO)0
-rw-r--r--drivers/staging/media/hantro/hantro.h351
-rw-r--r--drivers/staging/media/hantro/hantro_drv.c876
-rw-r--r--drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c260
-rw-r--r--drivers/staging/media/hantro/hantro_g1_regs.h301
-rw-r--r--drivers/staging/media/hantro/hantro_h1_jpeg_enc.c125
-rw-r--r--drivers/staging/media/hantro/hantro_h1_regs.h154
-rw-r--r--drivers/staging/media/hantro/hantro_hw.h102
-rw-r--r--drivers/staging/media/hantro/hantro_jpeg.c (renamed from drivers/staging/media/rockchip/vpu/rockchip_vpu_jpeg.c)41
-rw-r--r--drivers/staging/media/hantro/hantro_jpeg.h13
-rw-r--r--drivers/staging/media/hantro/hantro_mpeg2.c61
-rw-r--r--drivers/staging/media/hantro/hantro_v4l2.c686
-rw-r--r--drivers/staging/media/hantro/hantro_v4l2.h26
-rw-r--r--drivers/staging/media/hantro/rk3288_vpu_hw.c187
-rw-r--r--drivers/staging/media/hantro/rk3399_vpu_hw.c186
-rw-r--r--drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c (renamed from drivers/staging/media/rockchip/vpu/rk3399_vpu_hw_jpeg_enc.c)42
-rw-r--r--drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c266
-rw-r--r--drivers/staging/media/hantro/rk3399_vpu_regs.h (renamed from drivers/staging/media/rockchip/vpu/rk3399_vpu_regs.h)2
-rw-r--r--drivers/staging/media/imx/Makefile18
-rw-r--r--drivers/staging/media/imx/imx-ic-common.c68
-rw-r--r--drivers/staging/media/imx/imx-ic-prp.c36
-rw-r--r--drivers/staging/media/imx/imx-ic-prpencvf.c90
-rw-r--r--drivers/staging/media/imx/imx-ic.h6
-rw-r--r--drivers/staging/media/imx/imx-media-capture.c97
-rw-r--r--drivers/staging/media/imx/imx-media-csi.c51
-rw-r--r--drivers/staging/media/imx/imx-media-dev-common.c346
-rw-r--r--drivers/staging/media/imx/imx-media-dev.c449
-rw-r--r--drivers/staging/media/imx/imx-media-fim.c9
-rw-r--r--drivers/staging/media/imx/imx-media-internal-sd.c357
-rw-r--r--drivers/staging/media/imx/imx-media-of.c41
-rw-r--r--drivers/staging/media/imx/imx-media-utils.c170
-rw-r--r--drivers/staging/media/imx/imx-media-vdic.c84
-rw-r--r--drivers/staging/media/imx/imx-media.h116
-rw-r--r--drivers/staging/media/imx/imx7-media-csi.c169
-rw-r--r--drivers/staging/media/imx/imx7-mipi-csis.c41
-rw-r--r--drivers/staging/media/ipu3/include/intel-ipu3.h2
-rw-r--r--drivers/staging/media/ipu3/ipu3-css-fw.c6
-rw-r--r--drivers/staging/media/ipu3/ipu3-css.c14
-rw-r--r--drivers/staging/media/ipu3/ipu3-dmamap.c15
-rw-r--r--drivers/staging/media/ipu3/ipu3-mmu.c125
-rw-r--r--drivers/staging/media/ipu3/ipu3-mmu.h5
-rw-r--r--drivers/staging/media/ipu3/ipu3-v4l2.c4
-rw-r--r--drivers/staging/media/meson/vdec/Kconfig11
-rw-r--r--drivers/staging/media/meson/vdec/Makefile8
-rw-r--r--drivers/staging/media/meson/vdec/TODO8
-rw-r--r--drivers/staging/media/meson/vdec/codec_mpeg12.c210
-rw-r--r--drivers/staging/media/meson/vdec/codec_mpeg12.h14
-rw-r--r--drivers/staging/media/meson/vdec/dos_regs.h98
-rw-r--r--drivers/staging/media/meson/vdec/esparser.c324
-rw-r--r--drivers/staging/media/meson/vdec/esparser.h32
-rw-r--r--drivers/staging/media/meson/vdec/vdec.c1099
-rw-r--r--drivers/staging/media/meson/vdec/vdec.h267
-rw-r--r--drivers/staging/media/meson/vdec/vdec_1.c230
-rw-r--r--drivers/staging/media/meson/vdec/vdec_1.h14
-rw-r--r--drivers/staging/media/meson/vdec/vdec_helpers.c449
-rw-r--r--drivers/staging/media/meson/vdec/vdec_helpers.h83
-rw-r--r--drivers/staging/media/meson/vdec/vdec_platform.c101
-rw-r--r--drivers/staging/media/meson/vdec/vdec_platform.h30
-rw-r--r--drivers/staging/media/omap4iss/iss_video.c11
-rw-r--r--drivers/staging/media/rockchip/vpu/Kconfig13
-rw-r--r--drivers/staging/media/rockchip/vpu/Makefile11
-rw-r--r--drivers/staging/media/rockchip/vpu/rk3288_vpu_hw.c118
-rw-r--r--drivers/staging/media/rockchip/vpu/rk3288_vpu_hw_jpeg_enc.c125
-rw-r--r--drivers/staging/media/rockchip/vpu/rk3288_vpu_regs.h442
-rw-r--r--drivers/staging/media/rockchip/vpu/rk3399_vpu_hw.c118
-rw-r--r--drivers/staging/media/rockchip/vpu/rockchip_vpu.h232
-rw-r--r--drivers/staging/media/rockchip/vpu/rockchip_vpu_common.h29
-rw-r--r--drivers/staging/media/rockchip/vpu/rockchip_vpu_drv.c542
-rw-r--r--drivers/staging/media/rockchip/vpu/rockchip_vpu_enc.c671
-rw-r--r--drivers/staging/media/rockchip/vpu/rockchip_vpu_hw.h58
-rw-r--r--drivers/staging/media/rockchip/vpu/rockchip_vpu_jpeg.h14
-rw-r--r--drivers/staging/media/soc_camera/imx074.c2
-rw-r--r--drivers/staging/media/soc_camera/mt9t031.c2
-rw-r--r--drivers/staging/media/soc_camera/soc_mt9v022.c2
-rw-r--r--drivers/staging/media/soc_camera/soc_ov5642.c6
-rw-r--r--drivers/staging/media/sunxi/cedrus/Makefile3
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus.c42
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus.h39
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_dec.c13
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_h264.c576
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_hw.c6
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_hw.h2
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_regs.h91
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_video.c9
-rw-r--r--drivers/staging/media/tegra-vde/Kconfig1
-rw-r--r--drivers/staging/media/tegra-vde/Makefile1
-rw-r--r--drivers/staging/media/tegra-vde/dmabuf-cache.c226
-rw-r--r--drivers/staging/media/tegra-vde/iommu.c157
-rw-r--r--drivers/staging/media/tegra-vde/trace.h2
-rw-r--r--drivers/staging/media/tegra-vde/uapi.h48
-rw-r--r--drivers/staging/media/tegra-vde/vde.c (renamed from drivers/staging/media/tegra-vde/tegra-vde.c)212
-rw-r--r--drivers/staging/media/tegra-vde/vde.h107
-rw-r--r--drivers/staging/most/Documentation/ABI/configfs-most.txt16
-rw-r--r--drivers/staging/most/Documentation/driver_usage.txt8
-rw-r--r--drivers/staging/most/Kconfig2
-rw-r--r--drivers/staging/most/configfs.c14
-rw-r--r--drivers/staging/most/core.c9
-rw-r--r--drivers/staging/most/net/net.c13
-rw-r--r--drivers/staging/most/video/video.c19
-rw-r--r--drivers/staging/mt7621-dma/mtk-hsdma.c5
-rw-r--r--drivers/staging/mt7621-dts/Kconfig7
-rw-r--r--drivers/staging/mt7621-dts/Makefile1
-rw-r--r--drivers/staging/mt7621-dts/TODO2
-rw-r--r--drivers/staging/mt7621-dts/gbpc1.dts2
-rw-r--r--drivers/staging/mt7621-dts/gbpc2.dts21
-rw-r--r--drivers/staging/mt7621-dts/mt7621.dtsi55
-rw-r--r--drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c8
-rw-r--r--drivers/staging/mt7621-pci/mediatek,mt7621-pci.txt2
-rw-r--r--drivers/staging/mt7621-pci/pci-mt7621.c120
-rw-r--r--drivers/staging/netlogic/xlr_net.c2
-rw-r--r--drivers/staging/octeon-usb/octeon-hcd.c3
-rw-r--r--drivers/staging/pi433/pi433_if.c5
-rw-r--r--drivers/staging/pi433/rf69.c4
-rw-r--r--drivers/staging/pi433/rf69_registers.h2
-rw-r--r--drivers/staging/ralink-gdma/ralink-gdma.c3
-rw-r--r--drivers/staging/rtl8188eu/Kconfig4
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ieee80211.c4
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mlme.c35
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mlme_ext.c2
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_recv.c14
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_wlan_util.c46
-rw-r--r--drivers/staging/rtl8188eu/hal/hal_com.c6
-rw-r--r--drivers/staging/rtl8188eu/hal/odm.c10
-rw-r--r--drivers/staging/rtl8188eu/hal/odm_hwconfig.c15
-rw-r--r--drivers/staging/rtl8188eu/hal/usb_halinit.c24
-rw-r--r--drivers/staging/rtl8188eu/include/hal_com.h1
-rw-r--r--drivers/staging/rtl8188eu/include/ieee80211.h10
-rw-r--r--drivers/staging/rtl8188eu/include/odm_precomp.h2
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_eeprom.h6
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_mlme.h3
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_mlme_ext.h2
-rw-r--r--drivers/staging/rtl8188eu/os_dep/ioctl_linux.c22
-rw-r--r--drivers/staging/rtl8188eu/os_dep/mlme_linux.c8
-rw-r--r--drivers/staging/rtl8188eu/os_dep/os_intfs.c1
-rw-r--r--drivers/staging/rtl8188eu/os_dep/rtw_android.c2
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c2
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_dm.c4
-rw-r--r--drivers/staging/rtl8192e/rtllib_module.c1
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_module.c3
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c33
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c13
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c4
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c58
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c36
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c10
-rw-r--r--drivers/staging/rtl8192u/r8192U_core.c10
-rw-r--r--drivers/staging/rtl8192u/r8192U_dm.c109
-rw-r--r--drivers/staging/rtl8192u/r8192U_dm.h1
-rw-r--r--drivers/staging/rtl8712/drv_types.h13
-rw-r--r--drivers/staging/rtl8712/hal_init.c174
-rw-r--r--drivers/staging/rtl8712/ieee80211.c74
-rw-r--r--drivers/staging/rtl8712/mlme_linux.c36
-rw-r--r--drivers/staging/rtl8712/os_intfs.c13
-rw-r--r--drivers/staging/rtl8712/recv_linux.c50
-rw-r--r--drivers/staging/rtl8712/rtl8712_efuse.c152
-rw-r--r--drivers/staging/rtl8712/rtl8712_xmit.c2
-rw-r--r--drivers/staging/rtl8712/rtl871x_cmd.c306
-rw-r--r--drivers/staging/rtl8712/rtl871x_cmd.h43
-rw-r--r--drivers/staging/rtl8712/rtl871x_eeprom.c6
-rw-r--r--drivers/staging/rtl8712/rtl871x_io.c4
-rw-r--r--drivers/staging/rtl8712/rtl871x_ioctl_linux.c171
-rw-r--r--drivers/staging/rtl8712/rtl871x_ioctl_rtl.c4
-rw-r--r--drivers/staging/rtl8712/rtl871x_ioctl_set.c4
-rw-r--r--drivers/staging/rtl8712/rtl871x_mlme.c45
-rw-r--r--drivers/staging/rtl8712/rtl871x_mlme.h3
-rw-r--r--drivers/staging/rtl8712/rtl871x_mp.c14
-rw-r--r--drivers/staging/rtl8712/rtl871x_mp_ioctl.c27
-rw-r--r--drivers/staging/rtl8712/rtl871x_mp_ioctl.h2
-rw-r--r--drivers/staging/rtl8712/rtl871x_recv.c14
-rw-r--r--drivers/staging/rtl8712/rtl871x_security.c4
-rw-r--r--drivers/staging/rtl8712/rtl871x_sta_mgt.c9
-rw-r--r--drivers/staging/rtl8712/rtl871x_xmit.c17
-rw-r--r--drivers/staging/rtl8712/rtl871x_xmit.h4
-rw-r--r--drivers/staging/rtl8712/sta_info.h4
-rw-r--r--drivers/staging/rtl8712/usb_halinit.c288
-rw-r--r--drivers/staging/rtl8712/usb_intf.c4
-rw-r--r--drivers/staging/rtl8712/usb_ops.c84
-rw-r--r--drivers/staging/rtl8712/wifi.h11
-rw-r--r--drivers/staging/rtl8712/xmit_linux.c56
-rw-r--r--drivers/staging/rtl8723bs/Kconfig2
-rw-r--r--drivers/staging/rtl8723bs/TODO3
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_ap.c25
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_btcoex.c147
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_cmd.c37
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_debug.c7
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_eeprom.c139
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_ieee80211.c4
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_ioctl_set.c2
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_mlme.c24
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_mlme_ext.c83
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_pwrctrl.c52
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_recv.c56
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_wlan_util.c19
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_xmit.c70
-rw-r--r--drivers/staging/rtl8723bs/hal/HalBtc8723b1Ant.c8
-rw-r--r--drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.c742
-rw-r--r--drivers/staging/rtl8723bs/hal/HalHWImg8723B_BB.c4
-rw-r--r--drivers/staging/rtl8723bs/hal/HalHWImg8723B_MAC.c2
-rw-r--r--drivers/staging/rtl8723bs/hal/HalHWImg8723B_RF.c2
-rw-r--r--drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.c6
-rw-r--r--drivers/staging/rtl8723bs/hal/hal_btcoex.c66
-rw-r--r--drivers/staging/rtl8723bs/hal/hal_com.c8
-rw-r--r--drivers/staging/rtl8723bs/hal/hal_intf.c5
-rw-r--r--drivers/staging/rtl8723bs/hal/hal_phy.c59
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_AntDiv.c62
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_AntDiv.h30
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_DIG.c11
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_HWConfig.c36
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_HWConfig.h2
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_RegConfig8723B.h61
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_precomp.h1
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c43
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723b_dm.c4
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c76
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c4
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723b_rf6052.c10
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c10
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c39
-rw-r--r--drivers/staging/rtl8723bs/hal/sdio_halinit.c145
-rw-r--r--drivers/staging/rtl8723bs/hal/sdio_ops.c68
-rw-r--r--drivers/staging/rtl8723bs/include/drv_types.h2
-rw-r--r--drivers/staging/rtl8723bs/include/hal_btcoex.h4
-rw-r--r--drivers/staging/rtl8723bs/include/hal_com.h1
-rw-r--r--drivers/staging/rtl8723bs/include/hal_intf.h1
-rw-r--r--drivers/staging/rtl8723bs/include/ieee80211.h2
-rw-r--r--drivers/staging/rtl8723bs/include/osdep_intf.h2
-rw-r--r--drivers/staging/rtl8723bs/include/osdep_service.h2
-rw-r--r--drivers/staging/rtl8723bs/include/recv_osdep.h4
-rw-r--r--drivers/staging/rtl8723bs/include/rtw_ap.h4
-rw-r--r--drivers/staging/rtl8723bs/include/rtw_btcoex.h28
-rw-r--r--drivers/staging/rtl8723bs/include/rtw_mlme.h3
-rw-r--r--drivers/staging/rtl8723bs/include/rtw_mlme_ext.h2
-rw-r--r--drivers/staging/rtl8723bs/include/sdio_ops.h2
-rw-r--r--drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c34
-rw-r--r--drivers/staging/rtl8723bs/os_dep/ioctl_linux.c520
-rw-r--r--drivers/staging/rtl8723bs/os_dep/mlme_linux.c20
-rw-r--r--drivers/staging/rtl8723bs/os_dep/os_intfs.c30
-rw-r--r--drivers/staging/rtl8723bs/os_dep/osdep_service.c41
-rw-r--r--drivers/staging/rtl8723bs/os_dep/recv_linux.c101
-rw-r--r--drivers/staging/rtl8723bs/os_dep/rtw_proc.c30
-rw-r--r--drivers/staging/rtl8723bs/os_dep/sdio_intf.c75
-rw-r--r--drivers/staging/rtl8723bs/os_dep/sdio_ops_linux.c24
-rw-r--r--drivers/staging/rtl8723bs/os_dep/xmit_linux.c10
-rw-r--r--drivers/staging/rts5208/TODO2
-rw-r--r--drivers/staging/rts5208/rtsx_chip.c20
-rw-r--r--drivers/staging/rts5208/sd.c30
-rw-r--r--drivers/staging/rts5208/sd.h1
-rw-r--r--drivers/staging/rts5208/xd.c8
-rw-r--r--drivers/staging/sm750fb/Kconfig2
-rw-r--r--drivers/staging/speakup/serialio.h3
-rw-r--r--drivers/staging/unisys/Documentation/overview.txt4
-rw-r--r--drivers/staging/unisys/Kconfig4
-rw-r--r--drivers/staging/unisys/visorhba/visorhba_main.c9
-rw-r--r--drivers/staging/unisys/visornic/visornic_main.c4
-rw-r--r--drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c381
-rw-r--r--drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h32
-rw-r--r--drivers/staging/vc04_services/bcm2835-camera/controls.c208
-rw-r--r--drivers/staging/vc04_services/bcm2835-camera/mmal-common.h12
-rw-r--r--drivers/staging/vc04_services/bcm2835-camera/mmal-encodings.h9
-rw-r--r--drivers/staging/vc04_services/bcm2835-camera/mmal-msg-common.h9
-rw-r--r--drivers/staging/vc04_services/bcm2835-camera/mmal-msg-format.h104
-rw-r--r--drivers/staging/vc04_services/bcm2835-camera/mmal-msg-port.h133
-rw-r--r--drivers/staging/vc04_services/bcm2835-camera/mmal-msg.h154
-rw-r--r--drivers/staging/vc04_services/bcm2835-camera/mmal-parameters.h286
-rw-r--r--drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c159
-rw-r--r--drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h22
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c2
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c356
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h6
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c4
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c106
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h9
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c4
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h2
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_shim.c4
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.c11
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.h1
-rw-r--r--drivers/staging/vt6655/Kconfig5
-rw-r--r--drivers/staging/vt6655/card.c8
-rw-r--r--drivers/staging/vt6655/card.h2
-rw-r--r--drivers/staging/vt6655/test2
-rw-r--r--drivers/staging/vt6656/Kconfig5
-rw-r--r--drivers/staging/vt6656/baseband.c130
-rw-r--r--drivers/staging/vt6656/baseband.h8
-rw-r--r--drivers/staging/vt6656/card.c22
-rw-r--r--drivers/staging/vt6656/firmware.c91
-rw-r--r--drivers/staging/vt6656/int.c8
-rw-r--r--drivers/staging/vt6656/int.h2
-rw-r--r--drivers/staging/vt6656/mac.c19
-rw-r--r--drivers/staging/vt6656/mac.h6
-rw-r--r--drivers/staging/vt6656/main_usb.c230
-rw-r--r--drivers/staging/vt6656/rf.c38
-rw-r--r--drivers/staging/vt6656/rf.h2
-rw-r--r--drivers/staging/vt6656/usbpipe.c115
-rw-r--r--drivers/staging/vt6656/usbpipe.h4
-rw-r--r--drivers/staging/wilc1000/Makefile2
-rw-r--r--drivers/staging/wilc1000/wilc_hif.c (renamed from drivers/staging/wilc1000/host_interface.c)188
-rw-r--r--drivers/staging/wilc1000/wilc_hif.h (renamed from drivers/staging/wilc1000/host_interface.h)2
-rw-r--r--drivers/staging/wilc1000/wilc_mon.c9
-rw-r--r--drivers/staging/wilc1000/wilc_netdev.c294
-rw-r--r--drivers/staging/wilc1000/wilc_sdio.c7
-rw-r--r--drivers/staging/wilc1000/wilc_spi.c3
-rw-r--r--drivers/staging/wilc1000/wilc_wfi_cfgoperations.c548
-rw-r--r--drivers/staging/wilc1000/wilc_wfi_cfgoperations.h13
-rw-r--r--drivers/staging/wilc1000/wilc_wfi_netdevice.h24
-rw-r--r--drivers/staging/wilc1000/wilc_wlan.c26
-rw-r--r--drivers/staging/wilc1000/wilc_wlan.h8
-rw-r--r--drivers/staging/wilc1000/wilc_wlan_if.h2
-rw-r--r--drivers/staging/wlan-ng/cfg80211.c14
-rw-r--r--drivers/target/iscsi/cxgbit/cxgbit.h5
-rw-r--r--drivers/target/iscsi/cxgbit/cxgbit_cm.c5
-rw-r--r--drivers/target/iscsi/cxgbit/cxgbit_ddp.c11
-rw-r--r--drivers/target/iscsi/cxgbit/cxgbit_main.c5
-rw-r--r--drivers/target/iscsi/cxgbit/cxgbit_target.c5
-rw-r--r--drivers/target/iscsi/iscsi_target_auth.c16
-rw-r--r--drivers/target/iscsi/iscsi_target_nego.c15
-rw-r--r--drivers/target/target_core_iblock.c2
-rw-r--r--drivers/target/target_core_user.c16
-rw-r--r--drivers/thermal/broadcom/bcm2835_thermal.c2
-rw-r--r--drivers/thermal/broadcom/ns-thermal.c5
-rw-r--r--drivers/thermal/fair_share.c12
-rw-r--r--drivers/thermal/gov_bang_bang.c11
-rw-r--r--drivers/thermal/intel/int340x_thermal/Kconfig6
-rw-r--r--drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c6
-rw-r--r--drivers/thermal/intel/int340x_thermal/int3400_thermal.c6
-rw-r--r--drivers/thermal/intel/int340x_thermal/int3402_thermal.c6
-rw-r--r--drivers/thermal/intel/int340x_thermal/int3406_thermal.c6
-rw-r--r--drivers/thermal/intel/int340x_thermal/processor_thermal_device.c191
-rw-r--r--drivers/thermal/intel/intel_powerclamp.c12
-rw-r--r--drivers/thermal/intel/x86_pkg_temp_thermal.c167
-rw-r--r--drivers/thermal/power_allocator.c11
-rw-r--r--drivers/thermal/step_wise.c11
-rw-r--r--drivers/thermal/tegra/soctherm.c14
-rw-r--r--drivers/thermal/thermal-generic-adc.c5
-rw-r--r--drivers/thermal/thermal_core.c52
-rw-r--r--drivers/thermal/thermal_core.h55
-rw-r--r--drivers/thermal/user_space.c12
-rw-r--r--drivers/thunderbolt/icm.c188
-rw-r--r--drivers/thunderbolt/switch.c49
-rw-r--r--drivers/thunderbolt/tb.h7
-rw-r--r--drivers/tty/Kconfig8
-rw-r--r--drivers/tty/hvc/hvc_vio.c16
-rw-r--r--drivers/tty/serial/8250/8250.h90
-rw-r--r--drivers/tty/serial/8250/8250_core.c20
-rw-r--r--drivers/tty/serial/8250/8250_dma.c11
-rw-r--r--drivers/tty/serial/8250/8250_mtk.c73
-rw-r--r--drivers/tty/serial/8250/8250_of.c14
-rw-r--r--drivers/tty/serial/8250/8250_omap.c43
-rw-r--r--drivers/tty/serial/8250/8250_pci.c97
-rw-r--r--drivers/tty/serial/8250/8250_pnp.c4
-rw-r--r--drivers/tty/serial/8250/8250_port.c50
-rw-r--r--drivers/tty/serial/8250/Kconfig1
-rw-r--r--drivers/tty/serial/Kconfig16
-rw-r--r--drivers/tty/serial/Makefile1
-rw-r--r--drivers/tty/serial/amba-pl011.c2
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart_core.c19
-rw-r--r--drivers/tty/serial/digicolor-usart.c6
-rw-r--r--drivers/tty/serial/fsl_lpuart.c114
-rw-r--r--drivers/tty/serial/imx.c82
-rw-r--r--drivers/tty/serial/max310x.c157
-rw-r--r--drivers/tty/serial/mpsc.c2138
-rw-r--r--drivers/tty/serial/msm_serial.c4
-rw-r--r--drivers/tty/serial/serial_core.c7
-rw-r--r--drivers/tty/serial/serial_mctrl_gpio.c14
-rw-r--r--drivers/tty/serial/sh-sci.c33
-rw-r--r--drivers/tty/serial/stm32-usart.c348
-rw-r--r--drivers/tty/serial/stm32-usart.h33
-rw-r--r--drivers/tty/serial/sunhv.c2
-rw-r--r--drivers/tty/serial/ucc_uart.c2
-rw-r--r--drivers/tty/serial/xilinx_uartps.c37
-rw-r--r--drivers/tty/tty_io.c4
-rw-r--r--drivers/tty/tty_ldisc.c14
-rw-r--r--drivers/uio/uio_dmem_genirq.c5
-rw-r--r--drivers/uio/uio_pdrv_genirq.c5
-rw-r--r--drivers/usb/Kconfig3
-rw-r--r--drivers/usb/Makefile3
-rw-r--r--drivers/usb/atm/Kconfig1
-rw-r--r--drivers/usb/atm/ueagle-atm.c48
-rw-r--r--drivers/usb/chipidea/ci_hdrc_imx.c33
-rw-r--r--drivers/usb/chipidea/ci_hdrc_msm.c4
-rw-r--r--drivers/usb/chipidea/core.c5
-rw-r--r--drivers/usb/chipidea/udc.c20
-rw-r--r--drivers/usb/chipidea/usbmisc_imx.c8
-rw-r--r--drivers/usb/class/Kconfig2
-rw-r--r--drivers/usb/class/cdc-wdm.c2
-rw-r--r--drivers/usb/common/common.c21
-rw-r--r--drivers/usb/common/common.h14
-rw-r--r--drivers/usb/common/led.c9
-rw-r--r--drivers/usb/core/Kconfig1
-rw-r--r--drivers/usb/core/buffer.c17
-rw-r--r--drivers/usb/core/devio.c123
-rw-r--r--drivers/usb/core/hcd.c51
-rw-r--r--drivers/usb/core/hub.c45
-rw-r--r--drivers/usb/core/notify.c3
-rw-r--r--drivers/usb/core/usb.c14
-rw-r--r--drivers/usb/core/usb.h1
-rw-r--r--drivers/usb/dwc2/Kconfig1
-rw-r--r--drivers/usb/dwc2/core.c2
-rw-r--r--drivers/usb/dwc2/core.h8
-rw-r--r--drivers/usb/dwc2/hcd.c20
-rw-r--r--drivers/usb/dwc2/hcd.h1
-rw-r--r--drivers/usb/dwc2/params.c10
-rw-r--r--drivers/usb/dwc2/platform.c32
-rw-r--r--drivers/usb/dwc3/Kconfig2
-rw-r--r--drivers/usb/dwc3/core.c16
-rw-r--r--drivers/usb/dwc3/core.h6
-rw-r--r--drivers/usb/dwc3/dwc3-meson-g12a.c36
-rw-r--r--drivers/usb/dwc3/dwc3-pci.c8
-rw-r--r--drivers/usb/dwc3/dwc3-qcom.c224
-rw-r--r--drivers/usb/dwc3/ep0.c9
-rw-r--r--drivers/usb/dwc3/gadget.c22
-rw-r--r--drivers/usb/dwc3/gadget.h6
-rw-r--r--drivers/usb/gadget/Kconfig6
-rw-r--r--drivers/usb/gadget/composite.c2
-rw-r--r--drivers/usb/gadget/function/f_eem.c3
-rw-r--r--drivers/usb/gadget/function/f_fs.c9
-rw-r--r--drivers/usb/gadget/function/f_mass_storage.c2
-rw-r--r--drivers/usb/gadget/function/f_uvc.c1
-rw-r--r--drivers/usb/gadget/function/u_audio.c4
-rw-r--r--drivers/usb/gadget/function/u_ether.c10
-rw-r--r--drivers/usb/gadget/function/uvc_v4l2.c4
-rw-r--r--drivers/usb/gadget/legacy/Kconfig8
-rw-r--r--drivers/usb/gadget/legacy/inode.c21
-rw-r--r--drivers/usb/gadget/udc/at91_udc.c3
-rw-r--r--drivers/usb/gadget/udc/fotg210-udc.c3
-rw-r--r--drivers/usb/gadget/udc/net2272.c5
-rw-r--r--drivers/usb/gadget/udc/omap_udc.c3
-rw-r--r--drivers/usb/gadget/udc/renesas_usb3.c93
-rw-r--r--drivers/usb/host/Kconfig7
-rw-r--r--drivers/usb/host/ehci-exynos.c11
-rw-r--r--drivers/usb/host/ehci-fsl.c52
-rw-r--r--drivers/usb/host/ehci-fsl.h3
-rw-r--r--drivers/usb/host/ehci-hcd.c2
-rw-r--r--drivers/usb/host/ehci-st.c2
-rw-r--r--drivers/usb/host/fotg210-hcd.c12
-rw-r--r--drivers/usb/host/fsl-mph-dr-of.c10
-rw-r--r--drivers/usb/host/isp1362.h2
-rw-r--r--drivers/usb/host/ohci-exynos.c11
-rw-r--r--drivers/usb/host/ohci-hcd.c25
-rw-r--r--drivers/usb/host/ohci-mem.c37
-rw-r--r--drivers/usb/host/ohci-pci.c2
-rw-r--r--drivers/usb/host/ohci-s3c2410.c2
-rw-r--r--drivers/usb/host/ohci-sm501.c50
-rw-r--r--drivers/usb/host/ohci-spear.c3
-rw-r--r--drivers/usb/host/ohci-st.c2
-rw-r--r--drivers/usb/host/ohci-tmio.c15
-rw-r--r--drivers/usb/host/ohci.h2
-rw-r--r--drivers/usb/host/u132-hcd.c3
-rw-r--r--drivers/usb/host/uhci-hcd.c2
-rw-r--r--drivers/usb/host/xhci-ring.c42
-rw-r--r--drivers/usb/host/xhci-tegra.c23
-rw-r--r--drivers/usb/host/xhci.c48
-rw-r--r--drivers/usb/host/xhci.h14
-rw-r--r--drivers/usb/image/microtek.c20
-rw-r--r--drivers/usb/image/microtek.h2
-rw-r--r--drivers/usb/misc/Kconfig6
-rw-r--r--drivers/usb/misc/adutux.c16
-rw-r--r--drivers/usb/misc/ftdi-elan.c7
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.c10
-rw-r--r--drivers/usb/mon/Kconfig2
-rw-r--r--drivers/usb/mtu3/mtu3_debugfs.c3
-rw-r--r--drivers/usb/phy/phy-am335x-control.c4
-rw-r--r--drivers/usb/phy/phy-isp1301.c4
-rw-r--r--drivers/usb/phy/phy-mv-usb.c2
-rw-r--r--drivers/usb/phy/phy-mxs-usb.c67
-rw-r--r--drivers/usb/renesas_usbhs/Kconfig1
-rw-r--r--drivers/usb/renesas_usbhs/Makefile2
-rw-r--r--drivers/usb/renesas_usbhs/common.c214
-rw-r--r--drivers/usb/renesas_usbhs/common.h9
-rw-r--r--drivers/usb/renesas_usbhs/fifo.c52
-rw-r--r--drivers/usb/renesas_usbhs/mod.c23
-rw-r--r--drivers/usb/renesas_usbhs/mod.h26
-rw-r--r--drivers/usb/renesas_usbhs/mod_gadget.c7
-rw-r--r--drivers/usb/renesas_usbhs/rcar2.c22
-rw-r--r--drivers/usb/renesas_usbhs/rcar2.h3
-rw-r--r--drivers/usb/renesas_usbhs/rcar3.c33
-rw-r--r--drivers/usb/renesas_usbhs/rcar3.h5
-rw-r--r--drivers/usb/renesas_usbhs/rza.c18
-rw-r--r--drivers/usb/renesas_usbhs/rza.h3
-rw-r--r--drivers/usb/renesas_usbhs/rza2.c74
-rw-r--r--drivers/usb/roles/class.c2
-rw-r--r--drivers/usb/serial/Kconfig10
-rw-r--r--drivers/usb/serial/belkin_sa.c2
-rw-r--r--drivers/usb/serial/belkin_sa.h2
-rw-r--r--drivers/usb/serial/cypress_m8.c2
-rw-r--r--drivers/usb/serial/empeg.c2
-rw-r--r--drivers/usb/serial/ftdi_sio.c3
-rw-r--r--drivers/usb/serial/ftdi_sio_ids.h6
-rw-r--r--drivers/usb/serial/ir-usb.c2
-rw-r--r--drivers/usb/serial/keyspan_pda.c2
-rw-r--r--drivers/usb/serial/omninet.c2
-rw-r--r--drivers/usb/serial/option.c1
-rw-r--r--drivers/usb/serial/oti6858.c2
-rw-r--r--drivers/usb/serial/pl2303.c2
-rw-r--r--drivers/usb/serial/usb-serial.c2
-rw-r--r--drivers/usb/serial/visor.c2
-rw-r--r--drivers/usb/serial/visor.h2
-rw-r--r--drivers/usb/serial/whiteheat.c2
-rw-r--r--drivers/usb/serial/whiteheat.h2
-rw-r--r--drivers/usb/storage/scsiglue.c7
-rw-r--r--drivers/usb/typec/bus.h15
-rw-r--r--drivers/usb/typec/class.c17
-rw-r--r--drivers/usb/typec/mux.c238
-rw-r--r--drivers/usb/typec/mux/pi3usb30532.c46
-rw-r--r--drivers/usb/typec/tcpm/fusb302.c3
-rw-r--r--drivers/usb/typec/tps6598x.c6
-rw-r--r--drivers/usb/typec/ucsi/ucsi.c10
-rw-r--r--drivers/usb/typec/ucsi/ucsi.h1
-rw-r--r--drivers/usb/typec/ucsi/ucsi_ccg.c118
-rw-r--r--drivers/usb/usbip/stub_main.c8
-rw-r--r--drivers/usb/usbip/vhci_tx.c12
-rw-r--r--drivers/usb/wusbcore/Kconfig8
-rw-r--r--drivers/usb/wusbcore/crypto.c169
-rw-r--r--drivers/uwb/allocator.c13
-rw-r--r--drivers/uwb/drp-avail.c14
-rw-r--r--drivers/uwb/drp-ie.c13
-rw-r--r--drivers/uwb/drp.c13
-rw-r--r--drivers/uwb/ie-rcv.c13
-rw-r--r--drivers/uwb/pal.c13
-rw-r--r--drivers/uwb/radio.c13
-rw-r--r--drivers/uwb/rsv.c13
-rw-r--r--drivers/vfio/Kconfig2
-rw-r--r--drivers/vfio/mdev/Kconfig2
-rw-r--r--drivers/vfio/mdev/mdev_core.c14
-rw-r--r--drivers/vfio/mdev/mdev_driver.c5
-rw-r--r--drivers/vfio/mdev/mdev_private.h5
-rw-r--r--drivers/vfio/mdev/mdev_sysfs.c5
-rw-r--r--drivers/vfio/mdev/vfio_mdev.c5
-rw-r--r--drivers/vfio/pci/vfio_pci.c5
-rw-r--r--drivers/vfio/pci/vfio_pci_config.c5
-rw-r--r--drivers/vfio/pci/vfio_pci_igd.c5
-rw-r--r--drivers/vfio/pci/vfio_pci_intrs.c5
-rw-r--r--drivers/vfio/pci/vfio_pci_nvlink2.c3
-rw-r--r--drivers/vfio/pci/vfio_pci_private.h5
-rw-r--r--drivers/vfio/pci/vfio_pci_rdwr.c5
-rw-r--r--drivers/vfio/vfio.c5
-rw-r--r--drivers/vfio/vfio_iommu_spapr_tce.c59
-rw-r--r--drivers/vfio/vfio_iommu_type1.c22
-rw-r--r--drivers/vfio/vfio_spapr_eeh.c5
-rw-r--r--drivers/vfio/virqfd.c5
-rw-r--r--drivers/vhost/net.c9
-rw-r--r--drivers/vhost/test.c3
-rw-r--r--drivers/vhost/vhost.c855
-rw-r--r--drivers/vhost/vhost.h43
-rw-r--r--drivers/vhost/vsock.c3
-rw-r--r--drivers/video/backlight/88pm860x_bl.c5
-rw-r--r--drivers/video/backlight/apple_bl.c5
-rw-r--r--drivers/video/backlight/arcxcnn_bl.c13
-rw-r--r--drivers/video/backlight/bd6107.c5
-rw-r--r--drivers/video/backlight/corgi_lcd.c6
-rw-r--r--drivers/video/backlight/da903x_bl.c5
-rw-r--r--drivers/video/backlight/ep93xx_bl.c5
-rw-r--r--drivers/video/backlight/generic_bl.c6
-rw-r--r--drivers/video/backlight/gpio_backlight.c28
-rw-r--r--drivers/video/backlight/ili9320.c5
-rw-r--r--drivers/video/backlight/ili9320.h5
-rw-r--r--drivers/video/backlight/ipaq_micro_bl.c4
-rw-r--r--drivers/video/backlight/kb3886_bl.c6
-rw-r--r--drivers/video/backlight/l4f00242t03.c5
-rw-r--r--drivers/video/backlight/lm3630a_bl.c6
-rw-r--r--drivers/video/backlight/lm3639_bl.c6
-rw-r--r--drivers/video/backlight/lms283gf05.c5
-rw-r--r--drivers/video/backlight/lp855x_bl.c6
-rw-r--r--drivers/video/backlight/lp8788_bl.c6
-rw-r--r--drivers/video/backlight/ltv350qv.c5
-rw-r--r--drivers/video/backlight/ltv350qv.h5
-rw-r--r--drivers/video/backlight/lv5207lp.c5
-rw-r--r--drivers/video/backlight/max8925_bl.c5
-rw-r--r--drivers/video/backlight/ot200_bl.c5
-rw-r--r--drivers/video/backlight/pandora_bl.c5
-rw-r--r--drivers/video/backlight/platform_lcd.c6
-rw-r--r--drivers/video/backlight/pwm_bl.c35
-rw-r--r--drivers/video/backlight/sky81452-backlight.c13
-rw-r--r--drivers/video/backlight/tosa_bl.c6
-rw-r--r--drivers/video/backlight/tosa_lcd.c6
-rw-r--r--drivers/video/backlight/vgg2432a4.c5
-rw-r--r--drivers/video/backlight/wm831x_bl.c5
-rw-r--r--drivers/video/fbdev/Kconfig72
-rw-r--r--drivers/video/fbdev/Makefile1
-rw-r--r--drivers/video/fbdev/acornfb.c5
-rw-r--r--drivers/video/fbdev/acornfb.h5
-rw-r--r--drivers/video/fbdev/amifb.c4
-rw-r--r--drivers/video/fbdev/arkfb.c4
-rw-r--r--drivers/video/fbdev/atafb.c21
-rw-r--r--drivers/video/fbdev/atmel_lcdfb.c10
-rw-r--r--drivers/video/fbdev/aty/aty128fb.c5
-rw-r--r--drivers/video/fbdev/aty/atyfb_base.c10
-rw-r--r--drivers/video/fbdev/aty/radeon_backlight.c5
-rw-r--r--drivers/video/fbdev/aty/radeon_base.c2
-rw-r--r--drivers/video/fbdev/au1100fb.c24
-rw-r--r--drivers/video/fbdev/au1100fb.h1
-rw-r--r--drivers/video/fbdev/au1200fb.c19
-rw-r--r--drivers/video/fbdev/chipsfb.c1
-rw-r--r--drivers/video/fbdev/cirrusfb.c5
-rw-r--r--drivers/video/fbdev/controlfb.c8
-rw-r--r--drivers/video/fbdev/cyber2000fb.c10
-rw-r--r--drivers/video/fbdev/cyber2000fb.h5
-rw-r--r--drivers/video/fbdev/da8xx-fb.c1
-rw-r--r--drivers/video/fbdev/efifb.c6
-rw-r--r--drivers/video/fbdev/ep93xx-fb.c6
-rw-r--r--drivers/video/fbdev/fb-puv3.c5
-rw-r--r--drivers/video/fbdev/gbefb.c19
-rw-r--r--drivers/video/fbdev/grvga.c4
-rw-r--r--drivers/video/fbdev/gxt4500.c5
-rw-r--r--drivers/video/fbdev/hyperv_fb.c4
-rw-r--r--drivers/video/fbdev/i740fb.c4
-rw-r--r--drivers/video/fbdev/imsttfb.c5
-rw-r--r--drivers/video/fbdev/imxfb.c11
-rw-r--r--drivers/video/fbdev/intelfb/intelfbdrv.c7
-rw-r--r--drivers/video/fbdev/jz4740_fb.c11
-rw-r--r--drivers/video/fbdev/matrox/matroxfb_base.c2
-rw-r--r--drivers/video/fbdev/mb862xx/mb862xx-i2c.c6
-rw-r--r--drivers/video/fbdev/mb862xx/mb862xxfb_accel.c6
-rw-r--r--drivers/video/fbdev/mb862xx/mb862xxfbdrv.c11
-rw-r--r--drivers/video/fbdev/mbx/mbxfb.c4
-rw-r--r--drivers/video/fbdev/mmp/hw/mmp_ctrl.c8
-rw-r--r--drivers/video/fbdev/mx3fb.c5
-rw-r--r--drivers/video/fbdev/mxsfb.c1028
-rw-r--r--drivers/video/fbdev/nvidia/nv_backlight.c5
-rw-r--r--drivers/video/fbdev/omap/omapfb_main.c2
-rw-r--r--drivers/video/fbdev/omap2/omapfb/displays/connector-analog-tv.c5
-rw-r--r--drivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c5
-rw-r--r--drivers/video/fbdev/omap2/omapfb/displays/connector-hdmi.c5
-rw-r--r--drivers/video/fbdev/omap2/omapfb/displays/encoder-opa362.c5
-rw-r--r--drivers/video/fbdev/omap2/omapfb/displays/encoder-tfp410.c5
-rw-r--r--drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c5
-rw-r--r--drivers/video/fbdev/omap2/omapfb/displays/panel-dpi.c5
-rw-r--r--drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c5
-rw-r--r--drivers/video/fbdev/omap2/omapfb/displays/panel-lgphilips-lb035q02.c5
-rw-r--r--drivers/video/fbdev/omap2/omapfb/displays/panel-sharp-ls037v7dw01.c5
-rw-r--r--drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td028ttec1.c13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/Kconfig12
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/Makefile1
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/apply.c13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/core.c19
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/dispc-compat.c13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/dispc-compat.h13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/dispc.c13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/dispc.h14
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/dispc_coefs.c13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/display-sysfs.c13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/display.c13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/dpi.c13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/dsi.c13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/dss.c13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/dss.h17
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/dss_features.c13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/dss_features.h13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/hdmi.h13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/hdmi4.c13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/hdmi4_core.c13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/hdmi4_core.h13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/hdmi5.c13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/hdmi5_core.c13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/hdmi5_core.h13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/hdmi_phy.c5
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/hdmi_pll.c5
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/hdmi_wp.c5
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/manager-sysfs.c13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/manager.c13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/omapdss-boot-init.c13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/output.c13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/overlay-sysfs.c13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/overlay.c13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/pll.c13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/rfbi.c1078
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/sdi.c13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/venc.c13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/omapfb-main.c19
-rw-r--r--drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c13
-rw-r--r--drivers/video/fbdev/omap2/omapfb/omapfb.h13
-rw-r--r--drivers/video/fbdev/platinumfb.c5
-rw-r--r--drivers/video/fbdev/pmag-aa-fb.c4
-rw-r--r--drivers/video/fbdev/pmag-ba-fb.c4
-rw-r--r--drivers/video/fbdev/pmagb-b-fb.c4
-rw-r--r--drivers/video/fbdev/pvr2fb.c188
-rw-r--r--drivers/video/fbdev/pxafb.c2
-rw-r--r--drivers/video/fbdev/riva/fbdev.c1
-rw-r--r--drivers/video/fbdev/s3c-fb.c29
-rw-r--r--drivers/video/fbdev/s3fb.c4
-rw-r--r--drivers/video/fbdev/sh7760fb.c2
-rw-r--r--drivers/video/fbdev/sh_mobile_lcdcfb.c8
-rw-r--r--drivers/video/fbdev/sm501fb.c9
-rw-r--r--drivers/video/fbdev/sm712fb.c1
-rw-r--r--drivers/video/fbdev/smscufx.c4
-rw-r--r--drivers/video/fbdev/ssd1307fb.c4
-rw-r--r--drivers/video/fbdev/sunxvr1000.c1
-rw-r--r--drivers/video/fbdev/sunxvr2500.c1
-rw-r--r--drivers/video/fbdev/sunxvr500.c1
-rw-r--r--drivers/video/fbdev/tgafb.c4
-rw-r--r--drivers/video/fbdev/udlfb.c4
-rw-r--r--drivers/video/fbdev/via/viafbdev.c6
-rw-r--r--drivers/video/fbdev/vt8623fb.c4
-rw-r--r--drivers/video/fbdev/w100fb.c6
-rw-r--r--drivers/video/fbdev/w100fb.h6
-rw-r--r--drivers/virtio/Kconfig11
-rw-r--r--drivers/virtio/virtio_balloon.c13
-rw-r--r--drivers/virtio/virtio_mmio.c7
-rw-r--r--drivers/visorbus/visorbus_main.c4
-rw-r--r--drivers/w1/Kconfig2
-rw-r--r--drivers/w1/masters/w1-gpio.c5
-rw-r--r--drivers/w1/slaves/w1_ds2406.c4
-rw-r--r--drivers/w1/slaves/w1_ds2408.c4
-rw-r--r--drivers/w1/slaves/w1_ds2413.c69
-rw-r--r--drivers/w1/slaves/w1_ds2431.c4
-rw-r--r--drivers/w1/slaves/w1_ds2433.c4
-rw-r--r--drivers/w1/slaves/w1_ds2438.c4
-rw-r--r--drivers/w1/slaves/w1_ds2780.c6
-rw-r--r--drivers/w1/slaves/w1_ds2780.h6
-rw-r--r--drivers/w1/slaves/w1_ds2781.c6
-rw-r--r--drivers/w1/slaves/w1_ds2781.h6
-rw-r--r--drivers/w1/slaves/w1_ds2805.c10
-rw-r--r--drivers/w1/slaves/w1_ds28e04.c4
-rw-r--r--drivers/w1/slaves/w1_ds28e17.c4
-rw-r--r--drivers/watchdog/Kconfig16
-rw-r--r--drivers/watchdog/acquirewdt.c6
-rw-r--r--drivers/watchdog/advantechwdt.c6
-rw-r--r--drivers/watchdog/aspeed_wdt.c8
-rw-r--r--drivers/watchdog/ath79_wdt.c6
-rw-r--r--drivers/watchdog/bcm2835_wdt.c5
-rw-r--r--drivers/watchdog/bcm7038_wdt.c4
-rw-r--r--drivers/watchdog/bcm_kona_wdt.c18
-rw-r--r--drivers/watchdog/cadence_wdt.c4
-rw-r--r--drivers/watchdog/da9052_wdt.c9
-rw-r--r--drivers/watchdog/da9062_wdt.c5
-rw-r--r--drivers/watchdog/davinci_wdt.c14
-rw-r--r--drivers/watchdog/digicolor_wdt.c9
-rw-r--r--drivers/watchdog/ebc-c384_wdt.c9
-rw-r--r--drivers/watchdog/eurotechwdt.c6
-rw-r--r--drivers/watchdog/ftwdt010_wdt.c9
-rw-r--r--drivers/watchdog/gpio_wdt.c7
-rw-r--r--drivers/watchdog/hpwdt.c65
-rw-r--r--drivers/watchdog/i6300esb.c5
-rw-r--r--drivers/watchdog/iTCO_vendor_support.c7
-rw-r--r--drivers/watchdog/iTCO_wdt.c6
-rw-r--r--drivers/watchdog/ib700wdt.c6
-rw-r--r--drivers/watchdog/ie6xx_wdt.c8
-rw-r--r--drivers/watchdog/imgpdc_wdt.c5
-rw-r--r--drivers/watchdog/imx2_wdt.c4
-rw-r--r--drivers/watchdog/imx_sc_wdt.c123
-rw-r--r--drivers/watchdog/intel-mid_wdt.c4
-rw-r--r--drivers/watchdog/jz4740_wdt.c57
-rw-r--r--drivers/watchdog/ks8695_wdt.c5
-rw-r--r--drivers/watchdog/lantiq_wdt.c4
-rw-r--r--drivers/watchdog/loongson1_wdt.c4
-rw-r--r--drivers/watchdog/lpc18xx_wdt.c5
-rw-r--r--drivers/watchdog/max77620_wdt.c13
-rw-r--r--drivers/watchdog/mei_wdt.c34
-rw-r--r--drivers/watchdog/mena21_wdt.c4
-rw-r--r--drivers/watchdog/menf21bmc_wdt.c4
-rw-r--r--drivers/watchdog/mpc8xxx_wdt.c5
-rw-r--r--drivers/watchdog/mt7621_wdt.c5
-rw-r--r--drivers/watchdog/mv64x60_wdt.c6
-rw-r--r--drivers/watchdog/ni903x_wdt.c4
-rw-r--r--drivers/watchdog/nic7018_wdt.c1
-rw-r--r--drivers/watchdog/npcm_wdt.c4
-rw-r--r--drivers/watchdog/nv_tco.h6
-rw-r--r--drivers/watchdog/octeon-wdt-main.c11
-rw-r--r--drivers/watchdog/of_xilinx_wdt.c4
-rw-r--r--drivers/watchdog/omap_wdt.c6
-rw-r--r--drivers/watchdog/omap_wdt.h21
-rw-r--r--drivers/watchdog/pc87413_wdt.c6
-rw-r--r--drivers/watchdog/pcwd_pci.c6
-rw-r--r--drivers/watchdog/pcwd_usb.c6
-rw-r--r--drivers/watchdog/pic32-dmt.c4
-rw-r--r--drivers/watchdog/pic32-wdt.c4
-rw-r--r--drivers/watchdog/pnx4008_wdt.c9
-rw-r--r--drivers/watchdog/qcom-wdt.c4
-rw-r--r--drivers/watchdog/rave-sp-wdt.c1
-rw-r--r--drivers/watchdog/renesas_wdt.c35
-rw-r--r--drivers/watchdog/retu_wdt.c10
-rw-r--r--drivers/watchdog/rt2880_wdt.c5
-rw-r--r--drivers/watchdog/s3c2410_wdt.c4
-rw-r--r--drivers/watchdog/sa1100_wdt.c6
-rw-r--r--drivers/watchdog/sama5d4_wdt.c29
-rw-r--r--drivers/watchdog/sbc7240_wdt.c11
-rw-r--r--drivers/watchdog/sbc8360.c6
-rw-r--r--drivers/watchdog/sch311x_wdt.c6
-rw-r--r--drivers/watchdog/smsc37b787_wdt.c2
-rw-r--r--drivers/watchdog/softdog.c6
-rw-r--r--drivers/watchdog/sp5100_tco.c4
-rw-r--r--drivers/watchdog/sp805_wdt.c5
-rw-r--r--drivers/watchdog/sprd_wdt.c1
-rw-r--r--drivers/watchdog/st_lpc_wdt.c4
-rw-r--r--drivers/watchdog/stm32_iwdg.c4
-rw-r--r--drivers/watchdog/stmp3xxx_rtc_wdt.c4
-rw-r--r--drivers/watchdog/tegra_wdt.c4
-rw-r--r--drivers/watchdog/ts4800_wdt.c4
-rw-r--r--drivers/watchdog/txx9wdt.c5
-rw-r--r--drivers/watchdog/w83627hf_wdt.c6
-rw-r--r--drivers/watchdog/wafer5823wdt.c6
-rw-r--r--drivers/watchdog/watchdog_core.c22
-rw-r--r--drivers/watchdog/watchdog_core.h6
-rw-r--r--drivers/watchdog/watchdog_dev.c54
-rw-r--r--drivers/watchdog/wd501p.h6
-rw-r--r--drivers/watchdog/wdat_wdt.c5
-rw-r--r--drivers/watchdog/wdt.c6
-rw-r--r--drivers/watchdog/wdt_pci.c6
-rw-r--r--drivers/watchdog/wm831x_wdt.c9
-rw-r--r--drivers/watchdog/xen_wdt.c4
-rw-r--r--drivers/xen/Kconfig23
-rw-r--r--drivers/xen/Makefile2
-rw-r--r--drivers/xen/balloon.c23
-rw-r--r--drivers/xen/events/events_base.c12
-rw-r--r--drivers/xen/evtchn.c2
-rw-r--r--drivers/xen/gntdev.c6
-rw-r--r--drivers/xen/privcmd.c6
-rw-r--r--drivers/xen/swiotlb-xen.c2
-rw-r--r--drivers/xen/sys-hypervisor.c5
-rw-r--r--drivers/xen/tmem.c419
-rw-r--r--drivers/xen/xen-balloon.c2
-rw-r--r--drivers/xen/xen-selfballoon.c579
-rw-r--r--drivers/xen/xenfs/super.c21
-rw-r--r--drivers/xen/xlate_mmu.c3
5938 files changed, 194461 insertions, 198928 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index e8231663f201..61cf4ea2c229 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -188,8 +188,6 @@ source "drivers/ipack/Kconfig"
source "drivers/reset/Kconfig"
-source "drivers/fmc/Kconfig"
-
source "drivers/phy/Kconfig"
source "drivers/powercap/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 28b030d7988d..6d37564e783c 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -168,7 +168,6 @@ obj-$(CONFIG_IIO) += iio/
obj-$(CONFIG_VME_BUS) += vme/
obj-$(CONFIG_IPACK_BUS) += ipack/
obj-$(CONFIG_NTB) += ntb/
-obj-$(CONFIG_FMC) += fmc/
obj-$(CONFIG_POWERCAP) += powercap/
obj-$(CONFIG_MCB) += mcb/
obj-$(CONFIG_PERF_EVENTS) += perf/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 283ee94224c6..5f6158973289 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -155,7 +155,6 @@ config ACPI_EC_DEBUGFS
config ACPI_AC
tristate "AC Adapter"
- depends on X86
select POWER_SUPPLY
default y
help
@@ -168,7 +167,6 @@ config ACPI_AC
config ACPI_BATTERY
tristate "Battery"
- depends on X86
select POWER_SUPPLY
default y
help
@@ -333,7 +331,7 @@ config ACPI_CUSTOM_DSDT_FILE
depends on !STANDALONE
help
This option supports a custom DSDT by linking it into the kernel.
- See Documentation/acpi/dsdt-override.txt
+ See Documentation/admin-guide/acpi/dsdt-override.rst
Enter the full path name to the file which includes the AmlCode
or dsdt_aml_code declaration.
@@ -355,7 +353,7 @@ config ACPI_TABLE_UPGRADE
This option provides functionality to upgrade arbitrary ACPI tables
via initrd. No functional change if no ACPI tables are passed via
initrd, therefore it's safe to say Y.
- See Documentation/acpi/initrd_table_override.txt for details
+ See Documentation/admin-guide/acpi/initrd_table_override.rst for details
config ACPI_TABLE_OVERRIDE_VIA_BUILTIN_INITRD
bool "Override ACPI tables from built-in initrd"
@@ -365,7 +363,7 @@ config ACPI_TABLE_OVERRIDE_VIA_BUILTIN_INITRD
This option provides functionality to override arbitrary ACPI tables
from built-in uncompressed initrd.
- See Documentation/acpi/initrd_table_override.txt for details
+ See Documentation/admin-guide/acpi/initrd_table_override.rst for details
config ACPI_DEBUG
bool "Debug Statements"
@@ -374,7 +372,7 @@ config ACPI_DEBUG
output and increases the kernel size by around 50K.
Use the acpi.debug_layer and acpi.debug_level kernel command-line
- parameters documented in Documentation/acpi/debug.txt and
+ parameters documented in Documentation/firmware-guide/acpi/debug.rst and
Documentation/admin-guide/kernel-parameters.rst to control the type and
amount of debug output.
@@ -445,7 +443,7 @@ config ACPI_CUSTOM_METHOD
help
This debug facility allows ACPI AML methods to be inserted and/or
replaced without rebooting the system. For details refer to:
- Documentation/acpi/method-customizing.txt.
+ Documentation/firmware-guide/acpi/method-customizing.rst.
NOTE: This option is security sensitive, because it allows arbitrary
kernel memory to be written to by root (uid=0) users, allowing them
diff --git a/drivers/acpi/acpi_amba.c b/drivers/acpi/acpi_amba.c
index 7f77c071709a..49b781a9cd97 100644
--- a/drivers/acpi/acpi_amba.c
+++ b/drivers/acpi/acpi_amba.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ACPI support for platform bus type.
*
* Copyright (C) 2015, Linaro Ltd
* Author: Graeme Gregory <graeme.gregory@linaro.org>
- *
- * 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.
*/
#include <linux/acpi.h>
@@ -24,6 +21,15 @@
static const struct acpi_device_id amba_id_list[] = {
{"ARMH0061", 0}, /* PL061 GPIO Device */
+ {"ARMHC500", 0}, /* ARM CoreSight ETM4x */
+ {"ARMHC501", 0}, /* ARM CoreSight ETR */
+ {"ARMHC502", 0}, /* ARM CoreSight STM */
+ {"ARMHC503", 0}, /* ARM CoreSight Debug */
+ {"ARMHC979", 0}, /* ARM CoreSight TPIU */
+ {"ARMHC97C", 0}, /* ARM CoreSight SoC-400 TMC, SoC-600 ETF/ETB */
+ {"ARMHC98D", 0}, /* ARM CoreSight Dynamic Replicator */
+ {"ARMHC9CA", 0}, /* ARM CoreSight CATU */
+ {"ARMHC9FF", 0}, /* ARM CoreSight Dynamic Funnel */
{"", 0},
};
diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c
index c16f9460c4a2..7cd0c9ac71ea 100644
--- a/drivers/acpi/acpi_apd.c
+++ b/drivers/acpi/acpi_apd.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AMD ACPI support for ACPI2platform device.
*
* Copyright (c) 2014,2015 AMD Corporation.
* Authors: Ken Xue <Ken.Xue@amd.com>
* Wu, Jeff <Jeff.Wu@amd.com>
- *
- * 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.
*/
#include <linux/clk-provider.h>
@@ -60,7 +57,7 @@ struct apd_private_data {
static int acpi_apd_setup(struct apd_private_data *pdata)
{
const struct apd_device_desc *dev_desc = pdata->dev_desc;
- struct clk *clk = ERR_PTR(-ENODEV);
+ struct clk *clk;
if (dev_desc->fixed_clk_rate) {
clk = clk_register_fixed_rate(&pdata->adev->dev,
diff --git a/drivers/acpi/acpi_cmos_rtc.c b/drivers/acpi/acpi_cmos_rtc.c
index 0980a133916f..33ac6cb428fe 100644
--- a/drivers/acpi/acpi_cmos_rtc.c
+++ b/drivers/acpi/acpi_cmos_rtc.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ACPI support for CMOS RTC Address Space access
*
* Copyright (C) 2013, Intel Corporation
* Authors: Lan Tianyu <tianyu.lan@intel.com>
- *
- * 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.
*/
#include <linux/acpi.h>
diff --git a/drivers/acpi/acpi_configfs.c b/drivers/acpi/acpi_configfs.c
index f92033661239..57d9d574d4dd 100644
--- a/drivers/acpi/acpi_configfs.c
+++ b/drivers/acpi/acpi_configfs.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ACPI configfs support
*
* Copyright (c) 2016 Intel Corporation
- *
- * 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.
*/
#define pr_fmt(fmt) "ACPI configfs: " fmt
@@ -56,11 +53,7 @@ static ssize_t acpi_table_aml_write(struct config_item *cfg,
if (!table->header)
return -ENOMEM;
- ACPI_INFO(("Host-directed Dynamic ACPI Table Load:"));
- ret = acpi_tb_install_and_load_table(
- ACPI_PTR_TO_PHYSADDR(table->header),
- ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL, FALSE,
- &table->index);
+ ret = acpi_load_table(table->header);
if (ret) {
kfree(table->header);
table->header = NULL;
diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c
index d18246a2a65e..7a265c2171c0 100644
--- a/drivers/acpi/acpi_dbg.c
+++ b/drivers/acpi/acpi_dbg.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ACPI AML interfacing support
*
* Copyright (C) 2015, Intel Corporation
* Authors: Lv Zheng <lv.zheng@intel.com>
- *
- * 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.
*/
/* #define DEBUG */
diff --git a/drivers/acpi/acpi_lpit.c b/drivers/acpi/acpi_lpit.c
index 6116b0fb86d4..433376e819bb 100644
--- a/drivers/acpi/acpi_lpit.c
+++ b/drivers/acpi/acpi_lpit.c
@@ -129,7 +129,7 @@ static void lpit_update_residency(struct lpit_residency_info *info,
static void lpit_process(u64 begin, u64 end)
{
- while (begin + sizeof(struct acpi_lpit_native) < end) {
+ while (begin + sizeof(struct acpi_lpit_native) <= end) {
struct acpi_lpit_native *lpit_native = (struct acpi_lpit_native *)begin;
if (!lpit_native->header.type && !lpit_native->header.flags) {
@@ -148,7 +148,6 @@ static void lpit_process(u64 begin, u64 end)
void acpi_init_lpit(void)
{
acpi_status status;
- u64 lpit_begin;
struct acpi_table_lpit *lpit;
status = acpi_get_table(ACPI_SIG_LPIT, 0, (struct acpi_table_header **)&lpit);
@@ -156,6 +155,6 @@ void acpi_init_lpit(void)
if (ACPI_FAILURE(status))
return;
- lpit_begin = (u64)lpit + sizeof(*lpit);
- lpit_process(lpit_begin, lpit_begin + lpit->header.length);
+ lpit_process((u64)lpit + sizeof(*lpit),
+ (u64)lpit + lpit->header.length);
}
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index cf768608437e..d696f165a50e 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ACPI support for Intel Lynxpoint LPSS.
*
* Copyright (C) 2013, Intel Corporation
* Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
* Rafael J. Wysocki <rafael.j.wysocki@intel.com>
- *
- * 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.
*/
#include <linux/acpi.h>
@@ -511,10 +508,10 @@ struct hid_uid {
const char *uid;
};
-static int match_hid_uid(struct device *dev, void *data)
+static int match_hid_uid(struct device *dev, const void *data)
{
struct acpi_device *adev = ACPI_COMPANION(dev);
- struct hid_uid *id = data;
+ const struct hid_uid *id = data;
if (!adev)
return 0;
@@ -1064,6 +1061,13 @@ static int acpi_lpss_suspend_noirq(struct device *dev)
int ret;
if (pdata->dev_desc->resume_from_noirq) {
+ /*
+ * The driver's ->suspend_late callback will be invoked by
+ * acpi_lpss_do_suspend_late(), with the assumption that the
+ * driver really wanted to run that code in ->suspend_noirq, but
+ * it could not run after acpi_dev_suspend() and the driver
+ * expected the latter to be called in the "late" phase.
+ */
ret = acpi_lpss_do_suspend_late(dev);
if (ret)
return ret;
@@ -1094,16 +1098,99 @@ static int acpi_lpss_resume_noirq(struct device *dev)
struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
int ret;
- ret = acpi_subsys_resume_noirq(dev);
+ /* Follow acpi_subsys_resume_noirq(). */
+ if (dev_pm_may_skip_resume(dev))
+ return 0;
+
+ if (dev_pm_smart_suspend_and_suspended(dev))
+ pm_runtime_set_active(dev);
+
+ ret = pm_generic_resume_noirq(dev);
if (ret)
return ret;
- if (!dev_pm_may_skip_resume(dev) && pdata->dev_desc->resume_from_noirq)
- ret = acpi_lpss_do_resume_early(dev);
+ if (!pdata->dev_desc->resume_from_noirq)
+ return 0;
- return ret;
+ /*
+ * The driver's ->resume_early callback will be invoked by
+ * acpi_lpss_do_resume_early(), with the assumption that the driver
+ * really wanted to run that code in ->resume_noirq, but it could not
+ * run before acpi_dev_resume() and the driver expected the latter to be
+ * called in the "early" phase.
+ */
+ return acpi_lpss_do_resume_early(dev);
+}
+
+static int acpi_lpss_do_restore_early(struct device *dev)
+{
+ int ret = acpi_lpss_resume(dev);
+
+ return ret ? ret : pm_generic_restore_early(dev);
+}
+
+static int acpi_lpss_restore_early(struct device *dev)
+{
+ struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+
+ if (pdata->dev_desc->resume_from_noirq)
+ return 0;
+
+ return acpi_lpss_do_restore_early(dev);
+}
+
+static int acpi_lpss_restore_noirq(struct device *dev)
+{
+ struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+ int ret;
+
+ ret = pm_generic_restore_noirq(dev);
+ if (ret)
+ return ret;
+
+ if (!pdata->dev_desc->resume_from_noirq)
+ return 0;
+
+ /* This is analogous to what happens in acpi_lpss_resume_noirq(). */
+ return acpi_lpss_do_restore_early(dev);
+}
+
+static int acpi_lpss_do_poweroff_late(struct device *dev)
+{
+ int ret = pm_generic_poweroff_late(dev);
+
+ return ret ? ret : acpi_lpss_suspend(dev, device_may_wakeup(dev));
}
+static int acpi_lpss_poweroff_late(struct device *dev)
+{
+ struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+
+ if (dev_pm_smart_suspend_and_suspended(dev))
+ return 0;
+
+ if (pdata->dev_desc->resume_from_noirq)
+ return 0;
+
+ return acpi_lpss_do_poweroff_late(dev);
+}
+
+static int acpi_lpss_poweroff_noirq(struct device *dev)
+{
+ struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+
+ if (dev_pm_smart_suspend_and_suspended(dev))
+ return 0;
+
+ if (pdata->dev_desc->resume_from_noirq) {
+ /* This is analogous to the acpi_lpss_suspend_noirq() case. */
+ int ret = acpi_lpss_do_poweroff_late(dev);
+ if (ret)
+ return ret;
+ }
+
+ return pm_generic_poweroff_noirq(dev);
+}
#endif /* CONFIG_PM_SLEEP */
static int acpi_lpss_runtime_suspend(struct device *dev)
@@ -1137,14 +1224,11 @@ static struct dev_pm_domain acpi_lpss_pm_domain = {
.resume_noirq = acpi_lpss_resume_noirq,
.resume_early = acpi_lpss_resume_early,
.freeze = acpi_subsys_freeze,
- .freeze_late = acpi_subsys_freeze_late,
- .freeze_noirq = acpi_subsys_freeze_noirq,
- .thaw_noirq = acpi_subsys_thaw_noirq,
- .poweroff = acpi_subsys_suspend,
- .poweroff_late = acpi_lpss_suspend_late,
- .poweroff_noirq = acpi_lpss_suspend_noirq,
- .restore_noirq = acpi_lpss_resume_noirq,
- .restore_early = acpi_lpss_resume_early,
+ .poweroff = acpi_subsys_poweroff,
+ .poweroff_late = acpi_lpss_poweroff_late,
+ .poweroff_noirq = acpi_lpss_poweroff_noirq,
+ .restore_noirq = acpi_lpss_restore_noirq,
+ .restore_early = acpi_lpss_restore_early,
#endif
.runtime_suspend = acpi_lpss_runtime_suspend,
.runtime_resume = acpi_lpss_runtime_resume,
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index db013dc21c02..e294f44a7850 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -155,16 +155,6 @@ static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
return 0;
}
-static unsigned long acpi_meminfo_start_pfn(struct acpi_memory_info *info)
-{
- return PFN_DOWN(info->start_addr);
-}
-
-static unsigned long acpi_meminfo_end_pfn(struct acpi_memory_info *info)
-{
- return PFN_UP(info->start_addr + info->length-1);
-}
-
static int acpi_bind_memblk(struct memory_block *mem, void *arg)
{
return acpi_bind_one(&mem->dev, arg);
@@ -173,9 +163,8 @@ static int acpi_bind_memblk(struct memory_block *mem, void *arg)
static int acpi_bind_memory_blocks(struct acpi_memory_info *info,
struct acpi_device *adev)
{
- return walk_memory_range(acpi_meminfo_start_pfn(info),
- acpi_meminfo_end_pfn(info), adev,
- acpi_bind_memblk);
+ return walk_memory_blocks(info->start_addr, info->length, adev,
+ acpi_bind_memblk);
}
static int acpi_unbind_memblk(struct memory_block *mem, void *arg)
@@ -186,8 +175,8 @@ static int acpi_unbind_memblk(struct memory_block *mem, void *arg)
static void acpi_unbind_memory_blocks(struct acpi_memory_info *info)
{
- walk_memory_range(acpi_meminfo_start_pfn(info),
- acpi_meminfo_end_pfn(info), NULL, acpi_unbind_memblk);
+ walk_memory_blocks(info->start_addr, info->length, NULL,
+ acpi_unbind_memblk);
}
static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c
index 6b3f1217a237..e7dc0133f817 100644
--- a/drivers/acpi/acpi_pad.c
+++ b/drivers/acpi/acpi_pad.c
@@ -64,6 +64,7 @@ static void power_saving_mwait_init(void)
case X86_VENDOR_HYGON:
case X86_VENDOR_AMD:
case X86_VENDOR_INTEL:
+ case X86_VENDOR_ZHAOXIN:
/*
* AMD Fam10h TSC will tick in all
* C/P/S0/S1 states when this bit is set.
diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c
index 1f32caa87686..00ec4f2bf015 100644
--- a/drivers/acpi/acpi_platform.c
+++ b/drivers/acpi/acpi_platform.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ACPI support for platform bus type.
*
@@ -5,10 +6,6 @@
* Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
* Mathias Nyman <mathias.nyman@linux.intel.com>
* Rafael J. Wysocki <rafael.j.wysocki@intel.com>
- *
- * 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.
*/
#include <linux/acpi.h>
diff --git a/drivers/acpi/acpi_pnp.c b/drivers/acpi/acpi_pnp.c
index 67d97c0090a2..f3039b93ff61 100644
--- a/drivers/acpi/acpi_pnp.c
+++ b/drivers/acpi/acpi_pnp.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ACPI support for PNP bus type
*
* Copyright (C) 2014, Intel Corporation
* Authors: Zhang Rui <rui.zhang@intel.com>
* Rafael J. Wysocki <rafael.j.wysocki@intel.com>
- *
- * 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.
*/
#include <linux/acpi.h>
diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c
index fc447410ae4d..24f065114d42 100644
--- a/drivers/acpi/acpi_processor.c
+++ b/drivers/acpi/acpi_processor.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* acpi_processor.c - ACPI processor enumeration support
*
@@ -7,10 +8,6 @@
* Copyright (C) 2004 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
* Copyright (C) 2013, Intel Corporation
* Rafael J. Wysocki <rafael.j.wysocki@intel.com>
- *
- * 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.
*/
#include <linux/acpi.h>
diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c
index 9489ffc06411..4f325e47519f 100644
--- a/drivers/acpi/acpi_video.c
+++ b/drivers/acpi/acpi_video.c
@@ -60,6 +60,12 @@ module_param(report_key_events, int, 0644);
MODULE_PARM_DESC(report_key_events,
"0: none, 1: output changes, 2: brightness changes, 3: all");
+static int hw_changes_brightness = -1;
+module_param(hw_changes_brightness, int, 0644);
+MODULE_PARM_DESC(hw_changes_brightness,
+ "Set this to 1 on buggy hw which changes the brightness itself when "
+ "a hotkey is pressed: -1: auto, 0: normal 1: hw-changes-brightness");
+
/*
* Whether the struct acpi_video_device_attrib::device_id_scheme bit should be
* assumed even if not actually set.
@@ -405,6 +411,14 @@ static int video_set_report_key_events(const struct dmi_system_id *id)
return 0;
}
+static int video_hw_changes_brightness(
+ const struct dmi_system_id *d)
+{
+ if (hw_changes_brightness == -1)
+ hw_changes_brightness = 1;
+ return 0;
+}
+
static const struct dmi_system_id video_dmi_table[] = {
/*
* Broken _BQC workaround http://bugzilla.kernel.org/show_bug.cgi?id=13121
@@ -529,6 +543,21 @@ static const struct dmi_system_id video_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"),
},
},
+ /*
+ * Some machines change the brightness themselves when a brightness
+ * hotkey gets pressed, despite us telling them not to. In this case
+ * acpi_video_device_notify() should only call backlight_force_update(
+ * BACKLIGHT_UPDATE_HOTKEY) and not do anything else.
+ */
+ {
+ /* https://bugzilla.kernel.org/show_bug.cgi?id=204077 */
+ .callback = video_hw_changes_brightness,
+ .ident = "Packard Bell EasyNote MZ35",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Packard Bell"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "EasyNote MZ35"),
+ },
+ },
{}
};
@@ -1612,6 +1641,14 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
bus = video_device->video;
input = bus->input;
+ if (hw_changes_brightness > 0) {
+ if (video_device->backlight)
+ backlight_force_update(video_device->backlight,
+ BACKLIGHT_UPDATE_HOTKEY);
+ acpi_notifier_call_chain(device, event, 0);
+ return;
+ }
+
switch (event) {
case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: /* Cycle brightness */
brightness_switch_event(video_device, event);
diff --git a/drivers/acpi/acpi_watchdog.c b/drivers/acpi/acpi_watchdog.c
index 95600309ce42..b5516b04ffc0 100644
--- a/drivers/acpi/acpi_watchdog.c
+++ b/drivers/acpi/acpi_watchdog.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ACPI watchdog table parsing support.
*
* Copyright (C) 2016, Intel Corporation
* Author: Mika Westerberg <mika.westerberg@linux.intel.com>
- *
- * 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.
*/
#define pr_fmt(fmt) "ACPI: watchdog: " fmt
diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h
index 831660179662..c8652f91054e 100644
--- a/drivers/acpi/acpica/acevents.h
+++ b/drivers/acpi/acpica/acevents.h
@@ -69,7 +69,8 @@ acpi_status
acpi_ev_mask_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 is_masked);
acpi_status
-acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info);
+acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info,
+ u8 clear_on_enable);
acpi_status
acpi_ev_remove_gpe_reference(struct acpi_gpe_event_info *gpe_event_info);
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index d056a1845613..fd3beea93421 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -178,7 +178,6 @@ ACPI_GLOBAL(u8, acpi_gbl_verbose_leak_dump);
ACPI_GLOBAL(struct acpi_namespace_node, acpi_gbl_root_node_struct);
ACPI_GLOBAL(struct acpi_namespace_node *, acpi_gbl_root_node);
ACPI_GLOBAL(struct acpi_namespace_node *, acpi_gbl_fadt_gpe_device);
-ACPI_GLOBAL(union acpi_operand_object *, acpi_gbl_module_code_list);
extern const u8 acpi_gbl_ns_properties[ACPI_NUM_NS_TYPES];
extern const struct acpi_predefined_names
diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h
index 39812fc4386a..7da1864798a0 100644
--- a/drivers/acpi/acpica/acnamesp.h
+++ b/drivers/acpi/acpica/acnamesp.h
@@ -207,8 +207,6 @@ acpi_ns_dump_object_paths(acpi_object_type type,
*/
acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info);
-void acpi_ns_exec_module_code_list(void);
-
/*
* nsarguments - Argument count/type checking for predefined/reserved names
*/
diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c
index 4ebd23700bbc..a1ffed29903b 100644
--- a/drivers/acpi/acpica/dsinit.c
+++ b/drivers/acpi/acpica/dsinit.c
@@ -202,7 +202,7 @@ acpi_ds_initialize_objects(u32 table_index,
if (ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_DSDT)) {
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
- "\nInitializing Namespace objects:\n"));
+ "\nACPI table initialization:\n"));
}
/* Summary of objects initialized */
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
index 62d3aa74277b..344feba29063 100644
--- a/drivers/acpi/acpica/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -146,6 +146,7 @@ acpi_ev_mask_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 is_masked)
* FUNCTION: acpi_ev_add_gpe_reference
*
* PARAMETERS: gpe_event_info - Add a reference to this GPE
+ * clear_on_enable - Clear GPE status before enabling it
*
* RETURN: Status
*
@@ -155,7 +156,8 @@ acpi_ev_mask_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 is_masked)
******************************************************************************/
acpi_status
-acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info)
+acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info,
+ u8 clear_on_enable)
{
acpi_status status = AE_OK;
@@ -170,6 +172,10 @@ acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info)
/* Enable on first reference */
+ if (clear_on_enable) {
+ (void)acpi_hw_clear_gpe(gpe_event_info);
+ }
+
status = acpi_ev_update_gpe_enable_mask(gpe_event_info);
if (ACPI_SUCCESS(status)) {
status = acpi_ev_enable_gpe(gpe_event_info);
diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c
index 328d1d6123ad..fb15e9e2373b 100644
--- a/drivers/acpi/acpica/evgpeblk.c
+++ b/drivers/acpi/acpica/evgpeblk.c
@@ -453,7 +453,7 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
continue;
}
- status = acpi_ev_add_gpe_reference(gpe_event_info);
+ status = acpi_ev_add_gpe_reference(gpe_event_info, FALSE);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
"Could not enable GPE 0x%02X",
diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c
index 3df00eb6621b..279ef0557aa3 100644
--- a/drivers/acpi/acpica/evxface.c
+++ b/drivers/acpi/acpica/evxface.c
@@ -971,7 +971,7 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
ACPI_GPE_DISPATCH_METHOD) ||
(ACPI_GPE_DISPATCH_TYPE(handler->original_flags) ==
ACPI_GPE_DISPATCH_NOTIFY)) && handler->originally_enabled) {
- (void)acpi_ev_add_gpe_reference(gpe_event_info);
+ (void)acpi_ev_add_gpe_reference(gpe_event_info, FALSE);
if (ACPI_GPE_IS_POLLING_NEEDED(gpe_event_info)) {
/* Poll edge triggered GPEs to handle existing events */
diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c
index 30a083902f52..710488ec59e9 100644
--- a/drivers/acpi/acpica/evxfgpe.c
+++ b/drivers/acpi/acpica/evxfgpe.c
@@ -108,7 +108,7 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number)
if (gpe_event_info) {
if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) !=
ACPI_GPE_DISPATCH_NONE) {
- status = acpi_ev_add_gpe_reference(gpe_event_info);
+ status = acpi_ev_add_gpe_reference(gpe_event_info, TRUE);
if (ACPI_SUCCESS(status) &&
ACPI_GPE_IS_POLLING_NEEDED(gpe_event_info)) {
diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c
index 587aeeeb5070..46a8baf28bd0 100644
--- a/drivers/acpi/acpica/exconfig.c
+++ b/drivers/acpi/acpica/exconfig.c
@@ -174,12 +174,11 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
return_ACPI_STATUS(status);
}
- /* Complete the initialization/resolution of package objects */
+ /* Complete the initialization/resolution of new objects */
- status = acpi_ns_walk_namespace(ACPI_TYPE_PACKAGE, ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX, 0,
- acpi_ns_init_one_package, NULL, NULL,
- NULL);
+ acpi_ex_exit_interpreter();
+ acpi_ns_initialize_objects();
+ acpi_ex_enter_interpreter();
/* Parameter Data (optional) */
@@ -437,12 +436,11 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
return_ACPI_STATUS(status);
}
- /* Complete the initialization/resolution of package objects */
+ /* Complete the initialization/resolution of new objects */
- status = acpi_ns_walk_namespace(ACPI_TYPE_PACKAGE, ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX, 0,
- acpi_ns_init_one_package, NULL, NULL,
- NULL);
+ acpi_ex_exit_interpreter();
+ acpi_ns_initialize_objects();
+ acpi_ex_enter_interpreter();
/* Store the ddb_handle into the Target operand */
diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c
index 7b855603f81a..2566e2d4c780 100644
--- a/drivers/acpi/acpica/nsaccess.c
+++ b/drivers/acpi/acpica/nsaccess.c
@@ -36,6 +36,7 @@ acpi_status acpi_ns_root_initialize(void)
acpi_status status;
const struct acpi_predefined_names *init_val = NULL;
struct acpi_namespace_node *new_node;
+ struct acpi_namespace_node *prev_node = NULL;
union acpi_operand_object *obj_desc;
acpi_string val = NULL;
@@ -61,12 +62,28 @@ acpi_status acpi_ns_root_initialize(void)
*/
acpi_gbl_root_node = &acpi_gbl_root_node_struct;
- /* Enter the pre-defined names in the name table */
+ /* Enter the predefined names in the name table */
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Entering predefined entries into namespace\n"));
+ /*
+ * Create the initial (default) namespace.
+ * This namespace looks like something similar to this:
+ *
+ * ACPI Namespace (from Namespace Root):
+ * 0 _GPE Scope 00203160 00
+ * 0 _PR_ Scope 002031D0 00
+ * 0 _SB_ Device 00203240 00 Notify Object: 0020ADD8
+ * 0 _SI_ Scope 002032B0 00
+ * 0 _TZ_ Device 00203320 00
+ * 0 _REV Integer 00203390 00 = 0000000000000002
+ * 0 _OS_ String 00203488 00 Len 14 "Microsoft Windows NT"
+ * 0 _GL_ Mutex 00203580 00 Object 002035F0
+ * 0 _OSI Method 00203678 00 Args 1 Len 0000 Aml 00000000
+ */
for (init_val = acpi_gbl_pre_defined_names; init_val->name; init_val++) {
+ status = AE_OK;
/* _OSI is optional for now, will be permanent later */
@@ -75,17 +92,32 @@ acpi_status acpi_ns_root_initialize(void)
continue;
}
- status =
- acpi_ns_lookup(NULL, ACPI_CAST_PTR(char, init_val->name),
- init_val->type, ACPI_IMODE_LOAD_PASS2,
- ACPI_NS_NO_UPSEARCH, NULL, &new_node);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not create predefined name %s",
- init_val->name));
- continue;
+ /*
+ * Create, init, and link the new predefined name
+ * Note: No need to use acpi_ns_lookup here because all the
+ * predefined names are at the root level. It is much easier to
+ * just create and link the new node(s) here.
+ */
+ new_node =
+ ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_namespace_node));
+ if (!new_node) {
+ status = AE_NO_MEMORY;
+ goto unlock_and_exit;
}
+ ACPI_COPY_NAMESEG(new_node->name.ascii, init_val->name);
+ new_node->descriptor_type = ACPI_DESC_TYPE_NAMED;
+ new_node->type = init_val->type;
+
+ if (!prev_node) {
+ acpi_gbl_root_node_struct.child = new_node;
+ } else {
+ prev_node->peer = new_node;
+ }
+
+ new_node->parent = &acpi_gbl_root_node_struct;
+ prev_node = new_node;
+
/*
* Name entered successfully. If entry in pre_defined_names[] specifies
* an initial value, create the initial value.
@@ -131,7 +163,7 @@ acpi_status acpi_ns_root_initialize(void)
new_node->value = obj_desc->method.param_count;
#else
- /* Mark this as a very SPECIAL method */
+ /* Mark this as a very SPECIAL method (_OSI) */
obj_desc->method.info_flags =
ACPI_METHOD_INTERNAL_ONLY;
diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c
index 6390b7951ebf..63748ac699f7 100644
--- a/drivers/acpi/acpica/nseval.c
+++ b/drivers/acpi/acpica/nseval.c
@@ -14,11 +14,6 @@
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nseval")
-/* Local prototypes */
-static void
-acpi_ns_exec_module_code(union acpi_operand_object *method_obj,
- struct acpi_evaluate_info *info);
-
/*******************************************************************************
*
* FUNCTION: acpi_ns_evaluate
@@ -44,7 +39,6 @@ acpi_ns_exec_module_code(union acpi_operand_object *method_obj,
* MUTEX: Locks interpreter
*
******************************************************************************/
-
acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info)
{
acpi_status status;
@@ -310,187 +304,3 @@ cleanup:
info->full_pathname = NULL;
return_ACPI_STATUS(status);
}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ns_exec_module_code_list
- *
- * PARAMETERS: None
- *
- * RETURN: None. Exceptions during method execution are ignored, since
- * we cannot abort a table load.
- *
- * DESCRIPTION: Execute all elements of the global module-level code list.
- * Each element is executed as a single control method.
- *
- * NOTE: With this option enabled, each block of detected executable AML
- * code that is outside of any control method is wrapped with a temporary
- * control method object and placed on a global list. The methods on this
- * list are executed below.
- *
- * This function executes the module-level code for all tables only after
- * all of the tables have been loaded. It is a legacy option and is
- * not compatible with other ACPI implementations. See acpi_ns_load_table.
- *
- * This function will be removed when the legacy option is removed.
- *
- ******************************************************************************/
-
-void acpi_ns_exec_module_code_list(void)
-{
- union acpi_operand_object *prev;
- union acpi_operand_object *next;
- struct acpi_evaluate_info *info;
- u32 method_count = 0;
-
- ACPI_FUNCTION_TRACE(ns_exec_module_code_list);
-
- /* Exit now if the list is empty */
-
- next = acpi_gbl_module_code_list;
- if (!next) {
- ACPI_DEBUG_PRINT((ACPI_DB_INIT_NAMES,
- "Legacy MLC block list is empty\n"));
-
- return_VOID;
- }
-
- /* Allocate the evaluation information block */
-
- info = ACPI_ALLOCATE(sizeof(struct acpi_evaluate_info));
- if (!info) {
- return_VOID;
- }
-
- /* Walk the list, executing each "method" */
-
- while (next) {
- prev = next;
- next = next->method.mutex;
-
- /* Clear the link field and execute the method */
-
- prev->method.mutex = NULL;
- acpi_ns_exec_module_code(prev, info);
- method_count++;
-
- /* Delete the (temporary) method object */
-
- acpi_ut_remove_reference(prev);
- }
-
- ACPI_INFO(("Executed %u blocks of module-level executable AML code",
- method_count));
-
- ACPI_FREE(info);
- acpi_gbl_module_code_list = NULL;
- return_VOID;
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ns_exec_module_code
- *
- * PARAMETERS: method_obj - Object container for the module-level code
- * info - Info block for method evaluation
- *
- * RETURN: None. Exceptions during method execution are ignored, since
- * we cannot abort a table load.
- *
- * DESCRIPTION: Execute a control method containing a block of module-level
- * executable AML code. The control method is temporarily
- * installed to the root node, then evaluated.
- *
- ******************************************************************************/
-
-static void
-acpi_ns_exec_module_code(union acpi_operand_object *method_obj,
- struct acpi_evaluate_info *info)
-{
- union acpi_operand_object *parent_obj;
- struct acpi_namespace_node *parent_node;
- acpi_object_type type;
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(ns_exec_module_code);
-
- /*
- * Get the parent node. We cheat by using the next_object field
- * of the method object descriptor.
- */
- parent_node =
- ACPI_CAST_PTR(struct acpi_namespace_node,
- method_obj->method.next_object);
- type = acpi_ns_get_type(parent_node);
-
- /*
- * Get the region handler and save it in the method object. We may need
- * this if an operation region declaration causes a _REG method to be run.
- *
- * We can't do this in acpi_ps_link_module_code because
- * acpi_gbl_root_node->Object is NULL at PASS1.
- */
- if ((type == ACPI_TYPE_DEVICE) && parent_node->object) {
- method_obj->method.dispatch.handler =
- parent_node->object->device.handler;
- }
-
- /* Must clear next_object (acpi_ns_attach_object needs the field) */
-
- method_obj->method.next_object = NULL;
-
- /* Initialize the evaluation information block */
-
- memset(info, 0, sizeof(struct acpi_evaluate_info));
- info->prefix_node = parent_node;
-
- /*
- * Get the currently attached parent object. Add a reference,
- * because the ref count will be decreased when the method object
- * is installed to the parent node.
- */
- parent_obj = acpi_ns_get_attached_object(parent_node);
- if (parent_obj) {
- acpi_ut_add_reference(parent_obj);
- }
-
- /* Install the method (module-level code) in the parent node */
-
- status =
- acpi_ns_attach_object(parent_node, method_obj, ACPI_TYPE_METHOD);
- if (ACPI_FAILURE(status)) {
- goto exit;
- }
-
- /* Execute the parent node as a control method */
-
- status = acpi_ns_evaluate(info);
-
- ACPI_DEBUG_PRINT((ACPI_DB_INIT_NAMES,
- "Executed module-level code at %p\n",
- method_obj->method.aml_start));
-
- /* Delete a possible implicit return value (in slack mode) */
-
- if (info->return_object) {
- acpi_ut_remove_reference(info->return_object);
- }
-
- /* Detach the temporary method object */
-
- acpi_ns_detach_object(parent_node);
-
- /* Restore the original parent object */
-
- if (parent_obj) {
- status = acpi_ns_attach_object(parent_node, parent_obj, type);
- } else {
- parent_node->type = (u8)type;
- }
-
-exit:
- if (parent_obj) {
- acpi_ut_remove_reference(parent_obj);
- }
- return_VOID;
-}
diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c
index 53e5d00d3a5e..61e9dfc9fe8c 100644
--- a/drivers/acpi/acpica/nsinit.c
+++ b/drivers/acpi/acpica/nsinit.c
@@ -55,14 +55,19 @@ acpi_status acpi_ns_initialize_objects(void)
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
"**** Starting initialization of namespace objects ****\n"));
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
- "Completing Region/Field/Buffer/Package initialization:\n"));
+ "Final data object initialization: "));
- /* Set all init info to zero */
+ /* Clear the info block */
memset(&info, 0, sizeof(struct acpi_init_walk_info));
/* Walk entire namespace from the supplied root */
+ /*
+ * TBD: will become ACPI_TYPE_PACKAGE as this type object
+ * is now the only one that supports deferred initialization
+ * (forward references).
+ */
status = acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, acpi_ns_init_one_object,
NULL, &info, NULL);
@@ -71,13 +76,8 @@ acpi_status acpi_ns_initialize_objects(void)
}
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
- " Initialized %u/%u Regions %u/%u Fields %u/%u "
- "Buffers %u/%u Packages (%u nodes)\n",
- info.op_region_init, info.op_region_count,
- info.field_init, info.field_count,
- info.buffer_init, info.buffer_count,
- info.package_init, info.package_count,
- info.object_count));
+ "Namespace contains %u (0x%X) objects\n",
+ info.object_count, info.object_count));
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
"%u Control Methods found\n%u Op Regions found\n",
@@ -382,34 +382,18 @@ acpi_ns_init_one_object(acpi_handle obj_handle,
acpi_ex_enter_interpreter();
/*
- * Each of these types can contain executable AML code within the
- * declaration.
+ * Only initialization of Package objects can be deferred, in order
+ * to support forward references.
*/
switch (type) {
- case ACPI_TYPE_REGION:
-
- info->op_region_init++;
- status = acpi_ds_get_region_arguments(obj_desc);
- break;
-
- case ACPI_TYPE_BUFFER_FIELD:
-
- info->field_init++;
- status = acpi_ds_get_buffer_field_arguments(obj_desc);
- break;
-
case ACPI_TYPE_LOCAL_BANK_FIELD:
+ /* TBD: bank_fields do not require deferred init, remove this code */
+
info->field_init++;
status = acpi_ds_get_bank_field_arguments(obj_desc);
break;
- case ACPI_TYPE_BUFFER:
-
- info->buffer_init++;
- status = acpi_ds_get_buffer_arguments(obj_desc);
- break;
-
case ACPI_TYPE_PACKAGE:
/* Complete the initialization/resolution of the package object */
@@ -421,8 +405,13 @@ acpi_ns_init_one_object(acpi_handle obj_handle,
default:
- /* No other types can get here */
+ /* No other types should get here */
+ status = AE_TYPE;
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Opcode is not deferred [%4.4s] (%s)",
+ acpi_ut_get_node_name(node),
+ acpi_ut_get_type_name(type)));
break;
}
diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c
index 35fff5c75da1..d7c4d6e8e21e 100644
--- a/drivers/acpi/acpica/nsload.c
+++ b/drivers/acpi/acpica/nsload.c
@@ -109,18 +109,6 @@ unlock:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"**** Completed Table Object Initialization\n"));
- /*
- * This case handles the legacy option that groups all module-level
- * code blocks together and defers execution until all of the tables
- * are loaded. Execute all of these blocks at this time.
- * Execute any module-level code that was detected during the table
- * load phase.
- *
- * Note: this option is deprecated and will be eliminated in the
- * future. Use of this option can cause problems with AML code that
- * depends upon in-order immediate execution of module-level code.
- */
- acpi_ns_exec_module_code_list();
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c
index 6bc90d46db5c..b8d007c84d32 100644
--- a/drivers/acpi/acpica/nsutils.c
+++ b/drivers/acpi/acpica/nsutils.c
@@ -560,21 +560,9 @@ struct acpi_namespace_node *acpi_ns_validate_handle(acpi_handle handle)
void acpi_ns_terminate(void)
{
acpi_status status;
- union acpi_operand_object *prev;
- union acpi_operand_object *next;
ACPI_FUNCTION_TRACE(ns_terminate);
- /* Delete any module-level code blocks */
-
- next = acpi_gbl_module_code_list;
- while (next) {
- prev = next;
- next = next->method.mutex;
- prev->method.mutex = NULL; /* Clear the Mutex (cheated) field */
- acpi_ut_remove_reference(prev);
- }
-
/*
* Free the entire namespace -- all nodes and all objects
* attached to the nodes
diff --git a/drivers/acpi/acpica/tbdata.c b/drivers/acpi/acpica/tbdata.c
index 933f81316ad2..91a4b984f224 100644
--- a/drivers/acpi/acpica/tbdata.c
+++ b/drivers/acpi/acpica/tbdata.c
@@ -934,19 +934,6 @@ acpi_tb_load_table(u32 table_index, struct acpi_namespace_node *parent_node)
status = acpi_ns_load_table(table_index, parent_node);
/*
- * This case handles the legacy option that groups all module-level
- * code blocks together and defers execution until all of the tables
- * are loaded. Execute all of these blocks at this time.
- * Execute any module-level code that was detected during the table
- * load phase.
- *
- * Note: this option is deprecated and will be eliminated in the
- * future. Use of this option can cause problems with AML code that
- * depends upon in-order immediate execution of module-level code.
- */
- acpi_ns_exec_module_code_list();
-
- /*
* Update GPEs for any new _Lxx/_Exx methods. Ignore errors. The host is
* responsible for discovering any new wake GPEs by running _PRW methods
* that may have been loaded by this table.
diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c
index 4f30f06a6f78..86f1693f6d29 100644
--- a/drivers/acpi/acpica/tbxfload.c
+++ b/drivers/acpi/acpica/tbxfload.c
@@ -297,6 +297,13 @@ acpi_status acpi_load_table(struct acpi_table_header *table)
status = acpi_tb_install_and_load_table(ACPI_PTR_TO_PHYSADDR(table),
ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL,
FALSE, &table_index);
+ if (ACPI_SUCCESS(status)) {
+
+ /* Complete the initialization/resolution of new objects */
+
+ acpi_ns_initialize_objects();
+ }
+
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c
index bc124591320e..6f33e7c72327 100644
--- a/drivers/acpi/acpica/utinit.c
+++ b/drivers/acpi/acpica/utinit.c
@@ -180,7 +180,6 @@ acpi_status acpi_ut_init_globals(void)
/* Namespace */
- acpi_gbl_module_code_list = NULL;
acpi_gbl_root_node = NULL;
acpi_gbl_root_node_struct.name.integer = ACPI_ROOT_NAME;
acpi_gbl_root_node_struct.descriptor_type = ACPI_DESC_TYPE_NAMED;
diff --git a/drivers/acpi/acpica/utxfinit.c b/drivers/acpi/acpica/utxfinit.c
index 9f3b1e3a09de..cf769e94fe0f 100644
--- a/drivers/acpi/acpica/utxfinit.c
+++ b/drivers/acpi/acpica/utxfinit.c
@@ -211,24 +211,17 @@ acpi_status ACPI_INIT_FUNCTION acpi_initialize_objects(u32 flags)
ACPI_FUNCTION_TRACE(acpi_initialize_objects);
+#ifdef ACPI_OBSOLETE_BEHAVIOR
/*
- * This case handles the legacy option that groups all module-level
- * code blocks together and defers execution until all of the tables
- * are loaded. Execute all of these blocks at this time.
- * Execute any module-level code that was detected during the table
- * load phase.
- *
- * Note: this option is deprecated and will be eliminated in the
- * future. Use of this option can cause problems with AML code that
- * depends upon in-order immediate execution of module-level code.
+ * 05/2019: Removed, initialization now happens at both object
+ * creation and table load time
*/
- acpi_ns_exec_module_code_list();
/*
* Initialize the objects that remain uninitialized. This
* runs the executable AML that may be part of the
- * declaration of these objects:
- * operation_regions, buffer_fields, Buffers, and Packages.
+ * declaration of these objects: operation_regions, buffer_fields,
+ * bank_fields, Buffers, and Packages.
*/
if (!(flags & ACPI_NO_OBJECT_INIT)) {
status = acpi_ns_initialize_objects();
@@ -236,6 +229,7 @@ acpi_status ACPI_INIT_FUNCTION acpi_initialize_objects(u32 flags)
return_ACPI_STATUS(status);
}
}
+#endif
/*
* Initialize all device/region objects in the namespace. This runs
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 993940d582f5..a66e00fe31fe 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -345,7 +345,7 @@ static int __ghes_peek_estatus(struct ghes *ghes,
return -ENOENT;
}
- return __ghes_check_estatus(ghes, estatus);
+ return 0;
}
static int __ghes_read_estatus(struct acpi_hest_generic_status *estatus,
diff --git a/drivers/acpi/arm64/gtdt.c b/drivers/acpi/arm64/gtdt.c
index 92f9edf9d11e..01962c63a711 100644
--- a/drivers/acpi/arm64/gtdt.c
+++ b/drivers/acpi/arm64/gtdt.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ARM Specific GTDT table Support
*
@@ -5,10 +6,6 @@
* Author: Daniel Lezcano <daniel.lezcano@linaro.org>
* Fu Wei <fu.wei@linaro.org>
* Hanjun Guo <hanjun.guo@linaro.org>
- *
- * 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.
*/
#include <linux/acpi.h>
diff --git a/drivers/acpi/bgrt.c b/drivers/acpi/bgrt.c
index 75af78361ce5..251f961c28cc 100644
--- a/drivers/acpi/bgrt.c
+++ b/drivers/acpi/bgrt.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* BGRT boot graphic support
* Authors: Matthew Garrett, Josh Triplett <josh@joshtriplett.org>
* Copyright 2012 Red Hat, Inc <mjg@redhat.com>
* Copyright 2012 Intel Corporation
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c
index ad2c565f5cbe..a86a770c9b79 100644
--- a/drivers/acpi/blacklist.c
+++ b/drivers/acpi/blacklist.c
@@ -17,7 +17,9 @@
#include "internal.h"
+#ifdef CONFIG_DMI
static const struct dmi_system_id acpi_rev_dmi_table[] __initconst;
+#endif
/*
* POLICY: If *anything* doesn't work, put it on the blacklist.
@@ -61,7 +63,9 @@ int __init acpi_blacklisted(void)
}
(void)early_acpi_osi_init();
+#ifdef CONFIG_DMI
dmi_check_system(acpi_rev_dmi_table);
+#endif
return blacklisted;
}
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index e54956ae93d3..28cffaaf9d82 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -45,6 +45,19 @@ const char *acpi_power_state_string(int state)
}
}
+static int acpi_dev_pm_explicit_get(struct acpi_device *device, int *state)
+{
+ unsigned long long psc;
+ acpi_status status;
+
+ status = acpi_evaluate_integer(device->handle, "_PSC", NULL, &psc);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ *state = psc;
+ return 0;
+}
+
/**
* acpi_device_get_power - Get power state of an ACPI device.
* @device: Device to get the power state of.
@@ -53,10 +66,16 @@ const char *acpi_power_state_string(int state)
* This function does not update the device's power.state field, but it may
* update its parent's power.state field (when the parent's power state is
* unknown and the device's power state turns out to be D0).
+ *
+ * Also, it does not update power resource reference counters to ensure that
+ * the power state returned by it will be persistent and it may return a power
+ * state shallower than previously set by acpi_device_set_power() for @device
+ * (if that power state depends on any power resources).
*/
int acpi_device_get_power(struct acpi_device *device, int *state)
{
int result = ACPI_STATE_UNKNOWN;
+ int error;
if (!device || !state)
return -EINVAL;
@@ -73,18 +92,16 @@ int acpi_device_get_power(struct acpi_device *device, int *state)
* if available.
*/
if (device->power.flags.power_resources) {
- int error = acpi_power_get_inferred_state(device, &result);
+ error = acpi_power_get_inferred_state(device, &result);
if (error)
return error;
}
if (device->power.flags.explicit_get) {
- acpi_handle handle = device->handle;
- unsigned long long psc;
- acpi_status status;
+ int psc;
- status = acpi_evaluate_integer(handle, "_PSC", NULL, &psc);
- if (ACPI_FAILURE(status))
- return -ENODEV;
+ error = acpi_dev_pm_explicit_get(device, &psc);
+ if (error)
+ return error;
/*
* The power resources settings may indicate a power state
@@ -118,7 +135,6 @@ int acpi_device_get_power(struct acpi_device *device, int *state)
return 0;
}
-EXPORT_SYMBOL(acpi_device_get_power);
static int acpi_dev_pm_explicit_set(struct acpi_device *adev, int state)
{
@@ -152,7 +168,8 @@ int acpi_device_set_power(struct acpi_device *device, int state)
/* Make sure this is a valid target state */
- if (state == device->power.state) {
+ /* There is a special case for D0 addressed below. */
+ if (state > ACPI_STATE_D0 && state == device->power.state) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] already in %s\n",
device->pnp.bus_id,
acpi_power_state_string(state)));
@@ -202,9 +219,15 @@ int acpi_device_set_power(struct acpi_device *device, int state)
return -ENODEV;
}
- result = acpi_dev_pm_explicit_set(device, state);
- if (result)
- goto end;
+ /*
+ * If the device goes from D3hot to D3cold, _PS3 has been
+ * evaluated for it already, so skip it in that case.
+ */
+ if (device->power.state < ACPI_STATE_D3_HOT) {
+ result = acpi_dev_pm_explicit_set(device, state);
+ if (result)
+ goto end;
+ }
if (device->power.flags.power_resources)
result = acpi_power_transition(device, target_state);
@@ -214,6 +237,30 @@ int acpi_device_set_power(struct acpi_device *device, int state)
if (result)
goto end;
}
+
+ if (device->power.state == ACPI_STATE_D0) {
+ int psc;
+
+ /* Nothing to do here if _PSC is not present. */
+ if (!device->power.flags.explicit_get)
+ return 0;
+
+ /*
+ * The power state of the device was set to D0 last
+ * time, but that might have happened before a
+ * system-wide transition involving the platform
+ * firmware, so it may be necessary to evaluate _PS0
+ * for the device here. However, use extra care here
+ * and evaluate _PSC to check the device's current power
+ * state, and only invoke _PS0 if the evaluation of _PSC
+ * is successful and it returns a power state different
+ * from D0.
+ */
+ result = acpi_dev_pm_explicit_get(device, &psc);
+ if (result || psc == ACPI_STATE_D0)
+ return 0;
+ }
+
result = acpi_dev_pm_explicit_set(device, ACPI_STATE_D0);
}
@@ -1073,7 +1120,7 @@ EXPORT_SYMBOL_GPL(acpi_subsys_suspend_noirq);
* acpi_subsys_resume_noirq - Run the device driver's "noirq" resume callback.
* @dev: Device to handle.
*/
-int acpi_subsys_resume_noirq(struct device *dev)
+static int acpi_subsys_resume_noirq(struct device *dev)
{
if (dev_pm_may_skip_resume(dev))
return 0;
@@ -1088,7 +1135,6 @@ int acpi_subsys_resume_noirq(struct device *dev)
return pm_generic_resume_noirq(dev);
}
-EXPORT_SYMBOL_GPL(acpi_subsys_resume_noirq);
/**
* acpi_subsys_resume_early - Resume device using ACPI.
@@ -1098,12 +1144,11 @@ EXPORT_SYMBOL_GPL(acpi_subsys_resume_noirq);
* generic early resume procedure for it during system transition into the
* working state.
*/
-int acpi_subsys_resume_early(struct device *dev)
+static int acpi_subsys_resume_early(struct device *dev)
{
int ret = acpi_dev_resume(dev);
return ret ? ret : pm_generic_resume_early(dev);
}
-EXPORT_SYMBOL_GPL(acpi_subsys_resume_early);
/**
* acpi_subsys_freeze - Run the device driver's freeze callback.
@@ -1112,65 +1157,81 @@ EXPORT_SYMBOL_GPL(acpi_subsys_resume_early);
int acpi_subsys_freeze(struct device *dev)
{
/*
- * This used to be done in acpi_subsys_prepare() for all devices and
- * some drivers may depend on it, so do it here. Ideally, however,
- * runtime-suspended devices should not be touched during freeze/thaw
- * transitions.
+ * Resume all runtime-suspended devices before creating a snapshot
+ * image of system memory, because the restore kernel generally cannot
+ * be expected to always handle them consistently and they need to be
+ * put into the runtime-active metastate during system resume anyway,
+ * so it is better to ensure that the state saved in the image will be
+ * always consistent with that.
*/
- if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND))
- pm_runtime_resume(dev);
+ pm_runtime_resume(dev);
return pm_generic_freeze(dev);
}
EXPORT_SYMBOL_GPL(acpi_subsys_freeze);
/**
- * acpi_subsys_freeze_late - Run the device driver's "late" freeze callback.
- * @dev: Device to handle.
+ * acpi_subsys_restore_early - Restore device using ACPI.
+ * @dev: Device to restore.
*/
-int acpi_subsys_freeze_late(struct device *dev)
+int acpi_subsys_restore_early(struct device *dev)
{
+ int ret = acpi_dev_resume(dev);
+ return ret ? ret : pm_generic_restore_early(dev);
+}
+EXPORT_SYMBOL_GPL(acpi_subsys_restore_early);
- if (dev_pm_smart_suspend_and_suspended(dev))
- return 0;
+/**
+ * acpi_subsys_poweroff - Run the device driver's poweroff callback.
+ * @dev: Device to handle.
+ *
+ * Follow PCI and resume devices from runtime suspend before running their
+ * system poweroff callbacks, unless the driver can cope with runtime-suspended
+ * devices during system suspend and there are no ACPI-specific reasons for
+ * resuming them.
+ */
+int acpi_subsys_poweroff(struct device *dev)
+{
+ if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) ||
+ acpi_dev_needs_resume(dev, ACPI_COMPANION(dev)))
+ pm_runtime_resume(dev);
- return pm_generic_freeze_late(dev);
+ return pm_generic_poweroff(dev);
}
-EXPORT_SYMBOL_GPL(acpi_subsys_freeze_late);
+EXPORT_SYMBOL_GPL(acpi_subsys_poweroff);
/**
- * acpi_subsys_freeze_noirq - Run the device driver's "noirq" freeze callback.
+ * acpi_subsys_poweroff_late - Run the device driver's poweroff callback.
* @dev: Device to handle.
+ *
+ * Carry out the generic late poweroff procedure for @dev and use ACPI to put
+ * it into a low-power state during system transition into a sleep state.
*/
-int acpi_subsys_freeze_noirq(struct device *dev)
+static int acpi_subsys_poweroff_late(struct device *dev)
{
+ int ret;
if (dev_pm_smart_suspend_and_suspended(dev))
return 0;
- return pm_generic_freeze_noirq(dev);
+ ret = pm_generic_poweroff_late(dev);
+ if (ret)
+ return ret;
+
+ return acpi_dev_suspend(dev, device_may_wakeup(dev));
}
-EXPORT_SYMBOL_GPL(acpi_subsys_freeze_noirq);
/**
- * acpi_subsys_thaw_noirq - Run the device driver's "noirq" thaw callback.
- * @dev: Device to handle.
+ * acpi_subsys_poweroff_noirq - Run the driver's "noirq" poweroff callback.
+ * @dev: Device to suspend.
*/
-int acpi_subsys_thaw_noirq(struct device *dev)
+static int acpi_subsys_poweroff_noirq(struct device *dev)
{
- /*
- * If the device is in runtime suspend, the "thaw" code may not work
- * correctly with it, so skip the driver callback and make the PM core
- * skip all of the subsequent "thaw" callbacks for the device.
- */
- if (dev_pm_smart_suspend_and_suspended(dev)) {
- dev_pm_skip_next_resume_phases(dev);
+ if (dev_pm_smart_suspend_and_suspended(dev))
return 0;
- }
- return pm_generic_thaw_noirq(dev);
+ return pm_generic_poweroff_noirq(dev);
}
-EXPORT_SYMBOL_GPL(acpi_subsys_thaw_noirq);
#endif /* CONFIG_PM_SLEEP */
static struct dev_pm_domain acpi_general_pm_domain = {
@@ -1186,14 +1247,10 @@ static struct dev_pm_domain acpi_general_pm_domain = {
.resume_noirq = acpi_subsys_resume_noirq,
.resume_early = acpi_subsys_resume_early,
.freeze = acpi_subsys_freeze,
- .freeze_late = acpi_subsys_freeze_late,
- .freeze_noirq = acpi_subsys_freeze_noirq,
- .thaw_noirq = acpi_subsys_thaw_noirq,
- .poweroff = acpi_subsys_suspend,
- .poweroff_late = acpi_subsys_suspend_late,
- .poweroff_noirq = acpi_subsys_suspend_noirq,
- .restore_noirq = acpi_subsys_resume_noirq,
- .restore_early = acpi_subsys_resume_early,
+ .poweroff = acpi_subsys_poweroff,
+ .poweroff_late = acpi_subsys_poweroff_late,
+ .poweroff_noirq = acpi_subsys_poweroff_noirq,
+ .restore_early = acpi_subsys_restore_early,
#endif
},
};
diff --git a/drivers/acpi/dptf/int340x_thermal.c b/drivers/acpi/dptf/int340x_thermal.c
index 0aa7c2e62e95..5c7a90186e3c 100644
--- a/drivers/acpi/dptf/int340x_thermal.c
+++ b/drivers/acpi/dptf/int340x_thermal.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ACPI support for int340x thermal drivers
*
* Copyright (C) 2014, Intel Corporation
* Authors: Zhang Rui <rui.zhang@intel.com>
- *
- * 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.
*/
#include <linux/acpi.h>
diff --git a/drivers/acpi/ec_sys.c b/drivers/acpi/ec_sys.c
index 23faa66ea772..fd39c14493ab 100644
--- a/drivers/acpi/ec_sys.c
+++ b/drivers/acpi/ec_sys.c
@@ -1,11 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ec_sys.c
*
* Copyright (C) 2010 SUSE Products GmbH/Novell
* Author:
* Thomas Renninger <trenn@suse.de>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.
*/
#include <linux/kernel.h>
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index f6157d4d637a..f4c2fe6be4f2 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -139,8 +139,15 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state);
int acpi_power_on_resources(struct acpi_device *device, int state);
int acpi_power_transition(struct acpi_device *device, int state);
+/* --------------------------------------------------------------------------
+ Device Power Management
+ -------------------------------------------------------------------------- */
+int acpi_device_get_power(struct acpi_device *device, int *state);
int acpi_wakeup_device_init(void);
+/* --------------------------------------------------------------------------
+ Processor
+ -------------------------------------------------------------------------- */
#ifdef CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC
void acpi_early_processor_set_pdc(void);
#else
diff --git a/drivers/acpi/ioapic.c b/drivers/acpi/ioapic.c
index 3595aa9c7c18..a690c7b18623 100644
--- a/drivers/acpi/ioapic.c
+++ b/drivers/acpi/ioapic.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* IOAPIC/IOxAPIC/IOSAPIC driver
*
@@ -6,10 +7,6 @@
*
* Copyright (C) 2014 Intel Corporation
*
- * 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.
- *
* Based on original drivers/pci/ioapic.c
* Yinghai Lu <yinghai@kernel.org>
* Jiang Liu <jiang.liu@intel.com>
diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c
index c3b2222e2129..e209081d644b 100644
--- a/drivers/acpi/irq.c
+++ b/drivers/acpi/irq.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ACPI GSI IRQ layer
*
* Copyright (C) 2015 ARM Ltd.
* Author: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
- *
- * 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.
*/
#include <linux/acpi.h>
#include <linux/irq.h>
@@ -295,3 +292,29 @@ void __init acpi_set_irq_model(enum acpi_irq_model_id model,
acpi_irq_model = model;
acpi_gsi_domain_id = fwnode;
}
+
+/**
+ * acpi_irq_create_hierarchy - Create a hierarchical IRQ domain with the default
+ * GSI domain as its parent.
+ * @flags: Irq domain flags associated with the domain
+ * @size: Size of the domain.
+ * @fwnode: Optional fwnode of the interrupt controller
+ * @ops: Pointer to the interrupt domain callbacks
+ * @host_data: Controller private data pointer
+ */
+struct irq_domain *acpi_irq_create_hierarchy(unsigned int flags,
+ unsigned int size,
+ struct fwnode_handle *fwnode,
+ const struct irq_domain_ops *ops,
+ void *host_data)
+{
+ struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
+ DOMAIN_BUS_ANY);
+
+ if (!d)
+ return NULL;
+
+ return irq_domain_create_hierarchy(d, flags, size, fwnode, ops,
+ host_data);
+}
+EXPORT_SYMBOL_GPL(acpi_irq_create_hierarchy);
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
index 23022cf20d26..c02fa27dd3f3 100644
--- a/drivers/acpi/nfit/core.c
+++ b/drivers/acpi/nfit/core.c
@@ -2426,7 +2426,7 @@ static void write_blk_ctl(struct nfit_blk *nfit_blk, unsigned int bw,
offset = to_interleave_offset(offset, mmio);
writeq(cmd, mmio->addr.base + offset);
- nvdimm_flush(nfit_blk->nd_region);
+ nvdimm_flush(nfit_blk->nd_region, NULL);
if (nfit_blk->dimm_flags & NFIT_BLK_DCR_LATCH)
readq(mmio->addr.base + offset);
@@ -2475,7 +2475,7 @@ static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk,
}
if (rw)
- nvdimm_flush(nfit_blk->nd_region);
+ nvdimm_flush(nfit_blk->nd_region, NULL);
rc = read_blk_stat(nfit_blk, lane) ? -EIO : 0;
return rc;
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index cc7507091dec..9c0edf2fc0dd 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -301,8 +301,8 @@ static void acpi_unmap(acpi_physical_address pg_off, void __iomem *vaddr)
* During early init (when acpi_permanent_mmap has not been set yet) this
* routine simply calls __acpi_map_table() to get the job done.
*/
-void __iomem *__ref
-acpi_os_map_iomem(acpi_physical_address phys, acpi_size size)
+void __iomem __ref
+*acpi_os_map_iomem(acpi_physical_address phys, acpi_size size)
{
struct acpi_ioremap *map;
void __iomem *virt;
diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c
index b42be067fb83..6b347d9920cc 100644
--- a/drivers/acpi/pci_mcfg.c
+++ b/drivers/acpi/pci_mcfg.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2016 Broadcom
* Author: Jayachandran C <jchandra@broadcom.com>
* Copyright (C) 2016 Semihalf
* Author: Tomasz Nowicki <tn@semihalf.com>
- *
- * 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 (the "GPL").
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License version 2 (GPLv2) for more details.
- *
- * You should have received a copy of the GNU General Public License
- * version 2 (GPLv2) along with this source code.
*/
#define pr_fmt(fmt) "ACPI: " fmt
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 39f5d172e84f..314a187ed572 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -881,6 +881,7 @@ struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
int node = acpi_get_node(device->handle);
struct pci_bus *bus;
struct pci_host_bridge *host_bridge;
+ union acpi_object *obj;
info->root = root;
info->bridge = device;
@@ -917,6 +918,17 @@ struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
if (!(root->osc_control_set & OSC_PCI_EXPRESS_LTR_CONTROL))
host_bridge->native_ltr = 0;
+ /*
+ * Evaluate the "PCI Boot Configuration" _DSM Function. If it
+ * exists and returns 0, we must preserve any PCI resource
+ * assignments made by firmware for this host bridge.
+ */
+ obj = acpi_evaluate_dsm(ACPI_HANDLE(bus->bridge), &pci_acpi_dsm_guid, 1,
+ IGNORE_PCI_BOOT_CONFIG_DSM, NULL);
+ if (obj && obj->type == ACPI_TYPE_INTEGER && obj->integer.value == 0)
+ host_bridge->preserve_config = 1;
+ ACPI_FREE(obj);
+
pci_scan_child_bus(bus);
pci_set_host_bridge_release(host_bridge, acpi_pci_root_release_info,
info);
diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c
index e90b61f7d2db..ca2461d1bf14 100644
--- a/drivers/acpi/pci_slot.c
+++ b/drivers/acpi/pci_slot.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* pci_slot.c - ACPI PCI Slot Driver
*
@@ -11,15 +12,6 @@
*
* Copyright (C) 2013 Huawei Tech. Co., Ltd.
* Jiang Liu <jiang.liu@huawei.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/acpi/pmic/intel_pmic.c b/drivers/acpi/pmic/intel_pmic.c
index 1b722fd57d5e..452041398b34 100644
--- a/drivers/acpi/pmic/intel_pmic.c
+++ b/drivers/acpi/pmic/intel_pmic.c
@@ -284,8 +284,6 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle,
intel_pmic_thermal_handler,
NULL, opregion);
if (ACPI_FAILURE(status)) {
- acpi_remove_address_space_handler(handle, PMIC_POWER_OPREGION_ID,
- intel_pmic_power_handler);
ret = -ENODEV;
goto out_remove_power_handler;
}
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index a916417b9e70..fe1e7bc91a5e 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -42,6 +42,11 @@ ACPI_MODULE_NAME("power");
#define ACPI_POWER_RESOURCE_STATE_ON 0x01
#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF
+struct acpi_power_dependent_device {
+ struct device *dev;
+ struct list_head node;
+};
+
struct acpi_power_resource {
struct acpi_device device;
struct list_head list_node;
@@ -51,6 +56,7 @@ struct acpi_power_resource {
unsigned int ref_count;
bool wakeup_enabled;
struct mutex resource_lock;
+ struct list_head dependents;
};
struct acpi_power_resource_entry {
@@ -232,8 +238,121 @@ static int acpi_power_get_list_state(struct list_head *list, int *state)
return 0;
}
+static int
+acpi_power_resource_add_dependent(struct acpi_power_resource *resource,
+ struct device *dev)
+{
+ struct acpi_power_dependent_device *dep;
+ int ret = 0;
+
+ mutex_lock(&resource->resource_lock);
+ list_for_each_entry(dep, &resource->dependents, node) {
+ /* Only add it once */
+ if (dep->dev == dev)
+ goto unlock;
+ }
+
+ dep = kzalloc(sizeof(*dep), GFP_KERNEL);
+ if (!dep) {
+ ret = -ENOMEM;
+ goto unlock;
+ }
+
+ dep->dev = dev;
+ list_add_tail(&dep->node, &resource->dependents);
+ dev_dbg(dev, "added power dependency to [%s]\n", resource->name);
+
+unlock:
+ mutex_unlock(&resource->resource_lock);
+ return ret;
+}
+
+static void
+acpi_power_resource_remove_dependent(struct acpi_power_resource *resource,
+ struct device *dev)
+{
+ struct acpi_power_dependent_device *dep;
+
+ mutex_lock(&resource->resource_lock);
+ list_for_each_entry(dep, &resource->dependents, node) {
+ if (dep->dev == dev) {
+ list_del(&dep->node);
+ kfree(dep);
+ dev_dbg(dev, "removed power dependency to [%s]\n",
+ resource->name);
+ break;
+ }
+ }
+ mutex_unlock(&resource->resource_lock);
+}
+
+/**
+ * acpi_device_power_add_dependent - Add dependent device of this ACPI device
+ * @adev: ACPI device pointer
+ * @dev: Dependent device
+ *
+ * If @adev has non-empty _PR0 the @dev is added as dependent device to all
+ * power resources returned by it. This means that whenever these power
+ * resources are turned _ON the dependent devices get runtime resumed. This
+ * is needed for devices such as PCI to allow its driver to re-initialize
+ * it after it went to D0uninitialized.
+ *
+ * If @adev does not have _PR0 this does nothing.
+ *
+ * Returns %0 in case of success and negative errno otherwise.
+ */
+int acpi_device_power_add_dependent(struct acpi_device *adev,
+ struct device *dev)
+{
+ struct acpi_power_resource_entry *entry;
+ struct list_head *resources;
+ int ret;
+
+ if (!adev->flags.power_manageable)
+ return 0;
+
+ resources = &adev->power.states[ACPI_STATE_D0].resources;
+ list_for_each_entry(entry, resources, node) {
+ ret = acpi_power_resource_add_dependent(entry->resource, dev);
+ if (ret)
+ goto err;
+ }
+
+ return 0;
+
+err:
+ list_for_each_entry(entry, resources, node)
+ acpi_power_resource_remove_dependent(entry->resource, dev);
+
+ return ret;
+}
+
+/**
+ * acpi_device_power_remove_dependent - Remove dependent device
+ * @adev: ACPI device pointer
+ * @dev: Dependent device
+ *
+ * Does the opposite of acpi_device_power_add_dependent() and removes the
+ * dependent device if it is found. Can be called to @adev that does not
+ * have _PR0 as well.
+ */
+void acpi_device_power_remove_dependent(struct acpi_device *adev,
+ struct device *dev)
+{
+ struct acpi_power_resource_entry *entry;
+ struct list_head *resources;
+
+ if (!adev->flags.power_manageable)
+ return;
+
+ resources = &adev->power.states[ACPI_STATE_D0].resources;
+ list_for_each_entry_reverse(entry, resources, node)
+ acpi_power_resource_remove_dependent(entry->resource, dev);
+}
+
static int __acpi_power_on(struct acpi_power_resource *resource)
{
+ struct acpi_power_dependent_device *dep;
acpi_status status = AE_OK;
status = acpi_evaluate_object(resource->device.handle, "_ON", NULL, NULL);
@@ -243,6 +362,21 @@ static int __acpi_power_on(struct acpi_power_resource *resource)
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Power resource [%s] turned on\n",
resource->name));
+ /*
+ * If there are other dependents on this power resource we need to
+ * resume them now so that their drivers can re-initialize the
+ * hardware properly after it went back to D0.
+ */
+ if (list_empty(&resource->dependents) ||
+ list_is_singular(&resource->dependents))
+ return 0;
+
+ list_for_each_entry(dep, &resource->dependents, node) {
+ dev_dbg(dep->dev, "runtime resuming because [%s] turned on\n",
+ resource->name);
+ pm_request_resume(dep->dev);
+ }
+
return 0;
}
@@ -810,6 +944,7 @@ int acpi_add_power_resource(acpi_handle handle)
ACPI_STA_DEFAULT);
mutex_init(&resource->resource_lock);
INIT_LIST_HEAD(&resource->list_node);
+ INIT_LIST_HEAD(&resource->dependents);
resource->name = device->pnp.bus_id;
strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_POWER_CLASS);
diff --git a/drivers/acpi/pptt.c b/drivers/acpi/pptt.c
index b72e6afaa8fb..1e7ac0bd0d3a 100644
--- a/drivers/acpi/pptt.c
+++ b/drivers/acpi/pptt.c
@@ -432,17 +432,40 @@ static void cache_setup_acpi_cpu(struct acpi_table_header *table,
}
}
+static bool flag_identical(struct acpi_table_header *table_hdr,
+ struct acpi_pptt_processor *cpu)
+{
+ struct acpi_pptt_processor *next;
+
+ /* heterogeneous machines must use PPTT revision > 1 */
+ if (table_hdr->revision < 2)
+ return false;
+
+ /* Locate the last node in the tree with IDENTICAL set */
+ if (cpu->flags & ACPI_PPTT_ACPI_IDENTICAL) {
+ next = fetch_pptt_node(table_hdr, cpu->parent);
+ if (!(next && next->flags & ACPI_PPTT_ACPI_IDENTICAL))
+ return true;
+ }
+
+ return false;
+}
+
/* Passing level values greater than this will result in search termination */
#define PPTT_ABORT_PACKAGE 0xFF
-static struct acpi_pptt_processor *acpi_find_processor_package_id(struct acpi_table_header *table_hdr,
- struct acpi_pptt_processor *cpu,
- int level, int flag)
+static struct acpi_pptt_processor *acpi_find_processor_tag(struct acpi_table_header *table_hdr,
+ struct acpi_pptt_processor *cpu,
+ int level, int flag)
{
struct acpi_pptt_processor *prev_node;
while (cpu && level) {
- if (cpu->flags & flag)
+ /* special case the identical flag to find last identical */
+ if (flag == ACPI_PPTT_ACPI_IDENTICAL) {
+ if (flag_identical(table_hdr, cpu))
+ break;
+ } else if (cpu->flags & flag)
break;
pr_debug("level %d\n", level);
prev_node = fetch_pptt_node(table_hdr, cpu->parent);
@@ -480,8 +503,8 @@ static int topology_get_acpi_cpu_tag(struct acpi_table_header *table,
cpu_node = acpi_find_processor_node(table, acpi_cpu_id);
if (cpu_node) {
- cpu_node = acpi_find_processor_package_id(table, cpu_node,
- level, flag);
+ cpu_node = acpi_find_processor_tag(table, cpu_node,
+ level, flag);
/*
* As per specification if the processor structure represents
* an actual processor, then ACPI processor ID must be valid.
@@ -660,3 +683,29 @@ int find_acpi_cpu_topology_package(unsigned int cpu)
return find_acpi_cpu_topology_tag(cpu, PPTT_ABORT_PACKAGE,
ACPI_PPTT_PHYSICAL_PACKAGE);
}
+
+/**
+ * find_acpi_cpu_topology_hetero_id() - Get a core architecture tag
+ * @cpu: Kernel logical CPU number
+ *
+ * Determine a unique heterogeneous tag for the given CPU. CPUs with the same
+ * implementation should have matching tags.
+ *
+ * The returned tag can be used to group peers with identical implementation.
+ *
+ * The search terminates when a level is found with the identical implementation
+ * flag set or we reach a root node.
+ *
+ * Due to limitations in the PPTT data structure, there may be rare situations
+ * where two cores in a heterogeneous machine may be identical, but won't have
+ * the same tag.
+ *
+ * Return: -ENOENT if the PPTT doesn't exist, or the CPU cannot be found.
+ * Otherwise returns a value which represents a group of identical cores
+ * similar to this CPU.
+ */
+int find_acpi_cpu_topology_hetero_id(unsigned int cpu)
+{
+ return find_acpi_cpu_topology_tag(cpu, PPTT_ABORT_PACKAGE,
+ ACPI_PPTT_ACPI_IDENTICAL);
+}
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index e387a258d649..ed56c6d20b08 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -196,6 +196,7 @@ static void tsc_check_state(int state)
case X86_VENDOR_AMD:
case X86_VENDOR_INTEL:
case X86_VENDOR_CENTAUR:
+ case X86_VENDOR_ZHAOXIN:
/*
* AMD Fam10h TSC will tick in all
* C/P/S0/S1 states when this bit is set.
diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c
index 9d460a859be0..ea3d700da3ca 100644
--- a/drivers/acpi/property.c
+++ b/drivers/acpi/property.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ACPI device specific properties support.
*
@@ -7,10 +8,6 @@
* Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
* Darren Hart <dvhart@linux.intel.com>
* Rafael J. Wysocki <rafael.j.wysocki@intel.com>
- *
- * 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.
*/
#include <linux/acpi.h>
@@ -603,15 +600,29 @@ static struct fwnode_handle *
acpi_fwnode_get_named_child_node(const struct fwnode_handle *fwnode,
const char *childname)
{
+ char name[ACPI_PATH_SEGMENT_LENGTH];
struct fwnode_handle *child;
+ struct acpi_buffer path;
+ acpi_status status;
- /*
- * Find first matching named child node of this fwnode.
- * For ACPI this will be a data only sub-node.
- */
- fwnode_for_each_child_node(fwnode, child)
- if (acpi_data_node_match(child, childname))
+ path.length = sizeof(name);
+ path.pointer = name;
+
+ fwnode_for_each_child_node(fwnode, child) {
+ if (is_acpi_data_node(child)) {
+ if (acpi_data_node_match(child, childname))
+ return child;
+ continue;
+ }
+
+ status = acpi_get_name(ACPI_HANDLE_FWNODE(child),
+ ACPI_SINGLE_NAME, &path);
+ if (ACPI_FAILURE(status))
+ break;
+
+ if (!strncmp(name, childname, ACPI_NAMESEG_SIZE))
return child;
+ }
return NULL;
}
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 8ff08e531443..f0fe7c15d657 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -77,7 +77,7 @@ static int acpi_sleep_prepare(u32 acpi_state)
return 0;
}
-static bool acpi_sleep_state_supported(u8 sleep_state)
+bool acpi_sleep_state_supported(u8 sleep_state)
{
acpi_status status;
u8 type_a, type_b;
@@ -452,14 +452,6 @@ static int acpi_pm_prepare(void)
return error;
}
-static int find_powerf_dev(struct device *dev, void *data)
-{
- struct acpi_device *device = to_acpi_device(dev);
- const char *hid = acpi_device_hid(device);
-
- return !strcmp(hid, ACPI_BUTTON_HID_POWERF);
-}
-
/**
* acpi_pm_finish - Instruct the platform to leave a sleep state.
*
@@ -468,7 +460,7 @@ static int find_powerf_dev(struct device *dev, void *data)
*/
static void acpi_pm_finish(void)
{
- struct device *pwr_btn_dev;
+ struct acpi_device *pwr_btn_adev;
u32 acpi_state = acpi_target_sleep_state;
acpi_ec_unblock_transactions();
@@ -499,11 +491,11 @@ static void acpi_pm_finish(void)
return;
pwr_btn_event_pending = false;
- pwr_btn_dev = bus_find_device(&acpi_bus_type, NULL, NULL,
- find_powerf_dev);
- if (pwr_btn_dev) {
- pm_wakeup_event(pwr_btn_dev, 0);
- put_device(pwr_btn_dev);
+ pwr_btn_adev = acpi_dev_get_first_match_dev(ACPI_BUTTON_HID_POWERF,
+ NULL, -1);
+ if (pwr_btn_adev) {
+ pm_wakeup_event(&pwr_btn_adev->dev, 0);
+ acpi_dev_put(pwr_btn_adev);
}
}
diff --git a/drivers/acpi/spcr.c b/drivers/acpi/spcr.c
index b34d05e365b7..d73b4535e79d 100644
--- a/drivers/acpi/spcr.c
+++ b/drivers/acpi/spcr.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012, Intel Corporation
* Copyright (c) 2015, Red Hat, Inc.
* Copyright (c) 2015, 2016 Linaro Ltd.
- *
- * 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.
- *
*/
#define pr_fmt(fmt) "ACPI: SPCR: " fmt
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index de974322a197..b32327759380 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -490,16 +490,17 @@ static u8 __init acpi_table_checksum(u8 *buffer, u32 length)
/* All but ACPI_SIG_RSDP and ACPI_SIG_FACS: */
static const char * const table_sigs[] = {
- ACPI_SIG_BERT, ACPI_SIG_CPEP, ACPI_SIG_ECDT, ACPI_SIG_EINJ,
- ACPI_SIG_ERST, ACPI_SIG_HEST, ACPI_SIG_MADT, ACPI_SIG_MSCT,
- ACPI_SIG_SBST, ACPI_SIG_SLIT, ACPI_SIG_SRAT, ACPI_SIG_ASF,
- ACPI_SIG_BOOT, ACPI_SIG_DBGP, ACPI_SIG_DMAR, ACPI_SIG_HPET,
- ACPI_SIG_IBFT, ACPI_SIG_IVRS, ACPI_SIG_MCFG, ACPI_SIG_MCHI,
- ACPI_SIG_SLIC, ACPI_SIG_SPCR, ACPI_SIG_SPMI, ACPI_SIG_TCPA,
- ACPI_SIG_UEFI, ACPI_SIG_WAET, ACPI_SIG_WDAT, ACPI_SIG_WDDT,
- ACPI_SIG_WDRT, ACPI_SIG_DSDT, ACPI_SIG_FADT, ACPI_SIG_PSDT,
- ACPI_SIG_RSDT, ACPI_SIG_XSDT, ACPI_SIG_SSDT, ACPI_SIG_IORT,
- ACPI_SIG_NFIT, ACPI_SIG_HMAT, ACPI_SIG_PPTT, NULL };
+ ACPI_SIG_BERT, ACPI_SIG_BGRT, ACPI_SIG_CPEP, ACPI_SIG_ECDT,
+ ACPI_SIG_EINJ, ACPI_SIG_ERST, ACPI_SIG_HEST, ACPI_SIG_MADT,
+ ACPI_SIG_MSCT, ACPI_SIG_SBST, ACPI_SIG_SLIT, ACPI_SIG_SRAT,
+ ACPI_SIG_ASF, ACPI_SIG_BOOT, ACPI_SIG_DBGP, ACPI_SIG_DMAR,
+ ACPI_SIG_HPET, ACPI_SIG_IBFT, ACPI_SIG_IVRS, ACPI_SIG_MCFG,
+ ACPI_SIG_MCHI, ACPI_SIG_SLIC, ACPI_SIG_SPCR, ACPI_SIG_SPMI,
+ ACPI_SIG_TCPA, ACPI_SIG_UEFI, ACPI_SIG_WAET, ACPI_SIG_WDAT,
+ ACPI_SIG_WDDT, ACPI_SIG_WDRT, ACPI_SIG_DSDT, ACPI_SIG_FADT,
+ ACPI_SIG_PSDT, ACPI_SIG_RSDT, ACPI_SIG_XSDT, ACPI_SIG_SSDT,
+ ACPI_SIG_IORT, ACPI_SIG_NFIT, ACPI_SIG_HMAT, ACPI_SIG_PPTT,
+ NULL };
#define ACPI_HEADER_SIZE sizeof(struct acpi_table_header)
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index 7def63ab00c0..e3974a8f8fd4 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -725,17 +725,15 @@ bool acpi_dev_found(const char *hid)
EXPORT_SYMBOL(acpi_dev_found);
struct acpi_dev_match_info {
- const char *dev_name;
- struct acpi_device *adev;
struct acpi_device_id hid[2];
const char *uid;
s64 hrv;
};
-static int acpi_dev_match_cb(struct device *dev, void *data)
+static int acpi_dev_match_cb(struct device *dev, const void *data)
{
struct acpi_device *adev = to_acpi_device(dev);
- struct acpi_dev_match_info *match = data;
+ const struct acpi_dev_match_info *match = data;
unsigned long long hrv;
acpi_status status;
@@ -746,9 +744,6 @@ static int acpi_dev_match_cb(struct device *dev, void *data)
strcmp(adev->pnp.unique_id, match->uid)))
return 0;
- match->dev_name = acpi_dev_name(adev);
- match->adev = adev;
-
if (match->hrv == -1)
return 1;
@@ -818,7 +813,7 @@ acpi_dev_get_first_match_dev(const char *hid, const char *uid, s64 hrv)
match.hrv = hrv;
dev = bus_find_device(&acpi_bus_type, NULL, &match, acpi_dev_match_cb);
- return dev ? match.adev : NULL;
+ return dev ? to_acpi_device(dev) : NULL;
}
EXPORT_SYMBOL(acpi_dev_get_first_match_dev);
diff --git a/drivers/acpi/x86/apple.c b/drivers/acpi/x86/apple.c
index b7c98ff82d78..c285c91a5e9c 100644
--- a/drivers/acpi/x86/apple.c
+++ b/drivers/acpi/x86/apple.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* apple.c - Apple ACPI quirks
* Copyright (C) 2017 Lukas Wunner <lukas@wunner.de>
- *
- * 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.
*/
#include <linux/acpi.h>
diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c
index c6df14802741..ba277cd5c7fa 100644
--- a/drivers/acpi/x86/utils.c
+++ b/drivers/acpi/x86/utils.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* X86 ACPI Utility Functions
*
@@ -5,10 +6,6 @@
*
* Based on various non upstream patches to support the CHT Whiskey Cove PMIC:
* Copyright (C) 2013-2015 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/acpi.h>
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
index b4dae624b9af..100e798a5c82 100644
--- a/drivers/amba/bus.c
+++ b/drivers/amba/bus.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/arch/arm/common/amba.c
*
* Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/init.h>
diff --git a/drivers/amba/tegra-ahb.c b/drivers/amba/tegra-ahb.c
index 3eaa459ae057..aa64eece77a6 100644
--- a/drivers/amba/tegra-ahb.c
+++ b/drivers/amba/tegra-ahb.c
@@ -134,10 +134,10 @@ static inline void gizmo_writel(struct tegra_ahb *ahb, u32 value, u32 offset)
}
#ifdef CONFIG_TEGRA_IOMMU_SMMU
-static int tegra_ahb_match_by_smmu(struct device *dev, void *data)
+static int tegra_ahb_match_by_smmu(struct device *dev, const void *data)
{
struct tegra_ahb *ahb = dev_get_drvdata(dev);
- struct device_node *dn = data;
+ const struct device_node *dn = data;
return (ahb->dev->of_node == dn) ? 1 : 0;
}
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 748ac489ef7e..38a59a630cd4 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -1941,8 +1941,18 @@ static void binder_free_txn_fixups(struct binder_transaction *t)
static void binder_free_transaction(struct binder_transaction *t)
{
- if (t->buffer)
- t->buffer->transaction = NULL;
+ struct binder_proc *target_proc = t->to_proc;
+
+ if (target_proc) {
+ binder_inner_proc_lock(target_proc);
+ if (t->buffer)
+ t->buffer->transaction = NULL;
+ binder_inner_proc_unlock(target_proc);
+ }
+ /*
+ * If the transaction has no target_proc, then
+ * t->buffer->transaction has already been cleared.
+ */
binder_free_txn_fixups(t);
kfree(t);
binder_stats_deleted(BINDER_STAT_TRANSACTION);
@@ -2049,10 +2059,9 @@ static size_t binder_get_object(struct binder_proc *proc,
read_size = min_t(size_t, sizeof(*object), buffer->data_size - offset);
if (offset > buffer->data_size || read_size < sizeof(*hdr) ||
- !IS_ALIGNED(offset, sizeof(u32)))
+ binder_alloc_copy_from_buffer(&proc->alloc, object, buffer,
+ offset, read_size))
return 0;
- binder_alloc_copy_from_buffer(&proc->alloc, object, buffer,
- offset, read_size);
/* Ok, now see if we read a complete object. */
hdr = &object->hdr;
@@ -2121,8 +2130,10 @@ static struct binder_buffer_object *binder_validate_ptr(
return NULL;
buffer_offset = start_offset + sizeof(binder_size_t) * index;
- binder_alloc_copy_from_buffer(&proc->alloc, &object_offset,
- b, buffer_offset, sizeof(object_offset));
+ if (binder_alloc_copy_from_buffer(&proc->alloc, &object_offset,
+ b, buffer_offset,
+ sizeof(object_offset)))
+ return NULL;
object_size = binder_get_object(proc, b, object_offset, object);
if (!object_size || object->hdr.type != BINDER_TYPE_PTR)
return NULL;
@@ -2202,10 +2213,12 @@ static bool binder_validate_fixup(struct binder_proc *proc,
return false;
last_min_offset = last_bbo->parent_offset + sizeof(uintptr_t);
buffer_offset = objects_start_offset +
- sizeof(binder_size_t) * last_bbo->parent,
- binder_alloc_copy_from_buffer(&proc->alloc, &last_obj_offset,
- b, buffer_offset,
- sizeof(last_obj_offset));
+ sizeof(binder_size_t) * last_bbo->parent;
+ if (binder_alloc_copy_from_buffer(&proc->alloc,
+ &last_obj_offset,
+ b, buffer_offset,
+ sizeof(last_obj_offset)))
+ return false;
}
return (fixup_offset >= last_min_offset);
}
@@ -2291,15 +2304,15 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
for (buffer_offset = off_start_offset; buffer_offset < off_end_offset;
buffer_offset += sizeof(binder_size_t)) {
struct binder_object_header *hdr;
- size_t object_size;
+ size_t object_size = 0;
struct binder_object object;
binder_size_t object_offset;
- binder_alloc_copy_from_buffer(&proc->alloc, &object_offset,
- buffer, buffer_offset,
- sizeof(object_offset));
- object_size = binder_get_object(proc, buffer,
- object_offset, &object);
+ if (!binder_alloc_copy_from_buffer(&proc->alloc, &object_offset,
+ buffer, buffer_offset,
+ sizeof(object_offset)))
+ object_size = binder_get_object(proc, buffer,
+ object_offset, &object);
if (object_size == 0) {
pr_err("transaction release %d bad object at offset %lld, size %zd\n",
debug_id, (u64)object_offset, buffer->data_size);
@@ -2422,15 +2435,16 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
for (fd_index = 0; fd_index < fda->num_fds;
fd_index++) {
u32 fd;
+ int err;
binder_size_t offset = fda_offset +
fd_index * sizeof(fd);
- binder_alloc_copy_from_buffer(&proc->alloc,
- &fd,
- buffer,
- offset,
- sizeof(fd));
- binder_deferred_fd_close(fd);
+ err = binder_alloc_copy_from_buffer(
+ &proc->alloc, &fd, buffer,
+ offset, sizeof(fd));
+ WARN_ON(err);
+ if (!err)
+ binder_deferred_fd_close(fd);
}
} break;
default:
@@ -2673,11 +2687,12 @@ static int binder_translate_fd_array(struct binder_fd_array_object *fda,
int ret;
binder_size_t offset = fda_offset + fdi * sizeof(fd);
- binder_alloc_copy_from_buffer(&target_proc->alloc,
- &fd, t->buffer,
- offset, sizeof(fd));
- ret = binder_translate_fd(fd, offset, t, thread,
- in_reply_to);
+ ret = binder_alloc_copy_from_buffer(&target_proc->alloc,
+ &fd, t->buffer,
+ offset, sizeof(fd));
+ if (!ret)
+ ret = binder_translate_fd(fd, offset, t, thread,
+ in_reply_to);
if (ret < 0)
return ret;
}
@@ -2730,8 +2745,12 @@ static int binder_fixup_parent(struct binder_transaction *t,
}
buffer_offset = bp->parent_offset +
(uintptr_t)parent->buffer - (uintptr_t)b->user_data;
- binder_alloc_copy_to_buffer(&target_proc->alloc, b, buffer_offset,
- &bp->buffer, sizeof(bp->buffer));
+ if (binder_alloc_copy_to_buffer(&target_proc->alloc, b, buffer_offset,
+ &bp->buffer, sizeof(bp->buffer))) {
+ binder_user_error("%d:%d got transaction with invalid parent offset\n",
+ proc->pid, thread->pid);
+ return -EINVAL;
+ }
return 0;
}
@@ -3150,15 +3169,20 @@ static void binder_transaction(struct binder_proc *proc,
goto err_binder_alloc_buf_failed;
}
if (secctx) {
+ int err;
size_t buf_offset = ALIGN(tr->data_size, sizeof(void *)) +
ALIGN(tr->offsets_size, sizeof(void *)) +
ALIGN(extra_buffers_size, sizeof(void *)) -
ALIGN(secctx_sz, sizeof(u64));
t->security_ctx = (uintptr_t)t->buffer->user_data + buf_offset;
- binder_alloc_copy_to_buffer(&target_proc->alloc,
- t->buffer, buf_offset,
- secctx, secctx_sz);
+ err = binder_alloc_copy_to_buffer(&target_proc->alloc,
+ t->buffer, buf_offset,
+ secctx, secctx_sz);
+ if (err) {
+ t->security_ctx = 0;
+ WARN_ON(1);
+ }
security_release_secctx(secctx, secctx_sz);
secctx = NULL;
}
@@ -3224,11 +3248,16 @@ static void binder_transaction(struct binder_proc *proc,
struct binder_object object;
binder_size_t object_offset;
- binder_alloc_copy_from_buffer(&target_proc->alloc,
- &object_offset,
- t->buffer,
- buffer_offset,
- sizeof(object_offset));
+ if (binder_alloc_copy_from_buffer(&target_proc->alloc,
+ &object_offset,
+ t->buffer,
+ buffer_offset,
+ sizeof(object_offset))) {
+ return_error = BR_FAILED_REPLY;
+ return_error_param = -EINVAL;
+ return_error_line = __LINE__;
+ goto err_bad_offset;
+ }
object_size = binder_get_object(target_proc, t->buffer,
object_offset, &object);
if (object_size == 0 || object_offset < off_min) {
@@ -3252,15 +3281,17 @@ static void binder_transaction(struct binder_proc *proc,
fp = to_flat_binder_object(hdr);
ret = binder_translate_binder(fp, t, thread);
- if (ret < 0) {
+
+ if (ret < 0 ||
+ binder_alloc_copy_to_buffer(&target_proc->alloc,
+ t->buffer,
+ object_offset,
+ fp, sizeof(*fp))) {
return_error = BR_FAILED_REPLY;
return_error_param = ret;
return_error_line = __LINE__;
goto err_translate_failed;
}
- binder_alloc_copy_to_buffer(&target_proc->alloc,
- t->buffer, object_offset,
- fp, sizeof(*fp));
} break;
case BINDER_TYPE_HANDLE:
case BINDER_TYPE_WEAK_HANDLE: {
@@ -3268,15 +3299,16 @@ static void binder_transaction(struct binder_proc *proc,
fp = to_flat_binder_object(hdr);
ret = binder_translate_handle(fp, t, thread);
- if (ret < 0) {
+ if (ret < 0 ||
+ binder_alloc_copy_to_buffer(&target_proc->alloc,
+ t->buffer,
+ object_offset,
+ fp, sizeof(*fp))) {
return_error = BR_FAILED_REPLY;
return_error_param = ret;
return_error_line = __LINE__;
goto err_translate_failed;
}
- binder_alloc_copy_to_buffer(&target_proc->alloc,
- t->buffer, object_offset,
- fp, sizeof(*fp));
} break;
case BINDER_TYPE_FD: {
@@ -3286,16 +3318,17 @@ static void binder_transaction(struct binder_proc *proc,
int ret = binder_translate_fd(fp->fd, fd_offset, t,
thread, in_reply_to);
- if (ret < 0) {
+ fp->pad_binder = 0;
+ if (ret < 0 ||
+ binder_alloc_copy_to_buffer(&target_proc->alloc,
+ t->buffer,
+ object_offset,
+ fp, sizeof(*fp))) {
return_error = BR_FAILED_REPLY;
return_error_param = ret;
return_error_line = __LINE__;
goto err_translate_failed;
}
- fp->pad_binder = 0;
- binder_alloc_copy_to_buffer(&target_proc->alloc,
- t->buffer, object_offset,
- fp, sizeof(*fp));
} break;
case BINDER_TYPE_FDA: {
struct binder_object ptr_object;
@@ -3383,15 +3416,16 @@ static void binder_transaction(struct binder_proc *proc,
num_valid,
last_fixup_obj_off,
last_fixup_min_off);
- if (ret < 0) {
+ if (ret < 0 ||
+ binder_alloc_copy_to_buffer(&target_proc->alloc,
+ t->buffer,
+ object_offset,
+ bp, sizeof(*bp))) {
return_error = BR_FAILED_REPLY;
return_error_param = ret;
return_error_line = __LINE__;
goto err_translate_failed;
}
- binder_alloc_copy_to_buffer(&target_proc->alloc,
- t->buffer, object_offset,
- bp, sizeof(*bp));
last_fixup_obj_off = object_offset;
last_fixup_min_off = 0;
} break;
@@ -3551,10 +3585,12 @@ err_invalid_target_handle:
static void
binder_free_buf(struct binder_proc *proc, struct binder_buffer *buffer)
{
+ binder_inner_proc_lock(proc);
if (buffer->transaction) {
buffer->transaction->buffer = NULL;
buffer->transaction = NULL;
}
+ binder_inner_proc_unlock(proc);
if (buffer->async_transaction && buffer->target_node) {
struct binder_node *buf_node;
struct binder_work *w;
@@ -4128,20 +4164,27 @@ static int binder_apply_fd_fixups(struct binder_proc *proc,
trace_binder_transaction_fd_recv(t, fd, fixup->offset);
fd_install(fd, fixup->file);
fixup->file = NULL;
- binder_alloc_copy_to_buffer(&proc->alloc, t->buffer,
- fixup->offset, &fd,
- sizeof(u32));
+ if (binder_alloc_copy_to_buffer(&proc->alloc, t->buffer,
+ fixup->offset, &fd,
+ sizeof(u32))) {
+ ret = -EINVAL;
+ break;
+ }
}
list_for_each_entry_safe(fixup, tmp, &t->fd_fixups, fixup_entry) {
if (fixup->file) {
fput(fixup->file);
} else if (ret) {
u32 fd;
-
- binder_alloc_copy_from_buffer(&proc->alloc, &fd,
- t->buffer, fixup->offset,
- sizeof(fd));
- binder_deferred_fd_close(fd);
+ int err;
+
+ err = binder_alloc_copy_from_buffer(&proc->alloc, &fd,
+ t->buffer,
+ fixup->offset,
+ sizeof(fd));
+ WARN_ON(err);
+ if (!err)
+ binder_deferred_fd_close(fd);
}
list_del(&fixup->fixup_entry);
kfree(fixup);
@@ -4256,6 +4299,8 @@ retry:
case BINDER_WORK_TRANSACTION_COMPLETE: {
binder_inner_proc_unlock(proc);
cmd = BR_TRANSACTION_COMPLETE;
+ kfree(w);
+ binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
if (put_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
@@ -4264,8 +4309,6 @@ retry:
binder_debug(BINDER_DEBUG_TRANSACTION_COMPLETE,
"%d:%d BR_TRANSACTION_COMPLETE\n",
proc->pid, thread->pid);
- kfree(w);
- binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
} break;
case BINDER_WORK_NODE: {
struct binder_node *node = container_of(w, struct binder_node, work);
diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c
index ce5603c2291c..6d79a1b0d446 100644
--- a/drivers/android/binder_alloc.c
+++ b/drivers/android/binder_alloc.c
@@ -1119,15 +1119,16 @@ binder_alloc_copy_user_to_buffer(struct binder_alloc *alloc,
return 0;
}
-static void binder_alloc_do_buffer_copy(struct binder_alloc *alloc,
- bool to_buffer,
- struct binder_buffer *buffer,
- binder_size_t buffer_offset,
- void *ptr,
- size_t bytes)
+static int binder_alloc_do_buffer_copy(struct binder_alloc *alloc,
+ bool to_buffer,
+ struct binder_buffer *buffer,
+ binder_size_t buffer_offset,
+ void *ptr,
+ size_t bytes)
{
/* All copies must be 32-bit aligned and 32-bit size */
- BUG_ON(!check_buffer(alloc, buffer, buffer_offset, bytes));
+ if (!check_buffer(alloc, buffer, buffer_offset, bytes))
+ return -EINVAL;
while (bytes) {
unsigned long size;
@@ -1155,25 +1156,26 @@ static void binder_alloc_do_buffer_copy(struct binder_alloc *alloc,
ptr = ptr + size;
buffer_offset += size;
}
+ return 0;
}
-void binder_alloc_copy_to_buffer(struct binder_alloc *alloc,
- struct binder_buffer *buffer,
- binder_size_t buffer_offset,
- void *src,
- size_t bytes)
+int binder_alloc_copy_to_buffer(struct binder_alloc *alloc,
+ struct binder_buffer *buffer,
+ binder_size_t buffer_offset,
+ void *src,
+ size_t bytes)
{
- binder_alloc_do_buffer_copy(alloc, true, buffer, buffer_offset,
- src, bytes);
+ return binder_alloc_do_buffer_copy(alloc, true, buffer, buffer_offset,
+ src, bytes);
}
-void binder_alloc_copy_from_buffer(struct binder_alloc *alloc,
- void *dest,
- struct binder_buffer *buffer,
- binder_size_t buffer_offset,
- size_t bytes)
+int binder_alloc_copy_from_buffer(struct binder_alloc *alloc,
+ void *dest,
+ struct binder_buffer *buffer,
+ binder_size_t buffer_offset,
+ size_t bytes)
{
- binder_alloc_do_buffer_copy(alloc, false, buffer, buffer_offset,
- dest, bytes);
+ return binder_alloc_do_buffer_copy(alloc, false, buffer, buffer_offset,
+ dest, bytes);
}
diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h
index 71bfa95f8e09..db9c1b984695 100644
--- a/drivers/android/binder_alloc.h
+++ b/drivers/android/binder_alloc.h
@@ -159,17 +159,17 @@ binder_alloc_copy_user_to_buffer(struct binder_alloc *alloc,
const void __user *from,
size_t bytes);
-void binder_alloc_copy_to_buffer(struct binder_alloc *alloc,
- struct binder_buffer *buffer,
- binder_size_t buffer_offset,
- void *src,
- size_t bytes);
-
-void binder_alloc_copy_from_buffer(struct binder_alloc *alloc,
- void *dest,
- struct binder_buffer *buffer,
- binder_size_t buffer_offset,
- size_t bytes);
+int binder_alloc_copy_to_buffer(struct binder_alloc *alloc,
+ struct binder_buffer *buffer,
+ binder_size_t buffer_offset,
+ void *src,
+ size_t bytes);
+
+int binder_alloc_copy_from_buffer(struct binder_alloc *alloc,
+ void *dest,
+ struct binder_buffer *buffer,
+ binder_size_t buffer_offset,
+ size_t bytes);
#endif /* _LINUX_BINDER_ALLOC_H */
diff --git a/drivers/ata/acard-ahci.c b/drivers/ata/acard-ahci.c
index b1b49dbd0b14..85357f27a66b 100644
--- a/drivers/ata/acard-ahci.c
+++ b/drivers/ata/acard-ahci.c
@@ -344,7 +344,6 @@ static int acard_ahci_port_start(struct ata_port *ap)
mem = dmam_alloc_coherent(dev, dma_sz, &mem_dma, GFP_KERNEL);
if (!mem)
return -ENOMEM;
- memset(mem, 0, dma_sz);
/*
* First item in chunk of DMA memory: 32-slot command table,
diff --git a/drivers/ata/ahci_seattle.c b/drivers/ata/ahci_seattle.c
index e57b6f92c288..ced12705ed9d 100644
--- a/drivers/ata/ahci_seattle.c
+++ b/drivers/ata/ahci_seattle.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AMD Seattle AHCI SATA driver
*
@@ -5,15 +6,6 @@
* Author: Brijesh Singh <brijesh.singh@amd.com>
*
* based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/kernel.h>
diff --git a/drivers/ata/ahci_st.c b/drivers/ata/ahci_st.c
index 21c5c44832ef..c268264c2129 100644
--- a/drivers/ata/ahci_st.c
+++ b/drivers/ata/ahci_st.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 STMicroelectronics Limited
*
* Authors: Francesco Virlinzi <francesco.virlinzi@st.com>
* Alexandre Torgue <alexandre.torgue@st.com>
- *
- * 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.
*/
#include <linux/init.h>
diff --git a/drivers/ata/ahci_sunxi.c b/drivers/ata/ahci_sunxi.c
index 4100e904376b..cb69b737cb49 100644
--- a/drivers/ata/ahci_sunxi.c
+++ b/drivers/ata/ahci_sunxi.c
@@ -149,8 +149,51 @@ static void ahci_sunxi_start_engine(struct ata_port *ap)
void __iomem *port_mmio = ahci_port_base(ap);
struct ahci_host_priv *hpriv = ap->host->private_data;
- /* Setup DMA before DMA start */
- sunxi_clrsetbits(hpriv->mmio + AHCI_P0DMACR, 0x0000ff00, 0x00004400);
+ /* Setup DMA before DMA start
+ *
+ * NOTE: A similar SoC with SATA/AHCI by Texas Instruments documents
+ * this Vendor Specific Port (P0DMACR, aka PxDMACR) in its
+ * User's Guide document (TMS320C674x/OMAP-L1x Processor
+ * Serial ATA (SATA) Controller, Literature Number: SPRUGJ8C,
+ * March 2011, Chapter 4.33 Port DMA Control Register (P0DMACR),
+ * p.68, https://www.ti.com/lit/ug/sprugj8c/sprugj8c.pdf)
+ * as equivalent to the following struct:
+ *
+ * struct AHCI_P0DMACR_t
+ * {
+ * unsigned TXTS : 4;
+ * unsigned RXTS : 4;
+ * unsigned TXABL : 4;
+ * unsigned RXABL : 4;
+ * unsigned Reserved : 16;
+ * };
+ *
+ * TXTS: Transmit Transaction Size (TX_TRANSACTION_SIZE).
+ * This field defines the DMA transaction size in DWORDs for
+ * transmit (system bus read, device write) operation. [...]
+ *
+ * RXTS: Receive Transaction Size (RX_TRANSACTION_SIZE).
+ * This field defines the Port DMA transaction size in DWORDs
+ * for receive (system bus write, device read) operation. [...]
+ *
+ * TXABL: Transmit Burst Limit.
+ * This field allows software to limit the VBUSP master read
+ * burst size. [...]
+ *
+ * RXABL: Receive Burst Limit.
+ * Allows software to limit the VBUSP master write burst
+ * size. [...]
+ *
+ * Reserved: Reserved.
+ *
+ *
+ * NOTE: According to the above document, the following alternative
+ * to the code below could perhaps be a better option
+ * (or preparation) for possible further improvements later:
+ * sunxi_clrsetbits(hpriv->mmio + AHCI_P0DMACR, 0x0000ffff,
+ * 0x00000033);
+ */
+ sunxi_clrsetbits(hpriv->mmio + AHCI_P0DMACR, 0x0000ffff, 0x00004433);
/* Start DMA */
sunxi_setbits(port_mmio + PORT_CMD, PORT_CMD_START);
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index 0984c4b76d7e..e4c45d3cca79 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -2365,7 +2365,6 @@ static int ahci_port_start(struct ata_port *ap)
mem = dmam_alloc_coherent(dev, dma_sz, &mem_dma, GFP_KERNEL);
if (!mem)
return -ENOMEM;
- memset(mem, 0, dma_sz);
/*
* First item in chunk of DMA memory: 32-slot command table,
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 4a2dff303865..28c492be0a57 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -4462,9 +4462,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
/* drives which fail FPDMA_AA activation (some may freeze afterwards)
the ST disks also have LPM issues */
- { "ST1000LM024 HN-M101MBB", "2AR10001", ATA_HORKAGE_BROKEN_FPDMA_AA |
- ATA_HORKAGE_NOLPM, },
- { "ST1000LM024 HN-M101MBB", "2BA30001", ATA_HORKAGE_BROKEN_FPDMA_AA |
+ { "ST1000LM024 HN-M101MBB", NULL, ATA_HORKAGE_BROKEN_FPDMA_AA |
ATA_HORKAGE_NOLPM, },
{ "VB0250EAVER", "HPG7", ATA_HORKAGE_BROKEN_FPDMA_AA },
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 9d687e1d4325..3bfd9da58473 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1469,7 +1469,7 @@ static int ata_eh_read_log_10h(struct ata_device *dev,
tf->hob_lbah = buf[10];
tf->nsect = buf[12];
tf->hob_nsect = buf[13];
- if (ata_id_has_ncq_autosense(dev->id))
+ if (dev->class == ATA_DEV_ZAC && ata_id_has_ncq_autosense(dev->id))
tf->auxiliary = buf[14] << 16 | buf[15] << 8 | buf[16];
return 0;
@@ -1716,7 +1716,8 @@ void ata_eh_analyze_ncq_error(struct ata_link *link)
memcpy(&qc->result_tf, &tf, sizeof(tf));
qc->result_tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ;
- if ((qc->result_tf.command & ATA_SENSE) || qc->result_tf.auxiliary) {
+ if (dev->class == ATA_DEV_ZAC &&
+ ((qc->result_tf.command & ATA_SENSE) || qc->result_tf.auxiliary)) {
char sense_key, asc, ascq;
sense_key = (qc->result_tf.auxiliary >> 16) & 0xff;
@@ -1770,10 +1771,11 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
}
switch (qc->dev->class) {
- case ATA_DEV_ATA:
case ATA_DEV_ZAC:
if (stat & ATA_SENSE)
ata_eh_request_sense(qc, qc->scsicmd);
+ /* fall through */
+ case ATA_DEV_ATA:
if (err & ATA_ICRC)
qc->err_mask |= AC_ERR_ATA_BUS;
if (err & (ATA_UNC | ATA_AMNF))
diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c
index 0b0d93065f5a..d1644a8ef9fa 100644
--- a/drivers/ata/pata_ixp4xx_cf.c
+++ b/drivers/ata/pata_ixp4xx_cf.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ixp4xx PATA/Compact Flash driver
* Copyright (C) 2006-07 Tower Technologies
@@ -9,11 +10,6 @@
* on the ixp4xx. In the irq is not available, you might
* want to modify both this driver and libata to run in
* polling mode.
- *
- * 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.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/ata/pata_of_platform.c b/drivers/ata/pata_of_platform.c
index 7a0b1759e5f0..35aa158fc976 100644
--- a/drivers/ata/pata_of_platform.c
+++ b/drivers/ata/pata_of_platform.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* OF-platform PATA driver
*
* Copyright (c) 2007 MontaVista Software, Inc.
* Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/ata/pata_palmld.c b/drivers/ata/pata_palmld.c
index 26817fd91700..2448441571ed 100644
--- a/drivers/ata/pata_palmld.c
+++ b/drivers/ata/pata_palmld.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/ata/pata_palmld.c
*
@@ -13,11 +14,6 @@
* ixp4xx PATA/Compact Flash driver
* Copyright (C) 2006-07 Tower Technologies
* Author: Alessandro Zummo <a.zummo@towertech.it>
- *
- * 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.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/ata/pata_rb532_cf.c b/drivers/ata/pata_rb532_cf.c
index 66bb5bff126b..7c37f2ff09e4 100644
--- a/drivers/ata/pata_rb532_cf.c
+++ b/drivers/ata/pata_rb532_cf.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* A low-level PATA driver to handle a Compact Flash connected on the
* Mikrotik's RouterBoard 532 board.
@@ -12,11 +13,6 @@
* Also was based on the driver for Linux 2.4.xx published by Mikrotik for
* their RouterBoard 1xx and 5xx series devices. The original Mikrotik code
* seems not to have a license.
- *
- * 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.
- *
*/
#include <linux/gfp.h>
diff --git a/drivers/ata/pata_samsung_cf.c b/drivers/ata/pata_samsung_cf.c
index 1dc3361cb5a5..3da0e8e30286 100644
--- a/drivers/ata/pata_samsung_cf.c
+++ b/drivers/ata/pata_samsung_cf.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2010 Samsung Electronics Co., Ltd.
* http://www.samsung.com
@@ -9,10 +10,6 @@
* Based on:
* PATA driver for AT91SAM9260 Static Memory Controller
* PATA driver for Toshiba SCC controller
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c
index 52fa8606a25f..c5bbb07aa7d9 100644
--- a/drivers/ata/pdc_adma.c
+++ b/drivers/ata/pdc_adma.c
@@ -550,7 +550,6 @@ static int adma_port_start(struct ata_port *ap)
(u32)pp->pkt_dma);
return -ENOMEM;
}
- memset(pp->pkt, 0, ADMA_PKT_BYTES);
ap->private_data = pp;
adma_reinit_engine(ap);
return 0;
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 54bfab15c74a..b44b4b64354c 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -1136,7 +1136,6 @@ static int nv_adma_port_start(struct ata_port *ap)
&mem_dma, GFP_KERNEL);
if (!mem)
return -ENOMEM;
- memset(mem, 0, NV_ADMA_PORT_PRIV_DMA_SZ);
/*
* First item in chunk of DMA memory:
@@ -1946,7 +1945,6 @@ static int nv_swncq_port_start(struct ata_port *ap)
&pp->prd_dma, GFP_KERNEL);
if (!pp->prd)
return -ENOMEM;
- memset(pp->prd, 0, ATA_PRD_TBL_SZ * ATA_MAX_QUEUE);
ap->private_data = pp;
pp->sactive_block = ap->ioaddr.scr_addr + 4 * SCR_ACTIVE;
diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c
index 7ec0c216a6a6..865e5c58bd94 100644
--- a/drivers/ata/sata_qstor.c
+++ b/drivers/ata/sata_qstor.c
@@ -477,7 +477,6 @@ static int qs_port_start(struct ata_port *ap)
GFP_KERNEL);
if (!pp->pkt)
return -ENOMEM;
- memset(pp->pkt, 0, QS_PKT_BYTES);
ap->private_data = pp;
qs_enter_reg_mode(ap);
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index bfdf41912588..98aad8206921 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -1202,7 +1202,6 @@ static int sil24_port_start(struct ata_port *ap)
cb = dmam_alloc_coherent(dev, cb_size, &cb_dma, GFP_KERNEL);
if (!cb)
return -ENOMEM;
- memset(cb, 0, cb_size);
pp->cmd_block = cb;
pp->cmd_block_dma = cb_dma;
diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
index 43a14579e80e..df51680e8931 100644
--- a/drivers/atm/idt77252.c
+++ b/drivers/atm/idt77252.c
@@ -1379,7 +1379,6 @@ init_tsq(struct idt77252_dev *card)
printk("%s: can't allocate TSQ.\n", card->name);
return -1;
}
- memset(card->tsq.base, 0, TSQSIZE);
card->tsq.last = card->tsq.base + TSQ_NUM_ENTRIES - 1;
card->tsq.next = card->tsq.last;
diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig
index c52c738e554a..dd61fdd400f0 100644
--- a/drivers/auxdisplay/Kconfig
+++ b/drivers/auxdisplay/Kconfig
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
#
# For a description of the syntax of this configuration file,
-# see Documentation/kbuild/kconfig-language.txt.
+# see Documentation/kbuild/kconfig-language.rst.
#
# Auxiliary display drivers configuration.
#
diff --git a/drivers/auxdisplay/cfag12864bfb.c b/drivers/auxdisplay/cfag12864bfb.c
index 40c8a552a478..4074886b7bc8 100644
--- a/drivers/auxdisplay/cfag12864bfb.c
+++ b/drivers/auxdisplay/cfag12864bfb.c
@@ -52,8 +52,9 @@ static const struct fb_var_screeninfo cfag12864bfb_var = {
static int cfag12864bfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
{
- return vm_insert_page(vma, vma->vm_start,
- virt_to_page(cfag12864b_buffer));
+ struct page *pages = virt_to_page(cfag12864b_buffer);
+
+ return vm_map_pages_zero(vma, &pages, 1);
}
static struct fb_ops cfag12864bfb_ops = {
diff --git a/drivers/auxdisplay/ht16k33.c b/drivers/auxdisplay/ht16k33.c
index 21393ec3b9a4..9c0bb771751d 100644
--- a/drivers/auxdisplay/ht16k33.c
+++ b/drivers/auxdisplay/ht16k33.c
@@ -223,9 +223,9 @@ static const struct backlight_ops ht16k33_bl_ops = {
static int ht16k33_mmap(struct fb_info *info, struct vm_area_struct *vma)
{
struct ht16k33_priv *priv = info->par;
+ struct page *pages = virt_to_page(priv->fbdev.buffer);
- return vm_insert_page(vma, vma->vm_start,
- virt_to_page(priv->fbdev.buffer));
+ return vm_map_pages_zero(vma, &pages, 1);
}
static struct fb_ops ht16k33_fb_ops = {
diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
index 1739d7e1952a..63c1e76739f1 100644
--- a/drivers/base/arch_topology.c
+++ b/drivers/base/arch_topology.c
@@ -43,7 +43,7 @@ static ssize_t cpu_capacity_show(struct device *dev,
{
struct cpu *cpu = container_of(dev, struct cpu, dev);
- return sprintf(buf, "%lu\n", topology_get_cpu_scale(NULL, cpu->dev.id));
+ return sprintf(buf, "%lu\n", topology_get_cpu_scale(cpu->dev.id));
}
static void update_topology_flags_workfn(struct work_struct *work);
@@ -116,7 +116,7 @@ void topology_normalize_cpu_scale(void)
/ capacity_scale;
topology_set_cpu_scale(cpu, capacity);
pr_debug("cpu_capacity: CPU%d cpu_capacity=%lu\n",
- cpu, topology_get_cpu_scale(NULL, cpu));
+ cpu, topology_get_cpu_scale(cpu));
}
}
@@ -137,7 +137,6 @@ bool __init topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu)
sizeof(*raw_capacity),
GFP_KERNEL);
if (!raw_capacity) {
- pr_err("cpu_capacity: failed to allocate memory for raw capacities\n");
cap_parsing_failed = true;
return false;
}
@@ -185,7 +184,7 @@ init_cpu_capacity_callback(struct notifier_block *nb,
cpumask_andnot(cpus_to_visit, cpus_to_visit, policy->related_cpus);
for_each_cpu(cpu, policy->related_cpus) {
- raw_capacity[cpu] = topology_get_cpu_scale(NULL, cpu) *
+ raw_capacity[cpu] = topology_get_cpu_scale(cpu) *
policy->cpuinfo.max_freq / 1000UL;
capacity_scale = max(raw_capacity[cpu], capacity_scale);
}
@@ -217,10 +216,8 @@ static int __init register_cpufreq_notifier(void)
if (!acpi_disabled || !raw_capacity)
return -EINVAL;
- if (!alloc_cpumask_var(&cpus_to_visit, GFP_KERNEL)) {
- pr_err("cpu_capacity: failed to allocate memory for cpus_to_visit\n");
+ if (!alloc_cpumask_var(&cpus_to_visit, GFP_KERNEL))
return -ENOMEM;
- }
cpumask_copy(cpus_to_visit, cpu_possible_mask);
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 0a58e969f8b7..df3cac739813 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -323,8 +323,8 @@ EXPORT_SYMBOL_GPL(bus_for_each_dev);
* return to the caller and not iterate over any more devices.
*/
struct device *bus_find_device(struct bus_type *bus,
- struct device *start, void *data,
- int (*match)(struct device *dev, void *data))
+ struct device *start, const void *data,
+ int (*match)(struct device *dev, const void *data))
{
struct klist_iter i;
struct device *dev;
@@ -342,7 +342,7 @@ struct device *bus_find_device(struct bus_type *bus,
}
EXPORT_SYMBOL_GPL(bus_find_device);
-static int match_name(struct device *dev, void *data)
+static int match_name(struct device *dev, const void *data)
{
const char *name = data;
diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c
index a7359535caf5..8d553c92cd32 100644
--- a/drivers/base/cacheinfo.c
+++ b/drivers/base/cacheinfo.c
@@ -213,6 +213,8 @@ int __weak cache_setup_acpi(unsigned int cpu)
return -ENOTSUPP;
}
+unsigned int coherency_max_size;
+
static int cache_shared_cpu_map_setup(unsigned int cpu)
{
struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
@@ -251,6 +253,9 @@ static int cache_shared_cpu_map_setup(unsigned int cpu)
cpumask_set_cpu(i, &this_leaf->shared_cpu_map);
}
}
+ /* record the maximum cache line size */
+ if (this_leaf->coherency_line_size > coherency_max_size)
+ coherency_max_size = this_leaf->coherency_line_size;
}
return 0;
@@ -655,7 +660,8 @@ static int cacheinfo_cpu_pre_down(unsigned int cpu)
static int __init cacheinfo_sysfs_init(void)
{
- return cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "base/cacheinfo:online",
+ return cpuhp_setup_state(CPUHP_AP_BASE_CACHEINFO_ONLINE,
+ "base/cacheinfo:online",
cacheinfo_cpu_online, cacheinfo_cpu_pre_down);
}
device_initcall(cacheinfo_sysfs_init);
diff --git a/drivers/base/core.c b/drivers/base/core.c
index fd7511e04e62..da84a73f2ba6 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -2474,6 +2474,34 @@ struct device *device_find_child(struct device *parent, void *data,
}
EXPORT_SYMBOL_GPL(device_find_child);
+/**
+ * device_find_child_by_name - device iterator for locating a child device.
+ * @parent: parent struct device
+ * @name: name of the child device
+ *
+ * This is similar to the device_find_child() function above, but it
+ * returns a reference to a device that has the name @name.
+ *
+ * NOTE: you will need to drop the reference with put_device() after use.
+ */
+struct device *device_find_child_by_name(struct device *parent,
+ const char *name)
+{
+ struct klist_iter i;
+ struct device *child;
+
+ if (!parent)
+ return NULL;
+
+ klist_iter_init(&parent->p->klist_children, &i);
+ while ((child = next_device(&i)))
+ if (!strcmp(dev_name(child), name) && get_device(child))
+ break;
+ klist_iter_exit(&i);
+ return child;
+}
+EXPORT_SYMBOL_GPL(device_find_child_by_name);
+
int __init devices_init(void)
{
devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
@@ -3328,3 +3356,9 @@ void device_set_of_node_from_dev(struct device *dev, const struct device *dev2)
dev->of_node_reused = true;
}
EXPORT_SYMBOL_GPL(device_set_of_node_from_dev);
+
+int device_match_of_node(struct device *dev, const void *np)
+{
+ return dev->of_node == np;
+}
+EXPORT_SYMBOL_GPL(device_match_of_node);
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 0df9b4461766..994a90747420 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -235,6 +235,19 @@ static int __init deferred_probe_timeout_setup(char *str)
}
__setup("deferred_probe_timeout=", deferred_probe_timeout_setup);
+static int __driver_deferred_probe_check_state(struct device *dev)
+{
+ if (!initcalls_done)
+ return -EPROBE_DEFER;
+
+ if (!deferred_probe_timeout) {
+ dev_WARN(dev, "deferred probe timeout, ignoring dependency");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
/**
* driver_deferred_probe_check_state() - Check deferred probe state
* @dev: device to check
@@ -248,14 +261,40 @@ __setup("deferred_probe_timeout=", deferred_probe_timeout_setup);
*/
int driver_deferred_probe_check_state(struct device *dev)
{
- if (initcalls_done) {
- if (!deferred_probe_timeout) {
- dev_WARN(dev, "deferred probe timeout, ignoring dependency");
- return -ETIMEDOUT;
- }
- dev_warn(dev, "ignoring dependency for device, assuming no driver");
- return -ENODEV;
- }
+ int ret;
+
+ ret = __driver_deferred_probe_check_state(dev);
+ if (ret < 0)
+ return ret;
+
+ dev_warn(dev, "ignoring dependency for device, assuming no driver");
+
+ return -ENODEV;
+}
+
+/**
+ * driver_deferred_probe_check_state_continue() - check deferred probe state
+ * @dev: device to check
+ *
+ * Returns -ETIMEDOUT if deferred probe debug timeout has expired, or
+ * -EPROBE_DEFER otherwise.
+ *
+ * Drivers or subsystems can opt-in to calling this function instead of
+ * directly returning -EPROBE_DEFER.
+ *
+ * This is similar to driver_deferred_probe_check_state(), but it allows the
+ * subsystem to keep deferring probe after built-in drivers have had a chance
+ * to probe. One scenario where that is useful is if built-in drivers rely on
+ * resources that are provided by modular drivers.
+ */
+int driver_deferred_probe_check_state_continue(struct device *dev)
+{
+ int ret;
+
+ ret = __driver_deferred_probe_check_state(dev);
+ if (ret < 0)
+ return ret;
+
return -EPROBE_DEFER;
}
diff --git a/drivers/base/devcon.c b/drivers/base/devcon.c
index 04db9ae235e4..09f28479b243 100644
--- a/drivers/base/devcon.c
+++ b/drivers/base/devcon.c
@@ -38,6 +38,28 @@ fwnode_graph_devcon_match(struct fwnode_handle *fwnode, const char *con_id,
return NULL;
}
+static void *
+fwnode_devcon_match(struct fwnode_handle *fwnode, const char *con_id,
+ void *data, devcon_match_fn_t match)
+{
+ struct device_connection con = { };
+ void *ret;
+ int i;
+
+ for (i = 0; ; i++) {
+ con.fwnode = fwnode_find_reference(fwnode, con_id, i);
+ if (IS_ERR(con.fwnode))
+ break;
+
+ ret = match(&con, -1, data);
+ fwnode_handle_put(con.fwnode);
+ if (ret)
+ return ret;
+ }
+
+ return NULL;
+}
+
/**
* device_connection_find_match - Find physical connection to a device
* @dev: Device with the connection
@@ -65,6 +87,10 @@ void *device_connection_find_match(struct device *dev, const char *con_id,
ret = fwnode_graph_devcon_match(fwnode, con_id, data, match);
if (ret)
return ret;
+
+ ret = fwnode_devcon_match(fwnode, con_id, data, match);
+ if (ret)
+ return ret;
}
mutex_lock(&devcon_lock);
@@ -107,7 +133,7 @@ static struct bus_type *generic_match_buses[] = {
NULL,
};
-static int device_fwnode_match(struct device *dev, void *fwnode)
+static int device_fwnode_match(struct device *dev, const void *fwnode)
{
return dev_fwnode(dev) == fwnode;
}
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c
index 0dbc43068eeb..ba5c80903efe 100644
--- a/drivers/base/devtmpfs.c
+++ b/drivers/base/devtmpfs.c
@@ -357,8 +357,7 @@ int devtmpfs_mount(const char *mntdir)
if (!thread)
return 0;
- err = ksys_mount("devtmpfs", (char *)mntdir, "devtmpfs", MS_SILENT,
- NULL);
+ err = ksys_mount("devtmpfs", mntdir, "devtmpfs", MS_SILENT, NULL);
if (err)
printk(KERN_INFO "devtmpfs: error mounting %i\n", err);
else
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 857c8f1b876e..4e5ca632f35e 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -73,8 +73,8 @@ EXPORT_SYMBOL_GPL(driver_for_each_device);
* return to the caller and not iterate over any more devices.
*/
struct device *driver_find_device(struct device_driver *drv,
- struct device *start, void *data,
- int (*match)(struct device *dev, void *data))
+ struct device *start, const void *data,
+ int (*match)(struct device *dev, const void *data))
{
struct klist_iter i;
struct device *dev;
diff --git a/drivers/base/firmware_loader/Kconfig b/drivers/base/firmware_loader/Kconfig
index 38f2da6f5c2b..3f9e274e2ed3 100644
--- a/drivers/base/firmware_loader/Kconfig
+++ b/drivers/base/firmware_loader/Kconfig
@@ -26,6 +26,9 @@ config FW_LOADER
if FW_LOADER
+config FW_LOADER_PAGED_BUF
+ bool
+
config EXTRA_FIRMWARE
string "Build named firmware blobs into the kernel binary"
help
@@ -67,6 +70,7 @@ config EXTRA_FIRMWARE_DIR
config FW_LOADER_USER_HELPER
bool "Enable the firmware sysfs fallback mechanism"
+ select FW_LOADER_PAGED_BUF
help
This option enables a sysfs loading facility to enable firmware
loading to the kernel through userspace as a fallback mechanism
@@ -151,5 +155,19 @@ config FW_LOADER_USER_HELPER_FALLBACK
If you are unsure about this, say N here.
+config FW_LOADER_COMPRESS
+ bool "Enable compressed firmware support"
+ select FW_LOADER_PAGED_BUF
+ select XZ_DEC
+ help
+ This option enables the support for loading compressed firmware
+ files. The caller of firmware API receives the decompressed file
+ content. The compressed file is loaded as a fallback, only after
+ loading the raw file failed at first.
+
+ Currently only XZ-compressed files are supported, and they have to
+ be compressed with either none or crc32 integrity check type (pass
+ "-C crc32" option to xz command).
+
endif # FW_LOADER
endmenu
diff --git a/drivers/base/firmware_loader/fallback.c b/drivers/base/firmware_loader/fallback.c
index f962488546b6..62ee90b4db56 100644
--- a/drivers/base/firmware_loader/fallback.c
+++ b/drivers/base/firmware_loader/fallback.c
@@ -219,20 +219,6 @@ static ssize_t firmware_loading_show(struct device *dev,
return sprintf(buf, "%d\n", loading);
}
-/* one pages buffer should be mapped/unmapped only once */
-static int map_fw_priv_pages(struct fw_priv *fw_priv)
-{
- if (!fw_priv->is_paged_buf)
- return 0;
-
- vunmap(fw_priv->data);
- fw_priv->data = vmap(fw_priv->pages, fw_priv->nr_pages, 0,
- PAGE_KERNEL_RO);
- if (!fw_priv->data)
- return -ENOMEM;
- return 0;
-}
-
/**
* firmware_loading_store() - set value in the 'loading' control file
* @dev: device pointer
@@ -254,7 +240,6 @@ static ssize_t firmware_loading_store(struct device *dev,
struct fw_priv *fw_priv;
ssize_t written = count;
int loading = simple_strtol(buf, NULL, 10);
- int i;
mutex_lock(&fw_lock);
fw_priv = fw_sysfs->fw_priv;
@@ -265,12 +250,7 @@ static ssize_t firmware_loading_store(struct device *dev,
case 1:
/* discarding any previous partial load */
if (!fw_sysfs_done(fw_priv)) {
- for (i = 0; i < fw_priv->nr_pages; i++)
- __free_page(fw_priv->pages[i]);
- vfree(fw_priv->pages);
- fw_priv->pages = NULL;
- fw_priv->page_array_size = 0;
- fw_priv->nr_pages = 0;
+ fw_free_paged_buf(fw_priv);
fw_state_start(fw_priv);
}
break;
@@ -284,7 +264,7 @@ static ssize_t firmware_loading_store(struct device *dev,
* see the mapped 'buf->data' once the loading
* is completed.
* */
- rc = map_fw_priv_pages(fw_priv);
+ rc = fw_map_paged_buf(fw_priv);
if (rc)
dev_err(dev, "%s: map pages failed\n",
__func__);
@@ -389,40 +369,13 @@ out:
static int fw_realloc_pages(struct fw_sysfs *fw_sysfs, int min_size)
{
- struct fw_priv *fw_priv= fw_sysfs->fw_priv;
- int pages_needed = PAGE_ALIGN(min_size) >> PAGE_SHIFT;
-
- /* If the array of pages is too small, grow it... */
- if (fw_priv->page_array_size < pages_needed) {
- int new_array_size = max(pages_needed,
- fw_priv->page_array_size * 2);
- struct page **new_pages;
+ int err;
- new_pages = vmalloc(array_size(new_array_size, sizeof(void *)));
- if (!new_pages) {
- fw_load_abort(fw_sysfs);
- return -ENOMEM;
- }
- memcpy(new_pages, fw_priv->pages,
- fw_priv->page_array_size * sizeof(void *));
- memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) *
- (new_array_size - fw_priv->page_array_size));
- vfree(fw_priv->pages);
- fw_priv->pages = new_pages;
- fw_priv->page_array_size = new_array_size;
- }
-
- while (fw_priv->nr_pages < pages_needed) {
- fw_priv->pages[fw_priv->nr_pages] =
- alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
-
- if (!fw_priv->pages[fw_priv->nr_pages]) {
- fw_load_abort(fw_sysfs);
- return -ENOMEM;
- }
- fw_priv->nr_pages++;
- }
- return 0;
+ err = fw_grow_paged_buf(fw_sysfs->fw_priv,
+ PAGE_ALIGN(min_size) >> PAGE_SHIFT);
+ if (err)
+ fw_load_abort(fw_sysfs);
+ return err;
}
/**
@@ -659,7 +612,7 @@ static bool fw_run_sysfs_fallback(enum fw_opt opt_flags)
/* Also permit LSMs and IMA to fail firmware sysfs fallback */
ret = security_kernel_load_data(LOADING_FIRMWARE);
if (ret < 0)
- return ret;
+ return false;
return fw_force_sysfs_fallback(opt_flags);
}
diff --git a/drivers/base/firmware_loader/fallback_table.c b/drivers/base/firmware_loader/fallback_table.c
index 776dd69cf5be..ba9d30b28edc 100644
--- a/drivers/base/firmware_loader/fallback_table.c
+++ b/drivers/base/firmware_loader/fallback_table.c
@@ -16,9 +16,6 @@
* firmware fallback configuration table
*/
-static unsigned int zero;
-static unsigned int one = 1;
-
struct firmware_fallback_config fw_fallback_config = {
.force_sysfs_fallback = IS_ENABLED(CONFIG_FW_LOADER_USER_HELPER_FALLBACK),
.loading_timeout = 60,
@@ -26,6 +23,7 @@ struct firmware_fallback_config fw_fallback_config = {
};
EXPORT_SYMBOL_GPL(fw_fallback_config);
+#ifdef CONFIG_SYSCTL
struct ctl_table firmware_config_table[] = {
{
.procname = "force_sysfs_fallback",
@@ -33,8 +31,8 @@ struct ctl_table firmware_config_table[] = {
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = proc_douintvec_minmax,
- .extra1 = &zero,
- .extra2 = &one,
+ .extra1 = SYSCTL_ZERO,
+ .extra2 = SYSCTL_ONE,
},
{
.procname = "ignore_sysfs_fallback",
@@ -42,9 +40,10 @@ struct ctl_table firmware_config_table[] = {
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = proc_douintvec_minmax,
- .extra1 = &zero,
- .extra2 = &one,
+ .extra1 = SYSCTL_ZERO,
+ .extra2 = SYSCTL_ONE,
},
{ }
};
EXPORT_SYMBOL_GPL(firmware_config_table);
+#endif
diff --git a/drivers/base/firmware_loader/firmware.h b/drivers/base/firmware_loader/firmware.h
index 4c1395f8e7ed..7048a41973ed 100644
--- a/drivers/base/firmware_loader/firmware.h
+++ b/drivers/base/firmware_loader/firmware.h
@@ -64,12 +64,14 @@ struct fw_priv {
void *data;
size_t size;
size_t allocated_size;
-#ifdef CONFIG_FW_LOADER_USER_HELPER
+#ifdef CONFIG_FW_LOADER_PAGED_BUF
bool is_paged_buf;
- bool need_uevent;
struct page **pages;
int nr_pages;
int page_array_size;
+#endif
+#ifdef CONFIG_FW_LOADER_USER_HELPER
+ bool need_uevent;
struct list_head pending_list;
#endif
const char *fw_name;
@@ -133,4 +135,14 @@ static inline void fw_state_done(struct fw_priv *fw_priv)
int assign_fw(struct firmware *fw, struct device *device,
enum fw_opt opt_flags);
+#ifdef CONFIG_FW_LOADER_PAGED_BUF
+void fw_free_paged_buf(struct fw_priv *fw_priv);
+int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed);
+int fw_map_paged_buf(struct fw_priv *fw_priv);
+#else
+static inline void fw_free_paged_buf(struct fw_priv *fw_priv) {}
+int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed) { return -ENXIO; }
+int fw_map_paged_buf(struct fw_priv *fw_priv) { return -ENXIO; }
+#endif
+
#endif /* __FIRMWARE_LOADER_H */
diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c
index 7eaaf5ee5ba6..bf44c79beae9 100644
--- a/drivers/base/firmware_loader/main.c
+++ b/drivers/base/firmware_loader/main.c
@@ -33,6 +33,7 @@
#include <linux/syscore_ops.h>
#include <linux/reboot.h>
#include <linux/security.h>
+#include <linux/xz.h>
#include <generated/utsrelease.h>
@@ -251,15 +252,7 @@ static void __free_fw_priv(struct kref *ref)
list_del(&fw_priv->list);
spin_unlock(&fwc->lock);
-#ifdef CONFIG_FW_LOADER_USER_HELPER
- if (fw_priv->is_paged_buf) {
- int i;
- vunmap(fw_priv->data);
- for (i = 0; i < fw_priv->nr_pages; i++)
- __free_page(fw_priv->pages[i]);
- vfree(fw_priv->pages);
- } else
-#endif
+ fw_free_paged_buf(fw_priv); /* free leftover pages */
if (!fw_priv->allocated_size)
vfree(fw_priv->data);
kfree_const(fw_priv->fw_name);
@@ -274,6 +267,174 @@ static void free_fw_priv(struct fw_priv *fw_priv)
spin_unlock(&fwc->lock);
}
+#ifdef CONFIG_FW_LOADER_PAGED_BUF
+void fw_free_paged_buf(struct fw_priv *fw_priv)
+{
+ int i;
+
+ if (!fw_priv->pages)
+ return;
+
+ for (i = 0; i < fw_priv->nr_pages; i++)
+ __free_page(fw_priv->pages[i]);
+ kvfree(fw_priv->pages);
+ fw_priv->pages = NULL;
+ fw_priv->page_array_size = 0;
+ fw_priv->nr_pages = 0;
+}
+
+int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed)
+{
+ /* If the array of pages is too small, grow it */
+ if (fw_priv->page_array_size < pages_needed) {
+ int new_array_size = max(pages_needed,
+ fw_priv->page_array_size * 2);
+ struct page **new_pages;
+
+ new_pages = kvmalloc_array(new_array_size, sizeof(void *),
+ GFP_KERNEL);
+ if (!new_pages)
+ return -ENOMEM;
+ memcpy(new_pages, fw_priv->pages,
+ fw_priv->page_array_size * sizeof(void *));
+ memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) *
+ (new_array_size - fw_priv->page_array_size));
+ kvfree(fw_priv->pages);
+ fw_priv->pages = new_pages;
+ fw_priv->page_array_size = new_array_size;
+ }
+
+ while (fw_priv->nr_pages < pages_needed) {
+ fw_priv->pages[fw_priv->nr_pages] =
+ alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
+
+ if (!fw_priv->pages[fw_priv->nr_pages])
+ return -ENOMEM;
+ fw_priv->nr_pages++;
+ }
+
+ return 0;
+}
+
+int fw_map_paged_buf(struct fw_priv *fw_priv)
+{
+ /* one pages buffer should be mapped/unmapped only once */
+ if (!fw_priv->pages)
+ return 0;
+
+ vunmap(fw_priv->data);
+ fw_priv->data = vmap(fw_priv->pages, fw_priv->nr_pages, 0,
+ PAGE_KERNEL_RO);
+ if (!fw_priv->data)
+ return -ENOMEM;
+
+ /* page table is no longer needed after mapping, let's free */
+ kvfree(fw_priv->pages);
+ fw_priv->pages = NULL;
+
+ return 0;
+}
+#endif
+
+/*
+ * XZ-compressed firmware support
+ */
+#ifdef CONFIG_FW_LOADER_COMPRESS
+/* show an error and return the standard error code */
+static int fw_decompress_xz_error(struct device *dev, enum xz_ret xz_ret)
+{
+ if (xz_ret != XZ_STREAM_END) {
+ dev_warn(dev, "xz decompression failed (xz_ret=%d)\n", xz_ret);
+ return xz_ret == XZ_MEM_ERROR ? -ENOMEM : -EINVAL;
+ }
+ return 0;
+}
+
+/* single-shot decompression onto the pre-allocated buffer */
+static int fw_decompress_xz_single(struct device *dev, struct fw_priv *fw_priv,
+ size_t in_size, const void *in_buffer)
+{
+ struct xz_dec *xz_dec;
+ struct xz_buf xz_buf;
+ enum xz_ret xz_ret;
+
+ xz_dec = xz_dec_init(XZ_SINGLE, (u32)-1);
+ if (!xz_dec)
+ return -ENOMEM;
+
+ xz_buf.in_size = in_size;
+ xz_buf.in = in_buffer;
+ xz_buf.in_pos = 0;
+ xz_buf.out_size = fw_priv->allocated_size;
+ xz_buf.out = fw_priv->data;
+ xz_buf.out_pos = 0;
+
+ xz_ret = xz_dec_run(xz_dec, &xz_buf);
+ xz_dec_end(xz_dec);
+
+ fw_priv->size = xz_buf.out_pos;
+ return fw_decompress_xz_error(dev, xz_ret);
+}
+
+/* decompression on paged buffer and map it */
+static int fw_decompress_xz_pages(struct device *dev, struct fw_priv *fw_priv,
+ size_t in_size, const void *in_buffer)
+{
+ struct xz_dec *xz_dec;
+ struct xz_buf xz_buf;
+ enum xz_ret xz_ret;
+ struct page *page;
+ int err = 0;
+
+ xz_dec = xz_dec_init(XZ_DYNALLOC, (u32)-1);
+ if (!xz_dec)
+ return -ENOMEM;
+
+ xz_buf.in_size = in_size;
+ xz_buf.in = in_buffer;
+ xz_buf.in_pos = 0;
+
+ fw_priv->is_paged_buf = true;
+ fw_priv->size = 0;
+ do {
+ if (fw_grow_paged_buf(fw_priv, fw_priv->nr_pages + 1)) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ /* decompress onto the new allocated page */
+ page = fw_priv->pages[fw_priv->nr_pages - 1];
+ xz_buf.out = kmap(page);
+ xz_buf.out_pos = 0;
+ xz_buf.out_size = PAGE_SIZE;
+ xz_ret = xz_dec_run(xz_dec, &xz_buf);
+ kunmap(page);
+ fw_priv->size += xz_buf.out_pos;
+ /* partial decompression means either end or error */
+ if (xz_buf.out_pos != PAGE_SIZE)
+ break;
+ } while (xz_ret == XZ_OK);
+
+ err = fw_decompress_xz_error(dev, xz_ret);
+ if (!err)
+ err = fw_map_paged_buf(fw_priv);
+
+ out:
+ xz_dec_end(xz_dec);
+ return err;
+}
+
+static int fw_decompress_xz(struct device *dev, struct fw_priv *fw_priv,
+ size_t in_size, const void *in_buffer)
+{
+ /* if the buffer is pre-allocated, we can perform in single-shot mode */
+ if (fw_priv->data)
+ return fw_decompress_xz_single(dev, fw_priv, in_size, in_buffer);
+ else
+ return fw_decompress_xz_pages(dev, fw_priv, in_size, in_buffer);
+}
+#endif /* CONFIG_FW_LOADER_COMPRESS */
+
/* direct firmware loading support */
static char fw_path_para[256];
static const char * const fw_path[] = {
@@ -293,7 +454,12 @@ module_param_string(path, fw_path_para, sizeof(fw_path_para), 0644);
MODULE_PARM_DESC(path, "customized firmware image search path with a higher priority than default path");
static int
-fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv)
+fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv,
+ const char *suffix,
+ int (*decompress)(struct device *dev,
+ struct fw_priv *fw_priv,
+ size_t in_size,
+ const void *in_buffer))
{
loff_t size;
int i, len;
@@ -301,9 +467,11 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv)
char *path;
enum kernel_read_file_id id = READING_FIRMWARE;
size_t msize = INT_MAX;
+ void *buffer = NULL;
/* Already populated data member means we're loading into a buffer */
- if (fw_priv->data) {
+ if (!decompress && fw_priv->data) {
+ buffer = fw_priv->data;
id = READING_FIRMWARE_PREALLOC_BUFFER;
msize = fw_priv->allocated_size;
}
@@ -317,15 +485,15 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv)
if (!fw_path[i][0])
continue;
- len = snprintf(path, PATH_MAX, "%s/%s",
- fw_path[i], fw_priv->fw_name);
+ len = snprintf(path, PATH_MAX, "%s/%s%s",
+ fw_path[i], fw_priv->fw_name, suffix);
if (len >= PATH_MAX) {
rc = -ENAMETOOLONG;
break;
}
fw_priv->size = 0;
- rc = kernel_read_file_from_path(path, &fw_priv->data, &size,
+ rc = kernel_read_file_from_path(path, &buffer, &size,
msize, id);
if (rc) {
if (rc != -ENOENT)
@@ -336,8 +504,24 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv)
path);
continue;
}
- dev_dbg(device, "direct-loading %s\n", fw_priv->fw_name);
- fw_priv->size = size;
+ if (decompress) {
+ dev_dbg(device, "f/w decompressing %s\n",
+ fw_priv->fw_name);
+ rc = decompress(device, fw_priv, size, buffer);
+ /* discard the superfluous original content */
+ vfree(buffer);
+ buffer = NULL;
+ if (rc) {
+ fw_free_paged_buf(fw_priv);
+ continue;
+ }
+ } else {
+ dev_dbg(device, "direct-loading %s\n",
+ fw_priv->fw_name);
+ if (!fw_priv->data)
+ fw_priv->data = buffer;
+ fw_priv->size = size;
+ }
fw_state_done(fw_priv);
break;
}
@@ -584,7 +768,13 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
if (ret <= 0) /* error or already assigned */
goto out;
- ret = fw_get_filesystem_firmware(device, fw->priv);
+ ret = fw_get_filesystem_firmware(device, fw->priv, "", NULL);
+#ifdef CONFIG_FW_LOADER_COMPRESS
+ if (ret == -ENOENT)
+ ret = fw_get_filesystem_firmware(device, fw->priv, ".xz",
+ fw_decompress_xz);
+#endif
+
if (ret) {
if (!(opt_flags & FW_OPT_NO_WARN))
dev_warn(device,
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index f180427e48f4..20c39d1bcef8 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -34,11 +34,21 @@ static DEFINE_MUTEX(mem_sysfs_mutex);
static int sections_per_block;
-static inline int base_memory_block_id(int section_nr)
+static inline unsigned long base_memory_block_id(unsigned long section_nr)
{
return section_nr / sections_per_block;
}
+static inline unsigned long pfn_to_block_id(unsigned long pfn)
+{
+ return base_memory_block_id(pfn_to_section_nr(pfn));
+}
+
+static inline unsigned long phys_to_block_id(unsigned long phys)
+{
+ return pfn_to_block_id(PFN_DOWN(phys));
+}
+
static int memory_subsys_online(struct device *dev);
static int memory_subsys_offline(struct device *dev);
@@ -126,9 +136,9 @@ static ssize_t phys_index_show(struct device *dev,
static ssize_t removable_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
- unsigned long i, pfn;
- int ret = 1;
struct memory_block *mem = to_memory_block(dev);
+ unsigned long pfn;
+ int ret = 1, i;
if (mem->state != MEM_ONLINE)
goto out;
@@ -578,23 +588,13 @@ int __weak arch_get_memory_phys_device(unsigned long start_pfn)
return 0;
}
-/*
- * A reference for the returned object is held and the reference for the
- * hinted object is released.
- */
-struct memory_block *find_memory_block_hinted(struct mem_section *section,
- struct memory_block *hint)
+/* A reference for the returned memory block device is acquired. */
+static struct memory_block *find_memory_block_by_id(unsigned long block_id)
{
- int block_id = base_memory_block_id(__section_nr(section));
- struct device *hintdev = hint ? &hint->dev : NULL;
struct device *dev;
- dev = subsys_find_device_by_id(&memory_subsys, block_id, hintdev);
- if (hint)
- put_device(&hint->dev);
- if (!dev)
- return NULL;
- return to_memory_block(dev);
+ dev = subsys_find_device_by_id(&memory_subsys, block_id, NULL);
+ return dev ? to_memory_block(dev) : NULL;
}
/*
@@ -607,7 +607,9 @@ struct memory_block *find_memory_block_hinted(struct mem_section *section,
*/
struct memory_block *find_memory_block(struct mem_section *section)
{
- return find_memory_block_hinted(section, NULL);
+ unsigned long block_id = base_memory_block_id(__section_nr(section));
+
+ return find_memory_block_by_id(block_id);
}
static struct attribute *memory_memblk_attrs[] = {
@@ -652,20 +654,22 @@ int register_memory(struct memory_block *memory)
}
static int init_memory_block(struct memory_block **memory,
- struct mem_section *section, unsigned long state)
+ unsigned long block_id, unsigned long state)
{
struct memory_block *mem;
unsigned long start_pfn;
- int scn_nr;
int ret = 0;
+ mem = find_memory_block_by_id(block_id);
+ if (mem) {
+ put_device(&mem->dev);
+ return -EEXIST;
+ }
mem = kzalloc(sizeof(*mem), GFP_KERNEL);
if (!mem)
return -ENOMEM;
- scn_nr = __section_nr(section);
- mem->start_section_nr =
- base_memory_block_id(scn_nr) * sections_per_block;
+ mem->start_section_nr = block_id * sections_per_block;
mem->end_section_nr = mem->start_section_nr + sections_per_block - 1;
mem->state = state;
start_pfn = section_nr_to_pfn(mem->start_section_nr);
@@ -677,97 +681,101 @@ static int init_memory_block(struct memory_block **memory,
return ret;
}
-static int add_memory_block(int base_section_nr)
+static int add_memory_block(unsigned long base_section_nr)
{
+ int ret, section_count = 0;
struct memory_block *mem;
- int i, ret, section_count = 0, section_nr;
+ unsigned long nr;
- for (i = base_section_nr;
- i < base_section_nr + sections_per_block;
- i++) {
- if (!present_section_nr(i))
- continue;
- if (section_count == 0)
- section_nr = i;
- section_count++;
- }
+ for (nr = base_section_nr; nr < base_section_nr + sections_per_block;
+ nr++)
+ if (present_section_nr(nr))
+ section_count++;
if (section_count == 0)
return 0;
- ret = init_memory_block(&mem, __nr_to_section(section_nr), MEM_ONLINE);
+ ret = init_memory_block(&mem, base_memory_block_id(base_section_nr),
+ MEM_ONLINE);
if (ret)
return ret;
mem->section_count = section_count;
return 0;
}
+static void unregister_memory(struct memory_block *memory)
+{
+ if (WARN_ON_ONCE(memory->dev.bus != &memory_subsys))
+ return;
+
+ /* drop the ref. we got via find_memory_block() */
+ put_device(&memory->dev);
+ device_unregister(&memory->dev);
+}
+
/*
- * need an interface for the VM to add new memory regions,
- * but without onlining it.
+ * Create memory block devices for the given memory area. Start and size
+ * have to be aligned to memory block granularity. Memory block devices
+ * will be initialized as offline.
*/
-int hotplug_memory_register(int nid, struct mem_section *section)
+int create_memory_block_devices(unsigned long start, unsigned long size)
{
- int ret = 0;
+ const unsigned long start_block_id = pfn_to_block_id(PFN_DOWN(start));
+ unsigned long end_block_id = pfn_to_block_id(PFN_DOWN(start + size));
struct memory_block *mem;
+ unsigned long block_id;
+ int ret = 0;
- mutex_lock(&mem_sysfs_mutex);
+ if (WARN_ON_ONCE(!IS_ALIGNED(start, memory_block_size_bytes()) ||
+ !IS_ALIGNED(size, memory_block_size_bytes())))
+ return -EINVAL;
- mem = find_memory_block(section);
- if (mem) {
- mem->section_count++;
- put_device(&mem->dev);
- } else {
- ret = init_memory_block(&mem, section, MEM_OFFLINE);
+ mutex_lock(&mem_sysfs_mutex);
+ for (block_id = start_block_id; block_id != end_block_id; block_id++) {
+ ret = init_memory_block(&mem, block_id, MEM_OFFLINE);
if (ret)
- goto out;
- mem->section_count++;
+ break;
+ mem->section_count = sections_per_block;
+ }
+ if (ret) {
+ end_block_id = block_id;
+ for (block_id = start_block_id; block_id != end_block_id;
+ block_id++) {
+ mem = find_memory_block_by_id(block_id);
+ mem->section_count = 0;
+ unregister_memory(mem);
+ }
}
-
-out:
mutex_unlock(&mem_sysfs_mutex);
return ret;
}
-#ifdef CONFIG_MEMORY_HOTREMOVE
-static void
-unregister_memory(struct memory_block *memory)
-{
- BUG_ON(memory->dev.bus != &memory_subsys);
-
- /* drop the ref. we got via find_memory_block() */
- put_device(&memory->dev);
- device_unregister(&memory->dev);
-}
-
-void unregister_memory_section(struct mem_section *section)
+/*
+ * Remove memory block devices for the given memory area. Start and size
+ * have to be aligned to memory block granularity. Memory block devices
+ * have to be offline.
+ */
+void remove_memory_block_devices(unsigned long start, unsigned long size)
{
+ const unsigned long start_block_id = pfn_to_block_id(PFN_DOWN(start));
+ const unsigned long end_block_id = pfn_to_block_id(PFN_DOWN(start + size));
struct memory_block *mem;
+ unsigned long block_id;
- if (WARN_ON_ONCE(!present_section(section)))
+ if (WARN_ON_ONCE(!IS_ALIGNED(start, memory_block_size_bytes()) ||
+ !IS_ALIGNED(size, memory_block_size_bytes())))
return;
mutex_lock(&mem_sysfs_mutex);
-
- /*
- * Some users of the memory hotplug do not want/need memblock to
- * track all sections. Skip over those.
- */
- mem = find_memory_block(section);
- if (!mem)
- goto out_unlock;
-
- unregister_mem_sect_under_nodes(mem, __section_nr(section));
-
- mem->section_count--;
- if (mem->section_count == 0)
+ for (block_id = start_block_id; block_id != end_block_id; block_id++) {
+ mem = find_memory_block_by_id(block_id);
+ if (WARN_ON_ONCE(!mem))
+ continue;
+ mem->section_count = 0;
+ unregister_memory_block_under_nodes(mem);
unregister_memory(mem);
- else
- put_device(&mem->dev);
-
-out_unlock:
+ }
mutex_unlock(&mem_sysfs_mutex);
}
-#endif /* CONFIG_MEMORY_HOTREMOVE */
/* return true if the memory block is offlined, otherwise, return false */
bool is_memblock_offlined(struct memory_block *mem)
@@ -804,10 +812,9 @@ static const struct attribute_group *memory_root_attr_groups[] = {
*/
int __init memory_dev_init(void)
{
- unsigned int i;
int ret;
int err;
- unsigned long block_sz;
+ unsigned long block_sz, nr;
ret = subsys_system_register(&memory_subsys, memory_root_attr_groups);
if (ret)
@@ -821,9 +828,9 @@ int __init memory_dev_init(void)
* during boot and have been initialized
*/
mutex_lock(&mem_sysfs_mutex);
- for (i = 0; i <= __highest_present_section_nr;
- i += sections_per_block) {
- err = add_memory_block(i);
+ for (nr = 0; nr <= __highest_present_section_nr;
+ nr += sections_per_block) {
+ err = add_memory_block(nr);
if (!ret)
ret = err;
}
@@ -834,3 +841,43 @@ out:
printk(KERN_ERR "%s() failed: %d\n", __func__, ret);
return ret;
}
+
+/**
+ * walk_memory_blocks - walk through all present memory blocks overlapped
+ * by the range [start, start + size)
+ *
+ * @start: start address of the memory range
+ * @size: size of the memory range
+ * @arg: argument passed to func
+ * @func: callback for each memory section walked
+ *
+ * This function walks through all present memory blocks overlapped by the
+ * range [start, start + size), calling func on each memory block.
+ *
+ * In case func() returns an error, walking is aborted and the error is
+ * returned.
+ */
+int walk_memory_blocks(unsigned long start, unsigned long size,
+ void *arg, walk_memory_blocks_func_t func)
+{
+ const unsigned long start_block_id = phys_to_block_id(start);
+ const unsigned long end_block_id = phys_to_block_id(start + size - 1);
+ struct memory_block *mem;
+ unsigned long block_id;
+ int ret = 0;
+
+ if (!size)
+ return 0;
+
+ for (block_id = start_block_id; block_id <= end_block_id; block_id++) {
+ mem = find_memory_block_by_id(block_id);
+ if (!mem)
+ continue;
+
+ ret = func(mem, arg);
+ put_device(&mem->dev);
+ if (ret)
+ break;
+ }
+ return ret;
+}
diff --git a/drivers/base/node.c b/drivers/base/node.c
index 8598fcbd2a17..75b7e6f6535b 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -66,6 +66,7 @@ static DEVICE_ATTR(cpulist, S_IRUGO, node_read_cpulist, NULL);
* @dev: Device for this memory access class
* @list_node: List element in the node's access list
* @access: The access class rank
+ * @hmem_attrs: Heterogeneous memory performance attributes
*/
struct node_access_nodes {
struct device dev;
@@ -673,8 +674,8 @@ int register_cpu_under_node(unsigned int cpu, unsigned int nid)
/**
* register_memory_node_under_compute_node - link memory node to its compute
* node for a given access class.
- * @mem_node: Memory node number
- * @cpu_node: Cpu node number
+ * @mem_nid: Memory node number
+ * @cpu_nid: Cpu node number
* @access: Access class to register
*
* Description:
@@ -752,7 +753,8 @@ static int __ref get_nid_for_pfn(unsigned long pfn)
}
/* register memory section under specified node if it spans that node */
-int register_mem_sect_under_node(struct memory_block *mem_blk, void *arg)
+static int register_mem_sect_under_node(struct memory_block *mem_blk,
+ void *arg)
{
int ret, nid = *(int *)arg;
unsigned long pfn, sect_start_pfn, sect_end_pfn;
@@ -801,23 +803,18 @@ int register_mem_sect_under_node(struct memory_block *mem_blk, void *arg)
return 0;
}
-/* unregister memory section under all nodes that it spans */
-int unregister_mem_sect_under_nodes(struct memory_block *mem_blk,
- unsigned long phys_index)
+/*
+ * Unregister memory block device under all nodes that it spans.
+ * Has to be called with mem_sysfs_mutex held (due to unlinked_nodes).
+ */
+void unregister_memory_block_under_nodes(struct memory_block *mem_blk)
{
- NODEMASK_ALLOC(nodemask_t, unlinked_nodes, GFP_KERNEL);
unsigned long pfn, sect_start_pfn, sect_end_pfn;
+ static nodemask_t unlinked_nodes;
- if (!mem_blk) {
- NODEMASK_FREE(unlinked_nodes);
- return -EFAULT;
- }
- if (!unlinked_nodes)
- return -ENOMEM;
- nodes_clear(*unlinked_nodes);
-
- sect_start_pfn = section_nr_to_pfn(phys_index);
- sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1;
+ nodes_clear(unlinked_nodes);
+ sect_start_pfn = section_nr_to_pfn(mem_blk->start_section_nr);
+ sect_end_pfn = section_nr_to_pfn(mem_blk->end_section_nr);
for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) {
int nid;
@@ -826,21 +823,20 @@ int unregister_mem_sect_under_nodes(struct memory_block *mem_blk,
continue;
if (!node_online(nid))
continue;
- if (node_test_and_set(nid, *unlinked_nodes))
+ if (node_test_and_set(nid, unlinked_nodes))
continue;
sysfs_remove_link(&node_devices[nid]->dev.kobj,
kobject_name(&mem_blk->dev.kobj));
sysfs_remove_link(&mem_blk->dev.kobj,
kobject_name(&node_devices[nid]->dev.kobj));
}
- NODEMASK_FREE(unlinked_nodes);
- return 0;
}
int link_mem_sections(int nid, unsigned long start_pfn, unsigned long end_pfn)
{
- return walk_memory_range(start_pfn, end_pfn, (void *)&nid,
- register_mem_sect_under_node);
+ return walk_memory_blocks(PFN_PHYS(start_pfn),
+ PFN_PHYS(end_pfn - start_pfn), (void *)&nid,
+ register_mem_sect_under_node);
}
#ifdef CONFIG_HUGETLBFS
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 4d1729853d1a..506a0175a5a7 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -5,7 +5,7 @@
* Copyright (c) 2002-3 Patrick Mochel
* Copyright (c) 2002-3 Open Source Development Labs
*
- * Please see Documentation/driver-model/platform.txt for more
+ * Please see Documentation/driver-api/driver-model/platform.rst for more
* information.
*/
diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c
index 59d19dd64928..ced6863a16a5 100644
--- a/drivers/base/power/clock_ops.c
+++ b/drivers/base/power/clock_ops.c
@@ -12,6 +12,7 @@
#include <linux/pm_clock.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
+#include <linux/of_clk.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/pm_domain.h>
@@ -92,8 +93,6 @@ static int __pm_clk_add(struct device *dev, const char *con_id,
if (con_id) {
ce->con_id = kstrdup(con_id, GFP_KERNEL);
if (!ce->con_id) {
- dev_err(dev,
- "Not enough memory for clock connection ID.\n");
kfree(ce);
return -ENOMEM;
}
@@ -195,8 +194,7 @@ int of_pm_clk_add_clks(struct device *dev)
if (!dev || !dev->of_node)
return -EINVAL;
- count = of_count_phandle_with_args(dev->of_node, "clocks",
- "#clock-cells");
+ count = of_clk_get_parent_count(dev->of_node);
if (count <= 0)
return -ENODEV;
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 33c30c1e6a30..b063bc41b0a9 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -1536,7 +1536,8 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
if (ret)
genpd_free_dev_data(dev, gpd_data);
else
- dev_pm_qos_add_notifier(dev, &gpd_data->nb);
+ dev_pm_qos_add_notifier(dev, &gpd_data->nb,
+ DEV_PM_QOS_RESUME_LATENCY);
return ret;
}
@@ -1569,7 +1570,8 @@ static int genpd_remove_device(struct generic_pm_domain *genpd,
pdd = dev->power.subsys_data->domain_data;
gpd_data = to_gpd_data(pdd);
- dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
+ dev_pm_qos_remove_notifier(dev, &gpd_data->nb,
+ DEV_PM_QOS_RESUME_LATENCY);
genpd_lock(genpd);
@@ -1597,7 +1599,7 @@ static int genpd_remove_device(struct generic_pm_domain *genpd,
out:
genpd_unlock(genpd);
- dev_pm_qos_add_notifier(dev, &gpd_data->nb);
+ dev_pm_qos_add_notifier(dev, &gpd_data->nb, DEV_PM_QOS_RESUME_LATENCY);
return ret;
}
diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c
index 3838045c9277..daa8c7689f7e 100644
--- a/drivers/base/power/domain_governor.c
+++ b/drivers/base/power/domain_governor.c
@@ -33,7 +33,7 @@ static int dev_update_qos_constraint(struct device *dev, void *data)
* take its current PM QoS constraint (that's the only thing
* known at this point anyway).
*/
- constraint_ns = dev_pm_qos_read_value(dev);
+ constraint_ns = dev_pm_qos_read_value(dev, DEV_PM_QOS_RESUME_LATENCY);
constraint_ns *= NSEC_PER_USEC;
}
@@ -66,7 +66,7 @@ static bool default_suspend_ok(struct device *dev)
td->constraint_changed = false;
td->cached_suspend_ok = false;
td->effective_constraint_ns = 0;
- constraint_ns = __dev_pm_qos_read_value(dev);
+ constraint_ns = __dev_pm_qos_resume_latency(dev);
spin_unlock_irqrestore(&dev->power.lock, flags);
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index dcfc0a36c8f7..7fb2c39bc725 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -530,21 +530,6 @@ static void dpm_watchdog_clear(struct dpm_watchdog *wd)
/*------------------------- Resume routines -------------------------*/
/**
- * dev_pm_skip_next_resume_phases - Skip next system resume phases for device.
- * @dev: Target device.
- *
- * Make the core skip the "early resume" and "resume" phases for @dev.
- *
- * This function can be called by middle-layer code during the "noirq" phase of
- * system resume if necessary, but not by device drivers.
- */
-void dev_pm_skip_next_resume_phases(struct device *dev)
-{
- dev->power.is_late_suspended = false;
- dev->power.is_suspended = false;
-}
-
-/**
* suspend_event - Return a "suspend" message for given "resume" one.
* @resume_msg: PM message representing a system-wide resume transition.
*/
@@ -681,6 +666,9 @@ Skip:
dev->power.is_noirq_suspended = false;
if (skip_resume) {
+ /* Make the next phases of resume skip the device. */
+ dev->power.is_late_suspended = false;
+ dev->power.is_suspended = false;
/*
* The device is going to be left in suspend, but it might not
* have been in runtime suspend before the system suspended, so
@@ -689,7 +677,6 @@ Skip:
* device again.
*/
pm_runtime_set_suspended(dev);
- dev_pm_skip_next_resume_phases(dev);
}
Out:
@@ -1631,17 +1618,20 @@ int dpm_suspend_late(pm_message_t state)
*/
int dpm_suspend_end(pm_message_t state)
{
- int error = dpm_suspend_late(state);
+ ktime_t starttime = ktime_get();
+ int error;
+
+ error = dpm_suspend_late(state);
if (error)
- return error;
+ goto out;
error = dpm_suspend_noirq(state);
- if (error) {
+ if (error)
dpm_resume_early(resume_event(state));
- return error;
- }
- return 0;
+out:
+ dpm_show_time(starttime, state, error, "end");
+ return error;
}
EXPORT_SYMBOL_GPL(dpm_suspend_end);
@@ -2034,6 +2024,7 @@ int dpm_prepare(pm_message_t state)
*/
int dpm_suspend_start(pm_message_t state)
{
+ ktime_t starttime = ktime_get();
int error;
error = dpm_prepare(state);
@@ -2042,6 +2033,7 @@ int dpm_suspend_start(pm_message_t state)
dpm_save_failed_step(SUSPEND_PREPARE);
} else
error = dpm_suspend(state);
+ dpm_show_time(starttime, state, error, "start");
return error;
}
EXPORT_SYMBOL_GPL(dpm_suspend_start);
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
index 6c91f8df1d59..6c90fd7e2ff8 100644
--- a/drivers/base/power/qos.c
+++ b/drivers/base/power/qos.c
@@ -90,29 +90,49 @@ enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev, s32 mask)
EXPORT_SYMBOL_GPL(dev_pm_qos_flags);
/**
- * __dev_pm_qos_read_value - Get PM QoS constraint for a given device.
+ * __dev_pm_qos_resume_latency - Get resume latency constraint for a given device.
* @dev: Device to get the PM QoS constraint value for.
*
* This routine must be called with dev->power.lock held.
*/
-s32 __dev_pm_qos_read_value(struct device *dev)
+s32 __dev_pm_qos_resume_latency(struct device *dev)
{
lockdep_assert_held(&dev->power.lock);
- return dev_pm_qos_raw_read_value(dev);
+ return dev_pm_qos_raw_resume_latency(dev);
}
/**
* dev_pm_qos_read_value - Get PM QoS constraint for a given device (locked).
* @dev: Device to get the PM QoS constraint value for.
+ * @type: QoS request type.
*/
-s32 dev_pm_qos_read_value(struct device *dev)
+s32 dev_pm_qos_read_value(struct device *dev, enum dev_pm_qos_req_type type)
{
+ struct dev_pm_qos *qos = dev->power.qos;
unsigned long flags;
s32 ret;
spin_lock_irqsave(&dev->power.lock, flags);
- ret = __dev_pm_qos_read_value(dev);
+
+ switch (type) {
+ case DEV_PM_QOS_RESUME_LATENCY:
+ ret = IS_ERR_OR_NULL(qos) ? PM_QOS_RESUME_LATENCY_NO_CONSTRAINT
+ : pm_qos_read_value(&qos->resume_latency);
+ break;
+ case DEV_PM_QOS_MIN_FREQUENCY:
+ ret = IS_ERR_OR_NULL(qos) ? PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE
+ : pm_qos_read_value(&qos->min_frequency);
+ break;
+ case DEV_PM_QOS_MAX_FREQUENCY:
+ ret = IS_ERR_OR_NULL(qos) ? PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE
+ : pm_qos_read_value(&qos->max_frequency);
+ break;
+ default:
+ WARN_ON(1);
+ ret = 0;
+ }
+
spin_unlock_irqrestore(&dev->power.lock, flags);
return ret;
@@ -149,6 +169,14 @@ static int apply_constraint(struct dev_pm_qos_request *req,
req->dev->power.set_latency_tolerance(req->dev, value);
}
break;
+ case DEV_PM_QOS_MIN_FREQUENCY:
+ ret = pm_qos_update_target(&qos->min_frequency,
+ &req->data.pnode, action, value);
+ break;
+ case DEV_PM_QOS_MAX_FREQUENCY:
+ ret = pm_qos_update_target(&qos->max_frequency,
+ &req->data.pnode, action, value);
+ break;
case DEV_PM_QOS_FLAGS:
ret = pm_qos_update_flags(&qos->flags, &req->data.flr,
action, value);
@@ -177,12 +205,11 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
if (!qos)
return -ENOMEM;
- n = kzalloc(sizeof(*n), GFP_KERNEL);
+ n = kzalloc(3 * sizeof(*n), GFP_KERNEL);
if (!n) {
kfree(qos);
return -ENOMEM;
}
- BLOCKING_INIT_NOTIFIER_HEAD(n);
c = &qos->resume_latency;
plist_head_init(&c->list);
@@ -191,6 +218,7 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
c->no_constraint_value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
c->type = PM_QOS_MIN;
c->notifiers = n;
+ BLOCKING_INIT_NOTIFIER_HEAD(n);
c = &qos->latency_tolerance;
plist_head_init(&c->list);
@@ -199,6 +227,24 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
c->no_constraint_value = PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT;
c->type = PM_QOS_MIN;
+ c = &qos->min_frequency;
+ plist_head_init(&c->list);
+ c->target_value = PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE;
+ c->default_value = PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE;
+ c->no_constraint_value = PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE;
+ c->type = PM_QOS_MAX;
+ c->notifiers = ++n;
+ BLOCKING_INIT_NOTIFIER_HEAD(n);
+
+ c = &qos->max_frequency;
+ plist_head_init(&c->list);
+ c->target_value = PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE;
+ c->default_value = PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE;
+ c->no_constraint_value = PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE;
+ c->type = PM_QOS_MIN;
+ c->notifiers = ++n;
+ BLOCKING_INIT_NOTIFIER_HEAD(n);
+
INIT_LIST_HEAD(&qos->flags.list);
spin_lock_irq(&dev->power.lock);
@@ -252,11 +298,25 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
memset(req, 0, sizeof(*req));
}
+
c = &qos->latency_tolerance;
plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) {
apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
memset(req, 0, sizeof(*req));
}
+
+ c = &qos->min_frequency;
+ plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) {
+ apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE);
+ memset(req, 0, sizeof(*req));
+ }
+
+ c = &qos->max_frequency;
+ plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) {
+ apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE);
+ memset(req, 0, sizeof(*req));
+ }
+
f = &qos->flags;
list_for_each_entry_safe(req, tmp, &f->list, data.flr.node) {
apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
@@ -368,6 +428,8 @@ static int __dev_pm_qos_update_request(struct dev_pm_qos_request *req,
switch(req->type) {
case DEV_PM_QOS_RESUME_LATENCY:
case DEV_PM_QOS_LATENCY_TOLERANCE:
+ case DEV_PM_QOS_MIN_FREQUENCY:
+ case DEV_PM_QOS_MAX_FREQUENCY:
curr_value = req->data.pnode.prio;
break;
case DEV_PM_QOS_FLAGS:
@@ -467,6 +529,7 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_remove_request);
*
* @dev: target device for the constraint
* @notifier: notifier block managed by caller.
+ * @type: request type.
*
* Will register the notifier into a notification chain that gets called
* upon changes to the target value for the device.
@@ -474,7 +537,8 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_remove_request);
* If the device's constraints object doesn't exist when this routine is called,
* it will be created (or error code will be returned if that fails).
*/
-int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)
+int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier,
+ enum dev_pm_qos_req_type type)
{
int ret = 0;
@@ -485,10 +549,28 @@ int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)
else if (!dev->power.qos)
ret = dev_pm_qos_constraints_allocate(dev);
- if (!ret)
+ if (ret)
+ goto unlock;
+
+ switch (type) {
+ case DEV_PM_QOS_RESUME_LATENCY:
ret = blocking_notifier_chain_register(dev->power.qos->resume_latency.notifiers,
notifier);
+ break;
+ case DEV_PM_QOS_MIN_FREQUENCY:
+ ret = blocking_notifier_chain_register(dev->power.qos->min_frequency.notifiers,
+ notifier);
+ break;
+ case DEV_PM_QOS_MAX_FREQUENCY:
+ ret = blocking_notifier_chain_register(dev->power.qos->max_frequency.notifiers,
+ notifier);
+ break;
+ default:
+ WARN_ON(1);
+ ret = -EINVAL;
+ }
+unlock:
mutex_unlock(&dev_pm_qos_mtx);
return ret;
}
@@ -500,24 +582,44 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_add_notifier);
*
* @dev: target device for the constraint
* @notifier: notifier block to be removed.
+ * @type: request type.
*
* Will remove the notifier from the notification chain that gets called
* upon changes to the target value.
*/
int dev_pm_qos_remove_notifier(struct device *dev,
- struct notifier_block *notifier)
+ struct notifier_block *notifier,
+ enum dev_pm_qos_req_type type)
{
- int retval = 0;
+ int ret = 0;
mutex_lock(&dev_pm_qos_mtx);
/* Silently return if the constraints object is not present. */
- if (!IS_ERR_OR_NULL(dev->power.qos))
- retval = blocking_notifier_chain_unregister(dev->power.qos->resume_latency.notifiers,
- notifier);
+ if (IS_ERR_OR_NULL(dev->power.qos))
+ goto unlock;
+
+ switch (type) {
+ case DEV_PM_QOS_RESUME_LATENCY:
+ ret = blocking_notifier_chain_unregister(dev->power.qos->resume_latency.notifiers,
+ notifier);
+ break;
+ case DEV_PM_QOS_MIN_FREQUENCY:
+ ret = blocking_notifier_chain_unregister(dev->power.qos->min_frequency.notifiers,
+ notifier);
+ break;
+ case DEV_PM_QOS_MAX_FREQUENCY:
+ ret = blocking_notifier_chain_unregister(dev->power.qos->max_frequency.notifiers,
+ notifier);
+ break;
+ default:
+ WARN_ON(1);
+ ret = -EINVAL;
+ }
+unlock:
mutex_unlock(&dev_pm_qos_mtx);
- return retval;
+ return ret;
}
EXPORT_SYMBOL_GPL(dev_pm_qos_remove_notifier);
@@ -577,6 +679,9 @@ static void __dev_pm_qos_drop_user_request(struct device *dev,
req = dev->power.qos->flags_req;
dev->power.qos->flags_req = NULL;
break;
+ default:
+ WARN_ON(1);
+ return;
}
__dev_pm_qos_remove_request(req);
kfree(req);
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 952a1e7057c7..b75335508d2c 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -275,7 +275,7 @@ static int rpm_check_suspend_allowed(struct device *dev)
|| (dev->power.request_pending
&& dev->power.request == RPM_REQ_RESUME))
retval = -EAGAIN;
- else if (__dev_pm_qos_read_value(dev) == 0)
+ else if (__dev_pm_qos_resume_latency(dev) == 0)
retval = -EPERM;
else if (dev->power.runtime_status == RPM_SUSPENDED)
retval = 1;
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index 5b2b6a05a4f3..ee31d4f8d856 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -968,8 +968,6 @@ void pm_wakep_autosleep_enabled(bool set)
}
#endif /* CONFIG_PM_AUTOSLEEP */
-static struct dentry *wakeup_sources_stats_dentry;
-
/**
* print_wakeup_source_stats - Print wakeup source statistics information.
* @m: seq_file to print the statistics into.
@@ -1099,8 +1097,8 @@ static const struct file_operations wakeup_sources_stats_fops = {
static int __init wakeup_sources_debugfs_init(void)
{
- wakeup_sources_stats_dentry = debugfs_create_file("wakeup_sources",
- S_IRUGO, NULL, NULL, &wakeup_sources_stats_fops);
+ debugfs_create_file("wakeup_sources", S_IRUGO, NULL, NULL,
+ &wakeup_sources_stats_fops);
return 0;
}
diff --git a/drivers/base/property.c b/drivers/base/property.c
index 348b37e64944..81bd01ed4042 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -485,6 +485,30 @@ int fwnode_property_get_reference_args(const struct fwnode_handle *fwnode,
EXPORT_SYMBOL_GPL(fwnode_property_get_reference_args);
/**
+ * fwnode_find_reference - Find named reference to a fwnode_handle
+ * @fwnode: Firmware node where to look for the reference
+ * @name: The name of the reference
+ * @index: Index of the reference
+ *
+ * @index can be used when the named reference holds a table of references.
+ *
+ * Returns pointer to the reference fwnode, or ERR_PTR. Caller is responsible to
+ * call fwnode_handle_put() on the returned fwnode pointer.
+ */
+struct fwnode_handle *fwnode_find_reference(const struct fwnode_handle *fwnode,
+ const char *name,
+ unsigned int index)
+{
+ struct fwnode_reference_args args;
+ int ret;
+
+ ret = fwnode_property_get_reference_args(fwnode, name, NULL, 0, index,
+ &args);
+ return ret ? ERR_PTR(ret) : args.fwnode;
+}
+EXPORT_SYMBOL_GPL(fwnode_find_reference);
+
+/**
* device_remove_properties - Remove properties from a device object.
* @dev: Device whose properties to remove.
*
diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig
index 6ad5ef48b61e..a4984136c19d 100644
--- a/drivers/base/regmap/Kconfig
+++ b/drivers/base/regmap/Kconfig
@@ -4,7 +4,7 @@
# subsystems should select the appropriate symbols.
config REGMAP
- default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ)
+ default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SCCB || REGMAP_I3C)
select IRQ_DOMAIN if REGMAP_IRQ
bool
@@ -49,3 +49,7 @@ config REGMAP_SOUNDWIRE
config REGMAP_SCCB
tristate
depends on I2C
+
+config REGMAP_I3C
+ tristate
+ depends on I3C
diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile
index f5b4e8851d00..ff6c7d8ec1cd 100644
--- a/drivers/base/regmap/Makefile
+++ b/drivers/base/regmap/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o
obj-$(CONFIG_REGMAP_W1) += regmap-w1.o
obj-$(CONFIG_REGMAP_SOUNDWIRE) += regmap-sdw.o
obj-$(CONFIG_REGMAP_SCCB) += regmap-sccb.o
+obj-$(CONFIG_REGMAP_I3C) += regmap-i3c.o
diff --git a/drivers/base/regmap/regcache-lzo.c b/drivers/base/regmap/regcache-lzo.c
index fc14e8b9344f..7886303eb026 100644
--- a/drivers/base/regmap/regcache-lzo.c
+++ b/drivers/base/regmap/regcache-lzo.c
@@ -148,20 +148,18 @@ static int regcache_lzo_init(struct regmap *map)
* that register.
*/
bmp_size = map->num_reg_defaults_raw;
- sync_bmp = kmalloc_array(BITS_TO_LONGS(bmp_size), sizeof(long),
- GFP_KERNEL);
+ sync_bmp = bitmap_zalloc(bmp_size, GFP_KERNEL);
if (!sync_bmp) {
ret = -ENOMEM;
goto err;
}
- bitmap_zero(sync_bmp, bmp_size);
/* allocate the lzo blocks and initialize them */
for (i = 0; i < blkcount; i++) {
lzo_blocks[i] = kzalloc(sizeof **lzo_blocks,
GFP_KERNEL);
if (!lzo_blocks[i]) {
- kfree(sync_bmp);
+ bitmap_free(sync_bmp);
ret = -ENOMEM;
goto err;
}
@@ -213,7 +211,7 @@ static int regcache_lzo_exit(struct regmap *map)
* only once.
*/
if (lzo_blocks[0])
- kfree(lzo_blocks[0]->sync_bmp);
+ bitmap_free(lzo_blocks[0]->sync_bmp);
for (i = 0; i < blkcount; i++) {
if (lzo_blocks[i]) {
kfree(lzo_blocks[i]->wmem);
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
index 263f82516ff4..e5e1b3a01b1a 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -579,6 +579,8 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
}
if (!strcmp(name, "dummy")) {
+ kfree(map->debugfs_name);
+
map->debugfs_name = kasprintf(GFP_KERNEL, "dummy%d",
dummy_index);
name = map->debugfs_name;
diff --git a/drivers/base/regmap/regmap-i3c.c b/drivers/base/regmap/regmap-i3c.c
new file mode 100644
index 000000000000..1578fb506683
--- /dev/null
+++ b/drivers/base/regmap/regmap-i3c.c
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018 Synopsys, Inc. and/or its affiliates.
+
+#include <linux/regmap.h>
+#include <linux/i3c/device.h>
+#include <linux/i3c/master.h>
+#include <linux/module.h>
+
+static int regmap_i3c_write(void *context, const void *data, size_t count)
+{
+ struct device *dev = context;
+ struct i3c_device *i3c = dev_to_i3cdev(dev);
+ struct i3c_priv_xfer xfers[] = {
+ {
+ .rnw = false,
+ .len = count,
+ .data.out = data,
+ },
+ };
+
+ return i3c_device_do_priv_xfers(i3c, xfers, 1);
+}
+
+static int regmap_i3c_read(void *context,
+ const void *reg, size_t reg_size,
+ void *val, size_t val_size)
+{
+ struct device *dev = context;
+ struct i3c_device *i3c = dev_to_i3cdev(dev);
+ struct i3c_priv_xfer xfers[2];
+
+ xfers[0].rnw = false;
+ xfers[0].len = reg_size;
+ xfers[0].data.out = reg;
+
+ xfers[1].rnw = true;
+ xfers[1].len = val_size;
+ xfers[1].data.in = val;
+
+ return i3c_device_do_priv_xfers(i3c, xfers, 2);
+}
+
+static struct regmap_bus regmap_i3c = {
+ .write = regmap_i3c_write,
+ .read = regmap_i3c_read,
+};
+
+struct regmap *__devm_regmap_init_i3c(struct i3c_device *i3c,
+ const struct regmap_config *config,
+ struct lock_class_key *lock_key,
+ const char *lock_name)
+{
+ return __devm_regmap_init(&i3c->dev, &regmap_i3c, &i3c->dev, config,
+ lock_key, lock_name);
+}
+EXPORT_SYMBOL_GPL(__devm_regmap_init_i3c);
+
+MODULE_AUTHOR("Vitor Soares <vitor.soares@synopsys.com>");
+MODULE_DESCRIPTION("Regmap I3C Module");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index f1025452bb39..19f57ccfbe1d 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -1637,6 +1637,8 @@ static int _regmap_raw_write_impl(struct regmap *map, unsigned int reg,
map->format.reg_bytes +
map->format.pad_bytes,
val, val_len);
+ else
+ ret = -ENOTSUPP;
/* If that didn't work fall back on linearising by hand. */
if (ret == -ENOTSUPP) {
diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c
index 7fc5a18e02ad..e7b3aa3bd55a 100644
--- a/drivers/base/swnode.c
+++ b/drivers/base/swnode.c
@@ -11,25 +11,25 @@
#include <linux/property.h>
#include <linux/slab.h>
-struct software_node {
+struct swnode {
int id;
struct kobject kobj;
struct fwnode_handle fwnode;
+ const struct software_node *node;
/* hierarchy */
struct ida child_ids;
struct list_head entry;
struct list_head children;
- struct software_node *parent;
+ struct swnode *parent;
- /* properties */
- const struct property_entry *properties;
+ unsigned int allocated:1;
};
static DEFINE_IDA(swnode_root_ids);
static struct kset *swnode_kset;
-#define kobj_to_swnode(_kobj_) container_of(_kobj_, struct software_node, kobj)
+#define kobj_to_swnode(_kobj_) container_of(_kobj_, struct swnode, kobj)
static const struct fwnode_operations software_node_ops;
@@ -37,17 +37,56 @@ bool is_software_node(const struct fwnode_handle *fwnode)
{
return !IS_ERR_OR_NULL(fwnode) && fwnode->ops == &software_node_ops;
}
+EXPORT_SYMBOL_GPL(is_software_node);
-#define to_software_node(__fwnode) \
+#define to_swnode(__fwnode) \
({ \
- typeof(__fwnode) __to_software_node_fwnode = __fwnode; \
+ typeof(__fwnode) __to_swnode_fwnode = __fwnode; \
\
- is_software_node(__to_software_node_fwnode) ? \
- container_of(__to_software_node_fwnode, \
- struct software_node, fwnode) : \
- NULL; \
+ is_software_node(__to_swnode_fwnode) ? \
+ container_of(__to_swnode_fwnode, \
+ struct swnode, fwnode) : NULL; \
})
+static struct swnode *
+software_node_to_swnode(const struct software_node *node)
+{
+ struct swnode *swnode;
+ struct kobject *k;
+
+ if (!node)
+ return NULL;
+
+ spin_lock(&swnode_kset->list_lock);
+
+ list_for_each_entry(k, &swnode_kset->list, entry) {
+ swnode = kobj_to_swnode(k);
+ if (swnode->node == node)
+ break;
+ swnode = NULL;
+ }
+
+ spin_unlock(&swnode_kset->list_lock);
+
+ return swnode;
+}
+
+const struct software_node *to_software_node(struct fwnode_handle *fwnode)
+{
+ struct swnode *swnode = to_swnode(fwnode);
+
+ return swnode ? swnode->node : NULL;
+}
+EXPORT_SYMBOL_GPL(to_software_node);
+
+struct fwnode_handle *software_node_fwnode(const struct software_node *node)
+{
+ struct swnode *swnode = software_node_to_swnode(node);
+
+ return swnode ? &swnode->fwnode : NULL;
+}
+EXPORT_SYMBOL_GPL(software_node_fwnode);
+
/* -------------------------------------------------------------------------- */
/* property_entry processing */
@@ -383,6 +422,9 @@ property_entries_dup(const struct property_entry *properties)
int i, n = 0;
int ret;
+ if (!properties)
+ return NULL;
+
while (properties[n].name)
n++;
@@ -430,7 +472,7 @@ EXPORT_SYMBOL_GPL(property_entries_free);
static struct fwnode_handle *software_node_get(struct fwnode_handle *fwnode)
{
- struct software_node *swnode = to_software_node(fwnode);
+ struct swnode *swnode = to_swnode(fwnode);
kobject_get(&swnode->kobj);
@@ -439,7 +481,7 @@ static struct fwnode_handle *software_node_get(struct fwnode_handle *fwnode)
static void software_node_put(struct fwnode_handle *fwnode)
{
- struct software_node *swnode = to_software_node(fwnode);
+ struct swnode *swnode = to_swnode(fwnode);
kobject_put(&swnode->kobj);
}
@@ -447,8 +489,9 @@ static void software_node_put(struct fwnode_handle *fwnode)
static bool software_node_property_present(const struct fwnode_handle *fwnode,
const char *propname)
{
- return !!property_entry_get(to_software_node(fwnode)->properties,
- propname);
+ struct swnode *swnode = to_swnode(fwnode);
+
+ return !!property_entry_get(swnode->node->properties, propname);
}
static int software_node_read_int_array(const struct fwnode_handle *fwnode,
@@ -456,9 +499,9 @@ static int software_node_read_int_array(const struct fwnode_handle *fwnode,
unsigned int elem_size, void *val,
size_t nval)
{
- struct software_node *swnode = to_software_node(fwnode);
+ struct swnode *swnode = to_swnode(fwnode);
- return property_entry_read_int_array(swnode->properties, propname,
+ return property_entry_read_int_array(swnode->node->properties, propname,
elem_size, val, nval);
}
@@ -466,27 +509,26 @@ static int software_node_read_string_array(const struct fwnode_handle *fwnode,
const char *propname,
const char **val, size_t nval)
{
- struct software_node *swnode = to_software_node(fwnode);
+ struct swnode *swnode = to_swnode(fwnode);
- return property_entry_read_string_array(swnode->properties, propname,
- val, nval);
+ return property_entry_read_string_array(swnode->node->properties,
+ propname, val, nval);
}
static struct fwnode_handle *
software_node_get_parent(const struct fwnode_handle *fwnode)
{
- struct software_node *swnode = to_software_node(fwnode);
+ struct swnode *swnode = to_swnode(fwnode);
- return swnode ? (swnode->parent ? &swnode->parent->fwnode : NULL) :
- NULL;
+ return swnode ? (swnode->parent ? &swnode->parent->fwnode : NULL) : NULL;
}
static struct fwnode_handle *
software_node_get_next_child(const struct fwnode_handle *fwnode,
struct fwnode_handle *child)
{
- struct software_node *p = to_software_node(fwnode);
- struct software_node *c = to_software_node(child);
+ struct swnode *p = to_swnode(fwnode);
+ struct swnode *c = to_swnode(child);
if (!p || list_empty(&p->children) ||
(c && list_is_last(&c->entry, &p->children)))
@@ -495,7 +537,7 @@ software_node_get_next_child(const struct fwnode_handle *fwnode,
if (c)
c = list_next_entry(c, entry);
else
- c = list_first_entry(&p->children, struct software_node, entry);
+ c = list_first_entry(&p->children, struct swnode, entry);
return &c->fwnode;
}
@@ -503,18 +545,14 @@ static struct fwnode_handle *
software_node_get_named_child_node(const struct fwnode_handle *fwnode,
const char *childname)
{
- struct software_node *swnode = to_software_node(fwnode);
- const struct property_entry *prop;
- struct software_node *child;
+ struct swnode *swnode = to_swnode(fwnode);
+ struct swnode *child;
if (!swnode || list_empty(&swnode->children))
return NULL;
list_for_each_entry(child, &swnode->children, entry) {
- prop = property_entry_get(child->properties, "name");
- if (!prop)
- continue;
- if (!strcmp(childname, prop->value.str)) {
+ if (!strcmp(childname, kobject_name(&child->kobj))) {
kobject_get(&child->kobj);
return &child->fwnode;
}
@@ -522,6 +560,52 @@ software_node_get_named_child_node(const struct fwnode_handle *fwnode,
return NULL;
}
+static int
+software_node_get_reference_args(const struct fwnode_handle *fwnode,
+ const char *propname, const char *nargs_prop,
+ unsigned int nargs, unsigned int index,
+ struct fwnode_reference_args *args)
+{
+ struct swnode *swnode = to_swnode(fwnode);
+ const struct software_node_reference *ref;
+ const struct property_entry *prop;
+ struct fwnode_handle *refnode;
+ int i;
+
+ if (!swnode || !swnode->node->references)
+ return -ENOENT;
+
+ for (ref = swnode->node->references; ref->name; ref++)
+ if (!strcmp(ref->name, propname))
+ break;
+
+ if (!ref->name || index > (ref->nrefs - 1))
+ return -ENOENT;
+
+ refnode = software_node_fwnode(ref->refs[index].node);
+ if (!refnode)
+ return -ENOENT;
+
+ if (nargs_prop) {
+ prop = property_entry_get(swnode->node->properties, nargs_prop);
+ if (!prop)
+ return -EINVAL;
+
+ nargs = prop->value.u32_data;
+ }
+
+ if (nargs > NR_FWNODE_REFERENCE_ARGS)
+ return -EINVAL;
+
+ args->fwnode = software_node_get(refnode);
+ args->nargs = nargs;
+
+ for (i = 0; i < nargs; i++)
+ args->args[i] = ref->refs[index].args[i];
+
+ return 0;
+}
+
static const struct fwnode_operations software_node_ops = {
.get = software_node_get,
.put = software_node_put,
@@ -531,12 +615,13 @@ static const struct fwnode_operations software_node_ops = {
.get_parent = software_node_get_parent,
.get_next_child_node = software_node_get_next_child,
.get_named_child_node = software_node_get_named_child_node,
+ .get_reference_args = software_node_get_reference_args
};
/* -------------------------------------------------------------------------- */
static int
-software_node_register_properties(struct software_node *swnode,
+software_node_register_properties(struct software_node *node,
const struct property_entry *properties)
{
struct property_entry *props;
@@ -545,24 +630,20 @@ software_node_register_properties(struct software_node *swnode,
if (IS_ERR(props))
return PTR_ERR(props);
- swnode->properties = props;
+ node->properties = props;
return 0;
}
static void software_node_release(struct kobject *kobj)
{
- struct software_node *swnode = kobj_to_swnode(kobj);
+ struct swnode *swnode = kobj_to_swnode(kobj);
- if (swnode->parent) {
- ida_simple_remove(&swnode->parent->child_ids, swnode->id);
- list_del(&swnode->entry);
- } else {
- ida_simple_remove(&swnode_root_ids, swnode->id);
+ if (swnode->allocated) {
+ property_entries_free(swnode->node->properties);
+ kfree(swnode->node);
}
-
ida_destroy(&swnode->child_ids);
- property_entries_free(swnode->properties);
kfree(swnode);
}
@@ -571,70 +652,165 @@ static struct kobj_type software_node_type = {
.sysfs_ops = &kobj_sysfs_ops,
};
-struct fwnode_handle *
-fwnode_create_software_node(const struct property_entry *properties,
- const struct fwnode_handle *parent)
+static struct fwnode_handle *
+swnode_register(const struct software_node *node, struct swnode *parent,
+ unsigned int allocated)
{
- struct software_node *p = NULL;
- struct software_node *swnode;
+ struct swnode *swnode;
int ret;
- if (parent) {
- if (IS_ERR(parent))
- return ERR_CAST(parent);
- if (!is_software_node(parent))
- return ERR_PTR(-EINVAL);
- p = to_software_node(parent);
- }
-
swnode = kzalloc(sizeof(*swnode), GFP_KERNEL);
- if (!swnode)
- return ERR_PTR(-ENOMEM);
+ if (!swnode) {
+ ret = -ENOMEM;
+ goto out_err;
+ }
- ret = ida_simple_get(p ? &p->child_ids : &swnode_root_ids, 0, 0,
- GFP_KERNEL);
+ ret = ida_simple_get(parent ? &parent->child_ids : &swnode_root_ids,
+ 0, 0, GFP_KERNEL);
if (ret < 0) {
kfree(swnode);
- return ERR_PTR(ret);
+ goto out_err;
}
swnode->id = ret;
+ swnode->node = node;
+ swnode->parent = parent;
+ swnode->allocated = allocated;
swnode->kobj.kset = swnode_kset;
swnode->fwnode.ops = &software_node_ops;
ida_init(&swnode->child_ids);
INIT_LIST_HEAD(&swnode->entry);
INIT_LIST_HEAD(&swnode->children);
- swnode->parent = p;
-
- if (p)
- list_add_tail(&swnode->entry, &p->children);
- ret = kobject_init_and_add(&swnode->kobj, &software_node_type,
- p ? &p->kobj : NULL, "node%d", swnode->id);
+ if (node->name)
+ ret = kobject_init_and_add(&swnode->kobj, &software_node_type,
+ parent ? &parent->kobj : NULL,
+ "%s", node->name);
+ else
+ ret = kobject_init_and_add(&swnode->kobj, &software_node_type,
+ parent ? &parent->kobj : NULL,
+ "node%d", swnode->id);
if (ret) {
kobject_put(&swnode->kobj);
return ERR_PTR(ret);
}
- ret = software_node_register_properties(swnode, properties);
+ if (parent)
+ list_add_tail(&swnode->entry, &parent->children);
+
+ kobject_uevent(&swnode->kobj, KOBJ_ADD);
+ return &swnode->fwnode;
+
+out_err:
+ if (allocated)
+ property_entries_free(node->properties);
+ return ERR_PTR(ret);
+}
+
+/**
+ * software_node_register_nodes - Register an array of software nodes
+ * @nodes: Zero terminated array of software nodes to be registered
+ *
+ * Register multiple software nodes at once.
+ */
+int software_node_register_nodes(const struct software_node *nodes)
+{
+ int ret;
+ int i;
+
+ for (i = 0; nodes[i].name; i++) {
+ ret = software_node_register(&nodes[i]);
+ if (ret) {
+ software_node_unregister_nodes(nodes);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(software_node_register_nodes);
+
+/**
+ * software_node_unregister_nodes - Unregister an array of software nodes
+ * @nodes: Zero terminated array of software nodes to be unregistered
+ *
+ * Unregister multiple software nodes at once.
+ */
+void software_node_unregister_nodes(const struct software_node *nodes)
+{
+ struct swnode *swnode;
+ int i;
+
+ for (i = 0; nodes[i].name; i++) {
+ swnode = software_node_to_swnode(&nodes[i]);
+ if (swnode)
+ fwnode_remove_software_node(&swnode->fwnode);
+ }
+}
+EXPORT_SYMBOL_GPL(software_node_unregister_nodes);
+
+/**
+ * software_node_register - Register static software node
+ * @node: The software node to be registered
+ */
+int software_node_register(const struct software_node *node)
+{
+ struct swnode *parent = software_node_to_swnode(node->parent);
+
+ if (software_node_to_swnode(node))
+ return -EEXIST;
+
+ return PTR_ERR_OR_ZERO(swnode_register(node, parent, 0));
+}
+EXPORT_SYMBOL_GPL(software_node_register);
+
+struct fwnode_handle *
+fwnode_create_software_node(const struct property_entry *properties,
+ const struct fwnode_handle *parent)
+{
+ struct software_node *node;
+ struct swnode *p = NULL;
+ int ret;
+
+ if (parent) {
+ if (IS_ERR(parent))
+ return ERR_CAST(parent);
+ if (!is_software_node(parent))
+ return ERR_PTR(-EINVAL);
+ p = to_swnode(parent);
+ }
+
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
+ if (!node)
+ return ERR_PTR(-ENOMEM);
+
+ ret = software_node_register_properties(node, properties);
if (ret) {
- kobject_put(&swnode->kobj);
+ kfree(node);
return ERR_PTR(ret);
}
- kobject_uevent(&swnode->kobj, KOBJ_ADD);
- return &swnode->fwnode;
+ node->parent = p ? p->node : NULL;
+
+ return swnode_register(node, p, 1);
}
EXPORT_SYMBOL_GPL(fwnode_create_software_node);
void fwnode_remove_software_node(struct fwnode_handle *fwnode)
{
- struct software_node *swnode = to_software_node(fwnode);
+ struct swnode *swnode = to_swnode(fwnode);
if (!swnode)
return;
+ if (swnode->parent) {
+ ida_simple_remove(&swnode->parent->child_ids, swnode->id);
+ list_del(&swnode->entry);
+ } else {
+ ida_simple_remove(&swnode_root_ids, swnode->id);
+ }
+
kobject_put(&swnode->kobj);
}
EXPORT_SYMBOL_GPL(fwnode_remove_software_node);
@@ -642,7 +818,7 @@ EXPORT_SYMBOL_GPL(fwnode_remove_software_node);
int software_node_notify(struct device *dev, unsigned long action)
{
struct fwnode_handle *fwnode = dev_fwnode(dev);
- struct software_node *swnode;
+ struct swnode *swnode;
int ret;
if (!fwnode)
@@ -653,7 +829,7 @@ int software_node_notify(struct device *dev, unsigned long action)
if (!is_software_node(fwnode))
return 0;
- swnode = to_software_node(fwnode);
+ swnode = to_swnode(fwnode);
switch (action) {
case KOBJ_ADD:
diff --git a/drivers/base/topology.c b/drivers/base/topology.c
index 5fd9f167ecc1..4e033d4cc0dc 100644
--- a/drivers/base/topology.c
+++ b/drivers/base/topology.c
@@ -43,6 +43,9 @@ static ssize_t name##_list_show(struct device *dev, \
define_id_show_func(physical_package_id);
static DEVICE_ATTR_RO(physical_package_id);
+define_id_show_func(die_id);
+static DEVICE_ATTR_RO(die_id);
+
define_id_show_func(core_id);
static DEVICE_ATTR_RO(core_id);
@@ -50,10 +53,22 @@ define_siblings_show_func(thread_siblings, sibling_cpumask);
static DEVICE_ATTR_RO(thread_siblings);
static DEVICE_ATTR_RO(thread_siblings_list);
+define_siblings_show_func(core_cpus, sibling_cpumask);
+static DEVICE_ATTR_RO(core_cpus);
+static DEVICE_ATTR_RO(core_cpus_list);
+
define_siblings_show_func(core_siblings, core_cpumask);
static DEVICE_ATTR_RO(core_siblings);
static DEVICE_ATTR_RO(core_siblings_list);
+define_siblings_show_func(die_cpus, die_cpumask);
+static DEVICE_ATTR_RO(die_cpus);
+static DEVICE_ATTR_RO(die_cpus_list);
+
+define_siblings_show_func(package_cpus, core_cpumask);
+static DEVICE_ATTR_RO(package_cpus);
+static DEVICE_ATTR_RO(package_cpus_list);
+
#ifdef CONFIG_SCHED_BOOK
define_id_show_func(book_id);
static DEVICE_ATTR_RO(book_id);
@@ -72,11 +87,18 @@ static DEVICE_ATTR_RO(drawer_siblings_list);
static struct attribute *default_attrs[] = {
&dev_attr_physical_package_id.attr,
+ &dev_attr_die_id.attr,
&dev_attr_core_id.attr,
&dev_attr_thread_siblings.attr,
&dev_attr_thread_siblings_list.attr,
+ &dev_attr_core_cpus.attr,
+ &dev_attr_core_cpus_list.attr,
&dev_attr_core_siblings.attr,
&dev_attr_core_siblings_list.attr,
+ &dev_attr_die_cpus.attr,
+ &dev_attr_die_cpus_list.attr,
+ &dev_attr_package_cpus.attr,
+ &dev_attr_package_cpus_list.attr,
#ifdef CONFIG_SCHED_BOOK
&dev_attr_book_id.attr,
&dev_attr_book_siblings.attr,
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 20bb4bfa4be6..1bb8ec575352 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -31,7 +31,7 @@ config BLK_DEV_FD
If you want to use the floppy disk drive(s) of your PC under Linux,
say Y. Information about this driver, especially important for IBM
Thinkpad users, is contained in
- <file:Documentation/blockdev/floppy.txt>.
+ <file:Documentation/admin-guide/blockdev/floppy.rst>.
That file also contains the location of the Floppy driver FAQ as
well as location of the fdutils package used to configure additional
parameters of the driver at run time.
@@ -96,7 +96,7 @@ config PARIDE
your computer's parallel port. Most of them are actually IDE devices
using a parallel port IDE adapter. This option enables the PARIDE
subsystem which contains drivers for many of these external drives.
- Read <file:Documentation/blockdev/paride.txt> for more information.
+ Read <file:Documentation/admin-guide/blockdev/paride.rst> for more information.
If you have said Y to the "Parallel-port support" configuration
option, you may share a single port between your printer and other
@@ -261,7 +261,7 @@ config BLK_DEV_NBD
userland (making server and client physically the same computer,
communicating using the loopback network device).
- Read <file:Documentation/blockdev/nbd.txt> for more information,
+ Read <file:Documentation/admin-guide/blockdev/nbd.rst> for more information,
especially about where to find the server code, which runs in user
space and does not need special kernel support.
@@ -303,7 +303,7 @@ config BLK_DEV_RAM
during the initial install of Linux.
Note that the kernel command line option "ramdisk=XX" is now obsolete.
- For details, read <file:Documentation/blockdev/ramdisk.txt>.
+ For details, read <file:Documentation/admin-guide/blockdev/ramdisk.rst>.
To compile this driver as a module, choose M here: the
module will be called brd. An alias "rd" has been defined
@@ -347,7 +347,7 @@ config CDROM_PKTCDVD
is possible.
DVD-RW disks must be in restricted overwrite mode.
- See the file <file:Documentation/cdrom/packet-writing.txt>
+ See the file <file:Documentation/cdrom/packet-writing.rst>
for further information on the use of this driver.
To compile this driver as a module, choose M here: the
diff --git a/drivers/block/drbd/drbd_debugfs.c b/drivers/block/drbd/drbd_debugfs.c
index f13b48ff5f43..b3b9cd5628fd 100644
--- a/drivers/block/drbd/drbd_debugfs.c
+++ b/drivers/block/drbd/drbd_debugfs.c
@@ -465,35 +465,20 @@ static const struct file_operations in_flight_summary_fops = {
void drbd_debugfs_resource_add(struct drbd_resource *resource)
{
struct dentry *dentry;
- if (!drbd_debugfs_resources)
- return;
dentry = debugfs_create_dir(resource->name, drbd_debugfs_resources);
- if (IS_ERR_OR_NULL(dentry))
- goto fail;
resource->debugfs_res = dentry;
dentry = debugfs_create_dir("volumes", resource->debugfs_res);
- if (IS_ERR_OR_NULL(dentry))
- goto fail;
resource->debugfs_res_volumes = dentry;
dentry = debugfs_create_dir("connections", resource->debugfs_res);
- if (IS_ERR_OR_NULL(dentry))
- goto fail;
resource->debugfs_res_connections = dentry;
dentry = debugfs_create_file("in_flight_summary", 0440,
resource->debugfs_res, resource,
&in_flight_summary_fops);
- if (IS_ERR_OR_NULL(dentry))
- goto fail;
resource->debugfs_res_in_flight_summary = dentry;
- return;
-
-fail:
- drbd_debugfs_resource_cleanup(resource);
- drbd_err(resource, "failed to create debugfs dentry\n");
}
static void drbd_debugfs_remove(struct dentry **dp)
@@ -636,35 +621,22 @@ void drbd_debugfs_connection_add(struct drbd_connection *connection)
{
struct dentry *conns_dir = connection->resource->debugfs_res_connections;
struct dentry *dentry;
- if (!conns_dir)
- return;
/* Once we enable mutliple peers,
* these connections will have descriptive names.
* For now, it is just the one connection to the (only) "peer". */
dentry = debugfs_create_dir("peer", conns_dir);
- if (IS_ERR_OR_NULL(dentry))
- goto fail;
connection->debugfs_conn = dentry;
dentry = debugfs_create_file("callback_history", 0440,
connection->debugfs_conn, connection,
&connection_callback_history_fops);
- if (IS_ERR_OR_NULL(dentry))
- goto fail;
connection->debugfs_conn_callback_history = dentry;
dentry = debugfs_create_file("oldest_requests", 0440,
connection->debugfs_conn, connection,
&connection_oldest_requests_fops);
- if (IS_ERR_OR_NULL(dentry))
- goto fail;
connection->debugfs_conn_oldest_requests = dentry;
- return;
-
-fail:
- drbd_debugfs_connection_cleanup(connection);
- drbd_err(connection, "failed to create debugfs dentry\n");
}
void drbd_debugfs_connection_cleanup(struct drbd_connection *connection)
@@ -809,8 +781,6 @@ void drbd_debugfs_device_add(struct drbd_device *device)
snprintf(vnr_buf, sizeof(vnr_buf), "%u", device->vnr);
dentry = debugfs_create_dir(vnr_buf, vols_dir);
- if (IS_ERR_OR_NULL(dentry))
- goto fail;
device->debugfs_vol = dentry;
snprintf(minor_buf, sizeof(minor_buf), "%u", device->minor);
@@ -819,18 +789,14 @@ void drbd_debugfs_device_add(struct drbd_device *device)
if (!slink_name)
goto fail;
dentry = debugfs_create_symlink(minor_buf, drbd_debugfs_minors, slink_name);
+ device->debugfs_minor = dentry;
kfree(slink_name);
slink_name = NULL;
- if (IS_ERR_OR_NULL(dentry))
- goto fail;
- device->debugfs_minor = dentry;
#define DCF(name) do { \
dentry = debugfs_create_file(#name, 0440, \
device->debugfs_vol, device, \
&device_ ## name ## _fops); \
- if (IS_ERR_OR_NULL(dentry)) \
- goto fail; \
device->debugfs_vol_ ## name = dentry; \
} while (0)
@@ -864,19 +830,9 @@ void drbd_debugfs_peer_device_add(struct drbd_peer_device *peer_device)
struct dentry *dentry;
char vnr_buf[8];
- if (!conn_dir)
- return;
-
snprintf(vnr_buf, sizeof(vnr_buf), "%u", peer_device->device->vnr);
dentry = debugfs_create_dir(vnr_buf, conn_dir);
- if (IS_ERR_OR_NULL(dentry))
- goto fail;
peer_device->debugfs_peer_dev = dentry;
- return;
-
-fail:
- drbd_debugfs_peer_device_cleanup(peer_device);
- drbd_err(peer_device, "failed to create debugfs entries\n");
}
void drbd_debugfs_peer_device_cleanup(struct drbd_peer_device *peer_device)
@@ -917,35 +873,19 @@ void drbd_debugfs_cleanup(void)
drbd_debugfs_remove(&drbd_debugfs_root);
}
-int __init drbd_debugfs_init(void)
+void __init drbd_debugfs_init(void)
{
struct dentry *dentry;
dentry = debugfs_create_dir("drbd", NULL);
- if (IS_ERR_OR_NULL(dentry))
- goto fail;
drbd_debugfs_root = dentry;
dentry = debugfs_create_file("version", 0444, drbd_debugfs_root, NULL, &drbd_version_fops);
- if (IS_ERR_OR_NULL(dentry))
- goto fail;
drbd_debugfs_version = dentry;
dentry = debugfs_create_dir("resources", drbd_debugfs_root);
- if (IS_ERR_OR_NULL(dentry))
- goto fail;
drbd_debugfs_resources = dentry;
dentry = debugfs_create_dir("minors", drbd_debugfs_root);
- if (IS_ERR_OR_NULL(dentry))
- goto fail;
drbd_debugfs_minors = dentry;
- return 0;
-
-fail:
- drbd_debugfs_cleanup();
- if (dentry)
- return PTR_ERR(dentry);
- else
- return -EINVAL;
}
diff --git a/drivers/block/drbd/drbd_debugfs.h b/drivers/block/drbd/drbd_debugfs.h
index 4ecfbb3358d7..58e31cef0844 100644
--- a/drivers/block/drbd/drbd_debugfs.h
+++ b/drivers/block/drbd/drbd_debugfs.h
@@ -6,7 +6,7 @@
#include "drbd_int.h"
#ifdef CONFIG_DEBUG_FS
-int __init drbd_debugfs_init(void);
+void __init drbd_debugfs_init(void);
void drbd_debugfs_cleanup(void);
void drbd_debugfs_resource_add(struct drbd_resource *resource);
@@ -22,7 +22,7 @@ void drbd_debugfs_peer_device_add(struct drbd_peer_device *peer_device);
void drbd_debugfs_peer_device_cleanup(struct drbd_peer_device *peer_device);
#else
-static inline int __init drbd_debugfs_init(void) { return -ENODEV; }
+static inline void __init drbd_debugfs_init(void) { }
static inline void drbd_debugfs_cleanup(void) { }
static inline void drbd_debugfs_resource_add(struct drbd_resource *resource) { }
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h
index 31237f45247a..ddbf56014c51 100644
--- a/drivers/block/drbd/drbd_int.h
+++ b/drivers/block/drbd/drbd_int.h
@@ -1960,7 +1960,7 @@ static inline void wake_ack_receiver(struct drbd_connection *connection)
{
struct task_struct *task = connection->ack_receiver.task;
if (task && get_t_state(&connection->ack_receiver) == RUNNING)
- force_sig(SIGXCPU, task);
+ send_sig(SIGXCPU, task, 1);
}
static inline void request_ping(struct drbd_connection *connection)
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index 541b31fa42b3..9bd4ddd12b25 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -465,7 +465,7 @@ void _drbd_thread_stop(struct drbd_thread *thi, int restart, int wait)
smp_mb();
init_completion(&thi->stop);
if (thi->task != current)
- force_sig(DRBD_SIGKILL, thi->task);
+ send_sig(DRBD_SIGKILL, thi->task, 1);
}
spin_unlock_irqrestore(&thi->t_lock, flags);
@@ -3009,8 +3009,7 @@ static int __init drbd_init(void)
spin_lock_init(&retry.lock);
INIT_LIST_HEAD(&retry.writes);
- if (drbd_debugfs_init())
- pr_notice("failed to initialize debugfs -- will not be available\n");
+ drbd_debugfs_init();
pr_info("initialized. "
"Version: " REL_VERSION " (api:%d/proto:%d-%d)\n",
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index cdd748b8116d..5d52a2d32155 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -599,7 +599,7 @@ void conn_try_outdate_peer_async(struct drbd_connection *connection)
struct task_struct *opa;
kref_get(&connection->kref);
- /* We may just have force_sig()'ed this thread
+ /* We may have just sent a signal to this thread
* to get it out of some blocking network function.
* Clear signals; otherwise kthread_run(), which internally uses
* wait_on_completion_killable(), will mistake our pending signal
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 9fb9b312ab6b..0469aceaa230 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -2120,6 +2120,9 @@ static void setup_format_params(int track)
raw_cmd->kernel_data = floppy_track_buffer;
raw_cmd->length = 4 * F_SECT_PER_TRACK;
+ if (!F_SECT_PER_TRACK)
+ return;
+
/* allow for about 30ms for data transport per track */
head_shift = (F_SECT_PER_TRACK + 5) / 6;
@@ -3230,8 +3233,12 @@ static int set_geometry(unsigned int cmd, struct floppy_struct *g,
int cnt;
/* sanity checking for parameters. */
- if (g->sect <= 0 ||
- g->head <= 0 ||
+ if ((int)g->sect <= 0 ||
+ (int)g->head <= 0 ||
+ /* check for overflow in max_sector */
+ (int)(g->sect * g->head) <= 0 ||
+ /* check for zero in F_SECT_PER_TRACK */
+ (unsigned char)((g->sect << 2) >> FD_SIZECODE(g)) == 0 ||
g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
/* check if reserved bits are set */
(g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
@@ -3375,6 +3382,24 @@ static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
return 0;
}
+static bool valid_floppy_drive_params(const short autodetect[8],
+ int native_format)
+{
+ size_t floppy_type_size = ARRAY_SIZE(floppy_type);
+ size_t i = 0;
+
+ for (i = 0; i < 8; ++i) {
+ if (autodetect[i] < 0 ||
+ autodetect[i] >= floppy_type_size)
+ return false;
+ }
+
+ if (native_format < 0 || native_format >= floppy_type_size)
+ return false;
+
+ return true;
+}
+
static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
unsigned long param)
{
@@ -3501,6 +3526,9 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
SUPBOUND(size, strlen((const char *)outparam) + 1);
break;
case FDSETDRVPRM:
+ if (!valid_floppy_drive_params(inparam.dp.autodetect,
+ inparam.dp.native_format))
+ return -EINVAL;
*UDP = inparam.dp;
break;
case FDGETDRVPRM:
@@ -3698,6 +3726,8 @@ static int compat_setdrvprm(int drive,
return -EPERM;
if (copy_from_user(&v, arg, sizeof(struct compat_floppy_drive_params)))
return -EFAULT;
+ if (!valid_floppy_drive_params(v.autodetect, v.native_format))
+ return -EINVAL;
mutex_lock(&floppy_mutex);
UDP->cmos = v.cmos;
UDP->max_dtr = v.max_dtr;
@@ -3900,7 +3930,7 @@ static void __init config_types(void)
if (!UDP->cmos)
UDP->cmos = FLOPPY0_TYPE;
drive = 1;
- if (!UDP->cmos && FLOPPY1_TYPE)
+ if (!UDP->cmos)
UDP->cmos = FLOPPY1_TYPE;
/* FIXME: additional physical CMOS drive detection should go here */
@@ -4424,7 +4454,7 @@ static int __init floppy_setup(char *str)
pr_cont("\n");
} else
DPRINT("botched floppy option\n");
- DPRINT("Read Documentation/blockdev/floppy.txt\n");
+ DPRINT("Read Documentation/admin-guide/blockdev/floppy.rst\n");
return 0;
}
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index f11b7dc16e9d..44c9985f352a 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -264,20 +264,12 @@ lo_do_transfer(struct loop_device *lo, int cmd,
return ret;
}
-static inline void loop_iov_iter_bvec(struct iov_iter *i,
- unsigned int direction, const struct bio_vec *bvec,
- unsigned long nr_segs, size_t count)
-{
- iov_iter_bvec(i, direction, bvec, nr_segs, count);
- i->type |= ITER_BVEC_FLAG_NO_REF;
-}
-
static int lo_write_bvec(struct file *file, struct bio_vec *bvec, loff_t *ppos)
{
struct iov_iter i;
ssize_t bw;
- loop_iov_iter_bvec(&i, WRITE, bvec, 1, bvec->bv_len);
+ iov_iter_bvec(&i, WRITE, bvec, 1, bvec->bv_len);
file_start_write(file);
bw = vfs_iter_write(file, &i, ppos, 0);
@@ -355,7 +347,7 @@ static int lo_read_simple(struct loop_device *lo, struct request *rq,
ssize_t len;
rq_for_each_segment(bvec, rq, iter) {
- loop_iov_iter_bvec(&i, READ, &bvec, 1, bvec.bv_len);
+ iov_iter_bvec(&i, READ, &bvec, 1, bvec.bv_len);
len = vfs_iter_read(lo->lo_backing_file, &i, &pos, 0);
if (len < 0)
return len;
@@ -396,7 +388,7 @@ static int lo_read_transfer(struct loop_device *lo, struct request *rq,
b.bv_offset = 0;
b.bv_len = bvec.bv_len;
- loop_iov_iter_bvec(&i, READ, &b, 1, b.bv_len);
+ iov_iter_bvec(&i, READ, &b, 1, b.bv_len);
len = vfs_iter_read(lo->lo_backing_file, &i, &pos, 0);
if (len < 0) {
ret = len;
@@ -563,7 +555,7 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd,
}
atomic_set(&cmd->ref, 2);
- loop_iov_iter_bvec(&iter, rw, bvec, nr_bvec, blk_rq_bytes(rq));
+ iov_iter_bvec(&iter, rw, bvec, nr_bvec, blk_rq_bytes(rq));
iter.iov_offset = offset;
cmd->iocb.ki_pos = pos;
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c
index a14b09ab3a41..964f78cfffa0 100644
--- a/drivers/block/mtip32xx/mtip32xx.c
+++ b/drivers/block/mtip32xx/mtip32xx.c
@@ -1577,7 +1577,6 @@ static int exec_drive_command(struct mtip_port *port, u8 *command,
ATA_SECT_SIZE * xfer_sz);
return -ENOMEM;
}
- memset(buf, 0, ATA_SECT_SIZE * xfer_sz);
}
/* Build the FIS. */
@@ -2776,7 +2775,6 @@ static int mtip_dma_alloc(struct driver_data *dd)
&port->block1_dma, GFP_KERNEL);
if (!port->block1)
return -ENOMEM;
- memset(port->block1, 0, BLOCK_DMA_ALLOC_SZ);
/* Allocate dma memory for command list */
port->command_list =
@@ -2789,7 +2787,6 @@ static int mtip_dma_alloc(struct driver_data *dd)
port->block1_dma = 0;
return -ENOMEM;
}
- memset(port->command_list, 0, AHCI_CMD_TBL_SZ);
/* Setup all pointers into first DMA region */
port->rxfis = port->block1 + AHCI_RX_FIS_OFFSET;
@@ -3529,8 +3526,6 @@ static int mtip_init_cmd(struct blk_mq_tag_set *set, struct request *rq,
if (!cmd->command)
return -ENOMEM;
- memset(cmd->command, 0, CMD_DMA_ALLOC_SZ);
-
sg_init_table(cmd->sg, MTIP_MAX_SG);
return 0;
}
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 3a9bca3aa093..9bcde2325893 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -134,6 +134,8 @@ static struct dentry *nbd_dbg_dir;
#define NBD_MAGIC 0x68797548
+#define NBD_DEF_BLKSIZE 1024
+
static unsigned int nbds_max = 16;
static int max_part = 16;
static struct workqueue_struct *recv_workqueue;
@@ -1236,6 +1238,14 @@ static void nbd_clear_sock_ioctl(struct nbd_device *nbd,
nbd_config_put(nbd);
}
+static bool nbd_is_valid_blksize(unsigned long blksize)
+{
+ if (!blksize || !is_power_of_2(blksize) || blksize < 512 ||
+ blksize > PAGE_SIZE)
+ return false;
+ return true;
+}
+
/* Must be called with config_lock held */
static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
unsigned int cmd, unsigned long arg)
@@ -1251,8 +1261,9 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
case NBD_SET_SOCK:
return nbd_add_socket(nbd, arg, false);
case NBD_SET_BLKSIZE:
- if (!arg || !is_power_of_2(arg) || arg < 512 ||
- arg > PAGE_SIZE)
+ if (!arg)
+ arg = NBD_DEF_BLKSIZE;
+ if (!nbd_is_valid_blksize(arg))
return -EINVAL;
nbd_size_set(nbd, arg,
div_s64(config->bytesize, arg));
@@ -1332,7 +1343,7 @@ static struct nbd_config *nbd_alloc_config(void)
atomic_set(&config->recv_threads, 0);
init_waitqueue_head(&config->recv_wq);
init_waitqueue_head(&config->conn_wait);
- config->blksize = 1024;
+ config->blksize = NBD_DEF_BLKSIZE;
atomic_set(&config->live_connections, 0);
try_module_get(THIS_MODULE);
return config;
@@ -1673,6 +1684,30 @@ nbd_device_policy[NBD_DEVICE_ATTR_MAX + 1] = {
[NBD_DEVICE_CONNECTED] = { .type = NLA_U8 },
};
+static int nbd_genl_size_set(struct genl_info *info, struct nbd_device *nbd)
+{
+ struct nbd_config *config = nbd->config;
+ u64 bsize = config->blksize;
+ u64 bytes = config->bytesize;
+
+ if (info->attrs[NBD_ATTR_SIZE_BYTES])
+ bytes = nla_get_u64(info->attrs[NBD_ATTR_SIZE_BYTES]);
+
+ if (info->attrs[NBD_ATTR_BLOCK_SIZE_BYTES]) {
+ bsize = nla_get_u64(info->attrs[NBD_ATTR_BLOCK_SIZE_BYTES]);
+ if (!bsize)
+ bsize = NBD_DEF_BLKSIZE;
+ if (!nbd_is_valid_blksize(bsize)) {
+ printk(KERN_ERR "Invalid block size %llu\n", bsize);
+ return -EINVAL;
+ }
+ }
+
+ if (bytes != config->bytesize || bsize != config->blksize)
+ nbd_size_set(nbd, bsize, div64_u64(bytes, bsize));
+ return 0;
+}
+
static int nbd_genl_connect(struct sk_buff *skb, struct genl_info *info)
{
struct nbd_device *nbd = NULL;
@@ -1760,16 +1795,10 @@ again:
refcount_set(&nbd->config_refs, 1);
set_bit(NBD_BOUND, &config->runtime_flags);
- if (info->attrs[NBD_ATTR_SIZE_BYTES]) {
- u64 bytes = nla_get_u64(info->attrs[NBD_ATTR_SIZE_BYTES]);
- nbd_size_set(nbd, config->blksize,
- div64_u64(bytes, config->blksize));
- }
- if (info->attrs[NBD_ATTR_BLOCK_SIZE_BYTES]) {
- u64 bsize =
- nla_get_u64(info->attrs[NBD_ATTR_BLOCK_SIZE_BYTES]);
- nbd_size_set(nbd, bsize, div64_u64(config->bytesize, bsize));
- }
+ ret = nbd_genl_size_set(info, nbd);
+ if (ret)
+ goto out;
+
if (info->attrs[NBD_ATTR_TIMEOUT]) {
u64 timeout = nla_get_u64(info->attrs[NBD_ATTR_TIMEOUT]);
nbd->tag_set.timeout = timeout * HZ;
@@ -1938,6 +1967,10 @@ static int nbd_genl_reconfigure(struct sk_buff *skb, struct genl_info *info)
goto out;
}
+ ret = nbd_genl_size_set(info, nbd);
+ if (ret)
+ goto out;
+
if (info->attrs[NBD_ATTR_TIMEOUT]) {
u64 timeout = nla_get_u64(info->attrs[NBD_ATTR_TIMEOUT]);
nbd->tag_set.timeout = timeout * HZ;
diff --git a/drivers/block/null_blk.h b/drivers/block/null_blk.h
index 34b22d6523ba..a1b9929bd911 100644
--- a/drivers/block/null_blk.h
+++ b/drivers/block/null_blk.h
@@ -89,8 +89,7 @@ struct nullb {
int null_zone_init(struct nullb_device *dev);
void null_zone_exit(struct nullb_device *dev);
int null_zone_report(struct gendisk *disk, sector_t sector,
- struct blk_zone *zones, unsigned int *nr_zones,
- gfp_t gfp_mask);
+ struct blk_zone *zones, unsigned int *nr_zones);
void null_zone_write(struct nullb_cmd *cmd, sector_t sector,
unsigned int nr_sectors);
void null_zone_reset(struct nullb_cmd *cmd, sector_t sector);
@@ -103,7 +102,7 @@ static inline int null_zone_init(struct nullb_device *dev)
static inline void null_zone_exit(struct nullb_device *dev) {}
static inline int null_zone_report(struct gendisk *disk, sector_t sector,
struct blk_zone *zones,
- unsigned int *nr_zones, gfp_t gfp_mask)
+ unsigned int *nr_zones)
{
return -EOPNOTSUPP;
}
diff --git a/drivers/block/null_blk_main.c b/drivers/block/null_blk_main.c
index 447d635c79a2..99328ded60d1 100644
--- a/drivers/block/null_blk_main.c
+++ b/drivers/block/null_blk_main.c
@@ -327,11 +327,12 @@ static ssize_t nullb_device_power_store(struct config_item *item,
set_bit(NULLB_DEV_FL_CONFIGURED, &dev->flags);
dev->power = newp;
} else if (dev->power && !newp) {
- mutex_lock(&lock);
- dev->power = newp;
- null_del_dev(dev->nullb);
- mutex_unlock(&lock);
- clear_bit(NULLB_DEV_FL_UP, &dev->flags);
+ if (test_and_clear_bit(NULLB_DEV_FL_UP, &dev->flags)) {
+ mutex_lock(&lock);
+ dev->power = newp;
+ null_del_dev(dev->nullb);
+ mutex_unlock(&lock);
+ }
clear_bit(NULLB_DEV_FL_CONFIGURED, &dev->flags);
}
@@ -1197,7 +1198,7 @@ static blk_status_t null_handle_cmd(struct nullb_cmd *cmd)
if (!cmd->error && dev->zoned) {
sector_t sector;
unsigned int nr_sectors;
- int op;
+ enum req_opf op;
if (dev->queue_mode == NULL_Q_BIO) {
op = bio_op(cmd->bio);
@@ -1488,7 +1489,6 @@ static int setup_queues(struct nullb *nullb)
if (!nullb->queues)
return -ENOMEM;
- nullb->nr_queues = 0;
nullb->queue_depth = nullb->dev->hw_queue_depth;
return 0;
diff --git a/drivers/block/null_blk_zoned.c b/drivers/block/null_blk_zoned.c
index fca0c97ff1aa..cb28d93f2bd1 100644
--- a/drivers/block/null_blk_zoned.c
+++ b/drivers/block/null_blk_zoned.c
@@ -67,8 +67,7 @@ void null_zone_exit(struct nullb_device *dev)
}
int null_zone_report(struct gendisk *disk, sector_t sector,
- struct blk_zone *zones, unsigned int *nr_zones,
- gfp_t gfp_mask)
+ struct blk_zone *zones, unsigned int *nr_zones)
{
struct nullb *nullb = disk->private_data;
struct nullb_device *dev = nullb->dev;
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index e5009a34f9c2..3327192bb71f 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -115,6 +115,8 @@ static int atomic_dec_return_safe(atomic_t *v)
#define RBD_FEATURE_LAYERING (1ULL<<0)
#define RBD_FEATURE_STRIPINGV2 (1ULL<<1)
#define RBD_FEATURE_EXCLUSIVE_LOCK (1ULL<<2)
+#define RBD_FEATURE_OBJECT_MAP (1ULL<<3)
+#define RBD_FEATURE_FAST_DIFF (1ULL<<4)
#define RBD_FEATURE_DEEP_FLATTEN (1ULL<<5)
#define RBD_FEATURE_DATA_POOL (1ULL<<7)
#define RBD_FEATURE_OPERATIONS (1ULL<<8)
@@ -122,6 +124,8 @@ static int atomic_dec_return_safe(atomic_t *v)
#define RBD_FEATURES_ALL (RBD_FEATURE_LAYERING | \
RBD_FEATURE_STRIPINGV2 | \
RBD_FEATURE_EXCLUSIVE_LOCK | \
+ RBD_FEATURE_OBJECT_MAP | \
+ RBD_FEATURE_FAST_DIFF | \
RBD_FEATURE_DEEP_FLATTEN | \
RBD_FEATURE_DATA_POOL | \
RBD_FEATURE_OPERATIONS)
@@ -203,6 +207,11 @@ struct rbd_client {
struct list_head node;
};
+struct pending_result {
+ int result; /* first nonzero result */
+ int num_pending;
+};
+
struct rbd_img_request;
enum obj_request_type {
@@ -219,6 +228,18 @@ enum obj_operation_type {
OBJ_OP_ZEROOUT,
};
+#define RBD_OBJ_FLAG_DELETION (1U << 0)
+#define RBD_OBJ_FLAG_COPYUP_ENABLED (1U << 1)
+#define RBD_OBJ_FLAG_COPYUP_ZEROS (1U << 2)
+#define RBD_OBJ_FLAG_MAY_EXIST (1U << 3)
+#define RBD_OBJ_FLAG_NOOP_FOR_NONEXISTENT (1U << 4)
+
+enum rbd_obj_read_state {
+ RBD_OBJ_READ_START = 1,
+ RBD_OBJ_READ_OBJECT,
+ RBD_OBJ_READ_PARENT,
+};
+
/*
* Writes go through the following state machine to deal with
* layering:
@@ -245,17 +266,28 @@ enum obj_operation_type {
* even if there is a parent).
*/
enum rbd_obj_write_state {
- RBD_OBJ_WRITE_FLAT = 1,
- RBD_OBJ_WRITE_GUARD,
- RBD_OBJ_WRITE_READ_FROM_PARENT,
- RBD_OBJ_WRITE_COPYUP_EMPTY_SNAPC,
- RBD_OBJ_WRITE_COPYUP_OPS,
+ RBD_OBJ_WRITE_START = 1,
+ RBD_OBJ_WRITE_PRE_OBJECT_MAP,
+ RBD_OBJ_WRITE_OBJECT,
+ __RBD_OBJ_WRITE_COPYUP,
+ RBD_OBJ_WRITE_COPYUP,
+ RBD_OBJ_WRITE_POST_OBJECT_MAP,
+};
+
+enum rbd_obj_copyup_state {
+ RBD_OBJ_COPYUP_START = 1,
+ RBD_OBJ_COPYUP_READ_PARENT,
+ __RBD_OBJ_COPYUP_OBJECT_MAPS,
+ RBD_OBJ_COPYUP_OBJECT_MAPS,
+ __RBD_OBJ_COPYUP_WRITE_OBJECT,
+ RBD_OBJ_COPYUP_WRITE_OBJECT,
};
struct rbd_obj_request {
struct ceph_object_extent ex;
+ unsigned int flags; /* RBD_OBJ_FLAG_* */
union {
- bool tried_parent; /* for reads */
+ enum rbd_obj_read_state read_state; /* for reads */
enum rbd_obj_write_state write_state; /* for writes */
};
@@ -271,14 +303,15 @@ struct rbd_obj_request {
u32 bvec_idx;
};
};
+
+ enum rbd_obj_copyup_state copyup_state;
struct bio_vec *copyup_bvecs;
u32 copyup_bvec_count;
- struct ceph_osd_request *osd_req;
-
- u64 xferred; /* bytes transferred */
- int result;
+ struct list_head osd_reqs; /* w/ r_private_item */
+ struct mutex state_mutex;
+ struct pending_result pending;
struct kref kref;
};
@@ -287,11 +320,19 @@ enum img_req_flags {
IMG_REQ_LAYERED, /* ENOENT handling: normal = 0, layered = 1 */
};
+enum rbd_img_state {
+ RBD_IMG_START = 1,
+ RBD_IMG_EXCLUSIVE_LOCK,
+ __RBD_IMG_OBJECT_REQUESTS,
+ RBD_IMG_OBJECT_REQUESTS,
+};
+
struct rbd_img_request {
struct rbd_device *rbd_dev;
enum obj_operation_type op_type;
enum obj_request_type data_type;
unsigned long flags;
+ enum rbd_img_state state;
union {
u64 snap_id; /* for reads */
struct ceph_snap_context *snapc; /* for writes */
@@ -300,13 +341,14 @@ struct rbd_img_request {
struct request *rq; /* block request */
struct rbd_obj_request *obj_request; /* obj req initiator */
};
- spinlock_t completion_lock;
- u64 xferred;/* aggregate bytes transferred */
- int result; /* first nonzero obj_request result */
+ struct list_head lock_item;
struct list_head object_extents; /* obj_req.ex structs */
- u32 pending_count;
+ struct mutex state_mutex;
+ struct pending_result pending;
+ struct work_struct work;
+ int work_result;
struct kref kref;
};
@@ -380,7 +422,17 @@ struct rbd_device {
struct work_struct released_lock_work;
struct delayed_work lock_dwork;
struct work_struct unlock_work;
- wait_queue_head_t lock_waitq;
+ spinlock_t lock_lists_lock;
+ struct list_head acquiring_list;
+ struct list_head running_list;
+ struct completion acquire_wait;
+ int acquire_err;
+ struct completion releasing_wait;
+
+ spinlock_t object_map_lock;
+ u8 *object_map;
+ u64 object_map_size; /* in objects */
+ u64 object_map_flags;
struct workqueue_struct *task_wq;
@@ -408,12 +460,10 @@ struct rbd_device {
* Flag bits for rbd_dev->flags:
* - REMOVING (which is coupled with rbd_dev->open_count) is protected
* by rbd_dev->lock
- * - BLACKLISTED is protected by rbd_dev->lock_rwsem
*/
enum rbd_dev_flags {
RBD_DEV_FLAG_EXISTS, /* mapped snapshot has not been deleted */
RBD_DEV_FLAG_REMOVING, /* this mapping is being removed */
- RBD_DEV_FLAG_BLACKLISTED, /* our ceph_client is blacklisted */
};
static DEFINE_MUTEX(client_mutex); /* Serialize client creation */
@@ -466,6 +516,8 @@ static int minor_to_rbd_dev_id(int minor)
static bool __rbd_is_lock_owner(struct rbd_device *rbd_dev)
{
+ lockdep_assert_held(&rbd_dev->lock_rwsem);
+
return rbd_dev->lock_state == RBD_LOCK_STATE_LOCKED ||
rbd_dev->lock_state == RBD_LOCK_STATE_RELEASING;
}
@@ -583,6 +635,26 @@ static int _rbd_dev_v2_snap_size(struct rbd_device *rbd_dev, u64 snap_id,
u8 *order, u64 *snap_size);
static int _rbd_dev_v2_snap_features(struct rbd_device *rbd_dev, u64 snap_id,
u64 *snap_features);
+static int rbd_dev_v2_get_flags(struct rbd_device *rbd_dev);
+
+static void rbd_obj_handle_request(struct rbd_obj_request *obj_req, int result);
+static void rbd_img_handle_request(struct rbd_img_request *img_req, int result);
+
+/*
+ * Return true if nothing else is pending.
+ */
+static bool pending_result_dec(struct pending_result *pending, int *result)
+{
+ rbd_assert(pending->num_pending > 0);
+
+ if (*result && !pending->result)
+ pending->result = *result;
+ if (--pending->num_pending)
+ return false;
+
+ *result = pending->result;
+ return true;
+}
static int rbd_open(struct block_device *bdev, fmode_t mode)
{
@@ -1317,6 +1389,8 @@ static void zero_bvecs(struct ceph_bvec_iter *bvec_pos, u32 off, u32 bytes)
static void rbd_obj_zero_range(struct rbd_obj_request *obj_req, u32 off,
u32 bytes)
{
+ dout("%s %p data buf %u~%u\n", __func__, obj_req, off, bytes);
+
switch (obj_req->img_request->data_type) {
case OBJ_REQUEST_BIO:
zero_bios(&obj_req->bio_pos, off, bytes);
@@ -1339,13 +1413,6 @@ static void rbd_obj_request_put(struct rbd_obj_request *obj_request)
kref_put(&obj_request->kref, rbd_obj_request_destroy);
}
-static void rbd_img_request_get(struct rbd_img_request *img_request)
-{
- dout("%s: img %p (was %d)\n", __func__, img_request,
- kref_read(&img_request->kref));
- kref_get(&img_request->kref);
-}
-
static void rbd_img_request_destroy(struct kref *kref);
static void rbd_img_request_put(struct rbd_img_request *img_request)
{
@@ -1362,7 +1429,6 @@ static inline void rbd_img_obj_request_add(struct rbd_img_request *img_request,
/* Image request now owns object's original reference */
obj_request->img_request = img_request;
- img_request->pending_count++;
dout("%s: img %p obj %p\n", __func__, img_request, obj_request);
}
@@ -1375,13 +1441,13 @@ static inline void rbd_img_obj_request_del(struct rbd_img_request *img_request,
rbd_obj_request_put(obj_request);
}
-static void rbd_obj_request_submit(struct rbd_obj_request *obj_request)
+static void rbd_osd_submit(struct ceph_osd_request *osd_req)
{
- struct ceph_osd_request *osd_req = obj_request->osd_req;
+ struct rbd_obj_request *obj_req = osd_req->r_priv;
- dout("%s %p object_no %016llx %llu~%llu osd_req %p\n", __func__,
- obj_request, obj_request->ex.oe_objno, obj_request->ex.oe_off,
- obj_request->ex.oe_len, osd_req);
+ dout("%s osd_req %p for obj_req %p objno %llu %llu~%llu\n",
+ __func__, osd_req, obj_req, obj_req->ex.oe_objno,
+ obj_req->ex.oe_off, obj_req->ex.oe_len);
ceph_osdc_start_request(osd_req->r_osdc, osd_req, false);
}
@@ -1457,41 +1523,38 @@ static bool rbd_img_is_write(struct rbd_img_request *img_req)
}
}
-static void rbd_obj_handle_request(struct rbd_obj_request *obj_req);
-
static void rbd_osd_req_callback(struct ceph_osd_request *osd_req)
{
struct rbd_obj_request *obj_req = osd_req->r_priv;
+ int result;
dout("%s osd_req %p result %d for obj_req %p\n", __func__, osd_req,
osd_req->r_result, obj_req);
- rbd_assert(osd_req == obj_req->osd_req);
- obj_req->result = osd_req->r_result < 0 ? osd_req->r_result : 0;
- if (!obj_req->result && !rbd_img_is_write(obj_req->img_request))
- obj_req->xferred = osd_req->r_result;
+ /*
+ * Writes aren't allowed to return a data payload. In some
+ * guarded write cases (e.g. stat + zero on an empty object)
+ * a stat response makes it through, but we don't care.
+ */
+ if (osd_req->r_result > 0 && rbd_img_is_write(obj_req->img_request))
+ result = 0;
else
- /*
- * Writes aren't allowed to return a data payload. In some
- * guarded write cases (e.g. stat + zero on an empty object)
- * a stat response makes it through, but we don't care.
- */
- obj_req->xferred = 0;
+ result = osd_req->r_result;
- rbd_obj_handle_request(obj_req);
+ rbd_obj_handle_request(obj_req, result);
}
-static void rbd_osd_req_format_read(struct rbd_obj_request *obj_request)
+static void rbd_osd_format_read(struct ceph_osd_request *osd_req)
{
- struct ceph_osd_request *osd_req = obj_request->osd_req;
+ struct rbd_obj_request *obj_request = osd_req->r_priv;
osd_req->r_flags = CEPH_OSD_FLAG_READ;
osd_req->r_snapid = obj_request->img_request->snap_id;
}
-static void rbd_osd_req_format_write(struct rbd_obj_request *obj_request)
+static void rbd_osd_format_write(struct ceph_osd_request *osd_req)
{
- struct ceph_osd_request *osd_req = obj_request->osd_req;
+ struct rbd_obj_request *obj_request = osd_req->r_priv;
osd_req->r_flags = CEPH_OSD_FLAG_WRITE;
ktime_get_real_ts64(&osd_req->r_mtime);
@@ -1499,19 +1562,21 @@ static void rbd_osd_req_format_write(struct rbd_obj_request *obj_request)
}
static struct ceph_osd_request *
-__rbd_osd_req_create(struct rbd_obj_request *obj_req,
- struct ceph_snap_context *snapc, unsigned int num_ops)
+__rbd_obj_add_osd_request(struct rbd_obj_request *obj_req,
+ struct ceph_snap_context *snapc, int num_ops)
{
struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
struct ceph_osd_request *req;
const char *name_format = rbd_dev->image_format == 1 ?
RBD_V1_DATA_FORMAT : RBD_V2_DATA_FORMAT;
+ int ret;
req = ceph_osdc_alloc_request(osdc, snapc, num_ops, false, GFP_NOIO);
if (!req)
- return NULL;
+ return ERR_PTR(-ENOMEM);
+ list_add_tail(&req->r_private_item, &obj_req->osd_reqs);
req->r_callback = rbd_osd_req_callback;
req->r_priv = obj_req;
@@ -1522,27 +1587,20 @@ __rbd_osd_req_create(struct rbd_obj_request *obj_req,
ceph_oloc_copy(&req->r_base_oloc, &rbd_dev->header_oloc);
req->r_base_oloc.pool = rbd_dev->layout.pool_id;
- if (ceph_oid_aprintf(&req->r_base_oid, GFP_NOIO, name_format,
- rbd_dev->header.object_prefix, obj_req->ex.oe_objno))
- goto err_req;
+ ret = ceph_oid_aprintf(&req->r_base_oid, GFP_NOIO, name_format,
+ rbd_dev->header.object_prefix,
+ obj_req->ex.oe_objno);
+ if (ret)
+ return ERR_PTR(ret);
return req;
-
-err_req:
- ceph_osdc_put_request(req);
- return NULL;
}
static struct ceph_osd_request *
-rbd_osd_req_create(struct rbd_obj_request *obj_req, unsigned int num_ops)
+rbd_obj_add_osd_request(struct rbd_obj_request *obj_req, int num_ops)
{
- return __rbd_osd_req_create(obj_req, obj_req->img_request->snapc,
- num_ops);
-}
-
-static void rbd_osd_req_destroy(struct ceph_osd_request *osd_req)
-{
- ceph_osdc_put_request(osd_req);
+ return __rbd_obj_add_osd_request(obj_req, obj_req->img_request->snapc,
+ num_ops);
}
static struct rbd_obj_request *rbd_obj_request_create(void)
@@ -1554,6 +1612,8 @@ static struct rbd_obj_request *rbd_obj_request_create(void)
return NULL;
ceph_object_extent_init(&obj_request->ex);
+ INIT_LIST_HEAD(&obj_request->osd_reqs);
+ mutex_init(&obj_request->state_mutex);
kref_init(&obj_request->kref);
dout("%s %p\n", __func__, obj_request);
@@ -1563,14 +1623,19 @@ static struct rbd_obj_request *rbd_obj_request_create(void)
static void rbd_obj_request_destroy(struct kref *kref)
{
struct rbd_obj_request *obj_request;
+ struct ceph_osd_request *osd_req;
u32 i;
obj_request = container_of(kref, struct rbd_obj_request, kref);
dout("%s: obj %p\n", __func__, obj_request);
- if (obj_request->osd_req)
- rbd_osd_req_destroy(obj_request->osd_req);
+ while (!list_empty(&obj_request->osd_reqs)) {
+ osd_req = list_first_entry(&obj_request->osd_reqs,
+ struct ceph_osd_request, r_private_item);
+ list_del_init(&osd_req->r_private_item);
+ ceph_osdc_put_request(osd_req);
+ }
switch (obj_request->img_request->data_type) {
case OBJ_REQUEST_NODATA:
@@ -1684,8 +1749,9 @@ static struct rbd_img_request *rbd_img_request_create(
if (rbd_dev_parent_get(rbd_dev))
img_request_layered_set(img_request);
- spin_lock_init(&img_request->completion_lock);
+ INIT_LIST_HEAD(&img_request->lock_item);
INIT_LIST_HEAD(&img_request->object_extents);
+ mutex_init(&img_request->state_mutex);
kref_init(&img_request->kref);
dout("%s: rbd_dev %p %s -> img %p\n", __func__, rbd_dev,
@@ -1703,6 +1769,7 @@ static void rbd_img_request_destroy(struct kref *kref)
dout("%s: img %p\n", __func__, img_request);
+ WARN_ON(!list_empty(&img_request->lock_item));
for_each_obj_request_safe(img_request, obj_request, next_obj_request)
rbd_img_obj_request_del(img_request, obj_request);
@@ -1717,6 +1784,466 @@ static void rbd_img_request_destroy(struct kref *kref)
kmem_cache_free(rbd_img_request_cache, img_request);
}
+#define BITS_PER_OBJ 2
+#define OBJS_PER_BYTE (BITS_PER_BYTE / BITS_PER_OBJ)
+#define OBJ_MASK ((1 << BITS_PER_OBJ) - 1)
+
+static void __rbd_object_map_index(struct rbd_device *rbd_dev, u64 objno,
+ u64 *index, u8 *shift)
+{
+ u32 off;
+
+ rbd_assert(objno < rbd_dev->object_map_size);
+ *index = div_u64_rem(objno, OBJS_PER_BYTE, &off);
+ *shift = (OBJS_PER_BYTE - off - 1) * BITS_PER_OBJ;
+}
+
+static u8 __rbd_object_map_get(struct rbd_device *rbd_dev, u64 objno)
+{
+ u64 index;
+ u8 shift;
+
+ lockdep_assert_held(&rbd_dev->object_map_lock);
+ __rbd_object_map_index(rbd_dev, objno, &index, &shift);
+ return (rbd_dev->object_map[index] >> shift) & OBJ_MASK;
+}
+
+static void __rbd_object_map_set(struct rbd_device *rbd_dev, u64 objno, u8 val)
+{
+ u64 index;
+ u8 shift;
+ u8 *p;
+
+ lockdep_assert_held(&rbd_dev->object_map_lock);
+ rbd_assert(!(val & ~OBJ_MASK));
+
+ __rbd_object_map_index(rbd_dev, objno, &index, &shift);
+ p = &rbd_dev->object_map[index];
+ *p = (*p & ~(OBJ_MASK << shift)) | (val << shift);
+}
+
+static u8 rbd_object_map_get(struct rbd_device *rbd_dev, u64 objno)
+{
+ u8 state;
+
+ spin_lock(&rbd_dev->object_map_lock);
+ state = __rbd_object_map_get(rbd_dev, objno);
+ spin_unlock(&rbd_dev->object_map_lock);
+ return state;
+}
+
+static bool use_object_map(struct rbd_device *rbd_dev)
+{
+ return ((rbd_dev->header.features & RBD_FEATURE_OBJECT_MAP) &&
+ !(rbd_dev->object_map_flags & RBD_FLAG_OBJECT_MAP_INVALID));
+}
+
+static bool rbd_object_map_may_exist(struct rbd_device *rbd_dev, u64 objno)
+{
+ u8 state;
+
+ /* fall back to default logic if object map is disabled or invalid */
+ if (!use_object_map(rbd_dev))
+ return true;
+
+ state = rbd_object_map_get(rbd_dev, objno);
+ return state != OBJECT_NONEXISTENT;
+}
+
+static void rbd_object_map_name(struct rbd_device *rbd_dev, u64 snap_id,
+ struct ceph_object_id *oid)
+{
+ if (snap_id == CEPH_NOSNAP)
+ ceph_oid_printf(oid, "%s%s", RBD_OBJECT_MAP_PREFIX,
+ rbd_dev->spec->image_id);
+ else
+ ceph_oid_printf(oid, "%s%s.%016llx", RBD_OBJECT_MAP_PREFIX,
+ rbd_dev->spec->image_id, snap_id);
+}
+
+static int rbd_object_map_lock(struct rbd_device *rbd_dev)
+{
+ struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
+ CEPH_DEFINE_OID_ONSTACK(oid);
+ u8 lock_type;
+ char *lock_tag;
+ struct ceph_locker *lockers;
+ u32 num_lockers;
+ bool broke_lock = false;
+ int ret;
+
+ rbd_object_map_name(rbd_dev, CEPH_NOSNAP, &oid);
+
+again:
+ ret = ceph_cls_lock(osdc, &oid, &rbd_dev->header_oloc, RBD_LOCK_NAME,
+ CEPH_CLS_LOCK_EXCLUSIVE, "", "", "", 0);
+ if (ret != -EBUSY || broke_lock) {
+ if (ret == -EEXIST)
+ ret = 0; /* already locked by myself */
+ if (ret)
+ rbd_warn(rbd_dev, "failed to lock object map: %d", ret);
+ return ret;
+ }
+
+ ret = ceph_cls_lock_info(osdc, &oid, &rbd_dev->header_oloc,
+ RBD_LOCK_NAME, &lock_type, &lock_tag,
+ &lockers, &num_lockers);
+ if (ret) {
+ if (ret == -ENOENT)
+ goto again;
+
+ rbd_warn(rbd_dev, "failed to get object map lockers: %d", ret);
+ return ret;
+ }
+
+ kfree(lock_tag);
+ if (num_lockers == 0)
+ goto again;
+
+ rbd_warn(rbd_dev, "breaking object map lock owned by %s%llu",
+ ENTITY_NAME(lockers[0].id.name));
+
+ ret = ceph_cls_break_lock(osdc, &oid, &rbd_dev->header_oloc,
+ RBD_LOCK_NAME, lockers[0].id.cookie,
+ &lockers[0].id.name);
+ ceph_free_lockers(lockers, num_lockers);
+ if (ret) {
+ if (ret == -ENOENT)
+ goto again;
+
+ rbd_warn(rbd_dev, "failed to break object map lock: %d", ret);
+ return ret;
+ }
+
+ broke_lock = true;
+ goto again;
+}
+
+static void rbd_object_map_unlock(struct rbd_device *rbd_dev)
+{
+ struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
+ CEPH_DEFINE_OID_ONSTACK(oid);
+ int ret;
+
+ rbd_object_map_name(rbd_dev, CEPH_NOSNAP, &oid);
+
+ ret = ceph_cls_unlock(osdc, &oid, &rbd_dev->header_oloc, RBD_LOCK_NAME,
+ "");
+ if (ret && ret != -ENOENT)
+ rbd_warn(rbd_dev, "failed to unlock object map: %d", ret);
+}
+
+static int decode_object_map_header(void **p, void *end, u64 *object_map_size)
+{
+ u8 struct_v;
+ u32 struct_len;
+ u32 header_len;
+ void *header_end;
+ int ret;
+
+ ceph_decode_32_safe(p, end, header_len, e_inval);
+ header_end = *p + header_len;
+
+ ret = ceph_start_decoding(p, end, 1, "BitVector header", &struct_v,
+ &struct_len);
+ if (ret)
+ return ret;
+
+ ceph_decode_64_safe(p, end, *object_map_size, e_inval);
+
+ *p = header_end;
+ return 0;
+
+e_inval:
+ return -EINVAL;
+}
+
+static int __rbd_object_map_load(struct rbd_device *rbd_dev)
+{
+ struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
+ CEPH_DEFINE_OID_ONSTACK(oid);
+ struct page **pages;
+ void *p, *end;
+ size_t reply_len;
+ u64 num_objects;
+ u64 object_map_bytes;
+ u64 object_map_size;
+ int num_pages;
+ int ret;
+
+ rbd_assert(!rbd_dev->object_map && !rbd_dev->object_map_size);
+
+ num_objects = ceph_get_num_objects(&rbd_dev->layout,
+ rbd_dev->mapping.size);
+ object_map_bytes = DIV_ROUND_UP_ULL(num_objects * BITS_PER_OBJ,
+ BITS_PER_BYTE);
+ num_pages = calc_pages_for(0, object_map_bytes) + 1;
+ pages = ceph_alloc_page_vector(num_pages, GFP_KERNEL);
+ if (IS_ERR(pages))
+ return PTR_ERR(pages);
+
+ reply_len = num_pages * PAGE_SIZE;
+ rbd_object_map_name(rbd_dev, rbd_dev->spec->snap_id, &oid);
+ ret = ceph_osdc_call(osdc, &oid, &rbd_dev->header_oloc,
+ "rbd", "object_map_load", CEPH_OSD_FLAG_READ,
+ NULL, 0, pages, &reply_len);
+ if (ret)
+ goto out;
+
+ p = page_address(pages[0]);
+ end = p + min(reply_len, (size_t)PAGE_SIZE);
+ ret = decode_object_map_header(&p, end, &object_map_size);
+ if (ret)
+ goto out;
+
+ if (object_map_size != num_objects) {
+ rbd_warn(rbd_dev, "object map size mismatch: %llu vs %llu",
+ object_map_size, num_objects);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (offset_in_page(p) + object_map_bytes > reply_len) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ rbd_dev->object_map = kvmalloc(object_map_bytes, GFP_KERNEL);
+ if (!rbd_dev->object_map) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ rbd_dev->object_map_size = object_map_size;
+ ceph_copy_from_page_vector(pages, rbd_dev->object_map,
+ offset_in_page(p), object_map_bytes);
+
+out:
+ ceph_release_page_vector(pages, num_pages);
+ return ret;
+}
+
+static void rbd_object_map_free(struct rbd_device *rbd_dev)
+{
+ kvfree(rbd_dev->object_map);
+ rbd_dev->object_map = NULL;
+ rbd_dev->object_map_size = 0;
+}
+
+static int rbd_object_map_load(struct rbd_device *rbd_dev)
+{
+ int ret;
+
+ ret = __rbd_object_map_load(rbd_dev);
+ if (ret)
+ return ret;
+
+ ret = rbd_dev_v2_get_flags(rbd_dev);
+ if (ret) {
+ rbd_object_map_free(rbd_dev);
+ return ret;
+ }
+
+ if (rbd_dev->object_map_flags & RBD_FLAG_OBJECT_MAP_INVALID)
+ rbd_warn(rbd_dev, "object map is invalid");
+
+ return 0;
+}
+
+static int rbd_object_map_open(struct rbd_device *rbd_dev)
+{
+ int ret;
+
+ ret = rbd_object_map_lock(rbd_dev);
+ if (ret)
+ return ret;
+
+ ret = rbd_object_map_load(rbd_dev);
+ if (ret) {
+ rbd_object_map_unlock(rbd_dev);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void rbd_object_map_close(struct rbd_device *rbd_dev)
+{
+ rbd_object_map_free(rbd_dev);
+ rbd_object_map_unlock(rbd_dev);
+}
+
+/*
+ * This function needs snap_id (or more precisely just something to
+ * distinguish between HEAD and snapshot object maps), new_state and
+ * current_state that were passed to rbd_object_map_update().
+ *
+ * To avoid allocating and stashing a context we piggyback on the OSD
+ * request. A HEAD update has two ops (assert_locked). For new_state
+ * and current_state we decode our own object_map_update op, encoded in
+ * rbd_cls_object_map_update().
+ */
+static int rbd_object_map_update_finish(struct rbd_obj_request *obj_req,
+ struct ceph_osd_request *osd_req)
+{
+ struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
+ struct ceph_osd_data *osd_data;
+ u64 objno;
+ u8 state, new_state, current_state;
+ bool has_current_state;
+ void *p;
+
+ if (osd_req->r_result)
+ return osd_req->r_result;
+
+ /*
+ * Nothing to do for a snapshot object map.
+ */
+ if (osd_req->r_num_ops == 1)
+ return 0;
+
+ /*
+ * Update in-memory HEAD object map.
+ */
+ rbd_assert(osd_req->r_num_ops == 2);
+ osd_data = osd_req_op_data(osd_req, 1, cls, request_data);
+ rbd_assert(osd_data->type == CEPH_OSD_DATA_TYPE_PAGES);
+
+ p = page_address(osd_data->pages[0]);
+ objno = ceph_decode_64(&p);
+ rbd_assert(objno == obj_req->ex.oe_objno);
+ rbd_assert(ceph_decode_64(&p) == objno + 1);
+ new_state = ceph_decode_8(&p);
+ has_current_state = ceph_decode_8(&p);
+ if (has_current_state)
+ current_state = ceph_decode_8(&p);
+
+ spin_lock(&rbd_dev->object_map_lock);
+ state = __rbd_object_map_get(rbd_dev, objno);
+ if (!has_current_state || current_state == state ||
+ (current_state == OBJECT_EXISTS && state == OBJECT_EXISTS_CLEAN))
+ __rbd_object_map_set(rbd_dev, objno, new_state);
+ spin_unlock(&rbd_dev->object_map_lock);
+
+ return 0;
+}
+
+static void rbd_object_map_callback(struct ceph_osd_request *osd_req)
+{
+ struct rbd_obj_request *obj_req = osd_req->r_priv;
+ int result;
+
+ dout("%s osd_req %p result %d for obj_req %p\n", __func__, osd_req,
+ osd_req->r_result, obj_req);
+
+ result = rbd_object_map_update_finish(obj_req, osd_req);
+ rbd_obj_handle_request(obj_req, result);
+}
+
+static bool update_needed(struct rbd_device *rbd_dev, u64 objno, u8 new_state)
+{
+ u8 state = rbd_object_map_get(rbd_dev, objno);
+
+ if (state == new_state ||
+ (new_state == OBJECT_PENDING && state == OBJECT_NONEXISTENT) ||
+ (new_state == OBJECT_NONEXISTENT && state != OBJECT_PENDING))
+ return false;
+
+ return true;
+}
+
+static int rbd_cls_object_map_update(struct ceph_osd_request *req,
+ int which, u64 objno, u8 new_state,
+ const u8 *current_state)
+{
+ struct page **pages;
+ void *p, *start;
+ int ret;
+
+ ret = osd_req_op_cls_init(req, which, "rbd", "object_map_update");
+ if (ret)
+ return ret;
+
+ pages = ceph_alloc_page_vector(1, GFP_NOIO);
+ if (IS_ERR(pages))
+ return PTR_ERR(pages);
+
+ p = start = page_address(pages[0]);
+ ceph_encode_64(&p, objno);
+ ceph_encode_64(&p, objno + 1);
+ ceph_encode_8(&p, new_state);
+ if (current_state) {
+ ceph_encode_8(&p, 1);
+ ceph_encode_8(&p, *current_state);
+ } else {
+ ceph_encode_8(&p, 0);
+ }
+
+ osd_req_op_cls_request_data_pages(req, which, pages, p - start, 0,
+ false, true);
+ return 0;
+}
+
+/*
+ * Return:
+ * 0 - object map update sent
+ * 1 - object map update isn't needed
+ * <0 - error
+ */
+static int rbd_object_map_update(struct rbd_obj_request *obj_req, u64 snap_id,
+ u8 new_state, const u8 *current_state)
+{
+ struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
+ struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
+ struct ceph_osd_request *req;
+ int num_ops = 1;
+ int which = 0;
+ int ret;
+
+ if (snap_id == CEPH_NOSNAP) {
+ if (!update_needed(rbd_dev, obj_req->ex.oe_objno, new_state))
+ return 1;
+
+ num_ops++; /* assert_locked */
+ }
+
+ req = ceph_osdc_alloc_request(osdc, NULL, num_ops, false, GFP_NOIO);
+ if (!req)
+ return -ENOMEM;
+
+ list_add_tail(&req->r_private_item, &obj_req->osd_reqs);
+ req->r_callback = rbd_object_map_callback;
+ req->r_priv = obj_req;
+
+ rbd_object_map_name(rbd_dev, snap_id, &req->r_base_oid);
+ ceph_oloc_copy(&req->r_base_oloc, &rbd_dev->header_oloc);
+ req->r_flags = CEPH_OSD_FLAG_WRITE;
+ ktime_get_real_ts64(&req->r_mtime);
+
+ if (snap_id == CEPH_NOSNAP) {
+ /*
+ * Protect against possible race conditions during lock
+ * ownership transitions.
+ */
+ ret = ceph_cls_assert_locked(req, which++, RBD_LOCK_NAME,
+ CEPH_CLS_LOCK_EXCLUSIVE, "", "");
+ if (ret)
+ return ret;
+ }
+
+ ret = rbd_cls_object_map_update(req, which, obj_req->ex.oe_objno,
+ new_state, current_state);
+ if (ret)
+ return ret;
+
+ ret = ceph_osdc_alloc_messages(req, GFP_NOIO);
+ if (ret)
+ return ret;
+
+ ceph_osdc_start_request(osdc, req, false);
+ return 0;
+}
+
static void prune_extents(struct ceph_file_extent *img_extents,
u32 *num_img_extents, u64 overlap)
{
@@ -1764,11 +2291,13 @@ static int rbd_obj_calc_img_extents(struct rbd_obj_request *obj_req,
return 0;
}
-static void rbd_osd_req_setup_data(struct rbd_obj_request *obj_req, u32 which)
+static void rbd_osd_setup_data(struct ceph_osd_request *osd_req, int which)
{
+ struct rbd_obj_request *obj_req = osd_req->r_priv;
+
switch (obj_req->img_request->data_type) {
case OBJ_REQUEST_BIO:
- osd_req_op_extent_osd_data_bio(obj_req->osd_req, which,
+ osd_req_op_extent_osd_data_bio(osd_req, which,
&obj_req->bio_pos,
obj_req->ex.oe_len);
break;
@@ -1777,7 +2306,7 @@ static void rbd_osd_req_setup_data(struct rbd_obj_request *obj_req, u32 which)
rbd_assert(obj_req->bvec_pos.iter.bi_size ==
obj_req->ex.oe_len);
rbd_assert(obj_req->bvec_idx == obj_req->bvec_count);
- osd_req_op_extent_osd_data_bvec_pos(obj_req->osd_req, which,
+ osd_req_op_extent_osd_data_bvec_pos(osd_req, which,
&obj_req->bvec_pos);
break;
default:
@@ -1785,22 +2314,7 @@ static void rbd_osd_req_setup_data(struct rbd_obj_request *obj_req, u32 which)
}
}
-static int rbd_obj_setup_read(struct rbd_obj_request *obj_req)
-{
- obj_req->osd_req = __rbd_osd_req_create(obj_req, NULL, 1);
- if (!obj_req->osd_req)
- return -ENOMEM;
-
- osd_req_op_extent_init(obj_req->osd_req, 0, CEPH_OSD_OP_READ,
- obj_req->ex.oe_off, obj_req->ex.oe_len, 0, 0);
- rbd_osd_req_setup_data(obj_req, 0);
-
- rbd_osd_req_format_read(obj_req);
- return 0;
-}
-
-static int __rbd_obj_setup_stat(struct rbd_obj_request *obj_req,
- unsigned int which)
+static int rbd_osd_setup_stat(struct ceph_osd_request *osd_req, int which)
{
struct page **pages;
@@ -1816,45 +2330,60 @@ static int __rbd_obj_setup_stat(struct rbd_obj_request *obj_req,
if (IS_ERR(pages))
return PTR_ERR(pages);
- osd_req_op_init(obj_req->osd_req, which, CEPH_OSD_OP_STAT, 0);
- osd_req_op_raw_data_in_pages(obj_req->osd_req, which, pages,
+ osd_req_op_init(osd_req, which, CEPH_OSD_OP_STAT, 0);
+ osd_req_op_raw_data_in_pages(osd_req, which, pages,
8 + sizeof(struct ceph_timespec),
0, false, true);
return 0;
}
-static int count_write_ops(struct rbd_obj_request *obj_req)
+static int rbd_osd_setup_copyup(struct ceph_osd_request *osd_req, int which,
+ u32 bytes)
+{
+ struct rbd_obj_request *obj_req = osd_req->r_priv;
+ int ret;
+
+ ret = osd_req_op_cls_init(osd_req, which, "rbd", "copyup");
+ if (ret)
+ return ret;
+
+ osd_req_op_cls_request_data_bvecs(osd_req, which, obj_req->copyup_bvecs,
+ obj_req->copyup_bvec_count, bytes);
+ return 0;
+}
+
+static int rbd_obj_init_read(struct rbd_obj_request *obj_req)
{
- return 2; /* setallochint + write/writefull */
+ obj_req->read_state = RBD_OBJ_READ_START;
+ return 0;
}
-static void __rbd_obj_setup_write(struct rbd_obj_request *obj_req,
- unsigned int which)
+static void __rbd_osd_setup_write_ops(struct ceph_osd_request *osd_req,
+ int which)
{
+ struct rbd_obj_request *obj_req = osd_req->r_priv;
struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
u16 opcode;
- osd_req_op_alloc_hint_init(obj_req->osd_req, which++,
- rbd_dev->layout.object_size,
- rbd_dev->layout.object_size);
+ if (!use_object_map(rbd_dev) ||
+ !(obj_req->flags & RBD_OBJ_FLAG_MAY_EXIST)) {
+ osd_req_op_alloc_hint_init(osd_req, which++,
+ rbd_dev->layout.object_size,
+ rbd_dev->layout.object_size);
+ }
if (rbd_obj_is_entire(obj_req))
opcode = CEPH_OSD_OP_WRITEFULL;
else
opcode = CEPH_OSD_OP_WRITE;
- osd_req_op_extent_init(obj_req->osd_req, which, opcode,
+ osd_req_op_extent_init(osd_req, which, opcode,
obj_req->ex.oe_off, obj_req->ex.oe_len, 0, 0);
- rbd_osd_req_setup_data(obj_req, which++);
-
- rbd_assert(which == obj_req->osd_req->r_num_ops);
- rbd_osd_req_format_write(obj_req);
+ rbd_osd_setup_data(osd_req, which);
}
-static int rbd_obj_setup_write(struct rbd_obj_request *obj_req)
+static int rbd_obj_init_write(struct rbd_obj_request *obj_req)
{
- unsigned int num_osd_ops, which = 0;
- bool need_guard;
int ret;
/* reverse map the entire object onto the parent */
@@ -1862,24 +2391,10 @@ static int rbd_obj_setup_write(struct rbd_obj_request *obj_req)
if (ret)
return ret;
- need_guard = rbd_obj_copyup_enabled(obj_req);
- num_osd_ops = need_guard + count_write_ops(obj_req);
-
- obj_req->osd_req = rbd_osd_req_create(obj_req, num_osd_ops);
- if (!obj_req->osd_req)
- return -ENOMEM;
-
- if (need_guard) {
- ret = __rbd_obj_setup_stat(obj_req, which++);
- if (ret)
- return ret;
+ if (rbd_obj_copyup_enabled(obj_req))
+ obj_req->flags |= RBD_OBJ_FLAG_COPYUP_ENABLED;
- obj_req->write_state = RBD_OBJ_WRITE_GUARD;
- } else {
- obj_req->write_state = RBD_OBJ_WRITE_FLAT;
- }
-
- __rbd_obj_setup_write(obj_req, which);
+ obj_req->write_state = RBD_OBJ_WRITE_START;
return 0;
}
@@ -1889,11 +2404,26 @@ static u16 truncate_or_zero_opcode(struct rbd_obj_request *obj_req)
CEPH_OSD_OP_ZERO;
}
-static int rbd_obj_setup_discard(struct rbd_obj_request *obj_req)
+static void __rbd_osd_setup_discard_ops(struct ceph_osd_request *osd_req,
+ int which)
+{
+ struct rbd_obj_request *obj_req = osd_req->r_priv;
+
+ if (rbd_obj_is_entire(obj_req) && !obj_req->num_img_extents) {
+ rbd_assert(obj_req->flags & RBD_OBJ_FLAG_DELETION);
+ osd_req_op_init(osd_req, which, CEPH_OSD_OP_DELETE, 0);
+ } else {
+ osd_req_op_extent_init(osd_req, which,
+ truncate_or_zero_opcode(obj_req),
+ obj_req->ex.oe_off, obj_req->ex.oe_len,
+ 0, 0);
+ }
+}
+
+static int rbd_obj_init_discard(struct rbd_obj_request *obj_req)
{
struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
- u64 off = obj_req->ex.oe_off;
- u64 next_off = obj_req->ex.oe_off + obj_req->ex.oe_len;
+ u64 off, next_off;
int ret;
/*
@@ -1906,10 +2436,17 @@ static int rbd_obj_setup_discard(struct rbd_obj_request *obj_req)
*/
if (rbd_dev->opts->alloc_size != rbd_dev->layout.object_size ||
!rbd_obj_is_tail(obj_req)) {
- off = round_up(off, rbd_dev->opts->alloc_size);
- next_off = round_down(next_off, rbd_dev->opts->alloc_size);
+ off = round_up(obj_req->ex.oe_off, rbd_dev->opts->alloc_size);
+ next_off = round_down(obj_req->ex.oe_off + obj_req->ex.oe_len,
+ rbd_dev->opts->alloc_size);
if (off >= next_off)
return 1;
+
+ dout("%s %p %llu~%llu -> %llu~%llu\n", __func__,
+ obj_req, obj_req->ex.oe_off, obj_req->ex.oe_len,
+ off, next_off - off);
+ obj_req->ex.oe_off = off;
+ obj_req->ex.oe_len = next_off - off;
}
/* reverse map the entire object onto the parent */
@@ -1917,52 +2454,29 @@ static int rbd_obj_setup_discard(struct rbd_obj_request *obj_req)
if (ret)
return ret;
- obj_req->osd_req = rbd_osd_req_create(obj_req, 1);
- if (!obj_req->osd_req)
- return -ENOMEM;
-
- if (rbd_obj_is_entire(obj_req) && !obj_req->num_img_extents) {
- osd_req_op_init(obj_req->osd_req, 0, CEPH_OSD_OP_DELETE, 0);
- } else {
- dout("%s %p %llu~%llu -> %llu~%llu\n", __func__,
- obj_req, obj_req->ex.oe_off, obj_req->ex.oe_len,
- off, next_off - off);
- osd_req_op_extent_init(obj_req->osd_req, 0,
- truncate_or_zero_opcode(obj_req),
- off, next_off - off, 0, 0);
- }
+ obj_req->flags |= RBD_OBJ_FLAG_NOOP_FOR_NONEXISTENT;
+ if (rbd_obj_is_entire(obj_req) && !obj_req->num_img_extents)
+ obj_req->flags |= RBD_OBJ_FLAG_DELETION;
- obj_req->write_state = RBD_OBJ_WRITE_FLAT;
- rbd_osd_req_format_write(obj_req);
+ obj_req->write_state = RBD_OBJ_WRITE_START;
return 0;
}
-static int count_zeroout_ops(struct rbd_obj_request *obj_req)
-{
- int num_osd_ops;
-
- if (rbd_obj_is_entire(obj_req) && obj_req->num_img_extents &&
- !rbd_obj_copyup_enabled(obj_req))
- num_osd_ops = 2; /* create + truncate */
- else
- num_osd_ops = 1; /* delete/truncate/zero */
-
- return num_osd_ops;
-}
-
-static void __rbd_obj_setup_zeroout(struct rbd_obj_request *obj_req,
- unsigned int which)
+static void __rbd_osd_setup_zeroout_ops(struct ceph_osd_request *osd_req,
+ int which)
{
+ struct rbd_obj_request *obj_req = osd_req->r_priv;
u16 opcode;
if (rbd_obj_is_entire(obj_req)) {
if (obj_req->num_img_extents) {
- if (!rbd_obj_copyup_enabled(obj_req))
- osd_req_op_init(obj_req->osd_req, which++,
+ if (!(obj_req->flags & RBD_OBJ_FLAG_COPYUP_ENABLED))
+ osd_req_op_init(osd_req, which++,
CEPH_OSD_OP_CREATE, 0);
opcode = CEPH_OSD_OP_TRUNCATE;
} else {
- osd_req_op_init(obj_req->osd_req, which++,
+ rbd_assert(obj_req->flags & RBD_OBJ_FLAG_DELETION);
+ osd_req_op_init(osd_req, which++,
CEPH_OSD_OP_DELETE, 0);
opcode = 0;
}
@@ -1971,18 +2485,13 @@ static void __rbd_obj_setup_zeroout(struct rbd_obj_request *obj_req,
}
if (opcode)
- osd_req_op_extent_init(obj_req->osd_req, which++, opcode,
+ osd_req_op_extent_init(osd_req, which, opcode,
obj_req->ex.oe_off, obj_req->ex.oe_len,
0, 0);
-
- rbd_assert(which == obj_req->osd_req->r_num_ops);
- rbd_osd_req_format_write(obj_req);
}
-static int rbd_obj_setup_zeroout(struct rbd_obj_request *obj_req)
+static int rbd_obj_init_zeroout(struct rbd_obj_request *obj_req)
{
- unsigned int num_osd_ops, which = 0;
- bool need_guard;
int ret;
/* reverse map the entire object onto the parent */
@@ -1990,31 +2499,66 @@ static int rbd_obj_setup_zeroout(struct rbd_obj_request *obj_req)
if (ret)
return ret;
- need_guard = rbd_obj_copyup_enabled(obj_req);
- num_osd_ops = need_guard + count_zeroout_ops(obj_req);
+ if (rbd_obj_copyup_enabled(obj_req))
+ obj_req->flags |= RBD_OBJ_FLAG_COPYUP_ENABLED;
+ if (!obj_req->num_img_extents) {
+ obj_req->flags |= RBD_OBJ_FLAG_NOOP_FOR_NONEXISTENT;
+ if (rbd_obj_is_entire(obj_req))
+ obj_req->flags |= RBD_OBJ_FLAG_DELETION;
+ }
- obj_req->osd_req = rbd_osd_req_create(obj_req, num_osd_ops);
- if (!obj_req->osd_req)
- return -ENOMEM;
+ obj_req->write_state = RBD_OBJ_WRITE_START;
+ return 0;
+}
- if (need_guard) {
- ret = __rbd_obj_setup_stat(obj_req, which++);
- if (ret)
- return ret;
+static int count_write_ops(struct rbd_obj_request *obj_req)
+{
+ struct rbd_img_request *img_req = obj_req->img_request;
- obj_req->write_state = RBD_OBJ_WRITE_GUARD;
- } else {
- obj_req->write_state = RBD_OBJ_WRITE_FLAT;
+ switch (img_req->op_type) {
+ case OBJ_OP_WRITE:
+ if (!use_object_map(img_req->rbd_dev) ||
+ !(obj_req->flags & RBD_OBJ_FLAG_MAY_EXIST))
+ return 2; /* setallochint + write/writefull */
+
+ return 1; /* write/writefull */
+ case OBJ_OP_DISCARD:
+ return 1; /* delete/truncate/zero */
+ case OBJ_OP_ZEROOUT:
+ if (rbd_obj_is_entire(obj_req) && obj_req->num_img_extents &&
+ !(obj_req->flags & RBD_OBJ_FLAG_COPYUP_ENABLED))
+ return 2; /* create + truncate */
+
+ return 1; /* delete/truncate/zero */
+ default:
+ BUG();
}
+}
- __rbd_obj_setup_zeroout(obj_req, which);
- return 0;
+static void rbd_osd_setup_write_ops(struct ceph_osd_request *osd_req,
+ int which)
+{
+ struct rbd_obj_request *obj_req = osd_req->r_priv;
+
+ switch (obj_req->img_request->op_type) {
+ case OBJ_OP_WRITE:
+ __rbd_osd_setup_write_ops(osd_req, which);
+ break;
+ case OBJ_OP_DISCARD:
+ __rbd_osd_setup_discard_ops(osd_req, which);
+ break;
+ case OBJ_OP_ZEROOUT:
+ __rbd_osd_setup_zeroout_ops(osd_req, which);
+ break;
+ default:
+ BUG();
+ }
}
/*
- * For each object request in @img_req, allocate an OSD request, add
- * individual OSD ops and prepare them for submission. The number of
- * OSD ops depends on op_type and the overlap point (if any).
+ * Prune the list of object requests (adjust offset and/or length, drop
+ * redundant requests). Prepare object request state machines and image
+ * request state machine for execution.
*/
static int __rbd_img_fill_request(struct rbd_img_request *img_req)
{
@@ -2024,16 +2568,16 @@ static int __rbd_img_fill_request(struct rbd_img_request *img_req)
for_each_obj_request_safe(img_req, obj_req, next_obj_req) {
switch (img_req->op_type) {
case OBJ_OP_READ:
- ret = rbd_obj_setup_read(obj_req);
+ ret = rbd_obj_init_read(obj_req);
break;
case OBJ_OP_WRITE:
- ret = rbd_obj_setup_write(obj_req);
+ ret = rbd_obj_init_write(obj_req);
break;
case OBJ_OP_DISCARD:
- ret = rbd_obj_setup_discard(obj_req);
+ ret = rbd_obj_init_discard(obj_req);
break;
case OBJ_OP_ZEROOUT:
- ret = rbd_obj_setup_zeroout(obj_req);
+ ret = rbd_obj_init_zeroout(obj_req);
break;
default:
BUG();
@@ -2041,17 +2585,12 @@ static int __rbd_img_fill_request(struct rbd_img_request *img_req)
if (ret < 0)
return ret;
if (ret > 0) {
- img_req->xferred += obj_req->ex.oe_len;
- img_req->pending_count--;
rbd_img_obj_request_del(img_req, obj_req);
continue;
}
-
- ret = ceph_osdc_alloc_messages(obj_req->osd_req, GFP_NOIO);
- if (ret)
- return ret;
}
+ img_req->state = RBD_IMG_START;
return 0;
}
@@ -2340,17 +2879,55 @@ static int rbd_img_fill_from_bvecs(struct rbd_img_request *img_req,
&it);
}
-static void rbd_img_request_submit(struct rbd_img_request *img_request)
+static void rbd_img_handle_request_work(struct work_struct *work)
{
- struct rbd_obj_request *obj_request;
+ struct rbd_img_request *img_req =
+ container_of(work, struct rbd_img_request, work);
- dout("%s: img %p\n", __func__, img_request);
+ rbd_img_handle_request(img_req, img_req->work_result);
+}
- rbd_img_request_get(img_request);
- for_each_obj_request(img_request, obj_request)
- rbd_obj_request_submit(obj_request);
+static void rbd_img_schedule(struct rbd_img_request *img_req, int result)
+{
+ INIT_WORK(&img_req->work, rbd_img_handle_request_work);
+ img_req->work_result = result;
+ queue_work(rbd_wq, &img_req->work);
+}
- rbd_img_request_put(img_request);
+static bool rbd_obj_may_exist(struct rbd_obj_request *obj_req)
+{
+ struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
+
+ if (rbd_object_map_may_exist(rbd_dev, obj_req->ex.oe_objno)) {
+ obj_req->flags |= RBD_OBJ_FLAG_MAY_EXIST;
+ return true;
+ }
+
+ dout("%s %p objno %llu assuming dne\n", __func__, obj_req,
+ obj_req->ex.oe_objno);
+ return false;
+}
+
+static int rbd_obj_read_object(struct rbd_obj_request *obj_req)
+{
+ struct ceph_osd_request *osd_req;
+ int ret;
+
+ osd_req = __rbd_obj_add_osd_request(obj_req, NULL, 1);
+ if (IS_ERR(osd_req))
+ return PTR_ERR(osd_req);
+
+ osd_req_op_extent_init(osd_req, 0, CEPH_OSD_OP_READ,
+ obj_req->ex.oe_off, obj_req->ex.oe_len, 0, 0);
+ rbd_osd_setup_data(osd_req, 0);
+ rbd_osd_format_read(osd_req);
+
+ ret = ceph_osdc_alloc_messages(osd_req, GFP_NOIO);
+ if (ret)
+ return ret;
+
+ rbd_osd_submit(osd_req);
+ return 0;
}
static int rbd_obj_read_from_parent(struct rbd_obj_request *obj_req)
@@ -2396,51 +2973,144 @@ static int rbd_obj_read_from_parent(struct rbd_obj_request *obj_req)
return ret;
}
- rbd_img_request_submit(child_img_req);
+ /* avoid parent chain recursion */
+ rbd_img_schedule(child_img_req, 0);
return 0;
}
-static bool rbd_obj_handle_read(struct rbd_obj_request *obj_req)
+static bool rbd_obj_advance_read(struct rbd_obj_request *obj_req, int *result)
{
struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
int ret;
- if (obj_req->result == -ENOENT &&
- rbd_dev->parent_overlap && !obj_req->tried_parent) {
- /* reverse map this object extent onto the parent */
- ret = rbd_obj_calc_img_extents(obj_req, false);
+again:
+ switch (obj_req->read_state) {
+ case RBD_OBJ_READ_START:
+ rbd_assert(!*result);
+
+ if (!rbd_obj_may_exist(obj_req)) {
+ *result = -ENOENT;
+ obj_req->read_state = RBD_OBJ_READ_OBJECT;
+ goto again;
+ }
+
+ ret = rbd_obj_read_object(obj_req);
if (ret) {
- obj_req->result = ret;
+ *result = ret;
return true;
}
-
- if (obj_req->num_img_extents) {
- obj_req->tried_parent = true;
- ret = rbd_obj_read_from_parent(obj_req);
+ obj_req->read_state = RBD_OBJ_READ_OBJECT;
+ return false;
+ case RBD_OBJ_READ_OBJECT:
+ if (*result == -ENOENT && rbd_dev->parent_overlap) {
+ /* reverse map this object extent onto the parent */
+ ret = rbd_obj_calc_img_extents(obj_req, false);
if (ret) {
- obj_req->result = ret;
+ *result = ret;
return true;
}
- return false;
+ if (obj_req->num_img_extents) {
+ ret = rbd_obj_read_from_parent(obj_req);
+ if (ret) {
+ *result = ret;
+ return true;
+ }
+ obj_req->read_state = RBD_OBJ_READ_PARENT;
+ return false;
+ }
+ }
+
+ /*
+ * -ENOENT means a hole in the image -- zero-fill the entire
+ * length of the request. A short read also implies zero-fill
+ * to the end of the request.
+ */
+ if (*result == -ENOENT) {
+ rbd_obj_zero_range(obj_req, 0, obj_req->ex.oe_len);
+ *result = 0;
+ } else if (*result >= 0) {
+ if (*result < obj_req->ex.oe_len)
+ rbd_obj_zero_range(obj_req, *result,
+ obj_req->ex.oe_len - *result);
+ else
+ rbd_assert(*result == obj_req->ex.oe_len);
+ *result = 0;
}
+ return true;
+ case RBD_OBJ_READ_PARENT:
+ return true;
+ default:
+ BUG();
}
+}
- /*
- * -ENOENT means a hole in the image -- zero-fill the entire
- * length of the request. A short read also implies zero-fill
- * to the end of the request. In both cases we update xferred
- * count to indicate the whole request was satisfied.
- */
- if (obj_req->result == -ENOENT ||
- (!obj_req->result && obj_req->xferred < obj_req->ex.oe_len)) {
- rbd_assert(!obj_req->xferred || !obj_req->result);
- rbd_obj_zero_range(obj_req, obj_req->xferred,
- obj_req->ex.oe_len - obj_req->xferred);
- obj_req->result = 0;
- obj_req->xferred = obj_req->ex.oe_len;
+static bool rbd_obj_write_is_noop(struct rbd_obj_request *obj_req)
+{
+ struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
+
+ if (rbd_object_map_may_exist(rbd_dev, obj_req->ex.oe_objno))
+ obj_req->flags |= RBD_OBJ_FLAG_MAY_EXIST;
+
+ if (!(obj_req->flags & RBD_OBJ_FLAG_MAY_EXIST) &&
+ (obj_req->flags & RBD_OBJ_FLAG_NOOP_FOR_NONEXISTENT)) {
+ dout("%s %p noop for nonexistent\n", __func__, obj_req);
+ return true;
}
- return true;
+ return false;
+}
+
+/*
+ * Return:
+ * 0 - object map update sent
+ * 1 - object map update isn't needed
+ * <0 - error
+ */
+static int rbd_obj_write_pre_object_map(struct rbd_obj_request *obj_req)
+{
+ struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
+ u8 new_state;
+
+ if (!(rbd_dev->header.features & RBD_FEATURE_OBJECT_MAP))
+ return 1;
+
+ if (obj_req->flags & RBD_OBJ_FLAG_DELETION)
+ new_state = OBJECT_PENDING;
+ else
+ new_state = OBJECT_EXISTS;
+
+ return rbd_object_map_update(obj_req, CEPH_NOSNAP, new_state, NULL);
+}
+
+static int rbd_obj_write_object(struct rbd_obj_request *obj_req)
+{
+ struct ceph_osd_request *osd_req;
+ int num_ops = count_write_ops(obj_req);
+ int which = 0;
+ int ret;
+
+ if (obj_req->flags & RBD_OBJ_FLAG_COPYUP_ENABLED)
+ num_ops++; /* stat */
+
+ osd_req = rbd_obj_add_osd_request(obj_req, num_ops);
+ if (IS_ERR(osd_req))
+ return PTR_ERR(osd_req);
+
+ if (obj_req->flags & RBD_OBJ_FLAG_COPYUP_ENABLED) {
+ ret = rbd_osd_setup_stat(osd_req, which++);
+ if (ret)
+ return ret;
+ }
+
+ rbd_osd_setup_write_ops(osd_req, which);
+ rbd_osd_format_write(osd_req);
+
+ ret = ceph_osdc_alloc_messages(osd_req, GFP_NOIO);
+ if (ret)
+ return ret;
+
+ rbd_osd_submit(osd_req);
+ return 0;
}
/*
@@ -2463,123 +3133,67 @@ static bool is_zero_bvecs(struct bio_vec *bvecs, u32 bytes)
#define MODS_ONLY U32_MAX
-static int rbd_obj_issue_copyup_empty_snapc(struct rbd_obj_request *obj_req,
- u32 bytes)
+static int rbd_obj_copyup_empty_snapc(struct rbd_obj_request *obj_req,
+ u32 bytes)
{
+ struct ceph_osd_request *osd_req;
int ret;
dout("%s obj_req %p bytes %u\n", __func__, obj_req, bytes);
- rbd_assert(obj_req->osd_req->r_ops[0].op == CEPH_OSD_OP_STAT);
rbd_assert(bytes > 0 && bytes != MODS_ONLY);
- rbd_osd_req_destroy(obj_req->osd_req);
- obj_req->osd_req = __rbd_osd_req_create(obj_req, &rbd_empty_snapc, 1);
- if (!obj_req->osd_req)
- return -ENOMEM;
+ osd_req = __rbd_obj_add_osd_request(obj_req, &rbd_empty_snapc, 1);
+ if (IS_ERR(osd_req))
+ return PTR_ERR(osd_req);
- ret = osd_req_op_cls_init(obj_req->osd_req, 0, "rbd", "copyup");
+ ret = rbd_osd_setup_copyup(osd_req, 0, bytes);
if (ret)
return ret;
- osd_req_op_cls_request_data_bvecs(obj_req->osd_req, 0,
- obj_req->copyup_bvecs,
- obj_req->copyup_bvec_count,
- bytes);
- rbd_osd_req_format_write(obj_req);
+ rbd_osd_format_write(osd_req);
- ret = ceph_osdc_alloc_messages(obj_req->osd_req, GFP_NOIO);
+ ret = ceph_osdc_alloc_messages(osd_req, GFP_NOIO);
if (ret)
return ret;
- rbd_obj_request_submit(obj_req);
+ rbd_osd_submit(osd_req);
return 0;
}
-static int rbd_obj_issue_copyup_ops(struct rbd_obj_request *obj_req, u32 bytes)
+static int rbd_obj_copyup_current_snapc(struct rbd_obj_request *obj_req,
+ u32 bytes)
{
- struct rbd_img_request *img_req = obj_req->img_request;
- unsigned int num_osd_ops = (bytes != MODS_ONLY);
- unsigned int which = 0;
+ struct ceph_osd_request *osd_req;
+ int num_ops = count_write_ops(obj_req);
+ int which = 0;
int ret;
dout("%s obj_req %p bytes %u\n", __func__, obj_req, bytes);
- rbd_assert(obj_req->osd_req->r_ops[0].op == CEPH_OSD_OP_STAT ||
- obj_req->osd_req->r_ops[0].op == CEPH_OSD_OP_CALL);
- rbd_osd_req_destroy(obj_req->osd_req);
- switch (img_req->op_type) {
- case OBJ_OP_WRITE:
- num_osd_ops += count_write_ops(obj_req);
- break;
- case OBJ_OP_ZEROOUT:
- num_osd_ops += count_zeroout_ops(obj_req);
- break;
- default:
- BUG();
- }
+ if (bytes != MODS_ONLY)
+ num_ops++; /* copyup */
- obj_req->osd_req = rbd_osd_req_create(obj_req, num_osd_ops);
- if (!obj_req->osd_req)
- return -ENOMEM;
+ osd_req = rbd_obj_add_osd_request(obj_req, num_ops);
+ if (IS_ERR(osd_req))
+ return PTR_ERR(osd_req);
if (bytes != MODS_ONLY) {
- ret = osd_req_op_cls_init(obj_req->osd_req, which, "rbd",
- "copyup");
+ ret = rbd_osd_setup_copyup(osd_req, which++, bytes);
if (ret)
return ret;
-
- osd_req_op_cls_request_data_bvecs(obj_req->osd_req, which++,
- obj_req->copyup_bvecs,
- obj_req->copyup_bvec_count,
- bytes);
}
- switch (img_req->op_type) {
- case OBJ_OP_WRITE:
- __rbd_obj_setup_write(obj_req, which);
- break;
- case OBJ_OP_ZEROOUT:
- __rbd_obj_setup_zeroout(obj_req, which);
- break;
- default:
- BUG();
- }
+ rbd_osd_setup_write_ops(osd_req, which);
+ rbd_osd_format_write(osd_req);
- ret = ceph_osdc_alloc_messages(obj_req->osd_req, GFP_NOIO);
+ ret = ceph_osdc_alloc_messages(osd_req, GFP_NOIO);
if (ret)
return ret;
- rbd_obj_request_submit(obj_req);
+ rbd_osd_submit(osd_req);
return 0;
}
-static int rbd_obj_issue_copyup(struct rbd_obj_request *obj_req, u32 bytes)
-{
- /*
- * Only send non-zero copyup data to save some I/O and network
- * bandwidth -- zero copyup data is equivalent to the object not
- * existing.
- */
- if (is_zero_bvecs(obj_req->copyup_bvecs, bytes)) {
- dout("%s obj_req %p detected zeroes\n", __func__, obj_req);
- bytes = 0;
- }
-
- if (obj_req->img_request->snapc->num_snaps && bytes > 0) {
- /*
- * Send a copyup request with an empty snapshot context to
- * deep-copyup the object through all existing snapshots.
- * A second request with the current snapshot context will be
- * sent for the actual modification.
- */
- obj_req->write_state = RBD_OBJ_WRITE_COPYUP_EMPTY_SNAPC;
- return rbd_obj_issue_copyup_empty_snapc(obj_req, bytes);
- }
-
- obj_req->write_state = RBD_OBJ_WRITE_COPYUP_OPS;
- return rbd_obj_issue_copyup_ops(obj_req, bytes);
-}
-
static int setup_copyup_bvecs(struct rbd_obj_request *obj_req, u64 obj_overlap)
{
u32 i;
@@ -2608,7 +3222,12 @@ static int setup_copyup_bvecs(struct rbd_obj_request *obj_req, u64 obj_overlap)
return 0;
}
-static int rbd_obj_handle_write_guard(struct rbd_obj_request *obj_req)
+/*
+ * The target object doesn't exist. Read the data for the entire
+ * target object up to the overlap point (if any) from the parent,
+ * so we can use it for a copyup.
+ */
+static int rbd_obj_copyup_read_parent(struct rbd_obj_request *obj_req)
{
struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
int ret;
@@ -2623,178 +3242,492 @@ static int rbd_obj_handle_write_guard(struct rbd_obj_request *obj_req)
* request -- pass MODS_ONLY since the copyup isn't needed
* anymore.
*/
- obj_req->write_state = RBD_OBJ_WRITE_COPYUP_OPS;
- return rbd_obj_issue_copyup_ops(obj_req, MODS_ONLY);
+ return rbd_obj_copyup_current_snapc(obj_req, MODS_ONLY);
}
ret = setup_copyup_bvecs(obj_req, rbd_obj_img_extents_bytes(obj_req));
if (ret)
return ret;
- obj_req->write_state = RBD_OBJ_WRITE_READ_FROM_PARENT;
return rbd_obj_read_from_parent(obj_req);
}
-static bool rbd_obj_handle_write(struct rbd_obj_request *obj_req)
+static void rbd_obj_copyup_object_maps(struct rbd_obj_request *obj_req)
{
+ struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
+ struct ceph_snap_context *snapc = obj_req->img_request->snapc;
+ u8 new_state;
+ u32 i;
int ret;
- switch (obj_req->write_state) {
- case RBD_OBJ_WRITE_GUARD:
- rbd_assert(!obj_req->xferred);
- if (obj_req->result == -ENOENT) {
- /*
- * The target object doesn't exist. Read the data for
- * the entire target object up to the overlap point (if
- * any) from the parent, so we can use it for a copyup.
- */
- ret = rbd_obj_handle_write_guard(obj_req);
- if (ret) {
- obj_req->result = ret;
- return true;
- }
- return false;
+ rbd_assert(!obj_req->pending.result && !obj_req->pending.num_pending);
+
+ if (!(rbd_dev->header.features & RBD_FEATURE_OBJECT_MAP))
+ return;
+
+ if (obj_req->flags & RBD_OBJ_FLAG_COPYUP_ZEROS)
+ return;
+
+ for (i = 0; i < snapc->num_snaps; i++) {
+ if ((rbd_dev->header.features & RBD_FEATURE_FAST_DIFF) &&
+ i + 1 < snapc->num_snaps)
+ new_state = OBJECT_EXISTS_CLEAN;
+ else
+ new_state = OBJECT_EXISTS;
+
+ ret = rbd_object_map_update(obj_req, snapc->snaps[i],
+ new_state, NULL);
+ if (ret < 0) {
+ obj_req->pending.result = ret;
+ return;
}
- /* fall through */
- case RBD_OBJ_WRITE_FLAT:
- case RBD_OBJ_WRITE_COPYUP_OPS:
- if (!obj_req->result)
- /*
- * There is no such thing as a successful short
- * write -- indicate the whole request was satisfied.
- */
- obj_req->xferred = obj_req->ex.oe_len;
- return true;
- case RBD_OBJ_WRITE_READ_FROM_PARENT:
- if (obj_req->result)
- return true;
- rbd_assert(obj_req->xferred);
- ret = rbd_obj_issue_copyup(obj_req, obj_req->xferred);
+ rbd_assert(!ret);
+ obj_req->pending.num_pending++;
+ }
+}
+
+static void rbd_obj_copyup_write_object(struct rbd_obj_request *obj_req)
+{
+ u32 bytes = rbd_obj_img_extents_bytes(obj_req);
+ int ret;
+
+ rbd_assert(!obj_req->pending.result && !obj_req->pending.num_pending);
+
+ /*
+ * Only send non-zero copyup data to save some I/O and network
+ * bandwidth -- zero copyup data is equivalent to the object not
+ * existing.
+ */
+ if (obj_req->flags & RBD_OBJ_FLAG_COPYUP_ZEROS)
+ bytes = 0;
+
+ if (obj_req->img_request->snapc->num_snaps && bytes > 0) {
+ /*
+ * Send a copyup request with an empty snapshot context to
+ * deep-copyup the object through all existing snapshots.
+ * A second request with the current snapshot context will be
+ * sent for the actual modification.
+ */
+ ret = rbd_obj_copyup_empty_snapc(obj_req, bytes);
+ if (ret) {
+ obj_req->pending.result = ret;
+ return;
+ }
+
+ obj_req->pending.num_pending++;
+ bytes = MODS_ONLY;
+ }
+
+ ret = rbd_obj_copyup_current_snapc(obj_req, bytes);
+ if (ret) {
+ obj_req->pending.result = ret;
+ return;
+ }
+
+ obj_req->pending.num_pending++;
+}
+
+static bool rbd_obj_advance_copyup(struct rbd_obj_request *obj_req, int *result)
+{
+ struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
+ int ret;
+
+again:
+ switch (obj_req->copyup_state) {
+ case RBD_OBJ_COPYUP_START:
+ rbd_assert(!*result);
+
+ ret = rbd_obj_copyup_read_parent(obj_req);
if (ret) {
- obj_req->result = ret;
- obj_req->xferred = 0;
+ *result = ret;
return true;
}
+ if (obj_req->num_img_extents)
+ obj_req->copyup_state = RBD_OBJ_COPYUP_READ_PARENT;
+ else
+ obj_req->copyup_state = RBD_OBJ_COPYUP_WRITE_OBJECT;
return false;
- case RBD_OBJ_WRITE_COPYUP_EMPTY_SNAPC:
- if (obj_req->result)
+ case RBD_OBJ_COPYUP_READ_PARENT:
+ if (*result)
return true;
- obj_req->write_state = RBD_OBJ_WRITE_COPYUP_OPS;
- ret = rbd_obj_issue_copyup_ops(obj_req, MODS_ONLY);
- if (ret) {
- obj_req->result = ret;
+ if (is_zero_bvecs(obj_req->copyup_bvecs,
+ rbd_obj_img_extents_bytes(obj_req))) {
+ dout("%s %p detected zeros\n", __func__, obj_req);
+ obj_req->flags |= RBD_OBJ_FLAG_COPYUP_ZEROS;
+ }
+
+ rbd_obj_copyup_object_maps(obj_req);
+ if (!obj_req->pending.num_pending) {
+ *result = obj_req->pending.result;
+ obj_req->copyup_state = RBD_OBJ_COPYUP_OBJECT_MAPS;
+ goto again;
+ }
+ obj_req->copyup_state = __RBD_OBJ_COPYUP_OBJECT_MAPS;
+ return false;
+ case __RBD_OBJ_COPYUP_OBJECT_MAPS:
+ if (!pending_result_dec(&obj_req->pending, result))
+ return false;
+ /* fall through */
+ case RBD_OBJ_COPYUP_OBJECT_MAPS:
+ if (*result) {
+ rbd_warn(rbd_dev, "snap object map update failed: %d",
+ *result);
return true;
}
+
+ rbd_obj_copyup_write_object(obj_req);
+ if (!obj_req->pending.num_pending) {
+ *result = obj_req->pending.result;
+ obj_req->copyup_state = RBD_OBJ_COPYUP_WRITE_OBJECT;
+ goto again;
+ }
+ obj_req->copyup_state = __RBD_OBJ_COPYUP_WRITE_OBJECT;
return false;
+ case __RBD_OBJ_COPYUP_WRITE_OBJECT:
+ if (!pending_result_dec(&obj_req->pending, result))
+ return false;
+ /* fall through */
+ case RBD_OBJ_COPYUP_WRITE_OBJECT:
+ return true;
default:
BUG();
}
}
/*
- * Returns true if @obj_req is completed, or false otherwise.
+ * Return:
+ * 0 - object map update sent
+ * 1 - object map update isn't needed
+ * <0 - error
*/
-static bool __rbd_obj_handle_request(struct rbd_obj_request *obj_req)
+static int rbd_obj_write_post_object_map(struct rbd_obj_request *obj_req)
{
- switch (obj_req->img_request->op_type) {
- case OBJ_OP_READ:
- return rbd_obj_handle_read(obj_req);
- case OBJ_OP_WRITE:
- return rbd_obj_handle_write(obj_req);
- case OBJ_OP_DISCARD:
- case OBJ_OP_ZEROOUT:
- if (rbd_obj_handle_write(obj_req)) {
+ struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
+ u8 current_state = OBJECT_PENDING;
+
+ if (!(rbd_dev->header.features & RBD_FEATURE_OBJECT_MAP))
+ return 1;
+
+ if (!(obj_req->flags & RBD_OBJ_FLAG_DELETION))
+ return 1;
+
+ return rbd_object_map_update(obj_req, CEPH_NOSNAP, OBJECT_NONEXISTENT,
+ &current_state);
+}
+
+static bool rbd_obj_advance_write(struct rbd_obj_request *obj_req, int *result)
+{
+ struct rbd_device *rbd_dev = obj_req->img_request->rbd_dev;
+ int ret;
+
+again:
+ switch (obj_req->write_state) {
+ case RBD_OBJ_WRITE_START:
+ rbd_assert(!*result);
+
+ if (rbd_obj_write_is_noop(obj_req))
+ return true;
+
+ ret = rbd_obj_write_pre_object_map(obj_req);
+ if (ret < 0) {
+ *result = ret;
+ return true;
+ }
+ obj_req->write_state = RBD_OBJ_WRITE_PRE_OBJECT_MAP;
+ if (ret > 0)
+ goto again;
+ return false;
+ case RBD_OBJ_WRITE_PRE_OBJECT_MAP:
+ if (*result) {
+ rbd_warn(rbd_dev, "pre object map update failed: %d",
+ *result);
+ return true;
+ }
+ ret = rbd_obj_write_object(obj_req);
+ if (ret) {
+ *result = ret;
+ return true;
+ }
+ obj_req->write_state = RBD_OBJ_WRITE_OBJECT;
+ return false;
+ case RBD_OBJ_WRITE_OBJECT:
+ if (*result == -ENOENT) {
+ if (obj_req->flags & RBD_OBJ_FLAG_COPYUP_ENABLED) {
+ *result = 0;
+ obj_req->copyup_state = RBD_OBJ_COPYUP_START;
+ obj_req->write_state = __RBD_OBJ_WRITE_COPYUP;
+ goto again;
+ }
/*
- * Hide -ENOENT from delete/truncate/zero -- discarding
- * a non-existent object is not a problem.
+ * On a non-existent object:
+ * delete - -ENOENT, truncate/zero - 0
*/
- if (obj_req->result == -ENOENT) {
- obj_req->result = 0;
- obj_req->xferred = obj_req->ex.oe_len;
- }
+ if (obj_req->flags & RBD_OBJ_FLAG_DELETION)
+ *result = 0;
+ }
+ if (*result)
+ return true;
+
+ obj_req->write_state = RBD_OBJ_WRITE_COPYUP;
+ goto again;
+ case __RBD_OBJ_WRITE_COPYUP:
+ if (!rbd_obj_advance_copyup(obj_req, result))
+ return false;
+ /* fall through */
+ case RBD_OBJ_WRITE_COPYUP:
+ if (*result) {
+ rbd_warn(rbd_dev, "copyup failed: %d", *result);
+ return true;
+ }
+ ret = rbd_obj_write_post_object_map(obj_req);
+ if (ret < 0) {
+ *result = ret;
return true;
}
+ obj_req->write_state = RBD_OBJ_WRITE_POST_OBJECT_MAP;
+ if (ret > 0)
+ goto again;
return false;
+ case RBD_OBJ_WRITE_POST_OBJECT_MAP:
+ if (*result)
+ rbd_warn(rbd_dev, "post object map update failed: %d",
+ *result);
+ return true;
default:
BUG();
}
}
-static void rbd_obj_end_request(struct rbd_obj_request *obj_req)
+/*
+ * Return true if @obj_req is completed.
+ */
+static bool __rbd_obj_handle_request(struct rbd_obj_request *obj_req,
+ int *result)
{
struct rbd_img_request *img_req = obj_req->img_request;
+ struct rbd_device *rbd_dev = img_req->rbd_dev;
+ bool done;
- rbd_assert((!obj_req->result &&
- obj_req->xferred == obj_req->ex.oe_len) ||
- (obj_req->result < 0 && !obj_req->xferred));
- if (!obj_req->result) {
- img_req->xferred += obj_req->xferred;
- return;
- }
+ mutex_lock(&obj_req->state_mutex);
+ if (!rbd_img_is_write(img_req))
+ done = rbd_obj_advance_read(obj_req, result);
+ else
+ done = rbd_obj_advance_write(obj_req, result);
+ mutex_unlock(&obj_req->state_mutex);
- rbd_warn(img_req->rbd_dev,
- "%s at objno %llu %llu~%llu result %d xferred %llu",
- obj_op_name(img_req->op_type), obj_req->ex.oe_objno,
- obj_req->ex.oe_off, obj_req->ex.oe_len, obj_req->result,
- obj_req->xferred);
- if (!img_req->result) {
- img_req->result = obj_req->result;
- img_req->xferred = 0;
+ if (done && *result) {
+ rbd_assert(*result < 0);
+ rbd_warn(rbd_dev, "%s at objno %llu %llu~%llu result %d",
+ obj_op_name(img_req->op_type), obj_req->ex.oe_objno,
+ obj_req->ex.oe_off, obj_req->ex.oe_len, *result);
}
+ return done;
}
-static void rbd_img_end_child_request(struct rbd_img_request *img_req)
+/*
+ * This is open-coded in rbd_img_handle_request() to avoid parent chain
+ * recursion.
+ */
+static void rbd_obj_handle_request(struct rbd_obj_request *obj_req, int result)
{
- struct rbd_obj_request *obj_req = img_req->obj_request;
+ if (__rbd_obj_handle_request(obj_req, &result))
+ rbd_img_handle_request(obj_req->img_request, result);
+}
- rbd_assert(test_bit(IMG_REQ_CHILD, &img_req->flags));
- rbd_assert((!img_req->result &&
- img_req->xferred == rbd_obj_img_extents_bytes(obj_req)) ||
- (img_req->result < 0 && !img_req->xferred));
+static bool need_exclusive_lock(struct rbd_img_request *img_req)
+{
+ struct rbd_device *rbd_dev = img_req->rbd_dev;
- obj_req->result = img_req->result;
- obj_req->xferred = img_req->xferred;
- rbd_img_request_put(img_req);
+ if (!(rbd_dev->header.features & RBD_FEATURE_EXCLUSIVE_LOCK))
+ return false;
+
+ if (rbd_dev->spec->snap_id != CEPH_NOSNAP)
+ return false;
+
+ rbd_assert(!test_bit(IMG_REQ_CHILD, &img_req->flags));
+ if (rbd_dev->opts->lock_on_read ||
+ (rbd_dev->header.features & RBD_FEATURE_OBJECT_MAP))
+ return true;
+
+ return rbd_img_is_write(img_req);
}
-static void rbd_img_end_request(struct rbd_img_request *img_req)
+static bool rbd_lock_add_request(struct rbd_img_request *img_req)
{
- rbd_assert(!test_bit(IMG_REQ_CHILD, &img_req->flags));
- rbd_assert((!img_req->result &&
- img_req->xferred == blk_rq_bytes(img_req->rq)) ||
- (img_req->result < 0 && !img_req->xferred));
+ struct rbd_device *rbd_dev = img_req->rbd_dev;
+ bool locked;
+
+ lockdep_assert_held(&rbd_dev->lock_rwsem);
+ locked = rbd_dev->lock_state == RBD_LOCK_STATE_LOCKED;
+ spin_lock(&rbd_dev->lock_lists_lock);
+ rbd_assert(list_empty(&img_req->lock_item));
+ if (!locked)
+ list_add_tail(&img_req->lock_item, &rbd_dev->acquiring_list);
+ else
+ list_add_tail(&img_req->lock_item, &rbd_dev->running_list);
+ spin_unlock(&rbd_dev->lock_lists_lock);
+ return locked;
+}
+
+static void rbd_lock_del_request(struct rbd_img_request *img_req)
+{
+ struct rbd_device *rbd_dev = img_req->rbd_dev;
+ bool need_wakeup;
- blk_mq_end_request(img_req->rq,
- errno_to_blk_status(img_req->result));
- rbd_img_request_put(img_req);
+ lockdep_assert_held(&rbd_dev->lock_rwsem);
+ spin_lock(&rbd_dev->lock_lists_lock);
+ rbd_assert(!list_empty(&img_req->lock_item));
+ list_del_init(&img_req->lock_item);
+ need_wakeup = (rbd_dev->lock_state == RBD_LOCK_STATE_RELEASING &&
+ list_empty(&rbd_dev->running_list));
+ spin_unlock(&rbd_dev->lock_lists_lock);
+ if (need_wakeup)
+ complete(&rbd_dev->releasing_wait);
}
-static void rbd_obj_handle_request(struct rbd_obj_request *obj_req)
+static int rbd_img_exclusive_lock(struct rbd_img_request *img_req)
{
- struct rbd_img_request *img_req;
+ struct rbd_device *rbd_dev = img_req->rbd_dev;
+
+ if (!need_exclusive_lock(img_req))
+ return 1;
+
+ if (rbd_lock_add_request(img_req))
+ return 1;
+
+ if (rbd_dev->opts->exclusive) {
+ WARN_ON(1); /* lock got released? */
+ return -EROFS;
+ }
+
+ /*
+ * Note the use of mod_delayed_work() in rbd_acquire_lock()
+ * and cancel_delayed_work() in wake_lock_waiters().
+ */
+ dout("%s rbd_dev %p queueing lock_dwork\n", __func__, rbd_dev);
+ queue_delayed_work(rbd_dev->task_wq, &rbd_dev->lock_dwork, 0);
+ return 0;
+}
+
+static void rbd_img_object_requests(struct rbd_img_request *img_req)
+{
+ struct rbd_obj_request *obj_req;
+
+ rbd_assert(!img_req->pending.result && !img_req->pending.num_pending);
+
+ for_each_obj_request(img_req, obj_req) {
+ int result = 0;
+
+ if (__rbd_obj_handle_request(obj_req, &result)) {
+ if (result) {
+ img_req->pending.result = result;
+ return;
+ }
+ } else {
+ img_req->pending.num_pending++;
+ }
+ }
+}
+
+static bool rbd_img_advance(struct rbd_img_request *img_req, int *result)
+{
+ struct rbd_device *rbd_dev = img_req->rbd_dev;
+ int ret;
again:
- if (!__rbd_obj_handle_request(obj_req))
- return;
+ switch (img_req->state) {
+ case RBD_IMG_START:
+ rbd_assert(!*result);
- img_req = obj_req->img_request;
- spin_lock(&img_req->completion_lock);
- rbd_obj_end_request(obj_req);
- rbd_assert(img_req->pending_count);
- if (--img_req->pending_count) {
- spin_unlock(&img_req->completion_lock);
- return;
+ ret = rbd_img_exclusive_lock(img_req);
+ if (ret < 0) {
+ *result = ret;
+ return true;
+ }
+ img_req->state = RBD_IMG_EXCLUSIVE_LOCK;
+ if (ret > 0)
+ goto again;
+ return false;
+ case RBD_IMG_EXCLUSIVE_LOCK:
+ if (*result)
+ return true;
+
+ rbd_assert(!need_exclusive_lock(img_req) ||
+ __rbd_is_lock_owner(rbd_dev));
+
+ rbd_img_object_requests(img_req);
+ if (!img_req->pending.num_pending) {
+ *result = img_req->pending.result;
+ img_req->state = RBD_IMG_OBJECT_REQUESTS;
+ goto again;
+ }
+ img_req->state = __RBD_IMG_OBJECT_REQUESTS;
+ return false;
+ case __RBD_IMG_OBJECT_REQUESTS:
+ if (!pending_result_dec(&img_req->pending, result))
+ return false;
+ /* fall through */
+ case RBD_IMG_OBJECT_REQUESTS:
+ return true;
+ default:
+ BUG();
+ }
+}
+
+/*
+ * Return true if @img_req is completed.
+ */
+static bool __rbd_img_handle_request(struct rbd_img_request *img_req,
+ int *result)
+{
+ struct rbd_device *rbd_dev = img_req->rbd_dev;
+ bool done;
+
+ if (need_exclusive_lock(img_req)) {
+ down_read(&rbd_dev->lock_rwsem);
+ mutex_lock(&img_req->state_mutex);
+ done = rbd_img_advance(img_req, result);
+ if (done)
+ rbd_lock_del_request(img_req);
+ mutex_unlock(&img_req->state_mutex);
+ up_read(&rbd_dev->lock_rwsem);
+ } else {
+ mutex_lock(&img_req->state_mutex);
+ done = rbd_img_advance(img_req, result);
+ mutex_unlock(&img_req->state_mutex);
+ }
+
+ if (done && *result) {
+ rbd_assert(*result < 0);
+ rbd_warn(rbd_dev, "%s%s result %d",
+ test_bit(IMG_REQ_CHILD, &img_req->flags) ? "child " : "",
+ obj_op_name(img_req->op_type), *result);
}
+ return done;
+}
+
+static void rbd_img_handle_request(struct rbd_img_request *img_req, int result)
+{
+again:
+ if (!__rbd_img_handle_request(img_req, &result))
+ return;
- spin_unlock(&img_req->completion_lock);
if (test_bit(IMG_REQ_CHILD, &img_req->flags)) {
- obj_req = img_req->obj_request;
- rbd_img_end_child_request(img_req);
- goto again;
+ struct rbd_obj_request *obj_req = img_req->obj_request;
+
+ rbd_img_request_put(img_req);
+ if (__rbd_obj_handle_request(obj_req, &result)) {
+ img_req = obj_req->img_request;
+ goto again;
+ }
+ } else {
+ struct request *rq = img_req->rq;
+
+ rbd_img_request_put(img_req);
+ blk_mq_end_request(rq, errno_to_blk_status(result));
}
- rbd_img_end_request(img_req);
}
static const struct rbd_client_id rbd_empty_cid;
@@ -2839,6 +3772,7 @@ static void __rbd_lock(struct rbd_device *rbd_dev, const char *cookie)
{
struct rbd_client_id cid = rbd_get_cid(rbd_dev);
+ rbd_dev->lock_state = RBD_LOCK_STATE_LOCKED;
strcpy(rbd_dev->lock_cookie, cookie);
rbd_set_owner_cid(rbd_dev, &cid);
queue_work(rbd_dev->task_wq, &rbd_dev->acquired_lock_work);
@@ -2863,7 +3797,6 @@ static int rbd_lock(struct rbd_device *rbd_dev)
if (ret)
return ret;
- rbd_dev->lock_state = RBD_LOCK_STATE_LOCKED;
__rbd_lock(rbd_dev, cookie);
return 0;
}
@@ -2882,7 +3815,7 @@ static void rbd_unlock(struct rbd_device *rbd_dev)
ret = ceph_cls_unlock(osdc, &rbd_dev->header_oid, &rbd_dev->header_oloc,
RBD_LOCK_NAME, rbd_dev->lock_cookie);
if (ret && ret != -ENOENT)
- rbd_warn(rbd_dev, "failed to unlock: %d", ret);
+ rbd_warn(rbd_dev, "failed to unlock header: %d", ret);
/* treat errors as the image is unlocked */
rbd_dev->lock_state = RBD_LOCK_STATE_UNLOCKED;
@@ -3009,15 +3942,34 @@ e_inval:
goto out;
}
-static void wake_requests(struct rbd_device *rbd_dev, bool wake_all)
+/*
+ * Either image request state machine(s) or rbd_add_acquire_lock()
+ * (i.e. "rbd map").
+ */
+static void wake_lock_waiters(struct rbd_device *rbd_dev, int result)
{
- dout("%s rbd_dev %p wake_all %d\n", __func__, rbd_dev, wake_all);
+ struct rbd_img_request *img_req;
+
+ dout("%s rbd_dev %p result %d\n", __func__, rbd_dev, result);
+ lockdep_assert_held_write(&rbd_dev->lock_rwsem);
cancel_delayed_work(&rbd_dev->lock_dwork);
- if (wake_all)
- wake_up_all(&rbd_dev->lock_waitq);
- else
- wake_up(&rbd_dev->lock_waitq);
+ if (!completion_done(&rbd_dev->acquire_wait)) {
+ rbd_assert(list_empty(&rbd_dev->acquiring_list) &&
+ list_empty(&rbd_dev->running_list));
+ rbd_dev->acquire_err = result;
+ complete_all(&rbd_dev->acquire_wait);
+ return;
+ }
+
+ list_for_each_entry(img_req, &rbd_dev->acquiring_list, lock_item) {
+ mutex_lock(&img_req->state_mutex);
+ rbd_assert(img_req->state == RBD_IMG_EXCLUSIVE_LOCK);
+ rbd_img_schedule(img_req, result);
+ mutex_unlock(&img_req->state_mutex);
+ }
+
+ list_splice_tail_init(&rbd_dev->acquiring_list, &rbd_dev->running_list);
}
static int get_lock_owner_info(struct rbd_device *rbd_dev,
@@ -3132,13 +4084,10 @@ static int rbd_try_lock(struct rbd_device *rbd_dev)
goto again;
ret = find_watcher(rbd_dev, lockers);
- if (ret) {
- if (ret > 0)
- ret = 0; /* have to request lock */
- goto out;
- }
+ if (ret)
+ goto out; /* request lock or error */
- rbd_warn(rbd_dev, "%s%llu seems dead, breaking lock",
+ rbd_warn(rbd_dev, "breaking header lock owned by %s%llu",
ENTITY_NAME(lockers[0].id.name));
ret = ceph_monc_blacklist_add(&client->monc,
@@ -3165,53 +4114,90 @@ out:
return ret;
}
+static int rbd_post_acquire_action(struct rbd_device *rbd_dev)
+{
+ int ret;
+
+ if (rbd_dev->header.features & RBD_FEATURE_OBJECT_MAP) {
+ ret = rbd_object_map_open(rbd_dev);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
/*
- * ret is set only if lock_state is RBD_LOCK_STATE_UNLOCKED
+ * Return:
+ * 0 - lock acquired
+ * 1 - caller should call rbd_request_lock()
+ * <0 - error
*/
-static enum rbd_lock_state rbd_try_acquire_lock(struct rbd_device *rbd_dev,
- int *pret)
+static int rbd_try_acquire_lock(struct rbd_device *rbd_dev)
{
- enum rbd_lock_state lock_state;
+ int ret;
down_read(&rbd_dev->lock_rwsem);
dout("%s rbd_dev %p read lock_state %d\n", __func__, rbd_dev,
rbd_dev->lock_state);
if (__rbd_is_lock_owner(rbd_dev)) {
- lock_state = rbd_dev->lock_state;
up_read(&rbd_dev->lock_rwsem);
- return lock_state;
+ return 0;
}
up_read(&rbd_dev->lock_rwsem);
down_write(&rbd_dev->lock_rwsem);
dout("%s rbd_dev %p write lock_state %d\n", __func__, rbd_dev,
rbd_dev->lock_state);
- if (!__rbd_is_lock_owner(rbd_dev)) {
- *pret = rbd_try_lock(rbd_dev);
- if (*pret)
- rbd_warn(rbd_dev, "failed to acquire lock: %d", *pret);
+ if (__rbd_is_lock_owner(rbd_dev)) {
+ up_write(&rbd_dev->lock_rwsem);
+ return 0;
+ }
+
+ ret = rbd_try_lock(rbd_dev);
+ if (ret < 0) {
+ rbd_warn(rbd_dev, "failed to lock header: %d", ret);
+ if (ret == -EBLACKLISTED)
+ goto out;
+
+ ret = 1; /* request lock anyway */
+ }
+ if (ret > 0) {
+ up_write(&rbd_dev->lock_rwsem);
+ return ret;
+ }
+
+ rbd_assert(rbd_dev->lock_state == RBD_LOCK_STATE_LOCKED);
+ rbd_assert(list_empty(&rbd_dev->running_list));
+
+ ret = rbd_post_acquire_action(rbd_dev);
+ if (ret) {
+ rbd_warn(rbd_dev, "post-acquire action failed: %d", ret);
+ /*
+ * Can't stay in RBD_LOCK_STATE_LOCKED because
+ * rbd_lock_add_request() would let the request through,
+ * assuming that e.g. object map is locked and loaded.
+ */
+ rbd_unlock(rbd_dev);
}
- lock_state = rbd_dev->lock_state;
+out:
+ wake_lock_waiters(rbd_dev, ret);
up_write(&rbd_dev->lock_rwsem);
- return lock_state;
+ return ret;
}
static void rbd_acquire_lock(struct work_struct *work)
{
struct rbd_device *rbd_dev = container_of(to_delayed_work(work),
struct rbd_device, lock_dwork);
- enum rbd_lock_state lock_state;
- int ret = 0;
+ int ret;
dout("%s rbd_dev %p\n", __func__, rbd_dev);
again:
- lock_state = rbd_try_acquire_lock(rbd_dev, &ret);
- if (lock_state != RBD_LOCK_STATE_UNLOCKED || ret == -EBLACKLISTED) {
- if (lock_state == RBD_LOCK_STATE_LOCKED)
- wake_requests(rbd_dev, true);
- dout("%s rbd_dev %p lock_state %d ret %d - done\n", __func__,
- rbd_dev, lock_state, ret);
+ ret = rbd_try_acquire_lock(rbd_dev);
+ if (ret <= 0) {
+ dout("%s rbd_dev %p ret %d - done\n", __func__, rbd_dev, ret);
return;
}
@@ -3220,16 +4206,9 @@ again:
goto again; /* treat this as a dead client */
} else if (ret == -EROFS) {
rbd_warn(rbd_dev, "peer will not release lock");
- /*
- * If this is rbd_add_acquire_lock(), we want to fail
- * immediately -- reuse BLACKLISTED flag. Otherwise we
- * want to block.
- */
- if (!(rbd_dev->disk->flags & GENHD_FL_UP)) {
- set_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags);
- /* wake "rbd map --exclusive" process */
- wake_requests(rbd_dev, false);
- }
+ down_write(&rbd_dev->lock_rwsem);
+ wake_lock_waiters(rbd_dev, ret);
+ up_write(&rbd_dev->lock_rwsem);
} else if (ret < 0) {
rbd_warn(rbd_dev, "error requesting lock: %d", ret);
mod_delayed_work(rbd_dev->task_wq, &rbd_dev->lock_dwork,
@@ -3246,43 +4225,67 @@ again:
}
}
-/*
- * lock_rwsem must be held for write
- */
-static bool rbd_release_lock(struct rbd_device *rbd_dev)
+static bool rbd_quiesce_lock(struct rbd_device *rbd_dev)
{
- dout("%s rbd_dev %p read lock_state %d\n", __func__, rbd_dev,
- rbd_dev->lock_state);
+ bool need_wait;
+
+ dout("%s rbd_dev %p\n", __func__, rbd_dev);
+ lockdep_assert_held_write(&rbd_dev->lock_rwsem);
+
if (rbd_dev->lock_state != RBD_LOCK_STATE_LOCKED)
return false;
- rbd_dev->lock_state = RBD_LOCK_STATE_RELEASING;
- downgrade_write(&rbd_dev->lock_rwsem);
/*
* Ensure that all in-flight IO is flushed.
- *
- * FIXME: ceph_osdc_sync() flushes the entire OSD client, which
- * may be shared with other devices.
*/
- ceph_osdc_sync(&rbd_dev->rbd_client->client->osdc);
+ rbd_dev->lock_state = RBD_LOCK_STATE_RELEASING;
+ rbd_assert(!completion_done(&rbd_dev->releasing_wait));
+ need_wait = !list_empty(&rbd_dev->running_list);
+ downgrade_write(&rbd_dev->lock_rwsem);
+ if (need_wait)
+ wait_for_completion(&rbd_dev->releasing_wait);
up_read(&rbd_dev->lock_rwsem);
down_write(&rbd_dev->lock_rwsem);
- dout("%s rbd_dev %p write lock_state %d\n", __func__, rbd_dev,
- rbd_dev->lock_state);
if (rbd_dev->lock_state != RBD_LOCK_STATE_RELEASING)
return false;
+ rbd_assert(list_empty(&rbd_dev->running_list));
+ return true;
+}
+
+static void rbd_pre_release_action(struct rbd_device *rbd_dev)
+{
+ if (rbd_dev->header.features & RBD_FEATURE_OBJECT_MAP)
+ rbd_object_map_close(rbd_dev);
+}
+
+static void __rbd_release_lock(struct rbd_device *rbd_dev)
+{
+ rbd_assert(list_empty(&rbd_dev->running_list));
+
+ rbd_pre_release_action(rbd_dev);
rbd_unlock(rbd_dev);
+}
+
+/*
+ * lock_rwsem must be held for write
+ */
+static void rbd_release_lock(struct rbd_device *rbd_dev)
+{
+ if (!rbd_quiesce_lock(rbd_dev))
+ return;
+
+ __rbd_release_lock(rbd_dev);
+
/*
* Give others a chance to grab the lock - we would re-acquire
- * almost immediately if we got new IO during ceph_osdc_sync()
- * otherwise. We need to ack our own notifications, so this
- * lock_dwork will be requeued from rbd_wait_state_locked()
- * after wake_requests() in rbd_handle_released_lock().
+ * almost immediately if we got new IO while draining the running
+ * list otherwise. We need to ack our own notifications, so this
+ * lock_dwork will be requeued from rbd_handle_released_lock() by
+ * way of maybe_kick_acquire().
*/
cancel_delayed_work(&rbd_dev->lock_dwork);
- return true;
}
static void rbd_release_lock_work(struct work_struct *work)
@@ -3295,6 +4298,23 @@ static void rbd_release_lock_work(struct work_struct *work)
up_write(&rbd_dev->lock_rwsem);
}
+static void maybe_kick_acquire(struct rbd_device *rbd_dev)
+{
+ bool have_requests;
+
+ dout("%s rbd_dev %p\n", __func__, rbd_dev);
+ if (__rbd_is_lock_owner(rbd_dev))
+ return;
+
+ spin_lock(&rbd_dev->lock_lists_lock);
+ have_requests = !list_empty(&rbd_dev->acquiring_list);
+ spin_unlock(&rbd_dev->lock_lists_lock);
+ if (have_requests || delayed_work_pending(&rbd_dev->lock_dwork)) {
+ dout("%s rbd_dev %p kicking lock_dwork\n", __func__, rbd_dev);
+ mod_delayed_work(rbd_dev->task_wq, &rbd_dev->lock_dwork, 0);
+ }
+}
+
static void rbd_handle_acquired_lock(struct rbd_device *rbd_dev, u8 struct_v,
void **p)
{
@@ -3324,8 +4344,7 @@ static void rbd_handle_acquired_lock(struct rbd_device *rbd_dev, u8 struct_v,
down_read(&rbd_dev->lock_rwsem);
}
- if (!__rbd_is_lock_owner(rbd_dev))
- wake_requests(rbd_dev, false);
+ maybe_kick_acquire(rbd_dev);
up_read(&rbd_dev->lock_rwsem);
}
@@ -3357,8 +4376,7 @@ static void rbd_handle_released_lock(struct rbd_device *rbd_dev, u8 struct_v,
down_read(&rbd_dev->lock_rwsem);
}
- if (!__rbd_is_lock_owner(rbd_dev))
- wake_requests(rbd_dev, false);
+ maybe_kick_acquire(rbd_dev);
up_read(&rbd_dev->lock_rwsem);
}
@@ -3608,7 +4626,6 @@ static void cancel_tasks_sync(struct rbd_device *rbd_dev)
static void rbd_unregister_watch(struct rbd_device *rbd_dev)
{
- WARN_ON(waitqueue_active(&rbd_dev->lock_waitq));
cancel_tasks_sync(rbd_dev);
mutex_lock(&rbd_dev->watch_mutex);
@@ -3630,7 +4647,8 @@ static void rbd_reacquire_lock(struct rbd_device *rbd_dev)
char cookie[32];
int ret;
- WARN_ON(rbd_dev->lock_state != RBD_LOCK_STATE_LOCKED);
+ if (!rbd_quiesce_lock(rbd_dev))
+ return;
format_lock_cookie(rbd_dev, cookie);
ret = ceph_cls_set_cookie(osdc, &rbd_dev->header_oid,
@@ -3646,11 +4664,11 @@ static void rbd_reacquire_lock(struct rbd_device *rbd_dev)
* Lock cookie cannot be updated on older OSDs, so do
* a manual release and queue an acquire.
*/
- if (rbd_release_lock(rbd_dev))
- queue_delayed_work(rbd_dev->task_wq,
- &rbd_dev->lock_dwork, 0);
+ __rbd_release_lock(rbd_dev);
+ queue_delayed_work(rbd_dev->task_wq, &rbd_dev->lock_dwork, 0);
} else {
__rbd_lock(rbd_dev, cookie);
+ wake_lock_waiters(rbd_dev, 0);
}
}
@@ -3671,15 +4689,18 @@ static void rbd_reregister_watch(struct work_struct *work)
ret = __rbd_register_watch(rbd_dev);
if (ret) {
rbd_warn(rbd_dev, "failed to reregister watch: %d", ret);
- if (ret == -EBLACKLISTED || ret == -ENOENT) {
- set_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags);
- wake_requests(rbd_dev, true);
- } else {
+ if (ret != -EBLACKLISTED && ret != -ENOENT) {
queue_delayed_work(rbd_dev->task_wq,
&rbd_dev->watch_dwork,
RBD_RETRY_DELAY);
+ mutex_unlock(&rbd_dev->watch_mutex);
+ return;
}
+
mutex_unlock(&rbd_dev->watch_mutex);
+ down_write(&rbd_dev->lock_rwsem);
+ wake_lock_waiters(rbd_dev, ret);
+ up_write(&rbd_dev->lock_rwsem);
return;
}
@@ -3742,7 +4763,7 @@ static int rbd_obj_method_sync(struct rbd_device *rbd_dev,
ret = ceph_osdc_call(osdc, oid, oloc, RBD_DRV_NAME, method_name,
CEPH_OSD_FLAG_READ, req_page, outbound_size,
- reply_page, &inbound_size);
+ &reply_page, &inbound_size);
if (!ret) {
memcpy(inbound, page_address(reply_page), inbound_size);
ret = inbound_size;
@@ -3754,54 +4775,6 @@ static int rbd_obj_method_sync(struct rbd_device *rbd_dev,
return ret;
}
-/*
- * lock_rwsem must be held for read
- */
-static int rbd_wait_state_locked(struct rbd_device *rbd_dev, bool may_acquire)
-{
- DEFINE_WAIT(wait);
- unsigned long timeout;
- int ret = 0;
-
- if (test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags))
- return -EBLACKLISTED;
-
- if (rbd_dev->lock_state == RBD_LOCK_STATE_LOCKED)
- return 0;
-
- if (!may_acquire) {
- rbd_warn(rbd_dev, "exclusive lock required");
- return -EROFS;
- }
-
- do {
- /*
- * Note the use of mod_delayed_work() in rbd_acquire_lock()
- * and cancel_delayed_work() in wake_requests().
- */
- dout("%s rbd_dev %p queueing lock_dwork\n", __func__, rbd_dev);
- queue_delayed_work(rbd_dev->task_wq, &rbd_dev->lock_dwork, 0);
- prepare_to_wait_exclusive(&rbd_dev->lock_waitq, &wait,
- TASK_UNINTERRUPTIBLE);
- up_read(&rbd_dev->lock_rwsem);
- timeout = schedule_timeout(ceph_timeout_jiffies(
- rbd_dev->opts->lock_timeout));
- down_read(&rbd_dev->lock_rwsem);
- if (test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags)) {
- ret = -EBLACKLISTED;
- break;
- }
- if (!timeout) {
- rbd_warn(rbd_dev, "timed out waiting for lock");
- ret = -ETIMEDOUT;
- break;
- }
- } while (rbd_dev->lock_state != RBD_LOCK_STATE_LOCKED);
-
- finish_wait(&rbd_dev->lock_waitq, &wait);
- return ret;
-}
-
static void rbd_queue_workfn(struct work_struct *work)
{
struct request *rq = blk_mq_rq_from_pdu(work);
@@ -3812,7 +4785,6 @@ static void rbd_queue_workfn(struct work_struct *work)
u64 length = blk_rq_bytes(rq);
enum obj_operation_type op_type;
u64 mapping_size;
- bool must_be_locked;
int result;
switch (req_op(rq)) {
@@ -3886,21 +4858,10 @@ static void rbd_queue_workfn(struct work_struct *work)
goto err_rq;
}
- must_be_locked =
- (rbd_dev->header.features & RBD_FEATURE_EXCLUSIVE_LOCK) &&
- (op_type != OBJ_OP_READ || rbd_dev->opts->lock_on_read);
- if (must_be_locked) {
- down_read(&rbd_dev->lock_rwsem);
- result = rbd_wait_state_locked(rbd_dev,
- !rbd_dev->opts->exclusive);
- if (result)
- goto err_unlock;
- }
-
img_request = rbd_img_request_create(rbd_dev, op_type, snapc);
if (!img_request) {
result = -ENOMEM;
- goto err_unlock;
+ goto err_rq;
}
img_request->rq = rq;
snapc = NULL; /* img_request consumes a ref */
@@ -3910,19 +4871,14 @@ static void rbd_queue_workfn(struct work_struct *work)
else
result = rbd_img_fill_from_bio(img_request, offset, length,
rq->bio);
- if (result || !img_request->pending_count)
+ if (result)
goto err_img_request;
- rbd_img_request_submit(img_request);
- if (must_be_locked)
- up_read(&rbd_dev->lock_rwsem);
+ rbd_img_handle_request(img_request, 0);
return;
err_img_request:
rbd_img_request_put(img_request);
-err_unlock:
- if (must_be_locked)
- up_read(&rbd_dev->lock_rwsem);
err_rq:
if (result)
rbd_warn(rbd_dev, "%s %llx at %llx result %d",
@@ -4589,7 +5545,13 @@ static struct rbd_device *__rbd_dev_create(struct rbd_client *rbdc,
INIT_WORK(&rbd_dev->released_lock_work, rbd_notify_released_lock);
INIT_DELAYED_WORK(&rbd_dev->lock_dwork, rbd_acquire_lock);
INIT_WORK(&rbd_dev->unlock_work, rbd_release_lock_work);
- init_waitqueue_head(&rbd_dev->lock_waitq);
+ spin_lock_init(&rbd_dev->lock_lists_lock);
+ INIT_LIST_HEAD(&rbd_dev->acquiring_list);
+ INIT_LIST_HEAD(&rbd_dev->running_list);
+ init_completion(&rbd_dev->acquire_wait);
+ init_completion(&rbd_dev->releasing_wait);
+
+ spin_lock_init(&rbd_dev->object_map_lock);
rbd_dev->dev.bus = &rbd_bus_type;
rbd_dev->dev.type = &rbd_device_type;
@@ -4772,6 +5734,32 @@ static int rbd_dev_v2_features(struct rbd_device *rbd_dev)
&rbd_dev->header.features);
}
+/*
+ * These are generic image flags, but since they are used only for
+ * object map, store them in rbd_dev->object_map_flags.
+ *
+ * For the same reason, this function is called only on object map
+ * (re)load and not on header refresh.
+ */
+static int rbd_dev_v2_get_flags(struct rbd_device *rbd_dev)
+{
+ __le64 snapid = cpu_to_le64(rbd_dev->spec->snap_id);
+ __le64 flags;
+ int ret;
+
+ ret = rbd_obj_method_sync(rbd_dev, &rbd_dev->header_oid,
+ &rbd_dev->header_oloc, "get_flags",
+ &snapid, sizeof(snapid),
+ &flags, sizeof(flags));
+ if (ret < 0)
+ return ret;
+ if (ret < sizeof(flags))
+ return -EBADMSG;
+
+ rbd_dev->object_map_flags = le64_to_cpu(flags);
+ return 0;
+}
+
struct parent_image_info {
u64 pool_id;
const char *pool_ns;
@@ -4829,7 +5817,7 @@ static int __get_parent_info(struct rbd_device *rbd_dev,
ret = ceph_osdc_call(osdc, &rbd_dev->header_oid, &rbd_dev->header_oloc,
"rbd", "parent_get", CEPH_OSD_FLAG_READ,
- req_page, sizeof(u64), reply_page, &reply_len);
+ req_page, sizeof(u64), &reply_page, &reply_len);
if (ret)
return ret == -EOPNOTSUPP ? 1 : ret;
@@ -4841,7 +5829,7 @@ static int __get_parent_info(struct rbd_device *rbd_dev,
ret = ceph_osdc_call(osdc, &rbd_dev->header_oid, &rbd_dev->header_oloc,
"rbd", "parent_overlap_get", CEPH_OSD_FLAG_READ,
- req_page, sizeof(u64), reply_page, &reply_len);
+ req_page, sizeof(u64), &reply_page, &reply_len);
if (ret)
return ret;
@@ -4872,7 +5860,7 @@ static int __get_parent_info_legacy(struct rbd_device *rbd_dev,
ret = ceph_osdc_call(osdc, &rbd_dev->header_oid, &rbd_dev->header_oloc,
"rbd", "get_parent", CEPH_OSD_FLAG_READ,
- req_page, sizeof(u64), reply_page, &reply_len);
+ req_page, sizeof(u64), &reply_page, &reply_len);
if (ret)
return ret;
@@ -5605,28 +6593,49 @@ static void rbd_dev_image_unlock(struct rbd_device *rbd_dev)
{
down_write(&rbd_dev->lock_rwsem);
if (__rbd_is_lock_owner(rbd_dev))
- rbd_unlock(rbd_dev);
+ __rbd_release_lock(rbd_dev);
up_write(&rbd_dev->lock_rwsem);
}
+/*
+ * If the wait is interrupted, an error is returned even if the lock
+ * was successfully acquired. rbd_dev_image_unlock() will release it
+ * if needed.
+ */
static int rbd_add_acquire_lock(struct rbd_device *rbd_dev)
{
- int ret;
+ long ret;
if (!(rbd_dev->header.features & RBD_FEATURE_EXCLUSIVE_LOCK)) {
+ if (!rbd_dev->opts->exclusive && !rbd_dev->opts->lock_on_read)
+ return 0;
+
rbd_warn(rbd_dev, "exclusive-lock feature is not enabled");
return -EINVAL;
}
- /* FIXME: "rbd map --exclusive" should be in interruptible */
- down_read(&rbd_dev->lock_rwsem);
- ret = rbd_wait_state_locked(rbd_dev, true);
- up_read(&rbd_dev->lock_rwsem);
+ if (rbd_dev->spec->snap_id != CEPH_NOSNAP)
+ return 0;
+
+ rbd_assert(!rbd_is_lock_owner(rbd_dev));
+ queue_delayed_work(rbd_dev->task_wq, &rbd_dev->lock_dwork, 0);
+ ret = wait_for_completion_killable_timeout(&rbd_dev->acquire_wait,
+ ceph_timeout_jiffies(rbd_dev->opts->lock_timeout));
+ if (ret > 0)
+ ret = rbd_dev->acquire_err;
+ else if (!ret)
+ ret = -ETIMEDOUT;
+
if (ret) {
- rbd_warn(rbd_dev, "failed to acquire exclusive lock");
- return -EROFS;
+ rbd_warn(rbd_dev, "failed to acquire exclusive lock: %ld", ret);
+ return ret;
}
+ /*
+ * The lock may have been released by now, unless automatic lock
+ * transitions are disabled.
+ */
+ rbd_assert(!rbd_dev->opts->exclusive || rbd_is_lock_owner(rbd_dev));
return 0;
}
@@ -5724,6 +6733,8 @@ static void rbd_dev_unprobe(struct rbd_device *rbd_dev)
struct rbd_image_header *header;
rbd_dev_parent_put(rbd_dev);
+ rbd_object_map_free(rbd_dev);
+ rbd_dev_mapping_clear(rbd_dev);
/* Free dynamic fields from the header, then zero it out */
@@ -5824,7 +6835,6 @@ out_err:
static void rbd_dev_device_release(struct rbd_device *rbd_dev)
{
clear_bit(RBD_DEV_FLAG_EXISTS, &rbd_dev->flags);
- rbd_dev_mapping_clear(rbd_dev);
rbd_free_disk(rbd_dev);
if (!single_major)
unregister_blkdev(rbd_dev->major, rbd_dev->name);
@@ -5858,23 +6868,17 @@ static int rbd_dev_device_setup(struct rbd_device *rbd_dev)
if (ret)
goto err_out_blkdev;
- ret = rbd_dev_mapping_set(rbd_dev);
- if (ret)
- goto err_out_disk;
-
set_capacity(rbd_dev->disk, rbd_dev->mapping.size / SECTOR_SIZE);
set_disk_ro(rbd_dev->disk, rbd_dev->opts->read_only);
ret = dev_set_name(&rbd_dev->dev, "%d", rbd_dev->dev_id);
if (ret)
- goto err_out_mapping;
+ goto err_out_disk;
set_bit(RBD_DEV_FLAG_EXISTS, &rbd_dev->flags);
up_write(&rbd_dev->header_rwsem);
return 0;
-err_out_mapping:
- rbd_dev_mapping_clear(rbd_dev);
err_out_disk:
rbd_free_disk(rbd_dev);
err_out_blkdev:
@@ -5975,6 +6979,17 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth)
goto err_out_probe;
}
+ ret = rbd_dev_mapping_set(rbd_dev);
+ if (ret)
+ goto err_out_probe;
+
+ if (rbd_dev->spec->snap_id != CEPH_NOSNAP &&
+ (rbd_dev->header.features & RBD_FEATURE_OBJECT_MAP)) {
+ ret = rbd_object_map_load(rbd_dev);
+ if (ret)
+ goto err_out_probe;
+ }
+
if (rbd_dev->header.features & RBD_FEATURE_LAYERING) {
ret = rbd_dev_v2_parent_info(rbd_dev);
if (ret)
@@ -6071,11 +7086,9 @@ static ssize_t do_rbd_add(struct bus_type *bus,
if (rc)
goto err_out_image_probe;
- if (rbd_dev->opts->exclusive) {
- rc = rbd_add_acquire_lock(rbd_dev);
- if (rc)
- goto err_out_device_setup;
- }
+ rc = rbd_add_acquire_lock(rbd_dev);
+ if (rc)
+ goto err_out_image_lock;
/* Everything's ready. Announce the disk to the world. */
@@ -6101,7 +7114,6 @@ out:
err_out_image_lock:
rbd_dev_image_unlock(rbd_dev);
-err_out_device_setup:
rbd_dev_device_release(rbd_dev);
err_out_image_probe:
rbd_dev_image_release(rbd_dev);
diff --git a/drivers/block/rbd_types.h b/drivers/block/rbd_types.h
index 62ff50d3e7a6..ac98ab6ccd3b 100644
--- a/drivers/block/rbd_types.h
+++ b/drivers/block/rbd_types.h
@@ -18,6 +18,7 @@
/* For format version 2, rbd image 'foo' consists of objects
* rbd_id.foo - id of image
* rbd_header.<id> - image metadata
+ * rbd_object_map.<id> - optional image object map
* rbd_data.<id>.0000000000000000
* rbd_data.<id>.0000000000000001
* ... - data
@@ -25,6 +26,7 @@
*/
#define RBD_HEADER_PREFIX "rbd_header."
+#define RBD_OBJECT_MAP_PREFIX "rbd_object_map."
#define RBD_ID_PREFIX "rbd_id."
#define RBD_V2_DATA_FORMAT "%s.%016llx"
@@ -39,6 +41,14 @@ enum rbd_notify_op {
RBD_NOTIFY_OP_HEADER_UPDATE = 3,
};
+#define OBJECT_NONEXISTENT 0
+#define OBJECT_EXISTS 1
+#define OBJECT_PENDING 2
+#define OBJECT_EXISTS_CLEAN 3
+
+#define RBD_FLAG_OBJECT_MAP_INVALID (1ULL << 0)
+#define RBD_FLAG_FAST_DIFF_INVALID (1ULL << 1)
+
/*
* For format version 1, rbd image 'foo' consists of objects
* foo.rbd - image metadata
diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c
index 7d3ad6c22ee5..51569c199a6c 100644
--- a/drivers/block/skd_main.c
+++ b/drivers/block/skd_main.c
@@ -1,12 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for sTec s1120 PCIe SSDs. sTec was acquired in 2013 by HGST and HGST
* was acquired by Western Digital in 2012.
*
* Copyright 2012 sTec, Inc.
* Copyright (c) 2017 Western Digital Corporation or its affiliates.
- *
- * This file is part of the Linux kernel, and is made available under
- * the terms of the GNU General Public License version 2.
*/
#include <linux/kernel.h>
@@ -2696,7 +2694,6 @@ static int skd_cons_skmsg(struct skd_device *skdev)
(FIT_QCMD_ALIGN - 1),
"not aligned: msg_buf %p mb_dma_address %pad\n",
skmsg->msg_buf, &skmsg->mb_dma_address);
- memset(skmsg->msg_buf, 0, SKD_N_FITMSG_BYTES);
}
err_out:
diff --git a/drivers/block/skd_s1120.h b/drivers/block/skd_s1120.h
index de35f47e953c..c30bb98c7cd2 100644
--- a/drivers/block/skd_s1120.h
+++ b/drivers/block/skd_s1120.h
@@ -1,9 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2012 STEC, Inc.
* Copyright (c) 2017 Western Digital Corporation or its affiliates.
- *
- * This file is part of the Linux kernel, and is made available under
- * the terms of the GNU General Public License version 2.
*/
diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c
index 464c9092bc8b..5d8e0ab3f054 100644
--- a/drivers/block/xsysace.c
+++ b/drivers/block/xsysace.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Xilinx SystemACE device driver
*
* Copyright 2007 Secret Lab Technologies Ltd.
- *
- * 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.
*/
/*
diff --git a/drivers/block/zram/Kconfig b/drivers/block/zram/Kconfig
index 1ffc64770643..fe7a4b7d30cf 100644
--- a/drivers/block/zram/Kconfig
+++ b/drivers/block/zram/Kconfig
@@ -12,7 +12,7 @@ config ZRAM
It has several use cases, for example: /tmp storage, use as swap
disks and maybe many more.
- See Documentation/blockdev/zram.txt for more information.
+ See Documentation/admin-guide/blockdev/zram.rst for more information.
config ZRAM_WRITEBACK
bool "Write back incompressible or idle page to backing device"
@@ -26,7 +26,7 @@ config ZRAM_WRITEBACK
With /sys/block/zramX/{idle,writeback}, application could ask
idle page's writeback to the backing device to save in memory.
- See Documentation/blockdev/zram.txt for more information.
+ See Documentation/admin-guide/blockdev/zram.rst for more information.
config ZRAM_MEMORY_TRACKING
bool "Track zRam block status"
@@ -36,4 +36,4 @@ config ZRAM_MEMORY_TRACKING
of zRAM. Admin could see the information via
/sys/kernel/debug/zram/zramX/block_state.
- See Documentation/blockdev/zram.txt for more information.
+ See Documentation/admin-guide/blockdev/zram.rst for more information.
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index b9c34ff9a0d3..aae665a3a254 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -52,6 +52,17 @@ config BT_HCIBTUSB_BCM
Say Y here to compile support for Broadcom protocol.
+config BT_HCIBTUSB_MTK
+ bool "MediaTek protocol support"
+ depends on BT_HCIBTUSB
+ default n
+ help
+ The MediaTek protocol support enables firmware download
+ support and chip initialization for MediaTek Bluetooth
+ USB controllers.
+
+ Say Y here to compile support for MediaTek protocol.
+
config BT_HCIBTUSB_RTL
bool "Realtek protocol support"
depends on BT_HCIBTUSB
@@ -237,6 +248,7 @@ config BT_HCIUART_AG6XX
config BT_HCIUART_MRVL
bool "Marvell protocol support"
depends on BT_HCIUART
+ depends on BT_HCIUART_SERDEV
select BT_HCIUART_H4
help
Marvell is serial protocol for communication between Bluetooth
diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c
index a346ccb5450d..a0e84538cec8 100644
--- a/drivers/bluetooth/bpa10x.c
+++ b/drivers/bluetooth/bpa10x.c
@@ -359,7 +359,8 @@ static int bpa10x_set_diag(struct hci_dev *hdev, bool enable)
return 0;
}
-static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *id)
+static int bpa10x_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
{
struct bpa10x_data *data;
struct hci_dev *hdev;
diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c
index 3fe941539a1f..124ef0a3e1dd 100644
--- a/drivers/bluetooth/btbcm.c
+++ b/drivers/bluetooth/btbcm.c
@@ -335,6 +335,7 @@ static const struct bcm_subver_table bcm_uart_subver_table[] = {
{ 0x230f, "BCM4356A2" }, /* 001.003.015 */
{ 0x220e, "BCM20702A1" }, /* 001.002.014 */
{ 0x4217, "BCM4329B1" }, /* 002.002.023 */
+ { 0x6106, "BCM4359C0" }, /* 003.001.006 */
{ }
};
diff --git a/drivers/bluetooth/btmtkuart.c b/drivers/bluetooth/btmtkuart.c
index f5dbeec8e274..e11169ad8247 100644
--- a/drivers/bluetooth/btmtkuart.c
+++ b/drivers/bluetooth/btmtkuart.c
@@ -115,10 +115,12 @@ struct btmtk_hci_wmt_params {
struct btmtkuart_dev {
struct hci_dev *hdev;
struct serdev_device *serdev;
- struct clk *clk;
+ struct clk *clk;
+ struct clk *osc;
struct regulator *vcc;
struct gpio_desc *reset;
+ struct gpio_desc *boot;
struct pinctrl *pinctrl;
struct pinctrl_state *pins_runtime;
struct pinctrl_state *pins_boot;
@@ -911,6 +913,19 @@ static int btmtkuart_parse_dt(struct serdev_device *serdev)
return err;
}
+ bdev->osc = devm_clk_get_optional(&serdev->dev, "osc");
+ if (IS_ERR(bdev->osc)) {
+ err = PTR_ERR(bdev->osc);
+ return err;
+ }
+
+ bdev->boot = devm_gpiod_get_optional(&serdev->dev, "boot",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(bdev->boot)) {
+ err = PTR_ERR(bdev->boot);
+ return err;
+ }
+
bdev->pinctrl = devm_pinctrl_get(&serdev->dev);
if (IS_ERR(bdev->pinctrl)) {
err = PTR_ERR(bdev->pinctrl);
@@ -919,8 +934,10 @@ static int btmtkuart_parse_dt(struct serdev_device *serdev)
bdev->pins_boot = pinctrl_lookup_state(bdev->pinctrl,
"default");
- if (IS_ERR(bdev->pins_boot)) {
+ if (IS_ERR(bdev->pins_boot) && !bdev->boot) {
err = PTR_ERR(bdev->pins_boot);
+ dev_err(&serdev->dev,
+ "Should assign RXD to LOW at boot stage\n");
return err;
}
@@ -996,13 +1013,25 @@ static int btmtkuart_probe(struct serdev_device *serdev)
set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks);
if (btmtkuart_is_standalone(bdev)) {
- /* Switch to the specific pin state for the booting requires */
- pinctrl_select_state(bdev->pinctrl, bdev->pins_boot);
+ err = clk_prepare_enable(bdev->osc);
+ if (err < 0)
+ return err;
+
+ if (bdev->boot) {
+ gpiod_set_value_cansleep(bdev->boot, 1);
+ } else {
+ /* Switch to the specific pin state for the booting
+ * requires.
+ */
+ pinctrl_select_state(bdev->pinctrl, bdev->pins_boot);
+ }
/* Power on */
err = regulator_enable(bdev->vcc);
- if (err < 0)
+ if (err < 0) {
+ clk_disable_unprepare(bdev->osc);
return err;
+ }
/* Reset if the reset-gpios is available otherwise the board
* -level design should be guaranteed.
@@ -1017,6 +1046,10 @@ static int btmtkuart_probe(struct serdev_device *serdev)
* mode the device requires for UART transfers.
*/
msleep(50);
+
+ if (bdev->boot)
+ devm_gpiod_put(&serdev->dev, bdev->boot);
+
pinctrl_select_state(bdev->pinctrl, bdev->pins_runtime);
/* A standalone device doesn't depends on power domain on SoC,
@@ -1037,10 +1070,8 @@ static int btmtkuart_probe(struct serdev_device *serdev)
return 0;
err_regulator_disable:
- if (btmtkuart_is_standalone(bdev)) {
- pinctrl_select_state(bdev->pinctrl, bdev->pins_boot);
+ if (btmtkuart_is_standalone(bdev))
regulator_disable(bdev->vcc);
- }
return err;
}
@@ -1050,9 +1081,9 @@ static void btmtkuart_remove(struct serdev_device *serdev)
struct btmtkuart_dev *bdev = serdev_device_get_drvdata(serdev);
struct hci_dev *hdev = bdev->hdev;
- if (btmtkuart_is_standalone(bdev)) {
- pinctrl_select_state(bdev->pinctrl, bdev->pins_boot);
+ if (btmtkuart_is_standalone(bdev)) {
regulator_disable(bdev->vcc);
+ clk_disable_unprepare(bdev->osc);
}
hci_unregister_dev(hdev);
diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
index aff1d22223bd..8b33128dccee 100644
--- a/drivers/bluetooth/btqca.c
+++ b/drivers/bluetooth/btqca.c
@@ -131,6 +131,7 @@ static void qca_tlv_check_data(struct rome_config *config,
* In case VSE is skipped, only the last segment is acked.
*/
config->dnld_mode = tlv_patch->download_mode;
+ config->dnld_type = config->dnld_mode;
BT_DBG("Total Length : %d bytes",
le32_to_cpu(tlv_patch->total_size));
@@ -251,6 +252,31 @@ out:
return err;
}
+static int qca_inject_cmd_complete_event(struct hci_dev *hdev)
+{
+ struct hci_event_hdr *hdr;
+ struct hci_ev_cmd_complete *evt;
+ struct sk_buff *skb;
+
+ skb = bt_skb_alloc(sizeof(*hdr) + sizeof(*evt) + 1, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+
+ hdr = skb_put(skb, sizeof(*hdr));
+ hdr->evt = HCI_EV_CMD_COMPLETE;
+ hdr->plen = sizeof(*evt) + 1;
+
+ evt = skb_put(skb, sizeof(*evt));
+ evt->ncmd = 1;
+ evt->opcode = QCA_HCI_CC_OPCODE;
+
+ skb_put_u8(skb, QCA_HCI_CC_SUCCESS);
+
+ hci_skb_pkt_type(skb) = HCI_EVENT_PKT;
+
+ return hci_recv_frame(hdev, skb);
+}
+
static int qca_download_firmware(struct hci_dev *hdev,
struct rome_config *config)
{
@@ -284,11 +310,22 @@ static int qca_download_firmware(struct hci_dev *hdev,
ret = qca_tlv_send_segment(hdev, segsize, segment,
config->dnld_mode);
if (ret)
- break;
+ goto out;
segment += segsize;
}
+ /* Latest qualcomm chipsets are not sending a command complete event
+ * for every fw packet sent. They only respond with a vendor specific
+ * event for the last packet. This optimization in the chip will
+ * decrease the BT in initialization time. Here we will inject a command
+ * complete event to avoid a command timeout error message.
+ */
+ if (config->dnld_type == ROME_SKIP_EVT_VSE_CC ||
+ config->dnld_type == ROME_SKIP_EVT_VSE)
+ return qca_inject_cmd_complete_event(hdev);
+
+out:
release_firmware(fw);
return ret;
@@ -319,7 +356,8 @@ int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr)
EXPORT_SYMBOL_GPL(qca_set_bdaddr_rome);
int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
- enum qca_btsoc_type soc_type, u32 soc_ver)
+ enum qca_btsoc_type soc_type, u32 soc_ver,
+ const char *firmware_name)
{
struct rome_config config;
int err;
@@ -352,7 +390,10 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
/* Download NVM configuration */
config.type = TLV_TYPE_NVM;
- if (qca_is_wcn399x(soc_type))
+ if (firmware_name)
+ snprintf(config.fwname, sizeof(config.fwname),
+ "qca/%s", firmware_name);
+ else if (qca_is_wcn399x(soc_type))
snprintf(config.fwname, sizeof(config.fwname),
"qca/crnv%02x.bin", rom_ver);
else
diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h
index e9c999959603..6a291a7a5d96 100644
--- a/drivers/bluetooth/btqca.h
+++ b/drivers/bluetooth/btqca.h
@@ -28,6 +28,9 @@
#define QCA_WCN3990_POWERON_PULSE 0xFC
#define QCA_WCN3990_POWEROFF_PULSE 0xC0
+#define QCA_HCI_CC_OPCODE 0xFC00
+#define QCA_HCI_CC_SUCCESS 0x00
+
enum qca_baudrate {
QCA_BAUDRATE_115200 = 0,
QCA_BAUDRATE_57600,
@@ -69,6 +72,7 @@ struct rome_config {
char fwname[64];
uint8_t user_baud_rate;
enum rome_tlv_dnld_mode dnld_mode;
+ enum rome_tlv_dnld_mode dnld_type;
};
struct edl_event_hdr {
@@ -127,7 +131,8 @@ enum qca_btsoc_type {
int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr);
int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
- enum qca_btsoc_type soc_type, u32 soc_ver);
+ enum qca_btsoc_type soc_type, u32 soc_ver,
+ const char *firmware_name);
int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version);
int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr);
static inline bool qca_is_wcn399x(enum qca_btsoc_type soc_type)
@@ -142,7 +147,8 @@ static inline int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdad
}
static inline int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
- enum qca_btsoc_type soc_type, u32 soc_ver)
+ enum qca_btsoc_type soc_type, u32 soc_ver,
+ const char *firmware_name)
{
return -EOPNOTSUPP;
}
diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c
index 208feef63de4..4f75a9b61d09 100644
--- a/drivers/bluetooth/btrtl.c
+++ b/drivers/bluetooth/btrtl.c
@@ -21,6 +21,7 @@
#define RTL_ROM_LMP_3499 0x3499
#define RTL_ROM_LMP_8723A 0x1200
#define RTL_ROM_LMP_8723B 0x8723
+#define RTL_ROM_LMP_8723D 0x8873
#define RTL_ROM_LMP_8821A 0x8821
#define RTL_ROM_LMP_8761A 0x8761
#define RTL_ROM_LMP_8822B 0x8822
@@ -107,6 +108,13 @@ static const struct id_table ic_id_table[] = {
.fw_name = "rtl_bt/rtl8723ds_fw.bin",
.cfg_name = "rtl_bt/rtl8723ds_config" },
+ /* 8723DU */
+ { IC_INFO(RTL_ROM_LMP_8723D, 0x826C),
+ .config_needed = true,
+ .has_rom_version = true,
+ .fw_name = "rtl_bt/rtl8723d_fw.bin",
+ .cfg_name = "rtl_bt/rtl8723d_config" },
+
/* 8821A */
{ IC_INFO(RTL_ROM_LMP_8821A, 0xa),
.config_needed = false,
@@ -637,6 +645,26 @@ int btrtl_setup_realtek(struct hci_dev *hdev)
}
EXPORT_SYMBOL_GPL(btrtl_setup_realtek);
+int btrtl_shutdown_realtek(struct hci_dev *hdev)
+{
+ struct sk_buff *skb;
+ int ret;
+
+ /* According to the vendor driver, BT must be reset on close to avoid
+ * firmware crash.
+ */
+ skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ ret = PTR_ERR(skb);
+ bt_dev_err(hdev, "HCI reset during shutdown failed");
+ return ret;
+ }
+ kfree_skb(skb);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(btrtl_shutdown_realtek);
+
static unsigned int btrtl_convert_baudrate(u32 device_baudrate)
{
switch (device_baudrate) {
diff --git a/drivers/bluetooth/btrtl.h b/drivers/bluetooth/btrtl.h
index f1676144fce8..10ad40c3e42c 100644
--- a/drivers/bluetooth/btrtl.h
+++ b/drivers/bluetooth/btrtl.h
@@ -55,6 +55,7 @@ void btrtl_free(struct btrtl_device_info *btrtl_dev);
int btrtl_download_firmware(struct hci_dev *hdev,
struct btrtl_device_info *btrtl_dev);
int btrtl_setup_realtek(struct hci_dev *hdev);
+int btrtl_shutdown_realtek(struct hci_dev *hdev);
int btrtl_get_uart_settings(struct hci_dev *hdev,
struct btrtl_device_info *btrtl_dev,
unsigned int *controller_baudrate,
@@ -83,6 +84,11 @@ static inline int btrtl_setup_realtek(struct hci_dev *hdev)
return -EOPNOTSUPP;
}
+static inline int btrtl_shutdown_realtek(struct hci_dev *hdev)
+{
+ return -EOPNOTSUPP;
+}
+
static inline int btrtl_get_uart_settings(struct hci_dev *hdev,
struct btrtl_device_info *btrtl_dev,
unsigned int *controller_baudrate,
diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c
index 83748b7b2033..fd9571d5fdac 100644
--- a/drivers/bluetooth/btsdio.c
+++ b/drivers/bluetooth/btsdio.c
@@ -286,6 +286,7 @@ static int btsdio_probe(struct sdio_func *func,
switch (func->device) {
case SDIO_DEVICE_ID_BROADCOM_43341:
case SDIO_DEVICE_ID_BROADCOM_43430:
+ case SDIO_DEVICE_ID_BROADCOM_4356:
return -ENODEV;
}
}
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 50aed5259c2b..3876fee6ad13 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -11,6 +11,7 @@
#include <linux/usb.h>
#include <linux/usb/quirks.h>
#include <linux/firmware.h>
+#include <linux/iopoll.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/suspend.h>
@@ -55,6 +56,7 @@ static struct usb_driver btusb_driver;
#define BTUSB_BCM2045 0x40000
#define BTUSB_IFNUM_2 0x80000
#define BTUSB_CW6622 0x100000
+#define BTUSB_MEDIATEK 0x200000
static const struct usb_device_id btusb_table[] = {
/* Generic Bluetooth USB device */
@@ -264,7 +266,9 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x04ca, 0x3015), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x04ca, 0x3016), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x04ca, 0x301a), .driver_info = BTUSB_QCA_ROME },
+ { USB_DEVICE(0x13d3, 0x3491), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x13d3, 0x3496), .driver_info = BTUSB_QCA_ROME },
+ { USB_DEVICE(0x13d3, 0x3501), .driver_info = BTUSB_QCA_ROME },
/* Broadcom BCM2035 */
{ USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 },
@@ -346,6 +350,10 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_VENDOR_AND_INTERFACE_INFO(0x0bda, 0xe0, 0x01, 0x01),
.driver_info = BTUSB_REALTEK },
+ /* MediaTek Bluetooth devices */
+ { USB_VENDOR_AND_INTERFACE_INFO(0x0e8d, 0xe0, 0x01, 0x01),
+ .driver_info = BTUSB_MEDIATEK },
+
/* Additional Realtek 8723AE Bluetooth devices */
{ USB_DEVICE(0x0930, 0x021d), .driver_info = BTUSB_REALTEK },
{ USB_DEVICE(0x13d3, 0x3394), .driver_info = BTUSB_REALTEK },
@@ -426,6 +434,7 @@ static const struct dmi_system_id btusb_needs_reset_resume_table[] = {
#define BTUSB_DIAG_RUNNING 10
#define BTUSB_OOB_WAKE_ENABLED 11
#define BTUSB_HW_RESET_ACTIVE 12
+#define BTUSB_TX_WAIT_VND_EVT 13
struct btusb_data {
struct hci_dev *hdev;
@@ -449,6 +458,7 @@ struct btusb_data {
struct usb_anchor bulk_anchor;
struct usb_anchor isoc_anchor;
struct usb_anchor diag_anchor;
+ struct usb_anchor ctrl_anchor;
spinlock_t rxlock;
struct sk_buff *evt_skb;
@@ -1202,6 +1212,7 @@ static void btusb_stop_traffic(struct btusb_data *data)
usb_kill_anchored_urbs(&data->bulk_anchor);
usb_kill_anchored_urbs(&data->isoc_anchor);
usb_kill_anchored_urbs(&data->diag_anchor);
+ usb_kill_anchored_urbs(&data->ctrl_anchor);
}
static int btusb_close(struct hci_dev *hdev)
@@ -2437,6 +2448,568 @@ static int btusb_shutdown_intel_new(struct hci_dev *hdev)
return 0;
}
+#ifdef CONFIG_BT_HCIBTUSB_MTK
+
+#define FIRMWARE_MT7663 "mediatek/mt7663pr2h.bin"
+#define FIRMWARE_MT7668 "mediatek/mt7668pr2h.bin"
+
+#define HCI_WMT_MAX_EVENT_SIZE 64
+
+enum {
+ BTMTK_WMT_PATCH_DWNLD = 0x1,
+ BTMTK_WMT_FUNC_CTRL = 0x6,
+ BTMTK_WMT_RST = 0x7,
+ BTMTK_WMT_SEMAPHORE = 0x17,
+};
+
+enum {
+ BTMTK_WMT_INVALID,
+ BTMTK_WMT_PATCH_UNDONE,
+ BTMTK_WMT_PATCH_DONE,
+ BTMTK_WMT_ON_UNDONE,
+ BTMTK_WMT_ON_DONE,
+ BTMTK_WMT_ON_PROGRESS,
+};
+
+struct btmtk_wmt_hdr {
+ u8 dir;
+ u8 op;
+ __le16 dlen;
+ u8 flag;
+} __packed;
+
+struct btmtk_hci_wmt_cmd {
+ struct btmtk_wmt_hdr hdr;
+ u8 data[256];
+} __packed;
+
+struct btmtk_hci_wmt_evt {
+ struct hci_event_hdr hhdr;
+ struct btmtk_wmt_hdr whdr;
+} __packed;
+
+struct btmtk_hci_wmt_evt_funcc {
+ struct btmtk_hci_wmt_evt hwhdr;
+ __be16 status;
+} __packed;
+
+struct btmtk_tci_sleep {
+ u8 mode;
+ __le16 duration;
+ __le16 host_duration;
+ u8 host_wakeup_pin;
+ u8 time_compensation;
+} __packed;
+
+struct btmtk_hci_wmt_params {
+ u8 op;
+ u8 flag;
+ u16 dlen;
+ const void *data;
+ u32 *status;
+};
+
+static void btusb_mtk_wmt_recv(struct urb *urb)
+{
+ struct hci_dev *hdev = urb->context;
+ struct btusb_data *data = hci_get_drvdata(hdev);
+ struct hci_event_hdr *hdr;
+ struct sk_buff *skb;
+ int err;
+
+ if (urb->status == 0 && urb->actual_length > 0) {
+ hdev->stat.byte_rx += urb->actual_length;
+
+ /* WMT event shouldn't be fragmented and the size should be
+ * less than HCI_WMT_MAX_EVENT_SIZE.
+ */
+ skb = bt_skb_alloc(HCI_WMT_MAX_EVENT_SIZE, GFP_ATOMIC);
+ if (!skb) {
+ hdev->stat.err_rx++;
+ goto err_out;
+ }
+
+ hci_skb_pkt_type(skb) = HCI_EVENT_PKT;
+ skb_put_data(skb, urb->transfer_buffer, urb->actual_length);
+
+ hdr = (void *)skb->data;
+ /* Fix up the vendor event id with 0xff for vendor specific
+ * instead of 0xe4 so that event send via monitoring socket can
+ * be parsed properly.
+ */
+ hdr->evt = 0xff;
+
+ /* When someone waits for the WMT event, the skb is being cloned
+ * and being processed the events from there then.
+ */
+ if (test_bit(BTUSB_TX_WAIT_VND_EVT, &data->flags)) {
+ data->evt_skb = skb_clone(skb, GFP_KERNEL);
+ if (!data->evt_skb)
+ goto err_out;
+ }
+
+ err = hci_recv_frame(hdev, skb);
+ if (err < 0)
+ goto err_free_skb;
+
+ if (test_and_clear_bit(BTUSB_TX_WAIT_VND_EVT,
+ &data->flags)) {
+ /* Barrier to sync with other CPUs */
+ smp_mb__after_atomic();
+ wake_up_bit(&data->flags,
+ BTUSB_TX_WAIT_VND_EVT);
+ }
+err_out:
+ return;
+err_free_skb:
+ kfree_skb(data->evt_skb);
+ data->evt_skb = NULL;
+ return;
+ } else if (urb->status == -ENOENT) {
+ /* Avoid suspend failed when usb_kill_urb */
+ return;
+ }
+
+ usb_mark_last_busy(data->udev);
+
+ /* The URB complete handler is still called with urb->actual_length = 0
+ * when the event is not available, so we should keep re-submitting
+ * URB until WMT event returns, Also, It's necessary to wait some time
+ * between the two consecutive control URBs to relax the target device
+ * to generate the event. Otherwise, the WMT event cannot return from
+ * the device successfully.
+ */
+ udelay(100);
+
+ usb_anchor_urb(urb, &data->ctrl_anchor);
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err < 0) {
+ /* -EPERM: urb is being killed;
+ * -ENODEV: device got disconnected
+ */
+ if (err != -EPERM && err != -ENODEV)
+ bt_dev_err(hdev, "urb %p failed to resubmit (%d)",
+ urb, -err);
+ usb_unanchor_urb(urb);
+ }
+}
+
+static int btusb_mtk_submit_wmt_recv_urb(struct hci_dev *hdev)
+{
+ struct btusb_data *data = hci_get_drvdata(hdev);
+ struct usb_ctrlrequest *dr;
+ unsigned char *buf;
+ int err, size = 64;
+ unsigned int pipe;
+ struct urb *urb;
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb)
+ return -ENOMEM;
+
+ dr = kmalloc(sizeof(*dr), GFP_KERNEL);
+ if (!dr) {
+ usb_free_urb(urb);
+ return -ENOMEM;
+ }
+
+ dr->bRequestType = USB_TYPE_VENDOR | USB_DIR_IN;
+ dr->bRequest = 1;
+ dr->wIndex = cpu_to_le16(0);
+ dr->wValue = cpu_to_le16(48);
+ dr->wLength = cpu_to_le16(size);
+
+ buf = kmalloc(size, GFP_KERNEL);
+ if (!buf) {
+ kfree(dr);
+ return -ENOMEM;
+ }
+
+ pipe = usb_rcvctrlpipe(data->udev, 0);
+
+ usb_fill_control_urb(urb, data->udev, pipe, (void *)dr,
+ buf, size, btusb_mtk_wmt_recv, hdev);
+
+ urb->transfer_flags |= URB_FREE_BUFFER;
+
+ usb_anchor_urb(urb, &data->ctrl_anchor);
+ err = usb_submit_urb(urb, GFP_KERNEL);
+ if (err < 0) {
+ if (err != -EPERM && err != -ENODEV)
+ bt_dev_err(hdev, "urb %p submission failed (%d)",
+ urb, -err);
+ usb_unanchor_urb(urb);
+ }
+
+ usb_free_urb(urb);
+
+ return err;
+}
+
+static int btusb_mtk_hci_wmt_sync(struct hci_dev *hdev,
+ struct btmtk_hci_wmt_params *wmt_params)
+{
+ struct btusb_data *data = hci_get_drvdata(hdev);
+ struct btmtk_hci_wmt_evt_funcc *wmt_evt_funcc;
+ u32 hlen, status = BTMTK_WMT_INVALID;
+ struct btmtk_hci_wmt_evt *wmt_evt;
+ struct btmtk_hci_wmt_cmd wc;
+ struct btmtk_wmt_hdr *hdr;
+ int err;
+
+ /* Submit control IN URB on demand to process the WMT event */
+ err = btusb_mtk_submit_wmt_recv_urb(hdev);
+ if (err < 0)
+ return err;
+
+ /* Send the WMT command and wait until the WMT event returns */
+ hlen = sizeof(*hdr) + wmt_params->dlen;
+ if (hlen > 255)
+ return -EINVAL;
+
+ hdr = (struct btmtk_wmt_hdr *)&wc;
+ hdr->dir = 1;
+ hdr->op = wmt_params->op;
+ hdr->dlen = cpu_to_le16(wmt_params->dlen + 1);
+ hdr->flag = wmt_params->flag;
+ memcpy(wc.data, wmt_params->data, wmt_params->dlen);
+
+ set_bit(BTUSB_TX_WAIT_VND_EVT, &data->flags);
+
+ err = __hci_cmd_send(hdev, 0xfc6f, hlen, &wc);
+
+ if (err < 0) {
+ clear_bit(BTUSB_TX_WAIT_VND_EVT, &data->flags);
+ return err;
+ }
+
+ /* The vendor specific WMT commands are all answered by a vendor
+ * specific event and will have the Command Status or Command
+ * Complete as with usual HCI command flow control.
+ *
+ * After sending the command, wait for BTUSB_TX_WAIT_VND_EVT
+ * state to be cleared. The driver specific event receive routine
+ * will clear that state and with that indicate completion of the
+ * WMT command.
+ */
+ err = wait_on_bit_timeout(&data->flags, BTUSB_TX_WAIT_VND_EVT,
+ TASK_INTERRUPTIBLE, HCI_INIT_TIMEOUT);
+ if (err == -EINTR) {
+ bt_dev_err(hdev, "Execution of wmt command interrupted");
+ clear_bit(BTUSB_TX_WAIT_VND_EVT, &data->flags);
+ return err;
+ }
+
+ if (err) {
+ bt_dev_err(hdev, "Execution of wmt command timed out");
+ clear_bit(BTUSB_TX_WAIT_VND_EVT, &data->flags);
+ return -ETIMEDOUT;
+ }
+
+ /* Parse and handle the return WMT event */
+ wmt_evt = (struct btmtk_hci_wmt_evt *)data->evt_skb->data;
+ if (wmt_evt->whdr.op != hdr->op) {
+ bt_dev_err(hdev, "Wrong op received %d expected %d",
+ wmt_evt->whdr.op, hdr->op);
+ err = -EIO;
+ goto err_free_skb;
+ }
+
+ switch (wmt_evt->whdr.op) {
+ case BTMTK_WMT_SEMAPHORE:
+ if (wmt_evt->whdr.flag == 2)
+ status = BTMTK_WMT_PATCH_UNDONE;
+ else
+ status = BTMTK_WMT_PATCH_DONE;
+ break;
+ case BTMTK_WMT_FUNC_CTRL:
+ wmt_evt_funcc = (struct btmtk_hci_wmt_evt_funcc *)wmt_evt;
+ if (be16_to_cpu(wmt_evt_funcc->status) == 0x404)
+ status = BTMTK_WMT_ON_DONE;
+ else if (be16_to_cpu(wmt_evt_funcc->status) == 0x420)
+ status = BTMTK_WMT_ON_PROGRESS;
+ else
+ status = BTMTK_WMT_ON_UNDONE;
+ break;
+ }
+
+ if (wmt_params->status)
+ *wmt_params->status = status;
+
+err_free_skb:
+ kfree_skb(data->evt_skb);
+ data->evt_skb = NULL;
+
+ return err;
+}
+
+static int btusb_mtk_setup_firmware(struct hci_dev *hdev, const char *fwname)
+{
+ struct btmtk_hci_wmt_params wmt_params;
+ const struct firmware *fw;
+ const u8 *fw_ptr;
+ size_t fw_size;
+ int err, dlen;
+ u8 flag;
+
+ err = request_firmware(&fw, fwname, &hdev->dev);
+ if (err < 0) {
+ bt_dev_err(hdev, "Failed to load firmware file (%d)", err);
+ return err;
+ }
+
+ fw_ptr = fw->data;
+ fw_size = fw->size;
+
+ /* The size of patch header is 30 bytes, should be skip */
+ if (fw_size < 30)
+ goto err_release_fw;
+
+ fw_size -= 30;
+ fw_ptr += 30;
+ flag = 1;
+
+ wmt_params.op = BTMTK_WMT_PATCH_DWNLD;
+ wmt_params.status = NULL;
+
+ while (fw_size > 0) {
+ dlen = min_t(int, 250, fw_size);
+
+ /* Tell deivice the position in sequence */
+ if (fw_size - dlen <= 0)
+ flag = 3;
+ else if (fw_size < fw->size - 30)
+ flag = 2;
+
+ wmt_params.flag = flag;
+ wmt_params.dlen = dlen;
+ wmt_params.data = fw_ptr;
+
+ err = btusb_mtk_hci_wmt_sync(hdev, &wmt_params);
+ if (err < 0) {
+ bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)",
+ err);
+ goto err_release_fw;
+ }
+
+ fw_size -= dlen;
+ fw_ptr += dlen;
+ }
+
+ wmt_params.op = BTMTK_WMT_RST;
+ wmt_params.flag = 4;
+ wmt_params.dlen = 0;
+ wmt_params.data = NULL;
+ wmt_params.status = NULL;
+
+ /* Activate funciton the firmware providing to */
+ err = btusb_mtk_hci_wmt_sync(hdev, &wmt_params);
+ if (err < 0) {
+ bt_dev_err(hdev, "Failed to send wmt rst (%d)", err);
+ return err;
+ }
+
+ /* Wait a few moments for firmware activation done */
+ usleep_range(10000, 12000);
+
+err_release_fw:
+ release_firmware(fw);
+
+ return err;
+}
+
+static int btusb_mtk_func_query(struct hci_dev *hdev)
+{
+ struct btmtk_hci_wmt_params wmt_params;
+ int status, err;
+ u8 param = 0;
+
+ /* Query whether the function is enabled */
+ wmt_params.op = BTMTK_WMT_FUNC_CTRL;
+ wmt_params.flag = 4;
+ wmt_params.dlen = sizeof(param);
+ wmt_params.data = &param;
+ wmt_params.status = &status;
+
+ err = btusb_mtk_hci_wmt_sync(hdev, &wmt_params);
+ if (err < 0) {
+ bt_dev_err(hdev, "Failed to query function status (%d)", err);
+ return err;
+ }
+
+ return status;
+}
+
+static int btusb_mtk_reg_read(struct btusb_data *data, u32 reg, u32 *val)
+{
+ int pipe, err, size = sizeof(u32);
+ void *buf;
+
+ buf = kzalloc(size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ pipe = usb_rcvctrlpipe(data->udev, 0);
+ err = usb_control_msg(data->udev, pipe, 0x63,
+ USB_TYPE_VENDOR | USB_DIR_IN,
+ reg >> 16, reg & 0xffff,
+ buf, size, USB_CTRL_SET_TIMEOUT);
+ if (err < 0)
+ goto err_free_buf;
+
+ *val = get_unaligned_le32(buf);
+
+err_free_buf:
+ kfree(buf);
+
+ return err;
+}
+
+static int btusb_mtk_id_get(struct btusb_data *data, u32 *id)
+{
+ return btusb_mtk_reg_read(data, 0x80000008, id);
+}
+
+static int btusb_mtk_setup(struct hci_dev *hdev)
+{
+ struct btusb_data *data = hci_get_drvdata(hdev);
+ struct btmtk_hci_wmt_params wmt_params;
+ ktime_t calltime, delta, rettime;
+ struct btmtk_tci_sleep tci_sleep;
+ unsigned long long duration;
+ struct sk_buff *skb;
+ const char *fwname;
+ int err, status;
+ u32 dev_id;
+ u8 param;
+
+ calltime = ktime_get();
+
+ err = btusb_mtk_id_get(data, &dev_id);
+ if (err < 0) {
+ bt_dev_err(hdev, "Failed to get device id (%d)", err);
+ return err;
+ }
+
+ switch (dev_id) {
+ case 0x7663:
+ fwname = FIRMWARE_MT7663;
+ break;
+ case 0x7668:
+ fwname = FIRMWARE_MT7668;
+ break;
+ default:
+ bt_dev_err(hdev, "Unsupported support hardware variant (%08x)",
+ dev_id);
+ return -ENODEV;
+ }
+
+ /* Query whether the firmware is already download */
+ wmt_params.op = BTMTK_WMT_SEMAPHORE;
+ wmt_params.flag = 1;
+ wmt_params.dlen = 0;
+ wmt_params.data = NULL;
+ wmt_params.status = &status;
+
+ err = btusb_mtk_hci_wmt_sync(hdev, &wmt_params);
+ if (err < 0) {
+ bt_dev_err(hdev, "Failed to query firmware status (%d)", err);
+ return err;
+ }
+
+ if (status == BTMTK_WMT_PATCH_DONE) {
+ bt_dev_info(hdev, "firmware already downloaded");
+ goto ignore_setup_fw;
+ }
+
+ /* Setup a firmware which the device definitely requires */
+ err = btusb_mtk_setup_firmware(hdev, fwname);
+ if (err < 0)
+ return err;
+
+ignore_setup_fw:
+ err = readx_poll_timeout(btusb_mtk_func_query, hdev, status,
+ status < 0 || status != BTMTK_WMT_ON_PROGRESS,
+ 2000, 5000000);
+ /* -ETIMEDOUT happens */
+ if (err < 0)
+ return err;
+
+ /* The other errors happen in btusb_mtk_func_query */
+ if (status < 0)
+ return status;
+
+ if (status == BTMTK_WMT_ON_DONE) {
+ bt_dev_info(hdev, "function already on");
+ goto ignore_func_on;
+ }
+
+ /* Enable Bluetooth protocol */
+ param = 1;
+ wmt_params.op = BTMTK_WMT_FUNC_CTRL;
+ wmt_params.flag = 0;
+ wmt_params.dlen = sizeof(param);
+ wmt_params.data = &param;
+ wmt_params.status = NULL;
+
+ err = btusb_mtk_hci_wmt_sync(hdev, &wmt_params);
+ if (err < 0) {
+ bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err);
+ return err;
+ }
+
+ignore_func_on:
+ /* Apply the low power environment setup */
+ tci_sleep.mode = 0x5;
+ tci_sleep.duration = cpu_to_le16(0x640);
+ tci_sleep.host_duration = cpu_to_le16(0x640);
+ tci_sleep.host_wakeup_pin = 0;
+ tci_sleep.time_compensation = 0;
+
+ skb = __hci_cmd_sync(hdev, 0xfc7a, sizeof(tci_sleep), &tci_sleep,
+ HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ err = PTR_ERR(skb);
+ bt_dev_err(hdev, "Failed to apply low power setting (%d)", err);
+ return err;
+ }
+ kfree_skb(skb);
+
+ rettime = ktime_get();
+ delta = ktime_sub(rettime, calltime);
+ duration = (unsigned long long)ktime_to_ns(delta) >> 10;
+
+ bt_dev_info(hdev, "Device setup in %llu usecs", duration);
+
+ return 0;
+}
+
+static int btusb_mtk_shutdown(struct hci_dev *hdev)
+{
+ struct btmtk_hci_wmt_params wmt_params;
+ u8 param = 0;
+ int err;
+
+ /* Disable the device */
+ wmt_params.op = BTMTK_WMT_FUNC_CTRL;
+ wmt_params.flag = 0;
+ wmt_params.dlen = sizeof(param);
+ wmt_params.data = &param;
+ wmt_params.status = NULL;
+
+ err = btusb_mtk_hci_wmt_sync(hdev, &wmt_params);
+ if (err < 0) {
+ bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err);
+ return err;
+ }
+
+ return 0;
+}
+
+MODULE_FIRMWARE(FIRMWARE_MT7663);
+MODULE_FIRMWARE(FIRMWARE_MT7668);
+#endif
+
#ifdef CONFIG_PM
/* Configure an out-of-band gpio as wake-up pin, if specified in device tree */
static int marvell_config_oob_wake(struct hci_dev *hdev)
@@ -3044,6 +3617,7 @@ static int btusb_probe(struct usb_interface *intf,
init_usb_anchor(&data->bulk_anchor);
init_usb_anchor(&data->isoc_anchor);
init_usb_anchor(&data->diag_anchor);
+ init_usb_anchor(&data->ctrl_anchor);
spin_lock_init(&data->rxlock);
if (id->driver_info & BTUSB_INTEL_NEW) {
@@ -3157,6 +3731,15 @@ static int btusb_probe(struct usb_interface *intf,
if (id->driver_info & BTUSB_MARVELL)
hdev->set_bdaddr = btusb_set_bdaddr_marvell;
+#ifdef CONFIG_BT_HCIBTUSB_MTK
+ if (id->driver_info & BTUSB_MEDIATEK) {
+ hdev->setup = btusb_mtk_setup;
+ hdev->shutdown = btusb_mtk_shutdown;
+ hdev->manufacturer = 70;
+ set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks);
+ }
+#endif
+
if (id->driver_info & BTUSB_SWAVE) {
set_bit(HCI_QUIRK_FIXUP_INQUIRY_MODE, &hdev->quirks);
set_bit(HCI_QUIRK_BROKEN_LOCAL_COMMANDS, &hdev->quirks);
@@ -3184,6 +3767,7 @@ static int btusb_probe(struct usb_interface *intf,
#ifdef CONFIG_BT_HCIBTUSB_RTL
if (id->driver_info & BTUSB_REALTEK) {
hdev->setup = btrtl_setup_realtek;
+ hdev->shutdown = btrtl_shutdown_realtek;
/* Realtek devices lose their updated firmware over suspend,
* but the USB hub doesn't notice any status change.
diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c
index 82b13faa9422..fe2e307009f4 100644
--- a/drivers/bluetooth/hci_bcsp.c
+++ b/drivers/bluetooth/hci_bcsp.c
@@ -744,6 +744,11 @@ static int bcsp_close(struct hci_uart *hu)
skb_queue_purge(&bcsp->rel);
skb_queue_purge(&bcsp->unrel);
+ if (bcsp->rx_skb) {
+ kfree_skb(bcsp->rx_skb);
+ bcsp->rx_skb = NULL;
+ }
+
kfree(bcsp);
return 0;
}
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index c84f985f348d..8950e07889fe 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -178,6 +178,7 @@ restart:
goto restart;
clear_bit(HCI_UART_SENDING, &hu->tx_state);
+ wake_up_bit(&hu->tx_state, HCI_UART_SENDING);
}
void hci_uart_init_work(struct work_struct *work)
@@ -213,6 +214,13 @@ int hci_uart_init_ready(struct hci_uart *hu)
return 0;
}
+int hci_uart_wait_until_sent(struct hci_uart *hu)
+{
+ return wait_on_bit_timeout(&hu->tx_state, HCI_UART_SENDING,
+ TASK_INTERRUPTIBLE,
+ msecs_to_jiffies(2000));
+}
+
/* ------- Interface to HCI layer ------ */
/* Reset device */
static int hci_uart_flush(struct hci_dev *hdev)
diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c
index c04f5f9e1ed0..285706618f8a 100644
--- a/drivers/bluetooth/hci_ll.c
+++ b/drivers/bluetooth/hci_ll.c
@@ -128,6 +128,7 @@ static int ll_open(struct hci_uart *hu)
if (hu->serdev) {
struct ll_device *lldev = serdev_device_get_drvdata(hu->serdev);
+
if (!IS_ERR(lldev->ext_clk))
clk_prepare_enable(lldev->ext_clk);
}
@@ -162,6 +163,7 @@ static int ll_close(struct hci_uart *hu)
if (hu->serdev) {
struct ll_device *lldev = serdev_device_get_drvdata(hu->serdev);
+
gpiod_set_value_cansleep(lldev->enable_gpio, 0);
clk_disable_unprepare(lldev->ext_clk);
@@ -227,7 +229,8 @@ static void ll_device_want_to_wakeup(struct hci_uart *hu)
break;
default:
/* any other state is illegal */
- BT_ERR("received HCILL_WAKE_UP_IND in state %ld", ll->hcill_state);
+ BT_ERR("received HCILL_WAKE_UP_IND in state %ld",
+ ll->hcill_state);
break;
}
@@ -256,7 +259,8 @@ static void ll_device_want_to_sleep(struct hci_uart *hu)
/* sanity check */
if (ll->hcill_state != HCILL_AWAKE)
- BT_ERR("ERR: HCILL_GO_TO_SLEEP_IND in state %ld", ll->hcill_state);
+ BT_ERR("ERR: HCILL_GO_TO_SLEEP_IND in state %ld",
+ ll->hcill_state);
/* acknowledge device sleep */
if (send_hcill_cmd(HCILL_GO_TO_SLEEP_ACK, hu) < 0) {
@@ -289,7 +293,8 @@ static void ll_device_woke_up(struct hci_uart *hu)
/* sanity check */
if (ll->hcill_state != HCILL_ASLEEP_TO_AWAKE)
- BT_ERR("received HCILL_WAKE_UP_ACK in state %ld", ll->hcill_state);
+ BT_ERR("received HCILL_WAKE_UP_ACK in state %ld",
+ ll->hcill_state);
/* send pending packets and change state to HCILL_AWAKE */
__ll_do_awake(ll);
@@ -338,7 +343,8 @@ static int ll_enqueue(struct hci_uart *hu, struct sk_buff *skb)
skb_queue_tail(&ll->tx_wait_q, skb);
break;
default:
- BT_ERR("illegal hcill state: %ld (losing packet)", ll->hcill_state);
+ BT_ERR("illegal hcill state: %ld (losing packet)",
+ ll->hcill_state);
kfree_skb(skb);
break;
}
@@ -438,6 +444,7 @@ static int ll_recv(struct hci_uart *hu, const void *data, int count)
static struct sk_buff *ll_dequeue(struct hci_uart *hu)
{
struct ll_struct *ll = hu->priv;
+
return skb_dequeue(&ll->txq);
}
@@ -449,7 +456,8 @@ static int read_local_version(struct hci_dev *hdev)
struct sk_buff *skb;
struct hci_rp_read_local_version *ver;
- skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, HCI_INIT_TIMEOUT);
+ skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
+ HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Reading TI version information failed (%ld)",
PTR_ERR(skb));
@@ -469,11 +477,38 @@ static int read_local_version(struct hci_dev *hdev)
version = le16_to_cpu(ver->lmp_subver);
out:
- if (err) bt_dev_err(hdev, "Failed to read TI version info: %d", err);
+ if (err)
+ bt_dev_err(hdev, "Failed to read TI version info: %d", err);
kfree_skb(skb);
return err ? err : version;
}
+static int send_command_from_firmware(struct ll_device *lldev,
+ struct hci_command *cmd)
+{
+ struct sk_buff *skb;
+
+ if (cmd->opcode == HCI_VS_UPDATE_UART_HCI_BAUDRATE) {
+ /* ignore remote change
+ * baud rate HCI VS command
+ */
+ bt_dev_warn(lldev->hu.hdev,
+ "change remote baud rate command in firmware");
+ return 0;
+ }
+ if (cmd->prefix != 1)
+ bt_dev_dbg(lldev->hu.hdev, "command type %d", cmd->prefix);
+
+ skb = __hci_cmd_sync(lldev->hu.hdev, cmd->opcode, cmd->plen,
+ &cmd->speed, HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ bt_dev_err(lldev->hu.hdev, "send command failed");
+ return PTR_ERR(skb);
+ }
+ kfree_skb(skb);
+ return 0;
+}
+
/**
* download_firmware -
* internal function which parses through the .bts firmware
@@ -486,7 +521,6 @@ static int download_firmware(struct ll_device *lldev)
unsigned char *ptr, *action_ptr;
unsigned char bts_scr_name[40]; /* 40 char long bts scr name? */
const struct firmware *fw;
- struct sk_buff *skb;
struct hci_command *cmd;
version = read_local_version(lldev->hu.hdev);
@@ -528,23 +562,9 @@ static int download_firmware(struct ll_device *lldev)
case ACTION_SEND_COMMAND: /* action send */
bt_dev_dbg(lldev->hu.hdev, "S");
cmd = (struct hci_command *)action_ptr;
- if (cmd->opcode == HCI_VS_UPDATE_UART_HCI_BAUDRATE) {
- /* ignore remote change
- * baud rate HCI VS command
- */
- bt_dev_warn(lldev->hu.hdev, "change remote baud rate command in firmware");
- break;
- }
- if (cmd->prefix != 1)
- bt_dev_dbg(lldev->hu.hdev, "command type %d", cmd->prefix);
-
- skb = __hci_cmd_sync(lldev->hu.hdev, cmd->opcode, cmd->plen, &cmd->speed, HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- bt_dev_err(lldev->hu.hdev, "send command failed");
- err = PTR_ERR(skb);
+ err = send_command_from_firmware(lldev, cmd);
+ if (err)
goto out_rel_fw;
- }
- kfree_skb(skb);
break;
case ACTION_WAIT_EVENT: /* wait */
/* no need to wait as command was synchronous */
@@ -601,6 +621,13 @@ static int ll_setup(struct hci_uart *hu)
serdev_device_set_flow_control(serdev, true);
+ if (hu->oper_speed)
+ speed = hu->oper_speed;
+ else if (hu->proto->oper_speed)
+ speed = hu->proto->oper_speed;
+ else
+ speed = 0;
+
do {
/* Reset the Bluetooth device */
gpiod_set_value_cansleep(lldev->enable_gpio, 0);
@@ -612,6 +639,20 @@ static int ll_setup(struct hci_uart *hu)
return err;
}
+ if (speed) {
+ __le32 speed_le = cpu_to_le32(speed);
+ struct sk_buff *skb;
+
+ skb = __hci_cmd_sync(hu->hdev,
+ HCI_VS_UPDATE_UART_HCI_BAUDRATE,
+ sizeof(speed_le), &speed_le,
+ HCI_INIT_TIMEOUT);
+ if (!IS_ERR(skb)) {
+ kfree_skb(skb);
+ serdev_device_set_baudrate(serdev, speed);
+ }
+ }
+
err = download_firmware(lldev);
if (!err)
break;
@@ -636,25 +677,7 @@ static int ll_setup(struct hci_uart *hu)
}
/* Operational speed if any */
- if (hu->oper_speed)
- speed = hu->oper_speed;
- else if (hu->proto->oper_speed)
- speed = hu->proto->oper_speed;
- else
- speed = 0;
-
- if (speed) {
- __le32 speed_le = cpu_to_le32(speed);
- struct sk_buff *skb;
- skb = __hci_cmd_sync(hu->hdev, HCI_VS_UPDATE_UART_HCI_BAUDRATE,
- sizeof(speed_le), &speed_le,
- HCI_INIT_TIMEOUT);
- if (!IS_ERR(skb)) {
- kfree_skb(skb);
- serdev_device_set_baudrate(serdev, speed);
- }
- }
return 0;
}
@@ -676,7 +699,9 @@ static int hci_ti_probe(struct serdev_device *serdev)
serdev_device_set_drvdata(serdev, lldev);
lldev->serdev = hu->serdev = serdev;
- lldev->enable_gpio = devm_gpiod_get_optional(&serdev->dev, "enable", GPIOD_OUT_LOW);
+ lldev->enable_gpio = devm_gpiod_get_optional(&serdev->dev,
+ "enable",
+ GPIOD_OUT_LOW);
if (IS_ERR(lldev->enable_gpio))
return PTR_ERR(lldev->enable_gpio);
diff --git a/drivers/bluetooth/hci_mrvl.c b/drivers/bluetooth/hci_mrvl.c
index 50212ac629e3..f98e5cc343b2 100644
--- a/drivers/bluetooth/hci_mrvl.c
+++ b/drivers/bluetooth/hci_mrvl.c
@@ -13,6 +13,8 @@
#include <linux/firmware.h>
#include <linux/module.h>
#include <linux/tty.h>
+#include <linux/of.h>
+#include <linux/serdev.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@@ -40,6 +42,10 @@ struct mrvl_data {
u8 id, rev;
};
+struct mrvl_serdev {
+ struct hci_uart hu;
+};
+
struct hci_mrvl_pkt {
__le16 lhs;
__le16 rhs;
@@ -49,6 +55,7 @@ struct hci_mrvl_pkt {
static int mrvl_open(struct hci_uart *hu)
{
struct mrvl_data *mrvl;
+ int ret;
BT_DBG("hu %p", hu);
@@ -62,7 +69,18 @@ static int mrvl_open(struct hci_uart *hu)
set_bit(STATE_CHIP_VER_PENDING, &mrvl->flags);
hu->priv = mrvl;
+
+ if (hu->serdev) {
+ ret = serdev_device_open(hu->serdev);
+ if (ret)
+ goto err;
+ }
+
return 0;
+err:
+ kfree(mrvl);
+
+ return ret;
}
static int mrvl_close(struct hci_uart *hu)
@@ -71,6 +89,9 @@ static int mrvl_close(struct hci_uart *hu)
BT_DBG("hu %p", hu);
+ if (hu->serdev)
+ serdev_device_close(hu->serdev);
+
skb_queue_purge(&mrvl->txq);
skb_queue_purge(&mrvl->rawq);
kfree_skb(mrvl->rx_skb);
@@ -339,7 +360,14 @@ static int mrvl_setup(struct hci_uart *hu)
return -EINVAL;
}
- hci_uart_set_baudrate(hu, 3000000);
+ /* Let the final ack go out before switching the baudrate */
+ hci_uart_wait_until_sent(hu);
+
+ if (hu->serdev)
+ serdev_device_set_baudrate(hu->serdev, 3000000);
+ else
+ hci_uart_set_baudrate(hu, 3000000);
+
hci_uart_set_flow_control(hu, false);
err = mrvl_load_firmware(hu->hdev, "mrvl/uart8897_bt.bin");
@@ -362,12 +390,54 @@ static const struct hci_uart_proto mrvl_proto = {
.dequeue = mrvl_dequeue,
};
+static int mrvl_serdev_probe(struct serdev_device *serdev)
+{
+ struct mrvl_serdev *mrvldev;
+
+ mrvldev = devm_kzalloc(&serdev->dev, sizeof(*mrvldev), GFP_KERNEL);
+ if (!mrvldev)
+ return -ENOMEM;
+
+ mrvldev->hu.serdev = serdev;
+ serdev_device_set_drvdata(serdev, mrvldev);
+
+ return hci_uart_register_device(&mrvldev->hu, &mrvl_proto);
+}
+
+static void mrvl_serdev_remove(struct serdev_device *serdev)
+{
+ struct mrvl_serdev *mrvldev = serdev_device_get_drvdata(serdev);
+
+ hci_uart_unregister_device(&mrvldev->hu);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id mrvl_bluetooth_of_match[] = {
+ { .compatible = "mrvl,88w8897" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, mrvl_bluetooth_of_match);
+#endif
+
+static struct serdev_device_driver mrvl_serdev_driver = {
+ .probe = mrvl_serdev_probe,
+ .remove = mrvl_serdev_remove,
+ .driver = {
+ .name = "hci_uart_mrvl",
+ .of_match_table = of_match_ptr(mrvl_bluetooth_of_match),
+ },
+};
+
int __init mrvl_init(void)
{
+ serdev_device_driver_register(&mrvl_serdev_driver);
+
return hci_uart_register_proto(&mrvl_proto);
}
int __exit mrvl_deinit(void)
{
+ serdev_device_driver_unregister(&mrvl_serdev_driver);
+
return hci_uart_unregister_proto(&mrvl_proto);
}
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index 9d273cdde563..9a5c9c1f9484 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -17,6 +17,7 @@
#include <linux/kernel.h>
#include <linux/clk.h>
+#include <linux/completion.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -53,6 +54,7 @@
enum qca_flags {
QCA_IBS_ENABLED,
+ QCA_DROP_VENDOR_EVENT,
};
/* HCI_IBS transmit side sleep protocol states */
@@ -97,6 +99,7 @@ struct qca_data {
struct work_struct ws_rx_vote_off;
struct work_struct ws_tx_vote_off;
unsigned long flags;
+ struct completion drop_ev_comp;
/* For debugging purpose */
u64 ibs_sent_wacks;
@@ -156,6 +159,7 @@ struct qca_serdev {
struct qca_power *bt_power;
u32 init_speed;
u32 oper_speed;
+ const char *firmware_name;
};
static int qca_power_setup(struct hci_uart *hu, bool on);
@@ -177,6 +181,17 @@ static enum qca_btsoc_type qca_soc_type(struct hci_uart *hu)
return soc_type;
}
+static const char *qca_get_firmware_name(struct hci_uart *hu)
+{
+ if (hu->serdev) {
+ struct qca_serdev *qsd = serdev_device_get_drvdata(hu->serdev);
+
+ return qsd->firmware_name;
+ } else {
+ return NULL;
+ }
+}
+
static void __serial_clock_on(struct tty_struct *tty)
{
/* TODO: Some chipset requires to enable UART clock on client
@@ -478,6 +493,7 @@ static int qca_open(struct hci_uart *hu)
INIT_WORK(&qca->ws_tx_vote_off, qca_wq_serial_tx_clock_vote_off);
qca->hu = hu;
+ init_completion(&qca->drop_ev_comp);
/* Assume we start with both sides asleep -- extra wakes OK */
qca->tx_ibs_state = HCI_IBS_TX_ASLEEP;
@@ -872,6 +888,35 @@ static int qca_recv_acl_data(struct hci_dev *hdev, struct sk_buff *skb)
return hci_recv_frame(hdev, skb);
}
+static int qca_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ struct hci_uart *hu = hci_get_drvdata(hdev);
+ struct qca_data *qca = hu->priv;
+
+ if (test_bit(QCA_DROP_VENDOR_EVENT, &qca->flags)) {
+ struct hci_event_hdr *hdr = (void *)skb->data;
+
+ /* For the WCN3990 the vendor command for a baudrate change
+ * isn't sent as synchronous HCI command, because the
+ * controller sends the corresponding vendor event with the
+ * new baudrate. The event is received and properly decoded
+ * after changing the baudrate of the host port. It needs to
+ * be dropped, otherwise it can be misinterpreted as
+ * response to a later firmware download command (also a
+ * vendor command).
+ */
+
+ if (hdr->evt == HCI_EV_VENDOR)
+ complete(&qca->drop_ev_comp);
+
+ kfree(skb);
+
+ return 0;
+ }
+
+ return hci_recv_frame(hdev, skb);
+}
+
#define QCA_IBS_SLEEP_IND_EVENT \
.type = HCI_IBS_SLEEP_IND, \
.hlen = 0, \
@@ -896,7 +941,7 @@ static int qca_recv_acl_data(struct hci_dev *hdev, struct sk_buff *skb)
static const struct h4_recv_pkt qca_recv_pkts[] = {
{ H4_RECV_ACL, .recv = qca_recv_acl_data },
{ H4_RECV_SCO, .recv = hci_recv_frame },
- { H4_RECV_EVENT, .recv = hci_recv_frame },
+ { H4_RECV_EVENT, .recv = qca_recv_event },
{ QCA_IBS_WAKE_IND_EVENT, .recv = qca_ibs_wake_ind },
{ QCA_IBS_WAKE_ACK_EVENT, .recv = qca_ibs_wake_ack },
{ QCA_IBS_SLEEP_IND_EVENT, .recv = qca_ibs_sleep_ind },
@@ -1091,6 +1136,7 @@ static int qca_check_speeds(struct hci_uart *hu)
static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
{
unsigned int speed, qca_baudrate;
+ struct qca_data *qca = hu->priv;
int ret = 0;
if (speed_type == QCA_INIT_SPEED) {
@@ -1110,6 +1156,11 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
if (qca_is_wcn399x(soc_type))
hci_uart_set_flow_control(hu, true);
+ if (soc_type == QCA_WCN3990) {
+ reinit_completion(&qca->drop_ev_comp);
+ set_bit(QCA_DROP_VENDOR_EVENT, &qca->flags);
+ }
+
qca_baudrate = qca_get_baudrate_value(speed);
bt_dev_dbg(hu->hdev, "Set UART speed to %d", speed);
ret = qca_set_baudrate(hu->hdev, qca_baudrate);
@@ -1121,6 +1172,20 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
error:
if (qca_is_wcn399x(soc_type))
hci_uart_set_flow_control(hu, false);
+
+ if (soc_type == QCA_WCN3990) {
+ /* Wait for the controller to send the vendor event
+ * for the baudrate change command.
+ */
+ if (!wait_for_completion_timeout(&qca->drop_ev_comp,
+ msecs_to_jiffies(100))) {
+ bt_dev_err(hu->hdev,
+ "Failed to change controller baudrate\n");
+ ret = -ETIMEDOUT;
+ }
+
+ clear_bit(QCA_DROP_VENDOR_EVENT, &qca->flags);
+ }
}
return ret;
@@ -1182,6 +1247,7 @@ static int qca_setup(struct hci_uart *hu)
struct qca_data *qca = hu->priv;
unsigned int speed, qca_baudrate = QCA_BAUDRATE_115200;
enum qca_btsoc_type soc_type = qca_soc_type(hu);
+ const char *firmware_name = qca_get_firmware_name(hu);
int ret;
int soc_ver = 0;
@@ -1232,7 +1298,8 @@ static int qca_setup(struct hci_uart *hu)
bt_dev_info(hdev, "QCA controller version 0x%08x", soc_ver);
/* Setup patch / NVM configurations */
- ret = qca_uart_setup(hdev, qca_baudrate, soc_type, soc_ver);
+ ret = qca_uart_setup(hdev, qca_baudrate, soc_type, soc_ver,
+ firmware_name);
if (!ret) {
set_bit(QCA_IBS_ENABLED, &qca->flags);
qca_debugfs_init(hdev);
@@ -1426,6 +1493,8 @@ static int qca_serdev_probe(struct serdev_device *serdev)
qcadev->serdev_hu.serdev = serdev;
data = of_device_get_match_data(&serdev->dev);
serdev_device_set_drvdata(serdev, qcadev);
+ device_property_read_string(&serdev->dev, "firmware-name",
+ &qcadev->firmware_name);
if (data && qca_is_wcn399x(data->soc_type)) {
qcadev->btsoc_type = data->soc_type;
qcadev->bt_power = devm_kzalloc(&serdev->dev,
diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
index d8cf005e3c5d..f11af3912ce6 100644
--- a/drivers/bluetooth/hci_uart.h
+++ b/drivers/bluetooth/hci_uart.h
@@ -100,6 +100,7 @@ int hci_uart_register_device(struct hci_uart *hu, const struct hci_uart_proto *p
void hci_uart_unregister_device(struct hci_uart *hu);
int hci_uart_tx_wakeup(struct hci_uart *hu);
+int hci_uart_wait_until_sent(struct hci_uart *hu);
int hci_uart_init_ready(struct hci_uart *hu);
void hci_uart_init_work(struct work_struct *work);
void hci_uart_set_baudrate(struct hci_uart *hu, unsigned int speed);
diff --git a/drivers/bus/da8xx-mstpri.c b/drivers/bus/da8xx-mstpri.c
index 9af9bcc68059..ee4c02335130 100644
--- a/drivers/bus/da8xx-mstpri.c
+++ b/drivers/bus/da8xx-mstpri.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TI da8xx master peripheral priority driver
*
@@ -5,10 +6,6 @@
*
* Author:
* Bartosz Golaszewski <bgolaszewski@baylibre.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/bus/qcom-ebi2.c b/drivers/bus/qcom-ebi2.c
index 56b01e4344d3..03ddcf426887 100644
--- a/drivers/bus/qcom-ebi2.c
+++ b/drivers/bus/qcom-ebi2.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Qualcomm External Bus Interface 2 (EBI2) driver
* an older version of the Qualcomm Parallel Interface Controller (QPIC)
@@ -6,10 +7,6 @@
*
* Author: Linus Walleij <linus.walleij@linaro.org>
*
- * 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.
- *
* See the device tree bindings for this block for more details on the
* hardware.
*/
diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
index 308475ed4b32..b72741668c92 100644
--- a/drivers/bus/ti-sysc.c
+++ b/drivers/bus/ti-sysc.c
@@ -660,12 +660,6 @@ static int sysc_check_registers(struct sysc *ddata)
nr_regs++;
}
- if (nr_regs < 1) {
- dev_err(ddata->dev, "missing registers\n");
-
- return -EINVAL;
- }
-
if (nr_matches > nr_regs) {
dev_err(ddata->dev, "overlapping registers: (%i/%i)",
nr_regs, nr_matches);
@@ -691,12 +685,18 @@ static int sysc_ioremap(struct sysc *ddata)
{
int size;
- size = max3(ddata->offsets[SYSC_REVISION],
- ddata->offsets[SYSC_SYSCONFIG],
- ddata->offsets[SYSC_SYSSTATUS]);
+ if (ddata->offsets[SYSC_REVISION] < 0 &&
+ ddata->offsets[SYSC_SYSCONFIG] < 0 &&
+ ddata->offsets[SYSC_SYSSTATUS] < 0) {
+ size = ddata->module_size;
+ } else {
+ size = max3(ddata->offsets[SYSC_REVISION],
+ ddata->offsets[SYSC_SYSCONFIG],
+ ddata->offsets[SYSC_SYSSTATUS]);
- if (size < 0 || (size + sizeof(u32)) > ddata->module_size)
- return -EINVAL;
+ if ((size + sizeof(u32)) > ddata->module_size)
+ return -EINVAL;
+ }
ddata->module_va = devm_ioremap(ddata->dev,
ddata->module_pa,
@@ -1128,7 +1128,6 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
SYSC_QUIRK("cpgmac", 0, 0x1200, 0x1208, 0x1204, 0x4edb1902,
0xffff00f0, 0),
SYSC_QUIRK("dcan", 0, 0, -1, -1, 0xffffffff, 0xffffffff, 0),
- SYSC_QUIRK("dcan", 0, 0, -1, -1, 0x00001401, 0xffffffff, 0),
SYSC_QUIRK("dmic", 0, 0, 0x10, -1, 0x50010000, 0xffffffff, 0),
SYSC_QUIRK("dwc3", 0, 0, 0x10, -1, 0x500a0200, 0xffffffff, 0),
SYSC_QUIRK("epwmss", 0, 0, 0x4, -1, 0x47400001, 0xffffffff, 0),
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index 933268b8d6a5..ac42ae4651ce 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -7,7 +7,7 @@
License. See linux/COPYING for more information.
Uniform CD-ROM driver for Linux.
- See Documentation/cdrom/cdrom-standard.tex for usage information.
+ See Documentation/cdrom/cdrom-standard.rst for usage information.
The routines in the file provide a uniform interface between the
software that uses CD-ROMs and the various low-level drivers that
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 466ebd84ad17..3e866885a405 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -291,7 +291,7 @@ config RTC
and set the RTC in an SMP compatible fashion.
If you think you have a use for such a device (such as periodic data
- sampling), then say Y here, and read <file:Documentation/rtc.txt>
+ sampling), then say Y here, and read <file:Documentation/admin-guide/rtc.rst>
for details.
To compile this driver as a module, choose M here: the
@@ -313,7 +313,7 @@ config JS_RTC
/dev/rtc.
If you think you have a use for such a device (such as periodic data
- sampling), then say Y here, and read <file:Documentation/rtc.txt>
+ sampling), then say Y here, and read <file:Documentation/admin-guide/rtc.rst>
for details.
To compile this driver as a module, choose M here: the
@@ -382,7 +382,7 @@ config SONYPI
Device which can be found in many (all ?) Sony Vaio laptops.
If you have one of those laptops, read
- <file:Documentation/laptops/sonypi.txt>, and say Y or M here.
+ <file:Documentation/admin-guide/laptops/sonypi.rst>, and say Y or M here.
To compile this driver as a module, choose M here: the
module will be called sonypi.
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index 658664a5a5aa..df1edb5ec0ad 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -1311,8 +1311,7 @@ static void ipi_handler(void *null)
void global_cache_flush(void)
{
- if (on_each_cpu(ipi_handler, NULL, 1) != 0)
- panic(PFX "timed out waiting for the other CPUs!\n");
+ on_each_cpu(ipi_handler, NULL, 1);
}
EXPORT_SYMBOL(global_cache_flush);
diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c
index 3695773ce7c3..84d9adbb62f6 100644
--- a/drivers/char/agp/hp-agp.c
+++ b/drivers/char/agp/hp-agp.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* HP zx1 AGPGART routines.
*
* (c) Copyright 2002, 2003 Hewlett-Packard Development Company, L.P.
* Bjorn Helgaas <bjorn.helgaas@hp.com>
- *
- * 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.
*/
#include <linux/acpi.h>
diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c
index 15f2e7025b78..ed3c4c42fc23 100644
--- a/drivers/char/agp/parisc-agp.c
+++ b/drivers/char/agp/parisc-agp.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* HP Quicksilver AGP GART routines
*
@@ -6,11 +7,6 @@
* Based on drivers/char/agpgart/hp-agp.c which is
* (c) Copyright 2002, 2003 Hewlett-Packard Development Company, L.P.
* Bjorn Helgaas <bjorn.helgaas@hp.com>
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c
index 167e7370d43a..e5e5333f302d 100644
--- a/drivers/char/bsr.c
+++ b/drivers/char/bsr.c
@@ -134,7 +134,7 @@ static int bsr_mmap(struct file *filp, struct vm_area_struct *vma)
return 0;
}
-static int bsr_open(struct inode * inode, struct file * filp)
+static int bsr_open(struct inode *inode, struct file *filp)
{
struct cdev *cdev = inode->i_cdev;
struct bsr_dev *dev = container_of(cdev, struct bsr_dev, bsr_cdev);
@@ -309,7 +309,8 @@ static int __init bsr_init(void)
goto out_err_2;
}
- if ((ret = bsr_create_devs(np)) < 0) {
+ ret = bsr_create_devs(np);
+ if (ret < 0) {
np = NULL;
goto out_err_3;
}
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 3a1e6b3ccd10..5c39f20378b8 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Intel & MS High Precision Event Timer Implementation.
*
@@ -5,10 +6,6 @@
* Venki Pallipadi
* (c) Copyright 2004 Hewlett-Packard Development Company, L.P.
* Bob Picco <robert.picco@hp.com>
- *
- * 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.
*/
#include <linux/interrupt.h>
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index 95be7228f327..9044d31ab1a1 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -4,7 +4,7 @@
* Copyright 2006 Michael Buesch <m@bues.ch>
* Copyright 2005 (c) MontaVista Software, Inc.
*
- * Please read Documentation/hw_random.txt for details on use.
+ * Please read Documentation/admin-guide/hw_random.rst for details on use.
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
diff --git a/drivers/char/hw_random/hisi-rng.c b/drivers/char/hw_random/hisi-rng.c
index 40d96572c591..c663d5dd85bb 100644
--- a/drivers/char/hw_random/hisi-rng.c
+++ b/drivers/char/hw_random/hisi-rng.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2016 HiSilicon Co., Ltd.
- *
- * 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.
*/
#include <linux/err.h>
diff --git a/drivers/char/hw_random/iproc-rng200.c b/drivers/char/hw_random/iproc-rng200.c
index 8b5a20b35293..92be1c0ab99f 100644
--- a/drivers/char/hw_random/iproc-rng200.c
+++ b/drivers/char/hw_random/iproc-rng200.c
@@ -220,6 +220,7 @@ static int iproc_rng200_probe(struct platform_device *pdev)
}
static const struct of_device_id iproc_rng200_of_match[] = {
+ { .compatible = "brcm,bcm7211-rng200", },
{ .compatible = "brcm,bcm7278-rng200", },
{ .compatible = "brcm,iproc-rng200", },
{},
diff --git a/drivers/char/hw_random/meson-rng.c b/drivers/char/hw_random/meson-rng.c
index 2e23be802a62..76e693da5dde 100644
--- a/drivers/char/hw_random/meson-rng.c
+++ b/drivers/char/hw_random/meson-rng.c
@@ -1,58 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * This file is provided under a dual BSD/GPLv2 license. When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
* Copyright (c) 2016 BayLibre, SAS.
* Author: Neil Armstrong <narmstrong@baylibre.com>
* Copyright (C) 2014 Amlogic, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- * The full GNU General Public License is included in this distribution
- * in the file called COPYING.
- *
- * BSD LICENSE
- *
- * Copyright (c) 2016 BayLibre, SAS.
- * Author: Neil Armstrong <narmstrong@baylibre.com>
- * Copyright (C) 2014 Amlogic, Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Intel Corporation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <linux/err.h>
#include <linux/module.h>
diff --git a/drivers/char/hw_random/st-rng.c b/drivers/char/hw_random/st-rng.c
index 938ec10e733d..bd6a98b3479b 100644
--- a/drivers/char/hw_random/st-rng.c
+++ b/drivers/char/hw_random/st-rng.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ST Random Number Generator Driver ST's Platforms
*
@@ -5,10 +6,6 @@
* Lee Jones <lee.jones@linaro.org>
*
* Copyright (C) 2015 STMicroelectronics (R&D) Limited
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/char/hw_random/timeriomem-rng.c b/drivers/char/hw_random/timeriomem-rng.c
index f615684028af..ccd1f6e0696b 100644
--- a/drivers/char/hw_random/timeriomem-rng.c
+++ b/drivers/char/hw_random/timeriomem-rng.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/char/hw_random/timeriomem-rng.c
*
@@ -7,10 +8,6 @@
* Copyright 2005 (c) MontaVista Software, Inc.
* Author: Deepak Saxena <dsaxena@plexity.net>
*
- * 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.
- *
* Overview:
* This driver is useful for platforms that have an IO range that provides
* periodic random data from a single IO memory address. All the platform
diff --git a/drivers/char/ipmi/Kconfig b/drivers/char/ipmi/Kconfig
index caac5d24baa4..4bad0614109b 100644
--- a/drivers/char/ipmi/Kconfig
+++ b/drivers/char/ipmi/Kconfig
@@ -132,3 +132,12 @@ config ASPEED_BT_IPMI_BMC
Provides a driver for the BT (Block Transfer) IPMI interface
found on Aspeed SOCs (AST2400 and AST2500). The driver
implements the BMC side of the BT interface.
+
+config IPMB_DEVICE_INTERFACE
+ tristate 'IPMB Interface handler'
+ depends on I2C
+ depends on I2C_SLAVE
+ help
+ Provides a driver for a device (Satellite MC) to
+ receive requests and send responses back to the BMC via
+ the IPMB interface. This module requires I2C support.
diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile
index 3f06b2062475..0822adc2ec41 100644
--- a/drivers/char/ipmi/Makefile
+++ b/drivers/char/ipmi/Makefile
@@ -26,3 +26,4 @@ obj-$(CONFIG_IPMI_KCS_BMC) += kcs_bmc.o
obj-$(CONFIG_ASPEED_BT_IPMI_BMC) += bt-bmc.o
obj-$(CONFIG_ASPEED_KCS_IPMI_BMC) += kcs_bmc_aspeed.o
obj-$(CONFIG_NPCM7XX_KCS_IPMI_BMC) += kcs_bmc_npcm7xx.o
+obj-$(CONFIG_IPMB_DEVICE_INTERFACE) += ipmb_dev_int.o
diff --git a/drivers/char/ipmi/ipmb_dev_int.c b/drivers/char/ipmi/ipmb_dev_int.c
new file mode 100644
index 000000000000..57204335c5f5
--- /dev/null
+++ b/drivers/char/ipmi/ipmb_dev_int.c
@@ -0,0 +1,364 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * IPMB driver to receive a request and send a response
+ *
+ * Copyright (C) 2019 Mellanox Techologies, Ltd.
+ *
+ * This was inspired by Brendan Higgins' ipmi-bmc-bt-i2c driver.
+ */
+
+#include <linux/acpi.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+
+#define MAX_MSG_LEN 128
+#define IPMB_REQUEST_LEN_MIN 7
+#define NETFN_RSP_BIT_MASK 0x4
+#define REQUEST_QUEUE_MAX_LEN 256
+
+#define IPMB_MSG_LEN_IDX 0
+#define RQ_SA_8BIT_IDX 1
+#define NETFN_LUN_IDX 2
+
+#define GET_7BIT_ADDR(addr_8bit) (addr_8bit >> 1)
+#define GET_8BIT_ADDR(addr_7bit) ((addr_7bit << 1) & 0xff)
+
+#define IPMB_MSG_PAYLOAD_LEN_MAX (MAX_MSG_LEN - IPMB_REQUEST_LEN_MIN - 1)
+
+#define SMBUS_MSG_HEADER_LENGTH 2
+#define SMBUS_MSG_IDX_OFFSET (SMBUS_MSG_HEADER_LENGTH + 1)
+
+struct ipmb_msg {
+ u8 len;
+ u8 rs_sa;
+ u8 netfn_rs_lun;
+ u8 checksum1;
+ u8 rq_sa;
+ u8 rq_seq_rq_lun;
+ u8 cmd;
+ u8 payload[IPMB_MSG_PAYLOAD_LEN_MAX];
+ /* checksum2 is included in payload */
+} __packed;
+
+struct ipmb_request_elem {
+ struct list_head list;
+ struct ipmb_msg request;
+};
+
+struct ipmb_dev {
+ struct i2c_client *client;
+ struct miscdevice miscdev;
+ struct ipmb_msg request;
+ struct list_head request_queue;
+ atomic_t request_queue_len;
+ size_t msg_idx;
+ spinlock_t lock;
+ wait_queue_head_t wait_queue;
+ struct mutex file_mutex;
+};
+
+static inline struct ipmb_dev *to_ipmb_dev(struct file *file)
+{
+ return container_of(file->private_data, struct ipmb_dev, miscdev);
+}
+
+static ssize_t ipmb_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ struct ipmb_dev *ipmb_dev = to_ipmb_dev(file);
+ struct ipmb_request_elem *queue_elem;
+ struct ipmb_msg msg;
+ ssize_t ret;
+
+ memset(&msg, 0, sizeof(msg));
+
+ spin_lock_irq(&ipmb_dev->lock);
+
+ while (list_empty(&ipmb_dev->request_queue)) {
+ spin_unlock_irq(&ipmb_dev->lock);
+
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ ret = wait_event_interruptible(ipmb_dev->wait_queue,
+ !list_empty(&ipmb_dev->request_queue));
+ if (ret)
+ return ret;
+
+ spin_lock_irq(&ipmb_dev->lock);
+ }
+
+ queue_elem = list_first_entry(&ipmb_dev->request_queue,
+ struct ipmb_request_elem, list);
+ memcpy(&msg, &queue_elem->request, sizeof(msg));
+ list_del(&queue_elem->list);
+ kfree(queue_elem);
+ atomic_dec(&ipmb_dev->request_queue_len);
+
+ spin_unlock_irq(&ipmb_dev->lock);
+
+ count = min_t(size_t, count, msg.len + 1);
+ if (copy_to_user(buf, &msg, count))
+ ret = -EFAULT;
+
+ return ret < 0 ? ret : count;
+}
+
+static ssize_t ipmb_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct ipmb_dev *ipmb_dev = to_ipmb_dev(file);
+ u8 rq_sa, netf_rq_lun, msg_len;
+ union i2c_smbus_data data;
+ u8 msg[MAX_MSG_LEN];
+ ssize_t ret;
+
+ if (count > sizeof(msg))
+ return -EINVAL;
+
+ if (copy_from_user(&msg, buf, count))
+ return -EFAULT;
+
+ if (count < msg[0])
+ return -EINVAL;
+
+ rq_sa = GET_7BIT_ADDR(msg[RQ_SA_8BIT_IDX]);
+ netf_rq_lun = msg[NETFN_LUN_IDX];
+
+ if (!(netf_rq_lun & NETFN_RSP_BIT_MASK))
+ return -EINVAL;
+
+ /*
+ * subtract rq_sa and netf_rq_lun from the length of the msg passed to
+ * i2c_smbus_xfer
+ */
+ msg_len = msg[IPMB_MSG_LEN_IDX] - SMBUS_MSG_HEADER_LENGTH;
+ if (msg_len > I2C_SMBUS_BLOCK_MAX)
+ msg_len = I2C_SMBUS_BLOCK_MAX;
+
+ data.block[0] = msg_len;
+ memcpy(&data.block[1], msg + SMBUS_MSG_IDX_OFFSET, msg_len);
+ ret = i2c_smbus_xfer(ipmb_dev->client->adapter, rq_sa,
+ ipmb_dev->client->flags,
+ I2C_SMBUS_WRITE, netf_rq_lun,
+ I2C_SMBUS_BLOCK_DATA, &data);
+
+ return ret ? : count;
+}
+
+static unsigned int ipmb_poll(struct file *file, poll_table *wait)
+{
+ struct ipmb_dev *ipmb_dev = to_ipmb_dev(file);
+ unsigned int mask = POLLOUT;
+
+ mutex_lock(&ipmb_dev->file_mutex);
+ poll_wait(file, &ipmb_dev->wait_queue, wait);
+
+ if (atomic_read(&ipmb_dev->request_queue_len))
+ mask |= POLLIN;
+ mutex_unlock(&ipmb_dev->file_mutex);
+
+ return mask;
+}
+
+static const struct file_operations ipmb_fops = {
+ .owner = THIS_MODULE,
+ .read = ipmb_read,
+ .write = ipmb_write,
+ .poll = ipmb_poll,
+};
+
+/* Called with ipmb_dev->lock held. */
+static void ipmb_handle_request(struct ipmb_dev *ipmb_dev)
+{
+ struct ipmb_request_elem *queue_elem;
+
+ if (atomic_read(&ipmb_dev->request_queue_len) >=
+ REQUEST_QUEUE_MAX_LEN)
+ return;
+
+ queue_elem = kmalloc(sizeof(*queue_elem), GFP_ATOMIC);
+ if (!queue_elem)
+ return;
+
+ memcpy(&queue_elem->request, &ipmb_dev->request,
+ sizeof(struct ipmb_msg));
+ list_add(&queue_elem->list, &ipmb_dev->request_queue);
+ atomic_inc(&ipmb_dev->request_queue_len);
+ wake_up_all(&ipmb_dev->wait_queue);
+}
+
+static u8 ipmb_verify_checksum1(struct ipmb_dev *ipmb_dev, u8 rs_sa)
+{
+ /* The 8 lsb of the sum is 0 when the checksum is valid */
+ return (rs_sa + ipmb_dev->request.netfn_rs_lun +
+ ipmb_dev->request.checksum1);
+}
+
+static bool is_ipmb_request(struct ipmb_dev *ipmb_dev, u8 rs_sa)
+{
+ if (ipmb_dev->msg_idx >= IPMB_REQUEST_LEN_MIN) {
+ if (ipmb_verify_checksum1(ipmb_dev, rs_sa))
+ return false;
+
+ /*
+ * Check whether this is an IPMB request or
+ * response.
+ * The 6 MSB of netfn_rs_lun are dedicated to the netfn
+ * while the remaining bits are dedicated to the lun.
+ * If the LSB of the netfn is cleared, it is associated
+ * with an IPMB request.
+ * If the LSB of the netfn is set, it is associated with
+ * an IPMB response.
+ */
+ if (!(ipmb_dev->request.netfn_rs_lun & NETFN_RSP_BIT_MASK))
+ return true;
+ }
+ return false;
+}
+
+/*
+ * The IPMB protocol only supports I2C Writes so there is no need
+ * to support I2C_SLAVE_READ* events.
+ * This i2c callback function only monitors IPMB request messages
+ * and adds them in a queue, so that they can be handled by
+ * receive_ipmb_request.
+ */
+static int ipmb_slave_cb(struct i2c_client *client,
+ enum i2c_slave_event event, u8 *val)
+{
+ struct ipmb_dev *ipmb_dev = i2c_get_clientdata(client);
+ u8 *buf = (u8 *)&ipmb_dev->request;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ipmb_dev->lock, flags);
+ switch (event) {
+ case I2C_SLAVE_WRITE_REQUESTED:
+ memset(&ipmb_dev->request, 0, sizeof(ipmb_dev->request));
+ ipmb_dev->msg_idx = 0;
+
+ /*
+ * At index 0, ipmb_msg stores the length of msg,
+ * skip it for now.
+ * The len will be populated once the whole
+ * buf is populated.
+ *
+ * The I2C bus driver's responsibility is to pass the
+ * data bytes to the backend driver; it does not
+ * forward the i2c slave address.
+ * Since the first byte in the IPMB message is the
+ * address of the responder, it is the responsibility
+ * of the IPMB driver to format the message properly.
+ * So this driver prepends the address of the responder
+ * to the received i2c data before the request message
+ * is handled in userland.
+ */
+ buf[++ipmb_dev->msg_idx] = GET_8BIT_ADDR(client->addr);
+ break;
+
+ case I2C_SLAVE_WRITE_RECEIVED:
+ if (ipmb_dev->msg_idx >= sizeof(struct ipmb_msg))
+ break;
+
+ buf[++ipmb_dev->msg_idx] = *val;
+ break;
+
+ case I2C_SLAVE_STOP:
+ ipmb_dev->request.len = ipmb_dev->msg_idx;
+
+ if (is_ipmb_request(ipmb_dev, GET_8BIT_ADDR(client->addr)))
+ ipmb_handle_request(ipmb_dev);
+ break;
+
+ default:
+ break;
+ }
+ spin_unlock_irqrestore(&ipmb_dev->lock, flags);
+
+ return 0;
+}
+
+static int ipmb_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct ipmb_dev *ipmb_dev;
+ int ret;
+
+ ipmb_dev = devm_kzalloc(&client->dev, sizeof(*ipmb_dev),
+ GFP_KERNEL);
+ if (!ipmb_dev)
+ return -ENOMEM;
+
+ spin_lock_init(&ipmb_dev->lock);
+ init_waitqueue_head(&ipmb_dev->wait_queue);
+ atomic_set(&ipmb_dev->request_queue_len, 0);
+ INIT_LIST_HEAD(&ipmb_dev->request_queue);
+
+ mutex_init(&ipmb_dev->file_mutex);
+
+ ipmb_dev->miscdev.minor = MISC_DYNAMIC_MINOR;
+
+ ipmb_dev->miscdev.name = devm_kasprintf(&client->dev, GFP_KERNEL,
+ "%s%d", "ipmb-",
+ client->adapter->nr);
+ ipmb_dev->miscdev.fops = &ipmb_fops;
+ ipmb_dev->miscdev.parent = &client->dev;
+ ret = misc_register(&ipmb_dev->miscdev);
+ if (ret)
+ return ret;
+
+ ipmb_dev->client = client;
+ i2c_set_clientdata(client, ipmb_dev);
+ ret = i2c_slave_register(client, ipmb_slave_cb);
+ if (ret) {
+ misc_deregister(&ipmb_dev->miscdev);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ipmb_remove(struct i2c_client *client)
+{
+ struct ipmb_dev *ipmb_dev = i2c_get_clientdata(client);
+
+ i2c_slave_unregister(client);
+ misc_deregister(&ipmb_dev->miscdev);
+
+ return 0;
+}
+
+static const struct i2c_device_id ipmb_id[] = {
+ { "ipmb-dev", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, ipmb_id);
+
+static const struct acpi_device_id acpi_ipmb_id[] = {
+ { "IPMB0001", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, acpi_ipmb_id);
+
+static struct i2c_driver ipmb_driver = {
+ .driver = {
+ .name = "ipmb-dev",
+ .acpi_match_table = ACPI_PTR(acpi_ipmb_id),
+ },
+ .probe = ipmb_probe,
+ .remove = ipmb_remove,
+ .id_table = ipmb_id,
+};
+module_i2c_driver(ipmb_driver);
+
+MODULE_AUTHOR("Mellanox Technologies");
+MODULE_DESCRIPTION("IPMB driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 1dc10740fc0f..6707659cffd6 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -2819,9 +2819,9 @@ static const struct device_type bmc_device_type = {
.groups = bmc_dev_attr_groups,
};
-static int __find_bmc_guid(struct device *dev, void *data)
+static int __find_bmc_guid(struct device *dev, const void *data)
{
- guid_t *guid = data;
+ const guid_t *guid = data;
struct bmc_device *bmc;
int rv;
@@ -2857,9 +2857,9 @@ struct prod_dev_id {
unsigned char device_id;
};
-static int __find_bmc_prod_dev_id(struct device *dev, void *data)
+static int __find_bmc_prod_dev_id(struct device *dev, const void *data)
{
- struct prod_dev_id *cid = data;
+ const struct prod_dev_id *cid = data;
struct bmc_device *bmc;
int rv;
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index f124a2d2bb9f..da5b6723329a 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -71,7 +71,7 @@ enum si_intf_state {
static const char * const si_to_str[] = { "invalid", "kcs", "smic", "bt" };
-static int initialized;
+static bool initialized;
/*
* Indexes into stats[] in smi_info below.
@@ -2124,7 +2124,7 @@ static int __init init_ipmi_si(void)
}
skip_fallback_noirq:
- initialized = 1;
+ initialized = true;
mutex_unlock(&smi_infos_lock);
if (type)
diff --git a/drivers/char/ipmi/ipmi_si_platform.c b/drivers/char/ipmi/ipmi_si_platform.c
index f2a91c4d8cab..22f6c9b20e9a 100644
--- a/drivers/char/ipmi/ipmi_si_platform.c
+++ b/drivers/char/ipmi/ipmi_si_platform.c
@@ -19,6 +19,7 @@
#include "ipmi_si.h"
#include "ipmi_dmi.h"
+static bool platform_registered;
static bool si_tryplatform = true;
#ifdef CONFIG_ACPI
static bool si_tryacpi = true;
@@ -426,7 +427,7 @@ static int ipmi_remove(struct platform_device *pdev)
return ipmi_si_remove_by_dev(&pdev->dev);
}
-static int pdev_match_name(struct device *dev, void *data)
+static int pdev_match_name(struct device *dev, const void *data)
{
struct platform_device *pdev = to_platform_device(dev);
const char *name = data;
@@ -443,6 +444,7 @@ void ipmi_remove_platform_device_by_name(char *name)
struct platform_device *pdev = to_platform_device(dev);
platform_device_unregister(pdev);
+ put_device(dev);
}
}
@@ -469,9 +471,12 @@ void ipmi_si_platform_init(void)
int rv = platform_driver_register(&ipmi_platform_driver);
if (rv)
pr_err("Unable to register driver: %d\n", rv);
+ else
+ platform_registered = true;
}
void ipmi_si_platform_shutdown(void)
{
- platform_driver_unregister(&ipmi_platform_driver);
+ if (platform_registered)
+ platform_driver_unregister(&ipmi_platform_driver);
}
diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
index cf8156d6bc07..305fa5054274 100644
--- a/drivers/char/ipmi/ipmi_ssif.c
+++ b/drivers/char/ipmi/ipmi_ssif.c
@@ -303,6 +303,7 @@ struct ssif_info {
((unsigned int) atomic_read(&(ssif)->stats[SSIF_STAT_ ## stat]))
static bool initialized;
+static bool platform_registered;
static void return_hosed_msg(struct ssif_info *ssif_info,
struct ipmi_smi_msg *msg);
@@ -2088,6 +2089,8 @@ static int init_ipmi_ssif(void)
rv = platform_driver_register(&ipmi_driver);
if (rv)
pr_err("Unable to register driver: %d\n", rv);
+ else
+ platform_registered = true;
}
ssif_i2c_driver.address_list = ssif_address_list();
@@ -2111,7 +2114,7 @@ static void cleanup_ipmi_ssif(void)
kfree(ssif_i2c_driver.address_list);
- if (ssif_trydmi)
+ if (ssif_trydmi && platform_registered)
platform_driver_unregister(&ipmi_driver);
free_ssif_clients();
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 53cfe574d8d4..f6a147427029 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -226,6 +226,7 @@ int misc_register(struct miscdevice *misc)
mutex_unlock(&misc_mtx);
return err;
}
+EXPORT_SYMBOL(misc_register);
/**
* misc_deregister - unregister a miscellaneous device
@@ -249,8 +250,6 @@ void misc_deregister(struct miscdevice *misc)
clear_bit(i, misc_minors);
mutex_unlock(&misc_mtx);
}
-
-EXPORT_SYMBOL(misc_register);
EXPORT_SYMBOL(misc_deregister);
static char *misc_devnode(struct device *dev, umode_t *mode)
diff --git a/drivers/char/tpm/eventlog/efi.c b/drivers/char/tpm/eventlog/efi.c
index 3e44362e469c..6bb023de17f1 100644
--- a/drivers/char/tpm/eventlog/efi.c
+++ b/drivers/char/tpm/eventlog/efi.c
@@ -16,10 +16,13 @@
int tpm_read_log_efi(struct tpm_chip *chip)
{
+ struct efi_tcg2_final_events_table *final_tbl = NULL;
struct linux_efi_tpm_eventlog *log_tbl;
struct tpm_bios_log *log;
u32 log_size;
u8 tpm_log_version;
+ void *tmp;
+ int ret;
if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
return -ENODEV;
@@ -47,15 +50,57 @@ int tpm_read_log_efi(struct tpm_chip *chip)
/* malloc EventLog space */
log->bios_event_log = kmemdup(log_tbl->log, log_size, GFP_KERNEL);
- if (!log->bios_event_log)
- goto err_memunmap;
- log->bios_event_log_end = log->bios_event_log + log_size;
+ if (!log->bios_event_log) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ log->bios_event_log_end = log->bios_event_log + log_size;
tpm_log_version = log_tbl->version;
- memunmap(log_tbl);
- return tpm_log_version;
-err_memunmap:
+ ret = tpm_log_version;
+
+ if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR ||
+ efi_tpm_final_log_size == 0 ||
+ tpm_log_version != EFI_TCG2_EVENT_LOG_FORMAT_TCG_2)
+ goto out;
+
+ final_tbl = memremap(efi.tpm_final_log,
+ sizeof(*final_tbl) + efi_tpm_final_log_size,
+ MEMREMAP_WB);
+ if (!final_tbl) {
+ pr_err("Could not map UEFI TPM final log\n");
+ kfree(log->bios_event_log);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ efi_tpm_final_log_size -= log_tbl->final_events_preboot_size;
+
+ tmp = krealloc(log->bios_event_log,
+ log_size + efi_tpm_final_log_size,
+ GFP_KERNEL);
+ if (!tmp) {
+ kfree(log->bios_event_log);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ log->bios_event_log = tmp;
+
+ /*
+ * Copy any of the final events log that didn't also end up in the
+ * main log. Events can be logged in both if events are generated
+ * between GetEventLog() and ExitBootServices().
+ */
+ memcpy((void *)log->bios_event_log + log_size,
+ final_tbl->events + log_tbl->final_events_preboot_size,
+ efi_tpm_final_log_size);
+ log->bios_event_log_end = log->bios_event_log +
+ log_size + efi_tpm_final_log_size;
+
+out:
+ memunmap(final_tbl);
memunmap(log_tbl);
- return -ENOMEM;
+ return ret;
}
diff --git a/drivers/char/tpm/eventlog/tpm2.c b/drivers/char/tpm/eventlog/tpm2.c
index d506362e046f..b9aeda1cbcd7 100644
--- a/drivers/char/tpm/eventlog/tpm2.c
+++ b/drivers/char/tpm/eventlog/tpm2.c
@@ -36,52 +36,7 @@
static size_t calc_tpm2_event_size(struct tcg_pcr_event2_head *event,
struct tcg_pcr_event *event_header)
{
- struct tcg_efi_specid_event_head *efispecid;
- struct tcg_event_field *event_field;
- void *marker;
- void *marker_start;
- u32 halg_size;
- size_t size;
- u16 halg;
- int i;
- int j;
-
- marker = event;
- marker_start = marker;
- marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type)
- + sizeof(event->count);
-
- efispecid = (struct tcg_efi_specid_event_head *)event_header->event;
-
- /* Check if event is malformed. */
- if (event->count > efispecid->num_algs)
- return 0;
-
- for (i = 0; i < event->count; i++) {
- halg_size = sizeof(event->digests[i].alg_id);
- memcpy(&halg, marker, halg_size);
- marker = marker + halg_size;
- for (j = 0; j < efispecid->num_algs; j++) {
- if (halg == efispecid->digest_sizes[j].alg_id) {
- marker +=
- efispecid->digest_sizes[j].digest_size;
- break;
- }
- }
- /* Algorithm without known length. Such event is unparseable. */
- if (j == efispecid->num_algs)
- return 0;
- }
-
- event_field = (struct tcg_event_field *)marker;
- marker = marker + sizeof(event_field->event_size)
- + event_field->event_size;
- size = marker - marker_start;
-
- if ((event->event_type == 0) && (event_field->event_size == 0))
- return 0;
-
- return size;
+ return __calc_tpm2_event_size(event, event_header, false);
}
static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos)
diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index 90325e1749fb..d47ad10a35fe 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -289,15 +289,15 @@ static int tpm_class_shutdown(struct device *dev)
{
struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
+ down_write(&chip->ops_sem);
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
- down_write(&chip->ops_sem);
if (!tpm_chip_start(chip)) {
tpm2_shutdown(chip, TPM2_SU_CLEAR);
tpm_chip_stop(chip);
}
- chip->ops = NULL;
- up_write(&chip->ops_sem);
}
+ chip->ops = NULL;
+ up_write(&chip->ops_sem);
return 0;
}
diff --git a/drivers/char/tpm/tpm1-cmd.c b/drivers/char/tpm/tpm1-cmd.c
index 85dcf2654d11..faacbe1ffa1a 100644
--- a/drivers/char/tpm/tpm1-cmd.c
+++ b/drivers/char/tpm/tpm1-cmd.c
@@ -510,7 +510,7 @@ struct tpm1_get_random_out {
*
* Return:
* * number of bytes read
- * * -errno or a TPM return code otherwise
+ * * -errno (positive TPM return codes are masked to -EIO)
*/
int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
{
@@ -531,8 +531,11 @@ int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
rc = tpm_transmit_cmd(chip, &buf, sizeof(out->rng_data_len),
"attempting get random");
- if (rc)
+ if (rc) {
+ if (rc > 0)
+ rc = -EIO;
goto out;
+ }
out = (struct tpm1_get_random_out *)&buf.data[TPM_HEADER_SIZE];
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index 4de49924cfc4..d103545e4055 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -297,7 +297,7 @@ struct tpm2_get_random_out {
*
* Return:
* size of the buffer on success,
- * -errno otherwise
+ * -errno otherwise (positive TPM return codes are masked to -EIO)
*/
int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
{
@@ -324,8 +324,11 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
offsetof(struct tpm2_get_random_out,
buffer),
"attempting get random");
- if (err)
+ if (err) {
+ if (err > 0)
+ err = -EIO;
goto out;
+ }
out = (struct tpm2_get_random_out *)
&buf.data[TPM_HEADER_SIZE];
diff --git a/drivers/char/tpm/tpmrm-dev.c b/drivers/char/tpm/tpmrm-dev.c
index 0c751a79bbed..7a0a7051a06f 100644
--- a/drivers/char/tpm/tpmrm-dev.c
+++ b/drivers/char/tpm/tpmrm-dev.c
@@ -1,7 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2017 James.Bottomley@HansenPartnership.com
- *
- * GPLv2
*/
#include <linux/slab.h>
#include "tpm-dev.h"
diff --git a/drivers/char/tpm/xen-tpmfront.c b/drivers/char/tpm/xen-tpmfront.c
index 4e2d00cb0d81..da5b30771418 100644
--- a/drivers/char/tpm/xen-tpmfront.c
+++ b/drivers/char/tpm/xen-tpmfront.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Implementation of the Xen vTPM device frontend
*
* Author: Daniel De Graaf <dgdegra@tycho.nsa.gov>
- *
- * 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.
*/
#include <linux/errno.h>
#include <linux/err.h>
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index fc1e0cf44995..801fa1cd0321 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -53,13 +53,12 @@ config COMMON_CLK_MAX9485
This driver supports Maxim 9485 Programmable Audio Clock Generator
config COMMON_CLK_RK808
- tristate "Clock driver for RK805/RK808/RK818"
+ tristate "Clock driver for RK805/RK808/RK809/RK817/RK818"
depends on MFD_RK808
---help---
- This driver supports RK805, RK808 and RK818 crystal oscillator clock. These
- multi-function devices have two fixed-rate oscillators,
- clocked at 32KHz each. Clkout1 is always on, Clkout2 can off
- by control register.
+ This driver supports RK805, RK809 and RK817, RK808 and RK818 crystal oscillator clock.
+ These multi-function devices have two fixed-rate oscillators, clocked at 32KHz each.
+ Clkout1 is always on, Clkout2 can off by control register.
config COMMON_CLK_HI655X
tristate "Clock driver for Hi655x" if EXPERT
@@ -91,6 +90,17 @@ config COMMON_CLK_SCPI
This driver uses SCPI Message Protocol to interact with the
firmware providing all the clock controls.
+config COMMON_CLK_SI5341
+ tristate "Clock driver for SiLabs 5341 and 5340 A/B/C/D devices"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ This driver supports Silicon Labs Si5341 and Si5340 programmable clock
+ generators. Not all features of these chips are currently supported
+ by the driver, in particular it only supports XTAL input. The chip can
+ be pre-programmed to support other configurations and features not yet
+ implemented in the driver.
+
config COMMON_CLK_SI5351
tristate "Clock driver for SiLabs 5351A/B/C"
depends on I2C
@@ -215,7 +225,7 @@ config CLK_QORIQ
config COMMON_CLK_XGENE
bool "Clock driver for APM XGene SoC"
- default y
+ default ARCH_XGENE
depends on ARM64 || COMPILE_TEST
---help---
Sypport for the APM X-Gene SoC reference, PLL, and device clocks.
@@ -293,10 +303,10 @@ config COMMON_CLK_STM32H7
config COMMON_CLK_BD718XX
tristate "Clock driver for ROHM BD718x7 PMIC"
- depends on MFD_ROHM_BD718XX
+ depends on MFD_ROHM_BD718XX || MFD_ROHM_BD70528
help
- This driver supports ROHM BD71837 and ROHM BD71847
- PMICs clock gates.
+ This driver supports ROHM BD71837, ROHM BD71847 and
+ ROHM BD70528 PMICs clock gates.
config COMMON_CLK_FIXED_MMIO
bool "Clock driver for Memory Mapped Fixed values"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 9ef4305d55e0..0cad76021297 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -49,6 +49,7 @@ obj-$(CONFIG_COMMON_CLK_HI655X) += clk-hi655x.o
obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o
obj-$(CONFIG_COMMON_CLK_SCMI) += clk-scmi.o
obj-$(CONFIG_COMMON_CLK_SCPI) += clk-scpi.o
+obj-$(CONFIG_COMMON_CLK_SI5341) += clk-si5341.o
obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o
obj-$(CONFIG_COMMON_CLK_SI514) += clk-si514.o
obj-$(CONFIG_COMMON_CLK_SI544) += clk-si544.o
diff --git a/drivers/clk/at91/sckc.c b/drivers/clk/at91/sckc.c
index 45526f56f1ba..9bfe9a28294a 100644
--- a/drivers/clk/at91/sckc.c
+++ b/drivers/clk/at91/sckc.c
@@ -18,14 +18,18 @@
SLOW_CLOCK_FREQ)
#define AT91_SCKC_CR 0x00
-#define AT91_SCKC_RCEN (1 << 0)
-#define AT91_SCKC_OSC32EN (1 << 1)
-#define AT91_SCKC_OSC32BYP (1 << 2)
-#define AT91_SCKC_OSCSEL (1 << 3)
+
+struct clk_slow_bits {
+ u32 cr_rcen;
+ u32 cr_osc32en;
+ u32 cr_osc32byp;
+ u32 cr_oscsel;
+};
struct clk_slow_osc {
struct clk_hw hw;
void __iomem *sckcr;
+ const struct clk_slow_bits *bits;
unsigned long startup_usec;
};
@@ -34,6 +38,7 @@ struct clk_slow_osc {
struct clk_sama5d4_slow_osc {
struct clk_hw hw;
void __iomem *sckcr;
+ const struct clk_slow_bits *bits;
unsigned long startup_usec;
bool prepared;
};
@@ -43,6 +48,7 @@ struct clk_sama5d4_slow_osc {
struct clk_slow_rc_osc {
struct clk_hw hw;
void __iomem *sckcr;
+ const struct clk_slow_bits *bits;
unsigned long frequency;
unsigned long accuracy;
unsigned long startup_usec;
@@ -53,6 +59,7 @@ struct clk_slow_rc_osc {
struct clk_sam9x5_slow {
struct clk_hw hw;
void __iomem *sckcr;
+ const struct clk_slow_bits *bits;
u8 parent;
};
@@ -64,10 +71,10 @@ static int clk_slow_osc_prepare(struct clk_hw *hw)
void __iomem *sckcr = osc->sckcr;
u32 tmp = readl(sckcr);
- if (tmp & (AT91_SCKC_OSC32BYP | AT91_SCKC_OSC32EN))
+ if (tmp & (osc->bits->cr_osc32byp | osc->bits->cr_osc32en))
return 0;
- writel(tmp | AT91_SCKC_OSC32EN, sckcr);
+ writel(tmp | osc->bits->cr_osc32en, sckcr);
usleep_range(osc->startup_usec, osc->startup_usec + 1);
@@ -80,10 +87,10 @@ static void clk_slow_osc_unprepare(struct clk_hw *hw)
void __iomem *sckcr = osc->sckcr;
u32 tmp = readl(sckcr);
- if (tmp & AT91_SCKC_OSC32BYP)
+ if (tmp & osc->bits->cr_osc32byp)
return;
- writel(tmp & ~AT91_SCKC_OSC32EN, sckcr);
+ writel(tmp & ~osc->bits->cr_osc32en, sckcr);
}
static int clk_slow_osc_is_prepared(struct clk_hw *hw)
@@ -92,10 +99,10 @@ static int clk_slow_osc_is_prepared(struct clk_hw *hw)
void __iomem *sckcr = osc->sckcr;
u32 tmp = readl(sckcr);
- if (tmp & AT91_SCKC_OSC32BYP)
+ if (tmp & osc->bits->cr_osc32byp)
return 1;
- return !!(tmp & AT91_SCKC_OSC32EN);
+ return !!(tmp & osc->bits->cr_osc32en);
}
static const struct clk_ops slow_osc_ops = {
@@ -109,7 +116,8 @@ at91_clk_register_slow_osc(void __iomem *sckcr,
const char *name,
const char *parent_name,
unsigned long startup,
- bool bypass)
+ bool bypass,
+ const struct clk_slow_bits *bits)
{
struct clk_slow_osc *osc;
struct clk_hw *hw;
@@ -132,10 +140,11 @@ at91_clk_register_slow_osc(void __iomem *sckcr,
osc->hw.init = &init;
osc->sckcr = sckcr;
osc->startup_usec = startup;
+ osc->bits = bits;
if (bypass)
- writel((readl(sckcr) & ~AT91_SCKC_OSC32EN) | AT91_SCKC_OSC32BYP,
- sckcr);
+ writel((readl(sckcr) & ~osc->bits->cr_osc32en) |
+ osc->bits->cr_osc32byp, sckcr);
hw = &osc->hw;
ret = clk_hw_register(NULL, &osc->hw);
@@ -147,6 +156,14 @@ at91_clk_register_slow_osc(void __iomem *sckcr,
return hw;
}
+static void at91_clk_unregister_slow_osc(struct clk_hw *hw)
+{
+ struct clk_slow_osc *osc = to_clk_slow_osc(hw);
+
+ clk_hw_unregister(hw);
+ kfree(osc);
+}
+
static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
@@ -168,7 +185,7 @@ static int clk_slow_rc_osc_prepare(struct clk_hw *hw)
struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
void __iomem *sckcr = osc->sckcr;
- writel(readl(sckcr) | AT91_SCKC_RCEN, sckcr);
+ writel(readl(sckcr) | osc->bits->cr_rcen, sckcr);
usleep_range(osc->startup_usec, osc->startup_usec + 1);
@@ -180,14 +197,14 @@ static void clk_slow_rc_osc_unprepare(struct clk_hw *hw)
struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
void __iomem *sckcr = osc->sckcr;
- writel(readl(sckcr) & ~AT91_SCKC_RCEN, sckcr);
+ writel(readl(sckcr) & ~osc->bits->cr_rcen, sckcr);
}
static int clk_slow_rc_osc_is_prepared(struct clk_hw *hw)
{
struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
- return !!(readl(osc->sckcr) & AT91_SCKC_RCEN);
+ return !!(readl(osc->sckcr) & osc->bits->cr_rcen);
}
static const struct clk_ops slow_rc_osc_ops = {
@@ -203,7 +220,8 @@ at91_clk_register_slow_rc_osc(void __iomem *sckcr,
const char *name,
unsigned long frequency,
unsigned long accuracy,
- unsigned long startup)
+ unsigned long startup,
+ const struct clk_slow_bits *bits)
{
struct clk_slow_rc_osc *osc;
struct clk_hw *hw;
@@ -225,6 +243,7 @@ at91_clk_register_slow_rc_osc(void __iomem *sckcr,
osc->hw.init = &init;
osc->sckcr = sckcr;
+ osc->bits = bits;
osc->frequency = frequency;
osc->accuracy = accuracy;
osc->startup_usec = startup;
@@ -239,6 +258,14 @@ at91_clk_register_slow_rc_osc(void __iomem *sckcr,
return hw;
}
+static void at91_clk_unregister_slow_rc_osc(struct clk_hw *hw)
+{
+ struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
+
+ clk_hw_unregister(hw);
+ kfree(osc);
+}
+
static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
@@ -250,14 +277,14 @@ static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index)
tmp = readl(sckcr);
- if ((!index && !(tmp & AT91_SCKC_OSCSEL)) ||
- (index && (tmp & AT91_SCKC_OSCSEL)))
+ if ((!index && !(tmp & slowck->bits->cr_oscsel)) ||
+ (index && (tmp & slowck->bits->cr_oscsel)))
return 0;
if (index)
- tmp |= AT91_SCKC_OSCSEL;
+ tmp |= slowck->bits->cr_oscsel;
else
- tmp &= ~AT91_SCKC_OSCSEL;
+ tmp &= ~slowck->bits->cr_oscsel;
writel(tmp, sckcr);
@@ -270,7 +297,7 @@ static u8 clk_sam9x5_slow_get_parent(struct clk_hw *hw)
{
struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
- return !!(readl(slowck->sckcr) & AT91_SCKC_OSCSEL);
+ return !!(readl(slowck->sckcr) & slowck->bits->cr_oscsel);
}
static const struct clk_ops sam9x5_slow_ops = {
@@ -282,7 +309,8 @@ static struct clk_hw * __init
at91_clk_register_sam9x5_slow(void __iomem *sckcr,
const char *name,
const char **parent_names,
- int num_parents)
+ int num_parents,
+ const struct clk_slow_bits *bits)
{
struct clk_sam9x5_slow *slowck;
struct clk_hw *hw;
@@ -304,7 +332,8 @@ at91_clk_register_sam9x5_slow(void __iomem *sckcr,
slowck->hw.init = &init;
slowck->sckcr = sckcr;
- slowck->parent = !!(readl(sckcr) & AT91_SCKC_OSCSEL);
+ slowck->bits = bits;
+ slowck->parent = !!(readl(sckcr) & slowck->bits->cr_oscsel);
hw = &slowck->hw;
ret = clk_hw_register(NULL, &slowck->hw);
@@ -316,22 +345,33 @@ at91_clk_register_sam9x5_slow(void __iomem *sckcr,
return hw;
}
+static void at91_clk_unregister_sam9x5_slow(struct clk_hw *hw)
+{
+ struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
+
+ clk_hw_unregister(hw);
+ kfree(slowck);
+}
+
static void __init at91sam9x5_sckc_register(struct device_node *np,
- unsigned int rc_osc_startup_us)
+ unsigned int rc_osc_startup_us,
+ const struct clk_slow_bits *bits)
{
const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
void __iomem *regbase = of_iomap(np, 0);
struct device_node *child = NULL;
const char *xtal_name;
- struct clk_hw *hw;
+ struct clk_hw *slow_rc, *slow_osc, *slowck;
bool bypass;
+ int ret;
if (!regbase)
return;
- hw = at91_clk_register_slow_rc_osc(regbase, parent_names[0], 32768,
- 50000000, rc_osc_startup_us);
- if (IS_ERR(hw))
+ slow_rc = at91_clk_register_slow_rc_osc(regbase, parent_names[0],
+ 32768, 50000000,
+ rc_osc_startup_us, bits);
+ if (IS_ERR(slow_rc))
return;
xtal_name = of_clk_get_parent_name(np, 0);
@@ -339,7 +379,7 @@ static void __init at91sam9x5_sckc_register(struct device_node *np,
/* DT backward compatibility */
child = of_get_compatible_child(np, "atmel,at91sam9x5-clk-slow-osc");
if (!child)
- return;
+ goto unregister_slow_rc;
xtal_name = of_clk_get_parent_name(child, 0);
bypass = of_property_read_bool(child, "atmel,osc-bypass");
@@ -350,38 +390,133 @@ static void __init at91sam9x5_sckc_register(struct device_node *np,
}
if (!xtal_name)
- return;
-
- hw = at91_clk_register_slow_osc(regbase, parent_names[1], xtal_name,
- 1200000, bypass);
- if (IS_ERR(hw))
- return;
+ goto unregister_slow_rc;
- hw = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names, 2);
- if (IS_ERR(hw))
- return;
+ slow_osc = at91_clk_register_slow_osc(regbase, parent_names[1],
+ xtal_name, 1200000, bypass, bits);
+ if (IS_ERR(slow_osc))
+ goto unregister_slow_rc;
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
+ slowck = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names,
+ 2, bits);
+ if (IS_ERR(slowck))
+ goto unregister_slow_osc;
/* DT backward compatibility */
if (child)
- of_clk_add_hw_provider(child, of_clk_hw_simple_get, hw);
+ ret = of_clk_add_hw_provider(child, of_clk_hw_simple_get,
+ slowck);
+ else
+ ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, slowck);
+
+ if (WARN_ON(ret))
+ goto unregister_slowck;
+
+ return;
+
+unregister_slowck:
+ at91_clk_unregister_sam9x5_slow(slowck);
+unregister_slow_osc:
+ at91_clk_unregister_slow_osc(slow_osc);
+unregister_slow_rc:
+ at91_clk_unregister_slow_rc_osc(slow_rc);
}
+static const struct clk_slow_bits at91sam9x5_bits = {
+ .cr_rcen = BIT(0),
+ .cr_osc32en = BIT(1),
+ .cr_osc32byp = BIT(2),
+ .cr_oscsel = BIT(3),
+};
+
static void __init of_at91sam9x5_sckc_setup(struct device_node *np)
{
- at91sam9x5_sckc_register(np, 75);
+ at91sam9x5_sckc_register(np, 75, &at91sam9x5_bits);
}
CLK_OF_DECLARE(at91sam9x5_clk_sckc, "atmel,at91sam9x5-sckc",
of_at91sam9x5_sckc_setup);
static void __init of_sama5d3_sckc_setup(struct device_node *np)
{
- at91sam9x5_sckc_register(np, 500);
+ at91sam9x5_sckc_register(np, 500, &at91sam9x5_bits);
}
CLK_OF_DECLARE(sama5d3_clk_sckc, "atmel,sama5d3-sckc",
of_sama5d3_sckc_setup);
+static const struct clk_slow_bits at91sam9x60_bits = {
+ .cr_osc32en = BIT(1),
+ .cr_osc32byp = BIT(2),
+ .cr_oscsel = BIT(24),
+};
+
+static void __init of_sam9x60_sckc_setup(struct device_node *np)
+{
+ void __iomem *regbase = of_iomap(np, 0);
+ struct clk_hw_onecell_data *clk_data;
+ struct clk_hw *slow_rc, *slow_osc;
+ const char *xtal_name;
+ const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
+ bool bypass;
+ int ret;
+
+ if (!regbase)
+ return;
+
+ slow_rc = clk_hw_register_fixed_rate(NULL, parent_names[0], NULL, 0,
+ 32768);
+ if (IS_ERR(slow_rc))
+ return;
+
+ xtal_name = of_clk_get_parent_name(np, 0);
+ if (!xtal_name)
+ goto unregister_slow_rc;
+
+ bypass = of_property_read_bool(np, "atmel,osc-bypass");
+ slow_osc = at91_clk_register_slow_osc(regbase, parent_names[1],
+ xtal_name, 5000000, bypass,
+ &at91sam9x60_bits);
+ if (IS_ERR(slow_osc))
+ goto unregister_slow_rc;
+
+ clk_data = kzalloc(sizeof(*clk_data) + (2 * sizeof(struct clk_hw *)),
+ GFP_KERNEL);
+ if (!clk_data)
+ goto unregister_slow_osc;
+
+ /* MD_SLCK and TD_SLCK. */
+ clk_data->num = 2;
+ clk_data->hws[0] = clk_hw_register_fixed_rate(NULL, "md_slck",
+ parent_names[0],
+ 0, 32768);
+ if (IS_ERR(clk_data->hws[0]))
+ goto clk_data_free;
+
+ clk_data->hws[1] = at91_clk_register_sam9x5_slow(regbase, "td_slck",
+ parent_names, 2,
+ &at91sam9x60_bits);
+ if (IS_ERR(clk_data->hws[1]))
+ goto unregister_md_slck;
+
+ ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
+ if (WARN_ON(ret))
+ goto unregister_td_slck;
+
+ return;
+
+unregister_td_slck:
+ at91_clk_unregister_sam9x5_slow(clk_data->hws[1]);
+unregister_md_slck:
+ clk_hw_unregister(clk_data->hws[0]);
+clk_data_free:
+ kfree(clk_data);
+unregister_slow_osc:
+ at91_clk_unregister_slow_osc(slow_osc);
+unregister_slow_rc:
+ clk_hw_unregister(slow_rc);
+}
+CLK_OF_DECLARE(sam9x60_clk_sckc, "microchip,sam9x60-sckc",
+ of_sam9x60_sckc_setup);
+
static int clk_sama5d4_slow_osc_prepare(struct clk_hw *hw)
{
struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw);
@@ -393,7 +528,7 @@ static int clk_sama5d4_slow_osc_prepare(struct clk_hw *hw)
* Assume that if it has already been selected (for example by the
* bootloader), enough time has aready passed.
*/
- if ((readl(osc->sckcr) & AT91_SCKC_OSCSEL)) {
+ if ((readl(osc->sckcr) & osc->bits->cr_oscsel)) {
osc->prepared = true;
return 0;
}
@@ -416,33 +551,35 @@ static const struct clk_ops sama5d4_slow_osc_ops = {
.is_prepared = clk_sama5d4_slow_osc_is_prepared,
};
+static const struct clk_slow_bits at91sama5d4_bits = {
+ .cr_oscsel = BIT(3),
+};
+
static void __init of_sama5d4_sckc_setup(struct device_node *np)
{
void __iomem *regbase = of_iomap(np, 0);
- struct clk_hw *hw;
+ struct clk_hw *slow_rc, *slowck;
struct clk_sama5d4_slow_osc *osc;
struct clk_init_data init;
const char *xtal_name;
const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
- bool bypass;
int ret;
if (!regbase)
return;
- hw = clk_hw_register_fixed_rate_with_accuracy(NULL, parent_names[0],
- NULL, 0, 32768,
- 250000000);
- if (IS_ERR(hw))
+ slow_rc = clk_hw_register_fixed_rate_with_accuracy(NULL,
+ parent_names[0],
+ NULL, 0, 32768,
+ 250000000);
+ if (IS_ERR(slow_rc))
return;
xtal_name = of_clk_get_parent_name(np, 0);
- bypass = of_property_read_bool(np, "atmel,osc-bypass");
-
osc = kzalloc(sizeof(*osc), GFP_KERNEL);
if (!osc)
- return;
+ goto unregister_slow_rc;
init.name = parent_names[1];
init.ops = &sama5d4_slow_osc_ops;
@@ -453,22 +590,32 @@ static void __init of_sama5d4_sckc_setup(struct device_node *np)
osc->hw.init = &init;
osc->sckcr = regbase;
osc->startup_usec = 1200000;
+ osc->bits = &at91sama5d4_bits;
- if (bypass)
- writel((readl(regbase) | AT91_SCKC_OSC32BYP), regbase);
-
- hw = &osc->hw;
ret = clk_hw_register(NULL, &osc->hw);
- if (ret) {
- kfree(osc);
- return;
- }
-
- hw = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names, 2);
- if (IS_ERR(hw))
- return;
-
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
+ if (ret)
+ goto free_slow_osc_data;
+
+ slowck = at91_clk_register_sam9x5_slow(regbase, "slowck",
+ parent_names, 2,
+ &at91sama5d4_bits);
+ if (IS_ERR(slowck))
+ goto unregister_slow_osc;
+
+ ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, slowck);
+ if (WARN_ON(ret))
+ goto unregister_slowck;
+
+ return;
+
+unregister_slowck:
+ at91_clk_unregister_sam9x5_slow(slowck);
+unregister_slow_osc:
+ clk_hw_unregister(&osc->hw);
+free_slow_osc_data:
+ kfree(osc);
+unregister_slow_rc:
+ clk_hw_unregister(slow_rc);
}
CLK_OF_DECLARE(sama5d4_clk_sckc, "atmel,sama5d4-sckc",
of_sama5d4_sckc_setup);
diff --git a/drivers/clk/axis/clk-artpec6.c b/drivers/clk/axis/clk-artpec6.c
index da1a073c2236..f95959ff85ac 100644
--- a/drivers/clk/axis/clk-artpec6.c
+++ b/drivers/clk/axis/clk-artpec6.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ARTPEC-6 clock initialization
*
* Copyright 2015-2016 Axis Comunications AB.
- *
- * 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.
*/
#include <linux/clk-provider.h>
diff --git a/drivers/clk/bcm/Kconfig b/drivers/clk/bcm/Kconfig
index 29ee7b776cd4..8c83977a7dc4 100644
--- a/drivers/clk/bcm/Kconfig
+++ b/drivers/clk/bcm/Kconfig
@@ -1,4 +1,13 @@
# SPDX-License-Identifier: GPL-2.0-only
+config CLK_BCM2835
+ bool "Broadcom BCM2835 clock support"
+ depends on ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST
+ depends on COMMON_CLK
+ default ARCH_BCM2835 || ARCH_BRCMSTB
+ help
+ Enable common clock framework support for Broadcom BCM2835
+ SoCs.
+
config CLK_BCM_63XX
bool "Broadcom BCM63xx clock support"
depends on ARCH_BCM_63XX || COMPILE_TEST
@@ -8,6 +17,14 @@ config CLK_BCM_63XX
Enable common clock framework support for Broadcom BCM63xx DSL SoCs
based on the ARM architecture
+config CLK_BCM_63XX_GATE
+ bool "Broadcom BCM63xx gated clock support"
+ depends on BMIPS_GENERIC || COMPILE_TEST
+ default BMIPS_GENERIC
+ help
+ Enable common clock framework support for Broadcom BCM63xx DSL SoCs
+ based on the MIPS architecture
+
config CLK_BCM_KONA
bool "Broadcom Kona CCU clock support"
depends on ARCH_BCM_MOBILE || COMPILE_TEST
@@ -64,3 +81,10 @@ config CLK_BCM_SR
default ARCH_BCM_IPROC
help
Enable common clock framework support for the Broadcom Stingray SoC
+
+config CLK_RASPBERRYPI
+ tristate "Raspberry Pi firmware based clock support"
+ depends on RASPBERRYPI_FIRMWARE || (COMPILE_TEST && !RASPBERRYPI_FIRMWARE)
+ help
+ Enable common clock framework support for Raspberry Pi's firmware
+ dependent clocks
diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile
index 002661d39128..0070ddf6cdd2 100644
--- a/drivers/clk/bcm/Makefile
+++ b/drivers/clk/bcm/Makefile
@@ -1,12 +1,14 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_CLK_BCM_63XX) += clk-bcm63xx.o
+obj-$(CONFIG_CLK_BCM_63XX_GATE) += clk-bcm63xx-gate.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-kona.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o
obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o
-obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
-obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835-aux.o
+obj-$(CONFIG_CLK_BCM2835) += clk-bcm2835.o
+obj-$(CONFIG_CLK_BCM2835) += clk-bcm2835-aux.o
+obj-$(CONFIG_CLK_RASPBERRYPI) += clk-raspberrypi.o
obj-$(CONFIG_ARCH_BCM_53573) += clk-bcm53573-ilp.o
obj-$(CONFIG_CLK_BCM_CYGNUS) += clk-cygnus.o
obj-$(CONFIG_CLK_BCM_HR2) += clk-hr2.o
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index 770bb01f523e..867ae3c20041 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -1651,30 +1651,10 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
.fixed_divider = 1,
.flags = CLK_SET_RATE_PARENT),
- /* PLLB is used for the ARM's clock. */
- [BCM2835_PLLB] = REGISTER_PLL(
- .name = "pllb",
- .cm_ctrl_reg = CM_PLLB,
- .a2w_ctrl_reg = A2W_PLLB_CTRL,
- .frac_reg = A2W_PLLB_FRAC,
- .ana_reg_base = A2W_PLLB_ANA0,
- .reference_enable_mask = A2W_XOSC_CTRL_PLLB_ENABLE,
- .lock_mask = CM_LOCK_FLOCKB,
-
- .ana = &bcm2835_ana_default,
-
- .min_rate = 600000000u,
- .max_rate = 3000000000u,
- .max_fb_rate = BCM2835_MAX_FB_RATE),
- [BCM2835_PLLB_ARM] = REGISTER_PLL_DIV(
- .name = "pllb_arm",
- .source_pll = "pllb",
- .cm_reg = CM_PLLB,
- .a2w_reg = A2W_PLLB_ARM,
- .load_mask = CM_PLLB_LOADARM,
- .hold_mask = CM_PLLB_HOLDARM,
- .fixed_divider = 1,
- .flags = CLK_SET_RATE_PARENT),
+ /*
+ * PLLB is used for the ARM's clock. Controlled by firmware, see
+ * clk-raspberrypi.c.
+ */
/*
* PLLC is the core PLL, used to drive the core VPU clock.
diff --git a/drivers/clk/bcm/clk-bcm53573-ilp.c b/drivers/clk/bcm/clk-bcm53573-ilp.c
index 36eb3716ffb0..84f2af736ee8 100644
--- a/drivers/clk/bcm/clk-bcm53573-ilp.c
+++ b/drivers/clk/bcm/clk-bcm53573-ilp.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2016 Rafał Miłecki <rafal@milecki.pl>
- *
- * 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.
*/
#include <linux/clk-provider.h>
diff --git a/drivers/clk/bcm/clk-bcm63xx-gate.c b/drivers/clk/bcm/clk-bcm63xx-gate.c
new file mode 100644
index 000000000000..9e1dcd43258c
--- /dev/null
+++ b/drivers/clk/bcm/clk-bcm63xx-gate.c
@@ -0,0 +1,238 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/clk-provider.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+struct clk_bcm63xx_table_entry {
+ const char * const name;
+ u8 bit;
+ unsigned long flags;
+};
+
+struct clk_bcm63xx_hw {
+ void __iomem *regs;
+ spinlock_t lock;
+
+ struct clk_hw_onecell_data data;
+};
+
+static const struct clk_bcm63xx_table_entry bcm3368_clocks[] = {
+ { .name = "mac", .bit = 3, },
+ { .name = "tc", .bit = 5, },
+ { .name = "us_top", .bit = 6, },
+ { .name = "ds_top", .bit = 7, },
+ { .name = "acm", .bit = 8, },
+ { .name = "spi", .bit = 9, },
+ { .name = "usbs", .bit = 10, },
+ { .name = "bmu", .bit = 11, },
+ { .name = "pcm", .bit = 12, },
+ { .name = "ntp", .bit = 13, },
+ { .name = "acp_b", .bit = 14, },
+ { .name = "acp_a", .bit = 15, },
+ { .name = "emusb", .bit = 17, },
+ { .name = "enet0", .bit = 18, },
+ { .name = "enet1", .bit = 19, },
+ { .name = "usbsu", .bit = 20, },
+ { .name = "ephy", .bit = 21, },
+ { },
+};
+
+static const struct clk_bcm63xx_table_entry bcm6328_clocks[] = {
+ { .name = "phy_mips", .bit = 0, },
+ { .name = "adsl_qproc", .bit = 1, },
+ { .name = "adsl_afe", .bit = 2, },
+ { .name = "adsl", .bit = 3, },
+ { .name = "mips", .bit = 4, .flags = CLK_IS_CRITICAL, },
+ { .name = "sar", .bit = 5, },
+ { .name = "pcm", .bit = 6, },
+ { .name = "usbd", .bit = 7, },
+ { .name = "usbh", .bit = 8, },
+ { .name = "hsspi", .bit = 9, },
+ { .name = "pcie", .bit = 10, },
+ { .name = "robosw", .bit = 11, },
+ { },
+};
+
+static const struct clk_bcm63xx_table_entry bcm6358_clocks[] = {
+ { .name = "enet", .bit = 4, },
+ { .name = "adslphy", .bit = 5, },
+ { .name = "pcm", .bit = 8, },
+ { .name = "spi", .bit = 9, },
+ { .name = "usbs", .bit = 10, },
+ { .name = "sar", .bit = 11, },
+ { .name = "emusb", .bit = 17, },
+ { .name = "enet0", .bit = 18, },
+ { .name = "enet1", .bit = 19, },
+ { .name = "usbsu", .bit = 20, },
+ { .name = "ephy", .bit = 21, },
+ { },
+};
+
+static const struct clk_bcm63xx_table_entry bcm6362_clocks[] = {
+ { .name = "adsl_qproc", .bit = 1, },
+ { .name = "adsl_afe", .bit = 2, },
+ { .name = "adsl", .bit = 3, },
+ { .name = "mips", .bit = 4, .flags = CLK_IS_CRITICAL, },
+ { .name = "wlan_ocp", .bit = 5, },
+ { .name = "swpkt_usb", .bit = 7, },
+ { .name = "swpkt_sar", .bit = 8, },
+ { .name = "sar", .bit = 9, },
+ { .name = "robosw", .bit = 10, },
+ { .name = "pcm", .bit = 11, },
+ { .name = "usbd", .bit = 12, },
+ { .name = "usbh", .bit = 13, },
+ { .name = "ipsec", .bit = 14, },
+ { .name = "spi", .bit = 15, },
+ { .name = "hsspi", .bit = 16, },
+ { .name = "pcie", .bit = 17, },
+ { .name = "fap", .bit = 18, },
+ { .name = "phymips", .bit = 19, },
+ { .name = "nand", .bit = 20, },
+ { },
+};
+
+static const struct clk_bcm63xx_table_entry bcm6368_clocks[] = {
+ { .name = "vdsl_qproc", .bit = 2, },
+ { .name = "vdsl_afe", .bit = 3, },
+ { .name = "vdsl_bonding", .bit = 4, },
+ { .name = "vdsl", .bit = 5, },
+ { .name = "phymips", .bit = 6, },
+ { .name = "swpkt_usb", .bit = 7, },
+ { .name = "swpkt_sar", .bit = 8, },
+ { .name = "spi", .bit = 9, },
+ { .name = "usbd", .bit = 10, },
+ { .name = "sar", .bit = 11, },
+ { .name = "robosw", .bit = 12, },
+ { .name = "utopia", .bit = 13, },
+ { .name = "pcm", .bit = 14, },
+ { .name = "usbh", .bit = 15, },
+ { .name = "disable_gless", .bit = 16, },
+ { .name = "nand", .bit = 17, },
+ { .name = "ipsec", .bit = 18, },
+ { },
+};
+
+static const struct clk_bcm63xx_table_entry bcm63268_clocks[] = {
+ { .name = "disable_gless", .bit = 0, },
+ { .name = "vdsl_qproc", .bit = 1, },
+ { .name = "vdsl_afe", .bit = 2, },
+ { .name = "vdsl", .bit = 3, },
+ { .name = "mips", .bit = 4, .flags = CLK_IS_CRITICAL, },
+ { .name = "wlan_ocp", .bit = 5, },
+ { .name = "dect", .bit = 6, },
+ { .name = "fap0", .bit = 7, },
+ { .name = "fap1", .bit = 8, },
+ { .name = "sar", .bit = 9, },
+ { .name = "robosw", .bit = 10, },
+ { .name = "pcm", .bit = 11, },
+ { .name = "usbd", .bit = 12, },
+ { .name = "usbh", .bit = 13, },
+ { .name = "ipsec", .bit = 14, },
+ { .name = "spi", .bit = 15, },
+ { .name = "hsspi", .bit = 16, },
+ { .name = "pcie", .bit = 17, },
+ { .name = "phymips", .bit = 18, },
+ { .name = "gmac", .bit = 19, },
+ { .name = "nand", .bit = 20, },
+ { .name = "tbus", .bit = 27, },
+ { .name = "robosw250", .bit = 31, },
+ { },
+};
+
+static int clk_bcm63xx_probe(struct platform_device *pdev)
+{
+ const struct clk_bcm63xx_table_entry *entry, *table;
+ struct clk_bcm63xx_hw *hw;
+ struct resource *r;
+ u8 maxbit = 0;
+ int i, ret;
+
+ table = of_device_get_match_data(&pdev->dev);
+ if (!table)
+ return -EINVAL;
+
+ for (entry = table; entry->name; entry++)
+ maxbit = max_t(u8, maxbit, entry->bit);
+
+ hw = devm_kzalloc(&pdev->dev, struct_size(hw, data.hws, maxbit),
+ GFP_KERNEL);
+ if (!hw)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, hw);
+
+ spin_lock_init(&hw->lock);
+
+ hw->data.num = maxbit;
+ for (i = 0; i < maxbit; i++)
+ hw->data.hws[i] = ERR_PTR(-ENODEV);
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ hw->regs = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(hw->regs))
+ return PTR_ERR(hw->regs);
+
+ for (entry = table; entry->name; entry++) {
+ struct clk_hw *clk;
+
+ clk = clk_hw_register_gate(&pdev->dev, entry->name, NULL,
+ entry->flags, hw->regs, entry->bit,
+ CLK_GATE_BIG_ENDIAN, &hw->lock);
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ goto out_err;
+ }
+
+ hw->data.hws[entry->bit] = clk;
+ }
+
+ ret = of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_onecell_get,
+ &hw->data);
+ if (!ret)
+ return 0;
+out_err:
+ for (i = 0; i < hw->data.num; i++) {
+ if (!IS_ERR(hw->data.hws[i]))
+ clk_hw_unregister_gate(hw->data.hws[i]);
+ }
+
+ return ret;
+}
+
+static int clk_bcm63xx_remove(struct platform_device *pdev)
+{
+ struct clk_bcm63xx_hw *hw = platform_get_drvdata(pdev);
+ int i;
+
+ of_clk_del_provider(pdev->dev.of_node);
+
+ for (i = 0; i < hw->data.num; i++) {
+ if (!IS_ERR(hw->data.hws[i]))
+ clk_hw_unregister_gate(hw->data.hws[i]);
+ }
+
+ return 0;
+}
+
+static const struct of_device_id clk_bcm63xx_dt_ids[] = {
+ { .compatible = "brcm,bcm3368-clocks", .data = &bcm3368_clocks, },
+ { .compatible = "brcm,bcm6328-clocks", .data = &bcm6328_clocks, },
+ { .compatible = "brcm,bcm6358-clocks", .data = &bcm6358_clocks, },
+ { .compatible = "brcm,bcm6362-clocks", .data = &bcm6362_clocks, },
+ { .compatible = "brcm,bcm6368-clocks", .data = &bcm6368_clocks, },
+ { .compatible = "brcm,bcm63268-clocks", .data = &bcm63268_clocks, },
+ { }
+};
+
+static struct platform_driver clk_bcm63xx = {
+ .probe = clk_bcm63xx_probe,
+ .remove = clk_bcm63xx_remove,
+ .driver = {
+ .name = "bcm63xx-clock",
+ .of_match_table = clk_bcm63xx_dt_ids,
+ },
+};
+builtin_platform_driver(clk_bcm63xx);
diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c
new file mode 100644
index 000000000000..1654fd0eedc9
--- /dev/null
+++ b/drivers/clk/bcm/clk-raspberrypi.c
@@ -0,0 +1,315 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Raspberry Pi driver for firmware controlled clocks
+ *
+ * Even though clk-bcm2835 provides an interface to the hardware registers for
+ * the system clocks we've had to factor out 'pllb' as the firmware 'owns' it.
+ * We're not allowed to change it directly as we might race with the
+ * over-temperature and under-voltage protections provided by the firmware.
+ *
+ * Copyright (C) 2019 Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+ */
+
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <soc/bcm2835/raspberrypi-firmware.h>
+
+#define RPI_FIRMWARE_ARM_CLK_ID 0x00000003
+
+#define RPI_FIRMWARE_STATE_ENABLE_BIT BIT(0)
+#define RPI_FIRMWARE_STATE_WAIT_BIT BIT(1)
+
+/*
+ * Even though the firmware interface alters 'pllb' the frequencies are
+ * provided as per 'pllb_arm'. We need to scale before passing them trough.
+ */
+#define RPI_FIRMWARE_PLLB_ARM_DIV_RATE 2
+
+#define A2W_PLL_FRAC_BITS 20
+
+struct raspberrypi_clk {
+ struct device *dev;
+ struct rpi_firmware *firmware;
+ struct platform_device *cpufreq;
+
+ unsigned long min_rate;
+ unsigned long max_rate;
+
+ struct clk_hw pllb;
+ struct clk_hw *pllb_arm;
+ struct clk_lookup *pllb_arm_lookup;
+};
+
+/*
+ * Structure of the message passed to Raspberry Pi's firmware in order to
+ * change clock rates. The 'disable_turbo' option is only available to the ARM
+ * clock (pllb) which we enable by default as turbo mode will alter multiple
+ * clocks at once.
+ *
+ * Even though we're able to access the clock registers directly we're bound to
+ * use the firmware interface as the firmware ultimately takes care of
+ * mitigating overheating/undervoltage situations and we would be changing
+ * frequencies behind his back.
+ *
+ * For more information on the firmware interface check:
+ * https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface
+ */
+struct raspberrypi_firmware_prop {
+ __le32 id;
+ __le32 val;
+ __le32 disable_turbo;
+} __packed;
+
+static int raspberrypi_clock_property(struct rpi_firmware *firmware, u32 tag,
+ u32 clk, u32 *val)
+{
+ struct raspberrypi_firmware_prop msg = {
+ .id = cpu_to_le32(clk),
+ .val = cpu_to_le32(*val),
+ .disable_turbo = cpu_to_le32(1),
+ };
+ int ret;
+
+ ret = rpi_firmware_property(firmware, tag, &msg, sizeof(msg));
+ if (ret)
+ return ret;
+
+ *val = le32_to_cpu(msg.val);
+
+ return 0;
+}
+
+static int raspberrypi_fw_pll_is_on(struct clk_hw *hw)
+{
+ struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
+ pllb);
+ u32 val = 0;
+ int ret;
+
+ ret = raspberrypi_clock_property(rpi->firmware,
+ RPI_FIRMWARE_GET_CLOCK_STATE,
+ RPI_FIRMWARE_ARM_CLK_ID, &val);
+ if (ret)
+ return 0;
+
+ return !!(val & RPI_FIRMWARE_STATE_ENABLE_BIT);
+}
+
+
+static unsigned long raspberrypi_fw_pll_get_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
+ pllb);
+ u32 val = 0;
+ int ret;
+
+ ret = raspberrypi_clock_property(rpi->firmware,
+ RPI_FIRMWARE_GET_CLOCK_RATE,
+ RPI_FIRMWARE_ARM_CLK_ID,
+ &val);
+ if (ret)
+ return ret;
+
+ return val * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
+}
+
+static int raspberrypi_fw_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
+ pllb);
+ u32 new_rate = rate / RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
+ int ret;
+
+ ret = raspberrypi_clock_property(rpi->firmware,
+ RPI_FIRMWARE_SET_CLOCK_RATE,
+ RPI_FIRMWARE_ARM_CLK_ID,
+ &new_rate);
+ if (ret)
+ dev_err_ratelimited(rpi->dev, "Failed to change %s frequency: %d",
+ clk_hw_get_name(hw), ret);
+
+ return ret;
+}
+
+/*
+ * Sadly there is no firmware rate rounding interface. We borrowed it from
+ * clk-bcm2835.
+ */
+static int raspberrypi_pll_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
+ pllb);
+ u64 div, final_rate;
+ u32 ndiv, fdiv;
+
+ /* We can't use req->rate directly as it would overflow */
+ final_rate = clamp(req->rate, rpi->min_rate, rpi->max_rate);
+
+ div = (u64)final_rate << A2W_PLL_FRAC_BITS;
+ do_div(div, req->best_parent_rate);
+
+ ndiv = div >> A2W_PLL_FRAC_BITS;
+ fdiv = div & ((1 << A2W_PLL_FRAC_BITS) - 1);
+
+ final_rate = ((u64)req->best_parent_rate *
+ ((ndiv << A2W_PLL_FRAC_BITS) + fdiv));
+
+ req->rate = final_rate >> A2W_PLL_FRAC_BITS;
+
+ return 0;
+}
+
+static const struct clk_ops raspberrypi_firmware_pll_clk_ops = {
+ .is_prepared = raspberrypi_fw_pll_is_on,
+ .recalc_rate = raspberrypi_fw_pll_get_rate,
+ .set_rate = raspberrypi_fw_pll_set_rate,
+ .determine_rate = raspberrypi_pll_determine_rate,
+};
+
+static int raspberrypi_register_pllb(struct raspberrypi_clk *rpi)
+{
+ u32 min_rate = 0, max_rate = 0;
+ struct clk_init_data init;
+ int ret;
+
+ memset(&init, 0, sizeof(init));
+
+ /* All of the PLLs derive from the external oscillator. */
+ init.parent_names = (const char *[]){ "osc" };
+ init.num_parents = 1;
+ init.name = "pllb";
+ init.ops = &raspberrypi_firmware_pll_clk_ops;
+ init.flags = CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED;
+
+ /* Get min & max rates set by the firmware */
+ ret = raspberrypi_clock_property(rpi->firmware,
+ RPI_FIRMWARE_GET_MIN_CLOCK_RATE,
+ RPI_FIRMWARE_ARM_CLK_ID,
+ &min_rate);
+ if (ret) {
+ dev_err(rpi->dev, "Failed to get %s min freq: %d\n",
+ init.name, ret);
+ return ret;
+ }
+
+ ret = raspberrypi_clock_property(rpi->firmware,
+ RPI_FIRMWARE_GET_MAX_CLOCK_RATE,
+ RPI_FIRMWARE_ARM_CLK_ID,
+ &max_rate);
+ if (ret) {
+ dev_err(rpi->dev, "Failed to get %s max freq: %d\n",
+ init.name, ret);
+ return ret;
+ }
+
+ if (!min_rate || !max_rate) {
+ dev_err(rpi->dev, "Unexpected frequency range: min %u, max %u\n",
+ min_rate, max_rate);
+ return -EINVAL;
+ }
+
+ dev_info(rpi->dev, "CPU frequency range: min %u, max %u\n",
+ min_rate, max_rate);
+
+ rpi->min_rate = min_rate * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
+ rpi->max_rate = max_rate * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
+
+ rpi->pllb.init = &init;
+
+ return devm_clk_hw_register(rpi->dev, &rpi->pllb);
+}
+
+static int raspberrypi_register_pllb_arm(struct raspberrypi_clk *rpi)
+{
+ rpi->pllb_arm = clk_hw_register_fixed_factor(rpi->dev,
+ "pllb_arm", "pllb",
+ CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+ 1, 2);
+ if (IS_ERR(rpi->pllb_arm)) {
+ dev_err(rpi->dev, "Failed to initialize pllb_arm\n");
+ return PTR_ERR(rpi->pllb_arm);
+ }
+
+ rpi->pllb_arm_lookup = clkdev_hw_create(rpi->pllb_arm, NULL, "cpu0");
+ if (!rpi->pllb_arm_lookup) {
+ dev_err(rpi->dev, "Failed to initialize pllb_arm_lookup\n");
+ clk_hw_unregister_fixed_factor(rpi->pllb_arm);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int raspberrypi_clk_probe(struct platform_device *pdev)
+{
+ struct device_node *firmware_node;
+ struct device *dev = &pdev->dev;
+ struct rpi_firmware *firmware;
+ struct raspberrypi_clk *rpi;
+ int ret;
+
+ firmware_node = of_find_compatible_node(NULL, NULL,
+ "raspberrypi,bcm2835-firmware");
+ if (!firmware_node) {
+ dev_err(dev, "Missing firmware node\n");
+ return -ENOENT;
+ }
+
+ firmware = rpi_firmware_get(firmware_node);
+ of_node_put(firmware_node);
+ if (!firmware)
+ return -EPROBE_DEFER;
+
+ rpi = devm_kzalloc(dev, sizeof(*rpi), GFP_KERNEL);
+ if (!rpi)
+ return -ENOMEM;
+
+ rpi->dev = dev;
+ rpi->firmware = firmware;
+ platform_set_drvdata(pdev, rpi);
+
+ ret = raspberrypi_register_pllb(rpi);
+ if (ret) {
+ dev_err(dev, "Failed to initialize pllb, %d\n", ret);
+ return ret;
+ }
+
+ ret = raspberrypi_register_pllb_arm(rpi);
+ if (ret)
+ return ret;
+
+ rpi->cpufreq = platform_device_register_data(dev, "raspberrypi-cpufreq",
+ -1, NULL, 0);
+
+ return 0;
+}
+
+static int raspberrypi_clk_remove(struct platform_device *pdev)
+{
+ struct raspberrypi_clk *rpi = platform_get_drvdata(pdev);
+
+ platform_device_unregister(rpi->cpufreq);
+
+ return 0;
+}
+
+static struct platform_driver raspberrypi_clk_driver = {
+ .driver = {
+ .name = "raspberrypi-clk",
+ },
+ .probe = raspberrypi_clk_probe,
+ .remove = raspberrypi_clk_remove,
+};
+module_platform_driver(raspberrypi_clk_driver);
+
+MODULE_AUTHOR("Nicolas Saenz Julienne <nsaenzjulienne@suse.de>");
+MODULE_DESCRIPTION("Raspberry Pi firmware clock driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:raspberrypi-clk");
diff --git a/drivers/clk/bcm/clk-sr.c b/drivers/clk/bcm/clk-sr.c
index 7b9efc0212a8..5db021685d6d 100644
--- a/drivers/clk/bcm/clk-sr.c
+++ b/drivers/clk/bcm/clk-sr.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2017 Broadcom
- *
- * 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 (the "GPL").
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License version 2 (GPLv2) for more details.
- *
- * You should have received a copy of the GNU General Public License
- * version 2 (GPLv2) along with this source code.
*/
#include <linux/err.h>
diff --git a/drivers/clk/clk-axm5516.c b/drivers/clk/clk-axm5516.c
index 98e0c9ba7b61..07e80fe8c310 100644
--- a/drivers/clk/clk-axm5516.c
+++ b/drivers/clk/clk-axm5516.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/clk/clk-axm5516.c
*
@@ -5,10 +6,6 @@
* the Axxia device: PLL clock, a clock divider and a clock mux.
*
* Copyright (C) 2014 LSI Corporation
- *
- * 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.
*/
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/drivers/clk/clk-bd718x7.c b/drivers/clk/clk-bd718x7.c
index 60422c72d142..ae6e5baee330 100644
--- a/drivers/clk/clk-bd718x7.c
+++ b/drivers/clk/clk-bd718x7.c
@@ -8,6 +8,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/mfd/rohm-bd718x7.h>
+#include <linux/mfd/rohm-bd70528.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/regmap.h>
@@ -17,7 +18,7 @@ struct bd718xx_clk {
u8 reg;
u8 mask;
struct platform_device *pdev;
- struct bd718xx *mfd;
+ struct rohm_regmap_dev *mfd;
};
static int bd71837_clk_set(struct clk_hw *hw, int status)
@@ -68,7 +69,7 @@ static int bd71837_clk_probe(struct platform_device *pdev)
int rval = -ENOMEM;
const char *parent_clk;
struct device *parent = pdev->dev.parent;
- struct bd718xx *mfd = dev_get_drvdata(parent);
+ struct rohm_regmap_dev *mfd = dev_get_drvdata(parent);
struct clk_init_data init = {
.name = "bd718xx-32k-out",
.ops = &bd71837_clk_ops,
@@ -86,9 +87,20 @@ static int bd71837_clk_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "No parent clk found\n");
return -EINVAL;
}
-
- c->reg = BD718XX_REG_OUT32K;
- c->mask = BD718XX_OUT32K_EN;
+ switch (mfd->chip_type) {
+ case ROHM_CHIP_TYPE_BD71837:
+ case ROHM_CHIP_TYPE_BD71847:
+ c->reg = BD718XX_REG_OUT32K;
+ c->mask = BD718XX_OUT32K_EN;
+ break;
+ case ROHM_CHIP_TYPE_BD70528:
+ c->reg = BD70528_REG_CLK_OUT;
+ c->mask = BD70528_CLK_OUT_EN_MASK;
+ break;
+ default:
+ dev_err(&pdev->dev, "Unknown clk chip\n");
+ return -EINVAL;
+ }
c->mfd = mfd;
c->pdev = pdev;
c->hw.init = &init;
@@ -119,5 +131,5 @@ static struct platform_driver bd71837_clk = {
module_platform_driver(bd71837_clk);
MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
-MODULE_DESCRIPTION("BD71837 chip clk driver");
+MODULE_DESCRIPTION("BD71837/BD71847/BD70528 chip clk driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/clk/clk-bulk.c b/drivers/clk/clk-bulk.c
index 06499568cf07..524bf9a53098 100644
--- a/drivers/clk/clk-bulk.c
+++ b/drivers/clk/clk-bulk.c
@@ -75,8 +75,8 @@ void clk_bulk_put(int num_clks, struct clk_bulk_data *clks)
}
EXPORT_SYMBOL_GPL(clk_bulk_put);
-int __must_check clk_bulk_get(struct device *dev, int num_clks,
- struct clk_bulk_data *clks)
+static int __clk_bulk_get(struct device *dev, int num_clks,
+ struct clk_bulk_data *clks, bool optional)
{
int ret;
int i;
@@ -88,10 +88,14 @@ int __must_check clk_bulk_get(struct device *dev, int num_clks,
clks[i].clk = clk_get(dev, clks[i].id);
if (IS_ERR(clks[i].clk)) {
ret = PTR_ERR(clks[i].clk);
+ clks[i].clk = NULL;
+
+ if (ret == -ENOENT && optional)
+ continue;
+
if (ret != -EPROBE_DEFER)
dev_err(dev, "Failed to get clk '%s': %d\n",
clks[i].id, ret);
- clks[i].clk = NULL;
goto err;
}
}
@@ -103,8 +107,21 @@ err:
return ret;
}
+
+int __must_check clk_bulk_get(struct device *dev, int num_clks,
+ struct clk_bulk_data *clks)
+{
+ return __clk_bulk_get(dev, num_clks, clks, false);
+}
EXPORT_SYMBOL(clk_bulk_get);
+int __must_check clk_bulk_get_optional(struct device *dev, int num_clks,
+ struct clk_bulk_data *clks)
+{
+ return __clk_bulk_get(dev, num_clks, clks, true);
+}
+EXPORT_SYMBOL_GPL(clk_bulk_get_optional);
+
void clk_bulk_put_all(int num_clks, struct clk_bulk_data *clks)
{
if (IS_ERR_OR_NULL(clks))
diff --git a/drivers/clk/clk-cdce706.c b/drivers/clk/clk-cdce706.c
index f21d9092564f..239102e37e2f 100644
--- a/drivers/clk/clk-cdce706.c
+++ b/drivers/clk/clk-cdce706.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TI CDCE706 programmable 3-PLL clock synthesizer driver
*
* Copyright (c) 2014 Cadence Design Systems Inc.
*
* Reference: http://www.ti.com/lit/ds/symlink/cdce706.pdf
- *
- * 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.
*/
#include <linux/clk.h>
@@ -633,7 +630,7 @@ of_clk_cdce_get(struct of_phandle_args *clkspec, void *data)
static int cdce706_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adapter = client->adapter;
struct cdce706_dev_data *cdce;
int ret;
diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c
index daa1fc8fba53..be160764911b 100644
--- a/drivers/clk/clk-devres.c
+++ b/drivers/clk/clk-devres.c
@@ -52,8 +52,8 @@ static void devm_clk_bulk_release(struct device *dev, void *res)
clk_bulk_put(devres->num_clks, devres->clks);
}
-int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
- struct clk_bulk_data *clks)
+static int __devm_clk_bulk_get(struct device *dev, int num_clks,
+ struct clk_bulk_data *clks, bool optional)
{
struct clk_bulk_devres *devres;
int ret;
@@ -63,7 +63,10 @@ int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
if (!devres)
return -ENOMEM;
- ret = clk_bulk_get(dev, num_clks, clks);
+ if (optional)
+ ret = clk_bulk_get_optional(dev, num_clks, clks);
+ else
+ ret = clk_bulk_get(dev, num_clks, clks);
if (!ret) {
devres->clks = clks;
devres->num_clks = num_clks;
@@ -74,8 +77,21 @@ int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
return ret;
}
+
+int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
+ struct clk_bulk_data *clks)
+{
+ return __devm_clk_bulk_get(dev, num_clks, clks, false);
+}
EXPORT_SYMBOL_GPL(devm_clk_bulk_get);
+int __must_check devm_clk_bulk_get_optional(struct device *dev, int num_clks,
+ struct clk_bulk_data *clks)
+{
+ return __devm_clk_bulk_get(dev, num_clks, clks, true);
+}
+EXPORT_SYMBOL_GPL(devm_clk_bulk_get_optional);
+
int __must_check devm_clk_bulk_get_all(struct device *dev,
struct clk_bulk_data **clks)
{
diff --git a/drivers/clk/clk-efm32gg.c b/drivers/clk/clk-efm32gg.c
index f37cf08ff7aa..85beaacb4088 100644
--- a/drivers/clk/clk-efm32gg.c
+++ b/drivers/clk/clk-efm32gg.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Pengutronix
* Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
- *
- * 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.
*/
#include <linux/io.h>
#include <linux/clk-provider.h>
diff --git a/drivers/clk/clk-lochnagar.c b/drivers/clk/clk-lochnagar.c
index a2f31e58ee48..fa8c91758b1d 100644
--- a/drivers/clk/clk-lochnagar.c
+++ b/drivers/clk/clk-lochnagar.c
@@ -16,7 +16,6 @@
#include <linux/platform_device.h>
#include <linux/regmap.h>
-#include <linux/mfd/lochnagar.h>
#include <linux/mfd/lochnagar1_regs.h>
#include <linux/mfd/lochnagar2_regs.h>
@@ -40,48 +39,46 @@ struct lochnagar_clk {
struct lochnagar_clk_priv {
struct device *dev;
struct regmap *regmap;
- enum lochnagar_type type;
-
- const char **parents;
- unsigned int nparents;
struct lochnagar_clk lclks[LOCHNAGAR_NUM_CLOCKS];
};
-static const char * const lochnagar1_clk_parents[] = {
- "ln-none",
- "ln-spdif-mclk",
- "ln-psia1-mclk",
- "ln-psia2-mclk",
- "ln-cdc-clkout",
- "ln-dsp-clkout",
- "ln-pmic-32k",
- "ln-gf-mclk1",
- "ln-gf-mclk3",
- "ln-gf-mclk2",
- "ln-gf-mclk4",
+#define LN_PARENT(NAME) { .name = NAME, .fw_name = NAME }
+
+static const struct clk_parent_data lochnagar1_clk_parents[] = {
+ LN_PARENT("ln-none"),
+ LN_PARENT("ln-spdif-mclk"),
+ LN_PARENT("ln-psia1-mclk"),
+ LN_PARENT("ln-psia2-mclk"),
+ LN_PARENT("ln-cdc-clkout"),
+ LN_PARENT("ln-dsp-clkout"),
+ LN_PARENT("ln-pmic-32k"),
+ LN_PARENT("ln-gf-mclk1"),
+ LN_PARENT("ln-gf-mclk3"),
+ LN_PARENT("ln-gf-mclk2"),
+ LN_PARENT("ln-gf-mclk4"),
};
-static const char * const lochnagar2_clk_parents[] = {
- "ln-none",
- "ln-cdc-clkout",
- "ln-dsp-clkout",
- "ln-pmic-32k",
- "ln-spdif-mclk",
- "ln-clk-12m",
- "ln-clk-11m",
- "ln-clk-24m",
- "ln-clk-22m",
- "ln-clk-8m",
- "ln-usb-clk-24m",
- "ln-gf-mclk1",
- "ln-gf-mclk3",
- "ln-gf-mclk2",
- "ln-psia1-mclk",
- "ln-psia2-mclk",
- "ln-spdif-clkout",
- "ln-adat-mclk",
- "ln-usb-clk-12m",
+static const struct clk_parent_data lochnagar2_clk_parents[] = {
+ LN_PARENT("ln-none"),
+ LN_PARENT("ln-cdc-clkout"),
+ LN_PARENT("ln-dsp-clkout"),
+ LN_PARENT("ln-pmic-32k"),
+ LN_PARENT("ln-spdif-mclk"),
+ LN_PARENT("ln-clk-12m"),
+ LN_PARENT("ln-clk-11m"),
+ LN_PARENT("ln-clk-24m"),
+ LN_PARENT("ln-clk-22m"),
+ LN_PARENT("ln-clk-8m"),
+ LN_PARENT("ln-usb-clk-24m"),
+ LN_PARENT("ln-gf-mclk1"),
+ LN_PARENT("ln-gf-mclk3"),
+ LN_PARENT("ln-gf-mclk2"),
+ LN_PARENT("ln-psia1-mclk"),
+ LN_PARENT("ln-psia2-mclk"),
+ LN_PARENT("ln-spdif-clkout"),
+ LN_PARENT("ln-adat-mclk"),
+ LN_PARENT("ln-usb-clk-12m"),
};
#define LN1_CLK(ID, NAME, REG) \
@@ -122,6 +119,24 @@ static const struct lochnagar_clk lochnagar2_clks[LOCHNAGAR_NUM_CLOCKS] = {
LN2_CLK(SOUNDCARD_MCLK, "ln-soundcard-mclk"),
};
+struct lochnagar_config {
+ const struct clk_parent_data *parents;
+ int nparents;
+ const struct lochnagar_clk *clks;
+};
+
+static const struct lochnagar_config lochnagar1_conf = {
+ .parents = lochnagar1_clk_parents,
+ .nparents = ARRAY_SIZE(lochnagar1_clk_parents),
+ .clks = lochnagar1_clks,
+};
+
+static const struct lochnagar_config lochnagar2_conf = {
+ .parents = lochnagar2_clk_parents,
+ .nparents = ARRAY_SIZE(lochnagar2_clk_parents),
+ .clks = lochnagar2_clks,
+};
+
static inline struct lochnagar_clk *lochnagar_hw_to_lclk(struct clk_hw *hw)
{
return container_of(hw, struct lochnagar_clk, hw);
@@ -183,7 +198,7 @@ static u8 lochnagar_clk_get_parent(struct clk_hw *hw)
if (ret < 0) {
dev_dbg(priv->dev, "Failed to read parent of %s: %d\n",
lclk->name, ret);
- return priv->nparents;
+ return hw->init->num_parents;
}
val &= lclk->src_mask;
@@ -198,46 +213,6 @@ static const struct clk_ops lochnagar_clk_ops = {
.get_parent = lochnagar_clk_get_parent,
};
-static int lochnagar_init_parents(struct lochnagar_clk_priv *priv)
-{
- struct device_node *np = priv->dev->of_node;
- int i, j;
-
- switch (priv->type) {
- case LOCHNAGAR1:
- memcpy(priv->lclks, lochnagar1_clks, sizeof(lochnagar1_clks));
-
- priv->nparents = ARRAY_SIZE(lochnagar1_clk_parents);
- priv->parents = devm_kmemdup(priv->dev, lochnagar1_clk_parents,
- sizeof(lochnagar1_clk_parents),
- GFP_KERNEL);
- break;
- case LOCHNAGAR2:
- memcpy(priv->lclks, lochnagar2_clks, sizeof(lochnagar2_clks));
-
- priv->nparents = ARRAY_SIZE(lochnagar2_clk_parents);
- priv->parents = devm_kmemdup(priv->dev, lochnagar2_clk_parents,
- sizeof(lochnagar2_clk_parents),
- GFP_KERNEL);
- break;
- default:
- dev_err(priv->dev, "Unknown Lochnagar type: %d\n", priv->type);
- return -EINVAL;
- }
-
- if (!priv->parents)
- return -ENOMEM;
-
- for (i = 0; i < priv->nparents; i++) {
- j = of_property_match_string(np, "clock-names",
- priv->parents[i]);
- if (j >= 0)
- priv->parents[i] = of_clk_get_parent_name(np, j);
- }
-
- return 0;
-}
-
static struct clk_hw *
lochnagar_of_clk_hw_get(struct of_phandle_args *clkspec, void *data)
{
@@ -252,16 +227,42 @@ lochnagar_of_clk_hw_get(struct of_phandle_args *clkspec, void *data)
return &priv->lclks[idx].hw;
}
-static int lochnagar_init_clks(struct lochnagar_clk_priv *priv)
+static const struct of_device_id lochnagar_of_match[] = {
+ { .compatible = "cirrus,lochnagar1-clk", .data = &lochnagar1_conf },
+ { .compatible = "cirrus,lochnagar2-clk", .data = &lochnagar2_conf },
+ {}
+};
+MODULE_DEVICE_TABLE(of, lochnagar_of_match);
+
+static int lochnagar_clk_probe(struct platform_device *pdev)
{
struct clk_init_data clk_init = {
.ops = &lochnagar_clk_ops,
- .parent_names = priv->parents,
- .num_parents = priv->nparents,
};
+ struct device *dev = &pdev->dev;
+ struct lochnagar_clk_priv *priv;
+ const struct of_device_id *of_id;
struct lochnagar_clk *lclk;
+ struct lochnagar_config *conf;
int ret, i;
+ of_id = of_match_device(lochnagar_of_match, dev);
+ if (!of_id)
+ return -EINVAL;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = dev;
+ priv->regmap = dev_get_regmap(dev->parent, NULL);
+ conf = (struct lochnagar_config *)of_id->data;
+
+ memcpy(priv->lclks, conf->clks, sizeof(priv->lclks));
+
+ clk_init.parent_data = conf->parents;
+ clk_init.num_parents = conf->nparents;
+
for (i = 0; i < ARRAY_SIZE(priv->lclks); i++) {
lclk = &priv->lclks[i];
@@ -273,55 +274,21 @@ static int lochnagar_init_clks(struct lochnagar_clk_priv *priv)
lclk->priv = priv;
lclk->hw.init = &clk_init;
- ret = devm_clk_hw_register(priv->dev, &lclk->hw);
+ ret = devm_clk_hw_register(dev, &lclk->hw);
if (ret) {
- dev_err(priv->dev, "Failed to register %s: %d\n",
+ dev_err(dev, "Failed to register %s: %d\n",
lclk->name, ret);
return ret;
}
}
- ret = devm_of_clk_add_hw_provider(priv->dev, lochnagar_of_clk_hw_get,
- priv);
+ ret = devm_of_clk_add_hw_provider(dev, lochnagar_of_clk_hw_get, priv);
if (ret < 0)
- dev_err(priv->dev, "Failed to register provider: %d\n", ret);
+ dev_err(dev, "Failed to register provider: %d\n", ret);
return ret;
}
-static const struct of_device_id lochnagar_of_match[] = {
- { .compatible = "cirrus,lochnagar1-clk", .data = (void *)LOCHNAGAR1 },
- { .compatible = "cirrus,lochnagar2-clk", .data = (void *)LOCHNAGAR2 },
- {}
-};
-MODULE_DEVICE_TABLE(of, lochnagar_of_match);
-
-static int lochnagar_clk_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct lochnagar_clk_priv *priv;
- const struct of_device_id *of_id;
- int ret;
-
- of_id = of_match_device(lochnagar_of_match, dev);
- if (!of_id)
- return -EINVAL;
-
- priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- priv->dev = dev;
- priv->regmap = dev_get_regmap(dev->parent, NULL);
- priv->type = (enum lochnagar_type)of_id->data;
-
- ret = lochnagar_init_parents(priv);
- if (ret)
- return ret;
-
- return lochnagar_init_clks(priv);
-}
-
static struct platform_driver lochnagar_clk_driver = {
.driver = {
.name = "lochnagar-clk",
diff --git a/drivers/clk/clk-nspire.c b/drivers/clk/clk-nspire.c
index f861011d5d21..6305058dd0d3 100644
--- a/drivers/clk/clk-nspire.c
+++ b/drivers/clk/clk-nspire.c
@@ -1,11 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
*
* Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au>
- *
- * 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.
- *
*/
#include <linux/clk-provider.h>
diff --git a/drivers/clk/clk-pwm.c b/drivers/clk/clk-pwm.c
index 02b472a1f9b0..87fe0b0e01a3 100644
--- a/drivers/clk/clk-pwm.c
+++ b/drivers/clk/clk-pwm.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 Philipp Zabel, Pengutronix
*
- * 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.
- *
* PWM (mis)used as clock output
*/
#include <linux/clk-provider.h>
@@ -47,10 +44,24 @@ static unsigned long clk_pwm_recalc_rate(struct clk_hw *hw,
return clk_pwm->fixed_rate;
}
+static int clk_pwm_get_duty_cycle(struct clk_hw *hw, struct clk_duty *duty)
+{
+ struct clk_pwm *clk_pwm = to_clk_pwm(hw);
+ struct pwm_state state;
+
+ pwm_get_state(clk_pwm->pwm, &state);
+
+ duty->num = state.duty_cycle;
+ duty->den = state.period;
+
+ return 0;
+}
+
static const struct clk_ops clk_pwm_ops = {
.prepare = clk_pwm_prepare,
.unprepare = clk_pwm_unprepare,
.recalc_rate = clk_pwm_recalc_rate,
+ .get_duty_cycle = clk_pwm_get_duty_cycle,
};
static int clk_pwm_probe(struct platform_device *pdev)
diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c
index 4739a47ec8bd..07f3b252f3e0 100644
--- a/drivers/clk/clk-qoriq.c
+++ b/drivers/clk/clk-qoriq.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2013 Freescale Semiconductor, 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.
- *
* clock driver for Freescale QorIQ SoCs.
*/
@@ -638,6 +635,17 @@ static const struct clockgen_chipinfo chipinfo[] = {
.flags = CG_VER3 | CG_LITTLE_ENDIAN,
},
{
+ .compat = "fsl,lx2160a-clockgen",
+ .cmux_groups = {
+ &clockgen2_cmux_cga12, &clockgen2_cmux_cgb
+ },
+ .cmux_to_group = {
+ 0, 0, 0, 0, 1, 1, 1, 1, -1
+ },
+ .pll_mask = 0x37,
+ .flags = CG_VER3 | CG_LITTLE_ENDIAN,
+ },
+ {
.compat = "fsl,p2041-clockgen",
.guts_compat = "fsl,qoriq-device-config-1.0",
.init_periph = p2041_init_periph,
@@ -1496,6 +1504,7 @@ CLK_OF_DECLARE(qoriq_clockgen_ls1043a, "fsl,ls1043a-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_ls1046a, "fsl,ls1046a-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_ls1088a, "fsl,ls1088a-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_ls2080a, "fsl,ls2080a-clockgen", clockgen_init);
+CLK_OF_DECLARE(qoriq_clockgen_lx2160a, "fsl,lx2160a-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_p2041, "fsl,p2041-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_p3041, "fsl,p3041-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_p4080, "fsl,p4080-clockgen", clockgen_init);
diff --git a/drivers/clk/clk-rk808.c b/drivers/clk/clk-rk808.c
index b1d7e4a296ef..32f833d732ed 100644
--- a/drivers/clk/clk-rk808.c
+++ b/drivers/clk/clk-rk808.c
@@ -88,6 +88,68 @@ of_clk_rk808_get(struct of_phandle_args *clkspec, void *data)
return idx ? &rk808_clkout->clkout2_hw : &rk808_clkout->clkout1_hw;
}
+static int rk817_clkout2_enable(struct clk_hw *hw, bool enable)
+{
+ struct rk808_clkout *rk808_clkout = container_of(hw,
+ struct rk808_clkout,
+ clkout2_hw);
+ struct rk808 *rk808 = rk808_clkout->rk808;
+
+ return regmap_update_bits(rk808->regmap, RK817_SYS_CFG(1),
+ RK817_CLK32KOUT2_EN,
+ enable ? RK817_CLK32KOUT2_EN : 0);
+}
+
+static int rk817_clkout2_prepare(struct clk_hw *hw)
+{
+ return rk817_clkout2_enable(hw, true);
+}
+
+static void rk817_clkout2_unprepare(struct clk_hw *hw)
+{
+ rk817_clkout2_enable(hw, false);
+}
+
+static int rk817_clkout2_is_prepared(struct clk_hw *hw)
+{
+ struct rk808_clkout *rk808_clkout = container_of(hw,
+ struct rk808_clkout,
+ clkout2_hw);
+ struct rk808 *rk808 = rk808_clkout->rk808;
+ unsigned int val;
+
+ int ret = regmap_read(rk808->regmap, RK817_SYS_CFG(1), &val);
+
+ if (ret < 0)
+ return 0;
+
+ return (val & RK817_CLK32KOUT2_EN) ? 1 : 0;
+}
+
+static const struct clk_ops rk817_clkout2_ops = {
+ .prepare = rk817_clkout2_prepare,
+ .unprepare = rk817_clkout2_unprepare,
+ .is_prepared = rk817_clkout2_is_prepared,
+ .recalc_rate = rk808_clkout_recalc_rate,
+};
+
+static const struct clk_ops *rkpmic_get_ops(long variant)
+{
+ switch (variant) {
+ case RK809_ID:
+ case RK817_ID:
+ return &rk817_clkout2_ops;
+ /*
+ * For the default case, it match the following PMIC type.
+ * RK805_ID
+ * RK808_ID
+ * RK818_ID
+ */
+ default:
+ return &rk808_clkout2_ops;
+ }
+}
+
static int rk808_clkout_probe(struct platform_device *pdev)
{
struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent);
@@ -119,7 +181,7 @@ static int rk808_clkout_probe(struct platform_device *pdev)
return ret;
init.name = "rk808-clkout2";
- init.ops = &rk808_clkout2_ops;
+ init.ops = rkpmic_get_ops(rk808->variant);
rk808_clkout->clkout2_hw.init = &init;
/* optional override of the clockname */
diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c
new file mode 100644
index 000000000000..72424eb7e5f8
--- /dev/null
+++ b/drivers/clk/clk-si5341.c
@@ -0,0 +1,1346 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Silicon Labs Si5341/Si5340 Clock generator
+ * Copyright (C) 2019 Topic Embedded Products
+ * Author: Mike Looijmans <mike.looijmans@topic.nl>
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/gcd.h>
+#include <linux/math64.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <asm/unaligned.h>
+
+#define SI5341_MAX_NUM_OUTPUTS 10
+#define SI5340_MAX_NUM_OUTPUTS 4
+
+#define SI5341_NUM_SYNTH 5
+#define SI5340_NUM_SYNTH 4
+
+/* Range of the synthesizer fractional divider */
+#define SI5341_SYNTH_N_MIN 10
+#define SI5341_SYNTH_N_MAX 4095
+
+/* The chip can get its input clock from 3 input pins or an XTAL */
+
+/* There is one PLL running at 13500–14256 MHz */
+#define SI5341_PLL_VCO_MIN 13500000000ull
+#define SI5341_PLL_VCO_MAX 14256000000ull
+
+/* The 5 frequency synthesizers obtain their input from the PLL */
+struct clk_si5341_synth {
+ struct clk_hw hw;
+ struct clk_si5341 *data;
+ u8 index;
+};
+#define to_clk_si5341_synth(_hw) \
+ container_of(_hw, struct clk_si5341_synth, hw)
+
+/* The output stages can be connected to any synth (full mux) */
+struct clk_si5341_output {
+ struct clk_hw hw;
+ struct clk_si5341 *data;
+ u8 index;
+};
+#define to_clk_si5341_output(_hw) \
+ container_of(_hw, struct clk_si5341_output, hw)
+
+struct clk_si5341 {
+ struct clk_hw hw;
+ struct regmap *regmap;
+ struct i2c_client *i2c_client;
+ struct clk_si5341_synth synth[SI5341_NUM_SYNTH];
+ struct clk_si5341_output clk[SI5341_MAX_NUM_OUTPUTS];
+ struct clk *pxtal;
+ const char *pxtal_name;
+ const u16 *reg_output_offset;
+ const u16 *reg_rdiv_offset;
+ u64 freq_vco; /* 13500–14256 MHz */
+ u8 num_outputs;
+ u8 num_synth;
+};
+#define to_clk_si5341(_hw) container_of(_hw, struct clk_si5341, hw)
+
+struct clk_si5341_output_config {
+ u8 out_format_drv_bits;
+ u8 out_cm_ampl_bits;
+ bool synth_master;
+ bool always_on;
+};
+
+#define SI5341_PAGE 0x0001
+#define SI5341_PN_BASE 0x0002
+#define SI5341_DEVICE_REV 0x0005
+#define SI5341_STATUS 0x000C
+#define SI5341_SOFT_RST 0x001C
+
+/* Input dividers (48-bit) */
+#define SI5341_IN_PDIV(x) (0x0208 + ((x) * 10))
+#define SI5341_IN_PSET(x) (0x020E + ((x) * 10))
+
+/* PLL configuration */
+#define SI5341_PLL_M_NUM 0x0235
+#define SI5341_PLL_M_DEN 0x023B
+
+/* Output configuration */
+#define SI5341_OUT_CONFIG(output) \
+ ((output)->data->reg_output_offset[(output)->index])
+#define SI5341_OUT_FORMAT(output) (SI5341_OUT_CONFIG(output) + 1)
+#define SI5341_OUT_CM(output) (SI5341_OUT_CONFIG(output) + 2)
+#define SI5341_OUT_MUX_SEL(output) (SI5341_OUT_CONFIG(output) + 3)
+#define SI5341_OUT_R_REG(output) \
+ ((output)->data->reg_rdiv_offset[(output)->index])
+
+/* Synthesize N divider */
+#define SI5341_SYNTH_N_NUM(x) (0x0302 + ((x) * 11))
+#define SI5341_SYNTH_N_DEN(x) (0x0308 + ((x) * 11))
+#define SI5341_SYNTH_N_UPD(x) (0x030C + ((x) * 11))
+
+/* Synthesizer output enable, phase bypass, power mode */
+#define SI5341_SYNTH_N_CLK_TO_OUTX_EN 0x0A03
+#define SI5341_SYNTH_N_PIBYP 0x0A04
+#define SI5341_SYNTH_N_PDNB 0x0A05
+#define SI5341_SYNTH_N_CLK_DIS 0x0B4A
+
+#define SI5341_REGISTER_MAX 0xBFF
+
+/* SI5341_OUT_CONFIG bits */
+#define SI5341_OUT_CFG_PDN BIT(0)
+#define SI5341_OUT_CFG_OE BIT(1)
+#define SI5341_OUT_CFG_RDIV_FORCE2 BIT(2)
+
+/* Static configuration (to be moved to firmware) */
+struct si5341_reg_default {
+ u16 address;
+ u8 value;
+};
+
+/* Output configuration registers 0..9 are not quite logically organized */
+static const u16 si5341_reg_output_offset[] = {
+ 0x0108,
+ 0x010D,
+ 0x0112,
+ 0x0117,
+ 0x011C,
+ 0x0121,
+ 0x0126,
+ 0x012B,
+ 0x0130,
+ 0x013A,
+};
+
+static const u16 si5340_reg_output_offset[] = {
+ 0x0112,
+ 0x0117,
+ 0x0126,
+ 0x012B,
+};
+
+/* The location of the R divider registers */
+static const u16 si5341_reg_rdiv_offset[] = {
+ 0x024A,
+ 0x024D,
+ 0x0250,
+ 0x0253,
+ 0x0256,
+ 0x0259,
+ 0x025C,
+ 0x025F,
+ 0x0262,
+ 0x0268,
+};
+static const u16 si5340_reg_rdiv_offset[] = {
+ 0x0250,
+ 0x0253,
+ 0x025C,
+ 0x025F,
+};
+
+/*
+ * Programming sequence from ClockBuilder, settings to initialize the system
+ * using only the XTAL input, without pre-divider.
+ * This also contains settings that aren't mentioned anywhere in the datasheet.
+ * The "known" settings like synth and output configuration are done later.
+ */
+static const struct si5341_reg_default si5341_reg_defaults[] = {
+ { 0x0017, 0x3A }, /* INT mask (disable interrupts) */
+ { 0x0018, 0xFF }, /* INT mask */
+ { 0x0021, 0x0F }, /* Select XTAL as input */
+ { 0x0022, 0x00 }, /* Not in datasheet */
+ { 0x002B, 0x02 }, /* SPI config */
+ { 0x002C, 0x20 }, /* LOS enable for XTAL */
+ { 0x002D, 0x00 }, /* LOS timing */
+ { 0x002E, 0x00 },
+ { 0x002F, 0x00 },
+ { 0x0030, 0x00 },
+ { 0x0031, 0x00 },
+ { 0x0032, 0x00 },
+ { 0x0033, 0x00 },
+ { 0x0034, 0x00 },
+ { 0x0035, 0x00 },
+ { 0x0036, 0x00 },
+ { 0x0037, 0x00 },
+ { 0x0038, 0x00 }, /* LOS setting (thresholds) */
+ { 0x0039, 0x00 },
+ { 0x003A, 0x00 },
+ { 0x003B, 0x00 },
+ { 0x003C, 0x00 },
+ { 0x003D, 0x00 }, /* LOS setting (thresholds) end */
+ { 0x0041, 0x00 }, /* LOS0_DIV_SEL */
+ { 0x0042, 0x00 }, /* LOS1_DIV_SEL */
+ { 0x0043, 0x00 }, /* LOS2_DIV_SEL */
+ { 0x0044, 0x00 }, /* LOS3_DIV_SEL */
+ { 0x009E, 0x00 }, /* Not in datasheet */
+ { 0x0102, 0x01 }, /* Enable outputs */
+ { 0x013F, 0x00 }, /* Not in datasheet */
+ { 0x0140, 0x00 }, /* Not in datasheet */
+ { 0x0141, 0x40 }, /* OUT LOS */
+ { 0x0202, 0x00 }, /* XAXB_FREQ_OFFSET (=0)*/
+ { 0x0203, 0x00 },
+ { 0x0204, 0x00 },
+ { 0x0205, 0x00 },
+ { 0x0206, 0x00 }, /* PXAXB (2^x) */
+ { 0x0208, 0x00 }, /* Px divider setting (usually 0) */
+ { 0x0209, 0x00 },
+ { 0x020A, 0x00 },
+ { 0x020B, 0x00 },
+ { 0x020C, 0x00 },
+ { 0x020D, 0x00 },
+ { 0x020E, 0x00 },
+ { 0x020F, 0x00 },
+ { 0x0210, 0x00 },
+ { 0x0211, 0x00 },
+ { 0x0212, 0x00 },
+ { 0x0213, 0x00 },
+ { 0x0214, 0x00 },
+ { 0x0215, 0x00 },
+ { 0x0216, 0x00 },
+ { 0x0217, 0x00 },
+ { 0x0218, 0x00 },
+ { 0x0219, 0x00 },
+ { 0x021A, 0x00 },
+ { 0x021B, 0x00 },
+ { 0x021C, 0x00 },
+ { 0x021D, 0x00 },
+ { 0x021E, 0x00 },
+ { 0x021F, 0x00 },
+ { 0x0220, 0x00 },
+ { 0x0221, 0x00 },
+ { 0x0222, 0x00 },
+ { 0x0223, 0x00 },
+ { 0x0224, 0x00 },
+ { 0x0225, 0x00 },
+ { 0x0226, 0x00 },
+ { 0x0227, 0x00 },
+ { 0x0228, 0x00 },
+ { 0x0229, 0x00 },
+ { 0x022A, 0x00 },
+ { 0x022B, 0x00 },
+ { 0x022C, 0x00 },
+ { 0x022D, 0x00 },
+ { 0x022E, 0x00 },
+ { 0x022F, 0x00 }, /* Px divider setting (usually 0) end */
+ { 0x026B, 0x00 }, /* DESIGN_ID (ASCII string) */
+ { 0x026C, 0x00 },
+ { 0x026D, 0x00 },
+ { 0x026E, 0x00 },
+ { 0x026F, 0x00 },
+ { 0x0270, 0x00 },
+ { 0x0271, 0x00 },
+ { 0x0272, 0x00 }, /* DESIGN_ID (ASCII string) end */
+ { 0x0339, 0x1F }, /* N_FSTEP_MSK */
+ { 0x033B, 0x00 }, /* Nx_FSTEPW (Frequency step) */
+ { 0x033C, 0x00 },
+ { 0x033D, 0x00 },
+ { 0x033E, 0x00 },
+ { 0x033F, 0x00 },
+ { 0x0340, 0x00 },
+ { 0x0341, 0x00 },
+ { 0x0342, 0x00 },
+ { 0x0343, 0x00 },
+ { 0x0344, 0x00 },
+ { 0x0345, 0x00 },
+ { 0x0346, 0x00 },
+ { 0x0347, 0x00 },
+ { 0x0348, 0x00 },
+ { 0x0349, 0x00 },
+ { 0x034A, 0x00 },
+ { 0x034B, 0x00 },
+ { 0x034C, 0x00 },
+ { 0x034D, 0x00 },
+ { 0x034E, 0x00 },
+ { 0x034F, 0x00 },
+ { 0x0350, 0x00 },
+ { 0x0351, 0x00 },
+ { 0x0352, 0x00 },
+ { 0x0353, 0x00 },
+ { 0x0354, 0x00 },
+ { 0x0355, 0x00 },
+ { 0x0356, 0x00 },
+ { 0x0357, 0x00 },
+ { 0x0358, 0x00 }, /* Nx_FSTEPW (Frequency step) end */
+ { 0x0359, 0x00 }, /* Nx_DELAY */
+ { 0x035A, 0x00 },
+ { 0x035B, 0x00 },
+ { 0x035C, 0x00 },
+ { 0x035D, 0x00 },
+ { 0x035E, 0x00 },
+ { 0x035F, 0x00 },
+ { 0x0360, 0x00 },
+ { 0x0361, 0x00 },
+ { 0x0362, 0x00 }, /* Nx_DELAY end */
+ { 0x0802, 0x00 }, /* Not in datasheet */
+ { 0x0803, 0x00 }, /* Not in datasheet */
+ { 0x0804, 0x00 }, /* Not in datasheet */
+ { 0x090E, 0x02 }, /* XAXB_EXTCLK_EN=0 XAXB_PDNB=1 (use XTAL) */
+ { 0x091C, 0x04 }, /* ZDM_EN=4 (Normal mode) */
+ { 0x0943, 0x00 }, /* IO_VDD_SEL=0 (0=1v8, use 1=3v3) */
+ { 0x0949, 0x00 }, /* IN_EN (disable input clocks) */
+ { 0x094A, 0x00 }, /* INx_TO_PFD_EN (disabled) */
+ { 0x0A02, 0x00 }, /* Not in datasheet */
+ { 0x0B44, 0x0F }, /* PDIV_ENB (datasheet does not mention what it is) */
+};
+
+/* Read and interpret a 44-bit followed by a 32-bit value in the regmap */
+static int si5341_decode_44_32(struct regmap *regmap, unsigned int reg,
+ u64 *val1, u32 *val2)
+{
+ int err;
+ u8 r[10];
+
+ err = regmap_bulk_read(regmap, reg, r, 10);
+ if (err < 0)
+ return err;
+
+ *val1 = ((u64)((r[5] & 0x0f) << 8 | r[4]) << 32) |
+ (get_unaligned_le32(r));
+ *val2 = get_unaligned_le32(&r[6]);
+
+ return 0;
+}
+
+static int si5341_encode_44_32(struct regmap *regmap, unsigned int reg,
+ u64 n_num, u32 n_den)
+{
+ u8 r[10];
+
+ /* Shift left as far as possible without overflowing */
+ while (!(n_num & BIT_ULL(43)) && !(n_den & BIT(31))) {
+ n_num <<= 1;
+ n_den <<= 1;
+ }
+
+ /* 44 bits (6 bytes) numerator */
+ put_unaligned_le32(n_num, r);
+ r[4] = (n_num >> 32) & 0xff;
+ r[5] = (n_num >> 40) & 0x0f;
+ /* 32 bits denominator */
+ put_unaligned_le32(n_den, &r[6]);
+
+ /* Program the fraction */
+ return regmap_bulk_write(regmap, reg, r, sizeof(r));
+}
+
+/* VCO, we assume it runs at a constant frequency */
+static unsigned long si5341_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_si5341 *data = to_clk_si5341(hw);
+ int err;
+ u64 res;
+ u64 m_num;
+ u32 m_den;
+ unsigned int shift;
+
+ /* Assume that PDIV is not being used, just read the PLL setting */
+ err = si5341_decode_44_32(data->regmap, SI5341_PLL_M_NUM,
+ &m_num, &m_den);
+ if (err < 0)
+ return 0;
+
+ if (!m_num || !m_den)
+ return 0;
+
+ /*
+ * Though m_num is 64-bit, only the upper bits are actually used. While
+ * calculating m_num and m_den, they are shifted as far as possible to
+ * the left. To avoid 96-bit division here, we just shift them back so
+ * we can do with just 64 bits.
+ */
+ shift = 0;
+ res = m_num;
+ while (res & 0xffff00000000ULL) {
+ ++shift;
+ res >>= 1;
+ }
+ res *= parent_rate;
+ do_div(res, (m_den >> shift));
+
+ /* We cannot return the actual frequency in 32 bit, store it locally */
+ data->freq_vco = res;
+
+ /* Report kHz since the value is out of range */
+ do_div(res, 1000);
+
+ return (unsigned long)res;
+}
+
+static const struct clk_ops si5341_clk_ops = {
+ .recalc_rate = si5341_clk_recalc_rate,
+};
+
+/* Synthesizers, there are 5 synthesizers that connect to any of the outputs */
+
+/* The synthesizer is on if all power and enable bits are set */
+static int si5341_synth_clk_is_on(struct clk_hw *hw)
+{
+ struct clk_si5341_synth *synth = to_clk_si5341_synth(hw);
+ int err;
+ u32 val;
+ u8 index = synth->index;
+
+ err = regmap_read(synth->data->regmap,
+ SI5341_SYNTH_N_CLK_TO_OUTX_EN, &val);
+ if (err < 0)
+ return 0;
+
+ if (!(val & BIT(index)))
+ return 0;
+
+ err = regmap_read(synth->data->regmap, SI5341_SYNTH_N_PDNB, &val);
+ if (err < 0)
+ return 0;
+
+ if (!(val & BIT(index)))
+ return 0;
+
+ /* This bit must be 0 for the synthesizer to receive clock input */
+ err = regmap_read(synth->data->regmap, SI5341_SYNTH_N_CLK_DIS, &val);
+ if (err < 0)
+ return 0;
+
+ return !(val & BIT(index));
+}
+
+static void si5341_synth_clk_unprepare(struct clk_hw *hw)
+{
+ struct clk_si5341_synth *synth = to_clk_si5341_synth(hw);
+ u8 index = synth->index; /* In range 0..5 */
+ u8 mask = BIT(index);
+
+ /* Disable output */
+ regmap_update_bits(synth->data->regmap,
+ SI5341_SYNTH_N_CLK_TO_OUTX_EN, mask, 0);
+ /* Power down */
+ regmap_update_bits(synth->data->regmap,
+ SI5341_SYNTH_N_PDNB, mask, 0);
+ /* Disable clock input to synth (set to 1 to disable) */
+ regmap_update_bits(synth->data->regmap,
+ SI5341_SYNTH_N_CLK_DIS, mask, mask);
+}
+
+static int si5341_synth_clk_prepare(struct clk_hw *hw)
+{
+ struct clk_si5341_synth *synth = to_clk_si5341_synth(hw);
+ int err;
+ u8 index = synth->index;
+ u8 mask = BIT(index);
+
+ /* Power up */
+ err = regmap_update_bits(synth->data->regmap,
+ SI5341_SYNTH_N_PDNB, mask, mask);
+ if (err < 0)
+ return err;
+
+ /* Enable clock input to synth (set bit to 0 to enable) */
+ err = regmap_update_bits(synth->data->regmap,
+ SI5341_SYNTH_N_CLK_DIS, mask, 0);
+ if (err < 0)
+ return err;
+
+ /* Enable output */
+ return regmap_update_bits(synth->data->regmap,
+ SI5341_SYNTH_N_CLK_TO_OUTX_EN, mask, mask);
+}
+
+/* Synth clock frequency: Fvco * n_den / n_den, with Fvco in 13500-14256 MHz */
+static unsigned long si5341_synth_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_si5341_synth *synth = to_clk_si5341_synth(hw);
+ u64 f;
+ u64 n_num;
+ u32 n_den;
+ int err;
+
+ err = si5341_decode_44_32(synth->data->regmap,
+ SI5341_SYNTH_N_NUM(synth->index), &n_num, &n_den);
+ if (err < 0)
+ return err;
+
+ /*
+ * n_num and n_den are shifted left as much as possible, so to prevent
+ * overflow in 64-bit math, we shift n_den 4 bits to the right
+ */
+ f = synth->data->freq_vco;
+ f *= n_den >> 4;
+
+ /* Now we need to to 64-bit division: f/n_num */
+ /* And compensate for the 4 bits we dropped */
+ f = div64_u64(f, (n_num >> 4));
+
+ return f;
+}
+
+static long si5341_synth_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct clk_si5341_synth *synth = to_clk_si5341_synth(hw);
+ u64 f;
+
+ /* The synthesizer accuracy is such that anything in range will work */
+ f = synth->data->freq_vco;
+ do_div(f, SI5341_SYNTH_N_MAX);
+ if (rate < f)
+ return f;
+
+ f = synth->data->freq_vco;
+ do_div(f, SI5341_SYNTH_N_MIN);
+ if (rate > f)
+ return f;
+
+ return rate;
+}
+
+static int si5341_synth_program(struct clk_si5341_synth *synth,
+ u64 n_num, u32 n_den, bool is_integer)
+{
+ int err;
+ u8 index = synth->index;
+
+ err = si5341_encode_44_32(synth->data->regmap,
+ SI5341_SYNTH_N_NUM(index), n_num, n_den);
+
+ err = regmap_update_bits(synth->data->regmap,
+ SI5341_SYNTH_N_PIBYP, BIT(index), is_integer ? BIT(index) : 0);
+ if (err < 0)
+ return err;
+
+ return regmap_write(synth->data->regmap,
+ SI5341_SYNTH_N_UPD(index), 0x01);
+}
+
+
+static int si5341_synth_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_si5341_synth *synth = to_clk_si5341_synth(hw);
+ u64 n_num;
+ u32 n_den;
+ u32 r;
+ u32 g;
+ bool is_integer;
+
+ n_num = synth->data->freq_vco;
+ n_den = rate;
+
+ /* see if there's an integer solution */
+ r = do_div(n_num, rate);
+ is_integer = (r == 0);
+ if (is_integer) {
+ /* Integer divider equal to n_num */
+ n_den = 1;
+ } else {
+ /* Calculate a fractional solution */
+ g = gcd(r, rate);
+ n_den = rate / g;
+ n_num *= n_den;
+ n_num += r / g;
+ }
+
+ dev_dbg(&synth->data->i2c_client->dev,
+ "%s(%u): n=0x%llx d=0x%x %s\n", __func__,
+ synth->index, n_num, n_den,
+ is_integer ? "int" : "frac");
+
+ return si5341_synth_program(synth, n_num, n_den, is_integer);
+}
+
+static const struct clk_ops si5341_synth_clk_ops = {
+ .is_prepared = si5341_synth_clk_is_on,
+ .prepare = si5341_synth_clk_prepare,
+ .unprepare = si5341_synth_clk_unprepare,
+ .recalc_rate = si5341_synth_clk_recalc_rate,
+ .round_rate = si5341_synth_clk_round_rate,
+ .set_rate = si5341_synth_clk_set_rate,
+};
+
+static int si5341_output_clk_is_on(struct clk_hw *hw)
+{
+ struct clk_si5341_output *output = to_clk_si5341_output(hw);
+ int err;
+ u32 val;
+
+ err = regmap_read(output->data->regmap,
+ SI5341_OUT_CONFIG(output), &val);
+ if (err < 0)
+ return err;
+
+ /* Bit 0=PDN, 1=OE so only a value of 0x2 enables the output */
+ return (val & 0x03) == SI5341_OUT_CFG_OE;
+}
+
+/* Disables and then powers down the output */
+static void si5341_output_clk_unprepare(struct clk_hw *hw)
+{
+ struct clk_si5341_output *output = to_clk_si5341_output(hw);
+
+ regmap_update_bits(output->data->regmap,
+ SI5341_OUT_CONFIG(output),
+ SI5341_OUT_CFG_OE, 0);
+ regmap_update_bits(output->data->regmap,
+ SI5341_OUT_CONFIG(output),
+ SI5341_OUT_CFG_PDN, SI5341_OUT_CFG_PDN);
+}
+
+/* Powers up and then enables the output */
+static int si5341_output_clk_prepare(struct clk_hw *hw)
+{
+ struct clk_si5341_output *output = to_clk_si5341_output(hw);
+ int err;
+
+ err = regmap_update_bits(output->data->regmap,
+ SI5341_OUT_CONFIG(output),
+ SI5341_OUT_CFG_PDN, 0);
+ if (err < 0)
+ return err;
+
+ return regmap_update_bits(output->data->regmap,
+ SI5341_OUT_CONFIG(output),
+ SI5341_OUT_CFG_OE, SI5341_OUT_CFG_OE);
+}
+
+static unsigned long si5341_output_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_si5341_output *output = to_clk_si5341_output(hw);
+ int err;
+ u32 val;
+ u32 r_divider;
+ u8 r[3];
+
+ err = regmap_bulk_read(output->data->regmap,
+ SI5341_OUT_R_REG(output), r, 3);
+ if (err < 0)
+ return err;
+
+ /* Calculate value as 24-bit integer*/
+ r_divider = r[2] << 16 | r[1] << 8 | r[0];
+
+ /* If Rx_REG is zero, the divider is disabled, so return a "0" rate */
+ if (!r_divider)
+ return 0;
+
+ /* Divider is 2*(Rx_REG+1) */
+ r_divider += 1;
+ r_divider <<= 1;
+
+ err = regmap_read(output->data->regmap,
+ SI5341_OUT_CONFIG(output), &val);
+ if (err < 0)
+ return err;
+
+ if (val & SI5341_OUT_CFG_RDIV_FORCE2)
+ r_divider = 2;
+
+ return parent_rate / r_divider;
+}
+
+static long si5341_output_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ unsigned long r;
+
+ r = *parent_rate >> 1;
+
+ /* If rate is an even divisor, no changes to parent required */
+ if (r && !(r % rate))
+ return (long)rate;
+
+ if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
+ if (rate > 200000000) {
+ /* minimum r-divider is 2 */
+ r = 2;
+ } else {
+ /* Take a parent frequency near 400 MHz */
+ r = (400000000u / rate) & ~1;
+ }
+ *parent_rate = r * rate;
+ } else {
+ /* We cannot change our parent's rate, report what we can do */
+ r /= rate;
+ rate = *parent_rate / (r << 1);
+ }
+
+ return rate;
+}
+
+static int si5341_output_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_si5341_output *output = to_clk_si5341_output(hw);
+ /* Frequency divider is (r_div + 1) * 2 */
+ u32 r_div = (parent_rate / rate) >> 1;
+ int err;
+ u8 r[3];
+
+ if (r_div <= 1)
+ r_div = 0;
+ else if (r_div >= BIT(24))
+ r_div = BIT(24) - 1;
+ else
+ --r_div;
+
+ /* For a value of "2", we set the "OUT0_RDIV_FORCE2" bit */
+ err = regmap_update_bits(output->data->regmap,
+ SI5341_OUT_CONFIG(output),
+ SI5341_OUT_CFG_RDIV_FORCE2,
+ (r_div == 0) ? SI5341_OUT_CFG_RDIV_FORCE2 : 0);
+ if (err < 0)
+ return err;
+
+ /* Always write Rx_REG, because a zero value disables the divider */
+ r[0] = r_div ? (r_div & 0xff) : 1;
+ r[1] = (r_div >> 8) & 0xff;
+ r[2] = (r_div >> 16) & 0xff;
+ err = regmap_bulk_write(output->data->regmap,
+ SI5341_OUT_R_REG(output), r, 3);
+
+ return 0;
+}
+
+static int si5341_output_reparent(struct clk_si5341_output *output, u8 index)
+{
+ return regmap_update_bits(output->data->regmap,
+ SI5341_OUT_MUX_SEL(output), 0x07, index);
+}
+
+static int si5341_output_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct clk_si5341_output *output = to_clk_si5341_output(hw);
+
+ if (index >= output->data->num_synth)
+ return -EINVAL;
+
+ return si5341_output_reparent(output, index);
+}
+
+static u8 si5341_output_get_parent(struct clk_hw *hw)
+{
+ struct clk_si5341_output *output = to_clk_si5341_output(hw);
+ int err;
+ u32 val;
+
+ err = regmap_read(output->data->regmap,
+ SI5341_OUT_MUX_SEL(output), &val);
+
+ return val & 0x7;
+}
+
+static const struct clk_ops si5341_output_clk_ops = {
+ .is_prepared = si5341_output_clk_is_on,
+ .prepare = si5341_output_clk_prepare,
+ .unprepare = si5341_output_clk_unprepare,
+ .recalc_rate = si5341_output_clk_recalc_rate,
+ .round_rate = si5341_output_clk_round_rate,
+ .set_rate = si5341_output_clk_set_rate,
+ .set_parent = si5341_output_set_parent,
+ .get_parent = si5341_output_get_parent,
+};
+
+/*
+ * The chip can be bought in a pre-programmed version, or one can program the
+ * NVM in the chip to boot up in a preset mode. This routine tries to determine
+ * if that's the case, or if we need to reset and program everything from
+ * scratch. Returns negative error, or true/false.
+ */
+static int si5341_is_programmed_already(struct clk_si5341 *data)
+{
+ int err;
+ u8 r[4];
+
+ /* Read the PLL divider value, it must have a non-zero value */
+ err = regmap_bulk_read(data->regmap, SI5341_PLL_M_DEN,
+ r, ARRAY_SIZE(r));
+ if (err < 0)
+ return err;
+
+ return !!get_unaligned_le32(r);
+}
+
+static struct clk_hw *
+of_clk_si5341_get(struct of_phandle_args *clkspec, void *_data)
+{
+ struct clk_si5341 *data = _data;
+ unsigned int idx = clkspec->args[1];
+ unsigned int group = clkspec->args[0];
+
+ switch (group) {
+ case 0:
+ if (idx >= data->num_outputs) {
+ dev_err(&data->i2c_client->dev,
+ "invalid output index %u\n", idx);
+ return ERR_PTR(-EINVAL);
+ }
+ return &data->clk[idx].hw;
+ case 1:
+ if (idx >= data->num_synth) {
+ dev_err(&data->i2c_client->dev,
+ "invalid synthesizer index %u\n", idx);
+ return ERR_PTR(-EINVAL);
+ }
+ return &data->synth[idx].hw;
+ case 2:
+ if (idx > 0) {
+ dev_err(&data->i2c_client->dev,
+ "invalid PLL index %u\n", idx);
+ return ERR_PTR(-EINVAL);
+ }
+ return &data->hw;
+ default:
+ dev_err(&data->i2c_client->dev, "invalid group %u\n", group);
+ return ERR_PTR(-EINVAL);
+ }
+}
+
+static int si5341_probe_chip_id(struct clk_si5341 *data)
+{
+ int err;
+ u8 reg[4];
+ u16 model;
+
+ err = regmap_bulk_read(data->regmap, SI5341_PN_BASE, reg,
+ ARRAY_SIZE(reg));
+ if (err < 0) {
+ dev_err(&data->i2c_client->dev, "Failed to read chip ID\n");
+ return err;
+ }
+
+ model = get_unaligned_le16(reg);
+
+ dev_info(&data->i2c_client->dev, "Chip: %x Grade: %u Rev: %u\n",
+ model, reg[2], reg[3]);
+
+ switch (model) {
+ case 0x5340:
+ data->num_outputs = SI5340_MAX_NUM_OUTPUTS;
+ data->num_synth = SI5340_NUM_SYNTH;
+ data->reg_output_offset = si5340_reg_output_offset;
+ data->reg_rdiv_offset = si5340_reg_rdiv_offset;
+ break;
+ case 0x5341:
+ data->num_outputs = SI5341_MAX_NUM_OUTPUTS;
+ data->num_synth = SI5341_NUM_SYNTH;
+ data->reg_output_offset = si5341_reg_output_offset;
+ data->reg_rdiv_offset = si5341_reg_rdiv_offset;
+ break;
+ default:
+ dev_err(&data->i2c_client->dev, "Model '%x' not supported\n",
+ model);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* Read active settings into the regmap cache for later reference */
+static int si5341_read_settings(struct clk_si5341 *data)
+{
+ int err;
+ u8 i;
+ u8 r[10];
+
+ err = regmap_bulk_read(data->regmap, SI5341_PLL_M_NUM, r, 10);
+ if (err < 0)
+ return err;
+
+ err = regmap_bulk_read(data->regmap,
+ SI5341_SYNTH_N_CLK_TO_OUTX_EN, r, 3);
+ if (err < 0)
+ return err;
+
+ err = regmap_bulk_read(data->regmap,
+ SI5341_SYNTH_N_CLK_DIS, r, 1);
+ if (err < 0)
+ return err;
+
+ for (i = 0; i < data->num_synth; ++i) {
+ err = regmap_bulk_read(data->regmap,
+ SI5341_SYNTH_N_NUM(i), r, 10);
+ if (err < 0)
+ return err;
+ }
+
+ for (i = 0; i < data->num_outputs; ++i) {
+ err = regmap_bulk_read(data->regmap,
+ data->reg_output_offset[i], r, 4);
+ if (err < 0)
+ return err;
+
+ err = regmap_bulk_read(data->regmap,
+ data->reg_rdiv_offset[i], r, 3);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int si5341_write_multiple(struct clk_si5341 *data,
+ const struct si5341_reg_default *values, unsigned int num_values)
+{
+ unsigned int i;
+ int res;
+
+ for (i = 0; i < num_values; ++i) {
+ res = regmap_write(data->regmap,
+ values[i].address, values[i].value);
+ if (res < 0) {
+ dev_err(&data->i2c_client->dev,
+ "Failed to write %#x:%#x\n",
+ values[i].address, values[i].value);
+ return res;
+ }
+ }
+
+ return 0;
+}
+
+static const struct si5341_reg_default si5341_preamble[] = {
+ { 0x0B25, 0x00 },
+ { 0x0502, 0x01 },
+ { 0x0505, 0x03 },
+ { 0x0957, 0x1F },
+ { 0x0B4E, 0x1A },
+};
+
+static int si5341_send_preamble(struct clk_si5341 *data)
+{
+ int res;
+ u32 revision;
+
+ /* For revision 2 and up, the values are slightly different */
+ res = regmap_read(data->regmap, SI5341_DEVICE_REV, &revision);
+ if (res < 0)
+ return res;
+
+ /* Write "preamble" as specified by datasheet */
+ res = regmap_write(data->regmap, 0xB24, revision < 2 ? 0xD8 : 0xC0);
+ if (res < 0)
+ return res;
+ res = si5341_write_multiple(data,
+ si5341_preamble, ARRAY_SIZE(si5341_preamble));
+ if (res < 0)
+ return res;
+
+ /* Datasheet specifies a 300ms wait after sending the preamble */
+ msleep(300);
+
+ return 0;
+}
+
+/* Perform a soft reset and write post-amble */
+static int si5341_finalize_defaults(struct clk_si5341 *data)
+{
+ int res;
+ u32 revision;
+
+ res = regmap_read(data->regmap, SI5341_DEVICE_REV, &revision);
+ if (res < 0)
+ return res;
+
+ dev_dbg(&data->i2c_client->dev, "%s rev=%u\n", __func__, revision);
+
+ res = regmap_write(data->regmap, SI5341_SOFT_RST, 0x01);
+ if (res < 0)
+ return res;
+
+ /* Datasheet does not explain these nameless registers */
+ res = regmap_write(data->regmap, 0xB24, revision < 2 ? 0xDB : 0xC3);
+ if (res < 0)
+ return res;
+ res = regmap_write(data->regmap, 0x0B25, 0x02);
+ if (res < 0)
+ return res;
+
+ return 0;
+}
+
+
+static const struct regmap_range si5341_regmap_volatile_range[] = {
+ regmap_reg_range(0x000C, 0x0012), /* Status */
+ regmap_reg_range(0x001C, 0x001E), /* reset, finc/fdec */
+ regmap_reg_range(0x00E2, 0x00FE), /* NVM, interrupts, device ready */
+ /* Update bits for synth config */
+ regmap_reg_range(SI5341_SYNTH_N_UPD(0), SI5341_SYNTH_N_UPD(0)),
+ regmap_reg_range(SI5341_SYNTH_N_UPD(1), SI5341_SYNTH_N_UPD(1)),
+ regmap_reg_range(SI5341_SYNTH_N_UPD(2), SI5341_SYNTH_N_UPD(2)),
+ regmap_reg_range(SI5341_SYNTH_N_UPD(3), SI5341_SYNTH_N_UPD(3)),
+ regmap_reg_range(SI5341_SYNTH_N_UPD(4), SI5341_SYNTH_N_UPD(4)),
+};
+
+static const struct regmap_access_table si5341_regmap_volatile = {
+ .yes_ranges = si5341_regmap_volatile_range,
+ .n_yes_ranges = ARRAY_SIZE(si5341_regmap_volatile_range),
+};
+
+/* Pages 0, 1, 2, 3, 9, A, B are valid, so there are 12 pages */
+static const struct regmap_range_cfg si5341_regmap_ranges[] = {
+ {
+ .range_min = 0,
+ .range_max = SI5341_REGISTER_MAX,
+ .selector_reg = SI5341_PAGE,
+ .selector_mask = 0xff,
+ .selector_shift = 0,
+ .window_start = 0,
+ .window_len = 256,
+ },
+};
+
+static const struct regmap_config si5341_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .cache_type = REGCACHE_RBTREE,
+ .ranges = si5341_regmap_ranges,
+ .num_ranges = ARRAY_SIZE(si5341_regmap_ranges),
+ .max_register = SI5341_REGISTER_MAX,
+ .volatile_table = &si5341_regmap_volatile,
+};
+
+static int si5341_dt_parse_dt(struct i2c_client *client,
+ struct clk_si5341_output_config *config)
+{
+ struct device_node *child;
+ struct device_node *np = client->dev.of_node;
+ u32 num;
+ u32 val;
+
+ memset(config, 0, sizeof(struct clk_si5341_output_config) *
+ SI5341_MAX_NUM_OUTPUTS);
+
+ for_each_child_of_node(np, child) {
+ if (of_property_read_u32(child, "reg", &num)) {
+ dev_err(&client->dev, "missing reg property of %s\n",
+ child->name);
+ goto put_child;
+ }
+
+ if (num >= SI5341_MAX_NUM_OUTPUTS) {
+ dev_err(&client->dev, "invalid clkout %d\n", num);
+ goto put_child;
+ }
+
+ if (!of_property_read_u32(child, "silabs,format", &val)) {
+ /* Set cm and ampl conservatively to 3v3 settings */
+ switch (val) {
+ case 1: /* normal differential */
+ config[num].out_cm_ampl_bits = 0x33;
+ break;
+ case 2: /* low-power differential */
+ config[num].out_cm_ampl_bits = 0x13;
+ break;
+ case 4: /* LVCMOS */
+ config[num].out_cm_ampl_bits = 0x33;
+ /* Set SI recommended impedance for LVCMOS */
+ config[num].out_format_drv_bits |= 0xc0;
+ break;
+ default:
+ dev_err(&client->dev,
+ "invalid silabs,format %u for %u\n",
+ val, num);
+ goto put_child;
+ }
+ config[num].out_format_drv_bits &= ~0x07;
+ config[num].out_format_drv_bits |= val & 0x07;
+ /* Always enable the SYNC feature */
+ config[num].out_format_drv_bits |= 0x08;
+ }
+
+ if (!of_property_read_u32(child, "silabs,common-mode", &val)) {
+ if (val > 0xf) {
+ dev_err(&client->dev,
+ "invalid silabs,common-mode %u\n",
+ val);
+ goto put_child;
+ }
+ config[num].out_cm_ampl_bits &= 0xf0;
+ config[num].out_cm_ampl_bits |= val & 0x0f;
+ }
+
+ if (!of_property_read_u32(child, "silabs,amplitude", &val)) {
+ if (val > 0xf) {
+ dev_err(&client->dev,
+ "invalid silabs,amplitude %u\n",
+ val);
+ goto put_child;
+ }
+ config[num].out_cm_ampl_bits &= 0x0f;
+ config[num].out_cm_ampl_bits |= (val << 4) & 0xf0;
+ }
+
+ if (of_property_read_bool(child, "silabs,disable-high"))
+ config[num].out_format_drv_bits |= 0x10;
+
+ config[num].synth_master =
+ of_property_read_bool(child, "silabs,synth-master");
+
+ config[num].always_on =
+ of_property_read_bool(child, "always-on");
+ }
+
+ return 0;
+
+put_child:
+ of_node_put(child);
+ return -EINVAL;
+}
+
+/*
+ * If not pre-configured, calculate and set the PLL configuration manually.
+ * For low-jitter performance, the PLL should be set such that the synthesizers
+ * only need integer division.
+ * Without any user guidance, we'll set the PLL to 14GHz, which still allows
+ * the chip to generate any frequency on its outputs, but jitter performance
+ * may be sub-optimal.
+ */
+static int si5341_initialize_pll(struct clk_si5341 *data)
+{
+ struct device_node *np = data->i2c_client->dev.of_node;
+ u32 m_num = 0;
+ u32 m_den = 0;
+
+ if (of_property_read_u32(np, "silabs,pll-m-num", &m_num)) {
+ dev_err(&data->i2c_client->dev,
+ "PLL configuration requires silabs,pll-m-num\n");
+ }
+ if (of_property_read_u32(np, "silabs,pll-m-den", &m_den)) {
+ dev_err(&data->i2c_client->dev,
+ "PLL configuration requires silabs,pll-m-den\n");
+ }
+
+ if (!m_num || !m_den) {
+ dev_err(&data->i2c_client->dev,
+ "PLL configuration invalid, assume 14GHz\n");
+ m_den = clk_get_rate(data->pxtal) / 10;
+ m_num = 1400000000;
+ }
+
+ return si5341_encode_44_32(data->regmap,
+ SI5341_PLL_M_NUM, m_num, m_den);
+}
+
+static int si5341_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct clk_si5341 *data;
+ struct clk_init_data init;
+ const char *root_clock_name;
+ const char *synth_clock_names[SI5341_NUM_SYNTH];
+ int err;
+ unsigned int i;
+ struct clk_si5341_output_config config[SI5341_MAX_NUM_OUTPUTS];
+ bool initialization_required;
+
+ data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->i2c_client = client;
+
+ data->pxtal = devm_clk_get(&client->dev, "xtal");
+ if (IS_ERR(data->pxtal)) {
+ if (PTR_ERR(data->pxtal) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ dev_err(&client->dev, "Missing xtal clock input\n");
+ }
+
+ err = si5341_dt_parse_dt(client, config);
+ if (err)
+ return err;
+
+ if (of_property_read_string(client->dev.of_node, "clock-output-names",
+ &init.name))
+ init.name = client->dev.of_node->name;
+ root_clock_name = init.name;
+
+ data->regmap = devm_regmap_init_i2c(client, &si5341_regmap_config);
+ if (IS_ERR(data->regmap))
+ return PTR_ERR(data->regmap);
+
+ i2c_set_clientdata(client, data);
+
+ err = si5341_probe_chip_id(data);
+ if (err < 0)
+ return err;
+
+ /* "Activate" the xtal (usually a fixed clock) */
+ clk_prepare_enable(data->pxtal);
+
+ if (of_property_read_bool(client->dev.of_node, "silabs,reprogram")) {
+ initialization_required = true;
+ } else {
+ err = si5341_is_programmed_already(data);
+ if (err < 0)
+ return err;
+
+ initialization_required = !err;
+ }
+
+ if (initialization_required) {
+ /* Populate the regmap cache in preparation for "cache only" */
+ err = si5341_read_settings(data);
+ if (err < 0)
+ return err;
+
+ err = si5341_send_preamble(data);
+ if (err < 0)
+ return err;
+
+ /*
+ * We intend to send all 'final' register values in a single
+ * transaction. So cache all register writes until we're done
+ * configuring.
+ */
+ regcache_cache_only(data->regmap, true);
+
+ /* Write the configuration pairs from the firmware blob */
+ err = si5341_write_multiple(data, si5341_reg_defaults,
+ ARRAY_SIZE(si5341_reg_defaults));
+ if (err < 0)
+ return err;
+
+ /* PLL configuration is required */
+ err = si5341_initialize_pll(data);
+ if (err < 0)
+ return err;
+ }
+
+ /* Register the PLL */
+ data->pxtal_name = __clk_get_name(data->pxtal);
+ init.parent_names = &data->pxtal_name;
+ init.num_parents = 1; /* For now, only XTAL input supported */
+ init.ops = &si5341_clk_ops;
+ init.flags = 0;
+ data->hw.init = &init;
+
+ err = devm_clk_hw_register(&client->dev, &data->hw);
+ if (err) {
+ dev_err(&client->dev, "clock registration failed\n");
+ return err;
+ }
+
+ init.num_parents = 1;
+ init.parent_names = &root_clock_name;
+ init.ops = &si5341_synth_clk_ops;
+ for (i = 0; i < data->num_synth; ++i) {
+ synth_clock_names[i] = devm_kasprintf(&client->dev, GFP_KERNEL,
+ "%s.N%u", client->dev.of_node->name, i);
+ init.name = synth_clock_names[i];
+ data->synth[i].index = i;
+ data->synth[i].data = data;
+ data->synth[i].hw.init = &init;
+ err = devm_clk_hw_register(&client->dev, &data->synth[i].hw);
+ if (err) {
+ dev_err(&client->dev,
+ "synth N%u registration failed\n", i);
+ }
+ }
+
+ init.num_parents = data->num_synth;
+ init.parent_names = synth_clock_names;
+ init.ops = &si5341_output_clk_ops;
+ for (i = 0; i < data->num_outputs; ++i) {
+ init.name = kasprintf(GFP_KERNEL, "%s.%d",
+ client->dev.of_node->name, i);
+ init.flags = config[i].synth_master ? CLK_SET_RATE_PARENT : 0;
+ data->clk[i].index = i;
+ data->clk[i].data = data;
+ data->clk[i].hw.init = &init;
+ if (config[i].out_format_drv_bits & 0x07) {
+ regmap_write(data->regmap,
+ SI5341_OUT_FORMAT(&data->clk[i]),
+ config[i].out_format_drv_bits);
+ regmap_write(data->regmap,
+ SI5341_OUT_CM(&data->clk[i]),
+ config[i].out_cm_ampl_bits);
+ }
+ err = devm_clk_hw_register(&client->dev, &data->clk[i].hw);
+ kfree(init.name); /* clock framework made a copy of the name */
+ if (err) {
+ dev_err(&client->dev,
+ "output %u registration failed\n", i);
+ return err;
+ }
+ if (config[i].always_on)
+ clk_prepare(data->clk[i].hw.clk);
+ }
+
+ err = of_clk_add_hw_provider(client->dev.of_node, of_clk_si5341_get,
+ data);
+ if (err) {
+ dev_err(&client->dev, "unable to add clk provider\n");
+ return err;
+ }
+
+ if (initialization_required) {
+ /* Synchronize */
+ regcache_cache_only(data->regmap, false);
+ err = regcache_sync(data->regmap);
+ if (err < 0)
+ return err;
+
+ err = si5341_finalize_defaults(data);
+ if (err < 0)
+ return err;
+ }
+
+ /* Free the names, clk framework makes copies */
+ for (i = 0; i < data->num_synth; ++i)
+ devm_kfree(&client->dev, (void *)synth_clock_names[i]);
+
+ return 0;
+}
+
+static const struct i2c_device_id si5341_id[] = {
+ { "si5340", 0 },
+ { "si5341", 1 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, si5341_id);
+
+static const struct of_device_id clk_si5341_of_match[] = {
+ { .compatible = "silabs,si5340" },
+ { .compatible = "silabs,si5341" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, clk_si5341_of_match);
+
+static struct i2c_driver si5341_driver = {
+ .driver = {
+ .name = "si5341",
+ .of_match_table = clk_si5341_of_match,
+ },
+ .probe = si5341_probe,
+ .id_table = si5341_id,
+};
+module_i2c_driver(si5341_driver);
+
+MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>");
+MODULE_DESCRIPTION("Si5341 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/clk-si544.c b/drivers/clk/clk-si544.c
index 64e607f3232a..d9ec9086184d 100644
--- a/drivers/clk/clk-si544.c
+++ b/drivers/clk/clk-si544.c
@@ -7,6 +7,7 @@
#include <linux/clk-provider.h>
#include <linux/delay.h>
+#include <linux/math64.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
@@ -50,6 +51,11 @@
/* Lowest frequency synthesizeable using only the HS divider */
#define MIN_HSDIV_FREQ (FVCO_MIN / HS_DIV_MAX)
+/* Range and interpretation of the adjustment value */
+#define DELTA_M_MAX 8161512
+#define DELTA_M_FRAC_NUM 19
+#define DELTA_M_FRAC_DEN 20000
+
enum si544_speed_grade {
si544a,
si544b,
@@ -71,12 +77,14 @@ struct clk_si544 {
* @hs_div: 1st divider, 5..2046, must be even when >33
* @ls_div_bits: 2nd divider, as 2^x, range 0..5
* If ls_div_bits is non-zero, hs_div must be even
+ * @delta_m: Frequency shift for small -950..+950 ppm changes, 24 bit
*/
struct clk_si544_muldiv {
u32 fb_div_frac;
u16 fb_div_int;
u16 hs_div;
u8 ls_div_bits;
+ s32 delta_m;
};
/* Enables or disables the output driver */
@@ -134,9 +142,30 @@ static int si544_get_muldiv(struct clk_si544 *data,
settings->fb_div_int = reg[4] | (reg[5] & 0x07) << 8;
settings->fb_div_frac = reg[0] | reg[1] << 8 | reg[2] << 16 |
reg[3] << 24;
+
+ err = regmap_bulk_read(data->regmap, SI544_REG_ADPLL_DELTA_M0, reg, 3);
+ if (err)
+ return err;
+
+ /* Interpret as 24-bit signed number */
+ settings->delta_m = reg[0] << 8 | reg[1] << 16 | reg[2] << 24;
+ settings->delta_m >>= 8;
+
return 0;
}
+static int si544_set_delta_m(struct clk_si544 *data, s32 delta_m)
+{
+ u8 reg[3];
+
+ reg[0] = delta_m;
+ reg[1] = delta_m >> 8;
+ reg[2] = delta_m >> 16;
+
+ return regmap_bulk_write(data->regmap, SI544_REG_ADPLL_DELTA_M0,
+ reg, 3);
+}
+
static int si544_set_muldiv(struct clk_si544 *data,
struct clk_si544_muldiv *settings)
{
@@ -238,11 +267,15 @@ static int si544_calc_muldiv(struct clk_si544_muldiv *settings,
do_div(vco, FXO);
settings->fb_div_frac = vco;
+ /* Reset the frequency adjustment */
+ settings->delta_m = 0;
+
return 0;
}
/* Calculate resulting frequency given the register settings */
-static unsigned long si544_calc_rate(struct clk_si544_muldiv *settings)
+static unsigned long si544_calc_center_rate(
+ const struct clk_si544_muldiv *settings)
{
u32 d = settings->hs_div * BIT(settings->ls_div_bits);
u64 vco;
@@ -261,6 +294,25 @@ static unsigned long si544_calc_rate(struct clk_si544_muldiv *settings)
return vco;
}
+static unsigned long si544_calc_rate(const struct clk_si544_muldiv *settings)
+{
+ unsigned long rate = si544_calc_center_rate(settings);
+ s64 delta = (s64)rate * (DELTA_M_FRAC_NUM * settings->delta_m);
+
+ /*
+ * The clock adjustment is much smaller than 1 Hz, round to the
+ * nearest multiple. Apparently div64_s64 rounds towards zero, hence
+ * check the sign and adjust into the proper direction.
+ */
+ if (settings->delta_m < 0)
+ delta -= ((s64)DELTA_M_MAX * DELTA_M_FRAC_DEN) / 2;
+ else
+ delta += ((s64)DELTA_M_MAX * DELTA_M_FRAC_DEN) / 2;
+ delta = div64_s64(delta, ((s64)DELTA_M_MAX * DELTA_M_FRAC_DEN));
+
+ return rate + delta;
+}
+
static unsigned long si544_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
@@ -279,33 +331,60 @@ static long si544_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
struct clk_si544 *data = to_clk_si544(hw);
- struct clk_si544_muldiv settings;
- int err;
if (!is_valid_frequency(data, rate))
return -EINVAL;
- err = si544_calc_muldiv(&settings, rate);
- if (err)
- return err;
+ /* The accuracy is less than 1 Hz, so any rate is possible */
+ return rate;
+}
- return si544_calc_rate(&settings);
+/* Calculates the maximum "small" change, 950 * rate / 1000000 */
+static unsigned long si544_max_delta(unsigned long rate)
+{
+ u64 num = rate;
+
+ num *= DELTA_M_FRAC_NUM;
+ do_div(num, DELTA_M_FRAC_DEN);
+
+ return num;
+}
+
+static s32 si544_calc_delta(s32 delta, s32 max_delta)
+{
+ s64 n = (s64)delta * DELTA_M_MAX;
+
+ return div_s64(n, max_delta);
}
-/*
- * Update output frequency for "big" frequency changes
- */
static int si544_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_si544 *data = to_clk_si544(hw);
struct clk_si544_muldiv settings;
+ unsigned long center;
+ long max_delta;
+ long delta;
unsigned int old_oe_state;
int err;
if (!is_valid_frequency(data, rate))
return -EINVAL;
+ /* Try using the frequency adjustment feature for a <= 950ppm change */
+ err = si544_get_muldiv(data, &settings);
+ if (err)
+ return err;
+
+ center = si544_calc_center_rate(&settings);
+ max_delta = si544_max_delta(center);
+ delta = rate - center;
+
+ if (abs(delta) <= max_delta)
+ return si544_set_delta_m(data,
+ si544_calc_delta(delta, max_delta));
+
+ /* Too big for the delta adjustment, need to reprogram */
err = si544_calc_muldiv(&settings, rate);
if (err)
return err;
@@ -321,6 +400,9 @@ static int si544_set_rate(struct clk_hw *hw, unsigned long rate,
if (err < 0)
return err;
+ err = si544_set_delta_m(data, settings.delta_m);
+ if (err < 0)
+ return err;
err = si544_set_muldiv(data, &settings);
if (err < 0)
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index aa51756fd4d6..c0990703ce54 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -368,7 +368,7 @@ static struct clk_core *clk_core_get(struct clk_core *core, u8 p_index)
const char *dev_id = dev ? dev_name(dev) : NULL;
struct device_node *np = core->of_node;
- if (np && index >= 0)
+ if (np && (name || index >= 0))
hw = of_clk_get_hw(np, index, name);
/*
@@ -1324,10 +1324,7 @@ static void clk_core_init_rate_req(struct clk_core * const core,
static bool clk_core_can_round(struct clk_core * const core)
{
- if (core->ops->determine_rate || core->ops->round_rate)
- return true;
-
- return false;
+ return core->ops->determine_rate || core->ops->round_rate;
}
static int clk_core_round_rate_nolock(struct clk_core *core,
@@ -2194,7 +2191,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
EXPORT_SYMBOL_GPL(clk_set_rate);
/**
- * clk_set_rate_exclusive - specify a new rate get exclusive control
+ * clk_set_rate_exclusive - specify a new rate and get exclusive control
* @clk: the clk whose rate is being changed
* @rate: the new rate for clk
*
@@ -2202,7 +2199,7 @@ EXPORT_SYMBOL_GPL(clk_set_rate);
* within a critical section
*
* This can be used initially to ensure that at least 1 consumer is
- * statisfied when several consumers are competing for exclusivity over the
+ * satisfied when several consumers are competing for exclusivity over the
* same clock provider.
*
* The exclusivity is not applied if setting the rate failed.
@@ -2997,20 +2994,65 @@ static int clk_flags_show(struct seq_file *s, void *data)
}
DEFINE_SHOW_ATTRIBUTE(clk_flags);
+static void possible_parent_show(struct seq_file *s, struct clk_core *core,
+ unsigned int i, char terminator)
+{
+ struct clk_core *parent;
+
+ /*
+ * Go through the following options to fetch a parent's name.
+ *
+ * 1. Fetch the registered parent clock and use its name
+ * 2. Use the global (fallback) name if specified
+ * 3. Use the local fw_name if provided
+ * 4. Fetch parent clock's clock-output-name if DT index was set
+ *
+ * This may still fail in some cases, such as when the parent is
+ * specified directly via a struct clk_hw pointer, but it isn't
+ * registered (yet).
+ */
+ parent = clk_core_get_parent_by_index(core, i);
+ if (parent)
+ seq_printf(s, "%s", parent->name);
+ else if (core->parents[i].name)
+ seq_printf(s, "%s", core->parents[i].name);
+ else if (core->parents[i].fw_name)
+ seq_printf(s, "<%s>(fw)", core->parents[i].fw_name);
+ else if (core->parents[i].index >= 0)
+ seq_printf(s, "%s",
+ of_clk_get_parent_name(core->of_node,
+ core->parents[i].index));
+ else
+ seq_puts(s, "(missing)");
+
+ seq_putc(s, terminator);
+}
+
static int possible_parents_show(struct seq_file *s, void *data)
{
struct clk_core *core = s->private;
int i;
for (i = 0; i < core->num_parents - 1; i++)
- seq_printf(s, "%s ", core->parents[i].name);
+ possible_parent_show(s, core, i, ' ');
- seq_printf(s, "%s\n", core->parents[i].name);
+ possible_parent_show(s, core, i, '\n');
return 0;
}
DEFINE_SHOW_ATTRIBUTE(possible_parents);
+static int current_parent_show(struct seq_file *s, void *data)
+{
+ struct clk_core *core = s->private;
+
+ if (core->parent)
+ seq_printf(s, "%s\n", core->parent->name);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(current_parent);
+
static int clk_duty_cycle_show(struct seq_file *s, void *data)
{
struct clk_core *core = s->private;
@@ -3043,6 +3085,10 @@ static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
debugfs_create_file("clk_duty_cycle", 0444, root, core,
&clk_duty_cycle_fops);
+ if (core->num_parents > 0)
+ debugfs_create_file("clk_parent", 0444, root, core,
+ &current_parent_fops);
+
if (core->num_parents > 1)
debugfs_create_file("clk_possible_parents", 0444, root, core,
&possible_parents_fops);
@@ -4038,6 +4084,7 @@ struct of_clk_provider {
void *data;
};
+extern struct of_device_id __clk_of_table;
static const struct of_device_id __clk_of_table_sentinel
__used __section(__clk_of_table_end);
diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h
index d8400d623b34..2d801900cad5 100644
--- a/drivers/clk/clk.h
+++ b/drivers/clk/clk.h
@@ -33,10 +33,6 @@ clk_hw_create_clk(struct device *dev, struct clk_hw *hw, const char *dev_id,
{
return (struct clk *)hw;
}
-static struct clk_hw *__clk_get_hw(struct clk *clk)
-{
- return (struct clk_hw *)clk;
-}
static inline void __clk_put(struct clk *clk) { }
#endif
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index 2afc8df8acff..0f2e3fcf0f19 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/clk/clkdev.c
*
* Copyright (C) 2008 Russell King.
*
- * 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.
- *
* Helper for the clk API to assist looking up a struct clk.
*/
#include <linux/module.h>
diff --git a/drivers/clk/hisilicon/clk-hi6220-stub.c b/drivers/clk/hisilicon/clk-hi6220-stub.c
index 329a09214d12..4fdee4424d82 100644
--- a/drivers/clk/hisilicon/clk-hi6220-stub.c
+++ b/drivers/clk/hisilicon/clk-hi6220-stub.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Hi6220 stub clock driver
*
@@ -5,11 +6,6 @@
* Copyright (c) 2015 Linaro Limited.
*
* Author: Leo Yan <leo.yan@linaro.org>
- *
- * 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.
- *
*/
#include <linux/clk-provider.h>
diff --git a/drivers/clk/hisilicon/clk-hi6220.c b/drivers/clk/hisilicon/clk-hi6220.c
index a87809d4bd52..b2c5b6bbb1c1 100644
--- a/drivers/clk/hisilicon/clk-hi6220.c
+++ b/drivers/clk/hisilicon/clk-hi6220.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Hisilicon Hi6220 clock driver
*
* Copyright (c) 2015 Hisilicon Limited.
*
* Author: Bintian Wang <bintian.wang@huawei.com>
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/clk/hisilicon/clkdivider-hi6220.c b/drivers/clk/hisilicon/clkdivider-hi6220.c
index 9f46cf9dcc65..5348bafe694f 100644
--- a/drivers/clk/hisilicon/clkdivider-hi6220.c
+++ b/drivers/clk/hisilicon/clkdivider-hi6220.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Hisilicon hi6220 SoC divider clock driver
*
* Copyright (c) 2015 Hisilicon Limited.
*
* Author: Bintian Wang <bintian.wang@huawei.com>
- *
- * 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.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/clk/imx/clk-busy.c b/drivers/clk/imx/clk-busy.c
index 7b35a11238ca..25c863da32c7 100644
--- a/drivers/clk/imx/clk-busy.c
+++ b/drivers/clk/imx/clk-busy.c
@@ -72,13 +72,14 @@ static const struct clk_ops clk_busy_divider_ops = {
.set_rate = clk_busy_divider_set_rate,
};
-struct clk *imx_clk_busy_divider(const char *name, const char *parent_name,
+struct clk_hw *imx_clk_hw_busy_divider(const char *name, const char *parent_name,
void __iomem *reg, u8 shift, u8 width,
void __iomem *busy_reg, u8 busy_shift)
{
struct clk_busy_divider *busy;
- struct clk *clk;
+ struct clk_hw *hw;
struct clk_init_data init;
+ int ret;
busy = kzalloc(sizeof(*busy), GFP_KERNEL);
if (!busy)
@@ -101,11 +102,15 @@ struct clk *imx_clk_busy_divider(const char *name, const char *parent_name,
busy->div.hw.init = &init;
- clk = clk_register(NULL, &busy->div.hw);
- if (IS_ERR(clk))
+ hw = &busy->div.hw;
+
+ ret = clk_hw_register(NULL, hw);
+ if (ret) {
kfree(busy);
+ return ERR_PTR(ret);
+ }
- return clk;
+ return hw;
}
struct clk_busy_mux {
@@ -146,13 +151,14 @@ static const struct clk_ops clk_busy_mux_ops = {
.set_parent = clk_busy_mux_set_parent,
};
-struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift,
+struct clk_hw *imx_clk_hw_busy_mux(const char *name, void __iomem *reg, u8 shift,
u8 width, void __iomem *busy_reg, u8 busy_shift,
const char * const *parent_names, int num_parents)
{
struct clk_busy_mux *busy;
- struct clk *clk;
+ struct clk_hw *hw;
struct clk_init_data init;
+ int ret;
busy = kzalloc(sizeof(*busy), GFP_KERNEL);
if (!busy)
@@ -175,9 +181,13 @@ struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift,
busy->mux.hw.init = &init;
- clk = clk_register(NULL, &busy->mux.hw);
- if (IS_ERR(clk))
+ hw = &busy->mux.hw;
+
+ ret = clk_hw_register(NULL, hw);
+ if (ret) {
kfree(busy);
+ return ERR_PTR(ret);
+ }
- return clk;
+ return hw;
}
diff --git a/drivers/clk/imx/clk-cpu.c b/drivers/clk/imx/clk-cpu.c
index ed1b7e97a0d3..cb182bec79ba 100644
--- a/drivers/clk/imx/clk-cpu.c
+++ b/drivers/clk/imx/clk-cpu.c
@@ -1,12 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014 Lucas Stach <l.stach@pengutronix.de>, Pengutronix
- *
- * 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.
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
*/
#include <linux/clk.h>
@@ -75,13 +69,14 @@ static const struct clk_ops clk_cpu_ops = {
.set_rate = clk_cpu_set_rate,
};
-struct clk *imx_clk_cpu(const char *name, const char *parent_name,
+struct clk_hw *imx_clk_hw_cpu(const char *name, const char *parent_name,
struct clk *div, struct clk *mux, struct clk *pll,
struct clk *step)
{
struct clk_cpu *cpu;
- struct clk *clk;
+ struct clk_hw *hw;
struct clk_init_data init;
+ int ret;
cpu = kzalloc(sizeof(*cpu), GFP_KERNEL);
if (!cpu)
@@ -99,10 +94,13 @@ struct clk *imx_clk_cpu(const char *name, const char *parent_name,
init.num_parents = 1;
cpu->hw.init = &init;
+ hw = &cpu->hw;
- clk = clk_register(NULL, &cpu->hw);
- if (IS_ERR(clk))
+ ret = clk_hw_register(NULL, hw);
+ if (ret) {
kfree(cpu);
+ return ERR_PTR(ret);
+ }
- return clk;
+ return hw;
}
diff --git a/drivers/clk/imx/clk-fixup-div.c b/drivers/clk/imx/clk-fixup-div.c
index bab46c6fd3db..4b17b91504ed 100644
--- a/drivers/clk/imx/clk-fixup-div.c
+++ b/drivers/clk/imx/clk-fixup-div.c
@@ -85,13 +85,14 @@ static const struct clk_ops clk_fixup_div_ops = {
.set_rate = clk_fixup_div_set_rate,
};
-struct clk *imx_clk_fixup_divider(const char *name, const char *parent,
+struct clk_hw *imx_clk_hw_fixup_divider(const char *name, const char *parent,
void __iomem *reg, u8 shift, u8 width,
void (*fixup)(u32 *val))
{
struct clk_fixup_div *fixup_div;
- struct clk *clk;
+ struct clk_hw *hw;
struct clk_init_data init;
+ int ret;
if (!fixup)
return ERR_PTR(-EINVAL);
@@ -114,9 +115,13 @@ struct clk *imx_clk_fixup_divider(const char *name, const char *parent,
fixup_div->ops = &clk_divider_ops;
fixup_div->fixup = fixup;
- clk = clk_register(NULL, &fixup_div->divider.hw);
- if (IS_ERR(clk))
+ hw = &fixup_div->divider.hw;
+
+ ret = clk_hw_register(NULL, hw);
+ if (ret) {
kfree(fixup_div);
+ return ERR_PTR(ret);
+ }
- return clk;
+ return hw;
}
diff --git a/drivers/clk/imx/clk-fixup-mux.c b/drivers/clk/imx/clk-fixup-mux.c
index 1aa3e8d9abf3..b569d919c645 100644
--- a/drivers/clk/imx/clk-fixup-mux.c
+++ b/drivers/clk/imx/clk-fixup-mux.c
@@ -63,13 +63,14 @@ static const struct clk_ops clk_fixup_mux_ops = {
.set_parent = clk_fixup_mux_set_parent,
};
-struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg,
+struct clk_hw *imx_clk_hw_fixup_mux(const char *name, void __iomem *reg,
u8 shift, u8 width, const char * const *parents,
int num_parents, void (*fixup)(u32 *val))
{
struct clk_fixup_mux *fixup_mux;
- struct clk *clk;
+ struct clk_hw *hw;
struct clk_init_data init;
+ int ret;
if (!fixup)
return ERR_PTR(-EINVAL);
@@ -92,9 +93,13 @@ struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg,
fixup_mux->ops = &clk_mux_ops;
fixup_mux->fixup = fixup;
- clk = clk_register(NULL, &fixup_mux->mux.hw);
- if (IS_ERR(clk))
+ hw = &fixup_mux->mux.hw;
+
+ ret = clk_hw_register(NULL, hw);
+ if (ret) {
kfree(fixup_mux);
+ return ERR_PTR(ret);
+ }
- return clk;
+ return hw;
}
diff --git a/drivers/clk/imx/clk-gate-exclusive.c b/drivers/clk/imx/clk-gate-exclusive.c
index 3bd9dee618b2..77342893bb71 100644
--- a/drivers/clk/imx/clk-gate-exclusive.c
+++ b/drivers/clk/imx/clk-gate-exclusive.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2014 Freescale Semiconductor, 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.
*/
#include <linux/clk-provider.h>
@@ -58,13 +55,14 @@ static const struct clk_ops clk_gate_exclusive_ops = {
.is_enabled = clk_gate_exclusive_is_enabled,
};
-struct clk *imx_clk_gate_exclusive(const char *name, const char *parent,
+struct clk_hw *imx_clk_hw_gate_exclusive(const char *name, const char *parent,
void __iomem *reg, u8 shift, u32 exclusive_mask)
{
struct clk_gate_exclusive *exgate;
struct clk_gate *gate;
- struct clk *clk;
+ struct clk_hw *hw;
struct clk_init_data init;
+ int ret;
if (exclusive_mask == 0)
return ERR_PTR(-EINVAL);
@@ -86,9 +84,13 @@ struct clk *imx_clk_gate_exclusive(const char *name, const char *parent,
gate->hw.init = &init;
exgate->exclusive_mask = exclusive_mask;
- clk = clk_register(NULL, &gate->hw);
- if (IS_ERR(clk))
- kfree(exgate);
+ hw = &gate->hw;
+
+ ret = clk_hw_register(NULL, hw);
+ if (ret) {
+ kfree(gate);
+ return ERR_PTR(ret);
+ }
- return clk;
+ return hw;
}
diff --git a/drivers/clk/imx/clk-gate2.c b/drivers/clk/imx/clk-gate2.c
index 60fc9d7a9723..7d44ce814806 100644
--- a/drivers/clk/imx/clk-gate2.c
+++ b/drivers/clk/imx/clk-gate2.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
* Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
*
- * 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.
- *
* Gated clock implementation
*/
@@ -125,15 +122,16 @@ static const struct clk_ops clk_gate2_ops = {
.is_enabled = clk_gate2_is_enabled,
};
-struct clk *clk_register_gate2(struct device *dev, const char *name,
+struct clk_hw *clk_hw_register_gate2(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 bit_idx, u8 cgr_val,
u8 clk_gate2_flags, spinlock_t *lock,
unsigned int *share_count)
{
struct clk_gate2 *gate;
- struct clk *clk;
+ struct clk_hw *hw;
struct clk_init_data init;
+ int ret;
gate = kzalloc(sizeof(struct clk_gate2), GFP_KERNEL);
if (!gate)
@@ -154,10 +152,13 @@ struct clk *clk_register_gate2(struct device *dev, const char *name,
init.num_parents = parent_name ? 1 : 0;
gate->hw.init = &init;
+ hw = &gate->hw;
- clk = clk_register(dev, &gate->hw);
- if (IS_ERR(clk))
+ ret = clk_hw_register(NULL, hw);
+ if (ret) {
kfree(gate);
+ return ERR_PTR(ret);
+ }
- return clk;
+ return hw;
}
diff --git a/drivers/clk/imx/clk-imx35.c b/drivers/clk/imx/clk-imx35.c
index 203cad6c9aab..e595f559907f 100644
--- a/drivers/clk/imx/clk-imx35.c
+++ b/drivers/clk/imx/clk-imx35.c
@@ -1,10 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
- *
- * 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.
- *
*/
#include <linux/mm.h>
#include <linux/delay.h>
diff --git a/drivers/clk/imx/clk-imx5.c b/drivers/clk/imx/clk-imx5.c
index c85ebd74a8a5..01e079b81026 100644
--- a/drivers/clk/imx/clk-imx5.c
+++ b/drivers/clk/imx/clk-imx5.c
@@ -1,10 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
- *
- * 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.
- *
*/
#include <linux/mm.h>
#include <linux/delay.h>
diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c
index d5de733f336e..60f2de851f39 100644
--- a/drivers/clk/imx/clk-imx6q.c
+++ b/drivers/clk/imx/clk-imx6q.c
@@ -8,6 +8,7 @@
#include <linux/types.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/of.h>
@@ -87,8 +88,8 @@ static const char *pll5_bypass_sels[] = { "pll5", "pll5_bypass_src", };
static const char *pll6_bypass_sels[] = { "pll6", "pll6_bypass_src", };
static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", };
-static struct clk *clk[IMX6QDL_CLK_END];
-static struct clk_onecell_data clk_data;
+static struct clk_hw **hws;
+static struct clk_hw_onecell_data *clk_hw_data;
static struct clk_div_table clk_enet_ref_table[] = {
{ .val = 0, .div = 20, },
@@ -138,12 +139,13 @@ static inline int clk_on_imx6dl(void)
return of_machine_is_compatible("fsl,imx6dl");
}
-static struct clk ** const uart_clks[] __initconst = {
- &clk[IMX6QDL_CLK_UART_IPG],
- &clk[IMX6QDL_CLK_UART_SERIAL],
- NULL
+static const int uart_clk_ids[] __initconst = {
+ IMX6QDL_CLK_UART_IPG,
+ IMX6QDL_CLK_UART_SERIAL,
};
+static struct clk **uart_clks[ARRAY_SIZE(uart_clk_ids) + 1] __initdata;
+
static int ldb_di_sel_by_clock_id(int clock_id)
{
switch (clock_id) {
@@ -254,25 +256,14 @@ static bool pll6_bypassed(struct device_node *node)
return false;
}
-#define CCM_CCDR 0x04
#define CCM_CCSR 0x0c
#define CCM_CS2CDR 0x2c
-#define CCDR_MMDC_CH1_MASK BIT(16)
#define CCSR_PLL3_SW_CLK_SEL BIT(0)
#define CS2CDR_LDB_DI0_CLK_SEL_SHIFT 9
#define CS2CDR_LDB_DI1_CLK_SEL_SHIFT 12
-static void __init imx6q_mmdc_ch1_mask_handshake(void __iomem *ccm_base)
-{
- unsigned int reg;
-
- reg = readl_relaxed(ccm_base + CCM_CCDR);
- reg |= CCDR_MMDC_CH1_MASK;
- writel_relaxed(reg, ccm_base + CCM_CCDR);
-}
-
/*
* The only way to disable the MMDC_CH1 clock is to move it to pll3_sw_clk
* via periph2_clk2_sel and then to disable pll3_sw_clk by selecting the
@@ -282,14 +273,8 @@ static void mmdc_ch1_disable(void __iomem *ccm_base)
{
unsigned int reg;
- clk_set_parent(clk[IMX6QDL_CLK_PERIPH2_CLK2_SEL],
- clk[IMX6QDL_CLK_PLL3_USB_OTG]);
-
- /*
- * Handshake with mmdc_ch1 module must be masked when changing
- * periph2_clk_sel.
- */
- clk_set_parent(clk[IMX6QDL_CLK_PERIPH2], clk[IMX6QDL_CLK_PERIPH2_CLK2]);
+ clk_set_parent(hws[IMX6QDL_CLK_PERIPH2_CLK2_SEL]->clk,
+ hws[IMX6QDL_CLK_PLL3_USB_OTG]->clk);
/* Disable pll3_sw_clk by selecting the bypass clock source */
reg = readl_relaxed(ccm_base + CCM_CCSR);
@@ -305,8 +290,6 @@ static void mmdc_ch1_reenable(void __iomem *ccm_base)
reg = readl_relaxed(ccm_base + CCM_CCSR);
reg &= ~CCSR_PLL3_SW_CLK_SEL;
writel_relaxed(reg, ccm_base + CCM_CCSR);
-
- clk_set_parent(clk[IMX6QDL_CLK_PERIPH2], clk[IMX6QDL_CLK_PERIPH2_PRE]);
}
/*
@@ -365,8 +348,8 @@ static void init_ldb_clks(struct device_node *np, void __iomem *ccm_base)
/* Only switch to or from pll2_pfd2_396m if it is disabled */
if ((sel[i][0] == 2 || sel[i][3] == 2) &&
- (clk_get_parent(clk[IMX6QDL_CLK_PERIPH_PRE]) ==
- clk[IMX6QDL_CLK_PLL2_PFD2_396M])) {
+ (clk_get_parent(hws[IMX6QDL_CLK_PERIPH_PRE]->clk) ==
+ hws[IMX6QDL_CLK_PLL2_PFD2_396M]->clk)) {
pr_err("ccm: ldb_di%d_sel: couldn't disable pll2_pfd2_396m\n",
i);
sel[i][3] = sel[i][2] = sel[i][1] = sel[i][0];
@@ -418,8 +401,8 @@ static void disable_anatop_clocks(void __iomem *anatop_base)
/* Make sure PLL2 PFDs 0-2 are gated */
reg = readl_relaxed(anatop_base + CCM_ANALOG_PFD_528);
/* Cannot gate PFD2 if pll2_pfd2_396m is the parent of MMDC clock */
- if (clk_get_parent(clk[IMX6QDL_CLK_PERIPH_PRE]) ==
- clk[IMX6QDL_CLK_PLL2_PFD2_396M])
+ if (clk_get_parent(hws[IMX6QDL_CLK_PERIPH_PRE]->clk) ==
+ hws[IMX6QDL_CLK_PLL2_PFD2_396M]->clk)
reg |= PFD0_CLKGATE | PFD1_CLKGATE;
else
reg |= PFD0_CLKGATE | PFD1_CLKGATE | PFD2_CLKGATE;
@@ -436,31 +419,45 @@ static void disable_anatop_clocks(void __iomem *anatop_base)
writel_relaxed(reg, anatop_base + CCM_ANALOG_PLL_VIDEO);
}
+static struct clk_hw * __init imx6q_obtain_fixed_clk_hw(struct device_node *np,
+ const char *name,
+ unsigned long rate)
+{
+ struct clk *clk = of_clk_get_by_name(np, name);
+ struct clk_hw *hw;
+
+ if (IS_ERR(clk))
+ hw = imx_obtain_fixed_clock_hw(name, rate);
+ else
+ hw = __clk_get_hw(clk);
+
+ return hw;
+}
+
static void __init imx6q_clocks_init(struct device_node *ccm_node)
{
struct device_node *np;
void __iomem *anatop_base, *base;
int ret;
+ int i;
+
+ clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
+ IMX6QDL_CLK_END), GFP_KERNEL);
+ if (WARN_ON(!clk_hw_data))
+ return;
- clk[IMX6QDL_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
- clk[IMX6QDL_CLK_CKIL] = of_clk_get_by_name(ccm_node, "ckil");
- if (IS_ERR(clk[IMX6QDL_CLK_CKIL]))
- clk[IMX6QDL_CLK_CKIL] = imx_obtain_fixed_clock("ckil", 0);
- clk[IMX6QDL_CLK_CKIH] = of_clk_get_by_name(ccm_node, "ckih1");
- if (IS_ERR(clk[IMX6QDL_CLK_CKIH]))
- clk[IMX6QDL_CLK_CKIH] = imx_obtain_fixed_clock("ckih1", 0);
- clk[IMX6QDL_CLK_OSC] = of_clk_get_by_name(ccm_node, "osc");
- if (IS_ERR(clk[IMX6QDL_CLK_OSC]))
- clk[IMX6QDL_CLK_OSC] = imx_obtain_fixed_clock("osc", 0);
+ clk_hw_data->num = IMX6QDL_CLK_END;
+ hws = clk_hw_data->hws;
- /* Clock source from external clock via CLK1/2 PADs */
- clk[IMX6QDL_CLK_ANACLK1] = of_clk_get_by_name(ccm_node, "anaclk1");
- if (IS_ERR(clk[IMX6QDL_CLK_ANACLK1]))
- clk[IMX6QDL_CLK_ANACLK1] = imx_obtain_fixed_clock("anaclk1", 0);
+ hws[IMX6QDL_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
- clk[IMX6QDL_CLK_ANACLK2] = of_clk_get_by_name(ccm_node, "anaclk2");
- if (IS_ERR(clk[IMX6QDL_CLK_ANACLK2]))
- clk[IMX6QDL_CLK_ANACLK2] = imx_obtain_fixed_clock("anaclk2", 0);
+ hws[IMX6QDL_CLK_CKIL] = imx6q_obtain_fixed_clk_hw(ccm_node, "ckil", 0);
+ hws[IMX6QDL_CLK_CKIH] = imx6q_obtain_fixed_clk_hw(ccm_node, "ckih1", 0);
+ hws[IMX6QDL_CLK_OSC] = imx6q_obtain_fixed_clk_hw(ccm_node, "osc", 0);
+
+ /* Clock source from external clock via CLK1/2 PADs */
+ hws[IMX6QDL_CLK_ANACLK1] = imx6q_obtain_fixed_clk_hw(ccm_node, "anaclk1", 0);
+ hws[IMX6QDL_CLK_ANACLK2] = imx6q_obtain_fixed_clk_hw(ccm_node, "anaclk2", 0);
np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
anatop_base = base = of_iomap(np, 0);
@@ -475,47 +472,47 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
video_div_table[3].div = 1;
}
- clk[IMX6QDL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
- clk[IMX6QDL_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
- clk[IMX6QDL_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
- clk[IMX6QDL_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
- clk[IMX6QDL_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
- clk[IMX6QDL_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
- clk[IMX6QDL_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6QDL_PLL1_BYPASS_SRC] = imx_clk_hw_mux("pll1_bypass_src", base + 0x00, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6QDL_PLL2_BYPASS_SRC] = imx_clk_hw_mux("pll2_bypass_src", base + 0x30, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6QDL_PLL3_BYPASS_SRC] = imx_clk_hw_mux("pll3_bypass_src", base + 0x10, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6QDL_PLL4_BYPASS_SRC] = imx_clk_hw_mux("pll4_bypass_src", base + 0x70, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6QDL_PLL5_BYPASS_SRC] = imx_clk_hw_mux("pll5_bypass_src", base + 0xa0, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6QDL_PLL6_BYPASS_SRC] = imx_clk_hw_mux("pll6_bypass_src", base + 0xe0, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6QDL_PLL7_BYPASS_SRC] = imx_clk_hw_mux("pll7_bypass_src", base + 0x20, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
/* type name parent_name base div_mask */
- clk[IMX6QDL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "osc", base + 0x00, 0x7f);
- clk[IMX6QDL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
- clk[IMX6QDL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "osc", base + 0x10, 0x3);
- clk[IMX6QDL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "osc", base + 0x70, 0x7f);
- clk[IMX6QDL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "osc", base + 0xa0, 0x7f);
- clk[IMX6QDL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "osc", base + 0xe0, 0x3);
- clk[IMX6QDL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "osc", base + 0x20, 0x3);
-
- clk[IMX6QDL_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
- clk[IMX6QDL_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
- clk[IMX6QDL_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
- clk[IMX6QDL_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
- clk[IMX6QDL_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
- clk[IMX6QDL_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
- clk[IMX6QDL_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6QDL_CLK_PLL1] = imx_clk_hw_pllv3(IMX_PLLV3_SYS, "pll1", "osc", base + 0x00, 0x7f);
+ hws[IMX6QDL_CLK_PLL2] = imx_clk_hw_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
+ hws[IMX6QDL_CLK_PLL3] = imx_clk_hw_pllv3(IMX_PLLV3_USB, "pll3", "osc", base + 0x10, 0x3);
+ hws[IMX6QDL_CLK_PLL4] = imx_clk_hw_pllv3(IMX_PLLV3_AV, "pll4", "osc", base + 0x70, 0x7f);
+ hws[IMX6QDL_CLK_PLL5] = imx_clk_hw_pllv3(IMX_PLLV3_AV, "pll5", "osc", base + 0xa0, 0x7f);
+ hws[IMX6QDL_CLK_PLL6] = imx_clk_hw_pllv3(IMX_PLLV3_ENET, "pll6", "osc", base + 0xe0, 0x3);
+ hws[IMX6QDL_CLK_PLL7] = imx_clk_hw_pllv3(IMX_PLLV3_USB, "pll7", "osc", base + 0x20, 0x3);
+
+ hws[IMX6QDL_PLL1_BYPASS] = imx_clk_hw_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6QDL_PLL2_BYPASS] = imx_clk_hw_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6QDL_PLL3_BYPASS] = imx_clk_hw_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6QDL_PLL4_BYPASS] = imx_clk_hw_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6QDL_PLL5_BYPASS] = imx_clk_hw_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6QDL_PLL6_BYPASS] = imx_clk_hw_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6QDL_PLL7_BYPASS] = imx_clk_hw_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
/* Do not bypass PLLs initially */
- clk_set_parent(clk[IMX6QDL_PLL1_BYPASS], clk[IMX6QDL_CLK_PLL1]);
- clk_set_parent(clk[IMX6QDL_PLL2_BYPASS], clk[IMX6QDL_CLK_PLL2]);
- clk_set_parent(clk[IMX6QDL_PLL3_BYPASS], clk[IMX6QDL_CLK_PLL3]);
- clk_set_parent(clk[IMX6QDL_PLL4_BYPASS], clk[IMX6QDL_CLK_PLL4]);
- clk_set_parent(clk[IMX6QDL_PLL5_BYPASS], clk[IMX6QDL_CLK_PLL5]);
- clk_set_parent(clk[IMX6QDL_PLL6_BYPASS], clk[IMX6QDL_CLK_PLL6]);
- clk_set_parent(clk[IMX6QDL_PLL7_BYPASS], clk[IMX6QDL_CLK_PLL7]);
-
- clk[IMX6QDL_CLK_PLL1_SYS] = imx_clk_gate("pll1_sys", "pll1_bypass", base + 0x00, 13);
- clk[IMX6QDL_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", base + 0x30, 13);
- clk[IMX6QDL_CLK_PLL3_USB_OTG] = imx_clk_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13);
- clk[IMX6QDL_CLK_PLL4_AUDIO] = imx_clk_gate("pll4_audio", "pll4_bypass", base + 0x70, 13);
- clk[IMX6QDL_CLK_PLL5_VIDEO] = imx_clk_gate("pll5_video", "pll5_bypass", base + 0xa0, 13);
- clk[IMX6QDL_CLK_PLL6_ENET] = imx_clk_gate("pll6_enet", "pll6_bypass", base + 0xe0, 13);
- clk[IMX6QDL_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
+ clk_set_parent(hws[IMX6QDL_PLL1_BYPASS]->clk, hws[IMX6QDL_CLK_PLL1]->clk);
+ clk_set_parent(hws[IMX6QDL_PLL2_BYPASS]->clk, hws[IMX6QDL_CLK_PLL2]->clk);
+ clk_set_parent(hws[IMX6QDL_PLL3_BYPASS]->clk, hws[IMX6QDL_CLK_PLL3]->clk);
+ clk_set_parent(hws[IMX6QDL_PLL4_BYPASS]->clk, hws[IMX6QDL_CLK_PLL4]->clk);
+ clk_set_parent(hws[IMX6QDL_PLL5_BYPASS]->clk, hws[IMX6QDL_CLK_PLL5]->clk);
+ clk_set_parent(hws[IMX6QDL_PLL6_BYPASS]->clk, hws[IMX6QDL_CLK_PLL6]->clk);
+ clk_set_parent(hws[IMX6QDL_PLL7_BYPASS]->clk, hws[IMX6QDL_CLK_PLL7]->clk);
+
+ hws[IMX6QDL_CLK_PLL1_SYS] = imx_clk_hw_gate("pll1_sys", "pll1_bypass", base + 0x00, 13);
+ hws[IMX6QDL_CLK_PLL2_BUS] = imx_clk_hw_gate("pll2_bus", "pll2_bypass", base + 0x30, 13);
+ hws[IMX6QDL_CLK_PLL3_USB_OTG] = imx_clk_hw_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13);
+ hws[IMX6QDL_CLK_PLL4_AUDIO] = imx_clk_hw_gate("pll4_audio", "pll4_bypass", base + 0x70, 13);
+ hws[IMX6QDL_CLK_PLL5_VIDEO] = imx_clk_hw_gate("pll5_video", "pll5_bypass", base + 0xa0, 13);
+ hws[IMX6QDL_CLK_PLL6_ENET] = imx_clk_hw_gate("pll6_enet", "pll6_bypass", base + 0xe0, 13);
+ hws[IMX6QDL_CLK_PLL7_USB_HOST] = imx_clk_hw_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
/*
* Bit 20 is the reserved and read-only bit, we do this only for:
@@ -523,15 +520,15 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
* - Keep refcount when do usbphy clk_enable/disable, in that case,
* the clk framework may need to enable/disable usbphy's parent
*/
- clk[IMX6QDL_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20);
- clk[IMX6QDL_CLK_USBPHY2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
+ hws[IMX6QDL_CLK_USBPHY1] = imx_clk_hw_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20);
+ hws[IMX6QDL_CLK_USBPHY2] = imx_clk_hw_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
/*
* usbphy*_gate needs to be on after system boots up, and software
* never needs to control it anymore.
*/
- clk[IMX6QDL_CLK_USBPHY1_GATE] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6);
- clk[IMX6QDL_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6);
+ hws[IMX6QDL_CLK_USBPHY1_GATE] = imx_clk_hw_gate("usbphy1_gate", "dummy", base + 0x10, 6);
+ hws[IMX6QDL_CLK_USBPHY2_GATE] = imx_clk_hw_gate("usbphy2_gate", "dummy", base + 0x20, 6);
/*
* The ENET PLL is special in that is has multiple outputs with
@@ -545,22 +542,22 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
*
*/
if (!pll6_bypassed(ccm_node)) {
- clk[IMX6QDL_CLK_SATA_REF] = imx_clk_fixed_factor("sata_ref", "pll6_enet", 1, 5);
- clk[IMX6QDL_CLK_PCIE_REF] = imx_clk_fixed_factor("pcie_ref", "pll6_enet", 1, 4);
- clk[IMX6QDL_CLK_ENET_REF] = clk_register_divider_table(NULL, "enet_ref", "pll6_enet", 0,
+ hws[IMX6QDL_CLK_SATA_REF] = imx_clk_hw_fixed_factor("sata_ref", "pll6_enet", 1, 5);
+ hws[IMX6QDL_CLK_PCIE_REF] = imx_clk_hw_fixed_factor("pcie_ref", "pll6_enet", 1, 4);
+ hws[IMX6QDL_CLK_ENET_REF] = clk_hw_register_divider_table(NULL, "enet_ref", "pll6_enet", 0,
base + 0xe0, 0, 2, 0, clk_enet_ref_table,
&imx_ccm_lock);
} else {
- clk[IMX6QDL_CLK_SATA_REF] = imx_clk_fixed_factor("sata_ref", "pll6_enet", 1, 1);
- clk[IMX6QDL_CLK_PCIE_REF] = imx_clk_fixed_factor("pcie_ref", "pll6_enet", 1, 1);
- clk[IMX6QDL_CLK_ENET_REF] = imx_clk_fixed_factor("enet_ref", "pll6_enet", 1, 1);
+ hws[IMX6QDL_CLK_SATA_REF] = imx_clk_hw_fixed_factor("sata_ref", "pll6_enet", 1, 1);
+ hws[IMX6QDL_CLK_PCIE_REF] = imx_clk_hw_fixed_factor("pcie_ref", "pll6_enet", 1, 1);
+ hws[IMX6QDL_CLK_ENET_REF] = imx_clk_hw_fixed_factor("enet_ref", "pll6_enet", 1, 1);
}
- clk[IMX6QDL_CLK_SATA_REF_100M] = imx_clk_gate("sata_ref_100m", "sata_ref", base + 0xe0, 20);
- clk[IMX6QDL_CLK_PCIE_REF_125M] = imx_clk_gate("pcie_ref_125m", "pcie_ref", base + 0xe0, 19);
+ hws[IMX6QDL_CLK_SATA_REF_100M] = imx_clk_hw_gate("sata_ref_100m", "sata_ref", base + 0xe0, 20);
+ hws[IMX6QDL_CLK_PCIE_REF_125M] = imx_clk_hw_gate("pcie_ref_125m", "pcie_ref", base + 0xe0, 19);
- clk[IMX6QDL_CLK_LVDS1_SEL] = imx_clk_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
- clk[IMX6QDL_CLK_LVDS2_SEL] = imx_clk_mux("lvds2_sel", base + 0x160, 5, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
+ hws[IMX6QDL_CLK_LVDS1_SEL] = imx_clk_hw_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
+ hws[IMX6QDL_CLK_LVDS2_SEL] = imx_clk_hw_mux("lvds2_sel", base + 0x160, 5, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
/*
* lvds1_gate and lvds2_gate are pseudo-gates. Both can be
@@ -572,84 +569,84 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
* it.
*/
writel(readl(base + 0x160) & ~0x3c00, base + 0x160);
- clk[IMX6QDL_CLK_LVDS1_GATE] = imx_clk_gate_exclusive("lvds1_gate", "lvds1_sel", base + 0x160, 10, BIT(12));
- clk[IMX6QDL_CLK_LVDS2_GATE] = imx_clk_gate_exclusive("lvds2_gate", "lvds2_sel", base + 0x160, 11, BIT(13));
+ hws[IMX6QDL_CLK_LVDS1_GATE] = imx_clk_hw_gate_exclusive("lvds1_gate", "lvds1_sel", base + 0x160, 10, BIT(12));
+ hws[IMX6QDL_CLK_LVDS2_GATE] = imx_clk_hw_gate_exclusive("lvds2_gate", "lvds2_sel", base + 0x160, 11, BIT(13));
- clk[IMX6QDL_CLK_LVDS1_IN] = imx_clk_gate_exclusive("lvds1_in", "anaclk1", base + 0x160, 12, BIT(10));
- clk[IMX6QDL_CLK_LVDS2_IN] = imx_clk_gate_exclusive("lvds2_in", "anaclk2", base + 0x160, 13, BIT(11));
+ hws[IMX6QDL_CLK_LVDS1_IN] = imx_clk_hw_gate_exclusive("lvds1_in", "anaclk1", base + 0x160, 12, BIT(10));
+ hws[IMX6QDL_CLK_LVDS2_IN] = imx_clk_hw_gate_exclusive("lvds2_in", "anaclk2", base + 0x160, 13, BIT(11));
/* name parent_name reg idx */
- clk[IMX6QDL_CLK_PLL2_PFD0_352M] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0);
- clk[IMX6QDL_CLK_PLL2_PFD1_594M] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1);
- clk[IMX6QDL_CLK_PLL2_PFD2_396M] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2);
- clk[IMX6QDL_CLK_PLL3_PFD0_720M] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0);
- clk[IMX6QDL_CLK_PLL3_PFD1_540M] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1);
- clk[IMX6QDL_CLK_PLL3_PFD2_508M] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2);
- clk[IMX6QDL_CLK_PLL3_PFD3_454M] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3);
+ hws[IMX6QDL_CLK_PLL2_PFD0_352M] = imx_clk_hw_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0);
+ hws[IMX6QDL_CLK_PLL2_PFD1_594M] = imx_clk_hw_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1);
+ hws[IMX6QDL_CLK_PLL2_PFD2_396M] = imx_clk_hw_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2);
+ hws[IMX6QDL_CLK_PLL3_PFD0_720M] = imx_clk_hw_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0);
+ hws[IMX6QDL_CLK_PLL3_PFD1_540M] = imx_clk_hw_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1);
+ hws[IMX6QDL_CLK_PLL3_PFD2_508M] = imx_clk_hw_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2);
+ hws[IMX6QDL_CLK_PLL3_PFD3_454M] = imx_clk_hw_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3);
/* name parent_name mult div */
- clk[IMX6QDL_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2);
- clk[IMX6QDL_CLK_PLL3_120M] = imx_clk_fixed_factor("pll3_120m", "pll3_usb_otg", 1, 4);
- clk[IMX6QDL_CLK_PLL3_80M] = imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6);
- clk[IMX6QDL_CLK_PLL3_60M] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8);
- clk[IMX6QDL_CLK_TWD] = imx_clk_fixed_factor("twd", "arm", 1, 2);
- clk[IMX6QDL_CLK_GPT_3M] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8);
- clk[IMX6QDL_CLK_VIDEO_27M] = imx_clk_fixed_factor("video_27m", "pll3_pfd1_540m", 1, 20);
+ hws[IMX6QDL_CLK_PLL2_198M] = imx_clk_hw_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2);
+ hws[IMX6QDL_CLK_PLL3_120M] = imx_clk_hw_fixed_factor("pll3_120m", "pll3_usb_otg", 1, 4);
+ hws[IMX6QDL_CLK_PLL3_80M] = imx_clk_hw_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6);
+ hws[IMX6QDL_CLK_PLL3_60M] = imx_clk_hw_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8);
+ hws[IMX6QDL_CLK_TWD] = imx_clk_hw_fixed_factor("twd", "arm", 1, 2);
+ hws[IMX6QDL_CLK_GPT_3M] = imx_clk_hw_fixed_factor("gpt_3m", "osc", 1, 8);
+ hws[IMX6QDL_CLK_VIDEO_27M] = imx_clk_hw_fixed_factor("video_27m", "pll3_pfd1_540m", 1, 20);
if (clk_on_imx6dl() || clk_on_imx6qp()) {
- clk[IMX6QDL_CLK_GPU2D_AXI] = imx_clk_fixed_factor("gpu2d_axi", "mmdc_ch0_axi_podf", 1, 1);
- clk[IMX6QDL_CLK_GPU3D_AXI] = imx_clk_fixed_factor("gpu3d_axi", "mmdc_ch0_axi_podf", 1, 1);
+ hws[IMX6QDL_CLK_GPU2D_AXI] = imx_clk_hw_fixed_factor("gpu2d_axi", "mmdc_ch0_axi_podf", 1, 1);
+ hws[IMX6QDL_CLK_GPU3D_AXI] = imx_clk_hw_fixed_factor("gpu3d_axi", "mmdc_ch0_axi_podf", 1, 1);
}
- clk[IMX6QDL_CLK_PLL4_POST_DIV] = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio", CLK_SET_RATE_PARENT, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock);
- clk[IMX6QDL_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT, base + 0x170, 15, 1, 0, &imx_ccm_lock);
- clk[IMX6QDL_CLK_PLL5_POST_DIV] = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video", CLK_SET_RATE_PARENT, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock);
- clk[IMX6QDL_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", CLK_SET_RATE_PARENT, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock);
+ hws[IMX6QDL_CLK_PLL4_POST_DIV] = clk_hw_register_divider_table(NULL, "pll4_post_div", "pll4_audio", CLK_SET_RATE_PARENT, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock);
+ hws[IMX6QDL_CLK_PLL4_AUDIO_DIV] = clk_hw_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT, base + 0x170, 15, 1, 0, &imx_ccm_lock);
+ hws[IMX6QDL_CLK_PLL5_POST_DIV] = clk_hw_register_divider_table(NULL, "pll5_post_div", "pll5_video", CLK_SET_RATE_PARENT, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock);
+ hws[IMX6QDL_CLK_PLL5_VIDEO_DIV] = clk_hw_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", CLK_SET_RATE_PARENT, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock);
np = ccm_node;
base = of_iomap(np, 0);
WARN_ON(!base);
/* name reg shift width parent_names num_parents */
- clk[IMX6QDL_CLK_STEP] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels));
- clk[IMX6QDL_CLK_PLL1_SW] = imx_clk_mux("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels));
- clk[IMX6QDL_CLK_PERIPH_PRE] = imx_clk_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
- clk[IMX6QDL_CLK_PERIPH2_PRE] = imx_clk_mux("periph2_pre", base + 0x18, 21, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
- clk[IMX6QDL_CLK_PERIPH_CLK2_SEL] = imx_clk_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
- clk[IMX6QDL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
- clk[IMX6QDL_CLK_AXI_SEL] = imx_clk_mux("axi_sel", base + 0x14, 6, 2, axi_sels, ARRAY_SIZE(axi_sels));
- clk[IMX6QDL_CLK_ESAI_SEL] = imx_clk_mux("esai_sel", base + 0x20, 19, 2, audio_sels, ARRAY_SIZE(audio_sels));
- clk[IMX6QDL_CLK_ASRC_SEL] = imx_clk_mux("asrc_sel", base + 0x30, 7, 2, audio_sels, ARRAY_SIZE(audio_sels));
- clk[IMX6QDL_CLK_SPDIF_SEL] = imx_clk_mux("spdif_sel", base + 0x30, 20, 2, audio_sels, ARRAY_SIZE(audio_sels));
+ hws[IMX6QDL_CLK_STEP] = imx_clk_hw_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels));
+ hws[IMX6QDL_CLK_PLL1_SW] = imx_clk_hw_mux("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels));
+ hws[IMX6QDL_CLK_PERIPH_PRE] = imx_clk_hw_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
+ hws[IMX6QDL_CLK_PERIPH2_PRE] = imx_clk_hw_mux("periph2_pre", base + 0x18, 21, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
+ hws[IMX6QDL_CLK_PERIPH_CLK2_SEL] = imx_clk_hw_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
+ hws[IMX6QDL_CLK_PERIPH2_CLK2_SEL] = imx_clk_hw_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
+ hws[IMX6QDL_CLK_AXI_SEL] = imx_clk_hw_mux("axi_sel", base + 0x14, 6, 2, axi_sels, ARRAY_SIZE(axi_sels));
+ hws[IMX6QDL_CLK_ESAI_SEL] = imx_clk_hw_mux("esai_sel", base + 0x20, 19, 2, audio_sels, ARRAY_SIZE(audio_sels));
+ hws[IMX6QDL_CLK_ASRC_SEL] = imx_clk_hw_mux("asrc_sel", base + 0x30, 7, 2, audio_sels, ARRAY_SIZE(audio_sels));
+ hws[IMX6QDL_CLK_SPDIF_SEL] = imx_clk_hw_mux("spdif_sel", base + 0x30, 20, 2, audio_sels, ARRAY_SIZE(audio_sels));
if (clk_on_imx6q()) {
- clk[IMX6QDL_CLK_GPU2D_AXI] = imx_clk_mux("gpu2d_axi", base + 0x18, 0, 1, gpu_axi_sels, ARRAY_SIZE(gpu_axi_sels));
- clk[IMX6QDL_CLK_GPU3D_AXI] = imx_clk_mux("gpu3d_axi", base + 0x18, 1, 1, gpu_axi_sels, ARRAY_SIZE(gpu_axi_sels));
+ hws[IMX6QDL_CLK_GPU2D_AXI] = imx_clk_hw_mux("gpu2d_axi", base + 0x18, 0, 1, gpu_axi_sels, ARRAY_SIZE(gpu_axi_sels));
+ hws[IMX6QDL_CLK_GPU3D_AXI] = imx_clk_hw_mux("gpu3d_axi", base + 0x18, 1, 1, gpu_axi_sels, ARRAY_SIZE(gpu_axi_sels));
}
if (clk_on_imx6qp()) {
- clk[IMX6QDL_CLK_CAN_SEL] = imx_clk_mux("can_sel", base + 0x20, 8, 2, can_sels, ARRAY_SIZE(can_sels));
- clk[IMX6QDL_CLK_ECSPI_SEL] = imx_clk_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels));
- clk[IMX6QDL_CLK_IPG_PER_SEL] = imx_clk_mux("ipg_per_sel", base + 0x1c, 6, 1, ipg_per_sels, ARRAY_SIZE(ipg_per_sels));
- clk[IMX6QDL_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels));
- clk[IMX6QDL_CLK_GPU2D_CORE_SEL] = imx_clk_mux("gpu2d_core_sel", base + 0x18, 16, 2, gpu2d_core_sels_2, ARRAY_SIZE(gpu2d_core_sels_2));
+ hws[IMX6QDL_CLK_CAN_SEL] = imx_clk_hw_mux("can_sel", base + 0x20, 8, 2, can_sels, ARRAY_SIZE(can_sels));
+ hws[IMX6QDL_CLK_ECSPI_SEL] = imx_clk_hw_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels));
+ hws[IMX6QDL_CLK_IPG_PER_SEL] = imx_clk_hw_mux("ipg_per_sel", base + 0x1c, 6, 1, ipg_per_sels, ARRAY_SIZE(ipg_per_sels));
+ hws[IMX6QDL_CLK_UART_SEL] = imx_clk_hw_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels));
+ hws[IMX6QDL_CLK_GPU2D_CORE_SEL] = imx_clk_hw_mux("gpu2d_core_sel", base + 0x18, 16, 2, gpu2d_core_sels_2, ARRAY_SIZE(gpu2d_core_sels_2));
} else if (clk_on_imx6dl()) {
- clk[IMX6QDL_CLK_MLB_SEL] = imx_clk_mux("mlb_sel", base + 0x18, 16, 2, gpu2d_core_sels, ARRAY_SIZE(gpu2d_core_sels));
+ hws[IMX6QDL_CLK_MLB_SEL] = imx_clk_hw_mux("mlb_sel", base + 0x18, 16, 2, gpu2d_core_sels, ARRAY_SIZE(gpu2d_core_sels));
} else {
- clk[IMX6QDL_CLK_GPU2D_CORE_SEL] = imx_clk_mux("gpu2d_core_sel", base + 0x18, 16, 2, gpu2d_core_sels, ARRAY_SIZE(gpu2d_core_sels));
+ hws[IMX6QDL_CLK_GPU2D_CORE_SEL] = imx_clk_hw_mux("gpu2d_core_sel", base + 0x18, 16, 2, gpu2d_core_sels, ARRAY_SIZE(gpu2d_core_sels));
}
- clk[IMX6QDL_CLK_GPU3D_CORE_SEL] = imx_clk_mux("gpu3d_core_sel", base + 0x18, 4, 2, gpu3d_core_sels, ARRAY_SIZE(gpu3d_core_sels));
+ hws[IMX6QDL_CLK_GPU3D_CORE_SEL] = imx_clk_hw_mux("gpu3d_core_sel", base + 0x18, 4, 2, gpu3d_core_sels, ARRAY_SIZE(gpu3d_core_sels));
if (clk_on_imx6dl())
- clk[IMX6QDL_CLK_GPU2D_CORE_SEL] = imx_clk_mux("gpu2d_core_sel", base + 0x18, 8, 2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels));
+ hws[IMX6QDL_CLK_GPU2D_CORE_SEL] = imx_clk_hw_mux("gpu2d_core_sel", base + 0x18, 8, 2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels));
else
- clk[IMX6QDL_CLK_GPU3D_SHADER_SEL] = imx_clk_mux("gpu3d_shader_sel", base + 0x18, 8, 2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels));
- clk[IMX6QDL_CLK_IPU1_SEL] = imx_clk_mux("ipu1_sel", base + 0x3c, 9, 2, ipu_sels, ARRAY_SIZE(ipu_sels));
- clk[IMX6QDL_CLK_IPU2_SEL] = imx_clk_mux("ipu2_sel", base + 0x3c, 14, 2, ipu_sels, ARRAY_SIZE(ipu_sels));
+ hws[IMX6QDL_CLK_GPU3D_SHADER_SEL] = imx_clk_hw_mux("gpu3d_shader_sel", base + 0x18, 8, 2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels));
+ hws[IMX6QDL_CLK_IPU1_SEL] = imx_clk_hw_mux("ipu1_sel", base + 0x3c, 9, 2, ipu_sels, ARRAY_SIZE(ipu_sels));
+ hws[IMX6QDL_CLK_IPU2_SEL] = imx_clk_hw_mux("ipu2_sel", base + 0x3c, 14, 2, ipu_sels, ARRAY_SIZE(ipu_sels));
disable_anatop_clocks(anatop_base);
- imx6q_mmdc_ch1_mask_handshake(base);
+ imx_mmdc_mask_handshake(base, 1);
if (clk_on_imx6qp()) {
- clk[IMX6QDL_CLK_LDB_DI0_SEL] = imx_clk_mux_flags("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT);
- clk[IMX6QDL_CLK_LDB_DI1_SEL] = imx_clk_mux_flags("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6QDL_CLK_LDB_DI0_SEL] = imx_clk_hw_mux_flags("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6QDL_CLK_LDB_DI1_SEL] = imx_clk_hw_mux_flags("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT);
} else {
/*
* The LDB_DI0/1_SEL muxes are registered read-only due to a hardware
@@ -658,322 +655,333 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
*/
init_ldb_clks(np, base);
- clk[IMX6QDL_CLK_LDB_DI0_SEL] = imx_clk_mux_ldb("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels));
- clk[IMX6QDL_CLK_LDB_DI1_SEL] = imx_clk_mux_ldb("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels));
+ hws[IMX6QDL_CLK_LDB_DI0_SEL] = imx_clk_hw_mux_ldb("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels));
+ hws[IMX6QDL_CLK_LDB_DI1_SEL] = imx_clk_hw_mux_ldb("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels));
}
- clk[IMX6QDL_CLK_IPU1_DI0_PRE_SEL] = imx_clk_mux_flags("ipu1_di0_pre_sel", base + 0x34, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
- clk[IMX6QDL_CLK_IPU1_DI1_PRE_SEL] = imx_clk_mux_flags("ipu1_di1_pre_sel", base + 0x34, 15, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
- clk[IMX6QDL_CLK_IPU2_DI0_PRE_SEL] = imx_clk_mux_flags("ipu2_di0_pre_sel", base + 0x38, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
- clk[IMX6QDL_CLK_IPU2_DI1_PRE_SEL] = imx_clk_mux_flags("ipu2_di1_pre_sel", base + 0x38, 15, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
- clk[IMX6QDL_CLK_HSI_TX_SEL] = imx_clk_mux("hsi_tx_sel", base + 0x30, 28, 1, hsi_tx_sels, ARRAY_SIZE(hsi_tx_sels));
- clk[IMX6QDL_CLK_PCIE_AXI_SEL] = imx_clk_mux("pcie_axi_sel", base + 0x18, 10, 1, pcie_axi_sels, ARRAY_SIZE(pcie_axi_sels));
+
+ hws[IMX6QDL_CLK_IPU1_DI0_PRE_SEL] = imx_clk_hw_mux_flags("ipu1_di0_pre_sel", base + 0x34, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6QDL_CLK_IPU1_DI1_PRE_SEL] = imx_clk_hw_mux_flags("ipu1_di1_pre_sel", base + 0x34, 15, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6QDL_CLK_IPU2_DI0_PRE_SEL] = imx_clk_hw_mux_flags("ipu2_di0_pre_sel", base + 0x38, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6QDL_CLK_IPU2_DI1_PRE_SEL] = imx_clk_hw_mux_flags("ipu2_di1_pre_sel", base + 0x38, 15, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6QDL_CLK_HSI_TX_SEL] = imx_clk_hw_mux("hsi_tx_sel", base + 0x30, 28, 1, hsi_tx_sels, ARRAY_SIZE(hsi_tx_sels));
+ hws[IMX6QDL_CLK_PCIE_AXI_SEL] = imx_clk_hw_mux("pcie_axi_sel", base + 0x18, 10, 1, pcie_axi_sels, ARRAY_SIZE(pcie_axi_sels));
+
if (clk_on_imx6qp()) {
- clk[IMX6QDL_CLK_IPU1_DI0_SEL] = imx_clk_mux_flags("ipu1_di0_sel", base + 0x34, 0, 3, ipu1_di0_sels_2, ARRAY_SIZE(ipu1_di0_sels_2), CLK_SET_RATE_PARENT);
- clk[IMX6QDL_CLK_IPU1_DI1_SEL] = imx_clk_mux_flags("ipu1_di1_sel", base + 0x34, 9, 3, ipu1_di1_sels_2, ARRAY_SIZE(ipu1_di1_sels_2), CLK_SET_RATE_PARENT);
- clk[IMX6QDL_CLK_IPU2_DI0_SEL] = imx_clk_mux_flags("ipu2_di0_sel", base + 0x38, 0, 3, ipu2_di0_sels_2, ARRAY_SIZE(ipu2_di0_sels_2), CLK_SET_RATE_PARENT);
- clk[IMX6QDL_CLK_IPU2_DI1_SEL] = imx_clk_mux_flags("ipu2_di1_sel", base + 0x38, 9, 3, ipu2_di1_sels_2, ARRAY_SIZE(ipu2_di1_sels_2), CLK_SET_RATE_PARENT);
- clk[IMX6QDL_CLK_SSI1_SEL] = imx_clk_mux("ssi1_sel", base + 0x1c, 10, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
- clk[IMX6QDL_CLK_SSI2_SEL] = imx_clk_mux("ssi2_sel", base + 0x1c, 12, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
- clk[IMX6QDL_CLK_SSI3_SEL] = imx_clk_mux("ssi3_sel", base + 0x1c, 14, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
- clk[IMX6QDL_CLK_USDHC1_SEL] = imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
- clk[IMX6QDL_CLK_USDHC2_SEL] = imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
- clk[IMX6QDL_CLK_USDHC3_SEL] = imx_clk_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
- clk[IMX6QDL_CLK_USDHC4_SEL] = imx_clk_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
- clk[IMX6QDL_CLK_ENFC_SEL] = imx_clk_mux("enfc_sel", base + 0x2c, 15, 3, enfc_sels_2, ARRAY_SIZE(enfc_sels_2));
- clk[IMX6QDL_CLK_EIM_SEL] = imx_clk_mux("eim_sel", base + 0x1c, 27, 2, eim_sels, ARRAY_SIZE(eim_sels));
- clk[IMX6QDL_CLK_EIM_SLOW_SEL] = imx_clk_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels, ARRAY_SIZE(eim_slow_sels));
- clk[IMX6QDL_CLK_PRE_AXI] = imx_clk_mux("pre_axi", base + 0x18, 1, 1, pre_axi_sels, ARRAY_SIZE(pre_axi_sels));
+ hws[IMX6QDL_CLK_IPU1_DI0_SEL] = imx_clk_hw_mux_flags("ipu1_di0_sel", base + 0x34, 0, 3, ipu1_di0_sels_2, ARRAY_SIZE(ipu1_di0_sels_2), CLK_SET_RATE_PARENT);
+ hws[IMX6QDL_CLK_IPU1_DI1_SEL] = imx_clk_hw_mux_flags("ipu1_di1_sel", base + 0x34, 9, 3, ipu1_di1_sels_2, ARRAY_SIZE(ipu1_di1_sels_2), CLK_SET_RATE_PARENT);
+ hws[IMX6QDL_CLK_IPU2_DI0_SEL] = imx_clk_hw_mux_flags("ipu2_di0_sel", base + 0x38, 0, 3, ipu2_di0_sels_2, ARRAY_SIZE(ipu2_di0_sels_2), CLK_SET_RATE_PARENT);
+ hws[IMX6QDL_CLK_IPU2_DI1_SEL] = imx_clk_hw_mux_flags("ipu2_di1_sel", base + 0x38, 9, 3, ipu2_di1_sels_2, ARRAY_SIZE(ipu2_di1_sels_2), CLK_SET_RATE_PARENT);
+ hws[IMX6QDL_CLK_SSI1_SEL] = imx_clk_hw_mux("ssi1_sel", base + 0x1c, 10, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
+ hws[IMX6QDL_CLK_SSI2_SEL] = imx_clk_hw_mux("ssi2_sel", base + 0x1c, 12, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
+ hws[IMX6QDL_CLK_SSI3_SEL] = imx_clk_hw_mux("ssi3_sel", base + 0x1c, 14, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
+ hws[IMX6QDL_CLK_USDHC1_SEL] = imx_clk_hw_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+ hws[IMX6QDL_CLK_USDHC2_SEL] = imx_clk_hw_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+ hws[IMX6QDL_CLK_USDHC3_SEL] = imx_clk_hw_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+ hws[IMX6QDL_CLK_USDHC4_SEL] = imx_clk_hw_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+ hws[IMX6QDL_CLK_ENFC_SEL] = imx_clk_hw_mux("enfc_sel", base + 0x2c, 15, 3, enfc_sels_2, ARRAY_SIZE(enfc_sels_2));
+ hws[IMX6QDL_CLK_EIM_SEL] = imx_clk_hw_mux("eim_sel", base + 0x1c, 27, 2, eim_sels, ARRAY_SIZE(eim_sels));
+ hws[IMX6QDL_CLK_EIM_SLOW_SEL] = imx_clk_hw_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels, ARRAY_SIZE(eim_slow_sels));
+ hws[IMX6QDL_CLK_PRE_AXI] = imx_clk_hw_mux("pre_axi", base + 0x18, 1, 1, pre_axi_sels, ARRAY_SIZE(pre_axi_sels));
} else {
- clk[IMX6QDL_CLK_IPU1_DI0_SEL] = imx_clk_mux_flags("ipu1_di0_sel", base + 0x34, 0, 3, ipu1_di0_sels, ARRAY_SIZE(ipu1_di0_sels), CLK_SET_RATE_PARENT);
- clk[IMX6QDL_CLK_IPU1_DI1_SEL] = imx_clk_mux_flags("ipu1_di1_sel", base + 0x34, 9, 3, ipu1_di1_sels, ARRAY_SIZE(ipu1_di1_sels), CLK_SET_RATE_PARENT);
- clk[IMX6QDL_CLK_IPU2_DI0_SEL] = imx_clk_mux_flags("ipu2_di0_sel", base + 0x38, 0, 3, ipu2_di0_sels, ARRAY_SIZE(ipu2_di0_sels), CLK_SET_RATE_PARENT);
- clk[IMX6QDL_CLK_IPU2_DI1_SEL] = imx_clk_mux_flags("ipu2_di1_sel", base + 0x38, 9, 3, ipu2_di1_sels, ARRAY_SIZE(ipu2_di1_sels), CLK_SET_RATE_PARENT);
- clk[IMX6QDL_CLK_SSI1_SEL] = imx_clk_fixup_mux("ssi1_sel", base + 0x1c, 10, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup);
- clk[IMX6QDL_CLK_SSI2_SEL] = imx_clk_fixup_mux("ssi2_sel", base + 0x1c, 12, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup);
- clk[IMX6QDL_CLK_SSI3_SEL] = imx_clk_fixup_mux("ssi3_sel", base + 0x1c, 14, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup);
- clk[IMX6QDL_CLK_USDHC1_SEL] = imx_clk_fixup_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
- clk[IMX6QDL_CLK_USDHC2_SEL] = imx_clk_fixup_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
- clk[IMX6QDL_CLK_USDHC3_SEL] = imx_clk_fixup_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
- clk[IMX6QDL_CLK_USDHC4_SEL] = imx_clk_fixup_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
- clk[IMX6QDL_CLK_ENFC_SEL] = imx_clk_mux("enfc_sel", base + 0x2c, 16, 2, enfc_sels, ARRAY_SIZE(enfc_sels));
- clk[IMX6QDL_CLK_EIM_SEL] = imx_clk_fixup_mux("eim_sel", base + 0x1c, 27, 2, eim_sels, ARRAY_SIZE(eim_sels), imx_cscmr1_fixup);
- clk[IMX6QDL_CLK_EIM_SLOW_SEL] = imx_clk_fixup_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels, ARRAY_SIZE(eim_slow_sels), imx_cscmr1_fixup);
+ hws[IMX6QDL_CLK_IPU1_DI0_SEL] = imx_clk_hw_mux_flags("ipu1_di0_sel", base + 0x34, 0, 3, ipu1_di0_sels, ARRAY_SIZE(ipu1_di0_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6QDL_CLK_IPU1_DI1_SEL] = imx_clk_hw_mux_flags("ipu1_di1_sel", base + 0x34, 9, 3, ipu1_di1_sels, ARRAY_SIZE(ipu1_di1_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6QDL_CLK_IPU2_DI0_SEL] = imx_clk_hw_mux_flags("ipu2_di0_sel", base + 0x38, 0, 3, ipu2_di0_sels, ARRAY_SIZE(ipu2_di0_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6QDL_CLK_IPU2_DI1_SEL] = imx_clk_hw_mux_flags("ipu2_di1_sel", base + 0x38, 9, 3, ipu2_di1_sels, ARRAY_SIZE(ipu2_di1_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6QDL_CLK_SSI1_SEL] = imx_clk_hw_fixup_mux("ssi1_sel", base + 0x1c, 10, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup);
+ hws[IMX6QDL_CLK_SSI2_SEL] = imx_clk_hw_fixup_mux("ssi2_sel", base + 0x1c, 12, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup);
+ hws[IMX6QDL_CLK_SSI3_SEL] = imx_clk_hw_fixup_mux("ssi3_sel", base + 0x1c, 14, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup);
+ hws[IMX6QDL_CLK_USDHC1_SEL] = imx_clk_hw_fixup_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
+ hws[IMX6QDL_CLK_USDHC2_SEL] = imx_clk_hw_fixup_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
+ hws[IMX6QDL_CLK_USDHC3_SEL] = imx_clk_hw_fixup_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
+ hws[IMX6QDL_CLK_USDHC4_SEL] = imx_clk_hw_fixup_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
+ hws[IMX6QDL_CLK_ENFC_SEL] = imx_clk_hw_mux("enfc_sel", base + 0x2c, 16, 2, enfc_sels, ARRAY_SIZE(enfc_sels));
+ hws[IMX6QDL_CLK_EIM_SEL] = imx_clk_hw_fixup_mux("eim_sel", base + 0x1c, 27, 2, eim_sels, ARRAY_SIZE(eim_sels), imx_cscmr1_fixup);
+ hws[IMX6QDL_CLK_EIM_SLOW_SEL] = imx_clk_hw_fixup_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels, ARRAY_SIZE(eim_slow_sels), imx_cscmr1_fixup);
}
- clk[IMX6QDL_CLK_VDO_AXI_SEL] = imx_clk_mux("vdo_axi_sel", base + 0x18, 11, 1, vdo_axi_sels, ARRAY_SIZE(vdo_axi_sels));
- clk[IMX6QDL_CLK_VPU_AXI_SEL] = imx_clk_mux("vpu_axi_sel", base + 0x18, 14, 2, vpu_axi_sels, ARRAY_SIZE(vpu_axi_sels));
- clk[IMX6QDL_CLK_CKO1_SEL] = imx_clk_mux("cko1_sel", base + 0x60, 0, 4, cko1_sels, ARRAY_SIZE(cko1_sels));
- clk[IMX6QDL_CLK_CKO2_SEL] = imx_clk_mux("cko2_sel", base + 0x60, 16, 5, cko2_sels, ARRAY_SIZE(cko2_sels));
- clk[IMX6QDL_CLK_CKO] = imx_clk_mux("cko", base + 0x60, 8, 1, cko_sels, ARRAY_SIZE(cko_sels));
+
+ hws[IMX6QDL_CLK_VDO_AXI_SEL] = imx_clk_hw_mux("vdo_axi_sel", base + 0x18, 11, 1, vdo_axi_sels, ARRAY_SIZE(vdo_axi_sels));
+ hws[IMX6QDL_CLK_VPU_AXI_SEL] = imx_clk_hw_mux("vpu_axi_sel", base + 0x18, 14, 2, vpu_axi_sels, ARRAY_SIZE(vpu_axi_sels));
+ hws[IMX6QDL_CLK_CKO1_SEL] = imx_clk_hw_mux("cko1_sel", base + 0x60, 0, 4, cko1_sels, ARRAY_SIZE(cko1_sels));
+ hws[IMX6QDL_CLK_CKO2_SEL] = imx_clk_hw_mux("cko2_sel", base + 0x60, 16, 5, cko2_sels, ARRAY_SIZE(cko2_sels));
+ hws[IMX6QDL_CLK_CKO] = imx_clk_hw_mux("cko", base + 0x60, 8, 1, cko_sels, ARRAY_SIZE(cko_sels));
/* name reg shift width busy: reg, shift parent_names num_parents */
- clk[IMX6QDL_CLK_PERIPH] = imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels));
- clk[IMX6QDL_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels));
+ hws[IMX6QDL_CLK_PERIPH] = imx_clk_hw_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels));
+ hws[IMX6QDL_CLK_PERIPH2] = imx_clk_hw_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels));
/* name parent_name reg shift width */
- clk[IMX6QDL_CLK_PERIPH_CLK2] = imx_clk_divider("periph_clk2", "periph_clk2_sel", base + 0x14, 27, 3);
- clk[IMX6QDL_CLK_PERIPH2_CLK2] = imx_clk_divider("periph2_clk2", "periph2_clk2_sel", base + 0x14, 0, 3);
- clk[IMX6QDL_CLK_IPG] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2);
- clk[IMX6QDL_CLK_ESAI_PRED] = imx_clk_divider("esai_pred", "esai_sel", base + 0x28, 9, 3);
- clk[IMX6QDL_CLK_ESAI_PODF] = imx_clk_divider("esai_podf", "esai_pred", base + 0x28, 25, 3);
- clk[IMX6QDL_CLK_ASRC_PRED] = imx_clk_divider("asrc_pred", "asrc_sel", base + 0x30, 12, 3);
- clk[IMX6QDL_CLK_ASRC_PODF] = imx_clk_divider("asrc_podf", "asrc_pred", base + 0x30, 9, 3);
- clk[IMX6QDL_CLK_SPDIF_PRED] = imx_clk_divider("spdif_pred", "spdif_sel", base + 0x30, 25, 3);
- clk[IMX6QDL_CLK_SPDIF_PODF] = imx_clk_divider("spdif_podf", "spdif_pred", base + 0x30, 22, 3);
+ hws[IMX6QDL_CLK_PERIPH_CLK2] = imx_clk_hw_divider("periph_clk2", "periph_clk2_sel", base + 0x14, 27, 3);
+ hws[IMX6QDL_CLK_PERIPH2_CLK2] = imx_clk_hw_divider("periph2_clk2", "periph2_clk2_sel", base + 0x14, 0, 3);
+ hws[IMX6QDL_CLK_IPG] = imx_clk_hw_divider("ipg", "ahb", base + 0x14, 8, 2);
+ hws[IMX6QDL_CLK_ESAI_PRED] = imx_clk_hw_divider("esai_pred", "esai_sel", base + 0x28, 9, 3);
+ hws[IMX6QDL_CLK_ESAI_PODF] = imx_clk_hw_divider("esai_podf", "esai_pred", base + 0x28, 25, 3);
+ hws[IMX6QDL_CLK_ASRC_PRED] = imx_clk_hw_divider("asrc_pred", "asrc_sel", base + 0x30, 12, 3);
+ hws[IMX6QDL_CLK_ASRC_PODF] = imx_clk_hw_divider("asrc_podf", "asrc_pred", base + 0x30, 9, 3);
+ hws[IMX6QDL_CLK_SPDIF_PRED] = imx_clk_hw_divider("spdif_pred", "spdif_sel", base + 0x30, 25, 3);
+ hws[IMX6QDL_CLK_SPDIF_PODF] = imx_clk_hw_divider("spdif_podf", "spdif_pred", base + 0x30, 22, 3);
+
if (clk_on_imx6qp()) {
- clk[IMX6QDL_CLK_IPG_PER] = imx_clk_divider("ipg_per", "ipg_per_sel", base + 0x1c, 0, 6);
- clk[IMX6QDL_CLK_ECSPI_ROOT] = imx_clk_divider("ecspi_root", "ecspi_sel", base + 0x38, 19, 6);
- clk[IMX6QDL_CLK_CAN_ROOT] = imx_clk_divider("can_root", "can_sel", base + 0x20, 2, 6);
- clk[IMX6QDL_CLK_UART_SERIAL_PODF] = imx_clk_divider("uart_serial_podf", "uart_sel", base + 0x24, 0, 6);
- clk[IMX6QDL_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0", 2, 7);
- clk[IMX6QDL_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1", 2, 7);
+ hws[IMX6QDL_CLK_IPG_PER] = imx_clk_hw_divider("ipg_per", "ipg_per_sel", base + 0x1c, 0, 6);
+ hws[IMX6QDL_CLK_ECSPI_ROOT] = imx_clk_hw_divider("ecspi_root", "ecspi_sel", base + 0x38, 19, 6);
+ hws[IMX6QDL_CLK_CAN_ROOT] = imx_clk_hw_divider("can_root", "can_sel", base + 0x20, 2, 6);
+ hws[IMX6QDL_CLK_UART_SERIAL_PODF] = imx_clk_hw_divider("uart_serial_podf", "uart_sel", base + 0x24, 0, 6);
+ hws[IMX6QDL_CLK_LDB_DI0_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di0_div_3_5", "ldb_di0", 2, 7);
+ hws[IMX6QDL_CLK_LDB_DI1_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di1_div_3_5", "ldb_di1", 2, 7);
} else {
- clk[IMX6QDL_CLK_ECSPI_ROOT] = imx_clk_divider("ecspi_root", "pll3_60m", base + 0x38, 19, 6);
- clk[IMX6QDL_CLK_CAN_ROOT] = imx_clk_divider("can_root", "pll3_60m", base + 0x20, 2, 6);
- clk[IMX6QDL_CLK_IPG_PER] = imx_clk_fixup_divider("ipg_per", "ipg", base + 0x1c, 0, 6, imx_cscmr1_fixup);
- clk[IMX6QDL_CLK_UART_SERIAL_PODF] = imx_clk_divider("uart_serial_podf", "pll3_80m", base + 0x24, 0, 6);
- clk[IMX6QDL_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
- clk[IMX6QDL_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7);
+ hws[IMX6QDL_CLK_ECSPI_ROOT] = imx_clk_hw_divider("ecspi_root", "pll3_60m", base + 0x38, 19, 6);
+ hws[IMX6QDL_CLK_CAN_ROOT] = imx_clk_hw_divider("can_root", "pll3_60m", base + 0x20, 2, 6);
+ hws[IMX6QDL_CLK_IPG_PER] = imx_clk_hw_fixup_divider("ipg_per", "ipg", base + 0x1c, 0, 6, imx_cscmr1_fixup);
+ hws[IMX6QDL_CLK_UART_SERIAL_PODF] = imx_clk_hw_divider("uart_serial_podf", "pll3_80m", base + 0x24, 0, 6);
+ hws[IMX6QDL_CLK_LDB_DI0_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
+ hws[IMX6QDL_CLK_LDB_DI1_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7);
}
+
if (clk_on_imx6dl())
- clk[IMX6QDL_CLK_MLB_PODF] = imx_clk_divider("mlb_podf", "mlb_sel", base + 0x18, 23, 3);
+ hws[IMX6QDL_CLK_MLB_PODF] = imx_clk_hw_divider("mlb_podf", "mlb_sel", base + 0x18, 23, 3);
else
- clk[IMX6QDL_CLK_GPU2D_CORE_PODF] = imx_clk_divider("gpu2d_core_podf", "gpu2d_core_sel", base + 0x18, 23, 3);
- clk[IMX6QDL_CLK_GPU3D_CORE_PODF] = imx_clk_divider("gpu3d_core_podf", "gpu3d_core_sel", base + 0x18, 26, 3);
+ hws[IMX6QDL_CLK_GPU2D_CORE_PODF] = imx_clk_hw_divider("gpu2d_core_podf", "gpu2d_core_sel", base + 0x18, 23, 3);
+ hws[IMX6QDL_CLK_GPU3D_CORE_PODF] = imx_clk_hw_divider("gpu3d_core_podf", "gpu3d_core_sel", base + 0x18, 26, 3);
if (clk_on_imx6dl())
- clk[IMX6QDL_CLK_GPU2D_CORE_PODF] = imx_clk_divider("gpu2d_core_podf", "gpu2d_core_sel", base + 0x18, 29, 3);
+ hws[IMX6QDL_CLK_GPU2D_CORE_PODF] = imx_clk_hw_divider("gpu2d_core_podf", "gpu2d_core_sel", base + 0x18, 29, 3);
else
- clk[IMX6QDL_CLK_GPU3D_SHADER] = imx_clk_divider("gpu3d_shader", "gpu3d_shader_sel", base + 0x18, 29, 3);
- clk[IMX6QDL_CLK_IPU1_PODF] = imx_clk_divider("ipu1_podf", "ipu1_sel", base + 0x3c, 11, 3);
- clk[IMX6QDL_CLK_IPU2_PODF] = imx_clk_divider("ipu2_podf", "ipu2_sel", base + 0x3c, 16, 3);
- clk[IMX6QDL_CLK_LDB_DI0_PODF] = imx_clk_divider_flags("ldb_di0_podf", "ldb_di0_div_3_5", base + 0x20, 10, 1, 0);
- clk[IMX6QDL_CLK_LDB_DI1_PODF] = imx_clk_divider_flags("ldb_di1_podf", "ldb_di1_div_3_5", base + 0x20, 11, 1, 0);
- clk[IMX6QDL_CLK_IPU1_DI0_PRE] = imx_clk_divider("ipu1_di0_pre", "ipu1_di0_pre_sel", base + 0x34, 3, 3);
- clk[IMX6QDL_CLK_IPU1_DI1_PRE] = imx_clk_divider("ipu1_di1_pre", "ipu1_di1_pre_sel", base + 0x34, 12, 3);
- clk[IMX6QDL_CLK_IPU2_DI0_PRE] = imx_clk_divider("ipu2_di0_pre", "ipu2_di0_pre_sel", base + 0x38, 3, 3);
- clk[IMX6QDL_CLK_IPU2_DI1_PRE] = imx_clk_divider("ipu2_di1_pre", "ipu2_di1_pre_sel", base + 0x38, 12, 3);
- clk[IMX6QDL_CLK_HSI_TX_PODF] = imx_clk_divider("hsi_tx_podf", "hsi_tx_sel", base + 0x30, 29, 3);
- clk[IMX6QDL_CLK_SSI1_PRED] = imx_clk_divider("ssi1_pred", "ssi1_sel", base + 0x28, 6, 3);
- clk[IMX6QDL_CLK_SSI1_PODF] = imx_clk_divider("ssi1_podf", "ssi1_pred", base + 0x28, 0, 6);
- clk[IMX6QDL_CLK_SSI2_PRED] = imx_clk_divider("ssi2_pred", "ssi2_sel", base + 0x2c, 6, 3);
- clk[IMX6QDL_CLK_SSI2_PODF] = imx_clk_divider("ssi2_podf", "ssi2_pred", base + 0x2c, 0, 6);
- clk[IMX6QDL_CLK_SSI3_PRED] = imx_clk_divider("ssi3_pred", "ssi3_sel", base + 0x28, 22, 3);
- clk[IMX6QDL_CLK_SSI3_PODF] = imx_clk_divider("ssi3_podf", "ssi3_pred", base + 0x28, 16, 6);
- clk[IMX6QDL_CLK_USDHC1_PODF] = imx_clk_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3);
- clk[IMX6QDL_CLK_USDHC2_PODF] = imx_clk_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3);
- clk[IMX6QDL_CLK_USDHC3_PODF] = imx_clk_divider("usdhc3_podf", "usdhc3_sel", base + 0x24, 19, 3);
- clk[IMX6QDL_CLK_USDHC4_PODF] = imx_clk_divider("usdhc4_podf", "usdhc4_sel", base + 0x24, 22, 3);
- clk[IMX6QDL_CLK_ENFC_PRED] = imx_clk_divider("enfc_pred", "enfc_sel", base + 0x2c, 18, 3);
- clk[IMX6QDL_CLK_ENFC_PODF] = imx_clk_divider("enfc_podf", "enfc_pred", base + 0x2c, 21, 6);
+ hws[IMX6QDL_CLK_GPU3D_SHADER] = imx_clk_hw_divider("gpu3d_shader", "gpu3d_shader_sel", base + 0x18, 29, 3);
+ hws[IMX6QDL_CLK_IPU1_PODF] = imx_clk_hw_divider("ipu1_podf", "ipu1_sel", base + 0x3c, 11, 3);
+ hws[IMX6QDL_CLK_IPU2_PODF] = imx_clk_hw_divider("ipu2_podf", "ipu2_sel", base + 0x3c, 16, 3);
+ hws[IMX6QDL_CLK_LDB_DI0_PODF] = imx_clk_hw_divider_flags("ldb_di0_podf", "ldb_di0_div_3_5", base + 0x20, 10, 1, 0);
+ hws[IMX6QDL_CLK_LDB_DI1_PODF] = imx_clk_hw_divider_flags("ldb_di1_podf", "ldb_di1_div_3_5", base + 0x20, 11, 1, 0);
+ hws[IMX6QDL_CLK_IPU1_DI0_PRE] = imx_clk_hw_divider("ipu1_di0_pre", "ipu1_di0_pre_sel", base + 0x34, 3, 3);
+ hws[IMX6QDL_CLK_IPU1_DI1_PRE] = imx_clk_hw_divider("ipu1_di1_pre", "ipu1_di1_pre_sel", base + 0x34, 12, 3);
+ hws[IMX6QDL_CLK_IPU2_DI0_PRE] = imx_clk_hw_divider("ipu2_di0_pre", "ipu2_di0_pre_sel", base + 0x38, 3, 3);
+ hws[IMX6QDL_CLK_IPU2_DI1_PRE] = imx_clk_hw_divider("ipu2_di1_pre", "ipu2_di1_pre_sel", base + 0x38, 12, 3);
+ hws[IMX6QDL_CLK_HSI_TX_PODF] = imx_clk_hw_divider("hsi_tx_podf", "hsi_tx_sel", base + 0x30, 29, 3);
+ hws[IMX6QDL_CLK_SSI1_PRED] = imx_clk_hw_divider("ssi1_pred", "ssi1_sel", base + 0x28, 6, 3);
+ hws[IMX6QDL_CLK_SSI1_PODF] = imx_clk_hw_divider("ssi1_podf", "ssi1_pred", base + 0x28, 0, 6);
+ hws[IMX6QDL_CLK_SSI2_PRED] = imx_clk_hw_divider("ssi2_pred", "ssi2_sel", base + 0x2c, 6, 3);
+ hws[IMX6QDL_CLK_SSI2_PODF] = imx_clk_hw_divider("ssi2_podf", "ssi2_pred", base + 0x2c, 0, 6);
+ hws[IMX6QDL_CLK_SSI3_PRED] = imx_clk_hw_divider("ssi3_pred", "ssi3_sel", base + 0x28, 22, 3);
+ hws[IMX6QDL_CLK_SSI3_PODF] = imx_clk_hw_divider("ssi3_podf", "ssi3_pred", base + 0x28, 16, 6);
+ hws[IMX6QDL_CLK_USDHC1_PODF] = imx_clk_hw_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3);
+ hws[IMX6QDL_CLK_USDHC2_PODF] = imx_clk_hw_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3);
+ hws[IMX6QDL_CLK_USDHC3_PODF] = imx_clk_hw_divider("usdhc3_podf", "usdhc3_sel", base + 0x24, 19, 3);
+ hws[IMX6QDL_CLK_USDHC4_PODF] = imx_clk_hw_divider("usdhc4_podf", "usdhc4_sel", base + 0x24, 22, 3);
+ hws[IMX6QDL_CLK_ENFC_PRED] = imx_clk_hw_divider("enfc_pred", "enfc_sel", base + 0x2c, 18, 3);
+ hws[IMX6QDL_CLK_ENFC_PODF] = imx_clk_hw_divider("enfc_podf", "enfc_pred", base + 0x2c, 21, 6);
if (clk_on_imx6qp()) {
- clk[IMX6QDL_CLK_EIM_PODF] = imx_clk_divider("eim_podf", "eim_sel", base + 0x1c, 20, 3);
- clk[IMX6QDL_CLK_EIM_SLOW_PODF] = imx_clk_divider("eim_slow_podf", "eim_slow_sel", base + 0x1c, 23, 3);
+ hws[IMX6QDL_CLK_EIM_PODF] = imx_clk_hw_divider("eim_podf", "eim_sel", base + 0x1c, 20, 3);
+ hws[IMX6QDL_CLK_EIM_SLOW_PODF] = imx_clk_hw_divider("eim_slow_podf", "eim_slow_sel", base + 0x1c, 23, 3);
} else {
- clk[IMX6QDL_CLK_EIM_PODF] = imx_clk_fixup_divider("eim_podf", "eim_sel", base + 0x1c, 20, 3, imx_cscmr1_fixup);
- clk[IMX6QDL_CLK_EIM_SLOW_PODF] = imx_clk_fixup_divider("eim_slow_podf", "eim_slow_sel", base + 0x1c, 23, 3, imx_cscmr1_fixup);
+ hws[IMX6QDL_CLK_EIM_PODF] = imx_clk_hw_fixup_divider("eim_podf", "eim_sel", base + 0x1c, 20, 3, imx_cscmr1_fixup);
+ hws[IMX6QDL_CLK_EIM_SLOW_PODF] = imx_clk_hw_fixup_divider("eim_slow_podf", "eim_slow_sel", base + 0x1c, 23, 3, imx_cscmr1_fixup);
}
- clk[IMX6QDL_CLK_VPU_AXI_PODF] = imx_clk_divider("vpu_axi_podf", "vpu_axi_sel", base + 0x24, 25, 3);
- clk[IMX6QDL_CLK_CKO1_PODF] = imx_clk_divider("cko1_podf", "cko1_sel", base + 0x60, 4, 3);
- clk[IMX6QDL_CLK_CKO2_PODF] = imx_clk_divider("cko2_podf", "cko2_sel", base + 0x60, 21, 3);
+
+ hws[IMX6QDL_CLK_VPU_AXI_PODF] = imx_clk_hw_divider("vpu_axi_podf", "vpu_axi_sel", base + 0x24, 25, 3);
+ hws[IMX6QDL_CLK_CKO1_PODF] = imx_clk_hw_divider("cko1_podf", "cko1_sel", base + 0x60, 4, 3);
+ hws[IMX6QDL_CLK_CKO2_PODF] = imx_clk_hw_divider("cko2_podf", "cko2_sel", base + 0x60, 21, 3);
/* name parent_name reg shift width busy: reg, shift */
- clk[IMX6QDL_CLK_AXI] = imx_clk_busy_divider("axi", "axi_sel", base + 0x14, 16, 3, base + 0x48, 0);
- clk[IMX6QDL_CLK_MMDC_CH0_AXI_PODF] = imx_clk_busy_divider("mmdc_ch0_axi_podf", "periph", base + 0x14, 19, 3, base + 0x48, 4);
+ hws[IMX6QDL_CLK_AXI] = imx_clk_hw_busy_divider("axi", "axi_sel", base + 0x14, 16, 3, base + 0x48, 0);
+ hws[IMX6QDL_CLK_MMDC_CH0_AXI_PODF] = imx_clk_hw_busy_divider("mmdc_ch0_axi_podf", "periph", base + 0x14, 19, 3, base + 0x48, 4);
if (clk_on_imx6qp()) {
- clk[IMX6QDL_CLK_MMDC_CH1_AXI_CG] = imx_clk_gate("mmdc_ch1_axi_cg", "periph2", base + 0x4, 18);
- clk[IMX6QDL_CLK_MMDC_CH1_AXI_PODF] = imx_clk_busy_divider("mmdc_ch1_axi_podf", "mmdc_ch1_axi_cg", base + 0x14, 3, 3, base + 0x48, 2);
+ hws[IMX6QDL_CLK_MMDC_CH1_AXI_CG] = imx_clk_hw_gate("mmdc_ch1_axi_cg", "periph2", base + 0x4, 18);
+ hws[IMX6QDL_CLK_MMDC_CH1_AXI_PODF] = imx_clk_hw_busy_divider("mmdc_ch1_axi_podf", "mmdc_ch1_axi_cg", base + 0x14, 3, 3, base + 0x48, 2);
} else {
- clk[IMX6QDL_CLK_MMDC_CH1_AXI_PODF] = imx_clk_busy_divider("mmdc_ch1_axi_podf", "periph2", base + 0x14, 3, 3, base + 0x48, 2);
+ hws[IMX6QDL_CLK_MMDC_CH1_AXI_PODF] = imx_clk_hw_busy_divider("mmdc_ch1_axi_podf", "periph2", base + 0x14, 3, 3, base + 0x48, 2);
}
- clk[IMX6QDL_CLK_ARM] = imx_clk_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16);
- clk[IMX6QDL_CLK_AHB] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1);
+ hws[IMX6QDL_CLK_ARM] = imx_clk_hw_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16);
+ hws[IMX6QDL_CLK_AHB] = imx_clk_hw_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1);
/* name parent_name reg shift */
- clk[IMX6QDL_CLK_APBH_DMA] = imx_clk_gate2("apbh_dma", "usdhc3", base + 0x68, 4);
- clk[IMX6QDL_CLK_ASRC] = imx_clk_gate2_shared("asrc", "asrc_podf", base + 0x68, 6, &share_count_asrc);
- clk[IMX6QDL_CLK_ASRC_IPG] = imx_clk_gate2_shared("asrc_ipg", "ahb", base + 0x68, 6, &share_count_asrc);
- clk[IMX6QDL_CLK_ASRC_MEM] = imx_clk_gate2_shared("asrc_mem", "ahb", base + 0x68, 6, &share_count_asrc);
- clk[IMX6QDL_CLK_CAAM_MEM] = imx_clk_gate2("caam_mem", "ahb", base + 0x68, 8);
- clk[IMX6QDL_CLK_CAAM_ACLK] = imx_clk_gate2("caam_aclk", "ahb", base + 0x68, 10);
- clk[IMX6QDL_CLK_CAAM_IPG] = imx_clk_gate2("caam_ipg", "ipg", base + 0x68, 12);
- clk[IMX6QDL_CLK_CAN1_IPG] = imx_clk_gate2("can1_ipg", "ipg", base + 0x68, 14);
- clk[IMX6QDL_CLK_CAN1_SERIAL] = imx_clk_gate2("can1_serial", "can_root", base + 0x68, 16);
- clk[IMX6QDL_CLK_CAN2_IPG] = imx_clk_gate2("can2_ipg", "ipg", base + 0x68, 18);
- clk[IMX6QDL_CLK_CAN2_SERIAL] = imx_clk_gate2("can2_serial", "can_root", base + 0x68, 20);
- clk[IMX6QDL_CLK_DCIC1] = imx_clk_gate2("dcic1", "ipu1_podf", base + 0x68, 24);
- clk[IMX6QDL_CLK_DCIC2] = imx_clk_gate2("dcic2", "ipu2_podf", base + 0x68, 26);
- clk[IMX6QDL_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_root", base + 0x6c, 0);
- clk[IMX6QDL_CLK_ECSPI2] = imx_clk_gate2("ecspi2", "ecspi_root", base + 0x6c, 2);
- clk[IMX6QDL_CLK_ECSPI3] = imx_clk_gate2("ecspi3", "ecspi_root", base + 0x6c, 4);
- clk[IMX6QDL_CLK_ECSPI4] = imx_clk_gate2("ecspi4", "ecspi_root", base + 0x6c, 6);
+ hws[IMX6QDL_CLK_APBH_DMA] = imx_clk_hw_gate2("apbh_dma", "usdhc3", base + 0x68, 4);
+ hws[IMX6QDL_CLK_ASRC] = imx_clk_hw_gate2_shared("asrc", "asrc_podf", base + 0x68, 6, &share_count_asrc);
+ hws[IMX6QDL_CLK_ASRC_IPG] = imx_clk_hw_gate2_shared("asrc_ipg", "ahb", base + 0x68, 6, &share_count_asrc);
+ hws[IMX6QDL_CLK_ASRC_MEM] = imx_clk_hw_gate2_shared("asrc_mem", "ahb", base + 0x68, 6, &share_count_asrc);
+ hws[IMX6QDL_CLK_CAAM_MEM] = imx_clk_hw_gate2("caam_mem", "ahb", base + 0x68, 8);
+ hws[IMX6QDL_CLK_CAAM_ACLK] = imx_clk_hw_gate2("caam_aclk", "ahb", base + 0x68, 10);
+ hws[IMX6QDL_CLK_CAAM_IPG] = imx_clk_hw_gate2("caam_ipg", "ipg", base + 0x68, 12);
+ hws[IMX6QDL_CLK_CAN1_IPG] = imx_clk_hw_gate2("can1_ipg", "ipg", base + 0x68, 14);
+ hws[IMX6QDL_CLK_CAN1_SERIAL] = imx_clk_hw_gate2("can1_serial", "can_root", base + 0x68, 16);
+ hws[IMX6QDL_CLK_CAN2_IPG] = imx_clk_hw_gate2("can2_ipg", "ipg", base + 0x68, 18);
+ hws[IMX6QDL_CLK_CAN2_SERIAL] = imx_clk_hw_gate2("can2_serial", "can_root", base + 0x68, 20);
+ hws[IMX6QDL_CLK_DCIC1] = imx_clk_hw_gate2("dcic1", "ipu1_podf", base + 0x68, 24);
+ hws[IMX6QDL_CLK_DCIC2] = imx_clk_hw_gate2("dcic2", "ipu2_podf", base + 0x68, 26);
+ hws[IMX6QDL_CLK_ECSPI1] = imx_clk_hw_gate2("ecspi1", "ecspi_root", base + 0x6c, 0);
+ hws[IMX6QDL_CLK_ECSPI2] = imx_clk_hw_gate2("ecspi2", "ecspi_root", base + 0x6c, 2);
+ hws[IMX6QDL_CLK_ECSPI3] = imx_clk_hw_gate2("ecspi3", "ecspi_root", base + 0x6c, 4);
+ hws[IMX6QDL_CLK_ECSPI4] = imx_clk_hw_gate2("ecspi4", "ecspi_root", base + 0x6c, 6);
if (clk_on_imx6dl())
- clk[IMX6DL_CLK_I2C4] = imx_clk_gate2("i2c4", "ipg_per", base + 0x6c, 8);
+ hws[IMX6DL_CLK_I2C4] = imx_clk_hw_gate2("i2c4", "ipg_per", base + 0x6c, 8);
else
- clk[IMX6Q_CLK_ECSPI5] = imx_clk_gate2("ecspi5", "ecspi_root", base + 0x6c, 8);
- clk[IMX6QDL_CLK_ENET] = imx_clk_gate2("enet", "ipg", base + 0x6c, 10);
- clk[IMX6QDL_CLK_EPIT1] = imx_clk_gate2("epit1", "ipg", base + 0x6c, 12);
- clk[IMX6QDL_CLK_EPIT2] = imx_clk_gate2("epit2", "ipg", base + 0x6c, 14);
- clk[IMX6QDL_CLK_ESAI_EXTAL] = imx_clk_gate2_shared("esai_extal", "esai_podf", base + 0x6c, 16, &share_count_esai);
- clk[IMX6QDL_CLK_ESAI_IPG] = imx_clk_gate2_shared("esai_ipg", "ahb", base + 0x6c, 16, &share_count_esai);
- clk[IMX6QDL_CLK_ESAI_MEM] = imx_clk_gate2_shared("esai_mem", "ahb", base + 0x6c, 16, &share_count_esai);
- clk[IMX6QDL_CLK_GPT_IPG] = imx_clk_gate2("gpt_ipg", "ipg", base + 0x6c, 20);
- clk[IMX6QDL_CLK_GPT_IPG_PER] = imx_clk_gate2("gpt_ipg_per", "ipg_per", base + 0x6c, 22);
- clk[IMX6QDL_CLK_GPU2D_CORE] = imx_clk_gate2("gpu2d_core", "gpu2d_core_podf", base + 0x6c, 24);
- clk[IMX6QDL_CLK_GPU3D_CORE] = imx_clk_gate2("gpu3d_core", "gpu3d_core_podf", base + 0x6c, 26);
- clk[IMX6QDL_CLK_HDMI_IAHB] = imx_clk_gate2("hdmi_iahb", "ahb", base + 0x70, 0);
- clk[IMX6QDL_CLK_HDMI_ISFR] = imx_clk_gate2("hdmi_isfr", "mipi_core_cfg", base + 0x70, 4);
- clk[IMX6QDL_CLK_I2C1] = imx_clk_gate2("i2c1", "ipg_per", base + 0x70, 6);
- clk[IMX6QDL_CLK_I2C2] = imx_clk_gate2("i2c2", "ipg_per", base + 0x70, 8);
- clk[IMX6QDL_CLK_I2C3] = imx_clk_gate2("i2c3", "ipg_per", base + 0x70, 10);
- clk[IMX6QDL_CLK_IIM] = imx_clk_gate2("iim", "ipg", base + 0x70, 12);
- clk[IMX6QDL_CLK_ENFC] = imx_clk_gate2("enfc", "enfc_podf", base + 0x70, 14);
- clk[IMX6QDL_CLK_VDOA] = imx_clk_gate2("vdoa", "vdo_axi", base + 0x70, 26);
- clk[IMX6QDL_CLK_IPU1] = imx_clk_gate2("ipu1", "ipu1_podf", base + 0x74, 0);
- clk[IMX6QDL_CLK_IPU1_DI0] = imx_clk_gate2("ipu1_di0", "ipu1_di0_sel", base + 0x74, 2);
- clk[IMX6QDL_CLK_IPU1_DI1] = imx_clk_gate2("ipu1_di1", "ipu1_di1_sel", base + 0x74, 4);
- clk[IMX6QDL_CLK_IPU2] = imx_clk_gate2("ipu2", "ipu2_podf", base + 0x74, 6);
- clk[IMX6QDL_CLK_IPU2_DI0] = imx_clk_gate2("ipu2_di0", "ipu2_di0_sel", base + 0x74, 8);
+ hws[IMX6Q_CLK_ECSPI5] = imx_clk_hw_gate2("ecspi5", "ecspi_root", base + 0x6c, 8);
+ hws[IMX6QDL_CLK_ENET] = imx_clk_hw_gate2("enet", "ipg", base + 0x6c, 10);
+ hws[IMX6QDL_CLK_EPIT1] = imx_clk_hw_gate2("epit1", "ipg", base + 0x6c, 12);
+ hws[IMX6QDL_CLK_EPIT2] = imx_clk_hw_gate2("epit2", "ipg", base + 0x6c, 14);
+ hws[IMX6QDL_CLK_ESAI_EXTAL] = imx_clk_hw_gate2_shared("esai_extal", "esai_podf", base + 0x6c, 16, &share_count_esai);
+ hws[IMX6QDL_CLK_ESAI_IPG] = imx_clk_hw_gate2_shared("esai_ipg", "ahb", base + 0x6c, 16, &share_count_esai);
+ hws[IMX6QDL_CLK_ESAI_MEM] = imx_clk_hw_gate2_shared("esai_mem", "ahb", base + 0x6c, 16, &share_count_esai);
+ hws[IMX6QDL_CLK_GPT_IPG] = imx_clk_hw_gate2("gpt_ipg", "ipg", base + 0x6c, 20);
+ hws[IMX6QDL_CLK_GPT_IPG_PER] = imx_clk_hw_gate2("gpt_ipg_per", "ipg_per", base + 0x6c, 22);
+ hws[IMX6QDL_CLK_GPU2D_CORE] = imx_clk_hw_gate2("gpu2d_core", "gpu2d_core_podf", base + 0x6c, 24);
+ hws[IMX6QDL_CLK_GPU3D_CORE] = imx_clk_hw_gate2("gpu3d_core", "gpu3d_core_podf", base + 0x6c, 26);
+ hws[IMX6QDL_CLK_HDMI_IAHB] = imx_clk_hw_gate2("hdmi_iahb", "ahb", base + 0x70, 0);
+ hws[IMX6QDL_CLK_HDMI_ISFR] = imx_clk_hw_gate2("hdmi_isfr", "mipi_core_cfg", base + 0x70, 4);
+ hws[IMX6QDL_CLK_I2C1] = imx_clk_hw_gate2("i2c1", "ipg_per", base + 0x70, 6);
+ hws[IMX6QDL_CLK_I2C2] = imx_clk_hw_gate2("i2c2", "ipg_per", base + 0x70, 8);
+ hws[IMX6QDL_CLK_I2C3] = imx_clk_hw_gate2("i2c3", "ipg_per", base + 0x70, 10);
+ hws[IMX6QDL_CLK_IIM] = imx_clk_hw_gate2("iim", "ipg", base + 0x70, 12);
+ hws[IMX6QDL_CLK_ENFC] = imx_clk_hw_gate2("enfc", "enfc_podf", base + 0x70, 14);
+ hws[IMX6QDL_CLK_VDOA] = imx_clk_hw_gate2("vdoa", "vdo_axi", base + 0x70, 26);
+ hws[IMX6QDL_CLK_IPU1] = imx_clk_hw_gate2("ipu1", "ipu1_podf", base + 0x74, 0);
+ hws[IMX6QDL_CLK_IPU1_DI0] = imx_clk_hw_gate2("ipu1_di0", "ipu1_di0_sel", base + 0x74, 2);
+ hws[IMX6QDL_CLK_IPU1_DI1] = imx_clk_hw_gate2("ipu1_di1", "ipu1_di1_sel", base + 0x74, 4);
+ hws[IMX6QDL_CLK_IPU2] = imx_clk_hw_gate2("ipu2", "ipu2_podf", base + 0x74, 6);
+ hws[IMX6QDL_CLK_IPU2_DI0] = imx_clk_hw_gate2("ipu2_di0", "ipu2_di0_sel", base + 0x74, 8);
if (clk_on_imx6qp()) {
- clk[IMX6QDL_CLK_LDB_DI0] = imx_clk_gate2("ldb_di0", "ldb_di0_sel", base + 0x74, 12);
- clk[IMX6QDL_CLK_LDB_DI1] = imx_clk_gate2("ldb_di1", "ldb_di1_sel", base + 0x74, 14);
+ hws[IMX6QDL_CLK_LDB_DI0] = imx_clk_hw_gate2("ldb_di0", "ldb_di0_sel", base + 0x74, 12);
+ hws[IMX6QDL_CLK_LDB_DI1] = imx_clk_hw_gate2("ldb_di1", "ldb_di1_sel", base + 0x74, 14);
} else {
- clk[IMX6QDL_CLK_LDB_DI0] = imx_clk_gate2("ldb_di0", "ldb_di0_podf", base + 0x74, 12);
- clk[IMX6QDL_CLK_LDB_DI1] = imx_clk_gate2("ldb_di1", "ldb_di1_podf", base + 0x74, 14);
+ hws[IMX6QDL_CLK_LDB_DI0] = imx_clk_hw_gate2("ldb_di0", "ldb_di0_podf", base + 0x74, 12);
+ hws[IMX6QDL_CLK_LDB_DI1] = imx_clk_hw_gate2("ldb_di1", "ldb_di1_podf", base + 0x74, 14);
}
- clk[IMX6QDL_CLK_IPU2_DI1] = imx_clk_gate2("ipu2_di1", "ipu2_di1_sel", base + 0x74, 10);
- clk[IMX6QDL_CLK_HSI_TX] = imx_clk_gate2_shared("hsi_tx", "hsi_tx_podf", base + 0x74, 16, &share_count_mipi_core_cfg);
- clk[IMX6QDL_CLK_MIPI_CORE_CFG] = imx_clk_gate2_shared("mipi_core_cfg", "video_27m", base + 0x74, 16, &share_count_mipi_core_cfg);
- clk[IMX6QDL_CLK_MIPI_IPG] = imx_clk_gate2_shared("mipi_ipg", "ipg", base + 0x74, 16, &share_count_mipi_core_cfg);
+ hws[IMX6QDL_CLK_IPU2_DI1] = imx_clk_hw_gate2("ipu2_di1", "ipu2_di1_sel", base + 0x74, 10);
+ hws[IMX6QDL_CLK_HSI_TX] = imx_clk_hw_gate2_shared("hsi_tx", "hsi_tx_podf", base + 0x74, 16, &share_count_mipi_core_cfg);
+ hws[IMX6QDL_CLK_MIPI_CORE_CFG] = imx_clk_hw_gate2_shared("mipi_core_cfg", "video_27m", base + 0x74, 16, &share_count_mipi_core_cfg);
+ hws[IMX6QDL_CLK_MIPI_IPG] = imx_clk_hw_gate2_shared("mipi_ipg", "ipg", base + 0x74, 16, &share_count_mipi_core_cfg);
+
if (clk_on_imx6dl())
/*
* The multiplexer and divider of the imx6q clock gpu2d get
* redefined/reused as mlb_sys_sel and mlb_sys_clk_podf on imx6dl.
*/
- clk[IMX6QDL_CLK_MLB] = imx_clk_gate2("mlb", "mlb_podf", base + 0x74, 18);
+ hws[IMX6QDL_CLK_MLB] = imx_clk_hw_gate2("mlb", "mlb_podf", base + 0x74, 18);
else
- clk[IMX6QDL_CLK_MLB] = imx_clk_gate2("mlb", "axi", base + 0x74, 18);
- clk[IMX6QDL_CLK_MMDC_CH0_AXI] = imx_clk_gate2_flags("mmdc_ch0_axi", "mmdc_ch0_axi_podf", base + 0x74, 20, CLK_IS_CRITICAL);
- clk[IMX6QDL_CLK_MMDC_CH1_AXI] = imx_clk_gate2("mmdc_ch1_axi", "mmdc_ch1_axi_podf", base + 0x74, 22);
- clk[IMX6QDL_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
- clk[IMX6QDL_CLK_OCRAM] = imx_clk_gate2("ocram", "ahb", base + 0x74, 28);
- clk[IMX6QDL_CLK_OPENVG_AXI] = imx_clk_gate2("openvg_axi", "axi", base + 0x74, 30);
- clk[IMX6QDL_CLK_PCIE_AXI] = imx_clk_gate2("pcie_axi", "pcie_axi_sel", base + 0x78, 0);
- clk[IMX6QDL_CLK_PER1_BCH] = imx_clk_gate2("per1_bch", "usdhc3", base + 0x78, 12);
- clk[IMX6QDL_CLK_PWM1] = imx_clk_gate2("pwm1", "ipg_per", base + 0x78, 16);
- clk[IMX6QDL_CLK_PWM2] = imx_clk_gate2("pwm2", "ipg_per", base + 0x78, 18);
- clk[IMX6QDL_CLK_PWM3] = imx_clk_gate2("pwm3", "ipg_per", base + 0x78, 20);
- clk[IMX6QDL_CLK_PWM4] = imx_clk_gate2("pwm4", "ipg_per", base + 0x78, 22);
- clk[IMX6QDL_CLK_GPMI_BCH_APB] = imx_clk_gate2("gpmi_bch_apb", "usdhc3", base + 0x78, 24);
- clk[IMX6QDL_CLK_GPMI_BCH] = imx_clk_gate2("gpmi_bch", "usdhc4", base + 0x78, 26);
- clk[IMX6QDL_CLK_GPMI_IO] = imx_clk_gate2("gpmi_io", "enfc", base + 0x78, 28);
- clk[IMX6QDL_CLK_GPMI_APB] = imx_clk_gate2("gpmi_apb", "usdhc3", base + 0x78, 30);
- clk[IMX6QDL_CLK_ROM] = imx_clk_gate2_flags("rom", "ahb", base + 0x7c, 0, CLK_IS_CRITICAL);
- clk[IMX6QDL_CLK_SATA] = imx_clk_gate2("sata", "ahb", base + 0x7c, 4);
- clk[IMX6QDL_CLK_SDMA] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6);
- clk[IMX6QDL_CLK_SPBA] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12);
- clk[IMX6QDL_CLK_SPDIF] = imx_clk_gate2_shared("spdif", "spdif_podf", base + 0x7c, 14, &share_count_spdif);
- clk[IMX6QDL_CLK_SPDIF_GCLK] = imx_clk_gate2_shared("spdif_gclk", "ipg", base + 0x7c, 14, &share_count_spdif);
- clk[IMX6QDL_CLK_SSI1_IPG] = imx_clk_gate2_shared("ssi1_ipg", "ipg", base + 0x7c, 18, &share_count_ssi1);
- clk[IMX6QDL_CLK_SSI2_IPG] = imx_clk_gate2_shared("ssi2_ipg", "ipg", base + 0x7c, 20, &share_count_ssi2);
- clk[IMX6QDL_CLK_SSI3_IPG] = imx_clk_gate2_shared("ssi3_ipg", "ipg", base + 0x7c, 22, &share_count_ssi3);
- clk[IMX6QDL_CLK_SSI1] = imx_clk_gate2_shared("ssi1", "ssi1_podf", base + 0x7c, 18, &share_count_ssi1);
- clk[IMX6QDL_CLK_SSI2] = imx_clk_gate2_shared("ssi2", "ssi2_podf", base + 0x7c, 20, &share_count_ssi2);
- clk[IMX6QDL_CLK_SSI3] = imx_clk_gate2_shared("ssi3", "ssi3_podf", base + 0x7c, 22, &share_count_ssi3);
- clk[IMX6QDL_CLK_UART_IPG] = imx_clk_gate2("uart_ipg", "ipg", base + 0x7c, 24);
- clk[IMX6QDL_CLK_UART_SERIAL] = imx_clk_gate2("uart_serial", "uart_serial_podf", base + 0x7c, 26);
- clk[IMX6QDL_CLK_USBOH3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0);
- clk[IMX6QDL_CLK_USDHC1] = imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2);
- clk[IMX6QDL_CLK_USDHC2] = imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4);
- clk[IMX6QDL_CLK_USDHC3] = imx_clk_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6);
- clk[IMX6QDL_CLK_USDHC4] = imx_clk_gate2("usdhc4", "usdhc4_podf", base + 0x80, 8);
- clk[IMX6QDL_CLK_EIM_SLOW] = imx_clk_gate2("eim_slow", "eim_slow_podf", base + 0x80, 10);
- clk[IMX6QDL_CLK_VDO_AXI] = imx_clk_gate2("vdo_axi", "vdo_axi_sel", base + 0x80, 12);
- clk[IMX6QDL_CLK_VPU_AXI] = imx_clk_gate2("vpu_axi", "vpu_axi_podf", base + 0x80, 14);
+ hws[IMX6QDL_CLK_MLB] = imx_clk_hw_gate2("mlb", "axi", base + 0x74, 18);
+ hws[IMX6QDL_CLK_MMDC_CH0_AXI] = imx_clk_hw_gate2_flags("mmdc_ch0_axi", "mmdc_ch0_axi_podf", base + 0x74, 20, CLK_IS_CRITICAL);
+ hws[IMX6QDL_CLK_MMDC_CH1_AXI] = imx_clk_hw_gate2("mmdc_ch1_axi", "mmdc_ch1_axi_podf", base + 0x74, 22);
+ hws[IMX6QDL_CLK_MMDC_P0_IPG] = imx_clk_hw_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
+ hws[IMX6QDL_CLK_OCRAM] = imx_clk_hw_gate2("ocram", "ahb", base + 0x74, 28);
+ hws[IMX6QDL_CLK_OPENVG_AXI] = imx_clk_hw_gate2("openvg_axi", "axi", base + 0x74, 30);
+ hws[IMX6QDL_CLK_PCIE_AXI] = imx_clk_hw_gate2("pcie_axi", "pcie_axi_sel", base + 0x78, 0);
+ hws[IMX6QDL_CLK_PER1_BCH] = imx_clk_hw_gate2("per1_bch", "usdhc3", base + 0x78, 12);
+ hws[IMX6QDL_CLK_PWM1] = imx_clk_hw_gate2("pwm1", "ipg_per", base + 0x78, 16);
+ hws[IMX6QDL_CLK_PWM2] = imx_clk_hw_gate2("pwm2", "ipg_per", base + 0x78, 18);
+ hws[IMX6QDL_CLK_PWM3] = imx_clk_hw_gate2("pwm3", "ipg_per", base + 0x78, 20);
+ hws[IMX6QDL_CLK_PWM4] = imx_clk_hw_gate2("pwm4", "ipg_per", base + 0x78, 22);
+ hws[IMX6QDL_CLK_GPMI_BCH_APB] = imx_clk_hw_gate2("gpmi_bch_apb", "usdhc3", base + 0x78, 24);
+ hws[IMX6QDL_CLK_GPMI_BCH] = imx_clk_hw_gate2("gpmi_bch", "usdhc4", base + 0x78, 26);
+ hws[IMX6QDL_CLK_GPMI_IO] = imx_clk_hw_gate2("gpmi_io", "enfc", base + 0x78, 28);
+ hws[IMX6QDL_CLK_GPMI_APB] = imx_clk_hw_gate2("gpmi_apb", "usdhc3", base + 0x78, 30);
+ hws[IMX6QDL_CLK_ROM] = imx_clk_hw_gate2_flags("rom", "ahb", base + 0x7c, 0, CLK_IS_CRITICAL);
+ hws[IMX6QDL_CLK_SATA] = imx_clk_hw_gate2("sata", "ahb", base + 0x7c, 4);
+ hws[IMX6QDL_CLK_SDMA] = imx_clk_hw_gate2("sdma", "ahb", base + 0x7c, 6);
+ hws[IMX6QDL_CLK_SPBA] = imx_clk_hw_gate2("spba", "ipg", base + 0x7c, 12);
+ hws[IMX6QDL_CLK_SPDIF] = imx_clk_hw_gate2_shared("spdif", "spdif_podf", base + 0x7c, 14, &share_count_spdif);
+ hws[IMX6QDL_CLK_SPDIF_GCLK] = imx_clk_hw_gate2_shared("spdif_gclk", "ipg", base + 0x7c, 14, &share_count_spdif);
+ hws[IMX6QDL_CLK_SSI1_IPG] = imx_clk_hw_gate2_shared("ssi1_ipg", "ipg", base + 0x7c, 18, &share_count_ssi1);
+ hws[IMX6QDL_CLK_SSI2_IPG] = imx_clk_hw_gate2_shared("ssi2_ipg", "ipg", base + 0x7c, 20, &share_count_ssi2);
+ hws[IMX6QDL_CLK_SSI3_IPG] = imx_clk_hw_gate2_shared("ssi3_ipg", "ipg", base + 0x7c, 22, &share_count_ssi3);
+ hws[IMX6QDL_CLK_SSI1] = imx_clk_hw_gate2_shared("ssi1", "ssi1_podf", base + 0x7c, 18, &share_count_ssi1);
+ hws[IMX6QDL_CLK_SSI2] = imx_clk_hw_gate2_shared("ssi2", "ssi2_podf", base + 0x7c, 20, &share_count_ssi2);
+ hws[IMX6QDL_CLK_SSI3] = imx_clk_hw_gate2_shared("ssi3", "ssi3_podf", base + 0x7c, 22, &share_count_ssi3);
+ hws[IMX6QDL_CLK_UART_IPG] = imx_clk_hw_gate2("uart_ipg", "ipg", base + 0x7c, 24);
+ hws[IMX6QDL_CLK_UART_SERIAL] = imx_clk_hw_gate2("uart_serial", "uart_serial_podf", base + 0x7c, 26);
+ hws[IMX6QDL_CLK_USBOH3] = imx_clk_hw_gate2("usboh3", "ipg", base + 0x80, 0);
+ hws[IMX6QDL_CLK_USDHC1] = imx_clk_hw_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2);
+ hws[IMX6QDL_CLK_USDHC2] = imx_clk_hw_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4);
+ hws[IMX6QDL_CLK_USDHC3] = imx_clk_hw_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6);
+ hws[IMX6QDL_CLK_USDHC4] = imx_clk_hw_gate2("usdhc4", "usdhc4_podf", base + 0x80, 8);
+ hws[IMX6QDL_CLK_EIM_SLOW] = imx_clk_hw_gate2("eim_slow", "eim_slow_podf", base + 0x80, 10);
+ hws[IMX6QDL_CLK_VDO_AXI] = imx_clk_hw_gate2("vdo_axi", "vdo_axi_sel", base + 0x80, 12);
+ hws[IMX6QDL_CLK_VPU_AXI] = imx_clk_hw_gate2("vpu_axi", "vpu_axi_podf", base + 0x80, 14);
if (clk_on_imx6qp()) {
- clk[IMX6QDL_CLK_PRE0] = imx_clk_gate2("pre0", "pre_axi", base + 0x80, 16);
- clk[IMX6QDL_CLK_PRE1] = imx_clk_gate2("pre1", "pre_axi", base + 0x80, 18);
- clk[IMX6QDL_CLK_PRE2] = imx_clk_gate2("pre2", "pre_axi", base + 0x80, 20);
- clk[IMX6QDL_CLK_PRE3] = imx_clk_gate2("pre3", "pre_axi", base + 0x80, 22);
- clk[IMX6QDL_CLK_PRG0_AXI] = imx_clk_gate2_shared("prg0_axi", "ipu1_podf", base + 0x80, 24, &share_count_prg0);
- clk[IMX6QDL_CLK_PRG1_AXI] = imx_clk_gate2_shared("prg1_axi", "ipu2_podf", base + 0x80, 26, &share_count_prg1);
- clk[IMX6QDL_CLK_PRG0_APB] = imx_clk_gate2_shared("prg0_apb", "ipg", base + 0x80, 24, &share_count_prg0);
- clk[IMX6QDL_CLK_PRG1_APB] = imx_clk_gate2_shared("prg1_apb", "ipg", base + 0x80, 26, &share_count_prg1);
+ hws[IMX6QDL_CLK_PRE0] = imx_clk_hw_gate2("pre0", "pre_axi", base + 0x80, 16);
+ hws[IMX6QDL_CLK_PRE1] = imx_clk_hw_gate2("pre1", "pre_axi", base + 0x80, 18);
+ hws[IMX6QDL_CLK_PRE2] = imx_clk_hw_gate2("pre2", "pre_axi", base + 0x80, 20);
+ hws[IMX6QDL_CLK_PRE3] = imx_clk_hw_gate2("pre3", "pre_axi", base + 0x80, 22);
+ hws[IMX6QDL_CLK_PRG0_AXI] = imx_clk_hw_gate2_shared("prg0_axi", "ipu1_podf", base + 0x80, 24, &share_count_prg0);
+ hws[IMX6QDL_CLK_PRG1_AXI] = imx_clk_hw_gate2_shared("prg1_axi", "ipu2_podf", base + 0x80, 26, &share_count_prg1);
+ hws[IMX6QDL_CLK_PRG0_APB] = imx_clk_hw_gate2_shared("prg0_apb", "ipg", base + 0x80, 24, &share_count_prg0);
+ hws[IMX6QDL_CLK_PRG1_APB] = imx_clk_hw_gate2_shared("prg1_apb", "ipg", base + 0x80, 26, &share_count_prg1);
}
- clk[IMX6QDL_CLK_CKO1] = imx_clk_gate("cko1", "cko1_podf", base + 0x60, 7);
- clk[IMX6QDL_CLK_CKO2] = imx_clk_gate("cko2", "cko2_podf", base + 0x60, 24);
+ hws[IMX6QDL_CLK_CKO1] = imx_clk_hw_gate("cko1", "cko1_podf", base + 0x60, 7);
+ hws[IMX6QDL_CLK_CKO2] = imx_clk_hw_gate("cko2", "cko2_podf", base + 0x60, 24);
/*
* The gpt_3m clock is not available on i.MX6Q TO1.0. Let's point it
* to clock gpt_ipg_per to ease the gpt driver code.
*/
if (clk_on_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_1_0)
- clk[IMX6QDL_CLK_GPT_3M] = clk[IMX6QDL_CLK_GPT_IPG_PER];
+ hws[IMX6QDL_CLK_GPT_3M] = hws[IMX6QDL_CLK_GPT_IPG_PER];
- imx_check_clocks(clk, ARRAY_SIZE(clk));
+ imx_check_clk_hws(hws, IMX6QDL_CLK_END);
- clk_data.clks = clk;
- clk_data.clk_num = ARRAY_SIZE(clk);
- of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+ of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
- clk_register_clkdev(clk[IMX6QDL_CLK_ENET_REF], "enet_ref", NULL);
+ clk_hw_register_clkdev(hws[IMX6QDL_CLK_ENET_REF], "enet_ref", NULL);
- clk_set_rate(clk[IMX6QDL_CLK_PLL3_PFD1_540M], 540000000);
+ clk_set_rate(hws[IMX6QDL_CLK_PLL3_PFD1_540M]->clk, 540000000);
if (clk_on_imx6dl())
- clk_set_parent(clk[IMX6QDL_CLK_IPU1_SEL], clk[IMX6QDL_CLK_PLL3_PFD1_540M]);
+ clk_set_parent(hws[IMX6QDL_CLK_IPU1_SEL]->clk, hws[IMX6QDL_CLK_PLL3_PFD1_540M]->clk);
- clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI0_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
- clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI1_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
- clk_set_parent(clk[IMX6QDL_CLK_IPU2_DI0_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
- clk_set_parent(clk[IMX6QDL_CLK_IPU2_DI1_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
- clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI0_SEL], clk[IMX6QDL_CLK_IPU1_DI0_PRE]);
- clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI1_SEL], clk[IMX6QDL_CLK_IPU1_DI1_PRE]);
- clk_set_parent(clk[IMX6QDL_CLK_IPU2_DI0_SEL], clk[IMX6QDL_CLK_IPU2_DI0_PRE]);
- clk_set_parent(clk[IMX6QDL_CLK_IPU2_DI1_SEL], clk[IMX6QDL_CLK_IPU2_DI1_PRE]);
+ clk_set_parent(hws[IMX6QDL_CLK_IPU1_DI0_PRE_SEL]->clk, hws[IMX6QDL_CLK_PLL5_VIDEO_DIV]->clk);
+ clk_set_parent(hws[IMX6QDL_CLK_IPU1_DI1_PRE_SEL]->clk, hws[IMX6QDL_CLK_PLL5_VIDEO_DIV]->clk);
+ clk_set_parent(hws[IMX6QDL_CLK_IPU2_DI0_PRE_SEL]->clk, hws[IMX6QDL_CLK_PLL5_VIDEO_DIV]->clk);
+ clk_set_parent(hws[IMX6QDL_CLK_IPU2_DI1_PRE_SEL]->clk, hws[IMX6QDL_CLK_PLL5_VIDEO_DIV]->clk);
+ clk_set_parent(hws[IMX6QDL_CLK_IPU1_DI0_SEL]->clk, hws[IMX6QDL_CLK_IPU1_DI0_PRE]->clk);
+ clk_set_parent(hws[IMX6QDL_CLK_IPU1_DI1_SEL]->clk, hws[IMX6QDL_CLK_IPU1_DI1_PRE]->clk);
+ clk_set_parent(hws[IMX6QDL_CLK_IPU2_DI0_SEL]->clk, hws[IMX6QDL_CLK_IPU2_DI0_PRE]->clk);
+ clk_set_parent(hws[IMX6QDL_CLK_IPU2_DI1_SEL]->clk, hws[IMX6QDL_CLK_IPU2_DI1_PRE]->clk);
/*
* The gpmi needs 100MHz frequency in the EDO/Sync mode,
* We can not get the 100MHz from the pll2_pfd0_352m.
* So choose pll2_pfd2_396m as enfc_sel's parent.
*/
- clk_set_parent(clk[IMX6QDL_CLK_ENFC_SEL], clk[IMX6QDL_CLK_PLL2_PFD2_396M]);
+ clk_set_parent(hws[IMX6QDL_CLK_ENFC_SEL]->clk, hws[IMX6QDL_CLK_PLL2_PFD2_396M]->clk);
if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
- clk_prepare_enable(clk[IMX6QDL_CLK_USBPHY1_GATE]);
- clk_prepare_enable(clk[IMX6QDL_CLK_USBPHY2_GATE]);
+ clk_prepare_enable(hws[IMX6QDL_CLK_USBPHY1_GATE]->clk);
+ clk_prepare_enable(hws[IMX6QDL_CLK_USBPHY2_GATE]->clk);
}
/*
* Let's initially set up CLKO with OSC24M, since this configuration
* is widely used by imx6q board designs to clock audio codec.
*/
- ret = clk_set_parent(clk[IMX6QDL_CLK_CKO2_SEL], clk[IMX6QDL_CLK_OSC]);
+ ret = clk_set_parent(hws[IMX6QDL_CLK_CKO2_SEL]->clk, hws[IMX6QDL_CLK_OSC]->clk);
if (!ret)
- ret = clk_set_parent(clk[IMX6QDL_CLK_CKO], clk[IMX6QDL_CLK_CKO2]);
+ ret = clk_set_parent(hws[IMX6QDL_CLK_CKO]->clk, hws[IMX6QDL_CLK_CKO2]->clk);
if (ret)
pr_warn("failed to set up CLKO: %d\n", ret);
/* Audio-related clocks configuration */
- clk_set_parent(clk[IMX6QDL_CLK_SPDIF_SEL], clk[IMX6QDL_CLK_PLL3_PFD3_454M]);
+ clk_set_parent(hws[IMX6QDL_CLK_SPDIF_SEL]->clk, hws[IMX6QDL_CLK_PLL3_PFD3_454M]->clk);
/* All existing boards with PCIe use LVDS1 */
if (IS_ENABLED(CONFIG_PCI_IMX6))
- clk_set_parent(clk[IMX6QDL_CLK_LVDS1_SEL], clk[IMX6QDL_CLK_SATA_REF_100M]);
+ clk_set_parent(hws[IMX6QDL_CLK_LVDS1_SEL]->clk, hws[IMX6QDL_CLK_SATA_REF_100M]->clk);
/*
* Initialize the GPU clock muxes, so that the maximum specified clock
* rates for the respective SoC are not exceeded.
*/
if (clk_on_imx6dl()) {
- clk_set_parent(clk[IMX6QDL_CLK_GPU3D_CORE_SEL],
- clk[IMX6QDL_CLK_PLL2_PFD1_594M]);
- clk_set_parent(clk[IMX6QDL_CLK_GPU2D_CORE_SEL],
- clk[IMX6QDL_CLK_PLL2_PFD1_594M]);
+ clk_set_parent(hws[IMX6QDL_CLK_GPU3D_CORE_SEL]->clk,
+ hws[IMX6QDL_CLK_PLL2_PFD1_594M]->clk);
+ clk_set_parent(hws[IMX6QDL_CLK_GPU2D_CORE_SEL]->clk,
+ hws[IMX6QDL_CLK_PLL2_PFD1_594M]->clk);
} else if (clk_on_imx6q()) {
- clk_set_parent(clk[IMX6QDL_CLK_GPU3D_CORE_SEL],
- clk[IMX6QDL_CLK_MMDC_CH0_AXI]);
- clk_set_parent(clk[IMX6QDL_CLK_GPU3D_SHADER_SEL],
- clk[IMX6QDL_CLK_PLL2_PFD1_594M]);
- clk_set_parent(clk[IMX6QDL_CLK_GPU2D_CORE_SEL],
- clk[IMX6QDL_CLK_PLL3_USB_OTG]);
+ clk_set_parent(hws[IMX6QDL_CLK_GPU3D_CORE_SEL]->clk,
+ hws[IMX6QDL_CLK_MMDC_CH0_AXI]->clk);
+ clk_set_parent(hws[IMX6QDL_CLK_GPU3D_SHADER_SEL]->clk,
+ hws[IMX6QDL_CLK_PLL2_PFD1_594M]->clk);
+ clk_set_parent(hws[IMX6QDL_CLK_GPU2D_CORE_SEL]->clk,
+ hws[IMX6QDL_CLK_PLL3_USB_OTG]->clk);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(uart_clk_ids); i++) {
+ int index = uart_clk_ids[i];
+
+ uart_clks[i] = &hws[index]->clk;
}
imx_register_uart_clocks(uart_clks);
diff --git a/drivers/clk/imx/clk-imx6sl.c b/drivers/clk/imx/clk-imx6sl.c
index e13d8814cfa4..4bd44d89eaaa 100644
--- a/drivers/clk/imx/clk-imx6sl.c
+++ b/drivers/clk/imx/clk-imx6sl.c
@@ -1,10 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2013-2014 Freescale Semiconductor, 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.
- *
*/
#include <linux/clk.h>
@@ -17,8 +13,6 @@
#include "clk.h"
-#define CCDR 0x4
-#define BM_CCM_CCDR_MMDC_CH0_MASK (1 << 17)
#define CCSR 0xc
#define BM_CCSR_PLL1_SW_CLK_SEL (1 << 2)
#define CACRR 0x10
@@ -101,8 +95,8 @@ static unsigned int share_count_ssi2;
static unsigned int share_count_ssi3;
static unsigned int share_count_spdif;
-static struct clk *clks[IMX6SL_CLK_END];
-static struct clk_onecell_data clk_data;
+static struct clk_hw **hws;
+static struct clk_hw_onecell_data *clk_hw_data;
static void __iomem *ccm_base;
static void __iomem *anatop_base;
@@ -183,74 +177,84 @@ void imx6sl_set_wait_clk(bool enter)
imx6sl_enable_pll_arm(false);
}
-static struct clk ** const uart_clks[] __initconst = {
- &clks[IMX6SL_CLK_UART],
- &clks[IMX6SL_CLK_UART_SERIAL],
- NULL
+static const int uart_clk_ids[] __initconst = {
+ IMX6SL_CLK_UART,
+ IMX6SL_CLK_UART_SERIAL,
};
+static struct clk **uart_clks[ARRAY_SIZE(uart_clk_ids) + 1] __initdata;
+
static void __init imx6sl_clocks_init(struct device_node *ccm_node)
{
struct device_node *np;
void __iomem *base;
int ret;
+ int i;
+
+ clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
+ IMX6SL_CLK_END), GFP_KERNEL);
+ if (WARN_ON(!clk_hw_data))
+ return;
- clks[IMX6SL_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
- clks[IMX6SL_CLK_CKIL] = imx_obtain_fixed_clock("ckil", 0);
- clks[IMX6SL_CLK_OSC] = imx_obtain_fixed_clock("osc", 0);
+ clk_hw_data->num = IMX6SL_CLK_END;
+ hws = clk_hw_data->hws;
+
+ hws[IMX6SL_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
+ hws[IMX6SL_CLK_CKIL] = imx_obtain_fixed_clock_hw("ckil", 0);
+ hws[IMX6SL_CLK_OSC] = imx_obtain_fixed_clock_hw("osc", 0);
/* Clock source from external clock via CLK1 PAD */
- clks[IMX6SL_CLK_ANACLK1] = imx_obtain_fixed_clock("anaclk1", 0);
+ hws[IMX6SL_CLK_ANACLK1] = imx_obtain_fixed_clock_hw("anaclk1", 0);
np = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-anatop");
base = of_iomap(np, 0);
WARN_ON(!base);
anatop_base = base;
- clks[IMX6SL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
- clks[IMX6SL_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
- clks[IMX6SL_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
- clks[IMX6SL_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
- clks[IMX6SL_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
- clks[IMX6SL_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
- clks[IMX6SL_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6SL_PLL1_BYPASS_SRC] = imx_clk_hw_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6SL_PLL2_BYPASS_SRC] = imx_clk_hw_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6SL_PLL3_BYPASS_SRC] = imx_clk_hw_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6SL_PLL4_BYPASS_SRC] = imx_clk_hw_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6SL_PLL5_BYPASS_SRC] = imx_clk_hw_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6SL_PLL6_BYPASS_SRC] = imx_clk_hw_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6SL_PLL7_BYPASS_SRC] = imx_clk_hw_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
/* type name parent_name base div_mask */
- clks[IMX6SL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "osc", base + 0x00, 0x7f);
- clks[IMX6SL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
- clks[IMX6SL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "osc", base + 0x10, 0x3);
- clks[IMX6SL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "osc", base + 0x70, 0x7f);
- clks[IMX6SL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "osc", base + 0xa0, 0x7f);
- clks[IMX6SL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "osc", base + 0xe0, 0x3);
- clks[IMX6SL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "osc", base + 0x20, 0x3);
-
- clks[IMX6SL_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
- clks[IMX6SL_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
- clks[IMX6SL_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
- clks[IMX6SL_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
- clks[IMX6SL_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
- clks[IMX6SL_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
- clks[IMX6SL_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6SL_CLK_PLL1] = imx_clk_hw_pllv3(IMX_PLLV3_SYS, "pll1", "osc", base + 0x00, 0x7f);
+ hws[IMX6SL_CLK_PLL2] = imx_clk_hw_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
+ hws[IMX6SL_CLK_PLL3] = imx_clk_hw_pllv3(IMX_PLLV3_USB, "pll3", "osc", base + 0x10, 0x3);
+ hws[IMX6SL_CLK_PLL4] = imx_clk_hw_pllv3(IMX_PLLV3_AV, "pll4", "osc", base + 0x70, 0x7f);
+ hws[IMX6SL_CLK_PLL5] = imx_clk_hw_pllv3(IMX_PLLV3_AV, "pll5", "osc", base + 0xa0, 0x7f);
+ hws[IMX6SL_CLK_PLL6] = imx_clk_hw_pllv3(IMX_PLLV3_ENET, "pll6", "osc", base + 0xe0, 0x3);
+ hws[IMX6SL_CLK_PLL7] = imx_clk_hw_pllv3(IMX_PLLV3_USB, "pll7", "osc", base + 0x20, 0x3);
+
+ hws[IMX6SL_PLL1_BYPASS] = imx_clk_hw_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6SL_PLL2_BYPASS] = imx_clk_hw_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6SL_PLL3_BYPASS] = imx_clk_hw_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6SL_PLL4_BYPASS] = imx_clk_hw_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6SL_PLL5_BYPASS] = imx_clk_hw_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6SL_PLL6_BYPASS] = imx_clk_hw_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6SL_PLL7_BYPASS] = imx_clk_hw_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
/* Do not bypass PLLs initially */
- clk_set_parent(clks[IMX6SL_PLL1_BYPASS], clks[IMX6SL_CLK_PLL1]);
- clk_set_parent(clks[IMX6SL_PLL2_BYPASS], clks[IMX6SL_CLK_PLL2]);
- clk_set_parent(clks[IMX6SL_PLL3_BYPASS], clks[IMX6SL_CLK_PLL3]);
- clk_set_parent(clks[IMX6SL_PLL4_BYPASS], clks[IMX6SL_CLK_PLL4]);
- clk_set_parent(clks[IMX6SL_PLL5_BYPASS], clks[IMX6SL_CLK_PLL5]);
- clk_set_parent(clks[IMX6SL_PLL6_BYPASS], clks[IMX6SL_CLK_PLL6]);
- clk_set_parent(clks[IMX6SL_PLL7_BYPASS], clks[IMX6SL_CLK_PLL7]);
-
- clks[IMX6SL_CLK_PLL1_SYS] = imx_clk_gate("pll1_sys", "pll1_bypass", base + 0x00, 13);
- clks[IMX6SL_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", base + 0x30, 13);
- clks[IMX6SL_CLK_PLL3_USB_OTG] = imx_clk_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13);
- clks[IMX6SL_CLK_PLL4_AUDIO] = imx_clk_gate("pll4_audio", "pll4_bypass", base + 0x70, 13);
- clks[IMX6SL_CLK_PLL5_VIDEO] = imx_clk_gate("pll5_video", "pll5_bypass", base + 0xa0, 13);
- clks[IMX6SL_CLK_PLL6_ENET] = imx_clk_gate("pll6_enet", "pll6_bypass", base + 0xe0, 13);
- clks[IMX6SL_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
-
- clks[IMX6SL_CLK_LVDS1_SEL] = imx_clk_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
- clks[IMX6SL_CLK_LVDS1_OUT] = imx_clk_gate_exclusive("lvds1_out", "lvds1_sel", base + 0x160, 10, BIT(12));
- clks[IMX6SL_CLK_LVDS1_IN] = imx_clk_gate_exclusive("lvds1_in", "anaclk1", base + 0x160, 12, BIT(10));
+ clk_set_parent(hws[IMX6SL_PLL1_BYPASS]->clk, hws[IMX6SL_CLK_PLL1]->clk);
+ clk_set_parent(hws[IMX6SL_PLL2_BYPASS]->clk, hws[IMX6SL_CLK_PLL2]->clk);
+ clk_set_parent(hws[IMX6SL_PLL3_BYPASS]->clk, hws[IMX6SL_CLK_PLL3]->clk);
+ clk_set_parent(hws[IMX6SL_PLL4_BYPASS]->clk, hws[IMX6SL_CLK_PLL4]->clk);
+ clk_set_parent(hws[IMX6SL_PLL5_BYPASS]->clk, hws[IMX6SL_CLK_PLL5]->clk);
+ clk_set_parent(hws[IMX6SL_PLL6_BYPASS]->clk, hws[IMX6SL_CLK_PLL6]->clk);
+ clk_set_parent(hws[IMX6SL_PLL7_BYPASS]->clk, hws[IMX6SL_CLK_PLL7]->clk);
+
+ hws[IMX6SL_CLK_PLL1_SYS] = imx_clk_hw_gate("pll1_sys", "pll1_bypass", base + 0x00, 13);
+ hws[IMX6SL_CLK_PLL2_BUS] = imx_clk_hw_gate("pll2_bus", "pll2_bypass", base + 0x30, 13);
+ hws[IMX6SL_CLK_PLL3_USB_OTG] = imx_clk_hw_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13);
+ hws[IMX6SL_CLK_PLL4_AUDIO] = imx_clk_hw_gate("pll4_audio", "pll4_bypass", base + 0x70, 13);
+ hws[IMX6SL_CLK_PLL5_VIDEO] = imx_clk_hw_gate("pll5_video", "pll5_bypass", base + 0xa0, 13);
+ hws[IMX6SL_CLK_PLL6_ENET] = imx_clk_hw_gate("pll6_enet", "pll6_bypass", base + 0xe0, 13);
+ hws[IMX6SL_CLK_PLL7_USB_HOST] = imx_clk_hw_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
+
+ hws[IMX6SL_CLK_LVDS1_SEL] = imx_clk_hw_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
+ hws[IMX6SL_CLK_LVDS1_OUT] = imx_clk_hw_gate_exclusive("lvds1_out", "lvds1_sel", base + 0x160, 10, BIT(12));
+ hws[IMX6SL_CLK_LVDS1_IN] = imx_clk_hw_gate_exclusive("lvds1_in", "anaclk1", base + 0x160, 12, BIT(10));
/*
* usbphy1 and usbphy2 are implemented as dummy gates using reserve
@@ -259,32 +263,32 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
* turned on during boot, and software will not need to control it
* anymore after that.
*/
- clks[IMX6SL_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20);
- clks[IMX6SL_CLK_USBPHY2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
- clks[IMX6SL_CLK_USBPHY1_GATE] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6);
- clks[IMX6SL_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6);
+ hws[IMX6SL_CLK_USBPHY1] = imx_clk_hw_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20);
+ hws[IMX6SL_CLK_USBPHY2] = imx_clk_hw_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
+ hws[IMX6SL_CLK_USBPHY1_GATE] = imx_clk_hw_gate("usbphy1_gate", "dummy", base + 0x10, 6);
+ hws[IMX6SL_CLK_USBPHY2_GATE] = imx_clk_hw_gate("usbphy2_gate", "dummy", base + 0x20, 6);
/* dev name parent_name flags reg shift width div: flags, div_table lock */
- clks[IMX6SL_CLK_PLL4_POST_DIV] = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio", CLK_SET_RATE_PARENT, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock);
- clks[IMX6SL_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT, base + 0x170, 15, 1, 0, &imx_ccm_lock);
- clks[IMX6SL_CLK_PLL5_POST_DIV] = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video", CLK_SET_RATE_PARENT, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock);
- clks[IMX6SL_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", CLK_SET_RATE_PARENT, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock);
- clks[IMX6SL_CLK_ENET_REF] = clk_register_divider_table(NULL, "enet_ref", "pll6_enet", 0, base + 0xe0, 0, 2, 0, clk_enet_ref_table, &imx_ccm_lock);
+ hws[IMX6SL_CLK_PLL4_POST_DIV] = clk_hw_register_divider_table(NULL, "pll4_post_div", "pll4_audio", CLK_SET_RATE_PARENT, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock);
+ hws[IMX6SL_CLK_PLL4_AUDIO_DIV] = clk_hw_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT, base + 0x170, 15, 1, 0, &imx_ccm_lock);
+ hws[IMX6SL_CLK_PLL5_POST_DIV] = clk_hw_register_divider_table(NULL, "pll5_post_div", "pll5_video", CLK_SET_RATE_PARENT, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock);
+ hws[IMX6SL_CLK_PLL5_VIDEO_DIV] = clk_hw_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", CLK_SET_RATE_PARENT, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock);
+ hws[IMX6SL_CLK_ENET_REF] = clk_hw_register_divider_table(NULL, "enet_ref", "pll6_enet", 0, base + 0xe0, 0, 2, 0, clk_enet_ref_table, &imx_ccm_lock);
/* name parent_name reg idx */
- clks[IMX6SL_CLK_PLL2_PFD0] = imx_clk_pfd("pll2_pfd0", "pll2_bus", base + 0x100, 0);
- clks[IMX6SL_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1", "pll2_bus", base + 0x100, 1);
- clks[IMX6SL_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2", "pll2_bus", base + 0x100, 2);
- clks[IMX6SL_CLK_PLL3_PFD0] = imx_clk_pfd("pll3_pfd0", "pll3_usb_otg", base + 0xf0, 0);
- clks[IMX6SL_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1", "pll3_usb_otg", base + 0xf0, 1);
- clks[IMX6SL_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2", "pll3_usb_otg", base + 0xf0, 2);
- clks[IMX6SL_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3", "pll3_usb_otg", base + 0xf0, 3);
+ hws[IMX6SL_CLK_PLL2_PFD0] = imx_clk_hw_pfd("pll2_pfd0", "pll2_bus", base + 0x100, 0);
+ hws[IMX6SL_CLK_PLL2_PFD1] = imx_clk_hw_pfd("pll2_pfd1", "pll2_bus", base + 0x100, 1);
+ hws[IMX6SL_CLK_PLL2_PFD2] = imx_clk_hw_pfd("pll2_pfd2", "pll2_bus", base + 0x100, 2);
+ hws[IMX6SL_CLK_PLL3_PFD0] = imx_clk_hw_pfd("pll3_pfd0", "pll3_usb_otg", base + 0xf0, 0);
+ hws[IMX6SL_CLK_PLL3_PFD1] = imx_clk_hw_pfd("pll3_pfd1", "pll3_usb_otg", base + 0xf0, 1);
+ hws[IMX6SL_CLK_PLL3_PFD2] = imx_clk_hw_pfd("pll3_pfd2", "pll3_usb_otg", base + 0xf0, 2);
+ hws[IMX6SL_CLK_PLL3_PFD3] = imx_clk_hw_pfd("pll3_pfd3", "pll3_usb_otg", base + 0xf0, 3);
/* name parent_name mult div */
- clks[IMX6SL_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2", 1, 2);
- clks[IMX6SL_CLK_PLL3_120M] = imx_clk_fixed_factor("pll3_120m", "pll3_usb_otg", 1, 4);
- clks[IMX6SL_CLK_PLL3_80M] = imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6);
- clks[IMX6SL_CLK_PLL3_60M] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8);
+ hws[IMX6SL_CLK_PLL2_198M] = imx_clk_hw_fixed_factor("pll2_198m", "pll2_pfd2", 1, 2);
+ hws[IMX6SL_CLK_PLL3_120M] = imx_clk_hw_fixed_factor("pll3_120m", "pll3_usb_otg", 1, 4);
+ hws[IMX6SL_CLK_PLL3_80M] = imx_clk_hw_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6);
+ hws[IMX6SL_CLK_PLL3_60M] = imx_clk_hw_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8);
np = ccm_node;
base = of_iomap(np, 0);
@@ -292,157 +296,160 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
ccm_base = base;
/* name reg shift width parent_names num_parents */
- clks[IMX6SL_CLK_STEP] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels));
- clks[IMX6SL_CLK_PLL1_SW] = imx_clk_mux("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels));
- clks[IMX6SL_CLK_OCRAM_ALT_SEL] = imx_clk_mux("ocram_alt_sel", base + 0x14, 7, 1, ocram_alt_sels, ARRAY_SIZE(ocram_alt_sels));
- clks[IMX6SL_CLK_OCRAM_SEL] = imx_clk_mux("ocram_sel", base + 0x14, 6, 1, ocram_sels, ARRAY_SIZE(ocram_sels));
- clks[IMX6SL_CLK_PRE_PERIPH2_SEL] = imx_clk_mux("pre_periph2_sel", base + 0x18, 21, 2, pre_periph_sels, ARRAY_SIZE(pre_periph_sels));
- clks[IMX6SL_CLK_PRE_PERIPH_SEL] = imx_clk_mux("pre_periph_sel", base + 0x18, 18, 2, pre_periph_sels, ARRAY_SIZE(pre_periph_sels));
- clks[IMX6SL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
- clks[IMX6SL_CLK_PERIPH_CLK2_SEL] = imx_clk_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
- clks[IMX6SL_CLK_CSI_SEL] = imx_clk_mux("csi_sel", base + 0x3c, 9, 2, csi_sels, ARRAY_SIZE(csi_sels));
- clks[IMX6SL_CLK_LCDIF_AXI_SEL] = imx_clk_mux("lcdif_axi_sel", base + 0x3c, 14, 2, lcdif_axi_sels, ARRAY_SIZE(lcdif_axi_sels));
- clks[IMX6SL_CLK_USDHC1_SEL] = imx_clk_fixup_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
- clks[IMX6SL_CLK_USDHC2_SEL] = imx_clk_fixup_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
- clks[IMX6SL_CLK_USDHC3_SEL] = imx_clk_fixup_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
- clks[IMX6SL_CLK_USDHC4_SEL] = imx_clk_fixup_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
- clks[IMX6SL_CLK_SSI1_SEL] = imx_clk_fixup_mux("ssi1_sel", base + 0x1c, 10, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup);
- clks[IMX6SL_CLK_SSI2_SEL] = imx_clk_fixup_mux("ssi2_sel", base + 0x1c, 12, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup);
- clks[IMX6SL_CLK_SSI3_SEL] = imx_clk_fixup_mux("ssi3_sel", base + 0x1c, 14, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup);
- clks[IMX6SL_CLK_PERCLK_SEL] = imx_clk_fixup_mux("perclk_sel", base + 0x1c, 6, 1, perclk_sels, ARRAY_SIZE(perclk_sels), imx_cscmr1_fixup);
- clks[IMX6SL_CLK_PXP_AXI_SEL] = imx_clk_mux("pxp_axi_sel", base + 0x34, 6, 3, pxp_axi_sels, ARRAY_SIZE(pxp_axi_sels));
- clks[IMX6SL_CLK_EPDC_AXI_SEL] = imx_clk_mux("epdc_axi_sel", base + 0x34, 15, 3, epdc_axi_sels, ARRAY_SIZE(epdc_axi_sels));
- clks[IMX6SL_CLK_GPU2D_OVG_SEL] = imx_clk_mux("gpu2d_ovg_sel", base + 0x18, 4, 2, gpu2d_ovg_sels, ARRAY_SIZE(gpu2d_ovg_sels));
- clks[IMX6SL_CLK_GPU2D_SEL] = imx_clk_mux("gpu2d_sel", base + 0x18, 8, 2, gpu2d_sels, ARRAY_SIZE(gpu2d_sels));
- clks[IMX6SL_CLK_LCDIF_PIX_SEL] = imx_clk_mux("lcdif_pix_sel", base + 0x38, 6, 3, lcdif_pix_sels, ARRAY_SIZE(lcdif_pix_sels));
- clks[IMX6SL_CLK_EPDC_PIX_SEL] = imx_clk_mux("epdc_pix_sel", base + 0x38, 15, 3, epdc_pix_sels, ARRAY_SIZE(epdc_pix_sels));
- clks[IMX6SL_CLK_SPDIF0_SEL] = imx_clk_mux("spdif0_sel", base + 0x30, 20, 2, audio_sels, ARRAY_SIZE(audio_sels));
- clks[IMX6SL_CLK_SPDIF1_SEL] = imx_clk_mux("spdif1_sel", base + 0x30, 7, 2, audio_sels, ARRAY_SIZE(audio_sels));
- clks[IMX6SL_CLK_EXTERN_AUDIO_SEL] = imx_clk_mux("extern_audio_sel", base + 0x20, 19, 2, audio_sels, ARRAY_SIZE(audio_sels));
- clks[IMX6SL_CLK_ECSPI_SEL] = imx_clk_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels));
- clks[IMX6SL_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels));
+ hws[IMX6SL_CLK_STEP] = imx_clk_hw_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels));
+ hws[IMX6SL_CLK_PLL1_SW] = imx_clk_hw_mux("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels));
+ hws[IMX6SL_CLK_OCRAM_ALT_SEL] = imx_clk_hw_mux("ocram_alt_sel", base + 0x14, 7, 1, ocram_alt_sels, ARRAY_SIZE(ocram_alt_sels));
+ hws[IMX6SL_CLK_OCRAM_SEL] = imx_clk_hw_mux("ocram_sel", base + 0x14, 6, 1, ocram_sels, ARRAY_SIZE(ocram_sels));
+ hws[IMX6SL_CLK_PRE_PERIPH2_SEL] = imx_clk_hw_mux("pre_periph2_sel", base + 0x18, 21, 2, pre_periph_sels, ARRAY_SIZE(pre_periph_sels));
+ hws[IMX6SL_CLK_PRE_PERIPH_SEL] = imx_clk_hw_mux("pre_periph_sel", base + 0x18, 18, 2, pre_periph_sels, ARRAY_SIZE(pre_periph_sels));
+ hws[IMX6SL_CLK_PERIPH2_CLK2_SEL] = imx_clk_hw_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
+ hws[IMX6SL_CLK_PERIPH_CLK2_SEL] = imx_clk_hw_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
+ hws[IMX6SL_CLK_CSI_SEL] = imx_clk_hw_mux("csi_sel", base + 0x3c, 9, 2, csi_sels, ARRAY_SIZE(csi_sels));
+ hws[IMX6SL_CLK_LCDIF_AXI_SEL] = imx_clk_hw_mux("lcdif_axi_sel", base + 0x3c, 14, 2, lcdif_axi_sels, ARRAY_SIZE(lcdif_axi_sels));
+ hws[IMX6SL_CLK_USDHC1_SEL] = imx_clk_hw_fixup_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
+ hws[IMX6SL_CLK_USDHC2_SEL] = imx_clk_hw_fixup_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
+ hws[IMX6SL_CLK_USDHC3_SEL] = imx_clk_hw_fixup_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
+ hws[IMX6SL_CLK_USDHC4_SEL] = imx_clk_hw_fixup_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
+ hws[IMX6SL_CLK_SSI1_SEL] = imx_clk_hw_fixup_mux("ssi1_sel", base + 0x1c, 10, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup);
+ hws[IMX6SL_CLK_SSI2_SEL] = imx_clk_hw_fixup_mux("ssi2_sel", base + 0x1c, 12, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup);
+ hws[IMX6SL_CLK_SSI3_SEL] = imx_clk_hw_fixup_mux("ssi3_sel", base + 0x1c, 14, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup);
+ hws[IMX6SL_CLK_PERCLK_SEL] = imx_clk_hw_fixup_mux("perclk_sel", base + 0x1c, 6, 1, perclk_sels, ARRAY_SIZE(perclk_sels), imx_cscmr1_fixup);
+ hws[IMX6SL_CLK_PXP_AXI_SEL] = imx_clk_hw_mux("pxp_axi_sel", base + 0x34, 6, 3, pxp_axi_sels, ARRAY_SIZE(pxp_axi_sels));
+ hws[IMX6SL_CLK_EPDC_AXI_SEL] = imx_clk_hw_mux("epdc_axi_sel", base + 0x34, 15, 3, epdc_axi_sels, ARRAY_SIZE(epdc_axi_sels));
+ hws[IMX6SL_CLK_GPU2D_OVG_SEL] = imx_clk_hw_mux("gpu2d_ovg_sel", base + 0x18, 4, 2, gpu2d_ovg_sels, ARRAY_SIZE(gpu2d_ovg_sels));
+ hws[IMX6SL_CLK_GPU2D_SEL] = imx_clk_hw_mux("gpu2d_sel", base + 0x18, 8, 2, gpu2d_sels, ARRAY_SIZE(gpu2d_sels));
+ hws[IMX6SL_CLK_LCDIF_PIX_SEL] = imx_clk_hw_mux("lcdif_pix_sel", base + 0x38, 6, 3, lcdif_pix_sels, ARRAY_SIZE(lcdif_pix_sels));
+ hws[IMX6SL_CLK_EPDC_PIX_SEL] = imx_clk_hw_mux("epdc_pix_sel", base + 0x38, 15, 3, epdc_pix_sels, ARRAY_SIZE(epdc_pix_sels));
+ hws[IMX6SL_CLK_SPDIF0_SEL] = imx_clk_hw_mux("spdif0_sel", base + 0x30, 20, 2, audio_sels, ARRAY_SIZE(audio_sels));
+ hws[IMX6SL_CLK_SPDIF1_SEL] = imx_clk_hw_mux("spdif1_sel", base + 0x30, 7, 2, audio_sels, ARRAY_SIZE(audio_sels));
+ hws[IMX6SL_CLK_EXTERN_AUDIO_SEL] = imx_clk_hw_mux("extern_audio_sel", base + 0x20, 19, 2, audio_sels, ARRAY_SIZE(audio_sels));
+ hws[IMX6SL_CLK_ECSPI_SEL] = imx_clk_hw_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels));
+ hws[IMX6SL_CLK_UART_SEL] = imx_clk_hw_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels));
/* name reg shift width busy: reg, shift parent_names num_parents */
- clks[IMX6SL_CLK_PERIPH] = imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels));
- clks[IMX6SL_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels));
+ hws[IMX6SL_CLK_PERIPH] = imx_clk_hw_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels));
+ hws[IMX6SL_CLK_PERIPH2] = imx_clk_hw_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels));
/* name parent_name reg shift width */
- clks[IMX6SL_CLK_OCRAM_PODF] = imx_clk_busy_divider("ocram_podf", "ocram_sel", base + 0x14, 16, 3, base + 0x48, 0);
- clks[IMX6SL_CLK_PERIPH_CLK2_PODF] = imx_clk_divider("periph_clk2_podf", "periph_clk2_sel", base + 0x14, 27, 3);
- clks[IMX6SL_CLK_PERIPH2_CLK2_PODF] = imx_clk_divider("periph2_clk2_podf", "periph2_clk2_sel", base + 0x14, 0, 3);
- clks[IMX6SL_CLK_IPG] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2);
- clks[IMX6SL_CLK_CSI_PODF] = imx_clk_divider("csi_podf", "csi_sel", base + 0x3c, 11, 3);
- clks[IMX6SL_CLK_LCDIF_AXI_PODF] = imx_clk_divider("lcdif_axi_podf", "lcdif_axi_sel", base + 0x3c, 16, 3);
- clks[IMX6SL_CLK_USDHC1_PODF] = imx_clk_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3);
- clks[IMX6SL_CLK_USDHC2_PODF] = imx_clk_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3);
- clks[IMX6SL_CLK_USDHC3_PODF] = imx_clk_divider("usdhc3_podf", "usdhc3_sel", base + 0x24, 19, 3);
- clks[IMX6SL_CLK_USDHC4_PODF] = imx_clk_divider("usdhc4_podf", "usdhc4_sel", base + 0x24, 22, 3);
- clks[IMX6SL_CLK_SSI1_PRED] = imx_clk_divider("ssi1_pred", "ssi1_sel", base + 0x28, 6, 3);
- clks[IMX6SL_CLK_SSI1_PODF] = imx_clk_divider("ssi1_podf", "ssi1_pred", base + 0x28, 0, 6);
- clks[IMX6SL_CLK_SSI2_PRED] = imx_clk_divider("ssi2_pred", "ssi2_sel", base + 0x2c, 6, 3);
- clks[IMX6SL_CLK_SSI2_PODF] = imx_clk_divider("ssi2_podf", "ssi2_pred", base + 0x2c, 0, 6);
- clks[IMX6SL_CLK_SSI3_PRED] = imx_clk_divider("ssi3_pred", "ssi3_sel", base + 0x28, 22, 3);
- clks[IMX6SL_CLK_SSI3_PODF] = imx_clk_divider("ssi3_podf", "ssi3_pred", base + 0x28, 16, 6);
- clks[IMX6SL_CLK_PERCLK] = imx_clk_fixup_divider("perclk", "perclk_sel", base + 0x1c, 0, 6, imx_cscmr1_fixup);
- clks[IMX6SL_CLK_PXP_AXI_PODF] = imx_clk_divider("pxp_axi_podf", "pxp_axi_sel", base + 0x34, 3, 3);
- clks[IMX6SL_CLK_EPDC_AXI_PODF] = imx_clk_divider("epdc_axi_podf", "epdc_axi_sel", base + 0x34, 12, 3);
- clks[IMX6SL_CLK_GPU2D_OVG_PODF] = imx_clk_divider("gpu2d_ovg_podf", "gpu2d_ovg_sel", base + 0x18, 26, 3);
- clks[IMX6SL_CLK_GPU2D_PODF] = imx_clk_divider("gpu2d_podf", "gpu2d_sel", base + 0x18, 29, 3);
- clks[IMX6SL_CLK_LCDIF_PIX_PRED] = imx_clk_divider("lcdif_pix_pred", "lcdif_pix_sel", base + 0x38, 3, 3);
- clks[IMX6SL_CLK_EPDC_PIX_PRED] = imx_clk_divider("epdc_pix_pred", "epdc_pix_sel", base + 0x38, 12, 3);
- clks[IMX6SL_CLK_LCDIF_PIX_PODF] = imx_clk_fixup_divider("lcdif_pix_podf", "lcdif_pix_pred", base + 0x1c, 20, 3, imx_cscmr1_fixup);
- clks[IMX6SL_CLK_EPDC_PIX_PODF] = imx_clk_divider("epdc_pix_podf", "epdc_pix_pred", base + 0x18, 23, 3);
- clks[IMX6SL_CLK_SPDIF0_PRED] = imx_clk_divider("spdif0_pred", "spdif0_sel", base + 0x30, 25, 3);
- clks[IMX6SL_CLK_SPDIF0_PODF] = imx_clk_divider("spdif0_podf", "spdif0_pred", base + 0x30, 22, 3);
- clks[IMX6SL_CLK_SPDIF1_PRED] = imx_clk_divider("spdif1_pred", "spdif1_sel", base + 0x30, 12, 3);
- clks[IMX6SL_CLK_SPDIF1_PODF] = imx_clk_divider("spdif1_podf", "spdif1_pred", base + 0x30, 9, 3);
- clks[IMX6SL_CLK_EXTERN_AUDIO_PRED] = imx_clk_divider("extern_audio_pred", "extern_audio_sel", base + 0x28, 9, 3);
- clks[IMX6SL_CLK_EXTERN_AUDIO_PODF] = imx_clk_divider("extern_audio_podf", "extern_audio_pred", base + 0x28, 25, 3);
- clks[IMX6SL_CLK_ECSPI_ROOT] = imx_clk_divider("ecspi_root", "ecspi_sel", base + 0x38, 19, 6);
- clks[IMX6SL_CLK_UART_ROOT] = imx_clk_divider("uart_root", "uart_sel", base + 0x24, 0, 6);
+ hws[IMX6SL_CLK_OCRAM_PODF] = imx_clk_hw_busy_divider("ocram_podf", "ocram_sel", base + 0x14, 16, 3, base + 0x48, 0);
+ hws[IMX6SL_CLK_PERIPH_CLK2_PODF] = imx_clk_hw_divider("periph_clk2_podf", "periph_clk2_sel", base + 0x14, 27, 3);
+ hws[IMX6SL_CLK_PERIPH2_CLK2_PODF] = imx_clk_hw_divider("periph2_clk2_podf", "periph2_clk2_sel", base + 0x14, 0, 3);
+ hws[IMX6SL_CLK_IPG] = imx_clk_hw_divider("ipg", "ahb", base + 0x14, 8, 2);
+ hws[IMX6SL_CLK_CSI_PODF] = imx_clk_hw_divider("csi_podf", "csi_sel", base + 0x3c, 11, 3);
+ hws[IMX6SL_CLK_LCDIF_AXI_PODF] = imx_clk_hw_divider("lcdif_axi_podf", "lcdif_axi_sel", base + 0x3c, 16, 3);
+ hws[IMX6SL_CLK_USDHC1_PODF] = imx_clk_hw_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3);
+ hws[IMX6SL_CLK_USDHC2_PODF] = imx_clk_hw_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3);
+ hws[IMX6SL_CLK_USDHC3_PODF] = imx_clk_hw_divider("usdhc3_podf", "usdhc3_sel", base + 0x24, 19, 3);
+ hws[IMX6SL_CLK_USDHC4_PODF] = imx_clk_hw_divider("usdhc4_podf", "usdhc4_sel", base + 0x24, 22, 3);
+ hws[IMX6SL_CLK_SSI1_PRED] = imx_clk_hw_divider("ssi1_pred", "ssi1_sel", base + 0x28, 6, 3);
+ hws[IMX6SL_CLK_SSI1_PODF] = imx_clk_hw_divider("ssi1_podf", "ssi1_pred", base + 0x28, 0, 6);
+ hws[IMX6SL_CLK_SSI2_PRED] = imx_clk_hw_divider("ssi2_pred", "ssi2_sel", base + 0x2c, 6, 3);
+ hws[IMX6SL_CLK_SSI2_PODF] = imx_clk_hw_divider("ssi2_podf", "ssi2_pred", base + 0x2c, 0, 6);
+ hws[IMX6SL_CLK_SSI3_PRED] = imx_clk_hw_divider("ssi3_pred", "ssi3_sel", base + 0x28, 22, 3);
+ hws[IMX6SL_CLK_SSI3_PODF] = imx_clk_hw_divider("ssi3_podf", "ssi3_pred", base + 0x28, 16, 6);
+ hws[IMX6SL_CLK_PERCLK] = imx_clk_hw_fixup_divider("perclk", "perclk_sel", base + 0x1c, 0, 6, imx_cscmr1_fixup);
+ hws[IMX6SL_CLK_PXP_AXI_PODF] = imx_clk_hw_divider("pxp_axi_podf", "pxp_axi_sel", base + 0x34, 3, 3);
+ hws[IMX6SL_CLK_EPDC_AXI_PODF] = imx_clk_hw_divider("epdc_axi_podf", "epdc_axi_sel", base + 0x34, 12, 3);
+ hws[IMX6SL_CLK_GPU2D_OVG_PODF] = imx_clk_hw_divider("gpu2d_ovg_podf", "gpu2d_ovg_sel", base + 0x18, 26, 3);
+ hws[IMX6SL_CLK_GPU2D_PODF] = imx_clk_hw_divider("gpu2d_podf", "gpu2d_sel", base + 0x18, 29, 3);
+ hws[IMX6SL_CLK_LCDIF_PIX_PRED] = imx_clk_hw_divider("lcdif_pix_pred", "lcdif_pix_sel", base + 0x38, 3, 3);
+ hws[IMX6SL_CLK_EPDC_PIX_PRED] = imx_clk_hw_divider("epdc_pix_pred", "epdc_pix_sel", base + 0x38, 12, 3);
+ hws[IMX6SL_CLK_LCDIF_PIX_PODF] = imx_clk_hw_fixup_divider("lcdif_pix_podf", "lcdif_pix_pred", base + 0x1c, 20, 3, imx_cscmr1_fixup);
+ hws[IMX6SL_CLK_EPDC_PIX_PODF] = imx_clk_hw_divider("epdc_pix_podf", "epdc_pix_pred", base + 0x18, 23, 3);
+ hws[IMX6SL_CLK_SPDIF0_PRED] = imx_clk_hw_divider("spdif0_pred", "spdif0_sel", base + 0x30, 25, 3);
+ hws[IMX6SL_CLK_SPDIF0_PODF] = imx_clk_hw_divider("spdif0_podf", "spdif0_pred", base + 0x30, 22, 3);
+ hws[IMX6SL_CLK_SPDIF1_PRED] = imx_clk_hw_divider("spdif1_pred", "spdif1_sel", base + 0x30, 12, 3);
+ hws[IMX6SL_CLK_SPDIF1_PODF] = imx_clk_hw_divider("spdif1_podf", "spdif1_pred", base + 0x30, 9, 3);
+ hws[IMX6SL_CLK_EXTERN_AUDIO_PRED] = imx_clk_hw_divider("extern_audio_pred", "extern_audio_sel", base + 0x28, 9, 3);
+ hws[IMX6SL_CLK_EXTERN_AUDIO_PODF] = imx_clk_hw_divider("extern_audio_podf", "extern_audio_pred", base + 0x28, 25, 3);
+ hws[IMX6SL_CLK_ECSPI_ROOT] = imx_clk_hw_divider("ecspi_root", "ecspi_sel", base + 0x38, 19, 6);
+ hws[IMX6SL_CLK_UART_ROOT] = imx_clk_hw_divider("uart_root", "uart_sel", base + 0x24, 0, 6);
/* name parent_name reg shift width busy: reg, shift */
- clks[IMX6SL_CLK_AHB] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1);
- clks[IMX6SL_CLK_MMDC_ROOT] = imx_clk_busy_divider("mmdc", "periph2", base + 0x14, 3, 3, base + 0x48, 2);
- clks[IMX6SL_CLK_ARM] = imx_clk_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16);
+ hws[IMX6SL_CLK_AHB] = imx_clk_hw_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1);
+ hws[IMX6SL_CLK_MMDC_ROOT] = imx_clk_hw_busy_divider("mmdc", "periph2", base + 0x14, 3, 3, base + 0x48, 2);
+ hws[IMX6SL_CLK_ARM] = imx_clk_hw_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16);
/* name parent_name reg shift */
- clks[IMX6SL_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_root", base + 0x6c, 0);
- clks[IMX6SL_CLK_ECSPI2] = imx_clk_gate2("ecspi2", "ecspi_root", base + 0x6c, 2);
- clks[IMX6SL_CLK_ECSPI3] = imx_clk_gate2("ecspi3", "ecspi_root", base + 0x6c, 4);
- clks[IMX6SL_CLK_ECSPI4] = imx_clk_gate2("ecspi4", "ecspi_root", base + 0x6c, 6);
- clks[IMX6SL_CLK_ENET] = imx_clk_gate2("enet", "ipg", base + 0x6c, 10);
- clks[IMX6SL_CLK_EPIT1] = imx_clk_gate2("epit1", "perclk", base + 0x6c, 12);
- clks[IMX6SL_CLK_EPIT2] = imx_clk_gate2("epit2", "perclk", base + 0x6c, 14);
- clks[IMX6SL_CLK_EXTERN_AUDIO] = imx_clk_gate2("extern_audio", "extern_audio_podf", base + 0x6c, 16);
- clks[IMX6SL_CLK_GPT] = imx_clk_gate2("gpt", "perclk", base + 0x6c, 20);
- clks[IMX6SL_CLK_GPT_SERIAL] = imx_clk_gate2("gpt_serial", "perclk", base + 0x6c, 22);
- clks[IMX6SL_CLK_GPU2D_OVG] = imx_clk_gate2("gpu2d_ovg", "gpu2d_ovg_podf", base + 0x6c, 26);
- clks[IMX6SL_CLK_I2C1] = imx_clk_gate2("i2c1", "perclk", base + 0x70, 6);
- clks[IMX6SL_CLK_I2C2] = imx_clk_gate2("i2c2", "perclk", base + 0x70, 8);
- clks[IMX6SL_CLK_I2C3] = imx_clk_gate2("i2c3", "perclk", base + 0x70, 10);
- clks[IMX6SL_CLK_OCOTP] = imx_clk_gate2("ocotp", "ipg", base + 0x70, 12);
- clks[IMX6SL_CLK_CSI] = imx_clk_gate2("csi", "csi_podf", base + 0x74, 0);
- clks[IMX6SL_CLK_PXP_AXI] = imx_clk_gate2("pxp_axi", "pxp_axi_podf", base + 0x74, 2);
- clks[IMX6SL_CLK_EPDC_AXI] = imx_clk_gate2("epdc_axi", "epdc_axi_podf", base + 0x74, 4);
- clks[IMX6SL_CLK_LCDIF_AXI] = imx_clk_gate2("lcdif_axi", "lcdif_axi_podf", base + 0x74, 6);
- clks[IMX6SL_CLK_LCDIF_PIX] = imx_clk_gate2("lcdif_pix", "lcdif_pix_podf", base + 0x74, 8);
- clks[IMX6SL_CLK_EPDC_PIX] = imx_clk_gate2("epdc_pix", "epdc_pix_podf", base + 0x74, 10);
- clks[IMX6SL_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
- clks[IMX6SL_CLK_MMDC_P1_IPG] = imx_clk_gate2("mmdc_p1_ipg", "ipg", base + 0x74, 26);
- clks[IMX6SL_CLK_OCRAM] = imx_clk_gate2("ocram", "ocram_podf", base + 0x74, 28);
- clks[IMX6SL_CLK_PWM1] = imx_clk_gate2("pwm1", "perclk", base + 0x78, 16);
- clks[IMX6SL_CLK_PWM2] = imx_clk_gate2("pwm2", "perclk", base + 0x78, 18);
- clks[IMX6SL_CLK_PWM3] = imx_clk_gate2("pwm3", "perclk", base + 0x78, 20);
- clks[IMX6SL_CLK_PWM4] = imx_clk_gate2("pwm4", "perclk", base + 0x78, 22);
- clks[IMX6SL_CLK_SDMA] = imx_clk_gate2("sdma", "ipg", base + 0x7c, 6);
- clks[IMX6SL_CLK_SPBA] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12);
- clks[IMX6SL_CLK_SPDIF] = imx_clk_gate2_shared("spdif", "spdif0_podf", base + 0x7c, 14, &share_count_spdif);
- clks[IMX6SL_CLK_SPDIF_GCLK] = imx_clk_gate2_shared("spdif_gclk", "ipg", base + 0x7c, 14, &share_count_spdif);
- clks[IMX6SL_CLK_SSI1_IPG] = imx_clk_gate2_shared("ssi1_ipg", "ipg", base + 0x7c, 18, &share_count_ssi1);
- clks[IMX6SL_CLK_SSI2_IPG] = imx_clk_gate2_shared("ssi2_ipg", "ipg", base + 0x7c, 20, &share_count_ssi2);
- clks[IMX6SL_CLK_SSI3_IPG] = imx_clk_gate2_shared("ssi3_ipg", "ipg", base + 0x7c, 22, &share_count_ssi3);
- clks[IMX6SL_CLK_SSI1] = imx_clk_gate2_shared("ssi1", "ssi1_podf", base + 0x7c, 18, &share_count_ssi1);
- clks[IMX6SL_CLK_SSI2] = imx_clk_gate2_shared("ssi2", "ssi2_podf", base + 0x7c, 20, &share_count_ssi2);
- clks[IMX6SL_CLK_SSI3] = imx_clk_gate2_shared("ssi3", "ssi3_podf", base + 0x7c, 22, &share_count_ssi3);
- clks[IMX6SL_CLK_UART] = imx_clk_gate2("uart", "ipg", base + 0x7c, 24);
- clks[IMX6SL_CLK_UART_SERIAL] = imx_clk_gate2("uart_serial", "uart_root", base + 0x7c, 26);
- clks[IMX6SL_CLK_USBOH3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0);
- clks[IMX6SL_CLK_USDHC1] = imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2);
- clks[IMX6SL_CLK_USDHC2] = imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4);
- clks[IMX6SL_CLK_USDHC3] = imx_clk_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6);
- clks[IMX6SL_CLK_USDHC4] = imx_clk_gate2("usdhc4", "usdhc4_podf", base + 0x80, 8);
+ hws[IMX6SL_CLK_ECSPI1] = imx_clk_hw_gate2("ecspi1", "ecspi_root", base + 0x6c, 0);
+ hws[IMX6SL_CLK_ECSPI2] = imx_clk_hw_gate2("ecspi2", "ecspi_root", base + 0x6c, 2);
+ hws[IMX6SL_CLK_ECSPI3] = imx_clk_hw_gate2("ecspi3", "ecspi_root", base + 0x6c, 4);
+ hws[IMX6SL_CLK_ECSPI4] = imx_clk_hw_gate2("ecspi4", "ecspi_root", base + 0x6c, 6);
+ hws[IMX6SL_CLK_ENET] = imx_clk_hw_gate2("enet", "ipg", base + 0x6c, 10);
+ hws[IMX6SL_CLK_EPIT1] = imx_clk_hw_gate2("epit1", "perclk", base + 0x6c, 12);
+ hws[IMX6SL_CLK_EPIT2] = imx_clk_hw_gate2("epit2", "perclk", base + 0x6c, 14);
+ hws[IMX6SL_CLK_EXTERN_AUDIO] = imx_clk_hw_gate2("extern_audio", "extern_audio_podf", base + 0x6c, 16);
+ hws[IMX6SL_CLK_GPT] = imx_clk_hw_gate2("gpt", "perclk", base + 0x6c, 20);
+ hws[IMX6SL_CLK_GPT_SERIAL] = imx_clk_hw_gate2("gpt_serial", "perclk", base + 0x6c, 22);
+ hws[IMX6SL_CLK_GPU2D_OVG] = imx_clk_hw_gate2("gpu2d_ovg", "gpu2d_ovg_podf", base + 0x6c, 26);
+ hws[IMX6SL_CLK_I2C1] = imx_clk_hw_gate2("i2c1", "perclk", base + 0x70, 6);
+ hws[IMX6SL_CLK_I2C2] = imx_clk_hw_gate2("i2c2", "perclk", base + 0x70, 8);
+ hws[IMX6SL_CLK_I2C3] = imx_clk_hw_gate2("i2c3", "perclk", base + 0x70, 10);
+ hws[IMX6SL_CLK_OCOTP] = imx_clk_hw_gate2("ocotp", "ipg", base + 0x70, 12);
+ hws[IMX6SL_CLK_CSI] = imx_clk_hw_gate2("csi", "csi_podf", base + 0x74, 0);
+ hws[IMX6SL_CLK_PXP_AXI] = imx_clk_hw_gate2("pxp_axi", "pxp_axi_podf", base + 0x74, 2);
+ hws[IMX6SL_CLK_EPDC_AXI] = imx_clk_hw_gate2("epdc_axi", "epdc_axi_podf", base + 0x74, 4);
+ hws[IMX6SL_CLK_LCDIF_AXI] = imx_clk_hw_gate2("lcdif_axi", "lcdif_axi_podf", base + 0x74, 6);
+ hws[IMX6SL_CLK_LCDIF_PIX] = imx_clk_hw_gate2("lcdif_pix", "lcdif_pix_podf", base + 0x74, 8);
+ hws[IMX6SL_CLK_EPDC_PIX] = imx_clk_hw_gate2("epdc_pix", "epdc_pix_podf", base + 0x74, 10);
+ hws[IMX6SL_CLK_MMDC_P0_IPG] = imx_clk_hw_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
+ hws[IMX6SL_CLK_MMDC_P1_IPG] = imx_clk_hw_gate2("mmdc_p1_ipg", "ipg", base + 0x74, 26);
+ hws[IMX6SL_CLK_OCRAM] = imx_clk_hw_gate2("ocram", "ocram_podf", base + 0x74, 28);
+ hws[IMX6SL_CLK_PWM1] = imx_clk_hw_gate2("pwm1", "perclk", base + 0x78, 16);
+ hws[IMX6SL_CLK_PWM2] = imx_clk_hw_gate2("pwm2", "perclk", base + 0x78, 18);
+ hws[IMX6SL_CLK_PWM3] = imx_clk_hw_gate2("pwm3", "perclk", base + 0x78, 20);
+ hws[IMX6SL_CLK_PWM4] = imx_clk_hw_gate2("pwm4", "perclk", base + 0x78, 22);
+ hws[IMX6SL_CLK_SDMA] = imx_clk_hw_gate2("sdma", "ipg", base + 0x7c, 6);
+ hws[IMX6SL_CLK_SPBA] = imx_clk_hw_gate2("spba", "ipg", base + 0x7c, 12);
+ hws[IMX6SL_CLK_SPDIF] = imx_clk_hw_gate2_shared("spdif", "spdif0_podf", base + 0x7c, 14, &share_count_spdif);
+ hws[IMX6SL_CLK_SPDIF_GCLK] = imx_clk_hw_gate2_shared("spdif_gclk", "ipg", base + 0x7c, 14, &share_count_spdif);
+ hws[IMX6SL_CLK_SSI1_IPG] = imx_clk_hw_gate2_shared("ssi1_ipg", "ipg", base + 0x7c, 18, &share_count_ssi1);
+ hws[IMX6SL_CLK_SSI2_IPG] = imx_clk_hw_gate2_shared("ssi2_ipg", "ipg", base + 0x7c, 20, &share_count_ssi2);
+ hws[IMX6SL_CLK_SSI3_IPG] = imx_clk_hw_gate2_shared("ssi3_ipg", "ipg", base + 0x7c, 22, &share_count_ssi3);
+ hws[IMX6SL_CLK_SSI1] = imx_clk_hw_gate2_shared("ssi1", "ssi1_podf", base + 0x7c, 18, &share_count_ssi1);
+ hws[IMX6SL_CLK_SSI2] = imx_clk_hw_gate2_shared("ssi2", "ssi2_podf", base + 0x7c, 20, &share_count_ssi2);
+ hws[IMX6SL_CLK_SSI3] = imx_clk_hw_gate2_shared("ssi3", "ssi3_podf", base + 0x7c, 22, &share_count_ssi3);
+ hws[IMX6SL_CLK_UART] = imx_clk_hw_gate2("uart", "ipg", base + 0x7c, 24);
+ hws[IMX6SL_CLK_UART_SERIAL] = imx_clk_hw_gate2("uart_serial", "uart_root", base + 0x7c, 26);
+ hws[IMX6SL_CLK_USBOH3] = imx_clk_hw_gate2("usboh3", "ipg", base + 0x80, 0);
+ hws[IMX6SL_CLK_USDHC1] = imx_clk_hw_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2);
+ hws[IMX6SL_CLK_USDHC2] = imx_clk_hw_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4);
+ hws[IMX6SL_CLK_USDHC3] = imx_clk_hw_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6);
+ hws[IMX6SL_CLK_USDHC4] = imx_clk_hw_gate2("usdhc4", "usdhc4_podf", base + 0x80, 8);
/* Ensure the MMDC CH0 handshake is bypassed */
- writel_relaxed(readl_relaxed(base + CCDR) |
- BM_CCM_CCDR_MMDC_CH0_MASK, base + CCDR);
+ imx_mmdc_mask_handshake(base, 0);
- imx_check_clocks(clks, ARRAY_SIZE(clks));
+ imx_check_clk_hws(hws, IMX6SL_CLK_END);
- clk_data.clks = clks;
- clk_data.clk_num = ARRAY_SIZE(clks);
- of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+ of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
/* Ensure the AHB clk is at 132MHz. */
- ret = clk_set_rate(clks[IMX6SL_CLK_AHB], 132000000);
+ ret = clk_set_rate(hws[IMX6SL_CLK_AHB]->clk, 132000000);
if (ret)
pr_warn("%s: failed to set AHB clock rate %d!\n",
__func__, ret);
if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
- clk_prepare_enable(clks[IMX6SL_CLK_USBPHY1_GATE]);
- clk_prepare_enable(clks[IMX6SL_CLK_USBPHY2_GATE]);
+ clk_prepare_enable(hws[IMX6SL_CLK_USBPHY1_GATE]->clk);
+ clk_prepare_enable(hws[IMX6SL_CLK_USBPHY2_GATE]->clk);
}
/* Audio-related clocks configuration */
- clk_set_parent(clks[IMX6SL_CLK_SPDIF0_SEL], clks[IMX6SL_CLK_PLL3_PFD3]);
+ clk_set_parent(hws[IMX6SL_CLK_SPDIF0_SEL]->clk, hws[IMX6SL_CLK_PLL3_PFD3]->clk);
/* set PLL5 video as lcdif pix parent clock */
- clk_set_parent(clks[IMX6SL_CLK_LCDIF_PIX_SEL],
- clks[IMX6SL_CLK_PLL5_VIDEO_DIV]);
+ clk_set_parent(hws[IMX6SL_CLK_LCDIF_PIX_SEL]->clk,
+ hws[IMX6SL_CLK_PLL5_VIDEO_DIV]->clk);
+
+ clk_set_parent(hws[IMX6SL_CLK_LCDIF_AXI_SEL]->clk,
+ hws[IMX6SL_CLK_PLL2_PFD2]->clk);
- clk_set_parent(clks[IMX6SL_CLK_LCDIF_AXI_SEL],
- clks[IMX6SL_CLK_PLL2_PFD2]);
+ for (i = 0; i < ARRAY_SIZE(uart_clk_ids); i++) {
+ int index = uart_clk_ids[i];
+
+ uart_clks[i] = &hws[index]->clk;
+ }
imx_register_uart_clocks(uart_clks);
}
diff --git a/drivers/clk/imx/clk-imx6sll.c b/drivers/clk/imx/clk-imx6sll.c
index 7eea448cb9a9..5f3e92c09a5e 100644
--- a/drivers/clk/imx/clk-imx6sll.c
+++ b/drivers/clk/imx/clk-imx6sll.c
@@ -7,6 +7,7 @@
#include <dt-bindings/clock/imx6sll-clock.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
@@ -16,7 +17,6 @@
#include "clk.h"
#define CCM_ANALOG_PLL_BYPASS (0x1 << 16)
-#define BM_CCM_CCDR_MMDC_CH0_MASK (0x2 << 16)
#define xPLL_CLR(offset) (offset + 0x8)
static const char *pll_bypass_src_sels[] = { "osc", "dummy", };
@@ -53,8 +53,8 @@ static const char *lcdif_sels[] = { "lcdif_podf", "ipp_di0", "ipp_di1", "ldb_di0
static const char *epdc_pre_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd2_508m", };
static const char *epdc_sels[] = { "epdc_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", };
-static struct clk *clks[IMX6SLL_CLK_END];
-static struct clk_onecell_data clk_data;
+static struct clk_hw **hws;
+static struct clk_hw_onecell_data *clk_hw_data;
static const struct clk_div_table post_div_table[] = {
{ .val = 2, .div = 1, },
@@ -76,33 +76,43 @@ static u32 share_count_ssi1;
static u32 share_count_ssi2;
static u32 share_count_ssi3;
-static struct clk ** const uart_clks[] __initconst = {
- &clks[IMX6SLL_CLK_UART1_IPG],
- &clks[IMX6SLL_CLK_UART1_SERIAL],
- &clks[IMX6SLL_CLK_UART2_IPG],
- &clks[IMX6SLL_CLK_UART2_SERIAL],
- &clks[IMX6SLL_CLK_UART3_IPG],
- &clks[IMX6SLL_CLK_UART3_SERIAL],
- &clks[IMX6SLL_CLK_UART4_IPG],
- &clks[IMX6SLL_CLK_UART4_SERIAL],
- &clks[IMX6SLL_CLK_UART5_IPG],
- &clks[IMX6SLL_CLK_UART5_SERIAL],
- NULL
+static const int uart_clk_ids[] __initconst = {
+ IMX6SLL_CLK_UART1_IPG,
+ IMX6SLL_CLK_UART1_SERIAL,
+ IMX6SLL_CLK_UART2_IPG,
+ IMX6SLL_CLK_UART2_SERIAL,
+ IMX6SLL_CLK_UART3_IPG,
+ IMX6SLL_CLK_UART3_SERIAL,
+ IMX6SLL_CLK_UART4_IPG,
+ IMX6SLL_CLK_UART4_SERIAL,
+ IMX6SLL_CLK_UART5_IPG,
+ IMX6SLL_CLK_UART5_SERIAL,
};
+static struct clk **uart_clks[ARRAY_SIZE(uart_clk_ids) + 1] __initdata;
+
static void __init imx6sll_clocks_init(struct device_node *ccm_node)
{
struct device_node *np;
void __iomem *base;
+ int i;
+
+ clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
+ IMX6SLL_CLK_END), GFP_KERNEL);
+ if (WARN_ON(!clk_hw_data))
+ return;
+
+ clk_hw_data->num = IMX6SLL_CLK_END;
+ hws = clk_hw_data->hws;
- clks[IMX6SLL_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
+ hws[IMX6SLL_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
- clks[IMX6SLL_CLK_CKIL] = of_clk_get_by_name(ccm_node, "ckil");
- clks[IMX6SLL_CLK_OSC] = of_clk_get_by_name(ccm_node, "osc");
+ hws[IMX6SLL_CLK_CKIL] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ckil"));
+ hws[IMX6SLL_CLK_OSC] = __clk_get_hw(of_clk_get_by_name(ccm_node, "osc"));
/* ipp_di clock is external input */
- clks[IMX6SLL_CLK_IPP_DI0] = of_clk_get_by_name(ccm_node, "ipp_di0");
- clks[IMX6SLL_CLK_IPP_DI1] = of_clk_get_by_name(ccm_node, "ipp_di1");
+ hws[IMX6SLL_CLK_IPP_DI0] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ipp_di0"));
+ hws[IMX6SLL_CLK_IPP_DI1] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ipp_di1"));
np = of_find_compatible_node(NULL, NULL, "fsl,imx6sll-anatop");
base = of_iomap(np, 0);
@@ -118,37 +128,37 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node)
writel_relaxed(CCM_ANALOG_PLL_BYPASS, base + xPLL_CLR(0xa0));
writel_relaxed(CCM_ANALOG_PLL_BYPASS, base + xPLL_CLR(0xe0));
- clks[IMX6SLL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
- clks[IMX6SLL_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
- clks[IMX6SLL_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
- clks[IMX6SLL_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
- clks[IMX6SLL_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
- clks[IMX6SLL_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
- clks[IMX6SLL_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-
- clks[IMX6SLL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "pll1_bypass_src", base + 0x00, 0x7f);
- clks[IMX6SLL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", base + 0x30, 0x1);
- clks[IMX6SLL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "pll3_bypass_src", base + 0x10, 0x3);
- clks[IMX6SLL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "pll4_bypass_src", base + 0x70, 0x7f);
- clks[IMX6SLL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "pll5_bypass_src", base + 0xa0, 0x7f);
- clks[IMX6SLL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "pll6_bypass_src", base + 0xe0, 0x3);
- clks[IMX6SLL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "pll7_bypass_src", base + 0x20, 0x3);
-
- clks[IMX6SLL_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
- clks[IMX6SLL_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
- clks[IMX6SLL_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
- clks[IMX6SLL_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
- clks[IMX6SLL_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
- clks[IMX6SLL_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
- clks[IMX6SLL_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
-
- clks[IMX6SLL_CLK_PLL1_SYS] = imx_clk_fixed_factor("pll1_sys", "pll1_bypass", 1, 1);
- clks[IMX6SLL_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", base + 0x30, 13);
- clks[IMX6SLL_CLK_PLL3_USB_OTG] = imx_clk_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13);
- clks[IMX6SLL_CLK_PLL4_AUDIO] = imx_clk_gate("pll4_audio", "pll4_bypass", base + 0x70, 13);
- clks[IMX6SLL_CLK_PLL5_VIDEO] = imx_clk_gate("pll5_video", "pll5_bypass", base + 0xa0, 13);
- clks[IMX6SLL_CLK_PLL6_ENET] = imx_clk_gate("pll6_enet", "pll6_bypass", base + 0xe0, 13);
- clks[IMX6SLL_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
+ hws[IMX6SLL_PLL1_BYPASS_SRC] = imx_clk_hw_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6SLL_PLL2_BYPASS_SRC] = imx_clk_hw_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6SLL_PLL3_BYPASS_SRC] = imx_clk_hw_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6SLL_PLL4_BYPASS_SRC] = imx_clk_hw_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6SLL_PLL5_BYPASS_SRC] = imx_clk_hw_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6SLL_PLL6_BYPASS_SRC] = imx_clk_hw_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6SLL_PLL7_BYPASS_SRC] = imx_clk_hw_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+
+ hws[IMX6SLL_CLK_PLL1] = imx_clk_hw_pllv3(IMX_PLLV3_SYS, "pll1", "pll1_bypass_src", base + 0x00, 0x7f);
+ hws[IMX6SLL_CLK_PLL2] = imx_clk_hw_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", base + 0x30, 0x1);
+ hws[IMX6SLL_CLK_PLL3] = imx_clk_hw_pllv3(IMX_PLLV3_USB, "pll3", "pll3_bypass_src", base + 0x10, 0x3);
+ hws[IMX6SLL_CLK_PLL4] = imx_clk_hw_pllv3(IMX_PLLV3_AV, "pll4", "pll4_bypass_src", base + 0x70, 0x7f);
+ hws[IMX6SLL_CLK_PLL5] = imx_clk_hw_pllv3(IMX_PLLV3_AV, "pll5", "pll5_bypass_src", base + 0xa0, 0x7f);
+ hws[IMX6SLL_CLK_PLL6] = imx_clk_hw_pllv3(IMX_PLLV3_ENET, "pll6", "pll6_bypass_src", base + 0xe0, 0x3);
+ hws[IMX6SLL_CLK_PLL7] = imx_clk_hw_pllv3(IMX_PLLV3_USB, "pll7", "pll7_bypass_src", base + 0x20, 0x3);
+
+ hws[IMX6SLL_PLL1_BYPASS] = imx_clk_hw_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6SLL_PLL2_BYPASS] = imx_clk_hw_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6SLL_PLL3_BYPASS] = imx_clk_hw_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6SLL_PLL4_BYPASS] = imx_clk_hw_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6SLL_PLL5_BYPASS] = imx_clk_hw_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6SLL_PLL6_BYPASS] = imx_clk_hw_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6SLL_PLL7_BYPASS] = imx_clk_hw_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
+
+ hws[IMX6SLL_CLK_PLL1_SYS] = imx_clk_hw_fixed_factor("pll1_sys", "pll1_bypass", 1, 1);
+ hws[IMX6SLL_CLK_PLL2_BUS] = imx_clk_hw_gate("pll2_bus", "pll2_bypass", base + 0x30, 13);
+ hws[IMX6SLL_CLK_PLL3_USB_OTG] = imx_clk_hw_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13);
+ hws[IMX6SLL_CLK_PLL4_AUDIO] = imx_clk_hw_gate("pll4_audio", "pll4_bypass", base + 0x70, 13);
+ hws[IMX6SLL_CLK_PLL5_VIDEO] = imx_clk_hw_gate("pll5_video", "pll5_bypass", base + 0xa0, 13);
+ hws[IMX6SLL_CLK_PLL6_ENET] = imx_clk_hw_gate("pll6_enet", "pll6_bypass", base + 0xe0, 13);
+ hws[IMX6SLL_CLK_PLL7_USB_HOST] = imx_clk_hw_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
/*
* Bit 20 is the reserved and read-only bit, we do this only for:
@@ -156,209 +166,213 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node)
* - Keep refcount when do usbphy clk_enable/disable, in that case,
* the clk framework many need to enable/disable usbphy's parent
*/
- clks[IMX6SLL_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20);
- clks[IMX6SLL_CLK_USBPHY2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
+ hws[IMX6SLL_CLK_USBPHY1] = imx_clk_hw_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20);
+ hws[IMX6SLL_CLK_USBPHY2] = imx_clk_hw_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
/*
* usbphy*_gate needs to be on after system boots up, and software
* never needs to control it anymore.
*/
if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
- clks[IMX6SLL_CLK_USBPHY1_GATE] = imx_clk_gate_flags("usbphy1_gate", "dummy", base + 0x10, 6, CLK_IS_CRITICAL);
- clks[IMX6SLL_CLK_USBPHY2_GATE] = imx_clk_gate_flags("usbphy2_gate", "dummy", base + 0x20, 6, CLK_IS_CRITICAL);
+ hws[IMX6SLL_CLK_USBPHY1_GATE] = imx_clk_hw_gate_flags("usbphy1_gate", "dummy", base + 0x10, 6, CLK_IS_CRITICAL);
+ hws[IMX6SLL_CLK_USBPHY2_GATE] = imx_clk_hw_gate_flags("usbphy2_gate", "dummy", base + 0x20, 6, CLK_IS_CRITICAL);
}
/* name parent_name reg idx */
- clks[IMX6SLL_CLK_PLL2_PFD0] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0);
- clks[IMX6SLL_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1);
- clks[IMX6SLL_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2);
- clks[IMX6SLL_CLK_PLL2_PFD3] = imx_clk_pfd("pll2_pfd3_594m", "pll2_bus", base + 0x100, 3);
- clks[IMX6SLL_CLK_PLL3_PFD0] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0);
- clks[IMX6SLL_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1);
- clks[IMX6SLL_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2);
- clks[IMX6SLL_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3);
-
- clks[IMX6SLL_CLK_PLL4_POST_DIV] = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio",
+ hws[IMX6SLL_CLK_PLL2_PFD0] = imx_clk_hw_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0);
+ hws[IMX6SLL_CLK_PLL2_PFD1] = imx_clk_hw_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1);
+ hws[IMX6SLL_CLK_PLL2_PFD2] = imx_clk_hw_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2);
+ hws[IMX6SLL_CLK_PLL2_PFD3] = imx_clk_hw_pfd("pll2_pfd3_594m", "pll2_bus", base + 0x100, 3);
+ hws[IMX6SLL_CLK_PLL3_PFD0] = imx_clk_hw_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0);
+ hws[IMX6SLL_CLK_PLL3_PFD1] = imx_clk_hw_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1);
+ hws[IMX6SLL_CLK_PLL3_PFD2] = imx_clk_hw_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2);
+ hws[IMX6SLL_CLK_PLL3_PFD3] = imx_clk_hw_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3);
+
+ hws[IMX6SLL_CLK_PLL4_POST_DIV] = clk_hw_register_divider_table(NULL, "pll4_post_div", "pll4_audio",
CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock);
- clks[IMX6SLL_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div",
+ hws[IMX6SLL_CLK_PLL4_AUDIO_DIV] = clk_hw_register_divider(NULL, "pll4_audio_div", "pll4_post_div",
CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 15, 1, 0, &imx_ccm_lock);
- clks[IMX6SLL_CLK_PLL5_POST_DIV] = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video",
+ hws[IMX6SLL_CLK_PLL5_POST_DIV] = clk_hw_register_divider_table(NULL, "pll5_post_div", "pll5_video",
CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock);
- clks[IMX6SLL_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div",
+ hws[IMX6SLL_CLK_PLL5_VIDEO_DIV] = clk_hw_register_divider_table(NULL, "pll5_video_div", "pll5_post_div",
CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock);
/* name parent_name mult div */
- clks[IMX6SLL_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2);
- clks[IMX6SLL_CLK_PLL3_120M] = imx_clk_fixed_factor("pll3_120m", "pll3_usb_otg", 1, 4);
- clks[IMX6SLL_CLK_PLL3_80M] = imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6);
- clks[IMX6SLL_CLK_PLL3_60M] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8);
+ hws[IMX6SLL_CLK_PLL2_198M] = imx_clk_hw_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2);
+ hws[IMX6SLL_CLK_PLL3_120M] = imx_clk_hw_fixed_factor("pll3_120m", "pll3_usb_otg", 1, 4);
+ hws[IMX6SLL_CLK_PLL3_80M] = imx_clk_hw_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6);
+ hws[IMX6SLL_CLK_PLL3_60M] = imx_clk_hw_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8);
np = ccm_node;
base = of_iomap(np, 0);
WARN_ON(!base);
- clks[IMX6SLL_CLK_STEP] = imx_clk_mux("step", base + 0x0c, 8, 1, step_sels, ARRAY_SIZE(step_sels));
- clks[IMX6SLL_CLK_PLL1_SW] = imx_clk_mux_flags("pll1_sw", base + 0x0c, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels), 0);
- clks[IMX6SLL_CLK_AXI_ALT_SEL] = imx_clk_mux("axi_alt_sel", base + 0x14, 7, 1, axi_alt_sels, ARRAY_SIZE(axi_alt_sels));
- clks[IMX6SLL_CLK_AXI_SEL] = imx_clk_mux_flags("axi_sel", base + 0x14, 6, 1, axi_sels, ARRAY_SIZE(axi_sels), 0);
- clks[IMX6SLL_CLK_PERIPH_PRE] = imx_clk_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
- clks[IMX6SLL_CLK_PERIPH2_PRE] = imx_clk_mux("periph2_pre", base + 0x18, 21, 2, periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels));
- clks[IMX6SLL_CLK_PERIPH_CLK2_SEL] = imx_clk_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
- clks[IMX6SLL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
- clks[IMX6SLL_CLK_USDHC1_SEL] = imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
- clks[IMX6SLL_CLK_USDHC2_SEL] = imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
- clks[IMX6SLL_CLK_USDHC3_SEL] = imx_clk_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
- clks[IMX6SLL_CLK_SSI1_SEL] = imx_clk_mux("ssi1_sel", base + 0x1c, 10, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
- clks[IMX6SLL_CLK_SSI2_SEL] = imx_clk_mux("ssi2_sel", base + 0x1c, 12, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
- clks[IMX6SLL_CLK_SSI3_SEL] = imx_clk_mux("ssi3_sel", base + 0x1c, 14, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
- clks[IMX6SLL_CLK_PERCLK_SEL] = imx_clk_mux("perclk_sel", base + 0x1c, 6, 1, perclk_sels, ARRAY_SIZE(perclk_sels));
- clks[IMX6SLL_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels));
- clks[IMX6SLL_CLK_SPDIF_SEL] = imx_clk_mux("spdif_sel", base + 0x30, 20, 2, spdif_sels, ARRAY_SIZE(spdif_sels));
- clks[IMX6SLL_CLK_EXTERN_AUDIO_SEL] = imx_clk_mux("extern_audio_sel", base + 0x30, 7, 2, spdif_sels, ARRAY_SIZE(spdif_sels));
- clks[IMX6SLL_CLK_EPDC_PRE_SEL] = imx_clk_mux("epdc_pre_sel", base + 0x34, 15, 3, epdc_pre_sels, ARRAY_SIZE(epdc_pre_sels));
- clks[IMX6SLL_CLK_EPDC_SEL] = imx_clk_mux("epdc_sel", base + 0x34, 9, 3, epdc_sels, ARRAY_SIZE(epdc_sels));
- clks[IMX6SLL_CLK_ECSPI_SEL] = imx_clk_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels));
- clks[IMX6SLL_CLK_LCDIF_PRE_SEL] = imx_clk_mux("lcdif_pre_sel", base + 0x38, 15, 3, lcdif_pre_sels, ARRAY_SIZE(lcdif_pre_sels));
- clks[IMX6SLL_CLK_LCDIF_SEL] = imx_clk_mux("lcdif_sel", base + 0x38, 9, 3, lcdif_sels, ARRAY_SIZE(lcdif_sels));
-
- clks[IMX6SLL_CLK_PERIPH] = imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels));
- clks[IMX6SLL_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels));
-
- clks[IMX6SLL_CLK_PERIPH_CLK2] = imx_clk_divider("periph_clk2", "periph_clk2_sel", base + 0x14, 27, 3);
- clks[IMX6SLL_CLK_PERIPH2_CLK2] = imx_clk_divider("periph2_clk2", "periph2_clk2_sel", base + 0x14, 0, 3);
- clks[IMX6SLL_CLK_IPG] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2);
- clks[IMX6SLL_CLK_LCDIF_PODF] = imx_clk_divider("lcdif_podf", "lcdif_pred", base + 0x18, 23, 3);
- clks[IMX6SLL_CLK_PERCLK] = imx_clk_divider("perclk", "perclk_sel", base + 0x1c, 0, 6);
- clks[IMX6SLL_CLK_USDHC3_PODF] = imx_clk_divider("usdhc3_podf", "usdhc3_sel", base + 0x24, 19, 3);
- clks[IMX6SLL_CLK_USDHC2_PODF] = imx_clk_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3);
- clks[IMX6SLL_CLK_USDHC1_PODF] = imx_clk_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3);
- clks[IMX6SLL_CLK_UART_PODF] = imx_clk_divider("uart_podf", "uart_sel", base + 0x24, 0, 6);
- clks[IMX6SLL_CLK_SSI3_PRED] = imx_clk_divider("ssi3_pred", "ssi3_sel", base + 0x28, 22, 3);
- clks[IMX6SLL_CLK_SSI3_PODF] = imx_clk_divider("ssi3_podf", "ssi3_pred", base + 0x28, 16, 6);
- clks[IMX6SLL_CLK_SSI1_PRED] = imx_clk_divider("ssi1_pred", "ssi1_sel", base + 0x28, 6, 3);
- clks[IMX6SLL_CLK_SSI1_PODF] = imx_clk_divider("ssi1_podf", "ssi1_pred", base + 0x28, 0, 6);
- clks[IMX6SLL_CLK_SSI2_PRED] = imx_clk_divider("ssi2_pred", "ssi2_sel", base + 0x2c, 6, 3);
- clks[IMX6SLL_CLK_SSI2_PODF] = imx_clk_divider("ssi2_podf", "ssi2_pred", base + 0x2c, 0, 6);
- clks[IMX6SLL_CLK_SPDIF_PRED] = imx_clk_divider("spdif_pred", "spdif_sel", base + 0x30, 25, 3);
- clks[IMX6SLL_CLK_SPDIF_PODF] = imx_clk_divider("spdif_podf", "spdif_pred", base + 0x30, 22, 3);
- clks[IMX6SLL_CLK_EXTERN_AUDIO_PRED] = imx_clk_divider("extern_audio_pred", "extern_audio_sel", base + 0x30, 12, 3);
- clks[IMX6SLL_CLK_EXTERN_AUDIO_PODF] = imx_clk_divider("extern_audio_podf", "extern_audio_pred", base + 0x30, 9, 3);
- clks[IMX6SLL_CLK_EPDC_PODF] = imx_clk_divider("epdc_podf", "epdc_pre_sel", base + 0x34, 12, 3);
- clks[IMX6SLL_CLK_ECSPI_PODF] = imx_clk_divider("ecspi_podf", "ecspi_sel", base + 0x38, 19, 6);
- clks[IMX6SLL_CLK_LCDIF_PRED] = imx_clk_divider("lcdif_pred", "lcdif_pre_sel", base + 0x38, 12, 3);
-
- clks[IMX6SLL_CLK_ARM] = imx_clk_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16);
- clks[IMX6SLL_CLK_MMDC_PODF] = imx_clk_busy_divider("mmdc_podf", "periph2", base + 0x14, 3, 3, base + 0x48, 2);
- clks[IMX6SLL_CLK_AXI_PODF] = imx_clk_busy_divider("axi", "axi_sel", base + 0x14, 16, 3, base + 0x48, 0);
- clks[IMX6SLL_CLK_AHB] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1);
-
- clks[IMX6SLL_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
- clks[IMX6SLL_CLK_LDB_DI0_DIV_7] = imx_clk_fixed_factor("ldb_di0_div_7", "ldb_di0_sel", 1, 7);
- clks[IMX6SLL_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7);
- clks[IMX6SLL_CLK_LDB_DI1_DIV_7] = imx_clk_fixed_factor("ldb_di1_div_7", "ldb_di1_sel", 1, 7);
-
- clks[IMX6SLL_CLK_LDB_DI0_SEL] = imx_clk_mux("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di0_sels, ARRAY_SIZE(ldb_di0_sels));
- clks[IMX6SLL_CLK_LDB_DI1_SEL] = imx_clk_mux("ldb_di1_sel", base + 0x1c, 7, 3, ldb_di1_sels, ARRAY_SIZE(ldb_di1_sels));
- clks[IMX6SLL_CLK_LDB_DI0_DIV_SEL] = imx_clk_mux("ldb_di0_div_sel", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels));
- clks[IMX6SLL_CLK_LDB_DI1_DIV_SEL] = imx_clk_mux("ldb_di1_div_sel", base + 0x20, 10, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels));
+ hws[IMX6SLL_CLK_STEP] = imx_clk_hw_mux("step", base + 0x0c, 8, 1, step_sels, ARRAY_SIZE(step_sels));
+ hws[IMX6SLL_CLK_PLL1_SW] = imx_clk_hw_mux_flags("pll1_sw", base + 0x0c, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels), 0);
+ hws[IMX6SLL_CLK_AXI_ALT_SEL] = imx_clk_hw_mux("axi_alt_sel", base + 0x14, 7, 1, axi_alt_sels, ARRAY_SIZE(axi_alt_sels));
+ hws[IMX6SLL_CLK_AXI_SEL] = imx_clk_hw_mux_flags("axi_sel", base + 0x14, 6, 1, axi_sels, ARRAY_SIZE(axi_sels), 0);
+ hws[IMX6SLL_CLK_PERIPH_PRE] = imx_clk_hw_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
+ hws[IMX6SLL_CLK_PERIPH2_PRE] = imx_clk_hw_mux("periph2_pre", base + 0x18, 21, 2, periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels));
+ hws[IMX6SLL_CLK_PERIPH_CLK2_SEL] = imx_clk_hw_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
+ hws[IMX6SLL_CLK_PERIPH2_CLK2_SEL] = imx_clk_hw_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
+ hws[IMX6SLL_CLK_USDHC1_SEL] = imx_clk_hw_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+ hws[IMX6SLL_CLK_USDHC2_SEL] = imx_clk_hw_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+ hws[IMX6SLL_CLK_USDHC3_SEL] = imx_clk_hw_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+ hws[IMX6SLL_CLK_SSI1_SEL] = imx_clk_hw_mux("ssi1_sel", base + 0x1c, 10, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
+ hws[IMX6SLL_CLK_SSI2_SEL] = imx_clk_hw_mux("ssi2_sel", base + 0x1c, 12, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
+ hws[IMX6SLL_CLK_SSI3_SEL] = imx_clk_hw_mux("ssi3_sel", base + 0x1c, 14, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
+ hws[IMX6SLL_CLK_PERCLK_SEL] = imx_clk_hw_mux("perclk_sel", base + 0x1c, 6, 1, perclk_sels, ARRAY_SIZE(perclk_sels));
+ hws[IMX6SLL_CLK_UART_SEL] = imx_clk_hw_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels));
+ hws[IMX6SLL_CLK_SPDIF_SEL] = imx_clk_hw_mux("spdif_sel", base + 0x30, 20, 2, spdif_sels, ARRAY_SIZE(spdif_sels));
+ hws[IMX6SLL_CLK_EXTERN_AUDIO_SEL] = imx_clk_hw_mux("extern_audio_sel", base + 0x30, 7, 2, spdif_sels, ARRAY_SIZE(spdif_sels));
+ hws[IMX6SLL_CLK_EPDC_PRE_SEL] = imx_clk_hw_mux("epdc_pre_sel", base + 0x34, 15, 3, epdc_pre_sels, ARRAY_SIZE(epdc_pre_sels));
+ hws[IMX6SLL_CLK_EPDC_SEL] = imx_clk_hw_mux("epdc_sel", base + 0x34, 9, 3, epdc_sels, ARRAY_SIZE(epdc_sels));
+ hws[IMX6SLL_CLK_ECSPI_SEL] = imx_clk_hw_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels));
+ hws[IMX6SLL_CLK_LCDIF_PRE_SEL] = imx_clk_hw_mux("lcdif_pre_sel", base + 0x38, 15, 3, lcdif_pre_sels, ARRAY_SIZE(lcdif_pre_sels));
+ hws[IMX6SLL_CLK_LCDIF_SEL] = imx_clk_hw_mux("lcdif_sel", base + 0x38, 9, 3, lcdif_sels, ARRAY_SIZE(lcdif_sels));
+
+ hws[IMX6SLL_CLK_PERIPH] = imx_clk_hw_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels));
+ hws[IMX6SLL_CLK_PERIPH2] = imx_clk_hw_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels));
+
+ hws[IMX6SLL_CLK_PERIPH_CLK2] = imx_clk_hw_divider("periph_clk2", "periph_clk2_sel", base + 0x14, 27, 3);
+ hws[IMX6SLL_CLK_PERIPH2_CLK2] = imx_clk_hw_divider("periph2_clk2", "periph2_clk2_sel", base + 0x14, 0, 3);
+ hws[IMX6SLL_CLK_IPG] = imx_clk_hw_divider("ipg", "ahb", base + 0x14, 8, 2);
+ hws[IMX6SLL_CLK_LCDIF_PODF] = imx_clk_hw_divider("lcdif_podf", "lcdif_pred", base + 0x18, 23, 3);
+ hws[IMX6SLL_CLK_PERCLK] = imx_clk_hw_divider("perclk", "perclk_sel", base + 0x1c, 0, 6);
+ hws[IMX6SLL_CLK_USDHC3_PODF] = imx_clk_hw_divider("usdhc3_podf", "usdhc3_sel", base + 0x24, 19, 3);
+ hws[IMX6SLL_CLK_USDHC2_PODF] = imx_clk_hw_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3);
+ hws[IMX6SLL_CLK_USDHC1_PODF] = imx_clk_hw_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3);
+ hws[IMX6SLL_CLK_UART_PODF] = imx_clk_hw_divider("uart_podf", "uart_sel", base + 0x24, 0, 6);
+ hws[IMX6SLL_CLK_SSI3_PRED] = imx_clk_hw_divider("ssi3_pred", "ssi3_sel", base + 0x28, 22, 3);
+ hws[IMX6SLL_CLK_SSI3_PODF] = imx_clk_hw_divider("ssi3_podf", "ssi3_pred", base + 0x28, 16, 6);
+ hws[IMX6SLL_CLK_SSI1_PRED] = imx_clk_hw_divider("ssi1_pred", "ssi1_sel", base + 0x28, 6, 3);
+ hws[IMX6SLL_CLK_SSI1_PODF] = imx_clk_hw_divider("ssi1_podf", "ssi1_pred", base + 0x28, 0, 6);
+ hws[IMX6SLL_CLK_SSI2_PRED] = imx_clk_hw_divider("ssi2_pred", "ssi2_sel", base + 0x2c, 6, 3);
+ hws[IMX6SLL_CLK_SSI2_PODF] = imx_clk_hw_divider("ssi2_podf", "ssi2_pred", base + 0x2c, 0, 6);
+ hws[IMX6SLL_CLK_SPDIF_PRED] = imx_clk_hw_divider("spdif_pred", "spdif_sel", base + 0x30, 25, 3);
+ hws[IMX6SLL_CLK_SPDIF_PODF] = imx_clk_hw_divider("spdif_podf", "spdif_pred", base + 0x30, 22, 3);
+ hws[IMX6SLL_CLK_EXTERN_AUDIO_PRED] = imx_clk_hw_divider("extern_audio_pred", "extern_audio_sel", base + 0x30, 12, 3);
+ hws[IMX6SLL_CLK_EXTERN_AUDIO_PODF] = imx_clk_hw_divider("extern_audio_podf", "extern_audio_pred", base + 0x30, 9, 3);
+ hws[IMX6SLL_CLK_EPDC_PODF] = imx_clk_hw_divider("epdc_podf", "epdc_pre_sel", base + 0x34, 12, 3);
+ hws[IMX6SLL_CLK_ECSPI_PODF] = imx_clk_hw_divider("ecspi_podf", "ecspi_sel", base + 0x38, 19, 6);
+ hws[IMX6SLL_CLK_LCDIF_PRED] = imx_clk_hw_divider("lcdif_pred", "lcdif_pre_sel", base + 0x38, 12, 3);
+
+ hws[IMX6SLL_CLK_ARM] = imx_clk_hw_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16);
+ hws[IMX6SLL_CLK_MMDC_PODF] = imx_clk_hw_busy_divider("mmdc_podf", "periph2", base + 0x14, 3, 3, base + 0x48, 2);
+ hws[IMX6SLL_CLK_AXI_PODF] = imx_clk_hw_busy_divider("axi", "axi_sel", base + 0x14, 16, 3, base + 0x48, 0);
+ hws[IMX6SLL_CLK_AHB] = imx_clk_hw_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1);
+
+ hws[IMX6SLL_CLK_LDB_DI0_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
+ hws[IMX6SLL_CLK_LDB_DI0_DIV_7] = imx_clk_hw_fixed_factor("ldb_di0_div_7", "ldb_di0_sel", 1, 7);
+ hws[IMX6SLL_CLK_LDB_DI1_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7);
+ hws[IMX6SLL_CLK_LDB_DI1_DIV_7] = imx_clk_hw_fixed_factor("ldb_di1_div_7", "ldb_di1_sel", 1, 7);
+
+ hws[IMX6SLL_CLK_LDB_DI0_SEL] = imx_clk_hw_mux("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di0_sels, ARRAY_SIZE(ldb_di0_sels));
+ hws[IMX6SLL_CLK_LDB_DI1_SEL] = imx_clk_hw_mux("ldb_di1_sel", base + 0x1c, 7, 3, ldb_di1_sels, ARRAY_SIZE(ldb_di1_sels));
+ hws[IMX6SLL_CLK_LDB_DI0_DIV_SEL] = imx_clk_hw_mux("ldb_di0_div_sel", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels));
+ hws[IMX6SLL_CLK_LDB_DI1_DIV_SEL] = imx_clk_hw_mux("ldb_di1_div_sel", base + 0x20, 10, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels));
/* CCGR0 */
- clks[IMX6SLL_CLK_AIPSTZ1] = imx_clk_gate2_flags("aips_tz1", "ahb", base + 0x68, 0, CLK_IS_CRITICAL);
- clks[IMX6SLL_CLK_AIPSTZ2] = imx_clk_gate2_flags("aips_tz2", "ahb", base + 0x68, 2, CLK_IS_CRITICAL);
- clks[IMX6SLL_CLK_DCP] = imx_clk_gate2("dcp", "ahb", base + 0x68, 10);
- clks[IMX6SLL_CLK_UART2_IPG] = imx_clk_gate2("uart2_ipg", "ipg", base + 0x68, 28);
- clks[IMX6SLL_CLK_UART2_SERIAL] = imx_clk_gate2("uart2_serial", "uart_podf", base + 0x68, 28);
- clks[IMX6SLL_CLK_GPIO2] = imx_clk_gate2("gpio2", "ipg", base + 0x68, 30);
+ hws[IMX6SLL_CLK_AIPSTZ1] = imx_clk_hw_gate2_flags("aips_tz1", "ahb", base + 0x68, 0, CLK_IS_CRITICAL);
+ hws[IMX6SLL_CLK_AIPSTZ2] = imx_clk_hw_gate2_flags("aips_tz2", "ahb", base + 0x68, 2, CLK_IS_CRITICAL);
+ hws[IMX6SLL_CLK_DCP] = imx_clk_hw_gate2("dcp", "ahb", base + 0x68, 10);
+ hws[IMX6SLL_CLK_UART2_IPG] = imx_clk_hw_gate2("uart2_ipg", "ipg", base + 0x68, 28);
+ hws[IMX6SLL_CLK_UART2_SERIAL] = imx_clk_hw_gate2("uart2_serial", "uart_podf", base + 0x68, 28);
+ hws[IMX6SLL_CLK_GPIO2] = imx_clk_hw_gate2("gpio2", "ipg", base + 0x68, 30);
/* CCGR1 */
- clks[IMX6SLL_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_podf", base + 0x6c, 0);
- clks[IMX6SLL_CLK_ECSPI2] = imx_clk_gate2("ecspi2", "ecspi_podf", base + 0x6c, 2);
- clks[IMX6SLL_CLK_ECSPI3] = imx_clk_gate2("ecspi3", "ecspi_podf", base + 0x6c, 4);
- clks[IMX6SLL_CLK_ECSPI4] = imx_clk_gate2("ecspi4", "ecspi_podf", base + 0x6c, 6);
- clks[IMX6SLL_CLK_UART3_IPG] = imx_clk_gate2("uart3_ipg", "ipg", base + 0x6c, 10);
- clks[IMX6SLL_CLK_UART3_SERIAL] = imx_clk_gate2("uart3_serial", "uart_podf", base + 0x6c, 10);
- clks[IMX6SLL_CLK_EPIT1] = imx_clk_gate2("epit1", "perclk", base + 0x6c, 12);
- clks[IMX6SLL_CLK_EPIT2] = imx_clk_gate2("epit2", "perclk", base + 0x6c, 14);
- clks[IMX6SLL_CLK_GPT_BUS] = imx_clk_gate2("gpt1_bus", "perclk", base + 0x6c, 20);
- clks[IMX6SLL_CLK_GPT_SERIAL] = imx_clk_gate2("gpt1_serial", "perclk", base + 0x6c, 22);
- clks[IMX6SLL_CLK_UART4_IPG] = imx_clk_gate2("uart4_ipg", "ipg", base + 0x6c, 24);
- clks[IMX6SLL_CLK_UART4_SERIAL] = imx_clk_gate2("uart4_serial", "uart_podf", base + 0x6c, 24);
- clks[IMX6SLL_CLK_GPIO1] = imx_clk_gate2("gpio1", "ipg", base + 0x6c, 26);
- clks[IMX6SLL_CLK_GPIO5] = imx_clk_gate2("gpio5", "ipg", base + 0x6c, 30);
+ hws[IMX6SLL_CLK_ECSPI1] = imx_clk_hw_gate2("ecspi1", "ecspi_podf", base + 0x6c, 0);
+ hws[IMX6SLL_CLK_ECSPI2] = imx_clk_hw_gate2("ecspi2", "ecspi_podf", base + 0x6c, 2);
+ hws[IMX6SLL_CLK_ECSPI3] = imx_clk_hw_gate2("ecspi3", "ecspi_podf", base + 0x6c, 4);
+ hws[IMX6SLL_CLK_ECSPI4] = imx_clk_hw_gate2("ecspi4", "ecspi_podf", base + 0x6c, 6);
+ hws[IMX6SLL_CLK_UART3_IPG] = imx_clk_hw_gate2("uart3_ipg", "ipg", base + 0x6c, 10);
+ hws[IMX6SLL_CLK_UART3_SERIAL] = imx_clk_hw_gate2("uart3_serial", "uart_podf", base + 0x6c, 10);
+ hws[IMX6SLL_CLK_EPIT1] = imx_clk_hw_gate2("epit1", "perclk", base + 0x6c, 12);
+ hws[IMX6SLL_CLK_EPIT2] = imx_clk_hw_gate2("epit2", "perclk", base + 0x6c, 14);
+ hws[IMX6SLL_CLK_GPT_BUS] = imx_clk_hw_gate2("gpt1_bus", "perclk", base + 0x6c, 20);
+ hws[IMX6SLL_CLK_GPT_SERIAL] = imx_clk_hw_gate2("gpt1_serial", "perclk", base + 0x6c, 22);
+ hws[IMX6SLL_CLK_UART4_IPG] = imx_clk_hw_gate2("uart4_ipg", "ipg", base + 0x6c, 24);
+ hws[IMX6SLL_CLK_UART4_SERIAL] = imx_clk_hw_gate2("uart4_serial", "uart_podf", base + 0x6c, 24);
+ hws[IMX6SLL_CLK_GPIO1] = imx_clk_hw_gate2("gpio1", "ipg", base + 0x6c, 26);
+ hws[IMX6SLL_CLK_GPIO5] = imx_clk_hw_gate2("gpio5", "ipg", base + 0x6c, 30);
/* CCGR2 */
- clks[IMX6SLL_CLK_GPIO6] = imx_clk_gate2("gpio6", "ipg", base + 0x70, 0);
- clks[IMX6SLL_CLK_CSI] = imx_clk_gate2("csi", "axi", base + 0x70, 2);
- clks[IMX6SLL_CLK_I2C1] = imx_clk_gate2("i2c1", "perclk", base + 0x70, 6);
- clks[IMX6SLL_CLK_I2C2] = imx_clk_gate2("i2c2", "perclk", base + 0x70, 8);
- clks[IMX6SLL_CLK_I2C3] = imx_clk_gate2("i2c3", "perclk", base + 0x70, 10);
- clks[IMX6SLL_CLK_OCOTP] = imx_clk_gate2("ocotp", "ipg", base + 0x70, 12);
- clks[IMX6SLL_CLK_GPIO3] = imx_clk_gate2("gpio3", "ipg", base + 0x70, 26);
- clks[IMX6SLL_CLK_LCDIF_APB] = imx_clk_gate2("lcdif_apb", "axi", base + 0x70, 28);
- clks[IMX6SLL_CLK_PXP] = imx_clk_gate2("pxp", "axi", base + 0x70, 30);
+ hws[IMX6SLL_CLK_GPIO6] = imx_clk_hw_gate2("gpio6", "ipg", base + 0x70, 0);
+ hws[IMX6SLL_CLK_CSI] = imx_clk_hw_gate2("csi", "axi", base + 0x70, 2);
+ hws[IMX6SLL_CLK_I2C1] = imx_clk_hw_gate2("i2c1", "perclk", base + 0x70, 6);
+ hws[IMX6SLL_CLK_I2C2] = imx_clk_hw_gate2("i2c2", "perclk", base + 0x70, 8);
+ hws[IMX6SLL_CLK_I2C3] = imx_clk_hw_gate2("i2c3", "perclk", base + 0x70, 10);
+ hws[IMX6SLL_CLK_OCOTP] = imx_clk_hw_gate2("ocotp", "ipg", base + 0x70, 12);
+ hws[IMX6SLL_CLK_GPIO3] = imx_clk_hw_gate2("gpio3", "ipg", base + 0x70, 26);
+ hws[IMX6SLL_CLK_LCDIF_APB] = imx_clk_hw_gate2("lcdif_apb", "axi", base + 0x70, 28);
+ hws[IMX6SLL_CLK_PXP] = imx_clk_hw_gate2("pxp", "axi", base + 0x70, 30);
/* CCGR3 */
- clks[IMX6SLL_CLK_UART5_IPG] = imx_clk_gate2("uart5_ipg", "ipg", base + 0x74, 2);
- clks[IMX6SLL_CLK_UART5_SERIAL] = imx_clk_gate2("uart5_serial", "uart_podf", base + 0x74, 2);
- clks[IMX6SLL_CLK_EPDC_AXI] = imx_clk_gate2("epdc_aclk", "axi", base + 0x74, 4);
- clks[IMX6SLL_CLK_EPDC_PIX] = imx_clk_gate2("epdc_pix", "epdc_podf", base + 0x74, 4);
- clks[IMX6SLL_CLK_LCDIF_PIX] = imx_clk_gate2("lcdif_pix", "lcdif_podf", base + 0x74, 10);
- clks[IMX6SLL_CLK_GPIO4] = imx_clk_gate2("gpio4", "ipg", base + 0x74, 12);
- clks[IMX6SLL_CLK_WDOG1] = imx_clk_gate2("wdog1", "ipg", base + 0x74, 16);
- clks[IMX6SLL_CLK_MMDC_P0_FAST] = imx_clk_gate_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL);
- clks[IMX6SLL_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
- clks[IMX6SLL_CLK_MMDC_P1_IPG] = imx_clk_gate2("mmdc_p1_ipg", "ipg", base + 0x74, 26);
- clks[IMX6SLL_CLK_OCRAM] = imx_clk_gate_flags("ocram","ahb", base + 0x74, 28, CLK_IS_CRITICAL);
+ hws[IMX6SLL_CLK_UART5_IPG] = imx_clk_hw_gate2("uart5_ipg", "ipg", base + 0x74, 2);
+ hws[IMX6SLL_CLK_UART5_SERIAL] = imx_clk_hw_gate2("uart5_serial", "uart_podf", base + 0x74, 2);
+ hws[IMX6SLL_CLK_EPDC_AXI] = imx_clk_hw_gate2("epdc_aclk", "axi", base + 0x74, 4);
+ hws[IMX6SLL_CLK_EPDC_PIX] = imx_clk_hw_gate2("epdc_pix", "epdc_podf", base + 0x74, 4);
+ hws[IMX6SLL_CLK_LCDIF_PIX] = imx_clk_hw_gate2("lcdif_pix", "lcdif_podf", base + 0x74, 10);
+ hws[IMX6SLL_CLK_GPIO4] = imx_clk_hw_gate2("gpio4", "ipg", base + 0x74, 12);
+ hws[IMX6SLL_CLK_WDOG1] = imx_clk_hw_gate2("wdog1", "ipg", base + 0x74, 16);
+ hws[IMX6SLL_CLK_MMDC_P0_FAST] = imx_clk_hw_gate_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL);
+ hws[IMX6SLL_CLK_MMDC_P0_IPG] = imx_clk_hw_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
+ hws[IMX6SLL_CLK_MMDC_P1_IPG] = imx_clk_hw_gate2_flags("mmdc_p1_ipg", "ipg", base + 0x74, 26, CLK_IS_CRITICAL);
+ hws[IMX6SLL_CLK_OCRAM] = imx_clk_hw_gate_flags("ocram", "ahb", base + 0x74, 28, CLK_IS_CRITICAL);
/* CCGR4 */
- clks[IMX6SLL_CLK_PWM1] = imx_clk_gate2("pwm1", "perclk", base + 0x78, 16);
- clks[IMX6SLL_CLK_PWM2] = imx_clk_gate2("pwm2", "perclk", base + 0x78, 18);
- clks[IMX6SLL_CLK_PWM3] = imx_clk_gate2("pwm3", "perclk", base + 0x78, 20);
- clks[IMX6SLL_CLK_PWM4] = imx_clk_gate2("pwm4", "perclk", base + 0x78, 22);
+ hws[IMX6SLL_CLK_PWM1] = imx_clk_hw_gate2("pwm1", "perclk", base + 0x78, 16);
+ hws[IMX6SLL_CLK_PWM2] = imx_clk_hw_gate2("pwm2", "perclk", base + 0x78, 18);
+ hws[IMX6SLL_CLK_PWM3] = imx_clk_hw_gate2("pwm3", "perclk", base + 0x78, 20);
+ hws[IMX6SLL_CLK_PWM4] = imx_clk_hw_gate2("pwm4", "perclk", base + 0x78, 22);
/* CCGR5 */
- clks[IMX6SLL_CLK_ROM] = imx_clk_gate2_flags("rom", "ahb", base + 0x7c, 0, CLK_IS_CRITICAL);
- clks[IMX6SLL_CLK_SDMA] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6);
- clks[IMX6SLL_CLK_WDOG2] = imx_clk_gate2("wdog2", "ipg", base + 0x7c, 10);
- clks[IMX6SLL_CLK_SPBA] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12);
- clks[IMX6SLL_CLK_EXTERN_AUDIO] = imx_clk_gate2_shared("extern_audio", "extern_audio_podf", base + 0x7c, 14, &share_count_audio);
- clks[IMX6SLL_CLK_SPDIF] = imx_clk_gate2_shared("spdif", "spdif_podf", base + 0x7c, 14, &share_count_audio);
- clks[IMX6SLL_CLK_SPDIF_GCLK] = imx_clk_gate2_shared("spdif_gclk", "ipg", base + 0x7c, 14, &share_count_audio);
- clks[IMX6SLL_CLK_SSI1] = imx_clk_gate2_shared("ssi1", "ssi1_podf", base + 0x7c, 18, &share_count_ssi1);
- clks[IMX6SLL_CLK_SSI1_IPG] = imx_clk_gate2_shared("ssi1_ipg", "ipg", base + 0x7c, 18, &share_count_ssi1);
- clks[IMX6SLL_CLK_SSI2] = imx_clk_gate2_shared("ssi2", "ssi2_podf", base + 0x7c, 20, &share_count_ssi2);
- clks[IMX6SLL_CLK_SSI2_IPG] = imx_clk_gate2_shared("ssi2_ipg", "ipg", base + 0x7c, 20, &share_count_ssi2);
- clks[IMX6SLL_CLK_SSI3] = imx_clk_gate2_shared("ssi3", "ssi3_podf", base + 0x7c, 22, &share_count_ssi3);
- clks[IMX6SLL_CLK_SSI3_IPG] = imx_clk_gate2_shared("ssi3_ipg", "ipg", base + 0x7c, 22, &share_count_ssi3);
- clks[IMX6SLL_CLK_UART1_IPG] = imx_clk_gate2("uart1_ipg", "ipg", base + 0x7c, 24);
- clks[IMX6SLL_CLK_UART1_SERIAL] = imx_clk_gate2("uart1_serial", "uart_podf", base + 0x7c, 24);
+ hws[IMX6SLL_CLK_ROM] = imx_clk_hw_gate2_flags("rom", "ahb", base + 0x7c, 0, CLK_IS_CRITICAL);
+ hws[IMX6SLL_CLK_SDMA] = imx_clk_hw_gate2("sdma", "ahb", base + 0x7c, 6);
+ hws[IMX6SLL_CLK_WDOG2] = imx_clk_hw_gate2("wdog2", "ipg", base + 0x7c, 10);
+ hws[IMX6SLL_CLK_SPBA] = imx_clk_hw_gate2("spba", "ipg", base + 0x7c, 12);
+ hws[IMX6SLL_CLK_EXTERN_AUDIO] = imx_clk_hw_gate2_shared("extern_audio", "extern_audio_podf", base + 0x7c, 14, &share_count_audio);
+ hws[IMX6SLL_CLK_SPDIF] = imx_clk_hw_gate2_shared("spdif", "spdif_podf", base + 0x7c, 14, &share_count_audio);
+ hws[IMX6SLL_CLK_SPDIF_GCLK] = imx_clk_hw_gate2_shared("spdif_gclk", "ipg", base + 0x7c, 14, &share_count_audio);
+ hws[IMX6SLL_CLK_SSI1] = imx_clk_hw_gate2_shared("ssi1", "ssi1_podf", base + 0x7c, 18, &share_count_ssi1);
+ hws[IMX6SLL_CLK_SSI1_IPG] = imx_clk_hw_gate2_shared("ssi1_ipg", "ipg", base + 0x7c, 18, &share_count_ssi1);
+ hws[IMX6SLL_CLK_SSI2] = imx_clk_hw_gate2_shared("ssi2", "ssi2_podf", base + 0x7c, 20, &share_count_ssi2);
+ hws[IMX6SLL_CLK_SSI2_IPG] = imx_clk_hw_gate2_shared("ssi2_ipg", "ipg", base + 0x7c, 20, &share_count_ssi2);
+ hws[IMX6SLL_CLK_SSI3] = imx_clk_hw_gate2_shared("ssi3", "ssi3_podf", base + 0x7c, 22, &share_count_ssi3);
+ hws[IMX6SLL_CLK_SSI3_IPG] = imx_clk_hw_gate2_shared("ssi3_ipg", "ipg", base + 0x7c, 22, &share_count_ssi3);
+ hws[IMX6SLL_CLK_UART1_IPG] = imx_clk_hw_gate2("uart1_ipg", "ipg", base + 0x7c, 24);
+ hws[IMX6SLL_CLK_UART1_SERIAL] = imx_clk_hw_gate2("uart1_serial", "uart_podf", base + 0x7c, 24);
/* CCGR6 */
- clks[IMX6SLL_CLK_USBOH3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0);
- clks[IMX6SLL_CLK_USDHC1] = imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2);
- clks[IMX6SLL_CLK_USDHC2] = imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4);
- clks[IMX6SLL_CLK_USDHC3] = imx_clk_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6);
+ hws[IMX6SLL_CLK_USBOH3] = imx_clk_hw_gate2("usboh3", "ipg", base + 0x80, 0);
+ hws[IMX6SLL_CLK_USDHC1] = imx_clk_hw_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2);
+ hws[IMX6SLL_CLK_USDHC2] = imx_clk_hw_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4);
+ hws[IMX6SLL_CLK_USDHC3] = imx_clk_hw_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6);
/* mask handshake of mmdc */
- writel_relaxed(BM_CCM_CCDR_MMDC_CH0_MASK, base + 0x4);
+ imx_mmdc_mask_handshake(base, 0);
- imx_check_clocks(clks, ARRAY_SIZE(clks));
+ imx_check_clk_hws(hws, IMX6SLL_CLK_END);
- clk_data.clks = clks;
- clk_data.clk_num = ARRAY_SIZE(clks);
- of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+ of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
+
+ for (i = 0; i < ARRAY_SIZE(uart_clk_ids); i++) {
+ int index = uart_clk_ids[i];
+
+ uart_clks[i] = &hws[index]->clk;
+ }
imx_register_uart_clocks(uart_clks);
/* Lower the AHB clock rate before changing the clock source. */
- clk_set_rate(clks[IMX6SLL_CLK_AHB], 99000000);
+ clk_set_rate(hws[IMX6SLL_CLK_AHB]->clk, 99000000);
/* Change periph_pre clock to pll2_bus to adjust AXI rate to 264MHz */
- clk_set_parent(clks[IMX6SLL_CLK_PERIPH_CLK2_SEL], clks[IMX6SLL_CLK_PLL3_USB_OTG]);
- clk_set_parent(clks[IMX6SLL_CLK_PERIPH], clks[IMX6SLL_CLK_PERIPH_CLK2]);
- clk_set_parent(clks[IMX6SLL_CLK_PERIPH_PRE], clks[IMX6SLL_CLK_PLL2_BUS]);
- clk_set_parent(clks[IMX6SLL_CLK_PERIPH], clks[IMX6SLL_CLK_PERIPH_PRE]);
+ clk_set_parent(hws[IMX6SLL_CLK_PERIPH_CLK2_SEL]->clk, hws[IMX6SLL_CLK_PLL3_USB_OTG]->clk);
+ clk_set_parent(hws[IMX6SLL_CLK_PERIPH]->clk, hws[IMX6SLL_CLK_PERIPH_CLK2]->clk);
+ clk_set_parent(hws[IMX6SLL_CLK_PERIPH_PRE]->clk, hws[IMX6SLL_CLK_PLL2_BUS]->clk);
+ clk_set_parent(hws[IMX6SLL_CLK_PERIPH]->clk, hws[IMX6SLL_CLK_PERIPH_PRE]->clk);
- clk_set_rate(clks[IMX6SLL_CLK_AHB], 132000000);
+ clk_set_rate(hws[IMX6SLL_CLK_AHB]->clk, 132000000);
}
CLK_OF_DECLARE_DRIVER(imx6sll, "fsl,imx6sll-ccm", imx6sll_clocks_init);
diff --git a/drivers/clk/imx/clk-imx6sx.c b/drivers/clk/imx/clk-imx6sx.c
index d243e3483e24..c4685c01929a 100644
--- a/drivers/clk/imx/clk-imx6sx.c
+++ b/drivers/clk/imx/clk-imx6sx.c
@@ -6,6 +6,7 @@
#include <dt-bindings/clock/imx6sx-clock.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
@@ -16,9 +17,6 @@
#include "clk.h"
-#define CCDR 0x4
-#define BM_CCM_CCDR_MMDC_CH0_MASK (0x2 << 16)
-
static const char *step_sels[] = { "osc", "pll2_pfd2_396m", };
static const char *pll1_sw_sels[] = { "pll1_sys", "step", };
static const char *periph_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll2_198m", };
@@ -83,8 +81,8 @@ static const char *pll5_bypass_sels[] = { "pll5", "pll5_bypass_src", };
static const char *pll6_bypass_sels[] = { "pll6", "pll6_bypass_src", };
static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", };
-static struct clk *clks[IMX6SX_CLK_CLK_END];
-static struct clk_onecell_data clk_data;
+static struct clk_hw **hws;
+static struct clk_hw_onecell_data *clk_hw_data;
static const struct clk_div_table clk_enet_ref_table[] = {
{ .val = 0, .div = 20, },
@@ -118,76 +116,86 @@ static u32 share_count_ssi3;
static u32 share_count_sai1;
static u32 share_count_sai2;
-static struct clk ** const uart_clks[] __initconst = {
- &clks[IMX6SX_CLK_UART_IPG],
- &clks[IMX6SX_CLK_UART_SERIAL],
- NULL
+static const int uart_clk_ids[] __initconst = {
+ IMX6SX_CLK_UART_IPG,
+ IMX6SX_CLK_UART_SERIAL,
};
+static struct clk **uart_clks[ARRAY_SIZE(uart_clk_ids) + 1] __initdata;
+
static void __init imx6sx_clocks_init(struct device_node *ccm_node)
{
struct device_node *np;
void __iomem *base;
+ int i;
+
+ clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
+ IMX6SX_CLK_CLK_END), GFP_KERNEL);
+ if (WARN_ON(!clk_hw_data))
+ return;
+
+ clk_hw_data->num = IMX6SX_CLK_CLK_END;
+ hws = clk_hw_data->hws;
- clks[IMX6SX_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
+ hws[IMX6SX_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
- clks[IMX6SX_CLK_CKIL] = of_clk_get_by_name(ccm_node, "ckil");
- clks[IMX6SX_CLK_OSC] = of_clk_get_by_name(ccm_node, "osc");
+ hws[IMX6SX_CLK_CKIL] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ckil"));
+ hws[IMX6SX_CLK_OSC] = __clk_get_hw(of_clk_get_by_name(ccm_node, "osc"));
/* ipp_di clock is external input */
- clks[IMX6SX_CLK_IPP_DI0] = of_clk_get_by_name(ccm_node, "ipp_di0");
- clks[IMX6SX_CLK_IPP_DI1] = of_clk_get_by_name(ccm_node, "ipp_di1");
+ hws[IMX6SX_CLK_IPP_DI0] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ipp_di0"));
+ hws[IMX6SX_CLK_IPP_DI1] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ipp_di1"));
/* Clock source from external clock via CLK1/2 PAD */
- clks[IMX6SX_CLK_ANACLK1] = of_clk_get_by_name(ccm_node, "anaclk1");
- clks[IMX6SX_CLK_ANACLK2] = of_clk_get_by_name(ccm_node, "anaclk2");
+ hws[IMX6SX_CLK_ANACLK1] = __clk_get_hw(of_clk_get_by_name(ccm_node, "anaclk1"));
+ hws[IMX6SX_CLK_ANACLK2] = __clk_get_hw(of_clk_get_by_name(ccm_node, "anaclk2"));
np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-anatop");
base = of_iomap(np, 0);
WARN_ON(!base);
of_node_put(np);
- clks[IMX6SX_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
- clks[IMX6SX_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
- clks[IMX6SX_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
- clks[IMX6SX_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
- clks[IMX6SX_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
- clks[IMX6SX_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
- clks[IMX6SX_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6SX_PLL1_BYPASS_SRC] = imx_clk_hw_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6SX_PLL2_BYPASS_SRC] = imx_clk_hw_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6SX_PLL3_BYPASS_SRC] = imx_clk_hw_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6SX_PLL4_BYPASS_SRC] = imx_clk_hw_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6SX_PLL5_BYPASS_SRC] = imx_clk_hw_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6SX_PLL6_BYPASS_SRC] = imx_clk_hw_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6SX_PLL7_BYPASS_SRC] = imx_clk_hw_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
/* type name parent_name base div_mask */
- clks[IMX6SX_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "osc", base + 0x00, 0x7f);
- clks[IMX6SX_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
- clks[IMX6SX_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "osc", base + 0x10, 0x3);
- clks[IMX6SX_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "osc", base + 0x70, 0x7f);
- clks[IMX6SX_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "osc", base + 0xa0, 0x7f);
- clks[IMX6SX_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "osc", base + 0xe0, 0x3);
- clks[IMX6SX_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "osc", base + 0x20, 0x3);
-
- clks[IMX6SX_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
- clks[IMX6SX_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
- clks[IMX6SX_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
- clks[IMX6SX_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
- clks[IMX6SX_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
- clks[IMX6SX_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
- clks[IMX6SX_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6SX_CLK_PLL1] = imx_clk_hw_pllv3(IMX_PLLV3_SYS, "pll1", "osc", base + 0x00, 0x7f);
+ hws[IMX6SX_CLK_PLL2] = imx_clk_hw_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
+ hws[IMX6SX_CLK_PLL3] = imx_clk_hw_pllv3(IMX_PLLV3_USB, "pll3", "osc", base + 0x10, 0x3);
+ hws[IMX6SX_CLK_PLL4] = imx_clk_hw_pllv3(IMX_PLLV3_AV, "pll4", "osc", base + 0x70, 0x7f);
+ hws[IMX6SX_CLK_PLL5] = imx_clk_hw_pllv3(IMX_PLLV3_AV, "pll5", "osc", base + 0xa0, 0x7f);
+ hws[IMX6SX_CLK_PLL6] = imx_clk_hw_pllv3(IMX_PLLV3_ENET, "pll6", "osc", base + 0xe0, 0x3);
+ hws[IMX6SX_CLK_PLL7] = imx_clk_hw_pllv3(IMX_PLLV3_USB, "pll7", "osc", base + 0x20, 0x3);
+
+ hws[IMX6SX_PLL1_BYPASS] = imx_clk_hw_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6SX_PLL2_BYPASS] = imx_clk_hw_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6SX_PLL3_BYPASS] = imx_clk_hw_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6SX_PLL4_BYPASS] = imx_clk_hw_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6SX_PLL5_BYPASS] = imx_clk_hw_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6SX_PLL6_BYPASS] = imx_clk_hw_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6SX_PLL7_BYPASS] = imx_clk_hw_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
/* Do not bypass PLLs initially */
- clk_set_parent(clks[IMX6SX_PLL1_BYPASS], clks[IMX6SX_CLK_PLL1]);
- clk_set_parent(clks[IMX6SX_PLL2_BYPASS], clks[IMX6SX_CLK_PLL2]);
- clk_set_parent(clks[IMX6SX_PLL3_BYPASS], clks[IMX6SX_CLK_PLL3]);
- clk_set_parent(clks[IMX6SX_PLL4_BYPASS], clks[IMX6SX_CLK_PLL4]);
- clk_set_parent(clks[IMX6SX_PLL5_BYPASS], clks[IMX6SX_CLK_PLL5]);
- clk_set_parent(clks[IMX6SX_PLL6_BYPASS], clks[IMX6SX_CLK_PLL6]);
- clk_set_parent(clks[IMX6SX_PLL7_BYPASS], clks[IMX6SX_CLK_PLL7]);
-
- clks[IMX6SX_CLK_PLL1_SYS] = imx_clk_gate("pll1_sys", "pll1_bypass", base + 0x00, 13);
- clks[IMX6SX_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", base + 0x30, 13);
- clks[IMX6SX_CLK_PLL3_USB_OTG] = imx_clk_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13);
- clks[IMX6SX_CLK_PLL4_AUDIO] = imx_clk_gate("pll4_audio", "pll4_bypass", base + 0x70, 13);
- clks[IMX6SX_CLK_PLL5_VIDEO] = imx_clk_gate("pll5_video", "pll5_bypass", base + 0xa0, 13);
- clks[IMX6SX_CLK_PLL6_ENET] = imx_clk_gate("pll6_enet", "pll6_bypass", base + 0xe0, 13);
- clks[IMX6SX_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
+ clk_set_parent(hws[IMX6SX_PLL1_BYPASS]->clk, hws[IMX6SX_CLK_PLL1]->clk);
+ clk_set_parent(hws[IMX6SX_PLL2_BYPASS]->clk, hws[IMX6SX_CLK_PLL2]->clk);
+ clk_set_parent(hws[IMX6SX_PLL3_BYPASS]->clk, hws[IMX6SX_CLK_PLL3]->clk);
+ clk_set_parent(hws[IMX6SX_PLL4_BYPASS]->clk, hws[IMX6SX_CLK_PLL4]->clk);
+ clk_set_parent(hws[IMX6SX_PLL5_BYPASS]->clk, hws[IMX6SX_CLK_PLL5]->clk);
+ clk_set_parent(hws[IMX6SX_PLL6_BYPASS]->clk, hws[IMX6SX_CLK_PLL6]->clk);
+ clk_set_parent(hws[IMX6SX_PLL7_BYPASS]->clk, hws[IMX6SX_CLK_PLL7]->clk);
+
+ hws[IMX6SX_CLK_PLL1_SYS] = imx_clk_hw_gate("pll1_sys", "pll1_bypass", base + 0x00, 13);
+ hws[IMX6SX_CLK_PLL2_BUS] = imx_clk_hw_gate("pll2_bus", "pll2_bypass", base + 0x30, 13);
+ hws[IMX6SX_CLK_PLL3_USB_OTG] = imx_clk_hw_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13);
+ hws[IMX6SX_CLK_PLL4_AUDIO] = imx_clk_hw_gate("pll4_audio", "pll4_bypass", base + 0x70, 13);
+ hws[IMX6SX_CLK_PLL5_VIDEO] = imx_clk_hw_gate("pll5_video", "pll5_bypass", base + 0xa0, 13);
+ hws[IMX6SX_CLK_PLL6_ENET] = imx_clk_hw_gate("pll6_enet", "pll6_bypass", base + 0xe0, 13);
+ hws[IMX6SX_CLK_PLL7_USB_HOST] = imx_clk_hw_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
/*
* Bit 20 is the reserved and read-only bit, we do this only for:
@@ -195,361 +203,363 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
* - Keep refcount when do usbphy clk_enable/disable, in that case,
* the clk framework may need to enable/disable usbphy's parent
*/
- clks[IMX6SX_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20);
- clks[IMX6SX_CLK_USBPHY2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
+ hws[IMX6SX_CLK_USBPHY1] = imx_clk_hw_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20);
+ hws[IMX6SX_CLK_USBPHY2] = imx_clk_hw_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
/*
* usbphy*_gate needs to be on after system boots up, and software
* never needs to control it anymore.
*/
- clks[IMX6SX_CLK_USBPHY1_GATE] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6);
- clks[IMX6SX_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6);
+ hws[IMX6SX_CLK_USBPHY1_GATE] = imx_clk_hw_gate("usbphy1_gate", "dummy", base + 0x10, 6);
+ hws[IMX6SX_CLK_USBPHY2_GATE] = imx_clk_hw_gate("usbphy2_gate", "dummy", base + 0x20, 6);
/* FIXME 100MHz is used for pcie ref for all imx6 pcie, excepted imx6q */
- clks[IMX6SX_CLK_PCIE_REF] = imx_clk_fixed_factor("pcie_ref", "pll6_enet", 1, 5);
- clks[IMX6SX_CLK_PCIE_REF_125M] = imx_clk_gate("pcie_ref_125m", "pcie_ref", base + 0xe0, 19);
+ hws[IMX6SX_CLK_PCIE_REF] = imx_clk_hw_fixed_factor("pcie_ref", "pll6_enet", 1, 5);
+ hws[IMX6SX_CLK_PCIE_REF_125M] = imx_clk_hw_gate("pcie_ref_125m", "pcie_ref", base + 0xe0, 19);
- clks[IMX6SX_CLK_LVDS1_OUT] = imx_clk_gate_exclusive("lvds1_out", "lvds1_sel", base + 0x160, 10, BIT(12));
- clks[IMX6SX_CLK_LVDS2_OUT] = imx_clk_gate_exclusive("lvds2_out", "lvds2_sel", base + 0x160, 11, BIT(13));
- clks[IMX6SX_CLK_LVDS1_IN] = imx_clk_gate_exclusive("lvds1_in", "anaclk1", base + 0x160, 12, BIT(10));
- clks[IMX6SX_CLK_LVDS2_IN] = imx_clk_gate_exclusive("lvds2_in", "anaclk2", base + 0x160, 13, BIT(11));
+ hws[IMX6SX_CLK_LVDS1_OUT] = imx_clk_hw_gate_exclusive("lvds1_out", "lvds1_sel", base + 0x160, 10, BIT(12));
+ hws[IMX6SX_CLK_LVDS2_OUT] = imx_clk_hw_gate_exclusive("lvds2_out", "lvds2_sel", base + 0x160, 11, BIT(13));
+ hws[IMX6SX_CLK_LVDS1_IN] = imx_clk_hw_gate_exclusive("lvds1_in", "anaclk1", base + 0x160, 12, BIT(10));
+ hws[IMX6SX_CLK_LVDS2_IN] = imx_clk_hw_gate_exclusive("lvds2_in", "anaclk2", base + 0x160, 13, BIT(11));
- clks[IMX6SX_CLK_ENET_REF] = clk_register_divider_table(NULL, "enet_ref", "pll6_enet", 0,
+ hws[IMX6SX_CLK_ENET_REF] = clk_hw_register_divider_table(NULL, "enet_ref", "pll6_enet", 0,
base + 0xe0, 0, 2, 0, clk_enet_ref_table,
&imx_ccm_lock);
- clks[IMX6SX_CLK_ENET2_REF] = clk_register_divider_table(NULL, "enet2_ref", "pll6_enet", 0,
+ hws[IMX6SX_CLK_ENET2_REF] = clk_hw_register_divider_table(NULL, "enet2_ref", "pll6_enet", 0,
base + 0xe0, 2, 2, 0, clk_enet_ref_table,
&imx_ccm_lock);
- clks[IMX6SX_CLK_ENET2_REF_125M] = imx_clk_gate("enet2_ref_125m", "enet2_ref", base + 0xe0, 20);
+ hws[IMX6SX_CLK_ENET2_REF_125M] = imx_clk_hw_gate("enet2_ref_125m", "enet2_ref", base + 0xe0, 20);
- clks[IMX6SX_CLK_ENET_PTP_REF] = imx_clk_fixed_factor("enet_ptp_ref", "pll6_enet", 1, 20);
- clks[IMX6SX_CLK_ENET_PTP] = imx_clk_gate("enet_ptp_25m", "enet_ptp_ref", base + 0xe0, 21);
+ hws[IMX6SX_CLK_ENET_PTP_REF] = imx_clk_hw_fixed_factor("enet_ptp_ref", "pll6_enet", 1, 20);
+ hws[IMX6SX_CLK_ENET_PTP] = imx_clk_hw_gate("enet_ptp_25m", "enet_ptp_ref", base + 0xe0, 21);
/* name parent_name reg idx */
- clks[IMX6SX_CLK_PLL2_PFD0] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0);
- clks[IMX6SX_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1);
- clks[IMX6SX_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2);
- clks[IMX6SX_CLK_PLL2_PFD3] = imx_clk_pfd("pll2_pfd3_594m", "pll2_bus", base + 0x100, 3);
- clks[IMX6SX_CLK_PLL3_PFD0] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0);
- clks[IMX6SX_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1);
- clks[IMX6SX_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2);
- clks[IMX6SX_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3);
+ hws[IMX6SX_CLK_PLL2_PFD0] = imx_clk_hw_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0);
+ hws[IMX6SX_CLK_PLL2_PFD1] = imx_clk_hw_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1);
+ hws[IMX6SX_CLK_PLL2_PFD2] = imx_clk_hw_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2);
+ hws[IMX6SX_CLK_PLL2_PFD3] = imx_clk_hw_pfd("pll2_pfd3_594m", "pll2_bus", base + 0x100, 3);
+ hws[IMX6SX_CLK_PLL3_PFD0] = imx_clk_hw_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0);
+ hws[IMX6SX_CLK_PLL3_PFD1] = imx_clk_hw_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1);
+ hws[IMX6SX_CLK_PLL3_PFD2] = imx_clk_hw_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2);
+ hws[IMX6SX_CLK_PLL3_PFD3] = imx_clk_hw_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3);
/* name parent_name mult div */
- clks[IMX6SX_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2);
- clks[IMX6SX_CLK_PLL3_120M] = imx_clk_fixed_factor("pll3_120m", "pll3_usb_otg", 1, 4);
- clks[IMX6SX_CLK_PLL3_80M] = imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6);
- clks[IMX6SX_CLK_PLL3_60M] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8);
- clks[IMX6SX_CLK_TWD] = imx_clk_fixed_factor("twd", "arm", 1, 2);
- clks[IMX6SX_CLK_GPT_3M] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8);
-
- clks[IMX6SX_CLK_PLL4_POST_DIV] = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio",
+ hws[IMX6SX_CLK_PLL2_198M] = imx_clk_hw_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2);
+ hws[IMX6SX_CLK_PLL3_120M] = imx_clk_hw_fixed_factor("pll3_120m", "pll3_usb_otg", 1, 4);
+ hws[IMX6SX_CLK_PLL3_80M] = imx_clk_hw_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6);
+ hws[IMX6SX_CLK_PLL3_60M] = imx_clk_hw_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8);
+ hws[IMX6SX_CLK_TWD] = imx_clk_hw_fixed_factor("twd", "arm", 1, 2);
+ hws[IMX6SX_CLK_GPT_3M] = imx_clk_hw_fixed_factor("gpt_3m", "osc", 1, 8);
+
+ hws[IMX6SX_CLK_PLL4_POST_DIV] = clk_hw_register_divider_table(NULL, "pll4_post_div", "pll4_audio",
CLK_SET_RATE_PARENT, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock);
- clks[IMX6SX_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div",
+ hws[IMX6SX_CLK_PLL4_AUDIO_DIV] = clk_hw_register_divider(NULL, "pll4_audio_div", "pll4_post_div",
CLK_SET_RATE_PARENT, base + 0x170, 15, 1, 0, &imx_ccm_lock);
- clks[IMX6SX_CLK_PLL5_POST_DIV] = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video",
+ hws[IMX6SX_CLK_PLL5_POST_DIV] = clk_hw_register_divider_table(NULL, "pll5_post_div", "pll5_video",
CLK_SET_RATE_PARENT, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock);
- clks[IMX6SX_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div",
+ hws[IMX6SX_CLK_PLL5_VIDEO_DIV] = clk_hw_register_divider_table(NULL, "pll5_video_div", "pll5_post_div",
CLK_SET_RATE_PARENT, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock);
/* name reg shift width parent_names num_parents */
- clks[IMX6SX_CLK_LVDS1_SEL] = imx_clk_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
- clks[IMX6SX_CLK_LVDS2_SEL] = imx_clk_mux("lvds2_sel", base + 0x160, 5, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
+ hws[IMX6SX_CLK_LVDS1_SEL] = imx_clk_hw_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
+ hws[IMX6SX_CLK_LVDS2_SEL] = imx_clk_hw_mux("lvds2_sel", base + 0x160, 5, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
np = ccm_node;
base = of_iomap(np, 0);
WARN_ON(!base);
/* name reg shift width parent_names num_parents */
- clks[IMX6SX_CLK_STEP] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels));
- clks[IMX6SX_CLK_PLL1_SW] = imx_clk_mux("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels));
- clks[IMX6SX_CLK_OCRAM_SEL] = imx_clk_mux("ocram_sel", base + 0x14, 6, 2, ocram_sels, ARRAY_SIZE(ocram_sels));
- clks[IMX6SX_CLK_PERIPH_PRE] = imx_clk_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
- clks[IMX6SX_CLK_PERIPH2_PRE] = imx_clk_mux("periph2_pre", base + 0x18, 21, 2, periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels));
- clks[IMX6SX_CLK_PERIPH_CLK2_SEL] = imx_clk_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
- clks[IMX6SX_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
- clks[IMX6SX_CLK_PCIE_AXI_SEL] = imx_clk_mux("pcie_axi_sel", base + 0x18, 10, 1, pcie_axi_sels, ARRAY_SIZE(pcie_axi_sels));
- clks[IMX6SX_CLK_GPU_AXI_SEL] = imx_clk_mux("gpu_axi_sel", base + 0x18, 8, 2, gpu_axi_sels, ARRAY_SIZE(gpu_axi_sels));
- clks[IMX6SX_CLK_GPU_CORE_SEL] = imx_clk_mux("gpu_core_sel", base + 0x18, 4, 2, gpu_core_sels, ARRAY_SIZE(gpu_core_sels));
- clks[IMX6SX_CLK_EIM_SLOW_SEL] = imx_clk_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels, ARRAY_SIZE(eim_slow_sels));
- clks[IMX6SX_CLK_USDHC1_SEL] = imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
- clks[IMX6SX_CLK_USDHC2_SEL] = imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
- clks[IMX6SX_CLK_USDHC3_SEL] = imx_clk_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
- clks[IMX6SX_CLK_USDHC4_SEL] = imx_clk_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
- clks[IMX6SX_CLK_SSI3_SEL] = imx_clk_mux("ssi3_sel", base + 0x1c, 14, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
- clks[IMX6SX_CLK_SSI2_SEL] = imx_clk_mux("ssi2_sel", base + 0x1c, 12, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
- clks[IMX6SX_CLK_SSI1_SEL] = imx_clk_mux("ssi1_sel", base + 0x1c, 10, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
- clks[IMX6SX_CLK_QSPI1_SEL] = imx_clk_mux_flags("qspi1_sel", base + 0x1c, 7, 3, qspi1_sels, ARRAY_SIZE(qspi1_sels), CLK_SET_RATE_PARENT);
- clks[IMX6SX_CLK_PERCLK_SEL] = imx_clk_mux("perclk_sel", base + 0x1c, 6, 1, perclk_sels, ARRAY_SIZE(perclk_sels));
- clks[IMX6SX_CLK_VID_SEL] = imx_clk_mux("vid_sel", base + 0x20, 21, 3, vid_sels, ARRAY_SIZE(vid_sels));
- clks[IMX6SX_CLK_ESAI_SEL] = imx_clk_mux("esai_sel", base + 0x20, 19, 2, audio_sels, ARRAY_SIZE(audio_sels));
- clks[IMX6SX_CLK_CAN_SEL] = imx_clk_mux("can_sel", base + 0x20, 8, 2, can_sels, ARRAY_SIZE(can_sels));
- clks[IMX6SX_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels));
- clks[IMX6SX_CLK_QSPI2_SEL] = imx_clk_mux_flags("qspi2_sel", base + 0x2c, 15, 3, qspi2_sels, ARRAY_SIZE(qspi2_sels), CLK_SET_RATE_PARENT);
- clks[IMX6SX_CLK_SPDIF_SEL] = imx_clk_mux("spdif_sel", base + 0x30, 20, 2, audio_sels, ARRAY_SIZE(audio_sels));
- clks[IMX6SX_CLK_AUDIO_SEL] = imx_clk_mux("audio_sel", base + 0x30, 7, 2, audio_sels, ARRAY_SIZE(audio_sels));
- clks[IMX6SX_CLK_ENET_PRE_SEL] = imx_clk_mux("enet_pre_sel", base + 0x34, 15, 3, enet_pre_sels, ARRAY_SIZE(enet_pre_sels));
- clks[IMX6SX_CLK_ENET_SEL] = imx_clk_mux("enet_sel", base + 0x34, 9, 3, enet_sels, ARRAY_SIZE(enet_sels));
- clks[IMX6SX_CLK_M4_PRE_SEL] = imx_clk_mux("m4_pre_sel", base + 0x34, 6, 3, m4_pre_sels, ARRAY_SIZE(m4_pre_sels));
- clks[IMX6SX_CLK_M4_SEL] = imx_clk_mux("m4_sel", base + 0x34, 0, 3, m4_sels, ARRAY_SIZE(m4_sels));
- clks[IMX6SX_CLK_ECSPI_SEL] = imx_clk_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels));
- clks[IMX6SX_CLK_LCDIF2_PRE_SEL] = imx_clk_mux("lcdif2_pre_sel", base + 0x38, 6, 3, lcdif2_pre_sels, ARRAY_SIZE(lcdif2_pre_sels));
- clks[IMX6SX_CLK_LCDIF2_SEL] = imx_clk_mux("lcdif2_sel", base + 0x38, 0, 3, lcdif2_sels, ARRAY_SIZE(lcdif2_sels));
- clks[IMX6SX_CLK_DISPLAY_SEL] = imx_clk_mux("display_sel", base + 0x3c, 14, 2, display_sels, ARRAY_SIZE(display_sels));
- clks[IMX6SX_CLK_CSI_SEL] = imx_clk_mux("csi_sel", base + 0x3c, 9, 2, csi_sels, ARRAY_SIZE(csi_sels));
- clks[IMX6SX_CLK_CKO1_SEL] = imx_clk_mux("cko1_sel", base + 0x60, 0, 4, cko1_sels, ARRAY_SIZE(cko1_sels));
- clks[IMX6SX_CLK_CKO2_SEL] = imx_clk_mux("cko2_sel", base + 0x60, 16, 5, cko2_sels, ARRAY_SIZE(cko2_sels));
- clks[IMX6SX_CLK_CKO] = imx_clk_mux("cko", base + 0x60, 8, 1, cko_sels, ARRAY_SIZE(cko_sels));
-
- clks[IMX6SX_CLK_LDB_DI1_DIV_SEL] = imx_clk_mux_flags("ldb_di1_div_sel", base + 0x20, 11, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels), CLK_SET_RATE_PARENT);
- clks[IMX6SX_CLK_LDB_DI0_DIV_SEL] = imx_clk_mux_flags("ldb_di0_div_sel", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels), CLK_SET_RATE_PARENT);
- clks[IMX6SX_CLK_LDB_DI1_SEL] = imx_clk_mux_flags("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di1_sels, ARRAY_SIZE(ldb_di1_sels), CLK_SET_RATE_PARENT);
- clks[IMX6SX_CLK_LDB_DI0_SEL] = imx_clk_mux_flags("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di0_sels, ARRAY_SIZE(ldb_di0_sels), CLK_SET_RATE_PARENT);
- clks[IMX6SX_CLK_LCDIF1_PRE_SEL] = imx_clk_mux_flags("lcdif1_pre_sel", base + 0x38, 15, 3, lcdif1_pre_sels, ARRAY_SIZE(lcdif1_pre_sels), CLK_SET_RATE_PARENT);
- clks[IMX6SX_CLK_LCDIF1_SEL] = imx_clk_mux_flags("lcdif1_sel", base + 0x38, 9, 3, lcdif1_sels, ARRAY_SIZE(lcdif1_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6SX_CLK_STEP] = imx_clk_hw_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels));
+ hws[IMX6SX_CLK_PLL1_SW] = imx_clk_hw_mux("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels));
+ hws[IMX6SX_CLK_OCRAM_SEL] = imx_clk_hw_mux("ocram_sel", base + 0x14, 6, 2, ocram_sels, ARRAY_SIZE(ocram_sels));
+ hws[IMX6SX_CLK_PERIPH_PRE] = imx_clk_hw_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
+ hws[IMX6SX_CLK_PERIPH2_PRE] = imx_clk_hw_mux("periph2_pre", base + 0x18, 21, 2, periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels));
+ hws[IMX6SX_CLK_PERIPH_CLK2_SEL] = imx_clk_hw_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
+ hws[IMX6SX_CLK_PERIPH2_CLK2_SEL] = imx_clk_hw_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
+ hws[IMX6SX_CLK_PCIE_AXI_SEL] = imx_clk_hw_mux("pcie_axi_sel", base + 0x18, 10, 1, pcie_axi_sels, ARRAY_SIZE(pcie_axi_sels));
+ hws[IMX6SX_CLK_GPU_AXI_SEL] = imx_clk_hw_mux("gpu_axi_sel", base + 0x18, 8, 2, gpu_axi_sels, ARRAY_SIZE(gpu_axi_sels));
+ hws[IMX6SX_CLK_GPU_CORE_SEL] = imx_clk_hw_mux("gpu_core_sel", base + 0x18, 4, 2, gpu_core_sels, ARRAY_SIZE(gpu_core_sels));
+ hws[IMX6SX_CLK_EIM_SLOW_SEL] = imx_clk_hw_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels, ARRAY_SIZE(eim_slow_sels));
+ hws[IMX6SX_CLK_USDHC1_SEL] = imx_clk_hw_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+ hws[IMX6SX_CLK_USDHC2_SEL] = imx_clk_hw_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+ hws[IMX6SX_CLK_USDHC3_SEL] = imx_clk_hw_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+ hws[IMX6SX_CLK_USDHC4_SEL] = imx_clk_hw_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+ hws[IMX6SX_CLK_SSI3_SEL] = imx_clk_hw_mux("ssi3_sel", base + 0x1c, 14, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
+ hws[IMX6SX_CLK_SSI2_SEL] = imx_clk_hw_mux("ssi2_sel", base + 0x1c, 12, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
+ hws[IMX6SX_CLK_SSI1_SEL] = imx_clk_hw_mux("ssi1_sel", base + 0x1c, 10, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
+ hws[IMX6SX_CLK_QSPI1_SEL] = imx_clk_hw_mux_flags("qspi1_sel", base + 0x1c, 7, 3, qspi1_sels, ARRAY_SIZE(qspi1_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6SX_CLK_PERCLK_SEL] = imx_clk_hw_mux("perclk_sel", base + 0x1c, 6, 1, perclk_sels, ARRAY_SIZE(perclk_sels));
+ hws[IMX6SX_CLK_VID_SEL] = imx_clk_hw_mux("vid_sel", base + 0x20, 21, 3, vid_sels, ARRAY_SIZE(vid_sels));
+ hws[IMX6SX_CLK_ESAI_SEL] = imx_clk_hw_mux("esai_sel", base + 0x20, 19, 2, audio_sels, ARRAY_SIZE(audio_sels));
+ hws[IMX6SX_CLK_CAN_SEL] = imx_clk_hw_mux("can_sel", base + 0x20, 8, 2, can_sels, ARRAY_SIZE(can_sels));
+ hws[IMX6SX_CLK_UART_SEL] = imx_clk_hw_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels));
+ hws[IMX6SX_CLK_QSPI2_SEL] = imx_clk_hw_mux_flags("qspi2_sel", base + 0x2c, 15, 3, qspi2_sels, ARRAY_SIZE(qspi2_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6SX_CLK_SPDIF_SEL] = imx_clk_hw_mux("spdif_sel", base + 0x30, 20, 2, audio_sels, ARRAY_SIZE(audio_sels));
+ hws[IMX6SX_CLK_AUDIO_SEL] = imx_clk_hw_mux("audio_sel", base + 0x30, 7, 2, audio_sels, ARRAY_SIZE(audio_sels));
+ hws[IMX6SX_CLK_ENET_PRE_SEL] = imx_clk_hw_mux("enet_pre_sel", base + 0x34, 15, 3, enet_pre_sels, ARRAY_SIZE(enet_pre_sels));
+ hws[IMX6SX_CLK_ENET_SEL] = imx_clk_hw_mux("enet_sel", base + 0x34, 9, 3, enet_sels, ARRAY_SIZE(enet_sels));
+ hws[IMX6SX_CLK_M4_PRE_SEL] = imx_clk_hw_mux("m4_pre_sel", base + 0x34, 6, 3, m4_pre_sels, ARRAY_SIZE(m4_pre_sels));
+ hws[IMX6SX_CLK_M4_SEL] = imx_clk_hw_mux("m4_sel", base + 0x34, 0, 3, m4_sels, ARRAY_SIZE(m4_sels));
+ hws[IMX6SX_CLK_ECSPI_SEL] = imx_clk_hw_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels));
+ hws[IMX6SX_CLK_LCDIF2_PRE_SEL] = imx_clk_hw_mux("lcdif2_pre_sel", base + 0x38, 6, 3, lcdif2_pre_sels, ARRAY_SIZE(lcdif2_pre_sels));
+ hws[IMX6SX_CLK_LCDIF2_SEL] = imx_clk_hw_mux("lcdif2_sel", base + 0x38, 0, 3, lcdif2_sels, ARRAY_SIZE(lcdif2_sels));
+ hws[IMX6SX_CLK_DISPLAY_SEL] = imx_clk_hw_mux("display_sel", base + 0x3c, 14, 2, display_sels, ARRAY_SIZE(display_sels));
+ hws[IMX6SX_CLK_CSI_SEL] = imx_clk_hw_mux("csi_sel", base + 0x3c, 9, 2, csi_sels, ARRAY_SIZE(csi_sels));
+ hws[IMX6SX_CLK_CKO1_SEL] = imx_clk_hw_mux("cko1_sel", base + 0x60, 0, 4, cko1_sels, ARRAY_SIZE(cko1_sels));
+ hws[IMX6SX_CLK_CKO2_SEL] = imx_clk_hw_mux("cko2_sel", base + 0x60, 16, 5, cko2_sels, ARRAY_SIZE(cko2_sels));
+ hws[IMX6SX_CLK_CKO] = imx_clk_hw_mux("cko", base + 0x60, 8, 1, cko_sels, ARRAY_SIZE(cko_sels));
+
+ hws[IMX6SX_CLK_LDB_DI1_DIV_SEL] = imx_clk_hw_mux_flags("ldb_di1_div_sel", base + 0x20, 11, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6SX_CLK_LDB_DI0_DIV_SEL] = imx_clk_hw_mux_flags("ldb_di0_div_sel", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6SX_CLK_LDB_DI1_SEL] = imx_clk_hw_mux_flags("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di1_sels, ARRAY_SIZE(ldb_di1_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6SX_CLK_LDB_DI0_SEL] = imx_clk_hw_mux_flags("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di0_sels, ARRAY_SIZE(ldb_di0_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6SX_CLK_LCDIF1_PRE_SEL] = imx_clk_hw_mux_flags("lcdif1_pre_sel", base + 0x38, 15, 3, lcdif1_pre_sels, ARRAY_SIZE(lcdif1_pre_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6SX_CLK_LCDIF1_SEL] = imx_clk_hw_mux_flags("lcdif1_sel", base + 0x38, 9, 3, lcdif1_sels, ARRAY_SIZE(lcdif1_sels), CLK_SET_RATE_PARENT);
/* name parent_name reg shift width */
- clks[IMX6SX_CLK_PERIPH_CLK2] = imx_clk_divider("periph_clk2", "periph_clk2_sel", base + 0x14, 27, 3);
- clks[IMX6SX_CLK_PERIPH2_CLK2] = imx_clk_divider("periph2_clk2", "periph2_clk2_sel", base + 0x14, 0, 3);
- clks[IMX6SX_CLK_IPG] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2);
- clks[IMX6SX_CLK_GPU_CORE_PODF] = imx_clk_divider("gpu_core_podf", "gpu_core_sel", base + 0x18, 29, 3);
- clks[IMX6SX_CLK_GPU_AXI_PODF] = imx_clk_divider("gpu_axi_podf", "gpu_axi_sel", base + 0x18, 26, 3);
- clks[IMX6SX_CLK_LCDIF1_PODF] = imx_clk_divider("lcdif1_podf", "lcdif1_pred", base + 0x18, 23, 3);
- clks[IMX6SX_CLK_QSPI1_PODF] = imx_clk_divider("qspi1_podf", "qspi1_sel", base + 0x1c, 26, 3);
- clks[IMX6SX_CLK_EIM_SLOW_PODF] = imx_clk_divider("eim_slow_podf", "eim_slow_sel", base + 0x1c, 23, 3);
- clks[IMX6SX_CLK_LCDIF2_PODF] = imx_clk_divider("lcdif2_podf", "lcdif2_pred", base + 0x1c, 20, 3);
- clks[IMX6SX_CLK_PERCLK] = imx_clk_divider_flags("perclk", "perclk_sel", base + 0x1c, 0, 6, CLK_IS_CRITICAL);
- clks[IMX6SX_CLK_VID_PODF] = imx_clk_divider("vid_podf", "vid_sel", base + 0x20, 24, 2);
- clks[IMX6SX_CLK_CAN_PODF] = imx_clk_divider("can_podf", "can_sel", base + 0x20, 2, 6);
- clks[IMX6SX_CLK_USDHC4_PODF] = imx_clk_divider("usdhc4_podf", "usdhc4_sel", base + 0x24, 22, 3);
- clks[IMX6SX_CLK_USDHC3_PODF] = imx_clk_divider("usdhc3_podf", "usdhc3_sel", base + 0x24, 19, 3);
- clks[IMX6SX_CLK_USDHC2_PODF] = imx_clk_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3);
- clks[IMX6SX_CLK_USDHC1_PODF] = imx_clk_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3);
- clks[IMX6SX_CLK_UART_PODF] = imx_clk_divider("uart_podf", "uart_sel", base + 0x24, 0, 6);
- clks[IMX6SX_CLK_ESAI_PRED] = imx_clk_divider("esai_pred", "esai_sel", base + 0x28, 9, 3);
- clks[IMX6SX_CLK_ESAI_PODF] = imx_clk_divider("esai_podf", "esai_pred", base + 0x28, 25, 3);
- clks[IMX6SX_CLK_SSI3_PRED] = imx_clk_divider("ssi3_pred", "ssi3_sel", base + 0x28, 22, 3);
- clks[IMX6SX_CLK_SSI3_PODF] = imx_clk_divider("ssi3_podf", "ssi3_pred", base + 0x28, 16, 6);
- clks[IMX6SX_CLK_SSI1_PRED] = imx_clk_divider("ssi1_pred", "ssi1_sel", base + 0x28, 6, 3);
- clks[IMX6SX_CLK_SSI1_PODF] = imx_clk_divider("ssi1_podf", "ssi1_pred", base + 0x28, 0, 6);
- clks[IMX6SX_CLK_QSPI2_PRED] = imx_clk_divider("qspi2_pred", "qspi2_sel", base + 0x2c, 18, 3);
- clks[IMX6SX_CLK_QSPI2_PODF] = imx_clk_divider("qspi2_podf", "qspi2_pred", base + 0x2c, 21, 6);
- clks[IMX6SX_CLK_SSI2_PRED] = imx_clk_divider("ssi2_pred", "ssi2_sel", base + 0x2c, 6, 3);
- clks[IMX6SX_CLK_SSI2_PODF] = imx_clk_divider("ssi2_podf", "ssi2_pred", base + 0x2c, 0, 6);
- clks[IMX6SX_CLK_SPDIF_PRED] = imx_clk_divider("spdif_pred", "spdif_sel", base + 0x30, 25, 3);
- clks[IMX6SX_CLK_SPDIF_PODF] = imx_clk_divider("spdif_podf", "spdif_pred", base + 0x30, 22, 3);
- clks[IMX6SX_CLK_AUDIO_PRED] = imx_clk_divider("audio_pred", "audio_sel", base + 0x30, 12, 3);
- clks[IMX6SX_CLK_AUDIO_PODF] = imx_clk_divider("audio_podf", "audio_pred", base + 0x30, 9, 3);
- clks[IMX6SX_CLK_ENET_PODF] = imx_clk_divider("enet_podf", "enet_pre_sel", base + 0x34, 12, 3);
- clks[IMX6SX_CLK_M4_PODF] = imx_clk_divider("m4_podf", "m4_sel", base + 0x34, 3, 3);
- clks[IMX6SX_CLK_ECSPI_PODF] = imx_clk_divider("ecspi_podf", "ecspi_sel", base + 0x38, 19, 6);
- clks[IMX6SX_CLK_LCDIF1_PRED] = imx_clk_divider("lcdif1_pred", "lcdif1_pre_sel", base + 0x38, 12, 3);
- clks[IMX6SX_CLK_LCDIF2_PRED] = imx_clk_divider("lcdif2_pred", "lcdif2_pre_sel", base + 0x38, 3, 3);
- clks[IMX6SX_CLK_DISPLAY_PODF] = imx_clk_divider("display_podf", "display_sel", base + 0x3c, 16, 3);
- clks[IMX6SX_CLK_CSI_PODF] = imx_clk_divider("csi_podf", "csi_sel", base + 0x3c, 11, 3);
- clks[IMX6SX_CLK_CKO1_PODF] = imx_clk_divider("cko1_podf", "cko1_sel", base + 0x60, 4, 3);
- clks[IMX6SX_CLK_CKO2_PODF] = imx_clk_divider("cko2_podf", "cko2_sel", base + 0x60, 21, 3);
-
- clks[IMX6SX_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
- clks[IMX6SX_CLK_LDB_DI0_DIV_7] = imx_clk_fixed_factor("ldb_di0_div_7", "ldb_di0_sel", 1, 7);
- clks[IMX6SX_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7);
- clks[IMX6SX_CLK_LDB_DI1_DIV_7] = imx_clk_fixed_factor("ldb_di1_div_7", "ldb_di1_sel", 1, 7);
+ hws[IMX6SX_CLK_PERIPH_CLK2] = imx_clk_hw_divider("periph_clk2", "periph_clk2_sel", base + 0x14, 27, 3);
+ hws[IMX6SX_CLK_PERIPH2_CLK2] = imx_clk_hw_divider("periph2_clk2", "periph2_clk2_sel", base + 0x14, 0, 3);
+ hws[IMX6SX_CLK_IPG] = imx_clk_hw_divider("ipg", "ahb", base + 0x14, 8, 2);
+ hws[IMX6SX_CLK_GPU_CORE_PODF] = imx_clk_hw_divider("gpu_core_podf", "gpu_core_sel", base + 0x18, 29, 3);
+ hws[IMX6SX_CLK_GPU_AXI_PODF] = imx_clk_hw_divider("gpu_axi_podf", "gpu_axi_sel", base + 0x18, 26, 3);
+ hws[IMX6SX_CLK_LCDIF1_PODF] = imx_clk_hw_divider("lcdif1_podf", "lcdif1_pred", base + 0x18, 23, 3);
+ hws[IMX6SX_CLK_QSPI1_PODF] = imx_clk_hw_divider("qspi1_podf", "qspi1_sel", base + 0x1c, 26, 3);
+ hws[IMX6SX_CLK_EIM_SLOW_PODF] = imx_clk_hw_divider("eim_slow_podf", "eim_slow_sel", base + 0x1c, 23, 3);
+ hws[IMX6SX_CLK_LCDIF2_PODF] = imx_clk_hw_divider("lcdif2_podf", "lcdif2_pred", base + 0x1c, 20, 3);
+ hws[IMX6SX_CLK_PERCLK] = imx_clk_hw_divider_flags("perclk", "perclk_sel", base + 0x1c, 0, 6, CLK_IS_CRITICAL);
+ hws[IMX6SX_CLK_VID_PODF] = imx_clk_hw_divider("vid_podf", "vid_sel", base + 0x20, 24, 2);
+ hws[IMX6SX_CLK_CAN_PODF] = imx_clk_hw_divider("can_podf", "can_sel", base + 0x20, 2, 6);
+ hws[IMX6SX_CLK_USDHC4_PODF] = imx_clk_hw_divider("usdhc4_podf", "usdhc4_sel", base + 0x24, 22, 3);
+ hws[IMX6SX_CLK_USDHC3_PODF] = imx_clk_hw_divider("usdhc3_podf", "usdhc3_sel", base + 0x24, 19, 3);
+ hws[IMX6SX_CLK_USDHC2_PODF] = imx_clk_hw_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3);
+ hws[IMX6SX_CLK_USDHC1_PODF] = imx_clk_hw_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3);
+ hws[IMX6SX_CLK_UART_PODF] = imx_clk_hw_divider("uart_podf", "uart_sel", base + 0x24, 0, 6);
+ hws[IMX6SX_CLK_ESAI_PRED] = imx_clk_hw_divider("esai_pred", "esai_sel", base + 0x28, 9, 3);
+ hws[IMX6SX_CLK_ESAI_PODF] = imx_clk_hw_divider("esai_podf", "esai_pred", base + 0x28, 25, 3);
+ hws[IMX6SX_CLK_SSI3_PRED] = imx_clk_hw_divider("ssi3_pred", "ssi3_sel", base + 0x28, 22, 3);
+ hws[IMX6SX_CLK_SSI3_PODF] = imx_clk_hw_divider("ssi3_podf", "ssi3_pred", base + 0x28, 16, 6);
+ hws[IMX6SX_CLK_SSI1_PRED] = imx_clk_hw_divider("ssi1_pred", "ssi1_sel", base + 0x28, 6, 3);
+ hws[IMX6SX_CLK_SSI1_PODF] = imx_clk_hw_divider("ssi1_podf", "ssi1_pred", base + 0x28, 0, 6);
+ hws[IMX6SX_CLK_QSPI2_PRED] = imx_clk_hw_divider("qspi2_pred", "qspi2_sel", base + 0x2c, 18, 3);
+ hws[IMX6SX_CLK_QSPI2_PODF] = imx_clk_hw_divider("qspi2_podf", "qspi2_pred", base + 0x2c, 21, 6);
+ hws[IMX6SX_CLK_SSI2_PRED] = imx_clk_hw_divider("ssi2_pred", "ssi2_sel", base + 0x2c, 6, 3);
+ hws[IMX6SX_CLK_SSI2_PODF] = imx_clk_hw_divider("ssi2_podf", "ssi2_pred", base + 0x2c, 0, 6);
+ hws[IMX6SX_CLK_SPDIF_PRED] = imx_clk_hw_divider("spdif_pred", "spdif_sel", base + 0x30, 25, 3);
+ hws[IMX6SX_CLK_SPDIF_PODF] = imx_clk_hw_divider("spdif_podf", "spdif_pred", base + 0x30, 22, 3);
+ hws[IMX6SX_CLK_AUDIO_PRED] = imx_clk_hw_divider("audio_pred", "audio_sel", base + 0x30, 12, 3);
+ hws[IMX6SX_CLK_AUDIO_PODF] = imx_clk_hw_divider("audio_podf", "audio_pred", base + 0x30, 9, 3);
+ hws[IMX6SX_CLK_ENET_PODF] = imx_clk_hw_divider("enet_podf", "enet_pre_sel", base + 0x34, 12, 3);
+ hws[IMX6SX_CLK_M4_PODF] = imx_clk_hw_divider("m4_podf", "m4_sel", base + 0x34, 3, 3);
+ hws[IMX6SX_CLK_ECSPI_PODF] = imx_clk_hw_divider("ecspi_podf", "ecspi_sel", base + 0x38, 19, 6);
+ hws[IMX6SX_CLK_LCDIF1_PRED] = imx_clk_hw_divider("lcdif1_pred", "lcdif1_pre_sel", base + 0x38, 12, 3);
+ hws[IMX6SX_CLK_LCDIF2_PRED] = imx_clk_hw_divider("lcdif2_pred", "lcdif2_pre_sel", base + 0x38, 3, 3);
+ hws[IMX6SX_CLK_DISPLAY_PODF] = imx_clk_hw_divider("display_podf", "display_sel", base + 0x3c, 16, 3);
+ hws[IMX6SX_CLK_CSI_PODF] = imx_clk_hw_divider("csi_podf", "csi_sel", base + 0x3c, 11, 3);
+ hws[IMX6SX_CLK_CKO1_PODF] = imx_clk_hw_divider("cko1_podf", "cko1_sel", base + 0x60, 4, 3);
+ hws[IMX6SX_CLK_CKO2_PODF] = imx_clk_hw_divider("cko2_podf", "cko2_sel", base + 0x60, 21, 3);
+
+ hws[IMX6SX_CLK_LDB_DI0_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
+ hws[IMX6SX_CLK_LDB_DI0_DIV_7] = imx_clk_hw_fixed_factor("ldb_di0_div_7", "ldb_di0_sel", 1, 7);
+ hws[IMX6SX_CLK_LDB_DI1_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7);
+ hws[IMX6SX_CLK_LDB_DI1_DIV_7] = imx_clk_hw_fixed_factor("ldb_di1_div_7", "ldb_di1_sel", 1, 7);
/* name reg shift width busy: reg, shift parent_names num_parents */
- clks[IMX6SX_CLK_PERIPH] = imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels));
- clks[IMX6SX_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels));
+ hws[IMX6SX_CLK_PERIPH] = imx_clk_hw_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels));
+ hws[IMX6SX_CLK_PERIPH2] = imx_clk_hw_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels));
/* name parent_name reg shift width busy: reg, shift */
- clks[IMX6SX_CLK_OCRAM_PODF] = imx_clk_busy_divider("ocram_podf", "ocram_sel", base + 0x14, 16, 3, base + 0x48, 0);
- clks[IMX6SX_CLK_AHB] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1);
- clks[IMX6SX_CLK_MMDC_PODF] = imx_clk_busy_divider("mmdc_podf", "periph2", base + 0x14, 3, 3, base + 0x48, 2);
- clks[IMX6SX_CLK_ARM] = imx_clk_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16);
+ hws[IMX6SX_CLK_OCRAM_PODF] = imx_clk_hw_busy_divider("ocram_podf", "ocram_sel", base + 0x14, 16, 3, base + 0x48, 0);
+ hws[IMX6SX_CLK_AHB] = imx_clk_hw_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1);
+ hws[IMX6SX_CLK_MMDC_PODF] = imx_clk_hw_busy_divider("mmdc_podf", "periph2", base + 0x14, 3, 3, base + 0x48, 2);
+ hws[IMX6SX_CLK_ARM] = imx_clk_hw_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16);
/* name parent_name reg shift */
/* CCGR0 */
- clks[IMX6SX_CLK_AIPS_TZ1] = imx_clk_gate2_flags("aips_tz1", "ahb", base + 0x68, 0, CLK_IS_CRITICAL);
- clks[IMX6SX_CLK_AIPS_TZ2] = imx_clk_gate2_flags("aips_tz2", "ahb", base + 0x68, 2, CLK_IS_CRITICAL);
- clks[IMX6SX_CLK_APBH_DMA] = imx_clk_gate2("apbh_dma", "usdhc3", base + 0x68, 4);
- clks[IMX6SX_CLK_ASRC_MEM] = imx_clk_gate2_shared("asrc_mem", "ahb", base + 0x68, 6, &share_count_asrc);
- clks[IMX6SX_CLK_ASRC_IPG] = imx_clk_gate2_shared("asrc_ipg", "ahb", base + 0x68, 6, &share_count_asrc);
- clks[IMX6SX_CLK_CAAM_MEM] = imx_clk_gate2("caam_mem", "ahb", base + 0x68, 8);
- clks[IMX6SX_CLK_CAAM_ACLK] = imx_clk_gate2("caam_aclk", "ahb", base + 0x68, 10);
- clks[IMX6SX_CLK_CAAM_IPG] = imx_clk_gate2("caam_ipg", "ipg", base + 0x68, 12);
- clks[IMX6SX_CLK_CAN1_IPG] = imx_clk_gate2("can1_ipg", "ipg", base + 0x68, 14);
- clks[IMX6SX_CLK_CAN1_SERIAL] = imx_clk_gate2("can1_serial", "can_podf", base + 0x68, 16);
- clks[IMX6SX_CLK_CAN2_IPG] = imx_clk_gate2("can2_ipg", "ipg", base + 0x68, 18);
- clks[IMX6SX_CLK_CAN2_SERIAL] = imx_clk_gate2("can2_serial", "can_podf", base + 0x68, 20);
- clks[IMX6SX_CLK_DCIC1] = imx_clk_gate2("dcic1", "display_podf", base + 0x68, 24);
- clks[IMX6SX_CLK_DCIC2] = imx_clk_gate2("dcic2", "display_podf", base + 0x68, 26);
- clks[IMX6SX_CLK_AIPS_TZ3] = imx_clk_gate2_flags("aips_tz3", "ahb", base + 0x68, 30, CLK_IS_CRITICAL);
+ hws[IMX6SX_CLK_AIPS_TZ1] = imx_clk_hw_gate2_flags("aips_tz1", "ahb", base + 0x68, 0, CLK_IS_CRITICAL);
+ hws[IMX6SX_CLK_AIPS_TZ2] = imx_clk_hw_gate2_flags("aips_tz2", "ahb", base + 0x68, 2, CLK_IS_CRITICAL);
+ hws[IMX6SX_CLK_APBH_DMA] = imx_clk_hw_gate2("apbh_dma", "usdhc3", base + 0x68, 4);
+ hws[IMX6SX_CLK_ASRC_MEM] = imx_clk_hw_gate2_shared("asrc_mem", "ahb", base + 0x68, 6, &share_count_asrc);
+ hws[IMX6SX_CLK_ASRC_IPG] = imx_clk_hw_gate2_shared("asrc_ipg", "ahb", base + 0x68, 6, &share_count_asrc);
+ hws[IMX6SX_CLK_CAAM_MEM] = imx_clk_hw_gate2("caam_mem", "ahb", base + 0x68, 8);
+ hws[IMX6SX_CLK_CAAM_ACLK] = imx_clk_hw_gate2("caam_aclk", "ahb", base + 0x68, 10);
+ hws[IMX6SX_CLK_CAAM_IPG] = imx_clk_hw_gate2("caam_ipg", "ipg", base + 0x68, 12);
+ hws[IMX6SX_CLK_CAN1_IPG] = imx_clk_hw_gate2("can1_ipg", "ipg", base + 0x68, 14);
+ hws[IMX6SX_CLK_CAN1_SERIAL] = imx_clk_hw_gate2("can1_serial", "can_podf", base + 0x68, 16);
+ hws[IMX6SX_CLK_CAN2_IPG] = imx_clk_hw_gate2("can2_ipg", "ipg", base + 0x68, 18);
+ hws[IMX6SX_CLK_CAN2_SERIAL] = imx_clk_hw_gate2("can2_serial", "can_podf", base + 0x68, 20);
+ hws[IMX6SX_CLK_DCIC1] = imx_clk_hw_gate2("dcic1", "display_podf", base + 0x68, 24);
+ hws[IMX6SX_CLK_DCIC2] = imx_clk_hw_gate2("dcic2", "display_podf", base + 0x68, 26);
+ hws[IMX6SX_CLK_AIPS_TZ3] = imx_clk_hw_gate2_flags("aips_tz3", "ahb", base + 0x68, 30, CLK_IS_CRITICAL);
/* CCGR1 */
- clks[IMX6SX_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_podf", base + 0x6c, 0);
- clks[IMX6SX_CLK_ECSPI2] = imx_clk_gate2("ecspi2", "ecspi_podf", base + 0x6c, 2);
- clks[IMX6SX_CLK_ECSPI3] = imx_clk_gate2("ecspi3", "ecspi_podf", base + 0x6c, 4);
- clks[IMX6SX_CLK_ECSPI4] = imx_clk_gate2("ecspi4", "ecspi_podf", base + 0x6c, 6);
- clks[IMX6SX_CLK_ECSPI5] = imx_clk_gate2("ecspi5", "ecspi_podf", base + 0x6c, 8);
- clks[IMX6SX_CLK_EPIT1] = imx_clk_gate2("epit1", "perclk", base + 0x6c, 12);
- clks[IMX6SX_CLK_EPIT2] = imx_clk_gate2("epit2", "perclk", base + 0x6c, 14);
- clks[IMX6SX_CLK_ESAI_EXTAL] = imx_clk_gate2_shared("esai_extal", "esai_podf", base + 0x6c, 16, &share_count_esai);
- clks[IMX6SX_CLK_ESAI_IPG] = imx_clk_gate2_shared("esai_ipg", "ahb", base + 0x6c, 16, &share_count_esai);
- clks[IMX6SX_CLK_ESAI_MEM] = imx_clk_gate2_shared("esai_mem", "ahb", base + 0x6c, 16, &share_count_esai);
- clks[IMX6SX_CLK_WAKEUP] = imx_clk_gate2_flags("wakeup", "ipg", base + 0x6c, 18, CLK_IS_CRITICAL);
- clks[IMX6SX_CLK_GPT_BUS] = imx_clk_gate2("gpt_bus", "perclk", base + 0x6c, 20);
- clks[IMX6SX_CLK_GPT_SERIAL] = imx_clk_gate2("gpt_serial", "perclk", base + 0x6c, 22);
- clks[IMX6SX_CLK_GPU] = imx_clk_gate2("gpu", "gpu_core_podf", base + 0x6c, 26);
- clks[IMX6SX_CLK_OCRAM_S] = imx_clk_gate2("ocram_s", "ahb", base + 0x6c, 28);
- clks[IMX6SX_CLK_CANFD] = imx_clk_gate2("canfd", "can_podf", base + 0x6c, 30);
+ hws[IMX6SX_CLK_ECSPI1] = imx_clk_hw_gate2("ecspi1", "ecspi_podf", base + 0x6c, 0);
+ hws[IMX6SX_CLK_ECSPI2] = imx_clk_hw_gate2("ecspi2", "ecspi_podf", base + 0x6c, 2);
+ hws[IMX6SX_CLK_ECSPI3] = imx_clk_hw_gate2("ecspi3", "ecspi_podf", base + 0x6c, 4);
+ hws[IMX6SX_CLK_ECSPI4] = imx_clk_hw_gate2("ecspi4", "ecspi_podf", base + 0x6c, 6);
+ hws[IMX6SX_CLK_ECSPI5] = imx_clk_hw_gate2("ecspi5", "ecspi_podf", base + 0x6c, 8);
+ hws[IMX6SX_CLK_EPIT1] = imx_clk_hw_gate2("epit1", "perclk", base + 0x6c, 12);
+ hws[IMX6SX_CLK_EPIT2] = imx_clk_hw_gate2("epit2", "perclk", base + 0x6c, 14);
+ hws[IMX6SX_CLK_ESAI_EXTAL] = imx_clk_hw_gate2_shared("esai_extal", "esai_podf", base + 0x6c, 16, &share_count_esai);
+ hws[IMX6SX_CLK_ESAI_IPG] = imx_clk_hw_gate2_shared("esai_ipg", "ahb", base + 0x6c, 16, &share_count_esai);
+ hws[IMX6SX_CLK_ESAI_MEM] = imx_clk_hw_gate2_shared("esai_mem", "ahb", base + 0x6c, 16, &share_count_esai);
+ hws[IMX6SX_CLK_WAKEUP] = imx_clk_hw_gate2_flags("wakeup", "ipg", base + 0x6c, 18, CLK_IS_CRITICAL);
+ hws[IMX6SX_CLK_GPT_BUS] = imx_clk_hw_gate2("gpt_bus", "perclk", base + 0x6c, 20);
+ hws[IMX6SX_CLK_GPT_SERIAL] = imx_clk_hw_gate2("gpt_serial", "perclk", base + 0x6c, 22);
+ hws[IMX6SX_CLK_GPU] = imx_clk_hw_gate2("gpu", "gpu_core_podf", base + 0x6c, 26);
+ hws[IMX6SX_CLK_OCRAM_S] = imx_clk_hw_gate2("ocram_s", "ahb", base + 0x6c, 28);
+ hws[IMX6SX_CLK_CANFD] = imx_clk_hw_gate2("canfd", "can_podf", base + 0x6c, 30);
/* CCGR2 */
- clks[IMX6SX_CLK_CSI] = imx_clk_gate2("csi", "csi_podf", base + 0x70, 2);
- clks[IMX6SX_CLK_I2C1] = imx_clk_gate2("i2c1", "perclk", base + 0x70, 6);
- clks[IMX6SX_CLK_I2C2] = imx_clk_gate2("i2c2", "perclk", base + 0x70, 8);
- clks[IMX6SX_CLK_I2C3] = imx_clk_gate2("i2c3", "perclk", base + 0x70, 10);
- clks[IMX6SX_CLK_OCOTP] = imx_clk_gate2("ocotp", "ipg", base + 0x70, 12);
- clks[IMX6SX_CLK_IOMUXC] = imx_clk_gate2("iomuxc", "lcdif1_podf", base + 0x70, 14);
- clks[IMX6SX_CLK_IPMUX1] = imx_clk_gate2_flags("ipmux1", "ahb", base + 0x70, 16, CLK_IS_CRITICAL);
- clks[IMX6SX_CLK_IPMUX2] = imx_clk_gate2_flags("ipmux2", "ahb", base + 0x70, 18, CLK_IS_CRITICAL);
- clks[IMX6SX_CLK_IPMUX3] = imx_clk_gate2_flags("ipmux3", "ahb", base + 0x70, 20, CLK_IS_CRITICAL);
- clks[IMX6SX_CLK_TZASC1] = imx_clk_gate2_flags("tzasc1", "mmdc_podf", base + 0x70, 22, CLK_IS_CRITICAL);
- clks[IMX6SX_CLK_LCDIF_APB] = imx_clk_gate2("lcdif_apb", "display_podf", base + 0x70, 28);
- clks[IMX6SX_CLK_PXP_AXI] = imx_clk_gate2("pxp_axi", "display_podf", base + 0x70, 30);
+ hws[IMX6SX_CLK_CSI] = imx_clk_hw_gate2("csi", "csi_podf", base + 0x70, 2);
+ hws[IMX6SX_CLK_I2C1] = imx_clk_hw_gate2("i2c1", "perclk", base + 0x70, 6);
+ hws[IMX6SX_CLK_I2C2] = imx_clk_hw_gate2("i2c2", "perclk", base + 0x70, 8);
+ hws[IMX6SX_CLK_I2C3] = imx_clk_hw_gate2("i2c3", "perclk", base + 0x70, 10);
+ hws[IMX6SX_CLK_OCOTP] = imx_clk_hw_gate2("ocotp", "ipg", base + 0x70, 12);
+ hws[IMX6SX_CLK_IOMUXC] = imx_clk_hw_gate2("iomuxc", "lcdif1_podf", base + 0x70, 14);
+ hws[IMX6SX_CLK_IPMUX1] = imx_clk_hw_gate2_flags("ipmux1", "ahb", base + 0x70, 16, CLK_IS_CRITICAL);
+ hws[IMX6SX_CLK_IPMUX2] = imx_clk_hw_gate2_flags("ipmux2", "ahb", base + 0x70, 18, CLK_IS_CRITICAL);
+ hws[IMX6SX_CLK_IPMUX3] = imx_clk_hw_gate2_flags("ipmux3", "ahb", base + 0x70, 20, CLK_IS_CRITICAL);
+ hws[IMX6SX_CLK_TZASC1] = imx_clk_hw_gate2_flags("tzasc1", "mmdc_podf", base + 0x70, 22, CLK_IS_CRITICAL);
+ hws[IMX6SX_CLK_LCDIF_APB] = imx_clk_hw_gate2("lcdif_apb", "display_podf", base + 0x70, 28);
+ hws[IMX6SX_CLK_PXP_AXI] = imx_clk_hw_gate2("pxp_axi", "display_podf", base + 0x70, 30);
/* CCGR3 */
- clks[IMX6SX_CLK_M4] = imx_clk_gate2("m4", "m4_podf", base + 0x74, 2);
- clks[IMX6SX_CLK_ENET] = imx_clk_gate2("enet", "ipg", base + 0x74, 4);
- clks[IMX6SX_CLK_ENET_AHB] = imx_clk_gate2("enet_ahb", "enet_sel", base + 0x74, 4);
- clks[IMX6SX_CLK_DISPLAY_AXI] = imx_clk_gate2("display_axi", "display_podf", base + 0x74, 6);
- clks[IMX6SX_CLK_LCDIF2_PIX] = imx_clk_gate2("lcdif2_pix", "lcdif2_sel", base + 0x74, 8);
- clks[IMX6SX_CLK_LCDIF1_PIX] = imx_clk_gate2("lcdif1_pix", "lcdif1_sel", base + 0x74, 10);
- clks[IMX6SX_CLK_LDB_DI0] = imx_clk_gate2("ldb_di0", "ldb_di0_div_sel", base + 0x74, 12);
- clks[IMX6SX_CLK_QSPI1] = imx_clk_gate2("qspi1", "qspi1_podf", base + 0x74, 14);
- clks[IMX6SX_CLK_MLB] = imx_clk_gate2("mlb", "ahb", base + 0x74, 18);
- clks[IMX6SX_CLK_MMDC_P0_FAST] = imx_clk_gate2_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL);
- clks[IMX6SX_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
- clks[IMX6SX_CLK_MMDC_P1_IPG] = imx_clk_gate2("mmdc_p1_ipg", "ipg", base + 0x74, 26);
- clks[IMX6SX_CLK_OCRAM] = imx_clk_gate2_flags("ocram", "ocram_podf", base + 0x74, 28, CLK_IS_CRITICAL);
+ hws[IMX6SX_CLK_M4] = imx_clk_hw_gate2("m4", "m4_podf", base + 0x74, 2);
+ hws[IMX6SX_CLK_ENET] = imx_clk_hw_gate2("enet", "ipg", base + 0x74, 4);
+ hws[IMX6SX_CLK_ENET_AHB] = imx_clk_hw_gate2("enet_ahb", "enet_sel", base + 0x74, 4);
+ hws[IMX6SX_CLK_DISPLAY_AXI] = imx_clk_hw_gate2("display_axi", "display_podf", base + 0x74, 6);
+ hws[IMX6SX_CLK_LCDIF2_PIX] = imx_clk_hw_gate2("lcdif2_pix", "lcdif2_sel", base + 0x74, 8);
+ hws[IMX6SX_CLK_LCDIF1_PIX] = imx_clk_hw_gate2("lcdif1_pix", "lcdif1_sel", base + 0x74, 10);
+ hws[IMX6SX_CLK_LDB_DI0] = imx_clk_hw_gate2("ldb_di0", "ldb_di0_div_sel", base + 0x74, 12);
+ hws[IMX6SX_CLK_QSPI1] = imx_clk_hw_gate2("qspi1", "qspi1_podf", base + 0x74, 14);
+ hws[IMX6SX_CLK_MLB] = imx_clk_hw_gate2("mlb", "ahb", base + 0x74, 18);
+ hws[IMX6SX_CLK_MMDC_P0_FAST] = imx_clk_hw_gate2_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL);
+ hws[IMX6SX_CLK_MMDC_P0_IPG] = imx_clk_hw_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
+ hws[IMX6SX_CLK_MMDC_P1_IPG] = imx_clk_hw_gate2_flags("mmdc_p1_ipg", "ipg", base + 0x74, 26, CLK_IS_CRITICAL);
+ hws[IMX6SX_CLK_OCRAM] = imx_clk_hw_gate2_flags("ocram", "ocram_podf", base + 0x74, 28, CLK_IS_CRITICAL);
/* CCGR4 */
- clks[IMX6SX_CLK_PCIE_AXI] = imx_clk_gate2("pcie_axi", "display_podf", base + 0x78, 0);
- clks[IMX6SX_CLK_QSPI2] = imx_clk_gate2("qspi2", "qspi2_podf", base + 0x78, 10);
- clks[IMX6SX_CLK_PER1_BCH] = imx_clk_gate2("per1_bch", "usdhc3", base + 0x78, 12);
- clks[IMX6SX_CLK_PER2_MAIN] = imx_clk_gate2_flags("per2_main", "ahb", base + 0x78, 14, CLK_IS_CRITICAL);
- clks[IMX6SX_CLK_PWM1] = imx_clk_gate2("pwm1", "perclk", base + 0x78, 16);
- clks[IMX6SX_CLK_PWM2] = imx_clk_gate2("pwm2", "perclk", base + 0x78, 18);
- clks[IMX6SX_CLK_PWM3] = imx_clk_gate2("pwm3", "perclk", base + 0x78, 20);
- clks[IMX6SX_CLK_PWM4] = imx_clk_gate2("pwm4", "perclk", base + 0x78, 22);
- clks[IMX6SX_CLK_GPMI_BCH_APB] = imx_clk_gate2("gpmi_bch_apb", "usdhc3", base + 0x78, 24);
- clks[IMX6SX_CLK_GPMI_BCH] = imx_clk_gate2("gpmi_bch", "usdhc4", base + 0x78, 26);
- clks[IMX6SX_CLK_GPMI_IO] = imx_clk_gate2("gpmi_io", "qspi2_podf", base + 0x78, 28);
- clks[IMX6SX_CLK_GPMI_APB] = imx_clk_gate2("gpmi_apb", "usdhc3", base + 0x78, 30);
+ hws[IMX6SX_CLK_PCIE_AXI] = imx_clk_hw_gate2("pcie_axi", "display_podf", base + 0x78, 0);
+ hws[IMX6SX_CLK_QSPI2] = imx_clk_hw_gate2("qspi2", "qspi2_podf", base + 0x78, 10);
+ hws[IMX6SX_CLK_PER1_BCH] = imx_clk_hw_gate2("per1_bch", "usdhc3", base + 0x78, 12);
+ hws[IMX6SX_CLK_PER2_MAIN] = imx_clk_hw_gate2_flags("per2_main", "ahb", base + 0x78, 14, CLK_IS_CRITICAL);
+ hws[IMX6SX_CLK_PWM1] = imx_clk_hw_gate2("pwm1", "perclk", base + 0x78, 16);
+ hws[IMX6SX_CLK_PWM2] = imx_clk_hw_gate2("pwm2", "perclk", base + 0x78, 18);
+ hws[IMX6SX_CLK_PWM3] = imx_clk_hw_gate2("pwm3", "perclk", base + 0x78, 20);
+ hws[IMX6SX_CLK_PWM4] = imx_clk_hw_gate2("pwm4", "perclk", base + 0x78, 22);
+ hws[IMX6SX_CLK_GPMI_BCH_APB] = imx_clk_hw_gate2("gpmi_bch_apb", "usdhc3", base + 0x78, 24);
+ hws[IMX6SX_CLK_GPMI_BCH] = imx_clk_hw_gate2("gpmi_bch", "usdhc4", base + 0x78, 26);
+ hws[IMX6SX_CLK_GPMI_IO] = imx_clk_hw_gate2("gpmi_io", "qspi2_podf", base + 0x78, 28);
+ hws[IMX6SX_CLK_GPMI_APB] = imx_clk_hw_gate2("gpmi_apb", "usdhc3", base + 0x78, 30);
/* CCGR5 */
- clks[IMX6SX_CLK_ROM] = imx_clk_gate2_flags("rom", "ahb", base + 0x7c, 0, CLK_IS_CRITICAL);
- clks[IMX6SX_CLK_SDMA] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6);
- clks[IMX6SX_CLK_SPBA] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12);
- clks[IMX6SX_CLK_AUDIO] = imx_clk_gate2_shared("audio", "audio_podf", base + 0x7c, 14, &share_count_audio);
- clks[IMX6SX_CLK_SPDIF] = imx_clk_gate2_shared("spdif", "spdif_podf", base + 0x7c, 14, &share_count_audio);
- clks[IMX6SX_CLK_SPDIF_GCLK] = imx_clk_gate2_shared("spdif_gclk", "ipg", base + 0x7c, 14, &share_count_audio);
- clks[IMX6SX_CLK_SSI1_IPG] = imx_clk_gate2_shared("ssi1_ipg", "ipg", base + 0x7c, 18, &share_count_ssi1);
- clks[IMX6SX_CLK_SSI2_IPG] = imx_clk_gate2_shared("ssi2_ipg", "ipg", base + 0x7c, 20, &share_count_ssi2);
- clks[IMX6SX_CLK_SSI3_IPG] = imx_clk_gate2_shared("ssi3_ipg", "ipg", base + 0x7c, 22, &share_count_ssi3);
- clks[IMX6SX_CLK_SSI1] = imx_clk_gate2_shared("ssi1", "ssi1_podf", base + 0x7c, 18, &share_count_ssi1);
- clks[IMX6SX_CLK_SSI2] = imx_clk_gate2_shared("ssi2", "ssi2_podf", base + 0x7c, 20, &share_count_ssi2);
- clks[IMX6SX_CLK_SSI3] = imx_clk_gate2_shared("ssi3", "ssi3_podf", base + 0x7c, 22, &share_count_ssi3);
- clks[IMX6SX_CLK_UART_IPG] = imx_clk_gate2("uart_ipg", "ipg", base + 0x7c, 24);
- clks[IMX6SX_CLK_UART_SERIAL] = imx_clk_gate2("uart_serial", "uart_podf", base + 0x7c, 26);
- clks[IMX6SX_CLK_SAI1_IPG] = imx_clk_gate2_shared("sai1_ipg", "ipg", base + 0x7c, 28, &share_count_sai1);
- clks[IMX6SX_CLK_SAI2_IPG] = imx_clk_gate2_shared("sai2_ipg", "ipg", base + 0x7c, 30, &share_count_sai2);
- clks[IMX6SX_CLK_SAI1] = imx_clk_gate2_shared("sai1", "ssi1_podf", base + 0x7c, 28, &share_count_sai1);
- clks[IMX6SX_CLK_SAI2] = imx_clk_gate2_shared("sai2", "ssi2_podf", base + 0x7c, 30, &share_count_sai2);
+ hws[IMX6SX_CLK_ROM] = imx_clk_hw_gate2_flags("rom", "ahb", base + 0x7c, 0, CLK_IS_CRITICAL);
+ hws[IMX6SX_CLK_SDMA] = imx_clk_hw_gate2("sdma", "ahb", base + 0x7c, 6);
+ hws[IMX6SX_CLK_SPBA] = imx_clk_hw_gate2("spba", "ipg", base + 0x7c, 12);
+ hws[IMX6SX_CLK_AUDIO] = imx_clk_hw_gate2_shared("audio", "audio_podf", base + 0x7c, 14, &share_count_audio);
+ hws[IMX6SX_CLK_SPDIF] = imx_clk_hw_gate2_shared("spdif", "spdif_podf", base + 0x7c, 14, &share_count_audio);
+ hws[IMX6SX_CLK_SPDIF_GCLK] = imx_clk_hw_gate2_shared("spdif_gclk", "ipg", base + 0x7c, 14, &share_count_audio);
+ hws[IMX6SX_CLK_SSI1_IPG] = imx_clk_hw_gate2_shared("ssi1_ipg", "ipg", base + 0x7c, 18, &share_count_ssi1);
+ hws[IMX6SX_CLK_SSI2_IPG] = imx_clk_hw_gate2_shared("ssi2_ipg", "ipg", base + 0x7c, 20, &share_count_ssi2);
+ hws[IMX6SX_CLK_SSI3_IPG] = imx_clk_hw_gate2_shared("ssi3_ipg", "ipg", base + 0x7c, 22, &share_count_ssi3);
+ hws[IMX6SX_CLK_SSI1] = imx_clk_hw_gate2_shared("ssi1", "ssi1_podf", base + 0x7c, 18, &share_count_ssi1);
+ hws[IMX6SX_CLK_SSI2] = imx_clk_hw_gate2_shared("ssi2", "ssi2_podf", base + 0x7c, 20, &share_count_ssi2);
+ hws[IMX6SX_CLK_SSI3] = imx_clk_hw_gate2_shared("ssi3", "ssi3_podf", base + 0x7c, 22, &share_count_ssi3);
+ hws[IMX6SX_CLK_UART_IPG] = imx_clk_hw_gate2("uart_ipg", "ipg", base + 0x7c, 24);
+ hws[IMX6SX_CLK_UART_SERIAL] = imx_clk_hw_gate2("uart_serial", "uart_podf", base + 0x7c, 26);
+ hws[IMX6SX_CLK_SAI1_IPG] = imx_clk_hw_gate2_shared("sai1_ipg", "ipg", base + 0x7c, 28, &share_count_sai1);
+ hws[IMX6SX_CLK_SAI2_IPG] = imx_clk_hw_gate2_shared("sai2_ipg", "ipg", base + 0x7c, 30, &share_count_sai2);
+ hws[IMX6SX_CLK_SAI1] = imx_clk_hw_gate2_shared("sai1", "ssi1_podf", base + 0x7c, 28, &share_count_sai1);
+ hws[IMX6SX_CLK_SAI2] = imx_clk_hw_gate2_shared("sai2", "ssi2_podf", base + 0x7c, 30, &share_count_sai2);
/* CCGR6 */
- clks[IMX6SX_CLK_USBOH3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0);
- clks[IMX6SX_CLK_USDHC1] = imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2);
- clks[IMX6SX_CLK_USDHC2] = imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4);
- clks[IMX6SX_CLK_USDHC3] = imx_clk_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6);
- clks[IMX6SX_CLK_USDHC4] = imx_clk_gate2("usdhc4", "usdhc4_podf", base + 0x80, 8);
- clks[IMX6SX_CLK_EIM_SLOW] = imx_clk_gate2("eim_slow", "eim_slow_podf", base + 0x80, 10);
- clks[IMX6SX_CLK_PWM8] = imx_clk_gate2("pwm8", "perclk", base + 0x80, 16);
- clks[IMX6SX_CLK_VADC] = imx_clk_gate2("vadc", "vid_podf", base + 0x80, 20);
- clks[IMX6SX_CLK_GIS] = imx_clk_gate2("gis", "display_podf", base + 0x80, 22);
- clks[IMX6SX_CLK_I2C4] = imx_clk_gate2("i2c4", "perclk", base + 0x80, 24);
- clks[IMX6SX_CLK_PWM5] = imx_clk_gate2("pwm5", "perclk", base + 0x80, 26);
- clks[IMX6SX_CLK_PWM6] = imx_clk_gate2("pwm6", "perclk", base + 0x80, 28);
- clks[IMX6SX_CLK_PWM7] = imx_clk_gate2("pwm7", "perclk", base + 0x80, 30);
-
- clks[IMX6SX_CLK_CKO1] = imx_clk_gate("cko1", "cko1_podf", base + 0x60, 7);
- clks[IMX6SX_CLK_CKO2] = imx_clk_gate("cko2", "cko2_podf", base + 0x60, 24);
+ hws[IMX6SX_CLK_USBOH3] = imx_clk_hw_gate2("usboh3", "ipg", base + 0x80, 0);
+ hws[IMX6SX_CLK_USDHC1] = imx_clk_hw_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2);
+ hws[IMX6SX_CLK_USDHC2] = imx_clk_hw_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4);
+ hws[IMX6SX_CLK_USDHC3] = imx_clk_hw_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6);
+ hws[IMX6SX_CLK_USDHC4] = imx_clk_hw_gate2("usdhc4", "usdhc4_podf", base + 0x80, 8);
+ hws[IMX6SX_CLK_EIM_SLOW] = imx_clk_hw_gate2("eim_slow", "eim_slow_podf", base + 0x80, 10);
+ hws[IMX6SX_CLK_PWM8] = imx_clk_hw_gate2("pwm8", "perclk", base + 0x80, 16);
+ hws[IMX6SX_CLK_VADC] = imx_clk_hw_gate2("vadc", "vid_podf", base + 0x80, 20);
+ hws[IMX6SX_CLK_GIS] = imx_clk_hw_gate2("gis", "display_podf", base + 0x80, 22);
+ hws[IMX6SX_CLK_I2C4] = imx_clk_hw_gate2("i2c4", "perclk", base + 0x80, 24);
+ hws[IMX6SX_CLK_PWM5] = imx_clk_hw_gate2("pwm5", "perclk", base + 0x80, 26);
+ hws[IMX6SX_CLK_PWM6] = imx_clk_hw_gate2("pwm6", "perclk", base + 0x80, 28);
+ hws[IMX6SX_CLK_PWM7] = imx_clk_hw_gate2("pwm7", "perclk", base + 0x80, 30);
+
+ hws[IMX6SX_CLK_CKO1] = imx_clk_hw_gate("cko1", "cko1_podf", base + 0x60, 7);
+ hws[IMX6SX_CLK_CKO2] = imx_clk_hw_gate("cko2", "cko2_podf", base + 0x60, 24);
/* mask handshake of mmdc */
- writel_relaxed(BM_CCM_CCDR_MMDC_CH0_MASK, base + CCDR);
+ imx_mmdc_mask_handshake(base, 0);
- imx_check_clocks(clks, ARRAY_SIZE(clks));
+ imx_check_clk_hws(hws, IMX6SX_CLK_CLK_END);
- clk_data.clks = clks;
- clk_data.clk_num = ARRAY_SIZE(clks);
- of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+ of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
- clk_prepare_enable(clks[IMX6SX_CLK_USBPHY1_GATE]);
- clk_prepare_enable(clks[IMX6SX_CLK_USBPHY2_GATE]);
+ clk_prepare_enable(hws[IMX6SX_CLK_USBPHY1_GATE]->clk);
+ clk_prepare_enable(hws[IMX6SX_CLK_USBPHY2_GATE]->clk);
}
/* Set the default 132MHz for EIM module */
- clk_set_parent(clks[IMX6SX_CLK_EIM_SLOW_SEL], clks[IMX6SX_CLK_PLL2_PFD2]);
- clk_set_rate(clks[IMX6SX_CLK_EIM_SLOW], 132000000);
+ clk_set_parent(hws[IMX6SX_CLK_EIM_SLOW_SEL]->clk, hws[IMX6SX_CLK_PLL2_PFD2]->clk);
+ clk_set_rate(hws[IMX6SX_CLK_EIM_SLOW]->clk, 132000000);
/* set parent clock for LCDIF1 pixel clock */
- clk_set_parent(clks[IMX6SX_CLK_LCDIF1_PRE_SEL], clks[IMX6SX_CLK_PLL5_VIDEO_DIV]);
- clk_set_parent(clks[IMX6SX_CLK_LCDIF1_SEL], clks[IMX6SX_CLK_LCDIF1_PODF]);
+ clk_set_parent(hws[IMX6SX_CLK_LCDIF1_PRE_SEL]->clk, hws[IMX6SX_CLK_PLL5_VIDEO_DIV]->clk);
+ clk_set_parent(hws[IMX6SX_CLK_LCDIF1_SEL]->clk, hws[IMX6SX_CLK_LCDIF1_PODF]->clk);
/* Set the parent clks of PCIe lvds1 and pcie_axi to be pcie ref, axi */
- if (clk_set_parent(clks[IMX6SX_CLK_LVDS1_SEL], clks[IMX6SX_CLK_PCIE_REF_125M]))
+ if (clk_set_parent(hws[IMX6SX_CLK_LVDS1_SEL]->clk, hws[IMX6SX_CLK_PCIE_REF_125M]->clk))
pr_err("Failed to set pcie bus parent clk.\n");
- if (clk_set_parent(clks[IMX6SX_CLK_PCIE_AXI_SEL], clks[IMX6SX_CLK_AXI]))
- pr_err("Failed to set pcie parent clk.\n");
/*
* Init enet system AHB clock, set to 200MHz
* pll2_pfd2_396m-> ENET_PODF-> ENET_AHB
*/
- clk_set_parent(clks[IMX6SX_CLK_ENET_PRE_SEL], clks[IMX6SX_CLK_PLL2_PFD2]);
- clk_set_parent(clks[IMX6SX_CLK_ENET_SEL], clks[IMX6SX_CLK_ENET_PODF]);
- clk_set_rate(clks[IMX6SX_CLK_ENET_PODF], 200000000);
- clk_set_rate(clks[IMX6SX_CLK_ENET_REF], 125000000);
- clk_set_rate(clks[IMX6SX_CLK_ENET2_REF], 125000000);
+ clk_set_parent(hws[IMX6SX_CLK_ENET_PRE_SEL]->clk, hws[IMX6SX_CLK_PLL2_PFD2]->clk);
+ clk_set_parent(hws[IMX6SX_CLK_ENET_SEL]->clk, hws[IMX6SX_CLK_ENET_PODF]->clk);
+ clk_set_rate(hws[IMX6SX_CLK_ENET_PODF]->clk, 200000000);
+ clk_set_rate(hws[IMX6SX_CLK_ENET_REF]->clk, 125000000);
+ clk_set_rate(hws[IMX6SX_CLK_ENET2_REF]->clk, 125000000);
/* Audio clocks */
- clk_set_rate(clks[IMX6SX_CLK_PLL4_AUDIO_DIV], 393216000);
+ clk_set_rate(hws[IMX6SX_CLK_PLL4_AUDIO_DIV]->clk, 393216000);
- clk_set_parent(clks[IMX6SX_CLK_SPDIF_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]);
- clk_set_rate(clks[IMX6SX_CLK_SPDIF_PODF], 98304000);
+ clk_set_parent(hws[IMX6SX_CLK_SPDIF_SEL]->clk, hws[IMX6SX_CLK_PLL4_AUDIO_DIV]->clk);
+ clk_set_rate(hws[IMX6SX_CLK_SPDIF_PODF]->clk, 98304000);
- clk_set_parent(clks[IMX6SX_CLK_AUDIO_SEL], clks[IMX6SX_CLK_PLL3_USB_OTG]);
- clk_set_rate(clks[IMX6SX_CLK_AUDIO_PODF], 24000000);
+ clk_set_parent(hws[IMX6SX_CLK_AUDIO_SEL]->clk, hws[IMX6SX_CLK_PLL3_USB_OTG]->clk);
+ clk_set_rate(hws[IMX6SX_CLK_AUDIO_PODF]->clk, 24000000);
- clk_set_parent(clks[IMX6SX_CLK_SSI1_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]);
- clk_set_parent(clks[IMX6SX_CLK_SSI2_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]);
- clk_set_parent(clks[IMX6SX_CLK_SSI3_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]);
- clk_set_rate(clks[IMX6SX_CLK_SSI1_PODF], 24576000);
- clk_set_rate(clks[IMX6SX_CLK_SSI2_PODF], 24576000);
- clk_set_rate(clks[IMX6SX_CLK_SSI3_PODF], 24576000);
+ clk_set_parent(hws[IMX6SX_CLK_SSI1_SEL]->clk, hws[IMX6SX_CLK_PLL4_AUDIO_DIV]->clk);
+ clk_set_parent(hws[IMX6SX_CLK_SSI2_SEL]->clk, hws[IMX6SX_CLK_PLL4_AUDIO_DIV]->clk);
+ clk_set_parent(hws[IMX6SX_CLK_SSI3_SEL]->clk, hws[IMX6SX_CLK_PLL4_AUDIO_DIV]->clk);
+ clk_set_rate(hws[IMX6SX_CLK_SSI1_PODF]->clk, 24576000);
+ clk_set_rate(hws[IMX6SX_CLK_SSI2_PODF]->clk, 24576000);
+ clk_set_rate(hws[IMX6SX_CLK_SSI3_PODF]->clk, 24576000);
- clk_set_parent(clks[IMX6SX_CLK_ESAI_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]);
- clk_set_rate(clks[IMX6SX_CLK_ESAI_PODF], 24576000);
+ clk_set_parent(hws[IMX6SX_CLK_ESAI_SEL]->clk, hws[IMX6SX_CLK_PLL4_AUDIO_DIV]->clk);
+ clk_set_rate(hws[IMX6SX_CLK_ESAI_PODF]->clk, 24576000);
/* Set parent clock for vadc */
- clk_set_parent(clks[IMX6SX_CLK_VID_SEL], clks[IMX6SX_CLK_PLL3_USB_OTG]);
+ clk_set_parent(hws[IMX6SX_CLK_VID_SEL]->clk, hws[IMX6SX_CLK_PLL3_USB_OTG]->clk);
/* default parent of can_sel clock is invalid, manually set it here */
- clk_set_parent(clks[IMX6SX_CLK_CAN_SEL], clks[IMX6SX_CLK_PLL3_60M]);
+ clk_set_parent(hws[IMX6SX_CLK_CAN_SEL]->clk, hws[IMX6SX_CLK_PLL3_60M]->clk);
/* Update gpu clock from default 528M to 720M */
- clk_set_parent(clks[IMX6SX_CLK_GPU_CORE_SEL], clks[IMX6SX_CLK_PLL3_PFD0]);
- clk_set_parent(clks[IMX6SX_CLK_GPU_AXI_SEL], clks[IMX6SX_CLK_PLL3_PFD0]);
+ clk_set_parent(hws[IMX6SX_CLK_GPU_CORE_SEL]->clk, hws[IMX6SX_CLK_PLL3_PFD0]->clk);
+ clk_set_parent(hws[IMX6SX_CLK_GPU_AXI_SEL]->clk, hws[IMX6SX_CLK_PLL3_PFD0]->clk);
- clk_set_parent(clks[IMX6SX_CLK_QSPI1_SEL], clks[IMX6SX_CLK_PLL2_BUS]);
- clk_set_parent(clks[IMX6SX_CLK_QSPI2_SEL], clks[IMX6SX_CLK_PLL2_BUS]);
+ clk_set_parent(hws[IMX6SX_CLK_QSPI1_SEL]->clk, hws[IMX6SX_CLK_PLL2_BUS]->clk);
+ clk_set_parent(hws[IMX6SX_CLK_QSPI2_SEL]->clk, hws[IMX6SX_CLK_PLL2_BUS]->clk);
+
+ for (i = 0; i < ARRAY_SIZE(uart_clk_ids); i++) {
+ int index = uart_clk_ids[i];
+
+ uart_clks[i] = &hws[index]->clk;
+ }
imx_register_uart_clocks(uart_clks);
}
diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c
index 8fd52e103cc2..bc931988fe7b 100644
--- a/drivers/clk/imx/clk-imx6ul.c
+++ b/drivers/clk/imx/clk-imx6ul.c
@@ -6,6 +6,7 @@
#include <dt-bindings/clock/imx6ul-clock.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
@@ -16,9 +17,6 @@
#include "clk.h"
-#define BM_CCM_CCDR_MMDC_CH0_MASK (0x2 << 16)
-#define CCDR 0x4
-
static const char *pll_bypass_src_sels[] = { "osc", "dummy", };
static const char *pll1_bypass_sels[] = { "pll1", "pll1_bypass_src", };
static const char *pll2_bypass_sels[] = { "pll2", "pll2_bypass_src", };
@@ -70,8 +68,8 @@ static const char *cko2_sels[] = { "dummy", "dummy", "dummy", "usdhc1", "dummy",
"dummy", "dummy", "dummy", "dummy", "uart_serial", "spdif", "dummy", "dummy", };
static const char *cko_sels[] = { "cko1", "cko2", };
-static struct clk *clks[IMX6UL_CLK_END];
-static struct clk_onecell_data clk_data;
+static struct clk_hw **hws;
+static struct clk_hw_onecell_data *clk_hw_data;
static const struct clk_div_table clk_enet_ref_table[] = {
{ .val = 0, .div = 20, },
@@ -118,61 +116,69 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
struct device_node *np;
void __iomem *base;
- clks[IMX6UL_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
+ clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
+ IMX6UL_CLK_END), GFP_KERNEL);
+ if (WARN_ON(!clk_hw_data))
+ return;
+
+ clk_hw_data->num = IMX6UL_CLK_END;
+ hws = clk_hw_data->hws;
+
+ hws[IMX6UL_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
- clks[IMX6UL_CLK_CKIL] = of_clk_get_by_name(ccm_node, "ckil");
- clks[IMX6UL_CLK_OSC] = of_clk_get_by_name(ccm_node, "osc");
+ hws[IMX6UL_CLK_CKIL] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ckil"));
+ hws[IMX6UL_CLK_OSC] = __clk_get_hw(of_clk_get_by_name(ccm_node, "osc"));
/* ipp_di clock is external input */
- clks[IMX6UL_CLK_IPP_DI0] = of_clk_get_by_name(ccm_node, "ipp_di0");
- clks[IMX6UL_CLK_IPP_DI1] = of_clk_get_by_name(ccm_node, "ipp_di1");
+ hws[IMX6UL_CLK_IPP_DI0] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ipp_di0"));
+ hws[IMX6UL_CLK_IPP_DI1] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ipp_di1"));
np = of_find_compatible_node(NULL, NULL, "fsl,imx6ul-anatop");
base = of_iomap(np, 0);
of_node_put(np);
WARN_ON(!base);
- clks[IMX6UL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
- clks[IMX6UL_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
- clks[IMX6UL_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
- clks[IMX6UL_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
- clks[IMX6UL_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
- clks[IMX6UL_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
- clks[IMX6UL_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
-
- clks[IMX6UL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "osc", base + 0x00, 0x7f);
- clks[IMX6UL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
- clks[IMX6UL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "osc", base + 0x10, 0x3);
- clks[IMX6UL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "osc", base + 0x70, 0x7f);
- clks[IMX6UL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "osc", base + 0xa0, 0x7f);
- clks[IMX6UL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "osc", base + 0xe0, 0x3);
- clks[IMX6UL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "osc", base + 0x20, 0x3);
-
- clks[IMX6UL_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
- clks[IMX6UL_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
- clks[IMX6UL_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
- clks[IMX6UL_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
- clks[IMX6UL_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
- clks[IMX6UL_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
- clks[IMX6UL_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
- clks[IMX6UL_CLK_CSI_SEL] = imx_clk_mux_flags("csi_sel", base + 0x3c, 9, 2, csi_sels, ARRAY_SIZE(csi_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6UL_PLL1_BYPASS_SRC] = imx_clk_hw_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6UL_PLL2_BYPASS_SRC] = imx_clk_hw_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6UL_PLL3_BYPASS_SRC] = imx_clk_hw_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6UL_PLL4_BYPASS_SRC] = imx_clk_hw_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6UL_PLL5_BYPASS_SRC] = imx_clk_hw_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6UL_PLL6_BYPASS_SRC] = imx_clk_hw_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ hws[IMX6UL_PLL7_BYPASS_SRC] = imx_clk_hw_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+
+ hws[IMX6UL_CLK_PLL1] = imx_clk_hw_pllv3(IMX_PLLV3_SYS, "pll1", "osc", base + 0x00, 0x7f);
+ hws[IMX6UL_CLK_PLL2] = imx_clk_hw_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
+ hws[IMX6UL_CLK_PLL3] = imx_clk_hw_pllv3(IMX_PLLV3_USB, "pll3", "osc", base + 0x10, 0x3);
+ hws[IMX6UL_CLK_PLL4] = imx_clk_hw_pllv3(IMX_PLLV3_AV, "pll4", "osc", base + 0x70, 0x7f);
+ hws[IMX6UL_CLK_PLL5] = imx_clk_hw_pllv3(IMX_PLLV3_AV, "pll5", "osc", base + 0xa0, 0x7f);
+ hws[IMX6UL_CLK_PLL6] = imx_clk_hw_pllv3(IMX_PLLV3_ENET, "pll6", "osc", base + 0xe0, 0x3);
+ hws[IMX6UL_CLK_PLL7] = imx_clk_hw_pllv3(IMX_PLLV3_USB, "pll7", "osc", base + 0x20, 0x3);
+
+ hws[IMX6UL_PLL1_BYPASS] = imx_clk_hw_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6UL_PLL2_BYPASS] = imx_clk_hw_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6UL_PLL3_BYPASS] = imx_clk_hw_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6UL_PLL4_BYPASS] = imx_clk_hw_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6UL_PLL5_BYPASS] = imx_clk_hw_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6UL_PLL6_BYPASS] = imx_clk_hw_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6UL_PLL7_BYPASS] = imx_clk_hw_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6UL_CLK_CSI_SEL] = imx_clk_hw_mux_flags("csi_sel", base + 0x3c, 9, 2, csi_sels, ARRAY_SIZE(csi_sels), CLK_SET_RATE_PARENT);
/* Do not bypass PLLs initially */
- clk_set_parent(clks[IMX6UL_PLL1_BYPASS], clks[IMX6UL_CLK_PLL1]);
- clk_set_parent(clks[IMX6UL_PLL2_BYPASS], clks[IMX6UL_CLK_PLL2]);
- clk_set_parent(clks[IMX6UL_PLL3_BYPASS], clks[IMX6UL_CLK_PLL3]);
- clk_set_parent(clks[IMX6UL_PLL4_BYPASS], clks[IMX6UL_CLK_PLL4]);
- clk_set_parent(clks[IMX6UL_PLL5_BYPASS], clks[IMX6UL_CLK_PLL5]);
- clk_set_parent(clks[IMX6UL_PLL6_BYPASS], clks[IMX6UL_CLK_PLL6]);
- clk_set_parent(clks[IMX6UL_PLL7_BYPASS], clks[IMX6UL_CLK_PLL7]);
-
- clks[IMX6UL_CLK_PLL1_SYS] = imx_clk_fixed_factor("pll1_sys", "pll1_bypass", 1, 1);
- clks[IMX6UL_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", base + 0x30, 13);
- clks[IMX6UL_CLK_PLL3_USB_OTG] = imx_clk_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13);
- clks[IMX6UL_CLK_PLL4_AUDIO] = imx_clk_gate("pll4_audio", "pll4_bypass", base + 0x70, 13);
- clks[IMX6UL_CLK_PLL5_VIDEO] = imx_clk_gate("pll5_video", "pll5_bypass", base + 0xa0, 13);
- clks[IMX6UL_CLK_PLL6_ENET] = imx_clk_gate("pll6_enet", "pll6_bypass", base + 0xe0, 13);
- clks[IMX6UL_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
+ clk_set_parent(hws[IMX6UL_PLL1_BYPASS]->clk, hws[IMX6UL_CLK_PLL1]->clk);
+ clk_set_parent(hws[IMX6UL_PLL2_BYPASS]->clk, hws[IMX6UL_CLK_PLL2]->clk);
+ clk_set_parent(hws[IMX6UL_PLL3_BYPASS]->clk, hws[IMX6UL_CLK_PLL3]->clk);
+ clk_set_parent(hws[IMX6UL_PLL4_BYPASS]->clk, hws[IMX6UL_CLK_PLL4]->clk);
+ clk_set_parent(hws[IMX6UL_PLL5_BYPASS]->clk, hws[IMX6UL_CLK_PLL5]->clk);
+ clk_set_parent(hws[IMX6UL_PLL6_BYPASS]->clk, hws[IMX6UL_CLK_PLL6]->clk);
+ clk_set_parent(hws[IMX6UL_PLL7_BYPASS]->clk, hws[IMX6UL_CLK_PLL7]->clk);
+
+ hws[IMX6UL_CLK_PLL1_SYS] = imx_clk_hw_fixed_factor("pll1_sys", "pll1_bypass", 1, 1);
+ hws[IMX6UL_CLK_PLL2_BUS] = imx_clk_hw_gate("pll2_bus", "pll2_bypass", base + 0x30, 13);
+ hws[IMX6UL_CLK_PLL3_USB_OTG] = imx_clk_hw_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13);
+ hws[IMX6UL_CLK_PLL4_AUDIO] = imx_clk_hw_gate("pll4_audio", "pll4_bypass", base + 0x70, 13);
+ hws[IMX6UL_CLK_PLL5_VIDEO] = imx_clk_hw_gate("pll5_video", "pll5_bypass", base + 0xa0, 13);
+ hws[IMX6UL_CLK_PLL6_ENET] = imx_clk_hw_gate("pll6_enet", "pll6_bypass", base + 0xe0, 13);
+ hws[IMX6UL_CLK_PLL7_USB_HOST] = imx_clk_hw_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
/*
* Bit 20 is the reserved and read-only bit, we do this only for:
@@ -180,291 +186,289 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
* - Keep refcount when do usbphy clk_enable/disable, in that case,
* the clk framework many need to enable/disable usbphy's parent
*/
- clks[IMX6UL_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20);
- clks[IMX6UL_CLK_USBPHY2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
+ hws[IMX6UL_CLK_USBPHY1] = imx_clk_hw_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20);
+ hws[IMX6UL_CLK_USBPHY2] = imx_clk_hw_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
/*
* usbphy*_gate needs to be on after system boots up, and software
* never needs to control it anymore.
*/
- clks[IMX6UL_CLK_USBPHY1_GATE] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6);
- clks[IMX6UL_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6);
+ hws[IMX6UL_CLK_USBPHY1_GATE] = imx_clk_hw_gate("usbphy1_gate", "dummy", base + 0x10, 6);
+ hws[IMX6UL_CLK_USBPHY2_GATE] = imx_clk_hw_gate("usbphy2_gate", "dummy", base + 0x20, 6);
/* name parent_name reg idx */
- clks[IMX6UL_CLK_PLL2_PFD0] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0);
- clks[IMX6UL_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1);
- clks[IMX6UL_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2);
- clks[IMX6UL_CLK_PLL2_PFD3] = imx_clk_pfd("pll2_pfd3_594m", "pll2_bus", base + 0x100, 3);
- clks[IMX6UL_CLK_PLL3_PFD0] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0);
- clks[IMX6UL_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1);
- clks[IMX6UL_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2);
- clks[IMX6UL_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3);
-
- clks[IMX6UL_CLK_ENET_REF] = clk_register_divider_table(NULL, "enet_ref", "pll6_enet", 0,
+ hws[IMX6UL_CLK_PLL2_PFD0] = imx_clk_hw_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0);
+ hws[IMX6UL_CLK_PLL2_PFD1] = imx_clk_hw_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1);
+ hws[IMX6UL_CLK_PLL2_PFD2] = imx_clk_hw_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2);
+ hws[IMX6UL_CLK_PLL2_PFD3] = imx_clk_hw_pfd("pll2_pfd3_594m", "pll2_bus", base + 0x100, 3);
+ hws[IMX6UL_CLK_PLL3_PFD0] = imx_clk_hw_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0);
+ hws[IMX6UL_CLK_PLL3_PFD1] = imx_clk_hw_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1);
+ hws[IMX6UL_CLK_PLL3_PFD2] = imx_clk_hw_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2);
+ hws[IMX6UL_CLK_PLL3_PFD3] = imx_clk_hw_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3);
+
+ hws[IMX6UL_CLK_ENET_REF] = clk_hw_register_divider_table(NULL, "enet_ref", "pll6_enet", 0,
base + 0xe0, 0, 2, 0, clk_enet_ref_table, &imx_ccm_lock);
- clks[IMX6UL_CLK_ENET2_REF] = clk_register_divider_table(NULL, "enet2_ref", "pll6_enet", 0,
+ hws[IMX6UL_CLK_ENET2_REF] = clk_hw_register_divider_table(NULL, "enet2_ref", "pll6_enet", 0,
base + 0xe0, 2, 2, 0, clk_enet_ref_table, &imx_ccm_lock);
- clks[IMX6UL_CLK_ENET2_REF_125M] = imx_clk_gate("enet_ref_125m", "enet2_ref", base + 0xe0, 20);
- clks[IMX6UL_CLK_ENET_PTP_REF] = imx_clk_fixed_factor("enet_ptp_ref", "pll6_enet", 1, 20);
- clks[IMX6UL_CLK_ENET_PTP] = imx_clk_gate("enet_ptp", "enet_ptp_ref", base + 0xe0, 21);
+ hws[IMX6UL_CLK_ENET2_REF_125M] = imx_clk_hw_gate("enet_ref_125m", "enet2_ref", base + 0xe0, 20);
+ hws[IMX6UL_CLK_ENET_PTP_REF] = imx_clk_hw_fixed_factor("enet_ptp_ref", "pll6_enet", 1, 20);
+ hws[IMX6UL_CLK_ENET_PTP] = imx_clk_hw_gate("enet_ptp", "enet_ptp_ref", base + 0xe0, 21);
- clks[IMX6UL_CLK_PLL4_POST_DIV] = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio",
+ hws[IMX6UL_CLK_PLL4_POST_DIV] = clk_hw_register_divider_table(NULL, "pll4_post_div", "pll4_audio",
CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock);
- clks[IMX6UL_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div",
+ hws[IMX6UL_CLK_PLL4_AUDIO_DIV] = clk_hw_register_divider(NULL, "pll4_audio_div", "pll4_post_div",
CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 15, 1, 0, &imx_ccm_lock);
- clks[IMX6UL_CLK_PLL5_POST_DIV] = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video",
+ hws[IMX6UL_CLK_PLL5_POST_DIV] = clk_hw_register_divider_table(NULL, "pll5_post_div", "pll5_video",
CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock);
- clks[IMX6UL_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div",
+ hws[IMX6UL_CLK_PLL5_VIDEO_DIV] = clk_hw_register_divider_table(NULL, "pll5_video_div", "pll5_post_div",
CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock);
/* name parent_name mult div */
- clks[IMX6UL_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2);
- clks[IMX6UL_CLK_PLL3_80M] = imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6);
- clks[IMX6UL_CLK_PLL3_60M] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8);
- clks[IMX6UL_CLK_GPT_3M] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8);
+ hws[IMX6UL_CLK_PLL2_198M] = imx_clk_hw_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2);
+ hws[IMX6UL_CLK_PLL3_80M] = imx_clk_hw_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6);
+ hws[IMX6UL_CLK_PLL3_60M] = imx_clk_hw_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8);
+ hws[IMX6UL_CLK_GPT_3M] = imx_clk_hw_fixed_factor("gpt_3m", "osc", 1, 8);
np = ccm_node;
base = of_iomap(np, 0);
WARN_ON(!base);
- clks[IMX6UL_CA7_SECONDARY_SEL] = imx_clk_mux("ca7_secondary_sel", base + 0xc, 3, 1, ca7_secondary_sels, ARRAY_SIZE(ca7_secondary_sels));
- clks[IMX6UL_CLK_STEP] = imx_clk_mux("step", base + 0x0c, 8, 1, step_sels, ARRAY_SIZE(step_sels));
- clks[IMX6UL_CLK_PLL1_SW] = imx_clk_mux_flags("pll1_sw", base + 0x0c, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels), 0);
- clks[IMX6UL_CLK_AXI_ALT_SEL] = imx_clk_mux("axi_alt_sel", base + 0x14, 7, 1, axi_alt_sels, ARRAY_SIZE(axi_alt_sels));
- clks[IMX6UL_CLK_AXI_SEL] = imx_clk_mux_flags("axi_sel", base + 0x14, 6, 1, axi_sels, ARRAY_SIZE(axi_sels), 0);
- clks[IMX6UL_CLK_PERIPH_PRE] = imx_clk_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
- clks[IMX6UL_CLK_PERIPH2_PRE] = imx_clk_mux("periph2_pre", base + 0x18, 21, 2, periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels));
- clks[IMX6UL_CLK_PERIPH_CLK2_SEL] = imx_clk_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
- clks[IMX6UL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
- clks[IMX6UL_CLK_EIM_SLOW_SEL] = imx_clk_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels, ARRAY_SIZE(eim_slow_sels));
- clks[IMX6UL_CLK_GPMI_SEL] = imx_clk_mux("gpmi_sel", base + 0x1c, 19, 1, gpmi_sels, ARRAY_SIZE(gpmi_sels));
- clks[IMX6UL_CLK_BCH_SEL] = imx_clk_mux("bch_sel", base + 0x1c, 18, 1, bch_sels, ARRAY_SIZE(bch_sels));
- clks[IMX6UL_CLK_USDHC2_SEL] = imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
- clks[IMX6UL_CLK_USDHC1_SEL] = imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
- clks[IMX6UL_CLK_SAI3_SEL] = imx_clk_mux("sai3_sel", base + 0x1c, 14, 2, sai_sels, ARRAY_SIZE(sai_sels));
- clks[IMX6UL_CLK_SAI2_SEL] = imx_clk_mux("sai2_sel", base + 0x1c, 12, 2, sai_sels, ARRAY_SIZE(sai_sels));
- clks[IMX6UL_CLK_SAI1_SEL] = imx_clk_mux("sai1_sel", base + 0x1c, 10, 2, sai_sels, ARRAY_SIZE(sai_sels));
- clks[IMX6UL_CLK_QSPI1_SEL] = imx_clk_mux("qspi1_sel", base + 0x1c, 7, 3, qspi1_sels, ARRAY_SIZE(qspi1_sels));
- clks[IMX6UL_CLK_PERCLK_SEL] = imx_clk_mux("perclk_sel", base + 0x1c, 6, 1, perclk_sels, ARRAY_SIZE(perclk_sels));
- clks[IMX6UL_CLK_CAN_SEL] = imx_clk_mux("can_sel", base + 0x20, 8, 2, can_sels, ARRAY_SIZE(can_sels));
+ hws[IMX6UL_CA7_SECONDARY_SEL] = imx_clk_hw_mux("ca7_secondary_sel", base + 0xc, 3, 1, ca7_secondary_sels, ARRAY_SIZE(ca7_secondary_sels));
+ hws[IMX6UL_CLK_STEP] = imx_clk_hw_mux("step", base + 0x0c, 8, 1, step_sels, ARRAY_SIZE(step_sels));
+ hws[IMX6UL_CLK_PLL1_SW] = imx_clk_hw_mux_flags("pll1_sw", base + 0x0c, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels), 0);
+ hws[IMX6UL_CLK_AXI_ALT_SEL] = imx_clk_hw_mux("axi_alt_sel", base + 0x14, 7, 1, axi_alt_sels, ARRAY_SIZE(axi_alt_sels));
+ hws[IMX6UL_CLK_AXI_SEL] = imx_clk_hw_mux_flags("axi_sel", base + 0x14, 6, 1, axi_sels, ARRAY_SIZE(axi_sels), 0);
+ hws[IMX6UL_CLK_PERIPH_PRE] = imx_clk_hw_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
+ hws[IMX6UL_CLK_PERIPH2_PRE] = imx_clk_hw_mux("periph2_pre", base + 0x18, 21, 2, periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels));
+ hws[IMX6UL_CLK_PERIPH_CLK2_SEL] = imx_clk_hw_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
+ hws[IMX6UL_CLK_PERIPH2_CLK2_SEL] = imx_clk_hw_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
+ hws[IMX6UL_CLK_EIM_SLOW_SEL] = imx_clk_hw_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels, ARRAY_SIZE(eim_slow_sels));
+ hws[IMX6UL_CLK_GPMI_SEL] = imx_clk_hw_mux("gpmi_sel", base + 0x1c, 19, 1, gpmi_sels, ARRAY_SIZE(gpmi_sels));
+ hws[IMX6UL_CLK_BCH_SEL] = imx_clk_hw_mux("bch_sel", base + 0x1c, 18, 1, bch_sels, ARRAY_SIZE(bch_sels));
+ hws[IMX6UL_CLK_USDHC2_SEL] = imx_clk_hw_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+ hws[IMX6UL_CLK_USDHC1_SEL] = imx_clk_hw_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+ hws[IMX6UL_CLK_SAI3_SEL] = imx_clk_hw_mux("sai3_sel", base + 0x1c, 14, 2, sai_sels, ARRAY_SIZE(sai_sels));
+ hws[IMX6UL_CLK_SAI2_SEL] = imx_clk_hw_mux("sai2_sel", base + 0x1c, 12, 2, sai_sels, ARRAY_SIZE(sai_sels));
+ hws[IMX6UL_CLK_SAI1_SEL] = imx_clk_hw_mux("sai1_sel", base + 0x1c, 10, 2, sai_sels, ARRAY_SIZE(sai_sels));
+ hws[IMX6UL_CLK_QSPI1_SEL] = imx_clk_hw_mux("qspi1_sel", base + 0x1c, 7, 3, qspi1_sels, ARRAY_SIZE(qspi1_sels));
+ hws[IMX6UL_CLK_PERCLK_SEL] = imx_clk_hw_mux("perclk_sel", base + 0x1c, 6, 1, perclk_sels, ARRAY_SIZE(perclk_sels));
+ hws[IMX6UL_CLK_CAN_SEL] = imx_clk_hw_mux("can_sel", base + 0x20, 8, 2, can_sels, ARRAY_SIZE(can_sels));
if (clk_on_imx6ull())
- clks[IMX6ULL_CLK_ESAI_SEL] = imx_clk_mux("esai_sel", base + 0x20, 19, 2, esai_sels, ARRAY_SIZE(esai_sels));
- clks[IMX6UL_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels));
- clks[IMX6UL_CLK_ENFC_SEL] = imx_clk_mux("enfc_sel", base + 0x2c, 15, 3, enfc_sels, ARRAY_SIZE(enfc_sels));
- clks[IMX6UL_CLK_LDB_DI0_SEL] = imx_clk_mux("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di0_sels, ARRAY_SIZE(ldb_di0_sels));
- clks[IMX6UL_CLK_SPDIF_SEL] = imx_clk_mux("spdif_sel", base + 0x30, 20, 2, spdif_sels, ARRAY_SIZE(spdif_sels));
+ hws[IMX6ULL_CLK_ESAI_SEL] = imx_clk_hw_mux("esai_sel", base + 0x20, 19, 2, esai_sels, ARRAY_SIZE(esai_sels));
+ hws[IMX6UL_CLK_UART_SEL] = imx_clk_hw_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels));
+ hws[IMX6UL_CLK_ENFC_SEL] = imx_clk_hw_mux("enfc_sel", base + 0x2c, 15, 3, enfc_sels, ARRAY_SIZE(enfc_sels));
+ hws[IMX6UL_CLK_LDB_DI0_SEL] = imx_clk_hw_mux("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di0_sels, ARRAY_SIZE(ldb_di0_sels));
+ hws[IMX6UL_CLK_SPDIF_SEL] = imx_clk_hw_mux("spdif_sel", base + 0x30, 20, 2, spdif_sels, ARRAY_SIZE(spdif_sels));
if (clk_on_imx6ul()) {
- clks[IMX6UL_CLK_SIM_PRE_SEL] = imx_clk_mux("sim_pre_sel", base + 0x34, 15, 3, sim_pre_sels, ARRAY_SIZE(sim_pre_sels));
- clks[IMX6UL_CLK_SIM_SEL] = imx_clk_mux("sim_sel", base + 0x34, 9, 3, sim_sels, ARRAY_SIZE(sim_sels));
+ hws[IMX6UL_CLK_SIM_PRE_SEL] = imx_clk_hw_mux("sim_pre_sel", base + 0x34, 15, 3, sim_pre_sels, ARRAY_SIZE(sim_pre_sels));
+ hws[IMX6UL_CLK_SIM_SEL] = imx_clk_hw_mux("sim_sel", base + 0x34, 9, 3, sim_sels, ARRAY_SIZE(sim_sels));
} else if (clk_on_imx6ull()) {
- clks[IMX6ULL_CLK_EPDC_PRE_SEL] = imx_clk_mux("epdc_pre_sel", base + 0x34, 15, 3, epdc_pre_sels, ARRAY_SIZE(epdc_pre_sels));
- clks[IMX6ULL_CLK_EPDC_SEL] = imx_clk_mux("epdc_sel", base + 0x34, 9, 3, epdc_sels, ARRAY_SIZE(epdc_sels));
+ hws[IMX6ULL_CLK_EPDC_PRE_SEL] = imx_clk_hw_mux("epdc_pre_sel", base + 0x34, 15, 3, epdc_pre_sels, ARRAY_SIZE(epdc_pre_sels));
+ hws[IMX6ULL_CLK_EPDC_SEL] = imx_clk_hw_mux("epdc_sel", base + 0x34, 9, 3, epdc_sels, ARRAY_SIZE(epdc_sels));
}
- clks[IMX6UL_CLK_ECSPI_SEL] = imx_clk_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels));
- clks[IMX6UL_CLK_LCDIF_PRE_SEL] = imx_clk_mux_flags("lcdif_pre_sel", base + 0x38, 15, 3, lcdif_pre_sels, ARRAY_SIZE(lcdif_pre_sels), CLK_SET_RATE_PARENT);
- clks[IMX6UL_CLK_LCDIF_SEL] = imx_clk_mux("lcdif_sel", base + 0x38, 9, 3, lcdif_sels, ARRAY_SIZE(lcdif_sels));
-
- clks[IMX6UL_CLK_LDB_DI0_DIV_SEL] = imx_clk_mux("ldb_di0", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels));
- clks[IMX6UL_CLK_LDB_DI1_DIV_SEL] = imx_clk_mux("ldb_di1", base + 0x20, 11, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels));
-
- clks[IMX6UL_CLK_CKO1_SEL] = imx_clk_mux("cko1_sel", base + 0x60, 0, 4, cko1_sels, ARRAY_SIZE(cko1_sels));
- clks[IMX6UL_CLK_CKO2_SEL] = imx_clk_mux("cko2_sel", base + 0x60, 16, 5, cko2_sels, ARRAY_SIZE(cko2_sels));
- clks[IMX6UL_CLK_CKO] = imx_clk_mux("cko", base + 0x60, 8, 1, cko_sels, ARRAY_SIZE(cko_sels));
-
- clks[IMX6UL_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
- clks[IMX6UL_CLK_LDB_DI0_DIV_7] = imx_clk_fixed_factor("ldb_di0_div_7", "ldb_di0_sel", 1, 7);
- clks[IMX6UL_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "qspi1_sel", 2, 7);
- clks[IMX6UL_CLK_LDB_DI1_DIV_7] = imx_clk_fixed_factor("ldb_di1_div_7", "qspi1_sel", 1, 7);
-
- clks[IMX6UL_CLK_PERIPH] = imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels));
- clks[IMX6UL_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels));
-
- clks[IMX6UL_CLK_PERIPH_CLK2] = imx_clk_divider("periph_clk2", "periph_clk2_sel", base + 0x14, 27, 3);
- clks[IMX6UL_CLK_PERIPH2_CLK2] = imx_clk_divider("periph2_clk2", "periph2_clk2_sel", base + 0x14, 0, 3);
- clks[IMX6UL_CLK_IPG] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2);
- clks[IMX6UL_CLK_LCDIF_PODF] = imx_clk_divider("lcdif_podf", "lcdif_pred", base + 0x18, 23, 3);
- clks[IMX6UL_CLK_QSPI1_PDOF] = imx_clk_divider("qspi1_podf", "qspi1_sel", base + 0x1c, 26, 3);
- clks[IMX6UL_CLK_EIM_SLOW_PODF] = imx_clk_divider("eim_slow_podf", "eim_slow_sel", base + 0x1c, 23, 3);
- clks[IMX6UL_CLK_PERCLK] = imx_clk_divider("perclk", "perclk_sel", base + 0x1c, 0, 6);
- clks[IMX6UL_CLK_CAN_PODF] = imx_clk_divider("can_podf", "can_sel", base + 0x20, 2, 6);
- clks[IMX6UL_CLK_GPMI_PODF] = imx_clk_divider("gpmi_podf", "gpmi_sel", base + 0x24, 22, 3);
- clks[IMX6UL_CLK_BCH_PODF] = imx_clk_divider("bch_podf", "bch_sel", base + 0x24, 19, 3);
- clks[IMX6UL_CLK_USDHC2_PODF] = imx_clk_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3);
- clks[IMX6UL_CLK_USDHC1_PODF] = imx_clk_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3);
- clks[IMX6UL_CLK_UART_PODF] = imx_clk_divider("uart_podf", "uart_sel", base + 0x24, 0, 6);
- clks[IMX6UL_CLK_SAI3_PRED] = imx_clk_divider("sai3_pred", "sai3_sel", base + 0x28, 22, 3);
- clks[IMX6UL_CLK_SAI3_PODF] = imx_clk_divider("sai3_podf", "sai3_pred", base + 0x28, 16, 6);
- clks[IMX6UL_CLK_SAI1_PRED] = imx_clk_divider("sai1_pred", "sai1_sel", base + 0x28, 6, 3);
- clks[IMX6UL_CLK_SAI1_PODF] = imx_clk_divider("sai1_podf", "sai1_pred", base + 0x28, 0, 6);
+ hws[IMX6UL_CLK_ECSPI_SEL] = imx_clk_hw_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels));
+ hws[IMX6UL_CLK_LCDIF_PRE_SEL] = imx_clk_hw_mux_flags("lcdif_pre_sel", base + 0x38, 15, 3, lcdif_pre_sels, ARRAY_SIZE(lcdif_pre_sels), CLK_SET_RATE_PARENT);
+ hws[IMX6UL_CLK_LCDIF_SEL] = imx_clk_hw_mux("lcdif_sel", base + 0x38, 9, 3, lcdif_sels, ARRAY_SIZE(lcdif_sels));
+
+ hws[IMX6UL_CLK_LDB_DI0_DIV_SEL] = imx_clk_hw_mux("ldb_di0", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels));
+ hws[IMX6UL_CLK_LDB_DI1_DIV_SEL] = imx_clk_hw_mux("ldb_di1", base + 0x20, 11, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels));
+
+ hws[IMX6UL_CLK_CKO1_SEL] = imx_clk_hw_mux("cko1_sel", base + 0x60, 0, 4, cko1_sels, ARRAY_SIZE(cko1_sels));
+ hws[IMX6UL_CLK_CKO2_SEL] = imx_clk_hw_mux("cko2_sel", base + 0x60, 16, 5, cko2_sels, ARRAY_SIZE(cko2_sels));
+ hws[IMX6UL_CLK_CKO] = imx_clk_hw_mux("cko", base + 0x60, 8, 1, cko_sels, ARRAY_SIZE(cko_sels));
+
+ hws[IMX6UL_CLK_LDB_DI0_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
+ hws[IMX6UL_CLK_LDB_DI0_DIV_7] = imx_clk_hw_fixed_factor("ldb_di0_div_7", "ldb_di0_sel", 1, 7);
+ hws[IMX6UL_CLK_LDB_DI1_DIV_3_5] = imx_clk_hw_fixed_factor("ldb_di1_div_3_5", "qspi1_sel", 2, 7);
+ hws[IMX6UL_CLK_LDB_DI1_DIV_7] = imx_clk_hw_fixed_factor("ldb_di1_div_7", "qspi1_sel", 1, 7);
+
+ hws[IMX6UL_CLK_PERIPH] = imx_clk_hw_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels));
+ hws[IMX6UL_CLK_PERIPH2] = imx_clk_hw_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels));
+
+ hws[IMX6UL_CLK_PERIPH_CLK2] = imx_clk_hw_divider("periph_clk2", "periph_clk2_sel", base + 0x14, 27, 3);
+ hws[IMX6UL_CLK_PERIPH2_CLK2] = imx_clk_hw_divider("periph2_clk2", "periph2_clk2_sel", base + 0x14, 0, 3);
+ hws[IMX6UL_CLK_IPG] = imx_clk_hw_divider("ipg", "ahb", base + 0x14, 8, 2);
+ hws[IMX6UL_CLK_LCDIF_PODF] = imx_clk_hw_divider("lcdif_podf", "lcdif_pred", base + 0x18, 23, 3);
+ hws[IMX6UL_CLK_QSPI1_PDOF] = imx_clk_hw_divider("qspi1_podf", "qspi1_sel", base + 0x1c, 26, 3);
+ hws[IMX6UL_CLK_EIM_SLOW_PODF] = imx_clk_hw_divider("eim_slow_podf", "eim_slow_sel", base + 0x1c, 23, 3);
+ hws[IMX6UL_CLK_PERCLK] = imx_clk_hw_divider("perclk", "perclk_sel", base + 0x1c, 0, 6);
+ hws[IMX6UL_CLK_CAN_PODF] = imx_clk_hw_divider("can_podf", "can_sel", base + 0x20, 2, 6);
+ hws[IMX6UL_CLK_GPMI_PODF] = imx_clk_hw_divider("gpmi_podf", "gpmi_sel", base + 0x24, 22, 3);
+ hws[IMX6UL_CLK_BCH_PODF] = imx_clk_hw_divider("bch_podf", "bch_sel", base + 0x24, 19, 3);
+ hws[IMX6UL_CLK_USDHC2_PODF] = imx_clk_hw_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3);
+ hws[IMX6UL_CLK_USDHC1_PODF] = imx_clk_hw_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3);
+ hws[IMX6UL_CLK_UART_PODF] = imx_clk_hw_divider("uart_podf", "uart_sel", base + 0x24, 0, 6);
+ hws[IMX6UL_CLK_SAI3_PRED] = imx_clk_hw_divider("sai3_pred", "sai3_sel", base + 0x28, 22, 3);
+ hws[IMX6UL_CLK_SAI3_PODF] = imx_clk_hw_divider("sai3_podf", "sai3_pred", base + 0x28, 16, 6);
+ hws[IMX6UL_CLK_SAI1_PRED] = imx_clk_hw_divider("sai1_pred", "sai1_sel", base + 0x28, 6, 3);
+ hws[IMX6UL_CLK_SAI1_PODF] = imx_clk_hw_divider("sai1_podf", "sai1_pred", base + 0x28, 0, 6);
if (clk_on_imx6ull()) {
- clks[IMX6ULL_CLK_ESAI_PRED] = imx_clk_divider("esai_pred", "esai_sel", base + 0x28, 9, 3);
- clks[IMX6ULL_CLK_ESAI_PODF] = imx_clk_divider("esai_podf", "esai_pred", base + 0x28, 25, 3);
+ hws[IMX6ULL_CLK_ESAI_PRED] = imx_clk_hw_divider("esai_pred", "esai_sel", base + 0x28, 9, 3);
+ hws[IMX6ULL_CLK_ESAI_PODF] = imx_clk_hw_divider("esai_podf", "esai_pred", base + 0x28, 25, 3);
}
- clks[IMX6UL_CLK_ENFC_PRED] = imx_clk_divider("enfc_pred", "enfc_sel", base + 0x2c, 18, 3);
- clks[IMX6UL_CLK_ENFC_PODF] = imx_clk_divider("enfc_podf", "enfc_pred", base + 0x2c, 21, 6);
- clks[IMX6UL_CLK_SAI2_PRED] = imx_clk_divider("sai2_pred", "sai2_sel", base + 0x2c, 6, 3);
- clks[IMX6UL_CLK_SAI2_PODF] = imx_clk_divider("sai2_podf", "sai2_pred", base + 0x2c, 0, 6);
- clks[IMX6UL_CLK_SPDIF_PRED] = imx_clk_divider("spdif_pred", "spdif_sel", base + 0x30, 25, 3);
- clks[IMX6UL_CLK_SPDIF_PODF] = imx_clk_divider("spdif_podf", "spdif_pred", base + 0x30, 22, 3);
+ hws[IMX6UL_CLK_ENFC_PRED] = imx_clk_hw_divider("enfc_pred", "enfc_sel", base + 0x2c, 18, 3);
+ hws[IMX6UL_CLK_ENFC_PODF] = imx_clk_hw_divider("enfc_podf", "enfc_pred", base + 0x2c, 21, 6);
+ hws[IMX6UL_CLK_SAI2_PRED] = imx_clk_hw_divider("sai2_pred", "sai2_sel", base + 0x2c, 6, 3);
+ hws[IMX6UL_CLK_SAI2_PODF] = imx_clk_hw_divider("sai2_podf", "sai2_pred", base + 0x2c, 0, 6);
+ hws[IMX6UL_CLK_SPDIF_PRED] = imx_clk_hw_divider("spdif_pred", "spdif_sel", base + 0x30, 25, 3);
+ hws[IMX6UL_CLK_SPDIF_PODF] = imx_clk_hw_divider("spdif_podf", "spdif_pred", base + 0x30, 22, 3);
if (clk_on_imx6ul())
- clks[IMX6UL_CLK_SIM_PODF] = imx_clk_divider("sim_podf", "sim_pre_sel", base + 0x34, 12, 3);
+ hws[IMX6UL_CLK_SIM_PODF] = imx_clk_hw_divider("sim_podf", "sim_pre_sel", base + 0x34, 12, 3);
else if (clk_on_imx6ull())
- clks[IMX6ULL_CLK_EPDC_PODF] = imx_clk_divider("epdc_podf", "epdc_pre_sel", base + 0x34, 12, 3);
- clks[IMX6UL_CLK_ECSPI_PODF] = imx_clk_divider("ecspi_podf", "ecspi_sel", base + 0x38, 19, 6);
- clks[IMX6UL_CLK_LCDIF_PRED] = imx_clk_divider("lcdif_pred", "lcdif_pre_sel", base + 0x38, 12, 3);
- clks[IMX6UL_CLK_CSI_PODF] = imx_clk_divider("csi_podf", "csi_sel", base + 0x3c, 11, 3);
+ hws[IMX6ULL_CLK_EPDC_PODF] = imx_clk_hw_divider("epdc_podf", "epdc_pre_sel", base + 0x34, 12, 3);
+ hws[IMX6UL_CLK_ECSPI_PODF] = imx_clk_hw_divider("ecspi_podf", "ecspi_sel", base + 0x38, 19, 6);
+ hws[IMX6UL_CLK_LCDIF_PRED] = imx_clk_hw_divider("lcdif_pred", "lcdif_pre_sel", base + 0x38, 12, 3);
+ hws[IMX6UL_CLK_CSI_PODF] = imx_clk_hw_divider("csi_podf", "csi_sel", base + 0x3c, 11, 3);
- clks[IMX6UL_CLK_CKO1_PODF] = imx_clk_divider("cko1_podf", "cko1_sel", base + 0x60, 4, 3);
- clks[IMX6UL_CLK_CKO2_PODF] = imx_clk_divider("cko2_podf", "cko2_sel", base + 0x60, 21, 3);
+ hws[IMX6UL_CLK_CKO1_PODF] = imx_clk_hw_divider("cko1_podf", "cko1_sel", base + 0x60, 4, 3);
+ hws[IMX6UL_CLK_CKO2_PODF] = imx_clk_hw_divider("cko2_podf", "cko2_sel", base + 0x60, 21, 3);
- clks[IMX6UL_CLK_ARM] = imx_clk_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16);
- clks[IMX6UL_CLK_MMDC_PODF] = imx_clk_busy_divider("mmdc_podf", "periph2", base + 0x14, 3, 3, base + 0x48, 2);
- clks[IMX6UL_CLK_AXI_PODF] = imx_clk_busy_divider("axi_podf", "axi_sel", base + 0x14, 16, 3, base + 0x48, 0);
- clks[IMX6UL_CLK_AHB] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1);
+ hws[IMX6UL_CLK_ARM] = imx_clk_hw_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16);
+ hws[IMX6UL_CLK_MMDC_PODF] = imx_clk_hw_busy_divider("mmdc_podf", "periph2", base + 0x14, 3, 3, base + 0x48, 2);
+ hws[IMX6UL_CLK_AXI_PODF] = imx_clk_hw_busy_divider("axi_podf", "axi_sel", base + 0x14, 16, 3, base + 0x48, 0);
+ hws[IMX6UL_CLK_AHB] = imx_clk_hw_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1);
/* CCGR0 */
- clks[IMX6UL_CLK_AIPSTZ1] = imx_clk_gate2_flags("aips_tz1", "ahb", base + 0x68, 0, CLK_IS_CRITICAL);
- clks[IMX6UL_CLK_AIPSTZ2] = imx_clk_gate2_flags("aips_tz2", "ahb", base + 0x68, 2, CLK_IS_CRITICAL);
- clks[IMX6UL_CLK_APBHDMA] = imx_clk_gate2("apbh_dma", "bch_podf", base + 0x68, 4);
- clks[IMX6UL_CLK_ASRC_IPG] = imx_clk_gate2_shared("asrc_ipg", "ahb", base + 0x68, 6, &share_count_asrc);
- clks[IMX6UL_CLK_ASRC_MEM] = imx_clk_gate2_shared("asrc_mem", "ahb", base + 0x68, 6, &share_count_asrc);
+ hws[IMX6UL_CLK_AIPSTZ1] = imx_clk_hw_gate2_flags("aips_tz1", "ahb", base + 0x68, 0, CLK_IS_CRITICAL);
+ hws[IMX6UL_CLK_AIPSTZ2] = imx_clk_hw_gate2_flags("aips_tz2", "ahb", base + 0x68, 2, CLK_IS_CRITICAL);
+ hws[IMX6UL_CLK_APBHDMA] = imx_clk_hw_gate2("apbh_dma", "bch_podf", base + 0x68, 4);
+ hws[IMX6UL_CLK_ASRC_IPG] = imx_clk_hw_gate2_shared("asrc_ipg", "ahb", base + 0x68, 6, &share_count_asrc);
+ hws[IMX6UL_CLK_ASRC_MEM] = imx_clk_hw_gate2_shared("asrc_mem", "ahb", base + 0x68, 6, &share_count_asrc);
if (clk_on_imx6ul()) {
- clks[IMX6UL_CLK_CAAM_MEM] = imx_clk_gate2("caam_mem", "ahb", base + 0x68, 8);
- clks[IMX6UL_CLK_CAAM_ACLK] = imx_clk_gate2("caam_aclk", "ahb", base + 0x68, 10);
- clks[IMX6UL_CLK_CAAM_IPG] = imx_clk_gate2("caam_ipg", "ipg", base + 0x68, 12);
+ hws[IMX6UL_CLK_CAAM_MEM] = imx_clk_hw_gate2("caam_mem", "ahb", base + 0x68, 8);
+ hws[IMX6UL_CLK_CAAM_ACLK] = imx_clk_hw_gate2("caam_aclk", "ahb", base + 0x68, 10);
+ hws[IMX6UL_CLK_CAAM_IPG] = imx_clk_hw_gate2("caam_ipg", "ipg", base + 0x68, 12);
} else if (clk_on_imx6ull()) {
- clks[IMX6ULL_CLK_DCP_CLK] = imx_clk_gate2("dcp", "ahb", base + 0x68, 10);
- clks[IMX6UL_CLK_ENET] = imx_clk_gate2("enet", "ipg", base + 0x68, 12);
- clks[IMX6UL_CLK_ENET_AHB] = imx_clk_gate2("enet_ahb", "ahb", base + 0x68, 12);
+ hws[IMX6ULL_CLK_DCP_CLK] = imx_clk_hw_gate2("dcp", "ahb", base + 0x68, 10);
+ hws[IMX6UL_CLK_ENET] = imx_clk_hw_gate2("enet", "ipg", base + 0x68, 12);
+ hws[IMX6UL_CLK_ENET_AHB] = imx_clk_hw_gate2("enet_ahb", "ahb", base + 0x68, 12);
}
- clks[IMX6UL_CLK_CAN1_IPG] = imx_clk_gate2("can1_ipg", "ipg", base + 0x68, 14);
- clks[IMX6UL_CLK_CAN1_SERIAL] = imx_clk_gate2("can1_serial", "can_podf", base + 0x68, 16);
- clks[IMX6UL_CLK_CAN2_IPG] = imx_clk_gate2("can2_ipg", "ipg", base + 0x68, 18);
- clks[IMX6UL_CLK_CAN2_SERIAL] = imx_clk_gate2("can2_serial", "can_podf", base + 0x68, 20);
- clks[IMX6UL_CLK_GPT2_BUS] = imx_clk_gate2("gpt2_bus", "perclk", base + 0x68, 24);
- clks[IMX6UL_CLK_GPT2_SERIAL] = imx_clk_gate2("gpt2_serial", "perclk", base + 0x68, 26);
- clks[IMX6UL_CLK_UART2_IPG] = imx_clk_gate2("uart2_ipg", "ipg", base + 0x68, 28);
- clks[IMX6UL_CLK_UART2_SERIAL] = imx_clk_gate2("uart2_serial", "uart_podf", base + 0x68, 28);
+ hws[IMX6UL_CLK_CAN1_IPG] = imx_clk_hw_gate2("can1_ipg", "ipg", base + 0x68, 14);
+ hws[IMX6UL_CLK_CAN1_SERIAL] = imx_clk_hw_gate2("can1_serial", "can_podf", base + 0x68, 16);
+ hws[IMX6UL_CLK_CAN2_IPG] = imx_clk_hw_gate2("can2_ipg", "ipg", base + 0x68, 18);
+ hws[IMX6UL_CLK_CAN2_SERIAL] = imx_clk_hw_gate2("can2_serial", "can_podf", base + 0x68, 20);
+ hws[IMX6UL_CLK_GPT2_BUS] = imx_clk_hw_gate2("gpt2_bus", "perclk", base + 0x68, 24);
+ hws[IMX6UL_CLK_GPT2_SERIAL] = imx_clk_hw_gate2("gpt2_serial", "perclk", base + 0x68, 26);
+ hws[IMX6UL_CLK_UART2_IPG] = imx_clk_hw_gate2("uart2_ipg", "ipg", base + 0x68, 28);
+ hws[IMX6UL_CLK_UART2_SERIAL] = imx_clk_hw_gate2("uart2_serial", "uart_podf", base + 0x68, 28);
if (clk_on_imx6ull())
- clks[IMX6UL_CLK_AIPSTZ3] = imx_clk_gate2("aips_tz3", "ahb", base + 0x80, 18);
- clks[IMX6UL_CLK_GPIO2] = imx_clk_gate2("gpio2", "ipg", base + 0x68, 30);
+ hws[IMX6UL_CLK_AIPSTZ3] = imx_clk_hw_gate2("aips_tz3", "ahb", base + 0x80, 18);
+ hws[IMX6UL_CLK_GPIO2] = imx_clk_hw_gate2("gpio2", "ipg", base + 0x68, 30);
/* CCGR1 */
- clks[IMX6UL_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_podf", base + 0x6c, 0);
- clks[IMX6UL_CLK_ECSPI2] = imx_clk_gate2("ecspi2", "ecspi_podf", base + 0x6c, 2);
- clks[IMX6UL_CLK_ECSPI3] = imx_clk_gate2("ecspi3", "ecspi_podf", base + 0x6c, 4);
- clks[IMX6UL_CLK_ECSPI4] = imx_clk_gate2("ecspi4", "ecspi_podf", base + 0x6c, 6);
- clks[IMX6UL_CLK_ADC2] = imx_clk_gate2("adc2", "ipg", base + 0x6c, 8);
- clks[IMX6UL_CLK_UART3_IPG] = imx_clk_gate2("uart3_ipg", "ipg", base + 0x6c, 10);
- clks[IMX6UL_CLK_UART3_SERIAL] = imx_clk_gate2("uart3_serial", "uart_podf", base + 0x6c, 10);
- clks[IMX6UL_CLK_EPIT1] = imx_clk_gate2("epit1", "perclk", base + 0x6c, 12);
- clks[IMX6UL_CLK_EPIT2] = imx_clk_gate2("epit2", "perclk", base + 0x6c, 14);
- clks[IMX6UL_CLK_ADC1] = imx_clk_gate2("adc1", "ipg", base + 0x6c, 16);
- clks[IMX6UL_CLK_GPT1_BUS] = imx_clk_gate2("gpt1_bus", "perclk", base + 0x6c, 20);
- clks[IMX6UL_CLK_GPT1_SERIAL] = imx_clk_gate2("gpt1_serial", "perclk", base + 0x6c, 22);
- clks[IMX6UL_CLK_UART4_IPG] = imx_clk_gate2("uart4_ipg", "ipg", base + 0x6c, 24);
- clks[IMX6UL_CLK_UART4_SERIAL] = imx_clk_gate2("uart4_serial", "uart_podf", base + 0x6c, 24);
- clks[IMX6UL_CLK_GPIO1] = imx_clk_gate2("gpio1", "ipg", base + 0x6c, 26);
- clks[IMX6UL_CLK_GPIO5] = imx_clk_gate2("gpio5", "ipg", base + 0x6c, 30);
+ hws[IMX6UL_CLK_ECSPI1] = imx_clk_hw_gate2("ecspi1", "ecspi_podf", base + 0x6c, 0);
+ hws[IMX6UL_CLK_ECSPI2] = imx_clk_hw_gate2("ecspi2", "ecspi_podf", base + 0x6c, 2);
+ hws[IMX6UL_CLK_ECSPI3] = imx_clk_hw_gate2("ecspi3", "ecspi_podf", base + 0x6c, 4);
+ hws[IMX6UL_CLK_ECSPI4] = imx_clk_hw_gate2("ecspi4", "ecspi_podf", base + 0x6c, 6);
+ hws[IMX6UL_CLK_ADC2] = imx_clk_hw_gate2("adc2", "ipg", base + 0x6c, 8);
+ hws[IMX6UL_CLK_UART3_IPG] = imx_clk_hw_gate2("uart3_ipg", "ipg", base + 0x6c, 10);
+ hws[IMX6UL_CLK_UART3_SERIAL] = imx_clk_hw_gate2("uart3_serial", "uart_podf", base + 0x6c, 10);
+ hws[IMX6UL_CLK_EPIT1] = imx_clk_hw_gate2("epit1", "perclk", base + 0x6c, 12);
+ hws[IMX6UL_CLK_EPIT2] = imx_clk_hw_gate2("epit2", "perclk", base + 0x6c, 14);
+ hws[IMX6UL_CLK_ADC1] = imx_clk_hw_gate2("adc1", "ipg", base + 0x6c, 16);
+ hws[IMX6UL_CLK_GPT1_BUS] = imx_clk_hw_gate2("gpt1_bus", "perclk", base + 0x6c, 20);
+ hws[IMX6UL_CLK_GPT1_SERIAL] = imx_clk_hw_gate2("gpt1_serial", "perclk", base + 0x6c, 22);
+ hws[IMX6UL_CLK_UART4_IPG] = imx_clk_hw_gate2("uart4_ipg", "ipg", base + 0x6c, 24);
+ hws[IMX6UL_CLK_UART4_SERIAL] = imx_clk_hw_gate2("uart4_serial", "uart_podf", base + 0x6c, 24);
+ hws[IMX6UL_CLK_GPIO1] = imx_clk_hw_gate2("gpio1", "ipg", base + 0x6c, 26);
+ hws[IMX6UL_CLK_GPIO5] = imx_clk_hw_gate2("gpio5", "ipg", base + 0x6c, 30);
/* CCGR2 */
if (clk_on_imx6ull()) {
- clks[IMX6ULL_CLK_ESAI_EXTAL] = imx_clk_gate2_shared("esai_extal", "esai_podf", base + 0x70, 0, &share_count_esai);
- clks[IMX6ULL_CLK_ESAI_IPG] = imx_clk_gate2_shared("esai_ipg", "ahb", base + 0x70, 0, &share_count_esai);
- clks[IMX6ULL_CLK_ESAI_MEM] = imx_clk_gate2_shared("esai_mem", "ahb", base + 0x70, 0, &share_count_esai);
+ hws[IMX6ULL_CLK_ESAI_EXTAL] = imx_clk_hw_gate2_shared("esai_extal", "esai_podf", base + 0x70, 0, &share_count_esai);
+ hws[IMX6ULL_CLK_ESAI_IPG] = imx_clk_hw_gate2_shared("esai_ipg", "ahb", base + 0x70, 0, &share_count_esai);
+ hws[IMX6ULL_CLK_ESAI_MEM] = imx_clk_hw_gate2_shared("esai_mem", "ahb", base + 0x70, 0, &share_count_esai);
}
- clks[IMX6UL_CLK_CSI] = imx_clk_gate2("csi", "csi_podf", base + 0x70, 2);
- clks[IMX6UL_CLK_I2C1] = imx_clk_gate2("i2c1", "perclk", base + 0x70, 6);
- clks[IMX6UL_CLK_I2C2] = imx_clk_gate2("i2c2", "perclk", base + 0x70, 8);
- clks[IMX6UL_CLK_I2C3] = imx_clk_gate2("i2c3", "perclk", base + 0x70, 10);
- clks[IMX6UL_CLK_OCOTP] = imx_clk_gate2("ocotp", "ipg", base + 0x70, 12);
- clks[IMX6UL_CLK_IOMUXC] = imx_clk_gate2("iomuxc", "lcdif_podf", base + 0x70, 14);
- clks[IMX6UL_CLK_GPIO3] = imx_clk_gate2("gpio3", "ipg", base + 0x70, 26);
- clks[IMX6UL_CLK_LCDIF_APB] = imx_clk_gate2("lcdif_apb", "axi", base + 0x70, 28);
- clks[IMX6UL_CLK_PXP] = imx_clk_gate2("pxp", "axi", base + 0x70, 30);
+ hws[IMX6UL_CLK_CSI] = imx_clk_hw_gate2("csi", "csi_podf", base + 0x70, 2);
+ hws[IMX6UL_CLK_I2C1] = imx_clk_hw_gate2("i2c1", "perclk", base + 0x70, 6);
+ hws[IMX6UL_CLK_I2C2] = imx_clk_hw_gate2("i2c2", "perclk", base + 0x70, 8);
+ hws[IMX6UL_CLK_I2C3] = imx_clk_hw_gate2("i2c3", "perclk", base + 0x70, 10);
+ hws[IMX6UL_CLK_OCOTP] = imx_clk_hw_gate2("ocotp", "ipg", base + 0x70, 12);
+ hws[IMX6UL_CLK_IOMUXC] = imx_clk_hw_gate2("iomuxc", "lcdif_podf", base + 0x70, 14);
+ hws[IMX6UL_CLK_GPIO3] = imx_clk_hw_gate2("gpio3", "ipg", base + 0x70, 26);
+ hws[IMX6UL_CLK_LCDIF_APB] = imx_clk_hw_gate2("lcdif_apb", "axi", base + 0x70, 28);
+ hws[IMX6UL_CLK_PXP] = imx_clk_hw_gate2("pxp", "axi", base + 0x70, 30);
/* CCGR3 */
- clks[IMX6UL_CLK_UART5_IPG] = imx_clk_gate2("uart5_ipg", "ipg", base + 0x74, 2);
- clks[IMX6UL_CLK_UART5_SERIAL] = imx_clk_gate2("uart5_serial", "uart_podf", base + 0x74, 2);
+ hws[IMX6UL_CLK_UART5_IPG] = imx_clk_hw_gate2("uart5_ipg", "ipg", base + 0x74, 2);
+ hws[IMX6UL_CLK_UART5_SERIAL] = imx_clk_hw_gate2("uart5_serial", "uart_podf", base + 0x74, 2);
if (clk_on_imx6ul()) {
- clks[IMX6UL_CLK_ENET] = imx_clk_gate2("enet", "ipg", base + 0x74, 4);
- clks[IMX6UL_CLK_ENET_AHB] = imx_clk_gate2("enet_ahb", "ahb", base + 0x74, 4);
+ hws[IMX6UL_CLK_ENET] = imx_clk_hw_gate2("enet", "ipg", base + 0x74, 4);
+ hws[IMX6UL_CLK_ENET_AHB] = imx_clk_hw_gate2("enet_ahb", "ahb", base + 0x74, 4);
} else if (clk_on_imx6ull()) {
- clks[IMX6ULL_CLK_EPDC_ACLK] = imx_clk_gate2("epdc_aclk", "axi", base + 0x74, 4);
- clks[IMX6ULL_CLK_EPDC_PIX] = imx_clk_gate2("epdc_pix", "epdc_podf", base + 0x74, 4);
+ hws[IMX6ULL_CLK_EPDC_ACLK] = imx_clk_hw_gate2("epdc_aclk", "axi", base + 0x74, 4);
+ hws[IMX6ULL_CLK_EPDC_PIX] = imx_clk_hw_gate2("epdc_pix", "epdc_podf", base + 0x74, 4);
}
- clks[IMX6UL_CLK_UART6_IPG] = imx_clk_gate2("uart6_ipg", "ipg", base + 0x74, 6);
- clks[IMX6UL_CLK_UART6_SERIAL] = imx_clk_gate2("uart6_serial", "uart_podf", base + 0x74, 6);
- clks[IMX6UL_CLK_LCDIF_PIX] = imx_clk_gate2("lcdif_pix", "lcdif_podf", base + 0x74, 10);
- clks[IMX6UL_CLK_GPIO4] = imx_clk_gate2("gpio4", "ipg", base + 0x74, 12);
- clks[IMX6UL_CLK_QSPI] = imx_clk_gate2("qspi1", "qspi1_podf", base + 0x74, 14);
- clks[IMX6UL_CLK_WDOG1] = imx_clk_gate2("wdog1", "ipg", base + 0x74, 16);
- clks[IMX6UL_CLK_MMDC_P0_FAST] = imx_clk_gate_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL);
- clks[IMX6UL_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
- clks[IMX6UL_CLK_MMDC_P1_IPG] = imx_clk_gate2("mmdc_p1_ipg", "ipg", base + 0x74, 26);
- clks[IMX6UL_CLK_AXI] = imx_clk_gate_flags("axi", "axi_podf", base + 0x74, 28, CLK_IS_CRITICAL);
+ hws[IMX6UL_CLK_UART6_IPG] = imx_clk_hw_gate2("uart6_ipg", "ipg", base + 0x74, 6);
+ hws[IMX6UL_CLK_UART6_SERIAL] = imx_clk_hw_gate2("uart6_serial", "uart_podf", base + 0x74, 6);
+ hws[IMX6UL_CLK_LCDIF_PIX] = imx_clk_hw_gate2("lcdif_pix", "lcdif_podf", base + 0x74, 10);
+ hws[IMX6UL_CLK_GPIO4] = imx_clk_hw_gate2("gpio4", "ipg", base + 0x74, 12);
+ hws[IMX6UL_CLK_QSPI] = imx_clk_hw_gate2("qspi1", "qspi1_podf", base + 0x74, 14);
+ hws[IMX6UL_CLK_WDOG1] = imx_clk_hw_gate2("wdog1", "ipg", base + 0x74, 16);
+ hws[IMX6UL_CLK_MMDC_P0_FAST] = imx_clk_hw_gate_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL);
+ hws[IMX6UL_CLK_MMDC_P0_IPG] = imx_clk_hw_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
+ hws[IMX6UL_CLK_MMDC_P1_IPG] = imx_clk_hw_gate2_flags("mmdc_p1_ipg", "ipg", base + 0x74, 26, CLK_IS_CRITICAL);
+ hws[IMX6UL_CLK_AXI] = imx_clk_hw_gate_flags("axi", "axi_podf", base + 0x74, 28, CLK_IS_CRITICAL);
/* CCGR4 */
- clks[IMX6UL_CLK_PER_BCH] = imx_clk_gate2("per_bch", "bch_podf", base + 0x78, 12);
- clks[IMX6UL_CLK_PWM1] = imx_clk_gate2("pwm1", "perclk", base + 0x78, 16);
- clks[IMX6UL_CLK_PWM2] = imx_clk_gate2("pwm2", "perclk", base + 0x78, 18);
- clks[IMX6UL_CLK_PWM3] = imx_clk_gate2("pwm3", "perclk", base + 0x78, 20);
- clks[IMX6UL_CLK_PWM4] = imx_clk_gate2("pwm4", "perclk", base + 0x78, 22);
- clks[IMX6UL_CLK_GPMI_BCH_APB] = imx_clk_gate2("gpmi_bch_apb", "bch_podf", base + 0x78, 24);
- clks[IMX6UL_CLK_GPMI_BCH] = imx_clk_gate2("gpmi_bch", "gpmi_podf", base + 0x78, 26);
- clks[IMX6UL_CLK_GPMI_IO] = imx_clk_gate2("gpmi_io", "enfc_podf", base + 0x78, 28);
- clks[IMX6UL_CLK_GPMI_APB] = imx_clk_gate2("gpmi_apb", "bch_podf", base + 0x78, 30);
+ hws[IMX6UL_CLK_PER_BCH] = imx_clk_hw_gate2("per_bch", "bch_podf", base + 0x78, 12);
+ hws[IMX6UL_CLK_PWM1] = imx_clk_hw_gate2("pwm1", "perclk", base + 0x78, 16);
+ hws[IMX6UL_CLK_PWM2] = imx_clk_hw_gate2("pwm2", "perclk", base + 0x78, 18);
+ hws[IMX6UL_CLK_PWM3] = imx_clk_hw_gate2("pwm3", "perclk", base + 0x78, 20);
+ hws[IMX6UL_CLK_PWM4] = imx_clk_hw_gate2("pwm4", "perclk", base + 0x78, 22);
+ hws[IMX6UL_CLK_GPMI_BCH_APB] = imx_clk_hw_gate2("gpmi_bch_apb", "bch_podf", base + 0x78, 24);
+ hws[IMX6UL_CLK_GPMI_BCH] = imx_clk_hw_gate2("gpmi_bch", "gpmi_podf", base + 0x78, 26);
+ hws[IMX6UL_CLK_GPMI_IO] = imx_clk_hw_gate2("gpmi_io", "enfc_podf", base + 0x78, 28);
+ hws[IMX6UL_CLK_GPMI_APB] = imx_clk_hw_gate2("gpmi_apb", "bch_podf", base + 0x78, 30);
/* CCGR5 */
- clks[IMX6UL_CLK_ROM] = imx_clk_gate2_flags("rom", "ahb", base + 0x7c, 0, CLK_IS_CRITICAL);
- clks[IMX6UL_CLK_SDMA] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6);
- clks[IMX6UL_CLK_KPP] = imx_clk_gate2("kpp", "ipg", base + 0x7c, 8);
- clks[IMX6UL_CLK_WDOG2] = imx_clk_gate2("wdog2", "ipg", base + 0x7c, 10);
- clks[IMX6UL_CLK_SPBA] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12);
- clks[IMX6UL_CLK_SPDIF] = imx_clk_gate2_shared("spdif", "spdif_podf", base + 0x7c, 14, &share_count_audio);
- clks[IMX6UL_CLK_SPDIF_GCLK] = imx_clk_gate2_shared("spdif_gclk", "ipg", base + 0x7c, 14, &share_count_audio);
- clks[IMX6UL_CLK_SAI3] = imx_clk_gate2_shared("sai3", "sai3_podf", base + 0x7c, 22, &share_count_sai3);
- clks[IMX6UL_CLK_SAI3_IPG] = imx_clk_gate2_shared("sai3_ipg", "ipg", base + 0x7c, 22, &share_count_sai3);
- clks[IMX6UL_CLK_UART1_IPG] = imx_clk_gate2("uart1_ipg", "ipg", base + 0x7c, 24);
- clks[IMX6UL_CLK_UART1_SERIAL] = imx_clk_gate2("uart1_serial", "uart_podf", base + 0x7c, 24);
- clks[IMX6UL_CLK_UART7_IPG] = imx_clk_gate2("uart7_ipg", "ipg", base + 0x7c, 26);
- clks[IMX6UL_CLK_UART7_SERIAL] = imx_clk_gate2("uart7_serial", "uart_podf", base + 0x7c, 26);
- clks[IMX6UL_CLK_SAI1] = imx_clk_gate2_shared("sai1", "sai1_podf", base + 0x7c, 28, &share_count_sai1);
- clks[IMX6UL_CLK_SAI1_IPG] = imx_clk_gate2_shared("sai1_ipg", "ipg", base + 0x7c, 28, &share_count_sai1);
- clks[IMX6UL_CLK_SAI2] = imx_clk_gate2_shared("sai2", "sai2_podf", base + 0x7c, 30, &share_count_sai2);
- clks[IMX6UL_CLK_SAI2_IPG] = imx_clk_gate2_shared("sai2_ipg", "ipg", base + 0x7c, 30, &share_count_sai2);
+ hws[IMX6UL_CLK_ROM] = imx_clk_hw_gate2_flags("rom", "ahb", base + 0x7c, 0, CLK_IS_CRITICAL);
+ hws[IMX6UL_CLK_SDMA] = imx_clk_hw_gate2("sdma", "ahb", base + 0x7c, 6);
+ hws[IMX6UL_CLK_KPP] = imx_clk_hw_gate2("kpp", "ipg", base + 0x7c, 8);
+ hws[IMX6UL_CLK_WDOG2] = imx_clk_hw_gate2("wdog2", "ipg", base + 0x7c, 10);
+ hws[IMX6UL_CLK_SPBA] = imx_clk_hw_gate2("spba", "ipg", base + 0x7c, 12);
+ hws[IMX6UL_CLK_SPDIF] = imx_clk_hw_gate2_shared("spdif", "spdif_podf", base + 0x7c, 14, &share_count_audio);
+ hws[IMX6UL_CLK_SPDIF_GCLK] = imx_clk_hw_gate2_shared("spdif_gclk", "ipg", base + 0x7c, 14, &share_count_audio);
+ hws[IMX6UL_CLK_SAI3] = imx_clk_hw_gate2_shared("sai3", "sai3_podf", base + 0x7c, 22, &share_count_sai3);
+ hws[IMX6UL_CLK_SAI3_IPG] = imx_clk_hw_gate2_shared("sai3_ipg", "ipg", base + 0x7c, 22, &share_count_sai3);
+ hws[IMX6UL_CLK_UART1_IPG] = imx_clk_hw_gate2("uart1_ipg", "ipg", base + 0x7c, 24);
+ hws[IMX6UL_CLK_UART1_SERIAL] = imx_clk_hw_gate2("uart1_serial", "uart_podf", base + 0x7c, 24);
+ hws[IMX6UL_CLK_UART7_IPG] = imx_clk_hw_gate2("uart7_ipg", "ipg", base + 0x7c, 26);
+ hws[IMX6UL_CLK_UART7_SERIAL] = imx_clk_hw_gate2("uart7_serial", "uart_podf", base + 0x7c, 26);
+ hws[IMX6UL_CLK_SAI1] = imx_clk_hw_gate2_shared("sai1", "sai1_podf", base + 0x7c, 28, &share_count_sai1);
+ hws[IMX6UL_CLK_SAI1_IPG] = imx_clk_hw_gate2_shared("sai1_ipg", "ipg", base + 0x7c, 28, &share_count_sai1);
+ hws[IMX6UL_CLK_SAI2] = imx_clk_hw_gate2_shared("sai2", "sai2_podf", base + 0x7c, 30, &share_count_sai2);
+ hws[IMX6UL_CLK_SAI2_IPG] = imx_clk_hw_gate2_shared("sai2_ipg", "ipg", base + 0x7c, 30, &share_count_sai2);
/* CCGR6 */
- clks[IMX6UL_CLK_USBOH3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0);
- clks[IMX6UL_CLK_USDHC1] = imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2);
- clks[IMX6UL_CLK_USDHC2] = imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4);
+ hws[IMX6UL_CLK_USBOH3] = imx_clk_hw_gate2("usboh3", "ipg", base + 0x80, 0);
+ hws[IMX6UL_CLK_USDHC1] = imx_clk_hw_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2);
+ hws[IMX6UL_CLK_USDHC2] = imx_clk_hw_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4);
if (clk_on_imx6ul()) {
- clks[IMX6UL_CLK_SIM1] = imx_clk_gate2("sim1", "sim_sel", base + 0x80, 6);
- clks[IMX6UL_CLK_SIM2] = imx_clk_gate2("sim2", "sim_sel", base + 0x80, 8);
+ hws[IMX6UL_CLK_SIM1] = imx_clk_hw_gate2("sim1", "sim_sel", base + 0x80, 6);
+ hws[IMX6UL_CLK_SIM2] = imx_clk_hw_gate2("sim2", "sim_sel", base + 0x80, 8);
}
- clks[IMX6UL_CLK_EIM] = imx_clk_gate2("eim", "eim_slow_podf", base + 0x80, 10);
- clks[IMX6UL_CLK_PWM8] = imx_clk_gate2("pwm8", "perclk", base + 0x80, 16);
- clks[IMX6UL_CLK_UART8_IPG] = imx_clk_gate2("uart8_ipg", "ipg", base + 0x80, 14);
- clks[IMX6UL_CLK_UART8_SERIAL] = imx_clk_gate2("uart8_serial", "uart_podf", base + 0x80, 14);
- clks[IMX6UL_CLK_WDOG3] = imx_clk_gate2("wdog3", "ipg", base + 0x80, 20);
- clks[IMX6UL_CLK_I2C4] = imx_clk_gate2("i2c4", "perclk", base + 0x80, 24);
- clks[IMX6UL_CLK_PWM5] = imx_clk_gate2("pwm5", "perclk", base + 0x80, 26);
- clks[IMX6UL_CLK_PWM6] = imx_clk_gate2("pwm6", "perclk", base + 0x80, 28);
- clks[IMX6UL_CLK_PWM7] = imx_clk_gate2("pwm7", "perclk", base + 0x80, 30);
+ hws[IMX6UL_CLK_EIM] = imx_clk_hw_gate2("eim", "eim_slow_podf", base + 0x80, 10);
+ hws[IMX6UL_CLK_PWM8] = imx_clk_hw_gate2("pwm8", "perclk", base + 0x80, 16);
+ hws[IMX6UL_CLK_UART8_IPG] = imx_clk_hw_gate2("uart8_ipg", "ipg", base + 0x80, 14);
+ hws[IMX6UL_CLK_UART8_SERIAL] = imx_clk_hw_gate2("uart8_serial", "uart_podf", base + 0x80, 14);
+ hws[IMX6UL_CLK_WDOG3] = imx_clk_hw_gate2("wdog3", "ipg", base + 0x80, 20);
+ hws[IMX6UL_CLK_I2C4] = imx_clk_hw_gate2("i2c4", "perclk", base + 0x80, 24);
+ hws[IMX6UL_CLK_PWM5] = imx_clk_hw_gate2("pwm5", "perclk", base + 0x80, 26);
+ hws[IMX6UL_CLK_PWM6] = imx_clk_hw_gate2("pwm6", "perclk", base + 0x80, 28);
+ hws[IMX6UL_CLK_PWM7] = imx_clk_hw_gate2("pwm7", "perclk", base + 0x80, 30);
/* CCOSR */
- clks[IMX6UL_CLK_CKO1] = imx_clk_gate("cko1", "cko1_podf", base + 0x60, 7);
- clks[IMX6UL_CLK_CKO2] = imx_clk_gate("cko2", "cko2_podf", base + 0x60, 24);
+ hws[IMX6UL_CLK_CKO1] = imx_clk_hw_gate("cko1", "cko1_podf", base + 0x60, 7);
+ hws[IMX6UL_CLK_CKO2] = imx_clk_hw_gate("cko2", "cko2_podf", base + 0x60, 24);
/* mask handshake of mmdc */
- writel_relaxed(BM_CCM_CCDR_MMDC_CH0_MASK, base + CCDR);
+ imx_mmdc_mask_handshake(base, 0);
- imx_check_clocks(clks, ARRAY_SIZE(clks));
+ imx_check_clk_hws(hws, IMX6UL_CLK_END);
- clk_data.clks = clks;
- clk_data.clk_num = ARRAY_SIZE(clks);
- of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+ of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
/*
* Lower the AHB clock rate before changing the parent clock source,
@@ -473,39 +477,39 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
* AXI clock rate, so we need to lower AHB rate first to make sure at
* any time, AHB rate is <= 133MHz.
*/
- clk_set_rate(clks[IMX6UL_CLK_AHB], 99000000);
+ clk_set_rate(hws[IMX6UL_CLK_AHB]->clk, 99000000);
/* Change periph_pre clock to pll2_bus to adjust AXI rate to 264MHz */
- clk_set_parent(clks[IMX6UL_CLK_PERIPH_CLK2_SEL], clks[IMX6UL_CLK_OSC]);
- clk_set_parent(clks[IMX6UL_CLK_PERIPH], clks[IMX6UL_CLK_PERIPH_CLK2]);
- clk_set_parent(clks[IMX6UL_CLK_PERIPH_PRE], clks[IMX6UL_CLK_PLL2_BUS]);
- clk_set_parent(clks[IMX6UL_CLK_PERIPH], clks[IMX6UL_CLK_PERIPH_PRE]);
+ clk_set_parent(hws[IMX6UL_CLK_PERIPH_CLK2_SEL]->clk, hws[IMX6UL_CLK_OSC]->clk);
+ clk_set_parent(hws[IMX6UL_CLK_PERIPH]->clk, hws[IMX6UL_CLK_PERIPH_CLK2]->clk);
+ clk_set_parent(hws[IMX6UL_CLK_PERIPH_PRE]->clk, hws[IMX6UL_CLK_PLL2_BUS]->clk);
+ clk_set_parent(hws[IMX6UL_CLK_PERIPH]->clk, hws[IMX6UL_CLK_PERIPH_PRE]->clk);
/* Make sure AHB rate is 132MHz */
- clk_set_rate(clks[IMX6UL_CLK_AHB], 132000000);
+ clk_set_rate(hws[IMX6UL_CLK_AHB]->clk, 132000000);
/* set perclk to from OSC */
- clk_set_parent(clks[IMX6UL_CLK_PERCLK_SEL], clks[IMX6UL_CLK_OSC]);
+ clk_set_parent(hws[IMX6UL_CLK_PERCLK_SEL]->clk, hws[IMX6UL_CLK_OSC]->clk);
- clk_set_rate(clks[IMX6UL_CLK_ENET_REF], 50000000);
- clk_set_rate(clks[IMX6UL_CLK_ENET2_REF], 50000000);
- clk_set_rate(clks[IMX6UL_CLK_CSI], 24000000);
+ clk_set_rate(hws[IMX6UL_CLK_ENET_REF]->clk, 50000000);
+ clk_set_rate(hws[IMX6UL_CLK_ENET2_REF]->clk, 50000000);
+ clk_set_rate(hws[IMX6UL_CLK_CSI]->clk, 24000000);
if (clk_on_imx6ull())
- clk_prepare_enable(clks[IMX6UL_CLK_AIPSTZ3]);
+ clk_prepare_enable(hws[IMX6UL_CLK_AIPSTZ3]->clk);
if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
- clk_prepare_enable(clks[IMX6UL_CLK_USBPHY1_GATE]);
- clk_prepare_enable(clks[IMX6UL_CLK_USBPHY2_GATE]);
+ clk_prepare_enable(hws[IMX6UL_CLK_USBPHY1_GATE]->clk);
+ clk_prepare_enable(hws[IMX6UL_CLK_USBPHY2_GATE]->clk);
}
- clk_set_parent(clks[IMX6UL_CLK_CAN_SEL], clks[IMX6UL_CLK_PLL3_60M]);
+ clk_set_parent(hws[IMX6UL_CLK_CAN_SEL]->clk, hws[IMX6UL_CLK_PLL3_60M]->clk);
if (clk_on_imx6ul())
- clk_set_parent(clks[IMX6UL_CLK_SIM_PRE_SEL], clks[IMX6UL_CLK_PLL3_USB_OTG]);
+ clk_set_parent(hws[IMX6UL_CLK_SIM_PRE_SEL]->clk, hws[IMX6UL_CLK_PLL3_USB_OTG]->clk);
else if (clk_on_imx6ull())
- clk_set_parent(clks[IMX6ULL_CLK_EPDC_PRE_SEL], clks[IMX6UL_CLK_PLL3_PFD2]);
+ clk_set_parent(hws[IMX6ULL_CLK_EPDC_PRE_SEL]->clk, hws[IMX6UL_CLK_PLL3_PFD2]->clk);
- clk_set_parent(clks[IMX6UL_CLK_ENFC_SEL], clks[IMX6UL_CLK_PLL2_PFD2]);
+ clk_set_parent(hws[IMX6UL_CLK_ENFC_SEL]->clk, hws[IMX6UL_CLK_PLL2_PFD2]->clk);
}
CLK_OF_DECLARE(imx6ul, "fsl,imx6ul-ccm", imx6ul_clocks_init);
diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c
index 8f3aa994c8f7..fbea774ef687 100644
--- a/drivers/clk/imx/clk-imx7d.c
+++ b/drivers/clk/imx/clk-imx7d.c
@@ -6,6 +6,7 @@
#include <dt-bindings/clock/imx7d-clock.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
@@ -39,7 +40,6 @@ static const struct clk_div_table post_div_table[] = {
{ }
};
-static struct clk *clks[IMX7D_CLK_END];
static const char *arm_a7_sel[] = { "osc", "pll_arm_main_clk",
"pll_enet_500m_clk", "pll_dram_main_clk",
"pll_sys_main_clk", "pll_sys_pfd0_392m_clk", "pll_audio_post_div",
@@ -373,517 +373,533 @@ static const char *pll_enet_bypass_sel[] = { "pll_enet_main", "pll_enet_main_src
static const char *pll_audio_bypass_sel[] = { "pll_audio_main", "pll_audio_main_src", };
static const char *pll_video_bypass_sel[] = { "pll_video_main", "pll_video_main_src", };
-static struct clk_onecell_data clk_data;
-
-static struct clk ** const uart_clks[] __initconst = {
- &clks[IMX7D_UART1_ROOT_CLK],
- &clks[IMX7D_UART2_ROOT_CLK],
- &clks[IMX7D_UART3_ROOT_CLK],
- &clks[IMX7D_UART4_ROOT_CLK],
- &clks[IMX7D_UART5_ROOT_CLK],
- &clks[IMX7D_UART6_ROOT_CLK],
- &clks[IMX7D_UART7_ROOT_CLK],
- NULL
+static struct clk_hw **hws;
+static struct clk_hw_onecell_data *clk_hw_data;
+
+static const int uart_clk_ids[] __initconst = {
+ IMX7D_UART1_ROOT_CLK,
+ IMX7D_UART2_ROOT_CLK,
+ IMX7D_UART3_ROOT_CLK,
+ IMX7D_UART4_ROOT_CLK,
+ IMX7D_UART5_ROOT_CLK,
+ IMX7D_UART6_ROOT_CLK,
+ IMX7D_UART7_ROOT_CLK,
};
+static struct clk **uart_clks[ARRAY_SIZE(uart_clk_ids) + 1] __initdata;
+
static void __init imx7d_clocks_init(struct device_node *ccm_node)
{
struct device_node *np;
void __iomem *base;
+ int i;
+
+ clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
+ IMX7D_CLK_END), GFP_KERNEL);
+ if (WARN_ON(!clk_hw_data))
+ return;
+
+ clk_hw_data->num = IMX7D_CLK_END;
+ hws = clk_hw_data->hws;
- clks[IMX7D_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
- clks[IMX7D_OSC_24M_CLK] = of_clk_get_by_name(ccm_node, "osc");
- clks[IMX7D_CKIL] = of_clk_get_by_name(ccm_node, "ckil");
+ hws[IMX7D_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
+ hws[IMX7D_OSC_24M_CLK] = __clk_get_hw(of_clk_get_by_name(ccm_node, "osc"));
+ hws[IMX7D_CKIL] = __clk_get_hw(of_clk_get_by_name(ccm_node, "ckil"));
np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-anatop");
base = of_iomap(np, 0);
WARN_ON(!base);
of_node_put(np);
- clks[IMX7D_PLL_ARM_MAIN_SRC] = imx_clk_mux("pll_arm_main_src", base + 0x60, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
- clks[IMX7D_PLL_DRAM_MAIN_SRC] = imx_clk_mux("pll_dram_main_src", base + 0x70, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
- clks[IMX7D_PLL_SYS_MAIN_SRC] = imx_clk_mux("pll_sys_main_src", base + 0xb0, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
- clks[IMX7D_PLL_ENET_MAIN_SRC] = imx_clk_mux("pll_enet_main_src", base + 0xe0, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
- clks[IMX7D_PLL_AUDIO_MAIN_SRC] = imx_clk_mux("pll_audio_main_src", base + 0xf0, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
- clks[IMX7D_PLL_VIDEO_MAIN_SRC] = imx_clk_mux("pll_video_main_src", base + 0x130, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
-
- clks[IMX7D_PLL_ARM_MAIN] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll_arm_main", "osc", base + 0x60, 0x7f);
- clks[IMX7D_PLL_DRAM_MAIN] = imx_clk_pllv3(IMX_PLLV3_DDR_IMX7, "pll_dram_main", "osc", base + 0x70, 0x7f);
- clks[IMX7D_PLL_SYS_MAIN] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll_sys_main", "osc", base + 0xb0, 0x1);
- clks[IMX7D_PLL_ENET_MAIN] = imx_clk_pllv3(IMX_PLLV3_ENET_IMX7, "pll_enet_main", "osc", base + 0xe0, 0x0);
- clks[IMX7D_PLL_AUDIO_MAIN] = imx_clk_pllv3(IMX_PLLV3_AV_IMX7, "pll_audio_main", "osc", base + 0xf0, 0x7f);
- clks[IMX7D_PLL_VIDEO_MAIN] = imx_clk_pllv3(IMX_PLLV3_AV_IMX7, "pll_video_main", "osc", base + 0x130, 0x7f);
-
- clks[IMX7D_PLL_ARM_MAIN_BYPASS] = imx_clk_mux_flags("pll_arm_main_bypass", base + 0x60, 16, 1, pll_arm_bypass_sel, ARRAY_SIZE(pll_arm_bypass_sel), CLK_SET_RATE_PARENT);
- clks[IMX7D_PLL_DRAM_MAIN_BYPASS] = imx_clk_mux_flags("pll_dram_main_bypass", base + 0x70, 16, 1, pll_dram_bypass_sel, ARRAY_SIZE(pll_dram_bypass_sel), CLK_SET_RATE_PARENT);
- clks[IMX7D_PLL_SYS_MAIN_BYPASS] = imx_clk_mux_flags("pll_sys_main_bypass", base + 0xb0, 16, 1, pll_sys_bypass_sel, ARRAY_SIZE(pll_sys_bypass_sel), CLK_SET_RATE_PARENT);
- clks[IMX7D_PLL_ENET_MAIN_BYPASS] = imx_clk_mux_flags("pll_enet_main_bypass", base + 0xe0, 16, 1, pll_enet_bypass_sel, ARRAY_SIZE(pll_enet_bypass_sel), CLK_SET_RATE_PARENT);
- clks[IMX7D_PLL_AUDIO_MAIN_BYPASS] = imx_clk_mux_flags("pll_audio_main_bypass", base + 0xf0, 16, 1, pll_audio_bypass_sel, ARRAY_SIZE(pll_audio_bypass_sel), CLK_SET_RATE_PARENT);
- clks[IMX7D_PLL_VIDEO_MAIN_BYPASS] = imx_clk_mux_flags("pll_video_main_bypass", base + 0x130, 16, 1, pll_video_bypass_sel, ARRAY_SIZE(pll_video_bypass_sel), CLK_SET_RATE_PARENT);
-
- clks[IMX7D_PLL_ARM_MAIN_CLK] = imx_clk_gate("pll_arm_main_clk", "pll_arm_main_bypass", base + 0x60, 13);
- clks[IMX7D_PLL_DRAM_MAIN_CLK] = imx_clk_gate("pll_dram_main_clk", "pll_dram_test_div", base + 0x70, 13);
- clks[IMX7D_PLL_SYS_MAIN_CLK] = imx_clk_gate("pll_sys_main_clk", "pll_sys_main_bypass", base + 0xb0, 13);
- clks[IMX7D_PLL_AUDIO_MAIN_CLK] = imx_clk_gate("pll_audio_main_clk", "pll_audio_main_bypass", base + 0xf0, 13);
- clks[IMX7D_PLL_VIDEO_MAIN_CLK] = imx_clk_gate("pll_video_main_clk", "pll_video_main_bypass", base + 0x130, 13);
-
- clks[IMX7D_PLL_DRAM_TEST_DIV] = clk_register_divider_table(NULL, "pll_dram_test_div", "pll_dram_main_bypass",
+ hws[IMX7D_PLL_ARM_MAIN_SRC] = imx_clk_hw_mux("pll_arm_main_src", base + 0x60, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
+ hws[IMX7D_PLL_DRAM_MAIN_SRC] = imx_clk_hw_mux("pll_dram_main_src", base + 0x70, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
+ hws[IMX7D_PLL_SYS_MAIN_SRC] = imx_clk_hw_mux("pll_sys_main_src", base + 0xb0, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
+ hws[IMX7D_PLL_ENET_MAIN_SRC] = imx_clk_hw_mux("pll_enet_main_src", base + 0xe0, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
+ hws[IMX7D_PLL_AUDIO_MAIN_SRC] = imx_clk_hw_mux("pll_audio_main_src", base + 0xf0, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
+ hws[IMX7D_PLL_VIDEO_MAIN_SRC] = imx_clk_hw_mux("pll_video_main_src", base + 0x130, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
+
+ hws[IMX7D_PLL_ARM_MAIN] = imx_clk_hw_pllv3(IMX_PLLV3_SYS, "pll_arm_main", "osc", base + 0x60, 0x7f);
+ hws[IMX7D_PLL_DRAM_MAIN] = imx_clk_hw_pllv3(IMX_PLLV3_DDR_IMX7, "pll_dram_main", "osc", base + 0x70, 0x7f);
+ hws[IMX7D_PLL_SYS_MAIN] = imx_clk_hw_pllv3(IMX_PLLV3_GENERIC, "pll_sys_main", "osc", base + 0xb0, 0x1);
+ hws[IMX7D_PLL_ENET_MAIN] = imx_clk_hw_pllv3(IMX_PLLV3_ENET_IMX7, "pll_enet_main", "osc", base + 0xe0, 0x0);
+ hws[IMX7D_PLL_AUDIO_MAIN] = imx_clk_hw_pllv3(IMX_PLLV3_AV_IMX7, "pll_audio_main", "osc", base + 0xf0, 0x7f);
+ hws[IMX7D_PLL_VIDEO_MAIN] = imx_clk_hw_pllv3(IMX_PLLV3_AV_IMX7, "pll_video_main", "osc", base + 0x130, 0x7f);
+
+ hws[IMX7D_PLL_ARM_MAIN_BYPASS] = imx_clk_hw_mux_flags("pll_arm_main_bypass", base + 0x60, 16, 1, pll_arm_bypass_sel, ARRAY_SIZE(pll_arm_bypass_sel), CLK_SET_RATE_PARENT);
+ hws[IMX7D_PLL_DRAM_MAIN_BYPASS] = imx_clk_hw_mux_flags("pll_dram_main_bypass", base + 0x70, 16, 1, pll_dram_bypass_sel, ARRAY_SIZE(pll_dram_bypass_sel), CLK_SET_RATE_PARENT);
+ hws[IMX7D_PLL_SYS_MAIN_BYPASS] = imx_clk_hw_mux_flags("pll_sys_main_bypass", base + 0xb0, 16, 1, pll_sys_bypass_sel, ARRAY_SIZE(pll_sys_bypass_sel), CLK_SET_RATE_PARENT);
+ hws[IMX7D_PLL_ENET_MAIN_BYPASS] = imx_clk_hw_mux_flags("pll_enet_main_bypass", base + 0xe0, 16, 1, pll_enet_bypass_sel, ARRAY_SIZE(pll_enet_bypass_sel), CLK_SET_RATE_PARENT);
+ hws[IMX7D_PLL_AUDIO_MAIN_BYPASS] = imx_clk_hw_mux_flags("pll_audio_main_bypass", base + 0xf0, 16, 1, pll_audio_bypass_sel, ARRAY_SIZE(pll_audio_bypass_sel), CLK_SET_RATE_PARENT);
+ hws[IMX7D_PLL_VIDEO_MAIN_BYPASS] = imx_clk_hw_mux_flags("pll_video_main_bypass", base + 0x130, 16, 1, pll_video_bypass_sel, ARRAY_SIZE(pll_video_bypass_sel), CLK_SET_RATE_PARENT);
+
+ hws[IMX7D_PLL_ARM_MAIN_CLK] = imx_clk_hw_gate("pll_arm_main_clk", "pll_arm_main_bypass", base + 0x60, 13);
+ hws[IMX7D_PLL_DRAM_MAIN_CLK] = imx_clk_hw_gate("pll_dram_main_clk", "pll_dram_test_div", base + 0x70, 13);
+ hws[IMX7D_PLL_SYS_MAIN_CLK] = imx_clk_hw_gate("pll_sys_main_clk", "pll_sys_main_bypass", base + 0xb0, 13);
+ hws[IMX7D_PLL_AUDIO_MAIN_CLK] = imx_clk_hw_gate("pll_audio_main_clk", "pll_audio_main_bypass", base + 0xf0, 13);
+ hws[IMX7D_PLL_VIDEO_MAIN_CLK] = imx_clk_hw_gate("pll_video_main_clk", "pll_video_main_bypass", base + 0x130, 13);
+
+ hws[IMX7D_PLL_DRAM_TEST_DIV] = clk_hw_register_divider_table(NULL, "pll_dram_test_div", "pll_dram_main_bypass",
CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x70, 21, 2, 0, test_div_table, &imx_ccm_lock);
- clks[IMX7D_PLL_AUDIO_TEST_DIV] = clk_register_divider_table(NULL, "pll_audio_test_div", "pll_audio_main_clk",
+ hws[IMX7D_PLL_AUDIO_TEST_DIV] = clk_hw_register_divider_table(NULL, "pll_audio_test_div", "pll_audio_main_clk",
CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xf0, 19, 2, 0, test_div_table, &imx_ccm_lock);
- clks[IMX7D_PLL_AUDIO_POST_DIV] = clk_register_divider_table(NULL, "pll_audio_post_div", "pll_audio_test_div",
+ hws[IMX7D_PLL_AUDIO_POST_DIV] = clk_hw_register_divider_table(NULL, "pll_audio_post_div", "pll_audio_test_div",
CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xf0, 22, 2, 0, post_div_table, &imx_ccm_lock);
- clks[IMX7D_PLL_VIDEO_TEST_DIV] = clk_register_divider_table(NULL, "pll_video_test_div", "pll_video_main_clk",
+ hws[IMX7D_PLL_VIDEO_TEST_DIV] = clk_hw_register_divider_table(NULL, "pll_video_test_div", "pll_video_main_clk",
CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x130, 19, 2, 0, test_div_table, &imx_ccm_lock);
- clks[IMX7D_PLL_VIDEO_POST_DIV] = clk_register_divider_table(NULL, "pll_video_post_div", "pll_video_test_div",
+ hws[IMX7D_PLL_VIDEO_POST_DIV] = clk_hw_register_divider_table(NULL, "pll_video_post_div", "pll_video_test_div",
CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x130, 22, 2, 0, post_div_table, &imx_ccm_lock);
- clks[IMX7D_PLL_SYS_PFD0_392M_CLK] = imx_clk_pfd("pll_sys_pfd0_392m_clk", "pll_sys_main_clk", base + 0xc0, 0);
- clks[IMX7D_PLL_SYS_PFD1_332M_CLK] = imx_clk_pfd("pll_sys_pfd1_332m_clk", "pll_sys_main_clk", base + 0xc0, 1);
- clks[IMX7D_PLL_SYS_PFD2_270M_CLK] = imx_clk_pfd("pll_sys_pfd2_270m_clk", "pll_sys_main_clk", base + 0xc0, 2);
-
- clks[IMX7D_PLL_SYS_PFD3_CLK] = imx_clk_pfd("pll_sys_pfd3_clk", "pll_sys_main_clk", base + 0xc0, 3);
- clks[IMX7D_PLL_SYS_PFD4_CLK] = imx_clk_pfd("pll_sys_pfd4_clk", "pll_sys_main_clk", base + 0xd0, 0);
- clks[IMX7D_PLL_SYS_PFD5_CLK] = imx_clk_pfd("pll_sys_pfd5_clk", "pll_sys_main_clk", base + 0xd0, 1);
- clks[IMX7D_PLL_SYS_PFD6_CLK] = imx_clk_pfd("pll_sys_pfd6_clk", "pll_sys_main_clk", base + 0xd0, 2);
- clks[IMX7D_PLL_SYS_PFD7_CLK] = imx_clk_pfd("pll_sys_pfd7_clk", "pll_sys_main_clk", base + 0xd0, 3);
-
- clks[IMX7D_PLL_SYS_MAIN_480M] = imx_clk_fixed_factor("pll_sys_main_480m", "pll_sys_main_clk", 1, 1);
- clks[IMX7D_PLL_SYS_MAIN_240M] = imx_clk_fixed_factor("pll_sys_main_240m", "pll_sys_main_clk", 1, 2);
- clks[IMX7D_PLL_SYS_MAIN_120M] = imx_clk_fixed_factor("pll_sys_main_120m", "pll_sys_main_clk", 1, 4);
- clks[IMX7D_PLL_DRAM_MAIN_533M] = imx_clk_fixed_factor("pll_dram_533m", "pll_dram_main_clk", 1, 2);
-
- clks[IMX7D_PLL_SYS_MAIN_480M_CLK] = imx_clk_gate_dis_flags("pll_sys_main_480m_clk", "pll_sys_main_480m", base + 0xb0, 4, CLK_IS_CRITICAL);
- clks[IMX7D_PLL_SYS_MAIN_240M_CLK] = imx_clk_gate_dis("pll_sys_main_240m_clk", "pll_sys_main_240m", base + 0xb0, 5);
- clks[IMX7D_PLL_SYS_MAIN_120M_CLK] = imx_clk_gate_dis("pll_sys_main_120m_clk", "pll_sys_main_120m", base + 0xb0, 6);
- clks[IMX7D_PLL_DRAM_MAIN_533M_CLK] = imx_clk_gate("pll_dram_533m_clk", "pll_dram_533m", base + 0x70, 12);
-
- clks[IMX7D_PLL_SYS_PFD0_196M] = imx_clk_fixed_factor("pll_sys_pfd0_196m", "pll_sys_pfd0_392m_clk", 1, 2);
- clks[IMX7D_PLL_SYS_PFD1_166M] = imx_clk_fixed_factor("pll_sys_pfd1_166m", "pll_sys_pfd1_332m_clk", 1, 2);
- clks[IMX7D_PLL_SYS_PFD2_135M] = imx_clk_fixed_factor("pll_sys_pfd2_135m", "pll_sys_pfd2_270m_clk", 1, 2);
-
- clks[IMX7D_PLL_SYS_PFD0_196M_CLK] = imx_clk_gate_dis("pll_sys_pfd0_196m_clk", "pll_sys_pfd0_196m", base + 0xb0, 26);
- clks[IMX7D_PLL_SYS_PFD1_166M_CLK] = imx_clk_gate_dis("pll_sys_pfd1_166m_clk", "pll_sys_pfd1_166m", base + 0xb0, 27);
- clks[IMX7D_PLL_SYS_PFD2_135M_CLK] = imx_clk_gate_dis("pll_sys_pfd2_135m_clk", "pll_sys_pfd2_135m", base + 0xb0, 28);
-
- clks[IMX7D_PLL_ENET_MAIN_CLK] = imx_clk_fixed_factor("pll_enet_main_clk", "pll_enet_main_bypass", 1, 1);
- clks[IMX7D_PLL_ENET_MAIN_500M] = imx_clk_fixed_factor("pll_enet_500m", "pll_enet_main_clk", 1, 2);
- clks[IMX7D_PLL_ENET_MAIN_250M] = imx_clk_fixed_factor("pll_enet_250m", "pll_enet_main_clk", 1, 4);
- clks[IMX7D_PLL_ENET_MAIN_125M] = imx_clk_fixed_factor("pll_enet_125m", "pll_enet_main_clk", 1, 8);
- clks[IMX7D_PLL_ENET_MAIN_100M] = imx_clk_fixed_factor("pll_enet_100m", "pll_enet_main_clk", 1, 10);
- clks[IMX7D_PLL_ENET_MAIN_50M] = imx_clk_fixed_factor("pll_enet_50m", "pll_enet_main_clk", 1, 20);
- clks[IMX7D_PLL_ENET_MAIN_40M] = imx_clk_fixed_factor("pll_enet_40m", "pll_enet_main_clk", 1, 25);
- clks[IMX7D_PLL_ENET_MAIN_25M] = imx_clk_fixed_factor("pll_enet_25m", "pll_enet_main_clk", 1, 40);
-
- clks[IMX7D_PLL_ENET_MAIN_500M_CLK] = imx_clk_gate("pll_enet_500m_clk", "pll_enet_500m", base + 0xe0, 12);
- clks[IMX7D_PLL_ENET_MAIN_250M_CLK] = imx_clk_gate("pll_enet_250m_clk", "pll_enet_250m", base + 0xe0, 11);
- clks[IMX7D_PLL_ENET_MAIN_125M_CLK] = imx_clk_gate("pll_enet_125m_clk", "pll_enet_125m", base + 0xe0, 10);
- clks[IMX7D_PLL_ENET_MAIN_100M_CLK] = imx_clk_gate("pll_enet_100m_clk", "pll_enet_100m", base + 0xe0, 9);
- clks[IMX7D_PLL_ENET_MAIN_50M_CLK] = imx_clk_gate("pll_enet_50m_clk", "pll_enet_50m", base + 0xe0, 8);
- clks[IMX7D_PLL_ENET_MAIN_40M_CLK] = imx_clk_gate("pll_enet_40m_clk", "pll_enet_40m", base + 0xe0, 7);
- clks[IMX7D_PLL_ENET_MAIN_25M_CLK] = imx_clk_gate("pll_enet_25m_clk", "pll_enet_25m", base + 0xe0, 6);
-
- clks[IMX7D_LVDS1_OUT_SEL] = imx_clk_mux("lvds1_sel", base + 0x170, 0, 5, lvds1_sel, ARRAY_SIZE(lvds1_sel));
- clks[IMX7D_LVDS1_OUT_CLK] = imx_clk_gate_exclusive("lvds1_out", "lvds1_sel", base + 0x170, 5, BIT(6));
+ hws[IMX7D_PLL_SYS_PFD0_392M_CLK] = imx_clk_hw_pfd("pll_sys_pfd0_392m_clk", "pll_sys_main_clk", base + 0xc0, 0);
+ hws[IMX7D_PLL_SYS_PFD1_332M_CLK] = imx_clk_hw_pfd("pll_sys_pfd1_332m_clk", "pll_sys_main_clk", base + 0xc0, 1);
+ hws[IMX7D_PLL_SYS_PFD2_270M_CLK] = imx_clk_hw_pfd("pll_sys_pfd2_270m_clk", "pll_sys_main_clk", base + 0xc0, 2);
+
+ hws[IMX7D_PLL_SYS_PFD3_CLK] = imx_clk_hw_pfd("pll_sys_pfd3_clk", "pll_sys_main_clk", base + 0xc0, 3);
+ hws[IMX7D_PLL_SYS_PFD4_CLK] = imx_clk_hw_pfd("pll_sys_pfd4_clk", "pll_sys_main_clk", base + 0xd0, 0);
+ hws[IMX7D_PLL_SYS_PFD5_CLK] = imx_clk_hw_pfd("pll_sys_pfd5_clk", "pll_sys_main_clk", base + 0xd0, 1);
+ hws[IMX7D_PLL_SYS_PFD6_CLK] = imx_clk_hw_pfd("pll_sys_pfd6_clk", "pll_sys_main_clk", base + 0xd0, 2);
+ hws[IMX7D_PLL_SYS_PFD7_CLK] = imx_clk_hw_pfd("pll_sys_pfd7_clk", "pll_sys_main_clk", base + 0xd0, 3);
+
+ hws[IMX7D_PLL_SYS_MAIN_480M] = imx_clk_hw_fixed_factor("pll_sys_main_480m", "pll_sys_main_clk", 1, 1);
+ hws[IMX7D_PLL_SYS_MAIN_240M] = imx_clk_hw_fixed_factor("pll_sys_main_240m", "pll_sys_main_clk", 1, 2);
+ hws[IMX7D_PLL_SYS_MAIN_120M] = imx_clk_hw_fixed_factor("pll_sys_main_120m", "pll_sys_main_clk", 1, 4);
+ hws[IMX7D_PLL_DRAM_MAIN_533M] = imx_clk_hw_fixed_factor("pll_dram_533m", "pll_dram_main_clk", 1, 2);
+
+ hws[IMX7D_PLL_SYS_MAIN_480M_CLK] = imx_clk_hw_gate_dis_flags("pll_sys_main_480m_clk", "pll_sys_main_480m", base + 0xb0, 4, CLK_IS_CRITICAL);
+ hws[IMX7D_PLL_SYS_MAIN_240M_CLK] = imx_clk_hw_gate_dis("pll_sys_main_240m_clk", "pll_sys_main_240m", base + 0xb0, 5);
+ hws[IMX7D_PLL_SYS_MAIN_120M_CLK] = imx_clk_hw_gate_dis("pll_sys_main_120m_clk", "pll_sys_main_120m", base + 0xb0, 6);
+ hws[IMX7D_PLL_DRAM_MAIN_533M_CLK] = imx_clk_hw_gate("pll_dram_533m_clk", "pll_dram_533m", base + 0x70, 12);
+
+ hws[IMX7D_PLL_SYS_PFD0_196M] = imx_clk_hw_fixed_factor("pll_sys_pfd0_196m", "pll_sys_pfd0_392m_clk", 1, 2);
+ hws[IMX7D_PLL_SYS_PFD1_166M] = imx_clk_hw_fixed_factor("pll_sys_pfd1_166m", "pll_sys_pfd1_332m_clk", 1, 2);
+ hws[IMX7D_PLL_SYS_PFD2_135M] = imx_clk_hw_fixed_factor("pll_sys_pfd2_135m", "pll_sys_pfd2_270m_clk", 1, 2);
+
+ hws[IMX7D_PLL_SYS_PFD0_196M_CLK] = imx_clk_hw_gate_dis("pll_sys_pfd0_196m_clk", "pll_sys_pfd0_196m", base + 0xb0, 26);
+ hws[IMX7D_PLL_SYS_PFD1_166M_CLK] = imx_clk_hw_gate_dis("pll_sys_pfd1_166m_clk", "pll_sys_pfd1_166m", base + 0xb0, 27);
+ hws[IMX7D_PLL_SYS_PFD2_135M_CLK] = imx_clk_hw_gate_dis("pll_sys_pfd2_135m_clk", "pll_sys_pfd2_135m", base + 0xb0, 28);
+
+ hws[IMX7D_PLL_ENET_MAIN_CLK] = imx_clk_hw_fixed_factor("pll_enet_main_clk", "pll_enet_main_bypass", 1, 1);
+ hws[IMX7D_PLL_ENET_MAIN_500M] = imx_clk_hw_fixed_factor("pll_enet_500m", "pll_enet_main_clk", 1, 2);
+ hws[IMX7D_PLL_ENET_MAIN_250M] = imx_clk_hw_fixed_factor("pll_enet_250m", "pll_enet_main_clk", 1, 4);
+ hws[IMX7D_PLL_ENET_MAIN_125M] = imx_clk_hw_fixed_factor("pll_enet_125m", "pll_enet_main_clk", 1, 8);
+ hws[IMX7D_PLL_ENET_MAIN_100M] = imx_clk_hw_fixed_factor("pll_enet_100m", "pll_enet_main_clk", 1, 10);
+ hws[IMX7D_PLL_ENET_MAIN_50M] = imx_clk_hw_fixed_factor("pll_enet_50m", "pll_enet_main_clk", 1, 20);
+ hws[IMX7D_PLL_ENET_MAIN_40M] = imx_clk_hw_fixed_factor("pll_enet_40m", "pll_enet_main_clk", 1, 25);
+ hws[IMX7D_PLL_ENET_MAIN_25M] = imx_clk_hw_fixed_factor("pll_enet_25m", "pll_enet_main_clk", 1, 40);
+
+ hws[IMX7D_PLL_ENET_MAIN_500M_CLK] = imx_clk_hw_gate("pll_enet_500m_clk", "pll_enet_500m", base + 0xe0, 12);
+ hws[IMX7D_PLL_ENET_MAIN_250M_CLK] = imx_clk_hw_gate("pll_enet_250m_clk", "pll_enet_250m", base + 0xe0, 11);
+ hws[IMX7D_PLL_ENET_MAIN_125M_CLK] = imx_clk_hw_gate("pll_enet_125m_clk", "pll_enet_125m", base + 0xe0, 10);
+ hws[IMX7D_PLL_ENET_MAIN_100M_CLK] = imx_clk_hw_gate("pll_enet_100m_clk", "pll_enet_100m", base + 0xe0, 9);
+ hws[IMX7D_PLL_ENET_MAIN_50M_CLK] = imx_clk_hw_gate("pll_enet_50m_clk", "pll_enet_50m", base + 0xe0, 8);
+ hws[IMX7D_PLL_ENET_MAIN_40M_CLK] = imx_clk_hw_gate("pll_enet_40m_clk", "pll_enet_40m", base + 0xe0, 7);
+ hws[IMX7D_PLL_ENET_MAIN_25M_CLK] = imx_clk_hw_gate("pll_enet_25m_clk", "pll_enet_25m", base + 0xe0, 6);
+
+ hws[IMX7D_LVDS1_OUT_SEL] = imx_clk_hw_mux("lvds1_sel", base + 0x170, 0, 5, lvds1_sel, ARRAY_SIZE(lvds1_sel));
+ hws[IMX7D_LVDS1_OUT_CLK] = imx_clk_hw_gate_exclusive("lvds1_out", "lvds1_sel", base + 0x170, 5, BIT(6));
np = ccm_node;
base = of_iomap(np, 0);
WARN_ON(!base);
- clks[IMX7D_ARM_A7_ROOT_SRC] = imx_clk_mux2("arm_a7_src", base + 0x8000, 24, 3, arm_a7_sel, ARRAY_SIZE(arm_a7_sel));
- clks[IMX7D_ARM_M4_ROOT_SRC] = imx_clk_mux2("arm_m4_src", base + 0x8080, 24, 3, arm_m4_sel, ARRAY_SIZE(arm_m4_sel));
- clks[IMX7D_MAIN_AXI_ROOT_SRC] = imx_clk_mux2("axi_src", base + 0x8800, 24, 3, axi_sel, ARRAY_SIZE(axi_sel));
- clks[IMX7D_DISP_AXI_ROOT_SRC] = imx_clk_mux2("disp_axi_src", base + 0x8880, 24, 3, disp_axi_sel, ARRAY_SIZE(disp_axi_sel));
- clks[IMX7D_ENET_AXI_ROOT_SRC] = imx_clk_mux2("enet_axi_src", base + 0x8900, 24, 3, enet_axi_sel, ARRAY_SIZE(enet_axi_sel));
- clks[IMX7D_NAND_USDHC_BUS_ROOT_SRC] = imx_clk_mux2("nand_usdhc_src", base + 0x8980, 24, 3, nand_usdhc_bus_sel, ARRAY_SIZE(nand_usdhc_bus_sel));
- clks[IMX7D_AHB_CHANNEL_ROOT_SRC] = imx_clk_mux2("ahb_src", base + 0x9000, 24, 3, ahb_channel_sel, ARRAY_SIZE(ahb_channel_sel));
- clks[IMX7D_DRAM_PHYM_ROOT_SRC] = imx_clk_mux2("dram_phym_src", base + 0x9800, 24, 1, dram_phym_sel, ARRAY_SIZE(dram_phym_sel));
- clks[IMX7D_DRAM_ROOT_SRC] = imx_clk_mux2("dram_src", base + 0x9880, 24, 1, dram_sel, ARRAY_SIZE(dram_sel));
- clks[IMX7D_DRAM_PHYM_ALT_ROOT_SRC] = imx_clk_mux2("dram_phym_alt_src", base + 0xa000, 24, 3, dram_phym_alt_sel, ARRAY_SIZE(dram_phym_alt_sel));
- clks[IMX7D_DRAM_ALT_ROOT_SRC] = imx_clk_mux2("dram_alt_src", base + 0xa080, 24, 3, dram_alt_sel, ARRAY_SIZE(dram_alt_sel));
- clks[IMX7D_USB_HSIC_ROOT_SRC] = imx_clk_mux2("usb_hsic_src", base + 0xa100, 24, 3, usb_hsic_sel, ARRAY_SIZE(usb_hsic_sel));
- clks[IMX7D_PCIE_CTRL_ROOT_SRC] = imx_clk_mux2("pcie_ctrl_src", base + 0xa180, 24, 3, pcie_ctrl_sel, ARRAY_SIZE(pcie_ctrl_sel));
- clks[IMX7D_PCIE_PHY_ROOT_SRC] = imx_clk_mux2("pcie_phy_src", base + 0xa200, 24, 3, pcie_phy_sel, ARRAY_SIZE(pcie_phy_sel));
- clks[IMX7D_EPDC_PIXEL_ROOT_SRC] = imx_clk_mux2("epdc_pixel_src", base + 0xa280, 24, 3, epdc_pixel_sel, ARRAY_SIZE(epdc_pixel_sel));
- clks[IMX7D_LCDIF_PIXEL_ROOT_SRC] = imx_clk_mux2("lcdif_pixel_src", base + 0xa300, 24, 3, lcdif_pixel_sel, ARRAY_SIZE(lcdif_pixel_sel));
- clks[IMX7D_MIPI_DSI_ROOT_SRC] = imx_clk_mux2("mipi_dsi_src", base + 0xa380, 24, 3, mipi_dsi_sel, ARRAY_SIZE(mipi_dsi_sel));
- clks[IMX7D_MIPI_CSI_ROOT_SRC] = imx_clk_mux2("mipi_csi_src", base + 0xa400, 24, 3, mipi_csi_sel, ARRAY_SIZE(mipi_csi_sel));
- clks[IMX7D_MIPI_DPHY_ROOT_SRC] = imx_clk_mux2("mipi_dphy_src", base + 0xa480, 24, 3, mipi_dphy_sel, ARRAY_SIZE(mipi_dphy_sel));
- clks[IMX7D_SAI1_ROOT_SRC] = imx_clk_mux2("sai1_src", base + 0xa500, 24, 3, sai1_sel, ARRAY_SIZE(sai1_sel));
- clks[IMX7D_SAI2_ROOT_SRC] = imx_clk_mux2("sai2_src", base + 0xa580, 24, 3, sai2_sel, ARRAY_SIZE(sai2_sel));
- clks[IMX7D_SAI3_ROOT_SRC] = imx_clk_mux2("sai3_src", base + 0xa600, 24, 3, sai3_sel, ARRAY_SIZE(sai3_sel));
- clks[IMX7D_SPDIF_ROOT_SRC] = imx_clk_mux2("spdif_src", base + 0xa680, 24, 3, spdif_sel, ARRAY_SIZE(spdif_sel));
- clks[IMX7D_ENET1_REF_ROOT_SRC] = imx_clk_mux2("enet1_ref_src", base + 0xa700, 24, 3, enet1_ref_sel, ARRAY_SIZE(enet1_ref_sel));
- clks[IMX7D_ENET1_TIME_ROOT_SRC] = imx_clk_mux2("enet1_time_src", base + 0xa780, 24, 3, enet1_time_sel, ARRAY_SIZE(enet1_time_sel));
- clks[IMX7D_ENET2_REF_ROOT_SRC] = imx_clk_mux2("enet2_ref_src", base + 0xa800, 24, 3, enet2_ref_sel, ARRAY_SIZE(enet2_ref_sel));
- clks[IMX7D_ENET2_TIME_ROOT_SRC] = imx_clk_mux2("enet2_time_src", base + 0xa880, 24, 3, enet2_time_sel, ARRAY_SIZE(enet2_time_sel));
- clks[IMX7D_ENET_PHY_REF_ROOT_SRC] = imx_clk_mux2("enet_phy_ref_src", base + 0xa900, 24, 3, enet_phy_ref_sel, ARRAY_SIZE(enet_phy_ref_sel));
- clks[IMX7D_EIM_ROOT_SRC] = imx_clk_mux2("eim_src", base + 0xa980, 24, 3, eim_sel, ARRAY_SIZE(eim_sel));
- clks[IMX7D_NAND_ROOT_SRC] = imx_clk_mux2("nand_src", base + 0xaa00, 24, 3, nand_sel, ARRAY_SIZE(nand_sel));
- clks[IMX7D_QSPI_ROOT_SRC] = imx_clk_mux2("qspi_src", base + 0xaa80, 24, 3, qspi_sel, ARRAY_SIZE(qspi_sel));
- clks[IMX7D_USDHC1_ROOT_SRC] = imx_clk_mux2("usdhc1_src", base + 0xab00, 24, 3, usdhc1_sel, ARRAY_SIZE(usdhc1_sel));
- clks[IMX7D_USDHC2_ROOT_SRC] = imx_clk_mux2("usdhc2_src", base + 0xab80, 24, 3, usdhc2_sel, ARRAY_SIZE(usdhc2_sel));
- clks[IMX7D_USDHC3_ROOT_SRC] = imx_clk_mux2("usdhc3_src", base + 0xac00, 24, 3, usdhc3_sel, ARRAY_SIZE(usdhc3_sel));
- clks[IMX7D_CAN1_ROOT_SRC] = imx_clk_mux2("can1_src", base + 0xac80, 24, 3, can1_sel, ARRAY_SIZE(can1_sel));
- clks[IMX7D_CAN2_ROOT_SRC] = imx_clk_mux2("can2_src", base + 0xad00, 24, 3, can2_sel, ARRAY_SIZE(can2_sel));
- clks[IMX7D_I2C1_ROOT_SRC] = imx_clk_mux2("i2c1_src", base + 0xad80, 24, 3, i2c1_sel, ARRAY_SIZE(i2c1_sel));
- clks[IMX7D_I2C2_ROOT_SRC] = imx_clk_mux2("i2c2_src", base + 0xae00, 24, 3, i2c2_sel, ARRAY_SIZE(i2c2_sel));
- clks[IMX7D_I2C3_ROOT_SRC] = imx_clk_mux2("i2c3_src", base + 0xae80, 24, 3, i2c3_sel, ARRAY_SIZE(i2c3_sel));
- clks[IMX7D_I2C4_ROOT_SRC] = imx_clk_mux2("i2c4_src", base + 0xaf00, 24, 3, i2c4_sel, ARRAY_SIZE(i2c4_sel));
- clks[IMX7D_UART1_ROOT_SRC] = imx_clk_mux2("uart1_src", base + 0xaf80, 24, 3, uart1_sel, ARRAY_SIZE(uart1_sel));
- clks[IMX7D_UART2_ROOT_SRC] = imx_clk_mux2("uart2_src", base + 0xb000, 24, 3, uart2_sel, ARRAY_SIZE(uart2_sel));
- clks[IMX7D_UART3_ROOT_SRC] = imx_clk_mux2("uart3_src", base + 0xb080, 24, 3, uart3_sel, ARRAY_SIZE(uart3_sel));
- clks[IMX7D_UART4_ROOT_SRC] = imx_clk_mux2("uart4_src", base + 0xb100, 24, 3, uart4_sel, ARRAY_SIZE(uart4_sel));
- clks[IMX7D_UART5_ROOT_SRC] = imx_clk_mux2("uart5_src", base + 0xb180, 24, 3, uart5_sel, ARRAY_SIZE(uart5_sel));
- clks[IMX7D_UART6_ROOT_SRC] = imx_clk_mux2("uart6_src", base + 0xb200, 24, 3, uart6_sel, ARRAY_SIZE(uart6_sel));
- clks[IMX7D_UART7_ROOT_SRC] = imx_clk_mux2("uart7_src", base + 0xb280, 24, 3, uart7_sel, ARRAY_SIZE(uart7_sel));
- clks[IMX7D_ECSPI1_ROOT_SRC] = imx_clk_mux2("ecspi1_src", base + 0xb300, 24, 3, ecspi1_sel, ARRAY_SIZE(ecspi1_sel));
- clks[IMX7D_ECSPI2_ROOT_SRC] = imx_clk_mux2("ecspi2_src", base + 0xb380, 24, 3, ecspi2_sel, ARRAY_SIZE(ecspi2_sel));
- clks[IMX7D_ECSPI3_ROOT_SRC] = imx_clk_mux2("ecspi3_src", base + 0xb400, 24, 3, ecspi3_sel, ARRAY_SIZE(ecspi3_sel));
- clks[IMX7D_ECSPI4_ROOT_SRC] = imx_clk_mux2("ecspi4_src", base + 0xb480, 24, 3, ecspi4_sel, ARRAY_SIZE(ecspi4_sel));
- clks[IMX7D_PWM1_ROOT_SRC] = imx_clk_mux2("pwm1_src", base + 0xb500, 24, 3, pwm1_sel, ARRAY_SIZE(pwm1_sel));
- clks[IMX7D_PWM2_ROOT_SRC] = imx_clk_mux2("pwm2_src", base + 0xb580, 24, 3, pwm2_sel, ARRAY_SIZE(pwm2_sel));
- clks[IMX7D_PWM3_ROOT_SRC] = imx_clk_mux2("pwm3_src", base + 0xb600, 24, 3, pwm3_sel, ARRAY_SIZE(pwm3_sel));
- clks[IMX7D_PWM4_ROOT_SRC] = imx_clk_mux2("pwm4_src", base + 0xb680, 24, 3, pwm4_sel, ARRAY_SIZE(pwm4_sel));
- clks[IMX7D_FLEXTIMER1_ROOT_SRC] = imx_clk_mux2("flextimer1_src", base + 0xb700, 24, 3, flextimer1_sel, ARRAY_SIZE(flextimer1_sel));
- clks[IMX7D_FLEXTIMER2_ROOT_SRC] = imx_clk_mux2("flextimer2_src", base + 0xb780, 24, 3, flextimer2_sel, ARRAY_SIZE(flextimer2_sel));
- clks[IMX7D_SIM1_ROOT_SRC] = imx_clk_mux2("sim1_src", base + 0xb800, 24, 3, sim1_sel, ARRAY_SIZE(sim1_sel));
- clks[IMX7D_SIM2_ROOT_SRC] = imx_clk_mux2("sim2_src", base + 0xb880, 24, 3, sim2_sel, ARRAY_SIZE(sim2_sel));
- clks[IMX7D_GPT1_ROOT_SRC] = imx_clk_mux2("gpt1_src", base + 0xb900, 24, 3, gpt1_sel, ARRAY_SIZE(gpt1_sel));
- clks[IMX7D_GPT2_ROOT_SRC] = imx_clk_mux2("gpt2_src", base + 0xb980, 24, 3, gpt2_sel, ARRAY_SIZE(gpt2_sel));
- clks[IMX7D_GPT3_ROOT_SRC] = imx_clk_mux2("gpt3_src", base + 0xba00, 24, 3, gpt3_sel, ARRAY_SIZE(gpt3_sel));
- clks[IMX7D_GPT4_ROOT_SRC] = imx_clk_mux2("gpt4_src", base + 0xba80, 24, 3, gpt4_sel, ARRAY_SIZE(gpt4_sel));
- clks[IMX7D_TRACE_ROOT_SRC] = imx_clk_mux2("trace_src", base + 0xbb00, 24, 3, trace_sel, ARRAY_SIZE(trace_sel));
- clks[IMX7D_WDOG_ROOT_SRC] = imx_clk_mux2("wdog_src", base + 0xbb80, 24, 3, wdog_sel, ARRAY_SIZE(wdog_sel));
- clks[IMX7D_CSI_MCLK_ROOT_SRC] = imx_clk_mux2("csi_mclk_src", base + 0xbc00, 24, 3, csi_mclk_sel, ARRAY_SIZE(csi_mclk_sel));
- clks[IMX7D_AUDIO_MCLK_ROOT_SRC] = imx_clk_mux2("audio_mclk_src", base + 0xbc80, 24, 3, audio_mclk_sel, ARRAY_SIZE(audio_mclk_sel));
- clks[IMX7D_WRCLK_ROOT_SRC] = imx_clk_mux2("wrclk_src", base + 0xbd00, 24, 3, wrclk_sel, ARRAY_SIZE(wrclk_sel));
- clks[IMX7D_CLKO1_ROOT_SRC] = imx_clk_mux2("clko1_src", base + 0xbd80, 24, 3, clko1_sel, ARRAY_SIZE(clko1_sel));
- clks[IMX7D_CLKO2_ROOT_SRC] = imx_clk_mux2("clko2_src", base + 0xbe00, 24, 3, clko2_sel, ARRAY_SIZE(clko2_sel));
-
- clks[IMX7D_ARM_A7_ROOT_CG] = imx_clk_gate3("arm_a7_cg", "arm_a7_src", base + 0x8000, 28);
- clks[IMX7D_ARM_M4_ROOT_CG] = imx_clk_gate3("arm_m4_cg", "arm_m4_src", base + 0x8080, 28);
- clks[IMX7D_MAIN_AXI_ROOT_CG] = imx_clk_gate3("axi_cg", "axi_src", base + 0x8800, 28);
- clks[IMX7D_DISP_AXI_ROOT_CG] = imx_clk_gate3("disp_axi_cg", "disp_axi_src", base + 0x8880, 28);
- clks[IMX7D_ENET_AXI_ROOT_CG] = imx_clk_gate3("enet_axi_cg", "enet_axi_src", base + 0x8900, 28);
- clks[IMX7D_NAND_USDHC_BUS_ROOT_CG] = imx_clk_gate3("nand_usdhc_cg", "nand_usdhc_src", base + 0x8980, 28);
- clks[IMX7D_AHB_CHANNEL_ROOT_CG] = imx_clk_gate3("ahb_cg", "ahb_src", base + 0x9000, 28);
- clks[IMX7D_DRAM_PHYM_ROOT_CG] = imx_clk_gate3("dram_phym_cg", "dram_phym_src", base + 0x9800, 28);
- clks[IMX7D_DRAM_ROOT_CG] = imx_clk_gate3("dram_cg", "dram_src", base + 0x9880, 28);
- clks[IMX7D_DRAM_PHYM_ALT_ROOT_CG] = imx_clk_gate3("dram_phym_alt_cg", "dram_phym_alt_src", base + 0xa000, 28);
- clks[IMX7D_DRAM_ALT_ROOT_CG] = imx_clk_gate3("dram_alt_cg", "dram_alt_src", base + 0xa080, 28);
- clks[IMX7D_USB_HSIC_ROOT_CG] = imx_clk_gate3("usb_hsic_cg", "usb_hsic_src", base + 0xa100, 28);
- clks[IMX7D_PCIE_CTRL_ROOT_CG] = imx_clk_gate3("pcie_ctrl_cg", "pcie_ctrl_src", base + 0xa180, 28);
- clks[IMX7D_PCIE_PHY_ROOT_CG] = imx_clk_gate3("pcie_phy_cg", "pcie_phy_src", base + 0xa200, 28);
- clks[IMX7D_EPDC_PIXEL_ROOT_CG] = imx_clk_gate3("epdc_pixel_cg", "epdc_pixel_src", base + 0xa280, 28);
- clks[IMX7D_LCDIF_PIXEL_ROOT_CG] = imx_clk_gate3("lcdif_pixel_cg", "lcdif_pixel_src", base + 0xa300, 28);
- clks[IMX7D_MIPI_DSI_ROOT_CG] = imx_clk_gate3("mipi_dsi_cg", "mipi_dsi_src", base + 0xa380, 28);
- clks[IMX7D_MIPI_CSI_ROOT_CG] = imx_clk_gate3("mipi_csi_cg", "mipi_csi_src", base + 0xa400, 28);
- clks[IMX7D_MIPI_DPHY_ROOT_CG] = imx_clk_gate3("mipi_dphy_cg", "mipi_dphy_src", base + 0xa480, 28);
- clks[IMX7D_SAI1_ROOT_CG] = imx_clk_gate3("sai1_cg", "sai1_src", base + 0xa500, 28);
- clks[IMX7D_SAI2_ROOT_CG] = imx_clk_gate3("sai2_cg", "sai2_src", base + 0xa580, 28);
- clks[IMX7D_SAI3_ROOT_CG] = imx_clk_gate3("sai3_cg", "sai3_src", base + 0xa600, 28);
- clks[IMX7D_SPDIF_ROOT_CG] = imx_clk_gate3("spdif_cg", "spdif_src", base + 0xa680, 28);
- clks[IMX7D_ENET1_REF_ROOT_CG] = imx_clk_gate3("enet1_ref_cg", "enet1_ref_src", base + 0xa700, 28);
- clks[IMX7D_ENET1_TIME_ROOT_CG] = imx_clk_gate3("enet1_time_cg", "enet1_time_src", base + 0xa780, 28);
- clks[IMX7D_ENET2_REF_ROOT_CG] = imx_clk_gate3("enet2_ref_cg", "enet2_ref_src", base + 0xa800, 28);
- clks[IMX7D_ENET2_TIME_ROOT_CG] = imx_clk_gate3("enet2_time_cg", "enet2_time_src", base + 0xa880, 28);
- clks[IMX7D_ENET_PHY_REF_ROOT_CG] = imx_clk_gate3("enet_phy_ref_cg", "enet_phy_ref_src", base + 0xa900, 28);
- clks[IMX7D_EIM_ROOT_CG] = imx_clk_gate3("eim_cg", "eim_src", base + 0xa980, 28);
- clks[IMX7D_NAND_ROOT_CG] = imx_clk_gate3("nand_cg", "nand_src", base + 0xaa00, 28);
- clks[IMX7D_QSPI_ROOT_CG] = imx_clk_gate3("qspi_cg", "qspi_src", base + 0xaa80, 28);
- clks[IMX7D_USDHC1_ROOT_CG] = imx_clk_gate3("usdhc1_cg", "usdhc1_src", base + 0xab00, 28);
- clks[IMX7D_USDHC2_ROOT_CG] = imx_clk_gate3("usdhc2_cg", "usdhc2_src", base + 0xab80, 28);
- clks[IMX7D_USDHC3_ROOT_CG] = imx_clk_gate3("usdhc3_cg", "usdhc3_src", base + 0xac00, 28);
- clks[IMX7D_CAN1_ROOT_CG] = imx_clk_gate3("can1_cg", "can1_src", base + 0xac80, 28);
- clks[IMX7D_CAN2_ROOT_CG] = imx_clk_gate3("can2_cg", "can2_src", base + 0xad00, 28);
- clks[IMX7D_I2C1_ROOT_CG] = imx_clk_gate3("i2c1_cg", "i2c1_src", base + 0xad80, 28);
- clks[IMX7D_I2C2_ROOT_CG] = imx_clk_gate3("i2c2_cg", "i2c2_src", base + 0xae00, 28);
- clks[IMX7D_I2C3_ROOT_CG] = imx_clk_gate3("i2c3_cg", "i2c3_src", base + 0xae80, 28);
- clks[IMX7D_I2C4_ROOT_CG] = imx_clk_gate3("i2c4_cg", "i2c4_src", base + 0xaf00, 28);
- clks[IMX7D_UART1_ROOT_CG] = imx_clk_gate3("uart1_cg", "uart1_src", base + 0xaf80, 28);
- clks[IMX7D_UART2_ROOT_CG] = imx_clk_gate3("uart2_cg", "uart2_src", base + 0xb000, 28);
- clks[IMX7D_UART3_ROOT_CG] = imx_clk_gate3("uart3_cg", "uart3_src", base + 0xb080, 28);
- clks[IMX7D_UART4_ROOT_CG] = imx_clk_gate3("uart4_cg", "uart4_src", base + 0xb100, 28);
- clks[IMX7D_UART5_ROOT_CG] = imx_clk_gate3("uart5_cg", "uart5_src", base + 0xb180, 28);
- clks[IMX7D_UART6_ROOT_CG] = imx_clk_gate3("uart6_cg", "uart6_src", base + 0xb200, 28);
- clks[IMX7D_UART7_ROOT_CG] = imx_clk_gate3("uart7_cg", "uart7_src", base + 0xb280, 28);
- clks[IMX7D_ECSPI1_ROOT_CG] = imx_clk_gate3("ecspi1_cg", "ecspi1_src", base + 0xb300, 28);
- clks[IMX7D_ECSPI2_ROOT_CG] = imx_clk_gate3("ecspi2_cg", "ecspi2_src", base + 0xb380, 28);
- clks[IMX7D_ECSPI3_ROOT_CG] = imx_clk_gate3("ecspi3_cg", "ecspi3_src", base + 0xb400, 28);
- clks[IMX7D_ECSPI4_ROOT_CG] = imx_clk_gate3("ecspi4_cg", "ecspi4_src", base + 0xb480, 28);
- clks[IMX7D_PWM1_ROOT_CG] = imx_clk_gate3("pwm1_cg", "pwm1_src", base + 0xb500, 28);
- clks[IMX7D_PWM2_ROOT_CG] = imx_clk_gate3("pwm2_cg", "pwm2_src", base + 0xb580, 28);
- clks[IMX7D_PWM3_ROOT_CG] = imx_clk_gate3("pwm3_cg", "pwm3_src", base + 0xb600, 28);
- clks[IMX7D_PWM4_ROOT_CG] = imx_clk_gate3("pwm4_cg", "pwm4_src", base + 0xb680, 28);
- clks[IMX7D_FLEXTIMER1_ROOT_CG] = imx_clk_gate3("flextimer1_cg", "flextimer1_src", base + 0xb700, 28);
- clks[IMX7D_FLEXTIMER2_ROOT_CG] = imx_clk_gate3("flextimer2_cg", "flextimer2_src", base + 0xb780, 28);
- clks[IMX7D_SIM1_ROOT_CG] = imx_clk_gate3("sim1_cg", "sim1_src", base + 0xb800, 28);
- clks[IMX7D_SIM2_ROOT_CG] = imx_clk_gate3("sim2_cg", "sim2_src", base + 0xb880, 28);
- clks[IMX7D_GPT1_ROOT_CG] = imx_clk_gate3("gpt1_cg", "gpt1_src", base + 0xb900, 28);
- clks[IMX7D_GPT2_ROOT_CG] = imx_clk_gate3("gpt2_cg", "gpt2_src", base + 0xb980, 28);
- clks[IMX7D_GPT3_ROOT_CG] = imx_clk_gate3("gpt3_cg", "gpt3_src", base + 0xbA00, 28);
- clks[IMX7D_GPT4_ROOT_CG] = imx_clk_gate3("gpt4_cg", "gpt4_src", base + 0xbA80, 28);
- clks[IMX7D_TRACE_ROOT_CG] = imx_clk_gate3("trace_cg", "trace_src", base + 0xbb00, 28);
- clks[IMX7D_WDOG_ROOT_CG] = imx_clk_gate3("wdog_cg", "wdog_src", base + 0xbb80, 28);
- clks[IMX7D_CSI_MCLK_ROOT_CG] = imx_clk_gate3("csi_mclk_cg", "csi_mclk_src", base + 0xbc00, 28);
- clks[IMX7D_AUDIO_MCLK_ROOT_CG] = imx_clk_gate3("audio_mclk_cg", "audio_mclk_src", base + 0xbc80, 28);
- clks[IMX7D_WRCLK_ROOT_CG] = imx_clk_gate3("wrclk_cg", "wrclk_src", base + 0xbd00, 28);
- clks[IMX7D_CLKO1_ROOT_CG] = imx_clk_gate3("clko1_cg", "clko1_src", base + 0xbd80, 28);
- clks[IMX7D_CLKO2_ROOT_CG] = imx_clk_gate3("clko2_cg", "clko2_src", base + 0xbe00, 28);
-
- clks[IMX7D_MAIN_AXI_ROOT_PRE_DIV] = imx_clk_divider2("axi_pre_div", "axi_cg", base + 0x8800, 16, 3);
- clks[IMX7D_DISP_AXI_ROOT_PRE_DIV] = imx_clk_divider2("disp_axi_pre_div", "disp_axi_cg", base + 0x8880, 16, 3);
- clks[IMX7D_ENET_AXI_ROOT_PRE_DIV] = imx_clk_divider2("enet_axi_pre_div", "enet_axi_cg", base + 0x8900, 16, 3);
- clks[IMX7D_NAND_USDHC_BUS_ROOT_PRE_DIV] = imx_clk_divider2("nand_usdhc_pre_div", "nand_usdhc_cg", base + 0x8980, 16, 3);
- clks[IMX7D_AHB_CHANNEL_ROOT_PRE_DIV] = imx_clk_divider2("ahb_pre_div", "ahb_cg", base + 0x9000, 16, 3);
- clks[IMX7D_DRAM_PHYM_ALT_ROOT_PRE_DIV] = imx_clk_divider2("dram_phym_alt_pre_div", "dram_phym_alt_cg", base + 0xa000, 16, 3);
- clks[IMX7D_DRAM_ALT_ROOT_PRE_DIV] = imx_clk_divider2("dram_alt_pre_div", "dram_alt_cg", base + 0xa080, 16, 3);
- clks[IMX7D_USB_HSIC_ROOT_PRE_DIV] = imx_clk_divider2("usb_hsic_pre_div", "usb_hsic_cg", base + 0xa100, 16, 3);
- clks[IMX7D_PCIE_CTRL_ROOT_PRE_DIV] = imx_clk_divider2("pcie_ctrl_pre_div", "pcie_ctrl_cg", base + 0xa180, 16, 3);
- clks[IMX7D_PCIE_PHY_ROOT_PRE_DIV] = imx_clk_divider2("pcie_phy_pre_div", "pcie_phy_cg", base + 0xa200, 16, 3);
- clks[IMX7D_EPDC_PIXEL_ROOT_PRE_DIV] = imx_clk_divider2("epdc_pixel_pre_div", "epdc_pixel_cg", base + 0xa280, 16, 3);
- clks[IMX7D_LCDIF_PIXEL_ROOT_PRE_DIV] = imx_clk_divider2("lcdif_pixel_pre_div", "lcdif_pixel_cg", base + 0xa300, 16, 3);
- clks[IMX7D_MIPI_DSI_ROOT_PRE_DIV] = imx_clk_divider2("mipi_dsi_pre_div", "mipi_dsi_cg", base + 0xa380, 16, 3);
- clks[IMX7D_MIPI_CSI_ROOT_PRE_DIV] = imx_clk_divider2("mipi_csi_pre_div", "mipi_csi_cg", base + 0xa400, 16, 3);
- clks[IMX7D_MIPI_DPHY_ROOT_PRE_DIV] = imx_clk_divider2("mipi_dphy_pre_div", "mipi_dphy_cg", base + 0xa480, 16, 3);
- clks[IMX7D_SAI1_ROOT_PRE_DIV] = imx_clk_divider2("sai1_pre_div", "sai1_cg", base + 0xa500, 16, 3);
- clks[IMX7D_SAI2_ROOT_PRE_DIV] = imx_clk_divider2("sai2_pre_div", "sai2_cg", base + 0xa580, 16, 3);
- clks[IMX7D_SAI3_ROOT_PRE_DIV] = imx_clk_divider2("sai3_pre_div", "sai3_cg", base + 0xa600, 16, 3);
- clks[IMX7D_SPDIF_ROOT_PRE_DIV] = imx_clk_divider2("spdif_pre_div", "spdif_cg", base + 0xa680, 16, 3);
- clks[IMX7D_ENET1_REF_ROOT_PRE_DIV] = imx_clk_divider2("enet1_ref_pre_div", "enet1_ref_cg", base + 0xa700, 16, 3);
- clks[IMX7D_ENET1_TIME_ROOT_PRE_DIV] = imx_clk_divider2("enet1_time_pre_div", "enet1_time_cg", base + 0xa780, 16, 3);
- clks[IMX7D_ENET2_REF_ROOT_PRE_DIV] = imx_clk_divider2("enet2_ref_pre_div", "enet2_ref_cg", base + 0xa800, 16, 3);
- clks[IMX7D_ENET2_TIME_ROOT_PRE_DIV] = imx_clk_divider2("enet2_time_pre_div", "enet2_time_cg", base + 0xa880, 16, 3);
- clks[IMX7D_ENET_PHY_REF_ROOT_PRE_DIV] = imx_clk_divider2("enet_phy_ref_pre_div", "enet_phy_ref_cg", base + 0xa900, 16, 3);
- clks[IMX7D_EIM_ROOT_PRE_DIV] = imx_clk_divider2("eim_pre_div", "eim_cg", base + 0xa980, 16, 3);
- clks[IMX7D_NAND_ROOT_PRE_DIV] = imx_clk_divider2("nand_pre_div", "nand_cg", base + 0xaa00, 16, 3);
- clks[IMX7D_QSPI_ROOT_PRE_DIV] = imx_clk_divider2("qspi_pre_div", "qspi_cg", base + 0xaa80, 16, 3);
- clks[IMX7D_USDHC1_ROOT_PRE_DIV] = imx_clk_divider2("usdhc1_pre_div", "usdhc1_cg", base + 0xab00, 16, 3);
- clks[IMX7D_USDHC2_ROOT_PRE_DIV] = imx_clk_divider2("usdhc2_pre_div", "usdhc2_cg", base + 0xab80, 16, 3);
- clks[IMX7D_USDHC3_ROOT_PRE_DIV] = imx_clk_divider2("usdhc3_pre_div", "usdhc3_cg", base + 0xac00, 16, 3);
- clks[IMX7D_CAN1_ROOT_PRE_DIV] = imx_clk_divider2("can1_pre_div", "can1_cg", base + 0xac80, 16, 3);
- clks[IMX7D_CAN2_ROOT_PRE_DIV] = imx_clk_divider2("can2_pre_div", "can2_cg", base + 0xad00, 16, 3);
- clks[IMX7D_I2C1_ROOT_PRE_DIV] = imx_clk_divider2("i2c1_pre_div", "i2c1_cg", base + 0xad80, 16, 3);
- clks[IMX7D_I2C2_ROOT_PRE_DIV] = imx_clk_divider2("i2c2_pre_div", "i2c2_cg", base + 0xae00, 16, 3);
- clks[IMX7D_I2C3_ROOT_PRE_DIV] = imx_clk_divider2("i2c3_pre_div", "i2c3_cg", base + 0xae80, 16, 3);
- clks[IMX7D_I2C4_ROOT_PRE_DIV] = imx_clk_divider2("i2c4_pre_div", "i2c4_cg", base + 0xaf00, 16, 3);
- clks[IMX7D_UART1_ROOT_PRE_DIV] = imx_clk_divider2("uart1_pre_div", "uart1_cg", base + 0xaf80, 16, 3);
- clks[IMX7D_UART2_ROOT_PRE_DIV] = imx_clk_divider2("uart2_pre_div", "uart2_cg", base + 0xb000, 16, 3);
- clks[IMX7D_UART3_ROOT_PRE_DIV] = imx_clk_divider2("uart3_pre_div", "uart3_cg", base + 0xb080, 16, 3);
- clks[IMX7D_UART4_ROOT_PRE_DIV] = imx_clk_divider2("uart4_pre_div", "uart4_cg", base + 0xb100, 16, 3);
- clks[IMX7D_UART5_ROOT_PRE_DIV] = imx_clk_divider2("uart5_pre_div", "uart5_cg", base + 0xb180, 16, 3);
- clks[IMX7D_UART6_ROOT_PRE_DIV] = imx_clk_divider2("uart6_pre_div", "uart6_cg", base + 0xb200, 16, 3);
- clks[IMX7D_UART7_ROOT_PRE_DIV] = imx_clk_divider2("uart7_pre_div", "uart7_cg", base + 0xb280, 16, 3);
- clks[IMX7D_ECSPI1_ROOT_PRE_DIV] = imx_clk_divider2("ecspi1_pre_div", "ecspi1_cg", base + 0xb300, 16, 3);
- clks[IMX7D_ECSPI2_ROOT_PRE_DIV] = imx_clk_divider2("ecspi2_pre_div", "ecspi2_cg", base + 0xb380, 16, 3);
- clks[IMX7D_ECSPI3_ROOT_PRE_DIV] = imx_clk_divider2("ecspi3_pre_div", "ecspi3_cg", base + 0xb400, 16, 3);
- clks[IMX7D_ECSPI4_ROOT_PRE_DIV] = imx_clk_divider2("ecspi4_pre_div", "ecspi4_cg", base + 0xb480, 16, 3);
- clks[IMX7D_PWM1_ROOT_PRE_DIV] = imx_clk_divider2("pwm1_pre_div", "pwm1_cg", base + 0xb500, 16, 3);
- clks[IMX7D_PWM2_ROOT_PRE_DIV] = imx_clk_divider2("pwm2_pre_div", "pwm2_cg", base + 0xb580, 16, 3);
- clks[IMX7D_PWM3_ROOT_PRE_DIV] = imx_clk_divider2("pwm3_pre_div", "pwm3_cg", base + 0xb600, 16, 3);
- clks[IMX7D_PWM4_ROOT_PRE_DIV] = imx_clk_divider2("pwm4_pre_div", "pwm4_cg", base + 0xb680, 16, 3);
- clks[IMX7D_FLEXTIMER1_ROOT_PRE_DIV] = imx_clk_divider2("flextimer1_pre_div", "flextimer1_cg", base + 0xb700, 16, 3);
- clks[IMX7D_FLEXTIMER2_ROOT_PRE_DIV] = imx_clk_divider2("flextimer2_pre_div", "flextimer2_cg", base + 0xb780, 16, 3);
- clks[IMX7D_SIM1_ROOT_PRE_DIV] = imx_clk_divider2("sim1_pre_div", "sim1_cg", base + 0xb800, 16, 3);
- clks[IMX7D_SIM2_ROOT_PRE_DIV] = imx_clk_divider2("sim2_pre_div", "sim2_cg", base + 0xb880, 16, 3);
- clks[IMX7D_GPT1_ROOT_PRE_DIV] = imx_clk_divider2("gpt1_pre_div", "gpt1_cg", base + 0xb900, 16, 3);
- clks[IMX7D_GPT2_ROOT_PRE_DIV] = imx_clk_divider2("gpt2_pre_div", "gpt2_cg", base + 0xb980, 16, 3);
- clks[IMX7D_GPT3_ROOT_PRE_DIV] = imx_clk_divider2("gpt3_pre_div", "gpt3_cg", base + 0xba00, 16, 3);
- clks[IMX7D_GPT4_ROOT_PRE_DIV] = imx_clk_divider2("gpt4_pre_div", "gpt4_cg", base + 0xba80, 16, 3);
- clks[IMX7D_TRACE_ROOT_PRE_DIV] = imx_clk_divider2("trace_pre_div", "trace_cg", base + 0xbb00, 16, 3);
- clks[IMX7D_WDOG_ROOT_PRE_DIV] = imx_clk_divider2("wdog_pre_div", "wdog_cg", base + 0xbb80, 16, 3);
- clks[IMX7D_CSI_MCLK_ROOT_PRE_DIV] = imx_clk_divider2("csi_mclk_pre_div", "csi_mclk_cg", base + 0xbc00, 16, 3);
- clks[IMX7D_AUDIO_MCLK_ROOT_PRE_DIV] = imx_clk_divider2("audio_mclk_pre_div", "audio_mclk_cg", base + 0xbc80, 16, 3);
- clks[IMX7D_WRCLK_ROOT_PRE_DIV] = imx_clk_divider2("wrclk_pre_div", "wrclk_cg", base + 0xbd00, 16, 3);
- clks[IMX7D_CLKO1_ROOT_PRE_DIV] = imx_clk_divider2("clko1_pre_div", "clko1_cg", base + 0xbd80, 16, 3);
- clks[IMX7D_CLKO2_ROOT_PRE_DIV] = imx_clk_divider2("clko2_pre_div", "clko2_cg", base + 0xbe00, 16, 3);
-
- clks[IMX7D_ARM_A7_ROOT_DIV] = imx_clk_divider2("arm_a7_div", "arm_a7_cg", base + 0x8000, 0, 3);
- clks[IMX7D_ARM_M4_ROOT_DIV] = imx_clk_divider2("arm_m4_div", "arm_m4_cg", base + 0x8080, 0, 3);
- clks[IMX7D_MAIN_AXI_ROOT_DIV] = imx_clk_divider2("axi_post_div", "axi_pre_div", base + 0x8800, 0, 6);
- clks[IMX7D_DISP_AXI_ROOT_DIV] = imx_clk_divider2("disp_axi_post_div", "disp_axi_pre_div", base + 0x8880, 0, 6);
- clks[IMX7D_ENET_AXI_ROOT_DIV] = imx_clk_divider2("enet_axi_post_div", "enet_axi_pre_div", base + 0x8900, 0, 6);
- clks[IMX7D_NAND_USDHC_BUS_ROOT_CLK] = imx_clk_divider2("nand_usdhc_root_clk", "nand_usdhc_pre_div", base + 0x8980, 0, 6);
- clks[IMX7D_AHB_CHANNEL_ROOT_DIV] = imx_clk_divider2("ahb_root_clk", "ahb_pre_div", base + 0x9000, 0, 6);
- clks[IMX7D_IPG_ROOT_CLK] = imx_clk_divider_flags("ipg_root_clk", "ahb_root_clk", base + 0x9080, 0, 2, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE | CLK_SET_RATE_PARENT);
- clks[IMX7D_DRAM_ROOT_DIV] = imx_clk_divider2("dram_post_div", "dram_cg", base + 0x9880, 0, 3);
- clks[IMX7D_DRAM_PHYM_ALT_ROOT_DIV] = imx_clk_divider2("dram_phym_alt_post_div", "dram_phym_alt_pre_div", base + 0xa000, 0, 3);
- clks[IMX7D_DRAM_ALT_ROOT_DIV] = imx_clk_divider2("dram_alt_post_div", "dram_alt_pre_div", base + 0xa080, 0, 3);
- clks[IMX7D_USB_HSIC_ROOT_DIV] = imx_clk_divider2("usb_hsic_post_div", "usb_hsic_pre_div", base + 0xa100, 0, 6);
- clks[IMX7D_PCIE_CTRL_ROOT_DIV] = imx_clk_divider2("pcie_ctrl_post_div", "pcie_ctrl_pre_div", base + 0xa180, 0, 6);
- clks[IMX7D_PCIE_PHY_ROOT_DIV] = imx_clk_divider2("pcie_phy_post_div", "pcie_phy_pre_div", base + 0xa200, 0, 6);
- clks[IMX7D_EPDC_PIXEL_ROOT_DIV] = imx_clk_divider2("epdc_pixel_post_div", "epdc_pixel_pre_div", base + 0xa280, 0, 6);
- clks[IMX7D_LCDIF_PIXEL_ROOT_DIV] = imx_clk_divider2("lcdif_pixel_post_div", "lcdif_pixel_pre_div", base + 0xa300, 0, 6);
- clks[IMX7D_MIPI_DSI_ROOT_DIV] = imx_clk_divider2("mipi_dsi_post_div", "mipi_dsi_pre_div", base + 0xa380, 0, 6);
- clks[IMX7D_MIPI_CSI_ROOT_DIV] = imx_clk_divider2("mipi_csi_post_div", "mipi_csi_pre_div", base + 0xa400, 0, 6);
- clks[IMX7D_MIPI_DPHY_ROOT_DIV] = imx_clk_divider2("mipi_dphy_post_div", "mipi_dphy_pre_div", base + 0xa480, 0, 6);
- clks[IMX7D_SAI1_ROOT_DIV] = imx_clk_divider2("sai1_post_div", "sai1_pre_div", base + 0xa500, 0, 6);
- clks[IMX7D_SAI2_ROOT_DIV] = imx_clk_divider2("sai2_post_div", "sai2_pre_div", base + 0xa580, 0, 6);
- clks[IMX7D_SAI3_ROOT_DIV] = imx_clk_divider2("sai3_post_div", "sai3_pre_div", base + 0xa600, 0, 6);
- clks[IMX7D_SPDIF_ROOT_DIV] = imx_clk_divider2("spdif_post_div", "spdif_pre_div", base + 0xa680, 0, 6);
- clks[IMX7D_ENET1_REF_ROOT_DIV] = imx_clk_divider2("enet1_ref_post_div", "enet1_ref_pre_div", base + 0xa700, 0, 6);
- clks[IMX7D_ENET1_TIME_ROOT_DIV] = imx_clk_divider2("enet1_time_post_div", "enet1_time_pre_div", base + 0xa780, 0, 6);
- clks[IMX7D_ENET2_REF_ROOT_DIV] = imx_clk_divider2("enet2_ref_post_div", "enet2_ref_pre_div", base + 0xa800, 0, 6);
- clks[IMX7D_ENET2_TIME_ROOT_DIV] = imx_clk_divider2("enet2_time_post_div", "enet2_time_pre_div", base + 0xa880, 0, 6);
- clks[IMX7D_ENET_PHY_REF_ROOT_CLK] = imx_clk_divider2("enet_phy_ref_root_clk", "enet_phy_ref_pre_div", base + 0xa900, 0, 6);
- clks[IMX7D_EIM_ROOT_DIV] = imx_clk_divider2("eim_post_div", "eim_pre_div", base + 0xa980, 0, 6);
- clks[IMX7D_NAND_ROOT_CLK] = imx_clk_divider2("nand_root_clk", "nand_pre_div", base + 0xaa00, 0, 6);
- clks[IMX7D_QSPI_ROOT_DIV] = imx_clk_divider2("qspi_post_div", "qspi_pre_div", base + 0xaa80, 0, 6);
- clks[IMX7D_USDHC1_ROOT_DIV] = imx_clk_divider2("usdhc1_post_div", "usdhc1_pre_div", base + 0xab00, 0, 6);
- clks[IMX7D_USDHC2_ROOT_DIV] = imx_clk_divider2("usdhc2_post_div", "usdhc2_pre_div", base + 0xab80, 0, 6);
- clks[IMX7D_USDHC3_ROOT_DIV] = imx_clk_divider2("usdhc3_post_div", "usdhc3_pre_div", base + 0xac00, 0, 6);
- clks[IMX7D_CAN1_ROOT_DIV] = imx_clk_divider2("can1_post_div", "can1_pre_div", base + 0xac80, 0, 6);
- clks[IMX7D_CAN2_ROOT_DIV] = imx_clk_divider2("can2_post_div", "can2_pre_div", base + 0xad00, 0, 6);
- clks[IMX7D_I2C1_ROOT_DIV] = imx_clk_divider2("i2c1_post_div", "i2c1_pre_div", base + 0xad80, 0, 6);
- clks[IMX7D_I2C2_ROOT_DIV] = imx_clk_divider2("i2c2_post_div", "i2c2_pre_div", base + 0xae00, 0, 6);
- clks[IMX7D_I2C3_ROOT_DIV] = imx_clk_divider2("i2c3_post_div", "i2c3_pre_div", base + 0xae80, 0, 6);
- clks[IMX7D_I2C4_ROOT_DIV] = imx_clk_divider2("i2c4_post_div", "i2c4_pre_div", base + 0xaf00, 0, 6);
- clks[IMX7D_UART1_ROOT_DIV] = imx_clk_divider2("uart1_post_div", "uart1_pre_div", base + 0xaf80, 0, 6);
- clks[IMX7D_UART2_ROOT_DIV] = imx_clk_divider2("uart2_post_div", "uart2_pre_div", base + 0xb000, 0, 6);
- clks[IMX7D_UART3_ROOT_DIV] = imx_clk_divider2("uart3_post_div", "uart3_pre_div", base + 0xb080, 0, 6);
- clks[IMX7D_UART4_ROOT_DIV] = imx_clk_divider2("uart4_post_div", "uart4_pre_div", base + 0xb100, 0, 6);
- clks[IMX7D_UART5_ROOT_DIV] = imx_clk_divider2("uart5_post_div", "uart5_pre_div", base + 0xb180, 0, 6);
- clks[IMX7D_UART6_ROOT_DIV] = imx_clk_divider2("uart6_post_div", "uart6_pre_div", base + 0xb200, 0, 6);
- clks[IMX7D_UART7_ROOT_DIV] = imx_clk_divider2("uart7_post_div", "uart7_pre_div", base + 0xb280, 0, 6);
- clks[IMX7D_ECSPI1_ROOT_DIV] = imx_clk_divider2("ecspi1_post_div", "ecspi1_pre_div", base + 0xb300, 0, 6);
- clks[IMX7D_ECSPI2_ROOT_DIV] = imx_clk_divider2("ecspi2_post_div", "ecspi2_pre_div", base + 0xb380, 0, 6);
- clks[IMX7D_ECSPI3_ROOT_DIV] = imx_clk_divider2("ecspi3_post_div", "ecspi3_pre_div", base + 0xb400, 0, 6);
- clks[IMX7D_ECSPI4_ROOT_DIV] = imx_clk_divider2("ecspi4_post_div", "ecspi4_pre_div", base + 0xb480, 0, 6);
- clks[IMX7D_PWM1_ROOT_DIV] = imx_clk_divider2("pwm1_post_div", "pwm1_pre_div", base + 0xb500, 0, 6);
- clks[IMX7D_PWM2_ROOT_DIV] = imx_clk_divider2("pwm2_post_div", "pwm2_pre_div", base + 0xb580, 0, 6);
- clks[IMX7D_PWM3_ROOT_DIV] = imx_clk_divider2("pwm3_post_div", "pwm3_pre_div", base + 0xb600, 0, 6);
- clks[IMX7D_PWM4_ROOT_DIV] = imx_clk_divider2("pwm4_post_div", "pwm4_pre_div", base + 0xb680, 0, 6);
- clks[IMX7D_FLEXTIMER1_ROOT_DIV] = imx_clk_divider2("flextimer1_post_div", "flextimer1_pre_div", base + 0xb700, 0, 6);
- clks[IMX7D_FLEXTIMER2_ROOT_DIV] = imx_clk_divider2("flextimer2_post_div", "flextimer2_pre_div", base + 0xb780, 0, 6);
- clks[IMX7D_SIM1_ROOT_DIV] = imx_clk_divider2("sim1_post_div", "sim1_pre_div", base + 0xb800, 0, 6);
- clks[IMX7D_SIM2_ROOT_DIV] = imx_clk_divider2("sim2_post_div", "sim2_pre_div", base + 0xb880, 0, 6);
- clks[IMX7D_GPT1_ROOT_DIV] = imx_clk_divider2("gpt1_post_div", "gpt1_pre_div", base + 0xb900, 0, 6);
- clks[IMX7D_GPT2_ROOT_DIV] = imx_clk_divider2("gpt2_post_div", "gpt2_pre_div", base + 0xb980, 0, 6);
- clks[IMX7D_GPT3_ROOT_DIV] = imx_clk_divider2("gpt3_post_div", "gpt3_pre_div", base + 0xba00, 0, 6);
- clks[IMX7D_GPT4_ROOT_DIV] = imx_clk_divider2("gpt4_post_div", "gpt4_pre_div", base + 0xba80, 0, 6);
- clks[IMX7D_TRACE_ROOT_DIV] = imx_clk_divider2("trace_post_div", "trace_pre_div", base + 0xbb00, 0, 6);
- clks[IMX7D_WDOG_ROOT_DIV] = imx_clk_divider2("wdog_post_div", "wdog_pre_div", base + 0xbb80, 0, 6);
- clks[IMX7D_CSI_MCLK_ROOT_DIV] = imx_clk_divider2("csi_mclk_post_div", "csi_mclk_pre_div", base + 0xbc00, 0, 6);
- clks[IMX7D_AUDIO_MCLK_ROOT_DIV] = imx_clk_divider2("audio_mclk_post_div", "audio_mclk_pre_div", base + 0xbc80, 0, 6);
- clks[IMX7D_WRCLK_ROOT_DIV] = imx_clk_divider2("wrclk_post_div", "wrclk_pre_div", base + 0xbd00, 0, 6);
- clks[IMX7D_CLKO1_ROOT_DIV] = imx_clk_divider2("clko1_post_div", "clko1_pre_div", base + 0xbd80, 0, 6);
- clks[IMX7D_CLKO2_ROOT_DIV] = imx_clk_divider2("clko2_post_div", "clko2_pre_div", base + 0xbe00, 0, 6);
-
- clks[IMX7D_ARM_A7_ROOT_CLK] = imx_clk_gate2_flags("arm_a7_root_clk", "arm_a7_div", base + 0x4000, 0, CLK_OPS_PARENT_ENABLE);
- clks[IMX7D_ARM_M4_ROOT_CLK] = imx_clk_gate4("arm_m4_root_clk", "arm_m4_div", base + 0x4010, 0);
- clks[IMX7D_MAIN_AXI_ROOT_CLK] = imx_clk_gate2_flags("main_axi_root_clk", "axi_post_div", base + 0x4040, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
- clks[IMX7D_DISP_AXI_ROOT_CLK] = imx_clk_gate4("disp_axi_root_clk", "disp_axi_post_div", base + 0x4050, 0);
- clks[IMX7D_ENET_AXI_ROOT_CLK] = imx_clk_gate4("enet_axi_root_clk", "enet_axi_post_div", base + 0x4060, 0);
- clks[IMX7D_OCRAM_CLK] = imx_clk_gate4("ocram_clk", "main_axi_root_clk", base + 0x4110, 0);
- clks[IMX7D_OCRAM_S_CLK] = imx_clk_gate4("ocram_s_clk", "ahb_root_clk", base + 0x4120, 0);
- clks[IMX7D_DRAM_ROOT_CLK] = imx_clk_gate2_flags("dram_root_clk", "dram_post_div", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
- clks[IMX7D_DRAM_PHYM_ROOT_CLK] = imx_clk_gate2_flags("dram_phym_root_clk", "dram_phym_cg", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
- clks[IMX7D_DRAM_PHYM_ALT_ROOT_CLK] = imx_clk_gate2_flags("dram_phym_alt_root_clk", "dram_phym_alt_post_div", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
- clks[IMX7D_DRAM_ALT_ROOT_CLK] = imx_clk_gate2_flags("dram_alt_root_clk", "dram_alt_post_div", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
- clks[IMX7D_OCOTP_CLK] = imx_clk_gate4("ocotp_clk", "ipg_root_clk", base + 0x4230, 0);
- clks[IMX7D_SNVS_CLK] = imx_clk_gate4("snvs_clk", "ipg_root_clk", base + 0x4250, 0);
- clks[IMX7D_MU_ROOT_CLK] = imx_clk_gate4("mu_root_clk", "ipg_root_clk", base + 0x4270, 0);
- clks[IMX7D_CAAM_CLK] = imx_clk_gate4("caam_clk", "ipg_root_clk", base + 0x4240, 0);
- clks[IMX7D_USB_HSIC_ROOT_CLK] = imx_clk_gate4("usb_hsic_root_clk", "usb_hsic_post_div", base + 0x4690, 0);
- clks[IMX7D_SDMA_CORE_CLK] = imx_clk_gate4("sdma_root_clk", "ahb_root_clk", base + 0x4480, 0);
- clks[IMX7D_PCIE_CTRL_ROOT_CLK] = imx_clk_gate4("pcie_ctrl_root_clk", "pcie_ctrl_post_div", base + 0x4600, 0);
- clks[IMX7D_PCIE_PHY_ROOT_CLK] = imx_clk_gate4("pcie_phy_root_clk", "pcie_phy_post_div", base + 0x4600, 0);
- clks[IMX7D_EPDC_PIXEL_ROOT_CLK] = imx_clk_gate4("epdc_pixel_root_clk", "epdc_pixel_post_div", base + 0x44a0, 0);
- clks[IMX7D_LCDIF_PIXEL_ROOT_CLK] = imx_clk_gate4("lcdif_pixel_root_clk", "lcdif_pixel_post_div", base + 0x44b0, 0);
- clks[IMX7D_MIPI_DSI_ROOT_CLK] = imx_clk_gate4("mipi_dsi_root_clk", "mipi_dsi_post_div", base + 0x4650, 0);
- clks[IMX7D_MIPI_CSI_ROOT_CLK] = imx_clk_gate4("mipi_csi_root_clk", "mipi_csi_post_div", base + 0x4640, 0);
- clks[IMX7D_MIPI_DPHY_ROOT_CLK] = imx_clk_gate4("mipi_dphy_root_clk", "mipi_dphy_post_div", base + 0x4660, 0);
- clks[IMX7D_ENET1_IPG_ROOT_CLK] = imx_clk_gate2_shared2("enet1_ipg_root_clk", "enet_axi_post_div", base + 0x4700, 0, &share_count_enet1);
- clks[IMX7D_ENET1_TIME_ROOT_CLK] = imx_clk_gate2_shared2("enet1_time_root_clk", "enet1_time_post_div", base + 0x4700, 0, &share_count_enet1);
- clks[IMX7D_ENET2_IPG_ROOT_CLK] = imx_clk_gate2_shared2("enet2_ipg_root_clk", "enet_axi_post_div", base + 0x4710, 0, &share_count_enet2);
- clks[IMX7D_ENET2_TIME_ROOT_CLK] = imx_clk_gate2_shared2("enet2_time_root_clk", "enet2_time_post_div", base + 0x4710, 0, &share_count_enet2);
- clks[IMX7D_SAI1_ROOT_CLK] = imx_clk_gate2_shared2("sai1_root_clk", "sai1_post_div", base + 0x48c0, 0, &share_count_sai1);
- clks[IMX7D_SAI1_IPG_CLK] = imx_clk_gate2_shared2("sai1_ipg_clk", "ipg_root_clk", base + 0x48c0, 0, &share_count_sai1);
- clks[IMX7D_SAI2_ROOT_CLK] = imx_clk_gate2_shared2("sai2_root_clk", "sai2_post_div", base + 0x48d0, 0, &share_count_sai2);
- clks[IMX7D_SAI2_IPG_CLK] = imx_clk_gate2_shared2("sai2_ipg_clk", "ipg_root_clk", base + 0x48d0, 0, &share_count_sai2);
- clks[IMX7D_SAI3_ROOT_CLK] = imx_clk_gate2_shared2("sai3_root_clk", "sai3_post_div", base + 0x48e0, 0, &share_count_sai3);
- clks[IMX7D_SAI3_IPG_CLK] = imx_clk_gate2_shared2("sai3_ipg_clk", "ipg_root_clk", base + 0x48e0, 0, &share_count_sai3);
- clks[IMX7D_SPDIF_ROOT_CLK] = imx_clk_gate4("spdif_root_clk", "spdif_post_div", base + 0x44d0, 0);
- clks[IMX7D_EIM_ROOT_CLK] = imx_clk_gate4("eim_root_clk", "eim_post_div", base + 0x4160, 0);
- clks[IMX7D_NAND_RAWNAND_CLK] = imx_clk_gate2_shared2("nand_rawnand_clk", "nand_root_clk", base + 0x4140, 0, &share_count_nand);
- clks[IMX7D_NAND_USDHC_BUS_RAWNAND_CLK] = imx_clk_gate2_shared2("nand_usdhc_rawnand_clk", "nand_usdhc_root_clk", base + 0x4140, 0, &share_count_nand);
- clks[IMX7D_QSPI_ROOT_CLK] = imx_clk_gate4("qspi_root_clk", "qspi_post_div", base + 0x4150, 0);
- clks[IMX7D_USDHC1_ROOT_CLK] = imx_clk_gate4("usdhc1_root_clk", "usdhc1_post_div", base + 0x46c0, 0);
- clks[IMX7D_USDHC2_ROOT_CLK] = imx_clk_gate4("usdhc2_root_clk", "usdhc2_post_div", base + 0x46d0, 0);
- clks[IMX7D_USDHC3_ROOT_CLK] = imx_clk_gate4("usdhc3_root_clk", "usdhc3_post_div", base + 0x46e0, 0);
- clks[IMX7D_CAN1_ROOT_CLK] = imx_clk_gate4("can1_root_clk", "can1_post_div", base + 0x4740, 0);
- clks[IMX7D_CAN2_ROOT_CLK] = imx_clk_gate4("can2_root_clk", "can2_post_div", base + 0x4750, 0);
- clks[IMX7D_I2C1_ROOT_CLK] = imx_clk_gate4("i2c1_root_clk", "i2c1_post_div", base + 0x4880, 0);
- clks[IMX7D_I2C2_ROOT_CLK] = imx_clk_gate4("i2c2_root_clk", "i2c2_post_div", base + 0x4890, 0);
- clks[IMX7D_I2C3_ROOT_CLK] = imx_clk_gate4("i2c3_root_clk", "i2c3_post_div", base + 0x48a0, 0);
- clks[IMX7D_I2C4_ROOT_CLK] = imx_clk_gate4("i2c4_root_clk", "i2c4_post_div", base + 0x48b0, 0);
- clks[IMX7D_UART1_ROOT_CLK] = imx_clk_gate4("uart1_root_clk", "uart1_post_div", base + 0x4940, 0);
- clks[IMX7D_UART2_ROOT_CLK] = imx_clk_gate4("uart2_root_clk", "uart2_post_div", base + 0x4950, 0);
- clks[IMX7D_UART3_ROOT_CLK] = imx_clk_gate4("uart3_root_clk", "uart3_post_div", base + 0x4960, 0);
- clks[IMX7D_UART4_ROOT_CLK] = imx_clk_gate4("uart4_root_clk", "uart4_post_div", base + 0x4970, 0);
- clks[IMX7D_UART5_ROOT_CLK] = imx_clk_gate4("uart5_root_clk", "uart5_post_div", base + 0x4980, 0);
- clks[IMX7D_UART6_ROOT_CLK] = imx_clk_gate4("uart6_root_clk", "uart6_post_div", base + 0x4990, 0);
- clks[IMX7D_UART7_ROOT_CLK] = imx_clk_gate4("uart7_root_clk", "uart7_post_div", base + 0x49a0, 0);
- clks[IMX7D_ECSPI1_ROOT_CLK] = imx_clk_gate4("ecspi1_root_clk", "ecspi1_post_div", base + 0x4780, 0);
- clks[IMX7D_ECSPI2_ROOT_CLK] = imx_clk_gate4("ecspi2_root_clk", "ecspi2_post_div", base + 0x4790, 0);
- clks[IMX7D_ECSPI3_ROOT_CLK] = imx_clk_gate4("ecspi3_root_clk", "ecspi3_post_div", base + 0x47a0, 0);
- clks[IMX7D_ECSPI4_ROOT_CLK] = imx_clk_gate4("ecspi4_root_clk", "ecspi4_post_div", base + 0x47b0, 0);
- clks[IMX7D_PWM1_ROOT_CLK] = imx_clk_gate4("pwm1_root_clk", "pwm1_post_div", base + 0x4840, 0);
- clks[IMX7D_PWM2_ROOT_CLK] = imx_clk_gate4("pwm2_root_clk", "pwm2_post_div", base + 0x4850, 0);
- clks[IMX7D_PWM3_ROOT_CLK] = imx_clk_gate4("pwm3_root_clk", "pwm3_post_div", base + 0x4860, 0);
- clks[IMX7D_PWM4_ROOT_CLK] = imx_clk_gate4("pwm4_root_clk", "pwm4_post_div", base + 0x4870, 0);
- clks[IMX7D_FLEXTIMER1_ROOT_CLK] = imx_clk_gate4("flextimer1_root_clk", "flextimer1_post_div", base + 0x4800, 0);
- clks[IMX7D_FLEXTIMER2_ROOT_CLK] = imx_clk_gate4("flextimer2_root_clk", "flextimer2_post_div", base + 0x4810, 0);
- clks[IMX7D_SIM1_ROOT_CLK] = imx_clk_gate4("sim1_root_clk", "sim1_post_div", base + 0x4900, 0);
- clks[IMX7D_SIM2_ROOT_CLK] = imx_clk_gate4("sim2_root_clk", "sim2_post_div", base + 0x4910, 0);
- clks[IMX7D_GPT1_ROOT_CLK] = imx_clk_gate4("gpt1_root_clk", "gpt1_post_div", base + 0x47c0, 0);
- clks[IMX7D_GPT2_ROOT_CLK] = imx_clk_gate4("gpt2_root_clk", "gpt2_post_div", base + 0x47d0, 0);
- clks[IMX7D_GPT3_ROOT_CLK] = imx_clk_gate4("gpt3_root_clk", "gpt3_post_div", base + 0x47e0, 0);
- clks[IMX7D_GPT4_ROOT_CLK] = imx_clk_gate4("gpt4_root_clk", "gpt4_post_div", base + 0x47f0, 0);
- clks[IMX7D_TRACE_ROOT_CLK] = imx_clk_gate4("trace_root_clk", "trace_post_div", base + 0x4300, 0);
- clks[IMX7D_WDOG1_ROOT_CLK] = imx_clk_gate4("wdog1_root_clk", "wdog_post_div", base + 0x49c0, 0);
- clks[IMX7D_WDOG2_ROOT_CLK] = imx_clk_gate4("wdog2_root_clk", "wdog_post_div", base + 0x49d0, 0);
- clks[IMX7D_WDOG3_ROOT_CLK] = imx_clk_gate4("wdog3_root_clk", "wdog_post_div", base + 0x49e0, 0);
- clks[IMX7D_WDOG4_ROOT_CLK] = imx_clk_gate4("wdog4_root_clk", "wdog_post_div", base + 0x49f0, 0);
- clks[IMX7D_KPP_ROOT_CLK] = imx_clk_gate4("kpp_root_clk", "ipg_root_clk", base + 0x4aa0, 0);
- clks[IMX7D_CSI_MCLK_ROOT_CLK] = imx_clk_gate4("csi_mclk_root_clk", "csi_mclk_post_div", base + 0x4490, 0);
- clks[IMX7D_AUDIO_MCLK_ROOT_CLK] = imx_clk_gate4("audio_mclk_root_clk", "audio_mclk_post_div", base + 0x4790, 0);
- clks[IMX7D_WRCLK_ROOT_CLK] = imx_clk_gate4("wrclk_root_clk", "wrclk_post_div", base + 0x47a0, 0);
- clks[IMX7D_USB_CTRL_CLK] = imx_clk_gate4("usb_ctrl_clk", "ahb_root_clk", base + 0x4680, 0);
- clks[IMX7D_USB_PHY1_CLK] = imx_clk_gate4("usb_phy1_clk", "pll_usb1_main_clk", base + 0x46a0, 0);
- clks[IMX7D_USB_PHY2_CLK] = imx_clk_gate4("usb_phy2_clk", "pll_usb_main_clk", base + 0x46b0, 0);
- clks[IMX7D_ADC_ROOT_CLK] = imx_clk_gate4("adc_root_clk", "ipg_root_clk", base + 0x4200, 0);
-
- clks[IMX7D_GPT_3M_CLK] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8);
-
- clks[IMX7D_CLK_ARM] = imx_clk_cpu("arm", "arm_a7_root_clk",
- clks[IMX7D_ARM_A7_ROOT_CLK],
- clks[IMX7D_ARM_A7_ROOT_SRC],
- clks[IMX7D_PLL_ARM_MAIN_CLK],
- clks[IMX7D_PLL_SYS_MAIN_CLK]);
-
- imx_check_clocks(clks, ARRAY_SIZE(clks));
-
- clk_data.clks = clks;
- clk_data.clk_num = ARRAY_SIZE(clks);
- of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
-
- clk_set_parent(clks[IMX7D_PLL_ARM_MAIN_BYPASS], clks[IMX7D_PLL_ARM_MAIN]);
- clk_set_parent(clks[IMX7D_PLL_DRAM_MAIN_BYPASS], clks[IMX7D_PLL_DRAM_MAIN]);
- clk_set_parent(clks[IMX7D_PLL_SYS_MAIN_BYPASS], clks[IMX7D_PLL_SYS_MAIN]);
- clk_set_parent(clks[IMX7D_PLL_ENET_MAIN_BYPASS], clks[IMX7D_PLL_ENET_MAIN]);
- clk_set_parent(clks[IMX7D_PLL_AUDIO_MAIN_BYPASS], clks[IMX7D_PLL_AUDIO_MAIN]);
- clk_set_parent(clks[IMX7D_PLL_VIDEO_MAIN_BYPASS], clks[IMX7D_PLL_VIDEO_MAIN]);
-
- clk_set_parent(clks[IMX7D_MIPI_CSI_ROOT_SRC], clks[IMX7D_PLL_SYS_PFD3_CLK]);
+ hws[IMX7D_ARM_A7_ROOT_SRC] = imx_clk_hw_mux2("arm_a7_src", base + 0x8000, 24, 3, arm_a7_sel, ARRAY_SIZE(arm_a7_sel));
+ hws[IMX7D_ARM_M4_ROOT_SRC] = imx_clk_hw_mux2("arm_m4_src", base + 0x8080, 24, 3, arm_m4_sel, ARRAY_SIZE(arm_m4_sel));
+ hws[IMX7D_MAIN_AXI_ROOT_SRC] = imx_clk_hw_mux2("axi_src", base + 0x8800, 24, 3, axi_sel, ARRAY_SIZE(axi_sel));
+ hws[IMX7D_DISP_AXI_ROOT_SRC] = imx_clk_hw_mux2("disp_axi_src", base + 0x8880, 24, 3, disp_axi_sel, ARRAY_SIZE(disp_axi_sel));
+ hws[IMX7D_ENET_AXI_ROOT_SRC] = imx_clk_hw_mux2("enet_axi_src", base + 0x8900, 24, 3, enet_axi_sel, ARRAY_SIZE(enet_axi_sel));
+ hws[IMX7D_NAND_USDHC_BUS_ROOT_SRC] = imx_clk_hw_mux2("nand_usdhc_src", base + 0x8980, 24, 3, nand_usdhc_bus_sel, ARRAY_SIZE(nand_usdhc_bus_sel));
+ hws[IMX7D_AHB_CHANNEL_ROOT_SRC] = imx_clk_hw_mux2("ahb_src", base + 0x9000, 24, 3, ahb_channel_sel, ARRAY_SIZE(ahb_channel_sel));
+ hws[IMX7D_DRAM_PHYM_ROOT_SRC] = imx_clk_hw_mux2("dram_phym_src", base + 0x9800, 24, 1, dram_phym_sel, ARRAY_SIZE(dram_phym_sel));
+ hws[IMX7D_DRAM_ROOT_SRC] = imx_clk_hw_mux2("dram_src", base + 0x9880, 24, 1, dram_sel, ARRAY_SIZE(dram_sel));
+ hws[IMX7D_DRAM_PHYM_ALT_ROOT_SRC] = imx_clk_hw_mux2("dram_phym_alt_src", base + 0xa000, 24, 3, dram_phym_alt_sel, ARRAY_SIZE(dram_phym_alt_sel));
+ hws[IMX7D_DRAM_ALT_ROOT_SRC] = imx_clk_hw_mux2("dram_alt_src", base + 0xa080, 24, 3, dram_alt_sel, ARRAY_SIZE(dram_alt_sel));
+ hws[IMX7D_USB_HSIC_ROOT_SRC] = imx_clk_hw_mux2("usb_hsic_src", base + 0xa100, 24, 3, usb_hsic_sel, ARRAY_SIZE(usb_hsic_sel));
+ hws[IMX7D_PCIE_CTRL_ROOT_SRC] = imx_clk_hw_mux2("pcie_ctrl_src", base + 0xa180, 24, 3, pcie_ctrl_sel, ARRAY_SIZE(pcie_ctrl_sel));
+ hws[IMX7D_PCIE_PHY_ROOT_SRC] = imx_clk_hw_mux2("pcie_phy_src", base + 0xa200, 24, 3, pcie_phy_sel, ARRAY_SIZE(pcie_phy_sel));
+ hws[IMX7D_EPDC_PIXEL_ROOT_SRC] = imx_clk_hw_mux2("epdc_pixel_src", base + 0xa280, 24, 3, epdc_pixel_sel, ARRAY_SIZE(epdc_pixel_sel));
+ hws[IMX7D_LCDIF_PIXEL_ROOT_SRC] = imx_clk_hw_mux2("lcdif_pixel_src", base + 0xa300, 24, 3, lcdif_pixel_sel, ARRAY_SIZE(lcdif_pixel_sel));
+ hws[IMX7D_MIPI_DSI_ROOT_SRC] = imx_clk_hw_mux2("mipi_dsi_src", base + 0xa380, 24, 3, mipi_dsi_sel, ARRAY_SIZE(mipi_dsi_sel));
+ hws[IMX7D_MIPI_CSI_ROOT_SRC] = imx_clk_hw_mux2("mipi_csi_src", base + 0xa400, 24, 3, mipi_csi_sel, ARRAY_SIZE(mipi_csi_sel));
+ hws[IMX7D_MIPI_DPHY_ROOT_SRC] = imx_clk_hw_mux2("mipi_dphy_src", base + 0xa480, 24, 3, mipi_dphy_sel, ARRAY_SIZE(mipi_dphy_sel));
+ hws[IMX7D_SAI1_ROOT_SRC] = imx_clk_hw_mux2("sai1_src", base + 0xa500, 24, 3, sai1_sel, ARRAY_SIZE(sai1_sel));
+ hws[IMX7D_SAI2_ROOT_SRC] = imx_clk_hw_mux2("sai2_src", base + 0xa580, 24, 3, sai2_sel, ARRAY_SIZE(sai2_sel));
+ hws[IMX7D_SAI3_ROOT_SRC] = imx_clk_hw_mux2("sai3_src", base + 0xa600, 24, 3, sai3_sel, ARRAY_SIZE(sai3_sel));
+ hws[IMX7D_SPDIF_ROOT_SRC] = imx_clk_hw_mux2("spdif_src", base + 0xa680, 24, 3, spdif_sel, ARRAY_SIZE(spdif_sel));
+ hws[IMX7D_ENET1_REF_ROOT_SRC] = imx_clk_hw_mux2("enet1_ref_src", base + 0xa700, 24, 3, enet1_ref_sel, ARRAY_SIZE(enet1_ref_sel));
+ hws[IMX7D_ENET1_TIME_ROOT_SRC] = imx_clk_hw_mux2("enet1_time_src", base + 0xa780, 24, 3, enet1_time_sel, ARRAY_SIZE(enet1_time_sel));
+ hws[IMX7D_ENET2_REF_ROOT_SRC] = imx_clk_hw_mux2("enet2_ref_src", base + 0xa800, 24, 3, enet2_ref_sel, ARRAY_SIZE(enet2_ref_sel));
+ hws[IMX7D_ENET2_TIME_ROOT_SRC] = imx_clk_hw_mux2("enet2_time_src", base + 0xa880, 24, 3, enet2_time_sel, ARRAY_SIZE(enet2_time_sel));
+ hws[IMX7D_ENET_PHY_REF_ROOT_SRC] = imx_clk_hw_mux2("enet_phy_ref_src", base + 0xa900, 24, 3, enet_phy_ref_sel, ARRAY_SIZE(enet_phy_ref_sel));
+ hws[IMX7D_EIM_ROOT_SRC] = imx_clk_hw_mux2("eim_src", base + 0xa980, 24, 3, eim_sel, ARRAY_SIZE(eim_sel));
+ hws[IMX7D_NAND_ROOT_SRC] = imx_clk_hw_mux2("nand_src", base + 0xaa00, 24, 3, nand_sel, ARRAY_SIZE(nand_sel));
+ hws[IMX7D_QSPI_ROOT_SRC] = imx_clk_hw_mux2("qspi_src", base + 0xaa80, 24, 3, qspi_sel, ARRAY_SIZE(qspi_sel));
+ hws[IMX7D_USDHC1_ROOT_SRC] = imx_clk_hw_mux2("usdhc1_src", base + 0xab00, 24, 3, usdhc1_sel, ARRAY_SIZE(usdhc1_sel));
+ hws[IMX7D_USDHC2_ROOT_SRC] = imx_clk_hw_mux2("usdhc2_src", base + 0xab80, 24, 3, usdhc2_sel, ARRAY_SIZE(usdhc2_sel));
+ hws[IMX7D_USDHC3_ROOT_SRC] = imx_clk_hw_mux2("usdhc3_src", base + 0xac00, 24, 3, usdhc3_sel, ARRAY_SIZE(usdhc3_sel));
+ hws[IMX7D_CAN1_ROOT_SRC] = imx_clk_hw_mux2("can1_src", base + 0xac80, 24, 3, can1_sel, ARRAY_SIZE(can1_sel));
+ hws[IMX7D_CAN2_ROOT_SRC] = imx_clk_hw_mux2("can2_src", base + 0xad00, 24, 3, can2_sel, ARRAY_SIZE(can2_sel));
+ hws[IMX7D_I2C1_ROOT_SRC] = imx_clk_hw_mux2("i2c1_src", base + 0xad80, 24, 3, i2c1_sel, ARRAY_SIZE(i2c1_sel));
+ hws[IMX7D_I2C2_ROOT_SRC] = imx_clk_hw_mux2("i2c2_src", base + 0xae00, 24, 3, i2c2_sel, ARRAY_SIZE(i2c2_sel));
+ hws[IMX7D_I2C3_ROOT_SRC] = imx_clk_hw_mux2("i2c3_src", base + 0xae80, 24, 3, i2c3_sel, ARRAY_SIZE(i2c3_sel));
+ hws[IMX7D_I2C4_ROOT_SRC] = imx_clk_hw_mux2("i2c4_src", base + 0xaf00, 24, 3, i2c4_sel, ARRAY_SIZE(i2c4_sel));
+ hws[IMX7D_UART1_ROOT_SRC] = imx_clk_hw_mux2("uart1_src", base + 0xaf80, 24, 3, uart1_sel, ARRAY_SIZE(uart1_sel));
+ hws[IMX7D_UART2_ROOT_SRC] = imx_clk_hw_mux2("uart2_src", base + 0xb000, 24, 3, uart2_sel, ARRAY_SIZE(uart2_sel));
+ hws[IMX7D_UART3_ROOT_SRC] = imx_clk_hw_mux2("uart3_src", base + 0xb080, 24, 3, uart3_sel, ARRAY_SIZE(uart3_sel));
+ hws[IMX7D_UART4_ROOT_SRC] = imx_clk_hw_mux2("uart4_src", base + 0xb100, 24, 3, uart4_sel, ARRAY_SIZE(uart4_sel));
+ hws[IMX7D_UART5_ROOT_SRC] = imx_clk_hw_mux2("uart5_src", base + 0xb180, 24, 3, uart5_sel, ARRAY_SIZE(uart5_sel));
+ hws[IMX7D_UART6_ROOT_SRC] = imx_clk_hw_mux2("uart6_src", base + 0xb200, 24, 3, uart6_sel, ARRAY_SIZE(uart6_sel));
+ hws[IMX7D_UART7_ROOT_SRC] = imx_clk_hw_mux2("uart7_src", base + 0xb280, 24, 3, uart7_sel, ARRAY_SIZE(uart7_sel));
+ hws[IMX7D_ECSPI1_ROOT_SRC] = imx_clk_hw_mux2("ecspi1_src", base + 0xb300, 24, 3, ecspi1_sel, ARRAY_SIZE(ecspi1_sel));
+ hws[IMX7D_ECSPI2_ROOT_SRC] = imx_clk_hw_mux2("ecspi2_src", base + 0xb380, 24, 3, ecspi2_sel, ARRAY_SIZE(ecspi2_sel));
+ hws[IMX7D_ECSPI3_ROOT_SRC] = imx_clk_hw_mux2("ecspi3_src", base + 0xb400, 24, 3, ecspi3_sel, ARRAY_SIZE(ecspi3_sel));
+ hws[IMX7D_ECSPI4_ROOT_SRC] = imx_clk_hw_mux2("ecspi4_src", base + 0xb480, 24, 3, ecspi4_sel, ARRAY_SIZE(ecspi4_sel));
+ hws[IMX7D_PWM1_ROOT_SRC] = imx_clk_hw_mux2("pwm1_src", base + 0xb500, 24, 3, pwm1_sel, ARRAY_SIZE(pwm1_sel));
+ hws[IMX7D_PWM2_ROOT_SRC] = imx_clk_hw_mux2("pwm2_src", base + 0xb580, 24, 3, pwm2_sel, ARRAY_SIZE(pwm2_sel));
+ hws[IMX7D_PWM3_ROOT_SRC] = imx_clk_hw_mux2("pwm3_src", base + 0xb600, 24, 3, pwm3_sel, ARRAY_SIZE(pwm3_sel));
+ hws[IMX7D_PWM4_ROOT_SRC] = imx_clk_hw_mux2("pwm4_src", base + 0xb680, 24, 3, pwm4_sel, ARRAY_SIZE(pwm4_sel));
+ hws[IMX7D_FLEXTIMER1_ROOT_SRC] = imx_clk_hw_mux2("flextimer1_src", base + 0xb700, 24, 3, flextimer1_sel, ARRAY_SIZE(flextimer1_sel));
+ hws[IMX7D_FLEXTIMER2_ROOT_SRC] = imx_clk_hw_mux2("flextimer2_src", base + 0xb780, 24, 3, flextimer2_sel, ARRAY_SIZE(flextimer2_sel));
+ hws[IMX7D_SIM1_ROOT_SRC] = imx_clk_hw_mux2("sim1_src", base + 0xb800, 24, 3, sim1_sel, ARRAY_SIZE(sim1_sel));
+ hws[IMX7D_SIM2_ROOT_SRC] = imx_clk_hw_mux2("sim2_src", base + 0xb880, 24, 3, sim2_sel, ARRAY_SIZE(sim2_sel));
+ hws[IMX7D_GPT1_ROOT_SRC] = imx_clk_hw_mux2("gpt1_src", base + 0xb900, 24, 3, gpt1_sel, ARRAY_SIZE(gpt1_sel));
+ hws[IMX7D_GPT2_ROOT_SRC] = imx_clk_hw_mux2("gpt2_src", base + 0xb980, 24, 3, gpt2_sel, ARRAY_SIZE(gpt2_sel));
+ hws[IMX7D_GPT3_ROOT_SRC] = imx_clk_hw_mux2("gpt3_src", base + 0xba00, 24, 3, gpt3_sel, ARRAY_SIZE(gpt3_sel));
+ hws[IMX7D_GPT4_ROOT_SRC] = imx_clk_hw_mux2("gpt4_src", base + 0xba80, 24, 3, gpt4_sel, ARRAY_SIZE(gpt4_sel));
+ hws[IMX7D_TRACE_ROOT_SRC] = imx_clk_hw_mux2("trace_src", base + 0xbb00, 24, 3, trace_sel, ARRAY_SIZE(trace_sel));
+ hws[IMX7D_WDOG_ROOT_SRC] = imx_clk_hw_mux2("wdog_src", base + 0xbb80, 24, 3, wdog_sel, ARRAY_SIZE(wdog_sel));
+ hws[IMX7D_CSI_MCLK_ROOT_SRC] = imx_clk_hw_mux2("csi_mclk_src", base + 0xbc00, 24, 3, csi_mclk_sel, ARRAY_SIZE(csi_mclk_sel));
+ hws[IMX7D_AUDIO_MCLK_ROOT_SRC] = imx_clk_hw_mux2("audio_mclk_src", base + 0xbc80, 24, 3, audio_mclk_sel, ARRAY_SIZE(audio_mclk_sel));
+ hws[IMX7D_WRCLK_ROOT_SRC] = imx_clk_hw_mux2("wrclk_src", base + 0xbd00, 24, 3, wrclk_sel, ARRAY_SIZE(wrclk_sel));
+ hws[IMX7D_CLKO1_ROOT_SRC] = imx_clk_hw_mux2("clko1_src", base + 0xbd80, 24, 3, clko1_sel, ARRAY_SIZE(clko1_sel));
+ hws[IMX7D_CLKO2_ROOT_SRC] = imx_clk_hw_mux2("clko2_src", base + 0xbe00, 24, 3, clko2_sel, ARRAY_SIZE(clko2_sel));
+
+ hws[IMX7D_ARM_A7_ROOT_CG] = imx_clk_hw_gate3("arm_a7_cg", "arm_a7_src", base + 0x8000, 28);
+ hws[IMX7D_ARM_M4_ROOT_CG] = imx_clk_hw_gate3("arm_m4_cg", "arm_m4_src", base + 0x8080, 28);
+ hws[IMX7D_MAIN_AXI_ROOT_CG] = imx_clk_hw_gate3("axi_cg", "axi_src", base + 0x8800, 28);
+ hws[IMX7D_DISP_AXI_ROOT_CG] = imx_clk_hw_gate3("disp_axi_cg", "disp_axi_src", base + 0x8880, 28);
+ hws[IMX7D_ENET_AXI_ROOT_CG] = imx_clk_hw_gate3("enet_axi_cg", "enet_axi_src", base + 0x8900, 28);
+ hws[IMX7D_NAND_USDHC_BUS_ROOT_CG] = imx_clk_hw_gate3("nand_usdhc_cg", "nand_usdhc_src", base + 0x8980, 28);
+ hws[IMX7D_AHB_CHANNEL_ROOT_CG] = imx_clk_hw_gate3("ahb_cg", "ahb_src", base + 0x9000, 28);
+ hws[IMX7D_DRAM_PHYM_ROOT_CG] = imx_clk_hw_gate3("dram_phym_cg", "dram_phym_src", base + 0x9800, 28);
+ hws[IMX7D_DRAM_ROOT_CG] = imx_clk_hw_gate3("dram_cg", "dram_src", base + 0x9880, 28);
+ hws[IMX7D_DRAM_PHYM_ALT_ROOT_CG] = imx_clk_hw_gate3("dram_phym_alt_cg", "dram_phym_alt_src", base + 0xa000, 28);
+ hws[IMX7D_DRAM_ALT_ROOT_CG] = imx_clk_hw_gate3("dram_alt_cg", "dram_alt_src", base + 0xa080, 28);
+ hws[IMX7D_USB_HSIC_ROOT_CG] = imx_clk_hw_gate3("usb_hsic_cg", "usb_hsic_src", base + 0xa100, 28);
+ hws[IMX7D_PCIE_CTRL_ROOT_CG] = imx_clk_hw_gate3("pcie_ctrl_cg", "pcie_ctrl_src", base + 0xa180, 28);
+ hws[IMX7D_PCIE_PHY_ROOT_CG] = imx_clk_hw_gate3("pcie_phy_cg", "pcie_phy_src", base + 0xa200, 28);
+ hws[IMX7D_EPDC_PIXEL_ROOT_CG] = imx_clk_hw_gate3("epdc_pixel_cg", "epdc_pixel_src", base + 0xa280, 28);
+ hws[IMX7D_LCDIF_PIXEL_ROOT_CG] = imx_clk_hw_gate3("lcdif_pixel_cg", "lcdif_pixel_src", base + 0xa300, 28);
+ hws[IMX7D_MIPI_DSI_ROOT_CG] = imx_clk_hw_gate3("mipi_dsi_cg", "mipi_dsi_src", base + 0xa380, 28);
+ hws[IMX7D_MIPI_CSI_ROOT_CG] = imx_clk_hw_gate3("mipi_csi_cg", "mipi_csi_src", base + 0xa400, 28);
+ hws[IMX7D_MIPI_DPHY_ROOT_CG] = imx_clk_hw_gate3("mipi_dphy_cg", "mipi_dphy_src", base + 0xa480, 28);
+ hws[IMX7D_SAI1_ROOT_CG] = imx_clk_hw_gate3("sai1_cg", "sai1_src", base + 0xa500, 28);
+ hws[IMX7D_SAI2_ROOT_CG] = imx_clk_hw_gate3("sai2_cg", "sai2_src", base + 0xa580, 28);
+ hws[IMX7D_SAI3_ROOT_CG] = imx_clk_hw_gate3("sai3_cg", "sai3_src", base + 0xa600, 28);
+ hws[IMX7D_SPDIF_ROOT_CG] = imx_clk_hw_gate3("spdif_cg", "spdif_src", base + 0xa680, 28);
+ hws[IMX7D_ENET1_REF_ROOT_CG] = imx_clk_hw_gate3("enet1_ref_cg", "enet1_ref_src", base + 0xa700, 28);
+ hws[IMX7D_ENET1_TIME_ROOT_CG] = imx_clk_hw_gate3("enet1_time_cg", "enet1_time_src", base + 0xa780, 28);
+ hws[IMX7D_ENET2_REF_ROOT_CG] = imx_clk_hw_gate3("enet2_ref_cg", "enet2_ref_src", base + 0xa800, 28);
+ hws[IMX7D_ENET2_TIME_ROOT_CG] = imx_clk_hw_gate3("enet2_time_cg", "enet2_time_src", base + 0xa880, 28);
+ hws[IMX7D_ENET_PHY_REF_ROOT_CG] = imx_clk_hw_gate3("enet_phy_ref_cg", "enet_phy_ref_src", base + 0xa900, 28);
+ hws[IMX7D_EIM_ROOT_CG] = imx_clk_hw_gate3("eim_cg", "eim_src", base + 0xa980, 28);
+ hws[IMX7D_NAND_ROOT_CG] = imx_clk_hw_gate3("nand_cg", "nand_src", base + 0xaa00, 28);
+ hws[IMX7D_QSPI_ROOT_CG] = imx_clk_hw_gate3("qspi_cg", "qspi_src", base + 0xaa80, 28);
+ hws[IMX7D_USDHC1_ROOT_CG] = imx_clk_hw_gate3("usdhc1_cg", "usdhc1_src", base + 0xab00, 28);
+ hws[IMX7D_USDHC2_ROOT_CG] = imx_clk_hw_gate3("usdhc2_cg", "usdhc2_src", base + 0xab80, 28);
+ hws[IMX7D_USDHC3_ROOT_CG] = imx_clk_hw_gate3("usdhc3_cg", "usdhc3_src", base + 0xac00, 28);
+ hws[IMX7D_CAN1_ROOT_CG] = imx_clk_hw_gate3("can1_cg", "can1_src", base + 0xac80, 28);
+ hws[IMX7D_CAN2_ROOT_CG] = imx_clk_hw_gate3("can2_cg", "can2_src", base + 0xad00, 28);
+ hws[IMX7D_I2C1_ROOT_CG] = imx_clk_hw_gate3("i2c1_cg", "i2c1_src", base + 0xad80, 28);
+ hws[IMX7D_I2C2_ROOT_CG] = imx_clk_hw_gate3("i2c2_cg", "i2c2_src", base + 0xae00, 28);
+ hws[IMX7D_I2C3_ROOT_CG] = imx_clk_hw_gate3("i2c3_cg", "i2c3_src", base + 0xae80, 28);
+ hws[IMX7D_I2C4_ROOT_CG] = imx_clk_hw_gate3("i2c4_cg", "i2c4_src", base + 0xaf00, 28);
+ hws[IMX7D_UART1_ROOT_CG] = imx_clk_hw_gate3("uart1_cg", "uart1_src", base + 0xaf80, 28);
+ hws[IMX7D_UART2_ROOT_CG] = imx_clk_hw_gate3("uart2_cg", "uart2_src", base + 0xb000, 28);
+ hws[IMX7D_UART3_ROOT_CG] = imx_clk_hw_gate3("uart3_cg", "uart3_src", base + 0xb080, 28);
+ hws[IMX7D_UART4_ROOT_CG] = imx_clk_hw_gate3("uart4_cg", "uart4_src", base + 0xb100, 28);
+ hws[IMX7D_UART5_ROOT_CG] = imx_clk_hw_gate3("uart5_cg", "uart5_src", base + 0xb180, 28);
+ hws[IMX7D_UART6_ROOT_CG] = imx_clk_hw_gate3("uart6_cg", "uart6_src", base + 0xb200, 28);
+ hws[IMX7D_UART7_ROOT_CG] = imx_clk_hw_gate3("uart7_cg", "uart7_src", base + 0xb280, 28);
+ hws[IMX7D_ECSPI1_ROOT_CG] = imx_clk_hw_gate3("ecspi1_cg", "ecspi1_src", base + 0xb300, 28);
+ hws[IMX7D_ECSPI2_ROOT_CG] = imx_clk_hw_gate3("ecspi2_cg", "ecspi2_src", base + 0xb380, 28);
+ hws[IMX7D_ECSPI3_ROOT_CG] = imx_clk_hw_gate3("ecspi3_cg", "ecspi3_src", base + 0xb400, 28);
+ hws[IMX7D_ECSPI4_ROOT_CG] = imx_clk_hw_gate3("ecspi4_cg", "ecspi4_src", base + 0xb480, 28);
+ hws[IMX7D_PWM1_ROOT_CG] = imx_clk_hw_gate3("pwm1_cg", "pwm1_src", base + 0xb500, 28);
+ hws[IMX7D_PWM2_ROOT_CG] = imx_clk_hw_gate3("pwm2_cg", "pwm2_src", base + 0xb580, 28);
+ hws[IMX7D_PWM3_ROOT_CG] = imx_clk_hw_gate3("pwm3_cg", "pwm3_src", base + 0xb600, 28);
+ hws[IMX7D_PWM4_ROOT_CG] = imx_clk_hw_gate3("pwm4_cg", "pwm4_src", base + 0xb680, 28);
+ hws[IMX7D_FLEXTIMER1_ROOT_CG] = imx_clk_hw_gate3("flextimer1_cg", "flextimer1_src", base + 0xb700, 28);
+ hws[IMX7D_FLEXTIMER2_ROOT_CG] = imx_clk_hw_gate3("flextimer2_cg", "flextimer2_src", base + 0xb780, 28);
+ hws[IMX7D_SIM1_ROOT_CG] = imx_clk_hw_gate3("sim1_cg", "sim1_src", base + 0xb800, 28);
+ hws[IMX7D_SIM2_ROOT_CG] = imx_clk_hw_gate3("sim2_cg", "sim2_src", base + 0xb880, 28);
+ hws[IMX7D_GPT1_ROOT_CG] = imx_clk_hw_gate3("gpt1_cg", "gpt1_src", base + 0xb900, 28);
+ hws[IMX7D_GPT2_ROOT_CG] = imx_clk_hw_gate3("gpt2_cg", "gpt2_src", base + 0xb980, 28);
+ hws[IMX7D_GPT3_ROOT_CG] = imx_clk_hw_gate3("gpt3_cg", "gpt3_src", base + 0xbA00, 28);
+ hws[IMX7D_GPT4_ROOT_CG] = imx_clk_hw_gate3("gpt4_cg", "gpt4_src", base + 0xbA80, 28);
+ hws[IMX7D_TRACE_ROOT_CG] = imx_clk_hw_gate3("trace_cg", "trace_src", base + 0xbb00, 28);
+ hws[IMX7D_WDOG_ROOT_CG] = imx_clk_hw_gate3("wdog_cg", "wdog_src", base + 0xbb80, 28);
+ hws[IMX7D_CSI_MCLK_ROOT_CG] = imx_clk_hw_gate3("csi_mclk_cg", "csi_mclk_src", base + 0xbc00, 28);
+ hws[IMX7D_AUDIO_MCLK_ROOT_CG] = imx_clk_hw_gate3("audio_mclk_cg", "audio_mclk_src", base + 0xbc80, 28);
+ hws[IMX7D_WRCLK_ROOT_CG] = imx_clk_hw_gate3("wrclk_cg", "wrclk_src", base + 0xbd00, 28);
+ hws[IMX7D_CLKO1_ROOT_CG] = imx_clk_hw_gate3("clko1_cg", "clko1_src", base + 0xbd80, 28);
+ hws[IMX7D_CLKO2_ROOT_CG] = imx_clk_hw_gate3("clko2_cg", "clko2_src", base + 0xbe00, 28);
+
+ hws[IMX7D_MAIN_AXI_ROOT_PRE_DIV] = imx_clk_hw_divider2("axi_pre_div", "axi_cg", base + 0x8800, 16, 3);
+ hws[IMX7D_DISP_AXI_ROOT_PRE_DIV] = imx_clk_hw_divider2("disp_axi_pre_div", "disp_axi_cg", base + 0x8880, 16, 3);
+ hws[IMX7D_ENET_AXI_ROOT_PRE_DIV] = imx_clk_hw_divider2("enet_axi_pre_div", "enet_axi_cg", base + 0x8900, 16, 3);
+ hws[IMX7D_NAND_USDHC_BUS_ROOT_PRE_DIV] = imx_clk_hw_divider2("nand_usdhc_pre_div", "nand_usdhc_cg", base + 0x8980, 16, 3);
+ hws[IMX7D_AHB_CHANNEL_ROOT_PRE_DIV] = imx_clk_hw_divider2("ahb_pre_div", "ahb_cg", base + 0x9000, 16, 3);
+ hws[IMX7D_DRAM_PHYM_ALT_ROOT_PRE_DIV] = imx_clk_hw_divider2("dram_phym_alt_pre_div", "dram_phym_alt_cg", base + 0xa000, 16, 3);
+ hws[IMX7D_DRAM_ALT_ROOT_PRE_DIV] = imx_clk_hw_divider2("dram_alt_pre_div", "dram_alt_cg", base + 0xa080, 16, 3);
+ hws[IMX7D_USB_HSIC_ROOT_PRE_DIV] = imx_clk_hw_divider2("usb_hsic_pre_div", "usb_hsic_cg", base + 0xa100, 16, 3);
+ hws[IMX7D_PCIE_CTRL_ROOT_PRE_DIV] = imx_clk_hw_divider2("pcie_ctrl_pre_div", "pcie_ctrl_cg", base + 0xa180, 16, 3);
+ hws[IMX7D_PCIE_PHY_ROOT_PRE_DIV] = imx_clk_hw_divider2("pcie_phy_pre_div", "pcie_phy_cg", base + 0xa200, 16, 3);
+ hws[IMX7D_EPDC_PIXEL_ROOT_PRE_DIV] = imx_clk_hw_divider2("epdc_pixel_pre_div", "epdc_pixel_cg", base + 0xa280, 16, 3);
+ hws[IMX7D_LCDIF_PIXEL_ROOT_PRE_DIV] = imx_clk_hw_divider2("lcdif_pixel_pre_div", "lcdif_pixel_cg", base + 0xa300, 16, 3);
+ hws[IMX7D_MIPI_DSI_ROOT_PRE_DIV] = imx_clk_hw_divider2("mipi_dsi_pre_div", "mipi_dsi_cg", base + 0xa380, 16, 3);
+ hws[IMX7D_MIPI_CSI_ROOT_PRE_DIV] = imx_clk_hw_divider2("mipi_csi_pre_div", "mipi_csi_cg", base + 0xa400, 16, 3);
+ hws[IMX7D_MIPI_DPHY_ROOT_PRE_DIV] = imx_clk_hw_divider2("mipi_dphy_pre_div", "mipi_dphy_cg", base + 0xa480, 16, 3);
+ hws[IMX7D_SAI1_ROOT_PRE_DIV] = imx_clk_hw_divider2("sai1_pre_div", "sai1_cg", base + 0xa500, 16, 3);
+ hws[IMX7D_SAI2_ROOT_PRE_DIV] = imx_clk_hw_divider2("sai2_pre_div", "sai2_cg", base + 0xa580, 16, 3);
+ hws[IMX7D_SAI3_ROOT_PRE_DIV] = imx_clk_hw_divider2("sai3_pre_div", "sai3_cg", base + 0xa600, 16, 3);
+ hws[IMX7D_SPDIF_ROOT_PRE_DIV] = imx_clk_hw_divider2("spdif_pre_div", "spdif_cg", base + 0xa680, 16, 3);
+ hws[IMX7D_ENET1_REF_ROOT_PRE_DIV] = imx_clk_hw_divider2("enet1_ref_pre_div", "enet1_ref_cg", base + 0xa700, 16, 3);
+ hws[IMX7D_ENET1_TIME_ROOT_PRE_DIV] = imx_clk_hw_divider2("enet1_time_pre_div", "enet1_time_cg", base + 0xa780, 16, 3);
+ hws[IMX7D_ENET2_REF_ROOT_PRE_DIV] = imx_clk_hw_divider2("enet2_ref_pre_div", "enet2_ref_cg", base + 0xa800, 16, 3);
+ hws[IMX7D_ENET2_TIME_ROOT_PRE_DIV] = imx_clk_hw_divider2("enet2_time_pre_div", "enet2_time_cg", base + 0xa880, 16, 3);
+ hws[IMX7D_ENET_PHY_REF_ROOT_PRE_DIV] = imx_clk_hw_divider2("enet_phy_ref_pre_div", "enet_phy_ref_cg", base + 0xa900, 16, 3);
+ hws[IMX7D_EIM_ROOT_PRE_DIV] = imx_clk_hw_divider2("eim_pre_div", "eim_cg", base + 0xa980, 16, 3);
+ hws[IMX7D_NAND_ROOT_PRE_DIV] = imx_clk_hw_divider2("nand_pre_div", "nand_cg", base + 0xaa00, 16, 3);
+ hws[IMX7D_QSPI_ROOT_PRE_DIV] = imx_clk_hw_divider2("qspi_pre_div", "qspi_cg", base + 0xaa80, 16, 3);
+ hws[IMX7D_USDHC1_ROOT_PRE_DIV] = imx_clk_hw_divider2("usdhc1_pre_div", "usdhc1_cg", base + 0xab00, 16, 3);
+ hws[IMX7D_USDHC2_ROOT_PRE_DIV] = imx_clk_hw_divider2("usdhc2_pre_div", "usdhc2_cg", base + 0xab80, 16, 3);
+ hws[IMX7D_USDHC3_ROOT_PRE_DIV] = imx_clk_hw_divider2("usdhc3_pre_div", "usdhc3_cg", base + 0xac00, 16, 3);
+ hws[IMX7D_CAN1_ROOT_PRE_DIV] = imx_clk_hw_divider2("can1_pre_div", "can1_cg", base + 0xac80, 16, 3);
+ hws[IMX7D_CAN2_ROOT_PRE_DIV] = imx_clk_hw_divider2("can2_pre_div", "can2_cg", base + 0xad00, 16, 3);
+ hws[IMX7D_I2C1_ROOT_PRE_DIV] = imx_clk_hw_divider2("i2c1_pre_div", "i2c1_cg", base + 0xad80, 16, 3);
+ hws[IMX7D_I2C2_ROOT_PRE_DIV] = imx_clk_hw_divider2("i2c2_pre_div", "i2c2_cg", base + 0xae00, 16, 3);
+ hws[IMX7D_I2C3_ROOT_PRE_DIV] = imx_clk_hw_divider2("i2c3_pre_div", "i2c3_cg", base + 0xae80, 16, 3);
+ hws[IMX7D_I2C4_ROOT_PRE_DIV] = imx_clk_hw_divider2("i2c4_pre_div", "i2c4_cg", base + 0xaf00, 16, 3);
+ hws[IMX7D_UART1_ROOT_PRE_DIV] = imx_clk_hw_divider2("uart1_pre_div", "uart1_cg", base + 0xaf80, 16, 3);
+ hws[IMX7D_UART2_ROOT_PRE_DIV] = imx_clk_hw_divider2("uart2_pre_div", "uart2_cg", base + 0xb000, 16, 3);
+ hws[IMX7D_UART3_ROOT_PRE_DIV] = imx_clk_hw_divider2("uart3_pre_div", "uart3_cg", base + 0xb080, 16, 3);
+ hws[IMX7D_UART4_ROOT_PRE_DIV] = imx_clk_hw_divider2("uart4_pre_div", "uart4_cg", base + 0xb100, 16, 3);
+ hws[IMX7D_UART5_ROOT_PRE_DIV] = imx_clk_hw_divider2("uart5_pre_div", "uart5_cg", base + 0xb180, 16, 3);
+ hws[IMX7D_UART6_ROOT_PRE_DIV] = imx_clk_hw_divider2("uart6_pre_div", "uart6_cg", base + 0xb200, 16, 3);
+ hws[IMX7D_UART7_ROOT_PRE_DIV] = imx_clk_hw_divider2("uart7_pre_div", "uart7_cg", base + 0xb280, 16, 3);
+ hws[IMX7D_ECSPI1_ROOT_PRE_DIV] = imx_clk_hw_divider2("ecspi1_pre_div", "ecspi1_cg", base + 0xb300, 16, 3);
+ hws[IMX7D_ECSPI2_ROOT_PRE_DIV] = imx_clk_hw_divider2("ecspi2_pre_div", "ecspi2_cg", base + 0xb380, 16, 3);
+ hws[IMX7D_ECSPI3_ROOT_PRE_DIV] = imx_clk_hw_divider2("ecspi3_pre_div", "ecspi3_cg", base + 0xb400, 16, 3);
+ hws[IMX7D_ECSPI4_ROOT_PRE_DIV] = imx_clk_hw_divider2("ecspi4_pre_div", "ecspi4_cg", base + 0xb480, 16, 3);
+ hws[IMX7D_PWM1_ROOT_PRE_DIV] = imx_clk_hw_divider2("pwm1_pre_div", "pwm1_cg", base + 0xb500, 16, 3);
+ hws[IMX7D_PWM2_ROOT_PRE_DIV] = imx_clk_hw_divider2("pwm2_pre_div", "pwm2_cg", base + 0xb580, 16, 3);
+ hws[IMX7D_PWM3_ROOT_PRE_DIV] = imx_clk_hw_divider2("pwm3_pre_div", "pwm3_cg", base + 0xb600, 16, 3);
+ hws[IMX7D_PWM4_ROOT_PRE_DIV] = imx_clk_hw_divider2("pwm4_pre_div", "pwm4_cg", base + 0xb680, 16, 3);
+ hws[IMX7D_FLEXTIMER1_ROOT_PRE_DIV] = imx_clk_hw_divider2("flextimer1_pre_div", "flextimer1_cg", base + 0xb700, 16, 3);
+ hws[IMX7D_FLEXTIMER2_ROOT_PRE_DIV] = imx_clk_hw_divider2("flextimer2_pre_div", "flextimer2_cg", base + 0xb780, 16, 3);
+ hws[IMX7D_SIM1_ROOT_PRE_DIV] = imx_clk_hw_divider2("sim1_pre_div", "sim1_cg", base + 0xb800, 16, 3);
+ hws[IMX7D_SIM2_ROOT_PRE_DIV] = imx_clk_hw_divider2("sim2_pre_div", "sim2_cg", base + 0xb880, 16, 3);
+ hws[IMX7D_GPT1_ROOT_PRE_DIV] = imx_clk_hw_divider2("gpt1_pre_div", "gpt1_cg", base + 0xb900, 16, 3);
+ hws[IMX7D_GPT2_ROOT_PRE_DIV] = imx_clk_hw_divider2("gpt2_pre_div", "gpt2_cg", base + 0xb980, 16, 3);
+ hws[IMX7D_GPT3_ROOT_PRE_DIV] = imx_clk_hw_divider2("gpt3_pre_div", "gpt3_cg", base + 0xba00, 16, 3);
+ hws[IMX7D_GPT4_ROOT_PRE_DIV] = imx_clk_hw_divider2("gpt4_pre_div", "gpt4_cg", base + 0xba80, 16, 3);
+ hws[IMX7D_TRACE_ROOT_PRE_DIV] = imx_clk_hw_divider2("trace_pre_div", "trace_cg", base + 0xbb00, 16, 3);
+ hws[IMX7D_WDOG_ROOT_PRE_DIV] = imx_clk_hw_divider2("wdog_pre_div", "wdog_cg", base + 0xbb80, 16, 3);
+ hws[IMX7D_CSI_MCLK_ROOT_PRE_DIV] = imx_clk_hw_divider2("csi_mclk_pre_div", "csi_mclk_cg", base + 0xbc00, 16, 3);
+ hws[IMX7D_AUDIO_MCLK_ROOT_PRE_DIV] = imx_clk_hw_divider2("audio_mclk_pre_div", "audio_mclk_cg", base + 0xbc80, 16, 3);
+ hws[IMX7D_WRCLK_ROOT_PRE_DIV] = imx_clk_hw_divider2("wrclk_pre_div", "wrclk_cg", base + 0xbd00, 16, 3);
+ hws[IMX7D_CLKO1_ROOT_PRE_DIV] = imx_clk_hw_divider2("clko1_pre_div", "clko1_cg", base + 0xbd80, 16, 3);
+ hws[IMX7D_CLKO2_ROOT_PRE_DIV] = imx_clk_hw_divider2("clko2_pre_div", "clko2_cg", base + 0xbe00, 16, 3);
+
+ hws[IMX7D_ARM_A7_ROOT_DIV] = imx_clk_hw_divider2("arm_a7_div", "arm_a7_cg", base + 0x8000, 0, 3);
+ hws[IMX7D_ARM_M4_ROOT_DIV] = imx_clk_hw_divider2("arm_m4_div", "arm_m4_cg", base + 0x8080, 0, 3);
+ hws[IMX7D_MAIN_AXI_ROOT_DIV] = imx_clk_hw_divider2("axi_post_div", "axi_pre_div", base + 0x8800, 0, 6);
+ hws[IMX7D_DISP_AXI_ROOT_DIV] = imx_clk_hw_divider2("disp_axi_post_div", "disp_axi_pre_div", base + 0x8880, 0, 6);
+ hws[IMX7D_ENET_AXI_ROOT_DIV] = imx_clk_hw_divider2("enet_axi_post_div", "enet_axi_pre_div", base + 0x8900, 0, 6);
+ hws[IMX7D_NAND_USDHC_BUS_ROOT_CLK] = imx_clk_hw_divider2("nand_usdhc_root_clk", "nand_usdhc_pre_div", base + 0x8980, 0, 6);
+ hws[IMX7D_AHB_CHANNEL_ROOT_DIV] = imx_clk_hw_divider2("ahb_root_clk", "ahb_pre_div", base + 0x9000, 0, 6);
+ hws[IMX7D_IPG_ROOT_CLK] = imx_clk_hw_divider_flags("ipg_root_clk", "ahb_root_clk", base + 0x9080, 0, 2, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE | CLK_SET_RATE_PARENT);
+ hws[IMX7D_DRAM_ROOT_DIV] = imx_clk_hw_divider2("dram_post_div", "dram_cg", base + 0x9880, 0, 3);
+ hws[IMX7D_DRAM_PHYM_ALT_ROOT_DIV] = imx_clk_hw_divider2("dram_phym_alt_post_div", "dram_phym_alt_pre_div", base + 0xa000, 0, 3);
+ hws[IMX7D_DRAM_ALT_ROOT_DIV] = imx_clk_hw_divider2("dram_alt_post_div", "dram_alt_pre_div", base + 0xa080, 0, 3);
+ hws[IMX7D_USB_HSIC_ROOT_DIV] = imx_clk_hw_divider2("usb_hsic_post_div", "usb_hsic_pre_div", base + 0xa100, 0, 6);
+ hws[IMX7D_PCIE_CTRL_ROOT_DIV] = imx_clk_hw_divider2("pcie_ctrl_post_div", "pcie_ctrl_pre_div", base + 0xa180, 0, 6);
+ hws[IMX7D_PCIE_PHY_ROOT_DIV] = imx_clk_hw_divider2("pcie_phy_post_div", "pcie_phy_pre_div", base + 0xa200, 0, 6);
+ hws[IMX7D_EPDC_PIXEL_ROOT_DIV] = imx_clk_hw_divider2("epdc_pixel_post_div", "epdc_pixel_pre_div", base + 0xa280, 0, 6);
+ hws[IMX7D_LCDIF_PIXEL_ROOT_DIV] = imx_clk_hw_divider2("lcdif_pixel_post_div", "lcdif_pixel_pre_div", base + 0xa300, 0, 6);
+ hws[IMX7D_MIPI_DSI_ROOT_DIV] = imx_clk_hw_divider2("mipi_dsi_post_div", "mipi_dsi_pre_div", base + 0xa380, 0, 6);
+ hws[IMX7D_MIPI_CSI_ROOT_DIV] = imx_clk_hw_divider2("mipi_csi_post_div", "mipi_csi_pre_div", base + 0xa400, 0, 6);
+ hws[IMX7D_MIPI_DPHY_ROOT_DIV] = imx_clk_hw_divider2("mipi_dphy_post_div", "mipi_dphy_pre_div", base + 0xa480, 0, 6);
+ hws[IMX7D_SAI1_ROOT_DIV] = imx_clk_hw_divider2("sai1_post_div", "sai1_pre_div", base + 0xa500, 0, 6);
+ hws[IMX7D_SAI2_ROOT_DIV] = imx_clk_hw_divider2("sai2_post_div", "sai2_pre_div", base + 0xa580, 0, 6);
+ hws[IMX7D_SAI3_ROOT_DIV] = imx_clk_hw_divider2("sai3_post_div", "sai3_pre_div", base + 0xa600, 0, 6);
+ hws[IMX7D_SPDIF_ROOT_DIV] = imx_clk_hw_divider2("spdif_post_div", "spdif_pre_div", base + 0xa680, 0, 6);
+ hws[IMX7D_ENET1_REF_ROOT_DIV] = imx_clk_hw_divider2("enet1_ref_post_div", "enet1_ref_pre_div", base + 0xa700, 0, 6);
+ hws[IMX7D_ENET1_TIME_ROOT_DIV] = imx_clk_hw_divider2("enet1_time_post_div", "enet1_time_pre_div", base + 0xa780, 0, 6);
+ hws[IMX7D_ENET2_REF_ROOT_DIV] = imx_clk_hw_divider2("enet2_ref_post_div", "enet2_ref_pre_div", base + 0xa800, 0, 6);
+ hws[IMX7D_ENET2_TIME_ROOT_DIV] = imx_clk_hw_divider2("enet2_time_post_div", "enet2_time_pre_div", base + 0xa880, 0, 6);
+ hws[IMX7D_ENET_PHY_REF_ROOT_CLK] = imx_clk_hw_divider2("enet_phy_ref_root_clk", "enet_phy_ref_pre_div", base + 0xa900, 0, 6);
+ hws[IMX7D_EIM_ROOT_DIV] = imx_clk_hw_divider2("eim_post_div", "eim_pre_div", base + 0xa980, 0, 6);
+ hws[IMX7D_NAND_ROOT_CLK] = imx_clk_hw_divider2("nand_root_clk", "nand_pre_div", base + 0xaa00, 0, 6);
+ hws[IMX7D_QSPI_ROOT_DIV] = imx_clk_hw_divider2("qspi_post_div", "qspi_pre_div", base + 0xaa80, 0, 6);
+ hws[IMX7D_USDHC1_ROOT_DIV] = imx_clk_hw_divider2("usdhc1_post_div", "usdhc1_pre_div", base + 0xab00, 0, 6);
+ hws[IMX7D_USDHC2_ROOT_DIV] = imx_clk_hw_divider2("usdhc2_post_div", "usdhc2_pre_div", base + 0xab80, 0, 6);
+ hws[IMX7D_USDHC3_ROOT_DIV] = imx_clk_hw_divider2("usdhc3_post_div", "usdhc3_pre_div", base + 0xac00, 0, 6);
+ hws[IMX7D_CAN1_ROOT_DIV] = imx_clk_hw_divider2("can1_post_div", "can1_pre_div", base + 0xac80, 0, 6);
+ hws[IMX7D_CAN2_ROOT_DIV] = imx_clk_hw_divider2("can2_post_div", "can2_pre_div", base + 0xad00, 0, 6);
+ hws[IMX7D_I2C1_ROOT_DIV] = imx_clk_hw_divider2("i2c1_post_div", "i2c1_pre_div", base + 0xad80, 0, 6);
+ hws[IMX7D_I2C2_ROOT_DIV] = imx_clk_hw_divider2("i2c2_post_div", "i2c2_pre_div", base + 0xae00, 0, 6);
+ hws[IMX7D_I2C3_ROOT_DIV] = imx_clk_hw_divider2("i2c3_post_div", "i2c3_pre_div", base + 0xae80, 0, 6);
+ hws[IMX7D_I2C4_ROOT_DIV] = imx_clk_hw_divider2("i2c4_post_div", "i2c4_pre_div", base + 0xaf00, 0, 6);
+ hws[IMX7D_UART1_ROOT_DIV] = imx_clk_hw_divider2("uart1_post_div", "uart1_pre_div", base + 0xaf80, 0, 6);
+ hws[IMX7D_UART2_ROOT_DIV] = imx_clk_hw_divider2("uart2_post_div", "uart2_pre_div", base + 0xb000, 0, 6);
+ hws[IMX7D_UART3_ROOT_DIV] = imx_clk_hw_divider2("uart3_post_div", "uart3_pre_div", base + 0xb080, 0, 6);
+ hws[IMX7D_UART4_ROOT_DIV] = imx_clk_hw_divider2("uart4_post_div", "uart4_pre_div", base + 0xb100, 0, 6);
+ hws[IMX7D_UART5_ROOT_DIV] = imx_clk_hw_divider2("uart5_post_div", "uart5_pre_div", base + 0xb180, 0, 6);
+ hws[IMX7D_UART6_ROOT_DIV] = imx_clk_hw_divider2("uart6_post_div", "uart6_pre_div", base + 0xb200, 0, 6);
+ hws[IMX7D_UART7_ROOT_DIV] = imx_clk_hw_divider2("uart7_post_div", "uart7_pre_div", base + 0xb280, 0, 6);
+ hws[IMX7D_ECSPI1_ROOT_DIV] = imx_clk_hw_divider2("ecspi1_post_div", "ecspi1_pre_div", base + 0xb300, 0, 6);
+ hws[IMX7D_ECSPI2_ROOT_DIV] = imx_clk_hw_divider2("ecspi2_post_div", "ecspi2_pre_div", base + 0xb380, 0, 6);
+ hws[IMX7D_ECSPI3_ROOT_DIV] = imx_clk_hw_divider2("ecspi3_post_div", "ecspi3_pre_div", base + 0xb400, 0, 6);
+ hws[IMX7D_ECSPI4_ROOT_DIV] = imx_clk_hw_divider2("ecspi4_post_div", "ecspi4_pre_div", base + 0xb480, 0, 6);
+ hws[IMX7D_PWM1_ROOT_DIV] = imx_clk_hw_divider2("pwm1_post_div", "pwm1_pre_div", base + 0xb500, 0, 6);
+ hws[IMX7D_PWM2_ROOT_DIV] = imx_clk_hw_divider2("pwm2_post_div", "pwm2_pre_div", base + 0xb580, 0, 6);
+ hws[IMX7D_PWM3_ROOT_DIV] = imx_clk_hw_divider2("pwm3_post_div", "pwm3_pre_div", base + 0xb600, 0, 6);
+ hws[IMX7D_PWM4_ROOT_DIV] = imx_clk_hw_divider2("pwm4_post_div", "pwm4_pre_div", base + 0xb680, 0, 6);
+ hws[IMX7D_FLEXTIMER1_ROOT_DIV] = imx_clk_hw_divider2("flextimer1_post_div", "flextimer1_pre_div", base + 0xb700, 0, 6);
+ hws[IMX7D_FLEXTIMER2_ROOT_DIV] = imx_clk_hw_divider2("flextimer2_post_div", "flextimer2_pre_div", base + 0xb780, 0, 6);
+ hws[IMX7D_SIM1_ROOT_DIV] = imx_clk_hw_divider2("sim1_post_div", "sim1_pre_div", base + 0xb800, 0, 6);
+ hws[IMX7D_SIM2_ROOT_DIV] = imx_clk_hw_divider2("sim2_post_div", "sim2_pre_div", base + 0xb880, 0, 6);
+ hws[IMX7D_GPT1_ROOT_DIV] = imx_clk_hw_divider2("gpt1_post_div", "gpt1_pre_div", base + 0xb900, 0, 6);
+ hws[IMX7D_GPT2_ROOT_DIV] = imx_clk_hw_divider2("gpt2_post_div", "gpt2_pre_div", base + 0xb980, 0, 6);
+ hws[IMX7D_GPT3_ROOT_DIV] = imx_clk_hw_divider2("gpt3_post_div", "gpt3_pre_div", base + 0xba00, 0, 6);
+ hws[IMX7D_GPT4_ROOT_DIV] = imx_clk_hw_divider2("gpt4_post_div", "gpt4_pre_div", base + 0xba80, 0, 6);
+ hws[IMX7D_TRACE_ROOT_DIV] = imx_clk_hw_divider2("trace_post_div", "trace_pre_div", base + 0xbb00, 0, 6);
+ hws[IMX7D_WDOG_ROOT_DIV] = imx_clk_hw_divider2("wdog_post_div", "wdog_pre_div", base + 0xbb80, 0, 6);
+ hws[IMX7D_CSI_MCLK_ROOT_DIV] = imx_clk_hw_divider2("csi_mclk_post_div", "csi_mclk_pre_div", base + 0xbc00, 0, 6);
+ hws[IMX7D_AUDIO_MCLK_ROOT_DIV] = imx_clk_hw_divider2("audio_mclk_post_div", "audio_mclk_pre_div", base + 0xbc80, 0, 6);
+ hws[IMX7D_WRCLK_ROOT_DIV] = imx_clk_hw_divider2("wrclk_post_div", "wrclk_pre_div", base + 0xbd00, 0, 6);
+ hws[IMX7D_CLKO1_ROOT_DIV] = imx_clk_hw_divider2("clko1_post_div", "clko1_pre_div", base + 0xbd80, 0, 6);
+ hws[IMX7D_CLKO2_ROOT_DIV] = imx_clk_hw_divider2("clko2_post_div", "clko2_pre_div", base + 0xbe00, 0, 6);
+
+ hws[IMX7D_ARM_A7_ROOT_CLK] = imx_clk_hw_gate2_flags("arm_a7_root_clk", "arm_a7_div", base + 0x4000, 0, CLK_OPS_PARENT_ENABLE);
+ hws[IMX7D_ARM_M4_ROOT_CLK] = imx_clk_hw_gate4("arm_m4_root_clk", "arm_m4_div", base + 0x4010, 0);
+ hws[IMX7D_MAIN_AXI_ROOT_CLK] = imx_clk_hw_gate2_flags("main_axi_root_clk", "axi_post_div", base + 0x4040, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
+ hws[IMX7D_DISP_AXI_ROOT_CLK] = imx_clk_hw_gate4("disp_axi_root_clk", "disp_axi_post_div", base + 0x4050, 0);
+ hws[IMX7D_ENET_AXI_ROOT_CLK] = imx_clk_hw_gate4("enet_axi_root_clk", "enet_axi_post_div", base + 0x4060, 0);
+ hws[IMX7D_OCRAM_CLK] = imx_clk_hw_gate4("ocram_clk", "main_axi_root_clk", base + 0x4110, 0);
+ hws[IMX7D_OCRAM_S_CLK] = imx_clk_hw_gate4("ocram_s_clk", "ahb_root_clk", base + 0x4120, 0);
+ hws[IMX7D_DRAM_ROOT_CLK] = imx_clk_hw_gate2_flags("dram_root_clk", "dram_post_div", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
+ hws[IMX7D_DRAM_PHYM_ROOT_CLK] = imx_clk_hw_gate2_flags("dram_phym_root_clk", "dram_phym_cg", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
+ hws[IMX7D_DRAM_PHYM_ALT_ROOT_CLK] = imx_clk_hw_gate2_flags("dram_phym_alt_root_clk", "dram_phym_alt_post_div", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
+ hws[IMX7D_DRAM_ALT_ROOT_CLK] = imx_clk_hw_gate2_flags("dram_alt_root_clk", "dram_alt_post_div", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
+ hws[IMX7D_OCOTP_CLK] = imx_clk_hw_gate4("ocotp_clk", "ipg_root_clk", base + 0x4230, 0);
+ hws[IMX7D_SNVS_CLK] = imx_clk_hw_gate4("snvs_clk", "ipg_root_clk", base + 0x4250, 0);
+ hws[IMX7D_MU_ROOT_CLK] = imx_clk_hw_gate4("mu_root_clk", "ipg_root_clk", base + 0x4270, 0);
+ hws[IMX7D_CAAM_CLK] = imx_clk_hw_gate4("caam_clk", "ipg_root_clk", base + 0x4240, 0);
+ hws[IMX7D_USB_HSIC_ROOT_CLK] = imx_clk_hw_gate4("usb_hsic_root_clk", "usb_hsic_post_div", base + 0x4690, 0);
+ hws[IMX7D_SDMA_CORE_CLK] = imx_clk_hw_gate4("sdma_root_clk", "ahb_root_clk", base + 0x4480, 0);
+ hws[IMX7D_PCIE_CTRL_ROOT_CLK] = imx_clk_hw_gate4("pcie_ctrl_root_clk", "pcie_ctrl_post_div", base + 0x4600, 0);
+ hws[IMX7D_PCIE_PHY_ROOT_CLK] = imx_clk_hw_gate4("pcie_phy_root_clk", "pcie_phy_post_div", base + 0x4600, 0);
+ hws[IMX7D_EPDC_PIXEL_ROOT_CLK] = imx_clk_hw_gate4("epdc_pixel_root_clk", "epdc_pixel_post_div", base + 0x44a0, 0);
+ hws[IMX7D_LCDIF_PIXEL_ROOT_CLK] = imx_clk_hw_gate4("lcdif_pixel_root_clk", "lcdif_pixel_post_div", base + 0x44b0, 0);
+ hws[IMX7D_MIPI_DSI_ROOT_CLK] = imx_clk_hw_gate4("mipi_dsi_root_clk", "mipi_dsi_post_div", base + 0x4650, 0);
+ hws[IMX7D_MIPI_CSI_ROOT_CLK] = imx_clk_hw_gate4("mipi_csi_root_clk", "mipi_csi_post_div", base + 0x4640, 0);
+ hws[IMX7D_MIPI_DPHY_ROOT_CLK] = imx_clk_hw_gate4("mipi_dphy_root_clk", "mipi_dphy_post_div", base + 0x4660, 0);
+ hws[IMX7D_ENET1_IPG_ROOT_CLK] = imx_clk_hw_gate2_shared2("enet1_ipg_root_clk", "enet_axi_post_div", base + 0x4700, 0, &share_count_enet1);
+ hws[IMX7D_ENET1_TIME_ROOT_CLK] = imx_clk_hw_gate2_shared2("enet1_time_root_clk", "enet1_time_post_div", base + 0x4700, 0, &share_count_enet1);
+ hws[IMX7D_ENET2_IPG_ROOT_CLK] = imx_clk_hw_gate2_shared2("enet2_ipg_root_clk", "enet_axi_post_div", base + 0x4710, 0, &share_count_enet2);
+ hws[IMX7D_ENET2_TIME_ROOT_CLK] = imx_clk_hw_gate2_shared2("enet2_time_root_clk", "enet2_time_post_div", base + 0x4710, 0, &share_count_enet2);
+ hws[IMX7D_SAI1_ROOT_CLK] = imx_clk_hw_gate2_shared2("sai1_root_clk", "sai1_post_div", base + 0x48c0, 0, &share_count_sai1);
+ hws[IMX7D_SAI1_IPG_CLK] = imx_clk_hw_gate2_shared2("sai1_ipg_clk", "ipg_root_clk", base + 0x48c0, 0, &share_count_sai1);
+ hws[IMX7D_SAI2_ROOT_CLK] = imx_clk_hw_gate2_shared2("sai2_root_clk", "sai2_post_div", base + 0x48d0, 0, &share_count_sai2);
+ hws[IMX7D_SAI2_IPG_CLK] = imx_clk_hw_gate2_shared2("sai2_ipg_clk", "ipg_root_clk", base + 0x48d0, 0, &share_count_sai2);
+ hws[IMX7D_SAI3_ROOT_CLK] = imx_clk_hw_gate2_shared2("sai3_root_clk", "sai3_post_div", base + 0x48e0, 0, &share_count_sai3);
+ hws[IMX7D_SAI3_IPG_CLK] = imx_clk_hw_gate2_shared2("sai3_ipg_clk", "ipg_root_clk", base + 0x48e0, 0, &share_count_sai3);
+ hws[IMX7D_SPDIF_ROOT_CLK] = imx_clk_hw_gate4("spdif_root_clk", "spdif_post_div", base + 0x44d0, 0);
+ hws[IMX7D_EIM_ROOT_CLK] = imx_clk_hw_gate4("eim_root_clk", "eim_post_div", base + 0x4160, 0);
+ hws[IMX7D_NAND_RAWNAND_CLK] = imx_clk_hw_gate2_shared2("nand_rawnand_clk", "nand_root_clk", base + 0x4140, 0, &share_count_nand);
+ hws[IMX7D_NAND_USDHC_BUS_RAWNAND_CLK] = imx_clk_hw_gate2_shared2("nand_usdhc_rawnand_clk", "nand_usdhc_root_clk", base + 0x4140, 0, &share_count_nand);
+ hws[IMX7D_QSPI_ROOT_CLK] = imx_clk_hw_gate4("qspi_root_clk", "qspi_post_div", base + 0x4150, 0);
+ hws[IMX7D_USDHC1_ROOT_CLK] = imx_clk_hw_gate4("usdhc1_root_clk", "usdhc1_post_div", base + 0x46c0, 0);
+ hws[IMX7D_USDHC2_ROOT_CLK] = imx_clk_hw_gate4("usdhc2_root_clk", "usdhc2_post_div", base + 0x46d0, 0);
+ hws[IMX7D_USDHC3_ROOT_CLK] = imx_clk_hw_gate4("usdhc3_root_clk", "usdhc3_post_div", base + 0x46e0, 0);
+ hws[IMX7D_CAN1_ROOT_CLK] = imx_clk_hw_gate4("can1_root_clk", "can1_post_div", base + 0x4740, 0);
+ hws[IMX7D_CAN2_ROOT_CLK] = imx_clk_hw_gate4("can2_root_clk", "can2_post_div", base + 0x4750, 0);
+ hws[IMX7D_I2C1_ROOT_CLK] = imx_clk_hw_gate4("i2c1_root_clk", "i2c1_post_div", base + 0x4880, 0);
+ hws[IMX7D_I2C2_ROOT_CLK] = imx_clk_hw_gate4("i2c2_root_clk", "i2c2_post_div", base + 0x4890, 0);
+ hws[IMX7D_I2C3_ROOT_CLK] = imx_clk_hw_gate4("i2c3_root_clk", "i2c3_post_div", base + 0x48a0, 0);
+ hws[IMX7D_I2C4_ROOT_CLK] = imx_clk_hw_gate4("i2c4_root_clk", "i2c4_post_div", base + 0x48b0, 0);
+ hws[IMX7D_UART1_ROOT_CLK] = imx_clk_hw_gate4("uart1_root_clk", "uart1_post_div", base + 0x4940, 0);
+ hws[IMX7D_UART2_ROOT_CLK] = imx_clk_hw_gate4("uart2_root_clk", "uart2_post_div", base + 0x4950, 0);
+ hws[IMX7D_UART3_ROOT_CLK] = imx_clk_hw_gate4("uart3_root_clk", "uart3_post_div", base + 0x4960, 0);
+ hws[IMX7D_UART4_ROOT_CLK] = imx_clk_hw_gate4("uart4_root_clk", "uart4_post_div", base + 0x4970, 0);
+ hws[IMX7D_UART5_ROOT_CLK] = imx_clk_hw_gate4("uart5_root_clk", "uart5_post_div", base + 0x4980, 0);
+ hws[IMX7D_UART6_ROOT_CLK] = imx_clk_hw_gate4("uart6_root_clk", "uart6_post_div", base + 0x4990, 0);
+ hws[IMX7D_UART7_ROOT_CLK] = imx_clk_hw_gate4("uart7_root_clk", "uart7_post_div", base + 0x49a0, 0);
+ hws[IMX7D_ECSPI1_ROOT_CLK] = imx_clk_hw_gate4("ecspi1_root_clk", "ecspi1_post_div", base + 0x4780, 0);
+ hws[IMX7D_ECSPI2_ROOT_CLK] = imx_clk_hw_gate4("ecspi2_root_clk", "ecspi2_post_div", base + 0x4790, 0);
+ hws[IMX7D_ECSPI3_ROOT_CLK] = imx_clk_hw_gate4("ecspi3_root_clk", "ecspi3_post_div", base + 0x47a0, 0);
+ hws[IMX7D_ECSPI4_ROOT_CLK] = imx_clk_hw_gate4("ecspi4_root_clk", "ecspi4_post_div", base + 0x47b0, 0);
+ hws[IMX7D_PWM1_ROOT_CLK] = imx_clk_hw_gate4("pwm1_root_clk", "pwm1_post_div", base + 0x4840, 0);
+ hws[IMX7D_PWM2_ROOT_CLK] = imx_clk_hw_gate4("pwm2_root_clk", "pwm2_post_div", base + 0x4850, 0);
+ hws[IMX7D_PWM3_ROOT_CLK] = imx_clk_hw_gate4("pwm3_root_clk", "pwm3_post_div", base + 0x4860, 0);
+ hws[IMX7D_PWM4_ROOT_CLK] = imx_clk_hw_gate4("pwm4_root_clk", "pwm4_post_div", base + 0x4870, 0);
+ hws[IMX7D_FLEXTIMER1_ROOT_CLK] = imx_clk_hw_gate4("flextimer1_root_clk", "flextimer1_post_div", base + 0x4800, 0);
+ hws[IMX7D_FLEXTIMER2_ROOT_CLK] = imx_clk_hw_gate4("flextimer2_root_clk", "flextimer2_post_div", base + 0x4810, 0);
+ hws[IMX7D_SIM1_ROOT_CLK] = imx_clk_hw_gate4("sim1_root_clk", "sim1_post_div", base + 0x4900, 0);
+ hws[IMX7D_SIM2_ROOT_CLK] = imx_clk_hw_gate4("sim2_root_clk", "sim2_post_div", base + 0x4910, 0);
+ hws[IMX7D_GPT1_ROOT_CLK] = imx_clk_hw_gate4("gpt1_root_clk", "gpt1_post_div", base + 0x47c0, 0);
+ hws[IMX7D_GPT2_ROOT_CLK] = imx_clk_hw_gate4("gpt2_root_clk", "gpt2_post_div", base + 0x47d0, 0);
+ hws[IMX7D_GPT3_ROOT_CLK] = imx_clk_hw_gate4("gpt3_root_clk", "gpt3_post_div", base + 0x47e0, 0);
+ hws[IMX7D_GPT4_ROOT_CLK] = imx_clk_hw_gate4("gpt4_root_clk", "gpt4_post_div", base + 0x47f0, 0);
+ hws[IMX7D_TRACE_ROOT_CLK] = imx_clk_hw_gate4("trace_root_clk", "trace_post_div", base + 0x4300, 0);
+ hws[IMX7D_WDOG1_ROOT_CLK] = imx_clk_hw_gate4("wdog1_root_clk", "wdog_post_div", base + 0x49c0, 0);
+ hws[IMX7D_WDOG2_ROOT_CLK] = imx_clk_hw_gate4("wdog2_root_clk", "wdog_post_div", base + 0x49d0, 0);
+ hws[IMX7D_WDOG3_ROOT_CLK] = imx_clk_hw_gate4("wdog3_root_clk", "wdog_post_div", base + 0x49e0, 0);
+ hws[IMX7D_WDOG4_ROOT_CLK] = imx_clk_hw_gate4("wdog4_root_clk", "wdog_post_div", base + 0x49f0, 0);
+ hws[IMX7D_KPP_ROOT_CLK] = imx_clk_hw_gate4("kpp_root_clk", "ipg_root_clk", base + 0x4aa0, 0);
+ hws[IMX7D_CSI_MCLK_ROOT_CLK] = imx_clk_hw_gate4("csi_mclk_root_clk", "csi_mclk_post_div", base + 0x4490, 0);
+ hws[IMX7D_AUDIO_MCLK_ROOT_CLK] = imx_clk_hw_gate4("audio_mclk_root_clk", "audio_mclk_post_div", base + 0x4790, 0);
+ hws[IMX7D_WRCLK_ROOT_CLK] = imx_clk_hw_gate4("wrclk_root_clk", "wrclk_post_div", base + 0x47a0, 0);
+ hws[IMX7D_USB_CTRL_CLK] = imx_clk_hw_gate4("usb_ctrl_clk", "ahb_root_clk", base + 0x4680, 0);
+ hws[IMX7D_USB_PHY1_CLK] = imx_clk_hw_gate4("usb_phy1_clk", "pll_usb1_main_clk", base + 0x46a0, 0);
+ hws[IMX7D_USB_PHY2_CLK] = imx_clk_hw_gate4("usb_phy2_clk", "pll_usb_main_clk", base + 0x46b0, 0);
+ hws[IMX7D_ADC_ROOT_CLK] = imx_clk_hw_gate4("adc_root_clk", "ipg_root_clk", base + 0x4200, 0);
+
+ hws[IMX7D_GPT_3M_CLK] = imx_clk_hw_fixed_factor("gpt_3m", "osc", 1, 8);
+
+ hws[IMX7D_CLK_ARM] = imx_clk_hw_cpu("arm", "arm_a7_root_clk",
+ hws[IMX7D_ARM_A7_ROOT_CLK]->clk,
+ hws[IMX7D_ARM_A7_ROOT_SRC]->clk,
+ hws[IMX7D_PLL_ARM_MAIN_CLK]->clk,
+ hws[IMX7D_PLL_SYS_MAIN_CLK]->clk);
+
+ imx_check_clk_hws(hws, IMX7D_CLK_END);
+
+ of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
+
+ clk_set_parent(hws[IMX7D_PLL_ARM_MAIN_BYPASS]->clk, hws[IMX7D_PLL_ARM_MAIN]->clk);
+ clk_set_parent(hws[IMX7D_PLL_DRAM_MAIN_BYPASS]->clk, hws[IMX7D_PLL_DRAM_MAIN]->clk);
+ clk_set_parent(hws[IMX7D_PLL_SYS_MAIN_BYPASS]->clk, hws[IMX7D_PLL_SYS_MAIN]->clk);
+ clk_set_parent(hws[IMX7D_PLL_ENET_MAIN_BYPASS]->clk, hws[IMX7D_PLL_ENET_MAIN]->clk);
+ clk_set_parent(hws[IMX7D_PLL_AUDIO_MAIN_BYPASS]->clk, hws[IMX7D_PLL_AUDIO_MAIN]->clk);
+ clk_set_parent(hws[IMX7D_PLL_VIDEO_MAIN_BYPASS]->clk, hws[IMX7D_PLL_VIDEO_MAIN]->clk);
+
+ clk_set_parent(hws[IMX7D_MIPI_CSI_ROOT_SRC]->clk, hws[IMX7D_PLL_SYS_PFD3_CLK]->clk);
/* use old gpt clk setting, gpt1 root clk must be twice as gpt counter freq */
- clk_set_parent(clks[IMX7D_GPT1_ROOT_SRC], clks[IMX7D_OSC_24M_CLK]);
+ clk_set_parent(hws[IMX7D_GPT1_ROOT_SRC]->clk, hws[IMX7D_OSC_24M_CLK]->clk);
/* Set clock rate for USBPHY, the USB_PLL at CCM is from USBOTG2 */
- clks[IMX7D_USB1_MAIN_480M_CLK] = imx_clk_fixed_factor("pll_usb1_main_clk", "osc", 20, 1);
- clks[IMX7D_USB_MAIN_480M_CLK] = imx_clk_fixed_factor("pll_usb_main_clk", "osc", 20, 1);
+ hws[IMX7D_USB1_MAIN_480M_CLK] = imx_clk_hw_fixed_factor("pll_usb1_main_clk", "osc", 20, 1);
+ hws[IMX7D_USB_MAIN_480M_CLK] = imx_clk_hw_fixed_factor("pll_usb_main_clk", "osc", 20, 1);
+
+ for (i = 0; i < ARRAY_SIZE(uart_clk_ids); i++) {
+ int index = uart_clk_ids[i];
+
+ uart_clks[i] = &hws[index]->clk;
+ }
+
imx_register_uart_clocks(uart_clks);
diff --git a/drivers/clk/imx/clk-imx7ulp.c b/drivers/clk/imx/clk-imx7ulp.c
index 66682100f14c..42e4667f22fd 100644
--- a/drivers/clk/imx/clk-imx7ulp.c
+++ b/drivers/clk/imx/clk-imx7ulp.c
@@ -115,7 +115,7 @@ static void __init imx7ulp_clk_scg1_init(struct device_node *np)
clks[IMX7ULP_CLK_NIC0_DIV] = imx_clk_hw_divider_flags("nic0_clk", "nic_sel", base + 0x40, 24, 4, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
clks[IMX7ULP_CLK_NIC1_DIV] = imx_clk_hw_divider_flags("nic1_clk", "nic0_clk", base + 0x40, 16, 4, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
- clks[IMX7ULP_CLK_NIC1_BUS_DIV] = imx_clk_hw_divider_flags("nic1_bus_clk", "nic1_clk", base + 0x40, 4, 4, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
+ clks[IMX7ULP_CLK_NIC1_BUS_DIV] = imx_clk_hw_divider_flags("nic1_bus_clk", "nic0_clk", base + 0x40, 4, 4, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
clks[IMX7ULP_CLK_GPU_DIV] = imx_clk_hw_divider("gpu_clk", "nic0_clk", base + 0x40, 20, 4);
diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c
index 122a81ab8e48..6b8e75df994d 100644
--- a/drivers/clk/imx/clk-imx8mm.c
+++ b/drivers/clk/imx/clk-imx8mm.c
@@ -288,6 +288,9 @@ static const char *imx8mm_usb_core_sels[] = {"osc_24m", "sys_pll1_100m", "sys_pl
static const char *imx8mm_usb_phy_sels[] = {"osc_24m", "sys_pll1_100m", "sys_pll1_40m", "sys_pll2_100m",
"sys_pll2_200m", "clk_ext2", "clk_ext3", "audio_pll2_out", };
+static const char *imx8mm_gic_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m", "sys_pll2_100m",
+ "sys_pll1_800m", "clk_ext2", "clk_ext4", "audio_pll2_out" };
+
static const char *imx8mm_ecspi1_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m", "sys_pll1_160m",
"sys_pll1_800m", "sys_pll3_out", "sys_pll2_250m", "audio_pll2_out", };
@@ -325,7 +328,7 @@ static const char *imx8mm_dsi_dbi_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll
"sys_pll2_1000m", "sys_pll3_out", "audio_pll2_out", "video_pll1_out", };
static const char *imx8mm_usdhc3_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll1_800m", "sys_pll2_500m",
- "sys_pll3_out", "sys_pll1_266m", "audio_pll2_clk", "sys_pll1_100m", };
+ "sys_pll3_out", "sys_pll1_266m", "audio_pll2_out", "sys_pll1_100m", };
static const char *imx8mm_csi1_core_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll2_250m", "sys_pll1_800m",
"sys_pll2_1000m", "sys_pll3_out", "audio_pll2_out", "video_pll1_out", };
@@ -361,11 +364,11 @@ static const char *imx8mm_pdm_sels[] = {"osc_24m", "sys_pll2_100m", "audio_pll1_
"sys_pll2_1000m", "sys_pll3_out", "clk_ext3", "audio_pll2_out", };
static const char *imx8mm_vpu_h1_sels[] = {"osc_24m", "vpu_pll_out", "sys_pll1_800m", "sys_pll2_1000m",
- "audio_pll2_clk", "sys_pll2_125m", "sys_pll3_clk", "audio_pll1_out", };
+ "audio_pll2_out", "sys_pll2_125m", "sys_pll3_clk", "audio_pll1_out", };
static const char *imx8mm_dram_core_sels[] = {"dram_pll_out", "dram_alt_root", };
-static const char *imx8mm_clko1_sels[] = {"osc_24m", "sys_pll1_800m", "osc_27m", "sys_pll1_200m", "audio_pll2_clk",
+static const char *imx8mm_clko1_sels[] = {"osc_24m", "sys_pll1_800m", "osc_27m", "sys_pll1_200m", "audio_pll2_out",
"vpu_pll", "sys_pll1_80m", };
static struct clk *clks[IMX8MM_CLK_END];
@@ -523,7 +526,7 @@ static int __init imx8mm_clocks_init(struct device_node *ccm_node)
/* IP */
clks[IMX8MM_CLK_DRAM_ALT] = imx8m_clk_composite("dram_alt", imx8mm_dram_alt_sels, base + 0xa000);
- clks[IMX8MM_CLK_DRAM_APB] = imx8m_clk_composite("dram_apb", imx8mm_dram_apb_sels, base + 0xa080);
+ clks[IMX8MM_CLK_DRAM_APB] = imx8m_clk_composite_critical("dram_apb", imx8mm_dram_apb_sels, base + 0xa080);
clks[IMX8MM_CLK_VPU_G1] = imx8m_clk_composite("vpu_g1", imx8mm_vpu_g1_sels, base + 0xa100);
clks[IMX8MM_CLK_VPU_G2] = imx8m_clk_composite("vpu_g2", imx8mm_vpu_g2_sels, base + 0xa180);
clks[IMX8MM_CLK_DISP_DTRC] = imx8m_clk_composite("disp_dtrc", imx8mm_disp_dtrc_sels, base + 0xa200);
@@ -558,6 +561,7 @@ static int __init imx8mm_clocks_init(struct device_node *ccm_node)
clks[IMX8MM_CLK_UART4] = imx8m_clk_composite("uart4", imx8mm_uart4_sels, base + 0xb080);
clks[IMX8MM_CLK_USB_CORE_REF] = imx8m_clk_composite("usb_core_ref", imx8mm_usb_core_sels, base + 0xb100);
clks[IMX8MM_CLK_USB_PHY_REF] = imx8m_clk_composite("usb_phy_ref", imx8mm_usb_phy_sels, base + 0xb180);
+ clks[IMX8MM_CLK_GIC] = imx8m_clk_composite_critical("gic", imx8mm_gic_sels, base + 0xb200);
clks[IMX8MM_CLK_ECSPI1] = imx8m_clk_composite("ecspi1", imx8mm_ecspi1_sels, base + 0xb280);
clks[IMX8MM_CLK_ECSPI2] = imx8m_clk_composite("ecspi2", imx8mm_ecspi2_sels, base + 0xb300);
clks[IMX8MM_CLK_PWM1] = imx8m_clk_composite("pwm1", imx8mm_pwm1_sels, base + 0xb380);
@@ -590,6 +594,11 @@ static int __init imx8mm_clocks_init(struct device_node *ccm_node)
clks[IMX8MM_CLK_ECSPI2_ROOT] = imx_clk_gate4("ecspi2_root_clk", "ecspi2", base + 0x4080, 0);
clks[IMX8MM_CLK_ECSPI3_ROOT] = imx_clk_gate4("ecspi3_root_clk", "ecspi3", base + 0x4090, 0);
clks[IMX8MM_CLK_ENET1_ROOT] = imx_clk_gate4("enet1_root_clk", "enet_axi", base + 0x40a0, 0);
+ clks[IMX8MM_CLK_GPIO1_ROOT] = imx_clk_gate4("gpio1_root_clk", "ipg_root", base + 0x40b0, 0);
+ clks[IMX8MM_CLK_GPIO2_ROOT] = imx_clk_gate4("gpio2_root_clk", "ipg_root", base + 0x40c0, 0);
+ clks[IMX8MM_CLK_GPIO3_ROOT] = imx_clk_gate4("gpio3_root_clk", "ipg_root", base + 0x40d0, 0);
+ clks[IMX8MM_CLK_GPIO4_ROOT] = imx_clk_gate4("gpio4_root_clk", "ipg_root", base + 0x40e0, 0);
+ clks[IMX8MM_CLK_GPIO5_ROOT] = imx_clk_gate4("gpio5_root_clk", "ipg_root", base + 0x40f0, 0);
clks[IMX8MM_CLK_GPT1_ROOT] = imx_clk_gate4("gpt1_root_clk", "gpt1", base + 0x4100, 0);
clks[IMX8MM_CLK_I2C1_ROOT] = imx_clk_gate4("i2c1_root_clk", "i2c1", base + 0x4170, 0);
clks[IMX8MM_CLK_I2C2_ROOT] = imx_clk_gate4("i2c2_root_clk", "i2c2", base + 0x4180, 0);
@@ -617,6 +626,7 @@ static int __init imx8mm_clocks_init(struct device_node *ccm_node)
clks[IMX8MM_CLK_SAI5_IPG] = imx_clk_gate2_shared2("sai5_ipg_clk", "ipg_audio_root", base + 0x4370, 0, &share_count_sai5);
clks[IMX8MM_CLK_SAI6_ROOT] = imx_clk_gate2_shared2("sai6_root_clk", "sai6", base + 0x4380, 0, &share_count_sai6);
clks[IMX8MM_CLK_SAI6_IPG] = imx_clk_gate2_shared2("sai6_ipg_clk", "ipg_audio_root", base + 0x4380, 0, &share_count_sai6);
+ clks[IMX8MM_CLK_SNVS_ROOT] = imx_clk_gate4("snvs_root_clk", "ipg_root", base + 0x4470, 0);
clks[IMX8MM_CLK_UART1_ROOT] = imx_clk_gate4("uart1_root_clk", "uart1", base + 0x4490, 0);
clks[IMX8MM_CLK_UART2_ROOT] = imx_clk_gate4("uart2_root_clk", "uart2", base + 0x44a0, 0);
clks[IMX8MM_CLK_UART3_ROOT] = imx_clk_gate4("uart3_root_clk", "uart3", base + 0x44b0, 0);
diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c
index daf1841b2adb..d407a07e7e6d 100644
--- a/drivers/clk/imx/clk-imx8mq.c
+++ b/drivers/clk/imx/clk-imx8mq.c
@@ -192,6 +192,9 @@ static const char * const imx8mq_usb_core_sels[] = {"osc_25m", "sys1_pll_100m",
static const char * const imx8mq_usb_phy_sels[] = {"osc_25m", "sys1_pll_100m", "sys1_pll_40m", "sys2_pll_100m",
"sys2_pll_200m", "clk_ext2", "clk_ext3", "audio_pll2_out", };
+static const char * const imx8mq_gic_sels[] = {"osc_25m", "sys2_pll_200m", "sys1_pll_40m", "sys2_pll_100m",
+ "sys2_pll_200m", "clk_ext2", "clk_ext3", "audio_pll2_out" };
+
static const char * const imx8mq_ecspi1_sels[] = {"osc_25m", "sys2_pll_200m", "sys1_pll_40m", "sys1_pll_160m",
"sys1_pll_800m", "sys3_pll2_out", "sys2_pll_250m", "audio_pll2_out", };
@@ -269,13 +272,20 @@ static const char * const imx8mq_clko2_sels[] = {"osc_25m", "sys2_pll_200m", "sy
static struct clk_onecell_data clk_data;
+static struct clk ** const uart_clks[] = {
+ &clks[IMX8MQ_CLK_UART1_ROOT],
+ &clks[IMX8MQ_CLK_UART2_ROOT],
+ &clks[IMX8MQ_CLK_UART3_ROOT],
+ &clks[IMX8MQ_CLK_UART4_ROOT],
+ NULL
+};
+
static int imx8mq_clocks_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
void __iomem *base;
int err;
- int i;
clks[IMX8MQ_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
clks[IMX8MQ_CLK_32K] = of_clk_get_by_name(np, "ckil");
@@ -358,9 +368,9 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
clks[IMX8MQ_SYS2_PLL_1000M] = imx_clk_fixed_factor("sys2_pll_1000m", "sys2_pll_out", 1, 1);
np = dev->of_node;
- base = of_iomap(np, 0);
- if (WARN_ON(!base))
- return -ENOMEM;
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (WARN_ON(IS_ERR(base)))
+ return PTR_ERR(base);
/* CORE */
clks[IMX8MQ_CLK_A53_SRC] = imx_clk_mux2("arm_a53_src", base + 0x8000, 24, 3, imx8mq_a53_sels, ARRAY_SIZE(imx8mq_a53_sels));
@@ -442,6 +452,7 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
clks[IMX8MQ_CLK_UART4] = imx8m_clk_composite("uart4", imx8mq_uart4_sels, base + 0xb080);
clks[IMX8MQ_CLK_USB_CORE_REF] = imx8m_clk_composite("usb_core_ref", imx8mq_usb_core_sels, base + 0xb100);
clks[IMX8MQ_CLK_USB_PHY_REF] = imx8m_clk_composite("usb_phy_ref", imx8mq_usb_phy_sels, base + 0xb180);
+ clks[IMX8MQ_CLK_GIC] = imx8m_clk_composite_critical("gic", imx8mq_gic_sels, base + 0xb200);
clks[IMX8MQ_CLK_ECSPI1] = imx8m_clk_composite("ecspi1", imx8mq_ecspi1_sels, base + 0xb280);
clks[IMX8MQ_CLK_ECSPI2] = imx8m_clk_composite("ecspi2", imx8mq_ecspi2_sels, base + 0xb300);
clks[IMX8MQ_CLK_PWM1] = imx8m_clk_composite("pwm1", imx8mq_pwm1_sels, base + 0xb380);
@@ -507,6 +518,7 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
clks[IMX8MQ_CLK_SAI5_IPG] = imx_clk_gate2_shared2("sai5_ipg_clk", "ipg_audio_root", base + 0x4370, 0, &share_count_sai5);
clks[IMX8MQ_CLK_SAI6_ROOT] = imx_clk_gate2_shared2("sai6_root_clk", "sai6", base + 0x4380, 0, &share_count_sai6);
clks[IMX8MQ_CLK_SAI6_IPG] = imx_clk_gate2_shared2("sai6_ipg_clk", "ipg_audio_root", base + 0x4380, 0, &share_count_sai6);
+ clks[IMX8MQ_CLK_SNVS_ROOT] = imx_clk_gate4("snvs_root_clk", "ipg_root", base + 0x4470, 0);
clks[IMX8MQ_CLK_UART1_ROOT] = imx_clk_gate4("uart1_root_clk", "uart1", base + 0x4490, 0);
clks[IMX8MQ_CLK_UART2_ROOT] = imx_clk_gate4("uart2_root_clk", "uart2", base + 0x44a0, 0);
clks[IMX8MQ_CLK_UART3_ROOT] = imx_clk_gate4("uart3_root_clk", "uart3", base + 0x44b0, 0);
@@ -543,10 +555,7 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
clks[IMX8MQ_ARM_PLL_OUT],
clks[IMX8MQ_SYS1_PLL_800M]);
- for (i = 0; i < IMX8MQ_CLK_END; i++)
- if (IS_ERR(clks[i]))
- pr_err("i.MX8mq clk %u register failed with %ld\n",
- i, PTR_ERR(clks[i]));
+ imx_check_clocks(clks, ARRAY_SIZE(clks));
clk_data.clks = clks;
clk_data.clk_num = ARRAY_SIZE(clks);
@@ -554,6 +563,8 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
err = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
WARN_ON(err);
+ imx_register_uart_clocks(uart_clks);
+
return err;
}
diff --git a/drivers/clk/imx/clk-pfd.c b/drivers/clk/imx/clk-pfd.c
index fa82ddea4996..50b7c30296f7 100644
--- a/drivers/clk/imx/clk-pfd.c
+++ b/drivers/clk/imx/clk-pfd.c
@@ -121,12 +121,13 @@ static const struct clk_ops clk_pfd_ops = {
.is_enabled = clk_pfd_is_enabled,
};
-struct clk *imx_clk_pfd(const char *name, const char *parent_name,
+struct clk_hw *imx_clk_hw_pfd(const char *name, const char *parent_name,
void __iomem *reg, u8 idx)
{
struct clk_pfd *pfd;
- struct clk *clk;
+ struct clk_hw *hw;
struct clk_init_data init;
+ int ret;
pfd = kzalloc(sizeof(*pfd), GFP_KERNEL);
if (!pfd)
@@ -142,10 +143,13 @@ struct clk *imx_clk_pfd(const char *name, const char *parent_name,
init.num_parents = 1;
pfd->hw.init = &init;
+ hw = &pfd->hw;
- clk = clk_register(NULL, &pfd->hw);
- if (IS_ERR(clk))
+ ret = clk_hw_register(NULL, hw);
+ if (ret) {
kfree(pfd);
+ return ERR_PTR(ret);
+ }
- return clk;
+ return hw;
}
diff --git a/drivers/clk/imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c
index 93b059608d3c..df91a8244fb4 100644
--- a/drivers/clk/imx/clk-pllv3.c
+++ b/drivers/clk/imx/clk-pllv3.c
@@ -410,14 +410,15 @@ static const struct clk_ops clk_pllv3_enet_ops = {
.recalc_rate = clk_pllv3_enet_recalc_rate,
};
-struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
+struct clk_hw *imx_clk_hw_pllv3(enum imx_pllv3_type type, const char *name,
const char *parent_name, void __iomem *base,
u32 div_mask)
{
struct clk_pllv3 *pll;
const struct clk_ops *ops;
- struct clk *clk;
+ struct clk_hw *hw;
struct clk_init_data init;
+ int ret;
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
if (!pll)
@@ -478,10 +479,13 @@ struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
init.num_parents = 1;
pll->hw.init = &init;
+ hw = &pll->hw;
- clk = clk_register(NULL, &pll->hw);
- if (IS_ERR(clk))
+ ret = clk_hw_register(NULL, hw);
+ if (ret) {
kfree(pll);
+ return ERR_PTR(ret);
+ }
- return clk;
+ return hw;
}
diff --git a/drivers/clk/imx/clk.c b/drivers/clk/imx/clk.c
index 1efed86217f7..f628071f6605 100644
--- a/drivers/clk/imx/clk.c
+++ b/drivers/clk/imx/clk.c
@@ -1,14 +1,30 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/err.h>
+#include <linux/io.h>
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include "clk.h"
+#define CCM_CCDR 0x4
+#define CCDR_MMDC_CH0_MASK BIT(17)
+#define CCDR_MMDC_CH1_MASK BIT(16)
+
DEFINE_SPINLOCK(imx_ccm_lock);
-void __init imx_check_clocks(struct clk *clks[], unsigned int count)
+void __init imx_mmdc_mask_handshake(void __iomem *ccm_base,
+ unsigned int chn)
+{
+ unsigned int reg;
+
+ reg = readl_relaxed(ccm_base + CCM_CCDR);
+ reg |= chn == 0 ? CCDR_MMDC_CH0_MASK : CCDR_MMDC_CH1_MASK;
+ writel_relaxed(reg, ccm_base + CCM_CCDR);
+}
+
+void imx_check_clocks(struct clk *clks[], unsigned int count)
{
unsigned i;
@@ -59,6 +75,17 @@ struct clk * __init imx_obtain_fixed_clock(
return clk;
}
+struct clk_hw * __init imx_obtain_fixed_clock_hw(
+ const char *name, unsigned long rate)
+{
+ struct clk *clk;
+
+ clk = imx_obtain_fixed_clock_from_dt(name);
+ if (IS_ERR(clk))
+ clk = imx_clk_fixed(name, rate);
+ return __clk_get_hw(clk);
+}
+
struct clk_hw * __init imx_obtain_fixed_clk_hw(struct device_node *np,
const char *name)
{
@@ -97,8 +124,8 @@ void imx_cscmr1_fixup(u32 *val)
return;
}
-static int imx_keep_uart_clocks __initdata;
-static struct clk ** const *imx_uart_clocks __initdata;
+static int imx_keep_uart_clocks;
+static struct clk ** const *imx_uart_clocks;
static int __init imx_keep_uart_clocks_param(char *str)
{
@@ -111,7 +138,7 @@ __setup_param("earlycon", imx_keep_uart_earlycon,
__setup_param("earlyprintk", imx_keep_uart_earlyprintk,
imx_keep_uart_clocks_param, 0);
-void __init imx_register_uart_clocks(struct clk ** const clks[])
+void imx_register_uart_clocks(struct clk ** const clks[])
{
if (imx_keep_uart_clocks) {
int i;
diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h
index 8639a8f2153e..d94d9cb079d3 100644
--- a/drivers/clk/imx/clk.h
+++ b/drivers/clk/imx/clk.h
@@ -10,6 +10,8 @@ extern spinlock_t imx_ccm_lock;
void imx_check_clocks(struct clk *clks[], unsigned int count);
void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count);
void imx_register_uart_clocks(struct clk ** const clks[]);
+void imx_register_uart_clocks_hws(struct clk_hw ** const hws[]);
+void imx_mmdc_mask_handshake(void __iomem *ccm_base, unsigned int chn);
extern void imx_cscmr1_fixup(u32 *val);
@@ -48,6 +50,74 @@ struct imx_pll14xx_clk {
int flags;
};
+#define imx_clk_busy_divider(name, parent_name, reg, shift, width, busy_reg, busy_shift) \
+ imx_clk_hw_busy_divider(name, parent_name, reg, shift, width, busy_reg, busy_shift)->clk
+
+#define imx_clk_busy_mux(name, reg, shift, width, busy_reg, busy_shift, parent_names, num_parents) \
+ imx_clk_hw_busy_mux(name, reg, shift, width, busy_reg, busy_shift, parent_names, num_parents)->clk
+
+#define imx_clk_cpu(name, parent_name, div, mux, pll, step) \
+ imx_clk_hw_cpu(name, parent_name, div, mux, pll, step)->clk
+
+#define clk_register_gate2(dev, name, parent_name, flags, reg, bit_idx, \
+ cgr_val, clk_gate_flags, lock, share_count) \
+ clk_hw_register_gate2(dev, name, parent_name, flags, reg, bit_idx, \
+ cgr_val, clk_gate_flags, lock, share_count)->clk
+
+#define imx_clk_pllv3(type, name, parent_name, base, div_mask) \
+ imx_clk_hw_pllv3(type, name, parent_name, base, div_mask)->clk
+
+#define imx_clk_pfd(name, parent_name, reg, idx) \
+ imx_clk_hw_pfd(name, parent_name, reg, idx)->clk
+
+#define imx_clk_gate_exclusive(name, parent, reg, shift, exclusive_mask) \
+ imx_clk_hw_gate_exclusive(name, parent, reg, shift, exclusive_mask)->clk
+
+#define imx_clk_fixup_divider(name, parent, reg, shift, width, fixup) \
+ imx_clk_hw_fixup_divider(name, parent, reg, shift, width, fixup)->clk
+
+#define imx_clk_fixup_mux(name, reg, shift, width, parents, num_parents, fixup) \
+ imx_clk_hw_fixup_mux(name, reg, shift, width, parents, num_parents, fixup)->clk
+
+#define imx_clk_mux_ldb(name, reg, shift, width, parents, num_parents) \
+ imx_clk_hw_mux_ldb(name, reg, shift, width, parents, num_parents)->clk
+
+#define imx_clk_fixed_factor(name, parent, mult, div) \
+ imx_clk_hw_fixed_factor(name, parent, mult, div)->clk
+
+#define imx_clk_divider2(name, parent, reg, shift, width) \
+ imx_clk_hw_divider2(name, parent, reg, shift, width)->clk
+
+#define imx_clk_gate_dis(name, parent, reg, shift) \
+ imx_clk_hw_gate_dis(name, parent, reg, shift)->clk
+
+#define imx_clk_gate_dis_flags(name, parent, reg, shift, flags) \
+ imx_clk_hw_gate_dis_flags(name, parent, reg, shift, flags)->clk
+
+#define imx_clk_gate_flags(name, parent, reg, shift, flags) \
+ imx_clk_hw_gate_flags(name, parent, reg, shift, flags)->clk
+
+#define imx_clk_gate2(name, parent, reg, shift) \
+ imx_clk_hw_gate2(name, parent, reg, shift)->clk
+
+#define imx_clk_gate2_flags(name, parent, reg, shift, flags) \
+ imx_clk_hw_gate2_flags(name, parent, reg, shift, flags)->clk
+
+#define imx_clk_gate2_shared(name, parent, reg, shift, share_count) \
+ imx_clk_hw_gate2_shared(name, parent, reg, shift, share_count)->clk
+
+#define imx_clk_gate2_shared2(name, parent, reg, shift, share_count) \
+ imx_clk_hw_gate2_shared2(name, parent, reg, shift, share_count)->clk
+
+#define imx_clk_gate3(name, parent, reg, shift) \
+ imx_clk_hw_gate3(name, parent, reg, shift)->clk
+
+#define imx_clk_gate4(name, parent, reg, shift) \
+ imx_clk_hw_gate4(name, parent, reg, shift)->clk
+
+#define imx_clk_mux(name, reg, shift, width, parents, num_parents) \
+ imx_clk_hw_mux(name, reg, shift, width, parents, num_parents)->clk
+
struct clk *imx_clk_pll14xx(const char *name, const char *parent_name,
void __iomem *base, const struct imx_pll14xx_clk *pll_clk);
@@ -80,13 +150,13 @@ enum imx_pllv3_type {
IMX_PLLV3_AV_IMX7,
};
-struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
+struct clk_hw *imx_clk_hw_pllv3(enum imx_pllv3_type type, const char *name,
const char *parent_name, void __iomem *base, u32 div_mask);
struct clk_hw *imx_clk_pllv4(const char *name, const char *parent_name,
void __iomem *base);
-struct clk *clk_register_gate2(struct device *dev, const char *name,
+struct clk_hw *clk_hw_register_gate2(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 bit_idx, u8 cgr_val,
u8 clk_gate_flags, spinlock_t *lock,
@@ -95,23 +165,26 @@ struct clk *clk_register_gate2(struct device *dev, const char *name,
struct clk * imx_obtain_fixed_clock(
const char *name, unsigned long rate);
+struct clk_hw *imx_obtain_fixed_clock_hw(
+ const char *name, unsigned long rate);
+
struct clk_hw *imx_obtain_fixed_clk_hw(struct device_node *np,
const char *name);
-struct clk *imx_clk_gate_exclusive(const char *name, const char *parent,
+struct clk_hw *imx_clk_hw_gate_exclusive(const char *name, const char *parent,
void __iomem *reg, u8 shift, u32 exclusive_mask);
-struct clk *imx_clk_pfd(const char *name, const char *parent_name,
+struct clk_hw *imx_clk_hw_pfd(const char *name, const char *parent_name,
void __iomem *reg, u8 idx);
struct clk_hw *imx_clk_pfdv2(const char *name, const char *parent_name,
void __iomem *reg, u8 idx);
-struct clk *imx_clk_busy_divider(const char *name, const char *parent_name,
+struct clk_hw *imx_clk_hw_busy_divider(const char *name, const char *parent_name,
void __iomem *reg, u8 shift, u8 width,
void __iomem *busy_reg, u8 busy_shift);
-struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift,
+struct clk_hw *imx_clk_hw_busy_mux(const char *name, void __iomem *reg, u8 shift,
u8 width, void __iomem *busy_reg, u8 busy_shift,
const char * const *parent_names, int num_parents);
@@ -121,11 +194,11 @@ struct clk_hw *imx7ulp_clk_composite(const char *name,
bool rate_present, bool gate_present,
void __iomem *reg);
-struct clk *imx_clk_fixup_divider(const char *name, const char *parent,
+struct clk_hw *imx_clk_hw_fixup_divider(const char *name, const char *parent,
void __iomem *reg, u8 shift, u8 width,
void (*fixup)(u32 *val));
-struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg,
+struct clk_hw *imx_clk_hw_fixup_mux(const char *name, void __iomem *reg,
u8 shift, u8 width, const char * const *parents,
int num_parents, void (*fixup)(u32 *val));
@@ -139,19 +212,19 @@ static inline struct clk_hw *imx_clk_hw_fixed(const char *name, int rate)
return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate);
}
-static inline struct clk *imx_clk_mux_ldb(const char *name, void __iomem *reg,
+static inline struct clk_hw *imx_clk_hw_mux_ldb(const char *name, void __iomem *reg,
u8 shift, u8 width, const char * const *parents,
int num_parents)
{
- return clk_register_mux(NULL, name, parents, num_parents,
+ return clk_hw_register_mux(NULL, name, parents, num_parents,
CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, reg,
shift, width, CLK_MUX_READ_ONLY, &imx_ccm_lock);
}
-static inline struct clk *imx_clk_fixed_factor(const char *name,
+static inline struct clk_hw *imx_clk_hw_fixed_factor(const char *name,
const char *parent, unsigned int mult, unsigned int div)
{
- return clk_register_fixed_factor(NULL, name, parent,
+ return clk_hw_register_fixed_factor(NULL, name, parent,
CLK_SET_RATE_PARENT, mult, div);
}
@@ -188,10 +261,10 @@ static inline struct clk_hw *imx_clk_hw_divider_flags(const char *name,
reg, shift, width, 0, &imx_ccm_lock);
}
-static inline struct clk *imx_clk_divider2(const char *name, const char *parent,
+static inline struct clk_hw *imx_clk_hw_divider2(const char *name, const char *parent,
void __iomem *reg, u8 shift, u8 width)
{
- return clk_register_divider(NULL, name, parent,
+ return clk_hw_register_divider(NULL, name, parent,
CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
reg, shift, width, 0, &imx_ccm_lock);
}
@@ -212,10 +285,10 @@ static inline struct clk *imx_clk_gate(const char *name, const char *parent,
shift, 0, &imx_ccm_lock);
}
-static inline struct clk *imx_clk_gate_flags(const char *name, const char *parent,
+static inline struct clk_hw *imx_clk_hw_gate_flags(const char *name, const char *parent,
void __iomem *reg, u8 shift, unsigned long flags)
{
- return clk_register_gate(NULL, name, parent, flags | CLK_SET_RATE_PARENT, reg,
+ return clk_hw_register_gate(NULL, name, parent, flags | CLK_SET_RATE_PARENT, reg,
shift, 0, &imx_ccm_lock);
}
@@ -226,47 +299,47 @@ static inline struct clk_hw *imx_clk_hw_gate(const char *name, const char *paren
shift, 0, &imx_ccm_lock);
}
-static inline struct clk *imx_clk_gate_dis(const char *name, const char *parent,
+static inline struct clk_hw *imx_clk_hw_gate_dis(const char *name, const char *parent,
void __iomem *reg, u8 shift)
{
- return clk_register_gate(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
+ return clk_hw_register_gate(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
shift, CLK_GATE_SET_TO_DISABLE, &imx_ccm_lock);
}
-static inline struct clk *imx_clk_gate_dis_flags(const char *name, const char *parent,
+static inline struct clk_hw *imx_clk_hw_gate_dis_flags(const char *name, const char *parent,
void __iomem *reg, u8 shift, unsigned long flags)
{
- return clk_register_gate(NULL, name, parent, flags | CLK_SET_RATE_PARENT, reg,
+ return clk_hw_register_gate(NULL, name, parent, flags | CLK_SET_RATE_PARENT, reg,
shift, CLK_GATE_SET_TO_DISABLE, &imx_ccm_lock);
}
-static inline struct clk *imx_clk_gate2(const char *name, const char *parent,
+static inline struct clk_hw *imx_clk_hw_gate2(const char *name, const char *parent,
void __iomem *reg, u8 shift)
{
- return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
+ return clk_hw_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
shift, 0x3, 0, &imx_ccm_lock, NULL);
}
-static inline struct clk *imx_clk_gate2_flags(const char *name, const char *parent,
+static inline struct clk_hw *imx_clk_hw_gate2_flags(const char *name, const char *parent,
void __iomem *reg, u8 shift, unsigned long flags)
{
- return clk_register_gate2(NULL, name, parent, flags | CLK_SET_RATE_PARENT, reg,
+ return clk_hw_register_gate2(NULL, name, parent, flags | CLK_SET_RATE_PARENT, reg,
shift, 0x3, 0, &imx_ccm_lock, NULL);
}
-static inline struct clk *imx_clk_gate2_shared(const char *name,
+static inline struct clk_hw *imx_clk_hw_gate2_shared(const char *name,
const char *parent, void __iomem *reg, u8 shift,
unsigned int *share_count)
{
- return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
+ return clk_hw_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
shift, 0x3, 0, &imx_ccm_lock, share_count);
}
-static inline struct clk *imx_clk_gate2_shared2(const char *name,
+static inline struct clk_hw *imx_clk_hw_gate2_shared2(const char *name,
const char *parent, void __iomem *reg, u8 shift,
unsigned int *share_count)
{
- return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT |
+ return clk_hw_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT |
CLK_OPS_PARENT_ENABLE, reg, shift, 0x3, 0,
&imx_ccm_lock, share_count);
}
@@ -278,10 +351,10 @@ static inline struct clk *imx_clk_gate2_cgr(const char *name,
shift, cgr_val, 0, &imx_ccm_lock, NULL);
}
-static inline struct clk *imx_clk_gate3(const char *name, const char *parent,
+static inline struct clk_hw *imx_clk_hw_gate3(const char *name, const char *parent,
void __iomem *reg, u8 shift)
{
- return clk_register_gate(NULL, name, parent,
+ return clk_hw_register_gate(NULL, name, parent,
CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
reg, shift, 0, &imx_ccm_lock);
}
@@ -295,10 +368,10 @@ static inline struct clk *imx_clk_gate3_flags(const char *name,
reg, shift, 0, &imx_ccm_lock);
}
-static inline struct clk *imx_clk_gate4(const char *name, const char *parent,
+static inline struct clk_hw *imx_clk_hw_gate4(const char *name, const char *parent,
void __iomem *reg, u8 shift)
{
- return clk_register_gate2(NULL, name, parent,
+ return clk_hw_register_gate2(NULL, name, parent,
CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
reg, shift, 0x3, 0, &imx_ccm_lock, NULL);
}
@@ -312,11 +385,11 @@ static inline struct clk *imx_clk_gate4_flags(const char *name,
reg, shift, 0x3, 0, &imx_ccm_lock, NULL);
}
-static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg,
+static inline struct clk_hw *imx_clk_hw_mux(const char *name, void __iomem *reg,
u8 shift, u8 width, const char * const *parents,
int num_parents)
{
- return clk_register_mux(NULL, name, parents, num_parents,
+ return clk_hw_register_mux(NULL, name, parents, num_parents,
CLK_SET_RATE_NO_REPARENT, reg, shift,
width, 0, &imx_ccm_lock);
}
@@ -373,7 +446,7 @@ static inline struct clk_hw *imx_clk_hw_mux_flags(const char *name,
reg, shift, width, 0, &imx_ccm_lock);
}
-struct clk *imx_clk_cpu(const char *name, const char *parent_name,
+struct clk_hw *imx_clk_hw_cpu(const char *name, const char *parent_name,
struct clk *div, struct clk *mux, struct clk *pll,
struct clk *step);
diff --git a/drivers/clk/ingenic/Makefile b/drivers/clk/ingenic/Makefile
index ab58a6a862a5..250570a809d3 100644
--- a/drivers/clk/ingenic/Makefile
+++ b/drivers/clk/ingenic/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_INGENIC_CGU_COMMON) += cgu.o
+obj-$(CONFIG_INGENIC_CGU_COMMON) += cgu.o pm.o
obj-$(CONFIG_INGENIC_CGU_JZ4740) += jz4740-cgu.o
obj-$(CONFIG_INGENIC_CGU_JZ4725B) += jz4725b-cgu.o
obj-$(CONFIG_INGENIC_CGU_JZ4770) += jz4770-cgu.o
diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c
index 92c331427513..6e963031cd87 100644
--- a/drivers/clk/ingenic/cgu.c
+++ b/drivers/clk/ingenic/cgu.c
@@ -375,8 +375,11 @@ ingenic_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
div_reg = readl(cgu->base + clk_info->div.reg);
div = (div_reg >> clk_info->div.shift) &
GENMASK(clk_info->div.bits - 1, 0);
- div += 1;
- div *= clk_info->div.div;
+
+ if (clk_info->div.div_table)
+ div = clk_info->div.div_table[div];
+ else
+ div = (div + 1) * clk_info->div.div;
rate /= div;
} else if (clk_info->type & CGU_CLK_FIXDIV) {
@@ -386,16 +389,37 @@ ingenic_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
return rate;
}
+static unsigned int
+ingenic_clk_calc_hw_div(const struct ingenic_cgu_clk_info *clk_info,
+ unsigned int div)
+{
+ unsigned int i;
+
+ for (i = 0; i < (1 << clk_info->div.bits)
+ && clk_info->div.div_table[i]; i++) {
+ if (clk_info->div.div_table[i] >= div)
+ return i;
+ }
+
+ return i - 1;
+}
+
static unsigned
ingenic_clk_calc_div(const struct ingenic_cgu_clk_info *clk_info,
unsigned long parent_rate, unsigned long req_rate)
{
- unsigned div;
+ unsigned int div, hw_div;
/* calculate the divide */
div = DIV_ROUND_UP(parent_rate, req_rate);
- /* and impose hardware constraints */
+ if (clk_info->div.div_table) {
+ hw_div = ingenic_clk_calc_hw_div(clk_info, div);
+
+ return clk_info->div.div_table[hw_div];
+ }
+
+ /* Impose hardware constraints */
div = min_t(unsigned, div, 1 << clk_info->div.bits);
div = max_t(unsigned, div, 1);
@@ -438,7 +462,7 @@ ingenic_clk_set_rate(struct clk_hw *hw, unsigned long req_rate,
const struct ingenic_cgu_clk_info *clk_info;
const unsigned timeout = 100;
unsigned long rate, flags;
- unsigned div, i;
+ unsigned int hw_div, div, i;
u32 reg, mask;
int ret = 0;
@@ -451,13 +475,18 @@ ingenic_clk_set_rate(struct clk_hw *hw, unsigned long req_rate,
if (rate != req_rate)
return -EINVAL;
+ if (clk_info->div.div_table)
+ hw_div = ingenic_clk_calc_hw_div(clk_info, div);
+ else
+ hw_div = ((div / clk_info->div.div) - 1);
+
spin_lock_irqsave(&cgu->lock, flags);
reg = readl(cgu->base + clk_info->div.reg);
/* update the divide */
mask = GENMASK(clk_info->div.bits - 1, 0);
reg &= ~(mask << clk_info->div.shift);
- reg |= ((div / clk_info->div.div) - 1) << clk_info->div.shift;
+ reg |= hw_div << clk_info->div.shift;
/* clear the stop bit */
if (clk_info->div.stop_bit != -1)
diff --git a/drivers/clk/ingenic/cgu.h b/drivers/clk/ingenic/cgu.h
index bfbcf6db437d..0dc8004079ee 100644
--- a/drivers/clk/ingenic/cgu.h
+++ b/drivers/clk/ingenic/cgu.h
@@ -10,6 +10,7 @@
#define __DRIVERS_CLK_INGENIC_CGU_H__
#include <linux/bitops.h>
+#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/spinlock.h>
@@ -79,6 +80,8 @@ struct ingenic_cgu_mux_info {
* isn't one
* @busy_bit: the index of the busy bit within reg, or -1 if there isn't one
* @stop_bit: the index of the stop bit within reg, or -1 if there isn't one
+ * @div_table: optional table to map the value read from the register to the
+ * actual divider value
*/
struct ingenic_cgu_div_info {
unsigned reg;
@@ -88,6 +91,7 @@ struct ingenic_cgu_div_info {
s8 ce_bit;
s8 busy_bit;
s8 stop_bit;
+ const u8 *div_table;
};
/**
diff --git a/drivers/clk/ingenic/jz4725b-cgu.c b/drivers/clk/ingenic/jz4725b-cgu.c
index 8901ea0295b7..2642d36d1e2c 100644
--- a/drivers/clk/ingenic/jz4725b-cgu.c
+++ b/drivers/clk/ingenic/jz4725b-cgu.c
@@ -11,6 +11,7 @@
#include <linux/of.h>
#include <dt-bindings/clock/jz4725b-cgu.h>
#include "cgu.h"
+#include "pm.h"
/* CGU register offsets */
#define CGU_REG_CPCCR 0x00
@@ -33,6 +34,14 @@ static const s8 pll_od_encoding[4] = {
0x0, 0x1, -1, 0x3,
};
+static const u8 jz4725b_cgu_cpccr_div_table[] = {
+ 1, 2, 3, 4, 6, 8,
+};
+
+static const u8 jz4725b_cgu_pll_half_div_table[] = {
+ 2, 1,
+};
+
static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = {
/* External clocks */
@@ -66,37 +75,55 @@ static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = {
[JZ4725B_CLK_PLL_HALF] = {
"pll half", CGU_CLK_DIV,
.parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
- .div = { CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1 },
+ .div = {
+ CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1,
+ jz4725b_cgu_pll_half_div_table,
+ },
},
[JZ4725B_CLK_CCLK] = {
"cclk", CGU_CLK_DIV,
.parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
- .div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 },
+ .div = {
+ CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1,
+ jz4725b_cgu_cpccr_div_table,
+ },
},
[JZ4725B_CLK_HCLK] = {
"hclk", CGU_CLK_DIV,
.parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
- .div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 },
+ .div = {
+ CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1,
+ jz4725b_cgu_cpccr_div_table,
+ },
},
[JZ4725B_CLK_PCLK] = {
"pclk", CGU_CLK_DIV,
.parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
- .div = { CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1 },
+ .div = {
+ CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1,
+ jz4725b_cgu_cpccr_div_table,
+ },
},
[JZ4725B_CLK_MCLK] = {
"mclk", CGU_CLK_DIV,
.parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
- .div = { CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1 },
+ .div = {
+ CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1,
+ jz4725b_cgu_cpccr_div_table,
+ },
},
[JZ4725B_CLK_IPU] = {
"ipu", CGU_CLK_DIV | CGU_CLK_GATE,
.parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
- .div = { CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1 },
+ .div = {
+ CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1,
+ jz4725b_cgu_cpccr_div_table,
+ },
.gate = { CGU_REG_CLKGR, 13 },
},
@@ -227,5 +254,7 @@ static void __init jz4725b_cgu_init(struct device_node *np)
retval = ingenic_cgu_register_clocks(cgu);
if (retval)
pr_err("%s: failed to register CGU Clocks\n", __func__);
+
+ ingenic_cgu_register_syscore_ops(cgu);
}
CLK_OF_DECLARE(jz4725b_cgu, "ingenic,jz4725b-cgu", jz4725b_cgu_init);
diff --git a/drivers/clk/ingenic/jz4740-cgu.c b/drivers/clk/ingenic/jz4740-cgu.c
index c77f4e1506dc..4c0a20949c2c 100644
--- a/drivers/clk/ingenic/jz4740-cgu.c
+++ b/drivers/clk/ingenic/jz4740-cgu.c
@@ -11,8 +11,8 @@
#include <linux/io.h>
#include <linux/of.h>
#include <dt-bindings/clock/jz4740-cgu.h>
-#include <asm/mach-jz4740/clock.h>
#include "cgu.h"
+#include "pm.h"
/* CGU register offsets */
#define CGU_REG_CPCCR 0x00
@@ -49,6 +49,10 @@ static const s8 pll_od_encoding[4] = {
0x0, 0x1, -1, 0x3,
};
+static const u8 jz4740_cgu_cpccr_div_table[] = {
+ 1, 2, 3, 4, 6, 8, 12, 16, 24, 32,
+};
+
static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
/* External clocks */
@@ -88,31 +92,46 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
[JZ4740_CLK_CCLK] = {
"cclk", CGU_CLK_DIV,
.parents = { JZ4740_CLK_PLL, -1, -1, -1 },
- .div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 },
+ .div = {
+ CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1,
+ jz4740_cgu_cpccr_div_table,
+ },
},
[JZ4740_CLK_HCLK] = {
"hclk", CGU_CLK_DIV,
.parents = { JZ4740_CLK_PLL, -1, -1, -1 },
- .div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 },
+ .div = {
+ CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1,
+ jz4740_cgu_cpccr_div_table,
+ },
},
[JZ4740_CLK_PCLK] = {
"pclk", CGU_CLK_DIV,
.parents = { JZ4740_CLK_PLL, -1, -1, -1 },
- .div = { CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1 },
+ .div = {
+ CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1,
+ jz4740_cgu_cpccr_div_table,
+ },
},
[JZ4740_CLK_MCLK] = {
"mclk", CGU_CLK_DIV,
.parents = { JZ4740_CLK_PLL, -1, -1, -1 },
- .div = { CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1 },
+ .div = {
+ CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1,
+ jz4740_cgu_cpccr_div_table,
+ },
},
[JZ4740_CLK_LCD] = {
"lcd", CGU_CLK_DIV | CGU_CLK_GATE,
.parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 },
- .div = { CGU_REG_CPCCR, 16, 1, 5, 22, -1, -1 },
+ .div = {
+ CGU_REG_CPCCR, 16, 1, 5, 22, -1, -1,
+ jz4740_cgu_cpccr_div_table,
+ },
.gate = { CGU_REG_CLKGR, 10 },
},
@@ -219,77 +238,7 @@ static void __init jz4740_cgu_init(struct device_node *np)
retval = ingenic_cgu_register_clocks(cgu);
if (retval)
pr_err("%s: failed to register CGU Clocks\n", __func__);
-}
-CLK_OF_DECLARE(jz4740_cgu, "ingenic,jz4740-cgu", jz4740_cgu_init);
-
-void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode)
-{
- uint32_t lcr = readl(cgu->base + CGU_REG_LCR);
-
- switch (mode) {
- case JZ4740_WAIT_MODE_IDLE:
- lcr &= ~LCR_SLEEP;
- break;
-
- case JZ4740_WAIT_MODE_SLEEP:
- lcr |= LCR_SLEEP;
- break;
- }
-
- writel(lcr, cgu->base + CGU_REG_LCR);
-}
-void jz4740_clock_udc_disable_auto_suspend(void)
-{
- uint32_t clkgr = readl(cgu->base + CGU_REG_CLKGR);
-
- clkgr &= ~CLKGR_UDC;
- writel(clkgr, cgu->base + CGU_REG_CLKGR);
-}
-EXPORT_SYMBOL_GPL(jz4740_clock_udc_disable_auto_suspend);
-
-void jz4740_clock_udc_enable_auto_suspend(void)
-{
- uint32_t clkgr = readl(cgu->base + CGU_REG_CLKGR);
-
- clkgr |= CLKGR_UDC;
- writel(clkgr, cgu->base + CGU_REG_CLKGR);
-}
-EXPORT_SYMBOL_GPL(jz4740_clock_udc_enable_auto_suspend);
-
-#define JZ_CLOCK_GATE_UART0 BIT(0)
-#define JZ_CLOCK_GATE_TCU BIT(1)
-#define JZ_CLOCK_GATE_DMAC BIT(12)
-
-void jz4740_clock_suspend(void)
-{
- uint32_t clkgr, cppcr;
-
- clkgr = readl(cgu->base + CGU_REG_CLKGR);
- clkgr |= JZ_CLOCK_GATE_TCU | JZ_CLOCK_GATE_DMAC | JZ_CLOCK_GATE_UART0;
- writel(clkgr, cgu->base + CGU_REG_CLKGR);
-
- cppcr = readl(cgu->base + CGU_REG_CPPCR);
- cppcr &= ~BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.enable_bit);
- writel(cppcr, cgu->base + CGU_REG_CPPCR);
-}
-
-void jz4740_clock_resume(void)
-{
- uint32_t clkgr, cppcr, stable;
-
- cppcr = readl(cgu->base + CGU_REG_CPPCR);
- cppcr |= BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.enable_bit);
- writel(cppcr, cgu->base + CGU_REG_CPPCR);
-
- stable = BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.stable_bit);
- do {
- cppcr = readl(cgu->base + CGU_REG_CPPCR);
- } while (!(cppcr & stable));
-
- clkgr = readl(cgu->base + CGU_REG_CLKGR);
- clkgr &= ~JZ_CLOCK_GATE_TCU;
- clkgr &= ~JZ_CLOCK_GATE_DMAC;
- clkgr &= ~JZ_CLOCK_GATE_UART0;
- writel(clkgr, cgu->base + CGU_REG_CLKGR);
+ ingenic_cgu_register_syscore_ops(cgu);
}
+CLK_OF_DECLARE(jz4740_cgu, "ingenic,jz4740-cgu", jz4740_cgu_init);
diff --git a/drivers/clk/ingenic/jz4770-cgu.c b/drivers/clk/ingenic/jz4770-cgu.c
index dfce740c25a8..eebc1bea3841 100644
--- a/drivers/clk/ingenic/jz4770-cgu.c
+++ b/drivers/clk/ingenic/jz4770-cgu.c
@@ -9,9 +9,9 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/of.h>
-#include <linux/syscore_ops.h>
#include <dt-bindings/clock/jz4770-cgu.h>
#include "cgu.h"
+#include "pm.h"
/*
* CPM registers offset address definition
@@ -38,9 +38,6 @@
#define CGU_REG_MSC2CDR 0xA8
#define CGU_REG_BCHCDR 0xAC
-/* bits within the LCR register */
-#define LCR_LPM BIT(0) /* Low Power Mode */
-
/* bits within the OPCR register */
#define OPCR_SPENDH BIT(5) /* UHC PHY suspend */
@@ -87,6 +84,10 @@ static const s8 pll_od_encoding[8] = {
0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,
};
+static const u8 jz4770_cgu_cpccr_div_table[] = {
+ 1, 2, 3, 4, 6, 8, 12,
+};
+
static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
/* External clocks */
@@ -144,34 +145,52 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
[JZ4770_CLK_CCLK] = {
"cclk", CGU_CLK_DIV,
.parents = { JZ4770_CLK_PLL0, },
- .div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 },
+ .div = {
+ CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1,
+ jz4770_cgu_cpccr_div_table,
+ },
},
[JZ4770_CLK_H0CLK] = {
"h0clk", CGU_CLK_DIV,
.parents = { JZ4770_CLK_PLL0, },
- .div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 },
+ .div = {
+ CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1,
+ jz4770_cgu_cpccr_div_table,
+ },
},
[JZ4770_CLK_H1CLK] = {
"h1clk", CGU_CLK_DIV | CGU_CLK_GATE,
.parents = { JZ4770_CLK_PLL0, },
- .div = { CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1 },
+ .div = {
+ CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1,
+ jz4770_cgu_cpccr_div_table,
+ },
.gate = { CGU_REG_CLKGR1, 7 },
},
[JZ4770_CLK_H2CLK] = {
"h2clk", CGU_CLK_DIV,
.parents = { JZ4770_CLK_PLL0, },
- .div = { CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1 },
+ .div = {
+ CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1,
+ jz4770_cgu_cpccr_div_table,
+ },
},
[JZ4770_CLK_C1CLK] = {
"c1clk", CGU_CLK_DIV | CGU_CLK_GATE,
.parents = { JZ4770_CLK_PLL0, },
- .div = { CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1 },
+ .div = {
+ CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1,
+ jz4770_cgu_cpccr_div_table,
+ },
.gate = { CGU_REG_OPCR, 31, true }, // disable CCLK stop on idle
},
[JZ4770_CLK_PCLK] = {
"pclk", CGU_CLK_DIV,
.parents = { JZ4770_CLK_PLL0, },
- .div = { CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1 },
+ .div = {
+ CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1,
+ jz4770_cgu_cpccr_div_table,
+ },
},
/* Those divided clocks can connect to PLL0 or PLL1 */
@@ -407,30 +426,6 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
},
};
-#if IS_ENABLED(CONFIG_PM_SLEEP)
-static int jz4770_cgu_pm_suspend(void)
-{
- u32 val;
-
- val = readl(cgu->base + CGU_REG_LCR);
- writel(val | LCR_LPM, cgu->base + CGU_REG_LCR);
- return 0;
-}
-
-static void jz4770_cgu_pm_resume(void)
-{
- u32 val;
-
- val = readl(cgu->base + CGU_REG_LCR);
- writel(val & ~LCR_LPM, cgu->base + CGU_REG_LCR);
-}
-
-static struct syscore_ops jz4770_cgu_pm_ops = {
- .suspend = jz4770_cgu_pm_suspend,
- .resume = jz4770_cgu_pm_resume,
-};
-#endif /* CONFIG_PM_SLEEP */
-
static void __init jz4770_cgu_init(struct device_node *np)
{
int retval;
@@ -444,9 +439,7 @@ static void __init jz4770_cgu_init(struct device_node *np)
if (retval)
pr_err("%s: failed to register CGU Clocks\n", __func__);
-#if IS_ENABLED(CONFIG_PM_SLEEP)
- register_syscore_ops(&jz4770_cgu_pm_ops);
-#endif
+ ingenic_cgu_register_syscore_ops(cgu);
}
/* We only probe via devicetree, no need for a platform driver */
diff --git a/drivers/clk/ingenic/jz4780-cgu.c b/drivers/clk/ingenic/jz4780-cgu.c
index 2464fc4032af..8c67f89df25e 100644
--- a/drivers/clk/ingenic/jz4780-cgu.c
+++ b/drivers/clk/ingenic/jz4780-cgu.c
@@ -12,6 +12,7 @@
#include <linux/of.h>
#include <dt-bindings/clock/jz4780-cgu.h>
#include "cgu.h"
+#include "pm.h"
/* CGU register offsets */
#define CGU_REG_CLOCKCONTROL 0x00
@@ -721,5 +722,7 @@ static void __init jz4780_cgu_init(struct device_node *np)
pr_err("%s: failed to register CGU Clocks\n", __func__);
return;
}
+
+ ingenic_cgu_register_syscore_ops(cgu);
}
CLK_OF_DECLARE(jz4780_cgu, "ingenic,jz4780-cgu", jz4780_cgu_init);
diff --git a/drivers/clk/ingenic/pm.c b/drivers/clk/ingenic/pm.c
new file mode 100644
index 000000000000..341752b640d2
--- /dev/null
+++ b/drivers/clk/ingenic/pm.c
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Paul Cercueil <paul@crapouillou.net>
+ */
+
+#include "cgu.h"
+#include "pm.h"
+
+#include <linux/io.h>
+#include <linux/syscore_ops.h>
+
+#define CGU_REG_LCR 0x04
+
+#define LCR_LOW_POWER_MODE BIT(0)
+
+static void __iomem * __maybe_unused ingenic_cgu_base;
+
+static int __maybe_unused ingenic_cgu_pm_suspend(void)
+{
+ u32 val = readl(ingenic_cgu_base + CGU_REG_LCR);
+
+ writel(val | LCR_LOW_POWER_MODE, ingenic_cgu_base + CGU_REG_LCR);
+
+ return 0;
+}
+
+static void __maybe_unused ingenic_cgu_pm_resume(void)
+{
+ u32 val = readl(ingenic_cgu_base + CGU_REG_LCR);
+
+ writel(val & ~LCR_LOW_POWER_MODE, ingenic_cgu_base + CGU_REG_LCR);
+}
+
+static struct syscore_ops __maybe_unused ingenic_cgu_pm_ops = {
+ .suspend = ingenic_cgu_pm_suspend,
+ .resume = ingenic_cgu_pm_resume,
+};
+
+void ingenic_cgu_register_syscore_ops(struct ingenic_cgu *cgu)
+{
+ if (IS_ENABLED(CONFIG_PM_SLEEP)) {
+ ingenic_cgu_base = cgu->base;
+ register_syscore_ops(&ingenic_cgu_pm_ops);
+ }
+}
diff --git a/drivers/clk/ingenic/pm.h b/drivers/clk/ingenic/pm.h
new file mode 100644
index 000000000000..fa7540407b6b
--- /dev/null
+++ b/drivers/clk/ingenic/pm.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2019 Paul Cercueil <paul@crapouillou.net>
+ */
+#ifndef DRIVERS_CLK_INGENIC_PM_H
+#define DRIVERS_CLK_INGENIC_PM_H
+
+struct ingenic_cgu;
+
+void ingenic_cgu_register_syscore_ops(struct ingenic_cgu *cgu);
+
+#endif /* DRIVERS_CLK_INGENIC_PM_H */
diff --git a/drivers/clk/keystone/Kconfig b/drivers/clk/keystone/Kconfig
index 0ca63014718a..38aeefb1e808 100644
--- a/drivers/clk/keystone/Kconfig
+++ b/drivers/clk/keystone/Kconfig
@@ -15,3 +15,14 @@ config TI_SCI_CLK
This adds the clock driver support over TI System Control Interface.
If you wish to use clock resources from the PMMC firmware, say Y.
Otherwise, say N.
+
+config TI_SCI_CLK_PROBE_FROM_FW
+ bool "Probe available clocks from firmware"
+ depends on TI_SCI_CLK
+ default n
+ help
+ Forces the TI SCI clock driver to probe available clocks from the
+ firmware. By default, only the used clocks are probed from DT.
+ This is mostly only useful for debugging purposes, and will
+ increase the boot time of the device. If you want the clocks probed
+ from firmware, say Y. Otherwise, say N.
diff --git a/drivers/clk/keystone/sci-clk.c b/drivers/clk/keystone/sci-clk.c
index 4cb70bed89a9..7edf8c8432b6 100644
--- a/drivers/clk/keystone/sci-clk.c
+++ b/drivers/clk/keystone/sci-clk.c
@@ -23,6 +23,7 @@
#include <linux/slab.h>
#include <linux/soc/ti/ti_sci_protocol.h>
#include <linux/bsearch.h>
+#include <linux/list_sort.h>
#define SCI_CLK_SSC_ENABLE BIT(0)
#define SCI_CLK_ALLOW_FREQ_CHANGE BIT(1)
@@ -52,14 +53,16 @@ struct sci_clk_provider {
* @num_parents: Number of parents for this clock
* @provider: Master clock provider
* @flags: Flags for the clock
+ * @node: Link for handling clocks probed via DT
*/
struct sci_clk {
struct clk_hw hw;
u16 dev_id;
- u8 clk_id;
- u8 num_parents;
+ u32 clk_id;
+ u32 num_parents;
struct sci_clk_provider *provider;
u8 flags;
+ struct list_head node;
};
#define to_sci_clk(_hw) container_of(_hw, struct sci_clk, hw)
@@ -218,11 +221,11 @@ static int sci_clk_set_rate(struct clk_hw *hw, unsigned long rate,
static u8 sci_clk_get_parent(struct clk_hw *hw)
{
struct sci_clk *clk = to_sci_clk(hw);
- u8 parent_id;
+ u32 parent_id = 0;
int ret;
ret = clk->provider->ops->get_parent(clk->provider->sci, clk->dev_id,
- clk->clk_id, &parent_id);
+ clk->clk_id, (void *)&parent_id);
if (ret) {
dev_err(clk->provider->dev,
"get-parent failed for dev=%d, clk=%d, ret=%d\n",
@@ -230,7 +233,9 @@ static u8 sci_clk_get_parent(struct clk_hw *hw)
return 0;
}
- return parent_id - clk->clk_id - 1;
+ parent_id = parent_id - clk->clk_id - 1;
+
+ return (u8)parent_id;
}
/**
@@ -280,8 +285,8 @@ static int _sci_clk_build(struct sci_clk_provider *provider,
int i;
int ret = 0;
- name = kasprintf(GFP_KERNEL, "%s:%d:%d", dev_name(provider->dev),
- sci_clk->dev_id, sci_clk->clk_id);
+ name = kasprintf(GFP_KERNEL, "clk:%d:%d", sci_clk->dev_id,
+ sci_clk->clk_id);
init.name = name;
@@ -306,8 +311,7 @@ static int _sci_clk_build(struct sci_clk_provider *provider,
for (i = 0; i < sci_clk->num_parents; i++) {
char *parent_name;
- parent_name = kasprintf(GFP_KERNEL, "%s:%d:%d",
- dev_name(provider->dev),
+ parent_name = kasprintf(GFP_KERNEL, "clk:%d:%d",
sci_clk->dev_id,
sci_clk->clk_id + 1 + i);
if (!parent_name) {
@@ -404,22 +408,9 @@ static const struct of_device_id ti_sci_clk_of_match[] = {
};
MODULE_DEVICE_TABLE(of, ti_sci_clk_of_match);
-/**
- * ti_sci_clk_probe - Probe function for the TI SCI clock driver
- * @pdev: platform device pointer to be probed
- *
- * Probes the TI SCI clock device. Allocates a new clock provider
- * and registers this to the common clock framework. Also applies
- * any required flags to the identified clocks via clock lists
- * supplied from DT. Returns 0 for success, negative error value
- * for failure.
- */
-static int ti_sci_clk_probe(struct platform_device *pdev)
+#ifdef CONFIG_TI_SCI_CLK_PROBE_FROM_FW
+static int ti_sci_scan_clocks_from_fw(struct sci_clk_provider *provider)
{
- struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
- struct sci_clk_provider *provider;
- const struct ti_sci_handle *handle;
int ret;
int num_clks = 0;
struct sci_clk **clks = NULL;
@@ -428,24 +419,14 @@ static int ti_sci_clk_probe(struct platform_device *pdev)
int max_clks = 0;
int clk_id = 0;
int dev_id = 0;
- u8 num_parents;
+ u32 num_parents = 0;
int gap_size = 0;
-
- handle = devm_ti_sci_get_handle(dev);
- if (IS_ERR(handle))
- return PTR_ERR(handle);
-
- provider = devm_kzalloc(dev, sizeof(*provider), GFP_KERNEL);
- if (!provider)
- return -ENOMEM;
-
- provider->sci = handle;
- provider->ops = &handle->ops.clk_ops;
- provider->dev = dev;
+ struct device *dev = provider->dev;
while (1) {
ret = provider->ops->get_num_parents(provider->sci, dev_id,
- clk_id, &num_parents);
+ clk_id,
+ (void *)&num_parents);
if (ret) {
gap_size++;
if (!clk_id) {
@@ -502,6 +483,188 @@ static int ti_sci_clk_probe(struct platform_device *pdev)
devm_kfree(dev, clks);
+ return 0;
+}
+
+#else
+
+static int _cmp_sci_clk_list(void *priv, struct list_head *a,
+ struct list_head *b)
+{
+ struct sci_clk *ca = container_of(a, struct sci_clk, node);
+ struct sci_clk *cb = container_of(b, struct sci_clk, node);
+
+ return _cmp_sci_clk(ca, &cb);
+}
+
+static int ti_sci_scan_clocks_from_dt(struct sci_clk_provider *provider)
+{
+ struct device *dev = provider->dev;
+ struct device_node *np = NULL;
+ int ret;
+ int index;
+ struct of_phandle_args args;
+ struct list_head clks;
+ struct sci_clk *sci_clk, *prev;
+ int num_clks = 0;
+ int num_parents;
+ int clk_id;
+ const char * const clk_names[] = {
+ "clocks", "assigned-clocks", "assigned-clock-parents", NULL
+ };
+ const char * const *clk_name;
+
+ INIT_LIST_HEAD(&clks);
+
+ clk_name = clk_names;
+
+ while (*clk_name) {
+ np = of_find_node_with_property(np, *clk_name);
+ if (!np) {
+ clk_name++;
+ break;
+ }
+
+ if (!of_device_is_available(np))
+ continue;
+
+ index = 0;
+
+ do {
+ ret = of_parse_phandle_with_args(np, *clk_name,
+ "#clock-cells", index,
+ &args);
+ if (ret)
+ break;
+
+ if (args.args_count == 2 && args.np == dev->of_node) {
+ sci_clk = devm_kzalloc(dev, sizeof(*sci_clk),
+ GFP_KERNEL);
+ if (!sci_clk)
+ return -ENOMEM;
+
+ sci_clk->dev_id = args.args[0];
+ sci_clk->clk_id = args.args[1];
+ sci_clk->provider = provider;
+ provider->ops->get_num_parents(provider->sci,
+ sci_clk->dev_id,
+ sci_clk->clk_id,
+ (void *)&sci_clk->num_parents);
+ list_add_tail(&sci_clk->node, &clks);
+
+ num_clks++;
+
+ num_parents = sci_clk->num_parents;
+ if (num_parents == 1)
+ num_parents = 0;
+
+ /*
+ * Linux kernel has inherent limitation
+ * of 255 clock parents at the moment.
+ * Right now, it is not expected that
+ * any mux clock from sci-clk driver
+ * would exceed that limit either, but
+ * the ABI basically provides that
+ * possibility. Print out a warning if
+ * this happens for any clock.
+ */
+ if (num_parents >= 255) {
+ dev_warn(dev, "too many parents for dev=%d, clk=%d (%d), cropping to 255.\n",
+ sci_clk->dev_id,
+ sci_clk->clk_id, num_parents);
+ num_parents = 255;
+ }
+
+ clk_id = args.args[1] + 1;
+
+ while (num_parents--) {
+ sci_clk = devm_kzalloc(dev,
+ sizeof(*sci_clk),
+ GFP_KERNEL);
+ if (!sci_clk)
+ return -ENOMEM;
+ sci_clk->dev_id = args.args[0];
+ sci_clk->clk_id = clk_id++;
+ sci_clk->provider = provider;
+ list_add_tail(&sci_clk->node, &clks);
+
+ num_clks++;
+ }
+ }
+
+ index++;
+ } while (args.np);
+ }
+
+ list_sort(NULL, &clks, _cmp_sci_clk_list);
+
+ provider->clocks = devm_kmalloc_array(dev, num_clks, sizeof(sci_clk),
+ GFP_KERNEL);
+ if (!provider->clocks)
+ return -ENOMEM;
+
+ num_clks = 0;
+ prev = NULL;
+
+ list_for_each_entry(sci_clk, &clks, node) {
+ if (prev && prev->dev_id == sci_clk->dev_id &&
+ prev->clk_id == sci_clk->clk_id)
+ continue;
+
+ provider->clocks[num_clks++] = sci_clk;
+ prev = sci_clk;
+ }
+
+ provider->num_clocks = num_clks;
+
+ return 0;
+}
+#endif
+
+/**
+ * ti_sci_clk_probe - Probe function for the TI SCI clock driver
+ * @pdev: platform device pointer to be probed
+ *
+ * Probes the TI SCI clock device. Allocates a new clock provider
+ * and registers this to the common clock framework. Also applies
+ * any required flags to the identified clocks via clock lists
+ * supplied from DT. Returns 0 for success, negative error value
+ * for failure.
+ */
+static int ti_sci_clk_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct sci_clk_provider *provider;
+ const struct ti_sci_handle *handle;
+ int ret;
+
+ handle = devm_ti_sci_get_handle(dev);
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+
+ provider = devm_kzalloc(dev, sizeof(*provider), GFP_KERNEL);
+ if (!provider)
+ return -ENOMEM;
+
+ provider->sci = handle;
+ provider->ops = &handle->ops.clk_ops;
+ provider->dev = dev;
+
+#ifdef CONFIG_TI_SCI_CLK_PROBE_FROM_FW
+ ret = ti_sci_scan_clocks_from_fw(provider);
+ if (ret) {
+ dev_err(dev, "scan clocks from FW failed: %d\n", ret);
+ return ret;
+ }
+#else
+ ret = ti_sci_scan_clocks_from_dt(provider);
+ if (ret) {
+ dev_err(dev, "scan clocks from DT failed: %d\n", ret);
+ return ret;
+ }
+#endif
+
ret = ti_sci_init_clocks(provider);
if (ret) {
pr_err("ti-sci-init-clocks failed.\n");
diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
index f797f09c6425..ce3d9b300bab 100644
--- a/drivers/clk/mediatek/Kconfig
+++ b/drivers/clk/mediatek/Kconfig
@@ -300,4 +300,10 @@ config COMMON_CLK_MT8516
help
This driver supports MediaTek MT8516 clocks.
+config COMMON_CLK_MT8516_AUDSYS
+ bool "Clock driver for MediaTek MT8516 audsys"
+ depends on COMMON_CLK_MT8516
+ help
+ This driver supports MediaTek MT8516 audsys clocks.
+
endmenu
diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
index f74937b35f68..672de0099eef 100644
--- a/drivers/clk/mediatek/Makefile
+++ b/drivers/clk/mediatek/Makefile
@@ -45,3 +45,4 @@ obj-$(CONFIG_COMMON_CLK_MT8183_MMSYS) += clk-mt8183-mm.o
obj-$(CONFIG_COMMON_CLK_MT8183_VDECSYS) += clk-mt8183-vdec.o
obj-$(CONFIG_COMMON_CLK_MT8183_VENCSYS) += clk-mt8183-venc.o
obj-$(CONFIG_COMMON_CLK_MT8516) += clk-mt8516.o
+obj-$(CONFIG_COMMON_CLK_MT8516_AUDSYS) += clk-mt8516-aud.o
diff --git a/drivers/clk/mediatek/clk-mt8183.c b/drivers/clk/mediatek/clk-mt8183.c
index 9d8651033ae9..1aa5f4059251 100644
--- a/drivers/clk/mediatek/clk-mt8183.c
+++ b/drivers/clk/mediatek/clk-mt8183.c
@@ -395,14 +395,6 @@ static const char * const atb_parents[] = {
"syspll_d5"
};
-static const char * const sspm_parents[] = {
- "clk26m",
- "univpll_d2_d4",
- "syspll_d2_d2",
- "univpll_d2_d2",
- "syspll_d3"
-};
-
static const char * const dpi0_parents[] = {
"clk26m",
"tvdpll_d2",
@@ -606,9 +598,6 @@ static const struct mtk_mux top_muxes[] = {
MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_ATB, "atb_sel",
atb_parents, 0xa0,
0xa4, 0xa8, 0, 2, 7, 0x004, 24),
- MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_SSPM, "sspm_sel",
- sspm_parents, 0xa0,
- 0xa4, 0xa8, 8, 3, 15, 0x004, 25),
MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_DPI0, "dpi0_sel",
dpi0_parents, 0xa0,
0xa4, 0xa8, 16, 4, 23, 0x004, 26),
@@ -947,12 +936,8 @@ static const struct mtk_gate infra_clks[] = {
"fufs_sel", 13),
GATE_INFRA2(CLK_INFRA_MD32_BCLK, "infra_md32_bclk",
"axi_sel", 14),
- GATE_INFRA2(CLK_INFRA_SSPM, "infra_sspm",
- "sspm_sel", 15),
GATE_INFRA2(CLK_INFRA_UNIPRO_MBIST, "infra_unipro_mbist",
"axi_sel", 16),
- GATE_INFRA2(CLK_INFRA_SSPM_BUS_HCLK, "infra_sspm_bus_hclk",
- "axi_sel", 17),
GATE_INFRA2(CLK_INFRA_I2C5, "infra_i2c5",
"i2c_sel", 18),
GATE_INFRA2(CLK_INFRA_I2C5_ARBITER, "infra_i2c5_arbiter",
@@ -986,10 +971,6 @@ static const struct mtk_gate infra_clks[] = {
"msdc50_0_sel", 1),
GATE_INFRA3(CLK_INFRA_MSDC2_SELF, "infra_msdc2_self",
"msdc50_0_sel", 2),
- GATE_INFRA3(CLK_INFRA_SSPM_26M_SELF, "infra_sspm_26m_self",
- "f_f26m_ck", 3),
- GATE_INFRA3(CLK_INFRA_SSPM_32K_SELF, "infra_sspm_32k_self",
- "f_f26m_ck", 4),
GATE_INFRA3(CLK_INFRA_UFS_AXI, "infra_ufs_axi",
"axi_sel", 5),
GATE_INFRA3(CLK_INFRA_I2C6, "infra_i2c6",
diff --git a/drivers/clk/mediatek/clk-mt8516-aud.c b/drivers/clk/mediatek/clk-mt8516-aud.c
new file mode 100644
index 000000000000..6ab3a06dc9d5
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8516-aud.c
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ * Author: James Liao <jamesjj.liao@mediatek.com>
+ * Fabien Parent <fparent@baylibre.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include "clk-mtk.h"
+#include "clk-gate.h"
+
+#include <dt-bindings/clock/mt8516-clk.h>
+
+static const struct mtk_gate_regs aud_cg_regs = {
+ .set_ofs = 0x0,
+ .clr_ofs = 0x0,
+ .sta_ofs = 0x0,
+};
+
+#define GATE_AUD(_id, _name, _parent, _shift) { \
+ .id = _id, \
+ .name = _name, \
+ .parent_name = _parent, \
+ .regs = &aud_cg_regs, \
+ .shift = _shift, \
+ .ops = &mtk_clk_gate_ops_no_setclr, \
+ }
+
+static const struct mtk_gate aud_clks[] __initconst = {
+ GATE_AUD(CLK_AUD_AFE, "aud_afe", "clk26m_ck", 2),
+ GATE_AUD(CLK_AUD_I2S, "aud_i2s", "i2s_infra_bck", 6),
+ GATE_AUD(CLK_AUD_22M, "aud_22m", "rg_aud_engen1", 8),
+ GATE_AUD(CLK_AUD_24M, "aud_24m", "rg_aud_engen2", 9),
+ GATE_AUD(CLK_AUD_INTDIR, "aud_intdir", "rg_aud_spdif_in", 15),
+ GATE_AUD(CLK_AUD_APLL2_TUNER, "aud_apll2_tuner", "rg_aud_engen2", 18),
+ GATE_AUD(CLK_AUD_APLL_TUNER, "aud_apll_tuner", "rg_aud_engen1", 19),
+ GATE_AUD(CLK_AUD_HDMI, "aud_hdmi", "apll12_div4", 20),
+ GATE_AUD(CLK_AUD_SPDF, "aud_spdf", "apll12_div6", 21),
+ GATE_AUD(CLK_AUD_ADC, "aud_adc", "aud_afe", 24),
+ GATE_AUD(CLK_AUD_DAC, "aud_dac", "aud_afe", 25),
+ GATE_AUD(CLK_AUD_DAC_PREDIS, "aud_dac_predis", "aud_afe", 26),
+ GATE_AUD(CLK_AUD_TML, "aud_tml", "aud_afe", 27),
+};
+
+static void __init mtk_audsys_init(struct device_node *node)
+{
+ struct clk_onecell_data *clk_data;
+ int r;
+
+ clk_data = mtk_alloc_clk_data(CLK_AUD_NR_CLK);
+
+ mtk_clk_register_gates(node, aud_clks, ARRAY_SIZE(aud_clks), clk_data);
+
+ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+ if (r)
+ pr_err("%s(): could not register clock provider: %d\n",
+ __func__, r);
+
+}
+CLK_OF_DECLARE(mtk_audsys, "mediatek,mt8516-audsys", mtk_audsys_init);
diff --git a/drivers/clk/mediatek/clk-mt8516.c b/drivers/clk/mediatek/clk-mt8516.c
index 26fe43cc9ea2..9d4261ecc760 100644
--- a/drivers/clk/mediatek/clk-mt8516.c
+++ b/drivers/clk/mediatek/clk-mt8516.c
@@ -231,11 +231,6 @@ static const char * const nfi1x_pad_parents[] __initconst = {
"nfi1x_ck"
};
-static const char * const ddrphycfg_parents[] __initconst = {
- "clk26m_ck",
- "mainpll_d16"
-};
-
static const char * const usb_78m_parents[] __initconst = {
"clk_null",
"clk26m_ck",
diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c
index 7a8ef80e5f2c..3ddd0efc9ee0 100644
--- a/drivers/clk/meson/axg.c
+++ b/drivers/clk/meson/axg.c
@@ -469,11 +469,6 @@ static struct clk_regmap axg_mpll0_div = {
.shift = 16,
.width = 9,
},
- .ssen = {
- .reg_off = HHI_MPLL_CNTL,
- .shift = 25,
- .width = 1,
- },
.misc = {
.reg_off = HHI_PLL_TOP_MISC,
.shift = 0,
@@ -568,6 +563,11 @@ static struct clk_regmap axg_mpll2_div = {
.shift = 16,
.width = 9,
},
+ .ssen = {
+ .reg_off = HHI_MPLL_CNTL,
+ .shift = 25,
+ .width = 1,
+ },
.misc = {
.reg_off = HHI_PLL_TOP_MISC,
.shift = 2,
diff --git a/drivers/clk/meson/clk-mpll.c b/drivers/clk/meson/clk-mpll.c
index f76850d99e59..2d39a8bc367c 100644
--- a/drivers/clk/meson/clk-mpll.c
+++ b/drivers/clk/meson/clk-mpll.c
@@ -115,21 +115,12 @@ static int mpll_set_rate(struct clk_hw *hw,
else
__acquire(mpll->lock);
- /* Enable and set the fractional part */
+ /* Set the fractional part */
meson_parm_write(clk->map, &mpll->sdm, sdm);
- meson_parm_write(clk->map, &mpll->sdm_en, 1);
-
- /* Set additional fractional part enable if required */
- if (MESON_PARM_APPLICABLE(&mpll->ssen))
- meson_parm_write(clk->map, &mpll->ssen, 1);
/* Set the integer divider part */
meson_parm_write(clk->map, &mpll->n2, n2);
- /* Set the magic misc bit if required */
- if (MESON_PARM_APPLICABLE(&mpll->misc))
- meson_parm_write(clk->map, &mpll->misc, 1);
-
if (mpll->lock)
spin_unlock_irqrestore(mpll->lock, flags);
else
@@ -138,6 +129,30 @@ static int mpll_set_rate(struct clk_hw *hw,
return 0;
}
+static void mpll_init(struct clk_hw *hw)
+{
+ struct clk_regmap *clk = to_clk_regmap(hw);
+ struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk);
+
+ if (mpll->init_count)
+ regmap_multi_reg_write(clk->map, mpll->init_regs,
+ mpll->init_count);
+
+ /* Enable the fractional part */
+ meson_parm_write(clk->map, &mpll->sdm_en, 1);
+
+ /* Set spread spectrum if possible */
+ if (MESON_PARM_APPLICABLE(&mpll->ssen)) {
+ unsigned int ss =
+ mpll->flags & CLK_MESON_MPLL_SPREAD_SPECTRUM ? 1 : 0;
+ meson_parm_write(clk->map, &mpll->ssen, ss);
+ }
+
+ /* Set the magic misc bit if required */
+ if (MESON_PARM_APPLICABLE(&mpll->misc))
+ meson_parm_write(clk->map, &mpll->misc, 1);
+}
+
const struct clk_ops meson_clk_mpll_ro_ops = {
.recalc_rate = mpll_recalc_rate,
.round_rate = mpll_round_rate,
@@ -148,6 +163,7 @@ const struct clk_ops meson_clk_mpll_ops = {
.recalc_rate = mpll_recalc_rate,
.round_rate = mpll_round_rate,
.set_rate = mpll_set_rate,
+ .init = mpll_init,
};
EXPORT_SYMBOL_GPL(meson_clk_mpll_ops);
diff --git a/drivers/clk/meson/clk-mpll.h b/drivers/clk/meson/clk-mpll.h
index cf79340006dd..a991d568c43a 100644
--- a/drivers/clk/meson/clk-mpll.h
+++ b/drivers/clk/meson/clk-mpll.h
@@ -18,11 +18,14 @@ struct meson_clk_mpll_data {
struct parm n2;
struct parm ssen;
struct parm misc;
+ const struct reg_sequence *init_regs;
+ unsigned int init_count;
spinlock_t *lock;
u8 flags;
};
#define CLK_MESON_MPLL_ROUND_CLOSEST BIT(0)
+#define CLK_MESON_MPLL_SPREAD_SPECTRUM BIT(1)
extern const struct clk_ops meson_clk_mpll_ro_ops;
extern const struct clk_ops meson_clk_mpll_ops;
diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c
index 739f64fdf1e3..db1c4ed9d54e 100644
--- a/drivers/clk/meson/g12a.c
+++ b/drivers/clk/meson/g12a.c
@@ -150,6 +150,57 @@ static struct clk_regmap g12a_sys_pll = {
},
};
+static struct clk_regmap g12b_sys1_pll_dco = {
+ .data = &(struct meson_clk_pll_data){
+ .en = {
+ .reg_off = HHI_SYS1_PLL_CNTL0,
+ .shift = 28,
+ .width = 1,
+ },
+ .m = {
+ .reg_off = HHI_SYS1_PLL_CNTL0,
+ .shift = 0,
+ .width = 8,
+ },
+ .n = {
+ .reg_off = HHI_SYS1_PLL_CNTL0,
+ .shift = 10,
+ .width = 5,
+ },
+ .l = {
+ .reg_off = HHI_SYS1_PLL_CNTL0,
+ .shift = 31,
+ .width = 1,
+ },
+ .rst = {
+ .reg_off = HHI_SYS1_PLL_CNTL0,
+ .shift = 29,
+ .width = 1,
+ },
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "sys1_pll_dco",
+ .ops = &meson_clk_pll_ro_ops,
+ .parent_names = (const char *[]){ IN_PREFIX "xtal" },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap g12b_sys1_pll = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = HHI_SYS1_PLL_CNTL0,
+ .shift = 16,
+ .width = 3,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "sys1_pll",
+ .ops = &clk_regmap_divider_ro_ops,
+ .parent_names = (const char *[]){ "sys1_pll_dco" },
+ .num_parents = 1,
+ },
+};
+
static struct clk_regmap g12a_sys_pll_div16_en = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_SYS_CPU_CLK_CNTL1,
@@ -167,6 +218,23 @@ static struct clk_regmap g12a_sys_pll_div16_en = {
},
};
+static struct clk_regmap g12b_sys1_pll_div16_en = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = HHI_SYS_CPUB_CLK_CNTL1,
+ .bit_idx = 24,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "sys1_pll_div16_en",
+ .ops = &clk_regmap_gate_ro_ops,
+ .parent_names = (const char *[]){ "sys1_pll" },
+ .num_parents = 1,
+ /*
+ * This clock is used to debug the sys_pll range
+ * Linux should not change it at runtime
+ */
+ },
+};
+
static struct clk_fixed_factor g12a_sys_pll_div16 = {
.mult = 1,
.div = 16,
@@ -178,6 +246,17 @@ static struct clk_fixed_factor g12a_sys_pll_div16 = {
},
};
+static struct clk_fixed_factor g12b_sys1_pll_div16 = {
+ .mult = 1,
+ .div = 16,
+ .hw.init = &(struct clk_init_data){
+ .name = "sys1_pll_div16",
+ .ops = &clk_fixed_factor_ops,
+ .parent_names = (const char *[]){ "sys1_pll_div16_en" },
+ .num_parents = 1,
+ },
+};
+
/* Datasheet names this field as "premux0" */
static struct clk_regmap g12a_cpu_clk_premux0 = {
.data = &(struct clk_regmap_mux_data){
@@ -306,6 +385,150 @@ static struct clk_regmap g12a_cpu_clk = {
},
};
+/* Datasheet names this field as "Final_mux_sel" */
+static struct clk_regmap g12b_cpu_clk = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = HHI_SYS_CPU_CLK_CNTL0,
+ .mask = 0x1,
+ .shift = 11,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "cpu_clk",
+ .ops = &clk_regmap_mux_ro_ops,
+ .parent_names = (const char *[]){ "cpu_clk_dyn",
+ "sys1_pll" },
+ .num_parents = 2,
+ },
+};
+
+/* Datasheet names this field as "premux0" */
+static struct clk_regmap g12b_cpub_clk_premux0 = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = HHI_SYS_CPUB_CLK_CNTL,
+ .mask = 0x3,
+ .shift = 0,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "cpub_clk_dyn0_sel",
+ .ops = &clk_regmap_mux_ro_ops,
+ .parent_names = (const char *[]){ IN_PREFIX "xtal",
+ "fclk_div2",
+ "fclk_div3" },
+ .num_parents = 3,
+ },
+};
+
+/* Datasheet names this field as "mux0_divn_tcnt" */
+static struct clk_regmap g12b_cpub_clk_mux0_div = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = HHI_SYS_CPUB_CLK_CNTL,
+ .shift = 4,
+ .width = 6,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "cpub_clk_dyn0_div",
+ .ops = &clk_regmap_divider_ro_ops,
+ .parent_names = (const char *[]){ "cpub_clk_dyn0_sel" },
+ .num_parents = 1,
+ },
+};
+
+/* Datasheet names this field as "postmux0" */
+static struct clk_regmap g12b_cpub_clk_postmux0 = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = HHI_SYS_CPUB_CLK_CNTL,
+ .mask = 0x1,
+ .shift = 2,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "cpub_clk_dyn0",
+ .ops = &clk_regmap_mux_ro_ops,
+ .parent_names = (const char *[]){ "cpub_clk_dyn0_sel",
+ "cpub_clk_dyn0_div" },
+ .num_parents = 2,
+ },
+};
+
+/* Datasheet names this field as "premux1" */
+static struct clk_regmap g12b_cpub_clk_premux1 = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = HHI_SYS_CPUB_CLK_CNTL,
+ .mask = 0x3,
+ .shift = 16,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "cpub_clk_dyn1_sel",
+ .ops = &clk_regmap_mux_ro_ops,
+ .parent_names = (const char *[]){ IN_PREFIX "xtal",
+ "fclk_div2",
+ "fclk_div3" },
+ .num_parents = 3,
+ },
+};
+
+/* Datasheet names this field as "Mux1_divn_tcnt" */
+static struct clk_regmap g12b_cpub_clk_mux1_div = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = HHI_SYS_CPUB_CLK_CNTL,
+ .shift = 20,
+ .width = 6,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "cpub_clk_dyn1_div",
+ .ops = &clk_regmap_divider_ro_ops,
+ .parent_names = (const char *[]){ "cpub_clk_dyn1_sel" },
+ .num_parents = 1,
+ },
+};
+
+/* Datasheet names this field as "postmux1" */
+static struct clk_regmap g12b_cpub_clk_postmux1 = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = HHI_SYS_CPUB_CLK_CNTL,
+ .mask = 0x1,
+ .shift = 18,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "cpub_clk_dyn1",
+ .ops = &clk_regmap_mux_ro_ops,
+ .parent_names = (const char *[]){ "cpub_clk_dyn1_sel",
+ "cpub_clk_dyn1_div" },
+ .num_parents = 2,
+ },
+};
+
+/* Datasheet names this field as "Final_dyn_mux_sel" */
+static struct clk_regmap g12b_cpub_clk_dyn = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = HHI_SYS_CPUB_CLK_CNTL,
+ .mask = 0x1,
+ .shift = 10,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "cpub_clk_dyn",
+ .ops = &clk_regmap_mux_ro_ops,
+ .parent_names = (const char *[]){ "cpub_clk_dyn0",
+ "cpub_clk_dyn1" },
+ .num_parents = 2,
+ },
+};
+
+/* Datasheet names this field as "Final_mux_sel" */
+static struct clk_regmap g12b_cpub_clk = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = HHI_SYS_CPUB_CLK_CNTL,
+ .mask = 0x1,
+ .shift = 11,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "cpub_clk",
+ .ops = &clk_regmap_mux_ro_ops,
+ .parent_names = (const char *[]){ "cpub_clk_dyn",
+ "sys_pll" },
+ .num_parents = 2,
+ },
+};
+
static struct clk_regmap g12a_cpu_clk_div16_en = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_SYS_CPU_CLK_CNTL1,
@@ -323,6 +546,23 @@ static struct clk_regmap g12a_cpu_clk_div16_en = {
},
};
+static struct clk_regmap g12b_cpub_clk_div16_en = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = HHI_SYS_CPUB_CLK_CNTL1,
+ .bit_idx = 1,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "cpub_clk_div16_en",
+ .ops = &clk_regmap_gate_ro_ops,
+ .parent_names = (const char *[]){ "cpub_clk" },
+ .num_parents = 1,
+ /*
+ * This clock is used to debug the cpu_clk range
+ * Linux should not change it at runtime
+ */
+ },
+};
+
static struct clk_fixed_factor g12a_cpu_clk_div16 = {
.mult = 1,
.div = 16,
@@ -334,6 +574,17 @@ static struct clk_fixed_factor g12a_cpu_clk_div16 = {
},
};
+static struct clk_fixed_factor g12b_cpub_clk_div16 = {
+ .mult = 1,
+ .div = 16,
+ .hw.init = &(struct clk_init_data){
+ .name = "cpub_clk_div16",
+ .ops = &clk_fixed_factor_ops,
+ .parent_names = (const char *[]){ "cpub_clk_div16_en" },
+ .num_parents = 1,
+ },
+};
+
static struct clk_regmap g12a_cpu_clk_apb_div = {
.data = &(struct clk_regmap_div_data){
.offset = HHI_SYS_CPU_CLK_CNTL1,
@@ -462,6 +713,240 @@ static struct clk_regmap g12a_cpu_clk_trace = {
},
};
+static struct clk_fixed_factor g12b_cpub_clk_div2 = {
+ .mult = 1,
+ .div = 2,
+ .hw.init = &(struct clk_init_data){
+ .name = "cpub_clk_div2",
+ .ops = &clk_fixed_factor_ops,
+ .parent_names = (const char *[]){ "cpub_clk" },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_fixed_factor g12b_cpub_clk_div3 = {
+ .mult = 1,
+ .div = 3,
+ .hw.init = &(struct clk_init_data){
+ .name = "cpub_clk_div3",
+ .ops = &clk_fixed_factor_ops,
+ .parent_names = (const char *[]){ "cpub_clk" },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_fixed_factor g12b_cpub_clk_div4 = {
+ .mult = 1,
+ .div = 4,
+ .hw.init = &(struct clk_init_data){
+ .name = "cpub_clk_div4",
+ .ops = &clk_fixed_factor_ops,
+ .parent_names = (const char *[]){ "cpub_clk" },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_fixed_factor g12b_cpub_clk_div5 = {
+ .mult = 1,
+ .div = 5,
+ .hw.init = &(struct clk_init_data){
+ .name = "cpub_clk_div5",
+ .ops = &clk_fixed_factor_ops,
+ .parent_names = (const char *[]){ "cpub_clk" },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_fixed_factor g12b_cpub_clk_div6 = {
+ .mult = 1,
+ .div = 6,
+ .hw.init = &(struct clk_init_data){
+ .name = "cpub_clk_div6",
+ .ops = &clk_fixed_factor_ops,
+ .parent_names = (const char *[]){ "cpub_clk" },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_fixed_factor g12b_cpub_clk_div7 = {
+ .mult = 1,
+ .div = 7,
+ .hw.init = &(struct clk_init_data){
+ .name = "cpub_clk_div7",
+ .ops = &clk_fixed_factor_ops,
+ .parent_names = (const char *[]){ "cpub_clk" },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_fixed_factor g12b_cpub_clk_div8 = {
+ .mult = 1,
+ .div = 8,
+ .hw.init = &(struct clk_init_data){
+ .name = "cpub_clk_div8",
+ .ops = &clk_fixed_factor_ops,
+ .parent_names = (const char *[]){ "cpub_clk" },
+ .num_parents = 1,
+ },
+};
+
+static u32 mux_table_cpub[] = { 1, 2, 3, 4, 5, 6, 7 };
+static struct clk_regmap g12b_cpub_clk_apb_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = HHI_SYS_CPUB_CLK_CNTL1,
+ .mask = 7,
+ .shift = 3,
+ .table = mux_table_cpub,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "cpub_clk_apb_sel",
+ .ops = &clk_regmap_mux_ro_ops,
+ .parent_names = (const char *[]){ "cpub_clk_div2",
+ "cpub_clk_div3",
+ "cpub_clk_div4",
+ "cpub_clk_div5",
+ "cpub_clk_div6",
+ "cpub_clk_div7",
+ "cpub_clk_div8" },
+ .num_parents = 7,
+ },
+};
+
+static struct clk_regmap g12b_cpub_clk_apb = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = HHI_SYS_CPUB_CLK_CNTL1,
+ .bit_idx = 16,
+ .flags = CLK_GATE_SET_TO_DISABLE,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "cpub_clk_apb",
+ .ops = &clk_regmap_gate_ro_ops,
+ .parent_names = (const char *[]){ "cpub_clk_apb_sel" },
+ .num_parents = 1,
+ /*
+ * This clock is set by the ROM monitor code,
+ * Linux should not change it at runtime
+ */
+ },
+};
+
+static struct clk_regmap g12b_cpub_clk_atb_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = HHI_SYS_CPUB_CLK_CNTL1,
+ .mask = 7,
+ .shift = 6,
+ .table = mux_table_cpub,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "cpub_clk_atb_sel",
+ .ops = &clk_regmap_mux_ro_ops,
+ .parent_names = (const char *[]){ "cpub_clk_div2",
+ "cpub_clk_div3",
+ "cpub_clk_div4",
+ "cpub_clk_div5",
+ "cpub_clk_div6",
+ "cpub_clk_div7",
+ "cpub_clk_div8" },
+ .num_parents = 7,
+ },
+};
+
+static struct clk_regmap g12b_cpub_clk_atb = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = HHI_SYS_CPUB_CLK_CNTL1,
+ .bit_idx = 17,
+ .flags = CLK_GATE_SET_TO_DISABLE,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "cpub_clk_atb",
+ .ops = &clk_regmap_gate_ro_ops,
+ .parent_names = (const char *[]){ "cpub_clk_atb_sel" },
+ .num_parents = 1,
+ /*
+ * This clock is set by the ROM monitor code,
+ * Linux should not change it at runtime
+ */
+ },
+};
+
+static struct clk_regmap g12b_cpub_clk_axi_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = HHI_SYS_CPUB_CLK_CNTL1,
+ .mask = 7,
+ .shift = 9,
+ .table = mux_table_cpub,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "cpub_clk_axi_sel",
+ .ops = &clk_regmap_mux_ro_ops,
+ .parent_names = (const char *[]){ "cpub_clk_div2",
+ "cpub_clk_div3",
+ "cpub_clk_div4",
+ "cpub_clk_div5",
+ "cpub_clk_div6",
+ "cpub_clk_div7",
+ "cpub_clk_div8" },
+ .num_parents = 7,
+ },
+};
+
+static struct clk_regmap g12b_cpub_clk_axi = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = HHI_SYS_CPUB_CLK_CNTL1,
+ .bit_idx = 18,
+ .flags = CLK_GATE_SET_TO_DISABLE,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "cpub_clk_axi",
+ .ops = &clk_regmap_gate_ro_ops,
+ .parent_names = (const char *[]){ "cpub_clk_axi_sel" },
+ .num_parents = 1,
+ /*
+ * This clock is set by the ROM monitor code,
+ * Linux should not change it at runtime
+ */
+ },
+};
+
+static struct clk_regmap g12b_cpub_clk_trace_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = HHI_SYS_CPUB_CLK_CNTL1,
+ .mask = 7,
+ .shift = 20,
+ .table = mux_table_cpub,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "cpub_clk_trace_sel",
+ .ops = &clk_regmap_mux_ro_ops,
+ .parent_names = (const char *[]){ "cpub_clk_div2",
+ "cpub_clk_div3",
+ "cpub_clk_div4",
+ "cpub_clk_div5",
+ "cpub_clk_div6",
+ "cpub_clk_div7",
+ "cpub_clk_div8" },
+ .num_parents = 7,
+ },
+};
+
+static struct clk_regmap g12b_cpub_clk_trace = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = HHI_SYS_CPUB_CLK_CNTL1,
+ .bit_idx = 23,
+ .flags = CLK_GATE_SET_TO_DISABLE,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "cpub_clk_trace",
+ .ops = &clk_regmap_gate_ro_ops,
+ .parent_names = (const char *[]){ "cpub_clk_trace_sel" },
+ .num_parents = 1,
+ /*
+ * This clock is set by the ROM monitor code,
+ * Linux should not change it at runtime
+ */
+ },
+};
+
static const struct pll_mult_range g12a_gp0_pll_mult_range = {
.min = 55,
.max = 255,
@@ -865,6 +1350,16 @@ static struct clk_regmap g12a_fclk_div3 = {
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "fclk_div3_div" },
.num_parents = 1,
+ /*
+ * This clock is used by the resident firmware and is required
+ * by the platform to operate correctly.
+ * Until the following condition are met, we need this clock to
+ * be marked as critical:
+ * a) Mark the clock used by a firmware resource, if possible
+ * b) CCF has a clock hand-off mechanism to make the sure the
+ * clock stays on until the proper driver comes along
+ */
+ .flags = CLK_IS_CRITICAL,
},
};
@@ -1001,6 +1496,10 @@ static struct clk_fixed_factor g12a_mpll_prediv = {
},
};
+static const struct reg_sequence g12a_mpll0_init_regs[] = {
+ { .reg = HHI_MPLL_CNTL2, .def = 0x40000033 },
+};
+
static struct clk_regmap g12a_mpll0_div = {
.data = &(struct meson_clk_mpll_data){
.sdm = {
@@ -1024,6 +1523,8 @@ static struct clk_regmap g12a_mpll0_div = {
.width = 1,
},
.lock = &meson_clk_lock,
+ .init_regs = g12a_mpll0_init_regs,
+ .init_count = ARRAY_SIZE(g12a_mpll0_init_regs),
},
.hw.init = &(struct clk_init_data){
.name = "mpll0_div",
@@ -1047,6 +1548,10 @@ static struct clk_regmap g12a_mpll0 = {
},
};
+static const struct reg_sequence g12a_mpll1_init_regs[] = {
+ { .reg = HHI_MPLL_CNTL4, .def = 0x40000033 },
+};
+
static struct clk_regmap g12a_mpll1_div = {
.data = &(struct meson_clk_mpll_data){
.sdm = {
@@ -1070,6 +1575,8 @@ static struct clk_regmap g12a_mpll1_div = {
.width = 1,
},
.lock = &meson_clk_lock,
+ .init_regs = g12a_mpll1_init_regs,
+ .init_count = ARRAY_SIZE(g12a_mpll1_init_regs),
},
.hw.init = &(struct clk_init_data){
.name = "mpll1_div",
@@ -1093,6 +1600,10 @@ static struct clk_regmap g12a_mpll1 = {
},
};
+static const struct reg_sequence g12a_mpll2_init_regs[] = {
+ { .reg = HHI_MPLL_CNTL6, .def = 0x40000033 },
+};
+
static struct clk_regmap g12a_mpll2_div = {
.data = &(struct meson_clk_mpll_data){
.sdm = {
@@ -1116,6 +1627,8 @@ static struct clk_regmap g12a_mpll2_div = {
.width = 1,
},
.lock = &meson_clk_lock,
+ .init_regs = g12a_mpll2_init_regs,
+ .init_count = ARRAY_SIZE(g12a_mpll2_init_regs),
},
.hw.init = &(struct clk_init_data){
.name = "mpll2_div",
@@ -1139,6 +1652,10 @@ static struct clk_regmap g12a_mpll2 = {
},
};
+static const struct reg_sequence g12a_mpll3_init_regs[] = {
+ { .reg = HHI_MPLL_CNTL8, .def = 0x40000033 },
+};
+
static struct clk_regmap g12a_mpll3_div = {
.data = &(struct meson_clk_mpll_data){
.sdm = {
@@ -1162,6 +1679,8 @@ static struct clk_regmap g12a_mpll3_div = {
.width = 1,
},
.lock = &meson_clk_lock,
+ .init_regs = g12a_mpll3_init_regs,
+ .init_count = ARRAY_SIZE(g12a_mpll3_init_regs),
},
.hw.init = &(struct clk_init_data){
.name = "mpll3_div",
@@ -2480,6 +2999,33 @@ static struct clk_regmap g12a_mali = {
},
};
+static struct clk_regmap g12a_ts_div = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = HHI_TS_CLK_CNTL,
+ .shift = 0,
+ .width = 8,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "ts_div",
+ .ops = &clk_regmap_divider_ro_ops,
+ .parent_names = (const char *[]){ "xtal" },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap g12a_ts = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = HHI_TS_CLK_CNTL,
+ .bit_idx = 8,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "ts",
+ .ops = &clk_regmap_gate_ops,
+ .parent_names = (const char *[]){ "ts_div" },
+ .num_parents = 1,
+ },
+};
+
/* Everything Else (EE) domain gates */
static MESON_GATE(g12a_ddr, HHI_GCLK_MPEG0, 0);
static MESON_GATE(g12a_dos, HHI_GCLK_MPEG0, 1);
@@ -2734,8 +3280,8 @@ static struct clk_hw_onecell_data g12a_hw_onecell_data = {
[CLKID_MALI_1_DIV] = &g12a_mali_1_div.hw,
[CLKID_MALI_1] = &g12a_mali_1.hw,
[CLKID_MALI] = &g12a_mali.hw,
- [CLKID_MPLL_5OM_DIV] = &g12a_mpll_50m_div.hw,
- [CLKID_MPLL_5OM] = &g12a_mpll_50m.hw,
+ [CLKID_MPLL_50M_DIV] = &g12a_mpll_50m_div.hw,
+ [CLKID_MPLL_50M] = &g12a_mpll_50m.hw,
[CLKID_SYS_PLL_DIV16_EN] = &g12a_sys_pll_div16_en.hw,
[CLKID_SYS_PLL_DIV16] = &g12a_sys_pll_div16.hw,
[CLKID_CPU_CLK_DYN0_SEL] = &g12a_cpu_clk_premux0.hw,
@@ -2769,6 +3315,257 @@ static struct clk_hw_onecell_data g12a_hw_onecell_data = {
[CLKID_VDEC_HEVCF_SEL] = &g12a_vdec_hevcf_sel.hw,
[CLKID_VDEC_HEVCF_DIV] = &g12a_vdec_hevcf_div.hw,
[CLKID_VDEC_HEVCF] = &g12a_vdec_hevcf.hw,
+ [CLKID_TS_DIV] = &g12a_ts_div.hw,
+ [CLKID_TS] = &g12a_ts.hw,
+ [NR_CLKS] = NULL,
+ },
+ .num = NR_CLKS,
+};
+
+static struct clk_hw_onecell_data g12b_hw_onecell_data = {
+ .hws = {
+ [CLKID_SYS_PLL] = &g12a_sys_pll.hw,
+ [CLKID_FIXED_PLL] = &g12a_fixed_pll.hw,
+ [CLKID_FCLK_DIV2] = &g12a_fclk_div2.hw,
+ [CLKID_FCLK_DIV3] = &g12a_fclk_div3.hw,
+ [CLKID_FCLK_DIV4] = &g12a_fclk_div4.hw,
+ [CLKID_FCLK_DIV5] = &g12a_fclk_div5.hw,
+ [CLKID_FCLK_DIV7] = &g12a_fclk_div7.hw,
+ [CLKID_FCLK_DIV2P5] = &g12a_fclk_div2p5.hw,
+ [CLKID_GP0_PLL] = &g12a_gp0_pll.hw,
+ [CLKID_MPEG_SEL] = &g12a_mpeg_clk_sel.hw,
+ [CLKID_MPEG_DIV] = &g12a_mpeg_clk_div.hw,
+ [CLKID_CLK81] = &g12a_clk81.hw,
+ [CLKID_MPLL0] = &g12a_mpll0.hw,
+ [CLKID_MPLL1] = &g12a_mpll1.hw,
+ [CLKID_MPLL2] = &g12a_mpll2.hw,
+ [CLKID_MPLL3] = &g12a_mpll3.hw,
+ [CLKID_DDR] = &g12a_ddr.hw,
+ [CLKID_DOS] = &g12a_dos.hw,
+ [CLKID_AUDIO_LOCKER] = &g12a_audio_locker.hw,
+ [CLKID_MIPI_DSI_HOST] = &g12a_mipi_dsi_host.hw,
+ [CLKID_ETH_PHY] = &g12a_eth_phy.hw,
+ [CLKID_ISA] = &g12a_isa.hw,
+ [CLKID_PL301] = &g12a_pl301.hw,
+ [CLKID_PERIPHS] = &g12a_periphs.hw,
+ [CLKID_SPICC0] = &g12a_spicc_0.hw,
+ [CLKID_I2C] = &g12a_i2c.hw,
+ [CLKID_SANA] = &g12a_sana.hw,
+ [CLKID_SD] = &g12a_sd.hw,
+ [CLKID_RNG0] = &g12a_rng0.hw,
+ [CLKID_UART0] = &g12a_uart0.hw,
+ [CLKID_SPICC1] = &g12a_spicc_1.hw,
+ [CLKID_HIU_IFACE] = &g12a_hiu_reg.hw,
+ [CLKID_MIPI_DSI_PHY] = &g12a_mipi_dsi_phy.hw,
+ [CLKID_ASSIST_MISC] = &g12a_assist_misc.hw,
+ [CLKID_SD_EMMC_A] = &g12a_emmc_a.hw,
+ [CLKID_SD_EMMC_B] = &g12a_emmc_b.hw,
+ [CLKID_SD_EMMC_C] = &g12a_emmc_c.hw,
+ [CLKID_AUDIO_CODEC] = &g12a_audio_codec.hw,
+ [CLKID_AUDIO] = &g12a_audio.hw,
+ [CLKID_ETH] = &g12a_eth_core.hw,
+ [CLKID_DEMUX] = &g12a_demux.hw,
+ [CLKID_AUDIO_IFIFO] = &g12a_audio_ififo.hw,
+ [CLKID_ADC] = &g12a_adc.hw,
+ [CLKID_UART1] = &g12a_uart1.hw,
+ [CLKID_G2D] = &g12a_g2d.hw,
+ [CLKID_RESET] = &g12a_reset.hw,
+ [CLKID_PCIE_COMB] = &g12a_pcie_comb.hw,
+ [CLKID_PARSER] = &g12a_parser.hw,
+ [CLKID_USB] = &g12a_usb_general.hw,
+ [CLKID_PCIE_PHY] = &g12a_pcie_phy.hw,
+ [CLKID_AHB_ARB0] = &g12a_ahb_arb0.hw,
+ [CLKID_AHB_DATA_BUS] = &g12a_ahb_data_bus.hw,
+ [CLKID_AHB_CTRL_BUS] = &g12a_ahb_ctrl_bus.hw,
+ [CLKID_HTX_HDCP22] = &g12a_htx_hdcp22.hw,
+ [CLKID_HTX_PCLK] = &g12a_htx_pclk.hw,
+ [CLKID_BT656] = &g12a_bt656.hw,
+ [CLKID_USB1_DDR_BRIDGE] = &g12a_usb1_to_ddr.hw,
+ [CLKID_MMC_PCLK] = &g12a_mmc_pclk.hw,
+ [CLKID_UART2] = &g12a_uart2.hw,
+ [CLKID_VPU_INTR] = &g12a_vpu_intr.hw,
+ [CLKID_GIC] = &g12a_gic.hw,
+ [CLKID_SD_EMMC_A_CLK0_SEL] = &g12a_sd_emmc_a_clk0_sel.hw,
+ [CLKID_SD_EMMC_A_CLK0_DIV] = &g12a_sd_emmc_a_clk0_div.hw,
+ [CLKID_SD_EMMC_A_CLK0] = &g12a_sd_emmc_a_clk0.hw,
+ [CLKID_SD_EMMC_B_CLK0_SEL] = &g12a_sd_emmc_b_clk0_sel.hw,
+ [CLKID_SD_EMMC_B_CLK0_DIV] = &g12a_sd_emmc_b_clk0_div.hw,
+ [CLKID_SD_EMMC_B_CLK0] = &g12a_sd_emmc_b_clk0.hw,
+ [CLKID_SD_EMMC_C_CLK0_SEL] = &g12a_sd_emmc_c_clk0_sel.hw,
+ [CLKID_SD_EMMC_C_CLK0_DIV] = &g12a_sd_emmc_c_clk0_div.hw,
+ [CLKID_SD_EMMC_C_CLK0] = &g12a_sd_emmc_c_clk0.hw,
+ [CLKID_MPLL0_DIV] = &g12a_mpll0_div.hw,
+ [CLKID_MPLL1_DIV] = &g12a_mpll1_div.hw,
+ [CLKID_MPLL2_DIV] = &g12a_mpll2_div.hw,
+ [CLKID_MPLL3_DIV] = &g12a_mpll3_div.hw,
+ [CLKID_FCLK_DIV2_DIV] = &g12a_fclk_div2_div.hw,
+ [CLKID_FCLK_DIV3_DIV] = &g12a_fclk_div3_div.hw,
+ [CLKID_FCLK_DIV4_DIV] = &g12a_fclk_div4_div.hw,
+ [CLKID_FCLK_DIV5_DIV] = &g12a_fclk_div5_div.hw,
+ [CLKID_FCLK_DIV7_DIV] = &g12a_fclk_div7_div.hw,
+ [CLKID_FCLK_DIV2P5_DIV] = &g12a_fclk_div2p5_div.hw,
+ [CLKID_HIFI_PLL] = &g12a_hifi_pll.hw,
+ [CLKID_VCLK2_VENCI0] = &g12a_vclk2_venci0.hw,
+ [CLKID_VCLK2_VENCI1] = &g12a_vclk2_venci1.hw,
+ [CLKID_VCLK2_VENCP0] = &g12a_vclk2_vencp0.hw,
+ [CLKID_VCLK2_VENCP1] = &g12a_vclk2_vencp1.hw,
+ [CLKID_VCLK2_VENCT0] = &g12a_vclk2_venct0.hw,
+ [CLKID_VCLK2_VENCT1] = &g12a_vclk2_venct1.hw,
+ [CLKID_VCLK2_OTHER] = &g12a_vclk2_other.hw,
+ [CLKID_VCLK2_ENCI] = &g12a_vclk2_enci.hw,
+ [CLKID_VCLK2_ENCP] = &g12a_vclk2_encp.hw,
+ [CLKID_DAC_CLK] = &g12a_dac_clk.hw,
+ [CLKID_AOCLK] = &g12a_aoclk_gate.hw,
+ [CLKID_IEC958] = &g12a_iec958_gate.hw,
+ [CLKID_ENC480P] = &g12a_enc480p.hw,
+ [CLKID_RNG1] = &g12a_rng1.hw,
+ [CLKID_VCLK2_ENCT] = &g12a_vclk2_enct.hw,
+ [CLKID_VCLK2_ENCL] = &g12a_vclk2_encl.hw,
+ [CLKID_VCLK2_VENCLMMC] = &g12a_vclk2_venclmmc.hw,
+ [CLKID_VCLK2_VENCL] = &g12a_vclk2_vencl.hw,
+ [CLKID_VCLK2_OTHER1] = &g12a_vclk2_other1.hw,
+ [CLKID_FIXED_PLL_DCO] = &g12a_fixed_pll_dco.hw,
+ [CLKID_SYS_PLL_DCO] = &g12a_sys_pll_dco.hw,
+ [CLKID_GP0_PLL_DCO] = &g12a_gp0_pll_dco.hw,
+ [CLKID_HIFI_PLL_DCO] = &g12a_hifi_pll_dco.hw,
+ [CLKID_DMA] = &g12a_dma.hw,
+ [CLKID_EFUSE] = &g12a_efuse.hw,
+ [CLKID_ROM_BOOT] = &g12a_rom_boot.hw,
+ [CLKID_RESET_SEC] = &g12a_reset_sec.hw,
+ [CLKID_SEC_AHB_APB3] = &g12a_sec_ahb_apb3.hw,
+ [CLKID_MPLL_PREDIV] = &g12a_mpll_prediv.hw,
+ [CLKID_VPU_0_SEL] = &g12a_vpu_0_sel.hw,
+ [CLKID_VPU_0_DIV] = &g12a_vpu_0_div.hw,
+ [CLKID_VPU_0] = &g12a_vpu_0.hw,
+ [CLKID_VPU_1_SEL] = &g12a_vpu_1_sel.hw,
+ [CLKID_VPU_1_DIV] = &g12a_vpu_1_div.hw,
+ [CLKID_VPU_1] = &g12a_vpu_1.hw,
+ [CLKID_VPU] = &g12a_vpu.hw,
+ [CLKID_VAPB_0_SEL] = &g12a_vapb_0_sel.hw,
+ [CLKID_VAPB_0_DIV] = &g12a_vapb_0_div.hw,
+ [CLKID_VAPB_0] = &g12a_vapb_0.hw,
+ [CLKID_VAPB_1_SEL] = &g12a_vapb_1_sel.hw,
+ [CLKID_VAPB_1_DIV] = &g12a_vapb_1_div.hw,
+ [CLKID_VAPB_1] = &g12a_vapb_1.hw,
+ [CLKID_VAPB_SEL] = &g12a_vapb_sel.hw,
+ [CLKID_VAPB] = &g12a_vapb.hw,
+ [CLKID_HDMI_PLL_DCO] = &g12a_hdmi_pll_dco.hw,
+ [CLKID_HDMI_PLL_OD] = &g12a_hdmi_pll_od.hw,
+ [CLKID_HDMI_PLL_OD2] = &g12a_hdmi_pll_od2.hw,
+ [CLKID_HDMI_PLL] = &g12a_hdmi_pll.hw,
+ [CLKID_VID_PLL] = &g12a_vid_pll_div.hw,
+ [CLKID_VID_PLL_SEL] = &g12a_vid_pll_sel.hw,
+ [CLKID_VID_PLL_DIV] = &g12a_vid_pll.hw,
+ [CLKID_VCLK_SEL] = &g12a_vclk_sel.hw,
+ [CLKID_VCLK2_SEL] = &g12a_vclk2_sel.hw,
+ [CLKID_VCLK_INPUT] = &g12a_vclk_input.hw,
+ [CLKID_VCLK2_INPUT] = &g12a_vclk2_input.hw,
+ [CLKID_VCLK_DIV] = &g12a_vclk_div.hw,
+ [CLKID_VCLK2_DIV] = &g12a_vclk2_div.hw,
+ [CLKID_VCLK] = &g12a_vclk.hw,
+ [CLKID_VCLK2] = &g12a_vclk2.hw,
+ [CLKID_VCLK_DIV1] = &g12a_vclk_div1.hw,
+ [CLKID_VCLK_DIV2_EN] = &g12a_vclk_div2_en.hw,
+ [CLKID_VCLK_DIV4_EN] = &g12a_vclk_div4_en.hw,
+ [CLKID_VCLK_DIV6_EN] = &g12a_vclk_div6_en.hw,
+ [CLKID_VCLK_DIV12_EN] = &g12a_vclk_div12_en.hw,
+ [CLKID_VCLK2_DIV1] = &g12a_vclk2_div1.hw,
+ [CLKID_VCLK2_DIV2_EN] = &g12a_vclk2_div2_en.hw,
+ [CLKID_VCLK2_DIV4_EN] = &g12a_vclk2_div4_en.hw,
+ [CLKID_VCLK2_DIV6_EN] = &g12a_vclk2_div6_en.hw,
+ [CLKID_VCLK2_DIV12_EN] = &g12a_vclk2_div12_en.hw,
+ [CLKID_VCLK_DIV2] = &g12a_vclk_div2.hw,
+ [CLKID_VCLK_DIV4] = &g12a_vclk_div4.hw,
+ [CLKID_VCLK_DIV6] = &g12a_vclk_div6.hw,
+ [CLKID_VCLK_DIV12] = &g12a_vclk_div12.hw,
+ [CLKID_VCLK2_DIV2] = &g12a_vclk2_div2.hw,
+ [CLKID_VCLK2_DIV4] = &g12a_vclk2_div4.hw,
+ [CLKID_VCLK2_DIV6] = &g12a_vclk2_div6.hw,
+ [CLKID_VCLK2_DIV12] = &g12a_vclk2_div12.hw,
+ [CLKID_CTS_ENCI_SEL] = &g12a_cts_enci_sel.hw,
+ [CLKID_CTS_ENCP_SEL] = &g12a_cts_encp_sel.hw,
+ [CLKID_CTS_VDAC_SEL] = &g12a_cts_vdac_sel.hw,
+ [CLKID_HDMI_TX_SEL] = &g12a_hdmi_tx_sel.hw,
+ [CLKID_CTS_ENCI] = &g12a_cts_enci.hw,
+ [CLKID_CTS_ENCP] = &g12a_cts_encp.hw,
+ [CLKID_CTS_VDAC] = &g12a_cts_vdac.hw,
+ [CLKID_HDMI_TX] = &g12a_hdmi_tx.hw,
+ [CLKID_HDMI_SEL] = &g12a_hdmi_sel.hw,
+ [CLKID_HDMI_DIV] = &g12a_hdmi_div.hw,
+ [CLKID_HDMI] = &g12a_hdmi.hw,
+ [CLKID_MALI_0_SEL] = &g12a_mali_0_sel.hw,
+ [CLKID_MALI_0_DIV] = &g12a_mali_0_div.hw,
+ [CLKID_MALI_0] = &g12a_mali_0.hw,
+ [CLKID_MALI_1_SEL] = &g12a_mali_1_sel.hw,
+ [CLKID_MALI_1_DIV] = &g12a_mali_1_div.hw,
+ [CLKID_MALI_1] = &g12a_mali_1.hw,
+ [CLKID_MALI] = &g12a_mali.hw,
+ [CLKID_MPLL_50M_DIV] = &g12a_mpll_50m_div.hw,
+ [CLKID_MPLL_50M] = &g12a_mpll_50m.hw,
+ [CLKID_SYS_PLL_DIV16_EN] = &g12a_sys_pll_div16_en.hw,
+ [CLKID_SYS_PLL_DIV16] = &g12a_sys_pll_div16.hw,
+ [CLKID_CPU_CLK_DYN0_SEL] = &g12a_cpu_clk_premux0.hw,
+ [CLKID_CPU_CLK_DYN0_DIV] = &g12a_cpu_clk_mux0_div.hw,
+ [CLKID_CPU_CLK_DYN0] = &g12a_cpu_clk_postmux0.hw,
+ [CLKID_CPU_CLK_DYN1_SEL] = &g12a_cpu_clk_premux1.hw,
+ [CLKID_CPU_CLK_DYN1_DIV] = &g12a_cpu_clk_mux1_div.hw,
+ [CLKID_CPU_CLK_DYN1] = &g12a_cpu_clk_postmux1.hw,
+ [CLKID_CPU_CLK_DYN] = &g12a_cpu_clk_dyn.hw,
+ [CLKID_CPU_CLK] = &g12b_cpu_clk.hw,
+ [CLKID_CPU_CLK_DIV16_EN] = &g12a_cpu_clk_div16_en.hw,
+ [CLKID_CPU_CLK_DIV16] = &g12a_cpu_clk_div16.hw,
+ [CLKID_CPU_CLK_APB_DIV] = &g12a_cpu_clk_apb_div.hw,
+ [CLKID_CPU_CLK_APB] = &g12a_cpu_clk_apb.hw,
+ [CLKID_CPU_CLK_ATB_DIV] = &g12a_cpu_clk_atb_div.hw,
+ [CLKID_CPU_CLK_ATB] = &g12a_cpu_clk_atb.hw,
+ [CLKID_CPU_CLK_AXI_DIV] = &g12a_cpu_clk_axi_div.hw,
+ [CLKID_CPU_CLK_AXI] = &g12a_cpu_clk_axi.hw,
+ [CLKID_CPU_CLK_TRACE_DIV] = &g12a_cpu_clk_trace_div.hw,
+ [CLKID_CPU_CLK_TRACE] = &g12a_cpu_clk_trace.hw,
+ [CLKID_PCIE_PLL_DCO] = &g12a_pcie_pll_dco.hw,
+ [CLKID_PCIE_PLL_DCO_DIV2] = &g12a_pcie_pll_dco_div2.hw,
+ [CLKID_PCIE_PLL_OD] = &g12a_pcie_pll_od.hw,
+ [CLKID_PCIE_PLL] = &g12a_pcie_pll.hw,
+ [CLKID_VDEC_1_SEL] = &g12a_vdec_1_sel.hw,
+ [CLKID_VDEC_1_DIV] = &g12a_vdec_1_div.hw,
+ [CLKID_VDEC_1] = &g12a_vdec_1.hw,
+ [CLKID_VDEC_HEVC_SEL] = &g12a_vdec_hevc_sel.hw,
+ [CLKID_VDEC_HEVC_DIV] = &g12a_vdec_hevc_div.hw,
+ [CLKID_VDEC_HEVC] = &g12a_vdec_hevc.hw,
+ [CLKID_VDEC_HEVCF_SEL] = &g12a_vdec_hevcf_sel.hw,
+ [CLKID_VDEC_HEVCF_DIV] = &g12a_vdec_hevcf_div.hw,
+ [CLKID_VDEC_HEVCF] = &g12a_vdec_hevcf.hw,
+ [CLKID_TS_DIV] = &g12a_ts_div.hw,
+ [CLKID_TS] = &g12a_ts.hw,
+ [CLKID_SYS1_PLL_DCO] = &g12b_sys1_pll_dco.hw,
+ [CLKID_SYS1_PLL] = &g12b_sys1_pll.hw,
+ [CLKID_SYS1_PLL_DIV16_EN] = &g12b_sys1_pll_div16_en.hw,
+ [CLKID_SYS1_PLL_DIV16] = &g12b_sys1_pll_div16.hw,
+ [CLKID_CPUB_CLK_DYN0_SEL] = &g12b_cpub_clk_premux0.hw,
+ [CLKID_CPUB_CLK_DYN0_DIV] = &g12b_cpub_clk_mux0_div.hw,
+ [CLKID_CPUB_CLK_DYN0] = &g12b_cpub_clk_postmux0.hw,
+ [CLKID_CPUB_CLK_DYN1_SEL] = &g12b_cpub_clk_premux1.hw,
+ [CLKID_CPUB_CLK_DYN1_DIV] = &g12b_cpub_clk_mux1_div.hw,
+ [CLKID_CPUB_CLK_DYN1] = &g12b_cpub_clk_postmux1.hw,
+ [CLKID_CPUB_CLK_DYN] = &g12b_cpub_clk_dyn.hw,
+ [CLKID_CPUB_CLK] = &g12b_cpub_clk.hw,
+ [CLKID_CPUB_CLK_DIV16_EN] = &g12b_cpub_clk_div16_en.hw,
+ [CLKID_CPUB_CLK_DIV16] = &g12b_cpub_clk_div16.hw,
+ [CLKID_CPUB_CLK_DIV2] = &g12b_cpub_clk_div2.hw,
+ [CLKID_CPUB_CLK_DIV3] = &g12b_cpub_clk_div3.hw,
+ [CLKID_CPUB_CLK_DIV4] = &g12b_cpub_clk_div4.hw,
+ [CLKID_CPUB_CLK_DIV5] = &g12b_cpub_clk_div5.hw,
+ [CLKID_CPUB_CLK_DIV6] = &g12b_cpub_clk_div6.hw,
+ [CLKID_CPUB_CLK_DIV7] = &g12b_cpub_clk_div7.hw,
+ [CLKID_CPUB_CLK_DIV8] = &g12b_cpub_clk_div8.hw,
+ [CLKID_CPUB_CLK_APB_SEL] = &g12b_cpub_clk_apb_sel.hw,
+ [CLKID_CPUB_CLK_APB] = &g12b_cpub_clk_apb.hw,
+ [CLKID_CPUB_CLK_ATB_SEL] = &g12b_cpub_clk_atb_sel.hw,
+ [CLKID_CPUB_CLK_ATB] = &g12b_cpub_clk_atb.hw,
+ [CLKID_CPUB_CLK_AXI_SEL] = &g12b_cpub_clk_axi_sel.hw,
+ [CLKID_CPUB_CLK_AXI] = &g12b_cpub_clk_axi.hw,
+ [CLKID_CPUB_CLK_TRACE_SEL] = &g12b_cpub_clk_trace_sel.hw,
+ [CLKID_CPUB_CLK_TRACE] = &g12b_cpub_clk_trace.hw,
[NR_CLKS] = NULL,
},
.num = NR_CLKS,
@@ -2966,16 +3763,52 @@ static struct clk_regmap *const g12a_clk_regmaps[] = {
&g12a_vdec_hevcf_sel,
&g12a_vdec_hevcf_div,
&g12a_vdec_hevcf,
+ &g12a_ts_div,
+ &g12a_ts,
+ &g12b_cpu_clk,
+ &g12b_sys1_pll_dco,
+ &g12b_sys1_pll,
+ &g12b_sys1_pll_div16_en,
+ &g12b_cpub_clk_premux0,
+ &g12b_cpub_clk_mux0_div,
+ &g12b_cpub_clk_postmux0,
+ &g12b_cpub_clk_premux1,
+ &g12b_cpub_clk_mux1_div,
+ &g12b_cpub_clk_postmux1,
+ &g12b_cpub_clk_dyn,
+ &g12b_cpub_clk,
+ &g12b_cpub_clk_div16_en,
+ &g12b_cpub_clk_apb_sel,
+ &g12b_cpub_clk_apb,
+ &g12b_cpub_clk_atb_sel,
+ &g12b_cpub_clk_atb,
+ &g12b_cpub_clk_axi_sel,
+ &g12b_cpub_clk_axi,
+ &g12b_cpub_clk_trace_sel,
+ &g12b_cpub_clk_trace,
+};
+
+static const struct reg_sequence g12a_init_regs[] = {
+ { .reg = HHI_MPLL_CNTL0, .def = 0x00000543 },
};
static const struct meson_eeclkc_data g12a_clkc_data = {
.regmap_clks = g12a_clk_regmaps,
.regmap_clk_num = ARRAY_SIZE(g12a_clk_regmaps),
- .hw_onecell_data = &g12a_hw_onecell_data
+ .hw_onecell_data = &g12a_hw_onecell_data,
+ .init_regs = g12a_init_regs,
+ .init_count = ARRAY_SIZE(g12a_init_regs),
+};
+
+static const struct meson_eeclkc_data g12b_clkc_data = {
+ .regmap_clks = g12a_clk_regmaps,
+ .regmap_clk_num = ARRAY_SIZE(g12a_clk_regmaps),
+ .hw_onecell_data = &g12b_hw_onecell_data
};
static const struct of_device_id clkc_match_table[] = {
{ .compatible = "amlogic,g12a-clkc", .data = &g12a_clkc_data },
+ { .compatible = "amlogic,g12b-clkc", .data = &g12b_clkc_data },
{}
};
diff --git a/drivers/clk/meson/g12a.h b/drivers/clk/meson/g12a.h
index 39c41af70804..c8aed31fbe17 100644
--- a/drivers/clk/meson/g12a.h
+++ b/drivers/clk/meson/g12a.h
@@ -69,6 +69,8 @@
#define HHI_VDEC4_CLK_CNTL 0x1EC
#define HHI_HDCP22_CLK_CNTL 0x1F0
#define HHI_VAPBCLK_CNTL 0x1F4
+#define HHI_SYS_CPUB_CLK_CNTL1 0x200
+#define HHI_SYS_CPUB_CLK_CNTL 0x208
#define HHI_VPU_CLKB_CNTL 0x20C
#define HHI_GEN_CLK_CNTL 0x228
#define HHI_VDIN_MEAS_CLK_CNTL 0x250
@@ -102,6 +104,13 @@
#define HHI_HDMI_PLL_CNTL5 0x334
#define HHI_HDMI_PLL_CNTL6 0x338
#define HHI_SPICC_CLK_CNTL 0x3dc
+#define HHI_SYS1_PLL_CNTL0 0x380
+#define HHI_SYS1_PLL_CNTL1 0x384
+#define HHI_SYS1_PLL_CNTL2 0x388
+#define HHI_SYS1_PLL_CNTL3 0x38c
+#define HHI_SYS1_PLL_CNTL4 0x390
+#define HHI_SYS1_PLL_CNTL5 0x394
+#define HHI_SYS1_PLL_CNTL6 0x398
/*
* CLKID index values
@@ -166,7 +175,7 @@
#define CLKID_HDMI_DIV 167
#define CLKID_MALI_0_DIV 170
#define CLKID_MALI_1_DIV 173
-#define CLKID_MPLL_5OM_DIV 176
+#define CLKID_MPLL_50M_DIV 176
#define CLKID_SYS_PLL_DIV16_EN 178
#define CLKID_SYS_PLL_DIV16 179
#define CLKID_CPU_CLK_DYN0_SEL 180
@@ -195,8 +204,38 @@
#define CLKID_VDEC_HEVC_DIV 206
#define CLKID_VDEC_HEVCF_SEL 208
#define CLKID_VDEC_HEVCF_DIV 209
+#define CLKID_TS_DIV 211
+#define CLKID_SYS1_PLL_DCO 213
+#define CLKID_SYS1_PLL 214
+#define CLKID_SYS1_PLL_DIV16_EN 215
+#define CLKID_SYS1_PLL_DIV16 216
+#define CLKID_CPUB_CLK_DYN0_SEL 217
+#define CLKID_CPUB_CLK_DYN0_DIV 218
+#define CLKID_CPUB_CLK_DYN0 219
+#define CLKID_CPUB_CLK_DYN1_SEL 220
+#define CLKID_CPUB_CLK_DYN1_DIV 221
+#define CLKID_CPUB_CLK_DYN1 222
+#define CLKID_CPUB_CLK_DYN 223
+#define CLKID_CPUB_CLK 224
+#define CLKID_CPUB_CLK_DIV16_EN 225
+#define CLKID_CPUB_CLK_DIV16 226
+#define CLKID_CPUB_CLK_DIV2 227
+#define CLKID_CPUB_CLK_DIV3 228
+#define CLKID_CPUB_CLK_DIV4 229
+#define CLKID_CPUB_CLK_DIV5 230
+#define CLKID_CPUB_CLK_DIV6 231
+#define CLKID_CPUB_CLK_DIV7 232
+#define CLKID_CPUB_CLK_DIV8 233
+#define CLKID_CPUB_CLK_APB_SEL 234
+#define CLKID_CPUB_CLK_APB 235
+#define CLKID_CPUB_CLK_ATB_SEL 236
+#define CLKID_CPUB_CLK_ATB 237
+#define CLKID_CPUB_CLK_AXI_SEL 238
+#define CLKID_CPUB_CLK_AXI 239
+#define CLKID_CPUB_CLK_TRACE_SEL 240
+#define CLKID_CPUB_CLK_TRACE 241
-#define NR_CLKS 211
+#define NR_CLKS 242
/* include the CLKIDs that have been made part of the DT binding */
#include <dt-bindings/clock/g12a-clkc.h>
diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c
index 29ffb4fde714..dab16d9b1af8 100644
--- a/drivers/clk/meson/gxbb.c
+++ b/drivers/clk/meson/gxbb.c
@@ -679,11 +679,6 @@ static struct clk_regmap gxbb_mpll0_div = {
.shift = 16,
.width = 9,
},
- .ssen = {
- .reg_off = HHI_MPLL_CNTL,
- .shift = 25,
- .width = 1,
- },
.lock = &meson_clk_lock,
},
.hw.init = &(struct clk_init_data){
diff --git a/drivers/clk/meson/meson-eeclk.c b/drivers/clk/meson/meson-eeclk.c
index 37a34c9c3885..6ba2094be257 100644
--- a/drivers/clk/meson/meson-eeclk.c
+++ b/drivers/clk/meson/meson-eeclk.c
@@ -34,6 +34,9 @@ int meson_eeclkc_probe(struct platform_device *pdev)
return PTR_ERR(map);
}
+ if (data->init_count)
+ regmap_multi_reg_write(map, data->init_regs, data->init_count);
+
input = meson_clk_hw_register_input(dev, "xtal", IN_PREFIX "xtal", 0);
if (IS_ERR(input)) {
ret = PTR_ERR(input);
diff --git a/drivers/clk/meson/meson-eeclk.h b/drivers/clk/meson/meson-eeclk.h
index 1b809b1419fe..9ab5d6fa7ccb 100644
--- a/drivers/clk/meson/meson-eeclk.h
+++ b/drivers/clk/meson/meson-eeclk.h
@@ -17,6 +17,8 @@ struct platform_device;
struct meson_eeclkc_data {
struct clk_regmap *const *regmap_clks;
unsigned int regmap_clk_num;
+ const struct reg_sequence *init_regs;
+ unsigned int init_count;
struct clk_hw_onecell_data *hw_onecell_data;
};
diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c
index 37cf0f01bb5d..537219fa573e 100644
--- a/drivers/clk/meson/meson8b.c
+++ b/drivers/clk/meson/meson8b.c
@@ -1761,7 +1761,7 @@ static struct clk_regmap meson8m2_gp_pll = {
},
};
-static const char * const mmeson8b_vpu_0_1_parent_names[] = {
+static const char * const meson8b_vpu_0_1_parent_names[] = {
"fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7"
};
@@ -1778,8 +1778,8 @@ static struct clk_regmap meson8b_vpu_0_sel = {
.hw.init = &(struct clk_init_data){
.name = "vpu_0_sel",
.ops = &clk_regmap_mux_ops,
- .parent_names = mmeson8b_vpu_0_1_parent_names,
- .num_parents = ARRAY_SIZE(mmeson8b_vpu_0_1_parent_names),
+ .parent_names = meson8b_vpu_0_1_parent_names,
+ .num_parents = ARRAY_SIZE(meson8b_vpu_0_1_parent_names),
.flags = CLK_SET_RATE_PARENT,
},
};
@@ -1837,8 +1837,8 @@ static struct clk_regmap meson8b_vpu_1_sel = {
.hw.init = &(struct clk_init_data){
.name = "vpu_1_sel",
.ops = &clk_regmap_mux_ops,
- .parent_names = mmeson8b_vpu_0_1_parent_names,
- .num_parents = ARRAY_SIZE(mmeson8b_vpu_0_1_parent_names),
+ .parent_names = meson8b_vpu_0_1_parent_names,
+ .num_parents = ARRAY_SIZE(meson8b_vpu_0_1_parent_names),
.flags = CLK_SET_RATE_PARENT,
},
};
@@ -2153,6 +2153,132 @@ static struct clk_regmap meson8b_vdec_hevc = {
},
};
+/* TODO: the clock at index 0 is "DDR_PLL" which we don't support yet */
+static const char * const meson8b_cts_amclk_parent_names[] = {
+ "mpll0", "mpll1", "mpll2"
+};
+
+static u32 meson8b_cts_amclk_mux_table[] = { 1, 2, 3 };
+
+static struct clk_regmap meson8b_cts_amclk_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = HHI_AUD_CLK_CNTL,
+ .mask = 0x3,
+ .shift = 9,
+ .table = meson8b_cts_amclk_mux_table,
+ .flags = CLK_MUX_ROUND_CLOSEST,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "cts_amclk_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_names = meson8b_cts_amclk_parent_names,
+ .num_parents = ARRAY_SIZE(meson8b_cts_amclk_parent_names),
+ },
+};
+
+static struct clk_regmap meson8b_cts_amclk_div = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = HHI_AUD_CLK_CNTL,
+ .shift = 0,
+ .width = 8,
+ .flags = CLK_DIVIDER_ROUND_CLOSEST,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "cts_amclk_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_names = (const char *[]){ "cts_amclk_sel" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap meson8b_cts_amclk = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = HHI_AUD_CLK_CNTL,
+ .bit_idx = 8,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "cts_amclk",
+ .ops = &clk_regmap_gate_ops,
+ .parent_names = (const char *[]){ "cts_amclk_div" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+/* TODO: the clock at index 0 is "DDR_PLL" which we don't support yet */
+static const char * const meson8b_cts_mclk_i958_parent_names[] = {
+ "mpll0", "mpll1", "mpll2"
+};
+
+static u32 meson8b_cts_mclk_i958_mux_table[] = { 1, 2, 3 };
+
+static struct clk_regmap meson8b_cts_mclk_i958_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = HHI_AUD_CLK_CNTL2,
+ .mask = 0x3,
+ .shift = 25,
+ .table = meson8b_cts_mclk_i958_mux_table,
+ .flags = CLK_MUX_ROUND_CLOSEST,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "cts_mclk_i958_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_names = meson8b_cts_mclk_i958_parent_names,
+ .num_parents = ARRAY_SIZE(meson8b_cts_mclk_i958_parent_names),
+ },
+};
+
+static struct clk_regmap meson8b_cts_mclk_i958_div = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = HHI_AUD_CLK_CNTL2,
+ .shift = 16,
+ .width = 8,
+ .flags = CLK_DIVIDER_ROUND_CLOSEST,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "cts_mclk_i958_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_names = (const char *[]){ "cts_mclk_i958_sel" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap meson8b_cts_mclk_i958 = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = HHI_AUD_CLK_CNTL2,
+ .bit_idx = 24,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "cts_mclk_i958",
+ .ops = &clk_regmap_gate_ops,
+ .parent_names = (const char *[]){ "cts_mclk_i958_div" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap meson8b_cts_i958 = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = HHI_AUD_CLK_CNTL2,
+ .mask = 0x1,
+ .shift = 27,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "cts_i958",
+ .ops = &clk_regmap_mux_ops,
+ .parent_names = (const char *[]){ "cts_amclk",
+ "cts_mclk_i958" },
+ .num_parents = 2,
+ /*
+ * The parent is specific to origin of the audio data. Let the
+ * consumer choose the appropriate parent.
+ */
+ .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
+ },
+};
+
/* Everything Else (EE) domain gates */
static MESON_GATE(meson8b_ddr, HHI_GCLK_MPEG0, 0);
@@ -2432,6 +2558,13 @@ static struct clk_hw_onecell_data meson8_hw_onecell_data = {
[CLKID_VDEC_HEVC_DIV] = &meson8b_vdec_hevc_div.hw,
[CLKID_VDEC_HEVC_EN] = &meson8b_vdec_hevc_en.hw,
[CLKID_VDEC_HEVC] = &meson8b_vdec_hevc.hw,
+ [CLKID_CTS_AMCLK_SEL] = &meson8b_cts_amclk_sel.hw,
+ [CLKID_CTS_AMCLK_DIV] = &meson8b_cts_amclk_div.hw,
+ [CLKID_CTS_AMCLK] = &meson8b_cts_amclk.hw,
+ [CLKID_CTS_MCLK_I958_SEL] = &meson8b_cts_mclk_i958_sel.hw,
+ [CLKID_CTS_MCLK_I958_DIV] = &meson8b_cts_mclk_i958_div.hw,
+ [CLKID_CTS_MCLK_I958] = &meson8b_cts_mclk_i958.hw,
+ [CLKID_CTS_I958] = &meson8b_cts_i958.hw,
[CLK_NR_CLKS] = NULL,
},
.num = CLK_NR_CLKS,
@@ -2641,6 +2774,13 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = {
[CLKID_VDEC_HEVC_DIV] = &meson8b_vdec_hevc_div.hw,
[CLKID_VDEC_HEVC_EN] = &meson8b_vdec_hevc_en.hw,
[CLKID_VDEC_HEVC] = &meson8b_vdec_hevc.hw,
+ [CLKID_CTS_AMCLK_SEL] = &meson8b_cts_amclk_sel.hw,
+ [CLKID_CTS_AMCLK_DIV] = &meson8b_cts_amclk_div.hw,
+ [CLKID_CTS_AMCLK] = &meson8b_cts_amclk.hw,
+ [CLKID_CTS_MCLK_I958_SEL] = &meson8b_cts_mclk_i958_sel.hw,
+ [CLKID_CTS_MCLK_I958_DIV] = &meson8b_cts_mclk_i958_div.hw,
+ [CLKID_CTS_MCLK_I958] = &meson8b_cts_mclk_i958.hw,
+ [CLKID_CTS_I958] = &meson8b_cts_i958.hw,
[CLK_NR_CLKS] = NULL,
},
.num = CLK_NR_CLKS,
@@ -2852,6 +2992,13 @@ static struct clk_hw_onecell_data meson8m2_hw_onecell_data = {
[CLKID_VDEC_HEVC_DIV] = &meson8b_vdec_hevc_div.hw,
[CLKID_VDEC_HEVC_EN] = &meson8b_vdec_hevc_en.hw,
[CLKID_VDEC_HEVC] = &meson8b_vdec_hevc.hw,
+ [CLKID_CTS_AMCLK_SEL] = &meson8b_cts_amclk_sel.hw,
+ [CLKID_CTS_AMCLK_DIV] = &meson8b_cts_amclk_div.hw,
+ [CLKID_CTS_AMCLK] = &meson8b_cts_amclk.hw,
+ [CLKID_CTS_MCLK_I958_SEL] = &meson8b_cts_mclk_i958_sel.hw,
+ [CLKID_CTS_MCLK_I958_DIV] = &meson8b_cts_mclk_i958_div.hw,
+ [CLKID_CTS_MCLK_I958] = &meson8b_cts_mclk_i958.hw,
+ [CLKID_CTS_I958] = &meson8b_cts_i958.hw,
[CLK_NR_CLKS] = NULL,
},
.num = CLK_NR_CLKS,
@@ -3041,6 +3188,13 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = {
&meson8b_vdec_hevc_div,
&meson8b_vdec_hevc_en,
&meson8b_vdec_hevc,
+ &meson8b_cts_amclk,
+ &meson8b_cts_amclk_sel,
+ &meson8b_cts_amclk_div,
+ &meson8b_cts_mclk_i958_sel,
+ &meson8b_cts_mclk_i958_div,
+ &meson8b_cts_mclk_i958,
+ &meson8b_cts_i958,
};
static const struct meson8b_clk_reset_line {
diff --git a/drivers/clk/meson/meson8b.h b/drivers/clk/meson/meson8b.h
index ed37196187e6..c889fbeec30f 100644
--- a/drivers/clk/meson/meson8b.h
+++ b/drivers/clk/meson/meson8b.h
@@ -30,7 +30,9 @@
#define HHI_SYS_CPU_CLK_CNTL1 0x15c /* 0x57 offset in data sheet */
#define HHI_VID_CLK_DIV 0x164 /* 0x59 offset in data sheet */
#define HHI_MPEG_CLK_CNTL 0x174 /* 0x5d offset in data sheet */
+#define HHI_AUD_CLK_CNTL 0x178 /* 0x5e offset in data sheet */
#define HHI_VID_CLK_CNTL 0x17c /* 0x5f offset in data sheet */
+#define HHI_AUD_CLK_CNTL2 0x190 /* 0x64 offset in data sheet */
#define HHI_VID_CLK_CNTL2 0x194 /* 0x65 offset in data sheet */
#define HHI_VID_DIVIDER_CNTL 0x198 /* 0x66 offset in data sheet */
#define HHI_SYS_CPU_CLK_CNTL0 0x19c /* 0x67 offset in data sheet */
@@ -171,8 +173,12 @@
#define CLKID_VDEC_HEVC_SEL 203
#define CLKID_VDEC_HEVC_DIV 204
#define CLKID_VDEC_HEVC_EN 205
+#define CLKID_CTS_AMCLK_SEL 207
+#define CLKID_CTS_AMCLK_DIV 208
+#define CLKID_CTS_MCLK_I958_SEL 210
+#define CLKID_CTS_MCLK_I958_DIV 211
-#define CLK_NR_CLKS 207
+#define CLK_NR_CLKS 214
/*
* include the CLKID and RESETID that have
diff --git a/drivers/clk/mmp/clk-frac.c b/drivers/clk/mmp/clk-frac.c
index cb43d54735b0..90bf181f191a 100644
--- a/drivers/clk/mmp/clk-frac.c
+++ b/drivers/clk/mmp/clk-frac.c
@@ -78,11 +78,10 @@ static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate,
struct mmp_clk_factor_masks *masks = factor->masks;
int i;
unsigned long val;
- unsigned long prev_rate, rate = 0;
+ unsigned long rate = 0;
unsigned long flags = 0;
for (i = 0; i < factor->ftbl_cnt; i++) {
- prev_rate = rate;
rate = (((prate / 10000) * factor->ftbl[i].den) /
(factor->ftbl[i].num * factor->masks->factor)) * 10000;
if (rate > drate)
diff --git a/drivers/clk/mvebu/kirkwood.c b/drivers/clk/mvebu/kirkwood.c
index 35af3aa18f1c..47680237d0be 100644
--- a/drivers/clk/mvebu/kirkwood.c
+++ b/drivers/clk/mvebu/kirkwood.c
@@ -185,6 +185,11 @@ static void __init mv88f6180_get_clk_ratio(
}
}
+static u32 __init mv98dx1135_get_tclk_freq(void __iomem *sar)
+{
+ return 166666667;
+}
+
static const struct coreclk_soc_desc kirkwood_coreclks = {
.get_tclk_freq = kirkwood_get_tclk_freq,
.get_cpu_freq = kirkwood_get_cpu_freq,
@@ -201,6 +206,14 @@ static const struct coreclk_soc_desc mv88f6180_coreclks = {
.num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios),
};
+static const struct coreclk_soc_desc mv98dx1135_coreclks = {
+ .get_tclk_freq = mv98dx1135_get_tclk_freq,
+ .get_cpu_freq = kirkwood_get_cpu_freq,
+ .get_clk_ratio = kirkwood_get_clk_ratio,
+ .ratios = kirkwood_coreclk_ratios,
+ .num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios),
+};
+
/*
* Clock Gating Control
*/
@@ -325,6 +338,8 @@ static void __init kirkwood_clk_init(struct device_node *np)
if (of_device_is_compatible(np, "marvell,mv88f6180-core-clock"))
mvebu_coreclk_setup(np, &mv88f6180_coreclks);
+ else if (of_device_is_compatible(np, "marvell,mv98dx1135-core-clock"))
+ mvebu_coreclk_setup(np, &mv98dx1135_coreclks);
else
mvebu_coreclk_setup(np, &kirkwood_coreclks);
@@ -339,3 +354,5 @@ CLK_OF_DECLARE(kirkwood_clk, "marvell,kirkwood-core-clock",
kirkwood_clk_init);
CLK_OF_DECLARE(mv88f6180_clk, "marvell,mv88f6180-core-clock",
kirkwood_clk_init);
+CLK_OF_DECLARE(98dx1135_clk, "marvell,mv98dx1135-core-clock",
+ kirkwood_clk_init);
diff --git a/drivers/clk/qcom/gcc-msm8996.c b/drivers/clk/qcom/gcc-msm8996.c
index d2f39a972cad..d004cdaa0e39 100644
--- a/drivers/clk/qcom/gcc-msm8996.c
+++ b/drivers/clk/qcom/gcc-msm8996.c
@@ -130,22 +130,6 @@ static const char * const gcc_xo_gpll0_gpll4_gpll0_early_div[] = {
"gpll0_early_div"
};
-static const struct parent_map gcc_xo_gpll0_gpll2_gpll3_gpll0_early_div_map[] = {
- { P_XO, 0 },
- { P_GPLL0, 1 },
- { P_GPLL2, 2 },
- { P_GPLL3, 3 },
- { P_GPLL0_EARLY_DIV, 6 }
-};
-
-static const char * const gcc_xo_gpll0_gpll2_gpll3_gpll0_early_div[] = {
- "xo",
- "gpll0",
- "gpll2",
- "gpll3",
- "gpll0_early_div"
-};
-
static const struct parent_map gcc_xo_gpll0_gpll1_early_div_gpll1_gpll4_gpll0_early_div_map[] = {
{ P_XO, 0 },
{ P_GPLL0, 1 },
@@ -184,26 +168,6 @@ static const char * const gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll2_early_gpll0_early
"gpll0_early_div"
};
-static const struct parent_map gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll4_gpll0_early_div_map[] = {
- { P_XO, 0 },
- { P_GPLL0, 1 },
- { P_GPLL2, 2 },
- { P_GPLL3, 3 },
- { P_GPLL1, 4 },
- { P_GPLL4, 5 },
- { P_GPLL0_EARLY_DIV, 6 }
-};
-
-static const char * const gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll4_gpll0_early_div[] = {
- "xo",
- "gpll0",
- "gpll2",
- "gpll3",
- "gpll1",
- "gpll4",
- "gpll0_early_div"
-};
-
static struct clk_fixed_factor xo = {
.mult = 1,
.div = 1,
diff --git a/drivers/clk/qcom/gcc-qcs404.c b/drivers/clk/qcom/gcc-qcs404.c
index a54807eb3b28..29cf464dd2c8 100644
--- a/drivers/clk/qcom/gcc-qcs404.c
+++ b/drivers/clk/qcom/gcc-qcs404.c
@@ -2766,6 +2766,13 @@ static const struct qcom_reset_map gcc_qcs404_resets[] = {
[GCC_PCIE_0_PHY_BCR] = { 0x3e004 },
[GCC_PCIE_0_LINK_DOWN_BCR] = { 0x3e038 },
[GCC_PCIEPHY_0_PHY_BCR] = { 0x3e03c },
+ [GCC_PCIE_0_AXI_MASTER_STICKY_ARES] = { 0x3e040, 6},
+ [GCC_PCIE_0_AHB_ARES] = { 0x3e040, 5 },
+ [GCC_PCIE_0_AXI_SLAVE_ARES] = { 0x3e040, 4 },
+ [GCC_PCIE_0_AXI_MASTER_ARES] = { 0x3e040, 3 },
+ [GCC_PCIE_0_CORE_STICKY_ARES] = { 0x3e040, 2 },
+ [GCC_PCIE_0_SLEEP_ARES] = { 0x3e040, 1 },
+ [GCC_PCIE_0_PIPE_ARES] = { 0x3e040, 0 },
[GCC_EMAC_BCR] = { 0x4e000 },
};
diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c
index 679bc7d8950a..a250f59708d8 100644
--- a/drivers/clk/qcom/gdsc.c
+++ b/drivers/clk/qcom/gdsc.c
@@ -141,7 +141,9 @@ static int gdsc_toggle_logic(struct gdsc *sc, enum gdsc_status status)
udelay(1);
}
- return gdsc_poll_status(sc, status);
+ ret = gdsc_poll_status(sc, status);
+ WARN(ret, "%s status stuck at 'o%s'", sc->pd.name, status ? "ff" : "n");
+ return ret;
}
static inline int gdsc_deassert_reset(struct gdsc *sc)
diff --git a/drivers/clk/renesas/clk-div6.c b/drivers/clk/renesas/clk-div6.c
index e98a9f5b3c90..5ca183e70166 100644
--- a/drivers/clk/renesas/clk-div6.c
+++ b/drivers/clk/renesas/clk-div6.c
@@ -30,8 +30,8 @@
* @div: divisor value (1-64)
* @src_shift: Shift to access the register bits to select the parent clock
* @src_width: Number of register bits to select the parent clock (may be 0)
- * @parents: Array to map from valid parent clocks indices to hardware indices
* @nb: Notifier block to save/restore clock state for system resume
+ * @parents: Array to map from valid parent clocks indices to hardware indices
*/
struct div6_clock {
struct clk_hw hw;
@@ -39,8 +39,8 @@ struct div6_clock {
unsigned int div;
u32 src_shift;
u32 src_width;
- u8 *parents;
struct notifier_block nb;
+ u8 parents[];
};
#define to_div6_clock(_hw) container_of(_hw, struct div6_clock, hw)
@@ -221,17 +221,10 @@ struct clk * __init cpg_div6_register(const char *name,
struct clk *clk;
unsigned int i;
- clock = kzalloc(sizeof(*clock), GFP_KERNEL);
+ clock = kzalloc(struct_size(clock, parents, num_parents), GFP_KERNEL);
if (!clock)
return ERR_PTR(-ENOMEM);
- clock->parents = kmalloc_array(num_parents, sizeof(*clock->parents),
- GFP_KERNEL);
- if (!clock->parents) {
- clk = ERR_PTR(-ENOMEM);
- goto free_clock;
- }
-
clock->reg = reg;
/*
@@ -259,7 +252,7 @@ struct clk * __init cpg_div6_register(const char *name,
pr_err("%s: invalid number of parents for DIV6 clock %s\n",
__func__, name);
clk = ERR_PTR(-EINVAL);
- goto free_parents;
+ goto free_clock;
}
/* Filter out invalid parents */
@@ -282,7 +275,7 @@ struct clk * __init cpg_div6_register(const char *name,
clk = clk_register(NULL, &clock->hw);
if (IS_ERR(clk))
- goto free_parents;
+ goto free_clock;
if (notifiers) {
clock->nb.notifier_call = cpg_div6_clock_notifier_call;
@@ -291,8 +284,6 @@ struct clk * __init cpg_div6_register(const char *name,
return clk;
-free_parents:
- kfree(clock->parents);
free_clock:
kfree(clock);
return clk;
diff --git a/drivers/clk/renesas/clk-mstp.c b/drivers/clk/renesas/clk-mstp.c
index 92ece221b0d4..2db9093546c6 100644
--- a/drivers/clk/renesas/clk-mstp.c
+++ b/drivers/clk/renesas/clk-mstp.c
@@ -30,11 +30,12 @@
/**
* struct mstp_clock_group - MSTP gating clocks group
*
- * @data: clocks in this group
+ * @data: clock specifier translation for clocks in this group
* @smstpcr: module stop control register
* @mstpsr: module stop status register (optional)
* @lock: protects writes to SMSTPCR
* @width_8bit: registers are 8-bit, not 32-bit
+ * @clks: clocks in this group
*/
struct mstp_clock_group {
struct clk_onecell_data data;
@@ -42,6 +43,7 @@ struct mstp_clock_group {
void __iomem *mstpsr;
spinlock_t lock;
bool width_8bit;
+ struct clk *clks[];
};
/**
@@ -186,14 +188,13 @@ static void __init cpg_mstp_clocks_init(struct device_node *np)
struct clk **clks;
unsigned int i;
- group = kzalloc(sizeof(*group), GFP_KERNEL);
- clks = kmalloc_array(MSTP_MAX_CLOCKS, sizeof(*clks), GFP_KERNEL);
- if (group == NULL || clks == NULL) {
+ group = kzalloc(struct_size(group, clks, MSTP_MAX_CLOCKS), GFP_KERNEL);
+ if (group == NULL) {
kfree(group);
- kfree(clks);
return;
}
+ clks = group->clks;
spin_lock_init(&group->lock);
group->data.clks = clks;
@@ -203,7 +204,6 @@ static void __init cpg_mstp_clocks_init(struct device_node *np)
if (group->smstpcr == NULL) {
pr_err("%s: failed to remap SMSTPCR\n", __func__);
kfree(group);
- kfree(clks);
return;
}
@@ -297,16 +297,12 @@ found:
return PTR_ERR(clk);
error = pm_clk_create(dev);
- if (error) {
- dev_err(dev, "pm_clk_create failed %d\n", error);
+ if (error)
goto fail_put;
- }
error = pm_clk_add_clk(dev, clk);
- if (error) {
- dev_err(dev, "pm_clk_add_clk %pC failed %d\n", clk, error);
+ if (error)
goto fail_destroy;
- }
return 0;
diff --git a/drivers/clk/renesas/r8a77470-cpg-mssr.c b/drivers/clk/renesas/r8a77470-cpg-mssr.c
index ab0fb10b6bf0..d81ae65f0d18 100644
--- a/drivers/clk/renesas/r8a77470-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a77470-cpg-mssr.c
@@ -175,7 +175,7 @@ static const unsigned int r8a77470_crit_mod_clks[] __initconst = {
*---------------------------------------------------
* 0 0 20 x80 x78 x50
* 0 1 26 x60 x60 x56
- * 1 0 Prohibitted setting
+ * 1 0 Prohibited setting
* 1 1 30 x52 x52 x50
*
* *1 : Table 7.4 indicates VCO output (PLL0 = VCO)
diff --git a/drivers/clk/renesas/r8a774a1-cpg-mssr.c b/drivers/clk/renesas/r8a774a1-cpg-mssr.c
index 76ed7d1bae36..e05bfa200480 100644
--- a/drivers/clk/renesas/r8a774a1-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a774a1-cpg-mssr.c
@@ -113,6 +113,11 @@ static const struct cpg_core_clk r8a774a1_core_clks[] __initconst = {
};
static const struct mssr_mod_clk r8a774a1_mod_clks[] __initconst = {
+ DEF_MOD("tmu4", 121, R8A774A1_CLK_S0D6),
+ DEF_MOD("tmu3", 122, R8A774A1_CLK_S3D2),
+ DEF_MOD("tmu2", 123, R8A774A1_CLK_S3D2),
+ DEF_MOD("tmu1", 124, R8A774A1_CLK_S3D2),
+ DEF_MOD("tmu0", 125, R8A774A1_CLK_CP),
DEF_MOD("fdp1-0", 119, R8A774A1_CLK_S0D1),
DEF_MOD("scif5", 202, R8A774A1_CLK_S3D4),
DEF_MOD("scif4", 203, R8A774A1_CLK_S3D4),
diff --git a/drivers/clk/renesas/r8a7795-cpg-mssr.c b/drivers/clk/renesas/r8a7795-cpg-mssr.c
index 9e9a6f2c31e8..fbc8c75f4314 100644
--- a/drivers/clk/renesas/r8a7795-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a7795-cpg-mssr.c
@@ -138,6 +138,7 @@ static struct mssr_mod_clk r8a7795_mod_clks[] __initdata = {
DEF_MOD("cmt2", 301, R8A7795_CLK_R),
DEF_MOD("cmt1", 302, R8A7795_CLK_R),
DEF_MOD("cmt0", 303, R8A7795_CLK_R),
+ DEF_MOD("tpu0", 304, R8A7795_CLK_S3D4),
DEF_MOD("scif2", 310, R8A7795_CLK_S3D4),
DEF_MOD("sdif3", 311, R8A7795_CLK_SD3),
DEF_MOD("sdif2", 312, R8A7795_CLK_SD2),
@@ -201,6 +202,10 @@ static struct mssr_mod_clk r8a7795_mod_clks[] __initdata = {
DEF_MOD("ehci0", 703, R8A7795_CLK_S3D2),
DEF_MOD("hsusb", 704, R8A7795_CLK_S3D2),
DEF_MOD("hsusb3", 705, R8A7795_CLK_S3D2),
+ DEF_MOD("cmm3", 708, R8A7795_CLK_S2D1),
+ DEF_MOD("cmm2", 709, R8A7795_CLK_S2D1),
+ DEF_MOD("cmm1", 710, R8A7795_CLK_S2D1),
+ DEF_MOD("cmm0", 711, R8A7795_CLK_S2D1),
DEF_MOD("csi21", 713, R8A7795_CLK_CSI0), /* ES1.x */
DEF_MOD("csi20", 714, R8A7795_CLK_CSI0),
DEF_MOD("csi41", 715, R8A7795_CLK_CSI0),
diff --git a/drivers/clk/renesas/r8a7796-cpg-mssr.c b/drivers/clk/renesas/r8a7796-cpg-mssr.c
index d8e9af5d9ae9..90cc6a102602 100644
--- a/drivers/clk/renesas/r8a7796-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a7796-cpg-mssr.c
@@ -134,6 +134,7 @@ static const struct mssr_mod_clk r8a7796_mod_clks[] __initconst = {
DEF_MOD("cmt2", 301, R8A7796_CLK_R),
DEF_MOD("cmt1", 302, R8A7796_CLK_R),
DEF_MOD("cmt0", 303, R8A7796_CLK_R),
+ DEF_MOD("tpu0", 304, R8A7796_CLK_S3D4),
DEF_MOD("scif2", 310, R8A7796_CLK_S3D4),
DEF_MOD("sdif3", 311, R8A7796_CLK_SD3),
DEF_MOD("sdif2", 312, R8A7796_CLK_SD2),
@@ -180,6 +181,9 @@ static const struct mssr_mod_clk r8a7796_mod_clks[] __initconst = {
DEF_MOD("ehci1", 702, R8A7796_CLK_S3D2),
DEF_MOD("ehci0", 703, R8A7796_CLK_S3D2),
DEF_MOD("hsusb", 704, R8A7796_CLK_S3D2),
+ DEF_MOD("cmm2", 709, R8A7796_CLK_S2D1),
+ DEF_MOD("cmm1", 710, R8A7796_CLK_S2D1),
+ DEF_MOD("cmm0", 711, R8A7796_CLK_S2D1),
DEF_MOD("csi20", 714, R8A7796_CLK_CSI0),
DEF_MOD("csi40", 716, R8A7796_CLK_CSI0),
DEF_MOD("du2", 722, R8A7796_CLK_S2D1),
diff --git a/drivers/clk/renesas/r8a77965-cpg-mssr.c b/drivers/clk/renesas/r8a77965-cpg-mssr.c
index 8f87e314d949..b4e8c5b7d515 100644
--- a/drivers/clk/renesas/r8a77965-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a77965-cpg-mssr.c
@@ -132,6 +132,7 @@ static const struct mssr_mod_clk r8a77965_mod_clks[] __initconst = {
DEF_MOD("cmt2", 301, R8A77965_CLK_R),
DEF_MOD("cmt1", 302, R8A77965_CLK_R),
DEF_MOD("cmt0", 303, R8A77965_CLK_R),
+ DEF_MOD("tpu0", 304, R8A77965_CLK_S3D4),
DEF_MOD("scif2", 310, R8A77965_CLK_S3D4),
DEF_MOD("sdif3", 311, R8A77965_CLK_SD3),
DEF_MOD("sdif2", 312, R8A77965_CLK_SD2),
@@ -179,6 +180,9 @@ static const struct mssr_mod_clk r8a77965_mod_clks[] __initconst = {
DEF_MOD("ehci1", 702, R8A77965_CLK_S3D2),
DEF_MOD("ehci0", 703, R8A77965_CLK_S3D2),
DEF_MOD("hsusb", 704, R8A77965_CLK_S3D2),
+ DEF_MOD("cmm3", 708, R8A77965_CLK_S2D1),
+ DEF_MOD("cmm1", 710, R8A77965_CLK_S2D1),
+ DEF_MOD("cmm0", 711, R8A77965_CLK_S2D1),
DEF_MOD("csi20", 714, R8A77965_CLK_CSI0),
DEF_MOD("csi40", 716, R8A77965_CLK_CSI0),
DEF_MOD("du3", 721, R8A77965_CLK_S2D1),
diff --git a/drivers/clk/renesas/r8a77990-cpg-mssr.c b/drivers/clk/renesas/r8a77990-cpg-mssr.c
index 9570404baa58..ceabf55c21c2 100644
--- a/drivers/clk/renesas/r8a77990-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a77990-cpg-mssr.c
@@ -183,6 +183,8 @@ static const struct mssr_mod_clk r8a77990_mod_clks[] __initconst = {
DEF_MOD("ehci0", 703, R8A77990_CLK_S3D2),
DEF_MOD("hsusb", 704, R8A77990_CLK_S3D2),
+ DEF_MOD("cmm1", 710, R8A77990_CLK_S1D1),
+ DEF_MOD("cmm0", 711, R8A77990_CLK_S1D1),
DEF_MOD("csi40", 716, R8A77990_CLK_CSI0),
DEF_MOD("du1", 723, R8A77990_CLK_S1D1),
DEF_MOD("du0", 724, R8A77990_CLK_S1D1),
diff --git a/drivers/clk/renesas/r8a77995-cpg-mssr.c b/drivers/clk/renesas/r8a77995-cpg-mssr.c
index 68707277b17b..962bb337f2e7 100644
--- a/drivers/clk/renesas/r8a77995-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a77995-cpg-mssr.c
@@ -146,6 +146,8 @@ static const struct mssr_mod_clk r8a77995_mod_clks[] __initconst = {
DEF_MOD("vspbs", 627, R8A77995_CLK_S0D1),
DEF_MOD("ehci0", 703, R8A77995_CLK_S3D2),
DEF_MOD("hsusb", 704, R8A77995_CLK_S3D2),
+ DEF_MOD("cmm1", 710, R8A77995_CLK_S1D1),
+ DEF_MOD("cmm0", 711, R8A77995_CLK_S1D1),
DEF_MOD("du1", 723, R8A77995_CLK_S1D1),
DEF_MOD("du0", 724, R8A77995_CLK_S1D1),
DEF_MOD("lvds", 727, R8A77995_CLK_S2D1),
diff --git a/drivers/clk/renesas/r9a06g032-clocks.c b/drivers/clk/renesas/r9a06g032-clocks.c
index 7d042183aa37..b33e1383efe3 100644
--- a/drivers/clk/renesas/r9a06g032-clocks.c
+++ b/drivers/clk/renesas/r9a06g032-clocks.c
@@ -17,6 +17,8 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
+#include <linux/pm_clock.h>
+#include <linux/pm_domain.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <dt-bindings/clock/r9a06g032-sysctrl.h>
@@ -29,6 +31,7 @@ struct r9a06g032_gate {
/* This is used to describe a clock for instantiation */
struct r9a06g032_clkdesc {
const char *name;
+ uint32_t managed: 1;
uint32_t type: 3;
uint32_t index: 8;
uint32_t source : 8; /* source index + 1 (0 == none) */
@@ -61,7 +64,11 @@ struct r9a06g032_clkdesc {
#define D_GATE(_idx, _n, _src, ...) \
{ .type = K_GATE, .index = R9A06G032_##_idx, \
.source = 1 + R9A06G032_##_src, .name = _n, \
- .gate = I_GATE(__VA_ARGS__), }
+ .gate = I_GATE(__VA_ARGS__) }
+#define D_MODULE(_idx, _n, _src, ...) \
+ { .type = K_GATE, .index = R9A06G032_##_idx, \
+ .source = 1 + R9A06G032_##_src, .name = _n, \
+ .managed = 1, .gate = I_GATE(__VA_ARGS__) }
#define D_ROOT(_idx, _n, _mul, _div) \
{ .type = K_FFC, .index = R9A06G032_##_idx, .name = _n, \
.div = _div, .mul = _mul }
@@ -122,7 +129,7 @@ enum { K_GATE = 0, K_FFC, K_DIV, K_BITSEL, K_DUALGATE };
#define R9A06G032_CLOCK_COUNT (R9A06G032_UART_GROUP_34567 + 1)
-static const struct r9a06g032_clkdesc r9a06g032_clocks[] __initconst = {
+static const struct r9a06g032_clkdesc r9a06g032_clocks[] = {
D_ROOT(CLKOUT, "clkout", 25, 1),
D_ROOT(CLK_PLL_USB, "clk_pll_usb", 12, 10),
D_FFC(CLKOUT_D10, "clkout_d10", CLKOUT, 10),
@@ -171,7 +178,7 @@ static const struct r9a06g032_clkdesc r9a06g032_clocks[] __initconst = {
D_GATE(CLK_P6_PG2, "clk_p6_pg2", DIV_P6_PG, 0x8a3, 0x8a4, 0x8a5, 0, 0xb61, 0, 0),
D_GATE(CLK_P6_PG3, "clk_p6_pg3", DIV_P6_PG, 0x8a6, 0x8a7, 0x8a8, 0, 0xb62, 0, 0),
D_GATE(CLK_P6_PG4, "clk_p6_pg4", DIV_P6_PG, 0x8a9, 0x8aa, 0x8ab, 0, 0xb63, 0, 0),
- D_GATE(CLK_PCI_USB, "clk_pci_usb", CLKOUT_D40, 0xe6, 0, 0, 0, 0, 0, 0),
+ D_MODULE(CLK_PCI_USB, "clk_pci_usb", CLKOUT_D40, 0xe6, 0, 0, 0, 0, 0, 0),
D_GATE(CLK_QSPI0, "clk_qspi0", DIV_QSPI0, 0x2a4, 0x2a5, 0, 0, 0, 0, 0),
D_GATE(CLK_QSPI1, "clk_qspi1", DIV_QSPI1, 0x484, 0x485, 0, 0, 0, 0, 0),
D_GATE(CLK_RGMII_REF, "clk_rgmii_ref", CLKOUT_D8, 0x340, 0, 0, 0, 0, 0, 0),
@@ -188,17 +195,17 @@ static const struct r9a06g032_clkdesc r9a06g032_clocks[] __initconst = {
D_GATE(CLK_SPI5, "clk_spi5", DIV_P4_PG, 0x822, 0x823, 0, 0, 0, 0, 0),
D_GATE(CLK_SWITCH, "clk_switch", DIV_SWITCH, 0x982, 0x983, 0, 0, 0, 0, 0),
D_DIV(DIV_MOTOR, "div_motor", CLKOUT_D5, 84, 2, 8),
- D_GATE(HCLK_ECAT125, "hclk_ecat125", CLKOUT_D8, 0x400, 0x401, 0, 0x402, 0, 0x440, 0x441),
- D_GATE(HCLK_PINCONFIG, "hclk_pinconfig", CLKOUT_D40, 0x740, 0x741, 0x742, 0, 0xae0, 0, 0),
- D_GATE(HCLK_SERCOS, "hclk_sercos", CLKOUT_D10, 0x420, 0x422, 0, 0x421, 0, 0x460, 0x461),
- D_GATE(HCLK_SGPIO2, "hclk_sgpio2", DIV_P5_PG, 0x8c3, 0x8c4, 0x8c5, 0, 0xb41, 0, 0),
- D_GATE(HCLK_SGPIO3, "hclk_sgpio3", DIV_P5_PG, 0x8c6, 0x8c7, 0x8c8, 0, 0xb42, 0, 0),
- D_GATE(HCLK_SGPIO4, "hclk_sgpio4", DIV_P5_PG, 0x8c9, 0x8ca, 0x8cb, 0, 0xb43, 0, 0),
- D_GATE(HCLK_TIMER0, "hclk_timer0", CLKOUT_D40, 0x743, 0x744, 0x745, 0, 0xae1, 0, 0),
- D_GATE(HCLK_TIMER1, "hclk_timer1", CLKOUT_D40, 0x746, 0x747, 0x748, 0, 0xae2, 0, 0),
- D_GATE(HCLK_USBF, "hclk_usbf", CLKOUT_D8, 0xe3, 0, 0, 0xe4, 0, 0x102, 0x103),
- D_GATE(HCLK_USBH, "hclk_usbh", CLKOUT_D8, 0xe0, 0xe1, 0, 0xe2, 0, 0x100, 0x101),
- D_GATE(HCLK_USBPM, "hclk_usbpm", CLKOUT_D8, 0xe5, 0, 0, 0, 0, 0, 0),
+ D_MODULE(HCLK_ECAT125, "hclk_ecat125", CLKOUT_D8, 0x400, 0x401, 0, 0x402, 0, 0x440, 0x441),
+ D_MODULE(HCLK_PINCONFIG, "hclk_pinconfig", CLKOUT_D40, 0x740, 0x741, 0x742, 0, 0xae0, 0, 0),
+ D_MODULE(HCLK_SERCOS, "hclk_sercos", CLKOUT_D10, 0x420, 0x422, 0, 0x421, 0, 0x460, 0x461),
+ D_MODULE(HCLK_SGPIO2, "hclk_sgpio2", DIV_P5_PG, 0x8c3, 0x8c4, 0x8c5, 0, 0xb41, 0, 0),
+ D_MODULE(HCLK_SGPIO3, "hclk_sgpio3", DIV_P5_PG, 0x8c6, 0x8c7, 0x8c8, 0, 0xb42, 0, 0),
+ D_MODULE(HCLK_SGPIO4, "hclk_sgpio4", DIV_P5_PG, 0x8c9, 0x8ca, 0x8cb, 0, 0xb43, 0, 0),
+ D_MODULE(HCLK_TIMER0, "hclk_timer0", CLKOUT_D40, 0x743, 0x744, 0x745, 0, 0xae1, 0, 0),
+ D_MODULE(HCLK_TIMER1, "hclk_timer1", CLKOUT_D40, 0x746, 0x747, 0x748, 0, 0xae2, 0, 0),
+ D_MODULE(HCLK_USBF, "hclk_usbf", CLKOUT_D8, 0xe3, 0, 0, 0xe4, 0, 0x102, 0x103),
+ D_MODULE(HCLK_USBH, "hclk_usbh", CLKOUT_D8, 0xe0, 0xe1, 0, 0xe2, 0, 0x100, 0x101),
+ D_MODULE(HCLK_USBPM, "hclk_usbpm", CLKOUT_D8, 0xe5, 0, 0, 0, 0, 0, 0),
D_GATE(CLK_48_PG_F, "clk_48_pg_f", CLK_48, 0x78c, 0x78d, 0, 0x78e, 0, 0xb04, 0xb05),
D_GATE(CLK_48_PG4, "clk_48_pg4", CLK_48, 0x789, 0x78a, 0x78b, 0, 0xb03, 0, 0),
D_FFC(CLK_DDRPHY_PLLCLK_D4, "clk_ddrphy_pllclk_d4", CLK_DDRPHY_PLLCLK, 4),
@@ -208,13 +215,13 @@ static const struct r9a06g032_clkdesc r9a06g032_clocks[] __initconst = {
D_FFC(CLK_REF_SYNC_D8, "clk_ref_sync_d8", CLK_REF_SYNC, 8),
D_FFC(CLK_SERCOS100_D2, "clk_sercos100_d2", CLK_SERCOS100, 2),
D_DIV(DIV_CA7, "div_ca7", CLK_REF_SYNC, 57, 1, 4, 1, 2, 4),
- D_GATE(HCLK_CAN0, "hclk_can0", CLK_48, 0x783, 0x784, 0x785, 0, 0xb01, 0, 0),
- D_GATE(HCLK_CAN1, "hclk_can1", CLK_48, 0x786, 0x787, 0x788, 0, 0xb02, 0, 0),
- D_GATE(HCLK_DELTASIGMA, "hclk_deltasigma", DIV_MOTOR, 0x1ef, 0x1f0, 0x1f1, 0, 0, 0, 0),
- D_GATE(HCLK_PWMPTO, "hclk_pwmpto", DIV_MOTOR, 0x1ec, 0x1ed, 0x1ee, 0, 0, 0, 0),
- D_GATE(HCLK_RSV, "hclk_rsv", CLK_48, 0x780, 0x781, 0x782, 0, 0xb00, 0, 0),
- D_GATE(HCLK_SGPIO0, "hclk_sgpio0", DIV_MOTOR, 0x1e0, 0x1e1, 0x1e2, 0, 0, 0, 0),
- D_GATE(HCLK_SGPIO1, "hclk_sgpio1", DIV_MOTOR, 0x1e3, 0x1e4, 0x1e5, 0, 0, 0, 0),
+ D_MODULE(HCLK_CAN0, "hclk_can0", CLK_48, 0x783, 0x784, 0x785, 0, 0xb01, 0, 0),
+ D_MODULE(HCLK_CAN1, "hclk_can1", CLK_48, 0x786, 0x787, 0x788, 0, 0xb02, 0, 0),
+ D_MODULE(HCLK_DELTASIGMA, "hclk_deltasigma", DIV_MOTOR, 0x1ef, 0x1f0, 0x1f1, 0, 0, 0, 0),
+ D_MODULE(HCLK_PWMPTO, "hclk_pwmpto", DIV_MOTOR, 0x1ec, 0x1ed, 0x1ee, 0, 0, 0, 0),
+ D_MODULE(HCLK_RSV, "hclk_rsv", CLK_48, 0x780, 0x781, 0x782, 0, 0xb00, 0, 0),
+ D_MODULE(HCLK_SGPIO0, "hclk_sgpio0", DIV_MOTOR, 0x1e0, 0x1e1, 0x1e2, 0, 0, 0, 0),
+ D_MODULE(HCLK_SGPIO1, "hclk_sgpio1", DIV_MOTOR, 0x1e3, 0x1e4, 0x1e5, 0, 0, 0, 0),
D_DIV(RTOS_MDC, "rtos_mdc", CLK_REF_SYNC, 100, 80, 640, 80, 160, 320, 640),
D_GATE(CLK_CM3, "clk_cm3", CLK_REF_SYNC_D4, 0xba0, 0xba1, 0, 0xba2, 0, 0xbc0, 0xbc1),
D_GATE(CLK_DDRC, "clk_ddrc", CLK_DDRPHY_PLLCLK_D4, 0x323, 0x324, 0, 0, 0, 0, 0),
@@ -222,53 +229,53 @@ static const struct r9a06g032_clkdesc r9a06g032_clocks[] __initconst = {
D_GATE(CLK_HSR50, "clk_hsr50", CLK_HSR100_D2, 0x484, 0x485, 0, 0, 0, 0, 0),
D_GATE(CLK_HW_RTOS, "clk_hw_rtos", CLK_REF_SYNC_D4, 0xc60, 0xc61, 0, 0, 0, 0, 0),
D_GATE(CLK_SERCOS50, "clk_sercos50", CLK_SERCOS100_D2, 0x424, 0x423, 0, 0, 0, 0, 0),
- D_GATE(HCLK_ADC, "hclk_adc", CLK_REF_SYNC_D8, 0x1af, 0x1b0, 0x1b1, 0, 0, 0, 0),
- D_GATE(HCLK_CM3, "hclk_cm3", CLK_REF_SYNC_D4, 0xc20, 0xc21, 0xc22, 0, 0, 0, 0),
- D_GATE(HCLK_CRYPTO_EIP150, "hclk_crypto_eip150", CLK_REF_SYNC_D4, 0x123, 0x124, 0x125, 0, 0x142, 0, 0),
- D_GATE(HCLK_CRYPTO_EIP93, "hclk_crypto_eip93", CLK_REF_SYNC_D4, 0x120, 0x121, 0, 0x122, 0, 0x140, 0x141),
- D_GATE(HCLK_DDRC, "hclk_ddrc", CLK_REF_SYNC_D4, 0x320, 0x322, 0, 0x321, 0, 0x3a0, 0x3a1),
- D_GATE(HCLK_DMA0, "hclk_dma0", CLK_REF_SYNC_D4, 0x260, 0x261, 0x262, 0x263, 0x2c0, 0x2c1, 0x2c2),
- D_GATE(HCLK_DMA1, "hclk_dma1", CLK_REF_SYNC_D4, 0x264, 0x265, 0x266, 0x267, 0x2c3, 0x2c4, 0x2c5),
- D_GATE(HCLK_GMAC0, "hclk_gmac0", CLK_REF_SYNC_D4, 0x360, 0x361, 0x362, 0x363, 0x3c0, 0x3c1, 0x3c2),
- D_GATE(HCLK_GMAC1, "hclk_gmac1", CLK_REF_SYNC_D4, 0x380, 0x381, 0x382, 0x383, 0x3e0, 0x3e1, 0x3e2),
- D_GATE(HCLK_GPIO0, "hclk_gpio0", CLK_REF_SYNC_D4, 0x212, 0x213, 0x214, 0, 0, 0, 0),
- D_GATE(HCLK_GPIO1, "hclk_gpio1", CLK_REF_SYNC_D4, 0x215, 0x216, 0x217, 0, 0, 0, 0),
- D_GATE(HCLK_GPIO2, "hclk_gpio2", CLK_REF_SYNC_D4, 0x229, 0x22a, 0x22b, 0, 0, 0, 0),
- D_GATE(HCLK_HSR, "hclk_hsr", CLK_HSR100_D2, 0x480, 0x482, 0, 0x481, 0, 0x4c0, 0x4c1),
- D_GATE(HCLK_I2C0, "hclk_i2c0", CLK_REF_SYNC_D8, 0x1a9, 0x1aa, 0x1ab, 0, 0, 0, 0),
- D_GATE(HCLK_I2C1, "hclk_i2c1", CLK_REF_SYNC_D8, 0x1ac, 0x1ad, 0x1ae, 0, 0, 0, 0),
- D_GATE(HCLK_LCD, "hclk_lcd", CLK_REF_SYNC_D4, 0x7a0, 0x7a1, 0x7a2, 0, 0xb20, 0, 0),
- D_GATE(HCLK_MSEBI_M, "hclk_msebi_m", CLK_REF_SYNC_D4, 0x164, 0x165, 0x166, 0, 0x183, 0, 0),
- D_GATE(HCLK_MSEBI_S, "hclk_msebi_s", CLK_REF_SYNC_D4, 0x160, 0x161, 0x162, 0x163, 0x180, 0x181, 0x182),
- D_GATE(HCLK_NAND, "hclk_nand", CLK_REF_SYNC_D4, 0x280, 0x281, 0x282, 0x283, 0x2e0, 0x2e1, 0x2e2),
- D_GATE(HCLK_PG_I, "hclk_pg_i", CLK_REF_SYNC_D4, 0x7ac, 0x7ad, 0, 0x7ae, 0, 0xb24, 0xb25),
- D_GATE(HCLK_PG19, "hclk_pg19", CLK_REF_SYNC_D4, 0x22c, 0x22d, 0x22e, 0, 0, 0, 0),
- D_GATE(HCLK_PG20, "hclk_pg20", CLK_REF_SYNC_D4, 0x22f, 0x230, 0x231, 0, 0, 0, 0),
- D_GATE(HCLK_PG3, "hclk_pg3", CLK_REF_SYNC_D4, 0x7a6, 0x7a7, 0x7a8, 0, 0xb22, 0, 0),
- D_GATE(HCLK_PG4, "hclk_pg4", CLK_REF_SYNC_D4, 0x7a9, 0x7aa, 0x7ab, 0, 0xb23, 0, 0),
- D_GATE(HCLK_QSPI0, "hclk_qspi0", CLK_REF_SYNC_D4, 0x2a0, 0x2a1, 0x2a2, 0x2a3, 0x300, 0x301, 0x302),
- D_GATE(HCLK_QSPI1, "hclk_qspi1", CLK_REF_SYNC_D4, 0x480, 0x481, 0x482, 0x483, 0x4c0, 0x4c1, 0x4c2),
- D_GATE(HCLK_ROM, "hclk_rom", CLK_REF_SYNC_D4, 0xaa0, 0xaa1, 0xaa2, 0, 0xb80, 0, 0),
- D_GATE(HCLK_RTC, "hclk_rtc", CLK_REF_SYNC_D8, 0xa00, 0, 0, 0, 0, 0, 0),
- D_GATE(HCLK_SDIO0, "hclk_sdio0", CLK_REF_SYNC_D4, 0x60, 0x61, 0x62, 0x63, 0x80, 0x81, 0x82),
- D_GATE(HCLK_SDIO1, "hclk_sdio1", CLK_REF_SYNC_D4, 0x640, 0x641, 0x642, 0x643, 0x660, 0x661, 0x662),
- D_GATE(HCLK_SEMAP, "hclk_semap", CLK_REF_SYNC_D4, 0x7a3, 0x7a4, 0x7a5, 0, 0xb21, 0, 0),
- D_GATE(HCLK_SPI0, "hclk_spi0", CLK_REF_SYNC_D4, 0x200, 0x201, 0x202, 0, 0, 0, 0),
- D_GATE(HCLK_SPI1, "hclk_spi1", CLK_REF_SYNC_D4, 0x203, 0x204, 0x205, 0, 0, 0, 0),
- D_GATE(HCLK_SPI2, "hclk_spi2", CLK_REF_SYNC_D4, 0x206, 0x207, 0x208, 0, 0, 0, 0),
- D_GATE(HCLK_SPI3, "hclk_spi3", CLK_REF_SYNC_D4, 0x209, 0x20a, 0x20b, 0, 0, 0, 0),
- D_GATE(HCLK_SPI4, "hclk_spi4", CLK_REF_SYNC_D4, 0x20c, 0x20d, 0x20e, 0, 0, 0, 0),
- D_GATE(HCLK_SPI5, "hclk_spi5", CLK_REF_SYNC_D4, 0x20f, 0x210, 0x211, 0, 0, 0, 0),
- D_GATE(HCLK_SWITCH, "hclk_switch", CLK_REF_SYNC_D4, 0x980, 0, 0x981, 0, 0, 0, 0),
- D_GATE(HCLK_SWITCH_RG, "hclk_switch_rg", CLK_REF_SYNC_D4, 0xc40, 0xc41, 0xc42, 0, 0, 0, 0),
- D_GATE(HCLK_UART0, "hclk_uart0", CLK_REF_SYNC_D8, 0x1a0, 0x1a1, 0x1a2, 0, 0, 0, 0),
- D_GATE(HCLK_UART1, "hclk_uart1", CLK_REF_SYNC_D8, 0x1a3, 0x1a4, 0x1a5, 0, 0, 0, 0),
- D_GATE(HCLK_UART2, "hclk_uart2", CLK_REF_SYNC_D8, 0x1a6, 0x1a7, 0x1a8, 0, 0, 0, 0),
- D_GATE(HCLK_UART3, "hclk_uart3", CLK_REF_SYNC_D4, 0x218, 0x219, 0x21a, 0, 0, 0, 0),
- D_GATE(HCLK_UART4, "hclk_uart4", CLK_REF_SYNC_D4, 0x21b, 0x21c, 0x21d, 0, 0, 0, 0),
- D_GATE(HCLK_UART5, "hclk_uart5", CLK_REF_SYNC_D4, 0x220, 0x221, 0x222, 0, 0, 0, 0),
- D_GATE(HCLK_UART6, "hclk_uart6", CLK_REF_SYNC_D4, 0x223, 0x224, 0x225, 0, 0, 0, 0),
- D_GATE(HCLK_UART7, "hclk_uart7", CLK_REF_SYNC_D4, 0x226, 0x227, 0x228, 0, 0, 0, 0),
+ D_MODULE(HCLK_ADC, "hclk_adc", CLK_REF_SYNC_D8, 0x1af, 0x1b0, 0x1b1, 0, 0, 0, 0),
+ D_MODULE(HCLK_CM3, "hclk_cm3", CLK_REF_SYNC_D4, 0xc20, 0xc21, 0xc22, 0, 0, 0, 0),
+ D_MODULE(HCLK_CRYPTO_EIP150, "hclk_crypto_eip150", CLK_REF_SYNC_D4, 0x123, 0x124, 0x125, 0, 0x142, 0, 0),
+ D_MODULE(HCLK_CRYPTO_EIP93, "hclk_crypto_eip93", CLK_REF_SYNC_D4, 0x120, 0x121, 0, 0x122, 0, 0x140, 0x141),
+ D_MODULE(HCLK_DDRC, "hclk_ddrc", CLK_REF_SYNC_D4, 0x320, 0x322, 0, 0x321, 0, 0x3a0, 0x3a1),
+ D_MODULE(HCLK_DMA0, "hclk_dma0", CLK_REF_SYNC_D4, 0x260, 0x261, 0x262, 0x263, 0x2c0, 0x2c1, 0x2c2),
+ D_MODULE(HCLK_DMA1, "hclk_dma1", CLK_REF_SYNC_D4, 0x264, 0x265, 0x266, 0x267, 0x2c3, 0x2c4, 0x2c5),
+ D_MODULE(HCLK_GMAC0, "hclk_gmac0", CLK_REF_SYNC_D4, 0x360, 0x361, 0x362, 0x363, 0x3c0, 0x3c1, 0x3c2),
+ D_MODULE(HCLK_GMAC1, "hclk_gmac1", CLK_REF_SYNC_D4, 0x380, 0x381, 0x382, 0x383, 0x3e0, 0x3e1, 0x3e2),
+ D_MODULE(HCLK_GPIO0, "hclk_gpio0", CLK_REF_SYNC_D4, 0x212, 0x213, 0x214, 0, 0, 0, 0),
+ D_MODULE(HCLK_GPIO1, "hclk_gpio1", CLK_REF_SYNC_D4, 0x215, 0x216, 0x217, 0, 0, 0, 0),
+ D_MODULE(HCLK_GPIO2, "hclk_gpio2", CLK_REF_SYNC_D4, 0x229, 0x22a, 0x22b, 0, 0, 0, 0),
+ D_MODULE(HCLK_HSR, "hclk_hsr", CLK_HSR100_D2, 0x480, 0x482, 0, 0x481, 0, 0x4c0, 0x4c1),
+ D_MODULE(HCLK_I2C0, "hclk_i2c0", CLK_REF_SYNC_D8, 0x1a9, 0x1aa, 0x1ab, 0, 0, 0, 0),
+ D_MODULE(HCLK_I2C1, "hclk_i2c1", CLK_REF_SYNC_D8, 0x1ac, 0x1ad, 0x1ae, 0, 0, 0, 0),
+ D_MODULE(HCLK_LCD, "hclk_lcd", CLK_REF_SYNC_D4, 0x7a0, 0x7a1, 0x7a2, 0, 0xb20, 0, 0),
+ D_MODULE(HCLK_MSEBI_M, "hclk_msebi_m", CLK_REF_SYNC_D4, 0x164, 0x165, 0x166, 0, 0x183, 0, 0),
+ D_MODULE(HCLK_MSEBI_S, "hclk_msebi_s", CLK_REF_SYNC_D4, 0x160, 0x161, 0x162, 0x163, 0x180, 0x181, 0x182),
+ D_MODULE(HCLK_NAND, "hclk_nand", CLK_REF_SYNC_D4, 0x280, 0x281, 0x282, 0x283, 0x2e0, 0x2e1, 0x2e2),
+ D_MODULE(HCLK_PG_I, "hclk_pg_i", CLK_REF_SYNC_D4, 0x7ac, 0x7ad, 0, 0x7ae, 0, 0xb24, 0xb25),
+ D_MODULE(HCLK_PG19, "hclk_pg19", CLK_REF_SYNC_D4, 0x22c, 0x22d, 0x22e, 0, 0, 0, 0),
+ D_MODULE(HCLK_PG20, "hclk_pg20", CLK_REF_SYNC_D4, 0x22f, 0x230, 0x231, 0, 0, 0, 0),
+ D_MODULE(HCLK_PG3, "hclk_pg3", CLK_REF_SYNC_D4, 0x7a6, 0x7a7, 0x7a8, 0, 0xb22, 0, 0),
+ D_MODULE(HCLK_PG4, "hclk_pg4", CLK_REF_SYNC_D4, 0x7a9, 0x7aa, 0x7ab, 0, 0xb23, 0, 0),
+ D_MODULE(HCLK_QSPI0, "hclk_qspi0", CLK_REF_SYNC_D4, 0x2a0, 0x2a1, 0x2a2, 0x2a3, 0x300, 0x301, 0x302),
+ D_MODULE(HCLK_QSPI1, "hclk_qspi1", CLK_REF_SYNC_D4, 0x480, 0x481, 0x482, 0x483, 0x4c0, 0x4c1, 0x4c2),
+ D_MODULE(HCLK_ROM, "hclk_rom", CLK_REF_SYNC_D4, 0xaa0, 0xaa1, 0xaa2, 0, 0xb80, 0, 0),
+ D_MODULE(HCLK_RTC, "hclk_rtc", CLK_REF_SYNC_D8, 0xa00, 0, 0, 0, 0, 0, 0),
+ D_MODULE(HCLK_SDIO0, "hclk_sdio0", CLK_REF_SYNC_D4, 0x60, 0x61, 0x62, 0x63, 0x80, 0x81, 0x82),
+ D_MODULE(HCLK_SDIO1, "hclk_sdio1", CLK_REF_SYNC_D4, 0x640, 0x641, 0x642, 0x643, 0x660, 0x661, 0x662),
+ D_MODULE(HCLK_SEMAP, "hclk_semap", CLK_REF_SYNC_D4, 0x7a3, 0x7a4, 0x7a5, 0, 0xb21, 0, 0),
+ D_MODULE(HCLK_SPI0, "hclk_spi0", CLK_REF_SYNC_D4, 0x200, 0x201, 0x202, 0, 0, 0, 0),
+ D_MODULE(HCLK_SPI1, "hclk_spi1", CLK_REF_SYNC_D4, 0x203, 0x204, 0x205, 0, 0, 0, 0),
+ D_MODULE(HCLK_SPI2, "hclk_spi2", CLK_REF_SYNC_D4, 0x206, 0x207, 0x208, 0, 0, 0, 0),
+ D_MODULE(HCLK_SPI3, "hclk_spi3", CLK_REF_SYNC_D4, 0x209, 0x20a, 0x20b, 0, 0, 0, 0),
+ D_MODULE(HCLK_SPI4, "hclk_spi4", CLK_REF_SYNC_D4, 0x20c, 0x20d, 0x20e, 0, 0, 0, 0),
+ D_MODULE(HCLK_SPI5, "hclk_spi5", CLK_REF_SYNC_D4, 0x20f, 0x210, 0x211, 0, 0, 0, 0),
+ D_MODULE(HCLK_SWITCH, "hclk_switch", CLK_REF_SYNC_D4, 0x980, 0, 0x981, 0, 0, 0, 0),
+ D_MODULE(HCLK_SWITCH_RG, "hclk_switch_rg", CLK_REF_SYNC_D4, 0xc40, 0xc41, 0xc42, 0, 0, 0, 0),
+ D_MODULE(HCLK_UART0, "hclk_uart0", CLK_REF_SYNC_D8, 0x1a0, 0x1a1, 0x1a2, 0, 0, 0, 0),
+ D_MODULE(HCLK_UART1, "hclk_uart1", CLK_REF_SYNC_D8, 0x1a3, 0x1a4, 0x1a5, 0, 0, 0, 0),
+ D_MODULE(HCLK_UART2, "hclk_uart2", CLK_REF_SYNC_D8, 0x1a6, 0x1a7, 0x1a8, 0, 0, 0, 0),
+ D_MODULE(HCLK_UART3, "hclk_uart3", CLK_REF_SYNC_D4, 0x218, 0x219, 0x21a, 0, 0, 0, 0),
+ D_MODULE(HCLK_UART4, "hclk_uart4", CLK_REF_SYNC_D4, 0x21b, 0x21c, 0x21d, 0, 0, 0, 0),
+ D_MODULE(HCLK_UART5, "hclk_uart5", CLK_REF_SYNC_D4, 0x220, 0x221, 0x222, 0, 0, 0, 0),
+ D_MODULE(HCLK_UART6, "hclk_uart6", CLK_REF_SYNC_D4, 0x223, 0x224, 0x225, 0, 0, 0, 0),
+ D_MODULE(HCLK_UART7, "hclk_uart7", CLK_REF_SYNC_D4, 0x226, 0x227, 0x228, 0, 0, 0, 0),
/*
* These are not hardware clocks, but are needed to handle the special
* case where we have a 'selector bit' that doesn't just change the
@@ -345,6 +352,84 @@ struct r9a06g032_clk_gate {
#define to_r9a06g032_gate(_hw) container_of(_hw, struct r9a06g032_clk_gate, hw)
+static int create_add_module_clock(struct of_phandle_args *clkspec,
+ struct device *dev)
+{
+ struct clk *clk;
+ int error;
+
+ clk = of_clk_get_from_provider(clkspec);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ error = pm_clk_create(dev);
+ if (error) {
+ clk_put(clk);
+ return error;
+ }
+
+ error = pm_clk_add_clk(dev, clk);
+ if (error) {
+ pm_clk_destroy(dev);
+ clk_put(clk);
+ }
+
+ return error;
+}
+
+static int r9a06g032_attach_dev(struct generic_pm_domain *pd,
+ struct device *dev)
+{
+ struct device_node *np = dev->of_node;
+ struct of_phandle_args clkspec;
+ int i = 0;
+ int error;
+ int index;
+
+ while (!of_parse_phandle_with_args(np, "clocks", "#clock-cells", i,
+ &clkspec)) {
+ if (clkspec.np != pd->dev.of_node)
+ continue;
+
+ index = clkspec.args[0];
+ if (index < R9A06G032_CLOCK_COUNT &&
+ r9a06g032_clocks[index].managed) {
+ error = create_add_module_clock(&clkspec, dev);
+ of_node_put(clkspec.np);
+ if (error)
+ return error;
+ }
+ i++;
+ }
+
+ return 0;
+}
+
+static void r9a06g032_detach_dev(struct generic_pm_domain *unused, struct device *dev)
+{
+ if (!pm_clk_no_clocks(dev))
+ pm_clk_destroy(dev);
+}
+
+static int r9a06g032_add_clk_domain(struct device *dev)
+{
+ struct device_node *np = dev->of_node;
+ struct generic_pm_domain *pd;
+
+ pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+ if (!pd)
+ return -ENOMEM;
+
+ pd->name = np->name;
+ pd->flags = GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP;
+ pd->attach_dev = r9a06g032_attach_dev;
+ pd->detach_dev = r9a06g032_detach_dev;
+ pm_genpd_init(pd, &pm_domain_always_on_gov, false);
+
+ of_genpd_add_provider_simple(np, pd);
+ return 0;
+}
+
static void
r9a06g032_clk_gate_set(struct r9a06g032_priv *clocks,
struct r9a06g032_gate *g, int on)
@@ -871,8 +956,12 @@ static int __init r9a06g032_clocks_probe(struct platform_device *pdev)
if (error)
return error;
- return devm_add_action_or_reset(dev,
+ error = devm_add_action_or_reset(dev,
r9a06g032_clocks_del_clk_provider, np);
+ if (error)
+ return error;
+
+ return r9a06g032_add_clk_domain(dev);
}
static const struct of_device_id r9a06g032_match[] = {
diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c
index 0201809bbd37..52bbb9ce3807 100644
--- a/drivers/clk/renesas/renesas-cpg-mssr.c
+++ b/drivers/clk/renesas/renesas-cpg-mssr.c
@@ -112,14 +112,15 @@ static const u16 srcr[] = {
* @dev: CPG/MSSR device
* @base: CPG/MSSR register block base address
* @rmw_lock: protects RMW register accesses
- * @clks: Array containing all Core and Module Clocks
+ * @np: Device node in DT for this CPG/MSSR module
* @num_core_clks: Number of Core Clocks in clks[]
* @num_mod_clks: Number of Module Clocks in clks[]
* @last_dt_core_clk: ID of the last Core Clock exported to DT
+ * @stbyctrl: This device has Standby Control Registers
* @notifiers: Notifier chain to save/restore clock state for system resume
* @smstpcr_saved[].mask: Mask of SMSTPCR[] bits under our control
* @smstpcr_saved[].val: Saved values of SMSTPCR[]
- * @stbyctrl: This device has Standby Control Registers
+ * @clks: Array containing all Core and Module Clocks
*/
struct cpg_mssr_priv {
#ifdef CONFIG_RESET_CONTROLLER
@@ -130,7 +131,6 @@ struct cpg_mssr_priv {
spinlock_t rmw_lock;
struct device_node *np;
- struct clk **clks;
unsigned int num_core_clks;
unsigned int num_mod_clks;
unsigned int last_dt_core_clk;
@@ -141,6 +141,8 @@ struct cpg_mssr_priv {
u32 mask;
u32 val;
} smstpcr_saved[ARRAY_SIZE(smstpcr)];
+
+ struct clk *clks[];
};
static struct cpg_mssr_priv *cpg_mssr_priv;
@@ -447,9 +449,8 @@ fail:
struct cpg_mssr_clk_domain {
struct generic_pm_domain genpd;
- struct device_node *np;
unsigned int num_core_pm_clks;
- unsigned int core_pm_clks[0];
+ unsigned int core_pm_clks[];
};
static struct cpg_mssr_clk_domain *cpg_mssr_clk_domain;
@@ -459,7 +460,7 @@ static bool cpg_mssr_is_pm_clk(const struct of_phandle_args *clkspec,
{
unsigned int i;
- if (clkspec->np != pd->np || clkspec->args_count != 2)
+ if (clkspec->np != pd->genpd.dev.of_node || clkspec->args_count != 2)
return false;
switch (clkspec->args[0]) {
@@ -510,16 +511,12 @@ found:
return PTR_ERR(clk);
error = pm_clk_create(dev);
- if (error) {
- dev_err(dev, "pm_clk_create failed %d\n", error);
+ if (error)
goto fail_put;
- }
error = pm_clk_add_clk(dev, clk);
- if (error) {
- dev_err(dev, "pm_clk_add_clk %pC failed %d\n", clk, error);
+ if (error)
goto fail_destroy;
- }
return 0;
@@ -549,7 +546,6 @@ static int __init cpg_mssr_add_clk_domain(struct device *dev,
if (!pd)
return -ENOMEM;
- pd->np = np;
pd->num_core_pm_clks = num_core_pm_clks;
memcpy(pd->core_pm_clks, core_pm_clks, pm_size);
@@ -896,7 +892,6 @@ static int __init cpg_mssr_common_init(struct device *dev,
const struct cpg_mssr_info *info)
{
struct cpg_mssr_priv *priv;
- struct clk **clks = NULL;
unsigned int nclks, i;
int error;
@@ -906,7 +901,8 @@ static int __init cpg_mssr_common_init(struct device *dev,
return error;
}
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ nclks = info->num_total_core_clks + info->num_hw_mod_clks;
+ priv = kzalloc(struct_size(priv, clks, nclks), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -920,15 +916,7 @@ static int __init cpg_mssr_common_init(struct device *dev,
goto out_err;
}
- nclks = info->num_total_core_clks + info->num_hw_mod_clks;
- clks = kmalloc_array(nclks, sizeof(*clks), GFP_KERNEL);
- if (!clks) {
- error = -ENOMEM;
- goto out_err;
- }
-
cpg_mssr_priv = priv;
- priv->clks = clks;
priv->num_core_clks = info->num_total_core_clks;
priv->num_mod_clks = info->num_hw_mod_clks;
priv->last_dt_core_clk = info->last_dt_core_clk;
@@ -936,7 +924,7 @@ static int __init cpg_mssr_common_init(struct device *dev,
priv->stbyctrl = info->stbyctrl;
for (i = 0; i < nclks; i++)
- clks[i] = ERR_PTR(-ENOENT);
+ priv->clks[i] = ERR_PTR(-ENOENT);
error = of_clk_add_provider(np, cpg_mssr_clk_src_twocell_get, priv);
if (error)
@@ -945,7 +933,6 @@ static int __init cpg_mssr_common_init(struct device *dev,
return 0;
out_err:
- kfree(clks);
if (priv->base)
iounmap(priv->base);
kfree(priv);
diff --git a/drivers/clk/rockchip/clk-cpu.c b/drivers/clk/rockchip/clk-cpu.c
index 32c19c0f1e14..0dc478a19451 100644
--- a/drivers/clk/rockchip/clk-cpu.c
+++ b/drivers/clk/rockchip/clk-cpu.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014 MundoReader S.L.
* Author: Heiko Stuebner <heiko@sntech.de>
@@ -6,10 +7,6 @@
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
* Author: Thomas Abraham <thomas.ab@samsung.com>
*
- * 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.
- *
* A CPU clock is defined as a clock supplied to a CPU or a group of CPUs.
* The CPU clock is typically derived from a hierarchy of clock
* blocks which includes mux and divider blocks. There are a number of other
diff --git a/drivers/clk/rockchip/clk-mmc-phase.c b/drivers/clk/rockchip/clk-mmc-phase.c
index c61f4d3e52e2..4abe7ff31f53 100644
--- a/drivers/clk/rockchip/clk-mmc-phase.c
+++ b/drivers/clk/rockchip/clk-mmc-phase.c
@@ -46,29 +46,27 @@ static unsigned long rockchip_mmc_recalc(struct clk_hw *hw,
static int rockchip_mmc_get_phase(struct clk_hw *hw)
{
struct rockchip_mmc_clock *mmc_clock = to_mmc_clock(hw);
- unsigned long rate = clk_get_rate(hw->clk);
+ unsigned long rate = clk_hw_get_rate(hw);
u32 raw_value;
u16 degrees;
u32 delay_num = 0;
/* See the comment for rockchip_mmc_set_phase below */
- if (!rate) {
- pr_err("%s: invalid clk rate\n", __func__);
+ if (!rate)
return -EINVAL;
- }
raw_value = readl(mmc_clock->reg) >> (mmc_clock->shift);
degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90;
if (raw_value & ROCKCHIP_MMC_DELAY_SEL) {
- /* degrees/delaynum * 10000 */
+ /* degrees/delaynum * 1000000 */
unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) *
- 36 * (rate / 1000000);
+ 36 * (rate / 10000);
delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET;
- degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000);
+ degrees += DIV_ROUND_CLOSEST(delay_num * factor, 1000000);
}
return degrees % 360;
@@ -77,7 +75,7 @@ static int rockchip_mmc_get_phase(struct clk_hw *hw)
static int rockchip_mmc_set_phase(struct clk_hw *hw, int degrees)
{
struct rockchip_mmc_clock *mmc_clock = to_mmc_clock(hw);
- unsigned long rate = clk_get_rate(hw->clk);
+ unsigned long rate = clk_hw_get_rate(hw);
u8 nineties, remainder;
u8 delay_num;
u32 raw_value;
diff --git a/drivers/clk/rockchip/clk-px30.c b/drivers/clk/rockchip/clk-px30.c
index bb39a799bdb5..3a501896b280 100644
--- a/drivers/clk/rockchip/clk-px30.c
+++ b/drivers/clk/rockchip/clk-px30.c
@@ -794,6 +794,9 @@ static struct rockchip_clk_branch px30_clk_branches[] __initdata = {
GATE(ACLK_GIC, "aclk_gic", "aclk_bus_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(13), 12, GFLAGS),
GATE(ACLK_DCF, "aclk_dcf", "aclk_bus_pre", 0, PX30_CLKGATE_CON(13), 15, GFLAGS),
+ /* aclk_dmac is controlled by sgrf_soc_con1[11]. */
+ SGRF_GATE(ACLK_DMAC, "aclk_dmac", "aclk_bus_pre"),
+
GATE(0, "hclk_bus_niu", "hclk_bus_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(13), 9, GFLAGS),
GATE(0, "hclk_rom", "hclk_bus_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(13), 14, GFLAGS),
GATE(HCLK_PDM, "hclk_pdm", "hclk_bus_pre", 0, PX30_CLKGATE_CON(14), 1, GFLAGS),
@@ -957,7 +960,6 @@ static void __init px30_clk_init(struct device_node *np)
{
struct rockchip_clk_provider *ctx;
void __iomem *reg_base;
- struct clk *clk;
reg_base = of_iomap(np, 0);
if (!reg_base) {
@@ -972,14 +974,6 @@ static void __init px30_clk_init(struct device_node *np)
return;
}
- /* aclk_dmac is controlled by sgrf_soc_con1[11]. */
- clk = clk_register_fixed_factor(NULL, "aclk_dmac", "aclk_bus_pre", 0, 1, 1);
- if (IS_ERR(clk))
- pr_warn("%s: could not register clock aclk_dmac: %ld\n",
- __func__, PTR_ERR(clk));
- else
- rockchip_clk_add_lookup(ctx, clk, ACLK_DMAC);
-
rockchip_clk_register_plls(ctx, px30_pll_clks,
ARRAY_SIZE(px30_pll_clks),
PX30_GRF_SOC_STATUS0);
diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c
index bdb126321e56..d17cfb7a3ff4 100644
--- a/drivers/clk/rockchip/clk-rk3228.c
+++ b/drivers/clk/rockchip/clk-rk3228.c
@@ -101,6 +101,7 @@ static struct rockchip_cpuclk_rate_table rk3228_cpuclk_rates[] __initdata = {
RK3228_CPUCLK_RATE(1608000000, 1, 7),
RK3228_CPUCLK_RATE(1512000000, 1, 7),
RK3228_CPUCLK_RATE(1488000000, 1, 5),
+ RK3228_CPUCLK_RATE(1464000000, 1, 5),
RK3228_CPUCLK_RATE(1416000000, 1, 5),
RK3228_CPUCLK_RATE(1392000000, 1, 5),
RK3228_CPUCLK_RATE(1296000000, 1, 5),
@@ -246,7 +247,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = {
RK2928_CLKGATE_CON(4), 0, GFLAGS),
/* PD_MISC */
- MUX(0, "hdmiphy", mux_hdmiphy_p, CLK_SET_RATE_PARENT,
+ MUX(SCLK_HDMI_PHY, "hdmiphy", mux_hdmiphy_p, CLK_SET_RATE_PARENT,
RK2928_MISC_CON, 13, 1, MFLAGS),
MUX(0, "usb480m_phy", mux_usb480m_phy_p, CLK_SET_RATE_PARENT,
RK2928_MISC_CON, 14, 1, MFLAGS),
diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
index 057629685ea1..cc2a177bbdbf 100644
--- a/drivers/clk/rockchip/clk-rk3288.c
+++ b/drivers/clk/rockchip/clk-rk3288.c
@@ -113,7 +113,6 @@ static struct rockchip_pll_rate_table rk3288_pll_rates[] = {
RK3066_PLL_RATE( 160000000, 1, 80, 12),
RK3066_PLL_RATE( 157500000, 1, 105, 16),
RK3066_PLL_RATE( 126000000, 1, 84, 16),
- RK3066_PLL_RATE( 48000000, 1, 64, 32),
{ /* sentinel */ },
};
@@ -767,6 +766,9 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
GATE(PCLK_GRF, "pclk_grf", "pclk_pd_alive", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(14), 11, GFLAGS),
GATE(0, "pclk_alive_niu", "pclk_pd_alive", 0, RK3288_CLKGATE_CON(14), 12, GFLAGS),
+ /* Watchdog pclk is controlled by RK3288_SGRF_SOC_CON0[1]. */
+ SGRF_GATE(PCLK_WDT, "pclk_wdt", "pclk_pd_alive"),
+
/* pclk_pd_pmu gates */
GATE(PCLK_PMU, "pclk_pmu", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(17), 0, GFLAGS),
GATE(0, "pclk_intmem1", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(17), 1, GFLAGS),
@@ -915,7 +917,6 @@ static struct syscore_ops rk3288_clk_syscore_ops = {
static void __init rk3288_clk_init(struct device_node *np)
{
struct rockchip_clk_provider *ctx;
- struct clk *clk;
rk3288_cru_base = of_iomap(np, 0);
if (!rk3288_cru_base) {
@@ -930,14 +931,6 @@ static void __init rk3288_clk_init(struct device_node *np)
return;
}
- /* Watchdog pclk is controlled by RK3288_SGRF_SOC_CON0[1]. */
- clk = clk_register_fixed_factor(NULL, "pclk_wdt", "pclk_pd_alive", 0, 1, 1);
- if (IS_ERR(clk))
- pr_warn("%s: could not register clock pclk_wdt: %ld\n",
- __func__, PTR_ERR(clk));
- else
- rockchip_clk_add_lookup(ctx, clk, PCLK_WDT);
-
rockchip_clk_register_plls(ctx, rk3288_pll_clks,
ARRAY_SIZE(rk3288_pll_clks),
RK3288_GRF_SOC_STATUS1);
diff --git a/drivers/clk/rockchip/clk-rk3328.c b/drivers/clk/rockchip/clk-rk3328.c
index 076b9777a955..c186a1985bf4 100644
--- a/drivers/clk/rockchip/clk-rk3328.c
+++ b/drivers/clk/rockchip/clk-rk3328.c
@@ -791,6 +791,9 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
GATE(PCLK_SARADC, "pclk_saradc", "pclk_bus", 0, RK3328_CLKGATE_CON(17), 15, GFLAGS),
GATE(0, "pclk_pmu", "pclk_bus", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(28), 3, GFLAGS),
+ /* Watchdog pclk is controlled from the secure GRF */
+ SGRF_GATE(PCLK_WDT, "pclk_wdt", "pclk_bus"),
+
GATE(PCLK_USB3PHY_OTG, "pclk_usb3phy_otg", "pclk_phy_pre", 0, RK3328_CLKGATE_CON(28), 1, GFLAGS),
GATE(PCLK_USB3PHY_PIPE, "pclk_usb3phy_pipe", "pclk_phy_pre", 0, RK3328_CLKGATE_CON(28), 2, GFLAGS),
GATE(PCLK_USB3_GRF, "pclk_usb3_grf", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(17), 2, GFLAGS),
diff --git a/drivers/clk/rockchip/clk-rk3368.c b/drivers/clk/rockchip/clk-rk3368.c
index 43b022d9393b..55443349439b 100644
--- a/drivers/clk/rockchip/clk-rk3368.c
+++ b/drivers/clk/rockchip/clk-rk3368.c
@@ -811,6 +811,9 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = {
GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(22), 2, GFLAGS),
GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(22), 1, GFLAGS),
+ /* Watchdog pclk is controlled by sgrf_soc_con3[7]. */
+ SGRF_GATE(PCLK_WDT, "pclk_wdt", "pclk_pd_alive"),
+
/*
* pclk_vio gates
* pclk_vio comes from the exactly same source as hclk_vio
@@ -862,7 +865,6 @@ static void __init rk3368_clk_init(struct device_node *np)
{
struct rockchip_clk_provider *ctx;
void __iomem *reg_base;
- struct clk *clk;
reg_base = of_iomap(np, 0);
if (!reg_base) {
@@ -877,14 +879,6 @@ static void __init rk3368_clk_init(struct device_node *np)
return;
}
- /* Watchdog pclk is controlled by sgrf_soc_con3[7]. */
- clk = clk_register_fixed_factor(NULL, "pclk_wdt", "pclk_pd_alive", 0, 1, 1);
- if (IS_ERR(clk))
- pr_warn("%s: could not register clock pclk_wdt: %ld\n",
- __func__, PTR_ERR(clk));
- else
- rockchip_clk_add_lookup(ctx, clk, PCLK_WDT);
-
rockchip_clk_register_plls(ctx, rk3368_pll_clks,
ARRAY_SIZE(rk3368_pll_clks),
RK3368_GRF_SOC_STATUS0);
diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c
index a7ff71313278..ce1d2446f142 100644
--- a/drivers/clk/rockchip/clk-rk3399.c
+++ b/drivers/clk/rockchip/clk-rk3399.c
@@ -1295,6 +1295,9 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
GATE(PCLK_PMU_INTR_ARB, "pclk_pmu_intr_arb", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 9, GFLAGS),
GATE(PCLK_SGRF, "pclk_sgrf", "pclk_alive", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(31), 10, GFLAGS),
+ /* Watchdog pclk is controlled by RK3399 SECURE_GRF_SOC_CON3[8]. */
+ SGRF_GATE(PCLK_WDT, "pclk_wdt", "pclk_alive"),
+
GATE(SCLK_MIPIDPHY_REF, "clk_mipidphy_ref", "xin24m", 0, RK3399_CLKGATE_CON(11), 14, GFLAGS),
GATE(SCLK_DPHY_PLL, "clk_dphy_pll", "clk_mipidphy_ref", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(21), 0, GFLAGS),
@@ -1522,7 +1525,6 @@ static void __init rk3399_clk_init(struct device_node *np)
{
struct rockchip_clk_provider *ctx;
void __iomem *reg_base;
- struct clk *clk;
reg_base = of_iomap(np, 0);
if (!reg_base) {
@@ -1537,14 +1539,6 @@ static void __init rk3399_clk_init(struct device_node *np)
return;
}
- /* Watchdog pclk is controlled by RK3399 SECURE_GRF_SOC_CON3[8]. */
- clk = clk_register_fixed_factor(NULL, "pclk_wdt", "pclk_alive", 0, 1, 1);
- if (IS_ERR(clk))
- pr_warn("%s: could not register clock pclk_wdt: %ld\n",
- __func__, PTR_ERR(clk));
- else
- rockchip_clk_add_lookup(ctx, clk, PCLK_WDT);
-
rockchip_clk_register_plls(ctx, rk3399_pll_clks,
ARRAY_SIZE(rk3399_pll_clks), -1);
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
index adb66cc94929..b811597a3d38 100644
--- a/drivers/clk/rockchip/clk.h
+++ b/drivers/clk/rockchip/clk.h
@@ -811,6 +811,10 @@ struct rockchip_clk_branch {
.gate_offset = -1, \
}
+/* SGRF clocks are only accessible from secure mode, so not controllable */
+#define SGRF_GATE(_id, cname, pname) \
+ FACTOR(_id, cname, pname, 0, 1, 1)
+
struct rockchip_clk_provider *rockchip_clk_init(struct device_node *np,
void __iomem *base, unsigned long nr_clks);
void rockchip_clk_of_add_provider(struct device_node *np,
diff --git a/drivers/clk/samsung/clk-cpu.c b/drivers/clk/samsung/clk-cpu.c
index 3f80bcd46074..efc4fa61fbaf 100644
--- a/drivers/clk/samsung/clk-cpu.c
+++ b/drivers/clk/samsung/clk-cpu.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
* Author: Thomas Abraham <thomas.ab@samsung.com>
@@ -5,10 +6,6 @@
* Copyright (c) 2015 Samsung Electronics Co., Ltd.
* Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
*
- * 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.
- *
* This file contains the utility function to register CPU clock for Samsung
* Exynos platforms. A CPU clock is defined as a clock supplied to a CPU or a
* group of CPUs. The CPU clock is typically derived from a hierarchy of clock
diff --git a/drivers/clk/samsung/clk-cpu.h b/drivers/clk/samsung/clk-cpu.h
index bd38c6aa3897..ad38cc27f3df 100644
--- a/drivers/clk/samsung/clk-cpu.h
+++ b/drivers/clk/samsung/clk-cpu.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
*
- * 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.
- *
* Common Clock Framework support for all PLL's in Samsung platforms
*/
diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c
index 8f8a0f9fc842..42b5d32c6cc7 100644
--- a/drivers/clk/samsung/clk-exynos-audss.c
+++ b/drivers/clk/samsung/clk-exynos-audss.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
* Author: Padmavathi Venna <padma.v@samsung.com>
*
- * 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.
- *
* Common Clock Framework support for Audio Subsystem Clock Controller.
*/
diff --git a/drivers/clk/samsung/clk-exynos-clkout.c b/drivers/clk/samsung/clk-exynos-clkout.c
index ce41f36a0e29..34ccb1d23bc3 100644
--- a/drivers/clk/samsung/clk-exynos-clkout.c
+++ b/drivers/clk/samsung/clk-exynos-clkout.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
* Author: Tomasz Figa <t.figa@samsung.com>
*
- * 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.
- *
* Clock driver for Exynos clock output
*/
diff --git a/drivers/clk/samsung/clk-exynos3250.c b/drivers/clk/samsung/clk-exynos3250.c
index facaad3c56a1..17897c7a84d4 100644
--- a/drivers/clk/samsung/clk-exynos3250.c
+++ b/drivers/clk/samsung/clk-exynos3250.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
*
- * 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.
- *
* Common Clock Framework support for Exynos3250 SoC.
*/
diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c
index d2a68a792a21..51564fc23c63 100644
--- a/drivers/clk/samsung/clk-exynos4.c
+++ b/drivers/clk/samsung/clk-exynos4.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
* Copyright (c) 2013 Linaro Ltd.
* Author: Thomas Abraham <thomas.ab@samsung.com>
*
- * 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.
- *
* Common Clock Framework support for all Exynos4 SoCs.
*/
@@ -961,6 +958,7 @@ static const struct samsung_gate_clock exynos4210_gate_clks[] __initconst = {
/* list of gate clocks supported in exynos4x12 soc */
static const struct samsung_gate_clock exynos4x12_gate_clks[] __initconst = {
+ GATE(CLK_ASYNC_G3D, "async_g3d", "aclk200", GATE_IP_LEFTBUS, 6, 0, 0),
GATE(CLK_AUDSS, "audss", "sclk_epll", E4X12_GATE_IP_MAUDIO, 0, 0, 0),
GATE(CLK_MDNIE0, "mdnie0", "aclk160", GATE_IP_LCD0, 2, 0, 0),
GATE(CLK_ROTATOR, "rotator", "aclk200", E4X12_GATE_IP_IMAGE, 1, 0, 0),
diff --git a/drivers/clk/samsung/clk-exynos4412-isp.c b/drivers/clk/samsung/clk-exynos4412-isp.c
index cfaa057035ad..4b9e73608c21 100644
--- a/drivers/clk/samsung/clk-exynos4412-isp.c
+++ b/drivers/clk/samsung/clk-exynos4412-isp.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2017 Samsung Electronics Co., Ltd.
* Author: Marek Szyprowski <m.szyprowski@samsung.com>
*
- * 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.
- *
* Common Clock Framework support for Exynos4412 ISP module.
*/
diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c
index c8265c4cbc4f..f2b896881768 100644
--- a/drivers/clk/samsung/clk-exynos5250.c
+++ b/drivers/clk/samsung/clk-exynos5250.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
* Copyright (c) 2013 Linaro Ltd.
* Author: Thomas Abraham <thomas.ab@samsung.com>
*
- * 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.
- *
* Common Clock Framework support for Exynos5250 SoC.
*/
diff --git a/drivers/clk/samsung/clk-exynos5260.c b/drivers/clk/samsung/clk-exynos5260.c
index 2cc2583abd87..e05d7323669a 100644
--- a/drivers/clk/samsung/clk-exynos5260.c
+++ b/drivers/clk/samsung/clk-exynos5260.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
* Author: Rahul Sharma <rahul.sharma@samsung.com>
*
- * 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.
- *
* Common Clock Framework support for Exynos5260 SoC.
*/
diff --git a/drivers/clk/samsung/clk-exynos5260.h b/drivers/clk/samsung/clk-exynos5260.h
index d739716d6ea1..50a5b77734b7 100644
--- a/drivers/clk/samsung/clk-exynos5260.h
+++ b/drivers/clk/samsung/clk-exynos5260.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
* Author: Rahul Sharma <rahul.sharma@samsung.com>
*
- * 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.
- *
* Common Clock Framework support for Exynos5260 SoC.
*/
diff --git a/drivers/clk/samsung/clk-exynos5410.c b/drivers/clk/samsung/clk-exynos5410.c
index b2da2c8fa0c7..d67d67a519a4 100644
--- a/drivers/clk/samsung/clk-exynos5410.c
+++ b/drivers/clk/samsung/clk-exynos5410.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
* Author: Tarek Dakhran <t.dakhran@samsung.com>
*
- * 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.
- *
* Common Clock Framework support for Exynos5410 SoC.
*/
diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c
index 34cce3c5898f..01bca5a498b2 100644
--- a/drivers/clk/samsung/clk-exynos5420.c
+++ b/drivers/clk/samsung/clk-exynos5420.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
* Authors: Thomas Abraham <thomas.ab@samsung.com>
* Chander Kashyap <k.chander@samsung.com>
*
- * 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.
- *
* Common Clock Framework support for Exynos5420 SoC.
*/
@@ -134,6 +131,8 @@
#define SRC_CDREX 0x20200
#define DIV_CDREX0 0x20500
#define DIV_CDREX1 0x20504
+#define GATE_BUS_CDREX0 0x20700
+#define GATE_BUS_CDREX1 0x20704
#define KPLL_LOCK 0x28000
#define KPLL_CON0 0x28100
#define SRC_KFC 0x28200
@@ -248,6 +247,8 @@ static const unsigned long exynos5x_clk_regs[] __initconst = {
DIV_CDREX1,
SRC_KFC,
DIV_KFC0,
+ GATE_BUS_CDREX0,
+ GATE_BUS_CDREX1,
};
static const unsigned long exynos5800_clk_regs[] __initconst = {
@@ -425,6 +426,9 @@ PNAME(mout_group13_5800_p) = { "dout_osc_div", "mout_sw_aclkfl1_550_cam" };
PNAME(mout_group14_5800_p) = { "dout_aclk550_cam", "dout_sclk_sw" };
PNAME(mout_group15_5800_p) = { "dout_osc_div", "mout_sw_aclk550_cam" };
PNAME(mout_group16_5800_p) = { "dout_osc_div", "mout_mau_epll_clk" };
+PNAME(mout_mx_mspll_ccore_phy_p) = { "sclk_bpll", "mout_sclk_dpll",
+ "mout_sclk_mpll", "ff_dout_spll2",
+ "mout_sclk_spll", "mout_sclk_epll"};
/* fixed rate clocks generated outside the soc */
static struct samsung_fixed_rate_clock
@@ -450,7 +454,7 @@ static const struct samsung_fixed_factor_clock
static const struct samsung_fixed_factor_clock
exynos5800_fixed_factor_clks[] __initconst = {
FFACTOR(0, "ff_dout_epll2", "mout_sclk_epll", 1, 2, 0),
- FFACTOR(0, "ff_dout_spll2", "mout_sclk_spll", 1, 2, 0),
+ FFACTOR(CLK_FF_DOUT_SPLL2, "ff_dout_spll2", "mout_sclk_spll", 1, 2, 0),
};
static const struct samsung_mux_clock exynos5800_mux_clks[] __initconst = {
@@ -472,11 +476,14 @@ static const struct samsung_mux_clock exynos5800_mux_clks[] __initconst = {
MUX(0, "mout_aclk300_disp1", mout_group5_5800_p, SRC_TOP2, 24, 2),
MUX(0, "mout_aclk300_gscl", mout_group5_5800_p, SRC_TOP2, 28, 2),
+ MUX(CLK_MOUT_MX_MSPLL_CCORE_PHY, "mout_mx_mspll_ccore_phy",
+ mout_mx_mspll_ccore_phy_p, SRC_TOP7, 0, 3),
+
MUX(CLK_MOUT_MX_MSPLL_CCORE, "mout_mx_mspll_ccore",
- mout_mx_mspll_ccore_p, SRC_TOP7, 16, 2),
+ mout_mx_mspll_ccore_p, SRC_TOP7, 16, 3),
MUX_F(CLK_MOUT_MAU_EPLL, "mout_mau_epll_clk", mout_mau_epll_clk_5800_p,
SRC_TOP7, 20, 2, CLK_SET_RATE_PARENT, 0),
- MUX(0, "sclk_bpll", mout_bpll_p, SRC_TOP7, 24, 1),
+ MUX(CLK_SCLK_BPLL, "sclk_bpll", mout_bpll_p, SRC_TOP7, 24, 1),
MUX(0, "mout_epll2", mout_epll2_5800_p, SRC_TOP7, 28, 1),
MUX(0, "mout_aclk550_cam", mout_group3_5800_p, SRC_TOP8, 16, 3),
@@ -648,7 +655,7 @@ static const struct samsung_mux_clock exynos5x_mux_clks[] __initconst = {
MUX(0, "mout_sclk_mpll", mout_mpll_p, SRC_TOP6, 0, 1),
MUX(CLK_MOUT_VPLL, "mout_sclk_vpll", mout_vpll_p, SRC_TOP6, 4, 1),
- MUX(0, "mout_sclk_spll", mout_spll_p, SRC_TOP6, 8, 1),
+ MUX(CLK_MOUT_SCLK_SPLL, "mout_sclk_spll", mout_spll_p, SRC_TOP6, 8, 1),
MUX(0, "mout_sclk_ipll", mout_ipll_p, SRC_TOP6, 12, 1),
MUX(0, "mout_sclk_rpll", mout_rpll_p, SRC_TOP6, 16, 1),
MUX_F(CLK_MOUT_EPLL, "mout_sclk_epll", mout_epll_p, SRC_TOP6, 20, 1,
@@ -806,8 +813,21 @@ static const struct samsung_div_clock exynos5x_div_clks[] __initconst = {
"mout_aclk400_disp1", DIV_TOP2, 4, 3),
/* CDREX Block */
- DIV(CLK_DOUT_PCLK_CDREX, "dout_pclk_cdrex", "dout_aclk_cdrex1",
- DIV_CDREX0, 28, 3),
+ /*
+ * The three clocks below are controlled using the same register and
+ * bits. They are put into one because there is a need of
+ * synchronization between the BUS and DREXs (two external memory
+ * interfaces).
+ * They are put here to show this HW assumption and for clock
+ * information summary completeness.
+ */
+ DIV_F(CLK_DOUT_PCLK_CDREX, "dout_pclk_cdrex", "dout_aclk_cdrex1",
+ DIV_CDREX0, 28, 3, CLK_GET_RATE_NOCACHE, 0),
+ DIV_F(CLK_DOUT_PCLK_DREX0, "dout_pclk_drex0", "dout_cclk_drex0",
+ DIV_CDREX0, 28, 3, CLK_GET_RATE_NOCACHE, 0),
+ DIV_F(CLK_DOUT_PCLK_DREX1, "dout_pclk_drex1", "dout_cclk_drex0",
+ DIV_CDREX0, 28, 3, CLK_GET_RATE_NOCACHE, 0),
+
DIV_F(CLK_DOUT_SCLK_CDREX, "dout_sclk_cdrex", "mout_mclk_cdrex",
DIV_CDREX0, 24, 3, CLK_SET_RATE_PARENT, 0),
DIV(CLK_DOUT_ACLK_CDREX1, "dout_aclk_cdrex1", "dout_clk2x_phy0",
@@ -1170,6 +1190,32 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = {
GATE_TOP_SCLK_ISP, 12, CLK_SET_RATE_PARENT, 0),
GATE(CLK_G3D, "g3d", "mout_user_aclk_g3d", GATE_IP_G3D, 9, 0, 0),
+
+ /* CDREX */
+ GATE(CLK_CLKM_PHY0, "clkm_phy0", "dout_sclk_cdrex",
+ GATE_BUS_CDREX0, 0, 0, 0),
+ GATE(CLK_CLKM_PHY1, "clkm_phy1", "dout_sclk_cdrex",
+ GATE_BUS_CDREX0, 1, 0, 0),
+ GATE(0, "mx_mspll_ccore_phy", "mout_mx_mspll_ccore_phy",
+ SRC_MASK_TOP7, 0, CLK_IGNORE_UNUSED, 0),
+
+ GATE(CLK_ACLK_PPMU_DREX1_1, "aclk_ppmu_drex1_1", "dout_aclk_cdrex1",
+ GATE_BUS_CDREX1, 12, CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_ACLK_PPMU_DREX1_0, "aclk_ppmu_drex1_0", "dout_aclk_cdrex1",
+ GATE_BUS_CDREX1, 13, CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_ACLK_PPMU_DREX0_1, "aclk_ppmu_drex0_1", "dout_aclk_cdrex1",
+ GATE_BUS_CDREX1, 14, CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_ACLK_PPMU_DREX0_0, "aclk_ppmu_drex0_0", "dout_aclk_cdrex1",
+ GATE_BUS_CDREX1, 15, CLK_IGNORE_UNUSED, 0),
+
+ GATE(CLK_PCLK_PPMU_DREX1_1, "pclk_ppmu_drex1_1", "dout_pclk_cdrex",
+ GATE_BUS_CDREX1, 26, CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_PCLK_PPMU_DREX1_0, "pclk_ppmu_drex1_0", "dout_pclk_cdrex",
+ GATE_BUS_CDREX1, 27, CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_PCLK_PPMU_DREX0_1, "pclk_ppmu_drex0_1", "dout_pclk_cdrex",
+ GATE_BUS_CDREX1, 28, CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_PCLK_PPMU_DREX0_0, "pclk_ppmu_drex0_0", "dout_pclk_cdrex",
+ GATE_BUS_CDREX1, 29, CLK_IGNORE_UNUSED, 0),
};
static const struct samsung_div_clock exynos5x_disp_div_clks[] __initconst = {
@@ -1285,6 +1331,17 @@ static const struct samsung_pll_rate_table exynos5420_pll2550x_24mhz_tbl[] __ini
PLL_35XX_RATE(24 * MHZ, 200000000, 200, 3, 3),
};
+static const struct samsung_pll_rate_table exynos5422_bpll_rate_table[] = {
+ PLL_35XX_RATE(24 * MHZ, 825000000, 275, 4, 1),
+ PLL_35XX_RATE(24 * MHZ, 728000000, 182, 3, 1),
+ PLL_35XX_RATE(24 * MHZ, 633000000, 211, 4, 1),
+ PLL_35XX_RATE(24 * MHZ, 543000000, 181, 2, 2),
+ PLL_35XX_RATE(24 * MHZ, 413000000, 413, 6, 2),
+ PLL_35XX_RATE(24 * MHZ, 275000000, 275, 3, 3),
+ PLL_35XX_RATE(24 * MHZ, 206000000, 206, 3, 3),
+ PLL_35XX_RATE(24 * MHZ, 165000000, 110, 2, 3),
+};
+
static const struct samsung_pll_rate_table exynos5420_epll_24mhz_tbl[] = {
PLL_36XX_RATE(24 * MHZ, 600000000U, 100, 2, 1, 0),
PLL_36XX_RATE(24 * MHZ, 400000000U, 200, 3, 2, 0),
@@ -1427,9 +1484,13 @@ static void __init exynos5x_clk_init(struct device_node *np,
exynos5x_plls[apll].rate_table = exynos5420_pll2550x_24mhz_tbl;
exynos5x_plls[epll].rate_table = exynos5420_epll_24mhz_tbl;
exynos5x_plls[kpll].rate_table = exynos5420_pll2550x_24mhz_tbl;
- exynos5x_plls[bpll].rate_table = exynos5420_pll2550x_24mhz_tbl;
}
+ if (soc == EXYNOS5420)
+ exynos5x_plls[bpll].rate_table = exynos5420_pll2550x_24mhz_tbl;
+ else
+ exynos5x_plls[bpll].rate_table = exynos5422_bpll_rate_table;
+
samsung_clk_register_pll(ctx, exynos5x_plls, ARRAY_SIZE(exynos5x_plls),
reg_base);
samsung_clk_register_fixed_rate(ctx, exynos5x_fixed_rate_clks,
diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c
index dae1c96de933..7824c2ba3d8e 100644
--- a/drivers/clk/samsung/clk-exynos5433.c
+++ b/drivers/clk/samsung/clk-exynos5433.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
* Author: Chanwoo Choi <cw00.choi@samsung.com>
*
- * 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.
- *
* Common Clock Framework support for Exynos5433 SoC.
*/
@@ -5590,8 +5587,8 @@ static int __init exynos5433_cmu_probe(struct platform_device *pdev)
data->nr_clk_save = info->nr_clk_regs;
data->clk_suspend = info->suspend_regs;
data->nr_clk_suspend = info->nr_suspend_regs;
- data->nr_pclks = of_count_phandle_with_args(dev->of_node, "clocks",
- "#clock-cells");
+ data->nr_pclks = of_clk_get_parent_count(dev->of_node);
+
if (data->nr_pclks > 0) {
data->pclks = devm_kcalloc(dev, sizeof(struct clk *),
data->nr_pclks, GFP_KERNEL);
diff --git a/drivers/clk/samsung/clk-exynos7.c b/drivers/clk/samsung/clk-exynos7.c
index 492d51691080..87ee1bad9a9a 100644
--- a/drivers/clk/samsung/clk-exynos7.c
+++ b/drivers/clk/samsung/clk-exynos7.c
@@ -1,11 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
* Author: Naveen Krishna Ch <naveenkrishna.ch@gmail.com>
- *
- * 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.
- *
*/
#include <linux/clk-provider.h>
diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c
index 0c6782ceac48..ac70ad785d8e 100644
--- a/drivers/clk/samsung/clk-pll.c
+++ b/drivers/clk/samsung/clk-pll.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
* Copyright (c) 2013 Linaro Ltd.
*
- * 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.
- *
* This file contains the utility functions to register the pll clocks.
*/
diff --git a/drivers/clk/samsung/clk-pll.h b/drivers/clk/samsung/clk-pll.h
index ca57b3dfa814..79e41c226b90 100644
--- a/drivers/clk/samsung/clk-pll.h
+++ b/drivers/clk/samsung/clk-pll.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
* Copyright (c) 2013 Linaro Ltd.
*
- * 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.
- *
* Common Clock Framework support for all PLL's in Samsung platforms
*/
diff --git a/drivers/clk/samsung/clk-s3c2410-dclk.c b/drivers/clk/samsung/clk-s3c2410-dclk.c
index 0117e40c1d0a..1281672cb00e 100644
--- a/drivers/clk/samsung/clk-s3c2410-dclk.c
+++ b/drivers/clk/samsung/clk-s3c2410-dclk.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de>
*
- * 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.
- *
* Common Clock Framework support for s3c24xx external clock output.
*/
diff --git a/drivers/clk/samsung/clk-s3c2410.c b/drivers/clk/samsung/clk-s3c2410.c
index 8cb868f06257..fcf6764693cc 100644
--- a/drivers/clk/samsung/clk-s3c2410.c
+++ b/drivers/clk/samsung/clk-s3c2410.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de>
*
- * 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.
- *
* Common Clock Framework support for S3C2410 and following SoCs.
*/
diff --git a/drivers/clk/samsung/clk-s3c2412.c b/drivers/clk/samsung/clk-s3c2412.c
index ce21b89d1eb1..a95ab5f75163 100644
--- a/drivers/clk/samsung/clk-s3c2412.c
+++ b/drivers/clk/samsung/clk-s3c2412.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de>
*
- * 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.
- *
* Common Clock Framework support for S3C2412 and S3C2413.
*/
diff --git a/drivers/clk/samsung/clk-s3c2443.c b/drivers/clk/samsung/clk-s3c2443.c
index b2ea4dfb5b8c..5f30fe72cd51 100644
--- a/drivers/clk/samsung/clk-s3c2443.c
+++ b/drivers/clk/samsung/clk-s3c2443.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de>
*
- * 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.
- *
* Common Clock Framework support for S3C2443 and following SoCs.
*/
diff --git a/drivers/clk/samsung/clk-s3c64xx.c b/drivers/clk/samsung/clk-s3c64xx.c
index 54916c7bdb06..b96d33e5eb45 100644
--- a/drivers/clk/samsung/clk-s3c64xx.c
+++ b/drivers/clk/samsung/clk-s3c64xx.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2013 Tomasz Figa <tomasz.figa at gmail.com>
*
- * 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.
- *
* Common Clock Framework support for all S3C64xx SoCs.
*/
diff --git a/drivers/clk/samsung/clk-s5pv210-audss.c b/drivers/clk/samsung/clk-s5pv210-audss.c
index 22b18e728b88..14985ebd043b 100644
--- a/drivers/clk/samsung/clk-s5pv210-audss.c
+++ b/drivers/clk/samsung/clk-s5pv210-audss.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014 Tomasz Figa <t.figa@samsung.com>
*
@@ -6,10 +7,6 @@
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
* Author: Padmavathi Venna <padma.v@samsung.com>
*
- * 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.
- *
* Driver for Audio Subsystem Clock Controller of S5PV210-compatible SoCs.
*/
diff --git a/drivers/clk/samsung/clk-s5pv210.c b/drivers/clk/samsung/clk-s5pv210.c
index 41d2337fe030..e7b68ffe36de 100644
--- a/drivers/clk/samsung/clk-s5pv210.c
+++ b/drivers/clk/samsung/clk-s5pv210.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
* Author: Mateusz Krawczuk <m.krawczuk@partner.samsung.com>
*
* Based on clock drivers for S3C64xx and Exynos4 SoCs.
*
- * 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.
- *
* Common Clock Framework support for all S5PC110/S5PV210 SoCs.
*/
diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c
index 9ad546a5f74c..e544a38106dd 100644
--- a/drivers/clk/samsung/clk.c
+++ b/drivers/clk/samsung/clk.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
* Copyright (c) 2013 Linaro Ltd.
* Author: Thomas Abraham <thomas.ab@samsung.com>
*
- * 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.
- *
* This file includes utility functions to register clocks to common
* clock framework for Samsung platforms.
*/
diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
index 9cfaca5fbcdb..c1e1a6b2f499 100644
--- a/drivers/clk/samsung/clk.h
+++ b/drivers/clk/samsung/clk.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
* Copyright (c) 2013 Linaro Ltd.
* Author: Thomas Abraham <thomas.ab@samsung.com>
*
- * 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.
- *
* Common Clock Framework support for all Samsung platforms
*/
diff --git a/drivers/clk/socfpga/clk-s10.c b/drivers/clk/socfpga/clk-s10.c
index 8281dfbf38c2..993f3a73c71e 100644
--- a/drivers/clk/socfpga/clk-s10.c
+++ b/drivers/clk/socfpga/clk-s10.c
@@ -103,9 +103,9 @@ static const struct stratix10_perip_cnt_clock s10_main_perip_cnt_clks[] = {
{ STRATIX10_NOC_CLK, "noc_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux),
0, 0, 0, 0x3C, 1},
{ STRATIX10_EMAC_A_FREE_CLK, "emaca_free_clk", NULL, emaca_free_mux, ARRAY_SIZE(emaca_free_mux),
- 0, 0, 4, 0xB0, 0},
+ 0, 0, 2, 0xB0, 0},
{ STRATIX10_EMAC_B_FREE_CLK, "emacb_free_clk", NULL, emacb_free_mux, ARRAY_SIZE(emacb_free_mux),
- 0, 0, 4, 0xB0, 1},
+ 0, 0, 2, 0xB0, 1},
{ STRATIX10_EMAC_PTP_FREE_CLK, "emac_ptp_free_clk", NULL, emac_ptp_free_mux,
ARRAY_SIZE(emac_ptp_free_mux), 0, 0, 4, 0xB0, 2},
{ STRATIX10_GPIO_DB_FREE_CLK, "gpio_db_free_clk", NULL, gpio_db_free_mux,
@@ -161,8 +161,12 @@ static const struct stratix10_gate_clock s10_gate_clks[] = {
8, 0, 0, 0, 0, 0, 0},
{ STRATIX10_SPI_M_CLK, "spi_m_clk", "l4_mp_clk", NULL, 1, 0, 0xA4,
9, 0, 0, 0, 0, 0, 0},
- { STRATIX10_NAND_CLK, "nand_clk", "l4_main_clk", NULL, 1, 0, 0xA4,
+ { STRATIX10_NAND_X_CLK, "nand_x_clk", "l4_mp_clk", NULL, 1, 0, 0xA4,
10, 0, 0, 0, 0, 0, 0},
+ { STRATIX10_NAND_CLK, "nand_clk", "nand_x_clk", NULL, 1, 0, 0xA4,
+ 10, 0, 0, 0, 0, 0, 4},
+ { STRATIX10_NAND_ECC_CLK, "nand_ecc_clk", "nand_x_clk", NULL, 1, 0, 0xA4,
+ 10, 0, 0, 0, 0, 0, 4},
};
static int s10_clk_register_c_perip(const struct stratix10_perip_c_clock *clks,
diff --git a/drivers/clk/sprd/common.c b/drivers/clk/sprd/common.c
index e038b0447206..a5bdca1de5d0 100644
--- a/drivers/clk/sprd/common.c
+++ b/drivers/clk/sprd/common.c
@@ -42,6 +42,7 @@ int sprd_clk_regmap_init(struct platform_device *pdev,
void __iomem *base;
struct device_node *node = pdev->dev.of_node;
struct regmap *regmap;
+ struct resource *res;
if (of_find_property(node, "sprd,syscon", NULL)) {
regmap = syscon_regmap_lookup_by_phandle(node, "sprd,syscon");
@@ -50,10 +51,14 @@ int sprd_clk_regmap_init(struct platform_device *pdev,
return PTR_ERR(regmap);
}
} else {
- base = of_iomap(node, 0);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
regmap = devm_regmap_init_mmio(&pdev->dev, base,
&sprdclk_regmap_config);
- if (IS_ERR_OR_NULL(regmap)) {
+ if (IS_ERR(regmap)) {
pr_err("failed to init regmap\n");
return PTR_ERR(regmap);
}
diff --git a/drivers/clk/sprd/sc9860-clk.c b/drivers/clk/sprd/sc9860-clk.c
index 9980ab55271b..f76305b4bc8d 100644
--- a/drivers/clk/sprd/sc9860-clk.c
+++ b/drivers/clk/sprd/sc9860-clk.c
@@ -2023,6 +2023,7 @@ static int sc9860_clk_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
const struct sprd_clk_desc *desc;
+ int ret;
match = of_match_node(sprd_sc9860_clk_ids, pdev->dev.of_node);
if (!match) {
@@ -2031,7 +2032,9 @@ static int sc9860_clk_probe(struct platform_device *pdev)
}
desc = match->data;
- sprd_clk_regmap_init(pdev, desc);
+ ret = sprd_clk_regmap_init(pdev, desc);
+ if (ret)
+ return ret;
return sprd_clk_probe(&pdev->dev, desc->hw_clks);
}
diff --git a/drivers/clk/st/clkgen-fsyn.c b/drivers/clk/st/clkgen-fsyn.c
index 946ceb14dbf7..ca1ccdb8a3b1 100644
--- a/drivers/clk/st/clkgen-fsyn.c
+++ b/drivers/clk/st/clkgen-fsyn.c
@@ -1,10 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 STMicroelectronics R&D Ltd
- *
- * 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.
- *
*/
/*
diff --git a/drivers/clk/sunxi-ng/ccu-sun4i-a10.c b/drivers/clk/sunxi-ng/ccu-sun4i-a10.c
index df43952e403e..f32366d9336e 100644
--- a/drivers/clk/sunxi-ng/ccu-sun4i-a10.c
+++ b/drivers/clk/sunxi-ng/ccu-sun4i-a10.c
@@ -160,8 +160,9 @@ static struct ccu_nk pll_periph_base_clk = {
},
};
-static CLK_FIXED_FACTOR(pll_periph_clk, "pll-periph", "pll-periph-base",
- 2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_periph_clk, "pll-periph",
+ &pll_periph_base_clk.common.hw,
+ 2, 1, CLK_SET_RATE_PARENT);
/* Not documented on A10 */
static struct ccu_div pll_periph_sata_clk = {
@@ -1028,19 +1029,29 @@ static struct ccu_common *sun4i_sun7i_ccu_clks[] = {
&out_b_clk.common
};
+static const struct clk_hw *clk_parent_pll_audio[] = {
+ &pll_audio_base_clk.common.hw
+};
+
/* Post-divider for pll-audio is hardcoded to 1 */
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
- "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
- "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
- "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
- "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_video0_2x_clk, "pll-video0-2x",
- "pll-video0", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_video1_2x_clk, "pll-video1-2x",
- "pll-video1", 1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+ clk_parent_pll_audio,
+ 1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+ clk_parent_pll_audio,
+ 2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+ clk_parent_pll_audio,
+ 1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
+ clk_parent_pll_audio,
+ 1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_video0_2x_clk, "pll-video0-2x",
+ &pll_video0_clk.common.hw,
+ 1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_video1_2x_clk, "pll-video1-2x",
+ &pll_video1_clk.common.hw,
+ 1, 2, CLK_SET_RATE_PARENT);
static struct clk_hw_onecell_data sun4i_a10_hw_clks = {
diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
index 1786ee8fe8bb..49bd7a4c015c 100644
--- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
+++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
@@ -597,23 +597,34 @@ static SUNXI_CCU_M_WITH_GATE(gpu_clk, "gpu", "pll-gpu",
0x1a0, 0, 3, BIT(31), CLK_SET_RATE_PARENT);
/* Fixed Factor clocks */
-static CLK_FIXED_FACTOR(osc12M_clk, "osc12M", "osc24M", 2, 1, 0);
+static CLK_FIXED_FACTOR_FW_NAME(osc12M_clk, "osc12M", "hosc", 2, 1, 0);
+
+static const struct clk_hw *clk_parent_pll_audio[] = {
+ &pll_audio_base_clk.common.hw
+};
/* We hardcode the divider to 1 for now */
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
- "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
- "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
- "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
- "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_periph0_2x_clk, "pll-periph0-2x",
- "pll-periph0", 1, 2, 0);
-static CLK_FIXED_FACTOR(pll_periph1_2x_clk, "pll-periph1-2x",
- "pll-periph1", 1, 2, 0);
-static CLK_FIXED_FACTOR(pll_video0_2x_clk, "pll-video0-2x",
- "pll-video0", 1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+ clk_parent_pll_audio,
+ 1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+ clk_parent_pll_audio,
+ 2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+ clk_parent_pll_audio,
+ 1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
+ clk_parent_pll_audio,
+ 1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_periph0_2x_clk, "pll-periph0-2x",
+ &pll_periph0_clk.common.hw,
+ 1, 2, 0);
+static CLK_FIXED_FACTOR_HW(pll_periph1_2x_clk, "pll-periph1-2x",
+ &pll_periph1_clk.common.hw,
+ 1, 2, 0);
+static CLK_FIXED_FACTOR_HW(pll_video0_2x_clk, "pll-video0-2x",
+ &pll_video0_clk.common.hw,
+ 1, 2, CLK_SET_RATE_PARENT);
static struct ccu_common *sun50i_a64_ccu_clks[] = {
&pll_cpux_clk.common,
diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c
index 27554eaf6929..45a1ed3fe674 100644
--- a/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c
+++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c
@@ -49,7 +49,7 @@ static struct ccu_div ar100_clk = {
},
};
-static CLK_FIXED_FACTOR(r_ahb_clk, "r-ahb", "ar100", 1, 1, 0);
+static CLK_FIXED_FACTOR_HW(r_ahb_clk, "r-ahb", &ar100_clk.common.hw, 1, 1, 0);
static struct ccu_div r_apb1_clk = {
.div = _SUNXI_CCU_DIV(0, 2),
@@ -104,7 +104,7 @@ static SUNXI_CCU_GATE(r_apb2_i2c_clk, "r-apb2-i2c", "r-apb2",
static SUNXI_CCU_GATE(r_apb1_ir_clk, "r-apb1-ir", "r-apb1",
0x1cc, BIT(0), 0);
static SUNXI_CCU_GATE(r_apb1_w1_clk, "r-apb1-w1", "r-apb1",
- 0x1cc, BIT(0), 0);
+ 0x1ec, BIT(0), 0);
/* Information of IR(RX) mod clock is gathered from BSP source code */
static const char * const r_mod0_default_parents[] = { "osc32k", "osc24M" };
diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c
index 9d3f98962779..aebef4af9861 100644
--- a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c
+++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c
@@ -622,8 +622,9 @@ static SUNXI_CCU_GATE(bus_xhci_clk, "bus-xhci", "ahb3", 0xa8c, BIT(5), 0);
static SUNXI_CCU_GATE(bus_ehci3_clk, "bus-ehci3", "ahb3", 0xa8c, BIT(7), 0);
static SUNXI_CCU_GATE(bus_otg_clk, "bus-otg", "ahb3", 0xa8c, BIT(8), 0);
-static CLK_FIXED_FACTOR(pcie_ref_100m_clk, "pcie-ref-100M",
- "pll-periph0-4x", 24, 1, 0);
+static struct clk_fixed_factor pll_periph0_4x_clk;
+static CLK_FIXED_FACTOR_HW(pcie_ref_100m_clk, "pcie-ref-100M",
+ &pll_periph0_4x_clk.hw, 24, 1, 0);
static SUNXI_CCU_GATE(pcie_ref_clk, "pcie-ref", "pcie-ref-100M",
0xab0, BIT(31), 0);
static SUNXI_CCU_GATE(pcie_ref_out_clk, "pcie-ref-out", "pcie-ref",
@@ -745,34 +746,52 @@ static SUNXI_CCU_M_WITH_MUX_GATE(hdcp_clk, "hdcp", hdcp_parents, 0xc40,
static SUNXI_CCU_GATE(bus_hdcp_clk, "bus-hdcp", "ahb3", 0xc4c, BIT(0), 0);
/* Fixed factor clocks */
-static CLK_FIXED_FACTOR(osc12M_clk, "osc12M", "osc24M", 2, 1, 0);
+static CLK_FIXED_FACTOR_FW_NAME(osc12M_clk, "osc12M", "hosc", 2, 1, 0);
+
+static const struct clk_hw *clk_parent_pll_audio[] = {
+ &pll_audio_base_clk.common.hw
+};
/*
* The divider of pll-audio is fixed to 8 now, as pll-audio-4x has a
* fixed post-divider 2.
*/
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
- "pll-audio-base", 8, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
- "pll-audio-base", 4, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
- "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-
-static CLK_FIXED_FACTOR(pll_periph0_4x_clk, "pll-periph0-4x",
- "pll-periph0", 1, 4, 0);
-static CLK_FIXED_FACTOR(pll_periph0_2x_clk, "pll-periph0-2x",
- "pll-periph0", 1, 2, 0);
-
-static CLK_FIXED_FACTOR(pll_periph1_4x_clk, "pll-periph1-4x",
- "pll-periph1", 1, 4, 0);
-static CLK_FIXED_FACTOR(pll_periph1_2x_clk, "pll-periph1-2x",
- "pll-periph1", 1, 2, 0);
-
-static CLK_FIXED_FACTOR(pll_video0_4x_clk, "pll-video0-4x",
- "pll-video0", 1, 4, CLK_SET_RATE_PARENT);
-
-static CLK_FIXED_FACTOR(pll_video1_4x_clk, "pll-video1-4x",
- "pll-video1", 1, 4, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+ clk_parent_pll_audio,
+ 8, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+ clk_parent_pll_audio,
+ 4, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+ clk_parent_pll_audio,
+ 2, 1, CLK_SET_RATE_PARENT);
+
+static const struct clk_hw *pll_periph0_parents[] = {
+ &pll_periph0_clk.common.hw
+};
+static CLK_FIXED_FACTOR_HWS(pll_periph0_4x_clk, "pll-periph0-4x",
+ pll_periph0_parents,
+ 1, 4, 0);
+static CLK_FIXED_FACTOR_HWS(pll_periph0_2x_clk, "pll-periph0-2x",
+ pll_periph0_parents,
+ 1, 2, 0);
+
+static const struct clk_hw *pll_periph1_parents[] = {
+ &pll_periph1_clk.common.hw
+};
+static CLK_FIXED_FACTOR_HWS(pll_periph1_4x_clk, "pll-periph1-4x",
+ pll_periph1_parents,
+ 1, 4, 0);
+static CLK_FIXED_FACTOR_HWS(pll_periph1_2x_clk, "pll-periph1-2x",
+ pll_periph1_parents,
+ 1, 2, 0);
+
+static CLK_FIXED_FACTOR_HW(pll_video0_4x_clk, "pll-video0-4x",
+ &pll_video0_clk.common.hw,
+ 1, 4, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_video1_4x_clk, "pll-video1-4x",
+ &pll_video1_clk.common.hw,
+ 1, 4, CLK_SET_RATE_PARENT);
static struct ccu_common *sun50i_h6_ccu_clks[] = {
&pll_cpux_clk.common,
diff --git a/drivers/clk/sunxi-ng/ccu-sun5i.c b/drivers/clk/sunxi-ng/ccu-sun5i.c
index b71ed0f6f785..b78e9b507c1c 100644
--- a/drivers/clk/sunxi-ng/ccu-sun5i.c
+++ b/drivers/clk/sunxi-ng/ccu-sun5i.c
@@ -603,19 +603,29 @@ static struct ccu_common *sun5i_a10s_ccu_clks[] = {
&iep_clk.common,
};
+static const struct clk_hw *clk_parent_pll_audio[] = {
+ &pll_audio_base_clk.common.hw
+};
+
/* We hardcode the divider to 1 for now */
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
- "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
- "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
- "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
- "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_video0_2x_clk, "pll-video0-2x",
- "pll-video0", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_video1_2x_clk, "pll-video1-2x",
- "pll-video1", 1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+ clk_parent_pll_audio,
+ 1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+ clk_parent_pll_audio,
+ 2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+ clk_parent_pll_audio,
+ 1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
+ clk_parent_pll_audio,
+ 1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_video0_2x_clk, "pll-video0-2x",
+ &pll_video0_clk.common.hw,
+ 1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_video1_2x_clk, "pll-video1-2x",
+ &pll_video1_clk.common.hw,
+ 1, 2, CLK_SET_RATE_PARENT);
static struct clk_hw_onecell_data sun5i_a10s_hw_clks = {
.hws = {
diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c
index 2ff7b082df28..9b40d53266a3 100644
--- a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c
+++ b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c
@@ -955,21 +955,32 @@ static struct ccu_common *sun6i_a31_ccu_clks[] = {
&out_c_clk.common,
};
+static const struct clk_hw *clk_parent_pll_audio[] = {
+ &pll_audio_base_clk.common.hw
+};
+
/* We hardcode the divider to 1 for now */
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
- "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
- "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
- "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
- "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_periph_2x_clk, "pll-periph-2x",
- "pll-periph", 1, 2, 0);
-static CLK_FIXED_FACTOR(pll_video0_2x_clk, "pll-video0-2x",
- "pll-video0", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_video1_2x_clk, "pll-video1-2x",
- "pll-video1", 1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+ clk_parent_pll_audio,
+ 1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+ clk_parent_pll_audio,
+ 2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+ clk_parent_pll_audio,
+ 1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
+ clk_parent_pll_audio,
+ 1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_periph_2x_clk, "pll-periph-2x",
+ &pll_periph_clk.common.hw,
+ 1, 2, 0);
+static CLK_FIXED_FACTOR_HW(pll_video0_2x_clk, "pll-video0-2x",
+ &pll_video0_clk.common.hw,
+ 1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_video1_2x_clk, "pll-video1-2x",
+ &pll_video1_clk.common.hw,
+ 1, 2, CLK_SET_RATE_PARENT);
static struct clk_hw_onecell_data sun6i_a31_hw_clks = {
.hws = {
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c
index 14ced502788a..103aa504f6c8 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c
@@ -543,19 +543,29 @@ static struct ccu_common *sun8i_a23_ccu_clks[] = {
&ats_clk.common,
};
+static const struct clk_hw *clk_parent_pll_audio[] = {
+ &pll_audio_base_clk.common.hw
+};
+
/* We hardcode the divider to 1 for now */
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
- "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
- "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
- "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
- "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_periph_2x_clk, "pll-periph-2x",
- "pll-periph", 1, 2, 0);
-static CLK_FIXED_FACTOR(pll_video_2x_clk, "pll-video-2x",
- "pll-video", 1, 2, 0);
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+ clk_parent_pll_audio,
+ 1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+ clk_parent_pll_audio,
+ 2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+ clk_parent_pll_audio,
+ 1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
+ clk_parent_pll_audio,
+ 1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_periph_2x_clk, "pll-periph-2x",
+ &pll_periph_clk.common.hw,
+ 1, 2, 0);
+static CLK_FIXED_FACTOR_HW(pll_video_2x_clk, "pll-video-2x",
+ &pll_video_clk.common.hw,
+ 1, 2, 0);
static struct clk_hw_onecell_data sun8i_a23_hw_clks = {
.hws = {
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a33.c b/drivers/clk/sunxi-ng/ccu-sun8i-a33.c
index 61fb41f4903c..91838cd11037 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-a33.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-a33.c
@@ -580,19 +580,29 @@ static struct ccu_common *sun8i_a33_ccu_clks[] = {
&ats_clk.common,
};
+static const struct clk_hw *clk_parent_pll_audio[] = {
+ &pll_audio_base_clk.common.hw
+};
+
/* We hardcode the divider to 1 for now */
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
- "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
- "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
- "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
- "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_periph_2x_clk, "pll-periph-2x",
- "pll-periph", 1, 2, 0);
-static CLK_FIXED_FACTOR(pll_video_2x_clk, "pll-video-2x",
- "pll-video", 1, 2, 0);
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+ clk_parent_pll_audio,
+ 1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+ clk_parent_pll_audio,
+ 2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+ clk_parent_pll_audio,
+ 1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
+ clk_parent_pll_audio,
+ 1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_periph_2x_clk, "pll-periph-2x",
+ &pll_periph_clk.common.hw,
+ 1, 2, 0);
+static CLK_FIXED_FACTOR_HW(pll_video_2x_clk, "pll-video-2x",
+ &pll_video_clk.common.hw,
+ 1, 2, 0);
static struct clk_hw_onecell_data sun8i_a33_hw_clks = {
.hws = {
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
index 9601504905b2..6b636362379e 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
@@ -717,17 +717,26 @@ static struct ccu_common *sun50i_h5_ccu_clks[] = {
&gpu_clk.common,
};
+static const struct clk_hw *clk_parent_pll_audio[] = {
+ &pll_audio_base_clk.common.hw
+};
+
/* We hardcode the divider to 1 for now */
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
- "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
- "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
- "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
- "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_periph0_2x_clk, "pll-periph0-2x",
- "pll-periph0", 1, 2, 0);
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+ clk_parent_pll_audio,
+ 1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+ clk_parent_pll_audio,
+ 2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+ clk_parent_pll_audio,
+ 1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
+ clk_parent_pll_audio,
+ 1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_periph0_2x_clk, "pll-periph0-2x",
+ &pll_periph0_clk.common.hw,
+ 1, 2, 0);
static struct clk_hw_onecell_data sun8i_h3_hw_clks = {
.hws = {
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r.c b/drivers/clk/sunxi-ng/ccu-sun8i-r.c
index b5be11e5de0d..4646fdc61053 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-r.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-r.c
@@ -17,10 +17,13 @@
#include "ccu-sun8i-r.h"
-static const char * const ar100_parents[] = { "osc32k", "osc24M",
- "pll-periph0", "iosc" };
-static const char * const a83t_ar100_parents[] = { "osc16M-d512", "osc24M",
- "pll-periph0", "iosc" };
+static const struct clk_parent_data ar100_parents[] = {
+ { .fw_name = "losc" },
+ { .fw_name = "hosc" },
+ { .fw_name = "pll-periph" },
+ { .fw_name = "iosc" },
+};
+
static const struct ccu_mux_var_prediv ar100_predivs[] = {
{ .index = 2, .shift = 8, .width = 5 },
};
@@ -39,64 +42,49 @@ static struct ccu_div ar100_clk = {
.common = {
.reg = 0x00,
.features = CCU_FEATURE_VARIABLE_PREDIV,
- .hw.init = CLK_HW_INIT_PARENTS("ar100",
- ar100_parents,
- &ccu_div_ops,
- 0),
- },
-};
-
-static struct ccu_div a83t_ar100_clk = {
- .div = _SUNXI_CCU_DIV_FLAGS(4, 2, CLK_DIVIDER_POWER_OF_TWO),
-
- .mux = {
- .shift = 16,
- .width = 2,
-
- .var_predivs = ar100_predivs,
- .n_var_predivs = ARRAY_SIZE(ar100_predivs),
- },
-
- .common = {
- .reg = 0x00,
- .features = CCU_FEATURE_VARIABLE_PREDIV,
- .hw.init = CLK_HW_INIT_PARENTS("ar100",
- a83t_ar100_parents,
- &ccu_div_ops,
- 0),
+ .hw.init = CLK_HW_INIT_PARENTS_DATA("ar100",
+ ar100_parents,
+ &ccu_div_ops,
+ 0),
},
};
-static CLK_FIXED_FACTOR(ahb0_clk, "ahb0", "ar100", 1, 1, 0);
+static CLK_FIXED_FACTOR_HW(ahb0_clk, "ahb0", &ar100_clk.common.hw, 1, 1, 0);
static struct ccu_div apb0_clk = {
.div = _SUNXI_CCU_DIV_FLAGS(0, 2, CLK_DIVIDER_POWER_OF_TWO),
.common = {
.reg = 0x0c,
- .hw.init = CLK_HW_INIT("apb0",
- "ahb0",
- &ccu_div_ops,
- 0),
+ .hw.init = CLK_HW_INIT_HW("apb0",
+ &ahb0_clk.hw,
+ &ccu_div_ops,
+ 0),
},
};
static SUNXI_CCU_M(a83t_apb0_clk, "apb0", "ahb0", 0x0c, 0, 2, 0);
-static SUNXI_CCU_GATE(apb0_pio_clk, "apb0-pio", "apb0",
- 0x28, BIT(0), 0);
-static SUNXI_CCU_GATE(apb0_ir_clk, "apb0-ir", "apb0",
- 0x28, BIT(1), 0);
-static SUNXI_CCU_GATE(apb0_timer_clk, "apb0-timer", "apb0",
- 0x28, BIT(2), 0);
-static SUNXI_CCU_GATE(apb0_rsb_clk, "apb0-rsb", "apb0",
- 0x28, BIT(3), 0);
-static SUNXI_CCU_GATE(apb0_uart_clk, "apb0-uart", "apb0",
- 0x28, BIT(4), 0);
-static SUNXI_CCU_GATE(apb0_i2c_clk, "apb0-i2c", "apb0",
- 0x28, BIT(6), 0);
-static SUNXI_CCU_GATE(apb0_twd_clk, "apb0-twd", "apb0",
- 0x28, BIT(7), 0);
+/*
+ * Define the parent as an array that can be reused to save space
+ * instead of having compound literals for each gate. Also have it
+ * non-const so we can change it on the A83T.
+ */
+static const struct clk_hw *apb0_gate_parent[] = { &apb0_clk.common.hw };
+static SUNXI_CCU_GATE_HWS(apb0_pio_clk, "apb0-pio",
+ apb0_gate_parent, 0x28, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(apb0_ir_clk, "apb0-ir",
+ apb0_gate_parent, 0x28, BIT(1), 0);
+static SUNXI_CCU_GATE_HWS(apb0_timer_clk, "apb0-timer",
+ apb0_gate_parent, 0x28, BIT(2), 0);
+static SUNXI_CCU_GATE_HWS(apb0_rsb_clk, "apb0-rsb",
+ apb0_gate_parent, 0x28, BIT(3), 0);
+static SUNXI_CCU_GATE_HWS(apb0_uart_clk, "apb0-uart",
+ apb0_gate_parent, 0x28, BIT(4), 0);
+static SUNXI_CCU_GATE_HWS(apb0_i2c_clk, "apb0-i2c",
+ apb0_gate_parent, 0x28, BIT(6), 0);
+static SUNXI_CCU_GATE_HWS(apb0_twd_clk, "apb0-twd",
+ apb0_gate_parent, 0x28, BIT(7), 0);
static const char * const r_mod0_default_parents[] = { "osc32k", "osc24M" };
static SUNXI_CCU_MP_WITH_MUX_GATE(ir_clk, "ir",
@@ -107,7 +95,10 @@ static SUNXI_CCU_MP_WITH_MUX_GATE(ir_clk, "ir",
BIT(31), /* gate */
0);
-static const char *const a83t_r_mod0_parents[] = { "osc16M", "osc24M" };
+static const struct clk_parent_data a83t_r_mod0_parents[] = {
+ { .fw_name = "iosc" },
+ { .fw_name = "hosc" },
+};
static const struct ccu_mux_fixed_prediv a83t_ir_predivs[] = {
{ .index = 0, .div = 16 },
};
@@ -127,15 +118,15 @@ static struct ccu_mp a83t_ir_clk = {
.common = {
.reg = 0x54,
.features = CCU_FEATURE_VARIABLE_PREDIV,
- .hw.init = CLK_HW_INIT_PARENTS("ir",
- a83t_r_mod0_parents,
- &ccu_mp_ops,
- 0),
+ .hw.init = CLK_HW_INIT_PARENTS_DATA("ir",
+ a83t_r_mod0_parents,
+ &ccu_mp_ops,
+ 0),
},
};
static struct ccu_common *sun8i_a83t_r_ccu_clks[] = {
- &a83t_ar100_clk.common,
+ &ar100_clk.common,
&a83t_apb0_clk.common,
&apb0_pio_clk.common,
&apb0_ir_clk.common,
@@ -174,7 +165,7 @@ static struct ccu_common *sun50i_a64_r_ccu_clks[] = {
static struct clk_hw_onecell_data sun8i_a83t_r_hw_clks = {
.hws = {
- [CLK_AR100] = &a83t_ar100_clk.common.hw,
+ [CLK_AR100] = &ar100_clk.common.hw,
[CLK_AHB0] = &ahb0_clk.hw,
[CLK_APB0] = &a83t_apb0_clk.common.hw,
[CLK_APB0_PIO] = &apb0_pio_clk.common.hw,
@@ -291,6 +282,9 @@ static void __init sunxi_r_ccu_init(struct device_node *node,
static void __init sun8i_a83t_r_ccu_setup(struct device_node *node)
{
+ /* Fix apb0 bus gate parents here */
+ apb0_gate_parent[0] = &a83t_apb0_clk.common.hw;
+
sunxi_r_ccu_init(node, &sun8i_a83t_r_ccu_desc);
}
CLK_OF_DECLARE(sun8i_a83t_r_ccu, "allwinner,sun8i-a83t-r-ccu",
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c
index 540f5f7454fc..897490800102 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c
@@ -944,25 +944,37 @@ static struct ccu_common *sun8i_r40_ccu_clks[] = {
};
/* Fixed Factor clocks */
-static CLK_FIXED_FACTOR(osc12M_clk, "osc12M", "osc24M", 2, 1, 0);
+static CLK_FIXED_FACTOR_FW_NAME(osc12M_clk, "osc12M", "hosc", 2, 1, 0);
+
+static const struct clk_hw *clk_parent_pll_audio[] = {
+ &pll_audio_base_clk.common.hw
+};
/* We hardcode the divider to 4 for now */
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
- "pll-audio-base", 4, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
- "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
- "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
- "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_periph0_2x_clk, "pll-periph0-2x",
- "pll-periph0", 1, 2, 0);
-static CLK_FIXED_FACTOR(pll_periph1_2x_clk, "pll-periph1-2x",
- "pll-periph1", 1, 2, 0);
-static CLK_FIXED_FACTOR(pll_video0_2x_clk, "pll-video0-2x",
- "pll-video0", 1, 2, 0);
-static CLK_FIXED_FACTOR(pll_video1_2x_clk, "pll-video1-2x",
- "pll-video1", 1, 2, 0);
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+ clk_parent_pll_audio,
+ 4, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+ clk_parent_pll_audio,
+ 2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+ clk_parent_pll_audio,
+ 1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
+ clk_parent_pll_audio,
+ 1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_periph0_2x_clk, "pll-periph0-2x",
+ &pll_periph0_clk.common.hw,
+ 1, 2, 0);
+static CLK_FIXED_FACTOR_HW(pll_periph1_2x_clk, "pll-periph1-2x",
+ &pll_periph1_clk.common.hw,
+ 1, 2, 0);
+static CLK_FIXED_FACTOR_HW(pll_video0_2x_clk, "pll-video0-2x",
+ &pll_video0_clk.common.hw,
+ 1, 2, 0);
+static CLK_FIXED_FACTOR_HW(pll_video1_2x_clk, "pll-video1-2x",
+ &pll_video1_clk.common.hw,
+ 1, 2, 0);
static struct clk_hw_onecell_data sun8i_r40_hw_clks = {
.hws = {
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c b/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c
index cbbf06d42c2c..9b3939fc7faa 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c
@@ -429,17 +429,26 @@ static struct ccu_common *sun8i_v3s_ccu_clks[] = {
&mipi_csi_clk.common,
};
+static const struct clk_hw *clk_parent_pll_audio[] = {
+ &pll_audio_base_clk.common.hw
+};
+
/* We hardcode the divider to 4 for now */
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
- "pll-audio-base", 4, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
- "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
- "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
- "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_periph0_2x_clk, "pll-periph0-2x",
- "pll-periph0", 1, 2, 0);
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+ clk_parent_pll_audio,
+ 4, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+ clk_parent_pll_audio,
+ 2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+ clk_parent_pll_audio,
+ 1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
+ clk_parent_pll_audio,
+ 1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_periph0_2x_clk, "pll-periph0-2x",
+ &pll_periph0_clk.common.hw,
+ 1, 2, 0);
static struct clk_hw_onecell_data sun8i_v3s_hw_clks = {
.hws = {
diff --git a/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c b/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c
index 2f82cd855b0f..4b4a507d04ed 100644
--- a/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c
+++ b/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c
@@ -14,18 +14,26 @@
#include "ccu-sun9i-a80-usb.h"
-static SUNXI_CCU_GATE(bus_hci0_clk, "bus-hci0", "bus-usb", 0x0, BIT(1), 0);
-static SUNXI_CCU_GATE(usb_ohci0_clk, "usb-ohci0", "osc24M", 0x0, BIT(2), 0);
-static SUNXI_CCU_GATE(bus_hci1_clk, "bus-hci1", "bus-usb", 0x0, BIT(3), 0);
-static SUNXI_CCU_GATE(bus_hci2_clk, "bus-hci2", "bus-usb", 0x0, BIT(5), 0);
-static SUNXI_CCU_GATE(usb_ohci2_clk, "usb-ohci2", "osc24M", 0x0, BIT(6), 0);
-
-static SUNXI_CCU_GATE(usb0_phy_clk, "usb0-phy", "osc24M", 0x4, BIT(1), 0);
-static SUNXI_CCU_GATE(usb1_hsic_clk, "usb1-hsic", "osc24M", 0x4, BIT(2), 0);
-static SUNXI_CCU_GATE(usb1_phy_clk, "usb1-phy", "osc24M", 0x4, BIT(3), 0);
-static SUNXI_CCU_GATE(usb2_hsic_clk, "usb2-hsic", "osc24M", 0x4, BIT(4), 0);
-static SUNXI_CCU_GATE(usb2_phy_clk, "usb2-phy", "osc24M", 0x4, BIT(5), 0);
-static SUNXI_CCU_GATE(usb_hsic_clk, "usb-hsic", "osc24M", 0x4, BIT(10), 0);
+static const struct clk_parent_data clk_parent_hosc[] = {
+ { .fw_name = "hosc" },
+};
+
+static const struct clk_parent_data clk_parent_bus[] = {
+ { .fw_name = "bus" },
+};
+
+static SUNXI_CCU_GATE_DATA(bus_hci0_clk, "bus-hci0", clk_parent_bus, 0x0, BIT(1), 0);
+static SUNXI_CCU_GATE_DATA(usb_ohci0_clk, "usb-ohci0", clk_parent_hosc, 0x0, BIT(2), 0);
+static SUNXI_CCU_GATE_DATA(bus_hci1_clk, "bus-hci1", clk_parent_bus, 0x0, BIT(3), 0);
+static SUNXI_CCU_GATE_DATA(bus_hci2_clk, "bus-hci2", clk_parent_bus, 0x0, BIT(5), 0);
+static SUNXI_CCU_GATE_DATA(usb_ohci2_clk, "usb-ohci2", clk_parent_hosc, 0x0, BIT(6), 0);
+
+static SUNXI_CCU_GATE_DATA(usb0_phy_clk, "usb0-phy", clk_parent_hosc, 0x4, BIT(1), 0);
+static SUNXI_CCU_GATE_DATA(usb1_hsic_clk, "usb1-hsic", clk_parent_hosc, 0x4, BIT(2), 0);
+static SUNXI_CCU_GATE_DATA(usb1_phy_clk, "usb1-phy", clk_parent_hosc, 0x4, BIT(3), 0);
+static SUNXI_CCU_GATE_DATA(usb2_hsic_clk, "usb2-hsic", clk_parent_hosc, 0x4, BIT(4), 0);
+static SUNXI_CCU_GATE_DATA(usb2_phy_clk, "usb2-phy", clk_parent_hosc, 0x4, BIT(5), 0);
+static SUNXI_CCU_GATE_DATA(usb_hsic_clk, "usb-hsic", clk_parent_hosc, 0x4, BIT(10), 0);
static struct ccu_common *sun9i_a80_usb_clks[] = {
&bus_hci0_clk.common,
diff --git a/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c b/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c
index e748b8a6f3c5..7ecc3a5a5b5e 100644
--- a/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c
+++ b/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c
@@ -374,16 +374,25 @@ static struct ccu_common *suniv_ccu_clks[] = {
&avs_clk.common,
};
-static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio",
- "pll-audio-base", 4, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x",
- "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x",
- "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x",
- "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT);
-static CLK_FIXED_FACTOR(pll_video_2x_clk, "pll-video-2x",
- "pll-video", 1, 2, 0);
+static const struct clk_hw *clk_parent_pll_audio[] = {
+ &pll_audio_base_clk.common.hw
+};
+
+static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
+ clk_parent_pll_audio,
+ 4, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
+ clk_parent_pll_audio,
+ 2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
+ clk_parent_pll_audio,
+ 1, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
+ clk_parent_pll_audio,
+ 1, 2, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HW(pll_video_2x_clk, "pll-video-2x",
+ &pll_video_clk.common.hw,
+ 1, 2, 0);
static struct clk_hw_onecell_data suniv_hw_clks = {
.hws = {
diff --git a/drivers/clk/sunxi-ng/ccu_common.c b/drivers/clk/sunxi-ng/ccu_common.c
index c173778c8a78..7fe3ac980e5f 100644
--- a/drivers/clk/sunxi-ng/ccu_common.c
+++ b/drivers/clk/sunxi-ng/ccu_common.c
@@ -101,7 +101,7 @@ int sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
if (!hw)
continue;
- ret = clk_hw_register(NULL, hw);
+ ret = of_clk_hw_register(node, hw);
if (ret) {
pr_err("Couldn't register clock %d - %s\n",
i, clk_hw_get_name(hw));
diff --git a/drivers/clk/sunxi-ng/ccu_gate.h b/drivers/clk/sunxi-ng/ccu_gate.h
index da8100e8846d..c386689a952b 100644
--- a/drivers/clk/sunxi-ng/ccu_gate.h
+++ b/drivers/clk/sunxi-ng/ccu_gate.h
@@ -28,6 +28,59 @@ struct ccu_gate {
} \
}
+#define SUNXI_CCU_GATE_HW(_struct, _name, _parent, _reg, _gate, _flags) \
+ struct ccu_gate _struct = { \
+ .enable = _gate, \
+ .common = { \
+ .reg = _reg, \
+ .hw.init = CLK_HW_INIT_HW(_name, \
+ _parent, \
+ &ccu_gate_ops, \
+ _flags), \
+ } \
+ }
+
+#define SUNXI_CCU_GATE_FW(_struct, _name, _parent, _reg, _gate, _flags) \
+ struct ccu_gate _struct = { \
+ .enable = _gate, \
+ .common = { \
+ .reg = _reg, \
+ .hw.init = CLK_HW_INIT_FW_NAME(_name, \
+ _parent, \
+ &ccu_gate_ops, \
+ _flags), \
+ } \
+ }
+
+/*
+ * The following two macros allow the re-use of the data structure
+ * holding the parent info.
+ */
+#define SUNXI_CCU_GATE_HWS(_struct, _name, _parent, _reg, _gate, _flags) \
+ struct ccu_gate _struct = { \
+ .enable = _gate, \
+ .common = { \
+ .reg = _reg, \
+ .hw.init = CLK_HW_INIT_HWS(_name, \
+ _parent, \
+ &ccu_gate_ops, \
+ _flags), \
+ } \
+ }
+
+#define SUNXI_CCU_GATE_DATA(_struct, _name, _data, _reg, _gate, _flags) \
+ struct ccu_gate _struct = { \
+ .enable = _gate, \
+ .common = { \
+ .reg = _reg, \
+ .hw.init = \
+ CLK_HW_INIT_PARENTS_DATA(_name, \
+ _data, \
+ &ccu_gate_ops, \
+ _flags), \
+ } \
+ }
+
static inline struct ccu_gate *hw_to_ccu_gate(struct clk_hw *hw)
{
struct ccu_common *common = hw_to_ccu_common(hw);
diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c
index 661a73284e9f..4d8f0422b876 100644
--- a/drivers/clk/sunxi/clk-factors.c
+++ b/drivers/clk/sunxi/clk-factors.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Emilio López <emilio@elopez.com.ar>
*
- * 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.
- *
* Adjustable factor-based clock implementation
*/
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index 623fda5e911f..d3a43381a792 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -980,6 +980,8 @@ static struct clk ** __init sunxi_divs_clk_setup(struct device_node *node,
if (endp) {
derived_name = kstrndup(clk_name, endp - clk_name,
GFP_KERNEL);
+ if (!derived_name)
+ return NULL;
factors.name = derived_name;
} else {
factors.name = clk_name;
diff --git a/drivers/clk/tegra/clk-bpmp.c b/drivers/clk/tegra/clk-bpmp.c
index 01dada561c10..a66263b6490d 100644
--- a/drivers/clk/tegra/clk-bpmp.c
+++ b/drivers/clk/tegra/clk-bpmp.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2016 NVIDIA Corporation
- *
- * 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.
*/
#include <linux/clk-provider.h>
diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
index e1ba62d2b1a0..df172d5772d7 100644
--- a/drivers/clk/tegra/clk-tegra210.c
+++ b/drivers/clk/tegra/clk-tegra210.c
@@ -984,8 +984,6 @@ static void tegra210_pllre_set_defaults(struct tegra_clk_pll *pllre)
pllre->params->defaults_set = true;
if (val & PLL_ENABLE) {
- pr_warn("PLL_RE already enabled. Postponing set full defaults\n");
-
/*
* PLL is ON: check if defaults already set, then set those
* that can be updated in flight.
@@ -1005,13 +1003,20 @@ static void tegra210_pllre_set_defaults(struct tegra_clk_pll *pllre)
_pll_misc_chk_default(clk_base, pllre->params, 0, val,
~mask & PLLRE_MISC0_WRITE_MASK);
- /* Enable lock detect */
+ /* The PLL doesn't work if it's in IDDQ. */
val = readl_relaxed(clk_base + pllre->params->ext_misc_reg[0]);
+ if (val & PLLRE_MISC0_IDDQ)
+ pr_warn("unexpected IDDQ bit set for enabled clock\n");
+
+ /* Enable lock detect */
val &= ~mask;
val |= PLLRE_MISC0_DEFAULT_VALUE & mask;
writel_relaxed(val, clk_base + pllre->params->ext_misc_reg[0]);
udelay(1);
+ if (!pllre->params->defaults_set)
+ pr_warn("PLL_RE already enabled. Postponing set full defaults\n");
+
return;
}
@@ -2204,9 +2209,9 @@ static struct div_nmp pllu_nmp = {
};
static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
- { 12000000, 480000000, 40, 1, 0, 0 },
- { 13000000, 480000000, 36, 1, 0, 0 }, /* actual: 468.0 MHz */
- { 38400000, 480000000, 25, 2, 0, 0 },
+ { 12000000, 480000000, 40, 1, 1, 0 },
+ { 13000000, 480000000, 36, 1, 1, 0 }, /* actual: 468.0 MHz */
+ { 38400000, 480000000, 25, 2, 1, 0 },
{ 0, 0, 0, 0, 0, 0 },
};
@@ -3332,7 +3337,7 @@ static struct tegra_clk_init_table init_table[] __initdata = {
{ TEGRA210_CLK_DFLL_SOC, TEGRA210_CLK_PLL_P, 51000000, 1 },
{ TEGRA210_CLK_DFLL_REF, TEGRA210_CLK_PLL_P, 51000000, 1 },
{ TEGRA210_CLK_SBC4, TEGRA210_CLK_PLL_P, 12000000, 1 },
- { TEGRA210_CLK_PLL_RE_VCO, TEGRA210_CLK_CLK_MAX, 672000000, 1 },
+ { TEGRA210_CLK_PLL_U_OUT1, TEGRA210_CLK_CLK_MAX, 48000000, 1 },
{ TEGRA210_CLK_XUSB_GATE, TEGRA210_CLK_CLK_MAX, 0, 1 },
{ TEGRA210_CLK_XUSB_SS_SRC, TEGRA210_CLK_PLL_U_480M, 120000000, 0 },
{ TEGRA210_CLK_XUSB_FS_SRC, TEGRA210_CLK_PLL_U_48M, 48000000, 0 },
@@ -3357,7 +3362,6 @@ static struct tegra_clk_init_table init_table[] __initdata = {
{ TEGRA210_CLK_PLL_DP, TEGRA210_CLK_CLK_MAX, 270000000, 0 },
{ TEGRA210_CLK_SOC_THERM, TEGRA210_CLK_PLL_P, 51000000, 0 },
{ TEGRA210_CLK_CCLK_G, TEGRA210_CLK_CLK_MAX, 0, 1 },
- { TEGRA210_CLK_PLL_U_OUT1, TEGRA210_CLK_CLK_MAX, 48000000, 1 },
{ TEGRA210_CLK_PLL_U_OUT2, TEGRA210_CLK_CLK_MAX, 60000000, 1 },
{ TEGRA210_CLK_SPDIF_IN_SYNC, TEGRA210_CLK_CLK_MAX, 24576000, 0 },
{ TEGRA210_CLK_I2S0_SYNC, TEGRA210_CLK_CLK_MAX, 24576000, 0 },
@@ -3366,6 +3370,8 @@ static struct tegra_clk_init_table init_table[] __initdata = {
{ TEGRA210_CLK_I2S3_SYNC, TEGRA210_CLK_CLK_MAX, 24576000, 0 },
{ TEGRA210_CLK_I2S4_SYNC, TEGRA210_CLK_CLK_MAX, 24576000, 0 },
{ TEGRA210_CLK_VIMCLK_SYNC, TEGRA210_CLK_CLK_MAX, 24576000, 0 },
+ { TEGRA210_CLK_HDA, TEGRA210_CLK_PLL_P, 51000000, 0 },
+ { TEGRA210_CLK_HDA2CODEC_2X, TEGRA210_CLK_PLL_P, 48000000, 0 },
/* This MUST be the last entry. */
{ TEGRA210_CLK_CLK_MAX, TEGRA210_CLK_CLK_MAX, 0, 0 },
};
diff --git a/drivers/clk/ti/clk-44xx.c b/drivers/clk/ti/clk-44xx.c
index 339d30d64ebb..b10ed0429091 100644
--- a/drivers/clk/ti/clk-44xx.c
+++ b/drivers/clk/ti/clk-44xx.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* OMAP4 Clock init
*
* Copyright (C) 2013 Texas Instruments, Inc.
*
* Tero Kristo (t-kristo@ti.com)
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/clk/ti/clk-54xx.c b/drivers/clk/ti/clk-54xx.c
index a17b0c4646a1..dafef7e70ba8 100644
--- a/drivers/clk/ti/clk-54xx.c
+++ b/drivers/clk/ti/clk-54xx.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* OMAP5 Clock init
*
* Copyright (C) 2013 Texas Instruments, Inc.
*
* Tero Kristo (t-kristo@ti.com)
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/clk/ti/clk-7xx-compat.c b/drivers/clk/ti/clk-7xx-compat.c
index b3cd2296f84b..ddf7c8277946 100644
--- a/drivers/clk/ti/clk-7xx-compat.c
+++ b/drivers/clk/ti/clk-7xx-compat.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* DRA7 Clock init
*
* Copyright (C) 2013 Texas Instruments, Inc.
*
* Tero Kristo (t-kristo@ti.com)
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/clk/ti/clk-7xx.c b/drivers/clk/ti/clk-7xx.c
index 79186b918d87..b57fe09b428b 100644
--- a/drivers/clk/ti/clk-7xx.c
+++ b/drivers/clk/ti/clk-7xx.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* DRA7 Clock init
*
* Copyright (C) 2013 Texas Instruments, Inc.
*
* Tero Kristo (t-kristo@ti.com)
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/clk/ti/clkctrl.c b/drivers/clk/ti/clkctrl.c
index 8e834317c97d..975995eea15c 100644
--- a/drivers/clk/ti/clkctrl.c
+++ b/drivers/clk/ti/clkctrl.c
@@ -229,6 +229,7 @@ static struct clk_hw *_ti_omap4_clkctrl_xlate(struct of_phandle_args *clkspec,
{
struct omap_clkctrl_provider *provider = data;
struct omap_clkctrl_clk *entry;
+ bool found = false;
if (clkspec->args_count != 2)
return ERR_PTR(-EINVAL);
@@ -238,11 +239,13 @@ static struct clk_hw *_ti_omap4_clkctrl_xlate(struct of_phandle_args *clkspec,
list_for_each_entry(entry, &provider->clocks, node) {
if (entry->reg_offset == clkspec->args[0] &&
- entry->bit_offset == clkspec->args[1])
+ entry->bit_offset == clkspec->args[1]) {
+ found = true;
break;
+ }
}
- if (!entry)
+ if (!found)
return ERR_PTR(-EINVAL);
return entry->clk;
diff --git a/drivers/clk/ti/clkt_dpll.c b/drivers/clk/ti/clkt_dpll.c
index ce98da2c10be..87ece6cd4226 100644
--- a/drivers/clk/ti/clkt_dpll.c
+++ b/drivers/clk/ti/clkt_dpll.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* OMAP2/3/4 DPLL clock functions
*
@@ -7,10 +8,6 @@
* Contacts:
* Richard Woodruff <r-woodruff2@ti.com>
* Paul Walmsley
- *
- * 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.
*/
#undef DEBUG
diff --git a/drivers/clk/ti/clkt_iclk.c b/drivers/clk/ti/clkt_iclk.c
index 60b583d7db33..b738ee615423 100644
--- a/drivers/clk/ti/clkt_iclk.c
+++ b/drivers/clk/ti/clkt_iclk.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* OMAP2/3 interface clock control
*
* Copyright (C) 2011 Nokia Corporation
* Paul Walmsley
- *
- * 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.
*/
#undef DEBUG
diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c
index 4786e0ebc2e8..6cb863c13648 100644
--- a/drivers/clk/ti/divider.c
+++ b/drivers/clk/ti/divider.c
@@ -425,91 +425,6 @@ int ti_clk_parse_divider_data(int *div_table, int num_dividers, int max_div,
return 0;
}
-static const struct clk_div_table *
-_get_div_table_from_setup(struct ti_clk_divider *setup, u8 *width)
-{
- const struct clk_div_table *table = NULL;
-
- ti_clk_parse_divider_data(setup->dividers, setup->num_dividers,
- setup->max_div, setup->flags, width,
- &table);
-
- return table;
-}
-
-struct clk_hw *ti_clk_build_component_div(struct ti_clk_divider *setup)
-{
- struct clk_omap_divider *div;
- struct clk_omap_reg *reg;
- int ret;
-
- if (!setup)
- return NULL;
-
- div = kzalloc(sizeof(*div), GFP_KERNEL);
- if (!div)
- return ERR_PTR(-ENOMEM);
-
- reg = (struct clk_omap_reg *)&div->reg;
- reg->index = setup->module;
- reg->offset = setup->reg;
-
- if (setup->flags & CLKF_INDEX_STARTS_AT_ONE)
- div->flags |= CLK_DIVIDER_ONE_BASED;
-
- if (setup->flags & CLKF_INDEX_POWER_OF_TWO)
- div->flags |= CLK_DIVIDER_POWER_OF_TWO;
-
- div->table = _get_div_table_from_setup(setup, &div->width);
- if (IS_ERR(div->table)) {
- ret = PTR_ERR(div->table);
- kfree(div);
- return ERR_PTR(ret);
- }
-
-
- div->shift = setup->bit_shift;
- div->latch = -EINVAL;
-
- return &div->hw;
-}
-
-struct clk *ti_clk_register_divider(struct ti_clk *setup)
-{
- struct ti_clk_divider *div = setup->data;
- struct clk_omap_reg reg = {
- .index = div->module,
- .offset = div->reg,
- };
- u8 width;
- u32 flags = 0;
- u8 div_flags = 0;
- const struct clk_div_table *table;
- struct clk *clk;
-
- if (div->flags & CLKF_INDEX_STARTS_AT_ONE)
- div_flags |= CLK_DIVIDER_ONE_BASED;
-
- if (div->flags & CLKF_INDEX_POWER_OF_TWO)
- div_flags |= CLK_DIVIDER_POWER_OF_TWO;
-
- if (div->flags & CLKF_SET_RATE_PARENT)
- flags |= CLK_SET_RATE_PARENT;
-
- table = _get_div_table_from_setup(div, &width);
- if (IS_ERR(table))
- return (struct clk *)table;
-
- clk = _register_divider(NULL, setup->name, div->parent,
- flags, &reg, div->bit_shift,
- width, -EINVAL, div_flags, table);
-
- if (IS_ERR(clk))
- kfree(table);
-
- return clk;
-}
-
static struct clk_div_table *
__init ti_clk_get_div_table(struct device_node *node)
{
diff --git a/drivers/clk/ti/dpll3xxx.c b/drivers/clk/ti/dpll3xxx.c
index 3dde6c8c3354..2490026948b4 100644
--- a/drivers/clk/ti/dpll3xxx.c
+++ b/drivers/clk/ti/dpll3xxx.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* OMAP3/4 - specific DPLL control functions
*
@@ -12,10 +13,6 @@
*
* Parts of this code are based on code written by
* Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/clk/ti/dpll44xx.c b/drivers/clk/ti/dpll44xx.c
index d7a3f7ec8d77..89c3ed1a24b8 100644
--- a/drivers/clk/ti/dpll44xx.c
+++ b/drivers/clk/ti/dpll44xx.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* OMAP4-specific DPLL control functions
*
* Copyright (C) 2011 Texas Instruments, Inc.
* Rajendra Nayak
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/clk/ti/gate.c b/drivers/clk/ti/gate.c
index 504c0e91cdc7..42389558418c 100644
--- a/drivers/clk/ti/gate.c
+++ b/drivers/clk/ti/gate.c
@@ -131,36 +131,6 @@ static struct clk *_register_gate(struct device *dev, const char *name,
return clk;
}
-struct clk_hw *ti_clk_build_component_gate(struct ti_clk_gate *setup)
-{
- struct clk_hw_omap *gate;
- struct clk_omap_reg *reg;
- const struct clk_hw_omap_ops *ops = &clkhwops_wait;
-
- if (!setup)
- return NULL;
-
- gate = kzalloc(sizeof(*gate), GFP_KERNEL);
- if (!gate)
- return ERR_PTR(-ENOMEM);
-
- reg = (struct clk_omap_reg *)&gate->enable_reg;
- reg->index = setup->module;
- reg->offset = setup->reg;
-
- gate->enable_bit = setup->bit_shift;
-
- if (setup->flags & CLKF_NO_WAIT)
- ops = NULL;
-
- if (setup->flags & CLKF_INTERFACE)
- ops = &clkhwops_iclk_wait;
-
- gate->ops = ops;
-
- return &gate->hw;
-}
-
static void __init _of_ti_gate_clk_setup(struct device_node *node,
const struct clk_ops *ops,
const struct clk_hw_omap_ops *hw_ops)
diff --git a/drivers/clk/ti/mux.c b/drivers/clk/ti/mux.c
index b7f9a4f068bf..0069e7cf3ebc 100644
--- a/drivers/clk/ti/mux.c
+++ b/drivers/clk/ti/mux.c
@@ -164,37 +164,6 @@ static struct clk *_register_mux(struct device *dev, const char *name,
return clk;
}
-struct clk *ti_clk_register_mux(struct ti_clk *setup)
-{
- struct ti_clk_mux *mux;
- u32 flags;
- u8 mux_flags = 0;
- struct clk_omap_reg reg;
- u32 mask;
-
- mux = setup->data;
- flags = CLK_SET_RATE_NO_REPARENT;
-
- mask = mux->num_parents;
- if (!(mux->flags & CLKF_INDEX_STARTS_AT_ONE))
- mask--;
-
- mask = (1 << fls(mask)) - 1;
- reg.index = mux->module;
- reg.offset = mux->reg;
- reg.ptr = NULL;
-
- if (mux->flags & CLKF_INDEX_STARTS_AT_ONE)
- mux_flags |= CLK_MUX_INDEX_ONE;
-
- if (mux->flags & CLKF_SET_RATE_PARENT)
- flags |= CLK_SET_RATE_PARENT;
-
- return _register_mux(NULL, setup->name, mux->parents, mux->num_parents,
- flags, &reg, mux->bit_shift, mask, -EINVAL,
- mux_flags, NULL);
-}
-
/**
* of_mux_clk_setup - Setup function for simple mux rate clock
* @node: DT node for the clock
diff --git a/drivers/clk/versatile/clk-icst.c b/drivers/clk/versatile/clk-icst.c
index dafe7a45875d..fe686f77787f 100644
--- a/drivers/clk/versatile/clk-icst.c
+++ b/drivers/clk/versatile/clk-icst.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for the ICST307 VCO clock found in the ARM Reference designs.
* We wrap the custom interface from <asm/hardware/icst.h> into the generic
@@ -5,10 +6,6 @@
*
* Copyright (C) 2012-2015 Linus Walleij
*
- * 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.
- *
* TODO: when all ARM reference designs are migrated to generic clocks, the
* ICST clock code from the ARM tree should probably be merged into this
* file.
diff --git a/drivers/clk/versatile/clk-impd1.c b/drivers/clk/versatile/clk-impd1.c
index 401558bfc409..1991f15a5db9 100644
--- a/drivers/clk/versatile/clk-impd1.c
+++ b/drivers/clk/versatile/clk-impd1.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Clock driver for the ARM Integrator/IM-PD1 board
* Copyright (C) 2012-2013 Linus Walleij
- *
- * 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.
*/
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
diff --git a/drivers/clk/versatile/clk-versatile.c b/drivers/clk/versatile/clk-versatile.c
index d6960de64d4a..90bb0b041b7a 100644
--- a/drivers/clk/versatile/clk-versatile.c
+++ b/drivers/clk/versatile/clk-versatile.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Clock driver for the ARM Integrator/AP, Integrator/CP, Versatile AB and
* Versatile PB boards.
* Copyright (C) 2012 Linus Walleij
- *
- * 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.
*/
#include <linux/clk-provider.h>
#include <linux/err.h>
diff --git a/drivers/clk/versatile/icst.c b/drivers/clk/versatile/icst.c
index de2af63a3aad..ba4b2d22ec97 100644
--- a/drivers/clk/versatile/icst.c
+++ b/drivers/clk/versatile/icst.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/arch/arm/common/icst307.c
*
* Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* Support functions for calculating clocks/divisors for the ICST307
* clock generators. See http://www.idt.com/ for more information
* on these devices.
diff --git a/drivers/clk/versatile/icst.h b/drivers/clk/versatile/icst.h
index 7519bba03b04..73a3062b4535 100644
--- a/drivers/clk/versatile/icst.h
+++ b/drivers/clk/versatile/icst.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* Support functions for calculating clocks/divisors for the ICST
* clock generators. See http://www.idt.com/ for more information
* on these devices.
diff --git a/drivers/clk/x86/clk-lpt.c b/drivers/clk/x86/clk-lpt.c
index 68bd3abaef2c..fbe9fd3ed948 100644
--- a/drivers/clk/x86/clk-lpt.c
+++ b/drivers/clk/x86/clk-lpt.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Intel Low Power Subsystem clocks.
*
* Copyright (C) 2013, Intel Corporation
* Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
* Heikki Krogerus <heikki.krogerus@linux.intel.com>
- *
- * 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.
*/
#include <linux/clk-provider.h>
diff --git a/drivers/clk/zte/clk-zx296702.c b/drivers/clk/zte/clk-zx296702.c
index 76e967c19775..e846f2a34feb 100644
--- a/drivers/clk/zte/clk-zx296702.c
+++ b/drivers/clk/zte/clk-zx296702.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2014 Linaro Ltd.
* Copyright (C) 2014 ZTE Corporation.
- *
- * 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.
*/
#include <linux/clk-provider.h>
diff --git a/drivers/clk/zte/clk-zx296718.c b/drivers/clk/zte/clk-zx296718.c
index 354dd508c516..fd6c347bec6a 100644
--- a/drivers/clk/zte/clk-zx296718.c
+++ b/drivers/clk/zte/clk-zx296718.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2015 - 2016 ZTE Corporation.
* Copyright (C) 2016 Linaro Ltd.
- *
- * 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.
*/
#include <linux/clk-provider.h>
#include <linux/device.h>
diff --git a/drivers/clk/zte/clk.c b/drivers/clk/zte/clk.c
index b82031766ffa..8bda6d41ad3a 100644
--- a/drivers/clk/zte/clk.c
+++ b/drivers/clk/zte/clk.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2014 Linaro Ltd.
* Copyright (C) 2014 ZTE Corporation.
- *
- * 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.
*/
#include <linux/clk-provider.h>
diff --git a/drivers/clk/zte/clk.h b/drivers/clk/zte/clk.h
index f1041e36bcf1..aeaf2a380ba6 100644
--- a/drivers/clk/zte/clk.h
+++ b/drivers/clk/zte/clk.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2015 Linaro Ltd.
* Copyright (C) 2014 ZTE Corporation.
- *
- * 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.
*/
#ifndef __ZTE_CLK_H
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 3300739edce4..5e9317dc3d39 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -43,6 +43,11 @@ config BCM_KONA_TIMER
help
Enables the support for the BCM Kona mobile timer driver.
+config DAVINCI_TIMER
+ bool "Texas Instruments DaVinci timer driver" if COMPILE_TEST
+ help
+ Enables the support for the TI DaVinci timer driver.
+
config DIGICOLOR_TIMER
bool "Digicolor timer driver" if COMPILE_TEST
select CLKSRC_MMIO
@@ -140,7 +145,7 @@ config TEGRA_TIMER
bool "Tegra timer driver" if COMPILE_TEST
select CLKSRC_MMIO
select TIMER_OF
- depends on ARM || ARM64
+ depends on ARCH_TEGRA || COMPILE_TEST
help
Enables support for the Tegra driver.
@@ -617,6 +622,13 @@ config CLKSRC_IMX_TPM
Enable this option to use IMX Timer/PWM Module (TPM) timer as
clocksource.
+config TIMER_IMX_SYS_CTR
+ bool "i.MX system counter timer" if COMPILE_TEST
+ select TIMER_OF
+ help
+ Enable this option to use i.MX system counter timer as a
+ clockevent.
+
config CLKSRC_ST_LPC
bool "Low power clocksource found in the LPC" if COMPILE_TEST
select TIMER_OF if OF
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 236858fa7fbf..2e7936e7833f 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o
obj-$(CONFIG_EM_TIMER_STI) += em_sti.o
obj-$(CONFIG_CLKBLD_I8253) += i8253.o
obj-$(CONFIG_CLKSRC_MMIO) += mmio.o
+obj-$(CONFIG_DAVINCI_TIMER) += timer-davinci.o
obj-$(CONFIG_DIGICOLOR_TIMER) += timer-digicolor.o
obj-$(CONFIG_OMAP_DM_TIMER) += timer-ti-dm.o
obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o
@@ -36,7 +37,7 @@ obj-$(CONFIG_U300_TIMER) += timer-u300.o
obj-$(CONFIG_SUN4I_TIMER) += timer-sun4i.o
obj-$(CONFIG_SUN5I_HSTIMER) += timer-sun5i.o
obj-$(CONFIG_MESON6_TIMER) += timer-meson6.o
-obj-$(CONFIG_TEGRA_TIMER) += timer-tegra20.o
+obj-$(CONFIG_TEGRA_TIMER) += timer-tegra.o
obj-$(CONFIG_VT8500_TIMER) += timer-vt8500.o
obj-$(CONFIG_NSPIRE_TIMER) += timer-zevio.o
obj-$(CONFIG_BCM_KONA_TIMER) += bcm_kona_timer.o
@@ -74,6 +75,7 @@ obj-$(CONFIG_CLKSRC_MIPS_GIC) += mips-gic-timer.o
obj-$(CONFIG_CLKSRC_TANGO_XTAL) += timer-tango-xtal.o
obj-$(CONFIG_CLKSRC_IMX_GPT) += timer-imx-gpt.o
obj-$(CONFIG_CLKSRC_IMX_TPM) += timer-imx-tpm.o
+obj-$(CONFIG_TIMER_IMX_SYS_CTR) += timer-imx-sysctr.o
obj-$(CONFIG_ASM9260_TIMER) += asm9260_timer.o
obj-$(CONFIG_H8300_TMR8) += h8300_timer8.o
obj-$(CONFIG_H8300_TMR16) += h8300_timer16.o
@@ -84,3 +86,4 @@ obj-$(CONFIG_ATCPIT100_TIMER) += timer-atcpit100.o
obj-$(CONFIG_RISCV_TIMER) += timer-riscv.o
obj-$(CONFIG_CSKY_MP_TIMER) += timer-mp-csky.o
obj-$(CONFIG_GX6605S_TIMER) += timer-gx6605s.o
+obj-$(CONFIG_HYPERV_TIMER) += hyperv_timer.o
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c
index 1961e3539b57..eb596ff9e7bb 100644
--- a/drivers/clocksource/acpi_pm.c
+++ b/drivers/clocksource/acpi_pm.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/clocksource/acpi_pm.c
*
@@ -12,8 +13,6 @@
*
* Based on parts of linux/drivers/acpi/hardware/hwtimer.c, timer_pit.c,
* timer_hpet.c, and on Arjan van de Ven's implementation for 2.4.
- *
- * This file is licensed under the GPL v2.
*/
#include <linux/acpi_pmtmr.h>
diff --git a/drivers/clocksource/arc_timer.c b/drivers/clocksource/arc_timer.c
index b28970ca4a7a..b29b5a75333e 100644
--- a/drivers/clocksource/arc_timer.c
+++ b/drivers/clocksource/arc_timer.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2016-17 Synopsys, Inc. (www.synopsys.com)
* Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
- *
- * 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.
*/
/* ARC700 has two 32bit independent prog Timers: TIMER0 and TIMER1, Each can be
@@ -16,6 +13,7 @@
*/
#include <linux/interrupt.h>
+#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clocksource.h>
@@ -142,7 +140,7 @@ static u64 arc_read_rtc(struct clocksource *cs)
l = read_aux_reg(AUX_RTC_LOW);
h = read_aux_reg(AUX_RTC_HIGH);
status = read_aux_reg(AUX_RTC_CTRL);
- } while (!(status & _BITUL(31)));
+ } while (!(status & BIT(31)));
return (((u64)h) << 32) | l;
}
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 5c69c9a9a6a4..9a5464c625b4 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/clocksource/arm_arch_timer.c
*
* Copyright (C) 2011 ARM Ltd.
* All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#define pr_fmt(fmt) "arch_timer: " fmt
@@ -804,14 +801,7 @@ static void arch_timer_evtstrm_enable(int divider)
cntkctl |= (divider << ARCH_TIMER_EVT_TRIGGER_SHIFT)
| ARCH_TIMER_VIRT_EVT_EN;
arch_timer_set_cntkctl(cntkctl);
-#ifdef CONFIG_ARM64
- cpu_set_named_feature(EVTSTRM);
-#else
- elf_hwcap |= HWCAP_EVTSTRM;
-#endif
-#ifdef CONFIG_COMPAT
- compat_elf_hwcap |= COMPAT_HWCAP_EVTSTRM;
-#endif
+ arch_timer_set_evtstrm_feature();
cpumask_set_cpu(smp_processor_id(), &evtstrm_available);
}
@@ -1040,11 +1030,7 @@ static int arch_timer_cpu_pm_notify(struct notifier_block *self,
} else if (action == CPU_PM_ENTER_FAILED || action == CPU_PM_EXIT) {
arch_timer_set_cntkctl(__this_cpu_read(saved_cntkctl));
-#ifdef CONFIG_ARM64
- if (cpu_have_named_feature(EVTSTRM))
-#else
- if (elf_hwcap & HWCAP_EVTSTRM)
-#endif
+ if (arch_timer_have_evtstrm_feature())
cpumask_set_cpu(smp_processor_id(), &evtstrm_available);
}
return NOTIFY_OK;
diff --git a/drivers/clocksource/arm_global_timer.c b/drivers/clocksource/arm_global_timer.c
index 095bb965f621..88b2d38a7a61 100644
--- a/drivers/clocksource/arm_global_timer.c
+++ b/drivers/clocksource/arm_global_timer.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/clocksource/arm_global_timer.c
*
* Copyright (C) 2013 STMicroelectronics (R&D) Limited.
* Author: Stuart Menefy <stuart.menefy@st.com>
* Author: Srinivas Kandagatla <srinivas.kandagatla@st.com>
- *
- * 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.
*/
#include <linux/init.h>
diff --git a/drivers/clocksource/dummy_timer.c b/drivers/clocksource/dummy_timer.c
index 01f3f5a59bc6..6cee6dce5605 100644
--- a/drivers/clocksource/dummy_timer.c
+++ b/drivers/clocksource/dummy_timer.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/clocksource/dummy_timer.c
*
* Copyright (C) 2013 ARM Ltd.
* All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/clockchips.h>
#include <linux/cpu.h>
diff --git a/drivers/clocksource/dw_apb_timer.c b/drivers/clocksource/dw_apb_timer.c
index 1f5f734e4919..654766538f93 100644
--- a/drivers/clocksource/dw_apb_timer.c
+++ b/drivers/clocksource/dw_apb_timer.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* (C) Copyright 2009 Intel Corporation
* Author: Jacob Pan (jacob.jun.pan@intel.com)
*
* Shared with ARM platforms, Jamie Iles, Picochip 2011
*
- * 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.
- *
* Support for the Synopsys DesignWare APB Timers.
*/
#include <linux/dw_apb_timer.h>
diff --git a/drivers/clocksource/dw_apb_timer_of.c b/drivers/clocksource/dw_apb_timer_of.c
index db410acd8964..8c28b127759f 100644
--- a/drivers/clocksource/dw_apb_timer_of.c
+++ b/drivers/clocksource/dw_apb_timer_of.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Altera Corporation
* Copyright (c) 2011 Picochip Ltd., Jamie Iles
*
* Modified from mach-picoxcell/time.c
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/delay.h>
#include <linux/dw_apb_timer.h>
diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c
index 34bd250d46c6..74cb299f5089 100644
--- a/drivers/clocksource/exynos_mct.c
+++ b/drivers/clocksource/exynos_mct.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* linux/arch/arm/mach-exynos4/mct.c
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* EXYNOS4 MCT(Multi-Core Timer) support
- *
- * 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.
*/
#include <linux/interrupt.h>
@@ -209,7 +206,7 @@ static void exynos4_frc_resume(struct clocksource *cs)
static struct clocksource mct_frc = {
.name = "mct-frc",
- .rating = 400,
+ .rating = 450, /* use value higher than ARM arch timer */
.read = exynos4_frc_read,
.mask = CLOCKSOURCE_MASK(32),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
@@ -464,7 +461,7 @@ static int exynos4_mct_starting_cpu(unsigned int cpu)
evt->set_state_oneshot_stopped = set_state_shutdown;
evt->tick_resume = set_state_shutdown;
evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
- evt->rating = 450;
+ evt->rating = 500; /* use value higher than ARM arch timer */
exynos4_mct_write(TICK_BASE_CNT, mevt->base + MCT_L_TCNTB_OFFSET);
diff --git a/drivers/clocksource/hyperv_timer.c b/drivers/clocksource/hyperv_timer.c
new file mode 100644
index 000000000000..ba2c79e6a0ee
--- /dev/null
+++ b/drivers/clocksource/hyperv_timer.c
@@ -0,0 +1,339 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Clocksource driver for the synthetic counter and timers
+ * provided by the Hyper-V hypervisor to guest VMs, as described
+ * in the Hyper-V Top Level Functional Spec (TLFS). This driver
+ * is instruction set architecture independent.
+ *
+ * Copyright (C) 2019, Microsoft, Inc.
+ *
+ * Author: Michael Kelley <mikelley@microsoft.com>
+ */
+
+#include <linux/percpu.h>
+#include <linux/cpumask.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/sched_clock.h>
+#include <linux/mm.h>
+#include <clocksource/hyperv_timer.h>
+#include <asm/hyperv-tlfs.h>
+#include <asm/mshyperv.h>
+
+static struct clock_event_device __percpu *hv_clock_event;
+
+/*
+ * If false, we're using the old mechanism for stimer0 interrupts
+ * where it sends a VMbus message when it expires. The old
+ * mechanism is used when running on older versions of Hyper-V
+ * that don't support Direct Mode. While Hyper-V provides
+ * four stimer's per CPU, Linux uses only stimer0.
+ */
+static bool direct_mode_enabled;
+
+static int stimer0_irq;
+static int stimer0_vector;
+static int stimer0_message_sint;
+
+/*
+ * ISR for when stimer0 is operating in Direct Mode. Direct Mode
+ * does not use VMbus or any VMbus messages, so process here and not
+ * in the VMbus driver code.
+ */
+void hv_stimer0_isr(void)
+{
+ struct clock_event_device *ce;
+
+ ce = this_cpu_ptr(hv_clock_event);
+ ce->event_handler(ce);
+}
+EXPORT_SYMBOL_GPL(hv_stimer0_isr);
+
+static int hv_ce_set_next_event(unsigned long delta,
+ struct clock_event_device *evt)
+{
+ u64 current_tick;
+
+ current_tick = hyperv_cs->read(NULL);
+ current_tick += delta;
+ hv_init_timer(0, current_tick);
+ return 0;
+}
+
+static int hv_ce_shutdown(struct clock_event_device *evt)
+{
+ hv_init_timer(0, 0);
+ hv_init_timer_config(0, 0);
+ if (direct_mode_enabled)
+ hv_disable_stimer0_percpu_irq(stimer0_irq);
+
+ return 0;
+}
+
+static int hv_ce_set_oneshot(struct clock_event_device *evt)
+{
+ union hv_stimer_config timer_cfg;
+
+ timer_cfg.as_uint64 = 0;
+ timer_cfg.enable = 1;
+ timer_cfg.auto_enable = 1;
+ if (direct_mode_enabled) {
+ /*
+ * When it expires, the timer will directly interrupt
+ * on the specified hardware vector/IRQ.
+ */
+ timer_cfg.direct_mode = 1;
+ timer_cfg.apic_vector = stimer0_vector;
+ hv_enable_stimer0_percpu_irq(stimer0_irq);
+ } else {
+ /*
+ * When it expires, the timer will generate a VMbus message,
+ * to be handled by the normal VMbus interrupt handler.
+ */
+ timer_cfg.direct_mode = 0;
+ timer_cfg.sintx = stimer0_message_sint;
+ }
+ hv_init_timer_config(0, timer_cfg.as_uint64);
+ return 0;
+}
+
+/*
+ * hv_stimer_init - Per-cpu initialization of the clockevent
+ */
+void hv_stimer_init(unsigned int cpu)
+{
+ struct clock_event_device *ce;
+
+ /*
+ * Synthetic timers are always available except on old versions of
+ * Hyper-V on x86. In that case, just return as Linux will use a
+ * clocksource based on emulated PIT or LAPIC timer hardware.
+ */
+ if (!(ms_hyperv.features & HV_MSR_SYNTIMER_AVAILABLE))
+ return;
+
+ ce = per_cpu_ptr(hv_clock_event, cpu);
+ ce->name = "Hyper-V clockevent";
+ ce->features = CLOCK_EVT_FEAT_ONESHOT;
+ ce->cpumask = cpumask_of(cpu);
+ ce->rating = 1000;
+ ce->set_state_shutdown = hv_ce_shutdown;
+ ce->set_state_oneshot = hv_ce_set_oneshot;
+ ce->set_next_event = hv_ce_set_next_event;
+
+ clockevents_config_and_register(ce,
+ HV_CLOCK_HZ,
+ HV_MIN_DELTA_TICKS,
+ HV_MAX_MAX_DELTA_TICKS);
+}
+EXPORT_SYMBOL_GPL(hv_stimer_init);
+
+/*
+ * hv_stimer_cleanup - Per-cpu cleanup of the clockevent
+ */
+void hv_stimer_cleanup(unsigned int cpu)
+{
+ struct clock_event_device *ce;
+
+ /* Turn off clockevent device */
+ if (ms_hyperv.features & HV_MSR_SYNTIMER_AVAILABLE) {
+ ce = per_cpu_ptr(hv_clock_event, cpu);
+ hv_ce_shutdown(ce);
+ }
+}
+EXPORT_SYMBOL_GPL(hv_stimer_cleanup);
+
+/* hv_stimer_alloc - Global initialization of the clockevent and stimer0 */
+int hv_stimer_alloc(int sint)
+{
+ int ret;
+
+ hv_clock_event = alloc_percpu(struct clock_event_device);
+ if (!hv_clock_event)
+ return -ENOMEM;
+
+ direct_mode_enabled = ms_hyperv.misc_features &
+ HV_STIMER_DIRECT_MODE_AVAILABLE;
+ if (direct_mode_enabled) {
+ ret = hv_setup_stimer0_irq(&stimer0_irq, &stimer0_vector,
+ hv_stimer0_isr);
+ if (ret) {
+ free_percpu(hv_clock_event);
+ hv_clock_event = NULL;
+ return ret;
+ }
+ }
+
+ stimer0_message_sint = sint;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(hv_stimer_alloc);
+
+/* hv_stimer_free - Free global resources allocated by hv_stimer_alloc() */
+void hv_stimer_free(void)
+{
+ if (direct_mode_enabled && (stimer0_irq != 0)) {
+ hv_remove_stimer0_irq(stimer0_irq);
+ stimer0_irq = 0;
+ }
+ free_percpu(hv_clock_event);
+ hv_clock_event = NULL;
+}
+EXPORT_SYMBOL_GPL(hv_stimer_free);
+
+/*
+ * Do a global cleanup of clockevents for the cases of kexec and
+ * vmbus exit
+ */
+void hv_stimer_global_cleanup(void)
+{
+ int cpu;
+ struct clock_event_device *ce;
+
+ if (ms_hyperv.features & HV_MSR_SYNTIMER_AVAILABLE) {
+ for_each_present_cpu(cpu) {
+ ce = per_cpu_ptr(hv_clock_event, cpu);
+ clockevents_unbind_device(ce, cpu);
+ }
+ }
+ hv_stimer_free();
+}
+EXPORT_SYMBOL_GPL(hv_stimer_global_cleanup);
+
+/*
+ * Code and definitions for the Hyper-V clocksources. Two
+ * clocksources are defined: one that reads the Hyper-V defined MSR, and
+ * the other that uses the TSC reference page feature as defined in the
+ * TLFS. The MSR version is for compatibility with old versions of
+ * Hyper-V and 32-bit x86. The TSC reference page version is preferred.
+ */
+
+struct clocksource *hyperv_cs;
+EXPORT_SYMBOL_GPL(hyperv_cs);
+
+#ifdef CONFIG_HYPERV_TSCPAGE
+
+static struct ms_hyperv_tsc_page *tsc_pg;
+
+struct ms_hyperv_tsc_page *hv_get_tsc_page(void)
+{
+ return tsc_pg;
+}
+EXPORT_SYMBOL_GPL(hv_get_tsc_page);
+
+static u64 notrace read_hv_sched_clock_tsc(void)
+{
+ u64 current_tick = hv_read_tsc_page(tsc_pg);
+
+ if (current_tick == U64_MAX)
+ hv_get_time_ref_count(current_tick);
+
+ return current_tick;
+}
+
+static u64 read_hv_clock_tsc(struct clocksource *arg)
+{
+ return read_hv_sched_clock_tsc();
+}
+
+static struct clocksource hyperv_cs_tsc = {
+ .name = "hyperv_clocksource_tsc_page",
+ .rating = 400,
+ .read = read_hv_clock_tsc,
+ .mask = CLOCKSOURCE_MASK(64),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+#endif
+
+static u64 notrace read_hv_sched_clock_msr(void)
+{
+ u64 current_tick;
+ /*
+ * Read the partition counter to get the current tick count. This count
+ * is set to 0 when the partition is created and is incremented in
+ * 100 nanosecond units.
+ */
+ hv_get_time_ref_count(current_tick);
+ return current_tick;
+}
+
+static u64 read_hv_clock_msr(struct clocksource *arg)
+{
+ return read_hv_sched_clock_msr();
+}
+
+static struct clocksource hyperv_cs_msr = {
+ .name = "hyperv_clocksource_msr",
+ .rating = 400,
+ .read = read_hv_clock_msr,
+ .mask = CLOCKSOURCE_MASK(64),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+#ifdef CONFIG_HYPERV_TSCPAGE
+static bool __init hv_init_tsc_clocksource(void)
+{
+ u64 tsc_msr;
+ phys_addr_t phys_addr;
+
+ if (!(ms_hyperv.features & HV_MSR_REFERENCE_TSC_AVAILABLE))
+ return false;
+
+ tsc_pg = vmalloc(PAGE_SIZE);
+ if (!tsc_pg)
+ return false;
+
+ hyperv_cs = &hyperv_cs_tsc;
+ phys_addr = page_to_phys(vmalloc_to_page(tsc_pg));
+
+ /*
+ * The Hyper-V TLFS specifies to preserve the value of reserved
+ * bits in registers. So read the existing value, preserve the
+ * low order 12 bits, and add in the guest physical address
+ * (which already has at least the low 12 bits set to zero since
+ * it is page aligned). Also set the "enable" bit, which is bit 0.
+ */
+ hv_get_reference_tsc(tsc_msr);
+ tsc_msr &= GENMASK_ULL(11, 0);
+ tsc_msr = tsc_msr | 0x1 | (u64)phys_addr;
+ hv_set_reference_tsc(tsc_msr);
+
+ hv_set_clocksource_vdso(hyperv_cs_tsc);
+ clocksource_register_hz(&hyperv_cs_tsc, NSEC_PER_SEC/100);
+
+ /* sched_clock_register is needed on ARM64 but is a no-op on x86 */
+ sched_clock_register(read_hv_sched_clock_tsc, 64, HV_CLOCK_HZ);
+ return true;
+}
+#else
+static bool __init hv_init_tsc_clocksource(void)
+{
+ return false;
+}
+#endif
+
+
+void __init hv_init_clocksource(void)
+{
+ /*
+ * Try to set up the TSC page clocksource. If it succeeds, we're
+ * done. Otherwise, set up the MSR clocksoruce. At least one of
+ * these will always be available except on very old versions of
+ * Hyper-V on x86. In that case we won't have a Hyper-V
+ * clocksource, but Linux will still run with a clocksource based
+ * on the emulated PIT or LAPIC timer.
+ */
+ if (hv_init_tsc_clocksource())
+ return;
+
+ if (!(ms_hyperv.features & HV_MSR_TIME_REF_COUNT_AVAILABLE))
+ return;
+
+ hyperv_cs = &hyperv_cs_msr;
+ clocksource_register_hz(&hyperv_cs_msr, NSEC_PER_SEC/100);
+
+ /* sched_clock_register is needed on ARM64 but is a no-op on x86 */
+ sched_clock_register(read_hv_sched_clock_msr, 64, HV_CLOCK_HZ);
+}
+EXPORT_SYMBOL_GPL(hv_init_clocksource);
diff --git a/drivers/clocksource/mmio.c b/drivers/clocksource/mmio.c
index 4c4df981d8cc..9de751531831 100644
--- a/drivers/clocksource/mmio.c
+++ b/drivers/clocksource/mmio.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic MMIO clocksource support
- *
- * 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.
*/
#include <linux/clocksource.h>
#include <linux/errno.h>
diff --git a/drivers/clocksource/mps2-timer.c b/drivers/clocksource/mps2-timer.c
index aa4d63af8706..2e64d984c83a 100644
--- a/drivers/clocksource/mps2-timer.c
+++ b/drivers/clocksource/mps2-timer.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2015 ARM Limited
*
* Author: Vladimir Murzin <vladimir.murzin@arm.com>
- *
- * 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.
- *
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/clocksource/nomadik-mtu.c b/drivers/clocksource/nomadik-mtu.c
index 19b336c9b417..3f7fa8c01367 100644
--- a/drivers/clocksource/nomadik-mtu.c
+++ b/drivers/clocksource/nomadik-mtu.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2008 STMicroelectronics
* Copyright (C) 2010 Alessandro Rubini
* Copyright (C) 2010 Linus Walleij for ST-Ericsson
- *
- * 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.
*/
#include <linux/init.h>
#include <linux/interrupt.h>
diff --git a/drivers/clocksource/samsung_pwm_timer.c b/drivers/clocksource/samsung_pwm_timer.c
index 6d5d126357c2..895f53eb5771 100644
--- a/drivers/clocksource/samsung_pwm_timer.c
+++ b/drivers/clocksource/samsung_pwm_timer.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
* samsung - Common hr-timer support (s3c and s5p)
- *
- * 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.
*/
#include <linux/interrupt.h>
diff --git a/drivers/clocksource/timer-atmel-pit.c b/drivers/clocksource/timer-atmel-pit.c
index 2fab18fae4fc..b4f264ed1937 100644
--- a/drivers/clocksource/timer-atmel-pit.c
+++ b/drivers/clocksource/timer-atmel-pit.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* at91sam926x_time.c - Periodic Interval Timer (PIT) for at91sam926x
*
* Copyright (C) 2005-2006 M. Amine SAYA, ATMEL Rousset, France
* Revision 2005 M. Nicolas Diremdjian, ATMEL Rousset, France
* Converted to ClockSource/ClockEvents by David Brownell.
- *
- * 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.
*/
#define pr_fmt(fmt) "AT91: PIT: " fmt
diff --git a/drivers/clocksource/timer-davinci.c b/drivers/clocksource/timer-davinci.c
new file mode 100644
index 000000000000..62745c962049
--- /dev/null
+++ b/drivers/clocksource/timer-davinci.c
@@ -0,0 +1,369 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * TI DaVinci clocksource driver
+ *
+ * Copyright (C) 2019 Texas Instruments
+ * Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
+ * (with tiny parts adopted from code by Kevin Hilman <khilman@baylibre.com>)
+ */
+
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/sched_clock.h>
+
+#include <clocksource/timer-davinci.h>
+
+#undef pr_fmt
+#define pr_fmt(fmt) "%s: " fmt "\n", __func__
+
+#define DAVINCI_TIMER_REG_TIM12 0x10
+#define DAVINCI_TIMER_REG_TIM34 0x14
+#define DAVINCI_TIMER_REG_PRD12 0x18
+#define DAVINCI_TIMER_REG_PRD34 0x1c
+#define DAVINCI_TIMER_REG_TCR 0x20
+#define DAVINCI_TIMER_REG_TGCR 0x24
+
+#define DAVINCI_TIMER_TIMMODE_MASK GENMASK(3, 2)
+#define DAVINCI_TIMER_RESET_MASK GENMASK(1, 0)
+#define DAVINCI_TIMER_TIMMODE_32BIT_UNCHAINED BIT(2)
+#define DAVINCI_TIMER_UNRESET GENMASK(1, 0)
+
+#define DAVINCI_TIMER_ENAMODE_MASK GENMASK(1, 0)
+#define DAVINCI_TIMER_ENAMODE_DISABLED 0x00
+#define DAVINCI_TIMER_ENAMODE_ONESHOT BIT(0)
+#define DAVINCI_TIMER_ENAMODE_PERIODIC BIT(1)
+
+#define DAVINCI_TIMER_ENAMODE_SHIFT_TIM12 6
+#define DAVINCI_TIMER_ENAMODE_SHIFT_TIM34 22
+
+#define DAVINCI_TIMER_MIN_DELTA 0x01
+#define DAVINCI_TIMER_MAX_DELTA 0xfffffffe
+
+#define DAVINCI_TIMER_CLKSRC_BITS 32
+
+#define DAVINCI_TIMER_TGCR_DEFAULT \
+ (DAVINCI_TIMER_TIMMODE_32BIT_UNCHAINED | DAVINCI_TIMER_UNRESET)
+
+struct davinci_clockevent {
+ struct clock_event_device dev;
+ void __iomem *base;
+ unsigned int cmp_off;
+};
+
+/*
+ * This must be globally accessible by davinci_timer_read_sched_clock(), so
+ * let's keep it here.
+ */
+static struct {
+ struct clocksource dev;
+ void __iomem *base;
+ unsigned int tim_off;
+} davinci_clocksource;
+
+static struct davinci_clockevent *
+to_davinci_clockevent(struct clock_event_device *clockevent)
+{
+ return container_of(clockevent, struct davinci_clockevent, dev);
+}
+
+static unsigned int
+davinci_clockevent_read(struct davinci_clockevent *clockevent,
+ unsigned int reg)
+{
+ return readl_relaxed(clockevent->base + reg);
+}
+
+static void davinci_clockevent_write(struct davinci_clockevent *clockevent,
+ unsigned int reg, unsigned int val)
+{
+ writel_relaxed(val, clockevent->base + reg);
+}
+
+static void davinci_tim12_shutdown(void __iomem *base)
+{
+ unsigned int tcr;
+
+ tcr = DAVINCI_TIMER_ENAMODE_DISABLED <<
+ DAVINCI_TIMER_ENAMODE_SHIFT_TIM12;
+ /*
+ * This function is only ever called if we're using both timer
+ * halves. In this case TIM34 runs in periodic mode and we must
+ * not modify it.
+ */
+ tcr |= DAVINCI_TIMER_ENAMODE_PERIODIC <<
+ DAVINCI_TIMER_ENAMODE_SHIFT_TIM34;
+
+ writel_relaxed(tcr, base + DAVINCI_TIMER_REG_TCR);
+}
+
+static void davinci_tim12_set_oneshot(void __iomem *base)
+{
+ unsigned int tcr;
+
+ tcr = DAVINCI_TIMER_ENAMODE_ONESHOT <<
+ DAVINCI_TIMER_ENAMODE_SHIFT_TIM12;
+ /* Same as above. */
+ tcr |= DAVINCI_TIMER_ENAMODE_PERIODIC <<
+ DAVINCI_TIMER_ENAMODE_SHIFT_TIM34;
+
+ writel_relaxed(tcr, base + DAVINCI_TIMER_REG_TCR);
+}
+
+static int davinci_clockevent_shutdown(struct clock_event_device *dev)
+{
+ struct davinci_clockevent *clockevent;
+
+ clockevent = to_davinci_clockevent(dev);
+
+ davinci_tim12_shutdown(clockevent->base);
+
+ return 0;
+}
+
+static int davinci_clockevent_set_oneshot(struct clock_event_device *dev)
+{
+ struct davinci_clockevent *clockevent = to_davinci_clockevent(dev);
+
+ davinci_clockevent_write(clockevent, DAVINCI_TIMER_REG_TIM12, 0x0);
+
+ davinci_tim12_set_oneshot(clockevent->base);
+
+ return 0;
+}
+
+static int
+davinci_clockevent_set_next_event_std(unsigned long cycles,
+ struct clock_event_device *dev)
+{
+ struct davinci_clockevent *clockevent = to_davinci_clockevent(dev);
+
+ davinci_clockevent_shutdown(dev);
+
+ davinci_clockevent_write(clockevent, DAVINCI_TIMER_REG_TIM12, 0x0);
+ davinci_clockevent_write(clockevent, DAVINCI_TIMER_REG_PRD12, cycles);
+
+ davinci_clockevent_set_oneshot(dev);
+
+ return 0;
+}
+
+static int
+davinci_clockevent_set_next_event_cmp(unsigned long cycles,
+ struct clock_event_device *dev)
+{
+ struct davinci_clockevent *clockevent = to_davinci_clockevent(dev);
+ unsigned int curr_time;
+
+ curr_time = davinci_clockevent_read(clockevent,
+ DAVINCI_TIMER_REG_TIM12);
+ davinci_clockevent_write(clockevent,
+ clockevent->cmp_off, curr_time + cycles);
+
+ return 0;
+}
+
+static irqreturn_t davinci_timer_irq_timer(int irq, void *data)
+{
+ struct davinci_clockevent *clockevent = data;
+
+ if (!clockevent_state_oneshot(&clockevent->dev))
+ davinci_tim12_shutdown(clockevent->base);
+
+ clockevent->dev.event_handler(&clockevent->dev);
+
+ return IRQ_HANDLED;
+}
+
+static u64 notrace davinci_timer_read_sched_clock(void)
+{
+ return readl_relaxed(davinci_clocksource.base +
+ davinci_clocksource.tim_off);
+}
+
+static u64 davinci_clocksource_read(struct clocksource *dev)
+{
+ return davinci_timer_read_sched_clock();
+}
+
+/*
+ * Standard use-case: we're using tim12 for clockevent and tim34 for
+ * clocksource. The default is making the former run in oneshot mode
+ * and the latter in periodic mode.
+ */
+static void davinci_clocksource_init_tim34(void __iomem *base)
+{
+ int tcr;
+
+ tcr = DAVINCI_TIMER_ENAMODE_PERIODIC <<
+ DAVINCI_TIMER_ENAMODE_SHIFT_TIM34;
+ tcr |= DAVINCI_TIMER_ENAMODE_ONESHOT <<
+ DAVINCI_TIMER_ENAMODE_SHIFT_TIM12;
+
+ writel_relaxed(0x0, base + DAVINCI_TIMER_REG_TIM34);
+ writel_relaxed(UINT_MAX, base + DAVINCI_TIMER_REG_PRD34);
+ writel_relaxed(tcr, base + DAVINCI_TIMER_REG_TCR);
+}
+
+/*
+ * Special use-case on da830: the DSP may use tim34. We're using tim12 for
+ * both clocksource and clockevent. We set tim12 to periodic and don't touch
+ * tim34.
+ */
+static void davinci_clocksource_init_tim12(void __iomem *base)
+{
+ unsigned int tcr;
+
+ tcr = DAVINCI_TIMER_ENAMODE_PERIODIC <<
+ DAVINCI_TIMER_ENAMODE_SHIFT_TIM12;
+
+ writel_relaxed(0x0, base + DAVINCI_TIMER_REG_TIM12);
+ writel_relaxed(UINT_MAX, base + DAVINCI_TIMER_REG_PRD12);
+ writel_relaxed(tcr, base + DAVINCI_TIMER_REG_TCR);
+}
+
+static void davinci_timer_init(void __iomem *base)
+{
+ /* Set clock to internal mode and disable it. */
+ writel_relaxed(0x0, base + DAVINCI_TIMER_REG_TCR);
+ /*
+ * Reset both 32-bit timers, set no prescaler for timer 34, set the
+ * timer to dual 32-bit unchained mode, unreset both 32-bit timers.
+ */
+ writel_relaxed(DAVINCI_TIMER_TGCR_DEFAULT,
+ base + DAVINCI_TIMER_REG_TGCR);
+ /* Init both counters to zero. */
+ writel_relaxed(0x0, base + DAVINCI_TIMER_REG_TIM12);
+ writel_relaxed(0x0, base + DAVINCI_TIMER_REG_TIM34);
+}
+
+int __init davinci_timer_register(struct clk *clk,
+ const struct davinci_timer_cfg *timer_cfg)
+{
+ struct davinci_clockevent *clockevent;
+ unsigned int tick_rate;
+ void __iomem *base;
+ int rv;
+
+ rv = clk_prepare_enable(clk);
+ if (rv) {
+ pr_err("Unable to prepare and enable the timer clock");
+ return rv;
+ }
+
+ if (!request_mem_region(timer_cfg->reg.start,
+ resource_size(&timer_cfg->reg),
+ "davinci-timer")) {
+ pr_err("Unable to request memory region");
+ return -EBUSY;
+ }
+
+ base = ioremap(timer_cfg->reg.start, resource_size(&timer_cfg->reg));
+ if (!base) {
+ pr_err("Unable to map the register range");
+ return -ENOMEM;
+ }
+
+ davinci_timer_init(base);
+ tick_rate = clk_get_rate(clk);
+
+ clockevent = kzalloc(sizeof(*clockevent), GFP_KERNEL | __GFP_NOFAIL);
+ if (!clockevent) {
+ pr_err("Error allocating memory for clockevent data");
+ return -ENOMEM;
+ }
+
+ clockevent->dev.name = "tim12";
+ clockevent->dev.features = CLOCK_EVT_FEAT_ONESHOT;
+ clockevent->dev.cpumask = cpumask_of(0);
+ clockevent->base = base;
+
+ if (timer_cfg->cmp_off) {
+ clockevent->cmp_off = timer_cfg->cmp_off;
+ clockevent->dev.set_next_event =
+ davinci_clockevent_set_next_event_cmp;
+ } else {
+ clockevent->dev.set_next_event =
+ davinci_clockevent_set_next_event_std;
+ clockevent->dev.set_state_oneshot =
+ davinci_clockevent_set_oneshot;
+ clockevent->dev.set_state_shutdown =
+ davinci_clockevent_shutdown;
+ }
+
+ rv = request_irq(timer_cfg->irq[DAVINCI_TIMER_CLOCKEVENT_IRQ].start,
+ davinci_timer_irq_timer, IRQF_TIMER,
+ "clockevent/tim12", clockevent);
+ if (rv) {
+ pr_err("Unable to request the clockevent interrupt");
+ return rv;
+ }
+
+ clockevents_config_and_register(&clockevent->dev, tick_rate,
+ DAVINCI_TIMER_MIN_DELTA,
+ DAVINCI_TIMER_MAX_DELTA);
+
+ davinci_clocksource.dev.rating = 300;
+ davinci_clocksource.dev.read = davinci_clocksource_read;
+ davinci_clocksource.dev.mask =
+ CLOCKSOURCE_MASK(DAVINCI_TIMER_CLKSRC_BITS);
+ davinci_clocksource.dev.flags = CLOCK_SOURCE_IS_CONTINUOUS;
+ davinci_clocksource.base = base;
+
+ if (timer_cfg->cmp_off) {
+ davinci_clocksource.dev.name = "tim12";
+ davinci_clocksource.tim_off = DAVINCI_TIMER_REG_TIM12;
+ davinci_clocksource_init_tim12(base);
+ } else {
+ davinci_clocksource.dev.name = "tim34";
+ davinci_clocksource.tim_off = DAVINCI_TIMER_REG_TIM34;
+ davinci_clocksource_init_tim34(base);
+ }
+
+ rv = clocksource_register_hz(&davinci_clocksource.dev, tick_rate);
+ if (rv) {
+ pr_err("Unable to register clocksource");
+ return rv;
+ }
+
+ sched_clock_register(davinci_timer_read_sched_clock,
+ DAVINCI_TIMER_CLKSRC_BITS, tick_rate);
+
+ return 0;
+}
+
+static int __init of_davinci_timer_register(struct device_node *np)
+{
+ struct davinci_timer_cfg timer_cfg = { };
+ struct clk *clk;
+ int rv;
+
+ rv = of_address_to_resource(np, 0, &timer_cfg.reg);
+ if (rv) {
+ pr_err("Unable to get the register range for timer");
+ return rv;
+ }
+
+ rv = of_irq_to_resource_table(np, timer_cfg.irq,
+ DAVINCI_TIMER_NUM_IRQS);
+ if (rv != DAVINCI_TIMER_NUM_IRQS) {
+ pr_err("Unable to get the interrupts for timer");
+ return rv;
+ }
+
+ clk = of_clk_get(np, 0);
+ if (IS_ERR(clk)) {
+ pr_err("Unable to get the timer clock");
+ return PTR_ERR(clk);
+ }
+
+ rv = davinci_timer_register(clk, &timer_cfg);
+ if (rv)
+ clk_put(clk);
+
+ return rv;
+}
+TIMER_OF_DECLARE(davinci_timer, "ti,da830-timer", of_davinci_timer_register);
diff --git a/drivers/clocksource/timer-efm32.c b/drivers/clocksource/timer-efm32.c
index 257e810ec1ad..5a22cb079ad3 100644
--- a/drivers/clocksource/timer-efm32.c
+++ b/drivers/clocksource/timer-efm32.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Pengutronix
* Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/clocksource/timer-imx-sysctr.c b/drivers/clocksource/timer-imx-sysctr.c
new file mode 100644
index 000000000000..fd7d68066efb
--- /dev/null
+++ b/drivers/clocksource/timer-imx-sysctr.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright 2017-2019 NXP
+
+#include <linux/interrupt.h>
+#include <linux/clockchips.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#include "timer-of.h"
+
+#define CMP_OFFSET 0x10000
+
+#define CNTCV_LO 0x8
+#define CNTCV_HI 0xc
+#define CMPCV_LO (CMP_OFFSET + 0x20)
+#define CMPCV_HI (CMP_OFFSET + 0x24)
+#define CMPCR (CMP_OFFSET + 0x2c)
+
+#define SYS_CTR_EN 0x1
+#define SYS_CTR_IRQ_MASK 0x2
+
+static void __iomem *sys_ctr_base;
+static u32 cmpcr;
+
+static void sysctr_timer_enable(bool enable)
+{
+ writel(enable ? cmpcr | SYS_CTR_EN : cmpcr, sys_ctr_base + CMPCR);
+}
+
+static void sysctr_irq_acknowledge(void)
+{
+ /*
+ * clear the enable bit(EN =0) will clear
+ * the status bit(ISTAT = 0), then the interrupt
+ * signal will be negated(acknowledged).
+ */
+ sysctr_timer_enable(false);
+}
+
+static inline u64 sysctr_read_counter(void)
+{
+ u32 cnt_hi, tmp_hi, cnt_lo;
+
+ do {
+ cnt_hi = readl_relaxed(sys_ctr_base + CNTCV_HI);
+ cnt_lo = readl_relaxed(sys_ctr_base + CNTCV_LO);
+ tmp_hi = readl_relaxed(sys_ctr_base + CNTCV_HI);
+ } while (tmp_hi != cnt_hi);
+
+ return ((u64) cnt_hi << 32) | cnt_lo;
+}
+
+static int sysctr_set_next_event(unsigned long delta,
+ struct clock_event_device *evt)
+{
+ u32 cmp_hi, cmp_lo;
+ u64 next;
+
+ sysctr_timer_enable(false);
+
+ next = sysctr_read_counter();
+
+ next += delta;
+
+ cmp_hi = (next >> 32) & 0x00fffff;
+ cmp_lo = next & 0xffffffff;
+
+ writel_relaxed(cmp_hi, sys_ctr_base + CMPCV_HI);
+ writel_relaxed(cmp_lo, sys_ctr_base + CMPCV_LO);
+
+ sysctr_timer_enable(true);
+
+ return 0;
+}
+
+static int sysctr_set_state_oneshot(struct clock_event_device *evt)
+{
+ return 0;
+}
+
+static int sysctr_set_state_shutdown(struct clock_event_device *evt)
+{
+ sysctr_timer_enable(false);
+
+ return 0;
+}
+
+static irqreturn_t sysctr_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = dev_id;
+
+ sysctr_irq_acknowledge();
+
+ evt->event_handler(evt);
+
+ return IRQ_HANDLED;
+}
+
+static struct timer_of to_sysctr = {
+ .flags = TIMER_OF_IRQ | TIMER_OF_CLOCK | TIMER_OF_BASE,
+ .clkevt = {
+ .name = "i.MX system counter timer",
+ .features = CLOCK_EVT_FEAT_ONESHOT |
+ CLOCK_EVT_FEAT_DYNIRQ,
+ .set_state_oneshot = sysctr_set_state_oneshot,
+ .set_next_event = sysctr_set_next_event,
+ .set_state_shutdown = sysctr_set_state_shutdown,
+ .rating = 200,
+ },
+ .of_irq = {
+ .handler = sysctr_timer_interrupt,
+ .flags = IRQF_TIMER | IRQF_IRQPOLL,
+ },
+ .of_clk = {
+ .name = "per",
+ },
+};
+
+static void __init sysctr_clockevent_init(void)
+{
+ to_sysctr.clkevt.cpumask = cpumask_of(0);
+
+ clockevents_config_and_register(&to_sysctr.clkevt,
+ timer_of_rate(&to_sysctr),
+ 0xff, 0x7fffffff);
+}
+
+static int __init sysctr_timer_init(struct device_node *np)
+{
+ int ret = 0;
+
+ ret = timer_of_init(np, &to_sysctr);
+ if (ret)
+ return ret;
+
+ sys_ctr_base = timer_of_base(&to_sysctr);
+ cmpcr = readl(sys_ctr_base + CMPCR);
+ cmpcr &= ~SYS_CTR_EN;
+
+ sysctr_clockevent_init();
+
+ return 0;
+}
+TIMER_OF_DECLARE(sysctr_timer, "nxp,sysctr-timer", sysctr_timer_init);
diff --git a/drivers/clocksource/timer-ixp4xx.c b/drivers/clocksource/timer-ixp4xx.c
index 5c2190b654cd..9396745e1c17 100644
--- a/drivers/clocksource/timer-ixp4xx.c
+++ b/drivers/clocksource/timer-ixp4xx.c
@@ -75,14 +75,19 @@ to_ixp4xx_timer(struct clock_event_device *evt)
return container_of(evt, struct ixp4xx_timer, clkevt);
}
-static u64 notrace ixp4xx_read_sched_clock(void)
+static unsigned long ixp4xx_read_timer(void)
{
return __raw_readl(local_ixp4xx_timer->base + IXP4XX_OSTS_OFFSET);
}
+static u64 notrace ixp4xx_read_sched_clock(void)
+{
+ return ixp4xx_read_timer();
+}
+
static u64 ixp4xx_clocksource_read(struct clocksource *c)
{
- return __raw_readl(local_ixp4xx_timer->base + IXP4XX_OSTS_OFFSET);
+ return ixp4xx_read_timer();
}
static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id)
@@ -224,6 +229,13 @@ static __init int ixp4xx_timer_register(void __iomem *base,
sched_clock_register(ixp4xx_read_sched_clock, 32, timer_freq);
+#ifdef CONFIG_ARM
+ /* Also use this timer for delays */
+ tmr->delay_timer.read_current_timer = ixp4xx_read_timer;
+ tmr->delay_timer.freq = timer_freq;
+ register_current_timer_delay(&tmr->delay_timer);
+#endif
+
return 0;
}
diff --git a/drivers/clocksource/timer-keystone.c b/drivers/clocksource/timer-keystone.c
index f5b2eda30bf3..fea8a4f85669 100644
--- a/drivers/clocksource/timer-keystone.c
+++ b/drivers/clocksource/timer-keystone.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Keystone broadcast clock-event
*
* Copyright 2013 Texas Instruments, Inc.
*
* Author: Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>
- *
- * 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.
- *
*/
#include <linux/clk.h>
diff --git a/drivers/clocksource/timer-meson6.c b/drivers/clocksource/timer-meson6.c
index 84bd9479c3f8..9e8b467c71da 100644
--- a/drivers/clocksource/timer-meson6.c
+++ b/drivers/clocksource/timer-meson6.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Amlogic Meson6 SoCs timer handling.
*
* Copyright (C) 2014 Carlo Caione <carlo@caione.org>
*
* Based on code from Amlogic, 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.
*/
#include <linux/bitfield.h>
diff --git a/drivers/clocksource/timer-npcm7xx.c b/drivers/clocksource/timer-npcm7xx.c
index 7a9bb5532d99..8a30da7f083b 100644
--- a/drivers/clocksource/timer-npcm7xx.c
+++ b/drivers/clocksource/timer-npcm7xx.c
@@ -32,7 +32,7 @@
#define NPCM7XX_Tx_INTEN BIT(29)
#define NPCM7XX_Tx_COUNTEN BIT(30)
#define NPCM7XX_Tx_ONESHOT 0x0
-#define NPCM7XX_Tx_OPER GENMASK(3, 27)
+#define NPCM7XX_Tx_OPER GENMASK(27, 3)
#define NPCM7XX_Tx_MIN_PRESCALE 0x1
#define NPCM7XX_Tx_TDR_MASK_BITS 24
#define NPCM7XX_Tx_MAX_CNT 0xFFFFFF
diff --git a/drivers/clocksource/timer-pxa.c b/drivers/clocksource/timer-pxa.c
index 395837938301..913a5d354a1f 100644
--- a/drivers/clocksource/timer-pxa.c
+++ b/drivers/clocksource/timer-pxa.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* arch/arm/mach-pxa/time.c
*
@@ -6,10 +7,6 @@
*
* Derived from Nicolas Pitre's PXA timer handler Copyright (c) 2001
* by MontaVista Software, Inc. (Nico, your code rocks!)
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/clocksource/timer-rockchip.c b/drivers/clocksource/timer-rockchip.c
index 33f370dbd0d6..1f95d0aca08f 100644
--- a/drivers/clocksource/timer-rockchip.c
+++ b/drivers/clocksource/timer-rockchip.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Rockchip timer support
*
* Copyright (C) Daniel Lezcano <daniel.lezcano@linaro.org>
- *
- * 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.
*/
#include <linux/clk.h>
#include <linux/clockchips.h>
diff --git a/drivers/clocksource/timer-tegra.c b/drivers/clocksource/timer-tegra.c
new file mode 100644
index 000000000000..e9635c25eef4
--- /dev/null
+++ b/drivers/clocksource/timer-tegra.c
@@ -0,0 +1,416 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ * Colin Cross <ccross@google.com>
+ */
+
+#define pr_fmt(fmt) "tegra-timer: " fmt
+
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/cpu.h>
+#include <linux/cpumask.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/percpu.h>
+#include <linux/sched_clock.h>
+#include <linux/time.h>
+
+#include "timer-of.h"
+
+#define RTC_SECONDS 0x08
+#define RTC_SHADOW_SECONDS 0x0c
+#define RTC_MILLISECONDS 0x10
+
+#define TIMERUS_CNTR_1US 0x10
+#define TIMERUS_USEC_CFG 0x14
+#define TIMERUS_CNTR_FREEZE 0x4c
+
+#define TIMER_PTV 0x0
+#define TIMER_PTV_EN BIT(31)
+#define TIMER_PTV_PER BIT(30)
+#define TIMER_PCR 0x4
+#define TIMER_PCR_INTR_CLR BIT(30)
+
+#define TIMER1_BASE 0x00
+#define TIMER2_BASE 0x08
+#define TIMER3_BASE 0x50
+#define TIMER4_BASE 0x58
+#define TIMER10_BASE 0x90
+
+#define TIMER1_IRQ_IDX 0
+#define TIMER10_IRQ_IDX 10
+
+#define TIMER_1MHz 1000000
+
+static u32 usec_config;
+static void __iomem *timer_reg_base;
+
+static int tegra_timer_set_next_event(unsigned long cycles,
+ struct clock_event_device *evt)
+{
+ void __iomem *reg_base = timer_of_base(to_timer_of(evt));
+
+ /*
+ * Tegra's timer uses n+1 scheme for the counter, i.e. timer will
+ * fire after one tick if 0 is loaded.
+ *
+ * The minimum and maximum numbers of oneshot ticks are defined
+ * by clockevents_config_and_register(1, 0x1fffffff + 1) invocation
+ * below in the code. Hence the cycles (ticks) can't be outside of
+ * a range supportable by hardware.
+ */
+ writel_relaxed(TIMER_PTV_EN | (cycles - 1), reg_base + TIMER_PTV);
+
+ return 0;
+}
+
+static int tegra_timer_shutdown(struct clock_event_device *evt)
+{
+ void __iomem *reg_base = timer_of_base(to_timer_of(evt));
+
+ writel_relaxed(0, reg_base + TIMER_PTV);
+
+ return 0;
+}
+
+static int tegra_timer_set_periodic(struct clock_event_device *evt)
+{
+ void __iomem *reg_base = timer_of_base(to_timer_of(evt));
+ unsigned long period = timer_of_period(to_timer_of(evt));
+
+ writel_relaxed(TIMER_PTV_EN | TIMER_PTV_PER | (period - 1),
+ reg_base + TIMER_PTV);
+
+ return 0;
+}
+
+static irqreturn_t tegra_timer_isr(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = dev_id;
+ void __iomem *reg_base = timer_of_base(to_timer_of(evt));
+
+ writel_relaxed(TIMER_PCR_INTR_CLR, reg_base + TIMER_PCR);
+ evt->event_handler(evt);
+
+ return IRQ_HANDLED;
+}
+
+static void tegra_timer_suspend(struct clock_event_device *evt)
+{
+ void __iomem *reg_base = timer_of_base(to_timer_of(evt));
+
+ writel_relaxed(TIMER_PCR_INTR_CLR, reg_base + TIMER_PCR);
+}
+
+static void tegra_timer_resume(struct clock_event_device *evt)
+{
+ writel_relaxed(usec_config, timer_reg_base + TIMERUS_USEC_CFG);
+}
+
+static DEFINE_PER_CPU(struct timer_of, tegra_to) = {
+ .flags = TIMER_OF_CLOCK | TIMER_OF_BASE,
+
+ .clkevt = {
+ .name = "tegra_timer",
+ .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
+ .set_next_event = tegra_timer_set_next_event,
+ .set_state_shutdown = tegra_timer_shutdown,
+ .set_state_periodic = tegra_timer_set_periodic,
+ .set_state_oneshot = tegra_timer_shutdown,
+ .tick_resume = tegra_timer_shutdown,
+ .suspend = tegra_timer_suspend,
+ .resume = tegra_timer_resume,
+ },
+};
+
+static int tegra_timer_setup(unsigned int cpu)
+{
+ struct timer_of *to = per_cpu_ptr(&tegra_to, cpu);
+
+ writel_relaxed(0, timer_of_base(to) + TIMER_PTV);
+ writel_relaxed(TIMER_PCR_INTR_CLR, timer_of_base(to) + TIMER_PCR);
+
+ irq_force_affinity(to->clkevt.irq, cpumask_of(cpu));
+ enable_irq(to->clkevt.irq);
+
+ /*
+ * Tegra's timer uses n+1 scheme for the counter, i.e. timer will
+ * fire after one tick if 0 is loaded and thus minimum number of
+ * ticks is 1. In result both of the clocksource's tick limits are
+ * higher than a minimum and maximum that hardware register can
+ * take by 1, this is then taken into account by set_next_event
+ * callback.
+ */
+ clockevents_config_and_register(&to->clkevt, timer_of_rate(to),
+ 1, /* min */
+ 0x1fffffff + 1); /* max 29 bits + 1 */
+
+ return 0;
+}
+
+static int tegra_timer_stop(unsigned int cpu)
+{
+ struct timer_of *to = per_cpu_ptr(&tegra_to, cpu);
+
+ to->clkevt.set_state_shutdown(&to->clkevt);
+ disable_irq_nosync(to->clkevt.irq);
+
+ return 0;
+}
+
+static u64 notrace tegra_read_sched_clock(void)
+{
+ return readl_relaxed(timer_reg_base + TIMERUS_CNTR_1US);
+}
+
+#ifdef CONFIG_ARM
+static unsigned long tegra_delay_timer_read_counter_long(void)
+{
+ return readl_relaxed(timer_reg_base + TIMERUS_CNTR_1US);
+}
+
+static struct delay_timer tegra_delay_timer = {
+ .read_current_timer = tegra_delay_timer_read_counter_long,
+ .freq = TIMER_1MHz,
+};
+#endif
+
+static struct timer_of suspend_rtc_to = {
+ .flags = TIMER_OF_BASE | TIMER_OF_CLOCK,
+};
+
+/*
+ * tegra_rtc_read - Reads the Tegra RTC registers
+ * Care must be taken that this function is not called while the
+ * tegra_rtc driver could be executing to avoid race conditions
+ * on the RTC shadow register
+ */
+static u64 tegra_rtc_read_ms(struct clocksource *cs)
+{
+ void __iomem *reg_base = timer_of_base(&suspend_rtc_to);
+
+ u32 ms = readl_relaxed(reg_base + RTC_MILLISECONDS);
+ u32 s = readl_relaxed(reg_base + RTC_SHADOW_SECONDS);
+
+ return (u64)s * MSEC_PER_SEC + ms;
+}
+
+static struct clocksource suspend_rtc_clocksource = {
+ .name = "tegra_suspend_timer",
+ .rating = 200,
+ .read = tegra_rtc_read_ms,
+ .mask = CLOCKSOURCE_MASK(32),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_SUSPEND_NONSTOP,
+};
+
+static inline unsigned int tegra_base_for_cpu(int cpu, bool tegra20)
+{
+ if (tegra20) {
+ switch (cpu) {
+ case 0:
+ return TIMER1_BASE;
+ case 1:
+ return TIMER2_BASE;
+ case 2:
+ return TIMER3_BASE;
+ default:
+ return TIMER4_BASE;
+ }
+ }
+
+ return TIMER10_BASE + cpu * 8;
+}
+
+static inline unsigned int tegra_irq_idx_for_cpu(int cpu, bool tegra20)
+{
+ if (tegra20)
+ return TIMER1_IRQ_IDX + cpu;
+
+ return TIMER10_IRQ_IDX + cpu;
+}
+
+static inline unsigned long tegra_rate_for_timer(struct timer_of *to,
+ bool tegra20)
+{
+ /*
+ * TIMER1-9 are fixed to 1MHz, TIMER10-13 are running off the
+ * parent clock.
+ */
+ if (tegra20)
+ return TIMER_1MHz;
+
+ return timer_of_rate(to);
+}
+
+static int __init tegra_init_timer(struct device_node *np, bool tegra20,
+ int rating)
+{
+ struct timer_of *to;
+ int cpu, ret;
+
+ to = this_cpu_ptr(&tegra_to);
+ ret = timer_of_init(np, to);
+ if (ret)
+ goto out;
+
+ timer_reg_base = timer_of_base(to);
+
+ /*
+ * Configure microsecond timers to have 1MHz clock
+ * Config register is 0xqqww, where qq is "dividend", ww is "divisor"
+ * Uses n+1 scheme
+ */
+ switch (timer_of_rate(to)) {
+ case 12000000:
+ usec_config = 0x000b; /* (11+1)/(0+1) */
+ break;
+ case 12800000:
+ usec_config = 0x043f; /* (63+1)/(4+1) */
+ break;
+ case 13000000:
+ usec_config = 0x000c; /* (12+1)/(0+1) */
+ break;
+ case 16800000:
+ usec_config = 0x0453; /* (83+1)/(4+1) */
+ break;
+ case 19200000:
+ usec_config = 0x045f; /* (95+1)/(4+1) */
+ break;
+ case 26000000:
+ usec_config = 0x0019; /* (25+1)/(0+1) */
+ break;
+ case 38400000:
+ usec_config = 0x04bf; /* (191+1)/(4+1) */
+ break;
+ case 48000000:
+ usec_config = 0x002f; /* (47+1)/(0+1) */
+ break;
+ default:
+ ret = -EINVAL;
+ goto out;
+ }
+
+ writel_relaxed(usec_config, timer_reg_base + TIMERUS_USEC_CFG);
+
+ for_each_possible_cpu(cpu) {
+ struct timer_of *cpu_to = per_cpu_ptr(&tegra_to, cpu);
+ unsigned long flags = IRQF_TIMER | IRQF_NOBALANCING;
+ unsigned long rate = tegra_rate_for_timer(to, tegra20);
+ unsigned int base = tegra_base_for_cpu(cpu, tegra20);
+ unsigned int idx = tegra_irq_idx_for_cpu(cpu, tegra20);
+ unsigned int irq = irq_of_parse_and_map(np, idx);
+
+ if (!irq) {
+ pr_err("failed to map irq for cpu%d\n", cpu);
+ ret = -EINVAL;
+ goto out_irq;
+ }
+
+ cpu_to->clkevt.irq = irq;
+ cpu_to->clkevt.rating = rating;
+ cpu_to->clkevt.cpumask = cpumask_of(cpu);
+ cpu_to->of_base.base = timer_reg_base + base;
+ cpu_to->of_clk.period = rate / HZ;
+ cpu_to->of_clk.rate = rate;
+
+ irq_set_status_flags(cpu_to->clkevt.irq, IRQ_NOAUTOEN);
+
+ ret = request_irq(cpu_to->clkevt.irq, tegra_timer_isr, flags,
+ cpu_to->clkevt.name, &cpu_to->clkevt);
+ if (ret) {
+ pr_err("failed to set up irq for cpu%d: %d\n",
+ cpu, ret);
+ irq_dispose_mapping(cpu_to->clkevt.irq);
+ cpu_to->clkevt.irq = 0;
+ goto out_irq;
+ }
+ }
+
+ sched_clock_register(tegra_read_sched_clock, 32, TIMER_1MHz);
+
+ ret = clocksource_mmio_init(timer_reg_base + TIMERUS_CNTR_1US,
+ "timer_us", TIMER_1MHz, 300, 32,
+ clocksource_mmio_readl_up);
+ if (ret)
+ pr_err("failed to register clocksource: %d\n", ret);
+
+#ifdef CONFIG_ARM
+ register_current_timer_delay(&tegra_delay_timer);
+#endif
+
+ ret = cpuhp_setup_state(CPUHP_AP_TEGRA_TIMER_STARTING,
+ "AP_TEGRA_TIMER_STARTING", tegra_timer_setup,
+ tegra_timer_stop);
+ if (ret)
+ pr_err("failed to set up cpu hp state: %d\n", ret);
+
+ return ret;
+
+out_irq:
+ for_each_possible_cpu(cpu) {
+ struct timer_of *cpu_to;
+
+ cpu_to = per_cpu_ptr(&tegra_to, cpu);
+ if (cpu_to->clkevt.irq) {
+ free_irq(cpu_to->clkevt.irq, &cpu_to->clkevt);
+ irq_dispose_mapping(cpu_to->clkevt.irq);
+ }
+ }
+
+ to->of_base.base = timer_reg_base;
+out:
+ timer_of_cleanup(to);
+
+ return ret;
+}
+
+static int __init tegra210_init_timer(struct device_node *np)
+{
+ /*
+ * Arch-timer can't survive across power cycle of CPU core and
+ * after CPUPORESET signal due to a system design shortcoming,
+ * hence tegra-timer is more preferable on Tegra210.
+ */
+ return tegra_init_timer(np, false, 460);
+}
+TIMER_OF_DECLARE(tegra210_timer, "nvidia,tegra210-timer", tegra210_init_timer);
+
+static int __init tegra20_init_timer(struct device_node *np)
+{
+ int rating;
+
+ /*
+ * Tegra20 and Tegra30 have Cortex A9 CPU that has a TWD timer,
+ * that timer runs off the CPU clock and hence is subjected to
+ * a jitter caused by DVFS clock rate changes. Tegra-timer is
+ * more preferable for older Tegra's, while later SoC generations
+ * have arch-timer as a main per-CPU timer and it is not affected
+ * by DVFS changes.
+ */
+ if (of_machine_is_compatible("nvidia,tegra20") ||
+ of_machine_is_compatible("nvidia,tegra30"))
+ rating = 460;
+ else
+ rating = 330;
+
+ return tegra_init_timer(np, true, rating);
+}
+TIMER_OF_DECLARE(tegra20_timer, "nvidia,tegra20-timer", tegra20_init_timer);
+
+static int __init tegra20_init_rtc(struct device_node *np)
+{
+ int ret;
+
+ ret = timer_of_init(np, &suspend_rtc_to);
+ if (ret)
+ return ret;
+
+ return clocksource_register_hz(&suspend_rtc_clocksource, 1000);
+}
+TIMER_OF_DECLARE(tegra20_rtc, "nvidia,tegra20-rtc", tegra20_init_rtc);
diff --git a/drivers/clocksource/timer-tegra20.c b/drivers/clocksource/timer-tegra20.c
deleted file mode 100644
index 1e7ece279730..000000000000
--- a/drivers/clocksource/timer-tegra20.c
+++ /dev/null
@@ -1,379 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2010 Google, Inc.
- *
- * Author:
- * Colin Cross <ccross@google.com>
- */
-
-#include <linux/clk.h>
-#include <linux/clockchips.h>
-#include <linux/cpu.h>
-#include <linux/cpumask.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/interrupt.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/percpu.h>
-#include <linux/sched_clock.h>
-#include <linux/time.h>
-
-#include "timer-of.h"
-
-#ifdef CONFIG_ARM
-#include <asm/mach/time.h>
-#endif
-
-#define RTC_SECONDS 0x08
-#define RTC_SHADOW_SECONDS 0x0c
-#define RTC_MILLISECONDS 0x10
-
-#define TIMERUS_CNTR_1US 0x10
-#define TIMERUS_USEC_CFG 0x14
-#define TIMERUS_CNTR_FREEZE 0x4c
-
-#define TIMER_PTV 0x0
-#define TIMER_PTV_EN BIT(31)
-#define TIMER_PTV_PER BIT(30)
-#define TIMER_PCR 0x4
-#define TIMER_PCR_INTR_CLR BIT(30)
-
-#ifdef CONFIG_ARM
-#define TIMER_CPU0 0x50 /* TIMER3 */
-#else
-#define TIMER_CPU0 0x90 /* TIMER10 */
-#define TIMER10_IRQ_IDX 10
-#define IRQ_IDX_FOR_CPU(cpu) (TIMER10_IRQ_IDX + cpu)
-#endif
-#define TIMER_BASE_FOR_CPU(cpu) (TIMER_CPU0 + (cpu) * 8)
-
-static u32 usec_config;
-static void __iomem *timer_reg_base;
-#ifdef CONFIG_ARM
-static struct delay_timer tegra_delay_timer;
-#endif
-
-static int tegra_timer_set_next_event(unsigned long cycles,
- struct clock_event_device *evt)
-{
- void __iomem *reg_base = timer_of_base(to_timer_of(evt));
-
- writel(TIMER_PTV_EN |
- ((cycles > 1) ? (cycles - 1) : 0), /* n+1 scheme */
- reg_base + TIMER_PTV);
-
- return 0;
-}
-
-static int tegra_timer_shutdown(struct clock_event_device *evt)
-{
- void __iomem *reg_base = timer_of_base(to_timer_of(evt));
-
- writel(0, reg_base + TIMER_PTV);
-
- return 0;
-}
-
-static int tegra_timer_set_periodic(struct clock_event_device *evt)
-{
- void __iomem *reg_base = timer_of_base(to_timer_of(evt));
-
- writel(TIMER_PTV_EN | TIMER_PTV_PER |
- ((timer_of_rate(to_timer_of(evt)) / HZ) - 1),
- reg_base + TIMER_PTV);
-
- return 0;
-}
-
-static irqreturn_t tegra_timer_isr(int irq, void *dev_id)
-{
- struct clock_event_device *evt = (struct clock_event_device *)dev_id;
- void __iomem *reg_base = timer_of_base(to_timer_of(evt));
-
- writel(TIMER_PCR_INTR_CLR, reg_base + TIMER_PCR);
- evt->event_handler(evt);
-
- return IRQ_HANDLED;
-}
-
-static void tegra_timer_suspend(struct clock_event_device *evt)
-{
- void __iomem *reg_base = timer_of_base(to_timer_of(evt));
-
- writel(TIMER_PCR_INTR_CLR, reg_base + TIMER_PCR);
-}
-
-static void tegra_timer_resume(struct clock_event_device *evt)
-{
- writel(usec_config, timer_reg_base + TIMERUS_USEC_CFG);
-}
-
-#ifdef CONFIG_ARM64
-static DEFINE_PER_CPU(struct timer_of, tegra_to) = {
- .flags = TIMER_OF_CLOCK | TIMER_OF_BASE,
-
- .clkevt = {
- .name = "tegra_timer",
- .rating = 460,
- .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
- .set_next_event = tegra_timer_set_next_event,
- .set_state_shutdown = tegra_timer_shutdown,
- .set_state_periodic = tegra_timer_set_periodic,
- .set_state_oneshot = tegra_timer_shutdown,
- .tick_resume = tegra_timer_shutdown,
- .suspend = tegra_timer_suspend,
- .resume = tegra_timer_resume,
- },
-};
-
-static int tegra_timer_setup(unsigned int cpu)
-{
- struct timer_of *to = per_cpu_ptr(&tegra_to, cpu);
-
- irq_force_affinity(to->clkevt.irq, cpumask_of(cpu));
- enable_irq(to->clkevt.irq);
-
- clockevents_config_and_register(&to->clkevt, timer_of_rate(to),
- 1, /* min */
- 0x1fffffff); /* 29 bits */
-
- return 0;
-}
-
-static int tegra_timer_stop(unsigned int cpu)
-{
- struct timer_of *to = per_cpu_ptr(&tegra_to, cpu);
-
- to->clkevt.set_state_shutdown(&to->clkevt);
- disable_irq_nosync(to->clkevt.irq);
-
- return 0;
-}
-#else /* CONFIG_ARM */
-static struct timer_of tegra_to = {
- .flags = TIMER_OF_CLOCK | TIMER_OF_BASE | TIMER_OF_IRQ,
-
- .clkevt = {
- .name = "tegra_timer",
- .rating = 300,
- .features = CLOCK_EVT_FEAT_ONESHOT |
- CLOCK_EVT_FEAT_PERIODIC |
- CLOCK_EVT_FEAT_DYNIRQ,
- .set_next_event = tegra_timer_set_next_event,
- .set_state_shutdown = tegra_timer_shutdown,
- .set_state_periodic = tegra_timer_set_periodic,
- .set_state_oneshot = tegra_timer_shutdown,
- .tick_resume = tegra_timer_shutdown,
- .suspend = tegra_timer_suspend,
- .resume = tegra_timer_resume,
- .cpumask = cpu_possible_mask,
- },
-
- .of_irq = {
- .index = 2,
- .flags = IRQF_TIMER | IRQF_TRIGGER_HIGH,
- .handler = tegra_timer_isr,
- },
-};
-
-static u64 notrace tegra_read_sched_clock(void)
-{
- return readl(timer_reg_base + TIMERUS_CNTR_1US);
-}
-
-static unsigned long tegra_delay_timer_read_counter_long(void)
-{
- return readl(timer_reg_base + TIMERUS_CNTR_1US);
-}
-
-static struct timer_of suspend_rtc_to = {
- .flags = TIMER_OF_BASE | TIMER_OF_CLOCK,
-};
-
-/*
- * tegra_rtc_read - Reads the Tegra RTC registers
- * Care must be taken that this funciton is not called while the
- * tegra_rtc driver could be executing to avoid race conditions
- * on the RTC shadow register
- */
-static u64 tegra_rtc_read_ms(struct clocksource *cs)
-{
- u32 ms = readl(timer_of_base(&suspend_rtc_to) + RTC_MILLISECONDS);
- u32 s = readl(timer_of_base(&suspend_rtc_to) + RTC_SHADOW_SECONDS);
- return (u64)s * MSEC_PER_SEC + ms;
-}
-
-static struct clocksource suspend_rtc_clocksource = {
- .name = "tegra_suspend_timer",
- .rating = 200,
- .read = tegra_rtc_read_ms,
- .mask = CLOCKSOURCE_MASK(32),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_SUSPEND_NONSTOP,
-};
-#endif
-
-static int tegra_timer_common_init(struct device_node *np, struct timer_of *to)
-{
- int ret = 0;
-
- ret = timer_of_init(np, to);
- if (ret < 0)
- goto out;
-
- timer_reg_base = timer_of_base(to);
-
- /*
- * Configure microsecond timers to have 1MHz clock
- * Config register is 0xqqww, where qq is "dividend", ww is "divisor"
- * Uses n+1 scheme
- */
- switch (timer_of_rate(to)) {
- case 12000000:
- usec_config = 0x000b; /* (11+1)/(0+1) */
- break;
- case 12800000:
- usec_config = 0x043f; /* (63+1)/(4+1) */
- break;
- case 13000000:
- usec_config = 0x000c; /* (12+1)/(0+1) */
- break;
- case 16800000:
- usec_config = 0x0453; /* (83+1)/(4+1) */
- break;
- case 19200000:
- usec_config = 0x045f; /* (95+1)/(4+1) */
- break;
- case 26000000:
- usec_config = 0x0019; /* (25+1)/(0+1) */
- break;
- case 38400000:
- usec_config = 0x04bf; /* (191+1)/(4+1) */
- break;
- case 48000000:
- usec_config = 0x002f; /* (47+1)/(0+1) */
- break;
- default:
- ret = -EINVAL;
- goto out;
- }
-
- writel(usec_config, timer_of_base(to) + TIMERUS_USEC_CFG);
-
-out:
- return ret;
-}
-
-#ifdef CONFIG_ARM64
-static int __init tegra_init_timer(struct device_node *np)
-{
- int cpu, ret = 0;
- struct timer_of *to;
-
- to = this_cpu_ptr(&tegra_to);
- ret = tegra_timer_common_init(np, to);
- if (ret < 0)
- goto out;
-
- for_each_possible_cpu(cpu) {
- struct timer_of *cpu_to;
-
- cpu_to = per_cpu_ptr(&tegra_to, cpu);
- cpu_to->of_base.base = timer_reg_base + TIMER_BASE_FOR_CPU(cpu);
- cpu_to->of_clk.rate = timer_of_rate(to);
- cpu_to->clkevt.cpumask = cpumask_of(cpu);
- cpu_to->clkevt.irq =
- irq_of_parse_and_map(np, IRQ_IDX_FOR_CPU(cpu));
- if (!cpu_to->clkevt.irq) {
- pr_err("%s: can't map IRQ for CPU%d\n",
- __func__, cpu);
- ret = -EINVAL;
- goto out;
- }
-
- irq_set_status_flags(cpu_to->clkevt.irq, IRQ_NOAUTOEN);
- ret = request_irq(cpu_to->clkevt.irq, tegra_timer_isr,
- IRQF_TIMER | IRQF_NOBALANCING,
- cpu_to->clkevt.name, &cpu_to->clkevt);
- if (ret) {
- pr_err("%s: cannot setup irq %d for CPU%d\n",
- __func__, cpu_to->clkevt.irq, cpu);
- ret = -EINVAL;
- goto out_irq;
- }
- }
-
- cpuhp_setup_state(CPUHP_AP_TEGRA_TIMER_STARTING,
- "AP_TEGRA_TIMER_STARTING", tegra_timer_setup,
- tegra_timer_stop);
-
- return ret;
-out_irq:
- for_each_possible_cpu(cpu) {
- struct timer_of *cpu_to;
-
- cpu_to = per_cpu_ptr(&tegra_to, cpu);
- if (cpu_to->clkevt.irq) {
- free_irq(cpu_to->clkevt.irq, &cpu_to->clkevt);
- irq_dispose_mapping(cpu_to->clkevt.irq);
- }
- }
-out:
- timer_of_cleanup(to);
- return ret;
-}
-#else /* CONFIG_ARM */
-static int __init tegra_init_timer(struct device_node *np)
-{
- int ret = 0;
-
- ret = tegra_timer_common_init(np, &tegra_to);
- if (ret < 0)
- goto out;
-
- tegra_to.of_base.base = timer_reg_base + TIMER_BASE_FOR_CPU(0);
- tegra_to.of_clk.rate = 1000000; /* microsecond timer */
-
- sched_clock_register(tegra_read_sched_clock, 32,
- timer_of_rate(&tegra_to));
- ret = clocksource_mmio_init(timer_reg_base + TIMERUS_CNTR_1US,
- "timer_us", timer_of_rate(&tegra_to),
- 300, 32, clocksource_mmio_readl_up);
- if (ret) {
- pr_err("Failed to register clocksource\n");
- goto out;
- }
-
- tegra_delay_timer.read_current_timer =
- tegra_delay_timer_read_counter_long;
- tegra_delay_timer.freq = timer_of_rate(&tegra_to);
- register_current_timer_delay(&tegra_delay_timer);
-
- clockevents_config_and_register(&tegra_to.clkevt,
- timer_of_rate(&tegra_to),
- 0x1,
- 0x1fffffff);
-
- return ret;
-out:
- timer_of_cleanup(&tegra_to);
-
- return ret;
-}
-
-static int __init tegra20_init_rtc(struct device_node *np)
-{
- int ret;
-
- ret = timer_of_init(np, &suspend_rtc_to);
- if (ret)
- return ret;
-
- clocksource_register_hz(&suspend_rtc_clocksource, 1000);
-
- return 0;
-}
-TIMER_OF_DECLARE(tegra20_rtc, "nvidia,tegra20-rtc", tegra20_init_rtc);
-#endif
-TIMER_OF_DECLARE(tegra210_timer, "nvidia,tegra210-timer", tegra_init_timer);
-TIMER_OF_DECLARE(tegra20_timer, "nvidia,tegra20-timer", tegra_init_timer);
diff --git a/drivers/clocksource/timer-zevio.c b/drivers/clocksource/timer-zevio.c
index 6127e8062a71..c0041561f1be 100644
--- a/drivers/clocksource/timer-zevio.c
+++ b/drivers/clocksource/timer-zevio.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/clocksource/zevio-timer.c
*
* Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au>
- *
- * 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.
- *
*/
#include <linux/io.h>
diff --git a/drivers/counter/104-quad-8.c b/drivers/counter/104-quad-8.c
index 4fa2931dcb7b..00b113f4b958 100644
--- a/drivers/counter/104-quad-8.c
+++ b/drivers/counter/104-quad-8.c
@@ -833,7 +833,7 @@ static int quad8_action_get(struct counter_device *counter,
return 0;
}
-const struct counter_ops quad8_ops = {
+static const struct counter_ops quad8_ops = {
.signal_read = quad8_signal_read,
.count_read = quad8_count_read,
.count_write = quad8_count_write,
diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig
index 138ecd8a8fbd..2967d0a9ff91 100644
--- a/drivers/counter/Kconfig
+++ b/drivers/counter/Kconfig
@@ -51,6 +51,7 @@ config STM32_LPTIMER_CNT
config FTM_QUADDEC
tristate "Flex Timer Module Quadrature decoder driver"
+ depends on HAS_IOMEM && OF
help
Select this option to enable the Flex Timer Quadrature decoder
driver.
diff --git a/drivers/counter/ftm-quaddec.c b/drivers/counter/ftm-quaddec.c
index c83c8875bf82..68a9b7393457 100644
--- a/drivers/counter/ftm-quaddec.c
+++ b/drivers/counter/ftm-quaddec.c
@@ -352,5 +352,5 @@ static struct platform_driver ftm_quaddec_driver = {
module_platform_driver(ftm_quaddec_driver);
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Kjeld Flarup <kfa@deif.com");
-MODULE_AUTHOR("Patrick Havelange <patrick.havelange@essensium.com");
+MODULE_AUTHOR("Kjeld Flarup <kfa@deif.com>");
+MODULE_AUTHOR("Patrick Havelange <patrick.havelange@essensium.com>");
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index f8129edc145e..56c31a78c692 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -93,6 +93,15 @@ config ARM_IMX6Q_CPUFREQ
If in doubt, say N.
+config ARM_IMX_CPUFREQ_DT
+ tristate "Freescale i.MX8M cpufreq support"
+ depends on ARCH_MXC && CPUFREQ_DT
+ help
+ This adds cpufreq driver support for Freescale i.MX8M series SoCs,
+ based on cpufreq-dt.
+
+ If in doubt, say N.
+
config ARM_KIRKWOOD_CPUFREQ
def_bool MACH_KIRKWOOD
help
@@ -133,6 +142,14 @@ config ARM_QCOM_CPUFREQ_HW
The driver implements the cpufreq interface for this HW engine.
Say Y if you want to support CPUFreq HW.
+config ARM_RASPBERRYPI_CPUFREQ
+ tristate "Raspberry Pi cpufreq support"
+ depends on CLK_RASPBERRYPI || COMPILE_TEST
+ help
+ This adds the CPUFreq driver for Raspberry Pi
+
+ If in doubt, say N.
+
config ARM_S3C_CPUFREQ
bool
help
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 689b26c6f949..5a6c70d26c98 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_ACPI_CPPC_CPUFREQ) += cppc_cpufreq.o
obj-$(CONFIG_ARCH_DAVINCI) += davinci-cpufreq.o
obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o
obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o
+obj-$(CONFIG_ARM_IMX_CPUFREQ_DT) += imx-cpufreq-dt.o
obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o
obj-$(CONFIG_ARM_MEDIATEK_CPUFREQ) += mediatek-cpufreq.o
obj-$(CONFIG_MACH_MVEBU_V7) += mvebu-cpufreq.o
@@ -64,6 +65,7 @@ obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2xx-cpufreq.o
obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o
obj-$(CONFIG_ARM_QCOM_CPUFREQ_HW) += qcom-cpufreq-hw.o
obj-$(CONFIG_ARM_QCOM_CPUFREQ_KRYO) += qcom-cpufreq-kryo.o
+obj-$(CONFIG_ARM_RASPBERRYPI_CPUFREQ) += raspberrypi-cpufreq.o
obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o
obj-$(CONFIG_ARM_S3C2412_CPUFREQ) += s3c2412-cpufreq.o
obj-$(CONFIG_ARM_S3C2416_CPUFREQ) += s3c2416-cpufreq.o
diff --git a/drivers/cpufreq/amd_freq_sensitivity.c b/drivers/cpufreq/amd_freq_sensitivity.c
index 6927a8c0e748..e2df9d112106 100644
--- a/drivers/cpufreq/amd_freq_sensitivity.c
+++ b/drivers/cpufreq/amd_freq_sensitivity.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* amd_freq_sensitivity.c: AMD frequency sensitivity feedback powersave bias
* for the ondemand governor.
@@ -5,10 +6,6 @@
* Copyright (C) 2013 Advanced Micro Devices, Inc.
*
* Author: Jacob Shin <jacob.shin@amd.com>
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/cpufreq/armada-37xx-cpufreq.c b/drivers/cpufreq/armada-37xx-cpufreq.c
index 0df16eb1eb3c..aa0f06dec959 100644
--- a/drivers/cpufreq/armada-37xx-cpufreq.c
+++ b/drivers/cpufreq/armada-37xx-cpufreq.c
@@ -257,7 +257,7 @@ static void __init armada37xx_cpufreq_avs_configure(struct regmap *base,
static void __init armada37xx_cpufreq_avs_setup(struct regmap *base,
struct armada_37xx_dvfs *dvfs)
{
- unsigned int avs_val = 0, freq;
+ unsigned int avs_val = 0;
int load_level = 0;
if (base == NULL)
@@ -275,8 +275,6 @@ static void __init armada37xx_cpufreq_avs_setup(struct regmap *base,
for (load_level = 1; load_level < LOAD_LEVEL_NR; load_level++) {
- freq = dvfs->cpu_freq_max / dvfs->divider[load_level];
-
avs_val = dvfs->avs[load_level];
regmap_update_bits(base, ARMADA_37XX_AVS_VSET(load_level-1),
ARMADA_37XX_AVS_VDD_MASK << ARMADA_37XX_AVS_HIGH_VDD_LIMIT |
diff --git a/drivers/cpufreq/bmips-cpufreq.c b/drivers/cpufreq/bmips-cpufreq.c
index 56a4ebbf00e0..f7c23fa468f0 100644
--- a/drivers/cpufreq/bmips-cpufreq.c
+++ b/drivers/cpufreq/bmips-cpufreq.c
@@ -131,23 +131,18 @@ static int bmips_cpufreq_exit(struct cpufreq_policy *policy)
static int bmips_cpufreq_init(struct cpufreq_policy *policy)
{
struct cpufreq_frequency_table *freq_table;
- int ret;
freq_table = bmips_cpufreq_get_freq_table(policy);
if (IS_ERR(freq_table)) {
- ret = PTR_ERR(freq_table);
- pr_err("%s: couldn't determine frequency table (%d).\n",
- BMIPS_CPUFREQ_NAME, ret);
- return ret;
+ pr_err("%s: couldn't determine frequency table (%ld).\n",
+ BMIPS_CPUFREQ_NAME, PTR_ERR(freq_table));
+ return PTR_ERR(freq_table);
}
- ret = cpufreq_generic_init(policy, freq_table, TRANSITION_LATENCY);
- if (ret)
- bmips_cpufreq_exit(policy);
- else
- pr_info("%s: registered\n", BMIPS_CPUFREQ_NAME);
+ cpufreq_generic_init(policy, freq_table, TRANSITION_LATENCY);
+ pr_info("%s: registered\n", BMIPS_CPUFREQ_NAME);
- return ret;
+ return 0;
}
static struct cpufreq_driver bmips_cpufreq_driver = {
diff --git a/drivers/cpufreq/brcmstb-avs-cpufreq.c b/drivers/cpufreq/brcmstb-avs-cpufreq.c
index e6f9cbe5835f..77b0e5d0fb13 100644
--- a/drivers/cpufreq/brcmstb-avs-cpufreq.c
+++ b/drivers/cpufreq/brcmstb-avs-cpufreq.c
@@ -384,12 +384,12 @@ static int brcm_avs_set_pstate(struct private_data *priv, unsigned int pstate)
return __issue_avs_command(priv, AVS_CMD_SET_PSTATE, true, args);
}
-static unsigned long brcm_avs_get_voltage(void __iomem *base)
+static u32 brcm_avs_get_voltage(void __iomem *base)
{
return readl(base + AVS_MBOX_VOLTAGE1);
}
-static unsigned long brcm_avs_get_frequency(void __iomem *base)
+static u32 brcm_avs_get_frequency(void __iomem *base)
{
return readl(base + AVS_MBOX_FREQUENCY) * 1000; /* in kHz */
}
@@ -446,8 +446,8 @@ static bool brcm_avs_is_firmware_loaded(struct private_data *priv)
rc = brcm_avs_get_pmap(priv, NULL);
magic = readl(priv->base + AVS_MBOX_MAGIC);
- return (magic == AVS_FIRMWARE_MAGIC) && (rc != -ENOTSUPP) &&
- (rc != -EINVAL);
+ return (magic == AVS_FIRMWARE_MAGIC) && ((rc != -ENOTSUPP) ||
+ (rc != -EINVAL));
}
static unsigned int brcm_avs_cpufreq_get(unsigned int cpu)
@@ -653,14 +653,14 @@ static ssize_t show_brcm_avs_voltage(struct cpufreq_policy *policy, char *buf)
{
struct private_data *priv = policy->driver_data;
- return sprintf(buf, "0x%08lx\n", brcm_avs_get_voltage(priv->base));
+ return sprintf(buf, "0x%08x\n", brcm_avs_get_voltage(priv->base));
}
static ssize_t show_brcm_avs_frequency(struct cpufreq_policy *policy, char *buf)
{
struct private_data *priv = policy->driver_data;
- return sprintf(buf, "0x%08lx\n", brcm_avs_get_frequency(priv->base));
+ return sprintf(buf, "0x%08x\n", brcm_avs_get_frequency(priv->base));
}
cpufreq_freq_attr_ro(brcm_avs_pstate);
diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c
index 47729a22c159..03dc4244ab00 100644
--- a/drivers/cpufreq/cpufreq-dt-platdev.c
+++ b/drivers/cpufreq/cpufreq-dt-platdev.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2016 Linaro.
* Viresh Kumar <viresh.kumar@linaro.org>
- *
- * 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.
*/
#include <linux/err.h>
@@ -40,7 +37,6 @@ static const struct of_device_id whitelist[] __initconst = {
{ .compatible = "fsl,imx27", },
{ .compatible = "fsl,imx51", },
{ .compatible = "fsl,imx53", },
- { .compatible = "fsl,imx7d", },
{ .compatible = "marvell,berlin", },
{ .compatible = "marvell,pxa250", },
@@ -108,6 +104,10 @@ static const struct of_device_id blacklist[] __initconst = {
{ .compatible = "calxeda,highbank", },
{ .compatible = "calxeda,ecx-2000", },
+ { .compatible = "fsl,imx7d", },
+ { .compatible = "fsl,imx8mq", },
+ { .compatible = "fsl,imx8mm", },
+
{ .compatible = "marvell,armadaxp", },
{ .compatible = "mediatek,mt2701", },
diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c
index bde28878725b..d2b5f062a07b 100644
--- a/drivers/cpufreq/cpufreq-dt.c
+++ b/drivers/cpufreq/cpufreq-dt.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Freescale Semiconductor, Inc.
*
* Copyright (C) 2014 Linaro.
* Viresh Kumar <viresh.kumar@linaro.org>
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/cpufreq/cpufreq-dt.h b/drivers/cpufreq/cpufreq-dt.h
index d5aeea13433e..a5a45b547d0b 100644
--- a/drivers/cpufreq/cpufreq-dt.h
+++ b/drivers/cpufreq/cpufreq-dt.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2016 Linaro
* Viresh Kumar <viresh.kumar@linaro.org>
- *
- * 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.
*/
#ifndef __CPUFREQ_DT_H__
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 85ff958e01f1..8dda62367816 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/cpufreq/cpufreq.c
*
@@ -9,10 +10,6 @@
* Added handling for CPU hotplug
* Feb 2006 - Jacob Shin <jacob.shin@amd.com>
* Fix handling for CPU hotplug -- affected CPUs
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -26,6 +23,7 @@
#include <linux/kernel_stat.h>
#include <linux/module.h>
#include <linux/mutex.h>
+#include <linux/pm_qos.h>
#include <linux/slab.h>
#include <linux/suspend.h>
#include <linux/syscore_ops.h>
@@ -161,7 +159,7 @@ EXPORT_SYMBOL_GPL(arch_set_freq_scale);
* - set policies transition latency
* - policy->cpus with all possible CPUs
*/
-int cpufreq_generic_init(struct cpufreq_policy *policy,
+void cpufreq_generic_init(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table,
unsigned int transition_latency)
{
@@ -173,8 +171,6 @@ int cpufreq_generic_init(struct cpufreq_policy *policy,
* share the clock and voltage and clock.
*/
cpumask_setall(policy->cpus);
-
- return 0;
}
EXPORT_SYMBOL_GPL(cpufreq_generic_init);
@@ -359,12 +355,10 @@ static void cpufreq_notify_transition(struct cpufreq_policy *policy,
* which is not equal to what the cpufreq core thinks is
* "old frequency".
*/
- if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
- if (policy->cur && (policy->cur != freqs->old)) {
- pr_debug("Warning: CPU frequency is %u, cpufreq assumed %u kHz\n",
- freqs->old, policy->cur);
- freqs->old = policy->cur;
- }
+ if (policy->cur && policy->cur != freqs->old) {
+ pr_debug("Warning: CPU frequency is %u, cpufreq assumed %u kHz\n",
+ freqs->old, policy->cur);
+ freqs->old = policy->cur;
}
srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
@@ -634,7 +628,7 @@ static int cpufreq_parse_policy(char *str_governor,
}
/**
- * cpufreq_parse_governor - parse a governor string only for !setpolicy
+ * cpufreq_parse_governor - parse a governor string only for has_target()
*/
static int cpufreq_parse_governor(char *str_governor,
struct cpufreq_policy *policy)
@@ -719,23 +713,15 @@ static ssize_t show_scaling_cur_freq(struct cpufreq_policy *policy, char *buf)
static ssize_t store_##file_name \
(struct cpufreq_policy *policy, const char *buf, size_t count) \
{ \
- int ret, temp; \
- struct cpufreq_policy new_policy; \
+ unsigned long val; \
+ int ret; \
\
- memcpy(&new_policy, policy, sizeof(*policy)); \
- new_policy.min = policy->user_policy.min; \
- new_policy.max = policy->user_policy.max; \
- \
- ret = sscanf(buf, "%u", &new_policy.object); \
+ ret = sscanf(buf, "%lu", &val); \
if (ret != 1) \
return -EINVAL; \
\
- temp = new_policy.object; \
- ret = cpufreq_set_policy(policy, &new_policy); \
- if (!ret) \
- policy->user_policy.object = temp; \
- \
- return ret ? ret : count; \
+ ret = dev_pm_qos_update_request(policy->object##_freq_req, val);\
+ return ret >= 0 ? count : ret; \
}
store_one(scaling_min_freq, min);
@@ -1001,7 +987,7 @@ static void add_cpu_dev_symlink(struct cpufreq_policy *policy, unsigned int cpu)
{
struct device *dev = get_cpu_device(cpu);
- if (!dev)
+ if (unlikely(!dev))
return;
if (cpumask_test_and_set_cpu(cpu, policy->real_cpus))
@@ -1117,20 +1103,79 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, unsigned int cp
return ret;
}
+void refresh_frequency_limits(struct cpufreq_policy *policy)
+{
+ struct cpufreq_policy new_policy;
+
+ if (!policy_is_inactive(policy)) {
+ new_policy = *policy;
+ pr_debug("updating policy for CPU %u\n", policy->cpu);
+
+ cpufreq_set_policy(policy, &new_policy);
+ }
+}
+EXPORT_SYMBOL(refresh_frequency_limits);
+
static void handle_update(struct work_struct *work)
{
struct cpufreq_policy *policy =
container_of(work, struct cpufreq_policy, update);
- unsigned int cpu = policy->cpu;
- pr_debug("handle_update for cpu %u called\n", cpu);
- cpufreq_update_policy(cpu);
+
+ pr_debug("handle_update for cpu %u called\n", policy->cpu);
+ down_write(&policy->rwsem);
+ refresh_frequency_limits(policy);
+ up_write(&policy->rwsem);
+}
+
+static int cpufreq_notifier_min(struct notifier_block *nb, unsigned long freq,
+ void *data)
+{
+ struct cpufreq_policy *policy = container_of(nb, struct cpufreq_policy, nb_min);
+
+ schedule_work(&policy->update);
+ return 0;
+}
+
+static int cpufreq_notifier_max(struct notifier_block *nb, unsigned long freq,
+ void *data)
+{
+ struct cpufreq_policy *policy = container_of(nb, struct cpufreq_policy, nb_max);
+
+ schedule_work(&policy->update);
+ return 0;
+}
+
+static void cpufreq_policy_put_kobj(struct cpufreq_policy *policy)
+{
+ struct kobject *kobj;
+ struct completion *cmp;
+
+ down_write(&policy->rwsem);
+ cpufreq_stats_free_table(policy);
+ kobj = &policy->kobj;
+ cmp = &policy->kobj_unregister;
+ up_write(&policy->rwsem);
+ kobject_put(kobj);
+
+ /*
+ * We need to make sure that the underlying kobj is
+ * actually not referenced anymore by anybody before we
+ * proceed with unloading.
+ */
+ pr_debug("waiting for dropping of refcount\n");
+ wait_for_completion(cmp);
+ pr_debug("wait complete\n");
}
static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
{
struct cpufreq_policy *policy;
+ struct device *dev = get_cpu_device(cpu);
int ret;
+ if (!dev)
+ return NULL;
+
policy = kzalloc(sizeof(*policy), GFP_KERNEL);
if (!policy)
return NULL;
@@ -1147,7 +1192,7 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq,
cpufreq_global_kobject, "policy%u", cpu);
if (ret) {
- pr_err("%s: failed to init policy->kobj: %d\n", __func__, ret);
+ dev_err(dev, "%s: failed to init policy->kobj: %d\n", __func__, ret);
/*
* The entire policy object will be freed below, but the extra
* memory allocated for the kobject name needs to be freed by
@@ -1157,6 +1202,25 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
goto err_free_real_cpus;
}
+ policy->nb_min.notifier_call = cpufreq_notifier_min;
+ policy->nb_max.notifier_call = cpufreq_notifier_max;
+
+ ret = dev_pm_qos_add_notifier(dev, &policy->nb_min,
+ DEV_PM_QOS_MIN_FREQUENCY);
+ if (ret) {
+ dev_err(dev, "Failed to register MIN QoS notifier: %d (%*pbl)\n",
+ ret, cpumask_pr_args(policy->cpus));
+ goto err_kobj_remove;
+ }
+
+ ret = dev_pm_qos_add_notifier(dev, &policy->nb_max,
+ DEV_PM_QOS_MAX_FREQUENCY);
+ if (ret) {
+ dev_err(dev, "Failed to register MAX QoS notifier: %d (%*pbl)\n",
+ ret, cpumask_pr_args(policy->cpus));
+ goto err_min_qos_notifier;
+ }
+
INIT_LIST_HEAD(&policy->policy_list);
init_rwsem(&policy->rwsem);
spin_lock_init(&policy->transition_lock);
@@ -1167,6 +1231,11 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
policy->cpu = cpu;
return policy;
+err_min_qos_notifier:
+ dev_pm_qos_remove_notifier(dev, &policy->nb_min,
+ DEV_PM_QOS_MIN_FREQUENCY);
+err_kobj_remove:
+ cpufreq_policy_put_kobj(policy);
err_free_real_cpus:
free_cpumask_var(policy->real_cpus);
err_free_rcpumask:
@@ -1179,30 +1248,9 @@ err_free_policy:
return NULL;
}
-static void cpufreq_policy_put_kobj(struct cpufreq_policy *policy)
-{
- struct kobject *kobj;
- struct completion *cmp;
-
- down_write(&policy->rwsem);
- cpufreq_stats_free_table(policy);
- kobj = &policy->kobj;
- cmp = &policy->kobj_unregister;
- up_write(&policy->rwsem);
- kobject_put(kobj);
-
- /*
- * We need to make sure that the underlying kobj is
- * actually not referenced anymore by anybody before we
- * proceed with unloading.
- */
- pr_debug("waiting for dropping of refcount\n");
- wait_for_completion(cmp);
- pr_debug("wait complete\n");
-}
-
static void cpufreq_policy_free(struct cpufreq_policy *policy)
{
+ struct device *dev = get_cpu_device(policy->cpu);
unsigned long flags;
int cpu;
@@ -1214,6 +1262,14 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy)
per_cpu(cpufreq_cpu_data, cpu) = NULL;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ dev_pm_qos_remove_notifier(dev, &policy->nb_max,
+ DEV_PM_QOS_MAX_FREQUENCY);
+ dev_pm_qos_remove_notifier(dev, &policy->nb_min,
+ DEV_PM_QOS_MIN_FREQUENCY);
+ dev_pm_qos_remove_request(policy->max_freq_req);
+ dev_pm_qos_remove_request(policy->min_freq_req);
+ kfree(policy->min_freq_req);
+
cpufreq_policy_put_kobj(policy);
free_cpumask_var(policy->real_cpus);
free_cpumask_var(policy->related_cpus);
@@ -1291,19 +1347,53 @@ static int cpufreq_online(unsigned int cpu)
cpumask_and(policy->cpus, policy->cpus, cpu_online_mask);
if (new_policy) {
- policy->user_policy.min = policy->min;
- policy->user_policy.max = policy->max;
+ struct device *dev = get_cpu_device(cpu);
for_each_cpu(j, policy->related_cpus) {
per_cpu(cpufreq_cpu_data, j) = policy;
add_cpu_dev_symlink(policy, j);
}
- } else {
- policy->min = policy->user_policy.min;
- policy->max = policy->user_policy.max;
+
+ policy->min_freq_req = kzalloc(2 * sizeof(*policy->min_freq_req),
+ GFP_KERNEL);
+ if (!policy->min_freq_req)
+ goto out_destroy_policy;
+
+ ret = dev_pm_qos_add_request(dev, policy->min_freq_req,
+ DEV_PM_QOS_MIN_FREQUENCY,
+ policy->min);
+ if (ret < 0) {
+ /*
+ * So we don't call dev_pm_qos_remove_request() for an
+ * uninitialized request.
+ */
+ kfree(policy->min_freq_req);
+ policy->min_freq_req = NULL;
+
+ dev_err(dev, "Failed to add min-freq constraint (%d)\n",
+ ret);
+ goto out_destroy_policy;
+ }
+
+ /*
+ * This must be initialized right here to avoid calling
+ * dev_pm_qos_remove_request() on uninitialized request in case
+ * of errors.
+ */
+ policy->max_freq_req = policy->min_freq_req + 1;
+
+ ret = dev_pm_qos_add_request(dev, policy->max_freq_req,
+ DEV_PM_QOS_MAX_FREQUENCY,
+ policy->max);
+ if (ret < 0) {
+ policy->max_freq_req = NULL;
+ dev_err(dev, "Failed to add max-freq constraint (%d)\n",
+ ret);
+ goto out_destroy_policy;
+ }
}
- if (cpufreq_driver->get && !cpufreq_driver->setpolicy) {
+ if (cpufreq_driver->get && has_target()) {
policy->cur = cpufreq_driver->get(policy->cpu);
if (!policy->cur) {
pr_err("%s: ->get() failed\n", __func__);
@@ -1378,8 +1468,7 @@ static int cpufreq_online(unsigned int cpu)
if (cpufreq_driver->ready)
cpufreq_driver->ready(policy);
- if (IS_ENABLED(CONFIG_CPU_THERMAL) &&
- cpufreq_driver->flags & CPUFREQ_IS_COOLING_DEV)
+ if (cpufreq_thermal_control_enabled(cpufreq_driver))
policy->cdev = of_cpufreq_cooling_register(policy);
pr_debug("initialization complete\n");
@@ -1469,8 +1558,7 @@ static int cpufreq_offline(unsigned int cpu)
goto unlock;
}
- if (IS_ENABLED(CONFIG_CPU_THERMAL) &&
- cpufreq_driver->flags & CPUFREQ_IS_COOLING_DEV) {
+ if (cpufreq_thermal_control_enabled(cpufreq_driver)) {
cpufreq_cooling_unregister(policy->cdev);
policy->cdev = NULL;
}
@@ -1549,6 +1637,30 @@ static void cpufreq_out_of_sync(struct cpufreq_policy *policy,
cpufreq_freq_transition_end(policy, &freqs, 0);
}
+static unsigned int cpufreq_verify_current_freq(struct cpufreq_policy *policy, bool update)
+{
+ unsigned int new_freq;
+
+ new_freq = cpufreq_driver->get(policy->cpu);
+ if (!new_freq)
+ return 0;
+
+ /*
+ * If fast frequency switching is used with the given policy, the check
+ * against policy->cur is pointless, so skip it in that case.
+ */
+ if (policy->fast_switch_enabled || !has_target())
+ return new_freq;
+
+ if (policy->cur != new_freq) {
+ cpufreq_out_of_sync(policy, new_freq);
+ if (update)
+ schedule_work(&policy->update);
+ }
+
+ return new_freq;
+}
+
/**
* cpufreq_quick_get - get the CPU frequency (in kHz) from policy->cur
* @cpu: CPU number
@@ -1604,31 +1716,10 @@ EXPORT_SYMBOL(cpufreq_quick_get_max);
static unsigned int __cpufreq_get(struct cpufreq_policy *policy)
{
- unsigned int ret_freq = 0;
-
if (unlikely(policy_is_inactive(policy)))
- return ret_freq;
-
- ret_freq = cpufreq_driver->get(policy->cpu);
-
- /*
- * If fast frequency switching is used with the given policy, the check
- * against policy->cur is pointless, so skip it in that case too.
- */
- if (policy->fast_switch_enabled)
- return ret_freq;
-
- if (ret_freq && policy->cur &&
- !(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
- /* verify no discrepancy between actual and
- saved value exists */
- if (unlikely(ret_freq != policy->cur)) {
- cpufreq_out_of_sync(policy, ret_freq);
- schedule_work(&policy->update);
- }
- }
+ return 0;
- return ret_freq;
+ return cpufreq_verify_current_freq(policy, true);
}
/**
@@ -1655,24 +1746,6 @@ unsigned int cpufreq_get(unsigned int cpu)
}
EXPORT_SYMBOL(cpufreq_get);
-static unsigned int cpufreq_update_current_freq(struct cpufreq_policy *policy)
-{
- unsigned int new_freq;
-
- new_freq = cpufreq_driver->get(policy->cpu);
- if (!new_freq)
- return 0;
-
- if (!policy->cur) {
- pr_debug("cpufreq: Driver did not initialize current freq\n");
- policy->cur = new_freq;
- } else if (policy->cur != new_freq && has_target()) {
- cpufreq_out_of_sync(policy, new_freq);
- }
-
- return new_freq;
-}
-
static struct subsys_interface cpufreq_interface = {
.name = "cpufreq",
.subsys = &cpu_subsys,
@@ -2153,8 +2226,8 @@ static int cpufreq_start_governor(struct cpufreq_policy *policy)
pr_debug("%s: for CPU %u\n", __func__, policy->cpu);
- if (cpufreq_driver->get && !cpufreq_driver->setpolicy)
- cpufreq_update_current_freq(policy);
+ if (cpufreq_driver->get)
+ cpufreq_verify_current_freq(policy, false);
if (policy->governor->start) {
ret = policy->governor->start(policy);
@@ -2290,6 +2363,7 @@ int cpufreq_set_policy(struct cpufreq_policy *policy,
struct cpufreq_policy *new_policy)
{
struct cpufreq_governor *old_gov;
+ struct device *cpu_dev = get_cpu_device(policy->cpu);
int ret;
pr_debug("setting new policy for CPU %u: %u - %u kHz\n",
@@ -2298,17 +2372,21 @@ int cpufreq_set_policy(struct cpufreq_policy *policy,
memcpy(&new_policy->cpuinfo, &policy->cpuinfo, sizeof(policy->cpuinfo));
/*
- * This check works well when we store new min/max freq attributes,
- * because new_policy is a copy of policy with one field updated.
- */
- if (new_policy->min > new_policy->max)
- return -EINVAL;
+ * PM QoS framework collects all the requests from users and provide us
+ * the final aggregated value here.
+ */
+ new_policy->min = dev_pm_qos_read_value(cpu_dev, DEV_PM_QOS_MIN_FREQUENCY);
+ new_policy->max = dev_pm_qos_read_value(cpu_dev, DEV_PM_QOS_MAX_FREQUENCY);
/* verify the cpu speed can be set within this limit */
ret = cpufreq_driver->verify(new_policy);
if (ret)
return ret;
+ /*
+ * The notifier-chain shall be removed once all the users of
+ * CPUFREQ_ADJUST are moved to use the QoS framework.
+ */
/* adjust if necessary - all reasons */
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
CPUFREQ_ADJUST, new_policy);
@@ -2387,15 +2465,13 @@ int cpufreq_set_policy(struct cpufreq_policy *policy,
* @cpu: CPU to re-evaluate the policy for.
*
* Update the current frequency for the cpufreq policy of @cpu and use
- * cpufreq_set_policy() to re-apply the min and max limits saved in the
- * user_policy sub-structure of that policy, which triggers the evaluation
- * of policy notifiers and the cpufreq driver's ->verify() callback for the
- * policy in question, among other things.
+ * cpufreq_set_policy() to re-apply the min and max limits, which triggers the
+ * evaluation of policy notifiers and the cpufreq driver's ->verify() callback
+ * for the policy in question, among other things.
*/
void cpufreq_update_policy(unsigned int cpu)
{
struct cpufreq_policy *policy = cpufreq_cpu_acquire(cpu);
- struct cpufreq_policy new_policy;
if (!policy)
return;
@@ -2404,16 +2480,11 @@ void cpufreq_update_policy(unsigned int cpu)
* BIOS might change freq behind our back
* -> ask driver for current freq and notify governors about a change
*/
- if (cpufreq_driver->get && !cpufreq_driver->setpolicy &&
- (cpufreq_suspended || WARN_ON(!cpufreq_update_current_freq(policy))))
+ if (cpufreq_driver->get && has_target() &&
+ (cpufreq_suspended || WARN_ON(!cpufreq_verify_current_freq(policy, false))))
goto unlock;
- pr_debug("updating policy for CPU %u\n", cpu);
- memcpy(&new_policy, policy, sizeof(*policy));
- new_policy.min = policy->user_policy.min;
- new_policy.max = policy->user_policy.max;
-
- cpufreq_set_policy(policy, &new_policy);
+ refresh_frequency_limits(policy);
unlock:
cpufreq_cpu_release(policy);
@@ -2456,10 +2527,9 @@ static int cpufreq_boost_set_sw(int state)
break;
}
- down_write(&policy->rwsem);
- policy->user_policy.max = policy->max;
- cpufreq_governor_limits(policy);
- up_write(&policy->rwsem);
+ ret = dev_pm_qos_update_request(policy->max_freq_req, policy->max);
+ if (ret)
+ break;
}
return ret;
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index 4268f87e99fc..b66e81c06a57 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/cpufreq/cpufreq_conservative.c
*
@@ -5,10 +6,6 @@
* (C) 2003 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>.
* Jun Nakajima <jun.nakajima@intel.com>
* (C) 2009 Alexander Clouter <alex@digriz.org.uk>
- *
- * 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.
*/
#include <linux/slab.h>
diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c
index 9d1d9bf02710..4bb054d0cb43 100644
--- a/drivers/cpufreq/cpufreq_governor.c
+++ b/drivers/cpufreq/cpufreq_governor.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/cpufreq/cpufreq_governor.c
*
@@ -8,10 +9,6 @@
* (C) 2003 Jun Nakajima <jun.nakajima@intel.com>
* (C) 2009 Alexander Clouter <alex@digriz.org.uk>
* (c) 2012 Viresh Kumar <viresh.kumar@linaro.org>
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h
index 8463f5def0f5..c56773c25757 100644
--- a/drivers/cpufreq/cpufreq_governor.h
+++ b/drivers/cpufreq/cpufreq_governor.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* drivers/cpufreq/cpufreq_governor.h
*
@@ -8,10 +9,6 @@
* (C) 2003 Jun Nakajima <jun.nakajima@intel.com>
* (C) 2009 Alexander Clouter <alex@digriz.org.uk>
* (c) 2012 Viresh Kumar <viresh.kumar@linaro.org>
- *
- * 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.
*/
#ifndef _CPUFREQ_GOVERNOR_H
diff --git a/drivers/cpufreq/cpufreq_governor_attr_set.c b/drivers/cpufreq/cpufreq_governor_attr_set.c
index 52841f807a7e..66b05a326910 100644
--- a/drivers/cpufreq/cpufreq_governor_attr_set.c
+++ b/drivers/cpufreq/cpufreq_governor_attr_set.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Abstract code for CPUFreq governor tunable sysfs attributes.
*
* Copyright (C) 2016, Intel Corporation
* Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
- *
- * 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.
*/
#include "cpufreq_governor.h"
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 6b423eebfd5d..dced033875bf 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/cpufreq/cpufreq_ondemand.c
*
* Copyright (C) 2001 Russell King
* (C) 2003 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>.
* Jun Nakajima <jun.nakajima@intel.com>
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/cpufreq/cpufreq_ondemand.h b/drivers/cpufreq/cpufreq_ondemand.h
index 640ea4e97106..1af8e5c4b86f 100644
--- a/drivers/cpufreq/cpufreq_ondemand.h
+++ b/drivers/cpufreq/cpufreq_ondemand.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Header file for CPUFreq ondemand governor and related code.
*
* Copyright (C) 2016, Intel Corporation
* Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
- *
- * 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.
*/
#include "cpufreq_governor.h"
diff --git a/drivers/cpufreq/cpufreq_performance.c b/drivers/cpufreq/cpufreq_performance.c
index dafb679adc58..aaa04dfcacd9 100644
--- a/drivers/cpufreq/cpufreq_performance.c
+++ b/drivers/cpufreq/cpufreq_performance.c
@@ -1,13 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/cpufreq/cpufreq_performance.c
*
* Copyright (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de>
- *
- *
- * 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.
- *
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/cpufreq/cpufreq_powersave.c b/drivers/cpufreq/cpufreq_powersave.c
index 78a651038faf..c143dc237d87 100644
--- a/drivers/cpufreq/cpufreq_powersave.c
+++ b/drivers/cpufreq/cpufreq_powersave.c
@@ -1,13 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/cpufreq/cpufreq_powersave.c
*
* Copyright (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de>
- *
- *
- * 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.
- *
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index 08b192eb22c6..f9bcf0f3ea30 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/cpufreq/cpufreq_stats.c
*
* Copyright (C) 2003-2004 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>.
* (C) 2004 Zou Nan hai <nanhai.zou@intel.com>.
- *
- * 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.
*/
#include <linux/cpu.h>
diff --git a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c
index bd897e3e134d..cbd81c58cb8f 100644
--- a/drivers/cpufreq/cpufreq_userspace.c
+++ b/drivers/cpufreq/cpufreq_userspace.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/cpufreq/cpufreq_userspace.c
*
* Copyright (C) 2001 Russell King
* (C) 2002 - 2004 Dominik Brodowski <linux@brodo.de>
- *
- * 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.
- *
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/cpufreq/davinci-cpufreq.c b/drivers/cpufreq/davinci-cpufreq.c
index 940fe85db97a..297d23cad8b5 100644
--- a/drivers/cpufreq/davinci-cpufreq.c
+++ b/drivers/cpufreq/davinci-cpufreq.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* CPU frequency scaling for DaVinci
*
@@ -13,10 +14,6 @@
* Copyright (C) 2007-2008 Texas Instruments, Inc.
* Updated to support OMAP3
* Rajendra Nayak <rnayak@ti.com>
- *
- * 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.
*/
#include <linux/types.h>
#include <linux/cpufreq.h>
@@ -93,7 +90,8 @@ static int davinci_cpu_init(struct cpufreq_policy *policy)
* Setting the latency to 2000 us to accommodate addition of drivers
* to pre/post change notification list.
*/
- return cpufreq_generic_init(policy, freq_table, 2000 * 1000);
+ cpufreq_generic_init(policy, freq_table, 2000 * 1000);
+ return 0;
}
static struct cpufreq_driver davinci_driver = {
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index e7be0af3199f..ded427e0a488 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/cpufreq/freq_table.c
*
* Copyright (C) 2002 - 2003 Dominik Brodowski
- *
- * 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.
- *
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/cpufreq/gx-suspmod.c b/drivers/cpufreq/gx-suspmod.c
index 8f52a06664e3..e97b5733aa24 100644
--- a/drivers/cpufreq/gx-suspmod.c
+++ b/drivers/cpufreq/gx-suspmod.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Cyrix MediaGX and NatSemi Geode Suspend Modulation
* (C) 2002 Zwane Mwaikambo <zwane@commfireservices.com>
* (C) 2002 Hiroshi Miura <miura@da-cha.org>
* All Rights Reserved
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation
- *
* The author(s) of this software shall not be held liable for damages
* of any nature resulting due to the use of this software. This
* software is provided AS-IS with no warranties.
@@ -48,7 +45,6 @@
* off_duration = (freq * DURATION) / stock_freq
* on_duration = DURATION - off_duration
*
- *
*---------------------------------------------------------------------------
*
* ChangeLog:
diff --git a/drivers/cpufreq/highbank-cpufreq.c b/drivers/cpufreq/highbank-cpufreq.c
index 1608f7105c9f..5a7f6dafcddb 100644
--- a/drivers/cpufreq/highbank-cpufreq.c
+++ b/drivers/cpufreq/highbank-cpufreq.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Calxeda, 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.
- *
* This driver provides the clk notifier callbacks that are used when
* the cpufreq-dt driver changes to frequency to alert the highbank
* EnergyCore Management Engine (ECME) about the need to change
diff --git a/drivers/cpufreq/imx-cpufreq-dt.c b/drivers/cpufreq/imx-cpufreq-dt.c
new file mode 100644
index 000000000000..4f85f3112784
--- /dev/null
+++ b/drivers/cpufreq/imx-cpufreq-dt.c
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP
+ */
+
+#include <linux/cpu.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_opp.h>
+#include <linux/slab.h>
+
+#define OCOTP_CFG3_SPEED_GRADE_SHIFT 8
+#define OCOTP_CFG3_SPEED_GRADE_MASK (0x3 << 8)
+#define OCOTP_CFG3_MKT_SEGMENT_SHIFT 6
+#define OCOTP_CFG3_MKT_SEGMENT_MASK (0x3 << 6)
+
+/* cpufreq-dt device registered by imx-cpufreq-dt */
+static struct platform_device *cpufreq_dt_pdev;
+static struct opp_table *cpufreq_opp_table;
+
+static int imx_cpufreq_dt_probe(struct platform_device *pdev)
+{
+ struct device *cpu_dev = get_cpu_device(0);
+ u32 cell_value, supported_hw[2];
+ int speed_grade, mkt_segment;
+ int ret;
+
+ ret = nvmem_cell_read_u32(cpu_dev, "speed_grade", &cell_value);
+ if (ret)
+ return ret;
+
+ speed_grade = (cell_value & OCOTP_CFG3_SPEED_GRADE_MASK) >> OCOTP_CFG3_SPEED_GRADE_SHIFT;
+ mkt_segment = (cell_value & OCOTP_CFG3_MKT_SEGMENT_MASK) >> OCOTP_CFG3_MKT_SEGMENT_SHIFT;
+
+ /*
+ * Early samples without fuses written report "0 0" which means
+ * consumer segment and minimum speed grading.
+ *
+ * According to datasheet minimum speed grading is not supported for
+ * consumer parts so clamp to 1 to avoid warning for "no OPPs"
+ *
+ * Applies to i.MX8M series SoCs.
+ */
+ if (mkt_segment == 0 && speed_grade == 0 && (
+ of_machine_is_compatible("fsl,imx8mm") ||
+ of_machine_is_compatible("fsl,imx8mn") ||
+ of_machine_is_compatible("fsl,imx8mq")))
+ speed_grade = 1;
+
+ supported_hw[0] = BIT(speed_grade);
+ supported_hw[1] = BIT(mkt_segment);
+ dev_info(&pdev->dev, "cpu speed grade %d mkt segment %d supported-hw %#x %#x\n",
+ speed_grade, mkt_segment, supported_hw[0], supported_hw[1]);
+
+ cpufreq_opp_table = dev_pm_opp_set_supported_hw(cpu_dev, supported_hw, 2);
+ if (IS_ERR(cpufreq_opp_table)) {
+ ret = PTR_ERR(cpufreq_opp_table);
+ dev_err(&pdev->dev, "Failed to set supported opp: %d\n", ret);
+ return ret;
+ }
+
+ cpufreq_dt_pdev = platform_device_register_data(
+ &pdev->dev, "cpufreq-dt", -1, NULL, 0);
+ if (IS_ERR(cpufreq_dt_pdev)) {
+ dev_pm_opp_put_supported_hw(cpufreq_opp_table);
+ ret = PTR_ERR(cpufreq_dt_pdev);
+ dev_err(&pdev->dev, "Failed to register cpufreq-dt: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int imx_cpufreq_dt_remove(struct platform_device *pdev)
+{
+ platform_device_unregister(cpufreq_dt_pdev);
+ dev_pm_opp_put_supported_hw(cpufreq_opp_table);
+
+ return 0;
+}
+
+static struct platform_driver imx_cpufreq_dt_driver = {
+ .probe = imx_cpufreq_dt_probe,
+ .remove = imx_cpufreq_dt_remove,
+ .driver = {
+ .name = "imx-cpufreq-dt",
+ },
+};
+module_platform_driver(imx_cpufreq_dt_driver);
+
+MODULE_ALIAS("platform:imx-cpufreq-dt");
+MODULE_DESCRIPTION("Freescale i.MX cpufreq speed grading driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c
index 3e17560b1efe..648a09a1778a 100644
--- a/drivers/cpufreq/imx6q-cpufreq.c
+++ b/drivers/cpufreq/imx6q-cpufreq.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Freescale Semiconductor, 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.
*/
#include <linux/clk.h>
@@ -193,14 +190,12 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
static int imx6q_cpufreq_init(struct cpufreq_policy *policy)
{
- int ret;
-
policy->clk = clks[ARM].clk;
- ret = cpufreq_generic_init(policy, freq_table, transition_latency);
+ cpufreq_generic_init(policy, freq_table, transition_latency);
policy->suspend_freq = max_freq;
dev_pm_opp_of_register_em(policy->cpus);
- return ret;
+ return 0;
}
static struct cpufreq_driver imx6q_cpufreq_driver = {
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index f2ff5de988c1..cc27d4c59dca 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -898,7 +898,6 @@ static void intel_pstate_update_policies(void)
static void intel_pstate_update_max_freq(unsigned int cpu)
{
struct cpufreq_policy *policy = cpufreq_cpu_acquire(cpu);
- struct cpufreq_policy new_policy;
struct cpudata *cpudata;
if (!policy)
@@ -908,11 +907,7 @@ static void intel_pstate_update_max_freq(unsigned int cpu)
policy->cpuinfo.max_freq = global.turbo_disabled_mf ?
cpudata->pstate.max_freq : cpudata->pstate.turbo_freq;
- memcpy(&new_policy, policy, sizeof(*policy));
- new_policy.max = min(policy->user_policy.max, policy->cpuinfo.max_freq);
- new_policy.min = min(policy->user_policy.min, new_policy.max);
-
- cpufreq_set_policy(policy, &new_policy);
+ refresh_frequency_limits(policy);
cpufreq_cpu_release(policy);
}
diff --git a/drivers/cpufreq/kirkwood-cpufreq.c b/drivers/cpufreq/kirkwood-cpufreq.c
index 7ab564c1f7ae..cb74bdc5baaa 100644
--- a/drivers/cpufreq/kirkwood-cpufreq.c
+++ b/drivers/cpufreq/kirkwood-cpufreq.c
@@ -85,7 +85,8 @@ static int kirkwood_cpufreq_target(struct cpufreq_policy *policy,
/* Module init and exit code */
static int kirkwood_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
- return cpufreq_generic_init(policy, kirkwood_freq_table, 5000);
+ cpufreq_generic_init(policy, kirkwood_freq_table, 5000);
+ return 0;
}
static struct cpufreq_driver kirkwood_cpufreq_driver = {
diff --git a/drivers/cpufreq/loongson1-cpufreq.c b/drivers/cpufreq/loongson1-cpufreq.c
index 21c9ce8526c0..0ea88778882a 100644
--- a/drivers/cpufreq/loongson1-cpufreq.c
+++ b/drivers/cpufreq/loongson1-cpufreq.c
@@ -81,7 +81,7 @@ static int ls1x_cpufreq_init(struct cpufreq_policy *policy)
struct device *cpu_dev = get_cpu_device(policy->cpu);
struct cpufreq_frequency_table *freq_tbl;
unsigned int pll_freq, freq;
- int steps, i, ret;
+ int steps, i;
pll_freq = clk_get_rate(cpufreq->pll_clk) / 1000;
@@ -103,11 +103,9 @@ static int ls1x_cpufreq_init(struct cpufreq_policy *policy)
freq_tbl[i].frequency = CPUFREQ_TABLE_END;
policy->clk = cpufreq->clk;
- ret = cpufreq_generic_init(policy, freq_tbl, 0);
- if (ret)
- kfree(freq_tbl);
+ cpufreq_generic_init(policy, freq_tbl, 0);
- return ret;
+ return 0;
}
static int ls1x_cpufreq_exit(struct cpufreq_policy *policy)
diff --git a/drivers/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c
index da344696beed..890813e0bb76 100644
--- a/drivers/cpufreq/loongson2_cpufreq.c
+++ b/drivers/cpufreq/loongson2_cpufreq.c
@@ -95,7 +95,8 @@ static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy)
}
policy->clk = cpuclk;
- return cpufreq_generic_init(policy, &loongson2_clockmod_table[0], 0);
+ cpufreq_generic_init(policy, &loongson2_clockmod_table[0], 0);
+ return 0;
}
static int loongson2_cpufreq_exit(struct cpufreq_policy *policy)
diff --git a/drivers/cpufreq/maple-cpufreq.c b/drivers/cpufreq/maple-cpufreq.c
index a94355723ef8..28d346062166 100644
--- a/drivers/cpufreq/maple-cpufreq.c
+++ b/drivers/cpufreq/maple-cpufreq.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Dmitry Eremin-Solenikov
* Copyright (C) 2002 - 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org>
* and Markus Demleitner <msdemlei@cl.uni-heidelberg.de>
*
- * 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.
- *
* This driver adds basic cpufreq support for SMU & 970FX based G5 Macs,
* that is iMac G5 and latest single CPU desktop.
*/
@@ -143,7 +140,8 @@ static unsigned int maple_cpufreq_get_speed(unsigned int cpu)
static int maple_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
- return cpufreq_generic_init(policy, maple_cpu_freqs, 12000);
+ cpufreq_generic_init(policy, maple_cpu_freqs, 12000);
+ return 0;
}
static struct cpufreq_driver maple_cpufreq_driver = {
diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c
index 68052b74d28f..8d14b42a8c6f 100644
--- a/drivers/cpufreq/omap-cpufreq.c
+++ b/drivers/cpufreq/omap-cpufreq.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* CPU frequency scaling for OMAP using OPP information
*
@@ -8,10 +9,6 @@
*
* Copyright (C) 2007-2011 Texas Instruments, Inc.
* - OMAP3/4 support by Rajendra Nayak, Santosh Shilimkar
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -125,23 +122,18 @@ static int omap_cpu_init(struct cpufreq_policy *policy)
dev_err(mpu_dev,
"%s: cpu%d: failed creating freq table[%d]\n",
__func__, policy->cpu, result);
- goto fail;
+ clk_put(policy->clk);
+ return result;
}
}
atomic_inc_return(&freq_table_users);
/* FIXME: what's the actual transition time? */
- result = cpufreq_generic_init(policy, freq_table, 300 * 1000);
- if (!result) {
- dev_pm_opp_of_register_em(policy->cpus);
- return 0;
- }
+ cpufreq_generic_init(policy, freq_table, 300 * 1000);
+ dev_pm_opp_of_register_em(policy->cpus);
- freq_table_free();
-fail:
- clk_put(policy->clk);
- return result;
+ return 0;
}
static int omap_cpu_exit(struct cpufreq_policy *policy)
diff --git a/drivers/cpufreq/pasemi-cpufreq.c b/drivers/cpufreq/pasemi-cpufreq.c
index 6b1e4abe3248..93f39a1d4c3d 100644
--- a/drivers/cpufreq/pasemi-cpufreq.c
+++ b/drivers/cpufreq/pasemi-cpufreq.c
@@ -196,7 +196,8 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
policy->cur = pas_freqs[cur_astate].frequency;
ppc_proc_freq = policy->cur * 1000ul;
- return cpufreq_generic_init(policy, pas_freqs, get_gizmo_latency());
+ cpufreq_generic_init(policy, pas_freqs, get_gizmo_latency());
+ return 0;
out_unmap_sdcpwr:
iounmap(sdcpwr_mapbase);
diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c
index 1e5e64643c3a..fdc767fdbe6a 100644
--- a/drivers/cpufreq/pcc-cpufreq.c
+++ b/drivers/cpufreq/pcc-cpufreq.c
@@ -582,10 +582,10 @@ static int __init pcc_cpufreq_init(void)
/* Skip initialization if another cpufreq driver is there. */
if (cpufreq_get_current_driver())
- return 0;
+ return -EEXIST;
if (acpi_disabled)
- return 0;
+ return -ENODEV;
ret = pcc_cpufreq_probe();
if (ret) {
diff --git a/drivers/cpufreq/pmac32-cpufreq.c b/drivers/cpufreq/pmac32-cpufreq.c
index 9b4ce2eb8222..73621bc11976 100644
--- a/drivers/cpufreq/pmac32-cpufreq.c
+++ b/drivers/cpufreq/pmac32-cpufreq.c
@@ -1,16 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2002 - 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org>
* Copyright (C) 2004 John Steele Scott <toojays@toojays.net>
*
- * 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.
- *
* TODO: Need a big cleanup here. Basically, we need to have different
* cpufreq_driver structures for the different type of HW instead of the
* current mess. We also need to better deal with the detection of the
* type of machine.
- *
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -376,7 +372,8 @@ static int pmac_cpufreq_target( struct cpufreq_policy *policy,
static int pmac_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
- return cpufreq_generic_init(policy, pmac_cpu_freqs, transition_latency);
+ cpufreq_generic_init(policy, pmac_cpu_freqs, transition_latency);
+ return 0;
}
static u32 read_gpio(struct device_node *np)
diff --git a/drivers/cpufreq/pmac64-cpufreq.c b/drivers/cpufreq/pmac64-cpufreq.c
index 1d32a863332d..d7542a106e6b 100644
--- a/drivers/cpufreq/pmac64-cpufreq.c
+++ b/drivers/cpufreq/pmac64-cpufreq.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2002 - 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org>
* and Markus Demleitner <msdemlei@cl.uni-heidelberg.de>
*
- * 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.
- *
* This driver adds basic cpufreq support for SMU & 970FX based G5 Macs,
* that is iMac G5 and latest single CPU desktop.
*/
@@ -324,7 +321,8 @@ static unsigned int g5_cpufreq_get_speed(unsigned int cpu)
static int g5_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
- return cpufreq_generic_init(policy, g5_cpu_freqs, transition_latency);
+ cpufreq_generic_init(policy, g5_cpu_freqs, transition_latency);
+ return 0;
}
static struct cpufreq_driver g5_cpufreq_driver = {
diff --git a/drivers/cpufreq/qoriq-cpufreq.c b/drivers/cpufreq/qoriq-cpufreq.c
index 71b640c8c1a5..8e436dc75c8b 100644
--- a/drivers/cpufreq/qoriq-cpufreq.c
+++ b/drivers/cpufreq/qoriq-cpufreq.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2013 Freescale Semiconductor, Inc.
*
* CPU Frequency Scaling driver for Freescale QorIQ SoCs.
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/cpufreq/raspberrypi-cpufreq.c b/drivers/cpufreq/raspberrypi-cpufreq.c
new file mode 100644
index 000000000000..2bc7d9734272
--- /dev/null
+++ b/drivers/cpufreq/raspberrypi-cpufreq.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Raspberry Pi cpufreq driver
+ *
+ * Copyright (C) 2019, Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+ */
+
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_opp.h>
+
+#define RASPBERRYPI_FREQ_INTERVAL 100000000
+
+static struct platform_device *cpufreq_dt;
+
+static int raspberrypi_cpufreq_probe(struct platform_device *pdev)
+{
+ struct device *cpu_dev;
+ unsigned long min, max;
+ unsigned long rate;
+ struct clk *clk;
+ int ret;
+
+ cpu_dev = get_cpu_device(0);
+ if (!cpu_dev) {
+ pr_err("Cannot get CPU for cpufreq driver\n");
+ return -ENODEV;
+ }
+
+ clk = clk_get(cpu_dev, NULL);
+ if (IS_ERR(clk)) {
+ dev_err(cpu_dev, "Cannot get clock for CPU0\n");
+ return PTR_ERR(clk);
+ }
+
+ /*
+ * The max and min frequencies are configurable in the Raspberry Pi
+ * firmware, so we query them at runtime.
+ */
+ min = roundup(clk_round_rate(clk, 0), RASPBERRYPI_FREQ_INTERVAL);
+ max = roundup(clk_round_rate(clk, ULONG_MAX), RASPBERRYPI_FREQ_INTERVAL);
+ clk_put(clk);
+
+ for (rate = min; rate <= max; rate += RASPBERRYPI_FREQ_INTERVAL) {
+ ret = dev_pm_opp_add(cpu_dev, rate, 0);
+ if (ret)
+ goto remove_opp;
+ }
+
+ cpufreq_dt = platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
+ ret = PTR_ERR_OR_ZERO(cpufreq_dt);
+ if (ret) {
+ dev_err(cpu_dev, "Failed to create platform device, %d\n", ret);
+ goto remove_opp;
+ }
+
+ return 0;
+
+remove_opp:
+ dev_pm_opp_remove_all_dynamic(cpu_dev);
+
+ return ret;
+}
+
+static int raspberrypi_cpufreq_remove(struct platform_device *pdev)
+{
+ struct device *cpu_dev;
+
+ cpu_dev = get_cpu_device(0);
+ if (cpu_dev)
+ dev_pm_opp_remove_all_dynamic(cpu_dev);
+
+ platform_device_unregister(cpufreq_dt);
+
+ return 0;
+}
+
+/*
+ * Since the driver depends on clk-raspberrypi, which may return EPROBE_DEFER,
+ * all the activity is performed in the probe, which may be defered as well.
+ */
+static struct platform_driver raspberrypi_cpufreq_driver = {
+ .driver = {
+ .name = "raspberrypi-cpufreq",
+ },
+ .probe = raspberrypi_cpufreq_probe,
+ .remove = raspberrypi_cpufreq_remove,
+};
+module_platform_driver(raspberrypi_cpufreq_driver);
+
+MODULE_AUTHOR("Nicolas Saenz Julienne <nsaenzjulienne@suse.de");
+MODULE_DESCRIPTION("Raspberry Pi cpufreq driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:raspberrypi-cpufreq");
diff --git a/drivers/cpufreq/s3c2410-cpufreq.c b/drivers/cpufreq/s3c2410-cpufreq.c
index b8e5da8e188b..0c4f2ccd7e22 100644
--- a/drivers/cpufreq/s3c2410-cpufreq.c
+++ b/drivers/cpufreq/s3c2410-cpufreq.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2006-2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
*
* S3C2410 CPU Frequency scaling
- *
- * 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.
*/
#include <linux/init.h>
diff --git a/drivers/cpufreq/s3c2412-cpufreq.c b/drivers/cpufreq/s3c2412-cpufreq.c
index b04b6f02bbdc..53385a9ab957 100644
--- a/drivers/cpufreq/s3c2412-cpufreq.c
+++ b/drivers/cpufreq/s3c2412-cpufreq.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
*
* S3C2412 CPU Frequency scalling
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/cpufreq/s3c2416-cpufreq.c b/drivers/cpufreq/s3c2416-cpufreq.c
index 5b2db3c6568f..106910351c41 100644
--- a/drivers/cpufreq/s3c2416-cpufreq.c
+++ b/drivers/cpufreq/s3c2416-cpufreq.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* S3C2416/2450 CPUfreq Support
*
@@ -6,10 +7,6 @@
* based on s3c64xx_cpufreq.c
*
* Copyright 2009 Wolfson Microelectronics plc
- *
- * 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.
*/
#include <linux/kernel.h>
@@ -450,21 +447,16 @@ static int s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy)
/* Datasheet says PLL stabalisation time must be at least 300us,
* so but add some fudge. (reference in LOCKCON0 register description)
*/
- ret = cpufreq_generic_init(policy, s3c_freq->freq_table,
+ cpufreq_generic_init(policy, s3c_freq->freq_table,
(500 * 1000) + s3c_freq->regulator_latency);
- if (ret)
- goto err_freq_table;
-
register_reboot_notifier(&s3c2416_cpufreq_reboot_notifier);
return 0;
-err_freq_table:
#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
- regulator_put(s3c_freq->vddarm);
err_vddarm:
-#endif
clk_put(s3c_freq->armclk);
+#endif
err_armclk:
clk_put(s3c_freq->hclk);
err_hclk:
diff --git a/drivers/cpufreq/s3c2440-cpufreq.c b/drivers/cpufreq/s3c2440-cpufreq.c
index d2f67b7a20dd..3f772ba8896e 100644
--- a/drivers/cpufreq/s3c2440-cpufreq.c
+++ b/drivers/cpufreq/s3c2440-cpufreq.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2006-2009 Simtec Electronics
* http://armlinux.simtec.co.uk/
@@ -5,10 +6,6 @@
* Vincent Sanders <vince@simtec.co.uk>
*
* S3C2440/S3C2442 CPU Frequency scaling
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/cpufreq/s3c24xx-cpufreq-debugfs.c b/drivers/cpufreq/s3c24xx-cpufreq-debugfs.c
index 0df87b6480fe..290e3539d03e 100644
--- a/drivers/cpufreq/s3c24xx-cpufreq-debugfs.c
+++ b/drivers/cpufreq/s3c24xx-cpufreq-debugfs.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2009 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
*
* S3C24XX CPU Frequency scaling - debugfs status support
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/cpufreq/s3c24xx-cpufreq.c b/drivers/cpufreq/s3c24xx-cpufreq.c
index 3b291a2b0cb3..ed0e713b1b57 100644
--- a/drivers/cpufreq/s3c24xx-cpufreq.c
+++ b/drivers/cpufreq/s3c24xx-cpufreq.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2006-2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
*
* S3C24XX CPU Frequency scaling
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/cpufreq/s3c64xx-cpufreq.c b/drivers/cpufreq/s3c64xx-cpufreq.c
index 0cb9040eca49..af0c00dabb22 100644
--- a/drivers/cpufreq/s3c64xx-cpufreq.c
+++ b/drivers/cpufreq/s3c64xx-cpufreq.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2009 Wolfson Microelectronics plc
*
* S3C64xx CPUfreq Support
- *
- * 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.
*/
#define pr_fmt(fmt) "cpufreq: " fmt
@@ -147,7 +144,6 @@ out:
static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
{
- int ret;
struct cpufreq_frequency_table *freq;
if (policy->cpu != 0)
@@ -168,8 +164,7 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
#ifdef CONFIG_REGULATOR
vddarm = regulator_get(NULL, "vddarm");
if (IS_ERR(vddarm)) {
- ret = PTR_ERR(vddarm);
- pr_err("Failed to obtain VDDARM: %d\n", ret);
+ pr_err("Failed to obtain VDDARM: %ld\n", PTR_ERR(vddarm));
pr_err("Only frequency scaling available\n");
vddarm = NULL;
} else {
@@ -199,16 +194,9 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
* the PLLs, which we don't currently) is ~300us worst case,
* but add some fudge.
*/
- ret = cpufreq_generic_init(policy, s3c64xx_freq_table,
+ cpufreq_generic_init(policy, s3c64xx_freq_table,
(500 * 1000) + regulator_latency);
- if (ret != 0) {
- pr_err("Failed to configure frequency table: %d\n",
- ret);
- regulator_put(vddarm);
- clk_put(policy->clk);
- }
-
- return ret;
+ return 0;
}
static struct cpufreq_driver s3c64xx_cpufreq_driver = {
diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c
index 5b4289460bc9..5d10030f2560 100644
--- a/drivers/cpufreq/s5pv210-cpufreq.c
+++ b/drivers/cpufreq/s5pv210-cpufreq.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2010 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* CPU frequency scaling for S5PC110/S5PV210
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -481,7 +478,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
arm_volt, arm_volt_max);
}
- printk(KERN_DEBUG "Perf changed[L%d]\n", index);
+ pr_debug("Perf changed[L%d]\n", index);
exit:
mutex_unlock(&set_freq_lock);
@@ -544,7 +541,8 @@ static int s5pv210_cpu_init(struct cpufreq_policy *policy)
s5pv210_dram_conf[1].freq = clk_get_rate(dmc1_clk);
policy->suspend_freq = SLEEP_FREQ;
- return cpufreq_generic_init(policy, s5pv210_freq_table, 40000);
+ cpufreq_generic_init(policy, s5pv210_freq_table, 40000);
+ return 0;
out_dmc1:
clk_put(dmc0_clk);
diff --git a/drivers/cpufreq/sa1100-cpufreq.c b/drivers/cpufreq/sa1100-cpufreq.c
index ab5cab93e638..5c075ef6adc0 100644
--- a/drivers/cpufreq/sa1100-cpufreq.c
+++ b/drivers/cpufreq/sa1100-cpufreq.c
@@ -181,7 +181,8 @@ static int sa1100_target(struct cpufreq_policy *policy, unsigned int ppcr)
static int __init sa1100_cpu_init(struct cpufreq_policy *policy)
{
- return cpufreq_generic_init(policy, sa11x0_freq_table, 0);
+ cpufreq_generic_init(policy, sa11x0_freq_table, 0);
+ return 0;
}
static struct cpufreq_driver sa1100_driver __refdata = {
diff --git a/drivers/cpufreq/sa1110-cpufreq.c b/drivers/cpufreq/sa1110-cpufreq.c
index 66e5fb088ecc..d9d04d935b3a 100644
--- a/drivers/cpufreq/sa1110-cpufreq.c
+++ b/drivers/cpufreq/sa1110-cpufreq.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/arch/arm/mach-sa1100/cpu-sa1110.c
*
* Copyright (C) 2001 Russell King
*
- * 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.
- *
* Note: there are two erratas that apply to the SA1110 here:
* 7 - SDRAM auto-power-up failure (rev A0)
* 13 - Corruption of internal register reads/writes following
@@ -306,7 +303,8 @@ static int sa1110_target(struct cpufreq_policy *policy, unsigned int ppcr)
static int __init sa1110_cpu_init(struct cpufreq_policy *policy)
{
- return cpufreq_generic_init(policy, sa11x0_freq_table, 0);
+ cpufreq_generic_init(policy, sa11x0_freq_table, 0);
+ return 0;
}
/* sa1110_driver needs __refdata because it must remain after init registers
diff --git a/drivers/cpufreq/sfi-cpufreq.c b/drivers/cpufreq/sfi-cpufreq.c
index 978770432b13..45cfdf67cf03 100644
--- a/drivers/cpufreq/sfi-cpufreq.c
+++ b/drivers/cpufreq/sfi-cpufreq.c
@@ -1,15 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* SFI Performance States Driver
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
* Author: Vishwesh M Rudramuni <vishwesh.m.rudramuni@intel.com>
* Author: Srinidhi Kasagar <srinidhi.kasagar@intel.com>
*/
diff --git a/drivers/cpufreq/spear-cpufreq.c b/drivers/cpufreq/spear-cpufreq.c
index 4074e2615522..73bd8dc47074 100644
--- a/drivers/cpufreq/spear-cpufreq.c
+++ b/drivers/cpufreq/spear-cpufreq.c
@@ -153,8 +153,9 @@ static int spear_cpufreq_target(struct cpufreq_policy *policy,
static int spear_cpufreq_init(struct cpufreq_policy *policy)
{
policy->clk = spear_cpufreq.clk;
- return cpufreq_generic_init(policy, spear_cpufreq.freq_tbl,
+ cpufreq_generic_init(policy, spear_cpufreq.freq_tbl,
spear_cpufreq.transition_latency);
+ return 0;
}
static struct cpufreq_driver spear_cpufreq_driver = {
diff --git a/drivers/cpufreq/tegra20-cpufreq.c b/drivers/cpufreq/tegra20-cpufreq.c
index 3c32cc7b0671..f84ecd22f488 100644
--- a/drivers/cpufreq/tegra20-cpufreq.c
+++ b/drivers/cpufreq/tegra20-cpufreq.c
@@ -118,17 +118,11 @@ static int tegra_target(struct cpufreq_policy *policy, unsigned int index)
static int tegra_cpu_init(struct cpufreq_policy *policy)
{
struct tegra20_cpufreq *cpufreq = cpufreq_get_driver_data();
- int ret;
clk_prepare_enable(cpufreq->cpu_clk);
/* FIXME: what's the actual transition time? */
- ret = cpufreq_generic_init(policy, freq_table, 300 * 1000);
- if (ret) {
- clk_disable_unprepare(cpufreq->cpu_clk);
- return ret;
- }
-
+ cpufreq_generic_init(policy, freq_table, 300 * 1000);
policy->clk = cpufreq->cpu_clk;
policy->suspend_freq = freq_table[0].frequency;
return 0;
diff --git a/drivers/cpufreq/unicore2-cpufreq.c b/drivers/cpufreq/unicore2-cpufreq.c
index db62d9844751..707dbc1b7ac8 100644
--- a/drivers/cpufreq/unicore2-cpufreq.c
+++ b/drivers/cpufreq/unicore2-cpufreq.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* clock scaling for the UniCore-II
*
@@ -5,10 +6,6 @@
*
* Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
* Copyright (C) 2001-2010 Guan Xuetao
- *
- * 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.
*/
#include <linux/err.h>
diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c
index 3a407a3ef22b..5bcd82c35dcf 100644
--- a/drivers/cpuidle/cpuidle-arm.c
+++ b/drivers/cpuidle/cpuidle-arm.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ARM/ARM64 generic CPU idle driver.
*
* Copyright (C) 2014 ARM Ltd.
* Author: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
- *
- * 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.
*/
#define pr_fmt(fmt) "CPUidle arm: " fmt
diff --git a/drivers/cpuidle/cpuidle-big_little.c b/drivers/cpuidle/cpuidle-big_little.c
index b44476a1b7ad..7f8ddc04342d 100644
--- a/drivers/cpuidle/cpuidle-big_little.c
+++ b/drivers/cpuidle/cpuidle-big_little.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2013 ARM/Linaro
*
@@ -5,10 +6,6 @@
* Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
* Nicolas Pitre <nicolas.pitre@linaro.org>
*
- * 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.
- *
* Maintainer: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
* Maintainer: Daniel Lezcano <daniel.lezcano@linaro.org>
*/
diff --git a/drivers/cpuidle/cpuidle-exynos.c b/drivers/cpuidle/cpuidle-exynos.c
index f7199a35cbb6..b2b5666e0515 100644
--- a/drivers/cpuidle/cpuidle-exynos.c
+++ b/drivers/cpuidle/cpuidle-exynos.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2011-2014 Samsung Electronics Co., Ltd.
* http://www.samsung.com
@@ -5,10 +6,6 @@
* Coupled cpuidle support based on the work of:
* Colin Cross <ccross@android.com>
* Daniel Lezcano <daniel.lezcano@linaro.org>
- *
- * 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.
*/
#include <linux/cpuidle.h>
diff --git a/drivers/cpuidle/cpuidle-ux500.c b/drivers/cpuidle/cpuidle-ux500.c
index 7941a090bea6..a2d34be17a09 100644
--- a/drivers/cpuidle/cpuidle-ux500.c
+++ b/drivers/cpuidle/cpuidle-ux500.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012 Linaro : Daniel Lezcano <daniel.lezcano@linaro.org> (IBM)
*
* Based on the work of Rickard Andersson <rickard.andersson@stericsson.com>
* and Jonas Aaberg <jonas.aberg@stericsson.com>.
- *
- * 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.
*/
#include <linux/init.h>
diff --git a/drivers/cpuidle/dt_idle_states.c b/drivers/cpuidle/dt_idle_states.c
index add9569636b5..d06d21a9525d 100644
--- a/drivers/cpuidle/dt_idle_states.c
+++ b/drivers/cpuidle/dt_idle_states.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* DT idle states parsing code.
*
* Copyright (C) 2014 ARM Ltd.
* Author: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
- *
- * 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.
*/
#define pr_fmt(fmt) "DT idle-states: " fmt
diff --git a/drivers/cpuidle/governor.c b/drivers/cpuidle/governor.c
index 9fddf828a76f..2e3e14192bee 100644
--- a/drivers/cpuidle/governor.c
+++ b/drivers/cpuidle/governor.c
@@ -110,7 +110,7 @@ int cpuidle_governor_latency_req(unsigned int cpu)
{
int global_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
struct device *device = get_cpu_device(cpu);
- int device_req = dev_pm_qos_raw_read_value(device);
+ int device_req = dev_pm_qos_raw_resume_latency(device);
return device_req < global_req ? device_req : global_req;
}
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 0af08081e305..603413f28fa3 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -520,10 +520,13 @@ config CRYPTO_DEV_ATMEL_SHA
To compile this driver as a module, choose M here: the module
will be called atmel-sha.
+config CRYPTO_DEV_ATMEL_I2C
+ tristate
+
config CRYPTO_DEV_ATMEL_ECC
tristate "Support for Microchip / Atmel ECC hw accelerator"
- depends on ARCH_AT91 || COMPILE_TEST
depends on I2C
+ select CRYPTO_DEV_ATMEL_I2C
select CRYPTO_ECDH
select CRC16
help
@@ -534,6 +537,21 @@ config CRYPTO_DEV_ATMEL_ECC
To compile this driver as a module, choose M here: the module
will be called atmel-ecc.
+config CRYPTO_DEV_ATMEL_SHA204A
+ tristate "Support for Microchip / Atmel SHA accelerator and RNG"
+ depends on I2C
+ select CRYPTO_DEV_ATMEL_I2C
+ select HW_RANDOM
+ select CRC16
+ help
+ Microhip / Atmel SHA accelerator and RNG.
+ Select this if you want to use the Microchip / Atmel SHA204A
+ module as a random number generator. (Other functions of the
+ chip are currently not exposed by this driver)
+
+ To compile this driver as a module, choose M here: the module
+ will be called atmel-sha204a.
+
config CRYPTO_DEV_CCP
bool "Support for AMD Secure Processor"
depends on ((X86 && PCI) || (ARM64 && (OF_ADDRESS || ACPI))) && HAS_IOMEM
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index a23a7197fcd7..afc4753b5d28 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -2,7 +2,9 @@
obj-$(CONFIG_CRYPTO_DEV_ATMEL_AES) += atmel-aes.o
obj-$(CONFIG_CRYPTO_DEV_ATMEL_SHA) += atmel-sha.o
obj-$(CONFIG_CRYPTO_DEV_ATMEL_TDES) += atmel-tdes.o
+obj-$(CONFIG_CRYPTO_DEV_ATMEL_I2C) += atmel-i2c.o
obj-$(CONFIG_CRYPTO_DEV_ATMEL_ECC) += atmel-ecc.o
+obj-$(CONFIG_CRYPTO_DEV_ATMEL_SHA204A) += atmel-sha204a.o
obj-$(CONFIG_CRYPTO_DEV_CAVIUM_ZIP) += cavium/
obj-$(CONFIG_CRYPTO_DEV_CCP) += ccp/
obj-$(CONFIG_CRYPTO_DEV_CCREE) += ccree/
diff --git a/drivers/crypto/amcc/crypto4xx_alg.c b/drivers/crypto/amcc/crypto4xx_alg.c
index 49f3e0ce242c..cbfc607282f4 100644
--- a/drivers/crypto/amcc/crypto4xx_alg.c
+++ b/drivers/crypto/amcc/crypto4xx_alg.c
@@ -67,12 +67,16 @@ static void set_dynamic_sa_command_1(struct dynamic_sa_ctl *sa, u32 cm,
}
static inline int crypto4xx_crypt(struct skcipher_request *req,
- const unsigned int ivlen, bool decrypt)
+ const unsigned int ivlen, bool decrypt,
+ bool check_blocksize)
{
struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(req);
struct crypto4xx_ctx *ctx = crypto_skcipher_ctx(cipher);
__le32 iv[AES_IV_SIZE];
+ if (check_blocksize && !IS_ALIGNED(req->cryptlen, AES_BLOCK_SIZE))
+ return -EINVAL;
+
if (ivlen)
crypto4xx_memcpy_to_le32(iv, req->iv, ivlen);
@@ -81,24 +85,34 @@ static inline int crypto4xx_crypt(struct skcipher_request *req,
ctx->sa_len, 0, NULL);
}
-int crypto4xx_encrypt_noiv(struct skcipher_request *req)
+int crypto4xx_encrypt_noiv_block(struct skcipher_request *req)
+{
+ return crypto4xx_crypt(req, 0, false, true);
+}
+
+int crypto4xx_encrypt_iv_stream(struct skcipher_request *req)
+{
+ return crypto4xx_crypt(req, AES_IV_SIZE, false, false);
+}
+
+int crypto4xx_decrypt_noiv_block(struct skcipher_request *req)
{
- return crypto4xx_crypt(req, 0, false);
+ return crypto4xx_crypt(req, 0, true, true);
}
-int crypto4xx_encrypt_iv(struct skcipher_request *req)
+int crypto4xx_decrypt_iv_stream(struct skcipher_request *req)
{
- return crypto4xx_crypt(req, AES_IV_SIZE, false);
+ return crypto4xx_crypt(req, AES_IV_SIZE, true, false);
}
-int crypto4xx_decrypt_noiv(struct skcipher_request *req)
+int crypto4xx_encrypt_iv_block(struct skcipher_request *req)
{
- return crypto4xx_crypt(req, 0, true);
+ return crypto4xx_crypt(req, AES_IV_SIZE, false, true);
}
-int crypto4xx_decrypt_iv(struct skcipher_request *req)
+int crypto4xx_decrypt_iv_block(struct skcipher_request *req)
{
- return crypto4xx_crypt(req, AES_IV_SIZE, true);
+ return crypto4xx_crypt(req, AES_IV_SIZE, true, true);
}
/**
@@ -269,8 +283,8 @@ crypto4xx_ctr_crypt(struct skcipher_request *req, bool encrypt)
return ret;
}
- return encrypt ? crypto4xx_encrypt_iv(req)
- : crypto4xx_decrypt_iv(req);
+ return encrypt ? crypto4xx_encrypt_iv_stream(req)
+ : crypto4xx_decrypt_iv_stream(req);
}
static int crypto4xx_sk_setup_fallback(struct crypto4xx_ctx *ctx,
diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c
index 16d911aaa508..de5e9352e920 100644
--- a/drivers/crypto/amcc/crypto4xx_core.c
+++ b/drivers/crypto/amcc/crypto4xx_core.c
@@ -182,7 +182,6 @@ static u32 crypto4xx_build_pdr(struct crypto4xx_device *dev)
dev->pdr_pa);
return -ENOMEM;
}
- memset(dev->pdr, 0, sizeof(struct ce_pd) * PPC4XX_NUM_PD);
dev->shadow_sa_pool = dma_alloc_coherent(dev->core_dev->device,
sizeof(union shadow_sa_buf) * PPC4XX_NUM_PD,
&dev->shadow_sa_pool_pa,
@@ -1210,8 +1209,8 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = {
.max_keysize = AES_MAX_KEY_SIZE,
.ivsize = AES_IV_SIZE,
.setkey = crypto4xx_setkey_aes_cbc,
- .encrypt = crypto4xx_encrypt_iv,
- .decrypt = crypto4xx_decrypt_iv,
+ .encrypt = crypto4xx_encrypt_iv_block,
+ .decrypt = crypto4xx_decrypt_iv_block,
.init = crypto4xx_sk_init,
.exit = crypto4xx_sk_exit,
} },
@@ -1222,7 +1221,7 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = {
.cra_priority = CRYPTO4XX_CRYPTO_PRIORITY,
.cra_flags = CRYPTO_ALG_ASYNC |
CRYPTO_ALG_KERN_DRIVER_ONLY,
- .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_blocksize = 1,
.cra_ctxsize = sizeof(struct crypto4xx_ctx),
.cra_module = THIS_MODULE,
},
@@ -1230,8 +1229,8 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = {
.max_keysize = AES_MAX_KEY_SIZE,
.ivsize = AES_IV_SIZE,
.setkey = crypto4xx_setkey_aes_cfb,
- .encrypt = crypto4xx_encrypt_iv,
- .decrypt = crypto4xx_decrypt_iv,
+ .encrypt = crypto4xx_encrypt_iv_stream,
+ .decrypt = crypto4xx_decrypt_iv_stream,
.init = crypto4xx_sk_init,
.exit = crypto4xx_sk_exit,
} },
@@ -1243,7 +1242,7 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = {
.cra_flags = CRYPTO_ALG_NEED_FALLBACK |
CRYPTO_ALG_ASYNC |
CRYPTO_ALG_KERN_DRIVER_ONLY,
- .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_blocksize = 1,
.cra_ctxsize = sizeof(struct crypto4xx_ctx),
.cra_module = THIS_MODULE,
},
@@ -1263,7 +1262,7 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = {
.cra_priority = CRYPTO4XX_CRYPTO_PRIORITY,
.cra_flags = CRYPTO_ALG_ASYNC |
CRYPTO_ALG_KERN_DRIVER_ONLY,
- .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_blocksize = 1,
.cra_ctxsize = sizeof(struct crypto4xx_ctx),
.cra_module = THIS_MODULE,
},
@@ -1290,8 +1289,8 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = {
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
.setkey = crypto4xx_setkey_aes_ecb,
- .encrypt = crypto4xx_encrypt_noiv,
- .decrypt = crypto4xx_decrypt_noiv,
+ .encrypt = crypto4xx_encrypt_noiv_block,
+ .decrypt = crypto4xx_decrypt_noiv_block,
.init = crypto4xx_sk_init,
.exit = crypto4xx_sk_exit,
} },
@@ -1302,7 +1301,7 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = {
.cra_priority = CRYPTO4XX_CRYPTO_PRIORITY,
.cra_flags = CRYPTO_ALG_ASYNC |
CRYPTO_ALG_KERN_DRIVER_ONLY,
- .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_blocksize = 1,
.cra_ctxsize = sizeof(struct crypto4xx_ctx),
.cra_module = THIS_MODULE,
},
@@ -1310,8 +1309,8 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = {
.max_keysize = AES_MAX_KEY_SIZE,
.ivsize = AES_IV_SIZE,
.setkey = crypto4xx_setkey_aes_ofb,
- .encrypt = crypto4xx_encrypt_iv,
- .decrypt = crypto4xx_decrypt_iv,
+ .encrypt = crypto4xx_encrypt_iv_stream,
+ .decrypt = crypto4xx_decrypt_iv_stream,
.init = crypto4xx_sk_init,
.exit = crypto4xx_sk_exit,
} },
diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h
index ca1c25c40c23..6b6841359190 100644
--- a/drivers/crypto/amcc/crypto4xx_core.h
+++ b/drivers/crypto/amcc/crypto4xx_core.h
@@ -173,10 +173,12 @@ int crypto4xx_setkey_rfc3686(struct crypto_skcipher *cipher,
const u8 *key, unsigned int keylen);
int crypto4xx_encrypt_ctr(struct skcipher_request *req);
int crypto4xx_decrypt_ctr(struct skcipher_request *req);
-int crypto4xx_encrypt_iv(struct skcipher_request *req);
-int crypto4xx_decrypt_iv(struct skcipher_request *req);
-int crypto4xx_encrypt_noiv(struct skcipher_request *req);
-int crypto4xx_decrypt_noiv(struct skcipher_request *req);
+int crypto4xx_encrypt_iv_stream(struct skcipher_request *req);
+int crypto4xx_decrypt_iv_stream(struct skcipher_request *req);
+int crypto4xx_encrypt_iv_block(struct skcipher_request *req);
+int crypto4xx_decrypt_iv_block(struct skcipher_request *req);
+int crypto4xx_encrypt_noiv_block(struct skcipher_request *req);
+int crypto4xx_decrypt_noiv_block(struct skcipher_request *req);
int crypto4xx_rfc3686_encrypt(struct skcipher_request *req);
int crypto4xx_rfc3686_decrypt(struct skcipher_request *req);
int crypto4xx_sha1_alg_init(struct crypto_tfm *tfm);
diff --git a/drivers/crypto/amcc/crypto4xx_trng.c b/drivers/crypto/amcc/crypto4xx_trng.c
index 02a6bed3b062..f10a87e541ed 100644
--- a/drivers/crypto/amcc/crypto4xx_trng.c
+++ b/drivers/crypto/amcc/crypto4xx_trng.c
@@ -108,7 +108,6 @@ void ppc4xx_trng_probe(struct crypto4xx_core_device *core_dev)
return;
err_out:
- of_node_put(trng);
iounmap(dev->trng_base);
kfree(rng);
dev->trng_base = NULL;
diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c
index ba00e4563ca0..ff02cc05affb 100644
--- a/drivers/crypto/atmel-ecc.c
+++ b/drivers/crypto/atmel-ecc.c
@@ -6,8 +6,6 @@
* Author: Tudor Ambarus <tudor.ambarus@microchip.com>
*/
-#include <linux/bitrev.h>
-#include <linux/crc16.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
@@ -23,42 +21,11 @@
#include <crypto/internal/kpp.h>
#include <crypto/ecdh.h>
#include <crypto/kpp.h>
-#include "atmel-ecc.h"
-
-/* Used for binding tfm objects to i2c clients. */
-struct atmel_ecc_driver_data {
- struct list_head i2c_client_list;
- spinlock_t i2c_list_lock;
-} ____cacheline_aligned;
+#include "atmel-i2c.h"
static struct atmel_ecc_driver_data driver_data;
/**
- * atmel_ecc_i2c_client_priv - i2c_client private data
- * @client : pointer to i2c client device
- * @i2c_client_list_node: part of i2c_client_list
- * @lock : lock for sending i2c commands
- * @wake_token : wake token array of zeros
- * @wake_token_sz : size in bytes of the wake_token
- * @tfm_count : number of active crypto transformations on i2c client
- *
- * Reads and writes from/to the i2c client are sequential. The first byte
- * transmitted to the device is treated as the byte size. Any attempt to send
- * more than this number of bytes will cause the device to not ACK those bytes.
- * After the host writes a single command byte to the input buffer, reads are
- * prohibited until after the device completes command execution. Use a mutex
- * when sending i2c commands.
- */
-struct atmel_ecc_i2c_client_priv {
- struct i2c_client *client;
- struct list_head i2c_client_list_node;
- struct mutex lock;
- u8 wake_token[WAKE_TOKEN_MAX_SIZE];
- size_t wake_token_sz;
- atomic_t tfm_count ____cacheline_aligned;
-};
-
-/**
* atmel_ecdh_ctx - transformation context
* @client : pointer to i2c client device
* @fallback : used for unsupported curves or when user wants to use its own
@@ -80,188 +47,12 @@ struct atmel_ecdh_ctx {
bool do_fallback;
};
-/**
- * atmel_ecc_work_data - data structure representing the work
- * @ctx : transformation context.
- * @cbk : pointer to a callback function to be invoked upon completion of this
- * request. This has the form:
- * callback(struct atmel_ecc_work_data *work_data, void *areq, u8 status)
- * where:
- * @work_data: data structure representing the work
- * @areq : optional pointer to an argument passed with the original
- * request.
- * @status : status returned from the i2c client device or i2c error.
- * @areq: optional pointer to a user argument for use at callback time.
- * @work: describes the task to be executed.
- * @cmd : structure used for communicating with the device.
- */
-struct atmel_ecc_work_data {
- struct atmel_ecdh_ctx *ctx;
- void (*cbk)(struct atmel_ecc_work_data *work_data, void *areq,
- int status);
- void *areq;
- struct work_struct work;
- struct atmel_ecc_cmd cmd;
-};
-
-static u16 atmel_ecc_crc16(u16 crc, const u8 *buffer, size_t len)
-{
- return cpu_to_le16(bitrev16(crc16(crc, buffer, len)));
-}
-
-/**
- * atmel_ecc_checksum() - Generate 16-bit CRC as required by ATMEL ECC.
- * CRC16 verification of the count, opcode, param1, param2 and data bytes.
- * The checksum is saved in little-endian format in the least significant
- * two bytes of the command. CRC polynomial is 0x8005 and the initial register
- * value should be zero.
- *
- * @cmd : structure used for communicating with the device.
- */
-static void atmel_ecc_checksum(struct atmel_ecc_cmd *cmd)
-{
- u8 *data = &cmd->count;
- size_t len = cmd->count - CRC_SIZE;
- u16 *crc16 = (u16 *)(data + len);
-
- *crc16 = atmel_ecc_crc16(0, data, len);
-}
-
-static void atmel_ecc_init_read_cmd(struct atmel_ecc_cmd *cmd)
-{
- cmd->word_addr = COMMAND;
- cmd->opcode = OPCODE_READ;
- /*
- * Read the word from Configuration zone that contains the lock bytes
- * (UserExtra, Selector, LockValue, LockConfig).
- */
- cmd->param1 = CONFIG_ZONE;
- cmd->param2 = DEVICE_LOCK_ADDR;
- cmd->count = READ_COUNT;
-
- atmel_ecc_checksum(cmd);
-
- cmd->msecs = MAX_EXEC_TIME_READ;
- cmd->rxsize = READ_RSP_SIZE;
-}
-
-static void atmel_ecc_init_genkey_cmd(struct atmel_ecc_cmd *cmd, u16 keyid)
-{
- cmd->word_addr = COMMAND;
- cmd->count = GENKEY_COUNT;
- cmd->opcode = OPCODE_GENKEY;
- cmd->param1 = GENKEY_MODE_PRIVATE;
- /* a random private key will be generated and stored in slot keyID */
- cmd->param2 = cpu_to_le16(keyid);
-
- atmel_ecc_checksum(cmd);
-
- cmd->msecs = MAX_EXEC_TIME_GENKEY;
- cmd->rxsize = GENKEY_RSP_SIZE;
-}
-
-static int atmel_ecc_init_ecdh_cmd(struct atmel_ecc_cmd *cmd,
- struct scatterlist *pubkey)
-{
- size_t copied;
-
- cmd->word_addr = COMMAND;
- cmd->count = ECDH_COUNT;
- cmd->opcode = OPCODE_ECDH;
- cmd->param1 = ECDH_PREFIX_MODE;
- /* private key slot */
- cmd->param2 = cpu_to_le16(DATA_SLOT_2);
-
- /*
- * The device only supports NIST P256 ECC keys. The public key size will
- * always be the same. Use a macro for the key size to avoid unnecessary
- * computations.
- */
- copied = sg_copy_to_buffer(pubkey,
- sg_nents_for_len(pubkey,
- ATMEL_ECC_PUBKEY_SIZE),
- cmd->data, ATMEL_ECC_PUBKEY_SIZE);
- if (copied != ATMEL_ECC_PUBKEY_SIZE)
- return -EINVAL;
-
- atmel_ecc_checksum(cmd);
-
- cmd->msecs = MAX_EXEC_TIME_ECDH;
- cmd->rxsize = ECDH_RSP_SIZE;
-
- return 0;
-}
-
-/*
- * After wake and after execution of a command, there will be error, status, or
- * result bytes in the device's output register that can be retrieved by the
- * system. When the length of that group is four bytes, the codes returned are
- * detailed in error_list.
- */
-static int atmel_ecc_status(struct device *dev, u8 *status)
-{
- size_t err_list_len = ARRAY_SIZE(error_list);
- int i;
- u8 err_id = status[1];
-
- if (*status != STATUS_SIZE)
- return 0;
-
- if (err_id == STATUS_WAKE_SUCCESSFUL || err_id == STATUS_NOERR)
- return 0;
-
- for (i = 0; i < err_list_len; i++)
- if (error_list[i].value == err_id)
- break;
-
- /* if err_id is not in the error_list then ignore it */
- if (i != err_list_len) {
- dev_err(dev, "%02x: %s:\n", err_id, error_list[i].error_text);
- return err_id;
- }
-
- return 0;
-}
-
-static int atmel_ecc_wakeup(struct i2c_client *client)
-{
- struct atmel_ecc_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
- u8 status[STATUS_RSP_SIZE];
- int ret;
-
- /*
- * The device ignores any levels or transitions on the SCL pin when the
- * device is idle, asleep or during waking up. Don't check for error
- * when waking up the device.
- */
- i2c_master_send(client, i2c_priv->wake_token, i2c_priv->wake_token_sz);
-
- /*
- * Wait to wake the device. Typical execution times for ecdh and genkey
- * are around tens of milliseconds. Delta is chosen to 50 microseconds.
- */
- usleep_range(TWHI_MIN, TWHI_MAX);
-
- ret = i2c_master_recv(client, status, STATUS_SIZE);
- if (ret < 0)
- return ret;
-
- return atmel_ecc_status(&client->dev, status);
-}
-
-static int atmel_ecc_sleep(struct i2c_client *client)
-{
- u8 sleep = SLEEP_TOKEN;
-
- return i2c_master_send(client, &sleep, 1);
-}
-
-static void atmel_ecdh_done(struct atmel_ecc_work_data *work_data, void *areq,
+static void atmel_ecdh_done(struct atmel_i2c_work_data *work_data, void *areq,
int status)
{
struct kpp_request *req = areq;
struct atmel_ecdh_ctx *ctx = work_data->ctx;
- struct atmel_ecc_cmd *cmd = &work_data->cmd;
+ struct atmel_i2c_cmd *cmd = &work_data->cmd;
size_t copied, n_sz;
if (status)
@@ -282,82 +73,6 @@ free_work_data:
kpp_request_complete(req, status);
}
-/*
- * atmel_ecc_send_receive() - send a command to the device and receive its
- * response.
- * @client: i2c client device
- * @cmd : structure used to communicate with the device
- *
- * After the device receives a Wake token, a watchdog counter starts within the
- * device. After the watchdog timer expires, the device enters sleep mode
- * regardless of whether some I/O transmission or command execution is in
- * progress. If a command is attempted when insufficient time remains prior to
- * watchdog timer execution, the device will return the watchdog timeout error
- * code without attempting to execute the command. There is no way to reset the
- * counter other than to put the device into sleep or idle mode and then
- * wake it up again.
- */
-static int atmel_ecc_send_receive(struct i2c_client *client,
- struct atmel_ecc_cmd *cmd)
-{
- struct atmel_ecc_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
- int ret;
-
- mutex_lock(&i2c_priv->lock);
-
- ret = atmel_ecc_wakeup(client);
- if (ret)
- goto err;
-
- /* send the command */
- ret = i2c_master_send(client, (u8 *)cmd, cmd->count + WORD_ADDR_SIZE);
- if (ret < 0)
- goto err;
-
- /* delay the appropriate amount of time for command to execute */
- msleep(cmd->msecs);
-
- /* receive the response */
- ret = i2c_master_recv(client, cmd->data, cmd->rxsize);
- if (ret < 0)
- goto err;
-
- /* put the device into low-power mode */
- ret = atmel_ecc_sleep(client);
- if (ret < 0)
- goto err;
-
- mutex_unlock(&i2c_priv->lock);
- return atmel_ecc_status(&client->dev, cmd->data);
-err:
- mutex_unlock(&i2c_priv->lock);
- return ret;
-}
-
-static void atmel_ecc_work_handler(struct work_struct *work)
-{
- struct atmel_ecc_work_data *work_data =
- container_of(work, struct atmel_ecc_work_data, work);
- struct atmel_ecc_cmd *cmd = &work_data->cmd;
- struct i2c_client *client = work_data->ctx->client;
- int status;
-
- status = atmel_ecc_send_receive(client, cmd);
- work_data->cbk(work_data, work_data->areq, status);
-}
-
-static void atmel_ecc_enqueue(struct atmel_ecc_work_data *work_data,
- void (*cbk)(struct atmel_ecc_work_data *work_data,
- void *areq, int status),
- void *areq)
-{
- work_data->cbk = (void *)cbk;
- work_data->areq = areq;
-
- INIT_WORK(&work_data->work, atmel_ecc_work_handler);
- schedule_work(&work_data->work);
-}
-
static unsigned int atmel_ecdh_supported_curve(unsigned int curve_id)
{
if (curve_id == ECC_CURVE_NIST_P256)
@@ -374,7 +89,7 @@ static int atmel_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf,
unsigned int len)
{
struct atmel_ecdh_ctx *ctx = kpp_tfm_ctx(tfm);
- struct atmel_ecc_cmd *cmd;
+ struct atmel_i2c_cmd *cmd;
void *public_key;
struct ecdh params;
int ret = -ENOMEM;
@@ -412,9 +127,9 @@ static int atmel_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf,
ctx->do_fallback = false;
ctx->curve_id = params.curve_id;
- atmel_ecc_init_genkey_cmd(cmd, DATA_SLOT_2);
+ atmel_i2c_init_genkey_cmd(cmd, DATA_SLOT_2);
- ret = atmel_ecc_send_receive(ctx->client, cmd);
+ ret = atmel_i2c_send_receive(ctx->client, cmd);
if (ret)
goto free_public_key;
@@ -444,6 +159,9 @@ static int atmel_ecdh_generate_public_key(struct kpp_request *req)
return crypto_kpp_generate_public_key(req);
}
+ if (!ctx->public_key)
+ return -EINVAL;
+
/* might want less than we've got */
nbytes = min_t(size_t, ATMEL_ECC_PUBKEY_SIZE, req->dst_len);
@@ -461,7 +179,7 @@ static int atmel_ecdh_compute_shared_secret(struct kpp_request *req)
{
struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
struct atmel_ecdh_ctx *ctx = kpp_tfm_ctx(tfm);
- struct atmel_ecc_work_data *work_data;
+ struct atmel_i2c_work_data *work_data;
gfp_t gfp;
int ret;
@@ -482,12 +200,13 @@ static int atmel_ecdh_compute_shared_secret(struct kpp_request *req)
return -ENOMEM;
work_data->ctx = ctx;
+ work_data->client = ctx->client;
- ret = atmel_ecc_init_ecdh_cmd(&work_data->cmd, req->src);
+ ret = atmel_i2c_init_ecdh_cmd(&work_data->cmd, req->src);
if (ret)
goto free_work_data;
- atmel_ecc_enqueue(work_data, atmel_ecdh_done, req);
+ atmel_i2c_enqueue(work_data, atmel_ecdh_done, req);
return -EINPROGRESS;
@@ -498,7 +217,7 @@ free_work_data:
static struct i2c_client *atmel_ecc_i2c_client_alloc(void)
{
- struct atmel_ecc_i2c_client_priv *i2c_priv, *min_i2c_priv = NULL;
+ struct atmel_i2c_client_priv *i2c_priv, *min_i2c_priv = NULL;
struct i2c_client *client = ERR_PTR(-ENODEV);
int min_tfm_cnt = INT_MAX;
int tfm_cnt;
@@ -533,7 +252,7 @@ static struct i2c_client *atmel_ecc_i2c_client_alloc(void)
static void atmel_ecc_i2c_client_free(struct i2c_client *client)
{
- struct atmel_ecc_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
+ struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
atomic_dec(&i2c_priv->tfm_count);
}
@@ -604,96 +323,18 @@ static struct kpp_alg atmel_ecdh = {
},
};
-static inline size_t atmel_ecc_wake_token_sz(u32 bus_clk_rate)
-{
- u32 no_of_bits = DIV_ROUND_UP(TWLO_USEC * bus_clk_rate, USEC_PER_SEC);
-
- /* return the size of the wake_token in bytes */
- return DIV_ROUND_UP(no_of_bits, 8);
-}
-
-static int device_sanity_check(struct i2c_client *client)
-{
- struct atmel_ecc_cmd *cmd;
- int ret;
-
- cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
- if (!cmd)
- return -ENOMEM;
-
- atmel_ecc_init_read_cmd(cmd);
-
- ret = atmel_ecc_send_receive(client, cmd);
- if (ret)
- goto free_cmd;
-
- /*
- * It is vital that the Configuration, Data and OTP zones be locked
- * prior to release into the field of the system containing the device.
- * Failure to lock these zones may permit modification of any secret
- * keys and may lead to other security problems.
- */
- if (cmd->data[LOCK_CONFIG_IDX] || cmd->data[LOCK_VALUE_IDX]) {
- dev_err(&client->dev, "Configuration or Data and OTP zones are unlocked!\n");
- ret = -ENOTSUPP;
- }
-
- /* fall through */
-free_cmd:
- kfree(cmd);
- return ret;
-}
-
static int atmel_ecc_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct atmel_ecc_i2c_client_priv *i2c_priv;
- struct device *dev = &client->dev;
+ struct atmel_i2c_client_priv *i2c_priv;
int ret;
- u32 bus_clk_rate;
-
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
- dev_err(dev, "I2C_FUNC_I2C not supported\n");
- return -ENODEV;
- }
- ret = of_property_read_u32(client->adapter->dev.of_node,
- "clock-frequency", &bus_clk_rate);
- if (ret) {
- dev_err(dev, "of: failed to read clock-frequency property\n");
- return ret;
- }
-
- if (bus_clk_rate > 1000000L) {
- dev_err(dev, "%d exceeds maximum supported clock frequency (1MHz)\n",
- bus_clk_rate);
- return -EINVAL;
- }
-
- i2c_priv = devm_kmalloc(dev, sizeof(*i2c_priv), GFP_KERNEL);
- if (!i2c_priv)
- return -ENOMEM;
-
- i2c_priv->client = client;
- mutex_init(&i2c_priv->lock);
-
- /*
- * WAKE_TOKEN_MAX_SIZE was calculated for the maximum bus_clk_rate -
- * 1MHz. The previous bus_clk_rate check ensures us that wake_token_sz
- * will always be smaller than or equal to WAKE_TOKEN_MAX_SIZE.
- */
- i2c_priv->wake_token_sz = atmel_ecc_wake_token_sz(bus_clk_rate);
-
- memset(i2c_priv->wake_token, 0, sizeof(i2c_priv->wake_token));
-
- atomic_set(&i2c_priv->tfm_count, 0);
-
- i2c_set_clientdata(client, i2c_priv);
-
- ret = device_sanity_check(client);
+ ret = atmel_i2c_probe(client, id);
if (ret)
return ret;
+ i2c_priv = i2c_get_clientdata(client);
+
spin_lock(&driver_data.i2c_list_lock);
list_add_tail(&i2c_priv->i2c_client_list_node,
&driver_data.i2c_client_list);
@@ -705,10 +346,10 @@ static int atmel_ecc_probe(struct i2c_client *client,
list_del(&i2c_priv->i2c_client_list_node);
spin_unlock(&driver_data.i2c_list_lock);
- dev_err(dev, "%s alg registration failed\n",
+ dev_err(&client->dev, "%s alg registration failed\n",
atmel_ecdh.base.cra_driver_name);
} else {
- dev_info(dev, "atmel ecc algorithms registered in /proc/crypto\n");
+ dev_info(&client->dev, "atmel ecc algorithms registered in /proc/crypto\n");
}
return ret;
@@ -716,7 +357,7 @@ static int atmel_ecc_probe(struct i2c_client *client,
static int atmel_ecc_remove(struct i2c_client *client)
{
- struct atmel_ecc_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
+ struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
/* Return EBUSY if i2c client already allocated. */
if (atomic_read(&i2c_priv->tfm_count)) {
diff --git a/drivers/crypto/atmel-ecc.h b/drivers/crypto/atmel-ecc.h
deleted file mode 100644
index 643a3b947338..000000000000
--- a/drivers/crypto/atmel-ecc.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (c) 2017, Microchip Technology Inc.
- * Author: Tudor Ambarus <tudor.ambarus@microchip.com>
- */
-
-#ifndef __ATMEL_ECC_H__
-#define __ATMEL_ECC_H__
-
-#define ATMEL_ECC_PRIORITY 300
-
-#define COMMAND 0x03 /* packet function */
-#define SLEEP_TOKEN 0x01
-#define WAKE_TOKEN_MAX_SIZE 8
-
-/* Definitions of Data and Command sizes */
-#define WORD_ADDR_SIZE 1
-#define COUNT_SIZE 1
-#define CRC_SIZE 2
-#define CMD_OVERHEAD_SIZE (COUNT_SIZE + CRC_SIZE)
-
-/* size in bytes of the n prime */
-#define ATMEL_ECC_NIST_P256_N_SIZE 32
-#define ATMEL_ECC_PUBKEY_SIZE (2 * ATMEL_ECC_NIST_P256_N_SIZE)
-
-#define STATUS_RSP_SIZE 4
-#define ECDH_RSP_SIZE (32 + CMD_OVERHEAD_SIZE)
-#define GENKEY_RSP_SIZE (ATMEL_ECC_PUBKEY_SIZE + \
- CMD_OVERHEAD_SIZE)
-#define READ_RSP_SIZE (4 + CMD_OVERHEAD_SIZE)
-#define MAX_RSP_SIZE GENKEY_RSP_SIZE
-
-/**
- * atmel_ecc_cmd - structure used for communicating with the device.
- * @word_addr: indicates the function of the packet sent to the device. This
- * byte should have a value of COMMAND for normal operation.
- * @count : number of bytes to be transferred to (or from) the device.
- * @opcode : the command code.
- * @param1 : the first parameter; always present.
- * @param2 : the second parameter; always present.
- * @data : optional remaining input data. Includes a 2-byte CRC.
- * @rxsize : size of the data received from i2c client.
- * @msecs : command execution time in milliseconds
- */
-struct atmel_ecc_cmd {
- u8 word_addr;
- u8 count;
- u8 opcode;
- u8 param1;
- u16 param2;
- u8 data[MAX_RSP_SIZE];
- u8 msecs;
- u16 rxsize;
-} __packed;
-
-/* Status/Error codes */
-#define STATUS_SIZE 0x04
-#define STATUS_NOERR 0x00
-#define STATUS_WAKE_SUCCESSFUL 0x11
-
-static const struct {
- u8 value;
- const char *error_text;
-} error_list[] = {
- { 0x01, "CheckMac or Verify miscompare" },
- { 0x03, "Parse Error" },
- { 0x05, "ECC Fault" },
- { 0x0F, "Execution Error" },
- { 0xEE, "Watchdog about to expire" },
- { 0xFF, "CRC or other communication error" },
-};
-
-/* Definitions for eeprom organization */
-#define CONFIG_ZONE 0
-
-/* Definitions for Indexes common to all commands */
-#define RSP_DATA_IDX 1 /* buffer index of data in response */
-#define DATA_SLOT_2 2 /* used for ECDH private key */
-
-/* Definitions for the device lock state */
-#define DEVICE_LOCK_ADDR 0x15
-#define LOCK_VALUE_IDX (RSP_DATA_IDX + 2)
-#define LOCK_CONFIG_IDX (RSP_DATA_IDX + 3)
-
-/*
- * Wake High delay to data communication (microseconds). SDA should be stable
- * high for this entire duration.
- */
-#define TWHI_MIN 1500
-#define TWHI_MAX 1550
-
-/* Wake Low duration */
-#define TWLO_USEC 60
-
-/* Command execution time (milliseconds) */
-#define MAX_EXEC_TIME_ECDH 58
-#define MAX_EXEC_TIME_GENKEY 115
-#define MAX_EXEC_TIME_READ 1
-
-/* Command opcode */
-#define OPCODE_ECDH 0x43
-#define OPCODE_GENKEY 0x40
-#define OPCODE_READ 0x02
-
-/* Definitions for the READ Command */
-#define READ_COUNT 7
-
-/* Definitions for the GenKey Command */
-#define GENKEY_COUNT 7
-#define GENKEY_MODE_PRIVATE 0x04
-
-/* Definitions for the ECDH Command */
-#define ECDH_COUNT 71
-#define ECDH_PREFIX_MODE 0x00
-
-#endif /* __ATMEL_ECC_H__ */
diff --git a/drivers/crypto/atmel-i2c.c b/drivers/crypto/atmel-i2c.c
new file mode 100644
index 000000000000..dc876fab2882
--- /dev/null
+++ b/drivers/crypto/atmel-i2c.c
@@ -0,0 +1,364 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Microchip / Atmel ECC (I2C) driver.
+ *
+ * Copyright (c) 2017, Microchip Technology Inc.
+ * Author: Tudor Ambarus <tudor.ambarus@microchip.com>
+ */
+
+#include <linux/bitrev.h>
+#include <linux/crc16.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include "atmel-i2c.h"
+
+/**
+ * atmel_i2c_checksum() - Generate 16-bit CRC as required by ATMEL ECC.
+ * CRC16 verification of the count, opcode, param1, param2 and data bytes.
+ * The checksum is saved in little-endian format in the least significant
+ * two bytes of the command. CRC polynomial is 0x8005 and the initial register
+ * value should be zero.
+ *
+ * @cmd : structure used for communicating with the device.
+ */
+static void atmel_i2c_checksum(struct atmel_i2c_cmd *cmd)
+{
+ u8 *data = &cmd->count;
+ size_t len = cmd->count - CRC_SIZE;
+ __le16 *__crc16 = (__le16 *)(data + len);
+
+ *__crc16 = cpu_to_le16(bitrev16(crc16(0, data, len)));
+}
+
+void atmel_i2c_init_read_cmd(struct atmel_i2c_cmd *cmd)
+{
+ cmd->word_addr = COMMAND;
+ cmd->opcode = OPCODE_READ;
+ /*
+ * Read the word from Configuration zone that contains the lock bytes
+ * (UserExtra, Selector, LockValue, LockConfig).
+ */
+ cmd->param1 = CONFIG_ZONE;
+ cmd->param2 = cpu_to_le16(DEVICE_LOCK_ADDR);
+ cmd->count = READ_COUNT;
+
+ atmel_i2c_checksum(cmd);
+
+ cmd->msecs = MAX_EXEC_TIME_READ;
+ cmd->rxsize = READ_RSP_SIZE;
+}
+EXPORT_SYMBOL(atmel_i2c_init_read_cmd);
+
+void atmel_i2c_init_random_cmd(struct atmel_i2c_cmd *cmd)
+{
+ cmd->word_addr = COMMAND;
+ cmd->opcode = OPCODE_RANDOM;
+ cmd->param1 = 0;
+ cmd->param2 = 0;
+ cmd->count = RANDOM_COUNT;
+
+ atmel_i2c_checksum(cmd);
+
+ cmd->msecs = MAX_EXEC_TIME_RANDOM;
+ cmd->rxsize = RANDOM_RSP_SIZE;
+}
+EXPORT_SYMBOL(atmel_i2c_init_random_cmd);
+
+void atmel_i2c_init_genkey_cmd(struct atmel_i2c_cmd *cmd, u16 keyid)
+{
+ cmd->word_addr = COMMAND;
+ cmd->count = GENKEY_COUNT;
+ cmd->opcode = OPCODE_GENKEY;
+ cmd->param1 = GENKEY_MODE_PRIVATE;
+ /* a random private key will be generated and stored in slot keyID */
+ cmd->param2 = cpu_to_le16(keyid);
+
+ atmel_i2c_checksum(cmd);
+
+ cmd->msecs = MAX_EXEC_TIME_GENKEY;
+ cmd->rxsize = GENKEY_RSP_SIZE;
+}
+EXPORT_SYMBOL(atmel_i2c_init_genkey_cmd);
+
+int atmel_i2c_init_ecdh_cmd(struct atmel_i2c_cmd *cmd,
+ struct scatterlist *pubkey)
+{
+ size_t copied;
+
+ cmd->word_addr = COMMAND;
+ cmd->count = ECDH_COUNT;
+ cmd->opcode = OPCODE_ECDH;
+ cmd->param1 = ECDH_PREFIX_MODE;
+ /* private key slot */
+ cmd->param2 = cpu_to_le16(DATA_SLOT_2);
+
+ /*
+ * The device only supports NIST P256 ECC keys. The public key size will
+ * always be the same. Use a macro for the key size to avoid unnecessary
+ * computations.
+ */
+ copied = sg_copy_to_buffer(pubkey,
+ sg_nents_for_len(pubkey,
+ ATMEL_ECC_PUBKEY_SIZE),
+ cmd->data, ATMEL_ECC_PUBKEY_SIZE);
+ if (copied != ATMEL_ECC_PUBKEY_SIZE)
+ return -EINVAL;
+
+ atmel_i2c_checksum(cmd);
+
+ cmd->msecs = MAX_EXEC_TIME_ECDH;
+ cmd->rxsize = ECDH_RSP_SIZE;
+
+ return 0;
+}
+EXPORT_SYMBOL(atmel_i2c_init_ecdh_cmd);
+
+/*
+ * After wake and after execution of a command, there will be error, status, or
+ * result bytes in the device's output register that can be retrieved by the
+ * system. When the length of that group is four bytes, the codes returned are
+ * detailed in error_list.
+ */
+static int atmel_i2c_status(struct device *dev, u8 *status)
+{
+ size_t err_list_len = ARRAY_SIZE(error_list);
+ int i;
+ u8 err_id = status[1];
+
+ if (*status != STATUS_SIZE)
+ return 0;
+
+ if (err_id == STATUS_WAKE_SUCCESSFUL || err_id == STATUS_NOERR)
+ return 0;
+
+ for (i = 0; i < err_list_len; i++)
+ if (error_list[i].value == err_id)
+ break;
+
+ /* if err_id is not in the error_list then ignore it */
+ if (i != err_list_len) {
+ dev_err(dev, "%02x: %s:\n", err_id, error_list[i].error_text);
+ return err_id;
+ }
+
+ return 0;
+}
+
+static int atmel_i2c_wakeup(struct i2c_client *client)
+{
+ struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
+ u8 status[STATUS_RSP_SIZE];
+ int ret;
+
+ /*
+ * The device ignores any levels or transitions on the SCL pin when the
+ * device is idle, asleep or during waking up. Don't check for error
+ * when waking up the device.
+ */
+ i2c_master_send(client, i2c_priv->wake_token, i2c_priv->wake_token_sz);
+
+ /*
+ * Wait to wake the device. Typical execution times for ecdh and genkey
+ * are around tens of milliseconds. Delta is chosen to 50 microseconds.
+ */
+ usleep_range(TWHI_MIN, TWHI_MAX);
+
+ ret = i2c_master_recv(client, status, STATUS_SIZE);
+ if (ret < 0)
+ return ret;
+
+ return atmel_i2c_status(&client->dev, status);
+}
+
+static int atmel_i2c_sleep(struct i2c_client *client)
+{
+ u8 sleep = SLEEP_TOKEN;
+
+ return i2c_master_send(client, &sleep, 1);
+}
+
+/*
+ * atmel_i2c_send_receive() - send a command to the device and receive its
+ * response.
+ * @client: i2c client device
+ * @cmd : structure used to communicate with the device
+ *
+ * After the device receives a Wake token, a watchdog counter starts within the
+ * device. After the watchdog timer expires, the device enters sleep mode
+ * regardless of whether some I/O transmission or command execution is in
+ * progress. If a command is attempted when insufficient time remains prior to
+ * watchdog timer execution, the device will return the watchdog timeout error
+ * code without attempting to execute the command. There is no way to reset the
+ * counter other than to put the device into sleep or idle mode and then
+ * wake it up again.
+ */
+int atmel_i2c_send_receive(struct i2c_client *client, struct atmel_i2c_cmd *cmd)
+{
+ struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
+ int ret;
+
+ mutex_lock(&i2c_priv->lock);
+
+ ret = atmel_i2c_wakeup(client);
+ if (ret)
+ goto err;
+
+ /* send the command */
+ ret = i2c_master_send(client, (u8 *)cmd, cmd->count + WORD_ADDR_SIZE);
+ if (ret < 0)
+ goto err;
+
+ /* delay the appropriate amount of time for command to execute */
+ msleep(cmd->msecs);
+
+ /* receive the response */
+ ret = i2c_master_recv(client, cmd->data, cmd->rxsize);
+ if (ret < 0)
+ goto err;
+
+ /* put the device into low-power mode */
+ ret = atmel_i2c_sleep(client);
+ if (ret < 0)
+ goto err;
+
+ mutex_unlock(&i2c_priv->lock);
+ return atmel_i2c_status(&client->dev, cmd->data);
+err:
+ mutex_unlock(&i2c_priv->lock);
+ return ret;
+}
+EXPORT_SYMBOL(atmel_i2c_send_receive);
+
+static void atmel_i2c_work_handler(struct work_struct *work)
+{
+ struct atmel_i2c_work_data *work_data =
+ container_of(work, struct atmel_i2c_work_data, work);
+ struct atmel_i2c_cmd *cmd = &work_data->cmd;
+ struct i2c_client *client = work_data->client;
+ int status;
+
+ status = atmel_i2c_send_receive(client, cmd);
+ work_data->cbk(work_data, work_data->areq, status);
+}
+
+void atmel_i2c_enqueue(struct atmel_i2c_work_data *work_data,
+ void (*cbk)(struct atmel_i2c_work_data *work_data,
+ void *areq, int status),
+ void *areq)
+{
+ work_data->cbk = (void *)cbk;
+ work_data->areq = areq;
+
+ INIT_WORK(&work_data->work, atmel_i2c_work_handler);
+ schedule_work(&work_data->work);
+}
+EXPORT_SYMBOL(atmel_i2c_enqueue);
+
+static inline size_t atmel_i2c_wake_token_sz(u32 bus_clk_rate)
+{
+ u32 no_of_bits = DIV_ROUND_UP(TWLO_USEC * bus_clk_rate, USEC_PER_SEC);
+
+ /* return the size of the wake_token in bytes */
+ return DIV_ROUND_UP(no_of_bits, 8);
+}
+
+static int device_sanity_check(struct i2c_client *client)
+{
+ struct atmel_i2c_cmd *cmd;
+ int ret;
+
+ cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+ atmel_i2c_init_read_cmd(cmd);
+
+ ret = atmel_i2c_send_receive(client, cmd);
+ if (ret)
+ goto free_cmd;
+
+ /*
+ * It is vital that the Configuration, Data and OTP zones be locked
+ * prior to release into the field of the system containing the device.
+ * Failure to lock these zones may permit modification of any secret
+ * keys and may lead to other security problems.
+ */
+ if (cmd->data[LOCK_CONFIG_IDX] || cmd->data[LOCK_VALUE_IDX]) {
+ dev_err(&client->dev, "Configuration or Data and OTP zones are unlocked!\n");
+ ret = -ENOTSUPP;
+ }
+
+ /* fall through */
+free_cmd:
+ kfree(cmd);
+ return ret;
+}
+
+int atmel_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct atmel_i2c_client_priv *i2c_priv;
+ struct device *dev = &client->dev;
+ int ret;
+ u32 bus_clk_rate;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(dev, "I2C_FUNC_I2C not supported\n");
+ return -ENODEV;
+ }
+
+ bus_clk_rate = i2c_acpi_find_bus_speed(&client->adapter->dev);
+ if (!bus_clk_rate) {
+ ret = device_property_read_u32(&client->adapter->dev,
+ "clock-frequency", &bus_clk_rate);
+ if (ret) {
+ dev_err(dev, "failed to read clock-frequency property\n");
+ return ret;
+ }
+ }
+
+ if (bus_clk_rate > 1000000L) {
+ dev_err(dev, "%d exceeds maximum supported clock frequency (1MHz)\n",
+ bus_clk_rate);
+ return -EINVAL;
+ }
+
+ i2c_priv = devm_kmalloc(dev, sizeof(*i2c_priv), GFP_KERNEL);
+ if (!i2c_priv)
+ return -ENOMEM;
+
+ i2c_priv->client = client;
+ mutex_init(&i2c_priv->lock);
+
+ /*
+ * WAKE_TOKEN_MAX_SIZE was calculated for the maximum bus_clk_rate -
+ * 1MHz. The previous bus_clk_rate check ensures us that wake_token_sz
+ * will always be smaller than or equal to WAKE_TOKEN_MAX_SIZE.
+ */
+ i2c_priv->wake_token_sz = atmel_i2c_wake_token_sz(bus_clk_rate);
+
+ memset(i2c_priv->wake_token, 0, sizeof(i2c_priv->wake_token));
+
+ atomic_set(&i2c_priv->tfm_count, 0);
+
+ i2c_set_clientdata(client, i2c_priv);
+
+ ret = device_sanity_check(client);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+EXPORT_SYMBOL(atmel_i2c_probe);
+
+MODULE_AUTHOR("Tudor Ambarus <tudor.ambarus@microchip.com>");
+MODULE_DESCRIPTION("Microchip / Atmel ECC (I2C) driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/crypto/atmel-i2c.h b/drivers/crypto/atmel-i2c.h
new file mode 100644
index 000000000000..21860b99c3e3
--- /dev/null
+++ b/drivers/crypto/atmel-i2c.h
@@ -0,0 +1,197 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2017, Microchip Technology Inc.
+ * Author: Tudor Ambarus <tudor.ambarus@microchip.com>
+ */
+
+#ifndef __ATMEL_I2C_H__
+#define __ATMEL_I2C_H__
+
+#include <linux/hw_random.h>
+#include <linux/types.h>
+
+#define ATMEL_ECC_PRIORITY 300
+
+#define COMMAND 0x03 /* packet function */
+#define SLEEP_TOKEN 0x01
+#define WAKE_TOKEN_MAX_SIZE 8
+
+/* Definitions of Data and Command sizes */
+#define WORD_ADDR_SIZE 1
+#define COUNT_SIZE 1
+#define CRC_SIZE 2
+#define CMD_OVERHEAD_SIZE (COUNT_SIZE + CRC_SIZE)
+
+/* size in bytes of the n prime */
+#define ATMEL_ECC_NIST_P256_N_SIZE 32
+#define ATMEL_ECC_PUBKEY_SIZE (2 * ATMEL_ECC_NIST_P256_N_SIZE)
+
+#define STATUS_RSP_SIZE 4
+#define ECDH_RSP_SIZE (32 + CMD_OVERHEAD_SIZE)
+#define GENKEY_RSP_SIZE (ATMEL_ECC_PUBKEY_SIZE + \
+ CMD_OVERHEAD_SIZE)
+#define READ_RSP_SIZE (4 + CMD_OVERHEAD_SIZE)
+#define RANDOM_RSP_SIZE (32 + CMD_OVERHEAD_SIZE)
+#define MAX_RSP_SIZE GENKEY_RSP_SIZE
+
+/**
+ * atmel_i2c_cmd - structure used for communicating with the device.
+ * @word_addr: indicates the function of the packet sent to the device. This
+ * byte should have a value of COMMAND for normal operation.
+ * @count : number of bytes to be transferred to (or from) the device.
+ * @opcode : the command code.
+ * @param1 : the first parameter; always present.
+ * @param2 : the second parameter; always present.
+ * @data : optional remaining input data. Includes a 2-byte CRC.
+ * @rxsize : size of the data received from i2c client.
+ * @msecs : command execution time in milliseconds
+ */
+struct atmel_i2c_cmd {
+ u8 word_addr;
+ u8 count;
+ u8 opcode;
+ u8 param1;
+ __le16 param2;
+ u8 data[MAX_RSP_SIZE];
+ u8 msecs;
+ u16 rxsize;
+} __packed;
+
+/* Status/Error codes */
+#define STATUS_SIZE 0x04
+#define STATUS_NOERR 0x00
+#define STATUS_WAKE_SUCCESSFUL 0x11
+
+static const struct {
+ u8 value;
+ const char *error_text;
+} error_list[] = {
+ { 0x01, "CheckMac or Verify miscompare" },
+ { 0x03, "Parse Error" },
+ { 0x05, "ECC Fault" },
+ { 0x0F, "Execution Error" },
+ { 0xEE, "Watchdog about to expire" },
+ { 0xFF, "CRC or other communication error" },
+};
+
+/* Definitions for eeprom organization */
+#define CONFIG_ZONE 0
+
+/* Definitions for Indexes common to all commands */
+#define RSP_DATA_IDX 1 /* buffer index of data in response */
+#define DATA_SLOT_2 2 /* used for ECDH private key */
+
+/* Definitions for the device lock state */
+#define DEVICE_LOCK_ADDR 0x15
+#define LOCK_VALUE_IDX (RSP_DATA_IDX + 2)
+#define LOCK_CONFIG_IDX (RSP_DATA_IDX + 3)
+
+/*
+ * Wake High delay to data communication (microseconds). SDA should be stable
+ * high for this entire duration.
+ */
+#define TWHI_MIN 1500
+#define TWHI_MAX 1550
+
+/* Wake Low duration */
+#define TWLO_USEC 60
+
+/* Command execution time (milliseconds) */
+#define MAX_EXEC_TIME_ECDH 58
+#define MAX_EXEC_TIME_GENKEY 115
+#define MAX_EXEC_TIME_READ 1
+#define MAX_EXEC_TIME_RANDOM 50
+
+/* Command opcode */
+#define OPCODE_ECDH 0x43
+#define OPCODE_GENKEY 0x40
+#define OPCODE_READ 0x02
+#define OPCODE_RANDOM 0x1b
+
+/* Definitions for the READ Command */
+#define READ_COUNT 7
+
+/* Definitions for the RANDOM Command */
+#define RANDOM_COUNT 7
+
+/* Definitions for the GenKey Command */
+#define GENKEY_COUNT 7
+#define GENKEY_MODE_PRIVATE 0x04
+
+/* Definitions for the ECDH Command */
+#define ECDH_COUNT 71
+#define ECDH_PREFIX_MODE 0x00
+
+/* Used for binding tfm objects to i2c clients. */
+struct atmel_ecc_driver_data {
+ struct list_head i2c_client_list;
+ spinlock_t i2c_list_lock;
+} ____cacheline_aligned;
+
+/**
+ * atmel_i2c_client_priv - i2c_client private data
+ * @client : pointer to i2c client device
+ * @i2c_client_list_node: part of i2c_client_list
+ * @lock : lock for sending i2c commands
+ * @wake_token : wake token array of zeros
+ * @wake_token_sz : size in bytes of the wake_token
+ * @tfm_count : number of active crypto transformations on i2c client
+ *
+ * Reads and writes from/to the i2c client are sequential. The first byte
+ * transmitted to the device is treated as the byte size. Any attempt to send
+ * more than this number of bytes will cause the device to not ACK those bytes.
+ * After the host writes a single command byte to the input buffer, reads are
+ * prohibited until after the device completes command execution. Use a mutex
+ * when sending i2c commands.
+ */
+struct atmel_i2c_client_priv {
+ struct i2c_client *client;
+ struct list_head i2c_client_list_node;
+ struct mutex lock;
+ u8 wake_token[WAKE_TOKEN_MAX_SIZE];
+ size_t wake_token_sz;
+ atomic_t tfm_count ____cacheline_aligned;
+ struct hwrng hwrng;
+};
+
+/**
+ * atmel_i2c_work_data - data structure representing the work
+ * @ctx : transformation context.
+ * @cbk : pointer to a callback function to be invoked upon completion of this
+ * request. This has the form:
+ * callback(struct atmel_i2c_work_data *work_data, void *areq, u8 status)
+ * where:
+ * @work_data: data structure representing the work
+ * @areq : optional pointer to an argument passed with the original
+ * request.
+ * @status : status returned from the i2c client device or i2c error.
+ * @areq: optional pointer to a user argument for use at callback time.
+ * @work: describes the task to be executed.
+ * @cmd : structure used for communicating with the device.
+ */
+struct atmel_i2c_work_data {
+ void *ctx;
+ struct i2c_client *client;
+ void (*cbk)(struct atmel_i2c_work_data *work_data, void *areq,
+ int status);
+ void *areq;
+ struct work_struct work;
+ struct atmel_i2c_cmd cmd;
+};
+
+int atmel_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id);
+
+void atmel_i2c_enqueue(struct atmel_i2c_work_data *work_data,
+ void (*cbk)(struct atmel_i2c_work_data *work_data,
+ void *areq, int status),
+ void *areq);
+
+int atmel_i2c_send_receive(struct i2c_client *client, struct atmel_i2c_cmd *cmd);
+
+void atmel_i2c_init_read_cmd(struct atmel_i2c_cmd *cmd);
+void atmel_i2c_init_random_cmd(struct atmel_i2c_cmd *cmd);
+void atmel_i2c_init_genkey_cmd(struct atmel_i2c_cmd *cmd, u16 keyid);
+int atmel_i2c_init_ecdh_cmd(struct atmel_i2c_cmd *cmd,
+ struct scatterlist *pubkey);
+
+#endif /* __ATMEL_I2C_H__ */
diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c
new file mode 100644
index 000000000000..ea0d2068ea4f
--- /dev/null
+++ b/drivers/crypto/atmel-sha204a.c
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Microchip / Atmel SHA204A (I2C) driver.
+ *
+ * Copyright (c) 2019 Linaro, Ltd. <ard.biesheuvel@linaro.org>
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include "atmel-i2c.h"
+
+static void atmel_sha204a_rng_done(struct atmel_i2c_work_data *work_data,
+ void *areq, int status)
+{
+ struct atmel_i2c_client_priv *i2c_priv = work_data->ctx;
+ struct hwrng *rng = areq;
+
+ if (status)
+ dev_warn_ratelimited(&i2c_priv->client->dev,
+ "i2c transaction failed (%d)\n",
+ status);
+
+ rng->priv = (unsigned long)work_data;
+ atomic_dec(&i2c_priv->tfm_count);
+}
+
+static int atmel_sha204a_rng_read_nonblocking(struct hwrng *rng, void *data,
+ size_t max)
+{
+ struct atmel_i2c_client_priv *i2c_priv;
+ struct atmel_i2c_work_data *work_data;
+
+ i2c_priv = container_of(rng, struct atmel_i2c_client_priv, hwrng);
+
+ /* keep maximum 1 asynchronous read in flight at any time */
+ if (!atomic_add_unless(&i2c_priv->tfm_count, 1, 1))
+ return 0;
+
+ if (rng->priv) {
+ work_data = (struct atmel_i2c_work_data *)rng->priv;
+ max = min(sizeof(work_data->cmd.data), max);
+ memcpy(data, &work_data->cmd.data, max);
+ rng->priv = 0;
+ } else {
+ work_data = kmalloc(sizeof(*work_data), GFP_ATOMIC);
+ if (!work_data)
+ return -ENOMEM;
+
+ work_data->ctx = i2c_priv;
+ work_data->client = i2c_priv->client;
+
+ max = 0;
+ }
+
+ atmel_i2c_init_random_cmd(&work_data->cmd);
+ atmel_i2c_enqueue(work_data, atmel_sha204a_rng_done, rng);
+
+ return max;
+}
+
+static int atmel_sha204a_rng_read(struct hwrng *rng, void *data, size_t max,
+ bool wait)
+{
+ struct atmel_i2c_client_priv *i2c_priv;
+ struct atmel_i2c_cmd cmd;
+ int ret;
+
+ if (!wait)
+ return atmel_sha204a_rng_read_nonblocking(rng, data, max);
+
+ i2c_priv = container_of(rng, struct atmel_i2c_client_priv, hwrng);
+
+ atmel_i2c_init_random_cmd(&cmd);
+
+ ret = atmel_i2c_send_receive(i2c_priv->client, &cmd);
+ if (ret)
+ return ret;
+
+ max = min(sizeof(cmd.data), max);
+ memcpy(data, cmd.data, max);
+
+ return max;
+}
+
+static int atmel_sha204a_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct atmel_i2c_client_priv *i2c_priv;
+ int ret;
+
+ ret = atmel_i2c_probe(client, id);
+ if (ret)
+ return ret;
+
+ i2c_priv = i2c_get_clientdata(client);
+
+ memset(&i2c_priv->hwrng, 0, sizeof(i2c_priv->hwrng));
+
+ i2c_priv->hwrng.name = dev_name(&client->dev);
+ i2c_priv->hwrng.read = atmel_sha204a_rng_read;
+ i2c_priv->hwrng.quality = 1024;
+
+ ret = hwrng_register(&i2c_priv->hwrng);
+ if (ret)
+ dev_warn(&client->dev, "failed to register RNG (%d)\n", ret);
+
+ return ret;
+}
+
+static int atmel_sha204a_remove(struct i2c_client *client)
+{
+ struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
+
+ if (atomic_read(&i2c_priv->tfm_count)) {
+ dev_err(&client->dev, "Device is busy\n");
+ return -EBUSY;
+ }
+
+ if (i2c_priv->hwrng.priv)
+ kfree((void *)i2c_priv->hwrng.priv);
+ hwrng_unregister(&i2c_priv->hwrng);
+
+ return 0;
+}
+
+static const struct of_device_id atmel_sha204a_dt_ids[] = {
+ { .compatible = "atmel,atsha204a", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, atmel_sha204a_dt_ids);
+
+static const struct i2c_device_id atmel_sha204a_id[] = {
+ { "atsha204a", 0 },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(i2c, atmel_sha204a_id);
+
+static struct i2c_driver atmel_sha204a_driver = {
+ .probe = atmel_sha204a_probe,
+ .remove = atmel_sha204a_remove,
+ .id_table = atmel_sha204a_id,
+
+ .driver.name = "atmel-sha204a",
+ .driver.of_match_table = of_match_ptr(atmel_sha204a_dt_ids),
+};
+
+static int __init atmel_sha204a_init(void)
+{
+ return i2c_add_driver(&atmel_sha204a_driver);
+}
+
+static void __exit atmel_sha204a_exit(void)
+{
+ flush_scheduled_work();
+ i2c_del_driver(&atmel_sha204a_driver);
+}
+
+module_init(atmel_sha204a_init);
+module_exit(atmel_sha204a_exit);
+
+MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/crypto/bcm/cipher.c b/drivers/crypto/bcm/cipher.c
index 25f8d3913ceb..869602fcfd96 100644
--- a/drivers/crypto/bcm/cipher.c
+++ b/drivers/crypto/bcm/cipher.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2016 Broadcom
- *
- * 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 (the "GPL").
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License version 2 (GPLv2) for more details.
- *
- * You should have received a copy of the GNU General Public License
- * version 2 (GPLv2) along with this source code.
*/
#include <linux/err.h>
@@ -96,7 +85,7 @@ MODULE_PARM_DESC(aead_pri, "Priority for AEAD algos");
* 0x70 - ring 2
* 0x78 - ring 3
*/
-char BCMHEADER[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28 };
+static char BCMHEADER[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28 };
/*
* Some SPU hw does not use BCM header on SPU messages. So BCM_HDR_LEN
* is set dynamically after reading SPU type from device tree.
@@ -2094,7 +2083,7 @@ static int __ahash_init(struct ahash_request *req)
* Return: true if incremental hashing is not supported
* false otherwise
*/
-bool spu_no_incr_hash(struct iproc_ctx_s *ctx)
+static bool spu_no_incr_hash(struct iproc_ctx_s *ctx)
{
struct spu_hw *spu = &iproc_priv.spu;
@@ -4820,7 +4809,7 @@ static int spu_dt_read(struct platform_device *pdev)
return 0;
}
-int bcm_spu_probe(struct platform_device *pdev)
+static int bcm_spu_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct spu_hw *spu = &iproc_priv.spu;
@@ -4864,7 +4853,7 @@ failure:
return err;
}
-int bcm_spu_remove(struct platform_device *pdev)
+static int bcm_spu_remove(struct platform_device *pdev)
{
int i;
struct device *dev = &pdev->dev;
diff --git a/drivers/crypto/bcm/cipher.h b/drivers/crypto/bcm/cipher.h
index f6da49758954..766452b24d0a 100644
--- a/drivers/crypto/bcm/cipher.h
+++ b/drivers/crypto/bcm/cipher.h
@@ -1,17 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2016 Broadcom
- *
- * 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 (the "GPL").
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License version 2 (GPLv2) for more details.
- *
- * You should have received a copy of the GNU General Public License
- * version 2 (GPLv2) along with this source code.
*/
#ifndef _CIPHER_H
diff --git a/drivers/crypto/bcm/spu.c b/drivers/crypto/bcm/spu.c
index 2baf6d7f2c1d..e7562e9bf396 100644
--- a/drivers/crypto/bcm/spu.c
+++ b/drivers/crypto/bcm/spu.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2016 Broadcom
- *
- * 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 (the "GPL").
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License version 2 (GPLv2) for more details.
- *
- * You should have received a copy of the GNU General Public License
- * version 2 (GPLv2) along with this source code.
*/
#include <linux/kernel.h>
diff --git a/drivers/crypto/bcm/spu.h b/drivers/crypto/bcm/spu.h
index aa6fc38db263..b247bc5b9354 100644
--- a/drivers/crypto/bcm/spu.h
+++ b/drivers/crypto/bcm/spu.h
@@ -1,17 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2016 Broadcom
- *
- * 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 (the "GPL").
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License version 2 (GPLv2) for more details.
- *
- * You should have received a copy of the GNU General Public License
- * version 2 (GPLv2) along with this source code.
*/
/*
diff --git a/drivers/crypto/bcm/spu2.c b/drivers/crypto/bcm/spu2.c
index bf7ac621c591..2add51024575 100644
--- a/drivers/crypto/bcm/spu2.c
+++ b/drivers/crypto/bcm/spu2.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2016 Broadcom
- *
- * 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 (the "GPL").
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License version 2 (GPLv2) for more details.
- *
- * You should have received a copy of the GNU General Public License
- * version 2 (GPLv2) along with this source code.
*/
/*
@@ -49,21 +38,21 @@ enum spu2_proto_sel {
SPU2_DTLS_AEAD = 10
};
-char *spu2_cipher_type_names[] = { "None", "AES128", "AES192", "AES256",
+static char *spu2_cipher_type_names[] = { "None", "AES128", "AES192", "AES256",
"DES", "3DES"
};
-char *spu2_cipher_mode_names[] = { "ECB", "CBC", "CTR", "CFB", "OFB", "XTS",
- "CCM", "GCM"
+static char *spu2_cipher_mode_names[] = { "ECB", "CBC", "CTR", "CFB", "OFB",
+ "XTS", "CCM", "GCM"
};
-char *spu2_hash_type_names[] = { "None", "AES128", "AES192", "AES256",
+static char *spu2_hash_type_names[] = { "None", "AES128", "AES192", "AES256",
"Reserved", "Reserved", "MD5", "SHA1", "SHA224", "SHA256", "SHA384",
"SHA512", "SHA512/224", "SHA512/256", "SHA3-224", "SHA3-256",
"SHA3-384", "SHA3-512"
};
-char *spu2_hash_mode_names[] = { "CMAC", "CBC-MAC", "XCBC-MAC", "HMAC",
+static char *spu2_hash_mode_names[] = { "CMAC", "CBC-MAC", "XCBC-MAC", "HMAC",
"Rabin", "CCM", "GCM", "Reserved"
};
diff --git a/drivers/crypto/bcm/spu2.h b/drivers/crypto/bcm/spu2.h
index ab1f59934828..03af6c38df7f 100644
--- a/drivers/crypto/bcm/spu2.h
+++ b/drivers/crypto/bcm/spu2.h
@@ -1,17 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2016 Broadcom
- *
- * 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 (the "GPL").
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License version 2 (GPLv2) for more details.
- *
- * You should have received a copy of the GNU General Public License
- * version 2 (GPLv2) along with this source code.
*/
/*
diff --git a/drivers/crypto/bcm/spum.h b/drivers/crypto/bcm/spum.h
index d0a5b5828638..6116ad1dd26e 100644
--- a/drivers/crypto/bcm/spum.h
+++ b/drivers/crypto/bcm/spum.h
@@ -1,17 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2016 Broadcom
- *
- * 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 (the "GPL").
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License version 2 (GPLv2) for more details.
- *
- * You should have received a copy of the GNU General Public License
- * version 2 (GPLv2) along with this source code.
*/
/*
diff --git a/drivers/crypto/bcm/util.c b/drivers/crypto/bcm/util.c
index 91ec56399d84..cd7504101acd 100644
--- a/drivers/crypto/bcm/util.c
+++ b/drivers/crypto/bcm/util.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2016 Broadcom
- *
- * 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 (the "GPL").
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License version 2 (GPLv2) for more details.
- *
- * You should have received a copy of the GNU General Public License
- * version 2 (GPLv2) along with this source code.
*/
#include <linux/debugfs.h>
diff --git a/drivers/crypto/bcm/util.h b/drivers/crypto/bcm/util.h
index 15c60356518a..a89b2b9c1f52 100644
--- a/drivers/crypto/bcm/util.h
+++ b/drivers/crypto/bcm/util.h
@@ -1,17 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2016 Broadcom
- *
- * 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 (the "GPL").
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License version 2 (GPLv2) for more details.
- *
- * You should have received a copy of the GNU General Public License
- * version 2 (GPLv2) along with this source code.
*/
#ifndef _UTIL_H
diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig
index 577c9844b322..3720ddabb507 100644
--- a/drivers/crypto/caam/Kconfig
+++ b/drivers/crypto/caam/Kconfig
@@ -2,6 +2,12 @@
config CRYPTO_DEV_FSL_CAAM_COMMON
tristate
+config CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC
+ tristate
+
+config CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC
+ tristate
+
config CRYPTO_DEV_FSL_CAAM
tristate "Freescale CAAM-Multicore platform driver backend"
depends on FSL_SOC || ARCH_MXC || ARCH_LAYERSCAPE
@@ -25,7 +31,7 @@ config CRYPTO_DEV_FSL_CAAM_DEBUG
Selecting this will enable printing of various debug
information in the CAAM driver.
-config CRYPTO_DEV_FSL_CAAM_JR
+menuconfig CRYPTO_DEV_FSL_CAAM_JR
tristate "Freescale CAAM Job Ring driver backend"
default y
help
@@ -86,8 +92,9 @@ config CRYPTO_DEV_FSL_CAAM_INTC_TIME_THLD
threshold. Range is 1-65535.
config CRYPTO_DEV_FSL_CAAM_CRYPTO_API
- tristate "Register algorithm implementations with the Crypto API"
+ bool "Register algorithm implementations with the Crypto API"
default y
+ select CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC
select CRYPTO_AEAD
select CRYPTO_AUTHENC
select CRYPTO_BLKCIPHER
@@ -97,13 +104,11 @@ config CRYPTO_DEV_FSL_CAAM_CRYPTO_API
scatterlist crypto API (such as the linux native IPSec
stack) to the SEC4 via job ring.
- To compile this as a module, choose M here: the module
- will be called caamalg.
-
config CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI
- tristate "Queue Interface as Crypto API backend"
+ bool "Queue Interface as Crypto API backend"
depends on FSL_DPAA && NET
default y
+ select CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC
select CRYPTO_AUTHENC
select CRYPTO_BLKCIPHER
help
@@ -114,33 +119,26 @@ config CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI
assigned to the kernel should also be more than the number of
job rings.
- To compile this as a module, choose M here: the module
- will be called caamalg_qi.
-
config CRYPTO_DEV_FSL_CAAM_AHASH_API
- tristate "Register hash algorithm implementations with Crypto API"
+ bool "Register hash algorithm implementations with Crypto API"
default y
+ select CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC
select CRYPTO_HASH
help
Selecting this will offload ahash for users of the
scatterlist crypto API to the SEC4 via job ring.
- To compile this as a module, choose M here: the module
- will be called caamhash.
-
config CRYPTO_DEV_FSL_CAAM_PKC_API
- tristate "Register public key cryptography implementations with Crypto API"
+ bool "Register public key cryptography implementations with Crypto API"
default y
select CRYPTO_RSA
help
Selecting this will allow SEC Public key support for RSA.
Supported cryptographic primitives: encryption, decryption,
signature and verification.
- To compile this as a module, choose M here: the module
- will be called caam_pkc.
config CRYPTO_DEV_FSL_CAAM_RNG_API
- tristate "Register caam device for hwrng API"
+ bool "Register caam device for hwrng API"
default y
select CRYPTO_RNG
select HW_RANDOM
@@ -148,9 +146,6 @@ config CRYPTO_DEV_FSL_CAAM_RNG_API
Selecting this will register the SEC4 hardware rng to
the hw_random API for suppying the kernel entropy pool.
- To compile this as a module, choose M here: the module
- will be called caamrng.
-
endif # CRYPTO_DEV_FSL_CAAM_JR
endif # CRYPTO_DEV_FSL_CAAM
@@ -160,6 +155,8 @@ config CRYPTO_DEV_FSL_DPAA2_CAAM
depends on FSL_MC_DPIO
depends on NETDEVICES
select CRYPTO_DEV_FSL_CAAM_COMMON
+ select CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC
+ select CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC
select CRYPTO_BLKCIPHER
select CRYPTO_AUTHENC
select CRYPTO_AEAD
@@ -171,12 +168,3 @@ config CRYPTO_DEV_FSL_DPAA2_CAAM
To compile this as a module, choose M here: the module
will be called dpaa2_caam.
-
-config CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC
- def_tristate (CRYPTO_DEV_FSL_CAAM_CRYPTO_API || \
- CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI || \
- CRYPTO_DEV_FSL_DPAA2_CAAM)
-
-config CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC
- def_tristate (CRYPTO_DEV_FSL_CAAM_AHASH_API || \
- CRYPTO_DEV_FSL_DPAA2_CAAM)
diff --git a/drivers/crypto/caam/Makefile b/drivers/crypto/caam/Makefile
index 7bbfd06a11ff..9ab4e81ea21e 100644
--- a/drivers/crypto/caam/Makefile
+++ b/drivers/crypto/caam/Makefile
@@ -11,20 +11,20 @@ ccflags-y += -DVERSION=\"\"
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_COMMON) += error.o
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam.o
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_JR) += caam_jr.o
-obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API) += caamalg.o
-obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) += caamalg_qi.o
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC) += caamalg_desc.o
-obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API) += caamhash.o
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC) += caamhash_desc.o
-obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API) += caamrng.o
-obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API) += caam_pkc.o
-caam-objs := ctrl.o
-caam_jr-objs := jr.o key_gen.o
-caam_pkc-y := caampkc.o pkc_desc.o
+caam-y := ctrl.o
+caam_jr-y := jr.o key_gen.o
+caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API) += caamalg.o
+caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) += caamalg_qi.o
+caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API) += caamhash.o
+caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API) += caamrng.o
+caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API) += caampkc.o pkc_desc.o
+
+caam-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) += qi.o
ifneq ($(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI),)
ccflags-y += -DCONFIG_CAAM_QI
- caam-objs += qi.o
endif
obj-$(CONFIG_CRYPTO_DEV_FSL_DPAA2_CAAM) += dpaa2_caam.o
diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c
index c0ece44f303b..43f18253e5b6 100644
--- a/drivers/crypto/caam/caamalg.c
+++ b/drivers/crypto/caam/caamalg.c
@@ -77,13 +77,6 @@
#define DESC_MAX_USED_BYTES (CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN)
#define DESC_MAX_USED_LEN (DESC_MAX_USED_BYTES / CAAM_CMD_SZ)
-#ifdef DEBUG
-/* for print_hex_dumps with line references */
-#define debug(format, arg...) printk(format, arg)
-#else
-#define debug(format, arg...)
-#endif
-
struct caam_alg_entry {
int class1_alg_type;
int class2_alg_type;
@@ -583,13 +576,11 @@ static int aead_setkey(struct crypto_aead *aead,
if (crypto_authenc_extractkeys(&keys, key, keylen) != 0)
goto badkey;
-#ifdef DEBUG
- printk(KERN_ERR "keylen %d enckeylen %d authkeylen %d\n",
+ dev_dbg(jrdev, "keylen %d enckeylen %d authkeylen %d\n",
keys.authkeylen + keys.enckeylen, keys.enckeylen,
keys.authkeylen);
- print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
-#endif
+ print_hex_dump_debug("key in @"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
/*
* If DKP is supported, use it in the shared descriptor to generate
@@ -623,11 +614,10 @@ static int aead_setkey(struct crypto_aead *aead,
memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey, keys.enckeylen);
dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->adata.keylen_pad +
keys.enckeylen, ctx->dir);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, ctx->key,
- ctx->adata.keylen_pad + keys.enckeylen, 1);
-#endif
+
+ print_hex_dump_debug("ctx.key@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, ctx->key,
+ ctx->adata.keylen_pad + keys.enckeylen, 1);
skip_split_key:
ctx->cdata.keylen = keys.enckeylen;
@@ -678,10 +668,8 @@ static int gcm_setkey(struct crypto_aead *aead,
struct caam_ctx *ctx = crypto_aead_ctx(aead);
struct device *jrdev = ctx->jrdev;
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
-#endif
+ print_hex_dump_debug("key in @"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
memcpy(ctx->key, key, keylen);
dma_sync_single_for_device(jrdev, ctx->key_dma, keylen, ctx->dir);
@@ -699,10 +687,8 @@ static int rfc4106_setkey(struct crypto_aead *aead,
if (keylen < 4)
return -EINVAL;
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
-#endif
+ print_hex_dump_debug("key in @"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
memcpy(ctx->key, key, keylen);
@@ -725,10 +711,8 @@ static int rfc4543_setkey(struct crypto_aead *aead,
if (keylen < 4)
return -EINVAL;
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
-#endif
+ print_hex_dump_debug("key in @"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
memcpy(ctx->key, key, keylen);
@@ -757,10 +741,8 @@ static int skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key,
OP_ALG_AAI_CTR_MOD128);
const bool is_rfc3686 = alg->caam.rfc3686;
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
-#endif
+ print_hex_dump_debug("key in @"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
/*
* AES-CTR needs to load IV in CONTEXT1 reg
* at an offset of 128bits (16bytes)
@@ -916,7 +898,7 @@ static void caam_unmap(struct device *dev, struct scatterlist *src,
}
if (iv_dma)
- dma_unmap_single(dev, iv_dma, ivsize, DMA_TO_DEVICE);
+ dma_unmap_single(dev, iv_dma, ivsize, DMA_BIDIRECTIONAL);
if (sec4_sg_bytes)
dma_unmap_single(dev, sec4_sg_dma, sec4_sg_bytes,
DMA_TO_DEVICE);
@@ -949,9 +931,7 @@ static void aead_encrypt_done(struct device *jrdev, u32 *desc, u32 err,
struct aead_request *req = context;
struct aead_edesc *edesc;
-#ifdef DEBUG
- dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
-#endif
+ dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
edesc = container_of(desc, struct aead_edesc, hw_desc[0]);
@@ -971,9 +951,7 @@ static void aead_decrypt_done(struct device *jrdev, u32 *desc, u32 err,
struct aead_request *req = context;
struct aead_edesc *edesc;
-#ifdef DEBUG
- dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
-#endif
+ dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
edesc = container_of(desc, struct aead_edesc, hw_desc[0]);
@@ -1001,33 +979,32 @@ static void skcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err,
struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
int ivsize = crypto_skcipher_ivsize(skcipher);
-#ifdef DEBUG
- dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
-#endif
+ dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
edesc = container_of(desc, struct skcipher_edesc, hw_desc[0]);
if (err)
caam_jr_strstatus(jrdev, err);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "dstiv @"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, req->iv,
- edesc->src_nents > 1 ? 100 : ivsize, 1);
-#endif
- caam_dump_sg(KERN_ERR, "dst @" __stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, req->dst,
- edesc->dst_nents > 1 ? 100 : req->cryptlen, 1);
-
skcipher_unmap(jrdev, edesc, req);
/*
* The crypto API expects us to set the IV (req->iv) to the last
- * ciphertext block. This is used e.g. by the CTS mode.
+ * ciphertext block (CBC mode) or last counter (CTR mode).
+ * This is used e.g. by the CTS mode.
*/
- if (ivsize)
- scatterwalk_map_and_copy(req->iv, req->dst, req->cryptlen -
- ivsize, ivsize, 0);
+ if (ivsize) {
+ memcpy(req->iv, (u8 *)edesc->sec4_sg + edesc->sec4_sg_bytes,
+ ivsize);
+
+ print_hex_dump_debug("dstiv @"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, req->iv,
+ edesc->src_nents > 1 ? 100 : ivsize, 1);
+ }
+
+ caam_dump_sg("dst @" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, req->dst,
+ edesc->dst_nents > 1 ? 100 : req->cryptlen, 1);
kfree(edesc);
@@ -1039,26 +1016,35 @@ static void skcipher_decrypt_done(struct device *jrdev, u32 *desc, u32 err,
{
struct skcipher_request *req = context;
struct skcipher_edesc *edesc;
-#ifdef DEBUG
struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
int ivsize = crypto_skcipher_ivsize(skcipher);
- dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
-#endif
+ dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
edesc = container_of(desc, struct skcipher_edesc, hw_desc[0]);
if (err)
caam_jr_strstatus(jrdev, err);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "dstiv @"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, req->iv, ivsize, 1);
-#endif
- caam_dump_sg(KERN_ERR, "dst @" __stringify(__LINE__)": ",
+ skcipher_unmap(jrdev, edesc, req);
+
+ /*
+ * The crypto API expects us to set the IV (req->iv) to the last
+ * ciphertext block (CBC mode) or last counter (CTR mode).
+ * This is used e.g. by the CTS mode.
+ */
+ if (ivsize) {
+ memcpy(req->iv, (u8 *)edesc->sec4_sg + edesc->sec4_sg_bytes,
+ ivsize);
+
+ print_hex_dump_debug("dstiv @" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, req->iv,
+ ivsize, 1);
+ }
+
+ caam_dump_sg("dst @" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, req->dst,
edesc->dst_nents > 1 ? 100 : req->cryptlen, 1);
- skcipher_unmap(jrdev, edesc, req);
kfree(edesc);
skcipher_request_complete(req, err);
@@ -1106,6 +1092,7 @@ static void init_aead_job(struct aead_request *req,
if (unlikely(req->src != req->dst)) {
if (!edesc->mapped_dst_nents) {
dst_dma = 0;
+ out_options = 0;
} else if (edesc->mapped_dst_nents == 1) {
dst_dma = sg_dma_address(req->dst);
out_options = 0;
@@ -1249,6 +1236,7 @@ static void init_skcipher_job(struct skcipher_request *req,
{
struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
+ struct device *jrdev = ctx->jrdev;
int ivsize = crypto_skcipher_ivsize(skcipher);
u32 *desc = edesc->hw_desc;
u32 *sh_desc;
@@ -1256,13 +1244,12 @@ static void init_skcipher_job(struct skcipher_request *req,
dma_addr_t src_dma, dst_dma, ptr;
int len, sec4_sg_index = 0;
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "presciv@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, req->iv, ivsize, 1);
- pr_err("asked=%d, cryptlen%d\n",
+ print_hex_dump_debug("presciv@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, req->iv, ivsize, 1);
+ dev_dbg(jrdev, "asked=%d, cryptlen%d\n",
(int)edesc->src_nents > 1 ? 100 : req->cryptlen, req->cryptlen);
-#endif
- caam_dump_sg(KERN_ERR, "src @" __stringify(__LINE__)": ",
+
+ caam_dump_sg("src @" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, req->src,
edesc->src_nents > 1 ? 100 : req->cryptlen, 1);
@@ -1285,7 +1272,7 @@ static void init_skcipher_job(struct skcipher_request *req,
if (likely(req->src == req->dst)) {
dst_dma = src_dma + !!ivsize * sizeof(struct sec4_sg_entry);
out_options = in_options;
- } else if (edesc->mapped_dst_nents == 1) {
+ } else if (!ivsize && edesc->mapped_dst_nents == 1) {
dst_dma = sg_dma_address(req->dst);
} else {
dst_dma = edesc->sec4_sg_dma + sec4_sg_index *
@@ -1293,7 +1280,7 @@ static void init_skcipher_job(struct skcipher_request *req,
out_options = LDST_SGF;
}
- append_seq_out_ptr(desc, dst_dma, req->cryptlen, out_options);
+ append_seq_out_ptr(desc, dst_dma, req->cryptlen + ivsize, out_options);
}
/*
@@ -1309,37 +1296,36 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
GFP_KERNEL : GFP_ATOMIC;
int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0;
+ int src_len, dst_len = 0;
struct aead_edesc *edesc;
int sec4_sg_index, sec4_sg_len, sec4_sg_bytes;
unsigned int authsize = ctx->authsize;
if (unlikely(req->dst != req->src)) {
- src_nents = sg_nents_for_len(req->src, req->assoclen +
- req->cryptlen);
+ src_len = req->assoclen + req->cryptlen;
+ dst_len = src_len + (encrypt ? authsize : (-authsize));
+
+ src_nents = sg_nents_for_len(req->src, src_len);
if (unlikely(src_nents < 0)) {
dev_err(jrdev, "Insufficient bytes (%d) in src S/G\n",
- req->assoclen + req->cryptlen);
+ src_len);
return ERR_PTR(src_nents);
}
- dst_nents = sg_nents_for_len(req->dst, req->assoclen +
- req->cryptlen +
- (encrypt ? authsize :
- (-authsize)));
+ dst_nents = sg_nents_for_len(req->dst, dst_len);
if (unlikely(dst_nents < 0)) {
dev_err(jrdev, "Insufficient bytes (%d) in dst S/G\n",
- req->assoclen + req->cryptlen +
- (encrypt ? authsize : (-authsize)));
+ dst_len);
return ERR_PTR(dst_nents);
}
} else {
- src_nents = sg_nents_for_len(req->src, req->assoclen +
- req->cryptlen +
- (encrypt ? authsize : 0));
+ src_len = req->assoclen + req->cryptlen +
+ (encrypt ? authsize : 0);
+
+ src_nents = sg_nents_for_len(req->src, src_len);
if (unlikely(src_nents < 0)) {
dev_err(jrdev, "Insufficient bytes (%d) in src S/G\n",
- req->assoclen + req->cryptlen +
- (encrypt ? authsize : 0));
+ src_len);
return ERR_PTR(src_nents);
}
}
@@ -1380,8 +1366,16 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
}
}
+ /*
+ * HW reads 4 S/G entries at a time; make sure the reads don't go beyond
+ * the end of the table by allocating more S/G entries.
+ */
sec4_sg_len = mapped_src_nents > 1 ? mapped_src_nents : 0;
- sec4_sg_len += mapped_dst_nents > 1 ? mapped_dst_nents : 0;
+ if (mapped_dst_nents > 1)
+ sec4_sg_len += pad_sg_nents(mapped_dst_nents);
+ else
+ sec4_sg_len = pad_sg_nents(sec4_sg_len);
+
sec4_sg_bytes = sec4_sg_len * sizeof(struct sec4_sg_entry);
/* allocate space for base edesc and hw desc commands, link tables */
@@ -1403,12 +1397,12 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
sec4_sg_index = 0;
if (mapped_src_nents > 1) {
- sg_to_sec4_sg_last(req->src, mapped_src_nents,
+ sg_to_sec4_sg_last(req->src, src_len,
edesc->sec4_sg + sec4_sg_index, 0);
sec4_sg_index += mapped_src_nents;
}
if (mapped_dst_nents > 1) {
- sg_to_sec4_sg_last(req->dst, mapped_dst_nents,
+ sg_to_sec4_sg_last(req->dst, dst_len,
edesc->sec4_sg + sec4_sg_index, 0);
}
@@ -1446,11 +1440,10 @@ static int gcm_encrypt(struct aead_request *req)
/* Create and submit job descriptor */
init_gcm_job(req, edesc, all_contig, true);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "aead jobdesc@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc,
- desc_bytes(edesc->hw_desc), 1);
-#endif
+
+ print_hex_dump_debug("aead jobdesc@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc,
+ desc_bytes(edesc->hw_desc), 1);
desc = edesc->hw_desc;
ret = caam_jr_enqueue(jrdev, desc, aead_encrypt_done, req);
@@ -1556,11 +1549,10 @@ static int aead_encrypt(struct aead_request *req)
/* Create and submit job descriptor */
init_authenc_job(req, edesc, all_contig, true);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "aead jobdesc@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc,
- desc_bytes(edesc->hw_desc), 1);
-#endif
+
+ print_hex_dump_debug("aead jobdesc@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc,
+ desc_bytes(edesc->hw_desc), 1);
desc = edesc->hw_desc;
ret = caam_jr_enqueue(jrdev, desc, aead_encrypt_done, req);
@@ -1591,11 +1583,10 @@ static int gcm_decrypt(struct aead_request *req)
/* Create and submit job descriptor*/
init_gcm_job(req, edesc, all_contig, false);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "aead jobdesc@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc,
- desc_bytes(edesc->hw_desc), 1);
-#endif
+
+ print_hex_dump_debug("aead jobdesc@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc,
+ desc_bytes(edesc->hw_desc), 1);
desc = edesc->hw_desc;
ret = caam_jr_enqueue(jrdev, desc, aead_decrypt_done, req);
@@ -1627,7 +1618,7 @@ static int aead_decrypt(struct aead_request *req)
u32 *desc;
int ret = 0;
- caam_dump_sg(KERN_ERR, "dec src@" __stringify(__LINE__)": ",
+ caam_dump_sg("dec src@" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, req->src,
req->assoclen + req->cryptlen, 1);
@@ -1639,11 +1630,10 @@ static int aead_decrypt(struct aead_request *req)
/* Create and submit job descriptor*/
init_authenc_job(req, edesc, all_contig, false);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "aead jobdesc@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc,
- desc_bytes(edesc->hw_desc), 1);
-#endif
+
+ print_hex_dump_debug("aead jobdesc@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc,
+ desc_bytes(edesc->hw_desc), 1);
desc = edesc->hw_desc;
ret = caam_jr_enqueue(jrdev, desc, aead_decrypt_done, req);
@@ -1719,7 +1709,29 @@ static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req,
else
sec4_sg_ents = mapped_src_nents + !!ivsize;
dst_sg_idx = sec4_sg_ents;
- sec4_sg_ents += mapped_dst_nents > 1 ? mapped_dst_nents : 0;
+
+ /*
+ * Input, output HW S/G tables: [IV, src][dst, IV]
+ * IV entries point to the same buffer
+ * If src == dst, S/G entries are reused (S/G tables overlap)
+ *
+ * HW reads 4 S/G entries at a time; make sure the reads don't go beyond
+ * the end of the table by allocating more S/G entries. Logic:
+ * if (output S/G)
+ * pad output S/G, if needed
+ * else if (input S/G) ...
+ * pad input S/G, if needed
+ */
+ if (ivsize || mapped_dst_nents > 1) {
+ if (req->src == req->dst)
+ sec4_sg_ents = !!ivsize + pad_sg_nents(sec4_sg_ents);
+ else
+ sec4_sg_ents += pad_sg_nents(mapped_dst_nents +
+ !!ivsize);
+ } else {
+ sec4_sg_ents = pad_sg_nents(sec4_sg_ents);
+ }
+
sec4_sg_bytes = sec4_sg_ents * sizeof(struct sec4_sg_entry);
/*
@@ -1744,10 +1756,10 @@ static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req,
/* Make sure IV is located in a DMAable area */
if (ivsize) {
- iv = (u8 *)edesc->hw_desc + desc_bytes + sec4_sg_bytes;
+ iv = (u8 *)edesc->sec4_sg + sec4_sg_bytes;
memcpy(iv, req->iv, ivsize);
- iv_dma = dma_map_single(jrdev, iv, ivsize, DMA_TO_DEVICE);
+ iv_dma = dma_map_single(jrdev, iv, ivsize, DMA_BIDIRECTIONAL);
if (dma_mapping_error(jrdev, iv_dma)) {
dev_err(jrdev, "unable to map IV\n");
caam_unmap(jrdev, req->src, req->dst, src_nents,
@@ -1759,13 +1771,20 @@ static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req,
dma_to_sec4_sg_one(edesc->sec4_sg, iv_dma, ivsize, 0);
}
if (dst_sg_idx)
- sg_to_sec4_sg_last(req->src, mapped_src_nents, edesc->sec4_sg +
- !!ivsize, 0);
+ sg_to_sec4_sg(req->src, req->cryptlen, edesc->sec4_sg +
+ !!ivsize, 0);
- if (mapped_dst_nents > 1) {
- sg_to_sec4_sg_last(req->dst, mapped_dst_nents,
- edesc->sec4_sg + dst_sg_idx, 0);
- }
+ if (req->src != req->dst && (ivsize || mapped_dst_nents > 1))
+ sg_to_sec4_sg(req->dst, req->cryptlen, edesc->sec4_sg +
+ dst_sg_idx, 0);
+
+ if (ivsize)
+ dma_to_sec4_sg_one(edesc->sec4_sg + dst_sg_idx +
+ mapped_dst_nents, iv_dma, ivsize, 0);
+
+ if (ivsize || mapped_dst_nents > 1)
+ sg_to_sec4_set_last(edesc->sec4_sg + dst_sg_idx +
+ mapped_dst_nents);
if (sec4_sg_bytes) {
edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg,
@@ -1782,11 +1801,9 @@ static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req,
edesc->iv_dma = iv_dma;
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "skcipher sec4_sg@" __stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, edesc->sec4_sg,
- sec4_sg_bytes, 1);
-#endif
+ print_hex_dump_debug("skcipher sec4_sg@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, edesc->sec4_sg,
+ sec4_sg_bytes, 1);
return edesc;
}
@@ -1807,11 +1824,11 @@ static int skcipher_encrypt(struct skcipher_request *req)
/* Create and submit job descriptor*/
init_skcipher_job(req, edesc, true);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "skcipher jobdesc@" __stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc,
- desc_bytes(edesc->hw_desc), 1);
-#endif
+
+ print_hex_dump_debug("skcipher jobdesc@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc,
+ desc_bytes(edesc->hw_desc), 1);
+
desc = edesc->hw_desc;
ret = caam_jr_enqueue(jrdev, desc, skcipher_encrypt_done, req);
@@ -1830,7 +1847,6 @@ static int skcipher_decrypt(struct skcipher_request *req)
struct skcipher_edesc *edesc;
struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
- int ivsize = crypto_skcipher_ivsize(skcipher);
struct device *jrdev = ctx->jrdev;
u32 *desc;
int ret = 0;
@@ -1840,22 +1856,13 @@ static int skcipher_decrypt(struct skcipher_request *req)
if (IS_ERR(edesc))
return PTR_ERR(edesc);
- /*
- * The crypto API expects us to set the IV (req->iv) to the last
- * ciphertext block.
- */
- if (ivsize)
- scatterwalk_map_and_copy(req->iv, req->src, req->cryptlen -
- ivsize, ivsize, 0);
-
/* Create and submit job descriptor*/
init_skcipher_job(req, edesc, false);
desc = edesc->hw_desc;
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "skcipher jobdesc@" __stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc,
- desc_bytes(edesc->hw_desc), 1);
-#endif
+
+ print_hex_dump_debug("skcipher jobdesc@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc,
+ desc_bytes(edesc->hw_desc), 1);
ret = caam_jr_enqueue(jrdev, desc, skcipher_decrypt_done, req);
if (!ret) {
@@ -3444,7 +3451,7 @@ static void caam_aead_exit(struct crypto_aead *tfm)
caam_exit_common(crypto_aead_ctx(tfm));
}
-static void __exit caam_algapi_exit(void)
+void caam_algapi_exit(void)
{
int i;
@@ -3489,43 +3496,15 @@ static void caam_aead_alg_init(struct caam_aead_alg *t_alg)
alg->exit = caam_aead_exit;
}
-static int __init caam_algapi_init(void)
+int caam_algapi_init(struct device *ctrldev)
{
- struct device_node *dev_node;
- struct platform_device *pdev;
- struct caam_drv_private *priv;
+ struct caam_drv_private *priv = dev_get_drvdata(ctrldev);
int i = 0, err = 0;
u32 aes_vid, aes_inst, des_inst, md_vid, md_inst, ccha_inst, ptha_inst;
u32 arc4_inst;
unsigned int md_limit = SHA512_DIGEST_SIZE;
bool registered = false, gcm_support;
- dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
- if (!dev_node) {
- dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
- if (!dev_node)
- return -ENODEV;
- }
-
- pdev = of_find_device_by_node(dev_node);
- if (!pdev) {
- of_node_put(dev_node);
- return -ENODEV;
- }
-
- priv = dev_get_drvdata(&pdev->dev);
- of_node_put(dev_node);
-
- /*
- * If priv is NULL, it's probably because the caam driver wasn't
- * properly initialized (e.g. RNG4 init failed). Thus, bail out here.
- */
- if (!priv) {
- err = -ENODEV;
- goto out_put_dev;
- }
-
-
/*
* Register crypto algorithms the device supports.
* First, detect presence and attributes of DES, AES, and MD blocks.
@@ -3668,14 +3647,5 @@ static int __init caam_algapi_init(void)
if (registered)
pr_info("caam algorithms registered in /proc/crypto\n");
-out_put_dev:
- put_device(&pdev->dev);
return err;
}
-
-module_init(caam_algapi_init);
-module_exit(caam_algapi_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("FSL CAAM support for crypto API");
-MODULE_AUTHOR("Freescale Semiconductor - NMG/STC");
diff --git a/drivers/crypto/caam/caamalg_desc.c b/drivers/crypto/caam/caamalg_desc.c
index 1e1a376edc2f..72531837571e 100644
--- a/drivers/crypto/caam/caamalg_desc.c
+++ b/drivers/crypto/caam/caamalg_desc.c
@@ -33,12 +33,11 @@ static inline void append_dec_op1(u32 *desc, u32 type)
}
jump_cmd = append_jump(desc, JUMP_TEST_ALL | JUMP_COND_SHRD);
- append_operation(desc, type | OP_ALG_AS_INITFINAL |
- OP_ALG_DECRYPT);
+ append_operation(desc, type | OP_ALG_AS_INIT | OP_ALG_DECRYPT);
uncond_jump_cmd = append_jump(desc, JUMP_TEST_ALL);
set_jump_tgt_here(desc, jump_cmd);
- append_operation(desc, type | OP_ALG_AS_INITFINAL |
- OP_ALG_DECRYPT | OP_ALG_AAI_DK);
+ append_operation(desc, type | OP_ALG_AS_INIT | OP_ALG_DECRYPT |
+ OP_ALG_AAI_DK);
set_jump_tgt_here(desc, uncond_jump_cmd);
}
@@ -115,11 +114,9 @@ void cnstr_shdsc_aead_null_encap(u32 * const desc, struct alginfo *adata,
append_seq_store(desc, icvsize, LDST_CLASS_2_CCB |
LDST_SRCDST_BYTE_CONTEXT);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR,
- "aead null enc shdesc@" __stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
-#endif
+ print_hex_dump_debug("aead null enc shdesc@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
+ 1);
}
EXPORT_SYMBOL(cnstr_shdsc_aead_null_encap);
@@ -204,11 +201,9 @@ void cnstr_shdsc_aead_null_decap(u32 * const desc, struct alginfo *adata,
append_seq_fifo_load(desc, icvsize, FIFOLD_CLASS_CLASS2 |
FIFOLD_TYPE_LAST2 | FIFOLD_TYPE_ICV);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR,
- "aead null dec shdesc@" __stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
-#endif
+ print_hex_dump_debug("aead null dec shdesc@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
+ 1);
}
EXPORT_SYMBOL(cnstr_shdsc_aead_null_decap);
@@ -358,10 +353,9 @@ void cnstr_shdsc_aead_encap(u32 * const desc, struct alginfo *cdata,
append_seq_store(desc, icvsize, LDST_CLASS_2_CCB |
LDST_SRCDST_BYTE_CONTEXT);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "aead enc shdesc@" __stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
-#endif
+ print_hex_dump_debug("aead enc shdesc@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
+ 1);
}
EXPORT_SYMBOL(cnstr_shdsc_aead_encap);
@@ -475,10 +469,9 @@ void cnstr_shdsc_aead_decap(u32 * const desc, struct alginfo *cdata,
append_seq_fifo_load(desc, icvsize, FIFOLD_CLASS_CLASS2 |
FIFOLD_TYPE_LAST2 | FIFOLD_TYPE_ICV);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "aead dec shdesc@" __stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
-#endif
+ print_hex_dump_debug("aead dec shdesc@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
+ 1);
}
EXPORT_SYMBOL(cnstr_shdsc_aead_decap);
@@ -613,11 +606,9 @@ copy_iv:
append_seq_store(desc, icvsize, LDST_CLASS_2_CCB |
LDST_SRCDST_BYTE_CONTEXT);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR,
- "aead givenc shdesc@" __stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
-#endif
+ print_hex_dump_debug("aead givenc shdesc@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
+ 1);
}
EXPORT_SYMBOL(cnstr_shdsc_aead_givencap);
@@ -742,10 +733,9 @@ void cnstr_shdsc_gcm_encap(u32 * const desc, struct alginfo *cdata,
append_seq_store(desc, icvsize, LDST_CLASS_1_CCB |
LDST_SRCDST_BYTE_CONTEXT);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "gcm enc shdesc@" __stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
-#endif
+ print_hex_dump_debug("gcm enc shdesc@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
+ 1);
}
EXPORT_SYMBOL(cnstr_shdsc_gcm_encap);
@@ -838,10 +828,9 @@ void cnstr_shdsc_gcm_decap(u32 * const desc, struct alginfo *cdata,
append_seq_fifo_load(desc, icvsize, FIFOLD_CLASS_CLASS1 |
FIFOLD_TYPE_ICV | FIFOLD_TYPE_LAST1);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "gcm dec shdesc@" __stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
-#endif
+ print_hex_dump_debug("gcm dec shdesc@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
+ 1);
}
EXPORT_SYMBOL(cnstr_shdsc_gcm_decap);
@@ -933,11 +922,9 @@ void cnstr_shdsc_rfc4106_encap(u32 * const desc, struct alginfo *cdata,
append_seq_store(desc, icvsize, LDST_CLASS_1_CCB |
LDST_SRCDST_BYTE_CONTEXT);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR,
- "rfc4106 enc shdesc@" __stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
-#endif
+ print_hex_dump_debug("rfc4106 enc shdesc@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
+ 1);
}
EXPORT_SYMBOL(cnstr_shdsc_rfc4106_encap);
@@ -1030,11 +1017,9 @@ void cnstr_shdsc_rfc4106_decap(u32 * const desc, struct alginfo *cdata,
append_seq_fifo_load(desc, icvsize, FIFOLD_CLASS_CLASS1 |
FIFOLD_TYPE_ICV | FIFOLD_TYPE_LAST1);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR,
- "rfc4106 dec shdesc@" __stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
-#endif
+ print_hex_dump_debug("rfc4106 dec shdesc@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
+ 1);
}
EXPORT_SYMBOL(cnstr_shdsc_rfc4106_decap);
@@ -1115,11 +1100,9 @@ void cnstr_shdsc_rfc4543_encap(u32 * const desc, struct alginfo *cdata,
append_seq_store(desc, icvsize, LDST_CLASS_1_CCB |
LDST_SRCDST_BYTE_CONTEXT);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR,
- "rfc4543 enc shdesc@" __stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
-#endif
+ print_hex_dump_debug("rfc4543 enc shdesc@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
+ 1);
}
EXPORT_SYMBOL(cnstr_shdsc_rfc4543_encap);
@@ -1205,11 +1188,9 @@ void cnstr_shdsc_rfc4543_decap(u32 * const desc, struct alginfo *cdata,
append_seq_fifo_load(desc, icvsize, FIFOLD_CLASS_CLASS1 |
FIFOLD_TYPE_ICV | FIFOLD_TYPE_LAST1);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR,
- "rfc4543 dec shdesc@" __stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
-#endif
+ print_hex_dump_debug("rfc4543 dec shdesc@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
+ 1);
}
EXPORT_SYMBOL(cnstr_shdsc_rfc4543_decap);
@@ -1410,17 +1391,21 @@ void cnstr_shdsc_skcipher_encap(u32 * const desc, struct alginfo *cdata,
LDST_OFFSET_SHIFT));
/* Load operation */
- append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL |
+ append_operation(desc, cdata->algtype | OP_ALG_AS_INIT |
OP_ALG_ENCRYPT);
/* Perform operation */
skcipher_append_src_dst(desc);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR,
- "skcipher enc shdesc@" __stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
-#endif
+ /* Store IV */
+ if (ivsize)
+ append_seq_store(desc, ivsize, LDST_SRCDST_BYTE_CONTEXT |
+ LDST_CLASS_1_CCB | (ctx1_iv_off <<
+ LDST_OFFSET_SHIFT));
+
+ print_hex_dump_debug("skcipher enc shdesc@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
+ 1);
}
EXPORT_SYMBOL(cnstr_shdsc_skcipher_encap);
@@ -1479,7 +1464,7 @@ void cnstr_shdsc_skcipher_decap(u32 * const desc, struct alginfo *cdata,
/* Choose operation */
if (ctx1_iv_off)
- append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL |
+ append_operation(desc, cdata->algtype | OP_ALG_AS_INIT |
OP_ALG_DECRYPT);
else
append_dec_op1(desc, cdata->algtype);
@@ -1487,11 +1472,15 @@ void cnstr_shdsc_skcipher_decap(u32 * const desc, struct alginfo *cdata,
/* Perform operation */
skcipher_append_src_dst(desc);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR,
- "skcipher dec shdesc@" __stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
-#endif
+ /* Store IV */
+ if (ivsize)
+ append_seq_store(desc, ivsize, LDST_SRCDST_BYTE_CONTEXT |
+ LDST_CLASS_1_CCB | (ctx1_iv_off <<
+ LDST_OFFSET_SHIFT));
+
+ print_hex_dump_debug("skcipher dec shdesc@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
+ 1);
}
EXPORT_SYMBOL(cnstr_shdsc_skcipher_decap);
@@ -1538,11 +1527,13 @@ void cnstr_shdsc_xts_skcipher_encap(u32 * const desc, struct alginfo *cdata)
/* Perform operation */
skcipher_append_src_dst(desc);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR,
- "xts skcipher enc shdesc@" __stringify(__LINE__) ": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
-#endif
+ /* Store upper 8B of IV */
+ append_seq_store(desc, 8, LDST_SRCDST_BYTE_CONTEXT | LDST_CLASS_1_CCB |
+ (0x20 << LDST_OFFSET_SHIFT));
+
+ print_hex_dump_debug("xts skcipher enc shdesc@" __stringify(__LINE__)
+ ": ", DUMP_PREFIX_ADDRESS, 16, 4,
+ desc, desc_bytes(desc), 1);
}
EXPORT_SYMBOL(cnstr_shdsc_xts_skcipher_encap);
@@ -1588,11 +1579,13 @@ void cnstr_shdsc_xts_skcipher_decap(u32 * const desc, struct alginfo *cdata)
/* Perform operation */
skcipher_append_src_dst(desc);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR,
- "xts skcipher dec shdesc@" __stringify(__LINE__) ": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
-#endif
+ /* Store upper 8B of IV */
+ append_seq_store(desc, 8, LDST_SRCDST_BYTE_CONTEXT | LDST_CLASS_1_CCB |
+ (0x20 << LDST_OFFSET_SHIFT));
+
+ print_hex_dump_debug("xts skcipher dec shdesc@" __stringify(__LINE__)
+ ": ", DUMP_PREFIX_ADDRESS, 16, 4, desc,
+ desc_bytes(desc), 1);
}
EXPORT_SYMBOL(cnstr_shdsc_xts_skcipher_decap);
diff --git a/drivers/crypto/caam/caamalg_desc.h b/drivers/crypto/caam/caamalg_desc.h
index d5ca42ff961a..da4a4ee60c80 100644
--- a/drivers/crypto/caam/caamalg_desc.h
+++ b/drivers/crypto/caam/caamalg_desc.h
@@ -44,9 +44,9 @@
#define DESC_SKCIPHER_BASE (3 * CAAM_CMD_SZ)
#define DESC_SKCIPHER_ENC_LEN (DESC_SKCIPHER_BASE + \
- 20 * CAAM_CMD_SZ)
+ 21 * CAAM_CMD_SZ)
#define DESC_SKCIPHER_DEC_LEN (DESC_SKCIPHER_BASE + \
- 15 * CAAM_CMD_SZ)
+ 16 * CAAM_CMD_SZ)
void cnstr_shdsc_aead_null_encap(u32 * const desc, struct alginfo *adata,
unsigned int icvsize, int era);
diff --git a/drivers/crypto/caam/caamalg_qi.c b/drivers/crypto/caam/caamalg_qi.c
index d290d6b41825..32f0f8a72067 100644
--- a/drivers/crypto/caam/caamalg_qi.c
+++ b/drivers/crypto/caam/caamalg_qi.c
@@ -4,7 +4,7 @@
* Based on caamalg.c
*
* Copyright 2013-2016 Freescale Semiconductor, Inc.
- * Copyright 2016-2018 NXP
+ * Copyright 2016-2019 NXP
*/
#include "compat.h"
@@ -214,13 +214,11 @@ static int aead_setkey(struct crypto_aead *aead, const u8 *key,
if (crypto_authenc_extractkeys(&keys, key, keylen) != 0)
goto badkey;
-#ifdef DEBUG
- dev_err(jrdev, "keylen %d enckeylen %d authkeylen %d\n",
+ dev_dbg(jrdev, "keylen %d enckeylen %d authkeylen %d\n",
keys.authkeylen + keys.enckeylen, keys.enckeylen,
keys.authkeylen);
- print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
-#endif
+ print_hex_dump_debug("key in @" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
/*
* If DKP is supported, use it in the shared descriptor to generate
@@ -237,7 +235,7 @@ static int aead_setkey(struct crypto_aead *aead, const u8 *key,
memcpy(ctx->key, keys.authkey, keys.authkeylen);
memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey,
keys.enckeylen);
- dma_sync_single_for_device(jrdev, ctx->key_dma,
+ dma_sync_single_for_device(jrdev->parent, ctx->key_dma,
ctx->adata.keylen_pad +
keys.enckeylen, ctx->dir);
goto skip_split_key;
@@ -251,8 +249,9 @@ static int aead_setkey(struct crypto_aead *aead, const u8 *key,
/* postpend encryption key to auth split key */
memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey, keys.enckeylen);
- dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->adata.keylen_pad +
- keys.enckeylen, ctx->dir);
+ dma_sync_single_for_device(jrdev->parent, ctx->key_dma,
+ ctx->adata.keylen_pad + keys.enckeylen,
+ ctx->dir);
#ifdef DEBUG
print_hex_dump(KERN_ERR, "ctx.key@" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, ctx->key,
@@ -386,13 +385,12 @@ static int gcm_setkey(struct crypto_aead *aead,
struct device *jrdev = ctx->jrdev;
int ret;
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
-#endif
+ print_hex_dump_debug("key in @" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
memcpy(ctx->key, key, keylen);
- dma_sync_single_for_device(jrdev, ctx->key_dma, keylen, ctx->dir);
+ dma_sync_single_for_device(jrdev->parent, ctx->key_dma, keylen,
+ ctx->dir);
ctx->cdata.keylen = keylen;
ret = gcm_set_sh_desc(aead);
@@ -485,10 +483,8 @@ static int rfc4106_setkey(struct crypto_aead *aead,
if (keylen < 4)
return -EINVAL;
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
-#endif
+ print_hex_dump_debug("key in @" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
memcpy(ctx->key, key, keylen);
/*
@@ -496,8 +492,8 @@ static int rfc4106_setkey(struct crypto_aead *aead,
* in the nonce. Update the AES key length.
*/
ctx->cdata.keylen = keylen - 4;
- dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->cdata.keylen,
- ctx->dir);
+ dma_sync_single_for_device(jrdev->parent, ctx->key_dma,
+ ctx->cdata.keylen, ctx->dir);
ret = rfc4106_set_sh_desc(aead);
if (ret)
@@ -589,10 +585,8 @@ static int rfc4543_setkey(struct crypto_aead *aead,
if (keylen < 4)
return -EINVAL;
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
-#endif
+ print_hex_dump_debug("key in @" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
memcpy(ctx->key, key, keylen);
/*
@@ -600,8 +594,8 @@ static int rfc4543_setkey(struct crypto_aead *aead,
* in the nonce. Update the AES key length.
*/
ctx->cdata.keylen = keylen - 4;
- dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->cdata.keylen,
- ctx->dir);
+ dma_sync_single_for_device(jrdev->parent, ctx->key_dma,
+ ctx->cdata.keylen, ctx->dir);
ret = rfc4543_set_sh_desc(aead);
if (ret)
@@ -644,10 +638,9 @@ static int skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key,
const bool is_rfc3686 = alg->caam.rfc3686;
int ret = 0;
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
-#endif
+ print_hex_dump_debug("key in @" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
+
/*
* AES-CTR needs to load IV in CONTEXT1 reg
* at an offset of 128bits (16bytes)
@@ -838,7 +831,8 @@ static struct caam_drv_ctx *get_drv_ctx(struct caam_ctx *ctx,
static void caam_unmap(struct device *dev, struct scatterlist *src,
struct scatterlist *dst, int src_nents,
int dst_nents, dma_addr_t iv_dma, int ivsize,
- dma_addr_t qm_sg_dma, int qm_sg_bytes)
+ enum dma_data_direction iv_dir, dma_addr_t qm_sg_dma,
+ int qm_sg_bytes)
{
if (dst != src) {
if (src_nents)
@@ -850,7 +844,7 @@ static void caam_unmap(struct device *dev, struct scatterlist *src,
}
if (iv_dma)
- dma_unmap_single(dev, iv_dma, ivsize, DMA_TO_DEVICE);
+ dma_unmap_single(dev, iv_dma, ivsize, iv_dir);
if (qm_sg_bytes)
dma_unmap_single(dev, qm_sg_dma, qm_sg_bytes, DMA_TO_DEVICE);
}
@@ -863,7 +857,8 @@ static void aead_unmap(struct device *dev,
int ivsize = crypto_aead_ivsize(aead);
caam_unmap(dev, req->src, req->dst, edesc->src_nents, edesc->dst_nents,
- edesc->iv_dma, ivsize, edesc->qm_sg_dma, edesc->qm_sg_bytes);
+ edesc->iv_dma, ivsize, DMA_TO_DEVICE, edesc->qm_sg_dma,
+ edesc->qm_sg_bytes);
dma_unmap_single(dev, edesc->assoclen_dma, 4, DMA_TO_DEVICE);
}
@@ -874,7 +869,8 @@ static void skcipher_unmap(struct device *dev, struct skcipher_edesc *edesc,
int ivsize = crypto_skcipher_ivsize(skcipher);
caam_unmap(dev, req->src, req->dst, edesc->src_nents, edesc->dst_nents,
- edesc->iv_dma, ivsize, edesc->qm_sg_dma, edesc->qm_sg_bytes);
+ edesc->iv_dma, ivsize, DMA_BIDIRECTIONAL, edesc->qm_sg_dma,
+ edesc->qm_sg_bytes);
}
static void aead_done(struct caam_drv_req *drv_req, u32 status)
@@ -924,6 +920,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
GFP_KERNEL : GFP_ATOMIC;
int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0;
+ int src_len, dst_len = 0;
struct aead_edesc *edesc;
dma_addr_t qm_sg_dma, iv_dma = 0;
int ivsize = 0;
@@ -945,13 +942,13 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
}
if (likely(req->src == req->dst)) {
- src_nents = sg_nents_for_len(req->src, req->assoclen +
- req->cryptlen +
- (encrypt ? authsize : 0));
+ src_len = req->assoclen + req->cryptlen +
+ (encrypt ? authsize : 0);
+
+ src_nents = sg_nents_for_len(req->src, src_len);
if (unlikely(src_nents < 0)) {
dev_err(qidev, "Insufficient bytes (%d) in src S/G\n",
- req->assoclen + req->cryptlen +
- (encrypt ? authsize : 0));
+ src_len);
qi_cache_free(edesc);
return ERR_PTR(src_nents);
}
@@ -964,23 +961,21 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
return ERR_PTR(-ENOMEM);
}
} else {
- src_nents = sg_nents_for_len(req->src, req->assoclen +
- req->cryptlen);
+ src_len = req->assoclen + req->cryptlen;
+ dst_len = src_len + (encrypt ? authsize : (-authsize));
+
+ src_nents = sg_nents_for_len(req->src, src_len);
if (unlikely(src_nents < 0)) {
dev_err(qidev, "Insufficient bytes (%d) in src S/G\n",
- req->assoclen + req->cryptlen);
+ src_len);
qi_cache_free(edesc);
return ERR_PTR(src_nents);
}
- dst_nents = sg_nents_for_len(req->dst, req->assoclen +
- req->cryptlen +
- (encrypt ? authsize :
- (-authsize)));
+ dst_nents = sg_nents_for_len(req->dst, dst_len);
if (unlikely(dst_nents < 0)) {
dev_err(qidev, "Insufficient bytes (%d) in dst S/G\n",
- req->assoclen + req->cryptlen +
- (encrypt ? authsize : (-authsize)));
+ dst_len);
qi_cache_free(edesc);
return ERR_PTR(dst_nents);
}
@@ -1019,9 +1014,24 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
/*
* Create S/G table: req->assoclen, [IV,] req->src [, req->dst].
* Input is not contiguous.
+ * HW reads 4 S/G entries at a time; make sure the reads don't go beyond
+ * the end of the table by allocating more S/G entries. Logic:
+ * if (src != dst && output S/G)
+ * pad output S/G, if needed
+ * else if (src == dst && S/G)
+ * overlapping S/Gs; pad one of them
+ * else if (input S/G) ...
+ * pad input S/G, if needed
*/
- qm_sg_ents = 1 + !!ivsize + mapped_src_nents +
- (mapped_dst_nents > 1 ? mapped_dst_nents : 0);
+ qm_sg_ents = 1 + !!ivsize + mapped_src_nents;
+ if (mapped_dst_nents > 1)
+ qm_sg_ents += pad_sg_nents(mapped_dst_nents);
+ else if ((req->src == req->dst) && (mapped_src_nents > 1))
+ qm_sg_ents = max(pad_sg_nents(qm_sg_ents),
+ 1 + !!ivsize + pad_sg_nents(mapped_src_nents));
+ else
+ qm_sg_ents = pad_sg_nents(qm_sg_ents);
+
sg_table = &edesc->sgt[0];
qm_sg_bytes = qm_sg_ents * sizeof(*sg_table);
if (unlikely(offsetof(struct aead_edesc, sgt) + qm_sg_bytes + ivsize >
@@ -1029,7 +1039,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
dev_err(qidev, "No space for %d S/G entries and/or %dB IV\n",
qm_sg_ents, ivsize);
caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0,
- 0, 0, 0);
+ 0, DMA_NONE, 0, 0);
qi_cache_free(edesc);
return ERR_PTR(-ENOMEM);
}
@@ -1044,7 +1054,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
if (dma_mapping_error(qidev, iv_dma)) {
dev_err(qidev, "unable to map IV\n");
caam_unmap(qidev, req->src, req->dst, src_nents,
- dst_nents, 0, 0, 0, 0);
+ dst_nents, 0, 0, DMA_NONE, 0, 0);
qi_cache_free(edesc);
return ERR_PTR(-ENOMEM);
}
@@ -1063,7 +1073,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
if (dma_mapping_error(qidev, edesc->assoclen_dma)) {
dev_err(qidev, "unable to map assoclen\n");
caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents,
- iv_dma, ivsize, 0, 0);
+ iv_dma, ivsize, DMA_TO_DEVICE, 0, 0);
qi_cache_free(edesc);
return ERR_PTR(-ENOMEM);
}
@@ -1074,19 +1084,18 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
dma_to_qm_sg_one(sg_table + qm_sg_index, iv_dma, ivsize, 0);
qm_sg_index++;
}
- sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table + qm_sg_index, 0);
+ sg_to_qm_sg_last(req->src, src_len, sg_table + qm_sg_index, 0);
qm_sg_index += mapped_src_nents;
if (mapped_dst_nents > 1)
- sg_to_qm_sg_last(req->dst, mapped_dst_nents, sg_table +
- qm_sg_index, 0);
+ sg_to_qm_sg_last(req->dst, dst_len, sg_table + qm_sg_index, 0);
qm_sg_dma = dma_map_single(qidev, sg_table, qm_sg_bytes, DMA_TO_DEVICE);
if (dma_mapping_error(qidev, qm_sg_dma)) {
dev_err(qidev, "unable to map S/G table\n");
dma_unmap_single(qidev, edesc->assoclen_dma, 4, DMA_TO_DEVICE);
caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents,
- iv_dma, ivsize, 0, 0);
+ iv_dma, ivsize, DMA_TO_DEVICE, 0, 0);
qi_cache_free(edesc);
return ERR_PTR(-ENOMEM);
}
@@ -1109,7 +1118,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
dma_to_qm_sg_one_ext(&fd_sgt[0], qm_sg_dma +
(1 + !!ivsize) * sizeof(*sg_table),
out_len, 0);
- } else if (mapped_dst_nents == 1) {
+ } else if (mapped_dst_nents <= 1) {
dma_to_qm_sg_one(&fd_sgt[0], sg_dma_address(req->dst), out_len,
0);
} else {
@@ -1182,33 +1191,28 @@ static void skcipher_done(struct caam_drv_req *drv_req, u32 status)
struct device *qidev = caam_ctx->qidev;
int ivsize = crypto_skcipher_ivsize(skcipher);
-#ifdef DEBUG
- dev_err(qidev, "%s %d: status 0x%x\n", __func__, __LINE__, status);
-#endif
+ dev_dbg(qidev, "%s %d: status 0x%x\n", __func__, __LINE__, status);
edesc = container_of(drv_req, typeof(*edesc), drv_req);
if (status)
caam_jr_strstatus(qidev, status);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "dstiv @" __stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, req->iv,
- edesc->src_nents > 1 ? 100 : ivsize, 1);
- caam_dump_sg(KERN_ERR, "dst @" __stringify(__LINE__)": ",
+ print_hex_dump_debug("dstiv @" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, req->iv,
+ edesc->src_nents > 1 ? 100 : ivsize, 1);
+ caam_dump_sg("dst @" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, req->dst,
edesc->dst_nents > 1 ? 100 : req->cryptlen, 1);
-#endif
skcipher_unmap(qidev, edesc, req);
/*
* The crypto API expects us to set the IV (req->iv) to the last
- * ciphertext block. This is used e.g. by the CTS mode.
+ * ciphertext block (CBC mode) or last counter (CTR mode).
+ * This is used e.g. by the CTS mode.
*/
- if (edesc->drv_req.drv_ctx->op_type == ENCRYPT)
- scatterwalk_map_and_copy(req->iv, req->dst, req->cryptlen -
- ivsize, ivsize, 0);
+ memcpy(req->iv, (u8 *)&edesc->sgt[0] + edesc->qm_sg_bytes, ivsize);
qi_cache_free(edesc);
skcipher_request_complete(req, status);
@@ -1276,14 +1280,26 @@ static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req,
qm_sg_ents = 1 + mapped_src_nents;
dst_sg_idx = qm_sg_ents;
- qm_sg_ents += mapped_dst_nents > 1 ? mapped_dst_nents : 0;
+ /*
+ * Input, output HW S/G tables: [IV, src][dst, IV]
+ * IV entries point to the same buffer
+ * If src == dst, S/G entries are reused (S/G tables overlap)
+ *
+ * HW reads 4 S/G entries at a time; make sure the reads don't go beyond
+ * the end of the table by allocating more S/G entries.
+ */
+ if (req->src != req->dst)
+ qm_sg_ents += pad_sg_nents(mapped_dst_nents + 1);
+ else
+ qm_sg_ents = 1 + pad_sg_nents(qm_sg_ents);
+
qm_sg_bytes = qm_sg_ents * sizeof(struct qm_sg_entry);
if (unlikely(offsetof(struct skcipher_edesc, sgt) + qm_sg_bytes +
ivsize > CAAM_QI_MEMCACHE_SIZE)) {
dev_err(qidev, "No space for %d S/G entries and/or %dB IV\n",
qm_sg_ents, ivsize);
caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0,
- 0, 0, 0);
+ 0, DMA_NONE, 0, 0);
return ERR_PTR(-ENOMEM);
}
@@ -1292,7 +1308,7 @@ static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req,
if (unlikely(!edesc)) {
dev_err(qidev, "could not allocate extended descriptor\n");
caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0,
- 0, 0, 0);
+ 0, DMA_NONE, 0, 0);
return ERR_PTR(-ENOMEM);
}
@@ -1301,11 +1317,11 @@ static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req,
iv = (u8 *)(sg_table + qm_sg_ents);
memcpy(iv, req->iv, ivsize);
- iv_dma = dma_map_single(qidev, iv, ivsize, DMA_TO_DEVICE);
+ iv_dma = dma_map_single(qidev, iv, ivsize, DMA_BIDIRECTIONAL);
if (dma_mapping_error(qidev, iv_dma)) {
dev_err(qidev, "unable to map IV\n");
caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0,
- 0, 0, 0);
+ 0, DMA_NONE, 0, 0);
qi_cache_free(edesc);
return ERR_PTR(-ENOMEM);
}
@@ -1319,18 +1335,20 @@ static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req,
edesc->drv_req.drv_ctx = drv_ctx;
dma_to_qm_sg_one(sg_table, iv_dma, ivsize, 0);
- sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table + 1, 0);
+ sg_to_qm_sg(req->src, req->cryptlen, sg_table + 1, 0);
- if (mapped_dst_nents > 1)
- sg_to_qm_sg_last(req->dst, mapped_dst_nents, sg_table +
- dst_sg_idx, 0);
+ if (req->src != req->dst)
+ sg_to_qm_sg(req->dst, req->cryptlen, sg_table + dst_sg_idx, 0);
+
+ dma_to_qm_sg_one(sg_table + dst_sg_idx + mapped_dst_nents, iv_dma,
+ ivsize, 0);
edesc->qm_sg_dma = dma_map_single(qidev, sg_table, edesc->qm_sg_bytes,
DMA_TO_DEVICE);
if (dma_mapping_error(qidev, edesc->qm_sg_dma)) {
dev_err(qidev, "unable to map S/G table\n");
caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents,
- iv_dma, ivsize, 0, 0);
+ iv_dma, ivsize, DMA_BIDIRECTIONAL, 0, 0);
qi_cache_free(edesc);
return ERR_PTR(-ENOMEM);
}
@@ -1340,16 +1358,14 @@ static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req,
dma_to_qm_sg_one_last_ext(&fd_sgt[1], edesc->qm_sg_dma,
ivsize + req->cryptlen, 0);
- if (req->src == req->dst) {
+ if (req->src == req->dst)
dma_to_qm_sg_one_ext(&fd_sgt[0], edesc->qm_sg_dma +
- sizeof(*sg_table), req->cryptlen, 0);
- } else if (mapped_dst_nents > 1) {
+ sizeof(*sg_table), req->cryptlen + ivsize,
+ 0);
+ else
dma_to_qm_sg_one_ext(&fd_sgt[0], edesc->qm_sg_dma + dst_sg_idx *
- sizeof(*sg_table), req->cryptlen, 0);
- } else {
- dma_to_qm_sg_one(&fd_sgt[0], sg_dma_address(req->dst),
- req->cryptlen, 0);
- }
+ sizeof(*sg_table), req->cryptlen + ivsize,
+ 0);
return edesc;
}
@@ -1359,7 +1375,6 @@ static inline int skcipher_crypt(struct skcipher_request *req, bool encrypt)
struct skcipher_edesc *edesc;
struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
- int ivsize = crypto_skcipher_ivsize(skcipher);
int ret;
if (unlikely(caam_congested))
@@ -1370,14 +1385,6 @@ static inline int skcipher_crypt(struct skcipher_request *req, bool encrypt)
if (IS_ERR(edesc))
return PTR_ERR(edesc);
- /*
- * The crypto API expects us to set the IV (req->iv) to the last
- * ciphertext block.
- */
- if (!encrypt)
- scatterwalk_map_and_copy(req->iv, req->src, req->cryptlen -
- ivsize, ivsize, 0);
-
ret = caam_qi_enqueue(ctx->qidev, &edesc->drv_req);
if (!ret) {
ret = -EINPROGRESS;
@@ -2382,6 +2389,7 @@ static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam,
bool uses_dkp)
{
struct caam_drv_private *priv;
+ struct device *dev;
/*
* distribute tfms across job rings to ensure in-order
@@ -2393,16 +2401,17 @@ static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam,
return PTR_ERR(ctx->jrdev);
}
- priv = dev_get_drvdata(ctx->jrdev->parent);
+ dev = ctx->jrdev->parent;
+ priv = dev_get_drvdata(dev);
if (priv->era >= 6 && uses_dkp)
ctx->dir = DMA_BIDIRECTIONAL;
else
ctx->dir = DMA_TO_DEVICE;
- ctx->key_dma = dma_map_single(ctx->jrdev, ctx->key, sizeof(ctx->key),
+ ctx->key_dma = dma_map_single(dev, ctx->key, sizeof(ctx->key),
ctx->dir);
- if (dma_mapping_error(ctx->jrdev, ctx->key_dma)) {
- dev_err(ctx->jrdev, "unable to map key\n");
+ if (dma_mapping_error(dev, ctx->key_dma)) {
+ dev_err(dev, "unable to map key\n");
caam_jr_free(ctx->jrdev);
return -ENOMEM;
}
@@ -2411,7 +2420,7 @@ static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam,
ctx->cdata.algtype = OP_TYPE_CLASS1_ALG | caam->class1_alg_type;
ctx->adata.algtype = OP_TYPE_CLASS2_ALG | caam->class2_alg_type;
- ctx->qidev = priv->qidev;
+ ctx->qidev = dev;
spin_lock_init(&ctx->lock);
ctx->drv_ctx[ENCRYPT] = NULL;
@@ -2445,7 +2454,8 @@ static void caam_exit_common(struct caam_ctx *ctx)
caam_drv_ctx_rel(ctx->drv_ctx[ENCRYPT]);
caam_drv_ctx_rel(ctx->drv_ctx[DECRYPT]);
- dma_unmap_single(ctx->jrdev, ctx->key_dma, sizeof(ctx->key), ctx->dir);
+ dma_unmap_single(ctx->jrdev->parent, ctx->key_dma, sizeof(ctx->key),
+ ctx->dir);
caam_jr_free(ctx->jrdev);
}
@@ -2460,7 +2470,7 @@ static void caam_aead_exit(struct crypto_aead *tfm)
caam_exit_common(crypto_aead_ctx(tfm));
}
-static void __exit caam_qi_algapi_exit(void)
+void caam_qi_algapi_exit(void)
{
int i;
@@ -2505,45 +2515,17 @@ static void caam_aead_alg_init(struct caam_aead_alg *t_alg)
alg->exit = caam_aead_exit;
}
-static int __init caam_qi_algapi_init(void)
+int caam_qi_algapi_init(struct device *ctrldev)
{
- struct device_node *dev_node;
- struct platform_device *pdev;
- struct device *ctrldev;
- struct caam_drv_private *priv;
+ struct caam_drv_private *priv = dev_get_drvdata(ctrldev);
int i = 0, err = 0;
u32 aes_vid, aes_inst, des_inst, md_vid, md_inst;
unsigned int md_limit = SHA512_DIGEST_SIZE;
bool registered = false;
- dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
- if (!dev_node) {
- dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
- if (!dev_node)
- return -ENODEV;
- }
-
- pdev = of_find_device_by_node(dev_node);
- of_node_put(dev_node);
- if (!pdev)
- return -ENODEV;
-
- ctrldev = &pdev->dev;
- priv = dev_get_drvdata(ctrldev);
-
- /*
- * If priv is NULL, it's probably because the caam driver wasn't
- * properly initialized (e.g. RNG4 init failed). Thus, bail out here.
- */
- if (!priv || !priv->qi_present) {
- err = -ENODEV;
- goto out_put_dev;
- }
-
if (caam_dpaa2) {
dev_info(ctrldev, "caam/qi frontend driver not suitable for DPAA 2.x, aborting...\n");
- err = -ENODEV;
- goto out_put_dev;
+ return -ENODEV;
}
/*
@@ -2598,7 +2580,7 @@ static int __init caam_qi_algapi_init(void)
err = crypto_register_skcipher(&t_alg->skcipher);
if (err) {
- dev_warn(priv->qidev, "%s alg registration failed\n",
+ dev_warn(ctrldev, "%s alg registration failed\n",
t_alg->skcipher.base.cra_driver_name);
continue;
}
@@ -2654,16 +2636,7 @@ static int __init caam_qi_algapi_init(void)
}
if (registered)
- dev_info(priv->qidev, "algorithms registered in /proc/crypto\n");
+ dev_info(ctrldev, "algorithms registered in /proc/crypto\n");
-out_put_dev:
- put_device(ctrldev);
return err;
}
-
-module_init(caam_qi_algapi_init);
-module_exit(caam_qi_algapi_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Support for crypto API using CAAM-QI backend");
-MODULE_AUTHOR("Freescale Semiconductor");
diff --git a/drivers/crypto/caam/caamalg_qi2.c b/drivers/crypto/caam/caamalg_qi2.c
index 2b2980a8a9b9..06bf32c32cbd 100644
--- a/drivers/crypto/caam/caamalg_qi2.c
+++ b/drivers/crypto/caam/caamalg_qi2.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/*
* Copyright 2015-2016 Freescale Semiconductor Inc.
- * Copyright 2017-2018 NXP
+ * Copyright 2017-2019 NXP
*/
#include "compat.h"
@@ -140,7 +140,8 @@ static struct caam_request *to_caam_req(struct crypto_async_request *areq)
static void caam_unmap(struct device *dev, struct scatterlist *src,
struct scatterlist *dst, int src_nents,
int dst_nents, dma_addr_t iv_dma, int ivsize,
- dma_addr_t qm_sg_dma, int qm_sg_bytes)
+ enum dma_data_direction iv_dir, dma_addr_t qm_sg_dma,
+ int qm_sg_bytes)
{
if (dst != src) {
if (src_nents)
@@ -152,7 +153,7 @@ static void caam_unmap(struct device *dev, struct scatterlist *src,
}
if (iv_dma)
- dma_unmap_single(dev, iv_dma, ivsize, DMA_TO_DEVICE);
+ dma_unmap_single(dev, iv_dma, ivsize, iv_dir);
if (qm_sg_bytes)
dma_unmap_single(dev, qm_sg_dma, qm_sg_bytes, DMA_TO_DEVICE);
@@ -371,6 +372,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
GFP_KERNEL : GFP_ATOMIC;
int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0;
+ int src_len, dst_len = 0;
struct aead_edesc *edesc;
dma_addr_t qm_sg_dma, iv_dma = 0;
int ivsize = 0;
@@ -387,23 +389,21 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
}
if (unlikely(req->dst != req->src)) {
- src_nents = sg_nents_for_len(req->src, req->assoclen +
- req->cryptlen);
+ src_len = req->assoclen + req->cryptlen;
+ dst_len = src_len + (encrypt ? authsize : (-authsize));
+
+ src_nents = sg_nents_for_len(req->src, src_len);
if (unlikely(src_nents < 0)) {
dev_err(dev, "Insufficient bytes (%d) in src S/G\n",
- req->assoclen + req->cryptlen);
+ src_len);
qi_cache_free(edesc);
return ERR_PTR(src_nents);
}
- dst_nents = sg_nents_for_len(req->dst, req->assoclen +
- req->cryptlen +
- (encrypt ? authsize :
- (-authsize)));
+ dst_nents = sg_nents_for_len(req->dst, dst_len);
if (unlikely(dst_nents < 0)) {
dev_err(dev, "Insufficient bytes (%d) in dst S/G\n",
- req->assoclen + req->cryptlen +
- (encrypt ? authsize : (-authsize)));
+ dst_len);
qi_cache_free(edesc);
return ERR_PTR(dst_nents);
}
@@ -434,13 +434,13 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
mapped_dst_nents = 0;
}
} else {
- src_nents = sg_nents_for_len(req->src, req->assoclen +
- req->cryptlen +
- (encrypt ? authsize : 0));
+ src_len = req->assoclen + req->cryptlen +
+ (encrypt ? authsize : 0);
+
+ src_nents = sg_nents_for_len(req->src, src_len);
if (unlikely(src_nents < 0)) {
dev_err(dev, "Insufficient bytes (%d) in src S/G\n",
- req->assoclen + req->cryptlen +
- (encrypt ? authsize : 0));
+ src_len);
qi_cache_free(edesc);
return ERR_PTR(src_nents);
}
@@ -460,9 +460,25 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
/*
* Create S/G table: req->assoclen, [IV,] req->src [, req->dst].
* Input is not contiguous.
+ * HW reads 4 S/G entries at a time; make sure the reads don't go beyond
+ * the end of the table by allocating more S/G entries. Logic:
+ * if (src != dst && output S/G)
+ * pad output S/G, if needed
+ * else if (src == dst && S/G)
+ * overlapping S/Gs; pad one of them
+ * else if (input S/G) ...
+ * pad input S/G, if needed
*/
- qm_sg_nents = 1 + !!ivsize + mapped_src_nents +
- (mapped_dst_nents > 1 ? mapped_dst_nents : 0);
+ qm_sg_nents = 1 + !!ivsize + mapped_src_nents;
+ if (mapped_dst_nents > 1)
+ qm_sg_nents += pad_sg_nents(mapped_dst_nents);
+ else if ((req->src == req->dst) && (mapped_src_nents > 1))
+ qm_sg_nents = max(pad_sg_nents(qm_sg_nents),
+ 1 + !!ivsize +
+ pad_sg_nents(mapped_src_nents));
+ else
+ qm_sg_nents = pad_sg_nents(qm_sg_nents);
+
sg_table = &edesc->sgt[0];
qm_sg_bytes = qm_sg_nents * sizeof(*sg_table);
if (unlikely(offsetof(struct aead_edesc, sgt) + qm_sg_bytes + ivsize >
@@ -470,7 +486,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
dev_err(dev, "No space for %d S/G entries and/or %dB IV\n",
qm_sg_nents, ivsize);
caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, 0,
- 0, 0, 0);
+ 0, DMA_NONE, 0, 0);
qi_cache_free(edesc);
return ERR_PTR(-ENOMEM);
}
@@ -485,7 +501,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
if (dma_mapping_error(dev, iv_dma)) {
dev_err(dev, "unable to map IV\n");
caam_unmap(dev, req->src, req->dst, src_nents,
- dst_nents, 0, 0, 0, 0);
+ dst_nents, 0, 0, DMA_NONE, 0, 0);
qi_cache_free(edesc);
return ERR_PTR(-ENOMEM);
}
@@ -509,7 +525,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
if (dma_mapping_error(dev, edesc->assoclen_dma)) {
dev_err(dev, "unable to map assoclen\n");
caam_unmap(dev, req->src, req->dst, src_nents, dst_nents,
- iv_dma, ivsize, 0, 0);
+ iv_dma, ivsize, DMA_TO_DEVICE, 0, 0);
qi_cache_free(edesc);
return ERR_PTR(-ENOMEM);
}
@@ -520,19 +536,18 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
dma_to_qm_sg_one(sg_table + qm_sg_index, iv_dma, ivsize, 0);
qm_sg_index++;
}
- sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table + qm_sg_index, 0);
+ sg_to_qm_sg_last(req->src, src_len, sg_table + qm_sg_index, 0);
qm_sg_index += mapped_src_nents;
if (mapped_dst_nents > 1)
- sg_to_qm_sg_last(req->dst, mapped_dst_nents, sg_table +
- qm_sg_index, 0);
+ sg_to_qm_sg_last(req->dst, dst_len, sg_table + qm_sg_index, 0);
qm_sg_dma = dma_map_single(dev, sg_table, qm_sg_bytes, DMA_TO_DEVICE);
if (dma_mapping_error(dev, qm_sg_dma)) {
dev_err(dev, "unable to map S/G table\n");
dma_unmap_single(dev, edesc->assoclen_dma, 4, DMA_TO_DEVICE);
caam_unmap(dev, req->src, req->dst, src_nents, dst_nents,
- iv_dma, ivsize, 0, 0);
+ iv_dma, ivsize, DMA_TO_DEVICE, 0, 0);
qi_cache_free(edesc);
return ERR_PTR(-ENOMEM);
}
@@ -559,6 +574,14 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
dpaa2_fl_set_addr(out_fle, qm_sg_dma +
(1 + !!ivsize) * sizeof(*sg_table));
}
+ } else if (!mapped_dst_nents) {
+ /*
+ * crypto engine requires the output entry to be present when
+ * "frame list" FD is used.
+ * Since engine does not support FMT=2'b11 (unused entry type),
+ * leaving out_fle zeroized is the best option.
+ */
+ goto skip_out_fle;
} else if (mapped_dst_nents == 1) {
dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
dpaa2_fl_set_addr(out_fle, sg_dma_address(req->dst));
@@ -570,6 +593,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
dpaa2_fl_set_len(out_fle, out_len);
+skip_out_fle:
return edesc;
}
@@ -1077,14 +1101,26 @@ static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req)
qm_sg_ents = 1 + mapped_src_nents;
dst_sg_idx = qm_sg_ents;
- qm_sg_ents += mapped_dst_nents > 1 ? mapped_dst_nents : 0;
+ /*
+ * Input, output HW S/G tables: [IV, src][dst, IV]
+ * IV entries point to the same buffer
+ * If src == dst, S/G entries are reused (S/G tables overlap)
+ *
+ * HW reads 4 S/G entries at a time; make sure the reads don't go beyond
+ * the end of the table by allocating more S/G entries.
+ */
+ if (req->src != req->dst)
+ qm_sg_ents += pad_sg_nents(mapped_dst_nents + 1);
+ else
+ qm_sg_ents = 1 + pad_sg_nents(qm_sg_ents);
+
qm_sg_bytes = qm_sg_ents * sizeof(struct dpaa2_sg_entry);
if (unlikely(offsetof(struct skcipher_edesc, sgt) + qm_sg_bytes +
ivsize > CAAM_QI_MEMCACHE_SIZE)) {
dev_err(dev, "No space for %d S/G entries and/or %dB IV\n",
qm_sg_ents, ivsize);
caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, 0,
- 0, 0, 0);
+ 0, DMA_NONE, 0, 0);
return ERR_PTR(-ENOMEM);
}
@@ -1093,7 +1129,7 @@ static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req)
if (unlikely(!edesc)) {
dev_err(dev, "could not allocate extended descriptor\n");
caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, 0,
- 0, 0, 0);
+ 0, DMA_NONE, 0, 0);
return ERR_PTR(-ENOMEM);
}
@@ -1102,11 +1138,11 @@ static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req)
iv = (u8 *)(sg_table + qm_sg_ents);
memcpy(iv, req->iv, ivsize);
- iv_dma = dma_map_single(dev, iv, ivsize, DMA_TO_DEVICE);
+ iv_dma = dma_map_single(dev, iv, ivsize, DMA_BIDIRECTIONAL);
if (dma_mapping_error(dev, iv_dma)) {
dev_err(dev, "unable to map IV\n");
caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, 0,
- 0, 0, 0);
+ 0, DMA_NONE, 0, 0);
qi_cache_free(edesc);
return ERR_PTR(-ENOMEM);
}
@@ -1117,18 +1153,20 @@ static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req)
edesc->qm_sg_bytes = qm_sg_bytes;
dma_to_qm_sg_one(sg_table, iv_dma, ivsize, 0);
- sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table + 1, 0);
+ sg_to_qm_sg(req->src, req->cryptlen, sg_table + 1, 0);
- if (mapped_dst_nents > 1)
- sg_to_qm_sg_last(req->dst, mapped_dst_nents, sg_table +
- dst_sg_idx, 0);
+ if (req->src != req->dst)
+ sg_to_qm_sg(req->dst, req->cryptlen, sg_table + dst_sg_idx, 0);
+
+ dma_to_qm_sg_one(sg_table + dst_sg_idx + mapped_dst_nents, iv_dma,
+ ivsize, 0);
edesc->qm_sg_dma = dma_map_single(dev, sg_table, edesc->qm_sg_bytes,
DMA_TO_DEVICE);
if (dma_mapping_error(dev, edesc->qm_sg_dma)) {
dev_err(dev, "unable to map S/G table\n");
caam_unmap(dev, req->src, req->dst, src_nents, dst_nents,
- iv_dma, ivsize, 0, 0);
+ iv_dma, ivsize, DMA_BIDIRECTIONAL, 0, 0);
qi_cache_free(edesc);
return ERR_PTR(-ENOMEM);
}
@@ -1136,23 +1174,19 @@ static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req)
memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt));
dpaa2_fl_set_final(in_fle, true);
dpaa2_fl_set_len(in_fle, req->cryptlen + ivsize);
- dpaa2_fl_set_len(out_fle, req->cryptlen);
+ dpaa2_fl_set_len(out_fle, req->cryptlen + ivsize);
dpaa2_fl_set_format(in_fle, dpaa2_fl_sg);
dpaa2_fl_set_addr(in_fle, edesc->qm_sg_dma);
- if (req->src == req->dst) {
- dpaa2_fl_set_format(out_fle, dpaa2_fl_sg);
+ dpaa2_fl_set_format(out_fle, dpaa2_fl_sg);
+
+ if (req->src == req->dst)
dpaa2_fl_set_addr(out_fle, edesc->qm_sg_dma +
sizeof(*sg_table));
- } else if (mapped_dst_nents > 1) {
- dpaa2_fl_set_format(out_fle, dpaa2_fl_sg);
+ else
dpaa2_fl_set_addr(out_fle, edesc->qm_sg_dma + dst_sg_idx *
sizeof(*sg_table));
- } else {
- dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
- dpaa2_fl_set_addr(out_fle, sg_dma_address(req->dst));
- }
return edesc;
}
@@ -1164,7 +1198,8 @@ static void aead_unmap(struct device *dev, struct aead_edesc *edesc,
int ivsize = crypto_aead_ivsize(aead);
caam_unmap(dev, req->src, req->dst, edesc->src_nents, edesc->dst_nents,
- edesc->iv_dma, ivsize, edesc->qm_sg_dma, edesc->qm_sg_bytes);
+ edesc->iv_dma, ivsize, DMA_TO_DEVICE, edesc->qm_sg_dma,
+ edesc->qm_sg_bytes);
dma_unmap_single(dev, edesc->assoclen_dma, 4, DMA_TO_DEVICE);
}
@@ -1175,7 +1210,8 @@ static void skcipher_unmap(struct device *dev, struct skcipher_edesc *edesc,
int ivsize = crypto_skcipher_ivsize(skcipher);
caam_unmap(dev, req->src, req->dst, edesc->src_nents, edesc->dst_nents,
- edesc->iv_dma, ivsize, edesc->qm_sg_dma, edesc->qm_sg_bytes);
+ edesc->iv_dma, ivsize, DMA_BIDIRECTIONAL, edesc->qm_sg_dma,
+ edesc->qm_sg_bytes);
}
static void aead_encrypt_done(void *cbk_ctx, u32 status)
@@ -1324,7 +1360,7 @@ static void skcipher_encrypt_done(void *cbk_ctx, u32 status)
print_hex_dump_debug("dstiv @" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, req->iv,
edesc->src_nents > 1 ? 100 : ivsize, 1);
- caam_dump_sg(KERN_DEBUG, "dst @" __stringify(__LINE__)": ",
+ caam_dump_sg("dst @" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, req->dst,
edesc->dst_nents > 1 ? 100 : req->cryptlen, 1);
@@ -1332,10 +1368,10 @@ static void skcipher_encrypt_done(void *cbk_ctx, u32 status)
/*
* The crypto API expects us to set the IV (req->iv) to the last
- * ciphertext block. This is used e.g. by the CTS mode.
+ * ciphertext block (CBC mode) or last counter (CTR mode).
+ * This is used e.g. by the CTS mode.
*/
- scatterwalk_map_and_copy(req->iv, req->dst, req->cryptlen - ivsize,
- ivsize, 0);
+ memcpy(req->iv, (u8 *)&edesc->sgt[0] + edesc->qm_sg_bytes, ivsize);
qi_cache_free(edesc);
skcipher_request_complete(req, ecode);
@@ -1362,11 +1398,19 @@ static void skcipher_decrypt_done(void *cbk_ctx, u32 status)
print_hex_dump_debug("dstiv @" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, req->iv,
edesc->src_nents > 1 ? 100 : ivsize, 1);
- caam_dump_sg(KERN_DEBUG, "dst @" __stringify(__LINE__)": ",
+ caam_dump_sg("dst @" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, req->dst,
edesc->dst_nents > 1 ? 100 : req->cryptlen, 1);
skcipher_unmap(ctx->dev, edesc, req);
+
+ /*
+ * The crypto API expects us to set the IV (req->iv) to the last
+ * ciphertext block (CBC mode) or last counter (CTR mode).
+ * This is used e.g. by the CTS mode.
+ */
+ memcpy(req->iv, (u8 *)&edesc->sgt[0] + edesc->qm_sg_bytes, ivsize);
+
qi_cache_free(edesc);
skcipher_request_complete(req, ecode);
}
@@ -1405,7 +1449,6 @@ static int skcipher_decrypt(struct skcipher_request *req)
struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
struct caam_request *caam_req = skcipher_request_ctx(req);
- int ivsize = crypto_skcipher_ivsize(skcipher);
int ret;
/* allocate extended descriptor */
@@ -1413,13 +1456,6 @@ static int skcipher_decrypt(struct skcipher_request *req)
if (IS_ERR(edesc))
return PTR_ERR(edesc);
- /*
- * The crypto API expects us to set the IV (req->iv) to the last
- * ciphertext block.
- */
- scatterwalk_map_and_copy(req->iv, req->src, req->cryptlen - ivsize,
- ivsize, 0);
-
caam_req->flc = &ctx->flc[DECRYPT];
caam_req->flc_dma = ctx->flc_dma[DECRYPT];
caam_req->cbk = skcipher_decrypt_done;
@@ -3380,9 +3416,9 @@ static int ahash_update_ctx(struct ahash_request *req)
if (to_hash) {
struct dpaa2_sg_entry *sg_table;
+ int src_len = req->nbytes - *next_buflen;
- src_nents = sg_nents_for_len(req->src,
- req->nbytes - (*next_buflen));
+ src_nents = sg_nents_for_len(req->src, src_len);
if (src_nents < 0) {
dev_err(ctx->dev, "Invalid number of src SG.\n");
return src_nents;
@@ -3409,7 +3445,7 @@ static int ahash_update_ctx(struct ahash_request *req)
edesc->src_nents = src_nents;
qm_sg_src_index = 1 + (*buflen ? 1 : 0);
- qm_sg_bytes = (qm_sg_src_index + mapped_nents) *
+ qm_sg_bytes = pad_sg_nents(qm_sg_src_index + mapped_nents) *
sizeof(*sg_table);
sg_table = &edesc->sgt[0];
@@ -3423,7 +3459,7 @@ static int ahash_update_ctx(struct ahash_request *req)
goto unmap_ctx;
if (mapped_nents) {
- sg_to_qm_sg_last(req->src, mapped_nents,
+ sg_to_qm_sg_last(req->src, src_len,
sg_table + qm_sg_src_index, 0);
if (*next_buflen)
scatterwalk_map_and_copy(next_buf, req->src,
@@ -3494,7 +3530,7 @@ static int ahash_final_ctx(struct ahash_request *req)
gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
GFP_KERNEL : GFP_ATOMIC;
int buflen = *current_buflen(state);
- int qm_sg_bytes, qm_sg_src_index;
+ int qm_sg_bytes;
int digestsize = crypto_ahash_digestsize(ahash);
struct ahash_edesc *edesc;
struct dpaa2_sg_entry *sg_table;
@@ -3505,8 +3541,7 @@ static int ahash_final_ctx(struct ahash_request *req)
if (!edesc)
return -ENOMEM;
- qm_sg_src_index = 1 + (buflen ? 1 : 0);
- qm_sg_bytes = qm_sg_src_index * sizeof(*sg_table);
+ qm_sg_bytes = pad_sg_nents(1 + (buflen ? 1 : 0)) * sizeof(*sg_table);
sg_table = &edesc->sgt[0];
ret = ctx_map_to_qm_sg(ctx->dev, state, ctx->ctx_len, sg_table,
@@ -3518,7 +3553,7 @@ static int ahash_final_ctx(struct ahash_request *req)
if (ret)
goto unmap_ctx;
- dpaa2_sg_set_final(sg_table + qm_sg_src_index - 1, true);
+ dpaa2_sg_set_final(sg_table + (buflen ? 1 : 0), true);
edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table, qm_sg_bytes,
DMA_TO_DEVICE);
@@ -3599,7 +3634,8 @@ static int ahash_finup_ctx(struct ahash_request *req)
edesc->src_nents = src_nents;
qm_sg_src_index = 1 + (buflen ? 1 : 0);
- qm_sg_bytes = (qm_sg_src_index + mapped_nents) * sizeof(*sg_table);
+ qm_sg_bytes = pad_sg_nents(qm_sg_src_index + mapped_nents) *
+ sizeof(*sg_table);
sg_table = &edesc->sgt[0];
ret = ctx_map_to_qm_sg(ctx->dev, state, ctx->ctx_len, sg_table,
@@ -3611,7 +3647,7 @@ static int ahash_finup_ctx(struct ahash_request *req)
if (ret)
goto unmap_ctx;
- sg_to_qm_sg_last(req->src, mapped_nents, sg_table + qm_sg_src_index, 0);
+ sg_to_qm_sg_last(req->src, req->nbytes, sg_table + qm_sg_src_index, 0);
edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table, qm_sg_bytes,
DMA_TO_DEVICE);
@@ -3696,8 +3732,8 @@ static int ahash_digest(struct ahash_request *req)
int qm_sg_bytes;
struct dpaa2_sg_entry *sg_table = &edesc->sgt[0];
- qm_sg_bytes = mapped_nents * sizeof(*sg_table);
- sg_to_qm_sg_last(req->src, mapped_nents, sg_table, 0);
+ qm_sg_bytes = pad_sg_nents(mapped_nents) * sizeof(*sg_table);
+ sg_to_qm_sg_last(req->src, req->nbytes, sg_table, 0);
edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table,
qm_sg_bytes, DMA_TO_DEVICE);
if (dma_mapping_error(ctx->dev, edesc->qm_sg_dma)) {
@@ -3840,9 +3876,9 @@ static int ahash_update_no_ctx(struct ahash_request *req)
if (to_hash) {
struct dpaa2_sg_entry *sg_table;
+ int src_len = req->nbytes - *next_buflen;
- src_nents = sg_nents_for_len(req->src,
- req->nbytes - *next_buflen);
+ src_nents = sg_nents_for_len(req->src, src_len);
if (src_nents < 0) {
dev_err(ctx->dev, "Invalid number of src SG.\n");
return src_nents;
@@ -3868,14 +3904,15 @@ static int ahash_update_no_ctx(struct ahash_request *req)
}
edesc->src_nents = src_nents;
- qm_sg_bytes = (1 + mapped_nents) * sizeof(*sg_table);
+ qm_sg_bytes = pad_sg_nents(1 + mapped_nents) *
+ sizeof(*sg_table);
sg_table = &edesc->sgt[0];
ret = buf_map_to_qm_sg(ctx->dev, sg_table, state);
if (ret)
goto unmap_ctx;
- sg_to_qm_sg_last(req->src, mapped_nents, sg_table + 1, 0);
+ sg_to_qm_sg_last(req->src, src_len, sg_table + 1, 0);
if (*next_buflen)
scatterwalk_map_and_copy(next_buf, req->src,
@@ -3987,14 +4024,14 @@ static int ahash_finup_no_ctx(struct ahash_request *req)
}
edesc->src_nents = src_nents;
- qm_sg_bytes = (2 + mapped_nents) * sizeof(*sg_table);
+ qm_sg_bytes = pad_sg_nents(2 + mapped_nents) * sizeof(*sg_table);
sg_table = &edesc->sgt[0];
ret = buf_map_to_qm_sg(ctx->dev, sg_table, state);
if (ret)
goto unmap;
- sg_to_qm_sg_last(req->src, mapped_nents, sg_table + 1, 0);
+ sg_to_qm_sg_last(req->src, req->nbytes, sg_table + 1, 0);
edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table, qm_sg_bytes,
DMA_TO_DEVICE);
@@ -4064,9 +4101,9 @@ static int ahash_update_first(struct ahash_request *req)
if (to_hash) {
struct dpaa2_sg_entry *sg_table;
+ int src_len = req->nbytes - *next_buflen;
- src_nents = sg_nents_for_len(req->src,
- req->nbytes - (*next_buflen));
+ src_nents = sg_nents_for_len(req->src, src_len);
if (src_nents < 0) {
dev_err(ctx->dev, "Invalid number of src SG.\n");
return src_nents;
@@ -4101,8 +4138,9 @@ static int ahash_update_first(struct ahash_request *req)
if (mapped_nents > 1) {
int qm_sg_bytes;
- sg_to_qm_sg_last(req->src, mapped_nents, sg_table, 0);
- qm_sg_bytes = mapped_nents * sizeof(*sg_table);
+ sg_to_qm_sg_last(req->src, src_len, sg_table, 0);
+ qm_sg_bytes = pad_sg_nents(mapped_nents) *
+ sizeof(*sg_table);
edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table,
qm_sg_bytes,
DMA_TO_DEVICE);
diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c
index 7205d9f4029e..e4ac5d591ad6 100644
--- a/drivers/crypto/caam/caamhash.c
+++ b/drivers/crypto/caam/caamhash.c
@@ -82,14 +82,6 @@
#define HASH_MSG_LEN 8
#define MAX_CTX_LEN (HASH_MSG_LEN + SHA512_DIGEST_SIZE)
-#ifdef DEBUG
-/* for print_hex_dumps with line references */
-#define debug(format, arg...) printk(format, arg)
-#else
-#define debug(format, arg...)
-#endif
-
-
static struct list_head hash_list;
/* ahash per-session context */
@@ -243,11 +235,10 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash)
ctx->ctx_len, true, ctrlpriv->era);
dma_sync_single_for_device(jrdev, ctx->sh_desc_update_dma,
desc_bytes(desc), ctx->dir);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR,
- "ahash update shdesc@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
-#endif
+
+ print_hex_dump_debug("ahash update shdesc@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
+ 1);
/* ahash_update_first shared descriptor */
desc = ctx->sh_desc_update_first;
@@ -255,11 +246,9 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash)
ctx->ctx_len, false, ctrlpriv->era);
dma_sync_single_for_device(jrdev, ctx->sh_desc_update_first_dma,
desc_bytes(desc), ctx->dir);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR,
- "ahash update first shdesc@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
-#endif
+ print_hex_dump_debug("ahash update first shdesc@"__stringify(__LINE__)
+ ": ", DUMP_PREFIX_ADDRESS, 16, 4, desc,
+ desc_bytes(desc), 1);
/* ahash_final shared descriptor */
desc = ctx->sh_desc_fin;
@@ -267,11 +256,10 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash)
ctx->ctx_len, true, ctrlpriv->era);
dma_sync_single_for_device(jrdev, ctx->sh_desc_fin_dma,
desc_bytes(desc), ctx->dir);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "ahash final shdesc@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc,
- desc_bytes(desc), 1);
-#endif
+
+ print_hex_dump_debug("ahash final shdesc@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc,
+ desc_bytes(desc), 1);
/* ahash_digest shared descriptor */
desc = ctx->sh_desc_digest;
@@ -279,12 +267,10 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash)
ctx->ctx_len, false, ctrlpriv->era);
dma_sync_single_for_device(jrdev, ctx->sh_desc_digest_dma,
desc_bytes(desc), ctx->dir);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR,
- "ahash digest shdesc@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc,
- desc_bytes(desc), 1);
-#endif
+
+ print_hex_dump_debug("ahash digest shdesc@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc,
+ desc_bytes(desc), 1);
return 0;
}
@@ -328,9 +314,9 @@ static int axcbc_set_sh_desc(struct crypto_ahash *ahash)
ctx->ctx_len, ctx->key_dma);
dma_sync_single_for_device(jrdev, ctx->sh_desc_update_first_dma,
desc_bytes(desc), ctx->dir);
- print_hex_dump_debug("axcbc update first shdesc@" __stringify(__LINE__)" : ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
- 1);
+ print_hex_dump_debug("axcbc update first shdesc@" __stringify(__LINE__)
+ " : ", DUMP_PREFIX_ADDRESS, 16, 4, desc,
+ desc_bytes(desc), 1);
/* shared descriptor for ahash_digest */
desc = ctx->sh_desc_digest;
@@ -377,8 +363,8 @@ static int acmac_set_sh_desc(struct crypto_ahash *ahash)
ctx->ctx_len, 0);
dma_sync_single_for_device(jrdev, ctx->sh_desc_update_first_dma,
desc_bytes(desc), ctx->dir);
- print_hex_dump_debug("acmac update first shdesc@" __stringify(__LINE__)" : ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc,
+ print_hex_dump_debug("acmac update first shdesc@" __stringify(__LINE__)
+ " : ", DUMP_PREFIX_ADDRESS, 16, 4, desc,
desc_bytes(desc), 1);
/* shared descriptor for ahash_digest */
@@ -429,12 +415,11 @@ static int hash_digest_key(struct caam_hash_ctx *ctx, u32 *keylen, u8 *key,
append_seq_store(desc, digestsize, LDST_CLASS_2_CCB |
LDST_SRCDST_BYTE_CONTEXT);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "key_in@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, key, *keylen, 1);
- print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
-#endif
+ print_hex_dump_debug("key_in@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, key, *keylen, 1);
+ print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
+ 1);
result.err = 0;
init_completion(&result.completion);
@@ -444,11 +429,10 @@ static int hash_digest_key(struct caam_hash_ctx *ctx, u32 *keylen, u8 *key,
/* in progress */
wait_for_completion(&result.completion);
ret = result.err;
-#ifdef DEBUG
- print_hex_dump(KERN_ERR,
- "digested key@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, key, digestsize, 1);
-#endif
+
+ print_hex_dump_debug("digested key@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, key,
+ digestsize, 1);
}
dma_unmap_single(jrdev, key_dma, *keylen, DMA_BIDIRECTIONAL);
@@ -463,15 +447,14 @@ static int ahash_setkey(struct crypto_ahash *ahash,
const u8 *key, unsigned int keylen)
{
struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
+ struct device *jrdev = ctx->jrdev;
int blocksize = crypto_tfm_alg_blocksize(&ahash->base);
int digestsize = crypto_ahash_digestsize(ahash);
struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctx->jrdev->parent);
int ret;
u8 *hashed_key = NULL;
-#ifdef DEBUG
- printk(KERN_ERR "keylen %d\n", keylen);
-#endif
+ dev_dbg(jrdev, "keylen %d\n", keylen);
if (keylen > blocksize) {
hashed_key = kmemdup(key, keylen, GFP_KERNEL | GFP_DMA);
@@ -600,11 +583,9 @@ static void ahash_done(struct device *jrdev, u32 *desc, u32 err,
struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
int digestsize = crypto_ahash_digestsize(ahash);
struct caam_hash_state *state = ahash_request_ctx(req);
-#ifdef DEBUG
struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
- dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
-#endif
+ dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
edesc = container_of(desc, struct ahash_edesc, hw_desc[0]);
if (err)
@@ -614,11 +595,9 @@ static void ahash_done(struct device *jrdev, u32 *desc, u32 err,
memcpy(req->result, state->caam_ctx, digestsize);
kfree(edesc);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "ctx@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx,
- ctx->ctx_len, 1);
-#endif
+ print_hex_dump_debug("ctx@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx,
+ ctx->ctx_len, 1);
req->base.complete(&req->base, err);
}
@@ -631,11 +610,9 @@ static void ahash_done_bi(struct device *jrdev, u32 *desc, u32 err,
struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
struct caam_hash_state *state = ahash_request_ctx(req);
-#ifdef DEBUG
int digestsize = crypto_ahash_digestsize(ahash);
- dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
-#endif
+ dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
edesc = container_of(desc, struct ahash_edesc, hw_desc[0]);
if (err)
@@ -645,15 +622,13 @@ static void ahash_done_bi(struct device *jrdev, u32 *desc, u32 err,
switch_buf(state);
kfree(edesc);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "ctx@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx,
- ctx->ctx_len, 1);
+ print_hex_dump_debug("ctx@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx,
+ ctx->ctx_len, 1);
if (req->result)
- print_hex_dump(KERN_ERR, "result@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, req->result,
- digestsize, 1);
-#endif
+ print_hex_dump_debug("result@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, req->result,
+ digestsize, 1);
req->base.complete(&req->base, err);
}
@@ -666,11 +641,9 @@ static void ahash_done_ctx_src(struct device *jrdev, u32 *desc, u32 err,
struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
int digestsize = crypto_ahash_digestsize(ahash);
struct caam_hash_state *state = ahash_request_ctx(req);
-#ifdef DEBUG
struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
- dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
-#endif
+ dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
edesc = container_of(desc, struct ahash_edesc, hw_desc[0]);
if (err)
@@ -680,11 +653,9 @@ static void ahash_done_ctx_src(struct device *jrdev, u32 *desc, u32 err,
memcpy(req->result, state->caam_ctx, digestsize);
kfree(edesc);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "ctx@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx,
- ctx->ctx_len, 1);
-#endif
+ print_hex_dump_debug("ctx@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx,
+ ctx->ctx_len, 1);
req->base.complete(&req->base, err);
}
@@ -697,11 +668,9 @@ static void ahash_done_ctx_dst(struct device *jrdev, u32 *desc, u32 err,
struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
struct caam_hash_state *state = ahash_request_ctx(req);
-#ifdef DEBUG
int digestsize = crypto_ahash_digestsize(ahash);
- dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
-#endif
+ dev_dbg(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
edesc = container_of(desc, struct ahash_edesc, hw_desc[0]);
if (err)
@@ -711,15 +680,13 @@ static void ahash_done_ctx_dst(struct device *jrdev, u32 *desc, u32 err,
switch_buf(state);
kfree(edesc);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "ctx@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx,
- ctx->ctx_len, 1);
+ print_hex_dump_debug("ctx@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx,
+ ctx->ctx_len, 1);
if (req->result)
- print_hex_dump(KERN_ERR, "result@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, req->result,
- digestsize, 1);
-#endif
+ print_hex_dump_debug("result@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, req->result,
+ digestsize, 1);
req->base.complete(&req->base, err);
}
@@ -759,9 +726,10 @@ static int ahash_edesc_add_src(struct caam_hash_ctx *ctx,
if (nents > 1 || first_sg) {
struct sec4_sg_entry *sg = edesc->sec4_sg;
- unsigned int sgsize = sizeof(*sg) * (first_sg + nents);
+ unsigned int sgsize = sizeof(*sg) *
+ pad_sg_nents(first_sg + nents);
- sg_to_sec4_sg_last(req->src, nents, sg + first_sg, 0);
+ sg_to_sec4_sg_last(req->src, to_hash, sg + first_sg, 0);
src_dma = dma_map_single(ctx->jrdev, sg, sgsize, DMA_TO_DEVICE);
if (dma_mapping_error(ctx->jrdev, src_dma)) {
@@ -819,8 +787,10 @@ static int ahash_update_ctx(struct ahash_request *req)
}
if (to_hash) {
- src_nents = sg_nents_for_len(req->src,
- req->nbytes - (*next_buflen));
+ int pad_nents;
+ int src_len = req->nbytes - *next_buflen;
+
+ src_nents = sg_nents_for_len(req->src, src_len);
if (src_nents < 0) {
dev_err(jrdev, "Invalid number of src SG.\n");
return src_nents;
@@ -838,15 +808,14 @@ static int ahash_update_ctx(struct ahash_request *req)
}
sec4_sg_src_index = 1 + (*buflen ? 1 : 0);
- sec4_sg_bytes = (sec4_sg_src_index + mapped_nents) *
- sizeof(struct sec4_sg_entry);
+ pad_nents = pad_sg_nents(sec4_sg_src_index + mapped_nents);
+ sec4_sg_bytes = pad_nents * sizeof(struct sec4_sg_entry);
/*
* allocate space for base edesc and hw desc commands,
* link tables
*/
- edesc = ahash_edesc_alloc(ctx, sec4_sg_src_index + mapped_nents,
- ctx->sh_desc_update,
+ edesc = ahash_edesc_alloc(ctx, pad_nents, ctx->sh_desc_update,
ctx->sh_desc_update_dma, flags);
if (!edesc) {
dma_unmap_sg(jrdev, req->src, src_nents, DMA_TO_DEVICE);
@@ -866,7 +835,7 @@ static int ahash_update_ctx(struct ahash_request *req)
goto unmap_ctx;
if (mapped_nents)
- sg_to_sec4_sg_last(req->src, mapped_nents,
+ sg_to_sec4_sg_last(req->src, src_len,
edesc->sec4_sg + sec4_sg_src_index,
0);
else
@@ -893,11 +862,9 @@ static int ahash_update_ctx(struct ahash_request *req)
append_seq_out_ptr(desc, state->ctx_dma, ctx->ctx_len, 0);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc,
- desc_bytes(desc), 1);
-#endif
+ print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc,
+ desc_bytes(desc), 1);
ret = caam_jr_enqueue(jrdev, desc, ahash_done_bi, req);
if (ret)
@@ -910,13 +877,12 @@ static int ahash_update_ctx(struct ahash_request *req)
*buflen = *next_buflen;
*next_buflen = last_buflen;
}
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "buf@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, buf, *buflen, 1);
- print_hex_dump(KERN_ERR, "next buf@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, next_buf,
- *next_buflen, 1);
-#endif
+
+ print_hex_dump_debug("buf@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, buf, *buflen, 1);
+ print_hex_dump_debug("next buf@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, next_buf,
+ *next_buflen, 1);
return ret;
unmap_ctx:
@@ -935,18 +901,17 @@ static int ahash_final_ctx(struct ahash_request *req)
GFP_KERNEL : GFP_ATOMIC;
int buflen = *current_buflen(state);
u32 *desc;
- int sec4_sg_bytes, sec4_sg_src_index;
+ int sec4_sg_bytes;
int digestsize = crypto_ahash_digestsize(ahash);
struct ahash_edesc *edesc;
int ret;
- sec4_sg_src_index = 1 + (buflen ? 1 : 0);
- sec4_sg_bytes = sec4_sg_src_index * sizeof(struct sec4_sg_entry);
+ sec4_sg_bytes = pad_sg_nents(1 + (buflen ? 1 : 0)) *
+ sizeof(struct sec4_sg_entry);
/* allocate space for base edesc and hw desc commands, link tables */
- edesc = ahash_edesc_alloc(ctx, sec4_sg_src_index,
- ctx->sh_desc_fin, ctx->sh_desc_fin_dma,
- flags);
+ edesc = ahash_edesc_alloc(ctx, 4, ctx->sh_desc_fin,
+ ctx->sh_desc_fin_dma, flags);
if (!edesc)
return -ENOMEM;
@@ -963,7 +928,7 @@ static int ahash_final_ctx(struct ahash_request *req)
if (ret)
goto unmap_ctx;
- sg_to_sec4_set_last(edesc->sec4_sg + sec4_sg_src_index - 1);
+ sg_to_sec4_set_last(edesc->sec4_sg + (buflen ? 1 : 0));
edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg,
sec4_sg_bytes, DMA_TO_DEVICE);
@@ -977,10 +942,9 @@ static int ahash_final_ctx(struct ahash_request *req)
LDST_SGF);
append_seq_out_ptr(desc, state->ctx_dma, digestsize, 0);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
-#endif
+ print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
+ 1);
ret = caam_jr_enqueue(jrdev, desc, ahash_done_ctx_src, req);
if (ret)
@@ -1058,10 +1022,9 @@ static int ahash_finup_ctx(struct ahash_request *req)
append_seq_out_ptr(desc, state->ctx_dma, digestsize, 0);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
-#endif
+ print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
+ 1);
ret = caam_jr_enqueue(jrdev, desc, ahash_done_ctx_src, req);
if (ret)
@@ -1135,10 +1098,9 @@ static int ahash_digest(struct ahash_request *req)
return -ENOMEM;
}
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
-#endif
+ print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
+ 1);
ret = caam_jr_enqueue(jrdev, desc, ahash_done, req);
if (!ret) {
@@ -1190,10 +1152,9 @@ static int ahash_final_no_ctx(struct ahash_request *req)
if (ret)
goto unmap;
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
-#endif
+ print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
+ 1);
ret = caam_jr_enqueue(jrdev, desc, ahash_done, req);
if (!ret) {
@@ -1246,8 +1207,10 @@ static int ahash_update_no_ctx(struct ahash_request *req)
}
if (to_hash) {
- src_nents = sg_nents_for_len(req->src,
- req->nbytes - *next_buflen);
+ int pad_nents;
+ int src_len = req->nbytes - *next_buflen;
+
+ src_nents = sg_nents_for_len(req->src, src_len);
if (src_nents < 0) {
dev_err(jrdev, "Invalid number of src SG.\n");
return src_nents;
@@ -1264,14 +1227,14 @@ static int ahash_update_no_ctx(struct ahash_request *req)
mapped_nents = 0;
}
- sec4_sg_bytes = (1 + mapped_nents) *
- sizeof(struct sec4_sg_entry);
+ pad_nents = pad_sg_nents(1 + mapped_nents);
+ sec4_sg_bytes = pad_nents * sizeof(struct sec4_sg_entry);
/*
* allocate space for base edesc and hw desc commands,
* link tables
*/
- edesc = ahash_edesc_alloc(ctx, 1 + mapped_nents,
+ edesc = ahash_edesc_alloc(ctx, pad_nents,
ctx->sh_desc_update_first,
ctx->sh_desc_update_first_dma,
flags);
@@ -1287,8 +1250,7 @@ static int ahash_update_no_ctx(struct ahash_request *req)
if (ret)
goto unmap_ctx;
- sg_to_sec4_sg_last(req->src, mapped_nents,
- edesc->sec4_sg + 1, 0);
+ sg_to_sec4_sg_last(req->src, src_len, edesc->sec4_sg + 1, 0);
if (*next_buflen) {
scatterwalk_map_and_copy(next_buf, req->src,
@@ -1313,11 +1275,9 @@ static int ahash_update_no_ctx(struct ahash_request *req)
if (ret)
goto unmap_ctx;
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc,
- desc_bytes(desc), 1);
-#endif
+ print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc,
+ desc_bytes(desc), 1);
ret = caam_jr_enqueue(jrdev, desc, ahash_done_ctx_dst, req);
if (ret)
@@ -1333,13 +1293,12 @@ static int ahash_update_no_ctx(struct ahash_request *req)
*buflen = *next_buflen;
*next_buflen = 0;
}
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "buf@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, buf, *buflen, 1);
- print_hex_dump(KERN_ERR, "next buf@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, next_buf,
- *next_buflen, 1);
-#endif
+
+ print_hex_dump_debug("buf@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, buf, *buflen, 1);
+ print_hex_dump_debug("next buf@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, next_buf, *next_buflen,
+ 1);
return ret;
unmap_ctx:
@@ -1414,10 +1373,9 @@ static int ahash_finup_no_ctx(struct ahash_request *req)
if (ret)
goto unmap;
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
-#endif
+ print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
+ 1);
ret = caam_jr_enqueue(jrdev, desc, ahash_done, req);
if (!ret) {
@@ -1517,11 +1475,9 @@ static int ahash_update_first(struct ahash_request *req)
if (ret)
goto unmap_ctx;
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc,
- desc_bytes(desc), 1);
-#endif
+ print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc,
+ desc_bytes(desc), 1);
ret = caam_jr_enqueue(jrdev, desc, ahash_done_ctx_dst, req);
if (ret)
@@ -1539,11 +1495,10 @@ static int ahash_update_first(struct ahash_request *req)
req->nbytes, 0);
switch_buf(state);
}
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "next buf@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, next_buf,
- *next_buflen, 1);
-#endif
+
+ print_hex_dump_debug("next buf@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, next_buf, *next_buflen,
+ 1);
return ret;
unmap_ctx:
@@ -1930,7 +1885,7 @@ static void caam_hash_cra_exit(struct crypto_tfm *tfm)
caam_jr_free(ctx->jrdev);
}
-static void __exit caam_algapi_hash_exit(void)
+void caam_algapi_hash_exit(void)
{
struct caam_hash_alg *t_alg, *n;
@@ -1988,40 +1943,13 @@ caam_hash_alloc(struct caam_hash_template *template,
return t_alg;
}
-static int __init caam_algapi_hash_init(void)
+int caam_algapi_hash_init(struct device *ctrldev)
{
- struct device_node *dev_node;
- struct platform_device *pdev;
int i = 0, err = 0;
- struct caam_drv_private *priv;
+ struct caam_drv_private *priv = dev_get_drvdata(ctrldev);
unsigned int md_limit = SHA512_DIGEST_SIZE;
u32 md_inst, md_vid;
- dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
- if (!dev_node) {
- dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
- if (!dev_node)
- return -ENODEV;
- }
-
- pdev = of_find_device_by_node(dev_node);
- if (!pdev) {
- of_node_put(dev_node);
- return -ENODEV;
- }
-
- priv = dev_get_drvdata(&pdev->dev);
- of_node_put(dev_node);
-
- /*
- * If priv is NULL, it's probably because the caam driver wasn't
- * properly initialized (e.g. RNG4 init failed). Thus, bail out here.
- */
- if (!priv) {
- err = -ENODEV;
- goto out_put_dev;
- }
-
/*
* Register crypto algorithms the device supports. First, identify
* presence and attributes of MD block.
@@ -2042,10 +1970,8 @@ static int __init caam_algapi_hash_init(void)
* Skip registration of any hashing algorithms if MD block
* is not present.
*/
- if (!md_inst) {
- err = -ENODEV;
- goto out_put_dev;
- }
+ if (!md_inst)
+ return -ENODEV;
/* Limit digest size based on LP256 */
if (md_vid == CHA_VER_VID_MD_LP256)
@@ -2102,14 +2028,5 @@ static int __init caam_algapi_hash_init(void)
list_add_tail(&t_alg->entry, &hash_list);
}
-out_put_dev:
- put_device(&pdev->dev);
return err;
}
-
-module_init(caam_algapi_hash_init);
-module_exit(caam_algapi_hash_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("FSL CAAM support for ahash functions of crypto API");
-MODULE_AUTHOR("Freescale Semiconductor - NMG");
diff --git a/drivers/crypto/caam/caampkc.c b/drivers/crypto/caam/caampkc.c
index fe24485274e1..80574106af29 100644
--- a/drivers/crypto/caam/caampkc.c
+++ b/drivers/crypto/caam/caampkc.c
@@ -3,7 +3,7 @@
* caam - Freescale FSL CAAM support for Public Key Cryptography
*
* Copyright 2016 Freescale Semiconductor, Inc.
- * Copyright 2018 NXP
+ * Copyright 2018-2019 NXP
*
* There is no Shared Descriptor for PKC so that the Job Descriptor must carry
* all the desired key parameters, input and output pointers.
@@ -24,12 +24,18 @@
sizeof(struct rsa_priv_f2_pdb))
#define DESC_RSA_PRIV_F3_LEN (2 * CAAM_CMD_SZ + \
sizeof(struct rsa_priv_f3_pdb))
+#define CAAM_RSA_MAX_INPUT_SIZE 512 /* for a 4096-bit modulus */
+
+/* buffer filled with zeros, used for padding */
+static u8 *zero_buffer;
static void rsa_io_unmap(struct device *dev, struct rsa_edesc *edesc,
struct akcipher_request *req)
{
+ struct caam_rsa_req_ctx *req_ctx = akcipher_request_ctx(req);
+
dma_unmap_sg(dev, req->dst, edesc->dst_nents, DMA_FROM_DEVICE);
- dma_unmap_sg(dev, req->src, edesc->src_nents, DMA_TO_DEVICE);
+ dma_unmap_sg(dev, req_ctx->fixup_src, edesc->src_nents, DMA_TO_DEVICE);
if (edesc->sec4_sg_bytes)
dma_unmap_single(dev, edesc->sec4_sg_dma, edesc->sec4_sg_bytes,
@@ -168,6 +174,13 @@ static void rsa_priv_f3_done(struct device *dev, u32 *desc, u32 err,
akcipher_request_complete(req, err);
}
+/**
+ * Count leading zeros, need it to strip, from a given scatterlist
+ *
+ * @sgl : scatterlist to count zeros from
+ * @nbytes: number of zeros, in bytes, to strip
+ * @flags : operation flags
+ */
static int caam_rsa_count_leading_zeros(struct scatterlist *sgl,
unsigned int nbytes,
unsigned int flags)
@@ -187,7 +200,8 @@ static int caam_rsa_count_leading_zeros(struct scatterlist *sgl,
lzeros = 0;
len = 0;
while (nbytes > 0) {
- while (len && !*buff) {
+ /* do not strip more than given bytes */
+ while (len && !*buff && lzeros < nbytes) {
lzeros++;
len--;
buff++;
@@ -218,6 +232,7 @@ static struct rsa_edesc *rsa_edesc_alloc(struct akcipher_request *req,
struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
struct device *dev = ctx->dev;
struct caam_rsa_req_ctx *req_ctx = akcipher_request_ctx(req);
+ struct caam_rsa_key *key = &ctx->key;
struct rsa_edesc *edesc;
gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
GFP_KERNEL : GFP_ATOMIC;
@@ -225,22 +240,45 @@ static struct rsa_edesc *rsa_edesc_alloc(struct akcipher_request *req,
int sgc;
int sec4_sg_index, sec4_sg_len = 0, sec4_sg_bytes;
int src_nents, dst_nents;
+ unsigned int diff_size = 0;
int lzeros;
- lzeros = caam_rsa_count_leading_zeros(req->src, req->src_len, sg_flags);
- if (lzeros < 0)
- return ERR_PTR(lzeros);
-
- req->src_len -= lzeros;
- req->src = scatterwalk_ffwd(req_ctx->src, req->src, lzeros);
+ if (req->src_len > key->n_sz) {
+ /*
+ * strip leading zeros and
+ * return the number of zeros to skip
+ */
+ lzeros = caam_rsa_count_leading_zeros(req->src, req->src_len -
+ key->n_sz, sg_flags);
+ if (lzeros < 0)
+ return ERR_PTR(lzeros);
+
+ req_ctx->fixup_src = scatterwalk_ffwd(req_ctx->src, req->src,
+ lzeros);
+ req_ctx->fixup_src_len = req->src_len - lzeros;
+ } else {
+ /*
+ * input src is less then n key modulus,
+ * so there will be zero padding
+ */
+ diff_size = key->n_sz - req->src_len;
+ req_ctx->fixup_src = req->src;
+ req_ctx->fixup_src_len = req->src_len;
+ }
- src_nents = sg_nents_for_len(req->src, req->src_len);
+ src_nents = sg_nents_for_len(req_ctx->fixup_src,
+ req_ctx->fixup_src_len);
dst_nents = sg_nents_for_len(req->dst, req->dst_len);
- if (src_nents > 1)
- sec4_sg_len = src_nents;
+ if (!diff_size && src_nents == 1)
+ sec4_sg_len = 0; /* no need for an input hw s/g table */
+ else
+ sec4_sg_len = src_nents + !!diff_size;
+ sec4_sg_index = sec4_sg_len;
if (dst_nents > 1)
- sec4_sg_len += dst_nents;
+ sec4_sg_len += pad_sg_nents(dst_nents);
+ else
+ sec4_sg_len = pad_sg_nents(sec4_sg_len);
sec4_sg_bytes = sec4_sg_len * sizeof(struct sec4_sg_entry);
@@ -250,7 +288,7 @@ static struct rsa_edesc *rsa_edesc_alloc(struct akcipher_request *req,
if (!edesc)
return ERR_PTR(-ENOMEM);
- sgc = dma_map_sg(dev, req->src, src_nents, DMA_TO_DEVICE);
+ sgc = dma_map_sg(dev, req_ctx->fixup_src, src_nents, DMA_TO_DEVICE);
if (unlikely(!sgc)) {
dev_err(dev, "unable to map source\n");
goto src_fail;
@@ -263,14 +301,16 @@ static struct rsa_edesc *rsa_edesc_alloc(struct akcipher_request *req,
}
edesc->sec4_sg = (void *)edesc + sizeof(*edesc) + desclen;
+ if (diff_size)
+ dma_to_sec4_sg_one(edesc->sec4_sg, ctx->padding_dma, diff_size,
+ 0);
+
+ if (sec4_sg_index)
+ sg_to_sec4_sg_last(req_ctx->fixup_src, req_ctx->fixup_src_len,
+ edesc->sec4_sg + !!diff_size, 0);
- sec4_sg_index = 0;
- if (src_nents > 1) {
- sg_to_sec4_sg_last(req->src, src_nents, edesc->sec4_sg, 0);
- sec4_sg_index += src_nents;
- }
if (dst_nents > 1)
- sg_to_sec4_sg_last(req->dst, dst_nents,
+ sg_to_sec4_sg_last(req->dst, req->dst_len,
edesc->sec4_sg + sec4_sg_index, 0);
/* Save nents for later use in Job Descriptor */
@@ -289,12 +329,16 @@ static struct rsa_edesc *rsa_edesc_alloc(struct akcipher_request *req,
edesc->sec4_sg_bytes = sec4_sg_bytes;
+ print_hex_dump_debug("caampkc sec4_sg@" __stringify(__LINE__) ": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, edesc->sec4_sg,
+ edesc->sec4_sg_bytes, 1);
+
return edesc;
sec4_sg_fail:
dma_unmap_sg(dev, req->dst, dst_nents, DMA_FROM_DEVICE);
dst_fail:
- dma_unmap_sg(dev, req->src, src_nents, DMA_TO_DEVICE);
+ dma_unmap_sg(dev, req_ctx->fixup_src, src_nents, DMA_TO_DEVICE);
src_fail:
kfree(edesc);
return ERR_PTR(-ENOMEM);
@@ -304,6 +348,7 @@ static int set_rsa_pub_pdb(struct akcipher_request *req,
struct rsa_edesc *edesc)
{
struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+ struct caam_rsa_req_ctx *req_ctx = akcipher_request_ctx(req);
struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
struct caam_rsa_key *key = &ctx->key;
struct device *dev = ctx->dev;
@@ -328,7 +373,7 @@ static int set_rsa_pub_pdb(struct akcipher_request *req,
pdb->f_dma = edesc->sec4_sg_dma;
sec4_sg_index += edesc->src_nents;
} else {
- pdb->f_dma = sg_dma_address(req->src);
+ pdb->f_dma = sg_dma_address(req_ctx->fixup_src);
}
if (edesc->dst_nents > 1) {
@@ -340,7 +385,7 @@ static int set_rsa_pub_pdb(struct akcipher_request *req,
}
pdb->sgf |= (key->e_sz << RSA_PDB_E_SHIFT) | key->n_sz;
- pdb->f_len = req->src_len;
+ pdb->f_len = req_ctx->fixup_src_len;
return 0;
}
@@ -373,7 +418,9 @@ static int set_rsa_priv_f1_pdb(struct akcipher_request *req,
pdb->g_dma = edesc->sec4_sg_dma;
sec4_sg_index += edesc->src_nents;
} else {
- pdb->g_dma = sg_dma_address(req->src);
+ struct caam_rsa_req_ctx *req_ctx = akcipher_request_ctx(req);
+
+ pdb->g_dma = sg_dma_address(req_ctx->fixup_src);
}
if (edesc->dst_nents > 1) {
@@ -436,7 +483,9 @@ static int set_rsa_priv_f2_pdb(struct akcipher_request *req,
pdb->g_dma = edesc->sec4_sg_dma;
sec4_sg_index += edesc->src_nents;
} else {
- pdb->g_dma = sg_dma_address(req->src);
+ struct caam_rsa_req_ctx *req_ctx = akcipher_request_ctx(req);
+
+ pdb->g_dma = sg_dma_address(req_ctx->fixup_src);
}
if (edesc->dst_nents > 1) {
@@ -523,7 +572,9 @@ static int set_rsa_priv_f3_pdb(struct akcipher_request *req,
pdb->g_dma = edesc->sec4_sg_dma;
sec4_sg_index += edesc->src_nents;
} else {
- pdb->g_dma = sg_dma_address(req->src);
+ struct caam_rsa_req_ctx *req_ctx = akcipher_request_ctx(req);
+
+ pdb->g_dma = sg_dma_address(req_ctx->fixup_src);
}
if (edesc->dst_nents > 1) {
@@ -978,6 +1029,15 @@ static int caam_rsa_init_tfm(struct crypto_akcipher *tfm)
return PTR_ERR(ctx->dev);
}
+ ctx->padding_dma = dma_map_single(ctx->dev, zero_buffer,
+ CAAM_RSA_MAX_INPUT_SIZE - 1,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(ctx->dev, ctx->padding_dma)) {
+ dev_err(ctx->dev, "unable to map padding\n");
+ caam_jr_free(ctx->dev);
+ return -ENOMEM;
+ }
+
return 0;
}
@@ -987,6 +1047,8 @@ static void caam_rsa_exit_tfm(struct crypto_akcipher *tfm)
struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
struct caam_rsa_key *key = &ctx->key;
+ dma_unmap_single(ctx->dev, ctx->padding_dma, CAAM_RSA_MAX_INPUT_SIZE -
+ 1, DMA_TO_DEVICE);
caam_rsa_free_key(key);
caam_jr_free(ctx->dev);
}
@@ -1010,41 +1072,12 @@ static struct akcipher_alg caam_rsa = {
};
/* Public Key Cryptography module initialization handler */
-static int __init caam_pkc_init(void)
+int caam_pkc_init(struct device *ctrldev)
{
- struct device_node *dev_node;
- struct platform_device *pdev;
- struct device *ctrldev;
- struct caam_drv_private *priv;
+ struct caam_drv_private *priv = dev_get_drvdata(ctrldev);
u32 pk_inst;
int err;
- dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
- if (!dev_node) {
- dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
- if (!dev_node)
- return -ENODEV;
- }
-
- pdev = of_find_device_by_node(dev_node);
- if (!pdev) {
- of_node_put(dev_node);
- return -ENODEV;
- }
-
- ctrldev = &pdev->dev;
- priv = dev_get_drvdata(ctrldev);
- of_node_put(dev_node);
-
- /*
- * If priv is NULL, it's probably because the caam driver wasn't
- * properly initialized (e.g. RNG4 init failed). Thus, bail out here.
- */
- if (!priv) {
- err = -ENODEV;
- goto out_put_dev;
- }
-
/* Determine public key hardware accelerator presence. */
if (priv->era < 10)
pk_inst = (rd_reg32(&priv->ctrl->perfmon.cha_num_ls) &
@@ -1053,31 +1086,29 @@ static int __init caam_pkc_init(void)
pk_inst = rd_reg32(&priv->ctrl->vreg.pkha) & CHA_VER_NUM_MASK;
/* Do not register algorithms if PKHA is not present. */
- if (!pk_inst) {
- err = -ENODEV;
- goto out_put_dev;
- }
+ if (!pk_inst)
+ return 0;
+
+ /* allocate zero buffer, used for padding input */
+ zero_buffer = kzalloc(CAAM_RSA_MAX_INPUT_SIZE - 1, GFP_DMA |
+ GFP_KERNEL);
+ if (!zero_buffer)
+ return -ENOMEM;
err = crypto_register_akcipher(&caam_rsa);
- if (err)
+ if (err) {
+ kfree(zero_buffer);
dev_warn(ctrldev, "%s alg registration failed\n",
caam_rsa.base.cra_driver_name);
- else
+ } else {
dev_info(ctrldev, "caam pkc algorithms registered in /proc/crypto\n");
+ }
-out_put_dev:
- put_device(ctrldev);
return err;
}
-static void __exit caam_pkc_exit(void)
+void caam_pkc_exit(void)
{
+ kfree(zero_buffer);
crypto_unregister_akcipher(&caam_rsa);
}
-
-module_init(caam_pkc_init);
-module_exit(caam_pkc_exit);
-
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_DESCRIPTION("FSL CAAM support for PKC functions of crypto API");
-MODULE_AUTHOR("Freescale Semiconductor");
diff --git a/drivers/crypto/caam/caampkc.h b/drivers/crypto/caam/caampkc.h
index 82645bcf8b27..2c488c9a3812 100644
--- a/drivers/crypto/caam/caampkc.h
+++ b/drivers/crypto/caam/caampkc.h
@@ -89,18 +89,25 @@ struct caam_rsa_key {
* caam_rsa_ctx - per session 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 caam_rsa_key key;
struct device *dev;
+ dma_addr_t padding_dma;
+
};
/**
* caam_rsa_req_ctx - per request context.
- * @src: input scatterlist (stripped of leading zeros)
+ * @src : input scatterlist (stripped of leading zeros)
+ * @fixup_src : input scatterlist (that might be stripped of leading zeros)
+ * @fixup_src_len : length of the fixup_src input scatterlist
*/
struct caam_rsa_req_ctx {
struct scatterlist src[2];
+ struct scatterlist *fixup_src;
+ unsigned int fixup_src_len;
};
/**
diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c
index 95eb5402c59f..561bcb535184 100644
--- a/drivers/crypto/caam/caamrng.c
+++ b/drivers/crypto/caam/caamrng.c
@@ -3,7 +3,7 @@
* caam - Freescale FSL CAAM support for hw_random
*
* Copyright 2011 Freescale Semiconductor, Inc.
- * Copyright 2018 NXP
+ * Copyright 2018-2019 NXP
*
* Based on caamalg.c crypto API driver.
*
@@ -113,10 +113,8 @@ static void rng_done(struct device *jrdev, u32 *desc, u32 err, void *context)
/* Buffer refilled, invalidate cache */
dma_sync_single_for_cpu(jrdev, bd->addr, RN_BUF_SIZE, DMA_FROM_DEVICE);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "rng refreshed buf@: ",
- DUMP_PREFIX_ADDRESS, 16, 4, bd->buf, RN_BUF_SIZE, 1);
-#endif
+ print_hex_dump_debug("rng refreshed buf@: ", DUMP_PREFIX_ADDRESS, 16, 4,
+ bd->buf, RN_BUF_SIZE, 1);
}
static inline int submit_job(struct caam_rng_ctx *ctx, int to_current)
@@ -209,10 +207,10 @@ static inline int rng_create_sh_desc(struct caam_rng_ctx *ctx)
dev_err(jrdev, "unable to map shared descriptor\n");
return -ENOMEM;
}
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "rng shdesc@: ", DUMP_PREFIX_ADDRESS, 16, 4,
- desc, desc_bytes(desc), 1);
-#endif
+
+ print_hex_dump_debug("rng shdesc@: ", DUMP_PREFIX_ADDRESS, 16, 4,
+ desc, desc_bytes(desc), 1);
+
return 0;
}
@@ -233,10 +231,10 @@ static inline int rng_create_job_desc(struct caam_rng_ctx *ctx, int buf_id)
}
append_seq_out_ptr_intlen(desc, bd->addr, RN_BUF_SIZE, 0);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "rng job desc@: ", DUMP_PREFIX_ADDRESS, 16, 4,
- desc, desc_bytes(desc), 1);
-#endif
+
+ print_hex_dump_debug("rng job desc@: ", DUMP_PREFIX_ADDRESS, 16, 4,
+ desc, desc_bytes(desc), 1);
+
return 0;
}
@@ -296,47 +294,20 @@ static struct hwrng caam_rng = {
.read = caam_read,
};
-static void __exit caam_rng_exit(void)
+void caam_rng_exit(void)
{
caam_jr_free(rng_ctx->jrdev);
hwrng_unregister(&caam_rng);
kfree(rng_ctx);
}
-static int __init caam_rng_init(void)
+int caam_rng_init(struct device *ctrldev)
{
struct device *dev;
- struct device_node *dev_node;
- struct platform_device *pdev;
- struct caam_drv_private *priv;
u32 rng_inst;
+ struct caam_drv_private *priv = dev_get_drvdata(ctrldev);
int err;
- dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
- if (!dev_node) {
- dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
- if (!dev_node)
- return -ENODEV;
- }
-
- pdev = of_find_device_by_node(dev_node);
- if (!pdev) {
- of_node_put(dev_node);
- return -ENODEV;
- }
-
- priv = dev_get_drvdata(&pdev->dev);
- of_node_put(dev_node);
-
- /*
- * If priv is NULL, it's probably because the caam driver wasn't
- * properly initialized (e.g. RNG4 init failed). Thus, bail out here.
- */
- if (!priv) {
- err = -ENODEV;
- goto out_put_dev;
- }
-
/* Check for an instantiated RNG before registration */
if (priv->era < 10)
rng_inst = (rd_reg32(&priv->ctrl->perfmon.cha_num_ls) &
@@ -344,16 +315,13 @@ static int __init caam_rng_init(void)
else
rng_inst = rd_reg32(&priv->ctrl->vreg.rng) & CHA_VER_NUM_MASK;
- if (!rng_inst) {
- err = -ENODEV;
- goto out_put_dev;
- }
+ if (!rng_inst)
+ return 0;
dev = caam_jr_alloc();
if (IS_ERR(dev)) {
pr_err("Job Ring Device allocation for transform failed\n");
- err = PTR_ERR(dev);
- goto out_put_dev;
+ return PTR_ERR(dev);
}
rng_ctx = kmalloc(sizeof(*rng_ctx), GFP_DMA | GFP_KERNEL);
if (!rng_ctx) {
@@ -364,7 +332,6 @@ static int __init caam_rng_init(void)
if (err)
goto free_rng_ctx;
- put_device(&pdev->dev);
dev_info(dev, "registering rng-caam\n");
return hwrng_register(&caam_rng);
@@ -372,14 +339,5 @@ free_rng_ctx:
kfree(rng_ctx);
free_caam_alloc:
caam_jr_free(dev);
-out_put_dev:
- put_device(&pdev->dev);
return err;
}
-
-module_init(caam_rng_init);
-module_exit(caam_rng_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("FSL CAAM support for hw_random API");
-MODULE_AUTHOR("Freescale Semiconductor - NMG");
diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c
index fec39c35c877..4e43ca4d3656 100644
--- a/drivers/crypto/caam/ctrl.c
+++ b/drivers/crypto/caam/ctrl.c
@@ -3,7 +3,7 @@
* Controller-level driver, kernel property detection, initialization
*
* Copyright 2008-2012 Freescale Semiconductor, Inc.
- * Copyright 2018 NXP
+ * Copyright 2018-2019 NXP
*/
#include <linux/device.h>
@@ -323,8 +323,8 @@ static int caam_remove(struct platform_device *pdev)
of_platform_depopulate(ctrldev);
#ifdef CONFIG_CAAM_QI
- if (ctrlpriv->qidev)
- caam_qi_shutdown(ctrlpriv->qidev);
+ if (ctrlpriv->qi_init)
+ caam_qi_shutdown(ctrldev);
#endif
/*
@@ -540,7 +540,8 @@ static int caam_probe(struct platform_device *pdev)
ctrlpriv->caam_ipg = clk;
if (!of_machine_is_compatible("fsl,imx7d") &&
- !of_machine_is_compatible("fsl,imx7s")) {
+ !of_machine_is_compatible("fsl,imx7s") &&
+ !of_machine_is_compatible("fsl,imx7ulp")) {
clk = caam_drv_identify_clk(&pdev->dev, "mem");
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
@@ -562,7 +563,8 @@ static int caam_probe(struct platform_device *pdev)
if (!of_machine_is_compatible("fsl,imx6ul") &&
!of_machine_is_compatible("fsl,imx7d") &&
- !of_machine_is_compatible("fsl,imx7s")) {
+ !of_machine_is_compatible("fsl,imx7s") &&
+ !of_machine_is_compatible("fsl,imx7ulp")) {
clk = caam_drv_identify_clk(&pdev->dev, "emi_slow");
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
@@ -702,12 +704,7 @@ static int caam_probe(struct platform_device *pdev)
}
ctrlpriv->era = caam_get_era(ctrl);
-
- ret = of_platform_populate(nprop, caam_match, NULL, dev);
- if (ret) {
- dev_err(dev, "JR platform devices creation error\n");
- goto iounmap_ctrl;
- }
+ ctrlpriv->domain = iommu_get_domain_for_dev(dev);
#ifdef CONFIG_DEBUG_FS
/*
@@ -721,19 +718,6 @@ static int caam_probe(struct platform_device *pdev)
ctrlpriv->ctl = debugfs_create_dir("ctl", ctrlpriv->dfs_root);
#endif
- ring = 0;
- for_each_available_child_of_node(nprop, np)
- if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring") ||
- of_device_is_compatible(np, "fsl,sec4.0-job-ring")) {
- ctrlpriv->jr[ring] = (struct caam_job_ring __iomem __force *)
- ((__force uint8_t *)ctrl +
- (ring + JR_BLOCK_NUMBER) *
- BLOCK_OFFSET
- );
- ctrlpriv->total_jobrs++;
- ring++;
- }
-
/* Check to see if (DPAA 1.x) QI present. If so, enable */
ctrlpriv->qi_present = !!(comp_params & CTPR_MS_QI_MASK);
if (ctrlpriv->qi_present && !caam_dpaa2) {
@@ -752,6 +736,25 @@ static int caam_probe(struct platform_device *pdev)
#endif
}
+ ret = of_platform_populate(nprop, caam_match, NULL, dev);
+ if (ret) {
+ dev_err(dev, "JR platform devices creation error\n");
+ goto shutdown_qi;
+ }
+
+ ring = 0;
+ for_each_available_child_of_node(nprop, np)
+ if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring") ||
+ of_device_is_compatible(np, "fsl,sec4.0-job-ring")) {
+ ctrlpriv->jr[ring] = (struct caam_job_ring __iomem __force *)
+ ((__force uint8_t *)ctrl +
+ (ring + JR_BLOCK_NUMBER) *
+ BLOCK_OFFSET
+ );
+ ctrlpriv->total_jobrs++;
+ ring++;
+ }
+
/* If no QI and no rings specified, quit and go home */
if ((!ctrlpriv->qi_present) && (!ctrlpriv->total_jobrs)) {
dev_err(dev, "no queues configured, terminating\n");
@@ -898,6 +901,11 @@ caam_remove:
caam_remove(pdev);
return ret;
+shutdown_qi:
+#ifdef CONFIG_CAAM_QI
+ if (ctrlpriv->qi_init)
+ caam_qi_shutdown(dev);
+#endif
iounmap_ctrl:
iounmap(ctrl);
disable_caam_emi_slow:
diff --git a/drivers/crypto/caam/desc_constr.h b/drivers/crypto/caam/desc_constr.h
index 2980b8ef1fb1..5988a26a2441 100644
--- a/drivers/crypto/caam/desc_constr.h
+++ b/drivers/crypto/caam/desc_constr.h
@@ -3,6 +3,7 @@
* caam descriptor construction helper functions
*
* Copyright 2008-2012 Freescale Semiconductor, Inc.
+ * Copyright 2019 NXP
*/
#ifndef DESC_CONSTR_H
@@ -37,6 +38,16 @@
extern bool caam_little_end;
+/*
+ * HW fetches 4 S/G table entries at a time, irrespective of how many entries
+ * are in the table. It's SW's responsibility to make sure these accesses
+ * do not have side effects.
+ */
+static inline int pad_sg_nents(int sg_nents)
+{
+ return ALIGN(sg_nents, 4);
+}
+
static inline int desc_len(u32 * const desc)
{
return caam32_to_cpu(*desc) & HDR_DESCLEN_MASK;
diff --git a/drivers/crypto/caam/error.c b/drivers/crypto/caam/error.c
index 4da844e4b61d..4f0d45865aa2 100644
--- a/drivers/crypto/caam/error.c
+++ b/drivers/crypto/caam/error.c
@@ -13,7 +13,7 @@
#ifdef DEBUG
#include <linux/highmem.h>
-void caam_dump_sg(const char *level, const char *prefix_str, int prefix_type,
+void caam_dump_sg(const char *prefix_str, int prefix_type,
int rowsize, int groupsize, struct scatterlist *sg,
size_t tlen, bool ascii)
{
@@ -35,15 +35,15 @@ void caam_dump_sg(const char *level, const char *prefix_str, int prefix_type,
buf = it_page + it->offset;
len = min_t(size_t, tlen, it->length);
- print_hex_dump(level, prefix_str, prefix_type, rowsize,
- groupsize, buf, len, ascii);
+ print_hex_dump_debug(prefix_str, prefix_type, rowsize,
+ groupsize, buf, len, ascii);
tlen -= len;
kunmap_atomic(it_page);
}
}
#else
-void caam_dump_sg(const char *level, const char *prefix_str, int prefix_type,
+void caam_dump_sg(const char *prefix_str, int prefix_type,
int rowsize, int groupsize, struct scatterlist *sg,
size_t tlen, bool ascii)
{}
diff --git a/drivers/crypto/caam/error.h b/drivers/crypto/caam/error.h
index 8c6b83e02a70..d9726e66edbf 100644
--- a/drivers/crypto/caam/error.h
+++ b/drivers/crypto/caam/error.h
@@ -17,7 +17,7 @@ void caam_strstatus(struct device *dev, u32 status, bool qi_v2);
#define caam_jr_strstatus(jrdev, status) caam_strstatus(jrdev, status, false)
#define caam_qi2_strstatus(qidev, status) caam_strstatus(qidev, status, true)
-void caam_dump_sg(const char *level, const char *prefix_str, int prefix_type,
+void caam_dump_sg(const char *prefix_str, int prefix_type,
int rowsize, int groupsize, struct scatterlist *sg,
size_t tlen, bool ascii);
diff --git a/drivers/crypto/caam/intern.h b/drivers/crypto/caam/intern.h
index 3392615dc91b..6af84bbc612c 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
*/
#ifndef INTERN_H
@@ -63,10 +63,6 @@ struct caam_drv_private_jr {
* Driver-private storage for a single CAAM block instance
*/
struct caam_drv_private {
-#ifdef CONFIG_CAAM_QI
- struct device *qidev;
-#endif
-
/* Physical-presence section */
struct caam_ctrl __iomem *ctrl; /* controller region */
struct caam_deco __iomem *deco; /* DECO/CCB views */
@@ -74,12 +70,17 @@ struct caam_drv_private {
struct caam_queue_if __iomem *qi; /* QI control region */
struct caam_job_ring __iomem *jr[4]; /* JobR's register space */
+ struct iommu_domain *domain;
+
/*
* Detected geometry block. Filled in from device tree if powerpc,
* or from register-based version detection code
*/
u8 total_jobrs; /* Total Job Rings in device */
u8 qi_present; /* Nonzero if QI present in device */
+#ifdef CONFIG_CAAM_QI
+ u8 qi_init; /* Nonzero if QI has been initialized */
+#endif
u8 mc_en; /* Nonzero if MC f/w is active */
int secvio_irq; /* Security violation interrupt number */
int virt_en; /* Virtualization enabled in CAAM */
@@ -107,8 +108,95 @@ struct caam_drv_private {
#endif
};
-void caam_jr_algapi_init(struct device *dev);
-void caam_jr_algapi_remove(struct device *dev);
+#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API
+
+int caam_algapi_init(struct device *dev);
+void caam_algapi_exit(void);
+
+#else
+
+static inline int caam_algapi_init(struct device *dev)
+{
+ return 0;
+}
+
+static inline void caam_algapi_exit(void)
+{
+}
+
+#endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API */
+
+#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API
+
+int caam_algapi_hash_init(struct device *dev);
+void caam_algapi_hash_exit(void);
+
+#else
+
+static inline int caam_algapi_hash_init(struct device *dev)
+{
+ return 0;
+}
+
+static inline void caam_algapi_hash_exit(void)
+{
+}
+
+#endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API */
+
+#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API
+
+int caam_pkc_init(struct device *dev);
+void caam_pkc_exit(void);
+
+#else
+
+static inline int caam_pkc_init(struct device *dev)
+{
+ return 0;
+}
+
+static inline void caam_pkc_exit(void)
+{
+}
+
+#endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API */
+
+#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API
+
+int caam_rng_init(struct device *dev);
+void caam_rng_exit(void);
+
+#else
+
+static inline int caam_rng_init(struct device *dev)
+{
+ return 0;
+}
+
+static inline void caam_rng_exit(void)
+{
+}
+
+#endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API */
+
+#ifdef CONFIG_CAAM_QI
+
+int caam_qi_algapi_init(struct device *dev);
+void caam_qi_algapi_exit(void);
+
+#else
+
+static inline int caam_qi_algapi_init(struct device *dev)
+{
+ return 0;
+}
+
+static inline void caam_qi_algapi_exit(void)
+{
+}
+
+#endif /* CONFIG_CAAM_QI */
#ifdef CONFIG_DEBUG_FS
static int caam_debugfs_u64_get(void *data, u64 *val)
diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c
index 1de2562d0982..cea811fed320 100644
--- a/drivers/crypto/caam/jr.c
+++ b/drivers/crypto/caam/jr.c
@@ -4,6 +4,7 @@
* JobR backend functionality
*
* Copyright 2008-2012 Freescale Semiconductor, Inc.
+ * Copyright 2019 NXP
*/
#include <linux/of_irq.h>
@@ -23,6 +24,43 @@ struct jr_driver_data {
} ____cacheline_aligned;
static struct jr_driver_data driver_data;
+static DEFINE_MUTEX(algs_lock);
+static unsigned int active_devs;
+
+static void register_algs(struct device *dev)
+{
+ mutex_lock(&algs_lock);
+
+ if (++active_devs != 1)
+ goto algs_unlock;
+
+ caam_algapi_init(dev);
+ caam_algapi_hash_init(dev);
+ caam_pkc_init(dev);
+ caam_rng_init(dev);
+ caam_qi_algapi_init(dev);
+
+algs_unlock:
+ mutex_unlock(&algs_lock);
+}
+
+static void unregister_algs(void)
+{
+ mutex_lock(&algs_lock);
+
+ if (--active_devs != 0)
+ goto algs_unlock;
+
+ caam_qi_algapi_exit();
+
+ caam_rng_exit();
+ caam_pkc_exit();
+ caam_algapi_hash_exit();
+ caam_algapi_exit();
+
+algs_unlock:
+ mutex_unlock(&algs_lock);
+}
static int caam_reset_hw_jr(struct device *dev)
{
@@ -109,6 +147,9 @@ static int caam_jr_remove(struct platform_device *pdev)
return -EBUSY;
}
+ /* Unregister JR-based RNG & crypto algorithms */
+ unregister_algs();
+
/* Remove the node from Physical JobR list maintained by driver */
spin_lock(&driver_data.jr_alloc_lock);
list_del(&jrpriv->list_node);
@@ -541,6 +582,8 @@ static int caam_jr_probe(struct platform_device *pdev)
atomic_set(&jrpriv->tfm_count, 0);
+ register_algs(jrdev->parent);
+
return 0;
}
diff --git a/drivers/crypto/caam/key_gen.c b/drivers/crypto/caam/key_gen.c
index 8d0713fae6ac..48dd3536060d 100644
--- a/drivers/crypto/caam/key_gen.c
+++ b/drivers/crypto/caam/key_gen.c
@@ -16,9 +16,7 @@ void split_key_done(struct device *dev, u32 *desc, u32 err,
{
struct split_key_result *res = context;
-#ifdef DEBUG
- dev_err(dev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
-#endif
+ dev_dbg(dev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
if (err)
caam_jr_strstatus(dev, err);
@@ -55,12 +53,10 @@ int gen_split_key(struct device *jrdev, u8 *key_out,
adata->keylen_pad = split_key_pad_len(adata->algtype &
OP_ALG_ALGSEL_MASK);
-#ifdef DEBUG
- dev_err(jrdev, "split keylen %d split keylen padded %d\n",
+ dev_dbg(jrdev, "split keylen %d split keylen padded %d\n",
adata->keylen, adata->keylen_pad);
- print_hex_dump(KERN_ERR, "ctx.key@" __stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, key_in, keylen, 1);
-#endif
+ print_hex_dump_debug("ctx.key@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, key_in, keylen, 1);
if (adata->keylen_pad > max_keylen)
return -EINVAL;
@@ -102,10 +98,9 @@ int gen_split_key(struct device *jrdev, u8 *key_out,
append_fifo_store(desc, dma_addr, adata->keylen,
LDST_CLASS_2_CCB | FIFOST_TYPE_SPLIT_KEK);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "jobdesc@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
-#endif
+ print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
+ 1);
result.err = 0;
init_completion(&result.completion);
@@ -115,11 +110,10 @@ int gen_split_key(struct device *jrdev, u8 *key_out,
/* in progress */
wait_for_completion(&result.completion);
ret = result.err;
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, key_out,
- adata->keylen_pad, 1);
-#endif
+
+ print_hex_dump_debug("ctx.key@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, key_out,
+ adata->keylen_pad, 1);
}
dma_unmap_single(jrdev, dma_addr, adata->keylen_pad, DMA_BIDIRECTIONAL);
diff --git a/drivers/crypto/caam/qi.c b/drivers/crypto/caam/qi.c
index 9f08f84cca59..0fe618e3804a 100644
--- a/drivers/crypto/caam/qi.c
+++ b/drivers/crypto/caam/qi.c
@@ -4,7 +4,7 @@
* Queue Interface backend functionality
*
* Copyright 2013-2016 Freescale Semiconductor, Inc.
- * Copyright 2016-2017 NXP
+ * Copyright 2016-2017, 2019 NXP
*/
#include <linux/cpumask.h>
@@ -18,6 +18,7 @@
#include "desc_constr.h"
#define PREHDR_RSLS_SHIFT 31
+#define PREHDR_ABS BIT(25)
/*
* Use a reasonable backlog of frames (per CPU) as congestion threshold,
@@ -58,11 +59,9 @@ static DEFINE_PER_CPU(int, last_cpu);
/*
* caam_qi_priv - CAAM QI backend private params
* @cgr: QMan congestion group
- * @qi_pdev: platform device for QI backend
*/
struct caam_qi_priv {
struct qman_cgr cgr;
- struct platform_device *qi_pdev;
};
static struct caam_qi_priv qipriv ____cacheline_aligned;
@@ -95,6 +94,16 @@ static u64 times_congested;
*/
static struct kmem_cache *qi_cache;
+static void *caam_iova_to_virt(struct iommu_domain *domain,
+ dma_addr_t iova_addr)
+{
+ phys_addr_t phys_addr;
+
+ phys_addr = domain ? iommu_iova_to_phys(domain, iova_addr) : iova_addr;
+
+ return phys_to_virt(phys_addr);
+}
+
int caam_qi_enqueue(struct device *qidev, struct caam_drv_req *req)
{
struct qm_fd fd;
@@ -135,6 +144,7 @@ static void caam_fq_ern_cb(struct qman_portal *qm, struct qman_fq *fq,
const struct qm_fd *fd;
struct caam_drv_req *drv_req;
struct device *qidev = &(raw_cpu_ptr(&pcpu_qipriv)->net_dev.dev);
+ struct caam_drv_private *priv = dev_get_drvdata(qidev);
fd = &msg->ern.fd;
@@ -143,7 +153,7 @@ static void caam_fq_ern_cb(struct qman_portal *qm, struct qman_fq *fq,
return;
}
- drv_req = (struct caam_drv_req *)phys_to_virt(qm_fd_addr_get64(fd));
+ drv_req = caam_iova_to_virt(priv->domain, qm_fd_addr_get64(fd));
if (!drv_req) {
dev_err(qidev,
"Can't find original request for CAAM response\n");
@@ -346,6 +356,7 @@ int caam_drv_ctx_update(struct caam_drv_ctx *drv_ctx, u32 *sh_desc)
*/
drv_ctx->prehdr[0] = cpu_to_caam32((1 << PREHDR_RSLS_SHIFT) |
num_words);
+ drv_ctx->prehdr[1] = cpu_to_caam32(PREHDR_ABS);
memcpy(drv_ctx->sh_desc, sh_desc, desc_bytes(sh_desc));
dma_sync_single_for_device(qidev, drv_ctx->context_a,
sizeof(drv_ctx->sh_desc) +
@@ -401,6 +412,7 @@ struct caam_drv_ctx *caam_drv_ctx_init(struct device *qidev,
*/
drv_ctx->prehdr[0] = cpu_to_caam32((1 << PREHDR_RSLS_SHIFT) |
num_words);
+ drv_ctx->prehdr[1] = cpu_to_caam32(PREHDR_ABS);
memcpy(drv_ctx->sh_desc, sh_desc, desc_bytes(sh_desc));
size = sizeof(drv_ctx->prehdr) + sizeof(drv_ctx->sh_desc);
hwdesc = dma_map_single(qidev, drv_ctx->prehdr, size,
@@ -488,7 +500,7 @@ EXPORT_SYMBOL(caam_drv_ctx_rel);
void caam_qi_shutdown(struct device *qidev)
{
int i;
- struct caam_qi_priv *priv = dev_get_drvdata(qidev);
+ struct caam_qi_priv *priv = &qipriv;
const cpumask_t *cpus = qman_affine_cpus();
for_each_cpu(i, cpus) {
@@ -506,8 +518,6 @@ void caam_qi_shutdown(struct device *qidev)
qman_release_cgrid(priv->cgr.cgrid);
kmem_cache_destroy(qi_cache);
-
- platform_device_unregister(priv->qi_pdev);
}
static void cgr_cb(struct qman_portal *qm, struct qman_cgr *cgr, int congested)
@@ -550,6 +560,7 @@ static enum qman_cb_dqrr_result caam_rsp_fq_dqrr_cb(struct qman_portal *p,
struct caam_drv_req *drv_req;
const struct qm_fd *fd;
struct device *qidev = &(raw_cpu_ptr(&pcpu_qipriv)->net_dev.dev);
+ struct caam_drv_private *priv = dev_get_drvdata(qidev);
u32 status;
if (caam_qi_napi_schedule(p, caam_napi))
@@ -572,7 +583,7 @@ static enum qman_cb_dqrr_result caam_rsp_fq_dqrr_cb(struct qman_portal *p,
return qman_cb_dqrr_consume;
}
- drv_req = (struct caam_drv_req *)phys_to_virt(qm_fd_addr_get64(fd));
+ drv_req = caam_iova_to_virt(priv->domain, qm_fd_addr_get64(fd));
if (unlikely(!drv_req)) {
dev_err(qidev,
"Can't find original request for caam response\n");
@@ -692,33 +703,17 @@ static void free_rsp_fqs(void)
int caam_qi_init(struct platform_device *caam_pdev)
{
int err, i;
- struct platform_device *qi_pdev;
struct device *ctrldev = &caam_pdev->dev, *qidev;
struct caam_drv_private *ctrlpriv;
const cpumask_t *cpus = qman_affine_cpus();
- static struct platform_device_info qi_pdev_info = {
- .name = "caam_qi",
- .id = PLATFORM_DEVID_NONE
- };
-
- qi_pdev_info.parent = ctrldev;
- qi_pdev_info.dma_mask = dma_get_mask(ctrldev);
- qi_pdev = platform_device_register_full(&qi_pdev_info);
- if (IS_ERR(qi_pdev))
- return PTR_ERR(qi_pdev);
- set_dma_ops(&qi_pdev->dev, get_dma_ops(ctrldev));
ctrlpriv = dev_get_drvdata(ctrldev);
- qidev = &qi_pdev->dev;
-
- qipriv.qi_pdev = qi_pdev;
- dev_set_drvdata(qidev, &qipriv);
+ qidev = ctrldev;
/* Initialize the congestion detection */
err = init_cgr(qidev);
if (err) {
dev_err(qidev, "CGR initialization failed: %d\n", err);
- platform_device_unregister(qi_pdev);
return err;
}
@@ -727,7 +722,6 @@ int caam_qi_init(struct platform_device *caam_pdev)
if (err) {
dev_err(qidev, "Can't allocate CAAM response FQs: %d\n", err);
free_rsp_fqs();
- platform_device_unregister(qi_pdev);
return err;
}
@@ -750,15 +744,11 @@ int caam_qi_init(struct platform_device *caam_pdev)
napi_enable(irqtask);
}
- /* Hook up QI device to parent controlling caam device */
- ctrlpriv->qidev = qidev;
-
qi_cache = kmem_cache_create("caamqicache", CAAM_QI_MEMCACHE_SIZE, 0,
SLAB_CACHE_DMA, NULL);
if (!qi_cache) {
dev_err(qidev, "Can't allocate CAAM cache\n");
free_rsp_fqs();
- platform_device_unregister(qi_pdev);
return -ENOMEM;
}
@@ -766,6 +756,8 @@ int caam_qi_init(struct platform_device *caam_pdev)
debugfs_create_file("qi_congested", 0444, ctrlpriv->ctl,
&times_congested, &caam_fops_u64_ro);
#endif
+
+ ctrlpriv->qi_init = 1;
dev_info(qidev, "Linux CAAM Queue I/F driver initialised\n");
return 0;
}
diff --git a/drivers/crypto/caam/sg_sw_qm.h b/drivers/crypto/caam/sg_sw_qm.h
index b3e1aaaeffea..d56cc7efbc13 100644
--- a/drivers/crypto/caam/sg_sw_qm.h
+++ b/drivers/crypto/caam/sg_sw_qm.h
@@ -54,15 +54,19 @@ static inline void dma_to_qm_sg_one_last_ext(struct qm_sg_entry *qm_sg_ptr,
* but does not have final bit; instead, returns last entry
*/
static inline struct qm_sg_entry *
-sg_to_qm_sg(struct scatterlist *sg, int sg_count,
+sg_to_qm_sg(struct scatterlist *sg, int len,
struct qm_sg_entry *qm_sg_ptr, u16 offset)
{
- while (sg_count && sg) {
- dma_to_qm_sg_one(qm_sg_ptr, sg_dma_address(sg),
- sg_dma_len(sg), offset);
+ int ent_len;
+
+ while (len) {
+ ent_len = min_t(int, sg_dma_len(sg), len);
+
+ dma_to_qm_sg_one(qm_sg_ptr, sg_dma_address(sg), ent_len,
+ offset);
qm_sg_ptr++;
sg = sg_next(sg);
- sg_count--;
+ len -= ent_len;
}
return qm_sg_ptr - 1;
}
@@ -71,10 +75,10 @@ sg_to_qm_sg(struct scatterlist *sg, int sg_count,
* convert scatterlist to h/w link table format
* scatterlist must have been previously dma mapped
*/
-static inline void sg_to_qm_sg_last(struct scatterlist *sg, int sg_count,
+static inline void sg_to_qm_sg_last(struct scatterlist *sg, int len,
struct qm_sg_entry *qm_sg_ptr, u16 offset)
{
- qm_sg_ptr = sg_to_qm_sg(sg, sg_count, qm_sg_ptr, offset);
+ qm_sg_ptr = sg_to_qm_sg(sg, len, qm_sg_ptr, offset);
qm_sg_entry_set_f(qm_sg_ptr, qm_sg_entry_get_len(qm_sg_ptr));
}
diff --git a/drivers/crypto/caam/sg_sw_qm2.h b/drivers/crypto/caam/sg_sw_qm2.h
index c9378402a5f8..b8b737d2b0ea 100644
--- a/drivers/crypto/caam/sg_sw_qm2.h
+++ b/drivers/crypto/caam/sg_sw_qm2.h
@@ -25,15 +25,19 @@ static inline void dma_to_qm_sg_one(struct dpaa2_sg_entry *qm_sg_ptr,
* but does not have final bit; instead, returns last entry
*/
static inline struct dpaa2_sg_entry *
-sg_to_qm_sg(struct scatterlist *sg, int sg_count,
+sg_to_qm_sg(struct scatterlist *sg, int len,
struct dpaa2_sg_entry *qm_sg_ptr, u16 offset)
{
- while (sg_count && sg) {
- dma_to_qm_sg_one(qm_sg_ptr, sg_dma_address(sg),
- sg_dma_len(sg), offset);
+ int ent_len;
+
+ while (len) {
+ ent_len = min_t(int, sg_dma_len(sg), len);
+
+ dma_to_qm_sg_one(qm_sg_ptr, sg_dma_address(sg), ent_len,
+ offset);
qm_sg_ptr++;
sg = sg_next(sg);
- sg_count--;
+ len -= ent_len;
}
return qm_sg_ptr - 1;
}
@@ -42,11 +46,11 @@ sg_to_qm_sg(struct scatterlist *sg, int sg_count,
* convert scatterlist to h/w link table format
* scatterlist must have been previously dma mapped
*/
-static inline void sg_to_qm_sg_last(struct scatterlist *sg, int sg_count,
+static inline void sg_to_qm_sg_last(struct scatterlist *sg, int len,
struct dpaa2_sg_entry *qm_sg_ptr,
u16 offset)
{
- qm_sg_ptr = sg_to_qm_sg(sg, sg_count, qm_sg_ptr, offset);
+ qm_sg_ptr = sg_to_qm_sg(sg, len, qm_sg_ptr, offset);
dpaa2_sg_set_final(qm_sg_ptr, true);
}
diff --git a/drivers/crypto/caam/sg_sw_sec4.h b/drivers/crypto/caam/sg_sw_sec4.h
index dbfa9fce33e0..07e1ee99273b 100644
--- a/drivers/crypto/caam/sg_sw_sec4.h
+++ b/drivers/crypto/caam/sg_sw_sec4.h
@@ -35,11 +35,9 @@ static inline void dma_to_sec4_sg_one(struct sec4_sg_entry *sec4_sg_ptr,
sec4_sg_ptr->bpid_offset = cpu_to_caam32(offset &
SEC4_SG_OFFSET_MASK);
}
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "sec4_sg_ptr@: ",
- DUMP_PREFIX_ADDRESS, 16, 4, sec4_sg_ptr,
- sizeof(struct sec4_sg_entry), 1);
-#endif
+
+ print_hex_dump_debug("sec4_sg_ptr@: ", DUMP_PREFIX_ADDRESS, 16, 4,
+ sec4_sg_ptr, sizeof(struct sec4_sg_entry), 1);
}
/*
@@ -47,15 +45,19 @@ static inline void dma_to_sec4_sg_one(struct sec4_sg_entry *sec4_sg_ptr,
* but does not have final bit; instead, returns last entry
*/
static inline struct sec4_sg_entry *
-sg_to_sec4_sg(struct scatterlist *sg, int sg_count,
+sg_to_sec4_sg(struct scatterlist *sg, int len,
struct sec4_sg_entry *sec4_sg_ptr, u16 offset)
{
- while (sg_count) {
- dma_to_sec4_sg_one(sec4_sg_ptr, sg_dma_address(sg),
- sg_dma_len(sg), offset);
+ int ent_len;
+
+ while (len) {
+ ent_len = min_t(int, sg_dma_len(sg), len);
+
+ dma_to_sec4_sg_one(sec4_sg_ptr, sg_dma_address(sg), ent_len,
+ offset);
sec4_sg_ptr++;
sg = sg_next(sg);
- sg_count--;
+ len -= ent_len;
}
return sec4_sg_ptr - 1;
}
@@ -72,11 +74,11 @@ static inline void sg_to_sec4_set_last(struct sec4_sg_entry *sec4_sg_ptr)
* convert scatterlist to h/w link table format
* scatterlist must have been previously dma mapped
*/
-static inline void sg_to_sec4_sg_last(struct scatterlist *sg, int sg_count,
+static inline void sg_to_sec4_sg_last(struct scatterlist *sg, int len,
struct sec4_sg_entry *sec4_sg_ptr,
u16 offset)
{
- sec4_sg_ptr = sg_to_sec4_sg(sg, sg_count, sec4_sg_ptr, offset);
+ sec4_sg_ptr = sg_to_sec4_sg(sg, len, sec4_sg_ptr, offset);
sg_to_sec4_set_last(sec4_sg_ptr);
}
diff --git a/drivers/crypto/cavium/cpt/cptvf_algs.c b/drivers/crypto/cavium/cpt/cptvf_algs.c
index e9f4704494fb..ff3cb1f8f2b6 100644
--- a/drivers/crypto/cavium/cpt/cptvf_algs.c
+++ b/drivers/crypto/cavium/cpt/cptvf_algs.c
@@ -7,7 +7,6 @@
#include <crypto/aes.h>
#include <crypto/algapi.h>
#include <crypto/authenc.h>
-#include <crypto/crypto_wq.h>
#include <crypto/des.h>
#include <crypto/xts.h>
#include <linux/crypto.h>
diff --git a/drivers/crypto/cavium/nitrox/nitrox_debugfs.h b/drivers/crypto/cavium/nitrox/nitrox_debugfs.h
index f177b79bbab0..09c4cf2513fb 100644
--- a/drivers/crypto/cavium/nitrox/nitrox_debugfs.h
+++ b/drivers/crypto/cavium/nitrox/nitrox_debugfs.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __NITROX_DEBUGFS_H
#define __NITROX_DEBUGFS_H
diff --git a/drivers/crypto/cavium/nitrox/nitrox_mbx.h b/drivers/crypto/cavium/nitrox/nitrox_mbx.h
index 5008399775a9..7c93d0282174 100644
--- a/drivers/crypto/cavium/nitrox/nitrox_mbx.h
+++ b/drivers/crypto/cavium/nitrox/nitrox_mbx.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __NITROX_MBX_H
#define __NITROX_MBX_H
diff --git a/drivers/crypto/ccp/ccp-crypto-aes-cmac.c b/drivers/crypto/ccp/ccp-crypto-aes-cmac.c
index f6e252c1d6fb..bb7219d36b2c 100644
--- a/drivers/crypto/ccp/ccp-crypto-aes-cmac.c
+++ b/drivers/crypto/ccp/ccp-crypto-aes-cmac.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AMD Cryptographic Coprocessor (CCP) AES CMAC crypto API support
*
* Copyright (C) 2013,2018 Advanced Micro Devices, Inc.
*
* Author: Tom Lendacky <thomas.lendacky@amd.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/crypto/ccp/ccp-crypto-aes-galois.c b/drivers/crypto/ccp/ccp-crypto-aes-galois.c
index ca1f0d780b61..f9fec2ddf56a 100644
--- a/drivers/crypto/ccp/ccp-crypto-aes-galois.c
+++ b/drivers/crypto/ccp/ccp-crypto-aes-galois.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AMD Cryptographic Coprocessor (CCP) AES GCM crypto API support
*
* Copyright (C) 2016,2017 Advanced Micro Devices, Inc.
*
* Author: Gary R Hook <gary.hook@amd.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/crypto/ccp/ccp-crypto-aes-xts.c b/drivers/crypto/ccp/ccp-crypto-aes-xts.c
index ca4630b8395f..783ba75e0618 100644
--- a/drivers/crypto/ccp/ccp-crypto-aes-xts.c
+++ b/drivers/crypto/ccp/ccp-crypto-aes-xts.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AMD Cryptographic Coprocessor (CCP) AES XTS crypto API support
*
@@ -5,10 +6,6 @@
*
* Author: Gary R Hook <gary.hook@amd.com>
* Author: Tom Lendacky <thomas.lendacky@amd.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/crypto/ccp/ccp-crypto-aes.c b/drivers/crypto/ccp/ccp-crypto-aes.c
index 89291c15015c..58c6dddfc5e1 100644
--- a/drivers/crypto/ccp/ccp-crypto-aes.c
+++ b/drivers/crypto/ccp/ccp-crypto-aes.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AMD Cryptographic Coprocessor (CCP) AES crypto API support
*
- * Copyright (C) 2013,2016 Advanced Micro Devices, Inc.
+ * Copyright (C) 2013-2019 Advanced Micro Devices, Inc.
*
* Author: Tom Lendacky <thomas.lendacky@amd.com>
- *
- * 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.
*/
#include <linux/module.h>
@@ -79,8 +76,7 @@ static int ccp_aes_crypt(struct ablkcipher_request *req, bool encrypt)
return -EINVAL;
if (((ctx->u.aes.mode == CCP_AES_MODE_ECB) ||
- (ctx->u.aes.mode == CCP_AES_MODE_CBC) ||
- (ctx->u.aes.mode == CCP_AES_MODE_CFB)) &&
+ (ctx->u.aes.mode == CCP_AES_MODE_CBC)) &&
(req->nbytes & (AES_BLOCK_SIZE - 1)))
return -EINVAL;
@@ -291,7 +287,7 @@ static struct ccp_aes_def aes_algs[] = {
.version = CCP_VERSION(3, 0),
.name = "cfb(aes)",
.driver_name = "cfb-aes-ccp",
- .blocksize = AES_BLOCK_SIZE,
+ .blocksize = 1,
.ivsize = AES_BLOCK_SIZE,
.alg_defaults = &ccp_aes_defaults,
},
diff --git a/drivers/crypto/ccp/ccp-crypto-des3.c b/drivers/crypto/ccp/ccp-crypto-des3.c
index 91482ffcac59..5f05f834c7cd 100644
--- a/drivers/crypto/ccp/ccp-crypto-des3.c
+++ b/drivers/crypto/ccp/ccp-crypto-des3.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AMD Cryptographic Coprocessor (CCP) DES3 crypto API support
*
* Copyright (C) 2016,2017 Advanced Micro Devices, Inc.
*
* Author: Gary R Hook <ghook@amd.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/crypto/ccp/ccp-crypto-main.c b/drivers/crypto/ccp/ccp-crypto-main.c
index b95d19974aa6..818096490829 100644
--- a/drivers/crypto/ccp/ccp-crypto-main.c
+++ b/drivers/crypto/ccp/ccp-crypto-main.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AMD Cryptographic Coprocessor (CCP) crypto API support
*
* Copyright (C) 2013,2017 Advanced Micro Devices, Inc.
*
* Author: Tom Lendacky <thomas.lendacky@amd.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/crypto/ccp/ccp-crypto-rsa.c b/drivers/crypto/ccp/ccp-crypto-rsa.c
index a2570c0c8cdc..649c91d60401 100644
--- a/drivers/crypto/ccp/ccp-crypto-rsa.c
+++ b/drivers/crypto/ccp/ccp-crypto-rsa.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AMD Cryptographic Coprocessor (CCP) RSA crypto API support
*
* Copyright (C) 2017 Advanced Micro Devices, Inc.
*
* Author: Gary R Hook <gary.hook@amd.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/crypto/ccp/ccp-crypto-sha.c b/drivers/crypto/ccp/ccp-crypto-sha.c
index 3e10573f589e..453b9797f93f 100644
--- a/drivers/crypto/ccp/ccp-crypto-sha.c
+++ b/drivers/crypto/ccp/ccp-crypto-sha.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AMD Cryptographic Coprocessor (CCP) SHA crypto API support
*
@@ -5,10 +6,6 @@
*
* Author: Tom Lendacky <thomas.lendacky@amd.com>
* Author: Gary R Hook <gary.hook@amd.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/crypto/ccp/ccp-crypto.h b/drivers/crypto/ccp/ccp-crypto.h
index 28819e11db96..622b34c17643 100644
--- a/drivers/crypto/ccp/ccp-crypto.h
+++ b/drivers/crypto/ccp/ccp-crypto.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* AMD Cryptographic Coprocessor (CCP) crypto API support
*
* Copyright (C) 2013,2017 Advanced Micro Devices, Inc.
*
* Author: Tom Lendacky <thomas.lendacky@amd.com>
- *
- * 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.
*/
#ifndef __CCP_CRYPTO_H__
diff --git a/drivers/crypto/ccp/ccp-debugfs.c b/drivers/crypto/ccp/ccp-debugfs.c
index 4bd26af7098d..a1055554b47a 100644
--- a/drivers/crypto/ccp/ccp-debugfs.c
+++ b/drivers/crypto/ccp/ccp-debugfs.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AMD Cryptographic Coprocessor (CCP) driver
*
* Copyright (C) 2017 Advanced Micro Devices, Inc.
*
* Author: Gary R Hook <gary.hook@amd.com>
- *
- * 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.
*/
#include <linux/debugfs.h>
diff --git a/drivers/crypto/ccp/ccp-dev-v3.c b/drivers/crypto/ccp/ccp-dev-v3.c
index 240bebbcb8ac..2b7d47ed5c74 100644
--- a/drivers/crypto/ccp/ccp-dev-v3.c
+++ b/drivers/crypto/ccp/ccp-dev-v3.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AMD Cryptographic Coprocessor (CCP) driver
*
@@ -5,10 +6,6 @@
*
* Author: Tom Lendacky <thomas.lendacky@amd.com>
* Author: Gary R Hook <gary.hook@amd.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/crypto/ccp/ccp-dev-v5.c b/drivers/crypto/ccp/ccp-dev-v5.c
index c9bfd4f439ce..217e41bbadaf 100644
--- a/drivers/crypto/ccp/ccp-dev-v5.c
+++ b/drivers/crypto/ccp/ccp-dev-v5.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AMD Cryptographic Coprocessor (CCP) driver
*
* Copyright (C) 2016,2017 Advanced Micro Devices, Inc.
*
* Author: Gary R Hook <gary.hook@amd.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/crypto/ccp/ccp-dev.c b/drivers/crypto/ccp/ccp-dev.c
index 1b5035d56288..f79eede71c62 100644
--- a/drivers/crypto/ccp/ccp-dev.c
+++ b/drivers/crypto/ccp/ccp-dev.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AMD Cryptographic Coprocessor (CCP) driver
*
@@ -5,10 +6,6 @@
*
* Author: Tom Lendacky <thomas.lendacky@amd.com>
* Author: Gary R Hook <gary.hook@amd.com>
- *
- * 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.
*/
#include <linux/kernel.h>
@@ -35,56 +32,62 @@ struct ccp_tasklet_data {
};
/* Human-readable error strings */
+#define CCP_MAX_ERROR_CODE 64
static char *ccp_error_codes[] = {
"",
- "ERR 01: ILLEGAL_ENGINE",
- "ERR 02: ILLEGAL_KEY_ID",
- "ERR 03: ILLEGAL_FUNCTION_TYPE",
- "ERR 04: ILLEGAL_FUNCTION_MODE",
- "ERR 05: ILLEGAL_FUNCTION_ENCRYPT",
- "ERR 06: ILLEGAL_FUNCTION_SIZE",
- "ERR 07: Zlib_MISSING_INIT_EOM",
- "ERR 08: ILLEGAL_FUNCTION_RSVD",
- "ERR 09: ILLEGAL_BUFFER_LENGTH",
- "ERR 10: VLSB_FAULT",
- "ERR 11: ILLEGAL_MEM_ADDR",
- "ERR 12: ILLEGAL_MEM_SEL",
- "ERR 13: ILLEGAL_CONTEXT_ID",
- "ERR 14: ILLEGAL_KEY_ADDR",
- "ERR 15: 0xF Reserved",
- "ERR 16: Zlib_ILLEGAL_MULTI_QUEUE",
- "ERR 17: Zlib_ILLEGAL_JOBID_CHANGE",
- "ERR 18: CMD_TIMEOUT",
- "ERR 19: IDMA0_AXI_SLVERR",
- "ERR 20: IDMA0_AXI_DECERR",
- "ERR 21: 0x15 Reserved",
- "ERR 22: IDMA1_AXI_SLAVE_FAULT",
- "ERR 23: IDMA1_AIXI_DECERR",
- "ERR 24: 0x18 Reserved",
- "ERR 25: ZLIBVHB_AXI_SLVERR",
- "ERR 26: ZLIBVHB_AXI_DECERR",
- "ERR 27: 0x1B Reserved",
- "ERR 27: ZLIB_UNEXPECTED_EOM",
- "ERR 27: ZLIB_EXTRA_DATA",
- "ERR 30: ZLIB_BTYPE",
- "ERR 31: ZLIB_UNDEFINED_SYMBOL",
- "ERR 32: ZLIB_UNDEFINED_DISTANCE_S",
- "ERR 33: ZLIB_CODE_LENGTH_SYMBOL",
- "ERR 34: ZLIB _VHB_ILLEGAL_FETCH",
- "ERR 35: ZLIB_UNCOMPRESSED_LEN",
- "ERR 36: ZLIB_LIMIT_REACHED",
- "ERR 37: ZLIB_CHECKSUM_MISMATCH0",
- "ERR 38: ODMA0_AXI_SLVERR",
- "ERR 39: ODMA0_AXI_DECERR",
- "ERR 40: 0x28 Reserved",
- "ERR 41: ODMA1_AXI_SLVERR",
- "ERR 42: ODMA1_AXI_DECERR",
- "ERR 43: LSB_PARITY_ERR",
+ "ILLEGAL_ENGINE",
+ "ILLEGAL_KEY_ID",
+ "ILLEGAL_FUNCTION_TYPE",
+ "ILLEGAL_FUNCTION_MODE",
+ "ILLEGAL_FUNCTION_ENCRYPT",
+ "ILLEGAL_FUNCTION_SIZE",
+ "Zlib_MISSING_INIT_EOM",
+ "ILLEGAL_FUNCTION_RSVD",
+ "ILLEGAL_BUFFER_LENGTH",
+ "VLSB_FAULT",
+ "ILLEGAL_MEM_ADDR",
+ "ILLEGAL_MEM_SEL",
+ "ILLEGAL_CONTEXT_ID",
+ "ILLEGAL_KEY_ADDR",
+ "0xF Reserved",
+ "Zlib_ILLEGAL_MULTI_QUEUE",
+ "Zlib_ILLEGAL_JOBID_CHANGE",
+ "CMD_TIMEOUT",
+ "IDMA0_AXI_SLVERR",
+ "IDMA0_AXI_DECERR",
+ "0x15 Reserved",
+ "IDMA1_AXI_SLAVE_FAULT",
+ "IDMA1_AIXI_DECERR",
+ "0x18 Reserved",
+ "ZLIBVHB_AXI_SLVERR",
+ "ZLIBVHB_AXI_DECERR",
+ "0x1B Reserved",
+ "ZLIB_UNEXPECTED_EOM",
+ "ZLIB_EXTRA_DATA",
+ "ZLIB_BTYPE",
+ "ZLIB_UNDEFINED_SYMBOL",
+ "ZLIB_UNDEFINED_DISTANCE_S",
+ "ZLIB_CODE_LENGTH_SYMBOL",
+ "ZLIB _VHB_ILLEGAL_FETCH",
+ "ZLIB_UNCOMPRESSED_LEN",
+ "ZLIB_LIMIT_REACHED",
+ "ZLIB_CHECKSUM_MISMATCH0",
+ "ODMA0_AXI_SLVERR",
+ "ODMA0_AXI_DECERR",
+ "0x28 Reserved",
+ "ODMA1_AXI_SLVERR",
+ "ODMA1_AXI_DECERR",
};
-void ccp_log_error(struct ccp_device *d, int e)
+void ccp_log_error(struct ccp_device *d, unsigned int e)
{
- dev_err(d->dev, "CCP error: %s (0x%x)\n", ccp_error_codes[e], e);
+ if (WARN_ON(e >= CCP_MAX_ERROR_CODE))
+ return;
+
+ if (e < ARRAY_SIZE(ccp_error_codes))
+ dev_err(d->dev, "CCP error %d: %s\n", e, ccp_error_codes[e]);
+ else
+ dev_err(d->dev, "CCP error %d: Unknown Error\n", e);
}
/* List of CCPs, CCP count, read-write access lock, and access functions
diff --git a/drivers/crypto/ccp/ccp-dev.h b/drivers/crypto/ccp/ccp-dev.h
index 6810b65c1939..5e624920fd99 100644
--- a/drivers/crypto/ccp/ccp-dev.h
+++ b/drivers/crypto/ccp/ccp-dev.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* AMD Cryptographic Coprocessor (CCP) driver
*
@@ -5,10 +6,6 @@
*
* Author: Tom Lendacky <thomas.lendacky@amd.com>
* Author: Gary R Hook <gary.hook@amd.com>
- *
- * 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.
*/
#ifndef __CCP_DEV_H__
@@ -632,7 +629,7 @@ struct ccp5_desc {
void ccp_add_device(struct ccp_device *ccp);
void ccp_del_device(struct ccp_device *ccp);
-extern void ccp_log_error(struct ccp_device *, int);
+extern void ccp_log_error(struct ccp_device *, unsigned int);
struct ccp_device *ccp_alloc_struct(struct sp_device *sp);
bool ccp_queues_suspended(struct ccp_device *ccp);
diff --git a/drivers/crypto/ccp/ccp-dmaengine.c b/drivers/crypto/ccp/ccp-dmaengine.c
index 67155cb21636..7f22a45bbc11 100644
--- a/drivers/crypto/ccp/ccp-dmaengine.c
+++ b/drivers/crypto/ccp/ccp-dmaengine.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AMD Cryptographic Coprocessor (CCP) driver
*
* Copyright (C) 2016,2017 Advanced Micro Devices, Inc.
*
* Author: Gary R Hook <gary.hook@amd.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/crypto/ccp/ccp-ops.c b/drivers/crypto/ccp/ccp-ops.c
index 267a367bd076..c69ed4bae2eb 100644
--- a/drivers/crypto/ccp/ccp-ops.c
+++ b/drivers/crypto/ccp/ccp-ops.c
@@ -1,14 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AMD Cryptographic Coprocessor (CCP) driver
*
- * Copyright (C) 2013,2018 Advanced Micro Devices, Inc.
+ * Copyright (C) 2013-2019 Advanced Micro Devices, Inc.
*
* Author: Tom Lendacky <thomas.lendacky@amd.com>
* Author: Gary R Hook <gary.hook@amd.com>
- *
- * 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.
*/
#include <linux/module.h>
@@ -625,6 +622,7 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q,
unsigned long long *final;
unsigned int dm_offset;
+ unsigned int jobid;
unsigned int ilen;
bool in_place = true; /* Default value */
int ret;
@@ -663,9 +661,11 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q,
p_tag = scatterwalk_ffwd(sg_tag, p_inp, ilen);
}
+ jobid = CCP_NEW_JOBID(cmd_q->ccp);
+
memset(&op, 0, sizeof(op));
op.cmd_q = cmd_q;
- op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
+ op.jobid = jobid;
op.sb_key = cmd_q->sb_key; /* Pre-allocated */
op.sb_ctx = cmd_q->sb_ctx; /* Pre-allocated */
op.init = 1;
@@ -816,6 +816,13 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q,
final[0] = cpu_to_be64(aes->aad_len * 8);
final[1] = cpu_to_be64(ilen * 8);
+ memset(&op, 0, sizeof(op));
+ op.cmd_q = cmd_q;
+ op.jobid = jobid;
+ op.sb_key = cmd_q->sb_key; /* Pre-allocated */
+ op.sb_ctx = cmd_q->sb_ctx; /* Pre-allocated */
+ op.init = 1;
+ op.u.aes.type = aes->type;
op.u.aes.mode = CCP_AES_MODE_GHASH;
op.u.aes.action = CCP_AES_GHASHFINAL;
op.src.type = CCP_MEMTYPE_SYSTEM;
@@ -843,7 +850,8 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q,
if (ret)
goto e_tag;
- ret = memcmp(tag.address, final_wa.address, AES_BLOCK_SIZE);
+ ret = crypto_memneq(tag.address, final_wa.address,
+ AES_BLOCK_SIZE) ? -EBADMSG : 0;
ccp_dm_free(&tag);
}
@@ -893,8 +901,7 @@ static int ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
return -EINVAL;
if (((aes->mode == CCP_AES_MODE_ECB) ||
- (aes->mode == CCP_AES_MODE_CBC) ||
- (aes->mode == CCP_AES_MODE_CFB)) &&
+ (aes->mode == CCP_AES_MODE_CBC)) &&
(aes->src_len & (AES_BLOCK_SIZE - 1)))
return -EINVAL;
@@ -1267,6 +1274,9 @@ static int ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
int ret;
/* Error checks */
+ if (cmd_q->ccp->vdata->version < CCP_VERSION(5, 0))
+ return -EINVAL;
+
if (!cmd_q->ccp->vdata->perform->des3)
return -EINVAL;
@@ -1349,8 +1359,6 @@ static int ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
* passthru option to convert from big endian to little endian.
*/
if (des3->mode != CCP_DES3_MODE_ECB) {
- u32 load_mode;
-
op.sb_ctx = cmd_q->sb_ctx;
ret = ccp_init_dm_workarea(&ctx, cmd_q,
@@ -1366,12 +1374,8 @@ static int ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
if (ret)
goto e_ctx;
- if (cmd_q->ccp->vdata->version == CCP_VERSION(3, 0))
- load_mode = CCP_PASSTHRU_BYTESWAP_NOOP;
- else
- load_mode = CCP_PASSTHRU_BYTESWAP_256BIT;
ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
- load_mode);
+ CCP_PASSTHRU_BYTESWAP_256BIT);
if (ret) {
cmd->engine_error = cmd_q->cmd_error;
goto e_ctx;
@@ -1433,10 +1437,6 @@ static int ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
}
/* ...but we only need the last DES3_EDE_BLOCK_SIZE bytes */
- if (cmd_q->ccp->vdata->version == CCP_VERSION(3, 0))
- dm_offset = CCP_SB_BYTES - des3->iv_len;
- else
- dm_offset = 0;
ccp_get_dm_area(&ctx, dm_offset, des3->iv, 0,
DES3_EDE_BLOCK_SIZE);
}
diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c
index 656838433f2f..6b17d179ef8a 100644
--- a/drivers/crypto/ccp/psp-dev.c
+++ b/drivers/crypto/ccp/psp-dev.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AMD Platform Security Processor (PSP) interface
*
* Copyright (C) 2016,2018 Advanced Micro Devices, Inc.
*
* Author: Brijesh Singh <brijesh.singh@amd.com>
- *
- * 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.
*/
#include <linux/module.h>
@@ -27,10 +24,6 @@
#include "sp-dev.h"
#include "psp-dev.h"
-#define SEV_VERSION_GREATER_OR_EQUAL(_maj, _min) \
- ((psp_master->api_major) >= _maj && \
- (psp_master->api_minor) >= _min)
-
#define DEVICE_NAME "sev"
#define SEV_FW_FILE "amd/sev.fw"
#define SEV_FW_NAME_SIZE 64
@@ -50,6 +43,15 @@ MODULE_PARM_DESC(psp_probe_timeout, " default timeout value, in seconds, during
static bool psp_dead;
static int psp_timeout;
+static inline bool sev_version_greater_or_equal(u8 maj, u8 min)
+{
+ if (psp_master->api_major > maj)
+ return true;
+ if (psp_master->api_major == maj && psp_master->api_minor >= min)
+ return true;
+ return false;
+}
+
static struct psp_device *psp_alloc_struct(struct sp_device *sp)
{
struct device *dev = sp->dev;
@@ -591,7 +593,7 @@ static int sev_ioctl_do_get_id2(struct sev_issue_cmd *argp)
int ret;
/* SEV GET_ID is available from SEV API v0.16 and up */
- if (!SEV_VERSION_GREATER_OR_EQUAL(0, 16))
+ if (!sev_version_greater_or_equal(0, 16))
return -ENOTSUPP;
if (copy_from_user(&input, (void __user *)argp->data, sizeof(input)))
@@ -654,7 +656,7 @@ static int sev_ioctl_do_get_id(struct sev_issue_cmd *argp)
int ret;
/* SEV GET_ID available from SEV API v0.16 and up */
- if (!SEV_VERSION_GREATER_OR_EQUAL(0, 16))
+ if (!sev_version_greater_or_equal(0, 16))
return -ENOTSUPP;
/* SEV FW expects the buffer it fills with the ID to be
@@ -1056,7 +1058,7 @@ void psp_pci_init(void)
psp_master->sev_state = SEV_STATE_UNINIT;
}
- if (SEV_VERSION_GREATER_OR_EQUAL(0, 15) &&
+ if (sev_version_greater_or_equal(0, 15) &&
sev_update_firmware(psp_master->dev) == 0)
sev_get_api_version();
diff --git a/drivers/crypto/ccp/psp-dev.h b/drivers/crypto/ccp/psp-dev.h
index f5afeccf42a1..c5e06c92d40e 100644
--- a/drivers/crypto/ccp/psp-dev.h
+++ b/drivers/crypto/ccp/psp-dev.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* AMD Platform Security Processor (PSP) interface driver
*
* Copyright (C) 2017-2018 Advanced Micro Devices, Inc.
*
* Author: Brijesh Singh <brijesh.singh@amd.com>
- *
- * 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.
*/
#ifndef __PSP_DEV_H__
diff --git a/drivers/crypto/ccp/sp-dev.c b/drivers/crypto/ccp/sp-dev.c
index b2879767fc98..ce42675d3274 100644
--- a/drivers/crypto/ccp/sp-dev.c
+++ b/drivers/crypto/ccp/sp-dev.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AMD Secure Processor driver
*
@@ -6,10 +7,6 @@
* Author: Tom Lendacky <thomas.lendacky@amd.com>
* Author: Gary R Hook <gary.hook@amd.com>
* Author: Brijesh Singh <brijesh.singh@amd.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/crypto/ccp/sp-dev.h b/drivers/crypto/ccp/sp-dev.h
index 5b0790025db3..8abe9ea7e76f 100644
--- a/drivers/crypto/ccp/sp-dev.h
+++ b/drivers/crypto/ccp/sp-dev.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* AMD Secure Processor driver
*
@@ -6,10 +7,6 @@
* Author: Tom Lendacky <thomas.lendacky@amd.com>
* Author: Gary R Hook <gary.hook@amd.com>
* Author: Brijesh Singh <brijesh.singh@amd.com>
- *
- * 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.
*/
#ifndef __SP_DEV_H__
diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c
index 41bce0a3f4bb..b29d2e663e10 100644
--- a/drivers/crypto/ccp/sp-pci.c
+++ b/drivers/crypto/ccp/sp-pci.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AMD Secure Processor device driver
*
@@ -5,10 +6,6 @@
*
* Author: Tom Lendacky <thomas.lendacky@amd.com>
* Author: Gary R Hook <gary.hook@amd.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/crypto/ccp/sp-platform.c b/drivers/crypto/ccp/sp-platform.c
index d24228efbaaa..1b45236e3716 100644
--- a/drivers/crypto/ccp/sp-platform.c
+++ b/drivers/crypto/ccp/sp-platform.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AMD Secure Processor device driver
*
* Copyright (C) 2014,2018 Advanced Micro Devices, Inc.
*
* Author: Tom Lendacky <thomas.lendacky@amd.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/crypto/ccree/cc_driver.c b/drivers/crypto/ccree/cc_driver.c
index 86ac7b443355..980aa04b655b 100644
--- a/drivers/crypto/ccree/cc_driver.c
+++ b/drivers/crypto/ccree/cc_driver.c
@@ -48,6 +48,7 @@ struct cc_hw_data {
};
#define CC_NUM_IDRS 4
+#define CC_HW_RESET_LOOP_COUNT 10
/* Note: PIDR3 holds CMOD/Rev so ignored for HW identification purposes */
static const u32 pidr_0124_offsets[CC_NUM_IDRS] = {
@@ -133,6 +134,9 @@ static irqreturn_t cc_isr(int irq, void *dev_id)
u32 imr;
/* STAT_OP_TYPE_GENERIC STAT_PHASE_0: Interrupt */
+ /* if driver suspended return, probebly shared interrupt */
+ if (cc_pm_is_dev_suspended(dev))
+ return IRQ_NONE;
/* read the interrupt status */
irr = cc_ioread(drvdata, CC_REG(HOST_IRR));
@@ -188,6 +192,31 @@ static irqreturn_t cc_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
+bool cc_wait_for_reset_completion(struct cc_drvdata *drvdata)
+{
+ unsigned int val;
+ unsigned int i;
+
+ /* 712/710/63 has no reset completion indication, always return true */
+ if (drvdata->hw_rev <= CC_HW_REV_712)
+ return true;
+
+ for (i = 0; i < CC_HW_RESET_LOOP_COUNT; i++) {
+ /* in cc7x3 NVM_IS_IDLE indicates that CC reset is
+ * completed and device is fully functional
+ */
+ val = cc_ioread(drvdata, CC_REG(NVM_IS_IDLE));
+ if (val & CC_NVM_IS_IDLE_MASK) {
+ /* hw indicate reset completed */
+ return true;
+ }
+ /* allow scheduling other process on the processor */
+ schedule();
+ }
+ /* reset not completed */
+ return false;
+}
+
int init_cc_regs(struct cc_drvdata *drvdata, bool is_probe)
{
unsigned int val, cache_params;
@@ -315,15 +344,6 @@ static int init_cc_resources(struct platform_device *plat_dev)
return new_drvdata->irq;
}
- rc = devm_request_irq(dev, new_drvdata->irq, cc_isr,
- IRQF_SHARED, "ccree", new_drvdata);
- if (rc) {
- dev_err(dev, "Could not register to interrupt %d\n",
- new_drvdata->irq);
- return rc;
- }
- dev_dbg(dev, "Registered to IRQ: %d\n", new_drvdata->irq);
-
init_completion(&new_drvdata->hw_queue_avail);
if (!plat_dev->dev.dma_mask)
@@ -352,6 +372,11 @@ static int init_cc_resources(struct platform_device *plat_dev)
new_drvdata->sec_disabled = cc_sec_disable;
+ /* wait for Crytpcell reset completion */
+ if (!cc_wait_for_reset_completion(new_drvdata)) {
+ dev_err(dev, "Cryptocell reset not completed");
+ }
+
if (hw_rev->rev <= CC_HW_REV_712) {
/* Verify correct mapping */
val = cc_ioread(new_drvdata, new_drvdata->sig_offset);
@@ -383,6 +408,24 @@ static int init_cc_resources(struct platform_device *plat_dev)
}
sig_cidr = val;
+ /* Check HW engine configuration */
+ val = cc_ioread(new_drvdata, CC_REG(HOST_REMOVE_INPUT_PINS));
+ switch (val) {
+ case CC_PINS_FULL:
+ /* This is fine */
+ break;
+ case CC_PINS_SLIM:
+ if (new_drvdata->std_bodies & CC_STD_NIST) {
+ dev_warn(dev, "703 mode forced due to HW configuration.\n");
+ new_drvdata->std_bodies = CC_STD_OSCCA;
+ }
+ break;
+ default:
+ dev_err(dev, "Unsupported engines configration.\n");
+ rc = -EINVAL;
+ goto post_clk_err;
+ }
+
/* Check security disable state */
val = cc_ioread(new_drvdata, CC_REG(SECURITY_DISABLED));
val &= CC_SECURITY_DISABLED_MASK;
@@ -401,6 +444,15 @@ static int init_cc_resources(struct platform_device *plat_dev)
/* Display HW versions */
dev_info(dev, "ARM CryptoCell %s Driver: HW version 0x%08X/0x%8X, Driver version %s\n",
hw_rev->name, hw_rev_pidr, sig_cidr, DRV_MODULE_VERSION);
+ /* register the driver isr function */
+ rc = devm_request_irq(dev, new_drvdata->irq, cc_isr,
+ IRQF_SHARED, "ccree", new_drvdata);
+ if (rc) {
+ dev_err(dev, "Could not register to interrupt %d\n",
+ new_drvdata->irq);
+ goto post_clk_err;
+ }
+ dev_dbg(dev, "Registered to IRQ: %d\n", new_drvdata->irq);
rc = init_cc_regs(new_drvdata, true);
if (rc) {
diff --git a/drivers/crypto/ccree/cc_driver.h b/drivers/crypto/ccree/cc_driver.h
index b76181335c08..7cd99380bf1f 100644
--- a/drivers/crypto/ccree/cc_driver.h
+++ b/drivers/crypto/ccree/cc_driver.h
@@ -53,6 +53,9 @@ enum cc_std_body {
#define CC_COHERENT_CACHE_PARAMS 0xEEE
+#define CC_PINS_FULL 0x0
+#define CC_PINS_SLIM 0x9F
+
/* Maximum DMA mask supported by IP */
#define DMA_BIT_MASK_LEN 48
@@ -67,6 +70,8 @@ enum cc_std_body {
#define CC_SECURITY_DISABLED_MASK BIT(CC_SECURITY_DISABLED_VALUE_BIT_SHIFT)
+#define CC_NVM_IS_IDLE_MASK BIT(CC_NVM_IS_IDLE_VALUE_BIT_SHIFT)
+
#define AXIM_MON_COMP_VALUE GENMASK(CC_AXIM_MON_COMP_VALUE_BIT_SIZE + \
CC_AXIM_MON_COMP_VALUE_BIT_SHIFT, \
CC_AXIM_MON_COMP_VALUE_BIT_SHIFT)
@@ -216,6 +221,7 @@ static inline void dump_byte_array(const char *name, const u8 *the_array,
__dump_byte_array(name, the_array, size);
}
+bool cc_wait_for_reset_completion(struct cc_drvdata *drvdata);
int init_cc_regs(struct cc_drvdata *drvdata, bool is_probe);
void fini_cc_regs(struct cc_drvdata *drvdata);
int cc_clk_on(struct cc_drvdata *drvdata);
diff --git a/drivers/crypto/ccree/cc_host_regs.h b/drivers/crypto/ccree/cc_host_regs.h
index d0764147573f..efe3e1d8b87b 100644
--- a/drivers/crypto/ccree/cc_host_regs.h
+++ b/drivers/crypto/ccree/cc_host_regs.h
@@ -114,6 +114,9 @@
#define CC_HOST_ICR_DSCRPTR_WATERMARK_QUEUE0_CLEAR_BIT_SIZE 0x1UL
#define CC_HOST_ICR_AXIM_COMP_INT_CLEAR_BIT_SHIFT 0x17UL
#define CC_HOST_ICR_AXIM_COMP_INT_CLEAR_BIT_SIZE 0x1UL
+#define CC_NVM_IS_IDLE_REG_OFFSET 0x0A10UL
+#define CC_NVM_IS_IDLE_VALUE_BIT_SHIFT 0x0UL
+#define CC_NVM_IS_IDLE_VALUE_BIT_SIZE 0x1UL
#define CC_SECURITY_DISABLED_REG_OFFSET 0x0A1CUL
#define CC_SECURITY_DISABLED_VALUE_BIT_SHIFT 0x0UL
#define CC_SECURITY_DISABLED_VALUE_BIT_SIZE 0x1UL
@@ -203,6 +206,23 @@
#define CC_HOST_POWER_DOWN_EN_REG_OFFSET 0xA78UL
#define CC_HOST_POWER_DOWN_EN_VALUE_BIT_SHIFT 0x0UL
#define CC_HOST_POWER_DOWN_EN_VALUE_BIT_SIZE 0x1UL
+#define CC_HOST_REMOVE_INPUT_PINS_REG_OFFSET 0x0A7CUL
+#define CC_HOST_REMOVE_INPUT_PINS_REMOVE_AES_ENGINE_BIT_SHIFT 0x0UL
+#define CC_HOST_REMOVE_INPUT_PINS_REMOVE_AES_ENGINE_BIT_SIZE 0x1UL
+#define CC_HOST_REMOVE_INPUT_PINS_REMOVE_AES_MAC_ENGINE_BIT_SHIFT 0x1UL
+#define CC_HOST_REMOVE_INPUT_PINS_REMOVE_AES_MAC_ENGINE_BIT_SIZE 0x1UL
+#define CC_HOST_REMOVE_INPUT_PINS_REMOVE_GHASH_ENGINE_BIT_SHIFT 0x2UL
+#define CC_HOST_REMOVE_INPUT_PINS_REMOVE_GHASH_ENGINE_BIT_SIZE 0x1UL
+#define CC_HOST_REMOVE_INPUT_PINS_REMOVE_DES_ENGINE_BIT_SHIFT 0x3UL
+#define CC_HOST_REMOVE_INPUT_PINS_REMOVE_DES_ENGINE_BIT_SIZE 0x1UL
+#define CC_HOST_REMOVE_INPUT_PINS_REMOVE_HASH_ENGINE_BIT_SHIFT 0x4UL
+#define CC_HOST_REMOVE_INPUT_PINS_REMOVE_HASH_ENGINE_BIT_SIZE 0x1UL
+#define CC_HOST_REMOVE_INPUT_PINS_REMOVE_SM3_ENGINE_BIT_SHIFT 0x5UL
+#define CC_HOST_REMOVE_INPUT_PINS_REMOVE_SM3_ENGINE_BIT_SIZE 0x1UL
+#define CC_HOST_REMOVE_INPUT_PINS_REMOVE_SM4_ENGINE_BIT_SHIFT 0x6UL
+#define CC_HOST_REMOVE_INPUT_PINS_REMOVE_SM4_ENGINE_BIT_SIZE 0x1UL
+#define CC_HOST_REMOVE_INPUT_PINS_OTP_DISCONNECTED_BIT_SHIFT 0x7UL
+#define CC_HOST_REMOVE_INPUT_PINS_OTP_DISCONNECTED_BIT_SIZE 0x1UL
// --------------------------------------
// BLOCK: ID_REGISTERS
// --------------------------------------
diff --git a/drivers/crypto/ccree/cc_pm.c b/drivers/crypto/ccree/cc_pm.c
index 2dad9c9543c6..899a52f05b7a 100644
--- a/drivers/crypto/ccree/cc_pm.c
+++ b/drivers/crypto/ccree/cc_pm.c
@@ -49,6 +49,11 @@ int cc_pm_resume(struct device *dev)
dev_err(dev, "failed getting clock back on. We're toast.\n");
return rc;
}
+ /* wait for Crytpcell reset completion */
+ if (!cc_wait_for_reset_completion(drvdata)) {
+ dev_err(dev, "Cryptocell reset not completed");
+ return -EBUSY;
+ }
cc_iowrite(drvdata, CC_REG(HOST_POWER_DOWN_EN), POWER_DOWN_DISABLE);
rc = init_cc_regs(drvdata, false);
@@ -101,6 +106,12 @@ int cc_pm_put_suspend(struct device *dev)
return rc;
}
+bool cc_pm_is_dev_suspended(struct device *dev)
+{
+ /* check device state using runtime api */
+ return pm_runtime_suspended(dev);
+}
+
int cc_pm_init(struct cc_drvdata *drvdata)
{
struct device *dev = drvdata_to_dev(drvdata);
diff --git a/drivers/crypto/ccree/cc_pm.h b/drivers/crypto/ccree/cc_pm.h
index 6190cdba5dad..a7d98a5da2e1 100644
--- a/drivers/crypto/ccree/cc_pm.h
+++ b/drivers/crypto/ccree/cc_pm.h
@@ -22,6 +22,7 @@ int cc_pm_suspend(struct device *dev);
int cc_pm_resume(struct device *dev);
int cc_pm_get(struct device *dev);
int cc_pm_put_suspend(struct device *dev);
+bool cc_pm_is_dev_suspended(struct device *dev);
#else
@@ -54,6 +55,12 @@ static inline int cc_pm_put_suspend(struct device *dev)
return 0;
}
+static inline bool cc_pm_is_dev_suspended(struct device *dev)
+{
+ /* if PM not supported device is never suspend */
+ return false;
+}
+
#endif
#endif /*__POWER_MGR_H__*/
diff --git a/drivers/crypto/chelsio/chtls/chtls.h b/drivers/crypto/chelsio/chtls/chtls.h
index 59bb67d5a7ce..025c831d0899 100644
--- a/drivers/crypto/chelsio/chtls/chtls.h
+++ b/drivers/crypto/chelsio/chtls/chtls.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2018 Chelsio Communications, 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.
*/
#ifndef __CHTLS_H__
diff --git a/drivers/crypto/chelsio/chtls/chtls_cm.c b/drivers/crypto/chelsio/chtls/chtls_cm.c
index 4e22332496c5..774d991d7cca 100644
--- a/drivers/crypto/chelsio/chtls/chtls_cm.c
+++ b/drivers/crypto/chelsio/chtls/chtls_cm.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2018 Chelsio Communications, 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.
- *
* Written by: Atul Gupta (atul.gupta@chelsio.com)
*/
diff --git a/drivers/crypto/chelsio/chtls/chtls_cm.h b/drivers/crypto/chelsio/chtls/chtls_cm.h
index 78eb3afa3a80..129d7ac649a9 100644
--- a/drivers/crypto/chelsio/chtls/chtls_cm.h
+++ b/drivers/crypto/chelsio/chtls/chtls_cm.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2018 Chelsio Communications, 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.
*/
#ifndef __CHTLS_CM_H__
diff --git a/drivers/crypto/chelsio/chtls/chtls_hw.c b/drivers/crypto/chelsio/chtls/chtls_hw.c
index 490960755864..f2424f4c5f78 100644
--- a/drivers/crypto/chelsio/chtls/chtls_hw.c
+++ b/drivers/crypto/chelsio/chtls/chtls_hw.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2018 Chelsio Communications, 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.
- *
* Written by: Atul Gupta (atul.gupta@chelsio.com)
*/
diff --git a/drivers/crypto/chelsio/chtls/chtls_io.c b/drivers/crypto/chelsio/chtls/chtls_io.c
index 1285a1bceda7..551bca6fef24 100644
--- a/drivers/crypto/chelsio/chtls/chtls_io.c
+++ b/drivers/crypto/chelsio/chtls/chtls_io.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2018 Chelsio Communications, 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.
- *
* Written by: Atul Gupta (atul.gupta@chelsio.com)
*/
diff --git a/drivers/crypto/chelsio/chtls/chtls_main.c b/drivers/crypto/chelsio/chtls/chtls_main.c
index dd2daf2a54e0..635bb4b447fb 100644
--- a/drivers/crypto/chelsio/chtls/chtls_main.c
+++ b/drivers/crypto/chelsio/chtls/chtls_main.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2018 Chelsio Communications, 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.
- *
* Written by: Atul Gupta (atul.gupta@chelsio.com)
*/
#include <linux/kernel.h>
diff --git a/drivers/crypto/hisilicon/sec/sec_drv.h b/drivers/crypto/hisilicon/sec/sec_drv.h
index 2d2f186674ba..4d9063a8b10b 100644
--- a/drivers/crypto/hisilicon/sec/sec_drv.h
+++ b/drivers/crypto/hisilicon/sec/sec_drv.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2016-2017 Hisilicon Limited. */
#ifndef _SEC_DRV_H_
diff --git a/drivers/crypto/img-hash.c b/drivers/crypto/img-hash.c
index b87000a0a01c..d27c812c3d8d 100644
--- a/drivers/crypto/img-hash.c
+++ b/drivers/crypto/img-hash.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014 Imagination Technologies
* Authors: Will Thomas, James Hartley
*
- * 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.
- *
* Interface structure taken from omap-sham driver
*/
diff --git a/drivers/crypto/inside-secure/safexcel.c b/drivers/crypto/inside-secure/safexcel.c
index 86c699c14f84..df43a2c6933b 100644
--- a/drivers/crypto/inside-secure/safexcel.c
+++ b/drivers/crypto/inside-secure/safexcel.c
@@ -398,6 +398,12 @@ static int safexcel_hw_init(struct safexcel_crypto_priv *priv)
/* Processing Engine configuration */
+ /* Token & context configuration */
+ val = EIP197_PE_EIP96_TOKEN_CTRL_CTX_UPDATES |
+ EIP197_PE_EIP96_TOKEN_CTRL_REUSE_CTX |
+ EIP197_PE_EIP96_TOKEN_CTRL_POST_REUSE_CTX;
+ writel(val, EIP197_PE(priv) + EIP197_PE_EIP96_TOKEN_CTRL(pe));
+
/* H/W capabilities selection */
val = EIP197_FUNCTION_RSVD;
val |= EIP197_PROTOCOL_ENCRYPT_ONLY | EIP197_PROTOCOL_HASH_ONLY;
@@ -589,9 +595,9 @@ inline int safexcel_rdesc_check_errors(struct safexcel_crypto_priv *priv,
if (rdesc->result_data.error_code & 0x407f) {
/* Fatal error (bits 0-7, 14) */
dev_err(priv->dev,
- "cipher: result: result descriptor error (%d)\n",
+ "cipher: result: result descriptor error (0x%x)\n",
rdesc->result_data.error_code);
- return -EIO;
+ return -EINVAL;
} else if (rdesc->result_data.error_code == BIT(9)) {
/* Authentication failed */
return -EBADMSG;
@@ -720,11 +726,10 @@ handle_results:
}
acknowledge:
- if (i) {
+ if (i)
writel(EIP197_xDR_PROC_xD_PKT(i) |
EIP197_xDR_PROC_xD_COUNT(tot_descs * priv->config.rd_offset),
EIP197_HIA_RDR(priv, ring) + EIP197_HIA_xDR_PROC_COUNT);
- }
/* If the number of requests overflowed the counter, try to proceed more
* requests.
diff --git a/drivers/crypto/inside-secure/safexcel.h b/drivers/crypto/inside-secure/safexcel.h
index 65624a81f0fd..e0c202f33674 100644
--- a/drivers/crypto/inside-secure/safexcel.h
+++ b/drivers/crypto/inside-secure/safexcel.h
@@ -118,6 +118,7 @@
#define EIP197_PE_ICE_SCRATCH_CTRL(n) (0x0d04 + (0x2000 * (n)))
#define EIP197_PE_ICE_FPP_CTRL(n) (0x0d80 + (0x2000 * (n)))
#define EIP197_PE_ICE_RAM_CTRL(n) (0x0ff0 + (0x2000 * (n)))
+#define EIP197_PE_EIP96_TOKEN_CTRL(n) (0x1000 + (0x2000 * (n)))
#define EIP197_PE_EIP96_FUNCTION_EN(n) (0x1004 + (0x2000 * (n)))
#define EIP197_PE_EIP96_CONTEXT_CTRL(n) (0x1008 + (0x2000 * (n)))
#define EIP197_PE_EIP96_CONTEXT_STAT(n) (0x100c + (0x2000 * (n)))
@@ -249,6 +250,11 @@
#define EIP197_PE_ICE_RAM_CTRL_PUE_PROG_EN BIT(0)
#define EIP197_PE_ICE_RAM_CTRL_FPP_PROG_EN BIT(1)
+/* EIP197_PE_EIP96_TOKEN_CTRL */
+#define EIP197_PE_EIP96_TOKEN_CTRL_CTX_UPDATES BIT(16)
+#define EIP197_PE_EIP96_TOKEN_CTRL_REUSE_CTX BIT(19)
+#define EIP197_PE_EIP96_TOKEN_CTRL_POST_REUSE_CTX BIT(20)
+
/* EIP197_PE_EIP96_FUNCTION_EN */
#define EIP197_FUNCTION_RSVD (BIT(6) | BIT(15) | BIT(20) | BIT(23))
#define EIP197_PROTOCOL_HASH_ONLY BIT(0)
@@ -333,6 +339,7 @@ struct safexcel_context_record {
#define CONTEXT_CONTROL_IV3 BIT(8)
#define CONTEXT_CONTROL_DIGEST_CNT BIT(9)
#define CONTEXT_CONTROL_COUNTER_MODE BIT(10)
+#define CONTEXT_CONTROL_CRYPTO_STORE BIT(12)
#define CONTEXT_CONTROL_HASH_STORE BIT(19)
/* The hash counter given to the engine in the context has a granularity of
@@ -425,6 +432,10 @@ struct safexcel_token {
#define EIP197_TOKEN_HASH_RESULT_VERIFY BIT(16)
+#define EIP197_TOKEN_CTX_OFFSET(x) (x)
+#define EIP197_TOKEN_DIRECTION_EXTERNAL BIT(11)
+#define EIP197_TOKEN_EXEC_IF_SUCCESSFUL (0x1 << 12)
+
#define EIP197_TOKEN_STAT_LAST_HASH BIT(0)
#define EIP197_TOKEN_STAT_LAST_PACKET BIT(1)
#define EIP197_TOKEN_OPCODE_DIRECTION 0x0
@@ -432,6 +443,7 @@ struct safexcel_token {
#define EIP197_TOKEN_OPCODE_NOOP EIP197_TOKEN_OPCODE_INSERT
#define EIP197_TOKEN_OPCODE_RETRIEVE 0x4
#define EIP197_TOKEN_OPCODE_VERIFY 0xd
+#define EIP197_TOKEN_OPCODE_CTX_ACCESS 0xe
#define EIP197_TOKEN_OPCODE_BYPASS GENMASK(3, 0)
static inline void eip197_noop_token(struct safexcel_token *token)
@@ -442,6 +454,8 @@ static inline void eip197_noop_token(struct safexcel_token *token)
/* Instructions */
#define EIP197_TOKEN_INS_INSERT_HASH_DIGEST 0x1c
+#define EIP197_TOKEN_INS_ORIGIN_IV0 0x14
+#define EIP197_TOKEN_INS_ORIGIN_LEN(x) ((x) << 5)
#define EIP197_TOKEN_INS_TYPE_OUTPUT BIT(5)
#define EIP197_TOKEN_INS_TYPE_HASH BIT(6)
#define EIP197_TOKEN_INS_TYPE_CRYTO BIT(7)
@@ -468,6 +482,7 @@ struct safexcel_control_data_desc {
#define EIP197_OPTION_MAGIC_VALUE BIT(0)
#define EIP197_OPTION_64BIT_CTX BIT(1)
+#define EIP197_OPTION_RC_AUTO (0x2 << 3)
#define EIP197_OPTION_CTX_CTRL_IN_CMD BIT(8)
#define EIP197_OPTION_2_TOKEN_IV_CMD GENMASK(11, 10)
#define EIP197_OPTION_4_TOKEN_IV_CMD GENMASK(11, 9)
@@ -629,7 +644,7 @@ struct safexcel_ahash_export_state {
u32 digest;
u32 state[SHA512_DIGEST_SIZE / sizeof(u32)];
- u8 cache[SHA512_BLOCK_SIZE];
+ u8 cache[SHA512_BLOCK_SIZE << 1];
};
/*
diff --git a/drivers/crypto/inside-secure/safexcel_cipher.c b/drivers/crypto/inside-secure/safexcel_cipher.c
index de4be10b172f..8cdbdbe35681 100644
--- a/drivers/crypto/inside-secure/safexcel_cipher.c
+++ b/drivers/crypto/inside-secure/safexcel_cipher.c
@@ -51,6 +51,8 @@ struct safexcel_cipher_ctx {
struct safexcel_cipher_req {
enum safexcel_cipher_direction direction;
+ /* Number of result descriptors associated to the request */
+ unsigned int rdescs;
bool needs_inv;
};
@@ -59,27 +61,26 @@ static void safexcel_skcipher_token(struct safexcel_cipher_ctx *ctx, u8 *iv,
u32 length)
{
struct safexcel_token *token;
- unsigned offset = 0;
+ u32 offset = 0, block_sz = 0;
if (ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CBC) {
switch (ctx->alg) {
case SAFEXCEL_DES:
- offset = DES_BLOCK_SIZE / sizeof(u32);
- memcpy(cdesc->control_data.token, iv, DES_BLOCK_SIZE);
+ block_sz = DES_BLOCK_SIZE;
cdesc->control_data.options |= EIP197_OPTION_2_TOKEN_IV_CMD;
break;
case SAFEXCEL_3DES:
- offset = DES3_EDE_BLOCK_SIZE / sizeof(u32);
- memcpy(cdesc->control_data.token, iv, DES3_EDE_BLOCK_SIZE);
+ block_sz = DES3_EDE_BLOCK_SIZE;
cdesc->control_data.options |= EIP197_OPTION_2_TOKEN_IV_CMD;
break;
-
case SAFEXCEL_AES:
- offset = AES_BLOCK_SIZE / sizeof(u32);
- memcpy(cdesc->control_data.token, iv, AES_BLOCK_SIZE);
+ block_sz = AES_BLOCK_SIZE;
cdesc->control_data.options |= EIP197_OPTION_4_TOKEN_IV_CMD;
break;
}
+
+ offset = block_sz / sizeof(u32);
+ memcpy(cdesc->control_data.token, iv, block_sz);
}
token = (struct safexcel_token *)(cdesc->control_data.token + offset);
@@ -91,6 +92,25 @@ static void safexcel_skcipher_token(struct safexcel_cipher_ctx *ctx, u8 *iv,
token[0].instructions = EIP197_TOKEN_INS_LAST |
EIP197_TOKEN_INS_TYPE_CRYTO |
EIP197_TOKEN_INS_TYPE_OUTPUT;
+
+ if (ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CBC) {
+ u32 last = (EIP197_MAX_TOKENS - 1) - offset;
+
+ token[last].opcode = EIP197_TOKEN_OPCODE_CTX_ACCESS;
+ token[last].packet_length = EIP197_TOKEN_DIRECTION_EXTERNAL |
+ EIP197_TOKEN_EXEC_IF_SUCCESSFUL|
+ EIP197_TOKEN_CTX_OFFSET(0x2);
+ token[last].stat = EIP197_TOKEN_STAT_LAST_HASH |
+ EIP197_TOKEN_STAT_LAST_PACKET;
+ token[last].instructions =
+ EIP197_TOKEN_INS_ORIGIN_LEN(block_sz / sizeof(u32)) |
+ EIP197_TOKEN_INS_ORIGIN_IV0;
+
+ /* Store the updated IV values back in the internal context
+ * registers.
+ */
+ cdesc->control_data.control1 |= CONTEXT_CONTROL_CRYPTO_STORE;
+ }
}
static void safexcel_aead_token(struct safexcel_cipher_ctx *ctx, u8 *iv,
@@ -333,7 +353,10 @@ static int safexcel_handle_req_result(struct safexcel_crypto_priv *priv, int rin
*ret = 0;
- do {
+ if (unlikely(!sreq->rdescs))
+ return 0;
+
+ while (sreq->rdescs--) {
rdesc = safexcel_ring_next_rptr(priv, &priv->ring[ring].rdr);
if (IS_ERR(rdesc)) {
dev_err(priv->dev,
@@ -346,21 +369,15 @@ static int safexcel_handle_req_result(struct safexcel_crypto_priv *priv, int rin
*ret = safexcel_rdesc_check_errors(priv, rdesc);
ndesc++;
- } while (!rdesc->last_seg);
+ }
safexcel_complete(priv, ring);
if (src == dst) {
- dma_unmap_sg(priv->dev, src,
- sg_nents_for_len(src, cryptlen),
- DMA_BIDIRECTIONAL);
+ dma_unmap_sg(priv->dev, src, sg_nents(src), DMA_BIDIRECTIONAL);
} else {
- dma_unmap_sg(priv->dev, src,
- sg_nents_for_len(src, cryptlen),
- DMA_TO_DEVICE);
- dma_unmap_sg(priv->dev, dst,
- sg_nents_for_len(dst, cryptlen),
- DMA_FROM_DEVICE);
+ dma_unmap_sg(priv->dev, src, sg_nents(src), DMA_TO_DEVICE);
+ dma_unmap_sg(priv->dev, dst, sg_nents(dst), DMA_FROM_DEVICE);
}
*should_complete = true;
@@ -385,26 +402,21 @@ static int safexcel_send_req(struct crypto_async_request *base, int ring,
int i, ret = 0;
if (src == dst) {
- nr_src = dma_map_sg(priv->dev, src,
- sg_nents_for_len(src, totlen),
+ nr_src = dma_map_sg(priv->dev, src, sg_nents(src),
DMA_BIDIRECTIONAL);
nr_dst = nr_src;
if (!nr_src)
return -EINVAL;
} else {
- nr_src = dma_map_sg(priv->dev, src,
- sg_nents_for_len(src, totlen),
+ nr_src = dma_map_sg(priv->dev, src, sg_nents(src),
DMA_TO_DEVICE);
if (!nr_src)
return -EINVAL;
- nr_dst = dma_map_sg(priv->dev, dst,
- sg_nents_for_len(dst, totlen),
+ nr_dst = dma_map_sg(priv->dev, dst, sg_nents(dst),
DMA_FROM_DEVICE);
if (!nr_dst) {
- dma_unmap_sg(priv->dev, src,
- sg_nents_for_len(src, totlen),
- DMA_TO_DEVICE);
+ dma_unmap_sg(priv->dev, src, nr_src, DMA_TO_DEVICE);
return -EINVAL;
}
}
@@ -454,7 +466,7 @@ static int safexcel_send_req(struct crypto_async_request *base, int ring,
/* result descriptors */
for_each_sg(dst, sg, nr_dst, i) {
- bool first = !i, last = (i == nr_dst - 1);
+ bool first = !i, last = sg_is_last(sg);
u32 len = sg_dma_len(sg);
rdesc = safexcel_add_rdesc(priv, ring, first, last,
@@ -483,16 +495,10 @@ cdesc_rollback:
safexcel_ring_rollback_wptr(priv, &priv->ring[ring].cdr);
if (src == dst) {
- dma_unmap_sg(priv->dev, src,
- sg_nents_for_len(src, totlen),
- DMA_BIDIRECTIONAL);
+ dma_unmap_sg(priv->dev, src, nr_src, DMA_BIDIRECTIONAL);
} else {
- dma_unmap_sg(priv->dev, src,
- sg_nents_for_len(src, totlen),
- DMA_TO_DEVICE);
- dma_unmap_sg(priv->dev, dst,
- sg_nents_for_len(dst, totlen),
- DMA_FROM_DEVICE);
+ dma_unmap_sg(priv->dev, src, nr_src, DMA_TO_DEVICE);
+ dma_unmap_sg(priv->dev, dst, nr_dst, DMA_FROM_DEVICE);
}
return ret;
@@ -501,6 +507,7 @@ cdesc_rollback:
static int safexcel_handle_inv_result(struct safexcel_crypto_priv *priv,
int ring,
struct crypto_async_request *base,
+ struct safexcel_cipher_req *sreq,
bool *should_complete, int *ret)
{
struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(base->tfm);
@@ -509,7 +516,10 @@ static int safexcel_handle_inv_result(struct safexcel_crypto_priv *priv,
*ret = 0;
- do {
+ if (unlikely(!sreq->rdescs))
+ return 0;
+
+ while (sreq->rdescs--) {
rdesc = safexcel_ring_next_rptr(priv, &priv->ring[ring].rdr);
if (IS_ERR(rdesc)) {
dev_err(priv->dev,
@@ -522,7 +532,7 @@ static int safexcel_handle_inv_result(struct safexcel_crypto_priv *priv,
*ret = safexcel_rdesc_check_errors(priv, rdesc);
ndesc++;
- } while (!rdesc->last_seg);
+ }
safexcel_complete(priv, ring);
@@ -560,16 +570,35 @@ static int safexcel_skcipher_handle_result(struct safexcel_crypto_priv *priv,
{
struct skcipher_request *req = skcipher_request_cast(async);
struct safexcel_cipher_req *sreq = skcipher_request_ctx(req);
+ struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(async->tfm);
int err;
if (sreq->needs_inv) {
sreq->needs_inv = false;
- err = safexcel_handle_inv_result(priv, ring, async,
+ err = safexcel_handle_inv_result(priv, ring, async, sreq,
should_complete, ret);
} else {
err = safexcel_handle_req_result(priv, ring, async, req->src,
req->dst, req->cryptlen, sreq,
should_complete, ret);
+
+ if (ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CBC) {
+ u32 block_sz = 0;
+
+ switch (ctx->alg) {
+ case SAFEXCEL_DES:
+ block_sz = DES_BLOCK_SIZE;
+ break;
+ case SAFEXCEL_3DES:
+ block_sz = DES3_EDE_BLOCK_SIZE;
+ break;
+ case SAFEXCEL_AES:
+ block_sz = AES_BLOCK_SIZE;
+ break;
+ }
+
+ memcpy(req->iv, ctx->base.ctxr->data, block_sz);
+ }
}
return err;
@@ -587,7 +616,7 @@ static int safexcel_aead_handle_result(struct safexcel_crypto_priv *priv,
if (sreq->needs_inv) {
sreq->needs_inv = false;
- err = safexcel_handle_inv_result(priv, ring, async,
+ err = safexcel_handle_inv_result(priv, ring, async, sreq,
should_complete, ret);
} else {
err = safexcel_handle_req_result(priv, ring, async, req->src,
@@ -633,6 +662,8 @@ static int safexcel_skcipher_send(struct crypto_async_request *async, int ring,
ret = safexcel_send_req(async, ring, sreq, req->src,
req->dst, req->cryptlen, 0, 0, req->iv,
commands, results);
+
+ sreq->rdescs = *results;
return ret;
}
@@ -655,6 +686,7 @@ static int safexcel_aead_send(struct crypto_async_request *async, int ring,
req->cryptlen, req->assoclen,
crypto_aead_authsize(tfm), req->iv,
commands, results);
+ sreq->rdescs = *results;
return ret;
}
diff --git a/drivers/crypto/inside-secure/safexcel_hash.c b/drivers/crypto/inside-secure/safexcel_hash.c
index ac9282c1a5ec..a80a5e757b1f 100644
--- a/drivers/crypto/inside-secure/safexcel_hash.c
+++ b/drivers/crypto/inside-secure/safexcel_hash.c
@@ -41,19 +41,21 @@ struct safexcel_ahash_req {
u64 len[2];
u64 processed[2];
- u8 cache[SHA512_BLOCK_SIZE] __aligned(sizeof(u32));
+ u8 cache[SHA512_BLOCK_SIZE << 1] __aligned(sizeof(u32));
dma_addr_t cache_dma;
unsigned int cache_sz;
- u8 cache_next[SHA512_BLOCK_SIZE] __aligned(sizeof(u32));
+ u8 cache_next[SHA512_BLOCK_SIZE << 1] __aligned(sizeof(u32));
};
static inline u64 safexcel_queued_len(struct safexcel_ahash_req *req)
{
- if (req->len[1] > req->processed[1])
- return 0xffffffff - (req->len[0] - req->processed[0]);
+ u64 len, processed;
- return req->len[0] - req->processed[0];
+ len = (0xffffffff * req->len[1]) + req->len[0];
+ processed = (0xffffffff * req->processed[1]) + req->processed[0];
+
+ return len - processed;
}
static void safexcel_hash_token(struct safexcel_command_desc *cdesc,
@@ -87,6 +89,9 @@ static void safexcel_context_control(struct safexcel_ahash_ctx *ctx,
cdesc->control_data.control0 |= ctx->alg;
cdesc->control_data.control0 |= req->digest;
+ if (!req->finish)
+ cdesc->control_data.control0 |= CONTEXT_CONTROL_NO_FINISH_HASH;
+
if (req->digest == CONTEXT_CONTROL_DIGEST_PRECOMPUTED) {
if (req->processed[0] || req->processed[1]) {
if (ctx->alg == CONTEXT_CONTROL_CRYPTO_ALG_MD5)
@@ -105,9 +110,6 @@ static void safexcel_context_control(struct safexcel_ahash_ctx *ctx,
cdesc->control_data.control0 |= CONTEXT_CONTROL_RESTART_HASH;
}
- if (!req->finish)
- cdesc->control_data.control0 |= CONTEXT_CONTROL_NO_FINISH_HASH;
-
/*
* Copy the input digest if needed, and setup the context
* fields. Do this now as we need it to setup the first command
@@ -183,6 +185,7 @@ static int safexcel_handle_req_result(struct safexcel_crypto_priv *priv, int rin
dma_unmap_single(priv->dev, sreq->cache_dma, sreq->cache_sz,
DMA_TO_DEVICE);
sreq->cache_dma = 0;
+ sreq->cache_sz = 0;
}
if (sreq->finish)
@@ -209,11 +212,15 @@ static int safexcel_ahash_send_req(struct crypto_async_request *async, int ring,
struct safexcel_command_desc *cdesc, *first_cdesc = NULL;
struct safexcel_result_desc *rdesc;
struct scatterlist *sg;
- int i, extra, n_cdesc = 0, ret = 0;
- u64 queued, len, cache_len;
+ int i, extra = 0, n_cdesc = 0, ret = 0;
+ u64 queued, len, cache_len, cache_max;
+
+ cache_max = crypto_ahash_blocksize(ahash);
+ if (req->digest == CONTEXT_CONTROL_DIGEST_HMAC)
+ cache_max <<= 1;
queued = len = safexcel_queued_len(req);
- if (queued <= crypto_ahash_blocksize(ahash))
+ if (queued <= cache_max)
cache_len = queued;
else
cache_len = queued - areq->nbytes;
@@ -223,26 +230,23 @@ static int safexcel_ahash_send_req(struct crypto_async_request *async, int ring,
* fit into full blocks, cache it for the next send() call.
*/
extra = queued & (crypto_ahash_blocksize(ahash) - 1);
+
+ if (req->digest == CONTEXT_CONTROL_DIGEST_HMAC &&
+ extra < crypto_ahash_blocksize(ahash))
+ extra += crypto_ahash_blocksize(ahash);
+
+ /* If this is not the last request and the queued data
+ * is a multiple of a block, cache the last one for now.
+ */
if (!extra)
- /* If this is not the last request and the queued data
- * is a multiple of a block, cache the last one for now.
- */
extra = crypto_ahash_blocksize(ahash);
- if (extra) {
- sg_pcopy_to_buffer(areq->src, sg_nents(areq->src),
- req->cache_next, extra,
- areq->nbytes - extra);
-
- queued -= extra;
- len -= extra;
+ sg_pcopy_to_buffer(areq->src, sg_nents(areq->src),
+ req->cache_next, extra,
+ areq->nbytes - extra);
- if (!queued) {
- *commands = 0;
- *results = 0;
- return 0;
- }
- }
+ queued -= extra;
+ len -= extra;
}
/* Add a command descriptor for the cached data, if any */
@@ -269,8 +273,7 @@ static int safexcel_ahash_send_req(struct crypto_async_request *async, int ring,
}
/* Now handle the current ahash request buffer(s) */
- req->nents = dma_map_sg(priv->dev, areq->src,
- sg_nents_for_len(areq->src, areq->nbytes),
+ req->nents = dma_map_sg(priv->dev, areq->src, sg_nents(areq->src),
DMA_TO_DEVICE);
if (!req->nents) {
ret = -ENOMEM;
@@ -345,6 +348,7 @@ unmap_cache:
if (req->cache_dma) {
dma_unmap_single(priv->dev, req->cache_dma, req->cache_sz,
DMA_TO_DEVICE);
+ req->cache_dma = 0;
req->cache_sz = 0;
}
@@ -486,7 +490,7 @@ static int safexcel_ahash_exit_inv(struct crypto_tfm *tfm)
struct safexcel_inv_result result = {};
int ring = ctx->base.ring;
- memset(req, 0, sizeof(struct ahash_request));
+ memset(req, 0, EIP197_AHASH_REQ_SIZE);
/* create invalidation request */
init_completion(&result.completion);
@@ -519,10 +523,9 @@ static int safexcel_ahash_exit_inv(struct crypto_tfm *tfm)
/* safexcel_ahash_cache: cache data until at least one request can be sent to
* the engine, aka. when there is at least 1 block size in the pipe.
*/
-static int safexcel_ahash_cache(struct ahash_request *areq)
+static int safexcel_ahash_cache(struct ahash_request *areq, u32 cache_max)
{
struct safexcel_ahash_req *req = ahash_request_ctx(areq);
- struct crypto_ahash *ahash = crypto_ahash_reqtfm(areq);
u64 queued, cache_len;
/* queued: everything accepted by the driver which will be handled by
@@ -539,7 +542,7 @@ static int safexcel_ahash_cache(struct ahash_request *areq)
* In case there isn't enough bytes to proceed (less than a
* block size), cache the data until we have enough.
*/
- if (cache_len + areq->nbytes <= crypto_ahash_blocksize(ahash)) {
+ if (cache_len + areq->nbytes <= cache_max) {
sg_pcopy_to_buffer(areq->src, sg_nents(areq->src),
req->cache + cache_len,
areq->nbytes, 0);
@@ -599,6 +602,7 @@ static int safexcel_ahash_update(struct ahash_request *areq)
{
struct safexcel_ahash_req *req = ahash_request_ctx(areq);
struct crypto_ahash *ahash = crypto_ahash_reqtfm(areq);
+ u32 cache_max;
/* If the request is 0 length, do nothing */
if (!areq->nbytes)
@@ -608,7 +612,11 @@ static int safexcel_ahash_update(struct ahash_request *areq)
if (req->len[0] < areq->nbytes)
req->len[1]++;
- safexcel_ahash_cache(areq);
+ cache_max = crypto_ahash_blocksize(ahash);
+ if (req->digest == CONTEXT_CONTROL_DIGEST_HMAC)
+ cache_max <<= 1;
+
+ safexcel_ahash_cache(areq, cache_max);
/*
* We're not doing partial updates when performing an hmac request.
@@ -621,7 +629,7 @@ static int safexcel_ahash_update(struct ahash_request *areq)
return safexcel_ahash_enqueue(areq);
if (!req->last_req &&
- safexcel_queued_len(req) > crypto_ahash_blocksize(ahash))
+ safexcel_queued_len(req) > cache_max)
return safexcel_ahash_enqueue(areq);
return 0;
@@ -678,6 +686,11 @@ static int safexcel_ahash_export(struct ahash_request *areq, void *out)
struct crypto_ahash *ahash = crypto_ahash_reqtfm(areq);
struct safexcel_ahash_req *req = ahash_request_ctx(areq);
struct safexcel_ahash_export_state *export = out;
+ u32 cache_sz;
+
+ cache_sz = crypto_ahash_blocksize(ahash);
+ if (req->digest == CONTEXT_CONTROL_DIGEST_HMAC)
+ cache_sz <<= 1;
export->len[0] = req->len[0];
export->len[1] = req->len[1];
@@ -687,7 +700,7 @@ static int safexcel_ahash_export(struct ahash_request *areq, void *out)
export->digest = req->digest;
memcpy(export->state, req->state, req->state_sz);
- memcpy(export->cache, req->cache, crypto_ahash_blocksize(ahash));
+ memcpy(export->cache, req->cache, cache_sz);
return 0;
}
@@ -697,12 +710,17 @@ static int safexcel_ahash_import(struct ahash_request *areq, const void *in)
struct crypto_ahash *ahash = crypto_ahash_reqtfm(areq);
struct safexcel_ahash_req *req = ahash_request_ctx(areq);
const struct safexcel_ahash_export_state *export = in;
+ u32 cache_sz;
int ret;
ret = crypto_ahash_init(areq);
if (ret)
return ret;
+ cache_sz = crypto_ahash_blocksize(ahash);
+ if (req->digest == CONTEXT_CONTROL_DIGEST_HMAC)
+ cache_sz <<= 1;
+
req->len[0] = export->len[0];
req->len[1] = export->len[1];
req->processed[0] = export->processed[0];
@@ -710,7 +728,7 @@ static int safexcel_ahash_import(struct ahash_request *areq, const void *in)
req->digest = export->digest;
- memcpy(req->cache, export->cache, crypto_ahash_blocksize(ahash));
+ memcpy(req->cache, export->cache, cache_sz);
memcpy(req->state, export->state, req->state_sz);
return 0;
diff --git a/drivers/crypto/inside-secure/safexcel_ring.c b/drivers/crypto/inside-secure/safexcel_ring.c
index eb75fa684876..142bc3f5c45c 100644
--- a/drivers/crypto/inside-secure/safexcel_ring.c
+++ b/drivers/crypto/inside-secure/safexcel_ring.c
@@ -145,6 +145,9 @@ struct safexcel_command_desc *safexcel_add_cdesc(struct safexcel_crypto_priv *pr
(lower_32_bits(context) & GENMASK(31, 2)) >> 2;
cdesc->control_data.context_hi = upper_32_bits(context);
+ if (priv->version == EIP197B || priv->version == EIP197D)
+ cdesc->control_data.options |= EIP197_OPTION_RC_AUTO;
+
/* TODO: large xform HMAC with SHA-384/512 uses refresh = 3 */
cdesc->control_data.refresh = 2;
diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c
index e5cf3a59c420..acedafe3fa98 100644
--- a/drivers/crypto/ixp4xx_crypto.c
+++ b/drivers/crypto/ixp4xx_crypto.c
@@ -100,7 +100,7 @@ struct buffer_desc {
u16 pkt_len;
u16 buf_len;
#endif
- u32 phys_addr;
+ dma_addr_t phys_addr;
u32 __reserved[4];
struct buffer_desc *next;
enum dma_data_direction dir;
@@ -117,9 +117,9 @@ struct crypt_ctl {
u8 mode; /* NPE_OP_* operation mode */
#endif
u8 iv[MAX_IVLEN]; /* IV for CBC mode or CTR IV for CTR mode */
- u32 icv_rev_aes; /* icv or rev aes */
- u32 src_buf;
- u32 dst_buf;
+ dma_addr_t icv_rev_aes; /* icv or rev aes */
+ dma_addr_t src_buf;
+ dma_addr_t dst_buf;
#ifdef __ARMEB__
u16 auth_offs; /* Authentication start offset */
u16 auth_len; /* Authentication data length */
@@ -320,7 +320,8 @@ static struct crypt_ctl *get_crypt_desc_emerg(void)
}
}
-static void free_buf_chain(struct device *dev, struct buffer_desc *buf,u32 phys)
+static void free_buf_chain(struct device *dev, struct buffer_desc *buf,
+ dma_addr_t phys)
{
while (buf) {
struct buffer_desc *buf1;
@@ -602,7 +603,7 @@ static int register_chain_var(struct crypto_tfm *tfm, u8 xpad, u32 target,
struct buffer_desc *buf;
int i;
u8 *pad;
- u32 pad_phys, buf_phys;
+ dma_addr_t pad_phys, buf_phys;
BUILD_BUG_ON(NPE_CTX_LEN < HMAC_PAD_BLOCKLEN);
pad = dma_pool_alloc(ctx_pool, GFP_KERNEL, &pad_phys);
@@ -787,7 +788,7 @@ static struct buffer_desc *chainup_buffers(struct device *dev,
for (; nbytes > 0; sg = sg_next(sg)) {
unsigned len = min(nbytes, sg->length);
struct buffer_desc *next_buf;
- u32 next_buf_phys;
+ dma_addr_t next_buf_phys;
void *ptr;
nbytes -= len;
diff --git a/drivers/crypto/marvell/cesa.c b/drivers/crypto/marvell/cesa.c
index a4aa6813de4b..8a5f0b0bdf77 100644
--- a/drivers/crypto/marvell/cesa.c
+++ b/drivers/crypto/marvell/cesa.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Support for Marvell's Cryptographic Engine and Security Accelerator (CESA)
* that can be found on the following platform: Orion, Kirkwood, Armada. This
@@ -8,10 +9,6 @@
*
* This work is based on an initial version written by
* Sebastian Andrzej Siewior < sebastian at breakpoint dot cc >
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/crypto/marvell/cipher.c b/drivers/crypto/marvell/cipher.c
index 2fd936b19c6d..f4321f3c0777 100644
--- a/drivers/crypto/marvell/cipher.c
+++ b/drivers/crypto/marvell/cipher.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Cipher algorithms supported by the CESA: DES, 3DES and AES.
*
@@ -6,10 +7,6 @@
*
* This work is based on an initial version written by
* Sebastian Andrzej Siewior < sebastian at breakpoint dot cc >
- *
- * 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.
*/
#include <crypto/aes.h>
diff --git a/drivers/crypto/marvell/hash.c b/drivers/crypto/marvell/hash.c
index fd456dd703bf..0f0ac851f4eb 100644
--- a/drivers/crypto/marvell/hash.c
+++ b/drivers/crypto/marvell/hash.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Hash algorithms supported by the CESA: MD5, SHA1 and SHA256.
*
@@ -6,10 +7,6 @@
*
* This work is based on an initial version written by
* Sebastian Andrzej Siewior < sebastian at breakpoint dot cc >
- *
- * 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.
*/
#include <crypto/hmac.h>
diff --git a/drivers/crypto/marvell/tdma.c b/drivers/crypto/marvell/tdma.c
index d0ef171c18df..45939d53e8d6 100644
--- a/drivers/crypto/marvell/tdma.c
+++ b/drivers/crypto/marvell/tdma.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Provide TDMA helper functions used by cipher and hash algorithm
* implementations.
@@ -7,10 +8,6 @@
*
* This work is based on an initial version written by
* Sebastian Andrzej Siewior < sebastian at breakpoint dot cc >
- *
- * 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.
*/
#include "cesa.h"
diff --git a/drivers/crypto/mediatek/mtk-aes.c b/drivers/crypto/mediatek/mtk-aes.c
index c2058cf59f57..b7477ee32ca0 100644
--- a/drivers/crypto/mediatek/mtk-aes.c
+++ b/drivers/crypto/mediatek/mtk-aes.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Cryptographic API.
*
@@ -5,10 +6,6 @@
*
* Copyright (c) 2016 Ryder Lee <ryder.lee@mediatek.com>
*
- * 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.
- *
* Some ideas are from atmel-aes.c drivers.
*/
diff --git a/drivers/crypto/mediatek/mtk-platform.c b/drivers/crypto/mediatek/mtk-platform.c
index 5660e5e5e022..125318a88cd4 100644
--- a/drivers/crypto/mediatek/mtk-platform.c
+++ b/drivers/crypto/mediatek/mtk-platform.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for EIP97 cryptographic accelerator.
*
* Copyright (c) 2016 Ryder Lee <ryder.lee@mediatek.com>
- *
- * 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.
- *
*/
#include <linux/clk.h>
diff --git a/drivers/crypto/mediatek/mtk-platform.h b/drivers/crypto/mediatek/mtk-platform.h
index f0831f1742ab..47920c51abac 100644
--- a/drivers/crypto/mediatek/mtk-platform.h
+++ b/drivers/crypto/mediatek/mtk-platform.h
@@ -1,12 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Driver for EIP97 cryptographic accelerator.
*
* Copyright (c) 2016 Ryder Lee <ryder.lee@mediatek.com>
- *
- * 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.
- *
*/
#ifndef __MTK_PLATFORM_H_
diff --git a/drivers/crypto/mediatek/mtk-sha.c b/drivers/crypto/mediatek/mtk-sha.c
index a0806ba40c68..f03b0f06fb2f 100644
--- a/drivers/crypto/mediatek/mtk-sha.c
+++ b/drivers/crypto/mediatek/mtk-sha.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Cryptographic API.
*
@@ -5,10 +6,6 @@
*
* Copyright (c) 2016 Ryder Lee <ryder.lee@mediatek.com>
*
- * 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.
- *
* Some ideas are from atmel-sha.c and omap-sham.c drivers.
*/
diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c
index bdc4c42d3ac8..f1fa637cb029 100644
--- a/drivers/crypto/mxs-dcp.c
+++ b/drivers/crypto/mxs-dcp.c
@@ -986,8 +986,6 @@ static int mxs_dcp_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct dcp *sdcp = NULL;
int i, ret;
-
- struct resource *iores;
int dcp_vmi_irq, dcp_irq;
if (global_sdcp) {
@@ -995,7 +993,6 @@ static int mxs_dcp_probe(struct platform_device *pdev)
return -ENODEV;
}
- iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dcp_vmi_irq = platform_get_irq(pdev, 0);
if (dcp_vmi_irq < 0) {
dev_err(dev, "Failed to get IRQ: (%d)!\n", dcp_vmi_irq);
@@ -1013,7 +1010,7 @@ static int mxs_dcp_probe(struct platform_device *pdev)
return -ENOMEM;
sdcp->dev = dev;
- sdcp->base = devm_ioremap_resource(dev, iores);
+ sdcp->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(sdcp->base))
return PTR_ERR(sdcp->base);
diff --git a/drivers/crypto/nx/nx-842-powernv.c b/drivers/crypto/nx/nx-842-powernv.c
index 4acbc47973e9..e78ff5c65ed6 100644
--- a/drivers/crypto/nx/nx-842-powernv.c
+++ b/drivers/crypto/nx/nx-842-powernv.c
@@ -27,8 +27,6 @@ MODULE_ALIAS_CRYPTO("842-nx");
#define WORKMEM_ALIGN (CRB_ALIGN)
#define CSB_WAIT_MAX (5000) /* ms */
#define VAS_RETRIES (10)
-/* # of requests allowed per RxFIFO at a time. 0 for unlimited */
-#define MAX_CREDITS_PER_RXFIFO (1024)
struct nx842_workmem {
/* Below fields must be properly aligned */
@@ -812,7 +810,11 @@ static int __init vas_cfg_coproc_info(struct device_node *dn, int chip_id,
rxattr.lnotify_lpid = lpid;
rxattr.lnotify_pid = pid;
rxattr.lnotify_tid = tid;
- rxattr.wcreds_max = MAX_CREDITS_PER_RXFIFO;
+ /*
+ * Maximum RX window credits can not be more than #CRBs in
+ * RxFIFO. Otherwise, can get checkstop if RxFIFO overruns.
+ */
+ rxattr.wcreds_max = fifo_size / CRB_SIZE;
/*
* Open a VAS receice window which is used to configure RxFIFO
diff --git a/drivers/crypto/nx/nx-842-pseries.c b/drivers/crypto/nx/nx-842-pseries.c
index 5c4aa606208c..2de5e3672e42 100644
--- a/drivers/crypto/nx/nx-842-pseries.c
+++ b/drivers/crypto/nx/nx-842-pseries.c
@@ -856,7 +856,7 @@ static ssize_t nx842_##_name##_show(struct device *dev, \
rcu_read_lock(); \
local_devdata = rcu_dereference(devdata); \
if (local_devdata) \
- p = snprintf(buf, PAGE_SIZE, "%ld\n", \
+ p = snprintf(buf, PAGE_SIZE, "%lld\n", \
atomic64_read(&local_devdata->counters->_name)); \
rcu_read_unlock(); \
return p; \
@@ -909,7 +909,7 @@ static ssize_t nx842_timehist_show(struct device *dev,
}
for (i = 0; i < (NX842_HIST_SLOTS - 2); i++) {
- bytes = snprintf(p, bytes_remain, "%u-%uus:\t%ld\n",
+ bytes = snprintf(p, bytes_remain, "%u-%uus:\t%lld\n",
i ? (2<<(i-1)) : 0, (2<<i)-1,
atomic64_read(&times[i]));
bytes_remain -= bytes;
@@ -917,7 +917,7 @@ static ssize_t nx842_timehist_show(struct device *dev,
}
/* The last bucket holds everything over
* 2<<(NX842_HIST_SLOTS - 2) us */
- bytes = snprintf(p, bytes_remain, "%uus - :\t%ld\n",
+ bytes = snprintf(p, bytes_remain, "%uus - :\t%lld\n",
2<<(NX842_HIST_SLOTS - 2),
atomic64_read(&times[(NX842_HIST_SLOTS - 1)]));
p += bytes;
diff --git a/drivers/crypto/nx/nx.c b/drivers/crypto/nx/nx.c
index 428c273a1ab6..28817880c76d 100644
--- a/drivers/crypto/nx/nx.c
+++ b/drivers/crypto/nx/nx.c
@@ -569,9 +569,7 @@ static int nx_register_algs(void)
memset(&nx_driver.stats, 0, sizeof(struct nx_stats));
- rc = NX_DEBUGFS_INIT(&nx_driver);
- if (rc)
- goto out;
+ NX_DEBUGFS_INIT(&nx_driver);
nx_driver.of.status = NX_OKAY;
diff --git a/drivers/crypto/nx/nx.h b/drivers/crypto/nx/nx.h
index c3e54af18645..c6b5a3be02be 100644
--- a/drivers/crypto/nx/nx.h
+++ b/drivers/crypto/nx/nx.h
@@ -76,20 +76,12 @@ struct nx_stats {
atomic_t last_error_pid;
};
-struct nx_debugfs {
- struct dentry *dfs_root;
- struct dentry *dfs_aes_ops, *dfs_aes_bytes;
- struct dentry *dfs_sha256_ops, *dfs_sha256_bytes;
- struct dentry *dfs_sha512_ops, *dfs_sha512_bytes;
- struct dentry *dfs_errors, *dfs_last_error, *dfs_last_error_pid;
-};
-
struct nx_crypto_driver {
struct nx_stats stats;
struct nx_of of;
struct vio_dev *viodev;
struct vio_driver viodriver;
- struct nx_debugfs dfs;
+ struct dentry *dfs_root;
};
#define NX_GCM4106_NONCE_LEN (4)
@@ -177,7 +169,7 @@ struct nx_sg *nx_walk_and_build(struct nx_sg *, unsigned int,
#define NX_DEBUGFS_INIT(drv) nx_debugfs_init(drv)
#define NX_DEBUGFS_FINI(drv) nx_debugfs_fini(drv)
-int nx_debugfs_init(struct nx_crypto_driver *);
+void nx_debugfs_init(struct nx_crypto_driver *);
void nx_debugfs_fini(struct nx_crypto_driver *);
#else
#define NX_DEBUGFS_INIT(drv) (0)
diff --git a/drivers/crypto/nx/nx_debugfs.c b/drivers/crypto/nx/nx_debugfs.c
index 03e4f0363c6a..e0d44a5512ab 100644
--- a/drivers/crypto/nx/nx_debugfs.c
+++ b/drivers/crypto/nx/nx_debugfs.c
@@ -30,62 +30,37 @@
* Documentation/ABI/testing/debugfs-pfo-nx-crypto
*/
-int nx_debugfs_init(struct nx_crypto_driver *drv)
+void nx_debugfs_init(struct nx_crypto_driver *drv)
{
- struct nx_debugfs *dfs = &drv->dfs;
+ struct dentry *root;
- dfs->dfs_root = debugfs_create_dir(NX_NAME, NULL);
+ root = debugfs_create_dir(NX_NAME, NULL);
+ drv->dfs_root = root;
- dfs->dfs_aes_ops =
- debugfs_create_u32("aes_ops",
- S_IRUSR | S_IRGRP | S_IROTH,
- dfs->dfs_root, (u32 *)&drv->stats.aes_ops);
- dfs->dfs_sha256_ops =
- debugfs_create_u32("sha256_ops",
- S_IRUSR | S_IRGRP | S_IROTH,
- dfs->dfs_root,
- (u32 *)&drv->stats.sha256_ops);
- dfs->dfs_sha512_ops =
- debugfs_create_u32("sha512_ops",
- S_IRUSR | S_IRGRP | S_IROTH,
- dfs->dfs_root,
- (u32 *)&drv->stats.sha512_ops);
- dfs->dfs_aes_bytes =
- debugfs_create_u64("aes_bytes",
- S_IRUSR | S_IRGRP | S_IROTH,
- dfs->dfs_root,
- (u64 *)&drv->stats.aes_bytes);
- dfs->dfs_sha256_bytes =
- debugfs_create_u64("sha256_bytes",
- S_IRUSR | S_IRGRP | S_IROTH,
- dfs->dfs_root,
- (u64 *)&drv->stats.sha256_bytes);
- dfs->dfs_sha512_bytes =
- debugfs_create_u64("sha512_bytes",
- S_IRUSR | S_IRGRP | S_IROTH,
- dfs->dfs_root,
- (u64 *)&drv->stats.sha512_bytes);
- dfs->dfs_errors =
- debugfs_create_u32("errors",
- S_IRUSR | S_IRGRP | S_IROTH,
- dfs->dfs_root, (u32 *)&drv->stats.errors);
- dfs->dfs_last_error =
- debugfs_create_u32("last_error",
- S_IRUSR | S_IRGRP | S_IROTH,
- dfs->dfs_root,
- (u32 *)&drv->stats.last_error);
- dfs->dfs_last_error_pid =
- debugfs_create_u32("last_error_pid",
- S_IRUSR | S_IRGRP | S_IROTH,
- dfs->dfs_root,
- (u32 *)&drv->stats.last_error_pid);
- return 0;
+ debugfs_create_u32("aes_ops", S_IRUSR | S_IRGRP | S_IROTH,
+ root, (u32 *)&drv->stats.aes_ops);
+ debugfs_create_u32("sha256_ops", S_IRUSR | S_IRGRP | S_IROTH,
+ root, (u32 *)&drv->stats.sha256_ops);
+ debugfs_create_u32("sha512_ops", S_IRUSR | S_IRGRP | S_IROTH,
+ root, (u32 *)&drv->stats.sha512_ops);
+ debugfs_create_u64("aes_bytes", S_IRUSR | S_IRGRP | S_IROTH,
+ root, (u64 *)&drv->stats.aes_bytes);
+ debugfs_create_u64("sha256_bytes", S_IRUSR | S_IRGRP | S_IROTH,
+ root, (u64 *)&drv->stats.sha256_bytes);
+ debugfs_create_u64("sha512_bytes", S_IRUSR | S_IRGRP | S_IROTH,
+ root, (u64 *)&drv->stats.sha512_bytes);
+ debugfs_create_u32("errors", S_IRUSR | S_IRGRP | S_IROTH,
+ root, (u32 *)&drv->stats.errors);
+ debugfs_create_u32("last_error", S_IRUSR | S_IRGRP | S_IROTH,
+ root, (u32 *)&drv->stats.last_error);
+ debugfs_create_u32("last_error_pid", S_IRUSR | S_IRGRP | S_IROTH,
+ root, (u32 *)&drv->stats.last_error_pid);
}
void
nx_debugfs_fini(struct nx_crypto_driver *drv)
{
- debugfs_remove_recursive(drv->dfs.dfs_root);
+ debugfs_remove_recursive(drv->dfs_root);
}
#endif
diff --git a/drivers/crypto/omap-aes-gcm.c b/drivers/crypto/omap-aes-gcm.c
index 0cc3b65d7162..9bbedbccfadf 100644
--- a/drivers/crypto/omap-aes-gcm.c
+++ b/drivers/crypto/omap-aes-gcm.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Cryptographic API.
*
* Support for OMAP AES GCM HW acceleration.
*
* Copyright (c) 2016 Texas Instruments Incorporated
- *
- * 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.
- *
*/
#include <linux/errno.h>
diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c
index 0120feb2d746..45a4647f7030 100644
--- a/drivers/crypto/omap-aes.c
+++ b/drivers/crypto/omap-aes.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Cryptographic API.
*
@@ -6,11 +7,6 @@
* Copyright (c) 2010 Nokia Corporation
* Author: Dmitry Kasatkin <dmitry.kasatkin@nokia.com>
* Copyright (c) 2011 Texas Instruments Incorporated
- *
- * 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.
- *
*/
#define pr_fmt(fmt) "%20s: " fmt, __func__
diff --git a/drivers/crypto/omap-aes.h b/drivers/crypto/omap-aes.h
index 7e02920ef6f8..2d4b1f87a1c9 100644
--- a/drivers/crypto/omap-aes.h
+++ b/drivers/crypto/omap-aes.h
@@ -1,14 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Cryptographic API.
*
* Support for OMAP AES HW ACCELERATOR defines
*
* Copyright (c) 2015 Texas Instruments Incorporated
- *
- * 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.
- *
*/
#ifndef __OMAP_AES_H__
#define __OMAP_AES_H__
diff --git a/drivers/crypto/omap-crypto.c b/drivers/crypto/omap-crypto.c
index 2c42e4b4a6e9..7d592d93bb1c 100644
--- a/drivers/crypto/omap-crypto.c
+++ b/drivers/crypto/omap-crypto.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* OMAP Crypto driver common support routines.
*
* Copyright (c) 2017 Texas Instruments Incorporated
* Tero Kristo <t-kristo@ti.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/crypto/omap-crypto.h b/drivers/crypto/omap-crypto.h
index 36a230eb87af..506ccde6f380 100644
--- a/drivers/crypto/omap-crypto.h
+++ b/drivers/crypto/omap-crypto.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* OMAP Crypto driver common support routines.
*
* Copyright (c) 2017 Texas Instruments Incorporated
* Tero Kristo <t-kristo@ti.com>
- *
- * 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.
*/
#ifndef __CRYPTO_OMAP_CRYPTO_H
diff --git a/drivers/crypto/omap-des.c b/drivers/crypto/omap-des.c
index 3d82d18ff810..1ee69a979677 100644
--- a/drivers/crypto/omap-des.c
+++ b/drivers/crypto/omap-des.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Support for OMAP DES and Triple DES HW acceleration.
*
* Copyright (c) 2013 Texas Instruments Incorporated
* Author: Joel Fernandes <joelf@ti.com>
- *
- * 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.
- *
*/
#define pr_fmt(fmt) "%s: " fmt, __func__
diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c
index 51b20abac464..e8e2907bd9f4 100644
--- a/drivers/crypto/omap-sham.c
+++ b/drivers/crypto/omap-sham.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Cryptographic API.
*
@@ -7,10 +8,6 @@
* Author: Dmitry Kasatkin <dmitry.kasatkin@nokia.com>
* Copyright (c) 2011 Texas Instruments Incorporated
*
- * 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.
- *
* Some ideas are from old omap-sha1-md5.c driver.
*/
diff --git a/drivers/crypto/qat/qat_common/qat_algs.c b/drivers/crypto/qat/qat_common/qat_algs.c
index c8d401646902..b50eb55f8f57 100644
--- a/drivers/crypto/qat/qat_common/qat_algs.c
+++ b/drivers/crypto/qat/qat_common/qat_algs.c
@@ -131,7 +131,6 @@ struct qat_alg_ablkcipher_ctx {
struct icp_qat_fw_la_bulk_req dec_fw_req;
struct qat_crypto_instance *inst;
struct crypto_tfm *tfm;
- spinlock_t lock; /* protects qat_alg_ablkcipher_ctx struct */
};
static int qat_get_inter_state_size(enum icp_qat_hw_auth_algo qat_hash_alg)
@@ -223,6 +222,9 @@ static int qat_alg_do_precomputes(struct icp_qat_hw_auth_algo_blk *hash,
return -EFAULT;
offset = round_up(qat_get_inter_state_size(ctx->qat_hash_alg), 8);
+ if (offset < 0)
+ return -EFAULT;
+
hash_state_out = (__be32 *)(hash->sha.state1 + offset);
hash512_state_out = (__be64 *)hash_state_out;
@@ -253,7 +255,24 @@ static int qat_alg_do_precomputes(struct icp_qat_hw_auth_algo_blk *hash,
return 0;
}
-static void qat_alg_init_common_hdr(struct icp_qat_fw_comn_req_hdr *header)
+static void qat_alg_init_hdr_iv_updt(struct icp_qat_fw_comn_req_hdr *header)
+{
+ ICP_QAT_FW_LA_CIPH_IV_FLD_FLAG_SET(header->serv_specif_flags,
+ ICP_QAT_FW_CIPH_IV_64BIT_PTR);
+ ICP_QAT_FW_LA_UPDATE_STATE_SET(header->serv_specif_flags,
+ ICP_QAT_FW_LA_UPDATE_STATE);
+}
+
+static void qat_alg_init_hdr_no_iv_updt(struct icp_qat_fw_comn_req_hdr *header)
+{
+ ICP_QAT_FW_LA_CIPH_IV_FLD_FLAG_SET(header->serv_specif_flags,
+ ICP_QAT_FW_CIPH_IV_16BYTE_DATA);
+ ICP_QAT_FW_LA_UPDATE_STATE_SET(header->serv_specif_flags,
+ ICP_QAT_FW_LA_NO_UPDATE_STATE);
+}
+
+static void qat_alg_init_common_hdr(struct icp_qat_fw_comn_req_hdr *header,
+ int aead)
{
header->hdr_flags =
ICP_QAT_FW_COMN_HDR_FLAGS_BUILD(ICP_QAT_FW_COMN_REQ_FLAG_SET);
@@ -263,12 +282,12 @@ static void qat_alg_init_common_hdr(struct icp_qat_fw_comn_req_hdr *header)
QAT_COMN_PTR_TYPE_SGL);
ICP_QAT_FW_LA_PARTIAL_SET(header->serv_specif_flags,
ICP_QAT_FW_LA_PARTIAL_NONE);
- ICP_QAT_FW_LA_CIPH_IV_FLD_FLAG_SET(header->serv_specif_flags,
- ICP_QAT_FW_CIPH_IV_16BYTE_DATA);
+ if (aead)
+ qat_alg_init_hdr_no_iv_updt(header);
+ else
+ qat_alg_init_hdr_iv_updt(header);
ICP_QAT_FW_LA_PROTO_SET(header->serv_specif_flags,
ICP_QAT_FW_LA_NO_PROTO);
- ICP_QAT_FW_LA_UPDATE_STATE_SET(header->serv_specif_flags,
- ICP_QAT_FW_LA_NO_UPDATE_STATE);
}
static int qat_alg_aead_init_enc_session(struct crypto_aead *aead_tfm,
@@ -303,7 +322,7 @@ static int qat_alg_aead_init_enc_session(struct crypto_aead *aead_tfm,
return -EFAULT;
/* Request setup */
- qat_alg_init_common_hdr(header);
+ qat_alg_init_common_hdr(header, 1);
header->service_cmd_id = ICP_QAT_FW_LA_CMD_CIPHER_HASH;
ICP_QAT_FW_LA_DIGEST_IN_BUFFER_SET(header->serv_specif_flags,
ICP_QAT_FW_LA_DIGEST_IN_BUFFER);
@@ -390,7 +409,7 @@ static int qat_alg_aead_init_dec_session(struct crypto_aead *aead_tfm,
return -EFAULT;
/* Request setup */
- qat_alg_init_common_hdr(header);
+ qat_alg_init_common_hdr(header, 1);
header->service_cmd_id = ICP_QAT_FW_LA_CMD_HASH_CIPHER;
ICP_QAT_FW_LA_DIGEST_IN_BUFFER_SET(header->serv_specif_flags,
ICP_QAT_FW_LA_DIGEST_IN_BUFFER);
@@ -454,7 +473,7 @@ static void qat_alg_ablkcipher_init_com(struct qat_alg_ablkcipher_ctx *ctx,
struct icp_qat_fw_cipher_cd_ctrl_hdr *cd_ctrl = (void *)&req->cd_ctrl;
memcpy(cd->aes.key, key, keylen);
- qat_alg_init_common_hdr(header);
+ qat_alg_init_common_hdr(header, 0);
header->service_cmd_id = ICP_QAT_FW_LA_CMD_CIPHER;
cd_pars->u.s.content_desc_params_sz =
sizeof(struct icp_qat_hw_cipher_algo_blk) >> 3;
@@ -576,45 +595,52 @@ bad_key:
return -EINVAL;
}
-static int qat_alg_aead_setkey(struct crypto_aead *tfm, const uint8_t *key,
+static int qat_alg_aead_rekey(struct crypto_aead *tfm, const uint8_t *key,
+ unsigned int keylen)
+{
+ struct qat_alg_aead_ctx *ctx = crypto_aead_ctx(tfm);
+
+ memset(ctx->enc_cd, 0, sizeof(*ctx->enc_cd));
+ memset(ctx->dec_cd, 0, sizeof(*ctx->dec_cd));
+ memset(&ctx->enc_fw_req, 0, sizeof(ctx->enc_fw_req));
+ memset(&ctx->dec_fw_req, 0, sizeof(ctx->dec_fw_req));
+
+ return qat_alg_aead_init_sessions(tfm, key, keylen,
+ ICP_QAT_HW_CIPHER_CBC_MODE);
+}
+
+static int qat_alg_aead_newkey(struct crypto_aead *tfm, const uint8_t *key,
unsigned int keylen)
{
struct qat_alg_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ struct qat_crypto_instance *inst = NULL;
+ int node = get_current_node();
struct device *dev;
+ int ret;
- if (ctx->enc_cd) {
- /* rekeying */
- dev = &GET_DEV(ctx->inst->accel_dev);
- memset(ctx->enc_cd, 0, sizeof(*ctx->enc_cd));
- memset(ctx->dec_cd, 0, sizeof(*ctx->dec_cd));
- memset(&ctx->enc_fw_req, 0, sizeof(ctx->enc_fw_req));
- memset(&ctx->dec_fw_req, 0, sizeof(ctx->dec_fw_req));
- } else {
- /* new key */
- int node = get_current_node();
- struct qat_crypto_instance *inst =
- qat_crypto_get_instance_node(node);
- if (!inst) {
- return -EINVAL;
- }
-
- dev = &GET_DEV(inst->accel_dev);
- ctx->inst = inst;
- ctx->enc_cd = dma_alloc_coherent(dev, sizeof(*ctx->enc_cd),
- &ctx->enc_cd_paddr,
- GFP_ATOMIC);
- if (!ctx->enc_cd) {
- return -ENOMEM;
- }
- ctx->dec_cd = dma_alloc_coherent(dev, sizeof(*ctx->dec_cd),
- &ctx->dec_cd_paddr,
- GFP_ATOMIC);
- if (!ctx->dec_cd) {
- goto out_free_enc;
- }
+ inst = qat_crypto_get_instance_node(node);
+ if (!inst)
+ return -EINVAL;
+ dev = &GET_DEV(inst->accel_dev);
+ ctx->inst = inst;
+ ctx->enc_cd = dma_alloc_coherent(dev, sizeof(*ctx->enc_cd),
+ &ctx->enc_cd_paddr,
+ GFP_ATOMIC);
+ if (!ctx->enc_cd) {
+ ret = -ENOMEM;
+ goto out_free_inst;
+ }
+ ctx->dec_cd = dma_alloc_coherent(dev, sizeof(*ctx->dec_cd),
+ &ctx->dec_cd_paddr,
+ GFP_ATOMIC);
+ if (!ctx->dec_cd) {
+ ret = -ENOMEM;
+ goto out_free_enc;
}
- if (qat_alg_aead_init_sessions(tfm, key, keylen,
- ICP_QAT_HW_CIPHER_CBC_MODE))
+
+ ret = qat_alg_aead_init_sessions(tfm, key, keylen,
+ ICP_QAT_HW_CIPHER_CBC_MODE);
+ if (ret)
goto out_free_all;
return 0;
@@ -629,7 +655,21 @@ out_free_enc:
dma_free_coherent(dev, sizeof(struct qat_alg_cd),
ctx->enc_cd, ctx->enc_cd_paddr);
ctx->enc_cd = NULL;
- return -ENOMEM;
+out_free_inst:
+ ctx->inst = NULL;
+ qat_crypto_put_instance(inst);
+ return ret;
+}
+
+static int qat_alg_aead_setkey(struct crypto_aead *tfm, const uint8_t *key,
+ unsigned int keylen)
+{
+ struct qat_alg_aead_ctx *ctx = crypto_aead_ctx(tfm);
+
+ if (ctx->enc_cd)
+ return qat_alg_aead_rekey(tfm, key, keylen);
+ else
+ return qat_alg_aead_newkey(tfm, key, keylen);
}
static void qat_alg_free_bufl(struct qat_crypto_instance *inst,
@@ -677,8 +717,7 @@ static int qat_alg_sgl_to_bufl(struct qat_crypto_instance *inst,
dma_addr_t blp;
dma_addr_t bloutp = 0;
struct scatterlist *sg;
- size_t sz_out, sz = sizeof(struct qat_alg_buf_list) +
- ((1 + n) * sizeof(struct qat_alg_buf));
+ size_t sz_out, sz = struct_size(bufl, bufers, n + 1);
if (unlikely(!n))
return -EINVAL;
@@ -715,8 +754,7 @@ static int qat_alg_sgl_to_bufl(struct qat_crypto_instance *inst,
struct qat_alg_buf *bufers;
n = sg_nents(sglout);
- sz_out = sizeof(struct qat_alg_buf_list) +
- ((1 + n) * sizeof(struct qat_alg_buf));
+ sz_out = struct_size(buflout, bufers, n + 1);
sg_nctr = 0;
buflout = kzalloc_node(sz_out, GFP_ATOMIC,
dev_to_node(&GET_DEV(inst->accel_dev)));
@@ -801,11 +839,17 @@ static void qat_ablkcipher_alg_callback(struct icp_qat_fw_la_resp *qat_resp,
struct qat_crypto_instance *inst = ctx->inst;
struct ablkcipher_request *areq = qat_req->ablkcipher_req;
uint8_t stat_filed = qat_resp->comn_resp.comn_status;
+ struct device *dev = &GET_DEV(ctx->inst->accel_dev);
int res = 0, qat_res = ICP_QAT_FW_COMN_RESP_CRYPTO_STAT_GET(stat_filed);
qat_alg_free_bufl(inst, qat_req);
if (unlikely(qat_res != ICP_QAT_FW_COMN_STATUS_FLAG_OK))
res = -EINVAL;
+
+ memcpy(areq->info, qat_req->iv, AES_BLOCK_SIZE);
+ dma_free_coherent(dev, AES_BLOCK_SIZE, qat_req->iv,
+ qat_req->iv_paddr);
+
areq->base.complete(&areq->base, res);
}
@@ -905,50 +949,49 @@ static int qat_alg_aead_enc(struct aead_request *areq)
return -EINPROGRESS;
}
-static int qat_alg_ablkcipher_setkey(struct crypto_ablkcipher *tfm,
+static int qat_alg_ablkcipher_rekey(struct qat_alg_ablkcipher_ctx *ctx,
+ const u8 *key, unsigned int keylen,
+ int mode)
+{
+ memset(ctx->enc_cd, 0, sizeof(*ctx->enc_cd));
+ memset(ctx->dec_cd, 0, sizeof(*ctx->dec_cd));
+ memset(&ctx->enc_fw_req, 0, sizeof(ctx->enc_fw_req));
+ memset(&ctx->dec_fw_req, 0, sizeof(ctx->dec_fw_req));
+
+ return qat_alg_ablkcipher_init_sessions(ctx, key, keylen, mode);
+}
+
+static int qat_alg_ablkcipher_newkey(struct qat_alg_ablkcipher_ctx *ctx,
const u8 *key, unsigned int keylen,
int mode)
{
- struct qat_alg_ablkcipher_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+ struct qat_crypto_instance *inst = NULL;
struct device *dev;
+ int node = get_current_node();
+ int ret;
- spin_lock(&ctx->lock);
- if (ctx->enc_cd) {
- /* rekeying */
- dev = &GET_DEV(ctx->inst->accel_dev);
- memset(ctx->enc_cd, 0, sizeof(*ctx->enc_cd));
- memset(ctx->dec_cd, 0, sizeof(*ctx->dec_cd));
- memset(&ctx->enc_fw_req, 0, sizeof(ctx->enc_fw_req));
- memset(&ctx->dec_fw_req, 0, sizeof(ctx->dec_fw_req));
- } else {
- /* new key */
- int node = get_current_node();
- struct qat_crypto_instance *inst =
- qat_crypto_get_instance_node(node);
- if (!inst) {
- spin_unlock(&ctx->lock);
- return -EINVAL;
- }
-
- dev = &GET_DEV(inst->accel_dev);
- ctx->inst = inst;
- ctx->enc_cd = dma_alloc_coherent(dev, sizeof(*ctx->enc_cd),
- &ctx->enc_cd_paddr,
- GFP_ATOMIC);
- if (!ctx->enc_cd) {
- spin_unlock(&ctx->lock);
- return -ENOMEM;
- }
- ctx->dec_cd = dma_alloc_coherent(dev, sizeof(*ctx->dec_cd),
- &ctx->dec_cd_paddr,
- GFP_ATOMIC);
- if (!ctx->dec_cd) {
- spin_unlock(&ctx->lock);
- goto out_free_enc;
- }
+ inst = qat_crypto_get_instance_node(node);
+ if (!inst)
+ return -EINVAL;
+ dev = &GET_DEV(inst->accel_dev);
+ ctx->inst = inst;
+ ctx->enc_cd = dma_alloc_coherent(dev, sizeof(*ctx->enc_cd),
+ &ctx->enc_cd_paddr,
+ GFP_ATOMIC);
+ if (!ctx->enc_cd) {
+ ret = -ENOMEM;
+ goto out_free_instance;
+ }
+ ctx->dec_cd = dma_alloc_coherent(dev, sizeof(*ctx->dec_cd),
+ &ctx->dec_cd_paddr,
+ GFP_ATOMIC);
+ if (!ctx->dec_cd) {
+ ret = -ENOMEM;
+ goto out_free_enc;
}
- spin_unlock(&ctx->lock);
- if (qat_alg_ablkcipher_init_sessions(ctx, key, keylen, mode))
+
+ ret = qat_alg_ablkcipher_init_sessions(ctx, key, keylen, mode);
+ if (ret)
goto out_free_all;
return 0;
@@ -963,7 +1006,22 @@ out_free_enc:
dma_free_coherent(dev, sizeof(*ctx->enc_cd),
ctx->enc_cd, ctx->enc_cd_paddr);
ctx->enc_cd = NULL;
- return -ENOMEM;
+out_free_instance:
+ ctx->inst = NULL;
+ qat_crypto_put_instance(inst);
+ return ret;
+}
+
+static int qat_alg_ablkcipher_setkey(struct crypto_ablkcipher *tfm,
+ const u8 *key, unsigned int keylen,
+ int mode)
+{
+ struct qat_alg_ablkcipher_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+
+ if (ctx->enc_cd)
+ return qat_alg_ablkcipher_rekey(ctx, key, keylen, mode);
+ else
+ return qat_alg_ablkcipher_newkey(ctx, key, keylen, mode);
}
static int qat_alg_ablkcipher_cbc_setkey(struct crypto_ablkcipher *tfm,
@@ -995,11 +1053,23 @@ static int qat_alg_ablkcipher_encrypt(struct ablkcipher_request *req)
struct qat_crypto_request *qat_req = ablkcipher_request_ctx(req);
struct icp_qat_fw_la_cipher_req_params *cipher_param;
struct icp_qat_fw_la_bulk_req *msg;
+ struct device *dev = &GET_DEV(ctx->inst->accel_dev);
int ret, ctr = 0;
+ if (req->nbytes == 0)
+ return 0;
+
+ qat_req->iv = dma_alloc_coherent(dev, AES_BLOCK_SIZE,
+ &qat_req->iv_paddr, GFP_ATOMIC);
+ if (!qat_req->iv)
+ return -ENOMEM;
+
ret = qat_alg_sgl_to_bufl(ctx->inst, req->src, req->dst, qat_req);
- if (unlikely(ret))
+ if (unlikely(ret)) {
+ dma_free_coherent(dev, AES_BLOCK_SIZE, qat_req->iv,
+ qat_req->iv_paddr);
return ret;
+ }
msg = &qat_req->req;
*msg = ctx->enc_fw_req;
@@ -1012,18 +1082,29 @@ static int qat_alg_ablkcipher_encrypt(struct ablkcipher_request *req)
cipher_param = (void *)&qat_req->req.serv_specif_rqpars;
cipher_param->cipher_length = req->nbytes;
cipher_param->cipher_offset = 0;
- memcpy(cipher_param->u.cipher_IV_array, req->info, AES_BLOCK_SIZE);
+ cipher_param->u.s.cipher_IV_ptr = qat_req->iv_paddr;
+ memcpy(qat_req->iv, req->info, AES_BLOCK_SIZE);
do {
ret = adf_send_message(ctx->inst->sym_tx, (uint32_t *)msg);
} while (ret == -EAGAIN && ctr++ < 10);
if (ret == -EAGAIN) {
qat_alg_free_bufl(ctx->inst, qat_req);
+ dma_free_coherent(dev, AES_BLOCK_SIZE, qat_req->iv,
+ qat_req->iv_paddr);
return -EBUSY;
}
return -EINPROGRESS;
}
+static int qat_alg_ablkcipher_blk_encrypt(struct ablkcipher_request *req)
+{
+ if (req->nbytes % AES_BLOCK_SIZE != 0)
+ return -EINVAL;
+
+ return qat_alg_ablkcipher_encrypt(req);
+}
+
static int qat_alg_ablkcipher_decrypt(struct ablkcipher_request *req)
{
struct crypto_ablkcipher *atfm = crypto_ablkcipher_reqtfm(req);
@@ -1032,11 +1113,23 @@ static int qat_alg_ablkcipher_decrypt(struct ablkcipher_request *req)
struct qat_crypto_request *qat_req = ablkcipher_request_ctx(req);
struct icp_qat_fw_la_cipher_req_params *cipher_param;
struct icp_qat_fw_la_bulk_req *msg;
+ struct device *dev = &GET_DEV(ctx->inst->accel_dev);
int ret, ctr = 0;
+ if (req->nbytes == 0)
+ return 0;
+
+ qat_req->iv = dma_alloc_coherent(dev, AES_BLOCK_SIZE,
+ &qat_req->iv_paddr, GFP_ATOMIC);
+ if (!qat_req->iv)
+ return -ENOMEM;
+
ret = qat_alg_sgl_to_bufl(ctx->inst, req->src, req->dst, qat_req);
- if (unlikely(ret))
+ if (unlikely(ret)) {
+ dma_free_coherent(dev, AES_BLOCK_SIZE, qat_req->iv,
+ qat_req->iv_paddr);
return ret;
+ }
msg = &qat_req->req;
*msg = ctx->dec_fw_req;
@@ -1049,18 +1142,28 @@ static int qat_alg_ablkcipher_decrypt(struct ablkcipher_request *req)
cipher_param = (void *)&qat_req->req.serv_specif_rqpars;
cipher_param->cipher_length = req->nbytes;
cipher_param->cipher_offset = 0;
- memcpy(cipher_param->u.cipher_IV_array, req->info, AES_BLOCK_SIZE);
+ cipher_param->u.s.cipher_IV_ptr = qat_req->iv_paddr;
+ memcpy(qat_req->iv, req->info, AES_BLOCK_SIZE);
do {
ret = adf_send_message(ctx->inst->sym_tx, (uint32_t *)msg);
} while (ret == -EAGAIN && ctr++ < 10);
if (ret == -EAGAIN) {
qat_alg_free_bufl(ctx->inst, qat_req);
+ dma_free_coherent(dev, AES_BLOCK_SIZE, qat_req->iv,
+ qat_req->iv_paddr);
return -EBUSY;
}
return -EINPROGRESS;
}
+static int qat_alg_ablkcipher_blk_decrypt(struct ablkcipher_request *req)
+{
+ if (req->nbytes % AES_BLOCK_SIZE != 0)
+ return -EINVAL;
+
+ return qat_alg_ablkcipher_decrypt(req);
+}
static int qat_alg_aead_init(struct crypto_aead *tfm,
enum icp_qat_hw_auth_algo hash,
const char *hash_name)
@@ -1119,7 +1222,6 @@ static int qat_alg_ablkcipher_init(struct crypto_tfm *tfm)
{
struct qat_alg_ablkcipher_ctx *ctx = crypto_tfm_ctx(tfm);
- spin_lock_init(&ctx->lock);
tfm->crt_ablkcipher.reqsize = sizeof(struct qat_crypto_request);
ctx->tfm = tfm;
return 0;
@@ -1221,8 +1323,8 @@ static struct crypto_alg qat_algs[] = { {
.cra_u = {
.ablkcipher = {
.setkey = qat_alg_ablkcipher_cbc_setkey,
- .decrypt = qat_alg_ablkcipher_decrypt,
- .encrypt = qat_alg_ablkcipher_encrypt,
+ .decrypt = qat_alg_ablkcipher_blk_decrypt,
+ .encrypt = qat_alg_ablkcipher_blk_encrypt,
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
.ivsize = AES_BLOCK_SIZE,
@@ -1233,7 +1335,7 @@ static struct crypto_alg qat_algs[] = { {
.cra_driver_name = "qat_aes_ctr",
.cra_priority = 4001,
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_blocksize = 1,
.cra_ctxsize = sizeof(struct qat_alg_ablkcipher_ctx),
.cra_alignmask = 0,
.cra_type = &crypto_ablkcipher_type,
@@ -1265,8 +1367,8 @@ static struct crypto_alg qat_algs[] = { {
.cra_u = {
.ablkcipher = {
.setkey = qat_alg_ablkcipher_xts_setkey,
- .decrypt = qat_alg_ablkcipher_decrypt,
- .encrypt = qat_alg_ablkcipher_encrypt,
+ .decrypt = qat_alg_ablkcipher_blk_decrypt,
+ .encrypt = qat_alg_ablkcipher_blk_encrypt,
.min_keysize = 2 * AES_MIN_KEY_SIZE,
.max_keysize = 2 * AES_MAX_KEY_SIZE,
.ivsize = AES_BLOCK_SIZE,
diff --git a/drivers/crypto/qat/qat_common/qat_crypto.h b/drivers/crypto/qat/qat_common/qat_crypto.h
index dc0273fe3620..c77a80020cde 100644
--- a/drivers/crypto/qat/qat_common/qat_crypto.h
+++ b/drivers/crypto/qat/qat_common/qat_crypto.h
@@ -88,6 +88,8 @@ struct qat_crypto_request {
struct qat_crypto_request_buffs buf;
void (*cb)(struct icp_qat_fw_la_resp *resp,
struct qat_crypto_request *req);
+ void *iv;
+ dma_addr_t iv_paddr;
};
#endif
diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c
index fd11162a915e..b0b8e3d48aef 100644
--- a/drivers/crypto/sahara.c
+++ b/drivers/crypto/sahara.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Cryptographic API.
*
@@ -7,10 +8,6 @@
* Copyright (c) 2013 Vista Silicon S.L.
* Author: Javier Martin <javier.martin@vista-silicon.com>
*
- * 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.
- *
* Based on omap-aes.c and tegra-aes.c
*/
@@ -1387,7 +1384,6 @@ MODULE_DEVICE_TABLE(of, sahara_dt_ids);
static int sahara_probe(struct platform_device *pdev)
{
struct sahara_dev *dev;
- struct resource *res;
u32 version;
int irq;
int err;
@@ -1401,8 +1397,7 @@ static int sahara_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dev);
/* Get the base address */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- dev->regs_base = devm_ioremap_resource(&pdev->dev, res);
+ dev->regs_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(dev->regs_base))
return PTR_ERR(dev->regs_base);
diff --git a/drivers/crypto/stm32/Makefile b/drivers/crypto/stm32/Makefile
index ce77e38c77e0..518e0e0b11a9 100644
--- a/drivers/crypto/stm32/Makefile
+++ b/drivers/crypto/stm32/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_CRYPTO_DEV_STM32_CRC) += stm32_crc32.o
+obj-$(CONFIG_CRYPTO_DEV_STM32_CRC) += stm32-crc32.o
obj-$(CONFIG_CRYPTO_DEV_STM32_HASH) += stm32-hash.o
obj-$(CONFIG_CRYPTO_DEV_STM32_CRYP) += stm32-cryp.o
diff --git a/drivers/crypto/stm32/stm32_crc32.c b/drivers/crypto/stm32/stm32-crc32.c
index 440c9f1bd006..440c9f1bd006 100644
--- a/drivers/crypto/stm32/stm32_crc32.c
+++ b/drivers/crypto/stm32/stm32-crc32.c
diff --git a/drivers/crypto/stm32/stm32-hash.c b/drivers/crypto/stm32/stm32-hash.c
index bfc49e67124b..2b70d8796f25 100644
--- a/drivers/crypto/stm32/stm32-hash.c
+++ b/drivers/crypto/stm32/stm32-hash.c
@@ -1,23 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* This file is part of STM32 Crypto driver for Linux.
*
* Copyright (C) 2017, STMicroelectronics - All Rights Reserved
* Author(s): Lionel DEBIEVE <lionel.debieve@st.com> for STMicroelectronics.
- *
- * License terms: GPL V2.0.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- *
*/
#include <linux/clk.h>
@@ -352,7 +338,7 @@ static int stm32_hash_xmit_cpu(struct stm32_hash_dev *hdev,
len32 = DIV_ROUND_UP(length, sizeof(u32));
- dev_dbg(hdev->dev, "%s: length: %d, final: %x len32 %i\n",
+ dev_dbg(hdev->dev, "%s: length: %zd, final: %x len32 %i\n",
__func__, length, final, len32);
hdev->flags |= HASH_FLAGS_CPU;
@@ -363,7 +349,7 @@ static int stm32_hash_xmit_cpu(struct stm32_hash_dev *hdev,
return -ETIMEDOUT;
if ((hdev->flags & HASH_FLAGS_HMAC) &&
- (hdev->flags & ~HASH_FLAGS_HMAC_KEY)) {
+ (!(hdev->flags & HASH_FLAGS_HMAC_KEY))) {
hdev->flags |= HASH_FLAGS_HMAC_KEY;
stm32_hash_write_key(hdev);
if (stm32_hash_wait_busy(hdev))
@@ -461,8 +447,8 @@ static int stm32_hash_xmit_dma(struct stm32_hash_dev *hdev,
dma_async_issue_pending(hdev->dma_lch);
- if (!wait_for_completion_interruptible_timeout(&hdev->dma_completion,
- msecs_to_jiffies(100)))
+ if (!wait_for_completion_timeout(&hdev->dma_completion,
+ msecs_to_jiffies(100)))
err = -ETIMEDOUT;
if (dma_async_is_tx_complete(hdev->dma_lch, cookie,
diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c b/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c
index 7b0c42882830..6f7cbf6c2b55 100644
--- a/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c
+++ b/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c
@@ -8,11 +8,11 @@
* keysize in CBC and ECB mode.
* Add support also for DES and 3DES in CBC and ECB mode.
*
- * You could find the datasheet in Documentation/arm/sunxi/README
+ * You could find the datasheet in Documentation/arm/sunxi.rst
*/
#include "sun4i-ss.h"
-static int sun4i_ss_opti_poll(struct skcipher_request *areq)
+static int noinline_for_stack sun4i_ss_opti_poll(struct skcipher_request *areq)
{
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
@@ -114,6 +114,29 @@ release_ss:
return err;
}
+
+static int noinline_for_stack sun4i_ss_cipher_poll_fallback(struct skcipher_request *areq)
+{
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
+ struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm);
+ struct sun4i_cipher_req_ctx *ctx = skcipher_request_ctx(areq);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, op->fallback_tfm);
+ int err;
+
+ skcipher_request_set_sync_tfm(subreq, op->fallback_tfm);
+ skcipher_request_set_callback(subreq, areq->base.flags, NULL,
+ NULL);
+ skcipher_request_set_crypt(subreq, areq->src, areq->dst,
+ areq->cryptlen, areq->iv);
+ if (ctx->mode & SS_DECRYPTION)
+ err = crypto_skcipher_decrypt(subreq);
+ else
+ err = crypto_skcipher_encrypt(subreq);
+ skcipher_request_zero(subreq);
+
+ return err;
+}
+
/* Generic function that support SG with size not multiple of 4 */
static int sun4i_ss_cipher_poll(struct skcipher_request *areq)
{
@@ -140,8 +163,6 @@ static int sun4i_ss_cipher_poll(struct skcipher_request *areq)
unsigned int todo;
struct sg_mapping_iter mi, mo;
unsigned int oi, oo; /* offset for in and out */
- char buf[4 * SS_RX_MAX];/* buffer for linearize SG src */
- char bufo[4 * SS_TX_MAX]; /* buffer for linearize SG dst */
unsigned int ob = 0; /* offset in buf */
unsigned int obo = 0; /* offset in bufo*/
unsigned int obl = 0; /* length of data in bufo */
@@ -178,20 +199,8 @@ static int sun4i_ss_cipher_poll(struct skcipher_request *areq)
if (no_chunk == 1 && !need_fallback)
return sun4i_ss_opti_poll(areq);
- if (need_fallback) {
- SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, op->fallback_tfm);
- skcipher_request_set_sync_tfm(subreq, op->fallback_tfm);
- skcipher_request_set_callback(subreq, areq->base.flags, NULL,
- NULL);
- skcipher_request_set_crypt(subreq, areq->src, areq->dst,
- areq->cryptlen, areq->iv);
- if (ctx->mode & SS_DECRYPTION)
- err = crypto_skcipher_decrypt(subreq);
- else
- err = crypto_skcipher_encrypt(subreq);
- skcipher_request_zero(subreq);
- return err;
- }
+ if (need_fallback)
+ return sun4i_ss_cipher_poll_fallback(areq);
spin_lock_irqsave(&ss->slock, flags);
@@ -224,6 +233,8 @@ static int sun4i_ss_cipher_poll(struct skcipher_request *areq)
while (oleft) {
if (ileft) {
+ char buf[4 * SS_RX_MAX];/* buffer for linearize SG src */
+
/*
* todo is the number of consecutive 4byte word that we
* can read from current SG
@@ -281,6 +292,8 @@ static int sun4i_ss_cipher_poll(struct skcipher_request *areq)
oo = 0;
}
} else {
+ char bufo[4 * SS_TX_MAX]; /* buffer for linearize SG dst */
+
/*
* read obl bytes in bufo, we read at maximum for
* emptying the device
diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-core.c b/drivers/crypto/sunxi-ss/sun4i-ss-core.c
index cdcda7f059c8..2e8704271f45 100644
--- a/drivers/crypto/sunxi-ss/sun4i-ss-core.c
+++ b/drivers/crypto/sunxi-ss/sun4i-ss-core.c
@@ -6,7 +6,7 @@
*
* Core file which registers crypto algorithms supported by the SS.
*
- * You could find a link for the datasheet in Documentation/arm/sunxi/README
+ * You could find a link for the datasheet in Documentation/arm/sunxi.rst
*/
#include <linux/clk.h>
#include <linux/crypto.h>
diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-hash.c b/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
index d2b6d89aad28..fcffba5ef927 100644
--- a/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
+++ b/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
@@ -6,7 +6,7 @@
*
* This file add support for MD5 and SHA1.
*
- * You could find the datasheet in Documentation/arm/sunxi/README
+ * You could find the datasheet in Documentation/arm/sunxi.rst
*/
#include "sun4i-ss.h"
#include <linux/scatterlist.h>
diff --git a/drivers/crypto/sunxi-ss/sun4i-ss.h b/drivers/crypto/sunxi-ss/sun4i-ss.h
index 68b82d1a6303..8654d48aedc0 100644
--- a/drivers/crypto/sunxi-ss/sun4i-ss.h
+++ b/drivers/crypto/sunxi-ss/sun4i-ss.h
@@ -8,7 +8,7 @@
* Support MD5 and SHA1 hash algorithms.
* Support DES and 3DES
*
- * You could find the datasheet in Documentation/arm/sunxi/README
+ * You could find the datasheet in Documentation/arm/sunxi.rst
*/
#include <linux/clk.h>
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index fbc7bf9d7380..c9d686a0e805 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -265,11 +265,11 @@ static int init_device(struct device *dev)
* callback must check err and feedback in descriptor header
* for device processing status.
*/
-int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc,
- void (*callback)(struct device *dev,
- struct talitos_desc *desc,
- void *context, int error),
- void *context)
+static int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc,
+ void (*callback)(struct device *dev,
+ struct talitos_desc *desc,
+ void *context, int error),
+ void *context)
{
struct talitos_private *priv = dev_get_drvdata(dev);
struct talitos_request *request;
@@ -319,7 +319,21 @@ int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc,
return -EINPROGRESS;
}
-EXPORT_SYMBOL(talitos_submit);
+
+static __be32 get_request_hdr(struct talitos_request *request, bool is_sec1)
+{
+ struct talitos_edesc *edesc;
+
+ if (!is_sec1)
+ return request->desc->hdr;
+
+ if (!request->desc->next_desc)
+ return request->desc->hdr1;
+
+ edesc = container_of(request->desc, struct talitos_edesc, desc);
+
+ return ((struct talitos_desc *)(edesc->buf + edesc->dma_len))->hdr1;
+}
/*
* process what was done, notify callback of error if not
@@ -342,12 +356,7 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch)
/* descriptors with their done bits set don't get the error */
rmb();
- if (!is_sec1)
- hdr = request->desc->hdr;
- else if (request->desc->next_desc)
- hdr = (request->desc + 1)->hdr1;
- else
- hdr = request->desc->hdr1;
+ hdr = get_request_hdr(request, is_sec1);
if ((hdr & DESC_HDR_DONE) == DESC_HDR_DONE)
status = 0;
@@ -477,8 +486,14 @@ static u32 current_desc_hdr(struct device *dev, int ch)
}
}
- if (priv->chan[ch].fifo[iter].desc->next_desc == cur_desc)
- return (priv->chan[ch].fifo[iter].desc + 1)->hdr;
+ if (priv->chan[ch].fifo[iter].desc->next_desc == cur_desc) {
+ struct talitos_edesc *edesc;
+
+ edesc = container_of(priv->chan[ch].fifo[iter].desc,
+ struct talitos_edesc, desc);
+ return ((struct talitos_desc *)
+ (edesc->buf + edesc->dma_len))->hdr;
+ }
return priv->chan[ch].fifo[iter].desc->hdr;
}
@@ -824,7 +839,11 @@ static void talitos_unregister_rng(struct device *dev)
* HMAC_SNOOP_NO_AFEA (HSNA) instead of type IPSEC_ESP
*/
#define TALITOS_CRA_PRIORITY_AEAD_HSNA (TALITOS_CRA_PRIORITY - 1)
+#ifdef CONFIG_CRYPTO_DEV_TALITOS2
#define TALITOS_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + SHA512_BLOCK_SIZE)
+#else
+#define TALITOS_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + SHA256_BLOCK_SIZE)
+#endif
#define TALITOS_MAX_IV_LENGTH 16 /* max of AES_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE */
struct talitos_ctx {
@@ -948,36 +967,6 @@ badkey:
goto out;
}
-/*
- * talitos_edesc - s/w-extended descriptor
- * @src_nents: number of segments in input scatterlist
- * @dst_nents: number of segments in output scatterlist
- * @icv_ool: whether ICV is out-of-line
- * @iv_dma: dma address of iv for checking continuity and link table
- * @dma_len: length of dma mapped link_tbl space
- * @dma_link_tbl: bus physical address of link_tbl/buf
- * @desc: h/w descriptor
- * @link_tbl: input and output h/w link tables (if {src,dst}_nents > 1) (SEC2)
- * @buf: input and output buffeur (if {src,dst}_nents > 1) (SEC1)
- *
- * if decrypting (with authcheck), or either one of src_nents or dst_nents
- * is greater than 1, an integrity check value is concatenated to the end
- * of link_tbl data
- */
-struct talitos_edesc {
- int src_nents;
- int dst_nents;
- bool icv_ool;
- dma_addr_t iv_dma;
- int dma_len;
- dma_addr_t dma_link_tbl;
- struct talitos_desc desc;
- union {
- struct talitos_ptr link_tbl[0];
- u8 buf[0];
- };
-};
-
static void talitos_sg_unmap(struct device *dev,
struct talitos_edesc *edesc,
struct scatterlist *src,
@@ -1008,11 +997,13 @@ static void talitos_sg_unmap(struct device *dev,
static void ipsec_esp_unmap(struct device *dev,
struct talitos_edesc *edesc,
- struct aead_request *areq)
+ struct aead_request *areq, bool encrypt)
{
struct crypto_aead *aead = crypto_aead_reqtfm(areq);
struct talitos_ctx *ctx = crypto_aead_ctx(aead);
unsigned int ivsize = crypto_aead_ivsize(aead);
+ unsigned int authsize = crypto_aead_authsize(aead);
+ unsigned int cryptlen = areq->cryptlen - (encrypt ? 0 : authsize);
bool is_ipsec_esp = edesc->desc.hdr & DESC_HDR_TYPE_IPSEC_ESP;
struct talitos_ptr *civ_ptr = &edesc->desc.ptr[is_ipsec_esp ? 2 : 3];
@@ -1021,8 +1012,8 @@ static void ipsec_esp_unmap(struct device *dev,
DMA_FROM_DEVICE);
unmap_single_talitos_ptr(dev, civ_ptr, DMA_TO_DEVICE);
- talitos_sg_unmap(dev, edesc, areq->src, areq->dst, areq->cryptlen,
- areq->assoclen);
+ talitos_sg_unmap(dev, edesc, areq->src, areq->dst,
+ cryptlen + authsize, areq->assoclen);
if (edesc->dma_len)
dma_unmap_single(dev, edesc->dma_link_tbl, edesc->dma_len,
@@ -1032,7 +1023,7 @@ static void ipsec_esp_unmap(struct device *dev,
unsigned int dst_nents = edesc->dst_nents ? : 1;
sg_pcopy_to_buffer(areq->dst, dst_nents, ctx->iv, ivsize,
- areq->assoclen + areq->cryptlen - ivsize);
+ areq->assoclen + cryptlen - ivsize);
}
}
@@ -1043,31 +1034,14 @@ static void ipsec_esp_encrypt_done(struct device *dev,
struct talitos_desc *desc, void *context,
int err)
{
- struct talitos_private *priv = dev_get_drvdata(dev);
- bool is_sec1 = has_ftr_sec1(priv);
struct aead_request *areq = context;
struct crypto_aead *authenc = crypto_aead_reqtfm(areq);
- unsigned int authsize = crypto_aead_authsize(authenc);
unsigned int ivsize = crypto_aead_ivsize(authenc);
struct talitos_edesc *edesc;
- struct scatterlist *sg;
- void *icvdata;
edesc = container_of(desc, struct talitos_edesc, desc);
- ipsec_esp_unmap(dev, edesc, areq);
-
- /* copy the generated ICV to dst */
- if (edesc->icv_ool) {
- if (is_sec1)
- icvdata = edesc->buf + areq->assoclen + areq->cryptlen;
- else
- icvdata = &edesc->link_tbl[edesc->src_nents +
- edesc->dst_nents + 2];
- sg = sg_last(areq->dst, edesc->dst_nents);
- memcpy((char *)sg_virt(sg) + sg->length - authsize,
- icvdata, authsize);
- }
+ ipsec_esp_unmap(dev, edesc, areq, true);
dma_unmap_single(dev, edesc->iv_dma, ivsize, DMA_TO_DEVICE);
@@ -1084,32 +1058,16 @@ static void ipsec_esp_decrypt_swauth_done(struct device *dev,
struct crypto_aead *authenc = crypto_aead_reqtfm(req);
unsigned int authsize = crypto_aead_authsize(authenc);
struct talitos_edesc *edesc;
- struct scatterlist *sg;
char *oicv, *icv;
- struct talitos_private *priv = dev_get_drvdata(dev);
- bool is_sec1 = has_ftr_sec1(priv);
edesc = container_of(desc, struct talitos_edesc, desc);
- ipsec_esp_unmap(dev, edesc, req);
+ ipsec_esp_unmap(dev, edesc, req, false);
if (!err) {
/* auth check */
- sg = sg_last(req->dst, edesc->dst_nents ? : 1);
- icv = (char *)sg_virt(sg) + sg->length - authsize;
-
- if (edesc->dma_len) {
- if (is_sec1)
- oicv = (char *)&edesc->dma_link_tbl +
- req->assoclen + req->cryptlen;
- else
- oicv = (char *)
- &edesc->link_tbl[edesc->src_nents +
- edesc->dst_nents + 2];
- if (edesc->icv_ool)
- icv = oicv + authsize;
- } else
- oicv = (char *)&edesc->link_tbl[0];
+ oicv = edesc->buf + edesc->dma_len;
+ icv = oicv - authsize;
err = crypto_memneq(oicv, icv, authsize) ? -EBADMSG : 0;
}
@@ -1128,7 +1086,7 @@ static void ipsec_esp_decrypt_hwauth_done(struct device *dev,
edesc = container_of(desc, struct talitos_edesc, desc);
- ipsec_esp_unmap(dev, edesc, req);
+ ipsec_esp_unmap(dev, edesc, req, false);
/* check ICV auth status */
if (!err && ((desc->hdr_lo & DESC_HDR_LO_ICCR1_MASK) !=
@@ -1145,11 +1103,12 @@ static void ipsec_esp_decrypt_hwauth_done(struct device *dev,
* stop at cryptlen bytes
*/
static int sg_to_link_tbl_offset(struct scatterlist *sg, int sg_count,
- unsigned int offset, int cryptlen,
+ unsigned int offset, int datalen, int elen,
struct talitos_ptr *link_tbl_ptr)
{
- int n_sg = sg_count;
+ int n_sg = elen ? sg_count + 1 : sg_count;
int count = 0;
+ int cryptlen = datalen + elen;
while (cryptlen && sg && n_sg--) {
unsigned int len = sg_dma_len(sg);
@@ -1164,11 +1123,20 @@ static int sg_to_link_tbl_offset(struct scatterlist *sg, int sg_count,
if (len > cryptlen)
len = cryptlen;
+ if (datalen > 0 && len > datalen) {
+ to_talitos_ptr(link_tbl_ptr + count,
+ sg_dma_address(sg) + offset, datalen, 0);
+ to_talitos_ptr_ext_set(link_tbl_ptr + count, 0, 0);
+ count++;
+ len -= datalen;
+ offset += datalen;
+ }
to_talitos_ptr(link_tbl_ptr + count,
sg_dma_address(sg) + offset, len, 0);
to_talitos_ptr_ext_set(link_tbl_ptr + count, 0, 0);
count++;
cryptlen -= len;
+ datalen -= len;
offset = 0;
next:
@@ -1178,7 +1146,7 @@ next:
/* tag end of link table */
if (count > 0)
to_talitos_ptr_ext_set(link_tbl_ptr + count - 1,
- DESC_PTR_LNKTBL_RETURN, 0);
+ DESC_PTR_LNKTBL_RET, 0);
return count;
}
@@ -1186,7 +1154,8 @@ next:
static int talitos_sg_map_ext(struct device *dev, struct scatterlist *src,
unsigned int len, struct talitos_edesc *edesc,
struct talitos_ptr *ptr, int sg_count,
- unsigned int offset, int tbl_off, int elen)
+ unsigned int offset, int tbl_off, int elen,
+ bool force)
{
struct talitos_private *priv = dev_get_drvdata(dev);
bool is_sec1 = has_ftr_sec1(priv);
@@ -1196,7 +1165,7 @@ static int talitos_sg_map_ext(struct device *dev, struct scatterlist *src,
return 1;
}
to_talitos_ptr_ext_set(ptr, elen, is_sec1);
- if (sg_count == 1) {
+ if (sg_count == 1 && !force) {
to_talitos_ptr(ptr, sg_dma_address(src) + offset, len, is_sec1);
return sg_count;
}
@@ -1204,9 +1173,9 @@ static int talitos_sg_map_ext(struct device *dev, struct scatterlist *src,
to_talitos_ptr(ptr, edesc->dma_link_tbl + offset, len, is_sec1);
return sg_count;
}
- sg_count = sg_to_link_tbl_offset(src, sg_count, offset, len + elen,
+ sg_count = sg_to_link_tbl_offset(src, sg_count, offset, len, elen,
&edesc->link_tbl[tbl_off]);
- if (sg_count == 1) {
+ if (sg_count == 1 && !force) {
/* Only one segment now, so no link tbl needed*/
copy_talitos_ptr(ptr, &edesc->link_tbl[tbl_off], is_sec1);
return sg_count;
@@ -1224,13 +1193,14 @@ static int talitos_sg_map(struct device *dev, struct scatterlist *src,
unsigned int offset, int tbl_off)
{
return talitos_sg_map_ext(dev, src, len, edesc, ptr, sg_count, offset,
- tbl_off, 0);
+ tbl_off, 0, false);
}
/*
* fill in and submit ipsec_esp descriptor
*/
static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
+ bool encrypt,
void (*callback)(struct device *dev,
struct talitos_desc *desc,
void *context, int error))
@@ -1240,7 +1210,7 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
struct talitos_ctx *ctx = crypto_aead_ctx(aead);
struct device *dev = ctx->dev;
struct talitos_desc *desc = &edesc->desc;
- unsigned int cryptlen = areq->cryptlen;
+ unsigned int cryptlen = areq->cryptlen - (encrypt ? 0 : authsize);
unsigned int ivsize = crypto_aead_ivsize(aead);
int tbl_off = 0;
int sg_count, ret;
@@ -1251,6 +1221,7 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
bool is_ipsec_esp = desc->hdr & DESC_HDR_TYPE_IPSEC_ESP;
struct talitos_ptr *civ_ptr = &desc->ptr[is_ipsec_esp ? 2 : 3];
struct talitos_ptr *ckey_ptr = &desc->ptr[is_ipsec_esp ? 3 : 2];
+ dma_addr_t dma_icv = edesc->dma_link_tbl + edesc->dma_len - authsize;
/* hmac key */
to_talitos_ptr(&desc->ptr[0], ctx->dma_key, ctx->authkeylen, is_sec1);
@@ -1290,7 +1261,8 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
elen = authsize;
ret = talitos_sg_map_ext(dev, areq->src, cryptlen, edesc, &desc->ptr[4],
- sg_count, areq->assoclen, tbl_off, elen);
+ sg_count, areq->assoclen, tbl_off, elen,
+ false);
if (ret > 1) {
tbl_off += ret;
@@ -1304,55 +1276,32 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
dma_map_sg(dev, areq->dst, sg_count, DMA_FROM_DEVICE);
}
- ret = talitos_sg_map(dev, areq->dst, cryptlen, edesc, &desc->ptr[5],
- sg_count, areq->assoclen, tbl_off);
-
- if (is_ipsec_esp)
- to_talitos_ptr_ext_or(&desc->ptr[5], authsize, is_sec1);
-
- /* ICV data */
- if (ret > 1) {
- tbl_off += ret;
- edesc->icv_ool = true;
- sync_needed = true;
-
- if (is_ipsec_esp) {
- struct talitos_ptr *tbl_ptr = &edesc->link_tbl[tbl_off];
- int offset = (edesc->src_nents + edesc->dst_nents + 2) *
- sizeof(struct talitos_ptr) + authsize;
-
- /* Add an entry to the link table for ICV data */
- to_talitos_ptr_ext_set(tbl_ptr - 1, 0, is_sec1);
- to_talitos_ptr_ext_set(tbl_ptr, DESC_PTR_LNKTBL_RETURN,
- is_sec1);
+ if (is_ipsec_esp && encrypt)
+ elen = authsize;
+ else
+ elen = 0;
+ ret = talitos_sg_map_ext(dev, areq->dst, cryptlen, edesc, &desc->ptr[5],
+ sg_count, areq->assoclen, tbl_off, elen,
+ is_ipsec_esp && !encrypt);
+ tbl_off += ret;
- /* icv data follows link tables */
- to_talitos_ptr(tbl_ptr, edesc->dma_link_tbl + offset,
- authsize, is_sec1);
- } else {
- dma_addr_t addr = edesc->dma_link_tbl;
+ if (!encrypt && is_ipsec_esp) {
+ struct talitos_ptr *tbl_ptr = &edesc->link_tbl[tbl_off];
- if (is_sec1)
- addr += areq->assoclen + cryptlen;
- else
- addr += sizeof(struct talitos_ptr) * tbl_off;
+ /* Add an entry to the link table for ICV data */
+ to_talitos_ptr_ext_set(tbl_ptr - 1, 0, is_sec1);
+ to_talitos_ptr_ext_set(tbl_ptr, DESC_PTR_LNKTBL_RET, is_sec1);
- to_talitos_ptr(&desc->ptr[6], addr, authsize, is_sec1);
- }
+ /* icv data follows link tables */
+ to_talitos_ptr(tbl_ptr, dma_icv, authsize, is_sec1);
+ to_talitos_ptr_ext_or(&desc->ptr[5], authsize, is_sec1);
+ sync_needed = true;
+ } else if (!encrypt) {
+ to_talitos_ptr(&desc->ptr[6], dma_icv, authsize, is_sec1);
+ sync_needed = true;
} else if (!is_ipsec_esp) {
- ret = talitos_sg_map(dev, areq->dst, authsize, edesc,
- &desc->ptr[6], sg_count, areq->assoclen +
- cryptlen,
- tbl_off);
- if (ret > 1) {
- tbl_off += ret;
- edesc->icv_ool = true;
- sync_needed = true;
- } else {
- edesc->icv_ool = false;
- }
- } else {
- edesc->icv_ool = false;
+ talitos_sg_map(dev, areq->dst, authsize, edesc, &desc->ptr[6],
+ sg_count, areq->assoclen + cryptlen, tbl_off);
}
/* iv out */
@@ -1367,7 +1316,7 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
ret = talitos_submit(dev, ctx->ch, desc, callback, areq);
if (ret != -EINPROGRESS) {
- ipsec_esp_unmap(dev, edesc, areq);
+ ipsec_esp_unmap(dev, edesc, areq, encrypt);
kfree(edesc);
}
return ret;
@@ -1435,18 +1384,18 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev,
* and space for two sets of ICVs (stashed and generated)
*/
alloc_len = sizeof(struct talitos_edesc);
- if (src_nents || dst_nents) {
+ if (src_nents || dst_nents || !encrypt) {
if (is_sec1)
dma_len = (src_nents ? src_len : 0) +
- (dst_nents ? dst_len : 0);
+ (dst_nents ? dst_len : 0) + authsize;
else
dma_len = (src_nents + dst_nents + 2) *
- sizeof(struct talitos_ptr) + authsize * 2;
+ sizeof(struct talitos_ptr) + authsize;
alloc_len += dma_len;
} else {
dma_len = 0;
- alloc_len += icv_stashing ? authsize : 0;
}
+ alloc_len += icv_stashing ? authsize : 0;
/* if its a ahash, add space for a second desc next to the first one */
if (is_sec1 && !dst)
@@ -1466,15 +1415,11 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev,
edesc->dst_nents = dst_nents;
edesc->iv_dma = iv_dma;
edesc->dma_len = dma_len;
- if (dma_len) {
- void *addr = &edesc->link_tbl[0];
-
- if (is_sec1 && !dst)
- addr += sizeof(struct talitos_desc);
- edesc->dma_link_tbl = dma_map_single(dev, addr,
+ if (dma_len)
+ edesc->dma_link_tbl = dma_map_single(dev, &edesc->link_tbl[0],
edesc->dma_len,
DMA_BIDIRECTIONAL);
- }
+
return edesc;
}
@@ -1485,9 +1430,10 @@ static struct talitos_edesc *aead_edesc_alloc(struct aead_request *areq, u8 *iv,
unsigned int authsize = crypto_aead_authsize(authenc);
struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
unsigned int ivsize = crypto_aead_ivsize(authenc);
+ unsigned int cryptlen = areq->cryptlen - (encrypt ? 0 : authsize);
return talitos_edesc_alloc(ctx->dev, areq->src, areq->dst,
- iv, areq->assoclen, areq->cryptlen,
+ iv, areq->assoclen, cryptlen,
authsize, ivsize, icv_stashing,
areq->base.flags, encrypt);
}
@@ -1506,7 +1452,7 @@ static int aead_encrypt(struct aead_request *req)
/* set encrypt */
edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_MODE0_ENCRYPT;
- return ipsec_esp(edesc, req, ipsec_esp_encrypt_done);
+ return ipsec_esp(edesc, req, true, ipsec_esp_encrypt_done);
}
static int aead_decrypt(struct aead_request *req)
@@ -1516,17 +1462,15 @@ static int aead_decrypt(struct aead_request *req)
struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
struct talitos_private *priv = dev_get_drvdata(ctx->dev);
struct talitos_edesc *edesc;
- struct scatterlist *sg;
void *icvdata;
- req->cryptlen -= authsize;
-
/* allocate extended descriptor */
edesc = aead_edesc_alloc(req, req->iv, 1, false);
if (IS_ERR(edesc))
return PTR_ERR(edesc);
- if ((priv->features & TALITOS_FTR_HW_AUTH_CHECK) &&
+ if ((edesc->desc.hdr & DESC_HDR_TYPE_IPSEC_ESP) &&
+ (priv->features & TALITOS_FTR_HW_AUTH_CHECK) &&
((!edesc->src_nents && !edesc->dst_nents) ||
priv->features & TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT)) {
@@ -1537,24 +1481,20 @@ static int aead_decrypt(struct aead_request *req)
/* reset integrity check result bits */
- return ipsec_esp(edesc, req, ipsec_esp_decrypt_hwauth_done);
+ return ipsec_esp(edesc, req, false,
+ ipsec_esp_decrypt_hwauth_done);
}
/* Have to check the ICV with software */
edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_DIR_INBOUND;
/* stash incoming ICV for later cmp with ICV generated by the h/w */
- if (edesc->dma_len)
- icvdata = (char *)&edesc->link_tbl[edesc->src_nents +
- edesc->dst_nents + 2];
- else
- icvdata = &edesc->link_tbl[0];
+ icvdata = edesc->buf + edesc->dma_len;
- sg = sg_last(req->src, edesc->src_nents ? : 1);
+ sg_pcopy_to_buffer(req->src, edesc->src_nents ? : 1, icvdata, authsize,
+ req->assoclen + req->cryptlen - authsize);
- memcpy(icvdata, (char *)sg_virt(sg) + sg->length - authsize, authsize);
-
- return ipsec_esp(edesc, req, ipsec_esp_decrypt_swauth_done);
+ return ipsec_esp(edesc, req, false, ipsec_esp_decrypt_swauth_done);
}
static int ablkcipher_setkey(struct crypto_ablkcipher *cipher,
@@ -1605,6 +1545,18 @@ static int ablkcipher_des3_setkey(struct crypto_ablkcipher *cipher,
return ablkcipher_setkey(cipher, key, keylen);
}
+static int ablkcipher_aes_setkey(struct crypto_ablkcipher *cipher,
+ const u8 *key, unsigned int keylen)
+{
+ if (keylen == AES_KEYSIZE_128 || keylen == AES_KEYSIZE_192 ||
+ keylen == AES_KEYSIZE_256)
+ return ablkcipher_setkey(cipher, key, keylen);
+
+ crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN);
+
+ return -EINVAL;
+}
+
static void common_nonsnoop_unmap(struct device *dev,
struct talitos_edesc *edesc,
struct ablkcipher_request *areq)
@@ -1624,11 +1576,15 @@ static void ablkcipher_done(struct device *dev,
int err)
{
struct ablkcipher_request *areq = context;
+ struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
+ struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+ unsigned int ivsize = crypto_ablkcipher_ivsize(cipher);
struct talitos_edesc *edesc;
edesc = container_of(desc, struct talitos_edesc, desc);
common_nonsnoop_unmap(dev, edesc, areq);
+ memcpy(areq->info, ctx->iv, ivsize);
kfree(edesc);
@@ -1723,6 +1679,14 @@ static int ablkcipher_encrypt(struct ablkcipher_request *areq)
struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher);
struct talitos_edesc *edesc;
+ unsigned int blocksize =
+ crypto_tfm_alg_blocksize(crypto_ablkcipher_tfm(cipher));
+
+ if (!areq->nbytes)
+ return 0;
+
+ if (areq->nbytes % blocksize)
+ return -EINVAL;
/* allocate extended descriptor */
edesc = ablkcipher_edesc_alloc(areq, true);
@@ -1740,6 +1704,14 @@ static int ablkcipher_decrypt(struct ablkcipher_request *areq)
struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher);
struct talitos_edesc *edesc;
+ unsigned int blocksize =
+ crypto_tfm_alg_blocksize(crypto_ablkcipher_tfm(cipher));
+
+ if (!areq->nbytes)
+ return 0;
+
+ if (areq->nbytes % blocksize)
+ return -EINVAL;
/* allocate extended descriptor */
edesc = ablkcipher_edesc_alloc(areq, false);
@@ -1759,14 +1731,16 @@ static void common_nonsnoop_hash_unmap(struct device *dev,
struct talitos_private *priv = dev_get_drvdata(dev);
bool is_sec1 = has_ftr_sec1(priv);
struct talitos_desc *desc = &edesc->desc;
- struct talitos_desc *desc2 = desc + 1;
+ struct talitos_desc *desc2 = (struct talitos_desc *)
+ (edesc->buf + edesc->dma_len);
unmap_single_talitos_ptr(dev, &edesc->desc.ptr[5], DMA_FROM_DEVICE);
if (desc->next_desc &&
desc->ptr[5].ptr != desc2->ptr[5].ptr)
unmap_single_talitos_ptr(dev, &desc2->ptr[5], DMA_FROM_DEVICE);
- talitos_sg_unmap(dev, edesc, req_ctx->psrc, NULL, 0, 0);
+ if (req_ctx->psrc)
+ talitos_sg_unmap(dev, edesc, req_ctx->psrc, NULL, 0, 0);
/* When using hashctx-in, must unmap it. */
if (from_talitos_ptr_len(&edesc->desc.ptr[1], is_sec1))
@@ -1833,7 +1807,6 @@ static void talitos_handle_buggy_hash(struct talitos_ctx *ctx,
static int common_nonsnoop_hash(struct talitos_edesc *edesc,
struct ahash_request *areq, unsigned int length,
- unsigned int offset,
void (*callback) (struct device *dev,
struct talitos_desc *desc,
void *context, int error))
@@ -1872,9 +1845,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
sg_count = edesc->src_nents ?: 1;
if (is_sec1 && sg_count > 1)
- sg_pcopy_to_buffer(req_ctx->psrc, sg_count,
- edesc->buf + sizeof(struct talitos_desc),
- length, req_ctx->nbuf);
+ sg_copy_to_buffer(req_ctx->psrc, sg_count, edesc->buf, length);
else if (length)
sg_count = dma_map_sg(dev, req_ctx->psrc, sg_count,
DMA_TO_DEVICE);
@@ -1887,7 +1858,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
DMA_TO_DEVICE);
} else {
sg_count = talitos_sg_map(dev, req_ctx->psrc, length, edesc,
- &desc->ptr[3], sg_count, offset, 0);
+ &desc->ptr[3], sg_count, 0, 0);
if (sg_count > 1)
sync_needed = true;
}
@@ -1911,7 +1882,8 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
talitos_handle_buggy_hash(ctx, edesc, &desc->ptr[3]);
if (is_sec1 && req_ctx->nbuf && length) {
- struct talitos_desc *desc2 = desc + 1;
+ struct talitos_desc *desc2 = (struct talitos_desc *)
+ (edesc->buf + edesc->dma_len);
dma_addr_t next_desc;
memset(desc2, 0, sizeof(*desc2));
@@ -1932,7 +1904,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
DMA_TO_DEVICE);
copy_talitos_ptr(&desc2->ptr[2], &desc->ptr[2], is_sec1);
sg_count = talitos_sg_map(dev, req_ctx->psrc, length, edesc,
- &desc2->ptr[3], sg_count, offset, 0);
+ &desc2->ptr[3], sg_count, 0, 0);
if (sg_count > 1)
sync_needed = true;
copy_talitos_ptr(&desc2->ptr[5], &desc->ptr[5], is_sec1);
@@ -2043,7 +2015,6 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
struct device *dev = ctx->dev;
struct talitos_private *priv = dev_get_drvdata(dev);
bool is_sec1 = has_ftr_sec1(priv);
- int offset = 0;
u8 *ctx_buf = req_ctx->buf[req_ctx->buf_idx];
if (!req_ctx->last && (nbytes + req_ctx->nbuf <= blocksize)) {
@@ -2083,6 +2054,8 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
sg_chain(req_ctx->bufsl, 2, areq->src);
req_ctx->psrc = req_ctx->bufsl;
} else if (is_sec1 && req_ctx->nbuf && req_ctx->nbuf < blocksize) {
+ int offset;
+
if (nbytes_to_hash > blocksize)
offset = blocksize - req_ctx->nbuf;
else
@@ -2095,7 +2068,8 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
sg_copy_to_buffer(areq->src, nents,
ctx_buf + req_ctx->nbuf, offset);
req_ctx->nbuf += offset;
- req_ctx->psrc = areq->src;
+ req_ctx->psrc = scatterwalk_ffwd(req_ctx->bufsl, areq->src,
+ offset);
} else
req_ctx->psrc = areq->src;
@@ -2135,8 +2109,7 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
if (ctx->keylen && (req_ctx->first || req_ctx->last))
edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_HMAC;
- return common_nonsnoop_hash(edesc, areq, nbytes_to_hash, offset,
- ahash_done);
+ return common_nonsnoop_hash(edesc, areq, nbytes_to_hash, ahash_done);
}
static int ahash_update(struct ahash_request *areq)
@@ -2339,7 +2312,7 @@ static struct talitos_alg_template driver_algs[] = {
.base = {
.cra_name = "authenc(hmac(sha1),cbc(aes))",
.cra_driver_name = "authenc-hmac-sha1-"
- "cbc-aes-talitos",
+ "cbc-aes-talitos-hsna",
.cra_blocksize = AES_BLOCK_SIZE,
.cra_flags = CRYPTO_ALG_ASYNC,
},
@@ -2384,7 +2357,7 @@ static struct talitos_alg_template driver_algs[] = {
.cra_name = "authenc(hmac(sha1),"
"cbc(des3_ede))",
.cra_driver_name = "authenc-hmac-sha1-"
- "cbc-3des-talitos",
+ "cbc-3des-talitos-hsna",
.cra_blocksize = DES3_EDE_BLOCK_SIZE,
.cra_flags = CRYPTO_ALG_ASYNC,
},
@@ -2427,7 +2400,7 @@ static struct talitos_alg_template driver_algs[] = {
.base = {
.cra_name = "authenc(hmac(sha224),cbc(aes))",
.cra_driver_name = "authenc-hmac-sha224-"
- "cbc-aes-talitos",
+ "cbc-aes-talitos-hsna",
.cra_blocksize = AES_BLOCK_SIZE,
.cra_flags = CRYPTO_ALG_ASYNC,
},
@@ -2472,7 +2445,7 @@ static struct talitos_alg_template driver_algs[] = {
.cra_name = "authenc(hmac(sha224),"
"cbc(des3_ede))",
.cra_driver_name = "authenc-hmac-sha224-"
- "cbc-3des-talitos",
+ "cbc-3des-talitos-hsna",
.cra_blocksize = DES3_EDE_BLOCK_SIZE,
.cra_flags = CRYPTO_ALG_ASYNC,
},
@@ -2515,7 +2488,7 @@ static struct talitos_alg_template driver_algs[] = {
.base = {
.cra_name = "authenc(hmac(sha256),cbc(aes))",
.cra_driver_name = "authenc-hmac-sha256-"
- "cbc-aes-talitos",
+ "cbc-aes-talitos-hsna",
.cra_blocksize = AES_BLOCK_SIZE,
.cra_flags = CRYPTO_ALG_ASYNC,
},
@@ -2560,7 +2533,7 @@ static struct talitos_alg_template driver_algs[] = {
.cra_name = "authenc(hmac(sha256),"
"cbc(des3_ede))",
.cra_driver_name = "authenc-hmac-sha256-"
- "cbc-3des-talitos",
+ "cbc-3des-talitos-hsna",
.cra_blocksize = DES3_EDE_BLOCK_SIZE,
.cra_flags = CRYPTO_ALG_ASYNC,
},
@@ -2689,7 +2662,7 @@ static struct talitos_alg_template driver_algs[] = {
.base = {
.cra_name = "authenc(hmac(md5),cbc(aes))",
.cra_driver_name = "authenc-hmac-md5-"
- "cbc-aes-talitos",
+ "cbc-aes-talitos-hsna",
.cra_blocksize = AES_BLOCK_SIZE,
.cra_flags = CRYPTO_ALG_ASYNC,
},
@@ -2732,7 +2705,7 @@ static struct talitos_alg_template driver_algs[] = {
.base = {
.cra_name = "authenc(hmac(md5),cbc(des3_ede))",
.cra_driver_name = "authenc-hmac-md5-"
- "cbc-3des-talitos",
+ "cbc-3des-talitos-hsna",
.cra_blocksize = DES3_EDE_BLOCK_SIZE,
.cra_flags = CRYPTO_ALG_ASYNC,
},
@@ -2760,7 +2733,7 @@ static struct talitos_alg_template driver_algs[] = {
.cra_ablkcipher = {
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
- .ivsize = AES_BLOCK_SIZE,
+ .setkey = ablkcipher_aes_setkey,
}
},
.desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
@@ -2777,6 +2750,7 @@ static struct talitos_alg_template driver_algs[] = {
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
.ivsize = AES_BLOCK_SIZE,
+ .setkey = ablkcipher_aes_setkey,
}
},
.desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
@@ -2787,13 +2761,14 @@ static struct talitos_alg_template driver_algs[] = {
.alg.crypto = {
.cra_name = "ctr(aes)",
.cra_driver_name = "ctr-aes-talitos",
- .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_blocksize = 1,
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
CRYPTO_ALG_ASYNC,
.cra_ablkcipher = {
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
.ivsize = AES_BLOCK_SIZE,
+ .setkey = ablkcipher_aes_setkey,
}
},
.desc_hdr_template = DESC_HDR_TYPE_AESU_CTR_NONSNOOP |
@@ -2810,7 +2785,6 @@ static struct talitos_alg_template driver_algs[] = {
.cra_ablkcipher = {
.min_keysize = DES_KEY_SIZE,
.max_keysize = DES_KEY_SIZE,
- .ivsize = DES_BLOCK_SIZE,
.setkey = ablkcipher_des_setkey,
}
},
@@ -2845,7 +2819,6 @@ static struct talitos_alg_template driver_algs[] = {
.cra_ablkcipher = {
.min_keysize = DES3_EDE_KEY_SIZE,
.max_keysize = DES3_EDE_KEY_SIZE,
- .ivsize = DES3_EDE_BLOCK_SIZE,
.setkey = ablkcipher_des3_setkey,
}
},
@@ -3270,7 +3243,10 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev,
alg->cra_priority = t_alg->algt.priority;
else
alg->cra_priority = TALITOS_CRA_PRIORITY;
- alg->cra_alignmask = 0;
+ if (has_ftr_sec1(priv))
+ alg->cra_alignmask = 3;
+ else
+ alg->cra_alignmask = 0;
alg->cra_ctxsize = sizeof(struct talitos_ctx);
alg->cra_flags |= CRYPTO_ALG_KERN_DRIVER_ONLY;
@@ -3418,7 +3394,7 @@ static int talitos_probe(struct platform_device *ofdev)
if (err)
goto err_out;
- if (of_device_is_compatible(np, "fsl,sec1.0")) {
+ if (has_ftr_sec1(priv)) {
if (priv->num_channels == 1)
tasklet_init(&priv->done_task[0], talitos1_done_ch0,
(unsigned long)dev);
diff --git a/drivers/crypto/talitos.h b/drivers/crypto/talitos.h
index a65a63e0d6c1..1469b956948a 100644
--- a/drivers/crypto/talitos.h
+++ b/drivers/crypto/talitos.h
@@ -1,31 +1,8 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
/*
* Freescale SEC (talitos) device register and descriptor header defines
*
* Copyright (c) 2006-2011 Freescale Semiconductor, Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
*/
#define TALITOS_TIMEOUT 100000
@@ -65,6 +42,34 @@ struct talitos_desc {
#define TALITOS_DESC_SIZE (sizeof(struct talitos_desc) - sizeof(__be32))
+/*
+ * talitos_edesc - s/w-extended descriptor
+ * @src_nents: number of segments in input scatterlist
+ * @dst_nents: number of segments in output scatterlist
+ * @iv_dma: dma address of iv for checking continuity and link table
+ * @dma_len: length of dma mapped link_tbl space
+ * @dma_link_tbl: bus physical address of link_tbl/buf
+ * @desc: h/w descriptor
+ * @link_tbl: input and output h/w link tables (if {src,dst}_nents > 1) (SEC2)
+ * @buf: input and output buffeur (if {src,dst}_nents > 1) (SEC1)
+ *
+ * if decrypting (with authcheck), or either one of src_nents or dst_nents
+ * is greater than 1, an integrity check value is concatenated to the end
+ * of link_tbl data
+ */
+struct talitos_edesc {
+ int src_nents;
+ int dst_nents;
+ dma_addr_t iv_dma;
+ int dma_len;
+ dma_addr_t dma_link_tbl;
+ struct talitos_desc desc;
+ union {
+ struct talitos_ptr link_tbl[0];
+ u8 buf[0];
+ };
+};
+
/**
* talitos_request - descriptor submission request
* @desc: descriptor pointer (kernel virtual)
@@ -150,12 +155,6 @@ struct talitos_private {
bool rng_registered;
};
-extern int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc,
- void (*callback)(struct device *dev,
- struct talitos_desc *desc,
- void *context, int error),
- void *context);
-
/* .features flag */
#define TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT 0x00000001
#define TALITOS_FTR_HW_AUTH_CHECK 0x00000002
@@ -170,13 +169,11 @@ extern int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc,
*/
static inline bool has_ftr_sec1(struct talitos_private *priv)
{
-#if defined(CONFIG_CRYPTO_DEV_TALITOS1) && defined(CONFIG_CRYPTO_DEV_TALITOS2)
- return priv->features & TALITOS_FTR_SEC1 ? true : false;
-#elif defined(CONFIG_CRYPTO_DEV_TALITOS1)
- return true;
-#else
- return false;
-#endif
+ if (IS_ENABLED(CONFIG_CRYPTO_DEV_TALITOS1) &&
+ IS_ENABLED(CONFIG_CRYPTO_DEV_TALITOS2))
+ return priv->features & TALITOS_FTR_SEC1;
+
+ return IS_ENABLED(CONFIG_CRYPTO_DEV_TALITOS1);
}
/*
@@ -412,5 +409,5 @@ static inline bool has_ftr_sec1(struct talitos_private *priv)
/* link table extent field bits */
#define DESC_PTR_LNKTBL_JUMP 0x80
-#define DESC_PTR_LNKTBL_RETURN 0x02
+#define DESC_PTR_LNKTBL_RET 0x02
#define DESC_PTR_LNKTBL_NEXT 0x01
diff --git a/drivers/crypto/vmx/aes_cbc.c b/drivers/crypto/vmx/aes_cbc.c
index c7e515a1bc97..d88084447f1c 100644
--- a/drivers/crypto/vmx/aes_cbc.c
+++ b/drivers/crypto/vmx/aes_cbc.c
@@ -7,64 +7,52 @@
* Author: Marcelo Henrique Cerri <mhcerri@br.ibm.com>
*/
-#include <linux/types.h>
-#include <linux/err.h>
-#include <linux/crypto.h>
-#include <linux/delay.h>
#include <asm/simd.h>
#include <asm/switch_to.h>
#include <crypto/aes.h>
#include <crypto/internal/simd.h>
-#include <crypto/scatterwalk.h>
-#include <crypto/skcipher.h>
+#include <crypto/internal/skcipher.h>
#include "aesp8-ppc.h"
struct p8_aes_cbc_ctx {
- struct crypto_sync_skcipher *fallback;
+ struct crypto_skcipher *fallback;
struct aes_key enc_key;
struct aes_key dec_key;
};
-static int p8_aes_cbc_init(struct crypto_tfm *tfm)
+static int p8_aes_cbc_init(struct crypto_skcipher *tfm)
{
- const char *alg = crypto_tfm_alg_name(tfm);
- struct crypto_sync_skcipher *fallback;
- struct p8_aes_cbc_ctx *ctx = crypto_tfm_ctx(tfm);
-
- fallback = crypto_alloc_sync_skcipher(alg, 0,
- CRYPTO_ALG_NEED_FALLBACK);
+ struct p8_aes_cbc_ctx *ctx = crypto_skcipher_ctx(tfm);
+ struct crypto_skcipher *fallback;
+ fallback = crypto_alloc_skcipher("cbc(aes)", 0,
+ CRYPTO_ALG_NEED_FALLBACK |
+ CRYPTO_ALG_ASYNC);
if (IS_ERR(fallback)) {
- printk(KERN_ERR
- "Failed to allocate transformation for '%s': %ld\n",
- alg, PTR_ERR(fallback));
+ pr_err("Failed to allocate cbc(aes) fallback: %ld\n",
+ PTR_ERR(fallback));
return PTR_ERR(fallback);
}
- crypto_sync_skcipher_set_flags(
- fallback,
- crypto_skcipher_get_flags((struct crypto_skcipher *)tfm));
+ crypto_skcipher_set_reqsize(tfm, sizeof(struct skcipher_request) +
+ crypto_skcipher_reqsize(fallback));
ctx->fallback = fallback;
-
return 0;
}
-static void p8_aes_cbc_exit(struct crypto_tfm *tfm)
+static void p8_aes_cbc_exit(struct crypto_skcipher *tfm)
{
- struct p8_aes_cbc_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct p8_aes_cbc_ctx *ctx = crypto_skcipher_ctx(tfm);
- if (ctx->fallback) {
- crypto_free_sync_skcipher(ctx->fallback);
- ctx->fallback = NULL;
- }
+ crypto_free_skcipher(ctx->fallback);
}
-static int p8_aes_cbc_setkey(struct crypto_tfm *tfm, const u8 *key,
+static int p8_aes_cbc_setkey(struct crypto_skcipher *tfm, const u8 *key,
unsigned int keylen)
{
+ struct p8_aes_cbc_ctx *ctx = crypto_skcipher_ctx(tfm);
int ret;
- struct p8_aes_cbc_ctx *ctx = crypto_tfm_ctx(tfm);
preempt_disable();
pagefault_disable();
@@ -75,108 +63,71 @@ static int p8_aes_cbc_setkey(struct crypto_tfm *tfm, const u8 *key,
pagefault_enable();
preempt_enable();
- ret |= crypto_sync_skcipher_setkey(ctx->fallback, key, keylen);
+ ret |= crypto_skcipher_setkey(ctx->fallback, key, keylen);
return ret ? -EINVAL : 0;
}
-static int p8_aes_cbc_encrypt(struct blkcipher_desc *desc,
- struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int p8_aes_cbc_crypt(struct skcipher_request *req, int enc)
{
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ const struct p8_aes_cbc_ctx *ctx = crypto_skcipher_ctx(tfm);
+ struct skcipher_walk walk;
+ unsigned int nbytes;
int ret;
- struct blkcipher_walk walk;
- struct p8_aes_cbc_ctx *ctx =
- crypto_tfm_ctx(crypto_blkcipher_tfm(desc->tfm));
if (!crypto_simd_usable()) {
- SYNC_SKCIPHER_REQUEST_ON_STACK(req, ctx->fallback);
- skcipher_request_set_sync_tfm(req, ctx->fallback);
- skcipher_request_set_callback(req, desc->flags, NULL, NULL);
- skcipher_request_set_crypt(req, src, dst, nbytes, desc->info);
- ret = crypto_skcipher_encrypt(req);
- skcipher_request_zero(req);
- } else {
- blkcipher_walk_init(&walk, dst, src, nbytes);
- ret = blkcipher_walk_virt(desc, &walk);
- while ((nbytes = walk.nbytes)) {
- preempt_disable();
- pagefault_disable();
- enable_kernel_vsx();
- aes_p8_cbc_encrypt(walk.src.virt.addr,
- walk.dst.virt.addr,
- nbytes & AES_BLOCK_MASK,
- &ctx->enc_key, walk.iv, 1);
- disable_kernel_vsx();
- pagefault_enable();
- preempt_enable();
-
- nbytes &= AES_BLOCK_SIZE - 1;
- ret = blkcipher_walk_done(desc, &walk, nbytes);
- }
+ struct skcipher_request *subreq = skcipher_request_ctx(req);
+
+ *subreq = *req;
+ skcipher_request_set_tfm(subreq, ctx->fallback);
+ return enc ? crypto_skcipher_encrypt(subreq) :
+ crypto_skcipher_decrypt(subreq);
}
+ ret = skcipher_walk_virt(&walk, req, false);
+ while ((nbytes = walk.nbytes) != 0) {
+ preempt_disable();
+ pagefault_disable();
+ enable_kernel_vsx();
+ aes_p8_cbc_encrypt(walk.src.virt.addr,
+ walk.dst.virt.addr,
+ round_down(nbytes, AES_BLOCK_SIZE),
+ enc ? &ctx->enc_key : &ctx->dec_key,
+ walk.iv, enc);
+ disable_kernel_vsx();
+ pagefault_enable();
+ preempt_enable();
+
+ ret = skcipher_walk_done(&walk, nbytes % AES_BLOCK_SIZE);
+ }
return ret;
}
-static int p8_aes_cbc_decrypt(struct blkcipher_desc *desc,
- struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int p8_aes_cbc_encrypt(struct skcipher_request *req)
{
- int ret;
- struct blkcipher_walk walk;
- struct p8_aes_cbc_ctx *ctx =
- crypto_tfm_ctx(crypto_blkcipher_tfm(desc->tfm));
-
- if (!crypto_simd_usable()) {
- SYNC_SKCIPHER_REQUEST_ON_STACK(req, ctx->fallback);
- skcipher_request_set_sync_tfm(req, ctx->fallback);
- skcipher_request_set_callback(req, desc->flags, NULL, NULL);
- skcipher_request_set_crypt(req, src, dst, nbytes, desc->info);
- ret = crypto_skcipher_decrypt(req);
- skcipher_request_zero(req);
- } else {
- blkcipher_walk_init(&walk, dst, src, nbytes);
- ret = blkcipher_walk_virt(desc, &walk);
- while ((nbytes = walk.nbytes)) {
- preempt_disable();
- pagefault_disable();
- enable_kernel_vsx();
- aes_p8_cbc_encrypt(walk.src.virt.addr,
- walk.dst.virt.addr,
- nbytes & AES_BLOCK_MASK,
- &ctx->dec_key, walk.iv, 0);
- disable_kernel_vsx();
- pagefault_enable();
- preempt_enable();
-
- nbytes &= AES_BLOCK_SIZE - 1;
- ret = blkcipher_walk_done(desc, &walk, nbytes);
- }
- }
-
- return ret;
+ return p8_aes_cbc_crypt(req, 1);
}
+static int p8_aes_cbc_decrypt(struct skcipher_request *req)
+{
+ return p8_aes_cbc_crypt(req, 0);
+}
-struct crypto_alg p8_aes_cbc_alg = {
- .cra_name = "cbc(aes)",
- .cra_driver_name = "p8_aes_cbc",
- .cra_module = THIS_MODULE,
- .cra_priority = 2000,
- .cra_type = &crypto_blkcipher_type,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_NEED_FALLBACK,
- .cra_alignmask = 0,
- .cra_blocksize = AES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct p8_aes_cbc_ctx),
- .cra_init = p8_aes_cbc_init,
- .cra_exit = p8_aes_cbc_exit,
- .cra_blkcipher = {
- .ivsize = AES_BLOCK_SIZE,
- .min_keysize = AES_MIN_KEY_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE,
- .setkey = p8_aes_cbc_setkey,
- .encrypt = p8_aes_cbc_encrypt,
- .decrypt = p8_aes_cbc_decrypt,
- },
+struct skcipher_alg p8_aes_cbc_alg = {
+ .base.cra_name = "cbc(aes)",
+ .base.cra_driver_name = "p8_aes_cbc",
+ .base.cra_module = THIS_MODULE,
+ .base.cra_priority = 2000,
+ .base.cra_flags = CRYPTO_ALG_NEED_FALLBACK,
+ .base.cra_blocksize = AES_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct p8_aes_cbc_ctx),
+ .setkey = p8_aes_cbc_setkey,
+ .encrypt = p8_aes_cbc_encrypt,
+ .decrypt = p8_aes_cbc_decrypt,
+ .init = p8_aes_cbc_init,
+ .exit = p8_aes_cbc_exit,
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
};
diff --git a/drivers/crypto/vmx/aes_ctr.c b/drivers/crypto/vmx/aes_ctr.c
index dd017ef42fa9..79ba062ee1c1 100644
--- a/drivers/crypto/vmx/aes_ctr.c
+++ b/drivers/crypto/vmx/aes_ctr.c
@@ -7,62 +7,51 @@
* Author: Marcelo Henrique Cerri <mhcerri@br.ibm.com>
*/
-#include <linux/types.h>
-#include <linux/err.h>
-#include <linux/crypto.h>
-#include <linux/delay.h>
#include <asm/simd.h>
#include <asm/switch_to.h>
#include <crypto/aes.h>
#include <crypto/internal/simd.h>
-#include <crypto/scatterwalk.h>
-#include <crypto/skcipher.h>
+#include <crypto/internal/skcipher.h>
#include "aesp8-ppc.h"
struct p8_aes_ctr_ctx {
- struct crypto_sync_skcipher *fallback;
+ struct crypto_skcipher *fallback;
struct aes_key enc_key;
};
-static int p8_aes_ctr_init(struct crypto_tfm *tfm)
+static int p8_aes_ctr_init(struct crypto_skcipher *tfm)
{
- const char *alg = crypto_tfm_alg_name(tfm);
- struct crypto_sync_skcipher *fallback;
- struct p8_aes_ctr_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct p8_aes_ctr_ctx *ctx = crypto_skcipher_ctx(tfm);
+ struct crypto_skcipher *fallback;
- fallback = crypto_alloc_sync_skcipher(alg, 0,
- CRYPTO_ALG_NEED_FALLBACK);
+ fallback = crypto_alloc_skcipher("ctr(aes)", 0,
+ CRYPTO_ALG_NEED_FALLBACK |
+ CRYPTO_ALG_ASYNC);
if (IS_ERR(fallback)) {
- printk(KERN_ERR
- "Failed to allocate transformation for '%s': %ld\n",
- alg, PTR_ERR(fallback));
+ pr_err("Failed to allocate ctr(aes) fallback: %ld\n",
+ PTR_ERR(fallback));
return PTR_ERR(fallback);
}
- crypto_sync_skcipher_set_flags(
- fallback,
- crypto_skcipher_get_flags((struct crypto_skcipher *)tfm));
+ crypto_skcipher_set_reqsize(tfm, sizeof(struct skcipher_request) +
+ crypto_skcipher_reqsize(fallback));
ctx->fallback = fallback;
-
return 0;
}
-static void p8_aes_ctr_exit(struct crypto_tfm *tfm)
+static void p8_aes_ctr_exit(struct crypto_skcipher *tfm)
{
- struct p8_aes_ctr_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct p8_aes_ctr_ctx *ctx = crypto_skcipher_ctx(tfm);
- if (ctx->fallback) {
- crypto_free_sync_skcipher(ctx->fallback);
- ctx->fallback = NULL;
- }
+ crypto_free_skcipher(ctx->fallback);
}
-static int p8_aes_ctr_setkey(struct crypto_tfm *tfm, const u8 *key,
+static int p8_aes_ctr_setkey(struct crypto_skcipher *tfm, const u8 *key,
unsigned int keylen)
{
+ struct p8_aes_ctr_ctx *ctx = crypto_skcipher_ctx(tfm);
int ret;
- struct p8_aes_ctr_ctx *ctx = crypto_tfm_ctx(tfm);
preempt_disable();
pagefault_disable();
@@ -72,13 +61,13 @@ static int p8_aes_ctr_setkey(struct crypto_tfm *tfm, const u8 *key,
pagefault_enable();
preempt_enable();
- ret |= crypto_sync_skcipher_setkey(ctx->fallback, key, keylen);
+ ret |= crypto_skcipher_setkey(ctx->fallback, key, keylen);
return ret ? -EINVAL : 0;
}
-static void p8_aes_ctr_final(struct p8_aes_ctr_ctx *ctx,
- struct blkcipher_walk *walk)
+static void p8_aes_ctr_final(const struct p8_aes_ctr_ctx *ctx,
+ struct skcipher_walk *walk)
{
u8 *ctrblk = walk->iv;
u8 keystream[AES_BLOCK_SIZE];
@@ -98,77 +87,63 @@ static void p8_aes_ctr_final(struct p8_aes_ctr_ctx *ctx,
crypto_inc(ctrblk, AES_BLOCK_SIZE);
}
-static int p8_aes_ctr_crypt(struct blkcipher_desc *desc,
- struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int p8_aes_ctr_crypt(struct skcipher_request *req)
{
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ const struct p8_aes_ctr_ctx *ctx = crypto_skcipher_ctx(tfm);
+ struct skcipher_walk walk;
+ unsigned int nbytes;
int ret;
- u64 inc;
- struct blkcipher_walk walk;
- struct p8_aes_ctr_ctx *ctx =
- crypto_tfm_ctx(crypto_blkcipher_tfm(desc->tfm));
if (!crypto_simd_usable()) {
- SYNC_SKCIPHER_REQUEST_ON_STACK(req, ctx->fallback);
- skcipher_request_set_sync_tfm(req, ctx->fallback);
- skcipher_request_set_callback(req, desc->flags, NULL, NULL);
- skcipher_request_set_crypt(req, src, dst, nbytes, desc->info);
- ret = crypto_skcipher_encrypt(req);
- skcipher_request_zero(req);
- } else {
- blkcipher_walk_init(&walk, dst, src, nbytes);
- ret = blkcipher_walk_virt_block(desc, &walk, AES_BLOCK_SIZE);
- while ((nbytes = walk.nbytes) >= AES_BLOCK_SIZE) {
- preempt_disable();
- pagefault_disable();
- enable_kernel_vsx();
- aes_p8_ctr32_encrypt_blocks(walk.src.virt.addr,
- walk.dst.virt.addr,
- (nbytes &
- AES_BLOCK_MASK) /
- AES_BLOCK_SIZE,
- &ctx->enc_key,
- walk.iv);
- disable_kernel_vsx();
- pagefault_enable();
- preempt_enable();
-
- /* We need to update IV mostly for last bytes/round */
- inc = (nbytes & AES_BLOCK_MASK) / AES_BLOCK_SIZE;
- if (inc > 0)
- while (inc--)
- crypto_inc(walk.iv, AES_BLOCK_SIZE);
-
- nbytes &= AES_BLOCK_SIZE - 1;
- ret = blkcipher_walk_done(desc, &walk, nbytes);
- }
- if (walk.nbytes) {
- p8_aes_ctr_final(ctx, &walk);
- ret = blkcipher_walk_done(desc, &walk, 0);
- }
+ struct skcipher_request *subreq = skcipher_request_ctx(req);
+
+ *subreq = *req;
+ skcipher_request_set_tfm(subreq, ctx->fallback);
+ return crypto_skcipher_encrypt(subreq);
}
+ ret = skcipher_walk_virt(&walk, req, false);
+ while ((nbytes = walk.nbytes) >= AES_BLOCK_SIZE) {
+ preempt_disable();
+ pagefault_disable();
+ enable_kernel_vsx();
+ aes_p8_ctr32_encrypt_blocks(walk.src.virt.addr,
+ walk.dst.virt.addr,
+ nbytes / AES_BLOCK_SIZE,
+ &ctx->enc_key, walk.iv);
+ disable_kernel_vsx();
+ pagefault_enable();
+ preempt_enable();
+
+ do {
+ crypto_inc(walk.iv, AES_BLOCK_SIZE);
+ } while ((nbytes -= AES_BLOCK_SIZE) >= AES_BLOCK_SIZE);
+
+ ret = skcipher_walk_done(&walk, nbytes);
+ }
+ if (nbytes) {
+ p8_aes_ctr_final(ctx, &walk);
+ ret = skcipher_walk_done(&walk, 0);
+ }
return ret;
}
-struct crypto_alg p8_aes_ctr_alg = {
- .cra_name = "ctr(aes)",
- .cra_driver_name = "p8_aes_ctr",
- .cra_module = THIS_MODULE,
- .cra_priority = 2000,
- .cra_type = &crypto_blkcipher_type,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_NEED_FALLBACK,
- .cra_alignmask = 0,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct p8_aes_ctr_ctx),
- .cra_init = p8_aes_ctr_init,
- .cra_exit = p8_aes_ctr_exit,
- .cra_blkcipher = {
- .ivsize = AES_BLOCK_SIZE,
- .min_keysize = AES_MIN_KEY_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE,
- .setkey = p8_aes_ctr_setkey,
- .encrypt = p8_aes_ctr_crypt,
- .decrypt = p8_aes_ctr_crypt,
- },
+struct skcipher_alg p8_aes_ctr_alg = {
+ .base.cra_name = "ctr(aes)",
+ .base.cra_driver_name = "p8_aes_ctr",
+ .base.cra_module = THIS_MODULE,
+ .base.cra_priority = 2000,
+ .base.cra_flags = CRYPTO_ALG_NEED_FALLBACK,
+ .base.cra_blocksize = 1,
+ .base.cra_ctxsize = sizeof(struct p8_aes_ctr_ctx),
+ .setkey = p8_aes_ctr_setkey,
+ .encrypt = p8_aes_ctr_crypt,
+ .decrypt = p8_aes_ctr_crypt,
+ .init = p8_aes_ctr_init,
+ .exit = p8_aes_ctr_exit,
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .chunksize = AES_BLOCK_SIZE,
};
diff --git a/drivers/crypto/vmx/aes_xts.c b/drivers/crypto/vmx/aes_xts.c
index 536167e737a0..49f7258045fa 100644
--- a/drivers/crypto/vmx/aes_xts.c
+++ b/drivers/crypto/vmx/aes_xts.c
@@ -7,67 +7,56 @@
* Author: Leonidas S. Barbosa <leosilva@linux.vnet.ibm.com>
*/
-#include <linux/types.h>
-#include <linux/err.h>
-#include <linux/crypto.h>
-#include <linux/delay.h>
#include <asm/simd.h>
#include <asm/switch_to.h>
#include <crypto/aes.h>
#include <crypto/internal/simd.h>
-#include <crypto/scatterwalk.h>
+#include <crypto/internal/skcipher.h>
#include <crypto/xts.h>
-#include <crypto/skcipher.h>
#include "aesp8-ppc.h"
struct p8_aes_xts_ctx {
- struct crypto_sync_skcipher *fallback;
+ struct crypto_skcipher *fallback;
struct aes_key enc_key;
struct aes_key dec_key;
struct aes_key tweak_key;
};
-static int p8_aes_xts_init(struct crypto_tfm *tfm)
+static int p8_aes_xts_init(struct crypto_skcipher *tfm)
{
- const char *alg = crypto_tfm_alg_name(tfm);
- struct crypto_sync_skcipher *fallback;
- struct p8_aes_xts_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct p8_aes_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
+ struct crypto_skcipher *fallback;
- fallback = crypto_alloc_sync_skcipher(alg, 0,
- CRYPTO_ALG_NEED_FALLBACK);
+ fallback = crypto_alloc_skcipher("xts(aes)", 0,
+ CRYPTO_ALG_NEED_FALLBACK |
+ CRYPTO_ALG_ASYNC);
if (IS_ERR(fallback)) {
- printk(KERN_ERR
- "Failed to allocate transformation for '%s': %ld\n",
- alg, PTR_ERR(fallback));
+ pr_err("Failed to allocate xts(aes) fallback: %ld\n",
+ PTR_ERR(fallback));
return PTR_ERR(fallback);
}
- crypto_sync_skcipher_set_flags(
- fallback,
- crypto_skcipher_get_flags((struct crypto_skcipher *)tfm));
+ crypto_skcipher_set_reqsize(tfm, sizeof(struct skcipher_request) +
+ crypto_skcipher_reqsize(fallback));
ctx->fallback = fallback;
-
return 0;
}
-static void p8_aes_xts_exit(struct crypto_tfm *tfm)
+static void p8_aes_xts_exit(struct crypto_skcipher *tfm)
{
- struct p8_aes_xts_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct p8_aes_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
- if (ctx->fallback) {
- crypto_free_sync_skcipher(ctx->fallback);
- ctx->fallback = NULL;
- }
+ crypto_free_skcipher(ctx->fallback);
}
-static int p8_aes_xts_setkey(struct crypto_tfm *tfm, const u8 *key,
+static int p8_aes_xts_setkey(struct crypto_skcipher *tfm, const u8 *key,
unsigned int keylen)
{
+ struct p8_aes_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
int ret;
- struct p8_aes_xts_ctx *ctx = crypto_tfm_ctx(tfm);
- ret = xts_check_key(tfm, key, keylen);
+ ret = xts_verify_key(tfm, key, keylen);
if (ret)
return ret;
@@ -81,100 +70,90 @@ static int p8_aes_xts_setkey(struct crypto_tfm *tfm, const u8 *key,
pagefault_enable();
preempt_enable();
- ret |= crypto_sync_skcipher_setkey(ctx->fallback, key, keylen);
+ ret |= crypto_skcipher_setkey(ctx->fallback, key, keylen);
return ret ? -EINVAL : 0;
}
-static int p8_aes_xts_crypt(struct blkcipher_desc *desc,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes, int enc)
+static int p8_aes_xts_crypt(struct skcipher_request *req, int enc)
{
- int ret;
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ const struct p8_aes_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
+ struct skcipher_walk walk;
+ unsigned int nbytes;
u8 tweak[AES_BLOCK_SIZE];
- u8 *iv;
- struct blkcipher_walk walk;
- struct p8_aes_xts_ctx *ctx =
- crypto_tfm_ctx(crypto_blkcipher_tfm(desc->tfm));
+ int ret;
if (!crypto_simd_usable()) {
- SYNC_SKCIPHER_REQUEST_ON_STACK(req, ctx->fallback);
- skcipher_request_set_sync_tfm(req, ctx->fallback);
- skcipher_request_set_callback(req, desc->flags, NULL, NULL);
- skcipher_request_set_crypt(req, src, dst, nbytes, desc->info);
- ret = enc? crypto_skcipher_encrypt(req) : crypto_skcipher_decrypt(req);
- skcipher_request_zero(req);
- } else {
- blkcipher_walk_init(&walk, dst, src, nbytes);
+ struct skcipher_request *subreq = skcipher_request_ctx(req);
+
+ *subreq = *req;
+ skcipher_request_set_tfm(subreq, ctx->fallback);
+ return enc ? crypto_skcipher_encrypt(subreq) :
+ crypto_skcipher_decrypt(subreq);
+ }
+
+ ret = skcipher_walk_virt(&walk, req, false);
+ if (ret)
+ return ret;
+
+ preempt_disable();
+ pagefault_disable();
+ enable_kernel_vsx();
- ret = blkcipher_walk_virt(desc, &walk);
+ aes_p8_encrypt(walk.iv, tweak, &ctx->tweak_key);
+
+ disable_kernel_vsx();
+ pagefault_enable();
+ preempt_enable();
+ while ((nbytes = walk.nbytes) != 0) {
preempt_disable();
pagefault_disable();
enable_kernel_vsx();
-
- iv = walk.iv;
- memset(tweak, 0, AES_BLOCK_SIZE);
- aes_p8_encrypt(iv, tweak, &ctx->tweak_key);
-
+ if (enc)
+ aes_p8_xts_encrypt(walk.src.virt.addr,
+ walk.dst.virt.addr,
+ round_down(nbytes, AES_BLOCK_SIZE),
+ &ctx->enc_key, NULL, tweak);
+ else
+ aes_p8_xts_decrypt(walk.src.virt.addr,
+ walk.dst.virt.addr,
+ round_down(nbytes, AES_BLOCK_SIZE),
+ &ctx->dec_key, NULL, tweak);
disable_kernel_vsx();
pagefault_enable();
preempt_enable();
- while ((nbytes = walk.nbytes)) {
- preempt_disable();
- pagefault_disable();
- enable_kernel_vsx();
- if (enc)
- aes_p8_xts_encrypt(walk.src.virt.addr, walk.dst.virt.addr,
- nbytes & AES_BLOCK_MASK, &ctx->enc_key, NULL, tweak);
- else
- aes_p8_xts_decrypt(walk.src.virt.addr, walk.dst.virt.addr,
- nbytes & AES_BLOCK_MASK, &ctx->dec_key, NULL, tweak);
- disable_kernel_vsx();
- pagefault_enable();
- preempt_enable();
-
- nbytes &= AES_BLOCK_SIZE - 1;
- ret = blkcipher_walk_done(desc, &walk, nbytes);
- }
+ ret = skcipher_walk_done(&walk, nbytes % AES_BLOCK_SIZE);
}
return ret;
}
-static int p8_aes_xts_encrypt(struct blkcipher_desc *desc,
- struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int p8_aes_xts_encrypt(struct skcipher_request *req)
{
- return p8_aes_xts_crypt(desc, dst, src, nbytes, 1);
+ return p8_aes_xts_crypt(req, 1);
}
-static int p8_aes_xts_decrypt(struct blkcipher_desc *desc,
- struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int p8_aes_xts_decrypt(struct skcipher_request *req)
{
- return p8_aes_xts_crypt(desc, dst, src, nbytes, 0);
+ return p8_aes_xts_crypt(req, 0);
}
-struct crypto_alg p8_aes_xts_alg = {
- .cra_name = "xts(aes)",
- .cra_driver_name = "p8_aes_xts",
- .cra_module = THIS_MODULE,
- .cra_priority = 2000,
- .cra_type = &crypto_blkcipher_type,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_NEED_FALLBACK,
- .cra_alignmask = 0,
- .cra_blocksize = AES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct p8_aes_xts_ctx),
- .cra_init = p8_aes_xts_init,
- .cra_exit = p8_aes_xts_exit,
- .cra_blkcipher = {
- .ivsize = AES_BLOCK_SIZE,
- .min_keysize = 2 * AES_MIN_KEY_SIZE,
- .max_keysize = 2 * AES_MAX_KEY_SIZE,
- .setkey = p8_aes_xts_setkey,
- .encrypt = p8_aes_xts_encrypt,
- .decrypt = p8_aes_xts_decrypt,
- }
+struct skcipher_alg p8_aes_xts_alg = {
+ .base.cra_name = "xts(aes)",
+ .base.cra_driver_name = "p8_aes_xts",
+ .base.cra_module = THIS_MODULE,
+ .base.cra_priority = 2000,
+ .base.cra_flags = CRYPTO_ALG_NEED_FALLBACK,
+ .base.cra_blocksize = AES_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct p8_aes_xts_ctx),
+ .setkey = p8_aes_xts_setkey,
+ .encrypt = p8_aes_xts_encrypt,
+ .decrypt = p8_aes_xts_decrypt,
+ .init = p8_aes_xts_init,
+ .exit = p8_aes_xts_exit,
+ .min_keysize = 2 * AES_MIN_KEY_SIZE,
+ .max_keysize = 2 * AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
};
diff --git a/drivers/crypto/vmx/aesp8-ppc.h b/drivers/crypto/vmx/aesp8-ppc.h
index 349646b73754..01774a4d26a2 100644
--- a/drivers/crypto/vmx/aesp8-ppc.h
+++ b/drivers/crypto/vmx/aesp8-ppc.h
@@ -2,8 +2,6 @@
#include <linux/types.h>
#include <crypto/aes.h>
-#define AES_BLOCK_MASK (~(AES_BLOCK_SIZE-1))
-
struct aes_key {
u8 key[AES_MAX_KEYLENGTH];
int rounds;
diff --git a/drivers/crypto/vmx/aesp8-ppc.pl b/drivers/crypto/vmx/aesp8-ppc.pl
index 9c6b5c1d6a1a..db874367b602 100644
--- a/drivers/crypto/vmx/aesp8-ppc.pl
+++ b/drivers/crypto/vmx/aesp8-ppc.pl
@@ -1286,6 +1286,24 @@ ___
#########################################################################
{{{ # CTR procedure[s] #
+
+####################### WARNING: Here be dragons! #######################
+#
+# This code is written as 'ctr32', based on a 32-bit counter used
+# upstream. The kernel does *not* use a 32-bit counter. The kernel uses
+# a 128-bit counter.
+#
+# This leads to subtle changes from the upstream code: the counter
+# is incremented with vaddu_q_m rather than vaddu_w_m. This occurs in
+# both the bulk (8 blocks at a time) path, and in the individual block
+# path. Be aware of this when doing updates.
+#
+# See:
+# 1d4aa0b4c181 ("crypto: vmx - Fixing AES-CTR counter bug")
+# 009b30ac7444 ("crypto: vmx - CTR: always increment IV as quadword")
+# https://github.com/openssl/openssl/pull/8942
+#
+#########################################################################
my ($inp,$out,$len,$key,$ivp,$x10,$rounds,$idx)=map("r$_",(3..10));
my ($rndkey0,$rndkey1,$inout,$tmp)= map("v$_",(0..3));
my ($ivec,$inptail,$inpperm,$outhead,$outperm,$outmask,$keyperm,$one)=
@@ -1357,7 +1375,7 @@ Loop_ctr32_enc:
addi $idx,$idx,16
bdnz Loop_ctr32_enc
- vadduqm $ivec,$ivec,$one
+ vadduqm $ivec,$ivec,$one # Kernel change for 128-bit
vmr $dat,$inptail
lvx $inptail,0,$inp
addi $inp,$inp,16
@@ -1501,7 +1519,7 @@ Load_ctr32_enc_key:
$SHL $len,$len,4
vadduqm $out1,$ivec,$one # counter values ...
- vadduqm $out2,$ivec,$two
+ vadduqm $out2,$ivec,$two # (do all ctr adds as 128-bit)
vxor $out0,$ivec,$rndkey0 # ... xored with rndkey[0]
le?li $idx,8
vadduqm $out3,$out1,$two
diff --git a/drivers/crypto/vmx/vmx.c b/drivers/crypto/vmx/vmx.c
index 6c4c77f4e159..3e0335fb406c 100644
--- a/drivers/crypto/vmx/vmx.c
+++ b/drivers/crypto/vmx/vmx.c
@@ -15,54 +15,58 @@
#include <linux/crypto.h>
#include <asm/cputable.h>
#include <crypto/internal/hash.h>
+#include <crypto/internal/skcipher.h>
extern struct shash_alg p8_ghash_alg;
extern struct crypto_alg p8_aes_alg;
-extern struct crypto_alg p8_aes_cbc_alg;
-extern struct crypto_alg p8_aes_ctr_alg;
-extern struct crypto_alg p8_aes_xts_alg;
-static struct crypto_alg *algs[] = {
- &p8_aes_alg,
- &p8_aes_cbc_alg,
- &p8_aes_ctr_alg,
- &p8_aes_xts_alg,
- NULL,
-};
+extern struct skcipher_alg p8_aes_cbc_alg;
+extern struct skcipher_alg p8_aes_ctr_alg;
+extern struct skcipher_alg p8_aes_xts_alg;
static int __init p8_init(void)
{
- int ret = 0;
- struct crypto_alg **alg_it;
+ int ret;
- for (alg_it = algs; *alg_it; alg_it++) {
- ret = crypto_register_alg(*alg_it);
- printk(KERN_INFO "crypto_register_alg '%s' = %d\n",
- (*alg_it)->cra_name, ret);
- if (ret) {
- for (alg_it--; alg_it >= algs; alg_it--)
- crypto_unregister_alg(*alg_it);
- break;
- }
- }
+ ret = crypto_register_shash(&p8_ghash_alg);
if (ret)
- return ret;
+ goto err;
- ret = crypto_register_shash(&p8_ghash_alg);
- if (ret) {
- for (alg_it = algs; *alg_it; alg_it++)
- crypto_unregister_alg(*alg_it);
- }
+ ret = crypto_register_alg(&p8_aes_alg);
+ if (ret)
+ goto err_unregister_ghash;
+
+ ret = crypto_register_skcipher(&p8_aes_cbc_alg);
+ if (ret)
+ goto err_unregister_aes;
+
+ ret = crypto_register_skcipher(&p8_aes_ctr_alg);
+ if (ret)
+ goto err_unregister_aes_cbc;
+
+ ret = crypto_register_skcipher(&p8_aes_xts_alg);
+ if (ret)
+ goto err_unregister_aes_ctr;
+
+ return 0;
+
+err_unregister_aes_ctr:
+ crypto_unregister_skcipher(&p8_aes_ctr_alg);
+err_unregister_aes_cbc:
+ crypto_unregister_skcipher(&p8_aes_cbc_alg);
+err_unregister_aes:
+ crypto_unregister_alg(&p8_aes_alg);
+err_unregister_ghash:
+ crypto_unregister_shash(&p8_ghash_alg);
+err:
return ret;
}
static void __exit p8_exit(void)
{
- struct crypto_alg **alg_it;
-
- for (alg_it = algs; *alg_it; alg_it++) {
- printk(KERN_INFO "Removing '%s'\n", (*alg_it)->cra_name);
- crypto_unregister_alg(*alg_it);
- }
+ crypto_unregister_skcipher(&p8_aes_xts_alg);
+ crypto_unregister_skcipher(&p8_aes_ctr_alg);
+ crypto_unregister_skcipher(&p8_aes_cbc_alg);
+ crypto_unregister_alg(&p8_aes_alg);
crypto_unregister_shash(&p8_ghash_alg);
}
diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c
index 2109cfe80219..8fafbeab510a 100644
--- a/drivers/dax/bus.c
+++ b/drivers/dax/bus.c
@@ -295,6 +295,22 @@ static ssize_t target_node_show(struct device *dev,
}
static DEVICE_ATTR_RO(target_node);
+static unsigned long long dev_dax_resource(struct dev_dax *dev_dax)
+{
+ struct dax_region *dax_region = dev_dax->region;
+
+ return dax_region->res.start;
+}
+
+static ssize_t resource_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dev_dax *dev_dax = to_dev_dax(dev);
+
+ return sprintf(buf, "%#llx\n", dev_dax_resource(dev_dax));
+}
+static DEVICE_ATTR_RO(resource);
+
static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -313,6 +329,8 @@ static umode_t dev_dax_visible(struct kobject *kobj, struct attribute *a, int n)
if (a == &dev_attr_target_node.attr && dev_dax_target_node(dev_dax) < 0)
return 0;
+ if (a == &dev_attr_resource.attr)
+ return 0400;
return a->mode;
}
@@ -320,6 +338,7 @@ static struct attribute *dev_dax_attributes[] = {
&dev_attr_modalias.attr,
&dev_attr_size.attr,
&dev_attr_target_node.attr,
+ &dev_attr_resource.attr,
NULL,
};
@@ -388,7 +407,7 @@ struct dev_dax *__devm_create_dev_dax(struct dax_region *dax_region, int id,
* No 'host' or dax_operations since there is no access to this
* device outside of mmap of the resulting character device.
*/
- dax_dev = alloc_dax(dev_dax, NULL, NULL);
+ dax_dev = alloc_dax(dev_dax, NULL, NULL, DAXDEV_F_SYNC);
if (!dax_dev)
goto err;
diff --git a/drivers/dax/dax-private.h b/drivers/dax/dax-private.h
index b4177aafbbd1..6ccca3b890d6 100644
--- a/drivers/dax/dax-private.h
+++ b/drivers/dax/dax-private.h
@@ -43,8 +43,7 @@ struct dax_region {
* @target_node: effective numa node if dev_dax memory range is onlined
* @dev - device core
* @pgmap - pgmap for memmap setup / lifetime (driver owned)
- * @ref: pgmap reference count (driver owned)
- * @cmp: @ref final put completion (driver owned)
+ * @dax_mem_res: physical address range of hotadded DAX memory
*/
struct dev_dax {
struct dax_region *region;
@@ -52,8 +51,7 @@ struct dev_dax {
int target_node;
struct device dev;
struct dev_pagemap pgmap;
- struct percpu_ref ref;
- struct completion cmp;
+ struct resource *dax_kmem_res;
};
static inline struct dev_dax *to_dev_dax(struct device *dev)
diff --git a/drivers/dax/device.c b/drivers/dax/device.c
index 8465d12fecba..1af823b2fe6b 100644
--- a/drivers/dax/device.c
+++ b/drivers/dax/device.c
@@ -14,37 +14,6 @@
#include "dax-private.h"
#include "bus.h"
-static struct dev_dax *ref_to_dev_dax(struct percpu_ref *ref)
-{
- return container_of(ref, struct dev_dax, ref);
-}
-
-static void dev_dax_percpu_release(struct percpu_ref *ref)
-{
- struct dev_dax *dev_dax = ref_to_dev_dax(ref);
-
- dev_dbg(&dev_dax->dev, "%s\n", __func__);
- complete(&dev_dax->cmp);
-}
-
-static void dev_dax_percpu_exit(struct percpu_ref *ref)
-{
- struct dev_dax *dev_dax = ref_to_dev_dax(ref);
-
- dev_dbg(&dev_dax->dev, "%s\n", __func__);
- wait_for_completion(&dev_dax->cmp);
- percpu_ref_exit(ref);
-}
-
-static void dev_dax_percpu_kill(struct percpu_ref *data)
-{
- struct percpu_ref *ref = data;
- struct dev_dax *dev_dax = ref_to_dev_dax(ref);
-
- dev_dbg(&dev_dax->dev, "%s\n", __func__);
- percpu_ref_kill(ref);
-}
-
static int check_vma(struct dev_dax *dev_dax, struct vm_area_struct *vma,
const char *func)
{
@@ -459,15 +428,7 @@ int dev_dax_probe(struct device *dev)
return -EBUSY;
}
- init_completion(&dev_dax->cmp);
- rc = percpu_ref_init(&dev_dax->ref, dev_dax_percpu_release, 0,
- GFP_KERNEL);
- if (rc)
- return rc;
-
- dev_dax->pgmap.ref = &dev_dax->ref;
- dev_dax->pgmap.kill = dev_dax_percpu_kill;
- dev_dax->pgmap.cleanup = dev_dax_percpu_exit;
+ dev_dax->pgmap.type = MEMORY_DEVICE_DEVDAX;
addr = devm_memremap_pages(dev, &dev_dax->pgmap);
if (IS_ERR(addr))
return PTR_ERR(addr);
diff --git a/drivers/dax/kmem.c b/drivers/dax/kmem.c
index a02318c6d28a..3d0a7e702c94 100644
--- a/drivers/dax/kmem.c
+++ b/drivers/dax/kmem.c
@@ -66,23 +66,59 @@ int dev_dax_kmem_probe(struct device *dev)
new_res->name = dev_name(dev);
rc = add_memory(numa_node, new_res->start, resource_size(new_res));
- if (rc)
+ if (rc) {
+ release_resource(new_res);
+ kfree(new_res);
return rc;
+ }
+ dev_dax->dax_kmem_res = new_res;
return 0;
}
+#ifdef CONFIG_MEMORY_HOTREMOVE
+static int dev_dax_kmem_remove(struct device *dev)
+{
+ struct dev_dax *dev_dax = to_dev_dax(dev);
+ struct resource *res = dev_dax->dax_kmem_res;
+ resource_size_t kmem_start = res->start;
+ resource_size_t kmem_size = resource_size(res);
+ int rc;
+
+ /*
+ * We have one shot for removing memory, if some memory blocks were not
+ * offline prior to calling this function remove_memory() will fail, and
+ * there is no way to hotremove this memory until reboot because device
+ * unbind will succeed even if we return failure.
+ */
+ rc = remove_memory(dev_dax->target_node, kmem_start, kmem_size);
+ if (rc) {
+ dev_err(dev,
+ "DAX region %pR cannot be hotremoved until the next reboot\n",
+ res);
+ return rc;
+ }
+
+ /* Release and free dax resources */
+ release_resource(res);
+ kfree(res);
+ dev_dax->dax_kmem_res = NULL;
+
+ return 0;
+}
+#else
static int dev_dax_kmem_remove(struct device *dev)
{
/*
- * Purposely leak the request_mem_region() for the device-dax
- * range and return '0' to ->remove() attempts. The removal of
- * the device from the driver always succeeds, but the region
- * is permanently pinned as reserved by the unreleased
+ * Without hotremove purposely leak the request_mem_region() for the
+ * device-dax range and return '0' to ->remove() attempts. The removal
+ * of the device from the driver always succeeds, but the region is
+ * permanently pinned as reserved by the unreleased
* request_mem_region().
*/
return 0;
}
+#endif /* CONFIG_MEMORY_HOTREMOVE */
static struct dax_device_driver device_dax_kmem_driver = {
.drv = {
diff --git a/drivers/dax/pmem/core.c b/drivers/dax/pmem/core.c
index f9f51786d556..6eb6dfdf19bf 100644
--- a/drivers/dax/pmem/core.c
+++ b/drivers/dax/pmem/core.c
@@ -16,7 +16,7 @@ struct dev_dax *__dax_pmem_probe(struct device *dev, enum dev_dax_subsys subsys)
struct dev_dax *dev_dax;
struct nd_namespace_io *nsio;
struct dax_region *dax_region;
- struct dev_pagemap pgmap = { 0 };
+ struct dev_pagemap pgmap = { };
struct nd_namespace_common *ndns;
struct nd_dax *nd_dax = to_nd_dax(dev);
struct nd_pfn *nd_pfn = &nd_dax->nd_pfn;
diff --git a/drivers/dax/super.c b/drivers/dax/super.c
index 4e5ae7e8b557..26a654dbc69a 100644
--- a/drivers/dax/super.c
+++ b/drivers/dax/super.c
@@ -5,6 +5,7 @@
#include <linux/pagemap.h>
#include <linux/module.h>
#include <linux/mount.h>
+#include <linux/pseudo_fs.h>
#include <linux/magic.h>
#include <linux/genhd.h>
#include <linux/pfn_t.h>
@@ -195,6 +196,8 @@ enum dax_device_flags {
DAXDEV_ALIVE,
/* gate whether dax_flush() calls the low level flush routine */
DAXDEV_WRITE_CACHE,
+ /* flag to check if device supports synchronous flush */
+ DAXDEV_SYNC,
};
/**
@@ -372,6 +375,18 @@ bool dax_write_cache_enabled(struct dax_device *dax_dev)
}
EXPORT_SYMBOL_GPL(dax_write_cache_enabled);
+bool __dax_synchronous(struct dax_device *dax_dev)
+{
+ return test_bit(DAXDEV_SYNC, &dax_dev->flags);
+}
+EXPORT_SYMBOL_GPL(__dax_synchronous);
+
+void __set_dax_synchronous(struct dax_device *dax_dev)
+{
+ set_bit(DAXDEV_SYNC, &dax_dev->flags);
+}
+EXPORT_SYMBOL_GPL(__set_dax_synchronous);
+
bool dax_alive(struct dax_device *dax_dev)
{
lockdep_assert_held(&dax_srcu);
@@ -455,16 +470,19 @@ static const struct super_operations dax_sops = {
.drop_inode = generic_delete_inode,
};
-static struct dentry *dax_mount(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int dax_init_fs_context(struct fs_context *fc)
{
- return mount_pseudo(fs_type, "dax:", &dax_sops, NULL, DAXFS_MAGIC);
+ struct pseudo_fs_context *ctx = init_pseudo(fc, DAXFS_MAGIC);
+ if (!ctx)
+ return -ENOMEM;
+ ctx->ops = &dax_sops;
+ return 0;
}
static struct file_system_type dax_fs_type = {
- .name = "dax",
- .mount = dax_mount,
- .kill_sb = kill_anon_super,
+ .name = "dax",
+ .init_fs_context = dax_init_fs_context,
+ .kill_sb = kill_anon_super,
};
static int dax_test(struct inode *inode, void *data)
@@ -526,7 +544,7 @@ static void dax_add_host(struct dax_device *dax_dev, const char *host)
}
struct dax_device *alloc_dax(void *private, const char *__host,
- const struct dax_operations *ops)
+ const struct dax_operations *ops, unsigned long flags)
{
struct dax_device *dax_dev;
const char *host;
@@ -549,6 +567,9 @@ struct dax_device *alloc_dax(void *private, const char *__host,
dax_add_host(dax_dev, host);
dax_dev->ops = ops;
dax_dev->private = private;
+ if (flags & DAXDEV_F_SYNC)
+ set_dax_synchronous(dax_dev);
+
return dax_dev;
err_dev:
@@ -648,10 +669,6 @@ static int dax_fs_init(void)
if (!dax_cache)
return -ENOMEM;
- rc = register_filesystem(&dax_fs_type);
- if (rc)
- goto err_register_fs;
-
dax_mnt = kern_mount(&dax_fs_type);
if (IS_ERR(dax_mnt)) {
rc = PTR_ERR(dax_mnt);
@@ -662,8 +679,6 @@ static int dax_fs_init(void)
return 0;
err_mount:
- unregister_filesystem(&dax_fs_type);
- err_register_fs:
kmem_cache_destroy(dax_cache);
return rc;
@@ -672,7 +687,6 @@ static int dax_fs_init(void)
static void dax_fs_exit(void)
{
kern_unmount(dax_mnt);
- unregister_filesystem(&dax_fs_type);
kmem_cache_destroy(dax_cache);
}
diff --git a/drivers/devfreq/devfreq-event.c b/drivers/devfreq/devfreq-event.c
index 87e93406d7cd..3dc5fd6065a3 100644
--- a/drivers/devfreq/devfreq-event.c
+++ b/drivers/devfreq/devfreq-event.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* devfreq-event: a framework to provide raw data and events of devfreq devices
*
* Copyright (C) 2015 Samsung Electronics
* Author: Chanwoo Choi <cw00.choi@samsung.com>
*
- * 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.
- *
* This driver is based on drivers/devfreq/devfreq.c.
*/
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 6b6991f0e873..ab22bf8a12d6 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* devfreq: Generic Dynamic Voltage and Frequency Scaling (DVFS) Framework
* for Non-CPU Devices.
*
* Copyright (C) 2011 Samsung Electronics
* MyungJoo Ham <myungjoo.ham@samsung.com>
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/devfreq/event/exynos-nocp.c b/drivers/devfreq/event/exynos-nocp.c
index f6e7956fc91a..1c565926db9f 100644
--- a/drivers/devfreq/event/exynos-nocp.c
+++ b/drivers/devfreq/event/exynos-nocp.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* exynos-nocp.c - EXYNOS NoC (Network On Chip) Probe support
*
* Copyright (c) 2016 Samsung Electronics Co., Ltd.
* Author : Chanwoo Choi <cw00.choi@samsung.com>
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/devfreq/event/exynos-nocp.h b/drivers/devfreq/event/exynos-nocp.h
index 28564db0edb8..55cc96284a36 100644
--- a/drivers/devfreq/event/exynos-nocp.h
+++ b/drivers/devfreq/event/exynos-nocp.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* exynos-nocp.h - EXYNOS NoC (Network on Chip) Probe header file
*
* Copyright (c) 2016 Samsung Electronics Co., Ltd.
* Author : Chanwoo Choi <cw00.choi@samsung.com>
- *
- * 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.
*/
#ifndef __EXYNOS_NOCP_H__
diff --git a/drivers/devfreq/event/exynos-ppmu.c b/drivers/devfreq/event/exynos-ppmu.c
index c2ea94957501..3ee3dd5653aa 100644
--- a/drivers/devfreq/event/exynos-ppmu.c
+++ b/drivers/devfreq/event/exynos-ppmu.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* exynos_ppmu.c - EXYNOS PPMU (Platform Performance Monitoring Unit) support
*
* Copyright (c) 2014-2015 Samsung Electronics Co., Ltd.
* Author : Chanwoo Choi <cw00.choi@samsung.com>
*
- * 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.
- *
* This driver is based on drivers/devfreq/exynos/exynos_ppmu.c
*/
diff --git a/drivers/devfreq/event/exynos-ppmu.h b/drivers/devfreq/event/exynos-ppmu.h
index 05774c449137..284420047455 100644
--- a/drivers/devfreq/event/exynos-ppmu.h
+++ b/drivers/devfreq/event/exynos-ppmu.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* exynos_ppmu.h - EXYNOS PPMU header file
*
* Copyright (c) 2015 Samsung Electronics Co., Ltd.
* Author : Chanwoo Choi <cw00.choi@samsung.com>
- *
- * 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.
*/
#ifndef __EXYNOS_PPMU_H__
diff --git a/drivers/devfreq/exynos-bus.c b/drivers/devfreq/exynos-bus.c
index 486cc5b422f1..d9f377912c10 100644
--- a/drivers/devfreq/exynos-bus.c
+++ b/drivers/devfreq/exynos-bus.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic Exynos Bus frequency driver with DEVFREQ Framework
*
@@ -6,10 +7,6 @@
*
* This driver support Exynos Bus frequency feature by using
* DEVFREQ framework and is based on drivers/devfreq/exynos/exynos4_bus.c.
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/devfreq/governor.h b/drivers/devfreq/governor.h
index f53339ca610f..bbe5ff9fcecf 100644
--- a/drivers/devfreq/governor.h
+++ b/drivers/devfreq/governor.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* governor.h - internal header for devfreq governors.
*
* Copyright (C) 2011 Samsung Electronics
* MyungJoo Ham <myungjoo.ham@samsung.com>
*
- * 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.
- *
* This header is for devfreq governors in drivers/devfreq/
*/
diff --git a/drivers/devfreq/governor_passive.c b/drivers/devfreq/governor_passive.c
index 3bc29acbd54e..58308948b863 100644
--- a/drivers/devfreq/governor_passive.c
+++ b/drivers/devfreq/governor_passive.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/devfreq/governor_passive.c
*
* Copyright (C) 2016 Samsung Electronics
* Author: Chanwoo Choi <cw00.choi@samsung.com>
* Author: MyungJoo Ham <myungjoo.ham@samsung.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/devfreq/governor_performance.c b/drivers/devfreq/governor_performance.c
index ded429fd51be..5dbc1e56ec08 100644
--- a/drivers/devfreq/governor_performance.c
+++ b/drivers/devfreq/governor_performance.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/devfreq/governor_performance.c
*
* Copyright (C) 2011 Samsung Electronics
* MyungJoo Ham <myungjoo.ham@samsung.com>
- *
- * 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.
*/
#include <linux/devfreq.h>
diff --git a/drivers/devfreq/governor_powersave.c b/drivers/devfreq/governor_powersave.c
index 9e8897f5ac42..4746af2435b0 100644
--- a/drivers/devfreq/governor_powersave.c
+++ b/drivers/devfreq/governor_powersave.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/devfreq/governor_powersave.c
*
* Copyright (C) 2011 Samsung Electronics
* MyungJoo Ham <myungjoo.ham@samsung.com>
- *
- * 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.
*/
#include <linux/devfreq.h>
diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c
index c0417f0e081e..3d809f228619 100644
--- a/drivers/devfreq/governor_simpleondemand.c
+++ b/drivers/devfreq/governor_simpleondemand.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/devfreq/governor_simpleondemand.c
*
* Copyright (C) 2011 Samsung Electronics
* MyungJoo Ham <myungjoo.ham@samsung.com>
- *
- * 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.
*/
#include <linux/errno.h>
diff --git a/drivers/devfreq/governor_userspace.c b/drivers/devfreq/governor_userspace.c
index 378d84c011df..af94942fcf95 100644
--- a/drivers/devfreq/governor_userspace.c
+++ b/drivers/devfreq/governor_userspace.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/devfreq/governor_userspace.c
*
* Copyright (C) 2011 Samsung Electronics
* MyungJoo Ham <myungjoo.ham@samsung.com>
- *
- * 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.
*/
#include <linux/slab.h>
diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig
index d5f915830b68..b6a9c2f1bc41 100644
--- a/drivers/dma-buf/Kconfig
+++ b/drivers/dma-buf/Kconfig
@@ -15,7 +15,7 @@ config SYNC_FILE
associated with a buffer. When a job is submitted to the GPU a fence
is attached to the buffer and is transferred via userspace, using Sync
Files fds, to the DRM driver for example. More details at
- Documentation/sync_file.txt.
+ Documentation/driver-api/sync_file.rst.
config SW_SYNC
bool "Sync File Validation Framework"
diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
index 6c15deb5d4ad..f45bfb29ef96 100644
--- a/drivers/dma-buf/dma-buf.c
+++ b/drivers/dma-buf/dma-buf.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Framework for buffer objects that can be shared across devices/subsystems.
*
@@ -8,18 +9,6 @@
* Arnd Bergmann <arnd@arndb.de>, Rob Clark <rob@ti.com> and
* Daniel Vetter <daniel@ffwll.ch> for their support in creation and
* refining of this idea.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/fs.h>
@@ -35,6 +24,7 @@
#include <linux/reservation.h>
#include <linux/mm.h>
#include <linux/mount.h>
+#include <linux/pseudo_fs.h>
#include <uapi/linux/dma-buf.h>
#include <uapi/linux/magic.h>
@@ -70,16 +60,20 @@ static const struct dentry_operations dma_buf_dentry_ops = {
static struct vfsmount *dma_buf_mnt;
-static struct dentry *dma_buf_fs_mount(struct file_system_type *fs_type,
- int flags, const char *name, void *data)
+static int dma_buf_fs_init_context(struct fs_context *fc)
{
- return mount_pseudo(fs_type, "dmabuf:", NULL, &dma_buf_dentry_ops,
- DMA_BUF_MAGIC);
+ struct pseudo_fs_context *ctx;
+
+ ctx = init_pseudo(fc, DMA_BUF_MAGIC);
+ if (!ctx)
+ return -ENOMEM;
+ ctx->dops = &dma_buf_dentry_ops;
+ return 0;
}
static struct file_system_type dma_buf_fs_type = {
.name = "dmabuf",
- .mount = dma_buf_fs_mount,
+ .init_fs_context = dma_buf_fs_init_context,
.kill_sb = kill_anon_super,
};
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 703275cc29de..03fa0c58cef3 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -103,6 +103,7 @@ config AXI_DMAC
depends on MICROBLAZE || NIOS2 || ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_SOCFPGA || COMPILE_TEST
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
+ select REGMAP_MMIO
help
Enable support for the Analog Devices AXI-DMAC peripheral. This DMA
controller is often used in Analog Device's reference designs for FPGA
@@ -584,7 +585,7 @@ config TEGRA20_APB_DMA
config TEGRA210_ADMA
tristate "NVIDIA Tegra210 ADMA support"
- depends on (ARCH_TEGRA_210_SOC || COMPILE_TEST) && PM_CLK
+ depends on (ARCH_TEGRA_210_SOC || COMPILE_TEST)
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
help
@@ -666,6 +667,8 @@ source "drivers/dma/qcom/Kconfig"
source "drivers/dma/dw/Kconfig"
+source "drivers/dma/dw-edma/Kconfig"
+
source "drivers/dma/hsu/Kconfig"
source "drivers/dma/sh/Kconfig"
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 6126e1c3a875..5bddf6f8790f 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_DMA_SUN4I) += sun4i-dma.o
obj-$(CONFIG_DMA_SUN6I) += sun6i-dma.o
obj-$(CONFIG_DW_AXI_DMAC) += dw-axi-dmac/
obj-$(CONFIG_DW_DMAC_CORE) += dw/
+obj-$(CONFIG_DW_EDMA) += dw-edma/
obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o
obj-$(CONFIG_FSL_DMA) += fsldma.o
obj-$(CONFIG_FSL_EDMA) += fsl-edma.o fsl-edma-common.o
diff --git a/drivers/dma/acpi-dma.c b/drivers/dma/acpi-dma.c
index 4a748c3435d7..30243f5c0710 100644
--- a/drivers/dma/acpi-dma.c
+++ b/drivers/dma/acpi-dma.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ACPI helpers for DMA request / controller
*
@@ -6,10 +7,6 @@
* Copyright (C) 2013, Intel Corporation
* Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
* Mika Westerberg <mika.westerberg@linux.intel.com>
- *
- * 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.
*/
#include <linux/device.h>
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 464725dcad00..9adc7a2fa3d3 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -2508,9 +2508,8 @@ DEFINE_SHOW_ATTRIBUTE(pl08x_debugfs);
static void init_pl08x_debugfs(struct pl08x_driver_data *pl08x)
{
/* Expose a simple debugfs interface to view all clocks */
- (void) debugfs_create_file(dev_name(&pl08x->adev->dev),
- S_IFREG | S_IRUGO, NULL, pl08x,
- &pl08x_debugfs_fops);
+ debugfs_create_file(dev_name(&pl08x->adev->dev), S_IFREG | S_IRUGO,
+ NULL, pl08x, &pl08x_debugfs_fops);
}
#else
diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
index e4ae2ee46d3f..b58ac720d9a1 100644
--- a/drivers/dma/at_xdmac.c
+++ b/drivers/dma/at_xdmac.c
@@ -1,21 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for the Atmel Extensible DMA Controller (aka XDMAC on AT91 systems)
*
* Copyright (C) 2014 Atmel Corporation
*
* Author: Ludovic Desroches <ludovic.desroches@atmel.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <asm/barrier.h>
@@ -1579,11 +1568,14 @@ static void at_xdmac_handle_cyclic(struct at_xdmac_chan *atchan)
struct at_xdmac_desc *desc;
struct dma_async_tx_descriptor *txd;
- desc = list_first_entry(&atchan->xfers_list, struct at_xdmac_desc, xfer_node);
- txd = &desc->tx_dma_desc;
+ if (!list_empty(&atchan->xfers_list)) {
+ desc = list_first_entry(&atchan->xfers_list,
+ struct at_xdmac_desc, xfer_node);
+ txd = &desc->tx_dma_desc;
- if (txd->flags & DMA_PREP_INTERRUPT)
- dmaengine_desc_get_callback_invoke(txd, NULL);
+ if (txd->flags & DMA_PREP_INTERRUPT)
+ dmaengine_desc_get_callback_invoke(txd, NULL);
+ }
}
static void at_xdmac_handle_error(struct at_xdmac_chan *atchan)
diff --git a/drivers/dma/bcm-sba-raid.c b/drivers/dma/bcm-sba-raid.c
index fa81d0177765..275e90fa829d 100644
--- a/drivers/dma/bcm-sba-raid.c
+++ b/drivers/dma/bcm-sba-raid.c
@@ -164,7 +164,6 @@ struct sba_device {
struct list_head reqs_free_list;
/* DebugFS directory entries */
struct dentry *root;
- struct dentry *stats;
};
/* ====== Command helper routines ===== */
@@ -1716,17 +1715,11 @@ static int sba_probe(struct platform_device *pdev)
/* Create debugfs root entry */
sba->root = debugfs_create_dir(dev_name(sba->dev), NULL);
- if (IS_ERR_OR_NULL(sba->root)) {
- dev_err(sba->dev, "failed to create debugfs root entry\n");
- sba->root = NULL;
- goto skip_debugfs;
- }
/* Create debugfs stats entry */
- sba->stats = debugfs_create_devm_seqfile(sba->dev, "stats", sba->root,
- sba_debugfs_stats_show);
- if (IS_ERR_OR_NULL(sba->stats))
- dev_err(sba->dev, "failed to create debugfs stats file\n");
+ debugfs_create_devm_seqfile(sba->dev, "stats", sba->root,
+ sba_debugfs_stats_show);
+
skip_debugfs:
/* Register DMA device with Linux async framework */
diff --git a/drivers/dma/bestcomm/bcom_ata_task.c b/drivers/dma/bestcomm/bcom_ata_task.c
index cc6049a4e469..9a1c349e932f 100644
--- a/drivers/dma/bestcomm/bcom_ata_task.c
+++ b/drivers/dma/bestcomm/bcom_ata_task.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Bestcomm ATA task microcode
*
* Copyright (c) 2004 Freescale Semiconductor, 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.
- *
* Created based on bestcom/code_dma/image_rtos1/dma_image.hex
*/
diff --git a/drivers/dma/bestcomm/bcom_fec_rx_task.c b/drivers/dma/bestcomm/bcom_fec_rx_task.c
index a1ad6a02fcef..c610dc76a82e 100644
--- a/drivers/dma/bestcomm/bcom_fec_rx_task.c
+++ b/drivers/dma/bestcomm/bcom_fec_rx_task.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Bestcomm FEC RX task microcode
*
* Copyright (c) 2004 Freescale Semiconductor, 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.
- *
* Automatically created based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex
* on Tue Mar 22 11:19:38 2005 GMT
*/
diff --git a/drivers/dma/bestcomm/bcom_fec_tx_task.c b/drivers/dma/bestcomm/bcom_fec_tx_task.c
index b1c495c3a65a..410b42695668 100644
--- a/drivers/dma/bestcomm/bcom_fec_tx_task.c
+++ b/drivers/dma/bestcomm/bcom_fec_tx_task.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Bestcomm FEC TX task microcode
*
* Copyright (c) 2004 Freescale Semiconductor, 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.
- *
* Automatically created based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex
* on Tue Mar 22 11:19:29 2005 GMT
*/
diff --git a/drivers/dma/bestcomm/bcom_gen_bd_rx_task.c b/drivers/dma/bestcomm/bcom_gen_bd_rx_task.c
index efee022b0256..8dd38ede26d2 100644
--- a/drivers/dma/bestcomm/bcom_gen_bd_rx_task.c
+++ b/drivers/dma/bestcomm/bcom_gen_bd_rx_task.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Bestcomm GenBD RX task microcode
*
@@ -5,13 +6,8 @@
* Jeff Gibbons <jeff.gibbons@appspec.com>
* Copyright (c) 2004 Freescale Semiconductor, 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.
- *
* Based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex
* on Tue Mar 4 10:14:12 2006 GMT
- *
*/
#include <asm/types.h>
diff --git a/drivers/dma/bestcomm/bcom_gen_bd_tx_task.c b/drivers/dma/bestcomm/bcom_gen_bd_tx_task.c
index c605aa42ecbb..844dfe258639 100644
--- a/drivers/dma/bestcomm/bcom_gen_bd_tx_task.c
+++ b/drivers/dma/bestcomm/bcom_gen_bd_tx_task.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Bestcomm GenBD TX task microcode
*
@@ -5,13 +6,8 @@
* Jeff Gibbons <jeff.gibbons@appspec.com>
* Copyright (c) 2004 Freescale Semiconductor, 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.
- *
* Based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex
* on Tue Mar 4 10:14:12 2006 GMT
- *
*/
#include <asm/types.h>
diff --git a/drivers/dma/bestcomm/gen_bd.c b/drivers/dma/bestcomm/gen_bd.c
index 1a5b22d88127..906ddba6a6f5 100644
--- a/drivers/dma/bestcomm/gen_bd.c
+++ b/drivers/dma/bestcomm/gen_bd.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for MPC52xx processor BestComm General Buffer Descriptor
*
* Copyright (C) 2007 Sylvain Munaut <tnt@246tNt.com>
* Copyright (C) 2006 AppSpec Computer Technologies Corp.
* Jeff Gibbons <jeff.gibbons@appspec.com>
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c
index 547786ac342b..e51d836afcc7 100644
--- a/drivers/dma/coh901318.c
+++ b/drivers/dma/coh901318.c
@@ -1378,10 +1378,8 @@ static int __init init_coh901318_debugfs(void)
dma_dentry = debugfs_create_dir("dma", NULL);
- (void) debugfs_create_file("status",
- S_IFREG | S_IRUGO,
- dma_dentry, NULL,
- &coh901318_debugfs_status_operations);
+ debugfs_create_file("status", S_IFREG | S_IRUGO, dma_dentry, NULL,
+ &coh901318_debugfs_status_operations);
return 0;
}
diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c
index 8a3f1043917b..a0ee404b736e 100644
--- a/drivers/dma/dma-axi-dmac.c
+++ b/drivers/dma/dma-axi-dmac.c
@@ -2,7 +2,7 @@
/*
* Driver for the Analog Devices AXI-DMAC core
*
- * Copyright 2013-2015 Analog Devices Inc.
+ * Copyright 2013-2019 Analog Devices Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
*/
@@ -18,7 +18,9 @@
#include <linux/of.h>
#include <linux/of_dma.h>
#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
+#include <linux/fpga/adi-axi-common.h>
#include <dt-bindings/dma/axi-dmac.h>
@@ -62,6 +64,8 @@
#define AXI_DMAC_REG_STATUS 0x430
#define AXI_DMAC_REG_CURRENT_SRC_ADDR 0x434
#define AXI_DMAC_REG_CURRENT_DEST_ADDR 0x438
+#define AXI_DMAC_REG_PARTIAL_XFER_LEN 0x44c
+#define AXI_DMAC_REG_PARTIAL_XFER_ID 0x450
#define AXI_DMAC_CTRL_ENABLE BIT(0)
#define AXI_DMAC_CTRL_PAUSE BIT(1)
@@ -70,6 +74,10 @@
#define AXI_DMAC_IRQ_EOT BIT(1)
#define AXI_DMAC_FLAG_CYCLIC BIT(0)
+#define AXI_DMAC_FLAG_LAST BIT(1)
+#define AXI_DMAC_FLAG_PARTIAL_REPORT BIT(2)
+
+#define AXI_DMAC_FLAG_PARTIAL_XFER_DONE BIT(31)
/* The maximum ID allocated by the hardware is 31 */
#define AXI_DMAC_SG_UNUSED 32U
@@ -82,12 +90,14 @@ struct axi_dmac_sg {
unsigned int dest_stride;
unsigned int src_stride;
unsigned int id;
+ unsigned int partial_len;
bool schedule_when_free;
};
struct axi_dmac_desc {
struct virt_dma_desc vdesc;
bool cyclic;
+ bool have_partial_xfer;
unsigned int num_submitted;
unsigned int num_completed;
@@ -108,8 +118,10 @@ struct axi_dmac_chan {
unsigned int dest_type;
unsigned int max_length;
- unsigned int align_mask;
+ unsigned int address_align_mask;
+ unsigned int length_align_mask;
+ bool hw_partial_xfer;
bool hw_cyclic;
bool hw_2d;
};
@@ -167,14 +179,14 @@ static bool axi_dmac_check_len(struct axi_dmac_chan *chan, unsigned int len)
{
if (len == 0)
return false;
- if ((len & chan->align_mask) != 0) /* Not aligned */
+ if ((len & chan->length_align_mask) != 0) /* Not aligned */
return false;
return true;
}
static bool axi_dmac_check_addr(struct axi_dmac_chan *chan, dma_addr_t addr)
{
- if ((addr & chan->align_mask) != 0) /* Not aligned */
+ if ((addr & chan->address_align_mask) != 0) /* Not aligned */
return false;
return true;
}
@@ -210,11 +222,13 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan)
}
desc->num_submitted++;
- if (desc->num_submitted == desc->num_sgs) {
+ if (desc->num_submitted == desc->num_sgs ||
+ desc->have_partial_xfer) {
if (desc->cyclic)
desc->num_submitted = 0; /* Start again */
else
chan->next_desc = NULL;
+ flags |= AXI_DMAC_FLAG_LAST;
} else {
chan->next_desc = desc;
}
@@ -240,6 +254,9 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan)
desc->num_sgs == 1)
flags |= AXI_DMAC_FLAG_CYCLIC;
+ if (chan->hw_partial_xfer)
+ flags |= AXI_DMAC_FLAG_PARTIAL_REPORT;
+
axi_dmac_write(dmac, AXI_DMAC_REG_X_LENGTH, sg->x_len - 1);
axi_dmac_write(dmac, AXI_DMAC_REG_Y_LENGTH, sg->y_len - 1);
axi_dmac_write(dmac, AXI_DMAC_REG_FLAGS, flags);
@@ -252,6 +269,83 @@ static struct axi_dmac_desc *axi_dmac_active_desc(struct axi_dmac_chan *chan)
struct axi_dmac_desc, vdesc.node);
}
+static inline unsigned int axi_dmac_total_sg_bytes(struct axi_dmac_chan *chan,
+ struct axi_dmac_sg *sg)
+{
+ if (chan->hw_2d)
+ return sg->x_len * sg->y_len;
+ else
+ return sg->x_len;
+}
+
+static void axi_dmac_dequeue_partial_xfers(struct axi_dmac_chan *chan)
+{
+ struct axi_dmac *dmac = chan_to_axi_dmac(chan);
+ struct axi_dmac_desc *desc;
+ struct axi_dmac_sg *sg;
+ u32 xfer_done, len, id, i;
+ bool found_sg;
+
+ do {
+ len = axi_dmac_read(dmac, AXI_DMAC_REG_PARTIAL_XFER_LEN);
+ id = axi_dmac_read(dmac, AXI_DMAC_REG_PARTIAL_XFER_ID);
+
+ found_sg = false;
+ list_for_each_entry(desc, &chan->active_descs, vdesc.node) {
+ for (i = 0; i < desc->num_sgs; i++) {
+ sg = &desc->sg[i];
+ if (sg->id == AXI_DMAC_SG_UNUSED)
+ continue;
+ if (sg->id == id) {
+ desc->have_partial_xfer = true;
+ sg->partial_len = len;
+ found_sg = true;
+ break;
+ }
+ }
+ if (found_sg)
+ break;
+ }
+
+ if (found_sg) {
+ dev_dbg(dmac->dma_dev.dev,
+ "Found partial segment id=%u, len=%u\n",
+ id, len);
+ } else {
+ dev_warn(dmac->dma_dev.dev,
+ "Not found partial segment id=%u, len=%u\n",
+ id, len);
+ }
+
+ /* Check if we have any more partial transfers */
+ xfer_done = axi_dmac_read(dmac, AXI_DMAC_REG_TRANSFER_DONE);
+ xfer_done = !(xfer_done & AXI_DMAC_FLAG_PARTIAL_XFER_DONE);
+
+ } while (!xfer_done);
+}
+
+static void axi_dmac_compute_residue(struct axi_dmac_chan *chan,
+ struct axi_dmac_desc *active)
+{
+ struct dmaengine_result *rslt = &active->vdesc.tx_result;
+ unsigned int start = active->num_completed - 1;
+ struct axi_dmac_sg *sg;
+ unsigned int i, total;
+
+ rslt->result = DMA_TRANS_NOERROR;
+ rslt->residue = 0;
+
+ /*
+ * We get here if the last completed segment is partial, which
+ * means we can compute the residue from that segment onwards
+ */
+ for (i = start; i < active->num_sgs; i++) {
+ sg = &active->sg[i];
+ total = axi_dmac_total_sg_bytes(chan, sg);
+ rslt->residue += (total - sg->partial_len);
+ }
+}
+
static bool axi_dmac_transfer_done(struct axi_dmac_chan *chan,
unsigned int completed_transfers)
{
@@ -263,6 +357,10 @@ static bool axi_dmac_transfer_done(struct axi_dmac_chan *chan,
if (!active)
return false;
+ if (chan->hw_partial_xfer &&
+ (completed_transfers & AXI_DMAC_FLAG_PARTIAL_XFER_DONE))
+ axi_dmac_dequeue_partial_xfers(chan);
+
do {
sg = &active->sg[active->num_completed];
if (sg->id == AXI_DMAC_SG_UNUSED) /* Not yet submitted */
@@ -276,10 +374,14 @@ static bool axi_dmac_transfer_done(struct axi_dmac_chan *chan,
start_next = true;
}
+ if (sg->partial_len)
+ axi_dmac_compute_residue(chan, active);
+
if (active->cyclic)
vchan_cyclic_callback(&active->vdesc);
- if (active->num_completed == active->num_sgs) {
+ if (active->num_completed == active->num_sgs ||
+ sg->partial_len) {
if (active->cyclic) {
active->num_completed = 0; /* wrap around */
} else {
@@ -391,7 +493,7 @@ static struct axi_dmac_sg *axi_dmac_fill_linear_sg(struct axi_dmac_chan *chan,
num_segments = DIV_ROUND_UP(period_len, chan->max_length);
segment_size = DIV_ROUND_UP(period_len, num_segments);
/* Take care of alignment */
- segment_size = ((segment_size - 1) | chan->align_mask) + 1;
+ segment_size = ((segment_size - 1) | chan->length_align_mask) + 1;
for (i = 0; i < num_periods; i++) {
len = period_len;
@@ -561,6 +663,9 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_interleaved(
desc->sg[0].y_len = 1;
}
+ if (flags & DMA_CYCLIC)
+ desc->cyclic = true;
+
return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
}
@@ -574,6 +679,44 @@ static void axi_dmac_desc_free(struct virt_dma_desc *vdesc)
kfree(container_of(vdesc, struct axi_dmac_desc, vdesc));
}
+static bool axi_dmac_regmap_rdwr(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case AXI_DMAC_REG_IRQ_MASK:
+ case AXI_DMAC_REG_IRQ_SOURCE:
+ case AXI_DMAC_REG_IRQ_PENDING:
+ case AXI_DMAC_REG_CTRL:
+ case AXI_DMAC_REG_TRANSFER_ID:
+ case AXI_DMAC_REG_START_TRANSFER:
+ case AXI_DMAC_REG_FLAGS:
+ case AXI_DMAC_REG_DEST_ADDRESS:
+ case AXI_DMAC_REG_SRC_ADDRESS:
+ case AXI_DMAC_REG_X_LENGTH:
+ case AXI_DMAC_REG_Y_LENGTH:
+ case AXI_DMAC_REG_DEST_STRIDE:
+ case AXI_DMAC_REG_SRC_STRIDE:
+ case AXI_DMAC_REG_TRANSFER_DONE:
+ case AXI_DMAC_REG_ACTIVE_TRANSFER_ID:
+ case AXI_DMAC_REG_STATUS:
+ case AXI_DMAC_REG_CURRENT_SRC_ADDR:
+ case AXI_DMAC_REG_CURRENT_DEST_ADDR:
+ case AXI_DMAC_REG_PARTIAL_XFER_LEN:
+ case AXI_DMAC_REG_PARTIAL_XFER_ID:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config axi_dmac_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = AXI_DMAC_REG_PARTIAL_XFER_ID,
+ .readable_reg = axi_dmac_regmap_rdwr,
+ .writeable_reg = axi_dmac_regmap_rdwr,
+};
+
/*
* The configuration stored in the devicetree matches the configuration
* parameters of the peripheral instance and allows the driver to know which
@@ -617,7 +760,7 @@ static int axi_dmac_parse_chan_dt(struct device_node *of_chan,
return ret;
chan->dest_width = val / 8;
- chan->align_mask = max(chan->dest_width, chan->src_width) - 1;
+ chan->address_align_mask = max(chan->dest_width, chan->src_width) - 1;
if (axi_dmac_dest_is_mem(chan) && axi_dmac_src_is_mem(chan))
chan->direction = DMA_MEM_TO_MEM;
@@ -631,9 +774,12 @@ static int axi_dmac_parse_chan_dt(struct device_node *of_chan,
return 0;
}
-static void axi_dmac_detect_caps(struct axi_dmac *dmac)
+static int axi_dmac_detect_caps(struct axi_dmac *dmac)
{
struct axi_dmac_chan *chan = &dmac->chan;
+ unsigned int version;
+
+ version = axi_dmac_read(dmac, ADI_AXI_REG_VERSION);
axi_dmac_write(dmac, AXI_DMAC_REG_FLAGS, AXI_DMAC_FLAG_CYCLIC);
if (axi_dmac_read(dmac, AXI_DMAC_REG_FLAGS) == AXI_DMAC_FLAG_CYCLIC)
@@ -647,6 +793,35 @@ static void axi_dmac_detect_caps(struct axi_dmac *dmac)
chan->max_length = axi_dmac_read(dmac, AXI_DMAC_REG_X_LENGTH);
if (chan->max_length != UINT_MAX)
chan->max_length++;
+
+ axi_dmac_write(dmac, AXI_DMAC_REG_DEST_ADDRESS, 0xffffffff);
+ if (axi_dmac_read(dmac, AXI_DMAC_REG_DEST_ADDRESS) == 0 &&
+ chan->dest_type == AXI_DMAC_BUS_TYPE_AXI_MM) {
+ dev_err(dmac->dma_dev.dev,
+ "Destination memory-mapped interface not supported.");
+ return -ENODEV;
+ }
+
+ axi_dmac_write(dmac, AXI_DMAC_REG_SRC_ADDRESS, 0xffffffff);
+ if (axi_dmac_read(dmac, AXI_DMAC_REG_SRC_ADDRESS) == 0 &&
+ chan->src_type == AXI_DMAC_BUS_TYPE_AXI_MM) {
+ dev_err(dmac->dma_dev.dev,
+ "Source memory-mapped interface not supported.");
+ return -ENODEV;
+ }
+
+ if (version >= ADI_AXI_PCORE_VER(4, 2, 'a'))
+ chan->hw_partial_xfer = true;
+
+ if (version >= ADI_AXI_PCORE_VER(4, 1, 'a')) {
+ axi_dmac_write(dmac, AXI_DMAC_REG_X_LENGTH, 0x00);
+ chan->length_align_mask =
+ axi_dmac_read(dmac, AXI_DMAC_REG_X_LENGTH);
+ } else {
+ chan->length_align_mask = chan->address_align_mask;
+ }
+
+ return 0;
}
static int axi_dmac_probe(struct platform_device *pdev)
@@ -722,7 +897,11 @@ static int axi_dmac_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
- axi_dmac_detect_caps(dmac);
+ ret = axi_dmac_detect_caps(dmac);
+ if (ret)
+ goto err_clk_disable;
+
+ dma_dev->copy_align = (dmac->chan.address_align_mask + 1);
axi_dmac_write(dmac, AXI_DMAC_REG_IRQ_MASK, 0x00);
@@ -742,6 +921,8 @@ static int axi_dmac_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dmac);
+ devm_regmap_init_mmio(&pdev->dev, dmac->base, &axi_dmac_regmap_config);
+
return 0;
err_unregister_of:
diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c
index 263bee76ef0d..7fe9309a876b 100644
--- a/drivers/dma/dma-jz4780.c
+++ b/drivers/dma/dma-jz4780.c
@@ -156,7 +156,6 @@ struct jz4780_dma_dev {
};
struct jz4780_dma_filter_data {
- struct device_node *of_node;
uint32_t transfer_type;
int channel;
};
@@ -718,12 +717,13 @@ static irqreturn_t jz4780_dma_irq_handler(int irq, void *data)
{
struct jz4780_dma_dev *jzdma = data;
unsigned int nb_channels = jzdma->soc_data->nb_channels;
- uint32_t pending, dmac;
+ unsigned long pending;
+ uint32_t dmac;
int i;
pending = jz4780_dma_ctrl_readl(jzdma, JZ_DMA_REG_DIRQP);
- for_each_set_bit(i, (unsigned long *)&pending, nb_channels) {
+ for_each_set_bit(i, &pending, nb_channels) {
if (jz4780_dma_chan_irq(jzdma, &jzdma->chan[i]))
pending &= ~BIT(i);
}
@@ -771,8 +771,6 @@ static bool jz4780_dma_filter_fn(struct dma_chan *chan, void *param)
struct jz4780_dma_dev *jzdma = jz4780_dma_chan_parent(jzchan);
struct jz4780_dma_filter_data *data = param;
- if (jzdma->dma_device.dev->of_node != data->of_node)
- return false;
if (data->channel > -1) {
if (data->channel != jzchan->id)
@@ -796,7 +794,6 @@ static struct dma_chan *jz4780_of_dma_xlate(struct of_phandle_args *dma_spec,
if (dma_spec->args_count != 2)
return NULL;
- data.of_node = ofdma->of_node;
data.transfer_type = dma_spec->args[0];
data.channel = dma_spec->args[1];
@@ -821,7 +818,8 @@ static struct dma_chan *jz4780_of_dma_xlate(struct of_phandle_args *dma_spec,
return dma_get_slave_channel(
&jzdma->chan[data.channel].vchan.chan);
} else {
- return dma_request_channel(mask, jz4780_dma_filter_fn, &data);
+ return __dma_request_channel(&mask, jz4780_dma_filter_fn, &data,
+ ofdma->of_node);
}
}
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 58cbf9fd5a46..03ac4b96117c 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -61,7 +61,7 @@ static long dmaengine_ref_count;
/* --- sysfs implementation --- */
/**
- * dev_to_dma_chan - convert a device pointer to the its sysfs container object
+ * dev_to_dma_chan - convert a device pointer to its sysfs container object
* @dev - device node
*
* Must be called under dma_list_mutex
@@ -629,11 +629,13 @@ EXPORT_SYMBOL_GPL(dma_get_any_slave_channel);
* @mask: capabilities that the channel must satisfy
* @fn: optional callback to disposition available channels
* @fn_param: opaque parameter to pass to dma_filter_fn
+ * @np: device node to look for DMA channels
*
* Returns pointer to appropriate DMA channel on success or NULL.
*/
struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask,
- dma_filter_fn fn, void *fn_param)
+ dma_filter_fn fn, void *fn_param,
+ struct device_node *np)
{
struct dma_device *device, *_d;
struct dma_chan *chan = NULL;
@@ -641,6 +643,10 @@ struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask,
/* Find a channel */
mutex_lock(&dma_list_mutex);
list_for_each_entry_safe(device, _d, &dma_device_list, global_node) {
+ /* Finds a DMA controller with matching device node */
+ if (np && device->dev->of_node && np != device->dev->of_node)
+ continue;
+
chan = find_candidate(device, mask, fn, fn_param);
if (!IS_ERR(chan))
break;
@@ -699,7 +705,7 @@ struct dma_chan *dma_request_chan(struct device *dev, const char *name)
chan = acpi_dma_request_slave_chan_by_name(dev, name);
if (chan) {
- /* Valid channel found or requester need to be deferred */
+ /* Valid channel found or requester needs to be deferred */
if (!IS_ERR(chan) || PTR_ERR(chan) == -EPROBE_DEFER)
return chan;
}
@@ -757,7 +763,7 @@ struct dma_chan *dma_request_chan_by_mask(const dma_cap_mask_t *mask)
if (!mask)
return ERR_PTR(-ENODEV);
- chan = __dma_request_channel(mask, NULL, NULL);
+ chan = __dma_request_channel(mask, NULL, NULL, NULL);
if (!chan) {
mutex_lock(&dma_list_mutex);
if (list_empty(&dma_device_list))
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
index b96814a7dceb..3d22ae8dca72 100644
--- a/drivers/dma/dmatest.c
+++ b/drivers/dma/dmatest.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* DMA Engine test module
*
* Copyright (C) 2007 Atmel Corporation
* Copyright (C) 2013 Intel Corporation
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -65,7 +62,7 @@ MODULE_PARM_DESC(pq_sources,
static int timeout = 3000;
module_param(timeout, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(timeout, "Transfer Timeout in msec (default: 3000), "
- "Pass -1 for infinite timeout");
+ "Pass 0xFFFFFFFF (4294967295) for maximum timeout");
static bool noverify;
module_param(noverify, bool, S_IRUGO | S_IWUSR);
@@ -97,7 +94,7 @@ MODULE_PARM_DESC(transfer_size, "Optional custom transfer size in bytes (default
* @iterations: iterations before stopping test
* @xor_sources: number of xor source buffers
* @pq_sources: number of p+q source buffers
- * @timeout: transfer timeout in msec, -1 for infinite timeout
+ * @timeout: transfer timeout in msec, 0 - 0xFFFFFFFF (4294967295)
*/
struct dmatest_params {
unsigned int buf_size;
@@ -108,7 +105,7 @@ struct dmatest_params {
unsigned int iterations;
unsigned int xor_sources;
unsigned int pq_sources;
- int timeout;
+ unsigned int timeout;
bool noverify;
bool norandom;
int alignment;
diff --git a/drivers/dma/dw-edma/Kconfig b/drivers/dma/dw-edma/Kconfig
new file mode 100644
index 000000000000..7ff17b2db6a1
--- /dev/null
+++ b/drivers/dma/dw-edma/Kconfig
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config DW_EDMA
+ tristate "Synopsys DesignWare eDMA controller driver"
+ depends on PCI && PCI_MSI
+ select DMA_ENGINE
+ select DMA_VIRTUAL_CHANNELS
+ help
+ Support the Synopsys DesignWare eDMA controller, normally
+ implemented on endpoints SoCs.
+
+config DW_EDMA_PCIE
+ tristate "Synopsys DesignWare eDMA PCIe driver"
+ depends on PCI && PCI_MSI
+ select DW_EDMA
+ help
+ Provides a glue-logic between the Synopsys DesignWare
+ eDMA controller and an endpoint PCIe device. This also serves
+ as a reference design to whom desires to use this IP.
diff --git a/drivers/dma/dw-edma/Makefile b/drivers/dma/dw-edma/Makefile
new file mode 100644
index 000000000000..8d45c0d5689d
--- /dev/null
+++ b/drivers/dma/dw-edma/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_DW_EDMA) += dw-edma.o
+dw-edma-$(CONFIG_DEBUG_FS) := dw-edma-v0-debugfs.o
+dw-edma-objs := dw-edma-core.o \
+ dw-edma-v0-core.o $(dw-edma-y)
+obj-$(CONFIG_DW_EDMA_PCIE) += dw-edma-pcie.o
diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
new file mode 100644
index 000000000000..ff392c01bad1
--- /dev/null
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -0,0 +1,937 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.
+ * Synopsys DesignWare eDMA core driver
+ *
+ * Author: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/pm_runtime.h>
+#include <linux/dmaengine.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/dma/edma.h>
+#include <linux/pci.h>
+
+#include "dw-edma-core.h"
+#include "dw-edma-v0-core.h"
+#include "../dmaengine.h"
+#include "../virt-dma.h"
+
+static inline
+struct device *dchan2dev(struct dma_chan *dchan)
+{
+ return &dchan->dev->device;
+}
+
+static inline
+struct device *chan2dev(struct dw_edma_chan *chan)
+{
+ return &chan->vc.chan.dev->device;
+}
+
+static inline
+struct dw_edma_desc *vd2dw_edma_desc(struct virt_dma_desc *vd)
+{
+ return container_of(vd, struct dw_edma_desc, vd);
+}
+
+static struct dw_edma_burst *dw_edma_alloc_burst(struct dw_edma_chunk *chunk)
+{
+ struct dw_edma_burst *burst;
+
+ burst = kzalloc(sizeof(*burst), GFP_NOWAIT);
+ if (unlikely(!burst))
+ return NULL;
+
+ INIT_LIST_HEAD(&burst->list);
+ if (chunk->burst) {
+ /* Create and add new element into the linked list */
+ chunk->bursts_alloc++;
+ list_add_tail(&burst->list, &chunk->burst->list);
+ } else {
+ /* List head */
+ chunk->bursts_alloc = 0;
+ chunk->burst = burst;
+ }
+
+ return burst;
+}
+
+static struct dw_edma_chunk *dw_edma_alloc_chunk(struct dw_edma_desc *desc)
+{
+ struct dw_edma_chan *chan = desc->chan;
+ struct dw_edma *dw = chan->chip->dw;
+ struct dw_edma_chunk *chunk;
+
+ chunk = kzalloc(sizeof(*chunk), GFP_NOWAIT);
+ if (unlikely(!chunk))
+ return NULL;
+
+ INIT_LIST_HEAD(&chunk->list);
+ chunk->chan = chan;
+ /* Toggling change bit (CB) in each chunk, this is a mechanism to
+ * inform the eDMA HW block that this is a new linked list ready
+ * to be consumed.
+ * - Odd chunks originate CB equal to 0
+ * - Even chunks originate CB equal to 1
+ */
+ chunk->cb = !(desc->chunks_alloc % 2);
+ chunk->ll_region.paddr = dw->ll_region.paddr + chan->ll_off;
+ chunk->ll_region.vaddr = dw->ll_region.vaddr + chan->ll_off;
+
+ if (desc->chunk) {
+ /* Create and add new element into the linked list */
+ desc->chunks_alloc++;
+ list_add_tail(&chunk->list, &desc->chunk->list);
+ if (!dw_edma_alloc_burst(chunk)) {
+ kfree(chunk);
+ return NULL;
+ }
+ } else {
+ /* List head */
+ chunk->burst = NULL;
+ desc->chunks_alloc = 0;
+ desc->chunk = chunk;
+ }
+
+ return chunk;
+}
+
+static struct dw_edma_desc *dw_edma_alloc_desc(struct dw_edma_chan *chan)
+{
+ struct dw_edma_desc *desc;
+
+ desc = kzalloc(sizeof(*desc), GFP_NOWAIT);
+ if (unlikely(!desc))
+ return NULL;
+
+ desc->chan = chan;
+ if (!dw_edma_alloc_chunk(desc)) {
+ kfree(desc);
+ return NULL;
+ }
+
+ return desc;
+}
+
+static void dw_edma_free_burst(struct dw_edma_chunk *chunk)
+{
+ struct dw_edma_burst *child, *_next;
+
+ /* Remove all the list elements */
+ list_for_each_entry_safe(child, _next, &chunk->burst->list, list) {
+ list_del(&child->list);
+ kfree(child);
+ chunk->bursts_alloc--;
+ }
+
+ /* Remove the list head */
+ kfree(child);
+ chunk->burst = NULL;
+}
+
+static void dw_edma_free_chunk(struct dw_edma_desc *desc)
+{
+ struct dw_edma_chunk *child, *_next;
+
+ if (!desc->chunk)
+ return;
+
+ /* Remove all the list elements */
+ list_for_each_entry_safe(child, _next, &desc->chunk->list, list) {
+ dw_edma_free_burst(child);
+ list_del(&child->list);
+ kfree(child);
+ desc->chunks_alloc--;
+ }
+
+ /* Remove the list head */
+ kfree(child);
+ desc->chunk = NULL;
+}
+
+static void dw_edma_free_desc(struct dw_edma_desc *desc)
+{
+ dw_edma_free_chunk(desc);
+ kfree(desc);
+}
+
+static void vchan_free_desc(struct virt_dma_desc *vdesc)
+{
+ dw_edma_free_desc(vd2dw_edma_desc(vdesc));
+}
+
+static void dw_edma_start_transfer(struct dw_edma_chan *chan)
+{
+ struct dw_edma_chunk *child;
+ struct dw_edma_desc *desc;
+ struct virt_dma_desc *vd;
+
+ vd = vchan_next_desc(&chan->vc);
+ if (!vd)
+ return;
+
+ desc = vd2dw_edma_desc(vd);
+ if (!desc)
+ return;
+
+ child = list_first_entry_or_null(&desc->chunk->list,
+ struct dw_edma_chunk, list);
+ if (!child)
+ return;
+
+ dw_edma_v0_core_start(child, !desc->xfer_sz);
+ desc->xfer_sz += child->ll_region.sz;
+ dw_edma_free_burst(child);
+ list_del(&child->list);
+ kfree(child);
+ desc->chunks_alloc--;
+}
+
+static int dw_edma_device_config(struct dma_chan *dchan,
+ struct dma_slave_config *config)
+{
+ struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
+
+ memcpy(&chan->config, config, sizeof(*config));
+ chan->configured = true;
+
+ return 0;
+}
+
+static int dw_edma_device_pause(struct dma_chan *dchan)
+{
+ struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
+ int err = 0;
+
+ if (!chan->configured)
+ err = -EPERM;
+ else if (chan->status != EDMA_ST_BUSY)
+ err = -EPERM;
+ else if (chan->request != EDMA_REQ_NONE)
+ err = -EPERM;
+ else
+ chan->request = EDMA_REQ_PAUSE;
+
+ return err;
+}
+
+static int dw_edma_device_resume(struct dma_chan *dchan)
+{
+ struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
+ int err = 0;
+
+ if (!chan->configured) {
+ err = -EPERM;
+ } else if (chan->status != EDMA_ST_PAUSE) {
+ err = -EPERM;
+ } else if (chan->request != EDMA_REQ_NONE) {
+ err = -EPERM;
+ } else {
+ chan->status = EDMA_ST_BUSY;
+ dw_edma_start_transfer(chan);
+ }
+
+ return err;
+}
+
+static int dw_edma_device_terminate_all(struct dma_chan *dchan)
+{
+ struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
+ int err = 0;
+ LIST_HEAD(head);
+
+ if (!chan->configured) {
+ /* Do nothing */
+ } else if (chan->status == EDMA_ST_PAUSE) {
+ chan->status = EDMA_ST_IDLE;
+ chan->configured = false;
+ } else if (chan->status == EDMA_ST_IDLE) {
+ chan->configured = false;
+ } else if (dw_edma_v0_core_ch_status(chan) == DMA_COMPLETE) {
+ /*
+ * The channel is in a false BUSY state, probably didn't
+ * receive or lost an interrupt
+ */
+ chan->status = EDMA_ST_IDLE;
+ chan->configured = false;
+ } else if (chan->request > EDMA_REQ_PAUSE) {
+ err = -EPERM;
+ } else {
+ chan->request = EDMA_REQ_STOP;
+ }
+
+ return err;
+}
+
+static void dw_edma_device_issue_pending(struct dma_chan *dchan)
+{
+ struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
+ unsigned long flags;
+
+ spin_lock_irqsave(&chan->vc.lock, flags);
+ if (chan->configured && chan->request == EDMA_REQ_NONE &&
+ chan->status == EDMA_ST_IDLE && vchan_issue_pending(&chan->vc)) {
+ chan->status = EDMA_ST_BUSY;
+ dw_edma_start_transfer(chan);
+ }
+ spin_unlock_irqrestore(&chan->vc.lock, flags);
+}
+
+static enum dma_status
+dw_edma_device_tx_status(struct dma_chan *dchan, dma_cookie_t cookie,
+ struct dma_tx_state *txstate)
+{
+ struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
+ struct dw_edma_desc *desc;
+ struct virt_dma_desc *vd;
+ unsigned long flags;
+ enum dma_status ret;
+ u32 residue = 0;
+
+ ret = dma_cookie_status(dchan, cookie, txstate);
+ if (ret == DMA_COMPLETE)
+ return ret;
+
+ if (ret == DMA_IN_PROGRESS && chan->status == EDMA_ST_PAUSE)
+ ret = DMA_PAUSED;
+
+ if (!txstate)
+ goto ret_residue;
+
+ spin_lock_irqsave(&chan->vc.lock, flags);
+ vd = vchan_find_desc(&chan->vc, cookie);
+ if (vd) {
+ desc = vd2dw_edma_desc(vd);
+ if (desc)
+ residue = desc->alloc_sz - desc->xfer_sz;
+ }
+ spin_unlock_irqrestore(&chan->vc.lock, flags);
+
+ret_residue:
+ dma_set_residue(txstate, residue);
+
+ return ret;
+}
+
+static struct dma_async_tx_descriptor *
+dw_edma_device_transfer(struct dw_edma_transfer *xfer)
+{
+ struct dw_edma_chan *chan = dchan2dw_edma_chan(xfer->dchan);
+ enum dma_transfer_direction direction = xfer->direction;
+ phys_addr_t src_addr, dst_addr;
+ struct scatterlist *sg = NULL;
+ struct dw_edma_chunk *chunk;
+ struct dw_edma_burst *burst;
+ struct dw_edma_desc *desc;
+ u32 cnt;
+ int i;
+
+ if ((direction == DMA_MEM_TO_DEV && chan->dir == EDMA_DIR_WRITE) ||
+ (direction == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ))
+ return NULL;
+
+ if (xfer->cyclic) {
+ if (!xfer->xfer.cyclic.len || !xfer->xfer.cyclic.cnt)
+ return NULL;
+ } else {
+ if (xfer->xfer.sg.len < 1)
+ return NULL;
+ }
+
+ if (!chan->configured)
+ return NULL;
+
+ desc = dw_edma_alloc_desc(chan);
+ if (unlikely(!desc))
+ goto err_alloc;
+
+ chunk = dw_edma_alloc_chunk(desc);
+ if (unlikely(!chunk))
+ goto err_alloc;
+
+ src_addr = chan->config.src_addr;
+ dst_addr = chan->config.dst_addr;
+
+ if (xfer->cyclic) {
+ cnt = xfer->xfer.cyclic.cnt;
+ } else {
+ cnt = xfer->xfer.sg.len;
+ sg = xfer->xfer.sg.sgl;
+ }
+
+ for (i = 0; i < cnt; i++) {
+ if (!xfer->cyclic && !sg)
+ break;
+
+ if (chunk->bursts_alloc == chan->ll_max) {
+ chunk = dw_edma_alloc_chunk(desc);
+ if (unlikely(!chunk))
+ goto err_alloc;
+ }
+
+ burst = dw_edma_alloc_burst(chunk);
+ if (unlikely(!burst))
+ goto err_alloc;
+
+ if (xfer->cyclic)
+ burst->sz = xfer->xfer.cyclic.len;
+ else
+ burst->sz = sg_dma_len(sg);
+
+ chunk->ll_region.sz += burst->sz;
+ desc->alloc_sz += burst->sz;
+
+ if (direction == DMA_DEV_TO_MEM) {
+ burst->sar = src_addr;
+ if (xfer->cyclic) {
+ burst->dar = xfer->xfer.cyclic.paddr;
+ } else {
+ burst->dar = sg_dma_address(sg);
+ /* Unlike the typical assumption by other
+ * drivers/IPs the peripheral memory isn't
+ * a FIFO memory, in this case, it's a
+ * linear memory and that why the source
+ * and destination addresses are increased
+ * by the same portion (data length)
+ */
+ src_addr += sg_dma_len(sg);
+ }
+ } else {
+ burst->dar = dst_addr;
+ if (xfer->cyclic) {
+ burst->sar = xfer->xfer.cyclic.paddr;
+ } else {
+ burst->sar = sg_dma_address(sg);
+ /* Unlike the typical assumption by other
+ * drivers/IPs the peripheral memory isn't
+ * a FIFO memory, in this case, it's a
+ * linear memory and that why the source
+ * and destination addresses are increased
+ * by the same portion (data length)
+ */
+ dst_addr += sg_dma_len(sg);
+ }
+ }
+
+ if (!xfer->cyclic)
+ sg = sg_next(sg);
+ }
+
+ return vchan_tx_prep(&chan->vc, &desc->vd, xfer->flags);
+
+err_alloc:
+ if (desc)
+ dw_edma_free_desc(desc);
+
+ return NULL;
+}
+
+static struct dma_async_tx_descriptor *
+dw_edma_device_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,
+ unsigned int len,
+ enum dma_transfer_direction direction,
+ unsigned long flags, void *context)
+{
+ struct dw_edma_transfer xfer;
+
+ xfer.dchan = dchan;
+ xfer.direction = direction;
+ xfer.xfer.sg.sgl = sgl;
+ xfer.xfer.sg.len = len;
+ xfer.flags = flags;
+ xfer.cyclic = false;
+
+ return dw_edma_device_transfer(&xfer);
+}
+
+static struct dma_async_tx_descriptor *
+dw_edma_device_prep_dma_cyclic(struct dma_chan *dchan, dma_addr_t paddr,
+ size_t len, size_t count,
+ enum dma_transfer_direction direction,
+ unsigned long flags)
+{
+ struct dw_edma_transfer xfer;
+
+ xfer.dchan = dchan;
+ xfer.direction = direction;
+ xfer.xfer.cyclic.paddr = paddr;
+ xfer.xfer.cyclic.len = len;
+ xfer.xfer.cyclic.cnt = count;
+ xfer.flags = flags;
+ xfer.cyclic = true;
+
+ return dw_edma_device_transfer(&xfer);
+}
+
+static void dw_edma_done_interrupt(struct dw_edma_chan *chan)
+{
+ struct dw_edma_desc *desc;
+ struct virt_dma_desc *vd;
+ unsigned long flags;
+
+ dw_edma_v0_core_clear_done_int(chan);
+
+ spin_lock_irqsave(&chan->vc.lock, flags);
+ vd = vchan_next_desc(&chan->vc);
+ if (vd) {
+ switch (chan->request) {
+ case EDMA_REQ_NONE:
+ desc = vd2dw_edma_desc(vd);
+ if (desc->chunks_alloc) {
+ chan->status = EDMA_ST_BUSY;
+ dw_edma_start_transfer(chan);
+ } else {
+ list_del(&vd->node);
+ vchan_cookie_complete(vd);
+ chan->status = EDMA_ST_IDLE;
+ }
+ break;
+
+ case EDMA_REQ_STOP:
+ list_del(&vd->node);
+ vchan_cookie_complete(vd);
+ chan->request = EDMA_REQ_NONE;
+ chan->status = EDMA_ST_IDLE;
+ break;
+
+ case EDMA_REQ_PAUSE:
+ chan->request = EDMA_REQ_NONE;
+ chan->status = EDMA_ST_PAUSE;
+ break;
+
+ default:
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&chan->vc.lock, flags);
+}
+
+static void dw_edma_abort_interrupt(struct dw_edma_chan *chan)
+{
+ struct virt_dma_desc *vd;
+ unsigned long flags;
+
+ dw_edma_v0_core_clear_abort_int(chan);
+
+ spin_lock_irqsave(&chan->vc.lock, flags);
+ vd = vchan_next_desc(&chan->vc);
+ if (vd) {
+ list_del(&vd->node);
+ vchan_cookie_complete(vd);
+ }
+ spin_unlock_irqrestore(&chan->vc.lock, flags);
+ chan->request = EDMA_REQ_NONE;
+ chan->status = EDMA_ST_IDLE;
+}
+
+static irqreturn_t dw_edma_interrupt(int irq, void *data, bool write)
+{
+ struct dw_edma_irq *dw_irq = data;
+ struct dw_edma *dw = dw_irq->dw;
+ unsigned long total, pos, val;
+ unsigned long off;
+ u32 mask;
+
+ if (write) {
+ total = dw->wr_ch_cnt;
+ off = 0;
+ mask = dw_irq->wr_mask;
+ } else {
+ total = dw->rd_ch_cnt;
+ off = dw->wr_ch_cnt;
+ mask = dw_irq->rd_mask;
+ }
+
+ val = dw_edma_v0_core_status_done_int(dw, write ?
+ EDMA_DIR_WRITE :
+ EDMA_DIR_READ);
+ val &= mask;
+ for_each_set_bit(pos, &val, total) {
+ struct dw_edma_chan *chan = &dw->chan[pos + off];
+
+ dw_edma_done_interrupt(chan);
+ }
+
+ val = dw_edma_v0_core_status_abort_int(dw, write ?
+ EDMA_DIR_WRITE :
+ EDMA_DIR_READ);
+ val &= mask;
+ for_each_set_bit(pos, &val, total) {
+ struct dw_edma_chan *chan = &dw->chan[pos + off];
+
+ dw_edma_abort_interrupt(chan);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static inline irqreturn_t dw_edma_interrupt_write(int irq, void *data)
+{
+ return dw_edma_interrupt(irq, data, true);
+}
+
+static inline irqreturn_t dw_edma_interrupt_read(int irq, void *data)
+{
+ return dw_edma_interrupt(irq, data, false);
+}
+
+static irqreturn_t dw_edma_interrupt_common(int irq, void *data)
+{
+ dw_edma_interrupt(irq, data, true);
+ dw_edma_interrupt(irq, data, false);
+
+ return IRQ_HANDLED;
+}
+
+static int dw_edma_alloc_chan_resources(struct dma_chan *dchan)
+{
+ struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
+
+ if (chan->status != EDMA_ST_IDLE)
+ return -EBUSY;
+
+ pm_runtime_get(chan->chip->dev);
+
+ return 0;
+}
+
+static void dw_edma_free_chan_resources(struct dma_chan *dchan)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(5000);
+ struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
+ int ret;
+
+ while (time_before(jiffies, timeout)) {
+ ret = dw_edma_device_terminate_all(dchan);
+ if (!ret)
+ break;
+
+ if (time_after_eq(jiffies, timeout))
+ return;
+
+ cpu_relax();
+ }
+
+ pm_runtime_put(chan->chip->dev);
+}
+
+static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
+ u32 wr_alloc, u32 rd_alloc)
+{
+ struct dw_edma_region *dt_region;
+ struct device *dev = chip->dev;
+ struct dw_edma *dw = chip->dw;
+ struct dw_edma_chan *chan;
+ size_t ll_chunk, dt_chunk;
+ struct dw_edma_irq *irq;
+ struct dma_device *dma;
+ u32 i, j, cnt, ch_cnt;
+ u32 alloc, off_alloc;
+ int err = 0;
+ u32 pos;
+
+ ch_cnt = dw->wr_ch_cnt + dw->rd_ch_cnt;
+ ll_chunk = dw->ll_region.sz;
+ dt_chunk = dw->dt_region.sz;
+
+ /* Calculate linked list chunk for each channel */
+ ll_chunk /= roundup_pow_of_two(ch_cnt);
+
+ /* Calculate linked list chunk for each channel */
+ dt_chunk /= roundup_pow_of_two(ch_cnt);
+
+ if (write) {
+ i = 0;
+ cnt = dw->wr_ch_cnt;
+ dma = &dw->wr_edma;
+ alloc = wr_alloc;
+ off_alloc = 0;
+ } else {
+ i = dw->wr_ch_cnt;
+ cnt = dw->rd_ch_cnt;
+ dma = &dw->rd_edma;
+ alloc = rd_alloc;
+ off_alloc = wr_alloc;
+ }
+
+ INIT_LIST_HEAD(&dma->channels);
+ for (j = 0; (alloc || dw->nr_irqs == 1) && j < cnt; j++, i++) {
+ chan = &dw->chan[i];
+
+ dt_region = devm_kzalloc(dev, sizeof(*dt_region), GFP_KERNEL);
+ if (!dt_region)
+ return -ENOMEM;
+
+ chan->vc.chan.private = dt_region;
+
+ chan->chip = chip;
+ chan->id = j;
+ chan->dir = write ? EDMA_DIR_WRITE : EDMA_DIR_READ;
+ chan->configured = false;
+ chan->request = EDMA_REQ_NONE;
+ chan->status = EDMA_ST_IDLE;
+
+ chan->ll_off = (ll_chunk * i);
+ chan->ll_max = (ll_chunk / EDMA_LL_SZ) - 1;
+
+ chan->dt_off = (dt_chunk * i);
+
+ dev_vdbg(dev, "L. List:\tChannel %s[%u] off=0x%.8lx, max_cnt=%u\n",
+ write ? "write" : "read", j,
+ chan->ll_off, chan->ll_max);
+
+ if (dw->nr_irqs == 1)
+ pos = 0;
+ else
+ pos = off_alloc + (j % alloc);
+
+ irq = &dw->irq[pos];
+
+ if (write)
+ irq->wr_mask |= BIT(j);
+ else
+ irq->rd_mask |= BIT(j);
+
+ irq->dw = dw;
+ memcpy(&chan->msi, &irq->msi, sizeof(chan->msi));
+
+ dev_vdbg(dev, "MSI:\t\tChannel %s[%u] addr=0x%.8x%.8x, data=0x%.8x\n",
+ write ? "write" : "read", j,
+ chan->msi.address_hi, chan->msi.address_lo,
+ chan->msi.data);
+
+ chan->vc.desc_free = vchan_free_desc;
+ vchan_init(&chan->vc, dma);
+
+ dt_region->paddr = dw->dt_region.paddr + chan->dt_off;
+ dt_region->vaddr = dw->dt_region.vaddr + chan->dt_off;
+ dt_region->sz = dt_chunk;
+
+ dev_vdbg(dev, "Data:\tChannel %s[%u] off=0x%.8lx\n",
+ write ? "write" : "read", j, chan->dt_off);
+
+ dw_edma_v0_core_device_config(chan);
+ }
+
+ /* Set DMA channel capabilities */
+ dma_cap_zero(dma->cap_mask);
+ dma_cap_set(DMA_SLAVE, dma->cap_mask);
+ dma_cap_set(DMA_CYCLIC, dma->cap_mask);
+ dma_cap_set(DMA_PRIVATE, dma->cap_mask);
+ dma->directions = BIT(write ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV);
+ dma->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
+ dma->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
+ dma->residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
+ dma->chancnt = cnt;
+
+ /* Set DMA channel callbacks */
+ dma->dev = chip->dev;
+ dma->device_alloc_chan_resources = dw_edma_alloc_chan_resources;
+ dma->device_free_chan_resources = dw_edma_free_chan_resources;
+ dma->device_config = dw_edma_device_config;
+ dma->device_pause = dw_edma_device_pause;
+ dma->device_resume = dw_edma_device_resume;
+ dma->device_terminate_all = dw_edma_device_terminate_all;
+ dma->device_issue_pending = dw_edma_device_issue_pending;
+ dma->device_tx_status = dw_edma_device_tx_status;
+ dma->device_prep_slave_sg = dw_edma_device_prep_slave_sg;
+ dma->device_prep_dma_cyclic = dw_edma_device_prep_dma_cyclic;
+
+ dma_set_max_seg_size(dma->dev, U32_MAX);
+
+ /* Register DMA device */
+ err = dma_async_device_register(dma);
+
+ return err;
+}
+
+static inline void dw_edma_dec_irq_alloc(int *nr_irqs, u32 *alloc, u16 cnt)
+{
+ if (*nr_irqs && *alloc < cnt) {
+ (*alloc)++;
+ (*nr_irqs)--;
+ }
+}
+
+static inline void dw_edma_add_irq_mask(u32 *mask, u32 alloc, u16 cnt)
+{
+ while (*mask * alloc < cnt)
+ (*mask)++;
+}
+
+static int dw_edma_irq_request(struct dw_edma_chip *chip,
+ u32 *wr_alloc, u32 *rd_alloc)
+{
+ struct device *dev = chip->dev;
+ struct dw_edma *dw = chip->dw;
+ u32 wr_mask = 1;
+ u32 rd_mask = 1;
+ int i, err = 0;
+ u32 ch_cnt;
+
+ ch_cnt = dw->wr_ch_cnt + dw->rd_ch_cnt;
+
+ if (dw->nr_irqs < 1)
+ return -EINVAL;
+
+ if (dw->nr_irqs == 1) {
+ /* Common IRQ shared among all channels */
+ err = request_irq(pci_irq_vector(to_pci_dev(dev), 0),
+ dw_edma_interrupt_common,
+ IRQF_SHARED, dw->name, &dw->irq[0]);
+ if (err) {
+ dw->nr_irqs = 0;
+ return err;
+ }
+
+ get_cached_msi_msg(pci_irq_vector(to_pci_dev(dev), 0),
+ &dw->irq[0].msi);
+ } else {
+ /* Distribute IRQs equally among all channels */
+ int tmp = dw->nr_irqs;
+
+ while (tmp && (*wr_alloc + *rd_alloc) < ch_cnt) {
+ dw_edma_dec_irq_alloc(&tmp, wr_alloc, dw->wr_ch_cnt);
+ dw_edma_dec_irq_alloc(&tmp, rd_alloc, dw->rd_ch_cnt);
+ }
+
+ dw_edma_add_irq_mask(&wr_mask, *wr_alloc, dw->wr_ch_cnt);
+ dw_edma_add_irq_mask(&rd_mask, *rd_alloc, dw->rd_ch_cnt);
+
+ for (i = 0; i < (*wr_alloc + *rd_alloc); i++) {
+ err = request_irq(pci_irq_vector(to_pci_dev(dev), i),
+ i < *wr_alloc ?
+ dw_edma_interrupt_write :
+ dw_edma_interrupt_read,
+ IRQF_SHARED, dw->name,
+ &dw->irq[i]);
+ if (err) {
+ dw->nr_irqs = i;
+ return err;
+ }
+
+ get_cached_msi_msg(pci_irq_vector(to_pci_dev(dev), i),
+ &dw->irq[i].msi);
+ }
+
+ dw->nr_irqs = i;
+ }
+
+ return err;
+}
+
+int dw_edma_probe(struct dw_edma_chip *chip)
+{
+ struct device *dev = chip->dev;
+ struct dw_edma *dw = chip->dw;
+ u32 wr_alloc = 0;
+ u32 rd_alloc = 0;
+ int i, err;
+
+ raw_spin_lock_init(&dw->lock);
+
+ /* Find out how many write channels are supported by hardware */
+ dw->wr_ch_cnt = dw_edma_v0_core_ch_count(dw, EDMA_DIR_WRITE);
+ if (!dw->wr_ch_cnt)
+ return -EINVAL;
+
+ /* Find out how many read channels are supported by hardware */
+ dw->rd_ch_cnt = dw_edma_v0_core_ch_count(dw, EDMA_DIR_READ);
+ if (!dw->rd_ch_cnt)
+ return -EINVAL;
+
+ dev_vdbg(dev, "Channels:\twrite=%d, read=%d\n",
+ dw->wr_ch_cnt, dw->rd_ch_cnt);
+
+ /* Allocate channels */
+ dw->chan = devm_kcalloc(dev, dw->wr_ch_cnt + dw->rd_ch_cnt,
+ sizeof(*dw->chan), GFP_KERNEL);
+ if (!dw->chan)
+ return -ENOMEM;
+
+ snprintf(dw->name, sizeof(dw->name), "dw-edma-core:%d", chip->id);
+
+ /* Disable eDMA, only to establish the ideal initial conditions */
+ dw_edma_v0_core_off(dw);
+
+ /* Request IRQs */
+ err = dw_edma_irq_request(chip, &wr_alloc, &rd_alloc);
+ if (err)
+ return err;
+
+ /* Setup write channels */
+ err = dw_edma_channel_setup(chip, true, wr_alloc, rd_alloc);
+ if (err)
+ goto err_irq_free;
+
+ /* Setup read channels */
+ err = dw_edma_channel_setup(chip, false, wr_alloc, rd_alloc);
+ if (err)
+ goto err_irq_free;
+
+ /* Power management */
+ pm_runtime_enable(dev);
+
+ /* Turn debugfs on */
+ dw_edma_v0_core_debugfs_on(chip);
+
+ return 0;
+
+err_irq_free:
+ for (i = (dw->nr_irqs - 1); i >= 0; i--)
+ free_irq(pci_irq_vector(to_pci_dev(dev), i), &dw->irq[i]);
+
+ dw->nr_irqs = 0;
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(dw_edma_probe);
+
+int dw_edma_remove(struct dw_edma_chip *chip)
+{
+ struct dw_edma_chan *chan, *_chan;
+ struct device *dev = chip->dev;
+ struct dw_edma *dw = chip->dw;
+ int i;
+
+ /* Disable eDMA */
+ dw_edma_v0_core_off(dw);
+
+ /* Free irqs */
+ for (i = (dw->nr_irqs - 1); i >= 0; i--)
+ free_irq(pci_irq_vector(to_pci_dev(dev), i), &dw->irq[i]);
+
+ /* Power management */
+ pm_runtime_disable(dev);
+
+ list_for_each_entry_safe(chan, _chan, &dw->wr_edma.channels,
+ vc.chan.device_node) {
+ list_del(&chan->vc.chan.device_node);
+ tasklet_kill(&chan->vc.task);
+ }
+
+ list_for_each_entry_safe(chan, _chan, &dw->rd_edma.channels,
+ vc.chan.device_node) {
+ list_del(&chan->vc.chan.device_node);
+ tasklet_kill(&chan->vc.task);
+ }
+
+ /* Deregister eDMA device */
+ dma_async_device_unregister(&dw->wr_edma);
+ dma_async_device_unregister(&dw->rd_edma);
+
+ /* Turn debugfs off */
+ dw_edma_v0_core_debugfs_off();
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dw_edma_remove);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Synopsys DesignWare eDMA controller core driver");
+MODULE_AUTHOR("Gustavo Pimentel <gustavo.pimentel@synopsys.com>");
diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
new file mode 100644
index 000000000000..b6cc90cbc9dc
--- /dev/null
+++ b/drivers/dma/dw-edma/dw-edma-core.h
@@ -0,0 +1,165 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.
+ * Synopsys DesignWare eDMA core driver
+ *
+ * Author: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+ */
+
+#ifndef _DW_EDMA_CORE_H
+#define _DW_EDMA_CORE_H
+
+#include <linux/msi.h>
+#include <linux/dma/edma.h>
+
+#include "../virt-dma.h"
+
+#define EDMA_LL_SZ 24
+
+enum dw_edma_dir {
+ EDMA_DIR_WRITE = 0,
+ EDMA_DIR_READ
+};
+
+enum dw_edma_mode {
+ EDMA_MODE_LEGACY = 0,
+ EDMA_MODE_UNROLL
+};
+
+enum dw_edma_request {
+ EDMA_REQ_NONE = 0,
+ EDMA_REQ_STOP,
+ EDMA_REQ_PAUSE
+};
+
+enum dw_edma_status {
+ EDMA_ST_IDLE = 0,
+ EDMA_ST_PAUSE,
+ EDMA_ST_BUSY
+};
+
+struct dw_edma_chan;
+struct dw_edma_chunk;
+
+struct dw_edma_burst {
+ struct list_head list;
+ u64 sar;
+ u64 dar;
+ u32 sz;
+};
+
+struct dw_edma_region {
+ phys_addr_t paddr;
+ dma_addr_t vaddr;
+ size_t sz;
+};
+
+struct dw_edma_chunk {
+ struct list_head list;
+ struct dw_edma_chan *chan;
+ struct dw_edma_burst *burst;
+
+ u32 bursts_alloc;
+
+ u8 cb;
+ struct dw_edma_region ll_region; /* Linked list */
+};
+
+struct dw_edma_desc {
+ struct virt_dma_desc vd;
+ struct dw_edma_chan *chan;
+ struct dw_edma_chunk *chunk;
+
+ u32 chunks_alloc;
+
+ u32 alloc_sz;
+ u32 xfer_sz;
+};
+
+struct dw_edma_chan {
+ struct virt_dma_chan vc;
+ struct dw_edma_chip *chip;
+ int id;
+ enum dw_edma_dir dir;
+
+ off_t ll_off;
+ u32 ll_max;
+
+ off_t dt_off;
+
+ struct msi_msg msi;
+
+ enum dw_edma_request request;
+ enum dw_edma_status status;
+ u8 configured;
+
+ struct dma_slave_config config;
+};
+
+struct dw_edma_irq {
+ struct msi_msg msi;
+ u32 wr_mask;
+ u32 rd_mask;
+ struct dw_edma *dw;
+};
+
+struct dw_edma {
+ char name[20];
+
+ struct dma_device wr_edma;
+ u16 wr_ch_cnt;
+
+ struct dma_device rd_edma;
+ u16 rd_ch_cnt;
+
+ struct dw_edma_region rg_region; /* Registers */
+ struct dw_edma_region ll_region; /* Linked list */
+ struct dw_edma_region dt_region; /* Data */
+
+ struct dw_edma_irq *irq;
+ int nr_irqs;
+
+ u32 version;
+ enum dw_edma_mode mode;
+
+ struct dw_edma_chan *chan;
+ const struct dw_edma_core_ops *ops;
+
+ raw_spinlock_t lock; /* Only for legacy */
+};
+
+struct dw_edma_sg {
+ struct scatterlist *sgl;
+ unsigned int len;
+};
+
+struct dw_edma_cyclic {
+ dma_addr_t paddr;
+ size_t len;
+ size_t cnt;
+};
+
+struct dw_edma_transfer {
+ struct dma_chan *dchan;
+ union dw_edma_xfer {
+ struct dw_edma_sg sg;
+ struct dw_edma_cyclic cyclic;
+ } xfer;
+ enum dma_transfer_direction direction;
+ unsigned long flags;
+ bool cyclic;
+};
+
+static inline
+struct dw_edma_chan *vc2dw_edma_chan(struct virt_dma_chan *vc)
+{
+ return container_of(vc, struct dw_edma_chan, vc);
+}
+
+static inline
+struct dw_edma_chan *dchan2dw_edma_chan(struct dma_chan *dchan)
+{
+ return vc2dw_edma_chan(to_virt_chan(dchan));
+}
+
+#endif /* _DW_EDMA_CORE_H */
diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
new file mode 100644
index 000000000000..4c96e1c948f2
--- /dev/null
+++ b/drivers/dma/dw-edma/dw-edma-pcie.c
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.
+ * Synopsys DesignWare eDMA PCIe driver
+ *
+ * Author: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/device.h>
+#include <linux/dma/edma.h>
+#include <linux/pci-epf.h>
+#include <linux/msi.h>
+
+#include "dw-edma-core.h"
+
+struct dw_edma_pcie_data {
+ /* eDMA registers location */
+ enum pci_barno rg_bar;
+ off_t rg_off;
+ size_t rg_sz;
+ /* eDMA memory linked list location */
+ enum pci_barno ll_bar;
+ off_t ll_off;
+ size_t ll_sz;
+ /* eDMA memory data location */
+ enum pci_barno dt_bar;
+ off_t dt_off;
+ size_t dt_sz;
+ /* Other */
+ u32 version;
+ enum dw_edma_mode mode;
+ u8 irqs;
+};
+
+static const struct dw_edma_pcie_data snps_edda_data = {
+ /* eDMA registers location */
+ .rg_bar = BAR_0,
+ .rg_off = 0x00001000, /* 4 Kbytes */
+ .rg_sz = 0x00002000, /* 8 Kbytes */
+ /* eDMA memory linked list location */
+ .ll_bar = BAR_2,
+ .ll_off = 0x00000000, /* 0 Kbytes */
+ .ll_sz = 0x00800000, /* 8 Mbytes */
+ /* eDMA memory data location */
+ .dt_bar = BAR_2,
+ .dt_off = 0x00800000, /* 8 Mbytes */
+ .dt_sz = 0x03800000, /* 56 Mbytes */
+ /* Other */
+ .version = 0,
+ .mode = EDMA_MODE_UNROLL,
+ .irqs = 1,
+};
+
+static int dw_edma_pcie_probe(struct pci_dev *pdev,
+ const struct pci_device_id *pid)
+{
+ const struct dw_edma_pcie_data *pdata = (void *)pid->driver_data;
+ struct device *dev = &pdev->dev;
+ struct dw_edma_chip *chip;
+ int err, nr_irqs;
+ struct dw_edma *dw;
+
+ /* Enable PCI device */
+ err = pcim_enable_device(pdev);
+ if (err) {
+ pci_err(pdev, "enabling device failed\n");
+ return err;
+ }
+
+ /* Mapping PCI BAR regions */
+ err = pcim_iomap_regions(pdev, BIT(pdata->rg_bar) |
+ BIT(pdata->ll_bar) |
+ BIT(pdata->dt_bar),
+ pci_name(pdev));
+ if (err) {
+ pci_err(pdev, "eDMA BAR I/O remapping failed\n");
+ return err;
+ }
+
+ pci_set_master(pdev);
+
+ /* DMA configuration */
+ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+ if (!err) {
+ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+ if (err) {
+ pci_err(pdev, "consistent DMA mask 64 set failed\n");
+ return err;
+ }
+ } else {
+ pci_err(pdev, "DMA mask 64 set failed\n");
+
+ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (err) {
+ pci_err(pdev, "DMA mask 32 set failed\n");
+ return err;
+ }
+
+ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (err) {
+ pci_err(pdev, "consistent DMA mask 32 set failed\n");
+ return err;
+ }
+ }
+
+ /* Data structure allocation */
+ chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ dw = devm_kzalloc(dev, sizeof(*dw), GFP_KERNEL);
+ if (!dw)
+ return -ENOMEM;
+
+ /* IRQs allocation */
+ nr_irqs = pci_alloc_irq_vectors(pdev, 1, pdata->irqs,
+ PCI_IRQ_MSI | PCI_IRQ_MSIX);
+ if (nr_irqs < 1) {
+ pci_err(pdev, "fail to alloc IRQ vector (number of IRQs=%u)\n",
+ nr_irqs);
+ return -EPERM;
+ }
+
+ /* Data structure initialization */
+ chip->dw = dw;
+ chip->dev = dev;
+ chip->id = pdev->devfn;
+ chip->irq = pdev->irq;
+
+ dw->rg_region.vaddr = (dma_addr_t)pcim_iomap_table(pdev)[pdata->rg_bar];
+ dw->rg_region.vaddr += pdata->rg_off;
+ dw->rg_region.paddr = pdev->resource[pdata->rg_bar].start;
+ dw->rg_region.paddr += pdata->rg_off;
+ dw->rg_region.sz = pdata->rg_sz;
+
+ dw->ll_region.vaddr = (dma_addr_t)pcim_iomap_table(pdev)[pdata->ll_bar];
+ dw->ll_region.vaddr += pdata->ll_off;
+ dw->ll_region.paddr = pdev->resource[pdata->ll_bar].start;
+ dw->ll_region.paddr += pdata->ll_off;
+ dw->ll_region.sz = pdata->ll_sz;
+
+ dw->dt_region.vaddr = (dma_addr_t)pcim_iomap_table(pdev)[pdata->dt_bar];
+ dw->dt_region.vaddr += pdata->dt_off;
+ dw->dt_region.paddr = pdev->resource[pdata->dt_bar].start;
+ dw->dt_region.paddr += pdata->dt_off;
+ dw->dt_region.sz = pdata->dt_sz;
+
+ dw->version = pdata->version;
+ dw->mode = pdata->mode;
+ dw->nr_irqs = nr_irqs;
+
+ /* Debug info */
+ pci_dbg(pdev, "Version:\t%u\n", dw->version);
+
+ pci_dbg(pdev, "Mode:\t%s\n",
+ dw->mode == EDMA_MODE_LEGACY ? "Legacy" : "Unroll");
+
+ pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%pa, p=%pa)\n",
+ pdata->rg_bar, pdata->rg_off, pdata->rg_sz,
+ &dw->rg_region.vaddr, &dw->rg_region.paddr);
+
+ pci_dbg(pdev, "L. List:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%pa, p=%pa)\n",
+ pdata->ll_bar, pdata->ll_off, pdata->ll_sz,
+ &dw->ll_region.vaddr, &dw->ll_region.paddr);
+
+ pci_dbg(pdev, "Data:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%pa, p=%pa)\n",
+ pdata->dt_bar, pdata->dt_off, pdata->dt_sz,
+ &dw->dt_region.vaddr, &dw->dt_region.paddr);
+
+ pci_dbg(pdev, "Nr. IRQs:\t%u\n", dw->nr_irqs);
+
+ /* Validating if PCI interrupts were enabled */
+ if (!pci_dev_msi_enabled(pdev)) {
+ pci_err(pdev, "enable interrupt failed\n");
+ return -EPERM;
+ }
+
+ dw->irq = devm_kcalloc(dev, nr_irqs, sizeof(*dw->irq), GFP_KERNEL);
+ if (!dw->irq)
+ return -ENOMEM;
+
+ /* Starting eDMA driver */
+ err = dw_edma_probe(chip);
+ if (err) {
+ pci_err(pdev, "eDMA probe failed\n");
+ return err;
+ }
+
+ /* Saving data structure reference */
+ pci_set_drvdata(pdev, chip);
+
+ return 0;
+}
+
+static void dw_edma_pcie_remove(struct pci_dev *pdev)
+{
+ struct dw_edma_chip *chip = pci_get_drvdata(pdev);
+ int err;
+
+ /* Stopping eDMA driver */
+ err = dw_edma_remove(chip);
+ if (err)
+ pci_warn(pdev, "can't remove device properly: %d\n", err);
+
+ /* Freeing IRQs */
+ pci_free_irq_vectors(pdev);
+}
+
+static const struct pci_device_id dw_edma_pcie_id_table[] = {
+ { PCI_DEVICE_DATA(SYNOPSYS, EDDA, &snps_edda_data) },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, dw_edma_pcie_id_table);
+
+static struct pci_driver dw_edma_pcie_driver = {
+ .name = "dw-edma-pcie",
+ .id_table = dw_edma_pcie_id_table,
+ .probe = dw_edma_pcie_probe,
+ .remove = dw_edma_pcie_remove,
+};
+
+module_pci_driver(dw_edma_pcie_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Synopsys DesignWare eDMA PCIe driver");
+MODULE_AUTHOR("Gustavo Pimentel <gustavo.pimentel@synopsys.com>");
diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
new file mode 100644
index 000000000000..8a3180ed49a6
--- /dev/null
+++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
@@ -0,0 +1,354 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.
+ * Synopsys DesignWare eDMA v0 core
+ *
+ * Author: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+ */
+
+#include <linux/bitfield.h>
+
+#include "dw-edma-core.h"
+#include "dw-edma-v0-core.h"
+#include "dw-edma-v0-regs.h"
+#include "dw-edma-v0-debugfs.h"
+
+enum dw_edma_control {
+ DW_EDMA_V0_CB = BIT(0),
+ DW_EDMA_V0_TCB = BIT(1),
+ DW_EDMA_V0_LLP = BIT(2),
+ DW_EDMA_V0_LIE = BIT(3),
+ DW_EDMA_V0_RIE = BIT(4),
+ DW_EDMA_V0_CCS = BIT(8),
+ DW_EDMA_V0_LLE = BIT(9),
+};
+
+static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
+{
+ return (struct dw_edma_v0_regs __iomem *)dw->rg_region.vaddr;
+}
+
+#define SET(dw, name, value) \
+ writel(value, &(__dw_regs(dw)->name))
+
+#define GET(dw, name) \
+ readl(&(__dw_regs(dw)->name))
+
+#define SET_RW(dw, dir, name, value) \
+ do { \
+ if ((dir) == EDMA_DIR_WRITE) \
+ SET(dw, wr_##name, value); \
+ else \
+ SET(dw, rd_##name, value); \
+ } while (0)
+
+#define GET_RW(dw, dir, name) \
+ ((dir) == EDMA_DIR_WRITE \
+ ? GET(dw, wr_##name) \
+ : GET(dw, rd_##name))
+
+#define SET_BOTH(dw, name, value) \
+ do { \
+ SET(dw, wr_##name, value); \
+ SET(dw, rd_##name, value); \
+ } while (0)
+
+static inline struct dw_edma_v0_ch_regs __iomem *
+__dw_ch_regs(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch)
+{
+ if (dw->mode == EDMA_MODE_LEGACY)
+ return &(__dw_regs(dw)->type.legacy.ch);
+
+ if (dir == EDMA_DIR_WRITE)
+ return &__dw_regs(dw)->type.unroll.ch[ch].wr;
+
+ return &__dw_regs(dw)->type.unroll.ch[ch].rd;
+}
+
+static inline void writel_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
+ u32 value, void __iomem *addr)
+{
+ if (dw->mode == EDMA_MODE_LEGACY) {
+ u32 viewport_sel;
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&dw->lock, flags);
+
+ viewport_sel = FIELD_PREP(EDMA_V0_VIEWPORT_MASK, ch);
+ if (dir == EDMA_DIR_READ)
+ viewport_sel |= BIT(31);
+
+ writel(viewport_sel,
+ &(__dw_regs(dw)->type.legacy.viewport_sel));
+ writel(value, addr);
+
+ raw_spin_unlock_irqrestore(&dw->lock, flags);
+ } else {
+ writel(value, addr);
+ }
+}
+
+static inline u32 readl_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
+ const void __iomem *addr)
+{
+ u32 value;
+
+ if (dw->mode == EDMA_MODE_LEGACY) {
+ u32 viewport_sel;
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&dw->lock, flags);
+
+ viewport_sel = FIELD_PREP(EDMA_V0_VIEWPORT_MASK, ch);
+ if (dir == EDMA_DIR_READ)
+ viewport_sel |= BIT(31);
+
+ writel(viewport_sel,
+ &(__dw_regs(dw)->type.legacy.viewport_sel));
+ value = readl(addr);
+
+ raw_spin_unlock_irqrestore(&dw->lock, flags);
+ } else {
+ value = readl(addr);
+ }
+
+ return value;
+}
+
+#define SET_CH(dw, dir, ch, name, value) \
+ writel_ch(dw, dir, ch, value, &(__dw_ch_regs(dw, dir, ch)->name))
+
+#define GET_CH(dw, dir, ch, name) \
+ readl_ch(dw, dir, ch, &(__dw_ch_regs(dw, dir, ch)->name))
+
+#define SET_LL(ll, value) \
+ writel(value, ll)
+
+/* eDMA management callbacks */
+void dw_edma_v0_core_off(struct dw_edma *dw)
+{
+ SET_BOTH(dw, int_mask, EDMA_V0_DONE_INT_MASK | EDMA_V0_ABORT_INT_MASK);
+ SET_BOTH(dw, int_clear, EDMA_V0_DONE_INT_MASK | EDMA_V0_ABORT_INT_MASK);
+ SET_BOTH(dw, engine_en, 0);
+}
+
+u16 dw_edma_v0_core_ch_count(struct dw_edma *dw, enum dw_edma_dir dir)
+{
+ u32 num_ch;
+
+ if (dir == EDMA_DIR_WRITE)
+ num_ch = FIELD_GET(EDMA_V0_WRITE_CH_COUNT_MASK, GET(dw, ctrl));
+ else
+ num_ch = FIELD_GET(EDMA_V0_READ_CH_COUNT_MASK, GET(dw, ctrl));
+
+ if (num_ch > EDMA_V0_MAX_NR_CH)
+ num_ch = EDMA_V0_MAX_NR_CH;
+
+ return (u16)num_ch;
+}
+
+enum dma_status dw_edma_v0_core_ch_status(struct dw_edma_chan *chan)
+{
+ struct dw_edma *dw = chan->chip->dw;
+ u32 tmp;
+
+ tmp = FIELD_GET(EDMA_V0_CH_STATUS_MASK,
+ GET_CH(dw, chan->dir, chan->id, ch_control1));
+
+ if (tmp == 1)
+ return DMA_IN_PROGRESS;
+ else if (tmp == 3)
+ return DMA_COMPLETE;
+ else
+ return DMA_ERROR;
+}
+
+void dw_edma_v0_core_clear_done_int(struct dw_edma_chan *chan)
+{
+ struct dw_edma *dw = chan->chip->dw;
+
+ SET_RW(dw, chan->dir, int_clear,
+ FIELD_PREP(EDMA_V0_DONE_INT_MASK, BIT(chan->id)));
+}
+
+void dw_edma_v0_core_clear_abort_int(struct dw_edma_chan *chan)
+{
+ struct dw_edma *dw = chan->chip->dw;
+
+ SET_RW(dw, chan->dir, int_clear,
+ FIELD_PREP(EDMA_V0_ABORT_INT_MASK, BIT(chan->id)));
+}
+
+u32 dw_edma_v0_core_status_done_int(struct dw_edma *dw, enum dw_edma_dir dir)
+{
+ return FIELD_GET(EDMA_V0_DONE_INT_MASK, GET_RW(dw, dir, int_status));
+}
+
+u32 dw_edma_v0_core_status_abort_int(struct dw_edma *dw, enum dw_edma_dir dir)
+{
+ return FIELD_GET(EDMA_V0_ABORT_INT_MASK, GET_RW(dw, dir, int_status));
+}
+
+static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
+{
+ struct dw_edma_burst *child;
+ struct dw_edma_v0_lli *lli;
+ struct dw_edma_v0_llp *llp;
+ u32 control = 0, i = 0;
+ u64 sar, dar, addr;
+ int j;
+
+ lli = (struct dw_edma_v0_lli *)chunk->ll_region.vaddr;
+
+ if (chunk->cb)
+ control = DW_EDMA_V0_CB;
+
+ j = chunk->bursts_alloc;
+ list_for_each_entry(child, &chunk->burst->list, list) {
+ j--;
+ if (!j)
+ control |= (DW_EDMA_V0_LIE | DW_EDMA_V0_RIE);
+
+ /* Channel control */
+ SET_LL(&lli[i].control, control);
+ /* Transfer size */
+ SET_LL(&lli[i].transfer_size, child->sz);
+ /* SAR - low, high */
+ sar = cpu_to_le64(child->sar);
+ SET_LL(&lli[i].sar_low, lower_32_bits(sar));
+ SET_LL(&lli[i].sar_high, upper_32_bits(sar));
+ /* DAR - low, high */
+ dar = cpu_to_le64(child->dar);
+ SET_LL(&lli[i].dar_low, lower_32_bits(dar));
+ SET_LL(&lli[i].dar_high, upper_32_bits(dar));
+ i++;
+ }
+
+ llp = (struct dw_edma_v0_llp *)&lli[i];
+ control = DW_EDMA_V0_LLP | DW_EDMA_V0_TCB;
+ if (!chunk->cb)
+ control |= DW_EDMA_V0_CB;
+
+ /* Channel control */
+ SET_LL(&llp->control, control);
+ /* Linked list - low, high */
+ addr = cpu_to_le64(chunk->ll_region.paddr);
+ SET_LL(&llp->llp_low, lower_32_bits(addr));
+ SET_LL(&llp->llp_high, upper_32_bits(addr));
+}
+
+void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
+{
+ struct dw_edma_chan *chan = chunk->chan;
+ struct dw_edma *dw = chan->chip->dw;
+ u32 tmp;
+ u64 llp;
+
+ dw_edma_v0_core_write_chunk(chunk);
+
+ if (first) {
+ /* Enable engine */
+ SET_RW(dw, chan->dir, engine_en, BIT(0));
+ /* Interrupt unmask - done, abort */
+ tmp = GET_RW(dw, chan->dir, int_mask);
+ tmp &= ~FIELD_PREP(EDMA_V0_DONE_INT_MASK, BIT(chan->id));
+ tmp &= ~FIELD_PREP(EDMA_V0_ABORT_INT_MASK, BIT(chan->id));
+ SET_RW(dw, chan->dir, int_mask, tmp);
+ /* Linked list error */
+ tmp = GET_RW(dw, chan->dir, linked_list_err_en);
+ tmp |= FIELD_PREP(EDMA_V0_LINKED_LIST_ERR_MASK, BIT(chan->id));
+ SET_RW(dw, chan->dir, linked_list_err_en, tmp);
+ /* Channel control */
+ SET_CH(dw, chan->dir, chan->id, ch_control1,
+ (DW_EDMA_V0_CCS | DW_EDMA_V0_LLE));
+ /* Linked list - low, high */
+ llp = cpu_to_le64(chunk->ll_region.paddr);
+ SET_CH(dw, chan->dir, chan->id, llp_low, lower_32_bits(llp));
+ SET_CH(dw, chan->dir, chan->id, llp_high, upper_32_bits(llp));
+ }
+ /* Doorbell */
+ SET_RW(dw, chan->dir, doorbell,
+ FIELD_PREP(EDMA_V0_DOORBELL_CH_MASK, chan->id));
+}
+
+int dw_edma_v0_core_device_config(struct dw_edma_chan *chan)
+{
+ struct dw_edma *dw = chan->chip->dw;
+ u32 tmp = 0;
+
+ /* MSI done addr - low, high */
+ SET_RW(dw, chan->dir, done_imwr_low, chan->msi.address_lo);
+ SET_RW(dw, chan->dir, done_imwr_high, chan->msi.address_hi);
+ /* MSI abort addr - low, high */
+ SET_RW(dw, chan->dir, abort_imwr_low, chan->msi.address_lo);
+ SET_RW(dw, chan->dir, abort_imwr_high, chan->msi.address_hi);
+ /* MSI data - low, high */
+ switch (chan->id) {
+ case 0:
+ case 1:
+ tmp = GET_RW(dw, chan->dir, ch01_imwr_data);
+ break;
+
+ case 2:
+ case 3:
+ tmp = GET_RW(dw, chan->dir, ch23_imwr_data);
+ break;
+
+ case 4:
+ case 5:
+ tmp = GET_RW(dw, chan->dir, ch45_imwr_data);
+ break;
+
+ case 6:
+ case 7:
+ tmp = GET_RW(dw, chan->dir, ch67_imwr_data);
+ break;
+ }
+
+ if (chan->id & BIT(0)) {
+ /* Channel odd {1, 3, 5, 7} */
+ tmp &= EDMA_V0_CH_EVEN_MSI_DATA_MASK;
+ tmp |= FIELD_PREP(EDMA_V0_CH_ODD_MSI_DATA_MASK,
+ chan->msi.data);
+ } else {
+ /* Channel even {0, 2, 4, 6} */
+ tmp &= EDMA_V0_CH_ODD_MSI_DATA_MASK;
+ tmp |= FIELD_PREP(EDMA_V0_CH_EVEN_MSI_DATA_MASK,
+ chan->msi.data);
+ }
+
+ switch (chan->id) {
+ case 0:
+ case 1:
+ SET_RW(dw, chan->dir, ch01_imwr_data, tmp);
+ break;
+
+ case 2:
+ case 3:
+ SET_RW(dw, chan->dir, ch23_imwr_data, tmp);
+ break;
+
+ case 4:
+ case 5:
+ SET_RW(dw, chan->dir, ch45_imwr_data, tmp);
+ break;
+
+ case 6:
+ case 7:
+ SET_RW(dw, chan->dir, ch67_imwr_data, tmp);
+ break;
+ }
+
+ return 0;
+}
+
+/* eDMA debugfs callbacks */
+void dw_edma_v0_core_debugfs_on(struct dw_edma_chip *chip)
+{
+ dw_edma_v0_debugfs_on(chip);
+}
+
+void dw_edma_v0_core_debugfs_off(void)
+{
+ dw_edma_v0_debugfs_off();
+}
diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.h b/drivers/dma/dw-edma/dw-edma-v0-core.h
new file mode 100644
index 000000000000..abae1527f1f9
--- /dev/null
+++ b/drivers/dma/dw-edma/dw-edma-v0-core.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.
+ * Synopsys DesignWare eDMA v0 core
+ *
+ * Author: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+ */
+
+#ifndef _DW_EDMA_V0_CORE_H
+#define _DW_EDMA_V0_CORE_H
+
+#include <linux/dma/edma.h>
+
+/* eDMA management callbacks */
+void dw_edma_v0_core_off(struct dw_edma *chan);
+u16 dw_edma_v0_core_ch_count(struct dw_edma *chan, enum dw_edma_dir dir);
+enum dma_status dw_edma_v0_core_ch_status(struct dw_edma_chan *chan);
+void dw_edma_v0_core_clear_done_int(struct dw_edma_chan *chan);
+void dw_edma_v0_core_clear_abort_int(struct dw_edma_chan *chan);
+u32 dw_edma_v0_core_status_done_int(struct dw_edma *chan, enum dw_edma_dir dir);
+u32 dw_edma_v0_core_status_abort_int(struct dw_edma *chan, enum dw_edma_dir dir);
+void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first);
+int dw_edma_v0_core_device_config(struct dw_edma_chan *chan);
+/* eDMA debug fs callbacks */
+void dw_edma_v0_core_debugfs_on(struct dw_edma_chip *chip);
+void dw_edma_v0_core_debugfs_off(void);
+
+#endif /* _DW_EDMA_V0_CORE_H */
diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
new file mode 100644
index 000000000000..3226f528cc11
--- /dev/null
+++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
@@ -0,0 +1,310 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.
+ * Synopsys DesignWare eDMA v0 core
+ *
+ * Author: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+ */
+
+#include <linux/debugfs.h>
+#include <linux/bitfield.h>
+
+#include "dw-edma-v0-debugfs.h"
+#include "dw-edma-v0-regs.h"
+#include "dw-edma-core.h"
+
+#define REGS_ADDR(name) \
+ ((dma_addr_t *)&regs->name)
+#define REGISTER(name) \
+ { #name, REGS_ADDR(name) }
+
+#define WR_REGISTER(name) \
+ { #name, REGS_ADDR(wr_##name) }
+#define RD_REGISTER(name) \
+ { #name, REGS_ADDR(rd_##name) }
+
+#define WR_REGISTER_LEGACY(name) \
+ { #name, REGS_ADDR(type.legacy.wr_##name) }
+#define RD_REGISTER_LEGACY(name) \
+ { #name, REGS_ADDR(type.legacy.rd_##name) }
+
+#define WR_REGISTER_UNROLL(name) \
+ { #name, REGS_ADDR(type.unroll.wr_##name) }
+#define RD_REGISTER_UNROLL(name) \
+ { #name, REGS_ADDR(type.unroll.rd_##name) }
+
+#define WRITE_STR "write"
+#define READ_STR "read"
+#define CHANNEL_STR "channel"
+#define REGISTERS_STR "registers"
+
+static struct dentry *base_dir;
+static struct dw_edma *dw;
+static struct dw_edma_v0_regs *regs;
+
+static struct {
+ void *start;
+ void *end;
+} lim[2][EDMA_V0_MAX_NR_CH];
+
+struct debugfs_entries {
+ char name[24];
+ dma_addr_t *reg;
+};
+
+static int dw_edma_debugfs_u32_get(void *data, u64 *val)
+{
+ if (dw->mode == EDMA_MODE_LEGACY &&
+ data >= (void *)&regs->type.legacy.ch) {
+ void *ptr = (void *)&regs->type.legacy.ch;
+ u32 viewport_sel = 0;
+ unsigned long flags;
+ u16 ch;
+
+ for (ch = 0; ch < dw->wr_ch_cnt; ch++)
+ if (lim[0][ch].start >= data && data < lim[0][ch].end) {
+ ptr += (data - lim[0][ch].start);
+ goto legacy_sel_wr;
+ }
+
+ for (ch = 0; ch < dw->rd_ch_cnt; ch++)
+ if (lim[1][ch].start >= data && data < lim[1][ch].end) {
+ ptr += (data - lim[1][ch].start);
+ goto legacy_sel_rd;
+ }
+
+ return 0;
+legacy_sel_rd:
+ viewport_sel = BIT(31);
+legacy_sel_wr:
+ viewport_sel |= FIELD_PREP(EDMA_V0_VIEWPORT_MASK, ch);
+
+ raw_spin_lock_irqsave(&dw->lock, flags);
+
+ writel(viewport_sel, &regs->type.legacy.viewport_sel);
+ *val = readl(ptr);
+
+ raw_spin_unlock_irqrestore(&dw->lock, flags);
+ } else {
+ *val = readl(data);
+ }
+
+ return 0;
+}
+DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, dw_edma_debugfs_u32_get, NULL, "0x%08llx\n");
+
+static void dw_edma_debugfs_create_x32(const struct debugfs_entries entries[],
+ int nr_entries, struct dentry *dir)
+{
+ int i;
+
+ for (i = 0; i < nr_entries; i++) {
+ if (!debugfs_create_file_unsafe(entries[i].name, 0444, dir,
+ entries[i].reg, &fops_x32))
+ break;
+ }
+}
+
+static void dw_edma_debugfs_regs_ch(struct dw_edma_v0_ch_regs *regs,
+ struct dentry *dir)
+{
+ int nr_entries;
+ const struct debugfs_entries debugfs_regs[] = {
+ REGISTER(ch_control1),
+ REGISTER(ch_control2),
+ REGISTER(transfer_size),
+ REGISTER(sar_low),
+ REGISTER(sar_high),
+ REGISTER(dar_low),
+ REGISTER(dar_high),
+ REGISTER(llp_low),
+ REGISTER(llp_high),
+ };
+
+ nr_entries = ARRAY_SIZE(debugfs_regs);
+ dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, dir);
+}
+
+static void dw_edma_debugfs_regs_wr(struct dentry *dir)
+{
+ const struct debugfs_entries debugfs_regs[] = {
+ /* eDMA global registers */
+ WR_REGISTER(engine_en),
+ WR_REGISTER(doorbell),
+ WR_REGISTER(ch_arb_weight_low),
+ WR_REGISTER(ch_arb_weight_high),
+ /* eDMA interrupts registers */
+ WR_REGISTER(int_status),
+ WR_REGISTER(int_mask),
+ WR_REGISTER(int_clear),
+ WR_REGISTER(err_status),
+ WR_REGISTER(done_imwr_low),
+ WR_REGISTER(done_imwr_high),
+ WR_REGISTER(abort_imwr_low),
+ WR_REGISTER(abort_imwr_high),
+ WR_REGISTER(ch01_imwr_data),
+ WR_REGISTER(ch23_imwr_data),
+ WR_REGISTER(ch45_imwr_data),
+ WR_REGISTER(ch67_imwr_data),
+ WR_REGISTER(linked_list_err_en),
+ };
+ const struct debugfs_entries debugfs_unroll_regs[] = {
+ /* eDMA channel context grouping */
+ WR_REGISTER_UNROLL(engine_chgroup),
+ WR_REGISTER_UNROLL(engine_hshake_cnt_low),
+ WR_REGISTER_UNROLL(engine_hshake_cnt_high),
+ WR_REGISTER_UNROLL(ch0_pwr_en),
+ WR_REGISTER_UNROLL(ch1_pwr_en),
+ WR_REGISTER_UNROLL(ch2_pwr_en),
+ WR_REGISTER_UNROLL(ch3_pwr_en),
+ WR_REGISTER_UNROLL(ch4_pwr_en),
+ WR_REGISTER_UNROLL(ch5_pwr_en),
+ WR_REGISTER_UNROLL(ch6_pwr_en),
+ WR_REGISTER_UNROLL(ch7_pwr_en),
+ };
+ struct dentry *regs_dir, *ch_dir;
+ int nr_entries, i;
+ char name[16];
+
+ regs_dir = debugfs_create_dir(WRITE_STR, dir);
+ if (!regs_dir)
+ return;
+
+ nr_entries = ARRAY_SIZE(debugfs_regs);
+ dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
+
+ if (dw->mode == EDMA_MODE_UNROLL) {
+ nr_entries = ARRAY_SIZE(debugfs_unroll_regs);
+ dw_edma_debugfs_create_x32(debugfs_unroll_regs, nr_entries,
+ regs_dir);
+ }
+
+ for (i = 0; i < dw->wr_ch_cnt; i++) {
+ snprintf(name, sizeof(name), "%s:%d", CHANNEL_STR, i);
+
+ ch_dir = debugfs_create_dir(name, regs_dir);
+ if (!ch_dir)
+ return;
+
+ dw_edma_debugfs_regs_ch(&regs->type.unroll.ch[i].wr, ch_dir);
+
+ lim[0][i].start = &regs->type.unroll.ch[i].wr;
+ lim[0][i].end = &regs->type.unroll.ch[i].padding_1[0];
+ }
+}
+
+static void dw_edma_debugfs_regs_rd(struct dentry *dir)
+{
+ const struct debugfs_entries debugfs_regs[] = {
+ /* eDMA global registers */
+ RD_REGISTER(engine_en),
+ RD_REGISTER(doorbell),
+ RD_REGISTER(ch_arb_weight_low),
+ RD_REGISTER(ch_arb_weight_high),
+ /* eDMA interrupts registers */
+ RD_REGISTER(int_status),
+ RD_REGISTER(int_mask),
+ RD_REGISTER(int_clear),
+ RD_REGISTER(err_status_low),
+ RD_REGISTER(err_status_high),
+ RD_REGISTER(linked_list_err_en),
+ RD_REGISTER(done_imwr_low),
+ RD_REGISTER(done_imwr_high),
+ RD_REGISTER(abort_imwr_low),
+ RD_REGISTER(abort_imwr_high),
+ RD_REGISTER(ch01_imwr_data),
+ RD_REGISTER(ch23_imwr_data),
+ RD_REGISTER(ch45_imwr_data),
+ RD_REGISTER(ch67_imwr_data),
+ };
+ const struct debugfs_entries debugfs_unroll_regs[] = {
+ /* eDMA channel context grouping */
+ RD_REGISTER_UNROLL(engine_chgroup),
+ RD_REGISTER_UNROLL(engine_hshake_cnt_low),
+ RD_REGISTER_UNROLL(engine_hshake_cnt_high),
+ RD_REGISTER_UNROLL(ch0_pwr_en),
+ RD_REGISTER_UNROLL(ch1_pwr_en),
+ RD_REGISTER_UNROLL(ch2_pwr_en),
+ RD_REGISTER_UNROLL(ch3_pwr_en),
+ RD_REGISTER_UNROLL(ch4_pwr_en),
+ RD_REGISTER_UNROLL(ch5_pwr_en),
+ RD_REGISTER_UNROLL(ch6_pwr_en),
+ RD_REGISTER_UNROLL(ch7_pwr_en),
+ };
+ struct dentry *regs_dir, *ch_dir;
+ int nr_entries, i;
+ char name[16];
+
+ regs_dir = debugfs_create_dir(READ_STR, dir);
+ if (!regs_dir)
+ return;
+
+ nr_entries = ARRAY_SIZE(debugfs_regs);
+ dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
+
+ if (dw->mode == EDMA_MODE_UNROLL) {
+ nr_entries = ARRAY_SIZE(debugfs_unroll_regs);
+ dw_edma_debugfs_create_x32(debugfs_unroll_regs, nr_entries,
+ regs_dir);
+ }
+
+ for (i = 0; i < dw->rd_ch_cnt; i++) {
+ snprintf(name, sizeof(name), "%s:%d", CHANNEL_STR, i);
+
+ ch_dir = debugfs_create_dir(name, regs_dir);
+ if (!ch_dir)
+ return;
+
+ dw_edma_debugfs_regs_ch(&regs->type.unroll.ch[i].rd, ch_dir);
+
+ lim[1][i].start = &regs->type.unroll.ch[i].rd;
+ lim[1][i].end = &regs->type.unroll.ch[i].padding_2[0];
+ }
+}
+
+static void dw_edma_debugfs_regs(void)
+{
+ const struct debugfs_entries debugfs_regs[] = {
+ REGISTER(ctrl_data_arb_prior),
+ REGISTER(ctrl),
+ };
+ struct dentry *regs_dir;
+ int nr_entries;
+
+ regs_dir = debugfs_create_dir(REGISTERS_STR, base_dir);
+ if (!regs_dir)
+ return;
+
+ nr_entries = ARRAY_SIZE(debugfs_regs);
+ dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
+
+ dw_edma_debugfs_regs_wr(regs_dir);
+ dw_edma_debugfs_regs_rd(regs_dir);
+}
+
+void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
+{
+ dw = chip->dw;
+ if (!dw)
+ return;
+
+ regs = (struct dw_edma_v0_regs *)dw->rg_region.vaddr;
+ if (!regs)
+ return;
+
+ base_dir = debugfs_create_dir(dw->name, 0);
+ if (!base_dir)
+ return;
+
+ debugfs_create_u32("version", 0444, base_dir, &dw->version);
+ debugfs_create_u32("mode", 0444, base_dir, &dw->mode);
+ debugfs_create_u16("wr_ch_cnt", 0444, base_dir, &dw->wr_ch_cnt);
+ debugfs_create_u16("rd_ch_cnt", 0444, base_dir, &dw->rd_ch_cnt);
+
+ dw_edma_debugfs_regs();
+}
+
+void dw_edma_v0_debugfs_off(void)
+{
+ debugfs_remove_recursive(base_dir);
+}
diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.h b/drivers/dma/dw-edma/dw-edma-v0-debugfs.h
new file mode 100644
index 000000000000..5450a0a94193
--- /dev/null
+++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.
+ * Synopsys DesignWare eDMA v0 core
+ *
+ * Author: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+ */
+
+#ifndef _DW_EDMA_V0_DEBUG_FS_H
+#define _DW_EDMA_V0_DEBUG_FS_H
+
+#include <linux/dma/edma.h>
+
+#ifdef CONFIG_DEBUG_FS
+void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip);
+void dw_edma_v0_debugfs_off(void);
+#else
+static inline void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
+{
+}
+
+static inline void dw_edma_v0_debugfs_off(void)
+{
+}
+#endif /* CONFIG_DEBUG_FS */
+
+#endif /* _DW_EDMA_V0_DEBUG_FS_H */
diff --git a/drivers/dma/dw-edma/dw-edma-v0-regs.h b/drivers/dma/dw-edma/dw-edma-v0-regs.h
new file mode 100644
index 000000000000..cd6476884507
--- /dev/null
+++ b/drivers/dma/dw-edma/dw-edma-v0-regs.h
@@ -0,0 +1,158 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.
+ * Synopsys DesignWare eDMA v0 core
+ *
+ * Author: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+ */
+
+#ifndef _DW_EDMA_V0_REGS_H
+#define _DW_EDMA_V0_REGS_H
+
+#include <linux/dmaengine.h>
+
+#define EDMA_V0_MAX_NR_CH 8
+#define EDMA_V0_VIEWPORT_MASK GENMASK(2, 0)
+#define EDMA_V0_DONE_INT_MASK GENMASK(7, 0)
+#define EDMA_V0_ABORT_INT_MASK GENMASK(23, 16)
+#define EDMA_V0_WRITE_CH_COUNT_MASK GENMASK(3, 0)
+#define EDMA_V0_READ_CH_COUNT_MASK GENMASK(19, 16)
+#define EDMA_V0_CH_STATUS_MASK GENMASK(6, 5)
+#define EDMA_V0_DOORBELL_CH_MASK GENMASK(2, 0)
+#define EDMA_V0_LINKED_LIST_ERR_MASK GENMASK(7, 0)
+
+#define EDMA_V0_CH_ODD_MSI_DATA_MASK GENMASK(31, 16)
+#define EDMA_V0_CH_EVEN_MSI_DATA_MASK GENMASK(15, 0)
+
+struct dw_edma_v0_ch_regs {
+ u32 ch_control1; /* 0x000 */
+ u32 ch_control2; /* 0x004 */
+ u32 transfer_size; /* 0x008 */
+ u32 sar_low; /* 0x00c */
+ u32 sar_high; /* 0x010 */
+ u32 dar_low; /* 0x014 */
+ u32 dar_high; /* 0x018 */
+ u32 llp_low; /* 0x01c */
+ u32 llp_high; /* 0x020 */
+};
+
+struct dw_edma_v0_ch {
+ struct dw_edma_v0_ch_regs wr; /* 0x200 */
+ u32 padding_1[55]; /* [0x224..0x2fc] */
+ struct dw_edma_v0_ch_regs rd; /* 0x300 */
+ u32 padding_2[55]; /* [0x224..0x2fc] */
+};
+
+struct dw_edma_v0_unroll {
+ u32 padding_1; /* 0x0f8 */
+ u32 wr_engine_chgroup; /* 0x100 */
+ u32 rd_engine_chgroup; /* 0x104 */
+ u32 wr_engine_hshake_cnt_low; /* 0x108 */
+ u32 wr_engine_hshake_cnt_high; /* 0x10c */
+ u32 padding_2[2]; /* [0x110..0x114] */
+ u32 rd_engine_hshake_cnt_low; /* 0x118 */
+ u32 rd_engine_hshake_cnt_high; /* 0x11c */
+ u32 padding_3[2]; /* [0x120..0x124] */
+ u32 wr_ch0_pwr_en; /* 0x128 */
+ u32 wr_ch1_pwr_en; /* 0x12c */
+ u32 wr_ch2_pwr_en; /* 0x130 */
+ u32 wr_ch3_pwr_en; /* 0x134 */
+ u32 wr_ch4_pwr_en; /* 0x138 */
+ u32 wr_ch5_pwr_en; /* 0x13c */
+ u32 wr_ch6_pwr_en; /* 0x140 */
+ u32 wr_ch7_pwr_en; /* 0x144 */
+ u32 padding_4[8]; /* [0x148..0x164] */
+ u32 rd_ch0_pwr_en; /* 0x168 */
+ u32 rd_ch1_pwr_en; /* 0x16c */
+ u32 rd_ch2_pwr_en; /* 0x170 */
+ u32 rd_ch3_pwr_en; /* 0x174 */
+ u32 rd_ch4_pwr_en; /* 0x178 */
+ u32 rd_ch5_pwr_en; /* 0x18c */
+ u32 rd_ch6_pwr_en; /* 0x180 */
+ u32 rd_ch7_pwr_en; /* 0x184 */
+ u32 padding_5[30]; /* [0x188..0x1fc] */
+ struct dw_edma_v0_ch ch[EDMA_V0_MAX_NR_CH]; /* [0x200..0x1120] */
+};
+
+struct dw_edma_v0_legacy {
+ u32 viewport_sel; /* 0x0f8 */
+ struct dw_edma_v0_ch_regs ch; /* [0x100..0x120] */
+};
+
+struct dw_edma_v0_regs {
+ /* eDMA global registers */
+ u32 ctrl_data_arb_prior; /* 0x000 */
+ u32 padding_1; /* 0x004 */
+ u32 ctrl; /* 0x008 */
+ u32 wr_engine_en; /* 0x00c */
+ u32 wr_doorbell; /* 0x010 */
+ u32 padding_2; /* 0x014 */
+ u32 wr_ch_arb_weight_low; /* 0x018 */
+ u32 wr_ch_arb_weight_high; /* 0x01c */
+ u32 padding_3[3]; /* [0x020..0x028] */
+ u32 rd_engine_en; /* 0x02c */
+ u32 rd_doorbell; /* 0x030 */
+ u32 padding_4; /* 0x034 */
+ u32 rd_ch_arb_weight_low; /* 0x038 */
+ u32 rd_ch_arb_weight_high; /* 0x03c */
+ u32 padding_5[3]; /* [0x040..0x048] */
+ /* eDMA interrupts registers */
+ u32 wr_int_status; /* 0x04c */
+ u32 padding_6; /* 0x050 */
+ u32 wr_int_mask; /* 0x054 */
+ u32 wr_int_clear; /* 0x058 */
+ u32 wr_err_status; /* 0x05c */
+ u32 wr_done_imwr_low; /* 0x060 */
+ u32 wr_done_imwr_high; /* 0x064 */
+ u32 wr_abort_imwr_low; /* 0x068 */
+ u32 wr_abort_imwr_high; /* 0x06c */
+ u32 wr_ch01_imwr_data; /* 0x070 */
+ u32 wr_ch23_imwr_data; /* 0x074 */
+ u32 wr_ch45_imwr_data; /* 0x078 */
+ u32 wr_ch67_imwr_data; /* 0x07c */
+ u32 padding_7[4]; /* [0x080..0x08c] */
+ u32 wr_linked_list_err_en; /* 0x090 */
+ u32 padding_8[3]; /* [0x094..0x09c] */
+ u32 rd_int_status; /* 0x0a0 */
+ u32 padding_9; /* 0x0a4 */
+ u32 rd_int_mask; /* 0x0a8 */
+ u32 rd_int_clear; /* 0x0ac */
+ u32 padding_10; /* 0x0b0 */
+ u32 rd_err_status_low; /* 0x0b4 */
+ u32 rd_err_status_high; /* 0x0b8 */
+ u32 padding_11[2]; /* [0x0bc..0x0c0] */
+ u32 rd_linked_list_err_en; /* 0x0c4 */
+ u32 padding_12; /* 0x0c8 */
+ u32 rd_done_imwr_low; /* 0x0cc */
+ u32 rd_done_imwr_high; /* 0x0d0 */
+ u32 rd_abort_imwr_low; /* 0x0d4 */
+ u32 rd_abort_imwr_high; /* 0x0d8 */
+ u32 rd_ch01_imwr_data; /* 0x0dc */
+ u32 rd_ch23_imwr_data; /* 0x0e0 */
+ u32 rd_ch45_imwr_data; /* 0x0e4 */
+ u32 rd_ch67_imwr_data; /* 0x0e8 */
+ u32 padding_13[4]; /* [0x0ec..0x0f8] */
+ /* eDMA channel context grouping */
+ union dw_edma_v0_type {
+ struct dw_edma_v0_legacy legacy; /* [0x0f8..0x120] */
+ struct dw_edma_v0_unroll unroll; /* [0x0f8..0x1120] */
+ } type;
+};
+
+struct dw_edma_v0_lli {
+ u32 control;
+ u32 transfer_size;
+ u32 sar_low;
+ u32 sar_high;
+ u32 dar_low;
+ u32 dar_high;
+};
+
+struct dw_edma_v0_llp {
+ u32 control;
+ u32 reserved;
+ u32 llp_low;
+ u32 llp_high;
+};
+
+#endif /* _DW_EDMA_V0_REGS_H */
diff --git a/drivers/dma/dw/pci.c b/drivers/dma/dw/pci.c
index e79a75db0852..8de87b15a988 100644
--- a/drivers/dma/dw/pci.c
+++ b/drivers/dma/dw/pci.c
@@ -15,10 +15,13 @@
struct dw_dma_pci_data {
const struct dw_dma_platform_data *pdata;
int (*probe)(struct dw_dma_chip *chip);
+ int (*remove)(struct dw_dma_chip *chip);
+ struct dw_dma_chip *chip;
};
static const struct dw_dma_pci_data dw_pci_data = {
.probe = dw_dma_probe,
+ .remove = dw_dma_remove,
};
static const struct dw_dma_platform_data idma32_pdata = {
@@ -34,11 +37,13 @@ static const struct dw_dma_platform_data idma32_pdata = {
static const struct dw_dma_pci_data idma32_pci_data = {
.pdata = &idma32_pdata,
.probe = idma32_dma_probe,
+ .remove = idma32_dma_remove,
};
static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
{
- const struct dw_dma_pci_data *data = (void *)pid->driver_data;
+ const struct dw_dma_pci_data *drv_data = (void *)pid->driver_data;
+ struct dw_dma_pci_data *data;
struct dw_dma_chip *chip;
int ret;
@@ -63,6 +68,10 @@ static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
if (ret)
return ret;
+ data = devm_kmemdup(&pdev->dev, drv_data, sizeof(*drv_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
@@ -73,21 +82,24 @@ static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
chip->irq = pdev->irq;
chip->pdata = data->pdata;
+ data->chip = chip;
+
ret = data->probe(chip);
if (ret)
return ret;
- pci_set_drvdata(pdev, chip);
+ pci_set_drvdata(pdev, data);
return 0;
}
static void dw_pci_remove(struct pci_dev *pdev)
{
- struct dw_dma_chip *chip = pci_get_drvdata(pdev);
+ struct dw_dma_pci_data *data = pci_get_drvdata(pdev);
+ struct dw_dma_chip *chip = data->chip;
int ret;
- ret = dw_dma_remove(chip);
+ ret = data->remove(chip);
if (ret)
dev_warn(&pdev->dev, "can't remove device properly: %d\n", ret);
}
@@ -96,16 +108,16 @@ static void dw_pci_remove(struct pci_dev *pdev)
static int dw_pci_suspend_late(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
- struct dw_dma_chip *chip = pci_get_drvdata(pci);
+ struct dw_dma_pci_data *data = dev_get_drvdata(dev);
+ struct dw_dma_chip *chip = data->chip;
return do_dw_dma_disable(chip);
};
static int dw_pci_resume_early(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
- struct dw_dma_chip *chip = pci_get_drvdata(pci);
+ struct dw_dma_pci_data *data = dev_get_drvdata(dev);
+ struct dw_dma_chip *chip = data->chip;
return do_dw_dma_enable(chip);
};
@@ -131,6 +143,11 @@ static const struct pci_device_id dw_pci_id_table[] = {
{ PCI_VDEVICE(INTEL, 0x2286), (kernel_ulong_t)&dw_pci_data },
{ PCI_VDEVICE(INTEL, 0x22c0), (kernel_ulong_t)&dw_pci_data },
+ /* Elkhart Lake iDMA 32-bit (OSE DMA) */
+ { PCI_VDEVICE(INTEL, 0x4bb4), (kernel_ulong_t)&idma32_pci_data },
+ { PCI_VDEVICE(INTEL, 0x4bb5), (kernel_ulong_t)&idma32_pci_data },
+ { PCI_VDEVICE(INTEL, 0x4bb6), (kernel_ulong_t)&idma32_pci_data },
+
/* Haswell */
{ PCI_VDEVICE(INTEL, 0x9c60), (kernel_ulong_t)&dw_pci_data },
diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c
index 680b2a00a953..44d92c34dec3 100644
--- a/drivers/dma/fsl-edma-common.c
+++ b/drivers/dma/fsl-edma-common.c
@@ -47,7 +47,7 @@ static void fsl_edma_enable_request(struct fsl_edma_chan *fsl_chan)
struct edma_regs *regs = &fsl_chan->edma->regs;
u32 ch = fsl_chan->vchan.chan.chan_id;
- if (fsl_chan->edma->version == v1) {
+ if (fsl_chan->edma->drvdata->version == v1) {
edma_writeb(fsl_chan->edma, EDMA_SEEI_SEEI(ch), regs->seei);
edma_writeb(fsl_chan->edma, ch, regs->serq);
} else {
@@ -64,7 +64,7 @@ void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan)
struct edma_regs *regs = &fsl_chan->edma->regs;
u32 ch = fsl_chan->vchan.chan.chan_id;
- if (fsl_chan->edma->version == v1) {
+ if (fsl_chan->edma->drvdata->version == v1) {
edma_writeb(fsl_chan->edma, ch, regs->cerq);
edma_writeb(fsl_chan->edma, EDMA_CEEI_CEEI(ch), regs->ceei);
} else {
@@ -77,22 +77,33 @@ void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan)
}
EXPORT_SYMBOL_GPL(fsl_edma_disable_request);
+static void mux_configure8(struct fsl_edma_chan *fsl_chan, void __iomem *addr,
+ u32 off, u32 slot, bool enable)
+{
+ u8 val8;
+
+ if (enable)
+ val8 = EDMAMUX_CHCFG_ENBL | slot;
+ else
+ val8 = EDMAMUX_CHCFG_DIS;
+
+ iowrite8(val8, addr + off);
+}
+
void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan,
unsigned int slot, bool enable)
{
u32 ch = fsl_chan->vchan.chan.chan_id;
void __iomem *muxaddr;
unsigned int chans_per_mux, ch_off;
+ u32 dmamux_nr = fsl_chan->edma->drvdata->dmamuxs;
- chans_per_mux = fsl_chan->edma->n_chans / DMAMUX_NR;
+ chans_per_mux = fsl_chan->edma->n_chans / dmamux_nr;
ch_off = fsl_chan->vchan.chan.chan_id % chans_per_mux;
muxaddr = fsl_chan->edma->muxbase[ch / chans_per_mux];
slot = EDMAMUX_CHCFG_SOURCE(slot);
- if (enable)
- iowrite8(EDMAMUX_CHCFG_ENBL | slot, muxaddr + ch_off);
- else
- iowrite8(EDMAMUX_CHCFG_DIS, muxaddr + ch_off);
+ mux_configure8(fsl_chan, muxaddr, ch_off, slot, enable);
}
EXPORT_SYMBOL_GPL(fsl_edma_chan_mux);
@@ -647,28 +658,28 @@ void fsl_edma_setup_regs(struct fsl_edma_engine *edma)
edma->regs.erql = edma->membase + EDMA_ERQ;
edma->regs.eeil = edma->membase + EDMA_EEI;
- edma->regs.serq = edma->membase + ((edma->version == v1) ?
- EDMA_SERQ : EDMA64_SERQ);
- edma->regs.cerq = edma->membase + ((edma->version == v1) ?
- EDMA_CERQ : EDMA64_CERQ);
- edma->regs.seei = edma->membase + ((edma->version == v1) ?
- EDMA_SEEI : EDMA64_SEEI);
- edma->regs.ceei = edma->membase + ((edma->version == v1) ?
- EDMA_CEEI : EDMA64_CEEI);
- edma->regs.cint = edma->membase + ((edma->version == v1) ?
- EDMA_CINT : EDMA64_CINT);
- edma->regs.cerr = edma->membase + ((edma->version == v1) ?
- EDMA_CERR : EDMA64_CERR);
- edma->regs.ssrt = edma->membase + ((edma->version == v1) ?
- EDMA_SSRT : EDMA64_SSRT);
- edma->regs.cdne = edma->membase + ((edma->version == v1) ?
- EDMA_CDNE : EDMA64_CDNE);
- edma->regs.intl = edma->membase + ((edma->version == v1) ?
- EDMA_INTR : EDMA64_INTL);
- edma->regs.errl = edma->membase + ((edma->version == v1) ?
- EDMA_ERR : EDMA64_ERRL);
-
- if (edma->version == v2) {
+ edma->regs.serq = edma->membase + ((edma->drvdata->version == v2) ?
+ EDMA64_SERQ : EDMA_SERQ);
+ edma->regs.cerq = edma->membase + ((edma->drvdata->version == v2) ?
+ EDMA64_CERQ : EDMA_CERQ);
+ edma->regs.seei = edma->membase + ((edma->drvdata->version == v2) ?
+ EDMA64_SEEI : EDMA_SEEI);
+ edma->regs.ceei = edma->membase + ((edma->drvdata->version == v2) ?
+ EDMA64_CEEI : EDMA_CEEI);
+ edma->regs.cint = edma->membase + ((edma->drvdata->version == v2) ?
+ EDMA64_CINT : EDMA_CINT);
+ edma->regs.cerr = edma->membase + ((edma->drvdata->version == v2) ?
+ EDMA64_CERR : EDMA_CERR);
+ edma->regs.ssrt = edma->membase + ((edma->drvdata->version == v2) ?
+ EDMA64_SSRT : EDMA_SSRT);
+ edma->regs.cdne = edma->membase + ((edma->drvdata->version == v2) ?
+ EDMA64_CDNE : EDMA_CDNE);
+ edma->regs.intl = edma->membase + ((edma->drvdata->version == v2) ?
+ EDMA64_INTL : EDMA_INTR);
+ edma->regs.errl = edma->membase + ((edma->drvdata->version == v2) ?
+ EDMA64_ERRL : EDMA_ERR);
+
+ if (edma->drvdata->version == v2) {
edma->regs.erqh = edma->membase + EDMA64_ERQH;
edma->regs.eeih = edma->membase + EDMA64_EEIH;
edma->regs.errh = edma->membase + EDMA64_ERRH;
diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h
index c53f76eeb4d3..4e175560292c 100644
--- a/drivers/dma/fsl-edma-common.h
+++ b/drivers/dma/fsl-edma-common.h
@@ -7,6 +7,7 @@
#define _FSL_EDMA_COMMON_H_
#include <linux/dma-direction.h>
+#include <linux/platform_device.h>
#include "virt-dma.h"
#define EDMA_CR_EDBG BIT(1)
@@ -140,17 +141,24 @@ enum edma_version {
v2, /* 64ch Coldfire */
};
+struct fsl_edma_drvdata {
+ enum edma_version version;
+ u32 dmamuxs;
+ int (*setup_irq)(struct platform_device *pdev,
+ struct fsl_edma_engine *fsl_edma);
+};
+
struct fsl_edma_engine {
struct dma_device dma_dev;
void __iomem *membase;
void __iomem *muxbase[DMAMUX_NR];
struct clk *muxclk[DMAMUX_NR];
struct mutex fsl_edma_mutex;
+ const struct fsl_edma_drvdata *drvdata;
u32 n_chans;
int txirq;
int errirq;
bool big_endian;
- enum edma_version version;
struct edma_regs regs;
struct fsl_edma_chan chans[];
};
diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c
index 0ddad3adb761..fcbad6ae954a 100644
--- a/drivers/dma/fsl-edma.c
+++ b/drivers/dma/fsl-edma.c
@@ -92,7 +92,8 @@ static struct dma_chan *fsl_edma_xlate(struct of_phandle_args *dma_spec,
struct fsl_edma_engine *fsl_edma = ofdma->of_dma_data;
struct dma_chan *chan, *_chan;
struct fsl_edma_chan *fsl_chan;
- unsigned long chans_per_mux = fsl_edma->n_chans / DMAMUX_NR;
+ u32 dmamux_nr = fsl_edma->drvdata->dmamuxs;
+ unsigned long chans_per_mux = fsl_edma->n_chans / dmamux_nr;
if (dma_spec->args_count != 2)
return NULL;
@@ -180,16 +181,38 @@ static void fsl_disable_clocks(struct fsl_edma_engine *fsl_edma, int nr_clocks)
clk_disable_unprepare(fsl_edma->muxclk[i]);
}
+static struct fsl_edma_drvdata vf610_data = {
+ .version = v1,
+ .dmamuxs = DMAMUX_NR,
+ .setup_irq = fsl_edma_irq_init,
+};
+
+static const struct of_device_id fsl_edma_dt_ids[] = {
+ { .compatible = "fsl,vf610-edma", .data = &vf610_data},
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, fsl_edma_dt_ids);
+
static int fsl_edma_probe(struct platform_device *pdev)
{
+ const struct of_device_id *of_id =
+ of_match_device(fsl_edma_dt_ids, &pdev->dev);
struct device_node *np = pdev->dev.of_node;
struct fsl_edma_engine *fsl_edma;
+ const struct fsl_edma_drvdata *drvdata = NULL;
struct fsl_edma_chan *fsl_chan;
struct edma_regs *regs;
struct resource *res;
int len, chans;
int ret, i;
+ if (of_id)
+ drvdata = of_id->data;
+ if (!drvdata) {
+ dev_err(&pdev->dev, "unable to find driver data\n");
+ return -EINVAL;
+ }
+
ret = of_property_read_u32(np, "dma-channels", &chans);
if (ret) {
dev_err(&pdev->dev, "Can't get dma-channels.\n");
@@ -201,7 +224,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
if (!fsl_edma)
return -ENOMEM;
- fsl_edma->version = v1;
+ fsl_edma->drvdata = drvdata;
fsl_edma->n_chans = chans;
mutex_init(&fsl_edma->fsl_edma_mutex);
@@ -213,7 +236,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
fsl_edma_setup_regs(fsl_edma);
regs = &fsl_edma->regs;
- for (i = 0; i < DMAMUX_NR; i++) {
+ for (i = 0; i < fsl_edma->drvdata->dmamuxs; i++) {
char clkname[32];
res = platform_get_resource(pdev, IORESOURCE_MEM, 1 + i);
@@ -259,7 +282,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
}
edma_writel(fsl_edma, ~0, regs->intl);
- ret = fsl_edma_irq_init(pdev, fsl_edma);
+ ret = fsl_edma->drvdata->setup_irq(pdev, fsl_edma);
if (ret)
return ret;
@@ -291,7 +314,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev,
"Can't register Freescale eDMA engine. (%d)\n", ret);
- fsl_disable_clocks(fsl_edma, DMAMUX_NR);
+ fsl_disable_clocks(fsl_edma, fsl_edma->drvdata->dmamuxs);
return ret;
}
@@ -300,7 +323,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
dev_err(&pdev->dev,
"Can't register Freescale eDMA of_dma. (%d)\n", ret);
dma_async_device_unregister(&fsl_edma->dma_dev);
- fsl_disable_clocks(fsl_edma, DMAMUX_NR);
+ fsl_disable_clocks(fsl_edma, fsl_edma->drvdata->dmamuxs);
return ret;
}
@@ -319,7 +342,7 @@ static int fsl_edma_remove(struct platform_device *pdev)
fsl_edma_cleanup_vchan(&fsl_edma->dma_dev);
of_dma_controller_free(np);
dma_async_device_unregister(&fsl_edma->dma_dev);
- fsl_disable_clocks(fsl_edma, DMAMUX_NR);
+ fsl_disable_clocks(fsl_edma, fsl_edma->drvdata->dmamuxs);
return 0;
}
@@ -378,12 +401,6 @@ static const struct dev_pm_ops fsl_edma_pm_ops = {
.resume_early = fsl_edma_resume_early,
};
-static const struct of_device_id fsl_edma_dt_ids[] = {
- { .compatible = "fsl,vf610-edma", },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, fsl_edma_dt_ids);
-
static struct platform_driver fsl_edma_driver = {
.driver = {
.name = "fsl-edma",
diff --git a/drivers/dma/fsl-qdma.c b/drivers/dma/fsl-qdma.c
index 60b062c3647b..8e341c0c13bc 100644
--- a/drivers/dma/fsl-qdma.c
+++ b/drivers/dma/fsl-qdma.c
@@ -113,6 +113,7 @@
/* Field definition for Descriptor offset */
#define QDMA_CCDF_STATUS 20
#define QDMA_CCDF_OFFSET 20
+#define QDMA_SDDF_CMD(x) (((u64)(x)) << 32)
/* Field definition for safe loop count*/
#define FSL_QDMA_HALT_COUNT 1500
@@ -341,6 +342,7 @@ static void fsl_qdma_free_chan_resources(struct dma_chan *chan)
static void fsl_qdma_comp_fill_memcpy(struct fsl_qdma_comp *fsl_comp,
dma_addr_t dst, dma_addr_t src, u32 len)
{
+ u32 cmd;
struct fsl_qdma_format *sdf, *ddf;
struct fsl_qdma_format *ccdf, *csgf_desc, *csgf_src, *csgf_dest;
@@ -369,14 +371,14 @@ static void fsl_qdma_comp_fill_memcpy(struct fsl_qdma_comp *fsl_comp,
/* This entry is the last entry. */
qdma_csgf_set_f(csgf_dest, len);
/* Descriptor Buffer */
- sdf->data =
- cpu_to_le64(FSL_QDMA_CMD_RWTTYPE <<
- FSL_QDMA_CMD_RWTTYPE_OFFSET);
- ddf->data =
- cpu_to_le64(FSL_QDMA_CMD_RWTTYPE <<
- FSL_QDMA_CMD_RWTTYPE_OFFSET);
- ddf->data |=
- cpu_to_le64(FSL_QDMA_CMD_LWC << FSL_QDMA_CMD_LWC_OFFSET);
+ cmd = cpu_to_le32(FSL_QDMA_CMD_RWTTYPE <<
+ FSL_QDMA_CMD_RWTTYPE_OFFSET);
+ sdf->data = QDMA_SDDF_CMD(cmd);
+
+ cmd = cpu_to_le32(FSL_QDMA_CMD_RWTTYPE <<
+ FSL_QDMA_CMD_RWTTYPE_OFFSET);
+ cmd |= cpu_to_le32(FSL_QDMA_CMD_LWC << FSL_QDMA_CMD_LWC_OFFSET);
+ ddf->data = QDMA_SDDF_CMD(cmd);
}
/*
diff --git a/drivers/dma/hsu/hsu.c b/drivers/dma/hsu/hsu.c
index e06f20272fd7..025d8ad5a63c 100644
--- a/drivers/dma/hsu/hsu.c
+++ b/drivers/dma/hsu/hsu.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Core driver for the High Speed UART DMA
*
@@ -5,10 +6,6 @@
* Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
*
* Partially based on the bits found in drivers/tty/serial/mfd.c.
- *
- * 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.
*/
/*
@@ -64,10 +61,10 @@ static void hsu_dma_chan_start(struct hsu_dma_chan *hsuc)
if (hsuc->direction == DMA_MEM_TO_DEV) {
bsr = config->dst_maxburst;
- mtsr = config->src_addr_width;
+ mtsr = config->dst_addr_width;
} else if (hsuc->direction == DMA_DEV_TO_MEM) {
bsr = config->src_maxburst;
- mtsr = config->dst_addr_width;
+ mtsr = config->src_addr_width;
}
hsu_chan_disable(hsuc);
diff --git a/drivers/dma/hsu/hsu.h b/drivers/dma/hsu/hsu.h
index 486b023b3af0..9e5956345748 100644
--- a/drivers/dma/hsu/hsu.h
+++ b/drivers/dma/hsu/hsu.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Driver for the High Speed UART DMA
*
* Copyright (C) 2015 Intel Corporation
*
* Partially based on the bits found in drivers/tty/serial/mfd.c.
- *
- * 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.
*/
#ifndef __DMA_HSU_H__
diff --git a/drivers/dma/hsu/pci.c b/drivers/dma/hsu/pci.c
index ad45cd344bba..07cc7320a614 100644
--- a/drivers/dma/hsu/pci.c
+++ b/drivers/dma/hsu/pci.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* PCI driver for the High Speed UART DMA
*
@@ -5,10 +6,6 @@
* Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
*
* Partially based on the bits found in drivers/tty/serial/mfd.c.
- *
- * 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.
*/
#include <linux/bitops.h>
diff --git a/drivers/dma/idma64.c b/drivers/dma/idma64.c
index 07fd4f25cdd8..f5a84c846394 100644
--- a/drivers/dma/idma64.c
+++ b/drivers/dma/idma64.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Core driver for the Intel integrated DMA 64-bit
*
* Copyright (C) 2015 Intel Corporation
* Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
- *
- * 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.
*/
#include <linux/bitops.h>
diff --git a/drivers/dma/idma64.h b/drivers/dma/idma64.h
index baa32e1425de..d013b54356aa 100644
--- a/drivers/dma/idma64.h
+++ b/drivers/dma/idma64.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Driver for the Intel integrated DMA 64-bit
*
* Copyright (C) 2015 Intel Corporation
- *
- * 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.
*/
#ifndef __DMA_IDMA64_H__
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 99d9f431ae2c..a01f4b5d793c 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -703,7 +703,7 @@ static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size,
spin_lock_irqsave(&sdma->channel_0_lock, flags);
bd0->mode.command = C0_SETPM;
- bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD;
+ bd0->mode.status = BD_DONE | BD_WRAP | BD_EXTD;
bd0->mode.count = size / 2;
bd0->buffer_addr = buf_phys;
bd0->ext_buffer_addr = address;
@@ -1025,7 +1025,7 @@ static int sdma_load_context(struct sdma_channel *sdmac)
context->gReg[7] = sdmac->watermark_level;
bd0->mode.command = C0_SETDM;
- bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD;
+ bd0->mode.status = BD_DONE | BD_WRAP | BD_EXTD;
bd0->mode.count = sizeof(*context) / 4;
bd0->buffer_addr = sdma->context_phys;
bd0->ext_buffer_addr = 2048 + (sizeof(*context) / 4) * channel;
@@ -1934,16 +1934,11 @@ disable_clk_ipg:
static bool sdma_filter_fn(struct dma_chan *chan, void *fn_param)
{
struct sdma_channel *sdmac = to_sdma_chan(chan);
- struct sdma_engine *sdma = sdmac->sdma;
struct imx_dma_data *data = fn_param;
if (!imx_dma_is_general_purpose(chan))
return false;
- /* return false if it's not the right device */
- if (sdma->dev->of_node != data->of_node)
- return false;
-
sdmac->data = *data;
chan->private = &sdmac->data;
@@ -1971,9 +1966,9 @@ static struct dma_chan *sdma_xlate(struct of_phandle_args *dma_spec,
* be set to sdmac->event_id1.
*/
data.dma_request2 = 0;
- data.of_node = ofdma->of_node;
- return dma_request_channel(mask, sdma_filter_fn, &data);
+ return __dma_request_channel(&mask, sdma_filter_fn, &data,
+ ofdma->of_node);
}
static int sdma_probe(struct platform_device *pdev)
@@ -2096,27 +2091,6 @@ static int sdma_probe(struct platform_device *pdev)
if (pdata && pdata->script_addrs)
sdma_add_scripts(sdma, pdata->script_addrs);
- if (pdata) {
- ret = sdma_get_firmware(sdma, pdata->fw_name);
- if (ret)
- dev_warn(&pdev->dev, "failed to get firmware from platform data\n");
- } else {
- /*
- * Because that device tree does not encode ROM script address,
- * the RAM script in firmware is mandatory for device tree
- * probe, otherwise it fails.
- */
- ret = of_property_read_string(np, "fsl,sdma-ram-script-name",
- &fw_name);
- if (ret)
- dev_warn(&pdev->dev, "failed to get firmware name\n");
- else {
- ret = sdma_get_firmware(sdma, fw_name);
- if (ret)
- dev_warn(&pdev->dev, "failed to get firmware from device tree\n");
- }
- }
-
sdma->dma_device.dev = &pdev->dev;
sdma->dma_device.device_alloc_chan_resources = sdma_alloc_chan_resources;
@@ -2161,6 +2135,33 @@ static int sdma_probe(struct platform_device *pdev)
of_node_put(spba_bus);
}
+ /*
+ * Kick off firmware loading as the very last step:
+ * attempt to load firmware only if we're not on the error path, because
+ * the firmware callback requires a fully functional and allocated sdma
+ * instance.
+ */
+ if (pdata) {
+ ret = sdma_get_firmware(sdma, pdata->fw_name);
+ if (ret)
+ dev_warn(&pdev->dev, "failed to get firmware from platform data\n");
+ } else {
+ /*
+ * Because that device tree does not encode ROM script address,
+ * the RAM script in firmware is mandatory for device tree
+ * probe, otherwise it fails.
+ */
+ ret = of_property_read_string(np, "fsl,sdma-ram-script-name",
+ &fw_name);
+ if (ret) {
+ dev_warn(&pdev->dev, "failed to get firmware name\n");
+ } else {
+ ret = sdma_get_firmware(sdma, fw_name);
+ if (ret)
+ dev_warn(&pdev->dev, "failed to get firmware from device tree\n");
+ }
+ }
+
return 0;
err_register:
diff --git a/drivers/dma/ipu/ipu_idmac.c b/drivers/dma/ipu/ipu_idmac.c
index bbff52be4f0f..0457b1f26540 100644
--- a/drivers/dma/ipu/ipu_idmac.c
+++ b/drivers/dma/ipu/ipu_idmac.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2008
* Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
*
* Copyright (C) 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/dma-mapping.h>
diff --git a/drivers/dma/ipu/ipu_intern.h b/drivers/dma/ipu/ipu_intern.h
index 545cf11a94ab..e7ec1dec3edf 100644
--- a/drivers/dma/ipu/ipu_intern.h
+++ b/drivers/dma/ipu/ipu_intern.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2008
* Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
*
* Copyright (C) 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#ifndef _IPU_INTERN_H_
diff --git a/drivers/dma/ipu/ipu_irq.c b/drivers/dma/ipu/ipu_irq.c
index 284627806b88..0d5c42f7bfa4 100644
--- a/drivers/dma/ipu/ipu_irq.c
+++ b/drivers/dma/ipu/ipu_irq.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2008
* Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
- *
- * 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.
*/
#include <linux/init.h>
diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c
index 5737d92eaeeb..4b36c8810517 100644
--- a/drivers/dma/k3dma.c
+++ b/drivers/dma/k3dma.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2013 - 2015 Linaro Ltd.
* Copyright (c) 2013 Hisilicon Limited.
- *
- * 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.
*/
#include <linux/sched.h>
#include <linux/device.h>
diff --git a/drivers/dma/lpc18xx-dmamux.c b/drivers/dma/lpc18xx-dmamux.c
index 761f32687055..df98cae8792b 100644
--- a/drivers/dma/lpc18xx-dmamux.c
+++ b/drivers/dma/lpc18xx-dmamux.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* DMA Router driver for LPC18xx/43xx DMA MUX
*
@@ -6,11 +7,6 @@
* Based on TI DMA Crossbar driver by:
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
* Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
- *
- * 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.
- *
*/
#include <linux/err.h>
diff --git a/drivers/dma/mcf-edma.c b/drivers/dma/mcf-edma.c
index 7de54b2fafdb..e15bd15a9ef6 100644
--- a/drivers/dma/mcf-edma.c
+++ b/drivers/dma/mcf-edma.c
@@ -164,6 +164,11 @@ static void mcf_edma_irq_free(struct platform_device *pdev,
free_irq(irq, mcf_edma);
}
+static struct fsl_edma_drvdata mcf_data = {
+ .version = v2,
+ .setup_irq = mcf_edma_irq_init,
+};
+
static int mcf_edma_probe(struct platform_device *pdev)
{
struct mcf_edma_platform_data *pdata;
@@ -187,8 +192,8 @@ static int mcf_edma_probe(struct platform_device *pdev)
mcf_edma->n_chans = chans;
- /* Set up version for ColdFire edma */
- mcf_edma->version = v2;
+ /* Set up drvdata for ColdFire edma */
+ mcf_edma->drvdata = &mcf_data;
mcf_edma->big_endian = 1;
if (!mcf_edma->n_chans) {
@@ -223,7 +228,7 @@ static int mcf_edma_probe(struct platform_device *pdev)
iowrite32(~0, regs->inth);
iowrite32(~0, regs->intl);
- ret = mcf_edma_irq_init(pdev, mcf_edma);
+ ret = mcf_edma->drvdata->setup_irq(pdev, mcf_edma);
if (ret)
return ret;
diff --git a/drivers/dma/mediatek/Kconfig b/drivers/dma/mediatek/Kconfig
index 7411eb3d419e..1ad63ddc292d 100644
--- a/drivers/dma/mediatek/Kconfig
+++ b/drivers/dma/mediatek/Kconfig
@@ -25,3 +25,14 @@ config MTK_CQDMA
This controller provides the channels which is dedicated to
memory-to-memory transfer to offload from CPU.
+
+config MTK_UART_APDMA
+ tristate "MediaTek SoCs APDMA support for UART"
+ depends on OF && SERIAL_8250_MT6577
+ select DMA_ENGINE
+ select DMA_VIRTUAL_CHANNELS
+ help
+ Support for the UART DMA engine found on MediaTek MTK SoCs.
+ When SERIAL_8250_MT6577 is enabled, and if you want to use DMA,
+ you can enable the config. The DMA engine can only be used
+ with MediaTek SoCs.
diff --git a/drivers/dma/mediatek/Makefile b/drivers/dma/mediatek/Makefile
index 13b144594510..5ba39a5edc13 100644
--- a/drivers/dma/mediatek/Makefile
+++ b/drivers/dma/mediatek/Makefile
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_MTK_UART_APDMA) += mtk-uart-apdma.o
obj-$(CONFIG_MTK_HSDMA) += mtk-hsdma.o
obj-$(CONFIG_MTK_CQDMA) += mtk-cqdma.o
diff --git a/drivers/dma/mediatek/mtk-uart-apdma.c b/drivers/dma/mediatek/mtk-uart-apdma.c
new file mode 100644
index 000000000000..546995c20876
--- /dev/null
+++ b/drivers/dma/mediatek/mtk-uart-apdma.c
@@ -0,0 +1,666 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek UART APDMA driver.
+ *
+ * Copyright (c) 2019 MediaTek Inc.
+ * Author: Long Cheng <long.cheng@mediatek.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_dma.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include "../virt-dma.h"
+
+/* The default number of virtual channel */
+#define MTK_UART_APDMA_NR_VCHANS 8
+
+#define VFF_EN_B BIT(0)
+#define VFF_STOP_B BIT(0)
+#define VFF_FLUSH_B BIT(0)
+#define VFF_4G_EN_B BIT(0)
+/* rx valid size >= vff thre */
+#define VFF_RX_INT_EN_B (BIT(0) | BIT(1))
+/* tx left size >= vff thre */
+#define VFF_TX_INT_EN_B BIT(0)
+#define VFF_WARM_RST_B BIT(0)
+#define VFF_RX_INT_CLR_B (BIT(0) | BIT(1))
+#define VFF_TX_INT_CLR_B 0
+#define VFF_STOP_CLR_B 0
+#define VFF_EN_CLR_B 0
+#define VFF_INT_EN_CLR_B 0
+#define VFF_4G_SUPPORT_CLR_B 0
+
+/*
+ * interrupt trigger level for tx
+ * if threshold is n, no polling is required to start tx.
+ * otherwise need polling VFF_FLUSH.
+ */
+#define VFF_TX_THRE(n) (n)
+/* interrupt trigger level for rx */
+#define VFF_RX_THRE(n) ((n) * 3 / 4)
+
+#define VFF_RING_SIZE 0xffff
+/* invert this bit when wrap ring head again */
+#define VFF_RING_WRAP 0x10000
+
+#define VFF_INT_FLAG 0x00
+#define VFF_INT_EN 0x04
+#define VFF_EN 0x08
+#define VFF_RST 0x0c
+#define VFF_STOP 0x10
+#define VFF_FLUSH 0x14
+#define VFF_ADDR 0x1c
+#define VFF_LEN 0x24
+#define VFF_THRE 0x28
+#define VFF_WPT 0x2c
+#define VFF_RPT 0x30
+/* TX: the buffer size HW can read. RX: the buffer size SW can read. */
+#define VFF_VALID_SIZE 0x3c
+/* TX: the buffer size SW can write. RX: the buffer size HW can write. */
+#define VFF_LEFT_SIZE 0x40
+#define VFF_DEBUG_STATUS 0x50
+#define VFF_4G_SUPPORT 0x54
+
+struct mtk_uart_apdmadev {
+ struct dma_device ddev;
+ struct clk *clk;
+ bool support_33bits;
+ unsigned int dma_requests;
+};
+
+struct mtk_uart_apdma_desc {
+ struct virt_dma_desc vd;
+
+ dma_addr_t addr;
+ unsigned int avail_len;
+};
+
+struct mtk_chan {
+ struct virt_dma_chan vc;
+ struct dma_slave_config cfg;
+ struct mtk_uart_apdma_desc *desc;
+ enum dma_transfer_direction dir;
+
+ void __iomem *base;
+ unsigned int irq;
+
+ unsigned int rx_status;
+};
+
+static inline struct mtk_uart_apdmadev *
+to_mtk_uart_apdma_dev(struct dma_device *d)
+{
+ return container_of(d, struct mtk_uart_apdmadev, ddev);
+}
+
+static inline struct mtk_chan *to_mtk_uart_apdma_chan(struct dma_chan *c)
+{
+ return container_of(c, struct mtk_chan, vc.chan);
+}
+
+static inline struct mtk_uart_apdma_desc *to_mtk_uart_apdma_desc
+ (struct dma_async_tx_descriptor *t)
+{
+ return container_of(t, struct mtk_uart_apdma_desc, vd.tx);
+}
+
+static void mtk_uart_apdma_write(struct mtk_chan *c,
+ unsigned int reg, unsigned int val)
+{
+ writel(val, c->base + reg);
+}
+
+static unsigned int mtk_uart_apdma_read(struct mtk_chan *c, unsigned int reg)
+{
+ return readl(c->base + reg);
+}
+
+static void mtk_uart_apdma_desc_free(struct virt_dma_desc *vd)
+{
+ struct dma_chan *chan = vd->tx.chan;
+ struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+
+ kfree(c->desc);
+}
+
+static void mtk_uart_apdma_start_tx(struct mtk_chan *c)
+{
+ struct mtk_uart_apdmadev *mtkd =
+ to_mtk_uart_apdma_dev(c->vc.chan.device);
+ struct mtk_uart_apdma_desc *d = c->desc;
+ unsigned int wpt, vff_sz;
+
+ vff_sz = c->cfg.dst_port_window_size;
+ if (!mtk_uart_apdma_read(c, VFF_LEN)) {
+ mtk_uart_apdma_write(c, VFF_ADDR, d->addr);
+ mtk_uart_apdma_write(c, VFF_LEN, vff_sz);
+ mtk_uart_apdma_write(c, VFF_THRE, VFF_TX_THRE(vff_sz));
+ mtk_uart_apdma_write(c, VFF_WPT, 0);
+ mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_TX_INT_CLR_B);
+
+ if (mtkd->support_33bits)
+ mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_EN_B);
+ }
+
+ mtk_uart_apdma_write(c, VFF_EN, VFF_EN_B);
+ if (mtk_uart_apdma_read(c, VFF_EN) != VFF_EN_B)
+ dev_err(c->vc.chan.device->dev, "Enable TX fail\n");
+
+ if (!mtk_uart_apdma_read(c, VFF_LEFT_SIZE)) {
+ mtk_uart_apdma_write(c, VFF_INT_EN, VFF_TX_INT_EN_B);
+ return;
+ }
+
+ wpt = mtk_uart_apdma_read(c, VFF_WPT);
+
+ wpt += c->desc->avail_len;
+ if ((wpt & VFF_RING_SIZE) == vff_sz)
+ wpt = (wpt & VFF_RING_WRAP) ^ VFF_RING_WRAP;
+
+ /* Let DMA start moving data */
+ mtk_uart_apdma_write(c, VFF_WPT, wpt);
+
+ /* HW auto set to 0 when left size >= threshold */
+ mtk_uart_apdma_write(c, VFF_INT_EN, VFF_TX_INT_EN_B);
+ if (!mtk_uart_apdma_read(c, VFF_FLUSH))
+ mtk_uart_apdma_write(c, VFF_FLUSH, VFF_FLUSH_B);
+}
+
+static void mtk_uart_apdma_start_rx(struct mtk_chan *c)
+{
+ struct mtk_uart_apdmadev *mtkd =
+ to_mtk_uart_apdma_dev(c->vc.chan.device);
+ struct mtk_uart_apdma_desc *d = c->desc;
+ unsigned int vff_sz;
+
+ vff_sz = c->cfg.src_port_window_size;
+ if (!mtk_uart_apdma_read(c, VFF_LEN)) {
+ mtk_uart_apdma_write(c, VFF_ADDR, d->addr);
+ mtk_uart_apdma_write(c, VFF_LEN, vff_sz);
+ mtk_uart_apdma_write(c, VFF_THRE, VFF_RX_THRE(vff_sz));
+ mtk_uart_apdma_write(c, VFF_RPT, 0);
+ mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_RX_INT_CLR_B);
+
+ if (mtkd->support_33bits)
+ mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_EN_B);
+ }
+
+ mtk_uart_apdma_write(c, VFF_INT_EN, VFF_RX_INT_EN_B);
+ mtk_uart_apdma_write(c, VFF_EN, VFF_EN_B);
+ if (mtk_uart_apdma_read(c, VFF_EN) != VFF_EN_B)
+ dev_err(c->vc.chan.device->dev, "Enable RX fail\n");
+}
+
+static void mtk_uart_apdma_tx_handler(struct mtk_chan *c)
+{
+ struct mtk_uart_apdma_desc *d = c->desc;
+
+ mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_TX_INT_CLR_B);
+ mtk_uart_apdma_write(c, VFF_INT_EN, VFF_INT_EN_CLR_B);
+ mtk_uart_apdma_write(c, VFF_EN, VFF_EN_CLR_B);
+
+ list_del(&d->vd.node);
+ vchan_cookie_complete(&d->vd);
+}
+
+static void mtk_uart_apdma_rx_handler(struct mtk_chan *c)
+{
+ struct mtk_uart_apdma_desc *d = c->desc;
+ unsigned int len, wg, rg;
+ int cnt;
+
+ mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_RX_INT_CLR_B);
+
+ if (!mtk_uart_apdma_read(c, VFF_VALID_SIZE))
+ return;
+
+ mtk_uart_apdma_write(c, VFF_EN, VFF_EN_CLR_B);
+ mtk_uart_apdma_write(c, VFF_INT_EN, VFF_INT_EN_CLR_B);
+
+ len = c->cfg.src_port_window_size;
+ rg = mtk_uart_apdma_read(c, VFF_RPT);
+ wg = mtk_uart_apdma_read(c, VFF_WPT);
+ cnt = (wg & VFF_RING_SIZE) - (rg & VFF_RING_SIZE);
+
+ /*
+ * The buffer is ring buffer. If wrap bit different,
+ * represents the start of the next cycle for WPT
+ */
+ if ((rg ^ wg) & VFF_RING_WRAP)
+ cnt += len;
+
+ c->rx_status = d->avail_len - cnt;
+ mtk_uart_apdma_write(c, VFF_RPT, wg);
+
+ list_del(&d->vd.node);
+ vchan_cookie_complete(&d->vd);
+}
+
+static irqreturn_t mtk_uart_apdma_irq_handler(int irq, void *dev_id)
+{
+ struct dma_chan *chan = (struct dma_chan *)dev_id;
+ struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+ unsigned long flags;
+
+ spin_lock_irqsave(&c->vc.lock, flags);
+ if (c->dir == DMA_DEV_TO_MEM)
+ mtk_uart_apdma_rx_handler(c);
+ else if (c->dir == DMA_MEM_TO_DEV)
+ mtk_uart_apdma_tx_handler(c);
+ spin_unlock_irqrestore(&c->vc.lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static int mtk_uart_apdma_alloc_chan_resources(struct dma_chan *chan)
+{
+ struct mtk_uart_apdmadev *mtkd = to_mtk_uart_apdma_dev(chan->device);
+ struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+ unsigned int status;
+ int ret;
+
+ ret = pm_runtime_get_sync(mtkd->ddev.dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(chan->device->dev);
+ return ret;
+ }
+
+ mtk_uart_apdma_write(c, VFF_ADDR, 0);
+ mtk_uart_apdma_write(c, VFF_THRE, 0);
+ mtk_uart_apdma_write(c, VFF_LEN, 0);
+ mtk_uart_apdma_write(c, VFF_RST, VFF_WARM_RST_B);
+
+ ret = readx_poll_timeout(readl, c->base + VFF_EN,
+ status, !status, 10, 100);
+ if (ret)
+ return ret;
+
+ ret = request_irq(c->irq, mtk_uart_apdma_irq_handler,
+ IRQF_TRIGGER_NONE, KBUILD_MODNAME, chan);
+ if (ret < 0) {
+ dev_err(chan->device->dev, "Can't request dma IRQ\n");
+ return -EINVAL;
+ }
+
+ if (mtkd->support_33bits)
+ mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_SUPPORT_CLR_B);
+
+ return ret;
+}
+
+static void mtk_uart_apdma_free_chan_resources(struct dma_chan *chan)
+{
+ struct mtk_uart_apdmadev *mtkd = to_mtk_uart_apdma_dev(chan->device);
+ struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+
+ free_irq(c->irq, chan);
+
+ tasklet_kill(&c->vc.task);
+
+ vchan_free_chan_resources(&c->vc);
+
+ pm_runtime_put_sync(mtkd->ddev.dev);
+}
+
+static enum dma_status mtk_uart_apdma_tx_status(struct dma_chan *chan,
+ dma_cookie_t cookie,
+ struct dma_tx_state *txstate)
+{
+ struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+ enum dma_status ret;
+
+ ret = dma_cookie_status(chan, cookie, txstate);
+ if (!txstate)
+ return ret;
+
+ dma_set_residue(txstate, c->rx_status);
+
+ return ret;
+}
+
+/*
+ * dmaengine_prep_slave_single will call the function. and sglen is 1.
+ * 8250 uart using one ring buffer, and deal with one sg.
+ */
+static struct dma_async_tx_descriptor *mtk_uart_apdma_prep_slave_sg
+ (struct dma_chan *chan, struct scatterlist *sgl,
+ unsigned int sglen, enum dma_transfer_direction dir,
+ unsigned long tx_flags, void *context)
+{
+ struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+ struct mtk_uart_apdma_desc *d;
+
+ if (!is_slave_direction(dir) || sglen != 1)
+ return NULL;
+
+ /* Now allocate and setup the descriptor */
+ d = kzalloc(sizeof(*d), GFP_ATOMIC);
+ if (!d)
+ return NULL;
+
+ d->avail_len = sg_dma_len(sgl);
+ d->addr = sg_dma_address(sgl);
+ c->dir = dir;
+
+ return vchan_tx_prep(&c->vc, &d->vd, tx_flags);
+}
+
+static void mtk_uart_apdma_issue_pending(struct dma_chan *chan)
+{
+ struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+ struct virt_dma_desc *vd;
+ unsigned long flags;
+
+ spin_lock_irqsave(&c->vc.lock, flags);
+ if (vchan_issue_pending(&c->vc)) {
+ vd = vchan_next_desc(&c->vc);
+ c->desc = to_mtk_uart_apdma_desc(&vd->tx);
+
+ if (c->dir == DMA_DEV_TO_MEM)
+ mtk_uart_apdma_start_rx(c);
+ else if (c->dir == DMA_MEM_TO_DEV)
+ mtk_uart_apdma_start_tx(c);
+ }
+
+ spin_unlock_irqrestore(&c->vc.lock, flags);
+}
+
+static int mtk_uart_apdma_slave_config(struct dma_chan *chan,
+ struct dma_slave_config *config)
+{
+ struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+
+ memcpy(&c->cfg, config, sizeof(*config));
+
+ return 0;
+}
+
+static int mtk_uart_apdma_terminate_all(struct dma_chan *chan)
+{
+ struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+ unsigned long flags;
+ unsigned int status;
+ LIST_HEAD(head);
+ int ret;
+
+ mtk_uart_apdma_write(c, VFF_FLUSH, VFF_FLUSH_B);
+
+ ret = readx_poll_timeout(readl, c->base + VFF_FLUSH,
+ status, status != VFF_FLUSH_B, 10, 100);
+ if (ret)
+ dev_err(c->vc.chan.device->dev, "flush: fail, status=0x%x\n",
+ mtk_uart_apdma_read(c, VFF_DEBUG_STATUS));
+
+ /*
+ * Stop need 3 steps.
+ * 1. set stop to 1
+ * 2. wait en to 0
+ * 3. set stop as 0
+ */
+ mtk_uart_apdma_write(c, VFF_STOP, VFF_STOP_B);
+ ret = readx_poll_timeout(readl, c->base + VFF_EN,
+ status, !status, 10, 100);
+ if (ret)
+ dev_err(c->vc.chan.device->dev, "stop: fail, status=0x%x\n",
+ mtk_uart_apdma_read(c, VFF_DEBUG_STATUS));
+
+ mtk_uart_apdma_write(c, VFF_STOP, VFF_STOP_CLR_B);
+ mtk_uart_apdma_write(c, VFF_INT_EN, VFF_INT_EN_CLR_B);
+
+ if (c->dir == DMA_DEV_TO_MEM)
+ mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_RX_INT_CLR_B);
+ else if (c->dir == DMA_MEM_TO_DEV)
+ mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_TX_INT_CLR_B);
+
+ synchronize_irq(c->irq);
+
+ spin_lock_irqsave(&c->vc.lock, flags);
+ vchan_get_all_descriptors(&c->vc, &head);
+ vchan_dma_desc_free_list(&c->vc, &head);
+ spin_unlock_irqrestore(&c->vc.lock, flags);
+
+ return 0;
+}
+
+static int mtk_uart_apdma_device_pause(struct dma_chan *chan)
+{
+ struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+ unsigned long flags;
+
+ spin_lock_irqsave(&c->vc.lock, flags);
+
+ mtk_uart_apdma_write(c, VFF_EN, VFF_EN_CLR_B);
+ mtk_uart_apdma_write(c, VFF_INT_EN, VFF_INT_EN_CLR_B);
+
+ synchronize_irq(c->irq);
+
+ spin_unlock_irqrestore(&c->vc.lock, flags);
+
+ return 0;
+}
+
+static void mtk_uart_apdma_free(struct mtk_uart_apdmadev *mtkd)
+{
+ while (!list_empty(&mtkd->ddev.channels)) {
+ struct mtk_chan *c = list_first_entry(&mtkd->ddev.channels,
+ struct mtk_chan, vc.chan.device_node);
+
+ list_del(&c->vc.chan.device_node);
+ tasklet_kill(&c->vc.task);
+ }
+}
+
+static const struct of_device_id mtk_uart_apdma_match[] = {
+ { .compatible = "mediatek,mt6577-uart-dma", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, mtk_uart_apdma_match);
+
+static int mtk_uart_apdma_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct mtk_uart_apdmadev *mtkd;
+ int bit_mask = 32, rc;
+ struct resource *res;
+ struct mtk_chan *c;
+ unsigned int i;
+
+ mtkd = devm_kzalloc(&pdev->dev, sizeof(*mtkd), GFP_KERNEL);
+ if (!mtkd)
+ return -ENOMEM;
+
+ mtkd->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(mtkd->clk)) {
+ dev_err(&pdev->dev, "No clock specified\n");
+ rc = PTR_ERR(mtkd->clk);
+ return rc;
+ }
+
+ if (of_property_read_bool(np, "mediatek,dma-33bits"))
+ mtkd->support_33bits = true;
+
+ if (mtkd->support_33bits)
+ bit_mask = 33;
+
+ rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(bit_mask));
+ if (rc)
+ return rc;
+
+ dma_cap_set(DMA_SLAVE, mtkd->ddev.cap_mask);
+ mtkd->ddev.device_alloc_chan_resources =
+ mtk_uart_apdma_alloc_chan_resources;
+ mtkd->ddev.device_free_chan_resources =
+ mtk_uart_apdma_free_chan_resources;
+ mtkd->ddev.device_tx_status = mtk_uart_apdma_tx_status;
+ mtkd->ddev.device_issue_pending = mtk_uart_apdma_issue_pending;
+ mtkd->ddev.device_prep_slave_sg = mtk_uart_apdma_prep_slave_sg;
+ mtkd->ddev.device_config = mtk_uart_apdma_slave_config;
+ mtkd->ddev.device_pause = mtk_uart_apdma_device_pause;
+ mtkd->ddev.device_terminate_all = mtk_uart_apdma_terminate_all;
+ mtkd->ddev.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE);
+ mtkd->ddev.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE);
+ mtkd->ddev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+ mtkd->ddev.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
+ mtkd->ddev.dev = &pdev->dev;
+ INIT_LIST_HEAD(&mtkd->ddev.channels);
+
+ mtkd->dma_requests = MTK_UART_APDMA_NR_VCHANS;
+ if (of_property_read_u32(np, "dma-requests", &mtkd->dma_requests)) {
+ dev_info(&pdev->dev,
+ "Using %u as missing dma-requests property\n",
+ MTK_UART_APDMA_NR_VCHANS);
+ }
+
+ for (i = 0; i < mtkd->dma_requests; i++) {
+ c = devm_kzalloc(mtkd->ddev.dev, sizeof(*c), GFP_KERNEL);
+ if (!c) {
+ rc = -ENODEV;
+ goto err_no_dma;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+ if (!res) {
+ rc = -ENODEV;
+ goto err_no_dma;
+ }
+
+ c->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(c->base)) {
+ rc = PTR_ERR(c->base);
+ goto err_no_dma;
+ }
+ c->vc.desc_free = mtk_uart_apdma_desc_free;
+ vchan_init(&c->vc, &mtkd->ddev);
+
+ rc = platform_get_irq(pdev, i);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "failed to get IRQ[%d]\n", i);
+ goto err_no_dma;
+ }
+ c->irq = rc;
+ }
+
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+
+ rc = dma_async_device_register(&mtkd->ddev);
+ if (rc)
+ goto rpm_disable;
+
+ platform_set_drvdata(pdev, mtkd);
+
+ /* Device-tree DMA controller registration */
+ rc = of_dma_controller_register(np, of_dma_xlate_by_chan_id, mtkd);
+ if (rc)
+ goto dma_remove;
+
+ return rc;
+
+dma_remove:
+ dma_async_device_unregister(&mtkd->ddev);
+rpm_disable:
+ pm_runtime_disable(&pdev->dev);
+err_no_dma:
+ mtk_uart_apdma_free(mtkd);
+ return rc;
+}
+
+static int mtk_uart_apdma_remove(struct platform_device *pdev)
+{
+ struct mtk_uart_apdmadev *mtkd = platform_get_drvdata(pdev);
+
+ of_dma_controller_free(pdev->dev.of_node);
+
+ mtk_uart_apdma_free(mtkd);
+
+ dma_async_device_unregister(&mtkd->ddev);
+
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mtk_uart_apdma_suspend(struct device *dev)
+{
+ struct mtk_uart_apdmadev *mtkd = dev_get_drvdata(dev);
+
+ if (!pm_runtime_suspended(dev))
+ clk_disable_unprepare(mtkd->clk);
+
+ return 0;
+}
+
+static int mtk_uart_apdma_resume(struct device *dev)
+{
+ int ret;
+ struct mtk_uart_apdmadev *mtkd = dev_get_drvdata(dev);
+
+ if (!pm_runtime_suspended(dev)) {
+ ret = clk_prepare_enable(mtkd->clk);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM
+static int mtk_uart_apdma_runtime_suspend(struct device *dev)
+{
+ struct mtk_uart_apdmadev *mtkd = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(mtkd->clk);
+
+ return 0;
+}
+
+static int mtk_uart_apdma_runtime_resume(struct device *dev)
+{
+ int ret;
+ struct mtk_uart_apdmadev *mtkd = dev_get_drvdata(dev);
+
+ ret = clk_prepare_enable(mtkd->clk);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+static const struct dev_pm_ops mtk_uart_apdma_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(mtk_uart_apdma_suspend, mtk_uart_apdma_resume)
+ SET_RUNTIME_PM_OPS(mtk_uart_apdma_runtime_suspend,
+ mtk_uart_apdma_runtime_resume, NULL)
+};
+
+static struct platform_driver mtk_uart_apdma_driver = {
+ .probe = mtk_uart_apdma_probe,
+ .remove = mtk_uart_apdma_remove,
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .pm = &mtk_uart_apdma_pm_ops,
+ .of_match_table = of_match_ptr(mtk_uart_apdma_match),
+ },
+};
+
+module_platform_driver(mtk_uart_apdma_driver);
+
+MODULE_DESCRIPTION("MediaTek UART APDMA Controller Driver");
+MODULE_AUTHOR("Long Cheng <long.cheng@mediatek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/dma/mic_x100_dma.c b/drivers/dma/mic_x100_dma.c
index 730a18d0c6d6..fea8608a7810 100644
--- a/drivers/dma/mic_x100_dma.c
+++ b/drivers/dma/mic_x100_dma.c
@@ -717,10 +717,8 @@ static int mic_dma_driver_probe(struct mbus_device *mbdev)
if (mic_dma_dbg) {
mic_dma_dev->dbg_dir = debugfs_create_dir(dev_name(&mbdev->dev),
mic_dma_dbg);
- if (mic_dma_dev->dbg_dir)
- debugfs_create_file("mic_dma_reg", 0444,
- mic_dma_dev->dbg_dir, mic_dma_dev,
- &mic_dma_reg_fops);
+ debugfs_create_file("mic_dma_reg", 0444, mic_dma_dev->dbg_dir,
+ mic_dma_dev, &mic_dma_reg_fops);
}
return 0;
}
diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c
index 334bab92d26d..7fe494fc50d4 100644
--- a/drivers/dma/mmp_pdma.c
+++ b/drivers/dma/mmp_pdma.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2012 Marvell International Ltd.
- *
- * 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.
*/
#include <linux/err.h>
diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c
index bb3ccbf90a31..e7d1e12bf464 100644
--- a/drivers/dma/mmp_tdma.c
+++ b/drivers/dma/mmp_tdma.c
@@ -582,18 +582,12 @@ static int mmp_tdma_chan_init(struct mmp_tdma_device *tdev,
}
struct mmp_tdma_filter_param {
- struct device_node *of_node;
unsigned int chan_id;
};
static bool mmp_tdma_filter_fn(struct dma_chan *chan, void *fn_param)
{
struct mmp_tdma_filter_param *param = fn_param;
- struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
- struct dma_device *pdma_device = tdmac->chan.device;
-
- if (pdma_device->dev->of_node != param->of_node)
- return false;
if (chan->chan_id != param->chan_id)
return false;
@@ -611,13 +605,13 @@ static struct dma_chan *mmp_tdma_xlate(struct of_phandle_args *dma_spec,
if (dma_spec->args_count != 1)
return NULL;
- param.of_node = ofdma->of_node;
param.chan_id = dma_spec->args[0];
if (param.chan_id >= TDMA_CHANNEL_NUM)
return NULL;
- return dma_request_channel(mask, mmp_tdma_filter_fn, &param);
+ return __dma_request_channel(&mask, mmp_tdma_filter_fn, &param,
+ ofdma->of_node);
}
static const struct of_device_id mmp_tdma_dt_ids[] = {
diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c
index 22cc7f68ef6e..3039bba0e4d5 100644
--- a/drivers/dma/mxs-dma.c
+++ b/drivers/dma/mxs-dma.c
@@ -24,6 +24,7 @@
#include <linux/of_device.h>
#include <linux/of_dma.h>
#include <linux/list.h>
+#include <linux/dma/mxs-dma.h>
#include <asm/irq.h>
@@ -77,6 +78,7 @@
#define BM_CCW_COMMAND (3 << 0)
#define CCW_CHAIN (1 << 2)
#define CCW_IRQ (1 << 3)
+#define CCW_WAIT4RDY (1 << 5)
#define CCW_DEC_SEM (1 << 6)
#define CCW_WAIT4END (1 << 7)
#define CCW_HALT_ON_TERM (1 << 8)
@@ -477,16 +479,16 @@ static void mxs_dma_free_chan_resources(struct dma_chan *chan)
* ......
* ->device_prep_slave_sg(0);
* ......
- * ->device_prep_slave_sg(DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ * ->device_prep_slave_sg(DMA_CTRL_ACK);
* ......
* [3] If there are more than two DMA commands in the DMA chain, the code
* should be:
* ......
* ->device_prep_slave_sg(0); // First
* ......
- * ->device_prep_slave_sg(DMA_PREP_INTERRUPT [| DMA_CTRL_ACK]);
+ * ->device_prep_slave_sg(DMA_CTRL_ACK]);
* ......
- * ->device_prep_slave_sg(DMA_PREP_INTERRUPT | DMA_CTRL_ACK); // Last
+ * ->device_prep_slave_sg(DMA_CTRL_ACK); // Last
* ......
*/
static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
@@ -500,13 +502,12 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
struct scatterlist *sg;
u32 i, j;
u32 *pio;
- bool append = flags & DMA_PREP_INTERRUPT;
- int idx = append ? mxs_chan->desc_count : 0;
+ int idx = 0;
- if (mxs_chan->status == DMA_IN_PROGRESS && !append)
- return NULL;
+ if (mxs_chan->status == DMA_IN_PROGRESS)
+ idx = mxs_chan->desc_count;
- if (sg_len + (append ? idx : 0) > NUM_CCW) {
+ if (sg_len + idx > NUM_CCW) {
dev_err(mxs_dma->dma_device.dev,
"maximum number of sg exceeded: %d > %d\n",
sg_len, NUM_CCW);
@@ -520,7 +521,7 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
* If the sg is prepared with append flag set, the sg
* will be appended to the last prepared sg.
*/
- if (append) {
+ if (idx) {
BUG_ON(idx < 1);
ccw = &mxs_chan->ccw[idx - 1];
ccw->next = mxs_chan->ccw_phys + sizeof(*ccw) * idx;
@@ -541,12 +542,14 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
ccw->bits = 0;
ccw->bits |= CCW_IRQ;
ccw->bits |= CCW_DEC_SEM;
- if (flags & DMA_CTRL_ACK)
+ if (flags & MXS_DMA_CTRL_WAIT4END)
ccw->bits |= CCW_WAIT4END;
ccw->bits |= CCW_HALT_ON_TERM;
ccw->bits |= CCW_TERM_FLUSH;
ccw->bits |= BF_CCW(sg_len, PIO_NUM);
ccw->bits |= BF_CCW(MXS_DMA_CMD_NO_XFER, COMMAND);
+ if (flags & MXS_DMA_CTRL_WAIT4RDY)
+ ccw->bits |= CCW_WAIT4RDY;
} else {
for_each_sg(sgl, sg, sg_len, i) {
if (sg_dma_len(sg) > MAX_XFER_BYTES) {
@@ -573,7 +576,7 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
ccw->bits &= ~CCW_CHAIN;
ccw->bits |= CCW_IRQ;
ccw->bits |= CCW_DEC_SEM;
- if (flags & DMA_CTRL_ACK)
+ if (flags & MXS_DMA_CTRL_WAIT4END)
ccw->bits |= CCW_WAIT4END;
}
}
@@ -716,7 +719,6 @@ err_out:
}
struct mxs_dma_filter_param {
- struct device_node *of_node;
unsigned int chan_id;
};
@@ -727,9 +729,6 @@ static bool mxs_dma_filter_fn(struct dma_chan *chan, void *fn_param)
struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
int chan_irq;
- if (mxs_dma->dma_device.dev->of_node != param->of_node)
- return false;
-
if (chan->chan_id != param->chan_id)
return false;
@@ -752,13 +751,13 @@ static struct dma_chan *mxs_dma_xlate(struct of_phandle_args *dma_spec,
if (dma_spec->args_count != 1)
return NULL;
- param.of_node = ofdma->of_node;
param.chan_id = dma_spec->args[0];
if (param.chan_id >= mxs_dma->nr_channels)
return NULL;
- return dma_request_channel(mask, mxs_dma_filter_fn, &param);
+ return __dma_request_channel(&mask, mxs_dma_filter_fn, &param,
+ ofdma->of_node);
}
static int __init mxs_dma_probe(struct platform_device *pdev)
diff --git a/drivers/dma/of-dma.c b/drivers/dma/of-dma.c
index 91fd395c90c4..c2d779daa4b5 100644
--- a/drivers/dma/of-dma.c
+++ b/drivers/dma/of-dma.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Device tree helpers for DMA request / controller
*
* Based on of_gpio.c
*
* Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
- *
- * 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.
*/
#include <linux/device.h>
@@ -316,8 +313,8 @@ struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec,
if (count != 1)
return NULL;
- return dma_request_channel(info->dma_cap, info->filter_fn,
- &dma_spec->args[0]);
+ return __dma_request_channel(&info->dma_cap, info->filter_fn,
+ &dma_spec->args[0], dma_spec->np);
}
EXPORT_SYMBOL_GPL(of_dma_simple_xlate);
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index 56f9fabc99c4..1163af2ba4a3 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -25,6 +25,7 @@
#include <linux/err.h>
#include <linux/pm_runtime.h>
#include <linux/bug.h>
+#include <linux/reset.h>
#include "dmaengine.h"
#define PL330_MAX_CHAN 8
@@ -496,6 +497,9 @@ struct pl330_dmac {
unsigned int num_peripherals;
struct dma_pl330_chan *peripherals; /* keep at end */
int quirks;
+
+ struct reset_control *rstc;
+ struct reset_control *rstc_ocp;
};
static struct pl330_of_quirks {
@@ -3024,6 +3028,32 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
amba_set_drvdata(adev, pl330);
+ pl330->rstc = devm_reset_control_get_optional(&adev->dev, "dma");
+ if (IS_ERR(pl330->rstc)) {
+ if (PTR_ERR(pl330->rstc) != -EPROBE_DEFER)
+ dev_err(&adev->dev, "Failed to get reset!\n");
+ return PTR_ERR(pl330->rstc);
+ } else {
+ ret = reset_control_deassert(pl330->rstc);
+ if (ret) {
+ dev_err(&adev->dev, "Couldn't deassert the device from reset!\n");
+ return ret;
+ }
+ }
+
+ pl330->rstc_ocp = devm_reset_control_get_optional(&adev->dev, "dma-ocp");
+ if (IS_ERR(pl330->rstc_ocp)) {
+ if (PTR_ERR(pl330->rstc_ocp) != -EPROBE_DEFER)
+ dev_err(&adev->dev, "Failed to get OCP reset!\n");
+ return PTR_ERR(pl330->rstc_ocp);
+ } else {
+ ret = reset_control_deassert(pl330->rstc_ocp);
+ if (ret) {
+ dev_err(&adev->dev, "Couldn't deassert the device from OCP reset!\n");
+ return ret;
+ }
+ }
+
for (i = 0; i < AMBA_NR_IRQS; i++) {
irq = adev->irq[i];
if (irq) {
@@ -3164,6 +3194,11 @@ probe_err3:
probe_err2:
pl330_del(pl330);
+ if (pl330->rstc_ocp)
+ reset_control_assert(pl330->rstc_ocp);
+
+ if (pl330->rstc)
+ reset_control_assert(pl330->rstc);
return ret;
}
@@ -3202,6 +3237,11 @@ static int pl330_remove(struct amba_device *adev)
pl330_del(pl330);
+ if (pl330->rstc_ocp)
+ reset_control_assert(pl330->rstc_ocp);
+
+ if (pl330->rstc)
+ reset_control_assert(pl330->rstc);
return 0;
}
diff --git a/drivers/dma/pxa_dma.c b/drivers/dma/pxa_dma.c
index b429642f3e7a..349fb312c872 100644
--- a/drivers/dma/pxa_dma.c
+++ b/drivers/dma/pxa_dma.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2015 Robert Jarzmik <robert.jarzmik@free.fr>
- *
- * 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.
*/
#include <linux/err.h>
@@ -132,7 +129,6 @@ struct pxad_device {
spinlock_t phy_lock; /* Phy association */
#ifdef CONFIG_DEBUG_FS
struct dentry *dbgfs_root;
- struct dentry *dbgfs_state;
struct dentry **dbgfs_chan;
#endif
};
@@ -326,31 +322,18 @@ static struct dentry *pxad_dbg_alloc_chan(struct pxad_device *pdev,
int ch, struct dentry *chandir)
{
char chan_name[11];
- struct dentry *chan, *chan_state = NULL, *chan_descr = NULL;
- struct dentry *chan_reqs = NULL;
+ struct dentry *chan;
void *dt;
scnprintf(chan_name, sizeof(chan_name), "%d", ch);
chan = debugfs_create_dir(chan_name, chandir);
dt = (void *)&pdev->phys[ch];
- if (chan)
- chan_state = debugfs_create_file("state", 0400, chan, dt,
- &chan_state_fops);
- if (chan_state)
- chan_descr = debugfs_create_file("descriptors", 0400, chan, dt,
- &descriptors_fops);
- if (chan_descr)
- chan_reqs = debugfs_create_file("requesters", 0400, chan, dt,
- &requester_chan_fops);
- if (!chan_reqs)
- goto err_state;
+ debugfs_create_file("state", 0400, chan, dt, &chan_state_fops);
+ debugfs_create_file("descriptors", 0400, chan, dt, &descriptors_fops);
+ debugfs_create_file("requesters", 0400, chan, dt, &requester_chan_fops);
return chan;
-
-err_state:
- debugfs_remove_recursive(chan);
- return NULL;
}
static void pxad_init_debugfs(struct pxad_device *pdev)
@@ -358,40 +341,20 @@ static void pxad_init_debugfs(struct pxad_device *pdev)
int i;
struct dentry *chandir;
- pdev->dbgfs_root = debugfs_create_dir(dev_name(pdev->slave.dev), NULL);
- if (IS_ERR(pdev->dbgfs_root) || !pdev->dbgfs_root)
- goto err_root;
-
- pdev->dbgfs_state = debugfs_create_file("state", 0400, pdev->dbgfs_root,
- pdev, &state_fops);
- if (!pdev->dbgfs_state)
- goto err_state;
-
pdev->dbgfs_chan =
- kmalloc_array(pdev->nr_chans, sizeof(*pdev->dbgfs_state),
+ kmalloc_array(pdev->nr_chans, sizeof(struct dentry *),
GFP_KERNEL);
if (!pdev->dbgfs_chan)
- goto err_alloc;
+ return;
+
+ pdev->dbgfs_root = debugfs_create_dir(dev_name(pdev->slave.dev), NULL);
+
+ debugfs_create_file("state", 0400, pdev->dbgfs_root, pdev, &state_fops);
chandir = debugfs_create_dir("channels", pdev->dbgfs_root);
- if (!chandir)
- goto err_chandir;
- for (i = 0; i < pdev->nr_chans; i++) {
+ for (i = 0; i < pdev->nr_chans; i++)
pdev->dbgfs_chan[i] = pxad_dbg_alloc_chan(pdev, i, chandir);
- if (!pdev->dbgfs_chan[i])
- goto err_chans;
- }
-
- return;
-err_chans:
-err_chandir:
- kfree(pdev->dbgfs_chan);
-err_alloc:
-err_state:
- debugfs_remove_recursive(pdev->dbgfs_root);
-err_root:
- pr_err("pxad: debugfs is not available\n");
}
static void pxad_cleanup_debugfs(struct pxad_device *pdev)
diff --git a/drivers/dma/qcom/bam_dma.c b/drivers/dma/qcom/bam_dma.c
index 4b43844f6af5..8e90a405939d 100644
--- a/drivers/dma/qcom/bam_dma.c
+++ b/drivers/dma/qcom/bam_dma.c
@@ -799,6 +799,9 @@ static u32 process_channel_irqs(struct bam_device *bdev)
/* Number of bytes available to read */
avail = CIRC_CNT(offset, bchan->head, MAX_DESCRIPTORS + 1);
+ if (offset < bchan->head)
+ avail--;
+
list_for_each_entry_safe(async_desc, tmp,
&bchan->desc_list, desc_node) {
/* Not enough data to read */
diff --git a/drivers/dma/qcom/hidma.h b/drivers/dma/qcom/hidma.h
index f337e2789ddc..f212466744f3 100644
--- a/drivers/dma/qcom/hidma.h
+++ b/drivers/dma/qcom/hidma.h
@@ -93,8 +93,6 @@ struct hidma_chan {
* It is used by the DMA complete notification to
* locate the descriptor that initiated the transfer.
*/
- struct dentry *debugfs;
- struct dentry *stats;
struct hidma_dev *dmadev;
struct hidma_desc *running;
@@ -126,7 +124,6 @@ struct hidma_dev {
struct dma_device ddev;
struct dentry *debugfs;
- struct dentry *stats;
/* sysfs entry for the channel id */
struct device_attribute *chid_attrs;
@@ -158,6 +155,6 @@ irqreturn_t hidma_ll_inthandler(int irq, void *arg);
irqreturn_t hidma_ll_inthandler_msi(int irq, void *arg, int cause);
void hidma_cleanup_pending_tre(struct hidma_lldev *llhndl, u8 err_info,
u8 err_code);
-int hidma_debug_init(struct hidma_dev *dmadev);
+void hidma_debug_init(struct hidma_dev *dmadev);
void hidma_debug_uninit(struct hidma_dev *dmadev);
#endif
diff --git a/drivers/dma/qcom/hidma_dbg.c b/drivers/dma/qcom/hidma_dbg.c
index 75b0691a670d..ce87c7937a0e 100644
--- a/drivers/dma/qcom/hidma_dbg.c
+++ b/drivers/dma/qcom/hidma_dbg.c
@@ -138,17 +138,13 @@ void hidma_debug_uninit(struct hidma_dev *dmadev)
debugfs_remove_recursive(dmadev->debugfs);
}
-int hidma_debug_init(struct hidma_dev *dmadev)
+void hidma_debug_init(struct hidma_dev *dmadev)
{
- int rc = 0;
int chidx = 0;
struct list_head *position = NULL;
+ struct dentry *dir;
dmadev->debugfs = debugfs_create_dir(dev_name(dmadev->ddev.dev), NULL);
- if (!dmadev->debugfs) {
- rc = -ENODEV;
- return rc;
- }
/* walk through the virtual channel list */
list_for_each(position, &dmadev->ddev.channels) {
@@ -157,32 +153,13 @@ int hidma_debug_init(struct hidma_dev *dmadev)
chan = list_entry(position, struct hidma_chan,
chan.device_node);
sprintf(chan->dbg_name, "chan%d", chidx);
- chan->debugfs = debugfs_create_dir(chan->dbg_name,
+ dir = debugfs_create_dir(chan->dbg_name,
dmadev->debugfs);
- if (!chan->debugfs) {
- rc = -ENOMEM;
- goto cleanup;
- }
- chan->stats = debugfs_create_file("stats", S_IRUGO,
- chan->debugfs, chan,
- &hidma_chan_fops);
- if (!chan->stats) {
- rc = -ENOMEM;
- goto cleanup;
- }
+ debugfs_create_file("stats", S_IRUGO, dir, chan,
+ &hidma_chan_fops);
chidx++;
}
- dmadev->stats = debugfs_create_file("stats", S_IRUGO,
- dmadev->debugfs, dmadev,
- &hidma_dma_fops);
- if (!dmadev->stats) {
- rc = -ENOMEM;
- goto cleanup;
- }
-
- return 0;
-cleanup:
- hidma_debug_uninit(dmadev);
- return rc;
+ debugfs_create_file("stats", S_IRUGO, dmadev->debugfs, dmadev,
+ &hidma_dma_fops);
}
diff --git a/drivers/dma/sa11x0-dma.c b/drivers/dma/sa11x0-dma.c
index 3fae23768b47..afb68055ed1b 100644
--- a/drivers/dma/sa11x0-dma.c
+++ b/drivers/dma/sa11x0-dma.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* SA11x0 DMAengine support
*
* Copyright (C) 2012 Russell King
* Derived in part from arch/arm/mach-sa1100/dma.c,
* Copyright (C) 2000, 2001 by Nicolas Pitre
- *
- * 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.
*/
#include <linux/sched.h>
#include <linux/device.h>
diff --git a/drivers/dma/sh/Kconfig b/drivers/dma/sh/Kconfig
index 4d6b02b3b1f1..54d5d0369d3c 100644
--- a/drivers/dma/sh/Kconfig
+++ b/drivers/dma/sh/Kconfig
@@ -47,9 +47,3 @@ config RENESAS_USB_DMAC
help
This driver supports the USB-DMA controller found in the Renesas
SoCs.
-
-config SUDMAC
- tristate "Renesas SUDMAC support"
- depends on SH_DMAE_BASE
- help
- Enable support for the Renesas SUDMAC controllers.
diff --git a/drivers/dma/sh/Makefile b/drivers/dma/sh/Makefile
index 42110dd57a56..112fbd22bb3f 100644
--- a/drivers/dma/sh/Makefile
+++ b/drivers/dma/sh/Makefile
@@ -15,4 +15,3 @@ obj-$(CONFIG_SH_DMAE) += shdma.o
obj-$(CONFIG_RCAR_DMAC) += rcar-dmac.o
obj-$(CONFIG_RENESAS_USB_DMAC) += usb-dmac.o
-obj-$(CONFIG_SUDMAC) += sudmac.o
diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c
index 33ab1b607e2b..9c41a4e42575 100644
--- a/drivers/dma/sh/rcar-dmac.c
+++ b/drivers/dma/sh/rcar-dmac.c
@@ -1165,7 +1165,7 @@ rcar_dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
/* Someone calling slave DMA on a generic channel? */
- if (rchan->mid_rid < 0 || !sg_len) {
+ if (rchan->mid_rid < 0 || !sg_len || !sg_dma_len(sgl)) {
dev_warn(chan->device->dev,
"%s: bad parameter: len=%d, id=%d\n",
__func__, sg_len, rchan->mid_rid);
@@ -1654,8 +1654,7 @@ static bool rcar_dmac_chan_filter(struct dma_chan *chan, void *arg)
* Forcing it to call dma_request_channel() and iterate through all
* channels from all controllers is just pointless.
*/
- if (chan->device->device_config != rcar_dmac_device_config ||
- dma_spec->np != chan->device->dev->of_node)
+ if (chan->device->device_config != rcar_dmac_device_config)
return false;
return !test_and_set_bit(dma_spec->args[0], dmac->modules);
@@ -1675,7 +1674,8 @@ static struct dma_chan *rcar_dmac_of_xlate(struct of_phandle_args *dma_spec,
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
- chan = dma_request_channel(mask, rcar_dmac_chan_filter, dma_spec);
+ chan = __dma_request_channel(&mask, rcar_dmac_chan_filter, dma_spec,
+ ofdma->of_node);
if (!chan)
return NULL;
diff --git a/drivers/dma/sh/sudmac.c b/drivers/dma/sh/sudmac.c
deleted file mode 100644
index 30cc3553cb8b..000000000000
--- a/drivers/dma/sh/sudmac.c
+++ /dev/null
@@ -1,414 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Renesas SUDMAC support
- *
- * Copyright (C) 2013 Renesas Solutions Corp.
- *
- * based on drivers/dma/sh/shdma.c:
- * Copyright (C) 2011-2012 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- * Copyright (C) 2009 Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
- * Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved.
- * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
- */
-
-#include <linux/dmaengine.h>
-#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/sudmac.h>
-
-struct sudmac_chan {
- struct shdma_chan shdma_chan;
- void __iomem *base;
- char dev_id[16]; /* unique name per DMAC of channel */
-
- u32 offset; /* for CFG, BA, BBC, CA, CBC, DEN */
- u32 cfg;
- u32 dint_end_bit;
-};
-
-struct sudmac_device {
- struct shdma_dev shdma_dev;
- struct sudmac_pdata *pdata;
- void __iomem *chan_reg;
-};
-
-struct sudmac_regs {
- u32 base_addr;
- u32 base_byte_count;
-};
-
-struct sudmac_desc {
- struct sudmac_regs hw;
- struct shdma_desc shdma_desc;
-};
-
-#define to_chan(schan) container_of(schan, struct sudmac_chan, shdma_chan)
-#define to_desc(sdesc) container_of(sdesc, struct sudmac_desc, shdma_desc)
-#define to_sdev(sc) container_of(sc->shdma_chan.dma_chan.device, \
- struct sudmac_device, shdma_dev.dma_dev)
-
-/* SUDMAC register */
-#define SUDMAC_CH0CFG 0x00
-#define SUDMAC_CH0BA 0x10
-#define SUDMAC_CH0BBC 0x18
-#define SUDMAC_CH0CA 0x20
-#define SUDMAC_CH0CBC 0x28
-#define SUDMAC_CH0DEN 0x30
-#define SUDMAC_DSTSCLR 0x38
-#define SUDMAC_DBUFCTRL 0x3C
-#define SUDMAC_DINTCTRL 0x40
-#define SUDMAC_DINTSTS 0x44
-#define SUDMAC_DINTSTSCLR 0x48
-#define SUDMAC_CH0SHCTRL 0x50
-
-/* Definitions for the sudmac_channel.config */
-#define SUDMAC_SENDBUFM 0x1000 /* b12: Transmit Buffer Mode */
-#define SUDMAC_RCVENDM 0x0100 /* b8: Receive Data Transfer End Mode */
-#define SUDMAC_LBA_WAIT 0x0030 /* b5-4: Local Bus Access Wait */
-
-/* Definitions for the sudmac_channel.dint_end_bit */
-#define SUDMAC_CH1ENDE 0x0002 /* b1: Ch1 DMA Transfer End Int Enable */
-#define SUDMAC_CH0ENDE 0x0001 /* b0: Ch0 DMA Transfer End Int Enable */
-
-#define SUDMAC_DRV_NAME "sudmac"
-
-static void sudmac_writel(struct sudmac_chan *sc, u32 data, u32 reg)
-{
- iowrite32(data, sc->base + reg);
-}
-
-static u32 sudmac_readl(struct sudmac_chan *sc, u32 reg)
-{
- return ioread32(sc->base + reg);
-}
-
-static bool sudmac_is_busy(struct sudmac_chan *sc)
-{
- u32 den = sudmac_readl(sc, SUDMAC_CH0DEN + sc->offset);
-
- if (den)
- return true; /* working */
-
- return false; /* waiting */
-}
-
-static void sudmac_set_reg(struct sudmac_chan *sc, struct sudmac_regs *hw,
- struct shdma_desc *sdesc)
-{
- sudmac_writel(sc, sc->cfg, SUDMAC_CH0CFG + sc->offset);
- sudmac_writel(sc, hw->base_addr, SUDMAC_CH0BA + sc->offset);
- sudmac_writel(sc, hw->base_byte_count, SUDMAC_CH0BBC + sc->offset);
-}
-
-static void sudmac_start(struct sudmac_chan *sc)
-{
- u32 dintctrl = sudmac_readl(sc, SUDMAC_DINTCTRL);
-
- sudmac_writel(sc, dintctrl | sc->dint_end_bit, SUDMAC_DINTCTRL);
- sudmac_writel(sc, 1, SUDMAC_CH0DEN + sc->offset);
-}
-
-static void sudmac_start_xfer(struct shdma_chan *schan,
- struct shdma_desc *sdesc)
-{
- struct sudmac_chan *sc = to_chan(schan);
- struct sudmac_desc *sd = to_desc(sdesc);
-
- sudmac_set_reg(sc, &sd->hw, sdesc);
- sudmac_start(sc);
-}
-
-static bool sudmac_channel_busy(struct shdma_chan *schan)
-{
- struct sudmac_chan *sc = to_chan(schan);
-
- return sudmac_is_busy(sc);
-}
-
-static void sudmac_setup_xfer(struct shdma_chan *schan, int slave_id)
-{
-}
-
-static const struct sudmac_slave_config *sudmac_find_slave(
- struct sudmac_chan *sc, int slave_id)
-{
- struct sudmac_device *sdev = to_sdev(sc);
- struct sudmac_pdata *pdata = sdev->pdata;
- const struct sudmac_slave_config *cfg;
- int i;
-
- for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
- if (cfg->slave_id == slave_id)
- return cfg;
-
- return NULL;
-}
-
-static int sudmac_set_slave(struct shdma_chan *schan, int slave_id,
- dma_addr_t slave_addr, bool try)
-{
- struct sudmac_chan *sc = to_chan(schan);
- const struct sudmac_slave_config *cfg = sudmac_find_slave(sc, slave_id);
-
- if (!cfg)
- return -ENODEV;
-
- return 0;
-}
-
-static inline void sudmac_dma_halt(struct sudmac_chan *sc)
-{
- u32 dintctrl = sudmac_readl(sc, SUDMAC_DINTCTRL);
-
- sudmac_writel(sc, 0, SUDMAC_CH0DEN + sc->offset);
- sudmac_writel(sc, dintctrl & ~sc->dint_end_bit, SUDMAC_DINTCTRL);
- sudmac_writel(sc, sc->dint_end_bit, SUDMAC_DINTSTSCLR);
-}
-
-static int sudmac_desc_setup(struct shdma_chan *schan,
- struct shdma_desc *sdesc,
- dma_addr_t src, dma_addr_t dst, size_t *len)
-{
- struct sudmac_chan *sc = to_chan(schan);
- struct sudmac_desc *sd = to_desc(sdesc);
-
- dev_dbg(sc->shdma_chan.dev, "%s: src=%pad, dst=%pad, len=%zu\n",
- __func__, &src, &dst, *len);
-
- if (*len > schan->max_xfer_len)
- *len = schan->max_xfer_len;
-
- if (dst)
- sd->hw.base_addr = dst;
- else if (src)
- sd->hw.base_addr = src;
- sd->hw.base_byte_count = *len;
-
- return 0;
-}
-
-static void sudmac_halt(struct shdma_chan *schan)
-{
- struct sudmac_chan *sc = to_chan(schan);
-
- sudmac_dma_halt(sc);
-}
-
-static bool sudmac_chan_irq(struct shdma_chan *schan, int irq)
-{
- struct sudmac_chan *sc = to_chan(schan);
- u32 dintsts = sudmac_readl(sc, SUDMAC_DINTSTS);
-
- if (!(dintsts & sc->dint_end_bit))
- return false;
-
- /* DMA stop */
- sudmac_dma_halt(sc);
-
- return true;
-}
-
-static size_t sudmac_get_partial(struct shdma_chan *schan,
- struct shdma_desc *sdesc)
-{
- struct sudmac_chan *sc = to_chan(schan);
- struct sudmac_desc *sd = to_desc(sdesc);
- u32 current_byte_count = sudmac_readl(sc, SUDMAC_CH0CBC + sc->offset);
-
- return sd->hw.base_byte_count - current_byte_count;
-}
-
-static bool sudmac_desc_completed(struct shdma_chan *schan,
- struct shdma_desc *sdesc)
-{
- struct sudmac_chan *sc = to_chan(schan);
- struct sudmac_desc *sd = to_desc(sdesc);
- u32 current_addr = sudmac_readl(sc, SUDMAC_CH0CA + sc->offset);
-
- return sd->hw.base_addr + sd->hw.base_byte_count == current_addr;
-}
-
-static int sudmac_chan_probe(struct sudmac_device *su_dev, int id, int irq,
- unsigned long flags)
-{
- struct shdma_dev *sdev = &su_dev->shdma_dev;
- struct platform_device *pdev = to_platform_device(sdev->dma_dev.dev);
- struct sudmac_chan *sc;
- struct shdma_chan *schan;
- int err;
-
- sc = devm_kzalloc(&pdev->dev, sizeof(struct sudmac_chan), GFP_KERNEL);
- if (!sc)
- return -ENOMEM;
-
- schan = &sc->shdma_chan;
- schan->max_xfer_len = 64 * 1024 * 1024 - 1;
-
- shdma_chan_probe(sdev, schan, id);
-
- sc->base = su_dev->chan_reg;
-
- /* get platform_data */
- sc->offset = su_dev->pdata->channel->offset;
- if (su_dev->pdata->channel->config & SUDMAC_TX_BUFFER_MODE)
- sc->cfg |= SUDMAC_SENDBUFM;
- if (su_dev->pdata->channel->config & SUDMAC_RX_END_MODE)
- sc->cfg |= SUDMAC_RCVENDM;
- sc->cfg |= (su_dev->pdata->channel->wait << 4) & SUDMAC_LBA_WAIT;
-
- if (su_dev->pdata->channel->dint_end_bit & SUDMAC_DMA_BIT_CH0)
- sc->dint_end_bit |= SUDMAC_CH0ENDE;
- if (su_dev->pdata->channel->dint_end_bit & SUDMAC_DMA_BIT_CH1)
- sc->dint_end_bit |= SUDMAC_CH1ENDE;
-
- /* set up channel irq */
- if (pdev->id >= 0)
- snprintf(sc->dev_id, sizeof(sc->dev_id), "sudmac%d.%d",
- pdev->id, id);
- else
- snprintf(sc->dev_id, sizeof(sc->dev_id), "sudmac%d", id);
-
- err = shdma_request_irq(schan, irq, flags, sc->dev_id);
- if (err) {
- dev_err(sdev->dma_dev.dev,
- "DMA channel %d request_irq failed %d\n", id, err);
- goto err_no_irq;
- }
-
- return 0;
-
-err_no_irq:
- /* remove from dmaengine device node */
- shdma_chan_remove(schan);
- return err;
-}
-
-static void sudmac_chan_remove(struct sudmac_device *su_dev)
-{
- struct shdma_chan *schan;
- int i;
-
- shdma_for_each_chan(schan, &su_dev->shdma_dev, i) {
- BUG_ON(!schan);
-
- shdma_chan_remove(schan);
- }
-}
-
-static dma_addr_t sudmac_slave_addr(struct shdma_chan *schan)
-{
- /* SUDMAC doesn't need the address */
- return 0;
-}
-
-static struct shdma_desc *sudmac_embedded_desc(void *buf, int i)
-{
- return &((struct sudmac_desc *)buf)[i].shdma_desc;
-}
-
-static const struct shdma_ops sudmac_shdma_ops = {
- .desc_completed = sudmac_desc_completed,
- .halt_channel = sudmac_halt,
- .channel_busy = sudmac_channel_busy,
- .slave_addr = sudmac_slave_addr,
- .desc_setup = sudmac_desc_setup,
- .set_slave = sudmac_set_slave,
- .setup_xfer = sudmac_setup_xfer,
- .start_xfer = sudmac_start_xfer,
- .embedded_desc = sudmac_embedded_desc,
- .chan_irq = sudmac_chan_irq,
- .get_partial = sudmac_get_partial,
-};
-
-static int sudmac_probe(struct platform_device *pdev)
-{
- struct sudmac_pdata *pdata = dev_get_platdata(&pdev->dev);
- int err, i;
- struct sudmac_device *su_dev;
- struct dma_device *dma_dev;
- struct resource *chan, *irq_res;
-
- /* get platform data */
- if (!pdata)
- return -ENODEV;
-
- irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!irq_res)
- return -ENODEV;
-
- err = -ENOMEM;
- su_dev = devm_kzalloc(&pdev->dev, sizeof(struct sudmac_device),
- GFP_KERNEL);
- if (!su_dev)
- return err;
-
- dma_dev = &su_dev->shdma_dev.dma_dev;
-
- chan = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- su_dev->chan_reg = devm_ioremap_resource(&pdev->dev, chan);
- if (IS_ERR(su_dev->chan_reg))
- return PTR_ERR(su_dev->chan_reg);
-
- dma_cap_set(DMA_SLAVE, dma_dev->cap_mask);
-
- su_dev->shdma_dev.ops = &sudmac_shdma_ops;
- su_dev->shdma_dev.desc_size = sizeof(struct sudmac_desc);
- err = shdma_init(&pdev->dev, &su_dev->shdma_dev, pdata->channel_num);
- if (err < 0)
- return err;
-
- /* platform data */
- su_dev->pdata = dev_get_platdata(&pdev->dev);
-
- platform_set_drvdata(pdev, su_dev);
-
- /* Create DMA Channel */
- for (i = 0; i < pdata->channel_num; i++) {
- err = sudmac_chan_probe(su_dev, i, irq_res->start, IRQF_SHARED);
- if (err)
- goto chan_probe_err;
- }
-
- err = dma_async_device_register(&su_dev->shdma_dev.dma_dev);
- if (err < 0)
- goto chan_probe_err;
-
- return err;
-
-chan_probe_err:
- sudmac_chan_remove(su_dev);
-
- shdma_cleanup(&su_dev->shdma_dev);
-
- return err;
-}
-
-static int sudmac_remove(struct platform_device *pdev)
-{
- struct sudmac_device *su_dev = platform_get_drvdata(pdev);
- struct dma_device *dma_dev = &su_dev->shdma_dev.dma_dev;
-
- dma_async_device_unregister(dma_dev);
- sudmac_chan_remove(su_dev);
- shdma_cleanup(&su_dev->shdma_dev);
-
- return 0;
-}
-
-static struct platform_driver sudmac_driver = {
- .driver = {
- .name = SUDMAC_DRV_NAME,
- },
- .probe = sudmac_probe,
- .remove = sudmac_remove,
-};
-module_platform_driver(sudmac_driver);
-
-MODULE_AUTHOR("Yoshihiro Shimoda");
-MODULE_DESCRIPTION("Renesas SUDMAC driver");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:" SUDMAC_DRV_NAME);
diff --git a/drivers/dma/sh/usb-dmac.c b/drivers/dma/sh/usb-dmac.c
index 59403f6d008a..17063aaf51bc 100644
--- a/drivers/dma/sh/usb-dmac.c
+++ b/drivers/dma/sh/usb-dmac.c
@@ -57,7 +57,7 @@ struct usb_dmac_desc {
u32 residue;
struct list_head node;
dma_cookie_t done_cookie;
- struct usb_dmac_sg sg[0];
+ struct usb_dmac_sg sg[];
};
#define to_usb_dmac_desc(vd) container_of(vd, struct usb_dmac_desc, vd)
@@ -636,9 +636,6 @@ static bool usb_dmac_chan_filter(struct dma_chan *chan, void *arg)
struct usb_dmac_chan *uchan = to_usb_dmac_chan(chan);
struct of_phandle_args *dma_spec = arg;
- if (dma_spec->np != chan->device->dev->of_node)
- return false;
-
/* USB-DMAC should be used with fixed usb controller's FIFO */
if (uchan->index != dma_spec->args[0])
return false;
@@ -659,7 +656,8 @@ static struct dma_chan *usb_dmac_of_xlate(struct of_phandle_args *dma_spec,
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
- chan = dma_request_channel(mask, usb_dmac_chan_filter, dma_spec);
+ chan = __dma_request_channel(&mask, usb_dmac_chan_filter, dma_spec,
+ ofdma->of_node);
if (!chan)
return NULL;
diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c
index da41bab98f5b..ef4d109e7189 100644
--- a/drivers/dma/stm32-dma.c
+++ b/drivers/dma/stm32-dma.c
@@ -1365,7 +1365,6 @@ static int stm32_dma_probe(struct platform_device *pdev)
for (i = 0; i < STM32_DMA_MAX_CHANNELS; i++) {
chan = &dmadev->chan[i];
- chan->irq = platform_get_irq(pdev, i);
ret = platform_get_irq(pdev, i);
if (ret < 0) {
if (ret != -EPROBE_DEFER)
diff --git a/drivers/dma/stm32-dmamux.c b/drivers/dma/stm32-dmamux.c
index 715aad7a9192..b552949da14b 100644
--- a/drivers/dma/stm32-dmamux.c
+++ b/drivers/dma/stm32-dmamux.c
@@ -295,8 +295,7 @@ static int stm32_dmamux_probe(struct platform_device *pdev)
#ifdef CONFIG_PM
static int stm32_dmamux_runtime_suspend(struct device *dev)
{
- struct platform_device *pdev =
- container_of(dev, struct platform_device, dev);
+ struct platform_device *pdev = to_platform_device(dev);
struct stm32_dmamux_data *stm32_dmamux = platform_get_drvdata(pdev);
clk_disable_unprepare(stm32_dmamux->clk);
@@ -306,8 +305,7 @@ static int stm32_dmamux_runtime_suspend(struct device *dev)
static int stm32_dmamux_runtime_resume(struct device *dev)
{
- struct platform_device *pdev =
- container_of(dev, struct platform_device, dev);
+ struct platform_device *pdev = to_platform_device(dev);
struct stm32_dmamux_data *stm32_dmamux = platform_get_drvdata(pdev);
int ret;
diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
index e8fcc69b1de9..ed5b68dcfe50 100644
--- a/drivers/dma/sun6i-dma.c
+++ b/drivers/dma/sun6i-dma.c
@@ -64,17 +64,20 @@
#define DMA_CHAN_LLI_ADDR 0x08
#define DMA_CHAN_CUR_CFG 0x0c
-#define DMA_CHAN_MAX_DRQ 0x1f
-#define DMA_CHAN_CFG_SRC_DRQ(x) ((x) & DMA_CHAN_MAX_DRQ)
-#define DMA_CHAN_CFG_SRC_IO_MODE BIT(5)
-#define DMA_CHAN_CFG_SRC_LINEAR_MODE (0 << 5)
+#define DMA_CHAN_MAX_DRQ_A31 0x1f
+#define DMA_CHAN_MAX_DRQ_H6 0x3f
+#define DMA_CHAN_CFG_SRC_DRQ_A31(x) ((x) & DMA_CHAN_MAX_DRQ_A31)
+#define DMA_CHAN_CFG_SRC_DRQ_H6(x) ((x) & DMA_CHAN_MAX_DRQ_H6)
+#define DMA_CHAN_CFG_SRC_MODE_A31(x) (((x) & 0x1) << 5)
+#define DMA_CHAN_CFG_SRC_MODE_H6(x) (((x) & 0x1) << 8)
#define DMA_CHAN_CFG_SRC_BURST_A31(x) (((x) & 0x3) << 7)
#define DMA_CHAN_CFG_SRC_BURST_H3(x) (((x) & 0x3) << 6)
#define DMA_CHAN_CFG_SRC_WIDTH(x) (((x) & 0x3) << 9)
-#define DMA_CHAN_CFG_DST_DRQ(x) (DMA_CHAN_CFG_SRC_DRQ(x) << 16)
-#define DMA_CHAN_CFG_DST_IO_MODE (DMA_CHAN_CFG_SRC_IO_MODE << 16)
-#define DMA_CHAN_CFG_DST_LINEAR_MODE (DMA_CHAN_CFG_SRC_LINEAR_MODE << 16)
+#define DMA_CHAN_CFG_DST_DRQ_A31(x) (DMA_CHAN_CFG_SRC_DRQ_A31(x) << 16)
+#define DMA_CHAN_CFG_DST_DRQ_H6(x) (DMA_CHAN_CFG_SRC_DRQ_H6(x) << 16)
+#define DMA_CHAN_CFG_DST_MODE_A31(x) (DMA_CHAN_CFG_SRC_MODE_A31(x) << 16)
+#define DMA_CHAN_CFG_DST_MODE_H6(x) (DMA_CHAN_CFG_SRC_MODE_H6(x) << 16)
#define DMA_CHAN_CFG_DST_BURST_A31(x) (DMA_CHAN_CFG_SRC_BURST_A31(x) << 16)
#define DMA_CHAN_CFG_DST_BURST_H3(x) (DMA_CHAN_CFG_SRC_BURST_H3(x) << 16)
#define DMA_CHAN_CFG_DST_WIDTH(x) (DMA_CHAN_CFG_SRC_WIDTH(x) << 16)
@@ -94,6 +97,8 @@
#define LLI_LAST_ITEM 0xfffff800
#define NORMAL_WAIT 8
#define DRQ_SDRAM 1
+#define LINEAR_MODE 0
+#define IO_MODE 1
/* forward declaration */
struct sun6i_dma_dev;
@@ -121,10 +126,13 @@ struct sun6i_dma_config {
*/
void (*clock_autogate_enable)(struct sun6i_dma_dev *);
void (*set_burst_length)(u32 *p_cfg, s8 src_burst, s8 dst_burst);
+ void (*set_drq)(u32 *p_cfg, s8 src_drq, s8 dst_drq);
+ void (*set_mode)(u32 *p_cfg, s8 src_mode, s8 dst_mode);
u32 src_burst_lengths;
u32 dst_burst_lengths;
u32 src_addr_widths;
u32 dst_addr_widths;
+ bool has_mbus_clk;
};
/*
@@ -178,6 +186,7 @@ struct sun6i_dma_dev {
struct dma_device slave;
void __iomem *base;
struct clk *clk;
+ struct clk *clk_mbus;
int irq;
spinlock_t lock;
struct reset_control *rstc;
@@ -305,6 +314,30 @@ static void sun6i_set_burst_length_h3(u32 *p_cfg, s8 src_burst, s8 dst_burst)
DMA_CHAN_CFG_DST_BURST_H3(dst_burst);
}
+static void sun6i_set_drq_a31(u32 *p_cfg, s8 src_drq, s8 dst_drq)
+{
+ *p_cfg |= DMA_CHAN_CFG_SRC_DRQ_A31(src_drq) |
+ DMA_CHAN_CFG_DST_DRQ_A31(dst_drq);
+}
+
+static void sun6i_set_drq_h6(u32 *p_cfg, s8 src_drq, s8 dst_drq)
+{
+ *p_cfg |= DMA_CHAN_CFG_SRC_DRQ_H6(src_drq) |
+ DMA_CHAN_CFG_DST_DRQ_H6(dst_drq);
+}
+
+static void sun6i_set_mode_a31(u32 *p_cfg, s8 src_mode, s8 dst_mode)
+{
+ *p_cfg |= DMA_CHAN_CFG_SRC_MODE_A31(src_mode) |
+ DMA_CHAN_CFG_DST_MODE_A31(dst_mode);
+}
+
+static void sun6i_set_mode_h6(u32 *p_cfg, s8 src_mode, s8 dst_mode)
+{
+ *p_cfg |= DMA_CHAN_CFG_SRC_MODE_H6(src_mode) |
+ DMA_CHAN_CFG_DST_MODE_H6(dst_mode);
+}
+
static size_t sun6i_get_chan_size(struct sun6i_pchan *pchan)
{
struct sun6i_desc *txd = pchan->desc;
@@ -628,14 +661,12 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
burst = convert_burst(8);
width = convert_buswidth(DMA_SLAVE_BUSWIDTH_4_BYTES);
- v_lli->cfg = DMA_CHAN_CFG_SRC_DRQ(DRQ_SDRAM) |
- DMA_CHAN_CFG_DST_DRQ(DRQ_SDRAM) |
- DMA_CHAN_CFG_DST_LINEAR_MODE |
- DMA_CHAN_CFG_SRC_LINEAR_MODE |
- DMA_CHAN_CFG_SRC_WIDTH(width) |
+ v_lli->cfg = DMA_CHAN_CFG_SRC_WIDTH(width) |
DMA_CHAN_CFG_DST_WIDTH(width);
sdev->cfg->set_burst_length(&v_lli->cfg, burst, burst);
+ sdev->cfg->set_drq(&v_lli->cfg, DRQ_SDRAM, DRQ_SDRAM);
+ sdev->cfg->set_mode(&v_lli->cfg, LINEAR_MODE, LINEAR_MODE);
sun6i_dma_lli_add(NULL, v_lli, p_lli, txd);
@@ -687,11 +718,9 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
if (dir == DMA_MEM_TO_DEV) {
v_lli->src = sg_dma_address(sg);
v_lli->dst = sconfig->dst_addr;
- v_lli->cfg = lli_cfg |
- DMA_CHAN_CFG_DST_IO_MODE |
- DMA_CHAN_CFG_SRC_LINEAR_MODE |
- DMA_CHAN_CFG_SRC_DRQ(DRQ_SDRAM) |
- DMA_CHAN_CFG_DST_DRQ(vchan->port);
+ v_lli->cfg = lli_cfg;
+ sdev->cfg->set_drq(&v_lli->cfg, DRQ_SDRAM, vchan->port);
+ sdev->cfg->set_mode(&v_lli->cfg, LINEAR_MODE, IO_MODE);
dev_dbg(chan2dev(chan),
"%s; chan: %d, dest: %pad, src: %pad, len: %u. flags: 0x%08lx\n",
@@ -702,11 +731,9 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
} else {
v_lli->src = sconfig->src_addr;
v_lli->dst = sg_dma_address(sg);
- v_lli->cfg = lli_cfg |
- DMA_CHAN_CFG_DST_LINEAR_MODE |
- DMA_CHAN_CFG_SRC_IO_MODE |
- DMA_CHAN_CFG_DST_DRQ(DRQ_SDRAM) |
- DMA_CHAN_CFG_SRC_DRQ(vchan->port);
+ v_lli->cfg = lli_cfg;
+ sdev->cfg->set_drq(&v_lli->cfg, vchan->port, DRQ_SDRAM);
+ sdev->cfg->set_mode(&v_lli->cfg, IO_MODE, LINEAR_MODE);
dev_dbg(chan2dev(chan),
"%s; chan: %d, dest: %pad, src: %pad, len: %u. flags: 0x%08lx\n",
@@ -772,19 +799,15 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_cyclic(
if (dir == DMA_MEM_TO_DEV) {
v_lli->src = buf_addr + period_len * i;
v_lli->dst = sconfig->dst_addr;
- v_lli->cfg = lli_cfg |
- DMA_CHAN_CFG_DST_IO_MODE |
- DMA_CHAN_CFG_SRC_LINEAR_MODE |
- DMA_CHAN_CFG_SRC_DRQ(DRQ_SDRAM) |
- DMA_CHAN_CFG_DST_DRQ(vchan->port);
+ v_lli->cfg = lli_cfg;
+ sdev->cfg->set_drq(&v_lli->cfg, DRQ_SDRAM, vchan->port);
+ sdev->cfg->set_mode(&v_lli->cfg, LINEAR_MODE, IO_MODE);
} else {
v_lli->src = sconfig->src_addr;
v_lli->dst = buf_addr + period_len * i;
- v_lli->cfg = lli_cfg |
- DMA_CHAN_CFG_DST_LINEAR_MODE |
- DMA_CHAN_CFG_SRC_IO_MODE |
- DMA_CHAN_CFG_DST_DRQ(DRQ_SDRAM) |
- DMA_CHAN_CFG_SRC_DRQ(vchan->port);
+ v_lli->cfg = lli_cfg;
+ sdev->cfg->set_drq(&v_lli->cfg, vchan->port, DRQ_SDRAM);
+ sdev->cfg->set_mode(&v_lli->cfg, IO_MODE, LINEAR_MODE);
}
prev = sun6i_dma_lli_add(prev, v_lli, p_lli, txd);
@@ -1049,6 +1072,8 @@ static struct sun6i_dma_config sun6i_a31_dma_cfg = {
.nr_max_requests = 30,
.nr_max_vchans = 53,
.set_burst_length = sun6i_set_burst_length_a31,
+ .set_drq = sun6i_set_drq_a31,
+ .set_mode = sun6i_set_mode_a31,
.src_burst_lengths = BIT(1) | BIT(8),
.dst_burst_lengths = BIT(1) | BIT(8),
.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
@@ -1070,6 +1095,8 @@ static struct sun6i_dma_config sun8i_a23_dma_cfg = {
.nr_max_vchans = 37,
.clock_autogate_enable = sun6i_enable_clock_autogate_a23,
.set_burst_length = sun6i_set_burst_length_a31,
+ .set_drq = sun6i_set_drq_a31,
+ .set_mode = sun6i_set_mode_a31,
.src_burst_lengths = BIT(1) | BIT(8),
.dst_burst_lengths = BIT(1) | BIT(8),
.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
@@ -1086,6 +1113,8 @@ static struct sun6i_dma_config sun8i_a83t_dma_cfg = {
.nr_max_vchans = 39,
.clock_autogate_enable = sun6i_enable_clock_autogate_a23,
.set_burst_length = sun6i_set_burst_length_a31,
+ .set_drq = sun6i_set_drq_a31,
+ .set_mode = sun6i_set_mode_a31,
.src_burst_lengths = BIT(1) | BIT(8),
.dst_burst_lengths = BIT(1) | BIT(8),
.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
@@ -1109,6 +1138,8 @@ static struct sun6i_dma_config sun8i_h3_dma_cfg = {
.nr_max_vchans = 34,
.clock_autogate_enable = sun6i_enable_clock_autogate_h3,
.set_burst_length = sun6i_set_burst_length_h3,
+ .set_drq = sun6i_set_drq_a31,
+ .set_mode = sun6i_set_mode_a31,
.src_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16),
.dst_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16),
.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
@@ -1128,6 +1159,8 @@ static struct sun6i_dma_config sun8i_h3_dma_cfg = {
static struct sun6i_dma_config sun50i_a64_dma_cfg = {
.clock_autogate_enable = sun6i_enable_clock_autogate_h3,
.set_burst_length = sun6i_set_burst_length_h3,
+ .set_drq = sun6i_set_drq_a31,
+ .set_mode = sun6i_set_mode_a31,
.src_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16),
.dst_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16),
.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
@@ -1141,6 +1174,28 @@ static struct sun6i_dma_config sun50i_a64_dma_cfg = {
};
/*
+ * The H6 binding uses the number of dma channels from the
+ * device tree node.
+ */
+static struct sun6i_dma_config sun50i_h6_dma_cfg = {
+ .clock_autogate_enable = sun6i_enable_clock_autogate_h3,
+ .set_burst_length = sun6i_set_burst_length_h3,
+ .set_drq = sun6i_set_drq_h6,
+ .set_mode = sun6i_set_mode_h6,
+ .src_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16),
+ .dst_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16),
+ .src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
+ BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
+ BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
+ BIT(DMA_SLAVE_BUSWIDTH_8_BYTES),
+ .dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
+ BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
+ BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
+ BIT(DMA_SLAVE_BUSWIDTH_8_BYTES),
+ .has_mbus_clk = true,
+};
+
+/*
* The V3s have only 8 physical channels, a maximum DRQ port id of 23,
* and a total of 24 usable source and destination endpoints.
*/
@@ -1151,6 +1206,8 @@ static struct sun6i_dma_config sun8i_v3s_dma_cfg = {
.nr_max_vchans = 24,
.clock_autogate_enable = sun6i_enable_clock_autogate_a23,
.set_burst_length = sun6i_set_burst_length_a31,
+ .set_drq = sun6i_set_drq_a31,
+ .set_mode = sun6i_set_mode_a31,
.src_burst_lengths = BIT(1) | BIT(8),
.dst_burst_lengths = BIT(1) | BIT(8),
.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
@@ -1168,6 +1225,7 @@ static const struct of_device_id sun6i_dma_match[] = {
{ .compatible = "allwinner,sun8i-h3-dma", .data = &sun8i_h3_dma_cfg },
{ .compatible = "allwinner,sun8i-v3s-dma", .data = &sun8i_v3s_dma_cfg },
{ .compatible = "allwinner,sun50i-a64-dma", .data = &sun50i_a64_dma_cfg },
+ { .compatible = "allwinner,sun50i-h6-dma", .data = &sun50i_h6_dma_cfg },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sun6i_dma_match);
@@ -1204,6 +1262,14 @@ static int sun6i_dma_probe(struct platform_device *pdev)
return PTR_ERR(sdc->clk);
}
+ if (sdc->cfg->has_mbus_clk) {
+ sdc->clk_mbus = devm_clk_get(&pdev->dev, "mbus");
+ if (IS_ERR(sdc->clk_mbus)) {
+ dev_err(&pdev->dev, "No mbus clock specified\n");
+ return PTR_ERR(sdc->clk_mbus);
+ }
+ }
+
sdc->rstc = devm_reset_control_get(&pdev->dev, NULL);
if (IS_ERR(sdc->rstc)) {
dev_err(&pdev->dev, "No reset controller specified\n");
@@ -1258,8 +1324,8 @@ static int sun6i_dma_probe(struct platform_device *pdev)
ret = of_property_read_u32(np, "dma-requests", &sdc->max_request);
if (ret && !sdc->max_request) {
dev_info(&pdev->dev, "Missing dma-requests, using %u.\n",
- DMA_CHAN_MAX_DRQ);
- sdc->max_request = DMA_CHAN_MAX_DRQ;
+ DMA_CHAN_MAX_DRQ_A31);
+ sdc->max_request = DMA_CHAN_MAX_DRQ_A31;
}
/*
@@ -1308,11 +1374,19 @@ static int sun6i_dma_probe(struct platform_device *pdev)
goto err_reset_assert;
}
+ if (sdc->cfg->has_mbus_clk) {
+ ret = clk_prepare_enable(sdc->clk_mbus);
+ if (ret) {
+ dev_err(&pdev->dev, "Couldn't enable mbus clock\n");
+ goto err_clk_disable;
+ }
+ }
+
ret = devm_request_irq(&pdev->dev, sdc->irq, sun6i_dma_interrupt, 0,
dev_name(&pdev->dev), sdc);
if (ret) {
dev_err(&pdev->dev, "Cannot request IRQ\n");
- goto err_clk_disable;
+ goto err_mbus_clk_disable;
}
ret = dma_async_device_register(&sdc->slave);
@@ -1337,6 +1411,8 @@ err_dma_unregister:
dma_async_device_unregister(&sdc->slave);
err_irq_disable:
sun6i_kill_tasklet(sdc);
+err_mbus_clk_disable:
+ clk_disable_unprepare(sdc->clk_mbus);
err_clk_disable:
clk_disable_unprepare(sdc->clk);
err_reset_assert:
@@ -1355,6 +1431,7 @@ static int sun6i_dma_remove(struct platform_device *pdev)
sun6i_kill_tasklet(sdc);
+ clk_disable_unprepare(sdc->clk_mbus);
clk_disable_unprepare(sdc->clk);
reset_control_assert(sdc->rstc);
diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index ef317c90fbe1..79e9593815f1 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -977,8 +977,12 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_slave_sg(
csr |= tdc->slave_id << TEGRA_APBDMA_CSR_REQ_SEL_SHIFT;
}
- if (flags & DMA_PREP_INTERRUPT)
+ if (flags & DMA_PREP_INTERRUPT) {
csr |= TEGRA_APBDMA_CSR_IE_EOC;
+ } else {
+ WARN_ON_ONCE(1);
+ return NULL;
+ }
apb_seq |= TEGRA_APBDMA_APBSEQ_WRAP_WORD_1;
@@ -1120,8 +1124,12 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_dma_cyclic(
csr |= tdc->slave_id << TEGRA_APBDMA_CSR_REQ_SEL_SHIFT;
}
- if (flags & DMA_PREP_INTERRUPT)
+ if (flags & DMA_PREP_INTERRUPT) {
csr |= TEGRA_APBDMA_CSR_IE_EOC;
+ } else {
+ WARN_ON_ONCE(1);
+ return NULL;
+ }
apb_seq |= TEGRA_APBDMA_APBSEQ_WRAP_WORD_1;
diff --git a/drivers/dma/ti/dma-crossbar.c b/drivers/dma/ti/dma-crossbar.c
index 9272b173c746..ad2f0a4cd6a4 100644
--- a/drivers/dma/ti/dma-crossbar.c
+++ b/drivers/dma/ti/dma-crossbar.c
@@ -1,11 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
* Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
- *
- * 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.
- *
*/
#include <linux/slab.h>
#include <linux/err.h>
diff --git a/drivers/dma/ti/omap-dma.c b/drivers/dma/ti/omap-dma.c
index a4a931ddf6f6..ba2489d4ea24 100644
--- a/drivers/dma/ti/omap-dma.c
+++ b/drivers/dma/ti/omap-dma.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* OMAP DMAengine support
- *
- * 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.
*/
#include <linux/delay.h>
#include <linux/dmaengine.h>
diff --git a/drivers/dma/txx9dmac.c b/drivers/dma/txx9dmac.c
index e8d0881b64d8..628bdf4430c7 100644
--- a/drivers/dma/txx9dmac.c
+++ b/drivers/dma/txx9dmac.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for the TXx9 SoC DMA Controller
*
* Copyright (C) 2009 Atsushi Nemoto
- *
- * 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.
*/
#include <linux/dma-mapping.h>
#include <linux/init.h>
diff --git a/drivers/dma/txx9dmac.h b/drivers/dma/txx9dmac.h
index f6517b928bab..aa53eafb1519 100644
--- a/drivers/dma/txx9dmac.h
+++ b/drivers/dma/txx9dmac.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Driver for the TXx9 SoC DMA Controller
*
* Copyright (C) 2009 Atsushi Nemoto
- *
- * 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.
*/
#ifndef TXX9DMAC_H
#define TXX9DMAC_H
diff --git a/drivers/dma/virt-dma.c b/drivers/dma/virt-dma.c
index 88ad8ed2a8d6..ec4adf4260a0 100644
--- a/drivers/dma/virt-dma.c
+++ b/drivers/dma/virt-dma.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Virtual DMA channel support for DMAengine
*
* Copyright (C) 2012 Russell King
- *
- * 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.
*/
#include <linux/device.h>
#include <linux/dmaengine.h>
@@ -101,7 +98,7 @@ static void vchan_complete(unsigned long arg)
}
spin_unlock_irq(&vc->lock);
- dmaengine_desc_callback_invoke(&cb, NULL);
+ dmaengine_desc_callback_invoke(&cb, &vd->tx_result);
list_for_each_entry_safe(vd, _vd, &head, node) {
dmaengine_desc_get_callback(&vd->tx, &cb);
@@ -109,7 +106,7 @@ static void vchan_complete(unsigned long arg)
list_del(&vd->node);
vchan_vdesc_fini(vd);
- dmaengine_desc_callback_invoke(&cb, NULL);
+ dmaengine_desc_callback_invoke(&cb, &vd->tx_result);
}
}
diff --git a/drivers/dma/virt-dma.h b/drivers/dma/virt-dma.h
index b09b75ab0751..ab158bac03a7 100644
--- a/drivers/dma/virt-dma.h
+++ b/drivers/dma/virt-dma.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Virtual DMA channel support for DMAengine
*
* Copyright (C) 2012 Russell King
- *
- * 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.
*/
#ifndef VIRT_DMA_H
#define VIRT_DMA_H
@@ -17,6 +14,7 @@
struct virt_dma_desc {
struct dma_async_tx_descriptor tx;
+ struct dmaengine_result tx_result;
/* protected by vc.lock */
struct list_head node;
};
@@ -65,6 +63,9 @@ static inline struct dma_async_tx_descriptor *vchan_tx_prep(struct virt_dma_chan
vd->tx.tx_submit = vchan_tx_submit;
vd->tx.desc_free = vchan_tx_desc_free;
+ vd->tx_result.result = DMA_TRANS_NOERROR;
+ vd->tx_result.residue = 0;
+
spin_lock_irqsave(&vc->lock, flags);
list_add_tail(&vd->node, &vc->desc_allocated);
spin_unlock_irqrestore(&vc->lock, flags);
diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
index 36c092349b5b..e7dc3c4dc8e0 100644
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -1095,7 +1095,7 @@ static void xilinx_dma_start(struct xilinx_dma_chan *chan)
static void xilinx_vdma_start_transfer(struct xilinx_dma_chan *chan)
{
struct xilinx_vdma_config *config = &chan->config;
- struct xilinx_dma_tx_descriptor *desc, *tail_desc;
+ struct xilinx_dma_tx_descriptor *desc;
u32 reg, j;
struct xilinx_vdma_tx_segment *segment, *last = NULL;
int i = 0;
@@ -1112,8 +1112,6 @@ static void xilinx_vdma_start_transfer(struct xilinx_dma_chan *chan)
desc = list_first_entry(&chan->pending_list,
struct xilinx_dma_tx_descriptor, node);
- tail_desc = list_last_entry(&chan->pending_list,
- struct xilinx_dma_tx_descriptor, node);
/* Configure the hardware using info in the config structure */
if (chan->has_vflip) {
diff --git a/drivers/dma/zx_dma.c b/drivers/dma/zx_dma.c
index 2571bc7693df..9f4436f7c914 100644
--- a/drivers/dma/zx_dma.c
+++ b/drivers/dma/zx_dma.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2015 Linaro.
- *
- * 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.
*/
#include <linux/sched.h>
#include <linux/device.h>
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 5e2e0348d460..200c04ce5b0e 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -460,6 +460,12 @@ config EDAC_ALTERA_SDMMC
Support for error detection and correction on the
Altera SDMMC FIFO Memory for Altera SoCs.
+config EDAC_SIFIVE
+ bool "Sifive platform EDAC driver"
+ depends on EDAC=y && RISCV
+ help
+ Support for error detection and correction on the SiFive SoCs.
+
config EDAC_SYNOPSYS
tristate "Synopsys DDR Memory Controller"
depends on ARCH_ZYNQ || ARCH_ZYNQMP
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index 89ad4a84a0f6..165ca65e1a3a 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -79,6 +79,7 @@ obj-$(CONFIG_EDAC_OCTEON_PCI) += octeon_edac-pci.o
obj-$(CONFIG_EDAC_THUNDERX) += thunderx_edac.o
obj-$(CONFIG_EDAC_ALTERA) += altera_edac.o
+obj-$(CONFIG_EDAC_SIFIVE) += sifive_edac.o
obj-$(CONFIG_EDAC_SYNOPSYS) += synopsys_edac.o
obj-$(CONFIG_EDAC_XGENE) += xgene_edac.o
obj-$(CONFIG_EDAC_TI) += ti_edac.o
diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c
index 8816f74a22b4..c2e693e34d43 100644
--- a/drivers/edac/altera_edac.c
+++ b/drivers/edac/altera_edac.c
@@ -1223,8 +1223,31 @@ static const struct edac_device_prv_data ocramecc_data = {
.inject_fops = &altr_edac_device_inject_fops,
};
+static int __maybe_unused
+altr_check_ocram_deps_init(struct altr_edac_device_dev *device)
+{
+ void __iomem *base = device->base;
+ int ret;
+
+ ret = altr_check_ecc_deps(device);
+ if (ret)
+ return ret;
+
+ /* Verify OCRAM has been initialized */
+ if (!ecc_test_bits(ALTR_A10_ECC_INITCOMPLETEA,
+ (base + ALTR_A10_ECC_INITSTAT_OFST)))
+ return -ENODEV;
+
+ /* Enable IRQ on Single Bit Error */
+ writel(ALTR_A10_ECC_SERRINTEN, (base + ALTR_A10_ECC_ERRINTENS_OFST));
+ /* Ensure all writes complete */
+ wmb();
+
+ return 0;
+}
+
static const struct edac_device_prv_data a10_ocramecc_data = {
- .setup = altr_check_ecc_deps,
+ .setup = altr_check_ocram_deps_init,
.ce_clear_mask = ALTR_A10_ECC_SERRPENA,
.ue_clear_mask = ALTR_A10_ECC_DERRPENA,
.irq_status_mask = A10_SYSMGR_ECC_INTSTAT_OCRAM,
@@ -1234,7 +1257,7 @@ static const struct edac_device_prv_data a10_ocramecc_data = {
.ue_set_mask = ALTR_A10_ECC_TDERRA,
.set_err_ofst = ALTR_A10_ECC_INTTEST_OFST,
.ecc_irq_handler = altr_edac_a10_ecc_irq,
- .inject_fops = &altr_edac_a10_device_inject_fops,
+ .inject_fops = &altr_edac_a10_device_inject2_fops,
/*
* OCRAM panic on uncorrectable error because sleep/resume
* functions and FPGA contents are stored in OCRAM. Prefer
@@ -1560,8 +1583,12 @@ static int altr_portb_setup(struct altr_edac_device_dev *device)
dci->mod_name = ecc_name;
dci->dev_name = ecc_name;
- /* Update the IRQs for PortB */
+ /* Update the PortB IRQs - A10 has 4, S10 has 2, Index accordingly */
+#ifdef CONFIG_ARCH_STRATIX10
+ altdev->sb_irq = irq_of_parse_and_map(np, 1);
+#else
altdev->sb_irq = irq_of_parse_and_map(np, 2);
+#endif
if (!altdev->sb_irq) {
edac_printk(KERN_ERR, EDAC_DEVICE, "Error PortB SBIRQ alloc\n");
rc = -ENODEV;
@@ -1576,6 +1603,15 @@ static int altr_portb_setup(struct altr_edac_device_dev *device)
goto err_release_group_1;
}
+#ifdef CONFIG_ARCH_STRATIX10
+ /* Use IRQ to determine SError origin instead of assigning IRQ */
+ rc = of_property_read_u32_index(np, "interrupts", 1, &altdev->db_irq);
+ if (rc) {
+ edac_printk(KERN_ERR, EDAC_DEVICE,
+ "Error PortB DBIRQ alloc\n");
+ goto err_release_group_1;
+ }
+#else
altdev->db_irq = irq_of_parse_and_map(np, 3);
if (!altdev->db_irq) {
edac_printk(KERN_ERR, EDAC_DEVICE, "Error PortB DBIRQ alloc\n");
@@ -1590,6 +1626,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device)
edac_printk(KERN_ERR, EDAC_DEVICE, "PortB DBERR IRQ error\n");
goto err_release_group_1;
}
+#endif
rc = edac_device_add_device(dci);
if (rc) {
diff --git a/drivers/edac/aspeed_edac.c b/drivers/edac/aspeed_edac.c
index 11833c0a5d07..5634437bb39d 100644
--- a/drivers/edac/aspeed_edac.c
+++ b/drivers/edac/aspeed_edac.c
@@ -281,15 +281,11 @@ static int aspeed_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct edac_mc_layer layers[2];
struct mem_ctl_info *mci;
- struct device_node *np;
struct resource *res;
void __iomem *regs;
u32 reg04;
int rc;
- /* setup regmap */
- np = dev->of_node;
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENOENT;
diff --git a/drivers/edac/debugfs.c b/drivers/edac/debugfs.c
index 6b8e484db851..1f943599a8ac 100644
--- a/drivers/edac/debugfs.c
+++ b/drivers/edac/debugfs.c
@@ -118,23 +118,23 @@ edac_debugfs_create_file(const char *name, umode_t mode, struct dentry *parent,
EXPORT_SYMBOL_GPL(edac_debugfs_create_file);
/* Wrapper for debugfs_create_x8() */
-struct dentry *edac_debugfs_create_x8(const char *name, umode_t mode,
- struct dentry *parent, u8 *value)
+void edac_debugfs_create_x8(const char *name, umode_t mode,
+ struct dentry *parent, u8 *value)
{
if (!parent)
parent = edac_debugfs;
- return debugfs_create_x8(name, mode, parent, value);
+ debugfs_create_x8(name, mode, parent, value);
}
EXPORT_SYMBOL_GPL(edac_debugfs_create_x8);
/* Wrapper for debugfs_create_x16() */
-struct dentry *edac_debugfs_create_x16(const char *name, umode_t mode,
- struct dentry *parent, u16 *value)
+void edac_debugfs_create_x16(const char *name, umode_t mode,
+ struct dentry *parent, u16 *value)
{
if (!parent)
parent = edac_debugfs;
- return debugfs_create_x16(name, mode, parent, value);
+ debugfs_create_x16(name, mode, parent, value);
}
EXPORT_SYMBOL_GPL(edac_debugfs_create_x16);
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index 464174685589..4386ea4b9b5a 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -26,7 +26,7 @@
static int edac_mc_log_ue = 1;
static int edac_mc_log_ce = 1;
static int edac_mc_panic_on_ue;
-static int edac_mc_poll_msec = 1000;
+static unsigned int edac_mc_poll_msec = 1000;
/* Getter functions for above */
int edac_mc_get_log_ue(void)
@@ -45,30 +45,30 @@ int edac_mc_get_panic_on_ue(void)
}
/* this is temporary */
-int edac_mc_get_poll_msec(void)
+unsigned int edac_mc_get_poll_msec(void)
{
return edac_mc_poll_msec;
}
static int edac_set_poll_msec(const char *val, const struct kernel_param *kp)
{
- unsigned long l;
+ unsigned int i;
int ret;
if (!val)
return -EINVAL;
- ret = kstrtoul(val, 0, &l);
+ ret = kstrtouint(val, 0, &i);
if (ret)
return ret;
- if (l < 1000)
+ if (i < 1000)
return -EINVAL;
- *((unsigned long *)kp->arg) = l;
+ *((unsigned int *)kp->arg) = i;
/* notify edac_mc engine to reset the poll period */
- edac_mc_reset_delay_period(l);
+ edac_mc_reset_delay_period(i);
return 0;
}
@@ -82,7 +82,7 @@ MODULE_PARM_DESC(edac_mc_log_ue,
module_param(edac_mc_log_ce, int, 0644);
MODULE_PARM_DESC(edac_mc_log_ce,
"Log correctable error to console: 0=off 1=on");
-module_param_call(edac_mc_poll_msec, edac_set_poll_msec, param_get_int,
+module_param_call(edac_mc_poll_msec, edac_set_poll_msec, param_get_uint,
&edac_mc_poll_msec, 0644);
MODULE_PARM_DESC(edac_mc_poll_msec, "Polling period in milliseconds");
@@ -404,6 +404,8 @@ static inline int nr_pages_per_csrow(struct csrow_info *csrow)
static int edac_create_csrow_object(struct mem_ctl_info *mci,
struct csrow_info *csrow, int index)
{
+ int err;
+
csrow->dev.type = &csrow_attr_type;
csrow->dev.groups = csrow_dev_groups;
device_initialize(&csrow->dev);
@@ -415,7 +417,11 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci,
edac_dbg(0, "creating (virtual) csrow node %s\n",
dev_name(&csrow->dev));
- return device_add(&csrow->dev);
+ err = device_add(&csrow->dev);
+ if (err)
+ put_device(&csrow->dev);
+
+ return err;
}
/* Create a CSROW object under specifed edac_mc_device */
@@ -443,7 +449,8 @@ error:
csrow = mci->csrows[i];
if (!nr_pages_per_csrow(csrow))
continue;
- put_device(&mci->csrows[i]->dev);
+
+ device_del(&mci->csrows[i]->dev);
}
return err;
@@ -645,9 +652,11 @@ static int edac_create_dimm_object(struct mem_ctl_info *mci,
dev_set_drvdata(&dimm->dev, dimm);
pm_runtime_forbid(&mci->dev);
- err = device_add(&dimm->dev);
+ err = device_add(&dimm->dev);
+ if (err)
+ put_device(&dimm->dev);
- edac_dbg(0, "creating rank/dimm device %s\n", dev_name(&dimm->dev));
+ edac_dbg(0, "created rank/dimm device %s\n", dev_name(&dimm->dev));
return err;
}
@@ -928,6 +937,7 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
err = device_add(&mci->dev);
if (err < 0) {
edac_dbg(1, "failure: create device %s\n", dev_name(&mci->dev));
+ put_device(&mci->dev);
goto out;
}
diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h
index dd7d0b509aa3..b2f59ee76c22 100644
--- a/drivers/edac/edac_module.h
+++ b/drivers/edac/edac_module.h
@@ -36,7 +36,7 @@ extern int edac_mc_get_log_ue(void);
extern int edac_mc_get_log_ce(void);
extern int edac_mc_get_panic_on_ue(void);
extern int edac_get_poll_msec(void);
-extern int edac_mc_get_poll_msec(void);
+extern unsigned int edac_mc_get_poll_msec(void);
unsigned edac_dimm_info_location(struct dimm_info *dimm, char *buf,
unsigned len);
@@ -78,10 +78,10 @@ edac_debugfs_create_dir_at(const char *dirname, struct dentry *parent);
struct dentry *
edac_debugfs_create_file(const char *name, umode_t mode, struct dentry *parent,
void *data, const struct file_operations *fops);
-struct dentry *
-edac_debugfs_create_x8(const char *name, umode_t mode, struct dentry *parent, u8 *value);
-struct dentry *
-edac_debugfs_create_x16(const char *name, umode_t mode, struct dentry *parent, u16 *value);
+void edac_debugfs_create_x8(const char *name, umode_t mode,
+ struct dentry *parent, u8 *value);
+void edac_debugfs_create_x16(const char *name, umode_t mode,
+ struct dentry *parent, u16 *value);
#else
static inline void edac_debugfs_init(void) { }
static inline void edac_debugfs_exit(void) { }
@@ -92,12 +92,10 @@ edac_debugfs_create_dir_at(const char *dirname, struct dentry *parent) { return
static inline struct dentry *
edac_debugfs_create_file(const char *name, umode_t mode, struct dentry *parent,
void *data, const struct file_operations *fops) { return NULL; }
-static inline struct dentry *
-edac_debugfs_create_x8(const char *name, umode_t mode,
- struct dentry *parent, u8 *value) { return NULL; }
-static inline struct dentry *
-edac_debugfs_create_x16(const char *name, umode_t mode,
- struct dentry *parent, u16 *value) { return NULL; }
+static inline void edac_debugfs_create_x8(const char *name, umode_t mode,
+ struct dentry *parent, u8 *value) { }
+static inline void edac_debugfs_create_x16(const char *name, umode_t mode,
+ struct dentry *parent, u16 *value) { }
#endif
/*
diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c
index 6f06aec4877c..83392f2841de 100644
--- a/drivers/edac/i10nm_base.c
+++ b/drivers/edac/i10nm_base.c
@@ -124,6 +124,8 @@ static int i10nm_get_all_munits(void)
static const struct x86_cpu_id i10nm_cpuids[] = {
{ X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_TREMONT_X, 0, 0 },
+ { X86_VENDOR_INTEL, 6, INTEL_FAM6_ICELAKE_X, 0, 0 },
+ { X86_VENDOR_INTEL, 6, INTEL_FAM6_ICELAKE_XEON_D, 0, 0 },
{ }
};
MODULE_DEVICE_TABLE(x86cpu, i10nm_cpuids);
@@ -166,9 +168,9 @@ static int i10nm_get_dimm_config(struct mem_ctl_info *mci)
ndimms += skx_get_nvdimm_info(dimm, imc, i, j,
EDAC_MOD_STR);
}
- if (ndimms && !i10nm_check_ecc(imc, 0)) {
- i10nm_printk(KERN_ERR, "ECC is disabled on imc %d\n",
- imc->mc);
+ if (ndimms && !i10nm_check_ecc(imc, i)) {
+ i10nm_printk(KERN_ERR, "ECC is disabled on imc %d channel %d\n",
+ imc->mc, i);
return -ENODEV;
}
}
@@ -265,7 +267,7 @@ static int __init i10nm_init(void)
goto fail;
list_for_each_entry(d, i10nm_edac_list, list) {
- rc = skx_get_src_id(d, &src_id);
+ rc = skx_get_src_id(d, 0xf8, &src_id);
if (rc < 0)
goto fail;
diff --git a/drivers/edac/ie31200_edac.c b/drivers/edac/ie31200_edac.c
index adf60eb45bd4..d26300f9cb07 100644
--- a/drivers/edac/ie31200_edac.c
+++ b/drivers/edac/ie31200_edac.c
@@ -20,11 +20,13 @@
* 0c08: Xeon E3-1200 v3 Processor DRAM Controller
* 1918: Xeon E3-1200 v5 Skylake Host Bridge/DRAM Registers
* 5918: Xeon E3-1200 Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers
+ * 3e..: 8th/9th Gen Core Processor Host Bridge/DRAM Registers
*
* Based on Intel specification:
* http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/xeon-e3-1200v3-vol-2-datasheet.pdf
* http://www.intel.com/content/www/us/en/processors/xeon/xeon-e3-1200-family-vol-2-datasheet.html
* http://www.intel.com/content/www/us/en/processors/core/7th-gen-core-family-mobile-h-processor-lines-datasheet-vol-2.html
+ * https://www.intel.com/content/www/us/en/products/docs/processors/core/8th-gen-core-family-datasheet-vol-2.html
*
* According to the above datasheet (p.16):
* "
@@ -61,6 +63,26 @@
#define PCI_DEVICE_ID_INTEL_IE31200_HB_8 0x1918
#define PCI_DEVICE_ID_INTEL_IE31200_HB_9 0x5918
+/* Coffee Lake-S */
+#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_MASK 0x3e00
+#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_1 0x3e0f
+#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_2 0x3e18
+#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_3 0x3e1f
+#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_4 0x3e30
+#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_5 0x3e31
+#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_6 0x3e32
+#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_7 0x3e33
+#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_8 0x3ec2
+#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_9 0x3ec6
+#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_10 0x3eca
+
+/* Test if HB is for Skylake or later. */
+#define DEVICE_ID_SKYLAKE_OR_LATER(did) \
+ (((did) == PCI_DEVICE_ID_INTEL_IE31200_HB_8) || \
+ ((did) == PCI_DEVICE_ID_INTEL_IE31200_HB_9) || \
+ (((did) & PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_MASK) == \
+ PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_MASK))
+
#define IE31200_DIMMS 4
#define IE31200_RANKS 8
#define IE31200_RANKS_PER_CHANNEL 4
@@ -381,10 +403,10 @@ static int ie31200_probe1(struct pci_dev *pdev, int dev_idx)
u32 addr_decode, mad_offset;
/*
- * Kaby Lake seems to work like Skylake. Please re-visit this logic
- * when adding new CPU support.
+ * Kaby Lake, Coffee Lake seem to work like Skylake. Please re-visit
+ * this logic when adding new CPU support.
*/
- bool skl = (pdev->device >= PCI_DEVICE_ID_INTEL_IE31200_HB_8);
+ bool skl = DEVICE_ID_SKYLAKE_OR_LATER(pdev->device);
edac_dbg(0, "MC:\n");
@@ -542,36 +564,26 @@ static void ie31200_remove_one(struct pci_dev *pdev)
}
static const struct pci_device_id ie31200_pci_tbl[] = {
- {
- PCI_VEND_DEV(INTEL, IE31200_HB_1), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- IE31200},
- {
- PCI_VEND_DEV(INTEL, IE31200_HB_2), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- IE31200},
- {
- PCI_VEND_DEV(INTEL, IE31200_HB_3), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- IE31200},
- {
- PCI_VEND_DEV(INTEL, IE31200_HB_4), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- IE31200},
- {
- PCI_VEND_DEV(INTEL, IE31200_HB_5), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- IE31200},
- {
- PCI_VEND_DEV(INTEL, IE31200_HB_6), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- IE31200},
- {
- PCI_VEND_DEV(INTEL, IE31200_HB_7), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- IE31200},
- {
- PCI_VEND_DEV(INTEL, IE31200_HB_8), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- IE31200},
- {
- PCI_VEND_DEV(INTEL, IE31200_HB_9), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- IE31200},
- {
- 0,
- } /* 0 terminated list. */
+ { PCI_VEND_DEV(INTEL, IE31200_HB_1), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
+ { PCI_VEND_DEV(INTEL, IE31200_HB_2), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
+ { PCI_VEND_DEV(INTEL, IE31200_HB_3), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
+ { PCI_VEND_DEV(INTEL, IE31200_HB_4), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
+ { PCI_VEND_DEV(INTEL, IE31200_HB_5), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
+ { PCI_VEND_DEV(INTEL, IE31200_HB_6), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
+ { PCI_VEND_DEV(INTEL, IE31200_HB_7), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
+ { PCI_VEND_DEV(INTEL, IE31200_HB_8), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
+ { PCI_VEND_DEV(INTEL, IE31200_HB_9), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
+ { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_1), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
+ { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_2), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
+ { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_3), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
+ { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_4), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
+ { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_5), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
+ { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_6), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
+ { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_7), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
+ { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_8), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
+ { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_9), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
+ { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_10), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
+ { 0, } /* 0 terminated list. */
};
MODULE_DEVICE_TABLE(pci, ie31200_pci_tbl);
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index fa700a170380..37746b045e18 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -1511,7 +1511,6 @@ static int knl_get_dimm_capacity(struct sbridge_pvt *pvt, u64 *mc_sizes)
sad_actual_size[mc] += tad_size;
}
}
- tad_base = tad_limit+1;
}
}
diff --git a/drivers/edac/sifive_edac.c b/drivers/edac/sifive_edac.c
new file mode 100644
index 000000000000..413cdb4a591d
--- /dev/null
+++ b/drivers/edac/sifive_edac.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SiFive Platform EDAC Driver
+ *
+ * Copyright (C) 2018-2019 SiFive, Inc.
+ *
+ * This driver is partially based on octeon_edac-pc.c
+ *
+ */
+#include <linux/edac.h>
+#include <linux/platform_device.h>
+#include "edac_module.h"
+#include <asm/sifive_l2_cache.h>
+
+#define DRVNAME "sifive_edac"
+
+struct sifive_edac_priv {
+ struct notifier_block notifier;
+ struct edac_device_ctl_info *dci;
+};
+
+/**
+ * EDAC error callback
+ *
+ * @event: non-zero if unrecoverable.
+ */
+static
+int ecc_err_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ const char *msg = (char *)ptr;
+ struct sifive_edac_priv *p;
+
+ p = container_of(this, struct sifive_edac_priv, notifier);
+
+ if (event == SIFIVE_L2_ERR_TYPE_UE)
+ edac_device_handle_ue(p->dci, 0, 0, msg);
+ else if (event == SIFIVE_L2_ERR_TYPE_CE)
+ edac_device_handle_ce(p->dci, 0, 0, msg);
+
+ return NOTIFY_OK;
+}
+
+static int ecc_register(struct platform_device *pdev)
+{
+ struct sifive_edac_priv *p;
+
+ p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ p->notifier.notifier_call = ecc_err_event;
+ platform_set_drvdata(pdev, p);
+
+ p->dci = edac_device_alloc_ctl_info(0, "sifive_ecc", 1, "sifive_ecc",
+ 1, 1, NULL, 0,
+ edac_device_alloc_index());
+ if (IS_ERR(p->dci))
+ return PTR_ERR(p->dci);
+
+ p->dci->dev = &pdev->dev;
+ p->dci->mod_name = "Sifive ECC Manager";
+ p->dci->ctl_name = dev_name(&pdev->dev);
+ p->dci->dev_name = dev_name(&pdev->dev);
+
+ if (edac_device_add_device(p->dci)) {
+ dev_err(p->dci->dev, "failed to register with EDAC core\n");
+ goto err;
+ }
+
+ register_sifive_l2_error_notifier(&p->notifier);
+
+ return 0;
+
+err:
+ edac_device_free_ctl_info(p->dci);
+
+ return -ENXIO;
+}
+
+static int ecc_unregister(struct platform_device *pdev)
+{
+ struct sifive_edac_priv *p = platform_get_drvdata(pdev);
+
+ unregister_sifive_l2_error_notifier(&p->notifier);
+ edac_device_del_device(&pdev->dev);
+ edac_device_free_ctl_info(p->dci);
+
+ return 0;
+}
+
+static struct platform_device *sifive_pdev;
+
+static int __init sifive_edac_init(void)
+{
+ int ret;
+
+ sifive_pdev = platform_device_register_simple(DRVNAME, 0, NULL, 0);
+ if (IS_ERR(sifive_pdev))
+ return PTR_ERR(sifive_pdev);
+
+ ret = ecc_register(sifive_pdev);
+ if (ret)
+ platform_device_unregister(sifive_pdev);
+
+ return ret;
+}
+
+static void __exit sifive_edac_exit(void)
+{
+ ecc_unregister(sifive_pdev);
+ platform_device_unregister(sifive_pdev);
+}
+
+module_init(sifive_edac_init);
+module_exit(sifive_edac_exit);
+
+MODULE_AUTHOR("SiFive Inc.");
+MODULE_DESCRIPTION("SiFive platform EDAC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/edac/skx_base.c b/drivers/edac/skx_base.c
index a5c8fa3a249a..0fcf3785e8f3 100644
--- a/drivers/edac/skx_base.c
+++ b/drivers/edac/skx_base.c
@@ -639,7 +639,7 @@ static int __init skx_init(void)
}
list_for_each_entry(d, skx_edac_list, list) {
- rc = skx_get_src_id(d, &src_id);
+ rc = skx_get_src_id(d, 0xf0, &src_id);
if (rc < 0)
goto fail;
rc = skx_get_node_id(d, &node_id);
diff --git a/drivers/edac/skx_common.c b/drivers/edac/skx_common.c
index b0dddcfa9baa..d8ff63d91b86 100644
--- a/drivers/edac/skx_common.c
+++ b/drivers/edac/skx_common.c
@@ -136,11 +136,11 @@ void skx_set_decode(skx_decode_f decode)
skx_decode = decode;
}
-int skx_get_src_id(struct skx_dev *d, u8 *id)
+int skx_get_src_id(struct skx_dev *d, int off, u8 *id)
{
u32 reg;
- if (pci_read_config_dword(d->util_all, 0xf0, &reg)) {
+ if (pci_read_config_dword(d->util_all, off, &reg)) {
skx_printk(KERN_ERR, "Failed to read src id\n");
return -ENODEV;
}
diff --git a/drivers/edac/skx_common.h b/drivers/edac/skx_common.h
index d18fa98669af..08cc971a50ea 100644
--- a/drivers/edac/skx_common.h
+++ b/drivers/edac/skx_common.h
@@ -118,7 +118,7 @@ int __init skx_adxl_get(void);
void __exit skx_adxl_put(void);
void skx_set_decode(skx_decode_f decode);
-int skx_get_src_id(struct skx_dev *d, u8 *id);
+int skx_get_src_id(struct skx_dev *d, int off, u8 *id);
int skx_get_node_id(struct skx_dev *d, u8 *id);
int skx_get_all_bus_mappings(unsigned int did, int off, enum type,
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index 6f5af4196b8d..fa1804460e8c 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -37,6 +37,18 @@ config EXTCON_AXP288
Say Y here to enable support for USB peripheral detection
and USB MUX switching by X-Power AXP288 PMIC.
+config EXTCON_FSA9480
+ tristate "FSA9480 EXTCON Support"
+ depends on INPUT && I2C
+ select IRQ_DOMAIN
+ select REGMAP_I2C
+ help
+ If you say yes here you get support for the Fairchild Semiconductor
+ FSA9480 microUSB switch and accessory detector chip. The FSA9480 is a USB
+ port accessory detector and switch. The FSA9480 is fully controlled using
+ I2C and enables USB data, stereo and mono audio, video, microphone
+ and UART data to use a common connector port.
+
config EXTCON_GPIO
tristate "GPIO extcon support"
depends on GPIOLIB || COMPILE_TEST
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
index d3941a735df3..52096fd8a216 100644
--- a/drivers/extcon/Makefile
+++ b/drivers/extcon/Makefile
@@ -8,6 +8,7 @@ extcon-core-objs += extcon.o devres.o
obj-$(CONFIG_EXTCON_ADC_JACK) += extcon-adc-jack.o
obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o
obj-$(CONFIG_EXTCON_AXP288) += extcon-axp288.o
+obj-$(CONFIG_EXTCON_FSA9480) += extcon-fsa9480.o
obj-$(CONFIG_EXTCON_GPIO) += extcon-gpio.o
obj-$(CONFIG_EXTCON_INTEL_INT3496) += extcon-intel-int3496.o
obj-$(CONFIG_EXTCON_INTEL_CHT_WC) += extcon-intel-cht-wc.o
diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c
index 18026354c332..ee9b5f70bfa4 100644
--- a/drivers/extcon/extcon-adc-jack.c
+++ b/drivers/extcon/extcon-adc-jack.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/extcon/extcon-adc-jack.c
*
@@ -10,11 +11,6 @@
* MyungJoo Ham <myungjoo.ham@samsung.com>
*
* Modified for calling to IIO to get adc by <anish.singh@samsung.com>
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index bb6434726c7a..7e9f4c9ee87d 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -326,10 +326,12 @@ static void arizona_start_mic(struct arizona_extcon_info *info)
arizona_extcon_pulse_micbias(info);
- regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
- ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
- &change);
- if (!change) {
+ ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
+ ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
+ &change);
+ if (ret < 0) {
+ dev_err(arizona->dev, "Failed to enable micd: %d\n", ret);
+ } else if (!change) {
regulator_disable(info->micvdd);
pm_runtime_put_autosuspend(info->dev);
}
@@ -341,12 +343,14 @@ static void arizona_stop_mic(struct arizona_extcon_info *info)
const char *widget = arizona_extcon_get_micbias(info);
struct snd_soc_dapm_context *dapm = arizona->dapm;
struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
- bool change;
+ bool change = false;
int ret;
- regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
- ARIZONA_MICD_ENA, 0,
- &change);
+ ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
+ ARIZONA_MICD_ENA, 0,
+ &change);
+ if (ret < 0)
+ dev_err(arizona->dev, "Failed to disable micd: %d\n", ret);
ret = snd_soc_component_disable_pin(component, widget);
if (ret != 0)
@@ -1718,12 +1722,15 @@ static int arizona_extcon_remove(struct platform_device *pdev)
struct arizona *arizona = info->arizona;
int jack_irq_rise, jack_irq_fall;
bool change;
+ int ret;
- regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
- ARIZONA_MICD_ENA, 0,
- &change);
-
- if (change) {
+ ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
+ ARIZONA_MICD_ENA, 0,
+ &change);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to disable micd on remove: %d\n",
+ ret);
+ } else if (change) {
regulator_disable(info->micvdd);
pm_runtime_put(info->dev);
}
diff --git a/drivers/extcon/extcon-fsa9480.c b/drivers/extcon/extcon-fsa9480.c
new file mode 100644
index 000000000000..350fb34abfa0
--- /dev/null
+++ b/drivers/extcon/extcon-fsa9480.c
@@ -0,0 +1,395 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * extcon-fsa9480.c - Fairchild Semiconductor FSA9480 extcon driver
+ *
+ * Copyright (c) 2019 Tomasz Figa <tomasz.figa@gmail.com>
+ *
+ * Loosely based on old fsa9480 misc-device driver.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/kobject.h>
+#include <linux/extcon-provider.h>
+#include <linux/irqdomain.h>
+#include <linux/regmap.h>
+
+/* FSA9480 I2C registers */
+#define FSA9480_REG_DEVID 0x01
+#define FSA9480_REG_CTRL 0x02
+#define FSA9480_REG_INT1 0x03
+#define FSA9480_REG_INT2 0x04
+#define FSA9480_REG_INT1_MASK 0x05
+#define FSA9480_REG_INT2_MASK 0x06
+#define FSA9480_REG_ADC 0x07
+#define FSA9480_REG_TIMING1 0x08
+#define FSA9480_REG_TIMING2 0x09
+#define FSA9480_REG_DEV_T1 0x0a
+#define FSA9480_REG_DEV_T2 0x0b
+#define FSA9480_REG_BTN1 0x0c
+#define FSA9480_REG_BTN2 0x0d
+#define FSA9480_REG_CK 0x0e
+#define FSA9480_REG_CK_INT1 0x0f
+#define FSA9480_REG_CK_INT2 0x10
+#define FSA9480_REG_CK_INTMASK1 0x11
+#define FSA9480_REG_CK_INTMASK2 0x12
+#define FSA9480_REG_MANSW1 0x13
+#define FSA9480_REG_MANSW2 0x14
+#define FSA9480_REG_END 0x15
+
+/* Control */
+#define CON_SWITCH_OPEN (1 << 4)
+#define CON_RAW_DATA (1 << 3)
+#define CON_MANUAL_SW (1 << 2)
+#define CON_WAIT (1 << 1)
+#define CON_INT_MASK (1 << 0)
+#define CON_MASK (CON_SWITCH_OPEN | CON_RAW_DATA | \
+ CON_MANUAL_SW | CON_WAIT)
+
+/* Device Type 1 */
+#define DEV_USB_OTG 7
+#define DEV_DEDICATED_CHG 6
+#define DEV_USB_CHG 5
+#define DEV_CAR_KIT 4
+#define DEV_UART 3
+#define DEV_USB 2
+#define DEV_AUDIO_2 1
+#define DEV_AUDIO_1 0
+
+#define DEV_T1_USB_MASK (DEV_USB_OTG | DEV_USB)
+#define DEV_T1_UART_MASK (DEV_UART)
+#define DEV_T1_CHARGER_MASK (DEV_DEDICATED_CHG | DEV_USB_CHG)
+
+/* Device Type 2 */
+#define DEV_AV 14
+#define DEV_TTY 13
+#define DEV_PPD 12
+#define DEV_JIG_UART_OFF 11
+#define DEV_JIG_UART_ON 10
+#define DEV_JIG_USB_OFF 9
+#define DEV_JIG_USB_ON 8
+
+#define DEV_T2_USB_MASK (DEV_JIG_USB_OFF | DEV_JIG_USB_ON)
+#define DEV_T2_UART_MASK (DEV_JIG_UART_OFF | DEV_JIG_UART_ON)
+#define DEV_T2_JIG_MASK (DEV_JIG_USB_OFF | DEV_JIG_USB_ON | \
+ DEV_JIG_UART_OFF | DEV_JIG_UART_ON)
+
+/*
+ * Manual Switch
+ * D- [7:5] / D+ [4:2]
+ * 000: Open all / 001: USB / 010: AUDIO / 011: UART / 100: V_AUDIO
+ */
+#define SW_VAUDIO ((4 << 5) | (4 << 2))
+#define SW_UART ((3 << 5) | (3 << 2))
+#define SW_AUDIO ((2 << 5) | (2 << 2))
+#define SW_DHOST ((1 << 5) | (1 << 2))
+#define SW_AUTO ((0 << 5) | (0 << 2))
+
+/* Interrupt 1 */
+#define INT1_MASK (0xff << 0)
+#define INT_DETACH (1 << 1)
+#define INT_ATTACH (1 << 0)
+
+/* Interrupt 2 mask */
+#define INT2_MASK (0x1f << 0)
+
+/* Timing Set 1 */
+#define TIMING1_ADC_500MS (0x6 << 0)
+
+struct fsa9480_usbsw {
+ struct device *dev;
+ struct regmap *regmap;
+ struct extcon_dev *edev;
+ u16 cable;
+};
+
+static const unsigned int fsa9480_extcon_cable[] = {
+ EXTCON_USB_HOST,
+ EXTCON_USB,
+ EXTCON_CHG_USB_DCP,
+ EXTCON_CHG_USB_SDP,
+ EXTCON_CHG_USB_ACA,
+ EXTCON_JACK_LINE_OUT,
+ EXTCON_JACK_VIDEO_OUT,
+ EXTCON_JIG,
+
+ EXTCON_NONE,
+};
+
+static const u64 cable_types[] = {
+ [DEV_USB_OTG] = BIT_ULL(EXTCON_USB_HOST),
+ [DEV_DEDICATED_CHG] = BIT_ULL(EXTCON_USB) | BIT_ULL(EXTCON_CHG_USB_DCP),
+ [DEV_USB_CHG] = BIT_ULL(EXTCON_USB) | BIT_ULL(EXTCON_CHG_USB_SDP),
+ [DEV_CAR_KIT] = BIT_ULL(EXTCON_USB) | BIT_ULL(EXTCON_CHG_USB_SDP)
+ | BIT_ULL(EXTCON_JACK_LINE_OUT),
+ [DEV_UART] = BIT_ULL(EXTCON_JIG),
+ [DEV_USB] = BIT_ULL(EXTCON_USB) | BIT_ULL(EXTCON_CHG_USB_SDP),
+ [DEV_AUDIO_2] = BIT_ULL(EXTCON_JACK_LINE_OUT),
+ [DEV_AUDIO_1] = BIT_ULL(EXTCON_JACK_LINE_OUT),
+ [DEV_AV] = BIT_ULL(EXTCON_JACK_LINE_OUT)
+ | BIT_ULL(EXTCON_JACK_VIDEO_OUT),
+ [DEV_TTY] = BIT_ULL(EXTCON_JIG),
+ [DEV_PPD] = BIT_ULL(EXTCON_JACK_LINE_OUT) | BIT_ULL(EXTCON_CHG_USB_ACA),
+ [DEV_JIG_UART_OFF] = BIT_ULL(EXTCON_JIG),
+ [DEV_JIG_UART_ON] = BIT_ULL(EXTCON_JIG),
+ [DEV_JIG_USB_OFF] = BIT_ULL(EXTCON_USB) | BIT_ULL(EXTCON_JIG),
+ [DEV_JIG_USB_ON] = BIT_ULL(EXTCON_USB) | BIT_ULL(EXTCON_JIG),
+};
+
+/* Define regmap configuration of FSA9480 for I2C communication */
+static bool fsa9480_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case FSA9480_REG_INT1_MASK:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+static const struct regmap_config fsa9480_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_reg = fsa9480_volatile_reg,
+ .max_register = FSA9480_REG_END,
+};
+
+static int fsa9480_write_reg(struct fsa9480_usbsw *usbsw, int reg, int value)
+{
+ int ret;
+
+ ret = regmap_write(usbsw->regmap, reg, value);
+ if (ret < 0)
+ dev_err(usbsw->dev, "%s: err %d\n", __func__, ret);
+
+ return ret;
+}
+
+static int fsa9480_read_reg(struct fsa9480_usbsw *usbsw, int reg)
+{
+ int ret, val;
+
+ ret = regmap_read(usbsw->regmap, reg, &val);
+ if (ret < 0) {
+ dev_err(usbsw->dev, "%s: err %d\n", __func__, ret);
+ return ret;
+ }
+
+ return val;
+}
+
+static int fsa9480_read_irq(struct fsa9480_usbsw *usbsw, int *value)
+{
+ u8 regs[2];
+ int ret;
+
+ ret = regmap_bulk_read(usbsw->regmap, FSA9480_REG_INT1, regs, 2);
+ if (ret < 0)
+ dev_err(usbsw->dev, "%s: err %d\n", __func__, ret);
+
+ *value = regs[1] << 8 | regs[0];
+ return ret;
+}
+
+static void fsa9480_handle_change(struct fsa9480_usbsw *usbsw,
+ u16 mask, bool attached)
+{
+ while (mask) {
+ int dev = fls64(mask) - 1;
+ u64 cables = cable_types[dev];
+
+ while (cables) {
+ int cable = fls64(cables) - 1;
+
+ extcon_set_state_sync(usbsw->edev, cable, attached);
+ cables &= ~BIT_ULL(cable);
+ }
+
+ mask &= ~BIT_ULL(dev);
+ }
+}
+
+static void fsa9480_detect_dev(struct fsa9480_usbsw *usbsw)
+{
+ int val1, val2;
+ u16 val;
+
+ val1 = fsa9480_read_reg(usbsw, FSA9480_REG_DEV_T1);
+ val2 = fsa9480_read_reg(usbsw, FSA9480_REG_DEV_T2);
+ if (val1 < 0 || val2 < 0) {
+ dev_err(usbsw->dev, "%s: failed to read registers", __func__);
+ return;
+ }
+ val = val2 << 8 | val1;
+
+ dev_info(usbsw->dev, "dev1: 0x%x, dev2: 0x%x\n", val1, val2);
+
+ /* handle detached cables first */
+ fsa9480_handle_change(usbsw, usbsw->cable & ~val, false);
+
+ /* then handle attached ones */
+ fsa9480_handle_change(usbsw, val & ~usbsw->cable, true);
+
+ usbsw->cable = val;
+}
+
+static irqreturn_t fsa9480_irq_handler(int irq, void *data)
+{
+ struct fsa9480_usbsw *usbsw = data;
+ int intr = 0;
+
+ /* clear interrupt */
+ fsa9480_read_irq(usbsw, &intr);
+ if (!intr)
+ return IRQ_NONE;
+
+ /* device detection */
+ fsa9480_detect_dev(usbsw);
+
+ return IRQ_HANDLED;
+}
+
+static int fsa9480_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct fsa9480_usbsw *info;
+ int ret;
+
+ if (!client->irq) {
+ dev_err(&client->dev, "no interrupt provided\n");
+ return -EINVAL;
+ }
+
+ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+ info->dev = &client->dev;
+
+ i2c_set_clientdata(client, info);
+
+ /* External connector */
+ info->edev = devm_extcon_dev_allocate(info->dev,
+ fsa9480_extcon_cable);
+ if (IS_ERR(info->edev)) {
+ dev_err(info->dev, "failed to allocate memory for extcon\n");
+ ret = -ENOMEM;
+ return ret;
+ }
+
+ ret = devm_extcon_dev_register(info->dev, info->edev);
+ if (ret) {
+ dev_err(info->dev, "failed to register extcon device\n");
+ return ret;
+ }
+
+ info->regmap = devm_regmap_init_i2c(client, &fsa9480_regmap_config);
+ if (IS_ERR(info->regmap)) {
+ ret = PTR_ERR(info->regmap);
+ dev_err(info->dev, "failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
+ /* ADC Detect Time: 500ms */
+ fsa9480_write_reg(info, FSA9480_REG_TIMING1, TIMING1_ADC_500MS);
+
+ /* configure automatic switching */
+ fsa9480_write_reg(info, FSA9480_REG_CTRL, CON_MASK);
+
+ /* unmask interrupt (attach/detach only) */
+ fsa9480_write_reg(info, FSA9480_REG_INT1_MASK,
+ INT1_MASK & ~(INT_ATTACH | INT_DETACH));
+ fsa9480_write_reg(info, FSA9480_REG_INT2_MASK, INT2_MASK);
+
+ ret = devm_request_threaded_irq(info->dev, client->irq, NULL,
+ fsa9480_irq_handler,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "fsa9480", info);
+ if (ret) {
+ dev_err(info->dev, "failed to request IRQ\n");
+ return ret;
+ }
+
+ device_init_wakeup(info->dev, true);
+ fsa9480_detect_dev(info);
+
+ return 0;
+}
+
+static int fsa9480_remove(struct i2c_client *client)
+{
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int fsa9480_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ if (device_may_wakeup(&client->dev) && client->irq)
+ enable_irq_wake(client->irq);
+
+ return 0;
+}
+
+static int fsa9480_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ if (device_may_wakeup(&client->dev) && client->irq)
+ disable_irq_wake(client->irq);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops fsa9480_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(fsa9480_suspend, fsa9480_resume)
+};
+
+static const struct i2c_device_id fsa9480_id[] = {
+ { "fsa9480", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, fsa9480_id);
+
+static const struct of_device_id fsa9480_of_match[] = {
+ { .compatible = "fcs,fsa9480", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, fsa9480_of_match);
+
+static struct i2c_driver fsa9480_i2c_driver = {
+ .driver = {
+ .name = "fsa9480",
+ .pm = &fsa9480_pm_ops,
+ .of_match_table = fsa9480_of_match,
+ },
+ .probe = fsa9480_probe,
+ .remove = fsa9480_remove,
+ .id_table = fsa9480_id,
+};
+
+static int __init fsa9480_module_init(void)
+{
+ return i2c_add_driver(&fsa9480_i2c_driver);
+}
+subsys_initcall(fsa9480_module_init);
+
+static void __exit fsa9480_module_exit(void)
+{
+ i2c_del_driver(&fsa9480_i2c_driver);
+}
+module_exit(fsa9480_module_exit);
+
+MODULE_DESCRIPTION("Fairchild Semiconductor FSA9480 extcon driver");
+MODULE_AUTHOR("Tomasz Figa <tomasz.figa@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/extcon/extcon-max3355.c b/drivers/extcon/extcon-max3355.c
index 1335a476bfec..fa01926c09f1 100644
--- a/drivers/extcon/extcon-max3355.c
+++ b/drivers/extcon/extcon-max3355.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Maxim Integrated MAX3355 USB OTG chip extcon driver
*
* Copyright (C) 2014-2015 Cogent Embedded, Inc.
* Author: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
*/
#include <linux/extcon-provider.h>
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 9026df923542..53446e39a32c 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# For a description of the syntax of this configuration file,
-# see Documentation/kbuild/kconfig-language.txt.
+# see Documentation/kbuild/kconfig-language.rst.
#
menu "Firmware Drivers"
@@ -256,7 +256,7 @@ config TI_SCI_PROTOCOL
config TRUSTED_FOUNDATIONS
bool "Trusted Foundations secure monitor support"
- depends on ARM
+ depends on ARM && CPU_V7
help
Some devices (including most early Tegra-based consumer devices on
the market) are booted with the Trusted Foundations secure monitor
diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h
index 937a930ce87d..44fd4f9404a9 100644
--- a/drivers/firmware/arm_scmi/common.h
+++ b/drivers/firmware/arm_scmi/common.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* System Control and Management Interface (SCMI) Message Protocol
* driver common header file containing some definitions, structures
diff --git a/drivers/firmware/efi/dev-path-parser.c b/drivers/firmware/efi/dev-path-parser.c
index 85ec99f97841..20123384271c 100644
--- a/drivers/firmware/efi/dev-path-parser.c
+++ b/drivers/firmware/efi/dev-path-parser.c
@@ -17,9 +17,9 @@ struct acpi_hid_uid {
char uid[11]; /* UINT_MAX + null byte */
};
-static int __init match_acpi_dev(struct device *dev, void *data)
+static int __init match_acpi_dev(struct device *dev, const void *data)
{
- struct acpi_hid_uid hid_uid = *(struct acpi_hid_uid *)data;
+ struct acpi_hid_uid hid_uid = *(const struct acpi_hid_uid *)data;
struct acpi_device *adev = to_acpi_device(dev);
if (acpi_match_device_ids(adev, hid_uid.hid))
diff --git a/drivers/firmware/efi/efi-bgrt.c b/drivers/firmware/efi/efi-bgrt.c
index a2384184a7de..b07c17643210 100644
--- a/drivers/firmware/efi/efi-bgrt.c
+++ b/drivers/firmware/efi/efi-bgrt.c
@@ -47,11 +47,6 @@ void __init efi_bgrt_init(struct acpi_table_header *table)
bgrt->version);
goto out;
}
- if (bgrt->status & 0xfe) {
- pr_notice("Ignoring BGRT: reserved status bits are non-zero %u\n",
- bgrt->status);
- goto out;
- }
if (bgrt->image_type != 0) {
pr_notice("Ignoring BGRT: invalid image type %u (expected 0)\n",
bgrt->image_type);
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 16b2137d117c..ad3b1f4866b3 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -52,6 +52,7 @@ struct efi __read_mostly efi = {
.mem_attr_table = EFI_INVALID_TABLE_ADDR,
.rng_seed = EFI_INVALID_TABLE_ADDR,
.tpm_log = EFI_INVALID_TABLE_ADDR,
+ .tpm_final_log = EFI_INVALID_TABLE_ADDR,
.mem_reserve = EFI_INVALID_TABLE_ADDR,
};
EXPORT_SYMBOL(efi);
@@ -484,6 +485,7 @@ static __initdata efi_config_table_type_t common_tables[] = {
{EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi.mem_attr_table},
{LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &efi.rng_seed},
{LINUX_EFI_TPM_EVENT_LOG_GUID, "TPMEventLog", &efi.tpm_log},
+ {LINUX_EFI_TPM_FINAL_LOG_GUID, "TPMFinalLog", &efi.tpm_final_log},
{LINUX_EFI_MEMRESERVE_TABLE_GUID, "MEMRESERVE", &efi.mem_reserve},
{NULL_GUID, NULL, NULL},
};
@@ -1009,14 +1011,16 @@ int __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size)
/* first try to find a slot in an existing linked list entry */
for (prsv = efi_memreserve_root->next; prsv; prsv = rsv->next) {
- rsv = __va(prsv);
+ rsv = memremap(prsv, sizeof(*rsv), MEMREMAP_WB);
index = atomic_fetch_add_unless(&rsv->count, 1, rsv->size);
if (index < rsv->size) {
rsv->entry[index].base = addr;
rsv->entry[index].size = size;
+ memunmap(rsv);
return 0;
}
+ memunmap(rsv);
}
/* no slot found - allocate a new linked list entry */
@@ -1024,7 +1028,13 @@ int __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size)
if (!rsv)
return -ENOMEM;
- rsv->size = EFI_MEMRESERVE_COUNT(PAGE_SIZE);
+ /*
+ * The memremap() call above assumes that a linux_efi_memreserve entry
+ * never crosses a page boundary, so let's ensure that this remains true
+ * even when kexec'ing a 4k pages kernel from a >4k pages kernel, by
+ * using SZ_4K explicitly in the size calculation below.
+ */
+ rsv->size = EFI_MEMRESERVE_COUNT(SZ_4K);
atomic_set(&rsv->count, 1);
rsv->entry[0].base = addr;
rsv->entry[0].size = size;
diff --git a/drivers/firmware/efi/efibc.c b/drivers/firmware/efi/efibc.c
index 61e099826cbb..35dccc88ac0a 100644
--- a/drivers/firmware/efi/efibc.c
+++ b/drivers/firmware/efi/efibc.c
@@ -43,11 +43,13 @@ static int efibc_set_variable(const char *name, const char *value)
efibc_str_to_str16(value, (efi_char16_t *)entry->var.Data);
memcpy(&entry->var.VendorGuid, &guid, sizeof(guid));
- ret = efivar_entry_set(entry,
- EFI_VARIABLE_NON_VOLATILE
- | EFI_VARIABLE_BOOTSERVICE_ACCESS
- | EFI_VARIABLE_RUNTIME_ACCESS,
- size, entry->var.Data, NULL);
+ ret = efivar_entry_set_safe(entry->var.VariableName,
+ entry->var.VendorGuid,
+ EFI_VARIABLE_NON_VOLATILE
+ | EFI_VARIABLE_BOOTSERVICE_ACCESS
+ | EFI_VARIABLE_RUNTIME_ACCESS,
+ false, size, entry->var.Data);
+
if (ret)
pr_err("failed to set %s EFI variable: 0x%x\n",
name, ret);
diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c
index 04e6ecd72cd9..c382a48c6678 100644
--- a/drivers/firmware/efi/libstub/arm-stub.c
+++ b/drivers/firmware/efi/libstub/arm-stub.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* EFI stub implementation that is shared by arm and arm64 architectures.
* This should be #included by the EFI stub implementation files.
@@ -6,10 +7,6 @@
* Roy Franz <roy.franz@linaro.org
* Copyright (C) 2013 Red Hat, Inc.
* Mark Salter <msalter@redhat.com>
- *
- * This file is part of the Linux kernel, and is made available under the
- * terms of the GNU General Public License version 2.
- *
*/
#include <linux/efi.h>
diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
index e4610e72b78f..1db780c0f07b 100644
--- a/drivers/firmware/efi/libstub/efi-stub-helper.c
+++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
@@ -926,3 +926,18 @@ free_map:
fail:
return status;
}
+
+void *get_efi_config_table(efi_system_table_t *sys_table, efi_guid_t guid)
+{
+ efi_config_table_t *tables = (efi_config_table_t *)sys_table->tables;
+ int i;
+
+ for (i = 0; i < sys_table->nr_tables; i++) {
+ if (efi_guidcmp(tables[i].guid, guid) != 0)
+ continue;
+
+ return (void *)tables[i].table;
+ }
+
+ return NULL;
+}
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index 1b1dfcaa6fb9..7f1556fd867d 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -65,6 +65,8 @@ efi_status_t check_platform_features(efi_system_table_t *sys_table_arg);
efi_status_t efi_random_get_seed(efi_system_table_t *sys_table_arg);
+void *get_efi_config_table(efi_system_table_t *sys_table, efi_guid_t guid);
+
/* Helper macros for the usual case of using simple C variables: */
#ifndef fdt_setprop_inplace_var
#define fdt_setprop_inplace_var(fdt, node_offset, name, var) \
diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c
index 5440ba17a1c5..0bf0190917e0 100644
--- a/drivers/firmware/efi/libstub/fdt.c
+++ b/drivers/firmware/efi/libstub/fdt.c
@@ -363,26 +363,17 @@ fail:
void *get_fdt(efi_system_table_t *sys_table, unsigned long *fdt_size)
{
- efi_guid_t fdt_guid = DEVICE_TREE_GUID;
- efi_config_table_t *tables;
- int i;
+ void *fdt;
- tables = (efi_config_table_t *)sys_table->tables;
+ fdt = get_efi_config_table(sys_table, DEVICE_TREE_GUID);
- for (i = 0; i < sys_table->nr_tables; i++) {
- void *fdt;
+ if (!fdt)
+ return NULL;
- if (efi_guidcmp(tables[i].guid, fdt_guid) != 0)
- continue;
-
- fdt = (void *)tables[i].table;
- if (fdt_check_header(fdt) != 0) {
- pr_efi_err(sys_table, "Invalid header detected on UEFI supplied FDT, ignoring ...\n");
- return NULL;
- }
- *fdt_size = fdt_totalsize(fdt);
- return fdt;
+ if (fdt_check_header(fdt) != 0) {
+ pr_efi_err(sys_table, "Invalid header detected on UEFI supplied FDT, ignoring ...\n");
+ return NULL;
}
-
- return NULL;
+ *fdt_size = fdt_totalsize(fdt);
+ return fdt;
}
diff --git a/drivers/firmware/efi/libstub/tpm.c b/drivers/firmware/efi/libstub/tpm.c
index 5bd04f75d8d6..eb9af83e4d59 100644
--- a/drivers/firmware/efi/libstub/tpm.c
+++ b/drivers/firmware/efi/libstub/tpm.c
@@ -57,31 +57,40 @@ void efi_enable_reset_attack_mitigation(efi_system_table_t *sys_table_arg)
#endif
-static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg)
+void efi_retrieve_tpm2_eventlog(efi_system_table_t *sys_table_arg)
{
efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID;
efi_guid_t linux_eventlog_guid = LINUX_EFI_TPM_EVENT_LOG_GUID;
efi_status_t status;
efi_physical_addr_t log_location = 0, log_last_entry = 0;
struct linux_efi_tpm_eventlog *log_tbl = NULL;
+ struct efi_tcg2_final_events_table *final_events_table;
unsigned long first_entry_addr, last_entry_addr;
size_t log_size, last_entry_size;
efi_bool_t truncated;
+ int version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_2;
void *tcg2_protocol = NULL;
+ int final_events_size = 0;
status = efi_call_early(locate_protocol, &tcg2_guid, NULL,
&tcg2_protocol);
if (status != EFI_SUCCESS)
return;
- status = efi_call_proto(efi_tcg2_protocol, get_event_log, tcg2_protocol,
- EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2,
- &log_location, &log_last_entry, &truncated);
- if (status != EFI_SUCCESS)
- return;
+ status = efi_call_proto(efi_tcg2_protocol, get_event_log,
+ tcg2_protocol, version, &log_location,
+ &log_last_entry, &truncated);
+
+ if (status != EFI_SUCCESS || !log_location) {
+ version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2;
+ status = efi_call_proto(efi_tcg2_protocol, get_event_log,
+ tcg2_protocol, version, &log_location,
+ &log_last_entry, &truncated);
+ if (status != EFI_SUCCESS || !log_location)
+ return;
+
+ }
- if (!log_location)
- return;
first_entry_addr = (unsigned long) log_location;
/*
@@ -96,8 +105,23 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg)
* We need to calculate its size to deduce the full size of
* the logs.
*/
- last_entry_size = sizeof(struct tcpa_event) +
- ((struct tcpa_event *) last_entry_addr)->event_size;
+ if (version == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) {
+ /*
+ * The TCG2 log format has variable length entries,
+ * and the information to decode the hash algorithms
+ * back into a size is contained in the first entry -
+ * pass a pointer to the final entry (to calculate its
+ * size) and the first entry (so we know how long each
+ * digest is)
+ */
+ last_entry_size =
+ __calc_tpm2_event_size((void *)last_entry_addr,
+ (void *)(long)log_location,
+ false);
+ } else {
+ last_entry_size = sizeof(struct tcpa_event) +
+ ((struct tcpa_event *) last_entry_addr)->event_size;
+ }
log_size = log_last_entry - log_location + last_entry_size;
}
@@ -112,9 +136,37 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg)
return;
}
+ /*
+ * Figure out whether any events have already been logged to the
+ * final events structure, and if so how much space they take up
+ */
+ final_events_table = get_efi_config_table(sys_table_arg,
+ LINUX_EFI_TPM_FINAL_LOG_GUID);
+ if (final_events_table && final_events_table->nr_events) {
+ struct tcg_pcr_event2_head *header;
+ int offset;
+ void *data;
+ int event_size;
+ int i = final_events_table->nr_events;
+
+ data = (void *)final_events_table;
+ offset = sizeof(final_events_table->version) +
+ sizeof(final_events_table->nr_events);
+
+ while (i > 0) {
+ header = data + offset + final_events_size;
+ event_size = __calc_tpm2_event_size(header,
+ (void *)(long)log_location,
+ false);
+ final_events_size += event_size;
+ i--;
+ }
+ }
+
memset(log_tbl, 0, sizeof(*log_tbl) + log_size);
log_tbl->size = log_size;
- log_tbl->version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2;
+ log_tbl->final_events_preboot_size = final_events_size;
+ log_tbl->version = version;
memcpy(log_tbl->log, (void *) first_entry_addr, log_size);
status = efi_call_early(install_configuration_table,
@@ -126,9 +178,3 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg)
err_free:
efi_call_early(free_pool, log_tbl);
}
-
-void efi_retrieve_tpm2_eventlog(efi_system_table_t *sys_table_arg)
-{
- /* Only try to retrieve the logs in 1.2 format. */
- efi_retrieve_tpm2_eventlog_1_2(sys_table_arg);
-}
diff --git a/drivers/firmware/efi/tpm.c b/drivers/firmware/efi/tpm.c
index 3a689b40ccc0..1d3f5ca3eaaf 100644
--- a/drivers/firmware/efi/tpm.c
+++ b/drivers/firmware/efi/tpm.c
@@ -4,11 +4,34 @@
* Thiebaud Weksteen <tweek@google.com>
*/
+#define TPM_MEMREMAP(start, size) early_memremap(start, size)
+#define TPM_MEMUNMAP(start, size) early_memunmap(start, size)
+
+#include <asm/early_ioremap.h>
#include <linux/efi.h>
#include <linux/init.h>
#include <linux/memblock.h>
+#include <linux/tpm_eventlog.h>
-#include <asm/early_ioremap.h>
+int efi_tpm_final_log_size;
+EXPORT_SYMBOL(efi_tpm_final_log_size);
+
+static int tpm2_calc_event_log_size(void *data, int count, void *size_info)
+{
+ struct tcg_pcr_event2_head *header;
+ int event_size, size = 0;
+
+ while (count > 0) {
+ header = data + size;
+ event_size = __calc_tpm2_event_size(header, size_info, true);
+ if (event_size == 0)
+ return -1;
+ size += event_size;
+ count--;
+ }
+
+ return size;
+}
/*
* Reserve the memory associated with the TPM Event Log configuration table.
@@ -16,22 +39,54 @@
int __init efi_tpm_eventlog_init(void)
{
struct linux_efi_tpm_eventlog *log_tbl;
+ struct efi_tcg2_final_events_table *final_tbl;
unsigned int tbl_size;
+ int ret = 0;
- if (efi.tpm_log == EFI_INVALID_TABLE_ADDR)
+ if (efi.tpm_log == EFI_INVALID_TABLE_ADDR) {
+ /*
+ * We can't calculate the size of the final events without the
+ * first entry in the TPM log, so bail here.
+ */
return 0;
+ }
log_tbl = early_memremap(efi.tpm_log, sizeof(*log_tbl));
if (!log_tbl) {
pr_err("Failed to map TPM Event Log table @ 0x%lx\n",
- efi.tpm_log);
+ efi.tpm_log);
efi.tpm_log = EFI_INVALID_TABLE_ADDR;
return -ENOMEM;
}
tbl_size = sizeof(*log_tbl) + log_tbl->size;
memblock_reserve(efi.tpm_log, tbl_size);
+
+ if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR)
+ goto out;
+
+ final_tbl = early_memremap(efi.tpm_final_log, sizeof(*final_tbl));
+
+ if (!final_tbl) {
+ pr_err("Failed to map TPM Final Event Log table @ 0x%lx\n",
+ efi.tpm_final_log);
+ efi.tpm_final_log = EFI_INVALID_TABLE_ADDR;
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ tbl_size = tpm2_calc_event_log_size((void *)efi.tpm_final_log
+ + sizeof(final_tbl->version)
+ + sizeof(final_tbl->nr_events),
+ final_tbl->nr_events,
+ log_tbl->log);
+ memblock_reserve((unsigned long)final_tbl,
+ tbl_size + sizeof(*final_tbl));
+ early_memunmap(final_tbl, sizeof(*final_tbl));
+ efi_tpm_final_log_size = tbl_size;
+
+out:
early_memunmap(log_tbl, sizeof(*log_tbl));
- return 0;
+ return ret;
}
diff --git a/drivers/firmware/google/coreboot_table.h b/drivers/firmware/google/coreboot_table.h
index 1f63b3034b17..7b7b4a6eedda 100644
--- a/drivers/firmware/google/coreboot_table.h
+++ b/drivers/firmware/google/coreboot_table.h
@@ -12,7 +12,7 @@
#ifndef __COREBOOT_TABLE_H
#define __COREBOOT_TABLE_H
-#include <linux/io.h>
+#include <linux/device.h>
/* Coreboot table header structure */
struct coreboot_table_header {
@@ -83,4 +83,13 @@ int coreboot_driver_register(struct coreboot_driver *driver);
/* Unregister a driver that uses the data from a coreboot table. */
void coreboot_driver_unregister(struct coreboot_driver *driver);
+/* module_coreboot_driver() - Helper macro for drivers that don't do
+ * anything special in module init/exit. This eliminates a lot of
+ * boilerplate. Each module may only use this macro once, and
+ * calling it replaces module_init() and module_exit()
+ */
+#define module_coreboot_driver(__coreboot_driver) \
+ module_driver(__coreboot_driver, coreboot_driver_register, \
+ coreboot_driver_unregister)
+
#endif /* __COREBOOT_TABLE_H */
diff --git a/drivers/firmware/google/framebuffer-coreboot.c b/drivers/firmware/google/framebuffer-coreboot.c
index 7e67b651e4ac..916f26adc595 100644
--- a/drivers/firmware/google/framebuffer-coreboot.c
+++ b/drivers/firmware/google/framebuffer-coreboot.c
@@ -89,19 +89,7 @@ static struct coreboot_driver framebuffer_driver = {
},
.tag = CB_TAG_FRAMEBUFFER,
};
-
-static int __init coreboot_framebuffer_init(void)
-{
- return coreboot_driver_register(&framebuffer_driver);
-}
-
-static void coreboot_framebuffer_exit(void)
-{
- coreboot_driver_unregister(&framebuffer_driver);
-}
-
-module_init(coreboot_framebuffer_init);
-module_exit(coreboot_framebuffer_exit);
+module_coreboot_driver(framebuffer_driver);
MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>");
MODULE_LICENSE("GPL");
diff --git a/drivers/firmware/google/memconsole-coreboot.c b/drivers/firmware/google/memconsole-coreboot.c
index ac90e8536565..fd7f0fbec07e 100644
--- a/drivers/firmware/google/memconsole-coreboot.c
+++ b/drivers/firmware/google/memconsole-coreboot.c
@@ -8,6 +8,7 @@
*/
#include <linux/device.h>
+#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -26,7 +27,7 @@ struct cbmem_cons {
#define CURSOR_MASK ((1 << 28) - 1)
#define OVERFLOW (1 << 31)
-static struct cbmem_cons __iomem *cbmem_console;
+static struct cbmem_cons *cbmem_console;
static u32 cbmem_console_size;
/*
@@ -67,7 +68,7 @@ static ssize_t memconsole_coreboot_read(char *buf, loff_t pos, size_t count)
static int memconsole_probe(struct coreboot_device *dev)
{
- struct cbmem_cons __iomem *tmp_cbmc;
+ struct cbmem_cons *tmp_cbmc;
tmp_cbmc = memremap(dev->cbmem_ref.cbmem_addr,
sizeof(*tmp_cbmc), MEMREMAP_WB);
@@ -77,13 +78,13 @@ static int memconsole_probe(struct coreboot_device *dev)
/* Read size only once to prevent overrun attack through /dev/mem. */
cbmem_console_size = tmp_cbmc->size_dont_access_after_boot;
- cbmem_console = memremap(dev->cbmem_ref.cbmem_addr,
+ cbmem_console = devm_memremap(&dev->dev, dev->cbmem_ref.cbmem_addr,
cbmem_console_size + sizeof(*cbmem_console),
MEMREMAP_WB);
memunmap(tmp_cbmc);
- if (!cbmem_console)
- return -ENOMEM;
+ if (IS_ERR(cbmem_console))
+ return PTR_ERR(cbmem_console);
memconsole_setup(memconsole_coreboot_read);
@@ -94,9 +95,6 @@ static int memconsole_remove(struct coreboot_device *dev)
{
memconsole_exit();
- if (cbmem_console)
- memunmap(cbmem_console);
-
return 0;
}
@@ -108,19 +106,7 @@ static struct coreboot_driver memconsole_driver = {
},
.tag = CB_TAG_CBMEM_CONSOLE,
};
-
-static void coreboot_memconsole_exit(void)
-{
- coreboot_driver_unregister(&memconsole_driver);
-}
-
-static int __init coreboot_memconsole_init(void)
-{
- return coreboot_driver_register(&memconsole_driver);
-}
-
-module_exit(coreboot_memconsole_exit);
-module_init(coreboot_memconsole_init);
+module_coreboot_driver(memconsole_driver);
MODULE_AUTHOR("Google, Inc.");
MODULE_LICENSE("GPL");
diff --git a/drivers/firmware/google/memconsole.c b/drivers/firmware/google/memconsole.c
index fe5aa740c34d..44d314ad69e4 100644
--- a/drivers/firmware/google/memconsole.c
+++ b/drivers/firmware/google/memconsole.c
@@ -7,21 +7,22 @@
* Copyright 2017 Google Inc.
*/
-#include <linux/init.h>
#include <linux/sysfs.h>
#include <linux/kobject.h>
#include <linux/module.h>
#include "memconsole.h"
-static ssize_t (*memconsole_read_func)(char *, loff_t, size_t);
-
static ssize_t memconsole_read(struct file *filp, struct kobject *kobp,
struct bin_attribute *bin_attr, char *buf,
loff_t pos, size_t count)
{
+ ssize_t (*memconsole_read_func)(char *, loff_t, size_t);
+
+ memconsole_read_func = bin_attr->private;
if (WARN_ON_ONCE(!memconsole_read_func))
return -EIO;
+
return memconsole_read_func(buf, pos, count);
}
@@ -32,7 +33,7 @@ static struct bin_attribute memconsole_bin_attr = {
void memconsole_setup(ssize_t (*read_func)(char *, loff_t, size_t))
{
- memconsole_read_func = read_func;
+ memconsole_bin_attr.private = read_func;
}
EXPORT_SYMBOL(memconsole_setup);
diff --git a/drivers/firmware/google/vpd.c b/drivers/firmware/google/vpd.c
index fd5212c395c0..0739f3b70347 100644
--- a/drivers/firmware/google/vpd.c
+++ b/drivers/firmware/google/vpd.c
@@ -316,19 +316,7 @@ static struct coreboot_driver vpd_driver = {
},
.tag = CB_TAG_VPD,
};
-
-static int __init coreboot_vpd_init(void)
-{
- return coreboot_driver_register(&vpd_driver);
-}
-
-static void __exit coreboot_vpd_exit(void)
-{
- coreboot_driver_unregister(&vpd_driver);
-}
-
-module_init(coreboot_vpd_init);
-module_exit(coreboot_vpd_exit);
+module_coreboot_driver(vpd_driver);
MODULE_AUTHOR("Google, Inc.");
MODULE_LICENSE("GPL");
diff --git a/drivers/firmware/google/vpd_decode.c b/drivers/firmware/google/vpd_decode.c
index c62fa7063a7c..92e3258552fc 100644
--- a/drivers/firmware/google/vpd_decode.c
+++ b/drivers/firmware/google/vpd_decode.c
@@ -7,8 +7,6 @@
* Copyright 2017 Google Inc.
*/
-#include <linux/export.h>
-
#include "vpd_decode.h"
static int vpd_decode_len(const s32 max_len, const u8 *in,
diff --git a/drivers/firmware/imx/imx-scu-irq.c b/drivers/firmware/imx/imx-scu-irq.c
index 043833ad3c1a..687121f8c4d5 100644
--- a/drivers/firmware/imx/imx-scu-irq.c
+++ b/drivers/firmware/imx/imx-scu-irq.c
@@ -100,6 +100,9 @@ int imx_scu_irq_group_enable(u8 group, u32 mask, u8 enable)
struct imx_sc_rpc_msg *hdr = &msg.hdr;
int ret;
+ if (!imx_sc_irq_ipc_handle)
+ return -EPROBE_DEFER;
+
hdr->ver = IMX_SC_RPC_VERSION;
hdr->svc = IMX_SC_RPC_SVC_IRQ;
hdr->func = IMX_SC_IRQ_FUNC_ENABLE;
diff --git a/drivers/firmware/pcdp.c b/drivers/firmware/pcdp.c
index e83d6aec0c13..4adeb7a2bdf5 100644
--- a/drivers/firmware/pcdp.c
+++ b/drivers/firmware/pcdp.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Parse the EFI PCDP table to locate the console device.
*
@@ -5,10 +6,6 @@
* Khalid Aziz <khalid.aziz@hp.com>
* Alex Williamson <alex.williamson@hp.com>
* Bjorn Helgaas <bjorn.helgaas@hp.com>
- *
- * 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.
*/
#include <linux/acpi.h>
diff --git a/drivers/firmware/pcdp.h b/drivers/firmware/pcdp.h
index e5530608e00d..ce75d1da9e84 100644
--- a/drivers/firmware/pcdp.h
+++ b/drivers/firmware/pcdp.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Definitions for PCDP-defined console devices
*
@@ -7,10 +8,6 @@
* (c) Copyright 2002, 2004 Hewlett-Packard Development Company, L.P.
* Khalid Aziz <khalid.aziz@hp.com>
* Bjorn Helgaas <bjorn.helgaas@hp.com>
- *
- * 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.
*/
#define PCDP_CONSOLE 0
diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c
index 61be15d9df7d..da26a584dca0 100644
--- a/drivers/firmware/raspberrypi.c
+++ b/drivers/firmware/raspberrypi.c
@@ -20,6 +20,7 @@
#define MBOX_CHAN_PROPERTY 8
static struct platform_device *rpi_hwmon;
+static struct platform_device *rpi_clk;
struct rpi_firmware {
struct mbox_client cl;
@@ -207,6 +208,12 @@ rpi_register_hwmon_driver(struct device *dev, struct rpi_firmware *fw)
-1, NULL, 0);
}
+static void rpi_register_clk_driver(struct device *dev)
+{
+ rpi_clk = platform_device_register_data(dev, "raspberrypi-clk",
+ -1, NULL, 0);
+}
+
static int rpi_firmware_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -234,6 +241,7 @@ static int rpi_firmware_probe(struct platform_device *pdev)
rpi_firmware_print_firmware_revision(fw);
rpi_register_hwmon_driver(dev, fw);
+ rpi_register_clk_driver(dev);
return 0;
}
@@ -254,6 +262,8 @@ static int rpi_firmware_remove(struct platform_device *pdev)
platform_device_unregister(rpi_hwmon);
rpi_hwmon = NULL;
+ platform_device_unregister(rpi_clk);
+ rpi_clk = NULL;
mbox_free_channel(fw->chan);
return 0;
diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index ef93406ace1b..7696c692ad5a 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -916,7 +916,7 @@ static int ti_sci_cmd_get_device_resets(const struct ti_sci_handle *handle,
* Return: 0 if all went well, else returns appropriate error value.
*/
static int ti_sci_set_clock_state(const struct ti_sci_handle *handle,
- u32 dev_id, u8 clk_id,
+ u32 dev_id, u32 clk_id,
u32 flags, u8 state)
{
struct ti_sci_info *info;
@@ -944,7 +944,12 @@ static int ti_sci_set_clock_state(const struct ti_sci_handle *handle,
}
req = (struct ti_sci_msg_req_set_clock_state *)xfer->xfer_buf;
req->dev_id = dev_id;
- req->clk_id = clk_id;
+ if (clk_id < 255) {
+ req->clk_id = clk_id;
+ } else {
+ req->clk_id = 255;
+ req->clk_id_32 = clk_id;
+ }
req->request_state = state;
ret = ti_sci_do_xfer(info, xfer);
@@ -976,7 +981,7 @@ fail:
* Return: 0 if all went well, else returns appropriate error value.
*/
static int ti_sci_cmd_get_clock_state(const struct ti_sci_handle *handle,
- u32 dev_id, u8 clk_id,
+ u32 dev_id, u32 clk_id,
u8 *programmed_state, u8 *current_state)
{
struct ti_sci_info *info;
@@ -1007,7 +1012,12 @@ static int ti_sci_cmd_get_clock_state(const struct ti_sci_handle *handle,
}
req = (struct ti_sci_msg_req_get_clock_state *)xfer->xfer_buf;
req->dev_id = dev_id;
- req->clk_id = clk_id;
+ if (clk_id < 255) {
+ req->clk_id = clk_id;
+ } else {
+ req->clk_id = 255;
+ req->clk_id_32 = clk_id;
+ }
ret = ti_sci_do_xfer(info, xfer);
if (ret) {
@@ -1047,8 +1057,8 @@ fail:
* Return: 0 if all went well, else returns appropriate error value.
*/
static int ti_sci_cmd_get_clock(const struct ti_sci_handle *handle, u32 dev_id,
- u8 clk_id, bool needs_ssc, bool can_change_freq,
- bool enable_input_term)
+ u32 clk_id, bool needs_ssc,
+ bool can_change_freq, bool enable_input_term)
{
u32 flags = 0;
@@ -1073,7 +1083,7 @@ static int ti_sci_cmd_get_clock(const struct ti_sci_handle *handle, u32 dev_id,
* Return: 0 if all went well, else returns appropriate error value.
*/
static int ti_sci_cmd_idle_clock(const struct ti_sci_handle *handle,
- u32 dev_id, u8 clk_id)
+ u32 dev_id, u32 clk_id)
{
return ti_sci_set_clock_state(handle, dev_id, clk_id, 0,
MSG_CLOCK_SW_STATE_UNREQ);
@@ -1092,7 +1102,7 @@ static int ti_sci_cmd_idle_clock(const struct ti_sci_handle *handle,
* Return: 0 if all went well, else returns appropriate error value.
*/
static int ti_sci_cmd_put_clock(const struct ti_sci_handle *handle,
- u32 dev_id, u8 clk_id)
+ u32 dev_id, u32 clk_id)
{
return ti_sci_set_clock_state(handle, dev_id, clk_id, 0,
MSG_CLOCK_SW_STATE_AUTO);
@@ -1110,7 +1120,7 @@ static int ti_sci_cmd_put_clock(const struct ti_sci_handle *handle,
* Return: 0 if all went well, else returns appropriate error value.
*/
static int ti_sci_cmd_clk_is_auto(const struct ti_sci_handle *handle,
- u32 dev_id, u8 clk_id, bool *req_state)
+ u32 dev_id, u32 clk_id, bool *req_state)
{
u8 state = 0;
int ret;
@@ -1139,7 +1149,7 @@ static int ti_sci_cmd_clk_is_auto(const struct ti_sci_handle *handle,
* Return: 0 if all went well, else returns appropriate error value.
*/
static int ti_sci_cmd_clk_is_on(const struct ti_sci_handle *handle, u32 dev_id,
- u8 clk_id, bool *req_state, bool *curr_state)
+ u32 clk_id, bool *req_state, bool *curr_state)
{
u8 c_state = 0, r_state = 0;
int ret;
@@ -1172,7 +1182,7 @@ static int ti_sci_cmd_clk_is_on(const struct ti_sci_handle *handle, u32 dev_id,
* Return: 0 if all went well, else returns appropriate error value.
*/
static int ti_sci_cmd_clk_is_off(const struct ti_sci_handle *handle, u32 dev_id,
- u8 clk_id, bool *req_state, bool *curr_state)
+ u32 clk_id, bool *req_state, bool *curr_state)
{
u8 c_state = 0, r_state = 0;
int ret;
@@ -1204,7 +1214,7 @@ static int ti_sci_cmd_clk_is_off(const struct ti_sci_handle *handle, u32 dev_id,
* Return: 0 if all went well, else returns appropriate error value.
*/
static int ti_sci_cmd_clk_set_parent(const struct ti_sci_handle *handle,
- u32 dev_id, u8 clk_id, u8 parent_id)
+ u32 dev_id, u32 clk_id, u32 parent_id)
{
struct ti_sci_info *info;
struct ti_sci_msg_req_set_clock_parent *req;
@@ -1231,8 +1241,18 @@ static int ti_sci_cmd_clk_set_parent(const struct ti_sci_handle *handle,
}
req = (struct ti_sci_msg_req_set_clock_parent *)xfer->xfer_buf;
req->dev_id = dev_id;
- req->clk_id = clk_id;
- req->parent_id = parent_id;
+ if (clk_id < 255) {
+ req->clk_id = clk_id;
+ } else {
+ req->clk_id = 255;
+ req->clk_id_32 = clk_id;
+ }
+ if (parent_id < 255) {
+ req->parent_id = parent_id;
+ } else {
+ req->parent_id = 255;
+ req->parent_id_32 = parent_id;
+ }
ret = ti_sci_do_xfer(info, xfer);
if (ret) {
@@ -1262,7 +1282,7 @@ fail:
* Return: 0 if all went well, else returns appropriate error value.
*/
static int ti_sci_cmd_clk_get_parent(const struct ti_sci_handle *handle,
- u32 dev_id, u8 clk_id, u8 *parent_id)
+ u32 dev_id, u32 clk_id, u32 *parent_id)
{
struct ti_sci_info *info;
struct ti_sci_msg_req_get_clock_parent *req;
@@ -1289,7 +1309,12 @@ static int ti_sci_cmd_clk_get_parent(const struct ti_sci_handle *handle,
}
req = (struct ti_sci_msg_req_get_clock_parent *)xfer->xfer_buf;
req->dev_id = dev_id;
- req->clk_id = clk_id;
+ if (clk_id < 255) {
+ req->clk_id = clk_id;
+ } else {
+ req->clk_id = 255;
+ req->clk_id_32 = clk_id;
+ }
ret = ti_sci_do_xfer(info, xfer);
if (ret) {
@@ -1299,10 +1324,14 @@ static int ti_sci_cmd_clk_get_parent(const struct ti_sci_handle *handle,
resp = (struct ti_sci_msg_resp_get_clock_parent *)xfer->xfer_buf;
- if (!ti_sci_is_response_ack(resp))
+ if (!ti_sci_is_response_ack(resp)) {
ret = -ENODEV;
- else
- *parent_id = resp->parent_id;
+ } else {
+ if (resp->parent_id < 255)
+ *parent_id = resp->parent_id;
+ else
+ *parent_id = resp->parent_id_32;
+ }
fail:
ti_sci_put_one_xfer(&info->minfo, xfer);
@@ -1322,8 +1351,8 @@ fail:
* Return: 0 if all went well, else returns appropriate error value.
*/
static int ti_sci_cmd_clk_get_num_parents(const struct ti_sci_handle *handle,
- u32 dev_id, u8 clk_id,
- u8 *num_parents)
+ u32 dev_id, u32 clk_id,
+ u32 *num_parents)
{
struct ti_sci_info *info;
struct ti_sci_msg_req_get_clock_num_parents *req;
@@ -1350,7 +1379,12 @@ static int ti_sci_cmd_clk_get_num_parents(const struct ti_sci_handle *handle,
}
req = (struct ti_sci_msg_req_get_clock_num_parents *)xfer->xfer_buf;
req->dev_id = dev_id;
- req->clk_id = clk_id;
+ if (clk_id < 255) {
+ req->clk_id = clk_id;
+ } else {
+ req->clk_id = 255;
+ req->clk_id_32 = clk_id;
+ }
ret = ti_sci_do_xfer(info, xfer);
if (ret) {
@@ -1360,10 +1394,14 @@ static int ti_sci_cmd_clk_get_num_parents(const struct ti_sci_handle *handle,
resp = (struct ti_sci_msg_resp_get_clock_num_parents *)xfer->xfer_buf;
- if (!ti_sci_is_response_ack(resp))
+ if (!ti_sci_is_response_ack(resp)) {
ret = -ENODEV;
- else
- *num_parents = resp->num_parents;
+ } else {
+ if (resp->num_parents < 255)
+ *num_parents = resp->num_parents;
+ else
+ *num_parents = resp->num_parents_32;
+ }
fail:
ti_sci_put_one_xfer(&info->minfo, xfer);
@@ -1391,7 +1429,7 @@ fail:
* Return: 0 if all went well, else returns appropriate error value.
*/
static int ti_sci_cmd_clk_get_match_freq(const struct ti_sci_handle *handle,
- u32 dev_id, u8 clk_id, u64 min_freq,
+ u32 dev_id, u32 clk_id, u64 min_freq,
u64 target_freq, u64 max_freq,
u64 *match_freq)
{
@@ -1420,7 +1458,12 @@ static int ti_sci_cmd_clk_get_match_freq(const struct ti_sci_handle *handle,
}
req = (struct ti_sci_msg_req_query_clock_freq *)xfer->xfer_buf;
req->dev_id = dev_id;
- req->clk_id = clk_id;
+ if (clk_id < 255) {
+ req->clk_id = clk_id;
+ } else {
+ req->clk_id = 255;
+ req->clk_id_32 = clk_id;
+ }
req->min_freq_hz = min_freq;
req->target_freq_hz = target_freq;
req->max_freq_hz = max_freq;
@@ -1463,7 +1506,7 @@ fail:
* Return: 0 if all went well, else returns appropriate error value.
*/
static int ti_sci_cmd_clk_set_freq(const struct ti_sci_handle *handle,
- u32 dev_id, u8 clk_id, u64 min_freq,
+ u32 dev_id, u32 clk_id, u64 min_freq,
u64 target_freq, u64 max_freq)
{
struct ti_sci_info *info;
@@ -1491,7 +1534,12 @@ static int ti_sci_cmd_clk_set_freq(const struct ti_sci_handle *handle,
}
req = (struct ti_sci_msg_req_set_clock_freq *)xfer->xfer_buf;
req->dev_id = dev_id;
- req->clk_id = clk_id;
+ if (clk_id < 255) {
+ req->clk_id = clk_id;
+ } else {
+ req->clk_id = 255;
+ req->clk_id_32 = clk_id;
+ }
req->min_freq_hz = min_freq;
req->target_freq_hz = target_freq;
req->max_freq_hz = max_freq;
@@ -1524,7 +1572,7 @@ fail:
* Return: 0 if all went well, else returns appropriate error value.
*/
static int ti_sci_cmd_clk_get_freq(const struct ti_sci_handle *handle,
- u32 dev_id, u8 clk_id, u64 *freq)
+ u32 dev_id, u32 clk_id, u64 *freq)
{
struct ti_sci_info *info;
struct ti_sci_msg_req_get_clock_freq *req;
@@ -1551,7 +1599,12 @@ static int ti_sci_cmd_clk_get_freq(const struct ti_sci_handle *handle,
}
req = (struct ti_sci_msg_req_get_clock_freq *)xfer->xfer_buf;
req->dev_id = dev_id;
- req->clk_id = clk_id;
+ if (clk_id < 255) {
+ req->clk_id = clk_id;
+ } else {
+ req->clk_id = 255;
+ req->clk_id_32 = clk_id;
+ }
ret = ti_sci_do_xfer(info, xfer);
if (ret) {
@@ -2349,12 +2402,13 @@ devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle,
if (!res)
return ERR_PTR(-ENOMEM);
- res->sets = of_property_count_elems_of_size(dev_of_node(dev), of_prop,
- sizeof(u32));
- if (res->sets < 0) {
+ ret = of_property_count_elems_of_size(dev_of_node(dev), of_prop,
+ sizeof(u32));
+ if (ret < 0) {
dev_err(dev, "%s resource type ids not available\n", of_prop);
- return ERR_PTR(res->sets);
+ return ERR_PTR(ret);
}
+ res->sets = ret;
res->desc = devm_kcalloc(dev, res->sets, sizeof(*res->desc),
GFP_KERNEL);
diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h
index 4983827151bf..414e0ced5409 100644
--- a/drivers/firmware/ti_sci.h
+++ b/drivers/firmware/ti_sci.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: BSD-3-Clause
+/* SPDX-License-Identifier: BSD-3-Clause */
/*
* Texas Instruments System Control Interface (TISCI) Protocol
*
@@ -202,7 +202,8 @@ struct ti_sci_msg_req_set_device_resets {
* @dev_id: Device identifier this request is for
* @clk_id: Clock identifier for the device for this request.
* Each device has it's own set of clock inputs. This indexes
- * which clock input to modify.
+ * which clock input to modify. Set to 255 if clock ID is
+ * greater than or equal to 255.
* @request_state: Request the state for the clock to be set to.
* MSG_CLOCK_SW_STATE_UNREQ: The IP does not require this clock,
* it can be disabled, regardless of the state of the device
@@ -213,6 +214,9 @@ struct ti_sci_msg_req_set_device_resets {
* being required by the device.(default)
* MSG_CLOCK_SW_STATE_REQ: Configure the clock to be enabled,
* regardless of the state of the device.
+ * @clk_id_32: Clock identifier for the device for this request.
+ * Only to be used if the clock ID is greater than or equal to
+ * 255.
*
* Normally, all required clocks are managed by TISCI entity, this is used
* only for specific control *IF* required. Auto managed state is
@@ -234,6 +238,7 @@ struct ti_sci_msg_req_set_clock_state {
#define MSG_CLOCK_SW_STATE_AUTO 1
#define MSG_CLOCK_SW_STATE_REQ 2
u8 request_state;
+ u32 clk_id_32;
} __packed;
/**
@@ -242,7 +247,11 @@ struct ti_sci_msg_req_set_clock_state {
* @dev_id: Device identifier this request is for
* @clk_id: Clock identifier for the device for this request.
* Each device has it's own set of clock inputs. This indexes
- * which clock input to get state of.
+ * which clock input to get state of. Set to 255 if the clock
+ * ID is greater than or equal to 255.
+ * @clk_id_32: Clock identifier for the device for the request.
+ * Only to be used if the clock ID is greater than or equal to
+ * 255.
*
* Request type is TI_SCI_MSG_GET_CLOCK_STATE, response is state
* of the clock
@@ -251,6 +260,7 @@ struct ti_sci_msg_req_get_clock_state {
struct ti_sci_msg_hdr hdr;
u32 dev_id;
u8 clk_id;
+ u32 clk_id_32;
} __packed;
/**
@@ -278,9 +288,13 @@ struct ti_sci_msg_resp_get_clock_state {
* @dev_id: Device identifier this request is for
* @clk_id: Clock identifier for the device for this request.
* Each device has it's own set of clock inputs. This indexes
- * which clock input to modify.
+ * which clock input to modify. Set to 255 if clock ID is
+ * greater than or equal to 255.
* @parent_id: The new clock parent is selectable by an index via this
- * parameter.
+ * parameter. Set to 255 if clock ID is greater than or
+ * equal to 255.
+ * @clk_id_32: Clock identifier if @clk_id field is 255.
+ * @parent_id_32: Parent identifier if @parent_id is 255.
*
* Request type is TI_SCI_MSG_SET_CLOCK_PARENT, response is generic
* ACK / NACK message.
@@ -290,6 +304,8 @@ struct ti_sci_msg_req_set_clock_parent {
u32 dev_id;
u8 clk_id;
u8 parent_id;
+ u32 clk_id_32;
+ u32 parent_id_32;
} __packed;
/**
@@ -298,7 +314,10 @@ struct ti_sci_msg_req_set_clock_parent {
* @dev_id: Device identifier this request is for
* @clk_id: Clock identifier for the device for this request.
* Each device has it's own set of clock inputs. This indexes
- * which clock input to get the parent for.
+ * which clock input to get the parent for. If this field
+ * contains 255, the actual clock identifier is stored in
+ * @clk_id_32.
+ * @clk_id_32: Clock identifier if the @clk_id field contains 255.
*
* Request type is TI_SCI_MSG_GET_CLOCK_PARENT, response is parent information
*/
@@ -306,25 +325,32 @@ struct ti_sci_msg_req_get_clock_parent {
struct ti_sci_msg_hdr hdr;
u32 dev_id;
u8 clk_id;
+ u32 clk_id_32;
} __packed;
/**
* struct ti_sci_msg_resp_get_clock_parent - Response with clock parent
* @hdr: Generic Header
- * @parent_id: The current clock parent
+ * @parent_id: The current clock parent. If set to 255, the current parent
+ * ID can be found from the @parent_id_32 field.
+ * @parent_id_32: Current clock parent if @parent_id field is set to
+ * 255.
*
* Response to TI_SCI_MSG_GET_CLOCK_PARENT.
*/
struct ti_sci_msg_resp_get_clock_parent {
struct ti_sci_msg_hdr hdr;
u8 parent_id;
+ u32 parent_id_32;
} __packed;
/**
* struct ti_sci_msg_req_get_clock_num_parents - Request to get clock parents
* @hdr: Generic header
* @dev_id: Device identifier this request is for
- * @clk_id: Clock identifier for the device for this request.
+ * @clk_id: Clock identifier for the device for this request. Set to
+ * 255 if clock ID is greater than or equal to 255.
+ * @clk_id_32: Clock identifier if the @clk_id field contains 255.
*
* This request provides information about how many clock parent options
* are available for a given clock to a device. This is typically used
@@ -337,18 +363,24 @@ struct ti_sci_msg_req_get_clock_num_parents {
struct ti_sci_msg_hdr hdr;
u32 dev_id;
u8 clk_id;
+ u32 clk_id_32;
} __packed;
/**
* struct ti_sci_msg_resp_get_clock_num_parents - Response for get clk parents
* @hdr: Generic header
- * @num_parents: Number of clock parents
+ * @num_parents: Number of clock parents. If set to 255, the actual
+ * number of parents is stored into @num_parents_32
+ * field instead.
+ * @num_parents_32: Number of clock parents if @num_parents field is
+ * set to 255.
*
* Response to TI_SCI_MSG_GET_NUM_CLOCK_PARENTS
*/
struct ti_sci_msg_resp_get_clock_num_parents {
struct ti_sci_msg_hdr hdr;
u8 num_parents;
+ u32 num_parents_32;
} __packed;
/**
@@ -363,7 +395,9 @@ struct ti_sci_msg_resp_get_clock_num_parents {
* @max_freq_hz: The maximum allowable frequency in Hz. This is the maximum
* allowable programmed frequency and does not account for clock
* tolerances and jitter.
- * @clk_id: Clock identifier for the device for this request.
+ * @clk_id: Clock identifier for the device for this request. Set to
+ * 255 if clock identifier is greater than or equal to 255.
+ * @clk_id_32: Clock identifier if @clk_id is set to 255.
*
* NOTE: Normally clock frequency management is automatically done by TISCI
* entity. In case of specific requests, TISCI evaluates capability to achieve
@@ -380,6 +414,7 @@ struct ti_sci_msg_req_query_clock_freq {
u64 target_freq_hz;
u64 max_freq_hz;
u8 clk_id;
+ u32 clk_id_32;
} __packed;
/**
@@ -407,7 +442,9 @@ struct ti_sci_msg_resp_query_clock_freq {
* @max_freq_hz: The maximum allowable frequency in Hz. This is the maximum
* allowable programmed frequency and does not account for clock
* tolerances and jitter.
- * @clk_id: Clock identifier for the device for this request.
+ * @clk_id: Clock identifier for the device for this request. Set to
+ * 255 if clock ID is greater than or equal to 255.
+ * @clk_id_32: Clock identifier if @clk_id field is set to 255.
*
* NOTE: Normally clock frequency management is automatically done by TISCI
* entity. In case of specific requests, TISCI evaluates capability to achieve
@@ -436,13 +473,16 @@ struct ti_sci_msg_req_set_clock_freq {
u64 target_freq_hz;
u64 max_freq_hz;
u8 clk_id;
+ u32 clk_id_32;
} __packed;
/**
* struct ti_sci_msg_req_get_clock_freq - Request to get the clock frequency
* @hdr: Generic Header
* @dev_id: Device identifier this request is for
- * @clk_id: Clock identifier for the device for this request.
+ * @clk_id: Clock identifier for the device for this request. Set to
+ * 255 if clock ID is greater than or equal to 255.
+ * @clk_id_32: Clock identifier if @clk_id field is set to 255.
*
* NOTE: Normally clock frequency management is automatically done by TISCI
* entity. In some cases, clock frequencies are configured by host.
@@ -454,6 +494,7 @@ struct ti_sci_msg_req_get_clock_freq {
struct ti_sci_msg_hdr hdr;
u32 dev_id;
u8 clk_id;
+ u32 clk_id_32;
} __packed;
/**
diff --git a/drivers/fmc/Kconfig b/drivers/fmc/Kconfig
deleted file mode 100644
index ae3d7f634932..000000000000
--- a/drivers/fmc/Kconfig
+++ /dev/null
@@ -1,52 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# FMC (ANSI-VITA 57.1) bus support
-#
-
-menuconfig FMC
- tristate "FMC support"
- help
-
- FMC (FPGA Mezzanine Carrier) is a mechanical and electrical
- standard for mezzanine cards that plug into a carrier board.
- This kernel subsystem supports the matching between carrier
- and mezzanine based on identifiers stored in the internal I2C
- EEPROM, as well as having carrier-independent drivers.
-
- The framework was born outside of the kernel and at this time
- the off-tree code base is more complete. Code and documentation
- is at git://ohwr.org/fmc-projects/fmc-bus.git .
-
-if FMC
-
-config FMC_FAKEDEV
- tristate "FMC fake device (software testing)"
- help
- This is a fake carrier, bringing a default EEPROM content
- that can be rewritten at run time and usef for matching
- mezzanines.
-
-config FMC_TRIVIAL
- tristate "FMC trivial mezzanine driver (software testing)"
- help
- This is a fake mezzanine driver, to show how FMC works and test it.
- The driver also handles interrupts (we used it with a real carrier
- before the mezzanines were produced)
-
-config FMC_WRITE_EEPROM
- tristate "FMC mezzanine driver to write I2C EEPROM"
- help
- This driver matches every mezzanine device and can write the
- internal EEPROM of the PCB, using the firmware loader to get
- its binary and the function carrier->reprogram to actually do it.
- It is useful when the mezzanines are produced.
-
-config FMC_CHARDEV
- tristate "FMC mezzanine driver that registers a char device"
- help
- This driver matches every mezzanine device and allows user
- space to read and write registers using a char device. It
- can be used to write user-space drivers, or just get
- acquainted with a mezzanine before writing its specific driver.
-
-endif # FMC
diff --git a/drivers/fmc/Makefile b/drivers/fmc/Makefile
deleted file mode 100644
index e3da6192cf39..000000000000
--- a/drivers/fmc/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-obj-$(CONFIG_FMC) += fmc.o
-
-fmc-y = fmc-core.o
-fmc-y += fmc-match.o
-fmc-y += fmc-sdb.o
-fmc-y += fru-parse.o
-fmc-y += fmc-dump.o
-fmc-y += fmc-debug.o
-
-obj-$(CONFIG_FMC_FAKEDEV) += fmc-fakedev.o
-obj-$(CONFIG_FMC_TRIVIAL) += fmc-trivial.o
-obj-$(CONFIG_FMC_WRITE_EEPROM) += fmc-write-eeprom.o
-obj-$(CONFIG_FMC_CHARDEV) += fmc-chardev.o
diff --git a/drivers/fmc/fmc-chardev.c b/drivers/fmc/fmc-chardev.c
deleted file mode 100644
index 7d2091b5e978..000000000000
--- a/drivers/fmc/fmc-chardev.c
+++ /dev/null
@@ -1,199 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2012 CERN (www.cern.ch)
- * Author: Alessandro Rubini <rubini@gnudd.com>
- *
- * This work is part of the White Rabbit project, a research effort led
- * by CERN, the European Institute for Nuclear Research.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
-#include <linux/spinlock.h>
-#include <linux/fmc.h>
-#include <linux/uaccess.h>
-
-static LIST_HEAD(fc_devices);
-static DEFINE_SPINLOCK(fc_lock);
-
-struct fc_instance {
- struct list_head list;
- struct fmc_device *fmc;
- struct miscdevice misc;
-};
-
-/* at open time, we must identify our device */
-static int fc_open(struct inode *ino, struct file *f)
-{
- struct fmc_device *fmc;
- struct fc_instance *fc;
- int minor = iminor(ino);
-
- list_for_each_entry(fc, &fc_devices, list)
- if (fc->misc.minor == minor)
- break;
- if (fc->misc.minor != minor)
- return -ENODEV;
- fmc = fc->fmc;
- if (try_module_get(fmc->owner) == 0)
- return -ENODEV;
-
- f->private_data = fmc;
- return 0;
-}
-
-static int fc_release(struct inode *ino, struct file *f)
-{
- struct fmc_device *fmc = f->private_data;
- module_put(fmc->owner);
- return 0;
-}
-
-/* read and write are simple after the default llseek has been used */
-static ssize_t fc_read(struct file *f, char __user *buf, size_t count,
- loff_t *offp)
-{
- struct fmc_device *fmc = f->private_data;
- unsigned long addr;
- uint32_t val;
-
- if (count < sizeof(val))
- return -EINVAL;
- count = sizeof(val);
-
- addr = *offp;
- if (addr > fmc->memlen)
- return -ESPIPE; /* Illegal seek */
- val = fmc_readl(fmc, addr);
- if (copy_to_user(buf, &val, count))
- return -EFAULT;
- *offp += count;
- return count;
-}
-
-static ssize_t fc_write(struct file *f, const char __user *buf, size_t count,
- loff_t *offp)
-{
- struct fmc_device *fmc = f->private_data;
- unsigned long addr;
- uint32_t val;
-
- if (count < sizeof(val))
- return -EINVAL;
- count = sizeof(val);
-
- addr = *offp;
- if (addr > fmc->memlen)
- return -ESPIPE; /* Illegal seek */
- if (copy_from_user(&val, buf, count))
- return -EFAULT;
- fmc_writel(fmc, val, addr);
- *offp += count;
- return count;
-}
-
-static const struct file_operations fc_fops = {
- .owner = THIS_MODULE,
- .open = fc_open,
- .release = fc_release,
- .llseek = generic_file_llseek,
- .read = fc_read,
- .write = fc_write,
-};
-
-
-/* Device part .. */
-static int fc_probe(struct fmc_device *fmc);
-static int fc_remove(struct fmc_device *fmc);
-
-static struct fmc_driver fc_drv = {
- .version = FMC_VERSION,
- .driver.name = KBUILD_MODNAME,
- .probe = fc_probe,
- .remove = fc_remove,
- /* no table: we want to match everything */
-};
-
-/* We accept the generic busid parameter */
-FMC_PARAM_BUSID(fc_drv);
-
-/* probe and remove must allocate and release a misc device */
-static int fc_probe(struct fmc_device *fmc)
-{
- int ret;
- int index = 0;
-
- struct fc_instance *fc;
-
- index = fmc_validate(fmc, &fc_drv);
- if (index < 0)
- return -EINVAL; /* not our device: invalid */
-
- /* Create a char device: we want to create it anew */
- fc = kzalloc(sizeof(*fc), GFP_KERNEL);
- if (!fc)
- return -ENOMEM;
- fc->fmc = fmc;
- fc->misc.minor = MISC_DYNAMIC_MINOR;
- fc->misc.fops = &fc_fops;
- fc->misc.name = kstrdup(dev_name(&fmc->dev), GFP_KERNEL);
-
- ret = misc_register(&fc->misc);
- if (ret < 0)
- goto out;
- spin_lock(&fc_lock);
- list_add(&fc->list, &fc_devices);
- spin_unlock(&fc_lock);
- dev_info(&fc->fmc->dev, "Created misc device \"%s\"\n",
- fc->misc.name);
- return 0;
-
-out:
- kfree(fc->misc.name);
- kfree(fc);
- return ret;
-}
-
-static int fc_remove(struct fmc_device *fmc)
-{
- struct fc_instance *fc;
-
- list_for_each_entry(fc, &fc_devices, list)
- if (fc->fmc == fmc)
- break;
- if (fc->fmc != fmc) {
- dev_err(&fmc->dev, "remove called but not found\n");
- return -ENODEV;
- }
-
- spin_lock(&fc_lock);
- list_del(&fc->list);
- spin_unlock(&fc_lock);
- misc_deregister(&fc->misc);
- kfree(fc->misc.name);
- kfree(fc);
-
- return 0;
-}
-
-
-static int fc_init(void)
-{
- int ret;
-
- ret = fmc_driver_register(&fc_drv);
- return ret;
-}
-
-static void fc_exit(void)
-{
- fmc_driver_unregister(&fc_drv);
-}
-
-module_init(fc_init);
-module_exit(fc_exit);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/fmc/fmc-core.c b/drivers/fmc/fmc-core.c
deleted file mode 100644
index 573f5471f680..000000000000
--- a/drivers/fmc/fmc-core.c
+++ /dev/null
@@ -1,388 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2012 CERN (www.cern.ch)
- * Author: Alessandro Rubini <rubini@gnudd.com>
- *
- * This work is part of the White Rabbit project, a research effort led
- * by CERN, the European Institute for Nuclear Research.
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/fmc.h>
-#include <linux/fmc-sdb.h>
-
-#include "fmc-private.h"
-
-static int fmc_check_version(unsigned long version, const char *name)
-{
- if (__FMC_MAJOR(version) != FMC_MAJOR) {
- pr_err("%s: \"%s\" has wrong major (has %li, expected %i)\n",
- __func__, name, __FMC_MAJOR(version), FMC_MAJOR);
- return -EINVAL;
- }
-
- if (__FMC_MINOR(version) != FMC_MINOR)
- pr_info("%s: \"%s\" has wrong minor (has %li, expected %i)\n",
- __func__, name, __FMC_MINOR(version), FMC_MINOR);
- return 0;
-}
-
-static int fmc_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
- /* struct fmc_device *fdev = to_fmc_device(dev); */
-
- /* FIXME: The MODALIAS */
- add_uevent_var(env, "MODALIAS=%s", "fmc");
- return 0;
-}
-
-static int fmc_probe(struct device *dev)
-{
- struct fmc_driver *fdrv = to_fmc_driver(dev->driver);
- struct fmc_device *fdev = to_fmc_device(dev);
-
- return fdrv->probe(fdev);
-}
-
-static int fmc_remove(struct device *dev)
-{
- struct fmc_driver *fdrv = to_fmc_driver(dev->driver);
- struct fmc_device *fdev = to_fmc_device(dev);
-
- return fdrv->remove(fdev);
-}
-
-static void fmc_shutdown(struct device *dev)
-{
- /* not implemented but mandatory */
-}
-
-static struct bus_type fmc_bus_type = {
- .name = "fmc",
- .match = fmc_match,
- .uevent = fmc_uevent,
- .probe = fmc_probe,
- .remove = fmc_remove,
- .shutdown = fmc_shutdown,
-};
-
-static void fmc_release(struct device *dev)
-{
- struct fmc_device *fmc = container_of(dev, struct fmc_device, dev);
-
- kfree(fmc);
-}
-
-/*
- * The eeprom is exported in sysfs, through a binary attribute
- */
-
-static ssize_t fmc_read_eeprom(struct file *file, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
-{
- struct device *dev;
- struct fmc_device *fmc;
- int eelen;
-
- dev = container_of(kobj, struct device, kobj);
- fmc = container_of(dev, struct fmc_device, dev);
- eelen = fmc->eeprom_len;
- if (off > eelen)
- return -ESPIPE;
- if (off == eelen)
- return 0; /* EOF */
- if (off + count > eelen)
- count = eelen - off;
- memcpy(buf, fmc->eeprom + off, count);
- return count;
-}
-
-static ssize_t fmc_write_eeprom(struct file *file, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
-{
- struct device *dev;
- struct fmc_device *fmc;
-
- dev = container_of(kobj, struct device, kobj);
- fmc = container_of(dev, struct fmc_device, dev);
- return fmc->op->write_ee(fmc, off, buf, count);
-}
-
-static struct bin_attribute fmc_eeprom_attr = {
- .attr = { .name = "eeprom", .mode = S_IRUGO | S_IWUSR, },
- .size = 8192, /* more or less standard */
- .read = fmc_read_eeprom,
- .write = fmc_write_eeprom,
-};
-
-int fmc_irq_request(struct fmc_device *fmc, irq_handler_t h,
- char *name, int flags)
-{
- if (fmc->op->irq_request)
- return fmc->op->irq_request(fmc, h, name, flags);
- return -EPERM;
-}
-EXPORT_SYMBOL(fmc_irq_request);
-
-void fmc_irq_free(struct fmc_device *fmc)
-{
- if (fmc->op->irq_free)
- fmc->op->irq_free(fmc);
-}
-EXPORT_SYMBOL(fmc_irq_free);
-
-void fmc_irq_ack(struct fmc_device *fmc)
-{
- if (likely(fmc->op->irq_ack))
- fmc->op->irq_ack(fmc);
-}
-EXPORT_SYMBOL(fmc_irq_ack);
-
-int fmc_validate(struct fmc_device *fmc, struct fmc_driver *drv)
-{
- if (fmc->op->validate)
- return fmc->op->validate(fmc, drv);
- return -EPERM;
-}
-EXPORT_SYMBOL(fmc_validate);
-
-int fmc_gpio_config(struct fmc_device *fmc, struct fmc_gpio *gpio, int ngpio)
-{
- if (fmc->op->gpio_config)
- return fmc->op->gpio_config(fmc, gpio, ngpio);
- return -EPERM;
-}
-EXPORT_SYMBOL(fmc_gpio_config);
-
-int fmc_read_ee(struct fmc_device *fmc, int pos, void *d, int l)
-{
- if (fmc->op->read_ee)
- return fmc->op->read_ee(fmc, pos, d, l);
- return -EPERM;
-}
-EXPORT_SYMBOL(fmc_read_ee);
-
-int fmc_write_ee(struct fmc_device *fmc, int pos, const void *d, int l)
-{
- if (fmc->op->write_ee)
- return fmc->op->write_ee(fmc, pos, d, l);
- return -EPERM;
-}
-EXPORT_SYMBOL(fmc_write_ee);
-
-/*
- * Functions for client modules follow
- */
-
-int fmc_driver_register(struct fmc_driver *drv)
-{
- if (fmc_check_version(drv->version, drv->driver.name))
- return -EINVAL;
- drv->driver.bus = &fmc_bus_type;
- return driver_register(&drv->driver);
-}
-EXPORT_SYMBOL(fmc_driver_register);
-
-void fmc_driver_unregister(struct fmc_driver *drv)
-{
- driver_unregister(&drv->driver);
-}
-EXPORT_SYMBOL(fmc_driver_unregister);
-
-/*
- * When a device set is registered, all eeproms must be read
- * and all FRUs must be parsed
- */
-int fmc_device_register_n_gw(struct fmc_device **devs, int n,
- struct fmc_gateware *gw)
-{
- struct fmc_device *fmc, **devarray;
- uint32_t device_id;
- int i, ret = 0;
-
- if (n < 1)
- return 0;
-
- /* Check the version of the first data structure (function prints) */
- if (fmc_check_version(devs[0]->version, devs[0]->carrier_name))
- return -EINVAL;
-
- devarray = kmemdup(devs, n * sizeof(*devs), GFP_KERNEL);
- if (!devarray)
- return -ENOMEM;
-
- /* Make all other checks before continuing, for all devices */
- for (i = 0; i < n; i++) {
- fmc = devarray[i];
- if (!fmc->hwdev) {
- pr_err("%s: device nr. %i has no hwdev pointer\n",
- __func__, i);
- ret = -EINVAL;
- break;
- }
- if (fmc->flags & FMC_DEVICE_NO_MEZZANINE) {
- dev_info(fmc->hwdev, "absent mezzanine in slot %d\n",
- fmc->slot_id);
- continue;
- }
- if (!fmc->eeprom) {
- dev_err(fmc->hwdev, "no eeprom provided for slot %i\n",
- fmc->slot_id);
- ret = -EINVAL;
- }
- if (!fmc->eeprom_addr) {
- dev_err(fmc->hwdev, "no eeprom_addr for slot %i\n",
- fmc->slot_id);
- ret = -EINVAL;
- }
- if (!fmc->carrier_name || !fmc->carrier_data ||
- !fmc->device_id) {
- dev_err(fmc->hwdev,
- "device nr %i: carrier name, "
- "data or dev_id not set\n", i);
- ret = -EINVAL;
- }
- if (ret)
- break;
-
- }
- if (ret) {
- kfree(devarray);
- return ret;
- }
-
- /* Validation is ok. Now init and register the devices */
- for (i = 0; i < n; i++) {
- fmc = devarray[i];
-
- fmc->nr_slots = n; /* each slot must know how many are there */
- fmc->devarray = devarray;
-
- device_initialize(&fmc->dev);
- fmc->dev.release = fmc_release;
- fmc->dev.parent = fmc->hwdev;
-
- /* Fill the identification stuff (may fail) */
- fmc_fill_id_info(fmc);
-
- fmc->dev.bus = &fmc_bus_type;
-
- /* Name from mezzanine info or carrier info. Or 0,1,2.. */
- device_id = fmc->device_id;
- if (!fmc->mezzanine_name)
- dev_set_name(&fmc->dev, "fmc-%04x", device_id);
- else
- dev_set_name(&fmc->dev, "%s-%04x", fmc->mezzanine_name,
- device_id);
-
- if (gw) {
- /*
- * The carrier already know the bitstream to load
- * for this set of FMC mezzanines.
- */
- ret = fmc->op->reprogram_raw(fmc, NULL,
- gw->bitstream, gw->len);
- if (ret) {
- dev_warn(fmc->hwdev,
- "Invalid gateware for FMC mezzanine\n");
- goto out;
- }
- }
-
- ret = device_add(&fmc->dev);
- if (ret < 0) {
- dev_err(fmc->hwdev, "Slot %i: Failed in registering "
- "\"%s\"\n", fmc->slot_id, fmc->dev.kobj.name);
- goto out;
- }
- ret = sysfs_create_bin_file(&fmc->dev.kobj, &fmc_eeprom_attr);
- if (ret < 0) {
- dev_err(&fmc->dev, "Failed in registering eeprom\n");
- goto out1;
- }
- /* This device went well, give information to the user */
- fmc_dump_eeprom(fmc);
- fmc_debug_init(fmc);
- }
- return 0;
-
-out1:
- device_del(&fmc->dev);
-out:
- kfree(devarray);
- for (i--; i >= 0; i--) {
- fmc_debug_exit(devs[i]);
- sysfs_remove_bin_file(&devs[i]->dev.kobj, &fmc_eeprom_attr);
- device_del(&devs[i]->dev);
- fmc_free_id_info(devs[i]);
- put_device(&devs[i]->dev);
- }
- return ret;
-
-}
-EXPORT_SYMBOL(fmc_device_register_n_gw);
-
-int fmc_device_register_n(struct fmc_device **devs, int n)
-{
- return fmc_device_register_n_gw(devs, n, NULL);
-}
-EXPORT_SYMBOL(fmc_device_register_n);
-
-int fmc_device_register_gw(struct fmc_device *fmc, struct fmc_gateware *gw)
-{
- return fmc_device_register_n_gw(&fmc, 1, gw);
-}
-EXPORT_SYMBOL(fmc_device_register_gw);
-
-int fmc_device_register(struct fmc_device *fmc)
-{
- return fmc_device_register_n(&fmc, 1);
-}
-EXPORT_SYMBOL(fmc_device_register);
-
-void fmc_device_unregister_n(struct fmc_device **devs, int n)
-{
- int i;
-
- if (n < 1)
- return;
-
- /* Free devarray first, not used by the later loop */
- kfree(devs[0]->devarray);
-
- for (i = 0; i < n; i++) {
- fmc_debug_exit(devs[i]);
- sysfs_remove_bin_file(&devs[i]->dev.kobj, &fmc_eeprom_attr);
- device_del(&devs[i]->dev);
- fmc_free_id_info(devs[i]);
- put_device(&devs[i]->dev);
- }
-}
-EXPORT_SYMBOL(fmc_device_unregister_n);
-
-void fmc_device_unregister(struct fmc_device *fmc)
-{
- fmc_device_unregister_n(&fmc, 1);
-}
-EXPORT_SYMBOL(fmc_device_unregister);
-
-/* Init and exit are trivial */
-static int fmc_init(void)
-{
- return bus_register(&fmc_bus_type);
-}
-
-static void fmc_exit(void)
-{
- bus_unregister(&fmc_bus_type);
-}
-
-module_init(fmc_init);
-module_exit(fmc_exit);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/fmc/fmc-debug.c b/drivers/fmc/fmc-debug.c
deleted file mode 100644
index 1734c7cf0e76..000000000000
--- a/drivers/fmc/fmc-debug.c
+++ /dev/null
@@ -1,172 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2015 CERN (www.cern.ch)
- * Author: Federico Vaga <federico.vaga@cern.ch>
- */
-
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <asm/byteorder.h>
-
-#include <linux/fmc.h>
-#include <linux/sdb.h>
-#include <linux/fmc-sdb.h>
-
-#define FMC_DBG_SDB_DUMP "dump_sdb"
-
-static char *__strip_trailing_space(char *buf, char *str, int len)
-{
- int i = len - 1;
-
- memcpy(buf, str, len);
- buf[len] = '\0';
- while (i >= 0 && buf[i] == ' ')
- buf[i--] = '\0';
- return buf;
-}
-
-#define __sdb_string(buf, field) ({ \
- BUILD_BUG_ON(sizeof(buf) < sizeof(field)); \
- __strip_trailing_space(buf, (void *)(field), sizeof(field)); \
- })
-
-/**
- * We do not check seq_printf() errors because we want to see things in any case
- */
-static void fmc_sdb_dump_recursive(struct fmc_device *fmc, struct seq_file *s,
- const struct sdb_array *arr)
-{
- unsigned long base = arr->baseaddr;
- int i, j, n = arr->len, level = arr->level;
- char tmp[64];
-
- for (i = 0; i < n; i++) {
- union sdb_record *r;
- struct sdb_product *p;
- struct sdb_component *c;
-
- r = &arr->record[i];
- c = &r->dev.sdb_component;
- p = &c->product;
-
- for (j = 0; j < level; j++)
- seq_printf(s, " ");
- switch (r->empty.record_type) {
- case sdb_type_interconnect:
- seq_printf(s, "%08llx:%08x %.19s\n",
- __be64_to_cpu(p->vendor_id),
- __be32_to_cpu(p->device_id),
- p->name);
- break;
- case sdb_type_device:
- seq_printf(s, "%08llx:%08x %.19s (%08llx-%08llx)\n",
- __be64_to_cpu(p->vendor_id),
- __be32_to_cpu(p->device_id),
- p->name,
- __be64_to_cpu(c->addr_first) + base,
- __be64_to_cpu(c->addr_last) + base);
- break;
- case sdb_type_bridge:
- seq_printf(s, "%08llx:%08x %.19s (bridge: %08llx)\n",
- __be64_to_cpu(p->vendor_id),
- __be32_to_cpu(p->device_id),
- p->name,
- __be64_to_cpu(c->addr_first) + base);
- if (IS_ERR(arr->subtree[i])) {
- seq_printf(s, "SDB: (bridge error %li)\n",
- PTR_ERR(arr->subtree[i]));
- break;
- }
- fmc_sdb_dump_recursive(fmc, s, arr->subtree[i]);
- break;
- case sdb_type_integration:
- seq_printf(s, "integration\n");
- break;
- case sdb_type_repo_url:
- seq_printf(s, "Synthesis repository: %s\n",
- __sdb_string(tmp, r->repo_url.repo_url));
- break;
- case sdb_type_synthesis:
- seq_printf(s, "Bitstream '%s' ",
- __sdb_string(tmp, r->synthesis.syn_name));
- seq_printf(s, "synthesized %08x by %s ",
- __be32_to_cpu(r->synthesis.date),
- __sdb_string(tmp, r->synthesis.user_name));
- seq_printf(s, "(%s version %x), ",
- __sdb_string(tmp, r->synthesis.tool_name),
- __be32_to_cpu(r->synthesis.tool_version));
- seq_printf(s, "commit %pm\n",
- r->synthesis.commit_id);
- break;
- case sdb_type_empty:
- seq_printf(s, "empty\n");
- break;
- default:
- seq_printf(s, "UNKNOWN TYPE 0x%02x\n",
- r->empty.record_type);
- break;
- }
- }
-}
-
-static int fmc_sdb_dump(struct seq_file *s, void *offset)
-{
- struct fmc_device *fmc = s->private;
-
- if (!fmc->sdb) {
- seq_printf(s, "no SDB information\n");
- return 0;
- }
-
- seq_printf(s, "FMC: %s (%s), slot %i, device %s\n", dev_name(fmc->hwdev),
- fmc->carrier_name, fmc->slot_id, dev_name(&fmc->dev));
- /* Dump SDB information */
- fmc_sdb_dump_recursive(fmc, s, fmc->sdb);
-
- return 0;
-}
-
-
-static int fmc_sdb_dump_open(struct inode *inode, struct file *file)
-{
- struct fmc_device *fmc = inode->i_private;
-
- return single_open(file, fmc_sdb_dump, fmc);
-}
-
-
-const struct file_operations fmc_dbgfs_sdb_dump = {
- .owner = THIS_MODULE,
- .open = fmc_sdb_dump_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-int fmc_debug_init(struct fmc_device *fmc)
-{
- fmc->dbg_dir = debugfs_create_dir(dev_name(&fmc->dev), NULL);
- if (IS_ERR_OR_NULL(fmc->dbg_dir)) {
- pr_err("FMC: Cannot create debugfs\n");
- return PTR_ERR(fmc->dbg_dir);
- }
-
- fmc->dbg_sdb_dump = debugfs_create_file(FMC_DBG_SDB_DUMP, 0444,
- fmc->dbg_dir, fmc,
- &fmc_dbgfs_sdb_dump);
- if (IS_ERR_OR_NULL(fmc->dbg_sdb_dump))
- pr_err("FMC: Cannot create debugfs file %s\n",
- FMC_DBG_SDB_DUMP);
-
- return 0;
-}
-
-void fmc_debug_exit(struct fmc_device *fmc)
-{
- if (fmc->dbg_dir)
- debugfs_remove_recursive(fmc->dbg_dir);
-}
diff --git a/drivers/fmc/fmc-dump.c b/drivers/fmc/fmc-dump.c
deleted file mode 100644
index 6c81dbde1d16..000000000000
--- a/drivers/fmc/fmc-dump.c
+++ /dev/null
@@ -1,58 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2013 CERN (www.cern.ch)
- * Author: Alessandro Rubini <rubini@gnudd.com>
- *
- * This work is part of the White Rabbit project, a research effort led
- * by CERN, the European Institute for Nuclear Research.
- */
-#include <linux/kernel.h>
-#include <linux/moduleparam.h>
-#include <linux/device.h>
-#include <linux/fmc.h>
-#include <linux/fmc-sdb.h>
-
-static int fmc_must_dump_eeprom;
-module_param_named(dump_eeprom, fmc_must_dump_eeprom, int, 0644);
-
-#define LINELEN 16
-
-/* Dumping 8k takes oh so much: avoid duplicate lines */
-static const uint8_t *dump_line(int addr, const uint8_t *line,
- const uint8_t *prev)
-{
- int i;
-
- if (!prev || memcmp(line, prev, LINELEN)) {
- pr_info("%04x: ", addr);
- for (i = 0; i < LINELEN; ) {
- printk(KERN_CONT "%02x", line[i]);
- i++;
- printk(i & 3 ? " " : i & (LINELEN - 1) ? " " : "\n");
- }
- return line;
- }
- /* repeated line */
- if (line == prev + LINELEN)
- pr_info("[...]\n");
- return prev;
-}
-
-void fmc_dump_eeprom(const struct fmc_device *fmc)
-{
- const uint8_t *line, *prev;
- int i;
-
- if (!fmc_must_dump_eeprom)
- return;
-
- pr_info("FMC: %s (%s), slot %i, device %s\n", dev_name(fmc->hwdev),
- fmc->carrier_name, fmc->slot_id, dev_name(&fmc->dev));
- pr_info("FMC: dumping eeprom 0x%x (%i) bytes\n", fmc->eeprom_len,
- fmc->eeprom_len);
-
- line = fmc->eeprom;
- prev = NULL;
- for (i = 0; i < fmc->eeprom_len; i += LINELEN, line += LINELEN)
- prev = dump_line(i, line, prev);
-}
diff --git a/drivers/fmc/fmc-fakedev.c b/drivers/fmc/fmc-fakedev.c
deleted file mode 100644
index 941d0930969a..000000000000
--- a/drivers/fmc/fmc-fakedev.c
+++ /dev/null
@@ -1,355 +0,0 @@
-/*
- * Copyright (C) 2012 CERN (www.cern.ch)
- * Author: Alessandro Rubini <rubini@gnudd.com>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * The software is provided "as is"; the copyright holders disclaim
- * all warranties and liabilities, to the extent permitted by
- * applicable law.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/device.h>
-#include <linux/slab.h>
-#include <linux/firmware.h>
-#include <linux/workqueue.h>
-#include <linux/err.h>
-#include <linux/fmc.h>
-
-#define FF_EEPROM_SIZE 8192 /* The standard eeprom size */
-#define FF_MAX_MEZZANINES 4 /* Fakes a multi-mezzanine carrier */
-
-/* The user can pass up to 4 names of eeprom images to load */
-static char *ff_eeprom[FF_MAX_MEZZANINES];
-static int ff_nr_eeprom;
-module_param_array_named(eeprom, ff_eeprom, charp, &ff_nr_eeprom, 0444);
-
-/* The user can ask for a multi-mezzanine carrier, with the default eeprom */
-static int ff_nr_dev = 1;
-module_param_named(ndev, ff_nr_dev, int, 0444);
-
-
-/* Lazily, don't support the "standard" module parameters */
-
-/*
- * Eeprom built from these commands:
-
- ../fru-generator -v fake-vendor -n fake-design-for-testing \
- -s 01234 -p none > IPMI-FRU
-
- gensdbfs . ../fake-eeprom.bin
-*/
-static char ff_eeimg[FF_MAX_MEZZANINES][FF_EEPROM_SIZE] = {
- {
- 0x01, 0x00, 0x00, 0x01, 0x00, 0x0c, 0x00, 0xf2, 0x01, 0x0b, 0x00, 0xb2,
- 0x86, 0x87, 0xcb, 0x66, 0x61, 0x6b, 0x65, 0x2d, 0x76, 0x65, 0x6e, 0x64,
- 0x6f, 0x72, 0xd7, 0x66, 0x61, 0x6b, 0x65, 0x2d, 0x64, 0x65, 0x73, 0x69,
- 0x67, 0x6e, 0x2d, 0x66, 0x6f, 0x72, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x69,
- 0x6e, 0x67, 0xc5, 0x30, 0x31, 0x32, 0x33, 0x34, 0xc4, 0x6e, 0x6f, 0x6e,
- 0x65, 0xda, 0x32, 0x30, 0x31, 0x32, 0x2d, 0x31, 0x31, 0x2d, 0x31, 0x39,
- 0x20, 0x32, 0x32, 0x3a, 0x34, 0x32, 0x3a, 0x33, 0x30, 0x2e, 0x30, 0x37,
- 0x34, 0x30, 0x35, 0x35, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87,
- 0x02, 0x02, 0x0d, 0xf7, 0xf8, 0x02, 0xb0, 0x04, 0x74, 0x04, 0xec, 0x04,
- 0x00, 0x00, 0x00, 0x00, 0xe8, 0x03, 0x02, 0x02, 0x0d, 0x5c, 0x93, 0x01,
- 0x4a, 0x01, 0x39, 0x01, 0x5a, 0x01, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x0b,
- 0x02, 0x02, 0x0d, 0x63, 0x8c, 0x00, 0xfa, 0x00, 0xed, 0x00, 0x06, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0f, 0x01, 0x02, 0x0d, 0xfb, 0xf5, 0x05,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x01, 0x02, 0x0d, 0xfc, 0xf4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x0d, 0xfd, 0xf3, 0x03,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xfa, 0x82, 0x0b, 0xea, 0x8f, 0xa2, 0x12, 0x00, 0x00, 0x1e, 0x44, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x53, 0x44, 0x42, 0x2d, 0x00, 0x03, 0x01, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x01, 0xc4, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x61, 0x74, 0x61,
- 0x2e, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
- 0x2e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc4, 0x46, 0x69, 0x6c, 0x65,
- 0x44, 0x61, 0x74, 0x61, 0x6e, 0x61, 0x6d, 0x65, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf,
- 0x46, 0x69, 0x6c, 0x65, 0x44, 0x61, 0x74, 0x61, 0x49, 0x50, 0x4d, 0x49,
- 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x49, 0x50, 0x4d, 0x49,
- 0x2d, 0x46, 0x52, 0x55, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x01, 0x66, 0x61, 0x6b, 0x65, 0x0a,
- },
-};
-
-struct ff_dev {
- struct fmc_device *fmc[FF_MAX_MEZZANINES];
- struct device dev;
-};
-
-static struct ff_dev *ff_current_dev; /* We have 1 carrier, 1 slot */
-
-static int ff_reprogram(struct fmc_device *fmc, struct fmc_driver *drv,
- char *gw)
-{
- const struct firmware *fw;
- int ret;
-
- if (!gw) {
- /* program golden: success */
- fmc->flags &= ~FMC_DEVICE_HAS_CUSTOM;
- fmc->flags |= FMC_DEVICE_HAS_GOLDEN;
- return 0;
- }
-
- dev_info(&fmc->dev, "reprogramming with %s\n", gw);
- ret = request_firmware(&fw, gw, &fmc->dev);
- if (ret < 0) {
- dev_warn(&fmc->dev, "request firmware \"%s\": error %i\n",
- gw, ret);
- goto out;
- }
- fmc->flags &= ~FMC_DEVICE_HAS_GOLDEN;
- fmc->flags |= FMC_DEVICE_HAS_CUSTOM;
-
-out:
- release_firmware(fw);
- return ret;
-}
-
-static int ff_irq_request(struct fmc_device *fmc, irq_handler_t handler,
- char *name, int flags)
-{
- return -EOPNOTSUPP;
-}
-
-/* FIXME: should also have some fake FMC GPIO mapping */
-
-
-/*
- * This work function is called when we changed the eeprom. It removes the
- * current fmc device and registers a new one, with different identifiers.
- */
-static struct ff_dev *ff_dev_create(void); /* defined later */
-
-static void ff_work_fn(struct work_struct *work)
-{
- struct ff_dev *ff = ff_current_dev;
- int ret;
-
- fmc_device_unregister_n(ff->fmc, ff_nr_dev);
- device_unregister(&ff->dev);
- ff_current_dev = NULL;
-
- ff = ff_dev_create();
- if (IS_ERR(ff)) {
- pr_warning("%s: can't re-create FMC devices\n", __func__);
- return;
- }
- ret = fmc_device_register_n(ff->fmc, ff_nr_dev);
- if (ret < 0) {
- dev_warn(&ff->dev, "can't re-register FMC devices\n");
- device_unregister(&ff->dev);
- return;
- }
-
- ff_current_dev = ff;
-}
-
-static DECLARE_DELAYED_WORK(ff_work, ff_work_fn);
-
-
-/* low-level i2c */
-static int ff_eeprom_read(struct fmc_device *fmc, uint32_t offset,
- void *buf, size_t size)
-{
- if (offset > FF_EEPROM_SIZE)
- return -EINVAL;
- if (offset + size > FF_EEPROM_SIZE)
- size = FF_EEPROM_SIZE - offset;
- memcpy(buf, fmc->eeprom + offset, size);
- return size;
-}
-
-static int ff_eeprom_write(struct fmc_device *fmc, uint32_t offset,
- const void *buf, size_t size)
-{
- if (offset > FF_EEPROM_SIZE)
- return -EINVAL;
- if (offset + size > FF_EEPROM_SIZE)
- size = FF_EEPROM_SIZE - offset;
- dev_info(&fmc->dev, "write_eeprom: offset %i, size %zi\n",
- (int)offset, size);
- memcpy(fmc->eeprom + offset, buf, size);
- schedule_delayed_work(&ff_work, HZ * 2); /* remove, replug, in 2s */
- return size;
-}
-
-/* i2c operations for fmc */
-static int ff_read_ee(struct fmc_device *fmc, int pos, void *data, int len)
-{
- if (!(fmc->flags & FMC_DEVICE_HAS_GOLDEN))
- return -EOPNOTSUPP;
- return ff_eeprom_read(fmc, pos, data, len);
-}
-
-static int ff_write_ee(struct fmc_device *fmc, int pos,
- const void *data, int len)
-{
- if (!(fmc->flags & FMC_DEVICE_HAS_GOLDEN))
- return -EOPNOTSUPP;
- return ff_eeprom_write(fmc, pos, data, len);
-}
-
-/* readl and writel do not do anything. Don't waste RAM with "base" */
-static uint32_t ff_readl(struct fmc_device *fmc, int offset)
-{
- return 0;
-}
-
-static void ff_writel(struct fmc_device *fmc, uint32_t value, int offset)
-{
- return;
-}
-
-/* validate is useful so fmc-write-eeprom will not reprogram every 2 seconds */
-static int ff_validate(struct fmc_device *fmc, struct fmc_driver *drv)
-{
- int i;
-
- if (!drv->busid_n)
- return 0; /* everyhing is valid */
- for (i = 0; i < drv->busid_n; i++)
- if (drv->busid_val[i] == fmc->device_id)
- return i;
- return -ENOENT;
-}
-
-
-
-static struct fmc_operations ff_fmc_operations = {
- .read32 = ff_readl,
- .write32 = ff_writel,
- .reprogram = ff_reprogram,
- .irq_request = ff_irq_request,
- .read_ee = ff_read_ee,
- .write_ee = ff_write_ee,
- .validate = ff_validate,
-};
-
-/* This device is kmalloced: release it */
-static void ff_dev_release(struct device *dev)
-{
- struct ff_dev *ff = container_of(dev, struct ff_dev, dev);
- kfree(ff);
-}
-
-static struct fmc_device ff_template_fmc = {
- .version = FMC_VERSION,
- .owner = THIS_MODULE,
- .carrier_name = "fake-fmc-carrier",
- .device_id = 0xf001, /* fool */
- .eeprom_len = sizeof(ff_eeimg[0]),
- .memlen = 0x1000, /* 4k, to show something */
- .op = &ff_fmc_operations,
- .hwdev = NULL, /* filled at creation time */
- .flags = FMC_DEVICE_HAS_GOLDEN,
-};
-
-static struct ff_dev *ff_dev_create(void)
-{
- struct ff_dev *ff;
- struct fmc_device *fmc;
- int i, ret;
-
- ff = kzalloc(sizeof(*ff), GFP_KERNEL);
- if (!ff)
- return ERR_PTR(-ENOMEM);
- dev_set_name(&ff->dev, "fake-fmc-carrier");
- ff->dev.release = ff_dev_release;
-
- ret = device_register(&ff->dev);
- if (ret < 0) {
- put_device(&ff->dev);
- return ERR_PTR(ret);
- }
-
- /* Create fmc structures that refer to this new "hw" device */
- for (i = 0; i < ff_nr_dev; i++) {
- fmc = kmemdup(&ff_template_fmc, sizeof(ff_template_fmc),
- GFP_KERNEL);
- fmc->hwdev = &ff->dev;
- fmc->carrier_data = ff;
- fmc->nr_slots = ff_nr_dev;
- /* the following fields are different for each slot */
- fmc->eeprom = ff_eeimg[i];
- fmc->eeprom_addr = 0x50 + 2 * i;
- fmc->slot_id = i;
- ff->fmc[i] = fmc;
- /* increment the identifier, each must be different */
- ff_template_fmc.device_id++;
- }
- return ff;
-}
-
-/* init and exit */
-static int ff_init(void)
-{
- struct ff_dev *ff;
- const struct firmware *fw;
- int i, len, ret = 0;
-
- /* Replicate the default eeprom for the max number of mezzanines */
- for (i = 1; i < FF_MAX_MEZZANINES; i++)
- memcpy(ff_eeimg[i], ff_eeimg[0], sizeof(ff_eeimg[0]));
-
- if (ff_nr_eeprom > ff_nr_dev)
- ff_nr_dev = ff_nr_eeprom;
-
- ff = ff_dev_create();
- if (IS_ERR(ff))
- return PTR_ERR(ff);
-
- /* If the user passed "eeprom=" as a parameter, fetch them */
- for (i = 0; i < ff_nr_eeprom; i++) {
- if (!strlen(ff_eeprom[i]))
- continue;
- ret = request_firmware(&fw, ff_eeprom[i], &ff->dev);
- if (ret < 0) {
- dev_err(&ff->dev, "Mezzanine %i: can't load \"%s\" "
- "(error %i)\n", i, ff_eeprom[i], -ret);
- } else {
- len = min_t(size_t, fw->size, (size_t)FF_EEPROM_SIZE);
- memcpy(ff_eeimg[i], fw->data, len);
- release_firmware(fw);
- dev_info(&ff->dev, "Mezzanine %i: eeprom \"%s\"\n", i,
- ff_eeprom[i]);
- }
- }
-
- ret = fmc_device_register_n(ff->fmc, ff_nr_dev);
- if (ret) {
- device_unregister(&ff->dev);
- return ret;
- }
- ff_current_dev = ff;
- return ret;
-}
-
-static void ff_exit(void)
-{
- if (ff_current_dev) {
- fmc_device_unregister_n(ff_current_dev->fmc, ff_nr_dev);
- device_unregister(&ff_current_dev->dev);
- }
- cancel_delayed_work_sync(&ff_work);
-}
-
-module_init(ff_init);
-module_exit(ff_exit);
-
-MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/fmc/fmc-match.c b/drivers/fmc/fmc-match.c
deleted file mode 100644
index 995bd6041a67..000000000000
--- a/drivers/fmc/fmc-match.c
+++ /dev/null
@@ -1,113 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2012 CERN (www.cern.ch)
- * Author: Alessandro Rubini <rubini@gnudd.com>
- *
- * This work is part of the White Rabbit project, a research effort led
- * by CERN, the European Institute for Nuclear Research.
- */
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/fmc.h>
-#include <linux/ipmi-fru.h>
-
-/* The fru parser is both user and kernel capable: it needs alloc */
-void *fru_alloc(size_t size)
-{
- return kzalloc(size, GFP_KERNEL);
-}
-
-/* The actual match function */
-int fmc_match(struct device *dev, struct device_driver *drv)
-{
- struct fmc_driver *fdrv = to_fmc_driver(drv);
- struct fmc_device *fdev = to_fmc_device(dev);
- struct fmc_fru_id *fid;
- int i, matched = 0;
-
- /* This currently only matches the EEPROM (FRU id) */
- fid = fdrv->id_table.fru_id;
- if (!fid) {
- dev_warn(&fdev->dev, "Driver has no ID: matches all\n");
- matched = 1;
- } else {
- if (!fdev->id.manufacturer || !fdev->id.product_name)
- return 0; /* the device has no FRU information */
- for (i = 0; i < fdrv->id_table.fru_id_nr; i++, fid++) {
- if (fid->manufacturer &&
- strcmp(fid->manufacturer, fdev->id.manufacturer))
- continue;
- if (fid->product_name &&
- strcmp(fid->product_name, fdev->id.product_name))
- continue;
- matched = 1;
- break;
- }
- }
-
- /* FIXME: match SDB contents */
- return matched;
-}
-
-/* This function creates ID info for a newly registered device */
-int fmc_fill_id_info(struct fmc_device *fmc)
-{
- struct fru_common_header *h;
- struct fru_board_info_area *bia;
- int ret, allocated = 0;
-
- /* If we know the eeprom length, try to read it off the device */
- if (fmc->eeprom_len && !fmc->eeprom) {
- fmc->eeprom = kzalloc(fmc->eeprom_len, GFP_KERNEL);
- if (!fmc->eeprom)
- return -ENOMEM;
- allocated = 1;
- ret = fmc_read_ee(fmc, 0, fmc->eeprom, fmc->eeprom_len);
- if (ret < 0)
- goto out;
- }
-
- /* If no eeprom, continue with other matches */
- if (!fmc->eeprom)
- return 0;
-
- dev_info(fmc->hwdev, "mezzanine %i\n", fmc->slot_id); /* header */
-
- /* So we have the eeprom: parse the FRU part (if any) */
- h = (void *)fmc->eeprom;
- if (h->format != 1) {
- pr_info(" EEPROM has no FRU information\n");
- goto out;
- }
- if (!fru_header_cksum_ok(h)) {
- pr_info(" FRU: wrong header checksum\n");
- goto out;
- }
- bia = fru_get_board_area(h);
- if (!fru_bia_cksum_ok(bia)) {
- pr_info(" FRU: wrong board area checksum\n");
- goto out;
- }
- fmc->id.manufacturer = fru_get_board_manufacturer(h);
- fmc->id.product_name = fru_get_product_name(h);
- pr_info(" Manufacturer: %s\n", fmc->id.manufacturer);
- pr_info(" Product name: %s\n", fmc->id.product_name);
-
- /* Create the short name (FIXME: look in sdb as well) */
- fmc->mezzanine_name = kstrdup(fmc->id.product_name, GFP_KERNEL);
-
-out:
- if (allocated) {
- kfree(fmc->eeprom);
- fmc->eeprom = NULL;
- }
- return 0; /* no error: let other identification work */
-}
-
-/* Some ID data is allocated using fru_alloc() above, so release it */
-void fmc_free_id_info(struct fmc_device *fmc)
-{
- kfree(fmc->mezzanine_name);
- kfree(fmc->id.manufacturer);
- kfree(fmc->id.product_name);
-}
diff --git a/drivers/fmc/fmc-private.h b/drivers/fmc/fmc-private.h
deleted file mode 100644
index 93cb8030f764..000000000000
--- a/drivers/fmc/fmc-private.h
+++ /dev/null
@@ -1,8 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Copyright (C) 2015 CERN (www.cern.ch)
- * Author: Federico Vaga <federico.vaga@cern.ch>
- */
-
-extern int fmc_debug_init(struct fmc_device *fmc);
-extern void fmc_debug_exit(struct fmc_device *fmc);
diff --git a/drivers/fmc/fmc-sdb.c b/drivers/fmc/fmc-sdb.c
deleted file mode 100644
index 14758db1a5fb..000000000000
--- a/drivers/fmc/fmc-sdb.c
+++ /dev/null
@@ -1,219 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2012 CERN (www.cern.ch)
- * Author: Alessandro Rubini <rubini@gnudd.com>
- *
- * This work is part of the White Rabbit project, a research effort led
- * by CERN, the European Institute for Nuclear Research.
- */
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/fmc.h>
-#include <linux/sdb.h>
-#include <linux/err.h>
-#include <linux/fmc-sdb.h>
-#include <asm/byteorder.h>
-
-static uint32_t __sdb_rd(struct fmc_device *fmc, unsigned long address,
- int convert)
-{
- uint32_t res = fmc_readl(fmc, address);
- if (convert)
- return __be32_to_cpu(res);
- return res;
-}
-
-static struct sdb_array *__fmc_scan_sdb_tree(struct fmc_device *fmc,
- unsigned long sdb_addr,
- unsigned long reg_base, int level)
-{
- uint32_t onew;
- int i, j, n, convert = 0;
- struct sdb_array *arr, *sub;
-
- onew = fmc_readl(fmc, sdb_addr);
- if (onew == SDB_MAGIC) {
- /* Uh! If we are little-endian, we must convert */
- if (SDB_MAGIC != __be32_to_cpu(SDB_MAGIC))
- convert = 1;
- } else if (onew == __be32_to_cpu(SDB_MAGIC)) {
- /* ok, don't convert */
- } else {
- return ERR_PTR(-ENOENT);
- }
- /* So, the magic was there: get the count from offset 4*/
- onew = __sdb_rd(fmc, sdb_addr + 4, convert);
- n = __be16_to_cpu(*(uint16_t *)&onew);
- arr = kzalloc(sizeof(*arr), GFP_KERNEL);
- if (!arr)
- return ERR_PTR(-ENOMEM);
- arr->record = kcalloc(n, sizeof(arr->record[0]), GFP_KERNEL);
- arr->subtree = kcalloc(n, sizeof(arr->subtree[0]), GFP_KERNEL);
- if (!arr->record || !arr->subtree) {
- kfree(arr->record);
- kfree(arr->subtree);
- kfree(arr);
- return ERR_PTR(-ENOMEM);
- }
-
- arr->len = n;
- arr->level = level;
- arr->fmc = fmc;
- for (i = 0; i < n; i++) {
- union sdb_record *r;
-
- for (j = 0; j < sizeof(arr->record[0]); j += 4) {
- *(uint32_t *)((void *)(arr->record + i) + j) =
- __sdb_rd(fmc, sdb_addr + (i * 64) + j, convert);
- }
- r = &arr->record[i];
- arr->subtree[i] = ERR_PTR(-ENODEV);
- if (r->empty.record_type == sdb_type_bridge) {
- struct sdb_component *c = &r->bridge.sdb_component;
- uint64_t subaddr = __be64_to_cpu(r->bridge.sdb_child);
- uint64_t newbase = __be64_to_cpu(c->addr_first);
-
- subaddr += reg_base;
- newbase += reg_base;
- sub = __fmc_scan_sdb_tree(fmc, subaddr, newbase,
- level + 1);
- arr->subtree[i] = sub; /* may be error */
- if (IS_ERR(sub))
- continue;
- sub->parent = arr;
- sub->baseaddr = newbase;
- }
- }
- return arr;
-}
-
-int fmc_scan_sdb_tree(struct fmc_device *fmc, unsigned long address)
-{
- struct sdb_array *ret;
- if (fmc->sdb)
- return -EBUSY;
- ret = __fmc_scan_sdb_tree(fmc, address, 0 /* regs */, 0);
- if (IS_ERR(ret))
- return PTR_ERR(ret);
- fmc->sdb = ret;
- return 0;
-}
-EXPORT_SYMBOL(fmc_scan_sdb_tree);
-
-static void __fmc_sdb_free(struct sdb_array *arr)
-{
- int i, n;
-
- if (!arr)
- return;
- n = arr->len;
- for (i = 0; i < n; i++) {
- if (IS_ERR(arr->subtree[i]))
- continue;
- __fmc_sdb_free(arr->subtree[i]);
- }
- kfree(arr->record);
- kfree(arr->subtree);
- kfree(arr);
-}
-
-int fmc_free_sdb_tree(struct fmc_device *fmc)
-{
- __fmc_sdb_free(fmc->sdb);
- fmc->sdb = NULL;
- return 0;
-}
-EXPORT_SYMBOL(fmc_free_sdb_tree);
-
-/* This helper calls reprogram and inizialized sdb as well */
-int fmc_reprogram_raw(struct fmc_device *fmc, struct fmc_driver *d,
- void *gw, unsigned long len, int sdb_entry)
-{
- int ret;
-
- ret = fmc->op->reprogram_raw(fmc, d, gw, len);
- if (ret < 0)
- return ret;
- if (sdb_entry < 0)
- return ret;
-
- /* We are required to find SDB at a given offset */
- ret = fmc_scan_sdb_tree(fmc, sdb_entry);
- if (ret < 0) {
- dev_err(&fmc->dev, "Can't find SDB at address 0x%x\n",
- sdb_entry);
- return -ENODEV;
- }
-
- return 0;
-}
-EXPORT_SYMBOL(fmc_reprogram_raw);
-
-/* This helper calls reprogram and inizialized sdb as well */
-int fmc_reprogram(struct fmc_device *fmc, struct fmc_driver *d, char *gw,
- int sdb_entry)
-{
- int ret;
-
- ret = fmc->op->reprogram(fmc, d, gw);
- if (ret < 0)
- return ret;
- if (sdb_entry < 0)
- return ret;
-
- /* We are required to find SDB at a given offset */
- ret = fmc_scan_sdb_tree(fmc, sdb_entry);
- if (ret < 0) {
- dev_err(&fmc->dev, "Can't find SDB at address 0x%x\n",
- sdb_entry);
- return -ENODEV;
- }
-
- return 0;
-}
-EXPORT_SYMBOL(fmc_reprogram);
-
-void fmc_show_sdb_tree(const struct fmc_device *fmc)
-{
- pr_err("%s: not supported anymore, use debugfs to dump SDB\n",
- __func__);
-}
-EXPORT_SYMBOL(fmc_show_sdb_tree);
-
-signed long fmc_find_sdb_device(struct sdb_array *tree,
- uint64_t vid, uint32_t did, unsigned long *sz)
-{
- signed long res = -ENODEV;
- union sdb_record *r;
- struct sdb_product *p;
- struct sdb_component *c;
- int i, n = tree->len;
- uint64_t last, first;
-
- /* FIXME: what if the first interconnect is not at zero? */
- for (i = 0; i < n; i++) {
- r = &tree->record[i];
- c = &r->dev.sdb_component;
- p = &c->product;
-
- if (!IS_ERR(tree->subtree[i]))
- res = fmc_find_sdb_device(tree->subtree[i],
- vid, did, sz);
- if (res >= 0)
- return res + tree->baseaddr;
- if (r->empty.record_type != sdb_type_device)
- continue;
- if (__be64_to_cpu(p->vendor_id) != vid)
- continue;
- if (__be32_to_cpu(p->device_id) != did)
- continue;
- /* found */
- last = __be64_to_cpu(c->addr_last);
- first = __be64_to_cpu(c->addr_first);
- if (sz)
- *sz = (typeof(*sz))(last + 1 - first);
- return first + tree->baseaddr;
- }
- return res;
-}
-EXPORT_SYMBOL(fmc_find_sdb_device);
diff --git a/drivers/fmc/fmc-trivial.c b/drivers/fmc/fmc-trivial.c
deleted file mode 100644
index 8defdee3e3a3..000000000000
--- a/drivers/fmc/fmc-trivial.c
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2012 CERN (www.cern.ch)
- * Author: Alessandro Rubini <rubini@gnudd.com>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * The software is provided "as is"; the copyright holders disclaim
- * all warranties and liabilities, to the extent permitted by
- * applicable law.
- */
-
-/* A trivial fmc driver that can load a gateware file and reports interrupts */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/gpio.h>
-#include <linux/fmc.h>
-
-static struct fmc_driver t_drv; /* initialized later */
-
-static irqreturn_t t_handler(int irq, void *dev_id)
-{
- struct fmc_device *fmc = dev_id;
-
- fmc_irq_ack(fmc);
- dev_info(&fmc->dev, "received irq %i\n", irq);
- return IRQ_HANDLED;
-}
-
-static struct fmc_gpio t_gpio[] = {
- {
- .gpio = FMC_GPIO_IRQ(0),
- .mode = GPIOF_DIR_IN,
- .irqmode = IRQF_TRIGGER_RISING,
- }, {
- .gpio = FMC_GPIO_IRQ(1),
- .mode = GPIOF_DIR_IN,
- .irqmode = IRQF_TRIGGER_RISING,
- }
-};
-
-static int t_probe(struct fmc_device *fmc)
-{
- int ret;
- int index = 0;
-
- index = fmc_validate(fmc, &t_drv);
- if (index < 0)
- return -EINVAL; /* not our device: invalid */
-
- ret = fmc_irq_request(fmc, t_handler, "fmc-trivial", IRQF_SHARED);
- if (ret < 0)
- return ret;
- /* ignore error code of call below, we really don't care */
- fmc_gpio_config(fmc, t_gpio, ARRAY_SIZE(t_gpio));
-
- ret = fmc_reprogram(fmc, &t_drv, "", 0);
- if (ret == -EPERM) /* programming not supported */
- ret = 0;
- if (ret < 0)
- fmc_irq_free(fmc);
-
- /* FIXME: reprogram LM32 too */
- return ret;
-}
-
-static int t_remove(struct fmc_device *fmc)
-{
- fmc_irq_free(fmc);
- return 0;
-}
-
-static struct fmc_driver t_drv = {
- .version = FMC_VERSION,
- .driver.name = KBUILD_MODNAME,
- .probe = t_probe,
- .remove = t_remove,
- /* no table, as the current match just matches everything */
-};
-
- /* We accept the generic parameters */
-FMC_PARAM_BUSID(t_drv);
-FMC_PARAM_GATEWARE(t_drv);
-
-static int t_init(void)
-{
- int ret;
-
- ret = fmc_driver_register(&t_drv);
- return ret;
-}
-
-static void t_exit(void)
-{
- fmc_driver_unregister(&t_drv);
-}
-
-module_init(t_init);
-module_exit(t_exit);
-
-MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/fmc/fmc-write-eeprom.c b/drivers/fmc/fmc-write-eeprom.c
deleted file mode 100644
index 1c7826e3f526..000000000000
--- a/drivers/fmc/fmc-write-eeprom.c
+++ /dev/null
@@ -1,175 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2012 CERN (www.cern.ch)
- * Author: Alessandro Rubini <rubini@gnudd.com>
- *
- * This work is part of the White Rabbit project, a research effort led
- * by CERN, the European Institute for Nuclear Research.
- */
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/firmware.h>
-#include <linux/init.h>
-#include <linux/fmc.h>
-#include <asm/unaligned.h>
-
-/*
- * This module uses the firmware loader to program the whole or part
- * of the FMC eeprom. The meat is in the _run functions. However, no
- * default file name is provided, to avoid accidental mishaps. Also,
- * you must pass the busid argument
- */
-static struct fmc_driver fwe_drv;
-
-FMC_PARAM_BUSID(fwe_drv);
-
-/* The "file=" is like the generic "gateware=" used elsewhere */
-static char *fwe_file[FMC_MAX_CARDS];
-static int fwe_file_n;
-module_param_array_named(file, fwe_file, charp, &fwe_file_n, 0444);
-
-static int fwe_run_tlv(struct fmc_device *fmc, const struct firmware *fw,
- int write)
-{
- const uint8_t *p = fw->data;
- int len = fw->size;
- uint16_t thislen, thisaddr;
- int err;
-
- /* format is: 'w' addr16 len16 data... */
- while (len > 5) {
- thisaddr = get_unaligned_le16(p+1);
- thislen = get_unaligned_le16(p+3);
- if (p[0] != 'w' || thislen + 5 > len) {
- dev_err(&fmc->dev, "invalid tlv at offset %ti\n",
- p - fw->data);
- return -EINVAL;
- }
- err = 0;
- if (write) {
- dev_info(&fmc->dev, "write %i bytes at 0x%04x\n",
- thislen, thisaddr);
- err = fmc_write_ee(fmc, thisaddr, p + 5, thislen);
- }
- if (err < 0) {
- dev_err(&fmc->dev, "write failure @0x%04x\n",
- thisaddr);
- return err;
- }
- p += 5 + thislen;
- len -= 5 + thislen;
- }
- if (write)
- dev_info(&fmc->dev, "write_eeprom: success\n");
- return 0;
-}
-
-static int fwe_run_bin(struct fmc_device *fmc, const struct firmware *fw)
-{
- int ret;
-
- dev_info(&fmc->dev, "programming %zi bytes\n", fw->size);
- ret = fmc_write_ee(fmc, 0, (void *)fw->data, fw->size);
- if (ret < 0) {
- dev_info(&fmc->dev, "write_eeprom: error %i\n", ret);
- return ret;
- }
- dev_info(&fmc->dev, "write_eeprom: success\n");
- return 0;
-}
-
-static int fwe_run(struct fmc_device *fmc, const struct firmware *fw, char *s)
-{
- char *last4 = s + strlen(s) - 4;
- int err;
-
- if (!strcmp(last4, ".bin"))
- return fwe_run_bin(fmc, fw);
- if (!strcmp(last4, ".tlv")) {
- err = fwe_run_tlv(fmc, fw, 0);
- if (!err)
- err = fwe_run_tlv(fmc, fw, 1);
- return err;
- }
- dev_err(&fmc->dev, "invalid file name \"%s\"\n", s);
- return -EINVAL;
-}
-
-/*
- * Programming is done at probe time. Morever, only those listed with
- * busid= are programmed.
- * card is probed for, only one is programmed. Unfortunately, it's
- * difficult to know in advance when probing the first card if others
- * are there.
- */
-static int fwe_probe(struct fmc_device *fmc)
-{
- int err, index = 0;
- const struct firmware *fw;
- struct device *dev = &fmc->dev;
- char *s;
-
- if (!fwe_drv.busid_n) {
- dev_err(dev, "%s: no busid passed, refusing all cards\n",
- KBUILD_MODNAME);
- return -ENODEV;
- }
-
- index = fmc_validate(fmc, &fwe_drv);
- if (index < 0) {
- pr_err("%s: refusing device \"%s\"\n", KBUILD_MODNAME,
- dev_name(dev));
- return -ENODEV;
- }
- if (index >= fwe_file_n) {
- pr_err("%s: no filename for device index %i\n",
- KBUILD_MODNAME, index);
- return -ENODEV;
- }
- s = fwe_file[index];
- if (!s) {
- pr_err("%s: no filename for \"%s\" not programming\n",
- KBUILD_MODNAME, dev_name(dev));
- return -ENOENT;
- }
- err = request_firmware(&fw, s, dev);
- if (err < 0) {
- dev_err(&fmc->dev, "request firmware \"%s\": error %i\n",
- s, err);
- return err;
- }
- fwe_run(fmc, fw, s);
- release_firmware(fw);
- return 0;
-}
-
-static int fwe_remove(struct fmc_device *fmc)
-{
- return 0;
-}
-
-static struct fmc_driver fwe_drv = {
- .version = FMC_VERSION,
- .driver.name = KBUILD_MODNAME,
- .probe = fwe_probe,
- .remove = fwe_remove,
- /* no table, as the current match just matches everything */
-};
-
-static int fwe_init(void)
-{
- int ret;
-
- ret = fmc_driver_register(&fwe_drv);
- return ret;
-}
-
-static void fwe_exit(void)
-{
- fmc_driver_unregister(&fwe_drv);
-}
-
-module_init(fwe_init);
-module_exit(fwe_exit);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/fmc/fru-parse.c b/drivers/fmc/fru-parse.c
deleted file mode 100644
index f551b81f4fd9..000000000000
--- a/drivers/fmc/fru-parse.c
+++ /dev/null
@@ -1,80 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2012 CERN (www.cern.ch)
- * Author: Alessandro Rubini <rubini@gnudd.com>
- *
- * This work is part of the White Rabbit project, a research effort led
- * by CERN, the European Institute for Nuclear Research.
- */
-#include <linux/ipmi-fru.h>
-
-/* Some internal helpers */
-static struct fru_type_length *
-__fru_get_board_tl(struct fru_common_header *header, int nr)
-{
- struct fru_board_info_area *bia;
- struct fru_type_length *tl;
-
- bia = fru_get_board_area(header);
- tl = bia->tl;
- while (nr > 0 && !fru_is_eof(tl)) {
- tl = fru_next_tl(tl);
- nr--;
- }
- if (fru_is_eof(tl))
- return NULL;
- return tl;
-}
-
-static char *__fru_alloc_get_tl(struct fru_common_header *header, int nr)
-{
- struct fru_type_length *tl;
- char *res;
-
- tl = __fru_get_board_tl(header, nr);
- if (!tl)
- return NULL;
-
- res = fru_alloc(fru_strlen(tl) + 1);
- if (!res)
- return NULL;
- return fru_strcpy(res, tl);
-}
-
-/* Public checksum verifiers */
-int fru_header_cksum_ok(struct fru_common_header *header)
-{
- uint8_t *ptr = (void *)header;
- int i, sum;
-
- for (i = sum = 0; i < sizeof(*header); i++)
- sum += ptr[i];
- return (sum & 0xff) == 0;
-}
-int fru_bia_cksum_ok(struct fru_board_info_area *bia)
-{
- uint8_t *ptr = (void *)bia;
- int i, sum;
-
- for (i = sum = 0; i < 8 * bia->area_len; i++)
- sum += ptr[i];
- return (sum & 0xff) == 0;
-}
-
-/* Get various stuff, trivial */
-char *fru_get_board_manufacturer(struct fru_common_header *header)
-{
- return __fru_alloc_get_tl(header, 0);
-}
-char *fru_get_product_name(struct fru_common_header *header)
-{
- return __fru_alloc_get_tl(header, 1);
-}
-char *fru_get_serial_number(struct fru_common_header *header)
-{
- return __fru_alloc_get_tl(header, 2);
-}
-char *fru_get_part_number(struct fru_common_header *header)
-{
- return __fru_alloc_get_tl(header, 3);
-}
diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index 8072c195d831..474f304ec109 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -26,9 +26,9 @@ config FPGA_MGR_SOCFPGA_A10
FPGA manager driver support for Altera Arria10 SoCFPGA.
config ALTERA_PR_IP_CORE
- tristate "Altera Partial Reconfiguration IP Core"
- help
- Core driver support for Altera Partial Reconfiguration IP component
+ tristate "Altera Partial Reconfiguration IP Core"
+ help
+ Core driver support for Altera Partial Reconfiguration IP component
config ALTERA_PR_IP_CORE_PLAT
tristate "Platform support of Altera Partial Reconfiguration IP Core"
diff --git a/drivers/fpga/dfl-afu-dma-region.c b/drivers/fpga/dfl-afu-dma-region.c
index dcd80b088c7b..62f924489db5 100644
--- a/drivers/fpga/dfl-afu-dma-region.c
+++ b/drivers/fpga/dfl-afu-dma-region.c
@@ -12,6 +12,7 @@
#include <linux/dma-mapping.h>
#include <linux/sched/signal.h>
#include <linux/uaccess.h>
+#include <linux/mm.h>
#include "dfl-afu.h"
@@ -32,52 +33,6 @@ void afu_dma_region_init(struct dfl_feature_platform_data *pdata)
}
/**
- * afu_dma_adjust_locked_vm - adjust locked memory
- * @dev: port device
- * @npages: number of pages
- * @incr: increase or decrease locked memory
- *
- * Increase or decrease the locked memory size with npages input.
- *
- * Return 0 on success.
- * Return -ENOMEM if locked memory size is over the limit and no CAP_IPC_LOCK.
- */
-static int afu_dma_adjust_locked_vm(struct device *dev, long npages, bool incr)
-{
- unsigned long locked, lock_limit;
- int ret = 0;
-
- /* the task is exiting. */
- if (!current->mm)
- return 0;
-
- down_write(&current->mm->mmap_sem);
-
- if (incr) {
- locked = current->mm->locked_vm + npages;
- lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
-
- if (locked > lock_limit && !capable(CAP_IPC_LOCK))
- ret = -ENOMEM;
- else
- current->mm->locked_vm += npages;
- } else {
- if (WARN_ON_ONCE(npages > current->mm->locked_vm))
- npages = current->mm->locked_vm;
- current->mm->locked_vm -= npages;
- }
-
- dev_dbg(dev, "[%d] RLIMIT_MEMLOCK %c%ld %ld/%ld%s\n", current->pid,
- incr ? '+' : '-', npages << PAGE_SHIFT,
- current->mm->locked_vm << PAGE_SHIFT, rlimit(RLIMIT_MEMLOCK),
- ret ? "- exceeded" : "");
-
- up_write(&current->mm->mmap_sem);
-
- return ret;
-}
-
-/**
* afu_dma_pin_pages - pin pages of given dma memory region
* @pdata: feature device platform data
* @region: dma memory region to be pinned
@@ -92,7 +47,7 @@ static int afu_dma_pin_pages(struct dfl_feature_platform_data *pdata,
struct device *dev = &pdata->dev->dev;
int ret, pinned;
- ret = afu_dma_adjust_locked_vm(dev, npages, true);
+ ret = account_locked_vm(current->mm, npages, true);
if (ret)
return ret;
@@ -121,7 +76,7 @@ put_pages:
free_pages:
kfree(region->pages);
unlock_vm:
- afu_dma_adjust_locked_vm(dev, npages, false);
+ account_locked_vm(current->mm, npages, false);
return ret;
}
@@ -141,7 +96,7 @@ static void afu_dma_unpin_pages(struct dfl_feature_platform_data *pdata,
put_all_pages(region->pages, npages);
kfree(region->pages);
- afu_dma_adjust_locked_vm(dev, npages, false);
+ account_locked_vm(current->mm, npages, false);
dev_dbg(dev, "%ld pages unpinned\n", npages);
}
diff --git a/drivers/fpga/dfl-fme-mgr.c b/drivers/fpga/dfl-fme-mgr.c
index 76f37709dd1a..b3f7eee3c93f 100644
--- a/drivers/fpga/dfl-fme-mgr.c
+++ b/drivers/fpga/dfl-fme-mgr.c
@@ -30,8 +30,8 @@
#define FME_PR_STS 0x10
#define FME_PR_DATA 0x18
#define FME_PR_ERR 0x20
-#define FME_PR_INTFC_ID_H 0xA8
-#define FME_PR_INTFC_ID_L 0xB0
+#define FME_PR_INTFC_ID_L 0xA8
+#define FME_PR_INTFC_ID_H 0xB0
/* FME PR Control Register Bitfield */
#define FME_PR_CTRL_PR_RST BIT_ULL(0) /* Reset PR engine */
diff --git a/drivers/fpga/dfl-fme-pr.c b/drivers/fpga/dfl-fme-pr.c
index d9ca9554844a..3c71dc3faaf5 100644
--- a/drivers/fpga/dfl-fme-pr.c
+++ b/drivers/fpga/dfl-fme-pr.c
@@ -74,6 +74,7 @@ static int fme_pr(struct platform_device *pdev, unsigned long arg)
struct dfl_fme *fme;
unsigned long minsz;
void *buf = NULL;
+ size_t length;
int ret = 0;
u64 v;
@@ -85,9 +86,6 @@ static int fme_pr(struct platform_device *pdev, unsigned long arg)
if (port_pr.argsz < minsz || port_pr.flags)
return -EINVAL;
- if (!IS_ALIGNED(port_pr.buffer_size, 4))
- return -EINVAL;
-
/* get fme header region */
fme_hdr = dfl_get_feature_ioaddr_by_id(&pdev->dev,
FME_FEATURE_ID_HEADER);
@@ -103,7 +101,13 @@ static int fme_pr(struct platform_device *pdev, unsigned long arg)
port_pr.buffer_size))
return -EFAULT;
- buf = vmalloc(port_pr.buffer_size);
+ /*
+ * align PR buffer per PR bandwidth, as HW ignores the extra padding
+ * data automatically.
+ */
+ length = ALIGN(port_pr.buffer_size, 4);
+
+ buf = vmalloc(length);
if (!buf)
return -ENOMEM;
@@ -140,7 +144,7 @@ static int fme_pr(struct platform_device *pdev, unsigned long arg)
fpga_image_info_free(region->info);
info->buf = buf;
- info->count = port_pr.buffer_size;
+ info->count = length;
info->region_id = port_pr.port_id;
region->info = info;
@@ -159,9 +163,6 @@ unlock_exit:
mutex_unlock(&pdata->lock);
free_exit:
vfree(buf);
- if (copy_to_user((void __user *)arg, &port_pr, minsz))
- return -EFAULT;
-
return ret;
}
diff --git a/drivers/fpga/of-fpga-region.c b/drivers/fpga/of-fpga-region.c
index 75f64abf9c81..e405309baadc 100644
--- a/drivers/fpga/of-fpga-region.c
+++ b/drivers/fpga/of-fpga-region.c
@@ -22,11 +22,6 @@ static const struct of_device_id fpga_region_of_match[] = {
};
MODULE_DEVICE_TABLE(of, fpga_region_of_match);
-static int fpga_region_of_node_match(struct device *dev, const void *data)
-{
- return dev->of_node == data;
-}
-
/**
* of_fpga_region_find - find FPGA region
* @np: device node of FPGA Region
@@ -37,7 +32,7 @@ static int fpga_region_of_node_match(struct device *dev, const void *data)
*/
static struct fpga_region *of_fpga_region_find(struct device_node *np)
{
- return fpga_region_class_find(NULL, np, fpga_region_of_node_match);
+ return fpga_region_class_find(NULL, np, device_match_of_node);
}
/**
diff --git a/drivers/fsi/cf-fsi-fw.h b/drivers/fsi/cf-fsi-fw.h
index 712df0461911..1118eaf7ee39 100644
--- a/drivers/fsi/cf-fsi-fw.h
+++ b/drivers/fsi/cf-fsi-fw.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __CF_FSI_FW_H
#define __CF_FSI_FW_H
diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index 1d83f3ba478b..1f76740f33b6 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -1029,6 +1029,14 @@ static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
}
+ rc = fsi_slave_set_smode(slave);
+ if (rc) {
+ dev_warn(&master->dev,
+ "can't set smode on slave:%02x:%02x %d\n",
+ link, id, rc);
+ goto err_free;
+ }
+
/* Allocate a minor in the FSI space */
rc = __fsi_get_new_minor(slave, fsi_dev_cfam, &slave->dev.devt,
&slave->cdev_idx);
@@ -1040,17 +1048,14 @@ static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
rc = cdev_device_add(&slave->cdev, &slave->dev);
if (rc) {
dev_err(&slave->dev, "Error %d creating slave device\n", rc);
- goto err_free;
+ goto err_free_ida;
}
- rc = fsi_slave_set_smode(slave);
- if (rc) {
- dev_warn(&master->dev,
- "can't set smode on slave:%02x:%02x %d\n",
- link, id, rc);
- kfree(slave);
- return -ENODEV;
- }
+ /* Now that we have the cdev registered with the core, any fatal
+ * failures beyond this point will need to clean up through
+ * cdev_device_del(). Fortunately though, nothing past here is fatal.
+ */
+
if (master->link_config)
master->link_config(master, link,
slave->t_send_delay,
@@ -1067,10 +1072,13 @@ static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
dev_dbg(&master->dev, "failed during slave scan with: %d\n",
rc);
- return rc;
+ return 0;
- err_free:
- put_device(&slave->dev);
+err_free_ida:
+ fsi_free_minor(slave->dev.devt);
+err_free:
+ of_node_put(slave->dev.of_node);
+ kfree(slave);
return rc;
}
diff --git a/drivers/fsi/fsi-occ.c b/drivers/fsi/fsi-occ.c
index a2301cea1cbb..7da9c81759ac 100644
--- a/drivers/fsi/fsi-occ.c
+++ b/drivers/fsi/fsi-occ.c
@@ -412,6 +412,7 @@ int fsi_occ_submit(struct device *dev, const void *request, size_t req_len,
msecs_to_jiffies(OCC_CMD_IN_PRG_WAIT_MS);
struct occ *occ = dev_get_drvdata(dev);
struct occ_response *resp = response;
+ u8 seq_no;
u16 resp_data_length;
unsigned long start;
int rc;
@@ -426,6 +427,8 @@ int fsi_occ_submit(struct device *dev, const void *request, size_t req_len,
mutex_lock(&occ->occ_lock);
+ /* Extract the seq_no from the command (first byte) */
+ seq_no = *(const u8 *)request;
rc = occ_putsram(occ, OCC_SRAM_CMD_ADDR, request, req_len);
if (rc)
goto done;
@@ -441,11 +444,17 @@ int fsi_occ_submit(struct device *dev, const void *request, size_t req_len,
if (rc)
goto done;
- if (resp->return_status == OCC_RESP_CMD_IN_PRG) {
+ if (resp->return_status == OCC_RESP_CMD_IN_PRG ||
+ resp->seq_no != seq_no) {
rc = -ETIMEDOUT;
- if (time_after(jiffies, start + timeout))
- break;
+ if (time_after(jiffies, start + timeout)) {
+ dev_err(occ->dev, "resp timeout status=%02x "
+ "resp seq_no=%d our seq_no=%d\n",
+ resp->return_status, resp->seq_no,
+ seq_no);
+ goto done;
+ }
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(wait_time);
diff --git a/drivers/fsi/fsi-sbefifo.c b/drivers/fsi/fsi-sbefifo.c
index d92f5b87c251..f54df9ebc8b3 100644
--- a/drivers/fsi/fsi-sbefifo.c
+++ b/drivers/fsi/fsi-sbefifo.c
@@ -289,11 +289,11 @@ static int sbefifo_check_sbe_state(struct sbefifo *sbefifo)
switch ((sbm & CFAM_SBM_SBE_STATE_MASK) >> CFAM_SBM_SBE_STATE_SHIFT) {
case SBE_STATE_UNKNOWN:
return -ESHUTDOWN;
+ case SBE_STATE_DMT:
+ return -EBUSY;
case SBE_STATE_IPLING:
case SBE_STATE_ISTEP:
case SBE_STATE_MPIPL:
- case SBE_STATE_DMT:
- return -EBUSY;
case SBE_STATE_RUNTIME:
case SBE_STATE_DUMP: /* Not sure about that one */
break;
diff --git a/drivers/fsi/fsi-scom.c b/drivers/fsi/fsi-scom.c
index 81dc01ac2351..343153d47e5b 100644
--- a/drivers/fsi/fsi-scom.c
+++ b/drivers/fsi/fsi-scom.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* SCOM FSI Client device driver
*
* Copyright (C) IBM Corporation 2016
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERGCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/fsi.h>
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index acd40eb51c46..bb13c266c329 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -62,16 +62,12 @@ config GPIO_SYSFS
bool "/sys/class/gpio/... (sysfs interface)"
depends on SYSFS
help
- Say Y here to add a sysfs interface for GPIOs.
+ Say Y here to add the legacy sysfs interface for GPIOs.
- This is mostly useful to work around omissions in a system's
- kernel support. Those are common in custom and semicustom
- hardware assembled using standard kernels with a minimum of
- custom patches. In those cases, userspace code may import
- a given GPIO from the kernel, if no kernel driver requested it.
-
- Kernel drivers may also request that a particular GPIO be
- exported to userspace; this can be useful when debugging.
+ This ABI is deprecated. If you want to use GPIO from userspace,
+ use the character device /dev/gpiochipN with the appropriate
+ ioctl() operations instead. The character device is always
+ available.
config GPIO_GENERIC
depends on HAS_IOMEM # Only for IOMEM drivers
@@ -178,7 +174,7 @@ config GPIO_CLPS711X
config GPIO_DAVINCI
bool "TI Davinci/Keystone GPIO support"
default y if ARCH_DAVINCI
- depends on ARM && (ARCH_DAVINCI || ARCH_KEYSTONE)
+ depends on (ARM || ARM64) && (ARCH_DAVINCI || ARCH_KEYSTONE || ARCH_K3)
help
Say yes here to enable GPIO support for TI Davinci/Keystone SoCs.
@@ -493,7 +489,8 @@ config GPIO_STA2X11
config GPIO_STP_XWAY
bool "XWAY STP GPIOs"
- depends on SOC_XWAY
+ depends on SOC_XWAY || COMPILE_TEST
+ depends on OF_GPIO
help
This enables support for the Serial To Parallel (STP) unit found on
XWAY SoC. The STP allows the SoC to drive a shift registers cascade,
@@ -602,7 +599,6 @@ config GPIO_XGENE_SB
config GPIO_XILINX
tristate "Xilinx GPIO support"
- depends on OF_GPIO
help
Say yes here to support the Xilinx FPGA GPIO device
@@ -979,6 +975,17 @@ config GPIO_ARIZONA
help
Support for GPIOs on Wolfson Arizona class devices.
+config GPIO_BD70528
+ tristate "ROHM BD70528 GPIO support"
+ depends on MFD_ROHM_BD70528
+ help
+ Support for GPIOs on ROHM BD70528 PMIC. There are four GPIOs
+ available on the ROHM PMIC in total. The GPIOs can also
+ generate interrupts.
+
+ This driver can also be built as a module. If so, the module
+ will be called gpio-bd70528.
+
config GPIO_BD9571MWV
tristate "ROHM BD9571 GPIO support"
depends on MFD_BD9571MWV
@@ -1305,7 +1312,7 @@ config GPIO_BT8XX
The card needs to be physically altered for using it as a
GPIO card. For more information on how to build a GPIO card
from a BT8xx TV card, see the documentation file at
- Documentation/bt8xxgpio.txt
+ Documentation/driver-api/bt8xxgpio.rst
If unsure, say N.
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 6700eee860b7..a4e91175c708 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -17,154 +17,155 @@ obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o
# directly supported by gpio-generic
gpio-generic-$(CONFIG_GPIO_GENERIC) += gpio-mmio.o
-obj-$(CONFIG_GPIO_104_DIO_48E) += gpio-104-dio-48e.o
-obj-$(CONFIG_GPIO_104_IDIO_16) += gpio-104-idio-16.o
-obj-$(CONFIG_GPIO_104_IDI_48) += gpio-104-idi-48.o
-obj-$(CONFIG_GPIO_74X164) += gpio-74x164.o
-obj-$(CONFIG_GPIO_74XX_MMIO) += gpio-74xx-mmio.o
-obj-$(CONFIG_GPIO_ADNP) += gpio-adnp.o
-obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o
-obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o
-obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o
-obj-$(CONFIG_GPIO_ALTERA_A10SR) += gpio-altera-a10sr.o
-obj-$(CONFIG_GPIO_AMD_FCH) += gpio-amd-fch.o
-obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o
-obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o
-obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
-obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o
-obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o
-obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o
-obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
-obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o
-obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
-obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
-obj-$(CONFIG_GPIO_CADENCE) += gpio-cadence.o
-obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o
-obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o
-obj-$(CONFIG_GPIO_CRYSTAL_COVE) += gpio-crystalcove.o
-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_DWAPB) += gpio-dwapb.o
-obj-$(CONFIG_GPIO_EIC_SPRD) += gpio-eic-sprd.o
-obj-$(CONFIG_GPIO_EM) += gpio-em.o
-obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
-obj-$(CONFIG_GPIO_EXAR) += gpio-exar.o
-obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o
-obj-$(CONFIG_GPIO_FTGPIO010) += gpio-ftgpio010.o
-obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
-obj-$(CONFIG_GPIO_GPIO_MM) += gpio-gpio-mm.o
-obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o
-obj-$(CONFIG_GPIO_GW_PLD) += gpio-gw-pld.o
-obj-$(CONFIG_GPIO_HLWD) += gpio-hlwd.o
-obj-$(CONFIG_HTC_EGPIO) += gpio-htc-egpio.o
-obj-$(CONFIG_GPIO_ICH) += gpio-ich.o
-obj-$(CONFIG_GPIO_IOP) += gpio-iop.o
-obj-$(CONFIG_GPIO_IXP4XX) += gpio-ixp4xx.o
-obj-$(CONFIG_GPIO_IT87) += gpio-it87.o
-obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o
-obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o
-obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o
-obj-$(CONFIG_GPIO_INTEL_MID) += gpio-intel-mid.o
-obj-$(CONFIG_GPIO_LOONGSON) += gpio-loongson.o
-obj-$(CONFIG_GPIO_LP3943) += gpio-lp3943.o
-obj-$(CONFIG_GPIO_LPC18XX) += gpio-lpc18xx.o
-obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o
-obj-$(CONFIG_GPIO_LP873X) += gpio-lp873x.o
-obj-$(CONFIG_GPIO_LP87565) += gpio-lp87565.o
-obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o
-obj-$(CONFIG_GPIO_MADERA) += gpio-madera.o
-obj-$(CONFIG_GPIO_MAX3191X) += gpio-max3191x.o
-obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o
-obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o
-obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o
-obj-$(CONFIG_GPIO_MAX732X) += gpio-max732x.o
-obj-$(CONFIG_GPIO_MAX77620) += gpio-max77620.o
-obj-$(CONFIG_GPIO_MAX77650) += gpio-max77650.o
-obj-$(CONFIG_GPIO_MB86S7X) += gpio-mb86s7x.o
-obj-$(CONFIG_GPIO_MENZ127) += gpio-menz127.o
-obj-$(CONFIG_GPIO_MERRIFIELD) += gpio-merrifield.o
-obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o
-obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o
-obj-$(CONFIG_GPIO_MLXBF) += gpio-mlxbf.o
-obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o
-obj-$(CONFIG_GPIO_MM_LANTIQ) += gpio-mm-lantiq.o
-obj-$(CONFIG_GPIO_MOCKUP) += gpio-mockup.o
-obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o
-obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o
-obj-$(CONFIG_GPIO_MSIC) += gpio-msic.o
+obj-$(CONFIG_GPIO_104_DIO_48E) += gpio-104-dio-48e.o
+obj-$(CONFIG_GPIO_104_IDI_48) += gpio-104-idi-48.o
+obj-$(CONFIG_GPIO_104_IDIO_16) += gpio-104-idio-16.o
+obj-$(CONFIG_GPIO_74X164) += gpio-74x164.o
+obj-$(CONFIG_GPIO_74XX_MMIO) += gpio-74xx-mmio.o
+obj-$(CONFIG_GPIO_ADNP) += gpio-adnp.o
+obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o
+obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o
+obj-$(CONFIG_GPIO_ALTERA_A10SR) += gpio-altera-a10sr.o
+obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o
+obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o
+obj-$(CONFIG_GPIO_AMD_FCH) += gpio-amd-fch.o
+obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o
+obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
+obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o
+obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o
+obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
+obj-$(CONFIG_GPIO_BD70528) += gpio-bd70528.o
+obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o
+obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
+obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
+obj-$(CONFIG_GPIO_CADENCE) += gpio-cadence.o
+obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o
+obj-$(CONFIG_GPIO_SNPS_CREG) += gpio-creg-snps.o
+obj-$(CONFIG_GPIO_CRYSTAL_COVE) += gpio-crystalcove.o
+obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o
+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_DWAPB) += gpio-dwapb.o
+obj-$(CONFIG_GPIO_EIC_SPRD) += gpio-eic-sprd.o
+obj-$(CONFIG_GPIO_EM) += gpio-em.o
+obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
+obj-$(CONFIG_GPIO_EXAR) += gpio-exar.o
+obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o
+obj-$(CONFIG_GPIO_FTGPIO010) += gpio-ftgpio010.o
+obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
+obj-$(CONFIG_GPIO_GPIO_MM) += gpio-gpio-mm.o
+obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o
+obj-$(CONFIG_GPIO_GW_PLD) += gpio-gw-pld.o
+obj-$(CONFIG_GPIO_HLWD) += gpio-hlwd.o
+obj-$(CONFIG_HTC_EGPIO) += gpio-htc-egpio.o
+obj-$(CONFIG_GPIO_ICH) += gpio-ich.o
+obj-$(CONFIG_GPIO_INTEL_MID) += gpio-intel-mid.o
+obj-$(CONFIG_GPIO_IOP) += gpio-iop.o
+obj-$(CONFIG_GPIO_IT87) += gpio-it87.o
+obj-$(CONFIG_GPIO_IXP4XX) += gpio-ixp4xx.o
+obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o
+obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o
+obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o
+obj-$(CONFIG_GPIO_LOONGSON1) += gpio-loongson1.o
+obj-$(CONFIG_GPIO_LOONGSON) += gpio-loongson.o
+obj-$(CONFIG_GPIO_LP3943) += gpio-lp3943.o
+obj-$(CONFIG_GPIO_LP873X) += gpio-lp873x.o
+obj-$(CONFIG_GPIO_LP87565) += gpio-lp87565.o
+obj-$(CONFIG_GPIO_LPC18XX) += gpio-lpc18xx.o
+obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o
+obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o
+obj-$(CONFIG_GPIO_MADERA) += gpio-madera.o
+obj-$(CONFIG_GPIO_MAX3191X) += gpio-max3191x.o
+obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o
+obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o
+obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o
+obj-$(CONFIG_GPIO_MAX732X) += gpio-max732x.o
+obj-$(CONFIG_GPIO_MAX77620) += gpio-max77620.o
+obj-$(CONFIG_GPIO_MAX77650) += gpio-max77650.o
+obj-$(CONFIG_GPIO_MB86S7X) += gpio-mb86s7x.o
+obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o
+obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o
+obj-$(CONFIG_GPIO_MENZ127) += gpio-menz127.o
+obj-$(CONFIG_GPIO_MERRIFIELD) += gpio-merrifield.o
+obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o
+obj-$(CONFIG_GPIO_MLXBF) += gpio-mlxbf.o
+obj-$(CONFIG_GPIO_MM_LANTIQ) += gpio-mm-lantiq.o
+obj-$(CONFIG_GPIO_MOCKUP) += gpio-mockup.o
+obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o
+obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o
+obj-$(CONFIG_GPIO_MSIC) += gpio-msic.o
obj-$(CONFIG_GPIO_MT7621) += gpio-mt7621.o
-obj-$(CONFIG_GPIO_MVEBU) += gpio-mvebu.o
-obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o
-obj-$(CONFIG_GPIO_MXS) += gpio-mxs.o
-obj-$(CONFIG_GPIO_OCTEON) += gpio-octeon.o
-obj-$(CONFIG_GPIO_OMAP) += gpio-omap.o
-obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o
-obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o
-obj-$(CONFIG_GPIO_PCH) += gpio-pch.o
-obj-$(CONFIG_GPIO_PCI_IDIO_16) += gpio-pci-idio-16.o
-obj-$(CONFIG_GPIO_PCIE_IDIO_24) += gpio-pcie-idio-24.o
-obj-$(CONFIG_GPIO_PISOSR) += gpio-pisosr.o
-obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o
+obj-$(CONFIG_GPIO_MVEBU) += gpio-mvebu.o
+obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o
+obj-$(CONFIG_GPIO_MXS) += gpio-mxs.o
+obj-$(CONFIG_GPIO_OCTEON) += gpio-octeon.o
+obj-$(CONFIG_GPIO_OMAP) += gpio-omap.o
+obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o
+obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o
+obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o
+obj-$(CONFIG_GPIO_PCH) += gpio-pch.o
+obj-$(CONFIG_GPIO_PCIE_IDIO_24) += gpio-pcie-idio-24.o
+obj-$(CONFIG_GPIO_PCI_IDIO_16) += gpio-pci-idio-16.o
+obj-$(CONFIG_GPIO_PISOSR) += gpio-pisosr.o
+obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o
obj-$(CONFIG_GPIO_PMIC_EIC_SPRD) += gpio-pmic-eic-sprd.o
-obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o
-obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o
-obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o
-obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o
-obj-$(CONFIG_GPIO_REG) += gpio-reg.o
-obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o
+obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o
+obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o
+obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o
+obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o
+obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o
+obj-$(CONFIG_GPIO_REG) += gpio-reg.o
+obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o
obj-$(CONFIG_GPIO_SAMA5D2_PIOBU) += gpio-sama5d2-piobu.o
-obj-$(CONFIG_GPIO_SCH) += gpio-sch.o
-obj-$(CONFIG_GPIO_SCH311X) += gpio-sch311x.o
-obj-$(CONFIG_GPIO_SNPS_CREG) += gpio-creg-snps.o
-obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o
-obj-$(CONFIG_GPIO_SPEAR_SPICS) += gpio-spear-spics.o
-obj-$(CONFIG_GPIO_SPRD) += gpio-sprd.o
-obj-$(CONFIG_GPIO_STA2X11) += gpio-sta2x11.o
-obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o
-obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o
-obj-$(CONFIG_GPIO_SYSCON) += gpio-syscon.o
-obj-$(CONFIG_GPIO_TB10X) += gpio-tb10x.o
-obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o
-obj-$(CONFIG_GPIO_TEGRA) += gpio-tegra.o
-obj-$(CONFIG_GPIO_TEGRA186) += gpio-tegra186.o
-obj-$(CONFIG_GPIO_THUNDERX) += gpio-thunderx.o
-obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o
-obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o
-obj-$(CONFIG_GPIO_SIOX) += gpio-siox.o
-obj-$(CONFIG_GPIO_TPIC2810) += gpio-tpic2810.o
-obj-$(CONFIG_GPIO_TPS65086) += gpio-tps65086.o
-obj-$(CONFIG_GPIO_TPS65218) += gpio-tps65218.o
-obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o
-obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o
-obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o
-obj-$(CONFIG_GPIO_TPS68470) += gpio-tps68470.o
-obj-$(CONFIG_GPIO_TQMX86) += gpio-tqmx86.o
-obj-$(CONFIG_GPIO_TS4800) += gpio-ts4800.o
-obj-$(CONFIG_GPIO_TS4900) += gpio-ts4900.o
-obj-$(CONFIG_GPIO_TS5500) += gpio-ts5500.o
-obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o
-obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o
-obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o
-obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o
-obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o
-obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o
-obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o
-obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o
-obj-$(CONFIG_GPIO_WHISKEY_COVE) += gpio-wcove.o
-obj-$(CONFIG_GPIO_WINBOND) += gpio-winbond.o
-obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o
-obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o
-obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o
-obj-$(CONFIG_GPIO_WS16C48) += gpio-ws16c48.o
-obj-$(CONFIG_GPIO_XGENE) += gpio-xgene.o
-obj-$(CONFIG_GPIO_XGENE_SB) += gpio-xgene-sb.o
-obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o
-obj-$(CONFIG_GPIO_XLP) += gpio-xlp.o
-obj-$(CONFIG_GPIO_XRA1403) += gpio-xra1403.o
-obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o
-obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o
-obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o
-obj-$(CONFIG_GPIO_ZX) += gpio-zx.o
-obj-$(CONFIG_GPIO_LOONGSON1) += gpio-loongson1.o
+obj-$(CONFIG_GPIO_SCH311X) += gpio-sch311x.o
+obj-$(CONFIG_GPIO_SCH) += gpio-sch.o
+obj-$(CONFIG_GPIO_SIOX) += gpio-siox.o
+obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o
+obj-$(CONFIG_GPIO_SPEAR_SPICS) += gpio-spear-spics.o
+obj-$(CONFIG_GPIO_SPRD) += gpio-sprd.o
+obj-$(CONFIG_GPIO_STA2X11) += gpio-sta2x11.o
+obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o
+obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o
+obj-$(CONFIG_GPIO_SYSCON) += gpio-syscon.o
+obj-$(CONFIG_GPIO_TB10X) += gpio-tb10x.o
+obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o
+obj-$(CONFIG_GPIO_TEGRA186) += gpio-tegra186.o
+obj-$(CONFIG_GPIO_TEGRA) += gpio-tegra.o
+obj-$(CONFIG_GPIO_THUNDERX) += gpio-thunderx.o
+obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o
+obj-$(CONFIG_GPIO_TPIC2810) += gpio-tpic2810.o
+obj-$(CONFIG_GPIO_TPS65086) += gpio-tps65086.o
+obj-$(CONFIG_GPIO_TPS65218) += gpio-tps65218.o
+obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o
+obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o
+obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o
+obj-$(CONFIG_GPIO_TPS68470) += gpio-tps68470.o
+obj-$(CONFIG_GPIO_TQMX86) += gpio-tqmx86.o
+obj-$(CONFIG_GPIO_TS4800) += gpio-ts4800.o
+obj-$(CONFIG_GPIO_TS4900) += gpio-ts4900.o
+obj-$(CONFIG_GPIO_TS5500) += gpio-ts5500.o
+obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o
+obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o
+obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o
+obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o
+obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o
+obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o
+obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o
+obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o
+obj-$(CONFIG_GPIO_WHISKEY_COVE) += gpio-wcove.o
+obj-$(CONFIG_GPIO_WINBOND) += gpio-winbond.o
+obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o
+obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o
+obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o
+obj-$(CONFIG_GPIO_WS16C48) += gpio-ws16c48.o
+obj-$(CONFIG_GPIO_XGENE) += gpio-xgene.o
+obj-$(CONFIG_GPIO_XGENE_SB) += gpio-xgene-sb.o
+obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o
+obj-$(CONFIG_GPIO_XLP) += gpio-xlp.o
+obj-$(CONFIG_GPIO_XRA1403) += gpio-xra1403.o
+obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o
+obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o
+obj-$(CONFIG_GPIO_ZX) += gpio-zx.o
+obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o
diff --git a/drivers/gpio/TODO b/drivers/gpio/TODO
index 19d27c904916..9c048f10c9ad 100644
--- a/drivers/gpio/TODO
+++ b/drivers/gpio/TODO
@@ -90,6 +90,46 @@ GPIOLIB irqchip
The GPIOLIB irqchip is a helper irqchip for "simple cases" that should
try to cover any generic kind of irqchip cascaded from a GPIO.
+- Convert all the GPIOLIB_IRQCHIP users to pass an irqchip template,
+ parent and flags before calling [devm_]gpiochip_add[_data]().
+ Currently we set up the irqchip after setting up the gpiochip
+ using gpiochip_irqchip_add() and gpiochip_set_[chained|nested]_irqchip().
+ This is too complex, so convert all users over to just set up
+ the irqchip before registering the gpio_chip, typical example:
+
+ /* Typical state container with dynamic irqchip */
+ struct my_gpio {
+ struct gpio_chip gc;
+ struct irq_chip irq;
+ };
+
+ int irq; /* from platform etc */
+ struct my_gpio *g;
+ struct gpio_irq_chip *girq
+
+ /* Set up the irqchip dynamically */
+ g->irq.name = "my_gpio_irq";
+ g->irq.irq_ack = my_gpio_ack_irq;
+ g->irq.irq_mask = my_gpio_mask_irq;
+ g->irq.irq_unmask = my_gpio_unmask_irq;
+ g->irq.irq_set_type = my_gpio_set_irq_type;
+
+ /* Get a pointer to the gpio_irq_chip */
+ girq = &g->gc.irq;
+ girq->chip = &g->irq;
+ girq->parent_handler = ftgpio_gpio_irq_handler;
+ girq->num_parents = 1;
+ girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
+ GFP_KERNEL);
+ if (!girq->parents)
+ return -ENOMEM;
+ girq->default_type = IRQ_TYPE_NONE;
+ girq->handler = handle_bad_irq;
+ girq->parents[0] = irq;
+
+ When this is done, we will delete the old APIs for instatiating
+ GPIOLIB_IRQCHIP and simplify the code.
+
- Look over and identify any remaining easily converted drivers and
dry-code conversions to gpiolib irqchip for maintainers to test
diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c
index 12acdac85820..b9fcaab2a931 100644
--- a/drivers/gpio/gpio-adnp.c
+++ b/drivers/gpio/gpio-adnp.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011-2012 Avionic Design GmbH
- *
- * 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.
*/
#include <linux/gpio/driver.h>
diff --git a/drivers/gpio/gpio-altera.c b/drivers/gpio/gpio-altera.c
index e088b908c2c1..9f2e6b04c361 100644
--- a/drivers/gpio/gpio-altera.c
+++ b/drivers/gpio/gpio-altera.c
@@ -30,6 +30,7 @@ struct altera_gpio_chip {
raw_spinlock_t gpio_lock;
int interrupt_trigger;
int mapped_irq;
+ struct irq_chip irq_chip;
};
static void altera_gpio_irq_unmask(struct irq_data *d)
@@ -101,15 +102,6 @@ static unsigned int altera_gpio_irq_startup(struct irq_data *d)
return 0;
}
-static struct irq_chip altera_irq_chip = {
- .name = "altera-gpio",
- .irq_mask = altera_gpio_irq_mask,
- .irq_unmask = altera_gpio_irq_unmask,
- .irq_set_type = altera_gpio_irq_set_type,
- .irq_startup = altera_gpio_irq_startup,
- .irq_shutdown = altera_gpio_irq_mask,
-};
-
static int altera_gpio_get(struct gpio_chip *gc, unsigned offset)
{
struct of_mm_gpio_chip *mm_gc;
@@ -246,6 +238,7 @@ static int altera_gpio_probe(struct platform_device *pdev)
struct device_node *node = pdev->dev.of_node;
int reg, ret;
struct altera_gpio_chip *altera_gc;
+ struct gpio_irq_chip *girq;
altera_gc = devm_kzalloc(&pdev->dev, sizeof(*altera_gc), GFP_KERNEL);
if (!altera_gc)
@@ -273,50 +266,50 @@ static int altera_gpio_probe(struct platform_device *pdev)
altera_gc->mmchip.gc.owner = THIS_MODULE;
altera_gc->mmchip.gc.parent = &pdev->dev;
- ret = of_mm_gpiochip_add_data(node, &altera_gc->mmchip, altera_gc);
- if (ret) {
- dev_err(&pdev->dev, "Failed adding memory mapped gpiochip\n");
- return ret;
- }
-
- platform_set_drvdata(pdev, altera_gc);
-
altera_gc->mapped_irq = platform_get_irq(pdev, 0);
if (altera_gc->mapped_irq < 0)
goto skip_irq;
if (of_property_read_u32(node, "altr,interrupt-type", &reg)) {
- ret = -EINVAL;
dev_err(&pdev->dev,
"altr,interrupt-type value not set in device tree\n");
- goto teardown;
+ return -EINVAL;
}
altera_gc->interrupt_trigger = reg;
- ret = gpiochip_irqchip_add(&altera_gc->mmchip.gc, &altera_irq_chip, 0,
- handle_bad_irq, IRQ_TYPE_NONE);
+ altera_gc->irq_chip.name = "altera-gpio";
+ altera_gc->irq_chip.irq_mask = altera_gpio_irq_mask;
+ altera_gc->irq_chip.irq_unmask = altera_gpio_irq_unmask;
+ altera_gc->irq_chip.irq_set_type = altera_gpio_irq_set_type;
+ altera_gc->irq_chip.irq_startup = altera_gpio_irq_startup;
+ altera_gc->irq_chip.irq_shutdown = altera_gpio_irq_mask;
+
+ girq = &altera_gc->mmchip.gc.irq;
+ girq->chip = &altera_gc->irq_chip;
+ if (altera_gc->interrupt_trigger == IRQ_TYPE_LEVEL_HIGH)
+ girq->parent_handler = altera_gpio_irq_leveL_high_handler;
+ else
+ girq->parent_handler = altera_gpio_irq_edge_handler;
+ girq->num_parents = 1;
+ girq->parents = devm_kcalloc(&pdev->dev, 1, sizeof(*girq->parents),
+ GFP_KERNEL);
+ if (!girq->parents)
+ return -ENOMEM;
+ girq->default_type = IRQ_TYPE_NONE;
+ girq->handler = handle_bad_irq;
+ girq->parents[0] = altera_gc->mapped_irq;
+skip_irq:
+ ret = of_mm_gpiochip_add_data(node, &altera_gc->mmchip, altera_gc);
if (ret) {
- dev_err(&pdev->dev, "could not add irqchip\n");
- goto teardown;
+ dev_err(&pdev->dev, "Failed adding memory mapped gpiochip\n");
+ return ret;
}
- gpiochip_set_chained_irqchip(&altera_gc->mmchip.gc,
- &altera_irq_chip,
- altera_gc->mapped_irq,
- altera_gc->interrupt_trigger == IRQ_TYPE_LEVEL_HIGH ?
- altera_gpio_irq_leveL_high_handler :
- altera_gpio_irq_edge_handler);
+ platform_set_drvdata(pdev, altera_gc);
-skip_irq:
return 0;
-teardown:
- of_mm_gpiochip_remove(&altera_gc->mmchip);
- pr_err("%pOF: registration failed with status %d\n",
- node, ret);
-
- return ret;
}
static int altera_gpio_remove(struct platform_device *pdev)
diff --git a/drivers/gpio/gpio-amd-fch.c b/drivers/gpio/gpio-amd-fch.c
index 38c3f4a3d4aa..181df1581df5 100644
--- a/drivers/gpio/gpio-amd-fch.c
+++ b/drivers/gpio/gpio-amd-fch.c
@@ -25,14 +25,13 @@
#define AMD_FCH_GPIO_FLAG_WRITE BIT(22)
#define AMD_FCH_GPIO_FLAG_READ BIT(16)
-static struct resource amd_fch_gpio_iores =
+static const struct resource amd_fch_gpio_iores =
DEFINE_RES_MEM_NAMED(
AMD_FCH_MMIO_BASE + AMD_FCH_GPIO_BANK0_BASE,
AMD_FCH_GPIO_SIZE,
"amd-fch-gpio-iomem");
struct amd_fch_gpio_priv {
- struct platform_device *pdev;
struct gpio_chip gc;
void __iomem *base;
struct amd_fch_gpio_pdata *pdata;
@@ -153,7 +152,6 @@ static int amd_fch_gpio_probe(struct platform_device *pdev)
return -ENOMEM;
priv->pdata = pdata;
- priv->pdev = pdev;
priv->gc.owner = THIS_MODULE;
priv->gc.parent = &pdev->dev;
diff --git a/drivers/gpio/gpio-amdpt.c b/drivers/gpio/gpio-amdpt.c
index 1ffd7c2d1285..44398992ae15 100644
--- a/drivers/gpio/gpio-amdpt.c
+++ b/drivers/gpio/gpio-amdpt.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AMD Promontory GPIO driver
*
* Copyright (C) 2015 ASMedia Technology Inc.
* Author: YD Tseng <yd_tseng@asmedia.com.tw>
- *
- * 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.
*/
#include <linux/kernel.h>
@@ -91,7 +88,7 @@ static int pt_gpio_probe(struct platform_device *pdev)
pt_gpio->reg_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(pt_gpio->reg_base)) {
- dev_err(&pdev->dev, "Failed to map MMIO resource for PT GPIO.\n");
+ dev_err(dev, "Failed to map MMIO resource for PT GPIO.\n");
return PTR_ERR(pt_gpio->reg_base);
}
@@ -101,7 +98,7 @@ static int pt_gpio_probe(struct platform_device *pdev)
pt_gpio->reg_base + PT_DIRECTION_REG, NULL,
BGPIOF_READ_OUTPUT_REG_SET);
if (ret) {
- dev_err(&pdev->dev, "bgpio_init failed\n");
+ dev_err(dev, "bgpio_init failed\n");
return ret;
}
@@ -110,11 +107,11 @@ static int pt_gpio_probe(struct platform_device *pdev)
pt_gpio->gc.free = pt_gpio_free;
pt_gpio->gc.ngpio = PT_TOTAL_GPIO;
#if defined(CONFIG_OF_GPIO)
- pt_gpio->gc.of_node = pdev->dev.of_node;
+ pt_gpio->gc.of_node = dev->of_node;
#endif
ret = gpiochip_add_data(&pt_gpio->gc, pt_gpio);
if (ret) {
- dev_err(&pdev->dev, "Failed to register GPIO lib\n");
+ dev_err(dev, "Failed to register GPIO lib\n");
return ret;
}
@@ -124,7 +121,7 @@ static int pt_gpio_probe(struct platform_device *pdev)
writel(0, pt_gpio->reg_base + PT_SYNC_REG);
writel(0, pt_gpio->reg_base + PT_CLOCKRATE_REG);
- dev_dbg(&pdev->dev, "PT GPIO driver loaded\n");
+ dev_dbg(dev, "PT GPIO driver loaded\n");
return ret;
}
diff --git a/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c
index 0a553d676042..f1a5ea9b3de2 100644
--- a/drivers/gpio/gpio-ath79.c
+++ b/drivers/gpio/gpio-ath79.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Atheros AR71XX/AR724X/AR913X GPIO API support
*
@@ -5,10 +6,6 @@
* Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>
* Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
* Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
- *
- * 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.
*/
#include <linux/gpio/driver.h>
@@ -225,14 +222,16 @@ MODULE_DEVICE_TABLE(of, ath79_gpio_of_match);
static int ath79_gpio_probe(struct platform_device *pdev)
{
struct ath79_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
- struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
struct ath79_gpio_ctrl *ctrl;
+ struct gpio_irq_chip *girq;
struct resource *res;
u32 ath79_gpio_count;
bool oe_inverted;
int err;
- ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL);
+ ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
if (!ctrl)
return -ENOMEM;
platform_set_drvdata(pdev, ctrl);
@@ -240,7 +239,7 @@ static int ath79_gpio_probe(struct platform_device *pdev)
if (np) {
err = of_property_read_u32(np, "ngpios", &ath79_gpio_count);
if (err) {
- dev_err(&pdev->dev, "ngpios property is not valid\n");
+ dev_err(dev, "ngpios property is not valid\n");
return err;
}
oe_inverted = of_device_is_compatible(np, "qca,ar9340-gpio");
@@ -248,25 +247,24 @@ static int ath79_gpio_probe(struct platform_device *pdev)
ath79_gpio_count = pdata->ngpios;
oe_inverted = pdata->oe_inverted;
} else {
- dev_err(&pdev->dev, "No DT node or platform data found\n");
+ dev_err(dev, "No DT node or platform data found\n");
return -EINVAL;
}
if (ath79_gpio_count >= 32) {
- dev_err(&pdev->dev, "ngpios must be less than 32\n");
+ dev_err(dev, "ngpios must be less than 32\n");
return -EINVAL;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -EINVAL;
- ctrl->base = devm_ioremap_nocache(
- &pdev->dev, res->start, resource_size(res));
+ ctrl->base = devm_ioremap_nocache(dev, res->start, resource_size(res));
if (!ctrl->base)
return -ENOMEM;
raw_spin_lock_init(&ctrl->lock);
- err = bgpio_init(&ctrl->gc, &pdev->dev, 4,
+ err = bgpio_init(&ctrl->gc, dev, 4,
ctrl->base + AR71XX_GPIO_REG_IN,
ctrl->base + AR71XX_GPIO_REG_SET,
ctrl->base + AR71XX_GPIO_REG_CLEAR,
@@ -274,45 +272,33 @@ static int ath79_gpio_probe(struct platform_device *pdev)
oe_inverted ? ctrl->base + AR71XX_GPIO_REG_OE : NULL,
0);
if (err) {
- dev_err(&pdev->dev, "bgpio_init failed\n");
+ dev_err(dev, "bgpio_init failed\n");
return err;
}
/* Use base 0 to stay compatible with legacy platforms */
ctrl->gc.base = 0;
- err = gpiochip_add_data(&ctrl->gc, ctrl);
- if (err) {
- dev_err(&pdev->dev,
- "cannot add AR71xx GPIO chip, error=%d", err);
- return err;
+ /* Optional interrupt setup */
+ if (!np || of_property_read_bool(np, "interrupt-controller")) {
+ girq = &ctrl->gc.irq;
+ girq->chip = &ath79_gpio_irqchip;
+ girq->parent_handler = ath79_gpio_irq_handler;
+ girq->num_parents = 1;
+ girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
+ GFP_KERNEL);
+ if (!girq->parents)
+ return -ENOMEM;
+ girq->parents[0] = platform_get_irq(pdev, 0);
+ girq->default_type = IRQ_TYPE_NONE;
+ girq->handler = handle_simple_irq;
}
- if (np && !of_property_read_bool(np, "interrupt-controller"))
- return 0;
-
- err = gpiochip_irqchip_add(&ctrl->gc, &ath79_gpio_irqchip, 0,
- handle_simple_irq, IRQ_TYPE_NONE);
+ err = devm_gpiochip_add_data(dev, &ctrl->gc, ctrl);
if (err) {
- dev_err(&pdev->dev, "failed to add gpiochip_irqchip\n");
- goto gpiochip_remove;
+ dev_err(dev,
+ "cannot add AR71xx GPIO chip, error=%d", err);
+ return err;
}
-
- gpiochip_set_chained_irqchip(&ctrl->gc, &ath79_gpio_irqchip,
- platform_get_irq(pdev, 0),
- ath79_gpio_irq_handler);
-
- return 0;
-
-gpiochip_remove:
- gpiochip_remove(&ctrl->gc);
- return err;
-}
-
-static int ath79_gpio_remove(struct platform_device *pdev)
-{
- struct ath79_gpio_ctrl *ctrl = platform_get_drvdata(pdev);
-
- gpiochip_remove(&ctrl->gc);
return 0;
}
@@ -322,7 +308,6 @@ static struct platform_driver ath79_gpio_driver = {
.of_match_table = ath79_gpio_of_match,
},
.probe = ath79_gpio_probe,
- .remove = ath79_gpio_remove,
};
module_platform_driver(ath79_gpio_driver);
diff --git a/drivers/gpio/gpio-bd70528.c b/drivers/gpio/gpio-bd70528.c
new file mode 100644
index 000000000000..fd85605d2dab
--- /dev/null
+++ b/drivers/gpio/gpio-bd70528.c
@@ -0,0 +1,232 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 ROHM Semiconductors
+// gpio-bd70528.c ROHM BD70528MWV gpio driver
+
+#include <linux/gpio/driver.h>
+#include <linux/mfd/rohm-bd70528.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define GPIO_IN_REG(offset) (BD70528_REG_GPIO1_IN + (offset) * 2)
+#define GPIO_OUT_REG(offset) (BD70528_REG_GPIO1_OUT + (offset) * 2)
+
+struct bd70528_gpio {
+ struct rohm_regmap_dev chip;
+ struct gpio_chip gpio;
+};
+
+static int bd70528_set_debounce(struct bd70528_gpio *bdgpio,
+ unsigned int offset, unsigned int debounce)
+{
+ u8 val;
+
+ switch (debounce) {
+ case 0:
+ val = BD70528_DEBOUNCE_DISABLE;
+ break;
+ case 1 ... 15:
+ val = BD70528_DEBOUNCE_15MS;
+ break;
+ case 16 ... 30:
+ val = BD70528_DEBOUNCE_30MS;
+ break;
+ case 31 ... 50:
+ val = BD70528_DEBOUNCE_50MS;
+ break;
+ default:
+ dev_err(bdgpio->chip.dev,
+ "Invalid debouce value %u\n", debounce);
+ return -EINVAL;
+ }
+ return regmap_update_bits(bdgpio->chip.regmap, GPIO_IN_REG(offset),
+ BD70528_DEBOUNCE_MASK, val);
+}
+
+static int bd70528_get_direction(struct gpio_chip *chip, unsigned int offset)
+{
+ struct bd70528_gpio *bdgpio = gpiochip_get_data(chip);
+ int val, ret;
+
+ /* Do we need to do something to IRQs here? */
+ ret = regmap_read(bdgpio->chip.regmap, GPIO_OUT_REG(offset), &val);
+ if (ret) {
+ dev_err(bdgpio->chip.dev, "Could not read gpio direction\n");
+ return ret;
+ }
+
+ return !(val & BD70528_GPIO_OUT_EN_MASK);
+}
+
+static int bd70528_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
+ unsigned long config)
+{
+ struct bd70528_gpio *bdgpio = gpiochip_get_data(chip);
+
+ switch (pinconf_to_config_param(config)) {
+ case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+ return regmap_update_bits(bdgpio->chip.regmap,
+ GPIO_OUT_REG(offset),
+ BD70528_GPIO_DRIVE_MASK,
+ BD70528_GPIO_OPEN_DRAIN);
+ break;
+ case PIN_CONFIG_DRIVE_PUSH_PULL:
+ return regmap_update_bits(bdgpio->chip.regmap,
+ GPIO_OUT_REG(offset),
+ BD70528_GPIO_DRIVE_MASK,
+ BD70528_GPIO_PUSH_PULL);
+ break;
+ case PIN_CONFIG_INPUT_DEBOUNCE:
+ return bd70528_set_debounce(bdgpio, offset,
+ pinconf_to_config_argument(config));
+ break;
+ default:
+ break;
+ }
+ return -ENOTSUPP;
+}
+
+static int bd70528_direction_input(struct gpio_chip *chip, unsigned int offset)
+{
+ struct bd70528_gpio *bdgpio = gpiochip_get_data(chip);
+
+ /* Do we need to do something to IRQs here? */
+ return regmap_update_bits(bdgpio->chip.regmap, GPIO_OUT_REG(offset),
+ BD70528_GPIO_OUT_EN_MASK,
+ BD70528_GPIO_OUT_DISABLE);
+}
+
+static void bd70528_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
+{
+ int ret;
+ struct bd70528_gpio *bdgpio = gpiochip_get_data(chip);
+ u8 val = (value) ? BD70528_GPIO_OUT_HI : BD70528_GPIO_OUT_LO;
+
+ ret = regmap_update_bits(bdgpio->chip.regmap, GPIO_OUT_REG(offset),
+ BD70528_GPIO_OUT_MASK, val);
+ if (ret)
+ dev_err(bdgpio->chip.dev, "Could not set gpio to %d\n", value);
+}
+
+static int bd70528_direction_output(struct gpio_chip *chip, unsigned int offset,
+ int value)
+{
+ struct bd70528_gpio *bdgpio = gpiochip_get_data(chip);
+
+ bd70528_gpio_set(chip, offset, value);
+ return regmap_update_bits(bdgpio->chip.regmap, GPIO_OUT_REG(offset),
+ BD70528_GPIO_OUT_EN_MASK,
+ BD70528_GPIO_OUT_ENABLE);
+}
+
+#define GPIO_IN_STATE_MASK(offset) (BD70528_GPIO_IN_STATE_BASE << (offset))
+
+static int bd70528_gpio_get_o(struct bd70528_gpio *bdgpio, unsigned int offset)
+{
+ int ret;
+ unsigned int val;
+
+ ret = regmap_read(bdgpio->chip.regmap, GPIO_OUT_REG(offset), &val);
+ if (!ret)
+ ret = !!(val & BD70528_GPIO_OUT_MASK);
+ else
+ dev_err(bdgpio->chip.dev, "GPIO (out) state read failed\n");
+
+ return ret;
+}
+
+static int bd70528_gpio_get_i(struct bd70528_gpio *bdgpio, unsigned int offset)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(bdgpio->chip.regmap, BD70528_REG_GPIO_STATE, &val);
+
+ if (!ret)
+ ret = !(val & GPIO_IN_STATE_MASK(offset));
+ else
+ dev_err(bdgpio->chip.dev, "GPIO (in) state read failed\n");
+
+ return ret;
+}
+
+static int bd70528_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+ int ret = -EINVAL;
+ struct bd70528_gpio *bdgpio = gpiochip_get_data(chip);
+
+ /*
+ * There is a race condition where someone might be changing the
+ * GPIO direction after we get it but before we read the value. But
+ * application design where GPIO direction may be changed just when
+ * we read GPIO value would be pointless as reader could not know
+ * whether the returned high/low state is caused by input or output.
+ * Or then there must be other ways to mitigate the issue. Thus
+ * locking would make no sense.
+ */
+ ret = bd70528_get_direction(chip, offset);
+ if (ret == 0)
+ ret = bd70528_gpio_get_o(bdgpio, offset);
+ else if (ret == 1)
+ ret = bd70528_gpio_get_i(bdgpio, offset);
+ else
+ dev_err(bdgpio->chip.dev, "failed to read GPIO direction\n");
+
+ return ret;
+}
+
+static int bd70528_probe(struct platform_device *pdev)
+{
+ struct bd70528_gpio *bdgpio;
+ struct rohm_regmap_dev *bd70528;
+ int ret;
+
+ bd70528 = dev_get_drvdata(pdev->dev.parent);
+ if (!bd70528) {
+ dev_err(&pdev->dev, "No MFD driver data\n");
+ return -EINVAL;
+ }
+
+ bdgpio = devm_kzalloc(&pdev->dev, sizeof(*bdgpio),
+ GFP_KERNEL);
+ if (!bdgpio)
+ return -ENOMEM;
+ bdgpio->chip.dev = &pdev->dev;
+ bdgpio->gpio.parent = pdev->dev.parent;
+ bdgpio->gpio.label = "bd70528-gpio";
+ bdgpio->gpio.owner = THIS_MODULE;
+ bdgpio->gpio.get_direction = bd70528_get_direction;
+ bdgpio->gpio.direction_input = bd70528_direction_input;
+ bdgpio->gpio.direction_output = bd70528_direction_output;
+ bdgpio->gpio.set_config = bd70528_gpio_set_config;
+ bdgpio->gpio.can_sleep = true;
+ bdgpio->gpio.get = bd70528_gpio_get;
+ bdgpio->gpio.set = bd70528_gpio_set;
+ bdgpio->gpio.ngpio = 4;
+ bdgpio->gpio.base = -1;
+#ifdef CONFIG_OF_GPIO
+ bdgpio->gpio.of_node = pdev->dev.parent->of_node;
+#endif
+ bdgpio->chip.regmap = bd70528->regmap;
+
+ ret = devm_gpiochip_add_data(&pdev->dev, &bdgpio->gpio,
+ bdgpio);
+ if (ret)
+ dev_err(&pdev->dev, "gpio_init: Failed to add bd70528-gpio\n");
+
+ return ret;
+}
+
+static struct platform_driver bd70528_gpio = {
+ .driver = {
+ .name = "bd70528-gpio"
+ },
+ .probe = bd70528_probe,
+};
+
+module_platform_driver(bd70528_gpio);
+
+MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
+MODULE_DESCRIPTION("BD70528 voltage regulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-cs5535.c b/drivers/gpio/gpio-cs5535.c
index 6314225dbed0..53b24e3ae7de 100644
--- a/drivers/gpio/gpio-cs5535.c
+++ b/drivers/gpio/gpio-cs5535.c
@@ -41,7 +41,7 @@ MODULE_PARM_DESC(mask, "GPIO channel mask.");
/*
* FIXME: convert this singleton driver to use the state container
- * design pattern, see Documentation/driver-model/design-patterns.txt
+ * design pattern, see Documentation/driver-api/driver-model/design-patterns.rst
*/
static struct cs5535_gpio_chip {
struct gpio_chip chip;
diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c
index 3bbf5804bd11..e0b025689625 100644
--- a/drivers/gpio/gpio-davinci.c
+++ b/drivers/gpio/gpio-davinci.c
@@ -238,8 +238,9 @@ 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) {
- dev_info(dev, "IRQ not populated, err = %d\n",
- chips->irqs[i]);
+ if (chips->irqs[i] != -EPROBE_DEFER)
+ dev_info(dev, "IRQ not populated, err = %d\n",
+ chips->irqs[i]);
return chips->irqs[i];
}
}
@@ -297,7 +298,7 @@ static int davinci_gpio_probe(struct platform_device *pdev)
static void gpio_irq_disable(struct irq_data *d)
{
struct davinci_gpio_regs __iomem *g = irq2regs(d);
- u32 mask = (u32) irq_data_get_irq_handler_data(d);
+ uintptr_t mask = (uintptr_t)irq_data_get_irq_handler_data(d);
writel_relaxed(mask, &g->clr_falling);
writel_relaxed(mask, &g->clr_rising);
@@ -306,7 +307,7 @@ static void gpio_irq_disable(struct irq_data *d)
static void gpio_irq_enable(struct irq_data *d)
{
struct davinci_gpio_regs __iomem *g = irq2regs(d);
- u32 mask = (u32) irq_data_get_irq_handler_data(d);
+ uintptr_t mask = (uintptr_t)irq_data_get_irq_handler_data(d);
unsigned status = irqd_get_trigger_type(d);
status &= IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING;
@@ -447,7 +448,7 @@ davinci_gpio_irq_map(struct irq_domain *d, unsigned int irq,
"davinci_gpio");
irq_set_irq_type(irq, IRQ_TYPE_NONE);
irq_set_chip_data(irq, (__force void *)g);
- irq_set_handler_data(irq, (void *)__gpio_mask(hw));
+ irq_set_handler_data(irq, (void *)(uintptr_t)__gpio_mask(hw));
return 0;
}
@@ -632,6 +633,7 @@ done:
static const struct of_device_id davinci_gpio_ids[] = {
{ .compatible = "ti,keystone-gpio", keystone_gpio_get_irq_chip},
+ { .compatible = "ti,am654-gpio", keystone_gpio_get_irq_chip},
{ .compatible = "ti,dm6441-gpio", davinci_gpio_get_irq_chip},
{ /* sentinel */ },
};
diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c
index d3eda65fd6d3..3108be5e208c 100644
--- a/drivers/gpio/gpio-dwapb.c
+++ b/drivers/gpio/gpio-dwapb.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2011 Jamie Iles
*
- * 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.
- *
* All enquiries to support@picochip.com
*/
#include <linux/acpi.h>
diff --git a/drivers/gpio/gpio-eic-sprd.c b/drivers/gpio/gpio-eic-sprd.c
index 77092268ee95..7b9ac4a12c20 100644
--- a/drivers/gpio/gpio-eic-sprd.c
+++ b/drivers/gpio/gpio-eic-sprd.c
@@ -568,7 +568,6 @@ static int sprd_eic_probe(struct platform_device *pdev)
const struct sprd_eic_variant_data *pdata;
struct gpio_irq_chip *irq;
struct sprd_eic *sprd_eic;
- struct resource *res;
int ret, i;
pdata = of_device_get_match_data(&pdev->dev);
@@ -597,13 +596,9 @@ static int sprd_eic_probe(struct platform_device *pdev)
* have one bank EIC, thus base[1] and base[2] can be
* optional.
*/
- res = platform_get_resource(pdev, IORESOURCE_MEM, i);
- if (!res)
- continue;
-
- sprd_eic->base[i] = devm_ioremap_resource(&pdev->dev, res);
+ sprd_eic->base[i] = devm_platform_ioremap_resource(pdev, i);
if (IS_ERR(sprd_eic->base[i]))
- return PTR_ERR(sprd_eic->base[i]);
+ continue;
}
sprd_eic->chip.label = sprd_eic_label_name[sprd_eic->type];
diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c
index 84a7375cee0a..a87951293aaa 100644
--- a/drivers/gpio/gpio-em.c
+++ b/drivers/gpio/gpio-em.c
@@ -259,6 +259,13 @@ static const struct irq_domain_ops em_gio_irq_domain_ops = {
.xlate = irq_domain_xlate_twocell,
};
+static void em_gio_irq_domain_remove(void *data)
+{
+ struct irq_domain *domain = data;
+
+ irq_domain_remove(domain);
+}
+
static int em_gio_probe(struct platform_device *pdev)
{
struct em_gio_priv *p;
@@ -270,10 +277,8 @@ static int em_gio_probe(struct platform_device *pdev)
int ret;
p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
- if (!p) {
- ret = -ENOMEM;
- goto err0;
- }
+ if (!p)
+ return -ENOMEM;
p->pdev = pdev;
platform_set_drvdata(pdev, p);
@@ -286,30 +291,22 @@ static int em_gio_probe(struct platform_device *pdev)
if (!io[0] || !io[1] || !irq[0] || !irq[1]) {
dev_err(&pdev->dev, "missing IRQ or IOMEM\n");
- ret = -EINVAL;
- goto err0;
+ return -EINVAL;
}
p->base0 = devm_ioremap_nocache(&pdev->dev, io[0]->start,
resource_size(io[0]));
- if (!p->base0) {
- dev_err(&pdev->dev, "failed to remap low I/O memory\n");
- ret = -ENXIO;
- goto err0;
- }
+ if (!p->base0)
+ return -ENOMEM;
p->base1 = devm_ioremap_nocache(&pdev->dev, io[1]->start,
resource_size(io[1]));
- if (!p->base1) {
- dev_err(&pdev->dev, "failed to remap high I/O memory\n");
- ret = -ENXIO;
- goto err0;
- }
+ if (!p->base1)
+ return -ENOMEM;
if (of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpios)) {
dev_err(&pdev->dev, "Missing ngpios OF property\n");
- ret = -EINVAL;
- goto err0;
+ return -EINVAL;
}
gpio_chip = &p->gpio_chip;
@@ -339,47 +336,34 @@ static int em_gio_probe(struct platform_device *pdev)
p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, ngpios, 0,
&em_gio_irq_domain_ops, p);
if (!p->irq_domain) {
- ret = -ENXIO;
dev_err(&pdev->dev, "cannot initialize irq domain\n");
- goto err0;
+ return -ENXIO;
}
+ ret = devm_add_action_or_reset(&pdev->dev, em_gio_irq_domain_remove,
+ p->irq_domain);
+ if (ret)
+ return ret;
+
if (devm_request_irq(&pdev->dev, irq[0]->start,
em_gio_irq_handler, 0, name, p)) {
dev_err(&pdev->dev, "failed to request low IRQ\n");
- ret = -ENOENT;
- goto err1;
+ return -ENOENT;
}
if (devm_request_irq(&pdev->dev, irq[1]->start,
em_gio_irq_handler, 0, name, p)) {
dev_err(&pdev->dev, "failed to request high IRQ\n");
- ret = -ENOENT;
- goto err1;
+ return -ENOENT;
}
- ret = gpiochip_add_data(gpio_chip, p);
+ ret = devm_gpiochip_add_data(&pdev->dev, gpio_chip, p);
if (ret) {
dev_err(&pdev->dev, "failed to add GPIO controller\n");
- goto err1;
+ return ret;
}
return 0;
-
-err1:
- irq_domain_remove(p->irq_domain);
-err0:
- return ret;
-}
-
-static int em_gio_remove(struct platform_device *pdev)
-{
- struct em_gio_priv *p = platform_get_drvdata(pdev);
-
- gpiochip_remove(&p->gpio_chip);
-
- irq_domain_remove(p->irq_domain);
- return 0;
}
static const struct of_device_id em_gio_dt_ids[] = {
@@ -390,7 +374,6 @@ MODULE_DEVICE_TABLE(of, em_gio_dt_ids);
static struct platform_driver em_gio_device_driver = {
.probe = em_gio_probe,
- .remove = em_gio_remove,
.driver = {
.name = "em_gio",
.of_match_table = em_gio_dt_ids,
diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c
index 71728d6e0bca..a90870a60c15 100644
--- a/drivers/gpio/gpio-ep93xx.c
+++ b/drivers/gpio/gpio-ep93xx.c
@@ -393,16 +393,13 @@ static int ep93xx_gpio_add_bank(struct gpio_chip *gc, struct device *dev,
static int ep93xx_gpio_probe(struct platform_device *pdev)
{
struct ep93xx_gpio *epg;
- struct resource *res;
int i;
- struct device *dev = &pdev->dev;
- epg = devm_kzalloc(dev, sizeof(*epg), GFP_KERNEL);
+ epg = devm_kzalloc(&pdev->dev, sizeof(*epg), GFP_KERNEL);
if (!epg)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- epg->base = devm_ioremap_resource(dev, res);
+ epg->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(epg->base))
return PTR_ERR(epg->base);
diff --git a/drivers/gpio/gpio-exar.c b/drivers/gpio/gpio-exar.c
index a09d2f9ebacc..fae327d5b06e 100644
--- a/drivers/gpio/gpio-exar.c
+++ b/drivers/gpio/gpio-exar.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* GPIO driver for Exar XR17V35X chip
*
* Copyright (C) 2015 Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>
- *
- * 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.
*/
#include <linux/bitops.h>
#include <linux/device.h>
diff --git a/drivers/gpio/gpio-ftgpio010.c b/drivers/gpio/gpio-ftgpio010.c
index 8ff8ce2970d9..250e71f3e688 100644
--- a/drivers/gpio/gpio-ftgpio010.c
+++ b/drivers/gpio/gpio-ftgpio010.c
@@ -226,6 +226,7 @@ static int ftgpio_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ftgpio_gpio *g;
+ struct gpio_irq_chip *girq;
int irq;
int ret;
@@ -277,6 +278,24 @@ static int ftgpio_gpio_probe(struct platform_device *pdev)
if (!IS_ERR(g->clk))
g->gc.set_config = ftgpio_gpio_set_config;
+ g->irq.name = "FTGPIO010";
+ g->irq.irq_ack = ftgpio_gpio_ack_irq;
+ g->irq.irq_mask = ftgpio_gpio_mask_irq;
+ g->irq.irq_unmask = ftgpio_gpio_unmask_irq;
+ g->irq.irq_set_type = ftgpio_gpio_set_irq_type;
+
+ girq = &g->gc.irq;
+ girq->chip = &g->irq;
+ girq->parent_handler = ftgpio_gpio_irq_handler;
+ girq->num_parents = 1;
+ girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
+ GFP_KERNEL);
+ if (!girq->parents)
+ return -ENOMEM;
+ girq->default_type = IRQ_TYPE_NONE;
+ girq->handler = handle_bad_irq;
+ girq->parents[0] = irq;
+
ret = devm_gpiochip_add_data(dev, &g->gc, g);
if (ret)
goto dis_clk;
@@ -289,22 +308,6 @@ static int ftgpio_gpio_probe(struct platform_device *pdev)
/* Clear any use of debounce */
writel(0x0, g->base + GPIO_DEBOUNCE_EN);
- g->irq.name = "FTGPIO010";
- g->irq.irq_ack = ftgpio_gpio_ack_irq;
- g->irq.irq_mask = ftgpio_gpio_mask_irq;
- g->irq.irq_unmask = ftgpio_gpio_unmask_irq;
- g->irq.irq_set_type = ftgpio_gpio_set_irq_type;
-
- ret = gpiochip_irqchip_add(&g->gc, &g->irq,
- 0, handle_bad_irq,
- IRQ_TYPE_NONE);
- if (ret) {
- dev_info(dev, "could not add irqchip\n");
- goto dis_clk;
- }
- gpiochip_set_chained_irqchip(&g->gc, &g->irq,
- irq, ftgpio_gpio_irq_handler);
-
platform_set_drvdata(pdev, g);
dev_info(dev, "FTGPIO010 @%p registered\n", g->base);
diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c
index 7df48e76baea..0937b605e134 100644
--- a/drivers/gpio/gpio-grgpio.c
+++ b/drivers/gpio/gpio-grgpio.c
@@ -329,7 +329,6 @@ static int grgpio_probe(struct platform_device *ofdev)
void __iomem *regs;
struct gpio_chip *gc;
struct grgpio_priv *priv;
- struct resource *res;
int err;
u32 prop;
s32 *irqmap;
@@ -340,8 +339,7 @@ static int grgpio_probe(struct platform_device *ofdev)
if (!priv)
return -ENOMEM;
- res = platform_get_resource(ofdev, IORESOURCE_MEM, 0);
- regs = devm_ioremap_resource(&ofdev->dev, res);
+ regs = devm_platform_ioremap_resource(ofdev, 0);
if (IS_ERR(regs))
return PTR_ERR(regs);
diff --git a/drivers/gpio/gpio-iop.c b/drivers/gpio/gpio-iop.c
index e355c5961eb9..7390b5ca09e3 100644
--- a/drivers/gpio/gpio-iop.c
+++ b/drivers/gpio/gpio-iop.c
@@ -36,6 +36,7 @@ static int iop3xx_gpio_probe(struct platform_device *pdev)
gc->base = 0;
gc->owner = THIS_MODULE;
+ gc->label = "gpio-iop";
return devm_gpiochip_add_data(&pdev->dev, gc, NULL);
}
diff --git a/drivers/gpio/gpio-ixp4xx.c b/drivers/gpio/gpio-ixp4xx.c
index 4b1cf7ea858d..670c2a85a35b 100644
--- a/drivers/gpio/gpio-ixp4xx.c
+++ b/drivers/gpio/gpio-ixp4xx.c
@@ -205,20 +205,20 @@ static int ixp4xx_gpio_irq_domain_translate(struct irq_domain *domain,
unsigned long *hwirq,
unsigned int *type)
{
+ int ret;
/* We support standard DT translation */
if (is_of_node(fwspec->fwnode) && fwspec->param_count == 2) {
- *hwirq = fwspec->param[0];
- *type = fwspec->param[1];
- return 0;
+ return irq_domain_translate_twocell(domain, fwspec,
+ hwirq, type);
}
/* This goes away when we transition to DT */
if (is_fwnode_irqchip(fwspec->fwnode)) {
- if (fwspec->param_count != 2)
- return -EINVAL;
- *hwirq = fwspec->param[0];
- *type = fwspec->param[1];
+ ret = irq_domain_translate_twocell(domain, fwspec,
+ hwirq, type);
+ if (ret)
+ return ret;
WARN_ON(*type == IRQ_TYPE_NONE);
return 0;
}
diff --git a/drivers/gpio/gpio-janz-ttl.c b/drivers/gpio/gpio-janz-ttl.c
index 6b5b5a8b9173..cdf50e4ea165 100644
--- a/drivers/gpio/gpio-janz-ttl.c
+++ b/drivers/gpio/gpio-janz-ttl.c
@@ -140,18 +140,17 @@ static void ttl_setup_device(struct ttl_module *mod)
static int ttl_probe(struct platform_device *pdev)
{
struct janz_platform_data *pdata;
- struct device *dev = &pdev->dev;
struct ttl_module *mod;
struct gpio_chip *gpio;
int ret;
pdata = dev_get_platdata(&pdev->dev);
if (!pdata) {
- dev_err(dev, "no platform data\n");
+ dev_err(&pdev->dev, "no platform data\n");
return -ENXIO;
}
- mod = devm_kzalloc(dev, sizeof(*mod), GFP_KERNEL);
+ mod = devm_kzalloc(&pdev->dev, sizeof(*mod), GFP_KERNEL);
if (!mod)
return -ENOMEM;
@@ -177,9 +176,9 @@ static int ttl_probe(struct platform_device *pdev)
gpio->base = -1;
gpio->ngpio = 20;
- ret = devm_gpiochip_add_data(dev, gpio, NULL);
+ ret = devm_gpiochip_add_data(&pdev->dev, gpio, NULL);
if (ret) {
- dev_err(dev, "unable to add GPIO chip\n");
+ dev_err(&pdev->dev, "unable to add GPIO chip\n");
return ret;
}
diff --git a/drivers/gpio/gpio-madera.c b/drivers/gpio/gpio-madera.c
index c9dad0543672..4dbc837d1215 100644
--- a/drivers/gpio/gpio-madera.c
+++ b/drivers/gpio/gpio-madera.c
@@ -1,12 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* GPIO support for Cirrus Logic Madera codecs
*
* Copyright (C) 2015-2018 Cirrus Logic
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by the
- * Free Software Foundation; version 2.
*/
#include <linux/gpio/driver.h>
diff --git a/drivers/gpio/gpio-max3191x.c b/drivers/gpio/gpio-max3191x.c
index 9a8876abeb57..4b4b2ceb82fc 100644
--- a/drivers/gpio/gpio-max3191x.c
+++ b/drivers/gpio/gpio-max3191x.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* gpio-max3191x.c - GPIO driver for Maxim MAX3191x industrial serializer
*
@@ -27,10 +28,6 @@
* https://datasheets.maximintegrated.com/en/ds/MAX31912.pdf
* https://datasheets.maximintegrated.com/en/ds/MAX31913.pdf
* https://datasheets.maximintegrated.com/en/ds/MAX31953-MAX31963.pdf
- *
- * 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.
*/
#include <linux/bitmap.h>
diff --git a/drivers/gpio/gpio-max7300.c b/drivers/gpio/gpio-max7300.c
index 1ae9ba851c9a..19cc2ed6a3f5 100644
--- a/drivers/gpio/gpio-max7300.c
+++ b/drivers/gpio/gpio-max7300.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2009 Wolfram Sang, Pengutronix
*
- * 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.
- *
* Check max730x.c for further details.
*/
diff --git a/drivers/gpio/gpio-max7301.c b/drivers/gpio/gpio-max7301.c
index 647dfbbc4e1c..1307c243b4e9 100644
--- a/drivers/gpio/gpio-max7301.c
+++ b/drivers/gpio/gpio-max7301.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2006 Juergen Beisert, Pengutronix
* Copyright (C) 2008 Guennadi Liakhovetski, Pengutronix
* Copyright (C) 2009 Wolfram Sang, Pengutronix
*
- * 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.
- *
* Check max730x.c for further details.
*/
diff --git a/drivers/gpio/gpio-max730x.c b/drivers/gpio/gpio-max730x.c
index 198a36b07773..1e1935c51096 100644
--- a/drivers/gpio/gpio-max730x.c
+++ b/drivers/gpio/gpio-max730x.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/**
* Copyright (C) 2006 Juergen Beisert, Pengutronix
* Copyright (C) 2008 Guennadi Liakhovetski, Pengutronix
* Copyright (C) 2009 Wolfram Sang, Pengutronix
*
- * 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.
- *
* The Maxim MAX7300/1 device is an I2C/SPI driven GPIO expander. There are
* 28 GPIOs. 8 of them can trigger an interrupt. See datasheet for more
* details
diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c
index 5e4102e7b1f9..5fb0bcf31142 100644
--- a/drivers/gpio/gpio-max732x.c
+++ b/drivers/gpio/gpio-max732x.c
@@ -649,12 +649,12 @@ static int max732x_probe(struct i2c_client *client,
case 0x60:
chip->client_group_a = client;
if (nr_port > 8) {
- c = i2c_new_dummy(client->adapter, addr_b);
- if (!c) {
+ c = devm_i2c_new_dummy_device(&client->dev,
+ client->adapter, addr_b);
+ if (IS_ERR(c)) {
dev_err(&client->dev,
"Failed to allocate I2C device\n");
- ret = -ENODEV;
- goto out_failed;
+ return PTR_ERR(c);
}
chip->client_group_b = chip->client_dummy = c;
}
@@ -662,12 +662,12 @@ static int max732x_probe(struct i2c_client *client,
case 0x50:
chip->client_group_b = client;
if (nr_port > 8) {
- c = i2c_new_dummy(client->adapter, addr_a);
- if (!c) {
+ c = devm_i2c_new_dummy_device(&client->dev,
+ client->adapter, addr_a);
+ if (IS_ERR(c)) {
dev_err(&client->dev,
"Failed to allocate I2C device\n");
- ret = -ENODEV;
- goto out_failed;
+ return PTR_ERR(c);
}
chip->client_group_a = chip->client_dummy = c;
}
@@ -675,37 +675,33 @@ static int max732x_probe(struct i2c_client *client,
default:
dev_err(&client->dev, "invalid I2C address specified %02x\n",
client->addr);
- ret = -EINVAL;
- goto out_failed;
+ return -EINVAL;
}
if (nr_port > 8 && !chip->client_dummy) {
dev_err(&client->dev,
"Failed to allocate second group I2C device\n");
- ret = -ENODEV;
- goto out_failed;
+ return -ENODEV;
}
mutex_init(&chip->lock);
ret = max732x_readb(chip, is_group_a(chip, 0), &chip->reg_out[0]);
if (ret)
- goto out_failed;
+ return ret;
if (nr_port > 8) {
ret = max732x_readb(chip, is_group_a(chip, 8), &chip->reg_out[1]);
if (ret)
- goto out_failed;
+ return ret;
}
- ret = gpiochip_add_data(&chip->gpio_chip, chip);
+ ret = devm_gpiochip_add_data(&client->dev, &chip->gpio_chip, chip);
if (ret)
- goto out_failed;
+ return ret;
ret = max732x_irq_setup(chip, id);
- if (ret) {
- gpiochip_remove(&chip->gpio_chip);
- goto out_failed;
- }
+ if (ret)
+ return ret;
if (pdata && pdata->setup) {
ret = pdata->setup(client, chip->gpio_chip.base,
@@ -716,10 +712,6 @@ static int max732x_probe(struct i2c_client *client,
i2c_set_clientdata(client, chip);
return 0;
-
-out_failed:
- i2c_unregister_device(chip->client_dummy);
- return ret;
}
static int max732x_remove(struct i2c_client *client)
@@ -739,11 +731,6 @@ static int max732x_remove(struct i2c_client *client)
}
}
- gpiochip_remove(&chip->gpio_chip);
-
- /* unregister any dummy i2c_client */
- i2c_unregister_device(chip->client_dummy);
-
return 0;
}
diff --git a/drivers/gpio/gpio-mb86s7x.c b/drivers/gpio/gpio-mb86s7x.c
index 9bfff171f9fe..8f466993cd24 100644
--- a/drivers/gpio/gpio-mb86s7x.c
+++ b/drivers/gpio/gpio-mb86s7x.c
@@ -6,6 +6,7 @@
* Copyright (C) 2015 Linaro Ltd.
*/
+#include <linux/acpi.h>
#include <linux/io.h>
#include <linux/init.h>
#include <linux/clk.h>
@@ -19,6 +20,8 @@
#include <linux/spinlock.h>
#include <linux/slab.h>
+#include "gpiolib.h"
+
/*
* Only first 8bits of a register correspond to each pin,
* so there are 4 registers for 32 pins.
@@ -135,6 +138,20 @@ static void mb86s70_gpio_set(struct gpio_chip *gc, unsigned gpio, int value)
spin_unlock_irqrestore(&gchip->lock, flags);
}
+static int mb86s70_gpio_to_irq(struct gpio_chip *gc, unsigned int offset)
+{
+ int irq, index;
+
+ for (index = 0;; index++) {
+ irq = platform_get_irq(to_platform_device(gc->parent), index);
+ if (irq <= 0)
+ break;
+ if (irq_get_irq_data(irq)->hwirq == offset)
+ return irq;
+ }
+ return -EINVAL;
+}
+
static int mb86s70_gpio_probe(struct platform_device *pdev)
{
struct mb86s70_gpio_chip *gchip;
@@ -150,13 +167,15 @@ static int mb86s70_gpio_probe(struct platform_device *pdev)
if (IS_ERR(gchip->base))
return PTR_ERR(gchip->base);
- gchip->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(gchip->clk))
- return PTR_ERR(gchip->clk);
+ if (!has_acpi_companion(&pdev->dev)) {
+ gchip->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(gchip->clk))
+ return PTR_ERR(gchip->clk);
- ret = clk_prepare_enable(gchip->clk);
- if (ret)
- return ret;
+ ret = clk_prepare_enable(gchip->clk);
+ if (ret)
+ return ret;
+ }
spin_lock_init(&gchip->lock);
@@ -172,19 +191,28 @@ static int mb86s70_gpio_probe(struct platform_device *pdev)
gchip->gc.parent = &pdev->dev;
gchip->gc.base = -1;
+ if (has_acpi_companion(&pdev->dev))
+ gchip->gc.to_irq = mb86s70_gpio_to_irq;
+
ret = gpiochip_add_data(&gchip->gc, gchip);
if (ret) {
dev_err(&pdev->dev, "couldn't register gpio driver\n");
clk_disable_unprepare(gchip->clk);
+ return ret;
}
- return ret;
+ if (has_acpi_companion(&pdev->dev))
+ acpi_gpiochip_request_interrupts(&gchip->gc);
+
+ return 0;
}
static int mb86s70_gpio_remove(struct platform_device *pdev)
{
struct mb86s70_gpio_chip *gchip = platform_get_drvdata(pdev);
+ if (has_acpi_companion(&pdev->dev))
+ acpi_gpiochip_free_interrupts(&gchip->gc);
gpiochip_remove(&gchip->gc);
clk_disable_unprepare(gchip->clk);
@@ -197,10 +225,19 @@ static const struct of_device_id mb86s70_gpio_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, mb86s70_gpio_dt_ids);
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id mb86s70_gpio_acpi_ids[] = {
+ { "SCX0007" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(acpi, mb86s70_gpio_acpi_ids);
+#endif
+
static struct platform_driver mb86s70_gpio_driver = {
.driver = {
.name = "mb86s70-gpio",
.of_match_table = mb86s70_gpio_dt_ids,
+ .acpi_match_table = ACPI_PTR(mb86s70_gpio_acpi_ids),
},
.probe = mb86s70_gpio_probe,
.remove = mb86s70_gpio_remove,
diff --git a/drivers/gpio/gpio-mm-lantiq.c b/drivers/gpio/gpio-mm-lantiq.c
index b0754fe69e77..f460d71b0c92 100644
--- a/drivers/gpio/gpio-mm-lantiq.c
+++ b/drivers/gpio/gpio-mm-lantiq.c
@@ -1,7 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
- * 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.
*
* Copyright (C) 2012 John Crispin <john@phrozen.org>
*/
diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c
index b6a4efce7c92..f1a9c0544e3f 100644
--- a/drivers/gpio/gpio-mockup.c
+++ b/drivers/gpio/gpio-mockup.c
@@ -315,7 +315,6 @@ static void gpio_mockup_debugfs_setup(struct device *dev,
struct gpio_mockup_chip *chip)
{
struct gpio_mockup_dbgfs_private *priv;
- struct dentry *evfile;
struct gpio_chip *gc;
const char *devname;
char *name;
@@ -325,32 +324,25 @@ static void gpio_mockup_debugfs_setup(struct device *dev,
devname = dev_name(&gc->gpiodev->dev);
chip->dbg_dir = debugfs_create_dir(devname, gpio_mockup_dbg_dir);
- if (IS_ERR_OR_NULL(chip->dbg_dir))
- goto err;
for (i = 0; i < gc->ngpio; i++) {
name = devm_kasprintf(dev, GFP_KERNEL, "%d", i);
if (!name)
- goto err;
+ return;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
- goto err;
+ return;
priv->chip = chip;
priv->offset = i;
priv->desc = &gc->gpiodev->descs[i];
- evfile = debugfs_create_file(name, 0200, chip->dbg_dir, priv,
- &gpio_mockup_debugfs_ops);
- if (IS_ERR_OR_NULL(evfile))
- goto err;
+ debugfs_create_file(name, 0200, chip->dbg_dir, priv,
+ &gpio_mockup_debugfs_ops);
}
return;
-
-err:
- dev_err(dev, "error creating debugfs files\n");
}
static int gpio_mockup_name_lines(struct device *dev,
@@ -447,8 +439,7 @@ static int gpio_mockup_probe(struct platform_device *pdev)
if (rv)
return rv;
- if (!IS_ERR_OR_NULL(gpio_mockup_dbg_dir))
- gpio_mockup_debugfs_setup(dev, chip);
+ gpio_mockup_debugfs_setup(dev, chip);
return 0;
}
@@ -501,8 +492,6 @@ static int __init gpio_mockup_init(void)
}
gpio_mockup_dbg_dir = debugfs_create_dir("gpio-mockup", NULL);
- if (IS_ERR_OR_NULL(gpio_mockup_dbg_dir))
- gpio_mockup_err("error creating debugfs directory\n");
err = platform_driver_register(&gpio_mockup_driver);
if (err) {
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
index 059094ac44cb..869d47f89599 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -38,6 +38,7 @@
#include <linux/err.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/consumer.h>
+#include <linux/gpio/machine.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/irq.h>
@@ -618,18 +619,14 @@ static int mvebu_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
ret = -EBUSY;
} else {
desc = gpiochip_request_own_desc(&mvchip->chip,
- pwm->hwpwm, "mvebu-pwm", 0);
+ pwm->hwpwm, "mvebu-pwm",
+ GPIO_ACTIVE_HIGH,
+ GPIOD_OUT_LOW);
if (IS_ERR(desc)) {
ret = PTR_ERR(desc);
goto out;
}
- ret = gpiod_direction_output(desc, 0);
- if (ret) {
- gpiochip_free_own_desc(desc);
- goto out;
- }
-
mvpwm->gpiod = desc;
}
out:
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index 16289bafa001..d0f27084a942 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Support functions for OMAP GPIO
*
@@ -6,10 +7,6 @@
*
* Copyright (C) 2009 Texas Instruments
* Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
- *
- * 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.
*/
#include <linux/init.h>
@@ -47,8 +44,9 @@ struct gpio_regs {
};
struct gpio_bank {
- struct list_head node;
void __iomem *base;
+ const struct omap_gpio_reg_offs *regs;
+
int irq;
u32 non_wakeup_gpios;
u32 enabled_non_wakeup_gpios;
@@ -75,11 +73,7 @@ struct gpio_bank {
int context_loss_count;
void (*set_dataout)(struct gpio_bank *bank, unsigned gpio, int enable);
- void (*set_dataout_multiple)(struct gpio_bank *bank,
- unsigned long *mask, unsigned long *bits);
int (*get_context_loss_count)(struct device *dev);
-
- struct omap_gpio_reg_offs *regs;
};
#define GPIO_MOD_CTRL_BIT BIT(0)
@@ -95,20 +89,25 @@ static inline struct gpio_bank *omap_irq_data_get_bank(struct irq_data *d)
return gpiochip_get_data(chip);
}
-static void omap_set_gpio_direction(struct gpio_bank *bank, int gpio,
- int is_input)
+static inline u32 omap_gpio_rmw(void __iomem *reg, u32 mask, bool set)
{
- void __iomem *reg = bank->base;
- u32 l;
+ u32 val = readl_relaxed(reg);
- reg += bank->regs->direction;
- l = readl_relaxed(reg);
- if (is_input)
- l |= BIT(gpio);
+ if (set)
+ val |= mask;
else
- l &= ~(BIT(gpio));
- writel_relaxed(l, reg);
- bank->context.oe = l;
+ val &= ~mask;
+
+ writel_relaxed(val, reg);
+
+ return val;
+}
+
+static void omap_set_gpio_direction(struct gpio_bank *bank, int gpio,
+ int is_input)
+{
+ bank->context.oe = omap_gpio_rmw(bank->base + bank->regs->direction,
+ BIT(gpio), is_input);
}
@@ -134,88 +133,8 @@ static void omap_set_gpio_dataout_reg(struct gpio_bank *bank, unsigned offset,
static void omap_set_gpio_dataout_mask(struct gpio_bank *bank, unsigned offset,
int enable)
{
- void __iomem *reg = bank->base + bank->regs->dataout;
- u32 gpio_bit = BIT(offset);
- u32 l;
-
- l = readl_relaxed(reg);
- if (enable)
- l |= gpio_bit;
- else
- l &= ~gpio_bit;
- writel_relaxed(l, reg);
- bank->context.dataout = l;
-}
-
-static int omap_get_gpio_datain(struct gpio_bank *bank, int offset)
-{
- void __iomem *reg = bank->base + bank->regs->datain;
-
- return (readl_relaxed(reg) & (BIT(offset))) != 0;
-}
-
-static int omap_get_gpio_dataout(struct gpio_bank *bank, int offset)
-{
- void __iomem *reg = bank->base + bank->regs->dataout;
-
- return (readl_relaxed(reg) & (BIT(offset))) != 0;
-}
-
-/* set multiple data out values using dedicate set/clear register */
-static void omap_set_gpio_dataout_reg_multiple(struct gpio_bank *bank,
- unsigned long *mask,
- unsigned long *bits)
-{
- void __iomem *reg = bank->base;
- u32 l;
-
- l = *bits & *mask;
- writel_relaxed(l, reg + bank->regs->set_dataout);
- bank->context.dataout |= l;
-
- l = ~*bits & *mask;
- writel_relaxed(l, reg + bank->regs->clr_dataout);
- bank->context.dataout &= ~l;
-}
-
-/* set multiple data out values using mask register */
-static void omap_set_gpio_dataout_mask_multiple(struct gpio_bank *bank,
- unsigned long *mask,
- unsigned long *bits)
-{
- void __iomem *reg = bank->base + bank->regs->dataout;
- u32 l = (readl_relaxed(reg) & ~*mask) | (*bits & *mask);
-
- writel_relaxed(l, reg);
- bank->context.dataout = l;
-}
-
-static unsigned long omap_get_gpio_datain_multiple(struct gpio_bank *bank,
- unsigned long *mask)
-{
- void __iomem *reg = bank->base + bank->regs->datain;
-
- return readl_relaxed(reg) & *mask;
-}
-
-static unsigned long omap_get_gpio_dataout_multiple(struct gpio_bank *bank,
- unsigned long *mask)
-{
- void __iomem *reg = bank->base + bank->regs->dataout;
-
- return readl_relaxed(reg) & *mask;
-}
-
-static inline void omap_gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set)
-{
- int l = readl_relaxed(base + reg);
-
- if (set)
- l |= mask;
- else
- l &= ~mask;
-
- writel_relaxed(l, base + reg);
+ bank->context.dataout = omap_gpio_rmw(bank->base + bank->regs->dataout,
+ BIT(offset), enable);
}
static inline void omap_gpio_dbck_enable(struct gpio_bank *bank)
@@ -259,7 +178,6 @@ static inline void omap_gpio_dbck_disable(struct gpio_bank *bank)
static int omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset,
unsigned debounce)
{
- void __iomem *reg;
u32 val;
u32 l;
bool enable = !!debounce;
@@ -276,19 +194,11 @@ static int omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset,
l = BIT(offset);
clk_enable(bank->dbck);
- reg = bank->base + bank->regs->debounce;
- writel_relaxed(debounce, reg);
+ writel_relaxed(debounce, bank->base + bank->regs->debounce);
- reg = bank->base + bank->regs->debounce_en;
- val = readl_relaxed(reg);
-
- if (enable)
- val |= l;
- else
- val &= ~l;
+ val = omap_gpio_rmw(bank->base + bank->regs->debounce_en, l, enable);
bank->dbck_enable_mask = val;
- writel_relaxed(val, reg);
clk_disable(bank->dbck);
/*
* Enable debounce clock per module.
@@ -363,9 +273,9 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio,
void __iomem *base = bank->base;
u32 gpio_bit = BIT(gpio);
- omap_gpio_rmw(base, bank->regs->leveldetect0, gpio_bit,
+ omap_gpio_rmw(base + bank->regs->leveldetect0, gpio_bit,
trigger & IRQ_TYPE_LEVEL_LOW);
- omap_gpio_rmw(base, bank->regs->leveldetect1, gpio_bit,
+ omap_gpio_rmw(base + bank->regs->leveldetect1, gpio_bit,
trigger & IRQ_TYPE_LEVEL_HIGH);
/*
@@ -373,9 +283,9 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio,
* to be woken from idle state. Set the appropriate edge detection
* in addition to the level detection.
*/
- omap_gpio_rmw(base, bank->regs->risingdetect, gpio_bit,
+ omap_gpio_rmw(base + bank->regs->risingdetect, gpio_bit,
trigger & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH));
- omap_gpio_rmw(base, bank->regs->fallingdetect, gpio_bit,
+ omap_gpio_rmw(base + bank->regs->fallingdetect, gpio_bit,
trigger & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW));
bank->context.leveldetect0 =
@@ -387,11 +297,8 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio,
bank->context.fallingdetect =
readl_relaxed(bank->base + bank->regs->fallingdetect);
- if (likely(!(bank->non_wakeup_gpios & gpio_bit))) {
- omap_gpio_rmw(base, bank->regs->wkup_en, gpio_bit, trigger != 0);
- bank->context.wake_en =
- readl_relaxed(bank->base + bank->regs->wkup_en);
- }
+ bank->level_mask = bank->context.leveldetect0 |
+ bank->context.leveldetect1;
/* This part needs to be executed always for OMAP{34xx, 44xx} */
if (!bank->regs->irqctrl && !omap_gpio_is_off_wakeup_capable(bank, gpio)) {
@@ -406,44 +313,25 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio,
else
bank->enabled_non_wakeup_gpios &= ~gpio_bit;
}
-
- bank->level_mask =
- readl_relaxed(bank->base + bank->regs->leveldetect0) |
- readl_relaxed(bank->base + bank->regs->leveldetect1);
}
-#ifdef CONFIG_ARCH_OMAP1
/*
* This only applies to chips that can't do both rising and falling edge
* detection at once. For all other chips, this function is a noop.
*/
static void omap_toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio)
{
- void __iomem *reg = bank->base;
- u32 l = 0;
-
- if (!bank->regs->irqctrl)
- return;
+ if (IS_ENABLED(CONFIG_ARCH_OMAP1) && bank->regs->irqctrl) {
+ void __iomem *reg = bank->base + bank->regs->irqctrl;
- reg += bank->regs->irqctrl;
-
- l = readl_relaxed(reg);
- if ((l >> gpio) & 1)
- l &= ~(BIT(gpio));
- else
- l |= BIT(gpio);
-
- writel_relaxed(l, reg);
+ writel_relaxed(readl_relaxed(reg) ^ BIT(gpio), reg);
+ }
}
-#else
-static void omap_toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) {}
-#endif
static int omap_set_gpio_triggering(struct gpio_bank *bank, int gpio,
unsigned trigger)
{
void __iomem *reg = bank->base;
- void __iomem *base = bank->base;
u32 l = 0;
if (bank->regs->leveldetect0 && bank->regs->wkup_en) {
@@ -475,11 +363,6 @@ static int omap_set_gpio_triggering(struct gpio_bank *bank, int gpio,
l |= 2 << (gpio << 1);
if (trigger & IRQ_TYPE_EDGE_FALLING)
l |= BIT(gpio << 1);
-
- /* Enable wake-up during idle for dynamic tick */
- omap_gpio_rmw(base, bank->regs->wkup_en, BIT(gpio), trigger);
- bank->context.wake_en =
- readl_relaxed(bank->base + bank->regs->wkup_en);
writel_relaxed(l, reg);
}
return 0;
@@ -508,17 +391,6 @@ static void omap_enable_gpio_module(struct gpio_bank *bank, unsigned offset)
static void omap_disable_gpio_module(struct gpio_bank *bank, unsigned offset)
{
- void __iomem *base = bank->base;
-
- if (bank->regs->wkup_en &&
- !LINE_USED(bank->mod_usage, offset) &&
- !LINE_USED(bank->irq_usage, offset)) {
- /* Disable wake-up during idle for dynamic tick */
- omap_gpio_rmw(base, bank->regs->wkup_en, BIT(offset), 0);
- bank->context.wake_en =
- readl_relaxed(bank->base + bank->regs->wkup_en);
- }
-
if (bank->regs->ctrl && !BANK_USED(bank)) {
void __iomem *reg = bank->base + bank->regs->ctrl;
u32 ctrl;
@@ -629,57 +501,39 @@ static u32 omap_get_gpio_irqbank_mask(struct gpio_bank *bank)
return l;
}
-static void omap_enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
+static inline void omap_set_gpio_irqenable(struct gpio_bank *bank,
+ unsigned offset, int enable)
{
void __iomem *reg = bank->base;
- u32 l;
+ u32 gpio_mask = BIT(offset);
- if (bank->regs->set_irqenable) {
- reg += bank->regs->set_irqenable;
- l = gpio_mask;
- bank->context.irqenable1 |= gpio_mask;
+ if (bank->regs->set_irqenable && bank->regs->clr_irqenable) {
+ if (enable) {
+ reg += bank->regs->set_irqenable;
+ bank->context.irqenable1 |= gpio_mask;
+ } else {
+ reg += bank->regs->clr_irqenable;
+ bank->context.irqenable1 &= ~gpio_mask;
+ }
+ writel_relaxed(gpio_mask, reg);
} else {
- reg += bank->regs->irqenable;
- l = readl_relaxed(reg);
- if (bank->regs->irqenable_inv)
- l &= ~gpio_mask;
- else
- l |= gpio_mask;
- bank->context.irqenable1 = l;
+ bank->context.irqenable1 =
+ omap_gpio_rmw(reg + bank->regs->irqenable, gpio_mask,
+ enable ^ bank->regs->irqenable_inv);
}
- writel_relaxed(l, reg);
-}
-
-static void omap_disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
-{
- void __iomem *reg = bank->base;
- u32 l;
-
- if (bank->regs->clr_irqenable) {
- reg += bank->regs->clr_irqenable;
- l = gpio_mask;
- bank->context.irqenable1 &= ~gpio_mask;
- } else {
- reg += bank->regs->irqenable;
- l = readl_relaxed(reg);
- if (bank->regs->irqenable_inv)
- l |= gpio_mask;
- else
- l &= ~gpio_mask;
- bank->context.irqenable1 = l;
+ /*
+ * Program GPIO wakeup along with IRQ enable to satisfy OMAP4430 TRM
+ * note requiring correlation between the IRQ enable registers and
+ * the wakeup registers. In any case, we want wakeup from idle
+ * enabled for the GPIOs which support this feature.
+ */
+ if (bank->regs->wkup_en &&
+ (bank->regs->edgectrl1 || !(bank->non_wakeup_gpios & gpio_mask))) {
+ bank->context.wake_en =
+ omap_gpio_rmw(bank->base + bank->regs->wkup_en,
+ gpio_mask, enable);
}
-
- writel_relaxed(l, reg);
-}
-
-static inline void omap_set_gpio_irqenable(struct gpio_bank *bank,
- unsigned offset, int enable)
-{
- if (enable)
- omap_enable_gpio_irqbank(bank, BIT(offset));
- else
- omap_disable_gpio_irqbank(bank, BIT(offset));
}
/* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
@@ -690,38 +544,6 @@ static int omap_gpio_wake_enable(struct irq_data *d, unsigned int enable)
return irq_set_irq_wake(bank->irq, enable);
}
-static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
-{
- struct gpio_bank *bank = gpiochip_get_data(chip);
- unsigned long flags;
-
- pm_runtime_get_sync(chip->parent);
-
- raw_spin_lock_irqsave(&bank->lock, flags);
- omap_enable_gpio_module(bank, offset);
- bank->mod_usage |= BIT(offset);
- raw_spin_unlock_irqrestore(&bank->lock, flags);
-
- return 0;
-}
-
-static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
-{
- struct gpio_bank *bank = gpiochip_get_data(chip);
- unsigned long flags;
-
- raw_spin_lock_irqsave(&bank->lock, flags);
- bank->mod_usage &= ~(BIT(offset));
- if (!LINE_USED(bank->irq_usage, offset)) {
- omap_set_gpio_direction(bank, offset, 1);
- omap_clear_gpio_debounce(bank, offset);
- }
- omap_disable_gpio_module(bank, offset);
- raw_spin_unlock_irqrestore(&bank->lock, flags);
-
- pm_runtime_put(chip->parent);
-}
-
/*
* We need to unmask the GPIO bank interrupt as soon as possible to
* avoid missing GPIO interrupts for other lines in the bank.
@@ -734,7 +556,7 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
{
void __iomem *isr_reg = NULL;
- u32 enabled, isr, level_mask;
+ u32 enabled, isr, edge;
unsigned int bit;
struct gpio_bank *bank = gpiobank;
unsigned long wa_lock_flags;
@@ -754,16 +576,14 @@ static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
enabled = omap_get_gpio_irqbank_mask(bank);
isr = readl_relaxed(isr_reg) & enabled;
- if (bank->level_mask)
- level_mask = bank->level_mask & enabled;
- else
- level_mask = 0;
-
- /* clear edge sensitive interrupts before handler(s) are
- called so that we don't miss any interrupt occurred while
- executing them */
- if (isr & ~level_mask)
- omap_clear_gpio_irqbank(bank, isr & ~level_mask);
+ /*
+ * Clear edge sensitive interrupts before calling handler(s)
+ * so subsequent edge transitions are not missed while the
+ * handlers are running.
+ */
+ edge = isr & ~bank->level_mask;
+ if (edge)
+ omap_clear_gpio_irqbank(bank, edge);
raw_spin_unlock_irqrestore(&bank->lock, lock_flags);
@@ -810,8 +630,6 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d)
if (!LINE_USED(bank->mod_usage, offset))
omap_set_gpio_direction(bank, offset, 1);
- else if (!omap_gpio_is_input(bank, offset))
- goto err;
omap_enable_gpio_module(bank, offset);
bank->irq_usage |= BIT(offset);
@@ -819,9 +637,6 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d)
omap_gpio_unmask_irq(d);
return 0;
-err:
- raw_spin_unlock_irqrestore(&bank->lock, flags);
- return -EINVAL;
}
static void omap_gpio_irq_shutdown(struct irq_data *d)
@@ -832,9 +647,9 @@ static void omap_gpio_irq_shutdown(struct irq_data *d)
raw_spin_lock_irqsave(&bank->lock, flags);
bank->irq_usage &= ~(BIT(offset));
- omap_set_gpio_irqenable(bank, offset, 0);
- omap_clear_gpio_irqstatus(bank, offset);
omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
+ omap_clear_gpio_irqstatus(bank, offset);
+ omap_set_gpio_irqenable(bank, offset, 0);
if (!LINE_USED(bank->mod_usage, offset))
omap_clear_gpio_debounce(bank, offset);
omap_disable_gpio_module(bank, offset);
@@ -855,14 +670,6 @@ static void gpio_irq_bus_sync_unlock(struct irq_data *data)
pm_runtime_put(bank->chip.parent);
}
-static void omap_gpio_ack_irq(struct irq_data *d)
-{
- struct gpio_bank *bank = omap_irq_data_get_bank(d);
- unsigned offset = d->hwirq;
-
- omap_clear_gpio_irqstatus(bank, offset);
-}
-
static void omap_gpio_mask_irq(struct irq_data *d)
{
struct gpio_bank *bank = omap_irq_data_get_bank(d);
@@ -870,8 +677,8 @@ static void omap_gpio_mask_irq(struct irq_data *d)
unsigned long flags;
raw_spin_lock_irqsave(&bank->lock, flags);
- omap_set_gpio_irqenable(bank, offset, 0);
omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
+ omap_set_gpio_irqenable(bank, offset, 0);
raw_spin_unlock_irqrestore(&bank->lock, flags);
}
@@ -883,9 +690,6 @@ static void omap_gpio_unmask_irq(struct irq_data *d)
unsigned long flags;
raw_spin_lock_irqsave(&bank->lock, flags);
- if (trigger)
- omap_set_gpio_triggering(bank, offset, trigger);
-
omap_set_gpio_irqenable(bank, offset, 1);
/*
@@ -893,9 +697,13 @@ static void omap_gpio_unmask_irq(struct irq_data *d)
* is cleared, thus after the handler has run. OMAP4 needs this done
* after enabing the interrupt to clear the wakeup status.
*/
- if (bank->level_mask & BIT(offset))
+ if (bank->regs->leveldetect0 && bank->regs->wkup_en &&
+ trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
omap_clear_gpio_irqstatus(bank, offset);
+ if (trigger)
+ omap_set_gpio_triggering(bank, offset, trigger);
+
raw_spin_unlock_irqrestore(&bank->lock, flags);
}
@@ -961,19 +769,44 @@ static inline void omap_mpuio_init(struct gpio_bank *bank)
/*---------------------------------------------------------------------*/
-static int omap_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
{
- struct gpio_bank *bank;
+ struct gpio_bank *bank = gpiochip_get_data(chip);
+ unsigned long flags;
+
+ pm_runtime_get_sync(chip->parent);
+
+ raw_spin_lock_irqsave(&bank->lock, flags);
+ omap_enable_gpio_module(bank, offset);
+ bank->mod_usage |= BIT(offset);
+ raw_spin_unlock_irqrestore(&bank->lock, flags);
+
+ return 0;
+}
+
+static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ struct gpio_bank *bank = gpiochip_get_data(chip);
unsigned long flags;
- void __iomem *reg;
- int dir;
- bank = gpiochip_get_data(chip);
- reg = bank->base + bank->regs->direction;
raw_spin_lock_irqsave(&bank->lock, flags);
- dir = !!(readl_relaxed(reg) & BIT(offset));
+ bank->mod_usage &= ~(BIT(offset));
+ if (!LINE_USED(bank->irq_usage, offset)) {
+ omap_set_gpio_direction(bank, offset, 1);
+ omap_clear_gpio_debounce(bank, offset);
+ }
+ omap_disable_gpio_module(bank, offset);
raw_spin_unlock_irqrestore(&bank->lock, flags);
- return dir;
+
+ pm_runtime_put(chip->parent);
+}
+
+static int omap_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+{
+ struct gpio_bank *bank = gpiochip_get_data(chip);
+
+ return !!(readl_relaxed(bank->base + bank->regs->direction) &
+ BIT(offset));
}
static int omap_gpio_input(struct gpio_chip *chip, unsigned offset)
@@ -990,14 +823,15 @@ static int omap_gpio_input(struct gpio_chip *chip, unsigned offset)
static int omap_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct gpio_bank *bank;
-
- bank = gpiochip_get_data(chip);
+ struct gpio_bank *bank = gpiochip_get_data(chip);
+ void __iomem *reg;
if (omap_gpio_is_input(bank, offset))
- return omap_get_gpio_datain(bank, offset);
+ reg = bank->base + bank->regs->datain;
else
- return omap_get_gpio_dataout(bank, offset);
+ reg = bank->base + bank->regs->dataout;
+
+ return (readl_relaxed(reg) & BIT(offset)) != 0;
}
static int omap_gpio_output(struct gpio_chip *chip, unsigned offset, int value)
@@ -1017,18 +851,20 @@ static int omap_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
unsigned long *bits)
{
struct gpio_bank *bank = gpiochip_get_data(chip);
- void __iomem *reg = bank->base + bank->regs->direction;
- unsigned long in = readl_relaxed(reg), l;
+ void __iomem *base = bank->base;
+ u32 direction, m, val = 0;
- *bits = 0;
+ direction = readl_relaxed(base + bank->regs->direction);
- l = in & *mask;
- if (l)
- *bits |= omap_get_gpio_datain_multiple(bank, &l);
+ m = direction & *mask;
+ if (m)
+ val |= readl_relaxed(base + bank->regs->datain) & m;
- l = ~in & *mask;
- if (l)
- *bits |= omap_get_gpio_dataout_multiple(bank, &l);
+ m = ~direction & *mask;
+ if (m)
+ val |= readl_relaxed(base + bank->regs->dataout) & m;
+
+ *bits = val;
return 0;
}
@@ -1081,10 +917,14 @@ static void omap_gpio_set_multiple(struct gpio_chip *chip, unsigned long *mask,
unsigned long *bits)
{
struct gpio_bank *bank = gpiochip_get_data(chip);
+ void __iomem *reg = bank->base + bank->regs->dataout;
unsigned long flags;
+ u32 l;
raw_spin_lock_irqsave(&bank->lock, flags);
- bank->set_dataout_multiple(bank, mask, bits);
+ l = (readl_relaxed(reg) & ~*mask) | (*bits & *mask);
+ writel_relaxed(l, reg);
+ bank->context.dataout = l;
raw_spin_unlock_irqrestore(&bank->lock, flags);
}
@@ -1118,9 +958,9 @@ static void omap_gpio_mod_init(struct gpio_bank *bank)
return;
}
- omap_gpio_rmw(base, bank->regs->irqenable, l,
+ omap_gpio_rmw(base + bank->regs->irqenable, l,
bank->regs->irqenable_inv);
- omap_gpio_rmw(base, bank->regs->irqstatus, l,
+ omap_gpio_rmw(base + bank->regs->irqstatus, l,
!bank->regs->irqenable_inv);
if (bank->regs->debounce_en)
writel_relaxed(0, base + bank->regs->debounce_en);
@@ -1183,11 +1023,8 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
#endif
/* MPUIO is a bit different, reading IRQ status clears it */
- if (bank->is_mpuio) {
- irqc->irq_ack = dummy_irq_chip.irq_ack;
- if (!bank->regs->wkup_en)
- irqc->irq_set_wake = NULL;
- }
+ if (bank->is_mpuio && !bank->regs->wkup_en)
+ irqc->irq_set_wake = NULL;
irq = &bank->chip.irq;
irq->chip = irqc;
@@ -1218,7 +1055,7 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
static void omap_gpio_init_context(struct gpio_bank *p)
{
- struct omap_gpio_reg_offs *regs = p->regs;
+ const struct omap_gpio_reg_offs *regs = p->regs;
void __iomem *base = p->base;
p->context.ctrl = readl_relaxed(base + regs->ctrl);
@@ -1230,60 +1067,56 @@ static void omap_gpio_init_context(struct gpio_bank *p)
p->context.fallingdetect = readl_relaxed(base + regs->fallingdetect);
p->context.irqenable1 = readl_relaxed(base + regs->irqenable);
p->context.irqenable2 = readl_relaxed(base + regs->irqenable2);
-
- if (regs->set_dataout && p->regs->clr_dataout)
- p->context.dataout = readl_relaxed(base + regs->set_dataout);
- else
- p->context.dataout = readl_relaxed(base + regs->dataout);
+ p->context.dataout = readl_relaxed(base + regs->dataout);
p->context_valid = true;
}
static void omap_gpio_restore_context(struct gpio_bank *bank)
{
- writel_relaxed(bank->context.wake_en,
- bank->base + bank->regs->wkup_en);
- writel_relaxed(bank->context.ctrl, bank->base + bank->regs->ctrl);
- writel_relaxed(bank->context.leveldetect0,
- bank->base + bank->regs->leveldetect0);
- writel_relaxed(bank->context.leveldetect1,
- bank->base + bank->regs->leveldetect1);
- writel_relaxed(bank->context.risingdetect,
- bank->base + bank->regs->risingdetect);
- writel_relaxed(bank->context.fallingdetect,
- bank->base + bank->regs->fallingdetect);
- if (bank->regs->set_dataout && bank->regs->clr_dataout)
- writel_relaxed(bank->context.dataout,
- bank->base + bank->regs->set_dataout);
- else
- writel_relaxed(bank->context.dataout,
- bank->base + bank->regs->dataout);
- writel_relaxed(bank->context.oe, bank->base + bank->regs->direction);
+ const struct omap_gpio_reg_offs *regs = bank->regs;
+ void __iomem *base = bank->base;
+
+ writel_relaxed(bank->context.wake_en, base + regs->wkup_en);
+ writel_relaxed(bank->context.ctrl, base + regs->ctrl);
+ writel_relaxed(bank->context.leveldetect0, base + regs->leveldetect0);
+ writel_relaxed(bank->context.leveldetect1, base + regs->leveldetect1);
+ writel_relaxed(bank->context.risingdetect, base + regs->risingdetect);
+ writel_relaxed(bank->context.fallingdetect, base + regs->fallingdetect);
+ writel_relaxed(bank->context.dataout, base + regs->dataout);
+ writel_relaxed(bank->context.oe, base + regs->direction);
if (bank->dbck_enable_mask) {
- writel_relaxed(bank->context.debounce, bank->base +
- bank->regs->debounce);
+ writel_relaxed(bank->context.debounce, base + regs->debounce);
writel_relaxed(bank->context.debounce_en,
- bank->base + bank->regs->debounce_en);
+ base + regs->debounce_en);
}
- writel_relaxed(bank->context.irqenable1,
- bank->base + bank->regs->irqenable);
- writel_relaxed(bank->context.irqenable2,
- bank->base + bank->regs->irqenable2);
+ writel_relaxed(bank->context.irqenable1, base + regs->irqenable);
+ writel_relaxed(bank->context.irqenable2, base + regs->irqenable2);
}
static void omap_gpio_idle(struct gpio_bank *bank, bool may_lose_context)
{
struct device *dev = bank->chip.parent;
void __iomem *base = bank->base;
- u32 nowake;
+ u32 mask, nowake;
bank->saved_datain = readl_relaxed(base + bank->regs->datain);
if (!bank->enabled_non_wakeup_gpios)
goto update_gpio_context_count;
+ /* Check for pending EDGE_FALLING, ignore EDGE_BOTH */
+ mask = bank->enabled_non_wakeup_gpios & bank->context.fallingdetect;
+ mask &= ~bank->context.risingdetect;
+ bank->saved_datain |= mask;
+
+ /* Check for pending EDGE_RISING, ignore EDGE_BOTH */
+ mask = bank->enabled_non_wakeup_gpios & bank->context.risingdetect;
+ mask &= ~bank->context.fallingdetect;
+ bank->saved_datain &= ~mask;
+
if (!may_lose_context)
goto update_gpio_context_count;
@@ -1294,8 +1127,8 @@ static void omap_gpio_idle(struct gpio_bank *bank, bool may_lose_context)
*/
if (!bank->loses_context && bank->enabled_non_wakeup_gpios) {
nowake = bank->enabled_non_wakeup_gpios;
- omap_gpio_rmw(base, bank->regs->fallingdetect, nowake, ~nowake);
- omap_gpio_rmw(base, bank->regs->risingdetect, nowake, ~nowake);
+ omap_gpio_rmw(base + bank->regs->fallingdetect, nowake, ~nowake);
+ omap_gpio_rmw(base + bank->regs->risingdetect, nowake, ~nowake);
}
update_gpio_context_count:
@@ -1424,7 +1257,7 @@ static int gpio_omap_cpu_notifier(struct notifier_block *nb,
return NOTIFY_OK;
}
-static struct omap_gpio_reg_offs omap2_gpio_regs = {
+static const struct omap_gpio_reg_offs omap2_gpio_regs = {
.revision = OMAP24XX_GPIO_REVISION,
.direction = OMAP24XX_GPIO_OE,
.datain = OMAP24XX_GPIO_DATAIN,
@@ -1447,7 +1280,7 @@ static struct omap_gpio_reg_offs omap2_gpio_regs = {
.fallingdetect = OMAP24XX_GPIO_FALLINGDETECT,
};
-static struct omap_gpio_reg_offs omap4_gpio_regs = {
+static const struct omap_gpio_reg_offs omap4_gpio_regs = {
.revision = OMAP4_GPIO_REVISION,
.direction = OMAP4_GPIO_OE,
.datain = OMAP4_GPIO_DATAIN,
@@ -1456,6 +1289,8 @@ static struct omap_gpio_reg_offs omap4_gpio_regs = {
.clr_dataout = OMAP4_GPIO_CLEARDATAOUT,
.irqstatus = OMAP4_GPIO_IRQSTATUS0,
.irqstatus2 = OMAP4_GPIO_IRQSTATUS1,
+ .irqstatus_raw0 = OMAP4_GPIO_IRQSTATUSRAW0,
+ .irqstatus_raw1 = OMAP4_GPIO_IRQSTATUSRAW1,
.irqenable = OMAP4_GPIO_IRQSTATUSSET0,
.irqenable2 = OMAP4_GPIO_IRQSTATUSSET1,
.set_irqenable = OMAP4_GPIO_IRQSTATUSSET0,
@@ -1531,7 +1366,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
irqc->irq_startup = omap_gpio_irq_startup,
irqc->irq_shutdown = omap_gpio_irq_shutdown,
- irqc->irq_ack = omap_gpio_ack_irq,
+ irqc->irq_ack = dummy_irq_chip.irq_ack,
irqc->irq_mask = omap_gpio_mask_irq,
irqc->irq_unmask = omap_gpio_unmask_irq,
irqc->irq_set_type = omap_gpio_irq_type,
@@ -1575,14 +1410,10 @@ static int omap_gpio_probe(struct platform_device *pdev)
pdata->get_context_loss_count;
}
- if (bank->regs->set_dataout && bank->regs->clr_dataout) {
+ if (bank->regs->set_dataout && bank->regs->clr_dataout)
bank->set_dataout = omap_set_gpio_dataout_reg;
- bank->set_dataout_multiple = omap_set_gpio_dataout_reg_multiple;
- } else {
+ else
bank->set_dataout = omap_set_gpio_dataout_mask;
- bank->set_dataout_multiple =
- omap_set_gpio_dataout_mask_multiple;
- }
raw_spin_lock_init(&bank->lock);
raw_spin_lock_init(&bank->wa_lock);
@@ -1638,7 +1469,6 @@ static int omap_gpio_remove(struct platform_device *pdev)
struct gpio_bank *bank = platform_get_drvdata(pdev);
cpu_pm_unregister_notifier(&bank->nb);
- list_del(&bank->node);
gpiochip_remove(&bank->chip);
pm_runtime_disable(&pdev->dev);
if (bank->dbck_flag)
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index cfe827cefad8..378b206d2dc9 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -1178,6 +1178,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,tca9539", .data = OF_953X(16, PCA_INT), },
{ .compatible = "onnn,cat9554", .data = OF_953X( 8, PCA_INT), },
{ .compatible = "onnn,pca9654", .data = OF_953X( 8, PCA_INT), },
diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c
index dc42571e6fdc..722ce5cf861e 100644
--- a/drivers/gpio/gpio-pl061.c
+++ b/drivers/gpio/gpio-pl061.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2008, 2009 Provigent Ltd.
*
* Author: Baruch Siach <baruch@tkos.co.il>
*
- * 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.
- *
* Driver for the ARM PrimeCell(tm) General Purpose Input/Output (PL061)
*
* Data sheet: ARM DDI 0190B, September 2000
@@ -286,6 +283,7 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
{
struct device *dev = &adev->dev;
struct pl061 *pl061;
+ struct gpio_irq_chip *girq;
int ret, irq;
pl061 = devm_kzalloc(dev, sizeof(*pl061), GFP_KERNEL);
@@ -313,10 +311,6 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
pl061->gc.parent = dev;
pl061->gc.owner = THIS_MODULE;
- ret = gpiochip_add_data(&pl061->gc, pl061);
- if (ret)
- return ret;
-
/*
* irq_chip support
*/
@@ -335,19 +329,24 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
}
pl061->parent_irq = irq;
- ret = gpiochip_irqchip_add(&pl061->gc, &pl061->irq_chip,
- 0, handle_bad_irq,
- IRQ_TYPE_NONE);
- if (ret) {
- dev_info(&adev->dev, "could not add irqchip\n");
+ girq = &pl061->gc.irq;
+ girq->chip = &pl061->irq_chip;
+ girq->parent_handler = pl061_irq_handler;
+ girq->num_parents = 1;
+ girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
+ GFP_KERNEL);
+ if (!girq->parents)
+ return -ENOMEM;
+ girq->parents[0] = irq;
+ girq->default_type = IRQ_TYPE_NONE;
+ girq->handler = handle_bad_irq;
+
+ ret = devm_gpiochip_add_data(dev, &pl061->gc, pl061);
+ if (ret)
return ret;
- }
- gpiochip_set_chained_irqchip(&pl061->gc, &pl061->irq_chip,
- irq, pl061_irq_handler);
amba_set_drvdata(adev, pl061);
- dev_info(&adev->dev, "PL061 GPIO chip @%pa registered\n",
- &adev->res.start);
+ dev_info(dev, "PL061 GPIO chip registered\n");
return 0;
}
diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c
index 26f77fdb217e..9888b62f37af 100644
--- a/drivers/gpio/gpio-pxa.c
+++ b/drivers/gpio/gpio-pxa.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/arch/arm/plat-pxa/gpio.c
*
@@ -6,10 +7,6 @@
* Author: Nicolas Pitre
* Created: Jun 15, 2001
* Copyright: MontaVista Software 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.
*/
#include <linux/module.h>
#include <linux/clk.h>
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index 70e95fc4779f..187984d26f47 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -489,7 +489,7 @@ static int gpio_rcar_probe(struct platform_device *pdev)
irq_chip->irq_unmask = gpio_rcar_irq_enable;
irq_chip->irq_set_type = gpio_rcar_irq_set_type;
irq_chip->irq_set_wake = gpio_rcar_irq_set_wake;
- irq_chip->flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND;
+ irq_chip->flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND;
ret = gpiochip_add_data(gpio_chip, p);
if (ret) {
diff --git a/drivers/gpio/gpio-reg.c b/drivers/gpio/gpio-reg.c
index e85903eddc68..fdc7a9d5b382 100644
--- a/drivers/gpio/gpio-reg.c
+++ b/drivers/gpio/gpio-reg.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* gpio-reg: single register individually fixed-direction GPIOs
*
* Copyright (C) 2016 Russell King
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
*/
#include <linux/gpio/driver.h>
#include <linux/gpio/gpio-reg.h>
diff --git a/drivers/gpio/gpio-sa1100.c b/drivers/gpio/gpio-sa1100.c
index 986eb3b231ac..46b7cf23fb0f 100644
--- a/drivers/gpio/gpio-sa1100.c
+++ b/drivers/gpio/gpio-sa1100.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/arch/arm/mach-sa1100/gpio.c
*
* Generic SA-1100 GPIO handling
- *
- * 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.
*/
#include <linux/gpio/driver.h>
#include <linux/init.h>
diff --git a/drivers/gpio/gpio-siox.c b/drivers/gpio/gpio-siox.c
index 571b2a81c6de..006a7e6a75f2 100644
--- a/drivers/gpio/gpio-siox.c
+++ b/drivers/gpio/gpio-siox.c
@@ -211,20 +211,22 @@ static int gpio_siox_get_direction(struct gpio_chip *chip, unsigned int offset)
static int gpio_siox_probe(struct siox_device *sdevice)
{
struct gpio_siox_ddata *ddata;
+ struct gpio_irq_chip *girq;
+ struct device *dev = &sdevice->dev;
int ret;
- ddata = devm_kzalloc(&sdevice->dev, sizeof(*ddata), GFP_KERNEL);
+ ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
if (!ddata)
return -ENOMEM;
- dev_set_drvdata(&sdevice->dev, ddata);
+ dev_set_drvdata(dev, ddata);
mutex_init(&ddata->lock);
spin_lock_init(&ddata->irqlock);
ddata->gchip.base = -1;
ddata->gchip.can_sleep = 1;
- ddata->gchip.parent = &sdevice->dev;
+ ddata->gchip.parent = dev;
ddata->gchip.owner = THIS_MODULE;
ddata->gchip.get = gpio_siox_get;
ddata->gchip.set = gpio_siox_set;
@@ -239,54 +241,27 @@ static int gpio_siox_probe(struct siox_device *sdevice)
ddata->ichip.irq_unmask = gpio_siox_irq_unmask;
ddata->ichip.irq_set_type = gpio_siox_irq_set_type;
- ret = gpiochip_add(&ddata->gchip);
- if (ret) {
- dev_err(&sdevice->dev,
- "Failed to register gpio chip (%d)\n", ret);
- goto err_gpiochip;
- }
+ girq = &ddata->gchip.irq;
+ girq->chip = &ddata->ichip;
+ girq->default_type = IRQ_TYPE_NONE;
+ girq->handler = handle_level_irq;
- ret = gpiochip_irqchip_add(&ddata->gchip, &ddata->ichip,
- 0, handle_level_irq, IRQ_TYPE_EDGE_RISING);
- if (ret) {
- dev_err(&sdevice->dev,
- "Failed to register irq chip (%d)\n", ret);
-err_gpiochip:
- gpiochip_remove(&ddata->gchip);
- }
+ ret = devm_gpiochip_add_data(dev, &ddata->gchip, NULL);
+ if (ret)
+ dev_err(dev, "Failed to register gpio chip (%d)\n", ret);
return ret;
}
-static int gpio_siox_remove(struct siox_device *sdevice)
-{
- struct gpio_siox_ddata *ddata = dev_get_drvdata(&sdevice->dev);
-
- gpiochip_remove(&ddata->gchip);
- return 0;
-}
-
static struct siox_driver gpio_siox_driver = {
.probe = gpio_siox_probe,
- .remove = gpio_siox_remove,
.set_data = gpio_siox_set_data,
.get_data = gpio_siox_get_data,
.driver = {
.name = "gpio-siox",
},
};
-
-static int __init gpio_siox_init(void)
-{
- return siox_driver_register(&gpio_siox_driver);
-}
-module_init(gpio_siox_init);
-
-static void __exit gpio_siox_exit(void)
-{
- siox_driver_unregister(&gpio_siox_driver);
-}
-module_exit(gpio_siox_exit);
+module_siox_driver(gpio_siox_driver);
MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
MODULE_DESCRIPTION("SIOX gpio driver");
diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c
index 65a2315f1673..dbf9cbe36b2b 100644
--- a/drivers/gpio/gpio-stmpe.c
+++ b/drivers/gpio/gpio-stmpe.c
@@ -1,7 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) ST-Ericsson SA 2010
*
- * License Terms: GNU General Public License, version 2
* Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
*/
diff --git a/drivers/gpio/gpio-stp-xway.c b/drivers/gpio/gpio-stp-xway.c
index 8a319d56c5de..9e23a5ae8108 100644
--- a/drivers/gpio/gpio-stp-xway.c
+++ b/drivers/gpio/gpio-stp-xway.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
- * 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.
*
* Copyright (C) 2012 John Crispin <john@phrozen.org>
- *
*/
#include <linux/slab.h>
@@ -18,8 +15,6 @@
#include <linux/clk.h>
#include <linux/err.h>
-#include <lantiq_soc.h>
-
/*
* The Serial To Parallel (STP) is found on MIPS based Lantiq socs. It is a
* peripheral controller used to drive external shift register cascades. At most
@@ -74,8 +69,7 @@
#define xway_stp_r32(m, reg) __raw_readl(m + reg)
#define xway_stp_w32(m, val, reg) __raw_writel(val, m + reg)
#define xway_stp_w32_mask(m, clear, set, reg) \
- ltq_w32((ltq_r32(m + reg) & ~(clear)) | (set), \
- m + reg)
+ xway_stp_w32(m, (xway_stp_r32(m, reg) & ~(clear)) | (set), reg)
struct xway_stp {
struct gpio_chip gc;
@@ -159,9 +153,9 @@ static int xway_stp_request(struct gpio_chip *gc, unsigned gpio)
/**
* xway_stp_hw_init() - Configure the STP unit and enable the clock gate
- * @virt: pointer to the remapped register range
+ * @chip: Pointer to the xway_stp chip structure
*/
-static int xway_stp_hw_init(struct xway_stp *chip)
+static void xway_stp_hw_init(struct xway_stp *chip)
{
/* sane defaults */
xway_stp_w32(chip->virt, 0, XWAY_STP_AR);
@@ -204,8 +198,6 @@ static int xway_stp_hw_init(struct xway_stp *chip)
if (chip->reserved)
xway_stp_w32_mask(chip->virt, XWAY_STP_UPD_MASK,
XWAY_STP_UPD_FPI, XWAY_STP_CON1);
-
- return 0;
}
static int xway_stp_probe(struct platform_device *pdev)
@@ -261,21 +253,27 @@ static int xway_stp_probe(struct platform_device *pdev)
if (!of_find_property(pdev->dev.of_node, "lantiq,rising", NULL))
chip->edge = XWAY_STP_FALLING;
- clk = clk_get(&pdev->dev, NULL);
+ clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(clk)) {
dev_err(&pdev->dev, "Failed to get clock\n");
return PTR_ERR(clk);
}
- clk_enable(clk);
- ret = xway_stp_hw_init(chip);
- if (!ret)
- ret = devm_gpiochip_add_data(&pdev->dev, &chip->gc, chip);
+ ret = clk_prepare_enable(clk);
+ if (ret)
+ return ret;
- if (!ret)
- dev_info(&pdev->dev, "Init done\n");
+ xway_stp_hw_init(chip);
- return ret;
+ ret = devm_gpiochip_add_data(&pdev->dev, &chip->gc, chip);
+ if (ret) {
+ clk_disable_unprepare(clk);
+ return ret;
+ }
+
+ dev_info(&pdev->dev, "Init done\n");
+
+ return 0;
}
static const struct of_device_id xway_stp_match[] = {
diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c
index 91a8ef8e7f3f..75b1135b383a 100644
--- a/drivers/gpio/gpio-tc3589x.c
+++ b/drivers/gpio/gpio-tc3589x.c
@@ -1,7 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) ST-Ericsson SA 2010
*
- * License Terms: GNU General Public License, version 2
* Author: Hanumath Prasad <hanumath.prasad@stericsson.com> for ST-Ericsson
* Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
*/
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index f57bfc07ae22..0f59161a4701 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -541,8 +541,8 @@ DEFINE_SHOW_ATTRIBUTE(tegra_dbg_gpio);
static void tegra_gpio_debuginit(struct tegra_gpio_info *tgi)
{
- (void) debugfs_create_file("tegra_gpio", 0444,
- NULL, tgi, &tegra_dbg_gpio_fops);
+ debugfs_create_file("tegra_gpio", 0444, NULL, tgi,
+ &tegra_dbg_gpio_fops);
}
#else
diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c
index 7d42e3d7572c..a9058fda187e 100644
--- a/drivers/gpio/gpio-tegra186.c
+++ b/drivers/gpio/gpio-tegra186.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2016-2017 NVIDIA Corporation
*
* Author: Thierry Reding <treding@nvidia.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
*/
#include <linux/gpio/driver.h>
diff --git a/drivers/gpio/gpio-ucb1400.c b/drivers/gpio/gpio-ucb1400.c
index 5dbe31bf6699..d2a8644864c3 100644
--- a/drivers/gpio/gpio-ucb1400.c
+++ b/drivers/gpio/gpio-ucb1400.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Philips UCB1400 GPIO driver
*
* Author: Marek Vasut <marek.vasut@gmail.com>
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c
index 30aef41e3b7e..7ba668db171b 100644
--- a/drivers/gpio/gpio-vf610.c
+++ b/drivers/gpio/gpio-vf610.c
@@ -265,7 +265,8 @@ static int vf610_gpio_probe(struct platform_device *pdev)
return port->irq;
port->clk_port = devm_clk_get(dev, "port");
- if (!IS_ERR(port->clk_port)) {
+ ret = PTR_ERR_OR_ZERO(port->clk_port);
+ if (!ret) {
ret = clk_prepare_enable(port->clk_port);
if (ret)
return ret;
@@ -273,16 +274,17 @@ static int vf610_gpio_probe(struct platform_device *pdev)
port->clk_port);
if (ret)
return ret;
- } else if (port->clk_port == ERR_PTR(-EPROBE_DEFER)) {
+ } else if (ret == -EPROBE_DEFER) {
/*
* Percolate deferrals, for anything else,
* just live without the clocking.
*/
- return PTR_ERR(port->clk_port);
+ return ret;
}
port->clk_gpio = devm_clk_get(dev, "gpio");
- if (!IS_ERR(port->clk_gpio)) {
+ ret = PTR_ERR_OR_ZERO(port->clk_gpio);
+ if (!ret) {
ret = clk_prepare_enable(port->clk_gpio);
if (ret)
return ret;
@@ -290,8 +292,8 @@ static int vf610_gpio_probe(struct platform_device *pdev)
port->clk_gpio);
if (ret)
return ret;
- } else if (port->clk_gpio == ERR_PTR(-EPROBE_DEFER)) {
- return PTR_ERR(port->clk_gpio);
+ } else if (ret == -EPROBE_DEFER) {
+ return ret;
}
gc = &port->gc;
diff --git a/drivers/gpio/gpio-vr41xx.c b/drivers/gpio/gpio-vr41xx.c
index b13a49c89cc1..98cd715ccc33 100644
--- a/drivers/gpio/gpio-vr41xx.c
+++ b/drivers/gpio/gpio-vr41xx.c
@@ -467,10 +467,9 @@ static struct gpio_chip vr41xx_gpio_chip = {
static int giu_probe(struct platform_device *pdev)
{
- struct resource *res;
unsigned int trigger, i, pin;
struct irq_chip *chip;
- int irq, ret;
+ int irq;
switch (pdev->id) {
case GPIO_50PINS_PULLUPDOWN:
@@ -489,21 +488,14 @@ static int giu_probe(struct platform_device *pdev)
return -ENODEV;
}
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -EBUSY;
-
- giu_base = ioremap(res->start, resource_size(res));
- if (!giu_base)
- return -ENOMEM;
+ giu_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(giu_base))
+ return PTR_ERR(giu_base);
vr41xx_gpio_chip.parent = &pdev->dev;
- ret = gpiochip_add_data(&vr41xx_gpio_chip, NULL);
- if (!ret) {
- iounmap(giu_base);
+ if (gpiochip_add_data(&vr41xx_gpio_chip, NULL))
return -ENODEV;
- }
giu_write(GIUINTENL, 0);
giu_write(GIUINTENH, 0);
@@ -534,7 +526,6 @@ static int giu_probe(struct platform_device *pdev)
static int giu_remove(struct platform_device *pdev)
{
if (giu_base) {
- iounmap(giu_base);
giu_base = NULL;
}
diff --git a/drivers/gpio/gpio-xgene.c b/drivers/gpio/gpio-xgene.c
index f1c6ec17b90a..2918363884de 100644
--- a/drivers/gpio/gpio-xgene.c
+++ b/drivers/gpio/gpio-xgene.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AppliedMicro X-Gene SoC GPIO Driver
*
* Copyright (c) 2014, Applied Micro Circuits Corporation
* Author: Feng Kan <fkan@apm.com>.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/acpi.h>
diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c
index 32944eb886c1..a9748b5198e6 100644
--- a/drivers/gpio/gpio-xilinx.c
+++ b/drivers/gpio/gpio-xilinx.c
@@ -11,7 +11,6 @@
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
-#include <linux/of_gpio.h>
#include <linux/io.h>
#include <linux/gpio/driver.h>
#include <linux/slab.h>
@@ -33,14 +32,16 @@
/**
* struct xgpio_instance - Stores information about GPIO device
- * @mmchip: OF GPIO chip for memory mapped banks
+ * @gc: GPIO chip
+ * @regs: register block
* @gpio_width: GPIO width for every channel
* @gpio_state: GPIO state shadow register
* @gpio_dir: GPIO direction shadow register
* @gpio_lock: Lock used for synchronization
*/
struct xgpio_instance {
- struct of_mm_gpio_chip mmchip;
+ struct gpio_chip gc;
+ void __iomem *regs;
unsigned int gpio_width[2];
u32 gpio_state[2];
u32 gpio_dir[2];
@@ -84,11 +85,10 @@ static inline int xgpio_offset(struct xgpio_instance *chip, int gpio)
*/
static int xgpio_get(struct gpio_chip *gc, unsigned int gpio)
{
- struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct xgpio_instance *chip = gpiochip_get_data(gc);
u32 val;
- val = xgpio_readreg(mm_gc->regs + XGPIO_DATA_OFFSET +
+ val = xgpio_readreg(chip->regs + XGPIO_DATA_OFFSET +
xgpio_regoffset(chip, gpio));
return !!(val & BIT(xgpio_offset(chip, gpio)));
@@ -106,7 +106,6 @@ static int xgpio_get(struct gpio_chip *gc, unsigned int gpio)
static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
unsigned long flags;
- struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct xgpio_instance *chip = gpiochip_get_data(gc);
int index = xgpio_index(chip, gpio);
int offset = xgpio_offset(chip, gpio);
@@ -119,7 +118,7 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
else
chip->gpio_state[index] &= ~BIT(offset);
- xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET +
+ xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET +
xgpio_regoffset(chip, gpio), chip->gpio_state[index]);
spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
@@ -138,7 +137,6 @@ static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
unsigned long *bits)
{
unsigned long flags;
- struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct xgpio_instance *chip = gpiochip_get_data(gc);
int index = xgpio_index(chip, 0);
int offset, i;
@@ -150,7 +148,7 @@ static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
if (*mask == 0)
break;
if (index != xgpio_index(chip, i)) {
- xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET +
+ xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET +
xgpio_regoffset(chip, i),
chip->gpio_state[index]);
spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
@@ -166,7 +164,7 @@ static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
}
}
- xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET +
+ xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET +
xgpio_regoffset(chip, i), chip->gpio_state[index]);
spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
@@ -184,7 +182,6 @@ static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
unsigned long flags;
- struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct xgpio_instance *chip = gpiochip_get_data(gc);
int index = xgpio_index(chip, gpio);
int offset = xgpio_offset(chip, gpio);
@@ -193,7 +190,7 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
/* Set the GPIO bit in shadow register and set direction as input */
chip->gpio_dir[index] |= BIT(offset);
- xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET +
+ xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET +
xgpio_regoffset(chip, gpio), chip->gpio_dir[index]);
spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
@@ -216,7 +213,6 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
unsigned long flags;
- struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct xgpio_instance *chip = gpiochip_get_data(gc);
int index = xgpio_index(chip, gpio);
int offset = xgpio_offset(chip, gpio);
@@ -228,12 +224,12 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
chip->gpio_state[index] |= BIT(offset);
else
chip->gpio_state[index] &= ~BIT(offset);
- xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET +
+ xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET +
xgpio_regoffset(chip, gpio), chip->gpio_state[index]);
/* Clear the GPIO bit in shadow register and set direction as output */
chip->gpio_dir[index] &= ~BIT(offset);
- xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET +
+ xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET +
xgpio_regoffset(chip, gpio), chip->gpio_dir[index]);
spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
@@ -243,43 +239,23 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
/**
* xgpio_save_regs - Set initial values of GPIO pins
- * @mm_gc: Pointer to memory mapped GPIO chip structure
+ * @chip: Pointer to GPIO instance
*/
-static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc)
+static void xgpio_save_regs(struct xgpio_instance *chip)
{
- struct xgpio_instance *chip =
- container_of(mm_gc, struct xgpio_instance, mmchip);
-
- xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state[0]);
- xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir[0]);
+ xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET, chip->gpio_state[0]);
+ xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET, chip->gpio_dir[0]);
if (!chip->gpio_width[1])
return;
- xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET + XGPIO_CHANNEL_OFFSET,
+ xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET + XGPIO_CHANNEL_OFFSET,
chip->gpio_state[1]);
- xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET + XGPIO_CHANNEL_OFFSET,
+ xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET + XGPIO_CHANNEL_OFFSET,
chip->gpio_dir[1]);
}
/**
- * xgpio_remove - Remove method for the GPIO device.
- * @pdev: pointer to the platform device
- *
- * This function remove gpiochips and frees all the allocated resources.
- *
- * Return: 0 always
- */
-static int xgpio_remove(struct platform_device *pdev)
-{
- struct xgpio_instance *chip = platform_get_drvdata(pdev);
-
- of_mm_gpiochip_remove(&chip->mmchip);
-
- return 0;
-}
-
-/**
* xgpio_of_probe - Probe method for the GPIO device.
* @pdev: pointer to the platform device
*
@@ -340,21 +316,28 @@ static int xgpio_probe(struct platform_device *pdev)
spin_lock_init(&chip->gpio_lock[1]);
}
- chip->mmchip.gc.ngpio = chip->gpio_width[0] + chip->gpio_width[1];
- chip->mmchip.gc.parent = &pdev->dev;
- chip->mmchip.gc.direction_input = xgpio_dir_in;
- chip->mmchip.gc.direction_output = xgpio_dir_out;
- chip->mmchip.gc.get = xgpio_get;
- chip->mmchip.gc.set = xgpio_set;
- chip->mmchip.gc.set_multiple = xgpio_set_multiple;
+ chip->gc.base = -1;
+ chip->gc.ngpio = chip->gpio_width[0] + chip->gpio_width[1];
+ chip->gc.parent = &pdev->dev;
+ chip->gc.direction_input = xgpio_dir_in;
+ chip->gc.direction_output = xgpio_dir_out;
+ chip->gc.get = xgpio_get;
+ chip->gc.set = xgpio_set;
+ chip->gc.set_multiple = xgpio_set_multiple;
+
+ chip->gc.label = dev_name(&pdev->dev);
+
+ chip->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(chip->regs)) {
+ dev_err(&pdev->dev, "failed to ioremap memory resource\n");
+ return PTR_ERR(chip->regs);
+ }
- chip->mmchip.save_regs = xgpio_save_regs;
+ xgpio_save_regs(chip);
- /* Call the OF gpio helper to setup and register the GPIO device */
- status = of_mm_gpiochip_add_data(np, &chip->mmchip, chip);
+ status = devm_gpiochip_add_data(&pdev->dev, &chip->gc, chip);
if (status) {
- pr_err("%pOF: error in probe function with status %d\n",
- np, status);
+ dev_err(&pdev->dev, "failed to add GPIO chip\n");
return status;
}
@@ -370,7 +353,6 @@ MODULE_DEVICE_TABLE(of, xgpio_of_match);
static struct platform_driver xgpio_plat_driver = {
.probe = xgpio_probe,
- .remove = xgpio_remove,
.driver = {
.name = "gpio-xilinx",
.of_match_table = xgpio_of_match,
diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c
index 57432397e5e5..f6f8a541348f 100644
--- a/drivers/gpio/gpio-zevio.c
+++ b/drivers/gpio/gpio-zevio.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* GPIO controller in LSI ZEVIO SoCs.
*
* Author: Fabian Vogt <fabian@ritter-vogt.de>
- *
- * 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.
*/
#include <linux/spinlock.h>
diff --git a/drivers/gpio/gpio-zx.c b/drivers/gpio/gpio-zx.c
index fb927559aefa..8637adb6bc20 100644
--- a/drivers/gpio/gpio-zx.c
+++ b/drivers/gpio/gpio-zx.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ZTE ZX296702 GPIO driver
*
* Author: Jun Nie <jun.nie@linaro.org>
*
* Copyright (C) 2015 Linaro Ltd.
- *
- * 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.
*/
#include <linux/bitops.h>
#include <linux/device.h>
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index c9fc9e232aaf..39f2f9035c11 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -217,14 +217,13 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
if (!handler)
return AE_OK;
- desc = gpiochip_request_own_desc(chip, pin, "ACPI:Event", 0);
+ desc = gpiochip_request_own_desc(chip, pin, "ACPI:Event",
+ GPIO_ACTIVE_HIGH, GPIOD_IN);
if (IS_ERR(desc)) {
dev_err(chip->parent, "Failed to request GPIO\n");
return AE_ERROR;
}
- gpiod_direction_input(desc);
-
ret = gpiochip_lock_as_irq(chip, pin);
if (ret) {
dev_err(chip->parent, "Failed to lock GPIO as interrupt\n");
@@ -951,6 +950,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
const char *label = "ACPI:OpRegion";
desc = gpiochip_request_own_desc(chip, pin, label,
+ GPIO_ACTIVE_HIGH,
flags);
if (IS_ERR(desc)) {
status = AE_ERROR;
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index aec7bd86ae7e..567fb98c0892 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -154,10 +154,17 @@ static void of_gpio_flags_quirks(struct device_node *np,
of_node_full_name(child));
*flags |= OF_GPIO_ACTIVE_LOW;
}
+ of_node_put(child);
break;
}
}
}
+
+ /* Legacy handling of stmmac's active-low PHY reset line */
+ if (IS_ENABLED(CONFIG_STMMAC_ETH) &&
+ !strcmp(propname, "snps,reset-gpio") &&
+ of_property_read_bool(np, "snps,reset-active-low"))
+ *flags |= OF_GPIO_ACTIVE_LOW;
}
/**
@@ -255,6 +262,37 @@ static struct gpio_desc *of_find_spi_gpio(struct device *dev, const char *con_id
}
/*
+ * The old Freescale bindings use simply "gpios" as name for the chip select
+ * lines rather than "cs-gpios" like all other SPI hardware. Account for this
+ * with a special quirk.
+ */
+static struct gpio_desc *of_find_spi_cs_gpio(struct device *dev,
+ const char *con_id,
+ unsigned int idx,
+ unsigned long *flags)
+{
+ struct device_node *np = dev->of_node;
+
+ if (!IS_ENABLED(CONFIG_SPI_MASTER))
+ return ERR_PTR(-ENOENT);
+
+ /* Allow this specifically for Freescale devices */
+ if (!of_device_is_compatible(np, "fsl,spi") &&
+ !of_device_is_compatible(np, "aeroflexgaisler,spictrl"))
+ return ERR_PTR(-ENOENT);
+ /* Allow only if asking for "cs-gpios" */
+ if (!con_id || strcmp(con_id, "cs"))
+ return ERR_PTR(-ENOENT);
+
+ /*
+ * While all other SPI controllers use "cs-gpios" the Freescale
+ * uses just "gpios" so translate to that when "cs-gpios" is
+ * requested.
+ */
+ return of_find_gpio(dev, NULL, idx, flags);
+}
+
+/*
* Some regulator bindings happened before we managed to establish that GPIO
* properties should be named "foo-gpios" so we have this special kludge for
* them.
@@ -325,6 +363,12 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
/* Special handling for SPI GPIOs if used */
if (IS_ERR(desc))
desc = of_find_spi_gpio(dev, con_id, &of_flags);
+ if (IS_ERR(desc)) {
+ /* This quirk looks up flags and all */
+ desc = of_find_spi_cs_gpio(dev, con_id, idx, flags);
+ if (!IS_ERR(desc))
+ return desc;
+ }
/* Special handling for regulator GPIOs if used */
if (IS_ERR(desc) && PTR_ERR(desc) != -EPROBE_DEFER)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index e013d417a936..3ee99d070608 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1644,39 +1644,47 @@ EXPORT_SYMBOL_GPL(gpiochip_irqchip_irq_valid);
/**
* gpiochip_set_cascaded_irqchip() - connects a cascaded irqchip to a gpiochip
- * @gpiochip: the gpiochip to set the irqchip chain to
+ * @gc: the gpiochip to set the irqchip chain to
* @parent_irq: the irq number corresponding to the parent IRQ for this
* chained irqchip
* @parent_handler: the parent interrupt handler for the accumulated IRQ
* coming out of the gpiochip. If the interrupt is nested rather than
* cascaded, pass NULL in this handler argument
*/
-static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip,
+static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gc,
unsigned int parent_irq,
irq_flow_handler_t parent_handler)
{
- if (!gpiochip->irq.domain) {
- chip_err(gpiochip, "called %s before setting up irqchip\n",
+ struct gpio_irq_chip *girq = &gc->irq;
+ struct device *dev = &gc->gpiodev->dev;
+
+ if (!girq->domain) {
+ chip_err(gc, "called %s before setting up irqchip\n",
__func__);
return;
}
if (parent_handler) {
- if (gpiochip->can_sleep) {
- chip_err(gpiochip,
+ if (gc->can_sleep) {
+ chip_err(gc,
"you cannot have chained interrupts on a chip that may sleep\n");
return;
}
+ girq->parents = devm_kcalloc(dev, 1,
+ sizeof(*girq->parents),
+ GFP_KERNEL);
+ if (!girq->parents) {
+ chip_err(gc, "out of memory allocating parent IRQ\n");
+ return;
+ }
+ girq->parents[0] = parent_irq;
+ girq->num_parents = 1;
/*
* The parent irqchip is already using the chip_data for this
* irqchip, so our callbacks simply use the handler_data.
*/
irq_set_chained_handler_and_data(parent_irq, parent_handler,
- gpiochip);
-
- gpiochip->irq.parent_irq = parent_irq;
- gpiochip->irq.parents = &gpiochip->irq.parent_irq;
- gpiochip->irq.num_parents = 1;
+ gc);
}
}
@@ -2503,7 +2511,11 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested);
* @chip: GPIO chip
* @hwnum: hardware number of the GPIO for which to request the descriptor
* @label: label for the GPIO
- * @flags: flags for this GPIO or 0 if default
+ * @lflags: lookup flags for this GPIO or 0 if default, this can be used to
+ * specify things like line inversion semantics with the machine flags
+ * such as GPIO_OUT_LOW
+ * @dflags: descriptor request flags for this GPIO or 0 if default, this
+ * can be used to specify consumer semantics such as open drain
*
* Function allows GPIO chip drivers to request and use their own GPIO
* descriptors via gpiolib API. Difference to gpiod_request() is that this
@@ -2517,9 +2529,9 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested);
*/
struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum,
const char *label,
- enum gpiod_flags flags)
+ enum gpio_lookup_flags lflags,
+ enum gpiod_flags dflags)
{
- unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
struct gpio_desc *desc = gpiochip_get_desc(chip, hwnum);
int err;
@@ -2532,7 +2544,7 @@ struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum,
if (err < 0)
return ERR_PTR(err);
- err = gpiod_configure_flags(desc, label, lflags, flags);
+ err = gpiod_configure_flags(desc, label, lflags, dflags);
if (err) {
chip_err(chip, "setup of own GPIO %s failed\n", label);
gpiod_free_commit(desc);
@@ -3019,13 +3031,13 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
* Return the GPIO's raw value, i.e. the value of the physical line disregarding
* its ACTIVE_LOW status, or negative errno on failure.
*
- * This function should be called from contexts where we cannot sleep, and will
+ * This function can be called from contexts where we cannot sleep, and will
* complain if the GPIO chip functions potentially sleep.
*/
int gpiod_get_raw_value(const struct gpio_desc *desc)
{
VALIDATE_DESC(desc);
- /* Should be using gpio_get_value_cansleep() */
+ /* Should be using gpiod_get_raw_value_cansleep() */
WARN_ON(desc->gdev->chip->can_sleep);
return gpiod_get_raw_value_commit(desc);
}
@@ -3038,7 +3050,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_raw_value);
* Return the GPIO's logical value, i.e. taking the ACTIVE_LOW status into
* account, or negative errno on failure.
*
- * This function should be called from contexts where we cannot sleep, and will
+ * This function can be called from contexts where we cannot sleep, and will
* complain if the GPIO chip functions potentially sleep.
*/
int gpiod_get_value(const struct gpio_desc *desc)
@@ -3046,7 +3058,7 @@ int gpiod_get_value(const struct gpio_desc *desc)
int value;
VALIDATE_DESC(desc);
- /* Should be using gpio_get_value_cansleep() */
+ /* Should be using gpiod_get_value_cansleep() */
WARN_ON(desc->gdev->chip->can_sleep);
value = gpiod_get_raw_value_commit(desc);
@@ -3071,7 +3083,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_value);
* without regard for their ACTIVE_LOW status. Return 0 in case of success,
* else an error code.
*
- * This function should be called from contexts where we cannot sleep,
+ * This function can be called from contexts where we cannot sleep,
* and it will complain if the GPIO chip functions potentially sleep.
*/
int gpiod_get_raw_array_value(unsigned int array_size,
@@ -3097,7 +3109,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value);
* Read the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status
* into account. Return 0 in case of success, else an error code.
*
- * This function should be called from contexts where we cannot sleep,
+ * This function can be called from contexts where we cannot sleep,
* and it will complain if the GPIO chip functions potentially sleep.
*/
int gpiod_get_array_value(unsigned int array_size,
@@ -3311,13 +3323,13 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
* Set the raw value of the GPIO, i.e. the value of its physical line without
* regard for its ACTIVE_LOW status.
*
- * This function should be called from contexts where we cannot sleep, and will
+ * This function can be called from contexts where we cannot sleep, and will
* complain if the GPIO chip functions potentially sleep.
*/
void gpiod_set_raw_value(struct gpio_desc *desc, int value)
{
VALIDATE_DESC_VOID(desc);
- /* Should be using gpiod_set_value_cansleep() */
+ /* Should be using gpiod_set_raw_value_cansleep() */
WARN_ON(desc->gdev->chip->can_sleep);
gpiod_set_raw_value_commit(desc, value);
}
@@ -3352,12 +3364,13 @@ static void gpiod_set_value_nocheck(struct gpio_desc *desc, int value)
* Set the logical value of the GPIO, i.e. taking its ACTIVE_LOW,
* OPEN_DRAIN and OPEN_SOURCE flags into account.
*
- * This function should be called from contexts where we cannot sleep, and will
+ * This function can be called from contexts where we cannot sleep, and will
* complain if the GPIO chip functions potentially sleep.
*/
void gpiod_set_value(struct gpio_desc *desc, int value)
{
VALIDATE_DESC_VOID(desc);
+ /* Should be using gpiod_set_value_cansleep() */
WARN_ON(desc->gdev->chip->can_sleep);
gpiod_set_value_nocheck(desc, value);
}
@@ -3373,7 +3386,7 @@ EXPORT_SYMBOL_GPL(gpiod_set_value);
* Set the raw values of the GPIOs, i.e. the values of the physical lines
* without regard for their ACTIVE_LOW status.
*
- * This function should be called from contexts where we cannot sleep, and will
+ * This function can be called from contexts where we cannot sleep, and will
* complain if the GPIO chip functions potentially sleep.
*/
int gpiod_set_raw_array_value(unsigned int array_size,
@@ -3398,7 +3411,7 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value);
* Set the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status
* into account.
*
- * This function should be called from contexts where we cannot sleep, and will
+ * This function can be called from contexts where we cannot sleep, and will
* complain if the GPIO chip functions potentially sleep.
*/
int gpiod_set_array_value(unsigned int array_size,
@@ -4244,8 +4257,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_index);
*
* Returns:
* On successful request the GPIO pin is configured in accordance with
- * provided @dflags. If the node does not have the requested GPIO
- * property, NULL is returned.
+ * provided @dflags.
*
* In case of error an ERR_PTR() is returned.
*/
@@ -4267,9 +4279,6 @@ struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
index, &flags);
if (!desc || IS_ERR(desc)) {
- /* If it is not there, just return NULL */
- if (PTR_ERR(desc) == -ENOENT)
- return NULL;
return desc;
}
@@ -4420,15 +4429,8 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
chip = gpiod_to_chip(desc);
hwnum = gpio_chip_hwgpio(desc);
- /*
- * FIXME: not very elegant that we call gpiod_configure_flags()
- * twice here (once inside gpiochip_request_own_desc() and
- * again here), but the gpiochip_request_own_desc() is external
- * and cannot really pass the lflags so this is the lesser evil
- * at the moment. Pass zero as dflags on this first call so we
- * don't screw anything up.
- */
- local_desc = gpiochip_request_own_desc(chip, hwnum, name, 0);
+ local_desc = gpiochip_request_own_desc(chip, hwnum, name,
+ lflags, dflags);
if (IS_ERR(local_desc)) {
status = PTR_ERR(local_desc);
pr_err("requesting hog GPIO %s (chip %s, offset %d) failed, %d\n",
@@ -4436,14 +4438,6 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
return status;
}
- status = gpiod_configure_flags(desc, name, lflags, dflags);
- if (status < 0) {
- pr_err("setup of hog GPIO %s (chip %s, offset %d) failed, %d\n",
- name, chip->label, hwnum, status);
- gpiochip_free_own_desc(desc);
- return status;
- }
-
/* Mark GPIO as hogged so it can be identified and removed later */
set_bit(FLAG_IS_HOGGED, &desc->flags);
@@ -4805,8 +4799,8 @@ static const struct file_operations gpiolib_operations = {
static int __init gpiolib_debugfs_init(void)
{
/* /sys/kernel/debug/gpio */
- (void) debugfs_create_file("gpio", S_IFREG | S_IRUGO,
- NULL, NULL, &gpiolib_operations);
+ debugfs_create_file("gpio", S_IFREG | S_IRUGO, NULL, NULL,
+ &gpiolib_operations);
return 0;
}
subsys_initcall(gpiolib_debugfs_init);
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index 7a65dad43932..7c52c2442173 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -210,7 +210,7 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
struct gpio_array *array_info,
unsigned long *value_bitmap);
-extern struct spinlock gpio_lock;
+extern spinlock_t gpio_lock;
extern struct list_head gpio_devices;
struct gpio_desc {
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index b9362b4f6353..1d80222587ad 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -141,7 +141,7 @@ config DRM_LOAD_EDID_FIRMWARE
monitor are unable to provide appropriate EDID data. Since this
feature is provided as a workaround for broken hardware, the
default case is N. Details and instructions how to build your own
- EDID data are given in Documentation/EDID/HOWTO.txt.
+ EDID data are given in Documentation/driver-api/edid.rst.
config DRM_DP_CEC
bool "Enable DisplayPort CEC-Tunneling-over-AUX HDMI support"
diff --git a/drivers/gpu/drm/amd/amdgpu/Kconfig b/drivers/gpu/drm/amd/amdgpu/Kconfig
index a04f2fc7bf37..f6e5c0282fc1 100644
--- a/drivers/gpu/drm/amd/amdgpu/Kconfig
+++ b/drivers/gpu/drm/amd/amdgpu/Kconfig
@@ -27,8 +27,7 @@ config DRM_AMDGPU_CIK
config DRM_AMDGPU_USERPTR
bool "Always enable userptr write support"
depends on DRM_AMDGPU
- depends on ARCH_HAS_HMM
- select HMM_MIRROR
+ depends on HMM_MIRROR
help
This option selects CONFIG_HMM and CONFIG_HMM_MIRROR if it
isn't already selected to enabled full userptr support.
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
index 2bb9420b77a1..e51b48ac48eb 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -819,7 +819,7 @@ int amdgpu_ttm_tt_get_user_pages(struct amdgpu_bo *bo, struct page **pages)
0 : range->flags[HMM_PFN_WRITE];
range->pfn_flags_mask = 0;
range->pfns = pfns;
- hmm_range_register(range, mm, start,
+ hmm_range_register(range, mirror, start,
start + ttm->num_pages * PAGE_SIZE, PAGE_SHIFT);
retry:
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
index f91126f5f1be..26b15cc56c31 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
@@ -839,7 +839,7 @@ static int kfd_ioctl_get_clock_counters(struct file *filep,
/* No access to rdtsc. Using raw monotonic time */
args->cpu_clock_counter = ktime_get_raw_ns();
- args->system_clock_counter = ktime_get_boot_ns();
+ args->system_clock_counter = ktime_get_boottime_ns();
/* Since the counter is in nano-seconds we use 1GHz frequency */
args->system_clock_freq = 1000000000;
diff --git a/drivers/gpu/drm/armada/armada_510.c b/drivers/gpu/drm/armada/armada_510.c
index 6f8ad8fb19f1..93d5c0a2d49a 100644
--- a/drivers/gpu/drm/armada/armada_510.c
+++ b/drivers/gpu/drm/armada/armada_510.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Russell King
*
- * 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.
- *
* Armada 510 (aka Dove) variant support
*/
#include <linux/clk.h>
diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c
index 2e17d7e72eeb..d44fca4e1655 100644
--- a/drivers/gpu/drm/armada/armada_crtc.c
+++ b/drivers/gpu/drm/armada/armada_crtc.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Russell King
* Rewritten from the dovefb driver, and Armada510 manuals.
- *
- * 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.
*/
#include <linux/clk.h>
#include <linux/component.h>
diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h
index fb4aa48da60c..b21267d1745f 100644
--- a/drivers/gpu/drm/armada/armada_crtc.h
+++ b/drivers/gpu/drm/armada/armada_crtc.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2012 Russell King
- *
- * 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.
*/
#ifndef ARMADA_CRTC_H
#define ARMADA_CRTC_H
diff --git a/drivers/gpu/drm/armada/armada_debugfs.c b/drivers/gpu/drm/armada/armada_debugfs.c
index 4dcce002ea2a..dc3716dbb2c0 100644
--- a/drivers/gpu/drm/armada/armada_debugfs.c
+++ b/drivers/gpu/drm/armada/armada_debugfs.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Russell King
* Rewritten from the dovefb driver, and Armada510 manuals.
- *
- * 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.
*/
#include <linux/ctype.h>
#include <linux/debugfs.h>
diff --git a/drivers/gpu/drm/armada/armada_drm.h b/drivers/gpu/drm/armada/armada_drm.h
index b6307235f320..c7794c8bdd90 100644
--- a/drivers/gpu/drm/armada/armada_drm.h
+++ b/drivers/gpu/drm/armada/armada_drm.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2012 Russell King
- *
- * 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.
*/
#ifndef ARMADA_DRM_H
#define ARMADA_DRM_H
diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c
index f1729398b1bd..521464f08ccd 100644
--- a/drivers/gpu/drm/armada/armada_drv.c
+++ b/drivers/gpu/drm/armada/armada_drv.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Russell King
- *
- * 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.
*/
#include <linux/clk.h>
#include <linux/component.h>
diff --git a/drivers/gpu/drm/armada/armada_fb.c b/drivers/gpu/drm/armada/armada_fb.c
index a2f6472eb482..de030cb0aa90 100644
--- a/drivers/gpu/drm/armada/armada_fb.c
+++ b/drivers/gpu/drm/armada/armada_fb.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Russell King
- *
- * 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.
*/
#include <drm/drm_modeset_helper.h>
#include <drm/drm_fb_helper.h>
diff --git a/drivers/gpu/drm/armada/armada_fb.h b/drivers/gpu/drm/armada/armada_fb.h
index 476daad0a36a..7dda5f2a0af4 100644
--- a/drivers/gpu/drm/armada/armada_fb.h
+++ b/drivers/gpu/drm/armada/armada_fb.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2012 Russell King
- *
- * 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.
*/
#ifndef ARMADA_FB_H
#define ARMADA_FB_H
diff --git a/drivers/gpu/drm/armada/armada_fbdev.c b/drivers/gpu/drm/armada/armada_fbdev.c
index 1e7140f005a5..096aff530b01 100644
--- a/drivers/gpu/drm/armada/armada_fbdev.c
+++ b/drivers/gpu/drm/armada/armada_fbdev.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Russell King
* Written from the i915 driver.
- *
- * 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.
*/
#include <linux/errno.h>
#include <linux/kernel.h>
diff --git a/drivers/gpu/drm/armada/armada_gem.c b/drivers/gpu/drm/armada/armada_gem.c
index 642d0e70d0f8..874b2968a866 100644
--- a/drivers/gpu/drm/armada/armada_gem.c
+++ b/drivers/gpu/drm/armada/armada_gem.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Russell King
- *
- * 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.
*/
#include <linux/dma-buf.h>
#include <linux/dma-mapping.h>
diff --git a/drivers/gpu/drm/armada/armada_gem.h b/drivers/gpu/drm/armada/armada_gem.h
index 1ac90792b166..1dd80540b8ce 100644
--- a/drivers/gpu/drm/armada/armada_gem.h
+++ b/drivers/gpu/drm/armada/armada_gem.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2012 Russell King
- *
- * 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.
*/
#ifndef ARMADA_GEM_H
#define ARMADA_GEM_H
diff --git a/drivers/gpu/drm/armada/armada_hw.h b/drivers/gpu/drm/armada/armada_hw.h
index 5b1af0cc9f50..9c88b38a4003 100644
--- a/drivers/gpu/drm/armada/armada_hw.h
+++ b/drivers/gpu/drm/armada/armada_hw.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2012 Russell King
* Rewritten from the dovefb driver, and Armada510 manuals.
- *
- * 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.
*/
#ifndef ARMADA_HW_H
#define ARMADA_HW_H
diff --git a/drivers/gpu/drm/armada/armada_ioctlP.h b/drivers/gpu/drm/armada/armada_ioctlP.h
index bd8c4562066c..c266a01d697c 100644
--- a/drivers/gpu/drm/armada/armada_ioctlP.h
+++ b/drivers/gpu/drm/armada/armada_ioctlP.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2012 Russell King
- *
- * 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.
*/
#ifndef ARMADA_IOCTLP_H
#define ARMADA_IOCTLP_H
diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c
index a79d6e940435..e8060216b389 100644
--- a/drivers/gpu/drm/armada/armada_overlay.c
+++ b/drivers/gpu/drm/armada/armada_overlay.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Russell King
* Rewritten from the dovefb driver, and Armada510 manuals.
- *
- * 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.
*/
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
diff --git a/drivers/gpu/drm/armada/armada_plane.c b/drivers/gpu/drm/armada/armada_plane.c
index dbd4d52e8a32..f08b4f37816d 100644
--- a/drivers/gpu/drm/armada/armada_plane.c
+++ b/drivers/gpu/drm/armada/armada_plane.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Russell King
* Rewritten from the dovefb driver, and Armada510 manuals.
- *
- * 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.
*/
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
index 81c50772df05..6c6c7cf3c3e8 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
@@ -1,21 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 Traphandler
* Copyright (C) 2014 Free Electrons
*
* Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
* Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/clk.h>
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
index fb2e7646daeb..9bab6e5ba76b 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 Traphandler
* Copyright (C) 2014 Free Electrons
@@ -5,18 +6,6 @@
*
* Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
* Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/clk.h>
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
index 0155efb9c443..7300e3fd273e 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2014 Traphandler
* Copyright (C) 2014 Free Electrons
@@ -5,18 +6,6 @@
*
* Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
* Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DRM_ATMEL_HLCDC_H
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
index f73d8a92274e..7e08318b262e 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 Traphandler
* Copyright (C) 2014 Free Electrons
@@ -5,18 +6,6 @@
*
* Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
* Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/of_graph.h>
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
index 0ee5b7a3a4b0..4127aca212bb 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 Free Electrons
* Copyright (C) 2014 Atmel
*
* Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "atmel_hlcdc_dc.h"
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
index 0cf27c731727..e284ee8da58b 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Register definition file for Analogix DP core driver
*
* Copyright (C) 2012 Samsung Electronics Co., Ltd.
* Author: Jingoo Han <jg1.han@samsung.com>
- *
- * 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.
*/
#ifndef _ANALOGIX_DP_REG_H
diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c
index 0cc293a6ac24..bd3165ee5354 100644
--- a/drivers/gpu/drm/bridge/sil-sii8620.c
+++ b/drivers/gpu/drm/bridge/sil-sii8620.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Silicon Image SiI8620 HDMI/MHL bridge driver
*
* Copyright (C) 2015, Samsung Electronics Co., Ltd.
* Andrzej Hajda <a.hajda@samsung.com>
- *
- * 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.
*/
#include <asm/unaligned.h>
diff --git a/drivers/gpu/drm/bridge/sil-sii8620.h b/drivers/gpu/drm/bridge/sil-sii8620.h
index 51ab540cf092..79d61caf383f 100644
--- a/drivers/gpu/drm/bridge/sil-sii8620.h
+++ b/drivers/gpu/drm/bridge/sil-sii8620.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Registers of Silicon Image SiI8620 Mobile HD Transmitter
*
@@ -6,10 +7,6 @@
*
* Based on MHL driver for Android devices.
* Copyright (C) 2013-2014 Silicon Image, 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.
*/
#ifndef __SIL_SII8620_H__
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c
index ed7af7518b52..a494186ae6ce 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* DesignWare HDMI audio driver
*
- * 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.
- *
* Written and tested against the Designware HDMI Tx found in iMX6.
*/
#include <linux/io.h>
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
index 6c323510f128..0f949978d3fc 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Designware HDMI CEC driver
*
* Copyright (C) 2015-2017 Russell King.
- *
- * 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.
*/
#include <linux/interrupt.h>
#include <linux/io.h>
diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c
index 4e76b2b27374..dbf35c7bc85e 100644
--- a/drivers/gpu/drm/bridge/ti-tfp410.c
+++ b/drivers/gpu/drm/bridge/ti-tfp410.c
@@ -1,11 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2016 Texas Instruments
* Author: Jyri Sarha <jsarha@ti.com>
- *
- * 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.
- *
*/
#include <linux/delay.h>
diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c
index 68dacf8422c6..8ce9d73fab4f 100644
--- a/drivers/gpu/drm/drm_bufs.c
+++ b/drivers/gpu/drm/drm_bufs.c
@@ -1351,7 +1351,10 @@ static int copy_one_buf(void *data, int count, struct drm_buf_entry *from)
.size = from->buf_size,
.low_mark = from->low_mark,
.high_mark = from->high_mark};
- return copy_to_user(to, &v, offsetof(struct drm_buf_desc, flags));
+
+ if (copy_to_user(to, &v, offsetof(struct drm_buf_desc, flags)))
+ return -EFAULT;
+ return 0;
}
int drm_legacy_infobufs(struct drm_device *dev, void *data,
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index fe0ce86c280f..9d00947ca447 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -31,6 +31,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/mount.h>
+#include <linux/pseudo_fs.h>
#include <linux/slab.h>
#include <linux/srcu.h>
@@ -535,28 +536,15 @@ EXPORT_SYMBOL(drm_dev_unplug);
static int drm_fs_cnt;
static struct vfsmount *drm_fs_mnt;
-static const struct dentry_operations drm_fs_dops = {
- .d_dname = simple_dname,
-};
-
-static const struct super_operations drm_fs_sops = {
- .statfs = simple_statfs,
-};
-
-static struct dentry *drm_fs_mount(struct file_system_type *fs_type, int flags,
- const char *dev_name, void *data)
+static int drm_fs_init_fs_context(struct fs_context *fc)
{
- return mount_pseudo(fs_type,
- "drm:",
- &drm_fs_sops,
- &drm_fs_dops,
- 0x010203ff);
+ return init_pseudo(fc, 0x010203ff) ? 0 : -ENOMEM;
}
static struct file_system_type drm_fs_type = {
.name = "drm",
.owner = THIS_MODULE,
- .mount = drm_fs_mount,
+ .init_fs_context = drm_fs_init_fs_context,
.kill_sb = kill_anon_super,
};
diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c
index 586aa28024c5..a16b6dc2fa47 100644
--- a/drivers/gpu/drm/drm_ioc32.c
+++ b/drivers/gpu/drm/drm_ioc32.c
@@ -378,7 +378,10 @@ static int copy_one_buf32(void *data, int count, struct drm_buf_entry *from)
.size = from->buf_size,
.low_mark = from->low_mark,
.high_mark = from->high_mark};
- return copy_to_user(to + count, &v, offsetof(drm_buf_desc32_t, flags));
+
+ if (copy_to_user(to + count, &v, offsetof(drm_buf_desc32_t, flags)))
+ return -EFAULT;
+ return 0;
}
static int drm_legacy_infobufs32(struct drm_device *dev, void *data,
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index 9441a36a2469..bd810454d239 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -736,7 +736,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
* };
*
* Please make sure that you follow all the best practices from
- * ``Documentation/ioctl/botching-up-ioctls.txt``. Note that drm_ioctl()
+ * ``Documentation/ioctl/botching-up-ioctls.rst``. Note that drm_ioctl()
* automatically zero-extends structures, hence make sure you can add more stuff
* at the end, i.e. don't put a variable sized array there.
*
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c
index 80b75501f5c6..ad19df0686c9 100644
--- a/drivers/gpu/drm/drm_mipi_dsi.c
+++ b/drivers/gpu/drm/drm_mipi_dsi.c
@@ -93,7 +93,7 @@ static struct bus_type mipi_dsi_bus_type = {
.pm = &mipi_dsi_device_pm_ops,
};
-static int of_device_match(struct device *dev, void *data)
+static int of_device_match(struct device *dev, const void *data)
{
return dev->of_node == data;
}
diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c
index 53187821df01..fcfe1a03c4a1 100644
--- a/drivers/gpu/drm/drm_modeset_lock.c
+++ b/drivers/gpu/drm/drm_modeset_lock.c
@@ -36,7 +36,7 @@
* of extra utility/tracking out of our acquire-ctx. This is provided
* by &struct drm_modeset_lock and &struct drm_modeset_acquire_ctx.
*
- * For basic principles of &ww_mutex, see: Documentation/locking/ww-mutex-design.txt
+ * For basic principles of &ww_mutex, see: Documentation/locking/ww-mutex-design.rst
*
* The basic usage pattern is to::
*
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
index e054f09ac828..1a636469eeda 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2015 Etnaviv Project
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/dma-fence-array.h>
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index 72d01e873160..5418a1a87b2c 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -760,7 +760,7 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
if (IS_ERR(gpu->cmdbuf_suballoc)) {
dev_err(gpu->dev, "Failed to create cmdbuf suballocator\n");
ret = PTR_ERR(gpu->cmdbuf_suballoc);
- goto fail;
+ goto destroy_iommu;
}
/* Create buffer: */
@@ -768,7 +768,7 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
PAGE_SIZE);
if (ret) {
dev_err(gpu->dev, "could not create command buffer\n");
- goto destroy_iommu;
+ goto destroy_suballoc;
}
if (gpu->mmu->version == ETNAVIV_IOMMU_V1 &&
@@ -800,6 +800,9 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
free_buffer:
etnaviv_cmdbuf_free(&gpu->buffer);
gpu->buffer.suballoc = NULL;
+destroy_suballoc:
+ etnaviv_cmdbuf_suballoc_destroy(gpu->cmdbuf_suballoc);
+ gpu->cmdbuf_suballoc = NULL;
destroy_iommu:
etnaviv_iommu_destroy(gpu->mmu);
gpu->mmu = NULL;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
index 87289db12868..3cebb19ec1c4 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Exynos DRM Parallel output support.
*
* Copyright (c) 2014 Samsung Electronics Co., Ltd
*
* Contacts: Andrzej Hajda <a.hajda@samsung.com>
- *
- * 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.
*/
#include <linux/of_graph.h>
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 5f6f523821a2..6926cee91b36 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Samsung SoC MIPI DSI Master driver.
*
* Copyright (c) 2014 Samsung Electronics Co., Ltd
*
* Contacts: Tomasz Figa <t.figa@samsung.com>
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/gpu/drm/exynos/regs-fimc.h b/drivers/gpu/drm/exynos/regs-fimc.h
index d7cbe53c4c01..98e4bc18f160 100644
--- a/drivers/gpu/drm/exynos/regs-fimc.h
+++ b/drivers/gpu/drm/exynos/regs-fimc.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/* drivers/gpu/drm/exynos/regs-fimc.h
*
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
* Register definition file for Samsung Camera Interface (FIMC) driver
- *
- * 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.
*/
#ifndef EXYNOS_REGS_FIMC_H
diff --git a/drivers/gpu/drm/exynos/regs-gsc.h b/drivers/gpu/drm/exynos/regs-gsc.h
index 16b39734115c..9e203cab93b8 100644
--- a/drivers/gpu/drm/exynos/regs-gsc.h
+++ b/drivers/gpu/drm/exynos/regs-gsc.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/* linux/drivers/gpu/drm/exynos/regs-gsc.h
*
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Register definition file for Samsung G-Scaler driver
- *
- * 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.
*/
#ifndef EXYNOS_REGS_GSC_H_
diff --git a/drivers/gpu/drm/exynos/regs-hdmi.h b/drivers/gpu/drm/exynos/regs-hdmi.h
index 4420c203ac85..8496f230c0f0 100644
--- a/drivers/gpu/drm/exynos/regs-hdmi.h
+++ b/drivers/gpu/drm/exynos/regs-hdmi.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
*
* Cloned from drivers/media/video/s5p-tv/regs-hdmi.h
@@ -6,10 +7,6 @@
* http://www.samsung.com/
*
* HDMI register header file for Samsung TVOUT driver
- *
- * 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.
*/
#ifndef SAMSUNG_REGS_HDMI_H
diff --git a/drivers/gpu/drm/exynos/regs-mixer.h b/drivers/gpu/drm/exynos/regs-mixer.h
index 5ff095b0c1b3..85ca66b8949b 100644
--- a/drivers/gpu/drm/exynos/regs-mixer.h
+++ b/drivers/gpu/drm/exynos/regs-mixer.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
*
* Cloned from drivers/media/video/s5p-tv/regs-mixer.h
@@ -6,10 +7,6 @@
* http://www.samsung.com/
*
* Mixer register header file for Samsung Mixer driver
- *
- * 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.
*/
#ifndef SAMSUNG_REGS_MIXER_H
#define SAMSUNG_REGS_MIXER_H
diff --git a/drivers/gpu/drm/exynos/regs-rotator.h b/drivers/gpu/drm/exynos/regs-rotator.h
index a09ac6e180da..e6559f565547 100644
--- a/drivers/gpu/drm/exynos/regs-rotator.h
+++ b/drivers/gpu/drm/exynos/regs-rotator.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/* drivers/gpu/drm/exynos/regs-rotator.h
*
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
* Register definition file for Samsung Rotator Interface (Rotator) driver
- *
- * 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.
*/
#ifndef EXYNOS_REGS_ROTATOR_H
diff --git a/drivers/gpu/drm/exynos/regs-scaler.h b/drivers/gpu/drm/exynos/regs-scaler.h
index 512a2baced11..654c5f85f00b 100644
--- a/drivers/gpu/drm/exynos/regs-scaler.h
+++ b/drivers/gpu/drm/exynos/regs-scaler.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/* drivers/gpu/drm/exynos/regs-scaler.h
*
* Copyright (c) 2017 Samsung Electronics Co., Ltd.
@@ -5,10 +6,6 @@
* Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
*
* Register definition file for Samsung scaler driver
- *
- * 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.
*/
#ifndef EXYNOS_REGS_SCALER_H
diff --git a/drivers/gpu/drm/exynos/regs-vp.h b/drivers/gpu/drm/exynos/regs-vp.h
index 10b737af0a72..43c927e65c2b 100644
--- a/drivers/gpu/drm/exynos/regs-vp.h
+++ b/drivers/gpu/drm/exynos/regs-vp.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
*
* Cloned from drivers/media/video/s5p-tv/regs-vp.h
@@ -6,10 +7,6 @@
* http://www.samsung.com/
*
* Video processor register header file for Samsung Mixer driver
- *
- * 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.
*/
#ifndef SAMSUNG_REGS_VP_H
diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
index 3d6c45097f51..5bf8138941de 100644
--- a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
+++ b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* DesignWare MIPI DSI Host Controller v1.02 driver
*
@@ -8,11 +9,6 @@
* Xinliang Liu <z.liuxinliang@hisilicon.com>
* Xinliang Liu <xinliang.liu@linaro.org>
* Xinwei Kong <kong.kongxinwei@hisilicon.com>
- *
- * 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.
- *
*/
#include <linux/clk.h>
diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_dsi_reg.h b/drivers/gpu/drm/hisilicon/kirin/dw_dsi_reg.h
index 18808fc9f362..19e81ff64fac 100644
--- a/drivers/gpu/drm/hisilicon/kirin/dw_dsi_reg.h
+++ b/drivers/gpu/drm/hisilicon/kirin/dw_dsi_reg.h
@@ -1,11 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2016 Linaro Limited.
* Copyright (c) 2014-2016 Hisilicon Limited.
- *
- * 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.
- *
*/
#ifndef __DW_DSI_REG_H__
diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h b/drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h
index 4cf281b7ed63..e2ac09894a6d 100644
--- a/drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h
+++ b/drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h
@@ -1,11 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2016 Linaro Limited.
* Copyright (c) 2014-2016 Hisilicon Limited.
- *
- * 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.
- *
*/
#ifndef __KIRIN_ADE_REG_H__
diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
index 73611a92d96c..ad7042ae2241 100644
--- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
+++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Hisilicon Hi6220 SoC ADE(Advanced Display Engine)'s crtc&plane driver
*
@@ -8,11 +9,6 @@
* Xinliang Liu <z.liuxinliang@hisilicon.com>
* Xinliang Liu <xinliang.liu@linaro.org>
* Xinwei Kong <kong.kongxinwei@hisilicon.com>
- *
- * 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.
- *
*/
#include <linux/bitops.h>
diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c
index 7cb7c042b93f..4a7fe10a37cb 100644
--- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Hisilicon Kirin SoCs drm master driver
*
@@ -8,11 +9,6 @@
* Xinliang Liu <z.liuxinliang@hisilicon.com>
* Xinliang Liu <xinliang.liu@linaro.org>
* Xinwei Kong <kong.kongxinwei@hisilicon.com>
- *
- * 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.
- *
*/
#include <linux/of_platform.h>
diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h
index ad027d1cc826..22d1291668cd 100644
--- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h
@@ -1,11 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2016 Linaro Limited.
* Copyright (c) 2014-2016 Hisilicon Limited.
- *
- * 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.
- *
*/
#ifndef __KIRIN_DRM_DRV_H__
diff --git a/drivers/gpu/drm/i2c/tda9950.c b/drivers/gpu/drm/i2c/tda9950.c
index 250b5e02a314..8039fc0d83db 100644
--- a/drivers/gpu/drm/i2c/tda9950.c
+++ b/drivers/gpu/drm/i2c/tda9950.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TDA9950 Consumer Electronics Control driver
*
- * 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.
- *
* The NXP TDA9950 implements the HDMI Consumer Electronics Control
* interface. The host interface is similar to a mailbox: the data
* registers starting at REG_CDR0 are written to send a command to the
diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
index 3d368c43185f..61e042918a7f 100644
--- a/drivers/gpu/drm/i2c/tda998x_drv.c
+++ b/drivers/gpu/drm/i2c/tda998x_drv.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Texas Instruments
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/component.h>
diff --git a/drivers/gpu/drm/i915/.gitignore b/drivers/gpu/drm/i915/.gitignore
deleted file mode 100644
index cff45d81f42f..000000000000
--- a/drivers/gpu/drm/i915/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-header_test_*.c
diff --git a/drivers/gpu/drm/i915/Makefile.header-test b/drivers/gpu/drm/i915/Makefile.header-test
index e6ba66f787f9..7cde0ec34615 100644
--- a/drivers/gpu/drm/i915/Makefile.header-test
+++ b/drivers/gpu/drm/i915/Makefile.header-test
@@ -2,7 +2,7 @@
# Copyright © 2019 Intel Corporation
# Test the headers are compilable as standalone units
-header_test := \
+header-test-$(CONFIG_DRM_I915_WERROR) := \
i915_active_types.h \
i915_debugfs.h \
i915_drv.h \
@@ -20,13 +20,3 @@ header_test := \
intel_sideband.h \
intel_uncore.h \
intel_wakeref.h
-
-quiet_cmd_header_test = HDRTEST $@
- cmd_header_test = echo "\#include \"$(<F)\"" > $@
-
-header_test_%.c: %.h
- $(call cmd,header_test)
-
-i915-$(CONFIG_DRM_I915_WERROR) += $(foreach h,$(header_test),$(patsubst %.h,header_test_%.o,$(h)))
-
-clean-files += $(foreach h,$(header_test),$(patsubst %.h,header_test_%.c,$(h)))
diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c
index a6ade66349bd..25f78196b964 100644
--- a/drivers/gpu/drm/i915/gvt/handlers.c
+++ b/drivers/gpu/drm/i915/gvt/handlers.c
@@ -1254,18 +1254,15 @@ static int send_display_ready_uevent(struct intel_vgpu *vgpu, int ready)
static int pvinfo_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,
void *p_data, unsigned int bytes)
{
- u32 data;
- int ret;
-
- write_vreg(vgpu, offset, p_data, bytes);
- data = vgpu_vreg(vgpu, offset);
+ u32 data = *(u32 *)p_data;
+ bool invalid_write = false;
switch (offset) {
case _vgtif_reg(display_ready):
send_display_ready_uevent(vgpu, data ? 1 : 0);
break;
case _vgtif_reg(g2v_notify):
- ret = handle_g2v_notification(vgpu, data);
+ handle_g2v_notification(vgpu, data);
break;
/* add xhot and yhot to handled list to avoid error log */
case _vgtif_reg(cursor_x_hot):
@@ -1282,13 +1279,19 @@ static int pvinfo_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,
case _vgtif_reg(execlist_context_descriptor_hi):
break;
case _vgtif_reg(rsv5[0])..._vgtif_reg(rsv5[3]):
+ invalid_write = true;
enter_failsafe_mode(vgpu, GVT_FAILSAFE_INSUFFICIENT_RESOURCE);
break;
default:
+ invalid_write = true;
gvt_vgpu_err("invalid pvinfo write offset %x bytes %x data %x\n",
offset, bytes, data);
break;
}
+
+ if (!invalid_write)
+ write_vreg(vgpu, offset, p_data, bytes);
+
return 0;
}
diff --git a/drivers/gpu/drm/i915/i915_mm.c b/drivers/gpu/drm/i915/i915_mm.c
index e4935dd1fd37..c23bb29e6d3e 100644
--- a/drivers/gpu/drm/i915/i915_mm.c
+++ b/drivers/gpu/drm/i915/i915_mm.c
@@ -35,8 +35,7 @@ struct remap_pfn {
pgprot_t prot;
};
-static int remap_pfn(pte_t *pte, pgtable_t token,
- unsigned long addr, void *data)
+static int remap_pfn(pte_t *pte, unsigned long addr, void *data)
{
struct remap_pfn *r = data;
diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c
index 3d8162d28730..a700c5c3d167 100644
--- a/drivers/gpu/drm/i915/i915_perf.c
+++ b/drivers/gpu/drm/i915/i915_perf.c
@@ -274,8 +274,6 @@
#define POLL_PERIOD (NSEC_PER_SEC / POLL_FREQUENCY)
/* for sysctl proc_dointvec_minmax of dev.i915.perf_stream_paranoid */
-static int zero;
-static int one = 1;
static u32 i915_perf_stream_paranoid = true;
/* The maximum exponent the hardware accepts is 63 (essentially it selects one
@@ -3366,8 +3364,8 @@ static struct ctl_table oa_table[] = {
.maxlen = sizeof(i915_perf_stream_paranoid),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
- .extra1 = &zero,
- .extra2 = &one,
+ .extra1 = SYSCTL_ZERO,
+ .extra2 = SYSCTL_ONE,
},
{
.procname = "oa_max_sample_rate",
@@ -3375,7 +3373,7 @@ static struct ctl_table oa_table[] = {
.maxlen = sizeof(i915_oa_max_sample_rate),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
- .extra1 = &zero,
+ .extra1 = SYSCTL_ZERO,
.extra2 = &oa_sample_rate_hard_limit,
},
{}
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.h b/drivers/gpu/drm/i915/intel_runtime_pm.h
index 473c4850c01d..2ee8f9522e05 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.h
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.h
@@ -45,7 +45,7 @@ enum i915_drm_suspend_mode {
* to be disabled. This shouldn't happen and we'll print some error messages in
* case it happens.
*
- * For more, read the Documentation/power/runtime_pm.txt.
+ * For more, read the Documentation/power/runtime_pm.rst.
*/
struct intel_runtime_pm {
atomic_t wakeref_count;
diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c
index 9cc1d678674f..c436a28d50e4 100644
--- a/drivers/gpu/drm/imx/ipuv3-crtc.c
+++ b/drivers/gpu/drm/imx/ipuv3-crtc.c
@@ -91,14 +91,14 @@ static void ipu_crtc_atomic_disable(struct drm_crtc *crtc,
ipu_dc_disable(ipu);
ipu_prg_disable(ipu);
+ drm_crtc_vblank_off(crtc);
+
spin_lock_irq(&crtc->dev->event_lock);
- if (crtc->state->event) {
+ if (crtc->state->event && !crtc->state->active) {
drm_crtc_send_vblank_event(crtc, crtc->state->event);
crtc->state->event = NULL;
}
spin_unlock_irq(&crtc->dev->event_lock);
-
- drm_crtc_vblank_off(crtc);
}
static void imx_drm_crtc_reset(struct drm_crtc *crtc)
diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
index 13078c4975ff..5f7e98028eaf 100644
--- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
*
* Copyright (c) 2014 The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef CONFIG_MSM_OCMEM
diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.h b/drivers/gpu/drm/msm/adreno/a3xx_gpu.h
index ab60dc9e344e..5dc33e5ea53b 100644
--- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.h
@@ -1,18 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __A3XX_GPU_H__
diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c
index 5bcc169c1189..40133a43960c 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_device.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_device.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013-2014 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
*
* Copyright (c) 2014,2017 The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "adreno_gpu.h"
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
index 3db8e499d4c5..9acbbc0f3232 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
*
* Copyright (c) 2014 The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/ascii85.h>
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
index d67c1a69c49a..c7441fb8313e 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
@@ -1,20 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
*
* Copyright (c) 2014,2017 The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ADRENO_GPU_H__
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index 40ea6286eac1..b3417d56032d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014-2018 The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
index e59d62be4980..5181f079a6a1 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
@@ -1,19 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2015-2018 The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _DPU_CRTC_H_
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 1cf4e306fccf..0e2f74163a16 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
index d77f74fb26d4..a8bf1147fc56 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
@@ -1,19 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __DPU_ENCODER_H__
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index 435b846f9f52..bb9d44e7bd26 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
index e9f998344838..9e40f559c51f 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
@@ -1,19 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __DPU_KMS_H__
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
index 1858b40b18d8..45bfac9e3af7 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014-2018 The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
index 0e6063acd041..456949713e90 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
@@ -1,19 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _DPU_PLANE_H_
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c
index 0cfd4c06b610..668c41975d74 100644
--- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <drm/drm_crtc.h>
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c
index caa39b4621e3..772f0753ed38 100644
--- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
* Copyright (c) 2014, Inforce Computing. All rights reserved.
*
* Author: Vinay Simha <vinaysimha@inforcecomputing.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <drm/drm_crtc.h>
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c
index 259d51971401..5d8956055286 100644
--- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <drm/drm_crtc.h>
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c
index b764d7f10312..62fbca302ac2 100644
--- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <drm/drm_print.h>
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c
index e437aa806f7b..7a9ab55b4608 100644
--- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.h b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.h
index 0c13f8697bfe..18933bd81c77 100644
--- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.h
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.h
@@ -1,18 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __MDP4_KMS_H__
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c
index df6f9803a1d7..62e2ebe455ea 100644
--- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
* Author: Vinay Simha <vinaysimha@inforcecomputing.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <drm/drm_crtc.h>
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c
index 5368e621999c..ecef4f5b9f26 100644
--- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
* Author: Vinay Simha <vinaysimha@inforcecomputing.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/gpio.h>
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_pll.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_pll.c
index ce4245971673..ab8c0c187fb2 100644
--- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_pll.c
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_pll.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/clk.h>
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c
index 2d46d1126283..e3010f023371 100644
--- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <drm/drm_damage_helper.h>
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c
index c3751c95b452..ff14555372d0 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/sort.h>
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c
index 820a62c40063..f48827283c2b 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014, The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <drm/drm_crtc.h>
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c
index 280e368bc9bb..58db08a2abfa 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/irq.h>
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
index 1c55401956c4..4a60f5fca6b0 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014, The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/interconnect.h>
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.h
index 854dfd30e829..d1bf4fdfc815 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.h
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.h
@@ -1,18 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __MDP5_KMS_H__
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c
index 889c2940692c..09bd46ad820b 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2016, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/irqdomain.h>
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.c
index 113e6b569562..954db683ae44 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2017 The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "mdp5_kms.h"
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.h
index 9be94f567fbd..43c9ba43ce18 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.h
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.h
@@ -1,17 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2017 The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __MDP5_LM_H__
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c
index 1ef26bc63163..ba6695963aa6 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2016 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "mdp5_kms.h"
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.h
index bb2b0ac7aa2b..9b26d0761bd4 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.h
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.h
@@ -1,18 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2016 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __MDP5_PIPE_H__
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c
index 91609bde033a..c7e6725693ea 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014-2015 The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <drm/drm_damage_helper.h>
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c
index 2834837f4d3e..776337f85a68 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014, The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <drm/drm_util.h>
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.h
index b41d0448fbe8..ba5618e136c3 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.h
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.h
@@ -1,19 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2014, The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __MDP5_SMP_H__
diff --git a/drivers/gpu/drm/msm/disp/mdp_format.c b/drivers/gpu/drm/msm/disp/mdp_format.c
index 005760bee708..8afb0f9c04bb 100644
--- a/drivers/gpu/drm/msm/disp/mdp_format.c
+++ b/drivers/gpu/drm/msm/disp/mdp_format.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014 The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
diff --git a/drivers/gpu/drm/msm/disp/mdp_kms.c b/drivers/gpu/drm/msm/disp/mdp_kms.c
index 64287304054d..3c35ccfc7331 100644
--- a/drivers/gpu/drm/msm/disp/mdp_kms.c
+++ b/drivers/gpu/drm/msm/disp/mdp_kms.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
diff --git a/drivers/gpu/drm/msm/disp/mdp_kms.h b/drivers/gpu/drm/msm/disp/mdp_kms.h
index 4fa8dbe4e165..1535c5618491 100644
--- a/drivers/gpu/drm/msm/disp/mdp_kms.h
+++ b/drivers/gpu/drm/msm/disp/mdp_kms.h
@@ -1,18 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __MDP_KMS_H__
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index e247d6942a49..0e4217be3f00 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014 The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/of_irq.h>
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
index 5c5df6ab2a57..982865866a29 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
@@ -1,18 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __HDMI_CONNECTOR_H__
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_audio.c b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
index 9c34b91ae329..4c2058c4adc1 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/hdmi.h>
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
index 03197b8959ba..c8dbd82854c2 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "hdmi.h"
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
index a6eeab2c4dc3..07b4cb877d82 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/gpio.h>
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_i2c.c b/drivers/gpu/drm/msm/hdmi/hdmi_i2c.c
index 25d2fe2c60e8..de182c004843 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_i2c.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_i2c.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "hdmi.h"
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c
index 0980da8ec966..cf90a0c1f822 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "hdmi.h"
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x60.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x60.c
index a68eea4153fc..1acc33ce9d52 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x60.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x60.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "hdmi.h"
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c
index 4a8b8468586a..a2a6940e195a 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "hdmi.h"
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c b/drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c
index c6dae6e437f9..e24a11d91945 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2016, The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/clk-provider.h>
diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c
index 131c23a267ee..dd16babdd8c0 100644
--- a/drivers/gpu/drm/msm/msm_atomic.c
+++ b/drivers/gpu/drm/msm/msm_atomic.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <drm/drm_atomic_uapi.h>
diff --git a/drivers/gpu/drm/msm/msm_debugfs.c b/drivers/gpu/drm/msm/msm_debugfs.c
index 67ef300559cf..a0a8df591e93 100644
--- a/drivers/gpu/drm/msm/msm_debugfs.c
+++ b/drivers/gpu/drm/msm/msm_debugfs.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013-2016 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef CONFIG_DEBUG_FS
diff --git a/drivers/gpu/drm/msm/msm_debugfs.h b/drivers/gpu/drm/msm/msm_debugfs.h
index f4077e344e3a..2b91f8c178ad 100644
--- a/drivers/gpu/drm/msm/msm_debugfs.h
+++ b/drivers/gpu/drm/msm/msm_debugfs.h
@@ -1,18 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2016 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __MSM_DEBUGFS_H__
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 229d49740677..ab64ab470de7 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kthread.h>
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index d9aa7bad454d..ee7b512dc158 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -1,19 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __MSM_DRV_H__
diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c
index a816ceb58716..5bcd5e502a6b 100644
--- a/drivers/gpu/drm/msm/msm_fb.c
+++ b/drivers/gpu/drm/msm/msm_fb.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <drm/drm_crtc.h>
diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c
index d088299babf3..2429d5e6ce9f 100644
--- a/drivers/gpu/drm/msm/msm_fbdev.c
+++ b/drivers/gpu/drm/msm/msm_fbdev.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <drm/drm_crtc.h>
diff --git a/drivers/gpu/drm/msm/msm_fence.c b/drivers/gpu/drm/msm/msm_fence.c
index 77263cf97b20..ad2703698b05 100644
--- a/drivers/gpu/drm/msm/msm_fence.c
+++ b/drivers/gpu/drm/msm/msm_fence.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013-2016 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/dma-fence.h>
diff --git a/drivers/gpu/drm/msm/msm_fence.h b/drivers/gpu/drm/msm/msm_fence.h
index b9fe059091f2..2d9af66dcca5 100644
--- a/drivers/gpu/drm/msm/msm_fence.h
+++ b/drivers/gpu/drm/msm/msm_fence.h
@@ -1,18 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2013-2016 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __MSM_FENCE_H__
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index d31d9f927887..8b78554cfde3 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/spinlock.h>
diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h
index 36aeb58c132b..8cfcf8f09e3e 100644
--- a/drivers/gpu/drm/msm/msm_gem.h
+++ b/drivers/gpu/drm/msm/msm_gem.h
@@ -1,18 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __MSM_GEM_H__
diff --git a/drivers/gpu/drm/msm/msm_gem_prime.c b/drivers/gpu/drm/msm/msm_gem_prime.c
index 60bb290700ce..5d64e0671f7a 100644
--- a/drivers/gpu/drm/msm/msm_gem_prime.c
+++ b/drivers/gpu/drm/msm/msm_gem_prime.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "msm_drv.h"
diff --git a/drivers/gpu/drm/msm/msm_gem_shrinker.c b/drivers/gpu/drm/msm/msm_gem_shrinker.c
index b72d8e6cd51d..722d61668a97 100644
--- a/drivers/gpu/drm/msm/msm_gem_shrinker.c
+++ b/drivers/gpu/drm/msm/msm_gem_shrinker.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2016 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "msm_drv.h"
diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c
index d3801bfa4407..348f8c2be806 100644
--- a/drivers/gpu/drm/msm/msm_gem_submit.c
+++ b/drivers/gpu/drm/msm/msm_gem_submit.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/sync_file.h>
diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c
index fcf7a83f0e6f..1af5354bcd46 100644
--- a/drivers/gpu/drm/msm/msm_gem_vma.c
+++ b/drivers/gpu/drm/msm/msm_gem_vma.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2016 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "msm_drv.h"
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index 0a4c77fb3d94..4edb874548b3 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "msm_gpu.h"
diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h
index f2739cd97cea..ab8f0f9c9dc8 100644
--- a/drivers/gpu/drm/msm/msm_gpu.h
+++ b/drivers/gpu/drm/msm/msm_gpu.h
@@ -1,18 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __MSM_GPU_H__
diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c
index 19263290b9b7..8c95c31e2b12 100644
--- a/drivers/gpu/drm/msm/msm_iommu.c
+++ b/drivers/gpu/drm/msm/msm_iommu.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "msm_drv.h"
diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h
index 2b81b43a4bab..c7588a42635e 100644
--- a/drivers/gpu/drm/msm/msm_kms.h
+++ b/drivers/gpu/drm/msm/msm_kms.h
@@ -1,19 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __MSM_KMS_H__
diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h
index d21b26604d0b..871d56303697 100644
--- a/drivers/gpu/drm/msm/msm_mmu.h
+++ b/drivers/gpu/drm/msm/msm_mmu.h
@@ -1,18 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __MSM_MMU_H__
diff --git a/drivers/gpu/drm/msm/msm_perf.c b/drivers/gpu/drm/msm/msm_perf.c
index 95948cfe7a12..490cadda2796 100644
--- a/drivers/gpu/drm/msm/msm_perf.c
+++ b/drivers/gpu/drm/msm/msm_perf.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* For profiling, userspace can:
diff --git a/drivers/gpu/drm/msm/msm_rd.c b/drivers/gpu/drm/msm/msm_rd.c
index 480d810037ce..76d3fdd17bf8 100644
--- a/drivers/gpu/drm/msm/msm_rd.c
+++ b/drivers/gpu/drm/msm/msm_rd.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* For debugging crashes, userspace can:
diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.c b/drivers/gpu/drm/msm/msm_ringbuffer.c
index 20a96fe69dcd..e397c44cc011 100644
--- a/drivers/gpu/drm/msm/msm_ringbuffer.c
+++ b/drivers/gpu/drm/msm/msm_ringbuffer.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "msm_ringbuffer.h"
diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.h b/drivers/gpu/drm/msm/msm_ringbuffer.h
index 6434ebb13136..7764373d0ed2 100644
--- a/drivers/gpu/drm/msm/msm_ringbuffer.h
+++ b/drivers/gpu/drm/msm/msm_ringbuffer.h
@@ -1,18 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __MSM_RINGBUFFER_H__
diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig
index dba2613f7180..96b9814e6d06 100644
--- a/drivers/gpu/drm/nouveau/Kconfig
+++ b/drivers/gpu/drm/nouveau/Kconfig
@@ -84,11 +84,11 @@ config DRM_NOUVEAU_BACKLIGHT
config DRM_NOUVEAU_SVM
bool "(EXPERIMENTAL) Enable SVM (Shared Virtual Memory) support"
- depends on ARCH_HAS_HMM
+ depends on DEVICE_PRIVATE
depends on DRM_NOUVEAU
+ depends on HMM_MIRROR
depends on STAGING
- select HMM_MIRROR
- select DEVICE_PRIVATE
+ select MIGRATE_VMA_HELPER
default n
help
Say Y here if you want to enable experimental support for
diff --git a/drivers/gpu/drm/nouveau/nouveau_dmem.c b/drivers/gpu/drm/nouveau/nouveau_dmem.c
index 745e197a4775..1333220787a1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dmem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dmem.c
@@ -72,7 +72,8 @@ struct nouveau_dmem_migrate {
};
struct nouveau_dmem {
- struct hmm_devmem *devmem;
+ struct nouveau_drm *drm;
+ struct dev_pagemap pagemap;
struct nouveau_dmem_migrate migrate;
struct list_head chunk_free;
struct list_head chunk_full;
@@ -80,6 +81,11 @@ struct nouveau_dmem {
struct mutex mutex;
};
+static inline struct nouveau_dmem *page_to_dmem(struct page *page)
+{
+ return container_of(page->pgmap, struct nouveau_dmem, pagemap);
+}
+
struct nouveau_dmem_fault {
struct nouveau_drm *drm;
struct nouveau_fence *fence;
@@ -96,14 +102,10 @@ struct nouveau_migrate {
unsigned long dma_nr;
};
-static void
-nouveau_dmem_free(struct hmm_devmem *devmem, struct page *page)
+static void nouveau_dmem_page_free(struct page *page)
{
- struct nouveau_dmem_chunk *chunk;
- unsigned long idx;
-
- chunk = (void *)hmm_devmem_page_get_drvdata(page);
- idx = page_to_pfn(page) - chunk->pfn_first;
+ struct nouveau_dmem_chunk *chunk = page->zone_device_data;
+ unsigned long idx = page_to_pfn(page) - chunk->pfn_first;
/*
* FIXME:
@@ -148,11 +150,12 @@ nouveau_dmem_fault_alloc_and_copy(struct vm_area_struct *vma,
if (!spage || !(src_pfns[i] & MIGRATE_PFN_MIGRATE))
continue;
- dpage = hmm_vma_alloc_locked_page(vma, addr);
+ dpage = alloc_page_vma(GFP_HIGHUSER, vma, addr);
if (!dpage) {
dst_pfns[i] = MIGRATE_PFN_ERROR;
continue;
}
+ lock_page(dpage);
dst_pfns[i] = migrate_pfn(page_to_pfn(dpage)) |
MIGRATE_PFN_LOCKED;
@@ -194,7 +197,7 @@ nouveau_dmem_fault_alloc_and_copy(struct vm_area_struct *vma,
dst_addr = fault->dma[fault->npages++];
- chunk = (void *)hmm_devmem_page_get_drvdata(spage);
+ chunk = spage->zone_device_data;
src_addr = page_to_pfn(spage) - chunk->pfn_first;
src_addr = (src_addr << PAGE_SHIFT) + chunk->bo->bo.offset;
@@ -259,29 +262,21 @@ static const struct migrate_vma_ops nouveau_dmem_fault_migrate_ops = {
.finalize_and_map = nouveau_dmem_fault_finalize_and_map,
};
-static vm_fault_t
-nouveau_dmem_fault(struct hmm_devmem *devmem,
- struct vm_area_struct *vma,
- unsigned long addr,
- const struct page *page,
- unsigned int flags,
- pmd_t *pmdp)
+static vm_fault_t nouveau_dmem_migrate_to_ram(struct vm_fault *vmf)
{
- struct drm_device *drm_dev = dev_get_drvdata(devmem->device);
+ struct nouveau_dmem *dmem = page_to_dmem(vmf->page);
unsigned long src[1] = {0}, dst[1] = {0};
- struct nouveau_dmem_fault fault = {0};
+ struct nouveau_dmem_fault fault = { .drm = dmem->drm };
int ret;
-
-
/*
* FIXME what we really want is to find some heuristic to migrate more
* than just one page on CPU fault. When such fault happens it is very
* likely that more surrounding page will CPU fault too.
*/
- fault.drm = nouveau_drm(drm_dev);
- ret = migrate_vma(&nouveau_dmem_fault_migrate_ops, vma, addr,
- addr + PAGE_SIZE, src, dst, &fault);
+ ret = migrate_vma(&nouveau_dmem_fault_migrate_ops, vmf->vma,
+ vmf->address, vmf->address + PAGE_SIZE,
+ src, dst, &fault);
if (ret)
return VM_FAULT_SIGBUS;
@@ -291,10 +286,9 @@ nouveau_dmem_fault(struct hmm_devmem *devmem,
return 0;
}
-static const struct hmm_devmem_ops
-nouveau_dmem_devmem_ops = {
- .free = nouveau_dmem_free,
- .fault = nouveau_dmem_fault,
+static const struct dev_pagemap_ops nouveau_dmem_pagemap_ops = {
+ .page_free = nouveau_dmem_page_free,
+ .migrate_to_ram = nouveau_dmem_migrate_to_ram,
};
static int
@@ -581,7 +575,8 @@ void
nouveau_dmem_init(struct nouveau_drm *drm)
{
struct device *device = drm->dev->dev;
- unsigned long i, size;
+ struct resource *res;
+ unsigned long i, size, pfn_first;
int ret;
/* This only make sense on PASCAL or newer */
@@ -591,6 +586,7 @@ nouveau_dmem_init(struct nouveau_drm *drm)
if (!(drm->dmem = kzalloc(sizeof(*drm->dmem), GFP_KERNEL)))
return;
+ drm->dmem->drm = drm;
mutex_init(&drm->dmem->mutex);
INIT_LIST_HEAD(&drm->dmem->chunk_free);
INIT_LIST_HEAD(&drm->dmem->chunk_full);
@@ -600,11 +596,8 @@ nouveau_dmem_init(struct nouveau_drm *drm)
/* Initialize migration dma helpers before registering memory */
ret = nouveau_dmem_migrate_init(drm);
- if (ret) {
- kfree(drm->dmem);
- drm->dmem = NULL;
- return;
- }
+ if (ret)
+ goto out_free;
/*
* FIXME we need some kind of policy to decide how much VRAM we
@@ -612,14 +605,16 @@ nouveau_dmem_init(struct nouveau_drm *drm)
* and latter if we want to do thing like over commit then we
* could revisit this.
*/
- drm->dmem->devmem = hmm_devmem_add(&nouveau_dmem_devmem_ops,
- device, size);
- if (IS_ERR(drm->dmem->devmem)) {
- kfree(drm->dmem);
- drm->dmem = NULL;
- return;
- }
-
+ res = devm_request_free_mem_region(device, &iomem_resource, size);
+ if (IS_ERR(res))
+ goto out_free;
+ drm->dmem->pagemap.type = MEMORY_DEVICE_PRIVATE;
+ drm->dmem->pagemap.res = *res;
+ drm->dmem->pagemap.ops = &nouveau_dmem_pagemap_ops;
+ if (IS_ERR(devm_memremap_pages(device, &drm->dmem->pagemap)))
+ goto out_free;
+
+ pfn_first = res->start >> PAGE_SHIFT;
for (i = 0; i < (size / DMEM_CHUNK_SIZE); ++i) {
struct nouveau_dmem_chunk *chunk;
struct page *page;
@@ -632,17 +627,19 @@ nouveau_dmem_init(struct nouveau_drm *drm)
}
chunk->drm = drm;
- chunk->pfn_first = drm->dmem->devmem->pfn_first;
- chunk->pfn_first += (i * DMEM_CHUNK_NPAGES);
+ chunk->pfn_first = pfn_first + (i * DMEM_CHUNK_NPAGES);
list_add_tail(&chunk->list, &drm->dmem->chunk_empty);
page = pfn_to_page(chunk->pfn_first);
- for (j = 0; j < DMEM_CHUNK_NPAGES; ++j, ++page) {
- hmm_devmem_page_set_drvdata(page, (long)chunk);
- }
+ for (j = 0; j < DMEM_CHUNK_NPAGES; ++j, ++page)
+ page->zone_device_data = chunk;
}
NV_INFO(drm, "DMEM: registered %ldMB of device memory\n", size >> 20);
+ return;
+out_free:
+ kfree(drm->dmem);
+ drm->dmem = NULL;
}
static void
@@ -698,7 +695,7 @@ nouveau_dmem_migrate_alloc_and_copy(struct vm_area_struct *vma,
if (!dpage || dst_pfns[i] == MIGRATE_PFN_ERROR)
continue;
- chunk = (void *)hmm_devmem_page_get_drvdata(dpage);
+ chunk = dpage->zone_device_data;
dst_addr = page_to_pfn(dpage) - chunk->pfn_first;
dst_addr = (dst_addr << PAGE_SHIFT) + chunk->bo->bo.offset;
@@ -833,13 +830,7 @@ out:
static inline bool
nouveau_dmem_page(struct nouveau_drm *drm, struct page *page)
{
- if (!is_device_private_page(page))
- return false;
-
- if (drm->dmem->devmem != page->pgmap->data)
- return false;
-
- return true;
+ return is_device_private_page(page) && drm->dmem == page_to_dmem(page);
}
void
@@ -868,7 +859,7 @@ nouveau_dmem_convert_pfn(struct nouveau_drm *drm,
continue;
}
- chunk = (void *)hmm_devmem_page_get_drvdata(page);
+ chunk = page->zone_device_data;
addr = page_to_pfn(page) - chunk->pfn_first;
addr = (addr + chunk->bo->bo.mem.start) << PAGE_SHIFT;
diff --git a/drivers/gpu/drm/nouveau/nouveau_svm.c b/drivers/gpu/drm/nouveau/nouveau_svm.c
index 93ed43c413f0..8c92374afcf2 100644
--- a/drivers/gpu/drm/nouveau/nouveau_svm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_svm.c
@@ -649,7 +649,7 @@ nouveau_svm_fault(struct nvif_notify *notify)
range.values = nouveau_svm_pfn_values;
range.pfn_shift = NVIF_VMM_PFNMAP_V0_ADDR_SHIFT;
again:
- ret = hmm_vma_fault(&range, true);
+ ret = hmm_vma_fault(&svmm->mirror, &range, true);
if (ret == 0) {
mutex_lock(&svmm->mutex);
if (!hmm_vma_range_done(&range)) {
diff --git a/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c b/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c
index 6c0561101874..0d20fab605d7 100644
--- a/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c
+++ b/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Analog TV Connector driver
*
* Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
- *
- * 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.
*/
#include <linux/slab.h>
diff --git a/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c b/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c
index 68d6f6e44b03..f5d69d810bb8 100644
--- a/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c
+++ b/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* HDMI Connector driver
*
* Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
- *
- * 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.
*/
#include <linux/gpio/consumer.h>
diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c b/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c
index 29a5a130ebd1..b992387ed674 100644
--- a/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c
+++ b/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* OPA362 analog video amplifier with output/power control
*
@@ -8,10 +9,6 @@
*
* Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
- *
- * 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.
*/
#include <linux/gpio/consumer.h>
diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c
index bc03752d2762..089105c5aa0a 100644
--- a/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c
+++ b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TPD12S015 HDMI ESD protection & level shifter chip driver
*
* Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
- *
- * 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.
*/
#include <linux/completion.h>
diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c
index 913e8291a917..564e3e1a1891 100644
--- a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic DSI Command Mode panel driver
*
* Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
- *
- * 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.
*/
/* #define DEBUG */
diff --git a/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c b/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c
index 99f2350d462c..1fd0d84e6e38 100644
--- a/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LG.Philips LB035Q02 LCD Panel driver
*
* Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
* Based on a driver by: Steve Sakoman <steve@sakoman.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c b/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c
index 9c545de430f6..3ab50fd1f3f2 100644
--- a/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LCD panel driver for Sharp LS037V7DW01
*
* Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c
index 2038def14ba1..588a1a6bbcc3 100644
--- a/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Sony ACX565AKM LCD Panel driver
*
@@ -6,18 +7,6 @@
* Original Driver Author: Imre Deak <imre.deak@nokia.com>
* Based on panel-generic.c by Tomi Valkeinen <tomi.valkeinen@ti.com>
* Adapted to new DSS2 framework: Roger Quadros <roger.quadros@nokia.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/backlight.h>
diff --git a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c
index 2ad161e33106..c885018ac6ce 100644
--- a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Toppoly TD028TTEC1 panel support
*
@@ -10,18 +11,6 @@
*
* Ported and adapted from Neo 1973 U-Boot by:
* H. Nikolaus Schaller <hns@goldelico.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
diff --git a/drivers/gpu/drm/omapdrm/dss/core.c b/drivers/gpu/drm/omapdrm/dss/core.c
index a2edabc9f6b3..6ac497b63711 100644
--- a/drivers/gpu/drm/omapdrm/dss/core.c
+++ b/drivers/gpu/drm/omapdrm/dss/core.c
@@ -1,21 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2009 Nokia Corporation
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
*
* Some code and ideas taken from drivers/video/omap/ driver
* by Imre Deak.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "CORE"
diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c
index ba82d916719c..785c5546067a 100644
--- a/drivers/gpu/drm/omapdrm/dss/dispc.c
+++ b/drivers/gpu/drm/omapdrm/dss/dispc.c
@@ -1,21 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2009 Nokia Corporation
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
*
* Some code and ideas taken from drivers/video/omap/ driver
* by Imre Deak.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "DISPC"
diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.h b/drivers/gpu/drm/omapdrm/dss/dispc.h
index e901dd1e4365..2348faf88768 100644
--- a/drivers/gpu/drm/omapdrm/dss/dispc.h
+++ b/drivers/gpu/drm/omapdrm/dss/dispc.h
@@ -1,18 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
* Author: Archit Taneja <archit@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __OMAP2_DISPC_REG_H
diff --git a/drivers/gpu/drm/omapdrm/dss/dispc_coefs.c b/drivers/gpu/drm/omapdrm/dss/dispc_coefs.c
index 44804c8c8777..bccb28de5a59 100644
--- a/drivers/gpu/drm/omapdrm/dss/dispc_coefs.c
+++ b/drivers/gpu/drm/omapdrm/dss/dispc_coefs.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
* Author: Chandrabhanu Mahapatra <cmahapatra@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
diff --git a/drivers/gpu/drm/omapdrm/dss/display.c b/drivers/gpu/drm/omapdrm/dss/display.c
index e93f61a567a8..8a3f61f5825f 100644
--- a/drivers/gpu/drm/omapdrm/dss/display.c
+++ b/drivers/gpu/drm/omapdrm/dss/display.c
@@ -1,21 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2009 Nokia Corporation
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
*
* Some code and ideas taken from drivers/video/omap/ driver
* by Imre Deak.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "DISPLAY"
diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c
index cc78dfa07f04..95147437b990 100644
--- a/drivers/gpu/drm/omapdrm/dss/dpi.c
+++ b/drivers/gpu/drm/omapdrm/dss/dpi.c
@@ -1,21 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2009 Nokia Corporation
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
*
* Some code and ideas taken from drivers/video/omap/ driver
* by Imre Deak.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "DPI"
diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c
index 5202862d89b5..b30fcaa2d0f5 100644
--- a/drivers/gpu/drm/omapdrm/dss/dsi.c
+++ b/drivers/gpu/drm/omapdrm/dss/dsi.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2009 Nokia Corporation
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "DSI"
diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c
index 55e68863ef15..5711b7a720e6 100644
--- a/drivers/gpu/drm/omapdrm/dss/dss.c
+++ b/drivers/gpu/drm/omapdrm/dss/dss.c
@@ -1,21 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2009 Nokia Corporation
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
*
* Some code and ideas taken from drivers/video/omap/ driver
* by Imre Deak.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "DSS"
diff --git a/drivers/gpu/drm/omapdrm/dss/dss.h b/drivers/gpu/drm/omapdrm/dss/dss.h
index 37790c363128..2b404bcb41dd 100644
--- a/drivers/gpu/drm/omapdrm/dss/dss.h
+++ b/drivers/gpu/drm/omapdrm/dss/dss.h
@@ -1,21 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2009 Nokia Corporation
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
*
* Some code and ideas taken from drivers/video/omap/ driver
* by Imre Deak.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __OMAP2_DSS_H
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi.h b/drivers/gpu/drm/omapdrm/dss/hdmi.h
index 7f0dc490a31d..c867552c925c 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi.h
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi.h
@@ -1,19 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* HDMI driver definition for TI OMAP4 Processor.
*
* Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _HDMI_H
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c
index 6339e2756b34..0f557fad4513 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c
@@ -1,21 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* HDMI interface DSS driver for TI's OMAP4 family of SoCs.
*
* Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
* Authors: Yong Zhi
* Mythri pk <mythripk@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "HDMI"
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c
index e384b95ad857..5d5d5588ebc1 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.c
@@ -1,21 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* HDMI TI81xx, TI38xx, TI OMAP4 etc IP driver Library
*
* Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
* Authors: Yong Zhi
* Mythri pk <mythripk@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "HDMICORE"
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h
index 337a317c1a27..11c4b7ba1eee 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_core.h
@@ -1,19 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* HDMI header definition for OMAP4 HDMI core IP
*
* Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _HDMI4_CORE_H_
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c
index 2955bbad13bb..d9463b332554 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* HDMI driver for OMAP5
*
@@ -8,18 +9,6 @@
* Mythri pk
* Archit Taneja <archit@ti.com>
* Tomi Valkeinen <tomi.valkeinen@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "HDMI"
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c
index 02efabc7ed76..7400fb99d453 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* OMAP5 HDMI CORE IP driver library
*
@@ -7,18 +8,6 @@
* Mythri pk
* Archit Taneja <archit@ti.com>
* Tomi Valkeinen <tomi.valkeinen@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h
index f2f1022c5516..f10b8a283011 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h
@@ -1,19 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* HDMI driver definition for TI OMAP5 processors.
*
* Copyright (C) 2011-2012 Texas Instruments Incorporated - http://www.ti.com/
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _HDMI5_CORE_H_
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi_phy.c b/drivers/gpu/drm/omapdrm/dss/hdmi_phy.c
index 9915923a53bd..00bbf24488c1 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi_phy.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi_phy.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* HDMI PHY
*
* Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c b/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c
index e7be3707d147..cf2b000f397f 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* HDMI PLL
*
* Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
- *
- * 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.
*/
#define DSS_SUBSYS_NAME "HDMIPLL"
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c b/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c
index 100efb9f08c6..32f45f4f569d 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* HDMI wrapper
*
* Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
- *
- * 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.
*/
#define DSS_SUBSYS_NAME "HDMIWP"
diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c b/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c
index e02aa8e70968..a140de79c50e 100644
--- a/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c
+++ b/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h
index 0c734d1f89e1..79f6b195c7cf 100644
--- a/drivers/gpu/drm/omapdrm/dss/omapdss.h
+++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h
@@ -1,18 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __OMAP_DRM_DSS_H
diff --git a/drivers/gpu/drm/omapdrm/dss/output.c b/drivers/gpu/drm/omapdrm/dss/output.c
index 10a9ee5cdc61..de0f882f0f7b 100644
--- a/drivers/gpu/drm/omapdrm/dss/output.c
+++ b/drivers/gpu/drm/omapdrm/dss/output.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
* Author: Archit Taneja <archit@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
diff --git a/drivers/gpu/drm/omapdrm/dss/pll.c b/drivers/gpu/drm/omapdrm/dss/pll.c
index ff362b38bf0d..1212f3cc52d1 100644
--- a/drivers/gpu/drm/omapdrm/dss/pll.c
+++ b/drivers/gpu/drm/omapdrm/dss/pll.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "PLL"
diff --git a/drivers/gpu/drm/omapdrm/dss/sdi.c b/drivers/gpu/drm/omapdrm/dss/sdi.c
index 7aae52984fed..3b447c01fa2a 100644
--- a/drivers/gpu/drm/omapdrm/dss/sdi.c
+++ b/drivers/gpu/drm/omapdrm/dss/sdi.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2009 Nokia Corporation
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "SDI"
diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c
index da43b865d973..596a297d5813 100644
--- a/drivers/gpu/drm/omapdrm/dss/venc.c
+++ b/drivers/gpu/drm/omapdrm/dss/venc.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2009 Nokia Corporation
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
*
* VENC settings from TI's DSS driver
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "VENC"
diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c
index 5967283934e1..5b8799c69f68 100644
--- a/drivers/gpu/drm/omapdrm/omap_connector.c
+++ b/drivers/gpu/drm/omapdrm/omap_connector.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
* Author: Rob Clark <rob@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <drm/drm_atomic_helper.h>
diff --git a/drivers/gpu/drm/omapdrm/omap_connector.h b/drivers/gpu/drm/omapdrm/omap_connector.h
index 608085219336..13607bda33d8 100644
--- a/drivers/gpu/drm/omapdrm/omap_connector.h
+++ b/drivers/gpu/drm/omapdrm/omap_connector.h
@@ -1,20 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* omap_connector.h -- OMAP DRM Connector
*
* Copyright (C) 2011 Texas Instruments
* Author: Rob Clark <rob@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __OMAPDRM_CONNECTOR_H__
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
index d61215494617..f9ac9afc5641 100644
--- a/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
* Author: Rob Clark <rob@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <drm/drm_atomic.h>
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.h b/drivers/gpu/drm/omapdrm/omap_crtc.h
index 2b518c74203e..2fd57751ae2b 100644
--- a/drivers/gpu/drm/omapdrm/omap_crtc.h
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.h
@@ -1,20 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* omap_crtc.h -- OMAP DRM CRTC
*
* Copyright (C) 2011 Texas Instruments
* Author: Rob Clark <rob@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __OMAPDRM_CRTC_H__
diff --git a/drivers/gpu/drm/omapdrm/omap_debugfs.c b/drivers/gpu/drm/omapdrm/omap_debugfs.c
index 91cf043f2b6b..2b283f68fab7 100644
--- a/drivers/gpu/drm/omapdrm/omap_debugfs.c
+++ b/drivers/gpu/drm/omapdrm/omap_debugfs.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
* Author: Rob Clark <rob.clark@linaro.org>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/seq_file.h>
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index 672e0f8ad11c..288c59dae56a 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
* Author: Rob Clark <rob@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/of.h>
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h
index 896aa12f09b2..025bd57081d5 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.h
+++ b/drivers/gpu/drm/omapdrm/omap_drv.h
@@ -1,18 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
* Author: Rob Clark <rob@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __OMAPDRM_DRV_H__
diff --git a/drivers/gpu/drm/omapdrm/omap_encoder.c b/drivers/gpu/drm/omapdrm/omap_encoder.c
index 40512419642b..6fe14111cd95 100644
--- a/drivers/gpu/drm/omapdrm/omap_encoder.c
+++ b/drivers/gpu/drm/omapdrm/omap_encoder.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
* Author: Rob Clark <rob@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/list.h>
diff --git a/drivers/gpu/drm/omapdrm/omap_encoder.h b/drivers/gpu/drm/omapdrm/omap_encoder.h
index 4aefb3142886..051e590cd3ea 100644
--- a/drivers/gpu/drm/omapdrm/omap_encoder.h
+++ b/drivers/gpu/drm/omapdrm/omap_encoder.h
@@ -1,20 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* omap_encoder.h -- OMAP DRM Encoder
*
* Copyright (C) 2011 Texas Instruments
* Author: Rob Clark <rob@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __OMAPDRM_ENCODER_H__
diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c
index 06d5c5081e41..7e89e5cb4068 100644
--- a/drivers/gpu/drm/omapdrm/omap_fb.c
+++ b/drivers/gpu/drm/omapdrm/omap_fb.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
* Author: Rob Clark <rob@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/seq_file.h>
diff --git a/drivers/gpu/drm/omapdrm/omap_fb.h b/drivers/gpu/drm/omapdrm/omap_fb.h
index c20cb4bc714d..c0e19aed8220 100644
--- a/drivers/gpu/drm/omapdrm/omap_fb.h
+++ b/drivers/gpu/drm/omapdrm/omap_fb.h
@@ -1,20 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* omap_fb.h -- OMAP DRM Framebuffer
*
* Copyright (C) 2011 Texas Instruments
* Author: Rob Clark <rob@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __OMAPDRM_FB_H__
diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c
index 50aabd854f4d..561c4812545b 100644
--- a/drivers/gpu/drm/omapdrm/omap_fbdev.c
+++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
* Author: Rob Clark <rob@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <drm/drm_crtc.h>
diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.h b/drivers/gpu/drm/omapdrm/omap_fbdev.h
index 7dfd843f73f1..74a68a5a6eab 100644
--- a/drivers/gpu/drm/omapdrm/omap_fbdev.h
+++ b/drivers/gpu/drm/omapdrm/omap_fbdev.h
@@ -1,20 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* omap_fbdev.h -- OMAP DRM FBDEV Compatibility
*
* Copyright (C) 2011 Texas Instruments
* Author: Rob Clark <rob@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __OMAPDRM_FBDEV_H__
diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c
index 8dcaf9f4aa75..37378dbc50d0 100644
--- a/drivers/gpu/drm/omapdrm/omap_gem.c
+++ b/drivers/gpu/drm/omapdrm/omap_gem.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
* Author: Rob Clark <rob.clark@linaro.org>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/seq_file.h>
diff --git a/drivers/gpu/drm/omapdrm/omap_gem.h b/drivers/gpu/drm/omapdrm/omap_gem.h
index c1c45fbde155..31cf345bf8ae 100644
--- a/drivers/gpu/drm/omapdrm/omap_gem.h
+++ b/drivers/gpu/drm/omapdrm/omap_gem.h
@@ -1,20 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* omap_gem.h -- OMAP DRM GEM Object Management
*
* Copyright (C) 2011 Texas Instruments
* Author: Rob Clark <rob@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __OMAPDRM_GEM_H__
diff --git a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c
index 0f8b597ccd10..07c0b1b486f7 100644
--- a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c
+++ b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
* Author: Rob Clark <rob.clark@linaro.org>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/dma-buf.h>
diff --git a/drivers/gpu/drm/omapdrm/omap_irq.c b/drivers/gpu/drm/omapdrm/omap_irq.c
index 01dda84ca2ee..726a013e7988 100644
--- a/drivers/gpu/drm/omapdrm/omap_irq.c
+++ b/drivers/gpu/drm/omapdrm/omap_irq.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
* Author: Rob Clark <rob.clark@linaro.org>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "omap_drv.h"
diff --git a/drivers/gpu/drm/omapdrm/omap_irq.h b/drivers/gpu/drm/omapdrm/omap_irq.h
index 02abb4ed9813..35e9586c4a51 100644
--- a/drivers/gpu/drm/omapdrm/omap_irq.h
+++ b/drivers/gpu/drm/omapdrm/omap_irq.h
@@ -1,20 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* omap_irq.h -- OMAP DRM IRQ Handling
*
* Copyright (C) 2011 Texas Instruments
* Author: Rob Clark <rob@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __OMAPDRM_IRQ_H__
diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c
index 161233cbc9a0..84e1be981cfe 100644
--- a/drivers/gpu/drm/omapdrm/omap_plane.c
+++ b/drivers/gpu/drm/omapdrm/omap_plane.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
* Author: Rob Clark <rob.clark@linaro.org>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <drm/drm_atomic.h>
diff --git a/drivers/gpu/drm/omapdrm/omap_plane.h b/drivers/gpu/drm/omapdrm/omap_plane.h
index dc5e82ad061d..0c28fe8ffa20 100644
--- a/drivers/gpu/drm/omapdrm/omap_plane.h
+++ b/drivers/gpu/drm/omapdrm/omap_plane.h
@@ -1,20 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* omap_plane.h -- OMAP DRM Plane
*
* Copyright (C) 2011 Texas Instruments
* Author: Rob Clark <rob@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __OMAPDRM_PLANE_H__
diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9322.c b/drivers/gpu/drm/panel/panel-ilitek-ili9322.c
index 35a4bd05edf5..53dd1e128795 100644
--- a/drivers/gpu/drm/panel/panel-ilitek-ili9322.c
+++ b/drivers/gpu/drm/panel/panel-ilitek-ili9322.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Ilitek ILI9322 TFT LCD drm_panel driver.
*
@@ -16,10 +17,6 @@
*
* Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
* Derived from drivers/drm/gpu/panel/panel-samsung-ld9040.c
- *
- * 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.
*/
#include <linux/bitops.h>
diff --git a/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c b/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c
index ee5ddf771e10..ff3e89e61e3f 100644
--- a/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c
+++ b/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2016 InforceComputing
* Author: Vinay Simha BN <simhavcs@gmail.com>
@@ -8,18 +9,6 @@
* From internet archives, the panel for Nexus 7 2nd Gen, 2013 model is a
* JDI model LT070ME05000, and its data sheet is at:
* http://panelone.net/en/7-0-inch/JDI_LT070ME05000_7.0_inch-datasheet
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/backlight.h>
diff --git a/drivers/gpu/drm/panel/panel-lg-lg4573.c b/drivers/gpu/drm/panel/panel-lg-lg4573.c
index 0dd4bdda7c4e..41bf02d122a1 100644
--- a/drivers/gpu/drm/panel/panel-lg-lg4573.c
+++ b/drivers/gpu/drm/panel/panel-lg-lg4573.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2015 Heiko Schocher <hs@denx.de>
*
@@ -9,10 +10,6 @@
* Derived from drivers/video/backlight/ld9040.c
*
* Andrzej Hajda <a.hajda@samsung.com>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c b/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c
index 045df41dbde2..3dff0b3f73c2 100644
--- a/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c
+++ b/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c
@@ -1,21 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2015 Red Hat
* Copyright (C) 2015 Sony Mobile Communications Inc.
* Author: Werner Johansson <werner.johansson@sonymobile.com>
*
* Based on AUO panel driver by Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/backlight.h>
diff --git a/drivers/gpu/drm/panel/panel-samsung-ld9040.c b/drivers/gpu/drm/panel/panel-samsung-ld9040.c
index 5c2a1cae603b..3be902dcedc0 100644
--- a/drivers/gpu/drm/panel/panel-samsung-ld9040.c
+++ b/drivers/gpu/drm/panel/panel-samsung-ld9040.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ld9040 AMOLED LCD drm_panel driver.
*
@@ -5,10 +6,6 @@
* Derived from drivers/video/backlight/ld9040.c
*
* Andrzej Hajda <a.hajda@samsung.com>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c b/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c
index 351eee951648..b923de23ed65 100644
--- a/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c
+++ b/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* MIPI-DSI based s6e3ha2 AMOLED 5.7 inch panel driver.
*
@@ -5,10 +6,6 @@
* Donghwa Lee <dh09.lee@samsung.com>
* Hyungwon Hwang <human.hwang@samsung.com>
* Hoegeun Kwon <hoegeun.kwon@samsung.com>
- *
- * 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.
*/
#include <linux/backlight.h>
diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c b/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c
index 19ea325a0e9b..cd90fa700c49 100644
--- a/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c
+++ b/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* MIPI-DSI based S6E63J0X03 AMOLED lcd 1.63 inch panel driver.
*
@@ -5,10 +6,6 @@
*
* Inki Dae <inki.dae@samsung.com>
* Hoegeun Kwon <hoegeun.kwon@samsung.com>
- *
- * 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.
*/
#include <linux/backlight.h>
diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c b/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c
index 0dcbda8310e3..81858267723a 100644
--- a/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c
+++ b/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* MIPI-DSI based s6e8aa0 AMOLED LCD 5.3 inch panel driver.
*
@@ -9,10 +10,6 @@
* Eunchul Kim <chulspro.kim@samsung.com>
* Tomasz Figa <t.figa@samsung.com>
* Andrzej Hajda <a.hajda@samsung.com>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c
index 1ac75a30e431..e910b4ad1310 100644
--- a/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c
+++ b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 NVIDIA Corporation
- *
- * 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.
*/
#include <linux/backlight.h>
diff --git a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c
index 89d7fc842972..c39abde9f9f1 100644
--- a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c
+++ b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c
@@ -1,21 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2015 Red Hat
* Copyright (C) 2015 Sony Mobile Communications Inc.
* Author: Werner Johansson <werner.johansson@sonymobile.com>
*
* Based on AUO panel driver by Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/backlight.h>
diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
index bf85a8fa9ad0..5e3e92ea9ea6 100644
--- a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
+++ b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2017 Free Electrons
- *
- * 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.
*/
#include <linux/backlight.h>
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c
index e34e86a7378a..85b4b51b6a0d 100644
--- a/drivers/gpu/drm/panfrost/panfrost_drv.c
+++ b/drivers/gpu/drm/panfrost/panfrost_drv.c
@@ -67,7 +67,7 @@ static int panfrost_ioctl_create_bo(struct drm_device *dev, void *data,
return 0;
err_free:
- drm_gem_object_put_unlocked(&shmem->base);
+ drm_gem_handle_delete(file, args->handle);
return ret;
}
diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.c b/drivers/gpu/drm/panfrost/panfrost_gem.c
index 886875ae31d3..b46416be5a54 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gem.c
+++ b/drivers/gpu/drm/panfrost/panfrost_gem.c
@@ -19,7 +19,8 @@ static void panfrost_gem_free_object(struct drm_gem_object *obj)
struct panfrost_gem_object *bo = to_panfrost_bo(obj);
struct panfrost_device *pfdev = obj->dev->dev_private;
- panfrost_mmu_unmap(bo);
+ if (bo->is_mapped)
+ panfrost_mmu_unmap(bo);
spin_lock(&pfdev->mm_lock);
drm_mm_remove_node(&bo->node);
diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.h b/drivers/gpu/drm/panfrost/panfrost_gem.h
index 045000eb5fcf..6dbcaba020fc 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gem.h
+++ b/drivers/gpu/drm/panfrost/panfrost_gem.h
@@ -11,6 +11,7 @@ struct panfrost_gem_object {
struct drm_gem_shmem_object base;
struct drm_mm_node node;
+ bool is_mapped;
};
static inline
diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c
index 762b1bd2a8c2..92ac995dd9c6 100644
--- a/drivers/gpu/drm/panfrost/panfrost_mmu.c
+++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c
@@ -156,6 +156,9 @@ int panfrost_mmu_map(struct panfrost_gem_object *bo)
struct sg_table *sgt;
int ret;
+ if (WARN_ON(bo->is_mapped))
+ return 0;
+
sgt = drm_gem_shmem_get_pages_sgt(obj);
if (WARN_ON(IS_ERR(sgt)))
return PTR_ERR(sgt);
@@ -189,6 +192,7 @@ int panfrost_mmu_map(struct panfrost_gem_object *bo)
pm_runtime_mark_last_busy(pfdev->dev);
pm_runtime_put_autosuspend(pfdev->dev);
+ bo->is_mapped = true;
return 0;
}
@@ -203,6 +207,9 @@ void panfrost_mmu_unmap(struct panfrost_gem_object *bo)
size_t unmapped_len = 0;
int ret;
+ if (WARN_ON(!bo->is_mapped))
+ return;
+
dev_dbg(pfdev->dev, "unmap: iova=%llx, len=%zx", iova, len);
ret = pm_runtime_get_sync(pfdev->dev);
@@ -230,6 +237,7 @@ void panfrost_mmu_unmap(struct panfrost_gem_object *bo)
pm_runtime_mark_last_busy(pfdev->dev);
pm_runtime_put_autosuspend(pfdev->dev);
+ bo->is_mapped = false;
}
static void mmu_tlb_inv_context_s1(void *cookie)
diff --git a/drivers/gpu/drm/pl111/pl111_debugfs.c b/drivers/gpu/drm/pl111/pl111_debugfs.c
index 7ddc7e3b9e7d..8d6a40469f0b 100644
--- a/drivers/gpu/drm/pl111/pl111_debugfs.c
+++ b/drivers/gpu/drm/pl111/pl111_debugfs.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright © 2017 Broadcom
- *
- * 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.
*/
#include <linux/amba/clcd-regs.h>
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h
index 48fef95cb3c6..f18a01e6cbc2 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.h
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h
@@ -1,15 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2016 Chris Zhong <zyw@rock-chips.com>
* Copyright (C) 2016 ROCKCHIP, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#ifndef _CDN_DP_CORE_H
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index 079250c85733..4a75d149e368 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Avionic Design GmbH
* Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/clk.h>
@@ -2370,10 +2367,10 @@ static int tegra_dc_parse_dt(struct tegra_dc *dc)
return 0;
}
-static int tegra_dc_match_by_pipe(struct device *dev, void *data)
+static int tegra_dc_match_by_pipe(struct device *dev, const void *data)
{
struct tegra_dc *dc = dev_get_drvdata(dev);
- unsigned int pipe = (unsigned long)data;
+ unsigned int pipe = (unsigned long)(void *)data;
return dc->pipe == pipe;
}
diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h
index 1256dfb6b2f5..0c4d17851f47 100644
--- a/drivers/gpu/drm/tegra/dc.h
+++ b/drivers/gpu/drm/tegra/dc.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2012 Avionic Design GmbH
* Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#ifndef TEGRA_DC_H
diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c
index 65c389d9c85d..2d94da225e51 100644
--- a/drivers/gpu/drm/tegra/dpaux.c
+++ b/drivers/gpu/drm/tegra/dpaux.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 NVIDIA Corporation
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/gpu/drm/tegra/dpaux.h b/drivers/gpu/drm/tegra/dpaux.h
index 20783d9f4728..5eced10fad37 100644
--- a/drivers/gpu/drm/tegra/dpaux.h
+++ b/drivers/gpu/drm/tegra/dpaux.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2013 NVIDIA Corporation
- *
- * 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.
*/
#ifndef DRM_TEGRA_DPAUX_H
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index 0c5f1e6a0446..ddb802bce0a3 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Avionic Design GmbH
* Copyright (C) 2012-2016 NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/bitops.h>
diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h
index 488f36f00bd8..86daa19fcf24 100644
--- a/drivers/gpu/drm/tegra/drm.h
+++ b/drivers/gpu/drm/tegra/drm.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2012 Avionic Design GmbH
* Copyright (C) 2012-2013 NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#ifndef HOST1X_DRM_H
diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c
index ee6ca8fa1c65..2fbfefe9cb42 100644
--- a/drivers/gpu/drm/tegra/dsi.c
+++ b/drivers/gpu/drm/tegra/dsi.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 NVIDIA Corporation
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/gpu/drm/tegra/dsi.h b/drivers/gpu/drm/tegra/dsi.h
index 219263615399..f39594e65e97 100644
--- a/drivers/gpu/drm/tegra/dsi.h
+++ b/drivers/gpu/drm/tegra/dsi.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2013 NVIDIA Corporation
- *
- * 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.
*/
#ifndef DRM_TEGRA_DSI_H
diff --git a/drivers/gpu/drm/tegra/falcon.c b/drivers/gpu/drm/tegra/falcon.c
index 352d05feabb0..f49ad36e24db 100644
--- a/drivers/gpu/drm/tegra/falcon.c
+++ b/drivers/gpu/drm/tegra/falcon.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2015, NVIDIA Corporation.
- *
- * 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.
*/
#include <linux/platform_device.h>
diff --git a/drivers/gpu/drm/tegra/falcon.h b/drivers/gpu/drm/tegra/falcon.h
index 4504ed5a199e..3d1243217410 100644
--- a/drivers/gpu/drm/tegra/falcon.h
+++ b/drivers/gpu/drm/tegra/falcon.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2015, NVIDIA Corporation.
- *
- * 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.
*/
#ifndef _FALCON_H_
diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c
index 57cc26e1da01..888ed0d74ccd 100644
--- a/drivers/gpu/drm/tegra/fb.c
+++ b/drivers/gpu/drm/tegra/fb.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012-2013 Avionic Design GmbH
* Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
*
* Based on the KMS/FB CMA helpers
* Copyright (C) 2012 Analog Device 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.
*/
#include <linux/console.h>
diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c
index 4cce11fd8836..df53a46285a3 100644
--- a/drivers/gpu/drm/tegra/gem.c
+++ b/drivers/gpu/drm/tegra/gem.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* NVIDIA Tegra DRM GEM helper functions
*
@@ -7,10 +8,6 @@
* Based on the GEM/CMA helpers
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
- *
- * 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.
*/
#include <linux/dma-buf.h>
diff --git a/drivers/gpu/drm/tegra/gem.h b/drivers/gpu/drm/tegra/gem.h
index 6bd7dd7e55b4..413eae83ad81 100644
--- a/drivers/gpu/drm/tegra/gem.h
+++ b/drivers/gpu/drm/tegra/gem.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Tegra host1x GEM implementation
*
* Copyright (c) 2012-2013, NVIDIA Corporation.
- *
- * 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.
*/
#ifndef __HOST1X_GEM_H
diff --git a/drivers/gpu/drm/tegra/gr2d.c b/drivers/gpu/drm/tegra/gr2d.c
index 673059fd2fcb..8dbfb30344e7 100644
--- a/drivers/gpu/drm/tegra/gr2d.c
+++ b/drivers/gpu/drm/tegra/gr2d.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012-2013, NVIDIA Corporation.
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/gpu/drm/tegra/gr2d.h b/drivers/gpu/drm/tegra/gr2d.h
index 4d7304fb015e..2398486f0699 100644
--- a/drivers/gpu/drm/tegra/gr2d.h
+++ b/drivers/gpu/drm/tegra/gr2d.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2013 NVIDIA Corporation
- *
- * 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.
*/
#ifndef TEGRA_GR2D_H
diff --git a/drivers/gpu/drm/tegra/gr3d.c b/drivers/gpu/drm/tegra/gr3d.c
index 4778ae999668..8b9a35b1cbb3 100644
--- a/drivers/gpu/drm/tegra/gr3d.c
+++ b/drivers/gpu/drm/tegra/gr3d.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Avionic Design GmbH
* Copyright (C) 2013 NVIDIA Corporation
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/gpu/drm/tegra/gr3d.h b/drivers/gpu/drm/tegra/gr3d.h
index 0c30a1351c83..ca2921b68c2a 100644
--- a/drivers/gpu/drm/tegra/gr3d.h
+++ b/drivers/gpu/drm/tegra/gr3d.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2013 NVIDIA Corporation
- *
- * 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.
*/
#ifndef TEGRA_GR3D_H
diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c
index d23c4bfde790..334c4d7d238b 100644
--- a/drivers/gpu/drm/tegra/hdmi.c
+++ b/drivers/gpu/drm/tegra/hdmi.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Avionic Design GmbH
* Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/clk.h>
diff --git a/drivers/gpu/drm/tegra/hdmi.h b/drivers/gpu/drm/tegra/hdmi.h
index 2339f134a09a..8deb04223c18 100644
--- a/drivers/gpu/drm/tegra/hdmi.h
+++ b/drivers/gpu/drm/tegra/hdmi.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2012 Avionic Design GmbH
* Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#ifndef TEGRA_HDMI_H
diff --git a/drivers/gpu/drm/tegra/hub.c b/drivers/gpu/drm/tegra/hub.c
index b3436c2aed68..92f202ec0577 100644
--- a/drivers/gpu/drm/tegra/hub.c
+++ b/drivers/gpu/drm/tegra/hub.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/clk.h>
diff --git a/drivers/gpu/drm/tegra/hub.h b/drivers/gpu/drm/tegra/hub.h
index 479087c0705a..41541e261c91 100644
--- a/drivers/gpu/drm/tegra/hub.h
+++ b/drivers/gpu/drm/tegra/hub.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#ifndef TEGRA_HUB_H
diff --git a/drivers/gpu/drm/tegra/mipi-phy.c b/drivers/gpu/drm/tegra/mipi-phy.c
index ba2ae6511957..4fe05f2df637 100644
--- a/drivers/gpu/drm/tegra/mipi-phy.c
+++ b/drivers/gpu/drm/tegra/mipi-phy.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 NVIDIA Corporation
- *
- * 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.
*/
#include <linux/errno.h>
diff --git a/drivers/gpu/drm/tegra/mipi-phy.h b/drivers/gpu/drm/tegra/mipi-phy.h
index 012ea8ac36d7..41889a75035c 100644
--- a/drivers/gpu/drm/tegra/mipi-phy.h
+++ b/drivers/gpu/drm/tegra/mipi-phy.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2013 NVIDIA Corporation
- *
- * 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.
*/
#ifndef DRM_TEGRA_MIPI_PHY_H
diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c
index e4d242ca27b8..274cb955e2e1 100644
--- a/drivers/gpu/drm/tegra/output.c
+++ b/drivers/gpu/drm/tegra/output.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Avionic Design GmbH
* Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <drm/drm_atomic_helper.h>
diff --git a/drivers/gpu/drm/tegra/plane.c b/drivers/gpu/drm/tegra/plane.c
index d068e8aa3553..df80ca07e46e 100644
--- a/drivers/gpu/drm/tegra/plane.c
+++ b/drivers/gpu/drm/tegra/plane.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <drm/drm_atomic.h>
diff --git a/drivers/gpu/drm/tegra/plane.h b/drivers/gpu/drm/tegra/plane.h
index e79e6b4a8e0a..510c394e6d9a 100644
--- a/drivers/gpu/drm/tegra/plane.h
+++ b/drivers/gpu/drm/tegra/plane.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#ifndef TEGRA_PLANE_H
diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c
index 28a78d3120bc..4be4dfd4a68a 100644
--- a/drivers/gpu/drm/tegra/rgb.c
+++ b/drivers/gpu/drm/tegra/rgb.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Avionic Design GmbH
* Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/clk.h>
diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c
index 5be5a0817dfe..4ffe3794e6d3 100644
--- a/drivers/gpu/drm/tegra/sor.c
+++ b/drivers/gpu/drm/tegra/sor.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 NVIDIA Corporation
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/gpu/drm/tegra/sor.h b/drivers/gpu/drm/tegra/sor.h
index 13f7e68bec42..f8efd8be4b7c 100644
--- a/drivers/gpu/drm/tegra/sor.h
+++ b/drivers/gpu/drm/tegra/sor.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2013 NVIDIA Corporation
- *
- * 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.
*/
#ifndef DRM_TEGRA_SOR_H
diff --git a/drivers/gpu/drm/tegra/vic.c b/drivers/gpu/drm/tegra/vic.c
index 982ce37ecde1..958548ef69e7 100644
--- a/drivers/gpu/drm/tegra/vic.c
+++ b/drivers/gpu/drm/tegra/vic.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2015, NVIDIA Corporation.
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/gpu/drm/tegra/vic.h b/drivers/gpu/drm/tegra/vic.h
index 017584340dd6..be898bee6a57 100644
--- a/drivers/gpu/drm/tegra/vic.h
+++ b/drivers/gpu/drm/tegra/vic.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2015, NVIDIA Corporation.
- *
- * 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.
*/
#ifndef TEGRA_VIC_H
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
index 1067e702c22c..650d162e374b 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Texas Instruments
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <drm/drm_atomic.h>
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index 3030af9e7b35..7339bab3a0a1 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Texas Instruments
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* LCDC DRM driver, based on da8xx-fb */
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
index d86397da12a9..99432296c0ff 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
@@ -1,18 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2012 Texas Instruments
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __TILCDC_DRV_H__
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.c b/drivers/gpu/drm/tilcdc/tilcdc_external.c
index e9969cd36610..7050eb4cf152 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_external.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_external.c
@@ -1,11 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2015 Texas Instruments
* Author: Jyri Sarha <jsarha@ti.com>
- *
- * 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.
- *
*/
#include <linux/component.h>
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.h b/drivers/gpu/drm/tilcdc/tilcdc_external.h
index 763d18f006c7..7024b4877fdf 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_external.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_external.h
@@ -1,18 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2015 Texas Instruments
* Author: Jyri Sarha <jsarha@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __TILCDC_EXTERNAL_H__
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_panel.c b/drivers/gpu/drm/tilcdc/tilcdc_panel.c
index 5d532a596e1e..22b100d2e174 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_panel.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_panel.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Texas Instruments
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/pinctrl/pinmux.h>
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_panel.h b/drivers/gpu/drm/tilcdc/tilcdc_panel.h
index 7db40aacc74a..65d735d773a4 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_panel.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_panel.h
@@ -1,18 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2012 Texas Instruments
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __TILCDC_PANEL_H__
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_plane.c b/drivers/gpu/drm/tilcdc/tilcdc_plane.c
index 7667b038ae7f..8c2776acdf99 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_plane.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_plane.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2015 Texas Instruments
* Author: Jyri Sarha <jsarha@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <drm/drmP.h>
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_regs.h b/drivers/gpu/drm/tilcdc/tilcdc_regs.h
index 5048ebb86835..f90e2dc3457c 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_regs.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_regs.h
@@ -1,18 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2012 Texas Instruments
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __TILCDC_REGS_H__
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c
index fe59fbfdde69..62d014c20988 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Texas Instruments
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/i2c.h>
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.h b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.h
index 5b800f1f6aa5..f9aaf6911ffc 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.h
@@ -1,18 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2012 Texas Instruments
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __TILCDC_TFP410_H__
diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c
index 1434bb829267..a75a2f98b82f 100644
--- a/drivers/gpu/drm/vc4/vc4_bo.c
+++ b/drivers/gpu/drm/vc4/vc4_bo.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright © 2015 Broadcom
- *
- * 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.
*/
/**
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
index 5e09389e1514..5ea8db74418a 100644
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2015 Broadcom
- *
- * 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.
*/
/**
diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c
index f9b46911fa50..4829a00c16b0 100644
--- a/drivers/gpu/drm/vc4/vc4_debugfs.c
+++ b/drivers/gpu/drm/vc4/vc4_debugfs.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright © 2014 Broadcom
- *
- * 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.
*/
#include <linux/seq_file.h>
diff --git a/drivers/gpu/drm/vc4/vc4_dpi.c b/drivers/gpu/drm/vc4/vc4_dpi.c
index 34f90ca8f479..8a27a6acee61 100644
--- a/drivers/gpu/drm/vc4/vc4_dpi.c
+++ b/drivers/gpu/drm/vc4/vc4_dpi.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2016 Broadcom Limited
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
index 0f99ad03614e..bf11930e40e1 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.c
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014-2015 Broadcom
* Copyright (C) 2013 Red Hat
- *
- * 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.
*/
/**
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index 9170a24ec5f5..616c011bcb82 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2015 Broadcom
- *
- * 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.
*/
#include <linux/mm_types.h>
diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
index 2ea4e20b7b8a..1db39b570cf4 100644
--- a/drivers/gpu/drm/vc4/vc4_dsi.c
+++ b/drivers/gpu/drm/vc4/vc4_dsi.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2016 Broadcom
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 43442c5619a3..ee7d4e7b0ee3 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2015 Broadcom
* Copyright (c) 2014 The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
@@ -69,6 +58,9 @@
struct vc4_hdmi_audio {
struct snd_soc_card card;
struct snd_soc_dai_link link;
+ struct snd_soc_dai_link_component cpu;
+ struct snd_soc_dai_link_component codec;
+ struct snd_soc_dai_link_component platform;
int samplerate;
int channels;
struct snd_dmaengine_dai_dma_data dma_data;
@@ -1102,12 +1094,20 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *hdmi)
return ret;
}
+ dai_link->cpus = &hdmi->audio.cpu;
+ dai_link->codecs = &hdmi->audio.codec;
+ dai_link->platforms = &hdmi->audio.platform;
+
+ dai_link->num_cpus = 1;
+ dai_link->num_codecs = 1;
+ dai_link->num_platforms = 1;
+
dai_link->name = "MAI";
dai_link->stream_name = "MAI PCM";
- dai_link->codec_dai_name = vc4_hdmi_audio_codec_dai_drv.name;
- dai_link->cpu_dai_name = dev_name(dev);
- dai_link->codec_name = dev_name(dev);
- dai_link->platform_name = dev_name(dev);
+ dai_link->codecs->dai_name = vc4_hdmi_audio_codec_dai_drv.name;
+ dai_link->cpus->dai_name = dev_name(dev);
+ dai_link->codecs->name = dev_name(dev);
+ dai_link->platforms->name = dev_name(dev);
card->dai_link = dai_link;
card->num_links = 1;
diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c
index f746e9a7a88c..0f633bef6b9d 100644
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2015 Broadcom
- *
- * 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.
*/
/**
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
index 295dacc8bcb9..70d079b7b39f 100644
--- a/drivers/gpu/drm/vc4/vc4_kms.c
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2015 Broadcom
- *
- * 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.
*/
/**
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
index 441e06d45c89..0a0207c350a5 100644
--- a/drivers/gpu/drm/vc4/vc4_plane.c
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2015 Broadcom
- *
- * 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.
*/
/**
diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
index c0c5fadaf7e3..b5a6b4cdd332 100644
--- a/drivers/gpu/drm/vc4/vc4_regs.h
+++ b/drivers/gpu/drm/vc4/vc4_regs.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright © 2014-2015 Broadcom
- *
- * 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.
*/
#ifndef VC4_REGS_H
diff --git a/drivers/gpu/drm/vc4/vc4_trace.h b/drivers/gpu/drm/vc4/vc4_trace.h
index deafb32923e1..1cccde0b09a7 100644
--- a/drivers/gpu/drm/vc4/vc4_trace.h
+++ b/drivers/gpu/drm/vc4/vc4_trace.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2015 Broadcom
- *
- * 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.
*/
#if !defined(_VC4_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
diff --git a/drivers/gpu/drm/vc4/vc4_trace_points.c b/drivers/gpu/drm/vc4/vc4_trace_points.c
index e6278f25716b..126453abe294 100644
--- a/drivers/gpu/drm/vc4/vc4_trace_points.c
+++ b/drivers/gpu/drm/vc4/vc4_trace_points.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2015 Broadcom
- *
- * 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.
*/
#include "vc4_drv.h"
diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c
index 0533646a4d13..fee4f90e71aa 100644
--- a/drivers/gpu/drm/vc4/vc4_v3d.c
+++ b/drivers/gpu/drm/vc4/vc4_v3d.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014 The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/clk.h>
diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
index 0a27e48fab31..7402bc768664 100644
--- a/drivers/gpu/drm/vc4/vc4_vec.c
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2016 Broadcom
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c
index 6c1a90717535..981ee16e3ee9 100644
--- a/drivers/gpu/drm/virtio/virtgpu_vq.c
+++ b/drivers/gpu/drm/virtio/virtgpu_vq.c
@@ -631,11 +631,11 @@ static void virtio_gpu_cmd_get_edid_cb(struct virtio_gpu_device *vgdev,
output = vgdev->outputs + scanout;
new_edid = drm_do_get_edid(&output->conn, virtio_get_edid_block, resp);
+ drm_connector_update_edid_property(&output->conn, new_edid);
spin_lock(&vgdev->display_info_lock);
old_edid = output->edid;
output->edid = new_edid;
- drm_connector_update_edid_property(&output->conn, output->edid);
spin_unlock(&vgdev->display_info_lock);
kfree(old_edid);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 4ff11a0077e1..9506190a0300 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -747,6 +747,9 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
if (unlikely(ret != 0))
goto out_err0;
+ dma_set_max_seg_size(dev->dev, min_t(unsigned int, U32_MAX & PAGE_MASK,
+ SCATTERLIST_MAX_SEGMENT));
+
if (dev_priv->capabilities & SVGA_CAP_GMR2) {
DRM_INFO("Max GMR ids is %u\n",
(unsigned)dev_priv->max_gmr_ids);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c
index 8b9270f31409..e4e09d47c5c0 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c
@@ -136,6 +136,114 @@ static int vmw_close_channel(struct rpc_channel *channel)
return 0;
}
+/**
+ * vmw_port_hb_out - Send the message payload either through the
+ * high-bandwidth port if available, or through the backdoor otherwise.
+ * @channel: The rpc channel.
+ * @msg: NULL-terminated message.
+ * @hb: Whether the high-bandwidth port is available.
+ *
+ * Return: The port status.
+ */
+static unsigned long vmw_port_hb_out(struct rpc_channel *channel,
+ const char *msg, bool hb)
+{
+ unsigned long si, di, eax, ebx, ecx, edx;
+ unsigned long msg_len = strlen(msg);
+
+ if (hb) {
+ unsigned long bp = channel->cookie_high;
+
+ si = (uintptr_t) msg;
+ di = channel->cookie_low;
+
+ VMW_PORT_HB_OUT(
+ (MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG,
+ msg_len, si, di,
+ VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16),
+ VMW_HYPERVISOR_MAGIC, bp,
+ eax, ebx, ecx, edx, si, di);
+
+ return ebx;
+ }
+
+ /* HB port not available. Send the message 4 bytes at a time. */
+ ecx = MESSAGE_STATUS_SUCCESS << 16;
+ while (msg_len && (HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS)) {
+ unsigned int bytes = min_t(size_t, msg_len, 4);
+ unsigned long word = 0;
+
+ memcpy(&word, msg, bytes);
+ msg_len -= bytes;
+ msg += bytes;
+ si = channel->cookie_high;
+ di = channel->cookie_low;
+
+ VMW_PORT(VMW_PORT_CMD_MSG | (MSG_TYPE_SENDPAYLOAD << 16),
+ word, si, di,
+ VMW_HYPERVISOR_PORT | (channel->channel_id << 16),
+ VMW_HYPERVISOR_MAGIC,
+ eax, ebx, ecx, edx, si, di);
+ }
+
+ return ecx;
+}
+
+/**
+ * vmw_port_hb_in - Receive the message payload either through the
+ * high-bandwidth port if available, or through the backdoor otherwise.
+ * @channel: The rpc channel.
+ * @reply: Pointer to buffer holding reply.
+ * @reply_len: Length of the reply.
+ * @hb: Whether the high-bandwidth port is available.
+ *
+ * Return: The port status.
+ */
+static unsigned long vmw_port_hb_in(struct rpc_channel *channel, char *reply,
+ unsigned long reply_len, bool hb)
+{
+ unsigned long si, di, eax, ebx, ecx, edx;
+
+ if (hb) {
+ unsigned long bp = channel->cookie_low;
+
+ si = channel->cookie_high;
+ di = (uintptr_t) reply;
+
+ VMW_PORT_HB_IN(
+ (MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG,
+ reply_len, si, di,
+ VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16),
+ VMW_HYPERVISOR_MAGIC, bp,
+ eax, ebx, ecx, edx, si, di);
+
+ return ebx;
+ }
+
+ /* HB port not available. Retrieve the message 4 bytes at a time. */
+ ecx = MESSAGE_STATUS_SUCCESS << 16;
+ while (reply_len) {
+ unsigned int bytes = min_t(unsigned long, reply_len, 4);
+
+ si = channel->cookie_high;
+ di = channel->cookie_low;
+
+ VMW_PORT(VMW_PORT_CMD_MSG | (MSG_TYPE_RECVPAYLOAD << 16),
+ MESSAGE_STATUS_SUCCESS, si, di,
+ VMW_HYPERVISOR_PORT | (channel->channel_id << 16),
+ VMW_HYPERVISOR_MAGIC,
+ eax, ebx, ecx, edx, si, di);
+
+ if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0)
+ break;
+
+ memcpy(reply, &ebx, bytes);
+ reply_len -= bytes;
+ reply += bytes;
+ }
+
+ return ecx;
+}
/**
@@ -148,11 +256,10 @@ static int vmw_close_channel(struct rpc_channel *channel)
*/
static int vmw_send_msg(struct rpc_channel *channel, const char *msg)
{
- unsigned long eax, ebx, ecx, edx, si, di, bp;
+ unsigned long eax, ebx, ecx, edx, si, di;
size_t msg_len = strlen(msg);
int retries = 0;
-
while (retries < RETRIES) {
retries++;
@@ -166,23 +273,14 @@ static int vmw_send_msg(struct rpc_channel *channel, const char *msg)
VMW_HYPERVISOR_MAGIC,
eax, ebx, ecx, edx, si, di);
- if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0 ||
- (HIGH_WORD(ecx) & MESSAGE_STATUS_HB) == 0) {
- /* Expected success + high-bandwidth. Give up. */
+ if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) {
+ /* Expected success. Give up. */
return -EINVAL;
}
/* Send msg */
- si = (uintptr_t) msg;
- di = channel->cookie_low;
- bp = channel->cookie_high;
-
- VMW_PORT_HB_OUT(
- (MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG,
- msg_len, si, di,
- VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16),
- VMW_HYPERVISOR_MAGIC, bp,
- eax, ebx, ecx, edx, si, di);
+ ebx = vmw_port_hb_out(channel, msg,
+ !!(HIGH_WORD(ecx) & MESSAGE_STATUS_HB));
if ((HIGH_WORD(ebx) & MESSAGE_STATUS_SUCCESS) != 0) {
return 0;
@@ -211,7 +309,7 @@ STACK_FRAME_NON_STANDARD(vmw_send_msg);
static int vmw_recv_msg(struct rpc_channel *channel, void **msg,
size_t *msg_len)
{
- unsigned long eax, ebx, ecx, edx, si, di, bp;
+ unsigned long eax, ebx, ecx, edx, si, di;
char *reply;
size_t reply_len;
int retries = 0;
@@ -233,8 +331,7 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg,
VMW_HYPERVISOR_MAGIC,
eax, ebx, ecx, edx, si, di);
- if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0 ||
- (HIGH_WORD(ecx) & MESSAGE_STATUS_HB) == 0) {
+ if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) {
DRM_ERROR("Failed to get reply size for host message.\n");
return -EINVAL;
}
@@ -252,17 +349,8 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg,
/* Receive buffer */
- si = channel->cookie_high;
- di = (uintptr_t) reply;
- bp = channel->cookie_low;
-
- VMW_PORT_HB_IN(
- (MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG,
- reply_len, si, di,
- VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16),
- VMW_HYPERVISOR_MAGIC, bp,
- eax, ebx, ecx, edx, si, di);
-
+ ebx = vmw_port_hb_in(channel, reply, reply_len,
+ !!(HIGH_WORD(ecx) & MESSAGE_STATUS_HB));
if ((HIGH_WORD(ebx) & MESSAGE_STATUS_SUCCESS) == 0) {
kfree(reply);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c
index a6ea75b58a83..d8ea3dd10af0 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c
@@ -441,11 +441,11 @@ static int vmw_ttm_map_dma(struct vmw_ttm_tt *vmw_tt)
if (unlikely(ret != 0))
return ret;
- ret = sg_alloc_table_from_pages(&vmw_tt->sgt, vsgt->pages,
- vsgt->num_pages, 0,
- (unsigned long)
- vsgt->num_pages << PAGE_SHIFT,
- GFP_KERNEL);
+ ret = __sg_alloc_table_from_pages
+ (&vmw_tt->sgt, vsgt->pages, vsgt->num_pages, 0,
+ (unsigned long) vsgt->num_pages << PAGE_SHIFT,
+ dma_get_max_seg_size(dev_priv->dev->dev),
+ GFP_KERNEL);
if (unlikely(ret != 0))
goto out_sg_alloc_fail;
diff --git a/drivers/gpu/drm/zte/zx_common_regs.h b/drivers/gpu/drm/zte/zx_common_regs.h
index 2afd80664c51..b7b996db129d 100644
--- a/drivers/gpu/drm/zte/zx_common_regs.h
+++ b/drivers/gpu/drm/zte/zx_common_regs.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2017 Sanechips Technology Co., Ltd.
* Copyright 2017 Linaro Ltd.
- *
- * 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.
*/
#ifndef __ZX_COMMON_REGS_H__
diff --git a/drivers/gpu/drm/zte/zx_drm_drv.c b/drivers/gpu/drm/zte/zx_drm_drv.c
index 28e8d6072910..520d7369f85a 100644
--- a/drivers/gpu/drm/zte/zx_drm_drv.c
+++ b/drivers/gpu/drm/zte/zx_drm_drv.c
@@ -1,11 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2016 Linaro Ltd.
* Copyright 2016 ZTE Corporation.
- *
- * 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.
- *
*/
#include <linux/clk.h>
diff --git a/drivers/gpu/drm/zte/zx_drm_drv.h b/drivers/gpu/drm/zte/zx_drm_drv.h
index 2a8cdc5f8be4..80cdaf479c74 100644
--- a/drivers/gpu/drm/zte/zx_drm_drv.h
+++ b/drivers/gpu/drm/zte/zx_drm_drv.h
@@ -1,11 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2016 Linaro Ltd.
* Copyright 2016 ZTE Corporation.
- *
- * 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.
- *
*/
#ifndef __ZX_DRM_DRV_H__
diff --git a/drivers/gpu/drm/zte/zx_hdmi.c b/drivers/gpu/drm/zte/zx_hdmi.c
index df522d74bebf..bfe918b27c5c 100644
--- a/drivers/gpu/drm/zte/zx_hdmi.c
+++ b/drivers/gpu/drm/zte/zx_hdmi.c
@@ -1,11 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2016 Linaro Ltd.
* Copyright 2016 ZTE Corporation.
- *
- * 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.
- *
*/
#include <linux/clk.h>
diff --git a/drivers/gpu/drm/zte/zx_hdmi_regs.h b/drivers/gpu/drm/zte/zx_hdmi_regs.h
index c6d5d8211725..397949e64eff 100644
--- a/drivers/gpu/drm/zte/zx_hdmi_regs.h
+++ b/drivers/gpu/drm/zte/zx_hdmi_regs.h
@@ -1,11 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2016 Linaro Ltd.
* Copyright 2016 ZTE Corporation.
- *
- * 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.
- *
*/
#ifndef __ZX_HDMI_REGS_H__
diff --git a/drivers/gpu/drm/zte/zx_plane.c b/drivers/gpu/drm/zte/zx_plane.c
index 706452f9b276..6b812aad411b 100644
--- a/drivers/gpu/drm/zte/zx_plane.c
+++ b/drivers/gpu/drm/zte/zx_plane.c
@@ -1,11 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2016 Linaro Ltd.
* Copyright 2016 ZTE Corporation.
- *
- * 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.
- *
*/
#include <drm/drm_atomic.h>
diff --git a/drivers/gpu/drm/zte/zx_plane.h b/drivers/gpu/drm/zte/zx_plane.h
index 933611ddffd0..5a7cc8b3b985 100644
--- a/drivers/gpu/drm/zte/zx_plane.h
+++ b/drivers/gpu/drm/zte/zx_plane.h
@@ -1,11 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2016 Linaro Ltd.
* Copyright 2016 ZTE Corporation.
- *
- * 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.
- *
*/
#ifndef __ZX_PLANE_H__
diff --git a/drivers/gpu/drm/zte/zx_plane_regs.h b/drivers/gpu/drm/zte/zx_plane_regs.h
index 9c655f59f9f7..ce830637a92d 100644
--- a/drivers/gpu/drm/zte/zx_plane_regs.h
+++ b/drivers/gpu/drm/zte/zx_plane_regs.h
@@ -1,11 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2016 Linaro Ltd.
* Copyright 2016 ZTE Corporation.
- *
- * 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.
- *
*/
#ifndef __ZX_PLANE_REGS_H__
diff --git a/drivers/gpu/drm/zte/zx_tvenc.c b/drivers/gpu/drm/zte/zx_tvenc.c
index 87b5d86413d2..a768c567b557 100644
--- a/drivers/gpu/drm/zte/zx_tvenc.c
+++ b/drivers/gpu/drm/zte/zx_tvenc.c
@@ -1,11 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2017 Linaro Ltd.
* Copyright 2017 ZTE Corporation.
- *
- * 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.
- *
*/
#include <linux/clk.h>
diff --git a/drivers/gpu/drm/zte/zx_tvenc_regs.h b/drivers/gpu/drm/zte/zx_tvenc_regs.h
index bd91f5dcc1f3..40f033109374 100644
--- a/drivers/gpu/drm/zte/zx_tvenc_regs.h
+++ b/drivers/gpu/drm/zte/zx_tvenc_regs.h
@@ -1,11 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2017 Linaro Ltd.
* Copyright 2017 ZTE Corporation.
- *
- * 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.
- *
*/
#ifndef __ZX_TVENC_REGS_H__
diff --git a/drivers/gpu/drm/zte/zx_vga.c b/drivers/gpu/drm/zte/zx_vga.c
index e14c1d709740..1634a08707fb 100644
--- a/drivers/gpu/drm/zte/zx_vga.c
+++ b/drivers/gpu/drm/zte/zx_vga.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2017 Sanechips Technology Co., Ltd.
* Copyright 2017 Linaro Ltd.
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/gpu/drm/zte/zx_vga_regs.h b/drivers/gpu/drm/zte/zx_vga_regs.h
index feaa345fe6a6..1e8825ae70a5 100644
--- a/drivers/gpu/drm/zte/zx_vga_regs.h
+++ b/drivers/gpu/drm/zte/zx_vga_regs.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2017 Sanechips Technology Co., Ltd.
* Copyright 2017 Linaro Ltd.
- *
- * 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.
*/
#ifndef __ZX_VGA_REGS_H__
diff --git a/drivers/gpu/drm/zte/zx_vou.c b/drivers/gpu/drm/zte/zx_vou.c
index 15400ffb1d22..81b4cf107b75 100644
--- a/drivers/gpu/drm/zte/zx_vou.c
+++ b/drivers/gpu/drm/zte/zx_vou.c
@@ -1,11 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2016 Linaro Ltd.
* Copyright 2016 ZTE Corporation.
- *
- * 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.
- *
*/
#include <linux/clk.h>
diff --git a/drivers/gpu/drm/zte/zx_vou.h b/drivers/gpu/drm/zte/zx_vou.h
index 5b7f84fbb112..b25f34f865ae 100644
--- a/drivers/gpu/drm/zte/zx_vou.h
+++ b/drivers/gpu/drm/zte/zx_vou.h
@@ -1,11 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2016 Linaro Ltd.
* Copyright 2016 ZTE Corporation.
- *
- * 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.
- *
*/
#ifndef __ZX_VOU_H__
diff --git a/drivers/gpu/drm/zte/zx_vou_regs.h b/drivers/gpu/drm/zte/zx_vou_regs.h
index 5a218351b497..2ddb199cb912 100644
--- a/drivers/gpu/drm/zte/zx_vou_regs.h
+++ b/drivers/gpu/drm/zte/zx_vou_regs.h
@@ -1,11 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2016 Linaro Ltd.
* Copyright 2016 ZTE Corporation.
- *
- * 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.
- *
*/
#ifndef __ZX_VOU_REGS_H__
diff --git a/drivers/gpu/ipu-v3/ipu-image-convert.c b/drivers/gpu/ipu-v3/ipu-image-convert.c
index 61643382bbde..9d25db6924b3 100644
--- a/drivers/gpu/ipu-v3/ipu-image-convert.c
+++ b/drivers/gpu/ipu-v3/ipu-image-convert.c
@@ -401,12 +401,14 @@ static int calc_image_resize_coefficients(struct ipu_image_convert_ctx *ctx,
if (WARN_ON(resized_width == 0 || resized_height == 0))
return -EINVAL;
- while (downsized_width >= resized_width * 2) {
+ while (downsized_width > 1024 ||
+ downsized_width >= resized_width * 2) {
downsized_width >>= 1;
downsize_coeff_h++;
}
- while (downsized_height >= resized_height * 2) {
+ while (downsized_height > 1024 ||
+ downsized_height >= resized_height * 2) {
downsized_height >>= 1;
downsize_coeff_v++;
}
@@ -1881,7 +1883,8 @@ void ipu_image_convert_adjust(struct ipu_image *in, struct ipu_image *out,
enum ipu_rotate_mode rot_mode)
{
const struct ipu_image_pixfmt *infmt, *outfmt;
- u32 w_align, h_align;
+ u32 w_align_out, h_align_out;
+ u32 w_align_in, h_align_in;
infmt = get_format(in->pix.pixelformat);
outfmt = get_format(out->pix.pixelformat);
@@ -1913,22 +1916,33 @@ void ipu_image_convert_adjust(struct ipu_image *in, struct ipu_image *out,
}
/* align input width/height */
- w_align = ilog2(tile_width_align(IMAGE_CONVERT_IN, infmt, rot_mode));
- h_align = ilog2(tile_height_align(IMAGE_CONVERT_IN, infmt, rot_mode));
- in->pix.width = clamp_align(in->pix.width, MIN_W, MAX_W, w_align);
- in->pix.height = clamp_align(in->pix.height, MIN_H, MAX_H, h_align);
+ w_align_in = ilog2(tile_width_align(IMAGE_CONVERT_IN, infmt,
+ rot_mode));
+ h_align_in = ilog2(tile_height_align(IMAGE_CONVERT_IN, infmt,
+ rot_mode));
+ in->pix.width = clamp_align(in->pix.width, MIN_W, MAX_W,
+ w_align_in);
+ in->pix.height = clamp_align(in->pix.height, MIN_H, MAX_H,
+ h_align_in);
/* align output width/height */
- w_align = ilog2(tile_width_align(IMAGE_CONVERT_OUT, outfmt, rot_mode));
- h_align = ilog2(tile_height_align(IMAGE_CONVERT_OUT, outfmt, rot_mode));
- out->pix.width = clamp_align(out->pix.width, MIN_W, MAX_W, w_align);
- out->pix.height = clamp_align(out->pix.height, MIN_H, MAX_H, h_align);
+ w_align_out = ilog2(tile_width_align(IMAGE_CONVERT_OUT, outfmt,
+ rot_mode));
+ h_align_out = ilog2(tile_height_align(IMAGE_CONVERT_OUT, outfmt,
+ rot_mode));
+ out->pix.width = clamp_align(out->pix.width, MIN_W, MAX_W,
+ w_align_out);
+ out->pix.height = clamp_align(out->pix.height, MIN_H, MAX_H,
+ h_align_out);
/* set input/output strides and image sizes */
in->pix.bytesperline = infmt->planar ?
- clamp_align(in->pix.width, 2 << w_align, MAX_W, w_align) :
+ clamp_align(in->pix.width, 2 << w_align_in, MAX_W,
+ w_align_in) :
clamp_align((in->pix.width * infmt->bpp) >> 3,
- 2 << w_align, MAX_W, w_align);
+ ((2 << w_align_in) * infmt->bpp) >> 3,
+ (MAX_W * infmt->bpp) >> 3,
+ w_align_in);
in->pix.sizeimage = infmt->planar ?
(in->pix.height * in->pix.bytesperline * infmt->bpp) >> 3 :
in->pix.height * in->pix.bytesperline;
diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
index 5b37c570f611..8063b1d567b1 100644
--- a/drivers/hid/hid-asus.c
+++ b/drivers/hid/hid-asus.c
@@ -393,7 +393,7 @@ static bool asus_kbd_wmi_led_control_present(struct hid_device *hdev)
if (!IS_ENABLED(CONFIG_ASUS_WMI))
return false;
- ret = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS2,
+ ret = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS,
ASUS_WMI_DEVID_KBD_BACKLIGHT, 0, &value);
hid_dbg(hdev, "WMI backlight check: rc %d value %x", ret, value);
if (ret)
diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c
index 8bbe3d0cbe5d..2310c96ccf4a 100644
--- a/drivers/hid/hid-cp2112.c
+++ b/drivers/hid/hid-cp2112.c
@@ -16,7 +16,8 @@
* https://www.silabs.com/documents/public/application-notes/an495-cp2112-interface-specification.pdf
*/
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/machine.h>
#include <linux/gpio/driver.h>
#include <linux/hid.h>
#include <linux/hidraw.h>
@@ -1195,7 +1196,9 @@ static int __maybe_unused cp2112_allocate_irq(struct cp2112_device *dev,
return -EINVAL;
dev->desc[pin] = gpiochip_request_own_desc(&dev->gc, pin,
- "HID/I2C:Event", 0);
+ "HID/I2C:Event",
+ GPIO_ACTIVE_HIGH,
+ GPIOD_IN);
if (IS_ERR(dev->desc[pin])) {
dev_err(dev->gc.parent, "Failed to request GPIO\n");
return PTR_ERR(dev->desc[pin]);
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index eac0c54c5970..0d695f8e1b2c 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -80,6 +80,7 @@
#define HID_DEVICE_ID_ALPS_U1_DUAL_3BTN_PTP 0x1220
#define HID_DEVICE_ID_ALPS_U1 0x1215
#define HID_DEVICE_ID_ALPS_T4_BTNLESS 0x120C
+#define HID_DEVICE_ID_ALPS_1222 0x1222
#define USB_VENDOR_ID_AMI 0x046b
@@ -269,6 +270,7 @@
#define USB_DEVICE_ID_CHICONY_MULTI_TOUCH 0xb19d
#define USB_DEVICE_ID_CHICONY_WIRELESS 0x0618
#define USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE 0x1053
+#define USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE2 0x0939
#define USB_DEVICE_ID_CHICONY_WIRELESS2 0x1123
#define USB_DEVICE_ID_ASUS_AK1D 0x1125
#define USB_DEVICE_ID_CHICONY_TOSHIBA_WT10A 0x1408
@@ -569,6 +571,7 @@
#define USB_VENDOR_ID_HUION 0x256c
#define USB_DEVICE_ID_HUION_TABLET 0x006e
+#define USB_DEVICE_ID_HUION_HS64 0x006d
#define USB_VENDOR_ID_IBM 0x04b3
#define USB_DEVICE_ID_IBM_SCROLLPOINT_III 0x3100
@@ -1154,6 +1157,7 @@
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01 0x0042
#define USB_DEVICE_ID_UGEE_TABLET_G5 0x0074
#define USB_DEVICE_ID_UGEE_TABLET_EX07S 0x0071
+#define USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720 0x0055
#define USB_VENDOR_ID_UNITEC 0x227d
#define USB_DEVICE_ID_UNITEC_USB_TOUCH_0709 0x0709
@@ -1238,6 +1242,7 @@
#define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05
#define USB_DEVICE_ID_PRIMAX_REZEL 0x4e72
#define USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D0F 0x4d0f
+#define USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D65 0x4d65
#define USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4E22 0x4e22
diff --git a/drivers/hid/hid-ite.c b/drivers/hid/hid-ite.c
index 98b059d79bc8..a45f2352618d 100644
--- a/drivers/hid/hid-ite.c
+++ b/drivers/hid/hid-ite.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* HID driver for some ITE "special" devices
* Copyright (c) 2017 Hans de Goede <hdegoede@redhat.com>
- *
- * 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.
*/
#include <linux/device.h>
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index c8c6d0436ac9..5008a3dc28f4 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -869,8 +869,6 @@ static void lg_remove(struct hid_device *hdev)
}
static const struct hid_device_id lg_devices[] = {
- { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
- .driver_data = LG_RDESC | LG_WIRELESS },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
.driver_data = LG_RDESC | LG_WIRELESS },
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
index e564bff86515..6196217a7d93 100644
--- a/drivers/hid/hid-logitech-dj.c
+++ b/drivers/hid/hid-logitech-dj.c
@@ -30,6 +30,7 @@
#define REPORT_ID_HIDPP_SHORT 0x10
#define REPORT_ID_HIDPP_LONG 0x11
+#define REPORT_ID_HIDPP_VERY_LONG 0x12
#define HIDPP_REPORT_SHORT_LENGTH 7
#define HIDPP_REPORT_LONG_LENGTH 20
@@ -1102,12 +1103,14 @@ static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev,
static int logi_dj_recv_query_hidpp_devices(struct dj_receiver_dev *djrcv_dev)
{
- const u8 template[] = {REPORT_ID_HIDPP_SHORT,
- HIDPP_RECEIVER_INDEX,
- HIDPP_SET_REGISTER,
- HIDPP_REG_CONNECTION_STATE,
- HIDPP_FAKE_DEVICE_ARRIVAL,
- 0x00, 0x00};
+ static const u8 template[] = {
+ REPORT_ID_HIDPP_SHORT,
+ HIDPP_RECEIVER_INDEX,
+ HIDPP_SET_REGISTER,
+ HIDPP_REG_CONNECTION_STATE,
+ HIDPP_FAKE_DEVICE_ARRIVAL,
+ 0x00, 0x00
+ };
u8 *hidpp_report;
int retval;
@@ -1122,7 +1125,7 @@ static int logi_dj_recv_query_hidpp_devices(struct dj_receiver_dev *djrcv_dev)
HID_REQ_SET_REPORT);
kfree(hidpp_report);
- return 0;
+ return retval;
}
static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
@@ -1242,7 +1245,8 @@ static int logi_dj_ll_raw_request(struct hid_device *hid,
int ret;
if ((buf[0] == REPORT_ID_HIDPP_SHORT) ||
- (buf[0] == REPORT_ID_HIDPP_LONG)) {
+ (buf[0] == REPORT_ID_HIDPP_LONG) ||
+ (buf[0] == REPORT_ID_HIDPP_VERY_LONG)) {
if (count < 2)
return -EINVAL;
@@ -1832,6 +1836,9 @@ static const struct hid_device_id logi_dj_receivers[] = {
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_GAMING),
.driver_data = recvr_type_gaming_hidpp},
+ { /* Logitech 27 MHz HID++ 1.0 receiver (0xc513) */
+ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
+ .driver_data = recvr_type_27mhz},
{ /* Logitech 27 MHz HID++ 1.0 receiver (0xc517) */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
USB_DEVICE_ID_S510_RECEIVER_2),
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index cf05816a601f..e3b6245bf4b2 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -2858,7 +2858,7 @@ static u8 *hidpp10_consumer_keys_report_fixup(struct hidpp_device *hidpp,
u8 *_rdesc, unsigned int *rsize)
{
/* Note 0 terminated so we can use strnstr to search for this. */
- const char consumer_rdesc_start[] = {
+ static const char consumer_rdesc_start[] = {
0x05, 0x0C, /* USAGE_PAGE (Consumer Devices) */
0x09, 0x01, /* USAGE (Consumer Control) */
0xA1, 0x01, /* COLLECTION (Application) */
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 5df5dd56ecc8..b603c14d043b 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -1776,6 +1776,10 @@ static const struct hid_device_id mt_devices[] = {
HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
USB_VENDOR_ID_ALPS_JP,
HID_DEVICE_ID_ALPS_U1_DUAL_3BTN_PTP) },
+ { .driver_data = MT_CLS_WIN_8_DUAL,
+ HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
+ USB_VENDOR_ID_ALPS_JP,
+ HID_DEVICE_ID_ALPS_1222) },
/* Lenovo X1 TAB Gen 2 */
{ .driver_data = MT_CLS_WIN_8_DUAL,
diff --git a/drivers/hid/hid-picolcd_fb.c b/drivers/hid/hid-picolcd_fb.c
index 6897e14e7cb7..e162a668fb7e 100644
--- a/drivers/hid/hid-picolcd_fb.c
+++ b/drivers/hid/hid-picolcd_fb.c
@@ -512,10 +512,8 @@ int picolcd_init_framebuffer(struct picolcd_data *data)
sizeof(struct fb_deferred_io) +
sizeof(struct picolcd_fb_data) +
PICOLCDFB_SIZE, dev);
- if (info == NULL) {
- dev_err(dev, "failed to allocate a framebuffer\n");
+ if (!info)
goto err_nomem;
- }
info->fbdefio = info->par;
*info->fbdefio = picolcd_fb_defio;
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index e5ca6fe2ca57..185a577c46f6 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -16,6 +16,7 @@
#include <linux/export.h>
#include <linux/slab.h>
#include <linux/mutex.h>
+#include <linux/input/elan-i2c-ids.h>
#include "hid-ids.h"
@@ -42,6 +43,7 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM), HID_QUIRK_NOGET },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE2), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD), HID_QUIRK_BADPAD },
{ HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK), HID_QUIRK_NOGET },
@@ -129,6 +131,7 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_MOUSE_4D22), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D0F), HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D65), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4E22), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS), HID_QUIRK_NOGET },
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001), HID_QUIRK_NOGET },
@@ -914,6 +917,8 @@ static const struct hid_device_id hid_mouse_ignore_list[] = {
bool hid_ignore(struct hid_device *hdev)
{
+ int i;
+
if (hdev->quirks & HID_QUIRK_NO_IGNORE)
return false;
if (hdev->quirks & HID_QUIRK_IGNORE)
@@ -978,18 +983,15 @@ bool hid_ignore(struct hid_device *hdev)
break;
case USB_VENDOR_ID_ELAN:
/*
- * Many Elan devices have a product id of 0x0401 and are handled
- * by the elan_i2c input driver. But the ACPI HID ELAN0800 dev
- * is not (and cannot be) handled by that driver ->
- * Ignore all 0x0401 devs except for the ELAN0800 dev.
+ * Blacklist of everything that gets handled by the elan_i2c
+ * input driver. This avoids disabling valid touchpads and
+ * other ELAN devices.
*/
- if (hdev->product == 0x0401 &&
- strncmp(hdev->name, "ELAN0800", 8) != 0)
- return true;
- /* Same with product id 0x0400 */
- if (hdev->product == 0x0400 &&
- strncmp(hdev->name, "QTEC0001", 8) != 0)
- return true;
+ if ((hdev->product == 0x0401 || hdev->product == 0x0400))
+ for (i = 0; strlen(elan_acpi_id[i].id); ++i)
+ if (!strncmp(hdev->name, elan_acpi_id[i].id,
+ strlen(elan_acpi_id[i].id)))
+ return true;
break;
}
diff --git a/drivers/hid/hid-sensor-custom.c b/drivers/hid/hid-sensor-custom.c
index c60f82673cf2..fb827c295842 100644
--- a/drivers/hid/hid-sensor-custom.c
+++ b/drivers/hid/hid-sensor-custom.c
@@ -687,7 +687,7 @@ static int hid_sensor_custom_open(struct inode *inode, struct file *file)
if (test_and_set_bit(0, &sensor_inst->misc_opened))
return -EBUSY;
- return nonseekable_open(inode, file);
+ return stream_open(inode, file);
}
static __poll_t hid_sensor_custom_poll(struct file *file,
diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c
index 8fe02d81265d..86b568037cb8 100644
--- a/drivers/hid/hid-uclogic-core.c
+++ b/drivers/hid/hid-uclogic-core.c
@@ -369,6 +369,8 @@ static const struct hid_device_id uclogic_devices[] = {
USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HUION,
USB_DEVICE_ID_HUION_TABLET) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HUION,
+ USB_DEVICE_ID_HUION_HS64) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
USB_DEVICE_ID_HUION_TABLET) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
@@ -388,6 +390,8 @@ static const struct hid_device_id uclogic_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_TABLET_EX07S) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
+ USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640) },
diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c
index 0187c9f8fc22..78a364ae2f68 100644
--- a/drivers/hid/hid-uclogic-params.c
+++ b/drivers/hid/hid-uclogic-params.c
@@ -977,6 +977,8 @@ int uclogic_params_init(struct uclogic_params *params,
/* FALL THROUGH */
case VID_PID(USB_VENDOR_ID_HUION,
USB_DEVICE_ID_HUION_TABLET):
+ case VID_PID(USB_VENDOR_ID_HUION,
+ USB_DEVICE_ID_HUION_HS64):
case VID_PID(USB_VENDOR_ID_UCLOGIC,
USB_DEVICE_ID_HUION_TABLET):
case VID_PID(USB_VENDOR_ID_UCLOGIC,
@@ -999,6 +1001,8 @@ int uclogic_params_init(struct uclogic_params *params,
USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540):
case VID_PID(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640):
+ case VID_PID(USB_VENDOR_ID_UGEE,
+ USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720):
/* If this is the pen interface */
if (bInterfaceNumber == 1) {
/* Probe v1 pen parameters */
diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c
index 17ae49fba920..aa80b4d3b740 100644
--- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c
+++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c
@@ -184,6 +184,7 @@ static void ish_remove(struct pci_dev *pdev)
struct ishtp_device *ishtp_dev = pci_get_drvdata(pdev);
ishtp_bus_remove_all_clients(ishtp_dev, false);
+ pdev->dev_flags &= ~PCI_DEV_FLAGS_NO_D3;
ish_device_disable(ishtp_dev);
}
diff --git a/drivers/hid/intel-ish-hid/ishtp-fw-loader.c b/drivers/hid/intel-ish-hid/ishtp-fw-loader.c
index 22ba21457035..aa2dbed30fc3 100644
--- a/drivers/hid/intel-ish-hid/ishtp-fw-loader.c
+++ b/drivers/hid/intel-ish-hid/ishtp-fw-loader.c
@@ -816,9 +816,9 @@ static int load_fw_from_host(struct ishtp_cl_data *client_data)
goto end_err_fw_release;
release_firmware(fw);
- kfree(filename);
dev_info(cl_data_to_dev(client_data), "ISH firmware %s loaded\n",
filename);
+ kfree(filename);
return 0;
end_err_fw_release:
diff --git a/drivers/hid/intel-ish-hid/ishtp-hid-client.c b/drivers/hid/intel-ish-hid/ishtp-hid-client.c
index c0487b34d2cf..6ba944b40fdb 100644
--- a/drivers/hid/intel-ish-hid/ishtp-hid-client.c
+++ b/drivers/hid/intel-ish-hid/ishtp-hid-client.c
@@ -891,7 +891,7 @@ static int hid_ishtp_cl_reset(struct ishtp_cl_device *cl_device)
*/
static int hid_ishtp_cl_suspend(struct device *device)
{
- struct ishtp_cl_device *cl_device = dev_get_drvdata(device);
+ struct ishtp_cl_device *cl_device = ishtp_dev_to_cl_device(device);
struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
@@ -912,7 +912,7 @@ static int hid_ishtp_cl_suspend(struct device *device)
*/
static int hid_ishtp_cl_resume(struct device *device)
{
- struct ishtp_cl_device *cl_device = dev_get_drvdata(device);
+ struct ishtp_cl_device *cl_device = ishtp_dev_to_cl_device(device);
struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.c b/drivers/hid/intel-ish-hid/ishtp/bus.c
index 794e700d65f7..c47c3328a0f4 100644
--- a/drivers/hid/intel-ish-hid/ishtp/bus.c
+++ b/drivers/hid/intel-ish-hid/ishtp/bus.c
@@ -471,7 +471,6 @@ static struct ishtp_cl_device *ishtp_bus_add_device(struct ishtp_device *dev,
}
ishtp_device_ready = true;
- dev_set_drvdata(&device->dev, device);
return device;
}
@@ -640,6 +639,20 @@ void *ishtp_get_drvdata(struct ishtp_cl_device *cl_device)
EXPORT_SYMBOL(ishtp_get_drvdata);
/**
+ * ishtp_dev_to_cl_device() - get ishtp_cl_device instance from device instance
+ * @device: device instance
+ *
+ * Get ish_cl_device instance which embeds device instance in it.
+ *
+ * Return: pointer to ishtp_cl_device instance
+ */
+struct ishtp_cl_device *ishtp_dev_to_cl_device(struct device *device)
+{
+ return to_ishtp_cl_device(device);
+}
+EXPORT_SYMBOL(ishtp_dev_to_cl_device);
+
+/**
* ishtp_bus_new_client() - Create a new client
* @dev: ISHTP device instance
*
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
index 83dd3a2a7316..53bddb50aeba 100644
--- a/drivers/hid/wacom_sys.c
+++ b/drivers/hid/wacom_sys.c
@@ -304,18 +304,23 @@ static void wacom_feature_mapping(struct hid_device *hdev,
wacom_hid_usage_quirk(hdev, field, usage);
switch (equivalent_usage) {
+ case WACOM_HID_WD_TOUCH_RING_SETTING:
+ wacom->generic_has_leds = true;
+ break;
case HID_DG_CONTACTMAX:
/* leave touch_max as is if predefined */
if (!features->touch_max) {
/* read manually */
- data = kzalloc(2, GFP_KERNEL);
+ n = hid_report_len(field->report);
+ data = hid_alloc_report_buf(field->report, GFP_KERNEL);
if (!data)
break;
data[0] = field->report->id;
ret = wacom_get_report(hdev, HID_FEATURE_REPORT,
- data, 2, WAC_CMD_RETRIES);
- if (ret == 2) {
- features->touch_max = data[1];
+ data, n, WAC_CMD_RETRIES);
+ if (ret == n) {
+ ret = hid_report_raw_event(hdev,
+ HID_FEATURE_REPORT, data, n, 0);
} else {
features->touch_max = 16;
hid_warn(hdev, "wacom_feature_mapping: "
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index 43f6da357165..8fc36a28081b 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -1216,7 +1216,8 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
unsigned char *data = wacom->data;
int i;
- if (wacom->features.type == INTUOSP2_BT) {
+ if (wacom->features.type == INTUOSP2_BT ||
+ wacom->features.type == INTUOSP2S_BT) {
wacom->serial[0] = get_unaligned_le64(&data[99]);
wacom->id[0] = get_unaligned_le16(&data[107]);
pen_frame_len = 14;
@@ -1268,7 +1269,8 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
input_report_abs(pen_input, ABS_X, get_unaligned_le16(&frame[1]));
input_report_abs(pen_input, ABS_Y, get_unaligned_le16(&frame[3]));
- if (wacom->features.type == INTUOSP2_BT) {
+ if (wacom->features.type == INTUOSP2_BT ||
+ wacom->features.type == INTUOSP2S_BT) {
/* Fix rotation alignment: userspace expects zero at left */
int16_t rotation =
(int16_t)get_unaligned_le16(&frame[9]);
@@ -1286,7 +1288,6 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
get_unaligned_le16(&frame[11]));
}
}
-
if (wacom->tool[0]) {
input_report_abs(pen_input, ABS_PRESSURE, get_unaligned_le16(&frame[5]));
if (wacom->features.type == INTUOSP2_BT) {
@@ -1456,7 +1457,8 @@ static int wacom_intuos_pro2_bt_irq(struct wacom_wac *wacom, size_t len)
}
wacom_intuos_pro2_bt_pen(wacom);
- if (wacom->features.type == INTUOSP2_BT) {
+ if (wacom->features.type == INTUOSP2_BT ||
+ wacom->features.type == INTUOSP2S_BT) {
wacom_intuos_pro2_bt_touch(wacom);
wacom_intuos_pro2_bt_pad(wacom);
wacom_intuos_pro2_bt_battery(wacom);
@@ -1768,6 +1770,9 @@ int wacom_equivalent_usage(int usage)
int subpage = (usage & 0xFF00) << 8;
int subusage = (usage & 0xFF);
+ if (usage == WACOM_HID_WT_REPORT_VALID)
+ return usage;
+
if (subpage == HID_UP_UNDEFINED)
subpage = WACOM_HID_SP_DIGITIZER;
@@ -1926,8 +1931,6 @@ static void wacom_wac_pad_usage_mapping(struct hid_device *hdev,
features->device_type |= WACOM_DEVICETYPE_PAD;
break;
case WACOM_HID_WD_BUTTONCENTER:
- wacom->generic_has_leds = true;
- /* fall through */
case WACOM_HID_WD_BUTTONHOME:
case WACOM_HID_WD_BUTTONUP:
case WACOM_HID_WD_BUTTONDOWN:
@@ -2043,12 +2046,16 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
*/
if (hdev->vendor == 0x56a &&
(hdev->product == 0x34d || hdev->product == 0x34e || /* MobileStudio Pro */
- hdev->product == 0x357 || hdev->product == 0x358)) { /* Intuos Pro 2 */
+ hdev->product == 0x357 || hdev->product == 0x358 || /* Intuos Pro 2 */
+ hdev->product == 0x392 || /* Intuos Pro 2 */
+ hdev->product == 0x399)) { /* MobileStudio Pro */
value = (field->logical_maximum - value);
- if (hdev->product == 0x357 || hdev->product == 0x358)
+ if (hdev->product == 0x357 || hdev->product == 0x358 ||
+ hdev->product == 0x392)
value = wacom_offset_rotation(input, usage, value, 3, 16);
- else if (hdev->product == 0x34d || hdev->product == 0x34e)
+ else if (hdev->product == 0x34d || hdev->product == 0x34e ||
+ hdev->product == 0x399)
value = wacom_offset_rotation(input, usage, value, 1, 2);
}
else {
@@ -2119,14 +2126,12 @@ static void wacom_wac_pad_report(struct hid_device *hdev,
bool active = wacom_wac->hid_data.inrange_state != 0;
/* report prox for expresskey events */
- if ((wacom_equivalent_usage(field->physical) == HID_DG_TABLETFUNCTIONKEY) &&
- wacom_wac->hid_data.pad_input_event_flag) {
+ if (wacom_wac->hid_data.pad_input_event_flag) {
input_event(input, EV_ABS, ABS_MISC, active ? PAD_DEVICE_ID : 0);
input_sync(input);
if (!active)
wacom_wac->hid_data.pad_input_event_flag = false;
}
-
}
static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
@@ -2512,6 +2517,10 @@ static void wacom_wac_finger_event(struct hid_device *hdev,
struct wacom *wacom = hid_get_drvdata(hdev);
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
+ struct wacom_features *features = &wacom->wacom_wac.features;
+
+ if (wacom_wac->is_invalid_bt_frame)
+ return;
switch (equivalent_usage) {
case HID_GD_X:
@@ -2532,9 +2541,14 @@ static void wacom_wac_finger_event(struct hid_device *hdev,
case HID_DG_TIPSWITCH:
wacom_wac->hid_data.tipswitch = value;
break;
+ case WACOM_HID_WT_REPORT_VALID:
+ wacom_wac->is_invalid_bt_frame = !value;
+ return;
+ case HID_DG_CONTACTMAX:
+ features->touch_max = value;
+ return;
}
-
if (usage->usage_index + 1 == field->report_count) {
if (equivalent_usage == wacom_wac->hid_data.last_slot_field)
wacom_wac_finger_slot(wacom_wac, wacom_wac->touch_input);
@@ -2549,6 +2563,8 @@ static void wacom_wac_finger_pre_report(struct hid_device *hdev,
struct hid_data* hid_data = &wacom_wac->hid_data;
int i;
+ wacom_wac->is_invalid_bt_frame = false;
+
for (i = 0; i < report->maxfield; i++) {
struct hid_field *field = report->field[i];
int j;
@@ -2569,25 +2585,9 @@ static void wacom_wac_finger_pre_report(struct hid_device *hdev,
case HID_DG_TIPSWITCH:
hid_data->last_slot_field = equivalent_usage;
break;
- case HID_DG_CONTACTCOUNT:
- hid_data->cc_report = report->id;
- hid_data->cc_index = i;
- hid_data->cc_value_index = j;
- break;
}
}
}
-
- if (hid_data->cc_report != 0 &&
- hid_data->cc_index >= 0) {
- struct hid_field *field = report->field[hid_data->cc_index];
- int value = field->value[hid_data->cc_value_index];
- if (value)
- hid_data->num_expected = value;
- }
- else {
- hid_data->num_expected = wacom_wac->features.touch_max;
- }
}
static void wacom_wac_finger_report(struct hid_device *hdev,
@@ -2597,6 +2597,7 @@ static void wacom_wac_finger_report(struct hid_device *hdev,
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
struct input_dev *input = wacom_wac->touch_input;
unsigned touch_max = wacom_wac->features.touch_max;
+ struct hid_data *hid_data = &wacom_wac->hid_data;
/* If more packets of data are expected, give us a chance to
* process them rather than immediately syncing a partial
@@ -2610,6 +2611,7 @@ static void wacom_wac_finger_report(struct hid_device *hdev,
input_sync(input);
wacom_wac->hid_data.num_received = 0;
+ hid_data->num_expected = 0;
/* keep touch state for pen event */
wacom_wac->shared->touch_down = wacom_wac_finger_count_touches(wacom_wac);
@@ -2684,12 +2686,73 @@ static void wacom_report_events(struct hid_device *hdev,
}
}
+static void wacom_set_num_expected(struct hid_device *hdev,
+ struct hid_report *report,
+ int collection_index,
+ struct hid_field *field,
+ int field_index)
+{
+ struct wacom *wacom = hid_get_drvdata(hdev);
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct hid_data *hid_data = &wacom_wac->hid_data;
+ unsigned int original_collection_level =
+ hdev->collection[collection_index].level;
+ bool end_collection = false;
+ int i;
+
+ if (hid_data->num_expected)
+ return;
+
+ // find the contact count value for this segment
+ for (i = field_index; i < report->maxfield && !end_collection; i++) {
+ struct hid_field *field = report->field[i];
+ unsigned int field_level =
+ hdev->collection[field->usage[0].collection_index].level;
+ unsigned int j;
+
+ if (field_level != original_collection_level)
+ continue;
+
+ for (j = 0; j < field->maxusage; j++) {
+ struct hid_usage *usage = &field->usage[j];
+
+ if (usage->collection_index != collection_index) {
+ end_collection = true;
+ break;
+ }
+ if (wacom_equivalent_usage(usage->hid) == HID_DG_CONTACTCOUNT) {
+ hid_data->cc_report = report->id;
+ hid_data->cc_index = i;
+ hid_data->cc_value_index = j;
+
+ if (hid_data->cc_report != 0 &&
+ hid_data->cc_index >= 0) {
+
+ struct hid_field *field =
+ report->field[hid_data->cc_index];
+ int value =
+ field->value[hid_data->cc_value_index];
+
+ if (value)
+ hid_data->num_expected = value;
+ }
+ }
+ }
+ }
+
+ if (hid_data->cc_report == 0 || hid_data->cc_index < 0)
+ hid_data->num_expected = wacom_wac->features.touch_max;
+}
+
static int wacom_wac_collection(struct hid_device *hdev, struct hid_report *report,
int collection_index, struct hid_field *field,
int field_index)
{
struct wacom *wacom = hid_get_drvdata(hdev);
+ if (WACOM_FINGER_FIELD(field))
+ wacom_set_num_expected(hdev, report, collection_index, field,
+ field_index);
wacom_report_events(hdev, report, collection_index, field_index);
/*
@@ -2702,9 +2765,7 @@ static int wacom_wac_collection(struct hid_device *hdev, struct hid_report *repo
if (report->type != HID_INPUT_REPORT)
return -1;
- if (WACOM_PAD_FIELD(field) && wacom->wacom_wac.pad_input)
- wacom_wac_pad_report(hdev, report, field);
- else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input)
+ if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input)
wacom_wac_pen_report(hdev, report);
else if (WACOM_FINGER_FIELD(field) && wacom->wacom_wac.touch_input)
wacom_wac_finger_report(hdev, report);
@@ -2718,7 +2779,7 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
struct hid_field *field;
bool pad_in_hid_field = false, pen_in_hid_field = false,
- finger_in_hid_field = false;
+ finger_in_hid_field = false, true_pad = false;
int r;
int prev_collection = -1;
@@ -2734,6 +2795,8 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
pen_in_hid_field = true;
if (WACOM_FINGER_FIELD(field))
finger_in_hid_field = true;
+ if (wacom_equivalent_usage(field->physical) == HID_DG_TABLETFUNCTIONKEY)
+ true_pad = true;
}
wacom_wac_battery_pre_report(hdev, report);
@@ -2757,6 +2820,9 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
}
wacom_wac_battery_report(hdev, report);
+
+ if (true_pad && wacom->wacom_wac.pad_input)
+ wacom_wac_pad_report(hdev, report, field);
}
static int wacom_bpt_touch(struct wacom_wac *wacom)
@@ -3225,6 +3291,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
break;
case INTUOSP2_BT:
+ case INTUOSP2S_BT:
case INTUOSHT3_BT:
sync = wacom_intuos_pro2_bt_irq(wacom_wac, len);
break;
@@ -3405,7 +3472,8 @@ void wacom_setup_device_quirks(struct wacom *wacom)
if (features->type == REMOTE)
features->device_type = WACOM_DEVICETYPE_PAD;
- if (features->type == INTUOSP2_BT) {
+ if (features->type == INTUOSP2_BT ||
+ features->type == INTUOSP2S_BT) {
features->device_type |= WACOM_DEVICETYPE_PEN |
WACOM_DEVICETYPE_PAD |
WACOM_DEVICETYPE_TOUCH;
@@ -3586,6 +3654,7 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
case INTUOS5S:
case INTUOSPS:
case INTUOSP2_BT:
+ case INTUOSP2S_BT:
input_set_abs_params(input_dev, ABS_DISTANCE, 0,
features->distance_max,
features->distance_fuzz, 0);
@@ -3697,6 +3766,7 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
switch (features->type) {
case INTUOSP2_BT:
+ case INTUOSP2S_BT:
input_dev->evbit[0] |= BIT_MASK(EV_SW);
__set_bit(SW_MUTE_DEVICE, input_dev->swbit);
@@ -3712,8 +3782,14 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
0, 5920, 4, 0);
}
+ else if (wacom_wac->shared->touch->product == 0x393) {
+ input_set_abs_params(input_dev, ABS_MT_POSITION_X,
+ 0, 6400, 4, 0);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+ 0, 4000, 4, 0);
+ }
input_abs_set_res(input_dev, ABS_MT_POSITION_X, 40);
- input_abs_set_res(input_dev, ABS_MT_POSITION_X, 40);
+ input_abs_set_res(input_dev, ABS_MT_POSITION_Y, 40);
/* fall through */
@@ -4021,6 +4097,7 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
case INTUOS5S:
case INTUOSPS:
case INTUOSP2_BT:
+ case INTUOSP2S_BT:
input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
break;
@@ -4598,6 +4675,10 @@ static const struct wacom_features wacom_features_0x37A =
static const struct wacom_features wacom_features_0x37B =
{ "Wacom One by Wacom M", 21600, 13500, 2047, 63,
BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x393 =
+ { "Wacom Intuos Pro S", 31920, 19950, 8191, 63,
+ INTUOSP2S_BT, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7,
+ .touch_max = 10 };
static const struct wacom_features wacom_features_HID_ANY_ID =
{ "Wacom HID", .type = HID_GENERIC, .oVid = HID_ANY_ID, .oPid = HID_ANY_ID };
@@ -4770,6 +4851,7 @@ const struct hid_device_id wacom_ids[] = {
{ BT_DEVICE_WACOM(0x379) },
{ USB_DEVICE_WACOM(0x37A) },
{ USB_DEVICE_WACOM(0x37B) },
+ { BT_DEVICE_WACOM(0x393) },
{ USB_DEVICE_WACOM(0x4001) },
{ USB_DEVICE_WACOM(0x4004) },
{ USB_DEVICE_WACOM(0x5000) },
diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h
index cac68d1c20c5..da612b6e9c77 100644
--- a/drivers/hid/wacom_wac.h
+++ b/drivers/hid/wacom_wac.h
@@ -141,6 +141,7 @@
#define WACOM_HID_WD_OFFSETBOTTOM (WACOM_HID_UP_WACOMDIGITIZER | 0x0d33)
#define WACOM_HID_WD_DATAMODE (WACOM_HID_UP_WACOMDIGITIZER | 0x1002)
#define WACOM_HID_WD_DIGITIZERINFO (WACOM_HID_UP_WACOMDIGITIZER | 0x1013)
+#define WACOM_HID_WD_TOUCH_RING_SETTING (WACOM_HID_UP_WACOMDIGITIZER | 0x1032)
#define WACOM_HID_UP_G9 0xff090000
#define WACOM_HID_G9_PEN (WACOM_HID_UP_G9 | 0x02)
#define WACOM_HID_G9_TOUCHSCREEN (WACOM_HID_UP_G9 | 0x11)
@@ -154,6 +155,7 @@
#define WACOM_HID_WT_SERIALNUMBER (WACOM_HID_UP_WACOMTOUCH | 0x5b)
#define WACOM_HID_WT_X (WACOM_HID_UP_WACOMTOUCH | 0x130)
#define WACOM_HID_WT_Y (WACOM_HID_UP_WACOMTOUCH | 0x131)
+#define WACOM_HID_WT_REPORT_VALID (WACOM_HID_UP_WACOMTOUCH | 0x1d0)
#define WACOM_BATTERY_USAGE(f) (((f)->hid == HID_DG_BATTERYSTRENGTH) || \
((f)->hid == WACOM_HID_WD_BATTERY_CHARGING) || \
@@ -210,6 +212,7 @@ enum {
INTUOSPM,
INTUOSPL,
INTUOSP2_BT,
+ INTUOSP2S_BT,
INTUOSHT3_BT,
WACOM_21UX2,
WACOM_22HD,
diff --git a/drivers/hv/Kconfig b/drivers/hv/Kconfig
index 1c1a2514d6f3..9a59957922d4 100644
--- a/drivers/hv/Kconfig
+++ b/drivers/hv/Kconfig
@@ -6,10 +6,14 @@ config HYPERV
tristate "Microsoft Hyper-V client drivers"
depends on X86 && ACPI && X86_LOCAL_APIC && HYPERVISOR_GUEST
select PARAVIRT
+ select X86_HV_CALLBACK_VECTOR
help
Select this option to run Linux as a Hyper-V client operating
system.
+config HYPERV_TIMER
+ def_bool HYPERV
+
config HYPERV_TSCPAGE
def_bool HYPERV && X86_64
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c
index a1ea482183e8..6188fb7dda42 100644
--- a/drivers/hv/hv.c
+++ b/drivers/hv/hv.c
@@ -16,6 +16,7 @@
#include <linux/version.h>
#include <linux/random.h>
#include <linux/clockchips.h>
+#include <clocksource/hyperv_timer.h>
#include <asm/mshyperv.h>
#include "hyperv_vmbus.h"
@@ -23,21 +24,6 @@
struct hv_context hv_context;
/*
- * If false, we're using the old mechanism for stimer0 interrupts
- * where it sends a VMbus message when it expires. The old
- * mechanism is used when running on older versions of Hyper-V
- * that don't support Direct Mode. While Hyper-V provides
- * four stimer's per CPU, Linux uses only stimer0.
- */
-static bool direct_mode_enabled;
-static int stimer0_irq;
-static int stimer0_vector;
-
-#define HV_TIMER_FREQUENCY (10 * 1000 * 1000) /* 100ns period */
-#define HV_MAX_MAX_DELTA_TICKS 0xffffffff
-#define HV_MIN_DELTA_TICKS 1
-
-/*
* hv_init - Main initialization routine.
*
* This routine must be called before any other routines in here are called
@@ -47,9 +33,6 @@ int hv_init(void)
hv_context.cpu_context = alloc_percpu(struct hv_per_cpu_context);
if (!hv_context.cpu_context)
return -ENOMEM;
-
- direct_mode_enabled = ms_hyperv.misc_features &
- HV_STIMER_DIRECT_MODE_AVAILABLE;
return 0;
}
@@ -88,89 +71,6 @@ int hv_post_message(union hv_connection_id connection_id,
return status & 0xFFFF;
}
-/*
- * ISR for when stimer0 is operating in Direct Mode. Direct Mode
- * does not use VMbus or any VMbus messages, so process here and not
- * in the VMbus driver code.
- */
-
-static void hv_stimer0_isr(void)
-{
- struct hv_per_cpu_context *hv_cpu;
-
- hv_cpu = this_cpu_ptr(hv_context.cpu_context);
- hv_cpu->clk_evt->event_handler(hv_cpu->clk_evt);
- add_interrupt_randomness(stimer0_vector, 0);
-}
-
-static int hv_ce_set_next_event(unsigned long delta,
- struct clock_event_device *evt)
-{
- u64 current_tick;
-
- WARN_ON(!clockevent_state_oneshot(evt));
-
- current_tick = hyperv_cs->read(NULL);
- current_tick += delta;
- hv_init_timer(0, current_tick);
- return 0;
-}
-
-static int hv_ce_shutdown(struct clock_event_device *evt)
-{
- hv_init_timer(0, 0);
- hv_init_timer_config(0, 0);
- if (direct_mode_enabled)
- hv_disable_stimer0_percpu_irq(stimer0_irq);
-
- return 0;
-}
-
-static int hv_ce_set_oneshot(struct clock_event_device *evt)
-{
- union hv_stimer_config timer_cfg;
-
- timer_cfg.as_uint64 = 0;
- timer_cfg.enable = 1;
- timer_cfg.auto_enable = 1;
- if (direct_mode_enabled) {
- /*
- * When it expires, the timer will directly interrupt
- * on the specified hardware vector/IRQ.
- */
- timer_cfg.direct_mode = 1;
- timer_cfg.apic_vector = stimer0_vector;
- hv_enable_stimer0_percpu_irq(stimer0_irq);
- } else {
- /*
- * When it expires, the timer will generate a VMbus message,
- * to be handled by the normal VMbus interrupt handler.
- */
- timer_cfg.direct_mode = 0;
- timer_cfg.sintx = VMBUS_MESSAGE_SINT;
- }
- hv_init_timer_config(0, timer_cfg.as_uint64);
- return 0;
-}
-
-static void hv_init_clockevent_device(struct clock_event_device *dev, int cpu)
-{
- dev->name = "Hyper-V clockevent";
- dev->features = CLOCK_EVT_FEAT_ONESHOT;
- dev->cpumask = cpumask_of(cpu);
- dev->rating = 1000;
- /*
- * Avoid settint dev->owner = THIS_MODULE deliberately as doing so will
- * result in clockevents_config_and_register() taking additional
- * references to the hv_vmbus module making it impossible to unload.
- */
-
- dev->set_state_shutdown = hv_ce_shutdown;
- dev->set_state_oneshot = hv_ce_set_oneshot;
- dev->set_next_event = hv_ce_set_next_event;
-}
-
-
int hv_synic_alloc(void)
{
int cpu;
@@ -199,14 +99,6 @@ int hv_synic_alloc(void)
tasklet_init(&hv_cpu->msg_dpc,
vmbus_on_msg_dpc, (unsigned long) hv_cpu);
- hv_cpu->clk_evt = kzalloc(sizeof(struct clock_event_device),
- GFP_KERNEL);
- if (hv_cpu->clk_evt == NULL) {
- pr_err("Unable to allocate clock event device\n");
- goto err;
- }
- hv_init_clockevent_device(hv_cpu->clk_evt, cpu);
-
hv_cpu->synic_message_page =
(void *)get_zeroed_page(GFP_ATOMIC);
if (hv_cpu->synic_message_page == NULL) {
@@ -229,11 +121,6 @@ int hv_synic_alloc(void)
INIT_LIST_HEAD(&hv_cpu->chan_list);
}
- if (direct_mode_enabled &&
- hv_setup_stimer0_irq(&stimer0_irq, &stimer0_vector,
- hv_stimer0_isr))
- goto err;
-
return 0;
err:
/*
@@ -252,7 +139,6 @@ void hv_synic_free(void)
struct hv_per_cpu_context *hv_cpu
= per_cpu_ptr(hv_context.cpu_context, cpu);
- kfree(hv_cpu->clk_evt);
free_page((unsigned long)hv_cpu->synic_event_page);
free_page((unsigned long)hv_cpu->synic_message_page);
free_page((unsigned long)hv_cpu->post_msg_page);
@@ -311,36 +197,9 @@ int hv_synic_init(unsigned int cpu)
hv_set_synic_state(sctrl.as_uint64);
- /*
- * Register the per-cpu clockevent source.
- */
- if (ms_hyperv.features & HV_MSR_SYNTIMER_AVAILABLE)
- clockevents_config_and_register(hv_cpu->clk_evt,
- HV_TIMER_FREQUENCY,
- HV_MIN_DELTA_TICKS,
- HV_MAX_MAX_DELTA_TICKS);
- return 0;
-}
-
-/*
- * hv_synic_clockevents_cleanup - Cleanup clockevent devices
- */
-void hv_synic_clockevents_cleanup(void)
-{
- int cpu;
+ hv_stimer_init(cpu);
- if (!(ms_hyperv.features & HV_MSR_SYNTIMER_AVAILABLE))
- return;
-
- if (direct_mode_enabled)
- hv_remove_stimer0_irq(stimer0_irq);
-
- for_each_present_cpu(cpu) {
- struct hv_per_cpu_context *hv_cpu
- = per_cpu_ptr(hv_context.cpu_context, cpu);
-
- clockevents_unbind_device(hv_cpu->clk_evt, cpu);
- }
+ return 0;
}
/*
@@ -388,14 +247,7 @@ int hv_synic_cleanup(unsigned int cpu)
if (channel_found && vmbus_connection.conn_state == CONNECTED)
return -EBUSY;
- /* Turn off clockevent device */
- if (ms_hyperv.features & HV_MSR_SYNTIMER_AVAILABLE) {
- struct hv_per_cpu_context *hv_cpu
- = this_cpu_ptr(hv_context.cpu_context);
-
- clockevents_unbind_device(hv_cpu->clk_evt, cpu);
- hv_ce_shutdown(hv_cpu->clk_evt);
- }
+ hv_stimer_cleanup(cpu);
hv_get_synint_state(VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c
index 7d3d31f099ea..e32681ee7b9f 100644
--- a/drivers/hv/hv_util.c
+++ b/drivers/hv/hv_util.c
@@ -17,6 +17,7 @@
#include <linux/hyperv.h>
#include <linux/clockchips.h>
#include <linux/ptp_clock_kernel.h>
+#include <clocksource/hyperv_timer.h>
#include <asm/mshyperv.h>
#include "hyperv_vmbus.h"
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index b8e1ff05f110..362e70e9d145 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -138,7 +138,6 @@ struct hv_per_cpu_context {
* per-cpu list of the channels based on their CPU affinity.
*/
struct list_head chan_list;
- struct clock_event_device *clk_evt;
};
struct hv_context {
@@ -176,8 +175,6 @@ extern int hv_synic_init(unsigned int cpu);
extern int hv_synic_cleanup(unsigned int cpu);
-extern void hv_synic_clockevents_cleanup(void);
-
/* Interface */
void hv_ringbuffer_pre_init(struct vmbus_channel *channel);
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 92b1874b3eb3..ebd35fc35290 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -30,6 +30,7 @@
#include <linux/kdebug.h>
#include <linux/efi.h>
#include <linux/random.h>
+#include <clocksource/hyperv_timer.h>
#include "hyperv_vmbus.h"
struct vmbus_dynid {
@@ -955,17 +956,6 @@ static void vmbus_onmessage_work(struct work_struct *work)
kfree(ctx);
}
-static void hv_process_timer_expiration(struct hv_message *msg,
- struct hv_per_cpu_context *hv_cpu)
-{
- struct clock_event_device *dev = hv_cpu->clk_evt;
-
- if (dev->event_handler)
- dev->event_handler(dev);
-
- vmbus_signal_eom(msg, HVMSG_TIMER_EXPIRED);
-}
-
void vmbus_on_msg_dpc(unsigned long data)
{
struct hv_per_cpu_context *hv_cpu = (void *)data;
@@ -1159,9 +1149,10 @@ static void vmbus_isr(void)
/* Check if there are actual msgs to be processed */
if (msg->header.message_type != HVMSG_NONE) {
- if (msg->header.message_type == HVMSG_TIMER_EXPIRED)
- hv_process_timer_expiration(msg, hv_cpu);
- else
+ if (msg->header.message_type == HVMSG_TIMER_EXPIRED) {
+ hv_stimer0_isr();
+ vmbus_signal_eom(msg, HVMSG_TIMER_EXPIRED);
+ } else
tasklet_schedule(&hv_cpu->msg_dpc);
}
@@ -1206,8 +1197,6 @@ static struct kmsg_dumper hv_kmsg_dumper = {
};
static struct ctl_table_header *hv_ctl_table_hdr;
-static int zero;
-static int one = 1;
/*
* sysctl option to allow the user to control whether kmsg data should be
@@ -1220,8 +1209,8 @@ static struct ctl_table hv_ctl_table[] = {
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
- .extra1 = &zero,
- .extra2 = &one
+ .extra1 = SYSCTL_ZERO,
+ .extra2 = SYSCTL_ONE
},
{}
};
@@ -1263,14 +1252,19 @@ static int vmbus_bus_init(void)
ret = hv_synic_alloc();
if (ret)
goto err_alloc;
+
+ ret = hv_stimer_alloc(VMBUS_MESSAGE_SINT);
+ if (ret < 0)
+ goto err_alloc;
+
/*
- * Initialize the per-cpu interrupt state and
- * connect to the host.
+ * Initialize the per-cpu interrupt state and stimer state.
+ * Then connect to the host.
*/
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hyperv/vmbus:online",
hv_synic_init, hv_synic_cleanup);
if (ret < 0)
- goto err_alloc;
+ goto err_cpuhp;
hyperv_cpuhp_online = ret;
ret = vmbus_connect();
@@ -1318,6 +1312,8 @@ static int vmbus_bus_init(void)
err_connect:
cpuhp_remove_state(hyperv_cpuhp_online);
+err_cpuhp:
+ hv_stimer_free();
err_alloc:
hv_synic_free();
hv_remove_vmbus_irq();
@@ -2064,7 +2060,7 @@ static struct acpi_driver vmbus_acpi_driver = {
static void hv_kexec_handler(void)
{
- hv_synic_clockevents_cleanup();
+ hv_stimer_global_cleanup();
vmbus_initiate_unload(false);
vmbus_connection.conn_state = DISCONNECTED;
/* Make sure conn_state is set as hv_synic_cleanup checks for it */
@@ -2075,6 +2071,8 @@ static void hv_kexec_handler(void)
static void hv_crash_handler(struct pt_regs *regs)
{
+ int cpu;
+
vmbus_initiate_unload(true);
/*
* In crash handler we can't schedule synic cleanup for all CPUs,
@@ -2082,7 +2080,9 @@ static void hv_crash_handler(struct pt_regs *regs)
* for kdump.
*/
vmbus_connection.conn_state = DISCONNECTED;
- hv_synic_cleanup(smp_processor_id());
+ cpu = smp_processor_id();
+ hv_stimer_cleanup(cpu);
+ hv_synic_cleanup(cpu);
hyperv_cleanup();
};
@@ -2131,7 +2131,7 @@ static void __exit vmbus_exit(void)
hv_remove_kexec_handler();
hv_remove_crash_handler();
vmbus_connection.conn_state = DISCONNECTED;
- hv_synic_clockevents_cleanup();
+ hv_stimer_global_cleanup();
vmbus_disconnect();
hv_remove_vmbus_irq();
for_each_online_cpu(cpu) {
@@ -2161,6 +2161,7 @@ static void __exit vmbus_exit(void)
MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Microsoft Hyper-V VMBus Driver");
subsys_initcall(hv_acpi_init);
module_exit(vmbus_exit);
diff --git a/drivers/hwmon/adm1029.c b/drivers/hwmon/adm1029.c
index 388060ff85e7..f7752a5bef31 100644
--- a/drivers/hwmon/adm1029.c
+++ b/drivers/hwmon/adm1029.c
@@ -10,16 +10,6 @@
* Very rare chip please let me know if you use it
*
* http://www.analog.com/UploadedFiles/Data_Sheets/ADM1029.pdf
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/module.h>
diff --git a/drivers/hwmon/adt7411.c b/drivers/hwmon/adt7411.c
index 44a827b031cb..c7010b91bc13 100644
--- a/drivers/hwmon/adt7411.c
+++ b/drivers/hwmon/adt7411.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for the ADT7411 (I2C/SPI 8 channel 10 bit ADC & temperature-sensor)
*
* Copyright (C) 2008, 2010 Pengutronix
*
- * 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.
- *
* TODO: SPI, use power-down mode for suspend?, interrupt handling?
*/
diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c
index 7caec127df86..c3c6031a7285 100644
--- a/drivers/hwmon/adt7475.c
+++ b/drivers/hwmon/adt7475.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* adt7475 - Thermal sensor driver for the ADT7475 chip and derivatives
* Copyright (C) 2007-2008, Advanced Micro Devices, Inc.
@@ -6,10 +7,6 @@
* Copyright (C) 2009 Jean Delvare <jdelvare@suse.de>
*
* Derived from the lm83 driver by Jean Delvare
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c
index 8dd5b1b8db60..ff64a39d56de 100644
--- a/drivers/hwmon/asus_atk0110.c
+++ b/drivers/hwmon/asus_atk0110.c
@@ -789,33 +789,16 @@ static const struct file_operations atk_debugfs_ggrp_fops = {
static void atk_debugfs_init(struct atk_data *data)
{
struct dentry *d;
- struct dentry *f;
data->debugfs.id = 0;
d = debugfs_create_dir("asus_atk0110", NULL);
- if (!d || IS_ERR(d))
- return;
- f = debugfs_create_x32("id", 0600, d, &data->debugfs.id);
- if (!f || IS_ERR(f))
- goto cleanup;
-
- f = debugfs_create_file_unsafe("gitm", 0400, d, data,
- &atk_debugfs_gitm);
- if (!f || IS_ERR(f))
- goto cleanup;
-
- f = debugfs_create_file("ggrp", 0400, d, data,
- &atk_debugfs_ggrp_fops);
- if (!f || IS_ERR(f))
- goto cleanup;
+ debugfs_create_x32("id", 0600, d, &data->debugfs.id);
+ debugfs_create_file_unsafe("gitm", 0400, d, data, &atk_debugfs_gitm);
+ debugfs_create_file("ggrp", 0400, d, data, &atk_debugfs_ggrp_fops);
data->debugfs.root = d;
-
- return;
-cleanup:
- debugfs_remove_recursive(d);
}
static void atk_debugfs_cleanup(struct atk_data *data)
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index 4d0d6c86c12f..fe6618e49dc4 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -96,10 +96,10 @@ struct platform_data {
struct device_attribute name_attr;
};
-/* Keep track of how many package pointers we allocated in init() */
-static int max_packages __read_mostly;
-/* Array of package pointers. Serialized by cpu hotplug lock */
-static struct platform_device **pkg_devices;
+/* Keep track of how many zone pointers we allocated in init() */
+static int max_zones __read_mostly;
+/* Array of zone pointers. Serialized by cpu hotplug lock */
+static struct platform_device **zone_devices;
static ssize_t show_label(struct device *dev,
struct device_attribute *devattr, char *buf)
@@ -422,10 +422,10 @@ static int chk_ucode_version(unsigned int cpu)
static struct platform_device *coretemp_get_pdev(unsigned int cpu)
{
- int pkgid = topology_logical_package_id(cpu);
+ int id = topology_logical_die_id(cpu);
- if (pkgid >= 0 && pkgid < max_packages)
- return pkg_devices[pkgid];
+ if (id >= 0 && id < max_zones)
+ return zone_devices[id];
return NULL;
}
@@ -531,7 +531,7 @@ static int coretemp_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct platform_data *pdata;
- /* Initialize the per-package data structures */
+ /* Initialize the per-zone data structures */
pdata = devm_kzalloc(dev, sizeof(struct platform_data), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
@@ -566,13 +566,13 @@ static struct platform_driver coretemp_driver = {
static struct platform_device *coretemp_device_add(unsigned int cpu)
{
- int err, pkgid = topology_logical_package_id(cpu);
+ int err, zoneid = topology_logical_die_id(cpu);
struct platform_device *pdev;
- if (pkgid < 0)
+ if (zoneid < 0)
return ERR_PTR(-ENOMEM);
- pdev = platform_device_alloc(DRVNAME, pkgid);
+ pdev = platform_device_alloc(DRVNAME, zoneid);
if (!pdev)
return ERR_PTR(-ENOMEM);
@@ -582,7 +582,7 @@ static struct platform_device *coretemp_device_add(unsigned int cpu)
return ERR_PTR(err);
}
- pkg_devices[pkgid] = pdev;
+ zone_devices[zoneid] = pdev;
return pdev;
}
@@ -690,7 +690,7 @@ static int coretemp_cpu_offline(unsigned int cpu)
* the rest.
*/
if (cpumask_empty(&pd->cpumask)) {
- pkg_devices[topology_logical_package_id(cpu)] = NULL;
+ zone_devices[topology_logical_die_id(cpu)] = NULL;
platform_device_unregister(pdev);
return 0;
}
@@ -728,10 +728,10 @@ static int __init coretemp_init(void)
if (!x86_match_cpu(coretemp_ids))
return -ENODEV;
- max_packages = topology_max_packages();
- pkg_devices = kcalloc(max_packages, sizeof(struct platform_device *),
+ max_zones = topology_max_packages() * topology_max_die_per_package();
+ zone_devices = kcalloc(max_zones, sizeof(struct platform_device *),
GFP_KERNEL);
- if (!pkg_devices)
+ if (!zone_devices)
return -ENOMEM;
err = platform_driver_register(&coretemp_driver);
@@ -747,7 +747,7 @@ static int __init coretemp_init(void)
outdrv:
platform_driver_unregister(&coretemp_driver);
- kfree(pkg_devices);
+ kfree(zone_devices);
return err;
}
module_init(coretemp_init)
@@ -756,7 +756,7 @@ static void __exit coretemp_exit(void)
{
cpuhp_remove_state(coretemp_hp_online);
platform_driver_unregister(&coretemp_driver);
- kfree(pkg_devices);
+ kfree(zone_devices);
}
module_exit(coretemp_exit)
diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c
index 84753680a4e8..3ea4021f267c 100644
--- a/drivers/hwmon/gpio-fan.c
+++ b/drivers/hwmon/gpio-fan.c
@@ -54,8 +54,8 @@ static void fan_alarm_notify(struct work_struct *ws)
struct gpio_fan_data *fan_data =
container_of(ws, struct gpio_fan_data, alarm_work);
- sysfs_notify(&fan_data->dev->kobj, NULL, "fan1_alarm");
- kobject_uevent(&fan_data->dev->kobj, KOBJ_CHANGE);
+ sysfs_notify(&fan_data->hwmon_dev->kobj, NULL, "fan1_alarm");
+ kobject_uevent(&fan_data->hwmon_dev->kobj, KOBJ_CHANGE);
}
static irqreturn_t fan_alarm_irq_handler(int irq, void *dev_id)
@@ -510,13 +510,6 @@ static int gpio_fan_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, fan_data);
mutex_init(&fan_data->lock);
- /* Configure alarm GPIO if available. */
- if (fan_data->alarm_gpio) {
- err = fan_alarm_init(fan_data);
- if (err)
- return err;
- }
-
/* Configure control GPIOs if available. */
if (fan_data->gpios && fan_data->num_gpios > 0) {
if (!fan_data->speed || fan_data->num_speed <= 1)
@@ -524,7 +517,9 @@ static int gpio_fan_probe(struct platform_device *pdev)
err = fan_ctrl_init(fan_data);
if (err)
return err;
- devm_add_action_or_reset(dev, gpio_fan_stop, fan_data);
+ err = devm_add_action_or_reset(dev, gpio_fan_stop, fan_data);
+ if (err)
+ return err;
}
/* Make this driver part of hwmon class. */
@@ -535,6 +530,13 @@ static int gpio_fan_probe(struct platform_device *pdev)
if (IS_ERR(fan_data->hwmon_dev))
return PTR_ERR(fan_data->hwmon_dev);
+ /* Configure alarm GPIO if available. */
+ if (fan_data->alarm_gpio) {
+ err = fan_alarm_init(fan_data);
+ if (err)
+ return err;
+ }
+
/* Optional cooling device register for Device tree platforms */
fan_data->cdev = devm_thermal_of_cooling_device_register(dev, np,
"gpio-fan", fan_data, &gpio_fan_cool_ops);
diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c
index 05e120e01cb4..1f3b30b085b9 100644
--- a/drivers/hwmon/hwmon.c
+++ b/drivers/hwmon/hwmon.c
@@ -651,6 +651,12 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata,
hwdev, j);
if (err) {
device_unregister(hdev);
+ /*
+ * Don't worry about hwdev;
+ * hwmon_dev_release(), called
+ * from device_unregister(),
+ * will free it.
+ */
goto ida_remove;
}
}
diff --git a/drivers/hwmon/iio_hwmon.c b/drivers/hwmon/iio_hwmon.c
index 1770423f7a80..f1c2d5faedf0 100644
--- a/drivers/hwmon/iio_hwmon.c
+++ b/drivers/hwmon/iio_hwmon.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* Hwmon client for industrial I/O devices
*
* Copyright (c) 2011 Jonathan Cameron
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c
index 55943b4dcc7b..0037e2bdacd6 100644
--- a/drivers/hwmon/ina3221.c
+++ b/drivers/hwmon/ina3221.c
@@ -713,8 +713,10 @@ static int ina3221_probe_from_dt(struct device *dev, struct ina3221_data *ina)
for_each_child_of_node(np, child) {
ret = ina3221_probe_child_from_dt(dev, child, ina);
- if (ret)
+ if (ret) {
+ of_node_put(child);
return ret;
+ }
}
return 0;
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index e562a578f20e..9b3c9f390ef8 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -174,6 +174,7 @@ enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680,
#define LM90_HAVE_EMERGENCY_ALARM (1 << 5)/* emergency alarm */
#define LM90_HAVE_TEMP3 (1 << 6) /* 3rd temperature sensor */
#define LM90_HAVE_BROKEN_ALERT (1 << 7) /* Broken alert */
+#define LM90_PAUSE_FOR_CONFIG (1 << 8) /* Pause conversion for config */
/* LM90 status */
#define LM90_STATUS_LTHRM (1 << 0) /* local THERM limit tripped */
@@ -367,6 +368,7 @@ static const struct lm90_params lm90_params[] = {
.reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
},
[max6657] = {
+ .flags = LM90_PAUSE_FOR_CONFIG,
.alert_alarms = 0x7c,
.max_convrate = 8,
.reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
@@ -457,6 +459,7 @@ struct lm90_data {
unsigned int update_interval; /* in milliseconds */
+ u8 config; /* Current configuration register value */
u8 config_orig; /* Original configuration register value */
u8 convrate_orig; /* Original conversion rate register value */
u16 alert_alarms; /* Which alarm bits trigger ALERT# */
@@ -540,6 +543,21 @@ static int lm90_read16(struct i2c_client *client, u8 regh, u8 regl)
return (newh << 8) | l;
}
+static int lm90_update_confreg(struct lm90_data *data, u8 config)
+{
+ if (data->config != config) {
+ int err;
+
+ err = i2c_smbus_write_byte_data(data->client,
+ LM90_REG_W_CONFIG1,
+ config);
+ if (err)
+ return err;
+ data->config = config;
+ }
+ return 0;
+}
+
/*
* client->update_lock must be held when calling this function (unless we are
* in detection or initialization steps), and while a remote channel other
@@ -548,23 +566,39 @@ static int lm90_read16(struct i2c_client *client, u8 regh, u8 regl)
* various registers have different meanings as a result of selecting a
* non-default remote channel.
*/
-static inline int lm90_select_remote_channel(struct i2c_client *client,
- struct lm90_data *data,
- int channel)
+static int lm90_select_remote_channel(struct lm90_data *data, int channel)
{
- int config;
+ int err = 0;
if (data->kind == max6696) {
- config = lm90_read_reg(client, LM90_REG_R_CONFIG1);
- if (config < 0)
- return config;
- config &= ~0x08;
+ u8 config = data->config & ~0x08;
+
if (channel)
config |= 0x08;
- i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
- config);
+ err = lm90_update_confreg(data, config);
}
- return 0;
+ return err;
+}
+
+static int lm90_write_convrate(struct lm90_data *data, int val)
+{
+ u8 config = data->config;
+ int err;
+
+ /* Save config and pause conversion */
+ if (data->flags & LM90_PAUSE_FOR_CONFIG) {
+ err = lm90_update_confreg(data, config | 0x40);
+ if (err < 0)
+ return err;
+ }
+
+ /* Set conv rate */
+ err = i2c_smbus_write_byte_data(data->client, LM90_REG_W_CONVRATE, val);
+
+ /* Revert change to config */
+ lm90_update_confreg(data, config);
+
+ return err;
}
/*
@@ -587,7 +621,7 @@ static int lm90_set_convrate(struct i2c_client *client, struct lm90_data *data,
if (interval >= update_interval * 3 / 4)
break;
- err = i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE, i);
+ err = lm90_write_convrate(data, i);
data->update_interval = DIV_ROUND_CLOSEST(update_interval, 64);
return err;
}
@@ -658,7 +692,7 @@ static int lm90_update_limits(struct device *dev)
}
if (data->kind == max6696) {
- val = lm90_select_remote_channel(client, data, 1);
+ val = lm90_select_remote_channel(data, 1);
if (val < 0)
return val;
@@ -682,7 +716,7 @@ static int lm90_update_limits(struct device *dev)
return val;
data->temp11[REMOTE2_HIGH] = val << 8;
- lm90_select_remote_channel(client, data, 0);
+ lm90_select_remote_channel(data, 0);
}
return 0;
@@ -742,19 +776,19 @@ static int lm90_update_device(struct device *dev)
data->alarms = val; /* lower 8 bit of alarms */
if (data->kind == max6696) {
- val = lm90_select_remote_channel(client, data, 1);
+ val = lm90_select_remote_channel(data, 1);
if (val < 0)
return val;
val = lm90_read16(client, LM90_REG_R_REMOTE_TEMPH,
LM90_REG_R_REMOTE_TEMPL);
if (val < 0) {
- lm90_select_remote_channel(client, data, 0);
+ lm90_select_remote_channel(data, 0);
return val;
}
data->temp11[REMOTE2_TEMP] = val;
- lm90_select_remote_channel(client, data, 0);
+ lm90_select_remote_channel(data, 0);
val = lm90_read_reg(client, MAX6696_REG_R_STATUS2);
if (val < 0)
@@ -768,15 +802,9 @@ static int lm90_update_device(struct device *dev)
*/
if (!(data->config_orig & 0x80) &&
!(data->alarms & data->alert_alarms)) {
- val = lm90_read_reg(client, LM90_REG_R_CONFIG1);
- if (val < 0)
- return val;
-
- if (val & 0x80) {
+ if (data->config & 0x80) {
dev_dbg(&client->dev, "Re-enabling ALERT#\n");
- i2c_smbus_write_byte_data(client,
- LM90_REG_W_CONFIG1,
- val & ~0x80);
+ lm90_update_confreg(data, data->config & ~0x80);
}
}
@@ -994,7 +1022,7 @@ static int lm90_set_temp11(struct lm90_data *data, int index, long val)
else
data->temp11[index] = temp_to_s8(val) << 8;
- lm90_select_remote_channel(client, data, index >= 3);
+ lm90_select_remote_channel(data, index >= 3);
err = i2c_smbus_write_byte_data(client, regp->high,
data->temp11[index] >> 8);
if (err < 0)
@@ -1003,7 +1031,7 @@ static int lm90_set_temp11(struct lm90_data *data, int index, long val)
err = i2c_smbus_write_byte_data(client, regp->low,
data->temp11[index] & 0xff);
- lm90_select_remote_channel(client, data, 0);
+ lm90_select_remote_channel(data, 0);
return err;
}
@@ -1052,9 +1080,9 @@ static int lm90_set_temp8(struct lm90_data *data, int index, long val)
else
data->temp8[index] = temp_to_s8(val);
- lm90_select_remote_channel(client, data, index >= 6);
+ lm90_select_remote_channel(data, index >= 6);
err = i2c_smbus_write_byte_data(client, reg[index], data->temp8[index]);
- lm90_select_remote_channel(client, data, 0);
+ lm90_select_remote_channel(data, 0);
return err;
}
@@ -1593,8 +1621,7 @@ static void lm90_restore_conf(void *_data)
struct i2c_client *client = data->client;
/* Restore initial configuration */
- i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE,
- data->convrate_orig);
+ lm90_write_convrate(data, data->convrate_orig);
i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
data->config_orig);
}
@@ -1611,11 +1638,13 @@ static int lm90_init_client(struct i2c_client *client, struct lm90_data *data)
/*
* Start the conversions.
*/
- lm90_set_convrate(client, data, 500); /* 500ms; 2Hz conversion rate */
config = lm90_read_reg(client, LM90_REG_R_CONFIG1);
if (config < 0)
return config;
data->config_orig = config;
+ data->config = config;
+
+ lm90_set_convrate(client, data, 500); /* 500ms; 2Hz conversion rate */
/* Check Temperature Range Select */
if (data->kind == adt7461 || data->kind == tmp451) {
@@ -1638,8 +1667,7 @@ static int lm90_init_client(struct i2c_client *client, struct lm90_data *data)
config &= ~0x08;
config &= 0xBF; /* run */
- if (config != data->config_orig) /* Only write if changed */
- i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config);
+ lm90_update_confreg(data, config);
return devm_add_action_or_reset(&client->dev, lm90_restore_conf, data);
}
@@ -1718,7 +1746,7 @@ static int lm90_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
- struct i2c_adapter *adapter = to_i2c_adapter(dev->parent);
+ struct i2c_adapter *adapter = client->adapter;
struct hwmon_channel_info *info;
struct regulator *regulator;
struct device *hwmon_dev;
@@ -1873,14 +1901,8 @@ static void lm90_alert(struct i2c_client *client, enum i2c_alert_protocol type,
if ((data->flags & LM90_HAVE_BROKEN_ALERT) &&
(alarms & data->alert_alarms)) {
- int config;
-
dev_dbg(&client->dev, "Disabling ALERT#\n");
- config = lm90_read_reg(client, LM90_REG_R_CONFIG1);
- if (config >= 0)
- i2c_smbus_write_byte_data(client,
- LM90_REG_W_CONFIG1,
- config | 0x80);
+ lm90_update_confreg(data, data->config | 0x80);
}
} else {
dev_info(&client->dev, "Everything OK\n");
diff --git a/drivers/hwmon/max197.c b/drivers/hwmon/max197.c
index dd6a35219a18..56add579e32f 100644
--- a/drivers/hwmon/max197.c
+++ b/drivers/hwmon/max197.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Maxim MAX197 A/D Converter driver
*
* Copyright (c) 2012 Savoir-faire Linux Inc.
* Vivien Didelot <vivien.didelot@savoirfairelinux.com>
*
- * 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.
- *
* For further information, see the Documentation/hwmon/max197.rst file.
*/
diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c
index 6b9056f9483f..3d9d371c35b5 100644
--- a/drivers/hwmon/max6650.c
+++ b/drivers/hwmon/max6650.c
@@ -92,7 +92,8 @@ module_param(clock, int, 0444);
#define FAN_RPM_MIN 240
#define FAN_RPM_MAX 30000
-#define DIV_FROM_REG(reg) (1 << (reg & 7))
+#define DIV_FROM_REG(reg) (1 << ((reg) & 7))
+#define DAC_LIMIT(v12) ((v12) ? 180 : 76)
/*
* Client data (each client gets its own)
@@ -100,11 +101,9 @@ module_param(clock, int, 0444);
struct max6650_data {
struct i2c_client *client;
- const struct attribute_group *groups[3];
- struct thermal_cooling_device *cooling_dev;
- struct mutex update_lock;
+ struct mutex update_lock; /* protect alarm register updates */
int nr_fans;
- char valid; /* zero until following fields are valid */
+ bool valid; /* false until following fields are valid */
unsigned long last_updated; /* in jiffies */
/* register values */
@@ -114,6 +113,7 @@ struct max6650_data {
u8 count;
u8 dac;
u8 alarm;
+ u8 alarm_en;
unsigned long cooling_dev_state;
};
@@ -137,41 +137,60 @@ static const struct of_device_id __maybe_unused max6650_dt_match[] = {
};
MODULE_DEVICE_TABLE(of, max6650_dt_match);
+static int dac_to_pwm(int dac, bool v12)
+{
+ /*
+ * Useful range for dac is 0-180 for 12V fans and 0-76 for 5V fans.
+ * Lower DAC values mean higher speeds.
+ */
+ return clamp_val(255 - (255 * dac) / DAC_LIMIT(v12), 0, 255);
+}
+
+static u8 pwm_to_dac(unsigned int pwm, bool v12)
+{
+ int limit = DAC_LIMIT(v12);
+
+ return limit - (limit * pwm) / 255;
+}
+
static struct max6650_data *max6650_update_device(struct device *dev)
{
struct max6650_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
+ int reg, err = 0;
int i;
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
- data->speed = i2c_smbus_read_byte_data(client,
- MAX6650_REG_SPEED);
- data->config = i2c_smbus_read_byte_data(client,
- MAX6650_REG_CONFIG);
for (i = 0; i < data->nr_fans; i++) {
- data->tach[i] = i2c_smbus_read_byte_data(client,
- tach_reg[i]);
+ reg = i2c_smbus_read_byte_data(client, tach_reg[i]);
+ if (reg < 0) {
+ err = reg;
+ goto error;
+ }
+ data->tach[i] = reg;
}
- data->count = i2c_smbus_read_byte_data(client,
- MAX6650_REG_COUNT);
- data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC);
/*
* Alarms are cleared on read in case the condition that
* caused the alarm is removed. Keep the value latched here
* for providing the register through different alarm files.
*/
- data->alarm |= i2c_smbus_read_byte_data(client,
- MAX6650_REG_ALARM);
-
+ reg = i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM);
+ if (reg < 0) {
+ err = reg;
+ goto error;
+ }
+ data->alarm |= reg;
data->last_updated = jiffies;
- data->valid = 1;
+ data->valid = true;
}
+error:
mutex_unlock(&data->update_lock);
-
+ if (err)
+ data = ERR_PTR(err);
return data;
}
@@ -199,26 +218,6 @@ static int max6650_set_operating_mode(struct max6650_data *data, u8 mode)
return 0;
}
-static ssize_t fan_show(struct device *dev, struct device_attribute *devattr,
- char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct max6650_data *data = max6650_update_device(dev);
- int rpm;
-
- /*
- * Calculation details:
- *
- * Each tachometer counts over an interval given by the "count"
- * register (0.25, 0.5, 1 or 2 seconds). This module assumes
- * that the fans produce two pulses per revolution (this seems
- * to be the most common).
- */
-
- rpm = ((data->tach[attr->index] * 120) / DIV_FROM_REG(data->count));
- return sprintf(buf, "%d\n", rpm);
-}
-
/*
* Set the fan speed to the specified RPM (or read back the RPM setting).
* This works in closed loop mode only. Use pwm1 for open loop speed setting.
@@ -260,26 +259,6 @@ static ssize_t fan_show(struct device *dev, struct device_attribute *devattr,
* controlled.
*/
-static ssize_t fan1_target_show(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- struct max6650_data *data = max6650_update_device(dev);
- int kscale, ktach, rpm;
-
- /*
- * Use the datasheet equation:
- *
- * FanSpeed = KSCALE x fCLK / [256 x (KTACH + 1)]
- *
- * then multiply by 60 to give rpm.
- */
-
- kscale = DIV_FROM_REG(data->config);
- ktach = data->speed;
- rpm = 60 * kscale * clock / (256 * (ktach + 1));
- return sprintf(buf, "%d\n", rpm);
-}
-
static int max6650_set_target(struct max6650_data *data, unsigned long rpm)
{
int kscale, ktach;
@@ -308,197 +287,8 @@ static int max6650_set_target(struct max6650_data *data, unsigned long rpm)
data->speed);
}
-static ssize_t fan1_target_store(struct device *dev,
- struct device_attribute *devattr,
- const char *buf, size_t count)
-{
- struct max6650_data *data = dev_get_drvdata(dev);
- unsigned long rpm;
- int err;
-
- err = kstrtoul(buf, 10, &rpm);
- if (err)
- return err;
-
- mutex_lock(&data->update_lock);
-
- err = max6650_set_target(data, rpm);
-
- mutex_unlock(&data->update_lock);
-
- if (err < 0)
- return err;
-
- return count;
-}
-
-/*
- * Get/set the fan speed in open loop mode using pwm1 sysfs file.
- * Speed is given as a relative value from 0 to 255, where 255 is maximum
- * speed. Note that this is done by writing directly to the chip's DAC,
- * it won't change the closed loop speed set by fan1_target.
- * Also note that due to rounding errors it is possible that you don't read
- * back exactly the value you have set.
- */
-
-static ssize_t pwm1_show(struct device *dev, struct device_attribute *devattr,
- char *buf)
-{
- int pwm;
- struct max6650_data *data = max6650_update_device(dev);
-
- /*
- * Useful range for dac is 0-180 for 12V fans and 0-76 for 5V fans.
- * Lower DAC values mean higher speeds.
- */
- if (data->config & MAX6650_CFG_V12)
- pwm = 255 - (255 * (int)data->dac)/180;
- else
- pwm = 255 - (255 * (int)data->dac)/76;
-
- if (pwm < 0)
- pwm = 0;
-
- return sprintf(buf, "%d\n", pwm);
-}
-
-static ssize_t pwm1_store(struct device *dev,
- struct device_attribute *devattr, const char *buf,
- size_t count)
-{
- struct max6650_data *data = dev_get_drvdata(dev);
- struct i2c_client *client = data->client;
- unsigned long pwm;
- int err;
-
- err = kstrtoul(buf, 10, &pwm);
- if (err)
- return err;
-
- pwm = clamp_val(pwm, 0, 255);
-
- mutex_lock(&data->update_lock);
-
- if (data->config & MAX6650_CFG_V12)
- data->dac = 180 - (180 * pwm)/255;
- else
- data->dac = 76 - (76 * pwm)/255;
- err = i2c_smbus_write_byte_data(client, MAX6650_REG_DAC, data->dac);
-
- mutex_unlock(&data->update_lock);
-
- return err < 0 ? err : count;
-}
-
/*
- * Get/Set controller mode:
- * Possible values:
- * 0 = Fan always on
- * 1 = Open loop, Voltage is set according to speed, not regulated.
- * 2 = Closed loop, RPM for all fans regulated by fan1 tachometer
- * 3 = Fan off
- */
-static ssize_t pwm1_enable_show(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- struct max6650_data *data = max6650_update_device(dev);
- int mode = (data->config & MAX6650_CFG_MODE_MASK) >> 4;
- int sysfs_modes[4] = {0, 3, 2, 1};
-
- return sprintf(buf, "%d\n", sysfs_modes[mode]);
-}
-
-static ssize_t pwm1_enable_store(struct device *dev,
- struct device_attribute *devattr,
- const char *buf, size_t count)
-{
- struct max6650_data *data = dev_get_drvdata(dev);
- unsigned long mode;
- int err;
- const u8 max6650_modes[] = {
- MAX6650_CFG_MODE_ON,
- MAX6650_CFG_MODE_OPEN_LOOP,
- MAX6650_CFG_MODE_CLOSED_LOOP,
- MAX6650_CFG_MODE_OFF,
- };
-
- err = kstrtoul(buf, 10, &mode);
- if (err)
- return err;
-
- if (mode >= ARRAY_SIZE(max6650_modes))
- return -EINVAL;
-
- mutex_lock(&data->update_lock);
-
- max6650_set_operating_mode(data, max6650_modes[mode]);
-
- mutex_unlock(&data->update_lock);
-
- return count;
-}
-
-/*
- * Read/write functions for fan1_div sysfs file. The MAX6650 has no such
- * divider. We handle this by converting between divider and counttime:
- *
- * (counttime == k) <==> (divider == 2^k), k = 0, 1, 2, or 3
- *
- * Lower values of k allow to connect a faster fan without the risk of
- * counter overflow. The price is lower resolution. You can also set counttime
- * using the module parameter. Note that the module parameter "prescaler" also
- * influences the behaviour. Unfortunately, there's no sysfs attribute
- * defined for that. See the data sheet for details.
- */
-
-static ssize_t fan1_div_show(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- struct max6650_data *data = max6650_update_device(dev);
-
- return sprintf(buf, "%d\n", DIV_FROM_REG(data->count));
-}
-
-static ssize_t fan1_div_store(struct device *dev,
- struct device_attribute *devattr,
- const char *buf, size_t count)
-{
- struct max6650_data *data = dev_get_drvdata(dev);
- struct i2c_client *client = data->client;
- unsigned long div;
- int err;
-
- err = kstrtoul(buf, 10, &div);
- if (err)
- return err;
-
- mutex_lock(&data->update_lock);
- switch (div) {
- case 1:
- data->count = 0;
- break;
- case 2:
- data->count = 1;
- break;
- case 4:
- data->count = 2;
- break;
- case 8:
- data->count = 3;
- break;
- default:
- mutex_unlock(&data->update_lock);
- return -EINVAL;
- }
-
- i2c_smbus_write_byte_data(client, MAX6650_REG_COUNT, data->count);
- mutex_unlock(&data->update_lock);
-
- return count;
-}
-
-/*
- * Get alarm stati:
+ * Get gpio alarm status:
* Possible values:
* 0 = no alarm
* 1 = alarm
@@ -509,42 +299,30 @@ static ssize_t alarm_show(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct max6650_data *data = max6650_update_device(dev);
- struct i2c_client *client = data->client;
- int alarm = 0;
+ bool alarm;
- if (data->alarm & attr->index) {
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ alarm = data->alarm & attr->index;
+ if (alarm) {
mutex_lock(&data->update_lock);
- alarm = 1;
data->alarm &= ~attr->index;
- data->alarm |= i2c_smbus_read_byte_data(client,
- MAX6650_REG_ALARM);
+ data->valid = false;
mutex_unlock(&data->update_lock);
}
return sprintf(buf, "%d\n", alarm);
}
-static SENSOR_DEVICE_ATTR_RO(fan1_input, fan, 0);
-static SENSOR_DEVICE_ATTR_RO(fan2_input, fan, 1);
-static SENSOR_DEVICE_ATTR_RO(fan3_input, fan, 2);
-static SENSOR_DEVICE_ATTR_RO(fan4_input, fan, 3);
-static DEVICE_ATTR_RW(fan1_target);
-static DEVICE_ATTR_RW(fan1_div);
-static DEVICE_ATTR_RW(pwm1_enable);
-static DEVICE_ATTR_RW(pwm1);
-static SENSOR_DEVICE_ATTR_RO(fan1_max_alarm, alarm, MAX6650_ALRM_MAX);
-static SENSOR_DEVICE_ATTR_RO(fan1_min_alarm, alarm, MAX6650_ALRM_MIN);
-static SENSOR_DEVICE_ATTR_RO(fan1_fault, alarm, MAX6650_ALRM_TACH);
static SENSOR_DEVICE_ATTR_RO(gpio1_alarm, alarm, MAX6650_ALRM_GPIO1);
static SENSOR_DEVICE_ATTR_RO(gpio2_alarm, alarm, MAX6650_ALRM_GPIO2);
static umode_t max6650_attrs_visible(struct kobject *kobj, struct attribute *a,
- int n)
+ int n)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct max6650_data *data = dev_get_drvdata(dev);
- struct i2c_client *client = data->client;
- u8 alarm_en = i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN);
struct device_attribute *devattr;
/*
@@ -552,12 +330,9 @@ static umode_t max6650_attrs_visible(struct kobject *kobj, struct attribute *a,
*/
devattr = container_of(a, struct device_attribute, attr);
- if (devattr == &sensor_dev_attr_fan1_max_alarm.dev_attr
- || devattr == &sensor_dev_attr_fan1_min_alarm.dev_attr
- || devattr == &sensor_dev_attr_fan1_fault.dev_attr
- || devattr == &sensor_dev_attr_gpio1_alarm.dev_attr
- || devattr == &sensor_dev_attr_gpio2_alarm.dev_attr) {
- if (!(alarm_en & to_sensor_dev_attr(devattr)->index))
+ if (devattr == &sensor_dev_attr_gpio1_alarm.dev_attr ||
+ devattr == &sensor_dev_attr_gpio2_alarm.dev_attr) {
+ if (!(data->alarm_en & to_sensor_dev_attr(devattr)->index))
return 0;
}
@@ -565,14 +340,6 @@ static umode_t max6650_attrs_visible(struct kobject *kobj, struct attribute *a,
}
static struct attribute *max6650_attrs[] = {
- &sensor_dev_attr_fan1_input.dev_attr.attr,
- &dev_attr_fan1_target.attr,
- &dev_attr_fan1_div.attr,
- &dev_attr_pwm1_enable.attr,
- &dev_attr_pwm1.attr,
- &sensor_dev_attr_fan1_max_alarm.dev_attr.attr,
- &sensor_dev_attr_fan1_min_alarm.dev_attr.attr,
- &sensor_dev_attr_fan1_fault.dev_attr.attr,
&sensor_dev_attr_gpio1_alarm.dev_attr.attr,
&sensor_dev_attr_gpio2_alarm.dev_attr.attr,
NULL
@@ -583,27 +350,17 @@ static const struct attribute_group max6650_group = {
.is_visible = max6650_attrs_visible,
};
-static struct attribute *max6651_attrs[] = {
- &sensor_dev_attr_fan2_input.dev_attr.attr,
- &sensor_dev_attr_fan3_input.dev_attr.attr,
- &sensor_dev_attr_fan4_input.dev_attr.attr,
+static const struct attribute_group *max6650_groups[] = {
+ &max6650_group,
NULL
};
-static const struct attribute_group max6651_group = {
- .attrs = max6651_attrs,
-};
-
-/*
- * Real code
- */
-
static int max6650_init_client(struct max6650_data *data,
struct i2c_client *client)
{
struct device *dev = &client->dev;
- int config;
- int err = -EIO;
+ int reg;
+ int err;
u32 voltage;
u32 prescale;
u32 target_rpm;
@@ -617,21 +374,20 @@ static int max6650_init_client(struct max6650_data *data,
&prescale))
prescale = prescaler;
- config = i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG);
-
- if (config < 0) {
- dev_err(dev, "Error reading config, aborting.\n");
- return err;
+ reg = i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG);
+ if (reg < 0) {
+ dev_err(dev, "Error reading config register, aborting.\n");
+ return reg;
}
switch (voltage) {
case 0:
break;
case 5:
- config &= ~MAX6650_CFG_V12;
+ reg &= ~MAX6650_CFG_V12;
break;
case 12:
- config |= MAX6650_CFG_V12;
+ reg |= MAX6650_CFG_V12;
break;
default:
dev_err(dev, "illegal value for fan_voltage (%d)\n", voltage);
@@ -641,22 +397,22 @@ static int max6650_init_client(struct max6650_data *data,
case 0:
break;
case 1:
- config &= ~MAX6650_CFG_PRESCALER_MASK;
+ reg &= ~MAX6650_CFG_PRESCALER_MASK;
break;
case 2:
- config = (config & ~MAX6650_CFG_PRESCALER_MASK)
+ reg = (reg & ~MAX6650_CFG_PRESCALER_MASK)
| MAX6650_CFG_PRESCALER_2;
break;
case 4:
- config = (config & ~MAX6650_CFG_PRESCALER_MASK)
+ reg = (reg & ~MAX6650_CFG_PRESCALER_MASK)
| MAX6650_CFG_PRESCALER_4;
break;
case 8:
- config = (config & ~MAX6650_CFG_PRESCALER_MASK)
+ reg = (reg & ~MAX6650_CFG_PRESCALER_MASK)
| MAX6650_CFG_PRESCALER_8;
break;
case 16:
- config = (config & ~MAX6650_CFG_PRESCALER_MASK)
+ reg = (reg & ~MAX6650_CFG_PRESCALER_MASK)
| MAX6650_CFG_PRESCALER_16;
break;
default:
@@ -664,16 +420,43 @@ static int max6650_init_client(struct max6650_data *data,
}
dev_info(dev, "Fan voltage: %dV, prescaler: %d.\n",
- (config & MAX6650_CFG_V12) ? 12 : 5,
- 1 << (config & MAX6650_CFG_PRESCALER_MASK));
+ (reg & MAX6650_CFG_V12) ? 12 : 5,
+ 1 << (reg & MAX6650_CFG_PRESCALER_MASK));
- if (i2c_smbus_write_byte_data(client, MAX6650_REG_CONFIG, config)) {
+ err = i2c_smbus_write_byte_data(client, MAX6650_REG_CONFIG, reg);
+ if (err) {
dev_err(dev, "Config write error, aborting.\n");
return err;
}
+ data->config = reg;
- data->config = config;
- data->count = i2c_smbus_read_byte_data(client, MAX6650_REG_COUNT);
+ reg = i2c_smbus_read_byte_data(client, MAX6650_REG_SPEED);
+ if (reg < 0) {
+ dev_err(dev, "Failed to read speed register, aborting.\n");
+ return reg;
+ }
+ data->speed = reg;
+
+ reg = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC);
+ if (reg < 0) {
+ dev_err(dev, "Failed to read DAC register, aborting.\n");
+ return reg;
+ }
+ data->dac = reg;
+
+ reg = i2c_smbus_read_byte_data(client, MAX6650_REG_COUNT);
+ if (reg < 0) {
+ dev_err(dev, "Failed to read count register, aborting.\n");
+ return reg;
+ }
+ data->count = reg;
+
+ reg = i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN);
+ if (reg < 0) {
+ dev_err(dev, "Failed to read alarm configuration, aborting.\n");
+ return reg;
+ }
+ data->alarm_en = reg;
if (!of_property_read_u32(client->dev.of_node, "maxim,fan-target-rpm",
&target_rpm)) {
@@ -684,8 +467,6 @@ static int max6650_init_client(struct max6650_data *data,
return 0;
}
-#if IS_ENABLED(CONFIG_THERMAL)
-
static int max6650_get_max_state(struct thermal_cooling_device *cdev,
unsigned long *state)
{
@@ -715,23 +496,18 @@ static int max6650_set_cur_state(struct thermal_cooling_device *cdev,
mutex_lock(&data->update_lock);
- if (data->config & MAX6650_CFG_V12)
- data->dac = 180 - (180 * state)/255;
- else
- data->dac = 76 - (76 * state)/255;
-
+ data->dac = pwm_to_dac(state, data->config & MAX6650_CFG_V12);
err = i2c_smbus_write_byte_data(client, MAX6650_REG_DAC, data->dac);
-
if (!err) {
max6650_set_operating_mode(data, state ?
- MAX6650_CFG_MODE_OPEN_LOOP :
- MAX6650_CFG_MODE_OFF);
+ MAX6650_CFG_MODE_OPEN_LOOP :
+ MAX6650_CFG_MODE_OFF);
data->cooling_dev_state = state;
}
mutex_unlock(&data->update_lock);
- return err < 0 ? err : 0;
+ return err;
}
static const struct thermal_cooling_device_ops max6650_cooling_ops = {
@@ -739,11 +515,252 @@ static const struct thermal_cooling_device_ops max6650_cooling_ops = {
.get_cur_state = max6650_get_cur_state,
.set_cur_state = max6650_set_cur_state,
};
-#endif
+
+static int max6650_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct max6650_data *data = max6650_update_device(dev);
+ int mode;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ switch (type) {
+ case hwmon_pwm:
+ switch (attr) {
+ case hwmon_pwm_input:
+ *val = dac_to_pwm(data->dac,
+ data->config & MAX6650_CFG_V12);
+ break;
+ case hwmon_pwm_enable:
+ /*
+ * Possible values:
+ * 0 = Fan always on
+ * 1 = Open loop, Voltage is set according to speed,
+ * not regulated.
+ * 2 = Closed loop, RPM for all fans regulated by fan1
+ * tachometer
+ * 3 = Fan off
+ */
+ mode = (data->config & MAX6650_CFG_MODE_MASK) >> 4;
+ *val = (4 - mode) & 3; /* {0 1 2 3} -> {0 3 2 1} */
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ break;
+ case hwmon_fan:
+ switch (attr) {
+ case hwmon_fan_input:
+ /*
+ * Calculation details:
+ *
+ * Each tachometer counts over an interval given by the
+ * "count" register (0.25, 0.5, 1 or 2 seconds).
+ * The driver assumes that the fans produce two pulses
+ * per revolution (this seems to be the most common).
+ */
+ *val = DIV_ROUND_CLOSEST(data->tach[channel] * 120,
+ DIV_FROM_REG(data->count));
+ break;
+ case hwmon_fan_div:
+ *val = DIV_FROM_REG(data->count);
+ break;
+ case hwmon_fan_target:
+ /*
+ * Use the datasheet equation:
+ * FanSpeed = KSCALE x fCLK / [256 x (KTACH + 1)]
+ * then multiply by 60 to give rpm.
+ */
+ *val = 60 * DIV_FROM_REG(data->config) * clock /
+ (256 * (data->speed + 1));
+ break;
+ case hwmon_fan_min_alarm:
+ *val = !!(data->alarm & MAX6650_ALRM_MIN);
+ data->alarm &= ~MAX6650_ALRM_MIN;
+ data->valid = false;
+ break;
+ case hwmon_fan_max_alarm:
+ *val = !!(data->alarm & MAX6650_ALRM_MAX);
+ data->alarm &= ~MAX6650_ALRM_MAX;
+ data->valid = false;
+ break;
+ case hwmon_fan_fault:
+ *val = !!(data->alarm & MAX6650_ALRM_TACH);
+ data->alarm &= ~MAX6650_ALRM_TACH;
+ data->valid = false;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+static const u8 max6650_pwm_modes[] = {
+ MAX6650_CFG_MODE_ON,
+ MAX6650_CFG_MODE_OPEN_LOOP,
+ MAX6650_CFG_MODE_CLOSED_LOOP,
+ MAX6650_CFG_MODE_OFF,
+};
+
+static int max6650_write(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long val)
+{
+ struct max6650_data *data = dev_get_drvdata(dev);
+ int ret = 0;
+ u8 reg;
+
+ mutex_lock(&data->update_lock);
+
+ switch (type) {
+ case hwmon_pwm:
+ switch (attr) {
+ case hwmon_pwm_input:
+ reg = pwm_to_dac(clamp_val(val, 0, 255),
+ data->config & MAX6650_CFG_V12);
+ ret = i2c_smbus_write_byte_data(data->client,
+ MAX6650_REG_DAC, reg);
+ if (ret)
+ break;
+ data->dac = reg;
+ break;
+ case hwmon_pwm_enable:
+ if (val < 0 || val >= ARRAY_SIZE(max6650_pwm_modes)) {
+ ret = -EINVAL;
+ break;
+ }
+ ret = max6650_set_operating_mode(data,
+ max6650_pwm_modes[val]);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ break;
+ case hwmon_fan:
+ switch (attr) {
+ case hwmon_fan_div:
+ switch (val) {
+ case 1:
+ reg = 0;
+ break;
+ case 2:
+ reg = 1;
+ break;
+ case 4:
+ reg = 2;
+ break;
+ case 8:
+ reg = 3;
+ break;
+ default:
+ ret = -EINVAL;
+ goto error;
+ }
+ ret = i2c_smbus_write_byte_data(data->client,
+ MAX6650_REG_COUNT, reg);
+ if (ret)
+ break;
+ data->count = reg;
+ break;
+ case hwmon_fan_target:
+ if (val < 0) {
+ ret = -EINVAL;
+ break;
+ }
+ ret = max6650_set_target(data, val);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+error:
+ mutex_unlock(&data->update_lock);
+ return ret;
+}
+
+static umode_t max6650_is_visible(const void *_data,
+ enum hwmon_sensor_types type, u32 attr,
+ int channel)
+{
+ const struct max6650_data *data = _data;
+
+ if (channel && (channel >= data->nr_fans || type != hwmon_fan))
+ return 0;
+
+ switch (type) {
+ case hwmon_fan:
+ switch (attr) {
+ case hwmon_fan_input:
+ return 0444;
+ case hwmon_fan_target:
+ case hwmon_fan_div:
+ return 0644;
+ case hwmon_fan_min_alarm:
+ if (data->alarm_en & MAX6650_ALRM_MIN)
+ return 0444;
+ break;
+ case hwmon_fan_max_alarm:
+ if (data->alarm_en & MAX6650_ALRM_MAX)
+ return 0444;
+ break;
+ case hwmon_fan_fault:
+ if (data->alarm_en & MAX6650_ALRM_TACH)
+ return 0444;
+ break;
+ default:
+ break;
+ }
+ break;
+ case hwmon_pwm:
+ switch (attr) {
+ case hwmon_pwm_input:
+ case hwmon_pwm_enable:
+ return 0644;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static const struct hwmon_channel_info *max6650_info[] = {
+ HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_DIV |
+ HWMON_F_MIN_ALARM | HWMON_F_MAX_ALARM |
+ HWMON_F_FAULT,
+ HWMON_F_INPUT, HWMON_F_INPUT, HWMON_F_INPUT),
+ HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT | HWMON_PWM_ENABLE),
+ NULL
+};
+
+static const struct hwmon_ops max6650_hwmon_ops = {
+ .read = max6650_read,
+ .write = max6650_write,
+ .is_visible = max6650_is_visible,
+};
+
+static const struct hwmon_chip_info max6650_chip_info = {
+ .ops = &max6650_hwmon_ops,
+ .info = max6650_info,
+};
static int max6650_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
+ struct thermal_cooling_device *cooling_dev;
struct device *dev = &client->dev;
const struct of_device_id *of_id =
of_match_device(of_match_ptr(max6650_dt_match), dev);
@@ -767,37 +784,23 @@ static int max6650_probe(struct i2c_client *client,
if (err)
return err;
- data->groups[0] = &max6650_group;
- /* 3 additional fan inputs for the MAX6651 */
- if (data->nr_fans == 4)
- data->groups[1] = &max6651_group;
-
- hwmon_dev = devm_hwmon_device_register_with_groups(dev,
- client->name, data,
- data->groups);
+ hwmon_dev = devm_hwmon_device_register_with_info(dev,
+ client->name, data,
+ &max6650_chip_info,
+ max6650_groups);
err = PTR_ERR_OR_ZERO(hwmon_dev);
if (err)
return err;
-#if IS_ENABLED(CONFIG_THERMAL)
- data->cooling_dev =
- thermal_of_cooling_device_register(client->dev.of_node,
- client->name, data,
- &max6650_cooling_ops);
- if (IS_ERR(data->cooling_dev))
- dev_warn(&client->dev,
- "thermal cooling device register failed: %ld\n",
- PTR_ERR(data->cooling_dev));
-#endif
- return 0;
-}
-
-static int max6650_remove(struct i2c_client *client)
-{
- struct max6650_data *data = i2c_get_clientdata(client);
-
- if (!IS_ERR(data->cooling_dev))
- thermal_cooling_device_unregister(data->cooling_dev);
+ if (IS_ENABLED(CONFIG_THERMAL)) {
+ cooling_dev = devm_thermal_of_cooling_device_register(dev,
+ dev->of_node, client->name,
+ data, &max6650_cooling_ops);
+ if (IS_ERR(cooling_dev)) {
+ dev_warn(dev, "thermal cooling device register failed: %ld\n",
+ PTR_ERR(cooling_dev));
+ }
+ }
return 0;
}
@@ -815,7 +818,6 @@ static struct i2c_driver max6650_driver = {
.of_match_table = of_match_ptr(max6650_dt_match),
},
.probe = max6650_probe,
- .remove = max6650_remove,
.id_table = max6650_id,
};
diff --git a/drivers/hwmon/nct7904.c b/drivers/hwmon/nct7904.c
index 58a957445484..710c30562fc1 100644
--- a/drivers/hwmon/nct7904.c
+++ b/drivers/hwmon/nct7904.c
@@ -4,6 +4,9 @@
*
* Copyright (c) 2015 Kontron
* Author: Vadim V. Vlasov <vvlasov@dev.rtsoft.ru>
+ *
+ * Copyright (c) 2019 Advantech
+ * Author: Amy.Shih <amy.shih@advantech.com.tw>
*/
#include <linux/module.h>
@@ -50,6 +53,8 @@
#define T_CPU1_HV_REG 0xA0 /* Bank 0; 2 regs (HV/LV) per sensor */
#define PRTS_REG 0x03 /* Bank 2 */
+#define PFE_REG 0x00 /* Bank 2; PECI Function Enable */
+#define TSI_CTRL_REG 0x50 /* Bank 2; TSI Control Register */
#define FANCTL1_FMR_REG 0x00 /* Bank 3; 1 reg per channel */
#define FANCTL1_OUT_REG 0x10 /* Bank 3; 1 reg per channel */
@@ -65,6 +70,8 @@ struct nct7904_data {
u32 vsen_mask;
u32 tcpu_mask;
u8 fan_mode[FANCTL_MAX];
+ u8 enable_dts;
+ u8 has_dts;
};
/* Access functions */
@@ -229,11 +236,15 @@ static int nct7904_read_temp(struct device *dev, u32 attr, int channel,
switch (attr) {
case hwmon_temp_input:
- if (channel == 0)
+ if (channel == 4)
ret = nct7904_read_reg16(data, BANK_0, LTD_HV_REG);
+ else if (channel < 5)
+ ret = nct7904_read_reg16(data, BANK_0,
+ TEMP_CH1_HV_REG + channel * 4);
else
ret = nct7904_read_reg16(data, BANK_0,
- T_CPU1_HV_REG + (channel - 1) * 2);
+ T_CPU1_HV_REG + (channel - 5)
+ * 2);
if (ret < 0)
return ret;
temp = ((ret & 0xff00) >> 5) | (ret & 0x7);
@@ -249,11 +260,11 @@ static umode_t nct7904_temp_is_visible(const void *_data, u32 attr, int channel)
const struct nct7904_data *data = _data;
if (attr == hwmon_temp_input) {
- if (channel == 0) {
- if (data->vsen_mask & BIT(17))
+ if (channel < 5) {
+ if (data->tcpu_mask & BIT(channel))
return 0444;
} else {
- if (data->tcpu_mask & BIT(channel - 1))
+ if (data->has_dts & BIT(channel - 5))
return 0444;
}
}
@@ -460,6 +471,7 @@ static int nct7904_probe(struct i2c_client *client,
struct device *dev = &client->dev;
int ret, i;
u32 mask;
+ u8 val, bit;
data = devm_kzalloc(dev, sizeof(struct nct7904_data), GFP_KERNEL);
if (!data)
@@ -493,10 +505,65 @@ static int nct7904_probe(struct i2c_client *client,
data->vsen_mask = mask;
/* CPU_TEMP attributes */
- ret = nct7904_read_reg16(data, BANK_0, DTS_T_CTRL0_REG);
+ ret = nct7904_read_reg(data, BANK_0, VT_ADC_CTRL0_REG);
+ if (ret < 0)
+ return ret;
+
+ if ((ret & 0x6) == 0x6)
+ data->tcpu_mask |= 1; /* TR1 */
+ if ((ret & 0x18) == 0x18)
+ data->tcpu_mask |= 2; /* TR2 */
+ if ((ret & 0x20) == 0x20)
+ data->tcpu_mask |= 4; /* TR3 */
+ if ((ret & 0x80) == 0x80)
+ data->tcpu_mask |= 8; /* TR4 */
+
+ /* LTD */
+ ret = nct7904_read_reg(data, BANK_0, VT_ADC_CTRL2_REG);
+ if (ret < 0)
+ return ret;
+ if ((ret & 0x02) == 0x02)
+ data->tcpu_mask |= 0x10;
+
+ /* Multi-Function detecting for Volt and TR/TD */
+ ret = nct7904_read_reg(data, BANK_0, VT_ADC_MD_REG);
if (ret < 0)
return ret;
- data->tcpu_mask = ((ret >> 8) & 0xf) | ((ret & 0xf) << 4);
+
+ for (i = 0; i < 4; i++) {
+ val = (ret & (0x03 << i)) >> (i * 2);
+ bit = (1 << i);
+ if (val == 0)
+ data->tcpu_mask &= ~bit;
+ }
+
+ /* PECI */
+ ret = nct7904_read_reg(data, BANK_2, PFE_REG);
+ if (ret < 0)
+ return ret;
+ if (ret & 0x80) {
+ data->enable_dts = 1; /* Enable DTS & PECI */
+ } else {
+ ret = nct7904_read_reg(data, BANK_2, TSI_CTRL_REG);
+ if (ret < 0)
+ return ret;
+ if (ret & 0x80)
+ data->enable_dts = 0x3; /* Enable DTS & TSI */
+ }
+
+ /* Check DTS enable status */
+ if (data->enable_dts) {
+ ret = nct7904_read_reg(data, BANK_0, DTS_T_CTRL0_REG);
+ if (ret < 0)
+ return ret;
+ data->has_dts = ret & 0xF;
+ if (data->enable_dts & 0x2) {
+ ret = nct7904_read_reg(data, BANK_0, DTS_T_CTRL1_REG);
+ if (ret < 0)
+ return ret;
+ data->has_dts |= (ret & 0xF) << 4;
+ }
+ }
for (i = 0; i < FANCTL_MAX; i++) {
ret = nct7904_read_reg(data, BANK_3, FANCTL1_FMR_REG + i);
diff --git a/drivers/hwmon/occ/common.c b/drivers/hwmon/occ/common.c
index 13a6290c8d25..a7d2b16dd702 100644
--- a/drivers/hwmon/occ/common.c
+++ b/drivers/hwmon/occ/common.c
@@ -124,12 +124,12 @@ struct extended_sensor {
static int occ_poll(struct occ *occ)
{
int rc;
- u16 checksum = occ->poll_cmd_data + 1;
+ u16 checksum = occ->poll_cmd_data + occ->seq_no + 1;
u8 cmd[8];
struct occ_poll_response_header *header;
/* big endian */
- cmd[0] = 0; /* sequence number */
+ cmd[0] = occ->seq_no++; /* sequence number */
cmd[1] = 0; /* cmd type */
cmd[2] = 0; /* data length msb */
cmd[3] = 1; /* data length lsb */
@@ -241,6 +241,12 @@ static ssize_t occ_show_temp_1(struct device *dev,
val = get_unaligned_be16(&temp->sensor_id);
break;
case 1:
+ /*
+ * If a sensor reading has expired and couldn't be refreshed,
+ * OCC returns 0xFFFF for that sensor.
+ */
+ if (temp->value == 0xFFFF)
+ return -EREMOTEIO;
val = get_unaligned_be16(&temp->value) * 1000;
break;
default:
diff --git a/drivers/hwmon/occ/common.h b/drivers/hwmon/occ/common.h
index fc13f3c73c47..67e6968b8978 100644
--- a/drivers/hwmon/occ/common.h
+++ b/drivers/hwmon/occ/common.h
@@ -95,6 +95,7 @@ struct occ {
struct occ_sensors sensors;
int powr_sample_time_us; /* average power sample time */
+ u8 seq_no;
u8 poll_cmd_data; /* to perform OCC poll command */
int (*send_cmd)(struct occ *occ, u8 *cmd);
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
index 30751eb9550a..b6588483fae1 100644
--- a/drivers/hwmon/pmbus/Kconfig
+++ b/drivers/hwmon/pmbus/Kconfig
@@ -64,6 +64,15 @@ config SENSORS_IR38064
This driver can also be built as a module. If so, the module will
be called ir38064.
+config SENSORS_IRPS5401
+ tristate "Infineon IRPS5401"
+ help
+ If you say yes here you get hardware monitoring support for the
+ Infineon IRPS5401 controller.
+
+ This driver can also be built as a module. If so, the module will
+ be called irps5401.
+
config SENSORS_ISL68137
tristate "Intersil ISL68137"
help
@@ -154,6 +163,15 @@ config SENSORS_MAX8688
This driver can also be built as a module. If so, the module will
be called max8688.
+config SENSORS_PXE1610
+ tristate "Infineon PXE1610"
+ help
+ If you say yes here you get hardware monitoring support for Infineon
+ PXE1610.
+
+ This driver can also be built as a module. If so, the module will
+ be called pxe1610.
+
config SENSORS_TPS40422
tristate "TI TPS40422"
help
diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile
index 2219b9300316..c950ea9a5d00 100644
--- a/drivers/hwmon/pmbus/Makefile
+++ b/drivers/hwmon/pmbus/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o
obj-$(CONFIG_SENSORS_IBM_CFFPS) += ibm-cffps.o
obj-$(CONFIG_SENSORS_IR35221) += ir35221.o
obj-$(CONFIG_SENSORS_IR38064) += ir38064.o
+obj-$(CONFIG_SENSORS_IRPS5401) += irps5401.o
obj-$(CONFIG_SENSORS_ISL68137) += isl68137.o
obj-$(CONFIG_SENSORS_LM25066) += lm25066.o
obj-$(CONFIG_SENSORS_LTC2978) += ltc2978.o
@@ -18,6 +19,7 @@ obj-$(CONFIG_SENSORS_MAX20751) += max20751.o
obj-$(CONFIG_SENSORS_MAX31785) += max31785.o
obj-$(CONFIG_SENSORS_MAX34440) += max34440.o
obj-$(CONFIG_SENSORS_MAX8688) += max8688.o
+obj-$(CONFIG_SENSORS_PXE1610) += pxe1610.o
obj-$(CONFIG_SENSORS_TPS40422) += tps40422.o
obj-$(CONFIG_SENSORS_TPS53679) += tps53679.o
obj-$(CONFIG_SENSORS_UCD9000) += ucd9000.o
diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c
index 82052b6611c9..5caa37fbfc18 100644
--- a/drivers/hwmon/pmbus/adm1275.c
+++ b/drivers/hwmon/pmbus/adm1275.c
@@ -14,6 +14,8 @@
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/bitops.h>
+#include <linux/bitfield.h>
+#include <linux/log2.h>
#include "pmbus.h"
enum chips { adm1075, adm1272, adm1275, adm1276, adm1278, adm1293, adm1294 };
@@ -69,6 +71,18 @@ enum chips { adm1075, adm1272, adm1275, adm1276, adm1278, adm1293, adm1294 };
#define ADM1075_VAUX_OV_WARN BIT(7)
#define ADM1075_VAUX_UV_WARN BIT(6)
+#define ADM1275_VI_AVG_SHIFT 0
+#define ADM1275_VI_AVG_MASK GENMASK(ADM1275_VI_AVG_SHIFT + 2, \
+ ADM1275_VI_AVG_SHIFT)
+#define ADM1275_SAMPLES_AVG_MAX 128
+
+#define ADM1278_PWR_AVG_SHIFT 11
+#define ADM1278_PWR_AVG_MASK GENMASK(ADM1278_PWR_AVG_SHIFT + 2, \
+ ADM1278_PWR_AVG_SHIFT)
+#define ADM1278_VI_AVG_SHIFT 8
+#define ADM1278_VI_AVG_MASK GENMASK(ADM1278_VI_AVG_SHIFT + 2, \
+ ADM1278_VI_AVG_SHIFT)
+
struct adm1275_data {
int id;
bool have_oc_fault;
@@ -80,6 +94,7 @@ struct adm1275_data {
bool have_pin_min;
bool have_pin_max;
bool have_temp_max;
+ bool have_power_sampling;
struct pmbus_driver_info info;
};
@@ -155,6 +170,62 @@ static const struct coefficients adm1293_coefficients[] = {
[18] = { 7658, 0, -3 }, /* power, 21V, irange200 */
};
+static int adm1275_read_pmon_config(const struct adm1275_data *data,
+ struct i2c_client *client, bool is_power)
+{
+ int shift, ret;
+ u16 mask;
+
+ /*
+ * The PMON configuration register is a 16-bit register only on chips
+ * supporting power average sampling. On other chips it is an 8-bit
+ * register.
+ */
+ if (data->have_power_sampling) {
+ ret = i2c_smbus_read_word_data(client, ADM1275_PMON_CONFIG);
+ mask = is_power ? ADM1278_PWR_AVG_MASK : ADM1278_VI_AVG_MASK;
+ shift = is_power ? ADM1278_PWR_AVG_SHIFT : ADM1278_VI_AVG_SHIFT;
+ } else {
+ ret = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG);
+ mask = ADM1275_VI_AVG_MASK;
+ shift = ADM1275_VI_AVG_SHIFT;
+ }
+ if (ret < 0)
+ return ret;
+
+ return (ret & mask) >> shift;
+}
+
+static int adm1275_write_pmon_config(const struct adm1275_data *data,
+ struct i2c_client *client,
+ bool is_power, u16 word)
+{
+ int shift, ret;
+ u16 mask;
+
+ if (data->have_power_sampling) {
+ ret = i2c_smbus_read_word_data(client, ADM1275_PMON_CONFIG);
+ mask = is_power ? ADM1278_PWR_AVG_MASK : ADM1278_VI_AVG_MASK;
+ shift = is_power ? ADM1278_PWR_AVG_SHIFT : ADM1278_VI_AVG_SHIFT;
+ } else {
+ ret = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG);
+ mask = ADM1275_VI_AVG_MASK;
+ shift = ADM1275_VI_AVG_SHIFT;
+ }
+ if (ret < 0)
+ return ret;
+
+ word = (ret & ~mask) | ((word << shift) & mask);
+ if (data->have_power_sampling)
+ ret = i2c_smbus_write_word_data(client, ADM1275_PMON_CONFIG,
+ word);
+ else
+ ret = i2c_smbus_write_byte_data(client, ADM1275_PMON_CONFIG,
+ word);
+
+ return ret;
+}
+
static int adm1275_read_word_data(struct i2c_client *client, int page, int reg)
{
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
@@ -233,6 +304,21 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg)
if (!data->have_temp_max)
return -ENXIO;
break;
+ case PMBUS_VIRT_POWER_SAMPLES:
+ if (!data->have_power_sampling)
+ return -ENXIO;
+ ret = adm1275_read_pmon_config(data, client, true);
+ if (ret < 0)
+ break;
+ ret = BIT(ret);
+ break;
+ case PMBUS_VIRT_IN_SAMPLES:
+ case PMBUS_VIRT_CURR_SAMPLES:
+ ret = adm1275_read_pmon_config(data, client, false);
+ if (ret < 0)
+ break;
+ ret = BIT(ret);
+ break;
default:
ret = -ENODATA;
break;
@@ -277,6 +363,19 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg,
case PMBUS_VIRT_RESET_TEMP_HISTORY:
ret = pmbus_write_word_data(client, 0, ADM1278_PEAK_TEMP, 0);
break;
+ case PMBUS_VIRT_POWER_SAMPLES:
+ if (!data->have_power_sampling)
+ return -ENXIO;
+ word = clamp_val(word, 1, ADM1275_SAMPLES_AVG_MAX);
+ ret = adm1275_write_pmon_config(data, client, true,
+ ilog2(word));
+ break;
+ case PMBUS_VIRT_IN_SAMPLES:
+ case PMBUS_VIRT_CURR_SAMPLES:
+ word = clamp_val(word, 1, ADM1275_SAMPLES_AVG_MAX);
+ ret = adm1275_write_pmon_config(data, client, false,
+ ilog2(word));
+ break;
default:
ret = -ENODATA;
break;
@@ -430,7 +529,8 @@ static int adm1275_probe(struct i2c_client *client,
info->format[PSC_CURRENT_OUT] = direct;
info->format[PSC_POWER] = direct;
info->format[PSC_TEMPERATURE] = direct;
- info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
+ info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
+ PMBUS_HAVE_SAMPLES;
info->read_word_data = adm1275_read_word_data;
info->read_byte_data = adm1275_read_byte_data;
@@ -471,6 +571,7 @@ static int adm1275_probe(struct i2c_client *client,
data->have_vout = true;
data->have_pin_max = true;
data->have_temp_max = true;
+ data->have_power_sampling = true;
coefficients = adm1272_coefficients;
vindex = (config & ADM1275_VRANGE) ? 1 : 0;
@@ -556,6 +657,7 @@ static int adm1275_probe(struct i2c_client *client,
data->have_vout = true;
data->have_pin_max = true;
data->have_temp_max = true;
+ data->have_power_sampling = true;
coefficients = adm1278_coefficients;
vindex = 0;
@@ -591,6 +693,7 @@ static int adm1275_probe(struct i2c_client *client,
data->have_pin_min = true;
data->have_pin_max = true;
data->have_mfr_vaux_status = true;
+ data->have_power_sampling = true;
coefficients = adm1293_coefficients;
diff --git a/drivers/hwmon/pmbus/irps5401.c b/drivers/hwmon/pmbus/irps5401.c
new file mode 100644
index 000000000000..d37daa001fb3
--- /dev/null
+++ b/drivers/hwmon/pmbus/irps5401.c
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Hardware monitoring driver for the Infineon IRPS5401M PMIC.
+ *
+ * Copyright (c) 2019 SED Systems, a division of Calian Ltd.
+ *
+ * The device supports VOUT_PEAK, IOUT_PEAK, and TEMPERATURE_PEAK, however
+ * this driver does not currently support them.
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include "pmbus.h"
+
+#define IRPS5401_SW_FUNC (PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | \
+ PMBUS_HAVE_STATUS_INPUT | \
+ PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | \
+ PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | \
+ PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | \
+ PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP)
+
+#define IRPS5401_LDO_FUNC (PMBUS_HAVE_VIN | \
+ PMBUS_HAVE_STATUS_INPUT | \
+ PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | \
+ PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | \
+ PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | \
+ PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP)
+
+static struct pmbus_driver_info irps5401_info = {
+ .pages = 5,
+ .func[0] = IRPS5401_SW_FUNC,
+ .func[1] = IRPS5401_SW_FUNC,
+ .func[2] = IRPS5401_SW_FUNC,
+ .func[3] = IRPS5401_SW_FUNC,
+ .func[4] = IRPS5401_LDO_FUNC,
+};
+
+static int irps5401_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ return pmbus_do_probe(client, id, &irps5401_info);
+}
+
+static const struct i2c_device_id irps5401_id[] = {
+ {"irps5401", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, irps5401_id);
+
+static struct i2c_driver irps5401_driver = {
+ .driver = {
+ .name = "irps5401",
+ },
+ .probe = irps5401_probe,
+ .remove = pmbus_do_remove,
+ .id_table = irps5401_id,
+};
+
+module_i2c_driver(irps5401_driver);
+
+MODULE_AUTHOR("Robert Hancock");
+MODULE_DESCRIPTION("PMBus driver for Infineon IRPS5401");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/pmbus/pxe1610.c b/drivers/hwmon/pmbus/pxe1610.c
new file mode 100644
index 000000000000..ebe3f023f840
--- /dev/null
+++ b/drivers/hwmon/pmbus/pxe1610.c
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Hardware monitoring driver for Infineon PXE1610
+ *
+ * Copyright (c) 2019 Facebook Inc
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include "pmbus.h"
+
+#define PXE1610_NUM_PAGES 3
+
+/* Identify chip parameters. */
+static int pxe1610_identify(struct i2c_client *client,
+ struct pmbus_driver_info *info)
+{
+ if (pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE)) {
+ u8 vout_mode;
+ int ret;
+
+ /* Read the register with VOUT scaling value.*/
+ ret = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE);
+ if (ret < 0)
+ return ret;
+
+ vout_mode = ret & GENMASK(4, 0);
+
+ switch (vout_mode) {
+ case 1:
+ info->vrm_version = vr12;
+ break;
+ case 2:
+ info->vrm_version = vr13;
+ break;
+ default:
+ return -ENODEV;
+ }
+ }
+
+ return 0;
+}
+
+static struct pmbus_driver_info pxe1610_info = {
+ .pages = PXE1610_NUM_PAGES,
+ .format[PSC_VOLTAGE_IN] = linear,
+ .format[PSC_VOLTAGE_OUT] = vid,
+ .format[PSC_CURRENT_IN] = linear,
+ .format[PSC_CURRENT_OUT] = linear,
+ .format[PSC_TEMPERATURE] = linear,
+ .format[PSC_POWER] = linear,
+ .func[0] = PMBUS_HAVE_VIN
+ | PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN
+ | PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN
+ | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
+ | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
+ | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP,
+ .func[1] = PMBUS_HAVE_VIN
+ | PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN
+ | PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN
+ | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
+ | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
+ | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP,
+ .func[2] = PMBUS_HAVE_VIN
+ | PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN
+ | PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN
+ | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
+ | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
+ | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP,
+ .identify = pxe1610_identify,
+};
+
+static int pxe1610_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct pmbus_driver_info *info;
+ u8 buf[I2C_SMBUS_BLOCK_MAX];
+ int ret;
+
+ if (!i2c_check_functionality(
+ client->adapter,
+ I2C_FUNC_SMBUS_READ_BYTE_DATA
+ | I2C_FUNC_SMBUS_READ_WORD_DATA
+ | I2C_FUNC_SMBUS_READ_BLOCK_DATA))
+ return -ENODEV;
+
+ /*
+ * By default this device doesn't boot to page 0, so set page 0
+ * to access all pmbus registers.
+ */
+ i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0);
+
+ /* Read Manufacturer id */
+ ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed to read PMBUS_MFR_ID\n");
+ return ret;
+ }
+ if (ret != 2 || strncmp(buf, "XP", 2)) {
+ dev_err(&client->dev, "MFR_ID unrecognized\n");
+ return -ENODEV;
+ }
+
+ info = devm_kmemdup(&client->dev, &pxe1610_info,
+ sizeof(struct pmbus_driver_info),
+ GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ return pmbus_do_probe(client, id, info);
+}
+
+static const struct i2c_device_id pxe1610_id[] = {
+ {"pxe1610", 0},
+ {"pxe1110", 0},
+ {"pxm1310", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, pxe1610_id);
+
+static struct i2c_driver pxe1610_driver = {
+ .driver = {
+ .name = "pxe1610",
+ },
+ .probe = pxe1610_probe,
+ .remove = pmbus_do_remove,
+ .id_table = pxe1610_id,
+};
+
+module_i2c_driver(pxe1610_driver);
+
+MODULE_AUTHOR("Vijay Khemka <vijaykhemka@fb.com>");
+MODULE_DESCRIPTION("PMBus driver for Infineon PXE1610, PXE1110 and PXM1310");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c
index 08c9b9f1c16e..54c0ff00d67f 100644
--- a/drivers/hwmon/pwm-fan.c
+++ b/drivers/hwmon/pwm-fan.c
@@ -320,8 +320,10 @@ static int pwm_fan_probe(struct platform_device *pdev)
dev_err(dev, "Failed to enable fan supply: %d\n", ret);
return ret;
}
- devm_add_action_or_reset(dev, pwm_fan_regulator_disable,
- ctx->reg_en);
+ ret = devm_add_action_or_reset(dev, pwm_fan_regulator_disable,
+ ctx->reg_en);
+ if (ret)
+ return ret;
}
ctx->pwm_value = MAX_PWM;
@@ -337,7 +339,9 @@ static int pwm_fan_probe(struct platform_device *pdev)
return ret;
}
timer_setup(&ctx->rpm_timer, sample_timer, 0);
- devm_add_action_or_reset(dev, pwm_fan_pwm_disable, ctx);
+ ret = devm_add_action_or_reset(dev, pwm_fan_pwm_disable, ctx);
+ if (ret)
+ return ret;
of_property_read_u32(dev->of_node, "pulses-per-revolution", &ppr);
ctx->pulses_per_revolution = ppr;
diff --git a/drivers/hwmon/scpi-hwmon.c b/drivers/hwmon/scpi-hwmon.c
index 9bfa228d0eb0..25aac40f2764 100644
--- a/drivers/hwmon/scpi-hwmon.c
+++ b/drivers/hwmon/scpi-hwmon.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* System Control and Power Interface(SCPI) based hwmon sensor driver
*
* Copyright (C) 2015 ARM Ltd.
* Punit Agrawal <punit.agrawal@arm.com>
- *
- * 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.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/hwmon.h>
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c
index cc6aca6e436c..b637836b58a1 100644
--- a/drivers/hwmon/smsc47m1.c
+++ b/drivers/hwmon/smsc47m1.c
@@ -351,6 +351,8 @@ static ssize_t fan_div_store(struct device *dev,
tmp |= data->fan_div[2] << 4;
smsc47m1_write_value(data, SMSC47M2_REG_FANDIV3, tmp);
break;
+ default:
+ BUG();
}
/* Preserve fan min */
diff --git a/drivers/hwspinlock/Kconfig b/drivers/hwspinlock/Kconfig
index 7869c67e5b6b..37740e992cfa 100644
--- a/drivers/hwspinlock/Kconfig
+++ b/drivers/hwspinlock/Kconfig
@@ -9,7 +9,7 @@ menuconfig HWSPINLOCK
config HWSPINLOCK_OMAP
tristate "OMAP Hardware Spinlock device"
depends on HWSPINLOCK
- depends on ARCH_OMAP4 || SOC_OMAP5 || SOC_DRA7XX || SOC_AM33XX || SOC_AM43XX
+ depends on ARCH_OMAP4 || SOC_OMAP5 || SOC_DRA7XX || SOC_AM33XX || SOC_AM43XX || ARCH_K3
help
Say y here to support the OMAP Hardware Spinlock device (firstly
introduced in OMAP4).
diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c
index 2bad40d42210..8862445aa858 100644
--- a/drivers/hwspinlock/hwspinlock_core.c
+++ b/drivers/hwspinlock/hwspinlock_core.c
@@ -9,6 +9,7 @@
#define pr_fmt(fmt) "%s: " fmt, __func__
+#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/spinlock.h>
@@ -23,6 +24,9 @@
#include "hwspinlock_internal.h"
+/* retry delay used in atomic context */
+#define HWSPINLOCK_RETRY_DELAY_US 100
+
/* radix tree tags */
#define HWSPINLOCK_UNUSED (0) /* tags an hwspinlock as unused */
@@ -68,11 +72,11 @@ static DEFINE_MUTEX(hwspinlock_tree_lock);
* user need some time-consuming or sleepable operations under the hardware
* lock, they need one sleepable lock (like mutex) to protect the operations.
*
- * If the mode is not HWLOCK_RAW, upon a successful return from this function,
- * preemption (and possibly interrupts) is disabled, so the caller must not
- * sleep, and is advised to release the hwspinlock as soon as possible. This is
- * required in order to minimize remote cores polling on the hardware
- * interconnect.
+ * If the mode is neither HWLOCK_IN_ATOMIC nor HWLOCK_RAW, upon a successful
+ * return from this function, preemption (and possibly interrupts) is disabled,
+ * so the caller must not sleep, and is advised to release the hwspinlock as
+ * soon as possible. This is required in order to minimize remote cores polling
+ * on the hardware interconnect.
*
* The user decides whether local interrupts are disabled or not, and if yes,
* whether he wants their previous state to be saved. It is up to the user
@@ -112,6 +116,7 @@ int __hwspin_trylock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
ret = spin_trylock_irq(&hwlock->lock);
break;
case HWLOCK_RAW:
+ case HWLOCK_IN_ATOMIC:
ret = 1;
break;
default:
@@ -136,6 +141,7 @@ int __hwspin_trylock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
spin_unlock_irq(&hwlock->lock);
break;
case HWLOCK_RAW:
+ case HWLOCK_IN_ATOMIC:
/* Nothing to do */
break;
default:
@@ -179,11 +185,14 @@ EXPORT_SYMBOL_GPL(__hwspin_trylock);
* user need some time-consuming or sleepable operations under the hardware
* lock, they need one sleepable lock (like mutex) to protect the operations.
*
- * If the mode is not HWLOCK_RAW, upon a successful return from this function,
- * preemption is disabled (and possibly local interrupts, too), so the caller
- * must not sleep, and is advised to release the hwspinlock as soon as possible.
- * This is required in order to minimize remote cores polling on the
- * hardware interconnect.
+ * If the mode is HWLOCK_IN_ATOMIC (called from an atomic context) the timeout
+ * is handled with busy-waiting delays, hence shall not exceed few msecs.
+ *
+ * If the mode is neither HWLOCK_IN_ATOMIC nor HWLOCK_RAW, upon a successful
+ * return from this function, preemption (and possibly interrupts) is disabled,
+ * so the caller must not sleep, and is advised to release the hwspinlock as
+ * soon as possible. This is required in order to minimize remote cores polling
+ * on the hardware interconnect.
*
* The user decides whether local interrupts are disabled or not, and if yes,
* whether he wants their previous state to be saved. It is up to the user
@@ -198,7 +207,7 @@ int __hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int to,
int mode, unsigned long *flags)
{
int ret;
- unsigned long expire;
+ unsigned long expire, atomic_delay = 0;
expire = msecs_to_jiffies(to) + jiffies;
@@ -212,8 +221,15 @@ int __hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int to,
* The lock is already taken, let's check if the user wants
* us to try again
*/
- if (time_is_before_eq_jiffies(expire))
- return -ETIMEDOUT;
+ if (mode == HWLOCK_IN_ATOMIC) {
+ udelay(HWSPINLOCK_RETRY_DELAY_US);
+ atomic_delay += HWSPINLOCK_RETRY_DELAY_US;
+ if (atomic_delay > to * 1000)
+ return -ETIMEDOUT;
+ } else {
+ if (time_is_before_eq_jiffies(expire))
+ return -ETIMEDOUT;
+ }
/*
* Allow platform-specific relax handlers to prevent
@@ -276,6 +292,7 @@ void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
spin_unlock_irq(&hwlock->lock);
break;
case HWLOCK_RAW:
+ case HWLOCK_IN_ATOMIC:
/* Nothing to do */
break;
default:
@@ -333,6 +350,11 @@ int of_hwspin_lock_get_id(struct device_node *np, int index)
if (ret)
return ret;
+ if (!of_device_is_available(args.np)) {
+ ret = -ENOENT;
+ goto out;
+ }
+
/* Find the hwspinlock device: we need its base_id */
ret = -EPROBE_DEFER;
rcu_read_lock();
diff --git a/drivers/hwspinlock/omap_hwspinlock.c b/drivers/hwspinlock/omap_hwspinlock.c
index 625844e0abef..14e1a532ebb5 100644
--- a/drivers/hwspinlock/omap_hwspinlock.c
+++ b/drivers/hwspinlock/omap_hwspinlock.c
@@ -140,6 +140,9 @@ static int omap_hwspinlock_probe(struct platform_device *pdev)
if (ret)
goto reg_fail;
+ dev_dbg(&pdev->dev, "Registered %d locks with HwSpinlock core\n",
+ num_locks);
+
return 0;
reg_fail:
@@ -171,6 +174,7 @@ static int omap_hwspinlock_remove(struct platform_device *pdev)
static const struct of_device_id omap_hwspinlock_of_match[] = {
{ .compatible = "ti,omap4-hwspinlock", },
+ { .compatible = "ti,am654-hwspinlock", },
{ /* end */ },
};
MODULE_DEVICE_TABLE(of, omap_hwspinlock_of_match);
diff --git a/drivers/hwspinlock/stm32_hwspinlock.c b/drivers/hwspinlock/stm32_hwspinlock.c
index 441839288893..c8eacf4f9692 100644
--- a/drivers/hwspinlock/stm32_hwspinlock.c
+++ b/drivers/hwspinlock/stm32_hwspinlock.c
@@ -5,6 +5,7 @@
*/
#include <linux/clk.h>
+#include <linux/delay.h>
#include <linux/hwspinlock.h>
#include <linux/io.h>
#include <linux/kernel.h>
@@ -42,9 +43,15 @@ static void stm32_hwspinlock_unlock(struct hwspinlock *lock)
writel(STM32_MUTEX_COREID, lock_addr);
}
+static void stm32_hwspinlock_relax(struct hwspinlock *lock)
+{
+ ndelay(50);
+}
+
static const struct hwspinlock_ops stm32_hwspinlock_ops = {
.trylock = stm32_hwspinlock_trylock,
.unlock = stm32_hwspinlock_unlock,
+ .relax = stm32_hwspinlock_relax,
};
static int stm32_hwspinlock_probe(struct platform_device *pdev)
diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig
index 5487d4a1abc2..14638db4991d 100644
--- a/drivers/hwtracing/coresight/Kconfig
+++ b/drivers/hwtracing/coresight/Kconfig
@@ -4,6 +4,7 @@
#
menuconfig CORESIGHT
bool "CoreSight Tracing Support"
+ depends on OF || ACPI
select ARM_AMBA
select PERF_EVENTS
help
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile
index 3b435aa42af5..3c0ac421e211 100644
--- a/drivers/hwtracing/coresight/Makefile
+++ b/drivers/hwtracing/coresight/Makefile
@@ -2,8 +2,7 @@
#
# Makefile for CoreSight drivers.
#
-obj-$(CONFIG_CORESIGHT) += coresight.o coresight-etm-perf.o
-obj-$(CONFIG_OF) += of_coresight.o
+obj-$(CONFIG_CORESIGHT) += coresight.o coresight-etm-perf.o coresight-platform.o
obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o \
coresight-tmc-etf.o \
coresight-tmc-etr.o
diff --git a/drivers/hwtracing/coresight/coresight-catu.c b/drivers/hwtracing/coresight/coresight-catu.c
index 4ea68a3522e9..16ebf38a9f66 100644
--- a/drivers/hwtracing/coresight/coresight-catu.c
+++ b/drivers/hwtracing/coresight/coresight-catu.c
@@ -28,6 +28,8 @@
#define catu_dbg(x, ...) do {} while (0)
#endif
+DEFINE_CORESIGHT_DEVLIST(catu_devs, "catu");
+
struct catu_etr_buf {
struct tmc_sg_table *catu_table;
dma_addr_t sladdr;
@@ -328,19 +330,18 @@ static int catu_alloc_etr_buf(struct tmc_drvdata *tmc_drvdata,
struct etr_buf *etr_buf, int node, void **pages)
{
struct coresight_device *csdev;
- struct device *catu_dev;
struct tmc_sg_table *catu_table;
struct catu_etr_buf *catu_buf;
csdev = tmc_etr_get_catu_device(tmc_drvdata);
if (!csdev)
return -ENODEV;
- catu_dev = csdev->dev.parent;
catu_buf = kzalloc(sizeof(*catu_buf), GFP_KERNEL);
if (!catu_buf)
return -ENOMEM;
- catu_table = catu_init_sg_table(catu_dev, node, etr_buf->size, pages);
+ catu_table = catu_init_sg_table(&csdev->dev, node,
+ etr_buf->size, pages);
if (IS_ERR(catu_table)) {
kfree(catu_buf);
return PTR_ERR(catu_table);
@@ -409,13 +410,14 @@ static int catu_enable_hw(struct catu_drvdata *drvdata, void *data)
int rc;
u32 control, mode;
struct etr_buf *etr_buf = data;
+ struct device *dev = &drvdata->csdev->dev;
if (catu_wait_for_ready(drvdata))
- dev_warn(drvdata->dev, "Timeout while waiting for READY\n");
+ dev_warn(dev, "Timeout while waiting for READY\n");
control = catu_read_control(drvdata);
if (control & BIT(CATU_CONTROL_ENABLE)) {
- dev_warn(drvdata->dev, "CATU is already enabled\n");
+ dev_warn(dev, "CATU is already enabled\n");
return -EBUSY;
}
@@ -441,7 +443,7 @@ static int catu_enable_hw(struct catu_drvdata *drvdata, void *data)
catu_write_irqen(drvdata, 0);
catu_write_mode(drvdata, mode);
catu_write_control(drvdata, control);
- dev_dbg(drvdata->dev, "Enabled in %s mode\n",
+ dev_dbg(dev, "Enabled in %s mode\n",
(mode == CATU_MODE_PASS_THROUGH) ?
"Pass through" :
"Translate");
@@ -462,15 +464,16 @@ static int catu_enable(struct coresight_device *csdev, void *data)
static int catu_disable_hw(struct catu_drvdata *drvdata)
{
int rc = 0;
+ struct device *dev = &drvdata->csdev->dev;
catu_write_control(drvdata, 0);
coresight_disclaim_device_unlocked(drvdata->base);
if (catu_wait_for_ready(drvdata)) {
- dev_info(drvdata->dev, "Timeout while waiting for READY\n");
+ dev_info(dev, "Timeout while waiting for READY\n");
rc = -EAGAIN;
}
- dev_dbg(drvdata->dev, "Disabled\n");
+ dev_dbg(dev, "Disabled\n");
return rc;
}
@@ -502,17 +505,11 @@ static int catu_probe(struct amba_device *adev, const struct amba_id *id)
struct coresight_desc catu_desc;
struct coresight_platform_data *pdata = NULL;
struct device *dev = &adev->dev;
- struct device_node *np = dev->of_node;
void __iomem *base;
- if (np) {
- pdata = of_get_coresight_platform_data(dev, np);
- if (IS_ERR(pdata)) {
- ret = PTR_ERR(pdata);
- goto out;
- }
- dev->platform_data = pdata;
- }
+ catu_desc.name = coresight_alloc_device_name(&catu_devs, dev);
+ if (!catu_desc.name)
+ return -ENOMEM;
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata) {
@@ -520,7 +517,6 @@ static int catu_probe(struct amba_device *adev, const struct amba_id *id)
goto out;
}
- drvdata->dev = dev;
dev_set_drvdata(dev, drvdata);
base = devm_ioremap_resource(dev, &adev->res);
if (IS_ERR(base)) {
@@ -547,6 +543,13 @@ static int catu_probe(struct amba_device *adev, const struct amba_id *id)
if (ret)
goto out;
+ pdata = coresight_get_platform_data(dev);
+ if (IS_ERR(pdata)) {
+ ret = PTR_ERR(pdata);
+ goto out;
+ }
+ dev->platform_data = pdata;
+
drvdata->base = base;
catu_desc.pdata = pdata;
catu_desc.dev = dev;
@@ -554,6 +557,7 @@ static int catu_probe(struct amba_device *adev, const struct amba_id *id)
catu_desc.type = CORESIGHT_DEV_TYPE_HELPER;
catu_desc.subtype.helper_subtype = CORESIGHT_DEV_SUBTYPE_HELPER_CATU;
catu_desc.ops = &catu_ops;
+
drvdata->csdev = coresight_register(&catu_desc);
if (IS_ERR(drvdata->csdev))
ret = PTR_ERR(drvdata->csdev);
diff --git a/drivers/hwtracing/coresight/coresight-catu.h b/drivers/hwtracing/coresight/coresight-catu.h
index 1d2ad183fd92..80ceee3c739c 100644
--- a/drivers/hwtracing/coresight/coresight-catu.h
+++ b/drivers/hwtracing/coresight/coresight-catu.h
@@ -61,7 +61,6 @@
#define CATU_IRQEN_OFF 0x0
struct catu_drvdata {
- struct device *dev;
void __iomem *base;
struct coresight_device *csdev;
int irq;
diff --git a/drivers/hwtracing/coresight/coresight-cpu-debug.c b/drivers/hwtracing/coresight/coresight-cpu-debug.c
index e8819d750938..2463aa7ab4f6 100644
--- a/drivers/hwtracing/coresight/coresight-cpu-debug.c
+++ b/drivers/hwtracing/coresight/coresight-cpu-debug.c
@@ -525,23 +525,12 @@ static const struct file_operations debug_func_knob_fops = {
static int debug_func_init(void)
{
- struct dentry *file;
int ret;
/* Create debugfs node */
debug_debugfs_dir = debugfs_create_dir("coresight_cpu_debug", NULL);
- if (!debug_debugfs_dir) {
- pr_err("%s: unable to create debugfs directory\n", __func__);
- return -ENOMEM;
- }
-
- file = debugfs_create_file("enable", 0644, debug_debugfs_dir, NULL,
- &debug_func_knob_fops);
- if (!file) {
- pr_err("%s: unable to create enable knob file\n", __func__);
- ret = -ENOMEM;
- goto err;
- }
+ debugfs_create_file("enable", 0644, debug_debugfs_dir, NULL,
+ &debug_func_knob_fops);
/* Register function to be called for panic */
ret = atomic_notifier_chain_register(&panic_notifier_list,
@@ -572,14 +561,16 @@ static int debug_probe(struct amba_device *adev, const struct amba_id *id)
struct device *dev = &adev->dev;
struct debug_drvdata *drvdata;
struct resource *res = &adev->res;
- struct device_node *np = adev->dev.of_node;
int ret;
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
- drvdata->cpu = np ? of_coresight_get_cpu(np) : 0;
+ drvdata->cpu = coresight_get_cpu(dev);
+ if (drvdata->cpu < 0)
+ return drvdata->cpu;
+
if (per_cpu(debug_drvdata, drvdata->cpu)) {
dev_err(dev, "CPU%d drvdata has already been initialized\n",
drvdata->cpu);
diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c
index 4ee4c80a4354..3810290e6d07 100644
--- a/drivers/hwtracing/coresight/coresight-etb10.c
+++ b/drivers/hwtracing/coresight/coresight-etb10.c
@@ -63,10 +63,11 @@
#define ETB_FFSR_BIT 1
#define ETB_FRAME_SIZE_WORDS 4
+DEFINE_CORESIGHT_DEVLIST(etb_devs, "etb");
+
/**
* struct etb_drvdata - specifics associated to an ETB component
* @base: memory mapped base address for this component.
- * @dev: the device entity associated to this component.
* @atclk: optional clock for the core parts of the ETB.
* @csdev: component vitals needed by the framework.
* @miscdev: specifics to handle "/dev/xyz.etb" entry.
@@ -81,7 +82,6 @@
*/
struct etb_drvdata {
void __iomem *base;
- struct device *dev;
struct clk *atclk;
struct coresight_device *csdev;
struct miscdevice miscdev;
@@ -227,7 +227,6 @@ out:
static int etb_enable(struct coresight_device *csdev, u32 mode, void *data)
{
int ret;
- struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
switch (mode) {
case CS_MODE_SYSFS:
@@ -244,13 +243,14 @@ static int etb_enable(struct coresight_device *csdev, u32 mode, void *data)
if (ret)
return ret;
- dev_dbg(drvdata->dev, "ETB enabled\n");
+ dev_dbg(&csdev->dev, "ETB enabled\n");
return 0;
}
static void __etb_disable_hw(struct etb_drvdata *drvdata)
{
u32 ffcr;
+ struct device *dev = &drvdata->csdev->dev;
CS_UNLOCK(drvdata->base);
@@ -263,7 +263,7 @@ static void __etb_disable_hw(struct etb_drvdata *drvdata)
writel_relaxed(ffcr, drvdata->base + ETB_FFCR);
if (coresight_timeout(drvdata->base, ETB_FFCR, ETB_FFCR_BIT, 0)) {
- dev_err(drvdata->dev,
+ dev_err(dev,
"timeout while waiting for completion of Manual Flush\n");
}
@@ -271,7 +271,7 @@ static void __etb_disable_hw(struct etb_drvdata *drvdata)
writel_relaxed(0x0, drvdata->base + ETB_CTL_REG);
if (coresight_timeout(drvdata->base, ETB_FFSR, ETB_FFSR_BIT, 1)) {
- dev_err(drvdata->dev,
+ dev_err(dev,
"timeout while waiting for Formatter to Stop\n");
}
@@ -286,6 +286,7 @@ static void etb_dump_hw(struct etb_drvdata *drvdata)
u32 read_data, depth;
u32 read_ptr, write_ptr;
u32 frame_off, frame_endoff;
+ struct device *dev = &drvdata->csdev->dev;
CS_UNLOCK(drvdata->base);
@@ -295,10 +296,10 @@ static void etb_dump_hw(struct etb_drvdata *drvdata)
frame_off = write_ptr % ETB_FRAME_SIZE_WORDS;
frame_endoff = ETB_FRAME_SIZE_WORDS - frame_off;
if (frame_off) {
- dev_err(drvdata->dev,
+ dev_err(dev,
"write_ptr: %lu not aligned to formatter frame size\n",
(unsigned long)write_ptr);
- dev_err(drvdata->dev, "frameoff: %lu, frame_endoff: %lu\n",
+ dev_err(dev, "frameoff: %lu, frame_endoff: %lu\n",
(unsigned long)frame_off, (unsigned long)frame_endoff);
write_ptr += frame_endoff;
}
@@ -365,7 +366,7 @@ static int etb_disable(struct coresight_device *csdev)
drvdata->mode = CS_MODE_DISABLED;
spin_unlock_irqrestore(&drvdata->spinlock, flags);
- dev_dbg(drvdata->dev, "ETB disabled\n");
+ dev_dbg(&csdev->dev, "ETB disabled\n");
return 0;
}
@@ -373,12 +374,10 @@ static void *etb_alloc_buffer(struct coresight_device *csdev,
struct perf_event *event, void **pages,
int nr_pages, bool overwrite)
{
- int node, cpu = event->cpu;
+ int node;
struct cs_buffers *buf;
- if (cpu == -1)
- cpu = smp_processor_id();
- node = cpu_to_node(cpu);
+ node = (event->cpu == -1) ? NUMA_NO_NODE : cpu_to_node(event->cpu);
buf = kzalloc_node(sizeof(struct cs_buffers), GFP_KERNEL, node);
if (!buf)
@@ -460,7 +459,7 @@ static unsigned long etb_update_buffer(struct coresight_device *csdev,
* chance to fix things.
*/
if (write_ptr % ETB_FRAME_SIZE_WORDS) {
- dev_err(drvdata->dev,
+ dev_err(&csdev->dev,
"write_ptr: %lu not aligned to formatter frame size\n",
(unsigned long)write_ptr);
@@ -512,7 +511,13 @@ static unsigned long etb_update_buffer(struct coresight_device *csdev,
lost = true;
}
- if (lost)
+ /*
+ * Don't set the TRUNCATED flag in snapshot mode because 1) the
+ * captured buffer is expected to be truncated and 2) a full buffer
+ * prevents the event from being re-enabled by the perf core,
+ * resulting in stale data being send to user space.
+ */
+ if (!buf->snapshot && lost)
perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED);
/* finally tell HW where we want to start reading from */
@@ -548,13 +553,14 @@ static unsigned long etb_update_buffer(struct coresight_device *csdev,
writel_relaxed(0x0, drvdata->base + ETB_RAM_WRITE_POINTER);
/*
- * In snapshot mode we have to update the handle->head to point
- * to the new location.
+ * In snapshot mode we simply increment the head by the number of byte
+ * that were written. User space function cs_etm_find_snapshot() will
+ * figure out how many bytes to get from the AUX buffer based on the
+ * position of the head.
*/
- if (buf->snapshot) {
- handle->head = (cur * PAGE_SIZE) + offset;
- to_read = buf->nr_pages << PAGE_SHIFT;
- }
+ if (buf->snapshot)
+ handle->head += to_read;
+
__etb_enable_hw(drvdata);
CS_LOCK(drvdata->base);
out:
@@ -587,7 +593,7 @@ static void etb_dump(struct etb_drvdata *drvdata)
}
spin_unlock_irqrestore(&drvdata->spinlock, flags);
- dev_dbg(drvdata->dev, "ETB dumped\n");
+ dev_dbg(&drvdata->csdev->dev, "ETB dumped\n");
}
static int etb_open(struct inode *inode, struct file *file)
@@ -598,7 +604,7 @@ static int etb_open(struct inode *inode, struct file *file)
if (local_cmpxchg(&drvdata->reading, 0, 1))
return -EBUSY;
- dev_dbg(drvdata->dev, "%s: successfully opened\n", __func__);
+ dev_dbg(&drvdata->csdev->dev, "%s: successfully opened\n", __func__);
return 0;
}
@@ -608,6 +614,7 @@ static ssize_t etb_read(struct file *file, char __user *data,
u32 depth;
struct etb_drvdata *drvdata = container_of(file->private_data,
struct etb_drvdata, miscdev);
+ struct device *dev = &drvdata->csdev->dev;
etb_dump(drvdata);
@@ -616,13 +623,14 @@ static ssize_t etb_read(struct file *file, char __user *data,
len = depth * 4 - *ppos;
if (copy_to_user(data, drvdata->buf + *ppos, len)) {
- dev_dbg(drvdata->dev, "%s: copy_to_user failed\n", __func__);
+ dev_dbg(dev,
+ "%s: copy_to_user failed\n", __func__);
return -EFAULT;
}
*ppos += len;
- dev_dbg(drvdata->dev, "%s: %zu bytes copied, %d bytes left\n",
+ dev_dbg(dev, "%s: %zu bytes copied, %d bytes left\n",
__func__, len, (int)(depth * 4 - *ppos));
return len;
}
@@ -633,7 +641,7 @@ static int etb_release(struct inode *inode, struct file *file)
struct etb_drvdata, miscdev);
local_set(&drvdata->reading, 0);
- dev_dbg(drvdata->dev, "%s: released\n", __func__);
+ dev_dbg(&drvdata->csdev->dev, "%s: released\n", __func__);
return 0;
}
@@ -724,20 +732,15 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id)
struct etb_drvdata *drvdata;
struct resource *res = &adev->res;
struct coresight_desc desc = { 0 };
- struct device_node *np = adev->dev.of_node;
- if (np) {
- pdata = of_get_coresight_platform_data(dev, np);
- if (IS_ERR(pdata))
- return PTR_ERR(pdata);
- adev->dev.platform_data = pdata;
- }
+ desc.name = coresight_alloc_device_name(&etb_devs, dev);
+ if (!desc.name)
+ return -ENOMEM;
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
- drvdata->dev = &adev->dev;
drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */
if (!IS_ERR(drvdata->atclk)) {
ret = clk_prepare_enable(drvdata->atclk);
@@ -768,6 +771,11 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id)
/* This device is not associated with a session */
drvdata->pid = -1;
+ pdata = coresight_get_platform_data(dev);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+ adev->dev.platform_data = pdata;
+
desc.type = CORESIGHT_DEV_TYPE_SINK;
desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
desc.ops = &etb_cs_ops;
@@ -778,7 +786,7 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id)
if (IS_ERR(drvdata->csdev))
return PTR_ERR(drvdata->csdev);
- drvdata->miscdev.name = pdata->name;
+ drvdata->miscdev.name = desc.name;
drvdata->miscdev.minor = MISC_DYNAMIC_MINOR;
drvdata->miscdev.fops = &etb_fops;
ret = misc_register(&drvdata->miscdev);
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c
index 3c6294432748..5c1ca0df5cb0 100644
--- a/drivers/hwtracing/coresight/coresight-etm-perf.c
+++ b/drivers/hwtracing/coresight/coresight-etm-perf.c
@@ -523,7 +523,7 @@ int etm_perf_add_symlink_sink(struct coresight_device *csdev)
unsigned long hash;
const char *name;
struct device *pmu_dev = etm_pmu.dev;
- struct device *pdev = csdev->dev.parent;
+ struct device *dev = &csdev->dev;
struct dev_ext_attribute *ea;
if (csdev->type != CORESIGHT_DEV_TYPE_SINK &&
@@ -536,15 +536,15 @@ int etm_perf_add_symlink_sink(struct coresight_device *csdev)
if (!etm_perf_up)
return -EPROBE_DEFER;
- ea = devm_kzalloc(pdev, sizeof(*ea), GFP_KERNEL);
+ ea = devm_kzalloc(dev, sizeof(*ea), GFP_KERNEL);
if (!ea)
return -ENOMEM;
- name = dev_name(pdev);
+ name = dev_name(dev);
/* See function coresight_get_sink_by_id() to know where this is used */
hash = hashlen_hash(hashlen_string(NULL, name));
- ea->attr.attr.name = devm_kstrdup(pdev, name, GFP_KERNEL);
+ ea->attr.attr.name = devm_kstrdup(dev, name, GFP_KERNEL);
if (!ea->attr.attr.name)
return -ENOMEM;
diff --git a/drivers/hwtracing/coresight/coresight-etm.h b/drivers/hwtracing/coresight/coresight-etm.h
index 79e1ad860d8a..f3ab96eaf44e 100644
--- a/drivers/hwtracing/coresight/coresight-etm.h
+++ b/drivers/hwtracing/coresight/coresight-etm.h
@@ -208,7 +208,6 @@ struct etm_config {
/**
* struct etm_drvdata - specifics associated to an ETM component
* @base: memory mapped base address for this component.
- * @dev: the device entity associated to this component.
* @atclk: optional clock for the core parts of the ETM.
* @csdev: component vitals needed by the framework.
* @spinlock: only one at a time pls.
@@ -232,7 +231,6 @@ struct etm_config {
*/
struct etm_drvdata {
void __iomem *base;
- struct device *dev;
struct clk *atclk;
struct coresight_device *csdev;
spinlock_t spinlock;
@@ -260,7 +258,7 @@ static inline void etm_writel(struct etm_drvdata *drvdata,
{
if (drvdata->use_cp14) {
if (etm_writel_cp14(off, val)) {
- dev_err(drvdata->dev,
+ dev_err(&drvdata->csdev->dev,
"invalid CP14 access to ETM reg: %#x", off);
}
} else {
@@ -274,7 +272,7 @@ static inline unsigned int etm_readl(struct etm_drvdata *drvdata, u32 off)
if (drvdata->use_cp14) {
if (etm_readl_cp14(off, &val)) {
- dev_err(drvdata->dev,
+ dev_err(&drvdata->csdev->dev,
"invalid CP14 access to ETM reg: %#x", off);
}
} else {
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
index 75487b3fad86..e8c7649f123e 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
@@ -48,7 +48,7 @@ static ssize_t etmsr_show(struct device *dev,
unsigned long flags, val;
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
- pm_runtime_get_sync(drvdata->dev);
+ pm_runtime_get_sync(dev->parent);
spin_lock_irqsave(&drvdata->spinlock, flags);
CS_UNLOCK(drvdata->base);
@@ -56,7 +56,7 @@ static ssize_t etmsr_show(struct device *dev,
CS_LOCK(drvdata->base);
spin_unlock_irqrestore(&drvdata->spinlock, flags);
- pm_runtime_put(drvdata->dev);
+ pm_runtime_put(dev->parent);
return sprintf(buf, "%#lx\n", val);
}
@@ -131,7 +131,7 @@ static ssize_t mode_store(struct device *dev,
if (config->mode & ETM_MODE_STALL) {
if (!(drvdata->etmccr & ETMCCR_FIFOFULL)) {
- dev_warn(drvdata->dev, "stall mode not supported\n");
+ dev_warn(dev, "stall mode not supported\n");
ret = -EINVAL;
goto err_unlock;
}
@@ -141,7 +141,7 @@ static ssize_t mode_store(struct device *dev,
if (config->mode & ETM_MODE_TIMESTAMP) {
if (!(drvdata->etmccer & ETMCCER_TIMESTAMP)) {
- dev_warn(drvdata->dev, "timestamp not supported\n");
+ dev_warn(dev, "timestamp not supported\n");
ret = -EINVAL;
goto err_unlock;
}
@@ -945,7 +945,7 @@ static ssize_t seq_curr_state_show(struct device *dev,
goto out;
}
- pm_runtime_get_sync(drvdata->dev);
+ pm_runtime_get_sync(dev->parent);
spin_lock_irqsave(&drvdata->spinlock, flags);
CS_UNLOCK(drvdata->base);
@@ -953,7 +953,7 @@ static ssize_t seq_curr_state_show(struct device *dev,
CS_LOCK(drvdata->base);
spin_unlock_irqrestore(&drvdata->spinlock, flags);
- pm_runtime_put(drvdata->dev);
+ pm_runtime_put(dev->parent);
out:
return sprintf(buf, "%#lx\n", val);
}
diff --git a/drivers/hwtracing/coresight/coresight-etm3x.c b/drivers/hwtracing/coresight/coresight-etm3x.c
index be302ec5f66b..e2cb6873c3f2 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x.c
@@ -165,7 +165,7 @@ static void etm_set_prog(struct etm_drvdata *drvdata)
*/
isb();
if (coresight_timeout_etm(drvdata, ETMSR, ETMSR_PROG_BIT, 1)) {
- dev_err(drvdata->dev,
+ dev_err(&drvdata->csdev->dev,
"%s: timeout observed when probing at offset %#x\n",
__func__, ETMSR);
}
@@ -184,7 +184,7 @@ static void etm_clr_prog(struct etm_drvdata *drvdata)
*/
isb();
if (coresight_timeout_etm(drvdata, ETMSR, ETMSR_PROG_BIT, 0)) {
- dev_err(drvdata->dev,
+ dev_err(&drvdata->csdev->dev,
"%s: timeout observed when probing at offset %#x\n",
__func__, ETMSR);
}
@@ -425,7 +425,7 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
done:
CS_LOCK(drvdata->base);
- dev_dbg(drvdata->dev, "cpu: %d enable smp call done: %d\n",
+ dev_dbg(&drvdata->csdev->dev, "cpu: %d enable smp call done: %d\n",
drvdata->cpu, rc);
return rc;
}
@@ -455,14 +455,16 @@ int etm_get_trace_id(struct etm_drvdata *drvdata)
{
unsigned long flags;
int trace_id = -1;
+ struct device *etm_dev;
if (!drvdata)
goto out;
+ etm_dev = drvdata->csdev->dev.parent;
if (!local_read(&drvdata->mode))
return drvdata->traceid;
- pm_runtime_get_sync(drvdata->dev);
+ pm_runtime_get_sync(etm_dev);
spin_lock_irqsave(&drvdata->spinlock, flags);
@@ -471,7 +473,7 @@ int etm_get_trace_id(struct etm_drvdata *drvdata)
CS_LOCK(drvdata->base);
spin_unlock_irqrestore(&drvdata->spinlock, flags);
- pm_runtime_put(drvdata->dev);
+ pm_runtime_put(etm_dev);
out:
return trace_id;
@@ -526,7 +528,7 @@ static int etm_enable_sysfs(struct coresight_device *csdev)
spin_unlock(&drvdata->spinlock);
if (!ret)
- dev_dbg(drvdata->dev, "ETM tracing enabled\n");
+ dev_dbg(&csdev->dev, "ETM tracing enabled\n");
return ret;
}
@@ -581,7 +583,8 @@ static void etm_disable_hw(void *info)
CS_LOCK(drvdata->base);
- dev_dbg(drvdata->dev, "cpu: %d disable smp call done\n", drvdata->cpu);
+ dev_dbg(&drvdata->csdev->dev,
+ "cpu: %d disable smp call done\n", drvdata->cpu);
}
static void etm_disable_perf(struct coresight_device *csdev)
@@ -628,7 +631,7 @@ static void etm_disable_sysfs(struct coresight_device *csdev)
spin_unlock(&drvdata->spinlock);
cpus_read_unlock();
- dev_dbg(drvdata->dev, "ETM tracing disabled\n");
+ dev_dbg(&csdev->dev, "ETM tracing disabled\n");
}
static void etm_disable(struct coresight_device *csdev,
@@ -788,22 +791,12 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
struct etm_drvdata *drvdata;
struct resource *res = &adev->res;
struct coresight_desc desc = { 0 };
- struct device_node *np = adev->dev.of_node;
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
- if (np) {
- pdata = of_get_coresight_platform_data(dev, np);
- if (IS_ERR(pdata))
- return PTR_ERR(pdata);
-
- adev->dev.platform_data = pdata;
- drvdata->use_cp14 = of_property_read_bool(np, "arm,cp14");
- }
-
- drvdata->dev = &adev->dev;
+ drvdata->use_cp14 = fwnode_property_read_bool(dev->fwnode, "arm,cp14");
dev_set_drvdata(dev, drvdata);
/* Validity for the resource is already checked by the AMBA core */
@@ -822,7 +815,13 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
return ret;
}
- drvdata->cpu = pdata ? pdata->cpu : 0;
+ drvdata->cpu = coresight_get_cpu(dev);
+ if (drvdata->cpu < 0)
+ return drvdata->cpu;
+
+ desc.name = devm_kasprintf(dev, GFP_KERNEL, "etm%d", drvdata->cpu);
+ if (!desc.name)
+ return -ENOMEM;
cpus_read_lock();
etmdrvdata[drvdata->cpu] = drvdata;
@@ -852,6 +851,13 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
etm_init_trace_id(drvdata);
etm_set_default(&drvdata->config);
+ pdata = coresight_get_platform_data(dev);
+ if (IS_ERR(pdata)) {
+ ret = PTR_ERR(pdata);
+ goto err_arch_supported;
+ }
+ adev->dev.platform_data = pdata;
+
desc.type = CORESIGHT_DEV_TYPE_SOURCE;
desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
desc.ops = &etm_cs_ops;
@@ -871,7 +877,8 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
}
pm_runtime_put(&adev->dev);
- dev_info(dev, "%s initialized\n", (char *)coresight_get_uci_data(id));
+ dev_info(&drvdata->csdev->dev,
+ "%s initialized\n", (char *)coresight_get_uci_data(id));
if (boot_enable) {
coresight_enable(drvdata->csdev);
drvdata->boot_enable = true;
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
index 8bb0092c7ec2..7bcac8896fc1 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x.c
@@ -88,6 +88,7 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
{
int i, rc;
struct etmv4_config *config = &drvdata->config;
+ struct device *etm_dev = &drvdata->csdev->dev;
CS_UNLOCK(drvdata->base);
@@ -102,7 +103,7 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
/* wait for TRCSTATR.IDLE to go up */
if (coresight_timeout(drvdata->base, TRCSTATR, TRCSTATR_IDLE_BIT, 1))
- dev_err(drvdata->dev,
+ dev_err(etm_dev,
"timeout while waiting for Idle Trace Status\n");
writel_relaxed(config->pe_sel, drvdata->base + TRCPROCSELR);
@@ -184,13 +185,13 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
/* wait for TRCSTATR.IDLE to go back down to '0' */
if (coresight_timeout(drvdata->base, TRCSTATR, TRCSTATR_IDLE_BIT, 0))
- dev_err(drvdata->dev,
+ dev_err(etm_dev,
"timeout while waiting for Idle Trace Status\n");
done:
CS_LOCK(drvdata->base);
- dev_dbg(drvdata->dev, "cpu: %d enable smp call done: %d\n",
+ dev_dbg(etm_dev, "cpu: %d enable smp call done: %d\n",
drvdata->cpu, rc);
return rc;
}
@@ -400,7 +401,7 @@ static int etm4_enable_sysfs(struct coresight_device *csdev)
spin_unlock(&drvdata->spinlock);
if (!ret)
- dev_dbg(drvdata->dev, "ETM tracing enabled\n");
+ dev_dbg(&csdev->dev, "ETM tracing enabled\n");
return ret;
}
@@ -461,7 +462,8 @@ static void etm4_disable_hw(void *info)
CS_LOCK(drvdata->base);
- dev_dbg(drvdata->dev, "cpu: %d disable smp call done\n", drvdata->cpu);
+ dev_dbg(&drvdata->csdev->dev,
+ "cpu: %d disable smp call done\n", drvdata->cpu);
}
static int etm4_disable_perf(struct coresight_device *csdev,
@@ -511,7 +513,7 @@ static void etm4_disable_sysfs(struct coresight_device *csdev)
spin_unlock(&drvdata->spinlock);
cpus_read_unlock();
- dev_dbg(drvdata->dev, "ETM tracing disabled\n");
+ dev_dbg(&csdev->dev, "ETM tracing disabled\n");
}
static void etm4_disable(struct coresight_device *csdev,
@@ -1082,20 +1084,11 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
struct etmv4_drvdata *drvdata;
struct resource *res = &adev->res;
struct coresight_desc desc = { 0 };
- struct device_node *np = adev->dev.of_node;
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
- if (np) {
- pdata = of_get_coresight_platform_data(dev, np);
- if (IS_ERR(pdata))
- return PTR_ERR(pdata);
- adev->dev.platform_data = pdata;
- }
-
- drvdata->dev = &adev->dev;
dev_set_drvdata(dev, drvdata);
/* Validity for the resource is already checked by the AMBA core */
@@ -1107,7 +1100,13 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
spin_lock_init(&drvdata->spinlock);
- drvdata->cpu = pdata ? pdata->cpu : 0;
+ drvdata->cpu = coresight_get_cpu(dev);
+ if (drvdata->cpu < 0)
+ return drvdata->cpu;
+
+ desc.name = devm_kasprintf(dev, GFP_KERNEL, "etm%d", drvdata->cpu);
+ if (!desc.name)
+ return -ENOMEM;
cpus_read_lock();
etmdrvdata[drvdata->cpu] = drvdata;
@@ -1138,6 +1137,13 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
etm4_init_trace_id(drvdata);
etm4_set_default(&drvdata->config);
+ pdata = coresight_get_platform_data(dev);
+ if (IS_ERR(pdata)) {
+ ret = PTR_ERR(pdata);
+ goto err_arch_supported;
+ }
+ adev->dev.platform_data = pdata;
+
desc.type = CORESIGHT_DEV_TYPE_SOURCE;
desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
desc.ops = &etm4_cs_ops;
@@ -1157,7 +1163,7 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
}
pm_runtime_put(&adev->dev);
- dev_info(dev, "CPU%d: ETM v%d.%d initialized\n",
+ dev_info(&drvdata->csdev->dev, "CPU%d: ETM v%d.%d initialized\n",
drvdata->cpu, drvdata->arch >> 4, drvdata->arch & 0xf);
if (boot_enable) {
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
index 52786e9d8926..4523f10ddd0f 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.h
+++ b/drivers/hwtracing/coresight/coresight-etm4x.h
@@ -284,7 +284,6 @@ struct etmv4_config {
/**
* struct etm4_drvdata - specifics associated to an ETM component
* @base: Memory mapped base address for this component.
- * @dev: The device entity associated to this component.
* @csdev: Component vitals needed by the framework.
* @spinlock: Only one at a time pls.
* @mode: This tracer's mode, i.e sysFS, Perf or disabled.
@@ -340,7 +339,6 @@ struct etmv4_config {
*/
struct etmv4_drvdata {
void __iomem *base;
- struct device *dev;
struct coresight_device *csdev;
spinlock_t spinlock;
local_t mode;
diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c
index 16b0c0e1e43a..fa97cb9ab4f9 100644
--- a/drivers/hwtracing/coresight/coresight-funnel.c
+++ b/drivers/hwtracing/coresight/coresight-funnel.c
@@ -29,17 +29,17 @@
#define FUNNEL_HOLDTIME (0x7 << FUNNEL_HOLDTIME_SHFT)
#define FUNNEL_ENSx_MASK 0xff
+DEFINE_CORESIGHT_DEVLIST(funnel_devs, "funnel");
+
/**
* struct funnel_drvdata - specifics associated to a funnel component
* @base: memory mapped base address for this component.
- * @dev: the device entity associated to this component.
* @atclk: optional clock for the core parts of the funnel.
* @csdev: component vitals needed by the framework.
* @priority: port selection order.
*/
struct funnel_drvdata {
void __iomem *base;
- struct device *dev;
struct clk *atclk;
struct coresight_device *csdev;
unsigned long priority;
@@ -80,7 +80,7 @@ static int funnel_enable(struct coresight_device *csdev, int inport,
rc = dynamic_funnel_enable_hw(drvdata, inport);
if (!rc)
- dev_dbg(drvdata->dev, "FUNNEL inport %d enabled\n", inport);
+ dev_dbg(&csdev->dev, "FUNNEL inport %d enabled\n", inport);
return rc;
}
@@ -110,7 +110,7 @@ static void funnel_disable(struct coresight_device *csdev, int inport,
if (drvdata->base)
dynamic_funnel_disable_hw(drvdata, inport);
- dev_dbg(drvdata->dev, "FUNNEL inport %d disabled\n", inport);
+ dev_dbg(&csdev->dev, "FUNNEL inport %d disabled\n", inport);
}
static const struct coresight_ops_link funnel_link_ops = {
@@ -165,11 +165,11 @@ static ssize_t funnel_ctrl_show(struct device *dev,
u32 val;
struct funnel_drvdata *drvdata = dev_get_drvdata(dev->parent);
- pm_runtime_get_sync(drvdata->dev);
+ pm_runtime_get_sync(dev->parent);
val = get_funnel_ctrl_hw(drvdata);
- pm_runtime_put(drvdata->dev);
+ pm_runtime_put(dev->parent);
return sprintf(buf, "%#x\n", val);
}
@@ -189,23 +189,19 @@ static int funnel_probe(struct device *dev, struct resource *res)
struct coresight_platform_data *pdata = NULL;
struct funnel_drvdata *drvdata;
struct coresight_desc desc = { 0 };
- struct device_node *np = dev->of_node;
-
- if (np) {
- pdata = of_get_coresight_platform_data(dev, np);
- if (IS_ERR(pdata))
- return PTR_ERR(pdata);
- dev->platform_data = pdata;
- }
- if (of_device_is_compatible(np, "arm,coresight-funnel"))
+ if (is_of_node(dev_fwnode(dev)) &&
+ of_device_is_compatible(dev->of_node, "arm,coresight-funnel"))
pr_warn_once("Uses OBSOLETE CoreSight funnel binding\n");
+ desc.name = coresight_alloc_device_name(&funnel_devs, dev);
+ if (!desc.name)
+ return -ENOMEM;
+
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
- drvdata->dev = dev;
drvdata->atclk = devm_clk_get(dev, "atclk"); /* optional */
if (!IS_ERR(drvdata->atclk)) {
ret = clk_prepare_enable(drvdata->atclk);
@@ -229,6 +225,13 @@ static int funnel_probe(struct device *dev, struct resource *res)
dev_set_drvdata(dev, drvdata);
+ pdata = coresight_get_platform_data(dev);
+ if (IS_ERR(pdata)) {
+ ret = PTR_ERR(pdata);
+ goto out_disable_clk;
+ }
+ dev->platform_data = pdata;
+
desc.type = CORESIGHT_DEV_TYPE_LINK;
desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_MERG;
desc.ops = &funnel_cs_ops;
@@ -241,6 +244,7 @@ static int funnel_probe(struct device *dev, struct resource *res)
}
pm_runtime_put(dev);
+ ret = 0;
out_disable_clk:
if (ret && !IS_ERR_OR_NULL(drvdata->atclk))
diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c
new file mode 100644
index 000000000000..dad7d96c5943
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-platform.c
@@ -0,0 +1,815 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/acpi.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_graph.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/amba/bus.h>
+#include <linux/coresight.h>
+#include <linux/cpumask.h>
+#include <asm/smp_plat.h>
+
+#include "coresight-priv.h"
+/*
+ * coresight_alloc_conns: Allocate connections record for each output
+ * port from the device.
+ */
+static int coresight_alloc_conns(struct device *dev,
+ struct coresight_platform_data *pdata)
+{
+ if (pdata->nr_outport) {
+ pdata->conns = devm_kzalloc(dev, pdata->nr_outport *
+ sizeof(*pdata->conns),
+ GFP_KERNEL);
+ if (!pdata->conns)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+int coresight_device_fwnode_match(struct device *dev, const void *fwnode)
+{
+ return dev_fwnode(dev) == fwnode;
+}
+
+static struct device *
+coresight_find_device_by_fwnode(struct fwnode_handle *fwnode)
+{
+ struct device *dev = NULL;
+
+ /*
+ * If we have a non-configurable replicator, it will be found on the
+ * platform bus.
+ */
+ dev = bus_find_device(&platform_bus_type, NULL,
+ fwnode, coresight_device_fwnode_match);
+ if (dev)
+ return dev;
+
+ /*
+ * We have a configurable component - circle through the AMBA bus
+ * looking for the device that matches the endpoint node.
+ */
+ return bus_find_device(&amba_bustype, NULL,
+ fwnode, coresight_device_fwnode_match);
+}
+
+#ifdef CONFIG_OF
+static inline bool of_coresight_legacy_ep_is_input(struct device_node *ep)
+{
+ return of_property_read_bool(ep, "slave-mode");
+}
+
+static void of_coresight_get_ports_legacy(const struct device_node *node,
+ int *nr_inport, int *nr_outport)
+{
+ struct device_node *ep = NULL;
+ int in = 0, out = 0;
+
+ do {
+ ep = of_graph_get_next_endpoint(node, ep);
+ if (!ep)
+ break;
+
+ if (of_coresight_legacy_ep_is_input(ep))
+ in++;
+ else
+ out++;
+
+ } while (ep);
+
+ *nr_inport = in;
+ *nr_outport = out;
+}
+
+static struct device_node *of_coresight_get_port_parent(struct device_node *ep)
+{
+ struct device_node *parent = of_graph_get_port_parent(ep);
+
+ /*
+ * Skip one-level up to the real device node, if we
+ * are using the new bindings.
+ */
+ if (of_node_name_eq(parent, "in-ports") ||
+ of_node_name_eq(parent, "out-ports"))
+ parent = of_get_next_parent(parent);
+
+ return parent;
+}
+
+static inline struct device_node *
+of_coresight_get_input_ports_node(const struct device_node *node)
+{
+ return of_get_child_by_name(node, "in-ports");
+}
+
+static inline struct device_node *
+of_coresight_get_output_ports_node(const struct device_node *node)
+{
+ return of_get_child_by_name(node, "out-ports");
+}
+
+static inline int
+of_coresight_count_ports(struct device_node *port_parent)
+{
+ int i = 0;
+ struct device_node *ep = NULL;
+
+ while ((ep = of_graph_get_next_endpoint(port_parent, ep)))
+ i++;
+ return i;
+}
+
+static void of_coresight_get_ports(const struct device_node *node,
+ int *nr_inport, int *nr_outport)
+{
+ struct device_node *input_ports = NULL, *output_ports = NULL;
+
+ input_ports = of_coresight_get_input_ports_node(node);
+ output_ports = of_coresight_get_output_ports_node(node);
+
+ if (input_ports || output_ports) {
+ if (input_ports) {
+ *nr_inport = of_coresight_count_ports(input_ports);
+ of_node_put(input_ports);
+ }
+ if (output_ports) {
+ *nr_outport = of_coresight_count_ports(output_ports);
+ of_node_put(output_ports);
+ }
+ } else {
+ /* Fall back to legacy DT bindings parsing */
+ of_coresight_get_ports_legacy(node, nr_inport, nr_outport);
+ }
+}
+
+static int of_coresight_get_cpu(struct device *dev)
+{
+ int cpu;
+ struct device_node *dn;
+
+ if (!dev->of_node)
+ return -ENODEV;
+
+ dn = of_parse_phandle(dev->of_node, "cpu", 0);
+ if (!dn)
+ return -ENODEV;
+
+ cpu = of_cpu_node_to_id(dn);
+ of_node_put(dn);
+
+ return cpu;
+}
+
+/*
+ * of_coresight_parse_endpoint : Parse the given output endpoint @ep
+ * and fill the connection information in @conn
+ *
+ * Parses the local port, remote device name and the remote port.
+ *
+ * Returns :
+ * 1 - If the parsing is successful and a connection record
+ * was created for an output connection.
+ * 0 - If the parsing completed without any fatal errors.
+ * -Errno - Fatal error, abort the scanning.
+ */
+static int of_coresight_parse_endpoint(struct device *dev,
+ struct device_node *ep,
+ struct coresight_connection *conn)
+{
+ int ret = 0;
+ struct of_endpoint endpoint, rendpoint;
+ struct device_node *rparent = NULL;
+ struct device_node *rep = NULL;
+ struct device *rdev = NULL;
+ struct fwnode_handle *rdev_fwnode;
+
+ do {
+ /* Parse the local port details */
+ if (of_graph_parse_endpoint(ep, &endpoint))
+ break;
+ /*
+ * Get a handle on the remote endpoint and the device it is
+ * attached to.
+ */
+ rep = of_graph_get_remote_endpoint(ep);
+ if (!rep)
+ break;
+ rparent = of_coresight_get_port_parent(rep);
+ if (!rparent)
+ break;
+ if (of_graph_parse_endpoint(rep, &rendpoint))
+ break;
+
+ rdev_fwnode = of_fwnode_handle(rparent);
+ /* If the remote device is not available, defer probing */
+ rdev = coresight_find_device_by_fwnode(rdev_fwnode);
+ if (!rdev) {
+ ret = -EPROBE_DEFER;
+ break;
+ }
+
+ conn->outport = endpoint.port;
+ /*
+ * Hold the refcount to the target device. This could be
+ * released via:
+ * 1) coresight_release_platform_data() if the probe fails or
+ * this device is unregistered.
+ * 2) While removing the target device via
+ * coresight_remove_match()
+ */
+ conn->child_fwnode = fwnode_handle_get(rdev_fwnode);
+ conn->child_port = rendpoint.port;
+ /* Connection record updated */
+ ret = 1;
+ } while (0);
+
+ of_node_put(rparent);
+ of_node_put(rep);
+ put_device(rdev);
+
+ return ret;
+}
+
+static int of_get_coresight_platform_data(struct device *dev,
+ struct coresight_platform_data *pdata)
+{
+ int ret = 0;
+ struct coresight_connection *conn;
+ struct device_node *ep = NULL;
+ const struct device_node *parent = NULL;
+ bool legacy_binding = false;
+ struct device_node *node = dev->of_node;
+
+ /* Get the number of input and output port for this component */
+ of_coresight_get_ports(node, &pdata->nr_inport, &pdata->nr_outport);
+
+ /* If there are no output connections, we are done */
+ if (!pdata->nr_outport)
+ return 0;
+
+ ret = coresight_alloc_conns(dev, pdata);
+ if (ret)
+ return ret;
+
+ parent = of_coresight_get_output_ports_node(node);
+ /*
+ * If the DT uses obsoleted bindings, the ports are listed
+ * under the device and we need to filter out the input
+ * ports.
+ */
+ if (!parent) {
+ legacy_binding = true;
+ parent = node;
+ dev_warn_once(dev, "Uses obsolete Coresight DT bindings\n");
+ }
+
+ conn = pdata->conns;
+
+ /* Iterate through each output port to discover topology */
+ while ((ep = of_graph_get_next_endpoint(parent, ep))) {
+ /*
+ * Legacy binding mixes input/output ports under the
+ * same parent. So, skip the input ports if we are dealing
+ * with legacy binding, as they processed with their
+ * connected output ports.
+ */
+ if (legacy_binding && of_coresight_legacy_ep_is_input(ep))
+ continue;
+
+ ret = of_coresight_parse_endpoint(dev, ep, conn);
+ switch (ret) {
+ case 1:
+ conn++; /* Fall through */
+ case 0:
+ break;
+ default:
+ return ret;
+ }
+ }
+
+ return 0;
+}
+#else
+static inline int
+of_get_coresight_platform_data(struct device *dev,
+ struct coresight_platform_data *pdata)
+{
+ return -ENOENT;
+}
+
+static inline int of_coresight_get_cpu(struct device *dev)
+{
+ return -ENODEV;
+}
+#endif
+
+#ifdef CONFIG_ACPI
+
+#include <acpi/actypes.h>
+#include <acpi/processor.h>
+
+/* ACPI Graph _DSD UUID : "ab02a46b-74c7-45a2-bd68-f7d344ef2153" */
+static const guid_t acpi_graph_uuid = GUID_INIT(0xab02a46b, 0x74c7, 0x45a2,
+ 0xbd, 0x68, 0xf7, 0xd3,
+ 0x44, 0xef, 0x21, 0x53);
+/* Coresight ACPI Graph UUID : "3ecbc8b6-1d0e-4fb3-8107-e627f805c6cd" */
+static const guid_t coresight_graph_uuid = GUID_INIT(0x3ecbc8b6, 0x1d0e, 0x4fb3,
+ 0x81, 0x07, 0xe6, 0x27,
+ 0xf8, 0x05, 0xc6, 0xcd);
+#define ACPI_CORESIGHT_LINK_SLAVE 0
+#define ACPI_CORESIGHT_LINK_MASTER 1
+
+static inline bool is_acpi_guid(const union acpi_object *obj)
+{
+ return (obj->type == ACPI_TYPE_BUFFER) && (obj->buffer.length == 16);
+}
+
+/*
+ * acpi_guid_matches - Checks if the given object is a GUID object and
+ * that it matches the supplied the GUID.
+ */
+static inline bool acpi_guid_matches(const union acpi_object *obj,
+ const guid_t *guid)
+{
+ return is_acpi_guid(obj) &&
+ guid_equal((guid_t *)obj->buffer.pointer, guid);
+}
+
+static inline bool is_acpi_dsd_graph_guid(const union acpi_object *obj)
+{
+ return acpi_guid_matches(obj, &acpi_graph_uuid);
+}
+
+static inline bool is_acpi_coresight_graph_guid(const union acpi_object *obj)
+{
+ return acpi_guid_matches(obj, &coresight_graph_uuid);
+}
+
+static inline bool is_acpi_coresight_graph(const union acpi_object *obj)
+{
+ const union acpi_object *graphid, *guid, *links;
+
+ if (obj->type != ACPI_TYPE_PACKAGE ||
+ obj->package.count < 3)
+ return false;
+
+ graphid = &obj->package.elements[0];
+ guid = &obj->package.elements[1];
+ links = &obj->package.elements[2];
+
+ if (graphid->type != ACPI_TYPE_INTEGER ||
+ links->type != ACPI_TYPE_INTEGER)
+ return false;
+
+ return is_acpi_coresight_graph_guid(guid);
+}
+
+/*
+ * acpi_validate_dsd_graph - Make sure the given _DSD graph conforms
+ * to the ACPI _DSD Graph specification.
+ *
+ * ACPI Devices Graph property has the following format:
+ * {
+ * Revision - Integer, must be 0
+ * NumberOfGraphs - Integer, N indicating the following list.
+ * Graph[1],
+ * ...
+ * Graph[N]
+ * }
+ *
+ * And each Graph entry has the following format:
+ * {
+ * GraphID - Integer, identifying a graph the device belongs to.
+ * UUID - UUID identifying the specification that governs
+ * this graph. (e.g, see is_acpi_coresight_graph())
+ * NumberOfLinks - Number "N" of connections on this node of the graph.
+ * Links[1]
+ * ...
+ * Links[N]
+ * }
+ *
+ * Where each "Links" entry has the following format:
+ *
+ * {
+ * SourcePortAddress - Integer
+ * DestinationPortAddress - Integer
+ * DestinationDeviceName - Reference to another device
+ * ( --- CoreSight specific extensions below ---)
+ * DirectionOfFlow - Integer 1 for output(master)
+ * 0 for input(slave)
+ * }
+ *
+ * e.g:
+ * For a Funnel device
+ *
+ * Device(MFUN) {
+ * ...
+ *
+ * Name (_DSD, Package() {
+ * // DSD Package contains tuples of { Proeprty_Type_UUID, Package() }
+ * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), //Std. Property UUID
+ * Package() {
+ * Package(2) { "property-name", <property-value> }
+ * },
+ *
+ * ToUUID("ab02a46b-74c7-45a2-bd68-f7d344ef2153"), // ACPI Graph UUID
+ * Package() {
+ * 0, // Revision
+ * 1, // NumberOfGraphs.
+ * Package() { // Graph[0] Package
+ * 1, // GraphID
+ * // Coresight Graph UUID
+ * ToUUID("3ecbc8b6-1d0e-4fb3-8107-e627f805c6cd"),
+ * 3, // NumberOfLinks aka ports
+ * // Link[0]: Output_0 -> Replicator:Input_0
+ * Package () { 0, 0, \_SB_.RPL0, 1 },
+ * // Link[1]: Input_0 <- Cluster0_Funnel0:Output_0
+ * Package () { 0, 0, \_SB_.CLU0.FUN0, 0 },
+ * // Link[2]: Input_1 <- Cluster1_Funnel0:Output_0
+ * Package () { 1, 0, \_SB_.CLU1.FUN0, 0 },
+ * } // End of Graph[0] Package
+ *
+ * }, // End of ACPI Graph Property
+ * })
+ */
+static inline bool acpi_validate_dsd_graph(const union acpi_object *graph)
+{
+ int i, n;
+ const union acpi_object *rev, *nr_graphs;
+
+ /* The graph must contain at least the Revision and Number of Graphs */
+ if (graph->package.count < 2)
+ return false;
+
+ rev = &graph->package.elements[0];
+ nr_graphs = &graph->package.elements[1];
+
+ if (rev->type != ACPI_TYPE_INTEGER ||
+ nr_graphs->type != ACPI_TYPE_INTEGER)
+ return false;
+
+ /* We only support revision 0 */
+ if (rev->integer.value != 0)
+ return false;
+
+ n = nr_graphs->integer.value;
+ /* CoreSight devices are only part of a single Graph */
+ if (n != 1)
+ return false;
+
+ /* Make sure the ACPI graph package has right number of elements */
+ if (graph->package.count != (n + 2))
+ return false;
+
+ /*
+ * Each entry must be a graph package with at least 3 members :
+ * { GraphID, UUID, NumberOfLinks(n), Links[.],... }
+ */
+ for (i = 2; i < n + 2; i++) {
+ const union acpi_object *obj = &graph->package.elements[i];
+
+ if (obj->type != ACPI_TYPE_PACKAGE ||
+ obj->package.count < 3)
+ return false;
+ }
+
+ return true;
+}
+
+/* acpi_get_dsd_graph - Find the _DSD Graph property for the given device. */
+const union acpi_object *
+acpi_get_dsd_graph(struct acpi_device *adev)
+{
+ int i;
+ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+ acpi_status status;
+ const union acpi_object *dsd;
+
+ status = acpi_evaluate_object_typed(adev->handle, "_DSD", NULL,
+ &buf, ACPI_TYPE_PACKAGE);
+ if (ACPI_FAILURE(status))
+ return NULL;
+
+ dsd = buf.pointer;
+
+ /*
+ * _DSD property consists tuples { Prop_UUID, Package() }
+ * Iterate through all the packages and find the Graph.
+ */
+ for (i = 0; i + 1 < dsd->package.count; i += 2) {
+ const union acpi_object *guid, *package;
+
+ guid = &dsd->package.elements[i];
+ package = &dsd->package.elements[i + 1];
+
+ /* All _DSD elements must have a UUID and a Package */
+ if (!is_acpi_guid(guid) || package->type != ACPI_TYPE_PACKAGE)
+ break;
+ /* Skip the non-Graph _DSD packages */
+ if (!is_acpi_dsd_graph_guid(guid))
+ continue;
+ if (acpi_validate_dsd_graph(package))
+ return package;
+ /* Invalid graph format, continue */
+ dev_warn(&adev->dev, "Invalid Graph _DSD property\n");
+ }
+
+ return NULL;
+}
+
+static inline bool
+acpi_validate_coresight_graph(const union acpi_object *cs_graph)
+{
+ int nlinks;
+
+ nlinks = cs_graph->package.elements[2].integer.value;
+ /*
+ * Graph must have the following fields :
+ * { GraphID, GraphUUID, NumberOfLinks, Links... }
+ */
+ if (cs_graph->package.count != (nlinks + 3))
+ return false;
+ /* The links are validated in acpi_coresight_parse_link() */
+ return true;
+}
+
+/*
+ * acpi_get_coresight_graph - Parse the device _DSD tables and find
+ * the Graph property matching the CoreSight Graphs.
+ *
+ * Returns the pointer to the CoreSight Graph Package when found. Otherwise
+ * returns NULL.
+ */
+const union acpi_object *
+acpi_get_coresight_graph(struct acpi_device *adev)
+{
+ const union acpi_object *graph_list, *graph;
+ int i, nr_graphs;
+
+ graph_list = acpi_get_dsd_graph(adev);
+ if (!graph_list)
+ return graph_list;
+
+ nr_graphs = graph_list->package.elements[1].integer.value;
+
+ for (i = 2; i < nr_graphs + 2; i++) {
+ graph = &graph_list->package.elements[i];
+ if (!is_acpi_coresight_graph(graph))
+ continue;
+ if (acpi_validate_coresight_graph(graph))
+ return graph;
+ /* Invalid graph format */
+ break;
+ }
+
+ return NULL;
+}
+
+/*
+ * acpi_coresight_parse_link - Parse the given Graph connection
+ * of the device and populate the coresight_connection for an output
+ * connection.
+ *
+ * CoreSight Graph specification mandates that the direction of the data
+ * flow must be specified in the link. i.e,
+ *
+ * SourcePortAddress, // Integer
+ * DestinationPortAddress, // Integer
+ * DestinationDeviceName, // Reference to another device
+ * DirectionOfFlow, // 1 for output(master), 0 for input(slave)
+ *
+ * Returns the direction of the data flow [ Input(slave) or Output(master) ]
+ * upon success.
+ * Returns an negative error number otherwise.
+ */
+static int acpi_coresight_parse_link(struct acpi_device *adev,
+ const union acpi_object *link,
+ struct coresight_connection *conn)
+{
+ int rc, dir;
+ const union acpi_object *fields;
+ struct acpi_device *r_adev;
+ struct device *rdev;
+
+ if (link->type != ACPI_TYPE_PACKAGE ||
+ link->package.count != 4)
+ return -EINVAL;
+
+ fields = link->package.elements;
+
+ if (fields[0].type != ACPI_TYPE_INTEGER ||
+ fields[1].type != ACPI_TYPE_INTEGER ||
+ fields[2].type != ACPI_TYPE_LOCAL_REFERENCE ||
+ fields[3].type != ACPI_TYPE_INTEGER)
+ return -EINVAL;
+
+ rc = acpi_bus_get_device(fields[2].reference.handle, &r_adev);
+ if (rc)
+ return rc;
+
+ dir = fields[3].integer.value;
+ if (dir == ACPI_CORESIGHT_LINK_MASTER) {
+ conn->outport = fields[0].integer.value;
+ conn->child_port = fields[1].integer.value;
+ rdev = coresight_find_device_by_fwnode(&r_adev->fwnode);
+ if (!rdev)
+ return -EPROBE_DEFER;
+ /*
+ * Hold the refcount to the target device. This could be
+ * released via:
+ * 1) coresight_release_platform_data() if the probe fails or
+ * this device is unregistered.
+ * 2) While removing the target device via
+ * coresight_remove_match().
+ */
+ conn->child_fwnode = fwnode_handle_get(&r_adev->fwnode);
+ }
+
+ return dir;
+}
+
+/*
+ * acpi_coresight_parse_graph - Parse the _DSD CoreSight graph
+ * connection information and populate the supplied coresight_platform_data
+ * instance.
+ */
+static int acpi_coresight_parse_graph(struct acpi_device *adev,
+ struct coresight_platform_data *pdata)
+{
+ int rc, i, nlinks;
+ const union acpi_object *graph;
+ struct coresight_connection *conns, *ptr;
+
+ pdata->nr_inport = pdata->nr_outport = 0;
+ graph = acpi_get_coresight_graph(adev);
+ if (!graph)
+ return -ENOENT;
+
+ nlinks = graph->package.elements[2].integer.value;
+ if (!nlinks)
+ return 0;
+
+ /*
+ * To avoid scanning the table twice (once for finding the number of
+ * output links and then later for parsing the output links),
+ * cache the links information in one go and then later copy
+ * it to the pdata.
+ */
+ conns = devm_kcalloc(&adev->dev, nlinks, sizeof(*conns), GFP_KERNEL);
+ if (!conns)
+ return -ENOMEM;
+ ptr = conns;
+ for (i = 0; i < nlinks; i++) {
+ const union acpi_object *link = &graph->package.elements[3 + i];
+ int dir;
+
+ dir = acpi_coresight_parse_link(adev, link, ptr);
+ if (dir < 0)
+ return dir;
+
+ if (dir == ACPI_CORESIGHT_LINK_MASTER) {
+ pdata->nr_outport++;
+ ptr++;
+ } else {
+ pdata->nr_inport++;
+ }
+ }
+
+ rc = coresight_alloc_conns(&adev->dev, pdata);
+ if (rc)
+ return rc;
+
+ /* Copy the connection information to the final location */
+ for (i = 0; i < pdata->nr_outport; i++)
+ pdata->conns[i] = conns[i];
+
+ devm_kfree(&adev->dev, conns);
+ return 0;
+}
+
+/*
+ * acpi_handle_to_logical_cpuid - Map a given acpi_handle to the
+ * logical CPU id of the corresponding CPU device.
+ *
+ * Returns the logical CPU id when found. Otherwise returns >= nr_cpus_id.
+ */
+static int
+acpi_handle_to_logical_cpuid(acpi_handle handle)
+{
+ int i;
+ struct acpi_processor *pr;
+
+ for_each_possible_cpu(i) {
+ pr = per_cpu(processors, i);
+ if (pr && pr->handle == handle)
+ break;
+ }
+
+ return i;
+}
+
+/*
+ * acpi_coresigh_get_cpu - Find the logical CPU id of the CPU associated
+ * with this coresight device. With ACPI bindings, the CoreSight components
+ * are listed as child device of the associated CPU.
+ *
+ * Returns the logical CPU id when found. Otherwise returns 0.
+ */
+static int acpi_coresight_get_cpu(struct device *dev)
+{
+ int cpu;
+ acpi_handle cpu_handle;
+ acpi_status status;
+ struct acpi_device *adev = ACPI_COMPANION(dev);
+
+ if (!adev)
+ return -ENODEV;
+ status = acpi_get_parent(adev->handle, &cpu_handle);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ cpu = acpi_handle_to_logical_cpuid(cpu_handle);
+ if (cpu >= nr_cpu_ids)
+ return -ENODEV;
+ return cpu;
+}
+
+static int
+acpi_get_coresight_platform_data(struct device *dev,
+ struct coresight_platform_data *pdata)
+{
+ struct acpi_device *adev;
+
+ adev = ACPI_COMPANION(dev);
+ if (!adev)
+ return -EINVAL;
+
+ return acpi_coresight_parse_graph(adev, pdata);
+}
+
+#else
+
+static inline int
+acpi_get_coresight_platform_data(struct device *dev,
+ struct coresight_platform_data *pdata)
+{
+ return -ENOENT;
+}
+
+static inline int acpi_coresight_get_cpu(struct device *dev)
+{
+ return -ENODEV;
+}
+#endif
+
+int coresight_get_cpu(struct device *dev)
+{
+ if (is_of_node(dev->fwnode))
+ return of_coresight_get_cpu(dev);
+ else if (is_acpi_device_node(dev->fwnode))
+ return acpi_coresight_get_cpu(dev);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(coresight_get_cpu);
+
+struct coresight_platform_data *
+coresight_get_platform_data(struct device *dev)
+{
+ int ret = -ENOENT;
+ struct coresight_platform_data *pdata = NULL;
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
+
+ if (IS_ERR_OR_NULL(fwnode))
+ goto error;
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ if (is_of_node(fwnode))
+ ret = of_get_coresight_platform_data(dev, pdata);
+ else if (is_acpi_device_node(fwnode))
+ ret = acpi_get_coresight_platform_data(dev, pdata);
+
+ if (!ret)
+ return pdata;
+error:
+ if (!IS_ERR_OR_NULL(pdata))
+ /* Cleanup the connection information */
+ coresight_release_platform_data(pdata);
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(coresight_get_platform_data);
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
index e0684d06e9ee..7d401790dd7e 100644
--- a/drivers/hwtracing/coresight/coresight-priv.h
+++ b/drivers/hwtracing/coresight/coresight-priv.h
@@ -200,4 +200,8 @@ static inline void *coresight_get_uci_data(const struct amba_id *id)
return 0;
}
+void coresight_release_platform_data(struct coresight_platform_data *pdata);
+
+int coresight_device_fwnode_match(struct device *dev, const void *fwnode);
+
#endif
diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c
index 8c9ce74498e1..b7d6d59d56db 100644
--- a/drivers/hwtracing/coresight/coresight-replicator.c
+++ b/drivers/hwtracing/coresight/coresight-replicator.c
@@ -5,6 +5,7 @@
* Description: CoreSight Replicator driver
*/
+#include <linux/acpi.h>
#include <linux/amba/bus.h>
#include <linux/kernel.h>
#include <linux/device.h>
@@ -22,17 +23,17 @@
#define REPLICATOR_IDFILTER0 0x000
#define REPLICATOR_IDFILTER1 0x004
+DEFINE_CORESIGHT_DEVLIST(replicator_devs, "replicator");
+
/**
* struct replicator_drvdata - specifics associated to a replicator component
* @base: memory mapped base address for this component. Also indicates
* whether this one is programmable or not.
- * @dev: the device entity associated with this component
* @atclk: optional clock for the core parts of the replicator.
* @csdev: component vitals needed by the framework
*/
struct replicator_drvdata {
void __iomem *base;
- struct device *dev;
struct clk *atclk;
struct coresight_device *csdev;
};
@@ -100,7 +101,7 @@ static int replicator_enable(struct coresight_device *csdev, int inport,
if (drvdata->base)
rc = dynamic_replicator_enable(drvdata, inport, outport);
if (!rc)
- dev_dbg(drvdata->dev, "REPLICATOR enabled\n");
+ dev_dbg(&csdev->dev, "REPLICATOR enabled\n");
return rc;
}
@@ -139,7 +140,7 @@ static void replicator_disable(struct coresight_device *csdev, int inport,
if (drvdata->base)
dynamic_replicator_disable(drvdata, inport, outport);
- dev_dbg(drvdata->dev, "REPLICATOR disabled\n");
+ dev_dbg(&csdev->dev, "REPLICATOR disabled\n");
}
static const struct coresight_ops_link replicator_link_ops = {
@@ -179,24 +180,20 @@ static int replicator_probe(struct device *dev, struct resource *res)
struct coresight_platform_data *pdata = NULL;
struct replicator_drvdata *drvdata;
struct coresight_desc desc = { 0 };
- struct device_node *np = dev->of_node;
void __iomem *base;
- if (np) {
- pdata = of_get_coresight_platform_data(dev, np);
- if (IS_ERR(pdata))
- return PTR_ERR(pdata);
- dev->platform_data = pdata;
- }
-
- if (of_device_is_compatible(np, "arm,coresight-replicator"))
+ if (is_of_node(dev_fwnode(dev)) &&
+ of_device_is_compatible(dev->of_node, "arm,coresight-replicator"))
pr_warn_once("Uses OBSOLETE CoreSight replicator binding\n");
+ desc.name = coresight_alloc_device_name(&replicator_devs, dev);
+ if (!desc.name)
+ return -ENOMEM;
+
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
- drvdata->dev = dev;
drvdata->atclk = devm_clk_get(dev, "atclk"); /* optional */
if (!IS_ERR(drvdata->atclk)) {
ret = clk_prepare_enable(drvdata->atclk);
@@ -220,11 +217,19 @@ static int replicator_probe(struct device *dev, struct resource *res)
dev_set_drvdata(dev, drvdata);
+ pdata = coresight_get_platform_data(dev);
+ if (IS_ERR(pdata)) {
+ ret = PTR_ERR(pdata);
+ goto out_disable_clk;
+ }
+ dev->platform_data = pdata;
+
desc.type = CORESIGHT_DEV_TYPE_LINK;
desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT;
desc.ops = &replicator_cs_ops;
desc.pdata = dev->platform_data;
desc.dev = dev;
+
drvdata->csdev = coresight_register(&desc);
if (IS_ERR(drvdata->csdev)) {
ret = PTR_ERR(drvdata->csdev);
@@ -292,11 +297,19 @@ static const struct of_device_id static_replicator_match[] = {
{}
};
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id static_replicator_acpi_ids[] = {
+ {"ARMHC985", 0}, /* ARM CoreSight Static Replicator */
+ {}
+};
+#endif
+
static struct platform_driver static_replicator_driver = {
.probe = static_replicator_probe,
.driver = {
.name = "coresight-static-replicator",
- .of_match_table = static_replicator_match,
+ .of_match_table = of_match_ptr(static_replicator_match),
+ .acpi_match_table = ACPI_PTR(static_replicator_acpi_ids),
.pm = &replicator_dev_pm_ops,
.suppress_bind_attrs = true,
},
diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c
index 9f8a844ed7aa..b908ca104645 100644
--- a/drivers/hwtracing/coresight/coresight-stm.c
+++ b/drivers/hwtracing/coresight/coresight-stm.c
@@ -16,6 +16,7 @@
* (C) 2015-2016 Chunyan Zhang <zhang.chunyan@linaro.org>
*/
#include <asm/local.h>
+#include <linux/acpi.h>
#include <linux/amba/bus.h>
#include <linux/bitmap.h>
#include <linux/clk.h>
@@ -107,10 +108,11 @@ struct channel_space {
unsigned long *guaranteed;
};
+DEFINE_CORESIGHT_DEVLIST(stm_devs, "stm");
+
/**
* struct stm_drvdata - specifics associated to an STM component
* @base: memory mapped base address for this component.
- * @dev: the device entity associated to this component.
* @atclk: optional clock for the core parts of the STM.
* @csdev: component vitals needed by the framework.
* @spinlock: only one at a time pls.
@@ -128,7 +130,6 @@ struct channel_space {
*/
struct stm_drvdata {
void __iomem *base;
- struct device *dev;
struct clk *atclk;
struct coresight_device *csdev;
spinlock_t spinlock;
@@ -205,13 +206,13 @@ static int stm_enable(struct coresight_device *csdev,
if (val)
return -EBUSY;
- pm_runtime_get_sync(drvdata->dev);
+ pm_runtime_get_sync(csdev->dev.parent);
spin_lock(&drvdata->spinlock);
stm_enable_hw(drvdata);
spin_unlock(&drvdata->spinlock);
- dev_dbg(drvdata->dev, "STM tracing enabled\n");
+ dev_dbg(&csdev->dev, "STM tracing enabled\n");
return 0;
}
@@ -271,10 +272,10 @@ static void stm_disable(struct coresight_device *csdev,
/* Wait until the engine has completely stopped */
coresight_timeout(drvdata->base, STMTCSR, STMTCSR_BUSY_BIT, 0);
- pm_runtime_put(drvdata->dev);
+ pm_runtime_put(csdev->dev.parent);
local_set(&drvdata->mode, CS_MODE_DISABLED);
- dev_dbg(drvdata->dev, "STM tracing disabled\n");
+ dev_dbg(&csdev->dev, "STM tracing disabled\n");
}
}
@@ -685,14 +686,15 @@ static const struct attribute_group *coresight_stm_groups[] = {
NULL,
};
-static int stm_get_resource_byname(struct device_node *np,
- char *ch_base, struct resource *res)
+#ifdef CONFIG_OF
+static int of_stm_get_stimulus_area(struct device *dev, struct resource *res)
{
const char *name = NULL;
int index = 0, found = 0;
+ struct device_node *np = dev->of_node;
while (!of_property_read_string_index(np, "reg-names", index, &name)) {
- if (strcmp(ch_base, name)) {
+ if (strcmp("stm-stimulus-base", name)) {
index++;
continue;
}
@@ -707,6 +709,70 @@ static int stm_get_resource_byname(struct device_node *np,
return of_address_to_resource(np, index, res);
}
+#else
+static inline int of_stm_get_stimulus_area(struct device *dev,
+ struct resource *res)
+{
+ return -ENOENT;
+}
+#endif
+
+#ifdef CONFIG_ACPI
+static int acpi_stm_get_stimulus_area(struct device *dev, struct resource *res)
+{
+ int rc;
+ bool found_base = false;
+ struct resource_entry *rent;
+ LIST_HEAD(res_list);
+
+ struct acpi_device *adev = ACPI_COMPANION(dev);
+
+ if (!adev)
+ return -ENODEV;
+ rc = acpi_dev_get_resources(adev, &res_list, NULL, NULL);
+ if (rc < 0)
+ return rc;
+
+ /*
+ * The stimulus base for STM device must be listed as the second memory
+ * resource, followed by the programming base address as described in
+ * "Section 2.3 Resources" in ACPI for CoreSightTM 1.0 Platform Design
+ * document (DEN0067).
+ */
+ rc = -ENOENT;
+ list_for_each_entry(rent, &res_list, node) {
+ if (resource_type(rent->res) != IORESOURCE_MEM)
+ continue;
+ if (found_base) {
+ *res = *rent->res;
+ rc = 0;
+ break;
+ }
+
+ found_base = true;
+ }
+
+ acpi_dev_free_resource_list(&res_list);
+ return rc;
+}
+#else
+static inline int acpi_stm_get_stimulus_area(struct device *dev,
+ struct resource *res)
+{
+ return -ENOENT;
+}
+#endif
+
+static int stm_get_stimulus_area(struct device *dev, struct resource *res)
+{
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
+
+ if (is_of_node(fwnode))
+ return of_stm_get_stimulus_area(dev, res);
+ else if (is_acpi_node(fwnode))
+ return acpi_stm_get_stimulus_area(dev, res);
+ return -ENOENT;
+}
static u32 stm_fundamental_data_size(struct stm_drvdata *drvdata)
{
@@ -763,9 +829,10 @@ static void stm_init_default_data(struct stm_drvdata *drvdata)
bitmap_clear(drvdata->chs.guaranteed, 0, drvdata->numsp);
}
-static void stm_init_generic_data(struct stm_drvdata *drvdata)
+static void stm_init_generic_data(struct stm_drvdata *drvdata,
+ const char *name)
{
- drvdata->stm.name = dev_name(drvdata->dev);
+ drvdata->stm.name = name;
/*
* MasterIDs are assigned at HW design phase. As such the core is
@@ -795,19 +862,15 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id)
struct resource ch_res;
size_t bitmap_size;
struct coresight_desc desc = { 0 };
- struct device_node *np = adev->dev.of_node;
- if (np) {
- pdata = of_get_coresight_platform_data(dev, np);
- if (IS_ERR(pdata))
- return PTR_ERR(pdata);
- adev->dev.platform_data = pdata;
- }
+ desc.name = coresight_alloc_device_name(&stm_devs, dev);
+ if (!desc.name)
+ return -ENOMEM;
+
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
- drvdata->dev = &adev->dev;
drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */
if (!IS_ERR(drvdata->atclk)) {
ret = clk_prepare_enable(drvdata->atclk);
@@ -821,7 +884,7 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id)
return PTR_ERR(base);
drvdata->base = base;
- ret = stm_get_resource_byname(np, "stm-stimulus-base", &ch_res);
+ ret = stm_get_stimulus_area(dev, &ch_res);
if (ret)
return ret;
drvdata->chs.phys = ch_res.start;
@@ -848,14 +911,22 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id)
spin_lock_init(&drvdata->spinlock);
stm_init_default_data(drvdata);
- stm_init_generic_data(drvdata);
+ stm_init_generic_data(drvdata, desc.name);
if (stm_register_device(dev, &drvdata->stm, THIS_MODULE)) {
dev_info(dev,
- "stm_register_device failed, probing deferred\n");
+ "%s : stm_register_device failed, probing deferred\n",
+ desc.name);
return -EPROBE_DEFER;
}
+ pdata = coresight_get_platform_data(dev);
+ if (IS_ERR(pdata)) {
+ ret = PTR_ERR(pdata);
+ goto stm_unregister;
+ }
+ adev->dev.platform_data = pdata;
+
desc.type = CORESIGHT_DEV_TYPE_SOURCE;
desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE;
desc.ops = &stm_cs_ops;
@@ -870,7 +941,8 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id)
pm_runtime_put(&adev->dev);
- dev_info(dev, "%s initialized\n", (char *)coresight_get_uci_data(id));
+ dev_info(&drvdata->csdev->dev, "%s initialized\n",
+ (char *)coresight_get_uci_data(id));
return 0;
stm_unregister:
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index 2527b5d3b65e..23b7ff00af5c 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -280,7 +280,6 @@ static int tmc_enable_etf_sink(struct coresight_device *csdev,
u32 mode, void *data)
{
int ret;
- struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
switch (mode) {
case CS_MODE_SYSFS:
@@ -298,7 +297,7 @@ static int tmc_enable_etf_sink(struct coresight_device *csdev,
if (ret)
return ret;
- dev_dbg(drvdata->dev, "TMC-ETB/ETF enabled\n");
+ dev_dbg(&csdev->dev, "TMC-ETB/ETF enabled\n");
return 0;
}
@@ -328,7 +327,7 @@ static int tmc_disable_etf_sink(struct coresight_device *csdev)
spin_unlock_irqrestore(&drvdata->spinlock, flags);
- dev_dbg(drvdata->dev, "TMC-ETB/ETF disabled\n");
+ dev_dbg(&csdev->dev, "TMC-ETB/ETF disabled\n");
return 0;
}
@@ -351,7 +350,7 @@ static int tmc_enable_etf_link(struct coresight_device *csdev,
spin_unlock_irqrestore(&drvdata->spinlock, flags);
if (!ret)
- dev_dbg(drvdata->dev, "TMC-ETF enabled\n");
+ dev_dbg(&csdev->dev, "TMC-ETF enabled\n");
return ret;
}
@@ -371,19 +370,17 @@ static void tmc_disable_etf_link(struct coresight_device *csdev,
drvdata->mode = CS_MODE_DISABLED;
spin_unlock_irqrestore(&drvdata->spinlock, flags);
- dev_dbg(drvdata->dev, "TMC-ETF disabled\n");
+ dev_dbg(&csdev->dev, "TMC-ETF disabled\n");
}
static void *tmc_alloc_etf_buffer(struct coresight_device *csdev,
struct perf_event *event, void **pages,
int nr_pages, bool overwrite)
{
- int node, cpu = event->cpu;
+ int node;
struct cs_buffers *buf;
- if (cpu == -1)
- cpu = smp_processor_id();
- node = cpu_to_node(cpu);
+ node = (event->cpu == -1) ? NUMA_NO_NODE : cpu_to_node(event->cpu);
/* Allocate memory structure for interaction with Perf */
buf = kzalloc_node(sizeof(struct cs_buffers), GFP_KERNEL, node);
@@ -477,9 +474,11 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev,
/*
* The TMC RAM buffer may be bigger than the space available in the
* perf ring buffer (handle->size). If so advance the RRP so that we
- * get the latest trace data.
+ * get the latest trace data. In snapshot mode none of that matters
+ * since we are expected to clobber stale data in favour of the latest
+ * traces.
*/
- if (to_read > handle->size) {
+ if (!buf->snapshot && to_read > handle->size) {
u32 mask = 0;
/*
@@ -516,7 +515,13 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev,
lost = true;
}
- if (lost)
+ /*
+ * Don't set the TRUNCATED flag in snapshot mode because 1) the
+ * captured buffer is expected to be truncated and 2) a full buffer
+ * prevents the event from being re-enabled by the perf core,
+ * resulting in stale data being send to user space.
+ */
+ if (!buf->snapshot && lost)
perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED);
cur = buf->cur;
@@ -542,11 +547,15 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev,
}
}
- /* In snapshot mode we have to update the head */
- if (buf->snapshot) {
- handle->head = (cur * PAGE_SIZE) + offset;
- to_read = buf->nr_pages << PAGE_SHIFT;
- }
+ /*
+ * In snapshot mode we simply increment the head by the number of byte
+ * that were written. User space function cs_etm_find_snapshot() will
+ * figure out how many bytes to get from the AUX buffer based on the
+ * position of the head.
+ */
+ if (buf->snapshot)
+ handle->head += to_read;
+
CS_LOCK(drvdata->base);
out:
spin_unlock_irqrestore(&drvdata->spinlock, flags);
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index df6e4b0b84e9..17006705287a 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -162,10 +162,11 @@ static void tmc_pages_free(struct tmc_pages *tmc_pages,
struct device *dev, enum dma_data_direction dir)
{
int i;
+ struct device *real_dev = dev->parent;
for (i = 0; i < tmc_pages->nr_pages; i++) {
if (tmc_pages->daddrs && tmc_pages->daddrs[i])
- dma_unmap_page(dev, tmc_pages->daddrs[i],
+ dma_unmap_page(real_dev, tmc_pages->daddrs[i],
PAGE_SIZE, dir);
if (tmc_pages->pages && tmc_pages->pages[i])
__free_page(tmc_pages->pages[i]);
@@ -193,6 +194,7 @@ static int tmc_pages_alloc(struct tmc_pages *tmc_pages,
int i, nr_pages;
dma_addr_t paddr;
struct page *page;
+ struct device *real_dev = dev->parent;
nr_pages = tmc_pages->nr_pages;
tmc_pages->daddrs = kcalloc(nr_pages, sizeof(*tmc_pages->daddrs),
@@ -216,8 +218,8 @@ static int tmc_pages_alloc(struct tmc_pages *tmc_pages,
page = alloc_pages_node(node,
GFP_KERNEL | __GFP_ZERO, 0);
}
- paddr = dma_map_page(dev, page, 0, PAGE_SIZE, dir);
- if (dma_mapping_error(dev, paddr))
+ paddr = dma_map_page(real_dev, page, 0, PAGE_SIZE, dir);
+ if (dma_mapping_error(real_dev, paddr))
goto err;
tmc_pages->daddrs[i] = paddr;
tmc_pages->pages[i] = page;
@@ -304,7 +306,7 @@ static int tmc_alloc_data_pages(struct tmc_sg_table *sg_table, void **pages)
* and data buffers. TMC writes to the data buffers and reads from the SG
* Table pages.
*
- * @dev - Device to which page should be DMA mapped.
+ * @dev - Coresight device to which page should be DMA mapped.
* @node - Numa node for mem allocations
* @nr_tpages - Number of pages for the table entries.
* @nr_dpages - Number of pages for Data buffer.
@@ -348,13 +350,13 @@ void tmc_sg_table_sync_data_range(struct tmc_sg_table *table,
{
int i, index, start;
int npages = DIV_ROUND_UP(size, PAGE_SIZE);
- struct device *dev = table->dev;
+ struct device *real_dev = table->dev->parent;
struct tmc_pages *data = &table->data_pages;
start = offset >> PAGE_SHIFT;
for (i = start; i < (start + npages); i++) {
index = i % data->nr_pages;
- dma_sync_single_for_cpu(dev, data->daddrs[index],
+ dma_sync_single_for_cpu(real_dev, data->daddrs[index],
PAGE_SIZE, DMA_FROM_DEVICE);
}
}
@@ -363,11 +365,11 @@ void tmc_sg_table_sync_data_range(struct tmc_sg_table *table,
void tmc_sg_table_sync_table(struct tmc_sg_table *sg_table)
{
int i;
- struct device *dev = sg_table->dev;
+ struct device *real_dev = sg_table->dev->parent;
struct tmc_pages *table_pages = &sg_table->table_pages;
for (i = 0; i < table_pages->nr_pages; i++)
- dma_sync_single_for_device(dev, table_pages->daddrs[i],
+ dma_sync_single_for_device(real_dev, table_pages->daddrs[i],
PAGE_SIZE, DMA_TO_DEVICE);
}
@@ -590,6 +592,7 @@ static int tmc_etr_alloc_flat_buf(struct tmc_drvdata *drvdata,
void **pages)
{
struct etr_flat_buf *flat_buf;
+ struct device *real_dev = drvdata->csdev->dev.parent;
/* We cannot reuse existing pages for flat buf */
if (pages)
@@ -599,7 +602,7 @@ static int tmc_etr_alloc_flat_buf(struct tmc_drvdata *drvdata,
if (!flat_buf)
return -ENOMEM;
- flat_buf->vaddr = dma_alloc_coherent(drvdata->dev, etr_buf->size,
+ flat_buf->vaddr = dma_alloc_coherent(real_dev, etr_buf->size,
&flat_buf->daddr, GFP_KERNEL);
if (!flat_buf->vaddr) {
kfree(flat_buf);
@@ -607,7 +610,7 @@ static int tmc_etr_alloc_flat_buf(struct tmc_drvdata *drvdata,
}
flat_buf->size = etr_buf->size;
- flat_buf->dev = drvdata->dev;
+ flat_buf->dev = &drvdata->csdev->dev;
etr_buf->hwaddr = flat_buf->daddr;
etr_buf->mode = ETR_MODE_FLAT;
etr_buf->private = flat_buf;
@@ -618,9 +621,12 @@ static void tmc_etr_free_flat_buf(struct etr_buf *etr_buf)
{
struct etr_flat_buf *flat_buf = etr_buf->private;
- if (flat_buf && flat_buf->daddr)
- dma_free_coherent(flat_buf->dev, flat_buf->size,
+ if (flat_buf && flat_buf->daddr) {
+ struct device *real_dev = flat_buf->dev->parent;
+
+ dma_free_coherent(real_dev, flat_buf->size,
flat_buf->vaddr, flat_buf->daddr);
+ }
kfree(flat_buf);
}
@@ -666,8 +672,9 @@ static int tmc_etr_alloc_sg_buf(struct tmc_drvdata *drvdata,
void **pages)
{
struct etr_sg_table *etr_table;
+ struct device *dev = &drvdata->csdev->dev;
- etr_table = tmc_init_etr_sg_table(drvdata->dev, node,
+ etr_table = tmc_init_etr_sg_table(dev, node,
etr_buf->size, pages);
if (IS_ERR(etr_table))
return -ENOMEM;
@@ -751,8 +758,8 @@ tmc_etr_get_catu_device(struct tmc_drvdata *drvdata)
if (!IS_ENABLED(CONFIG_CORESIGHT_CATU))
return NULL;
- for (i = 0; i < etr->nr_outport; i++) {
- tmp = etr->conns[i].child_dev;
+ for (i = 0; i < etr->pdata->nr_outport; i++) {
+ tmp = etr->pdata->conns[i].child_dev;
if (tmp && coresight_is_catu_device(tmp))
return tmp;
}
@@ -823,9 +830,10 @@ static struct etr_buf *tmc_alloc_etr_buf(struct tmc_drvdata *drvdata,
bool has_etr_sg, has_iommu;
bool has_sg, has_catu;
struct etr_buf *etr_buf;
+ struct device *dev = &drvdata->csdev->dev;
has_etr_sg = tmc_etr_has_cap(drvdata, TMC_ETR_SG);
- has_iommu = iommu_get_domain_for_dev(drvdata->dev);
+ has_iommu = iommu_get_domain_for_dev(dev->parent);
has_catu = !!tmc_etr_get_catu_device(drvdata);
has_sg = has_catu || has_etr_sg;
@@ -863,7 +871,7 @@ static struct etr_buf *tmc_alloc_etr_buf(struct tmc_drvdata *drvdata,
return ERR_PTR(rc);
}
- dev_dbg(drvdata->dev, "allocated buffer of size %ldKB in mode %d\n",
+ dev_dbg(dev, "allocated buffer of size %ldKB in mode %d\n",
(unsigned long)size >> 10, etr_buf->mode);
return etr_buf;
}
@@ -1162,7 +1170,7 @@ out:
tmc_etr_free_sysfs_buf(free_buf);
if (!ret)
- dev_dbg(drvdata->dev, "TMC-ETR enabled\n");
+ dev_dbg(&csdev->dev, "TMC-ETR enabled\n");
return ret;
}
@@ -1178,14 +1186,11 @@ static struct etr_buf *
alloc_etr_buf(struct tmc_drvdata *drvdata, struct perf_event *event,
int nr_pages, void **pages, bool snapshot)
{
- int node, cpu = event->cpu;
+ int node;
struct etr_buf *etr_buf;
unsigned long size;
- if (cpu == -1)
- cpu = smp_processor_id();
- node = cpu_to_node(cpu);
-
+ node = (event->cpu == -1) ? NUMA_NO_NODE : cpu_to_node(event->cpu);
/*
* Try to match the perf ring buffer size if it is larger
* than the size requested via sysfs.
@@ -1317,13 +1322,11 @@ static struct etr_perf_buffer *
tmc_etr_setup_perf_buf(struct tmc_drvdata *drvdata, struct perf_event *event,
int nr_pages, void **pages, bool snapshot)
{
- int node, cpu = event->cpu;
+ int node;
struct etr_buf *etr_buf;
struct etr_perf_buffer *etr_perf;
- if (cpu == -1)
- cpu = smp_processor_id();
- node = cpu_to_node(cpu);
+ node = (event->cpu == -1) ? NUMA_NO_NODE : cpu_to_node(event->cpu);
etr_perf = kzalloc_node(sizeof(*etr_perf), GFP_KERNEL, node);
if (!etr_perf)
@@ -1358,7 +1361,7 @@ static void *tmc_alloc_etr_buffer(struct coresight_device *csdev,
etr_perf = tmc_etr_setup_perf_buf(drvdata, event,
nr_pages, pages, snapshot);
if (IS_ERR(etr_perf)) {
- dev_dbg(drvdata->dev, "Unable to allocate ETR buffer\n");
+ dev_dbg(&csdev->dev, "Unable to allocate ETR buffer\n");
return NULL;
}
@@ -1501,18 +1504,23 @@ tmc_update_etr_buffer(struct coresight_device *csdev,
tmc_etr_sync_perf_buffer(etr_perf);
/*
- * Update handle->head in snapshot mode. Also update the size to the
- * hardware buffer size if there was an overflow.
+ * In snapshot mode we simply increment the head by the number of byte
+ * that were written. User space function cs_etm_find_snapshot() will
+ * figure out how many bytes to get from the AUX buffer based on the
+ * position of the head.
*/
- if (etr_perf->snapshot) {
+ if (etr_perf->snapshot)
handle->head += size;
- if (etr_buf->full)
- size = etr_buf->size;
- }
lost |= etr_buf->full;
out:
- if (lost)
+ /*
+ * Don't set the TRUNCATED flag in snapshot mode because 1) the
+ * captured buffer is expected to be truncated and 2) a full buffer
+ * prevents the event from being re-enabled by the perf core,
+ * resulting in stale data being send to user space.
+ */
+ if (!etr_perf->snapshot && lost)
perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED);
return size;
}
@@ -1612,7 +1620,7 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev)
spin_unlock_irqrestore(&drvdata->spinlock, flags);
- dev_dbg(drvdata->dev, "TMC-ETR disabled\n");
+ dev_dbg(&csdev->dev, "TMC-ETR disabled\n");
return 0;
}
diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index 3f718729d741..be37aff573b4 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -27,12 +27,16 @@
#include "coresight-priv.h"
#include "coresight-tmc.h"
+DEFINE_CORESIGHT_DEVLIST(etb_devs, "tmc_etb");
+DEFINE_CORESIGHT_DEVLIST(etf_devs, "tmc_etf");
+DEFINE_CORESIGHT_DEVLIST(etr_devs, "tmc_etr");
+
void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata)
{
/* Ensure formatter, unformatter and hardware fifo are empty */
if (coresight_timeout(drvdata->base,
TMC_STS, TMC_STS_TMCREADY_BIT, 1)) {
- dev_err(drvdata->dev,
+ dev_err(&drvdata->csdev->dev,
"timeout while waiting for TMC to be Ready\n");
}
}
@@ -49,7 +53,7 @@ void tmc_flush_and_stop(struct tmc_drvdata *drvdata)
/* Ensure flush completes */
if (coresight_timeout(drvdata->base,
TMC_FFCR, TMC_FFCR_FLUSHMAN_BIT, 0)) {
- dev_err(drvdata->dev,
+ dev_err(&drvdata->csdev->dev,
"timeout while waiting for completion of Manual Flush\n");
}
@@ -83,7 +87,7 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata)
}
if (!ret)
- dev_dbg(drvdata->dev, "TMC read start\n");
+ dev_dbg(&drvdata->csdev->dev, "TMC read start\n");
return ret;
}
@@ -105,7 +109,7 @@ static int tmc_read_unprepare(struct tmc_drvdata *drvdata)
}
if (!ret)
- dev_dbg(drvdata->dev, "TMC read end\n");
+ dev_dbg(&drvdata->csdev->dev, "TMC read end\n");
return ret;
}
@@ -122,7 +126,7 @@ static int tmc_open(struct inode *inode, struct file *file)
nonseekable_open(inode, file);
- dev_dbg(drvdata->dev, "%s: successfully opened\n", __func__);
+ dev_dbg(&drvdata->csdev->dev, "%s: successfully opened\n", __func__);
return 0;
}
@@ -152,12 +156,13 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len,
return 0;
if (copy_to_user(data, bufp, actual)) {
- dev_dbg(drvdata->dev, "%s: copy_to_user failed\n", __func__);
+ dev_dbg(&drvdata->csdev->dev,
+ "%s: copy_to_user failed\n", __func__);
return -EFAULT;
}
*ppos += actual;
- dev_dbg(drvdata->dev, "%zu bytes copied\n", actual);
+ dev_dbg(&drvdata->csdev->dev, "%zu bytes copied\n", actual);
return actual;
}
@@ -172,7 +177,7 @@ static int tmc_release(struct inode *inode, struct file *file)
if (ret)
return ret;
- dev_dbg(drvdata->dev, "%s: released\n", __func__);
+ dev_dbg(&drvdata->csdev->dev, "%s: released\n", __func__);
return 0;
}
@@ -332,24 +337,22 @@ const struct attribute_group *coresight_tmc_groups[] = {
NULL,
};
-static inline bool tmc_etr_can_use_sg(struct tmc_drvdata *drvdata)
+static inline bool tmc_etr_can_use_sg(struct device *dev)
{
- return fwnode_property_present(drvdata->dev->fwnode,
- "arm,scatter-gather");
+ return fwnode_property_present(dev->fwnode, "arm,scatter-gather");
}
/* Detect and initialise the capabilities of a TMC ETR */
-static int tmc_etr_setup_caps(struct tmc_drvdata *drvdata,
- u32 devid, void *dev_caps)
+static int tmc_etr_setup_caps(struct device *parent, u32 devid, void *dev_caps)
{
int rc;
-
u32 dma_mask = 0;
+ struct tmc_drvdata *drvdata = dev_get_drvdata(parent);
/* Set the unadvertised capabilities */
tmc_etr_init_caps(drvdata, (u32)(unsigned long)dev_caps);
- if (!(devid & TMC_DEVID_NOSCAT) && tmc_etr_can_use_sg(drvdata))
+ if (!(devid & TMC_DEVID_NOSCAT) && tmc_etr_can_use_sg(parent))
tmc_etr_set_cap(drvdata, TMC_ETR_SG);
/* Check if the AXI address width is available */
@@ -367,18 +370,27 @@ static int tmc_etr_setup_caps(struct tmc_drvdata *drvdata,
case 44:
case 48:
case 52:
- dev_info(drvdata->dev, "Detected dma mask %dbits\n", dma_mask);
+ dev_info(parent, "Detected dma mask %dbits\n", dma_mask);
break;
default:
dma_mask = 40;
}
- rc = dma_set_mask_and_coherent(drvdata->dev, DMA_BIT_MASK(dma_mask));
+ rc = dma_set_mask_and_coherent(parent, DMA_BIT_MASK(dma_mask));
if (rc)
- dev_err(drvdata->dev, "Failed to setup DMA mask: %d\n", rc);
+ dev_err(parent, "Failed to setup DMA mask: %d\n", rc);
return rc;
}
+static u32 tmc_etr_get_default_buffer_size(struct device *dev)
+{
+ u32 size;
+
+ if (fwnode_property_read_u32(dev->fwnode, "arm,buffer-size", &size))
+ size = SZ_1M;
+ return size;
+}
+
static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
{
int ret = 0;
@@ -389,23 +401,13 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
struct tmc_drvdata *drvdata;
struct resource *res = &adev->res;
struct coresight_desc desc = { 0 };
- struct device_node *np = adev->dev.of_node;
-
- if (np) {
- pdata = of_get_coresight_platform_data(dev, np);
- if (IS_ERR(pdata)) {
- ret = PTR_ERR(pdata);
- goto out;
- }
- adev->dev.platform_data = pdata;
- }
+ struct coresight_dev_list *dev_list = NULL;
ret = -ENOMEM;
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
goto out;
- drvdata->dev = &adev->dev;
dev_set_drvdata(dev, drvdata);
/* Validity for the resource is already checked by the AMBA core */
@@ -425,18 +427,11 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
/* This device is not associated with a session */
drvdata->pid = -1;
- if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
- if (np)
- ret = of_property_read_u32(np,
- "arm,buffer-size",
- &drvdata->size);
- if (ret)
- drvdata->size = SZ_1M;
- } else {
+ if (drvdata->config_type == TMC_CONFIG_TYPE_ETR)
+ drvdata->size = tmc_etr_get_default_buffer_size(dev);
+ else
drvdata->size = readl_relaxed(drvdata->base + TMC_RSZ) * 4;
- }
- desc.pdata = pdata;
desc.dev = dev;
desc.groups = coresight_tmc_groups;
@@ -445,36 +440,53 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
desc.type = CORESIGHT_DEV_TYPE_SINK;
desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
desc.ops = &tmc_etb_cs_ops;
+ dev_list = &etb_devs;
break;
case TMC_CONFIG_TYPE_ETR:
desc.type = CORESIGHT_DEV_TYPE_SINK;
desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
desc.ops = &tmc_etr_cs_ops;
- ret = tmc_etr_setup_caps(drvdata, devid,
+ ret = tmc_etr_setup_caps(dev, devid,
coresight_get_uci_data(id));
if (ret)
goto out;
idr_init(&drvdata->idr);
mutex_init(&drvdata->idr_mutex);
+ dev_list = &etr_devs;
break;
case TMC_CONFIG_TYPE_ETF:
desc.type = CORESIGHT_DEV_TYPE_LINKSINK;
desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_FIFO;
desc.ops = &tmc_etf_cs_ops;
+ dev_list = &etf_devs;
break;
default:
- pr_err("%s: Unsupported TMC config\n", pdata->name);
+ pr_err("%s: Unsupported TMC config\n", desc.name);
ret = -EINVAL;
goto out;
}
+ desc.name = coresight_alloc_device_name(dev_list, dev);
+ if (!desc.name) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ pdata = coresight_get_platform_data(dev);
+ if (IS_ERR(pdata)) {
+ ret = PTR_ERR(pdata);
+ goto out;
+ }
+ adev->dev.platform_data = pdata;
+ desc.pdata = pdata;
+
drvdata->csdev = coresight_register(&desc);
if (IS_ERR(drvdata->csdev)) {
ret = PTR_ERR(drvdata->csdev);
goto out;
}
- drvdata->miscdev.name = pdata->name;
+ drvdata->miscdev.name = desc.name;
drvdata->miscdev.minor = MISC_DYNAMIC_MINOR;
drvdata->miscdev.fops = &tmc_fops;
ret = misc_register(&drvdata->miscdev);
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 503f1b3a3741..1ed50411cc3c 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -161,7 +161,6 @@ struct etr_buf {
/**
* struct tmc_drvdata - specifics associated to an TMC component
* @base: memory mapped base address for this component.
- * @dev: the device entity associated to this component.
* @csdev: component vitals needed by the framework.
* @miscdev: specifics to handle "/dev/xyz.tmc" entry.
* @spinlock: only one at a time pls.
@@ -184,7 +183,6 @@ struct etr_buf {
*/
struct tmc_drvdata {
void __iomem *base;
- struct device *dev;
struct coresight_device *csdev;
struct miscdevice miscdev;
spinlock_t spinlock;
diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c
index 63d9af31f57f..f8583e4032a6 100644
--- a/drivers/hwtracing/coresight/coresight-tpiu.c
+++ b/drivers/hwtracing/coresight/coresight-tpiu.c
@@ -47,15 +47,15 @@
#define FFCR_FON_MAN BIT(6)
#define FFCR_STOP_FI BIT(12)
+DEFINE_CORESIGHT_DEVLIST(tpiu_devs, "tpiu");
+
/**
* @base: memory mapped base address for this component.
- * @dev: the device entity associated to this component.
* @atclk: optional clock for the core parts of the TPIU.
* @csdev: component vitals needed by the framework.
*/
struct tpiu_drvdata {
void __iomem *base;
- struct device *dev;
struct clk *atclk;
struct coresight_device *csdev;
};
@@ -75,7 +75,7 @@ static int tpiu_enable(struct coresight_device *csdev, u32 mode, void *__unused)
tpiu_enable_hw(drvdata);
atomic_inc(csdev->refcnt);
- dev_dbg(drvdata->dev, "TPIU enabled\n");
+ dev_dbg(&csdev->dev, "TPIU enabled\n");
return 0;
}
@@ -104,7 +104,7 @@ static int tpiu_disable(struct coresight_device *csdev)
tpiu_disable_hw(drvdata);
- dev_dbg(drvdata->dev, "TPIU disabled\n");
+ dev_dbg(&csdev->dev, "TPIU disabled\n");
return 0;
}
@@ -126,20 +126,15 @@ static int tpiu_probe(struct amba_device *adev, const struct amba_id *id)
struct tpiu_drvdata *drvdata;
struct resource *res = &adev->res;
struct coresight_desc desc = { 0 };
- struct device_node *np = adev->dev.of_node;
- if (np) {
- pdata = of_get_coresight_platform_data(dev, np);
- if (IS_ERR(pdata))
- return PTR_ERR(pdata);
- adev->dev.platform_data = pdata;
- }
+ desc.name = coresight_alloc_device_name(&tpiu_devs, dev);
+ if (!desc.name)
+ return -ENOMEM;
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
- drvdata->dev = &adev->dev;
drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */
if (!IS_ERR(drvdata->atclk)) {
ret = clk_prepare_enable(drvdata->atclk);
@@ -158,6 +153,11 @@ static int tpiu_probe(struct amba_device *adev, const struct amba_id *id)
/* Disable tpiu to support older devices */
tpiu_disable_hw(drvdata);
+ pdata = coresight_get_platform_data(dev);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+ dev->platform_data = pdata;
+
desc.type = CORESIGHT_DEV_TYPE_SINK;
desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_PORT;
desc.ops = &tpiu_cs_ops;
diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c
index 4b130281236a..55db77f6410b 100644
--- a/drivers/hwtracing/coresight/coresight.c
+++ b/drivers/hwtracing/coresight/coresight.c
@@ -100,8 +100,8 @@ static int coresight_find_link_inport(struct coresight_device *csdev,
int i;
struct coresight_connection *conn;
- for (i = 0; i < parent->nr_outport; i++) {
- conn = &parent->conns[i];
+ for (i = 0; i < parent->pdata->nr_outport; i++) {
+ conn = &parent->pdata->conns[i];
if (conn->child_dev == csdev)
return conn->child_port;
}
@@ -118,8 +118,8 @@ static int coresight_find_link_outport(struct coresight_device *csdev,
int i;
struct coresight_connection *conn;
- for (i = 0; i < csdev->nr_outport; i++) {
- conn = &csdev->conns[i];
+ for (i = 0; i < csdev->pdata->nr_outport; i++) {
+ conn = &csdev->pdata->conns[i];
if (conn->child_dev == child)
return conn->outport;
}
@@ -306,10 +306,10 @@ static void coresight_disable_link(struct coresight_device *csdev,
if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) {
refport = inport;
- nr_conns = csdev->nr_inport;
+ nr_conns = csdev->pdata->nr_inport;
} else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) {
refport = outport;
- nr_conns = csdev->nr_outport;
+ nr_conns = csdev->pdata->nr_outport;
} else {
refport = 0;
nr_conns = 1;
@@ -498,9 +498,9 @@ struct coresight_device *coresight_get_sink(struct list_head *path)
return csdev;
}
-static int coresight_enabled_sink(struct device *dev, void *data)
+static int coresight_enabled_sink(struct device *dev, const void *data)
{
- bool *reset = data;
+ const bool *reset = data;
struct coresight_device *csdev = to_coresight_device(dev);
if ((csdev->type == CORESIGHT_DEV_TYPE_SINK ||
@@ -544,7 +544,7 @@ struct coresight_device *coresight_get_enabled_sink(bool deactivate)
return dev ? to_coresight_device(dev) : NULL;
}
-static int coresight_sink_by_id(struct device *dev, void *data)
+static int coresight_sink_by_id(struct device *dev, const void *data)
{
struct coresight_device *csdev = to_coresight_device(dev);
unsigned long hash;
@@ -595,9 +595,10 @@ static void coresight_grab_device(struct coresight_device *csdev)
{
int i;
- for (i = 0; i < csdev->nr_outport; i++) {
- struct coresight_device *child = csdev->conns[i].child_dev;
+ for (i = 0; i < csdev->pdata->nr_outport; i++) {
+ struct coresight_device *child;
+ child = csdev->pdata->conns[i].child_dev;
if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
pm_runtime_get_sync(child->dev.parent);
}
@@ -613,9 +614,10 @@ static void coresight_drop_device(struct coresight_device *csdev)
int i;
pm_runtime_put(csdev->dev.parent);
- for (i = 0; i < csdev->nr_outport; i++) {
- struct coresight_device *child = csdev->conns[i].child_dev;
+ for (i = 0; i < csdev->pdata->nr_outport; i++) {
+ struct coresight_device *child;
+ child = csdev->pdata->conns[i].child_dev;
if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
pm_runtime_put(child->dev.parent);
}
@@ -645,9 +647,10 @@ static int _coresight_build_path(struct coresight_device *csdev,
goto out;
/* Not a sink - recursively explore each port found on this element */
- for (i = 0; i < csdev->nr_outport; i++) {
- struct coresight_device *child_dev = csdev->conns[i].child_dev;
+ for (i = 0; i < csdev->pdata->nr_outport; i++) {
+ struct coresight_device *child_dev;
+ child_dev = csdev->pdata->conns[i].child_dev;
if (child_dev &&
_coresight_build_path(child_dev, sink, path) == 0) {
found = true;
@@ -975,6 +978,7 @@ static void coresight_device_release(struct device *dev)
{
struct coresight_device *csdev = to_coresight_device(dev);
+ fwnode_handle_put(csdev->dev.fwnode);
kfree(csdev->refcnt);
kfree(csdev);
}
@@ -1000,19 +1004,17 @@ static int coresight_orphan_match(struct device *dev, void *data)
* Circle throuch all the connection of that component. If we find
* an orphan connection whose name matches @csdev, link it.
*/
- for (i = 0; i < i_csdev->nr_outport; i++) {
- conn = &i_csdev->conns[i];
+ for (i = 0; i < i_csdev->pdata->nr_outport; i++) {
+ conn = &i_csdev->pdata->conns[i];
/* We have found at least one orphan connection */
if (conn->child_dev == NULL) {
/* Does it match this newly added device? */
- if (conn->child_name &&
- !strcmp(dev_name(&csdev->dev), conn->child_name)) {
+ if (conn->child_fwnode == csdev->dev.fwnode)
conn->child_dev = csdev;
- } else {
+ else
/* This component still has an orphan */
still_orphan = true;
- }
}
}
@@ -1040,13 +1042,13 @@ static void coresight_fixup_device_conns(struct coresight_device *csdev)
{
int i;
- for (i = 0; i < csdev->nr_outport; i++) {
- struct coresight_connection *conn = &csdev->conns[i];
+ for (i = 0; i < csdev->pdata->nr_outport; i++) {
+ struct coresight_connection *conn = &csdev->pdata->conns[i];
struct device *dev = NULL;
- if (conn->child_name)
- dev = bus_find_device_by_name(&coresight_bustype, NULL,
- conn->child_name);
+ dev = bus_find_device(&coresight_bustype, NULL,
+ (void *)conn->child_fwnode,
+ coresight_device_fwnode_match);
if (dev) {
conn->child_dev = to_coresight_device(dev);
/* and put reference from 'bus_find_device()' */
@@ -1075,15 +1077,21 @@ static int coresight_remove_match(struct device *dev, void *data)
* Circle throuch all the connection of that component. If we find
* a connection whose name matches @csdev, remove it.
*/
- for (i = 0; i < iterator->nr_outport; i++) {
- conn = &iterator->conns[i];
+ for (i = 0; i < iterator->pdata->nr_outport; i++) {
+ conn = &iterator->pdata->conns[i];
if (conn->child_dev == NULL)
continue;
- if (!strcmp(dev_name(&csdev->dev), conn->child_name)) {
+ if (csdev->dev.fwnode == conn->child_fwnode) {
iterator->orphan = true;
conn->child_dev = NULL;
+ /*
+ * Drop the reference to the handle for the remote
+ * device acquired in parsing the connections from
+ * platform data.
+ */
+ fwnode_handle_put(conn->child_fwnode);
/* No need to continue */
break;
}
@@ -1096,10 +1104,21 @@ static int coresight_remove_match(struct device *dev, void *data)
return 0;
}
+/*
+ * coresight_remove_conns - Remove references to this given devices
+ * from the connections of other devices.
+ */
static void coresight_remove_conns(struct coresight_device *csdev)
{
- bus_for_each_dev(&coresight_bustype, NULL,
- csdev, coresight_remove_match);
+ /*
+ * Another device will point to this device only if there is
+ * an output port connected to this one. i.e, if the device
+ * doesn't have at least one input port, there is no point
+ * in searching all the devices.
+ */
+ if (csdev->pdata->nr_inport)
+ bus_for_each_dev(&coresight_bustype, NULL,
+ csdev, coresight_remove_match);
}
/**
@@ -1152,6 +1171,22 @@ static int __init coresight_init(void)
}
postcore_initcall(coresight_init);
+/*
+ * coresight_release_platform_data: Release references to the devices connected
+ * to the output port of this device.
+ */
+void coresight_release_platform_data(struct coresight_platform_data *pdata)
+{
+ int i;
+
+ for (i = 0; i < pdata->nr_outport; i++) {
+ if (pdata->conns[i].child_fwnode) {
+ fwnode_handle_put(pdata->conns[i].child_fwnode);
+ pdata->conns[i].child_fwnode = NULL;
+ }
+ }
+}
+
struct coresight_device *coresight_register(struct coresight_desc *desc)
{
int ret;
@@ -1184,10 +1219,7 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
csdev->refcnt = refcnts;
- csdev->nr_inport = desc->pdata->nr_inport;
- csdev->nr_outport = desc->pdata->nr_outport;
-
- csdev->conns = desc->pdata->conns;
+ csdev->pdata = desc->pdata;
csdev->type = desc->type;
csdev->subtype = desc->subtype;
@@ -1199,7 +1231,12 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
csdev->dev.parent = desc->dev;
csdev->dev.release = coresight_device_release;
csdev->dev.bus = &coresight_bustype;
- dev_set_name(&csdev->dev, "%s", desc->pdata->name);
+ /*
+ * Hold the reference to our parent device. This will be
+ * dropped only in coresight_device_release().
+ */
+ csdev->dev.fwnode = fwnode_handle_get(dev_fwnode(desc->dev));
+ dev_set_name(&csdev->dev, "%s", desc->name);
ret = device_register(&csdev->dev);
if (ret) {
@@ -1239,6 +1276,8 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
err_free_csdev:
kfree(csdev);
err_out:
+ /* Cleanup the connection information */
+ coresight_release_platform_data(desc->pdata);
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(coresight_register);
@@ -1248,6 +1287,65 @@ void coresight_unregister(struct coresight_device *csdev)
etm_perf_del_symlink_sink(csdev);
/* Remove references of that device in the topology */
coresight_remove_conns(csdev);
+ coresight_release_platform_data(csdev->pdata);
device_unregister(&csdev->dev);
}
EXPORT_SYMBOL_GPL(coresight_unregister);
+
+
+/*
+ * coresight_search_device_idx - Search the fwnode handle of a device
+ * in the given dev_idx list. Must be called with the coresight_mutex held.
+ *
+ * Returns the index of the entry, when found. Otherwise, -ENOENT.
+ */
+static inline int coresight_search_device_idx(struct coresight_dev_list *dict,
+ struct fwnode_handle *fwnode)
+{
+ int i;
+
+ for (i = 0; i < dict->nr_idx; i++)
+ if (dict->fwnode_list[i] == fwnode)
+ return i;
+ return -ENOENT;
+}
+
+/*
+ * coresight_alloc_device_name - Get an index for a given device in the
+ * device index list specific to a driver. An index is allocated for a
+ * device and is tracked with the fwnode_handle to prevent allocating
+ * duplicate indices for the same device (e.g, if we defer probing of
+ * a device due to dependencies), in case the index is requested again.
+ */
+char *coresight_alloc_device_name(struct coresight_dev_list *dict,
+ struct device *dev)
+{
+ int idx;
+ char *name = NULL;
+ struct fwnode_handle **list;
+
+ mutex_lock(&coresight_mutex);
+
+ idx = coresight_search_device_idx(dict, dev_fwnode(dev));
+ if (idx < 0) {
+ /* Make space for the new entry */
+ idx = dict->nr_idx;
+ list = krealloc(dict->fwnode_list,
+ (idx + 1) * sizeof(*dict->fwnode_list),
+ GFP_KERNEL);
+ if (ZERO_OR_NULL_PTR(list)) {
+ idx = -ENOMEM;
+ goto done;
+ }
+
+ list[idx] = dev_fwnode(dev);
+ dict->fwnode_list = list;
+ dict->nr_idx = idx + 1;
+ }
+
+ name = devm_kasprintf(dev, GFP_KERNEL, "%s%d", dict->pfx, idx);
+done:
+ mutex_unlock(&coresight_mutex);
+ return name;
+}
+EXPORT_SYMBOL_GPL(coresight_alloc_device_name);
diff --git a/drivers/hwtracing/coresight/of_coresight.c b/drivers/hwtracing/coresight/of_coresight.c
deleted file mode 100644
index 7045930fc958..000000000000
--- a/drivers/hwtracing/coresight/of_coresight.c
+++ /dev/null
@@ -1,297 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
- */
-
-#include <linux/types.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/clk.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_graph.h>
-#include <linux/of_platform.h>
-#include <linux/platform_device.h>
-#include <linux/amba/bus.h>
-#include <linux/coresight.h>
-#include <linux/cpumask.h>
-#include <asm/smp_plat.h>
-
-
-static int of_dev_node_match(struct device *dev, void *data)
-{
- return dev->of_node == data;
-}
-
-static struct device *
-of_coresight_get_endpoint_device(struct device_node *endpoint)
-{
- struct device *dev = NULL;
-
- /*
- * If we have a non-configurable replicator, it will be found on the
- * platform bus.
- */
- dev = bus_find_device(&platform_bus_type, NULL,
- endpoint, of_dev_node_match);
- if (dev)
- return dev;
-
- /*
- * We have a configurable component - circle through the AMBA bus
- * looking for the device that matches the endpoint node.
- */
- return bus_find_device(&amba_bustype, NULL,
- endpoint, of_dev_node_match);
-}
-
-static inline bool of_coresight_legacy_ep_is_input(struct device_node *ep)
-{
- return of_property_read_bool(ep, "slave-mode");
-}
-
-static void of_coresight_get_ports_legacy(const struct device_node *node,
- int *nr_inport, int *nr_outport)
-{
- struct device_node *ep = NULL;
- int in = 0, out = 0;
-
- do {
- ep = of_graph_get_next_endpoint(node, ep);
- if (!ep)
- break;
-
- if (of_coresight_legacy_ep_is_input(ep))
- in++;
- else
- out++;
-
- } while (ep);
-
- *nr_inport = in;
- *nr_outport = out;
-}
-
-static struct device_node *of_coresight_get_port_parent(struct device_node *ep)
-{
- struct device_node *parent = of_graph_get_port_parent(ep);
-
- /*
- * Skip one-level up to the real device node, if we
- * are using the new bindings.
- */
- if (of_node_name_eq(parent, "in-ports") ||
- of_node_name_eq(parent, "out-ports"))
- parent = of_get_next_parent(parent);
-
- return parent;
-}
-
-static inline struct device_node *
-of_coresight_get_input_ports_node(const struct device_node *node)
-{
- return of_get_child_by_name(node, "in-ports");
-}
-
-static inline struct device_node *
-of_coresight_get_output_ports_node(const struct device_node *node)
-{
- return of_get_child_by_name(node, "out-ports");
-}
-
-static inline int
-of_coresight_count_ports(struct device_node *port_parent)
-{
- int i = 0;
- struct device_node *ep = NULL;
-
- while ((ep = of_graph_get_next_endpoint(port_parent, ep)))
- i++;
- return i;
-}
-
-static void of_coresight_get_ports(const struct device_node *node,
- int *nr_inport, int *nr_outport)
-{
- struct device_node *input_ports = NULL, *output_ports = NULL;
-
- input_ports = of_coresight_get_input_ports_node(node);
- output_ports = of_coresight_get_output_ports_node(node);
-
- if (input_ports || output_ports) {
- if (input_ports) {
- *nr_inport = of_coresight_count_ports(input_ports);
- of_node_put(input_ports);
- }
- if (output_ports) {
- *nr_outport = of_coresight_count_ports(output_ports);
- of_node_put(output_ports);
- }
- } else {
- /* Fall back to legacy DT bindings parsing */
- of_coresight_get_ports_legacy(node, nr_inport, nr_outport);
- }
-}
-
-static int of_coresight_alloc_memory(struct device *dev,
- struct coresight_platform_data *pdata)
-{
- if (pdata->nr_outport) {
- pdata->conns = devm_kzalloc(dev, pdata->nr_outport *
- sizeof(*pdata->conns),
- GFP_KERNEL);
- if (!pdata->conns)
- return -ENOMEM;
- }
-
- return 0;
-}
-
-int of_coresight_get_cpu(const struct device_node *node)
-{
- int cpu;
- struct device_node *dn;
-
- dn = of_parse_phandle(node, "cpu", 0);
- /* Affinity defaults to CPU0 */
- if (!dn)
- return 0;
- cpu = of_cpu_node_to_id(dn);
- of_node_put(dn);
-
- /* Affinity to CPU0 if no cpu nodes are found */
- return (cpu < 0) ? 0 : cpu;
-}
-EXPORT_SYMBOL_GPL(of_coresight_get_cpu);
-
-/*
- * of_coresight_parse_endpoint : Parse the given output endpoint @ep
- * and fill the connection information in @conn
- *
- * Parses the local port, remote device name and the remote port.
- *
- * Returns :
- * 1 - If the parsing is successful and a connection record
- * was created for an output connection.
- * 0 - If the parsing completed without any fatal errors.
- * -Errno - Fatal error, abort the scanning.
- */
-static int of_coresight_parse_endpoint(struct device *dev,
- struct device_node *ep,
- struct coresight_connection *conn)
-{
- int ret = 0;
- struct of_endpoint endpoint, rendpoint;
- struct device_node *rparent = NULL;
- struct device_node *rep = NULL;
- struct device *rdev = NULL;
-
- do {
- /* Parse the local port details */
- if (of_graph_parse_endpoint(ep, &endpoint))
- break;
- /*
- * Get a handle on the remote endpoint and the device it is
- * attached to.
- */
- rep = of_graph_get_remote_endpoint(ep);
- if (!rep)
- break;
- rparent = of_coresight_get_port_parent(rep);
- if (!rparent)
- break;
- if (of_graph_parse_endpoint(rep, &rendpoint))
- break;
-
- /* If the remote device is not available, defer probing */
- rdev = of_coresight_get_endpoint_device(rparent);
- if (!rdev) {
- ret = -EPROBE_DEFER;
- break;
- }
-
- conn->outport = endpoint.port;
- conn->child_name = devm_kstrdup(dev,
- dev_name(rdev),
- GFP_KERNEL);
- conn->child_port = rendpoint.port;
- /* Connection record updated */
- ret = 1;
- } while (0);
-
- of_node_put(rparent);
- of_node_put(rep);
- put_device(rdev);
-
- return ret;
-}
-
-struct coresight_platform_data *
-of_get_coresight_platform_data(struct device *dev,
- const struct device_node *node)
-{
- int ret = 0;
- struct coresight_platform_data *pdata;
- struct coresight_connection *conn;
- struct device_node *ep = NULL;
- const struct device_node *parent = NULL;
- bool legacy_binding = false;
-
- pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata)
- return ERR_PTR(-ENOMEM);
-
- /* Use device name as sysfs handle */
- pdata->name = dev_name(dev);
- pdata->cpu = of_coresight_get_cpu(node);
-
- /* Get the number of input and output port for this component */
- of_coresight_get_ports(node, &pdata->nr_inport, &pdata->nr_outport);
-
- /* If there are no output connections, we are done */
- if (!pdata->nr_outport)
- return pdata;
-
- ret = of_coresight_alloc_memory(dev, pdata);
- if (ret)
- return ERR_PTR(ret);
-
- parent = of_coresight_get_output_ports_node(node);
- /*
- * If the DT uses obsoleted bindings, the ports are listed
- * under the device and we need to filter out the input
- * ports.
- */
- if (!parent) {
- legacy_binding = true;
- parent = node;
- dev_warn_once(dev, "Uses obsolete Coresight DT bindings\n");
- }
-
- conn = pdata->conns;
-
- /* Iterate through each output port to discover topology */
- while ((ep = of_graph_get_next_endpoint(parent, ep))) {
- /*
- * Legacy binding mixes input/output ports under the
- * same parent. So, skip the input ports if we are dealing
- * with legacy binding, as they processed with their
- * connected output ports.
- */
- if (legacy_binding && of_coresight_legacy_ep_is_input(ep))
- continue;
-
- ret = of_coresight_parse_endpoint(dev, ep, conn);
- switch (ret) {
- case 1:
- conn++; /* Fall through */
- case 0:
- break;
- default:
- return ERR_PTR(ret);
- }
- }
-
- return pdata;
-}
-EXPORT_SYMBOL_GPL(of_get_coresight_platform_data);
diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c
index 033dce563c99..55922896d862 100644
--- a/drivers/hwtracing/intel_th/core.c
+++ b/drivers/hwtracing/intel_th/core.c
@@ -789,10 +789,9 @@ static int intel_th_populate(struct intel_th *th)
return 0;
}
-static int match_devt(struct device *dev, void *data)
+static int match_devt(struct device *dev, const void *data)
{
- dev_t devt = (dev_t)(unsigned long)data;
-
+ dev_t devt = (dev_t)(unsigned long)(void *)data;
return dev->devt == devt;
}
diff --git a/drivers/hwtracing/intel_th/msu.c b/drivers/hwtracing/intel_th/msu.c
index 81bb54fa3ce8..8ab28e5fb366 100644
--- a/drivers/hwtracing/intel_th/msu.c
+++ b/drivers/hwtracing/intel_th/msu.c
@@ -33,14 +33,18 @@
* @entry: window list linkage (msc::win_list)
* @pgoff: page offset into the buffer that this window starts at
* @nr_blocks: number of blocks (pages) in this window
+ * @nr_segs: number of segments in this window (<= @nr_blocks)
+ * @_sgt: array of block descriptors
* @sgt: array of block descriptors
*/
struct msc_window {
struct list_head entry;
unsigned long pgoff;
unsigned int nr_blocks;
+ unsigned int nr_segs;
struct msc *msc;
- struct sg_table sgt;
+ struct sg_table _sgt;
+ struct sg_table *sgt;
};
/**
@@ -138,13 +142,19 @@ static inline bool msc_block_is_empty(struct msc_block_desc *bdesc)
static inline struct msc_block_desc *
msc_win_block(struct msc_window *win, unsigned int block)
{
- return sg_virt(&win->sgt.sgl[block]);
+ return sg_virt(&win->sgt->sgl[block]);
+}
+
+static inline size_t
+msc_win_actual_bsz(struct msc_window *win, unsigned int block)
+{
+ return win->sgt->sgl[block].length;
}
static inline dma_addr_t
msc_win_baddr(struct msc_window *win, unsigned int block)
{
- return sg_dma_address(&win->sgt.sgl[block]);
+ return sg_dma_address(&win->sgt->sgl[block]);
}
static inline unsigned long
@@ -179,17 +189,18 @@ static struct msc_window *msc_next_window(struct msc_window *win)
}
/**
- * msc_oldest_window() - locate the window with oldest data
+ * msc_find_window() - find a window matching a given sg_table
* @msc: MSC device
+ * @sgt: SG table of the window
+ * @nonempty: skip over empty windows
*
- * This should only be used in multiblock mode. Caller should hold the
- * msc::user_count reference.
- *
- * Return: the oldest window with valid data
+ * Return: MSC window structure pointer or NULL if the window
+ * could not be found.
*/
-static struct msc_window *msc_oldest_window(struct msc *msc)
+static struct msc_window *
+msc_find_window(struct msc *msc, struct sg_table *sgt, bool nonempty)
{
- struct msc_window *win, *next = msc_next_window(msc->cur_win);
+ struct msc_window *win;
unsigned int found = 0;
if (list_empty(&msc->win_list))
@@ -201,17 +212,40 @@ static struct msc_window *msc_oldest_window(struct msc *msc)
* something like 2, in which case we're good
*/
list_for_each_entry(win, &msc->win_list, entry) {
- if (win == next)
+ if (win->sgt == sgt)
found++;
/* skip the empty ones */
- if (msc_block_is_empty(msc_win_block(win, 0)))
+ if (nonempty && msc_block_is_empty(msc_win_block(win, 0)))
continue;
if (found)
return win;
}
+ return NULL;
+}
+
+/**
+ * msc_oldest_window() - locate the window with oldest data
+ * @msc: MSC device
+ *
+ * This should only be used in multiblock mode. Caller should hold the
+ * msc::user_count reference.
+ *
+ * Return: the oldest window with valid data
+ */
+static struct msc_window *msc_oldest_window(struct msc *msc)
+{
+ struct msc_window *win;
+
+ if (list_empty(&msc->win_list))
+ return NULL;
+
+ win = msc_find_window(msc, msc_next_window(msc->cur_win)->sgt, true);
+ if (win)
+ return win;
+
return list_first_entry(&msc->win_list, struct msc_window, entry);
}
@@ -234,7 +268,7 @@ static unsigned int msc_win_oldest_block(struct msc_window *win)
* with wrapping, last written block contains both the newest and the
* oldest data for this window.
*/
- for (blk = 0; blk < win->nr_blocks; blk++) {
+ for (blk = 0; blk < win->nr_segs; blk++) {
bdesc = msc_win_block(win, blk);
if (msc_block_last_written(bdesc))
@@ -366,7 +400,7 @@ static int msc_iter_block_advance(struct msc_iter *iter)
return msc_iter_win_advance(iter);
/* block advance */
- if (++iter->block == iter->win->nr_blocks)
+ if (++iter->block == iter->win->nr_segs)
iter->block = 0;
/* no wrapping, sanity check in case there is no last written block */
@@ -478,7 +512,7 @@ static void msc_buffer_clear_hw_header(struct msc *msc)
size_t hw_sz = sizeof(struct msc_block_desc) -
offsetof(struct msc_block_desc, hw_tag);
- for (blk = 0; blk < win->nr_blocks; blk++) {
+ for (blk = 0; blk < win->nr_segs; blk++) {
struct msc_block_desc *bdesc = msc_win_block(win, blk);
memset(&bdesc->hw_tag, 0, hw_sz);
@@ -667,7 +701,7 @@ static int msc_buffer_contig_alloc(struct msc *msc, unsigned long size)
goto err_out;
ret = -ENOMEM;
- page = alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
+ page = alloc_pages(GFP_KERNEL | __GFP_ZERO | GFP_DMA32, order);
if (!page)
goto err_free_sgt;
@@ -734,17 +768,17 @@ static struct page *msc_buffer_contig_get_page(struct msc *msc,
}
static int __msc_buffer_win_alloc(struct msc_window *win,
- unsigned int nr_blocks)
+ unsigned int nr_segs)
{
struct scatterlist *sg_ptr;
void *block;
int i, ret;
- ret = sg_alloc_table(&win->sgt, nr_blocks, GFP_KERNEL);
+ ret = sg_alloc_table(win->sgt, nr_segs, GFP_KERNEL);
if (ret)
return -ENOMEM;
- for_each_sg(win->sgt.sgl, sg_ptr, nr_blocks, i) {
+ for_each_sg(win->sgt->sgl, sg_ptr, nr_segs, i) {
block = dma_alloc_coherent(msc_dev(win->msc)->parent->parent,
PAGE_SIZE, &sg_dma_address(sg_ptr),
GFP_KERNEL);
@@ -754,7 +788,7 @@ static int __msc_buffer_win_alloc(struct msc_window *win,
sg_set_buf(sg_ptr, block, PAGE_SIZE);
}
- return nr_blocks;
+ return nr_segs;
err_nomem:
for (i--; i >= 0; i--)
@@ -762,11 +796,35 @@ err_nomem:
msc_win_block(win, i),
msc_win_baddr(win, i));
- sg_free_table(&win->sgt);
+ sg_free_table(win->sgt);
return -ENOMEM;
}
+#ifdef CONFIG_X86
+static void msc_buffer_set_uc(struct msc_window *win, unsigned int nr_segs)
+{
+ int i;
+
+ for (i = 0; i < nr_segs; i++)
+ /* Set the page as uncached */
+ set_memory_uc((unsigned long)msc_win_block(win, i), 1);
+}
+
+static void msc_buffer_set_wb(struct msc_window *win)
+{
+ int i;
+
+ for (i = 0; i < win->nr_segs; i++)
+ /* Reset the page to write-back */
+ set_memory_wb((unsigned long)msc_win_block(win, i), 1);
+}
+#else /* !X86 */
+static inline void
+msc_buffer_set_uc(struct msc_window *win, unsigned int nr_segs) {}
+static inline void msc_buffer_set_wb(struct msc_window *win) {}
+#endif /* CONFIG_X86 */
+
/**
* msc_buffer_win_alloc() - alloc a window for a multiblock mode
* @msc: MSC device
@@ -780,7 +838,7 @@ err_nomem:
static int msc_buffer_win_alloc(struct msc *msc, unsigned int nr_blocks)
{
struct msc_window *win;
- int ret = -ENOMEM, i;
+ int ret = -ENOMEM;
if (!nr_blocks)
return 0;
@@ -797,13 +855,13 @@ static int msc_buffer_win_alloc(struct msc *msc, unsigned int nr_blocks)
return -ENOMEM;
win->msc = msc;
+ win->sgt = &win->_sgt;
if (!list_empty(&msc->win_list)) {
struct msc_window *prev = list_last_entry(&msc->win_list,
struct msc_window,
entry);
- /* This works as long as blocks are page-sized */
win->pgoff = prev->pgoff + prev->nr_blocks;
}
@@ -811,13 +869,10 @@ static int msc_buffer_win_alloc(struct msc *msc, unsigned int nr_blocks)
if (ret < 0)
goto err_nomem;
-#ifdef CONFIG_X86
- for (i = 0; i < ret; i++)
- /* Set the page as uncached */
- set_memory_uc((unsigned long)msc_win_block(win, i), 1);
-#endif
+ msc_buffer_set_uc(win, ret);
- win->nr_blocks = ret;
+ win->nr_segs = ret;
+ win->nr_blocks = nr_blocks;
if (list_empty(&msc->win_list)) {
msc->base = msc_win_block(win, 0);
@@ -840,14 +895,14 @@ static void __msc_buffer_win_free(struct msc *msc, struct msc_window *win)
{
int i;
- for (i = 0; i < win->nr_blocks; i++) {
- struct page *page = sg_page(&win->sgt.sgl[i]);
+ for (i = 0; i < win->nr_segs; i++) {
+ struct page *page = sg_page(&win->sgt->sgl[i]);
page->mapping = NULL;
dma_free_coherent(msc_dev(win->msc)->parent->parent, PAGE_SIZE,
msc_win_block(win, i), msc_win_baddr(win, i));
}
- sg_free_table(&win->sgt);
+ sg_free_table(win->sgt);
}
/**
@@ -860,8 +915,6 @@ static void __msc_buffer_win_free(struct msc *msc, struct msc_window *win)
*/
static void msc_buffer_win_free(struct msc *msc, struct msc_window *win)
{
- int i;
-
msc->nr_pages -= win->nr_blocks;
list_del(&win->entry);
@@ -870,11 +923,7 @@ static void msc_buffer_win_free(struct msc *msc, struct msc_window *win)
msc->base_addr = 0;
}
-#ifdef CONFIG_X86
- for (i = 0; i < win->nr_blocks; i++)
- /* Reset the page to write-back */
- set_memory_wb((unsigned long)msc_win_block(win, i), 1);
-#endif
+ msc_buffer_set_wb(win);
__msc_buffer_win_free(msc, win);
@@ -909,7 +958,7 @@ static void msc_buffer_relink(struct msc *msc)
next_win = list_next_entry(win, entry);
}
- for (blk = 0; blk < win->nr_blocks; blk++) {
+ for (blk = 0; blk < win->nr_segs; blk++) {
struct msc_block_desc *bdesc = msc_win_block(win, blk);
memset(bdesc, 0, sizeof(*bdesc));
@@ -920,7 +969,7 @@ static void msc_buffer_relink(struct msc *msc)
* Similarly to last window, last block should point
* to the first one.
*/
- if (blk == win->nr_blocks - 1) {
+ if (blk == win->nr_segs - 1) {
sw_tag |= MSC_SW_TAG_LASTBLK;
bdesc->next_blk = msc_win_bpfn(win, 0);
} else {
@@ -928,7 +977,7 @@ static void msc_buffer_relink(struct msc *msc)
}
bdesc->sw_tag = sw_tag;
- bdesc->block_sz = PAGE_SIZE / 64;
+ bdesc->block_sz = msc_win_actual_bsz(win, blk) / 64;
}
}
@@ -1087,6 +1136,7 @@ static int msc_buffer_free_unless_used(struct msc *msc)
static struct page *msc_buffer_get_page(struct msc *msc, unsigned long pgoff)
{
struct msc_window *win;
+ unsigned int blk;
if (msc->mode == MSC_MODE_SINGLE)
return msc_buffer_contig_get_page(msc, pgoff);
@@ -1099,7 +1149,18 @@ static struct page *msc_buffer_get_page(struct msc *msc, unsigned long pgoff)
found:
pgoff -= win->pgoff;
- return sg_page(&win->sgt.sgl[pgoff]);
+
+ for (blk = 0; blk < win->nr_segs; blk++) {
+ struct page *page = sg_page(&win->sgt->sgl[blk]);
+ size_t pgsz = PFN_DOWN(msc_win_actual_bsz(win, blk));
+
+ if (pgoff < pgsz)
+ return page + pgoff;
+
+ pgoff -= pgsz;
+ }
+
+ return NULL;
}
/**
@@ -1386,10 +1447,9 @@ static int intel_th_msc_init(struct msc *msc)
static void msc_win_switch(struct msc *msc)
{
- struct msc_window *last, *first;
+ struct msc_window *first;
first = list_first_entry(&msc->win_list, struct msc_window, entry);
- last = list_last_entry(&msc->win_list, struct msc_window, entry);
if (msc_is_last_win(msc->cur_win))
msc->cur_win = first;
diff --git a/drivers/hwtracing/intel_th/pci.c b/drivers/hwtracing/intel_th/pci.c
index f1228708f2a2..c0378c3de9a4 100644
--- a/drivers/hwtracing/intel_th/pci.c
+++ b/drivers/hwtracing/intel_th/pci.c
@@ -194,6 +194,11 @@ static const struct pci_device_id intel_th_pci_id_table[] = {
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x02a6),
.driver_data = (kernel_ulong_t)&intel_th_2x,
},
+ {
+ /* Ice Lake NNPI */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x45c5),
+ .driver_data = (kernel_ulong_t)&intel_th_2x,
+ },
{ 0 },
};
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index ee5dfb5aee2a..09367fc014c3 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -143,6 +143,8 @@ config I2C_I801
Cedar Fork (PCH)
Ice Lake (PCH)
Comet Lake (PCH)
+ Elkhart Lake (PCH)
+ Tiger Lake (PCH)
This driver can also be built as a module. If so, the module
will be called i2c-i801.
@@ -436,7 +438,7 @@ config I2C_AXXIA
config I2C_BCM2835
tristate "Broadcom BCM2835 I2C controller"
- depends on ARCH_BCM2835
+ depends on ARCH_BCM2835 || ARCH_BRCMSTB
help
If you say yes to this option, support will be included for the
BCM2835 I2C controller.
@@ -692,7 +694,7 @@ config I2C_IOP3XX
config I2C_JZ4780
tristate "JZ4780 I2C controller interface support"
- depends on MACH_JZ4780 || COMPILE_TEST
+ depends on MIPS || COMPILE_TEST
help
If you say yes to this option, support will be included for the
Ingenic JZ4780 I2C controller.
@@ -746,6 +748,13 @@ config I2C_MT65XX
If you want to use MediaTek(R) I2C interface, say Y or M here.
If unsure, say N.
+config I2C_MT7621
+ tristate "MT7621/MT7628 I2C Controller"
+ depends on (RALINK && (SOC_MT7620 || SOC_MT7621)) || COMPILE_TEST
+ help
+ Say Y here to include support for I2C controller in the
+ MediaTek MT7621/MT7628 SoCs.
+
config I2C_MV64XXX
tristate "Marvell mv64xxx I2C Controller"
depends on MV64X60 || PLAT_ORION || ARCH_SUNXI || ARCH_MVEBU
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index a3245231b0b7..80c23895eaaf 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -77,6 +77,7 @@ obj-$(CONFIG_I2C_LPC2K) += i2c-lpc2k.o
obj-$(CONFIG_I2C_MESON) += i2c-meson.o
obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
obj-$(CONFIG_I2C_MT65XX) += i2c-mt65xx.o
+obj-$(CONFIG_I2C_MT7621) += i2c-mt7621.o
obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
obj-$(CONFIG_I2C_MXS) += i2c-mxs.o
obj-$(CONFIG_I2C_NOMADIK) += i2c-nomadik.o
diff --git a/drivers/i2c/busses/i2c-acorn.c b/drivers/i2c/busses/i2c-acorn.c
index fa3763e4b3ee..34bbbb8c52f6 100644
--- a/drivers/i2c/busses/i2c-acorn.c
+++ b/drivers/i2c/busses/i2c-acorn.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ARM IOC/IOMD i2c driver.
*
* Copyright (C) 2000 Russell King
*
- * 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.
- *
* On Acorn machines, the following i2c devices are on the bus:
* - PCF8583 real time clock & static RAM
*/
diff --git a/drivers/i2c/busses/i2c-amd-mp2-pci.c b/drivers/i2c/busses/i2c-amd-mp2-pci.c
index 455e1f36a2a3..c7fe3b44a860 100644
--- a/drivers/i2c/busses/i2c-amd-mp2-pci.c
+++ b/drivers/i2c/busses/i2c-amd-mp2-pci.c
@@ -457,7 +457,7 @@ static struct pci_driver amd_mp2_pci_driver = {
};
module_pci_driver(amd_mp2_pci_driver);
-static int amd_mp2_device_match(struct device *dev, void *data)
+static int amd_mp2_device_match(struct device *dev, const void *data)
{
return 1;
}
diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
index 6c8b38fd6e64..fa66951b05d0 100644
--- a/drivers/i2c/busses/i2c-aspeed.c
+++ b/drivers/i2c/busses/i2c-aspeed.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Aspeed 24XX/25XX I2C Controller.
*
* Copyright (C) 2012-2017 ASPEED Technology Inc.
* Copyright 2017 IBM Corporation
* Copyright 2017 Google, 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.
*/
#include <linux/clk.h>
diff --git a/drivers/i2c/busses/i2c-axxia.c b/drivers/i2c/busses/i2c-axxia.c
index 1c7b41f45c83..ff3142b15cab 100644
--- a/drivers/i2c/busses/i2c-axxia.c
+++ b/drivers/i2c/busses/i2c-axxia.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* This driver implements I2C master functionality using the LSI API2C
* controller.
@@ -5,10 +6,6 @@
* NOTE: The controller has a limitation in that it can only do transfers of
* maximum 255 bytes at a time. If a larger transfer is attempted, error code
* (-EINVAL) is returned.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
*/
#include <linux/clk.h>
#include <linux/clkdev.h>
diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c
index a845b8decac8..2c7f145a036e 100644
--- a/drivers/i2c/busses/i2c-bcm-iproc.c
+++ b/drivers/i2c/busses/i2c-bcm-iproc.c
@@ -165,12 +165,6 @@ enum i2c_slave_read_status {
I2C_SLAVE_RX_END,
};
-enum i2c_slave_xfer_dir {
- I2C_SLAVE_DIR_READ = 0,
- I2C_SLAVE_DIR_WRITE,
- I2C_SLAVE_DIR_NONE,
-};
-
enum bus_speed_index {
I2C_SPD_100K = 0,
I2C_SPD_400K,
@@ -203,7 +197,6 @@ struct bcm_iproc_i2c_dev {
struct i2c_msg *msg;
struct i2c_client *slave;
- enum i2c_slave_xfer_dir xfer_dir;
/* bytes that have been transferred */
unsigned int tx_bytes;
@@ -219,7 +212,8 @@ struct bcm_iproc_i2c_dev {
| BIT(IS_M_RX_THLD_SHIFT))
#define ISR_MASK_SLAVE (BIT(IS_S_START_BUSY_SHIFT)\
- | BIT(IS_S_RX_EVENT_SHIFT) | BIT(IS_S_RD_EVENT_SHIFT))
+ | BIT(IS_S_RX_EVENT_SHIFT) | BIT(IS_S_RD_EVENT_SHIFT)\
+ | BIT(IS_S_TX_UNDERRUN_SHIFT))
static int bcm_iproc_i2c_reg_slave(struct i2c_client *slave);
static int bcm_iproc_i2c_unreg_slave(struct i2c_client *slave);
@@ -297,15 +291,11 @@ static void bcm_iproc_i2c_slave_init(
/* clear all pending slave interrupts */
iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, ISR_MASK_SLAVE);
- /* Enable interrupt register for any READ event */
- val = BIT(IE_S_RD_EVENT_SHIFT);
/* Enable interrupt register to indicate a valid byte in receive fifo */
- val |= BIT(IE_S_RX_EVENT_SHIFT);
+ val = BIT(IE_S_RX_EVENT_SHIFT);
/* Enable interrupt register for the Slave BUSY command */
val |= BIT(IE_S_START_BUSY_SHIFT);
iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val);
-
- iproc_i2c->xfer_dir = I2C_SLAVE_DIR_NONE;
}
static void bcm_iproc_i2c_check_slave_status(
@@ -314,8 +304,11 @@ static void bcm_iproc_i2c_check_slave_status(
u32 val;
val = iproc_i2c_rd_reg(iproc_i2c, S_CMD_OFFSET);
- val = (val >> S_CMD_STATUS_SHIFT) & S_CMD_STATUS_MASK;
+ /* status is valid only when START_BUSY is cleared after it was set */
+ if (val & BIT(S_CMD_START_BUSY_SHIFT))
+ return;
+ val = (val >> S_CMD_STATUS_SHIFT) & S_CMD_STATUS_MASK;
if (val == S_CMD_STATUS_TIMEOUT) {
dev_err(iproc_i2c->device, "slave random stretch time timeout\n");
@@ -327,70 +320,66 @@ static void bcm_iproc_i2c_check_slave_status(
}
static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c,
- u32 status)
+ u32 status)
{
- u8 value;
u32 val;
- u32 rd_status;
- u32 tmp;
+ u8 value, rx_status;
- /* Start of transaction. check address and populate the direction */
- if (iproc_i2c->xfer_dir == I2C_SLAVE_DIR_NONE) {
- tmp = iproc_i2c_rd_reg(iproc_i2c, S_RX_OFFSET);
- rd_status = (tmp >> S_RX_STATUS_SHIFT) & S_RX_STATUS_MASK;
- /* This condition checks whether the request is a new request */
- if (((rd_status == I2C_SLAVE_RX_START) &&
- (status & BIT(IS_S_RX_EVENT_SHIFT))) ||
- ((rd_status == I2C_SLAVE_RX_END) &&
- (status & BIT(IS_S_RD_EVENT_SHIFT)))) {
-
- /* Last bit is W/R bit.
- * If 1 then its a read request(by master).
- */
- iproc_i2c->xfer_dir = tmp & SLAVE_READ_WRITE_BIT_MASK;
- if (iproc_i2c->xfer_dir == I2C_SLAVE_DIR_WRITE)
- i2c_slave_event(iproc_i2c->slave,
- I2C_SLAVE_READ_REQUESTED, &value);
- else
- i2c_slave_event(iproc_i2c->slave,
+ /* Slave RX byte receive */
+ if (status & BIT(IS_S_RX_EVENT_SHIFT)) {
+ val = iproc_i2c_rd_reg(iproc_i2c, S_RX_OFFSET);
+ rx_status = (val >> S_RX_STATUS_SHIFT) & S_RX_STATUS_MASK;
+ if (rx_status == I2C_SLAVE_RX_START) {
+ /* Start of SMBUS for Master write */
+ i2c_slave_event(iproc_i2c->slave,
I2C_SLAVE_WRITE_REQUESTED, &value);
- }
- }
- /* read request from master */
- if ((status & BIT(IS_S_RD_EVENT_SHIFT)) &&
- (iproc_i2c->xfer_dir == I2C_SLAVE_DIR_WRITE)) {
- i2c_slave_event(iproc_i2c->slave,
- I2C_SLAVE_READ_PROCESSED, &value);
- iproc_i2c_wr_reg(iproc_i2c, S_TX_OFFSET, value);
+ val = iproc_i2c_rd_reg(iproc_i2c, S_RX_OFFSET);
+ value = (u8)((val >> S_RX_DATA_SHIFT) & S_RX_DATA_MASK);
+ i2c_slave_event(iproc_i2c->slave,
+ I2C_SLAVE_WRITE_RECEIVED, &value);
+ } else if (status & BIT(IS_S_RD_EVENT_SHIFT)) {
+ /* Start of SMBUS for Master Read */
+ i2c_slave_event(iproc_i2c->slave,
+ I2C_SLAVE_READ_REQUESTED, &value);
+ iproc_i2c_wr_reg(iproc_i2c, S_TX_OFFSET, value);
- val = BIT(S_CMD_START_BUSY_SHIFT);
- iproc_i2c_wr_reg(iproc_i2c, S_CMD_OFFSET, val);
- }
+ val = BIT(S_CMD_START_BUSY_SHIFT);
+ iproc_i2c_wr_reg(iproc_i2c, S_CMD_OFFSET, val);
- /* write request from master */
- if ((status & BIT(IS_S_RX_EVENT_SHIFT)) &&
- (iproc_i2c->xfer_dir == I2C_SLAVE_DIR_READ)) {
- val = iproc_i2c_rd_reg(iproc_i2c, S_RX_OFFSET);
- /* Its a write request by Master to Slave.
- * We read data present in receive FIFO
- */
- value = (u8)((val >> S_RX_DATA_SHIFT) & S_RX_DATA_MASK);
+ /*
+ * Enable interrupt for TX FIFO becomes empty and
+ * less than PKT_LENGTH bytes were output on the SMBUS
+ */
+ val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET);
+ val |= BIT(IE_S_TX_UNDERRUN_SHIFT);
+ iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val);
+ } else {
+ /* Master write other than start */
+ value = (u8)((val >> S_RX_DATA_SHIFT) & S_RX_DATA_MASK);
+ i2c_slave_event(iproc_i2c->slave,
+ I2C_SLAVE_WRITE_RECEIVED, &value);
+ }
+ } else if (status & BIT(IS_S_TX_UNDERRUN_SHIFT)) {
+ /* Master read other than start */
i2c_slave_event(iproc_i2c->slave,
- I2C_SLAVE_WRITE_RECEIVED, &value);
-
- /* check the status for the last byte of the transaction */
- rd_status = (val >> S_RX_STATUS_SHIFT) & S_RX_STATUS_MASK;
- if (rd_status == I2C_SLAVE_RX_END)
- iproc_i2c->xfer_dir = I2C_SLAVE_DIR_NONE;
+ I2C_SLAVE_READ_PROCESSED, &value);
- dev_dbg(iproc_i2c->device, "\nread value = 0x%x\n", value);
+ iproc_i2c_wr_reg(iproc_i2c, S_TX_OFFSET, value);
+ val = BIT(S_CMD_START_BUSY_SHIFT);
+ iproc_i2c_wr_reg(iproc_i2c, S_CMD_OFFSET, val);
}
/* Stop */
if (status & BIT(IS_S_START_BUSY_SHIFT)) {
i2c_slave_event(iproc_i2c->slave, I2C_SLAVE_STOP, &value);
- iproc_i2c->xfer_dir = I2C_SLAVE_DIR_NONE;
+ /*
+ * Enable interrupt for TX FIFO becomes empty and
+ * less than PKT_LENGTH bytes were output on the SMBUS
+ */
+ val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET);
+ val &= ~BIT(IE_S_TX_UNDERRUN_SHIFT);
+ iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val);
}
/* clear interrupt status */
diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
index d2fbb4bb4a43..67752f7b0371 100644
--- a/drivers/i2c/busses/i2c-bcm2835.c
+++ b/drivers/i2c/busses/i2c-bcm2835.c
@@ -4,6 +4,8 @@
*/
#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
#include <linux/completion.h>
#include <linux/err.h>
#include <linux/i2c.h>
@@ -51,9 +53,7 @@
struct bcm2835_i2c_dev {
struct device *dev;
void __iomem *regs;
- struct clk *clk;
int irq;
- u32 bus_clk_rate;
struct i2c_adapter adapter;
struct completion completion;
struct i2c_msg *curr_msg;
@@ -74,12 +74,17 @@ static inline u32 bcm2835_i2c_readl(struct bcm2835_i2c_dev *i2c_dev, u32 reg)
return readl(i2c_dev->regs + reg);
}
-static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev)
+#define to_clk_bcm2835_i2c(_hw) container_of(_hw, struct clk_bcm2835_i2c, hw)
+struct clk_bcm2835_i2c {
+ struct clk_hw hw;
+ struct bcm2835_i2c_dev *i2c_dev;
+};
+
+static int clk_bcm2835_i2c_calc_divider(unsigned long rate,
+ unsigned long parent_rate)
{
- u32 divider, redl, fedl;
+ u32 divider = DIV_ROUND_UP(parent_rate, rate);
- divider = DIV_ROUND_UP(clk_get_rate(i2c_dev->clk),
- i2c_dev->bus_clk_rate);
/*
* Per the datasheet, the register is always interpreted as an even
* number, by rounding down. In other words, the LSB is ignored. So,
@@ -88,12 +93,23 @@ static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev)
if (divider & 1)
divider++;
if ((divider < BCM2835_I2C_CDIV_MIN) ||
- (divider > BCM2835_I2C_CDIV_MAX)) {
- dev_err_ratelimited(i2c_dev->dev, "Invalid clock-frequency\n");
+ (divider > BCM2835_I2C_CDIV_MAX))
return -EINVAL;
- }
- bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DIV, divider);
+ return divider;
+}
+
+static int clk_bcm2835_i2c_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_bcm2835_i2c *div = to_clk_bcm2835_i2c(hw);
+ u32 redl, fedl;
+ u32 divider = clk_bcm2835_i2c_calc_divider(rate, parent_rate);
+
+ if (divider == -EINVAL)
+ return -EINVAL;
+
+ bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_DIV, divider);
/*
* Number of core clocks to wait after falling edge before
@@ -108,12 +124,65 @@ static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev)
*/
redl = max(divider / 4, 1u);
- bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DEL,
+ bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_DEL,
(fedl << BCM2835_I2C_FEDL_SHIFT) |
(redl << BCM2835_I2C_REDL_SHIFT));
return 0;
}
+static long clk_bcm2835_i2c_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ u32 divider = clk_bcm2835_i2c_calc_divider(rate, *parent_rate);
+
+ return DIV_ROUND_UP(*parent_rate, divider);
+}
+
+static unsigned long clk_bcm2835_i2c_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_bcm2835_i2c *div = to_clk_bcm2835_i2c(hw);
+ u32 divider = bcm2835_i2c_readl(div->i2c_dev, BCM2835_I2C_DIV);
+
+ return DIV_ROUND_UP(parent_rate, divider);
+}
+
+static const struct clk_ops clk_bcm2835_i2c_ops = {
+ .set_rate = clk_bcm2835_i2c_set_rate,
+ .round_rate = clk_bcm2835_i2c_round_rate,
+ .recalc_rate = clk_bcm2835_i2c_recalc_rate,
+};
+
+static struct clk *bcm2835_i2c_register_div(struct device *dev,
+ struct clk *mclk,
+ struct bcm2835_i2c_dev *i2c_dev)
+{
+ struct clk_init_data init;
+ struct clk_bcm2835_i2c *priv;
+ char name[32];
+ const char *mclk_name;
+
+ snprintf(name, sizeof(name), "%s_div", dev_name(dev));
+
+ mclk_name = __clk_get_name(mclk);
+
+ init.ops = &clk_bcm2835_i2c_ops;
+ init.name = name;
+ init.parent_names = (const char* []) { mclk_name };
+ init.num_parents = 1;
+ init.flags = 0;
+
+ priv = devm_kzalloc(dev, sizeof(struct clk_bcm2835_i2c), GFP_KERNEL);
+ if (priv == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ priv->hw.init = &init;
+ priv->i2c_dev = i2c_dev;
+
+ clk_hw_register_clkdev(&priv->hw, "div", dev_name(dev));
+ return devm_clk_register(dev, &priv->hw);
+}
+
static void bcm2835_fill_txfifo(struct bcm2835_i2c_dev *i2c_dev)
{
u32 val;
@@ -271,7 +340,7 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
{
struct bcm2835_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
unsigned long time_left;
- int i, ret;
+ int i;
for (i = 0; i < (num - 1); i++)
if (msgs[i].flags & I2C_M_RD) {
@@ -280,10 +349,6 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
return -EOPNOTSUPP;
}
- ret = bcm2835_i2c_set_divider(i2c_dev);
- if (ret)
- return ret;
-
i2c_dev->curr_msg = msgs;
i2c_dev->num_msgs = num;
reinit_completion(&i2c_dev->completion);
@@ -338,6 +403,9 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
struct resource *mem, *irq;
int ret;
struct i2c_adapter *adap;
+ struct clk *bus_clk;
+ struct clk *mclk;
+ u32 bus_clk_rate;
i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
if (!i2c_dev)
@@ -351,19 +419,38 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
if (IS_ERR(i2c_dev->regs))
return PTR_ERR(i2c_dev->regs);
- i2c_dev->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(i2c_dev->clk)) {
- if (PTR_ERR(i2c_dev->clk) != -EPROBE_DEFER)
+ mclk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(mclk)) {
+ if (PTR_ERR(mclk) != -EPROBE_DEFER)
dev_err(&pdev->dev, "Could not get clock\n");
- return PTR_ERR(i2c_dev->clk);
+ return PTR_ERR(mclk);
+ }
+
+ bus_clk = bcm2835_i2c_register_div(&pdev->dev, mclk, i2c_dev);
+
+ if (IS_ERR(bus_clk)) {
+ dev_err(&pdev->dev, "Could not register clock\n");
+ return PTR_ERR(bus_clk);
}
ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
- &i2c_dev->bus_clk_rate);
+ &bus_clk_rate);
if (ret < 0) {
dev_warn(&pdev->dev,
"Could not read clock-frequency property\n");
- i2c_dev->bus_clk_rate = 100000;
+ bus_clk_rate = 100000;
+ }
+
+ ret = clk_set_rate_exclusive(bus_clk, bus_clk_rate);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Could not set clock frequency\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(bus_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Couldn't prepare clock");
+ return ret;
}
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
@@ -402,6 +489,10 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
static int bcm2835_i2c_remove(struct platform_device *pdev)
{
struct bcm2835_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+ struct clk *bus_clk = devm_clk_get(i2c_dev->dev, "div");
+
+ clk_rate_exclusive_put(bus_clk);
+ clk_disable_unprepare(bus_clk);
free_irq(i2c_dev->irq, i2c_dev);
i2c_del_adapter(&i2c_dev->adapter);
diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c
index 187900594e3d..1213e1932ccb 100644
--- a/drivers/i2c/busses/i2c-cpm.c
+++ b/drivers/i2c/busses/i2c-cpm.c
@@ -531,7 +531,9 @@ static int cpm_i2c_setup(struct cpm_i2c *cpm)
}
out_be32(&rbdf[i].cbd_bufaddr, ((cpm->rxdma[i] + 1) & ~1));
- cpm->txbuf[i] = (unsigned char *)dma_alloc_coherent(&cpm->ofdev->dev, CPM_MAX_READ + 1, &cpm->txdma[i], GFP_KERNEL);
+ cpm->txbuf[i] = dma_alloc_coherent(&cpm->ofdev->dev,
+ CPM_MAX_READ + 1,
+ &cpm->txdma[i], GFP_KERNEL);
if (!cpm->txbuf[i]) {
ret = -ENOMEM;
goto out_muram;
diff --git a/drivers/i2c/busses/i2c-digicolor.c b/drivers/i2c/busses/i2c-digicolor.c
index 50813a24c541..3adf72540db1 100644
--- a/drivers/i2c/busses/i2c-digicolor.c
+++ b/drivers/i2c/busses/i2c-digicolor.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* I2C bus driver for Conexant Digicolor SoCs
*
* Author: Baruch Siach <baruch@tkos.co.il>
*
* Copyright (C) 2015 Paradox Innovation Ltd.
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/i2c/busses/i2c-efm32.c b/drivers/i2c/busses/i2c-efm32.c
index 5f2bab878b2c..a8c6323e7f44 100644
--- a/drivers/i2c/busses/i2c-efm32.c
+++ b/drivers/i2c/busses/i2c-efm32.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 Uwe Kleine-Koenig for Pengutronix
- *
- * 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.
*/
#include <linux/module.h>
#include <linux/platform_device.h>
diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c
index 41de4ee409b6..e4e7932f7800 100644
--- a/drivers/i2c/busses/i2c-exynos5.c
+++ b/drivers/i2c/busses/i2c-exynos5.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/**
* i2c-exynos5.c - Samsung Exynos5 I2C Controller Driver
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c
index 1e2be2219a60..da5eb3960def 100644
--- a/drivers/i2c/busses/i2c-fsi.c
+++ b/drivers/i2c/busses/i2c-fsi.c
@@ -658,13 +658,29 @@ static const struct i2c_algorithm fsi_i2c_algorithm = {
.functionality = fsi_i2c_functionality,
};
+static struct device_node *fsi_i2c_find_port_of_node(struct device_node *fsi,
+ int port)
+{
+ struct device_node *np;
+ u32 port_no;
+ int rc;
+
+ for_each_child_of_node(fsi, np) {
+ rc = of_property_read_u32(np, "reg", &port_no);
+ if (!rc && port_no == port)
+ return np;
+ }
+
+ return NULL;
+}
+
static int fsi_i2c_probe(struct device *dev)
{
struct fsi_i2c_master *i2c;
struct fsi_i2c_port *port;
struct device_node *np;
+ u32 port_no, ports, stat;
int rc;
- u32 port_no;
i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL);
if (!i2c)
@@ -678,10 +694,16 @@ static int fsi_i2c_probe(struct device *dev)
if (rc)
return rc;
- /* Add adapter for each i2c port of the master. */
- for_each_available_child_of_node(dev->of_node, np) {
- rc = of_property_read_u32(np, "reg", &port_no);
- if (rc || port_no > USHRT_MAX)
+ rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_STAT, &stat);
+ if (rc)
+ return rc;
+
+ ports = FIELD_GET(I2C_STAT_MAX_PORT, stat) + 1;
+ dev_dbg(dev, "I2C master has %d ports\n", ports);
+
+ for (port_no = 0; port_no < ports; port_no++) {
+ np = fsi_i2c_find_port_of_node(dev->of_node, port_no);
+ if (np && !of_device_is_available(np))
continue;
port = kzalloc(sizeof(*port), GFP_KERNEL);
diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c
index 9684a0ac2a6d..3a9e840a3546 100644
--- a/drivers/i2c/busses/i2c-gpio.c
+++ b/drivers/i2c/busses/i2c-gpio.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Bitbanging I2C bus driver using the GPIO API
*
* Copyright (C) 2007 Atmel Corporation
- *
- * 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.
*/
#include <linux/completion.h>
#include <linux/debugfs.h>
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index ac7f7817dc89..f2956936c3f2 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -64,12 +64,14 @@
* Cedar Fork (PCH) 0x18df 32 hard yes yes yes
* Ice Lake-LP (PCH) 0x34a3 32 hard yes yes yes
* Comet Lake (PCH) 0x02a3 32 hard yes yes yes
+ * Elkhart Lake (PCH) 0x4b23 32 hard yes yes yes
+ * Tiger Lake-LP (PCH) 0xa0a3 32 hard yes yes yes
*
* Features supported by this driver:
* Software PEC no
* Hardware PEC yes
* Block buffer yes
- * Block process call transaction no
+ * Block process call transaction yes
* I2C block read transaction yes (doesn't use the block buffer)
* Slave mode no
* SMBus Host Notify yes
@@ -92,6 +94,7 @@
#include <linux/io.h>
#include <linux/dmi.h>
#include <linux/slab.h>
+#include <linux/string.h>
#include <linux/wait.h>
#include <linux/err.h>
#include <linux/platform_device.h>
@@ -99,7 +102,7 @@
#include <linux/pm_runtime.h>
#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI
-#include <linux/gpio.h>
+#include <linux/gpio/machine.h>
#include <linux/platform_data/i2c-mux-gpio.h>
#endif
@@ -169,6 +172,7 @@
#define I801_PROC_CALL 0x10 /* unimplemented */
#define I801_BLOCK_DATA 0x14
#define I801_I2C_BLOCK_DATA 0x18 /* ICH5 and later */
+#define I801_BLOCK_PROC_CALL 0x1C
/* I801 Host Control register bits */
#define SMBHSTCNT_INTREN BIT(0)
@@ -200,6 +204,7 @@
STATUS_ERROR_FLAGS)
/* Older devices have their ID defined in <linux/pci_ids.h> */
+#define PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS 0x02a3
#define PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS 0x0f12
#define PCI_DEVICE_ID_INTEL_CDF_SMBUS 0x18df
#define PCI_DEVICE_ID_INTEL_DNV_SMBUS 0x19df
@@ -217,6 +222,7 @@
#define PCI_DEVICE_ID_INTEL_GEMINILAKE_SMBUS 0x31d4
#define PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS 0x34a3
#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30
+#define PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS 0x4b23
#define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22
#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS 0x8ca2
@@ -228,12 +234,12 @@
#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS 0x9ca2
#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS 0x9d23
#define PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS 0x9da3
+#define PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS 0xa0a3
#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS 0xa123
#define PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS 0xa1a3
#define PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS 0xa223
#define PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS 0xa2a3
#define PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS 0xa323
-#define PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS 0x02a3
struct i801_mux_config {
char *gpio_chip;
@@ -266,6 +272,7 @@ struct i801_priv {
#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI
const struct i801_mux_config *mux_drvdata;
struct platform_device *mux_pdev;
+ struct gpiod_lookup_table *lookup;
#endif
struct platform_device *tco_pdev;
@@ -509,10 +516,23 @@ static int i801_transaction(struct i801_priv *priv, int xact)
static int i801_block_transaction_by_block(struct i801_priv *priv,
union i2c_smbus_data *data,
- char read_write, int hwpec)
+ char read_write, int command,
+ int hwpec)
{
int i, len;
int status;
+ int xact = hwpec ? SMBHSTCNT_PEC_EN : 0;
+
+ switch (command) {
+ case I2C_SMBUS_BLOCK_PROC_CALL:
+ xact |= I801_BLOCK_PROC_CALL;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ xact |= I801_BLOCK_DATA;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */
@@ -524,12 +544,12 @@ static int i801_block_transaction_by_block(struct i801_priv *priv,
outb_p(data->block[i+1], SMBBLKDAT(priv));
}
- status = i801_transaction(priv, I801_BLOCK_DATA |
- (hwpec ? SMBHSTCNT_PEC_EN : 0));
+ status = i801_transaction(priv, xact);
if (status)
return status;
- if (read_write == I2C_SMBUS_READ) {
+ if (read_write == I2C_SMBUS_READ ||
+ command == I2C_SMBUS_BLOCK_PROC_CALL) {
len = inb_p(SMBHSTDAT0(priv));
if (len < 1 || len > I2C_SMBUS_BLOCK_MAX)
return -EPROTO;
@@ -667,6 +687,9 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
int result;
const struct i2c_adapter *adap = &priv->adapter;
+ if (command == I2C_SMBUS_BLOCK_PROC_CALL)
+ return -EOPNOTSUPP;
+
result = i801_check_pre(priv);
if (result < 0)
return result;
@@ -798,7 +821,8 @@ static int i801_block_transaction(struct i801_priv *priv,
&& command != I2C_SMBUS_I2C_BLOCK_DATA
&& i801_set_block_buffer_mode(priv) == 0)
result = i801_block_transaction_by_block(priv, data,
- read_write, hwpec);
+ read_write,
+ command, hwpec);
else
result = i801_block_transaction_byte_by_byte(priv, data,
read_write,
@@ -890,6 +914,15 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
outb_p(command, SMBHSTCMD(priv));
block = 1;
break;
+ case I2C_SMBUS_BLOCK_PROC_CALL:
+ /*
+ * Bit 0 of the slave address register always indicate a write
+ * command.
+ */
+ outb_p((addr & 0x7f) << 1, SMBHSTADD(priv));
+ outb_p(command, SMBHSTCMD(priv));
+ block = 1;
+ break;
default:
dev_err(&priv->pci_dev->dev, "Unsupported transaction %d\n",
size);
@@ -950,6 +983,8 @@ static u32 i801_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK |
((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) |
+ ((priv->features & FEATURE_BLOCK_PROC) ?
+ I2C_FUNC_SMBUS_BLOCK_PROC_CALL : 0) |
((priv->features & FEATURE_I2C_BLOCK_READ) ?
I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0) |
((priv->features & FEATURE_HOST_NOTIFY) ?
@@ -1033,6 +1068,8 @@ static const struct pci_device_id i801_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS) },
{ 0, }
};
@@ -1134,6 +1171,118 @@ static void dmi_check_onboard_devices(const struct dmi_header *dm, void *adap)
}
}
+/* NOTE: Keep this list in sync with drivers/platform/x86/dell-smo8800.c */
+static const char *const acpi_smo8800_ids[] = {
+ "SMO8800",
+ "SMO8801",
+ "SMO8810",
+ "SMO8811",
+ "SMO8820",
+ "SMO8821",
+ "SMO8830",
+ "SMO8831",
+};
+
+static acpi_status check_acpi_smo88xx_device(acpi_handle obj_handle,
+ u32 nesting_level,
+ void *context,
+ void **return_value)
+{
+ struct acpi_device_info *info;
+ acpi_status status;
+ char *hid;
+ int i;
+
+ status = acpi_get_object_info(obj_handle, &info);
+ if (!ACPI_SUCCESS(status) || !(info->valid & ACPI_VALID_HID))
+ return AE_OK;
+
+ hid = info->hardware_id.string;
+ if (!hid)
+ return AE_OK;
+
+ i = match_string(acpi_smo8800_ids, ARRAY_SIZE(acpi_smo8800_ids), hid);
+ if (i < 0)
+ return AE_OK;
+
+ *((bool *)return_value) = true;
+ return AE_CTRL_TERMINATE;
+}
+
+static bool is_dell_system_with_lis3lv02d(void)
+{
+ bool found;
+ const char *vendor;
+
+ vendor = dmi_get_system_info(DMI_SYS_VENDOR);
+ if (!vendor || strcmp(vendor, "Dell Inc."))
+ return false;
+
+ /*
+ * Check that ACPI device SMO88xx is present and is functioning.
+ * Function acpi_get_devices() already filters all ACPI devices
+ * which are not present or are not functioning.
+ * ACPI device SMO88xx represents our ST microelectronics lis3lv02d
+ * accelerometer but unfortunately ACPI does not provide any other
+ * information (like I2C address).
+ */
+ found = false;
+ acpi_get_devices(NULL, check_acpi_smo88xx_device, NULL,
+ (void **)&found);
+
+ return found;
+}
+
+/*
+ * Accelerometer's I2C address is not specified in DMI nor ACPI,
+ * so it is needed to define mapping table based on DMI product names.
+ */
+static const struct {
+ const char *dmi_product_name;
+ unsigned short i2c_addr;
+} dell_lis3lv02d_devices[] = {
+ /*
+ * Dell platform team told us that these Latitude devices have
+ * ST microelectronics accelerometer at I2C address 0x29.
+ */
+ { "Latitude E5250", 0x29 },
+ { "Latitude E5450", 0x29 },
+ { "Latitude E5550", 0x29 },
+ { "Latitude E6440", 0x29 },
+ { "Latitude E6440 ATG", 0x29 },
+ { "Latitude E6540", 0x29 },
+ /*
+ * Additional individual entries were added after verification.
+ */
+ { "Vostro V131", 0x1d },
+};
+
+static void register_dell_lis3lv02d_i2c_device(struct i801_priv *priv)
+{
+ struct i2c_board_info info;
+ const char *dmi_product_name;
+ int i;
+
+ dmi_product_name = dmi_get_system_info(DMI_PRODUCT_NAME);
+ for (i = 0; i < ARRAY_SIZE(dell_lis3lv02d_devices); ++i) {
+ if (strcmp(dmi_product_name,
+ dell_lis3lv02d_devices[i].dmi_product_name) == 0)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(dell_lis3lv02d_devices)) {
+ dev_warn(&priv->pci_dev->dev,
+ "Accelerometer lis3lv02d is present on SMBus but its"
+ " address is unknown, skipping registration\n");
+ return;
+ }
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ info.addr = dell_lis3lv02d_devices[i].i2c_addr;
+ strlcpy(info.type, "lis3lv02d", I2C_NAME_SIZE);
+ i2c_new_device(&priv->adapter, &info);
+}
+
/* Register optional slaves */
static void i801_probe_optional_slaves(struct i801_priv *priv)
{
@@ -1152,6 +1301,9 @@ static void i801_probe_optional_slaves(struct i801_priv *priv)
if (dmi_name_in_vendors("FUJITSU"))
dmi_walk(dmi_check_onboard_devices, &priv->adapter);
+
+ if (is_dell_system_with_lis3lv02d())
+ register_dell_lis3lv02d_i2c_device(priv);
}
#else
static void __init input_apanel_init(void) {}
@@ -1250,7 +1402,8 @@ static int i801_add_mux(struct i801_priv *priv)
struct device *dev = &priv->adapter.dev;
const struct i801_mux_config *mux_config;
struct i2c_mux_gpio_platform_data gpio_data;
- int err;
+ struct gpiod_lookup_table *lookup;
+ int err, i;
if (!priv->mux_drvdata)
return 0;
@@ -1262,17 +1415,36 @@ static int i801_add_mux(struct i801_priv *priv)
gpio_data.values = mux_config->values;
gpio_data.n_values = mux_config->n_values;
gpio_data.classes = mux_config->classes;
- gpio_data.gpio_chip = mux_config->gpio_chip;
- gpio_data.gpios = mux_config->gpios;
- gpio_data.n_gpios = mux_config->n_gpios;
gpio_data.idle = I2C_MUX_GPIO_NO_IDLE;
- /* Register the mux device */
+ /* Register GPIO descriptor lookup table */
+ lookup = devm_kzalloc(dev,
+ struct_size(lookup, table, mux_config->n_gpios),
+ GFP_KERNEL);
+ if (!lookup)
+ return -ENOMEM;
+ lookup->dev_id = "i2c-mux-gpio";
+ for (i = 0; i < mux_config->n_gpios; i++) {
+ lookup->table[i].chip_label = mux_config->gpio_chip;
+ lookup->table[i].chip_hwnum = mux_config->gpios[i];
+ lookup->table[i].con_id = "mux";
+ }
+ gpiod_add_lookup_table(lookup);
+ priv->lookup = lookup;
+
+ /*
+ * Register the mux device, we use PLATFORM_DEVID_NONE here
+ * because since we are referring to the GPIO chip by name we are
+ * anyways in deep trouble if there is more than one of these
+ * devices, and there should likely only be one platform controller
+ * hub.
+ */
priv->mux_pdev = platform_device_register_data(dev, "i2c-mux-gpio",
- PLATFORM_DEVID_AUTO, &gpio_data,
+ PLATFORM_DEVID_NONE, &gpio_data,
sizeof(struct i2c_mux_gpio_platform_data));
if (IS_ERR(priv->mux_pdev)) {
err = PTR_ERR(priv->mux_pdev);
+ gpiod_remove_lookup_table(lookup);
priv->mux_pdev = NULL;
dev_err(dev, "Failed to register i2c-mux-gpio device\n");
return err;
@@ -1285,6 +1457,8 @@ static void i801_del_mux(struct i801_priv *priv)
{
if (priv->mux_pdev)
platform_device_unregister(priv->mux_pdev);
+ if (priv->lookup)
+ gpiod_remove_lookup_table(priv->lookup);
}
static unsigned int i801_get_adapter_class(struct i801_priv *priv)
@@ -1530,6 +1704,9 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
case PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS:
case PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS:
case PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS:
+ case PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS:
+ case PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS:
+ priv->features |= FEATURE_BLOCK_PROC;
priv->features |= FEATURE_I2C_BLOCK_READ;
priv->features |= FEATURE_IRQ;
priv->features |= FEATURE_SMBUS_PEC;
@@ -1549,6 +1726,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
priv->features |= FEATURE_IDF;
/* fall through */
default:
+ priv->features |= FEATURE_BLOCK_PROC;
priv->features |= FEATURE_I2C_BLOCK_READ;
priv->features |= FEATURE_IRQ;
/* fall through */
diff --git a/drivers/i2c/busses/i2c-img-scb.c b/drivers/i2c/busses/i2c-img-scb.c
index f038858b6c54..20a4fbc53007 100644
--- a/drivers/i2c/busses/i2c-img-scb.c
+++ b/drivers/i2c/busses/i2c-img-scb.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* I2C adapter for the IMG Serial Control Bus (SCB) IP block.
*
* Copyright (C) 2009, 2010, 2012, 2014 Imagination Technologies Ltd.
*
- * 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.
- *
* There are three ways that this I2C controller can be driven:
*
* - Raw control of the SDA and SCK signals.
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index fd70b110e8f4..b1b8b938d7f4 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -1220,8 +1220,7 @@ static int i2c_imx_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
-static int i2c_imx_runtime_suspend(struct device *dev)
+static int __maybe_unused i2c_imx_runtime_suspend(struct device *dev)
{
struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
@@ -1230,7 +1229,7 @@ static int i2c_imx_runtime_suspend(struct device *dev)
return 0;
}
-static int i2c_imx_runtime_resume(struct device *dev)
+static int __maybe_unused i2c_imx_runtime_resume(struct device *dev)
{
struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
int ret;
@@ -1246,17 +1245,13 @@ static const struct dev_pm_ops i2c_imx_pm_ops = {
SET_RUNTIME_PM_OPS(i2c_imx_runtime_suspend,
i2c_imx_runtime_resume, NULL)
};
-#define I2C_IMX_PM_OPS (&i2c_imx_pm_ops)
-#else
-#define I2C_IMX_PM_OPS NULL
-#endif /* CONFIG_PM */
static struct platform_driver i2c_imx_driver = {
.probe = i2c_imx_probe,
.remove = i2c_imx_remove,
.driver = {
.name = DRIVER_NAME,
- .pm = I2C_IMX_PM_OPS,
+ .pm = &i2c_imx_pm_ops,
.of_match_table = i2c_imx_dt_ids,
},
.id_table = imx_i2c_devtype,
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
index 87ce788ab90c..38556381f4ca 100644
--- a/drivers/i2c/busses/i2c-iop3xx.c
+++ b/drivers/i2c/busses/i2c-iop3xx.c
@@ -35,7 +35,7 @@
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/io.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include "i2c-iop3xx.h"
@@ -68,17 +68,16 @@ iop3xx_i2c_enable(struct i2c_algo_iop3xx_data *iop3xx_adap)
/*
* Every time unit enable is asserted, GPOD needs to be cleared
- * on IOP3XX to avoid data corruption on the bus.
+ * on IOP3XX to avoid data corruption on the bus. We use the
+ * gpiod_set_raw_value() to make sure the 0 hits the hardware
+ * GPOD register. These descriptors are only passed along to
+ * the device if this is necessary.
*/
-#if defined(CONFIG_ARCH_IOP32X) || defined(CONFIG_ARCH_IOP33X)
- if (iop3xx_adap->id == 0) {
- gpio_set_value(7, 0);
- gpio_set_value(6, 0);
- } else {
- gpio_set_value(5, 0);
- gpio_set_value(4, 0);
- }
-#endif
+ if (iop3xx_adap->gpio_scl)
+ gpiod_set_raw_value(iop3xx_adap->gpio_scl, 0);
+ if (iop3xx_adap->gpio_sda)
+ gpiod_set_raw_value(iop3xx_adap->gpio_sda, 0);
+
/* NB SR bits not same position as CR IE bits :-( */
iop3xx_adap->SR_enabled =
IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD |
@@ -431,6 +430,17 @@ iop3xx_i2c_probe(struct platform_device *pdev)
goto free_adapter;
}
+ adapter_data->gpio_scl = devm_gpiod_get_optional(&pdev->dev,
+ "scl",
+ GPIOD_ASIS);
+ if (IS_ERR(adapter_data->gpio_scl))
+ return PTR_ERR(adapter_data->gpio_scl);
+ adapter_data->gpio_sda = devm_gpiod_get_optional(&pdev->dev,
+ "sda",
+ GPIOD_ASIS);
+ if (IS_ERR(adapter_data->gpio_sda))
+ return PTR_ERR(adapter_data->gpio_sda);
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
ret = -ENODEV;
diff --git a/drivers/i2c/busses/i2c-iop3xx.h b/drivers/i2c/busses/i2c-iop3xx.h
index 53ca1fc9b84c..143548335504 100644
--- a/drivers/i2c/busses/i2c-iop3xx.h
+++ b/drivers/i2c/busses/i2c-iop3xx.h
@@ -92,6 +92,8 @@ struct i2c_algo_iop3xx_data {
spinlock_t lock;
u32 SR_enabled, SR_received;
int id;
+ struct gpio_desc *gpio_scl;
+ struct gpio_desc *gpio_sda;
};
#endif /* I2C_IOP3XX_H */
diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c
index 90f5d0407d73..1e2647f9a2a7 100644
--- a/drivers/i2c/busses/i2c-meson.c
+++ b/drivers/i2c/busses/i2c-meson.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* I2C bus driver for Amlogic Meson SoCs
*
* Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/i2c/busses/i2c-mt7621.c b/drivers/i2c/busses/i2c-mt7621.c
new file mode 100644
index 000000000000..62df8379bc89
--- /dev/null
+++ b/drivers/i2c/busses/i2c-mt7621.c
@@ -0,0 +1,356 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * drivers/i2c/busses/i2c-mt7621.c
+ *
+ * Copyright (C) 2013 Steven Liu <steven_liu@mediatek.com>
+ * Copyright (C) 2016 Michael Lee <igvtee@gmail.com>
+ * Copyright (C) 2018 Jan Breuer <jan.breuer@jaybee.cz>
+ *
+ * Improve driver for i2cdetect from i2c-tools to detect i2c devices on the bus.
+ * (C) 2014 Sittisak <sittisaks@hotmail.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/reset.h>
+
+#define REG_SM0CFG2_REG 0x28
+#define REG_SM0CTL0_REG 0x40
+#define REG_SM0CTL1_REG 0x44
+#define REG_SM0D0_REG 0x50
+#define REG_SM0D1_REG 0x54
+#define REG_PINTEN_REG 0x5c
+#define REG_PINTST_REG 0x60
+#define REG_PINTCL_REG 0x64
+
+/* REG_SM0CFG2_REG */
+#define SM0CFG2_IS_AUTOMODE BIT(0)
+
+/* REG_SM0CTL0_REG */
+#define SM0CTL0_ODRAIN BIT(31)
+#define SM0CTL0_CLK_DIV_MASK (0x7ff << 16)
+#define SM0CTL0_CLK_DIV_MAX 0x7ff
+#define SM0CTL0_CS_STATUS BIT(4)
+#define SM0CTL0_SCL_STATE BIT(3)
+#define SM0CTL0_SDA_STATE BIT(2)
+#define SM0CTL0_EN BIT(1)
+#define SM0CTL0_SCL_STRETCH BIT(0)
+
+/* REG_SM0CTL1_REG */
+#define SM0CTL1_ACK_MASK (0xff << 16)
+#define SM0CTL1_PGLEN_MASK (0x7 << 8)
+#define SM0CTL1_PGLEN(x) ((((x) - 1) << 8) & SM0CTL1_PGLEN_MASK)
+#define SM0CTL1_READ (5 << 4)
+#define SM0CTL1_READ_LAST (4 << 4)
+#define SM0CTL1_STOP (3 << 4)
+#define SM0CTL1_WRITE (2 << 4)
+#define SM0CTL1_START (1 << 4)
+#define SM0CTL1_MODE_MASK (0x7 << 4)
+#define SM0CTL1_TRI BIT(0)
+
+/* timeout waiting for I2C devices to respond */
+#define TIMEOUT_MS 1000
+
+struct mtk_i2c {
+ void __iomem *base;
+ struct device *dev;
+ struct i2c_adapter adap;
+ u32 bus_freq;
+ u32 clk_div;
+ u32 flags;
+ struct clk *clk;
+};
+
+static int mtk_i2c_wait_idle(struct mtk_i2c *i2c)
+{
+ int ret;
+ u32 val;
+
+ ret = readl_relaxed_poll_timeout(i2c->base + REG_SM0CTL1_REG,
+ val, !(val & SM0CTL1_TRI),
+ 10, TIMEOUT_MS * 1000);
+ if (ret)
+ dev_dbg(i2c->dev, "idle err(%d)\n", ret);
+
+ return ret;
+}
+
+static void mtk_i2c_reset(struct mtk_i2c *i2c)
+{
+ int ret;
+
+ ret = device_reset(i2c->adap.dev.parent);
+ if (ret)
+ dev_err(i2c->dev, "I2C reset failed!\n");
+
+ /*
+ * Don't set SM0CTL0_ODRAIN as its bit meaning is inverted. To
+ * configure open-drain mode, this bit needs to be cleared.
+ */
+ iowrite32(((i2c->clk_div << 16) & SM0CTL0_CLK_DIV_MASK) | SM0CTL0_EN |
+ SM0CTL0_SCL_STRETCH, i2c->base + REG_SM0CTL0_REG);
+ iowrite32(0, i2c->base + REG_SM0CFG2_REG);
+}
+
+static void mtk_i2c_dump_reg(struct mtk_i2c *i2c)
+{
+ dev_dbg(i2c->dev,
+ "SM0CFG2 %08x, SM0CTL0 %08x, SM0CTL1 %08x, SM0D0 %08x, SM0D1 %08x\n",
+ ioread32(i2c->base + REG_SM0CFG2_REG),
+ ioread32(i2c->base + REG_SM0CTL0_REG),
+ ioread32(i2c->base + REG_SM0CTL1_REG),
+ ioread32(i2c->base + REG_SM0D0_REG),
+ ioread32(i2c->base + REG_SM0D1_REG));
+}
+
+static int mtk_i2c_check_ack(struct mtk_i2c *i2c, u32 expected)
+{
+ u32 ack = readl_relaxed(i2c->base + REG_SM0CTL1_REG);
+ u32 ack_expected = (expected << 16) & SM0CTL1_ACK_MASK;
+
+ return ((ack & ack_expected) == ack_expected) ? 0 : -ENXIO;
+}
+
+static int mtk_i2c_master_start(struct mtk_i2c *i2c)
+{
+ iowrite32(SM0CTL1_START | SM0CTL1_TRI, i2c->base + REG_SM0CTL1_REG);
+ return mtk_i2c_wait_idle(i2c);
+}
+
+static int mtk_i2c_master_stop(struct mtk_i2c *i2c)
+{
+ iowrite32(SM0CTL1_STOP | SM0CTL1_TRI, i2c->base + REG_SM0CTL1_REG);
+ return mtk_i2c_wait_idle(i2c);
+}
+
+static int mtk_i2c_master_cmd(struct mtk_i2c *i2c, u32 cmd, int page_len)
+{
+ iowrite32(cmd | SM0CTL1_TRI | SM0CTL1_PGLEN(page_len),
+ i2c->base + REG_SM0CTL1_REG);
+ return mtk_i2c_wait_idle(i2c);
+}
+
+static int mtk_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num)
+{
+ struct mtk_i2c *i2c;
+ struct i2c_msg *pmsg;
+ u16 addr;
+ int i, j, ret, len, page_len;
+ u32 cmd;
+ u32 data[2];
+
+ i2c = i2c_get_adapdata(adap);
+
+ for (i = 0; i < num; i++) {
+ pmsg = &msgs[i];
+
+ /* wait hardware idle */
+ ret = mtk_i2c_wait_idle(i2c);
+ if (ret)
+ goto err_timeout;
+
+ /* start sequence */
+ ret = mtk_i2c_master_start(i2c);
+ if (ret)
+ goto err_timeout;
+
+ /* write address */
+ if (pmsg->flags & I2C_M_TEN) {
+ /* 10 bits address */
+ addr = 0xf0 | ((pmsg->addr >> 7) & 0x06);
+ addr |= (pmsg->addr & 0xff) << 8;
+ if (pmsg->flags & I2C_M_RD)
+ addr |= 1;
+ iowrite32(addr, i2c->base + REG_SM0D0_REG);
+ ret = mtk_i2c_master_cmd(i2c, SM0CTL1_WRITE, 2);
+ if (ret)
+ goto err_timeout;
+ } else {
+ /* 7 bits address */
+ addr = i2c_8bit_addr_from_msg(pmsg);
+ iowrite32(addr, i2c->base + REG_SM0D0_REG);
+ ret = mtk_i2c_master_cmd(i2c, SM0CTL1_WRITE, 1);
+ if (ret)
+ goto err_timeout;
+ }
+
+ /* check address ACK */
+ if (!(pmsg->flags & I2C_M_IGNORE_NAK)) {
+ ret = mtk_i2c_check_ack(i2c, BIT(0));
+ if (ret)
+ goto err_ack;
+ }
+
+ /* transfer data */
+ for (len = pmsg->len, j = 0; len > 0; len -= 8, j += 8) {
+ page_len = (len >= 8) ? 8 : len;
+
+ if (pmsg->flags & I2C_M_RD) {
+ cmd = (len > 8) ?
+ SM0CTL1_READ : SM0CTL1_READ_LAST;
+ } else {
+ memcpy(data, &pmsg->buf[j], page_len);
+ iowrite32(data[0], i2c->base + REG_SM0D0_REG);
+ iowrite32(data[1], i2c->base + REG_SM0D1_REG);
+ cmd = SM0CTL1_WRITE;
+ }
+
+ ret = mtk_i2c_master_cmd(i2c, cmd, page_len);
+ if (ret)
+ goto err_timeout;
+
+ if (pmsg->flags & I2C_M_RD) {
+ data[0] = ioread32(i2c->base + REG_SM0D0_REG);
+ data[1] = ioread32(i2c->base + REG_SM0D1_REG);
+ memcpy(&pmsg->buf[j], data, page_len);
+ } else {
+ if (!(pmsg->flags & I2C_M_IGNORE_NAK)) {
+ ret = mtk_i2c_check_ack(i2c,
+ (1 << page_len)
+ - 1);
+ if (ret)
+ goto err_ack;
+ }
+ }
+ }
+ }
+
+ ret = mtk_i2c_master_stop(i2c);
+ if (ret)
+ goto err_timeout;
+
+ /* the return value is number of executed messages */
+ return i;
+
+err_ack:
+ ret = mtk_i2c_master_stop(i2c);
+ if (ret)
+ goto err_timeout;
+ return -ENXIO;
+
+err_timeout:
+ mtk_i2c_dump_reg(i2c);
+ mtk_i2c_reset(i2c);
+ return ret;
+}
+
+static u32 mtk_i2c_func(struct i2c_adapter *a)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+static const struct i2c_algorithm mtk_i2c_algo = {
+ .master_xfer = mtk_i2c_master_xfer,
+ .functionality = mtk_i2c_func,
+};
+
+static const struct of_device_id i2c_mtk_dt_ids[] = {
+ { .compatible = "mediatek,mt7621-i2c" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, i2c_mtk_dt_ids);
+
+static void mtk_i2c_init(struct mtk_i2c *i2c)
+{
+ i2c->clk_div = clk_get_rate(i2c->clk) / i2c->bus_freq - 1;
+ if (i2c->clk_div < 99)
+ i2c->clk_div = 99;
+ if (i2c->clk_div > SM0CTL0_CLK_DIV_MAX)
+ i2c->clk_div = SM0CTL0_CLK_DIV_MAX;
+
+ mtk_i2c_reset(i2c);
+}
+
+static int mtk_i2c_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct mtk_i2c *i2c;
+ struct i2c_adapter *adap;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ i2c = devm_kzalloc(&pdev->dev, sizeof(struct mtk_i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ i2c->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(i2c->base))
+ return PTR_ERR(i2c->base);
+
+ i2c->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(i2c->clk)) {
+ dev_err(&pdev->dev, "no clock defined\n");
+ return PTR_ERR(i2c->clk);
+ }
+ ret = clk_prepare_enable(i2c->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to enable clock\n");
+ return ret;
+ }
+
+ i2c->dev = &pdev->dev;
+
+ if (of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+ &i2c->bus_freq))
+ i2c->bus_freq = 100000;
+
+ if (i2c->bus_freq == 0) {
+ dev_warn(i2c->dev, "clock-frequency 0 not supported\n");
+ return -EINVAL;
+ }
+
+ adap = &i2c->adap;
+ adap->owner = THIS_MODULE;
+ adap->algo = &mtk_i2c_algo;
+ adap->retries = 3;
+ adap->dev.parent = &pdev->dev;
+ i2c_set_adapdata(adap, i2c);
+ adap->dev.of_node = pdev->dev.of_node;
+ strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name));
+
+ platform_set_drvdata(pdev, i2c);
+
+ mtk_i2c_init(i2c);
+
+ ret = i2c_add_adapter(adap);
+ if (ret < 0)
+ return ret;
+
+ dev_info(&pdev->dev, "clock %u kHz\n", i2c->bus_freq / 1000);
+
+ return ret;
+}
+
+static int mtk_i2c_remove(struct platform_device *pdev)
+{
+ struct mtk_i2c *i2c = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(i2c->clk);
+ i2c_del_adapter(&i2c->adap);
+
+ return 0;
+}
+
+static struct platform_driver mtk_i2c_driver = {
+ .probe = mtk_i2c_probe,
+ .remove = mtk_i2c_remove,
+ .driver = {
+ .name = "i2c-mt7621",
+ .of_match_table = i2c_mtk_dt_ids,
+ },
+};
+
+module_platform_driver(mtk_i2c_driver);
+
+MODULE_AUTHOR("Steven Liu");
+MODULE_DESCRIPTION("MT7621 I2C host driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:MT7621-I2C");
diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
index 4f30a43b63da..01a7d72e5511 100644
--- a/drivers/i2c/busses/i2c-nomadik.c
+++ b/drivers/i2c/busses/i2c-nomadik.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2009 ST-Ericsson SA
* Copyright (C) 2009 STMicroelectronics
@@ -7,10 +8,6 @@
*
* Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
* Author: Sachin Verma <sachin.verma@st.com>
- *
- * 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.
*/
#include <linux/init.h>
#include <linux/module.h>
diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c b/drivers/i2c/busses/i2c-nvidia-gpu.c
index 1c8f708f212b..cfc76b5de726 100644
--- a/drivers/i2c/busses/i2c-nvidia-gpu.c
+++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
@@ -51,6 +51,7 @@ struct gpu_i2c_dev {
void __iomem *regs;
struct i2c_adapter adapter;
struct i2c_board_info *gpu_ccgx_ucsi;
+ struct i2c_client *ccgx_client;
};
static void gpu_enable_i2c_bus(struct gpu_i2c_dev *i2cd)
@@ -169,12 +170,14 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
{
struct gpu_i2c_dev *i2cd = i2c_get_adapdata(adap);
int status, status2;
+ bool send_stop = true;
int i, j;
/*
* The controller supports maximum 4 byte read due to known
* limitation of sending STOP after every read.
*/
+ pm_runtime_get_sync(i2cd->dev);
for (i = 0; i < num; i++) {
if (msgs[i].flags & I2C_M_RD) {
/* program client address before starting read */
@@ -182,37 +185,42 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
/* gpu_i2c_read has implicit start */
status = gpu_i2c_read(i2cd, msgs[i].buf, msgs[i].len);
if (status < 0)
- goto stop;
+ goto exit;
} else {
u8 addr = i2c_8bit_addr_from_msg(msgs + i);
status = gpu_i2c_start(i2cd);
if (status < 0) {
if (i == 0)
- return status;
- goto stop;
+ send_stop = false;
+ goto exit;
}
status = gpu_i2c_write(i2cd, addr);
if (status < 0)
- goto stop;
+ goto exit;
for (j = 0; j < msgs[i].len; j++) {
status = gpu_i2c_write(i2cd, msgs[i].buf[j]);
if (status < 0)
- goto stop;
+ goto exit;
}
}
}
+ send_stop = false;
status = gpu_i2c_stop(i2cd);
if (status < 0)
- return status;
-
- return i;
-stop:
- status2 = gpu_i2c_stop(i2cd);
- if (status2 < 0)
- dev_err(i2cd->dev, "i2c stop failed %d\n", status2);
+ goto exit;
+
+ status = i;
+exit:
+ if (send_stop) {
+ status2 = gpu_i2c_stop(i2cd);
+ if (status2 < 0)
+ dev_err(i2cd->dev, "i2c stop failed %d\n", status2);
+ }
+ pm_runtime_mark_last_busy(i2cd->dev);
+ pm_runtime_put_autosuspend(i2cd->dev);
return status;
}
@@ -261,8 +269,6 @@ static const struct property_entry ccgx_props[] = {
static int gpu_populate_client(struct gpu_i2c_dev *i2cd, int irq)
{
- struct i2c_client *ccgx_client;
-
i2cd->gpu_ccgx_ucsi = devm_kzalloc(i2cd->dev,
sizeof(*i2cd->gpu_ccgx_ucsi),
GFP_KERNEL);
@@ -274,8 +280,8 @@ static int gpu_populate_client(struct gpu_i2c_dev *i2cd, int irq)
i2cd->gpu_ccgx_ucsi->addr = 0x8;
i2cd->gpu_ccgx_ucsi->irq = irq;
i2cd->gpu_ccgx_ucsi->properties = ccgx_props;
- ccgx_client = i2c_new_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi);
- if (!ccgx_client)
+ i2cd->ccgx_client = i2c_new_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi);
+ if (!i2cd->ccgx_client)
return -ENODEV;
return 0;
@@ -332,6 +338,11 @@ static int gpu_i2c_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto del_adapter;
}
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 3000);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_put_autosuspend(&pdev->dev);
+ pm_runtime_allow(&pdev->dev);
+
return 0;
del_adapter:
@@ -345,19 +356,38 @@ static void gpu_i2c_remove(struct pci_dev *pdev)
{
struct gpu_i2c_dev *i2cd = dev_get_drvdata(&pdev->dev);
+ pm_runtime_get_noresume(i2cd->dev);
i2c_del_adapter(&i2cd->adapter);
pci_free_irq_vectors(pdev);
}
+/*
+ * We need gpu_i2c_suspend() even if it is stub, for runtime pm to work
+ * correctly. Without it, lspci shows runtime pm status as "D0" for the card.
+ * Documentation/power/pci.txt also insists for driver to provide this.
+ */
+static __maybe_unused int gpu_i2c_suspend(struct device *dev)
+{
+ return 0;
+}
+
static __maybe_unused int gpu_i2c_resume(struct device *dev)
{
struct gpu_i2c_dev *i2cd = dev_get_drvdata(dev);
gpu_enable_i2c_bus(i2cd);
+ /*
+ * Runtime resume ccgx client so that it can see for any
+ * connector change event. Old ccg firmware has known
+ * issue of not triggering interrupt when a device is
+ * connected to runtime resume the controller.
+ */
+ pm_request_resume(&i2cd->ccgx_client->dev);
return 0;
}
-static UNIVERSAL_DEV_PM_OPS(gpu_i2c_driver_pm, NULL, gpu_i2c_resume, NULL);
+static UNIVERSAL_DEV_PM_OPS(gpu_i2c_driver_pm, gpu_i2c_suspend, gpu_i2c_resume,
+ NULL);
static struct pci_driver gpu_i2c_driver = {
.name = "nvidia-gpu",
diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index c3dabee0aa35..4117f1abc7c6 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -35,6 +35,7 @@ struct ocores_i2c {
int iobase;
u32 reg_shift;
u32 reg_io_width;
+ unsigned long flags;
wait_queue_head_t wait;
struct i2c_adapter adap;
struct i2c_msg *msg;
@@ -82,6 +83,9 @@ struct ocores_i2c {
#define TYPE_OCORES 0
#define TYPE_GRLIB 1
+#define TYPE_SIFIVE_REV0 2
+
+#define OCORES_FLAG_BROKEN_IRQ BIT(1) /* Broken IRQ for FU540-C000 SoC */
static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value)
{
@@ -235,9 +239,12 @@ static irqreturn_t ocores_isr(int irq, void *dev_id)
struct ocores_i2c *i2c = dev_id;
u8 stat = oc_getreg(i2c, OCI2C_STATUS);
- if (!(stat & OCI2C_STAT_IF))
+ if (i2c->flags & OCORES_FLAG_BROKEN_IRQ) {
+ if ((stat & OCI2C_STAT_IF) && !(stat & OCI2C_STAT_BUSY))
+ return IRQ_NONE;
+ } else if (!(stat & OCI2C_STAT_IF)) {
return IRQ_NONE;
-
+ }
ocores_process(i2c, stat);
return IRQ_HANDLED;
@@ -352,6 +359,11 @@ static void ocores_process_polling(struct ocores_i2c *i2c)
ret = ocores_isr(-1, i2c);
if (ret == IRQ_NONE)
break; /* all messages have been transferred */
+ else {
+ if (i2c->flags & OCORES_FLAG_BROKEN_IRQ)
+ if (i2c->state == STATE_DONE)
+ break;
+ }
}
}
@@ -462,6 +474,14 @@ static const struct of_device_id ocores_i2c_match[] = {
.compatible = "aeroflexgaisler,i2cmst",
.data = (void *)TYPE_GRLIB,
},
+ {
+ .compatible = "sifive,fu540-c000-i2c",
+ .data = (void *)TYPE_SIFIVE_REV0,
+ },
+ {
+ .compatible = "sifive,i2c0",
+ .data = (void *)TYPE_SIFIVE_REV0,
+ },
{},
};
MODULE_DEVICE_TABLE(of, ocores_i2c_match);
@@ -586,6 +606,7 @@ static int ocores_i2c_probe(struct platform_device *pdev)
{
struct ocores_i2c *i2c;
struct ocores_i2c_platform_data *pdata;
+ const struct of_device_id *match;
struct resource *res;
int irq;
int ret;
@@ -668,6 +689,14 @@ static int ocores_i2c_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq == -ENXIO) {
ocores_algorithm.master_xfer = ocores_xfer_polling;
+
+ /*
+ * Set in OCORES_FLAG_BROKEN_IRQ to enable workaround for
+ * FU540-C000 SoC in polling mode.
+ */
+ match = of_match_node(ocores_i2c_match, pdev->dev.of_node);
+ if (match && (long)match->data == TYPE_SIFIVE_REV0)
+ i2c->flags |= OCORES_FLAG_BROKEN_IRQ;
} else {
if (irq < 0)
return irq;
diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c
index f50afa8e3cba..a7a81846d5b1 100644
--- a/drivers/i2c/busses/i2c-pca-platform.c
+++ b/drivers/i2c/busses/i2c-pca-platform.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* i2c_pca_platform.c
*
@@ -5,9 +6,6 @@
*
* Copyright (C) 2008 Pengutronix
*
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/i2c/busses/i2c-puv3.c b/drivers/i2c/busses/i2c-puv3.c
index 287088b8c4c8..5cec5a36807d 100644
--- a/drivers/i2c/busses/i2c-puv3.c
+++ b/drivers/i2c/busses/i2c-puv3.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* I2C driver for PKUnity-v3 SoC
* Code specific to PKUnity SoC and UniCore ISA
*
* Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
* Copyright (C) 2001-2010 Guan Xuetao
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/i2c/busses/i2c-pxa-pci.c b/drivers/i2c/busses/i2c-pxa-pci.c
index 72ea8f4c61aa..f614cade432b 100644
--- a/drivers/i2c/busses/i2c-pxa-pci.c
+++ b/drivers/i2c/busses/i2c-pxa-pci.c
@@ -1,7 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* CE4100 PCI-I2C glue code for PXA's driver
* Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
- * License: GPL v2
*
* The CE4100's I2C device is more or less the same one as found on PXA.
* It does not support slave mode, the register slightly moved. This PCI
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index fbf91d383b40..2c3c3d6935c0 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* i2c_adap_pxa.c
*
@@ -6,10 +7,6 @@
* Copyright (C) 2002 Intrinsyc Software Inc.
* Copyright (C) 2004-2005 Deep Blue Solutions Ltd.
*
- * 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.
- *
* History:
* Apr 2002: Initial version [CS]
* Jun 2002: Properly separated algo/adap [FB]
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index db075bc0d952..a89bfce5388e 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+#include <linux/acpi.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
@@ -483,6 +484,14 @@ static const struct i2c_algorithm geni_i2c_algo = {
.functionality = geni_i2c_func,
};
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id geni_i2c_acpi_match[] = {
+ { "QCOM0220"},
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, geni_i2c_acpi_match);
+#endif
+
static int geni_i2c_probe(struct platform_device *pdev)
{
struct geni_i2c_dev *gi2c;
@@ -502,7 +511,7 @@ static int geni_i2c_probe(struct platform_device *pdev)
return PTR_ERR(gi2c->se.base);
gi2c->se.clk = devm_clk_get(&pdev->dev, "se");
- if (IS_ERR(gi2c->se.clk)) {
+ if (IS_ERR(gi2c->se.clk) && !has_acpi_companion(&pdev->dev)) {
ret = PTR_ERR(gi2c->se.clk);
dev_err(&pdev->dev, "Err getting SE Core clk %d\n", ret);
return ret;
@@ -516,6 +525,9 @@ static int geni_i2c_probe(struct platform_device *pdev)
gi2c->clk_freq_out = KHZ(100);
}
+ if (has_acpi_companion(&pdev->dev))
+ ACPI_COMPANION_SET(&gi2c->adap.dev, ACPI_COMPANION(&pdev->dev));
+
gi2c->irq = platform_get_irq(pdev, 0);
if (gi2c->irq < 0) {
dev_err(&pdev->dev, "IRQ error for i2c-geni\n");
@@ -584,6 +596,8 @@ static int geni_i2c_probe(struct platform_device *pdev)
return ret;
}
+ dev_dbg(&pdev->dev, "Geni-I2C adaptor successfully added\n");
+
return 0;
}
@@ -660,6 +674,7 @@ static struct platform_driver geni_i2c_driver = {
.name = "geni_i2c",
.pm = &geni_i2c_pm_ops,
.of_match_table = geni_i2c_dt_match,
+ .acpi_match_table = ACPI_PTR(geni_i2c_acpi_match),
},
};
diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index b8a2728dd4b6..1a33007b03e9 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for I2C adapter in Rockchip RK3xxx SoC
*
* Max Schwarz <max.schwarz@online.de>
* based on the patches by Rockchip 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index c9510d085c34..d97fb857b0ea 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -24,7 +24,7 @@
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/pinctrl/consumer.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
@@ -113,7 +113,7 @@ struct s3c24xx_i2c {
struct i2c_adapter adap;
struct s3c2410_platform_i2c *pdata;
- int gpios[2];
+ struct gpio_desc *gpios[2];
struct pinctrl *pctrl;
#if defined(CONFIG_ARM_S3C24XX_CPUFREQ)
struct notifier_block freq_transition;
@@ -947,53 +947,27 @@ static inline void s3c24xx_i2c_deregister_cpufreq(struct s3c24xx_i2c *i2c)
#ifdef CONFIG_OF
static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c)
{
- int idx, gpio, ret;
+ int i;
if (i2c->quirks & QUIRK_NO_GPIO)
return 0;
- for (idx = 0; idx < 2; idx++) {
- gpio = of_get_gpio(i2c->dev->of_node, idx);
- if (!gpio_is_valid(gpio)) {
- dev_err(i2c->dev, "invalid gpio[%d]: %d\n", idx, gpio);
- goto free_gpio;
- }
- i2c->gpios[idx] = gpio;
-
- ret = gpio_request(gpio, "i2c-bus");
- if (ret) {
- dev_err(i2c->dev, "gpio [%d] request failed (%d)\n",
- gpio, ret);
- goto free_gpio;
+ for (i = 0; i < 2; i++) {
+ i2c->gpios[i] = devm_gpiod_get_index(i2c->dev, NULL,
+ i, GPIOD_ASIS);
+ if (IS_ERR(i2c->gpios[i])) {
+ dev_err(i2c->dev, "i2c gpio invalid at index %d\n", i);
+ return -EINVAL;
}
}
return 0;
-
-free_gpio:
- while (--idx >= 0)
- gpio_free(i2c->gpios[idx]);
- return -EINVAL;
}
-static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c)
-{
- unsigned int idx;
-
- if (i2c->quirks & QUIRK_NO_GPIO)
- return;
-
- for (idx = 0; idx < 2; idx++)
- gpio_free(i2c->gpios[idx]);
-}
#else
static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c)
{
return 0;
}
-
-static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c)
-{
-}
#endif
/*
@@ -1222,9 +1196,6 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev)
i2c_del_adapter(&i2c->adap);
- if (pdev->dev.of_node && IS_ERR(i2c->pctrl))
- s3c24xx_i2c_dt_gpio_free(i2c);
-
return 0;
}
diff --git a/drivers/i2c/busses/i2c-simtec.c b/drivers/i2c/busses/i2c-simtec.c
index adca51a99487..458c7bcf1d24 100644
--- a/drivers/i2c/busses/i2c-simtec.c
+++ b/drivers/i2c/busses/i2c-simtec.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2005 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* Simtec Generic I2C Controller
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/kernel.h>
diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c
index 9e62f893958a..54e1fc8a495e 100644
--- a/drivers/i2c/busses/i2c-st.c
+++ b/drivers/i2c/busses/i2c-st.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 STMicroelectronics
*
* I2C master mode controller driver, used in STMicroelectronics devices.
*
* Author: Maxime Coquelin <maxime.coquelin@st.com>
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c
index 48337bef5b87..266d1c269b83 100644
--- a/drivers/i2c/busses/i2c-stm32f7.c
+++ b/drivers/i2c/busses/i2c-stm32f7.c
@@ -25,7 +25,6 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/consumer.h>
@@ -953,6 +952,9 @@ static int stm32f7_i2c_smbus_xfer_msg(struct stm32f7_i2c_dev *i2c_dev,
cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
f7_msg->read_write = I2C_SMBUS_READ;
break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ /* Rely on emulated i2c transfer (through master_xfer) */
+ return -EOPNOTSUPP;
default:
dev_err(dev, "Unsupported smbus protocol %d\n", f7_msg->size);
return -EOPNOTSUPP;
@@ -1803,7 +1805,8 @@ static u32 stm32f7_i2c_func(struct i2c_adapter *adap)
I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
- I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_PEC;
+ I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_PEC |
+ I2C_FUNC_SMBUS_I2C_BLOCK;
}
static struct i2c_algorithm stm32f7_i2c_algo = {
@@ -1816,15 +1819,14 @@ static struct i2c_algorithm stm32f7_i2c_algo = {
static int stm32f7_i2c_probe(struct platform_device *pdev)
{
- struct device_node *np = pdev->dev.of_node;
struct stm32f7_i2c_dev *i2c_dev;
const struct stm32f7_i2c_setup *setup;
struct resource *res;
- u32 irq_error, irq_event, clk_rate, rise_time, fall_time;
+ u32 clk_rate, rise_time, fall_time;
struct i2c_adapter *adap;
struct reset_control *rst;
dma_addr_t phy_addr;
- int ret;
+ int irq_error, irq_event, ret;
i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
if (!i2c_dev)
@@ -1836,16 +1838,20 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
return PTR_ERR(i2c_dev->base);
phy_addr = (dma_addr_t)res->start;
- irq_event = irq_of_parse_and_map(np, 0);
- if (!irq_event) {
- dev_err(&pdev->dev, "IRQ event missing or invalid\n");
- return -EINVAL;
+ irq_event = platform_get_irq(pdev, 0);
+ if (irq_event <= 0) {
+ if (irq_event != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Failed to get IRQ event: %d\n",
+ irq_event);
+ return irq_event ? : -ENOENT;
}
- irq_error = irq_of_parse_and_map(np, 1);
- if (!irq_error) {
- dev_err(&pdev->dev, "IRQ error missing or invalid\n");
- return -EINVAL;
+ irq_error = platform_get_irq(pdev, 1);
+ if (irq_error <= 0) {
+ if (irq_error != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Failed to get IRQ error: %d\n",
+ irq_error);
+ return irq_error ? : -ENOENT;
}
i2c_dev->clk = devm_clk_get(&pdev->dev, NULL);
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index ebaa78d17d6e..9fcb13beeb8f 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -54,20 +54,15 @@
#define I2C_INT_STATUS 0x068
#define I2C_INT_BUS_CLR_DONE BIT(11)
#define I2C_INT_PACKET_XFER_COMPLETE BIT(7)
-#define I2C_INT_ALL_PACKETS_XFER_COMPLETE BIT(6)
-#define I2C_INT_TX_FIFO_OVERFLOW BIT(5)
-#define I2C_INT_RX_FIFO_UNDERFLOW BIT(4)
#define I2C_INT_NO_ACK BIT(3)
#define I2C_INT_ARBITRATION_LOST BIT(2)
#define I2C_INT_TX_FIFO_DATA_REQ BIT(1)
#define I2C_INT_RX_FIFO_DATA_REQ BIT(0)
#define I2C_CLK_DIVISOR 0x06c
#define I2C_CLK_DIVISOR_STD_FAST_MODE_SHIFT 16
-#define I2C_CLK_MULTIPLIER_STD_FAST_MODE 8
#define DVC_CTRL_REG1 0x000
#define DVC_CTRL_REG1_INTR_EN BIT(10)
-#define DVC_CTRL_REG2 0x004
#define DVC_CTRL_REG3 0x008
#define DVC_CTRL_REG3_SW_PROG BIT(26)
#define DVC_CTRL_REG3_I2C_DONE_INTR_EN BIT(30)
@@ -75,24 +70,22 @@
#define DVC_STATUS_I2C_DONE_INTR BIT(30)
#define I2C_ERR_NONE 0x00
-#define I2C_ERR_NO_ACK 0x01
-#define I2C_ERR_ARBITRATION_LOST 0x02
-#define I2C_ERR_UNKNOWN_INTERRUPT 0x04
+#define I2C_ERR_NO_ACK BIT(0)
+#define I2C_ERR_ARBITRATION_LOST BIT(1)
+#define I2C_ERR_UNKNOWN_INTERRUPT BIT(2)
+#define I2C_ERR_RX_BUFFER_OVERFLOW BIT(3)
#define PACKET_HEADER0_HEADER_SIZE_SHIFT 28
#define PACKET_HEADER0_PACKET_ID_SHIFT 16
#define PACKET_HEADER0_CONT_ID_SHIFT 12
#define PACKET_HEADER0_PROTOCOL_I2C BIT(4)
-#define I2C_HEADER_HIGHSPEED_MODE BIT(22)
#define I2C_HEADER_CONT_ON_NAK BIT(21)
-#define I2C_HEADER_SEND_START_BYTE BIT(20)
#define I2C_HEADER_READ BIT(19)
#define I2C_HEADER_10BIT_ADDR BIT(18)
#define I2C_HEADER_IE_ENABLE BIT(17)
#define I2C_HEADER_REPEAT_START BIT(16)
#define I2C_HEADER_CONTINUE_XFER BIT(15)
-#define I2C_HEADER_MASTER_ADDR_SHIFT 12
#define I2C_HEADER_SLAVE_ADDR_SHIFT 1
#define I2C_BUS_CLEAR_CNFG 0x084
@@ -106,8 +99,6 @@
#define I2C_CONFIG_LOAD 0x08C
#define I2C_MSTR_CONFIG_LOAD BIT(0)
-#define I2C_SLV_CONFIG_LOAD BIT(1)
-#define I2C_TIMEOUT_CONFIG_LOAD BIT(2)
#define I2C_CLKEN_OVERRIDE 0x090
#define I2C_MST_CORE_CLKEN_OVR BIT(0)
@@ -133,7 +124,6 @@
#define I2C_STANDARD_MODE 100000
#define I2C_FAST_MODE 400000
#define I2C_FAST_PLUS_MODE 1000000
-#define I2C_HS_MODE 3500000
/* Packet header size in bytes */
#define I2C_PACKET_HEADER_SIZE 12
@@ -280,6 +270,7 @@ struct tegra_i2c_dev {
u32 bus_clk_rate;
u16 clk_divisor_non_hs_mode;
bool is_multimaster_mode;
+ /* xfer_lock: lock to serialize transfer submission and processing */
spinlock_t xfer_lock;
struct dma_chan *tx_dma_chan;
struct dma_chan *rx_dma_chan;
@@ -306,7 +297,7 @@ static u32 dvc_readl(struct tegra_i2c_dev *i2c_dev, unsigned long reg)
* to the I2C block inside the DVC block
*/
static unsigned long tegra_i2c_reg_addr(struct tegra_i2c_dev *i2c_dev,
- unsigned long reg)
+ unsigned long reg)
{
if (i2c_dev->is_dvc)
reg += (reg >= I2C_TX_FIFO) ? 0x10 : 0x40;
@@ -314,7 +305,7 @@ static unsigned long tegra_i2c_reg_addr(struct tegra_i2c_dev *i2c_dev,
}
static void i2c_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
- unsigned long reg)
+ unsigned long reg)
{
writel(val, i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
@@ -329,13 +320,13 @@ static u32 i2c_readl(struct tegra_i2c_dev *i2c_dev, unsigned long reg)
}
static void i2c_writesl(struct tegra_i2c_dev *i2c_dev, void *data,
- unsigned long reg, int len)
+ unsigned long reg, int len)
{
writesl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg), data, len);
}
static void i2c_readsl(struct tegra_i2c_dev *i2c_dev, void *data,
- unsigned long reg, int len)
+ unsigned long reg, int len)
{
readsl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg), data, len);
}
@@ -486,7 +477,7 @@ static int tegra_i2c_flush_fifos(struct tegra_i2c_dev *i2c_dev)
dev_warn(i2c_dev->dev, "timeout waiting for fifo flush\n");
return -ETIMEDOUT;
}
- msleep(1);
+ usleep_range(1000, 2000);
}
return 0;
}
@@ -499,6 +490,13 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev)
size_t buf_remaining = i2c_dev->msg_buf_remaining;
int words_to_transfer;
+ /*
+ * Catch overflow due to message fully sent
+ * before the check for RX FIFO availability.
+ */
+ if (WARN_ON_ONCE(!(i2c_dev->msg_buf_remaining)))
+ return -EINVAL;
+
if (i2c_dev->hw->has_mst_fifo) {
val = i2c_readl(i2c_dev, I2C_MST_FIFO_STATUS);
rx_fifo_avail = (val & I2C_MST_FIFO_STATUS_RX_MASK) >>
@@ -525,7 +523,11 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev)
* prevent overwriting past the end of buf
*/
if (rx_fifo_avail > 0 && buf_remaining > 0) {
- BUG_ON(buf_remaining > 3);
+ /*
+ * buf_remaining > 3 check not needed as rx_fifo_avail == 0
+ * when (words_to_transfer was > rx_fifo_avail) earlier
+ * in this function.
+ */
val = i2c_readl(i2c_dev, I2C_RX_FIFO);
val = cpu_to_le32(val);
memcpy(buf, &val, buf_remaining);
@@ -533,7 +535,10 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev)
rx_fifo_avail--;
}
- BUG_ON(rx_fifo_avail > 0 && buf_remaining > 0);
+ /* RX FIFO must be drained, otherwise it's an Overflow case. */
+ if (WARN_ON_ONCE(rx_fifo_avail))
+ return -EINVAL;
+
i2c_dev->msg_buf_remaining = buf_remaining;
i2c_dev->msg_buf = buf;
@@ -591,7 +596,11 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
* boundary and fault.
*/
if (tx_fifo_avail > 0 && buf_remaining > 0) {
- BUG_ON(buf_remaining > 3);
+ /*
+ * buf_remaining > 3 check not needed as tx_fifo_avail == 0
+ * when (words_to_transfer was > tx_fifo_avail) earlier
+ * in this function for non-zero words_to_transfer.
+ */
memcpy(&val, buf, buf_remaining);
val = le32_to_cpu(val);
@@ -680,10 +689,11 @@ static int tegra_i2c_wait_for_config_load(struct tegra_i2c_dev *i2c_dev)
i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD, I2C_CONFIG_LOAD);
if (in_interrupt())
err = readl_poll_timeout_atomic(addr, val, val == 0,
- 1000, I2C_CONFIG_LOAD_TIMEOUT);
+ 1000,
+ I2C_CONFIG_LOAD_TIMEOUT);
else
- err = readl_poll_timeout(addr, val, val == 0,
- 1000, I2C_CONFIG_LOAD_TIMEOUT);
+ err = readl_poll_timeout(addr, val, val == 0, 1000,
+ I2C_CONFIG_LOAD_TIMEOUT);
if (err) {
dev_warn(i2c_dev->dev,
@@ -700,7 +710,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev, bool clk_reinit)
u32 val;
int err;
u32 clk_divisor, clk_multiplier;
- u32 tsu_thd = 0;
+ u32 tsu_thd;
u8 tlow, thigh;
err = pm_runtime_get_sync(i2c_dev->dev);
@@ -856,10 +866,15 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
if (!i2c_dev->is_curr_dma_xfer) {
if (i2c_dev->msg_read && (status & I2C_INT_RX_FIFO_DATA_REQ)) {
- if (i2c_dev->msg_buf_remaining)
- tegra_i2c_empty_rx_fifo(i2c_dev);
- else
- BUG();
+ if (tegra_i2c_empty_rx_fifo(i2c_dev)) {
+ /*
+ * Overflow error condition: message fully sent,
+ * with no XFER_COMPLETE interrupt but hardware
+ * asks to transfer more.
+ */
+ i2c_dev->msg_err |= I2C_ERR_RX_BUFFER_OVERFLOW;
+ goto err;
+ }
}
if (!i2c_dev->msg_read && (status & I2C_INT_TX_FIFO_DATA_REQ)) {
@@ -885,7 +900,14 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
if (status & I2C_INT_PACKET_XFER_COMPLETE) {
if (i2c_dev->is_curr_dma_xfer)
i2c_dev->msg_buf_remaining = 0;
- BUG_ON(i2c_dev->msg_buf_remaining);
+ /*
+ * Underflow error condition: XFER_COMPLETE before message
+ * fully sent.
+ */
+ if (WARN_ON_ONCE(i2c_dev->msg_buf_remaining)) {
+ i2c_dev->msg_err |= I2C_ERR_UNKNOWN_INTERRUPT;
+ goto err;
+ }
complete(&i2c_dev->msg_complete);
}
goto done;
@@ -1024,7 +1046,8 @@ static int tegra_i2c_issue_bus_clear(struct i2c_adapter *adap)
}
static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
- struct i2c_msg *msg, enum msg_end_type end_state)
+ struct i2c_msg *msg,
+ enum msg_end_type end_state)
{
u32 packet_header;
u32 int_mask;
@@ -1161,9 +1184,8 @@ unlock:
if (err)
return err;
- time_left = wait_for_completion_timeout(
- &i2c_dev->dma_complete,
- msecs_to_jiffies(xfer_time));
+ time_left = wait_for_completion_timeout(&i2c_dev->dma_complete,
+ msecs_to_jiffies(xfer_time));
if (time_left == 0) {
dev_err(i2c_dev->dev, "DMA transfer timeout\n");
dmaengine_terminate_sync(i2c_dev->msg_read ?
@@ -1225,11 +1247,11 @@ unlock:
}
static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
- int num)
+ int num)
{
struct tegra_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
int i;
- int ret = 0;
+ int ret;
ret = pm_runtime_get_sync(i2c_dev->dev);
if (ret < 0) {
@@ -1271,14 +1293,15 @@ static void tegra_i2c_parse_dt(struct tegra_i2c_dev *i2c_dev)
{
struct device_node *np = i2c_dev->dev->of_node;
int ret;
+ bool multi_mode;
ret = of_property_read_u32(np, "clock-frequency",
- &i2c_dev->bus_clk_rate);
+ &i2c_dev->bus_clk_rate);
if (ret)
i2c_dev->bus_clk_rate = 100000; /* default clock rate */
- i2c_dev->is_multimaster_mode = of_property_read_bool(np,
- "multi-master");
+ multi_mode = of_property_read_bool(np, "multi-master");
+ i2c_dev->is_multimaster_mode = multi_mode;
}
static const struct i2c_algorithm tegra_i2c_algo = {
@@ -1500,7 +1523,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
void __iomem *base;
phys_addr_t base_phys;
int irq;
- int ret = 0;
+ int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base_phys = res->start;
@@ -1517,7 +1540,9 @@ static int tegra_i2c_probe(struct platform_device *pdev)
div_clk = devm_clk_get(&pdev->dev, "div-clk");
if (IS_ERR(div_clk)) {
- dev_err(&pdev->dev, "missing controller clock\n");
+ if (PTR_ERR(div_clk) != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "missing controller clock\n");
+
return PTR_ERR(div_clk);
}
@@ -1622,7 +1647,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
}
ret = devm_request_irq(&pdev->dev, i2c_dev->irq,
- tegra_i2c_isr, 0, dev_name(&pdev->dev), i2c_dev);
+ tegra_i2c_isr, 0, dev_name(&pdev->dev), i2c_dev);
if (ret) {
dev_err(&pdev->dev, "Failed to request irq %i\n", i2c_dev->irq);
goto release_dma;
@@ -1687,10 +1712,35 @@ static int tegra_i2c_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM_SLEEP
+static int tegra_i2c_suspend(struct device *dev)
+{
+ struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
+
+ i2c_mark_adapter_suspended(&i2c_dev->adapter);
+
+ return 0;
+}
+
+static int tegra_i2c_resume(struct device *dev)
+{
+ struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
+ int err;
+
+ err = tegra_i2c_init(i2c_dev, false);
+ if (err)
+ return err;
+
+ i2c_mark_adapter_resumed(&i2c_dev->adapter);
+
+ return 0;
+}
+
static const struct dev_pm_ops tegra_i2c_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(tegra_i2c_suspend, tegra_i2c_resume)
SET_RUNTIME_PM_OPS(tegra_i2c_runtime_suspend, tegra_i2c_runtime_resume,
NULL)
};
+
#define TEGRA_I2C_PM (&tegra_i2c_pm)
#else
#define TEGRA_I2C_PM NULL
diff --git a/drivers/i2c/busses/i2c-versatile.c b/drivers/i2c/busses/i2c-versatile.c
index f1ab2a637ec0..8d980b1374a8 100644
--- a/drivers/i2c/busses/i2c-versatile.c
+++ b/drivers/i2c/busses/i2c-versatile.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* i2c-versatile.c
*
* Copyright (C) 2006 ARM Ltd.
* written by Russell King, Deep Blue Solutions Ltd.
- *
- * 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.
*/
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/i2c/busses/i2c-zx2967.c b/drivers/i2c/busses/i2c-zx2967.c
index 7b98d97da3c6..5f3318559b8d 100644
--- a/drivers/i2c/busses/i2c-zx2967.c
+++ b/drivers/i2c/busses/i2c-zx2967.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2017 Sanechips Technology Co., Ltd.
* Copyright 2017 Linaro Ltd.
*
* Author: Baoyou Xie <baoyou.xie@linaro.org>
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c
index d84095591e45..4dbbc9a35f65 100644
--- a/drivers/i2c/i2c-core-acpi.c
+++ b/drivers/i2c/i2c-core-acpi.c
@@ -111,8 +111,7 @@ static int i2c_acpi_do_lookup(struct acpi_device *adev,
struct list_head resource_list;
int ret;
- if (acpi_bus_get_status(adev) || !adev->status.present ||
- acpi_device_enumerated(adev))
+ if (acpi_bus_get_status(adev) || !adev->status.present)
return -EINVAL;
if (acpi_match_device_ids(adev, i2c_acpi_ignored_device_ids) == 0)
@@ -133,13 +132,52 @@ static int i2c_acpi_do_lookup(struct acpi_device *adev,
return 0;
}
+static int i2c_acpi_add_resource(struct acpi_resource *ares, void *data)
+{
+ int *irq = data;
+ struct resource r;
+
+ if (*irq <= 0 && acpi_dev_resource_interrupt(ares, 0, &r))
+ *irq = i2c_dev_irq_from_resources(&r, 1);
+
+ return 1; /* No need to add resource to the list */
+}
+
+/**
+ * i2c_acpi_get_irq - get device IRQ number from ACPI
+ * @client: Pointer to the I2C client device
+ *
+ * Find the IRQ number used by a specific client device.
+ *
+ * Return: The IRQ number or an error code.
+ */
+int i2c_acpi_get_irq(struct i2c_client *client)
+{
+ struct acpi_device *adev = ACPI_COMPANION(&client->dev);
+ struct list_head resource_list;
+ int irq = -ENOENT;
+ int ret;
+
+ INIT_LIST_HEAD(&resource_list);
+
+ ret = acpi_dev_get_resources(adev, &resource_list,
+ i2c_acpi_add_resource, &irq);
+ if (ret < 0)
+ return ret;
+
+ acpi_dev_free_resource_list(&resource_list);
+
+ if (irq == -ENOENT)
+ irq = acpi_dev_gpio_irq_get(adev, 0);
+
+ return irq;
+}
+
static int i2c_acpi_get_info(struct acpi_device *adev,
struct i2c_board_info *info,
struct i2c_adapter *adapter,
acpi_handle *adapter_handle)
{
- struct list_head resource_list;
- struct resource_entry *entry;
struct i2c_acpi_lookup lookup;
int ret;
@@ -147,6 +185,9 @@ static int i2c_acpi_get_info(struct acpi_device *adev,
lookup.info = info;
lookup.index = -1;
+ if (acpi_device_enumerated(adev))
+ return -EINVAL;
+
ret = i2c_acpi_do_lookup(adev, &lookup);
if (ret)
return ret;
@@ -170,21 +211,6 @@ static int i2c_acpi_get_info(struct acpi_device *adev,
if (adapter_handle)
*adapter_handle = lookup.adapter_handle;
- /* Then fill IRQ number if any */
- INIT_LIST_HEAD(&resource_list);
- ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
- if (ret < 0)
- return -EINVAL;
-
- resource_list_for_each_entry(entry, &resource_list) {
- if (resource_type(entry->res) == IORESOURCE_IRQ) {
- info->irq = entry->res->start;
- break;
- }
- }
-
- acpi_dev_free_resource_list(&resource_list);
-
acpi_set_modalias(adev, dev_name(&adev->dev), info->type,
sizeof(info->type));
@@ -318,7 +344,7 @@ u32 i2c_acpi_find_bus_speed(struct device *dev)
}
EXPORT_SYMBOL_GPL(i2c_acpi_find_bus_speed);
-static int i2c_acpi_find_match_adapter(struct device *dev, void *data)
+static int i2c_acpi_find_match_adapter(struct device *dev, const void *data)
{
struct i2c_adapter *adapter = i2c_verify_adapter(dev);
@@ -328,12 +354,12 @@ static int i2c_acpi_find_match_adapter(struct device *dev, void *data)
return ACPI_HANDLE(dev) == (acpi_handle)data;
}
-static int i2c_acpi_find_match_device(struct device *dev, void *data)
+static int i2c_acpi_find_match_device(struct device *dev, const void *data)
{
return ACPI_COMPANION(dev) == data;
}
-static struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle handle)
+struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle handle)
{
struct device *dev;
@@ -341,6 +367,7 @@ static struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle handle)
i2c_acpi_find_match_adapter);
return dev ? i2c_verify_adapter(dev) : NULL;
}
+EXPORT_SYMBOL_GPL(i2c_acpi_find_adapter_by_handle);
static struct i2c_client *i2c_acpi_find_client_by_adev(struct acpi_device *adev)
{
diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
index 9e43508d4567..f26ed495d384 100644
--- a/drivers/i2c/i2c-core-base.c
+++ b/drivers/i2c/i2c-core-base.c
@@ -314,6 +314,8 @@ static int i2c_device_probe(struct device *dev)
driver = to_i2c_driver(dev->driver);
+ client->irq = client->init_irq;
+
if (!client->irq && !driver->disable_i2c_core_irq_mapping) {
int irq = -ENOENT;
@@ -327,7 +329,7 @@ static int i2c_device_probe(struct device *dev)
if (irq == -EINVAL || irq == -ENODATA)
irq = of_irq_get(dev->of_node, 0);
} else if (ACPI_COMPANION(dev)) {
- irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 0);
+ irq = i2c_acpi_get_irq(client);
}
if (irq == -EPROBE_DEFER)
return irq;
@@ -424,7 +426,7 @@ static int i2c_device_remove(struct device *dev)
dev_pm_clear_wake_irq(&client->dev);
device_init_wakeup(&client->dev, false);
- client->irq = client->init_irq;
+ client->irq = 0;
if (client->flags & I2C_CLIENT_HOST_NOTIFY)
pm_runtime_put(&client->adapter->dev);
@@ -679,8 +681,8 @@ static void i2c_dev_set_name(struct i2c_adapter *adap,
i2c_encode_flags_to_addr(client));
}
-static int i2c_dev_irq_from_resources(const struct resource *resources,
- unsigned int num_resources)
+int i2c_dev_irq_from_resources(const struct resource *resources,
+ unsigned int num_resources)
{
struct irq_data *irqd;
int i;
@@ -721,7 +723,7 @@ static int i2c_dev_irq_from_resources(const struct resource *resources,
* This returns the new i2c client, which may be saved for later use with
* i2c_unregister_device(); or an ERR_PTR to describe the error.
*/
-static struct i2c_client *
+struct i2c_client *
i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
{
struct i2c_client *client;
@@ -741,7 +743,6 @@ i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *inf
if (!client->init_irq)
client->init_irq = i2c_dev_irq_from_resources(info->resources,
info->num_resources);
- client->irq = client->init_irq;
strlcpy(client->name, info->type, sizeof(client->name));
@@ -887,8 +888,7 @@ static struct i2c_driver dummy_driver = {
* This returns the new i2c client, which should be saved for later use with
* i2c_unregister_device(); or an ERR_PTR to describe the error.
*/
-static struct i2c_client *
-i2c_new_dummy_device(struct i2c_adapter *adapter, u16 address)
+struct i2c_client *i2c_new_dummy_device(struct i2c_adapter *adapter, u16 address)
{
struct i2c_board_info info = {
I2C_BOARD_INFO("dummy", address),
@@ -1663,7 +1663,7 @@ EXPORT_SYMBOL_GPL(i2c_parse_fw_timings);
/* ------------------------------------------------------------------------- */
-int i2c_for_each_dev(void *data, int (*fn)(struct device *, void *))
+int i2c_for_each_dev(void *data, int (*fn)(struct device *dev, void *data))
{
int res;
@@ -2276,7 +2276,7 @@ struct i2c_client *
i2c_new_probed_device(struct i2c_adapter *adap,
struct i2c_board_info *info,
unsigned short const *addr_list,
- int (*probe)(struct i2c_adapter *, unsigned short addr))
+ int (*probe)(struct i2c_adapter *adap, unsigned short addr))
{
int i;
diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c
index 406e5f695a7e..d1c48dec7118 100644
--- a/drivers/i2c/i2c-core-of.c
+++ b/drivers/i2c/i2c-core-of.c
@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/sysfs.h>
#include "i2c-core.h"
@@ -112,12 +113,12 @@ void of_i2c_register_devices(struct i2c_adapter *adap)
of_node_put(bus);
}
-static int of_dev_node_match(struct device *dev, void *data)
+static int of_dev_node_match(struct device *dev, const void *data)
{
return dev->of_node == data;
}
-static int of_dev_or_parent_node_match(struct device *dev, void *data)
+static int of_dev_or_parent_node_match(struct device *dev, const void *data)
{
if (dev->of_node == data)
return 1;
diff --git a/drivers/i2c/i2c-core.h b/drivers/i2c/i2c-core.h
index 851c11b4c0f3..517d98be68d2 100644
--- a/drivers/i2c/i2c-core.h
+++ b/drivers/i2c/i2c-core.h
@@ -19,6 +19,8 @@ extern struct list_head __i2c_board_list;
extern int __i2c_first_dynamic_bus_num;
int i2c_check_7bit_addr_validity_strict(unsigned short addr);
+int i2c_dev_irq_from_resources(const struct resource *resources,
+ unsigned int num_resources);
/*
* We only allow atomic transfers for very late communication, e.g. to send
@@ -61,6 +63,8 @@ const struct acpi_device_id *
i2c_acpi_match_device(const struct acpi_device_id *matches,
struct i2c_client *client);
void i2c_acpi_register_devices(struct i2c_adapter *adap);
+
+int i2c_acpi_get_irq(struct i2c_client *client);
#else /* CONFIG_ACPI */
static inline void i2c_acpi_register_devices(struct i2c_adapter *adap) { }
static inline const struct acpi_device_id *
@@ -69,6 +73,11 @@ i2c_acpi_match_device(const struct acpi_device_id *matches,
{
return NULL;
}
+
+static inline int i2c_acpi_get_irq(struct i2c_client *client)
+{
+ return 0;
+}
#endif /* CONFIG_ACPI */
extern struct notifier_block i2c_acpi_notifier;
diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index 603252fa1284..774507b54b57 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -26,6 +26,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/slab.h>
+#include <linux/sysfs.h>
/* multiplexer per channel data */
struct i2c_mux_priv {
@@ -243,8 +244,7 @@ struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent,
{
struct i2c_mux_core *muxc;
- muxc = devm_kzalloc(dev, sizeof(*muxc)
- + max_adapters * sizeof(muxc->adapter[0])
+ muxc = devm_kzalloc(dev, struct_size(muxc, adapter, max_adapters)
+ sizeof_priv, GFP_KERNEL);
if (!muxc)
return NULL;
diff --git a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
index 255c598dcfc8..6dc88902c189 100644
--- a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
+++ b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
@@ -6,12 +6,11 @@
*/
#include <linux/delay.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include <linux/module.h>
-#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -19,22 +18,16 @@
/**
* struct i2c_arbitrator_data - Driver data for I2C arbitrator
*
- * @our_gpio: GPIO we'll use to claim.
- * @our_gpio_release: 0 if active high; 1 if active low; AKA if the GPIO ==
- * this then consider it released.
- * @their_gpio: GPIO that the other side will use to claim.
- * @their_gpio_release: 0 if active high; 1 if active low; AKA if the GPIO ==
- * this then consider it released.
+ * @our_gpio: GPIO descriptor we'll use to claim.
+ * @their_gpio: GPIO descriptor that the other side will use to claim.
* @slew_delay_us: microseconds to wait for a GPIO to go high.
* @wait_retry_us: we'll attempt another claim after this many microseconds.
* @wait_free_us: we'll give up after this many microseconds.
*/
struct i2c_arbitrator_data {
- int our_gpio;
- int our_gpio_release;
- int their_gpio;
- int their_gpio_release;
+ struct gpio_desc *our_gpio;
+ struct gpio_desc *their_gpio;
unsigned int slew_delay_us;
unsigned int wait_retry_us;
unsigned int wait_free_us;
@@ -55,15 +48,15 @@ static int i2c_arbitrator_select(struct i2c_mux_core *muxc, u32 chan)
stop_time = jiffies + usecs_to_jiffies(arb->wait_free_us) + 1;
do {
/* Indicate that we want to claim the bus */
- gpio_set_value(arb->our_gpio, !arb->our_gpio_release);
+ gpiod_set_value(arb->our_gpio, 1);
udelay(arb->slew_delay_us);
/* Wait for the other master to release it */
stop_retry = jiffies + usecs_to_jiffies(arb->wait_retry_us) + 1;
while (time_before(jiffies, stop_retry)) {
- int gpio_val = !!gpio_get_value(arb->their_gpio);
+ int gpio_val = gpiod_get_value(arb->their_gpio);
- if (gpio_val == arb->their_gpio_release) {
+ if (!gpio_val) {
/* We got it, so return */
return 0;
}
@@ -72,13 +65,13 @@ static int i2c_arbitrator_select(struct i2c_mux_core *muxc, u32 chan)
}
/* It didn't release, so give up, wait, and try again */
- gpio_set_value(arb->our_gpio, arb->our_gpio_release);
+ gpiod_set_value(arb->our_gpio, 0);
usleep_range(arb->wait_retry_us, arb->wait_retry_us * 2);
} while (time_before(jiffies, stop_time));
/* Give up, release our claim */
- gpio_set_value(arb->our_gpio, arb->our_gpio_release);
+ gpiod_set_value(arb->our_gpio, 0);
udelay(arb->slew_delay_us);
dev_err(muxc->dev, "Could not claim bus, timeout\n");
return -EBUSY;
@@ -94,7 +87,7 @@ static int i2c_arbitrator_deselect(struct i2c_mux_core *muxc, u32 chan)
const struct i2c_arbitrator_data *arb = i2c_mux_priv(muxc);
/* Release the bus and wait for the other master to notice */
- gpio_set_value(arb->our_gpio, arb->our_gpio_release);
+ gpiod_set_value(arb->our_gpio, 0);
udelay(arb->slew_delay_us);
return 0;
@@ -107,8 +100,7 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
struct device_node *parent_np;
struct i2c_mux_core *muxc;
struct i2c_arbitrator_data *arb;
- enum of_gpio_flags gpio_flags;
- unsigned long out_init;
+ struct gpio_desc *dummy;
int ret;
/* We only support probing from device tree; no platform_data */
@@ -129,45 +121,28 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, muxc);
- /* Request GPIOs */
- ret = of_get_named_gpio_flags(np, "our-claim-gpio", 0, &gpio_flags);
- if (!gpio_is_valid(ret)) {
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "Error getting our-claim-gpio\n");
- return ret;
- }
- arb->our_gpio = ret;
- arb->our_gpio_release = !!(gpio_flags & OF_GPIO_ACTIVE_LOW);
- out_init = (gpio_flags & OF_GPIO_ACTIVE_LOW) ?
- GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
- ret = devm_gpio_request_one(dev, arb->our_gpio, out_init,
- "our-claim-gpio");
- if (ret) {
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "Error requesting our-claim-gpio\n");
- return ret;
+ /* Request GPIOs, our GPIO as unclaimed to begin with */
+ arb->our_gpio = devm_gpiod_get(dev, "our-claim", GPIOD_OUT_LOW);
+ if (IS_ERR(arb->our_gpio)) {
+ dev_err(dev, "could not get \"our-claim\" GPIO (%ld)\n",
+ PTR_ERR(arb->our_gpio));
+ return PTR_ERR(arb->our_gpio);
}
- ret = of_get_named_gpio_flags(np, "their-claim-gpios", 0, &gpio_flags);
- if (!gpio_is_valid(ret)) {
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "Error getting their-claim-gpio\n");
- return ret;
- }
- arb->their_gpio = ret;
- arb->their_gpio_release = !!(gpio_flags & OF_GPIO_ACTIVE_LOW);
- ret = devm_gpio_request_one(dev, arb->their_gpio, GPIOF_IN,
- "their-claim-gpio");
- if (ret) {
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "Error requesting their-claim-gpio\n");
- return ret;
+ arb->their_gpio = devm_gpiod_get(dev, "their-claim", GPIOD_IN);
+ if (IS_ERR(arb->their_gpio)) {
+ dev_err(dev, "could not get \"their-claim\" GPIO (%ld)\n",
+ PTR_ERR(arb->their_gpio));
+ return PTR_ERR(arb->their_gpio);
}
/* At the moment we only support a single two master (us + 1 other) */
- if (gpio_is_valid(of_get_named_gpio(np, "their-claim-gpios", 1))) {
+ dummy = devm_gpiod_get_index(dev, "their-claim", 1, GPIOD_IN);
+ if (!IS_ERR(dummy)) {
dev_err(dev, "Only one other master is supported\n");
return -EINVAL;
+ } else if (PTR_ERR(dummy) == -EPROBE_DEFER) {
+ return -EPROBE_DEFER;
}
/* Arbitration parameters */
diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c
index 13882a2a4f60..4effe563e9e8 100644
--- a/drivers/i2c/muxes/i2c-mux-gpio.c
+++ b/drivers/i2c/muxes/i2c-mux-gpio.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* I2C multiplexer using GPIO API
*
* Peter Korsgaard <peter.korsgaard@barco.com>
- *
- * 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.
*/
#include <linux/i2c.h>
@@ -14,13 +11,14 @@
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/gpio.h>
+#include <linux/bits.h>
+#include <linux/gpio/consumer.h>
+/* FIXME: stop poking around inside gpiolib */
#include "../../gpio/gpiolib.h"
-#include <linux/of_gpio.h>
struct gpiomux {
struct i2c_mux_gpio_platform_data data;
- unsigned gpio_base;
+ int ngpios;
struct gpio_desc **gpios;
};
@@ -30,8 +28,7 @@ static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val)
values[0] = val;
- gpiod_set_array_value_cansleep(mux->data.n_gpios, mux->gpios, NULL,
- values);
+ gpiod_set_array_value_cansleep(mux->ngpios, mux->gpios, NULL, values);
}
static int i2c_mux_gpio_select(struct i2c_mux_core *muxc, u32 chan)
@@ -52,12 +49,6 @@ static int i2c_mux_gpio_deselect(struct i2c_mux_core *muxc, u32 chan)
return 0;
}
-static int match_gpio_chip_by_label(struct gpio_chip *chip,
- void *data)
-{
- return !strcmp(chip->label, data);
-}
-
#ifdef CONFIG_OF
static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
struct platform_device *pdev)
@@ -65,8 +56,8 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
struct device_node *np = pdev->dev.of_node;
struct device_node *adapter_np, *child;
struct i2c_adapter *adapter;
- unsigned *values, *gpios;
- int i = 0, ret;
+ unsigned *values;
+ int i = 0;
if (!np)
return -ENODEV;
@@ -103,29 +94,6 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
if (of_property_read_u32(np, "idle-state", &mux->data.idle))
mux->data.idle = I2C_MUX_GPIO_NO_IDLE;
- mux->data.n_gpios = of_gpio_named_count(np, "mux-gpios");
- if (mux->data.n_gpios < 0) {
- dev_err(&pdev->dev, "Missing mux-gpios property in the DT.\n");
- return -EINVAL;
- }
-
- gpios = devm_kcalloc(&pdev->dev,
- mux->data.n_gpios, sizeof(*mux->data.gpios),
- GFP_KERNEL);
- if (!gpios) {
- dev_err(&pdev->dev, "Cannot allocate gpios array");
- return -ENOMEM;
- }
-
- for (i = 0; i < mux->data.n_gpios; i++) {
- ret = of_get_named_gpio(np, "mux-gpios", i);
- if (ret < 0)
- return ret;
- gpios[i] = ret;
- }
-
- mux->data.gpios = gpios;
-
return 0;
}
#else
@@ -142,8 +110,8 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
struct gpiomux *mux;
struct i2c_adapter *parent;
struct i2c_adapter *root;
- unsigned initial_state, gpio_base;
- int i, ret;
+ unsigned initial_state;
+ int i, ngpios, ret;
mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
if (!mux)
@@ -158,29 +126,19 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
sizeof(mux->data));
}
- /*
- * If a GPIO chip name is provided, the GPIO pin numbers provided are
- * relative to its base GPIO number. Otherwise they are absolute.
- */
- if (mux->data.gpio_chip) {
- struct gpio_chip *gpio;
-
- gpio = gpiochip_find(mux->data.gpio_chip,
- match_gpio_chip_by_label);
- if (!gpio)
- return -EPROBE_DEFER;
-
- gpio_base = gpio->base;
- } else {
- gpio_base = 0;
+ ngpios = gpiod_count(&pdev->dev, "mux");
+ if (ngpios <= 0) {
+ dev_err(&pdev->dev, "no valid gpios provided\n");
+ return ngpios ?: -EINVAL;
}
+ mux->ngpios = ngpios;
parent = i2c_get_adapter(mux->data.parent);
if (!parent)
return -EPROBE_DEFER;
muxc = i2c_mux_alloc(parent, &pdev->dev, mux->data.n_values,
- mux->data.n_gpios * sizeof(*mux->gpios), 0,
+ ngpios * sizeof(*mux->gpios), 0,
i2c_mux_gpio_select, NULL);
if (!muxc) {
ret = -ENOMEM;
@@ -194,7 +152,6 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
root = i2c_root_adapter(&parent->dev);
muxc->mux_locked = true;
- mux->gpio_base = gpio_base;
if (mux->data.idle != I2C_MUX_GPIO_NO_IDLE) {
initial_state = mux->data.idle;
@@ -203,34 +160,28 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
initial_state = mux->data.values[0];
}
- for (i = 0; i < mux->data.n_gpios; i++) {
+ for (i = 0; i < ngpios; i++) {
struct device *gpio_dev;
- struct gpio_desc *gpio_desc;
-
- ret = gpio_request(gpio_base + mux->data.gpios[i], "i2c-mux-gpio");
- if (ret) {
- dev_err(&pdev->dev, "Failed to request GPIO %d\n",
- mux->data.gpios[i]);
- goto err_request_gpio;
+ struct gpio_desc *gpiod;
+ enum gpiod_flags flag;
+
+ if (initial_state & BIT(i))
+ flag = GPIOD_OUT_HIGH;
+ else
+ flag = GPIOD_OUT_LOW;
+ gpiod = devm_gpiod_get_index(&pdev->dev, "mux", i, flag);
+ if (IS_ERR(gpiod)) {
+ ret = PTR_ERR(gpiod);
+ goto alloc_failed;
}
- ret = gpio_direction_output(gpio_base + mux->data.gpios[i],
- initial_state & (1 << i));
- if (ret) {
- dev_err(&pdev->dev,
- "Failed to set direction of GPIO %d to output\n",
- mux->data.gpios[i]);
- i++; /* gpio_request above succeeded, so must free */
- goto err_request_gpio;
- }
-
- gpio_desc = gpio_to_desc(gpio_base + mux->data.gpios[i]);
- mux->gpios[i] = gpio_desc;
+ mux->gpios[i] = gpiod;
if (!muxc->mux_locked)
continue;
- gpio_dev = &gpio_desc->gdev->dev;
+ /* FIXME: find a proper way to access the GPIO device */
+ gpio_dev = &gpiod->gdev->dev;
muxc->mux_locked = i2c_root_adapter(gpio_dev) == root;
}
@@ -253,10 +204,6 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
add_adapter_failed:
i2c_mux_del_adapters(muxc);
- i = mux->data.n_gpios;
-err_request_gpio:
- for (; i > 0; i--)
- gpio_free(gpio_base + mux->data.gpios[i - 1]);
alloc_failed:
i2c_put_adapter(parent);
@@ -266,14 +213,8 @@ alloc_failed:
static int i2c_mux_gpio_remove(struct platform_device *pdev)
{
struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
- struct gpiomux *mux = i2c_mux_priv(muxc);
- int i;
i2c_mux_del_adapters(muxc);
-
- for (i = 0; i < mux->data.n_gpios; i++)
- gpio_free(mux->gpio_base + mux->data.gpios[i]);
-
i2c_put_adapter(muxc->parent);
return 0;
diff --git a/drivers/i2c/muxes/i2c-mux-gpmux.c b/drivers/i2c/muxes/i2c-mux-gpmux.c
index f60b670deff7..f830535cff12 100644
--- a/drivers/i2c/muxes/i2c-mux-gpmux.c
+++ b/drivers/i2c/muxes/i2c-mux-gpmux.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* General Purpose I2C multiplexer
*
* Copyright (C) 2017 Axentia Technologies AB
*
* Author: Peter Rosin <peda@axentia.se>
- *
- * 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.
*/
#include <linux/i2c.h>
diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c
index 41603586f8fa..f1bb00a11ad6 100644
--- a/drivers/i2c/muxes/i2c-mux-pinctrl.c
+++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c
@@ -16,7 +16,7 @@
struct i2c_mux_pinctrl {
struct pinctrl *pinctrl;
- struct pinctrl_state **states;
+ struct pinctrl_state *states[];
};
static int i2c_mux_pinctrl_select(struct i2c_mux_core *muxc, u32 chan)
@@ -93,14 +93,13 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
return PTR_ERR(parent);
muxc = i2c_mux_alloc(parent, dev, num_names,
- sizeof(*mux) + num_names * sizeof(*mux->states),
+ struct_size(mux, states, num_names),
0, i2c_mux_pinctrl_select, NULL);
if (!muxc) {
ret = -ENOMEM;
goto err_put_parent;
}
mux = i2c_mux_priv(muxc);
- mux->states = (struct pinctrl_state **)(mux + 1);
platform_set_drvdata(pdev, muxc);
diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
index 5f4bd52121fe..d6f8b038a896 100644
--- a/drivers/i3c/master.c
+++ b/drivers/i3c/master.c
@@ -91,6 +91,12 @@ void i3c_bus_normaluse_unlock(struct i3c_bus *bus)
up_read(&bus->lock);
}
+static struct i3c_master_controller *
+i3c_bus_to_i3c_master(struct i3c_bus *i3cbus)
+{
+ return container_of(i3cbus, struct i3c_master_controller, bus);
+}
+
static struct i3c_master_controller *dev_to_i3cmaster(struct device *dev)
{
return container_of(dev, struct i3c_master_controller, dev);
@@ -464,6 +470,7 @@ static int i3c_bus_init(struct i3c_bus *i3cbus)
static const char * const i3c_bus_mode_strings[] = {
[I3C_BUS_MODE_PURE] = "pure",
[I3C_BUS_MODE_MIXED_FAST] = "mixed-fast",
+ [I3C_BUS_MODE_MIXED_LIMITED] = "mixed-limited",
[I3C_BUS_MODE_MIXED_SLOW] = "mixed-slow",
};
@@ -565,20 +572,39 @@ static const struct device_type i3c_masterdev_type = {
.groups = i3c_masterdev_groups,
};
-int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode)
+int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode,
+ unsigned long max_i2c_scl_rate)
{
- i3cbus->mode = mode;
+ struct i3c_master_controller *master = i3c_bus_to_i3c_master(i3cbus);
- if (!i3cbus->scl_rate.i3c)
- i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE;
+ i3cbus->mode = mode;
- if (!i3cbus->scl_rate.i2c) {
- if (i3cbus->mode == I3C_BUS_MODE_MIXED_SLOW)
- i3cbus->scl_rate.i2c = I3C_BUS_I2C_FM_SCL_RATE;
- else
- i3cbus->scl_rate.i2c = I3C_BUS_I2C_FM_PLUS_SCL_RATE;
+ switch (i3cbus->mode) {
+ case I3C_BUS_MODE_PURE:
+ if (!i3cbus->scl_rate.i3c)
+ i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE;
+ break;
+ case I3C_BUS_MODE_MIXED_FAST:
+ case I3C_BUS_MODE_MIXED_LIMITED:
+ if (!i3cbus->scl_rate.i3c)
+ i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE;
+ if (!i3cbus->scl_rate.i2c)
+ i3cbus->scl_rate.i2c = max_i2c_scl_rate;
+ break;
+ case I3C_BUS_MODE_MIXED_SLOW:
+ if (!i3cbus->scl_rate.i2c)
+ i3cbus->scl_rate.i2c = max_i2c_scl_rate;
+ if (!i3cbus->scl_rate.i3c ||
+ i3cbus->scl_rate.i3c > i3cbus->scl_rate.i2c)
+ i3cbus->scl_rate.i3c = i3cbus->scl_rate.i2c;
+ break;
+ default:
+ return -EINVAL;
}
+ dev_dbg(&master->dev, "i2c-scl = %ld Hz i3c-scl = %ld Hz\n",
+ i3cbus->scl_rate.i2c, i3cbus->scl_rate.i3c);
+
/*
* I3C/I2C frequency may have been overridden, check that user-provided
* values are not exceeding max possible frequency.
@@ -924,9 +950,8 @@ int i3c_master_defslvs_locked(struct i3c_master_controller *master)
ndevs++;
defslvs = i3c_ccc_cmd_dest_init(&dest, I3C_BROADCAST_ADDR,
- sizeof(*defslvs) +
- ((ndevs - 1) *
- sizeof(struct i3c_ccc_dev_desc)));
+ struct_size(defslvs, slaves,
+ ndevs - 1));
if (!defslvs)
return -ENOMEM;
@@ -1963,12 +1988,19 @@ of_i3c_master_add_i2c_boardinfo(struct i3c_master_controller *master,
if (ret)
return ret;
+ /*
+ * The I3C Specification does not clearly say I2C devices with 10-bit
+ * address are supported. These devices can't be passed properly through
+ * DEFSLVS command.
+ */
+ if (boardinfo->base.flags & I2C_CLIENT_TEN) {
+ dev_err(&master->dev, "I2C device with 10 bit address not supported.");
+ return -ENOTSUPP;
+ }
+
/* LVR is encoded in reg[2]. */
boardinfo->lvr = reg[2];
- if (boardinfo->lvr & I3C_LVR_I2C_FM_MODE)
- master->bus.scl_rate.i2c = I3C_BUS_I2C_FM_SCL_RATE;
-
list_add_tail(&boardinfo->node, &master->boardinfo.i2c);
of_node_get(node);
@@ -2111,16 +2143,14 @@ static int i3c_master_i2c_adapter_xfer(struct i2c_adapter *adap,
return ret ? ret : nxfers;
}
-static u32 i3c_master_i2c_functionalities(struct i2c_adapter *adap)
+static u32 i3c_master_i2c_funcs(struct i2c_adapter *adapter)
{
- struct i3c_master_controller *master = i2c_adapter_to_i3c_master(adap);
-
- return master->ops->i2c_funcs(master);
+ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
}
static const struct i2c_algorithm i3c_master_i2c_algo = {
.master_xfer = i3c_master_i2c_adapter_xfer,
- .functionality = i3c_master_i2c_functionalities,
+ .functionality = i3c_master_i2c_funcs,
};
static int i3c_master_i2c_adapter_init(struct i3c_master_controller *master)
@@ -2379,8 +2409,7 @@ EXPORT_SYMBOL_GPL(i3c_generic_ibi_recycle_slot);
static int i3c_master_check_ops(const struct i3c_master_controller_ops *ops)
{
if (!ops || !ops->bus_init || !ops->priv_xfers ||
- !ops->send_ccc_cmd || !ops->do_daa || !ops->i2c_xfers ||
- !ops->i2c_funcs)
+ !ops->send_ccc_cmd || !ops->do_daa || !ops->i2c_xfers)
return -EINVAL;
if (ops->request_ibi &&
@@ -2417,6 +2446,7 @@ int i3c_master_register(struct i3c_master_controller *master,
const struct i3c_master_controller_ops *ops,
bool secondary)
{
+ unsigned long i2c_scl_rate = I3C_BUS_I2C_FM_PLUS_SCL_RATE;
struct i3c_bus *i3cbus = i3c_master_get_bus(master);
enum i3c_bus_mode mode = I3C_BUS_MODE_PURE;
struct i2c_dev_boardinfo *i2cbi;
@@ -2458,6 +2488,9 @@ int i3c_master_register(struct i3c_master_controller *master,
mode = I3C_BUS_MODE_MIXED_FAST;
break;
case I3C_LVR_I2C_INDEX(1):
+ if (mode < I3C_BUS_MODE_MIXED_LIMITED)
+ mode = I3C_BUS_MODE_MIXED_LIMITED;
+ break;
case I3C_LVR_I2C_INDEX(2):
if (mode < I3C_BUS_MODE_MIXED_SLOW)
mode = I3C_BUS_MODE_MIXED_SLOW;
@@ -2466,9 +2499,12 @@ int i3c_master_register(struct i3c_master_controller *master,
ret = -EINVAL;
goto err_put_dev;
}
+
+ if (i2cbi->lvr & I3C_LVR_I2C_FM_MODE)
+ i2c_scl_rate = I3C_BUS_I2C_FM_SCL_RATE;
}
- ret = i3c_bus_set_mode(i3cbus, mode);
+ ret = i3c_bus_set_mode(i3cbus, mode, i2c_scl_rate);
if (ret)
goto err_put_dev;
diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c
index 1d83c97431c7..09912d75c6d5 100644
--- a/drivers/i3c/master/dw-i3c-master.c
+++ b/drivers/i3c/master/dw-i3c-master.c
@@ -599,6 +599,7 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m)
switch (bus->mode) {
case I3C_BUS_MODE_MIXED_FAST:
+ case I3C_BUS_MODE_MIXED_LIMITED:
ret = dw_i2c_clk_cfg(master);
if (ret)
return ret;
@@ -1060,11 +1061,6 @@ static void dw_i3c_master_detach_i2c_dev(struct i2c_dev_desc *dev)
kfree(data);
}
-static u32 dw_i3c_master_i2c_funcs(struct i3c_master_controller *m)
-{
- return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
-}
-
static irqreturn_t dw_i3c_master_irq_handler(int irq, void *dev_id)
{
struct dw_i3c_master *master = dev_id;
@@ -1099,7 +1095,6 @@ static const struct i3c_master_controller_ops dw_mipi_i3c_ops = {
.attach_i2c_dev = dw_i3c_master_attach_i2c_dev,
.detach_i2c_dev = dw_i3c_master_detach_i2c_dev,
.i2c_xfers = dw_i3c_master_i2c_xfers,
- .i2c_funcs = dw_i3c_master_i2c_funcs,
};
static int dw_i3c_probe(struct platform_device *pdev)
diff --git a/drivers/i3c/master/i3c-master-cdns.c b/drivers/i3c/master/i3c-master-cdns.c
index 8889a4fdb454..237f24adddc6 100644
--- a/drivers/i3c/master/i3c-master-cdns.c
+++ b/drivers/i3c/master/i3c-master-cdns.c
@@ -864,11 +864,6 @@ static int cdns_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
return ret;
}
-static u32 cdns_i3c_master_i2c_funcs(struct i3c_master_controller *m)
-{
- return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR;
-}
-
struct cdns_i3c_i2c_dev_data {
u16 id;
s16 ibi;
@@ -1010,9 +1005,7 @@ static int cdns_i3c_master_attach_i2c_dev(struct i2c_dev_desc *dev)
master->free_rr_slots &= ~BIT(slot);
i2c_dev_set_master_data(dev, data);
- writel(prepare_rr0_dev_address(dev->boardinfo->base.addr) |
- (dev->boardinfo->base.flags & I2C_CLIENT_TEN ?
- DEV_ID_RR0_LVR_EXT_ADDR : 0),
+ writel(prepare_rr0_dev_address(dev->boardinfo->base.addr),
master->regs + DEV_ID_RR0(data->id));
writel(dev->boardinfo->lvr, master->regs + DEV_ID_RR2(data->id));
writel(readl(master->regs + DEVS_CTRL) |
@@ -1518,7 +1511,6 @@ static const struct i3c_master_controller_ops cdns_i3c_master_ops = {
.send_ccc_cmd = cdns_i3c_master_send_ccc_cmd,
.priv_xfers = cdns_i3c_master_priv_xfers,
.i2c_xfers = cdns_i3c_master_i2c_xfers,
- .i2c_funcs = cdns_i3c_master_i2c_funcs,
.enable_ibi = cdns_i3c_master_enable_ibi,
.disable_ibi = cdns_i3c_master_disable_ibi,
.request_ibi = cdns_i3c_master_request_ibi,
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index fdd2a62f9d52..9eada392df15 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -25,13 +25,13 @@ menuconfig IDE
To compile this driver as a module, choose M here: the
module will be called ide-core.
- For further information, please read <file:Documentation/ide/ide.txt>.
+ For further information, please read <file:Documentation/ide/ide.rst>.
If unsure, say N.
if IDE
-comment "Please see Documentation/ide/ide.txt for help/info on IDE drives"
+comment "Please see Documentation/ide/ide.rst for help/info on IDE drives"
config IDE_XFER_MODE
bool
@@ -163,7 +163,7 @@ config BLK_DEV_IDETAPE
along with other IDE devices, as "hdb" or "hdc", or something
similar, and will be mapped to a character device such as "ht0"
(check the boot messages with dmesg). Be sure to consult the
- <file:drivers/ide/ide-tape.c> and <file:Documentation/ide/ide.txt>
+ <file:drivers/ide/ide-tape.c> and <file:Documentation/ide/ide.rst>
files for usage information.
To compile this driver as a module, choose M here: the
@@ -251,7 +251,7 @@ config BLK_DEV_CMD640
The CMD640 chip is also used on add-in cards by Acculogic, and on
the "CSA-6400E PCI to IDE controller" that some people have. For
- details, read <file:Documentation/ide/ide.txt>.
+ details, read <file:Documentation/ide/ide.rst>.
config BLK_DEV_CMD640_ENHANCED
bool "CMD640 enhanced support"
@@ -259,7 +259,7 @@ config BLK_DEV_CMD640_ENHANCED
help
This option includes support for setting/autotuning PIO modes and
prefetch on CMD640 IDE interfaces. For details, read
- <file:Documentation/ide/ide.txt>. If you have a CMD640 IDE interface
+ <file:Documentation/ide/ide.rst>. If you have a CMD640 IDE interface
and your BIOS does not already do this for you, then say Y here.
Otherwise say N.
@@ -819,7 +819,7 @@ config BLK_DEV_ALI14XX
boot parameter. It enables support for the secondary IDE interface
of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster
I/O speeds to be set as well.
- See the files <file:Documentation/ide/ide.txt> and
+ See the files <file:Documentation/ide/ide.rst> and
<file:drivers/ide/ali14xx.c> for more info.
config BLK_DEV_DTC2278
@@ -830,7 +830,7 @@ config BLK_DEV_DTC2278
This driver is enabled at runtime using the "dtc2278.probe" kernel
boot parameter. It enables support for the secondary IDE interface
of the DTC-2278 card, and permits faster I/O speeds to be set as
- well. See the <file:Documentation/ide/ide.txt> and
+ well. See the <file:Documentation/ide/ide.rst> and
<file:drivers/ide/dtc2278.c> files for more info.
config BLK_DEV_HT6560B
@@ -841,7 +841,7 @@ config BLK_DEV_HT6560B
This driver is enabled at runtime using the "ht6560b.probe" kernel
boot parameter. It enables support for the secondary IDE interface
of the Holtek card, and permits faster I/O speeds to be set as well.
- See the <file:Documentation/ide/ide.txt> and
+ See the <file:Documentation/ide/ide.rst> and
<file:drivers/ide/ht6560b.c> files for more info.
config BLK_DEV_QD65XX
@@ -851,7 +851,7 @@ config BLK_DEV_QD65XX
help
This driver is enabled at runtime using the "qd65xx.probe" kernel
boot parameter. It permits faster I/O speeds to be set. See the
- <file:Documentation/ide/ide.txt> and <file:drivers/ide/qd65xx.c>
+ <file:Documentation/ide/ide.rst> and <file:drivers/ide/qd65xx.c>
for more info.
config BLK_DEV_UMC8672
@@ -862,7 +862,7 @@ config BLK_DEV_UMC8672
This driver is enabled at runtime using the "umc8672.probe" kernel
boot parameter. It enables support for the secondary IDE interface
of the UMC-8672, and permits faster I/O speeds to be set as well.
- See the files <file:Documentation/ide/ide.txt> and
+ See the files <file:Documentation/ide/ide.rst> and
<file:drivers/ide/umc8672.c> for more info.
endif
diff --git a/drivers/ide/amd74xx.c b/drivers/ide/amd74xx.c
index cbfe846911d1..7340597a373e 100644
--- a/drivers/ide/amd74xx.c
+++ b/drivers/ide/amd74xx.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AMD 755/756/766/8111 and nVidia nForce/2/2s/3/3s/CK804/MCP04
* IDE driver for Linux.
@@ -9,11 +10,6 @@
* Andre Hedrick
*/
-/*
- * 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.
- */
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/drivers/ide/cs5535.c b/drivers/ide/cs5535.c
index 3bc5b9a34013..70fdbe3161f8 100644
--- a/drivers/ide/cs5535.c
+++ b/drivers/ide/cs5535.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2004-2005 Advanced Micro Devices, Inc.
* Copyright (C) 2007 Bartlomiej Zolnierkiewicz
@@ -14,10 +15,6 @@
* Development of this chipset driver was funded
* by the nice folks at National Semiconductor/AMD.
*
- * 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.
- *
* Documentation:
* CS5535 documentation available from AMD
*/
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 3b15adc6ce98..9d117936bee1 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -9,7 +9,7 @@
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
- * See Documentation/cdrom/ide-cd for usage information.
+ * See Documentation/cdrom/ide-cd.rst for usage information.
*
* Suggestions are welcome. Patches that work are more welcome though. ;-)
*
diff --git a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c
index 01464f1e2339..977cb00398b0 100644
--- a/drivers/ide/via82cxxx.c
+++ b/drivers/ide/via82cxxx.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* VIA IDE driver for Linux. Supported southbridges:
*
@@ -18,11 +19,6 @@
* Current device documentation available under NDA only
*/
-/*
- * 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.
- */
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index 1d736a4952ab..5bd51853b15e 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -28,7 +28,7 @@ config IIO_CONFIGFS
help
This allows configuring various IIO bits through configfs
(e.g. software triggers). For more info see
- Documentation/iio/iio_configfs.txt.
+ Documentation/iio/iio_configfs.rst.
config IIO_TRIGGER
bool "Enable triggered sampling support"
diff --git a/drivers/iio/accel/adis16201.c b/drivers/iio/accel/adis16201.c
index 0af4b289fc63..c4810c73b2a2 100644
--- a/drivers/iio/accel/adis16201.c
+++ b/drivers/iio/accel/adis16201.c
@@ -70,7 +70,7 @@
#define ADIS16201_DIAG_STAT_FLASH_UPT_FAIL_BIT 2
/* Power supply above 3.625 V */
#define ADIS16201_DIAG_STAT_POWER_HIGH_BIT 1
-/* Power supply below 3.15 V */
+/* Power supply below 2.975 V */
#define ADIS16201_DIAG_STAT_POWER_LOW_BIT 0
/* System Command Register Definition */
@@ -230,7 +230,7 @@ static const char * const adis16201_status_error_msgs[] = {
[ADIS16201_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure",
[ADIS16201_DIAG_STAT_FLASH_UPT_FAIL_BIT] = "Flash update failed",
[ADIS16201_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V",
- [ADIS16201_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 3.15V",
+ [ADIS16201_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 2.975V",
};
static const struct adis_data adis16201_data = {
diff --git a/drivers/iio/accel/adis16209.c b/drivers/iio/accel/adis16209.c
index 40be7adfa1f2..98d77af8a2b0 100644
--- a/drivers/iio/accel/adis16209.c
+++ b/drivers/iio/accel/adis16209.c
@@ -72,7 +72,7 @@
#define ADIS16209_STAT_FLASH_UPT_FAIL_BIT 2
/* Power supply above 3.625 V */
#define ADIS16209_STAT_POWER_HIGH_BIT 1
-/* Power supply below 3.15 V */
+/* Power supply below 2.975 V */
#define ADIS16209_STAT_POWER_LOW_BIT 0
#define ADIS16209_CMD_REG 0x3E
@@ -240,7 +240,7 @@ static const char * const adis16209_status_error_msgs[] = {
[ADIS16209_STAT_SPI_FAIL_BIT] = "SPI failure",
[ADIS16209_STAT_FLASH_UPT_FAIL_BIT] = "Flash update failed",
[ADIS16209_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V",
- [ADIS16209_STAT_POWER_LOW_BIT] = "Power supply below 3.15V",
+ [ADIS16209_STAT_POWER_LOW_BIT] = "Power supply below 2.975V",
};
static const struct adis_data adis16209_data = {
diff --git a/drivers/iio/accel/adxl372.c b/drivers/iio/accel/adxl372.c
index 3b84cb243a87..055227cb3d43 100644
--- a/drivers/iio/accel/adxl372.c
+++ b/drivers/iio/accel/adxl372.c
@@ -782,10 +782,14 @@ static int adxl372_buffer_postenable(struct iio_dev *indio_dev)
unsigned int mask;
int i, ret;
- ret = adxl372_set_interrupts(st, ADXL372_INT1_MAP_FIFO_FULL_MSK, 0);
+ ret = iio_triggered_buffer_postenable(indio_dev);
if (ret < 0)
return ret;
+ ret = adxl372_set_interrupts(st, ADXL372_INT1_MAP_FIFO_FULL_MSK, 0);
+ if (ret < 0)
+ goto err;
+
mask = *indio_dev->active_scan_mask;
for (i = 0; i < ARRAY_SIZE(adxl372_axis_lookup_table); i++) {
@@ -793,8 +797,10 @@ static int adxl372_buffer_postenable(struct iio_dev *indio_dev)
break;
}
- if (i == ARRAY_SIZE(adxl372_axis_lookup_table))
- return -EINVAL;
+ if (i == ARRAY_SIZE(adxl372_axis_lookup_table)) {
+ ret = -EINVAL;
+ goto err;
+ }
st->fifo_format = adxl372_axis_lookup_table[i].fifo_format;
st->fifo_set_size = bitmap_weight(indio_dev->active_scan_mask,
@@ -814,26 +820,25 @@ static int adxl372_buffer_postenable(struct iio_dev *indio_dev)
if (ret < 0) {
st->fifo_mode = ADXL372_FIFO_BYPASSED;
adxl372_set_interrupts(st, 0, 0);
- return ret;
+ goto err;
}
- return iio_triggered_buffer_postenable(indio_dev);
+ return 0;
+
+err:
+ iio_triggered_buffer_predisable(indio_dev);
+ return ret;
}
static int adxl372_buffer_predisable(struct iio_dev *indio_dev)
{
struct adxl372_state *st = iio_priv(indio_dev);
- int ret;
-
- ret = iio_triggered_buffer_predisable(indio_dev);
- if (ret < 0)
- return ret;
adxl372_set_interrupts(st, 0, 0);
st->fifo_mode = ADXL372_FIFO_BYPASSED;
adxl372_configure_fifo(st);
- return 0;
+ return iio_triggered_buffer_predisable(indio_dev);
}
static const struct iio_buffer_setup_ops adxl372_buffer_ops = {
diff --git a/drivers/iio/accel/adxl372_spi.c b/drivers/iio/accel/adxl372_spi.c
index e14e655ef165..3ef7e3a4804e 100644
--- a/drivers/iio/accel/adxl372_spi.c
+++ b/drivers/iio/accel/adxl372_spi.c
@@ -7,6 +7,8 @@
#include <linux/module.h>
#include <linux/regmap.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/spi/spi.h>
#include "adxl372.h"
@@ -37,9 +39,16 @@ static const struct spi_device_id adxl372_spi_id[] = {
};
MODULE_DEVICE_TABLE(spi, adxl372_spi_id);
+static const struct of_device_id adxl372_of_match[] = {
+ { .compatible = "adi,adxl372" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, adxl372_of_match);
+
static struct spi_driver adxl372_spi_driver = {
.driver = {
.name = "adxl372_spi",
+ .of_match_table = adxl372_of_match,
},
.probe = adxl372_spi_probe,
.id_table = adxl372_spi_id,
diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c
index e589f64eab9d..6645771aa349 100644
--- a/drivers/iio/accel/kxcjk-1013.c
+++ b/drivers/iio/accel/kxcjk-1013.c
@@ -1487,6 +1487,7 @@ static const struct acpi_device_id kx_acpi_match[] = {
{"KIOX0009", KXTJ21009},
{"KIOX000A", KXCJ91008},
{"KIOX010A", KXCJ91008}, /* KXCJ91008 inside the display of a 2-in-1 */
+ {"KIOX020A", KXCJ91008},
{"KXTJ1009", KXTJ21009},
{"KXJ2109", KXTJ21009},
{"SMO8500", KXCJ91008},
diff --git a/drivers/iio/accel/kxsd9-spi.c b/drivers/iio/accel/kxsd9-spi.c
index 011aeff19e3e..7971ec1eeb7e 100644
--- a/drivers/iio/accel/kxsd9-spi.c
+++ b/drivers/iio/accel/kxsd9-spi.c
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/device.h>
#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/spi/spi.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -41,10 +43,17 @@ static const struct spi_device_id kxsd9_spi_id[] = {
};
MODULE_DEVICE_TABLE(spi, kxsd9_spi_id);
+static const struct of_device_id kxsd9_of_match[] = {
+ { .compatible = "kionix,kxsd9" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, kxsd9_of_match);
+
static struct spi_driver kxsd9_spi_driver = {
.driver = {
.name = "kxsd9",
.pm = &kxsd9_dev_pm_ops,
+ .of_match_table = kxsd9_of_match,
},
.probe = kxsd9_spi_probe,
.remove = kxsd9_spi_remove,
diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c
index 70c60db62247..0b876b2dc5bd 100644
--- a/drivers/iio/accel/kxsd9.c
+++ b/drivers/iio/accel/kxsd9.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* kxsd9.c simple support for the Kionix KXSD9 3D
* accelerometer.
*
* Copyright (c) 2008-2009 Jonathan Cameron <jic23@kernel.org>
*
- * 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.
- *
* The i2c interface is very similar, so shouldn't be a problem once
* I have a suitable wire made up.
*
diff --git a/drivers/iio/accel/mma7455.h b/drivers/iio/accel/mma7455.h
index 2b1152c53d4f..4e3fa988f690 100644
--- a/drivers/iio/accel/mma7455.h
+++ b/drivers/iio/accel/mma7455.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* IIO accel driver for Freescale MMA7455L 3-axis 10-bit accelerometer
* Copyright 2015 Joachim Eastwood <manabian@gmail.com>
- *
- * 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.
*/
#ifndef __MMA7455_H
diff --git a/drivers/iio/accel/mma7455_core.c b/drivers/iio/accel/mma7455_core.c
index da0ceaac46b5..8b5a6aff9bf4 100644
--- a/drivers/iio/accel/mma7455_core.c
+++ b/drivers/iio/accel/mma7455_core.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* IIO accel core driver for Freescale MMA7455L 3-axis 10-bit accelerometer
* Copyright 2015 Joachim Eastwood <manabian@gmail.com>
*
- * 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.
- *
* UNSUPPORTED hardware features:
* - 8-bit mode with different scales
* - INT1/INT2 interrupts
diff --git a/drivers/iio/accel/mma7455_i2c.c b/drivers/iio/accel/mma7455_i2c.c
index 73bf81a8ab14..cddeaa9e230a 100644
--- a/drivers/iio/accel/mma7455_i2c.c
+++ b/drivers/iio/accel/mma7455_i2c.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* IIO accel I2C driver for Freescale MMA7455L 3-axis 10-bit accelerometer
* Copyright 2015 Joachim Eastwood <manabian@gmail.com>
- *
- * 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.
*/
#include <linux/i2c.h>
diff --git a/drivers/iio/accel/mma7455_spi.c b/drivers/iio/accel/mma7455_spi.c
index 79df8f27cf99..eb82cdfa8abc 100644
--- a/drivers/iio/accel/mma7455_spi.c
+++ b/drivers/iio/accel/mma7455_spi.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* IIO accel SPI driver for Freescale MMA7455L 3-axis 10-bit accelerometer
* Copyright 2015 Joachim Eastwood <manabian@gmail.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c
index 4964561595f5..a923f90f6e80 100644
--- a/drivers/iio/accel/sca3000.c
+++ b/drivers/iio/accel/sca3000.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* sca3000_core.c -- support VTI sca3000 series accelerometers via SPI
*
- * 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.
- *
* Copyright (c) 2009 Jonathan Cameron <jic23@kernel.org>
*
* See industrialio/accels/sca3000.h for comments.
@@ -872,8 +869,9 @@ static int sca3000_read_event_value(struct iio_dev *indio_dev,
enum iio_event_info info,
int *val, int *val2)
{
- int ret, i;
struct sca3000_state *st = iio_priv(indio_dev);
+ long ret;
+ int i;
switch (info) {
case IIO_EV_INFO_VALUE:
@@ -885,11 +883,11 @@ static int sca3000_read_event_value(struct iio_dev *indio_dev,
return ret;
*val = 0;
if (chan->channel2 == IIO_MOD_Y)
- for_each_set_bit(i, (unsigned long *)&ret,
+ for_each_set_bit(i, &ret,
ARRAY_SIZE(st->info->mot_det_mult_y))
*val += st->info->mot_det_mult_y[i];
else
- for_each_set_bit(i, (unsigned long *)&ret,
+ for_each_set_bit(i, &ret,
ARRAY_SIZE(st->info->mot_det_mult_xz))
*val += st->info->mot_det_mult_xz[i];
diff --git a/drivers/iio/accel/st_accel_buffer.c b/drivers/iio/accel/st_accel_buffer.c
index 54f2ae91f614..0205c0167cdd 100644
--- a/drivers/iio/accel/st_accel_buffer.c
+++ b/drivers/iio/accel/st_accel_buffer.c
@@ -45,17 +45,19 @@ static int st_accel_buffer_postenable(struct iio_dev *indio_dev)
goto allocate_memory_error;
}
- err = st_sensors_set_axis_enable(indio_dev,
- (u8)indio_dev->active_scan_mask[0]);
+ err = iio_triggered_buffer_postenable(indio_dev);
if (err < 0)
goto st_accel_buffer_postenable_error;
- err = iio_triggered_buffer_postenable(indio_dev);
+ err = st_sensors_set_axis_enable(indio_dev,
+ (u8)indio_dev->active_scan_mask[0]);
if (err < 0)
- goto st_accel_buffer_postenable_error;
+ goto st_sensors_set_axis_enable_error;
return err;
+st_sensors_set_axis_enable_error:
+ iio_triggered_buffer_predisable(indio_dev);
st_accel_buffer_postenable_error:
kfree(adata->buffer_data);
allocate_memory_error:
@@ -64,20 +66,22 @@ allocate_memory_error:
static int st_accel_buffer_predisable(struct iio_dev *indio_dev)
{
- int err;
+ int err, err2;
struct st_sensor_data *adata = iio_priv(indio_dev);
- err = iio_triggered_buffer_predisable(indio_dev);
- if (err < 0)
- goto st_accel_buffer_predisable_error;
-
err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS);
if (err < 0)
goto st_accel_buffer_predisable_error;
err = st_sensors_set_enable(indio_dev, false);
+ if (err < 0)
+ goto st_accel_buffer_predisable_error;
st_accel_buffer_predisable_error:
+ err2 = iio_triggered_buffer_predisable(indio_dev);
+ if (!err)
+ err = err2;
+
kfree(adata->buffer_data);
return err;
}
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index f96a7702b020..7e3286265a38 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -1085,7 +1085,6 @@ config VIPERBOARD_ADC
config XILINX_XADC
tristate "Xilinx XADC driver"
- depends on ARCH_ZYNQ || MICROBLAZE || COMPILE_TEST
depends on HAS_IOMEM
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c
index 659ef37d5fe8..edc6f1cc90b2 100644
--- a/drivers/iio/adc/ad7124.c
+++ b/drivers/iio/adc/ad7124.c
@@ -61,6 +61,8 @@
#define AD7124_CONFIG_REF_SEL(x) FIELD_PREP(AD7124_CONFIG_REF_SEL_MSK, x)
#define AD7124_CONFIG_PGA_MSK GENMASK(2, 0)
#define AD7124_CONFIG_PGA(x) FIELD_PREP(AD7124_CONFIG_PGA_MSK, x)
+#define AD7124_CONFIG_IN_BUFF_MSK GENMASK(7, 6)
+#define AD7124_CONFIG_IN_BUFF(x) FIELD_PREP(AD7124_CONFIG_IN_BUFF_MSK, x)
/* AD7124_FILTER_X */
#define AD7124_FILTER_FS_MSK GENMASK(10, 0)
@@ -108,6 +110,8 @@ struct ad7124_chip_info {
struct ad7124_channel_config {
enum ad7124_ref_sel refsel;
bool bipolar;
+ bool buf_positive;
+ bool buf_negative;
unsigned int ain;
unsigned int vref_mv;
unsigned int pga_bits;
@@ -117,7 +121,7 @@ struct ad7124_channel_config {
struct ad7124_state {
const struct ad7124_chip_info *chip_info;
struct ad_sigma_delta sd;
- struct ad7124_channel_config channel_config[4];
+ struct ad7124_channel_config *channel_config;
struct regulator *vref[4];
struct clk *mclk;
unsigned int adc_control;
@@ -435,6 +439,7 @@ static int ad7124_of_parse_channel_config(struct iio_dev *indio_dev,
struct ad7124_state *st = iio_priv(indio_dev);
struct device_node *child;
struct iio_chan_spec *chan;
+ struct ad7124_channel_config *chan_config;
unsigned int ain[2], channel = 0, tmp;
int ret;
@@ -449,8 +454,14 @@ static int ad7124_of_parse_channel_config(struct iio_dev *indio_dev,
if (!chan)
return -ENOMEM;
+ chan_config = devm_kcalloc(indio_dev->dev.parent, st->num_channels,
+ sizeof(*chan_config), GFP_KERNEL);
+ if (!chan_config)
+ return -ENOMEM;
+
indio_dev->channels = chan;
indio_dev->num_channels = st->num_channels;
+ st->channel_config = chan_config;
for_each_available_child_of_node(np, child) {
ret = of_property_read_u32(child, "reg", &channel);
@@ -462,13 +473,6 @@ static int ad7124_of_parse_channel_config(struct iio_dev *indio_dev,
if (ret)
goto err;
- if (ain[0] >= st->chip_info->num_inputs ||
- ain[1] >= st->chip_info->num_inputs) {
- dev_err(indio_dev->dev.parent,
- "Input pin number out of range.\n");
- ret = -EINVAL;
- goto err;
- }
st->channel_config[channel].ain = AD7124_CHANNEL_AINP(ain[0]) |
AD7124_CHANNEL_AINM(ain[1]);
st->channel_config[channel].bipolar =
@@ -480,6 +484,11 @@ static int ad7124_of_parse_channel_config(struct iio_dev *indio_dev,
else
st->channel_config[channel].refsel = tmp;
+ st->channel_config[channel].buf_positive =
+ of_property_read_bool(child, "adi,buffered-positive");
+ st->channel_config[channel].buf_negative =
+ of_property_read_bool(child, "adi,buffered-negative");
+
*chan = ad7124_channel_template;
chan->address = channel;
chan->scan_index = channel;
@@ -499,7 +508,7 @@ err:
static int ad7124_setup(struct ad7124_state *st)
{
unsigned int val, fclk, power_mode;
- int i, ret;
+ int i, ret, tmp;
fclk = clk_get_rate(st->mclk);
if (!fclk)
@@ -532,8 +541,12 @@ static int ad7124_setup(struct ad7124_state *st)
if (ret < 0)
return ret;
+ tmp = (st->channel_config[i].buf_positive << 1) +
+ st->channel_config[i].buf_negative;
+
val = AD7124_CONFIG_BIPOLAR(st->channel_config[i].bipolar) |
- AD7124_CONFIG_REF_SEL(st->channel_config[i].refsel);
+ AD7124_CONFIG_REF_SEL(st->channel_config[i].refsel) |
+ AD7124_CONFIG_IN_BUFF(tmp);
ret = ad_sd_write_reg(&st->sd, AD7124_CONFIG(i), 2, val);
if (ret < 0)
return ret;
diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c
index 24c70c3cefb4..aba0fd123a51 100644
--- a/drivers/iio/adc/ad7606.c
+++ b/drivers/iio/adc/ad7606.c
@@ -140,7 +140,7 @@ static int ad7606_read_raw(struct iio_dev *indio_dev,
int *val2,
long m)
{
- int ret;
+ int ret, ch = 0;
struct ad7606_state *st = iio_priv(indio_dev);
switch (m) {
@@ -157,8 +157,10 @@ static int ad7606_read_raw(struct iio_dev *indio_dev,
*val = (short)ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
+ if (st->sw_mode_en)
+ ch = chan->address;
*val = 0;
- *val2 = st->scale_avail[st->range];
+ *val2 = st->scale_avail[st->range[ch]];
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
*val = st->oversampling;
@@ -194,6 +196,32 @@ static ssize_t in_voltage_scale_available_show(struct device *dev,
static IIO_DEVICE_ATTR_RO(in_voltage_scale_available, 0);
+static int ad7606_write_scale_hw(struct iio_dev *indio_dev, int ch, int val)
+{
+ struct ad7606_state *st = iio_priv(indio_dev);
+
+ gpiod_set_value(st->gpio_range, val);
+
+ return 0;
+}
+
+static int ad7606_write_os_hw(struct iio_dev *indio_dev, int val)
+{
+ struct ad7606_state *st = iio_priv(indio_dev);
+ DECLARE_BITMAP(values, 3);
+
+ values[0] = val;
+
+ gpiod_set_array_value(ARRAY_SIZE(values), st->gpio_os->desc,
+ st->gpio_os->info, values);
+
+ /* AD7616 requires a reset to update value */
+ if (st->chip_info->os_req_reset)
+ ad7606_reset(st);
+
+ return 0;
+}
+
static int ad7606_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
@@ -201,15 +229,20 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
long mask)
{
struct ad7606_state *st = iio_priv(indio_dev);
- DECLARE_BITMAP(values, 3);
- int i;
+ int i, ret, ch = 0;
switch (mask) {
case IIO_CHAN_INFO_SCALE:
mutex_lock(&st->lock);
i = find_closest(val2, st->scale_avail, st->num_scales);
- gpiod_set_value(st->gpio_range, i);
- st->range = i;
+ if (st->sw_mode_en)
+ ch = chan->address;
+ ret = st->write_scale(indio_dev, ch, i);
+ if (ret < 0) {
+ mutex_unlock(&st->lock);
+ return ret;
+ }
+ st->range[ch] = i;
mutex_unlock(&st->lock);
return 0;
@@ -218,17 +251,12 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
return -EINVAL;
i = find_closest(val, st->oversampling_avail,
st->num_os_ratios);
-
- values[0] = i;
-
mutex_lock(&st->lock);
- gpiod_set_array_value(ARRAY_SIZE(values), st->gpio_os->desc,
- st->gpio_os->info, values);
-
- /* AD7616 requires a reset to update value */
- if (st->chip_info->os_req_reset)
- ad7606_reset(st);
-
+ ret = st->write_os(indio_dev, i);
+ if (ret < 0) {
+ mutex_unlock(&st->lock);
+ return ret;
+ }
st->oversampling = st->oversampling_avail[i];
mutex_unlock(&st->lock);
@@ -536,7 +564,7 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
st->bops = bops;
st->base_address = base_address;
/* tied to logic low, analog input range is +/- 5V */
- st->range = 0;
+ st->range[0] = 0;
st->oversampling = 1;
st->scale_avail = ad7606_scale_avail;
st->num_scales = ARRAY_SIZE(ad7606_scale_avail);
@@ -589,6 +617,39 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
if (ret)
dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n");
+ st->write_scale = ad7606_write_scale_hw;
+ st->write_os = ad7606_write_os_hw;
+
+ if (st->chip_info->sw_mode_config)
+ st->sw_mode_en = device_property_present(st->dev,
+ "adi,sw-mode");
+
+ if (st->sw_mode_en) {
+ /* After reset, in software mode, ±10 V is set by default */
+ memset32(st->range, 2, ARRAY_SIZE(st->range));
+ indio_dev->info = &ad7606_info_os_and_range;
+
+ /*
+ * In software mode, the range gpio has no longer its function.
+ * Instead, the scale can be configured individually for each
+ * channel from the range registers.
+ */
+ if (st->chip_info->write_scale_sw)
+ st->write_scale = st->chip_info->write_scale_sw;
+
+ /*
+ * In software mode, the oversampling is no longer configured
+ * with GPIO pins. Instead, the oversampling can be configured
+ * in configuratiion register.
+ */
+ if (st->chip_info->write_os_sw)
+ st->write_os = st->chip_info->write_os_sw;
+
+ ret = st->chip_info->sw_mode_config(indio_dev);
+ if (ret < 0)
+ return ret;
+ }
+
st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
indio_dev->name, indio_dev->id);
if (!st->trig)
@@ -643,7 +704,7 @@ static int ad7606_resume(struct device *dev)
struct ad7606_state *st = iio_priv(indio_dev);
if (st->gpio_standby) {
- gpiod_set_value(st->gpio_range, st->range);
+ gpiod_set_value(st->gpio_range, st->range[0]);
gpiod_set_value(st->gpio_standby, 1);
ad7606_reset(st);
}
diff --git a/drivers/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h
index f9ef52131e74..d8a509c2c428 100644
--- a/drivers/iio/adc/ad7606.h
+++ b/drivers/iio/adc/ad7606.h
@@ -16,6 +16,12 @@
* oversampling ratios.
* @oversampling_num number of elements stored in oversampling_avail array
* @os_req_reset some devices require a reset to update oversampling
+ * @write_scale_sw pointer to the function which writes the scale via spi
+ in software mode
+ * @write_os_sw pointer to the function which writes the os via spi
+ in software mode
+ * @sw_mode_config: pointer to a function which configured the device
+ * for software mode
*/
struct ad7606_chip_info {
const struct iio_chan_spec *channels;
@@ -23,6 +29,9 @@ struct ad7606_chip_info {
const unsigned int *oversampling_avail;
unsigned int oversampling_num;
bool os_req_reset;
+ int (*write_scale_sw)(struct iio_dev *indio_dev, int ch, int val);
+ int (*write_os_sw)(struct iio_dev *indio_dev, int val);
+ int (*sw_mode_config)(struct iio_dev *indio_dev);
};
/**
@@ -34,11 +43,14 @@ struct ad7606_chip_info {
* @range voltage range selection, selects which scale to apply
* @oversampling oversampling selection
* @base_address address from where to read data in parallel operation
+ * @sw_mode_en software mode enabled
* @scale_avail pointer to the array which stores the available scales
* @num_scales number of elements stored in the scale_avail array
* @oversampling_avail pointer to the array which stores the available
* oversampling ratios.
* @num_os_ratios number of elements stored in oversampling_avail array
+ * @write_scale pointer to the function which writes the scale
+ * @write_os pointer to the function which writes the os
* @lock protect sensor state from concurrent accesses to GPIOs
* @gpio_convst GPIO descriptor for conversion start signal (CONVST)
* @gpio_reset GPIO descriptor for device hard-reset
@@ -57,13 +69,16 @@ struct ad7606_state {
const struct ad7606_chip_info *chip_info;
struct regulator *reg;
const struct ad7606_bus_ops *bops;
- unsigned int range;
+ unsigned int range[16];
unsigned int oversampling;
void __iomem *base_address;
+ bool sw_mode_en;
const unsigned int *scale_avail;
unsigned int num_scales;
const unsigned int *oversampling_avail;
unsigned int num_os_ratios;
+ int (*write_scale)(struct iio_dev *indio_dev, int ch, int val);
+ int (*write_os)(struct iio_dev *indio_dev, int val);
struct mutex lock; /* protect sensor state */
struct gpio_desc *gpio_convst;
diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c
index 7a5b5d00a87d..5a3ca5904ded 100644
--- a/drivers/iio/adc/ad799x.c
+++ b/drivers/iio/adc/ad799x.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* iio/adc/ad799x.c
* Copyright (C) 2010-2011 Michael Hennerich, Analog Devices Inc.
@@ -11,15 +12,10 @@
* based on linux/drivers/acron/char/pcf8583.c
* Copyright (C) 2000 Russell King
*
- * 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.
- *
* ad799x.c
*
* Support for ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997,
* ad7998 and similar chips.
- *
*/
#include <linux/interrupt.h>
diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c
index 1423221c6e06..2640b75fb774 100644
--- a/drivers/iio/adc/ad_sigma_delta.c
+++ b/drivers/iio/adc/ad_sigma_delta.c
@@ -357,7 +357,7 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev)
ret = ad_sigma_delta_set_channel(sigma_delta,
indio_dev->channels[channel].address);
if (ret)
- goto err_predisable;
+ return ret;
spi_bus_lock(sigma_delta->spi->master);
sigma_delta->bus_locked = true;
@@ -374,7 +374,6 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev)
err_unlock:
spi_bus_unlock(sigma_delta->spi->master);
-err_predisable:
return ret;
}
diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c
index d384cf0250ff..a2837a0e7cba 100644
--- a/drivers/iio/adc/at91-sama5d2_adc.c
+++ b/drivers/iio/adc/at91-sama5d2_adc.c
@@ -1578,8 +1578,7 @@ static void at91_adc_hw_init(struct at91_adc_state *st)
static ssize_t at91_adc_get_fifo_state(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev =
- platform_get_drvdata(to_platform_device(dev));
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct at91_adc_state *st = iio_priv(indio_dev);
return scnprintf(buf, PAGE_SIZE, "%d\n", !!st->dma_st.dma_chan);
@@ -1588,8 +1587,7 @@ static ssize_t at91_adc_get_fifo_state(struct device *dev,
static ssize_t at91_adc_get_watermark(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev =
- platform_get_drvdata(to_platform_device(dev));
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct at91_adc_state *st = iio_priv(indio_dev);
return scnprintf(buf, PAGE_SIZE, "%d\n", st->dma_st.watermark);
@@ -1841,8 +1839,7 @@ static int at91_adc_remove(struct platform_device *pdev)
static __maybe_unused int at91_adc_suspend(struct device *dev)
{
- struct iio_dev *indio_dev =
- platform_get_drvdata(to_platform_device(dev));
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct at91_adc_state *st = iio_priv(indio_dev);
/*
@@ -1862,8 +1859,7 @@ static __maybe_unused int at91_adc_suspend(struct device *dev)
static __maybe_unused int at91_adc_resume(struct device *dev)
{
- struct iio_dev *indio_dev =
- platform_get_drvdata(to_platform_device(dev));
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct at91_adc_state *st = iio_priv(indio_dev);
int ret;
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index d23709ed9049..32f1c4a33b20 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -1359,7 +1359,7 @@ static int at91_adc_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int at91_adc_suspend(struct device *dev)
{
- struct iio_dev *idev = platform_get_drvdata(to_platform_device(dev));
+ struct iio_dev *idev = dev_get_drvdata(dev);
struct at91_adc_state *st = iio_priv(idev);
pinctrl_pm_select_sleep_state(dev);
@@ -1370,7 +1370,7 @@ static int at91_adc_suspend(struct device *dev)
static int at91_adc_resume(struct device *dev)
{
- struct iio_dev *idev = platform_get_drvdata(to_platform_device(dev));
+ struct iio_dev *idev = dev_get_drvdata(dev);
struct at91_adc_state *st = iio_priv(idev);
clk_prepare_enable(st->clk);
diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c
index 5be789269353..88059480da17 100644
--- a/drivers/iio/adc/axp20x_adc.c
+++ b/drivers/iio/adc/axp20x_adc.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* ADC driver for AXP20X and AXP22X PMICs
*
* Copyright (c) 2016 Free Electrons NextThing Co.
* Quentin Schulz <quentin.schulz@free-electrons.com>
- *
- * 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.
*/
#include <linux/completion.h>
diff --git a/drivers/iio/adc/bcm_iproc_adc.c b/drivers/iio/adc/bcm_iproc_adc.c
index 7af59a4bbd8d..c46c0aa15376 100644
--- a/drivers/iio/adc/bcm_iproc_adc.c
+++ b/drivers/iio/adc/bcm_iproc_adc.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2016 Broadcom
- *
- * 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 (the "GPL").
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License version 2 (GPLv2) for more details.
- *
- * You should have received a copy of the GNU General Public License
- * version 2 (GPLv2) along with this source code.
*/
#include <linux/module.h>
diff --git a/drivers/iio/adc/cc10001_adc.c b/drivers/iio/adc/cc10001_adc.c
index 707d8b24b072..f93f1d93b80d 100644
--- a/drivers/iio/adc/cc10001_adc.c
+++ b/drivers/iio/adc/cc10001_adc.c
@@ -1,10 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014-2015 Imagination Technologies Ltd.
- *
- * 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.
- *
*/
#include <linux/clk.h>
diff --git a/drivers/iio/adc/ep93xx_adc.c b/drivers/iio/adc/ep93xx_adc.c
index 5036c392cb20..5c97e8a511f2 100644
--- a/drivers/iio/adc/ep93xx_adc.c
+++ b/drivers/iio/adc/ep93xx_adc.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for ADC module on the Cirrus Logic EP93xx series of SoCs
*
* Copyright (C) 2015 Alexander Sverdlin
*
- * 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.
- *
* The driver uses polling to get the conversion status. According to EP93xx
* datasheets, reading ADCResult register starts the conversion, but user is also
* responsible for ensuring that delay between adjacent conversion triggers is
diff --git a/drivers/iio/adc/fsl-imx25-gcq.c b/drivers/iio/adc/fsl-imx25-gcq.c
index 929c617db364..df19ecae52f7 100644
--- a/drivers/iio/adc/fsl-imx25-gcq.c
+++ b/drivers/iio/adc/fsl-imx25-gcq.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014-2015 Pengutronix, Markus Pargmann <mpa@pengutronix.de>
*
- * 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.
- *
* This is the driver for the imx25 GCQ (Generic Conversion Queue)
* connected to the imx25 ADC.
*/
diff --git a/drivers/iio/adc/imx7d_adc.c b/drivers/iio/adc/imx7d_adc.c
index 4fe97c2a0f43..26a7bbe4d534 100644
--- a/drivers/iio/adc/imx7d_adc.c
+++ b/drivers/iio/adc/imx7d_adc.c
@@ -78,6 +78,7 @@
#define IMX7D_REG_ADC_INT_STATUS_CHANNEL_CONV_TIME_OUT 0xf0000
#define IMX7D_ADC_TIMEOUT msecs_to_jiffies(100)
+#define IMX7D_ADC_INPUT_CLK 24000000
enum imx7d_adc_clk_pre_div {
IMX7D_ADC_ANALOG_CLK_PRE_DIV_4,
@@ -100,8 +101,6 @@ struct imx7d_adc_feature {
enum imx7d_adc_average_num avg_num;
u32 core_time_unit; /* impact the sample rate */
-
- bool average_en;
};
struct imx7d_adc {
@@ -179,7 +178,6 @@ static void imx7d_adc_feature_config(struct imx7d_adc *info)
info->adc_feature.clk_pre_div = IMX7D_ADC_ANALOG_CLK_PRE_DIV_4;
info->adc_feature.avg_num = IMX7D_ADC_AVERAGE_NUM_32;
info->adc_feature.core_time_unit = 1;
- info->adc_feature.average_en = true;
}
static void imx7d_adc_sample_rate_set(struct imx7d_adc *info)
@@ -240,9 +238,8 @@ static void imx7d_adc_channel_set(struct imx7d_adc *info)
/* the channel choose single conversion, and enable average mode */
cfg1 |= (IMX7D_REG_ADC_CH_CFG1_CHANNEL_EN |
- IMX7D_REG_ADC_CH_CFG1_CHANNEL_SINGLE);
- if (info->adc_feature.average_en)
- cfg1 |= IMX7D_REG_ADC_CH_CFG1_CHANNEL_AVG_EN;
+ IMX7D_REG_ADC_CH_CFG1_CHANNEL_SINGLE |
+ IMX7D_REG_ADC_CH_CFG1_CHANNEL_AVG_EN);
/*
* physical channel 0 chose logical channel A
@@ -272,13 +269,11 @@ static void imx7d_adc_channel_set(struct imx7d_adc *info)
static u32 imx7d_adc_get_sample_rate(struct imx7d_adc *info)
{
- /* input clock is always 24MHz */
- u32 input_clk = 24000000;
u32 analogue_core_clk;
u32 core_time_unit = info->adc_feature.core_time_unit;
u32 tmp;
- analogue_core_clk = input_clk / info->pre_div_num;
+ analogue_core_clk = IMX7D_ADC_INPUT_CLK / info->pre_div_num;
tmp = (core_time_unit + 1) * 6;
return analogue_core_clk / tmp;
@@ -493,11 +488,8 @@ static int imx7d_adc_probe(struct platform_device *pdev)
info->dev = dev;
info->regs = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(info->regs)) {
- ret = PTR_ERR(info->regs);
- dev_err(dev, "Failed to remap adc memory, err = %d\n", ret);
- return ret;
- }
+ if (IS_ERR(info->regs))
+ return PTR_ERR(info->regs);
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
@@ -531,9 +523,7 @@ static int imx7d_adc_probe(struct platform_device *pdev)
indio_dev->channels = imx7d_adc_iio_channels;
indio_dev->num_channels = ARRAY_SIZE(imx7d_adc_iio_channels);
- ret = devm_request_irq(dev, irq,
- imx7d_adc_isr, 0,
- dev_name(dev), info);
+ ret = devm_request_irq(dev, irq, imx7d_adc_isr, 0, dev_name(dev), info);
if (ret < 0) {
dev_err(dev, "Failed requesting irq, irq = %d\n", irq);
return ret;
diff --git a/drivers/iio/adc/lp8788_adc.c b/drivers/iio/adc/lp8788_adc.c
index 3bc4df916420..c1fc1b678e0f 100644
--- a/drivers/iio/adc/lp8788_adc.c
+++ b/drivers/iio/adc/lp8788_adc.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TI LP8788 MFD - ADC driver
*
* Copyright 2012 Texas Instruments
*
* Author: Milo(Woogyom) Kim <milo.kim@ti.com>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/iio/adc/lpc18xx_adc.c b/drivers/iio/adc/lpc18xx_adc.c
index 041dc4a3f66c..e400a95f553d 100644
--- a/drivers/iio/adc/lpc18xx_adc.c
+++ b/drivers/iio/adc/lpc18xx_adc.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* IIO ADC driver for NXP LPC18xx ADC
*
* Copyright (C) 2016 Joachim Eastwood <manabian@gmail.com>
*
- * 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.
- *
* UNSUPPORTED hardware features:
* - Hardware triggers
* - Burst mode
diff --git a/drivers/iio/adc/ltc2485.c b/drivers/iio/adc/ltc2485.c
index b24c14037fd4..c418466d51fd 100644
--- a/drivers/iio/adc/ltc2485.c
+++ b/drivers/iio/adc/ltc2485.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ltc2485.c - Driver for Linear Technology LTC2485 ADC
*
* Copyright (C) 2016 Alison Schofield <amsfield22@gmail.com>
*
- * 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.
- *
* Datasheet: http://cds.linear.com/docs/en/datasheet/2485fd.pdf
*/
diff --git a/drivers/iio/adc/max1027.c b/drivers/iio/adc/max1027.c
index 311c1a89c329..da84adfdb819 100644
--- a/drivers/iio/adc/max1027.c
+++ b/drivers/iio/adc/max1027.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* iio/adc/max1027.c
* Copyright (C) 2014 Philippe Reynes
@@ -6,10 +7,6 @@
* Copyright 2011 Analog Devices Inc (from AD7923 Driver)
* Copyright 2012 CS Systemes d'Information
*
- * 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.
- *
* max1027.c
*
* Partial support for max1027 and similar chips.
diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c
index a8d35aebee80..5c2cc61b666e 100644
--- a/drivers/iio/adc/max1363.c
+++ b/drivers/iio/adc/max1363.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* iio/adc/max1363.c
* Copyright (C) 2008-2010 Jonathan Cameron
@@ -9,10 +10,6 @@
* Copyright (C) 2000 Russell King
*
* Driver for max1363 and similar chips.
- *
- * 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.
*/
#include <linux/interrupt.h>
diff --git a/drivers/iio/adc/mcp320x.c b/drivers/iio/adc/mcp320x.c
index a04856d8afdb..38bf10085696 100644
--- a/drivers/iio/adc/mcp320x.c
+++ b/drivers/iio/adc/mcp320x.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Oskar Andero <oskar.andero@gmail.com>
* Copyright (C) 2014 Rose Technology
@@ -34,10 +35,6 @@
* http://ww1.microchip.com/downloads/en/DeviceDoc/21298c.pdf mcp3204/08
* http://ww1.microchip.com/downloads/en/DeviceDoc/21700E.pdf mcp3301
* http://ww1.microchip.com/downloads/en/DeviceDoc/21950D.pdf mcp3550/1/3
- *
- * 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.
*/
#include <linux/err.h>
diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c
index 70bbcf253cb6..7b28d045d271 100644
--- a/drivers/iio/adc/meson_saradc.c
+++ b/drivers/iio/adc/meson_saradc.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-License-Identifier: GPL-2.0
/*
* Amlogic Meson Successive Approximation Register (SAR) A/D Converter
*
diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c
index d1759c804b26..7bbb64ca3b32 100644
--- a/drivers/iio/adc/mt6577_auxadc.c
+++ b/drivers/iio/adc/mt6577_auxadc.c
@@ -34,10 +34,26 @@
#define MT6577_AUXADC_POWER_READY_MS 1
#define MT6577_AUXADC_SAMPLE_READY_US 25
+struct mtk_auxadc_compatible {
+ bool sample_data_cali;
+ bool check_global_idle;
+};
+
struct mt6577_auxadc_device {
void __iomem *reg_base;
struct clk *adc_clk;
struct mutex lock;
+ const struct mtk_auxadc_compatible *dev_comp;
+};
+
+static const struct mtk_auxadc_compatible mt8173_compat = {
+ .sample_data_cali = false,
+ .check_global_idle = true,
+};
+
+static const struct mtk_auxadc_compatible mt6765_compat = {
+ .sample_data_cali = true,
+ .check_global_idle = false,
};
#define MT6577_AUXADC_CHANNEL(idx) { \
@@ -66,6 +82,11 @@ static const struct iio_chan_spec mt6577_auxadc_iio_channels[] = {
MT6577_AUXADC_CHANNEL(15),
};
+static int mt_auxadc_get_cali_data(int rawdata, bool enable_cali)
+{
+ return rawdata;
+}
+
static inline void mt6577_auxadc_mod_reg(void __iomem *reg,
u32 or_mask, u32 and_mask)
{
@@ -112,15 +133,17 @@ static int mt6577_auxadc_read(struct iio_dev *indio_dev,
/* we must delay here for hardware sample channel data */
udelay(MT6577_AUXADC_SAMPLE_READY_US);
- /* check MTK_AUXADC_CON2 if auxadc is idle */
- ret = readl_poll_timeout(adc_dev->reg_base + MT6577_AUXADC_CON2, val,
- ((val & MT6577_AUXADC_STA) == 0),
- MT6577_AUXADC_SLEEP_US,
- MT6577_AUXADC_TIMEOUT_US);
- if (ret < 0) {
- dev_err(indio_dev->dev.parent,
- "wait for auxadc idle time out\n");
- goto err_timeout;
+ if (adc_dev->dev_comp->check_global_idle) {
+ /* check MTK_AUXADC_CON2 if auxadc is idle */
+ ret = readl_poll_timeout(adc_dev->reg_base + MT6577_AUXADC_CON2,
+ val, ((val & MT6577_AUXADC_STA) == 0),
+ MT6577_AUXADC_SLEEP_US,
+ MT6577_AUXADC_TIMEOUT_US);
+ if (ret < 0) {
+ dev_err(indio_dev->dev.parent,
+ "wait for auxadc idle time out\n");
+ goto err_timeout;
+ }
}
/* read channel and make sure ready bit == 1 */
@@ -155,6 +178,8 @@ static int mt6577_auxadc_read_raw(struct iio_dev *indio_dev,
int *val2,
long info)
{
+ struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
+
switch (info) {
case IIO_CHAN_INFO_PROCESSED:
*val = mt6577_auxadc_read(indio_dev, chan);
@@ -164,6 +189,8 @@ static int mt6577_auxadc_read_raw(struct iio_dev *indio_dev,
chan->channel);
return *val;
}
+ if (adc_dev->dev_comp->sample_data_cali)
+ *val = mt_auxadc_get_cali_data(*val, true);
return IIO_VAL_INT;
default:
@@ -296,10 +323,11 @@ static SIMPLE_DEV_PM_OPS(mt6577_auxadc_pm_ops,
mt6577_auxadc_resume);
static const struct of_device_id mt6577_auxadc_of_match[] = {
- { .compatible = "mediatek,mt2701-auxadc", },
- { .compatible = "mediatek,mt2712-auxadc", },
- { .compatible = "mediatek,mt7622-auxadc", },
- { .compatible = "mediatek,mt8173-auxadc", },
+ { .compatible = "mediatek,mt2701-auxadc", .data = &mt8173_compat},
+ { .compatible = "mediatek,mt2712-auxadc", .data = &mt8173_compat},
+ { .compatible = "mediatek,mt7622-auxadc", .data = &mt8173_compat},
+ { .compatible = "mediatek,mt8173-auxadc", .data = &mt8173_compat},
+ { .compatible = "mediatek,mt6765-auxadc", .data = &mt6765_compat},
{ }
};
MODULE_DEVICE_TABLE(of, mt6577_auxadc_of_match);
diff --git a/drivers/iio/adc/rcar-gyroadc.c b/drivers/iio/adc/rcar-gyroadc.c
index 2c0d0316d149..2d685730f867 100644
--- a/drivers/iio/adc/rcar-gyroadc.c
+++ b/drivers/iio/adc/rcar-gyroadc.c
@@ -485,10 +485,8 @@ static int rcar_gyroadc_probe(struct platform_device *pdev)
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
- if (!indio_dev) {
- dev_err(dev, "Failed to allocate IIO device.\n");
+ if (!indio_dev)
return -ENOMEM;
- }
priv = iio_priv(indio_dev);
priv->dev = dev;
diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c
index 2327ec18b40c..1f7ce5186dfc 100644
--- a/drivers/iio/adc/stm32-adc-core.c
+++ b/drivers/iio/adc/stm32-adc-core.c
@@ -87,6 +87,7 @@ struct stm32_adc_priv_cfg {
* @domain: irq domain reference
* @aclk: clock reference for the analog circuitry
* @bclk: bus clock common for all ADCs, depends on part used
+ * @vdda: vdda analog supply reference
* @vref: regulator reference
* @cfg: compatible configuration data
* @common: common data for all ADC instances
@@ -97,6 +98,7 @@ struct stm32_adc_priv {
struct irq_domain *domain;
struct clk *aclk;
struct clk *bclk;
+ struct regulator *vdda;
struct regulator *vref;
const struct stm32_adc_priv_cfg *cfg;
struct stm32_adc_common common;
@@ -394,10 +396,16 @@ static int stm32_adc_core_hw_start(struct device *dev)
struct stm32_adc_priv *priv = to_stm32_adc_priv(common);
int ret;
+ ret = regulator_enable(priv->vdda);
+ if (ret < 0) {
+ dev_err(dev, "vdda enable failed %d\n", ret);
+ return ret;
+ }
+
ret = regulator_enable(priv->vref);
if (ret < 0) {
dev_err(dev, "vref enable failed\n");
- return ret;
+ goto err_vdda_disable;
}
if (priv->bclk) {
@@ -425,6 +433,8 @@ err_bclk_disable:
clk_disable_unprepare(priv->bclk);
err_regulator_disable:
regulator_disable(priv->vref);
+err_vdda_disable:
+ regulator_disable(priv->vdda);
return ret;
}
@@ -441,6 +451,7 @@ static void stm32_adc_core_hw_stop(struct device *dev)
if (priv->bclk)
clk_disable_unprepare(priv->bclk);
regulator_disable(priv->vref);
+ regulator_disable(priv->vdda);
}
static int stm32_adc_probe(struct platform_device *pdev)
@@ -468,6 +479,14 @@ static int stm32_adc_probe(struct platform_device *pdev)
return PTR_ERR(priv->common.base);
priv->common.phys_base = res->start;
+ priv->vdda = devm_regulator_get(&pdev->dev, "vdda");
+ if (IS_ERR(priv->vdda)) {
+ ret = PTR_ERR(priv->vdda);
+ if (ret != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "vdda get failed, %d\n", ret);
+ return ret;
+ }
+
priv->vref = devm_regulator_get(&pdev->dev, "vref");
if (IS_ERR(priv->vref)) {
ret = PTR_ERR(priv->vref);
diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c
index 19adc2b23472..ee1e0569d0e1 100644
--- a/drivers/iio/adc/stm32-dfsdm-adc.c
+++ b/drivers/iio/adc/stm32-dfsdm-adc.c
@@ -39,9 +39,16 @@
#define DFSDM_MAX_INT_OVERSAMPLING 256
#define DFSDM_MAX_FL_OVERSAMPLING 1024
-/* Max sample resolutions */
-#define DFSDM_MAX_RES BIT(31)
-#define DFSDM_DATA_RES BIT(23)
+/* Limit filter output resolution to 31 bits. (i.e. sample range is +/-2^30) */
+#define DFSDM_DATA_MAX BIT(30)
+/*
+ * Data are output as two's complement data in a 24 bit field.
+ * Data from filters are in the range +/-2^(n-1)
+ * 2^(n-1) maximum positive value cannot be coded in 2's complement n bits
+ * An extra bit is required to avoid wrap-around of the binary code for 2^(n-1)
+ * So, the resolution of samples from filter is actually limited to 23 bits
+ */
+#define DFSDM_DATA_RES 24
/* Filter configuration */
#define DFSDM_CR1_CFG_MASK (DFSDM_CR1_RCH_MASK | DFSDM_CR1_RCONT_MASK | \
@@ -181,14 +188,15 @@ static int stm32_dfsdm_get_jextsel(struct iio_dev *indio_dev,
return -EINVAL;
}
-static int stm32_dfsdm_set_osrs(struct stm32_dfsdm_filter *fl,
- unsigned int fast, unsigned int oversamp)
+static int stm32_dfsdm_compute_osrs(struct stm32_dfsdm_filter *fl,
+ unsigned int fast, unsigned int oversamp)
{
unsigned int i, d, fosr, iosr;
- u64 res;
- s64 delta;
+ u64 res, max;
+ int bits, shift;
unsigned int m = 1; /* multiplication factor */
unsigned int p = fl->ford; /* filter order (ford) */
+ struct stm32_dfsdm_filter_osr *flo = &fl->flo[fast];
pr_debug("%s: Requested oversampling: %d\n", __func__, oversamp);
/*
@@ -207,11 +215,8 @@ static int stm32_dfsdm_set_osrs(struct stm32_dfsdm_filter *fl,
/*
* Look for filter and integrator oversampling ratios which allows
- * to reach 24 bits data output resolution.
- * Leave as soon as if exact resolution if reached.
- * Otherwise the higher resolution below 32 bits is kept.
+ * to maximize data output resolution.
*/
- fl->res = 0;
for (fosr = 1; fosr <= DFSDM_MAX_FL_OVERSAMPLING; fosr++) {
for (iosr = 1; iosr <= DFSDM_MAX_INT_OVERSAMPLING; iosr++) {
if (fast)
@@ -236,33 +241,91 @@ static int stm32_dfsdm_set_osrs(struct stm32_dfsdm_filter *fl,
res = fosr;
for (i = p - 1; i > 0; i--) {
res = res * (u64)fosr;
- if (res > DFSDM_MAX_RES)
+ if (res > DFSDM_DATA_MAX)
break;
}
- if (res > DFSDM_MAX_RES)
+ if (res > DFSDM_DATA_MAX)
continue;
+
res = res * (u64)m * (u64)iosr;
- if (res > DFSDM_MAX_RES)
+ if (res > DFSDM_DATA_MAX)
continue;
- delta = res - DFSDM_DATA_RES;
-
- if (res >= fl->res) {
- fl->res = res;
- fl->fosr = fosr;
- fl->iosr = iosr;
- fl->fast = fast;
- pr_debug("%s: fosr = %d, iosr = %d\n",
- __func__, fl->fosr, fl->iosr);
+ if (res >= flo->res) {
+ flo->res = res;
+ flo->fosr = fosr;
+ flo->iosr = iosr;
+
+ bits = fls(flo->res);
+ /* 8 LBSs in data register contain chan info */
+ max = flo->res << 8;
+
+ /* if resolution is not a power of two */
+ if (flo->res > BIT(bits - 1))
+ bits++;
+ else
+ max--;
+
+ shift = DFSDM_DATA_RES - bits;
+ /*
+ * Compute right/left shift
+ * Right shift is performed by hardware
+ * when transferring samples to data register.
+ * Left shift is done by software on buffer
+ */
+ if (shift > 0) {
+ /* Resolution is lower than 24 bits */
+ flo->rshift = 0;
+ flo->lshift = shift;
+ } else {
+ /*
+ * If resolution is 24 bits or more,
+ * max positive value may be ambiguous
+ * (equal to max negative value as sign
+ * bit is dropped).
+ * Reduce resolution to 23 bits (rshift)
+ * to keep the sign on bit 23 and treat
+ * saturation before rescaling on 24
+ * bits (lshift).
+ */
+ flo->rshift = 1 - shift;
+ flo->lshift = 1;
+ max >>= flo->rshift;
+ }
+ flo->max = (s32)max;
+
+ pr_debug("%s: fast %d, fosr %d, iosr %d, res 0x%llx/%d bits, rshift %d, lshift %d\n",
+ __func__, fast, flo->fosr, flo->iosr,
+ flo->res, bits, flo->rshift,
+ flo->lshift);
}
-
- if (!delta)
- return 0;
}
}
- if (!fl->res)
+ if (!flo->res)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int stm32_dfsdm_compute_all_osrs(struct iio_dev *indio_dev,
+ unsigned int oversamp)
+{
+ struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
+ struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id];
+ int ret0, ret1;
+
+ memset(&fl->flo[0], 0, sizeof(fl->flo[0]));
+ memset(&fl->flo[1], 0, sizeof(fl->flo[1]));
+
+ ret0 = stm32_dfsdm_compute_osrs(fl, 0, oversamp);
+ ret1 = stm32_dfsdm_compute_osrs(fl, 1, oversamp);
+ if (ret0 < 0 && ret1 < 0) {
+ dev_err(&indio_dev->dev,
+ "Filter parameters not found: errors %d/%d\n",
+ ret0, ret1);
return -EINVAL;
+ }
return 0;
}
@@ -384,6 +447,50 @@ static int stm32_dfsdm_filter_set_trig(struct stm32_dfsdm_adc *adc,
return 0;
}
+static int stm32_dfsdm_channels_configure(struct stm32_dfsdm_adc *adc,
+ unsigned int fl_id,
+ struct iio_trigger *trig)
+{
+ struct iio_dev *indio_dev = iio_priv_to_dev(adc);
+ struct regmap *regmap = adc->dfsdm->regmap;
+ struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[fl_id];
+ struct stm32_dfsdm_filter_osr *flo = &fl->flo[0];
+ const struct iio_chan_spec *chan;
+ unsigned int bit;
+ int ret;
+
+ fl->fast = 0;
+
+ /*
+ * In continuous mode, use fast mode configuration,
+ * if it provides a better resolution.
+ */
+ if (adc->nconv == 1 && !trig &&
+ (indio_dev->currentmode & INDIO_BUFFER_SOFTWARE)) {
+ if (fl->flo[1].res >= fl->flo[0].res) {
+ fl->fast = 1;
+ flo = &fl->flo[1];
+ }
+ }
+
+ if (!flo->res)
+ return -EINVAL;
+
+ for_each_set_bit(bit, &adc->smask,
+ sizeof(adc->smask) * BITS_PER_BYTE) {
+ chan = indio_dev->channels + bit;
+
+ ret = regmap_update_bits(regmap,
+ DFSDM_CHCFGR2(chan->channel),
+ DFSDM_CHCFGR2_DTRBS_MASK,
+ DFSDM_CHCFGR2_DTRBS(flo->rshift));
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static int stm32_dfsdm_filter_configure(struct stm32_dfsdm_adc *adc,
unsigned int fl_id,
struct iio_trigger *trig)
@@ -391,6 +498,7 @@ static int stm32_dfsdm_filter_configure(struct stm32_dfsdm_adc *adc,
struct iio_dev *indio_dev = iio_priv_to_dev(adc);
struct regmap *regmap = adc->dfsdm->regmap;
struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[fl_id];
+ struct stm32_dfsdm_filter_osr *flo = &fl->flo[fl->fast];
u32 cr1;
const struct iio_chan_spec *chan;
unsigned int bit, jchg = 0;
@@ -398,13 +506,13 @@ static int stm32_dfsdm_filter_configure(struct stm32_dfsdm_adc *adc,
/* Average integrator oversampling */
ret = regmap_update_bits(regmap, DFSDM_FCR(fl_id), DFSDM_FCR_IOSR_MASK,
- DFSDM_FCR_IOSR(fl->iosr - 1));
+ DFSDM_FCR_IOSR(flo->iosr - 1));
if (ret)
return ret;
/* Filter order and Oversampling */
ret = regmap_update_bits(regmap, DFSDM_FCR(fl_id), DFSDM_FCR_FOSR_MASK,
- DFSDM_FCR_FOSR(fl->fosr - 1));
+ DFSDM_FCR_FOSR(flo->fosr - 1));
if (ret)
return ret;
@@ -417,6 +525,12 @@ static int stm32_dfsdm_filter_configure(struct stm32_dfsdm_adc *adc,
if (ret)
return ret;
+ ret = regmap_update_bits(regmap, DFSDM_CR1(fl_id),
+ DFSDM_CR1_FAST_MASK,
+ DFSDM_CR1_FAST(fl->fast));
+ if (ret)
+ return ret;
+
/*
* DFSDM modes configuration W.R.T audio/iio type modes
* ----------------------------------------------------------------
@@ -563,7 +677,6 @@ static int dfsdm_adc_set_samp_freq(struct iio_dev *indio_dev,
unsigned int spi_freq)
{
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
- struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id];
unsigned int oversamp;
int ret;
@@ -573,11 +686,10 @@ static int dfsdm_adc_set_samp_freq(struct iio_dev *indio_dev,
"Rate not accurate. requested (%u), actual (%u)\n",
sample_freq, spi_freq / oversamp);
- ret = stm32_dfsdm_set_osrs(fl, 0, oversamp);
- if (ret < 0) {
- dev_err(&indio_dev->dev, "No filter parameters that match!\n");
+ ret = stm32_dfsdm_compute_all_osrs(indio_dev, oversamp);
+ if (ret < 0)
return ret;
- }
+
adc->sample_freq = spi_freq / oversamp;
adc->oversamp = oversamp;
@@ -623,6 +735,10 @@ static int stm32_dfsdm_start_conv(struct stm32_dfsdm_adc *adc,
struct regmap *regmap = adc->dfsdm->regmap;
int ret;
+ ret = stm32_dfsdm_channels_configure(adc, adc->fl_id, trig);
+ if (ret < 0)
+ return ret;
+
ret = stm32_dfsdm_start_channel(adc);
if (ret < 0)
return ret;
@@ -702,6 +818,30 @@ static unsigned int stm32_dfsdm_adc_dma_residue(struct stm32_dfsdm_adc *adc)
return 0;
}
+static inline void stm32_dfsdm_process_data(struct stm32_dfsdm_adc *adc,
+ s32 *buffer)
+{
+ struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id];
+ struct stm32_dfsdm_filter_osr *flo = &fl->flo[fl->fast];
+ unsigned int i = adc->nconv;
+ s32 *ptr = buffer;
+
+ while (i--) {
+ /* Mask 8 LSB that contains the channel ID */
+ *ptr &= 0xFFFFFF00;
+ /* Convert 2^(n-1) sample to 2^(n-1)-1 to avoid wrap-around */
+ if (*ptr > flo->max)
+ *ptr -= 1;
+ /*
+ * Samples from filter are retrieved with 23 bits resolution
+ * or less. Shift left to align MSB on 24 bits.
+ */
+ *ptr <<= flo->lshift;
+
+ ptr++;
+ }
+}
+
static irqreturn_t stm32_dfsdm_adc_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
@@ -710,7 +850,9 @@ static irqreturn_t stm32_dfsdm_adc_trigger_handler(int irq, void *p)
int available = stm32_dfsdm_adc_dma_residue(adc);
while (available >= indio_dev->scan_bytes) {
- u32 *buffer = (u32 *)&adc->rx_buf[adc->bufi];
+ s32 *buffer = (s32 *)&adc->rx_buf[adc->bufi];
+
+ stm32_dfsdm_process_data(adc, buffer);
iio_push_to_buffers_with_timestamp(indio_dev, buffer,
pf->timestamp);
@@ -751,10 +893,10 @@ static void stm32_dfsdm_dma_buffer_done(void *data)
old_pos = adc->bufi;
while (available >= indio_dev->scan_bytes) {
- u32 *buffer = (u32 *)&adc->rx_buf[adc->bufi];
+ s32 *buffer = (s32 *)&adc->rx_buf[adc->bufi];
+
+ stm32_dfsdm_process_data(adc, buffer);
- /* Mask 8 LSB that contains the channel ID */
- *buffer = (*buffer & 0xFFFFFF00) << 8;
available -= indio_dev->scan_bytes;
adc->bufi += indio_dev->scan_bytes;
if (adc->bufi >= adc->buf_sz) {
@@ -776,6 +918,11 @@ static void stm32_dfsdm_dma_buffer_done(void *data)
static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev)
{
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
+ /*
+ * The DFSDM supports half-word transfers. However, for 16 bits record,
+ * 4 bytes buswidth is kept, to avoid losing samples LSBs when left
+ * shift is required.
+ */
struct dma_slave_config config = {
.src_addr = (dma_addr_t)adc->dfsdm->phys_base,
.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
@@ -1068,7 +1215,6 @@ static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev,
int val, int val2, long mask)
{
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
- struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id];
struct stm32_dfsdm_channel *ch = &adc->dfsdm->ch_list[chan->channel];
unsigned int spi_freq;
int ret = -EINVAL;
@@ -1078,7 +1224,7 @@ static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev,
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
- ret = stm32_dfsdm_set_osrs(fl, 0, val);
+ ret = stm32_dfsdm_compute_all_osrs(indio_dev, val);
if (!ret)
adc->oversamp = val;
iio_device_release_direct_mode(indio_dev);
@@ -1277,11 +1423,11 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev,
BIT(IIO_CHAN_INFO_SAMP_FREQ);
if (adc->dev_data->type == DFSDM_AUDIO) {
- ch->scan_type.sign = 's';
ch->ext_info = dfsdm_adc_audio_ext_info;
} else {
- ch->scan_type.sign = 'u';
+ ch->scan_type.shift = 8;
}
+ ch->scan_type.sign = 's';
ch->scan_type.realbits = 24;
ch->scan_type.storagebits = 32;
@@ -1327,8 +1473,7 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev)
int ret, chan_idx;
adc->oversamp = DFSDM_DEFAULT_OVERSAMPLING;
- ret = stm32_dfsdm_set_osrs(&adc->dfsdm->fl_list[adc->fl_id], 0,
- adc->oversamp);
+ ret = stm32_dfsdm_compute_all_osrs(indio_dev, adc->oversamp);
if (ret < 0)
return ret;
@@ -1456,6 +1601,12 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev)
* So IRQ associated to filter instance 0 is dedicated to the Filter 0.
*/
irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ if (irq != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get IRQ: %d\n", irq);
+ return irq;
+ }
+
ret = devm_request_irq(dev, irq, stm32_dfsdm_irq,
0, pdev->name, adc);
if (ret < 0) {
diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c
index 0a4d3746d21c..26e2011c5868 100644
--- a/drivers/iio/adc/stm32-dfsdm-core.c
+++ b/drivers/iio/adc/stm32-dfsdm-core.c
@@ -233,6 +233,8 @@ static int stm32_dfsdm_parse_of(struct platform_device *pdev,
}
priv->dfsdm.phys_base = res->start;
priv->dfsdm.base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv->dfsdm.base))
+ return PTR_ERR(priv->dfsdm.base);
/*
* "dfsdm" clock is mandatory for DFSDM peripheral clocking.
@@ -242,8 +244,10 @@ static int stm32_dfsdm_parse_of(struct platform_device *pdev,
*/
priv->clk = devm_clk_get(&pdev->dev, "dfsdm");
if (IS_ERR(priv->clk)) {
- dev_err(&pdev->dev, "No stm32_dfsdm_clk clock found\n");
- return -EINVAL;
+ ret = PTR_ERR(priv->clk);
+ if (ret != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Failed to get clock (%d)\n", ret);
+ return ret;
}
priv->aclk = devm_clk_get(&pdev->dev, "audio");
diff --git a/drivers/iio/adc/stm32-dfsdm.h b/drivers/iio/adc/stm32-dfsdm.h
index 8708394b0725..5dbdae4ed881 100644
--- a/drivers/iio/adc/stm32-dfsdm.h
+++ b/drivers/iio/adc/stm32-dfsdm.h
@@ -243,19 +243,33 @@ enum stm32_dfsdm_sinc_order {
};
/**
- * struct stm32_dfsdm_filter - structure relative to stm32 FDSDM filter
+ * struct stm32_dfsdm_filter_osr - DFSDM filter settings linked to oversampling
* @iosr: integrator oversampling
* @fosr: filter oversampling
- * @ford: filter order
+ * @rshift: output sample right shift (hardware shift)
+ * @lshift: output sample left shift (software shift)
* @res: output sample resolution
+ * @max: output sample maximum positive value
+ */
+struct stm32_dfsdm_filter_osr {
+ unsigned int iosr;
+ unsigned int fosr;
+ unsigned int rshift;
+ unsigned int lshift;
+ u64 res;
+ s32 max;
+};
+
+/**
+ * struct stm32_dfsdm_filter - structure relative to stm32 FDSDM filter
+ * @ford: filter order
+ * @flo: filter oversampling data table indexed by fast mode flag
* @sync_mode: filter synchronized with filter 0
* @fast: filter fast mode
*/
struct stm32_dfsdm_filter {
- unsigned int iosr;
- unsigned int fosr;
enum stm32_dfsdm_sinc_order ford;
- u64 res;
+ struct stm32_dfsdm_filter_osr flo[2];
unsigned int sync_mode;
unsigned int fast;
};
diff --git a/drivers/iio/adc/stmpe-adc.c b/drivers/iio/adc/stmpe-adc.c
index 7921f827c6ec..bd72727fc417 100644
--- a/drivers/iio/adc/stmpe-adc.c
+++ b/drivers/iio/adc/stmpe-adc.c
@@ -65,6 +65,8 @@ static int stmpe_read_voltage(struct stmpe_adc *info,
mutex_lock(&info->lock);
+ reinit_completion(&info->completion);
+
info->channel = (u8)chan->channel;
if (info->channel > STMPE_ADC_LAST_NR) {
@@ -72,23 +74,16 @@ static int stmpe_read_voltage(struct stmpe_adc *info,
return -EINVAL;
}
- stmpe_reg_write(info->stmpe, STMPE_REG_ADC_INT_EN,
- STMPE_ADC_CH(info->channel));
-
stmpe_reg_write(info->stmpe, STMPE_REG_ADC_CAPT,
STMPE_ADC_CH(info->channel));
- *val = info->value;
-
- ret = wait_for_completion_interruptible_timeout
- (&info->completion, STMPE_ADC_TIMEOUT);
+ ret = wait_for_completion_timeout(&info->completion, STMPE_ADC_TIMEOUT);
if (ret <= 0) {
+ stmpe_reg_write(info->stmpe, STMPE_REG_ADC_INT_STA,
+ STMPE_ADC_CH(info->channel));
mutex_unlock(&info->lock);
- if (ret == 0)
- return -ETIMEDOUT;
- else
- return ret;
+ return -ETIMEDOUT;
}
*val = info->value;
@@ -105,6 +100,8 @@ static int stmpe_read_temp(struct stmpe_adc *info,
mutex_lock(&info->lock);
+ reinit_completion(&info->completion);
+
info->channel = (u8)chan->channel;
if (info->channel != STMPE_TEMP_CHANNEL) {
@@ -115,15 +112,11 @@ static int stmpe_read_temp(struct stmpe_adc *info,
stmpe_reg_write(info->stmpe, STMPE_REG_TEMP_CTRL,
STMPE_START_ONE_TEMP_CONV);
- ret = wait_for_completion_interruptible_timeout
- (&info->completion, STMPE_ADC_TIMEOUT);
+ ret = wait_for_completion_timeout(&info->completion, STMPE_ADC_TIMEOUT);
if (ret <= 0) {
mutex_unlock(&info->lock);
- if (ret == 0)
- return -ETIMEDOUT;
- else
- return ret;
+ return -ETIMEDOUT;
}
/*
@@ -331,6 +324,12 @@ static int stmpe_adc_probe(struct platform_device *pdev)
if (ret)
return ret;
+ stmpe_reg_write(info->stmpe, STMPE_REG_ADC_INT_EN,
+ ~(norequest_mask & 0xFF));
+
+ stmpe_reg_write(info->stmpe, STMPE_REG_ADC_INT_STA,
+ ~(norequest_mask & 0xFF));
+
return devm_iio_device_register(&pdev->dev, indio_dev);
}
@@ -353,9 +352,14 @@ static struct platform_driver stmpe_adc_driver = {
.pm = &stmpe_adc_pm_ops,
},
};
-
module_platform_driver(stmpe_adc_driver);
+static const struct of_device_id stmpe_adc_ids[] = {
+ { .compatible = "st,stmpe-adc", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, stmpe_adc_ids);
+
MODULE_AUTHOR("Stefan Agner <stefan.agner@toradex.com>");
MODULE_DESCRIPTION("STMPEXXX ADC driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
index 04d7147e0110..f13c6248a662 100644
--- a/drivers/iio/adc/sun4i-gpadc-iio.c
+++ b/drivers/iio/adc/sun4i-gpadc-iio.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/* ADC driver for sunxi platforms' (A10, A13 and A31) GPADC
*
* Copyright (c) 2016 Quentin Schulz <quentin.schulz@free-electrons.com>
*
- * 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.
- *
* The Allwinner SoCs all have an ADC that can also act as a touchscreen
* controller and a thermal sensor.
* The thermal sensor works only when the ADC acts as a touchscreen controller
diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c
index 405e3779c0c5..0235863ff77b 100644
--- a/drivers/iio/adc/ti-adc081c.c
+++ b/drivers/iio/adc/ti-adc081c.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TI ADC081C/ADC101C/ADC121C 8/10/12-bit ADC driver
*
* Copyright (C) 2012 Avionic Design GmbH
* Copyright (C) 2016 Intel
*
- * 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.
- *
* Datasheets:
* http://www.ti.com/lit/ds/symlink/adc081c021.pdf
* http://www.ti.com/lit/ds/symlink/adc101c021.pdf
diff --git a/drivers/iio/adc/ti-adc084s021.c b/drivers/iio/adc/ti-adc084s021.c
index 25504640e126..bdedf456ee05 100644
--- a/drivers/iio/adc/ti-adc084s021.c
+++ b/drivers/iio/adc/ti-adc084s021.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/**
* Copyright (C) 2017 Axis Communications AB
*
* Driver for Texas Instruments' ADC084S021 ADC chip.
* Datasheets can be found here:
* http://www.ti.com/lit/ds/symlink/adc084s021.pdf
- *
- * 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.
*/
#include <linux/err.h>
diff --git a/drivers/iio/adc/ti-ads8688.c b/drivers/iio/adc/ti-ads8688.c
index 8cb7a2034982..14fe7c320b52 100644
--- a/drivers/iio/adc/ti-ads8688.c
+++ b/drivers/iio/adc/ti-ads8688.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2015 Prevas A/S
- *
- * 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.
*/
#include <linux/device.h>
diff --git a/drivers/iio/adc/ti-tlc4541.c b/drivers/iio/adc/ti-tlc4541.c
index 2290024c89fc..4965246808bd 100644
--- a/drivers/iio/adc/ti-tlc4541.c
+++ b/drivers/iio/adc/ti-tlc4541.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TI tlc4541 ADC Driver
*
@@ -7,10 +8,6 @@
* http://www.ti.com/lit/gpn/tlc3541
* http://www.ti.com/lit/gpn/tlc4541
*
- * 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.
- *
* The tlc4541 requires 24 clock cycles to start a transfer.
* Conversion then takes 2.94us to complete before data is ready
* Data is returned MSB first.
diff --git a/drivers/iio/amplifiers/Kconfig b/drivers/iio/amplifiers/Kconfig
index 863d73519c0d..da7f126d197b 100644
--- a/drivers/iio/amplifiers/Kconfig
+++ b/drivers/iio/amplifiers/Kconfig
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0-only
+# SPDX-License-Identifier: GPL-2.0
#
# Gain Amplifiers, etc.
#
@@ -7,12 +7,17 @@
menu "Amplifiers"
config AD8366
- tristate "Analog Devices AD8366 VGA"
+ tristate "Analog Devices AD8366 and similar Gain Amplifiers"
depends on SPI
+ depends on GPIOLIB
select BITREVERSE
help
- Say yes here to build support for Analog Devices AD8366
- SPI Dual-Digital Variable Gain Amplifier (VGA).
+ Say yes here to build support for Analog Devices AD8366 and similar
+ gain amplifiers. This driver supports the following gain amplifiers
+ from Analog Devices:
+ AD8366 Dual-Digital Variable Gain Amplifier (VGA)
+ ADA4961 BiCMOS RF Digital Gain Amplifier (DGA)
+ ADL5240 Digitally controlled variable gain amplifier (VGA)
To compile this driver as a module, choose M here: the
module will be called ad8366.
diff --git a/drivers/iio/amplifiers/ad8366.c b/drivers/iio/amplifiers/ad8366.c
index 3d6246f86429..0176d3d8cc9c 100644
--- a/drivers/iio/amplifiers/ad8366.c
+++ b/drivers/iio/amplifiers/ad8366.c
@@ -1,8 +1,12 @@
-// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-License-Identifier: GPL-2.0
/*
- * AD8366 SPI Dual-Digital Variable Gain Amplifier (VGA)
+ * AD8366 and similar Gain Amplifiers
+ * This driver supports the following gain amplifiers:
+ * AD8366 Dual-Digital Variable Gain Amplifier (VGA)
+ * ADA4961 BiCMOS RF Digital Gain Amplifier (DGA)
+ * ADL5240 Digitally controlled variable gain amplifier (VGA)
*
- * Copyright 2012 Analog Devices Inc.
+ * Copyright 2012-2019 Analog Devices Inc.
*/
#include <linux/device.h>
@@ -11,6 +15,7 @@
#include <linux/sysfs.h>
#include <linux/spi/spi.h>
#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/bitrev.h>
@@ -18,10 +23,25 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
+enum ad8366_type {
+ ID_AD8366,
+ ID_ADA4961,
+ ID_ADL5240,
+};
+
+struct ad8366_info {
+ int gain_min;
+ int gain_max;
+};
+
struct ad8366_state {
struct spi_device *spi;
struct regulator *reg;
+ struct mutex lock; /* protect sensor state */
+ struct gpio_desc *reset_gpio;
unsigned char ch[2];
+ enum ad8366_type type;
+ struct ad8366_info *info;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
@@ -29,19 +49,44 @@ struct ad8366_state {
unsigned char data[2] ____cacheline_aligned;
};
+static struct ad8366_info ad8366_infos[] = {
+ [ID_AD8366] = {
+ .gain_min = 4500,
+ .gain_max = 20500,
+ },
+ [ID_ADA4961] = {
+ .gain_min = -6000,
+ .gain_max = 15000,
+ },
+ [ID_ADL5240] = {
+ .gain_min = -11500,
+ .gain_max = 20000,
+ },
+};
+
static int ad8366_write(struct iio_dev *indio_dev,
unsigned char ch_a, unsigned char ch_b)
{
struct ad8366_state *st = iio_priv(indio_dev);
int ret;
- ch_a = bitrev8(ch_a & 0x3F);
- ch_b = bitrev8(ch_b & 0x3F);
+ switch (st->type) {
+ case ID_AD8366:
+ ch_a = bitrev8(ch_a & 0x3F);
+ ch_b = bitrev8(ch_b & 0x3F);
- st->data[0] = ch_b >> 4;
- st->data[1] = (ch_b << 4) | (ch_a >> 2);
+ st->data[0] = ch_b >> 4;
+ st->data[1] = (ch_b << 4) | (ch_a >> 2);
+ break;
+ case ID_ADA4961:
+ st->data[0] = ch_a & 0x1F;
+ break;
+ case ID_ADL5240:
+ st->data[0] = (ch_a & 0x3F);
+ break;
+ }
- ret = spi_write(st->spi, st->data, ARRAY_SIZE(st->data));
+ ret = spi_write(st->spi, st->data, indio_dev->num_channels);
if (ret < 0)
dev_err(&indio_dev->dev, "write failed (%d)", ret);
@@ -56,24 +101,35 @@ static int ad8366_read_raw(struct iio_dev *indio_dev,
{
struct ad8366_state *st = iio_priv(indio_dev);
int ret;
- unsigned code;
+ int code, gain = 0;
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&st->lock);
switch (m) {
case IIO_CHAN_INFO_HARDWAREGAIN:
code = st->ch[chan->channel];
+ switch (st->type) {
+ case ID_AD8366:
+ gain = code * 253 + 4500;
+ break;
+ case ID_ADA4961:
+ gain = 15000 - code * 1000;
+ break;
+ case ID_ADL5240:
+ gain = 20000 - 31500 + code * 500;
+ break;
+ }
+
/* Values in dB */
- code = code * 253 + 4500;
- *val = code / 1000;
- *val2 = (code % 1000) * 1000;
+ *val = gain / 1000;
+ *val2 = (gain % 1000) * 1000;
ret = IIO_VAL_INT_PLUS_MICRO_DB;
break;
default:
ret = -EINVAL;
}
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&st->lock);
return ret;
};
@@ -85,21 +141,32 @@ static int ad8366_write_raw(struct iio_dev *indio_dev,
long mask)
{
struct ad8366_state *st = iio_priv(indio_dev);
- unsigned code;
+ struct ad8366_info *inf = st->info;
+ int code = 0, gain;
int ret;
- if (val < 0 || val2 < 0)
- return -EINVAL;
-
/* Values in dB */
- code = (((u8)val * 1000) + ((u32)val2 / 1000));
+ if (val < 0)
+ gain = (val * 1000) - (val2 / 1000);
+ else
+ gain = (val * 1000) + (val2 / 1000);
- if (code > 20500 || code < 4500)
+ if (gain > inf->gain_max || gain < inf->gain_min)
return -EINVAL;
- code = (code - 4500) / 253;
+ switch (st->type) {
+ case ID_AD8366:
+ code = (gain - 4500) / 253;
+ break;
+ case ID_ADA4961:
+ code = (15000 - gain) / 1000;
+ break;
+ case ID_ADL5240:
+ code = ((gain - 500 - 20000) / 500) & 0x3F;
+ break;
+ }
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&st->lock);
switch (mask) {
case IIO_CHAN_INFO_HARDWAREGAIN:
st->ch[chan->channel] = code;
@@ -108,7 +175,7 @@ static int ad8366_write_raw(struct iio_dev *indio_dev,
default:
ret = -EINVAL;
}
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&st->lock);
return ret;
}
@@ -131,6 +198,10 @@ static const struct iio_chan_spec ad8366_channels[] = {
AD8366_CHAN(1),
};
+static const struct iio_chan_spec ada4961_channels[] = {
+ AD8366_CHAN(0),
+};
+
static int ad8366_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
@@ -151,14 +222,33 @@ static int ad8366_probe(struct spi_device *spi)
}
spi_set_drvdata(spi, indio_dev);
+ mutex_init(&st->lock);
st->spi = spi;
+ st->type = spi_get_device_id(spi)->driver_data;
+
+ switch (st->type) {
+ case ID_AD8366:
+ indio_dev->channels = ad8366_channels;
+ indio_dev->num_channels = ARRAY_SIZE(ad8366_channels);
+ break;
+ case ID_ADA4961:
+ case ID_ADL5240:
+ st->reset_gpio = devm_gpiod_get(&spi->dev, "reset",
+ GPIOD_OUT_HIGH);
+ indio_dev->channels = ada4961_channels;
+ indio_dev->num_channels = ARRAY_SIZE(ada4961_channels);
+ break;
+ default:
+ dev_err(&spi->dev, "Invalid device ID\n");
+ ret = -EINVAL;
+ goto error_disable_reg;
+ }
+ st->info = &ad8366_infos[st->type];
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->info = &ad8366_info;
indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->channels = ad8366_channels;
- indio_dev->num_channels = ARRAY_SIZE(ad8366_channels);
ret = ad8366_write(indio_dev, 0 , 0);
if (ret < 0)
@@ -192,7 +282,9 @@ static int ad8366_remove(struct spi_device *spi)
}
static const struct spi_device_id ad8366_id[] = {
- {"ad8366", 0},
+ {"ad8366", ID_AD8366},
+ {"ada4961", ID_ADA4961},
+ {"adl5240", ID_ADL5240},
{}
};
MODULE_DEVICE_TABLE(spi, ad8366_id);
@@ -209,5 +301,5 @@ static struct spi_driver ad8366_driver = {
module_spi_driver(ad8366_driver);
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
-MODULE_DESCRIPTION("Analog Devices AD8366 VGA");
+MODULE_DESCRIPTION("Analog Devices AD8366 and similar Gain Amplifiers");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/buffer/industrialio-buffer-cb.c b/drivers/iio/buffer/industrialio-buffer-cb.c
index df21e7dbec40..47c96f7f4976 100644
--- a/drivers/iio/buffer/industrialio-buffer-cb.c
+++ b/drivers/iio/buffer/industrialio-buffer-cb.c
@@ -1,8 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* The industrial I/O callback buffer
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/iio/buffer/industrialio-triggered-buffer.c b/drivers/iio/buffer/industrialio-triggered-buffer.c
index d3db1fce54d2..cb322b2f09cd 100644
--- a/drivers/iio/buffer/industrialio-triggered-buffer.c
+++ b/drivers/iio/buffer/industrialio-triggered-buffer.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012 Analog Devices, Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/iio/chemical/ccs811.c b/drivers/iio/chemical/ccs811.c
index b4a46eb45789..2ebdfc35bcda 100644
--- a/drivers/iio/chemical/ccs811.c
+++ b/drivers/iio/chemical/ccs811.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ccs811.c - Support for AMS CCS811 VOC Sensor
*
@@ -5,10 +6,6 @@
*
* Datasheet: ams.com/content/download/951091/2269479/CCS811_DS000459_3-00.pdf
*
- * 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.
- *
* IIO driver for AMS CCS811 (I2C address 0x5A/0x5B set by ADDR Low/High)
*
* TODO:
diff --git a/drivers/iio/common/cros_ec_sensors/Kconfig b/drivers/iio/common/cros_ec_sensors/Kconfig
index f9bf7ff7fcaf..bcb58fb76b9f 100644
--- a/drivers/iio/common/cros_ec_sensors/Kconfig
+++ b/drivers/iio/common/cros_ec_sensors/Kconfig
@@ -21,3 +21,12 @@ config IIO_CROS_EC_SENSORS
Accelerometers, Gyroscope and Magnetometer that are
presented by the ChromeOS EC Sensor hub.
Creates an IIO device for each functions.
+
+config IIO_CROS_EC_SENSORS_LID_ANGLE
+ tristate "ChromeOS EC Sensor for lid angle"
+ depends on IIO_CROS_EC_SENSORS_CORE
+ help
+ Module to report the angle between lid and base for some
+ convertible devices.
+ This module is loaded when the EC can calculate the angle between the base
+ and the lid.
diff --git a/drivers/iio/common/cros_ec_sensors/Makefile b/drivers/iio/common/cros_ec_sensors/Makefile
index 7c2d6a966fe6..e0a33ab66d21 100644
--- a/drivers/iio/common/cros_ec_sensors/Makefile
+++ b/drivers/iio/common/cros_ec_sensors/Makefile
@@ -5,3 +5,4 @@
obj-$(CONFIG_IIO_CROS_EC_SENSORS_CORE) += cros_ec_sensors_core.o
obj-$(CONFIG_IIO_CROS_EC_SENSORS) += cros_ec_sensors.o
+obj-$(CONFIG_IIO_CROS_EC_SENSORS_LID_ANGLE) += cros_ec_lid_angle.o
diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c b/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c
new file mode 100644
index 000000000000..876dfd176b0e
--- /dev/null
+++ b/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * cros_ec_lid_angle - Driver for CrOS EC lid angle sensor.
+ *
+ * Copyright 2018 Google, Inc
+ *
+ * This driver uses the cros-ec interface to communicate with the Chrome OS
+ * EC about counter sensors. Counters are presented through
+ * iio sysfs.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/common/cros_ec_sensors_core.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/kernel.h>
+#include <linux/mfd/cros_ec.h>
+#include <linux/mfd/cros_ec_commands.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define DRV_NAME "cros-ec-lid-angle"
+
+/*
+ * One channel for the lid angle, the other for timestamp.
+ */
+static const struct iio_chan_spec cros_ec_lid_angle_channels[] = {
+ {
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .scan_type.realbits = CROS_EC_SENSOR_BITS,
+ .scan_type.storagebits = CROS_EC_SENSOR_BITS,
+ .scan_type.sign = 'u',
+ .type = IIO_ANGL
+ },
+ IIO_CHAN_SOFT_TIMESTAMP(1)
+};
+
+/* State data for ec_sensors iio driver. */
+struct cros_ec_lid_angle_state {
+ /* Shared by all sensors */
+ struct cros_ec_sensors_core_state core;
+};
+
+static int cros_ec_sensors_read_lid_angle(struct iio_dev *indio_dev,
+ unsigned long scan_mask, s16 *data)
+{
+ struct cros_ec_sensors_core_state *st = iio_priv(indio_dev);
+ int ret;
+
+ st->param.cmd = MOTIONSENSE_CMD_LID_ANGLE;
+ ret = cros_ec_motion_send_host_cmd(st, sizeof(st->resp->lid_angle));
+ if (ret) {
+ dev_warn(&indio_dev->dev, "Unable to read lid angle\n");
+ return ret;
+ }
+
+ *data = st->resp->lid_angle.value;
+ return 0;
+}
+
+static int cros_ec_lid_angle_read(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct cros_ec_lid_angle_state *st = iio_priv(indio_dev);
+ s16 data;
+ int ret;
+
+ mutex_lock(&st->core.cmd_lock);
+ ret = cros_ec_sensors_read_lid_angle(indio_dev, 1, &data);
+ if (ret == 0) {
+ *val = data;
+ ret = IIO_VAL_INT;
+ }
+ mutex_unlock(&st->core.cmd_lock);
+ return ret;
+}
+
+static const struct iio_info cros_ec_lid_angle_info = {
+ .read_raw = &cros_ec_lid_angle_read,
+};
+
+static int cros_ec_lid_angle_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct iio_dev *indio_dev;
+ struct cros_ec_lid_angle_state *state;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*state));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ ret = cros_ec_sensors_core_init(pdev, indio_dev, false);
+ if (ret)
+ return ret;
+
+ indio_dev->info = &cros_ec_lid_angle_info;
+ state = iio_priv(indio_dev);
+ indio_dev->channels = cros_ec_lid_angle_channels;
+ indio_dev->num_channels = ARRAY_SIZE(cros_ec_lid_angle_channels);
+
+ state->core.read_ec_sensors_data = cros_ec_sensors_read_lid_angle;
+
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
+ cros_ec_sensors_capture, NULL);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct platform_device_id cros_ec_lid_angle_ids[] = {
+ {
+ .name = DRV_NAME,
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, cros_ec_lid_angle_ids);
+
+static struct platform_driver cros_ec_lid_angle_platform_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .pm = &cros_ec_sensors_pm_ops,
+ },
+ .probe = cros_ec_lid_angle_probe,
+ .id_table = cros_ec_lid_angle_ids,
+};
+module_platform_driver(cros_ec_lid_angle_platform_driver);
+
+MODULE_DESCRIPTION("ChromeOS EC driver for reporting convertible lid angle.");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
index 719a0df5aeeb..130362ca421b 100644
--- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
+++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
@@ -125,6 +125,15 @@ static ssize_t cros_ec_sensors_calibrate(struct iio_dev *indio_dev,
return ret ? ret : len;
}
+static ssize_t cros_ec_sensors_id(struct iio_dev *indio_dev,
+ uintptr_t private,
+ const struct iio_chan_spec *chan, char *buf)
+{
+ struct cros_ec_sensors_core_state *st = iio_priv(indio_dev);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", st->param.info.sensor_num);
+}
+
static ssize_t cros_ec_sensors_loc(struct iio_dev *indio_dev,
uintptr_t private, const struct iio_chan_spec *chan,
char *buf)
@@ -141,6 +150,11 @@ const struct iio_chan_spec_ext_info cros_ec_sensors_ext_info[] = {
.write = cros_ec_sensors_calibrate
},
{
+ .name = "id",
+ .shared = IIO_SHARED_BY_ALL,
+ .read = cros_ec_sensors_id
+ },
+ {
.name = "location",
.shared = IIO_SHARED_BY_ALL,
.read = cros_ec_sensors_loc
diff --git a/drivers/iio/common/ms_sensors/ms_sensors_i2c.h b/drivers/iio/common/ms_sensors/ms_sensors_i2c.h
index 7b614adc5cae..bad09c80e47a 100644
--- a/drivers/iio/common/ms_sensors/ms_sensors_i2c.h
+++ b/drivers/iio/common/ms_sensors/ms_sensors_i2c.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Measurements Specialties common sensor driver
*
* Copyright (c) 2015 Measurement-Specialties
- *
- * 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.
*/
#ifndef _MS_SENSORS_I2C_H
diff --git a/drivers/iio/dac/ad5758.c b/drivers/iio/dac/ad5758.c
index a513c70faefa..475646c82b40 100644
--- a/drivers/iio/dac/ad5758.c
+++ b/drivers/iio/dac/ad5758.c
@@ -11,6 +11,8 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/property.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/spi/spi.h>
#include <linux/gpio/consumer.h>
@@ -582,7 +584,7 @@ static ssize_t ad5758_write_powerdown(struct iio_dev *indio_dev,
{
struct ad5758_state *st = iio_priv(indio_dev);
bool pwr_down;
- unsigned int dc_dc_mode, dac_config_mode, val;
+ unsigned int dac_config_mode, val;
unsigned long int dac_config_msk;
int ret;
@@ -591,13 +593,10 @@ static ssize_t ad5758_write_powerdown(struct iio_dev *indio_dev,
return ret;
mutex_lock(&st->lock);
- if (pwr_down) {
- dc_dc_mode = AD5758_DCDC_MODE_POWER_OFF;
+ if (pwr_down)
val = 0;
- } else {
- dc_dc_mode = st->dc_dc_mode;
+ else
val = 1;
- }
dac_config_mode = AD5758_DAC_CONFIG_OUT_EN_MODE(val) |
AD5758_DAC_CONFIG_INT_EN_MODE(val);
@@ -885,9 +884,16 @@ static const struct spi_device_id ad5758_id[] = {
};
MODULE_DEVICE_TABLE(spi, ad5758_id);
+static const struct of_device_id ad5758_of_match[] = {
+ { .compatible = "adi,ad5758" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ad5758_of_match);
+
static struct spi_driver ad5758_driver = {
.driver = {
.name = KBUILD_MODNAME,
+ .of_match_table = ad5758_of_match,
},
.probe = ad5758_probe,
.id_table = ad5758_id,
diff --git a/drivers/iio/dac/ds4424.c b/drivers/iio/dac/ds4424.c
index 714a97f91319..26d206681472 100644
--- a/drivers/iio/dac/ds4424.c
+++ b/drivers/iio/dac/ds4424.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Maxim Integrated
* 7-bit, Multi-Channel Sink/Source Current DAC Driver
* Copyright (C) 2017 Maxim Integrated
- *
- * 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.
*/
#include <linux/kernel.h>
@@ -236,12 +233,6 @@ static int ds4424_probe(struct i2c_client *client,
indio_dev->dev.of_node = client->dev.of_node;
indio_dev->dev.parent = &client->dev;
- if (!client->dev.of_node) {
- dev_err(&client->dev,
- "Not found DT.\n");
- return -ENODEV;
- }
-
data->vcc_reg = devm_regulator_get(&client->dev, "vcc");
if (IS_ERR(data->vcc_reg)) {
dev_err(&client->dev,
diff --git a/drivers/iio/dac/lpc18xx_dac.c b/drivers/iio/dac/lpc18xx_dac.c
index 7036f77fdf23..883e84e96609 100644
--- a/drivers/iio/dac/lpc18xx_dac.c
+++ b/drivers/iio/dac/lpc18xx_dac.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* IIO DAC driver for NXP LPC18xx DAC
*
* Copyright (C) 2016 Joachim Eastwood <manabian@gmail.com>
*
- * 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.
- *
* UNSUPPORTED hardware features:
* - Interrupts
* - DMA
diff --git a/drivers/iio/dac/max5821.c b/drivers/iio/dac/max5821.c
index f0cf6903dcd2..2da086e372af 100644
--- a/drivers/iio/dac/max5821.c
+++ b/drivers/iio/dac/max5821.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* iio/dac/max5821.c
* Copyright (C) 2014 Philippe Reynes
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/iio/dac/ti-dac082s085.c b/drivers/iio/dac/ti-dac082s085.c
index 4e1e28339c84..57b498d2a2a5 100644
--- a/drivers/iio/dac/ti-dac082s085.c
+++ b/drivers/iio/dac/ti-dac082s085.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ti-dac082s085.c - Texas Instruments 8/10/12-bit 2/4-channel DAC driver
*
@@ -9,10 +10,6 @@
* http://www.ti.com/lit/ds/symlink/dac084s085.pdf
* http://www.ti.com/lit/ds/symlink/dac104s085.pdf
* http://www.ti.com/lit/ds/symlink/dac124s085.pdf
- *
- * 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.
*/
#include <linux/iio/iio.h>
diff --git a/drivers/iio/dac/ti-dac5571.c b/drivers/iio/dac/ti-dac5571.c
index 891e9cac019e..3a2bb0efe50d 100644
--- a/drivers/iio/dac/ti-dac5571.c
+++ b/drivers/iio/dac/ti-dac5571.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ti-dac5571.c - Texas Instruments 8/10/12-bit 1/4-channel DAC driver
*
@@ -12,10 +13,6 @@
* http://www.ti.com/lit/ds/symlink/dac5573.pdf
* http://www.ti.com/lit/ds/symlink/dac6573.pdf
* http://www.ti.com/lit/ds/symlink/dac7573.pdf
- *
- * 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.
*/
#include <linux/iio/iio.h>
diff --git a/drivers/iio/dummy/iio_dummy_evgen.c b/drivers/iio/dummy/iio_dummy_evgen.c
index c6033e341963..a6edf30567aa 100644
--- a/drivers/iio/dummy/iio_dummy_evgen.c
+++ b/drivers/iio/dummy/iio_dummy_evgen.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/**
* Copyright (c) 2011 Jonathan Cameron
*
- * 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.
- *
* Companion module to the iio simple dummy example driver.
* The purpose of this is to generate 'fake' event interrupts thus
* allowing that driver's code to be as close as possible to that of
diff --git a/drivers/iio/dummy/iio_simple_dummy.c b/drivers/iio/dummy/iio_simple_dummy.c
index 62052479c349..8f99c005458a 100644
--- a/drivers/iio/dummy/iio_simple_dummy.c
+++ b/drivers/iio/dummy/iio_simple_dummy.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/**
* Copyright (c) 2011 Jonathan Cameron
*
- * 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.
- *
* A reference industrial I/O driver to illustrate the functionality available.
*
* There are numerous real drivers to illustrate the finer points.
diff --git a/drivers/iio/dummy/iio_simple_dummy.h b/drivers/iio/dummy/iio_simple_dummy.h
index f7005c3f5df3..a91622ac54e0 100644
--- a/drivers/iio/dummy/iio_simple_dummy.h
+++ b/drivers/iio/dummy/iio_simple_dummy.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/**
* Copyright (c) 2011 Jonathan Cameron
*
- * 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.
- *
* Join together the various functionality of iio_simple_dummy driver
*/
diff --git a/drivers/iio/dummy/iio_simple_dummy_buffer.c b/drivers/iio/dummy/iio_simple_dummy_buffer.c
index 744ca92c3c99..17606eca42b4 100644
--- a/drivers/iio/dummy/iio_simple_dummy_buffer.c
+++ b/drivers/iio/dummy/iio_simple_dummy_buffer.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/**
* Copyright (c) 2011 Jonathan Cameron
*
- * 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.
- *
* Buffer handling elements of industrial I/O reference driver.
* Uses the kfifo buffer.
*
diff --git a/drivers/iio/dummy/iio_simple_dummy_events.c b/drivers/iio/dummy/iio_simple_dummy_events.c
index 7ec2a0bb0807..b3abaaca6f5e 100644
--- a/drivers/iio/dummy/iio_simple_dummy_events.c
+++ b/drivers/iio/dummy/iio_simple_dummy_events.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/**
* Copyright (c) 2011 Jonathan Cameron
*
- * 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.
- *
* Event handling elements of industrial I/O reference driver.
*/
#include <linux/kernel.h>
diff --git a/drivers/iio/frequency/Kconfig b/drivers/iio/frequency/Kconfig
index c86db8b42380..240b81502512 100644
--- a/drivers/iio/frequency/Kconfig
+++ b/drivers/iio/frequency/Kconfig
@@ -39,5 +39,15 @@ config ADF4350
To compile this driver as a module, choose M here: the
module will be called adf4350.
+config ADF4371
+ tristate "Analog Devices ADF4371/ADF4372 Wideband Synthesizers"
+ depends on SPI
+ select REGMAP_SPI
+ help
+ Say yes here to build support for Analog Devices ADF4371 and ADF4372
+ Wideband Synthesizers. The driver provides direct access via sysfs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called adf4371.
endmenu
endmenu
diff --git a/drivers/iio/frequency/Makefile b/drivers/iio/frequency/Makefile
index f2e396d40ddd..518b1e50caef 100644
--- a/drivers/iio/frequency/Makefile
+++ b/drivers/iio/frequency/Makefile
@@ -6,3 +6,4 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AD9523) += ad9523.o
obj-$(CONFIG_ADF4350) += adf4350.o
+obj-$(CONFIG_ADF4371) += adf4371.o
diff --git a/drivers/iio/frequency/ad9523.c b/drivers/iio/frequency/ad9523.c
index 9691524ce5b0..a7322184cbdd 100644
--- a/drivers/iio/frequency/ad9523.c
+++ b/drivers/iio/frequency/ad9523.c
@@ -861,9 +861,11 @@ static int ad9523_setup(struct iio_dev *indio_dev)
if (ret < 0)
return ret;
- st->vco_freq = (pdata->vcxo_freq * (pdata->pll2_freq_doubler_en ? 2 : 1)
- / pdata->pll2_r2_div) * AD9523_PLL2_FB_NDIV(pdata->
- pll2_ndiv_a_cnt, pdata->pll2_ndiv_b_cnt);
+ st->vco_freq = div_u64((unsigned long long)pdata->vcxo_freq *
+ (pdata->pll2_freq_doubler_en ? 2 : 1) *
+ AD9523_PLL2_FB_NDIV(pdata->pll2_ndiv_a_cnt,
+ pdata->pll2_ndiv_b_cnt),
+ pdata->pll2_r2_div);
ret = ad9523_write(indio_dev, AD9523_PLL2_VCO_CTRL,
AD9523_PLL2_VCO_CALIBRATE);
diff --git a/drivers/iio/frequency/adf4371.c b/drivers/iio/frequency/adf4371.c
new file mode 100644
index 000000000000..e48f15cc9ab5
--- /dev/null
+++ b/drivers/iio/frequency/adf4371.c
@@ -0,0 +1,632 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Analog Devices ADF4371 SPI Wideband Synthesizer driver
+ *
+ * Copyright 2019 Analog Devices Inc.
+ */
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gcd.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/sysfs.h>
+#include <linux/spi/spi.h>
+
+#include <linux/iio/iio.h>
+
+/* Registers address macro */
+#define ADF4371_REG(x) (x)
+
+/* ADF4371_REG0 */
+#define ADF4371_ADDR_ASC_MSK BIT(2)
+#define ADF4371_ADDR_ASC(x) FIELD_PREP(ADF4371_ADDR_ASC_MSK, x)
+#define ADF4371_ADDR_ASC_R_MSK BIT(5)
+#define ADF4371_ADDR_ASC_R(x) FIELD_PREP(ADF4371_ADDR_ASC_R_MSK, x)
+#define ADF4371_RESET_CMD 0x81
+
+/* ADF4371_REG17 */
+#define ADF4371_FRAC2WORD_L_MSK GENMASK(7, 1)
+#define ADF4371_FRAC2WORD_L(x) FIELD_PREP(ADF4371_FRAC2WORD_L_MSK, x)
+#define ADF4371_FRAC1WORD_MSK BIT(0)
+#define ADF4371_FRAC1WORD(x) FIELD_PREP(ADF4371_FRAC1WORD_MSK, x)
+
+/* ADF4371_REG18 */
+#define ADF4371_FRAC2WORD_H_MSK GENMASK(6, 0)
+#define ADF4371_FRAC2WORD_H(x) FIELD_PREP(ADF4371_FRAC2WORD_H_MSK, x)
+
+/* ADF4371_REG1A */
+#define ADF4371_MOD2WORD_MSK GENMASK(5, 0)
+#define ADF4371_MOD2WORD(x) FIELD_PREP(ADF4371_MOD2WORD_MSK, x)
+
+/* ADF4371_REG24 */
+#define ADF4371_RF_DIV_SEL_MSK GENMASK(6, 4)
+#define ADF4371_RF_DIV_SEL(x) FIELD_PREP(ADF4371_RF_DIV_SEL_MSK, x)
+
+/* ADF4371_REG25 */
+#define ADF4371_MUTE_LD_MSK BIT(7)
+#define ADF4371_MUTE_LD(x) FIELD_PREP(ADF4371_MUTE_LD_MSK, x)
+
+/* ADF4371_REG32 */
+#define ADF4371_TIMEOUT_MSK GENMASK(1, 0)
+#define ADF4371_TIMEOUT(x) FIELD_PREP(ADF4371_TIMEOUT_MSK, x)
+
+/* ADF4371_REG34 */
+#define ADF4371_VCO_ALC_TOUT_MSK GENMASK(4, 0)
+#define ADF4371_VCO_ALC_TOUT(x) FIELD_PREP(ADF4371_VCO_ALC_TOUT_MSK, x)
+
+/* Specifications */
+#define ADF4371_MIN_VCO_FREQ 4000000000ULL /* 4000 MHz */
+#define ADF4371_MAX_VCO_FREQ 8000000000ULL /* 8000 MHz */
+#define ADF4371_MAX_OUT_RF8_FREQ ADF4371_MAX_VCO_FREQ /* Hz */
+#define ADF4371_MIN_OUT_RF8_FREQ (ADF4371_MIN_VCO_FREQ / 64) /* Hz */
+#define ADF4371_MAX_OUT_RF16_FREQ (ADF4371_MAX_VCO_FREQ * 2) /* Hz */
+#define ADF4371_MIN_OUT_RF16_FREQ (ADF4371_MIN_VCO_FREQ * 2) /* Hz */
+#define ADF4371_MAX_OUT_RF32_FREQ (ADF4371_MAX_VCO_FREQ * 4) /* Hz */
+#define ADF4371_MIN_OUT_RF32_FREQ (ADF4371_MIN_VCO_FREQ * 4) /* Hz */
+
+#define ADF4371_MAX_FREQ_PFD 250000000UL /* Hz */
+#define ADF4371_MAX_FREQ_REFIN 600000000UL /* Hz */
+
+/* MOD1 is a 24-bit primary modulus with fixed value of 2^25 */
+#define ADF4371_MODULUS1 33554432ULL
+/* MOD2 is the programmable, 14-bit auxiliary fractional modulus */
+#define ADF4371_MAX_MODULUS2 BIT(14)
+
+#define ADF4371_CHECK_RANGE(freq, range) \
+ ((freq > ADF4371_MAX_ ## range) || (freq < ADF4371_MIN_ ## range))
+
+enum {
+ ADF4371_FREQ,
+ ADF4371_POWER_DOWN,
+ ADF4371_CHANNEL_NAME
+};
+
+enum {
+ ADF4371_CH_RF8,
+ ADF4371_CH_RFAUX8,
+ ADF4371_CH_RF16,
+ ADF4371_CH_RF32
+};
+
+enum adf4371_variant {
+ ADF4371,
+ ADF4372
+};
+
+struct adf4371_pwrdown {
+ unsigned int reg;
+ unsigned int bit;
+};
+
+static const char * const adf4371_ch_names[] = {
+ "RF8x", "RFAUX8x", "RF16x", "RF32x"
+};
+
+static const struct adf4371_pwrdown adf4371_pwrdown_ch[4] = {
+ [ADF4371_CH_RF8] = { ADF4371_REG(0x25), 2 },
+ [ADF4371_CH_RFAUX8] = { ADF4371_REG(0x72), 3 },
+ [ADF4371_CH_RF16] = { ADF4371_REG(0x25), 3 },
+ [ADF4371_CH_RF32] = { ADF4371_REG(0x25), 4 },
+};
+
+static const struct reg_sequence adf4371_reg_defaults[] = {
+ { ADF4371_REG(0x0), 0x18 },
+ { ADF4371_REG(0x12), 0x40 },
+ { ADF4371_REG(0x1E), 0x48 },
+ { ADF4371_REG(0x20), 0x14 },
+ { ADF4371_REG(0x22), 0x00 },
+ { ADF4371_REG(0x23), 0x00 },
+ { ADF4371_REG(0x24), 0x80 },
+ { ADF4371_REG(0x25), 0x07 },
+ { ADF4371_REG(0x27), 0xC5 },
+ { ADF4371_REG(0x28), 0x83 },
+ { ADF4371_REG(0x2C), 0x44 },
+ { ADF4371_REG(0x2D), 0x11 },
+ { ADF4371_REG(0x2E), 0x12 },
+ { ADF4371_REG(0x2F), 0x94 },
+ { ADF4371_REG(0x32), 0x04 },
+ { ADF4371_REG(0x35), 0xFA },
+ { ADF4371_REG(0x36), 0x30 },
+ { ADF4371_REG(0x39), 0x07 },
+ { ADF4371_REG(0x3A), 0x55 },
+ { ADF4371_REG(0x3E), 0x0C },
+ { ADF4371_REG(0x3F), 0x80 },
+ { ADF4371_REG(0x40), 0x50 },
+ { ADF4371_REG(0x41), 0x28 },
+ { ADF4371_REG(0x47), 0xC0 },
+ { ADF4371_REG(0x52), 0xF4 },
+ { ADF4371_REG(0x70), 0x03 },
+ { ADF4371_REG(0x71), 0x60 },
+ { ADF4371_REG(0x72), 0x32 },
+};
+
+static const struct regmap_config adf4371_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .read_flag_mask = BIT(7),
+};
+
+struct adf4371_chip_info {
+ unsigned int num_channels;
+ const struct iio_chan_spec *channels;
+};
+
+struct adf4371_state {
+ struct spi_device *spi;
+ struct regmap *regmap;
+ struct clk *clkin;
+ /*
+ * Lock for accessing device registers. Some operations require
+ * multiple consecutive R/W operations, during which the device
+ * shouldn't be interrupted. The buffers are also shared across
+ * all operations so need to be protected on stand alone reads and
+ * writes.
+ */
+ struct mutex lock;
+ const struct adf4371_chip_info *chip_info;
+ unsigned long clkin_freq;
+ unsigned long fpfd;
+ unsigned int integer;
+ unsigned int fract1;
+ unsigned int fract2;
+ unsigned int mod2;
+ unsigned int rf_div_sel;
+ unsigned int ref_div_factor;
+ u8 buf[10] ____cacheline_aligned;
+};
+
+static unsigned long long adf4371_pll_fract_n_get_rate(struct adf4371_state *st,
+ u32 channel)
+{
+ unsigned long long val, tmp;
+ unsigned int ref_div_sel;
+
+ val = (((u64)st->integer * ADF4371_MODULUS1) + st->fract1) * st->fpfd;
+ tmp = (u64)st->fract2 * st->fpfd;
+ do_div(tmp, st->mod2);
+ val += tmp + ADF4371_MODULUS1 / 2;
+
+ if (channel == ADF4371_CH_RF8 || channel == ADF4371_CH_RFAUX8)
+ ref_div_sel = st->rf_div_sel;
+ else
+ ref_div_sel = 0;
+
+ do_div(val, ADF4371_MODULUS1 * (1 << ref_div_sel));
+
+ if (channel == ADF4371_CH_RF16)
+ val <<= 1;
+ else if (channel == ADF4371_CH_RF32)
+ val <<= 2;
+
+ return val;
+}
+
+static void adf4371_pll_fract_n_compute(unsigned long long vco,
+ unsigned long long pfd,
+ unsigned int *integer,
+ unsigned int *fract1,
+ unsigned int *fract2,
+ unsigned int *mod2)
+{
+ unsigned long long tmp;
+ u32 gcd_div;
+
+ tmp = do_div(vco, pfd);
+ tmp = tmp * ADF4371_MODULUS1;
+ *fract2 = do_div(tmp, pfd);
+
+ *integer = vco;
+ *fract1 = tmp;
+
+ *mod2 = pfd;
+
+ while (*mod2 > ADF4371_MAX_MODULUS2) {
+ *mod2 >>= 1;
+ *fract2 >>= 1;
+ }
+
+ gcd_div = gcd(*fract2, *mod2);
+ *mod2 /= gcd_div;
+ *fract2 /= gcd_div;
+}
+
+static int adf4371_set_freq(struct adf4371_state *st, unsigned long long freq,
+ unsigned int channel)
+{
+ u32 cp_bleed;
+ u8 int_mode = 0;
+ int ret;
+
+ switch (channel) {
+ case ADF4371_CH_RF8:
+ case ADF4371_CH_RFAUX8:
+ if (ADF4371_CHECK_RANGE(freq, OUT_RF8_FREQ))
+ return -EINVAL;
+
+ st->rf_div_sel = 0;
+
+ while (freq < ADF4371_MIN_VCO_FREQ) {
+ freq <<= 1;
+ st->rf_div_sel++;
+ }
+ break;
+ case ADF4371_CH_RF16:
+ /* ADF4371 RF16 8000...16000 MHz */
+ if (ADF4371_CHECK_RANGE(freq, OUT_RF16_FREQ))
+ return -EINVAL;
+
+ freq >>= 1;
+ break;
+ case ADF4371_CH_RF32:
+ /* ADF4371 RF32 16000...32000 MHz */
+ if (ADF4371_CHECK_RANGE(freq, OUT_RF32_FREQ))
+ return -EINVAL;
+
+ freq >>= 2;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ adf4371_pll_fract_n_compute(freq, st->fpfd, &st->integer, &st->fract1,
+ &st->fract2, &st->mod2);
+ st->buf[0] = st->integer >> 8;
+ st->buf[1] = 0x40; /* REG12 default */
+ st->buf[2] = 0x00;
+ st->buf[3] = st->fract2 & 0xFF;
+ st->buf[4] = st->fract2 >> 7;
+ st->buf[5] = st->fract2 >> 15;
+ st->buf[6] = ADF4371_FRAC2WORD_L(st->fract2 & 0x7F) |
+ ADF4371_FRAC1WORD(st->fract1 >> 23);
+ st->buf[7] = ADF4371_FRAC2WORD_H(st->fract2 >> 7);
+ st->buf[8] = st->mod2 & 0xFF;
+ st->buf[9] = ADF4371_MOD2WORD(st->mod2 >> 8);
+
+ ret = regmap_bulk_write(st->regmap, ADF4371_REG(0x11), st->buf, 10);
+ if (ret < 0)
+ return ret;
+ /*
+ * The R counter allows the input reference frequency to be
+ * divided down to produce the reference clock to the PFD
+ */
+ ret = regmap_write(st->regmap, ADF4371_REG(0x1F), st->ref_div_factor);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_update_bits(st->regmap, ADF4371_REG(0x24),
+ ADF4371_RF_DIV_SEL_MSK,
+ ADF4371_RF_DIV_SEL(st->rf_div_sel));
+ if (ret < 0)
+ return ret;
+
+ cp_bleed = DIV_ROUND_UP(400 * 1750, st->integer * 375);
+ cp_bleed = clamp(cp_bleed, 1U, 255U);
+ ret = regmap_write(st->regmap, ADF4371_REG(0x26), cp_bleed);
+ if (ret < 0)
+ return ret;
+ /*
+ * Set to 1 when in INT mode (when FRAC1 = FRAC2 = 0),
+ * and set to 0 when in FRAC mode.
+ */
+ if (st->fract1 == 0 && st->fract2 == 0)
+ int_mode = 0x01;
+
+ ret = regmap_write(st->regmap, ADF4371_REG(0x2B), int_mode);
+ if (ret < 0)
+ return ret;
+
+ return regmap_write(st->regmap, ADF4371_REG(0x10), st->integer & 0xFF);
+}
+
+static ssize_t adf4371_read(struct iio_dev *indio_dev,
+ uintptr_t private,
+ const struct iio_chan_spec *chan,
+ char *buf)
+{
+ struct adf4371_state *st = iio_priv(indio_dev);
+ unsigned long long val = 0;
+ unsigned int readval, reg, bit;
+ int ret;
+
+ switch ((u32)private) {
+ case ADF4371_FREQ:
+ val = adf4371_pll_fract_n_get_rate(st, chan->channel);
+ ret = regmap_read(st->regmap, ADF4371_REG(0x7C), &readval);
+ if (ret < 0)
+ break;
+
+ if (readval == 0x00) {
+ dev_dbg(&st->spi->dev, "PLL un-locked\n");
+ ret = -EBUSY;
+ }
+ break;
+ case ADF4371_POWER_DOWN:
+ reg = adf4371_pwrdown_ch[chan->channel].reg;
+ bit = adf4371_pwrdown_ch[chan->channel].bit;
+
+ ret = regmap_read(st->regmap, reg, &readval);
+ if (ret < 0)
+ break;
+
+ val = !(readval & BIT(bit));
+ break;
+ case ADF4371_CHANNEL_NAME:
+ return sprintf(buf, "%s\n", adf4371_ch_names[chan->channel]);
+ default:
+ ret = -EINVAL;
+ val = 0;
+ break;
+ }
+
+ return ret < 0 ? ret : sprintf(buf, "%llu\n", val);
+}
+
+static ssize_t adf4371_write(struct iio_dev *indio_dev,
+ uintptr_t private,
+ const struct iio_chan_spec *chan,
+ const char *buf, size_t len)
+{
+ struct adf4371_state *st = iio_priv(indio_dev);
+ unsigned long long freq;
+ bool power_down;
+ unsigned int bit, readval, reg;
+ int ret;
+
+ mutex_lock(&st->lock);
+ switch ((u32)private) {
+ case ADF4371_FREQ:
+ ret = kstrtoull(buf, 10, &freq);
+ if (ret)
+ break;
+
+ ret = adf4371_set_freq(st, freq, chan->channel);
+ break;
+ case ADF4371_POWER_DOWN:
+ ret = kstrtobool(buf, &power_down);
+ if (ret)
+ break;
+
+ reg = adf4371_pwrdown_ch[chan->channel].reg;
+ bit = adf4371_pwrdown_ch[chan->channel].bit;
+ ret = regmap_read(st->regmap, reg, &readval);
+ if (ret < 0)
+ break;
+
+ readval &= ~BIT(bit);
+ readval |= (!power_down << bit);
+
+ ret = regmap_write(st->regmap, reg, readval);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ mutex_unlock(&st->lock);
+
+ return ret ? ret : len;
+}
+
+#define _ADF4371_EXT_INFO(_name, _ident) { \
+ .name = _name, \
+ .read = adf4371_read, \
+ .write = adf4371_write, \
+ .private = _ident, \
+ .shared = IIO_SEPARATE, \
+}
+
+static const struct iio_chan_spec_ext_info adf4371_ext_info[] = {
+ /*
+ * Ideally we use IIO_CHAN_INFO_FREQUENCY, but there are
+ * values > 2^32 in order to support the entire frequency range
+ * in Hz. Using scale is a bit ugly.
+ */
+ _ADF4371_EXT_INFO("frequency", ADF4371_FREQ),
+ _ADF4371_EXT_INFO("powerdown", ADF4371_POWER_DOWN),
+ _ADF4371_EXT_INFO("name", ADF4371_CHANNEL_NAME),
+ { },
+};
+
+#define ADF4371_CHANNEL(index) { \
+ .type = IIO_ALTVOLTAGE, \
+ .output = 1, \
+ .channel = index, \
+ .ext_info = adf4371_ext_info, \
+ .indexed = 1, \
+ }
+
+static const struct iio_chan_spec adf4371_chan[] = {
+ ADF4371_CHANNEL(ADF4371_CH_RF8),
+ ADF4371_CHANNEL(ADF4371_CH_RFAUX8),
+ ADF4371_CHANNEL(ADF4371_CH_RF16),
+ ADF4371_CHANNEL(ADF4371_CH_RF32),
+};
+
+static const struct adf4371_chip_info adf4371_chip_info[] = {
+ [ADF4371] = {
+ .channels = adf4371_chan,
+ .num_channels = 4,
+ },
+ [ADF4372] = {
+ .channels = adf4371_chan,
+ .num_channels = 3,
+ }
+};
+
+static int adf4371_reg_access(struct iio_dev *indio_dev,
+ unsigned int reg,
+ unsigned int writeval,
+ unsigned int *readval)
+{
+ struct adf4371_state *st = iio_priv(indio_dev);
+
+ if (readval)
+ return regmap_read(st->regmap, reg, readval);
+ else
+ return regmap_write(st->regmap, reg, writeval);
+}
+
+static const struct iio_info adf4371_info = {
+ .debugfs_reg_access = &adf4371_reg_access,
+};
+
+static int adf4371_setup(struct adf4371_state *st)
+{
+ unsigned int synth_timeout = 2, timeout = 1, vco_alc_timeout = 1;
+ unsigned int vco_band_div, tmp;
+ int ret;
+
+ /* Perform a software reset */
+ ret = regmap_write(st->regmap, ADF4371_REG(0x0), ADF4371_RESET_CMD);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_multi_reg_write(st->regmap, adf4371_reg_defaults,
+ ARRAY_SIZE(adf4371_reg_defaults));
+ if (ret < 0)
+ return ret;
+
+ /* Mute to Lock Detect */
+ if (device_property_read_bool(&st->spi->dev, "adi,mute-till-lock-en")) {
+ ret = regmap_update_bits(st->regmap, ADF4371_REG(0x25),
+ ADF4371_MUTE_LD_MSK,
+ ADF4371_MUTE_LD(1));
+ if (ret < 0)
+ return ret;
+ }
+
+ /* Set address in ascending order, so the bulk_write() will work */
+ ret = regmap_update_bits(st->regmap, ADF4371_REG(0x0),
+ ADF4371_ADDR_ASC_MSK | ADF4371_ADDR_ASC_R_MSK,
+ ADF4371_ADDR_ASC(1) | ADF4371_ADDR_ASC_R(1));
+ if (ret < 0)
+ return ret;
+ /*
+ * Calculate and maximize PFD frequency
+ * fPFD = REFIN × ((1 + D)/(R × (1 + T)))
+ * Where D is the REFIN doubler bit, T is the reference divide by 2,
+ * R is the reference division factor
+ * TODO: it is assumed D and T equal 0.
+ */
+ do {
+ st->ref_div_factor++;
+ st->fpfd = st->clkin_freq / st->ref_div_factor;
+ } while (st->fpfd > ADF4371_MAX_FREQ_PFD);
+
+ /* Calculate Timeouts */
+ vco_band_div = DIV_ROUND_UP(st->fpfd, 2400000U);
+
+ tmp = DIV_ROUND_CLOSEST(st->fpfd, 1000000U);
+ do {
+ timeout++;
+ if (timeout > 1023) {
+ timeout = 2;
+ synth_timeout++;
+ }
+ } while (synth_timeout * 1024 + timeout <= 20 * tmp);
+
+ do {
+ vco_alc_timeout++;
+ } while (vco_alc_timeout * 1024 - timeout <= 50 * tmp);
+
+ st->buf[0] = vco_band_div;
+ st->buf[1] = timeout & 0xFF;
+ st->buf[2] = ADF4371_TIMEOUT(timeout >> 8) | 0x04;
+ st->buf[3] = synth_timeout;
+ st->buf[4] = ADF4371_VCO_ALC_TOUT(vco_alc_timeout);
+
+ return regmap_bulk_write(st->regmap, ADF4371_REG(0x30), st->buf, 5);
+}
+
+static void adf4371_clk_disable(void *data)
+{
+ struct adf4371_state *st = data;
+
+ clk_disable_unprepare(st->clkin);
+}
+
+static int adf4371_probe(struct spi_device *spi)
+{
+ const struct spi_device_id *id = spi_get_device_id(spi);
+ struct iio_dev *indio_dev;
+ struct adf4371_state *st;
+ struct regmap *regmap;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ regmap = devm_regmap_init_spi(spi, &adf4371_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(&spi->dev, "Error initializing spi regmap: %ld\n",
+ PTR_ERR(regmap));
+ return PTR_ERR(regmap);
+ }
+
+ st = iio_priv(indio_dev);
+ spi_set_drvdata(spi, indio_dev);
+ st->spi = spi;
+ st->regmap = regmap;
+ mutex_init(&st->lock);
+
+ st->chip_info = &adf4371_chip_info[id->driver_data];
+ indio_dev->dev.parent = &spi->dev;
+ indio_dev->name = id->name;
+ indio_dev->info = &adf4371_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = st->chip_info->channels;
+ indio_dev->num_channels = st->chip_info->num_channels;
+
+ st->clkin = devm_clk_get(&spi->dev, "clkin");
+ if (IS_ERR(st->clkin))
+ return PTR_ERR(st->clkin);
+
+ ret = clk_prepare_enable(st->clkin);
+ if (ret < 0)
+ return ret;
+
+ ret = devm_add_action_or_reset(&spi->dev, adf4371_clk_disable, st);
+ if (ret)
+ return ret;
+
+ st->clkin_freq = clk_get_rate(st->clkin);
+
+ ret = adf4371_setup(st);
+ if (ret < 0) {
+ dev_err(&spi->dev, "ADF4371 setup failed\n");
+ return ret;
+ }
+
+ return devm_iio_device_register(&spi->dev, indio_dev);
+}
+
+static const struct spi_device_id adf4371_id_table[] = {
+ { "adf4371", ADF4371 },
+ { "adf4372", ADF4372 },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, adf4371_id_table);
+
+static const struct of_device_id adf4371_of_match[] = {
+ { .compatible = "adi,adf4371" },
+ { .compatible = "adi,adf4372" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, adf4371_of_match);
+
+static struct spi_driver adf4371_driver = {
+ .driver = {
+ .name = "adf4371",
+ .of_match_table = adf4371_of_match,
+ },
+ .probe = adf4371_probe,
+ .id_table = adf4371_id_table,
+};
+module_spi_driver(adf4371_driver);
+
+MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
+MODULE_DESCRIPTION("Analog Devices ADF4371 SPI PLL");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/gyro/itg3200_buffer.c b/drivers/iio/gyro/itg3200_buffer.c
index 59770e5b6660..d3fbe9d86467 100644
--- a/drivers/iio/gyro/itg3200_buffer.c
+++ b/drivers/iio/gyro/itg3200_buffer.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* itg3200_buffer.c -- support InvenSense ITG3200
* Digital 3-Axis Gyroscope driver
@@ -5,10 +6,6 @@
* Copyright (c) 2011 Christian Strobel <christian.strobel@iis.fraunhofer.de>
* Copyright (c) 2011 Manuel Stahl <manuel.stahl@iis.fraunhofer.de>
* Copyright (c) 2012 Thorsten Nowak <thorsten.nowak@iis.fraunhofer.de>
- *
- * 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.
*/
#include <linux/slab.h>
diff --git a/drivers/iio/gyro/itg3200_core.c b/drivers/iio/gyro/itg3200_core.c
index 203a6be33b70..998fb8d66fe3 100644
--- a/drivers/iio/gyro/itg3200_core.c
+++ b/drivers/iio/gyro/itg3200_core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* itg3200_core.c -- support InvenSense ITG3200
* Digital 3-Axis Gyroscope driver
@@ -6,10 +7,6 @@
* Copyright (c) 2011 Manuel Stahl <manuel.stahl@iis.fraunhofer.de>
* Copyright (c) 2012 Thorsten Nowak <thorsten.nowak@iis.fraunhofer.de>
*
- * 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.
- *
* TODO:
* - Support digital low pass filter
* - Support power management
diff --git a/drivers/iio/humidity/dht11.c b/drivers/iio/humidity/dht11.c
index c8159205c77d..b459600e1a33 100644
--- a/drivers/iio/humidity/dht11.c
+++ b/drivers/iio/humidity/dht11.c
@@ -22,8 +22,7 @@
#include <linux/completion.h>
#include <linux/mutex.h>
#include <linux/delay.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/timekeeping.h>
#include <linux/iio/iio.h>
@@ -72,7 +71,7 @@
struct dht11 {
struct device *dev;
- int gpio;
+ struct gpio_desc *gpiod;
int irq;
struct completion completion;
@@ -149,7 +148,7 @@ static int dht11_decode(struct dht11 *dht11, int offset)
return -EIO;
}
- dht11->timestamp = ktime_get_boot_ns();
+ dht11->timestamp = ktime_get_boottime_ns();
if (hum_int < 4) { /* DHT22: 100000 = (3*256+232)*100 */
dht11->temperature = (((temp_int & 0x7f) << 8) + temp_dec) *
((temp_int & 0x80) ? -100 : 100);
@@ -177,9 +176,9 @@ static irqreturn_t dht11_handle_irq(int irq, void *data)
/* TODO: Consider making the handler safe for IRQ sharing */
if (dht11->num_edges < DHT11_EDGES_PER_READ && dht11->num_edges >= 0) {
- dht11->edges[dht11->num_edges].ts = ktime_get_boot_ns();
+ dht11->edges[dht11->num_edges].ts = ktime_get_boottime_ns();
dht11->edges[dht11->num_edges++].value =
- gpio_get_value(dht11->gpio);
+ gpiod_get_value(dht11->gpiod);
if (dht11->num_edges >= DHT11_EDGES_PER_READ)
complete(&dht11->completion);
@@ -196,7 +195,7 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
int ret, timeres, offset;
mutex_lock(&dht11->lock);
- if (dht11->timestamp + DHT11_DATA_VALID_TIME < ktime_get_boot_ns()) {
+ if (dht11->timestamp + DHT11_DATA_VALID_TIME < ktime_get_boottime_ns()) {
timeres = ktime_get_resolution_ns();
dev_dbg(dht11->dev, "current timeresolution: %dns\n", timeres);
if (timeres > DHT11_MIN_TIMERES) {
@@ -217,12 +216,12 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
reinit_completion(&dht11->completion);
dht11->num_edges = 0;
- ret = gpio_direction_output(dht11->gpio, 0);
+ ret = gpiod_direction_output(dht11->gpiod, 0);
if (ret)
goto err;
usleep_range(DHT11_START_TRANSMISSION_MIN,
DHT11_START_TRANSMISSION_MAX);
- ret = gpio_direction_input(dht11->gpio);
+ ret = gpiod_direction_input(dht11->gpiod);
if (ret)
goto err;
@@ -294,10 +293,8 @@ MODULE_DEVICE_TABLE(of, dht11_dt_ids);
static int dht11_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct device_node *node = dev->of_node;
struct dht11 *dht11;
struct iio_dev *iio;
- int ret;
iio = devm_iio_device_alloc(dev, sizeof(*dht11));
if (!iio) {
@@ -307,22 +304,17 @@ static int dht11_probe(struct platform_device *pdev)
dht11 = iio_priv(iio);
dht11->dev = dev;
+ dht11->gpiod = devm_gpiod_get(dev, NULL, GPIOD_IN);
+ if (IS_ERR(dht11->gpiod))
+ return PTR_ERR(dht11->gpiod);
- ret = of_get_gpio(node, 0);
- if (ret < 0)
- return ret;
- dht11->gpio = ret;
- ret = devm_gpio_request_one(dev, dht11->gpio, GPIOF_IN, pdev->name);
- if (ret)
- return ret;
-
- dht11->irq = gpio_to_irq(dht11->gpio);
+ dht11->irq = gpiod_to_irq(dht11->gpiod);
if (dht11->irq < 0) {
- dev_err(dev, "GPIO %d has no interrupt\n", dht11->gpio);
+ dev_err(dev, "GPIO %d has no interrupt\n", desc_to_gpio(dht11->gpiod));
return -EINVAL;
}
- dht11->timestamp = ktime_get_boot_ns() - DHT11_DATA_VALID_TIME - 1;
+ dht11->timestamp = ktime_get_boottime_ns() - DHT11_DATA_VALID_TIME - 1;
dht11->num_edges = -1;
platform_set_drvdata(pdev, iio);
diff --git a/drivers/iio/humidity/si7020.c b/drivers/iio/humidity/si7020.c
index 1b2ec8df1a72..b938f07eed64 100644
--- a/drivers/iio/humidity/si7020.c
+++ b/drivers/iio/humidity/si7020.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* si7020.c - Silicon Labs Si7013/20/21 Relative Humidity and Temp Sensors
* Copyright (c) 2013,2014 Uplogix, Inc.
* David Barksdale <dbarksdale@uplogix.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
/*
diff --git a/drivers/iio/iio_core.h b/drivers/iio/iio_core.h
index c775fedbcaf6..159ea3f8c02b 100644
--- a/drivers/iio/iio_core.h
+++ b/drivers/iio/iio_core.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/* The industrial I/O core function defs.
*
* Copyright (c) 2008 Jonathan Cameron
*
- * 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.
- *
* These definitions are meant for use only within the IIO core, not individual
* drivers.
*/
diff --git a/drivers/iio/iio_core_trigger.h b/drivers/iio/iio_core_trigger.h
index 1fdb1e4ea4a5..e59fe2f36bbb 100644
--- a/drivers/iio/iio_core_trigger.h
+++ b/drivers/iio/iio_core_trigger.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/* The industrial I/O core, trigger consumer handling functions
*
* Copyright (c) 2008 Jonathan Cameron
- *
- * 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.
*/
#ifdef CONFIG_IIO_TRIGGER
diff --git a/drivers/iio/imu/adis16400.c b/drivers/iio/imu/adis16400.c
index beb6919e7180..0575ff706bd4 100644
--- a/drivers/iio/imu/adis16400.c
+++ b/drivers/iio/imu/adis16400.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* adis16400.c support Analog Devices ADIS16400/5
* 3d 2g Linear Accelerometers,
@@ -7,11 +8,6 @@
* Copyright (c) 2009 Manuel Stahl <manuel.stahl@iis.fraunhofer.de>
* Copyright (c) 2007 Jonathan Cameron <jic23@kernel.org>
* Copyright (c) 2011 Analog 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.
- *
*/
#include <linux/interrupt.h>
diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c
index ab137c1bbe7b..b99d73887c9f 100644
--- a/drivers/iio/imu/adis16480.c
+++ b/drivers/iio/imu/adis16480.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ADIS16480 and similar IMUs driver
*
* Copyright 2012 Analog 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.
- *
*/
#include <linux/clk.h>
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
index 72f72056b328..c14bf533b66b 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
@@ -197,7 +197,7 @@ struct st_lsm6dsx_ext_dev_settings {
* struct st_lsm6dsx_settings - ST IMU sensor settings
* @wai: Sensor WhoAmI default value.
* @max_fifo_size: Sensor max fifo length in FIFO words.
- * @id: List of hw id supported by the driver configuration.
+ * @id: List of hw id/device name supported by the driver configuration.
* @decimator: List of decimator register info (addr + mask).
* @batch: List of FIFO batching register info (addr + mask).
* @fifo_ops: Sensor hw FIFO parameters.
@@ -207,7 +207,10 @@ struct st_lsm6dsx_ext_dev_settings {
struct st_lsm6dsx_settings {
u8 wai;
u16 max_fifo_size;
- enum st_lsm6dsx_hw_id id[ST_LSM6DSX_MAX_ID];
+ struct {
+ enum st_lsm6dsx_hw_id hw_id;
+ const char *name;
+ } id[ST_LSM6DSX_MAX_ID];
struct st_lsm6dsx_reg decimator[ST_LSM6DSX_MAX_ID];
struct st_lsm6dsx_reg batch[ST_LSM6DSX_MAX_ID];
struct st_lsm6dsx_fifo_ops fifo_ops;
@@ -270,6 +273,7 @@ struct st_lsm6dsx_sensor {
* @conf_lock: Mutex to prevent concurrent FIFO configuration update.
* @page_lock: Mutex to prevent concurrent memory page configuration.
* @fifo_mode: FIFO operating mode supported by the device.
+ * @suspend_mask: Suspended sensor bitmask.
* @enable_mask: Enabled sensor bitmask.
* @ts_sip: Total number of timestamp samples in a given pattern.
* @sip: Total number of samples (acc/gyro/ts) in a given pattern.
@@ -287,6 +291,7 @@ struct st_lsm6dsx_hw {
struct mutex page_lock;
enum st_lsm6dsx_fifo_mode fifo_mode;
+ u8 suspend_mask;
u8 enable_mask;
u8 ts_sip;
u8 sip;
@@ -301,7 +306,7 @@ struct st_lsm6dsx_hw {
static const unsigned long st_lsm6dsx_available_scan_masks[] = {0x7, 0x0};
extern const struct dev_pm_ops st_lsm6dsx_pm_ops;
-int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name,
+int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
struct regmap *regmap);
int st_lsm6dsx_sensor_set_enable(struct st_lsm6dsx_sensor *sensor,
bool enable);
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
index b6edc9886d1e..a6702a74570e 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
@@ -124,7 +124,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.wai = 0x69,
.max_fifo_size = 1365,
.id = {
- [0] = ST_LSM6DS3_ID,
+ {
+ .hw_id = ST_LSM6DS3_ID,
+ .name = ST_LSM6DS3_DEV_NAME,
+ },
},
.decimator = {
[ST_LSM6DSX_ID_ACC] = {
@@ -171,7 +174,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.wai = 0x69,
.max_fifo_size = 682,
.id = {
- [0] = ST_LSM6DS3H_ID,
+ {
+ .hw_id = ST_LSM6DS3H_ID,
+ .name = ST_LSM6DS3H_DEV_NAME,
+ },
},
.decimator = {
[ST_LSM6DSX_ID_ACC] = {
@@ -218,9 +224,16 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.wai = 0x6a,
.max_fifo_size = 682,
.id = {
- [0] = ST_LSM6DSL_ID,
- [1] = ST_LSM6DSM_ID,
- [2] = ST_ISM330DLC_ID,
+ {
+ .hw_id = ST_LSM6DSL_ID,
+ .name = ST_LSM6DSL_DEV_NAME,
+ }, {
+ .hw_id = ST_LSM6DSM_ID,
+ .name = ST_LSM6DSM_DEV_NAME,
+ }, {
+ .hw_id = ST_ISM330DLC_ID,
+ .name = ST_ISM330DLC_DEV_NAME,
+ },
},
.decimator = {
[ST_LSM6DSX_ID_ACC] = {
@@ -267,8 +280,13 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.wai = 0x6c,
.max_fifo_size = 512,
.id = {
- [0] = ST_LSM6DSO_ID,
- [1] = ST_LSM6DSOX_ID,
+ {
+ .hw_id = ST_LSM6DSO_ID,
+ .name = ST_LSM6DSO_DEV_NAME,
+ }, {
+ .hw_id = ST_LSM6DSOX_ID,
+ .name = ST_LSM6DSOX_DEV_NAME,
+ },
},
.batch = {
[ST_LSM6DSX_ID_ACC] = {
@@ -333,7 +351,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.wai = 0x6b,
.max_fifo_size = 512,
.id = {
- [0] = ST_ASM330LHH_ID,
+ {
+ .hw_id = ST_ASM330LHH_ID,
+ .name = ST_ASM330LHH_DEV_NAME,
+ },
},
.batch = {
[ST_LSM6DSX_ID_ACC] = {
@@ -372,7 +393,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.wai = 0x6b,
.max_fifo_size = 512,
.id = {
- [0] = ST_LSM6DSR_ID,
+ {
+ .hw_id = ST_LSM6DSR_ID,
+ .name = ST_LSM6DSR_DEV_NAME,
+ },
},
.batch = {
[ST_LSM6DSX_ID_ACC] = {
@@ -470,13 +494,14 @@ int st_lsm6dsx_set_page(struct st_lsm6dsx_hw *hw, bool enable)
return err;
}
-static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id)
+static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id,
+ const char **name)
{
int err, i, j, data;
for (i = 0; i < ARRAY_SIZE(st_lsm6dsx_sensor_settings); i++) {
for (j = 0; j < ST_LSM6DSX_MAX_ID; j++) {
- if (id == st_lsm6dsx_sensor_settings[i].id[j])
+ if (id == st_lsm6dsx_sensor_settings[i].id[j].hw_id)
break;
}
if (j < ST_LSM6DSX_MAX_ID)
@@ -499,6 +524,7 @@ static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id)
return -ENODEV;
}
+ *name = st_lsm6dsx_sensor_settings[i].id[j].name;
hw->settings = &st_lsm6dsx_sensor_settings[i];
return 0;
@@ -1040,11 +1066,12 @@ static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw,
return iio_dev;
}
-int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name,
+int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
struct regmap *regmap)
{
const struct st_lsm6dsx_shub_settings *hub_settings;
struct st_lsm6dsx_hw *hw;
+ const char *name = NULL;
int i, err;
hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
@@ -1065,7 +1092,7 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name,
hw->irq = irq;
hw->regmap = regmap;
- err = st_lsm6dsx_check_whoami(hw, hw_id);
+ err = st_lsm6dsx_check_whoami(hw, hw_id, &name);
if (err < 0)
return err;
@@ -1109,8 +1136,6 @@ static int __maybe_unused st_lsm6dsx_suspend(struct device *dev)
{
struct st_lsm6dsx_hw *hw = dev_get_drvdata(dev);
struct st_lsm6dsx_sensor *sensor;
- const struct st_lsm6dsx_reg *reg;
- unsigned int data;
int i, err = 0;
for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
@@ -1121,12 +1146,16 @@ static int __maybe_unused st_lsm6dsx_suspend(struct device *dev)
if (!(hw->enable_mask & BIT(sensor->id)))
continue;
- reg = &st_lsm6dsx_odr_table[sensor->id].reg;
- data = ST_LSM6DSX_SHIFT_VAL(0, reg->mask);
- err = st_lsm6dsx_update_bits_locked(hw, reg->addr, reg->mask,
- data);
+ if (sensor->id == ST_LSM6DSX_ID_EXT0 ||
+ sensor->id == ST_LSM6DSX_ID_EXT1 ||
+ sensor->id == ST_LSM6DSX_ID_EXT2)
+ err = st_lsm6dsx_shub_set_enable(sensor, false);
+ else
+ err = st_lsm6dsx_sensor_set_enable(sensor, false);
if (err < 0)
return err;
+
+ hw->suspend_mask |= BIT(sensor->id);
}
if (hw->fifo_mode != ST_LSM6DSX_FIFO_BYPASS)
@@ -1146,12 +1175,19 @@ static int __maybe_unused st_lsm6dsx_resume(struct device *dev)
continue;
sensor = iio_priv(hw->iio_devs[i]);
- if (!(hw->enable_mask & BIT(sensor->id)))
+ if (!(hw->suspend_mask & BIT(sensor->id)))
continue;
- err = st_lsm6dsx_set_odr(sensor, sensor->odr);
+ if (sensor->id == ST_LSM6DSX_ID_EXT0 ||
+ sensor->id == ST_LSM6DSX_ID_EXT1 ||
+ sensor->id == ST_LSM6DSX_ID_EXT2)
+ err = st_lsm6dsx_shub_set_enable(sensor, true);
+ else
+ err = st_lsm6dsx_sensor_set_enable(sensor, true);
if (err < 0)
return err;
+
+ hw->suspend_mask &= ~BIT(sensor->id);
}
if (hw->enable_mask)
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
index 966d52a4bf1d..b3211e0ac07b 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
@@ -35,8 +35,7 @@ static int st_lsm6dsx_i2c_probe(struct i2c_client *client,
return PTR_ERR(regmap);
}
- return st_lsm6dsx_probe(&client->dev, client->irq,
- hw_id, id->name, regmap);
+ return st_lsm6dsx_probe(&client->dev, client->irq, hw_id, regmap);
}
static const struct of_device_id st_lsm6dsx_i2c_of_match[] = {
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
index 24e4e50414e6..c9d3c4711018 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
@@ -35,8 +35,7 @@ static int st_lsm6dsx_spi_probe(struct spi_device *spi)
return PTR_ERR(regmap);
}
- return st_lsm6dsx_probe(&spi->dev, spi->irq,
- hw_id, id->name, regmap);
+ return st_lsm6dsx_probe(&spi->dev, spi->irq, hw_id, regmap);
}
static const struct of_device_id st_lsm6dsx_spi_of_match[] = {
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index 4fa273002c03..c193d64e5217 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* The industrial I/O core
*
* Copyright (c) 2008 Jonathan Cameron
*
- * 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.
- *
* Handling of buffer allocation / resizing.
*
- *
* Things to look at here.
* - Better memory allocation techniques?
* - Alternative access techniques?
diff --git a/drivers/iio/industrialio-configfs.c b/drivers/iio/industrialio-configfs.c
index 5a0aae119369..47900de1f105 100644
--- a/drivers/iio/industrialio-configfs.c
+++ b/drivers/iio/industrialio-configfs.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Industrial I/O configfs bits
*
* Copyright (c) 2015 Intel Corporation
- *
- * 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.
*/
#include <linux/configfs.h>
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index f5a4581302f4..524a686077ca 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* The industrial I/O core
*
* Copyright (c) 2008 Jonathan Cameron
*
- * 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.
- *
* Based on elements of hwmon and input subsystems.
*/
@@ -231,9 +228,9 @@ s64 iio_get_time_ns(const struct iio_dev *indio_dev)
ktime_get_coarse_ts64(&tp);
return timespec64_to_ns(&tp);
case CLOCK_BOOTTIME:
- return ktime_get_boot_ns();
+ return ktime_get_boottime_ns();
case CLOCK_TAI:
- return ktime_get_tai_ns();
+ return ktime_get_clocktai_ns();
default:
BUG();
}
@@ -369,39 +366,25 @@ static void iio_device_unregister_debugfs(struct iio_dev *indio_dev)
debugfs_remove_recursive(indio_dev->debugfs_dentry);
}
-static int iio_device_register_debugfs(struct iio_dev *indio_dev)
+static void iio_device_register_debugfs(struct iio_dev *indio_dev)
{
- struct dentry *d;
-
if (indio_dev->info->debugfs_reg_access == NULL)
- return 0;
+ return;
if (!iio_debugfs_dentry)
- return 0;
+ return;
indio_dev->debugfs_dentry =
debugfs_create_dir(dev_name(&indio_dev->dev),
iio_debugfs_dentry);
- if (indio_dev->debugfs_dentry == NULL) {
- dev_warn(indio_dev->dev.parent,
- "Failed to create debugfs directory\n");
- return -EFAULT;
- }
-
- d = debugfs_create_file("direct_reg_access", 0644,
- indio_dev->debugfs_dentry,
- indio_dev, &iio_debugfs_reg_fops);
- if (!d) {
- iio_device_unregister_debugfs(indio_dev);
- return -ENOMEM;
- }
- return 0;
+ debugfs_create_file("direct_reg_access", 0644,
+ indio_dev->debugfs_dentry, indio_dev,
+ &iio_debugfs_reg_fops);
}
#else
-static int iio_device_register_debugfs(struct iio_dev *indio_dev)
+static void iio_device_register_debugfs(struct iio_dev *indio_dev)
{
- return 0;
}
static void iio_device_unregister_debugfs(struct iio_dev *indio_dev)
@@ -1107,6 +1090,8 @@ static int iio_device_add_info_mask_type_avail(struct iio_dev *indio_dev,
char *avail_postfix;
for_each_set_bit(i, infomask, sizeof(*infomask) * 8) {
+ if (i >= ARRAY_SIZE(iio_chan_info_postfix))
+ return -EINVAL;
avail_postfix = kasprintf(GFP_KERNEL,
"%s_available",
iio_chan_info_postfix[i]);
@@ -1672,12 +1657,7 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod)
/* configure elements for the chrdev */
indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id);
- ret = iio_device_register_debugfs(indio_dev);
- if (ret) {
- dev_err(indio_dev->dev.parent,
- "Failed to register debugfs interfaces\n");
- return ret;
- }
+ iio_device_register_debugfs(indio_dev);
ret = iio_buffer_alloc_sysfs_and_mask(indio_dev);
if (ret) {
diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c
index c6dfdf0aaac5..5b17c92d3b50 100644
--- a/drivers/iio/industrialio-event.c
+++ b/drivers/iio/industrialio-event.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* Industrial I/O event handling
*
* Copyright (c) 2008 Jonathan Cameron
*
- * 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.
- *
* Based on elements of hwmon and input subsystems.
*/
diff --git a/drivers/iio/industrialio-sw-device.c b/drivers/iio/industrialio-sw-device.c
index 90df97c542f6..49f775f16ad5 100644
--- a/drivers/iio/industrialio-sw-device.c
+++ b/drivers/iio/industrialio-sw-device.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* The Industrial I/O core, software IIO devices functions
*
* Copyright (c) 2016 Intel Corporation
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/iio/industrialio-sw-trigger.c b/drivers/iio/industrialio-sw-trigger.c
index bc6b7fb43e3a..9ae793a70b8b 100644
--- a/drivers/iio/industrialio-sw-trigger.c
+++ b/drivers/iio/industrialio-sw-trigger.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* The Industrial I/O core, software trigger functions
*
* Copyright (c) 2015 Intel Corporation
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c
index e5b538379ed1..3908a9a90035 100644
--- a/drivers/iio/industrialio-trigger.c
+++ b/drivers/iio/industrialio-trigger.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* The industrial I/O core, trigger handling functions
*
* Copyright (c) 2008 Jonathan Cameron
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index 4a5eff3f18bc..5a8351c9a426 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* The industrial I/O core in kernel channel mapping
*
* Copyright (c) 2011 Jonathan Cameron
- *
- * 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.
*/
#include <linux/err.h>
#include <linux/export.h>
@@ -93,7 +90,7 @@ static const struct iio_chan_spec
#ifdef CONFIG_OF
-static int iio_dev_node_match(struct device *dev, void *data)
+static int iio_dev_node_match(struct device *dev, const void *data)
{
return dev->of_node == data && dev->type == &iio_device_type;
}
diff --git a/drivers/iio/light/bh1780.c b/drivers/iio/light/bh1780.c
index 340d64d0ac59..a8361006dcd9 100644
--- a/drivers/iio/light/bh1780.c
+++ b/drivers/iio/light/bh1780.c
@@ -146,7 +146,7 @@ static int bh1780_probe(struct i2c_client *client,
{
int ret;
struct bh1780_data *bh1780;
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adapter = client->adapter;
struct iio_dev *indio_dev;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
index aebf7dd071af..5f4fb5674fa0 100644
--- a/drivers/iio/light/cm32181.c
+++ b/drivers/iio/light/cm32181.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Capella Microsystems Inc.
* Author: Kevin Tsai <ktsai@capellamicro.com>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/iio/light/cm3232.c b/drivers/iio/light/cm3232.c
index c639cf276ee6..cd3cfb7d02bd 100644
--- a/drivers/iio/light/cm3232.c
+++ b/drivers/iio/light/cm3232.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* CM3232 Ambient Light Sensor
*
* Copyright (C) 2014-2015 Capella Microsystems Inc.
* Author: Kevin Tsai <ktsai@capellamicro.com>
*
- * 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.
- *
* IIO driver for CM3232 (7-bit I2C slave address 0x10).
*/
diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c
index 1dd8ed0121b3..7702c2bcbcfa 100644
--- a/drivers/iio/light/cm36651.c
+++ b/drivers/iio/light/cm36651.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* Author: Beomho Seo <beomho.seo@samsung.com>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c
index 44b13fbcd093..4d70c5bf35da 100644
--- a/drivers/iio/light/gp2ap020a00f.c
+++ b/drivers/iio/light/gp2ap020a00f.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* Author: Jacek Anaszewski <j.anaszewski@samsung.com>
@@ -28,10 +29,6 @@
* with any triggers or illuminance events. Enabling/disabling
* one of the proximity events automatically enables/disables
* the other one.
- *
- * 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.
*/
#include <linux/debugfs.h>
diff --git a/drivers/iio/light/pa12203001.c b/drivers/iio/light/pa12203001.c
index 30ea1a088dd9..0295783f036a 100644
--- a/drivers/iio/light/pa12203001.c
+++ b/drivers/iio/light/pa12203001.c
@@ -1,11 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2015 Intel Corporation
*
* Driver for TXC PA12203001 Proximity and Ambient Light Sensor.
*
- * 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.
* To do: Interrupt support.
*/
diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c
index eff7ac9ae669..b955183edfe8 100644
--- a/drivers/iio/light/stk3310.c
+++ b/drivers/iio/light/stk3310.c
@@ -37,6 +37,7 @@
#define STK3310_CHIP_ID_VAL 0x13
#define STK3311_CHIP_ID_VAL 0x1D
+#define STK3335_CHIP_ID_VAL 0x51
#define STK3310_PSINT_EN 0x01
#define STK3310_PS_MAX_VAL 0xFFFF
@@ -451,7 +452,8 @@ static int stk3310_init(struct iio_dev *indio_dev)
return ret;
if (chipid != STK3310_CHIP_ID_VAL &&
- chipid != STK3311_CHIP_ID_VAL) {
+ chipid != STK3311_CHIP_ID_VAL &&
+ chipid != STK3335_CHIP_ID_VAL) {
dev_err(&client->dev, "invalid chip id: 0x%x\n", chipid);
return -ENODEV;
}
@@ -663,6 +665,7 @@ static SIMPLE_DEV_PM_OPS(stk3310_pm_ops, stk3310_suspend, stk3310_resume);
static const struct i2c_device_id stk3310_i2c_id[] = {
{"STK3310", 0},
{"STK3311", 0},
+ {"STK3335", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, stk3310_i2c_id);
@@ -670,6 +673,7 @@ MODULE_DEVICE_TABLE(i2c, stk3310_i2c_id);
static const struct acpi_device_id stk3310_acpi_id[] = {
{"STK3310", 0},
{"STK3311", 0},
+ {"STK3335", 0},
{}
};
diff --git a/drivers/iio/light/us5182d.c b/drivers/iio/light/us5182d.c
index 68e52943879a..b995f21a3347 100644
--- a/drivers/iio/light/us5182d.c
+++ b/drivers/iio/light/us5182d.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2015 Intel Corporation
*
* Driver for UPISEMI us5182d Proximity and Ambient Light Sensor.
*
- * 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.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
* To do: Interrupt support.
*/
diff --git a/drivers/iio/magnetometer/hmc5843.h b/drivers/iio/magnetometer/hmc5843.h
index e3e22d2508d3..b0dee87a8b20 100644
--- a/drivers/iio/magnetometer/hmc5843.h
+++ b/drivers/iio/magnetometer/hmc5843.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Header file for hmc5843 driver
*
* Split from hmc5843.c
* Copyright (C) Josef Gajdusek <atx@atx.name>
- *
- * 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.
*/
#ifndef HMC5843_CORE_H
diff --git a/drivers/iio/magnetometer/hmc5843_i2c.c b/drivers/iio/magnetometer/hmc5843_i2c.c
index 86abba5827a2..67fe657fdb3e 100644
--- a/drivers/iio/magnetometer/hmc5843_i2c.c
+++ b/drivers/iio/magnetometer/hmc5843_i2c.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* i2c driver for hmc5843/5843/5883/5883l/5983
*
* Split from hmc5843.c
* Copyright (C) Josef Gajdusek <atx@atx.name>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/iio/magnetometer/hmc5843_spi.c b/drivers/iio/magnetometer/hmc5843_spi.c
index 79b2b707f90e..d827554c346e 100644
--- a/drivers/iio/magnetometer/hmc5843_spi.c
+++ b/drivers/iio/magnetometer/hmc5843_spi.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* SPI driver for hmc5983
*
* Copyright (C) Josef Gajdusek <atx@atx.name>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/iio/potentiometer/ds1803.c b/drivers/iio/potentiometer/ds1803.c
index 6bf12c9eccbd..d0de78232a93 100644
--- a/drivers/iio/potentiometer/ds1803.c
+++ b/drivers/iio/potentiometer/ds1803.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Maxim Integrated DS1803 digital potentiometer driver
* Copyright (c) 2016 Slawomir Stepien
@@ -6,10 +7,6 @@
*
* DEVID #Wipers #Positions Resistor Opts (kOhm) i2c address
* ds1803 2 256 10, 50, 100 0101xxx
- *
- * 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.
*/
#include <linux/err.h>
diff --git a/drivers/iio/potentiometer/max5481.c b/drivers/iio/potentiometer/max5481.c
index 6d2f13fa5662..732375b6d131 100644
--- a/drivers/iio/potentiometer/max5481.c
+++ b/drivers/iio/potentiometer/max5481.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Maxim Integrated MAX5481-MAX5484 digital potentiometer driver
* Copyright 2016 Rockwell Collins
*
* Datasheet:
* http://datasheets.maximintegrated.com/en/ds/MAX5481-MAX5484.pdf
- *
- * 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.
- *
*/
#include <linux/acpi.h>
diff --git a/drivers/iio/potentiometer/max5487.c b/drivers/iio/potentiometer/max5487.c
index 5042d3e09b12..68ff806d4668 100644
--- a/drivers/iio/potentiometer/max5487.c
+++ b/drivers/iio/potentiometer/max5487.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* max5487.c - Support for MAX5487, MAX5488, MAX5489 digital potentiometers
*
* Copyright (C) 2016 Cristina-Gabriela Moraru <cristina.moraru09@gmail.com>
- *
- * 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.
- *
*/
#include <linux/module.h>
#include <linux/spi/spi.h>
diff --git a/drivers/iio/potentiometer/mcp4131.c b/drivers/iio/potentiometer/mcp4131.c
index efe035ce010d..98df91e97f2f 100644
--- a/drivers/iio/potentiometer/mcp4131.c
+++ b/drivers/iio/potentiometer/mcp4131.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Industrial I/O driver for Microchip digital potentiometers
*
@@ -23,10 +24,6 @@
* mcp4252 2 257 5, 10, 50, 100
* mcp4261 2 257 5, 10, 50, 100
* mcp4262 2 257 5, 10, 50, 100
- *
- * 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.
*/
/*
diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig
index b191811fd749..ba420e484787 100644
--- a/drivers/iio/pressure/Kconfig
+++ b/drivers/iio/pressure/Kconfig
@@ -53,6 +53,17 @@ config IIO_CROS_EC_BARO
To compile this driver as a module, choose M here: the module
will be called cros_ec_baro.
+config DPS310
+ tristate "Infineon DPS310 pressure and temperature sensor"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Support for the Infineon DPS310 digital barometric pressure sensor.
+ It can be accessed over I2C bus.
+
+ This driver can also be built as a module. If so, the module will be
+ called dps310.
+
config HID_SENSOR_PRESS
depends on HID_SENSOR_HUB
select IIO_BUFFER
diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile
index c2058d7b2f93..d8f5ace1f25d 100644
--- a/drivers/iio/pressure/Makefile
+++ b/drivers/iio/pressure/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_BMP280) += bmp280.o
bmp280-objs := bmp280-core.o bmp280-regmap.o
obj-$(CONFIG_BMP280_I2C) += bmp280-i2c.o
obj-$(CONFIG_BMP280_SPI) += bmp280-spi.o
+obj-$(CONFIG_DPS310) += dps310.o
obj-$(CONFIG_IIO_CROS_EC_BARO) += cros_ec_baro.o
obj-$(CONFIG_HID_SENSOR_PRESS) += hid-sensor-press.o
obj-$(CONFIG_HP03) += hp03.o
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index 3329d740c86c..8d0f15f27dc5 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2010 Christoph Mair <christoph.mair@gmail.com>
* Copyright (c) 2012 Bosch Sensortec GmbH
@@ -7,10 +8,6 @@
*
* Driver for Bosch Sensortec BMP180 and BMP280 digital pressure sensor.
*
- * 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.
- *
* Datasheet:
* https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BMP180-DS000-121.pdf
* https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BMP280-DS001-12.pdf
diff --git a/drivers/iio/pressure/dps310.c b/drivers/iio/pressure/dps310.c
new file mode 100644
index 000000000000..2c1943bbc433
--- /dev/null
+++ b/drivers/iio/pressure/dps310.c
@@ -0,0 +1,827 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright IBM Corp 2019
+/*
+ * The DPS310 is a barometric pressure and temperature sensor.
+ * Currently only reading a single temperature is supported by
+ * this driver.
+ *
+ * https://www.infineon.com/dgdl/?fileId=5546d462576f34750157750826c42242
+ *
+ * Temperature calculation:
+ * c0 * 0.5 + c1 * T_raw / kT °C
+ *
+ * TODO:
+ * - Optionally support the FIFO
+ */
+
+#include <linux/i2c.h>
+#include <linux/limits.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define DPS310_DEV_NAME "dps310"
+
+#define DPS310_PRS_B0 0x00
+#define DPS310_PRS_B1 0x01
+#define DPS310_PRS_B2 0x02
+#define DPS310_TMP_B0 0x03
+#define DPS310_TMP_B1 0x04
+#define DPS310_TMP_B2 0x05
+#define DPS310_PRS_CFG 0x06
+#define DPS310_PRS_RATE_BITS GENMASK(6, 4)
+#define DPS310_PRS_PRC_BITS GENMASK(3, 0)
+#define DPS310_TMP_CFG 0x07
+#define DPS310_TMP_RATE_BITS GENMASK(6, 4)
+#define DPS310_TMP_PRC_BITS GENMASK(3, 0)
+#define DPS310_TMP_EXT BIT(7)
+#define DPS310_MEAS_CFG 0x08
+#define DPS310_MEAS_CTRL_BITS GENMASK(2, 0)
+#define DPS310_PRS_EN BIT(0)
+#define DPS310_TEMP_EN BIT(1)
+#define DPS310_BACKGROUND BIT(2)
+#define DPS310_PRS_RDY BIT(4)
+#define DPS310_TMP_RDY BIT(5)
+#define DPS310_SENSOR_RDY BIT(6)
+#define DPS310_COEF_RDY BIT(7)
+#define DPS310_CFG_REG 0x09
+#define DPS310_INT_HL BIT(7)
+#define DPS310_TMP_SHIFT_EN BIT(3)
+#define DPS310_PRS_SHIFT_EN BIT(4)
+#define DPS310_FIFO_EN BIT(5)
+#define DPS310_SPI_EN BIT(6)
+#define DPS310_RESET 0x0c
+#define DPS310_RESET_MAGIC 0x09
+#define DPS310_COEF_BASE 0x10
+
+/* Make sure sleep time is <= 20ms for usleep_range */
+#define DPS310_POLL_SLEEP_US(t) min(20000, (t) / 8)
+/* Silently handle error in rate value here */
+#define DPS310_POLL_TIMEOUT_US(rc) ((rc) <= 0 ? 1000000 : 1000000 / (rc))
+
+#define DPS310_PRS_BASE DPS310_PRS_B0
+#define DPS310_TMP_BASE DPS310_TMP_B0
+
+/*
+ * These values (defined in the spec) indicate how to scale the raw register
+ * values for each level of precision available.
+ */
+static const int scale_factors[] = {
+ 524288,
+ 1572864,
+ 3670016,
+ 7864320,
+ 253952,
+ 516096,
+ 1040384,
+ 2088960,
+};
+
+struct dps310_data {
+ struct i2c_client *client;
+ struct regmap *regmap;
+ struct mutex lock; /* Lock for sequential HW access functions */
+
+ s32 c0, c1;
+ s32 c00, c10, c20, c30, c01, c11, c21;
+ s32 pressure_raw;
+ s32 temp_raw;
+};
+
+static const struct iio_chan_spec dps310_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_PROCESSED),
+ },
+ {
+ .type = IIO_PRESSURE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_PROCESSED),
+ },
+};
+
+/* To be called after checking the COEF_RDY bit in MEAS_CFG */
+static int dps310_get_coefs(struct dps310_data *data)
+{
+ int rc;
+ u8 coef[18];
+ u32 c0, c1;
+ u32 c00, c10, c20, c30, c01, c11, c21;
+
+ /* Read all sensor calibration coefficients from the COEF registers. */
+ rc = regmap_bulk_read(data->regmap, DPS310_COEF_BASE, coef,
+ sizeof(coef));
+ if (rc < 0)
+ return rc;
+
+ /*
+ * Calculate temperature calibration coefficients c0 and c1. The
+ * numbers are 12-bit 2's complement numbers.
+ */
+ c0 = (coef[0] << 4) | (coef[1] >> 4);
+ data->c0 = sign_extend32(c0, 11);
+
+ c1 = ((coef[1] & GENMASK(3, 0)) << 8) | coef[2];
+ data->c1 = sign_extend32(c1, 11);
+
+ /*
+ * Calculate pressure calibration coefficients. c00 and c10 are 20 bit
+ * 2's complement numbers, while the rest are 16 bit 2's complement
+ * numbers.
+ */
+ c00 = (coef[3] << 12) | (coef[4] << 4) | (coef[5] >> 4);
+ data->c00 = sign_extend32(c00, 19);
+
+ c10 = ((coef[5] & GENMASK(3, 0)) << 16) | (coef[6] << 8) | coef[7];
+ data->c10 = sign_extend32(c10, 19);
+
+ c01 = (coef[8] << 8) | coef[9];
+ data->c01 = sign_extend32(c01, 15);
+
+ c11 = (coef[10] << 8) | coef[11];
+ data->c11 = sign_extend32(c11, 15);
+
+ c20 = (coef[12] << 8) | coef[13];
+ data->c20 = sign_extend32(c20, 15);
+
+ c21 = (coef[14] << 8) | coef[15];
+ data->c21 = sign_extend32(c21, 15);
+
+ c30 = (coef[16] << 8) | coef[17];
+ data->c30 = sign_extend32(c30, 15);
+
+ return 0;
+}
+
+static int dps310_get_pres_precision(struct dps310_data *data)
+{
+ int rc;
+ int val;
+
+ rc = regmap_read(data->regmap, DPS310_PRS_CFG, &val);
+ if (rc < 0)
+ return rc;
+
+ return BIT(val & GENMASK(2, 0));
+}
+
+static int dps310_get_temp_precision(struct dps310_data *data)
+{
+ int rc;
+ int val;
+
+ rc = regmap_read(data->regmap, DPS310_TMP_CFG, &val);
+ if (rc < 0)
+ return rc;
+
+ /*
+ * Scale factor is bottom 4 bits of the register, but 1111 is
+ * reserved so just grab bottom three
+ */
+ return BIT(val & GENMASK(2, 0));
+}
+
+/* Called with lock held */
+static int dps310_set_pres_precision(struct dps310_data *data, int val)
+{
+ int rc;
+ u8 shift_en;
+
+ if (val < 0 || val > 128)
+ return -EINVAL;
+
+ shift_en = val >= 16 ? DPS310_PRS_SHIFT_EN : 0;
+ rc = regmap_write_bits(data->regmap, DPS310_CFG_REG,
+ DPS310_PRS_SHIFT_EN, shift_en);
+ if (rc)
+ return rc;
+
+ return regmap_update_bits(data->regmap, DPS310_PRS_CFG,
+ DPS310_PRS_PRC_BITS, ilog2(val));
+}
+
+/* Called with lock held */
+static int dps310_set_temp_precision(struct dps310_data *data, int val)
+{
+ int rc;
+ u8 shift_en;
+
+ if (val < 0 || val > 128)
+ return -EINVAL;
+
+ shift_en = val >= 16 ? DPS310_TMP_SHIFT_EN : 0;
+ rc = regmap_write_bits(data->regmap, DPS310_CFG_REG,
+ DPS310_TMP_SHIFT_EN, shift_en);
+ if (rc)
+ return rc;
+
+ return regmap_update_bits(data->regmap, DPS310_TMP_CFG,
+ DPS310_TMP_PRC_BITS, ilog2(val));
+}
+
+/* Called with lock held */
+static int dps310_set_pres_samp_freq(struct dps310_data *data, int freq)
+{
+ u8 val;
+
+ if (freq < 0 || freq > 128)
+ return -EINVAL;
+
+ val = ilog2(freq) << 4;
+
+ return regmap_update_bits(data->regmap, DPS310_PRS_CFG,
+ DPS310_PRS_RATE_BITS, val);
+}
+
+/* Called with lock held */
+static int dps310_set_temp_samp_freq(struct dps310_data *data, int freq)
+{
+ u8 val;
+
+ if (freq < 0 || freq > 128)
+ return -EINVAL;
+
+ val = ilog2(freq) << 4;
+
+ return regmap_update_bits(data->regmap, DPS310_TMP_CFG,
+ DPS310_TMP_RATE_BITS, val);
+}
+
+static int dps310_get_pres_samp_freq(struct dps310_data *data)
+{
+ int rc;
+ int val;
+
+ rc = regmap_read(data->regmap, DPS310_PRS_CFG, &val);
+ if (rc < 0)
+ return rc;
+
+ return BIT((val & DPS310_PRS_RATE_BITS) >> 4);
+}
+
+static int dps310_get_temp_samp_freq(struct dps310_data *data)
+{
+ int rc;
+ int val;
+
+ rc = regmap_read(data->regmap, DPS310_TMP_CFG, &val);
+ if (rc < 0)
+ return rc;
+
+ return BIT((val & DPS310_TMP_RATE_BITS) >> 4);
+}
+
+static int dps310_get_pres_k(struct dps310_data *data)
+{
+ int rc = dps310_get_pres_precision(data);
+
+ if (rc < 0)
+ return rc;
+
+ return scale_factors[ilog2(rc)];
+}
+
+static int dps310_get_temp_k(struct dps310_data *data)
+{
+ int rc = dps310_get_temp_precision(data);
+
+ if (rc < 0)
+ return rc;
+
+ return scale_factors[ilog2(rc)];
+}
+
+static int dps310_read_pres_raw(struct dps310_data *data)
+{
+ int rc;
+ int rate;
+ int ready;
+ int timeout;
+ s32 raw;
+ u8 val[3];
+
+ if (mutex_lock_interruptible(&data->lock))
+ return -EINTR;
+
+ rate = dps310_get_pres_samp_freq(data);
+ timeout = DPS310_POLL_TIMEOUT_US(rate);
+
+ /* Poll for sensor readiness; base the timeout upon the sample rate. */
+ rc = regmap_read_poll_timeout(data->regmap, DPS310_MEAS_CFG, ready,
+ ready & DPS310_PRS_RDY,
+ DPS310_POLL_SLEEP_US(timeout), timeout);
+ if (rc)
+ goto done;
+
+ rc = regmap_bulk_read(data->regmap, DPS310_PRS_BASE, val, sizeof(val));
+ if (rc < 0)
+ goto done;
+
+ raw = (val[0] << 16) | (val[1] << 8) | val[2];
+ data->pressure_raw = sign_extend32(raw, 23);
+
+done:
+ mutex_unlock(&data->lock);
+ return rc;
+}
+
+/* Called with lock held */
+static int dps310_read_temp_ready(struct dps310_data *data)
+{
+ int rc;
+ u8 val[3];
+ s32 raw;
+
+ rc = regmap_bulk_read(data->regmap, DPS310_TMP_BASE, val, sizeof(val));
+ if (rc < 0)
+ return rc;
+
+ raw = (val[0] << 16) | (val[1] << 8) | val[2];
+ data->temp_raw = sign_extend32(raw, 23);
+
+ return 0;
+}
+
+static int dps310_read_temp_raw(struct dps310_data *data)
+{
+ int rc;
+ int rate;
+ int ready;
+ int timeout;
+
+ if (mutex_lock_interruptible(&data->lock))
+ return -EINTR;
+
+ rate = dps310_get_temp_samp_freq(data);
+ timeout = DPS310_POLL_TIMEOUT_US(rate);
+
+ /* Poll for sensor readiness; base the timeout upon the sample rate. */
+ rc = regmap_read_poll_timeout(data->regmap, DPS310_MEAS_CFG, ready,
+ ready & DPS310_TMP_RDY,
+ DPS310_POLL_SLEEP_US(timeout), timeout);
+ if (rc < 0)
+ goto done;
+
+ rc = dps310_read_temp_ready(data);
+
+done:
+ mutex_unlock(&data->lock);
+ return rc;
+}
+
+static bool dps310_is_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case DPS310_PRS_CFG:
+ case DPS310_TMP_CFG:
+ case DPS310_MEAS_CFG:
+ case DPS310_CFG_REG:
+ case DPS310_RESET:
+ /* No documentation available on the registers below */
+ case 0x0e:
+ case 0x0f:
+ case 0x62:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool dps310_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case DPS310_PRS_B0:
+ case DPS310_PRS_B1:
+ case DPS310_PRS_B2:
+ case DPS310_TMP_B0:
+ case DPS310_TMP_B1:
+ case DPS310_TMP_B2:
+ case DPS310_MEAS_CFG:
+ case 0x32: /* No documentation available on this register */
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int dps310_write_raw(struct iio_dev *iio,
+ struct iio_chan_spec const *chan, int val,
+ int val2, long mask)
+{
+ int rc;
+ struct dps310_data *data = iio_priv(iio);
+
+ if (mutex_lock_interruptible(&data->lock))
+ return -EINTR;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ switch (chan->type) {
+ case IIO_PRESSURE:
+ rc = dps310_set_pres_samp_freq(data, val);
+ break;
+
+ case IIO_TEMP:
+ rc = dps310_set_temp_samp_freq(data, val);
+ break;
+
+ default:
+ rc = -EINVAL;
+ break;
+ }
+ break;
+
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ switch (chan->type) {
+ case IIO_PRESSURE:
+ rc = dps310_set_pres_precision(data, val);
+ break;
+
+ case IIO_TEMP:
+ rc = dps310_set_temp_precision(data, val);
+ break;
+
+ default:
+ rc = -EINVAL;
+ break;
+ }
+ break;
+
+ default:
+ rc = -EINVAL;
+ break;
+ }
+
+ mutex_unlock(&data->lock);
+ return rc;
+}
+
+static int dps310_calculate_pressure(struct dps310_data *data)
+{
+ int i;
+ int rc;
+ int t_ready;
+ int kpi = dps310_get_pres_k(data);
+ int kti = dps310_get_temp_k(data);
+ s64 rem = 0ULL;
+ s64 pressure = 0ULL;
+ s64 p;
+ s64 t;
+ s64 denoms[7];
+ s64 nums[7];
+ s64 rems[7];
+ s64 kp;
+ s64 kt;
+
+ if (kpi < 0)
+ return kpi;
+
+ if (kti < 0)
+ return kti;
+
+ kp = (s64)kpi;
+ kt = (s64)kti;
+
+ /* Refresh temp if it's ready, otherwise just use the latest value */
+ if (mutex_trylock(&data->lock)) {
+ rc = regmap_read(data->regmap, DPS310_MEAS_CFG, &t_ready);
+ if (rc >= 0 && t_ready & DPS310_TMP_RDY)
+ dps310_read_temp_ready(data);
+
+ mutex_unlock(&data->lock);
+ }
+
+ p = (s64)data->pressure_raw;
+ t = (s64)data->temp_raw;
+
+ /* Section 4.9.1 of the DPS310 spec; algebra'd to avoid underflow */
+ nums[0] = (s64)data->c00;
+ denoms[0] = 1LL;
+ nums[1] = p * (s64)data->c10;
+ denoms[1] = kp;
+ nums[2] = p * p * (s64)data->c20;
+ denoms[2] = kp * kp;
+ nums[3] = p * p * p * (s64)data->c30;
+ denoms[3] = kp * kp * kp;
+ nums[4] = t * (s64)data->c01;
+ denoms[4] = kt;
+ nums[5] = t * p * (s64)data->c11;
+ denoms[5] = kp * kt;
+ nums[6] = t * p * p * (s64)data->c21;
+ denoms[6] = kp * kp * kt;
+
+ /* Kernel lacks a div64_s64_rem function; denoms are all positive */
+ for (i = 0; i < 7; ++i) {
+ u64 irem;
+
+ if (nums[i] < 0LL) {
+ pressure -= div64_u64_rem(-nums[i], denoms[i], &irem);
+ rems[i] = -irem;
+ } else {
+ pressure += div64_u64_rem(nums[i], denoms[i], &irem);
+ rems[i] = (s64)irem;
+ }
+ }
+
+ /* Increase precision and calculate the remainder sum */
+ for (i = 0; i < 7; ++i)
+ rem += div64_s64((s64)rems[i] * 1000000000LL, denoms[i]);
+
+ pressure += div_s64(rem, 1000000000LL);
+ if (pressure < 0LL)
+ return -ERANGE;
+
+ return (int)min_t(s64, pressure, INT_MAX);
+}
+
+static int dps310_read_pressure(struct dps310_data *data, int *val, int *val2,
+ long mask)
+{
+ int rc;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ rc = dps310_get_pres_samp_freq(data);
+ if (rc < 0)
+ return rc;
+
+ *val = rc;
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_PROCESSED:
+ rc = dps310_read_pres_raw(data);
+ if (rc)
+ return rc;
+
+ rc = dps310_calculate_pressure(data);
+ if (rc < 0)
+ return rc;
+
+ *val = rc;
+ *val2 = 1000; /* Convert Pa to KPa per IIO ABI */
+ return IIO_VAL_FRACTIONAL;
+
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ rc = dps310_get_pres_precision(data);
+ if (rc < 0)
+ return rc;
+
+ *val = rc;
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int dps310_calculate_temp(struct dps310_data *data)
+{
+ s64 c0;
+ s64 t;
+ int kt = dps310_get_temp_k(data);
+
+ if (kt < 0)
+ return kt;
+
+ /* Obtain inverse-scaled offset */
+ c0 = div_s64((s64)kt * (s64)data->c0, 2);
+
+ /* Add the offset to the unscaled temperature */
+ t = c0 + ((s64)data->temp_raw * (s64)data->c1);
+
+ /* Convert to milliCelsius and scale the temperature */
+ return (int)div_s64(t * 1000LL, kt);
+}
+
+static int dps310_read_temp(struct dps310_data *data, int *val, int *val2,
+ long mask)
+{
+ int rc;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ rc = dps310_get_temp_samp_freq(data);
+ if (rc < 0)
+ return rc;
+
+ *val = rc;
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_PROCESSED:
+ rc = dps310_read_temp_raw(data);
+ if (rc)
+ return rc;
+
+ rc = dps310_calculate_temp(data);
+ if (rc < 0)
+ return rc;
+
+ *val = rc;
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ rc = dps310_get_temp_precision(data);
+ if (rc < 0)
+ return rc;
+
+ *val = rc;
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int dps310_read_raw(struct iio_dev *iio,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct dps310_data *data = iio_priv(iio);
+
+ switch (chan->type) {
+ case IIO_PRESSURE:
+ return dps310_read_pressure(data, val, val2, mask);
+
+ case IIO_TEMP:
+ return dps310_read_temp(data, val, val2, mask);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static void dps310_reset(void *action_data)
+{
+ struct dps310_data *data = action_data;
+
+ regmap_write(data->regmap, DPS310_RESET, DPS310_RESET_MAGIC);
+}
+
+static const struct regmap_config dps310_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .writeable_reg = dps310_is_writeable_reg,
+ .volatile_reg = dps310_is_volatile_reg,
+ .cache_type = REGCACHE_RBTREE,
+ .max_register = 0x62, /* No documentation available on this register */
+};
+
+static const struct iio_info dps310_info = {
+ .read_raw = dps310_read_raw,
+ .write_raw = dps310_write_raw,
+};
+
+/*
+ * Some verions of chip will read temperatures in the ~60C range when
+ * its actually ~20C. This is the manufacturer recommended workaround
+ * to correct the issue. The registers used below are undocumented.
+ */
+static int dps310_temp_workaround(struct dps310_data *data)
+{
+ int rc;
+ int reg;
+
+ rc = regmap_read(data->regmap, 0x32, &reg);
+ if (rc < 0)
+ return rc;
+
+ /*
+ * If bit 1 is set then the device is okay, and the workaround does not
+ * need to be applied
+ */
+ if (reg & BIT(1))
+ return 0;
+
+ rc = regmap_write(data->regmap, 0x0e, 0xA5);
+ if (rc < 0)
+ return rc;
+
+ rc = regmap_write(data->regmap, 0x0f, 0x96);
+ if (rc < 0)
+ return rc;
+
+ rc = regmap_write(data->regmap, 0x62, 0x02);
+ if (rc < 0)
+ return rc;
+
+ rc = regmap_write(data->regmap, 0x0e, 0x00);
+ if (rc < 0)
+ return rc;
+
+ return regmap_write(data->regmap, 0x0f, 0x00);
+}
+
+static int dps310_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct dps310_data *data;
+ struct iio_dev *iio;
+ int rc, ready;
+
+ iio = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!iio)
+ return -ENOMEM;
+
+ data = iio_priv(iio);
+ data->client = client;
+ mutex_init(&data->lock);
+
+ iio->dev.parent = &client->dev;
+ iio->name = id->name;
+ iio->channels = dps310_channels;
+ iio->num_channels = ARRAY_SIZE(dps310_channels);
+ iio->info = &dps310_info;
+ iio->modes = INDIO_DIRECT_MODE;
+
+ data->regmap = devm_regmap_init_i2c(client, &dps310_regmap_config);
+ if (IS_ERR(data->regmap))
+ return PTR_ERR(data->regmap);
+
+ /* Register to run the device reset when the device is removed */
+ rc = devm_add_action_or_reset(&client->dev, dps310_reset, data);
+ if (rc)
+ return rc;
+
+ /*
+ * Set up pressure sensor in single sample, one measurement per second
+ * mode
+ */
+ rc = regmap_write(data->regmap, DPS310_PRS_CFG, 0);
+
+ /*
+ * Set up external (MEMS) temperature sensor in single sample, one
+ * measurement per second mode
+ */
+ rc = regmap_write(data->regmap, DPS310_TMP_CFG, DPS310_TMP_EXT);
+ if (rc < 0)
+ return rc;
+
+ /* Temp and pressure shifts are disabled when PRC <= 8 */
+ rc = regmap_write_bits(data->regmap, DPS310_CFG_REG,
+ DPS310_PRS_SHIFT_EN | DPS310_TMP_SHIFT_EN, 0);
+ if (rc < 0)
+ return rc;
+
+ /* MEAS_CFG doesn't update correctly unless first written with 0 */
+ rc = regmap_write_bits(data->regmap, DPS310_MEAS_CFG,
+ DPS310_MEAS_CTRL_BITS, 0);
+ if (rc < 0)
+ return rc;
+
+ /* Turn on temperature and pressure measurement in the background */
+ rc = regmap_write_bits(data->regmap, DPS310_MEAS_CFG,
+ DPS310_MEAS_CTRL_BITS, DPS310_PRS_EN |
+ DPS310_TEMP_EN | DPS310_BACKGROUND);
+ if (rc < 0)
+ return rc;
+
+ /*
+ * Calibration coefficients required for reporting temperature.
+ * They are available 40ms after the device has started
+ */
+ rc = regmap_read_poll_timeout(data->regmap, DPS310_MEAS_CFG, ready,
+ ready & DPS310_COEF_RDY, 10000, 40000);
+ if (rc < 0)
+ return rc;
+
+ rc = dps310_get_coefs(data);
+ if (rc < 0)
+ return rc;
+
+ rc = dps310_temp_workaround(data);
+ if (rc < 0)
+ return rc;
+
+ rc = devm_iio_device_register(&client->dev, iio);
+ if (rc)
+ return rc;
+
+ i2c_set_clientdata(client, iio);
+
+ return 0;
+}
+
+static const struct i2c_device_id dps310_id[] = {
+ { DPS310_DEV_NAME, 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, dps310_id);
+
+static struct i2c_driver dps310_driver = {
+ .driver = {
+ .name = DPS310_DEV_NAME,
+ },
+ .probe = dps310_probe,
+ .id_table = dps310_id,
+};
+module_i2c_driver(dps310_driver);
+
+MODULE_AUTHOR("Joel Stanley <joel@jms.id.au>");
+MODULE_DESCRIPTION("Infineon DPS310 pressure and temperature sensor");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/pressure/hp03.c b/drivers/iio/pressure/hp03.c
index 406934ea6228..f00102577fd5 100644
--- a/drivers/iio/pressure/hp03.c
+++ b/drivers/iio/pressure/hp03.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2016 Marek Vasut <marex@denx.de>
*
* Driver for Hope RF HP03 digital temperature and pressure sensor.
- *
- * 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.
*/
#define pr_fmt(fmt) "hp03: " fmt
diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c
index ff80409e0c44..612f79c53cfc 100644
--- a/drivers/iio/proximity/sx9500.c
+++ b/drivers/iio/proximity/sx9500.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014 Intel Corporation
*
* Driver for Semtech's SX9500 capacitive proximity/button solution.
* Datasheet available at
* <http://www.semtech.com/images/datasheet/sx9500.pdf>.
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/iio/resolver/ad2s1200.c b/drivers/iio/resolver/ad2s1200.c
index 28e618af9939..17b89623418c 100644
--- a/drivers/iio/resolver/ad2s1200.c
+++ b/drivers/iio/resolver/ad2s1200.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ad2s1200.c simple support for the ADI Resolver to Digital Converters:
* AD2S1200/1205
*
* Copyright (c) 2018-2018 David Veenstra <davidjulianveenstra@gmail.com>
* Copyright (c) 2010-2010 Analog 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.
*/
#include <linux/bitops.h>
diff --git a/drivers/iio/temperature/maxim_thermocouple.c b/drivers/iio/temperature/maxim_thermocouple.c
index c31b9633f32d..c613a64c017f 100644
--- a/drivers/iio/temperature/maxim_thermocouple.c
+++ b/drivers/iio/temperature/maxim_thermocouple.c
@@ -10,6 +10,8 @@
#include <linux/init.h>
#include <linux/mutex.h>
#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
@@ -262,9 +264,17 @@ static const struct spi_device_id maxim_thermocouple_id[] = {
};
MODULE_DEVICE_TABLE(spi, maxim_thermocouple_id);
+static const struct of_device_id maxim_thermocouple_of_match[] = {
+ { .compatible = "maxim,max6675" },
+ { .compatible = "maxim,max31855" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, maxim_thermocouple_of_match);
+
static struct spi_driver maxim_thermocouple_driver = {
.driver = {
.name = MAXIM_THERMOCOUPLE_DRV_NAME,
+ .of_match_table = maxim_thermocouple_of_match,
},
.probe = maxim_thermocouple_probe,
.remove = maxim_thermocouple_remove,
diff --git a/drivers/iio/temperature/mlx90632.c b/drivers/iio/temperature/mlx90632.c
index be03be719efe..eaca6ba06864 100644
--- a/drivers/iio/temperature/mlx90632.c
+++ b/drivers/iio/temperature/mlx90632.c
@@ -81,6 +81,8 @@
/* Magic constants */
#define MLX90632_ID_MEDICAL 0x0105 /* EEPROM DSPv5 Medical device id */
#define MLX90632_ID_CONSUMER 0x0205 /* EEPROM DSPv5 Consumer device id */
+#define MLX90632_DSP_VERSION 5 /* DSP version */
+#define MLX90632_DSP_MASK GENMASK(7, 0) /* DSP version in EE_VERSION */
#define MLX90632_RESET_CMD 0x0006 /* Reset sensor (address or global) */
#define MLX90632_REF_12 12LL /**< ResCtrlRef value of Ch 1 or Ch 2 */
#define MLX90632_REF_3 12LL /**< ResCtrlRef value of Channel 3 */
@@ -667,10 +669,13 @@ static int mlx90632_probe(struct i2c_client *client,
} else if (read == MLX90632_ID_CONSUMER) {
dev_dbg(&client->dev,
"Detected Consumer EEPROM calibration %x\n", read);
+ } else if ((read & MLX90632_DSP_MASK) == MLX90632_DSP_VERSION) {
+ dev_dbg(&client->dev,
+ "Detected Unknown EEPROM calibration %x\n", read);
} else {
dev_err(&client->dev,
- "EEPROM version mismatch %x (expected %x or %x)\n",
- read, MLX90632_ID_CONSUMER, MLX90632_ID_MEDICAL);
+ "Wrong DSP version %x (expected %x)\n",
+ read, MLX90632_DSP_VERSION);
return -EPROTONOSUPPORT;
}
diff --git a/drivers/iio/trigger/iio-trig-hrtimer.c b/drivers/iio/trigger/iio-trig-hrtimer.c
index 7accd0187ba1..a5e670726717 100644
--- a/drivers/iio/trigger/iio-trig-hrtimer.c
+++ b/drivers/iio/trigger/iio-trig-hrtimer.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/**
* The industrial I/O periodic hrtimer trigger driver
*
@@ -6,11 +7,6 @@
* Copyright (C) 2012, Analog Device Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
* Copyright (C) 2015, Intel Corporation
- *
- * 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.
- *
*/
#include <linux/kernel.h>
#include <linux/slab.h>
diff --git a/drivers/iio/trigger/iio-trig-interrupt.c b/drivers/iio/trigger/iio-trig-interrupt.c
index 171c4ed03543..94a487caf421 100644
--- a/drivers/iio/trigger/iio-trig-interrupt.c
+++ b/drivers/iio/trigger/iio-trig-interrupt.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Industrial I/O - generic interrupt based trigger support
*
* Copyright (c) 2008-2013 Jonathan Cameron
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig
index 8ba41cbf1869..85e103b147cc 100644
--- a/drivers/infiniband/Kconfig
+++ b/drivers/infiniband/Kconfig
@@ -7,6 +7,7 @@ menuconfig INFINIBAND
depends on m || IPV6 != m
depends on !ALPHA
select IRQ_POLL
+ select DIMLIB
---help---
Core support for InfiniBand (IB). Make sure to also select
any protocols you wish to use as well as drivers for your
@@ -36,17 +37,6 @@ config INFINIBAND_USER_ACCESS
libibverbs, libibcm and a hardware driver library from
rdma-core <https://github.com/linux-rdma/rdma-core>.
-config INFINIBAND_USER_ACCESS_UCM
- tristate "Userspace CM (UCM, DEPRECATED)"
- depends on BROKEN || COMPILE_TEST
- depends on INFINIBAND_USER_ACCESS
- help
- The UCM module has known security flaws, which no one is
- interested to fix. The user-space part of this code was
- dropped from the upstream a long time ago.
-
- This option is DEPRECATED and planned to be removed.
-
config INFINIBAND_EXP_LEGACY_VERBS_NEW_UAPI
bool "Allow experimental legacy verbs in new ioctl uAPI (EXPERIMENTAL)"
depends on INFINIBAND_USER_ACCESS
@@ -98,7 +88,6 @@ source "drivers/infiniband/hw/efa/Kconfig"
source "drivers/infiniband/hw/i40iw/Kconfig"
source "drivers/infiniband/hw/mlx4/Kconfig"
source "drivers/infiniband/hw/mlx5/Kconfig"
-source "drivers/infiniband/hw/nes/Kconfig"
source "drivers/infiniband/hw/ocrdma/Kconfig"
source "drivers/infiniband/hw/vmw_pvrdma/Kconfig"
source "drivers/infiniband/hw/usnic/Kconfig"
@@ -108,6 +97,7 @@ source "drivers/infiniband/hw/hfi1/Kconfig"
source "drivers/infiniband/hw/qedr/Kconfig"
source "drivers/infiniband/sw/rdmavt/Kconfig"
source "drivers/infiniband/sw/rxe/Kconfig"
+source "drivers/infiniband/sw/siw/Kconfig"
endif
source "drivers/infiniband/ulp/ipoib/Kconfig"
diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile
index 313f2349b518..09881bd5f12d 100644
--- a/drivers/infiniband/core/Makefile
+++ b/drivers/infiniband/core/Makefile
@@ -6,13 +6,12 @@ obj-$(CONFIG_INFINIBAND) += ib_core.o ib_cm.o iw_cm.o \
$(infiniband-y)
obj-$(CONFIG_INFINIBAND_USER_MAD) += ib_umad.o
obj-$(CONFIG_INFINIBAND_USER_ACCESS) += ib_uverbs.o $(user_access-y)
-obj-$(CONFIG_INFINIBAND_USER_ACCESS_UCM) += ib_ucm.o $(user_access-y)
ib_core-y := packer.o ud_header.o verbs.o cq.o rw.o sysfs.o \
device.o fmr_pool.o cache.o netlink.o \
roce_gid_mgmt.o mr_pool.o addr.o sa_query.o \
multicast.o mad.o smi.o agent.o mad_rmpp.o \
- nldev.o restrack.o
+ nldev.o restrack.o counters.o
ib_core-$(CONFIG_SECURITY_INFINIBAND) += security.o
ib_core-$(CONFIG_CGROUP_RDMA) += cgroup.o
@@ -29,8 +28,6 @@ rdma_ucm-y := ucma.o
ib_umad-y := user_mad.o
-ib_ucm-y := ucm.o
-
ib_uverbs-y := uverbs_main.o uverbs_cmd.o uverbs_marshall.o \
rdma_core.o uverbs_std_types.o uverbs_ioctl.o \
uverbs_std_types_cq.o \
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index 2f7d14159841..9b76a8fcdd24 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -337,7 +337,7 @@ static int dst_fetch_ha(const struct dst_entry *dst,
neigh_event_send(n, NULL);
ret = -ENODATA;
} else {
- memcpy(dev_addr->dst_dev_addr, n->ha, MAX_ADDR_LEN);
+ neigh_ha_snapshot(dev_addr->dst_dev_addr, n, dst->dev);
}
neigh_release(n);
diff --git a/drivers/infiniband/core/core_priv.h b/drivers/infiniband/core/core_priv.h
index ff40a450b5d2..888d89ce81df 100644
--- a/drivers/infiniband/core/core_priv.h
+++ b/drivers/infiniband/core/core_priv.h
@@ -60,6 +60,7 @@ extern bool ib_devices_shared_netns;
int ib_device_register_sysfs(struct ib_device *device);
void ib_device_unregister_sysfs(struct ib_device *device);
int ib_device_rename(struct ib_device *ibdev, const char *name);
+int ib_device_set_dim(struct ib_device *ibdev, u8 use_dim);
typedef void (*roce_netdev_callback)(struct ib_device *device, u8 port,
struct net_device *idev, void *cookie);
@@ -88,6 +89,15 @@ typedef int (*nldev_callback)(struct ib_device *device,
int ib_enum_all_devs(nldev_callback nldev_cb, struct sk_buff *skb,
struct netlink_callback *cb);
+struct ib_client_nl_info {
+ struct sk_buff *nl_msg;
+ struct device *cdev;
+ unsigned int port;
+ u64 abi;
+};
+int ib_get_client_nl_info(struct ib_device *ibdev, const char *client_name,
+ struct ib_client_nl_info *res);
+
enum ib_cache_gid_default_mode {
IB_CACHE_GID_DEFAULT_MODE_SET,
IB_CACHE_GID_DEFAULT_MODE_DELETE
diff --git a/drivers/infiniband/core/counters.c b/drivers/infiniband/core/counters.c
new file mode 100644
index 000000000000..01faef7bc061
--- /dev/null
+++ b/drivers/infiniband/core/counters.c
@@ -0,0 +1,634 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/*
+ * Copyright (c) 2019 Mellanox Technologies. All rights reserved.
+ */
+#include <rdma/ib_verbs.h>
+#include <rdma/rdma_counter.h>
+
+#include "core_priv.h"
+#include "restrack.h"
+
+#define ALL_AUTO_MODE_MASKS (RDMA_COUNTER_MASK_QP_TYPE)
+
+static int __counter_set_mode(struct rdma_counter_mode *curr,
+ enum rdma_nl_counter_mode new_mode,
+ enum rdma_nl_counter_mask new_mask)
+{
+ if ((new_mode == RDMA_COUNTER_MODE_AUTO) &&
+ ((new_mask & (~ALL_AUTO_MODE_MASKS)) ||
+ (curr->mode != RDMA_COUNTER_MODE_NONE)))
+ return -EINVAL;
+
+ curr->mode = new_mode;
+ curr->mask = new_mask;
+ return 0;
+}
+
+/**
+ * rdma_counter_set_auto_mode() - Turn on/off per-port auto mode
+ *
+ * When @on is true, the @mask must be set; When @on is false, it goes
+ * into manual mode if there's any counter, so that the user is able to
+ * manually access them.
+ */
+int rdma_counter_set_auto_mode(struct ib_device *dev, u8 port,
+ bool on, enum rdma_nl_counter_mask mask)
+{
+ struct rdma_port_counter *port_counter;
+ int ret;
+
+ port_counter = &dev->port_data[port].port_counter;
+ mutex_lock(&port_counter->lock);
+ if (on) {
+ ret = __counter_set_mode(&port_counter->mode,
+ RDMA_COUNTER_MODE_AUTO, mask);
+ } else {
+ if (port_counter->mode.mode != RDMA_COUNTER_MODE_AUTO) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (port_counter->num_counters)
+ ret = __counter_set_mode(&port_counter->mode,
+ RDMA_COUNTER_MODE_MANUAL, 0);
+ else
+ ret = __counter_set_mode(&port_counter->mode,
+ RDMA_COUNTER_MODE_NONE, 0);
+ }
+
+out:
+ mutex_unlock(&port_counter->lock);
+ return ret;
+}
+
+static struct rdma_counter *rdma_counter_alloc(struct ib_device *dev, u8 port,
+ enum rdma_nl_counter_mode mode)
+{
+ struct rdma_port_counter *port_counter;
+ struct rdma_counter *counter;
+ int ret;
+
+ if (!dev->ops.counter_dealloc || !dev->ops.counter_alloc_stats)
+ return NULL;
+
+ counter = kzalloc(sizeof(*counter), GFP_KERNEL);
+ if (!counter)
+ return NULL;
+
+ counter->device = dev;
+ counter->port = port;
+ counter->res.type = RDMA_RESTRACK_COUNTER;
+ counter->stats = dev->ops.counter_alloc_stats(counter);
+ if (!counter->stats)
+ goto err_stats;
+
+ port_counter = &dev->port_data[port].port_counter;
+ mutex_lock(&port_counter->lock);
+ if (mode == RDMA_COUNTER_MODE_MANUAL) {
+ ret = __counter_set_mode(&port_counter->mode,
+ RDMA_COUNTER_MODE_MANUAL, 0);
+ if (ret)
+ goto err_mode;
+ }
+
+ port_counter->num_counters++;
+ mutex_unlock(&port_counter->lock);
+
+ counter->mode.mode = mode;
+ kref_init(&counter->kref);
+ mutex_init(&counter->lock);
+
+ return counter;
+
+err_mode:
+ mutex_unlock(&port_counter->lock);
+ kfree(counter->stats);
+err_stats:
+ kfree(counter);
+ return NULL;
+}
+
+static void rdma_counter_free(struct rdma_counter *counter)
+{
+ struct rdma_port_counter *port_counter;
+
+ port_counter = &counter->device->port_data[counter->port].port_counter;
+ mutex_lock(&port_counter->lock);
+ port_counter->num_counters--;
+ if (!port_counter->num_counters &&
+ (port_counter->mode.mode == RDMA_COUNTER_MODE_MANUAL))
+ __counter_set_mode(&port_counter->mode, RDMA_COUNTER_MODE_NONE,
+ 0);
+
+ mutex_unlock(&port_counter->lock);
+
+ rdma_restrack_del(&counter->res);
+ kfree(counter->stats);
+ kfree(counter);
+}
+
+static void auto_mode_init_counter(struct rdma_counter *counter,
+ const struct ib_qp *qp,
+ enum rdma_nl_counter_mask new_mask)
+{
+ struct auto_mode_param *param = &counter->mode.param;
+
+ counter->mode.mode = RDMA_COUNTER_MODE_AUTO;
+ counter->mode.mask = new_mask;
+
+ if (new_mask & RDMA_COUNTER_MASK_QP_TYPE)
+ param->qp_type = qp->qp_type;
+}
+
+static bool auto_mode_match(struct ib_qp *qp, struct rdma_counter *counter,
+ enum rdma_nl_counter_mask auto_mask)
+{
+ struct auto_mode_param *param = &counter->mode.param;
+ bool match = true;
+
+ if (rdma_is_kernel_res(&counter->res) != rdma_is_kernel_res(&qp->res))
+ return false;
+
+ /* Ensure that counter belong to right PID */
+ if (!rdma_is_kernel_res(&counter->res) &&
+ !rdma_is_kernel_res(&qp->res) &&
+ (task_pid_vnr(counter->res.task) != current->pid))
+ return false;
+
+ if (auto_mask & RDMA_COUNTER_MASK_QP_TYPE)
+ match &= (param->qp_type == qp->qp_type);
+
+ return match;
+}
+
+static int __rdma_counter_bind_qp(struct rdma_counter *counter,
+ struct ib_qp *qp)
+{
+ int ret;
+
+ if (qp->counter)
+ return -EINVAL;
+
+ if (!qp->device->ops.counter_bind_qp)
+ return -EOPNOTSUPP;
+
+ mutex_lock(&counter->lock);
+ ret = qp->device->ops.counter_bind_qp(counter, qp);
+ mutex_unlock(&counter->lock);
+
+ return ret;
+}
+
+static int __rdma_counter_unbind_qp(struct ib_qp *qp)
+{
+ struct rdma_counter *counter = qp->counter;
+ int ret;
+
+ if (!qp->device->ops.counter_unbind_qp)
+ return -EOPNOTSUPP;
+
+ mutex_lock(&counter->lock);
+ ret = qp->device->ops.counter_unbind_qp(qp);
+ mutex_unlock(&counter->lock);
+
+ return ret;
+}
+
+static void counter_history_stat_update(const struct rdma_counter *counter)
+{
+ struct ib_device *dev = counter->device;
+ struct rdma_port_counter *port_counter;
+ int i;
+
+ port_counter = &dev->port_data[counter->port].port_counter;
+ if (!port_counter->hstats)
+ return;
+
+ for (i = 0; i < counter->stats->num_counters; i++)
+ port_counter->hstats->value[i] += counter->stats->value[i];
+}
+
+/**
+ * rdma_get_counter_auto_mode - Find the counter that @qp should be bound
+ * with in auto mode
+ *
+ * Return: The counter (with ref-count increased) if found
+ */
+static struct rdma_counter *rdma_get_counter_auto_mode(struct ib_qp *qp,
+ u8 port)
+{
+ struct rdma_port_counter *port_counter;
+ struct rdma_counter *counter = NULL;
+ struct ib_device *dev = qp->device;
+ struct rdma_restrack_entry *res;
+ struct rdma_restrack_root *rt;
+ unsigned long id = 0;
+
+ port_counter = &dev->port_data[port].port_counter;
+ rt = &dev->res[RDMA_RESTRACK_COUNTER];
+ xa_lock(&rt->xa);
+ xa_for_each(&rt->xa, id, res) {
+ if (!rdma_is_visible_in_pid_ns(res))
+ continue;
+
+ counter = container_of(res, struct rdma_counter, res);
+ if ((counter->device != qp->device) || (counter->port != port))
+ goto next;
+
+ if (auto_mode_match(qp, counter, port_counter->mode.mask))
+ break;
+next:
+ counter = NULL;
+ }
+
+ if (counter && !kref_get_unless_zero(&counter->kref))
+ counter = NULL;
+
+ xa_unlock(&rt->xa);
+ return counter;
+}
+
+static void rdma_counter_res_add(struct rdma_counter *counter,
+ struct ib_qp *qp)
+{
+ if (rdma_is_kernel_res(&qp->res)) {
+ rdma_restrack_set_task(&counter->res, qp->res.kern_name);
+ rdma_restrack_kadd(&counter->res);
+ } else {
+ rdma_restrack_attach_task(&counter->res, qp->res.task);
+ rdma_restrack_uadd(&counter->res);
+ }
+}
+
+static void counter_release(struct kref *kref)
+{
+ struct rdma_counter *counter;
+
+ counter = container_of(kref, struct rdma_counter, kref);
+ counter_history_stat_update(counter);
+ counter->device->ops.counter_dealloc(counter);
+ rdma_counter_free(counter);
+}
+
+/**
+ * rdma_counter_bind_qp_auto - Check and bind the QP to a counter base on
+ * the auto-mode rule
+ */
+int rdma_counter_bind_qp_auto(struct ib_qp *qp, u8 port)
+{
+ struct rdma_port_counter *port_counter;
+ struct ib_device *dev = qp->device;
+ struct rdma_counter *counter;
+ int ret;
+
+ if (!rdma_is_port_valid(dev, port))
+ return -EINVAL;
+
+ port_counter = &dev->port_data[port].port_counter;
+ if (port_counter->mode.mode != RDMA_COUNTER_MODE_AUTO)
+ return 0;
+
+ counter = rdma_get_counter_auto_mode(qp, port);
+ if (counter) {
+ ret = __rdma_counter_bind_qp(counter, qp);
+ if (ret) {
+ kref_put(&counter->kref, counter_release);
+ return ret;
+ }
+ } else {
+ counter = rdma_counter_alloc(dev, port, RDMA_COUNTER_MODE_AUTO);
+ if (!counter)
+ return -ENOMEM;
+
+ auto_mode_init_counter(counter, qp, port_counter->mode.mask);
+
+ ret = __rdma_counter_bind_qp(counter, qp);
+ if (ret) {
+ rdma_counter_free(counter);
+ return ret;
+ }
+
+ rdma_counter_res_add(counter, qp);
+ }
+
+ return 0;
+}
+
+/**
+ * rdma_counter_unbind_qp - Unbind a qp from a counter
+ * @force:
+ * true - Decrease the counter ref-count anyway (e.g., qp destroy)
+ */
+int rdma_counter_unbind_qp(struct ib_qp *qp, bool force)
+{
+ struct rdma_counter *counter = qp->counter;
+ int ret;
+
+ if (!counter)
+ return -EINVAL;
+
+ ret = __rdma_counter_unbind_qp(qp);
+ if (ret && !force)
+ return ret;
+
+ kref_put(&counter->kref, counter_release);
+ return 0;
+}
+
+int rdma_counter_query_stats(struct rdma_counter *counter)
+{
+ struct ib_device *dev = counter->device;
+ int ret;
+
+ if (!dev->ops.counter_update_stats)
+ return -EINVAL;
+
+ mutex_lock(&counter->lock);
+ ret = dev->ops.counter_update_stats(counter);
+ mutex_unlock(&counter->lock);
+
+ return ret;
+}
+
+static u64 get_running_counters_hwstat_sum(struct ib_device *dev,
+ u8 port, u32 index)
+{
+ struct rdma_restrack_entry *res;
+ struct rdma_restrack_root *rt;
+ struct rdma_counter *counter;
+ unsigned long id = 0;
+ u64 sum = 0;
+
+ rt = &dev->res[RDMA_RESTRACK_COUNTER];
+ xa_lock(&rt->xa);
+ xa_for_each(&rt->xa, id, res) {
+ if (!rdma_restrack_get(res))
+ continue;
+
+ xa_unlock(&rt->xa);
+
+ counter = container_of(res, struct rdma_counter, res);
+ if ((counter->device != dev) || (counter->port != port) ||
+ rdma_counter_query_stats(counter))
+ goto next;
+
+ sum += counter->stats->value[index];
+
+next:
+ xa_lock(&rt->xa);
+ rdma_restrack_put(res);
+ }
+
+ xa_unlock(&rt->xa);
+ return sum;
+}
+
+/**
+ * rdma_counter_get_hwstat_value() - Get the sum value of all counters on a
+ * specific port, including the running ones and history data
+ */
+u64 rdma_counter_get_hwstat_value(struct ib_device *dev, u8 port, u32 index)
+{
+ struct rdma_port_counter *port_counter;
+ u64 sum;
+
+ port_counter = &dev->port_data[port].port_counter;
+ sum = get_running_counters_hwstat_sum(dev, port, index);
+ sum += port_counter->hstats->value[index];
+
+ return sum;
+}
+
+static struct ib_qp *rdma_counter_get_qp(struct ib_device *dev, u32 qp_num)
+{
+ struct rdma_restrack_entry *res = NULL;
+ struct ib_qp *qp = NULL;
+
+ res = rdma_restrack_get_byid(dev, RDMA_RESTRACK_QP, qp_num);
+ if (IS_ERR(res))
+ return NULL;
+
+ if (!rdma_is_visible_in_pid_ns(res))
+ goto err;
+
+ qp = container_of(res, struct ib_qp, res);
+ if (qp->qp_type == IB_QPT_RAW_PACKET && !capable(CAP_NET_RAW))
+ goto err;
+
+ return qp;
+
+err:
+ rdma_restrack_put(&qp->res);
+ return NULL;
+}
+
+static int rdma_counter_bind_qp_manual(struct rdma_counter *counter,
+ struct ib_qp *qp)
+{
+ if ((counter->device != qp->device) || (counter->port != qp->port))
+ return -EINVAL;
+
+ return __rdma_counter_bind_qp(counter, qp);
+}
+
+static struct rdma_counter *rdma_get_counter_by_id(struct ib_device *dev,
+ u32 counter_id)
+{
+ struct rdma_restrack_entry *res;
+ struct rdma_counter *counter;
+
+ res = rdma_restrack_get_byid(dev, RDMA_RESTRACK_COUNTER, counter_id);
+ if (IS_ERR(res))
+ return NULL;
+
+ if (!rdma_is_visible_in_pid_ns(res)) {
+ rdma_restrack_put(res);
+ return NULL;
+ }
+
+ counter = container_of(res, struct rdma_counter, res);
+ kref_get(&counter->kref);
+ rdma_restrack_put(res);
+
+ return counter;
+}
+
+/**
+ * rdma_counter_bind_qpn() - Bind QP @qp_num to counter @counter_id
+ */
+int rdma_counter_bind_qpn(struct ib_device *dev, u8 port,
+ u32 qp_num, u32 counter_id)
+{
+ struct rdma_counter *counter;
+ struct ib_qp *qp;
+ int ret;
+
+ qp = rdma_counter_get_qp(dev, qp_num);
+ if (!qp)
+ return -ENOENT;
+
+ counter = rdma_get_counter_by_id(dev, counter_id);
+ if (!counter) {
+ ret = -ENOENT;
+ goto err;
+ }
+
+ if (counter->res.task != qp->res.task) {
+ ret = -EINVAL;
+ goto err_task;
+ }
+
+ ret = rdma_counter_bind_qp_manual(counter, qp);
+ if (ret)
+ goto err_task;
+
+ rdma_restrack_put(&qp->res);
+ return 0;
+
+err_task:
+ kref_put(&counter->kref, counter_release);
+err:
+ rdma_restrack_put(&qp->res);
+ return ret;
+}
+
+/**
+ * rdma_counter_bind_qpn_alloc() - Alloc a counter and bind QP @qp_num to it
+ * The id of new counter is returned in @counter_id
+ */
+int rdma_counter_bind_qpn_alloc(struct ib_device *dev, u8 port,
+ u32 qp_num, u32 *counter_id)
+{
+ struct rdma_counter *counter;
+ struct ib_qp *qp;
+ int ret;
+
+ if (!rdma_is_port_valid(dev, port))
+ return -EINVAL;
+
+ qp = rdma_counter_get_qp(dev, qp_num);
+ if (!qp)
+ return -ENOENT;
+
+ if (rdma_is_port_valid(dev, qp->port) && (qp->port != port)) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ counter = rdma_counter_alloc(dev, port, RDMA_COUNTER_MODE_MANUAL);
+ if (!counter) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ret = rdma_counter_bind_qp_manual(counter, qp);
+ if (ret)
+ goto err_bind;
+
+ if (counter_id)
+ *counter_id = counter->id;
+
+ rdma_counter_res_add(counter, qp);
+
+ rdma_restrack_put(&qp->res);
+ return ret;
+
+err_bind:
+ rdma_counter_free(counter);
+err:
+ rdma_restrack_put(&qp->res);
+ return ret;
+}
+
+/**
+ * rdma_counter_unbind_qpn() - Unbind QP @qp_num from a counter
+ */
+int rdma_counter_unbind_qpn(struct ib_device *dev, u8 port,
+ u32 qp_num, u32 counter_id)
+{
+ struct rdma_port_counter *port_counter;
+ struct ib_qp *qp;
+ int ret;
+
+ if (!rdma_is_port_valid(dev, port))
+ return -EINVAL;
+
+ qp = rdma_counter_get_qp(dev, qp_num);
+ if (!qp)
+ return -ENOENT;
+
+ if (rdma_is_port_valid(dev, qp->port) && (qp->port != port)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ port_counter = &dev->port_data[port].port_counter;
+ if (!qp->counter || qp->counter->id != counter_id ||
+ port_counter->mode.mode != RDMA_COUNTER_MODE_MANUAL) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = rdma_counter_unbind_qp(qp, false);
+
+out:
+ rdma_restrack_put(&qp->res);
+ return ret;
+}
+
+int rdma_counter_get_mode(struct ib_device *dev, u8 port,
+ enum rdma_nl_counter_mode *mode,
+ enum rdma_nl_counter_mask *mask)
+{
+ struct rdma_port_counter *port_counter;
+
+ port_counter = &dev->port_data[port].port_counter;
+ *mode = port_counter->mode.mode;
+ *mask = port_counter->mode.mask;
+
+ return 0;
+}
+
+void rdma_counter_init(struct ib_device *dev)
+{
+ struct rdma_port_counter *port_counter;
+ u32 port;
+
+ if (!dev->ops.alloc_hw_stats || !dev->port_data)
+ return;
+
+ rdma_for_each_port(dev, port) {
+ port_counter = &dev->port_data[port].port_counter;
+ port_counter->mode.mode = RDMA_COUNTER_MODE_NONE;
+ mutex_init(&port_counter->lock);
+
+ port_counter->hstats = dev->ops.alloc_hw_stats(dev, port);
+ if (!port_counter->hstats)
+ goto fail;
+ }
+
+ return;
+
+fail:
+ rdma_for_each_port(dev, port) {
+ port_counter = &dev->port_data[port].port_counter;
+ kfree(port_counter->hstats);
+ port_counter->hstats = NULL;
+ }
+
+ return;
+}
+
+void rdma_counter_release(struct ib_device *dev)
+{
+ struct rdma_port_counter *port_counter;
+ u32 port;
+
+ if (!dev->ops.alloc_hw_stats)
+ return;
+
+ rdma_for_each_port(dev, port) {
+ port_counter = &dev->port_data[port].port_counter;
+ kfree(port_counter->hstats);
+ }
+}
diff --git a/drivers/infiniband/core/cq.c b/drivers/infiniband/core/cq.c
index a24c900fbdf6..7c599878ccf7 100644
--- a/drivers/infiniband/core/cq.c
+++ b/drivers/infiniband/core/cq.c
@@ -18,6 +18,53 @@
#define IB_POLL_FLAGS \
(IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS)
+static const struct dim_cq_moder
+rdma_dim_prof[RDMA_DIM_PARAMS_NUM_PROFILES] = {
+ {1, 0, 1, 0},
+ {1, 0, 4, 0},
+ {2, 0, 4, 0},
+ {2, 0, 8, 0},
+ {4, 0, 8, 0},
+ {16, 0, 8, 0},
+ {16, 0, 16, 0},
+ {32, 0, 16, 0},
+ {32, 0, 32, 0},
+};
+
+static void ib_cq_rdma_dim_work(struct work_struct *w)
+{
+ struct dim *dim = container_of(w, struct dim, work);
+ struct ib_cq *cq = dim->priv;
+
+ u16 usec = rdma_dim_prof[dim->profile_ix].usec;
+ u16 comps = rdma_dim_prof[dim->profile_ix].comps;
+
+ dim->state = DIM_START_MEASURE;
+
+ cq->device->ops.modify_cq(cq, comps, usec);
+}
+
+static void rdma_dim_init(struct ib_cq *cq)
+{
+ struct dim *dim;
+
+ if (!cq->device->ops.modify_cq || !cq->device->use_cq_dim ||
+ cq->poll_ctx == IB_POLL_DIRECT)
+ return;
+
+ dim = kzalloc(sizeof(struct dim), GFP_KERNEL);
+ if (!dim)
+ return;
+
+ dim->state = DIM_START_MEASURE;
+ dim->tune_state = DIM_GOING_RIGHT;
+ dim->profile_ix = RDMA_DIM_START_PROFILE;
+ dim->priv = cq;
+ cq->dim = dim;
+
+ INIT_WORK(&dim->work, ib_cq_rdma_dim_work);
+}
+
static int __ib_process_cq(struct ib_cq *cq, int budget, struct ib_wc *wcs,
int batch)
{
@@ -78,6 +125,7 @@ static void ib_cq_completion_direct(struct ib_cq *cq, void *private)
static int ib_poll_handler(struct irq_poll *iop, int budget)
{
struct ib_cq *cq = container_of(iop, struct ib_cq, iop);
+ struct dim *dim = cq->dim;
int completed;
completed = __ib_process_cq(cq, budget, cq->wc, IB_POLL_BATCH);
@@ -87,6 +135,9 @@ static int ib_poll_handler(struct irq_poll *iop, int budget)
irq_poll_sched(&cq->iop);
}
+ if (dim)
+ rdma_dim(dim, completed);
+
return completed;
}
@@ -105,6 +156,8 @@ static void ib_cq_poll_work(struct work_struct *work)
if (completed >= IB_POLL_BUDGET_WORKQUEUE ||
ib_req_notify_cq(cq, IB_POLL_FLAGS) > 0)
queue_work(cq->comp_wq, &cq->work);
+ else if (cq->dim)
+ rdma_dim(cq->dim, completed);
}
static void ib_cq_completion_workqueue(struct ib_cq *cq, void *private)
@@ -113,7 +166,7 @@ static void ib_cq_completion_workqueue(struct ib_cq *cq, void *private)
}
/**
- * __ib_alloc_cq - allocate a completion queue
+ * __ib_alloc_cq_user - allocate a completion queue
* @dev: device to allocate the CQ for
* @private: driver private data, accessible from cq->cq_context
* @nr_cqe: number of CQEs to allocate
@@ -139,25 +192,30 @@ struct ib_cq *__ib_alloc_cq_user(struct ib_device *dev, void *private,
struct ib_cq *cq;
int ret = -ENOMEM;
- cq = dev->ops.create_cq(dev, &cq_attr, NULL);
- if (IS_ERR(cq))
- return cq;
+ cq = rdma_zalloc_drv_obj(dev, ib_cq);
+ if (!cq)
+ return ERR_PTR(ret);
cq->device = dev;
- cq->uobject = NULL;
- cq->event_handler = NULL;
cq->cq_context = private;
cq->poll_ctx = poll_ctx;
atomic_set(&cq->usecnt, 0);
cq->wc = kmalloc_array(IB_POLL_BATCH, sizeof(*cq->wc), GFP_KERNEL);
if (!cq->wc)
- goto out_destroy_cq;
+ goto out_free_cq;
cq->res.type = RDMA_RESTRACK_CQ;
rdma_restrack_set_task(&cq->res, caller);
+
+ ret = dev->ops.create_cq(cq, &cq_attr, NULL);
+ if (ret)
+ goto out_free_wc;
+
rdma_restrack_kadd(&cq->res);
+ rdma_dim_init(cq);
+
switch (cq->poll_ctx) {
case IB_POLL_DIRECT:
cq->comp_handler = ib_cq_completion_direct;
@@ -178,29 +236,29 @@ struct ib_cq *__ib_alloc_cq_user(struct ib_device *dev, void *private,
break;
default:
ret = -EINVAL;
- goto out_free_wc;
+ goto out_destroy_cq;
}
return cq;
-out_free_wc:
- kfree(cq->wc);
- rdma_restrack_del(&cq->res);
out_destroy_cq:
+ rdma_restrack_del(&cq->res);
cq->device->ops.destroy_cq(cq, udata);
+out_free_wc:
+ kfree(cq->wc);
+out_free_cq:
+ kfree(cq);
return ERR_PTR(ret);
}
EXPORT_SYMBOL(__ib_alloc_cq_user);
/**
- * ib_free_cq - free a completion queue
+ * ib_free_cq_user - free a completion queue
* @cq: completion queue to free.
* @udata: User data or NULL for kernel object
*/
void ib_free_cq_user(struct ib_cq *cq, struct ib_udata *udata)
{
- int ret;
-
if (WARN_ON_ONCE(atomic_read(&cq->usecnt)))
return;
@@ -218,9 +276,12 @@ void ib_free_cq_user(struct ib_cq *cq, struct ib_udata *udata)
WARN_ON_ONCE(1);
}
- kfree(cq->wc);
rdma_restrack_del(&cq->res);
- ret = cq->device->ops.destroy_cq(cq, udata);
- WARN_ON_ONCE(ret);
+ cq->device->ops.destroy_cq(cq, udata);
+ if (cq->dim)
+ cancel_work_sync(&cq->dim->work);
+ kfree(cq->dim);
+ kfree(cq->wc);
+ kfree(cq);
}
EXPORT_SYMBOL(ib_free_cq_user);
diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c
index 29f7b15c81d9..9773145dee09 100644
--- a/drivers/infiniband/core/device.c
+++ b/drivers/infiniband/core/device.c
@@ -46,6 +46,7 @@
#include <rdma/rdma_netlink.h>
#include <rdma/ib_addr.h>
#include <rdma/ib_cache.h>
+#include <rdma/rdma_counter.h>
#include "core_priv.h"
#include "restrack.h"
@@ -270,7 +271,7 @@ struct ib_port_data_rcu {
struct ib_port_data pdata[];
};
-static int ib_device_check_mandatory(struct ib_device *device)
+static void ib_device_check_mandatory(struct ib_device *device)
{
#define IB_MANDATORY_FUNC(x) { offsetof(struct ib_device_ops, x), #x }
static const struct {
@@ -305,8 +306,6 @@ static int ib_device_check_mandatory(struct ib_device *device)
break;
}
}
-
- return 0;
}
/*
@@ -375,7 +374,7 @@ struct ib_device *ib_device_get_by_name(const char *name,
down_read(&devices_rwsem);
device = __ib_device_get_by_name(name);
if (device && driver_id != RDMA_DRIVER_UNKNOWN &&
- device->driver_id != driver_id)
+ device->ops.driver_id != driver_id)
device = NULL;
if (device) {
@@ -449,6 +448,15 @@ int ib_device_rename(struct ib_device *ibdev, const char *name)
return 0;
}
+int ib_device_set_dim(struct ib_device *ibdev, u8 use_dim)
+{
+ if (use_dim > 1)
+ return -EINVAL;
+ ibdev->use_cq_dim = use_dim;
+
+ return 0;
+}
+
static int alloc_name(struct ib_device *ibdev, const char *name)
{
struct ib_device *device;
@@ -457,7 +465,7 @@ static int alloc_name(struct ib_device *ibdev, const char *name)
int rc;
int i;
- lockdep_assert_held_exclusive(&devices_rwsem);
+ lockdep_assert_held_write(&devices_rwsem);
ida_init(&inuse);
xa_for_each (&devices, index, device) {
char buf[IB_DEVICE_NAME_MAX];
@@ -494,10 +502,12 @@ static void ib_device_release(struct device *device)
if (dev->port_data) {
ib_cache_release_one(dev);
ib_security_release_port_pkey_list(dev);
+ rdma_counter_release(dev);
kfree_rcu(container_of(dev->port_data, struct ib_port_data_rcu,
pdata[0]),
rcu_head);
}
+
xa_destroy(&dev->compat_devs);
xa_destroy(&dev->client_data);
kfree_rcu(dev, rcu_head);
@@ -1193,10 +1203,7 @@ static int setup_device(struct ib_device *device)
int ret;
setup_dma_device(device);
-
- ret = ib_device_check_mandatory(device);
- if (ret)
- return ret;
+ ib_device_check_mandatory(device);
ret = setup_port_data(device);
if (ret) {
@@ -1321,6 +1328,8 @@ int ib_register_device(struct ib_device *device, const char *name)
ib_device_register_rdmacg(device);
+ rdma_counter_init(device);
+
/*
* Ensure that ADD uevent is not fired because it
* is too early amd device is not initialized yet.
@@ -1479,7 +1488,7 @@ void ib_unregister_driver(enum rdma_driver_id driver_id)
down_read(&devices_rwsem);
xa_for_each (&devices, index, ib_dev) {
- if (ib_dev->driver_id != driver_id)
+ if (ib_dev->ops.driver_id != driver_id)
continue;
get_device(&ib_dev->dev);
@@ -1749,6 +1758,104 @@ void ib_unregister_client(struct ib_client *client)
}
EXPORT_SYMBOL(ib_unregister_client);
+static int __ib_get_global_client_nl_info(const char *client_name,
+ struct ib_client_nl_info *res)
+{
+ struct ib_client *client;
+ unsigned long index;
+ int ret = -ENOENT;
+
+ down_read(&clients_rwsem);
+ xa_for_each_marked (&clients, index, client, CLIENT_REGISTERED) {
+ if (strcmp(client->name, client_name) != 0)
+ continue;
+ if (!client->get_global_nl_info) {
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ ret = client->get_global_nl_info(res);
+ if (WARN_ON(ret == -ENOENT))
+ ret = -EINVAL;
+ if (!ret && res->cdev)
+ get_device(res->cdev);
+ break;
+ }
+ up_read(&clients_rwsem);
+ return ret;
+}
+
+static int __ib_get_client_nl_info(struct ib_device *ibdev,
+ const char *client_name,
+ struct ib_client_nl_info *res)
+{
+ unsigned long index;
+ void *client_data;
+ int ret = -ENOENT;
+
+ down_read(&ibdev->client_data_rwsem);
+ xan_for_each_marked (&ibdev->client_data, index, client_data,
+ CLIENT_DATA_REGISTERED) {
+ struct ib_client *client = xa_load(&clients, index);
+
+ if (!client || strcmp(client->name, client_name) != 0)
+ continue;
+ if (!client->get_nl_info) {
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ ret = client->get_nl_info(ibdev, client_data, res);
+ if (WARN_ON(ret == -ENOENT))
+ ret = -EINVAL;
+
+ /*
+ * The cdev is guaranteed valid as long as we are inside the
+ * client_data_rwsem as remove_one can't be called. Keep it
+ * valid for the caller.
+ */
+ if (!ret && res->cdev)
+ get_device(res->cdev);
+ break;
+ }
+ up_read(&ibdev->client_data_rwsem);
+
+ return ret;
+}
+
+/**
+ * ib_get_client_nl_info - Fetch the nl_info from a client
+ * @device - IB device
+ * @client_name - Name of the client
+ * @res - Result of the query
+ */
+int ib_get_client_nl_info(struct ib_device *ibdev, const char *client_name,
+ struct ib_client_nl_info *res)
+{
+ int ret;
+
+ if (ibdev)
+ ret = __ib_get_client_nl_info(ibdev, client_name, res);
+ else
+ ret = __ib_get_global_client_nl_info(client_name, res);
+#ifdef CONFIG_MODULES
+ if (ret == -ENOENT) {
+ request_module("rdma-client-%s", client_name);
+ if (ibdev)
+ ret = __ib_get_client_nl_info(ibdev, client_name, res);
+ else
+ ret = __ib_get_global_client_nl_info(client_name, res);
+ }
+#endif
+ if (ret) {
+ if (ret == -ENOENT)
+ return -EOPNOTSUPP;
+ return ret;
+ }
+
+ if (WARN_ON(!res->cdev))
+ return -EINVAL;
+ return 0;
+}
+
/**
* ib_set_client_data - Set IB client context
* @device:Device to set context for
@@ -2039,7 +2146,7 @@ struct ib_device *ib_device_get_by_netdev(struct net_device *ndev,
(uintptr_t)ndev) {
if (rcu_access_pointer(cur->netdev) == ndev &&
(driver_id == RDMA_DRIVER_UNKNOWN ||
- cur->ib_dev->driver_id == driver_id) &&
+ cur->ib_dev->ops.driver_id == driver_id) &&
ib_device_try_get(cur->ib_dev)) {
res = cur->ib_dev;
break;
@@ -2344,12 +2451,28 @@ void ib_set_device_ops(struct ib_device *dev, const struct ib_device_ops *ops)
#define SET_OBJ_SIZE(ptr, name) SET_DEVICE_OP(ptr, size_##name)
+ if (ops->driver_id != RDMA_DRIVER_UNKNOWN) {
+ WARN_ON(dev_ops->driver_id != RDMA_DRIVER_UNKNOWN &&
+ dev_ops->driver_id != ops->driver_id);
+ dev_ops->driver_id = ops->driver_id;
+ }
+ if (ops->owner) {
+ WARN_ON(dev_ops->owner && dev_ops->owner != ops->owner);
+ dev_ops->owner = ops->owner;
+ }
+ if (ops->uverbs_abi_ver)
+ dev_ops->uverbs_abi_ver = ops->uverbs_abi_ver;
+
+ dev_ops->uverbs_no_driver_id_binding |=
+ ops->uverbs_no_driver_id_binding;
+
SET_DEVICE_OP(dev_ops, add_gid);
SET_DEVICE_OP(dev_ops, advise_mr);
SET_DEVICE_OP(dev_ops, alloc_dm);
SET_DEVICE_OP(dev_ops, alloc_fmr);
SET_DEVICE_OP(dev_ops, alloc_hw_stats);
SET_DEVICE_OP(dev_ops, alloc_mr);
+ SET_DEVICE_OP(dev_ops, alloc_mr_integrity);
SET_DEVICE_OP(dev_ops, alloc_mw);
SET_DEVICE_OP(dev_ops, alloc_pd);
SET_DEVICE_OP(dev_ops, alloc_rdma_netdev);
@@ -2357,6 +2480,11 @@ void ib_set_device_ops(struct ib_device *dev, const struct ib_device_ops *ops)
SET_DEVICE_OP(dev_ops, alloc_xrcd);
SET_DEVICE_OP(dev_ops, attach_mcast);
SET_DEVICE_OP(dev_ops, check_mr_status);
+ SET_DEVICE_OP(dev_ops, counter_alloc_stats);
+ SET_DEVICE_OP(dev_ops, counter_bind_qp);
+ SET_DEVICE_OP(dev_ops, counter_dealloc);
+ SET_DEVICE_OP(dev_ops, counter_unbind_qp);
+ SET_DEVICE_OP(dev_ops, counter_update_stats);
SET_DEVICE_OP(dev_ops, create_ah);
SET_DEVICE_OP(dev_ops, create_counters);
SET_DEVICE_OP(dev_ops, create_cq);
@@ -2409,6 +2537,7 @@ void ib_set_device_ops(struct ib_device *dev, const struct ib_device_ops *ops)
SET_DEVICE_OP(dev_ops, iw_reject);
SET_DEVICE_OP(dev_ops, iw_rem_ref);
SET_DEVICE_OP(dev_ops, map_mr_sg);
+ SET_DEVICE_OP(dev_ops, map_mr_sg_pi);
SET_DEVICE_OP(dev_ops, map_phys_fmr);
SET_DEVICE_OP(dev_ops, mmap);
SET_DEVICE_OP(dev_ops, modify_ah);
@@ -2445,6 +2574,7 @@ void ib_set_device_ops(struct ib_device *dev, const struct ib_device_ops *ops)
SET_DEVICE_OP(dev_ops, unmap_fmr);
SET_OBJ_SIZE(dev_ops, ib_ah);
+ SET_OBJ_SIZE(dev_ops, ib_cq);
SET_OBJ_SIZE(dev_ops, ib_pd);
SET_OBJ_SIZE(dev_ops, ib_srq);
SET_OBJ_SIZE(dev_ops, ib_ucontext);
@@ -2520,7 +2650,7 @@ static int __init ib_core_init(void)
goto err_mad;
}
- ret = register_lsm_notifier(&ibdev_lsm_nb);
+ ret = register_blocking_lsm_notifier(&ibdev_lsm_nb);
if (ret) {
pr_warn("Couldn't register LSM notifier. ret %d\n", ret);
goto err_sa;
@@ -2539,7 +2669,7 @@ static int __init ib_core_init(void)
return 0;
err_compat:
- unregister_lsm_notifier(&ibdev_lsm_nb);
+ unregister_blocking_lsm_notifier(&ibdev_lsm_nb);
err_sa:
ib_sa_cleanup();
err_mad:
@@ -2565,7 +2695,7 @@ static void __exit ib_core_cleanup(void)
nldev_exit();
rdma_nl_unregister(RDMA_NL_LS);
unregister_pernet_device(&rdma_dev_net_ops);
- unregister_lsm_notifier(&ibdev_lsm_nb);
+ unregister_blocking_lsm_notifier(&ibdev_lsm_nb);
ib_sa_cleanup();
ib_mad_cleanup();
addr_cleanup();
diff --git a/drivers/infiniband/core/mr_pool.c b/drivers/infiniband/core/mr_pool.c
index d117f21ce9fd..c0e2df128b34 100644
--- a/drivers/infiniband/core/mr_pool.c
+++ b/drivers/infiniband/core/mr_pool.c
@@ -34,14 +34,18 @@ void ib_mr_pool_put(struct ib_qp *qp, struct list_head *list, struct ib_mr *mr)
EXPORT_SYMBOL(ib_mr_pool_put);
int ib_mr_pool_init(struct ib_qp *qp, struct list_head *list, int nr,
- enum ib_mr_type type, u32 max_num_sg)
+ enum ib_mr_type type, u32 max_num_sg, u32 max_num_meta_sg)
{
struct ib_mr *mr;
unsigned long flags;
int ret, i;
for (i = 0; i < nr; i++) {
- mr = ib_alloc_mr(qp->pd, type, max_num_sg);
+ if (type == IB_MR_TYPE_INTEGRITY)
+ mr = ib_alloc_mr_integrity(qp->pd, max_num_sg,
+ max_num_meta_sg);
+ else
+ mr = ib_alloc_mr(qp->pd, type, max_num_sg);
if (IS_ERR(mr)) {
ret = PTR_ERR(mr);
goto out;
diff --git a/drivers/infiniband/core/nldev.c b/drivers/infiniband/core/nldev.c
index 69188cbbd99b..783e465e7c41 100644
--- a/drivers/infiniband/core/nldev.c
+++ b/drivers/infiniband/core/nldev.c
@@ -42,84 +42,105 @@
#include "cma_priv.h"
#include "restrack.h"
+/*
+ * Sort array elements by the netlink attribute name
+ */
static const struct nla_policy nldev_policy[RDMA_NLDEV_ATTR_MAX] = {
- [RDMA_NLDEV_ATTR_DEV_INDEX] = { .type = NLA_U32 },
- [RDMA_NLDEV_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING,
- .len = IB_DEVICE_NAME_MAX - 1},
- [RDMA_NLDEV_ATTR_PORT_INDEX] = { .type = NLA_U32 },
- [RDMA_NLDEV_ATTR_FW_VERSION] = { .type = NLA_NUL_STRING,
- .len = IB_FW_VERSION_NAME_MAX - 1},
- [RDMA_NLDEV_ATTR_NODE_GUID] = { .type = NLA_U64 },
- [RDMA_NLDEV_ATTR_SYS_IMAGE_GUID] = { .type = NLA_U64 },
- [RDMA_NLDEV_ATTR_SUBNET_PREFIX] = { .type = NLA_U64 },
- [RDMA_NLDEV_ATTR_LID] = { .type = NLA_U32 },
- [RDMA_NLDEV_ATTR_SM_LID] = { .type = NLA_U32 },
- [RDMA_NLDEV_ATTR_LMC] = { .type = NLA_U8 },
- [RDMA_NLDEV_ATTR_PORT_STATE] = { .type = NLA_U8 },
- [RDMA_NLDEV_ATTR_PORT_PHYS_STATE] = { .type = NLA_U8 },
- [RDMA_NLDEV_ATTR_DEV_NODE_TYPE] = { .type = NLA_U8 },
- [RDMA_NLDEV_ATTR_RES_SUMMARY] = { .type = NLA_NESTED },
- [RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY] = { .type = NLA_NESTED },
- [RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME] = { .type = NLA_NUL_STRING,
- .len = 16 },
- [RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR] = { .type = NLA_U64 },
- [RDMA_NLDEV_ATTR_RES_QP] = { .type = NLA_NESTED },
- [RDMA_NLDEV_ATTR_RES_QP_ENTRY] = { .type = NLA_NESTED },
- [RDMA_NLDEV_ATTR_RES_LQPN] = { .type = NLA_U32 },
- [RDMA_NLDEV_ATTR_RES_RQPN] = { .type = NLA_U32 },
- [RDMA_NLDEV_ATTR_RES_RQ_PSN] = { .type = NLA_U32 },
- [RDMA_NLDEV_ATTR_RES_SQ_PSN] = { .type = NLA_U32 },
- [RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE] = { .type = NLA_U8 },
- [RDMA_NLDEV_ATTR_RES_TYPE] = { .type = NLA_U8 },
- [RDMA_NLDEV_ATTR_RES_STATE] = { .type = NLA_U8 },
- [RDMA_NLDEV_ATTR_RES_PID] = { .type = NLA_U32 },
- [RDMA_NLDEV_ATTR_RES_KERN_NAME] = { .type = NLA_NUL_STRING,
- .len = TASK_COMM_LEN },
+ [RDMA_NLDEV_ATTR_CHARDEV] = { .type = NLA_U64 },
+ [RDMA_NLDEV_ATTR_CHARDEV_ABI] = { .type = NLA_U64 },
+ [RDMA_NLDEV_ATTR_CHARDEV_NAME] = { .type = NLA_NUL_STRING,
+ .len = RDMA_NLDEV_ATTR_EMPTY_STRING },
+ [RDMA_NLDEV_ATTR_CHARDEV_TYPE] = { .type = NLA_NUL_STRING,
+ .len = RDMA_NLDEV_ATTR_CHARDEV_TYPE_SIZE },
+ [RDMA_NLDEV_ATTR_DEV_DIM] = { .type = NLA_U8 },
+ [RDMA_NLDEV_ATTR_DEV_INDEX] = { .type = NLA_U32 },
+ [RDMA_NLDEV_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING,
+ .len = IB_DEVICE_NAME_MAX },
+ [RDMA_NLDEV_ATTR_DEV_NODE_TYPE] = { .type = NLA_U8 },
+ [RDMA_NLDEV_ATTR_DEV_PROTOCOL] = { .type = NLA_NUL_STRING,
+ .len = RDMA_NLDEV_ATTR_EMPTY_STRING },
+ [RDMA_NLDEV_ATTR_DRIVER] = { .type = NLA_NESTED },
+ [RDMA_NLDEV_ATTR_DRIVER_ENTRY] = { .type = NLA_NESTED },
+ [RDMA_NLDEV_ATTR_DRIVER_PRINT_TYPE] = { .type = NLA_U8 },
+ [RDMA_NLDEV_ATTR_DRIVER_STRING] = { .type = NLA_NUL_STRING,
+ .len = RDMA_NLDEV_ATTR_EMPTY_STRING },
+ [RDMA_NLDEV_ATTR_DRIVER_S32] = { .type = NLA_S32 },
+ [RDMA_NLDEV_ATTR_DRIVER_S64] = { .type = NLA_S64 },
+ [RDMA_NLDEV_ATTR_DRIVER_U32] = { .type = NLA_U32 },
+ [RDMA_NLDEV_ATTR_DRIVER_U64] = { .type = NLA_U64 },
+ [RDMA_NLDEV_ATTR_FW_VERSION] = { .type = NLA_NUL_STRING,
+ .len = RDMA_NLDEV_ATTR_EMPTY_STRING },
+ [RDMA_NLDEV_ATTR_LID] = { .type = NLA_U32 },
+ [RDMA_NLDEV_ATTR_LINK_TYPE] = { .type = NLA_NUL_STRING,
+ .len = IFNAMSIZ },
+ [RDMA_NLDEV_ATTR_LMC] = { .type = NLA_U8 },
+ [RDMA_NLDEV_ATTR_NDEV_INDEX] = { .type = NLA_U32 },
+ [RDMA_NLDEV_ATTR_NDEV_NAME] = { .type = NLA_NUL_STRING,
+ .len = IFNAMSIZ },
+ [RDMA_NLDEV_ATTR_NODE_GUID] = { .type = NLA_U64 },
+ [RDMA_NLDEV_ATTR_PORT_INDEX] = { .type = NLA_U32 },
+ [RDMA_NLDEV_ATTR_PORT_PHYS_STATE] = { .type = NLA_U8 },
+ [RDMA_NLDEV_ATTR_PORT_STATE] = { .type = NLA_U8 },
[RDMA_NLDEV_ATTR_RES_CM_ID] = { .type = NLA_NESTED },
+ [RDMA_NLDEV_ATTR_RES_CM_IDN] = { .type = NLA_U32 },
[RDMA_NLDEV_ATTR_RES_CM_ID_ENTRY] = { .type = NLA_NESTED },
- [RDMA_NLDEV_ATTR_RES_PS] = { .type = NLA_U32 },
- [RDMA_NLDEV_ATTR_RES_SRC_ADDR] = {
- .len = sizeof(struct __kernel_sockaddr_storage) },
- [RDMA_NLDEV_ATTR_RES_DST_ADDR] = {
- .len = sizeof(struct __kernel_sockaddr_storage) },
[RDMA_NLDEV_ATTR_RES_CQ] = { .type = NLA_NESTED },
- [RDMA_NLDEV_ATTR_RES_CQ_ENTRY] = { .type = NLA_NESTED },
[RDMA_NLDEV_ATTR_RES_CQE] = { .type = NLA_U32 },
- [RDMA_NLDEV_ATTR_RES_USECNT] = { .type = NLA_U64 },
- [RDMA_NLDEV_ATTR_RES_POLL_CTX] = { .type = NLA_U8 },
- [RDMA_NLDEV_ATTR_RES_MR] = { .type = NLA_NESTED },
- [RDMA_NLDEV_ATTR_RES_MR_ENTRY] = { .type = NLA_NESTED },
- [RDMA_NLDEV_ATTR_RES_RKEY] = { .type = NLA_U32 },
- [RDMA_NLDEV_ATTR_RES_LKEY] = { .type = NLA_U32 },
+ [RDMA_NLDEV_ATTR_RES_CQN] = { .type = NLA_U32 },
+ [RDMA_NLDEV_ATTR_RES_CQ_ENTRY] = { .type = NLA_NESTED },
+ [RDMA_NLDEV_ATTR_RES_CTXN] = { .type = NLA_U32 },
+ [RDMA_NLDEV_ATTR_RES_DST_ADDR] = {
+ .len = sizeof(struct __kernel_sockaddr_storage) },
[RDMA_NLDEV_ATTR_RES_IOVA] = { .type = NLA_U64 },
+ [RDMA_NLDEV_ATTR_RES_KERN_NAME] = { .type = NLA_NUL_STRING,
+ .len = RDMA_NLDEV_ATTR_EMPTY_STRING },
+ [RDMA_NLDEV_ATTR_RES_LKEY] = { .type = NLA_U32 },
+ [RDMA_NLDEV_ATTR_RES_LOCAL_DMA_LKEY] = { .type = NLA_U32 },
+ [RDMA_NLDEV_ATTR_RES_LQPN] = { .type = NLA_U32 },
+ [RDMA_NLDEV_ATTR_RES_MR] = { .type = NLA_NESTED },
[RDMA_NLDEV_ATTR_RES_MRLEN] = { .type = NLA_U64 },
+ [RDMA_NLDEV_ATTR_RES_MRN] = { .type = NLA_U32 },
+ [RDMA_NLDEV_ATTR_RES_MR_ENTRY] = { .type = NLA_NESTED },
+ [RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE] = { .type = NLA_U8 },
[RDMA_NLDEV_ATTR_RES_PD] = { .type = NLA_NESTED },
- [RDMA_NLDEV_ATTR_RES_PD_ENTRY] = { .type = NLA_NESTED },
- [RDMA_NLDEV_ATTR_RES_LOCAL_DMA_LKEY] = { .type = NLA_U32 },
- [RDMA_NLDEV_ATTR_RES_UNSAFE_GLOBAL_RKEY] = { .type = NLA_U32 },
- [RDMA_NLDEV_ATTR_NDEV_INDEX] = { .type = NLA_U32 },
- [RDMA_NLDEV_ATTR_NDEV_NAME] = { .type = NLA_NUL_STRING,
- .len = IFNAMSIZ },
- [RDMA_NLDEV_ATTR_DRIVER] = { .type = NLA_NESTED },
- [RDMA_NLDEV_ATTR_DRIVER_ENTRY] = { .type = NLA_NESTED },
- [RDMA_NLDEV_ATTR_DRIVER_STRING] = { .type = NLA_NUL_STRING,
- .len = RDMA_NLDEV_ATTR_ENTRY_STRLEN },
- [RDMA_NLDEV_ATTR_DRIVER_PRINT_TYPE] = { .type = NLA_U8 },
- [RDMA_NLDEV_ATTR_DRIVER_S32] = { .type = NLA_S32 },
- [RDMA_NLDEV_ATTR_DRIVER_U32] = { .type = NLA_U32 },
- [RDMA_NLDEV_ATTR_DRIVER_S64] = { .type = NLA_S64 },
- [RDMA_NLDEV_ATTR_DRIVER_U64] = { .type = NLA_U64 },
[RDMA_NLDEV_ATTR_RES_PDN] = { .type = NLA_U32 },
- [RDMA_NLDEV_ATTR_RES_CQN] = { .type = NLA_U32 },
- [RDMA_NLDEV_ATTR_RES_MRN] = { .type = NLA_U32 },
- [RDMA_NLDEV_ATTR_RES_CM_IDN] = { .type = NLA_U32 },
- [RDMA_NLDEV_ATTR_RES_CTXN] = { .type = NLA_U32 },
- [RDMA_NLDEV_ATTR_LINK_TYPE] = { .type = NLA_NUL_STRING,
- .len = RDMA_NLDEV_ATTR_ENTRY_STRLEN },
- [RDMA_NLDEV_SYS_ATTR_NETNS_MODE] = { .type = NLA_U8 },
- [RDMA_NLDEV_ATTR_DEV_PROTOCOL] = { .type = NLA_NUL_STRING,
- .len = RDMA_NLDEV_ATTR_ENTRY_STRLEN },
+ [RDMA_NLDEV_ATTR_RES_PD_ENTRY] = { .type = NLA_NESTED },
+ [RDMA_NLDEV_ATTR_RES_PID] = { .type = NLA_U32 },
+ [RDMA_NLDEV_ATTR_RES_POLL_CTX] = { .type = NLA_U8 },
+ [RDMA_NLDEV_ATTR_RES_PS] = { .type = NLA_U32 },
+ [RDMA_NLDEV_ATTR_RES_QP] = { .type = NLA_NESTED },
+ [RDMA_NLDEV_ATTR_RES_QP_ENTRY] = { .type = NLA_NESTED },
+ [RDMA_NLDEV_ATTR_RES_RKEY] = { .type = NLA_U32 },
+ [RDMA_NLDEV_ATTR_RES_RQPN] = { .type = NLA_U32 },
+ [RDMA_NLDEV_ATTR_RES_RQ_PSN] = { .type = NLA_U32 },
+ [RDMA_NLDEV_ATTR_RES_SQ_PSN] = { .type = NLA_U32 },
+ [RDMA_NLDEV_ATTR_RES_SRC_ADDR] = {
+ .len = sizeof(struct __kernel_sockaddr_storage) },
+ [RDMA_NLDEV_ATTR_RES_STATE] = { .type = NLA_U8 },
+ [RDMA_NLDEV_ATTR_RES_SUMMARY] = { .type = NLA_NESTED },
+ [RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY] = { .type = NLA_NESTED },
+ [RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR]= { .type = NLA_U64 },
+ [RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME]= { .type = NLA_NUL_STRING,
+ .len = RDMA_NLDEV_ATTR_EMPTY_STRING },
+ [RDMA_NLDEV_ATTR_RES_TYPE] = { .type = NLA_U8 },
+ [RDMA_NLDEV_ATTR_RES_UNSAFE_GLOBAL_RKEY]= { .type = NLA_U32 },
+ [RDMA_NLDEV_ATTR_RES_USECNT] = { .type = NLA_U64 },
+ [RDMA_NLDEV_ATTR_SM_LID] = { .type = NLA_U32 },
+ [RDMA_NLDEV_ATTR_SUBNET_PREFIX] = { .type = NLA_U64 },
+ [RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK] = { .type = NLA_U32 },
+ [RDMA_NLDEV_ATTR_STAT_MODE] = { .type = NLA_U32 },
+ [RDMA_NLDEV_ATTR_STAT_RES] = { .type = NLA_U32 },
+ [RDMA_NLDEV_ATTR_STAT_COUNTER] = { .type = NLA_NESTED },
+ [RDMA_NLDEV_ATTR_STAT_COUNTER_ENTRY] = { .type = NLA_NESTED },
+ [RDMA_NLDEV_ATTR_STAT_COUNTER_ID] = { .type = NLA_U32 },
+ [RDMA_NLDEV_ATTR_STAT_HWCOUNTERS] = { .type = NLA_NESTED },
+ [RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY] = { .type = NLA_NESTED },
+ [RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_NAME] = { .type = NLA_NUL_STRING },
+ [RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_VALUE] = { .type = NLA_U64 },
+ [RDMA_NLDEV_ATTR_SYS_IMAGE_GUID] = { .type = NLA_U64 },
+ [RDMA_NLDEV_ATTR_UVERBS_DRIVER_ID] = { .type = NLA_U32 },
[RDMA_NLDEV_NET_NS_FD] = { .type = NLA_U32 },
+ [RDMA_NLDEV_SYS_ATTR_NETNS_MODE] = { .type = NLA_U8 },
};
static int put_driver_name_print_type(struct sk_buff *msg, const char *name,
@@ -232,6 +253,8 @@ static int fill_dev_info(struct sk_buff *msg, struct ib_device *device)
return -EMSGSIZE;
if (nla_put_u8(msg, RDMA_NLDEV_ATTR_DEV_NODE_TYPE, device->node_type))
return -EMSGSIZE;
+ if (nla_put_u8(msg, RDMA_NLDEV_ATTR_DEV_DIM, device->use_cq_dim))
+ return -EMSGSIZE;
/*
* Link type is determined on first port and mlx4 device
@@ -532,6 +555,9 @@ static int fill_res_cq_entry(struct sk_buff *msg, bool has_cap_net_admin,
nla_put_u8(msg, RDMA_NLDEV_ATTR_RES_POLL_CTX, cq->poll_ctx))
goto err;
+ if (nla_put_u8(msg, RDMA_NLDEV_ATTR_DEV_DIM, (cq->dim != NULL)))
+ goto err;
+
if (nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_CQN, res->id))
goto err;
if (!rdma_is_kernel_res(res) &&
@@ -623,6 +649,152 @@ static int fill_res_pd_entry(struct sk_buff *msg, bool has_cap_net_admin,
err: return -EMSGSIZE;
}
+static int fill_stat_counter_mode(struct sk_buff *msg,
+ struct rdma_counter *counter)
+{
+ struct rdma_counter_mode *m = &counter->mode;
+
+ if (nla_put_u32(msg, RDMA_NLDEV_ATTR_STAT_MODE, m->mode))
+ return -EMSGSIZE;
+
+ if (m->mode == RDMA_COUNTER_MODE_AUTO)
+ if ((m->mask & RDMA_COUNTER_MASK_QP_TYPE) &&
+ nla_put_u8(msg, RDMA_NLDEV_ATTR_RES_TYPE, m->param.qp_type))
+ return -EMSGSIZE;
+
+ return 0;
+}
+
+static int fill_stat_counter_qp_entry(struct sk_buff *msg, u32 qpn)
+{
+ struct nlattr *entry_attr;
+
+ entry_attr = nla_nest_start(msg, RDMA_NLDEV_ATTR_RES_QP_ENTRY);
+ if (!entry_attr)
+ return -EMSGSIZE;
+
+ if (nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_LQPN, qpn))
+ goto err;
+
+ nla_nest_end(msg, entry_attr);
+ return 0;
+
+err:
+ nla_nest_cancel(msg, entry_attr);
+ return -EMSGSIZE;
+}
+
+static int fill_stat_counter_qps(struct sk_buff *msg,
+ struct rdma_counter *counter)
+{
+ struct rdma_restrack_entry *res;
+ struct rdma_restrack_root *rt;
+ struct nlattr *table_attr;
+ struct ib_qp *qp = NULL;
+ unsigned long id = 0;
+ int ret = 0;
+
+ table_attr = nla_nest_start(msg, RDMA_NLDEV_ATTR_RES_QP);
+
+ rt = &counter->device->res[RDMA_RESTRACK_QP];
+ xa_lock(&rt->xa);
+ xa_for_each(&rt->xa, id, res) {
+ if (!rdma_is_visible_in_pid_ns(res))
+ continue;
+
+ qp = container_of(res, struct ib_qp, res);
+ if (qp->qp_type == IB_QPT_RAW_PACKET && !capable(CAP_NET_RAW))
+ continue;
+
+ if (!qp->counter || (qp->counter->id != counter->id))
+ continue;
+
+ ret = fill_stat_counter_qp_entry(msg, qp->qp_num);
+ if (ret)
+ goto err;
+ }
+
+ xa_unlock(&rt->xa);
+ nla_nest_end(msg, table_attr);
+ return 0;
+
+err:
+ xa_unlock(&rt->xa);
+ nla_nest_cancel(msg, table_attr);
+ return ret;
+}
+
+static int fill_stat_hwcounter_entry(struct sk_buff *msg,
+ const char *name, u64 value)
+{
+ struct nlattr *entry_attr;
+
+ entry_attr = nla_nest_start(msg, RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY);
+ if (!entry_attr)
+ return -EMSGSIZE;
+
+ if (nla_put_string(msg, RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_NAME,
+ name))
+ goto err;
+ if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_VALUE,
+ value, RDMA_NLDEV_ATTR_PAD))
+ goto err;
+
+ nla_nest_end(msg, entry_attr);
+ return 0;
+
+err:
+ nla_nest_cancel(msg, entry_attr);
+ return -EMSGSIZE;
+}
+
+static int fill_stat_counter_hwcounters(struct sk_buff *msg,
+ struct rdma_counter *counter)
+{
+ struct rdma_hw_stats *st = counter->stats;
+ struct nlattr *table_attr;
+ int i;
+
+ table_attr = nla_nest_start(msg, RDMA_NLDEV_ATTR_STAT_HWCOUNTERS);
+ if (!table_attr)
+ return -EMSGSIZE;
+
+ for (i = 0; i < st->num_counters; i++)
+ if (fill_stat_hwcounter_entry(msg, st->names[i], st->value[i]))
+ goto err;
+
+ nla_nest_end(msg, table_attr);
+ return 0;
+
+err:
+ nla_nest_cancel(msg, table_attr);
+ return -EMSGSIZE;
+}
+
+static int fill_res_counter_entry(struct sk_buff *msg, bool has_cap_net_admin,
+ struct rdma_restrack_entry *res,
+ uint32_t port)
+{
+ struct rdma_counter *counter =
+ container_of(res, struct rdma_counter, res);
+
+ if (port && port != counter->port)
+ return 0;
+
+ /* Dump it even query failed */
+ rdma_counter_query_stats(counter);
+
+ if (nla_put_u32(msg, RDMA_NLDEV_ATTR_PORT_INDEX, counter->port) ||
+ nla_put_u32(msg, RDMA_NLDEV_ATTR_STAT_COUNTER_ID, counter->id) ||
+ fill_res_name_pid(msg, &counter->res) ||
+ fill_stat_counter_mode(msg, counter) ||
+ fill_stat_counter_qps(msg, counter) ||
+ fill_stat_counter_hwcounters(msg, counter))
+ return -EMSGSIZE;
+
+ return 0;
+}
+
static int nldev_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
struct netlink_ext_ack *extack)
{
@@ -704,6 +876,14 @@ static int nldev_set_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
goto put_done;
}
+ if (tb[RDMA_NLDEV_ATTR_DEV_DIM]) {
+ u8 use_dim;
+
+ use_dim = nla_get_u8(tb[RDMA_NLDEV_ATTR_DEV_DIM]);
+ err = ib_device_set_dim(device, use_dim);
+ goto done;
+ }
+
done:
ib_device_put(device);
put_done:
@@ -990,19 +1170,15 @@ static const struct nldev_fill_res_entry fill_entries[RDMA_RESTRACK_MAX] = {
.entry = RDMA_NLDEV_ATTR_RES_PD_ENTRY,
.id = RDMA_NLDEV_ATTR_RES_PDN,
},
+ [RDMA_RESTRACK_COUNTER] = {
+ .fill_res_func = fill_res_counter_entry,
+ .nldev_cmd = RDMA_NLDEV_CMD_STAT_GET,
+ .nldev_attr = RDMA_NLDEV_ATTR_STAT_COUNTER,
+ .entry = RDMA_NLDEV_ATTR_STAT_COUNTER_ENTRY,
+ .id = RDMA_NLDEV_ATTR_STAT_COUNTER_ID,
+ },
};
-static bool is_visible_in_pid_ns(struct rdma_restrack_entry *res)
-{
- /*
- * 1. Kern resources should be visible in init name space only
- * 2. Present only resources visible in the current namespace
- */
- if (rdma_is_kernel_res(res))
- return task_active_pid_ns(current) == &init_pid_ns;
- return task_active_pid_ns(current) == task_active_pid_ns(res->task);
-}
-
static int res_get_common_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
struct netlink_ext_ack *extack,
enum rdma_restrack_type res_type)
@@ -1047,7 +1223,7 @@ static int res_get_common_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
goto err;
}
- if (!is_visible_in_pid_ns(res)) {
+ if (!rdma_is_visible_in_pid_ns(res)) {
ret = -ENOENT;
goto err_get;
}
@@ -1159,7 +1335,7 @@ static int res_get_common_dumpit(struct sk_buff *skb,
* objects.
*/
xa_for_each(&rt->xa, id, res) {
- if (!is_visible_in_pid_ns(res))
+ if (!rdma_is_visible_in_pid_ns(res))
continue;
if (idx < start || !rdma_restrack_get(res))
@@ -1237,6 +1413,7 @@ RES_GET_FUNCS(cm_id, RDMA_RESTRACK_CM_ID);
RES_GET_FUNCS(cq, RDMA_RESTRACK_CQ);
RES_GET_FUNCS(pd, RDMA_RESTRACK_PD);
RES_GET_FUNCS(mr, RDMA_RESTRACK_MR);
+RES_GET_FUNCS(counter, RDMA_RESTRACK_COUNTER);
static LIST_HEAD(link_ops);
static DECLARE_RWSEM(link_ops_rwsem);
@@ -1299,7 +1476,7 @@ static int nldev_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
nla_strlcpy(ndev_name, tb[RDMA_NLDEV_ATTR_NDEV_NAME],
sizeof(ndev_name));
- ndev = dev_get_by_name(&init_net, ndev_name);
+ ndev = dev_get_by_name(sock_net(skb->sk), ndev_name);
if (!ndev)
return -ENODEV;
@@ -1347,6 +1524,90 @@ static int nldev_dellink(struct sk_buff *skb, struct nlmsghdr *nlh,
return 0;
}
+static int nldev_get_chardev(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct netlink_ext_ack *extack)
+{
+ struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
+ char client_name[RDMA_NLDEV_ATTR_CHARDEV_TYPE_SIZE];
+ struct ib_client_nl_info data = {};
+ struct ib_device *ibdev = NULL;
+ struct sk_buff *msg;
+ u32 index;
+ int err;
+
+ err = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1, nldev_policy,
+ extack);
+ if (err || !tb[RDMA_NLDEV_ATTR_CHARDEV_TYPE])
+ return -EINVAL;
+
+ nla_strlcpy(client_name, tb[RDMA_NLDEV_ATTR_CHARDEV_TYPE],
+ sizeof(client_name));
+
+ if (tb[RDMA_NLDEV_ATTR_DEV_INDEX]) {
+ index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
+ ibdev = ib_device_get_by_index(sock_net(skb->sk), index);
+ if (!ibdev)
+ return -EINVAL;
+
+ if (tb[RDMA_NLDEV_ATTR_PORT_INDEX]) {
+ data.port = nla_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]);
+ if (!rdma_is_port_valid(ibdev, data.port)) {
+ err = -EINVAL;
+ goto out_put;
+ }
+ } else {
+ data.port = -1;
+ }
+ } else if (tb[RDMA_NLDEV_ATTR_PORT_INDEX]) {
+ return -EINVAL;
+ }
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!msg) {
+ err = -ENOMEM;
+ goto out_put;
+ }
+ nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq,
+ RDMA_NL_GET_TYPE(RDMA_NL_NLDEV,
+ RDMA_NLDEV_CMD_GET_CHARDEV),
+ 0, 0);
+
+ data.nl_msg = msg;
+ err = ib_get_client_nl_info(ibdev, client_name, &data);
+ if (err)
+ goto out_nlmsg;
+
+ err = nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_CHARDEV,
+ huge_encode_dev(data.cdev->devt),
+ RDMA_NLDEV_ATTR_PAD);
+ if (err)
+ goto out_data;
+ err = nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_CHARDEV_ABI, data.abi,
+ RDMA_NLDEV_ATTR_PAD);
+ if (err)
+ goto out_data;
+ if (nla_put_string(msg, RDMA_NLDEV_ATTR_CHARDEV_NAME,
+ dev_name(data.cdev))) {
+ err = -EMSGSIZE;
+ goto out_data;
+ }
+
+ nlmsg_end(msg, nlh);
+ put_device(data.cdev);
+ if (ibdev)
+ ib_device_put(ibdev);
+ return rdma_nl_unicast(msg, NETLINK_CB(skb).portid);
+
+out_data:
+ put_device(data.cdev);
+out_nlmsg:
+ nlmsg_free(msg);
+out_put:
+ if (ibdev)
+ ib_device_put(ibdev);
+ return err;
+}
+
static int nldev_sys_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
struct netlink_ext_ack *extack)
{
@@ -1399,11 +1660,375 @@ static int nldev_set_sys_set_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
return err;
}
+static int nldev_stat_set_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct netlink_ext_ack *extack)
+{
+ u32 index, port, mode, mask = 0, qpn, cntn = 0;
+ struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
+ struct ib_device *device;
+ struct sk_buff *msg;
+ int ret;
+
+ ret = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
+ nldev_policy, extack);
+ /* Currently only counter for QP is supported */
+ if (ret || !tb[RDMA_NLDEV_ATTR_STAT_RES] ||
+ !tb[RDMA_NLDEV_ATTR_DEV_INDEX] ||
+ !tb[RDMA_NLDEV_ATTR_PORT_INDEX] || !tb[RDMA_NLDEV_ATTR_STAT_MODE])
+ return -EINVAL;
+
+ if (nla_get_u32(tb[RDMA_NLDEV_ATTR_STAT_RES]) != RDMA_NLDEV_ATTR_RES_QP)
+ return -EINVAL;
+
+ index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
+ device = ib_device_get_by_index(sock_net(skb->sk), index);
+ if (!device)
+ return -EINVAL;
+
+ port = nla_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]);
+ if (!rdma_is_port_valid(device, port)) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!msg) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq,
+ RDMA_NL_GET_TYPE(RDMA_NL_NLDEV,
+ RDMA_NLDEV_CMD_STAT_SET),
+ 0, 0);
+
+ mode = nla_get_u32(tb[RDMA_NLDEV_ATTR_STAT_MODE]);
+ if (mode == RDMA_COUNTER_MODE_AUTO) {
+ if (tb[RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK])
+ mask = nla_get_u32(
+ tb[RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK]);
+
+ ret = rdma_counter_set_auto_mode(device, port,
+ mask ? true : false, mask);
+ if (ret)
+ goto err_msg;
+ } else {
+ qpn = nla_get_u32(tb[RDMA_NLDEV_ATTR_RES_LQPN]);
+ if (tb[RDMA_NLDEV_ATTR_STAT_COUNTER_ID]) {
+ cntn = nla_get_u32(tb[RDMA_NLDEV_ATTR_STAT_COUNTER_ID]);
+ ret = rdma_counter_bind_qpn(device, port, qpn, cntn);
+ } else {
+ ret = rdma_counter_bind_qpn_alloc(device, port,
+ qpn, &cntn);
+ }
+ if (ret)
+ goto err_msg;
+
+ if (fill_nldev_handle(msg, device) ||
+ nla_put_u32(msg, RDMA_NLDEV_ATTR_PORT_INDEX, port) ||
+ nla_put_u32(msg, RDMA_NLDEV_ATTR_STAT_COUNTER_ID, cntn) ||
+ nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_LQPN, qpn)) {
+ ret = -EMSGSIZE;
+ goto err_fill;
+ }
+ }
+
+ nlmsg_end(msg, nlh);
+ ib_device_put(device);
+ return rdma_nl_unicast(msg, NETLINK_CB(skb).portid);
+
+err_fill:
+ rdma_counter_unbind_qpn(device, port, qpn, cntn);
+err_msg:
+ nlmsg_free(msg);
+err:
+ ib_device_put(device);
+ return ret;
+}
+
+static int nldev_stat_del_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct netlink_ext_ack *extack)
+{
+ struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
+ struct ib_device *device;
+ struct sk_buff *msg;
+ u32 index, port, qpn, cntn;
+ int ret;
+
+ ret = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
+ nldev_policy, extack);
+ if (ret || !tb[RDMA_NLDEV_ATTR_STAT_RES] ||
+ !tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_PORT_INDEX] ||
+ !tb[RDMA_NLDEV_ATTR_STAT_COUNTER_ID] ||
+ !tb[RDMA_NLDEV_ATTR_RES_LQPN])
+ return -EINVAL;
+
+ if (nla_get_u32(tb[RDMA_NLDEV_ATTR_STAT_RES]) != RDMA_NLDEV_ATTR_RES_QP)
+ return -EINVAL;
+
+ index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
+ device = ib_device_get_by_index(sock_net(skb->sk), index);
+ if (!device)
+ return -EINVAL;
+
+ port = nla_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]);
+ if (!rdma_is_port_valid(device, port)) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!msg) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq,
+ RDMA_NL_GET_TYPE(RDMA_NL_NLDEV,
+ RDMA_NLDEV_CMD_STAT_SET),
+ 0, 0);
+
+ cntn = nla_get_u32(tb[RDMA_NLDEV_ATTR_STAT_COUNTER_ID]);
+ qpn = nla_get_u32(tb[RDMA_NLDEV_ATTR_RES_LQPN]);
+ ret = rdma_counter_unbind_qpn(device, port, qpn, cntn);
+ if (ret)
+ goto err_unbind;
+
+ if (fill_nldev_handle(msg, device) ||
+ nla_put_u32(msg, RDMA_NLDEV_ATTR_PORT_INDEX, port) ||
+ nla_put_u32(msg, RDMA_NLDEV_ATTR_STAT_COUNTER_ID, cntn) ||
+ nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_LQPN, qpn)) {
+ ret = -EMSGSIZE;
+ goto err_fill;
+ }
+
+ nlmsg_end(msg, nlh);
+ ib_device_put(device);
+ return rdma_nl_unicast(msg, NETLINK_CB(skb).portid);
+
+err_fill:
+ rdma_counter_bind_qpn(device, port, qpn, cntn);
+err_unbind:
+ nlmsg_free(msg);
+err:
+ ib_device_put(device);
+ return ret;
+}
+
+static int stat_get_doit_default_counter(struct sk_buff *skb,
+ struct nlmsghdr *nlh,
+ struct netlink_ext_ack *extack,
+ struct nlattr *tb[])
+{
+ struct rdma_hw_stats *stats;
+ struct nlattr *table_attr;
+ struct ib_device *device;
+ int ret, num_cnts, i;
+ struct sk_buff *msg;
+ u32 index, port;
+ u64 v;
+
+ if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_PORT_INDEX])
+ return -EINVAL;
+
+ index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
+ device = ib_device_get_by_index(sock_net(skb->sk), index);
+ if (!device)
+ return -EINVAL;
+
+ if (!device->ops.alloc_hw_stats || !device->ops.get_hw_stats) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ port = nla_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]);
+ if (!rdma_is_port_valid(device, port)) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!msg) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq,
+ RDMA_NL_GET_TYPE(RDMA_NL_NLDEV,
+ RDMA_NLDEV_CMD_STAT_GET),
+ 0, 0);
+
+ if (fill_nldev_handle(msg, device) ||
+ nla_put_u32(msg, RDMA_NLDEV_ATTR_PORT_INDEX, port)) {
+ ret = -EMSGSIZE;
+ goto err_msg;
+ }
+
+ stats = device->port_data ? device->port_data[port].hw_stats : NULL;
+ if (stats == NULL) {
+ ret = -EINVAL;
+ goto err_msg;
+ }
+ mutex_lock(&stats->lock);
+
+ num_cnts = device->ops.get_hw_stats(device, stats, port, 0);
+ if (num_cnts < 0) {
+ ret = -EINVAL;
+ goto err_stats;
+ }
+
+ table_attr = nla_nest_start(msg, RDMA_NLDEV_ATTR_STAT_HWCOUNTERS);
+ if (!table_attr) {
+ ret = -EMSGSIZE;
+ goto err_stats;
+ }
+ for (i = 0; i < num_cnts; i++) {
+ v = stats->value[i] +
+ rdma_counter_get_hwstat_value(device, port, i);
+ if (fill_stat_hwcounter_entry(msg, stats->names[i], v)) {
+ ret = -EMSGSIZE;
+ goto err_table;
+ }
+ }
+ nla_nest_end(msg, table_attr);
+
+ mutex_unlock(&stats->lock);
+ nlmsg_end(msg, nlh);
+ ib_device_put(device);
+ return rdma_nl_unicast(msg, NETLINK_CB(skb).portid);
+
+err_table:
+ nla_nest_cancel(msg, table_attr);
+err_stats:
+ mutex_unlock(&stats->lock);
+err_msg:
+ nlmsg_free(msg);
+err:
+ ib_device_put(device);
+ return ret;
+}
+
+static int stat_get_doit_qp(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct netlink_ext_ack *extack, struct nlattr *tb[])
+
+{
+ static enum rdma_nl_counter_mode mode;
+ static enum rdma_nl_counter_mask mask;
+ struct ib_device *device;
+ struct sk_buff *msg;
+ u32 index, port;
+ int ret;
+
+ if (tb[RDMA_NLDEV_ATTR_STAT_COUNTER_ID])
+ return nldev_res_get_counter_doit(skb, nlh, extack);
+
+ if (!tb[RDMA_NLDEV_ATTR_STAT_MODE] ||
+ !tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_PORT_INDEX])
+ return -EINVAL;
+
+ index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
+ device = ib_device_get_by_index(sock_net(skb->sk), index);
+ if (!device)
+ return -EINVAL;
+
+ port = nla_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]);
+ if (!rdma_is_port_valid(device, port)) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!msg) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq,
+ RDMA_NL_GET_TYPE(RDMA_NL_NLDEV,
+ RDMA_NLDEV_CMD_STAT_GET),
+ 0, 0);
+
+ ret = rdma_counter_get_mode(device, port, &mode, &mask);
+ if (ret)
+ goto err_msg;
+
+ if (fill_nldev_handle(msg, device) ||
+ nla_put_u32(msg, RDMA_NLDEV_ATTR_PORT_INDEX, port) ||
+ nla_put_u32(msg, RDMA_NLDEV_ATTR_STAT_MODE, mode))
+ goto err_msg;
+
+ if ((mode == RDMA_COUNTER_MODE_AUTO) &&
+ nla_put_u32(msg, RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK, mask))
+ goto err_msg;
+
+ nlmsg_end(msg, nlh);
+ ib_device_put(device);
+ return rdma_nl_unicast(msg, NETLINK_CB(skb).portid);
+
+err_msg:
+ nlmsg_free(msg);
+err:
+ ib_device_put(device);
+ return ret;
+}
+
+static int nldev_stat_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct netlink_ext_ack *extack)
+{
+ struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
+ int ret;
+
+ ret = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
+ nldev_policy, extack);
+ if (ret)
+ return -EINVAL;
+
+ if (!tb[RDMA_NLDEV_ATTR_STAT_RES])
+ return stat_get_doit_default_counter(skb, nlh, extack, tb);
+
+ switch (nla_get_u32(tb[RDMA_NLDEV_ATTR_STAT_RES])) {
+ case RDMA_NLDEV_ATTR_RES_QP:
+ ret = stat_get_doit_qp(skb, nlh, extack, tb);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int nldev_stat_get_dumpit(struct sk_buff *skb,
+ struct netlink_callback *cb)
+{
+ struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
+ int ret;
+
+ ret = nlmsg_parse(cb->nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
+ nldev_policy, NULL);
+ if (ret || !tb[RDMA_NLDEV_ATTR_STAT_RES])
+ return -EINVAL;
+
+ switch (nla_get_u32(tb[RDMA_NLDEV_ATTR_STAT_RES])) {
+ case RDMA_NLDEV_ATTR_RES_QP:
+ ret = nldev_res_get_counter_dumpit(skb, cb);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
static const struct rdma_nl_cbs nldev_cb_table[RDMA_NLDEV_NUM_OPS] = {
[RDMA_NLDEV_CMD_GET] = {
.doit = nldev_get_doit,
.dump = nldev_get_dumpit,
},
+ [RDMA_NLDEV_CMD_GET_CHARDEV] = {
+ .doit = nldev_get_chardev,
+ },
[RDMA_NLDEV_CMD_SET] = {
.doit = nldev_set_doit,
.flags = RDMA_NL_ADMIN_PERM,
@@ -1449,6 +2074,17 @@ static const struct rdma_nl_cbs nldev_cb_table[RDMA_NLDEV_NUM_OPS] = {
},
[RDMA_NLDEV_CMD_SYS_SET] = {
.doit = nldev_set_sys_set_doit,
+ },
+ [RDMA_NLDEV_CMD_STAT_SET] = {
+ .doit = nldev_stat_set_doit,
+ .flags = RDMA_NL_ADMIN_PERM,
+ },
+ [RDMA_NLDEV_CMD_STAT_GET] = {
+ .doit = nldev_stat_get_doit,
+ .dump = nldev_stat_get_dumpit,
+ },
+ [RDMA_NLDEV_CMD_STAT_DEL] = {
+ .doit = nldev_stat_del_doit,
.flags = RDMA_NL_ADMIN_PERM,
},
};
diff --git a/drivers/infiniband/core/restrack.c b/drivers/infiniband/core/restrack.c
index 3b5ff2f7b5f8..bddff426ee0f 100644
--- a/drivers/infiniband/core/restrack.c
+++ b/drivers/infiniband/core/restrack.c
@@ -6,6 +6,7 @@
#include <rdma/rdma_cm.h>
#include <rdma/ib_verbs.h>
#include <rdma/restrack.h>
+#include <rdma/rdma_counter.h>
#include <linux/mutex.h>
#include <linux/sched/task.h>
#include <linux/pid_namespace.h>
@@ -45,6 +46,7 @@ static const char *type2str(enum rdma_restrack_type type)
[RDMA_RESTRACK_CM_ID] = "CM_ID",
[RDMA_RESTRACK_MR] = "MR",
[RDMA_RESTRACK_CTX] = "CTX",
+ [RDMA_RESTRACK_COUNTER] = "COUNTER",
};
return names[type];
@@ -169,6 +171,8 @@ static struct ib_device *res_to_dev(struct rdma_restrack_entry *res)
return container_of(res, struct ib_mr, res)->device;
case RDMA_RESTRACK_CTX:
return container_of(res, struct ib_ucontext, res)->device;
+ case RDMA_RESTRACK_COUNTER:
+ return container_of(res, struct rdma_counter, res)->device;
default:
WARN_ONCE(true, "Wrong resource tracking type %u\n", res->type);
return NULL;
@@ -190,6 +194,20 @@ void rdma_restrack_set_task(struct rdma_restrack_entry *res,
}
EXPORT_SYMBOL(rdma_restrack_set_task);
+/**
+ * rdma_restrack_attach_task() - attach the task onto this resource
+ * @res: resource entry
+ * @task: the task to attach, the current task will be used if it is NULL.
+ */
+void rdma_restrack_attach_task(struct rdma_restrack_entry *res,
+ struct task_struct *task)
+{
+ if (res->task)
+ put_task_struct(res->task);
+ get_task_struct(task);
+ res->task = task;
+}
+
static void rdma_restrack_add(struct rdma_restrack_entry *res)
{
struct ib_device *dev = res_to_dev(res);
@@ -203,15 +221,22 @@ static void rdma_restrack_add(struct rdma_restrack_entry *res)
kref_init(&res->kref);
init_completion(&res->comp);
- if (res->type != RDMA_RESTRACK_QP)
- ret = xa_alloc_cyclic(&rt->xa, &res->id, res, xa_limit_32b,
- &rt->next_id, GFP_KERNEL);
- else {
+ if (res->type == RDMA_RESTRACK_QP) {
/* Special case to ensure that LQPN points to right QP */
struct ib_qp *qp = container_of(res, struct ib_qp, res);
ret = xa_insert(&rt->xa, qp->qp_num, res, GFP_KERNEL);
res->id = ret ? 0 : qp->qp_num;
+ } else if (res->type == RDMA_RESTRACK_COUNTER) {
+ /* Special case to ensure that cntn points to right counter */
+ struct rdma_counter *counter;
+
+ counter = container_of(res, struct rdma_counter, res);
+ ret = xa_insert(&rt->xa, counter->id, res, GFP_KERNEL);
+ res->id = ret ? 0 : counter->id;
+ } else {
+ ret = xa_alloc_cyclic(&rt->xa, &res->id, res, xa_limit_32b,
+ &rt->next_id, GFP_KERNEL);
}
if (!ret)
@@ -237,7 +262,8 @@ EXPORT_SYMBOL(rdma_restrack_kadd);
*/
void rdma_restrack_uadd(struct rdma_restrack_entry *res)
{
- if (res->type != RDMA_RESTRACK_CM_ID)
+ if ((res->type != RDMA_RESTRACK_CM_ID) &&
+ (res->type != RDMA_RESTRACK_COUNTER))
res->task = NULL;
if (!res->task)
@@ -323,3 +349,16 @@ out:
}
}
EXPORT_SYMBOL(rdma_restrack_del);
+
+bool rdma_is_visible_in_pid_ns(struct rdma_restrack_entry *res)
+{
+ /*
+ * 1. Kern resources should be visible in init
+ * namespace only
+ * 2. Present only resources visible in the current
+ * namespace
+ */
+ if (rdma_is_kernel_res(res))
+ return task_active_pid_ns(current) == &init_pid_ns;
+ return task_active_pid_ns(current) == task_active_pid_ns(res->task);
+}
diff --git a/drivers/infiniband/core/restrack.h b/drivers/infiniband/core/restrack.h
index 09a1fbdf578e..7bd177cc0a61 100644
--- a/drivers/infiniband/core/restrack.h
+++ b/drivers/infiniband/core/restrack.h
@@ -25,4 +25,7 @@ struct rdma_restrack_root {
int rdma_restrack_init(struct ib_device *dev);
void rdma_restrack_clean(struct ib_device *dev);
+void rdma_restrack_attach_task(struct rdma_restrack_entry *res,
+ struct task_struct *task);
+bool rdma_is_visible_in_pid_ns(struct rdma_restrack_entry *res);
#endif /* _RDMA_CORE_RESTRACK_H_ */
diff --git a/drivers/infiniband/core/roce_gid_mgmt.c b/drivers/infiniband/core/roce_gid_mgmt.c
index 558de0b9895c..2860def84f4d 100644
--- a/drivers/infiniband/core/roce_gid_mgmt.c
+++ b/drivers/infiniband/core/roce_gid_mgmt.c
@@ -330,6 +330,7 @@ static void bond_delete_netdev_default_gids(struct ib_device *ib_dev,
static void enum_netdev_ipv4_ips(struct ib_device *ib_dev,
u8 port, struct net_device *ndev)
{
+ const struct in_ifaddr *ifa;
struct in_device *in_dev;
struct sin_list {
struct list_head list;
@@ -349,7 +350,7 @@ static void enum_netdev_ipv4_ips(struct ib_device *ib_dev,
return;
}
- for_ifa(in_dev) {
+ in_dev_for_each_ifa_rcu(ifa, in_dev) {
struct sin_list *entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
if (!entry)
@@ -359,7 +360,7 @@ static void enum_netdev_ipv4_ips(struct ib_device *ib_dev,
entry->ip.sin_addr.s_addr = ifa->ifa_address;
list_add_tail(&entry->list, &sin_list);
}
- endfor_ifa(in_dev);
+
rcu_read_unlock();
list_for_each_entry_safe(sin_iter, sin_temp, &sin_list, list) {
diff --git a/drivers/infiniband/core/rw.c b/drivers/infiniband/core/rw.c
index 32ca8429eaae..dce06108c8c3 100644
--- a/drivers/infiniband/core/rw.c
+++ b/drivers/infiniband/core/rw.c
@@ -51,10 +51,34 @@ static inline bool rdma_rw_io_needs_mr(struct ib_device *dev, u8 port_num,
return false;
}
-static inline u32 rdma_rw_fr_page_list_len(struct ib_device *dev)
+static inline u32 rdma_rw_fr_page_list_len(struct ib_device *dev,
+ bool pi_support)
{
+ u32 max_pages;
+
+ if (pi_support)
+ max_pages = dev->attrs.max_pi_fast_reg_page_list_len;
+ else
+ max_pages = dev->attrs.max_fast_reg_page_list_len;
+
/* arbitrary limit to avoid allocating gigantic resources */
- return min_t(u32, dev->attrs.max_fast_reg_page_list_len, 256);
+ return min_t(u32, max_pages, 256);
+}
+
+static inline int rdma_rw_inv_key(struct rdma_rw_reg_ctx *reg)
+{
+ int count = 0;
+
+ if (reg->mr->need_inval) {
+ reg->inv_wr.opcode = IB_WR_LOCAL_INV;
+ reg->inv_wr.ex.invalidate_rkey = reg->mr->lkey;
+ reg->inv_wr.next = &reg->reg_wr.wr;
+ count++;
+ } else {
+ reg->inv_wr.next = NULL;
+ }
+
+ return count;
}
/* Caller must have zero-initialized *reg. */
@@ -62,7 +86,8 @@ static int rdma_rw_init_one_mr(struct ib_qp *qp, u8 port_num,
struct rdma_rw_reg_ctx *reg, struct scatterlist *sg,
u32 sg_cnt, u32 offset)
{
- u32 pages_per_mr = rdma_rw_fr_page_list_len(qp->pd->device);
+ u32 pages_per_mr = rdma_rw_fr_page_list_len(qp->pd->device,
+ qp->integrity_en);
u32 nents = min(sg_cnt, pages_per_mr);
int count = 0, ret;
@@ -70,14 +95,7 @@ static int rdma_rw_init_one_mr(struct ib_qp *qp, u8 port_num,
if (!reg->mr)
return -EAGAIN;
- if (reg->mr->need_inval) {
- reg->inv_wr.opcode = IB_WR_LOCAL_INV;
- reg->inv_wr.ex.invalidate_rkey = reg->mr->lkey;
- reg->inv_wr.next = &reg->reg_wr.wr;
- count++;
- } else {
- reg->inv_wr.next = NULL;
- }
+ count += rdma_rw_inv_key(reg);
ret = ib_map_mr_sg(reg->mr, sg, nents, &offset, PAGE_SIZE);
if (ret < 0 || ret < nents) {
@@ -102,7 +120,8 @@ static int rdma_rw_init_mr_wrs(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
u64 remote_addr, u32 rkey, enum dma_data_direction dir)
{
struct rdma_rw_reg_ctx *prev = NULL;
- u32 pages_per_mr = rdma_rw_fr_page_list_len(qp->pd->device);
+ u32 pages_per_mr = rdma_rw_fr_page_list_len(qp->pd->device,
+ qp->integrity_en);
int i, j, ret = 0, count = 0;
ctx->nr_ops = (sg_cnt + pages_per_mr - 1) / pages_per_mr;
@@ -343,13 +362,14 @@ int rdma_rw_ctx_signature_init(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
u64 remote_addr, u32 rkey, enum dma_data_direction dir)
{
struct ib_device *dev = qp->pd->device;
- u32 pages_per_mr = rdma_rw_fr_page_list_len(qp->pd->device);
+ u32 pages_per_mr = rdma_rw_fr_page_list_len(qp->pd->device,
+ qp->integrity_en);
struct ib_rdma_wr *rdma_wr;
- struct ib_send_wr *prev_wr = NULL;
int count = 0, ret;
if (sg_cnt > pages_per_mr || prot_sg_cnt > pages_per_mr) {
- pr_err("SG count too large\n");
+ pr_err("SG count too large: sg_cnt=%d, prot_sg_cnt=%d, pages_per_mr=%d\n",
+ sg_cnt, prot_sg_cnt, pages_per_mr);
return -EINVAL;
}
@@ -358,75 +378,58 @@ int rdma_rw_ctx_signature_init(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
return -ENOMEM;
sg_cnt = ret;
- ret = ib_dma_map_sg(dev, prot_sg, prot_sg_cnt, dir);
- if (!ret) {
- ret = -ENOMEM;
- goto out_unmap_sg;
+ if (prot_sg_cnt) {
+ ret = ib_dma_map_sg(dev, prot_sg, prot_sg_cnt, dir);
+ if (!ret) {
+ ret = -ENOMEM;
+ goto out_unmap_sg;
+ }
+ prot_sg_cnt = ret;
}
- prot_sg_cnt = ret;
ctx->type = RDMA_RW_SIG_MR;
ctx->nr_ops = 1;
- ctx->sig = kcalloc(1, sizeof(*ctx->sig), GFP_KERNEL);
- if (!ctx->sig) {
+ ctx->reg = kcalloc(1, sizeof(*ctx->reg), GFP_KERNEL);
+ if (!ctx->reg) {
ret = -ENOMEM;
goto out_unmap_prot_sg;
}
- ret = rdma_rw_init_one_mr(qp, port_num, &ctx->sig->data, sg, sg_cnt, 0);
- if (ret < 0)
- goto out_free_ctx;
- count += ret;
- prev_wr = &ctx->sig->data.reg_wr.wr;
-
- ret = rdma_rw_init_one_mr(qp, port_num, &ctx->sig->prot,
- prot_sg, prot_sg_cnt, 0);
- if (ret < 0)
- goto out_destroy_data_mr;
- count += ret;
-
- if (ctx->sig->prot.inv_wr.next)
- prev_wr->next = &ctx->sig->prot.inv_wr;
- else
- prev_wr->next = &ctx->sig->prot.reg_wr.wr;
- prev_wr = &ctx->sig->prot.reg_wr.wr;
-
- ctx->sig->sig_mr = ib_mr_pool_get(qp, &qp->sig_mrs);
- if (!ctx->sig->sig_mr) {
+ ctx->reg->mr = ib_mr_pool_get(qp, &qp->sig_mrs);
+ if (!ctx->reg->mr) {
ret = -EAGAIN;
- goto out_destroy_prot_mr;
+ goto out_free_ctx;
}
- if (ctx->sig->sig_mr->need_inval) {
- memset(&ctx->sig->sig_inv_wr, 0, sizeof(ctx->sig->sig_inv_wr));
+ count += rdma_rw_inv_key(ctx->reg);
- ctx->sig->sig_inv_wr.opcode = IB_WR_LOCAL_INV;
- ctx->sig->sig_inv_wr.ex.invalidate_rkey = ctx->sig->sig_mr->rkey;
+ memcpy(ctx->reg->mr->sig_attrs, sig_attrs, sizeof(struct ib_sig_attrs));
- prev_wr->next = &ctx->sig->sig_inv_wr;
- prev_wr = &ctx->sig->sig_inv_wr;
+ ret = ib_map_mr_sg_pi(ctx->reg->mr, sg, sg_cnt, NULL, prot_sg,
+ prot_sg_cnt, NULL, SZ_4K);
+ if (unlikely(ret)) {
+ pr_err("failed to map PI sg (%d)\n", sg_cnt + prot_sg_cnt);
+ goto out_destroy_sig_mr;
}
- ctx->sig->sig_wr.wr.opcode = IB_WR_REG_SIG_MR;
- ctx->sig->sig_wr.wr.wr_cqe = NULL;
- ctx->sig->sig_wr.wr.sg_list = &ctx->sig->data.sge;
- ctx->sig->sig_wr.wr.num_sge = 1;
- ctx->sig->sig_wr.access_flags = IB_ACCESS_LOCAL_WRITE;
- ctx->sig->sig_wr.sig_attrs = sig_attrs;
- ctx->sig->sig_wr.sig_mr = ctx->sig->sig_mr;
- if (prot_sg_cnt)
- ctx->sig->sig_wr.prot = &ctx->sig->prot.sge;
- prev_wr->next = &ctx->sig->sig_wr.wr;
- prev_wr = &ctx->sig->sig_wr.wr;
+ ctx->reg->reg_wr.wr.opcode = IB_WR_REG_MR_INTEGRITY;
+ ctx->reg->reg_wr.wr.wr_cqe = NULL;
+ ctx->reg->reg_wr.wr.num_sge = 0;
+ ctx->reg->reg_wr.wr.send_flags = 0;
+ ctx->reg->reg_wr.access = IB_ACCESS_LOCAL_WRITE;
+ if (rdma_protocol_iwarp(qp->device, port_num))
+ ctx->reg->reg_wr.access |= IB_ACCESS_REMOTE_WRITE;
+ ctx->reg->reg_wr.mr = ctx->reg->mr;
+ ctx->reg->reg_wr.key = ctx->reg->mr->lkey;
count++;
- ctx->sig->sig_sge.addr = 0;
- ctx->sig->sig_sge.length = ctx->sig->data.sge.length;
- if (sig_attrs->wire.sig_type != IB_SIG_TYPE_NONE)
- ctx->sig->sig_sge.length += ctx->sig->prot.sge.length;
+ ctx->reg->sge.addr = ctx->reg->mr->iova;
+ ctx->reg->sge.length = ctx->reg->mr->length;
+ if (sig_attrs->wire.sig_type == IB_SIG_TYPE_NONE)
+ ctx->reg->sge.length -= ctx->reg->mr->sig_attrs->meta_length;
- rdma_wr = &ctx->sig->data.wr;
- rdma_wr->wr.sg_list = &ctx->sig->sig_sge;
+ rdma_wr = &ctx->reg->wr;
+ rdma_wr->wr.sg_list = &ctx->reg->sge;
rdma_wr->wr.num_sge = 1;
rdma_wr->remote_addr = remote_addr;
rdma_wr->rkey = rkey;
@@ -434,21 +437,18 @@ int rdma_rw_ctx_signature_init(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
rdma_wr->wr.opcode = IB_WR_RDMA_WRITE;
else
rdma_wr->wr.opcode = IB_WR_RDMA_READ;
- prev_wr->next = &rdma_wr->wr;
- prev_wr = &rdma_wr->wr;
+ ctx->reg->reg_wr.wr.next = &rdma_wr->wr;
count++;
return count;
-out_destroy_prot_mr:
- if (prot_sg_cnt)
- ib_mr_pool_put(qp, &qp->rdma_mrs, ctx->sig->prot.mr);
-out_destroy_data_mr:
- ib_mr_pool_put(qp, &qp->rdma_mrs, ctx->sig->data.mr);
+out_destroy_sig_mr:
+ ib_mr_pool_put(qp, &qp->sig_mrs, ctx->reg->mr);
out_free_ctx:
- kfree(ctx->sig);
+ kfree(ctx->reg);
out_unmap_prot_sg:
- ib_dma_unmap_sg(dev, prot_sg, prot_sg_cnt, dir);
+ if (prot_sg_cnt)
+ ib_dma_unmap_sg(dev, prot_sg, prot_sg_cnt, dir);
out_unmap_sg:
ib_dma_unmap_sg(dev, sg, sg_cnt, dir);
return ret;
@@ -491,22 +491,8 @@ struct ib_send_wr *rdma_rw_ctx_wrs(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
switch (ctx->type) {
case RDMA_RW_SIG_MR:
- rdma_rw_update_lkey(&ctx->sig->data, true);
- if (ctx->sig->prot.mr)
- rdma_rw_update_lkey(&ctx->sig->prot, true);
-
- ctx->sig->sig_mr->need_inval = true;
- ib_update_fast_reg_key(ctx->sig->sig_mr,
- ib_inc_rkey(ctx->sig->sig_mr->lkey));
- ctx->sig->sig_sge.lkey = ctx->sig->sig_mr->lkey;
-
- if (ctx->sig->data.inv_wr.next)
- first_wr = &ctx->sig->data.inv_wr;
- else
- first_wr = &ctx->sig->data.reg_wr.wr;
- last_wr = &ctx->sig->data.wr.wr;
- break;
case RDMA_RW_MR:
+ /* fallthrough */
for (i = 0; i < ctx->nr_ops; i++) {
rdma_rw_update_lkey(&ctx->reg[i],
ctx->reg[i].wr.wr.opcode !=
@@ -605,7 +591,7 @@ EXPORT_SYMBOL(rdma_rw_ctx_destroy);
/**
* rdma_rw_ctx_destroy_signature - release all resources allocated by
- * rdma_rw_ctx_init_signature
+ * rdma_rw_ctx_signature_init
* @ctx: context to release
* @qp: queue pair to operate on
* @port_num: port num to which the connection is bound
@@ -623,16 +609,12 @@ void rdma_rw_ctx_destroy_signature(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
if (WARN_ON_ONCE(ctx->type != RDMA_RW_SIG_MR))
return;
- ib_mr_pool_put(qp, &qp->rdma_mrs, ctx->sig->data.mr);
- ib_dma_unmap_sg(qp->pd->device, sg, sg_cnt, dir);
+ ib_mr_pool_put(qp, &qp->sig_mrs, ctx->reg->mr);
+ kfree(ctx->reg);
- if (ctx->sig->prot.mr) {
- ib_mr_pool_put(qp, &qp->rdma_mrs, ctx->sig->prot.mr);
+ ib_dma_unmap_sg(qp->pd->device, sg, sg_cnt, dir);
+ if (prot_sg_cnt)
ib_dma_unmap_sg(qp->pd->device, prot_sg, prot_sg_cnt, dir);
- }
-
- ib_mr_pool_put(qp, &qp->sig_mrs, ctx->sig->sig_mr);
- kfree(ctx->sig);
}
EXPORT_SYMBOL(rdma_rw_ctx_destroy_signature);
@@ -653,7 +635,7 @@ unsigned int rdma_rw_mr_factor(struct ib_device *device, u8 port_num,
unsigned int mr_pages;
if (rdma_rw_can_use_mr(device, port_num))
- mr_pages = rdma_rw_fr_page_list_len(device);
+ mr_pages = rdma_rw_fr_page_list_len(device, false);
else
mr_pages = device->attrs.max_sge_rd;
return DIV_ROUND_UP(maxpages, mr_pages);
@@ -679,9 +661,8 @@ void rdma_rw_init_qp(struct ib_device *dev, struct ib_qp_init_attr *attr)
* we'll need two additional MRs for the registrations and the
* invalidation.
*/
- if (attr->create_flags & IB_QP_CREATE_SIGNATURE_EN)
- factor += 6; /* (inv + reg) * (data + prot + sig) */
- else if (rdma_rw_can_use_mr(dev, attr->port_num))
+ if (attr->create_flags & IB_QP_CREATE_INTEGRITY_EN ||
+ rdma_rw_can_use_mr(dev, attr->port_num))
factor += 2; /* inv + reg */
attr->cap.max_send_wr += factor * attr->cap.max_rdma_ctxs;
@@ -697,20 +678,22 @@ void rdma_rw_init_qp(struct ib_device *dev, struct ib_qp_init_attr *attr)
int rdma_rw_init_mrs(struct ib_qp *qp, struct ib_qp_init_attr *attr)
{
struct ib_device *dev = qp->pd->device;
- u32 nr_mrs = 0, nr_sig_mrs = 0;
+ u32 nr_mrs = 0, nr_sig_mrs = 0, max_num_sg = 0;
int ret = 0;
- if (attr->create_flags & IB_QP_CREATE_SIGNATURE_EN) {
+ if (attr->create_flags & IB_QP_CREATE_INTEGRITY_EN) {
nr_sig_mrs = attr->cap.max_rdma_ctxs;
- nr_mrs = attr->cap.max_rdma_ctxs * 2;
+ nr_mrs = attr->cap.max_rdma_ctxs;
+ max_num_sg = rdma_rw_fr_page_list_len(dev, true);
} else if (rdma_rw_can_use_mr(dev, attr->port_num)) {
nr_mrs = attr->cap.max_rdma_ctxs;
+ max_num_sg = rdma_rw_fr_page_list_len(dev, false);
}
if (nr_mrs) {
ret = ib_mr_pool_init(qp, &qp->rdma_mrs, nr_mrs,
IB_MR_TYPE_MEM_REG,
- rdma_rw_fr_page_list_len(dev));
+ max_num_sg, 0);
if (ret) {
pr_err("%s: failed to allocated %d MRs\n",
__func__, nr_mrs);
@@ -720,10 +703,10 @@ int rdma_rw_init_mrs(struct ib_qp *qp, struct ib_qp_init_attr *attr)
if (nr_sig_mrs) {
ret = ib_mr_pool_init(qp, &qp->sig_mrs, nr_sig_mrs,
- IB_MR_TYPE_SIGNATURE, 2);
+ IB_MR_TYPE_INTEGRITY, max_num_sg, max_num_sg);
if (ret) {
pr_err("%s: failed to allocated %d SIG MRs\n",
- __func__, nr_mrs);
+ __func__, nr_sig_mrs);
goto out_free_rdma_mrs;
}
}
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
index c78d0c9646ae..b477295a96c2 100644
--- a/drivers/infiniband/core/sysfs.c
+++ b/drivers/infiniband/core/sysfs.c
@@ -43,6 +43,7 @@
#include <rdma/ib_mad.h>
#include <rdma/ib_pma.h>
#include <rdma/ib_cache.h>
+#include <rdma/rdma_counter.h>
struct ib_port;
@@ -800,9 +801,12 @@ static int update_hw_stats(struct ib_device *dev, struct rdma_hw_stats *stats,
return 0;
}
-static ssize_t print_hw_stat(struct rdma_hw_stats *stats, int index, char *buf)
+static ssize_t print_hw_stat(struct ib_device *dev, int port_num,
+ struct rdma_hw_stats *stats, int index, char *buf)
{
- return sprintf(buf, "%llu\n", stats->value[index]);
+ u64 v = rdma_counter_get_hwstat_value(dev, port_num, index);
+
+ return sprintf(buf, "%llu\n", stats->value[index] + v);
}
static ssize_t show_hw_stats(struct kobject *kobj, struct attribute *attr,
@@ -828,7 +832,7 @@ static ssize_t show_hw_stats(struct kobject *kobj, struct attribute *attr,
ret = update_hw_stats(dev, stats, hsa->port_num, hsa->index);
if (ret)
goto unlock;
- ret = print_hw_stat(stats, hsa->index, buf);
+ ret = print_hw_stat(dev, hsa->port_num, stats, hsa->index, buf);
unlock:
mutex_unlock(&stats->lock);
@@ -999,6 +1003,8 @@ static void setup_hw_stats(struct ib_device *device, struct ib_port *port,
goto err;
port->hw_stats_ag = hsag;
port->hw_stats = stats;
+ if (device->port_data)
+ device->port_data[port_num].hw_stats = stats;
} else {
struct kobject *kobj = &device->dev.kobj;
ret = sysfs_create_group(kobj, hsag);
@@ -1289,6 +1295,8 @@ const struct attribute_group ib_dev_attr_group = {
void ib_free_port_attrs(struct ib_core_device *coredev)
{
+ struct ib_device *device = rdma_device_to_ibdev(&coredev->dev);
+ bool is_full_dev = &device->coredev == coredev;
struct kobject *p, *t;
list_for_each_entry_safe(p, t, &coredev->port_list, entry) {
@@ -1298,6 +1306,8 @@ void ib_free_port_attrs(struct ib_core_device *coredev)
if (port->hw_stats_ag)
free_hsag(&port->kobj, port->hw_stats_ag);
kfree(port->hw_stats);
+ if (device->port_data && is_full_dev)
+ device->port_data[port->port_num].hw_stats = NULL;
if (port->pma_table)
sysfs_remove_group(p, port->pma_table);
diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c
deleted file mode 100644
index 8e7da2d41fd8..000000000000
--- a/drivers/infiniband/core/ucm.c
+++ /dev/null
@@ -1,1350 +0,0 @@
-/*
- * Copyright (c) 2005 Topspin Communications. All rights reserved.
- * Copyright (c) 2005 Intel Corporation. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <linux/completion.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/poll.h>
-#include <linux/sched.h>
-#include <linux/file.h>
-#include <linux/mount.h>
-#include <linux/cdev.h>
-#include <linux/xarray.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-
-#include <linux/nospec.h>
-
-#include <linux/uaccess.h>
-
-#include <rdma/ib.h>
-#include <rdma/ib_cm.h>
-#include <rdma/ib_user_cm.h>
-#include <rdma/ib_marshall.h>
-
-#include "core_priv.h"
-
-MODULE_AUTHOR("Libor Michalek");
-MODULE_DESCRIPTION("InfiniBand userspace Connection Manager access");
-MODULE_LICENSE("Dual BSD/GPL");
-
-struct ib_ucm_device {
- int devnum;
- struct cdev cdev;
- struct device dev;
- struct ib_device *ib_dev;
-};
-
-struct ib_ucm_file {
- struct mutex file_mutex;
- struct file *filp;
- struct ib_ucm_device *device;
-
- struct list_head ctxs;
- struct list_head events;
- wait_queue_head_t poll_wait;
-};
-
-struct ib_ucm_context {
- int id;
- struct completion comp;
- atomic_t ref;
- int events_reported;
-
- struct ib_ucm_file *file;
- struct ib_cm_id *cm_id;
- __u64 uid;
-
- struct list_head events; /* list of pending events. */
- struct list_head file_list; /* member in file ctx list */
-};
-
-struct ib_ucm_event {
- struct ib_ucm_context *ctx;
- struct list_head file_list; /* member in file event list */
- struct list_head ctx_list; /* member in ctx event list */
-
- struct ib_cm_id *cm_id;
- struct ib_ucm_event_resp resp;
- void *data;
- void *info;
- int data_len;
- int info_len;
-};
-
-enum {
- IB_UCM_MAJOR = 231,
- IB_UCM_BASE_MINOR = 224,
- IB_UCM_MAX_DEVICES = RDMA_MAX_PORTS,
- IB_UCM_NUM_FIXED_MINOR = 32,
- IB_UCM_NUM_DYNAMIC_MINOR = IB_UCM_MAX_DEVICES - IB_UCM_NUM_FIXED_MINOR,
-};
-
-#define IB_UCM_BASE_DEV MKDEV(IB_UCM_MAJOR, IB_UCM_BASE_MINOR)
-static dev_t dynamic_ucm_dev;
-
-static void ib_ucm_add_one(struct ib_device *device);
-static void ib_ucm_remove_one(struct ib_device *device, void *client_data);
-
-static struct ib_client ucm_client = {
- .name = "ucm",
- .add = ib_ucm_add_one,
- .remove = ib_ucm_remove_one
-};
-
-static DEFINE_XARRAY_ALLOC(ctx_id_table);
-static DECLARE_BITMAP(dev_map, IB_UCM_MAX_DEVICES);
-
-static struct ib_ucm_context *ib_ucm_ctx_get(struct ib_ucm_file *file, int id)
-{
- struct ib_ucm_context *ctx;
-
- xa_lock(&ctx_id_table);
- ctx = xa_load(&ctx_id_table, id);
- if (!ctx)
- ctx = ERR_PTR(-ENOENT);
- else if (ctx->file != file)
- ctx = ERR_PTR(-EINVAL);
- else
- atomic_inc(&ctx->ref);
- xa_unlock(&ctx_id_table);
-
- return ctx;
-}
-
-static void ib_ucm_ctx_put(struct ib_ucm_context *ctx)
-{
- if (atomic_dec_and_test(&ctx->ref))
- complete(&ctx->comp);
-}
-
-static inline int ib_ucm_new_cm_id(int event)
-{
- return event == IB_CM_REQ_RECEIVED || event == IB_CM_SIDR_REQ_RECEIVED;
-}
-
-static void ib_ucm_cleanup_events(struct ib_ucm_context *ctx)
-{
- struct ib_ucm_event *uevent;
-
- mutex_lock(&ctx->file->file_mutex);
- list_del(&ctx->file_list);
- while (!list_empty(&ctx->events)) {
-
- uevent = list_entry(ctx->events.next,
- struct ib_ucm_event, ctx_list);
- list_del(&uevent->file_list);
- list_del(&uevent->ctx_list);
- mutex_unlock(&ctx->file->file_mutex);
-
- /* clear incoming connections. */
- if (ib_ucm_new_cm_id(uevent->resp.event))
- ib_destroy_cm_id(uevent->cm_id);
-
- kfree(uevent);
- mutex_lock(&ctx->file->file_mutex);
- }
- mutex_unlock(&ctx->file->file_mutex);
-}
-
-static struct ib_ucm_context *ib_ucm_ctx_alloc(struct ib_ucm_file *file)
-{
- struct ib_ucm_context *ctx;
-
- ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
- if (!ctx)
- return NULL;
-
- atomic_set(&ctx->ref, 1);
- init_completion(&ctx->comp);
- ctx->file = file;
- INIT_LIST_HEAD(&ctx->events);
-
- if (xa_alloc(&ctx_id_table, &ctx->id, ctx, xa_limit_32b, GFP_KERNEL))
- goto error;
-
- list_add_tail(&ctx->file_list, &file->ctxs);
- return ctx;
-
-error:
- kfree(ctx);
- return NULL;
-}
-
-static void ib_ucm_event_req_get(struct ib_ucm_req_event_resp *ureq,
- const struct ib_cm_req_event_param *kreq)
-{
- ureq->remote_ca_guid = kreq->remote_ca_guid;
- ureq->remote_qkey = kreq->remote_qkey;
- ureq->remote_qpn = kreq->remote_qpn;
- ureq->qp_type = kreq->qp_type;
- ureq->starting_psn = kreq->starting_psn;
- ureq->responder_resources = kreq->responder_resources;
- ureq->initiator_depth = kreq->initiator_depth;
- ureq->local_cm_response_timeout = kreq->local_cm_response_timeout;
- ureq->flow_control = kreq->flow_control;
- ureq->remote_cm_response_timeout = kreq->remote_cm_response_timeout;
- ureq->retry_count = kreq->retry_count;
- ureq->rnr_retry_count = kreq->rnr_retry_count;
- ureq->srq = kreq->srq;
- ureq->port = kreq->port;
-
- ib_copy_path_rec_to_user(&ureq->primary_path, kreq->primary_path);
- if (kreq->alternate_path)
- ib_copy_path_rec_to_user(&ureq->alternate_path,
- kreq->alternate_path);
-}
-
-static void ib_ucm_event_rep_get(struct ib_ucm_rep_event_resp *urep,
- const struct ib_cm_rep_event_param *krep)
-{
- urep->remote_ca_guid = krep->remote_ca_guid;
- urep->remote_qkey = krep->remote_qkey;
- urep->remote_qpn = krep->remote_qpn;
- urep->starting_psn = krep->starting_psn;
- urep->responder_resources = krep->responder_resources;
- urep->initiator_depth = krep->initiator_depth;
- urep->target_ack_delay = krep->target_ack_delay;
- urep->failover_accepted = krep->failover_accepted;
- urep->flow_control = krep->flow_control;
- urep->rnr_retry_count = krep->rnr_retry_count;
- urep->srq = krep->srq;
-}
-
-static void ib_ucm_event_sidr_rep_get(struct ib_ucm_sidr_rep_event_resp *urep,
- const struct ib_cm_sidr_rep_event_param *krep)
-{
- urep->status = krep->status;
- urep->qkey = krep->qkey;
- urep->qpn = krep->qpn;
-};
-
-static int ib_ucm_event_process(const struct ib_cm_event *evt,
- struct ib_ucm_event *uvt)
-{
- void *info = NULL;
-
- switch (evt->event) {
- case IB_CM_REQ_RECEIVED:
- ib_ucm_event_req_get(&uvt->resp.u.req_resp,
- &evt->param.req_rcvd);
- uvt->data_len = IB_CM_REQ_PRIVATE_DATA_SIZE;
- uvt->resp.present = IB_UCM_PRES_PRIMARY;
- uvt->resp.present |= (evt->param.req_rcvd.alternate_path ?
- IB_UCM_PRES_ALTERNATE : 0);
- break;
- case IB_CM_REP_RECEIVED:
- ib_ucm_event_rep_get(&uvt->resp.u.rep_resp,
- &evt->param.rep_rcvd);
- uvt->data_len = IB_CM_REP_PRIVATE_DATA_SIZE;
- break;
- case IB_CM_RTU_RECEIVED:
- uvt->data_len = IB_CM_RTU_PRIVATE_DATA_SIZE;
- uvt->resp.u.send_status = evt->param.send_status;
- break;
- case IB_CM_DREQ_RECEIVED:
- uvt->data_len = IB_CM_DREQ_PRIVATE_DATA_SIZE;
- uvt->resp.u.send_status = evt->param.send_status;
- break;
- case IB_CM_DREP_RECEIVED:
- uvt->data_len = IB_CM_DREP_PRIVATE_DATA_SIZE;
- uvt->resp.u.send_status = evt->param.send_status;
- break;
- case IB_CM_MRA_RECEIVED:
- uvt->resp.u.mra_resp.timeout =
- evt->param.mra_rcvd.service_timeout;
- uvt->data_len = IB_CM_MRA_PRIVATE_DATA_SIZE;
- break;
- case IB_CM_REJ_RECEIVED:
- uvt->resp.u.rej_resp.reason = evt->param.rej_rcvd.reason;
- uvt->data_len = IB_CM_REJ_PRIVATE_DATA_SIZE;
- uvt->info_len = evt->param.rej_rcvd.ari_length;
- info = evt->param.rej_rcvd.ari;
- break;
- case IB_CM_LAP_RECEIVED:
- ib_copy_path_rec_to_user(&uvt->resp.u.lap_resp.path,
- evt->param.lap_rcvd.alternate_path);
- uvt->data_len = IB_CM_LAP_PRIVATE_DATA_SIZE;
- uvt->resp.present = IB_UCM_PRES_ALTERNATE;
- break;
- case IB_CM_APR_RECEIVED:
- uvt->resp.u.apr_resp.status = evt->param.apr_rcvd.ap_status;
- uvt->data_len = IB_CM_APR_PRIVATE_DATA_SIZE;
- uvt->info_len = evt->param.apr_rcvd.info_len;
- info = evt->param.apr_rcvd.apr_info;
- break;
- case IB_CM_SIDR_REQ_RECEIVED:
- uvt->resp.u.sidr_req_resp.pkey =
- evt->param.sidr_req_rcvd.pkey;
- uvt->resp.u.sidr_req_resp.port =
- evt->param.sidr_req_rcvd.port;
- uvt->data_len = IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE;
- break;
- case IB_CM_SIDR_REP_RECEIVED:
- ib_ucm_event_sidr_rep_get(&uvt->resp.u.sidr_rep_resp,
- &evt->param.sidr_rep_rcvd);
- uvt->data_len = IB_CM_SIDR_REP_PRIVATE_DATA_SIZE;
- uvt->info_len = evt->param.sidr_rep_rcvd.info_len;
- info = evt->param.sidr_rep_rcvd.info;
- break;
- default:
- uvt->resp.u.send_status = evt->param.send_status;
- break;
- }
-
- if (uvt->data_len) {
- uvt->data = kmemdup(evt->private_data, uvt->data_len, GFP_KERNEL);
- if (!uvt->data)
- goto err1;
-
- uvt->resp.present |= IB_UCM_PRES_DATA;
- }
-
- if (uvt->info_len) {
- uvt->info = kmemdup(info, uvt->info_len, GFP_KERNEL);
- if (!uvt->info)
- goto err2;
-
- uvt->resp.present |= IB_UCM_PRES_INFO;
- }
- return 0;
-
-err2:
- kfree(uvt->data);
-err1:
- return -ENOMEM;
-}
-
-static int ib_ucm_event_handler(struct ib_cm_id *cm_id,
- const struct ib_cm_event *event)
-{
- struct ib_ucm_event *uevent;
- struct ib_ucm_context *ctx;
- int result = 0;
-
- ctx = cm_id->context;
-
- uevent = kzalloc(sizeof *uevent, GFP_KERNEL);
- if (!uevent)
- goto err1;
-
- uevent->ctx = ctx;
- uevent->cm_id = cm_id;
- uevent->resp.uid = ctx->uid;
- uevent->resp.id = ctx->id;
- uevent->resp.event = event->event;
-
- result = ib_ucm_event_process(event, uevent);
- if (result)
- goto err2;
-
- mutex_lock(&ctx->file->file_mutex);
- list_add_tail(&uevent->file_list, &ctx->file->events);
- list_add_tail(&uevent->ctx_list, &ctx->events);
- wake_up_interruptible(&ctx->file->poll_wait);
- mutex_unlock(&ctx->file->file_mutex);
- return 0;
-
-err2:
- kfree(uevent);
-err1:
- /* Destroy new cm_id's */
- return ib_ucm_new_cm_id(event->event);
-}
-
-static ssize_t ib_ucm_event(struct ib_ucm_file *file,
- const char __user *inbuf,
- int in_len, int out_len)
-{
- struct ib_ucm_context *ctx;
- struct ib_ucm_event_get cmd;
- struct ib_ucm_event *uevent;
- int result = 0;
-
- if (out_len < sizeof(struct ib_ucm_event_resp))
- return -ENOSPC;
-
- if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
- return -EFAULT;
-
- mutex_lock(&file->file_mutex);
- while (list_empty(&file->events)) {
- mutex_unlock(&file->file_mutex);
-
- if (file->filp->f_flags & O_NONBLOCK)
- return -EAGAIN;
-
- if (wait_event_interruptible(file->poll_wait,
- !list_empty(&file->events)))
- return -ERESTARTSYS;
-
- mutex_lock(&file->file_mutex);
- }
-
- uevent = list_entry(file->events.next, struct ib_ucm_event, file_list);
-
- if (ib_ucm_new_cm_id(uevent->resp.event)) {
- ctx = ib_ucm_ctx_alloc(file);
- if (!ctx) {
- result = -ENOMEM;
- goto done;
- }
-
- ctx->cm_id = uevent->cm_id;
- ctx->cm_id->context = ctx;
- uevent->resp.id = ctx->id;
- }
-
- if (copy_to_user(u64_to_user_ptr(cmd.response),
- &uevent->resp, sizeof(uevent->resp))) {
- result = -EFAULT;
- goto done;
- }
-
- if (uevent->data) {
- if (cmd.data_len < uevent->data_len) {
- result = -ENOMEM;
- goto done;
- }
- if (copy_to_user(u64_to_user_ptr(cmd.data),
- uevent->data, uevent->data_len)) {
- result = -EFAULT;
- goto done;
- }
- }
-
- if (uevent->info) {
- if (cmd.info_len < uevent->info_len) {
- result = -ENOMEM;
- goto done;
- }
- if (copy_to_user(u64_to_user_ptr(cmd.info),
- uevent->info, uevent->info_len)) {
- result = -EFAULT;
- goto done;
- }
- }
-
- list_del(&uevent->file_list);
- list_del(&uevent->ctx_list);
- uevent->ctx->events_reported++;
-
- kfree(uevent->data);
- kfree(uevent->info);
- kfree(uevent);
-done:
- mutex_unlock(&file->file_mutex);
- return result;
-}
-
-static ssize_t ib_ucm_create_id(struct ib_ucm_file *file,
- const char __user *inbuf,
- int in_len, int out_len)
-{
- struct ib_ucm_create_id cmd;
- struct ib_ucm_create_id_resp resp;
- struct ib_ucm_context *ctx;
- int result;
-
- if (out_len < sizeof(resp))
- return -ENOSPC;
-
- if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
- return -EFAULT;
-
- mutex_lock(&file->file_mutex);
- ctx = ib_ucm_ctx_alloc(file);
- mutex_unlock(&file->file_mutex);
- if (!ctx)
- return -ENOMEM;
-
- ctx->uid = cmd.uid;
- ctx->cm_id = ib_create_cm_id(file->device->ib_dev,
- ib_ucm_event_handler, ctx);
- if (IS_ERR(ctx->cm_id)) {
- result = PTR_ERR(ctx->cm_id);
- goto err1;
- }
-
- resp.id = ctx->id;
- if (copy_to_user(u64_to_user_ptr(cmd.response),
- &resp, sizeof(resp))) {
- result = -EFAULT;
- goto err2;
- }
- return 0;
-
-err2:
- ib_destroy_cm_id(ctx->cm_id);
-err1:
- xa_erase(&ctx_id_table, ctx->id);
- kfree(ctx);
- return result;
-}
-
-static ssize_t ib_ucm_destroy_id(struct ib_ucm_file *file,
- const char __user *inbuf,
- int in_len, int out_len)
-{
- struct ib_ucm_destroy_id cmd;
- struct ib_ucm_destroy_id_resp resp;
- struct ib_ucm_context *ctx;
- int result = 0;
-
- if (out_len < sizeof(resp))
- return -ENOSPC;
-
- if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
- return -EFAULT;
-
- xa_lock(&ctx_id_table);
- ctx = xa_load(&ctx_id_table, cmd.id);
- if (!ctx)
- ctx = ERR_PTR(-ENOENT);
- else if (ctx->file != file)
- ctx = ERR_PTR(-EINVAL);
- else
- __xa_erase(&ctx_id_table, ctx->id);
- xa_unlock(&ctx_id_table);
-
- if (IS_ERR(ctx))
- return PTR_ERR(ctx);
-
- ib_ucm_ctx_put(ctx);
- wait_for_completion(&ctx->comp);
-
- /* No new events will be generated after destroying the cm_id. */
- ib_destroy_cm_id(ctx->cm_id);
- /* Cleanup events not yet reported to the user. */
- ib_ucm_cleanup_events(ctx);
-
- resp.events_reported = ctx->events_reported;
- if (copy_to_user(u64_to_user_ptr(cmd.response),
- &resp, sizeof(resp)))
- result = -EFAULT;
-
- kfree(ctx);
- return result;
-}
-
-static ssize_t ib_ucm_attr_id(struct ib_ucm_file *file,
- const char __user *inbuf,
- int in_len, int out_len)
-{
- struct ib_ucm_attr_id_resp resp;
- struct ib_ucm_attr_id cmd;
- struct ib_ucm_context *ctx;
- int result = 0;
-
- if (out_len < sizeof(resp))
- return -ENOSPC;
-
- if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
- return -EFAULT;
-
- ctx = ib_ucm_ctx_get(file, cmd.id);
- if (IS_ERR(ctx))
- return PTR_ERR(ctx);
-
- resp.service_id = ctx->cm_id->service_id;
- resp.service_mask = ctx->cm_id->service_mask;
- resp.local_id = ctx->cm_id->local_id;
- resp.remote_id = ctx->cm_id->remote_id;
-
- if (copy_to_user(u64_to_user_ptr(cmd.response),
- &resp, sizeof(resp)))
- result = -EFAULT;
-
- ib_ucm_ctx_put(ctx);
- return result;
-}
-
-static ssize_t ib_ucm_init_qp_attr(struct ib_ucm_file *file,
- const char __user *inbuf,
- int in_len, int out_len)
-{
- struct ib_uverbs_qp_attr resp;
- struct ib_ucm_init_qp_attr cmd;
- struct ib_ucm_context *ctx;
- struct ib_qp_attr qp_attr;
- int result = 0;
-
- if (out_len < sizeof(resp))
- return -ENOSPC;
-
- if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
- return -EFAULT;
-
- ctx = ib_ucm_ctx_get(file, cmd.id);
- if (IS_ERR(ctx))
- return PTR_ERR(ctx);
-
- resp.qp_attr_mask = 0;
- memset(&qp_attr, 0, sizeof qp_attr);
- qp_attr.qp_state = cmd.qp_state;
- result = ib_cm_init_qp_attr(ctx->cm_id, &qp_attr, &resp.qp_attr_mask);
- if (result)
- goto out;
-
- ib_copy_qp_attr_to_user(ctx->cm_id->device, &resp, &qp_attr);
-
- if (copy_to_user(u64_to_user_ptr(cmd.response),
- &resp, sizeof(resp)))
- result = -EFAULT;
-
-out:
- ib_ucm_ctx_put(ctx);
- return result;
-}
-
-static int ucm_validate_listen(__be64 service_id, __be64 service_mask)
-{
- service_id &= service_mask;
-
- if (((service_id & IB_CMA_SERVICE_ID_MASK) == IB_CMA_SERVICE_ID) ||
- ((service_id & IB_SDP_SERVICE_ID_MASK) == IB_SDP_SERVICE_ID))
- return -EINVAL;
-
- return 0;
-}
-
-static ssize_t ib_ucm_listen(struct ib_ucm_file *file,
- const char __user *inbuf,
- int in_len, int out_len)
-{
- struct ib_ucm_listen cmd;
- struct ib_ucm_context *ctx;
- int result;
-
- if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
- return -EFAULT;
-
- ctx = ib_ucm_ctx_get(file, cmd.id);
- if (IS_ERR(ctx))
- return PTR_ERR(ctx);
-
- result = ucm_validate_listen(cmd.service_id, cmd.service_mask);
- if (result)
- goto out;
-
- result = ib_cm_listen(ctx->cm_id, cmd.service_id, cmd.service_mask);
-out:
- ib_ucm_ctx_put(ctx);
- return result;
-}
-
-static ssize_t ib_ucm_notify(struct ib_ucm_file *file,
- const char __user *inbuf,
- int in_len, int out_len)
-{
- struct ib_ucm_notify cmd;
- struct ib_ucm_context *ctx;
- int result;
-
- if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
- return -EFAULT;
-
- ctx = ib_ucm_ctx_get(file, cmd.id);
- if (IS_ERR(ctx))
- return PTR_ERR(ctx);
-
- result = ib_cm_notify(ctx->cm_id, (enum ib_event_type) cmd.event);
- ib_ucm_ctx_put(ctx);
- return result;
-}
-
-static int ib_ucm_alloc_data(const void **dest, u64 src, u32 len)
-{
- void *data;
-
- *dest = NULL;
-
- if (!len)
- return 0;
-
- data = memdup_user(u64_to_user_ptr(src), len);
- if (IS_ERR(data))
- return PTR_ERR(data);
-
- *dest = data;
- return 0;
-}
-
-static int ib_ucm_path_get(struct sa_path_rec **path, u64 src)
-{
- struct ib_user_path_rec upath;
- struct sa_path_rec *sa_path;
-
- *path = NULL;
-
- if (!src)
- return 0;
-
- sa_path = kmalloc(sizeof(*sa_path), GFP_KERNEL);
- if (!sa_path)
- return -ENOMEM;
-
- if (copy_from_user(&upath, u64_to_user_ptr(src),
- sizeof(upath))) {
-
- kfree(sa_path);
- return -EFAULT;
- }
-
- ib_copy_path_rec_from_user(sa_path, &upath);
- *path = sa_path;
- return 0;
-}
-
-static ssize_t ib_ucm_send_req(struct ib_ucm_file *file,
- const char __user *inbuf,
- int in_len, int out_len)
-{
- struct ib_cm_req_param param;
- struct ib_ucm_context *ctx;
- struct ib_ucm_req cmd;
- int result;
-
- param.private_data = NULL;
- param.primary_path = NULL;
- param.alternate_path = NULL;
-
- if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
- return -EFAULT;
-
- result = ib_ucm_alloc_data(&param.private_data, cmd.data, cmd.len);
- if (result)
- goto done;
-
- result = ib_ucm_path_get(&param.primary_path, cmd.primary_path);
- if (result)
- goto done;
-
- result = ib_ucm_path_get(&param.alternate_path, cmd.alternate_path);
- if (result)
- goto done;
-
- param.private_data_len = cmd.len;
- param.service_id = cmd.sid;
- param.qp_num = cmd.qpn;
- param.qp_type = cmd.qp_type;
- param.starting_psn = cmd.psn;
- param.peer_to_peer = cmd.peer_to_peer;
- param.responder_resources = cmd.responder_resources;
- param.initiator_depth = cmd.initiator_depth;
- param.remote_cm_response_timeout = cmd.remote_cm_response_timeout;
- param.flow_control = cmd.flow_control;
- param.local_cm_response_timeout = cmd.local_cm_response_timeout;
- param.retry_count = cmd.retry_count;
- param.rnr_retry_count = cmd.rnr_retry_count;
- param.max_cm_retries = cmd.max_cm_retries;
- param.srq = cmd.srq;
-
- ctx = ib_ucm_ctx_get(file, cmd.id);
- if (!IS_ERR(ctx)) {
- result = ib_send_cm_req(ctx->cm_id, &param);
- ib_ucm_ctx_put(ctx);
- } else
- result = PTR_ERR(ctx);
-
-done:
- kfree(param.private_data);
- kfree(param.primary_path);
- kfree(param.alternate_path);
- return result;
-}
-
-static ssize_t ib_ucm_send_rep(struct ib_ucm_file *file,
- const char __user *inbuf,
- int in_len, int out_len)
-{
- struct ib_cm_rep_param param;
- struct ib_ucm_context *ctx;
- struct ib_ucm_rep cmd;
- int result;
-
- param.private_data = NULL;
-
- if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
- return -EFAULT;
-
- result = ib_ucm_alloc_data(&param.private_data, cmd.data, cmd.len);
- if (result)
- return result;
-
- param.qp_num = cmd.qpn;
- param.starting_psn = cmd.psn;
- param.private_data_len = cmd.len;
- param.responder_resources = cmd.responder_resources;
- param.initiator_depth = cmd.initiator_depth;
- param.failover_accepted = cmd.failover_accepted;
- param.flow_control = cmd.flow_control;
- param.rnr_retry_count = cmd.rnr_retry_count;
- param.srq = cmd.srq;
-
- ctx = ib_ucm_ctx_get(file, cmd.id);
- if (!IS_ERR(ctx)) {
- ctx->uid = cmd.uid;
- result = ib_send_cm_rep(ctx->cm_id, &param);
- ib_ucm_ctx_put(ctx);
- } else
- result = PTR_ERR(ctx);
-
- kfree(param.private_data);
- return result;
-}
-
-static ssize_t ib_ucm_send_private_data(struct ib_ucm_file *file,
- const char __user *inbuf, int in_len,
- int (*func)(struct ib_cm_id *cm_id,
- const void *private_data,
- u8 private_data_len))
-{
- struct ib_ucm_private_data cmd;
- struct ib_ucm_context *ctx;
- const void *private_data = NULL;
- int result;
-
- if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
- return -EFAULT;
-
- result = ib_ucm_alloc_data(&private_data, cmd.data, cmd.len);
- if (result)
- return result;
-
- ctx = ib_ucm_ctx_get(file, cmd.id);
- if (!IS_ERR(ctx)) {
- result = func(ctx->cm_id, private_data, cmd.len);
- ib_ucm_ctx_put(ctx);
- } else
- result = PTR_ERR(ctx);
-
- kfree(private_data);
- return result;
-}
-
-static ssize_t ib_ucm_send_rtu(struct ib_ucm_file *file,
- const char __user *inbuf,
- int in_len, int out_len)
-{
- return ib_ucm_send_private_data(file, inbuf, in_len, ib_send_cm_rtu);
-}
-
-static ssize_t ib_ucm_send_dreq(struct ib_ucm_file *file,
- const char __user *inbuf,
- int in_len, int out_len)
-{
- return ib_ucm_send_private_data(file, inbuf, in_len, ib_send_cm_dreq);
-}
-
-static ssize_t ib_ucm_send_drep(struct ib_ucm_file *file,
- const char __user *inbuf,
- int in_len, int out_len)
-{
- return ib_ucm_send_private_data(file, inbuf, in_len, ib_send_cm_drep);
-}
-
-static ssize_t ib_ucm_send_info(struct ib_ucm_file *file,
- const char __user *inbuf, int in_len,
- int (*func)(struct ib_cm_id *cm_id,
- int status,
- const void *info,
- u8 info_len,
- const void *data,
- u8 data_len))
-{
- struct ib_ucm_context *ctx;
- struct ib_ucm_info cmd;
- const void *data = NULL;
- const void *info = NULL;
- int result;
-
- if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
- return -EFAULT;
-
- result = ib_ucm_alloc_data(&data, cmd.data, cmd.data_len);
- if (result)
- goto done;
-
- result = ib_ucm_alloc_data(&info, cmd.info, cmd.info_len);
- if (result)
- goto done;
-
- ctx = ib_ucm_ctx_get(file, cmd.id);
- if (!IS_ERR(ctx)) {
- result = func(ctx->cm_id, cmd.status, info, cmd.info_len,
- data, cmd.data_len);
- ib_ucm_ctx_put(ctx);
- } else
- result = PTR_ERR(ctx);
-
-done:
- kfree(data);
- kfree(info);
- return result;
-}
-
-static ssize_t ib_ucm_send_rej(struct ib_ucm_file *file,
- const char __user *inbuf,
- int in_len, int out_len)
-{
- return ib_ucm_send_info(file, inbuf, in_len, (void *)ib_send_cm_rej);
-}
-
-static ssize_t ib_ucm_send_apr(struct ib_ucm_file *file,
- const char __user *inbuf,
- int in_len, int out_len)
-{
- return ib_ucm_send_info(file, inbuf, in_len, (void *)ib_send_cm_apr);
-}
-
-static ssize_t ib_ucm_send_mra(struct ib_ucm_file *file,
- const char __user *inbuf,
- int in_len, int out_len)
-{
- struct ib_ucm_context *ctx;
- struct ib_ucm_mra cmd;
- const void *data = NULL;
- int result;
-
- if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
- return -EFAULT;
-
- result = ib_ucm_alloc_data(&data, cmd.data, cmd.len);
- if (result)
- return result;
-
- ctx = ib_ucm_ctx_get(file, cmd.id);
- if (!IS_ERR(ctx)) {
- result = ib_send_cm_mra(ctx->cm_id, cmd.timeout, data, cmd.len);
- ib_ucm_ctx_put(ctx);
- } else
- result = PTR_ERR(ctx);
-
- kfree(data);
- return result;
-}
-
-static ssize_t ib_ucm_send_lap(struct ib_ucm_file *file,
- const char __user *inbuf,
- int in_len, int out_len)
-{
- struct ib_ucm_context *ctx;
- struct sa_path_rec *path = NULL;
- struct ib_ucm_lap cmd;
- const void *data = NULL;
- int result;
-
- if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
- return -EFAULT;
-
- result = ib_ucm_alloc_data(&data, cmd.data, cmd.len);
- if (result)
- goto done;
-
- result = ib_ucm_path_get(&path, cmd.path);
- if (result)
- goto done;
-
- ctx = ib_ucm_ctx_get(file, cmd.id);
- if (!IS_ERR(ctx)) {
- result = ib_send_cm_lap(ctx->cm_id, path, data, cmd.len);
- ib_ucm_ctx_put(ctx);
- } else
- result = PTR_ERR(ctx);
-
-done:
- kfree(data);
- kfree(path);
- return result;
-}
-
-static ssize_t ib_ucm_send_sidr_req(struct ib_ucm_file *file,
- const char __user *inbuf,
- int in_len, int out_len)
-{
- struct ib_cm_sidr_req_param param = {};
- struct ib_ucm_context *ctx;
- struct ib_ucm_sidr_req cmd;
- int result;
-
- if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
- return -EFAULT;
-
- result = ib_ucm_alloc_data(&param.private_data, cmd.data, cmd.len);
- if (result)
- goto done;
-
- result = ib_ucm_path_get(&param.path, cmd.path);
- if (result)
- goto done;
-
- param.private_data_len = cmd.len;
- param.service_id = cmd.sid;
- param.timeout_ms = cmd.timeout;
- param.max_cm_retries = cmd.max_cm_retries;
-
- ctx = ib_ucm_ctx_get(file, cmd.id);
- if (!IS_ERR(ctx)) {
- result = ib_send_cm_sidr_req(ctx->cm_id, &param);
- ib_ucm_ctx_put(ctx);
- } else
- result = PTR_ERR(ctx);
-
-done:
- kfree(param.private_data);
- kfree(param.path);
- return result;
-}
-
-static ssize_t ib_ucm_send_sidr_rep(struct ib_ucm_file *file,
- const char __user *inbuf,
- int in_len, int out_len)
-{
- struct ib_cm_sidr_rep_param param;
- struct ib_ucm_sidr_rep cmd;
- struct ib_ucm_context *ctx;
- int result;
-
- param.info = NULL;
-
- if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
- return -EFAULT;
-
- result = ib_ucm_alloc_data(&param.private_data,
- cmd.data, cmd.data_len);
- if (result)
- goto done;
-
- result = ib_ucm_alloc_data(&param.info, cmd.info, cmd.info_len);
- if (result)
- goto done;
-
- param.qp_num = cmd.qpn;
- param.qkey = cmd.qkey;
- param.status = cmd.status;
- param.info_length = cmd.info_len;
- param.private_data_len = cmd.data_len;
-
- ctx = ib_ucm_ctx_get(file, cmd.id);
- if (!IS_ERR(ctx)) {
- result = ib_send_cm_sidr_rep(ctx->cm_id, &param);
- ib_ucm_ctx_put(ctx);
- } else
- result = PTR_ERR(ctx);
-
-done:
- kfree(param.private_data);
- kfree(param.info);
- return result;
-}
-
-static ssize_t (*ucm_cmd_table[])(struct ib_ucm_file *file,
- const char __user *inbuf,
- int in_len, int out_len) = {
- [IB_USER_CM_CMD_CREATE_ID] = ib_ucm_create_id,
- [IB_USER_CM_CMD_DESTROY_ID] = ib_ucm_destroy_id,
- [IB_USER_CM_CMD_ATTR_ID] = ib_ucm_attr_id,
- [IB_USER_CM_CMD_LISTEN] = ib_ucm_listen,
- [IB_USER_CM_CMD_NOTIFY] = ib_ucm_notify,
- [IB_USER_CM_CMD_SEND_REQ] = ib_ucm_send_req,
- [IB_USER_CM_CMD_SEND_REP] = ib_ucm_send_rep,
- [IB_USER_CM_CMD_SEND_RTU] = ib_ucm_send_rtu,
- [IB_USER_CM_CMD_SEND_DREQ] = ib_ucm_send_dreq,
- [IB_USER_CM_CMD_SEND_DREP] = ib_ucm_send_drep,
- [IB_USER_CM_CMD_SEND_REJ] = ib_ucm_send_rej,
- [IB_USER_CM_CMD_SEND_MRA] = ib_ucm_send_mra,
- [IB_USER_CM_CMD_SEND_LAP] = ib_ucm_send_lap,
- [IB_USER_CM_CMD_SEND_APR] = ib_ucm_send_apr,
- [IB_USER_CM_CMD_SEND_SIDR_REQ] = ib_ucm_send_sidr_req,
- [IB_USER_CM_CMD_SEND_SIDR_REP] = ib_ucm_send_sidr_rep,
- [IB_USER_CM_CMD_EVENT] = ib_ucm_event,
- [IB_USER_CM_CMD_INIT_QP_ATTR] = ib_ucm_init_qp_attr,
-};
-
-static ssize_t ib_ucm_write(struct file *filp, const char __user *buf,
- size_t len, loff_t *pos)
-{
- struct ib_ucm_file *file = filp->private_data;
- struct ib_ucm_cmd_hdr hdr;
- ssize_t result;
-
- if (!ib_safe_file_access(filp)) {
- pr_err_once("ucm_write: process %d (%s) changed security contexts after opening file descriptor, this is not allowed.\n",
- task_tgid_vnr(current), current->comm);
- return -EACCES;
- }
-
- if (len < sizeof(hdr))
- return -EINVAL;
-
- if (copy_from_user(&hdr, buf, sizeof(hdr)))
- return -EFAULT;
-
- if (hdr.cmd >= ARRAY_SIZE(ucm_cmd_table))
- return -EINVAL;
- hdr.cmd = array_index_nospec(hdr.cmd, ARRAY_SIZE(ucm_cmd_table));
-
- if (hdr.in + sizeof(hdr) > len)
- return -EINVAL;
-
- result = ucm_cmd_table[hdr.cmd](file, buf + sizeof(hdr),
- hdr.in, hdr.out);
- if (!result)
- result = len;
-
- return result;
-}
-
-static __poll_t ib_ucm_poll(struct file *filp,
- struct poll_table_struct *wait)
-{
- struct ib_ucm_file *file = filp->private_data;
- __poll_t mask = 0;
-
- poll_wait(filp, &file->poll_wait, wait);
-
- if (!list_empty(&file->events))
- mask = EPOLLIN | EPOLLRDNORM;
-
- return mask;
-}
-
-/*
- * ib_ucm_open() does not need the BKL:
- *
- * - no global state is referred to;
- * - there is no ioctl method to race against;
- * - no further module initialization is required for open to work
- * after the device is registered.
- */
-static int ib_ucm_open(struct inode *inode, struct file *filp)
-{
- struct ib_ucm_file *file;
-
- file = kmalloc(sizeof(*file), GFP_KERNEL);
- if (!file)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&file->events);
- INIT_LIST_HEAD(&file->ctxs);
- init_waitqueue_head(&file->poll_wait);
-
- mutex_init(&file->file_mutex);
-
- filp->private_data = file;
- file->filp = filp;
- file->device = container_of(inode->i_cdev, struct ib_ucm_device, cdev);
-
- return stream_open(inode, filp);
-}
-
-static int ib_ucm_close(struct inode *inode, struct file *filp)
-{
- struct ib_ucm_file *file = filp->private_data;
- struct ib_ucm_context *ctx;
-
- mutex_lock(&file->file_mutex);
- while (!list_empty(&file->ctxs)) {
- ctx = list_entry(file->ctxs.next,
- struct ib_ucm_context, file_list);
- mutex_unlock(&file->file_mutex);
-
- xa_erase(&ctx_id_table, ctx->id);
- ib_destroy_cm_id(ctx->cm_id);
- ib_ucm_cleanup_events(ctx);
- kfree(ctx);
-
- mutex_lock(&file->file_mutex);
- }
- mutex_unlock(&file->file_mutex);
- kfree(file);
- return 0;
-}
-
-static void ib_ucm_release_dev(struct device *dev)
-{
- struct ib_ucm_device *ucm_dev;
-
- ucm_dev = container_of(dev, struct ib_ucm_device, dev);
- kfree(ucm_dev);
-}
-
-static void ib_ucm_free_dev(struct ib_ucm_device *ucm_dev)
-{
- clear_bit(ucm_dev->devnum, dev_map);
-}
-
-static const struct file_operations ucm_fops = {
- .owner = THIS_MODULE,
- .open = ib_ucm_open,
- .release = ib_ucm_close,
- .write = ib_ucm_write,
- .poll = ib_ucm_poll,
- .llseek = no_llseek,
-};
-
-static ssize_t show_ibdev(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct ib_ucm_device *ucm_dev;
-
- ucm_dev = container_of(dev, struct ib_ucm_device, dev);
- return sprintf(buf, "%s\n", ucm_dev->ib_dev->name);
-}
-static DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL);
-
-static void ib_ucm_add_one(struct ib_device *device)
-{
- int devnum;
- dev_t base;
- struct ib_ucm_device *ucm_dev;
-
- if (!device->ops.alloc_ucontext || !rdma_cap_ib_cm(device, 1))
- return;
-
- ucm_dev = kzalloc(sizeof *ucm_dev, GFP_KERNEL);
- if (!ucm_dev)
- return;
-
- device_initialize(&ucm_dev->dev);
- ucm_dev->ib_dev = device;
- ucm_dev->dev.release = ib_ucm_release_dev;
-
- devnum = find_first_zero_bit(dev_map, IB_UCM_MAX_DEVICES);
- if (devnum >= IB_UCM_MAX_DEVICES)
- goto err;
- ucm_dev->devnum = devnum;
- set_bit(devnum, dev_map);
- if (devnum >= IB_UCM_NUM_FIXED_MINOR)
- base = dynamic_ucm_dev + devnum - IB_UCM_NUM_FIXED_MINOR;
- else
- base = IB_UCM_BASE_DEV + devnum;
-
- cdev_init(&ucm_dev->cdev, &ucm_fops);
- ucm_dev->cdev.owner = THIS_MODULE;
- kobject_set_name(&ucm_dev->cdev.kobj, "ucm%d", ucm_dev->devnum);
-
- ucm_dev->dev.class = &cm_class;
- ucm_dev->dev.parent = device->dev.parent;
- ucm_dev->dev.devt = base;
-
- dev_set_name(&ucm_dev->dev, "ucm%d", ucm_dev->devnum);
- if (cdev_device_add(&ucm_dev->cdev, &ucm_dev->dev))
- goto err_devnum;
-
- if (device_create_file(&ucm_dev->dev, &dev_attr_ibdev))
- goto err_dev;
-
- ib_set_client_data(device, &ucm_client, ucm_dev);
- return;
-
-err_dev:
- cdev_device_del(&ucm_dev->cdev, &ucm_dev->dev);
-err_devnum:
- ib_ucm_free_dev(ucm_dev);
-err:
- put_device(&ucm_dev->dev);
- return;
-}
-
-static void ib_ucm_remove_one(struct ib_device *device, void *client_data)
-{
- struct ib_ucm_device *ucm_dev = client_data;
-
- if (!ucm_dev)
- return;
-
- cdev_device_del(&ucm_dev->cdev, &ucm_dev->dev);
- ib_ucm_free_dev(ucm_dev);
- put_device(&ucm_dev->dev);
-}
-
-static CLASS_ATTR_STRING(abi_version, S_IRUGO,
- __stringify(IB_USER_CM_ABI_VERSION));
-
-static int __init ib_ucm_init(void)
-{
- int ret;
-
- ret = register_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_NUM_FIXED_MINOR,
- "infiniband_cm");
- if (ret) {
- pr_err("ucm: couldn't register device number\n");
- goto error1;
- }
-
- ret = alloc_chrdev_region(&dynamic_ucm_dev, 0, IB_UCM_NUM_DYNAMIC_MINOR,
- "infiniband_cm");
- if (ret) {
- pr_err("ucm: couldn't register dynamic device number\n");
- goto err_alloc;
- }
-
- ret = class_create_file(&cm_class, &class_attr_abi_version.attr);
- if (ret) {
- pr_err("ucm: couldn't create abi_version attribute\n");
- goto error2;
- }
-
- ret = ib_register_client(&ucm_client);
- if (ret) {
- pr_err("ucm: couldn't register client\n");
- goto error3;
- }
- return 0;
-
-error3:
- class_remove_file(&cm_class, &class_attr_abi_version.attr);
-error2:
- unregister_chrdev_region(dynamic_ucm_dev, IB_UCM_NUM_DYNAMIC_MINOR);
-err_alloc:
- unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_NUM_FIXED_MINOR);
-error1:
- return ret;
-}
-
-static void __exit ib_ucm_cleanup(void)
-{
- ib_unregister_client(&ucm_client);
- class_remove_file(&cm_class, &class_attr_abi_version.attr);
- unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_NUM_FIXED_MINOR);
- unregister_chrdev_region(dynamic_ucm_dev, IB_UCM_NUM_DYNAMIC_MINOR);
- WARN_ON(!xa_empty(&ctx_id_table));
-}
-
-module_init(ib_ucm_init);
-module_exit(ib_ucm_cleanup);
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
index 140a338a135f..0274e9b704be 100644
--- a/drivers/infiniband/core/ucma.c
+++ b/drivers/infiniband/core/ucma.c
@@ -52,6 +52,8 @@
#include <rdma/rdma_cm_ib.h>
#include <rdma/ib_addr.h>
#include <rdma/ib.h>
+#include <rdma/rdma_netlink.h>
+#include "core_priv.h"
MODULE_AUTHOR("Sean Hefty");
MODULE_DESCRIPTION("RDMA Userspace Connection Manager Access");
@@ -81,7 +83,7 @@ struct ucma_file {
};
struct ucma_context {
- int id;
+ u32 id;
struct completion comp;
atomic_t ref;
int events_reported;
@@ -94,7 +96,7 @@ struct ucma_context {
struct list_head list;
struct list_head mc_list;
/* mark that device is in process of destroying the internal HW
- * resources, protected by the global mut
+ * resources, protected by the ctx_table lock
*/
int closing;
/* sync between removal event and id destroy, protected by file mut */
@@ -104,7 +106,7 @@ struct ucma_context {
struct ucma_multicast {
struct ucma_context *ctx;
- int id;
+ u32 id;
int events_reported;
u64 uid;
@@ -122,9 +124,8 @@ struct ucma_event {
struct work_struct close_work;
};
-static DEFINE_MUTEX(mut);
-static DEFINE_IDR(ctx_idr);
-static DEFINE_IDR(multicast_idr);
+static DEFINE_XARRAY_ALLOC(ctx_table);
+static DEFINE_XARRAY_ALLOC(multicast_table);
static const struct file_operations ucma_fops;
@@ -133,7 +134,7 @@ static inline struct ucma_context *_ucma_find_context(int id,
{
struct ucma_context *ctx;
- ctx = idr_find(&ctx_idr, id);
+ ctx = xa_load(&ctx_table, id);
if (!ctx)
ctx = ERR_PTR(-ENOENT);
else if (ctx->file != file || !ctx->cm_id)
@@ -145,7 +146,7 @@ static struct ucma_context *ucma_get_ctx(struct ucma_file *file, int id)
{
struct ucma_context *ctx;
- mutex_lock(&mut);
+ xa_lock(&ctx_table);
ctx = _ucma_find_context(id, file);
if (!IS_ERR(ctx)) {
if (ctx->closing)
@@ -153,7 +154,7 @@ static struct ucma_context *ucma_get_ctx(struct ucma_file *file, int id)
else
atomic_inc(&ctx->ref);
}
- mutex_unlock(&mut);
+ xa_unlock(&ctx_table);
return ctx;
}
@@ -216,10 +217,7 @@ static struct ucma_context *ucma_alloc_ctx(struct ucma_file *file)
INIT_LIST_HEAD(&ctx->mc_list);
ctx->file = file;
- mutex_lock(&mut);
- ctx->id = idr_alloc(&ctx_idr, ctx, 0, 0, GFP_KERNEL);
- mutex_unlock(&mut);
- if (ctx->id < 0)
+ if (xa_alloc(&ctx_table, &ctx->id, ctx, xa_limit_32b, GFP_KERNEL))
goto error;
list_add_tail(&ctx->list, &file->ctx_list);
@@ -238,13 +236,10 @@ static struct ucma_multicast* ucma_alloc_multicast(struct ucma_context *ctx)
if (!mc)
return NULL;
- mutex_lock(&mut);
- mc->id = idr_alloc(&multicast_idr, NULL, 0, 0, GFP_KERNEL);
- mutex_unlock(&mut);
- if (mc->id < 0)
+ mc->ctx = ctx;
+ if (xa_alloc(&multicast_table, &mc->id, NULL, xa_limit_32b, GFP_KERNEL))
goto error;
- mc->ctx = ctx;
list_add_tail(&mc->list, &ctx->mc_list);
return mc;
@@ -319,9 +314,9 @@ static void ucma_removal_event_handler(struct rdma_cm_id *cm_id)
* handled separately below.
*/
if (ctx->cm_id == cm_id) {
- mutex_lock(&mut);
+ xa_lock(&ctx_table);
ctx->closing = 1;
- mutex_unlock(&mut);
+ xa_unlock(&ctx_table);
queue_work(ctx->file->close_wq, &ctx->close_work);
return;
}
@@ -523,9 +518,7 @@ static ssize_t ucma_create_id(struct ucma_file *file, const char __user *inbuf,
err2:
rdma_destroy_id(cm_id);
err1:
- mutex_lock(&mut);
- idr_remove(&ctx_idr, ctx->id);
- mutex_unlock(&mut);
+ xa_erase(&ctx_table, ctx->id);
mutex_lock(&file->mut);
list_del(&ctx->list);
mutex_unlock(&file->mut);
@@ -537,13 +530,13 @@ static void ucma_cleanup_multicast(struct ucma_context *ctx)
{
struct ucma_multicast *mc, *tmp;
- mutex_lock(&mut);
+ mutex_lock(&ctx->file->mut);
list_for_each_entry_safe(mc, tmp, &ctx->mc_list, list) {
list_del(&mc->list);
- idr_remove(&multicast_idr, mc->id);
+ xa_erase(&multicast_table, mc->id);
kfree(mc);
}
- mutex_unlock(&mut);
+ mutex_unlock(&ctx->file->mut);
}
static void ucma_cleanup_mc_events(struct ucma_multicast *mc)
@@ -614,11 +607,11 @@ static ssize_t ucma_destroy_id(struct ucma_file *file, const char __user *inbuf,
if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
return -EFAULT;
- mutex_lock(&mut);
+ xa_lock(&ctx_table);
ctx = _ucma_find_context(cmd.id, file);
if (!IS_ERR(ctx))
- idr_remove(&ctx_idr, ctx->id);
- mutex_unlock(&mut);
+ __xa_erase(&ctx_table, ctx->id);
+ xa_unlock(&ctx_table);
if (IS_ERR(ctx))
return PTR_ERR(ctx);
@@ -630,14 +623,14 @@ static ssize_t ucma_destroy_id(struct ucma_file *file, const char __user *inbuf,
flush_workqueue(ctx->file->close_wq);
/* At this point it's guaranteed that there is no inflight
* closing task */
- mutex_lock(&mut);
+ xa_lock(&ctx_table);
if (!ctx->closing) {
- mutex_unlock(&mut);
+ xa_unlock(&ctx_table);
ucma_put_ctx(ctx);
wait_for_completion(&ctx->comp);
rdma_destroy_id(ctx->cm_id);
} else {
- mutex_unlock(&mut);
+ xa_unlock(&ctx_table);
}
resp.events_reported = ucma_free_ctx(ctx);
@@ -951,8 +944,7 @@ static ssize_t ucma_query_path(struct ucma_context *ctx,
}
}
- if (copy_to_user(response, resp,
- sizeof(*resp) + (i * sizeof(struct ib_path_rec_data))))
+ if (copy_to_user(response, resp, struct_size(resp, path_data, i)))
ret = -EFAULT;
kfree(resp);
@@ -1432,9 +1424,7 @@ static ssize_t ucma_process_join(struct ucma_file *file,
goto err3;
}
- mutex_lock(&mut);
- idr_replace(&multicast_idr, mc, mc->id);
- mutex_unlock(&mut);
+ xa_store(&multicast_table, mc->id, mc, 0);
mutex_unlock(&file->mut);
ucma_put_ctx(ctx);
@@ -1444,9 +1434,7 @@ err3:
rdma_leave_multicast(ctx->cm_id, (struct sockaddr *) &mc->addr);
ucma_cleanup_mc_events(mc);
err2:
- mutex_lock(&mut);
- idr_remove(&multicast_idr, mc->id);
- mutex_unlock(&mut);
+ xa_erase(&multicast_table, mc->id);
list_del(&mc->list);
kfree(mc);
err1:
@@ -1508,8 +1496,8 @@ static ssize_t ucma_leave_multicast(struct ucma_file *file,
if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
return -EFAULT;
- mutex_lock(&mut);
- mc = idr_find(&multicast_idr, cmd.id);
+ xa_lock(&multicast_table);
+ mc = xa_load(&multicast_table, cmd.id);
if (!mc)
mc = ERR_PTR(-ENOENT);
else if (mc->ctx->file != file)
@@ -1517,8 +1505,8 @@ static ssize_t ucma_leave_multicast(struct ucma_file *file,
else if (!atomic_inc_not_zero(&mc->ctx->ref))
mc = ERR_PTR(-ENXIO);
else
- idr_remove(&multicast_idr, mc->id);
- mutex_unlock(&mut);
+ __xa_erase(&multicast_table, mc->id);
+ xa_unlock(&multicast_table);
if (IS_ERR(mc)) {
ret = PTR_ERR(mc);
@@ -1615,14 +1603,14 @@ static ssize_t ucma_migrate_id(struct ucma_file *new_file,
* events being added before existing events.
*/
ucma_lock_files(cur_file, new_file);
- mutex_lock(&mut);
+ xa_lock(&ctx_table);
list_move_tail(&ctx->list, &new_file->ctx_list);
ucma_move_events(ctx, new_file);
ctx->file = new_file;
resp.events_reported = ctx->events_reported;
- mutex_unlock(&mut);
+ xa_unlock(&ctx_table);
ucma_unlock_files(cur_file, new_file);
response:
@@ -1757,18 +1745,15 @@ static int ucma_close(struct inode *inode, struct file *filp)
ctx->destroying = 1;
mutex_unlock(&file->mut);
- mutex_lock(&mut);
- idr_remove(&ctx_idr, ctx->id);
- mutex_unlock(&mut);
-
+ xa_erase(&ctx_table, ctx->id);
flush_workqueue(file->close_wq);
/* At that step once ctx was marked as destroying and workqueue
* was flushed we are safe from any inflights handlers that
* might put other closing task.
*/
- mutex_lock(&mut);
+ xa_lock(&ctx_table);
if (!ctx->closing) {
- mutex_unlock(&mut);
+ xa_unlock(&ctx_table);
ucma_put_ctx(ctx);
wait_for_completion(&ctx->comp);
/* rdma_destroy_id ensures that no event handlers are
@@ -1776,7 +1761,7 @@ static int ucma_close(struct inode *inode, struct file *filp)
*/
rdma_destroy_id(ctx->cm_id);
} else {
- mutex_unlock(&mut);
+ xa_unlock(&ctx_table);
}
ucma_free_ctx(ctx);
@@ -1805,6 +1790,19 @@ static struct miscdevice ucma_misc = {
.fops = &ucma_fops,
};
+static int ucma_get_global_nl_info(struct ib_client_nl_info *res)
+{
+ res->abi = RDMA_USER_CM_ABI_VERSION;
+ res->cdev = ucma_misc.this_device;
+ return 0;
+}
+
+static struct ib_client rdma_cma_client = {
+ .name = "rdma_cm",
+ .get_global_nl_info = ucma_get_global_nl_info,
+};
+MODULE_ALIAS_RDMA_CLIENT("rdma_cm");
+
static ssize_t show_abi_version(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -1833,7 +1831,14 @@ static int __init ucma_init(void)
ret = -ENOMEM;
goto err2;
}
+
+ ret = ib_register_client(&rdma_cma_client);
+ if (ret)
+ goto err3;
+
return 0;
+err3:
+ unregister_net_sysctl_table(ucma_ctl_table_hdr);
err2:
device_remove_file(ucma_misc.this_device, &dev_attr_abi_version);
err1:
@@ -1843,11 +1848,10 @@ err1:
static void __exit ucma_cleanup(void)
{
+ ib_unregister_client(&rdma_cma_client);
unregister_net_sysctl_table(ucma_ctl_table_hdr);
device_remove_file(ucma_misc.this_device, &dev_attr_abi_version);
misc_deregister(&ucma_misc);
- idr_destroy(&ctx_idr);
- idr_destroy(&multicast_idr);
}
module_init(ucma_init);
diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c
index e7ea819fcb11..08da840ed7ee 100644
--- a/drivers/infiniband/core/umem.c
+++ b/drivers/infiniband/core/umem.c
@@ -54,9 +54,10 @@ static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int d
for_each_sg_page(umem->sg_head.sgl, &sg_iter, umem->sg_nents, 0) {
page = sg_page_iter_page(&sg_iter);
- if (!PageDirty(page) && umem->writable && dirty)
- set_page_dirty_lock(page);
- put_page(page);
+ if (umem->writable && dirty)
+ put_user_pages_dirty_lock(&page, 1);
+ else
+ put_user_page(page);
}
sg_free_table(&umem->sg_head);
@@ -244,7 +245,6 @@ struct ib_umem *ib_umem_get(struct ib_udata *udata, unsigned long addr,
umem->context = context;
umem->length = size;
umem->address = addr;
- umem->page_shift = PAGE_SHIFT;
umem->writable = ib_access_writable(access);
umem->owning_mm = mm = current->mm;
mmgrab(mm);
@@ -361,6 +361,9 @@ static void __ib_umem_release_tail(struct ib_umem *umem)
*/
void ib_umem_release(struct ib_umem *umem)
{
+ if (!umem)
+ return;
+
if (umem->is_odp) {
ib_umem_odp_release(to_ib_umem_odp(umem));
__ib_umem_release_tail(umem);
@@ -385,7 +388,7 @@ int ib_umem_page_count(struct ib_umem *umem)
n = 0;
for_each_sg(umem->sg_head.sgl, sg, umem->nmap, i)
- n += sg_dma_len(sg) >> umem->page_shift;
+ n += sg_dma_len(sg) >> PAGE_SHIFT;
return n;
}
diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c
index f962b5bbfa40..2a75c6f8d827 100644
--- a/drivers/infiniband/core/umem_odp.c
+++ b/drivers/infiniband/core/umem_odp.c
@@ -59,7 +59,7 @@ static u64 node_start(struct umem_odp_node *n)
struct ib_umem_odp *umem_odp =
container_of(n, struct ib_umem_odp, interval_tree);
- return ib_umem_start(&umem_odp->umem);
+ return ib_umem_start(umem_odp);
}
/* Note that the representation of the intervals in the interval tree
@@ -72,7 +72,7 @@ static u64 node_last(struct umem_odp_node *n)
struct ib_umem_odp *umem_odp =
container_of(n, struct ib_umem_odp, interval_tree);
- return ib_umem_end(&umem_odp->umem) - 1;
+ return ib_umem_end(umem_odp) - 1;
}
INTERVAL_TREE_DEFINE(struct umem_odp_node, rb, u64, __subtree_last,
@@ -107,8 +107,6 @@ static void ib_umem_notifier_end_account(struct ib_umem_odp *umem_odp)
static int ib_umem_notifier_release_trampoline(struct ib_umem_odp *umem_odp,
u64 start, u64 end, void *cookie)
{
- struct ib_umem *umem = &umem_odp->umem;
-
/*
* Increase the number of notifiers running, to
* prevent any further fault handling on this MR.
@@ -119,8 +117,8 @@ static int ib_umem_notifier_release_trampoline(struct ib_umem_odp *umem_odp,
* all pending page faults. */
smp_wmb();
complete_all(&umem_odp->notifier_completion);
- umem->context->invalidate_range(umem_odp, ib_umem_start(umem),
- ib_umem_end(umem));
+ umem_odp->umem.context->invalidate_range(
+ umem_odp, ib_umem_start(umem_odp), ib_umem_end(umem_odp));
return 0;
}
@@ -151,6 +149,7 @@ static int ib_umem_notifier_invalidate_range_start(struct mmu_notifier *mn,
{
struct ib_ucontext_per_mm *per_mm =
container_of(mn, struct ib_ucontext_per_mm, mn);
+ int rc;
if (mmu_notifier_range_blockable(range))
down_read(&per_mm->umem_rwsem);
@@ -167,11 +166,14 @@ static int ib_umem_notifier_invalidate_range_start(struct mmu_notifier *mn,
return 0;
}
- return rbt_ib_umem_for_each_in_range(&per_mm->umem_tree, range->start,
- range->end,
- invalidate_range_start_trampoline,
- mmu_notifier_range_blockable(range),
- NULL);
+ rc = rbt_ib_umem_for_each_in_range(&per_mm->umem_tree, range->start,
+ range->end,
+ invalidate_range_start_trampoline,
+ mmu_notifier_range_blockable(range),
+ NULL);
+ if (rc)
+ up_read(&per_mm->umem_rwsem);
+ return rc;
}
static int invalidate_range_end_trampoline(struct ib_umem_odp *item, u64 start,
@@ -205,10 +207,9 @@ static const struct mmu_notifier_ops ib_umem_notifiers = {
static void add_umem_to_per_mm(struct ib_umem_odp *umem_odp)
{
struct ib_ucontext_per_mm *per_mm = umem_odp->per_mm;
- struct ib_umem *umem = &umem_odp->umem;
down_write(&per_mm->umem_rwsem);
- if (likely(ib_umem_start(umem) != ib_umem_end(umem)))
+ if (likely(ib_umem_start(umem_odp) != ib_umem_end(umem_odp)))
rbt_ib_umem_insert(&umem_odp->interval_tree,
&per_mm->umem_tree);
up_write(&per_mm->umem_rwsem);
@@ -217,10 +218,9 @@ static void add_umem_to_per_mm(struct ib_umem_odp *umem_odp)
static void remove_umem_from_per_mm(struct ib_umem_odp *umem_odp)
{
struct ib_ucontext_per_mm *per_mm = umem_odp->per_mm;
- struct ib_umem *umem = &umem_odp->umem;
down_write(&per_mm->umem_rwsem);
- if (likely(ib_umem_start(umem) != ib_umem_end(umem)))
+ if (likely(ib_umem_start(umem_odp) != ib_umem_end(umem_odp)))
rbt_ib_umem_remove(&umem_odp->interval_tree,
&per_mm->umem_tree);
complete_all(&umem_odp->notifier_completion);
@@ -351,7 +351,7 @@ struct ib_umem_odp *ib_alloc_odp_umem(struct ib_umem_odp *root,
umem->context = ctx;
umem->length = size;
umem->address = addr;
- umem->page_shift = PAGE_SHIFT;
+ odp_data->page_shift = PAGE_SHIFT;
umem->writable = root->umem.writable;
umem->is_odp = 1;
odp_data->per_mm = per_mm;
@@ -405,18 +405,19 @@ int ib_umem_odp_get(struct ib_umem_odp *umem_odp, int access)
struct mm_struct *mm = umem->owning_mm;
int ret_val;
+ umem_odp->page_shift = PAGE_SHIFT;
if (access & IB_ACCESS_HUGETLB) {
struct vm_area_struct *vma;
struct hstate *h;
down_read(&mm->mmap_sem);
- vma = find_vma(mm, ib_umem_start(umem));
+ vma = find_vma(mm, ib_umem_start(umem_odp));
if (!vma || !is_vm_hugetlb_page(vma)) {
up_read(&mm->mmap_sem);
return -EINVAL;
}
h = hstate_vma(vma);
- umem->page_shift = huge_page_shift(h);
+ umem_odp->page_shift = huge_page_shift(h);
up_read(&mm->mmap_sem);
}
@@ -424,16 +425,16 @@ int ib_umem_odp_get(struct ib_umem_odp *umem_odp, int access)
init_completion(&umem_odp->notifier_completion);
- if (ib_umem_num_pages(umem)) {
+ if (ib_umem_odp_num_pages(umem_odp)) {
umem_odp->page_list =
vzalloc(array_size(sizeof(*umem_odp->page_list),
- ib_umem_num_pages(umem)));
+ ib_umem_odp_num_pages(umem_odp)));
if (!umem_odp->page_list)
return -ENOMEM;
umem_odp->dma_list =
vzalloc(array_size(sizeof(*umem_odp->dma_list),
- ib_umem_num_pages(umem)));
+ ib_umem_odp_num_pages(umem_odp)));
if (!umem_odp->dma_list) {
ret_val = -ENOMEM;
goto out_page_list;
@@ -456,16 +457,14 @@ out_page_list:
void ib_umem_odp_release(struct ib_umem_odp *umem_odp)
{
- struct ib_umem *umem = &umem_odp->umem;
-
/*
* Ensure that no more pages are mapped in the umem.
*
* It is the driver's responsibility to ensure, before calling us,
* that the hardware will not attempt to access the MR any more.
*/
- ib_umem_odp_unmap_dma_pages(umem_odp, ib_umem_start(umem),
- ib_umem_end(umem));
+ ib_umem_odp_unmap_dma_pages(umem_odp, ib_umem_start(umem_odp),
+ ib_umem_end(umem_odp));
remove_umem_from_per_mm(umem_odp);
put_per_mm(umem_odp);
@@ -487,7 +486,7 @@ void ib_umem_odp_release(struct ib_umem_odp *umem_odp)
* The function returns -EFAULT if the DMA mapping operation fails. It returns
* -EAGAIN if a concurrent invalidation prevents us from updating the page.
*
- * The page is released via put_page even if the operation failed. For
+ * The page is released via put_user_page even if the operation failed. For
* on-demand pinning, the page is released whenever it isn't stored in the
* umem.
*/
@@ -498,8 +497,8 @@ static int ib_umem_odp_map_dma_single_page(
u64 access_mask,
unsigned long current_seq)
{
- struct ib_umem *umem = &umem_odp->umem;
- struct ib_device *dev = umem->context->device;
+ struct ib_ucontext *context = umem_odp->umem.context;
+ struct ib_device *dev = context->device;
dma_addr_t dma_addr;
int remove_existing_mapping = 0;
int ret = 0;
@@ -514,10 +513,9 @@ static int ib_umem_odp_map_dma_single_page(
goto out;
}
if (!(umem_odp->dma_list[page_index])) {
- dma_addr = ib_dma_map_page(dev,
- page,
- 0, BIT(umem->page_shift),
- DMA_BIDIRECTIONAL);
+ dma_addr =
+ ib_dma_map_page(dev, page, 0, BIT(umem_odp->page_shift),
+ DMA_BIDIRECTIONAL);
if (ib_dma_mapping_error(dev, dma_addr)) {
ret = -EFAULT;
goto out;
@@ -536,15 +534,16 @@ static int ib_umem_odp_map_dma_single_page(
}
out:
- put_page(page);
+ put_user_page(page);
if (remove_existing_mapping) {
ib_umem_notifier_start_account(umem_odp);
- umem->context->invalidate_range(
+ context->invalidate_range(
umem_odp,
- ib_umem_start(umem) + (page_index << umem->page_shift),
- ib_umem_start(umem) +
- ((page_index + 1) << umem->page_shift));
+ ib_umem_start(umem_odp) +
+ (page_index << umem_odp->page_shift),
+ ib_umem_start(umem_odp) +
+ ((page_index + 1) << umem_odp->page_shift));
ib_umem_notifier_end_account(umem_odp);
ret = -EAGAIN;
}
@@ -581,27 +580,26 @@ int ib_umem_odp_map_dma_pages(struct ib_umem_odp *umem_odp, u64 user_virt,
u64 bcnt, u64 access_mask,
unsigned long current_seq)
{
- struct ib_umem *umem = &umem_odp->umem;
struct task_struct *owning_process = NULL;
struct mm_struct *owning_mm = umem_odp->umem.owning_mm;
struct page **local_page_list = NULL;
u64 page_mask, off;
- int j, k, ret = 0, start_idx, npages = 0, page_shift;
- unsigned int flags = 0;
+ int j, k, ret = 0, start_idx, npages = 0;
+ unsigned int flags = 0, page_shift;
phys_addr_t p = 0;
if (access_mask == 0)
return -EINVAL;
- if (user_virt < ib_umem_start(umem) ||
- user_virt + bcnt > ib_umem_end(umem))
+ if (user_virt < ib_umem_start(umem_odp) ||
+ user_virt + bcnt > ib_umem_end(umem_odp))
return -EFAULT;
local_page_list = (struct page **)__get_free_page(GFP_KERNEL);
if (!local_page_list)
return -ENOMEM;
- page_shift = umem->page_shift;
+ page_shift = umem_odp->page_shift;
page_mask = ~(BIT(page_shift) - 1);
off = user_virt & (~page_mask);
user_virt = user_virt & page_mask;
@@ -621,7 +619,7 @@ int ib_umem_odp_map_dma_pages(struct ib_umem_odp *umem_odp, u64 user_virt,
if (access_mask & ODP_WRITE_ALLOWED_BIT)
flags |= FOLL_WRITE;
- start_idx = (user_virt - ib_umem_start(umem)) >> page_shift;
+ start_idx = (user_virt - ib_umem_start(umem_odp)) >> page_shift;
k = start_idx;
while (bcnt > 0) {
@@ -659,7 +657,7 @@ int ib_umem_odp_map_dma_pages(struct ib_umem_odp *umem_odp, u64 user_virt,
ret = -EFAULT;
break;
}
- put_page(local_page_list[j]);
+ put_user_page(local_page_list[j]);
continue;
}
@@ -686,8 +684,8 @@ int ib_umem_odp_map_dma_pages(struct ib_umem_odp *umem_odp, u64 user_virt,
* ib_umem_odp_map_dma_single_page().
*/
if (npages - (j + 1) > 0)
- release_pages(&local_page_list[j+1],
- npages - (j + 1));
+ put_user_pages(&local_page_list[j+1],
+ npages - (j + 1));
break;
}
}
@@ -711,21 +709,20 @@ EXPORT_SYMBOL(ib_umem_odp_map_dma_pages);
void ib_umem_odp_unmap_dma_pages(struct ib_umem_odp *umem_odp, u64 virt,
u64 bound)
{
- struct ib_umem *umem = &umem_odp->umem;
int idx;
u64 addr;
- struct ib_device *dev = umem->context->device;
+ struct ib_device *dev = umem_odp->umem.context->device;
- virt = max_t(u64, virt, ib_umem_start(umem));
- bound = min_t(u64, bound, ib_umem_end(umem));
+ virt = max_t(u64, virt, ib_umem_start(umem_odp));
+ bound = min_t(u64, bound, ib_umem_end(umem_odp));
/* Note that during the run of this function, the
* notifiers_count of the MR is > 0, preventing any racing
* faults from completion. We might be racing with other
* invalidations, so we must make sure we free each page only
* once. */
mutex_lock(&umem_odp->umem_mutex);
- for (addr = virt; addr < bound; addr += BIT(umem->page_shift)) {
- idx = (addr - ib_umem_start(umem)) >> umem->page_shift;
+ for (addr = virt; addr < bound; addr += BIT(umem_odp->page_shift)) {
+ idx = (addr - ib_umem_start(umem_odp)) >> umem_odp->page_shift;
if (umem_odp->page_list[idx]) {
struct page *page = umem_odp->page_list[idx];
dma_addr_t dma = umem_odp->dma_list[idx];
@@ -733,7 +730,8 @@ void ib_umem_odp_unmap_dma_pages(struct ib_umem_odp *umem_odp, u64 virt,
WARN_ON(!dma_addr);
- ib_dma_unmap_page(dev, dma_addr, PAGE_SIZE,
+ ib_dma_unmap_page(dev, dma_addr,
+ BIT(umem_odp->page_shift),
DMA_BIDIRECTIONAL);
if (dma & ODP_WRITE_ALLOWED_BIT) {
struct page *head_page = compound_head(page);
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
index 671f07ba1fad..9f8a48016b41 100644
--- a/drivers/infiniband/core/user_mad.c
+++ b/drivers/infiniband/core/user_mad.c
@@ -54,6 +54,7 @@
#include <rdma/ib_mad.h>
#include <rdma/ib_user_mad.h>
+#include <rdma/rdma_netlink.h>
#include "core_priv.h"
@@ -744,7 +745,7 @@ found:
"process %s did not enable P_Key index support.\n",
current->comm);
dev_warn(&file->port->dev,
- " Documentation/infiniband/user_mad.txt has info on the new ABI.\n");
+ " Documentation/infiniband/user_mad.rst has info on the new ABI.\n");
}
}
@@ -1124,11 +1125,48 @@ static const struct file_operations umad_sm_fops = {
.llseek = no_llseek,
};
+static int ib_umad_get_nl_info(struct ib_device *ibdev, void *client_data,
+ struct ib_client_nl_info *res)
+{
+ struct ib_umad_device *umad_dev = client_data;
+
+ if (!rdma_is_port_valid(ibdev, res->port))
+ return -EINVAL;
+
+ res->abi = IB_USER_MAD_ABI_VERSION;
+ res->cdev = &umad_dev->ports[res->port - rdma_start_port(ibdev)].dev;
+
+ return 0;
+}
+
static struct ib_client umad_client = {
.name = "umad",
.add = ib_umad_add_one,
- .remove = ib_umad_remove_one
+ .remove = ib_umad_remove_one,
+ .get_nl_info = ib_umad_get_nl_info,
};
+MODULE_ALIAS_RDMA_CLIENT("umad");
+
+static int ib_issm_get_nl_info(struct ib_device *ibdev, void *client_data,
+ struct ib_client_nl_info *res)
+{
+ struct ib_umad_device *umad_dev =
+ ib_get_client_data(ibdev, &umad_client);
+
+ if (!rdma_is_port_valid(ibdev, res->port))
+ return -EINVAL;
+
+ res->abi = IB_USER_MAD_ABI_VERSION;
+ res->cdev = &umad_dev->ports[res->port - rdma_start_port(ibdev)].sm_dev;
+
+ return 0;
+}
+
+static struct ib_client issm_client = {
+ .name = "issm",
+ .get_nl_info = ib_issm_get_nl_info,
+};
+MODULE_ALIAS_RDMA_CLIENT("issm");
static ssize_t ibdev_show(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -1387,13 +1425,17 @@ static int __init ib_umad_init(void)
}
ret = ib_register_client(&umad_client);
- if (ret) {
- pr_err("couldn't register ib_umad client\n");
+ if (ret)
goto out_class;
- }
+
+ ret = ib_register_client(&issm_client);
+ if (ret)
+ goto out_client;
return 0;
+out_client:
+ ib_unregister_client(&umad_client);
out_class:
class_unregister(&umad_class);
@@ -1411,6 +1453,7 @@ out:
static void __exit ib_umad_cleanup(void)
{
+ ib_unregister_client(&issm_client);
ib_unregister_client(&umad_client);
class_unregister(&umad_class);
unregister_chrdev_region(base_umad_dev,
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 63fe14c7c68f..7ddd0e5bc6b3 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -756,7 +756,9 @@ static int ib_uverbs_reg_mr(struct uverbs_attr_bundle *attrs)
mr->device = pd->device;
mr->pd = pd;
+ mr->type = IB_MR_TYPE_USER;
mr->dm = NULL;
+ mr->sig_attrs = NULL;
mr->uobject = uobj;
atomic_inc(&pd->usecnt);
mr->res.type = RDMA_RESTRACK_MR;
@@ -1021,12 +1023,11 @@ static struct ib_ucq_object *create_cq(struct uverbs_attr_bundle *attrs,
attr.comp_vector = cmd->comp_vector;
attr.flags = cmd->flags;
- cq = ib_dev->ops.create_cq(ib_dev, &attr, &attrs->driver_udata);
- if (IS_ERR(cq)) {
- ret = PTR_ERR(cq);
+ cq = rdma_zalloc_drv_obj(ib_dev, ib_cq);
+ if (!cq) {
+ ret = -ENOMEM;
goto err_file;
}
-
cq->device = ib_dev;
cq->uobject = &obj->uobject;
cq->comp_handler = ib_uverbs_comp_handler;
@@ -1034,6 +1035,10 @@ static struct ib_ucq_object *create_cq(struct uverbs_attr_bundle *attrs,
cq->cq_context = ev_file ? &ev_file->ev_queue : NULL;
atomic_set(&cq->usecnt, 0);
+ ret = ib_dev->ops.create_cq(cq, &attr, &attrs->driver_udata);
+ if (ret)
+ goto err_free;
+
obj->uobject.object = cq;
memset(&resp, 0, sizeof resp);
resp.base.cq_handle = obj->uobject.id;
@@ -1054,7 +1059,9 @@ static struct ib_ucq_object *create_cq(struct uverbs_attr_bundle *attrs,
err_cb:
ib_destroy_cq_user(cq, uverbs_get_cleared_udata(attrs));
-
+ cq = NULL;
+err_free:
+ kfree(cq);
err_file:
if (ev_file)
ib_uverbs_release_ucq(attrs->ufile, ev_file, obj);
@@ -2541,7 +2548,7 @@ static int ib_uverbs_detach_mcast(struct uverbs_attr_bundle *attrs)
struct ib_uqp_object *obj;
struct ib_qp *qp;
struct ib_uverbs_mcast_entry *mcast;
- int ret = -EINVAL;
+ int ret;
bool found = false;
ret = uverbs_request(attrs, &cmd, sizeof(cmd));
@@ -3715,9 +3722,6 @@ static int ib_uverbs_ex_modify_cq(struct uverbs_attr_bundle *attrs)
* trailing driver_data flex array. In this case the size of the base struct
* cannot be changed.
*/
-#define offsetof_after(_struct, _member) \
- (offsetof(_struct, _member) + sizeof(((_struct *)NULL)->_member))
-
#define UAPI_DEF_WRITE_IO(req, resp) \
.write.has_resp = 1 + \
BUILD_BUG_ON_ZERO(offsetof(req, response) != 0) + \
@@ -3748,11 +3752,11 @@ static int ib_uverbs_ex_modify_cq(struct uverbs_attr_bundle *attrs)
*/
#define UAPI_DEF_WRITE_IO_EX(req, req_last_member, resp, resp_last_member) \
.write.has_resp = 1, \
- .write.req_size = offsetof_after(req, req_last_member), \
- .write.resp_size = offsetof_after(resp, resp_last_member)
+ .write.req_size = offsetofend(req, req_last_member), \
+ .write.resp_size = offsetofend(resp, resp_last_member)
#define UAPI_DEF_WRITE_I_EX(req, req_last_member) \
- .write.req_size = offsetof_after(req, req_last_member)
+ .write.req_size = offsetofend(req, req_last_member)
const struct uapi_definition uverbs_def_write_intf[] = {
DECLARE_UVERBS_OBJECT(
diff --git a/drivers/infiniband/core/uverbs_ioctl.c b/drivers/infiniband/core/uverbs_ioctl.c
index 829b0c6944d8..61758201d9b2 100644
--- a/drivers/infiniband/core/uverbs_ioctl.c
+++ b/drivers/infiniband/core/uverbs_ioctl.c
@@ -127,7 +127,7 @@ __malloc void *_uverbs_alloc(struct uverbs_attr_bundle *bundle, size_t size,
res = (void *)pbundle->internal_buffer + pbundle->internal_used;
pbundle->internal_used =
ALIGN(new_used, sizeof(*pbundle->internal_buffer));
- if (flags & __GFP_ZERO)
+ if (want_init_on_alloc(flags))
memset(res, 0, size);
return res;
}
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index 84a5e9a6d483..11c13c1381cf 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -51,6 +51,7 @@
#include <rdma/ib.h>
#include <rdma/uverbs_std_types.h>
+#include <rdma/rdma_netlink.h>
#include "uverbs.h"
#include "core_priv.h"
@@ -198,7 +199,7 @@ void ib_uverbs_release_file(struct kref *ref)
ib_dev = srcu_dereference(file->device->ib_dev,
&file->device->disassociate_srcu);
if (ib_dev && !ib_dev->ops.disassociate_ucontext)
- module_put(ib_dev->owner);
+ module_put(ib_dev->ops.owner);
srcu_read_unlock(&file->device->disassociate_srcu, srcu_key);
if (atomic_dec_and_test(&file->device->refcount))
@@ -1065,7 +1066,7 @@ static int ib_uverbs_open(struct inode *inode, struct file *filp)
module_dependent = !(ib_dev->ops.disassociate_ucontext);
if (module_dependent) {
- if (!try_module_get(ib_dev->owner)) {
+ if (!try_module_get(ib_dev->ops.owner)) {
ret = -ENODEV;
goto err;
}
@@ -1100,7 +1101,7 @@ static int ib_uverbs_open(struct inode *inode, struct file *filp)
return stream_open(inode, filp);
err_module:
- module_put(ib_dev->owner);
+ module_put(ib_dev->ops.owner);
err:
mutex_unlock(&dev->lists_mutex);
@@ -1148,12 +1149,41 @@ static const struct file_operations uverbs_mmap_fops = {
.compat_ioctl = ib_uverbs_ioctl,
};
+static int ib_uverbs_get_nl_info(struct ib_device *ibdev, void *client_data,
+ struct ib_client_nl_info *res)
+{
+ struct ib_uverbs_device *uverbs_dev = client_data;
+ int ret;
+
+ if (res->port != -1)
+ return -EINVAL;
+
+ res->abi = ibdev->ops.uverbs_abi_ver;
+ res->cdev = &uverbs_dev->dev;
+
+ /*
+ * To support DRIVER_ID binding in userspace some of the driver need
+ * upgrading to expose their PCI dependent revision information
+ * through get_context instead of relying on modalias matching. When
+ * the drivers are fixed they can drop this flag.
+ */
+ if (!ibdev->ops.uverbs_no_driver_id_binding) {
+ ret = nla_put_u32(res->nl_msg, RDMA_NLDEV_ATTR_UVERBS_DRIVER_ID,
+ ibdev->ops.driver_id);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
static struct ib_client uverbs_client = {
.name = "uverbs",
.no_kverbs_req = true,
.add = ib_uverbs_add_one,
- .remove = ib_uverbs_remove_one
+ .remove = ib_uverbs_remove_one,
+ .get_nl_info = ib_uverbs_get_nl_info,
};
+MODULE_ALIAS_RDMA_CLIENT("uverbs");
static ssize_t ibdev_show(struct device *device, struct device_attribute *attr,
char *buf)
@@ -1186,7 +1216,7 @@ static ssize_t abi_version_show(struct device *device,
srcu_key = srcu_read_lock(&dev->disassociate_srcu);
ib_dev = srcu_dereference(dev->ib_dev, &dev->disassociate_srcu);
if (ib_dev)
- ret = sprintf(buf, "%d\n", ib_dev->uverbs_abi_ver);
+ ret = sprintf(buf, "%u\n", ib_dev->ops.uverbs_abi_ver);
srcu_read_unlock(&dev->disassociate_srcu, srcu_key);
return ret;
diff --git a/drivers/infiniband/core/uverbs_std_types_cq.c b/drivers/infiniband/core/uverbs_std_types_cq.c
index 07ea4e3c4566..e39fe6a8aac4 100644
--- a/drivers/infiniband/core/uverbs_std_types_cq.c
+++ b/drivers/infiniband/core/uverbs_std_types_cq.c
@@ -111,9 +111,9 @@ static int UVERBS_HANDLER(UVERBS_METHOD_CQ_CREATE)(
INIT_LIST_HEAD(&obj->comp_list);
INIT_LIST_HEAD(&obj->async_list);
- cq = ib_dev->ops.create_cq(ib_dev, &attr, &attrs->driver_udata);
- if (IS_ERR(cq)) {
- ret = PTR_ERR(cq);
+ cq = rdma_zalloc_drv_obj(ib_dev, ib_cq);
+ if (!cq) {
+ ret = -ENOMEM;
goto err_event_file;
}
@@ -122,10 +122,15 @@ static int UVERBS_HANDLER(UVERBS_METHOD_CQ_CREATE)(
cq->comp_handler = ib_uverbs_comp_handler;
cq->event_handler = ib_uverbs_cq_event_handler;
cq->cq_context = ev_file ? &ev_file->ev_queue : NULL;
- obj->uobject.object = cq;
- obj->uobject.user_handle = user_handle;
atomic_set(&cq->usecnt, 0);
cq->res.type = RDMA_RESTRACK_CQ;
+
+ ret = ib_dev->ops.create_cq(cq, &attr, &attrs->driver_udata);
+ if (ret)
+ goto err_free;
+
+ obj->uobject.object = cq;
+ obj->uobject.user_handle = user_handle;
rdma_restrack_uadd(&cq->res);
ret = uverbs_copy_to(attrs, UVERBS_ATTR_CREATE_CQ_RESP_CQE, &cq->cqe,
@@ -136,7 +141,9 @@ static int UVERBS_HANDLER(UVERBS_METHOD_CQ_CREATE)(
return 0;
err_cq:
ib_destroy_cq_user(cq, uverbs_get_cleared_udata(attrs));
-
+ cq = NULL;
+err_free:
+ kfree(cq);
err_event_file:
if (ev_file)
uverbs_uobject_put(ev_file_uobj);
diff --git a/drivers/infiniband/core/uverbs_std_types_mr.c b/drivers/infiniband/core/uverbs_std_types_mr.c
index 997f7a3a558a..c1286a52dc84 100644
--- a/drivers/infiniband/core/uverbs_std_types_mr.c
+++ b/drivers/infiniband/core/uverbs_std_types_mr.c
@@ -128,6 +128,7 @@ static int UVERBS_HANDLER(UVERBS_METHOD_DM_MR_REG)(
mr->device = pd->device;
mr->pd = pd;
+ mr->type = IB_MR_TYPE_DM;
mr->dm = dm;
mr->uobject = uobj;
atomic_inc(&pd->usecnt);
diff --git a/drivers/infiniband/core/uverbs_uapi.c b/drivers/infiniband/core/uverbs_uapi.c
index 7a987acf0c0b..00c547887132 100644
--- a/drivers/infiniband/core/uverbs_uapi.c
+++ b/drivers/infiniband/core/uverbs_uapi.c
@@ -22,6 +22,8 @@ static void *uapi_add_elm(struct uverbs_api *uapi, u32 key, size_t alloc_size)
return ERR_PTR(-EOVERFLOW);
elm = kzalloc(alloc_size, GFP_KERNEL);
+ if (!elm)
+ return ERR_PTR(-ENOMEM);
rc = radix_tree_insert(&uapi->radix, key, elm);
if (rc) {
kfree(elm);
@@ -645,7 +647,7 @@ struct uverbs_api *uverbs_alloc_api(struct ib_device *ibdev)
return ERR_PTR(-ENOMEM);
INIT_RADIX_TREE(&uapi->radix, GFP_KERNEL);
- uapi->driver_id = ibdev->driver_id;
+ uapi->driver_id = ibdev->ops.driver_id;
rc = uapi_merge_def(uapi, ibdev, uverbs_core_api, false);
if (rc)
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
index e666a1f7608d..92349bf37589 100644
--- a/drivers/infiniband/core/verbs.c
+++ b/drivers/infiniband/core/verbs.c
@@ -209,7 +209,7 @@ __attribute_const__ int ib_rate_to_mbps(enum ib_rate rate)
EXPORT_SYMBOL(ib_rate_to_mbps);
__attribute_const__ enum rdma_transport_type
-rdma_node_get_transport(enum rdma_node_type node_type)
+rdma_node_get_transport(unsigned int node_type)
{
if (node_type == RDMA_NODE_USNIC)
@@ -299,6 +299,7 @@ struct ib_pd *__ib_alloc_pd(struct ib_device *device, unsigned int flags,
mr->device = pd->device;
mr->pd = pd;
+ mr->type = IB_MR_TYPE_DMA;
mr->uobject = NULL;
mr->need_inval = false;
@@ -316,7 +317,7 @@ struct ib_pd *__ib_alloc_pd(struct ib_device *device, unsigned int flags,
EXPORT_SYMBOL(__ib_alloc_pd);
/**
- * ib_dealloc_pd - Deallocates a protection domain.
+ * ib_dealloc_pd_user - Deallocates a protection domain.
* @pd: The protection domain to deallocate.
* @udata: Valid user data or NULL for kernel object
*
@@ -1157,6 +1158,10 @@ struct ib_qp *ib_create_qp_user(struct ib_pd *pd,
qp_init_attr->cap.max_recv_sge))
return ERR_PTR(-EINVAL);
+ if ((qp_init_attr->create_flags & IB_QP_CREATE_INTEGRITY_EN) &&
+ !(device->attrs.device_cap_flags & IB_DEVICE_INTEGRITY_HANDOVER))
+ return ERR_PTR(-EINVAL);
+
/*
* If the callers is using the RDMA API calculate the resources
* needed for the RDMA READ/WRITE operations.
@@ -1232,6 +1237,8 @@ struct ib_qp *ib_create_qp_user(struct ib_pd *pd,
qp->max_write_sge = qp_init_attr->cap.max_send_sge;
qp->max_read_sge = min_t(u32, qp_init_attr->cap.max_send_sge,
device->attrs.max_sge_rd);
+ if (qp_init_attr->create_flags & IB_QP_CREATE_INTEGRITY_EN)
+ qp->integrity_en = true;
return qp;
@@ -1683,6 +1690,14 @@ static int _ib_modify_qp(struct ib_qp *qp, struct ib_qp_attr *attr,
}
}
+ /*
+ * Bind this qp to a counter automatically based on the rdma counter
+ * rules. This only set in RST2INIT with port specified
+ */
+ if (!qp->counter && (attr_mask & IB_QP_PORT) &&
+ ((attr_mask & IB_QP_STATE) && attr->qp_state == IB_QPS_INIT))
+ rdma_counter_bind_qp_auto(qp, attr->port_num);
+
ret = ib_security_modify_qp(qp, attr, attr_mask, udata);
if (ret)
goto out;
@@ -1878,6 +1893,7 @@ int ib_destroy_qp_user(struct ib_qp *qp, struct ib_udata *udata)
if (!qp->uobject)
rdma_rw_cleanup_mrs(qp);
+ rdma_counter_unbind_qp(qp, true);
rdma_restrack_del(&qp->res);
ret = qp->device->ops.destroy_qp(qp, udata);
if (!ret) {
@@ -1916,21 +1932,28 @@ struct ib_cq *__ib_create_cq(struct ib_device *device,
const char *caller)
{
struct ib_cq *cq;
+ int ret;
+
+ cq = rdma_zalloc_drv_obj(device, ib_cq);
+ if (!cq)
+ return ERR_PTR(-ENOMEM);
- cq = device->ops.create_cq(device, cq_attr, NULL);
-
- if (!IS_ERR(cq)) {
- cq->device = device;
- cq->uobject = NULL;
- cq->comp_handler = comp_handler;
- cq->event_handler = event_handler;
- cq->cq_context = cq_context;
- atomic_set(&cq->usecnt, 0);
- cq->res.type = RDMA_RESTRACK_CQ;
- rdma_restrack_set_task(&cq->res, caller);
- rdma_restrack_kadd(&cq->res);
+ cq->device = device;
+ cq->uobject = NULL;
+ cq->comp_handler = comp_handler;
+ cq->event_handler = event_handler;
+ cq->cq_context = cq_context;
+ atomic_set(&cq->usecnt, 0);
+ cq->res.type = RDMA_RESTRACK_CQ;
+ rdma_restrack_set_task(&cq->res, caller);
+
+ ret = device->ops.create_cq(cq, cq_attr, NULL);
+ if (ret) {
+ kfree(cq);
+ return ERR_PTR(ret);
}
+ rdma_restrack_kadd(&cq->res);
return cq;
}
EXPORT_SYMBOL(__ib_create_cq);
@@ -1949,7 +1972,9 @@ int ib_destroy_cq_user(struct ib_cq *cq, struct ib_udata *udata)
return -EBUSY;
rdma_restrack_del(&cq->res);
- return cq->device->ops.destroy_cq(cq, udata);
+ cq->device->ops.destroy_cq(cq, udata);
+ kfree(cq);
+ return 0;
}
EXPORT_SYMBOL(ib_destroy_cq_user);
@@ -1966,6 +1991,7 @@ int ib_dereg_mr_user(struct ib_mr *mr, struct ib_udata *udata)
{
struct ib_pd *pd = mr->pd;
struct ib_dm *dm = mr->dm;
+ struct ib_sig_attrs *sig_attrs = mr->sig_attrs;
int ret;
rdma_restrack_del(&mr->res);
@@ -1974,6 +2000,7 @@ int ib_dereg_mr_user(struct ib_mr *mr, struct ib_udata *udata)
atomic_dec(&pd->usecnt);
if (dm)
atomic_dec(&dm->usecnt);
+ kfree(sig_attrs);
}
return ret;
@@ -1981,7 +2008,7 @@ int ib_dereg_mr_user(struct ib_mr *mr, struct ib_udata *udata)
EXPORT_SYMBOL(ib_dereg_mr_user);
/**
- * ib_alloc_mr() - Allocates a memory region
+ * ib_alloc_mr_user() - Allocates a memory region
* @pd: protection domain associated with the region
* @mr_type: memory region type
* @max_num_sg: maximum sg entries available for registration.
@@ -2001,6 +2028,9 @@ struct ib_mr *ib_alloc_mr_user(struct ib_pd *pd, enum ib_mr_type mr_type,
if (!pd->device->ops.alloc_mr)
return ERR_PTR(-EOPNOTSUPP);
+ if (WARN_ON_ONCE(mr_type == IB_MR_TYPE_INTEGRITY))
+ return ERR_PTR(-EINVAL);
+
mr = pd->device->ops.alloc_mr(pd, mr_type, max_num_sg, udata);
if (!IS_ERR(mr)) {
mr->device = pd->device;
@@ -2011,12 +2041,66 @@ struct ib_mr *ib_alloc_mr_user(struct ib_pd *pd, enum ib_mr_type mr_type,
mr->need_inval = false;
mr->res.type = RDMA_RESTRACK_MR;
rdma_restrack_kadd(&mr->res);
+ mr->type = mr_type;
+ mr->sig_attrs = NULL;
}
return mr;
}
EXPORT_SYMBOL(ib_alloc_mr_user);
+/**
+ * ib_alloc_mr_integrity() - Allocates an integrity memory region
+ * @pd: protection domain associated with the region
+ * @max_num_data_sg: maximum data sg entries available for registration
+ * @max_num_meta_sg: maximum metadata sg entries available for
+ * registration
+ *
+ * Notes:
+ * Memory registration page/sg lists must not exceed max_num_sg,
+ * also the integrity page/sg lists must not exceed max_num_meta_sg.
+ *
+ */
+struct ib_mr *ib_alloc_mr_integrity(struct ib_pd *pd,
+ u32 max_num_data_sg,
+ u32 max_num_meta_sg)
+{
+ struct ib_mr *mr;
+ struct ib_sig_attrs *sig_attrs;
+
+ if (!pd->device->ops.alloc_mr_integrity ||
+ !pd->device->ops.map_mr_sg_pi)
+ return ERR_PTR(-EOPNOTSUPP);
+
+ if (!max_num_meta_sg)
+ return ERR_PTR(-EINVAL);
+
+ sig_attrs = kzalloc(sizeof(struct ib_sig_attrs), GFP_KERNEL);
+ if (!sig_attrs)
+ return ERR_PTR(-ENOMEM);
+
+ mr = pd->device->ops.alloc_mr_integrity(pd, max_num_data_sg,
+ max_num_meta_sg);
+ if (IS_ERR(mr)) {
+ kfree(sig_attrs);
+ return mr;
+ }
+
+ mr->device = pd->device;
+ mr->pd = pd;
+ mr->dm = NULL;
+ mr->uobject = NULL;
+ atomic_inc(&pd->usecnt);
+ mr->need_inval = false;
+ mr->res.type = RDMA_RESTRACK_MR;
+ rdma_restrack_kadd(&mr->res);
+ mr->type = IB_MR_TYPE_INTEGRITY;
+ mr->sig_attrs = sig_attrs;
+
+ return mr;
+}
+EXPORT_SYMBOL(ib_alloc_mr_integrity);
+
/* "Fast" memory regions */
struct ib_fmr *ib_alloc_fmr(struct ib_pd *pd,
@@ -2226,19 +2310,17 @@ EXPORT_SYMBOL(ib_create_wq);
*/
int ib_destroy_wq(struct ib_wq *wq, struct ib_udata *udata)
{
- int err;
struct ib_cq *cq = wq->cq;
struct ib_pd *pd = wq->pd;
if (atomic_read(&wq->usecnt))
return -EBUSY;
- err = wq->device->ops.destroy_wq(wq, udata);
- if (!err) {
- atomic_dec(&pd->usecnt);
- atomic_dec(&cq->usecnt);
- }
- return err;
+ wq->device->ops.destroy_wq(wq, udata);
+ atomic_dec(&pd->usecnt);
+ atomic_dec(&cq->usecnt);
+
+ return 0;
}
EXPORT_SYMBOL(ib_destroy_wq);
@@ -2376,6 +2458,43 @@ int ib_set_vf_guid(struct ib_device *device, int vf, u8 port, u64 guid,
EXPORT_SYMBOL(ib_set_vf_guid);
/**
+ * ib_map_mr_sg_pi() - Map the dma mapped SG lists for PI (protection
+ * information) and set an appropriate memory region for registration.
+ * @mr: memory region
+ * @data_sg: dma mapped scatterlist for data
+ * @data_sg_nents: number of entries in data_sg
+ * @data_sg_offset: offset in bytes into data_sg
+ * @meta_sg: dma mapped scatterlist for metadata
+ * @meta_sg_nents: number of entries in meta_sg
+ * @meta_sg_offset: offset in bytes into meta_sg
+ * @page_size: page vector desired page size
+ *
+ * Constraints:
+ * - The MR must be allocated with type IB_MR_TYPE_INTEGRITY.
+ *
+ * Return: 0 on success.
+ *
+ * After this completes successfully, the memory region
+ * is ready for registration.
+ */
+int ib_map_mr_sg_pi(struct ib_mr *mr, struct scatterlist *data_sg,
+ int data_sg_nents, unsigned int *data_sg_offset,
+ struct scatterlist *meta_sg, int meta_sg_nents,
+ unsigned int *meta_sg_offset, unsigned int page_size)
+{
+ if (unlikely(!mr->device->ops.map_mr_sg_pi ||
+ WARN_ON_ONCE(mr->type != IB_MR_TYPE_INTEGRITY)))
+ return -EOPNOTSUPP;
+
+ mr->page_size = page_size;
+
+ return mr->device->ops.map_mr_sg_pi(mr, data_sg, data_sg_nents,
+ data_sg_offset, meta_sg,
+ meta_sg_nents, meta_sg_offset);
+}
+EXPORT_SYMBOL(ib_map_mr_sg_pi);
+
+/**
* ib_map_mr_sg() - Map the largest prefix of a dma mapped SG list
* and set it the memory region.
* @mr: memory region
diff --git a/drivers/infiniband/hw/Makefile b/drivers/infiniband/hw/Makefile
index 77094be1b262..433fca59febd 100644
--- a/drivers/infiniband/hw/Makefile
+++ b/drivers/infiniband/hw/Makefile
@@ -7,7 +7,6 @@ obj-$(CONFIG_INFINIBAND_EFA) += efa/
obj-$(CONFIG_INFINIBAND_I40IW) += i40iw/
obj-$(CONFIG_MLX4_INFINIBAND) += mlx4/
obj-$(CONFIG_MLX5_INFINIBAND) += mlx5/
-obj-$(CONFIG_INFINIBAND_NES) += nes/
obj-$(CONFIG_INFINIBAND_OCRDMA) += ocrdma/
obj-$(CONFIG_INFINIBAND_VMWARE_PVRDMA) += vmw_pvrdma/
obj-$(CONFIG_INFINIBAND_USNIC) += usnic/
diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
index 2c3685faa57a..a91653aabf38 100644
--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c
+++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
@@ -805,10 +805,8 @@ int bnxt_re_destroy_qp(struct ib_qp *ib_qp, struct ib_udata *udata)
rdev->sqp_ah = NULL;
}
- if (!IS_ERR_OR_NULL(qp->rumem))
- ib_umem_release(qp->rumem);
- if (!IS_ERR_OR_NULL(qp->sumem))
- ib_umem_release(qp->sumem);
+ ib_umem_release(qp->rumem);
+ ib_umem_release(qp->sumem);
mutex_lock(&rdev->qp_lock);
list_del(&qp->list);
@@ -1201,12 +1199,8 @@ struct ib_qp *bnxt_re_create_qp(struct ib_pd *ib_pd,
qp_destroy:
bnxt_qplib_destroy_qp(&rdev->qplib_res, &qp->qplib_qp);
free_umem:
- if (udata) {
- if (qp->rumem)
- ib_umem_release(qp->rumem);
- if (qp->sumem)
- ib_umem_release(qp->sumem);
- }
+ ib_umem_release(qp->rumem);
+ ib_umem_release(qp->sumem);
fail:
kfree(qp);
return ERR_PTR(rc);
@@ -1302,8 +1296,7 @@ void bnxt_re_destroy_srq(struct ib_srq *ib_srq, struct ib_udata *udata)
if (qplib_srq->cq)
nq = qplib_srq->cq->nq;
bnxt_qplib_destroy_srq(&rdev->qplib_res, qplib_srq);
- if (srq->umem)
- ib_umem_release(srq->umem);
+ ib_umem_release(srq->umem);
atomic_dec(&rdev->srq_count);
if (nq)
nq->budget--;
@@ -1412,8 +1405,7 @@ int bnxt_re_create_srq(struct ib_srq *ib_srq,
return 0;
fail:
- if (srq->umem)
- ib_umem_release(srq->umem);
+ ib_umem_release(srq->umem);
exit:
return rc;
}
@@ -2517,9 +2509,8 @@ int bnxt_re_post_recv(struct ib_qp *ib_qp, const struct ib_recv_wr *wr,
}
/* Completion Queues */
-int bnxt_re_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)
+void bnxt_re_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)
{
- int rc;
struct bnxt_re_cq *cq;
struct bnxt_qplib_nq *nq;
struct bnxt_re_dev *rdev;
@@ -2528,29 +2519,20 @@ int bnxt_re_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)
rdev = cq->rdev;
nq = cq->qplib_cq.nq;
- rc = bnxt_qplib_destroy_cq(&rdev->qplib_res, &cq->qplib_cq);
- if (rc) {
- dev_err(rdev_to_dev(rdev), "Failed to destroy HW CQ");
- return rc;
- }
- if (!IS_ERR_OR_NULL(cq->umem))
- ib_umem_release(cq->umem);
+ bnxt_qplib_destroy_cq(&rdev->qplib_res, &cq->qplib_cq);
+ ib_umem_release(cq->umem);
atomic_dec(&rdev->cq_count);
nq->budget--;
kfree(cq->cql);
- kfree(cq);
-
- return 0;
}
-struct ib_cq *bnxt_re_create_cq(struct ib_device *ibdev,
- const struct ib_cq_init_attr *attr,
- struct ib_udata *udata)
+int bnxt_re_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata)
{
- struct bnxt_re_dev *rdev = to_bnxt_re_dev(ibdev, ibdev);
+ struct bnxt_re_dev *rdev = to_bnxt_re_dev(ibcq->device, ibdev);
struct bnxt_qplib_dev_attr *dev_attr = &rdev->dev_attr;
- struct bnxt_re_cq *cq = NULL;
+ struct bnxt_re_cq *cq = container_of(ibcq, struct bnxt_re_cq, ib_cq);
int rc, entries;
int cqe = attr->cqe;
struct bnxt_qplib_nq *nq = NULL;
@@ -2559,11 +2541,8 @@ struct ib_cq *bnxt_re_create_cq(struct ib_device *ibdev,
/* Validate CQ fields */
if (cqe < 1 || cqe > dev_attr->max_cq_wqes) {
dev_err(rdev_to_dev(rdev), "Failed to create CQ -max exceeded");
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
}
- cq = kzalloc(sizeof(*cq), GFP_KERNEL);
- if (!cq)
- return ERR_PTR(-ENOMEM);
cq->rdev = rdev;
cq->qplib_cq.cq_handle = (u64)(unsigned long)(&cq->qplib_cq);
@@ -2641,15 +2620,13 @@ struct ib_cq *bnxt_re_create_cq(struct ib_device *ibdev,
}
}
- return &cq->ib_cq;
+ return 0;
c2fail:
- if (udata)
- ib_umem_release(cq->umem);
+ ib_umem_release(cq->umem);
fail:
kfree(cq->cql);
- kfree(cq);
- return ERR_PTR(rc);
+ return rc;
}
static u8 __req_to_ib_wc_status(u8 qstatus)
@@ -3353,8 +3330,7 @@ int bnxt_re_dereg_mr(struct ib_mr *ib_mr, struct ib_udata *udata)
mr->npages = 0;
mr->pages = NULL;
}
- if (!IS_ERR_OR_NULL(mr->ib_umem))
- ib_umem_release(mr->ib_umem);
+ ib_umem_release(mr->ib_umem);
kfree(mr);
atomic_dec(&rdev->mr_count);
@@ -3630,10 +3606,10 @@ int bnxt_re_alloc_ucontext(struct ib_ucontext *ctx, struct ib_udata *udata)
u32 chip_met_rev_num = 0;
int rc;
- dev_dbg(rdev_to_dev(rdev), "ABI version requested %d",
- ibdev->uverbs_abi_ver);
+ dev_dbg(rdev_to_dev(rdev), "ABI version requested %u",
+ ibdev->ops.uverbs_abi_ver);
- if (ibdev->uverbs_abi_ver != BNXT_RE_ABI_VERSION) {
+ if (ibdev->ops.uverbs_abi_ver != BNXT_RE_ABI_VERSION) {
dev_dbg(rdev_to_dev(rdev), " is different from the device %d ",
BNXT_RE_ABI_VERSION);
return -EPERM;
diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.h b/drivers/infiniband/hw/bnxt_re/ib_verbs.h
index 09a33049e42f..31662b1ee35a 100644
--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.h
+++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.h
@@ -94,11 +94,11 @@ struct bnxt_re_qp {
};
struct bnxt_re_cq {
+ struct ib_cq ib_cq;
struct bnxt_re_dev *rdev;
spinlock_t cq_lock; /* protect cq */
u16 cq_count;
u16 cq_period;
- struct ib_cq ib_cq;
struct bnxt_qplib_cq qplib_cq;
struct bnxt_qplib_cqe *cql;
#define MAX_CQL_PER_POLL 1024
@@ -190,10 +190,9 @@ int bnxt_re_post_send(struct ib_qp *qp, const struct ib_send_wr *send_wr,
const struct ib_send_wr **bad_send_wr);
int bnxt_re_post_recv(struct ib_qp *qp, const struct ib_recv_wr *recv_wr,
const struct ib_recv_wr **bad_recv_wr);
-struct ib_cq *bnxt_re_create_cq(struct ib_device *ibdev,
- const struct ib_cq_init_attr *attr,
- struct ib_udata *udata);
-int bnxt_re_destroy_cq(struct ib_cq *cq, struct ib_udata *udata);
+int bnxt_re_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata);
+void bnxt_re_destroy_cq(struct ib_cq *cq, struct ib_udata *udata);
int bnxt_re_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc);
int bnxt_re_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags);
struct ib_mr *bnxt_re_get_dma_mr(struct ib_pd *pd, int mr_access_flags);
diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c
index 814f959c7db9..029babe713f3 100644
--- a/drivers/infiniband/hw/bnxt_re/main.c
+++ b/drivers/infiniband/hw/bnxt_re/main.c
@@ -596,6 +596,10 @@ static void bnxt_re_unregister_ib(struct bnxt_re_dev *rdev)
}
static const struct ib_device_ops bnxt_re_dev_ops = {
+ .owner = THIS_MODULE,
+ .driver_id = RDMA_DRIVER_BNXT_RE,
+ .uverbs_abi_ver = BNXT_RE_ABI_VERSION,
+
.add_gid = bnxt_re_add_gid,
.alloc_hw_stats = bnxt_re_ib_alloc_hw_stats,
.alloc_mr = bnxt_re_alloc_mr,
@@ -637,6 +641,7 @@ static const struct ib_device_ops bnxt_re_dev_ops = {
.reg_user_mr = bnxt_re_reg_user_mr,
.req_notify_cq = bnxt_re_req_notify_cq,
INIT_RDMA_OBJ_SIZE(ib_ah, bnxt_re_ah, ib_ah),
+ INIT_RDMA_OBJ_SIZE(ib_cq, bnxt_re_cq, ib_cq),
INIT_RDMA_OBJ_SIZE(ib_pd, bnxt_re_pd, ib_pd),
INIT_RDMA_OBJ_SIZE(ib_srq, bnxt_re_srq, ib_srq),
INIT_RDMA_OBJ_SIZE(ib_ucontext, bnxt_re_ucontext, ib_uctx),
@@ -648,7 +653,6 @@ static int bnxt_re_register_ib(struct bnxt_re_dev *rdev)
int ret;
/* ib device init */
- ibdev->owner = THIS_MODULE;
ibdev->node_type = RDMA_NODE_IB_CA;
strlcpy(ibdev->node_desc, BNXT_RE_DESC " HCA",
strlen(BNXT_RE_DESC) + 5);
@@ -661,7 +665,6 @@ static int bnxt_re_register_ib(struct bnxt_re_dev *rdev)
ibdev->local_dma_lkey = BNXT_QPLIB_RSVD_LKEY;
/* User space */
- ibdev->uverbs_abi_ver = BNXT_RE_ABI_VERSION;
ibdev->uverbs_cmd_mask =
(1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
(1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |
@@ -691,7 +694,6 @@ static int bnxt_re_register_ib(struct bnxt_re_dev *rdev)
rdma_set_device_sysfs_group(ibdev, &bnxt_re_dev_attr_group);
- ibdev->driver_id = RDMA_DRIVER_BNXT_RE;
ib_set_device_ops(ibdev, &bnxt_re_dev_ops);
ret = ib_device_set_netdev(&rdev->ibdev, rdev->netdev, 1);
if (ret)
diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c
index 8ac72ac7cbac..95b22a651673 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_hal.c
+++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c
@@ -174,7 +174,6 @@ int cxio_create_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq, int kernel)
return -ENOMEM;
}
dma_unmap_addr_set(cq, mapping, cq->dma_addr);
- memset(cq->queue, 0, size);
setup.id = cq->cqid;
setup.base_addr = (u64) (cq->dma_addr);
setup.size = 1UL << cq->size_log2;
@@ -187,20 +186,6 @@ int cxio_create_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq, int kernel)
return (rdev_p->t3cdev_p->ctl(rdev_p->t3cdev_p, RDMA_CQ_SETUP, &setup));
}
-#ifdef notyet
-int cxio_resize_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq)
-{
- struct rdma_cq_setup setup;
- setup.id = cq->cqid;
- setup.base_addr = (u64) (cq->dma_addr);
- setup.size = 1UL << cq->size_log2;
- setup.credits = setup.size;
- setup.credit_thres = setup.size; /* TBD: overflow recovery */
- setup.ovfl_mode = 1;
- return (rdev_p->t3cdev_p->ctl(rdev_p->t3cdev_p, RDMA_CQ_SETUP, &setup));
-}
-#endif
-
static u32 get_qpid(struct cxio_rdev *rdev_p, struct cxio_ucontext *uctx)
{
struct cxio_qpid_list *entry;
@@ -219,7 +204,7 @@ static u32 get_qpid(struct cxio_rdev *rdev_p, struct cxio_ucontext *uctx)
if (!qpid)
goto out;
for (i = qpid+1; i & rdev_p->qpmask; i++) {
- entry = kmalloc(sizeof *entry, GFP_KERNEL);
+ entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry)
break;
entry->qpid = i;
@@ -237,7 +222,7 @@ static void put_qpid(struct cxio_rdev *rdev_p, u32 qpid,
{
struct cxio_qpid_list *entry;
- entry = kmalloc(sizeof *entry, GFP_KERNEL);
+ entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry)
return;
pr_debug("%s qpid 0x%x\n", __func__, qpid);
@@ -317,17 +302,15 @@ err1:
return -ENOMEM;
}
-int cxio_destroy_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq)
+void cxio_destroy_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq)
{
- int err;
- err = cxio_hal_clear_cq_ctx(rdev_p, cq->cqid);
+ cxio_hal_clear_cq_ctx(rdev_p, cq->cqid);
kfree(cq->sw_queue);
dma_free_coherent(&(rdev_p->rnic_info.pdev->dev),
(1UL << (cq->size_log2))
* sizeof(struct t3_cqe) + 1, cq->queue,
dma_unmap_addr(cq, mapping));
cxio_hal_put_cqid(rdev_p->rscp, cq->cqid);
- return err;
}
int cxio_destroy_qp(struct cxio_rdev *rdev_p, struct t3_wq *wq,
@@ -538,8 +521,6 @@ static int cxio_hal_init_ctrl_qp(struct cxio_rdev *rdev_p)
dma_unmap_addr_set(&rdev_p->ctrl_qp, mapping,
rdev_p->ctrl_qp.dma_addr);
rdev_p->ctrl_qp.doorbell = (void __iomem *)rdev_p->rnic_info.kdb_addr;
- memset(rdev_p->ctrl_qp.workq, 0,
- (1 << T3_CTRL_QP_SIZE_LOG2) * sizeof(union t3_wr));
mutex_init(&rdev_p->ctrl_qp.lock);
init_waitqueue_head(&rdev_p->ctrl_qp.waitq);
@@ -565,9 +546,9 @@ static int cxio_hal_init_ctrl_qp(struct cxio_rdev *rdev_p)
wqe->sge_cmd = cpu_to_be64(sge_cmd);
wqe->ctx1 = cpu_to_be64(ctx1);
wqe->ctx0 = cpu_to_be64(ctx0);
- pr_debug("CtrlQP dma_addr 0x%llx workq %p size %d\n",
- (unsigned long long)rdev_p->ctrl_qp.dma_addr,
- rdev_p->ctrl_qp.workq, 1 << T3_CTRL_QP_SIZE_LOG2);
+ pr_debug("CtrlQP dma_addr %pad workq %p size %d\n",
+ &rdev_p->ctrl_qp.dma_addr, rdev_p->ctrl_qp.workq,
+ 1 << T3_CTRL_QP_SIZE_LOG2);
skb->priority = CPL_PRIORITY_CONTROL;
return iwch_cxgb3_ofld_send(rdev_p->t3cdev_p, skb);
err:
diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.h b/drivers/infiniband/hw/cxgb3/cxio_hal.h
index c64e50b5a548..40c029ffa425 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_hal.h
+++ b/drivers/infiniband/hw/cxgb3/cxio_hal.h
@@ -158,8 +158,7 @@ void cxio_rdev_close(struct cxio_rdev *rdev);
int cxio_hal_cq_op(struct cxio_rdev *rdev, struct t3_cq *cq,
enum t3_cq_opcode op, u32 credit);
int cxio_create_cq(struct cxio_rdev *rdev, struct t3_cq *cq, int kernel);
-int cxio_destroy_cq(struct cxio_rdev *rdev, struct t3_cq *cq);
-int cxio_resize_cq(struct cxio_rdev *rdev, struct t3_cq *cq);
+void cxio_destroy_cq(struct cxio_rdev *rdev, struct t3_cq *cq);
void cxio_release_ucontext(struct cxio_rdev *rdev, struct cxio_ucontext *uctx);
void cxio_init_ucontext(struct cxio_rdev *rdev, struct cxio_ucontext *uctx);
int cxio_create_qp(struct cxio_rdev *rdev, u32 kernel_domain, struct t3_wq *wq,
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
index 1c90c86fc8b8..0bca72cb4d9a 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
@@ -170,7 +170,7 @@ static void release_tid(struct t3cdev *tdev, u32 hwtid, struct sk_buff *skb)
{
struct cpl_tid_release *req;
- skb = get_skb(skb, sizeof *req, GFP_KERNEL);
+ skb = get_skb(skb, sizeof(*req), GFP_KERNEL);
if (!skb)
return;
req = skb_put(skb, sizeof(*req));
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c
index 3a481dfb1607..e775c1a1a450 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c
@@ -88,7 +88,7 @@ static int iwch_alloc_ucontext(struct ib_ucontext *ucontext,
return 0;
}
-static int iwch_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)
+static void iwch_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)
{
struct iwch_cq *chp;
@@ -100,17 +100,16 @@ static int iwch_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)
wait_event(chp->wait, !atomic_read(&chp->refcnt));
cxio_destroy_cq(&chp->rhp->rdev, &chp->cq);
- kfree(chp);
- return 0;
}
-static struct ib_cq *iwch_create_cq(struct ib_device *ibdev,
- const struct ib_cq_init_attr *attr,
- struct ib_udata *udata)
+static int iwch_create_cq(struct ib_cq *ibcq,
+ const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata)
{
+ struct ib_device *ibdev = ibcq->device;
int entries = attr->cqe;
- struct iwch_dev *rhp;
- struct iwch_cq *chp;
+ struct iwch_dev *rhp = to_iwch_dev(ibcq->device);
+ struct iwch_cq *chp = to_iwch_cq(ibcq);
struct iwch_create_cq_resp uresp;
struct iwch_create_cq_req ureq;
static int warned;
@@ -118,19 +117,13 @@ static struct ib_cq *iwch_create_cq(struct ib_device *ibdev,
pr_debug("%s ib_dev %p entries %d\n", __func__, ibdev, entries);
if (attr->flags)
- return ERR_PTR(-EINVAL);
-
- rhp = to_iwch_dev(ibdev);
- chp = kzalloc(sizeof(*chp), GFP_KERNEL);
- if (!chp)
- return ERR_PTR(-ENOMEM);
+ return -EINVAL;
if (udata) {
if (!t3a_device(rhp)) {
- if (ib_copy_from_udata(&ureq, udata, sizeof (ureq))) {
- kfree(chp);
- return ERR_PTR(-EFAULT);
- }
+ if (ib_copy_from_udata(&ureq, udata, sizeof(ureq)))
+ return -EFAULT;
+
chp->user_rptr_addr = (u32 __user *)(unsigned long)ureq.user_rptr_addr;
}
}
@@ -151,10 +144,9 @@ static struct ib_cq *iwch_create_cq(struct ib_device *ibdev,
entries = roundup_pow_of_two(entries);
chp->cq.size_log2 = ilog2(entries);
- if (cxio_create_cq(&rhp->rdev, &chp->cq, !udata)) {
- kfree(chp);
- return ERR_PTR(-ENOMEM);
- }
+ if (cxio_create_cq(&rhp->rdev, &chp->cq, !udata))
+ return -ENOMEM;
+
chp->rhp = rhp;
chp->ibcq.cqe = 1 << chp->cq.size_log2;
spin_lock_init(&chp->lock);
@@ -163,8 +155,7 @@ static struct ib_cq *iwch_create_cq(struct ib_device *ibdev,
init_waitqueue_head(&chp->wait);
if (xa_store_irq(&rhp->cqs, chp->cq.cqid, chp, GFP_KERNEL)) {
cxio_destroy_cq(&chp->rhp->rdev, &chp->cq);
- kfree(chp);
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
}
if (udata) {
@@ -172,10 +163,10 @@ static struct ib_cq *iwch_create_cq(struct ib_device *ibdev,
struct iwch_ucontext *ucontext = rdma_udata_to_drv_context(
udata, struct iwch_ucontext, ibucontext);
- mm = kmalloc(sizeof *mm, GFP_KERNEL);
+ mm = kmalloc(sizeof(*mm), GFP_KERNEL);
if (!mm) {
iwch_destroy_cq(&chp->ibcq, udata);
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
}
uresp.cqid = chp->cq.cqid;
uresp.size_log2 = chp->cq.size_log2;
@@ -185,7 +176,7 @@ static struct ib_cq *iwch_create_cq(struct ib_device *ibdev,
spin_unlock(&ucontext->mmap_lock);
mm->key = uresp.key;
mm->addr = virt_to_phys(chp->cq.queue);
- if (udata->outlen < sizeof uresp) {
+ if (udata->outlen < sizeof(uresp)) {
if (!warned++)
pr_warn("Warning - downlevel libcxgb3 (non-fatal)\n");
mm->len = PAGE_ALIGN((1UL << uresp.size_log2) *
@@ -196,86 +187,19 @@ static struct ib_cq *iwch_create_cq(struct ib_device *ibdev,
sizeof(struct t3_cqe));
uresp.memsize = mm->len;
uresp.reserved = 0;
- resplen = sizeof uresp;
+ resplen = sizeof(uresp);
}
if (ib_copy_to_udata(udata, &uresp, resplen)) {
kfree(mm);
iwch_destroy_cq(&chp->ibcq, udata);
- return ERR_PTR(-EFAULT);
+ return -EFAULT;
}
insert_mmap(ucontext, mm);
}
- pr_debug("created cqid 0x%0x chp %p size 0x%0x, dma_addr 0x%0llx\n",
+ pr_debug("created cqid 0x%0x chp %p size 0x%0x, dma_addr %pad\n",
chp->cq.cqid, chp, (1 << chp->cq.size_log2),
- (unsigned long long)chp->cq.dma_addr);
- return &chp->ibcq;
-}
-
-static int iwch_resize_cq(struct ib_cq *cq, int cqe, struct ib_udata *udata)
-{
-#ifdef notyet
- struct iwch_cq *chp = to_iwch_cq(cq);
- struct t3_cq oldcq, newcq;
- int ret;
-
- pr_debug("%s ib_cq %p cqe %d\n", __func__, cq, cqe);
-
- /* We don't downsize... */
- if (cqe <= cq->cqe)
- return 0;
-
- /* create new t3_cq with new size */
- cqe = roundup_pow_of_two(cqe+1);
- newcq.size_log2 = ilog2(cqe);
-
- /* Dont allow resize to less than the current wce count */
- if (cqe < Q_COUNT(chp->cq.rptr, chp->cq.wptr)) {
- return -ENOMEM;
- }
-
- /* Quiesce all QPs using this CQ */
- ret = iwch_quiesce_qps(chp);
- if (ret) {
- return ret;
- }
-
- ret = cxio_create_cq(&chp->rhp->rdev, &newcq);
- if (ret) {
- return ret;
- }
-
- /* copy CQEs */
- memcpy(newcq.queue, chp->cq.queue, (1 << chp->cq.size_log2) *
- sizeof(struct t3_cqe));
-
- /* old iwch_qp gets new t3_cq but keeps old cqid */
- oldcq = chp->cq;
- chp->cq = newcq;
- chp->cq.cqid = oldcq.cqid;
-
- /* resize new t3_cq to update the HW context */
- ret = cxio_resize_cq(&chp->rhp->rdev, &chp->cq);
- if (ret) {
- chp->cq = oldcq;
- return ret;
- }
- chp->ibcq.cqe = (1<<chp->cq.size_log2) - 1;
-
- /* destroy old t3_cq */
- oldcq.cqid = newcq.cqid;
- ret = cxio_destroy_cq(&chp->rhp->rdev, &oldcq);
- if (ret) {
- pr_err("%s - cxio_destroy_cq failed %d\n", __func__, ret);
- }
-
- /* add user hooks here */
-
- /* resume qps */
- ret = iwch_resume_qps(chp);
- return ret;
-#else
- return -ENOSYS;
-#endif
+ &chp->cq.dma_addr);
+ return 0;
}
static int iwch_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags)
@@ -422,8 +346,7 @@ static int iwch_dereg_mr(struct ib_mr *ib_mr, struct ib_udata *udata)
xa_erase_irq(&rhp->mrs, mmid);
if (mhp->kva)
kfree((void *) (unsigned long) mhp->kva);
- if (mhp->umem)
- ib_umem_release(mhp->umem);
+ ib_umem_release(mhp->umem);
pr_debug("%s mmid 0x%x ptr %p\n", __func__, mmid, mhp);
kfree(mhp);
return 0;
@@ -553,7 +476,7 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
for_each_sg_dma_page(mhp->umem->sg_head.sgl, &sg_iter, mhp->umem->nmap, 0) {
pages[i++] = cpu_to_be64(sg_page_iter_dma_address(&sg_iter));
- if (i == PAGE_SIZE / sizeof *pages) {
+ if (i == PAGE_SIZE / sizeof(*pages)) {
err = iwch_write_pbl(mhp, pages, i, n);
if (err)
goto pbl_done;
@@ -587,7 +510,7 @@ pbl_done:
pr_debug("%s user resp pbl_addr 0x%x\n", __func__,
uresp.pbl_addr);
- if (ib_copy_to_udata(udata, &uresp, sizeof (uresp))) {
+ if (ib_copy_to_udata(udata, &uresp, sizeof(uresp))) {
iwch_dereg_mr(&mhp->ibmr, udata);
err = -EFAULT;
goto err;
@@ -880,13 +803,13 @@ static struct ib_qp *iwch_create_qp(struct ib_pd *pd,
struct iwch_mm_entry *mm1, *mm2;
- mm1 = kmalloc(sizeof *mm1, GFP_KERNEL);
+ mm1 = kmalloc(sizeof(*mm1), GFP_KERNEL);
if (!mm1) {
iwch_destroy_qp(&qhp->ibqp, udata);
return ERR_PTR(-ENOMEM);
}
- mm2 = kmalloc(sizeof *mm2, GFP_KERNEL);
+ mm2 = kmalloc(sizeof(*mm2), GFP_KERNEL);
if (!mm2) {
kfree(mm1);
iwch_destroy_qp(&qhp->ibqp, udata);
@@ -903,7 +826,7 @@ static struct ib_qp *iwch_create_qp(struct ib_pd *pd,
uresp.db_key = ucontext->key;
ucontext->key += PAGE_SIZE;
spin_unlock(&ucontext->mmap_lock);
- if (ib_copy_to_udata(udata, &uresp, sizeof (uresp))) {
+ if (ib_copy_to_udata(udata, &uresp, sizeof(uresp))) {
kfree(mm1);
kfree(mm2);
iwch_destroy_qp(&qhp->ibqp, udata);
@@ -911,7 +834,7 @@ static struct ib_qp *iwch_create_qp(struct ib_pd *pd,
}
mm1->key = uresp.key;
mm1->addr = virt_to_phys(qhp->wq.queue);
- mm1->len = PAGE_ALIGN(wqsize * sizeof (union t3_wr));
+ mm1->len = PAGE_ALIGN(wqsize * sizeof(union t3_wr));
insert_mmap(ucontext, mm1);
mm2->key = uresp.db_key;
mm2->addr = qhp->wq.udb & PAGE_MASK;
@@ -919,10 +842,11 @@ static struct ib_qp *iwch_create_qp(struct ib_pd *pd,
insert_mmap(ucontext, mm2);
}
qhp->ibqp.qp_num = qhp->wq.qpid;
- pr_debug("%s sq_num_entries %d, rq_num_entries %d qpid 0x%0x qhp %p dma_addr 0x%llx size %d rq_addr 0x%x\n",
- __func__, qhp->attr.sq_num_entries, qhp->attr.rq_num_entries,
- qhp->wq.qpid, qhp, (unsigned long long)qhp->wq.dma_addr,
- 1 << qhp->wq.size_log2, qhp->wq.rq_addr);
+ pr_debug(
+ "%s sq_num_entries %d, rq_num_entries %d qpid 0x%0x qhp %p dma_addr %pad size %d rq_addr 0x%x\n",
+ __func__, qhp->attr.sq_num_entries, qhp->attr.rq_num_entries,
+ qhp->wq.qpid, qhp, &qhp->wq.dma_addr, 1 << qhp->wq.size_log2,
+ qhp->wq.rq_addr);
return &qhp->ibqp;
}
@@ -932,7 +856,7 @@ static int iwch_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
struct iwch_dev *rhp;
struct iwch_qp *qhp;
enum iwch_qp_attr_mask mask = 0;
- struct iwch_qp_attributes attrs;
+ struct iwch_qp_attributes attrs = {};
pr_debug("%s ib_qp %p\n", __func__, ibqp);
@@ -944,7 +868,6 @@ static int iwch_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
if (!attr_mask)
return 0;
- memset(&attrs, 0, sizeof attrs);
qhp = to_iwch_qp(ibqp);
rhp = qhp->rhp;
@@ -1040,7 +963,6 @@ static int iwch_query_device(struct ib_device *ibdev, struct ib_device_attr *pro
return -EINVAL;
dev = to_iwch_dev(ibdev);
- memset(props, 0, sizeof *props);
memcpy(&props->sys_image_guid, dev->rdev.t3cdev_p->lldev->dev_addr, 6);
props->hw_ver = dev->rdev.t3cdev_p->type;
props->fw_ver = fw_vers_string_to_u64(dev);
@@ -1304,6 +1226,11 @@ static void get_dev_fw_ver_str(struct ib_device *ibdev, char *str)
}
static const struct ib_device_ops iwch_dev_ops = {
+ .owner = THIS_MODULE,
+ .driver_id = RDMA_DRIVER_CXGB3,
+ .uverbs_abi_ver = IWCH_UVERBS_ABI_VERSION,
+ .uverbs_no_driver_id_binding = 1,
+
.alloc_hw_stats = iwch_alloc_stats,
.alloc_mr = iwch_alloc_mr,
.alloc_mw = iwch_alloc_mw,
@@ -1341,8 +1268,8 @@ static const struct ib_device_ops iwch_dev_ops = {
.query_port = iwch_query_port,
.reg_user_mr = iwch_reg_user_mr,
.req_notify_cq = iwch_arm_cq,
- .resize_cq = iwch_resize_cq,
INIT_RDMA_OBJ_SIZE(ib_pd, iwch_pd, ibpd),
+ INIT_RDMA_OBJ_SIZE(ib_cq, iwch_cq, ibcq),
INIT_RDMA_OBJ_SIZE(ib_ucontext, iwch_ucontext, ibucontext),
};
@@ -1351,7 +1278,6 @@ int iwch_register_device(struct iwch_dev *dev)
pr_debug("%s iwch_dev %p\n", __func__, dev);
memset(&dev->ibdev.node_guid, 0, sizeof(dev->ibdev.node_guid));
memcpy(&dev->ibdev.node_guid, dev->rdev.t3cdev_p->lldev->dev_addr, 6);
- dev->ibdev.owner = THIS_MODULE;
dev->device_cap_flags = IB_DEVICE_LOCAL_DMA_LKEY |
IB_DEVICE_MEM_WINDOW |
IB_DEVICE_MEM_MGT_EXTENSIONS;
@@ -1383,12 +1309,10 @@ int iwch_register_device(struct iwch_dev *dev)
dev->ibdev.phys_port_cnt = dev->rdev.port_info.nports;
dev->ibdev.num_comp_vectors = 1;
dev->ibdev.dev.parent = &dev->rdev.rnic_info.pdev->dev;
- dev->ibdev.uverbs_abi_ver = IWCH_UVERBS_ABI_VERSION;
memcpy(dev->ibdev.iw_ifname, dev->rdev.t3cdev_p->lldev->name,
sizeof(dev->ibdev.iw_ifname));
- dev->ibdev.driver_id = RDMA_DRIVER_CXGB3;
rdma_set_device_sysfs_group(&dev->ibdev, &iwch_attr_group);
ib_set_device_ops(&dev->ibdev, &iwch_dev_ops);
return ib_register_device(&dev->ibdev, "cxgb3_%d");
diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
index 0f3b1193d5f8..e87fc0408470 100644
--- a/drivers/infiniband/hw/cxgb4/cm.c
+++ b/drivers/infiniband/hw/cxgb4/cm.c
@@ -953,7 +953,7 @@ static int send_mpa_req(struct c4iw_ep *ep, struct sk_buff *skb,
mpalen = sizeof(*mpa) + ep->plen;
if (mpa_rev_to_use == 2)
mpalen += sizeof(struct mpa_v2_conn_params);
- wrlen = roundup(mpalen + sizeof *req, 16);
+ wrlen = roundup(mpalen + sizeof(*req), 16);
skb = get_skb(skb, wrlen, GFP_KERNEL);
if (!skb) {
connect_reply_upcall(ep, -ENOMEM);
@@ -997,8 +997,9 @@ static int send_mpa_req(struct c4iw_ep *ep, struct sk_buff *skb,
}
if (mpa_rev_to_use == 2) {
- mpa->private_data_size = htons(ntohs(mpa->private_data_size) +
- sizeof (struct mpa_v2_conn_params));
+ mpa->private_data_size =
+ htons(ntohs(mpa->private_data_size) +
+ sizeof(struct mpa_v2_conn_params));
pr_debug("initiator ird %u ord %u\n", ep->ird,
ep->ord);
mpa_v2_params.ird = htons((u16)ep->ird);
@@ -1057,7 +1058,7 @@ static int send_mpa_reject(struct c4iw_ep *ep, const void *pdata, u8 plen)
mpalen = sizeof(*mpa) + plen;
if (ep->mpa_attr.version == 2 && ep->mpa_attr.enhanced_rdma_conn)
mpalen += sizeof(struct mpa_v2_conn_params);
- wrlen = roundup(mpalen + sizeof *req, 16);
+ wrlen = roundup(mpalen + sizeof(*req), 16);
skb = get_skb(NULL, wrlen, GFP_KERNEL);
if (!skb) {
@@ -1088,8 +1089,9 @@ static int send_mpa_reject(struct c4iw_ep *ep, const void *pdata, u8 plen)
if (ep->mpa_attr.version == 2 && ep->mpa_attr.enhanced_rdma_conn) {
mpa->flags |= MPA_ENHANCED_RDMA_CONN;
- mpa->private_data_size = htons(ntohs(mpa->private_data_size) +
- sizeof (struct mpa_v2_conn_params));
+ mpa->private_data_size =
+ htons(ntohs(mpa->private_data_size) +
+ sizeof(struct mpa_v2_conn_params));
mpa_v2_params.ird = htons(((u16)ep->ird) |
(peer2peer ? MPA_V2_PEER2PEER_MODEL :
0));
@@ -1136,7 +1138,7 @@ static int send_mpa_reply(struct c4iw_ep *ep, const void *pdata, u8 plen)
mpalen = sizeof(*mpa) + plen;
if (ep->mpa_attr.version == 2 && ep->mpa_attr.enhanced_rdma_conn)
mpalen += sizeof(struct mpa_v2_conn_params);
- wrlen = roundup(mpalen + sizeof *req, 16);
+ wrlen = roundup(mpalen + sizeof(*req), 16);
skb = get_skb(NULL, wrlen, GFP_KERNEL);
if (!skb) {
@@ -1171,8 +1173,9 @@ static int send_mpa_reply(struct c4iw_ep *ep, const void *pdata, u8 plen)
if (ep->mpa_attr.version == 2 && ep->mpa_attr.enhanced_rdma_conn) {
mpa->flags |= MPA_ENHANCED_RDMA_CONN;
- mpa->private_data_size = htons(ntohs(mpa->private_data_size) +
- sizeof (struct mpa_v2_conn_params));
+ mpa->private_data_size =
+ htons(ntohs(mpa->private_data_size) +
+ sizeof(struct mpa_v2_conn_params));
mpa_v2_params.ird = htons((u16)ep->ird);
mpa_v2_params.ord = htons((u16)ep->ord);
if (peer2peer && (ep->mpa_attr.p2p_type !=
@@ -3230,17 +3233,22 @@ static int pick_local_ipaddrs(struct c4iw_dev *dev, struct iw_cm_id *cm_id)
int found = 0;
struct sockaddr_in *laddr = (struct sockaddr_in *)&cm_id->m_local_addr;
struct sockaddr_in *raddr = (struct sockaddr_in *)&cm_id->m_remote_addr;
+ const struct in_ifaddr *ifa;
ind = in_dev_get(dev->rdev.lldi.ports[0]);
if (!ind)
return -EADDRNOTAVAIL;
- for_primary_ifa(ind) {
+ rcu_read_lock();
+ in_dev_for_each_ifa_rcu(ifa, ind) {
+ if (ifa->ifa_flags & IFA_F_SECONDARY)
+ continue;
laddr->sin_addr.s_addr = ifa->ifa_address;
raddr->sin_addr.s_addr = ifa->ifa_address;
found = 1;
break;
}
- endfor_ifa(ind);
+ rcu_read_unlock();
+
in_dev_put(ind);
return found ? 0 : -EADDRNOTAVAIL;
}
diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c
index 52ce586621c6..b1bb61c65f4f 100644
--- a/drivers/infiniband/hw/cxgb4/cq.c
+++ b/drivers/infiniband/hw/cxgb4/cq.c
@@ -34,16 +34,15 @@
#include "iw_cxgb4.h"
-static int destroy_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
- struct c4iw_dev_ucontext *uctx, struct sk_buff *skb,
- struct c4iw_wr_wait *wr_waitp)
+static void destroy_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
+ struct c4iw_dev_ucontext *uctx, struct sk_buff *skb,
+ struct c4iw_wr_wait *wr_waitp)
{
struct fw_ri_res_wr *res_wr;
struct fw_ri_res *res;
int wr_len;
- int ret;
- wr_len = sizeof *res_wr + sizeof *res;
+ wr_len = sizeof(*res_wr) + sizeof(*res);
set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0);
res_wr = __skb_put_zero(skb, wr_len);
@@ -59,14 +58,13 @@ static int destroy_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
res->u.cq.iqid = cpu_to_be32(cq->cqid);
c4iw_init_wr_wait(wr_waitp);
- ret = c4iw_ref_send_wait(rdev, skb, wr_waitp, 0, 0, __func__);
+ c4iw_ref_send_wait(rdev, skb, wr_waitp, 0, 0, __func__);
kfree(cq->sw_queue);
dma_free_coherent(&(rdev->lldi.pdev->dev),
cq->memsize, cq->queue,
dma_unmap_addr(cq, mapping));
c4iw_put_cqid(rdev, cq->cqid, uctx);
- return ret;
}
static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
@@ -104,7 +102,6 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
goto err3;
}
dma_unmap_addr_set(cq, mapping, cq->dma_addr);
- memset(cq->queue, 0, cq->memsize);
if (user && ucontext->is_32b_cqe) {
cq->qp_errp = &((struct t4_status_page *)
@@ -117,7 +114,7 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
}
/* build fw_ri_res_wr */
- wr_len = sizeof *res_wr + sizeof *res;
+ wr_len = sizeof(*res_wr) + sizeof(*res);
skb = alloc_skb(wr_len, GFP_KERNEL);
if (!skb) {
@@ -970,7 +967,7 @@ int c4iw_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc)
return !err || err == -ENODATA ? npolled : err;
}
-int c4iw_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)
+void c4iw_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)
{
struct c4iw_cq *chp;
struct c4iw_ucontext *ucontext;
@@ -988,18 +985,16 @@ int c4iw_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)
ucontext ? &ucontext->uctx : &chp->cq.rdev->uctx,
chp->destroy_skb, chp->wr_waitp);
c4iw_put_wr_wait(chp->wr_waitp);
- kfree(chp);
- return 0;
}
-struct ib_cq *c4iw_create_cq(struct ib_device *ibdev,
- const struct ib_cq_init_attr *attr,
- struct ib_udata *udata)
+int c4iw_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata)
{
+ struct ib_device *ibdev = ibcq->device;
int entries = attr->cqe;
int vector = attr->comp_vector;
- struct c4iw_dev *rhp;
- struct c4iw_cq *chp;
+ struct c4iw_dev *rhp = to_c4iw_dev(ibcq->device);
+ struct c4iw_cq *chp = to_c4iw_cq(ibcq);
struct c4iw_create_cq ucmd;
struct c4iw_create_cq_resp uresp;
int ret, wr_len;
@@ -1010,22 +1005,16 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev,
pr_debug("ib_dev %p entries %d\n", ibdev, entries);
if (attr->flags)
- return ERR_PTR(-EINVAL);
-
- rhp = to_c4iw_dev(ibdev);
+ return -EINVAL;
if (vector >= rhp->rdev.lldi.nciq)
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
if (udata) {
if (udata->inlen < sizeof(ucmd))
ucontext->is_32b_cqe = 1;
}
- chp = kzalloc(sizeof(*chp), GFP_KERNEL);
- if (!chp)
- return ERR_PTR(-ENOMEM);
-
chp->wr_waitp = c4iw_alloc_wr_wait(GFP_KERNEL);
if (!chp->wr_waitp) {
ret = -ENOMEM;
@@ -1095,10 +1084,10 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev,
if (ucontext) {
ret = -ENOMEM;
- mm = kmalloc(sizeof *mm, GFP_KERNEL);
+ mm = kmalloc(sizeof(*mm), GFP_KERNEL);
if (!mm)
goto err_remove_handle;
- mm2 = kmalloc(sizeof *mm2, GFP_KERNEL);
+ mm2 = kmalloc(sizeof(*mm2), GFP_KERNEL);
if (!mm2)
goto err_free_mm;
@@ -1135,10 +1124,11 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev,
mm2->len = PAGE_SIZE;
insert_mmap(ucontext, mm2);
}
- pr_debug("cqid 0x%0x chp %p size %u memsize %zu, dma_addr 0x%0llx\n",
- chp->cq.cqid, chp, chp->cq.size,
- chp->cq.memsize, (unsigned long long)chp->cq.dma_addr);
- return &chp->ibcq;
+
+ pr_debug("cqid 0x%0x chp %p size %u memsize %zu, dma_addr %pad\n",
+ chp->cq.cqid, chp, chp->cq.size, chp->cq.memsize,
+ &chp->cq.dma_addr);
+ return 0;
err_free_mm2:
kfree(mm2);
err_free_mm:
@@ -1154,8 +1144,7 @@ err_free_skb:
err_free_wr_wait:
c4iw_put_wr_wait(chp->wr_waitp);
err_free_chp:
- kfree(chp);
- return ERR_PTR(ret);
+ return ret;
}
int c4iw_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags)
diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c
index 4c0d925c5ff5..a8b9548bd1a2 100644
--- a/drivers/infiniband/hw/cxgb4/device.c
+++ b/drivers/infiniband/hw/cxgb4/device.c
@@ -327,7 +327,7 @@ static int qp_open(struct inode *inode, struct file *file)
unsigned long index;
int count = 1;
- qpd = kmalloc(sizeof *qpd, GFP_KERNEL);
+ qpd = kmalloc(sizeof(*qpd), GFP_KERNEL);
if (!qpd)
return -ENOMEM;
@@ -421,7 +421,7 @@ static int stag_open(struct inode *inode, struct file *file)
int ret = 0;
int count = 1;
- stagd = kmalloc(sizeof *stagd, GFP_KERNEL);
+ stagd = kmalloc(sizeof(*stagd), GFP_KERNEL);
if (!stagd) {
ret = -ENOMEM;
goto out;
@@ -1075,7 +1075,7 @@ static void *c4iw_uld_add(const struct cxgb4_lld_info *infop)
pr_info("Chelsio T4/T5 RDMA Driver - version %s\n",
DRV_VERSION);
- ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx) {
ctx = ERR_PTR(-ENOMEM);
goto out;
@@ -1243,10 +1243,9 @@ static int c4iw_uld_state_change(void *handle, enum cxgb4_state new_state)
case CXGB4_STATE_START_RECOVERY:
pr_info("%s: Fatal Error\n", pci_name(ctx->lldi.pdev));
if (ctx->dev) {
- struct ib_event event;
+ struct ib_event event = {};
ctx->dev->rdev.flags |= T4_FATAL_ERROR;
- memset(&event, 0, sizeof event);
event.event = IB_EVENT_DEVICE_FATAL;
event.device = &ctx->dev->ibdev;
ib_dispatch_event(&event);
diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
index 916ef982172e..7d06b0f8d49a 100644
--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
@@ -490,13 +490,13 @@ struct c4iw_qp {
struct t4_wq wq;
spinlock_t lock;
struct mutex mutex;
- struct kref kref;
wait_queue_head_t wait;
int sq_sig_all;
struct c4iw_srq *srq;
- struct work_struct free_work;
struct c4iw_ucontext *ucontext;
struct c4iw_wr_wait *wr_waitp;
+ struct completion qp_rel_comp;
+ refcount_t qp_refcnt;
};
static inline struct c4iw_qp *to_c4iw_qp(struct ib_qp *ibqp)
@@ -992,10 +992,9 @@ struct ib_mr *c4iw_reg_user_mr(struct ib_pd *pd, u64 start,
struct ib_udata *udata);
struct ib_mr *c4iw_get_dma_mr(struct ib_pd *pd, int acc);
int c4iw_dereg_mr(struct ib_mr *ib_mr, struct ib_udata *udata);
-int c4iw_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata);
-struct ib_cq *c4iw_create_cq(struct ib_device *ibdev,
- const struct ib_cq_init_attr *attr,
- struct ib_udata *udata);
+void c4iw_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata);
+int c4iw_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata);
int c4iw_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags);
int c4iw_modify_srq(struct ib_srq *ib_srq, struct ib_srq_attr *attr,
enum ib_srq_attr_mask srq_attr_mask,
diff --git a/drivers/infiniband/hw/cxgb4/mem.c b/drivers/infiniband/hw/cxgb4/mem.c
index 811c0c8c5b16..aa772ee0706f 100644
--- a/drivers/infiniband/hw/cxgb4/mem.c
+++ b/drivers/infiniband/hw/cxgb4/mem.c
@@ -130,8 +130,9 @@ static int _c4iw_write_mem_inline(struct c4iw_rdev *rdev, u32 addr, u32 len,
copy_len = len > C4IW_MAX_INLINE_SIZE ? C4IW_MAX_INLINE_SIZE :
len;
- wr_len = roundup(sizeof *req + sizeof *sc +
- roundup(copy_len, T4_ULPTX_MIN_IO), 16);
+ wr_len = roundup(sizeof(*req) + sizeof(*sc) +
+ roundup(copy_len, T4_ULPTX_MIN_IO),
+ 16);
if (!skb) {
skb = alloc_skb(wr_len, GFP_KERNEL | __GFP_NOFAIL);
@@ -807,8 +808,7 @@ int c4iw_dereg_mr(struct ib_mr *ib_mr, struct ib_udata *udata)
mhp->attr.pbl_size << 3);
if (mhp->kva)
kfree((void *) (unsigned long) mhp->kva);
- if (mhp->umem)
- ib_umem_release(mhp->umem);
+ ib_umem_release(mhp->umem);
pr_debug("mmid 0x%x ptr %p\n", mmid, mhp);
c4iw_put_wr_wait(mhp->wr_waitp);
kfree(mhp);
diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c
index 74b795642fca..5e59c5708729 100644
--- a/drivers/infiniband/hw/cxgb4/provider.c
+++ b/drivers/infiniband/hw/cxgb4/provider.c
@@ -271,7 +271,6 @@ static int c4iw_query_device(struct ib_device *ibdev, struct ib_device_attr *pro
return -EINVAL;
dev = to_c4iw_dev(ibdev);
- memset(props, 0, sizeof *props);
memcpy(&props->sys_image_guid, dev->rdev.lldi.ports[0]->dev_addr, 6);
props->hw_ver = CHELSIO_CHIP_RELEASE(dev->rdev.lldi.adapter_type);
props->fw_ver = dev->rdev.lldi.fw_vers;
@@ -490,6 +489,10 @@ static int fill_res_entry(struct sk_buff *msg, struct rdma_restrack_entry *res)
}
static const struct ib_device_ops c4iw_dev_ops = {
+ .owner = THIS_MODULE,
+ .driver_id = RDMA_DRIVER_CXGB4,
+ .uverbs_abi_ver = C4IW_UVERBS_ABI_VERSION,
+
.alloc_hw_stats = c4iw_alloc_stats,
.alloc_mr = c4iw_alloc_mr,
.alloc_mw = c4iw_alloc_mw,
@@ -534,6 +537,7 @@ static const struct ib_device_ops c4iw_dev_ops = {
.reg_user_mr = c4iw_reg_user_mr,
.req_notify_cq = c4iw_arm_cq,
INIT_RDMA_OBJ_SIZE(ib_pd, c4iw_pd, ibpd),
+ INIT_RDMA_OBJ_SIZE(ib_cq, c4iw_cq, ibcq),
INIT_RDMA_OBJ_SIZE(ib_srq, c4iw_srq, ibsrq),
INIT_RDMA_OBJ_SIZE(ib_ucontext, c4iw_ucontext, ibucontext),
};
@@ -561,7 +565,6 @@ void c4iw_register_device(struct work_struct *work)
pr_debug("c4iw_dev %p\n", dev);
memset(&dev->ibdev.node_guid, 0, sizeof(dev->ibdev.node_guid));
memcpy(&dev->ibdev.node_guid, dev->rdev.lldi.ports[0]->dev_addr, 6);
- dev->ibdev.owner = THIS_MODULE;
dev->device_cap_flags = IB_DEVICE_LOCAL_DMA_LKEY | IB_DEVICE_MEM_WINDOW;
if (fastreg_support)
dev->device_cap_flags |= IB_DEVICE_MEM_MGT_EXTENSIONS;
@@ -594,13 +597,11 @@ void c4iw_register_device(struct work_struct *work)
dev->ibdev.phys_port_cnt = dev->rdev.lldi.nports;
dev->ibdev.num_comp_vectors = dev->rdev.lldi.nciq;
dev->ibdev.dev.parent = &dev->rdev.lldi.pdev->dev;
- dev->ibdev.uverbs_abi_ver = C4IW_UVERBS_ABI_VERSION;
memcpy(dev->ibdev.iw_ifname, dev->rdev.lldi.ports[0]->name,
sizeof(dev->ibdev.iw_ifname));
rdma_set_device_sysfs_group(&dev->ibdev, &c4iw_attr_group);
- dev->ibdev.driver_id = RDMA_DRIVER_CXGB4;
ib_set_device_ops(&dev->ibdev, &c4iw_dev_ops);
ret = set_netdevs(&dev->ibdev, &dev->rdev);
if (ret)
diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c
index e92b9544357a..eb9368be28c1 100644
--- a/drivers/infiniband/hw/cxgb4/qp.c
+++ b/drivers/infiniband/hw/cxgb4/qp.c
@@ -274,7 +274,6 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
(unsigned long long)virt_to_phys(wq->sq.queue),
wq->rq.queue,
(unsigned long long)virt_to_phys(wq->rq.queue));
- memset(wq->rq.queue, 0, wq->rq.memsize);
dma_unmap_addr_set(&wq->rq, mapping, wq->rq.dma_addr);
}
@@ -303,7 +302,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
wq->rq.msn = 1;
/* build fw_ri_res_wr */
- wr_len = sizeof *res_wr + 2 * sizeof *res;
+ wr_len = sizeof(*res_wr) + 2 * sizeof(*res);
if (need_rq)
wr_len += sizeof(*res);
skb = alloc_skb(wr_len, GFP_KERNEL);
@@ -439,7 +438,7 @@ static int build_immd(struct t4_sq *sq, struct fw_ri_immd *immdp,
rem -= len;
}
}
- len = roundup(plen + sizeof *immdp, 16) - (plen + sizeof *immdp);
+ len = roundup(plen + sizeof(*immdp), 16) - (plen + sizeof(*immdp));
if (len)
memset(dstp, 0, len);
immdp->op = FW_RI_DATA_IMMD;
@@ -528,7 +527,7 @@ static int build_rdma_send(struct t4_sq *sq, union t4_wr *wqe,
T4_MAX_SEND_INLINE, &plen);
if (ret)
return ret;
- size = sizeof wqe->send + sizeof(struct fw_ri_immd) +
+ size = sizeof(wqe->send) + sizeof(struct fw_ri_immd) +
plen;
} else {
ret = build_isgl((__be64 *)sq->queue,
@@ -537,7 +536,7 @@ static int build_rdma_send(struct t4_sq *sq, union t4_wr *wqe,
wr->sg_list, wr->num_sge, &plen);
if (ret)
return ret;
- size = sizeof wqe->send + sizeof(struct fw_ri_isgl) +
+ size = sizeof(wqe->send) + sizeof(struct fw_ri_isgl) +
wr->num_sge * sizeof(struct fw_ri_sge);
}
} else {
@@ -545,7 +544,7 @@ static int build_rdma_send(struct t4_sq *sq, union t4_wr *wqe,
wqe->send.u.immd_src[0].r1 = 0;
wqe->send.u.immd_src[0].r2 = 0;
wqe->send.u.immd_src[0].immdlen = 0;
- size = sizeof wqe->send + sizeof(struct fw_ri_immd);
+ size = sizeof(wqe->send) + sizeof(struct fw_ri_immd);
plen = 0;
}
*len16 = DIV_ROUND_UP(size, 16);
@@ -579,7 +578,7 @@ static int build_rdma_write(struct t4_sq *sq, union t4_wr *wqe,
T4_MAX_WRITE_INLINE, &plen);
if (ret)
return ret;
- size = sizeof wqe->write + sizeof(struct fw_ri_immd) +
+ size = sizeof(wqe->write) + sizeof(struct fw_ri_immd) +
plen;
} else {
ret = build_isgl((__be64 *)sq->queue,
@@ -588,7 +587,7 @@ static int build_rdma_write(struct t4_sq *sq, union t4_wr *wqe,
wr->sg_list, wr->num_sge, &plen);
if (ret)
return ret;
- size = sizeof wqe->write + sizeof(struct fw_ri_isgl) +
+ size = sizeof(wqe->write) + sizeof(struct fw_ri_isgl) +
wr->num_sge * sizeof(struct fw_ri_sge);
}
} else {
@@ -596,7 +595,7 @@ static int build_rdma_write(struct t4_sq *sq, union t4_wr *wqe,
wqe->write.u.immd_src[0].r1 = 0;
wqe->write.u.immd_src[0].r2 = 0;
wqe->write.u.immd_src[0].immdlen = 0;
- size = sizeof wqe->write + sizeof(struct fw_ri_immd);
+ size = sizeof(wqe->write) + sizeof(struct fw_ri_immd);
plen = 0;
}
*len16 = DIV_ROUND_UP(size, 16);
@@ -683,7 +682,7 @@ static int build_rdma_read(union t4_wr *wqe, const struct ib_send_wr *wr,
}
wqe->read.r2 = 0;
wqe->read.r5 = 0;
- *len16 = DIV_ROUND_UP(sizeof wqe->read, 16);
+ *len16 = DIV_ROUND_UP(sizeof(wqe->read), 16);
return 0;
}
@@ -766,8 +765,8 @@ static int build_rdma_recv(struct c4iw_qp *qhp, union t4_recv_wr *wqe,
&wqe->recv.isgl, wr->sg_list, wr->num_sge, NULL);
if (ret)
return ret;
- *len16 = DIV_ROUND_UP(sizeof wqe->recv +
- wr->num_sge * sizeof(struct fw_ri_sge), 16);
+ *len16 = DIV_ROUND_UP(
+ sizeof(wqe->recv) + wr->num_sge * sizeof(struct fw_ri_sge), 16);
return 0;
}
@@ -886,47 +885,21 @@ static int build_inv_stag(union t4_wr *wqe, const struct ib_send_wr *wr,
{
wqe->inv.stag_inv = cpu_to_be32(wr->ex.invalidate_rkey);
wqe->inv.r2 = 0;
- *len16 = DIV_ROUND_UP(sizeof wqe->inv, 16);
+ *len16 = DIV_ROUND_UP(sizeof(wqe->inv), 16);
return 0;
}
-static void free_qp_work(struct work_struct *work)
-{
- struct c4iw_ucontext *ucontext;
- struct c4iw_qp *qhp;
- struct c4iw_dev *rhp;
-
- qhp = container_of(work, struct c4iw_qp, free_work);
- ucontext = qhp->ucontext;
- rhp = qhp->rhp;
-
- pr_debug("qhp %p ucontext %p\n", qhp, ucontext);
- destroy_qp(&rhp->rdev, &qhp->wq,
- ucontext ? &ucontext->uctx : &rhp->rdev.uctx, !qhp->srq);
-
- c4iw_put_wr_wait(qhp->wr_waitp);
- kfree(qhp);
-}
-
-static void queue_qp_free(struct kref *kref)
-{
- struct c4iw_qp *qhp;
-
- qhp = container_of(kref, struct c4iw_qp, kref);
- pr_debug("qhp %p\n", qhp);
- queue_work(qhp->rhp->rdev.free_workq, &qhp->free_work);
-}
-
void c4iw_qp_add_ref(struct ib_qp *qp)
{
pr_debug("ib_qp %p\n", qp);
- kref_get(&to_c4iw_qp(qp)->kref);
+ refcount_inc(&to_c4iw_qp(qp)->qp_refcnt);
}
void c4iw_qp_rem_ref(struct ib_qp *qp)
{
pr_debug("ib_qp %p\n", qp);
- kref_put(&to_c4iw_qp(qp)->kref, queue_qp_free);
+ if (refcount_dec_and_test(&to_c4iw_qp(qp)->qp_refcnt))
+ complete(&to_c4iw_qp(qp)->qp_rel_comp);
}
static void add_to_fc_list(struct list_head *head, struct list_head *entry)
@@ -1606,7 +1579,7 @@ static void post_terminate(struct c4iw_qp *qhp, struct t4_cqe *err_cqe,
FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*wqe), 16)));
wqe->u.terminate.type = FW_RI_TYPE_TERMINATE;
- wqe->u.terminate.immdlen = cpu_to_be32(sizeof *term);
+ wqe->u.terminate.immdlen = cpu_to_be32(sizeof(*term));
term = (struct terminate_message *)wqe->u.terminate.termmsg;
if (qhp->attr.layer_etype == (LAYER_MPA|DDP_LLP)) {
term->layer_etype = qhp->attr.layer_etype;
@@ -1751,16 +1724,15 @@ static int rdma_fini(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
static void build_rtr_msg(u8 p2p_type, struct fw_ri_init *init)
{
pr_debug("p2p_type = %d\n", p2p_type);
- memset(&init->u, 0, sizeof init->u);
+ memset(&init->u, 0, sizeof(init->u));
switch (p2p_type) {
case FW_RI_INIT_P2PTYPE_RDMA_WRITE:
init->u.write.opcode = FW_RI_RDMA_WRITE_WR;
init->u.write.stag_sink = cpu_to_be32(1);
init->u.write.to_sink = cpu_to_be64(1);
init->u.write.u.immd_src[0].op = FW_RI_DATA_IMMD;
- init->u.write.len16 = DIV_ROUND_UP(sizeof init->u.write +
- sizeof(struct fw_ri_immd),
- 16);
+ init->u.write.len16 = DIV_ROUND_UP(
+ sizeof(init->u.write) + sizeof(struct fw_ri_immd), 16);
break;
case FW_RI_INIT_P2PTYPE_READ_REQ:
init->u.write.opcode = FW_RI_RDMA_READ_WR;
@@ -1768,7 +1740,7 @@ static void build_rtr_msg(u8 p2p_type, struct fw_ri_init *init)
init->u.read.to_src_lo = cpu_to_be32(1);
init->u.read.stag_sink = cpu_to_be32(1);
init->u.read.to_sink_lo = cpu_to_be32(1);
- init->u.read.len16 = DIV_ROUND_UP(sizeof init->u.read, 16);
+ init->u.read.len16 = DIV_ROUND_UP(sizeof(init->u.read), 16);
break;
}
}
@@ -1782,7 +1754,7 @@ static int rdma_init(struct c4iw_dev *rhp, struct c4iw_qp *qhp)
pr_debug("qhp %p qid 0x%x tid %u ird %u ord %u\n", qhp,
qhp->wq.sq.qid, qhp->ep->hwtid, qhp->ep->ird, qhp->ep->ord);
- skb = alloc_skb(sizeof *wqe, GFP_KERNEL);
+ skb = alloc_skb(sizeof(*wqe), GFP_KERNEL);
if (!skb) {
ret = -ENOMEM;
goto out;
@@ -2099,10 +2071,12 @@ int c4iw_destroy_qp(struct ib_qp *ib_qp, struct ib_udata *udata)
{
struct c4iw_dev *rhp;
struct c4iw_qp *qhp;
+ struct c4iw_ucontext *ucontext;
struct c4iw_qp_attributes attrs;
qhp = to_c4iw_qp(ib_qp);
rhp = qhp->rhp;
+ ucontext = qhp->ucontext;
attrs.next_state = C4IW_QP_STATE_ERROR;
if (qhp->attr.state == C4IW_QP_STATE_TERMINATE)
@@ -2120,7 +2094,17 @@ int c4iw_destroy_qp(struct ib_qp *ib_qp, struct ib_udata *udata)
c4iw_qp_rem_ref(ib_qp);
+ wait_for_completion(&qhp->qp_rel_comp);
+
pr_debug("ib_qp %p qpid 0x%0x\n", ib_qp, qhp->wq.sq.qid);
+ pr_debug("qhp %p ucontext %p\n", qhp, ucontext);
+
+ destroy_qp(&rhp->rdev, &qhp->wq,
+ ucontext ? &ucontext->uctx : &rhp->rdev.uctx, !qhp->srq);
+
+ c4iw_put_wr_wait(qhp->wr_waitp);
+
+ kfree(qhp);
return 0;
}
@@ -2230,8 +2214,8 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
spin_lock_init(&qhp->lock);
mutex_init(&qhp->mutex);
init_waitqueue_head(&qhp->wait);
- kref_init(&qhp->kref);
- INIT_WORK(&qhp->free_work, free_qp_work);
+ init_completion(&qhp->qp_rel_comp);
+ refcount_set(&qhp->qp_refcnt, 1);
ret = xa_insert_irq(&rhp->qps, qhp->wq.sq.qid, qhp, GFP_KERNEL);
if (ret)
@@ -2302,7 +2286,7 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
ucontext->key += PAGE_SIZE;
}
spin_unlock(&ucontext->mmap_lock);
- ret = ib_copy_to_udata(udata, &uresp, sizeof uresp);
+ ret = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
if (ret)
goto err_free_ma_sync_key;
sq_key_mm->key = uresp.sq_key;
@@ -2386,7 +2370,7 @@ int c4iw_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
struct c4iw_dev *rhp;
struct c4iw_qp *qhp;
enum c4iw_qp_attr_mask mask = 0;
- struct c4iw_qp_attributes attrs;
+ struct c4iw_qp_attributes attrs = {};
pr_debug("ib_qp %p\n", ibqp);
@@ -2398,7 +2382,6 @@ int c4iw_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
if (!attr_mask)
return 0;
- memset(&attrs, 0, sizeof attrs);
qhp = to_c4iw_qp(ibqp);
rhp = qhp->rhp;
@@ -2482,8 +2465,8 @@ int c4iw_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
{
struct c4iw_qp *qhp = to_c4iw_qp(ibqp);
- memset(attr, 0, sizeof *attr);
- memset(init_attr, 0, sizeof *init_attr);
+ memset(attr, 0, sizeof(*attr));
+ memset(init_attr, 0, sizeof(*init_attr));
attr->qp_state = to_ib_qp_state(qhp->attr.state);
init_attr->cap.max_send_wr = qhp->attr.sq_num_entries;
init_attr->cap.max_recv_wr = qhp->attr.rq_num_entries;
diff --git a/drivers/infiniband/hw/cxgb4/resource.c b/drivers/infiniband/hw/cxgb4/resource.c
index 57ed26b3cc21..5c95c789f302 100644
--- a/drivers/infiniband/hw/cxgb4/resource.c
+++ b/drivers/infiniband/hw/cxgb4/resource.c
@@ -126,7 +126,7 @@ u32 c4iw_get_cqid(struct c4iw_rdev *rdev, struct c4iw_dev_ucontext *uctx)
rdev->stats.qid.cur += rdev->qpmask + 1;
mutex_unlock(&rdev->stats.lock);
for (i = qid+1; i & rdev->qpmask; i++) {
- entry = kmalloc(sizeof *entry, GFP_KERNEL);
+ entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry)
goto out;
entry->qid = i;
@@ -137,13 +137,13 @@ u32 c4iw_get_cqid(struct c4iw_rdev *rdev, struct c4iw_dev_ucontext *uctx)
* now put the same ids on the qp list since they all
* map to the same db/gts page.
*/
- entry = kmalloc(sizeof *entry, GFP_KERNEL);
+ entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry)
goto out;
entry->qid = qid;
list_add_tail(&entry->entry, &uctx->qpids);
for (i = qid+1; i & rdev->qpmask; i++) {
- entry = kmalloc(sizeof *entry, GFP_KERNEL);
+ entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry)
goto out;
entry->qid = i;
@@ -165,7 +165,7 @@ void c4iw_put_cqid(struct c4iw_rdev *rdev, u32 qid,
{
struct c4iw_qid_list *entry;
- entry = kmalloc(sizeof *entry, GFP_KERNEL);
+ entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry)
return;
pr_debug("qid 0x%x\n", qid);
@@ -200,7 +200,7 @@ u32 c4iw_get_qpid(struct c4iw_rdev *rdev, struct c4iw_dev_ucontext *uctx)
rdev->stats.qid.cur += rdev->qpmask + 1;
mutex_unlock(&rdev->stats.lock);
for (i = qid+1; i & rdev->qpmask; i++) {
- entry = kmalloc(sizeof *entry, GFP_KERNEL);
+ entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry)
goto out;
entry->qid = i;
@@ -211,13 +211,13 @@ u32 c4iw_get_qpid(struct c4iw_rdev *rdev, struct c4iw_dev_ucontext *uctx)
* now put the same ids on the cq list since they all
* map to the same db/gts page.
*/
- entry = kmalloc(sizeof *entry, GFP_KERNEL);
+ entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry)
goto out;
entry->qid = qid;
list_add_tail(&entry->entry, &uctx->cqids);
for (i = qid; i & rdev->qpmask; i++) {
- entry = kmalloc(sizeof *entry, GFP_KERNEL);
+ entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry)
goto out;
entry->qid = i;
@@ -239,7 +239,7 @@ void c4iw_put_qpid(struct c4iw_rdev *rdev, u32 qid,
{
struct c4iw_qid_list *entry;
- entry = kmalloc(sizeof *entry, GFP_KERNEL);
+ entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry)
return;
pr_debug("qid 0x%x\n", qid);
diff --git a/drivers/infiniband/hw/efa/efa.h b/drivers/infiniband/hw/efa/efa.h
index 9e3cc3239c13..119f8efec564 100644
--- a/drivers/infiniband/hw/efa/efa.h
+++ b/drivers/infiniband/hw/efa/efa.h
@@ -7,10 +7,8 @@
#define _EFA_H_
#include <linux/bitops.h>
-#include <linux/idr.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
-#include <linux/sched.h>
#include <rdma/efa-abi.h>
#include <rdma/ib_verbs.h>
@@ -136,10 +134,9 @@ int efa_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata);
struct ib_qp *efa_create_qp(struct ib_pd *ibpd,
struct ib_qp_init_attr *init_attr,
struct ib_udata *udata);
-int efa_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata);
-struct ib_cq *efa_create_cq(struct ib_device *ibdev,
- const struct ib_cq_init_attr *attr,
- struct ib_udata *udata);
+void efa_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata);
+int efa_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata);
struct ib_mr *efa_reg_mr(struct ib_pd *ibpd, u64 start, u64 length,
u64 virt_addr, int access_flags,
struct ib_udata *udata);
diff --git a/drivers/infiniband/hw/efa/efa_com.c b/drivers/infiniband/hw/efa/efa_com.c
index a5c788741a04..2cb42484b0f8 100644
--- a/drivers/infiniband/hw/efa/efa_com.c
+++ b/drivers/infiniband/hw/efa/efa_com.c
@@ -39,8 +39,6 @@
enum efa_cmd_status {
EFA_CMD_SUBMITTED,
EFA_CMD_COMPLETED,
- /* Abort - canceled by the driver */
- EFA_CMD_ABORTED,
};
struct efa_comp_ctx {
@@ -280,36 +278,34 @@ static void efa_com_dealloc_ctx_id(struct efa_com_admin_queue *aq,
static inline void efa_com_put_comp_ctx(struct efa_com_admin_queue *aq,
struct efa_comp_ctx *comp_ctx)
{
- u16 comp_id = comp_ctx->user_cqe->acq_common_descriptor.command &
- EFA_ADMIN_ACQ_COMMON_DESC_COMMAND_ID_MASK;
+ u16 cmd_id = comp_ctx->user_cqe->acq_common_descriptor.command &
+ EFA_ADMIN_ACQ_COMMON_DESC_COMMAND_ID_MASK;
+ u16 ctx_id = cmd_id & (aq->depth - 1);
- ibdev_dbg(aq->efa_dev, "Putting completion command_id %d\n", comp_id);
+ ibdev_dbg(aq->efa_dev, "Put completion command_id %#x\n", cmd_id);
comp_ctx->occupied = 0;
- efa_com_dealloc_ctx_id(aq, comp_id);
+ efa_com_dealloc_ctx_id(aq, ctx_id);
}
static struct efa_comp_ctx *efa_com_get_comp_ctx(struct efa_com_admin_queue *aq,
- u16 command_id, bool capture)
+ u16 cmd_id, bool capture)
{
- if (command_id >= aq->depth) {
- ibdev_err(aq->efa_dev,
- "command id is larger than the queue size. cmd_id: %u queue size %d\n",
- command_id, aq->depth);
- return NULL;
- }
+ u16 ctx_id = cmd_id & (aq->depth - 1);
- if (aq->comp_ctx[command_id].occupied && capture) {
- ibdev_err(aq->efa_dev, "Completion context is occupied\n");
+ if (aq->comp_ctx[ctx_id].occupied && capture) {
+ ibdev_err(aq->efa_dev,
+ "Completion context for command_id %#x is occupied\n",
+ cmd_id);
return NULL;
}
if (capture) {
- aq->comp_ctx[command_id].occupied = 1;
- ibdev_dbg(aq->efa_dev, "Taking completion ctxt command_id %d\n",
- command_id);
+ aq->comp_ctx[ctx_id].occupied = 1;
+ ibdev_dbg(aq->efa_dev,
+ "Take completion ctxt for command_id %#x\n", cmd_id);
}
- return &aq->comp_ctx[command_id];
+ return &aq->comp_ctx[ctx_id];
}
static struct efa_comp_ctx *__efa_com_submit_admin_cmd(struct efa_com_admin_queue *aq,
@@ -320,6 +316,7 @@ static struct efa_comp_ctx *__efa_com_submit_admin_cmd(struct efa_com_admin_queu
{
struct efa_comp_ctx *comp_ctx;
u16 queue_size_mask;
+ u16 cmd_id;
u16 ctx_id;
u16 pi;
@@ -328,13 +325,16 @@ static struct efa_comp_ctx *__efa_com_submit_admin_cmd(struct efa_com_admin_queu
ctx_id = efa_com_alloc_ctx_id(aq);
+ /* cmd_id LSBs are the ctx_id and MSBs are entropy bits from pc */
+ cmd_id = ctx_id & queue_size_mask;
+ cmd_id |= aq->sq.pc & ~queue_size_mask;
+ cmd_id &= EFA_ADMIN_AQ_COMMON_DESC_COMMAND_ID_MASK;
+
+ cmd->aq_common_descriptor.command_id = cmd_id;
cmd->aq_common_descriptor.flags |= aq->sq.phase &
EFA_ADMIN_AQ_COMMON_DESC_PHASE_MASK;
- cmd->aq_common_descriptor.command_id |= ctx_id &
- EFA_ADMIN_AQ_COMMON_DESC_COMMAND_ID_MASK;
-
- comp_ctx = efa_com_get_comp_ctx(aq, ctx_id, true);
+ comp_ctx = efa_com_get_comp_ctx(aq, cmd_id, true);
if (!comp_ctx) {
efa_com_dealloc_ctx_id(aq, ctx_id);
return ERR_PTR(-EINVAL);
@@ -532,16 +532,6 @@ static int efa_com_wait_and_process_admin_cq_polling(struct efa_comp_ctx *comp_c
msleep(aq->poll_interval);
}
- if (comp_ctx->status == EFA_CMD_ABORTED) {
- ibdev_err(aq->efa_dev, "Command was aborted\n");
- atomic64_inc(&aq->stats.aborted_cmd);
- err = -ENODEV;
- goto out;
- }
-
- WARN_ONCE(comp_ctx->status != EFA_CMD_COMPLETED,
- "Invalid completion status %d\n", comp_ctx->status);
-
err = efa_com_comp_status_to_errno(comp_ctx->comp_status);
out:
efa_com_put_comp_ctx(aq, comp_ctx);
@@ -666,66 +656,6 @@ int efa_com_cmd_exec(struct efa_com_admin_queue *aq,
}
/**
- * efa_com_abort_admin_commands - Abort all the outstanding admin commands.
- * @edev: EFA communication layer struct
- *
- * This method aborts all the outstanding admin commands.
- * The caller should then call efa_com_wait_for_abort_completion to make sure
- * all the commands were completed.
- */
-static void efa_com_abort_admin_commands(struct efa_com_dev *edev)
-{
- struct efa_com_admin_queue *aq = &edev->aq;
- struct efa_comp_ctx *comp_ctx;
- unsigned long flags;
- u16 i;
-
- spin_lock(&aq->sq.lock);
- spin_lock_irqsave(&aq->cq.lock, flags);
- for (i = 0; i < aq->depth; i++) {
- comp_ctx = efa_com_get_comp_ctx(aq, i, false);
- if (!comp_ctx)
- break;
-
- comp_ctx->status = EFA_CMD_ABORTED;
-
- complete(&comp_ctx->wait_event);
- }
- spin_unlock_irqrestore(&aq->cq.lock, flags);
- spin_unlock(&aq->sq.lock);
-}
-
-/**
- * efa_com_wait_for_abort_completion - Wait for admin commands abort.
- * @edev: EFA communication layer struct
- *
- * This method wait until all the outstanding admin commands will be completed.
- */
-static void efa_com_wait_for_abort_completion(struct efa_com_dev *edev)
-{
- struct efa_com_admin_queue *aq = &edev->aq;
- int i;
-
- /* all mine */
- for (i = 0; i < aq->depth; i++)
- down(&aq->avail_cmds);
-
- /* let it go */
- for (i = 0; i < aq->depth; i++)
- up(&aq->avail_cmds);
-}
-
-static void efa_com_admin_flush(struct efa_com_dev *edev)
-{
- struct efa_com_admin_queue *aq = &edev->aq;
-
- clear_bit(EFA_AQ_STATE_RUNNING_BIT, &aq->state);
-
- efa_com_abort_admin_commands(edev);
- efa_com_wait_for_abort_completion(edev);
-}
-
-/**
* efa_com_admin_destroy - Destroy the admin and the async events queues.
* @edev: EFA communication layer struct
*/
@@ -737,7 +667,7 @@ void efa_com_admin_destroy(struct efa_com_dev *edev)
struct efa_com_admin_sq *sq = &aq->sq;
u16 size;
- efa_com_admin_flush(edev);
+ clear_bit(EFA_AQ_STATE_RUNNING_BIT, &aq->state);
devm_kfree(edev->dmadev, aq->comp_ctx_pool);
devm_kfree(edev->dmadev, aq->comp_ctx);
diff --git a/drivers/infiniband/hw/efa/efa_com.h b/drivers/infiniband/hw/efa/efa_com.h
index 84d96724a74b..c67dd8109d1c 100644
--- a/drivers/infiniband/hw/efa/efa_com.h
+++ b/drivers/infiniband/hw/efa/efa_com.h
@@ -45,7 +45,6 @@ struct efa_com_admin_sq {
/* Don't use anything other than atomic64 */
struct efa_com_stats_admin {
- atomic64_t aborted_cmd;
atomic64_t submitted_cmd;
atomic64_t completed_cmd;
atomic64_t no_completion;
diff --git a/drivers/infiniband/hw/efa/efa_com_cmd.c b/drivers/infiniband/hw/efa/efa_com_cmd.c
index 14227725521c..62345d8abf3c 100644
--- a/drivers/infiniband/hw/efa/efa_com_cmd.c
+++ b/drivers/infiniband/hw/efa/efa_com_cmd.c
@@ -3,7 +3,6 @@
* Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All rights reserved.
*/
-#include "efa.h"
#include "efa_com.h"
#include "efa_com_cmd.h"
@@ -57,7 +56,7 @@ int efa_com_create_qp(struct efa_com_dev *edev,
res->send_sub_cq_idx = cmd_completion.send_sub_cq_idx;
res->recv_sub_cq_idx = cmd_completion.recv_sub_cq_idx;
- return err;
+ return 0;
}
int efa_com_modify_qp(struct efa_com_dev *edev,
@@ -139,9 +138,11 @@ int efa_com_destroy_qp(struct efa_com_dev *edev,
sizeof(qp_cmd),
(struct efa_admin_acq_entry *)&cmd_completion,
sizeof(cmd_completion));
- if (err)
+ if (err) {
ibdev_err(edev->efa_dev, "Failed to destroy qp-%u [%d]\n",
qp_cmd.qp_handle, err);
+ return err;
+ }
return 0;
}
@@ -179,7 +180,7 @@ int efa_com_create_cq(struct efa_com_dev *edev,
result->cq_idx = cmd_completion.cq_idx;
result->actual_depth = params->cq_depth;
- return err;
+ return 0;
}
int efa_com_destroy_cq(struct efa_com_dev *edev,
@@ -199,9 +200,11 @@ int efa_com_destroy_cq(struct efa_com_dev *edev,
(struct efa_admin_acq_entry *)&destroy_resp,
sizeof(destroy_resp));
- if (err)
+ if (err) {
ibdev_err(edev->efa_dev, "Failed to destroy CQ-%u [%d]\n",
params->cq_idx, err);
+ return err;
+ }
return 0;
}
@@ -273,10 +276,12 @@ int efa_com_dereg_mr(struct efa_com_dev *edev,
sizeof(mr_cmd),
(struct efa_admin_acq_entry *)&cmd_completion,
sizeof(cmd_completion));
- if (err)
+ if (err) {
ibdev_err(edev->efa_dev,
"Failed to de-register mr(lkey-%u) [%d]\n",
mr_cmd.l_key, err);
+ return err;
+ }
return 0;
}
@@ -301,7 +306,8 @@ int efa_com_create_ah(struct efa_com_dev *edev,
(struct efa_admin_acq_entry *)&cmd_completion,
sizeof(cmd_completion));
if (err) {
- ibdev_err(edev->efa_dev, "Failed to create ah [%d]\n", err);
+ ibdev_err(edev->efa_dev, "Failed to create ah for %pI6 [%d]\n",
+ ah_cmd.dest_addr, err);
return err;
}
@@ -327,9 +333,11 @@ int efa_com_destroy_ah(struct efa_com_dev *edev,
sizeof(ah_cmd),
(struct efa_admin_acq_entry *)&cmd_completion,
sizeof(cmd_completion));
- if (err)
+ if (err) {
ibdev_err(edev->efa_dev, "Failed to destroy ah-%d pd-%d [%d]\n",
ah_cmd.ah, ah_cmd.pd, err);
+ return err;
+ }
return 0;
}
@@ -387,10 +395,12 @@ static int efa_com_get_feature_ex(struct efa_com_dev *edev,
get_resp,
sizeof(*get_resp));
- if (err)
+ if (err) {
ibdev_err(edev->efa_dev,
"Failed to submit get_feature command %d [%d]\n",
feature_id, err);
+ return err;
+ }
return 0;
}
@@ -534,10 +544,12 @@ static int efa_com_set_feature_ex(struct efa_com_dev *edev,
(struct efa_admin_acq_entry *)set_resp,
sizeof(*set_resp));
- if (err)
+ if (err) {
ibdev_err(edev->efa_dev,
"Failed to submit set_feature command %d error: %d\n",
feature_id, err);
+ return err;
+ }
return 0;
}
diff --git a/drivers/infiniband/hw/efa/efa_main.c b/drivers/infiniband/hw/efa/efa_main.c
index db974caf1eb1..dd1c6d49466f 100644
--- a/drivers/infiniband/hw/efa/efa_main.c
+++ b/drivers/infiniband/hw/efa/efa_main.c
@@ -100,7 +100,7 @@ static int efa_request_mgmnt_irq(struct efa_dev *dev)
nr_cpumask_bits, &irq->affinity_hint_mask, irq->vector);
irq_set_affinity_hint(irq->vector, &irq->affinity_hint_mask);
- return err;
+ return 0;
}
static void efa_setup_mgmnt_irq(struct efa_dev *dev)
@@ -197,6 +197,10 @@ static void efa_stats_init(struct efa_dev *dev)
}
static const struct ib_device_ops efa_dev_ops = {
+ .owner = THIS_MODULE,
+ .driver_id = RDMA_DRIVER_EFA,
+ .uverbs_abi_ver = EFA_UVERBS_ABI_VERSION,
+
.alloc_pd = efa_alloc_pd,
.alloc_ucontext = efa_alloc_ucontext,
.create_ah = efa_create_ah,
@@ -220,6 +224,7 @@ static const struct ib_device_ops efa_dev_ops = {
.reg_user_mr = efa_reg_mr,
INIT_RDMA_OBJ_SIZE(ib_ah, efa_ah, ibah),
+ INIT_RDMA_OBJ_SIZE(ib_cq, efa_cq, ibcq),
INIT_RDMA_OBJ_SIZE(ib_pd, efa_pd, ibpd),
INIT_RDMA_OBJ_SIZE(ib_ucontext, efa_ucontext, ibucontext),
};
@@ -259,12 +264,10 @@ static int efa_ib_device_add(struct efa_dev *dev)
if (err)
goto err_release_doorbell_bar;
- dev->ibdev.owner = THIS_MODULE;
dev->ibdev.node_type = RDMA_NODE_UNSPECIFIED;
dev->ibdev.phys_port_cnt = 1;
dev->ibdev.num_comp_vectors = 1;
dev->ibdev.dev.parent = &pdev->dev;
- dev->ibdev.uverbs_abi_ver = EFA_UVERBS_ABI_VERSION;
dev->ibdev.uverbs_cmd_mask =
(1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
@@ -287,7 +290,6 @@ static int efa_ib_device_add(struct efa_dev *dev)
dev->ibdev.uverbs_ex_cmd_mask =
(1ull << IB_USER_VERBS_EX_CMD_QUERY_DEVICE);
- dev->ibdev.driver_id = RDMA_DRIVER_EFA;
ib_set_device_ops(&dev->ibdev, &efa_dev_ops);
err = ib_register_device(&dev->ibdev, "efa_%d");
diff --git a/drivers/infiniband/hw/efa/efa_verbs.c b/drivers/infiniband/hw/efa/efa_verbs.c
index 0fea5d63fdbe..df77bc312a25 100644
--- a/drivers/infiniband/hw/efa/efa_verbs.c
+++ b/drivers/infiniband/hw/efa/efa_verbs.c
@@ -204,6 +204,7 @@ static u64 mmap_entry_insert(struct efa_dev *dev, struct efa_ucontext *ucontext,
void *obj, u64 address, u64 length, u8 mmap_flag)
{
struct efa_mmap_entry *entry;
+ u32 next_mmap_page;
int err;
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
@@ -216,15 +217,19 @@ static u64 mmap_entry_insert(struct efa_dev *dev, struct efa_ucontext *ucontext,
entry->mmap_flag = mmap_flag;
xa_lock(&ucontext->mmap_xa);
+ if (check_add_overflow(ucontext->mmap_xa_page,
+ (u32)(length >> PAGE_SHIFT),
+ &next_mmap_page))
+ goto err_unlock;
+
entry->mmap_page = ucontext->mmap_xa_page;
- ucontext->mmap_xa_page += DIV_ROUND_UP(length, PAGE_SIZE);
+ ucontext->mmap_xa_page = next_mmap_page;
err = __xa_insert(&ucontext->mmap_xa, entry->mmap_page, entry,
GFP_KERNEL);
+ if (err)
+ goto err_unlock;
+
xa_unlock(&ucontext->mmap_xa);
- if (err){
- kfree(entry);
- return EFA_MMAP_INVALID;
- }
ibdev_dbg(
&dev->ibdev,
@@ -232,6 +237,12 @@ static u64 mmap_entry_insert(struct efa_dev *dev, struct efa_ucontext *ucontext,
entry->obj, entry->address, entry->length, get_mmap_key(entry));
return get_mmap_key(entry);
+
+err_unlock:
+ xa_unlock(&ucontext->mmap_xa);
+ kfree(entry);
+ return EFA_MMAP_INVALID;
+
}
int efa_query_device(struct ib_device *ibdev,
@@ -436,12 +447,6 @@ void efa_dealloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
struct efa_dev *dev = to_edev(ibpd->device);
struct efa_pd *pd = to_epd(ibpd);
- if (udata->inlen &&
- !ib_is_udata_cleared(udata, 0, udata->inlen)) {
- ibdev_dbg(&dev->ibdev, "Incompatible ABI params\n");
- return;
- }
-
ibdev_dbg(&dev->ibdev, "Dealloc pd[%d]\n", pd->pdn);
efa_pd_dealloc(dev, pd->pdn);
}
@@ -459,12 +464,6 @@ int efa_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
struct efa_qp *qp = to_eqp(ibqp);
int err;
- if (udata->inlen &&
- !ib_is_udata_cleared(udata, 0, udata->inlen)) {
- ibdev_dbg(&dev->ibdev, "Incompatible ABI params\n");
- return -EINVAL;
- }
-
ibdev_dbg(&dev->ibdev, "Destroy qp[%u]\n", ibqp->qp_num);
err = efa_destroy_qp_handle(dev, qp->qp_handle);
if (err)
@@ -859,31 +858,18 @@ static int efa_destroy_cq_idx(struct efa_dev *dev, int cq_idx)
return efa_com_destroy_cq(&dev->edev, &params);
}
-int efa_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
+void efa_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
{
struct efa_dev *dev = to_edev(ibcq->device);
struct efa_cq *cq = to_ecq(ibcq);
- int err;
-
- if (udata->inlen &&
- !ib_is_udata_cleared(udata, 0, udata->inlen)) {
- ibdev_dbg(&dev->ibdev, "Incompatible ABI params\n");
- return -EINVAL;
- }
ibdev_dbg(&dev->ibdev,
"Destroy cq[%d] virt[0x%p] freed: size[%lu], dma[%pad]\n",
cq->cq_idx, cq->cpu_addr, cq->size, &cq->dma_addr);
- err = efa_destroy_cq_idx(dev, cq->cq_idx);
- if (err)
- return err;
-
+ efa_destroy_cq_idx(dev, cq->cq_idx);
dma_unmap_single(&dev->pdev->dev, cq->dma_addr, cq->size,
DMA_FROM_DEVICE);
-
- kfree(cq);
- return 0;
}
static int cq_mmap_entries_setup(struct efa_dev *dev, struct efa_cq *cq,
@@ -899,17 +885,20 @@ static int cq_mmap_entries_setup(struct efa_dev *dev, struct efa_cq *cq,
return 0;
}
-static struct ib_cq *do_create_cq(struct ib_device *ibdev, int entries,
- int vector, struct ib_ucontext *ibucontext,
- struct ib_udata *udata)
+int efa_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata)
{
+ struct efa_ucontext *ucontext = rdma_udata_to_drv_context(
+ udata, struct efa_ucontext, ibucontext);
struct efa_ibv_create_cq_resp resp = {};
struct efa_com_create_cq_params params;
struct efa_com_create_cq_result result;
+ struct ib_device *ibdev = ibcq->device;
struct efa_dev *dev = to_edev(ibdev);
struct efa_ibv_create_cq cmd = {};
+ struct efa_cq *cq = to_ecq(ibcq);
bool cq_entry_inserted = false;
- struct efa_cq *cq;
+ int entries = attr->cqe;
int err;
ibdev_dbg(ibdev, "create_cq entries %d\n", entries);
@@ -967,19 +956,13 @@ static struct ib_cq *do_create_cq(struct ib_device *ibdev, int entries,
goto err_out;
}
- cq = kzalloc(sizeof(*cq), GFP_KERNEL);
- if (!cq) {
- err = -ENOMEM;
- goto err_out;
- }
-
- cq->ucontext = to_eucontext(ibucontext);
+ cq->ucontext = ucontext;
cq->size = PAGE_ALIGN(cmd.cq_entry_size * entries * cmd.num_sub_cqs);
cq->cpu_addr = efa_zalloc_mapped(dev, &cq->dma_addr, cq->size,
DMA_FROM_DEVICE);
if (!cq->cpu_addr) {
err = -ENOMEM;
- goto err_free_cq;
+ goto err_out;
}
params.uarn = cq->ucontext->uarn;
@@ -998,8 +981,8 @@ static struct ib_cq *do_create_cq(struct ib_device *ibdev, int entries,
err = cq_mmap_entries_setup(dev, cq, &resp);
if (err) {
- ibdev_dbg(ibdev,
- "Could not setup cq[%u] mmap entries\n", cq->cq_idx);
+ ibdev_dbg(ibdev, "Could not setup cq[%u] mmap entries\n",
+ cq->cq_idx);
goto err_destroy_cq;
}
@@ -1015,11 +998,10 @@ static struct ib_cq *do_create_cq(struct ib_device *ibdev, int entries,
}
}
- ibdev_dbg(ibdev,
- "Created cq[%d], cq depth[%u]. dma[%pad] virt[0x%p]\n",
+ ibdev_dbg(ibdev, "Created cq[%d], cq depth[%u]. dma[%pad] virt[0x%p]\n",
cq->cq_idx, result.actual_depth, &cq->dma_addr, cq->cpu_addr);
- return &cq->ibcq;
+ return 0;
err_destroy_cq:
efa_destroy_cq_idx(dev, cq->cq_idx);
@@ -1028,23 +1010,9 @@ err_free_mapped:
DMA_FROM_DEVICE);
if (!cq_entry_inserted)
free_pages_exact(cq->cpu_addr, cq->size);
-err_free_cq:
- kfree(cq);
err_out:
atomic64_inc(&dev->stats.sw_stats.create_cq_err);
- return ERR_PTR(err);
-}
-
-struct ib_cq *efa_create_cq(struct ib_device *ibdev,
- const struct ib_cq_init_attr *attr,
- struct ib_udata *udata)
-{
- struct efa_ucontext *ucontext = rdma_udata_to_drv_context(udata,
- struct efa_ucontext,
- ibucontext);
-
- return do_create_cq(ibdev, attr->cqe, attr->comp_vector,
- &ucontext->ibucontext, udata);
+ return err;
}
static int umem_to_page_list(struct efa_dev *dev,
@@ -1054,21 +1022,15 @@ static int umem_to_page_list(struct efa_dev *dev,
u8 hp_shift)
{
u32 pages_in_hp = BIT(hp_shift - PAGE_SHIFT);
- struct sg_dma_page_iter sg_iter;
- unsigned int page_idx = 0;
+ struct ib_block_iter biter;
unsigned int hp_idx = 0;
ibdev_dbg(&dev->ibdev, "hp_cnt[%u], pages_in_hp[%u]\n",
hp_cnt, pages_in_hp);
- for_each_sg_dma_page(umem->sg_head.sgl, &sg_iter, umem->nmap, 0) {
- if (page_idx % pages_in_hp == 0) {
- page_list[hp_idx] = sg_page_iter_dma_address(&sg_iter);
- hp_idx++;
- }
-
- page_idx++;
- }
+ rdma_for_each_block(umem->sg_head.sgl, &biter, umem->nmap,
+ BIT(hp_shift))
+ page_list[hp_idx++] = rdma_block_iter_dma_address(&biter);
return 0;
}
@@ -1103,14 +1065,14 @@ err:
*/
static int pbl_chunk_list_create(struct efa_dev *dev, struct pbl_context *pbl)
{
- unsigned int entry, payloads_in_sg, chunk_list_size, chunk_idx, payload_idx;
struct pbl_chunk_list *chunk_list = &pbl->phys.indirect.chunk_list;
int page_cnt = pbl->phys.indirect.pbl_buf_size_in_pages;
struct scatterlist *pages_sgl = pbl->phys.indirect.sgl;
+ unsigned int chunk_list_size, chunk_idx, payload_idx;
int sg_dma_cnt = pbl->phys.indirect.sg_dma_cnt;
struct efa_com_ctrl_buff_info *ctrl_buf;
u64 *cur_chunk_buf, *prev_chunk_buf;
- struct scatterlist *sg;
+ struct ib_block_iter biter;
dma_addr_t dma_addr;
int i;
@@ -1144,18 +1106,15 @@ static int pbl_chunk_list_create(struct efa_dev *dev, struct pbl_context *pbl)
chunk_idx = 0;
payload_idx = 0;
cur_chunk_buf = chunk_list->chunks[0].buf;
- for_each_sg(pages_sgl, sg, sg_dma_cnt, entry) {
- payloads_in_sg = sg_dma_len(sg) >> EFA_CHUNK_PAYLOAD_SHIFT;
- for (i = 0; i < payloads_in_sg; i++) {
- cur_chunk_buf[payload_idx++] =
- (sg_dma_address(sg) & ~(EFA_CHUNK_PAYLOAD_SIZE - 1)) +
- (EFA_CHUNK_PAYLOAD_SIZE * i);
-
- if (payload_idx == EFA_PTRS_PER_CHUNK) {
- chunk_idx++;
- cur_chunk_buf = chunk_list->chunks[chunk_idx].buf;
- payload_idx = 0;
- }
+ rdma_for_each_block(pages_sgl, &biter, sg_dma_cnt,
+ EFA_CHUNK_PAYLOAD_SIZE) {
+ cur_chunk_buf[payload_idx++] =
+ rdma_block_iter_dma_address(&biter);
+
+ if (payload_idx == EFA_PTRS_PER_CHUNK) {
+ chunk_idx++;
+ cur_chunk_buf = chunk_list->chunks[chunk_idx].buf;
+ payload_idx = 0;
}
}
@@ -1303,30 +1262,30 @@ static int pbl_create(struct efa_dev *dev,
int err;
pbl->pbl_buf_size_in_bytes = hp_cnt * EFA_CHUNK_PAYLOAD_PTR_SIZE;
- pbl->pbl_buf = kzalloc(pbl->pbl_buf_size_in_bytes,
- GFP_KERNEL | __GFP_NOWARN);
- if (pbl->pbl_buf) {
- pbl->physically_continuous = 1;
+ pbl->pbl_buf = kvzalloc(pbl->pbl_buf_size_in_bytes, GFP_KERNEL);
+ if (!pbl->pbl_buf)
+ return -ENOMEM;
+
+ if (is_vmalloc_addr(pbl->pbl_buf)) {
+ pbl->physically_continuous = 0;
err = umem_to_page_list(dev, umem, pbl->pbl_buf, hp_cnt,
hp_shift);
if (err)
- goto err_continuous;
- err = pbl_continuous_initialize(dev, pbl);
+ goto err_free;
+
+ err = pbl_indirect_initialize(dev, pbl);
if (err)
- goto err_continuous;
+ goto err_free;
} else {
- pbl->physically_continuous = 0;
- pbl->pbl_buf = vzalloc(pbl->pbl_buf_size_in_bytes);
- if (!pbl->pbl_buf)
- return -ENOMEM;
-
+ pbl->physically_continuous = 1;
err = umem_to_page_list(dev, umem, pbl->pbl_buf, hp_cnt,
hp_shift);
if (err)
- goto err_indirect;
- err = pbl_indirect_initialize(dev, pbl);
+ goto err_free;
+
+ err = pbl_continuous_initialize(dev, pbl);
if (err)
- goto err_indirect;
+ goto err_free;
}
ibdev_dbg(&dev->ibdev,
@@ -1335,24 +1294,20 @@ static int pbl_create(struct efa_dev *dev,
return 0;
-err_continuous:
- kfree(pbl->pbl_buf);
- return err;
-err_indirect:
- vfree(pbl->pbl_buf);
+err_free:
+ kvfree(pbl->pbl_buf);
return err;
}
static void pbl_destroy(struct efa_dev *dev, struct pbl_context *pbl)
{
- if (pbl->physically_continuous) {
+ if (pbl->physically_continuous)
dma_unmap_single(&dev->pdev->dev, pbl->phys.continuous.dma_addr,
pbl->pbl_buf_size_in_bytes, DMA_TO_DEVICE);
- kfree(pbl->pbl_buf);
- } else {
+ else
pbl_indirect_terminate(dev, pbl);
- vfree(pbl->pbl_buf);
- }
+
+ kvfree(pbl->pbl_buf);
}
static int efa_create_inline_pbl(struct efa_dev *dev, struct efa_mr *mr,
@@ -1406,56 +1361,6 @@ static int efa_create_pbl(struct efa_dev *dev,
return 0;
}
-static void efa_cont_pages(struct ib_umem *umem, u64 addr,
- unsigned long max_page_shift,
- int *count, u8 *shift, u32 *ncont)
-{
- struct scatterlist *sg;
- u64 base = ~0, p = 0;
- unsigned long tmp;
- unsigned long m;
- u64 len, pfn;
- int i = 0;
- int entry;
-
- addr = addr >> PAGE_SHIFT;
- tmp = (unsigned long)addr;
- m = find_first_bit(&tmp, BITS_PER_LONG);
- if (max_page_shift)
- m = min_t(unsigned long, max_page_shift - PAGE_SHIFT, m);
-
- for_each_sg(umem->sg_head.sgl, sg, umem->nmap, entry) {
- len = DIV_ROUND_UP(sg_dma_len(sg), PAGE_SIZE);
- pfn = sg_dma_address(sg) >> PAGE_SHIFT;
- if (base + p != pfn) {
- /*
- * If either the offset or the new
- * base are unaligned update m
- */
- tmp = (unsigned long)(pfn | p);
- if (!IS_ALIGNED(tmp, 1 << m))
- m = find_first_bit(&tmp, BITS_PER_LONG);
-
- base = pfn;
- p = 0;
- }
-
- p += len;
- i += len;
- }
-
- if (i) {
- m = min_t(unsigned long, ilog2(roundup_pow_of_two(i)), m);
- *ncont = DIV_ROUND_UP(i, (1 << m));
- } else {
- m = 0;
- *ncont = 0;
- }
-
- *shift = PAGE_SHIFT + m;
- *count = i;
-}
-
struct ib_mr *efa_reg_mr(struct ib_pd *ibpd, u64 start, u64 length,
u64 virt_addr, int access_flags,
struct ib_udata *udata)
@@ -1463,11 +1368,10 @@ struct ib_mr *efa_reg_mr(struct ib_pd *ibpd, u64 start, u64 length,
struct efa_dev *dev = to_edev(ibpd->device);
struct efa_com_reg_mr_params params = {};
struct efa_com_reg_mr_result result = {};
- unsigned long max_page_shift;
struct pbl_context pbl;
+ unsigned int pg_sz;
struct efa_mr *mr;
int inline_size;
- int npages;
int err;
if (udata->inlen &&
@@ -1504,13 +1408,24 @@ struct ib_mr *efa_reg_mr(struct ib_pd *ibpd, u64 start, u64 length,
params.iova = virt_addr;
params.mr_length_in_bytes = length;
params.permissions = access_flags & 0x1;
- max_page_shift = fls64(dev->dev_attr.page_size_cap);
- efa_cont_pages(mr->umem, start, max_page_shift, &npages,
- &params.page_shift, &params.page_num);
+ pg_sz = ib_umem_find_best_pgsz(mr->umem,
+ dev->dev_attr.page_size_cap,
+ virt_addr);
+ if (!pg_sz) {
+ err = -EOPNOTSUPP;
+ ibdev_dbg(&dev->ibdev, "Failed to find a suitable page size in page_size_cap %#llx\n",
+ dev->dev_attr.page_size_cap);
+ goto err_unmap;
+ }
+
+ params.page_shift = __ffs(pg_sz);
+ params.page_num = DIV_ROUND_UP(length + (start & (pg_sz - 1)),
+ pg_sz);
+
ibdev_dbg(&dev->ibdev,
- "start %#llx length %#llx npages %d params.page_shift %u params.page_num %u\n",
- start, length, npages, params.page_shift, params.page_num);
+ "start %#llx length %#llx params.page_shift %u params.page_num %u\n",
+ start, length, params.page_shift, params.page_num);
inline_size = ARRAY_SIZE(params.pbl.inline_pbl_array);
if (params.page_num <= inline_size) {
@@ -1556,12 +1471,6 @@ int efa_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
struct efa_mr *mr = to_emr(ibmr);
int err;
- if (udata->inlen &&
- !ib_is_udata_cleared(udata, 0, udata->inlen)) {
- ibdev_dbg(&dev->ibdev, "Incompatible ABI params\n");
- return -EINVAL;
- }
-
ibdev_dbg(&dev->ibdev, "Deregister mr[%d]\n", ibmr->lkey);
if (mr->umem) {
@@ -1569,8 +1478,8 @@ int efa_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
err = efa_com_dereg_mr(&dev->edev, &params);
if (err)
return err;
- ib_umem_release(mr->umem);
}
+ ib_umem_release(mr->umem);
kfree(mr);
@@ -1696,13 +1605,15 @@ static int __efa_mmap(struct efa_dev *dev, struct efa_ucontext *ucontext,
err = -EINVAL;
}
- if (err)
+ if (err) {
ibdev_dbg(
&dev->ibdev,
"Couldn't mmap address[%#llx] length[%#llx] mmap_flag[%d] err[%d]\n",
entry->address, length, entry->mmap_flag, err);
+ return err;
+ }
- return err;
+ return 0;
}
int efa_mmap(struct ib_ucontext *ibucontext,
diff --git a/drivers/infiniband/hw/hfi1/Makefile b/drivers/infiniband/hw/hfi1/Makefile
index 4044a8c8dbf4..0405d26d0833 100644
--- a/drivers/infiniband/hw/hfi1/Makefile
+++ b/drivers/infiniband/hw/hfi1/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_INFINIBAND_HFI1) += hfi1.o
hfi1-y := \
affinity.o \
+ aspm.o \
chip.o \
device.o \
driver.o \
diff --git a/drivers/infiniband/hw/hfi1/affinity.c b/drivers/infiniband/hw/hfi1/affinity.c
index 4fe662c3bbc1..c142b23bb401 100644
--- a/drivers/infiniband/hw/hfi1/affinity.c
+++ b/drivers/infiniband/hw/hfi1/affinity.c
@@ -1038,7 +1038,7 @@ int hfi1_get_proc_affinity(int node)
struct hfi1_affinity_node *entry;
cpumask_var_t diff, hw_thread_mask, available_mask, intrs_mask;
const struct cpumask *node_mask,
- *proc_mask = &current->cpus_allowed;
+ *proc_mask = current->cpus_ptr;
struct hfi1_affinity_node_list *affinity = &node_affinity;
struct cpu_mask_set *set = &affinity->proc;
@@ -1046,7 +1046,7 @@ int hfi1_get_proc_affinity(int node)
* check whether process/context affinity has already
* been set
*/
- if (cpumask_weight(proc_mask) == 1) {
+ if (current->nr_cpus_allowed == 1) {
hfi1_cdbg(PROC, "PID %u %s affinity set to CPU %*pbl",
current->pid, current->comm,
cpumask_pr_args(proc_mask));
@@ -1057,7 +1057,7 @@ int hfi1_get_proc_affinity(int node)
cpu = cpumask_first(proc_mask);
cpumask_set_cpu(cpu, &set->used);
goto done;
- } else if (cpumask_weight(proc_mask) < cpumask_weight(&set->mask)) {
+ } else if (current->nr_cpus_allowed < cpumask_weight(&set->mask)) {
hfi1_cdbg(PROC, "PID %u %s affinity set to CPU set(s) %*pbl",
current->pid, current->comm,
cpumask_pr_args(proc_mask));
diff --git a/drivers/infiniband/hw/hfi1/aspm.c b/drivers/infiniband/hw/hfi1/aspm.c
new file mode 100644
index 000000000000..a3c53be4072c
--- /dev/null
+++ b/drivers/infiniband/hw/hfi1/aspm.c
@@ -0,0 +1,270 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/*
+ * Copyright(c) 2019 Intel Corporation.
+ *
+ */
+
+#include "aspm.h"
+
+/* Time after which the timer interrupt will re-enable ASPM */
+#define ASPM_TIMER_MS 1000
+/* Time for which interrupts are ignored after a timer has been scheduled */
+#define ASPM_RESCHED_TIMER_MS (ASPM_TIMER_MS / 2)
+/* Two interrupts within this time trigger ASPM disable */
+#define ASPM_TRIGGER_MS 1
+#define ASPM_TRIGGER_NS (ASPM_TRIGGER_MS * 1000 * 1000ull)
+#define ASPM_L1_SUPPORTED(reg) \
+ ((((reg) & PCI_EXP_LNKCAP_ASPMS) >> 10) & 0x2)
+
+uint aspm_mode = ASPM_MODE_DISABLED;
+module_param_named(aspm, aspm_mode, uint, 0444);
+MODULE_PARM_DESC(aspm, "PCIe ASPM: 0: disable, 1: enable, 2: dynamic");
+
+static bool aspm_hw_l1_supported(struct hfi1_devdata *dd)
+{
+ struct pci_dev *parent = dd->pcidev->bus->self;
+ u32 up, dn;
+
+ /*
+ * If the driver does not have access to the upstream component,
+ * it cannot support ASPM L1 at all.
+ */
+ if (!parent)
+ return false;
+
+ pcie_capability_read_dword(dd->pcidev, PCI_EXP_LNKCAP, &dn);
+ dn = ASPM_L1_SUPPORTED(dn);
+
+ pcie_capability_read_dword(parent, PCI_EXP_LNKCAP, &up);
+ up = ASPM_L1_SUPPORTED(up);
+
+ /* ASPM works on A-step but is reported as not supported */
+ return (!!dn || is_ax(dd)) && !!up;
+}
+
+/* Set L1 entrance latency for slower entry to L1 */
+static void aspm_hw_set_l1_ent_latency(struct hfi1_devdata *dd)
+{
+ u32 l1_ent_lat = 0x4u;
+ u32 reg32;
+
+ pci_read_config_dword(dd->pcidev, PCIE_CFG_REG_PL3, &reg32);
+ reg32 &= ~PCIE_CFG_REG_PL3_L1_ENT_LATENCY_SMASK;
+ reg32 |= l1_ent_lat << PCIE_CFG_REG_PL3_L1_ENT_LATENCY_SHIFT;
+ pci_write_config_dword(dd->pcidev, PCIE_CFG_REG_PL3, reg32);
+}
+
+static void aspm_hw_enable_l1(struct hfi1_devdata *dd)
+{
+ struct pci_dev *parent = dd->pcidev->bus->self;
+
+ /*
+ * If the driver does not have access to the upstream component,
+ * it cannot support ASPM L1 at all.
+ */
+ if (!parent)
+ return;
+
+ /* Enable ASPM L1 first in upstream component and then downstream */
+ pcie_capability_clear_and_set_word(parent, PCI_EXP_LNKCTL,
+ PCI_EXP_LNKCTL_ASPMC,
+ PCI_EXP_LNKCTL_ASPM_L1);
+ pcie_capability_clear_and_set_word(dd->pcidev, PCI_EXP_LNKCTL,
+ PCI_EXP_LNKCTL_ASPMC,
+ PCI_EXP_LNKCTL_ASPM_L1);
+}
+
+void aspm_hw_disable_l1(struct hfi1_devdata *dd)
+{
+ struct pci_dev *parent = dd->pcidev->bus->self;
+
+ /* Disable ASPM L1 first in downstream component and then upstream */
+ pcie_capability_clear_and_set_word(dd->pcidev, PCI_EXP_LNKCTL,
+ PCI_EXP_LNKCTL_ASPMC, 0x0);
+ if (parent)
+ pcie_capability_clear_and_set_word(parent, PCI_EXP_LNKCTL,
+ PCI_EXP_LNKCTL_ASPMC, 0x0);
+}
+
+static void aspm_enable(struct hfi1_devdata *dd)
+{
+ if (dd->aspm_enabled || aspm_mode == ASPM_MODE_DISABLED ||
+ !dd->aspm_supported)
+ return;
+
+ aspm_hw_enable_l1(dd);
+ dd->aspm_enabled = true;
+}
+
+static void aspm_disable(struct hfi1_devdata *dd)
+{
+ if (!dd->aspm_enabled || aspm_mode == ASPM_MODE_ENABLED)
+ return;
+
+ aspm_hw_disable_l1(dd);
+ dd->aspm_enabled = false;
+}
+
+static void aspm_disable_inc(struct hfi1_devdata *dd)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dd->aspm_lock, flags);
+ aspm_disable(dd);
+ atomic_inc(&dd->aspm_disabled_cnt);
+ spin_unlock_irqrestore(&dd->aspm_lock, flags);
+}
+
+static void aspm_enable_dec(struct hfi1_devdata *dd)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dd->aspm_lock, flags);
+ if (atomic_dec_and_test(&dd->aspm_disabled_cnt))
+ aspm_enable(dd);
+ spin_unlock_irqrestore(&dd->aspm_lock, flags);
+}
+
+/* ASPM processing for each receive context interrupt */
+void __aspm_ctx_disable(struct hfi1_ctxtdata *rcd)
+{
+ bool restart_timer;
+ bool close_interrupts;
+ unsigned long flags;
+ ktime_t now, prev;
+
+ spin_lock_irqsave(&rcd->aspm_lock, flags);
+ /* PSM contexts are open */
+ if (!rcd->aspm_intr_enable)
+ goto unlock;
+
+ prev = rcd->aspm_ts_last_intr;
+ now = ktime_get();
+ rcd->aspm_ts_last_intr = now;
+
+ /* An interrupt pair close together in time */
+ close_interrupts = ktime_to_ns(ktime_sub(now, prev)) < ASPM_TRIGGER_NS;
+
+ /* Don't push out our timer till this much time has elapsed */
+ restart_timer = ktime_to_ns(ktime_sub(now, rcd->aspm_ts_timer_sched)) >
+ ASPM_RESCHED_TIMER_MS * NSEC_PER_MSEC;
+ restart_timer = restart_timer && close_interrupts;
+
+ /* Disable ASPM and schedule timer */
+ if (rcd->aspm_enabled && close_interrupts) {
+ aspm_disable_inc(rcd->dd);
+ rcd->aspm_enabled = false;
+ restart_timer = true;
+ }
+
+ if (restart_timer) {
+ mod_timer(&rcd->aspm_timer,
+ jiffies + msecs_to_jiffies(ASPM_TIMER_MS));
+ rcd->aspm_ts_timer_sched = now;
+ }
+unlock:
+ spin_unlock_irqrestore(&rcd->aspm_lock, flags);
+}
+
+/* Timer function for re-enabling ASPM in the absence of interrupt activity */
+static void aspm_ctx_timer_function(struct timer_list *t)
+{
+ struct hfi1_ctxtdata *rcd = from_timer(rcd, t, aspm_timer);
+ unsigned long flags;
+
+ spin_lock_irqsave(&rcd->aspm_lock, flags);
+ aspm_enable_dec(rcd->dd);
+ rcd->aspm_enabled = true;
+ spin_unlock_irqrestore(&rcd->aspm_lock, flags);
+}
+
+/*
+ * Disable interrupt processing for verbs contexts when PSM or VNIC contexts
+ * are open.
+ */
+void aspm_disable_all(struct hfi1_devdata *dd)
+{
+ struct hfi1_ctxtdata *rcd;
+ unsigned long flags;
+ u16 i;
+
+ for (i = 0; i < dd->first_dyn_alloc_ctxt; i++) {
+ rcd = hfi1_rcd_get_by_index(dd, i);
+ if (rcd) {
+ del_timer_sync(&rcd->aspm_timer);
+ spin_lock_irqsave(&rcd->aspm_lock, flags);
+ rcd->aspm_intr_enable = false;
+ spin_unlock_irqrestore(&rcd->aspm_lock, flags);
+ hfi1_rcd_put(rcd);
+ }
+ }
+
+ aspm_disable(dd);
+ atomic_set(&dd->aspm_disabled_cnt, 0);
+}
+
+/* Re-enable interrupt processing for verbs contexts */
+void aspm_enable_all(struct hfi1_devdata *dd)
+{
+ struct hfi1_ctxtdata *rcd;
+ unsigned long flags;
+ u16 i;
+
+ aspm_enable(dd);
+
+ if (aspm_mode != ASPM_MODE_DYNAMIC)
+ return;
+
+ for (i = 0; i < dd->first_dyn_alloc_ctxt; i++) {
+ rcd = hfi1_rcd_get_by_index(dd, i);
+ if (rcd) {
+ spin_lock_irqsave(&rcd->aspm_lock, flags);
+ rcd->aspm_intr_enable = true;
+ rcd->aspm_enabled = true;
+ spin_unlock_irqrestore(&rcd->aspm_lock, flags);
+ hfi1_rcd_put(rcd);
+ }
+ }
+}
+
+static void aspm_ctx_init(struct hfi1_ctxtdata *rcd)
+{
+ spin_lock_init(&rcd->aspm_lock);
+ timer_setup(&rcd->aspm_timer, aspm_ctx_timer_function, 0);
+ rcd->aspm_intr_supported = rcd->dd->aspm_supported &&
+ aspm_mode == ASPM_MODE_DYNAMIC &&
+ rcd->ctxt < rcd->dd->first_dyn_alloc_ctxt;
+}
+
+void aspm_init(struct hfi1_devdata *dd)
+{
+ struct hfi1_ctxtdata *rcd;
+ u16 i;
+
+ spin_lock_init(&dd->aspm_lock);
+ dd->aspm_supported = aspm_hw_l1_supported(dd);
+
+ for (i = 0; i < dd->first_dyn_alloc_ctxt; i++) {
+ rcd = hfi1_rcd_get_by_index(dd, i);
+ if (rcd)
+ aspm_ctx_init(rcd);
+ hfi1_rcd_put(rcd);
+ }
+
+ /* Start with ASPM disabled */
+ aspm_hw_set_l1_ent_latency(dd);
+ dd->aspm_enabled = false;
+ aspm_hw_disable_l1(dd);
+
+ /* Now turn on ASPM if configured */
+ aspm_enable_all(dd);
+}
+
+void aspm_exit(struct hfi1_devdata *dd)
+{
+ aspm_disable_all(dd);
+
+ /* Turn on ASPM on exit to conserve power */
+ aspm_enable(dd);
+}
+
diff --git a/drivers/infiniband/hw/hfi1/aspm.h b/drivers/infiniband/hw/hfi1/aspm.h
index e8133870ee87..75d5d18da3da 100644
--- a/drivers/infiniband/hw/hfi1/aspm.h
+++ b/drivers/infiniband/hw/hfi1/aspm.h
@@ -57,266 +57,20 @@ enum aspm_mode {
ASPM_MODE_DYNAMIC = 2, /* ASPM enabled/disabled dynamically */
};
-/* Time after which the timer interrupt will re-enable ASPM */
-#define ASPM_TIMER_MS 1000
-/* Time for which interrupts are ignored after a timer has been scheduled */
-#define ASPM_RESCHED_TIMER_MS (ASPM_TIMER_MS / 2)
-/* Two interrupts within this time trigger ASPM disable */
-#define ASPM_TRIGGER_MS 1
-#define ASPM_TRIGGER_NS (ASPM_TRIGGER_MS * 1000 * 1000ull)
-#define ASPM_L1_SUPPORTED(reg) \
- (((reg & PCI_EXP_LNKCAP_ASPMS) >> 10) & 0x2)
+void aspm_init(struct hfi1_devdata *dd);
+void aspm_exit(struct hfi1_devdata *dd);
+void aspm_hw_disable_l1(struct hfi1_devdata *dd);
+void __aspm_ctx_disable(struct hfi1_ctxtdata *rcd);
+void aspm_disable_all(struct hfi1_devdata *dd);
+void aspm_enable_all(struct hfi1_devdata *dd);
-static inline bool aspm_hw_l1_supported(struct hfi1_devdata *dd)
-{
- struct pci_dev *parent = dd->pcidev->bus->self;
- u32 up, dn;
-
- /*
- * If the driver does not have access to the upstream component,
- * it cannot support ASPM L1 at all.
- */
- if (!parent)
- return false;
-
- pcie_capability_read_dword(dd->pcidev, PCI_EXP_LNKCAP, &dn);
- dn = ASPM_L1_SUPPORTED(dn);
-
- pcie_capability_read_dword(parent, PCI_EXP_LNKCAP, &up);
- up = ASPM_L1_SUPPORTED(up);
-
- /* ASPM works on A-step but is reported as not supported */
- return (!!dn || is_ax(dd)) && !!up;
-}
-
-/* Set L1 entrance latency for slower entry to L1 */
-static inline void aspm_hw_set_l1_ent_latency(struct hfi1_devdata *dd)
-{
- u32 l1_ent_lat = 0x4u;
- u32 reg32;
-
- pci_read_config_dword(dd->pcidev, PCIE_CFG_REG_PL3, &reg32);
- reg32 &= ~PCIE_CFG_REG_PL3_L1_ENT_LATENCY_SMASK;
- reg32 |= l1_ent_lat << PCIE_CFG_REG_PL3_L1_ENT_LATENCY_SHIFT;
- pci_write_config_dword(dd->pcidev, PCIE_CFG_REG_PL3, reg32);
-}
-
-static inline void aspm_hw_enable_l1(struct hfi1_devdata *dd)
-{
- struct pci_dev *parent = dd->pcidev->bus->self;
-
- /*
- * If the driver does not have access to the upstream component,
- * it cannot support ASPM L1 at all.
- */
- if (!parent)
- return;
-
- /* Enable ASPM L1 first in upstream component and then downstream */
- pcie_capability_clear_and_set_word(parent, PCI_EXP_LNKCTL,
- PCI_EXP_LNKCTL_ASPMC,
- PCI_EXP_LNKCTL_ASPM_L1);
- pcie_capability_clear_and_set_word(dd->pcidev, PCI_EXP_LNKCTL,
- PCI_EXP_LNKCTL_ASPMC,
- PCI_EXP_LNKCTL_ASPM_L1);
-}
-
-static inline void aspm_hw_disable_l1(struct hfi1_devdata *dd)
-{
- struct pci_dev *parent = dd->pcidev->bus->self;
-
- /* Disable ASPM L1 first in downstream component and then upstream */
- pcie_capability_clear_and_set_word(dd->pcidev, PCI_EXP_LNKCTL,
- PCI_EXP_LNKCTL_ASPMC, 0x0);
- if (parent)
- pcie_capability_clear_and_set_word(parent, PCI_EXP_LNKCTL,
- PCI_EXP_LNKCTL_ASPMC, 0x0);
-}
-
-static inline void aspm_enable(struct hfi1_devdata *dd)
-{
- if (dd->aspm_enabled || aspm_mode == ASPM_MODE_DISABLED ||
- !dd->aspm_supported)
- return;
-
- aspm_hw_enable_l1(dd);
- dd->aspm_enabled = true;
-}
-
-static inline void aspm_disable(struct hfi1_devdata *dd)
-{
- if (!dd->aspm_enabled || aspm_mode == ASPM_MODE_ENABLED)
- return;
-
- aspm_hw_disable_l1(dd);
- dd->aspm_enabled = false;
-}
-
-static inline void aspm_disable_inc(struct hfi1_devdata *dd)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&dd->aspm_lock, flags);
- aspm_disable(dd);
- atomic_inc(&dd->aspm_disabled_cnt);
- spin_unlock_irqrestore(&dd->aspm_lock, flags);
-}
-
-static inline void aspm_enable_dec(struct hfi1_devdata *dd)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&dd->aspm_lock, flags);
- if (atomic_dec_and_test(&dd->aspm_disabled_cnt))
- aspm_enable(dd);
- spin_unlock_irqrestore(&dd->aspm_lock, flags);
-}
-
-/* ASPM processing for each receive context interrupt */
static inline void aspm_ctx_disable(struct hfi1_ctxtdata *rcd)
{
- bool restart_timer;
- bool close_interrupts;
- unsigned long flags;
- ktime_t now, prev;
-
/* Quickest exit for minimum impact */
- if (!rcd->aspm_intr_supported)
- return;
-
- spin_lock_irqsave(&rcd->aspm_lock, flags);
- /* PSM contexts are open */
- if (!rcd->aspm_intr_enable)
- goto unlock;
-
- prev = rcd->aspm_ts_last_intr;
- now = ktime_get();
- rcd->aspm_ts_last_intr = now;
-
- /* An interrupt pair close together in time */
- close_interrupts = ktime_to_ns(ktime_sub(now, prev)) < ASPM_TRIGGER_NS;
-
- /* Don't push out our timer till this much time has elapsed */
- restart_timer = ktime_to_ns(ktime_sub(now, rcd->aspm_ts_timer_sched)) >
- ASPM_RESCHED_TIMER_MS * NSEC_PER_MSEC;
- restart_timer = restart_timer && close_interrupts;
-
- /* Disable ASPM and schedule timer */
- if (rcd->aspm_enabled && close_interrupts) {
- aspm_disable_inc(rcd->dd);
- rcd->aspm_enabled = false;
- restart_timer = true;
- }
-
- if (restart_timer) {
- mod_timer(&rcd->aspm_timer,
- jiffies + msecs_to_jiffies(ASPM_TIMER_MS));
- rcd->aspm_ts_timer_sched = now;
- }
-unlock:
- spin_unlock_irqrestore(&rcd->aspm_lock, flags);
-}
-
-/* Timer function for re-enabling ASPM in the absence of interrupt activity */
-static inline void aspm_ctx_timer_function(struct timer_list *t)
-{
- struct hfi1_ctxtdata *rcd = from_timer(rcd, t, aspm_timer);
- unsigned long flags;
-
- spin_lock_irqsave(&rcd->aspm_lock, flags);
- aspm_enable_dec(rcd->dd);
- rcd->aspm_enabled = true;
- spin_unlock_irqrestore(&rcd->aspm_lock, flags);
-}
-
-/*
- * Disable interrupt processing for verbs contexts when PSM or VNIC contexts
- * are open.
- */
-static inline void aspm_disable_all(struct hfi1_devdata *dd)
-{
- struct hfi1_ctxtdata *rcd;
- unsigned long flags;
- u16 i;
-
- for (i = 0; i < dd->first_dyn_alloc_ctxt; i++) {
- rcd = hfi1_rcd_get_by_index(dd, i);
- if (rcd) {
- del_timer_sync(&rcd->aspm_timer);
- spin_lock_irqsave(&rcd->aspm_lock, flags);
- rcd->aspm_intr_enable = false;
- spin_unlock_irqrestore(&rcd->aspm_lock, flags);
- hfi1_rcd_put(rcd);
- }
- }
-
- aspm_disable(dd);
- atomic_set(&dd->aspm_disabled_cnt, 0);
-}
-
-/* Re-enable interrupt processing for verbs contexts */
-static inline void aspm_enable_all(struct hfi1_devdata *dd)
-{
- struct hfi1_ctxtdata *rcd;
- unsigned long flags;
- u16 i;
-
- aspm_enable(dd);
-
- if (aspm_mode != ASPM_MODE_DYNAMIC)
+ if (likely(!rcd->aspm_intr_supported))
return;
- for (i = 0; i < dd->first_dyn_alloc_ctxt; i++) {
- rcd = hfi1_rcd_get_by_index(dd, i);
- if (rcd) {
- spin_lock_irqsave(&rcd->aspm_lock, flags);
- rcd->aspm_intr_enable = true;
- rcd->aspm_enabled = true;
- spin_unlock_irqrestore(&rcd->aspm_lock, flags);
- hfi1_rcd_put(rcd);
- }
- }
-}
-
-static inline void aspm_ctx_init(struct hfi1_ctxtdata *rcd)
-{
- spin_lock_init(&rcd->aspm_lock);
- timer_setup(&rcd->aspm_timer, aspm_ctx_timer_function, 0);
- rcd->aspm_intr_supported = rcd->dd->aspm_supported &&
- aspm_mode == ASPM_MODE_DYNAMIC &&
- rcd->ctxt < rcd->dd->first_dyn_alloc_ctxt;
-}
-
-static inline void aspm_init(struct hfi1_devdata *dd)
-{
- struct hfi1_ctxtdata *rcd;
- u16 i;
-
- spin_lock_init(&dd->aspm_lock);
- dd->aspm_supported = aspm_hw_l1_supported(dd);
-
- for (i = 0; i < dd->first_dyn_alloc_ctxt; i++) {
- rcd = hfi1_rcd_get_by_index(dd, i);
- if (rcd)
- aspm_ctx_init(rcd);
- hfi1_rcd_put(rcd);
- }
-
- /* Start with ASPM disabled */
- aspm_hw_set_l1_ent_latency(dd);
- dd->aspm_enabled = false;
- aspm_hw_disable_l1(dd);
-
- /* Now turn on ASPM if configured */
- aspm_enable_all(dd);
-}
-
-static inline void aspm_exit(struct hfi1_devdata *dd)
-{
- aspm_disable_all(dd);
-
- /* Turn on ASPM on exit to conserve power */
- aspm_enable(dd);
+ __aspm_ctx_disable(rcd);
}
#endif /* _ASPM_H */
diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c
index 4221a99ee7f4..d5b643a1d9fd 100644
--- a/drivers/infiniband/hw/hfi1/chip.c
+++ b/drivers/infiniband/hw/hfi1/chip.c
@@ -14032,6 +14032,19 @@ static void init_kdeth_qp(struct hfi1_devdata *dd)
}
/**
+ * hfi1_get_qp_map
+ * @dd: device data
+ * @idx: index to read
+ */
+u8 hfi1_get_qp_map(struct hfi1_devdata *dd, u8 idx)
+{
+ u64 reg = read_csr(dd, RCV_QP_MAP_TABLE + (idx / 8) * 8);
+
+ reg >>= (idx % 8) * 8;
+ return reg;
+}
+
+/**
* init_qpmap_table
* @dd - device data
* @first_ctxt - first context
diff --git a/drivers/infiniband/hw/hfi1/chip.h b/drivers/infiniband/hw/hfi1/chip.h
index 4e6c3556ec48..b76cf81f927f 100644
--- a/drivers/infiniband/hw/hfi1/chip.h
+++ b/drivers/infiniband/hw/hfi1/chip.h
@@ -1445,6 +1445,7 @@ void clear_all_interrupts(struct hfi1_devdata *dd);
void remap_intr(struct hfi1_devdata *dd, int isrc, int msix_intr);
void remap_sdma_interrupts(struct hfi1_devdata *dd, int engine, int msix_intr);
void reset_interrupts(struct hfi1_devdata *dd);
+u8 hfi1_get_qp_map(struct hfi1_devdata *dd, u8 idx);
/*
* Interrupt source table.
diff --git a/drivers/infiniband/hw/hfi1/debugfs.c b/drivers/infiniband/hw/hfi1/debugfs.c
index 15efb4a380b2..d268bf9c42ee 100644
--- a/drivers/infiniband/hw/hfi1/debugfs.c
+++ b/drivers/infiniband/hw/hfi1/debugfs.c
@@ -987,9 +987,6 @@ static int __i2c_debugfs_open(struct inode *in, struct file *fp, u32 target)
struct hfi1_pportdata *ppd;
int ret;
- if (!try_module_get(THIS_MODULE))
- return -ENODEV;
-
ppd = private2ppd(fp);
ret = acquire_chip_resource(ppd->dd, i2c_target(target), 0);
@@ -1155,6 +1152,7 @@ static int exprom_wp_debugfs_release(struct inode *in, struct file *fp)
{ \
.name = nm, \
.ops = { \
+ .owner = THIS_MODULE, \
.read = readroutine, \
.write = writeroutine, \
.llseek = generic_file_llseek, \
@@ -1165,6 +1163,7 @@ static int exprom_wp_debugfs_release(struct inode *in, struct file *fp)
{ \
.name = nm, \
.ops = { \
+ .owner = THIS_MODULE, \
.read = readf, \
.write = writef, \
.llseek = generic_file_llseek, \
diff --git a/drivers/infiniband/hw/hfi1/fault.c b/drivers/infiniband/hw/hfi1/fault.c
index 3fd3315d0fb0..93613e5def9b 100644
--- a/drivers/infiniband/hw/hfi1/fault.c
+++ b/drivers/infiniband/hw/hfi1/fault.c
@@ -153,6 +153,7 @@ static ssize_t fault_opcodes_write(struct file *file, const char __user *buf,
char *dash;
unsigned long range_start, range_end, i;
bool remove = false;
+ unsigned long bound = 1U << BITS_PER_BYTE;
end = strchr(ptr, ',');
if (end)
@@ -178,6 +179,10 @@ static ssize_t fault_opcodes_write(struct file *file, const char __user *buf,
BITS_PER_BYTE);
break;
}
+ /* Check the inputs */
+ if (range_start >= bound || range_end >= bound)
+ break;
+
for (i = range_start; i <= range_end; i++) {
if (remove)
clear_bit(i, fault->opcodes);
diff --git a/drivers/infiniband/hw/hfi1/hfi.h b/drivers/infiniband/hw/hfi1/hfi.h
index b458c218842b..fa45350a9a1d 100644
--- a/drivers/infiniband/hw/hfi1/hfi.h
+++ b/drivers/infiniband/hw/hfi1/hfi.h
@@ -539,6 +539,37 @@ static inline void hfi1_16B_set_qpn(struct opa_16b_mgmt *mgmt,
mgmt->src_qpn = cpu_to_be32(src_qp & OPA_16B_MGMT_QPN_MASK);
}
+/**
+ * hfi1_get_rc_ohdr - get extended header
+ * @opah - the opaheader
+ */
+static inline struct ib_other_headers *
+hfi1_get_rc_ohdr(struct hfi1_opa_header *opah)
+{
+ struct ib_other_headers *ohdr;
+ struct ib_header *hdr = NULL;
+ struct hfi1_16b_header *hdr_16b = NULL;
+
+ /* Find out where the BTH is */
+ if (opah->hdr_type == HFI1_PKT_TYPE_9B) {
+ hdr = &opah->ibh;
+ if (ib_get_lnh(hdr) == HFI1_LRH_BTH)
+ ohdr = &hdr->u.oth;
+ else
+ ohdr = &hdr->u.l.oth;
+ } else {
+ u8 l4;
+
+ hdr_16b = &opah->opah;
+ l4 = hfi1_16B_get_l4(hdr_16b);
+ if (l4 == OPA_16B_L4_IB_LOCAL)
+ ohdr = &hdr_16b->u.oth;
+ else
+ ohdr = &hdr_16b->u.l.oth;
+ }
+ return ohdr;
+}
+
struct rvt_sge_state;
/*
diff --git a/drivers/infiniband/hw/hfi1/mad.c b/drivers/infiniband/hw/hfi1/mad.c
index 4228393e6c4c..184dba3c2828 100644
--- a/drivers/infiniband/hw/hfi1/mad.c
+++ b/drivers/infiniband/hw/hfi1/mad.c
@@ -2744,8 +2744,7 @@ static int pma_get_opa_portstatus(struct opa_pma_mad *pmp,
u16 link_width;
u16 link_speed;
- response_data_size = sizeof(struct opa_port_status_rsp) +
- num_vls * sizeof(struct _vls_pctrs);
+ response_data_size = struct_size(rsp, vls, num_vls);
if (response_data_size > sizeof(pmp->data)) {
pmp->mad_hdr.status |= OPA_PM_STATUS_REQUEST_TOO_LARGE;
return reply((struct ib_mad_hdr *)pmp);
@@ -3014,8 +3013,7 @@ static int pma_get_opa_datacounters(struct opa_pma_mad *pmp,
}
/* Sanity check */
- response_data_size = sizeof(struct opa_port_data_counters_msg) +
- num_vls * sizeof(struct _vls_dctrs);
+ response_data_size = struct_size(req, port[0].vls, num_vls);
if (response_data_size > sizeof(pmp->data)) {
pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD;
@@ -3232,8 +3230,7 @@ static int pma_get_opa_porterrors(struct opa_pma_mad *pmp,
return reply((struct ib_mad_hdr *)pmp);
}
- response_data_size = sizeof(struct opa_port_error_counters64_msg) +
- num_vls * sizeof(struct _vls_ectrs);
+ response_data_size = struct_size(req, port[0].vls, num_vls);
if (response_data_size > sizeof(pmp->data)) {
pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD;
diff --git a/drivers/infiniband/hw/hfi1/pcie.c b/drivers/infiniband/hw/hfi1/pcie.c
index c96d193bb236..61aa5504d7c3 100644
--- a/drivers/infiniband/hw/hfi1/pcie.c
+++ b/drivers/infiniband/hw/hfi1/pcie.c
@@ -1,5 +1,5 @@
/*
- * Copyright(c) 2015 - 2018 Intel Corporation.
+ * Copyright(c) 2015 - 2019 Intel Corporation.
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
@@ -450,10 +450,6 @@ static int hfi1_pcie_caps;
module_param_named(pcie_caps, hfi1_pcie_caps, int, 0444);
MODULE_PARM_DESC(pcie_caps, "Max PCIe tuning: Payload (0..3), ReadReq (4..7)");
-uint aspm_mode = ASPM_MODE_DISABLED;
-module_param_named(aspm, aspm_mode, uint, 0444);
-MODULE_PARM_DESC(aspm, "PCIe ASPM: 0: disable, 1: enable, 2: dynamic");
-
/**
* tune_pcie_caps() - Code to adjust PCIe capabilities.
* @dd: Valid device data structure
diff --git a/drivers/infiniband/hw/hfi1/pio.c b/drivers/infiniband/hw/hfi1/pio.c
index 16ba9d52e1b9..79126b2b14ab 100644
--- a/drivers/infiniband/hw/hfi1/pio.c
+++ b/drivers/infiniband/hw/hfi1/pio.c
@@ -952,6 +952,22 @@ void sc_disable(struct send_context *sc)
}
}
spin_unlock(&sc->release_lock);
+
+ write_seqlock(&sc->waitlock);
+ while (!list_empty(&sc->piowait)) {
+ struct iowait *wait;
+ struct rvt_qp *qp;
+ struct hfi1_qp_priv *priv;
+
+ wait = list_first_entry(&sc->piowait, struct iowait, list);
+ qp = iowait_to_qp(wait);
+ priv = qp->priv;
+ list_del_init(&priv->s_iowait.list);
+ priv->s_iowait.lock = NULL;
+ hfi1_qp_wakeup(qp, RVT_S_WAIT_PIO | HFI1_S_WAIT_PIO_DRAIN);
+ }
+ write_sequnlock(&sc->waitlock);
+
spin_unlock_irq(&sc->alloc_lock);
}
@@ -1427,7 +1443,8 @@ void sc_stop(struct send_context *sc, int flag)
* @cb: optional callback to call when the buffer is finished sending
* @arg: argument for cb
*
- * Return a pointer to a PIO buffer if successful, NULL if not enough room.
+ * Return a pointer to a PIO buffer, NULL if not enough room, -ECOMM
+ * when link is down.
*/
struct pio_buf *sc_buffer_alloc(struct send_context *sc, u32 dw_len,
pio_release_cb cb, void *arg)
@@ -1443,7 +1460,7 @@ struct pio_buf *sc_buffer_alloc(struct send_context *sc, u32 dw_len,
spin_lock_irqsave(&sc->alloc_lock, flags);
if (!(sc->flags & SCF_ENABLED)) {
spin_unlock_irqrestore(&sc->alloc_lock, flags);
- goto done;
+ return ERR_PTR(-ECOMM);
}
retry:
@@ -1577,9 +1594,8 @@ void hfi1_sc_wantpiobuf_intr(struct send_context *sc, u32 needint)
else
sc_del_credit_return_intr(sc);
trace_hfi1_wantpiointr(sc, needint, sc->credit_ctrl);
- if (needint) {
+ if (needint)
sc_return_credits(sc);
- }
}
/**
diff --git a/drivers/infiniband/hw/hfi1/qp.c b/drivers/infiniband/hw/hfi1/qp.c
index 4e0e9fc0a777..f8e733aa3bb8 100644
--- a/drivers/infiniband/hw/hfi1/qp.c
+++ b/drivers/infiniband/hw/hfi1/qp.c
@@ -1,5 +1,5 @@
/*
- * Copyright(c) 2015 - 2018 Intel Corporation.
+ * Copyright(c) 2015 - 2019 Intel Corporation.
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
@@ -348,7 +348,7 @@ int hfi1_setup_wqe(struct rvt_qp *qp, struct rvt_swqe *wqe, bool *call_send)
break;
case IB_QPT_GSI:
case IB_QPT_UD:
- ah = ibah_to_rvtah(wqe->ud_wr.ah);
+ ah = rvt_get_swqe_ah(wqe);
if (wqe->length > (1 << ah->log_pmtu))
return -EINVAL;
if (ibp->sl_to_sc[rdma_ah_get_sl(&ah->attr)] == 0xf)
@@ -702,8 +702,8 @@ void qp_iter_print(struct seq_file *s, struct rvt_qp_iter *iter)
sde ? sde->this_idx : 0,
send_context,
send_context ? send_context->sw_index : 0,
- ibcq_to_rvtcq(qp->ibqp.send_cq)->queue->head,
- ibcq_to_rvtcq(qp->ibqp.send_cq)->queue->tail,
+ ib_cq_head(qp->ibqp.send_cq),
+ ib_cq_tail(qp->ibqp.send_cq),
qp->pid,
qp->s_state,
qp->s_ack_state,
diff --git a/drivers/infiniband/hw/hfi1/rc.c b/drivers/infiniband/hw/hfi1/rc.c
index a922edcf23d6..0477c14633ab 100644
--- a/drivers/infiniband/hw/hfi1/rc.c
+++ b/drivers/infiniband/hw/hfi1/rc.c
@@ -1432,7 +1432,7 @@ void hfi1_send_rc_ack(struct hfi1_packet *packet, bool is_fecn)
pbc = create_pbc(ppd, pbc_flags, qp->srate_mbps,
sc_to_vlt(ppd->dd, sc5), plen);
pbuf = sc_buffer_alloc(rcd->sc, plen, NULL, NULL);
- if (!pbuf) {
+ if (IS_ERR_OR_NULL(pbuf)) {
/*
* We have no room to send at the moment. Pass
* responsibility for sending the ACK to the send engine
@@ -1701,6 +1701,36 @@ static void reset_sending_psn(struct rvt_qp *qp, u32 psn)
}
}
+/**
+ * hfi1_rc_verbs_aborted - handle abort status
+ * @qp: the QP
+ * @opah: the opa header
+ *
+ * This code modifies both ACK bit in BTH[2]
+ * and the s_flags to go into send one mode.
+ *
+ * This serves to throttle the send engine to only
+ * send a single packet in the likely case the
+ * a link has gone down.
+ */
+void hfi1_rc_verbs_aborted(struct rvt_qp *qp, struct hfi1_opa_header *opah)
+{
+ struct ib_other_headers *ohdr = hfi1_get_rc_ohdr(opah);
+ u8 opcode = ib_bth_get_opcode(ohdr);
+ u32 psn;
+
+ /* ignore responses */
+ if ((opcode >= OP(RDMA_READ_RESPONSE_FIRST) &&
+ opcode <= OP(ATOMIC_ACKNOWLEDGE)) ||
+ opcode == TID_OP(READ_RESP) ||
+ opcode == TID_OP(WRITE_RESP))
+ return;
+
+ psn = ib_bth_get_psn(ohdr) | IB_BTH_REQ_ACK;
+ ohdr->bth[2] = cpu_to_be32(psn);
+ qp->s_flags |= RVT_S_SEND_ONE;
+}
+
/*
* This should be called with the QP s_lock held and interrupts disabled.
*/
@@ -1709,8 +1739,6 @@ void hfi1_rc_send_complete(struct rvt_qp *qp, struct hfi1_opa_header *opah)
struct ib_other_headers *ohdr;
struct hfi1_qp_priv *priv = qp->priv;
struct rvt_swqe *wqe;
- struct ib_header *hdr = NULL;
- struct hfi1_16b_header *hdr_16b = NULL;
u32 opcode, head, tail;
u32 psn;
struct tid_rdma_request *req;
@@ -1719,24 +1747,7 @@ void hfi1_rc_send_complete(struct rvt_qp *qp, struct hfi1_opa_header *opah)
if (!(ib_rvt_state_ops[qp->state] & RVT_SEND_OR_FLUSH_OR_RECV_OK))
return;
- /* Find out where the BTH is */
- if (priv->hdr_type == HFI1_PKT_TYPE_9B) {
- hdr = &opah->ibh;
- if (ib_get_lnh(hdr) == HFI1_LRH_BTH)
- ohdr = &hdr->u.oth;
- else
- ohdr = &hdr->u.l.oth;
- } else {
- u8 l4;
-
- hdr_16b = &opah->opah;
- l4 = hfi1_16B_get_l4(hdr_16b);
- if (l4 == OPA_16B_L4_IB_LOCAL)
- ohdr = &hdr_16b->u.oth;
- else
- ohdr = &hdr_16b->u.l.oth;
- }
-
+ ohdr = hfi1_get_rc_ohdr(opah);
opcode = ib_bth_get_opcode(ohdr);
if ((opcode >= OP(RDMA_READ_RESPONSE_FIRST) &&
opcode <= OP(ATOMIC_ACKNOWLEDGE)) ||
@@ -1819,23 +1830,14 @@ void hfi1_rc_send_complete(struct rvt_qp *qp, struct hfi1_opa_header *opah)
}
while (qp->s_last != qp->s_acked) {
- u32 s_last;
-
wqe = rvt_get_swqe_ptr(qp, qp->s_last);
if (cmp_psn(wqe->lpsn, qp->s_sending_psn) >= 0 &&
cmp_psn(qp->s_sending_psn, qp->s_sending_hpsn) <= 0)
break;
trdma_clean_swqe(qp, wqe);
rvt_qp_wqe_unreserve(qp, wqe);
- s_last = qp->s_last;
- trace_hfi1_qp_send_completion(qp, wqe, s_last);
- if (++s_last >= qp->s_size)
- s_last = 0;
- qp->s_last = s_last;
- /* see post_send() */
- barrier();
- rvt_put_qp_swqe(qp, wqe);
- rvt_qp_swqe_complete(qp,
+ trace_hfi1_qp_send_completion(qp, wqe, qp->s_last);
+ rvt_qp_complete_swqe(qp,
wqe,
ib_hfi1_wc_opcode[wqe->wr.opcode],
IB_WC_SUCCESS);
@@ -1879,19 +1881,10 @@ struct rvt_swqe *do_rc_completion(struct rvt_qp *qp,
trace_hfi1_rc_completion(qp, wqe->lpsn);
if (cmp_psn(wqe->lpsn, qp->s_sending_psn) < 0 ||
cmp_psn(qp->s_sending_psn, qp->s_sending_hpsn) > 0) {
- u32 s_last;
-
trdma_clean_swqe(qp, wqe);
- rvt_put_qp_swqe(qp, wqe);
rvt_qp_wqe_unreserve(qp, wqe);
- s_last = qp->s_last;
- trace_hfi1_qp_send_completion(qp, wqe, s_last);
- if (++s_last >= qp->s_size)
- s_last = 0;
- qp->s_last = s_last;
- /* see post_send() */
- barrier();
- rvt_qp_swqe_complete(qp,
+ trace_hfi1_qp_send_completion(qp, wqe, qp->s_last);
+ rvt_qp_complete_swqe(qp,
wqe,
ib_hfi1_wc_opcode[wqe->wr.opcode],
IB_WC_SUCCESS);
@@ -3015,8 +3008,7 @@ send_last:
wc.dlid_path_bits = 0;
wc.port_num = 0;
/* Signal completion event if the solicited bit is set. */
- rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc,
- ib_bth_is_solicited(ohdr));
+ rvt_recv_cq(qp, &wc, ib_bth_is_solicited(ohdr));
break;
case OP(RDMA_WRITE_ONLY):
diff --git a/drivers/infiniband/hw/hfi1/sdma.c b/drivers/infiniband/hw/hfi1/sdma.c
index b0110728f541..2395fd4233a7 100644
--- a/drivers/infiniband/hw/hfi1/sdma.c
+++ b/drivers/infiniband/hw/hfi1/sdma.c
@@ -405,19 +405,33 @@ static void sdma_flush(struct sdma_engine *sde)
struct sdma_txreq *txp, *txp_next;
LIST_HEAD(flushlist);
unsigned long flags;
+ uint seq;
/* flush from head to tail */
sdma_flush_descq(sde);
spin_lock_irqsave(&sde->flushlist_lock, flags);
/* copy flush list */
- list_for_each_entry_safe(txp, txp_next, &sde->flushlist, list) {
- list_del_init(&txp->list);
- list_add_tail(&txp->list, &flushlist);
- }
+ list_splice_init(&sde->flushlist, &flushlist);
spin_unlock_irqrestore(&sde->flushlist_lock, flags);
/* flush from flush list */
list_for_each_entry_safe(txp, txp_next, &flushlist, list)
complete_tx(sde, txp, SDMA_TXREQ_S_ABORTED);
+ /* wakeup QPs orphaned on the dmawait list */
+ do {
+ struct iowait *w, *nw;
+
+ seq = read_seqbegin(&sde->waitlock);
+ if (!list_empty(&sde->dmawait)) {
+ write_seqlock(&sde->waitlock);
+ list_for_each_entry_safe(w, nw, &sde->dmawait, list) {
+ if (w->wakeup) {
+ w->wakeup(w, SDMA_AVAIL_REASON);
+ list_del_init(&w->list);
+ }
+ }
+ write_sequnlock(&sde->waitlock);
+ }
+ } while (read_seqretry(&sde->waitlock, seq));
}
/*
@@ -855,14 +869,13 @@ struct sdma_engine *sdma_select_user_engine(struct hfi1_devdata *dd,
{
struct sdma_rht_node *rht_node;
struct sdma_engine *sde = NULL;
- const struct cpumask *current_mask = &current->cpus_allowed;
unsigned long cpu_id;
/*
* To ensure that always the same sdma engine(s) will be
* selected make sure the process is pinned to this CPU only.
*/
- if (cpumask_weight(current_mask) != 1)
+ if (current->nr_cpus_allowed != 1)
goto out;
cpu_id = smp_processor_id();
@@ -2413,7 +2426,7 @@ unlock_noconn:
list_add_tail(&tx->list, &sde->flushlist);
spin_unlock(&sde->flushlist_lock);
iowait_inc_wait_count(wait, tx->num_desc);
- schedule_work(&sde->flush_worker);
+ queue_work_on(sde->cpu, system_highpri_wq, &sde->flush_worker);
ret = -ECOMM;
goto unlock;
nodesc:
@@ -2511,7 +2524,7 @@ unlock_noconn:
iowait_inc_wait_count(wait, tx->num_desc);
}
spin_unlock(&sde->flushlist_lock);
- schedule_work(&sde->flush_worker);
+ queue_work_on(sde->cpu, system_highpri_wq, &sde->flush_worker);
ret = -ECOMM;
goto update_tail;
nodesc:
diff --git a/drivers/infiniband/hw/hfi1/tid_rdma.c b/drivers/infiniband/hw/hfi1/tid_rdma.c
index 6fb93032fbef..92acccaaaa86 100644
--- a/drivers/infiniband/hw/hfi1/tid_rdma.c
+++ b/drivers/infiniband/hw/hfi1/tid_rdma.c
@@ -312,9 +312,7 @@ static struct hfi1_ctxtdata *qp_to_rcd(struct rvt_dev_info *rdi,
if (qp->ibqp.qp_num == 0)
ctxt = 0;
else
- ctxt = ((qp->ibqp.qp_num >> dd->qos_shift) %
- (dd->n_krcv_queues - 1)) + 1;
-
+ ctxt = hfi1_get_qp_map(dd, qp->ibqp.qp_num >> dd->qos_shift);
return dd->rcd[ctxt];
}
@@ -477,7 +475,7 @@ static struct rvt_qp *first_qp(struct hfi1_ctxtdata *rcd,
* Must hold the qp s_lock and the exp_lock.
*
* Return:
- * false if either of the conditions below are statisfied:
+ * false if either of the conditions below are satisfied:
* 1. The list is empty or
* 2. The indicated qp is at the head of the list and the
* HFI1_S_WAIT_TID_SPACE bit is set in qp->s_flags.
@@ -2026,7 +2024,6 @@ static int tid_rdma_rcv_error(struct hfi1_packet *packet,
trace_hfi1_tid_req_rcv_err(qp, 0, e->opcode, e->psn, e->lpsn, req);
if (e->opcode == TID_OP(READ_REQ)) {
struct ib_reth *reth;
- u32 offset;
u32 len;
u32 rkey;
u64 vaddr;
@@ -2038,7 +2035,6 @@ static int tid_rdma_rcv_error(struct hfi1_packet *packet,
* The requester always restarts from the start of the original
* request.
*/
- offset = delta_psn(psn, e->psn) * qp->pmtu;
len = be32_to_cpu(reth->length);
if (psn != e->psn || len != req->total_len)
goto unlock;
@@ -4552,7 +4548,7 @@ void hfi1_rc_rcv_tid_rdma_ack(struct hfi1_packet *packet)
struct rvt_swqe *wqe;
struct tid_rdma_request *req;
struct tid_rdma_flow *flow;
- u32 aeth, psn, req_psn, ack_psn, fspsn, resync_psn, ack_kpsn;
+ u32 aeth, psn, req_psn, ack_psn, resync_psn, ack_kpsn;
unsigned long flags;
u16 fidx;
@@ -4756,7 +4752,6 @@ done:
IB_AETH_CREDIT_MASK) {
case 0: /* PSN sequence error */
flow = &req->flows[req->acked_tail];
- fspsn = full_flow_psn(flow, flow->flow_state.spsn);
trace_hfi1_tid_flow_rcv_tid_ack(qp, req->acked_tail,
flow);
req->r_ack_psn = mask_psn(be32_to_cpu(ohdr->bth[2]));
diff --git a/drivers/infiniband/hw/hfi1/trace_ibhdrs.h b/drivers/infiniband/hw/hfi1/trace_ibhdrs.h
index d1372cc66de6..2f84290a88ca 100644
--- a/drivers/infiniband/hw/hfi1/trace_ibhdrs.h
+++ b/drivers/infiniband/hw/hfi1/trace_ibhdrs.h
@@ -79,6 +79,8 @@ __print_symbolic(opcode, \
ib_opcode_name(RC_ATOMIC_ACKNOWLEDGE), \
ib_opcode_name(RC_COMPARE_SWAP), \
ib_opcode_name(RC_FETCH_ADD), \
+ ib_opcode_name(RC_SEND_LAST_WITH_INVALIDATE), \
+ ib_opcode_name(RC_SEND_ONLY_WITH_INVALIDATE), \
ib_opcode_name(TID_RDMA_WRITE_REQ), \
ib_opcode_name(TID_RDMA_WRITE_RESP), \
ib_opcode_name(TID_RDMA_WRITE_DATA), \
diff --git a/drivers/infiniband/hw/hfi1/uc.c b/drivers/infiniband/hw/hfi1/uc.c
index 4ed4fcfabd6c..0c77f18120ed 100644
--- a/drivers/infiniband/hw/hfi1/uc.c
+++ b/drivers/infiniband/hw/hfi1/uc.c
@@ -476,8 +476,7 @@ last_imm:
wc.dlid_path_bits = 0;
wc.port_num = 0;
/* Signal completion event if the solicited bit is set. */
- rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc,
- ib_bth_is_solicited(ohdr));
+ rvt_recv_cq(qp, &wc, ib_bth_is_solicited(ohdr));
break;
case OP(RDMA_WRITE_FIRST):
diff --git a/drivers/infiniband/hw/hfi1/ud.c b/drivers/infiniband/hw/hfi1/ud.c
index f88ad425664a..e804af71b629 100644
--- a/drivers/infiniband/hw/hfi1/ud.c
+++ b/drivers/infiniband/hw/hfi1/ud.c
@@ -1,5 +1,5 @@
/*
- * Copyright(c) 2015 - 2018 Intel Corporation.
+ * Copyright(c) 2015 - 2019 Intel Corporation.
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
@@ -87,7 +87,7 @@ static void ud_loopback(struct rvt_qp *sqp, struct rvt_swqe *swqe)
rcu_read_lock();
qp = rvt_lookup_qpn(ib_to_rvt(sqp->ibqp.device), &ibp->rvp,
- swqe->ud_wr.remote_qpn);
+ rvt_get_swqe_remote_qpn(swqe));
if (!qp) {
ibp->rvp.n_pkt_drops++;
rcu_read_unlock();
@@ -105,7 +105,7 @@ static void ud_loopback(struct rvt_qp *sqp, struct rvt_swqe *swqe)
goto drop;
}
- ah_attr = &ibah_to_rvtah(swqe->ud_wr.ah)->attr;
+ ah_attr = rvt_get_swqe_ah_attr(swqe);
ppd = ppd_from_ibp(ibp);
if (qp->ibqp.qp_num > 1) {
@@ -135,8 +135,8 @@ static void ud_loopback(struct rvt_qp *sqp, struct rvt_swqe *swqe)
if (qp->ibqp.qp_num) {
u32 qkey;
- qkey = (int)swqe->ud_wr.remote_qkey < 0 ?
- sqp->qkey : swqe->ud_wr.remote_qkey;
+ qkey = (int)rvt_get_swqe_remote_qkey(swqe) < 0 ?
+ sqp->qkey : rvt_get_swqe_remote_qkey(swqe);
if (unlikely(qkey != qp->qkey))
goto drop; /* silently drop per IBTA spec */
}
@@ -240,7 +240,7 @@ static void ud_loopback(struct rvt_qp *sqp, struct rvt_swqe *swqe)
if (qp->ibqp.qp_type == IB_QPT_GSI || qp->ibqp.qp_type == IB_QPT_SMI) {
if (sqp->ibqp.qp_type == IB_QPT_GSI ||
sqp->ibqp.qp_type == IB_QPT_SMI)
- wc.pkey_index = swqe->ud_wr.pkey_index;
+ wc.pkey_index = rvt_get_swqe_pkey_index(swqe);
else
wc.pkey_index = sqp->s_pkey_index;
} else {
@@ -255,8 +255,7 @@ static void ud_loopback(struct rvt_qp *sqp, struct rvt_swqe *swqe)
wc.dlid_path_bits = rdma_ah_get_dlid(ah_attr) & ((1 << ppd->lmc) - 1);
wc.port_num = qp->port_num;
/* Signal completion event if the solicited bit is set. */
- rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc,
- swqe->wr.send_flags & IB_SEND_SOLICITED);
+ rvt_recv_cq(qp, &wc, swqe->wr.send_flags & IB_SEND_SOLICITED);
ibp->rvp.n_loop_pkts++;
bail_unlock:
spin_unlock_irqrestore(&qp->r_lock, flags);
@@ -283,20 +282,21 @@ static void hfi1_make_bth_deth(struct rvt_qp *qp, struct rvt_swqe *wqe,
bth0 |= IB_BTH_SOLICITED;
bth0 |= extra_bytes << 20;
if (qp->ibqp.qp_type == IB_QPT_GSI || qp->ibqp.qp_type == IB_QPT_SMI)
- *pkey = hfi1_get_pkey(ibp, wqe->ud_wr.pkey_index);
+ *pkey = hfi1_get_pkey(ibp, rvt_get_swqe_pkey_index(wqe));
else
*pkey = hfi1_get_pkey(ibp, qp->s_pkey_index);
if (!bypass)
bth0 |= *pkey;
ohdr->bth[0] = cpu_to_be32(bth0);
- ohdr->bth[1] = cpu_to_be32(wqe->ud_wr.remote_qpn);
+ ohdr->bth[1] = cpu_to_be32(rvt_get_swqe_remote_qpn(wqe));
ohdr->bth[2] = cpu_to_be32(mask_psn(wqe->psn));
/*
* Qkeys with the high order bit set mean use the
* qkey from the QP context instead of the WR (see 10.2.5).
*/
- ohdr->u.ud.deth[0] = cpu_to_be32((int)wqe->ud_wr.remote_qkey < 0 ?
- qp->qkey : wqe->ud_wr.remote_qkey);
+ ohdr->u.ud.deth[0] =
+ cpu_to_be32((int)rvt_get_swqe_remote_qkey(wqe) < 0 ? qp->qkey :
+ rvt_get_swqe_remote_qkey(wqe));
ohdr->u.ud.deth[1] = cpu_to_be32(qp->ibqp.qp_num);
}
@@ -316,7 +316,7 @@ void hfi1_make_ud_req_9B(struct rvt_qp *qp, struct hfi1_pkt_state *ps,
ibp = to_iport(qp->ibqp.device, qp->port_num);
ppd = ppd_from_ibp(ibp);
- ah_attr = &ibah_to_rvtah(wqe->ud_wr.ah)->attr;
+ ah_attr = rvt_get_swqe_ah_attr(wqe);
extra_bytes = -wqe->length & 3;
nwords = ((wqe->length + extra_bytes) >> 2) + SIZE_OF_CRC;
@@ -380,7 +380,7 @@ void hfi1_make_ud_req_16B(struct rvt_qp *qp, struct hfi1_pkt_state *ps,
struct hfi1_pportdata *ppd;
struct hfi1_ibport *ibp;
u32 dlid, slid, nwords, extra_bytes;
- u32 dest_qp = wqe->ud_wr.remote_qpn;
+ u32 dest_qp = rvt_get_swqe_remote_qpn(wqe);
u32 src_qp = qp->ibqp.qp_num;
u16 len, pkey;
u8 l4, sc5;
@@ -388,7 +388,7 @@ void hfi1_make_ud_req_16B(struct rvt_qp *qp, struct hfi1_pkt_state *ps,
ibp = to_iport(qp->ibqp.device, qp->port_num);
ppd = ppd_from_ibp(ibp);
- ah_attr = &ibah_to_rvtah(wqe->ud_wr.ah)->attr;
+ ah_attr = rvt_get_swqe_ah_attr(wqe);
/*
* Build 16B Management Packet if either the destination
@@ -450,7 +450,7 @@ void hfi1_make_ud_req_16B(struct rvt_qp *qp, struct hfi1_pkt_state *ps,
if (is_mgmt) {
l4 = OPA_16B_L4_FM;
- pkey = hfi1_get_pkey(ibp, wqe->ud_wr.pkey_index);
+ pkey = hfi1_get_pkey(ibp, rvt_get_swqe_pkey_index(wqe));
hfi1_16B_set_qpn(&ps->s_txreq->phdr.hdr.opah.u.mgmt,
dest_qp, src_qp);
} else {
@@ -515,7 +515,7 @@ int hfi1_make_ud_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps)
/* Construct the header. */
ibp = to_iport(qp->ibqp.device, qp->port_num);
ppd = ppd_from_ibp(ibp);
- ah_attr = &ibah_to_rvtah(wqe->ud_wr.ah)->attr;
+ ah_attr = rvt_get_swqe_ah_attr(wqe);
priv->hdr_type = hfi1_get_hdr_type(ppd->lid, ah_attr);
if ((!hfi1_check_mcast(rdma_ah_get_dlid(ah_attr))) ||
(rdma_ah_get_dlid(ah_attr) == be32_to_cpu(OPA_LID_PERMISSIVE))) {
@@ -683,7 +683,7 @@ void return_cnp_16B(struct hfi1_ibport *ibp, struct rvt_qp *qp,
pbc = create_pbc(ppd, pbc_flags, qp->srate_mbps, vl, plen);
if (ctxt) {
pbuf = sc_buffer_alloc(ctxt, plen, NULL, NULL);
- if (pbuf) {
+ if (!IS_ERR_OR_NULL(pbuf)) {
trace_pio_output_ibhdr(ppd->dd, &hdr, sc5);
ppd->dd->pio_inline_send(ppd->dd, pbuf, pbc,
&hdr, hwords);
@@ -738,7 +738,7 @@ void return_cnp(struct hfi1_ibport *ibp, struct rvt_qp *qp, u32 remote_qpn,
pbc = create_pbc(ppd, pbc_flags, qp->srate_mbps, vl, plen);
if (ctxt) {
pbuf = sc_buffer_alloc(ctxt, plen, NULL, NULL);
- if (pbuf) {
+ if (!IS_ERR_OR_NULL(pbuf)) {
trace_pio_output_ibhdr(ppd->dd, &hdr, sc5);
ppd->dd->pio_inline_send(ppd->dd, pbuf, pbc,
&hdr, hwords);
@@ -1061,7 +1061,7 @@ void hfi1_ud_rcv(struct hfi1_packet *packet)
dlid & ((1 << ppd_from_ibp(ibp)->lmc) - 1);
wc.port_num = qp->port_num;
/* Signal completion event if the solicited bit is set. */
- rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc, solicited);
+ rvt_recv_cq(qp, &wc, solicited);
return;
drop:
diff --git a/drivers/infiniband/hw/hfi1/user_pages.c b/drivers/infiniband/hw/hfi1/user_pages.c
index 02eee8eff1db..b89a9b9aef7a 100644
--- a/drivers/infiniband/hw/hfi1/user_pages.c
+++ b/drivers/infiniband/hw/hfi1/user_pages.c
@@ -118,13 +118,10 @@ int hfi1_acquire_user_pages(struct mm_struct *mm, unsigned long vaddr, size_t np
void hfi1_release_user_pages(struct mm_struct *mm, struct page **p,
size_t npages, bool dirty)
{
- size_t i;
-
- for (i = 0; i < npages; i++) {
- if (dirty)
- set_page_dirty_lock(p[i]);
- put_page(p[i]);
- }
+ if (dirty)
+ put_user_pages_dirty_lock(p, npages);
+ else
+ put_user_pages(p, npages);
if (mm) { /* during close after signal, mm can be NULL */
atomic64_sub(npages, &mm->pinned_vm);
diff --git a/drivers/infiniband/hw/hfi1/user_sdma.c b/drivers/infiniband/hw/hfi1/user_sdma.c
index 8bfbc6d7ea34..fd754a16475a 100644
--- a/drivers/infiniband/hw/hfi1/user_sdma.c
+++ b/drivers/infiniband/hw/hfi1/user_sdma.c
@@ -130,20 +130,16 @@ static int defer_packet_queue(
{
struct hfi1_user_sdma_pkt_q *pq =
container_of(wait->iow, struct hfi1_user_sdma_pkt_q, busy);
- struct user_sdma_txreq *tx =
- container_of(txreq, struct user_sdma_txreq, txreq);
- if (sdma_progress(sde, seq, txreq)) {
- if (tx->busycount++ < MAX_DEFER_RETRY_COUNT)
- goto eagain;
- }
+ write_seqlock(&sde->waitlock);
+ if (sdma_progress(sde, seq, txreq))
+ goto eagain;
/*
* We are assuming that if the list is enqueued somewhere, it
* is to the dmawait list since that is the only place where
* it is supposed to be enqueued.
*/
xchg(&pq->state, SDMA_PKT_Q_DEFERRED);
- write_seqlock(&sde->waitlock);
if (list_empty(&pq->busy.list)) {
iowait_get_priority(&pq->busy);
iowait_queue(pkts_sent, &pq->busy, &sde->dmawait);
@@ -151,6 +147,7 @@ static int defer_packet_queue(
write_sequnlock(&sde->waitlock);
return -EBUSY;
eagain:
+ write_sequnlock(&sde->waitlock);
return -EAGAIN;
}
@@ -804,7 +801,6 @@ static int user_sdma_send_pkts(struct user_sdma_request *req, u16 maxpkts)
tx->flags = 0;
tx->req = req;
- tx->busycount = 0;
INIT_LIST_HEAD(&tx->list);
/*
diff --git a/drivers/infiniband/hw/hfi1/user_sdma.h b/drivers/infiniband/hw/hfi1/user_sdma.h
index 14dfd757dafd..4d8510b0fc38 100644
--- a/drivers/infiniband/hw/hfi1/user_sdma.h
+++ b/drivers/infiniband/hw/hfi1/user_sdma.h
@@ -245,7 +245,6 @@ struct user_sdma_txreq {
struct list_head list;
struct user_sdma_request *req;
u16 flags;
- unsigned int busycount;
u16 seqnum;
};
diff --git a/drivers/infiniband/hw/hfi1/verbs.c b/drivers/infiniband/hw/hfi1/verbs.c
index a2b26a635baf..c4b243f50c76 100644
--- a/drivers/infiniband/hw/hfi1/verbs.c
+++ b/drivers/infiniband/hw/hfi1/verbs.c
@@ -638,6 +638,8 @@ static void verbs_sdma_complete(
struct hfi1_opa_header *hdr;
hdr = &tx->phdr.hdr;
+ if (unlikely(status == SDMA_TXREQ_S_ABORTED))
+ hfi1_rc_verbs_aborted(qp, hdr);
hfi1_rc_send_complete(qp, hdr);
}
spin_unlock(&qp->s_lock);
@@ -1037,10 +1039,10 @@ int hfi1_verbs_send_pio(struct rvt_qp *qp, struct hfi1_pkt_state *ps,
if (cb)
iowait_pio_inc(&priv->s_iowait);
pbuf = sc_buffer_alloc(sc, plen, cb, qp);
- if (unlikely(!pbuf)) {
+ if (unlikely(IS_ERR_OR_NULL(pbuf))) {
if (cb)
verbs_pio_complete(qp, 0);
- if (ppd->host_link_state != HLS_UP_ACTIVE) {
+ if (IS_ERR(pbuf)) {
/*
* If we have filled the PIO buffers to capacity and are
* not in an active state this request is not going to
@@ -1095,15 +1097,15 @@ int hfi1_verbs_send_pio(struct rvt_qp *qp, struct hfi1_pkt_state *ps,
&ps->s_txreq->phdr.hdr, ib_is_sc5(sc5));
pio_bail:
+ spin_lock_irqsave(&qp->s_lock, flags);
if (qp->s_wqe) {
- spin_lock_irqsave(&qp->s_lock, flags);
rvt_send_complete(qp, qp->s_wqe, wc_status);
- spin_unlock_irqrestore(&qp->s_lock, flags);
} else if (qp->ibqp.qp_type == IB_QPT_RC) {
- spin_lock_irqsave(&qp->s_lock, flags);
+ if (unlikely(wc_status == IB_WC_GENERAL_ERR))
+ hfi1_rc_verbs_aborted(qp, &ps->s_txreq->phdr.hdr);
hfi1_rc_send_complete(qp, &ps->s_txreq->phdr.hdr);
- spin_unlock_irqrestore(&qp->s_lock, flags);
}
+ spin_unlock_irqrestore(&qp->s_lock, flags);
ret = 0;
@@ -1777,6 +1779,9 @@ static int get_hw_stats(struct ib_device *ibdev, struct rdma_hw_stats *stats,
}
static const struct ib_device_ops hfi1_dev_ops = {
+ .owner = THIS_MODULE,
+ .driver_id = RDMA_DRIVER_HFI1,
+
.alloc_hw_stats = alloc_hw_stats,
.alloc_rdma_netdev = hfi1_vnic_alloc_rn,
.get_dev_fw_str = hfi1_get_dev_fw_str,
@@ -1827,7 +1832,6 @@ int hfi1_register_ib_device(struct hfi1_devdata *dd)
*/
if (!ib_hfi1_sys_image_guid)
ib_hfi1_sys_image_guid = ibdev->node_guid;
- ibdev->owner = THIS_MODULE;
ibdev->phys_port_cnt = dd->num_pports;
ibdev->dev.parent = &dd->pcidev->dev;
@@ -1921,7 +1925,7 @@ int hfi1_register_ib_device(struct hfi1_devdata *dd)
rdma_set_device_sysfs_group(&dd->verbs_dev.rdi.ibdev,
&ib_hfi1_attr_group);
- ret = rvt_register_device(&dd->verbs_dev.rdi, RDMA_DRIVER_HFI1);
+ ret = rvt_register_device(&dd->verbs_dev.rdi);
if (ret)
goto err_verbs_txreq;
diff --git a/drivers/infiniband/hw/hfi1/verbs.h b/drivers/infiniband/hw/hfi1/verbs.h
index 7ecb8ed4a1d9..ae9582ddbc8f 100644
--- a/drivers/infiniband/hw/hfi1/verbs.h
+++ b/drivers/infiniband/hw/hfi1/verbs.h
@@ -416,6 +416,7 @@ void hfi1_rc_hdrerr(
u8 ah_to_sc(struct ib_device *ibdev, struct rdma_ah_attr *ah_attr);
+void hfi1_rc_verbs_aborted(struct rvt_qp *qp, struct hfi1_opa_header *opah);
void hfi1_rc_send_complete(struct rvt_qp *qp, struct hfi1_opa_header *opah);
void hfi1_ud_rcv(struct hfi1_packet *packet);
diff --git a/drivers/infiniband/hw/hfi1/verbs_txreq.c b/drivers/infiniband/hw/hfi1/verbs_txreq.c
index c4ab2d5b4502..8f766dd3f61c 100644
--- a/drivers/infiniband/hw/hfi1/verbs_txreq.c
+++ b/drivers/infiniband/hw/hfi1/verbs_txreq.c
@@ -100,7 +100,7 @@ struct verbs_txreq *__get_txreq(struct hfi1_ibdev *dev,
if (ib_rvt_state_ops[qp->state] & RVT_PROCESS_RECV_OK) {
struct hfi1_qp_priv *priv;
- tx = kmem_cache_alloc(dev->verbs_txreq_cache, GFP_ATOMIC);
+ tx = kmem_cache_alloc(dev->verbs_txreq_cache, VERBS_TXREQ_GFP);
if (tx)
goto out;
priv = qp->priv;
diff --git a/drivers/infiniband/hw/hfi1/verbs_txreq.h b/drivers/infiniband/hw/hfi1/verbs_txreq.h
index b002e96eb335..bfa6e081cb56 100644
--- a/drivers/infiniband/hw/hfi1/verbs_txreq.h
+++ b/drivers/infiniband/hw/hfi1/verbs_txreq.h
@@ -72,6 +72,7 @@ struct hfi1_ibdev;
struct verbs_txreq *__get_txreq(struct hfi1_ibdev *dev,
struct rvt_qp *qp);
+#define VERBS_TXREQ_GFP (GFP_ATOMIC | __GFP_NOWARN)
static inline struct verbs_txreq *get_txreq(struct hfi1_ibdev *dev,
struct rvt_qp *qp)
__must_hold(&qp->slock)
@@ -79,7 +80,7 @@ static inline struct verbs_txreq *get_txreq(struct hfi1_ibdev *dev,
struct verbs_txreq *tx;
struct hfi1_qp_priv *priv = qp->priv;
- tx = kmem_cache_alloc(dev->verbs_txreq_cache, GFP_ATOMIC);
+ tx = kmem_cache_alloc(dev->verbs_txreq_cache, VERBS_TXREQ_GFP);
if (unlikely(!tx)) {
/* call slow path to get the lock */
tx = __get_txreq(dev, qp);
diff --git a/drivers/infiniband/hw/hns/Kconfig b/drivers/infiniband/hw/hns/Kconfig
index 61cda7d00627..8bf847bcd8d3 100644
--- a/drivers/infiniband/hw/hns/Kconfig
+++ b/drivers/infiniband/hw/hns/Kconfig
@@ -8,25 +8,24 @@ config INFINIBAND_HNS
is used in Hisilicon Hip06 and more further ICT SoC based on
platform device.
- To compile this driver as a module, choose M here: the module
- will be called hns-roce.
+ To compile HIP06 or HIP08 driver as module, choose M here.
config INFINIBAND_HNS_HIP06
- tristate "Hisilicon Hip06 Family RoCE support"
+ bool "Hisilicon Hip06 Family RoCE support"
depends on INFINIBAND_HNS && HNS && HNS_DSAF && HNS_ENET
---help---
RoCE driver support for Hisilicon RoCE engine in Hisilicon Hip06 and
Hip07 SoC. These RoCE engines are platform devices.
- To compile this driver as a module, choose M here: the module
- will be called hns-roce-hw-v1.
+ To compile this driver, choose Y here: if INFINIBAND_HNS is m, this
+ module will be called hns-roce-hw-v1
config INFINIBAND_HNS_HIP08
- tristate "Hisilicon Hip08 Family RoCE support"
+ bool "Hisilicon Hip08 Family RoCE support"
depends on INFINIBAND_HNS && PCI && HNS3
---help---
RoCE driver support for Hisilicon RoCE engine in Hisilicon Hip08 SoC.
The RoCE engine is a PCI device.
- To compile this driver as a module, choose M here: the module
- will be called hns-roce-hw-v2.
+ To compile this driver, choose Y here: if INFINIBAND_HNS is m, this
+ module will be called hns-roce-hw-v2.
diff --git a/drivers/infiniband/hw/hns/Makefile b/drivers/infiniband/hw/hns/Makefile
index f22d9922cfee..e105945b94a1 100644
--- a/drivers/infiniband/hw/hns/Makefile
+++ b/drivers/infiniband/hw/hns/Makefile
@@ -5,11 +5,16 @@
ccflags-y := -I $(srctree)/drivers/net/ethernet/hisilicon/hns3
-obj-$(CONFIG_INFINIBAND_HNS) += hns-roce.o
hns-roce-objs := hns_roce_main.o hns_roce_cmd.o hns_roce_pd.o \
hns_roce_ah.o hns_roce_hem.o hns_roce_mr.o hns_roce_qp.o \
hns_roce_cq.o hns_roce_alloc.o hns_roce_db.o hns_roce_srq.o hns_roce_restrack.o
-obj-$(CONFIG_INFINIBAND_HNS_HIP06) += hns-roce-hw-v1.o
-hns-roce-hw-v1-objs := hns_roce_hw_v1.o
-obj-$(CONFIG_INFINIBAND_HNS_HIP08) += hns-roce-hw-v2.o
-hns-roce-hw-v2-objs := hns_roce_hw_v2.o hns_roce_hw_v2_dfx.o
+
+ifdef CONFIG_INFINIBAND_HNS_HIP06
+hns-roce-hw-v1-objs := hns_roce_hw_v1.o $(hns-roce-objs)
+obj-$(CONFIG_INFINIBAND_HNS) += hns-roce-hw-v1.o
+endif
+
+ifdef CONFIG_INFINIBAND_HNS_HIP08
+hns-roce-hw-v2-objs := hns_roce_hw_v2.o hns_roce_hw_v2_dfx.o $(hns-roce-objs)
+obj-$(CONFIG_INFINIBAND_HNS) += hns-roce-hw-v2.o
+endif
diff --git a/drivers/infiniband/hw/hns/hns_roce_alloc.c b/drivers/infiniband/hw/hns/hns_roce_alloc.c
index dac058d3df53..8c063c598d2a 100644
--- a/drivers/infiniband/hw/hns/hns_roce_alloc.c
+++ b/drivers/infiniband/hw/hns/hns_roce_alloc.c
@@ -34,6 +34,7 @@
#include <linux/platform_device.h>
#include <linux/vmalloc.h>
#include "hns_roce_device.h"
+#include <rdma/ib_umem.h>
int hns_roce_bitmap_alloc(struct hns_roce_bitmap *bitmap, unsigned long *obj)
{
@@ -67,7 +68,6 @@ void hns_roce_bitmap_free(struct hns_roce_bitmap *bitmap, unsigned long obj,
{
hns_roce_bitmap_free_range(bitmap, obj, 1, rr);
}
-EXPORT_SYMBOL_GPL(hns_roce_bitmap_free);
int hns_roce_bitmap_alloc_range(struct hns_roce_bitmap *bitmap, int cnt,
int align, unsigned long *obj)
@@ -174,7 +174,6 @@ void hns_roce_buf_free(struct hns_roce_dev *hr_dev, u32 size,
kfree(buf->page_list);
}
}
-EXPORT_SYMBOL_GPL(hns_roce_buf_free);
int hns_roce_buf_alloc(struct hns_roce_dev *hr_dev, u32 size, u32 max_direct,
struct hns_roce_buf *buf, u32 page_shift)
@@ -238,6 +237,104 @@ err_free:
return -ENOMEM;
}
+int hns_roce_get_kmem_bufs(struct hns_roce_dev *hr_dev, dma_addr_t *bufs,
+ int buf_cnt, int start, struct hns_roce_buf *buf)
+{
+ int i, end;
+ int total;
+
+ end = start + buf_cnt;
+ if (end > buf->npages) {
+ dev_err(hr_dev->dev,
+ "invalid kmem region,offset %d,buf_cnt %d,total %d!\n",
+ start, buf_cnt, buf->npages);
+ return -EINVAL;
+ }
+
+ total = 0;
+ for (i = start; i < end; i++)
+ if (buf->nbufs == 1)
+ bufs[total++] = buf->direct.map +
+ ((dma_addr_t)i << buf->page_shift);
+ else
+ bufs[total++] = buf->page_list[i].map;
+
+ return total;
+}
+
+int hns_roce_get_umem_bufs(struct hns_roce_dev *hr_dev, dma_addr_t *bufs,
+ int buf_cnt, int start, struct ib_umem *umem,
+ int page_shift)
+{
+ struct ib_block_iter biter;
+ int total = 0;
+ int idx = 0;
+ u64 addr;
+
+ if (page_shift < PAGE_SHIFT) {
+ dev_err(hr_dev->dev, "invalid page shift %d!\n", page_shift);
+ return -EINVAL;
+ }
+
+ /* convert system page cnt to hw page cnt */
+ rdma_for_each_block(umem->sg_head.sgl, &biter, umem->nmap,
+ 1 << page_shift) {
+ addr = rdma_block_iter_dma_address(&biter);
+ if (idx >= start) {
+ bufs[total++] = addr;
+ if (total >= buf_cnt)
+ goto done;
+ }
+ idx++;
+ }
+
+done:
+ return total;
+}
+
+void hns_roce_init_buf_region(struct hns_roce_buf_region *region, int hopnum,
+ int offset, int buf_cnt)
+{
+ if (hopnum == HNS_ROCE_HOP_NUM_0)
+ region->hopnum = 0;
+ else
+ region->hopnum = hopnum;
+
+ region->offset = offset;
+ region->count = buf_cnt;
+}
+
+void hns_roce_free_buf_list(dma_addr_t **bufs, int region_cnt)
+{
+ int i;
+
+ for (i = 0; i < region_cnt; i++) {
+ kfree(bufs[i]);
+ bufs[i] = NULL;
+ }
+}
+
+int hns_roce_alloc_buf_list(struct hns_roce_buf_region *regions,
+ dma_addr_t **bufs, int region_cnt)
+{
+ struct hns_roce_buf_region *r;
+ int i;
+
+ for (i = 0; i < region_cnt; i++) {
+ r = &regions[i];
+ bufs[i] = kcalloc(r->count, sizeof(dma_addr_t), GFP_KERNEL);
+ if (!bufs[i])
+ goto err_alloc;
+ }
+
+ return 0;
+
+err_alloc:
+ hns_roce_free_buf_list(bufs, i);
+
+ return -ENOMEM;
+}
+
void hns_roce_cleanup_bitmap(struct hns_roce_dev *hr_dev)
{
if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_SRQ)
diff --git a/drivers/infiniband/hw/hns/hns_roce_cmd.c b/drivers/infiniband/hw/hns/hns_roce_cmd.c
index 2acf946d02e5..0cd09bf4d7ea 100644
--- a/drivers/infiniband/hw/hns/hns_roce_cmd.c
+++ b/drivers/infiniband/hw/hns/hns_roce_cmd.c
@@ -103,7 +103,6 @@ void hns_roce_cmd_event(struct hns_roce_dev *hr_dev, u16 token, u8 status,
context->out_param = out_param;
complete(&context->done);
}
-EXPORT_SYMBOL_GPL(hns_roce_cmd_event);
/* this should be called with "use_events" */
static int __hns_roce_cmd_mbox_wait(struct hns_roce_dev *hr_dev, u64 in_param,
@@ -162,7 +161,7 @@ static int hns_roce_cmd_mbox_wait(struct hns_roce_dev *hr_dev, u64 in_param,
u64 out_param, unsigned long in_modifier,
u8 op_modifier, u16 op, unsigned long timeout)
{
- int ret = 0;
+ int ret;
down(&hr_dev->cmd.event_sem);
ret = __hns_roce_cmd_mbox_wait(hr_dev, in_param, out_param,
@@ -204,7 +203,6 @@ int hns_roce_cmd_mbox(struct hns_roce_dev *hr_dev, u64 in_param, u64 out_param,
return ret;
}
-EXPORT_SYMBOL_GPL(hns_roce_cmd_mbox);
int hns_roce_cmd_init(struct hns_roce_dev *hr_dev)
{
@@ -291,7 +289,6 @@ struct hns_roce_cmd_mailbox
return mailbox;
}
-EXPORT_SYMBOL_GPL(hns_roce_alloc_cmd_mailbox);
void hns_roce_free_cmd_mailbox(struct hns_roce_dev *hr_dev,
struct hns_roce_cmd_mailbox *mailbox)
@@ -302,4 +299,3 @@ void hns_roce_free_cmd_mailbox(struct hns_roce_dev *hr_dev,
dma_pool_free(hr_dev->cmd.pool, mailbox->buf, mailbox->dma);
kfree(mailbox);
}
-EXPORT_SYMBOL_GPL(hns_roce_free_cmd_mailbox);
diff --git a/drivers/infiniband/hw/hns/hns_roce_cq.c b/drivers/infiniband/hw/hns/hns_roce_cq.c
index 9caf35061721..4e50c22a2da4 100644
--- a/drivers/infiniband/hw/hns/hns_roce_cq.c
+++ b/drivers/infiniband/hw/hns/hns_roce_cq.c
@@ -205,7 +205,6 @@ void hns_roce_free_cq(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq)
hns_roce_table_put(hr_dev, &cq_table->table, hr_cq->cqn);
hns_roce_bitmap_free(&cq_table->bitmap, hr_cq->cqn, BITMAP_NO_RR);
}
-EXPORT_SYMBOL_GPL(hns_roce_free_cq);
static int hns_roce_ib_get_cq_umem(struct hns_roce_dev *hr_dev,
struct ib_udata *udata,
@@ -235,8 +234,7 @@ static int hns_roce_ib_get_cq_umem(struct hns_roce_dev *hr_dev,
&buf->hr_mtt);
} else {
ret = hns_roce_mtt_init(hr_dev, ib_umem_page_count(*umem),
- (*umem)->page_shift,
- &buf->hr_mtt);
+ PAGE_SHIFT, &buf->hr_mtt);
}
if (ret)
goto err_buf;
@@ -300,15 +298,15 @@ static void hns_roce_ib_free_cq_buf(struct hns_roce_dev *hr_dev,
&buf->hr_buf);
}
-struct ib_cq *hns_roce_ib_create_cq(struct ib_device *ib_dev,
- const struct ib_cq_init_attr *attr,
- struct ib_udata *udata)
+int hns_roce_ib_create_cq(struct ib_cq *ib_cq,
+ const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata)
{
- struct hns_roce_dev *hr_dev = to_hr_dev(ib_dev);
+ struct hns_roce_dev *hr_dev = to_hr_dev(ib_cq->device);
struct device *dev = hr_dev->dev;
struct hns_roce_ib_create_cq ucmd;
struct hns_roce_ib_create_cq_resp resp = {};
- struct hns_roce_cq *hr_cq = NULL;
+ struct hns_roce_cq *hr_cq = to_hr_cq(ib_cq);
struct hns_roce_uar *uar = NULL;
int vector = attr->comp_vector;
int cq_entries = attr->cqe;
@@ -319,13 +317,9 @@ struct ib_cq *hns_roce_ib_create_cq(struct ib_device *ib_dev,
if (cq_entries < 1 || cq_entries > hr_dev->caps.max_cqes) {
dev_err(dev, "Creat CQ failed. entries=%d, max=%d\n",
cq_entries, hr_dev->caps.max_cqes);
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
}
- hr_cq = kzalloc(sizeof(*hr_cq), GFP_KERNEL);
- if (!hr_cq)
- return ERR_PTR(-ENOMEM);
-
if (hr_dev->caps.min_cqes)
cq_entries = max(cq_entries, hr_dev->caps.min_cqes);
@@ -416,7 +410,7 @@ struct ib_cq *hns_roce_ib_create_cq(struct ib_device *ib_dev,
goto err_cqc;
}
- return &hr_cq->ib_cq;
+ return 0;
err_cqc:
hns_roce_free_cq(hr_dev, hr_cq);
@@ -428,9 +422,8 @@ err_dbmap:
err_mtt:
hns_roce_mtt_cleanup(hr_dev, &hr_cq->hr_buf.hr_mtt);
- if (udata)
- ib_umem_release(hr_cq->umem);
- else
+ ib_umem_release(hr_cq->umem);
+ if (!udata)
hns_roce_ib_free_cq_buf(hr_dev, &hr_cq->hr_buf,
hr_cq->ib_cq.cqe);
@@ -439,47 +432,37 @@ err_db:
hns_roce_free_db(hr_dev, &hr_cq->db);
err_cq:
- kfree(hr_cq);
- return ERR_PTR(ret);
+ return ret;
}
-EXPORT_SYMBOL_GPL(hns_roce_ib_create_cq);
-int hns_roce_ib_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)
+void hns_roce_ib_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)
{
struct hns_roce_dev *hr_dev = to_hr_dev(ib_cq->device);
struct hns_roce_cq *hr_cq = to_hr_cq(ib_cq);
- int ret = 0;
if (hr_dev->hw->destroy_cq) {
- ret = hr_dev->hw->destroy_cq(ib_cq, udata);
- } else {
- hns_roce_free_cq(hr_dev, hr_cq);
- hns_roce_mtt_cleanup(hr_dev, &hr_cq->hr_buf.hr_mtt);
-
- if (udata) {
- ib_umem_release(hr_cq->umem);
-
- if (hr_cq->db_en == 1)
- hns_roce_db_unmap_user(
- rdma_udata_to_drv_context(
- udata,
- struct hns_roce_ucontext,
- ibucontext),
- &hr_cq->db);
- } else {
- /* Free the buff of stored cq */
- hns_roce_ib_free_cq_buf(hr_dev, &hr_cq->hr_buf,
- ib_cq->cqe);
- if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RECORD_DB)
- hns_roce_free_db(hr_dev, &hr_cq->db);
- }
-
- kfree(hr_cq);
+ hr_dev->hw->destroy_cq(ib_cq, udata);
+ return;
}
- return ret;
+ hns_roce_free_cq(hr_dev, hr_cq);
+ hns_roce_mtt_cleanup(hr_dev, &hr_cq->hr_buf.hr_mtt);
+
+ ib_umem_release(hr_cq->umem);
+ if (udata) {
+ if (hr_cq->db_en == 1)
+ hns_roce_db_unmap_user(rdma_udata_to_drv_context(
+ udata,
+ struct hns_roce_ucontext,
+ ibucontext),
+ &hr_cq->db);
+ } else {
+ /* Free the buff of stored cq */
+ hns_roce_ib_free_cq_buf(hr_dev, &hr_cq->hr_buf, ib_cq->cqe);
+ if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RECORD_DB)
+ hns_roce_free_db(hr_dev, &hr_cq->db);
+ }
}
-EXPORT_SYMBOL_GPL(hns_roce_ib_destroy_cq);
void hns_roce_cq_completion(struct hns_roce_dev *hr_dev, u32 cqn)
{
@@ -495,7 +478,6 @@ void hns_roce_cq_completion(struct hns_roce_dev *hr_dev, u32 cqn)
++cq->arm_sn;
cq->comp(cq);
}
-EXPORT_SYMBOL_GPL(hns_roce_cq_completion);
void hns_roce_cq_event(struct hns_roce_dev *hr_dev, u32 cqn, int event_type)
{
@@ -517,7 +499,6 @@ void hns_roce_cq_event(struct hns_roce_dev *hr_dev, u32 cqn, int event_type)
if (atomic_dec_and_test(&cq->refcount))
complete(&cq->free);
}
-EXPORT_SYMBOL_GPL(hns_roce_cq_event);
int hns_roce_init_cq_table(struct hns_roce_dev *hr_dev)
{
diff --git a/drivers/infiniband/hw/hns/hns_roce_db.c b/drivers/infiniband/hw/hns/hns_roce_db.c
index 0c6c1fe87705..627aa46ef683 100644
--- a/drivers/infiniband/hw/hns/hns_roce_db.c
+++ b/drivers/infiniband/hw/hns/hns_roce_db.c
@@ -51,7 +51,6 @@ out:
return ret;
}
-EXPORT_SYMBOL(hns_roce_db_map_user);
void hns_roce_db_unmap_user(struct hns_roce_ucontext *context,
struct hns_roce_db *db)
@@ -67,7 +66,6 @@ void hns_roce_db_unmap_user(struct hns_roce_ucontext *context,
mutex_unlock(&context->page_mutex);
}
-EXPORT_SYMBOL(hns_roce_db_unmap_user);
static struct hns_roce_db_pgdir *hns_roce_alloc_db_pgdir(
struct device *dma_device)
@@ -78,7 +76,8 @@ static struct hns_roce_db_pgdir *hns_roce_alloc_db_pgdir(
if (!pgdir)
return NULL;
- bitmap_fill(pgdir->order1, HNS_ROCE_DB_PER_PAGE / 2);
+ bitmap_fill(pgdir->order1,
+ HNS_ROCE_DB_PER_PAGE / HNS_ROCE_DB_TYPE_COUNT);
pgdir->bits[0] = pgdir->order0;
pgdir->bits[1] = pgdir->order1;
pgdir->page = dma_alloc_coherent(dma_device, PAGE_SIZE,
@@ -116,7 +115,7 @@ found:
db->u.pgdir = pgdir;
db->index = i;
db->db_record = pgdir->page + db->index;
- db->dma = pgdir->db_dma + db->index * 4;
+ db->dma = pgdir->db_dma + db->index * HNS_ROCE_DB_UNIT_SIZE;
db->order = order;
return 0;
@@ -150,7 +149,6 @@ out:
return ret;
}
-EXPORT_SYMBOL_GPL(hns_roce_alloc_db);
void hns_roce_free_db(struct hns_roce_dev *hr_dev, struct hns_roce_db *db)
{
@@ -170,7 +168,8 @@ void hns_roce_free_db(struct hns_roce_dev *hr_dev, struct hns_roce_db *db)
i >>= o;
set_bit(i, db->u.pgdir->bits[o]);
- if (bitmap_full(db->u.pgdir->order1, HNS_ROCE_DB_PER_PAGE / 2)) {
+ if (bitmap_full(db->u.pgdir->order1,
+ HNS_ROCE_DB_PER_PAGE / HNS_ROCE_DB_TYPE_COUNT)) {
dma_free_coherent(hr_dev->dev, PAGE_SIZE, db->u.pgdir->page,
db->u.pgdir->db_dma);
list_del(&db->u.pgdir->list);
@@ -179,4 +178,3 @@ void hns_roce_free_db(struct hns_roce_dev *hr_dev, struct hns_roce_db *db)
mutex_unlock(&hr_dev->pgdir_mutex);
}
-EXPORT_SYMBOL_GPL(hns_roce_free_db);
diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h
index 563cf39df6d5..a548b28aab63 100644
--- a/drivers/infiniband/hw/hns/hns_roce_device.h
+++ b/drivers/infiniband/hw/hns/hns_roce_device.h
@@ -37,9 +37,12 @@
#define DRV_NAME "hns_roce"
+/* hip08 is a pci device, it includes two version according pci version id */
+#define PCI_REVISION_ID_HIP08_A 0x20
+#define PCI_REVISION_ID_HIP08_B 0x21
+
#define HNS_ROCE_HW_VER1 ('h' << 24 | 'i' << 16 | '0' << 8 | '6')
-#define MAC_ADDR_OCTET_NUM 6
#define HNS_ROCE_MAX_MSG_LEN 0x80000000
#define HNS_ROCE_ALOGN_UP(a, b) ((((a) + (b) - 1) / (b)) * (b))
@@ -48,6 +51,10 @@
#define HNS_ROCE_BA_SIZE (32 * 4096)
+#define BA_BYTE_LEN 8
+
+#define BITS_PER_BYTE 8
+
/* Hardware specification only for v1 engine */
#define HNS_ROCE_MIN_CQE_NUM 0x40
#define HNS_ROCE_MIN_WQE_NUM 0x20
@@ -55,6 +62,7 @@
/* Hardware specification only for v1 engine */
#define HNS_ROCE_MAX_INNER_MTPT_NUM 0x7
#define HNS_ROCE_MAX_MTPT_PBL_NUM 0x100000
+#define HNS_ROCE_MAX_SGE_NUM 2
#define HNS_ROCE_EACH_FREE_CQ_WAIT_MSECS 20
#define HNS_ROCE_MAX_FREE_CQ_WAIT_CNT \
@@ -64,6 +72,9 @@
#define HNS_ROCE_MAX_IRQ_NUM 128
+#define HNS_ROCE_SGE_IN_WQE 2
+#define HNS_ROCE_SGE_SHIFT 4
+
#define EQ_ENABLE 1
#define EQ_DISABLE 0
@@ -81,6 +92,7 @@
#define HNS_ROCE_MAX_PORTS 6
#define HNS_ROCE_MAX_GID_NUM 16
#define HNS_ROCE_GID_SIZE 16
+#define HNS_ROCE_SGE_SIZE 16
#define HNS_ROCE_HOP_NUM_0 0xff
@@ -111,6 +123,8 @@
#define PAGES_SHIFT_24 24
#define PAGES_SHIFT_32 32
+#define HNS_ROCE_PCI_BAR_NUM 2
+
#define HNS_ROCE_IDX_QUE_ENTRY_SZ 4
#define SRQ_DB_REG 0x230
@@ -213,6 +227,9 @@ enum hns_roce_mtt_type {
MTT_TYPE_IDX
};
+#define HNS_ROCE_DB_TYPE_COUNT 2
+#define HNS_ROCE_DB_UNIT_SIZE 4
+
enum {
HNS_ROCE_DB_PER_PAGE = PAGE_SIZE / 4
};
@@ -324,6 +341,29 @@ struct hns_roce_mtt {
enum hns_roce_mtt_type mtt_type;
};
+struct hns_roce_buf_region {
+ int offset; /* page offset */
+ u32 count; /* page count*/
+ int hopnum; /* addressing hop num */
+};
+
+#define HNS_ROCE_MAX_BT_REGION 3
+#define HNS_ROCE_MAX_BT_LEVEL 3
+struct hns_roce_hem_list {
+ struct list_head root_bt;
+ /* link all bt dma mem by hop config */
+ struct list_head mid_bt[HNS_ROCE_MAX_BT_REGION][HNS_ROCE_MAX_BT_LEVEL];
+ struct list_head btm_bt; /* link all bottom bt in @mid_bt */
+ dma_addr_t root_ba; /* pointer to the root ba table */
+ int bt_pg_shift;
+};
+
+/* memory translate region */
+struct hns_roce_mtr {
+ struct hns_roce_hem_list hem_list;
+ int buf_pg_shift;
+};
+
struct hns_roce_mw {
struct ib_mw ibmw;
u32 pdn;
@@ -413,8 +453,8 @@ struct hns_roce_buf {
struct hns_roce_db_pgdir {
struct list_head list;
DECLARE_BITMAP(order0, HNS_ROCE_DB_PER_PAGE);
- DECLARE_BITMAP(order1, HNS_ROCE_DB_PER_PAGE / 2);
- unsigned long *bits[2];
+ DECLARE_BITMAP(order1, HNS_ROCE_DB_PER_PAGE / HNS_ROCE_DB_TYPE_COUNT);
+ unsigned long *bits[HNS_ROCE_DB_TYPE_COUNT];
u32 *page;
dma_addr_t db_dma;
};
@@ -472,7 +512,7 @@ struct hns_roce_idx_que {
u32 buf_size;
struct ib_umem *umem;
struct hns_roce_mtt mtt;
- u64 *bitmap;
+ unsigned long *bitmap;
};
struct hns_roce_srq {
@@ -535,7 +575,7 @@ struct hns_roce_av {
u8 hop_limit;
__le32 sl_tclass_flowlabel;
u8 dgid[HNS_ROCE_GID_SIZE];
- u8 mac[6];
+ u8 mac[ETH_ALEN];
__le16 vlan;
bool vlan_en;
};
@@ -620,6 +660,14 @@ struct hns_roce_qp {
struct ib_umem *umem;
struct hns_roce_mtt mtt;
+ struct hns_roce_mtr mtr;
+
+ /* this define must less than HNS_ROCE_MAX_BT_REGION */
+#define HNS_ROCE_WQE_REGION_MAX 3
+ struct hns_roce_buf_region regions[HNS_ROCE_WQE_REGION_MAX];
+ int region_cnt;
+ int wqe_bt_pg_shift;
+
u32 buff_size;
struct mutex mutex;
u8 port;
@@ -830,6 +878,9 @@ struct hns_roce_caps {
u32 mtt_ba_pg_sz;
u32 mtt_buf_pg_sz;
u32 mtt_hop_num;
+ u32 wqe_sq_hop_num;
+ u32 wqe_sge_hop_num;
+ u32 wqe_rq_hop_num;
u32 sccc_ba_pg_sz;
u32 sccc_buf_pg_sz;
u32 sccc_hop_num;
@@ -921,7 +972,7 @@ struct hns_roce_hw {
int (*poll_cq)(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc);
int (*dereg_mr)(struct hns_roce_dev *hr_dev, struct hns_roce_mr *mr,
struct ib_udata *udata);
- int (*destroy_cq)(struct ib_cq *ibcq, struct ib_udata *udata);
+ void (*destroy_cq)(struct ib_cq *ibcq, struct ib_udata *udata);
int (*modify_cq)(struct ib_cq *cq, u16 cq_count, u16 cq_period);
int (*init_eq)(struct hns_roce_dev *hr_dev);
void (*cleanup_eq)(struct hns_roce_dev *hr_dev);
@@ -940,6 +991,16 @@ struct hns_roce_hw {
const struct ib_device_ops *hns_roce_dev_srq_ops;
};
+enum hns_phy_state {
+ HNS_ROCE_PHY_SLEEP = 1,
+ HNS_ROCE_PHY_POLLING = 2,
+ HNS_ROCE_PHY_DISABLED = 3,
+ HNS_ROCE_PHY_TRAINING = 4,
+ HNS_ROCE_PHY_LINKUP = 5,
+ HNS_ROCE_PHY_LINKERR = 6,
+ HNS_ROCE_PHY_TEST = 7
+};
+
struct hns_roce_dev {
struct ib_device ib_dev;
struct platform_device *pdev;
@@ -962,7 +1023,7 @@ struct hns_roce_dev {
struct hns_roce_caps caps;
struct xarray qp_table_xa;
- unsigned char dev_addr[HNS_ROCE_MAX_PORTS][MAC_ADDR_OCTET_NUM];
+ unsigned char dev_addr[HNS_ROCE_MAX_PORTS][ETH_ALEN];
u64 sys_image_guid;
u32 vendor_id;
u32 vendor_part_id;
@@ -1084,6 +1145,19 @@ void hns_roce_mtt_cleanup(struct hns_roce_dev *hr_dev,
int hns_roce_buf_write_mtt(struct hns_roce_dev *hr_dev,
struct hns_roce_mtt *mtt, struct hns_roce_buf *buf);
+void hns_roce_mtr_init(struct hns_roce_mtr *mtr, int bt_pg_shift,
+ int buf_pg_shift);
+int hns_roce_mtr_attach(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
+ dma_addr_t **bufs, struct hns_roce_buf_region *regions,
+ int region_cnt);
+void hns_roce_mtr_cleanup(struct hns_roce_dev *hr_dev,
+ struct hns_roce_mtr *mtr);
+
+/* hns roce hw need current block and next block addr from mtt */
+#define MTT_MIN_COUNT 2
+int hns_roce_mtr_find(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
+ int offset, u64 *mtt_buf, int mtt_max, u64 *base_addr);
+
int hns_roce_init_pd_table(struct hns_roce_dev *hr_dev);
int hns_roce_init_mr_table(struct hns_roce_dev *hr_dev);
int hns_roce_init_eq_table(struct hns_roce_dev *hr_dev);
@@ -1148,6 +1222,18 @@ int hns_roce_buf_alloc(struct hns_roce_dev *hr_dev, u32 size, u32 max_direct,
int hns_roce_ib_umem_write_mtt(struct hns_roce_dev *hr_dev,
struct hns_roce_mtt *mtt, struct ib_umem *umem);
+void hns_roce_init_buf_region(struct hns_roce_buf_region *region, int hopnum,
+ int offset, int buf_cnt);
+int hns_roce_alloc_buf_list(struct hns_roce_buf_region *regions,
+ dma_addr_t **bufs, int count);
+void hns_roce_free_buf_list(dma_addr_t **bufs, int count);
+
+int hns_roce_get_kmem_bufs(struct hns_roce_dev *hr_dev, dma_addr_t *bufs,
+ int buf_cnt, int start, struct hns_roce_buf *buf);
+int hns_roce_get_umem_bufs(struct hns_roce_dev *hr_dev, dma_addr_t *bufs,
+ int buf_cnt, int start, struct ib_umem *umem,
+ int page_shift);
+
int hns_roce_create_srq(struct ib_srq *srq,
struct ib_srq_init_attr *srq_init_attr,
struct ib_udata *udata);
@@ -1178,11 +1264,11 @@ void hns_roce_release_range_qp(struct hns_roce_dev *hr_dev, int base_qpn,
__be32 send_ieth(const struct ib_send_wr *wr);
int to_hr_qp_type(int qp_type);
-struct ib_cq *hns_roce_ib_create_cq(struct ib_device *ib_dev,
- const struct ib_cq_init_attr *attr,
- struct ib_udata *udata);
+int hns_roce_ib_create_cq(struct ib_cq *ib_cq,
+ const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata);
-int hns_roce_ib_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata);
+void hns_roce_ib_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata);
void hns_roce_free_cq(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq);
int hns_roce_db_map_user(struct hns_roce_ucontext *context,
diff --git a/drivers/infiniband/hw/hns/hns_roce_hem.c b/drivers/infiniband/hw/hns/hns_roce_hem.c
index 8e29dbb5b5fb..f4da5bd2884f 100644
--- a/drivers/infiniband/hw/hns/hns_roce_hem.c
+++ b/drivers/infiniband/hw/hns/hns_roce_hem.c
@@ -56,7 +56,6 @@ bool hns_roce_check_whether_mhop(struct hns_roce_dev *hr_dev, u32 type)
return false;
}
-EXPORT_SYMBOL_GPL(hns_roce_check_whether_mhop);
static bool hns_roce_check_hem_null(struct hns_roce_hem **hem, u64 start_idx,
u32 bt_chunk_num)
@@ -165,7 +164,7 @@ int hns_roce_calc_hem_mhop(struct hns_roce_dev *hr_dev,
+ PAGE_SHIFT);
mhop->bt_chunk_size = 1 << (hr_dev->caps.mtt_ba_pg_sz
+ PAGE_SHIFT);
- mhop->ba_l0_num = mhop->bt_chunk_size / 8;
+ mhop->ba_l0_num = mhop->bt_chunk_size / BA_BYTE_LEN;
mhop->hop_num = hr_dev->caps.mtt_hop_num;
break;
case HEM_TYPE_CQE:
@@ -173,7 +172,7 @@ int hns_roce_calc_hem_mhop(struct hns_roce_dev *hr_dev,
+ PAGE_SHIFT);
mhop->bt_chunk_size = 1 << (hr_dev->caps.cqe_ba_pg_sz
+ PAGE_SHIFT);
- mhop->ba_l0_num = mhop->bt_chunk_size / 8;
+ mhop->ba_l0_num = mhop->bt_chunk_size / BA_BYTE_LEN;
mhop->hop_num = hr_dev->caps.cqe_hop_num;
break;
case HEM_TYPE_SRQWQE:
@@ -181,7 +180,7 @@ int hns_roce_calc_hem_mhop(struct hns_roce_dev *hr_dev,
+ PAGE_SHIFT);
mhop->bt_chunk_size = 1 << (hr_dev->caps.srqwqe_ba_pg_sz
+ PAGE_SHIFT);
- mhop->ba_l0_num = mhop->bt_chunk_size / 8;
+ mhop->ba_l0_num = mhop->bt_chunk_size / BA_BYTE_LEN;
mhop->hop_num = hr_dev->caps.srqwqe_hop_num;
break;
case HEM_TYPE_IDX:
@@ -189,7 +188,7 @@ int hns_roce_calc_hem_mhop(struct hns_roce_dev *hr_dev,
+ PAGE_SHIFT);
mhop->bt_chunk_size = 1 << (hr_dev->caps.idx_ba_pg_sz
+ PAGE_SHIFT);
- mhop->ba_l0_num = mhop->bt_chunk_size / 8;
+ mhop->ba_l0_num = mhop->bt_chunk_size / BA_BYTE_LEN;
mhop->hop_num = hr_dev->caps.idx_hop_num;
break;
default:
@@ -206,7 +205,7 @@ int hns_roce_calc_hem_mhop(struct hns_roce_dev *hr_dev,
* MTT/CQE alloc hem for bt pages.
*/
bt_num = hns_roce_get_bt_num(table->type, mhop->hop_num);
- chunk_ba_num = mhop->bt_chunk_size / 8;
+ chunk_ba_num = mhop->bt_chunk_size / BA_BYTE_LEN;
chunk_size = table->type < HEM_TYPE_MTT ? mhop->buf_chunk_size :
mhop->bt_chunk_size;
table_idx = (*obj & (table->num_obj - 1)) /
@@ -234,7 +233,6 @@ int hns_roce_calc_hem_mhop(struct hns_roce_dev *hr_dev,
return 0;
}
-EXPORT_SYMBOL_GPL(hns_roce_calc_hem_mhop);
static struct hns_roce_hem *hns_roce_alloc_hem(struct hns_roce_dev *hr_dev,
int npages,
@@ -376,18 +374,19 @@ static int hns_roce_set_hem(struct hns_roce_dev *hr_dev,
bt_cmd = hr_dev->reg_base + ROCEE_BT_CMD_H_REG;
- end = msecs_to_jiffies(HW_SYNC_TIMEOUT_MSECS) + jiffies;
- while (1) {
- if (readl(bt_cmd) >> BT_CMD_SYNC_SHIFT) {
- if (!(time_before(jiffies, end))) {
- dev_err(dev, "Write bt_cmd err,hw_sync is not zero.\n");
- spin_unlock_irqrestore(lock, flags);
- return -EBUSY;
- }
- } else {
+ end = HW_SYNC_TIMEOUT_MSECS;
+ while (end) {
+ if (!(readl(bt_cmd) >> BT_CMD_SYNC_SHIFT))
break;
- }
+
mdelay(HW_SYNC_SLEEP_TIME_INTERVAL);
+ end -= HW_SYNC_SLEEP_TIME_INTERVAL;
+ }
+
+ if (end <= 0) {
+ dev_err(dev, "Write bt_cmd err,hw_sync is not zero.\n");
+ spin_unlock_irqrestore(lock, flags);
+ return -EBUSY;
}
bt_cmd_l = (u32)bt_ba;
@@ -435,7 +434,7 @@ static int hns_roce_table_mhop_get(struct hns_roce_dev *hr_dev,
buf_chunk_size = mhop.buf_chunk_size;
bt_chunk_size = mhop.bt_chunk_size;
hop_num = mhop.hop_num;
- chunk_ba_num = bt_chunk_size / 8;
+ chunk_ba_num = bt_chunk_size / BA_BYTE_LEN;
bt_num = hns_roce_get_bt_num(table->type, hop_num);
switch (bt_num) {
@@ -620,7 +619,6 @@ out:
mutex_unlock(&table->mutex);
return ret;
}
-EXPORT_SYMBOL_GPL(hns_roce_table_get);
static void hns_roce_table_mhop_put(struct hns_roce_dev *hr_dev,
struct hns_roce_hem_table *table,
@@ -645,7 +643,7 @@ static void hns_roce_table_mhop_put(struct hns_roce_dev *hr_dev,
bt_chunk_size = mhop.bt_chunk_size;
hop_num = mhop.hop_num;
- chunk_ba_num = bt_chunk_size / 8;
+ chunk_ba_num = bt_chunk_size / BA_BYTE_LEN;
bt_num = hns_roce_get_bt_num(table->type, hop_num);
switch (bt_num) {
@@ -763,7 +761,6 @@ void hns_roce_table_put(struct hns_roce_dev *hr_dev,
mutex_unlock(&table->mutex);
}
-EXPORT_SYMBOL_GPL(hns_roce_table_put);
void *hns_roce_table_find(struct hns_roce_dev *hr_dev,
struct hns_roce_hem_table *table,
@@ -799,7 +796,7 @@ void *hns_roce_table_find(struct hns_roce_dev *hr_dev,
i = mhop.l0_idx;
j = mhop.l1_idx;
if (mhop.hop_num == 2)
- hem_idx = i * (mhop.bt_chunk_size / 8) + j;
+ hem_idx = i * (mhop.bt_chunk_size / BA_BYTE_LEN) + j;
else if (mhop.hop_num == 1 ||
mhop.hop_num == HNS_ROCE_HOP_NUM_0)
hem_idx = i;
@@ -836,7 +833,6 @@ out:
mutex_unlock(&table->mutex);
return addr;
}
-EXPORT_SYMBOL_GPL(hns_roce_table_find);
int hns_roce_table_get_range(struct hns_roce_dev *hr_dev,
struct hns_roce_hem_table *table,
@@ -999,7 +995,7 @@ int hns_roce_init_hem_table(struct hns_roce_dev *hr_dev,
}
obj_per_chunk = buf_chunk_size / obj_size;
num_hem = (nobj + obj_per_chunk - 1) / obj_per_chunk;
- bt_chunk_num = bt_chunk_size / 8;
+ bt_chunk_num = bt_chunk_size / BA_BYTE_LEN;
if (type >= HEM_TYPE_MTT)
num_bt_l0 = bt_chunk_num;
@@ -1156,3 +1152,463 @@ void hns_roce_cleanup_hem(struct hns_roce_dev *hr_dev)
&hr_dev->mr_table.mtt_cqe_table);
hns_roce_cleanup_hem_table(hr_dev, &hr_dev->mr_table.mtt_table);
}
+
+struct roce_hem_item {
+ struct list_head list; /* link all hems in the same bt level */
+ struct list_head sibling; /* link all hems in last hop for mtt */
+ void *addr;
+ dma_addr_t dma_addr;
+ size_t count; /* max ba numbers */
+ int start; /* start buf offset in this hem */
+ int end; /* end buf offset in this hem */
+};
+
+static struct roce_hem_item *hem_list_alloc_item(struct hns_roce_dev *hr_dev,
+ int start, int end,
+ int count, bool exist_bt,
+ int bt_level)
+{
+ struct roce_hem_item *hem;
+
+ hem = kzalloc(sizeof(*hem), GFP_KERNEL);
+ if (!hem)
+ return NULL;
+
+ if (exist_bt) {
+ hem->addr = dma_alloc_coherent(hr_dev->dev,
+ count * BA_BYTE_LEN,
+ &hem->dma_addr, GFP_KERNEL);
+ if (!hem->addr) {
+ kfree(hem);
+ return NULL;
+ }
+ }
+
+ hem->count = count;
+ hem->start = start;
+ hem->end = end;
+ INIT_LIST_HEAD(&hem->list);
+ INIT_LIST_HEAD(&hem->sibling);
+
+ return hem;
+}
+
+static void hem_list_free_item(struct hns_roce_dev *hr_dev,
+ struct roce_hem_item *hem, bool exist_bt)
+{
+ if (exist_bt)
+ dma_free_coherent(hr_dev->dev, hem->count * BA_BYTE_LEN,
+ hem->addr, hem->dma_addr);
+ kfree(hem);
+}
+
+static void hem_list_free_all(struct hns_roce_dev *hr_dev,
+ struct list_head *head, bool exist_bt)
+{
+ struct roce_hem_item *hem, *temp_hem;
+
+ list_for_each_entry_safe(hem, temp_hem, head, list) {
+ list_del(&hem->list);
+ hem_list_free_item(hr_dev, hem, exist_bt);
+ }
+}
+
+static void hem_list_link_bt(struct hns_roce_dev *hr_dev, void *base_addr,
+ u64 table_addr)
+{
+ *(u64 *)(base_addr) = table_addr;
+}
+
+/* assign L0 table address to hem from root bt */
+static void hem_list_assign_bt(struct hns_roce_dev *hr_dev,
+ struct roce_hem_item *hem, void *cpu_addr,
+ u64 phy_addr)
+{
+ hem->addr = cpu_addr;
+ hem->dma_addr = (dma_addr_t)phy_addr;
+}
+
+static inline bool hem_list_page_is_in_range(struct roce_hem_item *hem,
+ int offset)
+{
+ return (hem->start <= offset && offset <= hem->end);
+}
+
+static struct roce_hem_item *hem_list_search_item(struct list_head *ba_list,
+ int page_offset)
+{
+ struct roce_hem_item *hem, *temp_hem;
+ struct roce_hem_item *found = NULL;
+
+ list_for_each_entry_safe(hem, temp_hem, ba_list, list) {
+ if (hem_list_page_is_in_range(hem, page_offset)) {
+ found = hem;
+ break;
+ }
+ }
+
+ return found;
+}
+
+static bool hem_list_is_bottom_bt(int hopnum, int bt_level)
+{
+ /*
+ * hopnum base address table levels
+ * 0 L0(buf)
+ * 1 L0 -> buf
+ * 2 L0 -> L1 -> buf
+ * 3 L0 -> L1 -> L2 -> buf
+ */
+ return bt_level >= (hopnum ? hopnum - 1 : hopnum);
+}
+
+/**
+ * calc base address entries num
+ * @hopnum: num of mutihop addressing
+ * @bt_level: base address table level
+ * @unit: ba entries per bt page
+ */
+static u32 hem_list_calc_ba_range(int hopnum, int bt_level, int unit)
+{
+ u32 step;
+ int max;
+ int i;
+
+ if (hopnum <= bt_level)
+ return 0;
+ /*
+ * hopnum bt_level range
+ * 1 0 unit
+ * ------------
+ * 2 0 unit * unit
+ * 2 1 unit
+ * ------------
+ * 3 0 unit * unit * unit
+ * 3 1 unit * unit
+ * 3 2 unit
+ */
+ step = 1;
+ max = hopnum - bt_level;
+ for (i = 0; i < max; i++)
+ step = step * unit;
+
+ return step;
+}
+
+/**
+ * calc the root ba entries which could cover all regions
+ * @regions: buf region array
+ * @region_cnt: array size of @regions
+ * @unit: ba entries per bt page
+ */
+int hns_roce_hem_list_calc_root_ba(const struct hns_roce_buf_region *regions,
+ int region_cnt, int unit)
+{
+ struct hns_roce_buf_region *r;
+ int total = 0;
+ int step;
+ int i;
+
+ for (i = 0; i < region_cnt; i++) {
+ r = (struct hns_roce_buf_region *)&regions[i];
+ if (r->hopnum > 1) {
+ step = hem_list_calc_ba_range(r->hopnum, 1, unit);
+ if (step > 0)
+ total += (r->count + step - 1) / step;
+ } else {
+ total += r->count;
+ }
+ }
+
+ return total;
+}
+
+static int hem_list_alloc_mid_bt(struct hns_roce_dev *hr_dev,
+ const struct hns_roce_buf_region *r, int unit,
+ int offset, struct list_head *mid_bt,
+ struct list_head *btm_bt)
+{
+ struct roce_hem_item *hem_ptrs[HNS_ROCE_MAX_BT_LEVEL] = { NULL };
+ struct list_head temp_list[HNS_ROCE_MAX_BT_LEVEL];
+ struct roce_hem_item *cur, *pre;
+ const int hopnum = r->hopnum;
+ int start_aligned;
+ int distance;
+ int ret = 0;
+ int max_ofs;
+ int level;
+ u32 step;
+ int end;
+
+ if (hopnum <= 1)
+ return 0;
+
+ if (hopnum > HNS_ROCE_MAX_BT_LEVEL) {
+ dev_err(hr_dev->dev, "invalid hopnum %d!\n", hopnum);
+ return -EINVAL;
+ }
+
+ if (offset < r->offset) {
+ dev_err(hr_dev->dev, "invalid offset %d,min %d!\n",
+ offset, r->offset);
+ return -EINVAL;
+ }
+
+ distance = offset - r->offset;
+ max_ofs = r->offset + r->count - 1;
+ for (level = 0; level < hopnum; level++)
+ INIT_LIST_HEAD(&temp_list[level]);
+
+ /* config L1 bt to last bt and link them to corresponding parent */
+ for (level = 1; level < hopnum; level++) {
+ cur = hem_list_search_item(&mid_bt[level], offset);
+ if (cur) {
+ hem_ptrs[level] = cur;
+ continue;
+ }
+
+ step = hem_list_calc_ba_range(hopnum, level, unit);
+ if (step < 1) {
+ ret = -EINVAL;
+ goto err_exit;
+ }
+
+ start_aligned = (distance / step) * step + r->offset;
+ end = min_t(int, start_aligned + step - 1, max_ofs);
+ cur = hem_list_alloc_item(hr_dev, start_aligned, end, unit,
+ true, level);
+ if (!cur) {
+ ret = -ENOMEM;
+ goto err_exit;
+ }
+ hem_ptrs[level] = cur;
+ list_add(&cur->list, &temp_list[level]);
+ if (hem_list_is_bottom_bt(hopnum, level))
+ list_add(&cur->sibling, &temp_list[0]);
+
+ /* link bt to parent bt */
+ if (level > 1) {
+ pre = hem_ptrs[level - 1];
+ step = (cur->start - pre->start) / step * BA_BYTE_LEN;
+ hem_list_link_bt(hr_dev, pre->addr + step,
+ cur->dma_addr);
+ }
+ }
+
+ list_splice(&temp_list[0], btm_bt);
+ for (level = 1; level < hopnum; level++)
+ list_splice(&temp_list[level], &mid_bt[level]);
+
+ return 0;
+
+err_exit:
+ for (level = 1; level < hopnum; level++)
+ hem_list_free_all(hr_dev, &temp_list[level], true);
+
+ return ret;
+}
+
+static int hem_list_alloc_root_bt(struct hns_roce_dev *hr_dev,
+ struct hns_roce_hem_list *hem_list, int unit,
+ const struct hns_roce_buf_region *regions,
+ int region_cnt)
+{
+ struct roce_hem_item *hem, *temp_hem, *root_hem;
+ struct list_head temp_list[HNS_ROCE_MAX_BT_REGION];
+ const struct hns_roce_buf_region *r;
+ struct list_head temp_root;
+ struct list_head temp_btm;
+ void *cpu_base;
+ u64 phy_base;
+ int ret = 0;
+ int offset;
+ int total;
+ int step;
+ int i;
+
+ r = &regions[0];
+ root_hem = hem_list_search_item(&hem_list->root_bt, r->offset);
+ if (root_hem)
+ return 0;
+
+ INIT_LIST_HEAD(&temp_root);
+ total = r->offset;
+ /* indicate to last region */
+ r = &regions[region_cnt - 1];
+ root_hem = hem_list_alloc_item(hr_dev, total, r->offset + r->count - 1,
+ unit, true, 0);
+ if (!root_hem)
+ return -ENOMEM;
+ list_add(&root_hem->list, &temp_root);
+
+ hem_list->root_ba = root_hem->dma_addr;
+
+ INIT_LIST_HEAD(&temp_btm);
+ for (i = 0; i < region_cnt; i++)
+ INIT_LIST_HEAD(&temp_list[i]);
+
+ total = 0;
+ for (i = 0; i < region_cnt && total < unit; i++) {
+ r = &regions[i];
+ if (!r->count)
+ continue;
+
+ /* all regions's mid[x][0] shared the root_bt's trunk */
+ cpu_base = root_hem->addr + total * BA_BYTE_LEN;
+ phy_base = root_hem->dma_addr + total * BA_BYTE_LEN;
+
+ /* if hopnum is 0 or 1, cut a new fake hem from the root bt
+ * which's address share to all regions.
+ */
+ if (hem_list_is_bottom_bt(r->hopnum, 0)) {
+ hem = hem_list_alloc_item(hr_dev, r->offset,
+ r->offset + r->count - 1,
+ r->count, false, 0);
+ if (!hem) {
+ ret = -ENOMEM;
+ goto err_exit;
+ }
+ hem_list_assign_bt(hr_dev, hem, cpu_base, phy_base);
+ list_add(&hem->list, &temp_list[i]);
+ list_add(&hem->sibling, &temp_btm);
+ total += r->count;
+ } else {
+ step = hem_list_calc_ba_range(r->hopnum, 1, unit);
+ if (step < 1) {
+ ret = -EINVAL;
+ goto err_exit;
+ }
+ /* if exist mid bt, link L1 to L0 */
+ list_for_each_entry_safe(hem, temp_hem,
+ &hem_list->mid_bt[i][1], list) {
+ offset = hem->start / step * BA_BYTE_LEN;
+ hem_list_link_bt(hr_dev, cpu_base + offset,
+ hem->dma_addr);
+ total++;
+ }
+ }
+ }
+
+ list_splice(&temp_btm, &hem_list->btm_bt);
+ list_splice(&temp_root, &hem_list->root_bt);
+ for (i = 0; i < region_cnt; i++)
+ list_splice(&temp_list[i], &hem_list->mid_bt[i][0]);
+
+ return 0;
+
+err_exit:
+ for (i = 0; i < region_cnt; i++)
+ hem_list_free_all(hr_dev, &temp_list[i], false);
+
+ hem_list_free_all(hr_dev, &temp_root, true);
+
+ return ret;
+}
+
+/* construct the base address table and link them by address hop config */
+int hns_roce_hem_list_request(struct hns_roce_dev *hr_dev,
+ struct hns_roce_hem_list *hem_list,
+ const struct hns_roce_buf_region *regions,
+ int region_cnt)
+{
+ const struct hns_roce_buf_region *r;
+ int ofs, end;
+ int ret = 0;
+ int unit;
+ int i;
+
+ if (region_cnt > HNS_ROCE_MAX_BT_REGION) {
+ dev_err(hr_dev->dev, "invalid region region_cnt %d!\n",
+ region_cnt);
+ return -EINVAL;
+ }
+
+ unit = (1 << hem_list->bt_pg_shift) / BA_BYTE_LEN;
+ for (i = 0; i < region_cnt; i++) {
+ r = &regions[i];
+ if (!r->count)
+ continue;
+
+ end = r->offset + r->count;
+ for (ofs = r->offset; ofs < end; ofs += unit) {
+ ret = hem_list_alloc_mid_bt(hr_dev, r, unit, ofs,
+ hem_list->mid_bt[i],
+ &hem_list->btm_bt);
+ if (ret) {
+ dev_err(hr_dev->dev,
+ "alloc hem trunk fail ret=%d!\n", ret);
+ goto err_alloc;
+ }
+ }
+ }
+
+ ret = hem_list_alloc_root_bt(hr_dev, hem_list, unit, regions,
+ region_cnt);
+ if (ret)
+ dev_err(hr_dev->dev, "alloc hem root fail ret=%d!\n", ret);
+ else
+ return 0;
+
+err_alloc:
+ hns_roce_hem_list_release(hr_dev, hem_list);
+
+ return ret;
+}
+
+void hns_roce_hem_list_release(struct hns_roce_dev *hr_dev,
+ struct hns_roce_hem_list *hem_list)
+{
+ int i, j;
+
+ for (i = 0; i < HNS_ROCE_MAX_BT_REGION; i++)
+ for (j = 0; j < HNS_ROCE_MAX_BT_LEVEL; j++)
+ hem_list_free_all(hr_dev, &hem_list->mid_bt[i][j],
+ j != 0);
+
+ hem_list_free_all(hr_dev, &hem_list->root_bt, true);
+ INIT_LIST_HEAD(&hem_list->btm_bt);
+ hem_list->root_ba = 0;
+}
+
+void hns_roce_hem_list_init(struct hns_roce_hem_list *hem_list,
+ int bt_page_order)
+{
+ int i, j;
+
+ INIT_LIST_HEAD(&hem_list->root_bt);
+ INIT_LIST_HEAD(&hem_list->btm_bt);
+ for (i = 0; i < HNS_ROCE_MAX_BT_REGION; i++)
+ for (j = 0; j < HNS_ROCE_MAX_BT_LEVEL; j++)
+ INIT_LIST_HEAD(&hem_list->mid_bt[i][j]);
+
+ hem_list->bt_pg_shift = bt_page_order;
+}
+
+void *hns_roce_hem_list_find_mtt(struct hns_roce_dev *hr_dev,
+ struct hns_roce_hem_list *hem_list,
+ int offset, int *mtt_cnt, u64 *phy_addr)
+{
+ struct list_head *head = &hem_list->btm_bt;
+ struct roce_hem_item *hem, *temp_hem;
+ void *cpu_base = NULL;
+ u64 phy_base = 0;
+ int nr = 0;
+
+ list_for_each_entry_safe(hem, temp_hem, head, sibling) {
+ if (hem_list_page_is_in_range(hem, offset)) {
+ nr = offset - hem->start;
+ cpu_base = hem->addr + nr * BA_BYTE_LEN;
+ phy_base = hem->dma_addr + nr * BA_BYTE_LEN;
+ nr = hem->end + 1 - offset;
+ break;
+ }
+ }
+
+ if (mtt_cnt)
+ *mtt_cnt = nr;
+
+ if (phy_addr)
+ *phy_addr = phy_base;
+
+ return cpu_base;
+}
diff --git a/drivers/infiniband/hw/hns/hns_roce_hem.h b/drivers/infiniband/hw/hns/hns_roce_hem.h
index d9d668992e49..f1ccb8f35fe5 100644
--- a/drivers/infiniband/hw/hns/hns_roce_hem.h
+++ b/drivers/infiniband/hw/hns/hns_roce_hem.h
@@ -34,8 +34,8 @@
#ifndef _HNS_ROCE_HEM_H
#define _HNS_ROCE_HEM_H
-#define HW_SYNC_TIMEOUT_MSECS 500
#define HW_SYNC_SLEEP_TIME_INTERVAL 20
+#define HW_SYNC_TIMEOUT_MSECS (25 * HW_SYNC_SLEEP_TIME_INTERVAL)
#define BT_CMD_SYNC_SHIFT 31
enum {
@@ -133,6 +133,20 @@ int hns_roce_calc_hem_mhop(struct hns_roce_dev *hr_dev,
struct hns_roce_hem_mhop *mhop);
bool hns_roce_check_whether_mhop(struct hns_roce_dev *hr_dev, u32 type);
+void hns_roce_hem_list_init(struct hns_roce_hem_list *hem_list,
+ int bt_page_order);
+int hns_roce_hem_list_calc_root_ba(const struct hns_roce_buf_region *regions,
+ int region_cnt, int unit);
+int hns_roce_hem_list_request(struct hns_roce_dev *hr_dev,
+ struct hns_roce_hem_list *hem_list,
+ const struct hns_roce_buf_region *regions,
+ int region_cnt);
+void hns_roce_hem_list_release(struct hns_roce_dev *hr_dev,
+ struct hns_roce_hem_list *hem_list);
+void *hns_roce_hem_list_find_mtt(struct hns_roce_dev *hr_dev,
+ struct hns_roce_hem_list *hem_list,
+ int offset, int *mtt_cnt, u64 *phy_addr);
+
static inline void hns_roce_hem_first(struct hns_roce_hem *hem,
struct hns_roce_hem_iter *iter)
{
diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c
index e068a02122f5..81e6dedb1e02 100644
--- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c
+++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c
@@ -717,7 +717,7 @@ static int hns_roce_v1_rsv_lp_qp(struct hns_roce_dev *hr_dev)
union ib_gid dgid;
u64 subnet_prefix;
int attr_mask = 0;
- int ret = -ENOMEM;
+ int ret;
int i, j;
u8 queue_en[HNS_ROCE_V1_RESV_QP] = { 0 };
u8 phy_port;
@@ -730,10 +730,16 @@ static int hns_roce_v1_rsv_lp_qp(struct hns_roce_dev *hr_dev)
/* Reserved cq for loop qp */
cq_init_attr.cqe = HNS_ROCE_MIN_WQE_NUM * 2;
cq_init_attr.comp_vector = 0;
- cq = hns_roce_ib_create_cq(&hr_dev->ib_dev, &cq_init_attr, NULL);
- if (IS_ERR(cq)) {
- dev_err(dev, "Create cq for reserved loop qp failed!");
+
+ ibdev = &hr_dev->ib_dev;
+ cq = rdma_zalloc_drv_obj(ibdev, ib_cq);
+ if (!cq)
return -ENOMEM;
+
+ ret = hns_roce_ib_create_cq(cq, &cq_init_attr, NULL);
+ if (ret) {
+ dev_err(dev, "Create cq for reserved loop qp failed!");
+ goto alloc_cq_failed;
}
free_mr->mr_free_cq = to_hr_cq(cq);
free_mr->mr_free_cq->ib_cq.device = &hr_dev->ib_dev;
@@ -743,7 +749,6 @@ static int hns_roce_v1_rsv_lp_qp(struct hns_roce_dev *hr_dev)
free_mr->mr_free_cq->ib_cq.cq_context = NULL;
atomic_set(&free_mr->mr_free_cq->ib_cq.usecnt, 0);
- ibdev = &hr_dev->ib_dev;
pd = rdma_zalloc_drv_obj(ibdev, ib_pd);
if (!pd)
goto alloc_mem_failed;
@@ -818,7 +823,7 @@ static int hns_roce_v1_rsv_lp_qp(struct hns_roce_dev *hr_dev)
attr.dest_qp_num = hr_qp->qpn;
memcpy(rdma_ah_retrieve_dmac(&attr.ah_attr),
hr_dev->dev_addr[port],
- MAC_ADDR_OCTET_NUM);
+ ETH_ALEN);
memcpy(&dgid.raw, &subnet_prefix, sizeof(u64));
memcpy(&dgid.raw[8], hr_dev->dev_addr[port], 3);
@@ -865,9 +870,9 @@ alloc_pd_failed:
kfree(pd);
alloc_mem_failed:
- if (hns_roce_ib_destroy_cq(cq, NULL))
- dev_err(dev, "Destroy cq for create_lp_qp failed!\n");
-
+ hns_roce_ib_destroy_cq(cq, NULL);
+alloc_cq_failed:
+ kfree(cq);
return ret;
}
@@ -894,10 +899,8 @@ static void hns_roce_v1_release_lp_qp(struct hns_roce_dev *hr_dev)
i, ret);
}
- ret = hns_roce_ib_destroy_cq(&free_mr->mr_free_cq->ib_cq, NULL);
- if (ret)
- dev_err(dev, "Destroy cq for mr_free failed(%d)!\n", ret);
-
+ hns_roce_ib_destroy_cq(&free_mr->mr_free_cq->ib_cq, NULL);
+ kfree(&free_mr->mr_free_cq->ib_cq);
hns_roce_dealloc_pd(&free_mr->mr_free_pd->ibpd, NULL);
kfree(&free_mr->mr_free_pd->ibpd);
}
@@ -966,8 +969,7 @@ static int hns_roce_v1_recreate_lp_qp(struct hns_roce_dev *hr_dev)
struct hns_roce_free_mr *free_mr;
struct hns_roce_v1_priv *priv;
struct completion comp;
- unsigned long end =
- msecs_to_jiffies(HNS_ROCE_V1_RECREATE_LP_QP_TIMEOUT_MSECS) + jiffies;
+ unsigned long end = HNS_ROCE_V1_RECREATE_LP_QP_TIMEOUT_MSECS;
priv = (struct hns_roce_v1_priv *)hr_dev->priv;
free_mr = &priv->free_mr;
@@ -987,10 +989,11 @@ static int hns_roce_v1_recreate_lp_qp(struct hns_roce_dev *hr_dev)
queue_work(free_mr->free_mr_wq, &(lp_qp_work->work));
- while (time_before_eq(jiffies, end)) {
+ while (end) {
if (try_wait_for_completion(&comp))
return 0;
msleep(HNS_ROCE_V1_RECREATE_LP_QP_WAIT_VALUE);
+ end -= HNS_ROCE_V1_RECREATE_LP_QP_WAIT_VALUE;
}
lp_qp_work->comp_flag = 0;
@@ -1104,8 +1107,7 @@ static int hns_roce_v1_dereg_mr(struct hns_roce_dev *hr_dev,
struct hns_roce_free_mr *free_mr;
struct hns_roce_v1_priv *priv;
struct completion comp;
- unsigned long end =
- msecs_to_jiffies(HNS_ROCE_V1_FREE_MR_TIMEOUT_MSECS) + jiffies;
+ unsigned long end = HNS_ROCE_V1_FREE_MR_TIMEOUT_MSECS;
unsigned long start = jiffies;
int npages;
int ret = 0;
@@ -1135,10 +1137,11 @@ static int hns_roce_v1_dereg_mr(struct hns_roce_dev *hr_dev,
queue_work(free_mr->free_mr_wq, &(mr_work->work));
- while (time_before_eq(jiffies, end)) {
+ while (end) {
if (try_wait_for_completion(&comp))
goto free_mr;
msleep(HNS_ROCE_V1_FREE_MR_WAIT_VALUE);
+ end -= HNS_ROCE_V1_FREE_MR_WAIT_VALUE;
}
mr_work->comp_flag = 0;
@@ -1161,8 +1164,7 @@ free_mr:
hns_roce_bitmap_free(&hr_dev->mr_table.mtpt_bitmap,
key_to_hw_index(mr->key), 0);
- if (mr->umem)
- ib_umem_release(mr->umem);
+ ib_umem_release(mr->umem);
kfree(mr);
@@ -1557,6 +1559,7 @@ static int hns_roce_v1_profile(struct hns_roce_dev *hr_dev)
caps->reserved_mrws = 1;
caps->reserved_uars = 0;
caps->reserved_cqs = 0;
+ caps->reserved_qps = 12; /* 2 SQP per port, six ports total 12 */
caps->chunk_sz = HNS_ROCE_V1_TABLE_CHUNK_SIZE;
for (i = 0; i < caps->num_ports; i++)
@@ -1742,11 +1745,14 @@ static int hns_roce_v1_set_gid(struct hns_roce_dev *hr_dev, u8 port,
int gid_index, const union ib_gid *gid,
const struct ib_gid_attr *attr)
{
+ unsigned long flags;
u32 *p = NULL;
u8 gid_idx = 0;
gid_idx = hns_get_gid_index(hr_dev, port, gid_index);
+ spin_lock_irqsave(&hr_dev->iboe.lock, flags);
+
p = (u32 *)&gid->raw[0];
roce_raw_write(*p, hr_dev->reg_base + ROCEE_PORT_GID_L_0_REG +
(HNS_ROCE_V1_GID_NUM * gid_idx));
@@ -1763,6 +1769,8 @@ static int hns_roce_v1_set_gid(struct hns_roce_dev *hr_dev, u8 port,
roce_raw_write(*p, hr_dev->reg_base + ROCEE_PORT_GID_H_0_REG +
(HNS_ROCE_V1_GID_NUM * gid_idx));
+ spin_unlock_irqrestore(&hr_dev->iboe.lock, flags);
+
return 0;
}
@@ -2458,10 +2466,10 @@ static int hns_roce_v1_clear_hem(struct hns_roce_dev *hr_dev,
bt_cmd = hr_dev->reg_base + ROCEE_BT_CMD_H_REG;
- end = msecs_to_jiffies(HW_SYNC_TIMEOUT_MSECS) + jiffies;
+ end = HW_SYNC_TIMEOUT_MSECS;
while (1) {
if (readl(bt_cmd) >> BT_CMD_SYNC_SHIFT) {
- if (!(time_before(jiffies, end))) {
+ if (!end) {
dev_err(dev, "Write bt_cmd err,hw_sync is not zero.\n");
spin_unlock_irqrestore(&hr_dev->bt_cmd_lock,
flags);
@@ -2470,7 +2478,8 @@ static int hns_roce_v1_clear_hem(struct hns_roce_dev *hr_dev,
} else {
break;
}
- msleep(HW_SYNC_SLEEP_TIME_INTERVAL);
+ mdelay(HW_SYNC_SLEEP_TIME_INTERVAL);
+ end -= HW_SYNC_SLEEP_TIME_INTERVAL;
}
bt_cmd_val[0] = (__le32)bt_ba;
@@ -3633,9 +3642,8 @@ int hns_roce_v1_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
hns_roce_mtt_cleanup(hr_dev, &hr_qp->mtt);
- if (udata)
- ib_umem_release(hr_qp->umem);
- else {
+ ib_umem_release(hr_qp->umem);
+ if (!udata) {
kfree(hr_qp->sq.wrid);
kfree(hr_qp->rq.wrid);
@@ -3649,7 +3657,7 @@ int hns_roce_v1_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
return 0;
}
-static int hns_roce_v1_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
+static void hns_roce_v1_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
{
struct hns_roce_dev *hr_dev = to_hr_dev(ibcq->device);
struct hns_roce_cq *hr_cq = to_hr_cq(ibcq);
@@ -3658,7 +3666,6 @@ static int hns_roce_v1_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
u32 cqe_cnt_cur;
u32 cq_buf_size;
int wait_time = 0;
- int ret = 0;
hns_roce_free_cq(hr_dev, hr_cq);
@@ -3680,7 +3687,6 @@ static int hns_roce_v1_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
if (wait_time > HNS_ROCE_MAX_FREE_CQ_WAIT_CNT) {
dev_warn(dev, "Destroy cq 0x%lx timeout!\n",
hr_cq->cqn);
- ret = -ETIMEDOUT;
break;
}
wait_time++;
@@ -3688,17 +3694,12 @@ static int hns_roce_v1_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
hns_roce_mtt_cleanup(hr_dev, &hr_cq->hr_buf.hr_mtt);
- if (ibcq->uobject)
- ib_umem_release(hr_cq->umem);
- else {
+ ib_umem_release(hr_cq->umem);
+ if (!udata) {
/* Free the buff of stored cq */
cq_buf_size = (ibcq->cqe + 1) * hr_dev->caps.cq_entry_sz;
hns_roce_buf_free(hr_dev, cq_buf_size, &hr_cq->hr_buf.hr_buf);
}
-
- kfree(hr_cq);
-
- return ret;
}
static void set_eq_cons_index_v1(struct hns_roce_eq *eq, int req_not)
@@ -3902,7 +3903,8 @@ static int hns_roce_v1_aeq_int(struct hns_roce_dev *hr_dev,
*/
dma_rmb();
- dev_dbg(dev, "aeqe = %p, aeqe->asyn.event_type = 0x%lx\n", aeqe,
+ dev_dbg(dev, "aeqe = %pK, aeqe->asyn.event_type = 0x%lx\n",
+ aeqe,
roce_get_field(aeqe->asyn,
HNS_ROCE_AEQE_U32_4_EVENT_TYPE_M,
HNS_ROCE_AEQE_U32_4_EVENT_TYPE_S));
@@ -4265,7 +4267,6 @@ static int hns_roce_v1_create_eq(struct hns_roce_dev *hr_dev,
}
eq->buf_list[i].map = tmp_dma_addr;
- memset(eq->buf_list[i].buf, 0, HNS_ROCE_BA_SIZE);
}
eq->cons_index = 0;
roce_set_field(tmp, ROCEE_CAEP_AEQC_AEQE_SHIFT_CAEP_AEQC_STATE_M,
@@ -4498,7 +4499,7 @@ static const struct acpi_device_id hns_roce_acpi_match[] = {
};
MODULE_DEVICE_TABLE(acpi, hns_roce_acpi_match);
-static int hns_roce_node_match(struct device *dev, void *fwnode)
+static int hns_roce_node_match(struct device *dev, const void *fwnode)
{
return dev->fwnode == fwnode;
}
diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
index b5392cb5b20f..b76e3beeafb8 100644
--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
+++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
@@ -1098,7 +1098,7 @@ static int hns_roce_cmq_send(struct hns_roce_dev *hr_dev,
if (ret == CMD_RST_PRC_SUCCESS)
return 0;
if (ret == CMD_RST_PRC_EBUSY)
- return ret;
+ return -EBUSY;
ret = __hns_roce_cmq_send(hr_dev, desc, num);
if (ret) {
@@ -1106,7 +1106,7 @@ static int hns_roce_cmq_send(struct hns_roce_dev *hr_dev,
if (retval == CMD_RST_PRC_SUCCESS)
return 0;
else if (retval == CMD_RST_PRC_EBUSY)
- return retval;
+ return -EBUSY;
}
return ret;
@@ -1130,6 +1130,45 @@ static int hns_roce_cmq_query_hw_info(struct hns_roce_dev *hr_dev)
return 0;
}
+static void hns_roce_function_clear(struct hns_roce_dev *hr_dev)
+{
+ struct hns_roce_func_clear *resp;
+ struct hns_roce_cmq_desc desc;
+ unsigned long end;
+ int ret;
+
+ hns_roce_cmq_setup_basic_desc(&desc, HNS_ROCE_OPC_FUNC_CLEAR, false);
+ resp = (struct hns_roce_func_clear *)desc.data;
+
+ ret = hns_roce_cmq_send(hr_dev, &desc, 1);
+ if (ret) {
+ dev_err(hr_dev->dev, "Func clear write failed, ret = %d.\n",
+ ret);
+ return;
+ }
+
+ msleep(HNS_ROCE_V2_READ_FUNC_CLEAR_FLAG_INTERVAL);
+ end = HNS_ROCE_V2_FUNC_CLEAR_TIMEOUT_MSECS;
+ while (end) {
+ msleep(HNS_ROCE_V2_READ_FUNC_CLEAR_FLAG_FAIL_WAIT);
+ end -= HNS_ROCE_V2_READ_FUNC_CLEAR_FLAG_FAIL_WAIT;
+
+ hns_roce_cmq_setup_basic_desc(&desc, HNS_ROCE_OPC_FUNC_CLEAR,
+ true);
+
+ ret = hns_roce_cmq_send(hr_dev, &desc, 1);
+ if (ret)
+ continue;
+
+ if (roce_get_bit(resp->func_done, FUNC_CLEAR_RST_FUN_DONE_S)) {
+ hr_dev->is_reset = true;
+ return;
+ }
+ }
+
+ dev_err(hr_dev->dev, "Func clear fail.\n");
+}
+
static int hns_roce_query_fw_ver(struct hns_roce_dev *hr_dev)
{
struct hns_roce_query_fw_info *resp;
@@ -1574,7 +1613,10 @@ static int hns_roce_v2_profile(struct hns_roce_dev *hr_dev)
caps->mtt_ba_pg_sz = 0;
caps->mtt_buf_pg_sz = 0;
caps->mtt_hop_num = HNS_ROCE_MTT_HOP_NUM;
- caps->cqe_ba_pg_sz = 0;
+ caps->wqe_sq_hop_num = 2;
+ caps->wqe_sge_hop_num = 1;
+ caps->wqe_rq_hop_num = 2;
+ caps->cqe_ba_pg_sz = 6;
caps->cqe_buf_pg_sz = 0;
caps->cqe_hop_num = HNS_ROCE_CQE_HOP_NUM;
caps->srqwqe_ba_pg_sz = 0;
@@ -1774,7 +1816,6 @@ static int hns_roce_init_link_table(struct hns_roce_dev *hr_dev,
goto err_alloc_buf_failed;
link_tbl->pg_list[i].map = t;
- memset(link_tbl->pg_list[i].buf, 0, buf_chk_sz);
entry[i].blk_ba0 = (t >> 12) & 0xffffffff;
roce_set_field(entry[i].blk_ba1_nxt_ptr,
@@ -1891,6 +1932,9 @@ static void hns_roce_v2_exit(struct hns_roce_dev *hr_dev)
{
struct hns_roce_v2_priv *priv = hr_dev->priv;
+ if (hr_dev->pci_dev->revision == 0x21)
+ hns_roce_function_clear(hr_dev);
+
hns_roce_free_link_table(hr_dev, &priv->tpq);
hns_roce_free_link_table(hr_dev, &priv->tsq);
}
@@ -1974,7 +2018,7 @@ static int hns_roce_v2_chk_mbox(struct hns_roce_dev *hr_dev,
unsigned long timeout)
{
struct device *dev = hr_dev->dev;
- unsigned long end = 0;
+ unsigned long end;
u32 status;
end = msecs_to_jiffies(timeout) + jiffies;
@@ -2340,15 +2384,10 @@ static void *get_srq_wqe(struct hns_roce_srq *srq, int n)
static void hns_roce_free_srq_wqe(struct hns_roce_srq *srq, int wqe_index)
{
- u32 bitmap_num;
- int bit_num;
-
/* always called with interrupts disabled. */
spin_lock(&srq->lock);
- bitmap_num = wqe_index / (sizeof(u64) * 8);
- bit_num = wqe_index % (sizeof(u64) * 8);
- srq->idx_que.bitmap[bitmap_num] |= (1ULL << bit_num);
+ bitmap_clear(srq->idx_que.bitmap, wqe_index, 1);
srq->tail++;
spin_unlock(&srq->lock);
@@ -2977,7 +3016,7 @@ static int hns_roce_v2_clear_hem(struct hns_roce_dev *hr_dev,
{
struct device *dev = hr_dev->dev;
struct hns_roce_cmd_mailbox *mailbox;
- int ret = 0;
+ int ret;
u16 op = 0xff;
if (!hns_roce_check_whether_mhop(hr_dev, table->type))
@@ -3026,7 +3065,6 @@ static int hns_roce_v2_clear_hem(struct hns_roce_dev *hr_dev,
}
static int hns_roce_v2_qp_modify(struct hns_roce_dev *hr_dev,
- struct hns_roce_mtt *mtt,
enum ib_qp_state cur_state,
enum ib_qp_state new_state,
struct hns_roce_v2_qp_context *context,
@@ -3426,7 +3464,9 @@ static void modify_qp_init_to_init(struct ib_qp *ibqp,
else
roce_set_field(context->byte_4_sqpn_tst,
V2_QPC_BYTE_4_SGE_SHIFT_M,
- V2_QPC_BYTE_4_SGE_SHIFT_S, hr_qp->sq.max_gs > 2 ?
+ V2_QPC_BYTE_4_SGE_SHIFT_S,
+ hr_qp->sq.max_gs >
+ HNS_ROCE_V2_UC_RC_SGE_NUM_IN_WQE ?
ilog2((unsigned int)hr_qp->sge.sge_cnt) : 0);
roce_set_field(qpc_mask->byte_4_sqpn_tst, V2_QPC_BYTE_4_SGE_SHIFT_M,
@@ -3520,6 +3560,31 @@ static void modify_qp_init_to_init(struct ib_qp *ibqp,
}
}
+static bool check_wqe_rq_mtt_count(struct hns_roce_dev *hr_dev,
+ struct hns_roce_qp *hr_qp, int mtt_cnt,
+ u32 page_size)
+{
+ struct device *dev = hr_dev->dev;
+
+ if (hr_qp->rq.wqe_cnt < 1)
+ return true;
+
+ if (mtt_cnt < 1) {
+ dev_err(dev, "qp(0x%lx) rqwqe buf ba find failed\n",
+ hr_qp->qpn);
+ return false;
+ }
+
+ if (mtt_cnt < MTT_MIN_COUNT &&
+ (hr_qp->rq.offset + page_size) < hr_qp->buff_size) {
+ dev_err(dev, "qp(0x%lx) next rqwqe buf ba find failed\n",
+ hr_qp->qpn);
+ return false;
+ }
+
+ return true;
+}
+
static int modify_qp_init_to_rtr(struct ib_qp *ibqp,
const struct ib_qp_attr *attr, int attr_mask,
struct hns_roce_v2_qp_context *context,
@@ -3529,25 +3594,27 @@ static int modify_qp_init_to_rtr(struct ib_qp *ibqp,
struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device);
struct hns_roce_qp *hr_qp = to_hr_qp(ibqp);
struct device *dev = hr_dev->dev;
+ u64 mtts[MTT_MIN_COUNT] = { 0 };
dma_addr_t dma_handle_3;
dma_addr_t dma_handle_2;
- dma_addr_t dma_handle;
+ u64 wqe_sge_ba;
u32 page_size;
u8 port_num;
u64 *mtts_3;
u64 *mtts_2;
- u64 *mtts;
+ int count;
u8 *dmac;
u8 *smac;
int port;
/* Search qp buf's mtts */
- mtts = hns_roce_table_find(hr_dev, &hr_dev->mr_table.mtt_table,
- hr_qp->mtt.first_seg, &dma_handle);
- if (!mtts) {
- dev_err(dev, "qp buf pa find failed\n");
- return -EINVAL;
- }
+ page_size = 1 << (hr_dev->caps.mtt_buf_pg_sz + PAGE_SHIFT);
+ count = hns_roce_mtr_find(hr_dev, &hr_qp->mtr,
+ hr_qp->rq.offset / page_size, mtts,
+ MTT_MIN_COUNT, &wqe_sge_ba);
+ if (!ibqp->srq)
+ if (!check_wqe_rq_mtt_count(hr_dev, hr_qp, count, page_size))
+ return -EINVAL;
/* Search IRRL's mtts */
mtts_2 = hns_roce_table_find(hr_dev, &hr_dev->qp_table.irrl_table,
@@ -3571,7 +3638,7 @@ static int modify_qp_init_to_rtr(struct ib_qp *ibqp,
}
dmac = (u8 *)attr->ah_attr.roce.dmac;
- context->wqe_sge_ba = (u32)(dma_handle >> 3);
+ context->wqe_sge_ba = (u32)(wqe_sge_ba >> 3);
qpc_mask->wqe_sge_ba = 0;
/*
@@ -3581,22 +3648,23 @@ static int modify_qp_init_to_rtr(struct ib_qp *ibqp,
* 0 at the same time, else set them to 0x1.
*/
roce_set_field(context->byte_12_sq_hop, V2_QPC_BYTE_12_WQE_SGE_BA_M,
- V2_QPC_BYTE_12_WQE_SGE_BA_S, dma_handle >> (32 + 3));
+ V2_QPC_BYTE_12_WQE_SGE_BA_S, wqe_sge_ba >> (32 + 3));
roce_set_field(qpc_mask->byte_12_sq_hop, V2_QPC_BYTE_12_WQE_SGE_BA_M,
V2_QPC_BYTE_12_WQE_SGE_BA_S, 0);
roce_set_field(context->byte_12_sq_hop, V2_QPC_BYTE_12_SQ_HOP_NUM_M,
V2_QPC_BYTE_12_SQ_HOP_NUM_S,
- hr_dev->caps.mtt_hop_num == HNS_ROCE_HOP_NUM_0 ?
- 0 : hr_dev->caps.mtt_hop_num);
+ hr_dev->caps.wqe_sq_hop_num == HNS_ROCE_HOP_NUM_0 ?
+ 0 : hr_dev->caps.wqe_sq_hop_num);
roce_set_field(qpc_mask->byte_12_sq_hop, V2_QPC_BYTE_12_SQ_HOP_NUM_M,
V2_QPC_BYTE_12_SQ_HOP_NUM_S, 0);
roce_set_field(context->byte_20_smac_sgid_idx,
V2_QPC_BYTE_20_SGE_HOP_NUM_M,
V2_QPC_BYTE_20_SGE_HOP_NUM_S,
- ((ibqp->qp_type == IB_QPT_GSI) || hr_qp->sq.max_gs > 2) ?
- hr_dev->caps.mtt_hop_num : 0);
+ ((ibqp->qp_type == IB_QPT_GSI) ||
+ hr_qp->sq.max_gs > HNS_ROCE_V2_UC_RC_SGE_NUM_IN_WQE) ?
+ hr_dev->caps.wqe_sge_hop_num : 0);
roce_set_field(qpc_mask->byte_20_smac_sgid_idx,
V2_QPC_BYTE_20_SGE_HOP_NUM_M,
V2_QPC_BYTE_20_SGE_HOP_NUM_S, 0);
@@ -3604,8 +3672,8 @@ static int modify_qp_init_to_rtr(struct ib_qp *ibqp,
roce_set_field(context->byte_20_smac_sgid_idx,
V2_QPC_BYTE_20_RQ_HOP_NUM_M,
V2_QPC_BYTE_20_RQ_HOP_NUM_S,
- hr_dev->caps.mtt_hop_num == HNS_ROCE_HOP_NUM_0 ?
- 0 : hr_dev->caps.mtt_hop_num);
+ hr_dev->caps.wqe_rq_hop_num == HNS_ROCE_HOP_NUM_0 ?
+ 0 : hr_dev->caps.wqe_rq_hop_num);
roce_set_field(qpc_mask->byte_20_smac_sgid_idx,
V2_QPC_BYTE_20_RQ_HOP_NUM_M,
V2_QPC_BYTE_20_RQ_HOP_NUM_S, 0);
@@ -3613,7 +3681,7 @@ static int modify_qp_init_to_rtr(struct ib_qp *ibqp,
roce_set_field(context->byte_16_buf_ba_pg_sz,
V2_QPC_BYTE_16_WQE_SGE_BA_PG_SZ_M,
V2_QPC_BYTE_16_WQE_SGE_BA_PG_SZ_S,
- hr_dev->caps.mtt_ba_pg_sz + PG_SHIFT_OFFSET);
+ hr_qp->wqe_bt_pg_shift + PG_SHIFT_OFFSET);
roce_set_field(qpc_mask->byte_16_buf_ba_pg_sz,
V2_QPC_BYTE_16_WQE_SGE_BA_PG_SZ_M,
V2_QPC_BYTE_16_WQE_SGE_BA_PG_SZ_S, 0);
@@ -3626,29 +3694,24 @@ static int modify_qp_init_to_rtr(struct ib_qp *ibqp,
V2_QPC_BYTE_16_WQE_SGE_BUF_PG_SZ_M,
V2_QPC_BYTE_16_WQE_SGE_BUF_PG_SZ_S, 0);
- page_size = 1 << (hr_dev->caps.mtt_buf_pg_sz + PAGE_SHIFT);
- context->rq_cur_blk_addr = (u32)(mtts[hr_qp->rq.offset / page_size]
- >> PAGE_ADDR_SHIFT);
+ context->rq_cur_blk_addr = (u32)(mtts[0] >> PAGE_ADDR_SHIFT);
qpc_mask->rq_cur_blk_addr = 0;
roce_set_field(context->byte_92_srq_info,
V2_QPC_BYTE_92_RQ_CUR_BLK_ADDR_M,
V2_QPC_BYTE_92_RQ_CUR_BLK_ADDR_S,
- mtts[hr_qp->rq.offset / page_size]
- >> (32 + PAGE_ADDR_SHIFT));
+ mtts[0] >> (32 + PAGE_ADDR_SHIFT));
roce_set_field(qpc_mask->byte_92_srq_info,
V2_QPC_BYTE_92_RQ_CUR_BLK_ADDR_M,
V2_QPC_BYTE_92_RQ_CUR_BLK_ADDR_S, 0);
- context->rq_nxt_blk_addr = (u32)(mtts[hr_qp->rq.offset / page_size + 1]
- >> PAGE_ADDR_SHIFT);
+ context->rq_nxt_blk_addr = (u32)(mtts[1] >> PAGE_ADDR_SHIFT);
qpc_mask->rq_nxt_blk_addr = 0;
roce_set_field(context->byte_104_rq_sge,
V2_QPC_BYTE_104_RQ_NXT_BLK_ADDR_M,
V2_QPC_BYTE_104_RQ_NXT_BLK_ADDR_S,
- mtts[hr_qp->rq.offset / page_size + 1]
- >> (32 + PAGE_ADDR_SHIFT));
+ mtts[1] >> (32 + PAGE_ADDR_SHIFT));
roce_set_field(qpc_mask->byte_104_rq_sge,
V2_QPC_BYTE_104_RQ_NXT_BLK_ADDR_M,
V2_QPC_BYTE_104_RQ_NXT_BLK_ADDR_S, 0);
@@ -3708,13 +3771,14 @@ static int modify_qp_init_to_rtr(struct ib_qp *ibqp,
roce_set_field(qpc_mask->byte_20_smac_sgid_idx,
V2_QPC_BYTE_20_SGID_IDX_M,
V2_QPC_BYTE_20_SGID_IDX_S, 0);
- memcpy(&(context->dmac), dmac, 4);
+ memcpy(&(context->dmac), dmac, sizeof(u32));
roce_set_field(context->byte_52_udpspn_dmac, V2_QPC_BYTE_52_DMAC_M,
V2_QPC_BYTE_52_DMAC_S, *((u16 *)(&dmac[4])));
qpc_mask->dmac = 0;
roce_set_field(qpc_mask->byte_52_udpspn_dmac, V2_QPC_BYTE_52_DMAC_M,
V2_QPC_BYTE_52_DMAC_S, 0);
+ /* mtu*(2^LP_PKTN_INI) should not bigger than 1 message length 64kb */
roce_set_field(context->byte_56_dqpn_err, V2_QPC_BYTE_56_LP_PKTN_INI_M,
V2_QPC_BYTE_56_LP_PKTN_INI_S, 4);
roce_set_field(qpc_mask->byte_56_dqpn_err, V2_QPC_BYTE_56_LP_PKTN_INI_M,
@@ -3756,6 +3820,7 @@ static int modify_qp_init_to_rtr(struct ib_qp *ibqp,
roce_set_field(qpc_mask->byte_132_trrl, V2_QPC_BYTE_132_TRRL_TAIL_MAX_M,
V2_QPC_BYTE_132_TRRL_TAIL_MAX_S, 0);
+ /* rocee send 2^lp_sgen_ini segs every time */
roce_set_field(context->byte_168_irrl_idx,
V2_QPC_BYTE_168_LP_SGEN_INI_M,
V2_QPC_BYTE_168_LP_SGEN_INI_S, 3);
@@ -3774,18 +3839,30 @@ static int modify_qp_rtr_to_rts(struct ib_qp *ibqp,
struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device);
struct hns_roce_qp *hr_qp = to_hr_qp(ibqp);
struct device *dev = hr_dev->dev;
- dma_addr_t dma_handle;
+ u64 sge_cur_blk = 0;
+ u64 sq_cur_blk = 0;
u32 page_size;
- u64 *mtts;
+ int count;
/* Search qp buf's mtts */
- mtts = hns_roce_table_find(hr_dev, &hr_dev->mr_table.mtt_table,
- hr_qp->mtt.first_seg, &dma_handle);
- if (!mtts) {
- dev_err(dev, "qp buf pa find failed\n");
+ count = hns_roce_mtr_find(hr_dev, &hr_qp->mtr, 0, &sq_cur_blk, 1, NULL);
+ if (count < 1) {
+ dev_err(dev, "qp(0x%lx) buf pa find failed\n", hr_qp->qpn);
return -EINVAL;
}
+ if (hr_qp->sge.offset) {
+ page_size = 1 << (hr_dev->caps.mtt_buf_pg_sz + PAGE_SHIFT);
+ count = hns_roce_mtr_find(hr_dev, &hr_qp->mtr,
+ hr_qp->sge.offset / page_size,
+ &sge_cur_blk, 1, NULL);
+ if (count < 1) {
+ dev_err(dev, "qp(0x%lx) sge pa find failed\n",
+ hr_qp->qpn);
+ return -EINVAL;
+ }
+ }
+
/* Not support alternate path and path migration */
if ((attr_mask & IB_QP_ALT_PATH) ||
(attr_mask & IB_QP_PATH_MIG_STATE)) {
@@ -3799,37 +3876,37 @@ static int modify_qp_rtr_to_rts(struct ib_qp *ibqp,
* we should set all bits of the relevant fields in context mask to
* 0 at the same time, else set them to 0x1.
*/
- context->sq_cur_blk_addr = (u32)(mtts[0] >> PAGE_ADDR_SHIFT);
+ context->sq_cur_blk_addr = (u32)(sq_cur_blk >> PAGE_ADDR_SHIFT);
roce_set_field(context->byte_168_irrl_idx,
V2_QPC_BYTE_168_SQ_CUR_BLK_ADDR_M,
V2_QPC_BYTE_168_SQ_CUR_BLK_ADDR_S,
- mtts[0] >> (32 + PAGE_ADDR_SHIFT));
+ sq_cur_blk >> (32 + PAGE_ADDR_SHIFT));
qpc_mask->sq_cur_blk_addr = 0;
roce_set_field(qpc_mask->byte_168_irrl_idx,
V2_QPC_BYTE_168_SQ_CUR_BLK_ADDR_M,
V2_QPC_BYTE_168_SQ_CUR_BLK_ADDR_S, 0);
- page_size = 1 << (hr_dev->caps.mtt_buf_pg_sz + PAGE_SHIFT);
- context->sq_cur_sge_blk_addr =
- ((ibqp->qp_type == IB_QPT_GSI) || hr_qp->sq.max_gs > 2) ?
- ((u32)(mtts[hr_qp->sge.offset / page_size]
- >> PAGE_ADDR_SHIFT)) : 0;
+ context->sq_cur_sge_blk_addr = ((ibqp->qp_type == IB_QPT_GSI) ||
+ hr_qp->sq.max_gs > HNS_ROCE_V2_UC_RC_SGE_NUM_IN_WQE) ?
+ ((u32)(sge_cur_blk >>
+ PAGE_ADDR_SHIFT)) : 0;
roce_set_field(context->byte_184_irrl_idx,
V2_QPC_BYTE_184_SQ_CUR_SGE_BLK_ADDR_M,
V2_QPC_BYTE_184_SQ_CUR_SGE_BLK_ADDR_S,
- ((ibqp->qp_type == IB_QPT_GSI) || hr_qp->sq.max_gs > 2) ?
- (mtts[hr_qp->sge.offset / page_size] >>
+ ((ibqp->qp_type == IB_QPT_GSI) || hr_qp->sq.max_gs >
+ HNS_ROCE_V2_UC_RC_SGE_NUM_IN_WQE) ?
+ (sge_cur_blk >>
(32 + PAGE_ADDR_SHIFT)) : 0);
qpc_mask->sq_cur_sge_blk_addr = 0;
roce_set_field(qpc_mask->byte_184_irrl_idx,
V2_QPC_BYTE_184_SQ_CUR_SGE_BLK_ADDR_M,
V2_QPC_BYTE_184_SQ_CUR_SGE_BLK_ADDR_S, 0);
- context->rx_sq_cur_blk_addr = (u32)(mtts[0] >> PAGE_ADDR_SHIFT);
+ context->rx_sq_cur_blk_addr = (u32)(sq_cur_blk >> PAGE_ADDR_SHIFT);
roce_set_field(context->byte_232_irrl_sge,
V2_QPC_BYTE_232_RX_SQ_CUR_BLK_ADDR_M,
V2_QPC_BYTE_232_RX_SQ_CUR_BLK_ADDR_S,
- mtts[0] >> (32 + PAGE_ADDR_SHIFT));
+ sq_cur_blk >> (32 + PAGE_ADDR_SHIFT));
qpc_mask->rx_sq_cur_blk_addr = 0;
roce_set_field(qpc_mask->byte_232_irrl_sge,
V2_QPC_BYTE_232_RX_SQ_CUR_BLK_ADDR_M,
@@ -4144,7 +4221,7 @@ static int hns_roce_v2_modify_qp(struct ib_qp *ibqp,
roce_set_field(context->byte_224_retry_msg,
V2_QPC_BYTE_224_RETRY_MSG_PSN_M,
V2_QPC_BYTE_224_RETRY_MSG_PSN_S,
- attr->sq_psn >> 16);
+ attr->sq_psn >> V2_QPC_BYTE_220_RETRY_MSG_PSN_S);
roce_set_field(qpc_mask->byte_224_retry_msg,
V2_QPC_BYTE_224_RETRY_MSG_PSN_M,
V2_QPC_BYTE_224_RETRY_MSG_PSN_S, 0);
@@ -4230,7 +4307,7 @@ static int hns_roce_v2_modify_qp(struct ib_qp *ibqp,
V2_QPC_BYTE_60_QP_ST_S, 0);
/* SW pass context to HW */
- ret = hns_roce_v2_qp_modify(hr_dev, &hr_qp->mtt, cur_state, new_state,
+ ret = hns_roce_v2_qp_modify(hr_dev, cur_state, new_state,
context, hr_qp);
if (ret) {
dev_err(dev, "hns_roce_qp_modify failed(%d)\n", ret);
@@ -4374,11 +4451,12 @@ static int hns_roce_v2_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr,
V2_QPC_BYTE_56_DQPN_M,
V2_QPC_BYTE_56_DQPN_S);
qp_attr->qp_access_flags = ((roce_get_bit(context->byte_76_srqn_op_en,
- V2_QPC_BYTE_76_RRE_S)) << 2) |
- ((roce_get_bit(context->byte_76_srqn_op_en,
- V2_QPC_BYTE_76_RWE_S)) << 1) |
- ((roce_get_bit(context->byte_76_srqn_op_en,
- V2_QPC_BYTE_76_ATE_S)) << 3);
+ V2_QPC_BYTE_76_RRE_S)) << V2_QP_RWE_S) |
+ ((roce_get_bit(context->byte_76_srqn_op_en,
+ V2_QPC_BYTE_76_RWE_S)) << V2_QP_RRE_S) |
+ ((roce_get_bit(context->byte_76_srqn_op_en,
+ V2_QPC_BYTE_76_ATE_S)) << V2_QP_ATE_S);
+
if (hr_qp->ibqp.qp_type == IB_QPT_RC ||
hr_qp->ibqp.qp_type == IB_QPT_UC) {
struct ib_global_route *grh =
@@ -4487,7 +4565,7 @@ static int hns_roce_v2_destroy_qp_common(struct hns_roce_dev *hr_dev,
(hr_qp->ibqp.qp_type == IB_QPT_UD))
hns_roce_release_range_qp(hr_dev, hr_qp->qpn, 1);
- hns_roce_mtt_cleanup(hr_dev, &hr_qp->mtt);
+ hns_roce_mtr_cleanup(hr_dev, &hr_qp->mtr);
if (udata) {
struct hns_roce_ucontext *context =
@@ -4501,7 +4579,6 @@ static int hns_roce_v2_destroy_qp_common(struct hns_roce_dev *hr_dev,
if (hr_qp->rq.wqe_cnt && (hr_qp->rdb_en == 1))
hns_roce_db_unmap_user(context, &hr_qp->rdb);
- ib_umem_release(hr_qp->umem);
} else {
kfree(hr_qp->sq.wrid);
kfree(hr_qp->rq.wrid);
@@ -4509,6 +4586,7 @@ static int hns_roce_v2_destroy_qp_common(struct hns_roce_dev *hr_dev,
if (hr_qp->rq.wqe_cnt)
hns_roce_free_db(hr_dev, &hr_qp->rdb);
}
+ ib_umem_release(hr_qp->umem);
if ((hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RQ_INLINE) &&
hr_qp->rq.wqe_cnt) {
@@ -4682,7 +4760,6 @@ static void hns_roce_irq_work_handle(struct work_struct *work)
dev_warn(dev, "Path migration failed.\n");
break;
case HNS_ROCE_EVENT_TYPE_COMM_EST:
- dev_info(dev, "Communication established.\n");
break;
case HNS_ROCE_EVENT_TYPE_SQ_DRAINED:
dev_warn(dev, "Send queue drained.\n");
@@ -5151,8 +5228,8 @@ static void hns_roce_mhop_free_eq(struct hns_roce_dev *hr_dev,
dma_free_coherent(dev, bt_chk_sz, eq->bt_l1[i],
eq->l1_dma[i]);
- for (j = 0; j < bt_chk_sz / 8; j++) {
- idx = i * (bt_chk_sz / 8) + j;
+ for (j = 0; j < bt_chk_sz / BA_BYTE_LEN; j++) {
+ idx = i * (bt_chk_sz / BA_BYTE_LEN) + j;
if ((i == eq->l0_last_num - 1)
&& j == eq->l1_last_num - 1) {
eqe_alloc = (buf_chk_sz / eq->eqe_size)
@@ -5368,9 +5445,9 @@ static int hns_roce_mhop_alloc_eq(struct hns_roce_dev *hr_dev,
buf_chk_sz = 1 << (hr_dev->caps.eqe_buf_pg_sz + PAGE_SHIFT);
bt_chk_sz = 1 << (hr_dev->caps.eqe_ba_pg_sz + PAGE_SHIFT);
- ba_num = (PAGE_ALIGN(eq->entries * eq->eqe_size) + buf_chk_sz - 1)
- / buf_chk_sz;
- bt_num = (ba_num + bt_chk_sz / 8 - 1) / (bt_chk_sz / 8);
+ ba_num = DIV_ROUND_UP(PAGE_ALIGN(eq->entries * eq->eqe_size),
+ buf_chk_sz);
+ bt_num = DIV_ROUND_UP(ba_num, bt_chk_sz / BA_BYTE_LEN);
/* hop_num = 0 */
if (mhop_num == HNS_ROCE_HOP_NUM_0) {
@@ -5387,8 +5464,6 @@ static int hns_roce_mhop_alloc_eq(struct hns_roce_dev *hr_dev,
eq->cur_eqe_ba = eq->l0_dma;
eq->nxt_eqe_ba = 0;
- memset(eq->bt_l0, 0, eq->entries * eq->eqe_size);
-
return 0;
}
@@ -5415,12 +5490,12 @@ static int hns_roce_mhop_alloc_eq(struct hns_roce_dev *hr_dev,
goto err_dma_alloc_l0;
if (mhop_num == 1) {
- if (ba_num > (bt_chk_sz / 8))
+ if (ba_num > (bt_chk_sz / BA_BYTE_LEN))
dev_err(dev, "ba_num %d is too large for 1 hop\n",
ba_num);
/* alloc buf */
- for (i = 0; i < bt_chk_sz / 8; i++) {
+ for (i = 0; i < bt_chk_sz / BA_BYTE_LEN; i++) {
if (eq_buf_cnt + 1 < ba_num) {
size = buf_chk_sz;
} else {
@@ -5444,7 +5519,7 @@ static int hns_roce_mhop_alloc_eq(struct hns_roce_dev *hr_dev,
} else if (mhop_num == 2) {
/* alloc L1 BT and buf */
- for (i = 0; i < bt_chk_sz / 8; i++) {
+ for (i = 0; i < bt_chk_sz / BA_BYTE_LEN; i++) {
eq->bt_l1[i] = dma_alloc_coherent(dev, bt_chk_sz,
&(eq->l1_dma[i]),
GFP_KERNEL);
@@ -5452,8 +5527,8 @@ static int hns_roce_mhop_alloc_eq(struct hns_roce_dev *hr_dev,
goto err_dma_alloc_l1;
*(eq->bt_l0 + i) = eq->l1_dma[i];
- for (j = 0; j < bt_chk_sz / 8; j++) {
- idx = i * bt_chk_sz / 8 + j;
+ for (j = 0; j < bt_chk_sz / BA_BYTE_LEN; j++) {
+ idx = i * bt_chk_sz / BA_BYTE_LEN + j;
if (eq_buf_cnt + 1 < ba_num) {
size = buf_chk_sz;
} else {
@@ -5498,8 +5573,8 @@ err_dma_alloc_l1:
dma_free_coherent(dev, bt_chk_sz, eq->bt_l1[i],
eq->l1_dma[i]);
- for (j = 0; j < bt_chk_sz / 8; j++) {
- idx = i * bt_chk_sz / 8 + j;
+ for (j = 0; j < bt_chk_sz / BA_BYTE_LEN; j++) {
+ idx = i * bt_chk_sz / BA_BYTE_LEN + j;
dma_free_coherent(dev, buf_chk_sz, eq->buf[idx],
eq->buf_dma[idx]);
}
@@ -5522,11 +5597,11 @@ err_dma_alloc_buf:
dma_free_coherent(dev, bt_chk_sz, eq->bt_l1[i],
eq->l1_dma[i]);
- for (j = 0; j < bt_chk_sz / 8; j++) {
+ for (j = 0; j < bt_chk_sz / BA_BYTE_LEN; j++) {
if (i == record_i && j >= record_j)
break;
- idx = i * bt_chk_sz / 8 + j;
+ idx = i * bt_chk_sz / BA_BYTE_LEN + j;
dma_free_coherent(dev, buf_chk_sz,
eq->buf[idx],
eq->buf_dma[idx]);
@@ -5972,18 +6047,19 @@ out:
return ret;
}
-static int find_empty_entry(struct hns_roce_idx_que *idx_que)
+static int find_empty_entry(struct hns_roce_idx_que *idx_que,
+ unsigned long size)
{
- int bit_num;
- int i;
+ int wqe_idx;
- /* bitmap[i] is set zero if all bits are allocated */
- for (i = 0; idx_que->bitmap[i] == 0; ++i)
- ;
- bit_num = ffs(idx_que->bitmap[i]);
- idx_que->bitmap[i] &= ~(1ULL << (bit_num - 1));
+ if (unlikely(bitmap_full(idx_que->bitmap, size)))
+ return -ENOSPC;
+
+ wqe_idx = find_first_zero_bit(idx_que->bitmap, size);
- return i * sizeof(u64) * 8 + (bit_num - 1);
+ bitmap_set(idx_que->bitmap, wqe_idx, 1);
+
+ return wqe_idx;
}
static void fill_idx_queue(struct hns_roce_idx_que *idx_que,
@@ -6029,7 +6105,13 @@ static int hns_roce_v2_post_srq_recv(struct ib_srq *ibsrq,
break;
}
- wqe_idx = find_empty_entry(&srq->idx_que);
+ wqe_idx = find_empty_entry(&srq->idx_que, srq->max);
+ if (wqe_idx < 0) {
+ ret = -ENOMEM;
+ *bad_wr = wr;
+ break;
+ }
+
fill_idx_queue(&srq->idx_que, ind, wqe_idx);
wqe = get_srq_wqe(srq, wqe_idx);
dseg = (struct hns_roce_v2_wqe_data_seg *)wqe;
@@ -6041,9 +6123,9 @@ static int hns_roce_v2_post_srq_recv(struct ib_srq *ibsrq,
}
if (i < srq->max_gs) {
- dseg->len = 0;
- dseg->lkey = cpu_to_le32(0x100);
- dseg->addr = 0;
+ dseg[i].len = 0;
+ dseg[i].lkey = cpu_to_le32(0x100);
+ dseg[i].addr = 0;
}
srq->wrid[wqe_idx] = wr->wr_id;
@@ -6059,7 +6141,8 @@ static int hns_roce_v2_post_srq_recv(struct ib_srq *ibsrq,
*/
wmb();
- srq_db.byte_4 = HNS_ROCE_V2_SRQ_DB << 24 | srq->srqn;
+ srq_db.byte_4 = HNS_ROCE_V2_SRQ_DB << V2_DB_BYTE_4_CMD_S |
+ (srq->srqn & V2_DB_BYTE_4_TAG_M);
srq_db.parameter = srq->head;
hns_roce_write64(hr_dev, (__le32 *)&srq_db, srq->db_reg_l);
@@ -6301,6 +6384,7 @@ static int hns_roce_hw_v2_reset_notify_down(struct hnae3_handle *handle)
if (!hr_dev)
return 0;
+ hr_dev->is_reset = true;
hr_dev->active = false;
hr_dev->dis_db = true;
diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h
index edfdbe2ce0db..478f5a5b7aa1 100644
--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h
+++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h
@@ -54,7 +54,7 @@
#define HNS_ROCE_V2_MAX_CQ_NUM 0x100000
#define HNS_ROCE_V2_MAX_CQC_TIMER_NUM 0x100
#define HNS_ROCE_V2_MAX_SRQ_NUM 0x100000
-#define HNS_ROCE_V2_MAX_CQE_NUM 0x10000
+#define HNS_ROCE_V2_MAX_CQE_NUM 0x400000
#define HNS_ROCE_V2_MAX_SRQWQE_NUM 0x8000
#define HNS_ROCE_V2_MAX_RQ_SGE_NUM 0x100
#define HNS_ROCE_V2_MAX_SQ_SGE_NUM 0xff
@@ -241,6 +241,7 @@ enum hns_roce_opcode_type {
HNS_ROCE_OPC_POST_MB = 0x8504,
HNS_ROCE_OPC_QUERY_MB_ST = 0x8505,
HNS_ROCE_OPC_CFG_BT_ATTR = 0x8506,
+ HNS_ROCE_OPC_FUNC_CLEAR = 0x8508,
HNS_ROCE_OPC_CLR_SCCC = 0x8509,
HNS_ROCE_OPC_QUERY_SCCC = 0x850a,
HNS_ROCE_OPC_RESET_SCCC = 0x850b,
@@ -886,6 +887,10 @@ struct hns_roce_v2_qp_context {
#define V2_QPC_BYTE_256_SQ_FLUSH_IDX_S 16
#define V2_QPC_BYTE_256_SQ_FLUSH_IDX_M GENMASK(31, 16)
+#define V2_QP_RWE_S 1 /* rdma write enable */
+#define V2_QP_RRE_S 2 /* rdma read enable */
+#define V2_QP_ATE_S 3 /* rdma atomic enable */
+
struct hns_roce_v2_cqe {
__le32 byte_4;
union {
@@ -1226,6 +1231,22 @@ struct hns_roce_query_fw_info {
__le32 rsv[5];
};
+struct hns_roce_func_clear {
+ __le32 rst_funcid_en;
+ __le32 func_done;
+ __le32 rsv[4];
+};
+
+#define FUNC_CLEAR_RST_FUN_DONE_S 0
+/* Each physical function manages up to 248 virtual functionsï¼›
+ * it takes up to 100ms for each function to execute clearï¼›
+ * if an abnormal reset occurs, it is executed twice at most;
+ * so it takes up to 249 * 2 * 100ms.
+ */
+#define HNS_ROCE_V2_FUNC_CLEAR_TIMEOUT_MSECS (249 * 2 * 100)
+#define HNS_ROCE_V2_READ_FUNC_CLEAR_FLAG_INTERVAL 40
+#define HNS_ROCE_V2_READ_FUNC_CLEAR_FLAG_FAIL_WAIT 20
+
struct hns_roce_cfg_llm_a {
__le32 base_addr_l;
__le32 base_addr_h;
diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c
index 8da5f18bf820..1e4ba48f5613 100644
--- a/drivers/infiniband/hw/hns/hns_roce_main.c
+++ b/drivers/infiniband/hw/hns/hns_roce_main.c
@@ -57,17 +57,16 @@ int hns_get_gid_index(struct hns_roce_dev *hr_dev, u8 port, int gid_index)
{
return gid_index * hr_dev->caps.num_ports + port;
}
-EXPORT_SYMBOL_GPL(hns_get_gid_index);
static int hns_roce_set_mac(struct hns_roce_dev *hr_dev, u8 port, u8 *addr)
{
u8 phy_port;
u32 i = 0;
- if (!memcmp(hr_dev->dev_addr[port], addr, MAC_ADDR_OCTET_NUM))
+ if (!memcmp(hr_dev->dev_addr[port], addr, ETH_ALEN))
return 0;
- for (i = 0; i < MAC_ADDR_OCTET_NUM; i++)
+ for (i = 0; i < ETH_ALEN; i++)
hr_dev->dev_addr[port][i] = addr[i];
phy_port = hr_dev->iboe.phy_port[port];
@@ -78,18 +77,13 @@ static int hns_roce_add_gid(const struct ib_gid_attr *attr, void **context)
{
struct hns_roce_dev *hr_dev = to_hr_dev(attr->device);
u8 port = attr->port_num - 1;
- unsigned long flags;
int ret;
if (port >= hr_dev->caps.num_ports)
return -EINVAL;
- spin_lock_irqsave(&hr_dev->iboe.lock, flags);
-
ret = hr_dev->hw->set_gid(hr_dev, port, attr->index, &attr->gid, attr);
- spin_unlock_irqrestore(&hr_dev->iboe.lock, flags);
-
return ret;
}
@@ -98,18 +92,13 @@ static int hns_roce_del_gid(const struct ib_gid_attr *attr, void **context)
struct hns_roce_dev *hr_dev = to_hr_dev(attr->device);
struct ib_gid_attr zattr = { };
u8 port = attr->port_num - 1;
- unsigned long flags;
int ret;
if (port >= hr_dev->caps.num_ports)
return -EINVAL;
- spin_lock_irqsave(&hr_dev->iboe.lock, flags);
-
ret = hr_dev->hw->set_gid(hr_dev, port, attr->index, &zgid, &zattr);
- spin_unlock_irqrestore(&hr_dev->iboe.lock, flags);
-
return ret;
}
@@ -272,7 +261,8 @@ static int hns_roce_query_port(struct ib_device *ib_dev, u8 port_num,
props->active_mtu = mtu ? min(props->max_mtu, mtu) : IB_MTU_256;
props->state = (netif_running(net_dev) && netif_carrier_ok(net_dev)) ?
IB_PORT_ACTIVE : IB_PORT_DOWN;
- props->phys_state = (props->state == IB_PORT_ACTIVE) ? 5 : 3;
+ props->phys_state = (props->state == IB_PORT_ACTIVE) ?
+ HNS_ROCE_PHY_LINKUP : HNS_ROCE_PHY_DISABLED;
spin_unlock_irqrestore(&hr_dev->iboe.lock, flags);
@@ -319,7 +309,7 @@ static int hns_roce_modify_port(struct ib_device *ib_dev, u8 port_num, int mask,
static int hns_roce_alloc_ucontext(struct ib_ucontext *uctx,
struct ib_udata *udata)
{
- int ret = 0;
+ int ret;
struct hns_roce_ucontext *context = to_hr_ucontext(uctx);
struct hns_roce_ib_alloc_ucontext_resp resp = {};
struct hns_roce_dev *hr_dev = to_hr_dev(uctx->device);
@@ -423,6 +413,11 @@ static void hns_roce_unregister_device(struct hns_roce_dev *hr_dev)
}
static const struct ib_device_ops hns_roce_dev_ops = {
+ .owner = THIS_MODULE,
+ .driver_id = RDMA_DRIVER_HNS,
+ .uverbs_abi_ver = 1,
+ .uverbs_no_driver_id_binding = 1,
+
.add_gid = hns_roce_add_gid,
.alloc_pd = hns_roce_alloc_pd,
.alloc_ucontext = hns_roce_alloc_ucontext,
@@ -451,6 +446,7 @@ static const struct ib_device_ops hns_roce_dev_ops = {
.reg_user_mr = hns_roce_reg_user_mr,
INIT_RDMA_OBJ_SIZE(ib_ah, hns_roce_ah, ibah),
+ INIT_RDMA_OBJ_SIZE(ib_cq, hns_roce_cq, ib_cq),
INIT_RDMA_OBJ_SIZE(ib_pd, hns_roce_pd, ibpd),
INIT_RDMA_OBJ_SIZE(ib_ucontext, hns_roce_ucontext, ibucontext),
};
@@ -489,14 +485,12 @@ static int hns_roce_register_device(struct hns_roce_dev *hr_dev)
ib_dev = &hr_dev->ib_dev;
- ib_dev->owner = THIS_MODULE;
ib_dev->node_type = RDMA_NODE_IB_CA;
ib_dev->dev.parent = dev;
ib_dev->phys_port_cnt = hr_dev->caps.num_ports;
ib_dev->local_dma_lkey = hr_dev->caps.reserved_lkey;
ib_dev->num_comp_vectors = hr_dev->caps.num_comp_vectors;
- ib_dev->uverbs_abi_ver = 1;
ib_dev->uverbs_cmd_mask =
(1ULL << IB_USER_VERBS_CMD_GET_CONTEXT) |
(1ULL << IB_USER_VERBS_CMD_QUERY_DEVICE) |
@@ -545,7 +539,6 @@ static int hns_roce_register_device(struct hns_roce_dev *hr_dev)
ib_set_device_ops(ib_dev, hr_dev->hw->hns_roce_dev_srq_ops);
}
- ib_dev->driver_id = RDMA_DRIVER_HNS;
ib_set_device_ops(ib_dev, hr_dev->hw->hns_roce_dev_ops);
ib_set_device_ops(ib_dev, &hns_roce_dev_ops);
for (i = 0; i < hr_dev->caps.num_ports; i++) {
@@ -980,7 +973,6 @@ error_failed_cmq_init:
return ret;
}
-EXPORT_SYMBOL_GPL(hns_roce_init);
void hns_roce_exit(struct hns_roce_dev *hr_dev)
{
@@ -1001,7 +993,6 @@ void hns_roce_exit(struct hns_roce_dev *hr_dev)
if (hr_dev->hw->reset)
hr_dev->hw->reset(hr_dev, false);
}
-EXPORT_SYMBOL_GPL(hns_roce_exit);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Wei Hu <xavier.huwei@huawei.com>");
diff --git a/drivers/infiniband/hw/hns/hns_roce_mr.c b/drivers/infiniband/hw/hns/hns_roce_mr.c
index 6110ec408626..549e1a38dfe0 100644
--- a/drivers/infiniband/hw/hns/hns_roce_mr.c
+++ b/drivers/infiniband/hw/hns/hns_roce_mr.c
@@ -47,7 +47,6 @@ unsigned long key_to_hw_index(u32 key)
{
return (key << 24) | (key >> 8);
}
-EXPORT_SYMBOL_GPL(key_to_hw_index);
static int hns_roce_sw2hw_mpt(struct hns_roce_dev *hr_dev,
struct hns_roce_cmd_mailbox *mailbox,
@@ -66,7 +65,6 @@ int hns_roce_hw2sw_mpt(struct hns_roce_dev *hr_dev,
mpt_index, !mailbox, HNS_ROCE_CMD_HW2SW_MPT,
HNS_ROCE_CMD_TIMEOUT_MSECS);
}
-EXPORT_SYMBOL_GPL(hns_roce_hw2sw_mpt);
static int hns_roce_buddy_alloc(struct hns_roce_buddy *buddy, int order,
unsigned long *seg)
@@ -293,7 +291,6 @@ void hns_roce_mtt_cleanup(struct hns_roce_dev *hr_dev, struct hns_roce_mtt *mtt)
break;
}
}
-EXPORT_SYMBOL_GPL(hns_roce_mtt_cleanup);
static void hns_roce_loop_free(struct hns_roce_dev *hr_dev,
struct hns_roce_mr *mr, int err_loop_index,
@@ -314,11 +311,11 @@ static void hns_roce_loop_free(struct hns_roce_dev *hr_dev,
dma_free_coherent(dev, pbl_bt_sz, mr->pbl_bt_l1[i],
mr->pbl_l1_dma_addr[i]);
- for (j = 0; j < pbl_bt_sz / 8; j++) {
+ for (j = 0; j < pbl_bt_sz / BA_BYTE_LEN; j++) {
if (i == loop_i && j >= loop_j)
break;
- bt_idx = i * pbl_bt_sz / 8 + j;
+ bt_idx = i * pbl_bt_sz / BA_BYTE_LEN + j;
dma_free_coherent(dev, pbl_bt_sz,
mr->pbl_bt_l2[bt_idx],
mr->pbl_l2_dma_addr[bt_idx]);
@@ -329,8 +326,8 @@ static void hns_roce_loop_free(struct hns_roce_dev *hr_dev,
dma_free_coherent(dev, pbl_bt_sz, mr->pbl_bt_l1[i],
mr->pbl_l1_dma_addr[i]);
- for (j = 0; j < pbl_bt_sz / 8; j++) {
- bt_idx = i * pbl_bt_sz / 8 + j;
+ for (j = 0; j < pbl_bt_sz / BA_BYTE_LEN; j++) {
+ bt_idx = i * pbl_bt_sz / BA_BYTE_LEN + j;
dma_free_coherent(dev, pbl_bt_sz,
mr->pbl_bt_l2[bt_idx],
mr->pbl_l2_dma_addr[bt_idx]);
@@ -533,7 +530,7 @@ static int hns_roce_mr_alloc(struct hns_roce_dev *hr_dev, u32 pd, u64 iova,
{
struct device *dev = hr_dev->dev;
unsigned long index = 0;
- int ret = 0;
+ int ret;
/* Allocate a key for mr from mr_table */
ret = hns_roce_bitmap_alloc(&hr_dev->mr_table.mtpt_bitmap, &index);
@@ -559,7 +556,8 @@ static int hns_roce_mr_alloc(struct hns_roce_dev *hr_dev, u32 pd, u64 iova,
mr->pbl_l0_dma_addr = 0;
} else {
if (!hr_dev->caps.pbl_hop_num) {
- mr->pbl_buf = dma_alloc_coherent(dev, npages * 8,
+ mr->pbl_buf = dma_alloc_coherent(dev,
+ npages * BA_BYTE_LEN,
&(mr->pbl_dma_addr),
GFP_KERNEL);
if (!mr->pbl_buf)
@@ -590,9 +588,8 @@ static void hns_roce_mhop_free(struct hns_roce_dev *hr_dev,
if (mhop_num == HNS_ROCE_HOP_NUM_0)
return;
- /* hop_num = 1 */
if (mhop_num == 1) {
- dma_free_coherent(dev, (unsigned int)(npages * 8),
+ dma_free_coherent(dev, (unsigned int)(npages * BA_BYTE_LEN),
mr->pbl_buf, mr->pbl_dma_addr);
return;
}
@@ -603,12 +600,13 @@ static void hns_roce_mhop_free(struct hns_roce_dev *hr_dev,
if (mhop_num == 2) {
for (i = 0; i < mr->l0_chunk_last_num; i++) {
if (i == mr->l0_chunk_last_num - 1) {
- npages_allocated = i * (pbl_bt_sz / 8);
+ npages_allocated =
+ i * (pbl_bt_sz / BA_BYTE_LEN);
dma_free_coherent(dev,
- (npages - npages_allocated) * 8,
- mr->pbl_bt_l1[i],
- mr->pbl_l1_dma_addr[i]);
+ (npages - npages_allocated) * BA_BYTE_LEN,
+ mr->pbl_bt_l1[i],
+ mr->pbl_l1_dma_addr[i]);
break;
}
@@ -621,16 +619,17 @@ static void hns_roce_mhop_free(struct hns_roce_dev *hr_dev,
dma_free_coherent(dev, pbl_bt_sz, mr->pbl_bt_l1[i],
mr->pbl_l1_dma_addr[i]);
- for (j = 0; j < pbl_bt_sz / 8; j++) {
- bt_idx = i * (pbl_bt_sz / 8) + j;
+ for (j = 0; j < pbl_bt_sz / BA_BYTE_LEN; j++) {
+ bt_idx = i * (pbl_bt_sz / BA_BYTE_LEN) + j;
if ((i == mr->l0_chunk_last_num - 1)
&& j == mr->l1_chunk_last_num - 1) {
npages_allocated = bt_idx *
- (pbl_bt_sz / 8);
+ (pbl_bt_sz / BA_BYTE_LEN);
dma_free_coherent(dev,
- (npages - npages_allocated) * 8,
+ (npages - npages_allocated) *
+ BA_BYTE_LEN,
mr->pbl_bt_l2[bt_idx],
mr->pbl_l2_dma_addr[bt_idx]);
@@ -675,7 +674,8 @@ static void hns_roce_mr_free(struct hns_roce_dev *hr_dev,
npages = ib_umem_page_count(mr->umem);
if (!hr_dev->caps.pbl_hop_num)
- dma_free_coherent(dev, (unsigned int)(npages * 8),
+ dma_free_coherent(dev,
+ (unsigned int)(npages * BA_BYTE_LEN),
mr->pbl_buf, mr->pbl_dma_addr);
else
hns_roce_mhop_free(hr_dev, mr);
@@ -1059,6 +1059,7 @@ static int hns_roce_ib_umem_write_mr(struct hns_roce_dev *hr_dev,
for_each_sg_dma_page(umem->sg_head.sgl, &sg_iter, umem->nmap, 0) {
page_addr = sg_page_iter_dma_address(&sg_iter);
if (!hr_dev->caps.pbl_hop_num) {
+ /* for hip06, page addr is aligned to 4K */
mr->pbl_buf[i++] = page_addr >> 12;
} else if (hr_dev->caps.pbl_hop_num == 1) {
mr->pbl_buf[i++] = page_addr;
@@ -1069,7 +1070,7 @@ static int hns_roce_ib_umem_write_mr(struct hns_roce_dev *hr_dev,
mr->pbl_bt_l2[i][j] = page_addr;
j++;
- if (j >= (pbl_bt_sz / 8)) {
+ if (j >= (pbl_bt_sz / BA_BYTE_LEN)) {
i++;
j = 0;
}
@@ -1117,7 +1118,8 @@ struct ib_mr *hns_roce_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
} else {
u64 pbl_size = 1;
- bt_size = (1 << (hr_dev->caps.pbl_ba_pg_sz + PAGE_SHIFT)) / 8;
+ bt_size = (1 << (hr_dev->caps.pbl_ba_pg_sz + PAGE_SHIFT)) /
+ BA_BYTE_LEN;
for (i = 0; i < hr_dev->caps.pbl_hop_num; i++)
pbl_size *= bt_size;
if (n > pbl_size) {
@@ -1293,9 +1295,7 @@ int hns_roce_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
} else {
hns_roce_mr_free(hr_dev, mr);
- if (mr->umem)
- ib_umem_release(mr->umem);
-
+ ib_umem_release(mr->umem);
kfree(mr);
}
@@ -1491,3 +1491,119 @@ int hns_roce_dealloc_mw(struct ib_mw *ibmw)
return 0;
}
+
+void hns_roce_mtr_init(struct hns_roce_mtr *mtr, int bt_pg_shift,
+ int buf_pg_shift)
+{
+ hns_roce_hem_list_init(&mtr->hem_list, bt_pg_shift);
+ mtr->buf_pg_shift = buf_pg_shift;
+}
+
+void hns_roce_mtr_cleanup(struct hns_roce_dev *hr_dev,
+ struct hns_roce_mtr *mtr)
+{
+ hns_roce_hem_list_release(hr_dev, &mtr->hem_list);
+}
+
+static int hns_roce_write_mtr(struct hns_roce_dev *hr_dev,
+ struct hns_roce_mtr *mtr, dma_addr_t *bufs,
+ struct hns_roce_buf_region *r)
+{
+ int offset;
+ int count;
+ int npage;
+ u64 *mtts;
+ int end;
+ int i;
+
+ offset = r->offset;
+ end = offset + r->count;
+ npage = 0;
+ while (offset < end) {
+ mtts = hns_roce_hem_list_find_mtt(hr_dev, &mtr->hem_list,
+ offset, &count, NULL);
+ if (!mtts)
+ return -ENOBUFS;
+
+ /* Save page addr, low 12 bits : 0 */
+ for (i = 0; i < count; i++) {
+ if (hr_dev->hw_rev == HNS_ROCE_HW_VER1)
+ mtts[i] = cpu_to_le64(bufs[npage] >>
+ PAGE_ADDR_SHIFT);
+ else
+ mtts[i] = cpu_to_le64(bufs[npage]);
+
+ npage++;
+ }
+ offset += count;
+ }
+
+ return 0;
+}
+
+int hns_roce_mtr_attach(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
+ dma_addr_t **bufs, struct hns_roce_buf_region *regions,
+ int region_cnt)
+{
+ struct hns_roce_buf_region *r;
+ int ret;
+ int i;
+
+ ret = hns_roce_hem_list_request(hr_dev, &mtr->hem_list, regions,
+ region_cnt);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < region_cnt; i++) {
+ r = &regions[i];
+ ret = hns_roce_write_mtr(hr_dev, mtr, bufs[i], r);
+ if (ret) {
+ dev_err(hr_dev->dev,
+ "write mtr[%d/%d] err %d,offset=%d.\n",
+ i, region_cnt, ret, r->offset);
+ goto err_write;
+ }
+ }
+
+ return 0;
+
+err_write:
+ hns_roce_hem_list_release(hr_dev, &mtr->hem_list);
+
+ return ret;
+}
+
+int hns_roce_mtr_find(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
+ int offset, u64 *mtt_buf, int mtt_max, u64 *base_addr)
+{
+ u64 *mtts = mtt_buf;
+ int mtt_count;
+ int total = 0;
+ u64 *addr;
+ int npage;
+ int left;
+
+ if (mtts == NULL || mtt_max < 1)
+ goto done;
+
+ left = mtt_max;
+ while (left > 0) {
+ mtt_count = 0;
+ addr = hns_roce_hem_list_find_mtt(hr_dev, &mtr->hem_list,
+ offset + total,
+ &mtt_count, NULL);
+ if (!addr || !mtt_count)
+ goto done;
+
+ npage = min(mtt_count, left);
+ memcpy(&mtts[total], addr, BA_BYTE_LEN * npage);
+ left -= npage;
+ total += npage;
+ }
+
+done:
+ if (base_addr)
+ *base_addr = mtr->hem_list.root_ba;
+
+ return total;
+}
diff --git a/drivers/infiniband/hw/hns/hns_roce_pd.c b/drivers/infiniband/hw/hns/hns_roce_pd.c
index 813401384d78..912b89b4da34 100644
--- a/drivers/infiniband/hw/hns/hns_roce_pd.c
+++ b/drivers/infiniband/hw/hns/hns_roce_pd.c
@@ -83,18 +83,16 @@ int hns_roce_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
return 0;
}
-EXPORT_SYMBOL_GPL(hns_roce_alloc_pd);
void hns_roce_dealloc_pd(struct ib_pd *pd, struct ib_udata *udata)
{
hns_roce_pd_free(to_hr_dev(pd->device), to_hr_pd(pd)->pdn);
}
-EXPORT_SYMBOL_GPL(hns_roce_dealloc_pd);
int hns_roce_uar_alloc(struct hns_roce_dev *hr_dev, struct hns_roce_uar *uar)
{
struct resource *res;
- int ret = 0;
+ int ret;
/* Using bitmap to manager UAR index */
ret = hns_roce_bitmap_alloc(&hr_dev->uar_table.bitmap, &uar->logic_idx);
diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c
index 8db2817a249e..e0424029b058 100644
--- a/drivers/infiniband/hw/hns/hns_roce_qp.c
+++ b/drivers/infiniband/hw/hns/hns_roce_qp.c
@@ -64,7 +64,6 @@ void hns_roce_qp_event(struct hns_roce_dev *hr_dev, u32 qpn, int event_type)
if (atomic_dec_and_test(&qp->refcount))
complete(&qp->free);
}
-EXPORT_SYMBOL_GPL(hns_roce_qp_event);
static void hns_roce_ib_qp_event(struct hns_roce_qp *hr_qp,
enum hns_roce_event type)
@@ -139,7 +138,6 @@ enum hns_roce_qp_state to_hns_roce_state(enum ib_qp_state state)
return HNS_ROCE_QP_NUM_STATE;
}
}
-EXPORT_SYMBOL_GPL(to_hns_roce_state);
static int hns_roce_gsi_qp_alloc(struct hns_roce_dev *hr_dev, unsigned long qpn,
struct hns_roce_qp *hr_qp)
@@ -242,7 +240,6 @@ void hns_roce_qp_remove(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp)
__xa_erase(xa, hr_qp->qpn & (hr_dev->caps.num_qps - 1));
xa_unlock_irqrestore(xa, flags);
}
-EXPORT_SYMBOL_GPL(hns_roce_qp_remove);
void hns_roce_qp_free(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp)
{
@@ -257,22 +254,19 @@ void hns_roce_qp_free(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp)
hns_roce_table_put(hr_dev, &qp_table->trrl_table,
hr_qp->qpn);
hns_roce_table_put(hr_dev, &qp_table->irrl_table, hr_qp->qpn);
- hns_roce_table_put(hr_dev, &qp_table->qp_table, hr_qp->qpn);
}
}
-EXPORT_SYMBOL_GPL(hns_roce_qp_free);
void hns_roce_release_range_qp(struct hns_roce_dev *hr_dev, int base_qpn,
int cnt)
{
struct hns_roce_qp_table *qp_table = &hr_dev->qp_table;
- if (base_qpn < SQP_NUM)
+ if (base_qpn < hr_dev->caps.reserved_qps)
return;
hns_roce_bitmap_free_range(&qp_table->bitmap, base_qpn, cnt, BITMAP_RR);
}
-EXPORT_SYMBOL_GPL(hns_roce_release_range_qp);
static int hns_roce_set_rq_size(struct hns_roce_dev *hr_dev,
struct ib_qp_cap *cap, bool is_user, int has_rq,
@@ -392,8 +386,8 @@ static int hns_roce_set_user_sq_size(struct hns_roce_dev *hr_dev,
hr_qp->sq.wqe_shift), PAGE_SIZE);
} else {
page_size = 1 << (hr_dev->caps.mtt_buf_pg_sz + PAGE_SHIFT);
- hr_qp->sge.sge_cnt =
- max(page_size / (1 << hr_qp->sge.sge_shift), ex_sge_num);
+ hr_qp->sge.sge_cnt = ex_sge_num ?
+ max(page_size / (1 << hr_qp->sge.sge_shift), ex_sge_num) : 0;
hr_qp->buff_size = HNS_ROCE_ALOGN_UP((hr_qp->rq.wqe_cnt <<
hr_qp->rq.wqe_shift), page_size) +
HNS_ROCE_ALOGN_UP((hr_qp->sge.sge_cnt <<
@@ -422,6 +416,91 @@ static int hns_roce_set_user_sq_size(struct hns_roce_dev *hr_dev,
return 0;
}
+static int split_wqe_buf_region(struct hns_roce_dev *hr_dev,
+ struct hns_roce_qp *hr_qp,
+ struct hns_roce_buf_region *regions,
+ int region_max, int page_shift)
+{
+ int page_size = 1 << page_shift;
+ bool is_extend_sge;
+ int region_cnt = 0;
+ int buf_size;
+ int buf_cnt;
+
+ if (hr_qp->buff_size < 1 || region_max < 1)
+ return region_cnt;
+
+ if (hr_qp->sge.sge_cnt > 0)
+ is_extend_sge = true;
+ else
+ is_extend_sge = false;
+
+ /* sq region */
+ if (is_extend_sge)
+ buf_size = hr_qp->sge.offset - hr_qp->sq.offset;
+ else
+ buf_size = hr_qp->rq.offset - hr_qp->sq.offset;
+
+ if (buf_size > 0 && region_cnt < region_max) {
+ buf_cnt = DIV_ROUND_UP(buf_size, page_size);
+ hns_roce_init_buf_region(&regions[region_cnt],
+ hr_dev->caps.wqe_sq_hop_num,
+ hr_qp->sq.offset / page_size,
+ buf_cnt);
+ region_cnt++;
+ }
+
+ /* sge region */
+ if (is_extend_sge) {
+ buf_size = hr_qp->rq.offset - hr_qp->sge.offset;
+ if (buf_size > 0 && region_cnt < region_max) {
+ buf_cnt = DIV_ROUND_UP(buf_size, page_size);
+ hns_roce_init_buf_region(&regions[region_cnt],
+ hr_dev->caps.wqe_sge_hop_num,
+ hr_qp->sge.offset / page_size,
+ buf_cnt);
+ region_cnt++;
+ }
+ }
+
+ /* rq region */
+ buf_size = hr_qp->buff_size - hr_qp->rq.offset;
+ if (buf_size > 0) {
+ buf_cnt = DIV_ROUND_UP(buf_size, page_size);
+ hns_roce_init_buf_region(&regions[region_cnt],
+ hr_dev->caps.wqe_rq_hop_num,
+ hr_qp->rq.offset / page_size,
+ buf_cnt);
+ region_cnt++;
+ }
+
+ return region_cnt;
+}
+
+static int calc_wqe_bt_page_shift(struct hns_roce_dev *hr_dev,
+ struct hns_roce_buf_region *regions,
+ int region_cnt)
+{
+ int bt_pg_shift;
+ int ba_num;
+ int ret;
+
+ bt_pg_shift = PAGE_SHIFT + hr_dev->caps.mtt_ba_pg_sz;
+
+ /* all root ba entries must in one bt page */
+ do {
+ ba_num = (1 << bt_pg_shift) / BA_BYTE_LEN;
+ ret = hns_roce_hem_list_calc_root_ba(regions, region_cnt,
+ ba_num);
+ if (ret <= ba_num)
+ break;
+
+ bt_pg_shift++;
+ } while (ret > ba_num);
+
+ return bt_pg_shift - PAGE_SHIFT;
+}
+
static int hns_roce_set_kernel_sq_size(struct hns_roce_dev *hr_dev,
struct ib_qp_cap *cap,
struct hns_roce_qp *hr_qp)
@@ -534,15 +613,17 @@ static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev,
struct ib_udata *udata, unsigned long sqpn,
struct hns_roce_qp *hr_qp)
{
+ dma_addr_t *buf_list[ARRAY_SIZE(hr_qp->regions)] = { 0 };
struct device *dev = hr_dev->dev;
struct hns_roce_ib_create_qp ucmd;
struct hns_roce_ib_create_qp_resp resp = {};
struct hns_roce_ucontext *uctx = rdma_udata_to_drv_context(
udata, struct hns_roce_ucontext, ibucontext);
+ struct hns_roce_buf_region *r;
unsigned long qpn = 0;
- int ret = 0;
u32 page_shift;
- u32 npages;
+ int buf_count;
+ int ret;
int i;
mutex_init(&hr_qp->mutex);
@@ -596,6 +677,7 @@ static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev,
init_attr->cap.max_recv_sge];
}
+ page_shift = PAGE_SHIFT + hr_dev->caps.mtt_buf_pg_sz;
if (udata) {
if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) {
dev_err(dev, "ib_copy_from_udata error for create qp\n");
@@ -617,32 +699,28 @@ static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev,
ret = PTR_ERR(hr_qp->umem);
goto err_rq_sge_list;
}
-
- hr_qp->mtt.mtt_type = MTT_TYPE_WQE;
- page_shift = PAGE_SHIFT;
- if (hr_dev->caps.mtt_buf_pg_sz) {
- npages = (ib_umem_page_count(hr_qp->umem) +
- (1 << hr_dev->caps.mtt_buf_pg_sz) - 1) /
- (1 << hr_dev->caps.mtt_buf_pg_sz);
- page_shift += hr_dev->caps.mtt_buf_pg_sz;
- ret = hns_roce_mtt_init(hr_dev, npages,
- page_shift,
- &hr_qp->mtt);
- } else {
- ret = hns_roce_mtt_init(hr_dev,
- ib_umem_page_count(hr_qp->umem),
- page_shift, &hr_qp->mtt);
- }
+ hr_qp->region_cnt = split_wqe_buf_region(hr_dev, hr_qp,
+ hr_qp->regions, ARRAY_SIZE(hr_qp->regions),
+ page_shift);
+ ret = hns_roce_alloc_buf_list(hr_qp->regions, buf_list,
+ hr_qp->region_cnt);
if (ret) {
- dev_err(dev, "hns_roce_mtt_init error for create qp\n");
- goto err_buf;
+ dev_err(dev, "alloc buf_list error for create qp\n");
+ goto err_alloc_list;
}
- ret = hns_roce_ib_umem_write_mtt(hr_dev, &hr_qp->mtt,
- hr_qp->umem);
- if (ret) {
- dev_err(dev, "hns_roce_ib_umem_write_mtt error for create qp\n");
- goto err_mtt;
+ for (i = 0; i < hr_qp->region_cnt; i++) {
+ r = &hr_qp->regions[i];
+ buf_count = hns_roce_get_umem_bufs(hr_dev,
+ buf_list[i], r->count, r->offset,
+ hr_qp->umem, page_shift);
+ if (buf_count != r->count) {
+ dev_err(dev,
+ "get umem buf err, expect %d,ret %d.\n",
+ r->count, buf_count);
+ ret = -ENOBUFS;
+ goto err_get_bufs;
+ }
}
if ((hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_SQ_RECORD_DB) &&
@@ -653,7 +731,7 @@ static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev,
&hr_qp->sdb);
if (ret) {
dev_err(dev, "sq record doorbell map failed!\n");
- goto err_mtt;
+ goto err_get_bufs;
}
/* indicate kernel supports sq record db */
@@ -715,7 +793,6 @@ static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev,
}
/* Allocate QP buf */
- page_shift = PAGE_SHIFT + hr_dev->caps.mtt_buf_pg_sz;
if (hns_roce_buf_alloc(hr_dev, hr_qp->buff_size,
(1 << page_shift) * 2,
&hr_qp->hr_buf, page_shift)) {
@@ -723,21 +800,28 @@ static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev,
ret = -ENOMEM;
goto err_db;
}
-
- hr_qp->mtt.mtt_type = MTT_TYPE_WQE;
- /* Write MTT */
- ret = hns_roce_mtt_init(hr_dev, hr_qp->hr_buf.npages,
- hr_qp->hr_buf.page_shift, &hr_qp->mtt);
+ hr_qp->region_cnt = split_wqe_buf_region(hr_dev, hr_qp,
+ hr_qp->regions, ARRAY_SIZE(hr_qp->regions),
+ page_shift);
+ ret = hns_roce_alloc_buf_list(hr_qp->regions, buf_list,
+ hr_qp->region_cnt);
if (ret) {
- dev_err(dev, "hns_roce_mtt_init error for kernel create qp\n");
- goto err_buf;
+ dev_err(dev, "alloc buf_list error for create qp!\n");
+ goto err_alloc_list;
}
- ret = hns_roce_buf_write_mtt(hr_dev, &hr_qp->mtt,
- &hr_qp->hr_buf);
- if (ret) {
- dev_err(dev, "hns_roce_buf_write_mtt error for kernel create qp\n");
- goto err_mtt;
+ for (i = 0; i < hr_qp->region_cnt; i++) {
+ r = &hr_qp->regions[i];
+ buf_count = hns_roce_get_kmem_bufs(hr_dev,
+ buf_list[i], r->count, r->offset,
+ &hr_qp->hr_buf);
+ if (buf_count != r->count) {
+ dev_err(dev,
+ "get kmem buf err, expect %d,ret %d.\n",
+ r->count, buf_count);
+ ret = -ENOBUFS;
+ goto err_get_bufs;
+ }
}
hr_qp->sq.wrid = kcalloc(hr_qp->sq.wqe_cnt, sizeof(u64),
@@ -761,6 +845,17 @@ static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev,
}
}
+ hr_qp->wqe_bt_pg_shift = calc_wqe_bt_page_shift(hr_dev, hr_qp->regions,
+ hr_qp->region_cnt);
+ hns_roce_mtr_init(&hr_qp->mtr, PAGE_SHIFT + hr_qp->wqe_bt_pg_shift,
+ page_shift);
+ ret = hns_roce_mtr_attach(hr_dev, &hr_qp->mtr, buf_list,
+ hr_qp->regions, hr_qp->region_cnt);
+ if (ret) {
+ dev_err(dev, "mtr attach error for create qp\n");
+ goto err_mtr;
+ }
+
if (init_attr->qp_type == IB_QPT_GSI &&
hr_dev->hw_rev == HNS_ROCE_HW_VER1) {
/* In v1 engine, GSI QP context in RoCE engine's register */
@@ -796,6 +891,7 @@ static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev,
}
hr_qp->event = hns_roce_ib_qp_event;
+ hns_roce_free_buf_list(buf_list, hr_qp->region_cnt);
return 0;
@@ -810,6 +906,9 @@ err_qpn:
if (!sqpn)
hns_roce_release_range_qp(hr_dev, qpn, 1);
+err_mtr:
+ hns_roce_mtr_cleanup(hr_dev, &hr_qp->mtr);
+
err_wrid:
if (udata) {
if ((hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RECORD_DB) &&
@@ -829,14 +928,13 @@ err_sq_dbmap:
hns_roce_qp_has_sq(init_attr))
hns_roce_db_unmap_user(uctx, &hr_qp->sdb);
-err_mtt:
- hns_roce_mtt_cleanup(hr_dev, &hr_qp->mtt);
+err_get_bufs:
+ hns_roce_free_buf_list(buf_list, hr_qp->region_cnt);
-err_buf:
- if (hr_qp->umem)
- ib_umem_release(hr_qp->umem);
- else
+err_alloc_list:
+ if (!hr_qp->umem)
hns_roce_buf_free(hr_dev, hr_qp->buff_size, &hr_qp->hr_buf);
+ ib_umem_release(hr_qp->umem);
err_db:
if (!udata && hns_roce_qp_has_rq(init_attr) &&
@@ -923,7 +1021,6 @@ struct ib_qp *hns_roce_create_qp(struct ib_pd *pd,
return &hr_qp->ibqp;
}
-EXPORT_SYMBOL_GPL(hns_roce_create_qp);
int to_hr_qp_type(int qp_type)
{
@@ -942,7 +1039,6 @@ int to_hr_qp_type(int qp_type)
return transport_type;
}
-EXPORT_SYMBOL_GPL(to_hr_qp_type);
int hns_roce_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
int attr_mask, struct ib_udata *udata)
@@ -1062,7 +1158,6 @@ void hns_roce_lock_cqs(struct hns_roce_cq *send_cq, struct hns_roce_cq *recv_cq)
spin_lock_nested(&send_cq->lock, SINGLE_DEPTH_NESTING);
}
}
-EXPORT_SYMBOL_GPL(hns_roce_lock_cqs);
void hns_roce_unlock_cqs(struct hns_roce_cq *send_cq,
struct hns_roce_cq *recv_cq) __releases(&send_cq->lock)
@@ -1079,7 +1174,6 @@ void hns_roce_unlock_cqs(struct hns_roce_cq *send_cq,
spin_unlock_irq(&recv_cq->lock);
}
}
-EXPORT_SYMBOL_GPL(hns_roce_unlock_cqs);
static void *get_wqe(struct hns_roce_qp *hr_qp, int offset)
{
@@ -1091,20 +1185,17 @@ void *get_recv_wqe(struct hns_roce_qp *hr_qp, int n)
{
return get_wqe(hr_qp, hr_qp->rq.offset + (n << hr_qp->rq.wqe_shift));
}
-EXPORT_SYMBOL_GPL(get_recv_wqe);
void *get_send_wqe(struct hns_roce_qp *hr_qp, int n)
{
return get_wqe(hr_qp, hr_qp->sq.offset + (n << hr_qp->sq.wqe_shift));
}
-EXPORT_SYMBOL_GPL(get_send_wqe);
void *get_send_extend_sge(struct hns_roce_qp *hr_qp, int n)
{
return hns_roce_buf_offset(&hr_qp->hr_buf, hr_qp->sge.offset +
(n << hr_qp->sge.sge_shift));
}
-EXPORT_SYMBOL_GPL(get_send_extend_sge);
bool hns_roce_wq_overflow(struct hns_roce_wq *hr_wq, int nreq,
struct ib_cq *ib_cq)
@@ -1123,7 +1214,6 @@ bool hns_roce_wq_overflow(struct hns_roce_wq *hr_wq, int nreq,
return cur + nreq >= hr_wq->max_post;
}
-EXPORT_SYMBOL_GPL(hns_roce_wq_overflow);
int hns_roce_init_qp_table(struct hns_roce_dev *hr_dev)
{
@@ -1135,11 +1225,7 @@ int hns_roce_init_qp_table(struct hns_roce_dev *hr_dev)
mutex_init(&qp_table->scc_mutex);
xa_init(&hr_dev->qp_table_xa);
- /* In hw v1, a port include two SQP, six ports total 12 */
- if (hr_dev->caps.max_sq_sg <= 2)
- reserved_from_bot = SQP_NUM;
- else
- reserved_from_bot = hr_dev->caps.reserved_qps;
+ reserved_from_bot = hr_dev->caps.reserved_qps;
ret = hns_roce_bitmap_init(&qp_table->bitmap, hr_dev->caps.num_qps,
hr_dev->caps.num_qps - 1, reserved_from_bot,
diff --git a/drivers/infiniband/hw/hns/hns_roce_srq.c b/drivers/infiniband/hw/hns/hns_roce_srq.c
index b3421b1f21e0..38bb548eaa6d 100644
--- a/drivers/infiniband/hw/hns/hns_roce_srq.c
+++ b/drivers/infiniband/hw/hns/hns_roce_srq.c
@@ -30,7 +30,6 @@ void hns_roce_srq_event(struct hns_roce_dev *hr_dev, u32 srqn, int event_type)
if (atomic_dec_and_test(&srq->refcount))
complete(&srq->free);
}
-EXPORT_SYMBOL_GPL(hns_roce_srq_event);
static void hns_roce_ib_srq_event(struct hns_roce_srq *srq,
enum hns_roce_event event_type)
@@ -181,28 +180,19 @@ static int hns_roce_create_idx_que(struct ib_pd *pd, struct hns_roce_srq *srq,
{
struct hns_roce_dev *hr_dev = to_hr_dev(pd->device);
struct hns_roce_idx_que *idx_que = &srq->idx_que;
- u32 bitmap_num;
- int i;
- bitmap_num = HNS_ROCE_ALOGN_UP(srq->max, 8 * sizeof(u64));
-
- idx_que->bitmap = kcalloc(1, bitmap_num / 8, GFP_KERNEL);
+ idx_que->bitmap = bitmap_zalloc(srq->max, GFP_KERNEL);
if (!idx_que->bitmap)
return -ENOMEM;
- bitmap_num = bitmap_num / (8 * sizeof(u64));
-
idx_que->buf_size = srq->idx_que.buf_size;
if (hns_roce_buf_alloc(hr_dev, idx_que->buf_size, (1 << page_shift) * 2,
&idx_que->idx_buf, page_shift)) {
- kfree(idx_que->bitmap);
+ bitmap_free(idx_que->bitmap);
return -ENOMEM;
}
- for (i = 0; i < bitmap_num; i++)
- idx_que->bitmap[i] = ~(0UL);
-
return 0;
}
@@ -264,8 +254,7 @@ int hns_roce_create_srq(struct ib_srq *ib_srq,
} else
ret = hns_roce_mtt_init(hr_dev,
ib_umem_page_count(srq->umem),
- srq->umem->page_shift,
- &srq->mtt);
+ PAGE_SHIFT, &srq->mtt);
if (ret)
goto err_buf;
@@ -291,10 +280,9 @@ int hns_roce_create_srq(struct ib_srq *ib_srq,
ret = hns_roce_mtt_init(hr_dev, npages,
page_shift, &srq->idx_que.mtt);
} else {
- ret = hns_roce_mtt_init(hr_dev,
- ib_umem_page_count(srq->idx_que.umem),
- srq->idx_que.umem->page_shift,
- &srq->idx_que.mtt);
+ ret = hns_roce_mtt_init(
+ hr_dev, ib_umem_page_count(srq->idx_que.umem),
+ PAGE_SHIFT, &srq->idx_que.mtt);
}
if (ret) {
@@ -391,21 +379,19 @@ err_idx_buf:
hns_roce_mtt_cleanup(hr_dev, &srq->idx_que.mtt);
err_idx_mtt:
- if (udata)
- ib_umem_release(srq->idx_que.umem);
+ ib_umem_release(srq->idx_que.umem);
err_create_idx:
hns_roce_buf_free(hr_dev, srq->idx_que.buf_size,
&srq->idx_que.idx_buf);
- kfree(srq->idx_que.bitmap);
+ bitmap_free(srq->idx_que.bitmap);
err_srq_mtt:
hns_roce_mtt_cleanup(hr_dev, &srq->mtt);
err_buf:
- if (udata)
- ib_umem_release(srq->umem);
- else
+ ib_umem_release(srq->umem);
+ if (!udata)
hns_roce_buf_free(hr_dev, srq_buf_size, &srq->buf);
return ret;
@@ -419,15 +405,15 @@ void hns_roce_destroy_srq(struct ib_srq *ibsrq, struct ib_udata *udata)
hns_roce_srq_free(hr_dev, srq);
hns_roce_mtt_cleanup(hr_dev, &srq->mtt);
- if (ibsrq->uobject) {
+ if (udata) {
hns_roce_mtt_cleanup(hr_dev, &srq->idx_que.mtt);
- ib_umem_release(srq->idx_que.umem);
- ib_umem_release(srq->umem);
} else {
kvfree(srq->wrid);
hns_roce_buf_free(hr_dev, srq->max << srq->wqe_shift,
&srq->buf);
}
+ ib_umem_release(srq->idx_que.umem);
+ ib_umem_release(srq->umem);
}
int hns_roce_init_srq_table(struct hns_roce_dev *hr_dev)
diff --git a/drivers/infiniband/hw/i40iw/i40iw_cm.c b/drivers/infiniband/hw/i40iw/i40iw_cm.c
index 8233f5a4e623..2d6a378e8560 100644
--- a/drivers/infiniband/hw/i40iw/i40iw_cm.c
+++ b/drivers/infiniband/hw/i40iw/i40iw_cm.c
@@ -1773,8 +1773,11 @@ static enum i40iw_status_code i40iw_add_mqh_4(
if ((((rdma_vlan_dev_vlan_id(dev) < I40IW_NO_VLAN) &&
(rdma_vlan_dev_real_dev(dev) == iwdev->netdev)) ||
(dev == iwdev->netdev)) && (dev->flags & IFF_UP)) {
+ const struct in_ifaddr *ifa;
+
idev = in_dev_get(dev);
- for_ifa(idev) {
+
+ in_dev_for_each_ifa_rtnl(ifa, idev) {
i40iw_debug(&iwdev->sc_dev,
I40IW_DEBUG_CM,
"Allocating child CM Listener forIP=%pI4, vlan_id=%d, MAC=%pM\n",
@@ -1819,7 +1822,7 @@ static enum i40iw_status_code i40iw_add_mqh_4(
cm_parent_listen_node->cm_core->stats_listen_nodes_created--;
}
}
- endfor_ifa(idev);
+
in_dev_put(idev);
}
}
@@ -4276,11 +4279,11 @@ static void i40iw_qhash_ctrl(struct i40iw_device *iwdev,
/* if not found then add a child listener if interface is going up */
if (!ifup)
return;
- child_listen_node = kzalloc(sizeof(*child_listen_node), GFP_ATOMIC);
+ child_listen_node = kmemdup(parent_listen_node,
+ sizeof(*child_listen_node), GFP_ATOMIC);
if (!child_listen_node)
return;
node_allocated = true;
- memcpy(child_listen_node, parent_listen_node, sizeof(*child_listen_node));
memcpy(child_listen_node->loc_addr, ipaddr, ipv4 ? 4 : 16);
diff --git a/drivers/infiniband/hw/i40iw/i40iw_main.c b/drivers/infiniband/hw/i40iw/i40iw_main.c
index 10932baee279..d44cf33df81a 100644
--- a/drivers/infiniband/hw/i40iw/i40iw_main.c
+++ b/drivers/infiniband/hw/i40iw/i40iw_main.c
@@ -1222,8 +1222,10 @@ static void i40iw_add_ipv4_addr(struct i40iw_device *iwdev)
if ((((rdma_vlan_dev_vlan_id(dev) < 0xFFFF) &&
(rdma_vlan_dev_real_dev(dev) == iwdev->netdev)) ||
(dev == iwdev->netdev)) && (dev->flags & IFF_UP)) {
+ const struct in_ifaddr *ifa;
+
idev = in_dev_get(dev);
- for_ifa(idev) {
+ in_dev_for_each_ifa_rtnl(ifa, idev) {
i40iw_debug(&iwdev->sc_dev, I40IW_DEBUG_CM,
"IP=%pI4, vlan_id=%d, MAC=%pM\n", &ifa->ifa_address,
rdma_vlan_dev_vlan_id(dev), dev->dev_addr);
@@ -1235,7 +1237,7 @@ static void i40iw_add_ipv4_addr(struct i40iw_device *iwdev)
true,
I40IW_ARP_ADD);
}
- endfor_ifa(idev);
+
in_dev_put(idev);
}
}
diff --git a/drivers/infiniband/hw/i40iw/i40iw_utils.c b/drivers/infiniband/hw/i40iw/i40iw_utils.c
index 337410f40860..016524683e17 100644
--- a/drivers/infiniband/hw/i40iw/i40iw_utils.c
+++ b/drivers/infiniband/hw/i40iw/i40iw_utils.c
@@ -174,10 +174,14 @@ int i40iw_inetaddr_event(struct notifier_block *notifier,
rcu_read_lock();
in = __in_dev_get_rcu(upper_dev);
- if (!in->ifa_list)
- local_ipaddr = 0;
- else
- local_ipaddr = ntohl(in->ifa_list->ifa_address);
+ local_ipaddr = 0;
+ if (in) {
+ struct in_ifaddr *ifa;
+
+ ifa = rcu_dereference(in->ifa_list);
+ if (ifa)
+ local_ipaddr = ntohl(ifa->ifa_address);
+ }
rcu_read_unlock();
} else {
diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c
index 5689d742bafb..d169a8031375 100644
--- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c
+++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c
@@ -772,6 +772,8 @@ static int i40iw_query_qp(struct ib_qp *ibqp,
struct i40iw_qp *iwqp = to_iwqp(ibqp);
struct i40iw_sc_qp *qp = &iwqp->sc_qp;
+ attr->qp_state = iwqp->ibqp_state;
+ attr->cur_qp_state = attr->qp_state;
attr->qp_access_flags = 0;
attr->cap.max_send_wr = qp->qp_uk.sq_size;
attr->cap.max_recv_wr = qp->qp_uk.rq_size;
@@ -1064,44 +1066,38 @@ void i40iw_cq_wq_destroy(struct i40iw_device *iwdev, struct i40iw_sc_cq *cq)
* @ib_cq: cq pointer
* @udata: user data or NULL for kernel object
*/
-static int i40iw_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)
+static void i40iw_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)
{
struct i40iw_cq *iwcq;
struct i40iw_device *iwdev;
struct i40iw_sc_cq *cq;
- if (!ib_cq) {
- i40iw_pr_err("ib_cq == NULL\n");
- return 0;
- }
-
iwcq = to_iwcq(ib_cq);
iwdev = to_iwdev(ib_cq->device);
cq = &iwcq->sc_cq;
i40iw_cq_wq_destroy(iwdev, cq);
cq_free_resources(iwdev, iwcq);
- kfree(iwcq);
i40iw_rem_devusecount(iwdev);
- return 0;
}
/**
* i40iw_create_cq - create cq
- * @ibdev: device pointer from stack
+ * @ibcq: CQ allocated
* @attr: attributes for cq
* @udata: user data
*/
-static struct ib_cq *i40iw_create_cq(struct ib_device *ibdev,
- const struct ib_cq_init_attr *attr,
- struct ib_udata *udata)
+static int i40iw_create_cq(struct ib_cq *ibcq,
+ const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata)
{
+ struct ib_device *ibdev = ibcq->device;
struct i40iw_device *iwdev = to_iwdev(ibdev);
- struct i40iw_cq *iwcq;
+ struct i40iw_cq *iwcq = to_iwcq(ibcq);
struct i40iw_pbl *iwpbl;
u32 cq_num = 0;
struct i40iw_sc_cq *cq;
struct i40iw_sc_dev *dev = &iwdev->sc_dev;
- struct i40iw_cq_init_info info;
+ struct i40iw_cq_init_info info = {};
enum i40iw_status_code status;
struct i40iw_cqp_request *cqp_request;
struct cqp_commands_info *cqp_info;
@@ -1111,22 +1107,16 @@ static struct ib_cq *i40iw_create_cq(struct ib_device *ibdev,
int entries = attr->cqe;
if (iwdev->closing)
- return ERR_PTR(-ENODEV);
+ return -ENODEV;
if (entries > iwdev->max_cqe)
- return ERR_PTR(-EINVAL);
-
- iwcq = kzalloc(sizeof(*iwcq), GFP_KERNEL);
- if (!iwcq)
- return ERR_PTR(-ENOMEM);
-
- memset(&info, 0, sizeof(info));
+ return -EINVAL;
err_code = i40iw_alloc_resource(iwdev, iwdev->allocated_cqs,
iwdev->max_cq, &cq_num,
&iwdev->next_cq);
if (err_code)
- goto error;
+ return err_code;
cq = &iwcq->sc_cq;
cq->back_cq = (void *)iwcq;
@@ -1233,15 +1223,13 @@ static struct ib_cq *i40iw_create_cq(struct ib_device *ibdev,
}
i40iw_add_devusecount(iwdev);
- return (struct ib_cq *)iwcq;
+ return 0;
cq_destroy:
i40iw_cq_wq_destroy(iwdev, cq);
cq_free_resources:
cq_free_resources(iwdev, iwcq);
-error:
- kfree(iwcq);
- return ERR_PTR(err_code);
+ return err_code;
}
/**
@@ -2018,8 +2006,7 @@ static int i40iw_dereg_mr(struct ib_mr *ib_mr, struct ib_udata *udata)
struct cqp_commands_info *cqp_info;
u32 stag_idx;
- if (iwmr->region)
- ib_umem_release(iwmr->region);
+ ib_umem_release(iwmr->region);
if (iwmr->type != IW_MEMREG_TYPE_MEM) {
/* region is released. only test for userness. */
@@ -2655,6 +2642,11 @@ static int i40iw_query_pkey(struct ib_device *ibdev,
}
static const struct ib_device_ops i40iw_dev_ops = {
+ .owner = THIS_MODULE,
+ .driver_id = RDMA_DRIVER_I40IW,
+ /* NOTE: Older kernels wrongly use 0 for the uverbs_abi_ver */
+ .uverbs_abi_ver = I40IW_ABI_VER,
+
.alloc_hw_stats = i40iw_alloc_hw_stats,
.alloc_mr = i40iw_alloc_mr,
.alloc_pd = i40iw_alloc_pd,
@@ -2694,6 +2686,7 @@ static const struct ib_device_ops i40iw_dev_ops = {
.reg_user_mr = i40iw_reg_user_mr,
.req_notify_cq = i40iw_req_notify_cq,
INIT_RDMA_OBJ_SIZE(ib_pd, i40iw_pd, ibpd),
+ INIT_RDMA_OBJ_SIZE(ib_cq, i40iw_cq, ibcq),
INIT_RDMA_OBJ_SIZE(ib_ucontext, i40iw_ucontext, ibucontext),
};
@@ -2712,7 +2705,6 @@ static struct i40iw_ib_device *i40iw_init_rdma_device(struct i40iw_device *iwdev
i40iw_pr_err("iwdev == NULL\n");
return NULL;
}
- iwibdev->ibdev.owner = THIS_MODULE;
iwdev->iwibdev = iwibdev;
iwibdev->iwdev = iwdev;
@@ -2771,9 +2763,6 @@ void i40iw_port_ibevent(struct i40iw_device *iwdev)
*/
void i40iw_destroy_rdma_device(struct i40iw_ib_device *iwibdev)
{
- if (!iwibdev)
- return;
-
ib_unregister_device(&iwibdev->ibdev);
wait_event_timeout(iwibdev->iwdev->close_wq,
!atomic64_read(&iwibdev->iwdev->use_count),
@@ -2795,7 +2784,6 @@ int i40iw_register_rdma_device(struct i40iw_device *iwdev)
return -ENOMEM;
iwibdev = iwdev->iwibdev;
rdma_set_device_sysfs_group(&iwibdev->ibdev, &i40iw_attr_group);
- iwibdev->ibdev.driver_id = RDMA_DRIVER_I40IW;
ret = ib_register_device(&iwibdev->ibdev, "i40iw%d");
if (ret)
goto error;
diff --git a/drivers/infiniband/hw/mlx4/alias_GUID.c b/drivers/infiniband/hw/mlx4/alias_GUID.c
index 2a0b59a4b6eb..cca414ecfcd5 100644
--- a/drivers/infiniband/hw/mlx4/alias_GUID.c
+++ b/drivers/infiniband/hw/mlx4/alias_GUID.c
@@ -310,7 +310,7 @@ static void aliasguid_query_handler(int status,
if (status) {
pr_debug("(port: %d) failed: status = %d\n",
cb_ctx->port, status);
- rec->time_to_run = ktime_get_boot_ns() + 1 * NSEC_PER_SEC;
+ rec->time_to_run = ktime_get_boottime_ns() + 1 * NSEC_PER_SEC;
goto out;
}
@@ -416,7 +416,7 @@ next_entry:
be64_to_cpu((__force __be64)rec->guid_indexes),
be64_to_cpu((__force __be64)applied_guid_indexes),
be64_to_cpu((__force __be64)declined_guid_indexes));
- rec->time_to_run = ktime_get_boot_ns() +
+ rec->time_to_run = ktime_get_boottime_ns() +
resched_delay_sec * NSEC_PER_SEC;
} else {
rec->status = MLX4_GUID_INFO_STATUS_SET;
@@ -709,7 +709,7 @@ static int get_low_record_time_index(struct mlx4_ib_dev *dev, u8 port,
}
}
if (resched_delay_sec) {
- u64 curr_time = ktime_get_boot_ns();
+ u64 curr_time = ktime_get_boottime_ns();
*resched_delay_sec = (low_record_time < curr_time) ? 0 :
div_u64((low_record_time - curr_time), NSEC_PER_SEC);
diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c
index 022a0b4ea452..a7d238d312f0 100644
--- a/drivers/infiniband/hw/mlx4/cq.c
+++ b/drivers/infiniband/hw/mlx4/cq.c
@@ -172,14 +172,14 @@ err_buf:
}
#define CQ_CREATE_FLAGS_SUPPORTED IB_UVERBS_CQ_FLAGS_TIMESTAMP_COMPLETION
-struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev,
- const struct ib_cq_init_attr *attr,
- struct ib_udata *udata)
+int mlx4_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata)
{
+ struct ib_device *ibdev = ibcq->device;
int entries = attr->cqe;
int vector = attr->comp_vector;
struct mlx4_ib_dev *dev = to_mdev(ibdev);
- struct mlx4_ib_cq *cq;
+ struct mlx4_ib_cq *cq = to_mcq(ibcq);
struct mlx4_uar *uar;
void *buf_addr;
int err;
@@ -187,14 +187,10 @@ struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev,
udata, struct mlx4_ib_ucontext, ibucontext);
if (entries < 1 || entries > dev->dev->caps.max_cqes)
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
if (attr->flags & ~CQ_CREATE_FLAGS_SUPPORTED)
- return ERR_PTR(-EINVAL);
-
- cq = kzalloc(sizeof(*cq), GFP_KERNEL);
- if (!cq)
- return ERR_PTR(-ENOMEM);
+ return -EINVAL;
entries = roundup_pow_of_two(entries + 1);
cq->ibcq.cqe = entries - 1;
@@ -269,7 +265,7 @@ struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev,
goto err_cq_free;
}
- return &cq->ibcq;
+ return 0;
err_cq_free:
mlx4_cq_free(dev->dev, &cq->mcq);
@@ -281,19 +277,15 @@ err_dbmap:
err_mtt:
mlx4_mtt_cleanup(dev->dev, &cq->buf.mtt);
- if (udata)
- ib_umem_release(cq->umem);
- else
+ ib_umem_release(cq->umem);
+ if (!udata)
mlx4_ib_free_cq_buf(dev, &cq->buf, cq->ibcq.cqe);
err_db:
if (!udata)
mlx4_db_free(dev->dev, &cq->db);
-
err_cq:
- kfree(cq);
-
- return ERR_PTR(err);
+ return err;
}
static int mlx4_alloc_resize_buf(struct mlx4_ib_dev *dev, struct mlx4_ib_cq *cq,
@@ -475,18 +467,15 @@ err_buf:
kfree(cq->resize_buf);
cq->resize_buf = NULL;
- if (cq->resize_umem) {
- ib_umem_release(cq->resize_umem);
- cq->resize_umem = NULL;
- }
-
+ ib_umem_release(cq->resize_umem);
+ cq->resize_umem = NULL;
out:
mutex_unlock(&cq->resize_mutex);
return err;
}
-int mlx4_ib_destroy_cq(struct ib_cq *cq, struct ib_udata *udata)
+void mlx4_ib_destroy_cq(struct ib_cq *cq, struct ib_udata *udata)
{
struct mlx4_ib_dev *dev = to_mdev(cq->device);
struct mlx4_ib_cq *mcq = to_mcq(cq);
@@ -501,15 +490,11 @@ int mlx4_ib_destroy_cq(struct ib_cq *cq, struct ib_udata *udata)
struct mlx4_ib_ucontext,
ibucontext),
&mcq->db);
- ib_umem_release(mcq->umem);
} else {
mlx4_ib_free_cq_buf(dev, &mcq->buf, cq->cqe);
mlx4_db_free(dev->dev, &mcq->db);
}
-
- kfree(mcq);
-
- return 0;
+ ib_umem_release(mcq->umem);
}
static void dump_cqe(void *cqe)
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index 25d09d53b51c..8790101facb7 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -1089,7 +1089,8 @@ static int mlx4_ib_alloc_ucontext(struct ib_ucontext *uctx,
if (!dev->ib_active)
return -EAGAIN;
- if (ibdev->uverbs_abi_ver == MLX4_IB_UVERBS_NO_DEV_CAPS_ABI_VERSION) {
+ if (ibdev->ops.uverbs_abi_ver ==
+ MLX4_IB_UVERBS_NO_DEV_CAPS_ABI_VERSION) {
resp_v3.qp_tab_size = dev->dev->caps.num_qps;
resp_v3.bf_reg_size = dev->dev->caps.bf_reg_size;
resp_v3.bf_regs_per_page = dev->dev->caps.bf_regs_per_page;
@@ -1111,7 +1112,7 @@ static int mlx4_ib_alloc_ucontext(struct ib_ucontext *uctx,
INIT_LIST_HEAD(&context->wqn_ranges_list);
mutex_init(&context->wqn_ranges_mutex);
- if (ibdev->uverbs_abi_ver == MLX4_IB_UVERBS_NO_DEV_CAPS_ABI_VERSION)
+ if (ibdev->ops.uverbs_abi_ver == MLX4_IB_UVERBS_NO_DEV_CAPS_ABI_VERSION)
err = ib_copy_to_udata(udata, &resp_v3, sizeof(resp_v3));
else
err = ib_copy_to_udata(udata, &resp, sizeof(resp));
@@ -2509,6 +2510,10 @@ static void get_fw_ver_str(struct ib_device *device, char *str)
}
static const struct ib_device_ops mlx4_ib_dev_ops = {
+ .owner = THIS_MODULE,
+ .driver_id = RDMA_DRIVER_MLX4,
+ .uverbs_abi_ver = MLX4_IB_UVERBS_ABI_VERSION,
+
.add_gid = mlx4_ib_add_gid,
.alloc_mr = mlx4_ib_alloc_mr,
.alloc_pd = mlx4_ib_alloc_pd,
@@ -2560,6 +2565,7 @@ static const struct ib_device_ops mlx4_ib_dev_ops = {
.resize_cq = mlx4_ib_resize_cq,
INIT_RDMA_OBJ_SIZE(ib_ah, mlx4_ib_ah, ibah),
+ INIT_RDMA_OBJ_SIZE(ib_cq, mlx4_ib_cq, ibcq),
INIT_RDMA_OBJ_SIZE(ib_pd, mlx4_ib_pd, ibpd),
INIT_RDMA_OBJ_SIZE(ib_srq, mlx4_ib_srq, ibsrq),
INIT_RDMA_OBJ_SIZE(ib_ucontext, mlx4_ib_ucontext, ibucontext),
@@ -2642,7 +2648,6 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
ibdev->dev = dev;
ibdev->bond_next_port = 0;
- ibdev->ib_dev.owner = THIS_MODULE;
ibdev->ib_dev.node_type = RDMA_NODE_IB_CA;
ibdev->ib_dev.local_dma_lkey = dev->caps.reserved_lkey;
ibdev->num_ports = num_ports;
@@ -2651,11 +2656,6 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
ibdev->ib_dev.num_comp_vectors = dev->caps.num_comp_vectors;
ibdev->ib_dev.dev.parent = &dev->persist->pdev->dev;
- if (dev->caps.userspace_caps)
- ibdev->ib_dev.uverbs_abi_ver = MLX4_IB_UVERBS_ABI_VERSION;
- else
- ibdev->ib_dev.uverbs_abi_ver = MLX4_IB_UVERBS_NO_DEV_CAPS_ABI_VERSION;
-
ibdev->ib_dev.uverbs_cmd_mask =
(1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
(1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |
@@ -2729,6 +2729,10 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
ib_set_device_ops(&ibdev->ib_dev, &mlx4_ib_dev_fs_ops);
}
+ if (!dev->caps.userspace_caps)
+ ibdev->ib_dev.ops.uverbs_abi_ver =
+ MLX4_IB_UVERBS_NO_DEV_CAPS_ABI_VERSION;
+
mlx4_ib_alloc_eqs(dev, ibdev);
spin_lock_init(&iboe->lock);
@@ -2839,7 +2843,6 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
goto err_steer_free_bitmap;
rdma_set_device_sysfs_group(&ibdev->ib_dev, &mlx4_attr_group);
- ibdev->ib_dev.driver_id = RDMA_DRIVER_MLX4;
if (ib_register_device(&ibdev->ib_dev, "mlx4_%d"))
goto err_diag_counters;
diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h
index 26897102057d..eb53bb4c0c91 100644
--- a/drivers/infiniband/hw/mlx4/mlx4_ib.h
+++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h
@@ -743,10 +743,9 @@ int mlx4_ib_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents,
unsigned int *sg_offset);
int mlx4_ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period);
int mlx4_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata);
-struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev,
- const struct ib_cq_init_attr *attr,
- struct ib_udata *udata);
-int mlx4_ib_destroy_cq(struct ib_cq *cq, struct ib_udata *udata);
+int mlx4_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata);
+void mlx4_ib_destroy_cq(struct ib_cq *cq, struct ib_udata *udata);
int mlx4_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc);
int mlx4_ib_arm_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags);
void __mlx4_ib_cq_clean(struct mlx4_ib_cq *cq, u32 qpn, struct mlx4_ib_srq *srq);
@@ -907,7 +906,7 @@ void mlx4_ib_sl2vl_update(struct mlx4_ib_dev *mdev, int port);
struct ib_wq *mlx4_ib_create_wq(struct ib_pd *pd,
struct ib_wq_init_attr *init_attr,
struct ib_udata *udata);
-int mlx4_ib_destroy_wq(struct ib_wq *wq, struct ib_udata *udata);
+void mlx4_ib_destroy_wq(struct ib_wq *wq, struct ib_udata *udata);
int mlx4_ib_modify_wq(struct ib_wq *wq, struct ib_wq_attr *wq_attr,
u32 wq_attr_mask, struct ib_udata *udata);
diff --git a/drivers/infiniband/hw/mlx4/mr.c b/drivers/infiniband/hw/mlx4/mr.c
index 355205a28544..753479285ce9 100644
--- a/drivers/infiniband/hw/mlx4/mr.c
+++ b/drivers/infiniband/hw/mlx4/mr.c
@@ -258,7 +258,7 @@ int mlx4_ib_umem_calc_optimal_mtt_size(struct ib_umem *umem, u64 start_va,
int *num_of_mtts)
{
u64 block_shift = MLX4_MAX_MTT_SHIFT;
- u64 min_shift = umem->page_shift;
+ u64 min_shift = PAGE_SHIFT;
u64 last_block_aligned_end = 0;
u64 current_block_start = 0;
u64 first_block_start = 0;
@@ -295,8 +295,8 @@ int mlx4_ib_umem_calc_optimal_mtt_size(struct ib_umem *umem, u64 start_va,
* in access to the wrong data.
*/
misalignment_bits =
- (start_va & (~(((u64)(BIT(umem->page_shift))) - 1ULL)))
- ^ current_block_start;
+ (start_va & (~(((u64)(PAGE_SIZE)) - 1ULL))) ^
+ current_block_start;
block_shift = min(alignment_of(misalignment_bits),
block_shift);
}
@@ -368,8 +368,7 @@ end:
}
static struct ib_umem *mlx4_get_umem_mr(struct ib_udata *udata, u64 start,
- u64 length, u64 virt_addr,
- int access_flags)
+ u64 length, int access_flags)
{
/*
* Force registering the memory as writable if the underlying pages
@@ -415,8 +414,7 @@ struct ib_mr *mlx4_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
if (!mr)
return ERR_PTR(-ENOMEM);
- mr->umem =
- mlx4_get_umem_mr(udata, start, length, virt_addr, access_flags);
+ mr->umem = mlx4_get_umem_mr(udata, start, length, access_flags);
if (IS_ERR(mr->umem)) {
err = PTR_ERR(mr->umem);
goto err_free;
@@ -505,7 +503,7 @@ int mlx4_ib_rereg_user_mr(struct ib_mr *mr, int flags,
mlx4_mr_rereg_mem_cleanup(dev->dev, &mmr->mmr);
ib_umem_release(mmr->umem);
- mmr->umem = mlx4_get_umem_mr(udata, start, length, virt_addr,
+ mmr->umem = mlx4_get_umem_mr(udata, start, length,
mr_access_flags);
if (IS_ERR(mmr->umem)) {
err = PTR_ERR(mmr->umem);
@@ -514,7 +512,7 @@ int mlx4_ib_rereg_user_mr(struct ib_mr *mr, int flags,
goto release_mpt_entry;
}
n = ib_umem_page_count(mmr->umem);
- shift = mmr->umem->page_shift;
+ shift = PAGE_SHIFT;
err = mlx4_mr_rereg_mem_write(dev->dev, &mmr->mmr,
virt_addr, length, n, shift,
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index 5221c0794d1d..82aff2f2fdc2 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -1207,10 +1207,9 @@ err_mtt:
mlx4_mtt_cleanup(dev->dev, &qp->mtt);
err_buf:
- if (qp->umem)
- ib_umem_release(qp->umem);
- else
+ if (!qp->umem)
mlx4_buf_free(dev->dev, qp->buf_size, &qp->buf);
+ ib_umem_release(qp->umem);
err_db:
if (!udata && qp_has_rq(init_attr))
@@ -1421,7 +1420,6 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp,
mlx4_ib_db_unmap_user(mcontext, &qp->db);
}
- ib_umem_release(qp->umem);
} else {
kvfree(qp->sq.wrid);
kvfree(qp->rq.wrid);
@@ -1432,6 +1430,7 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp,
if (qp->rq.wqe_cnt)
mlx4_db_free(dev->dev, &qp->db);
}
+ ib_umem_release(qp->umem);
del_gid_entries(qp);
}
@@ -4248,7 +4247,7 @@ int mlx4_ib_modify_wq(struct ib_wq *ibwq, struct ib_wq_attr *wq_attr,
return err;
}
-int mlx4_ib_destroy_wq(struct ib_wq *ibwq, struct ib_udata *udata)
+void mlx4_ib_destroy_wq(struct ib_wq *ibwq, struct ib_udata *udata)
{
struct mlx4_ib_dev *dev = to_mdev(ibwq->device);
struct mlx4_ib_qp *qp = to_mqp((struct ib_qp *)ibwq);
@@ -4259,8 +4258,6 @@ int mlx4_ib_destroy_wq(struct ib_wq *ibwq, struct ib_udata *udata)
destroy_qp_common(dev, qp, MLX4_IB_RWQ_SRC, udata);
kfree(qp);
-
- return 0;
}
struct ib_rwq_ind_table
diff --git a/drivers/infiniband/hw/mlx4/srq.c b/drivers/infiniband/hw/mlx4/srq.c
index 4bf2946b9759..848db7264cc9 100644
--- a/drivers/infiniband/hw/mlx4/srq.c
+++ b/drivers/infiniband/hw/mlx4/srq.c
@@ -115,7 +115,7 @@ int mlx4_ib_create_srq(struct ib_srq *ib_srq,
return PTR_ERR(srq->umem);
err = mlx4_mtt_init(dev->dev, ib_umem_page_count(srq->umem),
- srq->umem->page_shift, &srq->mtt);
+ PAGE_SHIFT, &srq->mtt);
if (err)
goto err_buf;
@@ -204,10 +204,9 @@ err_mtt:
mlx4_mtt_cleanup(dev->dev, &srq->mtt);
err_buf:
- if (srq->umem)
- ib_umem_release(srq->umem);
- else
+ if (!srq->umem)
mlx4_buf_free(dev->dev, buf_size, &srq->buf);
+ ib_umem_release(srq->umem);
err_db:
if (!udata)
@@ -275,13 +274,13 @@ void mlx4_ib_destroy_srq(struct ib_srq *srq, struct ib_udata *udata)
struct mlx4_ib_ucontext,
ibucontext),
&msrq->db);
- ib_umem_release(msrq->umem);
} else {
kvfree(msrq->wrid);
mlx4_buf_free(dev->dev, msrq->msrq.max << msrq->msrq.wqe_shift,
&msrq->buf);
mlx4_db_free(dev->dev, &msrq->db);
}
+ ib_umem_release(msrq->umem);
}
void mlx4_ib_free_srq_wqe(struct mlx4_ib_srq *srq, int wqe_index)
diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c
index 2e2e65f00257..45f48cde6b9d 100644
--- a/drivers/infiniband/hw/mlx5/cq.c
+++ b/drivers/infiniband/hw/mlx5/cq.c
@@ -37,7 +37,7 @@
#include "mlx5_ib.h"
#include "srq.h"
-static void mlx5_ib_cq_comp(struct mlx5_core_cq *cq)
+static void mlx5_ib_cq_comp(struct mlx5_core_cq *cq, struct mlx5_eqe *eqe)
{
struct ib_cq *ibcq = &to_mibcq(cq)->ibcq;
@@ -522,9 +522,9 @@ repoll:
case MLX5_CQE_SIG_ERR:
sig_err_cqe = (struct mlx5_sig_err_cqe *)cqe64;
- read_lock(&dev->mdev->priv.mkey_table.lock);
- mmkey = __mlx5_mr_lookup(dev->mdev,
- mlx5_base_mkey(be32_to_cpu(sig_err_cqe->mkey)));
+ xa_lock(&dev->mdev->priv.mkey_table);
+ mmkey = xa_load(&dev->mdev->priv.mkey_table,
+ mlx5_base_mkey(be32_to_cpu(sig_err_cqe->mkey)));
mr = to_mibmr(mmkey);
get_sig_err_item(sig_err_cqe, &mr->sig->err_item);
mr->sig->sig_err_exists = true;
@@ -537,7 +537,7 @@ repoll:
mr->sig->err_item.expected,
mr->sig->err_item.actual);
- read_unlock(&dev->mdev->priv.mkey_table.lock);
+ xa_unlock(&dev->mdev->priv.mkey_table);
goto repoll;
}
@@ -884,14 +884,15 @@ static void notify_soft_wc_handler(struct work_struct *work)
cq->ibcq.comp_handler(&cq->ibcq, cq->ibcq.cq_context);
}
-struct ib_cq *mlx5_ib_create_cq(struct ib_device *ibdev,
- const struct ib_cq_init_attr *attr,
- struct ib_udata *udata)
+int mlx5_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata)
{
+ struct ib_device *ibdev = ibcq->device;
int entries = attr->cqe;
int vector = attr->comp_vector;
struct mlx5_ib_dev *dev = to_mdev(ibdev);
- struct mlx5_ib_cq *cq;
+ struct mlx5_ib_cq *cq = to_mcq(ibcq);
+ u32 out[MLX5_ST_SZ_DW(create_cq_out)];
int uninitialized_var(index);
int uninitialized_var(inlen);
u32 *cqb = NULL;
@@ -903,18 +904,14 @@ struct ib_cq *mlx5_ib_create_cq(struct ib_device *ibdev,
if (entries < 0 ||
(entries > (1 << MLX5_CAP_GEN(dev->mdev, log_max_cq_sz))))
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
if (check_cq_create_flags(attr->flags))
- return ERR_PTR(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
entries = roundup_pow_of_two(entries + 1);
if (entries > (1 << MLX5_CAP_GEN(dev->mdev, log_max_cq_sz)))
- return ERR_PTR(-EINVAL);
-
- cq = kzalloc(sizeof(*cq), GFP_KERNEL);
- if (!cq)
- return ERR_PTR(-ENOMEM);
+ return -EINVAL;
cq->ibcq.cqe = entries - 1;
mutex_init(&cq->resize_mutex);
@@ -929,13 +926,13 @@ struct ib_cq *mlx5_ib_create_cq(struct ib_device *ibdev,
err = create_cq_user(dev, udata, cq, entries, &cqb, &cqe_size,
&index, &inlen);
if (err)
- goto err_create;
+ return err;
} else {
cqe_size = cache_line_size() == 128 ? 128 : 64;
err = create_cq_kernel(dev, cq, entries, cqe_size, &cqb,
&index, &inlen);
if (err)
- goto err_create;
+ return err;
INIT_WORK(&cq->notify_work, notify_soft_wc_handler);
}
@@ -958,7 +955,7 @@ struct ib_cq *mlx5_ib_create_cq(struct ib_device *ibdev,
if (cq->create_flags & IB_UVERBS_CQ_FLAGS_IGNORE_OVERRUN)
MLX5_SET(cqc, cqc, oi, 1);
- err = mlx5_core_create_cq(dev->mdev, &cq->mcq, cqb, inlen);
+ err = mlx5_core_create_cq(dev->mdev, &cq->mcq, cqb, inlen, out, sizeof(out));
if (err)
goto err_cqb;
@@ -980,7 +977,7 @@ struct ib_cq *mlx5_ib_create_cq(struct ib_device *ibdev,
kvfree(cqb);
- return &cq->ibcq;
+ return 0;
err_cmd:
mlx5_core_destroy_cq(dev->mdev, &cq->mcq);
@@ -991,14 +988,10 @@ err_cqb:
destroy_cq_user(cq, udata);
else
destroy_cq_kernel(dev, cq);
-
-err_create:
- kfree(cq);
-
- return ERR_PTR(err);
+ return err;
}
-int mlx5_ib_destroy_cq(struct ib_cq *cq, struct ib_udata *udata)
+void mlx5_ib_destroy_cq(struct ib_cq *cq, struct ib_udata *udata)
{
struct mlx5_ib_dev *dev = to_mdev(cq->device);
struct mlx5_ib_cq *mcq = to_mcq(cq);
@@ -1008,10 +1001,6 @@ int mlx5_ib_destroy_cq(struct ib_cq *cq, struct ib_udata *udata)
destroy_cq_user(mcq, udata);
else
destroy_cq_kernel(dev, mcq);
-
- kfree(mcq);
-
- return 0;
}
static int is_equal_rsn(struct mlx5_cqe64 *cqe64, u32 rsn)
@@ -1137,11 +1126,6 @@ static int resize_user(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq,
return 0;
}
-static void un_resize_user(struct mlx5_ib_cq *cq)
-{
- ib_umem_release(cq->resize_umem);
-}
-
static int resize_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq,
int entries, int cqe_size)
{
@@ -1164,12 +1148,6 @@ ex:
return err;
}
-static void un_resize_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq)
-{
- free_cq_buf(dev, cq->resize_buf);
- cq->resize_buf = NULL;
-}
-
static int copy_resize_cqes(struct mlx5_ib_cq *cq)
{
struct mlx5_ib_dev *dev = to_mdev(cq->ibcq.device);
@@ -1350,10 +1328,11 @@ ex_alloc:
kvfree(in);
ex_resize:
- if (udata)
- un_resize_user(cq);
- else
- un_resize_kernel(dev, cq);
+ ib_umem_release(cq->resize_umem);
+ if (!udata) {
+ free_cq_buf(dev, cq->resize_buf);
+ cq->resize_buf = NULL;
+ }
ex:
mutex_unlock(&cq->resize_mutex);
return err;
diff --git a/drivers/infiniband/hw/mlx5/devx.c b/drivers/infiniband/hw/mlx5/devx.c
index 80b42d069328..ec4370f99381 100644
--- a/drivers/infiniband/hw/mlx5/devx.c
+++ b/drivers/infiniband/hw/mlx5/devx.c
@@ -14,13 +14,17 @@
#include <linux/mlx5/driver.h>
#include <linux/mlx5/fs.h>
#include "mlx5_ib.h"
+#include <linux/xarray.h>
#define UVERBS_MODULE_NAME mlx5_ib
#include <rdma/uverbs_named_ioctl.h>
+static void dispatch_event_fd(struct list_head *fd_list, const void *data);
+
enum devx_obj_flags {
DEVX_OBJ_FLAGS_INDIRECT_MKEY = 1 << 0,
DEVX_OBJ_FLAGS_DCT = 1 << 1,
+ DEVX_OBJ_FLAGS_CQ = 1 << 2,
};
struct devx_async_data {
@@ -33,9 +37,61 @@ struct devx_async_data {
struct mlx5_ib_uapi_devx_async_cmd_hdr hdr;
};
+struct devx_async_event_data {
+ struct list_head list; /* headed in ev_file->event_list */
+ struct mlx5_ib_uapi_devx_async_event_hdr hdr;
+};
+
+/* first level XA value data structure */
+struct devx_event {
+ struct xarray object_ids; /* second XA level, Key = object id */
+ struct list_head unaffiliated_list;
+};
+
+/* second level XA value data structure */
+struct devx_obj_event {
+ struct rcu_head rcu;
+ struct list_head obj_sub_list;
+};
+
+struct devx_event_subscription {
+ struct list_head file_list; /* headed in ev_file->
+ * subscribed_events_list
+ */
+ struct list_head xa_list; /* headed in devx_event->unaffiliated_list or
+ * devx_obj_event->obj_sub_list
+ */
+ struct list_head obj_list; /* headed in devx_object */
+ struct list_head event_list; /* headed in ev_file->event_list or in
+ * temp list via subscription
+ */
+
+ u8 is_cleaned:1;
+ u32 xa_key_level1;
+ u32 xa_key_level2;
+ struct rcu_head rcu;
+ u64 cookie;
+ struct devx_async_event_file *ev_file;
+ struct file *filp; /* Upon hot unplug we need a direct access to */
+ struct eventfd_ctx *eventfd;
+};
+
+struct devx_async_event_file {
+ struct ib_uobject uobj;
+ /* Head of events that are subscribed to this FD */
+ struct list_head subscribed_events_list;
+ spinlock_t lock;
+ wait_queue_head_t poll_wait;
+ struct list_head event_list;
+ struct mlx5_ib_dev *dev;
+ u8 omit_data:1;
+ u8 is_overflow_err:1;
+ u8 is_destroyed:1;
+};
+
#define MLX5_MAX_DESTROY_INBOX_SIZE_DW MLX5_ST_SZ_DW(delete_fte_in)
struct devx_obj {
- struct mlx5_core_dev *mdev;
+ struct mlx5_ib_dev *ib_dev;
u64 obj_id;
u32 dinlen; /* destroy inbox length */
u32 dinbox[MLX5_MAX_DESTROY_INBOX_SIZE_DW];
@@ -43,7 +99,9 @@ struct devx_obj {
union {
struct mlx5_ib_devx_mr devx_mr;
struct mlx5_core_dct core_dct;
+ struct mlx5_core_cq core_cq;
};
+ struct list_head event_sub; /* holds devx_event_subscription entries */
};
struct devx_umem {
@@ -149,6 +207,127 @@ bool mlx5_ib_devx_is_flow_counter(void *obj, u32 *counter_id)
return false;
}
+static bool is_legacy_unaffiliated_event_num(u16 event_num)
+{
+ switch (event_num) {
+ case MLX5_EVENT_TYPE_PORT_CHANGE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool is_legacy_obj_event_num(u16 event_num)
+{
+ switch (event_num) {
+ case MLX5_EVENT_TYPE_PATH_MIG:
+ case MLX5_EVENT_TYPE_COMM_EST:
+ case MLX5_EVENT_TYPE_SQ_DRAINED:
+ case MLX5_EVENT_TYPE_SRQ_LAST_WQE:
+ case MLX5_EVENT_TYPE_SRQ_RQ_LIMIT:
+ case MLX5_EVENT_TYPE_CQ_ERROR:
+ case MLX5_EVENT_TYPE_WQ_CATAS_ERROR:
+ case MLX5_EVENT_TYPE_PATH_MIG_FAILED:
+ case MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR:
+ case MLX5_EVENT_TYPE_WQ_ACCESS_ERROR:
+ case MLX5_EVENT_TYPE_SRQ_CATAS_ERROR:
+ case MLX5_EVENT_TYPE_DCT_DRAINED:
+ case MLX5_EVENT_TYPE_COMP:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static u16 get_legacy_obj_type(u16 opcode)
+{
+ switch (opcode) {
+ case MLX5_CMD_OP_CREATE_RQ:
+ return MLX5_EVENT_QUEUE_TYPE_RQ;
+ case MLX5_CMD_OP_CREATE_QP:
+ return MLX5_EVENT_QUEUE_TYPE_QP;
+ case MLX5_CMD_OP_CREATE_SQ:
+ return MLX5_EVENT_QUEUE_TYPE_SQ;
+ case MLX5_CMD_OP_CREATE_DCT:
+ return MLX5_EVENT_QUEUE_TYPE_DCT;
+ default:
+ return 0;
+ }
+}
+
+static u16 get_dec_obj_type(struct devx_obj *obj, u16 event_num)
+{
+ u16 opcode;
+
+ opcode = (obj->obj_id >> 32) & 0xffff;
+
+ if (is_legacy_obj_event_num(event_num))
+ return get_legacy_obj_type(opcode);
+
+ switch (opcode) {
+ case MLX5_CMD_OP_CREATE_GENERAL_OBJECT:
+ return (obj->obj_id >> 48);
+ case MLX5_CMD_OP_CREATE_RQ:
+ return MLX5_OBJ_TYPE_RQ;
+ case MLX5_CMD_OP_CREATE_QP:
+ return MLX5_OBJ_TYPE_QP;
+ case MLX5_CMD_OP_CREATE_SQ:
+ return MLX5_OBJ_TYPE_SQ;
+ case MLX5_CMD_OP_CREATE_DCT:
+ return MLX5_OBJ_TYPE_DCT;
+ case MLX5_CMD_OP_CREATE_TIR:
+ return MLX5_OBJ_TYPE_TIR;
+ case MLX5_CMD_OP_CREATE_TIS:
+ return MLX5_OBJ_TYPE_TIS;
+ case MLX5_CMD_OP_CREATE_PSV:
+ return MLX5_OBJ_TYPE_PSV;
+ case MLX5_OBJ_TYPE_MKEY:
+ return MLX5_OBJ_TYPE_MKEY;
+ case MLX5_CMD_OP_CREATE_RMP:
+ return MLX5_OBJ_TYPE_RMP;
+ case MLX5_CMD_OP_CREATE_XRC_SRQ:
+ return MLX5_OBJ_TYPE_XRC_SRQ;
+ case MLX5_CMD_OP_CREATE_XRQ:
+ return MLX5_OBJ_TYPE_XRQ;
+ case MLX5_CMD_OP_CREATE_RQT:
+ return MLX5_OBJ_TYPE_RQT;
+ case MLX5_CMD_OP_ALLOC_FLOW_COUNTER:
+ return MLX5_OBJ_TYPE_FLOW_COUNTER;
+ case MLX5_CMD_OP_CREATE_CQ:
+ return MLX5_OBJ_TYPE_CQ;
+ default:
+ return 0;
+ }
+}
+
+static u16 get_event_obj_type(unsigned long event_type, struct mlx5_eqe *eqe)
+{
+ switch (event_type) {
+ case MLX5_EVENT_TYPE_WQ_CATAS_ERROR:
+ case MLX5_EVENT_TYPE_WQ_ACCESS_ERROR:
+ case MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR:
+ case MLX5_EVENT_TYPE_SRQ_LAST_WQE:
+ case MLX5_EVENT_TYPE_PATH_MIG:
+ case MLX5_EVENT_TYPE_PATH_MIG_FAILED:
+ case MLX5_EVENT_TYPE_COMM_EST:
+ case MLX5_EVENT_TYPE_SQ_DRAINED:
+ case MLX5_EVENT_TYPE_SRQ_RQ_LIMIT:
+ case MLX5_EVENT_TYPE_SRQ_CATAS_ERROR:
+ return eqe->data.qp_srq.type;
+ case MLX5_EVENT_TYPE_CQ_ERROR:
+ return 0;
+ case MLX5_EVENT_TYPE_DCT_DRAINED:
+ return MLX5_EVENT_QUEUE_TYPE_DCT;
+ default:
+ return MLX5_GET(affiliated_event_header, &eqe->data, obj_type);
+ }
+}
+
+static u32 get_dec_obj_id(u64 obj_id)
+{
+ return (obj_id & 0xffffffff);
+}
+
/*
* As the obj_id in the firmware is not globally unique the object type
* must be considered upon checking for a valid object id.
@@ -715,12 +894,16 @@ static int devx_get_uid(struct mlx5_ib_ucontext *c, void *cmd_in)
return c->devx_uid;
}
-static bool devx_is_general_cmd(void *in)
+
+static bool devx_is_general_cmd(void *in, struct mlx5_ib_dev *dev)
{
u16 opcode = MLX5_GET(general_obj_in_cmd_hdr, in, opcode);
- if (opcode >= MLX5_CMD_OP_GENERAL_START &&
- opcode < MLX5_CMD_OP_GENERAL_END)
+ /* Pass all cmds for vhca_tunnel as general, tracking is done in FW */
+ if ((MLX5_CAP_GEN_64(dev->mdev, vhca_tunnel_commands) &&
+ MLX5_GET(general_obj_in_cmd_hdr, in, vhca_tunnel_id)) ||
+ (opcode >= MLX5_CMD_OP_GENERAL_START &&
+ opcode < MLX5_CMD_OP_GENERAL_END))
return true;
switch (opcode) {
@@ -846,7 +1029,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OTHER)(
return uid;
/* Only white list of some general HCA commands are allowed for this method. */
- if (!devx_is_general_cmd(cmd_in))
+ if (!devx_is_general_cmd(cmd_in, dev))
return -EINVAL;
cmd_out = uverbs_zalloc(attrs, cmd_out_len);
@@ -1043,13 +1226,10 @@ static int devx_handle_mkey_indirect(struct devx_obj *obj,
struct mlx5_ib_dev *dev,
void *in, void *out)
{
- struct mlx5_mkey_table *table = &dev->mdev->priv.mkey_table;
struct mlx5_ib_devx_mr *devx_mr = &obj->devx_mr;
- unsigned long flags;
struct mlx5_core_mkey *mkey;
void *mkc;
u8 key;
- int err;
mkey = &devx_mr->mmkey;
mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
@@ -1062,11 +1242,8 @@ static int devx_handle_mkey_indirect(struct devx_obj *obj,
mkey->pd = MLX5_GET(mkc, mkc, pd);
devx_mr->ndescs = MLX5_GET(mkc, mkc, translations_octword_size);
- write_lock_irqsave(&table->lock, flags);
- err = radix_tree_insert(&table->tree, mlx5_base_mkey(mkey->key),
- mkey);
- write_unlock_irqrestore(&table->lock, flags);
- return err;
+ return xa_err(xa_store(&dev->mdev->priv.mkey_table,
+ mlx5_base_mkey(mkey->key), mkey, GFP_KERNEL));
}
static int devx_handle_mkey_create(struct mlx5_ib_dev *dev,
@@ -1117,12 +1294,37 @@ static void devx_free_indirect_mkey(struct rcu_head *rcu)
*/
static void devx_cleanup_mkey(struct devx_obj *obj)
{
- struct mlx5_mkey_table *table = &obj->mdev->priv.mkey_table;
- unsigned long flags;
+ xa_erase(&obj->ib_dev->mdev->priv.mkey_table,
+ mlx5_base_mkey(obj->devx_mr.mmkey.key));
+}
- write_lock_irqsave(&table->lock, flags);
- radix_tree_delete(&table->tree, mlx5_base_mkey(obj->devx_mr.mmkey.key));
- write_unlock_irqrestore(&table->lock, flags);
+static void devx_cleanup_subscription(struct mlx5_ib_dev *dev,
+ struct devx_event_subscription *sub)
+{
+ struct devx_event *event;
+ struct devx_obj_event *xa_val_level2;
+
+ if (sub->is_cleaned)
+ return;
+
+ sub->is_cleaned = 1;
+ list_del_rcu(&sub->xa_list);
+
+ if (list_empty(&sub->obj_list))
+ return;
+
+ list_del_rcu(&sub->obj_list);
+ /* check whether key level 1 for this obj_sub_list is empty */
+ event = xa_load(&dev->devx_event_table.event_xa,
+ sub->xa_key_level1);
+ WARN_ON(!event);
+
+ xa_val_level2 = xa_load(&event->object_ids, sub->xa_key_level2);
+ if (list_empty(&xa_val_level2->obj_sub_list)) {
+ xa_erase(&event->object_ids,
+ sub->xa_key_level2);
+ kfree_rcu(xa_val_level2, rcu);
+ }
}
static int devx_obj_cleanup(struct ib_uobject *uobject,
@@ -1130,24 +1332,34 @@ static int devx_obj_cleanup(struct ib_uobject *uobject,
struct uverbs_attr_bundle *attrs)
{
u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)];
+ struct mlx5_devx_event_table *devx_event_table;
struct devx_obj *obj = uobject->object;
+ struct devx_event_subscription *sub_entry, *tmp;
+ struct mlx5_ib_dev *dev;
int ret;
+ dev = mlx5_udata_to_mdev(&attrs->driver_udata);
if (obj->flags & DEVX_OBJ_FLAGS_INDIRECT_MKEY)
devx_cleanup_mkey(obj);
if (obj->flags & DEVX_OBJ_FLAGS_DCT)
- ret = mlx5_core_destroy_dct(obj->mdev, &obj->core_dct);
+ ret = mlx5_core_destroy_dct(obj->ib_dev->mdev, &obj->core_dct);
+ else if (obj->flags & DEVX_OBJ_FLAGS_CQ)
+ ret = mlx5_core_destroy_cq(obj->ib_dev->mdev, &obj->core_cq);
else
- ret = mlx5_cmd_exec(obj->mdev, obj->dinbox, obj->dinlen, out,
- sizeof(out));
+ ret = mlx5_cmd_exec(obj->ib_dev->mdev, obj->dinbox,
+ obj->dinlen, out, sizeof(out));
if (ib_is_destroy_retryable(ret, why, uobject))
return ret;
- if (obj->flags & DEVX_OBJ_FLAGS_INDIRECT_MKEY) {
- struct mlx5_ib_dev *dev =
- mlx5_udata_to_mdev(&attrs->driver_udata);
+ devx_event_table = &dev->devx_event_table;
+
+ mutex_lock(&devx_event_table->event_xa_lock);
+ list_for_each_entry_safe(sub_entry, tmp, &obj->event_sub, obj_list)
+ devx_cleanup_subscription(dev, sub_entry);
+ mutex_unlock(&devx_event_table->event_xa_lock);
+ if (obj->flags & DEVX_OBJ_FLAGS_INDIRECT_MKEY) {
call_srcu(&dev->mr_srcu, &obj->devx_mr.rcu,
devx_free_indirect_mkey);
return ret;
@@ -1157,6 +1369,29 @@ static int devx_obj_cleanup(struct ib_uobject *uobject,
return ret;
}
+static void devx_cq_comp(struct mlx5_core_cq *mcq, struct mlx5_eqe *eqe)
+{
+ struct devx_obj *obj = container_of(mcq, struct devx_obj, core_cq);
+ struct mlx5_devx_event_table *table;
+ struct devx_event *event;
+ struct devx_obj_event *obj_event;
+ u32 obj_id = mcq->cqn;
+
+ table = &obj->ib_dev->devx_event_table;
+ rcu_read_lock();
+ event = xa_load(&table->event_xa, MLX5_EVENT_TYPE_COMP);
+ if (!event)
+ goto out;
+
+ obj_event = xa_load(&event->object_ids, obj_id);
+ if (!obj_event)
+ goto out;
+
+ dispatch_event_fd(&obj_event->obj_sub_list, eqe);
+out:
+ rcu_read_unlock();
+}
+
static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_CREATE)(
struct uverbs_attr_bundle *attrs)
{
@@ -1179,6 +1414,9 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_CREATE)(
u32 obj_id;
u16 opcode;
+ if (MLX5_GET(general_obj_in_cmd_hdr, cmd_in, vhca_tunnel_id))
+ return -EINVAL;
+
uid = devx_get_uid(c, cmd_in);
if (uid < 0)
return uid;
@@ -1208,6 +1446,12 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_CREATE)(
err = mlx5_core_create_dct(dev->mdev, &obj->core_dct,
cmd_in, cmd_in_len,
cmd_out, cmd_out_len);
+ } else if (opcode == MLX5_CMD_OP_CREATE_CQ) {
+ obj->flags |= DEVX_OBJ_FLAGS_CQ;
+ obj->core_cq.comp = devx_cq_comp;
+ err = mlx5_core_create_cq(dev->mdev, &obj->core_cq,
+ cmd_in, cmd_in_len, cmd_out,
+ cmd_out_len);
} else {
err = mlx5_cmd_exec(dev->mdev, cmd_in,
cmd_in_len,
@@ -1218,7 +1462,8 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_CREATE)(
goto obj_free;
uobj->object = obj;
- obj->mdev = dev->mdev;
+ INIT_LIST_HEAD(&obj->event_sub);
+ obj->ib_dev = dev;
devx_obj_build_destroy_cmd(cmd_in, cmd_out, obj->dinbox, &obj->dinlen,
&obj_id);
WARN_ON(obj->dinlen > MLX5_MAX_DESTROY_INBOX_SIZE_DW * sizeof(u32));
@@ -1245,9 +1490,11 @@ err_copy:
devx_cleanup_mkey(obj);
obj_destroy:
if (obj->flags & DEVX_OBJ_FLAGS_DCT)
- mlx5_core_destroy_dct(obj->mdev, &obj->core_dct);
+ mlx5_core_destroy_dct(obj->ib_dev->mdev, &obj->core_dct);
+ else if (obj->flags & DEVX_OBJ_FLAGS_CQ)
+ mlx5_core_destroy_cq(obj->ib_dev->mdev, &obj->core_cq);
else
- mlx5_cmd_exec(obj->mdev, obj->dinbox, obj->dinlen, out,
+ mlx5_cmd_exec(obj->ib_dev->mdev, obj->dinbox, obj->dinlen, out,
sizeof(out));
obj_free:
kfree(obj);
@@ -1269,6 +1516,9 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_MODIFY)(
int err;
int uid;
+ if (MLX5_GET(general_obj_in_cmd_hdr, cmd_in, vhca_tunnel_id))
+ return -EINVAL;
+
uid = devx_get_uid(c, cmd_in);
if (uid < 0)
return uid;
@@ -1311,6 +1561,9 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_QUERY)(
int uid;
struct mlx5_ib_dev *mdev = to_mdev(c->ibucontext.device);
+ if (MLX5_GET(general_obj_in_cmd_hdr, cmd_in, vhca_tunnel_id))
+ return -EINVAL;
+
uid = devx_get_uid(c, cmd_in);
if (uid < 0)
return uid;
@@ -1375,6 +1628,38 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_ASYNC_CMD_FD_ALLOC)(
return 0;
}
+static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_ASYNC_EVENT_FD_ALLOC)(
+ struct uverbs_attr_bundle *attrs)
+{
+ struct ib_uobject *uobj = uverbs_attr_get_uobject(
+ attrs, MLX5_IB_ATTR_DEVX_ASYNC_EVENT_FD_ALLOC_HANDLE);
+ struct devx_async_event_file *ev_file;
+ struct mlx5_ib_ucontext *c = rdma_udata_to_drv_context(
+ &attrs->driver_udata, struct mlx5_ib_ucontext, ibucontext);
+ struct mlx5_ib_dev *dev = to_mdev(c->ibucontext.device);
+ u32 flags;
+ int err;
+
+ err = uverbs_get_flags32(&flags, attrs,
+ MLX5_IB_ATTR_DEVX_ASYNC_EVENT_FD_ALLOC_FLAGS,
+ MLX5_IB_UAPI_DEVX_CR_EV_CH_FLAGS_OMIT_DATA);
+
+ if (err)
+ return err;
+
+ ev_file = container_of(uobj, struct devx_async_event_file,
+ uobj);
+ spin_lock_init(&ev_file->lock);
+ INIT_LIST_HEAD(&ev_file->event_list);
+ init_waitqueue_head(&ev_file->poll_wait);
+ if (flags & MLX5_IB_UAPI_DEVX_CR_EV_CH_FLAGS_OMIT_DATA)
+ ev_file->omit_data = 1;
+ INIT_LIST_HEAD(&ev_file->subscribed_events_list);
+ ev_file->dev = dev;
+ get_device(&dev->ib_dev.dev);
+ return 0;
+}
+
static void devx_query_callback(int status, struct mlx5_async_work *context)
{
struct devx_async_data *async_data =
@@ -1416,6 +1701,9 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_ASYNC_QUERY)(
struct devx_async_cmd_event_file *ev_file;
struct devx_async_data *async_data;
+ if (MLX5_GET(general_obj_in_cmd_hdr, cmd_in, vhca_tunnel_id))
+ return -EINVAL;
+
uid = devx_get_uid(c, cmd_in);
if (uid < 0)
return uid;
@@ -1484,6 +1772,331 @@ sub_bytes:
return err;
}
+static void
+subscribe_event_xa_dealloc(struct mlx5_devx_event_table *devx_event_table,
+ u32 key_level1,
+ bool is_level2,
+ u32 key_level2)
+{
+ struct devx_event *event;
+ struct devx_obj_event *xa_val_level2;
+
+ /* Level 1 is valid for future use, no need to free */
+ if (!is_level2)
+ return;
+
+ event = xa_load(&devx_event_table->event_xa, key_level1);
+ WARN_ON(!event);
+
+ xa_val_level2 = xa_load(&event->object_ids,
+ key_level2);
+ if (list_empty(&xa_val_level2->obj_sub_list)) {
+ xa_erase(&event->object_ids,
+ key_level2);
+ kfree_rcu(xa_val_level2, rcu);
+ }
+}
+
+static int
+subscribe_event_xa_alloc(struct mlx5_devx_event_table *devx_event_table,
+ u32 key_level1,
+ bool is_level2,
+ u32 key_level2)
+{
+ struct devx_obj_event *obj_event;
+ struct devx_event *event;
+ int err;
+
+ event = xa_load(&devx_event_table->event_xa, key_level1);
+ if (!event) {
+ event = kzalloc(sizeof(*event), GFP_KERNEL);
+ if (!event)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&event->unaffiliated_list);
+ xa_init(&event->object_ids);
+
+ err = xa_insert(&devx_event_table->event_xa,
+ key_level1,
+ event,
+ GFP_KERNEL);
+ if (err) {
+ kfree(event);
+ return err;
+ }
+ }
+
+ if (!is_level2)
+ return 0;
+
+ obj_event = xa_load(&event->object_ids, key_level2);
+ if (!obj_event) {
+ obj_event = kzalloc(sizeof(*obj_event), GFP_KERNEL);
+ if (!obj_event)
+ /* Level1 is valid for future use, no need to free */
+ return -ENOMEM;
+
+ err = xa_insert(&event->object_ids,
+ key_level2,
+ obj_event,
+ GFP_KERNEL);
+ if (err)
+ return err;
+ INIT_LIST_HEAD(&obj_event->obj_sub_list);
+ }
+
+ return 0;
+}
+
+static bool is_valid_events_legacy(int num_events, u16 *event_type_num_list,
+ struct devx_obj *obj)
+{
+ int i;
+
+ for (i = 0; i < num_events; i++) {
+ if (obj) {
+ if (!is_legacy_obj_event_num(event_type_num_list[i]))
+ return false;
+ } else if (!is_legacy_unaffiliated_event_num(
+ event_type_num_list[i])) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+#define MAX_SUPP_EVENT_NUM 255
+static bool is_valid_events(struct mlx5_core_dev *dev,
+ int num_events, u16 *event_type_num_list,
+ struct devx_obj *obj)
+{
+ __be64 *aff_events;
+ __be64 *unaff_events;
+ int mask_entry;
+ int mask_bit;
+ int i;
+
+ if (MLX5_CAP_GEN(dev, event_cap)) {
+ aff_events = MLX5_CAP_DEV_EVENT(dev,
+ user_affiliated_events);
+ unaff_events = MLX5_CAP_DEV_EVENT(dev,
+ user_unaffiliated_events);
+ } else {
+ return is_valid_events_legacy(num_events, event_type_num_list,
+ obj);
+ }
+
+ for (i = 0; i < num_events; i++) {
+ if (event_type_num_list[i] > MAX_SUPP_EVENT_NUM)
+ return false;
+
+ mask_entry = event_type_num_list[i] / 64;
+ mask_bit = event_type_num_list[i] % 64;
+
+ if (obj) {
+ /* CQ completion */
+ if (event_type_num_list[i] == 0)
+ continue;
+
+ if (!(be64_to_cpu(aff_events[mask_entry]) &
+ (1ull << mask_bit)))
+ return false;
+
+ continue;
+ }
+
+ if (!(be64_to_cpu(unaff_events[mask_entry]) &
+ (1ull << mask_bit)))
+ return false;
+ }
+
+ return true;
+}
+
+#define MAX_NUM_EVENTS 16
+static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_SUBSCRIBE_EVENT)(
+ struct uverbs_attr_bundle *attrs)
+{
+ struct ib_uobject *devx_uobj = uverbs_attr_get_uobject(
+ attrs,
+ MLX5_IB_ATTR_DEVX_SUBSCRIBE_EVENT_OBJ_HANDLE);
+ struct mlx5_ib_ucontext *c = rdma_udata_to_drv_context(
+ &attrs->driver_udata, struct mlx5_ib_ucontext, ibucontext);
+ struct mlx5_ib_dev *dev = to_mdev(c->ibucontext.device);
+ struct ib_uobject *fd_uobj;
+ struct devx_obj *obj = NULL;
+ struct devx_async_event_file *ev_file;
+ struct mlx5_devx_event_table *devx_event_table = &dev->devx_event_table;
+ u16 *event_type_num_list;
+ struct devx_event_subscription *event_sub, *tmp_sub;
+ struct list_head sub_list;
+ int redirect_fd;
+ bool use_eventfd = false;
+ int num_events;
+ int num_alloc_xa_entries = 0;
+ u16 obj_type = 0;
+ u64 cookie = 0;
+ u32 obj_id = 0;
+ int err;
+ int i;
+
+ if (!c->devx_uid)
+ return -EINVAL;
+
+ if (!IS_ERR(devx_uobj)) {
+ obj = (struct devx_obj *)devx_uobj->object;
+ if (obj)
+ obj_id = get_dec_obj_id(obj->obj_id);
+ }
+
+ fd_uobj = uverbs_attr_get_uobject(attrs,
+ MLX5_IB_ATTR_DEVX_SUBSCRIBE_EVENT_FD_HANDLE);
+ if (IS_ERR(fd_uobj))
+ return PTR_ERR(fd_uobj);
+
+ ev_file = container_of(fd_uobj, struct devx_async_event_file,
+ uobj);
+
+ if (uverbs_attr_is_valid(attrs,
+ MLX5_IB_ATTR_DEVX_SUBSCRIBE_EVENT_FD_NUM)) {
+ err = uverbs_copy_from(&redirect_fd, attrs,
+ MLX5_IB_ATTR_DEVX_SUBSCRIBE_EVENT_FD_NUM);
+ if (err)
+ return err;
+
+ use_eventfd = true;
+ }
+
+ if (uverbs_attr_is_valid(attrs,
+ MLX5_IB_ATTR_DEVX_SUBSCRIBE_EVENT_COOKIE)) {
+ if (use_eventfd)
+ return -EINVAL;
+
+ err = uverbs_copy_from(&cookie, attrs,
+ MLX5_IB_ATTR_DEVX_SUBSCRIBE_EVENT_COOKIE);
+ if (err)
+ return err;
+ }
+
+ num_events = uverbs_attr_ptr_get_array_size(
+ attrs, MLX5_IB_ATTR_DEVX_SUBSCRIBE_EVENT_TYPE_NUM_LIST,
+ sizeof(u16));
+
+ if (num_events < 0)
+ return num_events;
+
+ if (num_events > MAX_NUM_EVENTS)
+ return -EINVAL;
+
+ event_type_num_list = uverbs_attr_get_alloced_ptr(attrs,
+ MLX5_IB_ATTR_DEVX_SUBSCRIBE_EVENT_TYPE_NUM_LIST);
+
+ if (!is_valid_events(dev->mdev, num_events, event_type_num_list, obj))
+ return -EINVAL;
+
+ INIT_LIST_HEAD(&sub_list);
+
+ /* Protect from concurrent subscriptions to same XA entries to allow
+ * both to succeed
+ */
+ mutex_lock(&devx_event_table->event_xa_lock);
+ for (i = 0; i < num_events; i++) {
+ u32 key_level1;
+
+ if (obj)
+ obj_type = get_dec_obj_type(obj,
+ event_type_num_list[i]);
+ key_level1 = event_type_num_list[i] | obj_type << 16;
+
+ err = subscribe_event_xa_alloc(devx_event_table,
+ key_level1,
+ obj,
+ obj_id);
+ if (err)
+ goto err;
+
+ num_alloc_xa_entries++;
+ event_sub = kzalloc(sizeof(*event_sub), GFP_KERNEL);
+ if (!event_sub)
+ goto err;
+
+ list_add_tail(&event_sub->event_list, &sub_list);
+ if (use_eventfd) {
+ event_sub->eventfd =
+ eventfd_ctx_fdget(redirect_fd);
+
+ if (IS_ERR(event_sub)) {
+ err = PTR_ERR(event_sub->eventfd);
+ event_sub->eventfd = NULL;
+ goto err;
+ }
+ }
+
+ event_sub->cookie = cookie;
+ event_sub->ev_file = ev_file;
+ event_sub->filp = fd_uobj->object;
+ /* May be needed upon cleanup the devx object/subscription */
+ event_sub->xa_key_level1 = key_level1;
+ event_sub->xa_key_level2 = obj_id;
+ INIT_LIST_HEAD(&event_sub->obj_list);
+ }
+
+ /* Once all the allocations and the XA data insertions were done we
+ * can go ahead and add all the subscriptions to the relevant lists
+ * without concern of a failure.
+ */
+ list_for_each_entry_safe(event_sub, tmp_sub, &sub_list, event_list) {
+ struct devx_event *event;
+ struct devx_obj_event *obj_event;
+
+ list_del_init(&event_sub->event_list);
+
+ spin_lock_irq(&ev_file->lock);
+ list_add_tail_rcu(&event_sub->file_list,
+ &ev_file->subscribed_events_list);
+ spin_unlock_irq(&ev_file->lock);
+
+ event = xa_load(&devx_event_table->event_xa,
+ event_sub->xa_key_level1);
+ WARN_ON(!event);
+
+ if (!obj) {
+ list_add_tail_rcu(&event_sub->xa_list,
+ &event->unaffiliated_list);
+ continue;
+ }
+
+ obj_event = xa_load(&event->object_ids, obj_id);
+ WARN_ON(!obj_event);
+ list_add_tail_rcu(&event_sub->xa_list,
+ &obj_event->obj_sub_list);
+ list_add_tail_rcu(&event_sub->obj_list,
+ &obj->event_sub);
+ }
+
+ mutex_unlock(&devx_event_table->event_xa_lock);
+ return 0;
+
+err:
+ list_for_each_entry_safe(event_sub, tmp_sub, &sub_list, event_list) {
+ list_del(&event_sub->event_list);
+
+ subscribe_event_xa_dealloc(devx_event_table,
+ event_sub->xa_key_level1,
+ obj,
+ obj_id);
+
+ if (event_sub->eventfd)
+ eventfd_ctx_put(event_sub->eventfd);
+
+ kfree(event_sub);
+ }
+
+ mutex_unlock(&devx_event_table->event_xa_lock);
+ return err;
+}
+
static int devx_umem_get(struct mlx5_ib_dev *dev, struct ib_ucontext *ucontext,
struct uverbs_attr_bundle *attrs,
struct devx_umem *obj)
@@ -1631,6 +2244,203 @@ static int devx_umem_cleanup(struct ib_uobject *uobject,
return 0;
}
+static bool is_unaffiliated_event(struct mlx5_core_dev *dev,
+ unsigned long event_type)
+{
+ __be64 *unaff_events;
+ int mask_entry;
+ int mask_bit;
+
+ if (!MLX5_CAP_GEN(dev, event_cap))
+ return is_legacy_unaffiliated_event_num(event_type);
+
+ unaff_events = MLX5_CAP_DEV_EVENT(dev,
+ user_unaffiliated_events);
+ WARN_ON(event_type > MAX_SUPP_EVENT_NUM);
+
+ mask_entry = event_type / 64;
+ mask_bit = event_type % 64;
+
+ if (!(be64_to_cpu(unaff_events[mask_entry]) & (1ull << mask_bit)))
+ return false;
+
+ return true;
+}
+
+static u32 devx_get_obj_id_from_event(unsigned long event_type, void *data)
+{
+ struct mlx5_eqe *eqe = data;
+ u32 obj_id = 0;
+
+ switch (event_type) {
+ case MLX5_EVENT_TYPE_SRQ_CATAS_ERROR:
+ case MLX5_EVENT_TYPE_SRQ_RQ_LIMIT:
+ case MLX5_EVENT_TYPE_PATH_MIG:
+ case MLX5_EVENT_TYPE_COMM_EST:
+ case MLX5_EVENT_TYPE_SQ_DRAINED:
+ case MLX5_EVENT_TYPE_SRQ_LAST_WQE:
+ case MLX5_EVENT_TYPE_WQ_CATAS_ERROR:
+ case MLX5_EVENT_TYPE_PATH_MIG_FAILED:
+ case MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR:
+ case MLX5_EVENT_TYPE_WQ_ACCESS_ERROR:
+ obj_id = be32_to_cpu(eqe->data.qp_srq.qp_srq_n) & 0xffffff;
+ break;
+ case MLX5_EVENT_TYPE_DCT_DRAINED:
+ obj_id = be32_to_cpu(eqe->data.dct.dctn) & 0xffffff;
+ break;
+ case MLX5_EVENT_TYPE_CQ_ERROR:
+ obj_id = be32_to_cpu(eqe->data.cq_err.cqn) & 0xffffff;
+ break;
+ default:
+ obj_id = MLX5_GET(affiliated_event_header, &eqe->data, obj_id);
+ break;
+ }
+
+ return obj_id;
+}
+
+static int deliver_event(struct devx_event_subscription *event_sub,
+ const void *data)
+{
+ struct devx_async_event_file *ev_file;
+ struct devx_async_event_data *event_data;
+ unsigned long flags;
+
+ ev_file = event_sub->ev_file;
+
+ if (ev_file->omit_data) {
+ spin_lock_irqsave(&ev_file->lock, flags);
+ if (!list_empty(&event_sub->event_list)) {
+ spin_unlock_irqrestore(&ev_file->lock, flags);
+ return 0;
+ }
+
+ list_add_tail(&event_sub->event_list, &ev_file->event_list);
+ spin_unlock_irqrestore(&ev_file->lock, flags);
+ wake_up_interruptible(&ev_file->poll_wait);
+ return 0;
+ }
+
+ event_data = kzalloc(sizeof(*event_data) + sizeof(struct mlx5_eqe),
+ GFP_ATOMIC);
+ if (!event_data) {
+ spin_lock_irqsave(&ev_file->lock, flags);
+ ev_file->is_overflow_err = 1;
+ spin_unlock_irqrestore(&ev_file->lock, flags);
+ return -ENOMEM;
+ }
+
+ event_data->hdr.cookie = event_sub->cookie;
+ memcpy(event_data->hdr.out_data, data, sizeof(struct mlx5_eqe));
+
+ spin_lock_irqsave(&ev_file->lock, flags);
+ list_add_tail(&event_data->list, &ev_file->event_list);
+ spin_unlock_irqrestore(&ev_file->lock, flags);
+ wake_up_interruptible(&ev_file->poll_wait);
+
+ return 0;
+}
+
+static void dispatch_event_fd(struct list_head *fd_list,
+ const void *data)
+{
+ struct devx_event_subscription *item;
+
+ list_for_each_entry_rcu(item, fd_list, xa_list) {
+ if (!get_file_rcu(item->filp))
+ continue;
+
+ if (item->eventfd) {
+ eventfd_signal(item->eventfd, 1);
+ fput(item->filp);
+ continue;
+ }
+
+ deliver_event(item, data);
+ fput(item->filp);
+ }
+}
+
+static int devx_event_notifier(struct notifier_block *nb,
+ unsigned long event_type, void *data)
+{
+ struct mlx5_devx_event_table *table;
+ struct mlx5_ib_dev *dev;
+ struct devx_event *event;
+ struct devx_obj_event *obj_event;
+ u16 obj_type = 0;
+ bool is_unaffiliated;
+ u32 obj_id;
+
+ /* Explicit filtering to kernel events which may occur frequently */
+ if (event_type == MLX5_EVENT_TYPE_CMD ||
+ event_type == MLX5_EVENT_TYPE_PAGE_REQUEST)
+ return NOTIFY_OK;
+
+ table = container_of(nb, struct mlx5_devx_event_table, devx_nb.nb);
+ dev = container_of(table, struct mlx5_ib_dev, devx_event_table);
+ is_unaffiliated = is_unaffiliated_event(dev->mdev, event_type);
+
+ if (!is_unaffiliated)
+ obj_type = get_event_obj_type(event_type, data);
+
+ rcu_read_lock();
+ event = xa_load(&table->event_xa, event_type | (obj_type << 16));
+ if (!event) {
+ rcu_read_unlock();
+ return NOTIFY_DONE;
+ }
+
+ if (is_unaffiliated) {
+ dispatch_event_fd(&event->unaffiliated_list, data);
+ rcu_read_unlock();
+ return NOTIFY_OK;
+ }
+
+ obj_id = devx_get_obj_id_from_event(event_type, data);
+ obj_event = xa_load(&event->object_ids, obj_id);
+ if (!obj_event) {
+ rcu_read_unlock();
+ return NOTIFY_DONE;
+ }
+
+ dispatch_event_fd(&obj_event->obj_sub_list, data);
+
+ rcu_read_unlock();
+ return NOTIFY_OK;
+}
+
+void mlx5_ib_devx_init_event_table(struct mlx5_ib_dev *dev)
+{
+ struct mlx5_devx_event_table *table = &dev->devx_event_table;
+
+ xa_init(&table->event_xa);
+ mutex_init(&table->event_xa_lock);
+ MLX5_NB_INIT(&table->devx_nb, devx_event_notifier, NOTIFY_ANY);
+ mlx5_eq_notifier_register(dev->mdev, &table->devx_nb);
+}
+
+void mlx5_ib_devx_cleanup_event_table(struct mlx5_ib_dev *dev)
+{
+ struct mlx5_devx_event_table *table = &dev->devx_event_table;
+ struct devx_event_subscription *sub, *tmp;
+ struct devx_event *event;
+ void *entry;
+ unsigned long id;
+
+ mlx5_eq_notifier_unregister(dev->mdev, &table->devx_nb);
+ mutex_lock(&dev->devx_event_table.event_xa_lock);
+ xa_for_each(&table->event_xa, id, entry) {
+ event = entry;
+ list_for_each_entry_safe(sub, tmp, &event->unaffiliated_list,
+ xa_list)
+ devx_cleanup_subscription(dev, sub);
+ kfree(entry);
+ }
+ mutex_unlock(&dev->devx_event_table.event_xa_lock);
+ xa_destroy(&table->event_xa);
+}
+
static ssize_t devx_async_cmd_event_read(struct file *filp, char __user *buf,
size_t count, loff_t *pos)
{
@@ -1729,6 +2539,149 @@ static const struct file_operations devx_async_cmd_event_fops = {
.llseek = no_llseek,
};
+static ssize_t devx_async_event_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct devx_async_event_file *ev_file = filp->private_data;
+ struct devx_event_subscription *event_sub;
+ struct devx_async_event_data *uninitialized_var(event);
+ int ret = 0;
+ size_t eventsz;
+ bool omit_data;
+ void *event_data;
+
+ omit_data = ev_file->omit_data;
+
+ spin_lock_irq(&ev_file->lock);
+
+ if (ev_file->is_overflow_err) {
+ ev_file->is_overflow_err = 0;
+ spin_unlock_irq(&ev_file->lock);
+ return -EOVERFLOW;
+ }
+
+ if (ev_file->is_destroyed) {
+ spin_unlock_irq(&ev_file->lock);
+ return -EIO;
+ }
+
+ while (list_empty(&ev_file->event_list)) {
+ spin_unlock_irq(&ev_file->lock);
+
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ if (wait_event_interruptible(ev_file->poll_wait,
+ (!list_empty(&ev_file->event_list) ||
+ ev_file->is_destroyed))) {
+ return -ERESTARTSYS;
+ }
+
+ spin_lock_irq(&ev_file->lock);
+ if (ev_file->is_destroyed) {
+ spin_unlock_irq(&ev_file->lock);
+ return -EIO;
+ }
+ }
+
+ if (omit_data) {
+ event_sub = list_first_entry(&ev_file->event_list,
+ struct devx_event_subscription,
+ event_list);
+ eventsz = sizeof(event_sub->cookie);
+ event_data = &event_sub->cookie;
+ } else {
+ event = list_first_entry(&ev_file->event_list,
+ struct devx_async_event_data, list);
+ eventsz = sizeof(struct mlx5_eqe) +
+ sizeof(struct mlx5_ib_uapi_devx_async_event_hdr);
+ event_data = &event->hdr;
+ }
+
+ if (eventsz > count) {
+ spin_unlock_irq(&ev_file->lock);
+ return -EINVAL;
+ }
+
+ if (omit_data)
+ list_del_init(&event_sub->event_list);
+ else
+ list_del(&event->list);
+
+ spin_unlock_irq(&ev_file->lock);
+
+ if (copy_to_user(buf, event_data, eventsz))
+ /* This points to an application issue, not a kernel concern */
+ ret = -EFAULT;
+ else
+ ret = eventsz;
+
+ if (!omit_data)
+ kfree(event);
+ return ret;
+}
+
+static __poll_t devx_async_event_poll(struct file *filp,
+ struct poll_table_struct *wait)
+{
+ struct devx_async_event_file *ev_file = filp->private_data;
+ __poll_t pollflags = 0;
+
+ poll_wait(filp, &ev_file->poll_wait, wait);
+
+ spin_lock_irq(&ev_file->lock);
+ if (ev_file->is_destroyed)
+ pollflags = EPOLLIN | EPOLLRDNORM | EPOLLRDHUP;
+ else if (!list_empty(&ev_file->event_list))
+ pollflags = EPOLLIN | EPOLLRDNORM;
+ spin_unlock_irq(&ev_file->lock);
+
+ return pollflags;
+}
+
+static int devx_async_event_close(struct inode *inode, struct file *filp)
+{
+ struct devx_async_event_file *ev_file = filp->private_data;
+ struct devx_event_subscription *event_sub, *event_sub_tmp;
+ struct devx_async_event_data *entry, *tmp;
+
+ mutex_lock(&ev_file->dev->devx_event_table.event_xa_lock);
+ /* delete the subscriptions which are related to this FD */
+ list_for_each_entry_safe(event_sub, event_sub_tmp,
+ &ev_file->subscribed_events_list, file_list) {
+ devx_cleanup_subscription(ev_file->dev, event_sub);
+ if (event_sub->eventfd)
+ eventfd_ctx_put(event_sub->eventfd);
+
+ list_del_rcu(&event_sub->file_list);
+ /* subscription may not be used by the read API any more */
+ kfree_rcu(event_sub, rcu);
+ }
+
+ mutex_unlock(&ev_file->dev->devx_event_table.event_xa_lock);
+
+ /* free the pending events allocation */
+ if (!ev_file->omit_data) {
+ spin_lock_irq(&ev_file->lock);
+ list_for_each_entry_safe(entry, tmp,
+ &ev_file->event_list, list)
+ kfree(entry); /* read can't come any more */
+ spin_unlock_irq(&ev_file->lock);
+ }
+
+ uverbs_close_fd(filp);
+ put_device(&ev_file->dev->ib_dev.dev);
+ return 0;
+}
+
+static const struct file_operations devx_async_event_fops = {
+ .owner = THIS_MODULE,
+ .read = devx_async_event_read,
+ .poll = devx_async_event_poll,
+ .release = devx_async_event_close,
+ .llseek = no_llseek,
+};
+
static int devx_hot_unplug_async_cmd_event_file(struct ib_uobject *uobj,
enum rdma_remove_reason why)
{
@@ -1748,6 +2701,21 @@ static int devx_hot_unplug_async_cmd_event_file(struct ib_uobject *uobj,
return 0;
};
+static int devx_hot_unplug_async_event_file(struct ib_uobject *uobj,
+ enum rdma_remove_reason why)
+{
+ struct devx_async_event_file *ev_file =
+ container_of(uobj, struct devx_async_event_file,
+ uobj);
+
+ spin_lock_irq(&ev_file->lock);
+ ev_file->is_destroyed = 1;
+ spin_unlock_irq(&ev_file->lock);
+
+ wake_up_interruptible(&ev_file->poll_wait);
+ return 0;
+};
+
DECLARE_UVERBS_NAMED_METHOD(
MLX5_IB_METHOD_DEVX_UMEM_REG,
UVERBS_ATTR_IDR(MLX5_IB_ATTR_DEVX_UMEM_REG_HANDLE,
@@ -1879,10 +2847,32 @@ DECLARE_UVERBS_NAMED_METHOD(
UVERBS_ATTR_TYPE(u64),
UA_MANDATORY));
+DECLARE_UVERBS_NAMED_METHOD(
+ MLX5_IB_METHOD_DEVX_SUBSCRIBE_EVENT,
+ UVERBS_ATTR_FD(MLX5_IB_ATTR_DEVX_SUBSCRIBE_EVENT_FD_HANDLE,
+ MLX5_IB_OBJECT_DEVX_ASYNC_EVENT_FD,
+ UVERBS_ACCESS_READ,
+ UA_MANDATORY),
+ UVERBS_ATTR_IDR(MLX5_IB_ATTR_DEVX_SUBSCRIBE_EVENT_OBJ_HANDLE,
+ MLX5_IB_OBJECT_DEVX_OBJ,
+ UVERBS_ACCESS_READ,
+ UA_OPTIONAL),
+ UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_DEVX_SUBSCRIBE_EVENT_TYPE_NUM_LIST,
+ UVERBS_ATTR_MIN_SIZE(sizeof(u16)),
+ UA_MANDATORY,
+ UA_ALLOC_AND_COPY),
+ UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_DEVX_SUBSCRIBE_EVENT_COOKIE,
+ UVERBS_ATTR_TYPE(u64),
+ UA_OPTIONAL),
+ UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_DEVX_SUBSCRIBE_EVENT_FD_NUM,
+ UVERBS_ATTR_TYPE(u32),
+ UA_OPTIONAL));
+
DECLARE_UVERBS_GLOBAL_METHODS(MLX5_IB_OBJECT_DEVX,
&UVERBS_METHOD(MLX5_IB_METHOD_DEVX_OTHER),
&UVERBS_METHOD(MLX5_IB_METHOD_DEVX_QUERY_UAR),
- &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_QUERY_EQN));
+ &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_QUERY_EQN),
+ &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_SUBSCRIBE_EVENT));
DECLARE_UVERBS_NAMED_OBJECT(MLX5_IB_OBJECT_DEVX_OBJ,
UVERBS_TYPE_ALLOC_IDR(devx_obj_cleanup),
@@ -1913,6 +2903,24 @@ DECLARE_UVERBS_NAMED_OBJECT(
O_RDONLY),
&UVERBS_METHOD(MLX5_IB_METHOD_DEVX_ASYNC_CMD_FD_ALLOC));
+DECLARE_UVERBS_NAMED_METHOD(
+ MLX5_IB_METHOD_DEVX_ASYNC_EVENT_FD_ALLOC,
+ UVERBS_ATTR_FD(MLX5_IB_ATTR_DEVX_ASYNC_EVENT_FD_ALLOC_HANDLE,
+ MLX5_IB_OBJECT_DEVX_ASYNC_EVENT_FD,
+ UVERBS_ACCESS_NEW,
+ UA_MANDATORY),
+ UVERBS_ATTR_FLAGS_IN(MLX5_IB_ATTR_DEVX_ASYNC_EVENT_FD_ALLOC_FLAGS,
+ enum mlx5_ib_uapi_devx_create_event_channel_flags,
+ UA_MANDATORY));
+
+DECLARE_UVERBS_NAMED_OBJECT(
+ MLX5_IB_OBJECT_DEVX_ASYNC_EVENT_FD,
+ UVERBS_TYPE_ALLOC_FD(sizeof(struct devx_async_event_file),
+ devx_hot_unplug_async_event_file,
+ &devx_async_event_fops, "[devx_async_event]",
+ O_RDONLY),
+ &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_ASYNC_EVENT_FD_ALLOC));
+
static bool devx_is_supported(struct ib_device *device)
{
struct mlx5_ib_dev *dev = to_mdev(device);
@@ -1933,5 +2941,8 @@ const struct uapi_definition mlx5_ib_devx_defs[] = {
UAPI_DEF_CHAIN_OBJ_TREE_NAMED(
MLX5_IB_OBJECT_DEVX_ASYNC_CMD_FD,
UAPI_DEF_IS_OBJ_SUPPORTED(devx_is_supported)),
+ UAPI_DEF_CHAIN_OBJ_TREE_NAMED(
+ MLX5_IB_OBJECT_DEVX_ASYNC_EVENT_FD,
+ UAPI_DEF_IS_OBJ_SUPPORTED(devx_is_supported)),
{},
};
diff --git a/drivers/infiniband/hw/mlx5/flow.c b/drivers/infiniband/hw/mlx5/flow.c
index 1fc302d41a53..b8841355fcd5 100644
--- a/drivers/infiniband/hw/mlx5/flow.c
+++ b/drivers/infiniband/hw/mlx5/flow.c
@@ -65,11 +65,12 @@ static const struct uverbs_attr_spec mlx5_ib_flow_type[] = {
static int UVERBS_HANDLER(MLX5_IB_METHOD_CREATE_FLOW)(
struct uverbs_attr_bundle *attrs)
{
- struct mlx5_flow_act flow_act = {.flow_tag = MLX5_FS_DEFAULT_FLOW_TAG};
+ struct mlx5_flow_context flow_context = {.flow_tag = MLX5_FS_DEFAULT_FLOW_TAG};
struct mlx5_ib_flow_handler *flow_handler;
struct mlx5_ib_flow_matcher *fs_matcher;
struct ib_uobject **arr_flow_actions;
struct ib_uflow_resources *uflow_res;
+ struct mlx5_flow_act flow_act = {};
void *devx_obj;
int dest_id, dest_type;
void *cmd_in;
@@ -172,17 +173,19 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_CREATE_FLOW)(
arr_flow_actions[i]->object);
}
- ret = uverbs_copy_from(&flow_act.flow_tag, attrs,
+ ret = uverbs_copy_from(&flow_context.flow_tag, attrs,
MLX5_IB_ATTR_CREATE_FLOW_TAG);
if (!ret) {
- if (flow_act.flow_tag >= BIT(24)) {
+ if (flow_context.flow_tag >= BIT(24)) {
ret = -EINVAL;
goto err_out;
}
- flow_act.flags |= FLOW_ACT_HAS_TAG;
+ flow_context.flags |= FLOW_CONTEXT_HAS_TAG;
}
- flow_handler = mlx5_ib_raw_fs_rule_add(dev, fs_matcher, &flow_act,
+ flow_handler = mlx5_ib_raw_fs_rule_add(dev, fs_matcher,
+ &flow_context,
+ &flow_act,
counter_id,
cmd_in, inlen,
dest_id, dest_type);
diff --git a/drivers/infiniband/hw/mlx5/ib_rep.c b/drivers/infiniband/hw/mlx5/ib_rep.c
index 269b24a3baa1..74ce9249e75a 100644
--- a/drivers/infiniband/hw/mlx5/ib_rep.c
+++ b/drivers/infiniband/hw/mlx5/ib_rep.c
@@ -14,9 +14,10 @@ mlx5_ib_set_vport_rep(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
int vport_index;
ibdev = mlx5_ib_get_uplink_ibdev(dev->priv.eswitch);
- vport_index = ibdev->free_port++;
+ vport_index = rep->vport_index;
ibdev->port[vport_index].rep = rep;
+ rep->rep_data[REP_IB].priv = ibdev;
write_lock(&ibdev->port[vport_index].roce.netdev_lock);
ibdev->port[vport_index].roce.netdev =
mlx5_ib_get_rep_netdev(dev->priv.eswitch, rep->vport);
@@ -28,7 +29,7 @@ mlx5_ib_set_vport_rep(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
static int
mlx5_ib_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
{
- int num_ports = MLX5_TOTAL_VPORTS(dev);
+ int num_ports = mlx5_eswitch_get_total_vports(dev);
const struct mlx5_ib_profile *profile;
struct mlx5_ib_dev *ibdev;
int vport_index;
@@ -50,7 +51,7 @@ mlx5_ib_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
}
ibdev->is_rep = true;
- vport_index = ibdev->free_port++;
+ vport_index = rep->vport_index;
ibdev->port[vport_index].rep = rep;
ibdev->port[vport_index].roce.netdev =
mlx5_ib_get_rep_netdev(dev->priv.eswitch, rep->vport);
@@ -60,7 +61,7 @@ mlx5_ib_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
if (!__mlx5_ib_add(ibdev, profile))
return -EINVAL;
- rep->rep_if[REP_IB].priv = ibdev;
+ rep->rep_data[REP_IB].priv = ibdev;
return 0;
}
@@ -68,15 +69,18 @@ mlx5_ib_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
static void
mlx5_ib_vport_rep_unload(struct mlx5_eswitch_rep *rep)
{
- struct mlx5_ib_dev *dev;
+ struct mlx5_ib_dev *dev = mlx5_ib_rep_to_dev(rep);
+ struct mlx5_ib_port *port;
- if (!rep->rep_if[REP_IB].priv ||
- rep->vport != MLX5_VPORT_UPLINK)
- return;
+ port = &dev->port[rep->vport_index];
+ write_lock(&port->roce.netdev_lock);
+ port->roce.netdev = NULL;
+ write_unlock(&port->roce.netdev_lock);
+ rep->rep_data[REP_IB].priv = NULL;
+ port->rep = NULL;
- dev = mlx5_ib_rep_to_dev(rep);
- __mlx5_ib_remove(dev, dev->profile, MLX5_IB_STAGE_MAX);
- rep->rep_if[REP_IB].priv = NULL;
+ if (rep->vport == MLX5_VPORT_UPLINK)
+ __mlx5_ib_remove(dev, dev->profile, MLX5_IB_STAGE_MAX);
}
static void *mlx5_ib_vport_get_proto_dev(struct mlx5_eswitch_rep *rep)
@@ -84,16 +88,17 @@ static void *mlx5_ib_vport_get_proto_dev(struct mlx5_eswitch_rep *rep)
return mlx5_ib_rep_to_dev(rep);
}
+static const struct mlx5_eswitch_rep_ops rep_ops = {
+ .load = mlx5_ib_vport_rep_load,
+ .unload = mlx5_ib_vport_rep_unload,
+ .get_proto_dev = mlx5_ib_vport_get_proto_dev,
+};
+
void mlx5_ib_register_vport_reps(struct mlx5_core_dev *mdev)
{
struct mlx5_eswitch *esw = mdev->priv.eswitch;
- struct mlx5_eswitch_rep_if rep_if = {};
-
- rep_if.load = mlx5_ib_vport_rep_load;
- rep_if.unload = mlx5_ib_vport_rep_unload;
- rep_if.get_proto_dev = mlx5_ib_vport_get_proto_dev;
- mlx5_eswitch_register_vport_reps(esw, &rep_if, REP_IB);
+ mlx5_eswitch_register_vport_reps(esw, &rep_ops, REP_IB);
}
void mlx5_ib_unregister_vport_reps(struct mlx5_core_dev *mdev)
diff --git a/drivers/infiniband/hw/mlx5/ib_rep.h b/drivers/infiniband/hw/mlx5/ib_rep.h
index 8336e0517a5c..de43b423bafc 100644
--- a/drivers/infiniband/hw/mlx5/ib_rep.h
+++ b/drivers/infiniband/hw/mlx5/ib_rep.h
@@ -28,7 +28,7 @@ struct net_device *mlx5_ib_get_rep_netdev(struct mlx5_eswitch *esw,
#else /* CONFIG_MLX5_ESWITCH */
static inline u8 mlx5_ib_eswitch_mode(struct mlx5_eswitch *esw)
{
- return SRIOV_NONE;
+ return MLX5_ESWITCH_NONE;
}
static inline
@@ -72,6 +72,6 @@ struct net_device *mlx5_ib_get_rep_netdev(struct mlx5_eswitch *esw,
static inline
struct mlx5_ib_dev *mlx5_ib_rep_to_dev(struct mlx5_eswitch_rep *rep)
{
- return (struct mlx5_ib_dev *)rep->rep_if[REP_IB].priv;
+ return rep->rep_data[REP_IB].priv;
}
#endif /* __MLX5_IB_REP_H__ */
diff --git a/drivers/infiniband/hw/mlx5/mad.c b/drivers/infiniband/hw/mlx5/mad.c
index 6c529e6f3a01..348c1df69cdc 100644
--- a/drivers/infiniband/hw/mlx5/mad.c
+++ b/drivers/infiniband/hw/mlx5/mad.c
@@ -200,19 +200,33 @@ static void pma_cnt_assign(struct ib_pma_portcounters *pma_cnt,
vl_15_dropped);
}
-static int process_pma_cmd(struct mlx5_core_dev *mdev, u8 port_num,
+static int process_pma_cmd(struct mlx5_ib_dev *dev, u8 port_num,
const struct ib_mad *in_mad, struct ib_mad *out_mad)
{
- int err;
+ struct mlx5_core_dev *mdev;
+ bool native_port = true;
+ u8 mdev_port_num;
void *out_cnt;
+ int err;
+ mdev = mlx5_ib_get_native_port_mdev(dev, port_num, &mdev_port_num);
+ if (!mdev) {
+ /* Fail to get the native port, likely due to 2nd port is still
+ * unaffiliated. In such case default to 1st port and attached
+ * PF device.
+ */
+ native_port = false;
+ mdev = dev->mdev;
+ mdev_port_num = 1;
+ }
/* Declaring support of extended counters */
if (in_mad->mad_hdr.attr_id == IB_PMA_CLASS_PORT_INFO) {
struct ib_class_port_info cpi = {};
cpi.capability_mask = IB_PMA_CLASS_CAP_EXT_WIDTH;
memcpy((out_mad->data + 40), &cpi, sizeof(cpi));
- return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
+ err = IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
+ goto done;
}
if (in_mad->mad_hdr.attr_id == IB_PMA_PORT_COUNTERS_EXT) {
@@ -221,11 +235,13 @@ static int process_pma_cmd(struct mlx5_core_dev *mdev, u8 port_num,
int sz = MLX5_ST_SZ_BYTES(query_vport_counter_out);
out_cnt = kvzalloc(sz, GFP_KERNEL);
- if (!out_cnt)
- return IB_MAD_RESULT_FAILURE;
+ if (!out_cnt) {
+ err = IB_MAD_RESULT_FAILURE;
+ goto done;
+ }
err = mlx5_core_query_vport_counter(mdev, 0, 0,
- port_num, out_cnt, sz);
+ mdev_port_num, out_cnt, sz);
if (!err)
pma_cnt_ext_assign(pma_cnt_ext, out_cnt);
} else {
@@ -234,20 +250,23 @@ static int process_pma_cmd(struct mlx5_core_dev *mdev, u8 port_num,
int sz = MLX5_ST_SZ_BYTES(ppcnt_reg);
out_cnt = kvzalloc(sz, GFP_KERNEL);
- if (!out_cnt)
- return IB_MAD_RESULT_FAILURE;
+ if (!out_cnt) {
+ err = IB_MAD_RESULT_FAILURE;
+ goto done;
+ }
- err = mlx5_core_query_ib_ppcnt(mdev, port_num,
+ err = mlx5_core_query_ib_ppcnt(mdev, mdev_port_num,
out_cnt, sz);
if (!err)
pma_cnt_assign(pma_cnt, out_cnt);
- }
-
+ }
kvfree(out_cnt);
- if (err)
- return IB_MAD_RESULT_FAILURE;
-
- return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
+ err = err ? IB_MAD_RESULT_FAILURE :
+ IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
+done:
+ if (native_port)
+ mlx5_ib_put_native_port_mdev(dev, port_num);
+ return err;
}
int mlx5_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
@@ -259,8 +278,6 @@ int mlx5_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
struct mlx5_ib_dev *dev = to_mdev(ibdev);
const struct ib_mad *in_mad = (const struct ib_mad *)in;
struct ib_mad *out_mad = (struct ib_mad *)out;
- struct mlx5_core_dev *mdev;
- u8 mdev_port_num;
int ret;
if (WARN_ON_ONCE(in_mad_size != sizeof(*in_mad) ||
@@ -269,19 +286,14 @@ int mlx5_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
memset(out_mad->data, 0, sizeof(out_mad->data));
- mdev = mlx5_ib_get_native_port_mdev(dev, port_num, &mdev_port_num);
- if (!mdev)
- return IB_MAD_RESULT_FAILURE;
-
- if (MLX5_CAP_GEN(mdev, vport_counters) &&
+ if (MLX5_CAP_GEN(dev->mdev, vport_counters) &&
in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT &&
in_mad->mad_hdr.method == IB_MGMT_METHOD_GET) {
- ret = process_pma_cmd(mdev, mdev_port_num, in_mad, out_mad);
+ ret = process_pma_cmd(dev, port_num, in_mad, out_mad);
} else {
ret = process_mad(ibdev, mad_flags, port_num, in_wc, in_grh,
in_mad, out_mad);
}
- mlx5_ib_put_native_port_mdev(dev, port_num);
return ret;
}
diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
index 340290b883fe..c2a5780cb394 100644
--- a/drivers/infiniband/hw/mlx5/main.c
+++ b/drivers/infiniband/hw/mlx5/main.c
@@ -52,6 +52,7 @@
#include <linux/mlx5/port.h>
#include <linux/mlx5/vport.h>
#include <linux/mlx5/fs.h>
+#include <linux/mlx5/eswitch.h>
#include <linux/list.h>
#include <rdma/ib_smi.h>
#include <rdma/ib_umem.h>
@@ -888,7 +889,7 @@ static int mlx5_ib_query_device(struct ib_device *ibdev,
}
props->device_cap_flags |= IB_DEVICE_MEM_MGT_EXTENSIONS;
if (MLX5_CAP_GEN(mdev, sho)) {
- props->device_cap_flags |= IB_DEVICE_SIGNATURE_HANDOVER;
+ props->device_cap_flags |= IB_DEVICE_INTEGRITY_HANDOVER;
/* At this stage no support for signature handover */
props->sig_prot_cap = IB_PROT_T10DIF_TYPE_1 |
IB_PROT_T10DIF_TYPE_2 |
@@ -1008,6 +1009,8 @@ static int mlx5_ib_query_device(struct ib_device *ibdev,
props->max_srq_sge = max_rq_sg - 1;
props->max_fast_reg_page_list_len =
1 << MLX5_CAP_GEN(mdev, log_max_klm_list_size);
+ props->max_pi_fast_reg_page_list_len =
+ props->max_fast_reg_page_list_len / 2;
get_atomic_caps_qp(dev, props);
props->masked_atomic_cap = IB_ATOMIC_NONE;
props->max_mcast_grp = 1 << MLX5_CAP_GEN(mdev, log_max_mcg);
@@ -1043,15 +1046,19 @@ static int mlx5_ib_query_device(struct ib_device *ibdev,
}
if (MLX5_CAP_GEN(mdev, tag_matching)) {
- props->tm_caps.max_rndv_hdr_size = MLX5_TM_MAX_RNDV_MSG_SIZE;
props->tm_caps.max_num_tags =
(1 << MLX5_CAP_GEN(mdev, log_tag_matching_list_sz)) - 1;
- props->tm_caps.flags = IB_TM_CAP_RC;
props->tm_caps.max_ops =
1 << MLX5_CAP_GEN(mdev, log_max_qp_sz);
props->tm_caps.max_sge = MLX5_TM_MAX_SGE;
}
+ if (MLX5_CAP_GEN(mdev, tag_matching) &&
+ MLX5_CAP_GEN(mdev, rndv_offload_rc)) {
+ props->tm_caps.flags = IB_TM_CAP_RNDV_RC;
+ props->tm_caps.max_rndv_hdr_size = MLX5_TM_MAX_RNDV_MSG_SIZE;
+ }
+
if (MLX5_CAP_GEN(dev->mdev, cq_moderation)) {
props->cq_caps.max_cq_moderation_count =
MLX5_MAX_CQ_COUNT;
@@ -2666,11 +2673,15 @@ int parse_flow_flow_action(struct mlx5_ib_flow_action *maction,
}
}
-static int parse_flow_attr(struct mlx5_core_dev *mdev, u32 *match_c,
- u32 *match_v, const union ib_flow_spec *ib_spec,
+static int parse_flow_attr(struct mlx5_core_dev *mdev,
+ struct mlx5_flow_spec *spec,
+ const union ib_flow_spec *ib_spec,
const struct ib_flow_attr *flow_attr,
struct mlx5_flow_act *action, u32 prev_type)
{
+ struct mlx5_flow_context *flow_context = &spec->flow_context;
+ u32 *match_c = spec->match_criteria;
+ u32 *match_v = spec->match_value;
void *misc_params_c = MLX5_ADDR_OF(fte_match_param, match_c,
misc_parameters);
void *misc_params_v = MLX5_ADDR_OF(fte_match_param, match_v,
@@ -2989,8 +3000,8 @@ static int parse_flow_attr(struct mlx5_core_dev *mdev, u32 *match_c,
if (ib_spec->flow_tag.tag_id >= BIT(24))
return -EINVAL;
- action->flow_tag = ib_spec->flow_tag.tag_id;
- action->flags |= FLOW_ACT_HAS_TAG;
+ flow_context->flow_tag = ib_spec->flow_tag.tag_id;
+ flow_context->flags |= FLOW_CONTEXT_HAS_TAG;
break;
case IB_FLOW_SPEC_ACTION_DROP:
if (FIELDS_NOT_SUPPORTED(ib_spec->drop,
@@ -3084,7 +3095,8 @@ is_valid_esp_aes_gcm(struct mlx5_core_dev *mdev,
return VALID_SPEC_NA;
return is_crypto && is_ipsec &&
- (!egress || (!is_drop && !(flow_act->flags & FLOW_ACT_HAS_TAG))) ?
+ (!egress || (!is_drop &&
+ !(spec->flow_context.flags & FLOW_CONTEXT_HAS_TAG))) ?
VALID_SPEC_VALID : VALID_SPEC_INVALID;
}
@@ -3252,11 +3264,14 @@ static struct mlx5_ib_flow_prio *get_flow_table(struct mlx5_ib_dev *dev,
int max_table_size;
int num_entries;
int num_groups;
+ bool esw_encap;
u32 flags = 0;
int priority;
max_table_size = BIT(MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev,
log_max_ft_size));
+ esw_encap = mlx5_eswitch_get_encap_mode(dev->mdev) !=
+ DEVLINK_ESWITCH_ENCAP_MODE_NONE;
if (flow_attr->type == IB_FLOW_ATTR_NORMAL) {
enum mlx5_flow_namespace_type fn_type;
@@ -3269,10 +3284,10 @@ static struct mlx5_ib_flow_prio *get_flow_table(struct mlx5_ib_dev *dev,
if (ft_type == MLX5_IB_FT_RX) {
fn_type = MLX5_FLOW_NAMESPACE_BYPASS;
prio = &dev->flow_db->prios[priority];
- if (!dev->is_rep &&
+ if (!dev->is_rep && !esw_encap &&
MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, decap))
flags |= MLX5_FLOW_TABLE_TUNNEL_EN_DECAP;
- if (!dev->is_rep &&
+ if (!dev->is_rep && !esw_encap &&
MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev,
reformat_l3_tunnel_to_l2))
flags |= MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT;
@@ -3282,7 +3297,7 @@ static struct mlx5_ib_flow_prio *get_flow_table(struct mlx5_ib_dev *dev,
log_max_ft_size));
fn_type = MLX5_FLOW_NAMESPACE_EGRESS;
prio = &dev->flow_db->egress_prios[priority];
- if (!dev->is_rep &&
+ if (!dev->is_rep && !esw_encap &&
MLX5_CAP_FLOWTABLE_NIC_TX(dev->mdev, reformat))
flags |= MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT;
}
@@ -3464,6 +3479,37 @@ free:
return ret;
}
+static void mlx5_ib_set_rule_source_port(struct mlx5_ib_dev *dev,
+ struct mlx5_flow_spec *spec,
+ struct mlx5_eswitch_rep *rep)
+{
+ struct mlx5_eswitch *esw = dev->mdev->priv.eswitch;
+ void *misc;
+
+ if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
+ misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
+ misc_parameters_2);
+
+ MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0,
+ mlx5_eswitch_get_vport_metadata_for_match(esw,
+ rep->vport));
+ misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
+ misc_parameters_2);
+
+ MLX5_SET_TO_ONES(fte_match_set_misc2, misc, metadata_reg_c_0);
+ } else {
+ misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
+ misc_parameters);
+
+ MLX5_SET(fte_match_set_misc, misc, source_port, rep->vport);
+
+ misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
+ misc_parameters);
+
+ MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
+ }
+}
+
static struct mlx5_ib_flow_handler *_create_flow_rule(struct mlx5_ib_dev *dev,
struct mlx5_ib_flow_prio *ft_prio,
const struct ib_flow_attr *flow_attr,
@@ -3473,7 +3519,7 @@ static struct mlx5_ib_flow_handler *_create_flow_rule(struct mlx5_ib_dev *dev,
{
struct mlx5_flow_table *ft = ft_prio->flow_table;
struct mlx5_ib_flow_handler *handler;
- struct mlx5_flow_act flow_act = {.flow_tag = MLX5_FS_DEFAULT_FLOW_TAG};
+ struct mlx5_flow_act flow_act = {};
struct mlx5_flow_spec *spec;
struct mlx5_flow_destination dest_arr[2] = {};
struct mlx5_flow_destination *rule_dst = dest_arr;
@@ -3504,8 +3550,7 @@ static struct mlx5_ib_flow_handler *_create_flow_rule(struct mlx5_ib_dev *dev,
}
for (spec_index = 0; spec_index < flow_attr->num_of_specs; spec_index++) {
- err = parse_flow_attr(dev->mdev, spec->match_criteria,
- spec->match_value,
+ err = parse_flow_attr(dev->mdev, spec,
ib_flow, flow_attr, &flow_act,
prev_type);
if (err < 0)
@@ -3519,19 +3564,15 @@ static struct mlx5_ib_flow_handler *_create_flow_rule(struct mlx5_ib_dev *dev,
set_underlay_qp(dev, spec, underlay_qpn);
if (dev->is_rep) {
- void *misc;
+ struct mlx5_eswitch_rep *rep;
- if (!dev->port[flow_attr->port - 1].rep) {
+ rep = dev->port[flow_attr->port - 1].rep;
+ if (!rep) {
err = -EINVAL;
goto free;
}
- misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
- misc_parameters);
- MLX5_SET(fte_match_set_misc, misc, source_port,
- dev->port[flow_attr->port - 1].rep->vport);
- misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
- misc_parameters);
- MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
+
+ mlx5_ib_set_rule_source_port(dev, spec, rep);
}
spec->match_criteria_enable = get_match_criteria_enable(spec->match_criteria);
@@ -3572,11 +3613,11 @@ static struct mlx5_ib_flow_handler *_create_flow_rule(struct mlx5_ib_dev *dev,
MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO;
}
- if ((flow_act.flags & FLOW_ACT_HAS_TAG) &&
+ if ((spec->flow_context.flags & FLOW_CONTEXT_HAS_TAG) &&
(flow_attr->type == IB_FLOW_ATTR_ALL_DEFAULT ||
flow_attr->type == IB_FLOW_ATTR_MC_DEFAULT)) {
mlx5_ib_warn(dev, "Flow tag %u and attribute type %x isn't allowed in leftovers\n",
- flow_act.flow_tag, flow_attr->type);
+ spec->flow_context.flow_tag, flow_attr->type);
err = -EINVAL;
goto free;
}
@@ -3892,6 +3933,7 @@ _get_flow_table(struct mlx5_ib_dev *dev,
struct mlx5_flow_namespace *ns = NULL;
struct mlx5_ib_flow_prio *prio = NULL;
int max_table_size = 0;
+ bool esw_encap;
u32 flags = 0;
int priority;
@@ -3900,22 +3942,30 @@ _get_flow_table(struct mlx5_ib_dev *dev,
else
priority = ib_prio_to_core_prio(fs_matcher->priority, false);
+ esw_encap = mlx5_eswitch_get_encap_mode(dev->mdev) !=
+ DEVLINK_ESWITCH_ENCAP_MODE_NONE;
if (fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_BYPASS) {
max_table_size = BIT(MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev,
log_max_ft_size));
- if (MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, decap))
+ if (MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, decap) && !esw_encap)
flags |= MLX5_FLOW_TABLE_TUNNEL_EN_DECAP;
if (MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev,
- reformat_l3_tunnel_to_l2))
+ reformat_l3_tunnel_to_l2) &&
+ !esw_encap)
flags |= MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT;
} else if (fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_EGRESS) {
max_table_size = BIT(
MLX5_CAP_FLOWTABLE_NIC_TX(dev->mdev, log_max_ft_size));
- if (MLX5_CAP_FLOWTABLE_NIC_TX(dev->mdev, reformat))
+ if (MLX5_CAP_FLOWTABLE_NIC_TX(dev->mdev, reformat) && !esw_encap)
flags |= MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT;
} else if (fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_FDB) {
max_table_size = BIT(
MLX5_CAP_ESW_FLOWTABLE_FDB(dev->mdev, log_max_ft_size));
+ if (MLX5_CAP_ESW_FLOWTABLE_FDB(dev->mdev, decap) && esw_encap)
+ flags |= MLX5_FLOW_TABLE_TUNNEL_EN_DECAP;
+ if (MLX5_CAP_ESW_FLOWTABLE_FDB(dev->mdev, reformat_l3_tunnel_to_l2) &&
+ esw_encap)
+ flags |= MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT;
priority = FDB_BYPASS_PATH;
}
@@ -3947,6 +3997,7 @@ _create_raw_flow_rule(struct mlx5_ib_dev *dev,
struct mlx5_ib_flow_prio *ft_prio,
struct mlx5_flow_destination *dst,
struct mlx5_ib_flow_matcher *fs_matcher,
+ struct mlx5_flow_context *flow_context,
struct mlx5_flow_act *flow_act,
void *cmd_in, int inlen,
int dst_num)
@@ -3969,6 +4020,7 @@ _create_raw_flow_rule(struct mlx5_ib_dev *dev,
memcpy(spec->match_criteria, fs_matcher->matcher_mask.match_params,
fs_matcher->mask_len);
spec->match_criteria_enable = fs_matcher->match_criteria_enable;
+ spec->flow_context = *flow_context;
handler->rule = mlx5_add_flow_rules(ft, spec,
flow_act, dst, dst_num);
@@ -4033,6 +4085,7 @@ static bool raw_fs_is_multicast(struct mlx5_ib_flow_matcher *fs_matcher,
struct mlx5_ib_flow_handler *
mlx5_ib_raw_fs_rule_add(struct mlx5_ib_dev *dev,
struct mlx5_ib_flow_matcher *fs_matcher,
+ struct mlx5_flow_context *flow_context,
struct mlx5_flow_act *flow_act,
u32 counter_id,
void *cmd_in, int inlen, int dest_id,
@@ -4085,7 +4138,8 @@ mlx5_ib_raw_fs_rule_add(struct mlx5_ib_dev *dev,
dst_num++;
}
- handler = _create_raw_flow_rule(dev, ft_prio, dst, fs_matcher, flow_act,
+ handler = _create_raw_flow_rule(dev, ft_prio, dst, fs_matcher,
+ flow_context, flow_act,
cmd_in, inlen, dst_num);
if (IS_ERR(handler)) {
@@ -4457,7 +4511,7 @@ static void mlx5_ib_handle_internal_error(struct mlx5_ib_dev *ibdev)
* lock/unlock above locks Now need to arm all involved CQs.
*/
list_for_each_entry(mcq, &cq_armed_list, reset_notify) {
- mcq->comp(mcq);
+ mcq->comp(mcq, NULL);
}
spin_unlock_irqrestore(&ibdev->reset_flow_resource_lock, flags);
}
@@ -4676,7 +4730,7 @@ static int __get_port_caps(struct mlx5_ib_dev *dev, u8 port)
int err = -ENOMEM;
struct ib_udata uhw = {.inlen = 0, .outlen = 0};
- pprops = kmalloc(sizeof(*pprops), GFP_KERNEL);
+ pprops = kzalloc(sizeof(*pprops), GFP_KERNEL);
if (!pprops)
goto out;
@@ -4690,7 +4744,6 @@ static int __get_port_caps(struct mlx5_ib_dev *dev, u8 port)
goto out;
}
- memset(pprops, 0, sizeof(*pprops));
err = mlx5_ib_query_port(&dev->ib_dev, port, pprops);
if (err) {
mlx5_ib_warn(dev, "query_port %d failed %d\n",
@@ -4891,18 +4944,19 @@ static int create_dev_resources(struct mlx5_ib_resources *devr)
if (ret)
goto error0;
- devr->c0 = mlx5_ib_create_cq(&dev->ib_dev, &cq_attr, NULL);
- if (IS_ERR(devr->c0)) {
- ret = PTR_ERR(devr->c0);
+ devr->c0 = rdma_zalloc_drv_obj(ibdev, ib_cq);
+ if (!devr->c0) {
+ ret = -ENOMEM;
goto error1;
}
- devr->c0->device = &dev->ib_dev;
- devr->c0->uobject = NULL;
- devr->c0->comp_handler = NULL;
- devr->c0->event_handler = NULL;
- devr->c0->cq_context = NULL;
+
+ devr->c0->device = &dev->ib_dev;
atomic_set(&devr->c0->usecnt, 0);
+ ret = mlx5_ib_create_cq(devr->c0, &cq_attr, NULL);
+ if (ret)
+ goto err_create_cq;
+
devr->x0 = mlx5_ib_alloc_xrcd(&dev->ib_dev, NULL);
if (IS_ERR(devr->x0)) {
ret = PTR_ERR(devr->x0);
@@ -4994,6 +5048,8 @@ error3:
mlx5_ib_dealloc_xrcd(devr->x0, NULL);
error2:
mlx5_ib_destroy_cq(devr->c0, NULL);
+err_create_cq:
+ kfree(devr->c0);
error1:
mlx5_ib_dealloc_pd(devr->p0, NULL);
error0:
@@ -5012,6 +5068,7 @@ static void destroy_dev_resources(struct mlx5_ib_resources *devr)
mlx5_ib_dealloc_xrcd(devr->x0, NULL);
mlx5_ib_dealloc_xrcd(devr->x1, NULL);
mlx5_ib_destroy_cq(devr->c0, NULL);
+ kfree(devr->c0);
mlx5_ib_dealloc_pd(devr->p0, NULL);
kfree(devr->p0);
@@ -5424,7 +5481,8 @@ static struct rdma_hw_stats *mlx5_ib_alloc_hw_stats(struct ib_device *ibdev,
static int mlx5_ib_query_q_counters(struct mlx5_core_dev *mdev,
struct mlx5_ib_port *port,
- struct rdma_hw_stats *stats)
+ struct rdma_hw_stats *stats,
+ u16 set_id)
{
int outlen = MLX5_ST_SZ_BYTES(query_q_counter_out);
void *out;
@@ -5435,9 +5493,7 @@ static int mlx5_ib_query_q_counters(struct mlx5_core_dev *mdev,
if (!out)
return -ENOMEM;
- ret = mlx5_core_query_q_counter(mdev,
- port->cnts.set_id, 0,
- out, outlen);
+ ret = mlx5_core_query_q_counter(mdev, set_id, 0, out, outlen);
if (ret)
goto free;
@@ -5497,7 +5553,8 @@ static int mlx5_ib_get_hw_stats(struct ib_device *ibdev,
port->cnts.num_ext_ppcnt_counters;
/* q_counters are per IB device, query the master mdev */
- ret = mlx5_ib_query_q_counters(dev->mdev, port, stats);
+ ret = mlx5_ib_query_q_counters(dev->mdev, port, stats,
+ port->cnts.set_id);
if (ret)
return ret;
@@ -5533,6 +5590,68 @@ done:
return num_counters;
}
+static struct rdma_hw_stats *
+mlx5_ib_counter_alloc_stats(struct rdma_counter *counter)
+{
+ struct mlx5_ib_dev *dev = to_mdev(counter->device);
+ struct mlx5_ib_port *port = &dev->port[counter->port - 1];
+
+ /* Q counters are in the beginning of all counters */
+ return rdma_alloc_hw_stats_struct(port->cnts.names,
+ port->cnts.num_q_counters,
+ RDMA_HW_STATS_DEFAULT_LIFESPAN);
+}
+
+static int mlx5_ib_counter_update_stats(struct rdma_counter *counter)
+{
+ struct mlx5_ib_dev *dev = to_mdev(counter->device);
+ struct mlx5_ib_port *port = &dev->port[counter->port - 1];
+
+ return mlx5_ib_query_q_counters(dev->mdev, port,
+ counter->stats, counter->id);
+}
+
+static int mlx5_ib_counter_bind_qp(struct rdma_counter *counter,
+ struct ib_qp *qp)
+{
+ struct mlx5_ib_dev *dev = to_mdev(qp->device);
+ u16 cnt_set_id = 0;
+ int err;
+
+ if (!counter->id) {
+ err = mlx5_cmd_alloc_q_counter(dev->mdev,
+ &cnt_set_id,
+ MLX5_SHARED_RESOURCE_UID);
+ if (err)
+ return err;
+ counter->id = cnt_set_id;
+ }
+
+ err = mlx5_ib_qp_set_counter(qp, counter);
+ if (err)
+ goto fail_set_counter;
+
+ return 0;
+
+fail_set_counter:
+ mlx5_core_dealloc_q_counter(dev->mdev, cnt_set_id);
+ counter->id = 0;
+
+ return err;
+}
+
+static int mlx5_ib_counter_unbind_qp(struct ib_qp *qp)
+{
+ return mlx5_ib_qp_set_counter(qp, NULL);
+}
+
+static int mlx5_ib_counter_dealloc(struct rdma_counter *counter)
+{
+ struct mlx5_ib_dev *dev = to_mdev(counter->device);
+
+ return mlx5_core_dealloc_q_counter(dev->mdev, counter->id);
+}
+
static int mlx5_ib_rn_get_params(struct ib_device *device, u8 port_num,
enum rdma_netdev_t type,
struct rdma_netdev_alloc_params *params)
@@ -6044,7 +6163,6 @@ 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.owner = THIS_MODULE;
dev->ib_dev.node_type = RDMA_NODE_IB_CA;
dev->ib_dev.local_dma_lkey = 0 /* not supported for now */;
dev->ib_dev.phys_port_cnt = dev->num_ports;
@@ -6124,8 +6242,13 @@ static void mlx5_ib_stage_flow_db_cleanup(struct mlx5_ib_dev *dev)
}
static const struct ib_device_ops mlx5_ib_dev_ops = {
+ .owner = THIS_MODULE,
+ .driver_id = RDMA_DRIVER_MLX5,
+ .uverbs_abi_ver = MLX5_IB_UVERBS_ABI_VERSION,
+
.add_gid = mlx5_ib_add_gid,
.alloc_mr = mlx5_ib_alloc_mr,
+ .alloc_mr_integrity = mlx5_ib_alloc_mr_integrity,
.alloc_pd = mlx5_ib_alloc_pd,
.alloc_ucontext = mlx5_ib_alloc_ucontext,
.attach_mcast = mlx5_ib_mcg_attach,
@@ -6155,6 +6278,7 @@ static const struct ib_device_ops mlx5_ib_dev_ops = {
.get_dma_mr = mlx5_ib_get_dma_mr,
.get_link_layer = mlx5_ib_port_link_layer,
.map_mr_sg = mlx5_ib_map_mr_sg,
+ .map_mr_sg_pi = mlx5_ib_map_mr_sg_pi,
.mmap = mlx5_ib_mmap,
.modify_cq = mlx5_ib_modify_cq,
.modify_device = mlx5_ib_modify_device,
@@ -6179,6 +6303,7 @@ static const struct ib_device_ops mlx5_ib_dev_ops = {
.resize_cq = mlx5_ib_resize_cq,
INIT_RDMA_OBJ_SIZE(ib_ah, mlx5_ib_ah, ibah),
+ INIT_RDMA_OBJ_SIZE(ib_cq, mlx5_ib_cq, ibcq),
INIT_RDMA_OBJ_SIZE(ib_pd, mlx5_ib_pd, ibpd),
INIT_RDMA_OBJ_SIZE(ib_srq, mlx5_ib_srq, ibsrq),
INIT_RDMA_OBJ_SIZE(ib_ucontext, mlx5_ib_ucontext, ibucontext),
@@ -6221,7 +6346,6 @@ static int mlx5_ib_stage_caps_init(struct mlx5_ib_dev *dev)
struct mlx5_core_dev *mdev = dev->mdev;
int err;
- dev->ib_dev.uverbs_abi_ver = MLX5_IB_UVERBS_ABI_VERSION;
dev->ib_dev.uverbs_cmd_mask =
(1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
(1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |
@@ -6290,7 +6414,6 @@ static int mlx5_ib_stage_caps_init(struct mlx5_ib_dev *dev)
if (mlx5_accel_ipsec_device_caps(dev->mdev) &
MLX5_ACCEL_IPSEC_CAP_DEVICE)
ib_set_device_ops(&dev->ib_dev, &mlx5_ib_dev_flow_ipsec_ops);
- dev->ib_dev.driver_id = RDMA_DRIVER_MLX5;
ib_set_device_ops(&dev->ib_dev, &mlx5_ib_dev_ops);
if (IS_ENABLED(CONFIG_INFINIBAND_USER_ACCESS))
@@ -6305,6 +6428,8 @@ static int mlx5_ib_stage_caps_init(struct mlx5_ib_dev *dev)
MLX5_CAP_GEN(dev->mdev, disable_local_lb_mc)))
mutex_init(&dev->lb.mutex);
+ dev->ib_dev.use_cq_dim = true;
+
return 0;
}
@@ -6452,6 +6577,11 @@ static void mlx5_ib_stage_odp_cleanup(struct mlx5_ib_dev *dev)
static const struct ib_device_ops mlx5_ib_dev_hw_stats_ops = {
.alloc_hw_stats = mlx5_ib_alloc_hw_stats,
.get_hw_stats = mlx5_ib_get_hw_stats,
+ .counter_bind_qp = mlx5_ib_counter_bind_qp,
+ .counter_unbind_qp = mlx5_ib_counter_unbind_qp,
+ .counter_dealloc = mlx5_ib_counter_dealloc,
+ .counter_alloc_stats = mlx5_ib_counter_alloc_stats,
+ .counter_update_stats = mlx5_ib_counter_update_stats,
};
static int mlx5_ib_stage_counters_init(struct mlx5_ib_dev *dev)
@@ -6572,15 +6702,19 @@ static int mlx5_ib_stage_devx_init(struct mlx5_ib_dev *dev)
int uid;
uid = mlx5_ib_devx_create(dev, false);
- if (uid > 0)
+ if (uid > 0) {
dev->devx_whitelist_uid = uid;
+ mlx5_ib_devx_init_event_table(dev);
+ }
return 0;
}
static void mlx5_ib_stage_devx_cleanup(struct mlx5_ib_dev *dev)
{
- if (dev->devx_whitelist_uid)
+ if (dev->devx_whitelist_uid) {
+ mlx5_ib_devx_cleanup_event_table(dev);
mlx5_ib_devx_destroy(dev, dev->devx_whitelist_uid);
+ }
}
void __mlx5_ib_remove(struct mlx5_ib_dev *dev,
@@ -6779,7 +6913,7 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev)
printk_once(KERN_INFO "%s", mlx5_version);
if (MLX5_ESWITCH_MANAGER(mdev) &&
- mlx5_ib_eswitch_mode(mdev->priv.eswitch) == SRIOV_OFFLOADS) {
+ mlx5_ib_eswitch_mode(mdev->priv.eswitch) == MLX5_ESWITCH_OFFLOADS) {
if (!mlx5_core_mp_enabled(mdev))
mlx5_ib_register_vport_reps(mdev);
return mdev;
diff --git a/drivers/infiniband/hw/mlx5/mem.c b/drivers/infiniband/hw/mlx5/mem.c
index 9f90be296ee0..fe1a76d8531c 100644
--- a/drivers/infiniband/hw/mlx5/mem.c
+++ b/drivers/infiniband/hw/mlx5/mem.c
@@ -55,9 +55,10 @@ void mlx5_ib_cont_pages(struct ib_umem *umem, u64 addr,
int i = 0;
struct scatterlist *sg;
int entry;
- unsigned long page_shift = umem->page_shift;
if (umem->is_odp) {
+ unsigned int page_shift = to_ib_umem_odp(umem)->page_shift;
+
*ncont = ib_umem_page_count(umem);
*count = *ncont << (page_shift - PAGE_SHIFT);
*shift = page_shift;
@@ -67,15 +68,15 @@ void mlx5_ib_cont_pages(struct ib_umem *umem, u64 addr,
return;
}
- addr = addr >> page_shift;
+ addr = addr >> PAGE_SHIFT;
tmp = (unsigned long)addr;
m = find_first_bit(&tmp, BITS_PER_LONG);
if (max_page_shift)
- m = min_t(unsigned long, max_page_shift - page_shift, m);
+ m = min_t(unsigned long, max_page_shift - PAGE_SHIFT, m);
for_each_sg(umem->sg_head.sgl, sg, umem->nmap, entry) {
- len = sg_dma_len(sg) >> page_shift;
- pfn = sg_dma_address(sg) >> page_shift;
+ len = sg_dma_len(sg) >> PAGE_SHIFT;
+ pfn = sg_dma_address(sg) >> PAGE_SHIFT;
if (base + p != pfn) {
/* If either the offset or the new
* base are unaligned update m
@@ -107,7 +108,7 @@ void mlx5_ib_cont_pages(struct ib_umem *umem, u64 addr,
*ncont = 0;
}
- *shift = page_shift + m;
+ *shift = PAGE_SHIFT + m;
*count = i;
}
@@ -140,8 +141,7 @@ void __mlx5_ib_populate_pas(struct mlx5_ib_dev *dev, struct ib_umem *umem,
int page_shift, size_t offset, size_t num_pages,
__be64 *pas, int access_flags)
{
- unsigned long umem_page_shift = umem->page_shift;
- int shift = page_shift - umem_page_shift;
+ int shift = page_shift - PAGE_SHIFT;
int mask = (1 << shift) - 1;
int i, k, idx;
u64 cur = 0;
@@ -165,7 +165,7 @@ void __mlx5_ib_populate_pas(struct mlx5_ib_dev *dev, struct ib_umem *umem,
i = 0;
for_each_sg(umem->sg_head.sgl, sg, umem->nmap, entry) {
- len = sg_dma_len(sg) >> umem_page_shift;
+ len = sg_dma_len(sg) >> PAGE_SHIFT;
base = sg_dma_address(sg);
/* Skip elements below offset */
@@ -184,7 +184,7 @@ void __mlx5_ib_populate_pas(struct mlx5_ib_dev *dev, struct ib_umem *umem,
for (; k < len; k++) {
if (!(i & mask)) {
- cur = base + (k << umem_page_shift);
+ cur = base + (k << PAGE_SHIFT);
cur |= access_flags;
idx = (i >> shift) - offset;
diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h
index 40eb8be482e4..c482f19958b3 100644
--- a/drivers/infiniband/hw/mlx5/mlx5_ib.h
+++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h
@@ -431,9 +431,6 @@ struct mlx5_ib_qp {
int create_type;
- /* Store signature errors */
- bool signature_en;
-
struct list_head qps_list;
struct list_head cq_recv_list;
struct list_head cq_send_list;
@@ -442,6 +439,10 @@ struct mlx5_ib_qp {
u32 flags_en;
/* storage for qp sub type when core qp type is IB_QPT_DRIVER */
enum ib_qp_type qp_sub_type;
+ /* A flag to indicate if there's a new counter is configured
+ * but not take effective
+ */
+ u32 counter_pending;
};
struct mlx5_ib_cq_buf {
@@ -587,6 +588,9 @@ struct mlx5_ib_mr {
void *descs;
dma_addr_t desc_map;
int ndescs;
+ int data_length;
+ int meta_ndescs;
+ int meta_length;
int max_descs;
int desc_size;
int access_mode;
@@ -605,6 +609,13 @@ struct mlx5_ib_mr {
int access_flags; /* Needed for rereg MR */
struct mlx5_ib_mr *parent;
+ /* Needed for IB_MR_TYPE_INTEGRITY */
+ struct mlx5_ib_mr *pi_mr;
+ struct mlx5_ib_mr *klm_mr;
+ struct mlx5_ib_mr *mtt_mr;
+ u64 data_iova;
+ u64 pi_iova;
+
atomic_t num_leaf_free;
wait_queue_head_t q_leaf_free;
struct mlx5_async_work cb_work;
@@ -920,6 +931,7 @@ struct mlx5_ib_lb_state {
};
struct mlx5_ib_pf_eq {
+ struct notifier_block irq_nb;
struct mlx5_ib_dev *dev;
struct mlx5_eq *core;
struct work_struct work;
@@ -928,6 +940,13 @@ struct mlx5_ib_pf_eq {
mempool_t *pool;
};
+struct mlx5_devx_event_table {
+ struct mlx5_nb devx_nb;
+ /* serialize updating the event_xa */
+ struct mutex event_xa_lock;
+ struct xarray event_xa;
+};
+
struct mlx5_ib_dev {
struct ib_device ib_dev;
struct mlx5_core_dev *mdev;
@@ -977,7 +996,7 @@ struct mlx5_ib_dev {
u16 devx_whitelist_uid;
struct mlx5_srq_table srq_table;
struct mlx5_async_ctx async_ctx;
- int free_port;
+ struct mlx5_devx_event_table devx_event_table;
};
static inline struct mlx5_ib_cq *to_mibcq(struct mlx5_core_cq *mcq)
@@ -1115,10 +1134,9 @@ int mlx5_ib_read_user_wqe_rq(struct mlx5_ib_qp *qp, int wqe_index, void *buffer,
int buflen, size_t *bc);
int mlx5_ib_read_user_wqe_srq(struct mlx5_ib_srq *srq, int wqe_index,
void *buffer, int buflen, size_t *bc);
-struct ib_cq *mlx5_ib_create_cq(struct ib_device *ibdev,
- const struct ib_cq_init_attr *attr,
- struct ib_udata *udata);
-int mlx5_ib_destroy_cq(struct ib_cq *cq, struct ib_udata *udata);
+int mlx5_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata);
+void mlx5_ib_destroy_cq(struct ib_cq *cq, struct ib_udata *udata);
int mlx5_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc);
int mlx5_ib_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags);
int mlx5_ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period);
@@ -1148,8 +1166,15 @@ int mlx5_ib_rereg_user_mr(struct ib_mr *ib_mr, int flags, u64 start,
int mlx5_ib_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata);
struct ib_mr *mlx5_ib_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type,
u32 max_num_sg, struct ib_udata *udata);
+struct ib_mr *mlx5_ib_alloc_mr_integrity(struct ib_pd *pd,
+ u32 max_num_sg,
+ u32 max_num_meta_sg);
int mlx5_ib_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents,
unsigned int *sg_offset);
+int mlx5_ib_map_mr_sg_pi(struct ib_mr *ibmr, struct scatterlist *data_sg,
+ int data_sg_nents, unsigned int *data_sg_offset,
+ struct scatterlist *meta_sg, int meta_sg_nents,
+ unsigned int *meta_sg_offset);
int mlx5_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
const struct ib_wc *in_wc, const struct ib_grh *in_grh,
const struct ib_mad_hdr *in, size_t in_mad_size,
@@ -1201,7 +1226,7 @@ int mlx5_ib_check_mr_status(struct ib_mr *ibmr, u32 check_mask,
struct ib_wq *mlx5_ib_create_wq(struct ib_pd *pd,
struct ib_wq_init_attr *init_attr,
struct ib_udata *udata);
-int mlx5_ib_destroy_wq(struct ib_wq *wq, struct ib_udata *udata);
+void mlx5_ib_destroy_wq(struct ib_wq *wq, struct ib_udata *udata);
int mlx5_ib_modify_wq(struct ib_wq *wq, struct ib_wq_attr *wq_attr,
u32 wq_attr_mask, struct ib_udata *udata);
struct ib_rwq_ind_table *mlx5_ib_create_rwq_ind_table(struct ib_device *device,
@@ -1311,11 +1336,14 @@ void mlx5_ib_put_native_port_mdev(struct mlx5_ib_dev *dev,
#if IS_ENABLED(CONFIG_INFINIBAND_USER_ACCESS)
int mlx5_ib_devx_create(struct mlx5_ib_dev *dev, bool is_user);
void mlx5_ib_devx_destroy(struct mlx5_ib_dev *dev, u16 uid);
+void mlx5_ib_devx_init_event_table(struct mlx5_ib_dev *dev);
+void mlx5_ib_devx_cleanup_event_table(struct mlx5_ib_dev *dev);
const struct uverbs_object_tree_def *mlx5_ib_get_devx_tree(void);
extern const struct uapi_definition mlx5_ib_devx_defs[];
extern const struct uapi_definition mlx5_ib_flow_defs[];
struct mlx5_ib_flow_handler *mlx5_ib_raw_fs_rule_add(
struct mlx5_ib_dev *dev, struct mlx5_ib_flow_matcher *fs_matcher,
+ struct mlx5_flow_context *flow_context,
struct mlx5_flow_act *flow_act, u32 counter_id,
void *cmd_in, int inlen, int dest_id, int dest_type);
bool mlx5_ib_devx_is_flow_dest(void *obj, int *dest_id, int *dest_type);
@@ -1327,6 +1355,8 @@ static inline int
mlx5_ib_devx_create(struct mlx5_ib_dev *dev,
bool is_user) { return -EOPNOTSUPP; }
static inline void mlx5_ib_devx_destroy(struct mlx5_ib_dev *dev, u16 uid) {}
+static inline void mlx5_ib_devx_init_event_table(struct mlx5_ib_dev *dev) {}
+static inline void mlx5_ib_devx_cleanup_event_table(struct mlx5_ib_dev *dev) {}
static inline bool mlx5_ib_devx_is_flow_dest(void *obj, int *dest_id,
int *dest_type)
{
@@ -1442,4 +1472,6 @@ void mlx5_ib_put_xlt_emergency_page(void);
int bfregn_to_uar_index(struct mlx5_ib_dev *dev,
struct mlx5_bfreg_info *bfregi, u32 bfregn,
bool dyn_bfreg);
+
+int mlx5_ib_qp_set_counter(struct ib_qp *qp, struct rdma_counter *counter);
#endif /* MLX5_IB_H */
diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c
index 5f09699fab98..20ece6e0b2fc 100644
--- a/drivers/infiniband/hw/mlx5/mr.c
+++ b/drivers/infiniband/hw/mlx5/mr.c
@@ -130,7 +130,7 @@ static void reg_mr_callback(int status, struct mlx5_async_work *context)
struct mlx5_cache_ent *ent = &cache->ent[c];
u8 key;
unsigned long flags;
- struct mlx5_mkey_table *table = &dev->mdev->priv.mkey_table;
+ struct xarray *mkeys = &dev->mdev->priv.mkey_table;
int err;
spin_lock_irqsave(&ent->lock, flags);
@@ -158,12 +158,12 @@ static void reg_mr_callback(int status, struct mlx5_async_work *context)
ent->size++;
spin_unlock_irqrestore(&ent->lock, flags);
- write_lock_irqsave(&table->lock, flags);
- err = radix_tree_insert(&table->tree, mlx5_base_mkey(mr->mmkey.key),
- &mr->mmkey);
+ xa_lock_irqsave(mkeys, flags);
+ err = xa_err(__xa_store(mkeys, mlx5_base_mkey(mr->mmkey.key),
+ &mr->mmkey, GFP_ATOMIC));
+ xa_unlock_irqrestore(mkeys, flags);
if (err)
pr_err("Error inserting to mkey tree. 0x%x\n", -err);
- write_unlock_irqrestore(&table->lock, flags);
if (!completion_done(&ent->compl))
complete(&ent->compl);
@@ -1507,10 +1507,9 @@ int mlx5_ib_rereg_user_mr(struct ib_mr *ib_mr, int flags, u64 start,
return 0;
err:
- if (mr->umem) {
- ib_umem_release(mr->umem);
- mr->umem = NULL;
- }
+ ib_umem_release(mr->umem);
+ mr->umem = NULL;
+
clean_mr(dev, mr);
return err;
}
@@ -1606,8 +1605,9 @@ static void dereg_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
synchronize_srcu(&dev->mr_srcu);
/* Destroy all page mappings */
if (umem_odp->page_list)
- mlx5_ib_invalidate_range(umem_odp, ib_umem_start(umem),
- ib_umem_end(umem));
+ mlx5_ib_invalidate_range(umem_odp,
+ ib_umem_start(umem_odp),
+ ib_umem_end(umem_odp));
else
mlx5_ib_free_implicit_mr(mr);
/*
@@ -1629,28 +1629,85 @@ static void dereg_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
* remove the DMA mapping.
*/
mlx5_mr_cache_free(dev, mr);
- if (umem) {
- ib_umem_release(umem);
+ ib_umem_release(umem);
+ if (umem)
atomic_sub(npages, &dev->mdev->priv.reg_pages);
- }
+
if (!mr->allocated_from_cache)
kfree(mr);
}
int mlx5_ib_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
{
- dereg_mr(to_mdev(ibmr->device), to_mmr(ibmr));
+ struct mlx5_ib_mr *mmr = to_mmr(ibmr);
+
+ if (ibmr->type == IB_MR_TYPE_INTEGRITY) {
+ dereg_mr(to_mdev(mmr->mtt_mr->ibmr.device), mmr->mtt_mr);
+ dereg_mr(to_mdev(mmr->klm_mr->ibmr.device), mmr->klm_mr);
+ }
+
+ dereg_mr(to_mdev(ibmr->device), mmr);
+
return 0;
}
-struct ib_mr *mlx5_ib_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type,
- u32 max_num_sg, struct ib_udata *udata)
+static void mlx5_set_umr_free_mkey(struct ib_pd *pd, u32 *in, int ndescs,
+ int access_mode, int page_shift)
+{
+ void *mkc;
+
+ mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
+
+ MLX5_SET(mkc, mkc, free, 1);
+ MLX5_SET(mkc, mkc, qpn, 0xffffff);
+ MLX5_SET(mkc, mkc, pd, to_mpd(pd)->pdn);
+ MLX5_SET(mkc, mkc, translations_octword_size, ndescs);
+ MLX5_SET(mkc, mkc, access_mode_1_0, access_mode & 0x3);
+ MLX5_SET(mkc, mkc, access_mode_4_2, (access_mode >> 2) & 0x7);
+ MLX5_SET(mkc, mkc, umr_en, 1);
+ MLX5_SET(mkc, mkc, log_page_size, page_shift);
+}
+
+static int _mlx5_alloc_mkey_descs(struct ib_pd *pd, struct mlx5_ib_mr *mr,
+ int ndescs, int desc_size, int page_shift,
+ int access_mode, u32 *in, int inlen)
{
struct mlx5_ib_dev *dev = to_mdev(pd->device);
+ int err;
+
+ mr->access_mode = access_mode;
+ mr->desc_size = desc_size;
+ mr->max_descs = ndescs;
+
+ err = mlx5_alloc_priv_descs(pd->device, mr, ndescs, desc_size);
+ if (err)
+ return err;
+
+ mlx5_set_umr_free_mkey(pd, in, ndescs, access_mode, page_shift);
+
+ err = mlx5_core_create_mkey(dev->mdev, &mr->mmkey, in, inlen);
+ if (err)
+ goto err_free_descs;
+
+ mr->mmkey.type = MLX5_MKEY_MR;
+ mr->ibmr.lkey = mr->mmkey.key;
+ mr->ibmr.rkey = mr->mmkey.key;
+
+ return 0;
+
+err_free_descs:
+ mlx5_free_priv_descs(mr);
+ return err;
+}
+
+static struct mlx5_ib_mr *mlx5_ib_alloc_pi_mr(struct ib_pd *pd,
+ u32 max_num_sg, u32 max_num_meta_sg,
+ int desc_size, int access_mode)
+{
int inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
- int ndescs = ALIGN(max_num_sg, 4);
+ int ndescs = ALIGN(max_num_sg + max_num_meta_sg, 4);
+ int page_shift = 0;
struct mlx5_ib_mr *mr;
- void *mkc;
u32 *in;
int err;
@@ -1658,99 +1715,168 @@ struct ib_mr *mlx5_ib_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type,
if (!mr)
return ERR_PTR(-ENOMEM);
+ mr->ibmr.pd = pd;
+ mr->ibmr.device = pd->device;
+
in = kzalloc(inlen, GFP_KERNEL);
if (!in) {
err = -ENOMEM;
goto err_free;
}
+ if (access_mode == MLX5_MKC_ACCESS_MODE_MTT)
+ page_shift = PAGE_SHIFT;
+
+ err = _mlx5_alloc_mkey_descs(pd, mr, ndescs, desc_size, page_shift,
+ access_mode, in, inlen);
+ if (err)
+ goto err_free_in;
+
+ mr->umem = NULL;
+ kfree(in);
+
+ return mr;
+
+err_free_in:
+ kfree(in);
+err_free:
+ kfree(mr);
+ return ERR_PTR(err);
+}
+
+static int mlx5_alloc_mem_reg_descs(struct ib_pd *pd, struct mlx5_ib_mr *mr,
+ int ndescs, u32 *in, int inlen)
+{
+ return _mlx5_alloc_mkey_descs(pd, mr, ndescs, sizeof(struct mlx5_mtt),
+ PAGE_SHIFT, MLX5_MKC_ACCESS_MODE_MTT, in,
+ inlen);
+}
+
+static int mlx5_alloc_sg_gaps_descs(struct ib_pd *pd, struct mlx5_ib_mr *mr,
+ int ndescs, u32 *in, int inlen)
+{
+ return _mlx5_alloc_mkey_descs(pd, mr, ndescs, sizeof(struct mlx5_klm),
+ 0, MLX5_MKC_ACCESS_MODE_KLMS, in, inlen);
+}
+
+static int mlx5_alloc_integrity_descs(struct ib_pd *pd, struct mlx5_ib_mr *mr,
+ int max_num_sg, int max_num_meta_sg,
+ u32 *in, int inlen)
+{
+ struct mlx5_ib_dev *dev = to_mdev(pd->device);
+ u32 psv_index[2];
+ void *mkc;
+ int err;
+
+ mr->sig = kzalloc(sizeof(*mr->sig), GFP_KERNEL);
+ if (!mr->sig)
+ return -ENOMEM;
+
+ /* create mem & wire PSVs */
+ err = mlx5_core_create_psv(dev->mdev, to_mpd(pd)->pdn, 2, psv_index);
+ if (err)
+ goto err_free_sig;
+
+ mr->sig->psv_memory.psv_idx = psv_index[0];
+ mr->sig->psv_wire.psv_idx = psv_index[1];
+
+ mr->sig->sig_status_checked = true;
+ mr->sig->sig_err_exists = false;
+ /* Next UMR, Arm SIGERR */
+ ++mr->sig->sigerr_count;
+ mr->klm_mr = mlx5_ib_alloc_pi_mr(pd, max_num_sg, max_num_meta_sg,
+ sizeof(struct mlx5_klm),
+ MLX5_MKC_ACCESS_MODE_KLMS);
+ if (IS_ERR(mr->klm_mr)) {
+ err = PTR_ERR(mr->klm_mr);
+ goto err_destroy_psv;
+ }
+ mr->mtt_mr = mlx5_ib_alloc_pi_mr(pd, max_num_sg, max_num_meta_sg,
+ sizeof(struct mlx5_mtt),
+ MLX5_MKC_ACCESS_MODE_MTT);
+ if (IS_ERR(mr->mtt_mr)) {
+ err = PTR_ERR(mr->mtt_mr);
+ goto err_free_klm_mr;
+ }
+
+ /* Set bsf descriptors for mkey */
mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
- MLX5_SET(mkc, mkc, free, 1);
- MLX5_SET(mkc, mkc, translations_octword_size, ndescs);
- MLX5_SET(mkc, mkc, qpn, 0xffffff);
- MLX5_SET(mkc, mkc, pd, to_mpd(pd)->pdn);
+ MLX5_SET(mkc, mkc, bsf_en, 1);
+ MLX5_SET(mkc, mkc, bsf_octword_size, MLX5_MKEY_BSF_OCTO_SIZE);
- if (mr_type == IB_MR_TYPE_MEM_REG) {
- mr->access_mode = MLX5_MKC_ACCESS_MODE_MTT;
- MLX5_SET(mkc, mkc, log_page_size, PAGE_SHIFT);
- err = mlx5_alloc_priv_descs(pd->device, mr,
- ndescs, sizeof(struct mlx5_mtt));
- if (err)
- goto err_free_in;
+ err = _mlx5_alloc_mkey_descs(pd, mr, 4, sizeof(struct mlx5_klm), 0,
+ MLX5_MKC_ACCESS_MODE_KLMS, in, inlen);
+ if (err)
+ goto err_free_mtt_mr;
- mr->desc_size = sizeof(struct mlx5_mtt);
- mr->max_descs = ndescs;
- } else if (mr_type == IB_MR_TYPE_SG_GAPS) {
- mr->access_mode = MLX5_MKC_ACCESS_MODE_KLMS;
+ return 0;
- err = mlx5_alloc_priv_descs(pd->device, mr,
- ndescs, sizeof(struct mlx5_klm));
- if (err)
- goto err_free_in;
- mr->desc_size = sizeof(struct mlx5_klm);
- mr->max_descs = ndescs;
- } else if (mr_type == IB_MR_TYPE_SIGNATURE) {
- u32 psv_index[2];
-
- MLX5_SET(mkc, mkc, bsf_en, 1);
- MLX5_SET(mkc, mkc, bsf_octword_size, MLX5_MKEY_BSF_OCTO_SIZE);
- mr->sig = kzalloc(sizeof(*mr->sig), GFP_KERNEL);
- if (!mr->sig) {
- err = -ENOMEM;
- goto err_free_in;
- }
+err_free_mtt_mr:
+ dereg_mr(to_mdev(mr->mtt_mr->ibmr.device), mr->mtt_mr);
+ mr->mtt_mr = NULL;
+err_free_klm_mr:
+ dereg_mr(to_mdev(mr->klm_mr->ibmr.device), mr->klm_mr);
+ mr->klm_mr = NULL;
+err_destroy_psv:
+ if (mlx5_core_destroy_psv(dev->mdev, mr->sig->psv_memory.psv_idx))
+ mlx5_ib_warn(dev, "failed to destroy mem psv %d\n",
+ mr->sig->psv_memory.psv_idx);
+ if (mlx5_core_destroy_psv(dev->mdev, mr->sig->psv_wire.psv_idx))
+ mlx5_ib_warn(dev, "failed to destroy wire psv %d\n",
+ mr->sig->psv_wire.psv_idx);
+err_free_sig:
+ kfree(mr->sig);
- /* create mem & wire PSVs */
- err = mlx5_core_create_psv(dev->mdev, to_mpd(pd)->pdn,
- 2, psv_index);
- if (err)
- goto err_free_sig;
+ return err;
+}
+
+static struct ib_mr *__mlx5_ib_alloc_mr(struct ib_pd *pd,
+ enum ib_mr_type mr_type, u32 max_num_sg,
+ u32 max_num_meta_sg)
+{
+ struct mlx5_ib_dev *dev = to_mdev(pd->device);
+ int inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
+ int ndescs = ALIGN(max_num_sg, 4);
+ struct mlx5_ib_mr *mr;
+ u32 *in;
+ int err;
- mr->access_mode = MLX5_MKC_ACCESS_MODE_KLMS;
- mr->sig->psv_memory.psv_idx = psv_index[0];
- mr->sig->psv_wire.psv_idx = psv_index[1];
+ mr = kzalloc(sizeof(*mr), GFP_KERNEL);
+ if (!mr)
+ return ERR_PTR(-ENOMEM);
- mr->sig->sig_status_checked = true;
- mr->sig->sig_err_exists = false;
- /* Next UMR, Arm SIGERR */
- ++mr->sig->sigerr_count;
- } else {
+ in = kzalloc(inlen, GFP_KERNEL);
+ if (!in) {
+ err = -ENOMEM;
+ goto err_free;
+ }
+
+ mr->ibmr.device = pd->device;
+ mr->umem = NULL;
+
+ switch (mr_type) {
+ case IB_MR_TYPE_MEM_REG:
+ err = mlx5_alloc_mem_reg_descs(pd, mr, ndescs, in, inlen);
+ break;
+ case IB_MR_TYPE_SG_GAPS:
+ err = mlx5_alloc_sg_gaps_descs(pd, mr, ndescs, in, inlen);
+ break;
+ case IB_MR_TYPE_INTEGRITY:
+ err = mlx5_alloc_integrity_descs(pd, mr, max_num_sg,
+ max_num_meta_sg, in, inlen);
+ break;
+ default:
mlx5_ib_warn(dev, "Invalid mr type %d\n", mr_type);
err = -EINVAL;
- goto err_free_in;
}
- MLX5_SET(mkc, mkc, access_mode_1_0, mr->access_mode & 0x3);
- MLX5_SET(mkc, mkc, access_mode_4_2, (mr->access_mode >> 2) & 0x7);
- MLX5_SET(mkc, mkc, umr_en, 1);
-
- mr->ibmr.device = pd->device;
- err = mlx5_core_create_mkey(dev->mdev, &mr->mmkey, in, inlen);
if (err)
- goto err_destroy_psv;
+ goto err_free_in;
- mr->mmkey.type = MLX5_MKEY_MR;
- mr->ibmr.lkey = mr->mmkey.key;
- mr->ibmr.rkey = mr->mmkey.key;
- mr->umem = NULL;
kfree(in);
return &mr->ibmr;
-err_destroy_psv:
- if (mr->sig) {
- if (mlx5_core_destroy_psv(dev->mdev,
- mr->sig->psv_memory.psv_idx))
- mlx5_ib_warn(dev, "failed to destroy mem psv %d\n",
- mr->sig->psv_memory.psv_idx);
- if (mlx5_core_destroy_psv(dev->mdev,
- mr->sig->psv_wire.psv_idx))
- mlx5_ib_warn(dev, "failed to destroy wire psv %d\n",
- mr->sig->psv_wire.psv_idx);
- }
- mlx5_free_priv_descs(mr);
-err_free_sig:
- kfree(mr->sig);
err_free_in:
kfree(in);
err_free:
@@ -1758,6 +1884,19 @@ err_free:
return ERR_PTR(err);
}
+struct ib_mr *mlx5_ib_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type,
+ u32 max_num_sg, struct ib_udata *udata)
+{
+ return __mlx5_ib_alloc_mr(pd, mr_type, max_num_sg, 0);
+}
+
+struct ib_mr *mlx5_ib_alloc_mr_integrity(struct ib_pd *pd,
+ u32 max_num_sg, u32 max_num_meta_sg)
+{
+ return __mlx5_ib_alloc_mr(pd, IB_MR_TYPE_INTEGRITY, max_num_sg,
+ max_num_meta_sg);
+}
+
struct ib_mw *mlx5_ib_alloc_mw(struct ib_pd *pd, enum ib_mw_type type,
struct ib_udata *udata)
{
@@ -1887,16 +2026,53 @@ done:
}
static int
+mlx5_ib_map_pa_mr_sg_pi(struct ib_mr *ibmr, struct scatterlist *data_sg,
+ int data_sg_nents, unsigned int *data_sg_offset,
+ struct scatterlist *meta_sg, int meta_sg_nents,
+ unsigned int *meta_sg_offset)
+{
+ struct mlx5_ib_mr *mr = to_mmr(ibmr);
+ unsigned int sg_offset = 0;
+ int n = 0;
+
+ mr->meta_length = 0;
+ if (data_sg_nents == 1) {
+ n++;
+ mr->ndescs = 1;
+ if (data_sg_offset)
+ sg_offset = *data_sg_offset;
+ mr->data_length = sg_dma_len(data_sg) - sg_offset;
+ mr->data_iova = sg_dma_address(data_sg) + sg_offset;
+ if (meta_sg_nents == 1) {
+ n++;
+ mr->meta_ndescs = 1;
+ if (meta_sg_offset)
+ sg_offset = *meta_sg_offset;
+ else
+ sg_offset = 0;
+ mr->meta_length = sg_dma_len(meta_sg) - sg_offset;
+ mr->pi_iova = sg_dma_address(meta_sg) + sg_offset;
+ }
+ ibmr->length = mr->data_length + mr->meta_length;
+ }
+
+ return n;
+}
+
+static int
mlx5_ib_sg_to_klms(struct mlx5_ib_mr *mr,
struct scatterlist *sgl,
unsigned short sg_nents,
- unsigned int *sg_offset_p)
+ unsigned int *sg_offset_p,
+ struct scatterlist *meta_sgl,
+ unsigned short meta_sg_nents,
+ unsigned int *meta_sg_offset_p)
{
struct scatterlist *sg = sgl;
struct mlx5_klm *klms = mr->descs;
unsigned int sg_offset = sg_offset_p ? *sg_offset_p : 0;
u32 lkey = mr->ibmr.pd->local_dma_lkey;
- int i;
+ int i, j = 0;
mr->ibmr.iova = sg_dma_address(sg) + sg_offset;
mr->ibmr.length = 0;
@@ -1911,12 +2087,36 @@ mlx5_ib_sg_to_klms(struct mlx5_ib_mr *mr,
sg_offset = 0;
}
- mr->ndescs = i;
if (sg_offset_p)
*sg_offset_p = sg_offset;
- return i;
+ mr->ndescs = i;
+ mr->data_length = mr->ibmr.length;
+
+ if (meta_sg_nents) {
+ sg = meta_sgl;
+ sg_offset = meta_sg_offset_p ? *meta_sg_offset_p : 0;
+ for_each_sg(meta_sgl, sg, meta_sg_nents, j) {
+ if (unlikely(i + j >= mr->max_descs))
+ break;
+ klms[i + j].va = cpu_to_be64(sg_dma_address(sg) +
+ sg_offset);
+ klms[i + j].bcount = cpu_to_be32(sg_dma_len(sg) -
+ sg_offset);
+ klms[i + j].key = cpu_to_be32(lkey);
+ mr->ibmr.length += sg_dma_len(sg) - sg_offset;
+
+ sg_offset = 0;
+ }
+ if (meta_sg_offset_p)
+ *meta_sg_offset_p = sg_offset;
+
+ mr->meta_ndescs = j;
+ mr->meta_length = mr->ibmr.length - mr->data_length;
+ }
+
+ return i + j;
}
static int mlx5_set_page(struct ib_mr *ibmr, u64 addr)
@@ -1933,6 +2133,181 @@ static int mlx5_set_page(struct ib_mr *ibmr, u64 addr)
return 0;
}
+static int mlx5_set_page_pi(struct ib_mr *ibmr, u64 addr)
+{
+ struct mlx5_ib_mr *mr = to_mmr(ibmr);
+ __be64 *descs;
+
+ if (unlikely(mr->ndescs + mr->meta_ndescs == mr->max_descs))
+ return -ENOMEM;
+
+ descs = mr->descs;
+ descs[mr->ndescs + mr->meta_ndescs++] =
+ cpu_to_be64(addr | MLX5_EN_RD | MLX5_EN_WR);
+
+ return 0;
+}
+
+static int
+mlx5_ib_map_mtt_mr_sg_pi(struct ib_mr *ibmr, struct scatterlist *data_sg,
+ int data_sg_nents, unsigned int *data_sg_offset,
+ struct scatterlist *meta_sg, int meta_sg_nents,
+ unsigned int *meta_sg_offset)
+{
+ struct mlx5_ib_mr *mr = to_mmr(ibmr);
+ struct mlx5_ib_mr *pi_mr = mr->mtt_mr;
+ int n;
+
+ pi_mr->ndescs = 0;
+ pi_mr->meta_ndescs = 0;
+ pi_mr->meta_length = 0;
+
+ ib_dma_sync_single_for_cpu(ibmr->device, pi_mr->desc_map,
+ pi_mr->desc_size * pi_mr->max_descs,
+ DMA_TO_DEVICE);
+
+ pi_mr->ibmr.page_size = ibmr->page_size;
+ n = ib_sg_to_pages(&pi_mr->ibmr, data_sg, data_sg_nents, data_sg_offset,
+ mlx5_set_page);
+ if (n != data_sg_nents)
+ return n;
+
+ pi_mr->data_iova = pi_mr->ibmr.iova;
+ pi_mr->data_length = pi_mr->ibmr.length;
+ pi_mr->ibmr.length = pi_mr->data_length;
+ ibmr->length = pi_mr->data_length;
+
+ if (meta_sg_nents) {
+ u64 page_mask = ~((u64)ibmr->page_size - 1);
+ u64 iova = pi_mr->data_iova;
+
+ n += ib_sg_to_pages(&pi_mr->ibmr, meta_sg, meta_sg_nents,
+ meta_sg_offset, mlx5_set_page_pi);
+
+ pi_mr->meta_length = pi_mr->ibmr.length;
+ /*
+ * PI address for the HW is the offset of the metadata address
+ * relative to the first data page address.
+ * It equals to first data page address + size of data pages +
+ * metadata offset at the first metadata page
+ */
+ pi_mr->pi_iova = (iova & page_mask) +
+ pi_mr->ndescs * ibmr->page_size +
+ (pi_mr->ibmr.iova & ~page_mask);
+ /*
+ * In order to use one MTT MR for data and metadata, we register
+ * also the gaps between the end of the data and the start of
+ * the metadata (the sig MR will verify that the HW will access
+ * to right addresses). This mapping is safe because we use
+ * internal mkey for the registration.
+ */
+ pi_mr->ibmr.length = pi_mr->pi_iova + pi_mr->meta_length - iova;
+ pi_mr->ibmr.iova = iova;
+ ibmr->length += pi_mr->meta_length;
+ }
+
+ ib_dma_sync_single_for_device(ibmr->device, pi_mr->desc_map,
+ pi_mr->desc_size * pi_mr->max_descs,
+ DMA_TO_DEVICE);
+
+ return n;
+}
+
+static int
+mlx5_ib_map_klm_mr_sg_pi(struct ib_mr *ibmr, struct scatterlist *data_sg,
+ int data_sg_nents, unsigned int *data_sg_offset,
+ struct scatterlist *meta_sg, int meta_sg_nents,
+ unsigned int *meta_sg_offset)
+{
+ struct mlx5_ib_mr *mr = to_mmr(ibmr);
+ struct mlx5_ib_mr *pi_mr = mr->klm_mr;
+ int n;
+
+ pi_mr->ndescs = 0;
+ pi_mr->meta_ndescs = 0;
+ pi_mr->meta_length = 0;
+
+ ib_dma_sync_single_for_cpu(ibmr->device, pi_mr->desc_map,
+ pi_mr->desc_size * pi_mr->max_descs,
+ DMA_TO_DEVICE);
+
+ n = mlx5_ib_sg_to_klms(pi_mr, data_sg, data_sg_nents, data_sg_offset,
+ meta_sg, meta_sg_nents, meta_sg_offset);
+
+ ib_dma_sync_single_for_device(ibmr->device, pi_mr->desc_map,
+ pi_mr->desc_size * pi_mr->max_descs,
+ DMA_TO_DEVICE);
+
+ /* This is zero-based memory region */
+ pi_mr->data_iova = 0;
+ pi_mr->ibmr.iova = 0;
+ pi_mr->pi_iova = pi_mr->data_length;
+ ibmr->length = pi_mr->ibmr.length;
+
+ return n;
+}
+
+int mlx5_ib_map_mr_sg_pi(struct ib_mr *ibmr, struct scatterlist *data_sg,
+ int data_sg_nents, unsigned int *data_sg_offset,
+ struct scatterlist *meta_sg, int meta_sg_nents,
+ unsigned int *meta_sg_offset)
+{
+ struct mlx5_ib_mr *mr = to_mmr(ibmr);
+ struct mlx5_ib_mr *pi_mr = NULL;
+ int n;
+
+ WARN_ON(ibmr->type != IB_MR_TYPE_INTEGRITY);
+
+ mr->ndescs = 0;
+ mr->data_length = 0;
+ mr->data_iova = 0;
+ mr->meta_ndescs = 0;
+ mr->pi_iova = 0;
+ /*
+ * As a performance optimization, if possible, there is no need to
+ * perform UMR operation to register the data/metadata buffers.
+ * First try to map the sg lists to PA descriptors with local_dma_lkey.
+ * Fallback to UMR only in case of a failure.
+ */
+ n = mlx5_ib_map_pa_mr_sg_pi(ibmr, data_sg, data_sg_nents,
+ data_sg_offset, meta_sg, meta_sg_nents,
+ meta_sg_offset);
+ if (n == data_sg_nents + meta_sg_nents)
+ goto out;
+ /*
+ * As a performance optimization, if possible, there is no need to map
+ * the sg lists to KLM descriptors. First try to map the sg lists to MTT
+ * descriptors and fallback to KLM only in case of a failure.
+ * It's more efficient for the HW to work with MTT descriptors
+ * (especially in high load).
+ * Use KLM (indirect access) only if it's mandatory.
+ */
+ pi_mr = mr->mtt_mr;
+ n = mlx5_ib_map_mtt_mr_sg_pi(ibmr, data_sg, data_sg_nents,
+ data_sg_offset, meta_sg, meta_sg_nents,
+ meta_sg_offset);
+ if (n == data_sg_nents + meta_sg_nents)
+ goto out;
+
+ pi_mr = mr->klm_mr;
+ n = mlx5_ib_map_klm_mr_sg_pi(ibmr, data_sg, data_sg_nents,
+ data_sg_offset, meta_sg, meta_sg_nents,
+ meta_sg_offset);
+ if (unlikely(n != data_sg_nents + meta_sg_nents))
+ return -ENOMEM;
+
+out:
+ /* This is zero-based memory region */
+ ibmr->iova = 0;
+ mr->pi_mr = pi_mr;
+ if (pi_mr)
+ ibmr->sig_attrs->meta_length = pi_mr->meta_length;
+ else
+ ibmr->sig_attrs->meta_length = mr->meta_length;
+
+ return 0;
+}
+
int mlx5_ib_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents,
unsigned int *sg_offset)
{
@@ -1946,7 +2321,8 @@ int mlx5_ib_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents,
DMA_TO_DEVICE);
if (mr->access_mode == MLX5_MKC_ACCESS_MODE_KLMS)
- n = mlx5_ib_sg_to_klms(mr, sg, sg_nents, sg_offset);
+ n = mlx5_ib_sg_to_klms(mr, sg, sg_nents, sg_offset, NULL, 0,
+ NULL);
else
n = ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset,
mlx5_set_page);
diff --git a/drivers/infiniband/hw/mlx5/odp.c b/drivers/infiniband/hw/mlx5/odp.c
index 91507a2e9290..5b642d81e617 100644
--- a/drivers/infiniband/hw/mlx5/odp.c
+++ b/drivers/infiniband/hw/mlx5/odp.c
@@ -150,7 +150,7 @@ static struct ib_umem_odp *odp_lookup(u64 start, u64 length,
if (!rb)
goto not_found;
odp = rb_entry(rb, struct ib_umem_odp, interval_tree.rb);
- if (ib_umem_start(&odp->umem) > start + length)
+ if (ib_umem_start(odp) > start + length)
goto not_found;
}
not_found:
@@ -200,7 +200,7 @@ void mlx5_odp_populate_klm(struct mlx5_klm *pklm, size_t offset,
static void mr_leaf_free_action(struct work_struct *work)
{
struct ib_umem_odp *odp = container_of(work, struct ib_umem_odp, work);
- int idx = ib_umem_start(&odp->umem) >> MLX5_IMR_MTT_SHIFT;
+ int idx = ib_umem_start(odp) >> MLX5_IMR_MTT_SHIFT;
struct mlx5_ib_mr *mr = odp->private, *imr = mr->parent;
mr->parent = NULL;
@@ -224,7 +224,6 @@ void mlx5_ib_invalidate_range(struct ib_umem_odp *umem_odp, unsigned long start,
const u64 umr_block_mask = (MLX5_UMR_MTT_ALIGNMENT /
sizeof(struct mlx5_mtt)) - 1;
u64 idx = 0, blk_start_idx = 0;
- struct ib_umem *umem;
int in_block = 0;
u64 addr;
@@ -232,15 +231,14 @@ void mlx5_ib_invalidate_range(struct ib_umem_odp *umem_odp, unsigned long start,
pr_err("invalidation called on NULL umem or non-ODP umem\n");
return;
}
- umem = &umem_odp->umem;
mr = umem_odp->private;
if (!mr || !mr->ibmr.pd)
return;
- start = max_t(u64, ib_umem_start(umem), start);
- end = min_t(u64, ib_umem_end(umem), end);
+ start = max_t(u64, ib_umem_start(umem_odp), start);
+ end = min_t(u64, ib_umem_end(umem_odp), end);
/*
* Iteration one - zap the HW's MTTs. The notifiers_count ensures that
@@ -249,8 +247,8 @@ void mlx5_ib_invalidate_range(struct ib_umem_odp *umem_odp, unsigned long start,
* but they will write 0s as well, so no difference in the end result.
*/
- for (addr = start; addr < end; addr += BIT(umem->page_shift)) {
- idx = (addr - ib_umem_start(umem)) >> umem->page_shift;
+ for (addr = start; addr < end; addr += BIT(umem_odp->page_shift)) {
+ idx = (addr - ib_umem_start(umem_odp)) >> umem_odp->page_shift;
/*
* Strive to write the MTTs in chunks, but avoid overwriting
* non-existing MTTs. The huristic here can be improved to
@@ -544,13 +542,12 @@ static int mr_leaf_free(struct ib_umem_odp *umem_odp, u64 start, u64 end,
void *cookie)
{
struct mlx5_ib_mr *mr = umem_odp->private, *imr = cookie;
- struct ib_umem *umem = &umem_odp->umem;
if (mr->parent != imr)
return 0;
- ib_umem_odp_unmap_dma_pages(umem_odp, ib_umem_start(umem),
- ib_umem_end(umem));
+ ib_umem_odp_unmap_dma_pages(umem_odp, ib_umem_start(umem_odp),
+ ib_umem_end(umem_odp));
if (umem_odp->dying)
return 0;
@@ -602,9 +599,9 @@ static int pagefault_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr,
}
next_mr:
- size = min_t(size_t, bcnt, ib_umem_end(&odp->umem) - io_virt);
+ size = min_t(size_t, bcnt, ib_umem_end(odp) - io_virt);
- page_shift = mr->umem->page_shift;
+ page_shift = odp->page_shift;
page_mask = ~(BIT(page_shift) - 1);
start_idx = (io_virt - (mr->mmkey.iova & page_mask)) >> page_shift;
access_mask = ODP_READ_ALLOWED_BIT;
@@ -768,7 +765,7 @@ static int pagefault_single_data_segment(struct mlx5_ib_dev *dev,
bcnt -= *bytes_committed;
next_mr:
- mmkey = __mlx5_mr_lookup(dev->mdev, mlx5_base_mkey(key));
+ mmkey = xa_load(&dev->mdev->priv.mkey_table, mlx5_base_mkey(key));
if (!mkey_is_eq(mmkey, key)) {
mlx5_ib_dbg(dev, "failed to find mkey %x\n", key);
ret = -EFAULT;
@@ -1488,9 +1485,11 @@ static void mlx5_ib_eq_pf_process(struct mlx5_ib_pf_eq *eq)
mlx5_eq_update_ci(eq->core, cc, 1);
}
-static irqreturn_t mlx5_ib_eq_pf_int(int irq, void *eq_ptr)
+static int mlx5_ib_eq_pf_int(struct notifier_block *nb, unsigned long type,
+ void *data)
{
- struct mlx5_ib_pf_eq *eq = eq_ptr;
+ struct mlx5_ib_pf_eq *eq =
+ container_of(nb, struct mlx5_ib_pf_eq, irq_nb);
unsigned long flags;
if (spin_trylock_irqsave(&eq->lock, flags)) {
@@ -1553,20 +1552,26 @@ mlx5_ib_create_pf_eq(struct mlx5_ib_dev *dev, struct mlx5_ib_pf_eq *eq)
goto err_mempool;
}
+ eq->irq_nb.notifier_call = mlx5_ib_eq_pf_int;
param = (struct mlx5_eq_param) {
- .index = MLX5_EQ_PFAULT_IDX,
- .mask = 1 << MLX5_EVENT_TYPE_PAGE_FAULT,
+ .irq_index = 0,
.nent = MLX5_IB_NUM_PF_EQE,
- .context = eq,
- .handler = mlx5_ib_eq_pf_int
};
- eq->core = mlx5_eq_create_generic(dev->mdev, "mlx5_ib_page_fault_eq", &param);
+ param.mask[0] = 1ull << MLX5_EVENT_TYPE_PAGE_FAULT;
+ eq->core = mlx5_eq_create_generic(dev->mdev, &param);
if (IS_ERR(eq->core)) {
err = PTR_ERR(eq->core);
goto err_wq;
}
+ err = mlx5_eq_enable(dev->mdev, eq->core, &eq->irq_nb);
+ if (err) {
+ mlx5_ib_err(dev, "failed to enable odp EQ %d\n", err);
+ goto err_eq;
+ }
return 0;
+err_eq:
+ mlx5_eq_destroy_generic(dev->mdev, eq->core);
err_wq:
destroy_workqueue(eq->wq);
err_mempool:
@@ -1579,6 +1584,7 @@ mlx5_ib_destroy_pf_eq(struct mlx5_ib_dev *dev, struct mlx5_ib_pf_eq *eq)
{
int err;
+ mlx5_eq_disable(dev->mdev, eq->core, &eq->irq_nb);
err = mlx5_eq_destroy_generic(dev->mdev, eq->core);
cancel_work_sync(&eq->work);
destroy_workqueue(eq->wq);
@@ -1677,8 +1683,8 @@ static void num_pending_prefetch_dec(struct mlx5_ib_dev *dev,
struct mlx5_core_mkey *mmkey;
struct mlx5_ib_mr *mr;
- mmkey = __mlx5_mr_lookup(dev->mdev,
- mlx5_base_mkey(sg_list[i].lkey));
+ mmkey = xa_load(&dev->mdev->priv.mkey_table,
+ mlx5_base_mkey(sg_list[i].lkey));
mr = container_of(mmkey, struct mlx5_ib_mr, mmkey);
atomic_dec(&mr->num_pending_prefetch);
}
@@ -1697,8 +1703,8 @@ static bool num_pending_prefetch_inc(struct ib_pd *pd,
struct mlx5_core_mkey *mmkey;
struct mlx5_ib_mr *mr;
- mmkey = __mlx5_mr_lookup(dev->mdev,
- mlx5_base_mkey(sg_list[i].lkey));
+ mmkey = xa_load(&dev->mdev->priv.mkey_table,
+ mlx5_base_mkey(sg_list[i].lkey));
if (!mmkey || mmkey->key != sg_list[i].lkey) {
ret = false;
break;
diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c
index f6623c77443a..2a97619ed603 100644
--- a/drivers/infiniband/hw/mlx5/qp.c
+++ b/drivers/infiniband/hw/mlx5/qp.c
@@ -34,6 +34,7 @@
#include <rdma/ib_umem.h>
#include <rdma/ib_cache.h>
#include <rdma/ib_user_verbs.h>
+#include <rdma/rdma_counter.h>
#include <linux/mlx5/fs.h>
#include "mlx5_ib.h"
#include "ib_rep.h"
@@ -442,9 +443,9 @@ static int calc_send_wqe(struct ib_qp_init_attr *attr)
}
size += attr->cap.max_send_sge * sizeof(struct mlx5_wqe_data_seg);
- if (attr->create_flags & IB_QP_CREATE_SIGNATURE_EN &&
+ if (attr->create_flags & IB_QP_CREATE_INTEGRITY_EN &&
ALIGN(max_t(int, inl_size, size), MLX5_SEND_WQE_BB) < MLX5_SIG_WQE_SIZE)
- return MLX5_SIG_WQE_SIZE;
+ return MLX5_SIG_WQE_SIZE;
else
return ALIGN(max_t(int, inl_size, size), MLX5_SEND_WQE_BB);
}
@@ -496,9 +497,6 @@ static int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr,
sizeof(struct mlx5_wqe_inline_seg);
attr->cap.max_inline_data = qp->max_inline_data;
- if (attr->create_flags & IB_QP_CREATE_SIGNATURE_EN)
- qp->signature_en = true;
-
wq_size = roundup_pow_of_two(attr->cap.max_send_wr * wqe_size);
qp->sq.wqe_cnt = wq_size / MLX5_SEND_WQE_BB;
if (qp->sq.wqe_cnt > (1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz))) {
@@ -790,8 +788,7 @@ static void destroy_user_rq(struct mlx5_ib_dev *dev, struct ib_pd *pd,
atomic_dec(&dev->delay_drop.rqs_cnt);
mlx5_ib_db_unmap_user(context, &rwq->db);
- if (rwq->umem)
- ib_umem_release(rwq->umem);
+ ib_umem_release(rwq->umem);
}
static int create_user_rq(struct mlx5_ib_dev *dev, struct ib_pd *pd,
@@ -977,8 +974,7 @@ err_free:
kvfree(*in);
err_umem:
- if (ubuffer->umem)
- ib_umem_release(ubuffer->umem);
+ ib_umem_release(ubuffer->umem);
err_bfreg:
if (bfregn != MLX5_IB_INVALID_BFREG)
@@ -997,8 +993,7 @@ static void destroy_qp_user(struct mlx5_ib_dev *dev, struct ib_pd *pd,
ibucontext);
mlx5_ib_db_unmap_user(context, &qp->db);
- if (base->ubuffer.umem)
- ib_umem_release(base->ubuffer.umem);
+ ib_umem_release(base->ubuffer.umem);
/*
* Free only the BFREGs which are handled by the kernel.
@@ -1042,7 +1037,7 @@ static int create_kernel_qp(struct mlx5_ib_dev *dev,
void *qpc;
int err;
- if (init_attr->create_flags & ~(IB_QP_CREATE_SIGNATURE_EN |
+ if (init_attr->create_flags & ~(IB_QP_CREATE_INTEGRITY_EN |
IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK |
IB_QP_CREATE_IPOIB_UD_LSO |
IB_QP_CREATE_NETIF_QP |
@@ -3386,6 +3381,35 @@ static unsigned int get_tx_affinity(struct mlx5_ib_dev *dev,
return tx_port_affinity;
}
+static int __mlx5_ib_qp_set_counter(struct ib_qp *qp,
+ struct rdma_counter *counter)
+{
+ struct mlx5_ib_dev *dev = to_mdev(qp->device);
+ struct mlx5_ib_qp *mqp = to_mqp(qp);
+ struct mlx5_qp_context context = {};
+ struct mlx5_ib_port *mibport = NULL;
+ struct mlx5_ib_qp_base *base;
+ u32 set_id;
+
+ if (!MLX5_CAP_GEN(dev->mdev, rts2rts_qp_counters_set_id))
+ return 0;
+
+ if (counter) {
+ set_id = counter->id;
+ } else {
+ mibport = &dev->port[mqp->port - 1];
+ set_id = mibport->cnts.set_id;
+ }
+
+ base = &mqp->trans_qp.base;
+ context.qp_counter_set_usr_page &= cpu_to_be32(0xffffff);
+ context.qp_counter_set_usr_page |= cpu_to_be32(set_id << 24);
+ return mlx5_core_qp_modify(dev->mdev,
+ MLX5_CMD_OP_RTS2RTS_QP,
+ MLX5_QP_OPTPAR_COUNTER_SET_ID,
+ &context, &base->mqp);
+}
+
static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
const struct ib_qp_attr *attr, int attr_mask,
enum ib_qp_state cur_state,
@@ -3439,6 +3463,7 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
struct mlx5_ib_port *mibport = NULL;
enum mlx5_qp_state mlx5_cur, mlx5_new;
enum mlx5_qp_optpar optpar;
+ u32 set_id = 0;
int mlx5_st;
int err;
u16 op;
@@ -3601,8 +3626,12 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
port_num = 0;
mibport = &dev->port[port_num];
+ if (ibqp->counter)
+ set_id = ibqp->counter->id;
+ else
+ set_id = mibport->cnts.set_id;
context->qp_counter_set_usr_page |=
- cpu_to_be32((u32)(mibport->cnts.set_id) << 24);
+ cpu_to_be32(set_id << 24);
}
if (!ibqp->uobject && cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT)
@@ -3630,7 +3659,7 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
raw_qp_param.operation = op;
if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) {
- raw_qp_param.rq_q_ctr_id = mibport->cnts.set_id;
+ raw_qp_param.rq_q_ctr_id = set_id;
raw_qp_param.set_mask |= MLX5_RAW_QP_MOD_SET_RQ_Q_CTR_ID;
}
@@ -3707,6 +3736,12 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
qp->db.db[MLX5_SND_DBR] = 0;
}
+ if ((new_state == IB_QPS_RTS) && qp->counter_pending) {
+ err = __mlx5_ib_qp_set_counter(ibqp, ibqp->counter);
+ if (!err)
+ qp->counter_pending = 0;
+ }
+
out:
kfree(context);
return err;
@@ -4170,15 +4205,13 @@ static __be64 sig_mkey_mask(void)
}
static void set_reg_umr_seg(struct mlx5_wqe_umr_ctrl_seg *umr,
- struct mlx5_ib_mr *mr, bool umr_inline)
+ struct mlx5_ib_mr *mr, u8 flags)
{
- int size = mr->ndescs * mr->desc_size;
+ int size = (mr->ndescs + mr->meta_ndescs) * mr->desc_size;
memset(umr, 0, sizeof(*umr));
- umr->flags = MLX5_UMR_CHECK_NOT_FREE;
- if (umr_inline)
- umr->flags |= MLX5_UMR_INLINE;
+ umr->flags = flags;
umr->xlt_octowords = cpu_to_be16(get_xlt_octo(size));
umr->mkey_mask = frwr_mkey_mask();
}
@@ -4305,7 +4338,7 @@ static void set_reg_mkey_seg(struct mlx5_mkey_seg *seg,
struct mlx5_ib_mr *mr,
u32 key, int access)
{
- int ndescs = ALIGN(mr->ndescs, 8) >> 1;
+ int ndescs = ALIGN(mr->ndescs + mr->meta_ndescs, 8) >> 1;
memset(seg, 0, sizeof(*seg));
@@ -4356,7 +4389,7 @@ static void set_reg_data_seg(struct mlx5_wqe_data_seg *dseg,
struct mlx5_ib_mr *mr,
struct mlx5_ib_pd *pd)
{
- int bcount = mr->desc_size * mr->ndescs;
+ int bcount = mr->desc_size * (mr->ndescs + mr->meta_ndescs);
dseg->addr = cpu_to_be64(mr->desc_map);
dseg->byte_count = cpu_to_be32(ALIGN(bcount, 64));
@@ -4549,23 +4582,37 @@ static int mlx5_set_bsf(struct ib_mr *sig_mr,
return 0;
}
-static int set_sig_data_segment(const struct ib_sig_handover_wr *wr,
- struct mlx5_ib_qp *qp, void **seg,
- int *size, void **cur_edge)
+static int set_sig_data_segment(const struct ib_send_wr *send_wr,
+ struct ib_mr *sig_mr,
+ struct ib_sig_attrs *sig_attrs,
+ struct mlx5_ib_qp *qp, void **seg, int *size,
+ void **cur_edge)
{
- struct ib_sig_attrs *sig_attrs = wr->sig_attrs;
- struct ib_mr *sig_mr = wr->sig_mr;
struct mlx5_bsf *bsf;
- u32 data_len = wr->wr.sg_list->length;
- u32 data_key = wr->wr.sg_list->lkey;
- u64 data_va = wr->wr.sg_list->addr;
+ u32 data_len;
+ u32 data_key;
+ u64 data_va;
+ u32 prot_len = 0;
+ u32 prot_key = 0;
+ u64 prot_va = 0;
+ bool prot = false;
int ret;
int wqe_size;
+ struct mlx5_ib_mr *mr = to_mmr(sig_mr);
+ struct mlx5_ib_mr *pi_mr = mr->pi_mr;
+
+ data_len = pi_mr->data_length;
+ data_key = pi_mr->ibmr.lkey;
+ data_va = pi_mr->data_iova;
+ if (pi_mr->meta_ndescs) {
+ prot_len = pi_mr->meta_length;
+ prot_key = pi_mr->ibmr.lkey;
+ prot_va = pi_mr->pi_iova;
+ prot = true;
+ }
- if (!wr->prot ||
- (data_key == wr->prot->lkey &&
- data_va == wr->prot->addr &&
- data_len == wr->prot->length)) {
+ if (!prot || (data_key == prot_key && data_va == prot_va &&
+ data_len == prot_len)) {
/**
* Source domain doesn't contain signature information
* or data and protection are interleaved in memory.
@@ -4599,8 +4646,6 @@ static int set_sig_data_segment(const struct ib_sig_handover_wr *wr,
struct mlx5_stride_block_ctrl_seg *sblock_ctrl;
struct mlx5_stride_block_entry *data_sentry;
struct mlx5_stride_block_entry *prot_sentry;
- u32 prot_key = wr->prot->lkey;
- u64 prot_va = wr->prot->addr;
u16 block_size = sig_attrs->mem.sig.dif.pi_interval;
int prot_size;
@@ -4650,17 +4695,15 @@ static int set_sig_data_segment(const struct ib_sig_handover_wr *wr,
}
static void set_sig_mkey_segment(struct mlx5_mkey_seg *seg,
- const struct ib_sig_handover_wr *wr, u32 size,
- u32 length, u32 pdn)
+ struct ib_mr *sig_mr, int access_flags,
+ u32 size, u32 length, u32 pdn)
{
- struct ib_mr *sig_mr = wr->sig_mr;
u32 sig_key = sig_mr->rkey;
u8 sigerr = to_mmr(sig_mr)->sig->sigerr_count & 1;
memset(seg, 0, sizeof(*seg));
- seg->flags = get_umr_flags(wr->access_flags) |
- MLX5_MKC_ACCESS_MODE_KLMS;
+ seg->flags = get_umr_flags(access_flags) | MLX5_MKC_ACCESS_MODE_KLMS;
seg->qpn_mkey7_0 = cpu_to_be32((sig_key & 0xff) | 0xffffff00);
seg->flags_pd = cpu_to_be32(MLX5_MKEY_REMOTE_INVAL | sigerr << 26 |
MLX5_MKEY_BSF_EN | pdn);
@@ -4680,49 +4723,50 @@ static void set_sig_umr_segment(struct mlx5_wqe_umr_ctrl_seg *umr,
umr->mkey_mask = sig_mkey_mask();
}
-
-static int set_sig_umr_wr(const struct ib_send_wr *send_wr,
- struct mlx5_ib_qp *qp, void **seg, int *size,
- void **cur_edge)
+static int set_pi_umr_wr(const struct ib_send_wr *send_wr,
+ struct mlx5_ib_qp *qp, void **seg, int *size,
+ void **cur_edge)
{
- const struct ib_sig_handover_wr *wr = sig_handover_wr(send_wr);
- struct mlx5_ib_mr *sig_mr = to_mmr(wr->sig_mr);
+ const struct ib_reg_wr *wr = reg_wr(send_wr);
+ struct mlx5_ib_mr *sig_mr = to_mmr(wr->mr);
+ struct mlx5_ib_mr *pi_mr = sig_mr->pi_mr;
+ struct ib_sig_attrs *sig_attrs = sig_mr->ibmr.sig_attrs;
u32 pdn = get_pd(qp)->pdn;
u32 xlt_size;
int region_len, ret;
- if (unlikely(wr->wr.num_sge != 1) ||
- unlikely(wr->access_flags & IB_ACCESS_REMOTE_ATOMIC) ||
- unlikely(!sig_mr->sig) || unlikely(!qp->signature_en) ||
+ if (unlikely(send_wr->num_sge != 0) ||
+ unlikely(wr->access & IB_ACCESS_REMOTE_ATOMIC) ||
+ unlikely(!sig_mr->sig) || unlikely(!qp->ibqp.integrity_en) ||
unlikely(!sig_mr->sig->sig_status_checked))
return -EINVAL;
/* length of the protected region, data + protection */
- region_len = wr->wr.sg_list->length;
- if (wr->prot &&
- (wr->prot->lkey != wr->wr.sg_list->lkey ||
- wr->prot->addr != wr->wr.sg_list->addr ||
- wr->prot->length != wr->wr.sg_list->length))
- region_len += wr->prot->length;
+ region_len = pi_mr->ibmr.length;
/**
* KLM octoword size - if protection was provided
* then we use strided block format (3 octowords),
* else we use single KLM (1 octoword)
**/
- xlt_size = wr->prot ? 0x30 : sizeof(struct mlx5_klm);
+ if (sig_attrs->mem.sig_type != IB_SIG_TYPE_NONE)
+ xlt_size = 0x30;
+ else
+ xlt_size = sizeof(struct mlx5_klm);
set_sig_umr_segment(*seg, xlt_size);
*seg += sizeof(struct mlx5_wqe_umr_ctrl_seg);
*size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16;
handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
- set_sig_mkey_segment(*seg, wr, xlt_size, region_len, pdn);
+ set_sig_mkey_segment(*seg, wr->mr, wr->access, xlt_size, region_len,
+ pdn);
*seg += sizeof(struct mlx5_mkey_seg);
*size += sizeof(struct mlx5_mkey_seg) / 16;
handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
- ret = set_sig_data_segment(wr, qp, seg, size, cur_edge);
+ ret = set_sig_data_segment(send_wr, wr->mr, sig_attrs, qp, seg, size,
+ cur_edge);
if (ret)
return ret;
@@ -4759,12 +4803,14 @@ static int set_psv_wr(struct ib_sig_domain *domain,
static int set_reg_wr(struct mlx5_ib_qp *qp,
const struct ib_reg_wr *wr,
- void **seg, int *size, void **cur_edge)
+ void **seg, int *size, void **cur_edge,
+ bool check_not_free)
{
struct mlx5_ib_mr *mr = to_mmr(wr->mr);
struct mlx5_ib_pd *pd = to_mpd(qp->ibqp.pd);
- size_t mr_list_size = mr->ndescs * mr->desc_size;
+ int mr_list_size = (mr->ndescs + mr->meta_ndescs) * mr->desc_size;
bool umr_inline = mr_list_size <= MLX5_IB_SQ_UMR_INLINE_THRESHOLD;
+ u8 flags = 0;
if (unlikely(wr->wr.send_flags & IB_SEND_INLINE)) {
mlx5_ib_warn(to_mdev(qp->ibqp.device),
@@ -4772,7 +4818,12 @@ static int set_reg_wr(struct mlx5_ib_qp *qp,
return -EINVAL;
}
- set_reg_umr_seg(*seg, mr, umr_inline);
+ if (check_not_free)
+ flags |= MLX5_UMR_CHECK_NOT_FREE;
+ if (umr_inline)
+ flags |= MLX5_UMR_INLINE;
+
+ set_reg_umr_seg(*seg, mr, flags);
*seg += sizeof(struct mlx5_wqe_umr_ctrl_seg);
*size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16;
handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
@@ -4898,8 +4949,12 @@ static int _mlx5_ib_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
struct mlx5_wqe_ctrl_seg *ctrl = NULL; /* compiler warning */
struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
struct mlx5_core_dev *mdev = dev->mdev;
+ struct ib_reg_wr reg_pi_wr;
struct mlx5_ib_qp *qp;
struct mlx5_ib_mr *mr;
+ struct mlx5_ib_mr *pi_mr;
+ struct mlx5_ib_mr pa_pi_mr;
+ struct ib_sig_attrs *sig_attrs;
struct mlx5_wqe_xrc_seg *xrc;
struct mlx5_bf *bf;
void *cur_edge;
@@ -4953,7 +5008,8 @@ static int _mlx5_ib_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
goto out;
}
- if (wr->opcode == IB_WR_REG_MR) {
+ if (wr->opcode == IB_WR_REG_MR ||
+ wr->opcode == IB_WR_REG_MR_INTEGRITY) {
fence = dev->umr_fence;
next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL;
} else {
@@ -5003,7 +5059,7 @@ static int _mlx5_ib_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
qp->sq.wr_data[idx] = IB_WR_REG_MR;
ctrl->imm = cpu_to_be32(reg_wr(wr)->key);
err = set_reg_wr(qp, reg_wr(wr), &seg, &size,
- &cur_edge);
+ &cur_edge, true);
if (err) {
*bad_wr = wr;
goto out;
@@ -5011,26 +5067,82 @@ static int _mlx5_ib_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
num_sge = 0;
break;
- case IB_WR_REG_SIG_MR:
- qp->sq.wr_data[idx] = IB_WR_REG_SIG_MR;
- mr = to_mmr(sig_handover_wr(wr)->sig_mr);
-
+ case IB_WR_REG_MR_INTEGRITY:
+ qp->sq.wr_data[idx] = IB_WR_REG_MR_INTEGRITY;
+
+ mr = to_mmr(reg_wr(wr)->mr);
+ pi_mr = mr->pi_mr;
+
+ if (pi_mr) {
+ memset(&reg_pi_wr, 0,
+ sizeof(struct ib_reg_wr));
+
+ reg_pi_wr.mr = &pi_mr->ibmr;
+ reg_pi_wr.access = reg_wr(wr)->access;
+ reg_pi_wr.key = pi_mr->ibmr.rkey;
+
+ ctrl->imm = cpu_to_be32(reg_pi_wr.key);
+ /* UMR for data + prot registration */
+ err = set_reg_wr(qp, &reg_pi_wr, &seg,
+ &size, &cur_edge,
+ false);
+ if (err) {
+ *bad_wr = wr;
+ goto out;
+ }
+ finish_wqe(qp, ctrl, seg, size,
+ cur_edge, idx, wr->wr_id,
+ nreq, fence,
+ MLX5_OPCODE_UMR);
+
+ err = begin_wqe(qp, &seg, &ctrl, wr,
+ &idx, &size, &cur_edge,
+ nreq);
+ if (err) {
+ mlx5_ib_warn(dev, "\n");
+ err = -ENOMEM;
+ *bad_wr = wr;
+ goto out;
+ }
+ } else {
+ memset(&pa_pi_mr, 0,
+ sizeof(struct mlx5_ib_mr));
+ /* No UMR, use local_dma_lkey */
+ pa_pi_mr.ibmr.lkey =
+ mr->ibmr.pd->local_dma_lkey;
+
+ pa_pi_mr.ndescs = mr->ndescs;
+ pa_pi_mr.data_length = mr->data_length;
+ pa_pi_mr.data_iova = mr->data_iova;
+ if (mr->meta_ndescs) {
+ pa_pi_mr.meta_ndescs =
+ mr->meta_ndescs;
+ pa_pi_mr.meta_length =
+ mr->meta_length;
+ pa_pi_mr.pi_iova = mr->pi_iova;
+ }
+
+ pa_pi_mr.ibmr.length = mr->ibmr.length;
+ mr->pi_mr = &pa_pi_mr;
+ }
ctrl->imm = cpu_to_be32(mr->ibmr.rkey);
- err = set_sig_umr_wr(wr, qp, &seg, &size,
- &cur_edge);
+ /* UMR for sig MR */
+ err = set_pi_umr_wr(wr, qp, &seg, &size,
+ &cur_edge);
if (err) {
mlx5_ib_warn(dev, "\n");
*bad_wr = wr;
goto out;
}
-
finish_wqe(qp, ctrl, seg, size, cur_edge, idx,
wr->wr_id, nreq, fence,
MLX5_OPCODE_UMR);
+
/*
* SET_PSV WQEs are not signaled and solicited
* on error
*/
+ sig_attrs = mr->ibmr.sig_attrs;
err = __begin_wqe(qp, &seg, &ctrl, wr, &idx,
&size, &cur_edge, nreq, false,
true);
@@ -5040,19 +5152,18 @@ static int _mlx5_ib_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
*bad_wr = wr;
goto out;
}
-
- err = set_psv_wr(&sig_handover_wr(wr)->sig_attrs->mem,
- mr->sig->psv_memory.psv_idx, &seg,
- &size);
+ err = set_psv_wr(&sig_attrs->mem,
+ mr->sig->psv_memory.psv_idx,
+ &seg, &size);
if (err) {
mlx5_ib_warn(dev, "\n");
*bad_wr = wr;
goto out;
}
-
finish_wqe(qp, ctrl, seg, size, cur_edge, idx,
- wr->wr_id, nreq, fence,
+ wr->wr_id, nreq, next_fence,
MLX5_OPCODE_SET_PSV);
+
err = __begin_wqe(qp, &seg, &ctrl, wr, &idx,
&size, &cur_edge, nreq, false,
true);
@@ -5062,20 +5173,20 @@ static int _mlx5_ib_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
*bad_wr = wr;
goto out;
}
-
- err = set_psv_wr(&sig_handover_wr(wr)->sig_attrs->wire,
- mr->sig->psv_wire.psv_idx, &seg,
- &size);
+ err = set_psv_wr(&sig_attrs->wire,
+ mr->sig->psv_wire.psv_idx,
+ &seg, &size);
if (err) {
mlx5_ib_warn(dev, "\n");
*bad_wr = wr;
goto out;
}
-
finish_wqe(qp, ctrl, seg, size, cur_edge, idx,
- wr->wr_id, nreq, fence,
+ wr->wr_id, nreq, next_fence,
MLX5_OPCODE_SET_PSV);
- qp->next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL;
+
+ qp->next_fence =
+ MLX5_FENCE_MODE_INITIATOR_SMALL;
num_sge = 0;
goto skip_psv;
@@ -6047,7 +6158,7 @@ err:
return ERR_PTR(err);
}
-int mlx5_ib_destroy_wq(struct ib_wq *wq, struct ib_udata *udata)
+void mlx5_ib_destroy_wq(struct ib_wq *wq, struct ib_udata *udata)
{
struct mlx5_ib_dev *dev = to_mdev(wq->device);
struct mlx5_ib_rwq *rwq = to_mrwq(wq);
@@ -6055,8 +6166,6 @@ int mlx5_ib_destroy_wq(struct ib_wq *wq, struct ib_udata *udata)
mlx5_core_destroy_rq_tracked(dev->mdev, &rwq->core_qp);
destroy_user_rq(dev, wq->pd, rwq, udata);
kfree(rwq);
-
- return 0;
}
struct ib_rwq_ind_table *mlx5_ib_create_rwq_ind_table(struct ib_device *device,
@@ -6297,7 +6406,7 @@ static void handle_drain_completion(struct ib_cq *cq,
/* Run the CQ handler - this makes sure that the drain WR will
* be processed if wasn't processed yet.
*/
- mcq->mcq.comp(&mcq->mcq);
+ mcq->mcq.comp(&mcq->mcq, NULL);
}
wait_for_completion(&sdrain->done);
@@ -6367,3 +6476,34 @@ void mlx5_ib_drain_rq(struct ib_qp *qp)
handle_drain_completion(cq, &rdrain, dev);
}
+
+/**
+ * Bind a qp to a counter. If @counter is NULL then bind the qp to
+ * the default counter
+ */
+int mlx5_ib_qp_set_counter(struct ib_qp *qp, struct rdma_counter *counter)
+{
+ struct mlx5_ib_qp *mqp = to_mqp(qp);
+ int err = 0;
+
+ mutex_lock(&mqp->mutex);
+ if (mqp->state == IB_QPS_RESET) {
+ qp->counter = counter;
+ goto out;
+ }
+
+ if (mqp->state == IB_QPS_RTS) {
+ err = __mlx5_ib_qp_set_counter(qp, counter);
+ if (!err)
+ qp->counter = counter;
+
+ goto out;
+ }
+
+ mqp->counter_pending = 1;
+ qp->counter = counter;
+
+out:
+ mutex_unlock(&mqp->mutex);
+ return err;
+}
diff --git a/drivers/infiniband/hw/mthca/mthca_allocator.c b/drivers/infiniband/hw/mthca/mthca_allocator.c
index aaf10dd5364d..aef1d274a14e 100644
--- a/drivers/infiniband/hw/mthca/mthca_allocator.c
+++ b/drivers/infiniband/hw/mthca/mthca_allocator.c
@@ -214,8 +214,6 @@ int mthca_buf_alloc(struct mthca_dev *dev, int size, int max_direct,
dma_unmap_addr_set(&buf->direct, mapping, t);
- memset(buf->direct.buf, 0, size);
-
while (t & ((1 << shift) - 1)) {
--shift;
npages *= 2;
diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c
index 8ff0e90d7564..edccfd6e178f 100644
--- a/drivers/infiniband/hw/mthca/mthca_memfree.c
+++ b/drivers/infiniband/hw/mthca/mthca_memfree.c
@@ -482,7 +482,7 @@ int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
ret = pci_map_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE);
if (ret < 0) {
- put_page(pages[0]);
+ put_user_page(pages[0]);
goto out;
}
@@ -490,7 +490,7 @@ int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
mthca_uarc_virt(dev, uar, i));
if (ret) {
pci_unmap_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE);
- put_page(sg_page(&db_tab->page[i].mem));
+ put_user_page(sg_page(&db_tab->page[i].mem));
goto out;
}
@@ -556,7 +556,7 @@ void mthca_cleanup_user_db_tab(struct mthca_dev *dev, struct mthca_uar *uar,
if (db_tab->page[i].uvirt) {
mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, uar, i), 1);
pci_unmap_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE);
- put_page(sg_page(&db_tab->page[i].mem));
+ put_user_page(sg_page(&db_tab->page[i].mem));
}
}
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
index 4f40dfedf920..23554d8bf241 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -601,10 +601,11 @@ static int mthca_destroy_qp(struct ib_qp *qp, struct ib_udata *udata)
return 0;
}
-static struct ib_cq *mthca_create_cq(struct ib_device *ibdev,
- const struct ib_cq_init_attr *attr,
- struct ib_udata *udata)
+static int mthca_create_cq(struct ib_cq *ibcq,
+ const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata)
{
+ struct ib_device *ibdev = ibcq->device;
int entries = attr->cqe;
struct mthca_create_cq ucmd;
struct mthca_cq *cq;
@@ -614,20 +615,20 @@ static struct ib_cq *mthca_create_cq(struct ib_device *ibdev,
udata, struct mthca_ucontext, ibucontext);
if (attr->flags)
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
if (entries < 1 || entries > to_mdev(ibdev)->limits.max_cqes)
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
if (udata) {
- if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd))
- return ERR_PTR(-EFAULT);
+ if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd)))
+ return -EFAULT;
err = mthca_map_user_db(to_mdev(ibdev), &context->uar,
context->db_tab, ucmd.set_db_index,
ucmd.set_db_page);
if (err)
- return ERR_PTR(err);
+ return err;
err = mthca_map_user_db(to_mdev(ibdev), &context->uar,
context->db_tab, ucmd.arm_db_index,
@@ -636,11 +637,7 @@ static struct ib_cq *mthca_create_cq(struct ib_device *ibdev,
goto err_unmap_set;
}
- cq = kzalloc(sizeof(*cq), GFP_KERNEL);
- if (!cq) {
- err = -ENOMEM;
- goto err_unmap_arm;
- }
+ cq = to_mcq(ibcq);
if (udata) {
cq->buf.mr.ibmr.lkey = ucmd.lkey;
@@ -655,20 +652,17 @@ static struct ib_cq *mthca_create_cq(struct ib_device *ibdev,
udata ? ucmd.pdn : to_mdev(ibdev)->driver_pd.pd_num,
cq);
if (err)
- goto err_free;
+ goto err_unmap_arm;
if (udata && ib_copy_to_udata(udata, &cq->cqn, sizeof(__u32))) {
mthca_free_cq(to_mdev(ibdev), cq);
err = -EFAULT;
- goto err_free;
+ goto err_unmap_arm;
}
cq->resize_buf = NULL;
- return &cq->ibcq;
-
-err_free:
- kfree(cq);
+ return 0;
err_unmap_arm:
if (udata)
@@ -680,7 +674,7 @@ err_unmap_set:
mthca_unmap_user_db(to_mdev(ibdev), &context->uar,
context->db_tab, ucmd.set_db_index);
- return ERR_PTR(err);
+ return err;
}
static int mthca_alloc_resize_buf(struct mthca_dev *dev, struct mthca_cq *cq,
@@ -804,7 +798,7 @@ out:
return ret;
}
-static int mthca_destroy_cq(struct ib_cq *cq, struct ib_udata *udata)
+static void mthca_destroy_cq(struct ib_cq *cq, struct ib_udata *udata)
{
if (udata) {
struct mthca_ucontext *context =
@@ -823,9 +817,6 @@ static int mthca_destroy_cq(struct ib_cq *cq, struct ib_udata *udata)
to_mcq(cq)->set_ci_db_index);
}
mthca_free_cq(to_mdev(cq->device), to_mcq(cq));
- kfree(cq);
-
- return 0;
}
static inline u32 convert_access(int acc)
@@ -962,8 +953,7 @@ static int mthca_dereg_mr(struct ib_mr *mr, struct ib_udata *udata)
struct mthca_mr *mmr = to_mmr(mr);
mthca_free_mr(to_mdev(mr->device), mmr);
- if (mmr->umem)
- ib_umem_release(mmr->umem);
+ ib_umem_release(mmr->umem);
kfree(mmr);
return 0;
@@ -1153,6 +1143,11 @@ static void get_dev_fw_str(struct ib_device *device, char *str)
}
static const struct ib_device_ops mthca_dev_ops = {
+ .owner = THIS_MODULE,
+ .driver_id = RDMA_DRIVER_MTHCA,
+ .uverbs_abi_ver = MTHCA_UVERBS_ABI_VERSION,
+ .uverbs_no_driver_id_binding = 1,
+
.alloc_pd = mthca_alloc_pd,
.alloc_ucontext = mthca_alloc_ucontext,
.attach_mcast = mthca_multicast_attach,
@@ -1185,6 +1180,7 @@ static const struct ib_device_ops mthca_dev_ops = {
.resize_cq = mthca_resize_cq,
INIT_RDMA_OBJ_SIZE(ib_ah, mthca_ah, ibah),
+ INIT_RDMA_OBJ_SIZE(ib_cq, mthca_cq, ibcq),
INIT_RDMA_OBJ_SIZE(ib_pd, mthca_pd, ibpd),
INIT_RDMA_OBJ_SIZE(ib_ucontext, mthca_ucontext, ibucontext),
};
@@ -1243,9 +1239,6 @@ int mthca_register_device(struct mthca_dev *dev)
if (ret)
return ret;
- dev->ib_dev.owner = THIS_MODULE;
-
- dev->ib_dev.uverbs_abi_ver = MTHCA_UVERBS_ABI_VERSION;
dev->ib_dev.uverbs_cmd_mask =
(1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
(1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |
@@ -1303,7 +1296,6 @@ int mthca_register_device(struct mthca_dev *dev)
mutex_init(&dev->cap_mask_mutex);
rdma_set_device_sysfs_group(&dev->ib_dev, &mthca_attr_group);
- dev->ib_dev.driver_id = RDMA_DRIVER_MTHCA;
ret = ib_register_device(&dev->ib_dev, "mthca%d");
if (ret)
return ret;
diff --git a/drivers/infiniband/hw/nes/Kconfig b/drivers/infiniband/hw/nes/Kconfig
deleted file mode 100644
index 8245353e8106..000000000000
--- a/drivers/infiniband/hw/nes/Kconfig
+++ /dev/null
@@ -1,16 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-config INFINIBAND_NES
- tristate "NetEffect RNIC Driver"
- depends on PCI && INET
- select LIBCRC32C
- ---help---
- This is the RDMA Network Interface Card (RNIC) driver for
- NetEffect Ethernet Cluster Server Adapters.
-
-config INFINIBAND_NES_DEBUG
- bool "Verbose debugging output"
- depends on INFINIBAND_NES
- default n
- ---help---
- This option enables debug messages from the NetEffect RNIC
- driver. Select this if you are diagnosing a problem.
diff --git a/drivers/infiniband/hw/nes/Makefile b/drivers/infiniband/hw/nes/Makefile
deleted file mode 100644
index 239689ad1f9e..000000000000
--- a/drivers/infiniband/hw/nes/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_INFINIBAND_NES) += iw_nes.o
-
-iw_nes-objs := nes.o nes_hw.o nes_nic.o nes_utils.o nes_verbs.o nes_cm.o nes_mgt.o
diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c
deleted file mode 100644
index e00add6d78ec..000000000000
--- a/drivers/infiniband/hw/nes/nes.c
+++ /dev/null
@@ -1,1205 +0,0 @@
-/*
- * Copyright (c) 2006 - 2011 Intel Corporation. All rights reserved.
- * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/ethtool.h>
-#include <linux/mii.h>
-#include <linux/if_vlan.h>
-#include <linux/crc32.h>
-#include <linux/in.h>
-#include <linux/fs.h>
-#include <linux/init.h>
-#include <linux/if_arp.h>
-#include <linux/highmem.h>
-#include <linux/slab.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/byteorder.h>
-#include <rdma/ib_smi.h>
-#include <rdma/ib_verbs.h>
-#include <rdma/ib_pack.h>
-#include <rdma/iw_cm.h>
-
-#include "nes.h"
-
-#include <net/netevent.h>
-#include <net/neighbour.h>
-#include <linux/route.h>
-#include <net/ip_fib.h>
-
-MODULE_AUTHOR("NetEffect");
-MODULE_DESCRIPTION("NetEffect RNIC Low-level iWARP Driver");
-MODULE_LICENSE("Dual BSD/GPL");
-
-int interrupt_mod_interval = 0;
-
-/* Interoperability */
-int mpa_version = 1;
-module_param(mpa_version, int, 0644);
-MODULE_PARM_DESC(mpa_version, "MPA version to be used int MPA Req/Resp (0 or 1)");
-
-/* Interoperability */
-int disable_mpa_crc = 0;
-module_param(disable_mpa_crc, int, 0644);
-MODULE_PARM_DESC(disable_mpa_crc, "Disable checking of MPA CRC");
-
-unsigned int nes_drv_opt = NES_DRV_OPT_DISABLE_INT_MOD | NES_DRV_OPT_ENABLE_PAU;
-module_param(nes_drv_opt, int, 0644);
-MODULE_PARM_DESC(nes_drv_opt, "Driver option parameters");
-
-unsigned int nes_debug_level = 0;
-module_param_named(debug_level, nes_debug_level, uint, 0644);
-MODULE_PARM_DESC(debug_level, "Enable debug output level");
-
-unsigned int wqm_quanta = 0x10000;
-module_param(wqm_quanta, int, 0644);
-MODULE_PARM_DESC(wqm_quanta, "WQM quanta");
-
-static bool limit_maxrdreqsz;
-module_param(limit_maxrdreqsz, bool, 0644);
-MODULE_PARM_DESC(limit_maxrdreqsz, "Limit max read request size to 256 Bytes");
-
-LIST_HEAD(nes_adapter_list);
-static LIST_HEAD(nes_dev_list);
-
-atomic_t qps_destroyed;
-
-static unsigned int ee_flsh_adapter;
-static unsigned int sysfs_nonidx_addr;
-static unsigned int sysfs_idx_addr;
-
-static const struct pci_device_id nes_pci_table[] = {
- { PCI_VDEVICE(NETEFFECT, PCI_DEVICE_ID_NETEFFECT_NE020), },
- { PCI_VDEVICE(NETEFFECT, PCI_DEVICE_ID_NETEFFECT_NE020_KR), },
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, nes_pci_table);
-
-static int nes_inetaddr_event(struct notifier_block *, unsigned long, void *);
-static int nes_net_event(struct notifier_block *, unsigned long, void *);
-static int nes_notifiers_registered;
-
-
-static struct notifier_block nes_inetaddr_notifier = {
- .notifier_call = nes_inetaddr_event
-};
-
-static struct notifier_block nes_net_notifier = {
- .notifier_call = nes_net_event
-};
-
-/**
- * nes_inetaddr_event
- */
-static int nes_inetaddr_event(struct notifier_block *notifier,
- unsigned long event, void *ptr)
-{
- struct in_ifaddr *ifa = ptr;
- struct net_device *event_netdev = ifa->ifa_dev->dev;
- struct nes_device *nesdev;
- struct net_device *netdev;
- struct net_device *upper_dev;
- struct nes_vnic *nesvnic;
- unsigned int is_bonded;
-
- nes_debug(NES_DBG_NETDEV, "nes_inetaddr_event: ip address %pI4, netmask %pI4.\n",
- &ifa->ifa_address, &ifa->ifa_mask);
- list_for_each_entry(nesdev, &nes_dev_list, list) {
- nes_debug(NES_DBG_NETDEV, "Nesdev list entry = 0x%p. (%s)\n",
- nesdev, nesdev->netdev[0]->name);
- netdev = nesdev->netdev[0];
- nesvnic = netdev_priv(netdev);
- upper_dev = netdev_master_upper_dev_get(netdev);
- is_bonded = netif_is_bond_slave(netdev) &&
- (upper_dev == event_netdev);
- if ((netdev == event_netdev) || is_bonded) {
- if (nesvnic->rdma_enabled == 0) {
- nes_debug(NES_DBG_NETDEV, "Returning without processing event for %s since"
- " RDMA is not enabled.\n",
- netdev->name);
- return NOTIFY_OK;
- }
- /* we have ifa->ifa_address/mask here if we need it */
- switch (event) {
- case NETDEV_DOWN:
- nes_debug(NES_DBG_NETDEV, "event:DOWN\n");
- nes_write_indexed(nesdev,
- NES_IDX_DST_IP_ADDR+(0x10*PCI_FUNC(nesdev->pcidev->devfn)), 0);
-
- nes_manage_arp_cache(netdev, netdev->dev_addr,
- ntohl(nesvnic->local_ipaddr), NES_ARP_DELETE);
- nesvnic->local_ipaddr = 0;
- if (is_bonded)
- continue;
- else
- return NOTIFY_OK;
- break;
- case NETDEV_UP:
- nes_debug(NES_DBG_NETDEV, "event:UP\n");
-
- if (nesvnic->local_ipaddr != 0) {
- nes_debug(NES_DBG_NETDEV, "Interface already has local_ipaddr\n");
- return NOTIFY_OK;
- }
- /* fall through */
- case NETDEV_CHANGEADDR:
- /* Add the address to the IP table */
- if (upper_dev) {
- struct in_device *in;
-
- rcu_read_lock();
- in = __in_dev_get_rcu(upper_dev);
- nesvnic->local_ipaddr = in->ifa_list->ifa_address;
- rcu_read_unlock();
- } else {
- nesvnic->local_ipaddr = ifa->ifa_address;
- }
-
- nes_write_indexed(nesdev,
- NES_IDX_DST_IP_ADDR+(0x10*PCI_FUNC(nesdev->pcidev->devfn)),
- ntohl(nesvnic->local_ipaddr));
- nes_manage_arp_cache(netdev, netdev->dev_addr,
- ntohl(nesvnic->local_ipaddr), NES_ARP_ADD);
- if (is_bonded)
- continue;
- else
- return NOTIFY_OK;
- break;
- default:
- break;
- }
- }
- }
-
- return NOTIFY_DONE;
-}
-
-
-/**
- * nes_net_event
- */
-static int nes_net_event(struct notifier_block *notifier,
- unsigned long event, void *ptr)
-{
- struct neighbour *neigh = ptr;
- struct nes_device *nesdev;
- struct net_device *netdev;
- struct nes_vnic *nesvnic;
-
- switch (event) {
- case NETEVENT_NEIGH_UPDATE:
- list_for_each_entry(nesdev, &nes_dev_list, list) {
- /* nes_debug(NES_DBG_NETDEV, "Nesdev list entry = 0x%p.\n", nesdev); */
- netdev = nesdev->netdev[0];
- nesvnic = netdev_priv(netdev);
- if (netdev == neigh->dev) {
- if (nesvnic->rdma_enabled == 0) {
- nes_debug(NES_DBG_NETDEV, "Skipping device %s since no RDMA\n",
- netdev->name);
- } else {
- if (neigh->nud_state & NUD_VALID) {
- nes_manage_arp_cache(neigh->dev, neigh->ha,
- ntohl(*(__be32 *)neigh->primary_key), NES_ARP_ADD);
- } else {
- nes_manage_arp_cache(neigh->dev, neigh->ha,
- ntohl(*(__be32 *)neigh->primary_key), NES_ARP_DELETE);
- }
- }
- return NOTIFY_OK;
- }
- }
- break;
- default:
- nes_debug(NES_DBG_NETDEV, "NETEVENT_ %lu undefined\n", event);
- break;
- }
-
- return NOTIFY_DONE;
-}
-
-
-/**
- * nes_add_ref
- */
-void nes_add_ref(struct ib_qp *ibqp)
-{
- struct nes_qp *nesqp;
-
- nesqp = to_nesqp(ibqp);
- nes_debug(NES_DBG_QP, "Bumping refcount for QP%u. Pre-inc value = %u\n",
- ibqp->qp_num, atomic_read(&nesqp->refcount));
- atomic_inc(&nesqp->refcount);
-}
-
-static void nes_cqp_rem_ref_callback(struct nes_device *nesdev, struct nes_cqp_request *cqp_request)
-{
- unsigned long flags;
- struct nes_qp *nesqp = cqp_request->cqp_callback_pointer;
- struct nes_adapter *nesadapter = nesdev->nesadapter;
-
- atomic_inc(&qps_destroyed);
-
- /* Free the control structures */
-
- if (nesqp->pbl_vbase) {
- pci_free_consistent(nesdev->pcidev, nesqp->qp_mem_size,
- nesqp->hwqp.q2_vbase, nesqp->hwqp.q2_pbase);
- spin_lock_irqsave(&nesadapter->pbl_lock, flags);
- nesadapter->free_256pbl++;
- spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
- pci_free_consistent(nesdev->pcidev, 256, nesqp->pbl_vbase, nesqp->pbl_pbase);
- nesqp->pbl_vbase = NULL;
-
- } else {
- pci_free_consistent(nesdev->pcidev, nesqp->qp_mem_size,
- nesqp->hwqp.sq_vbase, nesqp->hwqp.sq_pbase);
- }
- nes_free_resource(nesadapter, nesadapter->allocated_qps, nesqp->hwqp.qp_id);
-
- nesadapter->qp_table[nesqp->hwqp.qp_id-NES_FIRST_QPN] = NULL;
- kfree(nesqp->allocated_buffer);
-
-}
-
-/**
- * nes_rem_ref
- */
-void nes_rem_ref(struct ib_qp *ibqp)
-{
- u64 u64temp;
- struct nes_qp *nesqp;
- struct nes_vnic *nesvnic = to_nesvnic(ibqp->device);
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_hw_cqp_wqe *cqp_wqe;
- struct nes_cqp_request *cqp_request;
- u32 opcode;
-
- nesqp = to_nesqp(ibqp);
-
- if (atomic_read(&nesqp->refcount) == 0) {
- printk(KERN_INFO PFX "%s: Reference count already 0 for QP%d, last aeq = 0x%04X.\n",
- __func__, ibqp->qp_num, nesqp->last_aeq);
- BUG();
- }
-
- if (atomic_dec_and_test(&nesqp->refcount)) {
- if (nesqp->pau_mode)
- nes_destroy_pau_qp(nesdev, nesqp);
-
- /* Destroy the QP */
- cqp_request = nes_get_cqp_request(nesdev);
- if (cqp_request == NULL) {
- nes_debug(NES_DBG_QP, "Failed to get a cqp_request.\n");
- return;
- }
- cqp_request->waiting = 0;
- cqp_request->callback = 1;
- cqp_request->cqp_callback = nes_cqp_rem_ref_callback;
- cqp_request->cqp_callback_pointer = nesqp;
- cqp_wqe = &cqp_request->cqp_wqe;
-
- nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
- opcode = NES_CQP_DESTROY_QP | NES_CQP_QP_TYPE_IWARP;
-
- if (nesqp->hte_added) {
- opcode |= NES_CQP_QP_DEL_HTE;
- nesqp->hte_added = 0;
- }
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, opcode);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX, nesqp->hwqp.qp_id);
- u64temp = (u64)nesqp->nesqp_context_pbase;
- set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_CONTEXT_LOW_IDX, u64temp);
- nes_post_cqp_request(nesdev, cqp_request);
- }
-}
-
-
-/**
- * nes_get_qp
- */
-struct ib_qp *nes_get_qp(struct ib_device *device, int qpn)
-{
- struct nes_vnic *nesvnic = to_nesvnic(device);
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_adapter *nesadapter = nesdev->nesadapter;
-
- if ((qpn < NES_FIRST_QPN) || (qpn >= (NES_FIRST_QPN + nesadapter->max_qp)))
- return NULL;
-
- return &nesadapter->qp_table[qpn - NES_FIRST_QPN]->ibqp;
-}
-
-
-/**
- * nes_print_macaddr
- */
-static void nes_print_macaddr(struct net_device *netdev)
-{
- nes_debug(NES_DBG_INIT, "%s: %pM, IRQ %u\n",
- netdev->name, netdev->dev_addr, netdev->irq);
-}
-
-/**
- * nes_interrupt - handle interrupts
- */
-static irqreturn_t nes_interrupt(int irq, void *dev_id)
-{
- struct nes_device *nesdev = (struct nes_device *)dev_id;
- int handled = 0;
- u32 int_mask;
- u32 int_req;
- u32 int_stat;
- u32 intf_int_stat;
- u32 timer_stat;
-
- if (nesdev->msi_enabled) {
- /* No need to read the interrupt pending register if msi is enabled */
- handled = 1;
- } else {
- if (unlikely(nesdev->nesadapter->hw_rev == NE020_REV)) {
- /* Master interrupt enable provides synchronization for kicking off bottom half
- when interrupt sharing is going on */
- int_mask = nes_read32(nesdev->regs + NES_INT_MASK);
- if (int_mask & 0x80000000) {
- /* Check interrupt status to see if this might be ours */
- int_stat = nes_read32(nesdev->regs + NES_INT_STAT);
- int_req = nesdev->int_req;
- if (int_stat&int_req) {
- /* if interesting CEQ or AEQ is pending, claim the interrupt */
- if ((int_stat&int_req) & (~(NES_INT_TIMER|NES_INT_INTF))) {
- handled = 1;
- } else {
- if (((int_stat & int_req) & NES_INT_TIMER) == NES_INT_TIMER) {
- /* Timer might be running but might be for another function */
- timer_stat = nes_read32(nesdev->regs + NES_TIMER_STAT);
- if ((timer_stat & nesdev->timer_int_req) != 0) {
- handled = 1;
- }
- }
- if ((((int_stat & int_req) & NES_INT_INTF) == NES_INT_INTF) &&
- (handled == 0)) {
- intf_int_stat = nes_read32(nesdev->regs+NES_INTF_INT_STAT);
- if ((intf_int_stat & nesdev->intf_int_req) != 0) {
- handled = 1;
- }
- }
- }
- if (handled) {
- nes_write32(nesdev->regs+NES_INT_MASK, int_mask & (~0x80000000));
- int_mask = nes_read32(nesdev->regs+NES_INT_MASK);
- /* Save off the status to save an additional read */
- nesdev->int_stat = int_stat;
- nesdev->napi_isr_ran = 1;
- }
- }
- }
- } else {
- handled = nes_read32(nesdev->regs+NES_INT_PENDING);
- }
- }
-
- if (handled) {
-
- if (nes_napi_isr(nesdev) == 0) {
- tasklet_schedule(&nesdev->dpc_tasklet);
-
- }
- return IRQ_HANDLED;
- } else {
- return IRQ_NONE;
- }
-}
-
-
-/**
- * nes_probe - Device initialization
- */
-static int nes_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
-{
- struct net_device *netdev = NULL;
- struct nes_device *nesdev = NULL;
- int ret = 0;
- void __iomem *mmio_regs = NULL;
- u8 hw_rev;
-
- printk(KERN_INFO PFX "NetEffect RNIC driver v%s loading. (%s)\n",
- DRV_VERSION, pci_name(pcidev));
-
- ret = pci_enable_device(pcidev);
- if (ret) {
- printk(KERN_ERR PFX "Unable to enable PCI device. (%s)\n", pci_name(pcidev));
- goto bail0;
- }
-
- nes_debug(NES_DBG_INIT, "BAR0 (@0x%08lX) size = 0x%lX bytes\n",
- (long unsigned int)pci_resource_start(pcidev, BAR_0),
- (long unsigned int)pci_resource_len(pcidev, BAR_0));
- nes_debug(NES_DBG_INIT, "BAR1 (@0x%08lX) size = 0x%lX bytes\n",
- (long unsigned int)pci_resource_start(pcidev, BAR_1),
- (long unsigned int)pci_resource_len(pcidev, BAR_1));
-
- /* Make sure PCI base addr are MMIO */
- if (!(pci_resource_flags(pcidev, BAR_0) & IORESOURCE_MEM) ||
- !(pci_resource_flags(pcidev, BAR_1) & IORESOURCE_MEM)) {
- printk(KERN_ERR PFX "PCI regions not an MMIO resource\n");
- ret = -ENODEV;
- goto bail1;
- }
-
- /* Reserve PCI I/O and memory resources */
- ret = pci_request_regions(pcidev, DRV_NAME);
- if (ret) {
- printk(KERN_ERR PFX "Unable to request regions. (%s)\n", pci_name(pcidev));
- goto bail1;
- }
-
- if ((sizeof(dma_addr_t) > 4)) {
- ret = pci_set_dma_mask(pcidev, DMA_BIT_MASK(64));
- if (ret < 0) {
- printk(KERN_ERR PFX "64b DMA mask configuration failed\n");
- goto bail2;
- }
- ret = pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(64));
- if (ret) {
- printk(KERN_ERR PFX "64b DMA consistent mask configuration failed\n");
- goto bail2;
- }
- } else {
- ret = pci_set_dma_mask(pcidev, DMA_BIT_MASK(32));
- if (ret < 0) {
- printk(KERN_ERR PFX "32b DMA mask configuration failed\n");
- goto bail2;
- }
- ret = pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(32));
- if (ret) {
- printk(KERN_ERR PFX "32b DMA consistent mask configuration failed\n");
- goto bail2;
- }
- }
-
- pci_set_master(pcidev);
-
- /* Allocate hardware structure */
- nesdev = kzalloc(sizeof(struct nes_device), GFP_KERNEL);
- if (!nesdev) {
- ret = -ENOMEM;
- goto bail2;
- }
-
- nes_debug(NES_DBG_INIT, "Allocated nes device at %p\n", nesdev);
- nesdev->pcidev = pcidev;
- pci_set_drvdata(pcidev, nesdev);
-
- pci_read_config_byte(pcidev, 0x0008, &hw_rev);
- nes_debug(NES_DBG_INIT, "hw_rev=%u\n", hw_rev);
-
- spin_lock_init(&nesdev->indexed_regs_lock);
-
- /* Remap the PCI registers in adapter BAR0 to kernel VA space */
- mmio_regs = ioremap_nocache(pci_resource_start(pcidev, BAR_0),
- pci_resource_len(pcidev, BAR_0));
- if (mmio_regs == NULL) {
- printk(KERN_ERR PFX "Unable to remap BAR0\n");
- ret = -EIO;
- goto bail3;
- }
- nesdev->regs = mmio_regs;
- nesdev->index_reg = 0x50 + (PCI_FUNC(pcidev->devfn)*8) + mmio_regs;
-
- /* Ensure interrupts are disabled */
- nes_write32(nesdev->regs+NES_INT_MASK, 0x7fffffff);
-
- if (nes_drv_opt & NES_DRV_OPT_ENABLE_MSI) {
- if (!pci_enable_msi(nesdev->pcidev)) {
- nesdev->msi_enabled = 1;
- nes_debug(NES_DBG_INIT, "MSI is enabled for device %s\n",
- pci_name(pcidev));
- } else {
- nes_debug(NES_DBG_INIT, "MSI is disabled by linux for device %s\n",
- pci_name(pcidev));
- }
- } else {
- nes_debug(NES_DBG_INIT, "MSI not requested due to driver options for device %s\n",
- pci_name(pcidev));
- }
-
- nesdev->csr_start = pci_resource_start(nesdev->pcidev, BAR_0);
- nesdev->doorbell_region = pci_resource_start(nesdev->pcidev, BAR_1);
-
- /* Init the adapter */
- nesdev->nesadapter = nes_init_adapter(nesdev, hw_rev);
- if (!nesdev->nesadapter) {
- printk(KERN_ERR PFX "Unable to initialize adapter.\n");
- ret = -ENOMEM;
- goto bail5;
- }
- nesdev->nesadapter->et_rx_coalesce_usecs_irq = interrupt_mod_interval;
- nesdev->nesadapter->wqm_quanta = wqm_quanta;
-
- /* nesdev->base_doorbell_index =
- nesdev->nesadapter->pd_config_base[PCI_FUNC(nesdev->pcidev->devfn)]; */
- nesdev->base_doorbell_index = 1;
- nesdev->doorbell_start = nesdev->nesadapter->doorbell_start;
- if (nesdev->nesadapter->phy_type[0] == NES_PHY_TYPE_PUMA_1G) {
- switch (PCI_FUNC(nesdev->pcidev->devfn) %
- nesdev->nesadapter->port_count) {
- case 1:
- nesdev->mac_index = 2;
- break;
- case 2:
- nesdev->mac_index = 1;
- break;
- case 3:
- nesdev->mac_index = 3;
- break;
- case 0:
- default:
- nesdev->mac_index = 0;
- }
- } else {
- nesdev->mac_index = PCI_FUNC(nesdev->pcidev->devfn) %
- nesdev->nesadapter->port_count;
- }
-
- if ((limit_maxrdreqsz ||
- ((nesdev->nesadapter->phy_type[0] == NES_PHY_TYPE_GLADIUS) &&
- (hw_rev == NE020_REV1))) &&
- (pcie_get_readrq(pcidev) > 256)) {
- if (pcie_set_readrq(pcidev, 256))
- printk(KERN_ERR PFX "Unable to set max read request"
- " to 256 bytes\n");
- else
- nes_debug(NES_DBG_INIT, "Max read request size set"
- " to 256 bytes\n");
- }
-
- tasklet_init(&nesdev->dpc_tasklet, nes_dpc, (unsigned long)nesdev);
-
- /* bring up the Control QP */
- if (nes_init_cqp(nesdev)) {
- ret = -ENODEV;
- goto bail6;
- }
-
- /* Arm the CCQ */
- nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT |
- PCI_FUNC(nesdev->pcidev->devfn));
- nes_read32(nesdev->regs+NES_CQE_ALLOC);
-
- /* Enable the interrupts */
- nesdev->int_req = (0x101 << PCI_FUNC(nesdev->pcidev->devfn)) |
- (1 << (PCI_FUNC(nesdev->pcidev->devfn)+16));
- if (PCI_FUNC(nesdev->pcidev->devfn) < 4) {
- nesdev->int_req |= (1 << (PCI_FUNC(nesdev->mac_index)+24));
- }
-
- /* TODO: This really should be the first driver to load, not function 0 */
- if (PCI_FUNC(nesdev->pcidev->devfn) == 0) {
- /* pick up PCI and critical errors if the first driver to load */
- nesdev->intf_int_req = NES_INTF_INT_PCIERR | NES_INTF_INT_CRITERR;
- nesdev->int_req |= NES_INT_INTF;
- } else {
- nesdev->intf_int_req = 0;
- }
- nesdev->intf_int_req |= (1 << (PCI_FUNC(nesdev->pcidev->devfn)+16));
- nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS0, 0);
- nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS1, 0);
- nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS2, 0x00001265);
- nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS4, 0x18021804);
-
- nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS3, 0x17801790);
-
- /* deal with both periodic and one_shot */
- nesdev->timer_int_req = 0x101 << PCI_FUNC(nesdev->pcidev->devfn);
- nesdev->nesadapter->timer_int_req |= nesdev->timer_int_req;
- nes_debug(NES_DBG_INIT, "setting int_req for function %u, nesdev = 0x%04X, adapter = 0x%04X\n",
- PCI_FUNC(nesdev->pcidev->devfn),
- nesdev->timer_int_req, nesdev->nesadapter->timer_int_req);
-
- nes_write32(nesdev->regs+NES_INTF_INT_MASK, ~(nesdev->intf_int_req));
-
- list_add_tail(&nesdev->list, &nes_dev_list);
-
- /* Request an interrupt line for the driver */
- ret = request_irq(pcidev->irq, nes_interrupt, IRQF_SHARED, DRV_NAME, nesdev);
- if (ret) {
- printk(KERN_ERR PFX "%s: requested IRQ %u is busy\n",
- pci_name(pcidev), pcidev->irq);
- goto bail65;
- }
-
- nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
-
- if (nes_notifiers_registered == 0) {
- register_inetaddr_notifier(&nes_inetaddr_notifier);
- register_netevent_notifier(&nes_net_notifier);
- }
- nes_notifiers_registered++;
-
- INIT_DELAYED_WORK(&nesdev->work, nes_recheck_link_status);
-
- /* Initialize network devices */
- netdev = nes_netdev_init(nesdev, mmio_regs);
- if (netdev == NULL) {
- ret = -ENOMEM;
- goto bail7;
- }
-
- /* Register network device */
- ret = register_netdev(netdev);
- if (ret) {
- printk(KERN_ERR PFX "Unable to register netdev, ret = %d\n", ret);
- nes_netdev_destroy(netdev);
- goto bail7;
- }
-
- nes_print_macaddr(netdev);
-
- nesdev->netdev_count++;
- nesdev->nesadapter->netdev_count++;
-
- printk(KERN_INFO PFX "%s: NetEffect RNIC driver successfully loaded.\n",
- pci_name(pcidev));
- return 0;
-
- bail7:
- printk(KERN_ERR PFX "bail7\n");
- while (nesdev->netdev_count > 0) {
- nesdev->netdev_count--;
- nesdev->nesadapter->netdev_count--;
-
- unregister_netdev(nesdev->netdev[nesdev->netdev_count]);
- nes_netdev_destroy(nesdev->netdev[nesdev->netdev_count]);
- }
-
- nes_debug(NES_DBG_INIT, "netdev_count=%d, nesadapter->netdev_count=%d\n",
- nesdev->netdev_count, nesdev->nesadapter->netdev_count);
-
- nes_notifiers_registered--;
- if (nes_notifiers_registered == 0) {
- unregister_netevent_notifier(&nes_net_notifier);
- unregister_inetaddr_notifier(&nes_inetaddr_notifier);
- }
-
- list_del(&nesdev->list);
- nes_destroy_cqp(nesdev);
-
- bail65:
- printk(KERN_ERR PFX "bail65\n");
- free_irq(pcidev->irq, nesdev);
- if (nesdev->msi_enabled) {
- pci_disable_msi(pcidev);
- }
- bail6:
- printk(KERN_ERR PFX "bail6\n");
- tasklet_kill(&nesdev->dpc_tasklet);
- /* Deallocate the Adapter Structure */
- nes_destroy_adapter(nesdev->nesadapter);
-
- bail5:
- printk(KERN_ERR PFX "bail5\n");
- iounmap(nesdev->regs);
-
- bail3:
- printk(KERN_ERR PFX "bail3\n");
- kfree(nesdev);
-
- bail2:
- pci_release_regions(pcidev);
-
- bail1:
- pci_disable_device(pcidev);
-
- bail0:
- return ret;
-}
-
-
-/**
- * nes_remove - unload from kernel
- */
-static void nes_remove(struct pci_dev *pcidev)
-{
- struct nes_device *nesdev = pci_get_drvdata(pcidev);
- struct net_device *netdev;
- int netdev_index = 0;
- unsigned long flags;
-
- if (nesdev->netdev_count) {
- netdev = nesdev->netdev[netdev_index];
- if (netdev) {
- netif_stop_queue(netdev);
- unregister_netdev(netdev);
- nes_netdev_destroy(netdev);
-
- nesdev->netdev[netdev_index] = NULL;
- nesdev->netdev_count--;
- nesdev->nesadapter->netdev_count--;
- }
- }
-
- nes_notifiers_registered--;
- if (nes_notifiers_registered == 0) {
- unregister_netevent_notifier(&nes_net_notifier);
- unregister_inetaddr_notifier(&nes_inetaddr_notifier);
- }
-
- list_del(&nesdev->list);
- nes_destroy_cqp(nesdev);
-
- free_irq(pcidev->irq, nesdev);
- tasklet_kill(&nesdev->dpc_tasklet);
-
- spin_lock_irqsave(&nesdev->nesadapter->phy_lock, flags);
- if (nesdev->link_recheck) {
- spin_unlock_irqrestore(&nesdev->nesadapter->phy_lock, flags);
- cancel_delayed_work_sync(&nesdev->work);
- } else {
- spin_unlock_irqrestore(&nesdev->nesadapter->phy_lock, flags);
- }
-
- /* Deallocate the Adapter Structure */
- nes_destroy_adapter(nesdev->nesadapter);
-
- if (nesdev->msi_enabled) {
- pci_disable_msi(pcidev);
- }
-
- iounmap(nesdev->regs);
- kfree(nesdev);
-
- /* nes_debug(NES_DBG_SHUTDOWN, "calling pci_release_regions.\n"); */
- pci_release_regions(pcidev);
- pci_disable_device(pcidev);
- pci_set_drvdata(pcidev, NULL);
-}
-
-
-static ssize_t adapter_show(struct device_driver *ddp, char *buf)
-{
- unsigned int devfn = 0xffffffff;
- unsigned char bus_number = 0xff;
- unsigned int i = 0;
- struct nes_device *nesdev;
-
- list_for_each_entry(nesdev, &nes_dev_list, list) {
- if (i == ee_flsh_adapter) {
- devfn = nesdev->pcidev->devfn;
- bus_number = nesdev->pcidev->bus->number;
- break;
- }
- i++;
- }
-
- return snprintf(buf, PAGE_SIZE, "%x:%x\n", bus_number, devfn);
-}
-
-static ssize_t adapter_store(struct device_driver *ddp,
- const char *buf, size_t count)
-{
- char *p = (char *)buf;
-
- ee_flsh_adapter = simple_strtoul(p, &p, 10);
- return strnlen(buf, count);
-}
-
-static ssize_t eeprom_cmd_show(struct device_driver *ddp, char *buf)
-{
- u32 eeprom_cmd = 0xdead;
- u32 i = 0;
- struct nes_device *nesdev;
-
- list_for_each_entry(nesdev, &nes_dev_list, list) {
- if (i == ee_flsh_adapter) {
- eeprom_cmd = nes_read32(nesdev->regs + NES_EEPROM_COMMAND);
- break;
- }
- i++;
- }
- return snprintf(buf, PAGE_SIZE, "0x%x\n", eeprom_cmd);
-}
-
-static ssize_t eeprom_cmd_store(struct device_driver *ddp,
- const char *buf, size_t count)
-{
- char *p = (char *)buf;
- u32 val;
- u32 i = 0;
- struct nes_device *nesdev;
-
- if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
- val = simple_strtoul(p, &p, 16);
- list_for_each_entry(nesdev, &nes_dev_list, list) {
- if (i == ee_flsh_adapter) {
- nes_write32(nesdev->regs + NES_EEPROM_COMMAND, val);
- break;
- }
- i++;
- }
- }
- return strnlen(buf, count);
-}
-
-static ssize_t eeprom_data_show(struct device_driver *ddp, char *buf)
-{
- u32 eeprom_data = 0xdead;
- u32 i = 0;
- struct nes_device *nesdev;
-
- list_for_each_entry(nesdev, &nes_dev_list, list) {
- if (i == ee_flsh_adapter) {
- eeprom_data = nes_read32(nesdev->regs + NES_EEPROM_DATA);
- break;
- }
- i++;
- }
-
- return snprintf(buf, PAGE_SIZE, "0x%x\n", eeprom_data);
-}
-
-static ssize_t eeprom_data_store(struct device_driver *ddp,
- const char *buf, size_t count)
-{
- char *p = (char *)buf;
- u32 val;
- u32 i = 0;
- struct nes_device *nesdev;
-
- if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
- val = simple_strtoul(p, &p, 16);
- list_for_each_entry(nesdev, &nes_dev_list, list) {
- if (i == ee_flsh_adapter) {
- nes_write32(nesdev->regs + NES_EEPROM_DATA, val);
- break;
- }
- i++;
- }
- }
- return strnlen(buf, count);
-}
-
-static ssize_t flash_cmd_show(struct device_driver *ddp, char *buf)
-{
- u32 flash_cmd = 0xdead;
- u32 i = 0;
- struct nes_device *nesdev;
-
- list_for_each_entry(nesdev, &nes_dev_list, list) {
- if (i == ee_flsh_adapter) {
- flash_cmd = nes_read32(nesdev->regs + NES_FLASH_COMMAND);
- break;
- }
- i++;
- }
-
- return snprintf(buf, PAGE_SIZE, "0x%x\n", flash_cmd);
-}
-
-static ssize_t flash_cmd_store(struct device_driver *ddp,
- const char *buf, size_t count)
-{
- char *p = (char *)buf;
- u32 val;
- u32 i = 0;
- struct nes_device *nesdev;
-
- if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
- val = simple_strtoul(p, &p, 16);
- list_for_each_entry(nesdev, &nes_dev_list, list) {
- if (i == ee_flsh_adapter) {
- nes_write32(nesdev->regs + NES_FLASH_COMMAND, val);
- break;
- }
- i++;
- }
- }
- return strnlen(buf, count);
-}
-
-static ssize_t flash_data_show(struct device_driver *ddp, char *buf)
-{
- u32 flash_data = 0xdead;
- u32 i = 0;
- struct nes_device *nesdev;
-
- list_for_each_entry(nesdev, &nes_dev_list, list) {
- if (i == ee_flsh_adapter) {
- flash_data = nes_read32(nesdev->regs + NES_FLASH_DATA);
- break;
- }
- i++;
- }
-
- return snprintf(buf, PAGE_SIZE, "0x%x\n", flash_data);
-}
-
-static ssize_t flash_data_store(struct device_driver *ddp,
- const char *buf, size_t count)
-{
- char *p = (char *)buf;
- u32 val;
- u32 i = 0;
- struct nes_device *nesdev;
-
- if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
- val = simple_strtoul(p, &p, 16);
- list_for_each_entry(nesdev, &nes_dev_list, list) {
- if (i == ee_flsh_adapter) {
- nes_write32(nesdev->regs + NES_FLASH_DATA, val);
- break;
- }
- i++;
- }
- }
- return strnlen(buf, count);
-}
-
-static ssize_t nonidx_addr_show(struct device_driver *ddp, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "0x%x\n", sysfs_nonidx_addr);
-}
-
-static ssize_t nonidx_addr_store(struct device_driver *ddp,
- const char *buf, size_t count)
-{
- char *p = (char *)buf;
-
- if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X')
- sysfs_nonidx_addr = simple_strtoul(p, &p, 16);
-
- return strnlen(buf, count);
-}
-
-static ssize_t nonidx_data_show(struct device_driver *ddp, char *buf)
-{
- u32 nonidx_data = 0xdead;
- u32 i = 0;
- struct nes_device *nesdev;
-
- list_for_each_entry(nesdev, &nes_dev_list, list) {
- if (i == ee_flsh_adapter) {
- nonidx_data = nes_read32(nesdev->regs + sysfs_nonidx_addr);
- break;
- }
- i++;
- }
-
- return snprintf(buf, PAGE_SIZE, "0x%x\n", nonidx_data);
-}
-
-static ssize_t nonidx_data_store(struct device_driver *ddp,
- const char *buf, size_t count)
-{
- char *p = (char *)buf;
- u32 val;
- u32 i = 0;
- struct nes_device *nesdev;
-
- if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
- val = simple_strtoul(p, &p, 16);
- list_for_each_entry(nesdev, &nes_dev_list, list) {
- if (i == ee_flsh_adapter) {
- nes_write32(nesdev->regs + sysfs_nonidx_addr, val);
- break;
- }
- i++;
- }
- }
- return strnlen(buf, count);
-}
-
-static ssize_t idx_addr_show(struct device_driver *ddp, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "0x%x\n", sysfs_idx_addr);
-}
-
-static ssize_t idx_addr_store(struct device_driver *ddp,
- const char *buf, size_t count)
-{
- char *p = (char *)buf;
-
- if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X')
- sysfs_idx_addr = simple_strtoul(p, &p, 16);
-
- return strnlen(buf, count);
-}
-
-static ssize_t idx_data_show(struct device_driver *ddp, char *buf)
-{
- u32 idx_data = 0xdead;
- u32 i = 0;
- struct nes_device *nesdev;
-
- list_for_each_entry(nesdev, &nes_dev_list, list) {
- if (i == ee_flsh_adapter) {
- idx_data = nes_read_indexed(nesdev, sysfs_idx_addr);
- break;
- }
- i++;
- }
-
- return snprintf(buf, PAGE_SIZE, "0x%x\n", idx_data);
-}
-
-static ssize_t idx_data_store(struct device_driver *ddp,
- const char *buf, size_t count)
-{
- char *p = (char *)buf;
- u32 val;
- u32 i = 0;
- struct nes_device *nesdev;
-
- if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
- val = simple_strtoul(p, &p, 16);
- list_for_each_entry(nesdev, &nes_dev_list, list) {
- if (i == ee_flsh_adapter) {
- nes_write_indexed(nesdev, sysfs_idx_addr, val);
- break;
- }
- i++;
- }
- }
- return strnlen(buf, count);
-}
-
-static ssize_t wqm_quanta_show(struct device_driver *ddp, char *buf)
-{
- u32 wqm_quanta_value = 0xdead;
- u32 i = 0;
- struct nes_device *nesdev;
-
- list_for_each_entry(nesdev, &nes_dev_list, list) {
- if (i == ee_flsh_adapter) {
- wqm_quanta_value = nesdev->nesadapter->wqm_quanta;
- break;
- }
- i++;
- }
-
- return snprintf(buf, PAGE_SIZE, "0x%X\n", wqm_quanta_value);
-}
-
-static ssize_t wqm_quanta_store(struct device_driver *ddp, const char *buf,
- size_t count)
-{
- unsigned long wqm_quanta_value;
- u32 wqm_config1;
- u32 i = 0;
- struct nes_device *nesdev;
-
- if (kstrtoul(buf, 0, &wqm_quanta_value) < 0)
- return -EINVAL;
-
- list_for_each_entry(nesdev, &nes_dev_list, list) {
- if (i == ee_flsh_adapter) {
- nesdev->nesadapter->wqm_quanta = wqm_quanta_value;
- wqm_config1 = nes_read_indexed(nesdev,
- NES_IDX_WQM_CONFIG1);
- nes_write_indexed(nesdev, NES_IDX_WQM_CONFIG1,
- ((wqm_quanta_value << 1) |
- (wqm_config1 & 0x00000001)));
- break;
- }
- i++;
- }
- return strnlen(buf, count);
-}
-
-static DRIVER_ATTR_RW(adapter);
-static DRIVER_ATTR_RW(eeprom_cmd);
-static DRIVER_ATTR_RW(eeprom_data);
-static DRIVER_ATTR_RW(flash_cmd);
-static DRIVER_ATTR_RW(flash_data);
-static DRIVER_ATTR_RW(nonidx_addr);
-static DRIVER_ATTR_RW(nonidx_data);
-static DRIVER_ATTR_RW(idx_addr);
-static DRIVER_ATTR_RW(idx_data);
-static DRIVER_ATTR_RW(wqm_quanta);
-
-static struct attribute *nes_attrs[] = {
- &driver_attr_adapter.attr,
- &driver_attr_eeprom_cmd.attr,
- &driver_attr_eeprom_data.attr,
- &driver_attr_flash_cmd.attr,
- &driver_attr_flash_data.attr,
- &driver_attr_nonidx_addr.attr,
- &driver_attr_nonidx_data.attr,
- &driver_attr_idx_addr.attr,
- &driver_attr_idx_data.attr,
- &driver_attr_wqm_quanta.attr,
- NULL,
-};
-ATTRIBUTE_GROUPS(nes);
-
-static struct pci_driver nes_pci_driver = {
- .name = DRV_NAME,
- .id_table = nes_pci_table,
- .probe = nes_probe,
- .remove = nes_remove,
- .groups = nes_groups,
-};
-
-
-/**
- * nes_init_module - module initialization entry point
- */
-static int __init nes_init_module(void)
-{
- int retval;
-
- retval = nes_cm_start();
- if (retval) {
- printk(KERN_ERR PFX "Unable to start NetEffect iWARP CM.\n");
- return retval;
- }
- return pci_register_driver(&nes_pci_driver);
-}
-
-
-/**
- * nes_exit_module - module unload entry point
- */
-static void __exit nes_exit_module(void)
-{
- nes_cm_stop();
-
- pci_unregister_driver(&nes_pci_driver);
-}
-
-
-module_init(nes_init_module);
-module_exit(nes_exit_module);
diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h
deleted file mode 100644
index a895fe980d10..000000000000
--- a/drivers/infiniband/hw/nes/nes.h
+++ /dev/null
@@ -1,574 +0,0 @@
-/*
- * Copyright (c) 2006 - 2011 Intel Corporation. All rights reserved.
- * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef __NES_H
-#define __NES_H
-
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/dma-mapping.h>
-#include <linux/workqueue.h>
-#include <linux/slab.h>
-#include <asm/io.h>
-#include <linux/crc32c.h>
-
-#include <rdma/ib_smi.h>
-#include <rdma/ib_verbs.h>
-#include <rdma/ib_pack.h>
-#include <rdma/rdma_cm.h>
-#include <rdma/iw_cm.h>
-#include <rdma/rdma_netlink.h>
-#include <rdma/iw_portmap.h>
-
-#define NES_SEND_FIRST_WRITE
-
-#define QUEUE_DISCONNECTS
-
-#define DRV_NAME "iw_nes"
-#define DRV_VERSION "1.5.0.1"
-#define PFX DRV_NAME ": "
-
-/*
- * NetEffect PCI vendor id and NE010 PCI device id.
- */
-#ifndef PCI_VENDOR_ID_NETEFFECT /* not in pci.ids yet */
-#define PCI_VENDOR_ID_NETEFFECT 0x1678
-#define PCI_DEVICE_ID_NETEFFECT_NE020 0x0100
-#define PCI_DEVICE_ID_NETEFFECT_NE020_KR 0x0110
-#endif
-
-#define NE020_REV 4
-#define NE020_REV1 5
-
-#define BAR_0 0
-#define BAR_1 2
-
-#define RX_BUF_SIZE (1536 + 8)
-#define NES_REG0_SIZE (4 * 1024)
-#define NES_TX_TIMEOUT (6*HZ)
-#define NES_FIRST_QPN 64
-#define NES_SW_CONTEXT_ALIGN 1024
-
-#define NES_MAX_MTU 9000
-
-#define NES_NIC_MAX_NICS 16
-#define NES_MAX_ARP_TABLE_SIZE 4096
-
-#define NES_NIC_CEQ_SIZE 8
-/* NICs will be on a separate CQ */
-#define NES_CCEQ_SIZE ((nesadapter->max_cq / nesadapter->port_count) - 32)
-
-#define NES_MAX_PORT_COUNT 4
-
-#define MAX_DPC_ITERATIONS 128
-
-#define NES_DRV_OPT_ENABLE_MPA_VER_0 0x00000001
-#define NES_DRV_OPT_DISABLE_MPA_CRC 0x00000002
-#define NES_DRV_OPT_DISABLE_FIRST_WRITE 0x00000004
-#define NES_DRV_OPT_DISABLE_INTF 0x00000008
-#define NES_DRV_OPT_ENABLE_MSI 0x00000010
-#define NES_DRV_OPT_DUAL_LOGICAL_PORT 0x00000020
-#define NES_DRV_OPT_SUPRESS_OPTION_BC 0x00000040
-#define NES_DRV_OPT_NO_INLINE_DATA 0x00000080
-#define NES_DRV_OPT_DISABLE_INT_MOD 0x00000100
-#define NES_DRV_OPT_DISABLE_VIRT_WQ 0x00000200
-#define NES_DRV_OPT_ENABLE_PAU 0x00000400
-
-#define NES_AEQ_EVENT_TIMEOUT 2500
-#define NES_DISCONNECT_EVENT_TIMEOUT 2000
-
-/* debug levels */
-/* must match userspace */
-#define NES_DBG_HW 0x00000001
-#define NES_DBG_INIT 0x00000002
-#define NES_DBG_ISR 0x00000004
-#define NES_DBG_PHY 0x00000008
-#define NES_DBG_NETDEV 0x00000010
-#define NES_DBG_CM 0x00000020
-#define NES_DBG_CM1 0x00000040
-#define NES_DBG_NIC_RX 0x00000080
-#define NES_DBG_NIC_TX 0x00000100
-#define NES_DBG_CQP 0x00000200
-#define NES_DBG_MMAP 0x00000400
-#define NES_DBG_MR 0x00000800
-#define NES_DBG_PD 0x00001000
-#define NES_DBG_CQ 0x00002000
-#define NES_DBG_QP 0x00004000
-#define NES_DBG_MOD_QP 0x00008000
-#define NES_DBG_AEQ 0x00010000
-#define NES_DBG_IW_RX 0x00020000
-#define NES_DBG_IW_TX 0x00040000
-#define NES_DBG_SHUTDOWN 0x00080000
-#define NES_DBG_PAU 0x00100000
-#define NES_DBG_NLMSG 0x00200000
-#define NES_DBG_RSVD1 0x10000000
-#define NES_DBG_RSVD2 0x20000000
-#define NES_DBG_RSVD3 0x40000000
-#define NES_DBG_RSVD4 0x80000000
-#define NES_DBG_ALL 0xffffffff
-
-#ifdef CONFIG_INFINIBAND_NES_DEBUG
-#define nes_debug(level, fmt, args...) \
-do { \
- if (level & nes_debug_level) \
- printk(KERN_ERR PFX "%s[%u]: " fmt, __func__, __LINE__, ##args); \
-} while (0)
-
-#define NES_EVENT_TIMEOUT 1200000
-#else
-#define nes_debug(level, fmt, args...) no_printk(fmt, ##args)
-
-#define NES_EVENT_TIMEOUT 100000
-#endif
-
-#include "nes_hw.h"
-#include "nes_verbs.h"
-#include "nes_context.h"
-#include <rdma/nes-abi.h>
-#include "nes_cm.h"
-#include "nes_mgt.h"
-
-extern int interrupt_mod_interval;
-extern int nes_if_count;
-extern int mpa_version;
-extern int disable_mpa_crc;
-extern unsigned int nes_drv_opt;
-extern unsigned int nes_debug_level;
-extern unsigned int wqm_quanta;
-extern struct list_head nes_adapter_list;
-
-extern atomic_t cm_connects;
-extern atomic_t cm_accepts;
-extern atomic_t cm_disconnects;
-extern atomic_t cm_closes;
-extern atomic_t cm_connecteds;
-extern atomic_t cm_connect_reqs;
-extern atomic_t cm_rejects;
-extern atomic_t mod_qp_timouts;
-extern atomic_t qps_created;
-extern atomic_t qps_destroyed;
-extern atomic_t sw_qps_destroyed;
-extern u32 mh_detected;
-extern u32 mh_pauses_sent;
-extern u32 cm_packets_sent;
-extern u32 cm_packets_bounced;
-extern u32 cm_packets_created;
-extern u32 cm_packets_received;
-extern u32 cm_packets_dropped;
-extern u32 cm_packets_retrans;
-extern atomic_t cm_listens_created;
-extern atomic_t cm_listens_destroyed;
-extern u32 cm_backlog_drops;
-extern atomic_t cm_loopbacks;
-extern atomic_t cm_nodes_created;
-extern atomic_t cm_nodes_destroyed;
-extern atomic_t cm_accel_dropped_pkts;
-extern atomic_t cm_resets_recvd;
-extern atomic_t pau_qps_created;
-extern atomic_t pau_qps_destroyed;
-
-extern u32 int_mod_timer_init;
-extern u32 int_mod_cq_depth_256;
-extern u32 int_mod_cq_depth_128;
-extern u32 int_mod_cq_depth_32;
-extern u32 int_mod_cq_depth_24;
-extern u32 int_mod_cq_depth_16;
-extern u32 int_mod_cq_depth_4;
-extern u32 int_mod_cq_depth_1;
-
-struct nes_device {
- struct nes_adapter *nesadapter;
- void __iomem *regs;
- void __iomem *index_reg;
- struct pci_dev *pcidev;
- struct net_device *netdev[NES_NIC_MAX_NICS];
- u64 link_status_interrupts;
- struct tasklet_struct dpc_tasklet;
- spinlock_t indexed_regs_lock;
- unsigned long csr_start;
- unsigned long doorbell_region;
- unsigned long doorbell_start;
- unsigned long mac_tx_errors;
- unsigned long mac_pause_frames_sent;
- unsigned long mac_pause_frames_received;
- unsigned long mac_rx_errors;
- unsigned long mac_rx_crc_errors;
- unsigned long mac_rx_symbol_err_frames;
- unsigned long mac_rx_jabber_frames;
- unsigned long mac_rx_oversized_frames;
- unsigned long mac_rx_short_frames;
- unsigned long port_rx_discards;
- unsigned long port_tx_discards;
- unsigned int mac_index;
- unsigned int nes_stack_start;
-
- /* Control Structures */
- void *cqp_vbase;
- dma_addr_t cqp_pbase;
- u32 cqp_mem_size;
- u8 ceq_index;
- u8 nic_ceq_index;
- struct nes_hw_cqp cqp;
- struct nes_hw_cq ccq;
- struct list_head cqp_avail_reqs;
- struct list_head cqp_pending_reqs;
- struct nes_cqp_request *nes_cqp_requests;
-
- u32 int_req;
- u32 int_stat;
- u32 timer_int_req;
- u32 timer_only_int_count;
- u32 intf_int_req;
- u32 last_mac_tx_pauses;
- u32 last_used_chunks_tx;
- struct list_head list;
-
- u16 base_doorbell_index;
- u16 currcq_count;
- u16 deepcq_count;
- u8 iw_status;
- u8 msi_enabled;
- u8 netdev_count;
- u8 napi_isr_ran;
- u8 disable_rx_flow_control;
- u8 disable_tx_flow_control;
-
- struct delayed_work work;
- u8 link_recheck;
-};
-
-/* Receive skb private area - must fit in skb->cb area */
-struct nes_rskb_cb {
- u64 busaddr;
- u32 maplen;
- u32 seqnum;
- u8 *data_start;
- struct nes_qp *nesqp;
-};
-
-static inline __le32 get_crc_value(struct nes_v4_quad *nes_quad)
-{
- u32 crc_value;
- crc_value = crc32c(~0, (void *)nes_quad, sizeof (struct nes_v4_quad));
-
- /*
- * With commit ef19454b ("[LIB] crc32c: Keep intermediate crc
- * state in cpu order"), behavior of crc32c changes on
- * big-endian platforms. Our algorithm expects the previous
- * behavior; otherwise we have RDMA connection establishment
- * issue on big-endian.
- */
- return cpu_to_le32(crc_value);
-}
-
-static inline void
-set_wqe_64bit_value(__le32 *wqe_words, u32 index, u64 value)
-{
- wqe_words[index] = cpu_to_le32((u32) value);
- wqe_words[index + 1] = cpu_to_le32(upper_32_bits(value));
-}
-
-static inline void
-set_wqe_32bit_value(__le32 *wqe_words, u32 index, u32 value)
-{
- wqe_words[index] = cpu_to_le32(value);
-}
-
-static inline void
-nes_fill_init_cqp_wqe(struct nes_hw_cqp_wqe *cqp_wqe, struct nes_device *nesdev)
-{
- cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX] = 0;
- cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0;
- cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] = 0;
- cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] = 0;
- cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PBL_BLK_COUNT_IDX] = 0;
- cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PBL_LEN_IDX] = 0;
- cqp_wqe->wqe_words[NES_CQP_STAG_WQE_LEN_LOW_IDX] = 0;
- cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PA_LOW_IDX] = 0;
- cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PA_HIGH_IDX] = 0;
-}
-
-static inline void
-nes_fill_init_qp_wqe(struct nes_hw_qp_wqe *wqe, struct nes_qp *nesqp, u32 head)
-{
- u32 value;
- value = ((u32)((unsigned long) nesqp)) | head;
- set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_CTX_HIGH_IDX,
- (u32)(upper_32_bits((unsigned long)(nesqp))));
- set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX, value);
-}
-
-/* Read from memory-mapped device */
-static inline u32 nes_read_indexed(struct nes_device *nesdev, u32 reg_index)
-{
- unsigned long flags;
- void __iomem *addr = nesdev->index_reg;
- u32 value;
-
- spin_lock_irqsave(&nesdev->indexed_regs_lock, flags);
-
- writel(reg_index, addr);
- value = readl((void __iomem *)addr + 4);
-
- spin_unlock_irqrestore(&nesdev->indexed_regs_lock, flags);
- return value;
-}
-
-static inline u32 nes_read32(const void __iomem *addr)
-{
- return readl(addr);
-}
-
-static inline u16 nes_read16(const void __iomem *addr)
-{
- return readw(addr);
-}
-
-static inline u8 nes_read8(const void __iomem *addr)
-{
- return readb(addr);
-}
-
-/* Write to memory-mapped device */
-static inline void nes_write_indexed(struct nes_device *nesdev, u32 reg_index, u32 val)
-{
- unsigned long flags;
- void __iomem *addr = nesdev->index_reg;
-
- spin_lock_irqsave(&nesdev->indexed_regs_lock, flags);
-
- writel(reg_index, addr);
- writel(val, (void __iomem *)addr + 4);
-
- spin_unlock_irqrestore(&nesdev->indexed_regs_lock, flags);
-}
-
-static inline void nes_write32(void __iomem *addr, u32 val)
-{
- writel(val, addr);
-}
-
-static inline void nes_write16(void __iomem *addr, u16 val)
-{
- writew(val, addr);
-}
-
-static inline void nes_write8(void __iomem *addr, u8 val)
-{
- writeb(val, addr);
-}
-
-enum nes_resource {
- NES_RESOURCE_MW = 1,
- NES_RESOURCE_FAST_MR,
- NES_RESOURCE_PHYS_MR,
- NES_RESOURCE_USER_MR,
- NES_RESOURCE_PD,
- NES_RESOURCE_QP,
- NES_RESOURCE_CQ,
- NES_RESOURCE_ARP
-};
-
-static inline int nes_alloc_resource(struct nes_adapter *nesadapter,
- unsigned long *resource_array, u32 max_resources,
- u32 *req_resource_num, u32 *next, enum nes_resource resource_type)
-{
- unsigned long flags;
- u32 resource_num;
-
- spin_lock_irqsave(&nesadapter->resource_lock, flags);
-
- resource_num = find_next_zero_bit(resource_array, max_resources, *next);
- if (resource_num >= max_resources) {
- resource_num = find_first_zero_bit(resource_array, max_resources);
- if (resource_num >= max_resources) {
- printk(KERN_ERR PFX "%s: No available resources [type=%u].\n", __func__, resource_type);
- spin_unlock_irqrestore(&nesadapter->resource_lock, flags);
- return -EMFILE;
- }
- }
- set_bit(resource_num, resource_array);
- *next = resource_num+1;
- if (*next == max_resources) {
- *next = 0;
- }
- spin_unlock_irqrestore(&nesadapter->resource_lock, flags);
- *req_resource_num = resource_num;
-
- return 0;
-}
-
-static inline int nes_is_resource_allocated(struct nes_adapter *nesadapter,
- unsigned long *resource_array, u32 resource_num)
-{
- unsigned long flags;
- int bit_is_set;
-
- spin_lock_irqsave(&nesadapter->resource_lock, flags);
-
- bit_is_set = test_bit(resource_num, resource_array);
- nes_debug(NES_DBG_HW, "resource_num %u is%s allocated.\n",
- resource_num, (bit_is_set ? "": " not"));
- spin_unlock_irqrestore(&nesadapter->resource_lock, flags);
-
- return bit_is_set;
-}
-
-static inline void nes_free_resource(struct nes_adapter *nesadapter,
- unsigned long *resource_array, u32 resource_num)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&nesadapter->resource_lock, flags);
- clear_bit(resource_num, resource_array);
- spin_unlock_irqrestore(&nesadapter->resource_lock, flags);
-}
-
-static inline struct nes_vnic *to_nesvnic(struct ib_device *ibdev)
-{
- return container_of(ibdev, struct nes_ib_device, ibdev)->nesvnic;
-}
-
-static inline struct nes_pd *to_nespd(struct ib_pd *ibpd)
-{
- return container_of(ibpd, struct nes_pd, ibpd);
-}
-
-static inline struct nes_ucontext *to_nesucontext(struct ib_ucontext *ibucontext)
-{
- return container_of(ibucontext, struct nes_ucontext, ibucontext);
-}
-
-static inline struct nes_mr *to_nesmr(struct ib_mr *ibmr)
-{
- return container_of(ibmr, struct nes_mr, ibmr);
-}
-
-static inline struct nes_mr *to_nesmr_from_ibfmr(struct ib_fmr *ibfmr)
-{
- return container_of(ibfmr, struct nes_mr, ibfmr);
-}
-
-static inline struct nes_mr *to_nesmw(struct ib_mw *ibmw)
-{
- return container_of(ibmw, struct nes_mr, ibmw);
-}
-
-static inline struct nes_fmr *to_nesfmr(struct nes_mr *nesmr)
-{
- return container_of(nesmr, struct nes_fmr, nesmr);
-}
-
-static inline struct nes_cq *to_nescq(struct ib_cq *ibcq)
-{
- return container_of(ibcq, struct nes_cq, ibcq);
-}
-
-static inline struct nes_qp *to_nesqp(struct ib_qp *ibqp)
-{
- return container_of(ibqp, struct nes_qp, ibqp);
-}
-
-
-
-/* nes.c */
-void nes_add_ref(struct ib_qp *);
-void nes_rem_ref(struct ib_qp *);
-struct ib_qp *nes_get_qp(struct ib_device *, int);
-
-
-/* nes_hw.c */
-struct nes_adapter *nes_init_adapter(struct nes_device *, u8);
-void nes_nic_init_timer_defaults(struct nes_device *, u8);
-void nes_destroy_adapter(struct nes_adapter *);
-int nes_init_cqp(struct nes_device *);
-int nes_init_phy(struct nes_device *);
-int nes_init_nic_qp(struct nes_device *, struct net_device *);
-void nes_destroy_nic_qp(struct nes_vnic *);
-int nes_napi_isr(struct nes_device *);
-void nes_dpc(unsigned long);
-void nes_nic_ce_handler(struct nes_device *, struct nes_hw_nic_cq *);
-void nes_iwarp_ce_handler(struct nes_device *, struct nes_hw_cq *);
-int nes_destroy_cqp(struct nes_device *);
-int nes_nic_cm_xmit(struct sk_buff *, struct net_device *);
-void nes_recheck_link_status(struct work_struct *work);
-void nes_terminate_timeout(struct timer_list *t);
-
-/* nes_nic.c */
-struct net_device *nes_netdev_init(struct nes_device *, void __iomem *);
-void nes_netdev_destroy(struct net_device *);
-int nes_nic_cm_xmit(struct sk_buff *, struct net_device *);
-
-/* nes_cm.c */
-void *nes_cm_create(struct net_device *);
-int nes_cm_recv(struct sk_buff *, struct net_device *);
-void nes_update_arp(unsigned char *, u32, u32, u16, u16);
-void nes_manage_arp_cache(struct net_device *, unsigned char *, u32, u32);
-void nes_sock_release(struct nes_qp *, unsigned long *);
-void flush_wqes(struct nes_device *nesdev, struct nes_qp *, u32, u32);
-int nes_manage_apbvt(struct nes_vnic *, u32, u32, u32);
-int nes_cm_disconn(struct nes_qp *);
-void nes_cm_disconn_worker(void *);
-
-/* nes_verbs.c */
-int nes_hw_modify_qp(struct nes_device *, struct nes_qp *, u32, u32, u32);
-int nes_modify_qp(struct ib_qp *, struct ib_qp_attr *, int, struct ib_udata *);
-struct nes_ib_device *nes_init_ofa_device(struct net_device *);
-void nes_port_ibevent(struct nes_vnic *nesvnic);
-void nes_destroy_ofa_device(struct nes_ib_device *);
-int nes_register_ofa_device(struct nes_ib_device *);
-
-/* nes_util.c */
-int nes_read_eeprom_values(struct nes_device *, struct nes_adapter *);
-void nes_write_1G_phy_reg(struct nes_device *, u8, u8, u16);
-void nes_read_1G_phy_reg(struct nes_device *, u8, u8, u16 *);
-void nes_write_10G_phy_reg(struct nes_device *, u16, u8, u16, u16);
-void nes_read_10G_phy_reg(struct nes_device *, u8, u8, u16);
-struct nes_cqp_request *nes_get_cqp_request(struct nes_device *);
-void nes_free_cqp_request(struct nes_device *nesdev,
- struct nes_cqp_request *cqp_request);
-void nes_put_cqp_request(struct nes_device *nesdev,
- struct nes_cqp_request *cqp_request);
-void nes_post_cqp_request(struct nes_device *, struct nes_cqp_request *);
-int nes_arp_table(struct nes_device *, u32, u8 *, u32);
-void nes_mh_fix(struct timer_list *t);
-void nes_clc(struct timer_list *t);
-void nes_dump_mem(unsigned int, void *, int);
-u32 nes_crc32(u32, u32, u32, u32, u8 *, u32, u32, u32);
-
-#endif /* __NES_H */
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
deleted file mode 100644
index 62bf986eba67..000000000000
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ /dev/null
@@ -1,3992 +0,0 @@
-/*
- * Copyright (c) 2006 - 2014 Intel Corporation. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-
-#define TCPOPT_TIMESTAMP 8
-
-#include <linux/atomic.h>
-#include <linux/skbuff.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>
-#include <linux/init.h>
-#include <linux/if_arp.h>
-#include <linux/if_vlan.h>
-#include <linux/notifier.h>
-#include <linux/net.h>
-#include <linux/types.h>
-#include <linux/timer.h>
-#include <linux/time.h>
-#include <linux/delay.h>
-#include <linux/etherdevice.h>
-#include <linux/netdevice.h>
-#include <linux/random.h>
-#include <linux/list.h>
-#include <linux/threads.h>
-#include <linux/highmem.h>
-#include <linux/slab.h>
-#include <net/arp.h>
-#include <net/neighbour.h>
-#include <net/route.h>
-#include <net/ip_fib.h>
-#include <net/secure_seq.h>
-#include <net/tcp.h>
-#include <linux/fcntl.h>
-
-#include "nes.h"
-
-u32 cm_packets_sent;
-u32 cm_packets_bounced;
-u32 cm_packets_dropped;
-u32 cm_packets_retrans;
-u32 cm_packets_created;
-u32 cm_packets_received;
-atomic_t cm_listens_created;
-atomic_t cm_listens_destroyed;
-u32 cm_backlog_drops;
-atomic_t cm_loopbacks;
-atomic_t cm_nodes_created;
-atomic_t cm_nodes_destroyed;
-atomic_t cm_accel_dropped_pkts;
-atomic_t cm_resets_recvd;
-
-static inline int mini_cm_accelerated(struct nes_cm_core *, struct nes_cm_node *);
-static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *, struct nes_vnic *, struct nes_cm_info *);
-static int mini_cm_del_listen(struct nes_cm_core *, struct nes_cm_listener *);
-static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *, struct nes_vnic *, u16, void *, struct nes_cm_info *);
-static int mini_cm_close(struct nes_cm_core *, struct nes_cm_node *);
-static int mini_cm_accept(struct nes_cm_core *, struct nes_cm_node *);
-static int mini_cm_reject(struct nes_cm_core *, struct nes_cm_node *);
-static int mini_cm_recv_pkt(struct nes_cm_core *, struct nes_vnic *, struct sk_buff *);
-static int mini_cm_dealloc_core(struct nes_cm_core *);
-static int mini_cm_get(struct nes_cm_core *);
-static int mini_cm_set(struct nes_cm_core *, u32, u32);
-
-static void form_cm_frame(struct sk_buff *, struct nes_cm_node *, void *, u32, void *, u32, u8);
-static int add_ref_cm_node(struct nes_cm_node *);
-static int rem_ref_cm_node(struct nes_cm_core *, struct nes_cm_node *);
-
-static int nes_cm_disconn_true(struct nes_qp *);
-static int nes_cm_post_event(struct nes_cm_event *event);
-static int nes_disconnect(struct nes_qp *nesqp, int abrupt);
-static void nes_disconnect_worker(struct work_struct *work);
-
-static int send_mpa_request(struct nes_cm_node *, struct sk_buff *);
-static int send_mpa_reject(struct nes_cm_node *);
-static int send_syn(struct nes_cm_node *, u32, struct sk_buff *);
-static int send_reset(struct nes_cm_node *, struct sk_buff *);
-static int send_ack(struct nes_cm_node *cm_node, struct sk_buff *skb);
-static int send_fin(struct nes_cm_node *cm_node, struct sk_buff *skb);
-static void process_packet(struct nes_cm_node *, struct sk_buff *, struct nes_cm_core *);
-
-static void active_open_err(struct nes_cm_node *, struct sk_buff *, int);
-static void passive_open_err(struct nes_cm_node *, struct sk_buff *, int);
-static void cleanup_retrans_entry(struct nes_cm_node *);
-static void handle_rcv_mpa(struct nes_cm_node *, struct sk_buff *);
-static void free_retrans_entry(struct nes_cm_node *cm_node);
-static int handle_tcp_options(struct nes_cm_node *cm_node, struct tcphdr *tcph, struct sk_buff *skb, int optionsize, int passive);
-
-/* CM event handler functions */
-static void cm_event_connected(struct nes_cm_event *);
-static void cm_event_connect_error(struct nes_cm_event *);
-static void cm_event_reset(struct nes_cm_event *);
-static void cm_event_mpa_req(struct nes_cm_event *);
-static void cm_event_mpa_reject(struct nes_cm_event *);
-static void handle_recv_entry(struct nes_cm_node *cm_node, u32 rem_node);
-
-/* MPA build functions */
-static int cm_build_mpa_frame(struct nes_cm_node *, u8 **, u16 *, u8 *, u8);
-static void build_mpa_v2(struct nes_cm_node *, void *, u8);
-static void build_mpa_v1(struct nes_cm_node *, void *, u8);
-static void build_rdma0_msg(struct nes_cm_node *, struct nes_qp **);
-
-static void print_core(struct nes_cm_core *core);
-static void record_ird_ord(struct nes_cm_node *, u16, u16);
-
-/* External CM API Interface */
-/* instance of function pointers for client API */
-/* set address of this instance to cm_core->cm_ops at cm_core alloc */
-static const struct nes_cm_ops nes_cm_api = {
- .accelerated = mini_cm_accelerated,
- .listen = mini_cm_listen,
- .stop_listener = mini_cm_del_listen,
- .connect = mini_cm_connect,
- .close = mini_cm_close,
- .accept = mini_cm_accept,
- .reject = mini_cm_reject,
- .recv_pkt = mini_cm_recv_pkt,
- .destroy_cm_core = mini_cm_dealloc_core,
- .get = mini_cm_get,
- .set = mini_cm_set
-};
-
-static struct nes_cm_core *g_cm_core;
-
-atomic_t cm_connects;
-atomic_t cm_accepts;
-atomic_t cm_disconnects;
-atomic_t cm_closes;
-atomic_t cm_connecteds;
-atomic_t cm_connect_reqs;
-atomic_t cm_rejects;
-
-int nes_add_ref_cm_node(struct nes_cm_node *cm_node)
-{
- return add_ref_cm_node(cm_node);
-}
-
-int nes_rem_ref_cm_node(struct nes_cm_node *cm_node)
-{
- return rem_ref_cm_node(cm_node->cm_core, cm_node);
-}
-/**
- * create_event
- */
-static struct nes_cm_event *create_event(struct nes_cm_node * cm_node,
- enum nes_cm_event_type type)
-{
- struct nes_cm_event *event;
-
- if (!cm_node->cm_id)
- return NULL;
-
- /* allocate an empty event */
- event = kzalloc(sizeof(*event), GFP_ATOMIC);
-
- if (!event)
- return NULL;
-
- event->type = type;
- event->cm_node = cm_node;
- event->cm_info.rem_addr = cm_node->rem_addr;
- event->cm_info.loc_addr = cm_node->loc_addr;
- event->cm_info.rem_port = cm_node->rem_port;
- event->cm_info.loc_port = cm_node->loc_port;
- event->cm_info.cm_id = cm_node->cm_id;
-
- nes_debug(NES_DBG_CM, "cm_node=%p Created event=%p, type=%u, "
- "dst_addr=%08x[%x], src_addr=%08x[%x]\n",
- cm_node, event, type, event->cm_info.loc_addr,
- event->cm_info.loc_port, event->cm_info.rem_addr,
- event->cm_info.rem_port);
-
- nes_cm_post_event(event);
- return event;
-}
-
-
-/**
- * send_mpa_request
- */
-static int send_mpa_request(struct nes_cm_node *cm_node, struct sk_buff *skb)
-{
- u8 start_addr = 0;
- u8 *start_ptr = &start_addr;
- u8 **start_buff = &start_ptr;
- u16 buff_len = 0;
-
- if (!skb) {
- nes_debug(NES_DBG_CM, "skb set to NULL\n");
- return -1;
- }
-
- /* send an MPA Request frame */
- cm_build_mpa_frame(cm_node, start_buff, &buff_len, NULL, MPA_KEY_REQUEST);
- form_cm_frame(skb, cm_node, NULL, 0, *start_buff, buff_len, SET_ACK);
-
- return schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);
-}
-
-
-
-static int send_mpa_reject(struct nes_cm_node *cm_node)
-{
- struct sk_buff *skb = NULL;
- u8 start_addr = 0;
- u8 *start_ptr = &start_addr;
- u8 **start_buff = &start_ptr;
- u16 buff_len = 0;
- struct ietf_mpa_v1 *mpa_frame;
-
- skb = dev_alloc_skb(MAX_CM_BUFFER);
- if (!skb) {
- nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
- return -ENOMEM;
- }
-
- /* send an MPA reject frame */
- cm_build_mpa_frame(cm_node, start_buff, &buff_len, NULL, MPA_KEY_REPLY);
- mpa_frame = (struct ietf_mpa_v1 *)*start_buff;
- mpa_frame->flags |= IETF_MPA_FLAGS_REJECT;
- form_cm_frame(skb, cm_node, NULL, 0, *start_buff, buff_len, SET_ACK | SET_FIN);
-
- cm_node->state = NES_CM_STATE_FIN_WAIT1;
- return schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);
-}
-
-
-/**
- * recv_mpa - process a received TCP pkt, we are expecting an
- * IETF MPA frame
- */
-static int parse_mpa(struct nes_cm_node *cm_node, u8 *buffer, u32 *type,
- u32 len)
-{
- struct ietf_mpa_v1 *mpa_frame;
- struct ietf_mpa_v2 *mpa_v2_frame;
- struct ietf_rtr_msg *rtr_msg;
- int mpa_hdr_len;
- int priv_data_len;
-
- *type = NES_MPA_REQUEST_ACCEPT;
-
- /* assume req frame is in tcp data payload */
- if (len < sizeof(struct ietf_mpa_v1)) {
- nes_debug(NES_DBG_CM, "The received ietf buffer was too small (%x)\n", len);
- return -EINVAL;
- }
-
- /* points to the beginning of the frame, which could be MPA V1 or V2 */
- mpa_frame = (struct ietf_mpa_v1 *)buffer;
- mpa_hdr_len = sizeof(struct ietf_mpa_v1);
- priv_data_len = ntohs(mpa_frame->priv_data_len);
-
- /* make sure mpa private data len is less than 512 bytes */
- if (priv_data_len > IETF_MAX_PRIV_DATA_LEN) {
- nes_debug(NES_DBG_CM, "The received Length of Private"
- " Data field exceeds 512 octets\n");
- return -EINVAL;
- }
- /*
- * make sure MPA receiver interoperate with the
- * received MPA version and MPA key information
- *
- */
- if (mpa_frame->rev != IETF_MPA_V1 && mpa_frame->rev != IETF_MPA_V2) {
- nes_debug(NES_DBG_CM, "The received mpa version"
- " is not supported\n");
- return -EINVAL;
- }
- /*
- * backwards compatibility only
- */
- if (mpa_frame->rev > cm_node->mpa_frame_rev) {
- nes_debug(NES_DBG_CM, "The received mpa version"
- " can not be interoperated\n");
- return -EINVAL;
- } else {
- cm_node->mpa_frame_rev = mpa_frame->rev;
- }
-
- if (cm_node->state != NES_CM_STATE_MPAREQ_SENT) {
- if (memcmp(mpa_frame->key, IEFT_MPA_KEY_REQ, IETF_MPA_KEY_SIZE)) {
- nes_debug(NES_DBG_CM, "Unexpected MPA Key received \n");
- return -EINVAL;
- }
- } else {
- if (memcmp(mpa_frame->key, IEFT_MPA_KEY_REP, IETF_MPA_KEY_SIZE)) {
- nes_debug(NES_DBG_CM, "Unexpected MPA Key received \n");
- return -EINVAL;
- }
- }
-
- if (priv_data_len + mpa_hdr_len != len) {
- nes_debug(NES_DBG_CM, "The received ietf buffer was not right"
- " complete (%x + %x != %x)\n",
- priv_data_len, mpa_hdr_len, len);
- return -EINVAL;
- }
- /* make sure it does not exceed the max size */
- if (len > MAX_CM_BUFFER) {
- nes_debug(NES_DBG_CM, "The received ietf buffer was too large"
- " (%x + %x != %x)\n",
- priv_data_len, mpa_hdr_len, len);
- return -EINVAL;
- }
-
- cm_node->mpa_frame_size = priv_data_len;
-
- switch (mpa_frame->rev) {
- case IETF_MPA_V2: {
- u16 ird_size;
- u16 ord_size;
- u16 rtr_ctrl_ird;
- u16 rtr_ctrl_ord;
-
- mpa_v2_frame = (struct ietf_mpa_v2 *)buffer;
- mpa_hdr_len += IETF_RTR_MSG_SIZE;
- cm_node->mpa_frame_size -= IETF_RTR_MSG_SIZE;
- rtr_msg = &mpa_v2_frame->rtr_msg;
-
- /* parse rtr message */
- rtr_ctrl_ird = ntohs(rtr_msg->ctrl_ird);
- rtr_ctrl_ord = ntohs(rtr_msg->ctrl_ord);
- ird_size = rtr_ctrl_ird & IETF_NO_IRD_ORD;
- ord_size = rtr_ctrl_ord & IETF_NO_IRD_ORD;
-
- if (!(rtr_ctrl_ird & IETF_PEER_TO_PEER)) {
- /* send reset */
- return -EINVAL;
- }
- if (ird_size == IETF_NO_IRD_ORD || ord_size == IETF_NO_IRD_ORD)
- cm_node->mpav2_ird_ord = IETF_NO_IRD_ORD;
-
- if (cm_node->mpav2_ird_ord != IETF_NO_IRD_ORD) {
- /* responder */
- if (cm_node->state != NES_CM_STATE_MPAREQ_SENT) {
- /* we are still negotiating */
- if (ord_size > NES_MAX_IRD) {
- cm_node->ird_size = NES_MAX_IRD;
- } else {
- cm_node->ird_size = ord_size;
- if (ord_size == 0 &&
- (rtr_ctrl_ord & IETF_RDMA0_READ)) {
- cm_node->ird_size = 1;
- nes_debug(NES_DBG_CM,
- "%s: Remote peer doesn't support RDMA0_READ (ord=%u)\n",
- __func__, ord_size);
- }
- }
- if (ird_size > NES_MAX_ORD)
- cm_node->ord_size = NES_MAX_ORD;
- else
- cm_node->ord_size = ird_size;
- } else { /* initiator */
- if (ord_size > NES_MAX_IRD) {
- nes_debug(NES_DBG_CM,
- "%s: Unable to support the requested (ord =%u)\n",
- __func__, ord_size);
- return -EINVAL;
- }
- cm_node->ird_size = ord_size;
-
- if (ird_size > NES_MAX_ORD) {
- cm_node->ord_size = NES_MAX_ORD;
- } else {
- if (ird_size == 0 &&
- (rtr_ctrl_ord & IETF_RDMA0_READ)) {
- nes_debug(NES_DBG_CM,
- "%s: Remote peer doesn't support RDMA0_READ (ird=%u)\n",
- __func__, ird_size);
- return -EINVAL;
- } else {
- cm_node->ord_size = ird_size;
- }
- }
- }
- }
-
- if (rtr_ctrl_ord & IETF_RDMA0_READ) {
- cm_node->send_rdma0_op = SEND_RDMA_READ_ZERO;
-
- } else if (rtr_ctrl_ord & IETF_RDMA0_WRITE) {
- cm_node->send_rdma0_op = SEND_RDMA_WRITE_ZERO;
- } else { /* Not supported RDMA0 operation */
- return -EINVAL;
- }
- break;
- }
- case IETF_MPA_V1:
- default:
- break;
- }
-
- /* copy entire MPA frame to our cm_node's frame */
- memcpy(cm_node->mpa_frame_buf, buffer + mpa_hdr_len, cm_node->mpa_frame_size);
-
- if (mpa_frame->flags & IETF_MPA_FLAGS_REJECT)
- *type = NES_MPA_REQUEST_REJECT;
- return 0;
-}
-
-
-/**
- * form_cm_frame - get a free packet and build empty frame Use
- * node info to build.
- */
-static void form_cm_frame(struct sk_buff *skb,
- struct nes_cm_node *cm_node, void *options, u32 optionsize,
- void *data, u32 datasize, u8 flags)
-{
- struct tcphdr *tcph;
- struct iphdr *iph;
- struct ethhdr *ethh;
- u8 *buf;
- u16 packetsize = sizeof(*iph);
-
- packetsize += sizeof(*tcph);
- packetsize += optionsize + datasize;
-
- skb_trim(skb, 0);
- memset(skb->data, 0x00, ETH_HLEN + sizeof(*iph) + sizeof(*tcph));
-
- buf = skb_put(skb, packetsize + ETH_HLEN);
-
- ethh = (struct ethhdr *)buf;
- buf += ETH_HLEN;
-
- iph = (struct iphdr *)buf;
- buf += sizeof(*iph);
- tcph = (struct tcphdr *)buf;
- skb_reset_mac_header(skb);
- skb_set_network_header(skb, ETH_HLEN);
- skb_set_transport_header(skb, ETH_HLEN + sizeof(*iph));
- buf += sizeof(*tcph);
-
- skb->ip_summed = CHECKSUM_PARTIAL;
- if (!(cm_node->netdev->features & NETIF_F_IP_CSUM))
- skb->ip_summed = CHECKSUM_NONE;
- skb->protocol = htons(0x800);
- skb->data_len = 0;
- skb->mac_len = ETH_HLEN;
-
- memcpy(ethh->h_dest, cm_node->rem_mac, ETH_ALEN);
- memcpy(ethh->h_source, cm_node->loc_mac, ETH_ALEN);
- ethh->h_proto = htons(0x0800);
-
- iph->version = IPVERSION;
- iph->ihl = 5; /* 5 * 4Byte words, IP headr len */
- iph->tos = 0;
- iph->tot_len = htons(packetsize);
- iph->id = htons(++cm_node->tcp_cntxt.loc_id);
-
- iph->frag_off = htons(0x4000);
- iph->ttl = 0x40;
- iph->protocol = 0x06; /* IPPROTO_TCP */
-
- iph->saddr = htonl(cm_node->loc_addr);
- iph->daddr = htonl(cm_node->rem_addr);
-
- tcph->source = htons(cm_node->loc_port);
- tcph->dest = htons(cm_node->rem_port);
- tcph->seq = htonl(cm_node->tcp_cntxt.loc_seq_num);
-
- if (flags & SET_ACK) {
- cm_node->tcp_cntxt.loc_ack_num = cm_node->tcp_cntxt.rcv_nxt;
- tcph->ack_seq = htonl(cm_node->tcp_cntxt.loc_ack_num);
- tcph->ack = 1;
- } else {
- tcph->ack_seq = 0;
- }
-
- if (flags & SET_SYN) {
- cm_node->tcp_cntxt.loc_seq_num++;
- tcph->syn = 1;
- } else {
- cm_node->tcp_cntxt.loc_seq_num += datasize;
- }
-
- if (flags & SET_FIN) {
- cm_node->tcp_cntxt.loc_seq_num++;
- tcph->fin = 1;
- }
-
- if (flags & SET_RST)
- tcph->rst = 1;
-
- tcph->doff = (u16)((sizeof(*tcph) + optionsize + 3) >> 2);
- tcph->window = htons(cm_node->tcp_cntxt.rcv_wnd);
- tcph->urg_ptr = 0;
- if (optionsize)
- memcpy(buf, options, optionsize);
- buf += optionsize;
- if (datasize)
- memcpy(buf, data, datasize);
-
- skb_shinfo(skb)->nr_frags = 0;
- cm_packets_created++;
-}
-
-/**
- * print_core - dump a cm core
- */
-static void print_core(struct nes_cm_core *core)
-{
- nes_debug(NES_DBG_CM, "---------------------------------------------\n");
- nes_debug(NES_DBG_CM, "CM Core -- (core = %p )\n", core);
- if (!core)
- return;
- nes_debug(NES_DBG_CM, "---------------------------------------------\n");
-
- nes_debug(NES_DBG_CM, "State : %u \n", core->state);
-
- nes_debug(NES_DBG_CM, "Listen Nodes : %u \n", atomic_read(&core->listen_node_cnt));
- nes_debug(NES_DBG_CM, "Active Nodes : %u \n", atomic_read(&core->node_cnt));
-
- nes_debug(NES_DBG_CM, "core : %p \n", core);
-
- nes_debug(NES_DBG_CM, "-------------- end core ---------------\n");
-}
-
-static void record_ird_ord(struct nes_cm_node *cm_node,
- u16 conn_ird, u16 conn_ord)
-{
- if (conn_ird > NES_MAX_IRD)
- conn_ird = NES_MAX_IRD;
-
- if (conn_ord > NES_MAX_ORD)
- conn_ord = NES_MAX_ORD;
-
- cm_node->ird_size = conn_ird;
- cm_node->ord_size = conn_ord;
-}
-
-/**
- * cm_build_mpa_frame - build a MPA V1 frame or MPA V2 frame
- */
-static int cm_build_mpa_frame(struct nes_cm_node *cm_node, u8 **start_buff,
- u16 *buff_len, u8 *pci_mem, u8 mpa_key)
-{
- int ret = 0;
-
- *start_buff = (pci_mem) ? pci_mem : &cm_node->mpa_frame_buf[0];
-
- switch (cm_node->mpa_frame_rev) {
- case IETF_MPA_V1:
- *start_buff = (u8 *)*start_buff + sizeof(struct ietf_rtr_msg);
- *buff_len = sizeof(struct ietf_mpa_v1) + cm_node->mpa_frame_size;
- build_mpa_v1(cm_node, *start_buff, mpa_key);
- break;
- case IETF_MPA_V2:
- *buff_len = sizeof(struct ietf_mpa_v2) + cm_node->mpa_frame_size;
- build_mpa_v2(cm_node, *start_buff, mpa_key);
- break;
- default:
- ret = -EINVAL;
- }
- return ret;
-}
-
-/**
- * build_mpa_v2 - build a MPA V2 frame
- */
-static void build_mpa_v2(struct nes_cm_node *cm_node,
- void *start_addr, u8 mpa_key)
-{
- struct ietf_mpa_v2 *mpa_frame = (struct ietf_mpa_v2 *)start_addr;
- struct ietf_rtr_msg *rtr_msg = &mpa_frame->rtr_msg;
- u16 ctrl_ird;
- u16 ctrl_ord;
-
- /* initialize the upper 5 bytes of the frame */
- build_mpa_v1(cm_node, start_addr, mpa_key);
- mpa_frame->flags |= IETF_MPA_V2_FLAG; /* set a bit to indicate MPA V2 */
- mpa_frame->priv_data_len += htons(IETF_RTR_MSG_SIZE);
-
- /* initialize RTR msg */
- if (cm_node->mpav2_ird_ord == IETF_NO_IRD_ORD) {
- ctrl_ird = IETF_NO_IRD_ORD;
- ctrl_ord = IETF_NO_IRD_ORD;
- } else {
- ctrl_ird = cm_node->ird_size & IETF_NO_IRD_ORD;
- ctrl_ord = cm_node->ord_size & IETF_NO_IRD_ORD;
- }
- ctrl_ird |= IETF_PEER_TO_PEER;
-
- switch (mpa_key) {
- case MPA_KEY_REQUEST:
- ctrl_ord |= IETF_RDMA0_WRITE;
- ctrl_ord |= IETF_RDMA0_READ;
- break;
- case MPA_KEY_REPLY:
- switch (cm_node->send_rdma0_op) {
- case SEND_RDMA_WRITE_ZERO:
- ctrl_ord |= IETF_RDMA0_WRITE;
- break;
- case SEND_RDMA_READ_ZERO:
- ctrl_ord |= IETF_RDMA0_READ;
- break;
- }
- }
- rtr_msg->ctrl_ird = htons(ctrl_ird);
- rtr_msg->ctrl_ord = htons(ctrl_ord);
-}
-
-/**
- * build_mpa_v1 - build a MPA V1 frame
- */
-static void build_mpa_v1(struct nes_cm_node *cm_node, void *start_addr, u8 mpa_key)
-{
- struct ietf_mpa_v1 *mpa_frame = (struct ietf_mpa_v1 *)start_addr;
-
- switch (mpa_key) {
- case MPA_KEY_REQUEST:
- memcpy(mpa_frame->key, IEFT_MPA_KEY_REQ, IETF_MPA_KEY_SIZE);
- break;
- case MPA_KEY_REPLY:
- memcpy(mpa_frame->key, IEFT_MPA_KEY_REP, IETF_MPA_KEY_SIZE);
- break;
- }
- mpa_frame->flags = IETF_MPA_FLAGS_CRC;
- mpa_frame->rev = cm_node->mpa_frame_rev;
- mpa_frame->priv_data_len = htons(cm_node->mpa_frame_size);
-}
-
-static void build_rdma0_msg(struct nes_cm_node *cm_node, struct nes_qp **nesqp_addr)
-{
- u64 u64temp;
- struct nes_qp *nesqp = *nesqp_addr;
- struct nes_hw_qp_wqe *wqe = &nesqp->hwqp.sq_vbase[0];
-
- u64temp = (unsigned long)nesqp->nesuqp_addr;
- u64temp |= NES_SW_CONTEXT_ALIGN >> 1;
- set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX, u64temp);
-
- wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_LOW_IDX] = 0;
- wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX] = 0;
-
- switch (cm_node->send_rdma0_op) {
- case SEND_RDMA_WRITE_ZERO:
- nes_debug(NES_DBG_CM, "Sending first write.\n");
- wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] =
- cpu_to_le32(NES_IWARP_SQ_OP_RDMAW);
- wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] = 0;
- wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX] = 0;
- wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = 0;
- break;
-
- case SEND_RDMA_READ_ZERO:
- default:
- if (cm_node->send_rdma0_op != SEND_RDMA_READ_ZERO)
- WARN(1, "Unsupported RDMA0 len operation=%u\n",
- cm_node->send_rdma0_op);
- nes_debug(NES_DBG_CM, "Sending first rdma operation.\n");
- wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] =
- cpu_to_le32(NES_IWARP_SQ_OP_RDMAR);
- wqe->wqe_words[NES_IWARP_SQ_WQE_RDMA_TO_LOW_IDX] = 1;
- wqe->wqe_words[NES_IWARP_SQ_WQE_RDMA_TO_HIGH_IDX] = 0;
- wqe->wqe_words[NES_IWARP_SQ_WQE_RDMA_LENGTH_IDX] = 0;
- wqe->wqe_words[NES_IWARP_SQ_WQE_RDMA_STAG_IDX] = 1;
- wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = 1;
- break;
- }
-
- if (nesqp->sq_kmapped) {
- nesqp->sq_kmapped = 0;
- kunmap(nesqp->page);
- }
-
- /*use the reserved spot on the WQ for the extra first WQE*/
- nesqp->nesqp_context->ird_ord_sizes &= cpu_to_le32(~(NES_QPCONTEXT_ORDIRD_LSMM_PRESENT |
- NES_QPCONTEXT_ORDIRD_WRPDU |
- NES_QPCONTEXT_ORDIRD_ALSMM));
- nesqp->skip_lsmm = 1;
- nesqp->hwqp.sq_tail = 0;
-}
-
-/**
- * schedule_nes_timer
- * note - cm_node needs to be protected before calling this. Encase in:
- * rem_ref_cm_node(cm_core, cm_node);add_ref_cm_node(cm_node);
- */
-int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb,
- enum nes_timer_type type, int send_retrans,
- int close_when_complete)
-{
- unsigned long flags;
- struct nes_cm_core *cm_core = cm_node->cm_core;
- struct nes_timer_entry *new_send;
- int ret = 0;
-
- new_send = kzalloc(sizeof(*new_send), GFP_ATOMIC);
- if (!new_send)
- return -ENOMEM;
-
- /* new_send->timetosend = currenttime */
- new_send->retrycount = NES_DEFAULT_RETRYS;
- new_send->retranscount = NES_DEFAULT_RETRANS;
- new_send->skb = skb;
- new_send->timetosend = jiffies;
- new_send->type = type;
- new_send->netdev = cm_node->netdev;
- new_send->send_retrans = send_retrans;
- new_send->close_when_complete = close_when_complete;
-
- if (type == NES_TIMER_TYPE_CLOSE) {
- new_send->timetosend += (HZ / 10);
- if (cm_node->recv_entry) {
- kfree(new_send);
- WARN_ON(1);
- return -EINVAL;
- }
- cm_node->recv_entry = new_send;
- }
-
- if (type == NES_TIMER_TYPE_SEND) {
- new_send->seq_num = ntohl(tcp_hdr(skb)->seq);
- refcount_inc(&new_send->skb->users);
- spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
- cm_node->send_entry = new_send;
- add_ref_cm_node(cm_node);
- spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
- new_send->timetosend = jiffies + NES_RETRY_TIMEOUT;
-
- ret = nes_nic_cm_xmit(new_send->skb, cm_node->netdev);
- if (ret != NETDEV_TX_OK) {
- nes_debug(NES_DBG_CM, "Error sending packet %p "
- "(jiffies = %lu)\n", new_send, jiffies);
- new_send->timetosend = jiffies;
- ret = NETDEV_TX_OK;
- } else {
- cm_packets_sent++;
- if (!send_retrans) {
- cleanup_retrans_entry(cm_node);
- if (close_when_complete)
- rem_ref_cm_node(cm_core, cm_node);
- return ret;
- }
- }
- }
-
- if (!timer_pending(&cm_core->tcp_timer))
- mod_timer(&cm_core->tcp_timer, new_send->timetosend);
-
- return ret;
-}
-
-static void nes_retrans_expired(struct nes_cm_node *cm_node)
-{
- struct iw_cm_id *cm_id = cm_node->cm_id;
- enum nes_cm_node_state state = cm_node->state;
- cm_node->state = NES_CM_STATE_CLOSED;
-
- switch (state) {
- case NES_CM_STATE_SYN_RCVD:
- case NES_CM_STATE_CLOSING:
- rem_ref_cm_node(cm_node->cm_core, cm_node);
- break;
- case NES_CM_STATE_LAST_ACK:
- case NES_CM_STATE_FIN_WAIT1:
- if (cm_node->cm_id)
- cm_id->rem_ref(cm_id);
- send_reset(cm_node, NULL);
- break;
- default:
- add_ref_cm_node(cm_node);
- send_reset(cm_node, NULL);
- create_event(cm_node, NES_CM_EVENT_ABORTED);
- }
-}
-
-static void handle_recv_entry(struct nes_cm_node *cm_node, u32 rem_node)
-{
- struct nes_timer_entry *recv_entry = cm_node->recv_entry;
- struct iw_cm_id *cm_id = cm_node->cm_id;
- struct nes_qp *nesqp;
- unsigned long qplockflags;
-
- if (!recv_entry)
- return;
- nesqp = (struct nes_qp *)recv_entry->skb;
- if (nesqp) {
- spin_lock_irqsave(&nesqp->lock, qplockflags);
- if (nesqp->cm_id) {
- nes_debug(NES_DBG_CM, "QP%u: cm_id = %p, "
- "refcount = %d: HIT A "
- "NES_TIMER_TYPE_CLOSE with something "
- "to do!!!\n", nesqp->hwqp.qp_id, cm_id,
- atomic_read(&nesqp->refcount));
- nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
- nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT;
- nesqp->ibqp_state = IB_QPS_ERR;
- spin_unlock_irqrestore(&nesqp->lock, qplockflags);
- nes_cm_disconn(nesqp);
- } else {
- spin_unlock_irqrestore(&nesqp->lock, qplockflags);
- nes_debug(NES_DBG_CM, "QP%u: cm_id = %p, "
- "refcount = %d: HIT A "
- "NES_TIMER_TYPE_CLOSE with nothing "
- "to do!!!\n", nesqp->hwqp.qp_id, cm_id,
- atomic_read(&nesqp->refcount));
- }
- } else if (rem_node) {
- /* TIME_WAIT state */
- rem_ref_cm_node(cm_node->cm_core, cm_node);
- }
- if (cm_node->cm_id)
- cm_id->rem_ref(cm_id);
- kfree(recv_entry);
- cm_node->recv_entry = NULL;
-}
-
-/**
- * nes_cm_timer_tick
- */
-static void nes_cm_timer_tick(struct timer_list *unused)
-{
- unsigned long flags;
- unsigned long nexttimeout = jiffies + NES_LONG_TIME;
- struct nes_cm_node *cm_node;
- struct nes_timer_entry *send_entry, *recv_entry;
- struct list_head *list_core_temp;
- struct list_head *list_node;
- struct nes_cm_core *cm_core = g_cm_core;
- u32 settimer = 0;
- unsigned long timetosend;
- int ret = NETDEV_TX_OK;
-
- struct list_head timer_list;
-
- INIT_LIST_HEAD(&timer_list);
- spin_lock_irqsave(&cm_core->ht_lock, flags);
-
- list_for_each_safe(list_node, list_core_temp,
- &cm_core->connected_nodes) {
- cm_node = container_of(list_node, struct nes_cm_node, list);
- if ((cm_node->recv_entry) || (cm_node->send_entry)) {
- add_ref_cm_node(cm_node);
- list_add(&cm_node->timer_entry, &timer_list);
- }
- }
- spin_unlock_irqrestore(&cm_core->ht_lock, flags);
-
- list_for_each_safe(list_node, list_core_temp, &timer_list) {
- cm_node = container_of(list_node, struct nes_cm_node,
- timer_entry);
- recv_entry = cm_node->recv_entry;
-
- if (recv_entry) {
- if (time_after(recv_entry->timetosend, jiffies)) {
- if (nexttimeout > recv_entry->timetosend ||
- !settimer) {
- nexttimeout = recv_entry->timetosend;
- settimer = 1;
- }
- } else {
- handle_recv_entry(cm_node, 1);
- }
- }
-
- spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
- do {
- send_entry = cm_node->send_entry;
- if (!send_entry)
- break;
- if (time_after(send_entry->timetosend, jiffies)) {
- if (cm_node->state != NES_CM_STATE_TSA) {
- if ((nexttimeout >
- send_entry->timetosend) ||
- !settimer) {
- nexttimeout =
- send_entry->timetosend;
- settimer = 1;
- }
- } else {
- free_retrans_entry(cm_node);
- }
- break;
- }
-
- if ((cm_node->state == NES_CM_STATE_TSA) ||
- (cm_node->state == NES_CM_STATE_CLOSED)) {
- free_retrans_entry(cm_node);
- break;
- }
-
- if (!send_entry->retranscount ||
- !send_entry->retrycount) {
- cm_packets_dropped++;
- free_retrans_entry(cm_node);
-
- spin_unlock_irqrestore(
- &cm_node->retrans_list_lock, flags);
- nes_retrans_expired(cm_node);
- cm_node->state = NES_CM_STATE_CLOSED;
- spin_lock_irqsave(&cm_node->retrans_list_lock,
- flags);
- break;
- }
- refcount_inc(&send_entry->skb->users);
- cm_packets_retrans++;
- nes_debug(NES_DBG_CM, "Retransmitting send_entry %p "
- "for node %p, jiffies = %lu, time to send = "
- "%lu, retranscount = %u, send_entry->seq_num = "
- "0x%08X, cm_node->tcp_cntxt.rem_ack_num = "
- "0x%08X\n", send_entry, cm_node, jiffies,
- send_entry->timetosend,
- send_entry->retranscount,
- send_entry->seq_num,
- cm_node->tcp_cntxt.rem_ack_num);
-
- spin_unlock_irqrestore(&cm_node->retrans_list_lock,
- flags);
- ret = nes_nic_cm_xmit(send_entry->skb, cm_node->netdev);
- spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
- if (ret != NETDEV_TX_OK) {
- nes_debug(NES_DBG_CM, "rexmit failed for "
- "node=%p\n", cm_node);
- cm_packets_bounced++;
- send_entry->retrycount--;
- nexttimeout = jiffies + NES_SHORT_TIME;
- settimer = 1;
- break;
- } else {
- cm_packets_sent++;
- }
- nes_debug(NES_DBG_CM, "Packet Sent: retrans count = "
- "%u, retry count = %u.\n",
- send_entry->retranscount,
- send_entry->retrycount);
- if (send_entry->send_retrans) {
- send_entry->retranscount--;
- timetosend = (NES_RETRY_TIMEOUT <<
- (NES_DEFAULT_RETRANS - send_entry->retranscount));
-
- send_entry->timetosend = jiffies +
- min(timetosend, NES_MAX_TIMEOUT);
- if (nexttimeout > send_entry->timetosend ||
- !settimer) {
- nexttimeout = send_entry->timetosend;
- settimer = 1;
- }
- } else {
- int close_when_complete;
- close_when_complete =
- send_entry->close_when_complete;
- nes_debug(NES_DBG_CM, "cm_node=%p state=%d\n",
- cm_node, cm_node->state);
- free_retrans_entry(cm_node);
- if (close_when_complete)
- rem_ref_cm_node(cm_node->cm_core,
- cm_node);
- }
- } while (0);
-
- spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
- rem_ref_cm_node(cm_node->cm_core, cm_node);
- }
-
- if (settimer) {
- if (!timer_pending(&cm_core->tcp_timer))
- mod_timer(&cm_core->tcp_timer, nexttimeout);
- }
-}
-
-
-/**
- * send_syn
- */
-static int send_syn(struct nes_cm_node *cm_node, u32 sendack,
- struct sk_buff *skb)
-{
- int ret;
- int flags = SET_SYN;
- char optionsbuffer[sizeof(struct option_mss) +
- sizeof(struct option_windowscale) + sizeof(struct option_base) +
- TCP_OPTIONS_PADDING];
-
- int optionssize = 0;
- /* Sending MSS option */
- union all_known_options *options;
-
- if (!cm_node)
- return -EINVAL;
-
- options = (union all_known_options *)&optionsbuffer[optionssize];
- options->as_mss.optionnum = OPTION_NUMBER_MSS;
- options->as_mss.length = sizeof(struct option_mss);
- options->as_mss.mss = htons(cm_node->tcp_cntxt.mss);
- optionssize += sizeof(struct option_mss);
-
- options = (union all_known_options *)&optionsbuffer[optionssize];
- options->as_windowscale.optionnum = OPTION_NUMBER_WINDOW_SCALE;
- options->as_windowscale.length = sizeof(struct option_windowscale);
- options->as_windowscale.shiftcount = cm_node->tcp_cntxt.rcv_wscale;
- optionssize += sizeof(struct option_windowscale);
-
- if (sendack && !(NES_DRV_OPT_SUPRESS_OPTION_BC & nes_drv_opt)) {
- options = (union all_known_options *)&optionsbuffer[optionssize];
- options->as_base.optionnum = OPTION_NUMBER_WRITE0;
- options->as_base.length = sizeof(struct option_base);
- optionssize += sizeof(struct option_base);
- /* we need the size to be a multiple of 4 */
- options = (union all_known_options *)&optionsbuffer[optionssize];
- options->as_end = 1;
- optionssize += 1;
- options = (union all_known_options *)&optionsbuffer[optionssize];
- options->as_end = 1;
- optionssize += 1;
- }
-
- options = (union all_known_options *)&optionsbuffer[optionssize];
- options->as_end = OPTION_NUMBER_END;
- optionssize += 1;
-
- if (!skb)
- skb = dev_alloc_skb(MAX_CM_BUFFER);
- if (!skb) {
- nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
- return -1;
- }
-
- if (sendack)
- flags |= SET_ACK;
-
- form_cm_frame(skb, cm_node, optionsbuffer, optionssize, NULL, 0, flags);
- ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);
-
- return ret;
-}
-
-
-/**
- * send_reset
- */
-static int send_reset(struct nes_cm_node *cm_node, struct sk_buff *skb)
-{
- int ret;
- int flags = SET_RST | SET_ACK;
-
- if (!skb)
- skb = dev_alloc_skb(MAX_CM_BUFFER);
- if (!skb) {
- nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
- return -ENOMEM;
- }
-
- form_cm_frame(skb, cm_node, NULL, 0, NULL, 0, flags);
- ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 0, 1);
-
- return ret;
-}
-
-
-/**
- * send_ack
- */
-static int send_ack(struct nes_cm_node *cm_node, struct sk_buff *skb)
-{
- int ret;
-
- if (!skb)
- skb = dev_alloc_skb(MAX_CM_BUFFER);
-
- if (!skb) {
- nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
- return -1;
- }
-
- form_cm_frame(skb, cm_node, NULL, 0, NULL, 0, SET_ACK);
- ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 0, 0);
-
- return ret;
-}
-
-
-/**
- * send_fin
- */
-static int send_fin(struct nes_cm_node *cm_node, struct sk_buff *skb)
-{
- int ret;
-
- /* if we didn't get a frame get one */
- if (!skb)
- skb = dev_alloc_skb(MAX_CM_BUFFER);
-
- if (!skb) {
- nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
- return -1;
- }
-
- form_cm_frame(skb, cm_node, NULL, 0, NULL, 0, SET_ACK | SET_FIN);
- ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);
-
- return ret;
-}
-
-
-/**
- * find_node - find a cm node that matches the reference cm node
- */
-static struct nes_cm_node *find_node(struct nes_cm_core *cm_core,
- u16 rem_port, nes_addr_t rem_addr, u16 loc_port, nes_addr_t loc_addr)
-{
- unsigned long flags;
- struct list_head *hte;
- struct nes_cm_node *cm_node;
-
- /* get a handle on the hte */
- hte = &cm_core->connected_nodes;
-
- /* walk list and find cm_node associated with this session ID */
- spin_lock_irqsave(&cm_core->ht_lock, flags);
- list_for_each_entry(cm_node, hte, list) {
- /* compare quad, return node handle if a match */
- nes_debug(NES_DBG_CM, "finding node %x:%x =? %x:%x ^ %x:%x =? %x:%x\n",
- cm_node->loc_addr, cm_node->loc_port,
- loc_addr, loc_port,
- cm_node->rem_addr, cm_node->rem_port,
- rem_addr, rem_port);
- if ((cm_node->loc_addr == loc_addr) &&
- (cm_node->loc_port == loc_port) &&
- (cm_node->rem_addr == rem_addr) &&
- (cm_node->rem_port == rem_port)) {
- add_ref_cm_node(cm_node);
- spin_unlock_irqrestore(&cm_core->ht_lock, flags);
- return cm_node;
- }
- }
- spin_unlock_irqrestore(&cm_core->ht_lock, flags);
-
- /* no owner node */
- return NULL;
-}
-
-
-/**
- * find_listener - find a cm node listening on this addr-port pair
- */
-static struct nes_cm_listener *find_listener(struct nes_cm_core *cm_core,
- nes_addr_t dst_addr, u16 dst_port,
- enum nes_cm_listener_state listener_state)
-{
- unsigned long flags;
- struct nes_cm_listener *listen_node;
- nes_addr_t listen_addr;
- u16 listen_port;
-
- /* walk list and find cm_node associated with this session ID */
- spin_lock_irqsave(&cm_core->listen_list_lock, flags);
- list_for_each_entry(listen_node, &cm_core->listen_list.list, list) {
- listen_addr = listen_node->loc_addr;
- listen_port = listen_node->loc_port;
-
- /* compare node pair, return node handle if a match */
- if (((listen_addr == dst_addr) ||
- listen_addr == 0x00000000) &&
- (listen_port == dst_port) &&
- (listener_state & listen_node->listener_state)) {
- atomic_inc(&listen_node->ref_count);
- spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
- return listen_node;
- }
- }
- spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
-
- /* no listener */
- return NULL;
-}
-
-/**
- * add_hte_node - add a cm node to the hash table
- */
-static int add_hte_node(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node)
-{
- unsigned long flags;
- struct list_head *hte;
-
- if (!cm_node || !cm_core)
- return -EINVAL;
-
- nes_debug(NES_DBG_CM, "Adding Node %p to Active Connection HT\n",
- cm_node);
-
- spin_lock_irqsave(&cm_core->ht_lock, flags);
-
- /* get a handle on the hash table element (list head for this slot) */
- hte = &cm_core->connected_nodes;
- list_add_tail(&cm_node->list, hte);
- atomic_inc(&cm_core->ht_node_cnt);
-
- spin_unlock_irqrestore(&cm_core->ht_lock, flags);
-
- return 0;
-}
-
-
-/**
- * mini_cm_dec_refcnt_listen
- */
-static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,
- struct nes_cm_listener *listener, int free_hanging_nodes)
-{
- int ret = -EINVAL;
- int err = 0;
- unsigned long flags;
- struct list_head *list_pos = NULL;
- struct list_head *list_temp = NULL;
- struct nes_cm_node *cm_node = NULL;
- struct list_head reset_list;
-
- nes_debug(NES_DBG_CM, "attempting listener= %p free_nodes= %d, "
- "refcnt=%d\n", listener, free_hanging_nodes,
- atomic_read(&listener->ref_count));
- /* free non-accelerated child nodes for this listener */
- INIT_LIST_HEAD(&reset_list);
- if (free_hanging_nodes) {
- spin_lock_irqsave(&cm_core->ht_lock, flags);
- list_for_each_safe(list_pos, list_temp,
- &g_cm_core->connected_nodes) {
- cm_node = container_of(list_pos, struct nes_cm_node,
- list);
- if ((cm_node->listener == listener) &&
- (!cm_node->accelerated)) {
- add_ref_cm_node(cm_node);
- list_add(&cm_node->reset_entry, &reset_list);
- }
- }
- spin_unlock_irqrestore(&cm_core->ht_lock, flags);
- }
-
- list_for_each_safe(list_pos, list_temp, &reset_list) {
- cm_node = container_of(list_pos, struct nes_cm_node,
- reset_entry);
- {
- struct nes_cm_node *loopback = cm_node->loopbackpartner;
- enum nes_cm_node_state old_state;
- if (NES_CM_STATE_FIN_WAIT1 <= cm_node->state) {
- rem_ref_cm_node(cm_node->cm_core, cm_node);
- } else {
- if (!loopback) {
- cleanup_retrans_entry(cm_node);
- err = send_reset(cm_node, NULL);
- if (err) {
- cm_node->state =
- NES_CM_STATE_CLOSED;
- WARN_ON(1);
- } else {
- old_state = cm_node->state;
- cm_node->state = NES_CM_STATE_LISTENER_DESTROYED;
- if (old_state != NES_CM_STATE_MPAREQ_RCVD)
- rem_ref_cm_node(
- cm_node->cm_core,
- cm_node);
- }
- } else {
- struct nes_cm_event event;
-
- event.cm_node = loopback;
- event.cm_info.rem_addr =
- loopback->rem_addr;
- event.cm_info.loc_addr =
- loopback->loc_addr;
- event.cm_info.rem_port =
- loopback->rem_port;
- event.cm_info.loc_port =
- loopback->loc_port;
- event.cm_info.cm_id = loopback->cm_id;
- add_ref_cm_node(loopback);
- loopback->state = NES_CM_STATE_CLOSED;
- cm_event_connect_error(&event);
- cm_node->state = NES_CM_STATE_LISTENER_DESTROYED;
-
- rem_ref_cm_node(cm_node->cm_core,
- cm_node);
-
- }
- }
- }
- }
-
- spin_lock_irqsave(&cm_core->listen_list_lock, flags);
- if (!atomic_dec_return(&listener->ref_count)) {
- list_del(&listener->list);
-
- /* decrement our listen node count */
- atomic_dec(&cm_core->listen_node_cnt);
-
- spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
-
- if (listener->nesvnic) {
- nes_manage_apbvt(listener->nesvnic,
- listener->loc_port,
- PCI_FUNC(listener->nesvnic->nesdev->pcidev->devfn),
- NES_MANAGE_APBVT_DEL);
-
- nes_debug(NES_DBG_NLMSG,
- "Delete APBVT loc_port = %04X\n",
- listener->loc_port);
- }
-
- nes_debug(NES_DBG_CM, "destroying listener (%p)\n", listener);
-
- kfree(listener);
- listener = NULL;
- ret = 0;
- atomic_inc(&cm_listens_destroyed);
- } else {
- spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
- }
- if (listener) {
- if (atomic_read(&listener->pend_accepts_cnt) > 0)
- nes_debug(NES_DBG_CM, "destroying listener (%p)"
- " with non-zero pending accepts=%u\n",
- listener, atomic_read(&listener->pend_accepts_cnt));
- }
-
- return ret;
-}
-
-
-/**
- * mini_cm_del_listen
- */
-static int mini_cm_del_listen(struct nes_cm_core *cm_core,
- struct nes_cm_listener *listener)
-{
- listener->listener_state = NES_CM_LISTENER_PASSIVE_STATE;
- listener->cm_id = NULL; /* going to be destroyed pretty soon */
- return mini_cm_dec_refcnt_listen(cm_core, listener, 1);
-}
-
-
-/**
- * mini_cm_accelerated
- */
-static inline int mini_cm_accelerated(struct nes_cm_core *cm_core,
- struct nes_cm_node *cm_node)
-{
- cm_node->accelerated = true;
-
- if (cm_node->accept_pend) {
- BUG_ON(!cm_node->listener);
- atomic_dec(&cm_node->listener->pend_accepts_cnt);
- cm_node->accept_pend = 0;
- BUG_ON(atomic_read(&cm_node->listener->pend_accepts_cnt) < 0);
- }
-
- if (!timer_pending(&cm_core->tcp_timer))
- mod_timer(&cm_core->tcp_timer, (jiffies + NES_SHORT_TIME));
-
- return 0;
-}
-
-
-/**
- * nes_addr_resolve_neigh
- */
-static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpindex)
-{
- struct rtable *rt;
- struct neighbour *neigh;
- int rc = arpindex;
- struct nes_adapter *nesadapter = nesvnic->nesdev->nesadapter;
- __be32 dst_ipaddr = htonl(dst_ip);
-
- rt = ip_route_output(&init_net, dst_ipaddr, nesvnic->local_ipaddr, 0, 0);
- if (IS_ERR(rt)) {
- printk(KERN_ERR "%s: ip_route_output_key failed for 0x%08X\n",
- __func__, dst_ip);
- return rc;
- }
-
- neigh = dst_neigh_lookup(&rt->dst, &dst_ipaddr);
-
- rcu_read_lock();
- if (neigh) {
- if (neigh->nud_state & NUD_VALID) {
- nes_debug(NES_DBG_CM, "Neighbor MAC address for 0x%08X"
- " is %pM, Gateway is 0x%08X \n", dst_ip,
- neigh->ha, ntohl(rt->rt_gw4));
-
- if (arpindex >= 0) {
- if (ether_addr_equal(nesadapter->arp_table[arpindex].mac_addr, neigh->ha)) {
- /* Mac address same as in nes_arp_table */
- goto out;
- }
-
- nes_manage_arp_cache(nesvnic->netdev,
- nesadapter->arp_table[arpindex].mac_addr,
- dst_ip, NES_ARP_DELETE);
- }
-
- nes_manage_arp_cache(nesvnic->netdev, neigh->ha,
- dst_ip, NES_ARP_ADD);
- rc = nes_arp_table(nesvnic->nesdev, dst_ip, NULL,
- NES_ARP_RESOLVE);
- } else {
- neigh_event_send(neigh, NULL);
- }
- }
-out:
- rcu_read_unlock();
-
- if (neigh)
- neigh_release(neigh);
-
- ip_rt_put(rt);
- return rc;
-}
-
-/**
- * make_cm_node - create a new instance of a cm node
- */
-static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,
- struct nes_vnic *nesvnic, struct nes_cm_info *cm_info,
- struct nes_cm_listener *listener)
-{
- struct nes_cm_node *cm_node;
- int oldarpindex = 0;
- int arpindex = 0;
- struct nes_device *nesdev;
- struct nes_adapter *nesadapter;
-
- /* create an hte and cm_node for this instance */
- cm_node = kzalloc(sizeof(*cm_node), GFP_ATOMIC);
- if (!cm_node)
- return NULL;
-
- /* set our node specific transport info */
- if (listener) {
- cm_node->loc_addr = listener->loc_addr;
- cm_node->loc_port = listener->loc_port;
- } else {
- cm_node->loc_addr = cm_info->loc_addr;
- cm_node->loc_port = cm_info->loc_port;
- }
- cm_node->rem_addr = cm_info->rem_addr;
- cm_node->rem_port = cm_info->rem_port;
-
- cm_node->mpa_frame_rev = mpa_version;
- cm_node->send_rdma0_op = SEND_RDMA_READ_ZERO;
- cm_node->mpav2_ird_ord = 0;
- cm_node->ird_size = 0;
- cm_node->ord_size = 0;
-
- nes_debug(NES_DBG_CM, "Make node addresses : loc = %pI4:%x, rem = %pI4:%x\n",
- &cm_node->loc_addr, cm_node->loc_port,
- &cm_node->rem_addr, cm_node->rem_port);
- cm_node->listener = listener;
- if (listener)
- cm_node->tos = listener->tos;
- cm_node->netdev = nesvnic->netdev;
- cm_node->cm_id = cm_info->cm_id;
- memcpy(cm_node->loc_mac, nesvnic->netdev->dev_addr, ETH_ALEN);
-
- nes_debug(NES_DBG_CM, "listener=%p, cm_id=%p\n", cm_node->listener,
- cm_node->cm_id);
-
- spin_lock_init(&cm_node->retrans_list_lock);
-
- cm_node->loopbackpartner = NULL;
- atomic_set(&cm_node->ref_count, 1);
- /* associate our parent CM core */
- cm_node->cm_core = cm_core;
- cm_node->tcp_cntxt.loc_id = NES_CM_DEF_LOCAL_ID;
- cm_node->tcp_cntxt.rcv_wscale = NES_CM_DEFAULT_RCV_WND_SCALE;
- cm_node->tcp_cntxt.rcv_wnd = NES_CM_DEFAULT_RCV_WND_SCALED >>
- NES_CM_DEFAULT_RCV_WND_SCALE;
- cm_node->tcp_cntxt.loc_seq_num = secure_tcp_seq(htonl(cm_node->loc_addr),
- htonl(cm_node->rem_addr),
- htons(cm_node->loc_port),
- htons(cm_node->rem_port));
- cm_node->tcp_cntxt.mss = nesvnic->max_frame_size - sizeof(struct iphdr) -
- sizeof(struct tcphdr) - ETH_HLEN - VLAN_HLEN;
- cm_node->tcp_cntxt.rcv_nxt = 0;
- /* get a unique session ID , add thread_id to an upcounter to handle race */
- atomic_inc(&cm_core->node_cnt);
- cm_node->conn_type = cm_info->conn_type;
- cm_node->apbvt_set = 0;
- cm_node->accept_pend = 0;
-
- cm_node->nesvnic = nesvnic;
- /* get some device handles, for arp lookup */
- nesdev = nesvnic->nesdev;
- nesadapter = nesdev->nesadapter;
-
- cm_node->loopbackpartner = NULL;
-
- /* get the mac addr for the remote node */
- oldarpindex = nes_arp_table(nesdev, cm_node->rem_addr,
- NULL, NES_ARP_RESOLVE);
- arpindex = nes_addr_resolve_neigh(nesvnic, cm_node->rem_addr,
- oldarpindex);
- if (arpindex < 0) {
- kfree(cm_node);
- return NULL;
- }
-
- /* copy the mac addr to node context */
- memcpy(cm_node->rem_mac, nesadapter->arp_table[arpindex].mac_addr, ETH_ALEN);
- nes_debug(NES_DBG_CM, "Remote mac addr from arp table: %pM\n",
- cm_node->rem_mac);
-
- add_hte_node(cm_core, cm_node);
- atomic_inc(&cm_nodes_created);
-
- return cm_node;
-}
-
-
-/**
- * add_ref_cm_node - destroy an instance of a cm node
- */
-static int add_ref_cm_node(struct nes_cm_node *cm_node)
-{
- atomic_inc(&cm_node->ref_count);
- return 0;
-}
-
-
-/**
- * rem_ref_cm_node - destroy an instance of a cm node
- */
-static int rem_ref_cm_node(struct nes_cm_core *cm_core,
- struct nes_cm_node *cm_node)
-{
- unsigned long flags;
- struct nes_qp *nesqp;
-
- if (!cm_node)
- return -EINVAL;
-
- spin_lock_irqsave(&cm_node->cm_core->ht_lock, flags);
- if (atomic_dec_return(&cm_node->ref_count)) {
- spin_unlock_irqrestore(&cm_node->cm_core->ht_lock, flags);
- return 0;
- }
- list_del(&cm_node->list);
- atomic_dec(&cm_core->ht_node_cnt);
- spin_unlock_irqrestore(&cm_node->cm_core->ht_lock, flags);
-
- /* if the node is destroyed before connection was accelerated */
- if (!cm_node->accelerated && cm_node->accept_pend) {
- BUG_ON(!cm_node->listener);
- atomic_dec(&cm_node->listener->pend_accepts_cnt);
- BUG_ON(atomic_read(&cm_node->listener->pend_accepts_cnt) < 0);
- }
- WARN_ON(cm_node->send_entry);
- if (cm_node->recv_entry)
- handle_recv_entry(cm_node, 0);
- if (cm_node->listener) {
- mini_cm_dec_refcnt_listen(cm_core, cm_node->listener, 0);
- } else {
- if (cm_node->apbvt_set && cm_node->nesvnic) {
- nes_manage_apbvt(cm_node->nesvnic, cm_node->loc_port,
- PCI_FUNC(cm_node->nesvnic->nesdev->pcidev->devfn),
- NES_MANAGE_APBVT_DEL);
- }
- nes_debug(NES_DBG_NLMSG, "Delete APBVT loc_port = %04X\n",
- cm_node->loc_port);
- }
-
- atomic_dec(&cm_core->node_cnt);
- atomic_inc(&cm_nodes_destroyed);
- nesqp = cm_node->nesqp;
- if (nesqp) {
- nesqp->cm_node = NULL;
- nes_rem_ref(&nesqp->ibqp);
- cm_node->nesqp = NULL;
- }
-
- kfree(cm_node);
- return 0;
-}
-
-/**
- * process_options
- */
-static int process_options(struct nes_cm_node *cm_node, u8 *optionsloc,
- u32 optionsize, u32 syn_packet)
-{
- u32 tmp;
- u32 offset = 0;
- union all_known_options *all_options;
- char got_mss_option = 0;
-
- while (offset < optionsize) {
- all_options = (union all_known_options *)(optionsloc + offset);
- switch (all_options->as_base.optionnum) {
- case OPTION_NUMBER_END:
- offset = optionsize;
- break;
- case OPTION_NUMBER_NONE:
- offset += 1;
- continue;
- case OPTION_NUMBER_MSS:
- nes_debug(NES_DBG_CM, "%s: MSS Length: %d Offset: %d "
- "Size: %d\n", __func__,
- all_options->as_mss.length, offset, optionsize);
- got_mss_option = 1;
- if (all_options->as_mss.length != 4) {
- return 1;
- } else {
- tmp = ntohs(all_options->as_mss.mss);
- if (tmp > 0 && tmp <
- cm_node->tcp_cntxt.mss)
- cm_node->tcp_cntxt.mss = tmp;
- }
- break;
- case OPTION_NUMBER_WINDOW_SCALE:
- cm_node->tcp_cntxt.snd_wscale =
- all_options->as_windowscale.shiftcount;
- break;
- default:
- nes_debug(NES_DBG_CM, "TCP Option not understood: %x\n",
- all_options->as_base.optionnum);
- break;
- }
- offset += all_options->as_base.length;
- }
- if ((!got_mss_option) && (syn_packet))
- cm_node->tcp_cntxt.mss = NES_CM_DEFAULT_MSS;
- return 0;
-}
-
-static void drop_packet(struct sk_buff *skb)
-{
- atomic_inc(&cm_accel_dropped_pkts);
- dev_kfree_skb_any(skb);
-}
-
-static void handle_fin_pkt(struct nes_cm_node *cm_node)
-{
- nes_debug(NES_DBG_CM, "Received FIN, cm_node = %p, state = %u. "
- "refcnt=%d\n", cm_node, cm_node->state,
- atomic_read(&cm_node->ref_count));
- switch (cm_node->state) {
- case NES_CM_STATE_SYN_RCVD:
- case NES_CM_STATE_SYN_SENT:
- case NES_CM_STATE_ESTABLISHED:
- case NES_CM_STATE_MPAREJ_RCVD:
- cm_node->tcp_cntxt.rcv_nxt++;
- cleanup_retrans_entry(cm_node);
- cm_node->state = NES_CM_STATE_LAST_ACK;
- send_fin(cm_node, NULL);
- break;
- case NES_CM_STATE_MPAREQ_SENT:
- create_event(cm_node, NES_CM_EVENT_ABORTED);
- cm_node->tcp_cntxt.rcv_nxt++;
- cleanup_retrans_entry(cm_node);
- cm_node->state = NES_CM_STATE_CLOSED;
- add_ref_cm_node(cm_node);
- send_reset(cm_node, NULL);
- break;
- case NES_CM_STATE_FIN_WAIT1:
- cm_node->tcp_cntxt.rcv_nxt++;
- cleanup_retrans_entry(cm_node);
- cm_node->state = NES_CM_STATE_CLOSING;
- send_ack(cm_node, NULL);
- /* Wait for ACK as this is simultaneous close..
- * After we receive ACK, do not send anything..
- * Just rm the node.. Done.. */
- break;
- case NES_CM_STATE_FIN_WAIT2:
- cm_node->tcp_cntxt.rcv_nxt++;
- cleanup_retrans_entry(cm_node);
- cm_node->state = NES_CM_STATE_TIME_WAIT;
- send_ack(cm_node, NULL);
- schedule_nes_timer(cm_node, NULL, NES_TIMER_TYPE_CLOSE, 1, 0);
- break;
- case NES_CM_STATE_TIME_WAIT:
- cm_node->tcp_cntxt.rcv_nxt++;
- cleanup_retrans_entry(cm_node);
- cm_node->state = NES_CM_STATE_CLOSED;
- rem_ref_cm_node(cm_node->cm_core, cm_node);
- break;
- case NES_CM_STATE_TSA:
- default:
- nes_debug(NES_DBG_CM, "Error Rcvd FIN for node-%p state = %d\n",
- cm_node, cm_node->state);
- break;
- }
-}
-
-
-static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
- struct tcphdr *tcph)
-{
-
- int reset = 0; /* whether to send reset in case of err.. */
- atomic_inc(&cm_resets_recvd);
- nes_debug(NES_DBG_CM, "Received Reset, cm_node = %p, state = %u."
- " refcnt=%d\n", cm_node, cm_node->state,
- atomic_read(&cm_node->ref_count));
- cleanup_retrans_entry(cm_node);
- switch (cm_node->state) {
- case NES_CM_STATE_SYN_SENT:
- case NES_CM_STATE_MPAREQ_SENT:
- nes_debug(NES_DBG_CM, "%s[%u] create abort for cm_node=%p "
- "listener=%p state=%d\n", __func__, __LINE__, cm_node,
- cm_node->listener, cm_node->state);
- switch (cm_node->mpa_frame_rev) {
- case IETF_MPA_V2:
- cm_node->mpa_frame_rev = IETF_MPA_V1;
- /* send a syn and goto syn sent state */
- cm_node->state = NES_CM_STATE_SYN_SENT;
- if (send_syn(cm_node, 0, NULL)) {
- active_open_err(cm_node, skb, reset);
- }
- break;
- case IETF_MPA_V1:
- default:
- active_open_err(cm_node, skb, reset);
- break;
- }
- break;
- case NES_CM_STATE_MPAREQ_RCVD:
- atomic_inc(&cm_node->passive_state);
- dev_kfree_skb_any(skb);
- break;
- case NES_CM_STATE_ESTABLISHED:
- case NES_CM_STATE_SYN_RCVD:
- case NES_CM_STATE_LISTENING:
- nes_debug(NES_DBG_CM, "Bad state %s[%u]\n", __func__, __LINE__);
- passive_open_err(cm_node, skb, reset);
- break;
- case NES_CM_STATE_TSA:
- active_open_err(cm_node, skb, reset);
- break;
- case NES_CM_STATE_CLOSED:
- drop_packet(skb);
- break;
- case NES_CM_STATE_FIN_WAIT2:
- case NES_CM_STATE_FIN_WAIT1:
- case NES_CM_STATE_LAST_ACK:
- cm_node->cm_id->rem_ref(cm_node->cm_id);
- /* fall through */
- case NES_CM_STATE_TIME_WAIT:
- cm_node->state = NES_CM_STATE_CLOSED;
- rem_ref_cm_node(cm_node->cm_core, cm_node);
- drop_packet(skb);
- break;
- default:
- drop_packet(skb);
- break;
- }
-}
-
-
-static void handle_rcv_mpa(struct nes_cm_node *cm_node, struct sk_buff *skb)
-{
- int ret = 0;
- int datasize = skb->len;
- u8 *dataloc = skb->data;
-
- enum nes_cm_event_type type = NES_CM_EVENT_UNKNOWN;
- u32 res_type;
-
- ret = parse_mpa(cm_node, dataloc, &res_type, datasize);
- if (ret) {
- nes_debug(NES_DBG_CM, "didn't like MPA Request\n");
- if (cm_node->state == NES_CM_STATE_MPAREQ_SENT) {
- nes_debug(NES_DBG_CM, "%s[%u] create abort for "
- "cm_node=%p listener=%p state=%d\n", __func__,
- __LINE__, cm_node, cm_node->listener,
- cm_node->state);
- active_open_err(cm_node, skb, 1);
- } else {
- passive_open_err(cm_node, skb, 1);
- }
- return;
- }
-
- switch (cm_node->state) {
- case NES_CM_STATE_ESTABLISHED:
- if (res_type == NES_MPA_REQUEST_REJECT)
- /*BIG problem as we are receiving the MPA.. So should
- * not be REJECT.. This is Passive Open.. We can
- * only receive it Reject for Active Open...*/
- WARN_ON(1);
- cm_node->state = NES_CM_STATE_MPAREQ_RCVD;
- type = NES_CM_EVENT_MPA_REQ;
- atomic_set(&cm_node->passive_state,
- NES_PASSIVE_STATE_INDICATED);
- break;
- case NES_CM_STATE_MPAREQ_SENT:
- cleanup_retrans_entry(cm_node);
- if (res_type == NES_MPA_REQUEST_REJECT) {
- type = NES_CM_EVENT_MPA_REJECT;
- cm_node->state = NES_CM_STATE_MPAREJ_RCVD;
- } else {
- type = NES_CM_EVENT_CONNECTED;
- cm_node->state = NES_CM_STATE_TSA;
- }
- send_ack(cm_node, NULL);
- break;
- default:
- WARN_ON(1);
- break;
- }
- dev_kfree_skb_any(skb);
- create_event(cm_node, type);
-}
-
-static void indicate_pkt_err(struct nes_cm_node *cm_node, struct sk_buff *skb)
-{
- switch (cm_node->state) {
- case NES_CM_STATE_SYN_SENT:
- case NES_CM_STATE_MPAREQ_SENT:
- nes_debug(NES_DBG_CM, "%s[%u] create abort for cm_node=%p "
- "listener=%p state=%d\n", __func__, __LINE__, cm_node,
- cm_node->listener, cm_node->state);
- active_open_err(cm_node, skb, 1);
- break;
- case NES_CM_STATE_ESTABLISHED:
- case NES_CM_STATE_SYN_RCVD:
- passive_open_err(cm_node, skb, 1);
- break;
- case NES_CM_STATE_TSA:
- default:
- drop_packet(skb);
- }
-}
-
-static int check_syn(struct nes_cm_node *cm_node, struct tcphdr *tcph,
- struct sk_buff *skb)
-{
- int err;
-
- err = ((ntohl(tcph->ack_seq) == cm_node->tcp_cntxt.loc_seq_num)) ? 0 : 1;
- if (err)
- active_open_err(cm_node, skb, 1);
-
- return err;
-}
-
-static int check_seq(struct nes_cm_node *cm_node, struct tcphdr *tcph,
- struct sk_buff *skb)
-{
- int err = 0;
- u32 seq;
- u32 ack_seq;
- u32 loc_seq_num = cm_node->tcp_cntxt.loc_seq_num;
- u32 rcv_nxt = cm_node->tcp_cntxt.rcv_nxt;
- u32 rcv_wnd;
-
- seq = ntohl(tcph->seq);
- ack_seq = ntohl(tcph->ack_seq);
- rcv_wnd = cm_node->tcp_cntxt.rcv_wnd;
- if (ack_seq != loc_seq_num)
- err = 1;
- else if (!between(seq, rcv_nxt, (rcv_nxt + rcv_wnd)))
- err = 1;
- if (err) {
- nes_debug(NES_DBG_CM, "%s[%u] create abort for cm_node=%p "
- "listener=%p state=%d\n", __func__, __LINE__, cm_node,
- cm_node->listener, cm_node->state);
- indicate_pkt_err(cm_node, skb);
- nes_debug(NES_DBG_CM, "seq ERROR cm_node =%p seq=0x%08X "
- "rcv_nxt=0x%08X rcv_wnd=0x%x\n", cm_node, seq, rcv_nxt,
- rcv_wnd);
- }
- return err;
-}
-
-/*
- * handle_syn_pkt() is for Passive node. The syn packet is received when a node
- * is created with a listener or it may comein as rexmitted packet which in
- * that case will be just dropped.
- */
-static void handle_syn_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
- struct tcphdr *tcph)
-{
- int ret;
- u32 inc_sequence;
- int optionsize;
-
- optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
- skb_trim(skb, 0);
- inc_sequence = ntohl(tcph->seq);
-
- switch (cm_node->state) {
- case NES_CM_STATE_SYN_SENT:
- case NES_CM_STATE_MPAREQ_SENT:
- /* Rcvd syn on active open connection*/
- active_open_err(cm_node, skb, 1);
- break;
- case NES_CM_STATE_LISTENING:
- /* Passive OPEN */
- if (atomic_read(&cm_node->listener->pend_accepts_cnt) >
- cm_node->listener->backlog) {
- nes_debug(NES_DBG_CM, "drop syn due to backlog "
- "pressure \n");
- cm_backlog_drops++;
- passive_open_err(cm_node, skb, 0);
- break;
- }
- ret = handle_tcp_options(cm_node, tcph, skb, optionsize,
- 1);
- if (ret) {
- passive_open_err(cm_node, skb, 0);
- /* drop pkt */
- break;
- }
- cm_node->tcp_cntxt.rcv_nxt = inc_sequence + 1;
- BUG_ON(cm_node->send_entry);
- cm_node->accept_pend = 1;
- atomic_inc(&cm_node->listener->pend_accepts_cnt);
-
- cm_node->state = NES_CM_STATE_SYN_RCVD;
- send_syn(cm_node, 1, skb);
- break;
- case NES_CM_STATE_CLOSED:
- cleanup_retrans_entry(cm_node);
- add_ref_cm_node(cm_node);
- send_reset(cm_node, skb);
- break;
- case NES_CM_STATE_TSA:
- case NES_CM_STATE_ESTABLISHED:
- case NES_CM_STATE_FIN_WAIT1:
- case NES_CM_STATE_FIN_WAIT2:
- case NES_CM_STATE_MPAREQ_RCVD:
- case NES_CM_STATE_LAST_ACK:
- case NES_CM_STATE_CLOSING:
- case NES_CM_STATE_UNKNOWN:
- default:
- drop_packet(skb);
- break;
- }
-}
-
-static void handle_synack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
- struct tcphdr *tcph)
-{
- int ret;
- u32 inc_sequence;
- int optionsize;
-
- optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
- skb_trim(skb, 0);
- inc_sequence = ntohl(tcph->seq);
- switch (cm_node->state) {
- case NES_CM_STATE_SYN_SENT:
- cleanup_retrans_entry(cm_node);
- /* active open */
- if (check_syn(cm_node, tcph, skb))
- return;
- cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
- /* setup options */
- ret = handle_tcp_options(cm_node, tcph, skb, optionsize, 0);
- if (ret) {
- nes_debug(NES_DBG_CM, "cm_node=%p tcp_options failed\n",
- cm_node);
- break;
- }
- cleanup_retrans_entry(cm_node);
- cm_node->tcp_cntxt.rcv_nxt = inc_sequence + 1;
- send_mpa_request(cm_node, skb);
- cm_node->state = NES_CM_STATE_MPAREQ_SENT;
- break;
- case NES_CM_STATE_MPAREQ_RCVD:
- /* passive open, so should not be here */
- passive_open_err(cm_node, skb, 1);
- break;
- case NES_CM_STATE_LISTENING:
- cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
- cleanup_retrans_entry(cm_node);
- cm_node->state = NES_CM_STATE_CLOSED;
- send_reset(cm_node, skb);
- break;
- case NES_CM_STATE_CLOSED:
- cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
- cleanup_retrans_entry(cm_node);
- add_ref_cm_node(cm_node);
- send_reset(cm_node, skb);
- break;
- case NES_CM_STATE_ESTABLISHED:
- case NES_CM_STATE_FIN_WAIT1:
- case NES_CM_STATE_FIN_WAIT2:
- case NES_CM_STATE_LAST_ACK:
- case NES_CM_STATE_TSA:
- case NES_CM_STATE_CLOSING:
- case NES_CM_STATE_UNKNOWN:
- case NES_CM_STATE_MPAREQ_SENT:
- default:
- drop_packet(skb);
- break;
- }
-}
-
-static int handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
- struct tcphdr *tcph)
-{
- int datasize = 0;
- u32 inc_sequence;
- int ret = 0;
- int optionsize;
-
- optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
-
- if (check_seq(cm_node, tcph, skb))
- return -EINVAL;
-
- skb_pull(skb, tcph->doff << 2);
- inc_sequence = ntohl(tcph->seq);
- datasize = skb->len;
- switch (cm_node->state) {
- case NES_CM_STATE_SYN_RCVD:
- /* Passive OPEN */
- cleanup_retrans_entry(cm_node);
- ret = handle_tcp_options(cm_node, tcph, skb, optionsize, 1);
- if (ret)
- break;
- cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
- cm_node->state = NES_CM_STATE_ESTABLISHED;
- if (datasize) {
- cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
- handle_rcv_mpa(cm_node, skb);
- } else { /* rcvd ACK only */
- dev_kfree_skb_any(skb);
- }
- break;
- case NES_CM_STATE_ESTABLISHED:
- /* Passive OPEN */
- cleanup_retrans_entry(cm_node);
- if (datasize) {
- cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
- handle_rcv_mpa(cm_node, skb);
- } else {
- drop_packet(skb);
- }
- break;
- case NES_CM_STATE_MPAREQ_SENT:
- cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
- if (datasize) {
- cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
- handle_rcv_mpa(cm_node, skb);
- } else { /* Could be just an ack pkt.. */
- dev_kfree_skb_any(skb);
- }
- break;
- case NES_CM_STATE_LISTENING:
- cleanup_retrans_entry(cm_node);
- cm_node->state = NES_CM_STATE_CLOSED;
- send_reset(cm_node, skb);
- break;
- case NES_CM_STATE_CLOSED:
- cleanup_retrans_entry(cm_node);
- add_ref_cm_node(cm_node);
- send_reset(cm_node, skb);
- break;
- case NES_CM_STATE_LAST_ACK:
- case NES_CM_STATE_CLOSING:
- cleanup_retrans_entry(cm_node);
- cm_node->state = NES_CM_STATE_CLOSED;
- cm_node->cm_id->rem_ref(cm_node->cm_id);
- rem_ref_cm_node(cm_node->cm_core, cm_node);
- drop_packet(skb);
- break;
- case NES_CM_STATE_FIN_WAIT1:
- cleanup_retrans_entry(cm_node);
- drop_packet(skb);
- cm_node->state = NES_CM_STATE_FIN_WAIT2;
- break;
- case NES_CM_STATE_SYN_SENT:
- case NES_CM_STATE_FIN_WAIT2:
- case NES_CM_STATE_TSA:
- case NES_CM_STATE_MPAREQ_RCVD:
- case NES_CM_STATE_UNKNOWN:
- default:
- cleanup_retrans_entry(cm_node);
- drop_packet(skb);
- break;
- }
- return ret;
-}
-
-
-
-static int handle_tcp_options(struct nes_cm_node *cm_node, struct tcphdr *tcph,
- struct sk_buff *skb, int optionsize, int passive)
-{
- u8 *optionsloc = (u8 *)&tcph[1];
-
- if (optionsize) {
- if (process_options(cm_node, optionsloc, optionsize,
- (u32)tcph->syn)) {
- nes_debug(NES_DBG_CM, "%s: Node %p, Sending RESET\n",
- __func__, cm_node);
- if (passive)
- passive_open_err(cm_node, skb, 1);
- else
- active_open_err(cm_node, skb, 1);
- return 1;
- }
- }
-
- cm_node->tcp_cntxt.snd_wnd = ntohs(tcph->window) <<
- cm_node->tcp_cntxt.snd_wscale;
-
- if (cm_node->tcp_cntxt.snd_wnd > cm_node->tcp_cntxt.max_snd_wnd)
- cm_node->tcp_cntxt.max_snd_wnd = cm_node->tcp_cntxt.snd_wnd;
- return 0;
-}
-
-/*
- * active_open_err() will send reset() if flag set..
- * It will also send ABORT event.
- */
-static void active_open_err(struct nes_cm_node *cm_node, struct sk_buff *skb,
- int reset)
-{
- cleanup_retrans_entry(cm_node);
- if (reset) {
- nes_debug(NES_DBG_CM, "ERROR active err called for cm_node=%p, "
- "state=%d\n", cm_node, cm_node->state);
- add_ref_cm_node(cm_node);
- send_reset(cm_node, skb);
- } else {
- dev_kfree_skb_any(skb);
- }
-
- cm_node->state = NES_CM_STATE_CLOSED;
- create_event(cm_node, NES_CM_EVENT_ABORTED);
-}
-
-/*
- * passive_open_err() will either do a reset() or will free up the skb and
- * remove the cm_node.
- */
-static void passive_open_err(struct nes_cm_node *cm_node, struct sk_buff *skb,
- int reset)
-{
- cleanup_retrans_entry(cm_node);
- cm_node->state = NES_CM_STATE_CLOSED;
- if (reset) {
- nes_debug(NES_DBG_CM, "passive_open_err sending RST for "
- "cm_node=%p state =%d\n", cm_node, cm_node->state);
- send_reset(cm_node, skb);
- } else {
- dev_kfree_skb_any(skb);
- rem_ref_cm_node(cm_node->cm_core, cm_node);
- }
-}
-
-/*
- * free_retrans_entry() routines assumes that the retrans_list_lock has
- * been acquired before calling.
- */
-static void free_retrans_entry(struct nes_cm_node *cm_node)
-{
- struct nes_timer_entry *send_entry;
-
- send_entry = cm_node->send_entry;
- if (send_entry) {
- cm_node->send_entry = NULL;
- dev_kfree_skb_any(send_entry->skb);
- kfree(send_entry);
- rem_ref_cm_node(cm_node->cm_core, cm_node);
- }
-}
-
-static void cleanup_retrans_entry(struct nes_cm_node *cm_node)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
- free_retrans_entry(cm_node);
- spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
-}
-
-/**
- * process_packet
- * Returns skb if to be freed, else it will return NULL if already used..
- */
-static void process_packet(struct nes_cm_node *cm_node, struct sk_buff *skb,
- struct nes_cm_core *cm_core)
-{
- enum nes_tcpip_pkt_type pkt_type = NES_PKT_TYPE_UNKNOWN;
- struct tcphdr *tcph = tcp_hdr(skb);
- u32 fin_set = 0;
- int ret = 0;
-
- skb_pull(skb, ip_hdr(skb)->ihl << 2);
-
- nes_debug(NES_DBG_CM, "process_packet: cm_node=%p state =%d syn=%d "
- "ack=%d rst=%d fin=%d\n", cm_node, cm_node->state, tcph->syn,
- tcph->ack, tcph->rst, tcph->fin);
-
- if (tcph->rst) {
- pkt_type = NES_PKT_TYPE_RST;
- } else if (tcph->syn) {
- pkt_type = NES_PKT_TYPE_SYN;
- if (tcph->ack)
- pkt_type = NES_PKT_TYPE_SYNACK;
- } else if (tcph->ack) {
- pkt_type = NES_PKT_TYPE_ACK;
- }
- if (tcph->fin)
- fin_set = 1;
-
- switch (pkt_type) {
- case NES_PKT_TYPE_SYN:
- handle_syn_pkt(cm_node, skb, tcph);
- break;
- case NES_PKT_TYPE_SYNACK:
- handle_synack_pkt(cm_node, skb, tcph);
- break;
- case NES_PKT_TYPE_ACK:
- ret = handle_ack_pkt(cm_node, skb, tcph);
- if (fin_set && !ret)
- handle_fin_pkt(cm_node);
- break;
- case NES_PKT_TYPE_RST:
- handle_rst_pkt(cm_node, skb, tcph);
- break;
- default:
- if ((fin_set) && (!check_seq(cm_node, tcph, skb)))
- handle_fin_pkt(cm_node);
- drop_packet(skb);
- break;
- }
-}
-
-/**
- * mini_cm_listen - create a listen node with params
- */
-static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core,
- struct nes_vnic *nesvnic, struct nes_cm_info *cm_info)
-{
- struct nes_cm_listener *listener;
- unsigned long flags;
-
- nes_debug(NES_DBG_CM, "Search for 0x%08x : 0x%04x\n",
- cm_info->loc_addr, cm_info->loc_port);
-
- /* cannot have multiple matching listeners */
- listener = find_listener(cm_core, cm_info->loc_addr, cm_info->loc_port,
- NES_CM_LISTENER_EITHER_STATE);
-
- if (listener && listener->listener_state == NES_CM_LISTENER_ACTIVE_STATE) {
- /* find automatically incs ref count ??? */
- atomic_dec(&listener->ref_count);
- nes_debug(NES_DBG_CM, "Not creating listener since it already exists\n");
- return NULL;
- }
-
- if (!listener) {
- /* create a CM listen node (1/2 node to compare incoming traffic to) */
- listener = kzalloc(sizeof(*listener), GFP_ATOMIC);
- if (!listener)
- return NULL;
-
- listener->loc_addr = cm_info->loc_addr;
- listener->loc_port = cm_info->loc_port;
- listener->reused_node = 0;
-
- atomic_set(&listener->ref_count, 1);
- }
- /* pasive case */
- /* find already inc'ed the ref count */
- else {
- listener->reused_node = 1;
- }
-
- listener->cm_id = cm_info->cm_id;
- atomic_set(&listener->pend_accepts_cnt, 0);
- listener->cm_core = cm_core;
- listener->nesvnic = nesvnic;
- atomic_inc(&cm_core->node_cnt);
-
- listener->conn_type = cm_info->conn_type;
- listener->backlog = cm_info->backlog;
- listener->listener_state = NES_CM_LISTENER_ACTIVE_STATE;
-
- if (!listener->reused_node) {
- spin_lock_irqsave(&cm_core->listen_list_lock, flags);
- list_add(&listener->list, &cm_core->listen_list.list);
- spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
- atomic_inc(&cm_core->listen_node_cnt);
- }
-
- nes_debug(NES_DBG_CM, "Api - listen(): addr=0x%08X, port=0x%04x,"
- " listener = %p, backlog = %d, cm_id = %p.\n",
- cm_info->loc_addr, cm_info->loc_port,
- listener, listener->backlog, listener->cm_id);
-
- return listener;
-}
-
-
-/**
- * mini_cm_connect - make a connection node with params
- */
-static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,
- struct nes_vnic *nesvnic, u16 private_data_len,
- void *private_data, struct nes_cm_info *cm_info)
-{
- int ret = 0;
- struct nes_cm_node *cm_node;
- struct nes_cm_listener *loopbackremotelistener;
- struct nes_cm_node *loopbackremotenode;
- struct nes_cm_info loopback_cm_info;
- u8 *start_buff;
-
- /* create a CM connection node */
- cm_node = make_cm_node(cm_core, nesvnic, cm_info, NULL);
- if (!cm_node)
- return NULL;
-
- /* set our node side to client (active) side */
- cm_node->tcp_cntxt.client = 1;
- cm_node->tcp_cntxt.rcv_wscale = NES_CM_DEFAULT_RCV_WND_SCALE;
-
- if (cm_info->loc_addr == cm_info->rem_addr) {
- loopbackremotelistener = find_listener(cm_core,
- cm_node->loc_addr, cm_node->rem_port,
- NES_CM_LISTENER_ACTIVE_STATE);
- if (loopbackremotelistener == NULL) {
- create_event(cm_node, NES_CM_EVENT_ABORTED);
- } else {
- loopback_cm_info = *cm_info;
- loopback_cm_info.loc_port = cm_info->rem_port;
- loopback_cm_info.rem_port = cm_info->loc_port;
- loopback_cm_info.loc_port =
- cm_info->rem_port;
- loopback_cm_info.rem_port =
- cm_info->loc_port;
- loopback_cm_info.cm_id = loopbackremotelistener->cm_id;
- loopbackremotenode = make_cm_node(cm_core, nesvnic,
- &loopback_cm_info, loopbackremotelistener);
- if (!loopbackremotenode) {
- rem_ref_cm_node(cm_node->cm_core, cm_node);
- return NULL;
- }
- atomic_inc(&cm_loopbacks);
- loopbackremotenode->loopbackpartner = cm_node;
- loopbackremotenode->tcp_cntxt.rcv_wscale =
- NES_CM_DEFAULT_RCV_WND_SCALE;
- cm_node->loopbackpartner = loopbackremotenode;
- memcpy(loopbackremotenode->mpa_frame_buf, private_data,
- private_data_len);
- loopbackremotenode->mpa_frame_size = private_data_len;
-
- /* we are done handling this state. */
- /* set node to a TSA state */
- cm_node->state = NES_CM_STATE_TSA;
- cm_node->tcp_cntxt.rcv_nxt =
- loopbackremotenode->tcp_cntxt.loc_seq_num;
- loopbackremotenode->tcp_cntxt.rcv_nxt =
- cm_node->tcp_cntxt.loc_seq_num;
- cm_node->tcp_cntxt.max_snd_wnd =
- loopbackremotenode->tcp_cntxt.rcv_wnd;
- loopbackremotenode->tcp_cntxt.max_snd_wnd =
- cm_node->tcp_cntxt.rcv_wnd;
- cm_node->tcp_cntxt.snd_wnd =
- loopbackremotenode->tcp_cntxt.rcv_wnd;
- loopbackremotenode->tcp_cntxt.snd_wnd =
- cm_node->tcp_cntxt.rcv_wnd;
- cm_node->tcp_cntxt.snd_wscale =
- loopbackremotenode->tcp_cntxt.rcv_wscale;
- loopbackremotenode->tcp_cntxt.snd_wscale =
- cm_node->tcp_cntxt.rcv_wscale;
- loopbackremotenode->state = NES_CM_STATE_MPAREQ_RCVD;
- create_event(loopbackremotenode, NES_CM_EVENT_MPA_REQ);
- }
- return cm_node;
- }
-
- start_buff = &cm_node->mpa_frame_buf[0] + sizeof(struct ietf_mpa_v2);
- cm_node->mpa_frame_size = private_data_len;
-
- memcpy(start_buff, private_data, private_data_len);
-
- /* send a syn and goto syn sent state */
- cm_node->state = NES_CM_STATE_SYN_SENT;
- ret = send_syn(cm_node, 0, NULL);
-
- if (ret) {
- /* error in sending the syn free up the cm_node struct */
- nes_debug(NES_DBG_CM, "Api - connect() FAILED: dest "
- "addr=0x%08X, port=0x%04x, cm_node=%p, cm_id = %p.\n",
- cm_node->rem_addr, cm_node->rem_port, cm_node,
- cm_node->cm_id);
- rem_ref_cm_node(cm_node->cm_core, cm_node);
- cm_node = NULL;
- }
-
- if (cm_node) {
- nes_debug(NES_DBG_CM, "Api - connect(): dest addr=0x%08X,"
- "port=0x%04x, cm_node=%p, cm_id = %p.\n",
- cm_node->rem_addr, cm_node->rem_port, cm_node,
- cm_node->cm_id);
- }
-
- return cm_node;
-}
-
-
-/**
- * mini_cm_accept - accept a connection
- * This function is never called
- */
-static int mini_cm_accept(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node)
-{
- return 0;
-}
-
-
-/**
- * mini_cm_reject - reject and teardown a connection
- */
-static int mini_cm_reject(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node)
-{
- int ret = 0;
- int err = 0;
- int passive_state;
- struct nes_cm_event event;
- struct iw_cm_id *cm_id = cm_node->cm_id;
- struct nes_cm_node *loopback = cm_node->loopbackpartner;
-
- nes_debug(NES_DBG_CM, "%s cm_node=%p type=%d state=%d\n",
- __func__, cm_node, cm_node->tcp_cntxt.client, cm_node->state);
-
- if (cm_node->tcp_cntxt.client)
- return ret;
- cleanup_retrans_entry(cm_node);
-
- if (!loopback) {
- passive_state = atomic_add_return(1, &cm_node->passive_state);
- if (passive_state == NES_SEND_RESET_EVENT) {
- cm_node->state = NES_CM_STATE_CLOSED;
- rem_ref_cm_node(cm_core, cm_node);
- } else {
- if (cm_node->state == NES_CM_STATE_LISTENER_DESTROYED) {
- rem_ref_cm_node(cm_core, cm_node);
- } else {
- ret = send_mpa_reject(cm_node);
- if (ret) {
- cm_node->state = NES_CM_STATE_CLOSED;
- err = send_reset(cm_node, NULL);
- if (err)
- WARN_ON(1);
- } else {
- cm_id->add_ref(cm_id);
- }
- }
- }
- } else {
- cm_node->cm_id = NULL;
- if (cm_node->state == NES_CM_STATE_LISTENER_DESTROYED) {
- rem_ref_cm_node(cm_core, cm_node);
- rem_ref_cm_node(cm_core, loopback);
- } else {
- event.cm_node = loopback;
- event.cm_info.rem_addr = loopback->rem_addr;
- event.cm_info.loc_addr = loopback->loc_addr;
- event.cm_info.rem_port = loopback->rem_port;
- event.cm_info.loc_port = loopback->loc_port;
- event.cm_info.cm_id = loopback->cm_id;
- cm_event_mpa_reject(&event);
- rem_ref_cm_node(cm_core, cm_node);
- loopback->state = NES_CM_STATE_CLOSING;
-
- cm_id = loopback->cm_id;
- rem_ref_cm_node(cm_core, loopback);
- cm_id->rem_ref(cm_id);
- }
- }
-
- return ret;
-}
-
-
-/**
- * mini_cm_close
- */
-static int mini_cm_close(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node)
-{
- int ret = 0;
-
- if (!cm_core || !cm_node)
- return -EINVAL;
-
- switch (cm_node->state) {
- case NES_CM_STATE_SYN_RCVD:
- case NES_CM_STATE_SYN_SENT:
- case NES_CM_STATE_ONE_SIDE_ESTABLISHED:
- case NES_CM_STATE_ESTABLISHED:
- case NES_CM_STATE_ACCEPTING:
- case NES_CM_STATE_MPAREQ_SENT:
- case NES_CM_STATE_MPAREQ_RCVD:
- cleanup_retrans_entry(cm_node);
- send_reset(cm_node, NULL);
- break;
- case NES_CM_STATE_CLOSE_WAIT:
- cm_node->state = NES_CM_STATE_LAST_ACK;
- send_fin(cm_node, NULL);
- break;
- case NES_CM_STATE_FIN_WAIT1:
- case NES_CM_STATE_FIN_WAIT2:
- case NES_CM_STATE_LAST_ACK:
- case NES_CM_STATE_TIME_WAIT:
- case NES_CM_STATE_CLOSING:
- ret = -1;
- break;
- case NES_CM_STATE_LISTENING:
- cleanup_retrans_entry(cm_node);
- send_reset(cm_node, NULL);
- break;
- case NES_CM_STATE_MPAREJ_RCVD:
- case NES_CM_STATE_UNKNOWN:
- case NES_CM_STATE_INITED:
- case NES_CM_STATE_CLOSED:
- case NES_CM_STATE_LISTENER_DESTROYED:
- ret = rem_ref_cm_node(cm_core, cm_node);
- break;
- case NES_CM_STATE_TSA:
- if (cm_node->send_entry)
- printk(KERN_ERR "ERROR Close got called from STATE_TSA "
- "send_entry=%p\n", cm_node->send_entry);
- ret = rem_ref_cm_node(cm_core, cm_node);
- break;
- }
- return ret;
-}
-
-
-/**
- * recv_pkt - recv an ETHERNET packet, and process it through CM
- * node state machine
- */
-static int mini_cm_recv_pkt(struct nes_cm_core *cm_core,
- struct nes_vnic *nesvnic, struct sk_buff *skb)
-{
- struct nes_cm_node *cm_node = NULL;
- struct nes_cm_listener *listener = NULL;
- struct iphdr *iph;
- struct tcphdr *tcph;
- struct nes_cm_info nfo;
- int skb_handled = 1;
- __be32 tmp_daddr, tmp_saddr;
-
- if (!skb)
- return 0;
- if (skb->len < sizeof(struct iphdr) + sizeof(struct tcphdr))
- return 0;
-
- iph = (struct iphdr *)skb->data;
- tcph = (struct tcphdr *)(skb->data + sizeof(struct iphdr));
-
- nfo.loc_addr = ntohl(iph->daddr);
- nfo.loc_port = ntohs(tcph->dest);
- nfo.rem_addr = ntohl(iph->saddr);
- nfo.rem_port = ntohs(tcph->source);
-
- tmp_daddr = cpu_to_be32(iph->daddr);
- tmp_saddr = cpu_to_be32(iph->saddr);
-
- nes_debug(NES_DBG_CM, "Received packet: dest=%pI4:0x%04X src=%pI4:0x%04X\n",
- &tmp_daddr, tcph->dest, &tmp_saddr, tcph->source);
-
- do {
- cm_node = find_node(cm_core,
- nfo.rem_port, nfo.rem_addr,
- nfo.loc_port, nfo.loc_addr);
-
- if (!cm_node) {
- /* Only type of packet accepted are for */
- /* the PASSIVE open (syn only) */
- if ((!tcph->syn) || (tcph->ack)) {
- skb_handled = 0;
- break;
- }
- listener = find_listener(cm_core, nfo.loc_addr,
- nfo.loc_port,
- NES_CM_LISTENER_ACTIVE_STATE);
- if (!listener) {
- nfo.cm_id = NULL;
- nfo.conn_type = 0;
- nes_debug(NES_DBG_CM, "Unable to find listener for the pkt\n");
- skb_handled = 0;
- break;
- }
- nfo.cm_id = listener->cm_id;
- nfo.conn_type = listener->conn_type;
- cm_node = make_cm_node(cm_core, nesvnic, &nfo,
- listener);
- if (!cm_node) {
- nes_debug(NES_DBG_CM, "Unable to allocate "
- "node\n");
- cm_packets_dropped++;
- atomic_dec(&listener->ref_count);
- dev_kfree_skb_any(skb);
- break;
- }
- if (!tcph->rst && !tcph->fin) {
- cm_node->state = NES_CM_STATE_LISTENING;
- } else {
- cm_packets_dropped++;
- rem_ref_cm_node(cm_core, cm_node);
- dev_kfree_skb_any(skb);
- break;
- }
- add_ref_cm_node(cm_node);
- } else if (cm_node->state == NES_CM_STATE_TSA) {
- if (cm_node->nesqp->pau_mode)
- nes_queue_mgt_skbs(skb, nesvnic, cm_node->nesqp);
- else {
- rem_ref_cm_node(cm_core, cm_node);
- atomic_inc(&cm_accel_dropped_pkts);
- dev_kfree_skb_any(skb);
- }
- break;
- }
- skb_reset_network_header(skb);
- skb_set_transport_header(skb, sizeof(*tcph));
- skb->len = ntohs(iph->tot_len);
- process_packet(cm_node, skb, cm_core);
- rem_ref_cm_node(cm_core, cm_node);
- } while (0);
- return skb_handled;
-}
-
-
-/**
- * nes_cm_alloc_core - allocate a top level instance of a cm core
- */
-static struct nes_cm_core *nes_cm_alloc_core(void)
-{
- struct nes_cm_core *cm_core;
-
- /* setup the CM core */
- /* alloc top level core control structure */
- cm_core = kzalloc(sizeof(*cm_core), GFP_KERNEL);
- if (!cm_core)
- return NULL;
-
- INIT_LIST_HEAD(&cm_core->connected_nodes);
- timer_setup(&cm_core->tcp_timer, nes_cm_timer_tick, 0);
-
- cm_core->mtu = NES_CM_DEFAULT_MTU;
- cm_core->state = NES_CM_STATE_INITED;
- cm_core->free_tx_pkt_max = NES_CM_DEFAULT_FREE_PKTS;
-
- atomic_set(&cm_core->events_posted, 0);
-
- cm_core->api = &nes_cm_api;
-
- spin_lock_init(&cm_core->ht_lock);
- spin_lock_init(&cm_core->listen_list_lock);
-
- INIT_LIST_HEAD(&cm_core->listen_list.list);
-
- nes_debug(NES_DBG_CM, "Init CM Core completed -- cm_core=%p\n", cm_core);
-
- nes_debug(NES_DBG_CM, "Enable QUEUE EVENTS\n");
- cm_core->event_wq = alloc_ordered_workqueue("nesewq", 0);
- if (!cm_core->event_wq)
- goto out_free_cmcore;
- cm_core->post_event = nes_cm_post_event;
- nes_debug(NES_DBG_CM, "Enable QUEUE DISCONNECTS\n");
- cm_core->disconn_wq = alloc_ordered_workqueue("nesdwq", 0);
- if (!cm_core->disconn_wq)
- goto out_free_wq;
-
- print_core(cm_core);
- return cm_core;
-
-out_free_wq:
- destroy_workqueue(cm_core->event_wq);
-out_free_cmcore:
- kfree(cm_core);
- return NULL;
-}
-
-
-/**
- * mini_cm_dealloc_core - deallocate a top level instance of a cm core
- */
-static int mini_cm_dealloc_core(struct nes_cm_core *cm_core)
-{
- nes_debug(NES_DBG_CM, "De-Alloc CM Core (%p)\n", cm_core);
-
- if (!cm_core)
- return -EINVAL;
-
- barrier();
-
- if (timer_pending(&cm_core->tcp_timer))
- del_timer(&cm_core->tcp_timer);
-
- destroy_workqueue(cm_core->event_wq);
- destroy_workqueue(cm_core->disconn_wq);
- nes_debug(NES_DBG_CM, "\n");
- kfree(cm_core);
-
- return 0;
-}
-
-
-/**
- * mini_cm_get
- */
-static int mini_cm_get(struct nes_cm_core *cm_core)
-{
- return cm_core->state;
-}
-
-
-/**
- * mini_cm_set
- */
-static int mini_cm_set(struct nes_cm_core *cm_core, u32 type, u32 value)
-{
- int ret = 0;
-
- switch (type) {
- case NES_CM_SET_PKT_SIZE:
- cm_core->mtu = value;
- break;
- case NES_CM_SET_FREE_PKT_Q_SIZE:
- cm_core->free_tx_pkt_max = value;
- break;
- default:
- /* unknown set option */
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-
-/**
- * nes_cm_init_tsa_conn setup HW; MPA frames must be
- * successfully exchanged when this is called
- */
-static int nes_cm_init_tsa_conn(struct nes_qp *nesqp, struct nes_cm_node *cm_node)
-{
- int ret = 0;
-
- if (!nesqp)
- return -EINVAL;
-
- nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_IPV4 |
- NES_QPCONTEXT_MISC_NO_NAGLE | NES_QPCONTEXT_MISC_DO_NOT_FRAG |
- NES_QPCONTEXT_MISC_DROS);
-
- if (cm_node->tcp_cntxt.snd_wscale || cm_node->tcp_cntxt.rcv_wscale)
- nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_WSCALE);
-
- nesqp->nesqp_context->misc2 |= cpu_to_le32(64 << NES_QPCONTEXT_MISC2_TTL_SHIFT);
-
- nesqp->nesqp_context->misc2 |= cpu_to_le32(
- cm_node->tos << NES_QPCONTEXT_MISC2_TOS_SHIFT);
-
- nesqp->nesqp_context->mss |= cpu_to_le32(((u32)cm_node->tcp_cntxt.mss) << 16);
-
- nesqp->nesqp_context->tcp_state_flow_label |= cpu_to_le32(
- (u32)NES_QPCONTEXT_TCPSTATE_EST << NES_QPCONTEXT_TCPFLOW_TCP_STATE_SHIFT);
-
- nesqp->nesqp_context->pd_index_wscale |= cpu_to_le32(
- (cm_node->tcp_cntxt.snd_wscale << NES_QPCONTEXT_PDWSCALE_SND_WSCALE_SHIFT) &
- NES_QPCONTEXT_PDWSCALE_SND_WSCALE_MASK);
-
- nesqp->nesqp_context->pd_index_wscale |= cpu_to_le32(
- (cm_node->tcp_cntxt.rcv_wscale << NES_QPCONTEXT_PDWSCALE_RCV_WSCALE_SHIFT) &
- NES_QPCONTEXT_PDWSCALE_RCV_WSCALE_MASK);
-
- nesqp->nesqp_context->keepalive = cpu_to_le32(0x80);
- nesqp->nesqp_context->ts_recent = 0;
- nesqp->nesqp_context->ts_age = 0;
- nesqp->nesqp_context->snd_nxt = cpu_to_le32(cm_node->tcp_cntxt.loc_seq_num);
- nesqp->nesqp_context->snd_wnd = cpu_to_le32(cm_node->tcp_cntxt.snd_wnd);
- nesqp->nesqp_context->rcv_nxt = cpu_to_le32(cm_node->tcp_cntxt.rcv_nxt);
- nesqp->nesqp_context->rcv_wnd = cpu_to_le32(cm_node->tcp_cntxt.rcv_wnd <<
- cm_node->tcp_cntxt.rcv_wscale);
- nesqp->nesqp_context->snd_max = cpu_to_le32(cm_node->tcp_cntxt.loc_seq_num);
- nesqp->nesqp_context->snd_una = cpu_to_le32(cm_node->tcp_cntxt.loc_seq_num);
- nesqp->nesqp_context->srtt = 0;
- nesqp->nesqp_context->rttvar = cpu_to_le32(0x6);
- nesqp->nesqp_context->ssthresh = cpu_to_le32(0x3FFFC000);
- nesqp->nesqp_context->cwnd = cpu_to_le32(2 * cm_node->tcp_cntxt.mss);
- nesqp->nesqp_context->snd_wl1 = cpu_to_le32(cm_node->tcp_cntxt.rcv_nxt);
- nesqp->nesqp_context->snd_wl2 = cpu_to_le32(cm_node->tcp_cntxt.loc_seq_num);
- nesqp->nesqp_context->max_snd_wnd = cpu_to_le32(cm_node->tcp_cntxt.max_snd_wnd);
-
- nes_debug(NES_DBG_CM, "QP%u: rcv_nxt = 0x%08X, snd_nxt = 0x%08X,"
- " Setting MSS to %u, PDWscale = 0x%08X, rcv_wnd = %u, context misc = 0x%08X.\n",
- nesqp->hwqp.qp_id, le32_to_cpu(nesqp->nesqp_context->rcv_nxt),
- le32_to_cpu(nesqp->nesqp_context->snd_nxt),
- cm_node->tcp_cntxt.mss, le32_to_cpu(nesqp->nesqp_context->pd_index_wscale),
- le32_to_cpu(nesqp->nesqp_context->rcv_wnd),
- le32_to_cpu(nesqp->nesqp_context->misc));
- nes_debug(NES_DBG_CM, " snd_wnd = 0x%08X.\n", le32_to_cpu(nesqp->nesqp_context->snd_wnd));
- nes_debug(NES_DBG_CM, " snd_cwnd = 0x%08X.\n", le32_to_cpu(nesqp->nesqp_context->cwnd));
- nes_debug(NES_DBG_CM, " max_swnd = 0x%08X.\n", le32_to_cpu(nesqp->nesqp_context->max_snd_wnd));
-
- nes_debug(NES_DBG_CM, "Change cm_node state to TSA\n");
- cm_node->state = NES_CM_STATE_TSA;
-
- return ret;
-}
-
-
-/**
- * nes_cm_disconn
- */
-int nes_cm_disconn(struct nes_qp *nesqp)
-{
- struct disconn_work *work;
-
- work = kzalloc(sizeof *work, GFP_ATOMIC);
- if (!work)
- return -ENOMEM; /* Timer will clean up */
-
- nes_add_ref(&nesqp->ibqp);
- work->nesqp = nesqp;
- INIT_WORK(&work->work, nes_disconnect_worker);
- queue_work(g_cm_core->disconn_wq, &work->work);
- return 0;
-}
-
-
-/**
- * nes_disconnect_worker
- */
-static void nes_disconnect_worker(struct work_struct *work)
-{
- struct disconn_work *dwork = container_of(work, struct disconn_work, work);
- struct nes_qp *nesqp = dwork->nesqp;
-
- kfree(dwork);
- nes_debug(NES_DBG_CM, "processing AEQE id 0x%04X for QP%u.\n",
- nesqp->last_aeq, nesqp->hwqp.qp_id);
- nes_cm_disconn_true(nesqp);
- nes_rem_ref(&nesqp->ibqp);
-}
-
-
-/**
- * nes_cm_disconn_true
- */
-static int nes_cm_disconn_true(struct nes_qp *nesqp)
-{
- unsigned long flags;
- int ret = 0;
- struct iw_cm_id *cm_id;
- struct iw_cm_event cm_event;
- struct nes_vnic *nesvnic;
- u16 last_ae;
- u8 original_hw_tcp_state;
- u8 original_ibqp_state;
- int disconn_status = 0;
- int issue_disconn = 0;
- int issue_close = 0;
- int issue_flush = 0;
- u32 flush_q = NES_CQP_FLUSH_RQ;
- struct ib_event ibevent;
-
- if (!nesqp) {
- nes_debug(NES_DBG_CM, "disconnect_worker nesqp is NULL\n");
- return -1;
- }
-
- spin_lock_irqsave(&nesqp->lock, flags);
- cm_id = nesqp->cm_id;
- /* make sure we havent already closed this connection */
- if (!cm_id) {
- nes_debug(NES_DBG_CM, "QP%u disconnect_worker cmid is NULL\n",
- nesqp->hwqp.qp_id);
- spin_unlock_irqrestore(&nesqp->lock, flags);
- return -1;
- }
-
- nesvnic = to_nesvnic(nesqp->ibqp.device);
- nes_debug(NES_DBG_CM, "Disconnecting QP%u\n", nesqp->hwqp.qp_id);
-
- original_hw_tcp_state = nesqp->hw_tcp_state;
- original_ibqp_state = nesqp->ibqp_state;
- last_ae = nesqp->last_aeq;
-
- if (nesqp->term_flags) {
- issue_disconn = 1;
- issue_close = 1;
- nesqp->cm_id = NULL;
- del_timer(&nesqp->terminate_timer);
- if (nesqp->flush_issued == 0) {
- nesqp->flush_issued = 1;
- issue_flush = 1;
- }
- } else if ((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) ||
- ((original_ibqp_state == IB_QPS_RTS) &&
- (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) {
- issue_disconn = 1;
- if (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET)
- disconn_status = -ECONNRESET;
- }
-
- if (((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSED) ||
- (original_hw_tcp_state == NES_AEQE_TCP_STATE_TIME_WAIT) ||
- (last_ae == NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) ||
- (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) {
- issue_close = 1;
- nesqp->cm_id = NULL;
- if (nesqp->flush_issued == 0) {
- nesqp->flush_issued = 1;
- issue_flush = 1;
- }
- }
-
- spin_unlock_irqrestore(&nesqp->lock, flags);
-
- if ((issue_flush) && (nesqp->destroyed == 0)) {
- /* Flush the queue(s) */
- if (nesqp->hw_iwarp_state >= NES_AEQE_IWARP_STATE_TERMINATE)
- flush_q |= NES_CQP_FLUSH_SQ;
- flush_wqes(nesvnic->nesdev, nesqp, flush_q, 1);
-
- if (nesqp->term_flags) {
- ibevent.device = nesqp->ibqp.device;
- ibevent.event = nesqp->terminate_eventtype;
- ibevent.element.qp = &nesqp->ibqp;
- if (nesqp->ibqp.event_handler)
- nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
- }
- }
-
- if ((cm_id) && (cm_id->event_handler)) {
- if (issue_disconn) {
- atomic_inc(&cm_disconnects);
- cm_event.event = IW_CM_EVENT_DISCONNECT;
- cm_event.status = disconn_status;
- cm_event.local_addr = cm_id->m_local_addr;
- cm_event.remote_addr = cm_id->m_remote_addr;
- cm_event.private_data = NULL;
- cm_event.private_data_len = 0;
-
- nes_debug(NES_DBG_CM, "Generating a CM Disconnect Event"
- " for QP%u, SQ Head = %u, SQ Tail = %u. "
- "cm_id = %p, refcount = %u.\n",
- nesqp->hwqp.qp_id, nesqp->hwqp.sq_head,
- nesqp->hwqp.sq_tail, cm_id,
- atomic_read(&nesqp->refcount));
-
- ret = cm_id->event_handler(cm_id, &cm_event);
- if (ret)
- nes_debug(NES_DBG_CM, "OFA CM event_handler "
- "returned, ret=%d\n", ret);
- }
-
- if (issue_close) {
- atomic_inc(&cm_closes);
- nes_disconnect(nesqp, 1);
-
- cm_id->provider_data = nesqp;
- /* Send up the close complete event */
- cm_event.event = IW_CM_EVENT_CLOSE;
- cm_event.status = 0;
- cm_event.provider_data = cm_id->provider_data;
- cm_event.local_addr = cm_id->m_local_addr;
- cm_event.remote_addr = cm_id->m_remote_addr;
- cm_event.private_data = NULL;
- cm_event.private_data_len = 0;
-
- ret = cm_id->event_handler(cm_id, &cm_event);
- if (ret)
- nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);
-
- cm_id->rem_ref(cm_id);
- }
- }
-
- return 0;
-}
-
-
-/**
- * nes_disconnect
- */
-static int nes_disconnect(struct nes_qp *nesqp, int abrupt)
-{
- int ret = 0;
- struct nes_vnic *nesvnic;
- struct nes_device *nesdev;
- struct nes_ib_device *nesibdev;
-
- nesvnic = to_nesvnic(nesqp->ibqp.device);
- if (!nesvnic)
- return -EINVAL;
-
- nesdev = nesvnic->nesdev;
- nesibdev = nesvnic->nesibdev;
-
- nes_debug(NES_DBG_CM, "netdev refcnt = %u.\n",
- netdev_refcnt_read(nesvnic->netdev));
-
- if (nesqp->active_conn) {
-
- /* indicate this connection is NOT active */
- nesqp->active_conn = 0;
- } else {
- /* Need to free the Last Streaming Mode Message */
- if (nesqp->ietf_frame) {
- if (nesqp->lsmm_mr)
- nesibdev->ibdev.ops.dereg_mr(nesqp->lsmm_mr,
- NULL);
- pci_free_consistent(nesdev->pcidev,
- nesqp->private_data_len + nesqp->ietf_frame_size,
- nesqp->ietf_frame, nesqp->ietf_frame_pbase);
- }
- }
-
- /* close the CM node down if it is still active */
- if (nesqp->cm_node) {
- nes_debug(NES_DBG_CM, "Call close API\n");
-
- g_cm_core->api->close(g_cm_core, nesqp->cm_node);
- }
-
- return ret;
-}
-
-
-/**
- * nes_accept
- */
-int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
-{
- u64 u64temp;
- struct ib_qp *ibqp;
- struct nes_qp *nesqp;
- struct nes_vnic *nesvnic;
- struct nes_device *nesdev;
- struct nes_cm_node *cm_node;
- struct nes_adapter *adapter;
- struct ib_qp_attr attr;
- struct iw_cm_event cm_event;
- struct nes_hw_qp_wqe *wqe;
- struct nes_v4_quad nes_quad;
- u32 crc_value;
- int ret;
- int passive_state;
- struct ib_mr *ibmr = NULL;
- struct nes_pd *nespd;
- u64 tagged_offset;
- u8 mpa_frame_offset = 0;
- struct ietf_mpa_v2 *mpa_v2_frame;
- u8 start_addr = 0;
- u8 *start_ptr = &start_addr;
- u8 **start_buff = &start_ptr;
- u16 buff_len = 0;
- struct sockaddr_in *laddr = (struct sockaddr_in *)&cm_id->m_local_addr;
- struct sockaddr_in *raddr = (struct sockaddr_in *)&cm_id->m_remote_addr;
-
- ibqp = nes_get_qp(cm_id->device, conn_param->qpn);
- if (!ibqp)
- return -EINVAL;
-
- /* get all our handles */
- nesqp = to_nesqp(ibqp);
- nesvnic = to_nesvnic(nesqp->ibqp.device);
- nesdev = nesvnic->nesdev;
- adapter = nesdev->nesadapter;
-
- cm_node = (struct nes_cm_node *)cm_id->provider_data;
- nes_debug(NES_DBG_CM, "nes_accept: cm_node= %p nesvnic=%p, netdev=%p,"
- "%s\n", cm_node, nesvnic, nesvnic->netdev,
- nesvnic->netdev->name);
-
- if (NES_CM_STATE_LISTENER_DESTROYED == cm_node->state) {
- if (cm_node->loopbackpartner)
- rem_ref_cm_node(cm_node->cm_core, cm_node->loopbackpartner);
- rem_ref_cm_node(cm_node->cm_core, cm_node);
- return -EINVAL;
- }
-
- passive_state = atomic_add_return(1, &cm_node->passive_state);
- if (passive_state == NES_SEND_RESET_EVENT) {
- rem_ref_cm_node(cm_node->cm_core, cm_node);
- return -ECONNRESET;
- }
- /* associate the node with the QP */
- nesqp->cm_node = (void *)cm_node;
- cm_node->nesqp = nesqp;
-
-
- nes_debug(NES_DBG_CM, "QP%u, cm_node=%p, jiffies = %lu listener = %p\n",
- nesqp->hwqp.qp_id, cm_node, jiffies, cm_node->listener);
- atomic_inc(&cm_accepts);
-
- nes_debug(NES_DBG_CM, "netdev refcnt = %u.\n",
- netdev_refcnt_read(nesvnic->netdev));
-
- nesqp->ietf_frame_size = sizeof(struct ietf_mpa_v2);
- /* allocate the ietf frame and space for private data */
- nesqp->ietf_frame = pci_alloc_consistent(nesdev->pcidev,
- nesqp->ietf_frame_size + conn_param->private_data_len,
- &nesqp->ietf_frame_pbase);
-
- if (!nesqp->ietf_frame) {
- nes_debug(NES_DBG_CM, "Unable to allocate memory for private data\n");
- return -ENOMEM;
- }
- mpa_v2_frame = (struct ietf_mpa_v2 *)nesqp->ietf_frame;
-
- if (cm_node->mpa_frame_rev == IETF_MPA_V1)
- mpa_frame_offset = 4;
-
- if (cm_node->mpa_frame_rev == IETF_MPA_V1 ||
- cm_node->mpav2_ird_ord == IETF_NO_IRD_ORD) {
- record_ird_ord(cm_node, (u16)conn_param->ird, (u16)conn_param->ord);
- }
-
- memcpy(mpa_v2_frame->priv_data, conn_param->private_data,
- conn_param->private_data_len);
-
- cm_build_mpa_frame(cm_node, start_buff, &buff_len, nesqp->ietf_frame, MPA_KEY_REPLY);
- nesqp->private_data_len = conn_param->private_data_len;
-
- /* setup our first outgoing iWarp send WQE (the IETF frame response) */
- wqe = &nesqp->hwqp.sq_vbase[0];
-
- if (raddr->sin_addr.s_addr != laddr->sin_addr.s_addr) {
- u64temp = (unsigned long)nesqp;
- nespd = nesqp->nespd;
- tagged_offset = (u64)(unsigned long)*start_buff;
- ibmr = nes_reg_phys_mr(&nespd->ibpd,
- nesqp->ietf_frame_pbase + mpa_frame_offset,
- buff_len, IB_ACCESS_LOCAL_WRITE,
- &tagged_offset);
- if (IS_ERR(ibmr)) {
- nes_debug(NES_DBG_CM, "Unable to register memory region"
- "for lSMM for cm_node = %p \n",
- cm_node);
- pci_free_consistent(nesdev->pcidev,
- nesqp->private_data_len + nesqp->ietf_frame_size,
- nesqp->ietf_frame, nesqp->ietf_frame_pbase);
- return PTR_ERR(ibmr);
- }
-
- ibmr->pd = &nespd->ibpd;
- ibmr->device = nespd->ibpd.device;
- nesqp->lsmm_mr = ibmr;
-
- u64temp |= NES_SW_CONTEXT_ALIGN >> 1;
- set_wqe_64bit_value(wqe->wqe_words,
- NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX,
- u64temp);
- wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] =
- cpu_to_le32(NES_IWARP_SQ_WQE_STREAMING |
- NES_IWARP_SQ_WQE_WRPDU);
- wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] =
- cpu_to_le32(buff_len);
- set_wqe_64bit_value(wqe->wqe_words,
- NES_IWARP_SQ_WQE_FRAG0_LOW_IDX,
- (u64)(unsigned long)(*start_buff));
- wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX] =
- cpu_to_le32(buff_len);
- wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = ibmr->lkey;
- if (nesqp->sq_kmapped) {
- nesqp->sq_kmapped = 0;
- kunmap(nesqp->page);
- }
-
- nesqp->nesqp_context->ird_ord_sizes |=
- cpu_to_le32(NES_QPCONTEXT_ORDIRD_LSMM_PRESENT |
- NES_QPCONTEXT_ORDIRD_WRPDU);
- } else {
- nesqp->nesqp_context->ird_ord_sizes |=
- cpu_to_le32(NES_QPCONTEXT_ORDIRD_WRPDU);
- }
- nesqp->skip_lsmm = 1;
-
- /* Cache the cm_id in the qp */
- nesqp->cm_id = cm_id;
- cm_node->cm_id = cm_id;
-
- /* nesqp->cm_node = (void *)cm_id->provider_data; */
- cm_id->provider_data = nesqp;
- nesqp->active_conn = 0;
-
- if (cm_node->state == NES_CM_STATE_TSA)
- nes_debug(NES_DBG_CM, "Already state = TSA for cm_node=%p\n",
- cm_node);
-
- nes_cm_init_tsa_conn(nesqp, cm_node);
-
- nesqp->nesqp_context->tcpPorts[0] =
- cpu_to_le16(cm_node->loc_port);
- nesqp->nesqp_context->tcpPorts[1] =
- cpu_to_le16(cm_node->rem_port);
-
- nesqp->nesqp_context->ip0 = cpu_to_le32(cm_node->rem_addr);
-
- nesqp->nesqp_context->misc2 |= cpu_to_le32(
- (u32)PCI_FUNC(nesdev->pcidev->devfn) <<
- NES_QPCONTEXT_MISC2_SRC_IP_SHIFT);
-
- nesqp->nesqp_context->arp_index_vlan |=
- cpu_to_le32(nes_arp_table(nesdev,
- le32_to_cpu(nesqp->nesqp_context->ip0), NULL,
- NES_ARP_RESOLVE) << 16);
-
- nesqp->nesqp_context->ts_val_delta = cpu_to_le32(
- jiffies - nes_read_indexed(nesdev, NES_IDX_TCP_NOW));
-
- nesqp->nesqp_context->ird_index = cpu_to_le32(nesqp->hwqp.qp_id);
-
- nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32(
- ((u32)1 << NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT));
- nesqp->nesqp_context->ird_ord_sizes |=
- cpu_to_le32((u32)cm_node->ord_size);
-
- memset(&nes_quad, 0, sizeof(nes_quad));
- nes_quad.DstIpAdrIndex =
- cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24);
- nes_quad.SrcIpadr = htonl(cm_node->rem_addr);
- nes_quad.TcpPorts[0] = htons(cm_node->rem_port);
- nes_quad.TcpPorts[1] = htons(cm_node->loc_port);
-
- /* Produce hash key */
- crc_value = get_crc_value(&nes_quad);
- nesqp->hte_index = cpu_to_be32(crc_value ^ 0xffffffff);
- nes_debug(NES_DBG_CM, "HTE Index = 0x%08X, CRC = 0x%08X\n",
- nesqp->hte_index, nesqp->hte_index & adapter->hte_index_mask);
-
- nesqp->hte_index &= adapter->hte_index_mask;
- nesqp->nesqp_context->hte_index = cpu_to_le32(nesqp->hte_index);
-
- cm_node->cm_core->api->accelerated(cm_node->cm_core, cm_node);
-
- nes_debug(NES_DBG_CM, "QP%u, Destination IP = 0x%08X:0x%04X, local = "
- "0x%08X:0x%04X, rcv_nxt=0x%08X, snd_nxt=0x%08X, mpa + "
- "private data length=%u.\n", nesqp->hwqp.qp_id,
- ntohl(raddr->sin_addr.s_addr), ntohs(raddr->sin_port),
- ntohl(laddr->sin_addr.s_addr), ntohs(laddr->sin_port),
- le32_to_cpu(nesqp->nesqp_context->rcv_nxt),
- le32_to_cpu(nesqp->nesqp_context->snd_nxt),
- buff_len);
-
- /* notify OF layer that accept event was successful */
- cm_id->add_ref(cm_id);
- nes_add_ref(&nesqp->ibqp);
-
- cm_event.event = IW_CM_EVENT_ESTABLISHED;
- cm_event.status = 0;
- cm_event.provider_data = (void *)nesqp;
- cm_event.local_addr = cm_id->m_local_addr;
- cm_event.remote_addr = cm_id->m_remote_addr;
- cm_event.private_data = NULL;
- cm_event.private_data_len = 0;
- cm_event.ird = cm_node->ird_size;
- cm_event.ord = cm_node->ord_size;
-
- ret = cm_id->event_handler(cm_id, &cm_event);
- attr.qp_state = IB_QPS_RTS;
- nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL);
- if (cm_node->loopbackpartner) {
- cm_node->loopbackpartner->mpa_frame_size =
- nesqp->private_data_len;
- /* copy entire MPA frame to our cm_node's frame */
- memcpy(cm_node->loopbackpartner->mpa_frame_buf,
- conn_param->private_data, conn_param->private_data_len);
- create_event(cm_node->loopbackpartner, NES_CM_EVENT_CONNECTED);
- }
- if (ret)
- printk(KERN_ERR "%s[%u] OFA CM event_handler returned, "
- "ret=%d\n", __func__, __LINE__, ret);
-
- return 0;
-}
-
-
-/**
- * nes_reject
- */
-int nes_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
-{
- struct nes_cm_node *cm_node;
- struct nes_cm_node *loopback;
- struct nes_cm_core *cm_core;
- u8 *start_buff;
-
- atomic_inc(&cm_rejects);
- cm_node = (struct nes_cm_node *)cm_id->provider_data;
- loopback = cm_node->loopbackpartner;
- cm_core = cm_node->cm_core;
- cm_node->cm_id = cm_id;
-
- if (pdata_len + sizeof(struct ietf_mpa_v2) > MAX_CM_BUFFER)
- return -EINVAL;
-
- if (loopback) {
- memcpy(&loopback->mpa_frame.priv_data, pdata, pdata_len);
- loopback->mpa_frame.priv_data_len = pdata_len;
- loopback->mpa_frame_size = pdata_len;
- } else {
- start_buff = &cm_node->mpa_frame_buf[0] + sizeof(struct ietf_mpa_v2);
- cm_node->mpa_frame_size = pdata_len;
- memcpy(start_buff, pdata, pdata_len);
- }
- return cm_core->api->reject(cm_core, cm_node);
-}
-
-
-/**
- * nes_connect
- * setup and launch cm connect node
- */
-int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
-{
- struct ib_qp *ibqp;
- struct nes_qp *nesqp;
- struct nes_vnic *nesvnic;
- struct nes_device *nesdev;
- struct nes_cm_node *cm_node;
- struct nes_cm_info cm_info;
- int apbvt_set = 0;
- struct sockaddr_in *laddr = (struct sockaddr_in *)&cm_id->m_local_addr;
- struct sockaddr_in *raddr = (struct sockaddr_in *)&cm_id->m_remote_addr;
-
- if (cm_id->remote_addr.ss_family != AF_INET)
- return -ENOSYS;
- ibqp = nes_get_qp(cm_id->device, conn_param->qpn);
- if (!ibqp)
- return -EINVAL;
- nesqp = to_nesqp(ibqp);
- if (!nesqp)
- return -EINVAL;
- nesvnic = to_nesvnic(nesqp->ibqp.device);
- if (!nesvnic)
- return -EINVAL;
- nesdev = nesvnic->nesdev;
- if (!nesdev)
- return -EINVAL;
-
- if (!laddr->sin_port || !raddr->sin_port)
- return -EINVAL;
-
- nes_debug(NES_DBG_CM, "QP%u, current IP = 0x%08X, Destination IP = "
- "0x%08X:0x%04X, local = 0x%08X:0x%04X.\n", nesqp->hwqp.qp_id,
- ntohl(nesvnic->local_ipaddr), ntohl(raddr->sin_addr.s_addr),
- ntohs(raddr->sin_port), ntohl(laddr->sin_addr.s_addr),
- ntohs(laddr->sin_port));
-
- atomic_inc(&cm_connects);
- nesqp->active_conn = 1;
-
- /* cache the cm_id in the qp */
- nesqp->cm_id = cm_id;
- cm_id->provider_data = nesqp;
- nesqp->private_data_len = conn_param->private_data_len;
-
- nes_debug(NES_DBG_CM, "requested ord = 0x%08X.\n", (u32)conn_param->ord);
- nes_debug(NES_DBG_CM, "mpa private data len =%u\n",
- conn_param->private_data_len);
-
- /* set up the connection params for the node */
- cm_info.loc_addr = ntohl(laddr->sin_addr.s_addr);
- cm_info.loc_port = ntohs(laddr->sin_port);
- cm_info.rem_addr = ntohl(raddr->sin_addr.s_addr);
- cm_info.rem_port = ntohs(raddr->sin_port);
- cm_info.cm_id = cm_id;
- cm_info.conn_type = NES_CM_IWARP_CONN_TYPE;
-
- if (laddr->sin_addr.s_addr != raddr->sin_addr.s_addr) {
- nes_manage_apbvt(nesvnic, cm_info.loc_port,
- PCI_FUNC(nesdev->pcidev->devfn),
- NES_MANAGE_APBVT_ADD);
- apbvt_set = 1;
- }
-
- cm_id->add_ref(cm_id);
-
- /* create a connect CM node connection */
- cm_node = g_cm_core->api->connect(g_cm_core, nesvnic,
- conn_param->private_data_len, (void *)conn_param->private_data,
- &cm_info);
- if (!cm_node) {
- if (apbvt_set)
- nes_manage_apbvt(nesvnic, cm_info.loc_port,
- PCI_FUNC(nesdev->pcidev->devfn),
- NES_MANAGE_APBVT_DEL);
-
- nes_debug(NES_DBG_NLMSG, "Delete loc_port = %04X\n",
- cm_info.loc_port);
- cm_id->rem_ref(cm_id);
- return -ENOMEM;
- }
-
- record_ird_ord(cm_node, (u16)conn_param->ird, (u16)conn_param->ord);
- if (cm_node->send_rdma0_op == SEND_RDMA_READ_ZERO &&
- cm_node->ord_size == 0)
- cm_node->ord_size = 1;
-
- cm_node->apbvt_set = apbvt_set;
- cm_node->tos = cm_id->tos;
- nesqp->cm_node = cm_node;
- cm_node->nesqp = nesqp;
- nes_add_ref(&nesqp->ibqp);
-
- return 0;
-}
-
-
-/**
- * nes_create_listen
- */
-int nes_create_listen(struct iw_cm_id *cm_id, int backlog)
-{
- struct nes_vnic *nesvnic;
- struct nes_cm_listener *cm_node;
- struct nes_cm_info cm_info;
- int err;
- struct sockaddr_in *laddr = (struct sockaddr_in *)&cm_id->m_local_addr;
-
- nes_debug(NES_DBG_CM, "cm_id = %p, local port = 0x%04X.\n",
- cm_id, ntohs(laddr->sin_port));
-
- if (cm_id->m_local_addr.ss_family != AF_INET)
- return -ENOSYS;
- nesvnic = to_nesvnic(cm_id->device);
- if (!nesvnic)
- return -EINVAL;
-
- nes_debug(NES_DBG_CM, "nesvnic=%p, netdev=%p, %s\n",
- nesvnic, nesvnic->netdev, nesvnic->netdev->name);
-
- nes_debug(NES_DBG_CM, "nesvnic->local_ipaddr=0x%08x, sin_addr.s_addr=0x%08x\n",
- nesvnic->local_ipaddr, laddr->sin_addr.s_addr);
-
- /* setup listen params in our api call struct */
- cm_info.loc_addr = ntohl(nesvnic->local_ipaddr);
- cm_info.loc_port = ntohs(laddr->sin_port);
- cm_info.backlog = backlog;
- cm_info.cm_id = cm_id;
-
- cm_info.conn_type = NES_CM_IWARP_CONN_TYPE;
-
- cm_node = g_cm_core->api->listen(g_cm_core, nesvnic, &cm_info);
- if (!cm_node) {
- printk(KERN_ERR "%s[%u] Error returned from listen API call\n",
- __func__, __LINE__);
- return -ENOMEM;
- }
-
- cm_id->provider_data = cm_node;
- cm_node->tos = cm_id->tos;
-
- if (!cm_node->reused_node) {
- err = nes_manage_apbvt(nesvnic, cm_node->loc_port,
- PCI_FUNC(nesvnic->nesdev->pcidev->devfn),
- NES_MANAGE_APBVT_ADD);
- if (err) {
- printk(KERN_ERR "nes_manage_apbvt call returned %d.\n",
- err);
- g_cm_core->api->stop_listener(g_cm_core, (void *)cm_node);
- return err;
- }
- atomic_inc(&cm_listens_created);
- }
-
- cm_id->add_ref(cm_id);
- cm_id->provider_data = (void *)cm_node;
-
-
- return 0;
-}
-
-
-/**
- * nes_destroy_listen
- */
-int nes_destroy_listen(struct iw_cm_id *cm_id)
-{
- if (cm_id->provider_data)
- g_cm_core->api->stop_listener(g_cm_core, cm_id->provider_data);
- else
- nes_debug(NES_DBG_CM, "cm_id->provider_data was NULL\n");
-
- cm_id->rem_ref(cm_id);
-
- return 0;
-}
-
-
-/**
- * nes_cm_recv
- */
-int nes_cm_recv(struct sk_buff *skb, struct net_device *netdevice)
-{
- int rc = 0;
-
- cm_packets_received++;
- if ((g_cm_core) && (g_cm_core->api))
- rc = g_cm_core->api->recv_pkt(g_cm_core, netdev_priv(netdevice), skb);
- else
- nes_debug(NES_DBG_CM, "Unable to process packet for CM,"
- " cm is not setup properly.\n");
-
- return rc;
-}
-
-
-/**
- * nes_cm_start
- * Start and init a cm core module
- */
-int nes_cm_start(void)
-{
- nes_debug(NES_DBG_CM, "\n");
- /* create the primary CM core, pass this handle to subsequent core inits */
- g_cm_core = nes_cm_alloc_core();
- if (g_cm_core)
- return 0;
- else
- return -ENOMEM;
-}
-
-
-/**
- * nes_cm_stop
- * stop and dealloc all cm core instances
- */
-int nes_cm_stop(void)
-{
- g_cm_core->api->destroy_cm_core(g_cm_core);
- return 0;
-}
-
-
-/**
- * cm_event_connected
- * handle a connected event, setup QPs and HW
- */
-static void cm_event_connected(struct nes_cm_event *event)
-{
- struct nes_qp *nesqp;
- struct nes_vnic *nesvnic;
- struct nes_device *nesdev;
- struct nes_cm_node *cm_node;
- struct nes_adapter *nesadapter;
- struct ib_qp_attr attr;
- struct iw_cm_id *cm_id;
- struct iw_cm_event cm_event;
- struct nes_v4_quad nes_quad;
- u32 crc_value;
- int ret;
- struct sockaddr_in *laddr;
- struct sockaddr_in *raddr;
- struct sockaddr_in *cm_event_laddr;
-
- /* get all our handles */
- cm_node = event->cm_node;
- cm_id = cm_node->cm_id;
- nes_debug(NES_DBG_CM, "cm_event_connected - %p - cm_id = %p\n", cm_node, cm_id);
- nesqp = (struct nes_qp *)cm_id->provider_data;
- nesvnic = to_nesvnic(nesqp->ibqp.device);
- nesdev = nesvnic->nesdev;
- nesadapter = nesdev->nesadapter;
- laddr = (struct sockaddr_in *)&cm_id->m_local_addr;
- raddr = (struct sockaddr_in *)&cm_id->m_remote_addr;
- cm_event_laddr = (struct sockaddr_in *)&cm_event.local_addr;
-
- if (nesqp->destroyed)
- return;
- atomic_inc(&cm_connecteds);
- nes_debug(NES_DBG_CM, "QP%u attempting to connect to 0x%08X:0x%04X on"
- " local port 0x%04X. jiffies = %lu.\n",
- nesqp->hwqp.qp_id, ntohl(raddr->sin_addr.s_addr),
- ntohs(raddr->sin_port), ntohs(laddr->sin_port), jiffies);
-
- nes_cm_init_tsa_conn(nesqp, cm_node);
-
- /* set the QP tsa context */
- nesqp->nesqp_context->tcpPorts[0] =
- cpu_to_le16(cm_node->loc_port);
- nesqp->nesqp_context->tcpPorts[1] =
- cpu_to_le16(cm_node->rem_port);
- nesqp->nesqp_context->ip0 = cpu_to_le32(cm_node->rem_addr);
-
- nesqp->nesqp_context->misc2 |= cpu_to_le32(
- (u32)PCI_FUNC(nesdev->pcidev->devfn) <<
- NES_QPCONTEXT_MISC2_SRC_IP_SHIFT);
- nesqp->nesqp_context->arp_index_vlan |= cpu_to_le32(
- nes_arp_table(nesdev,
- le32_to_cpu(nesqp->nesqp_context->ip0),
- NULL, NES_ARP_RESOLVE) << 16);
- nesqp->nesqp_context->ts_val_delta = cpu_to_le32(
- jiffies - nes_read_indexed(nesdev, NES_IDX_TCP_NOW));
- nesqp->nesqp_context->ird_index = cpu_to_le32(nesqp->hwqp.qp_id);
- nesqp->nesqp_context->ird_ord_sizes |=
- cpu_to_le32((u32)1 <<
- NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT);
- nesqp->nesqp_context->ird_ord_sizes |=
- cpu_to_le32((u32)cm_node->ord_size);
-
- /* Adjust tail for not having a LSMM */
- /*nesqp->hwqp.sq_tail = 1;*/
-
- build_rdma0_msg(cm_node, &nesqp);
-
- nes_write32(nesdev->regs + NES_WQE_ALLOC,
- (1 << 24) | 0x00800000 | nesqp->hwqp.qp_id);
-
- memset(&nes_quad, 0, sizeof(nes_quad));
-
- nes_quad.DstIpAdrIndex =
- cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24);
- nes_quad.SrcIpadr = htonl(cm_node->rem_addr);
- nes_quad.TcpPorts[0] = htons(cm_node->rem_port);
- nes_quad.TcpPorts[1] = htons(cm_node->loc_port);
-
- /* Produce hash key */
- crc_value = get_crc_value(&nes_quad);
- nesqp->hte_index = cpu_to_be32(crc_value ^ 0xffffffff);
- nes_debug(NES_DBG_CM, "HTE Index = 0x%08X, After CRC = 0x%08X\n",
- nesqp->hte_index, nesqp->hte_index & nesadapter->hte_index_mask);
-
- nesqp->hte_index &= nesadapter->hte_index_mask;
- nesqp->nesqp_context->hte_index = cpu_to_le32(nesqp->hte_index);
-
- nesqp->ietf_frame = &cm_node->mpa_frame;
- nesqp->private_data_len = (u8)cm_node->mpa_frame_size;
- cm_node->cm_core->api->accelerated(cm_node->cm_core, cm_node);
-
- /* notify OF layer we successfully created the requested connection */
- cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
- cm_event.status = 0;
- cm_event.provider_data = cm_id->provider_data;
- cm_event_laddr->sin_family = AF_INET;
- cm_event_laddr->sin_port = laddr->sin_port;
- cm_event.remote_addr = cm_id->m_remote_addr;
-
- cm_event.private_data = (void *)event->cm_node->mpa_frame_buf;
- cm_event.private_data_len = (u8)event->cm_node->mpa_frame_size;
- cm_event.ird = cm_node->ird_size;
- cm_event.ord = cm_node->ord_size;
-
- cm_event_laddr->sin_addr.s_addr = htonl(event->cm_info.loc_addr);
- ret = cm_id->event_handler(cm_id, &cm_event);
- nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);
-
- if (ret)
- printk(KERN_ERR "%s[%u] OFA CM event_handler returned, "
- "ret=%d\n", __func__, __LINE__, ret);
- attr.qp_state = IB_QPS_RTS;
- nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL);
-
- nes_debug(NES_DBG_CM, "Exiting connect thread for QP%u. jiffies = "
- "%lu\n", nesqp->hwqp.qp_id, jiffies);
-
- return;
-}
-
-
-/**
- * cm_event_connect_error
- */
-static void cm_event_connect_error(struct nes_cm_event *event)
-{
- struct nes_qp *nesqp;
- struct iw_cm_id *cm_id;
- struct iw_cm_event cm_event;
- /* struct nes_cm_info cm_info; */
- int ret;
-
- if (!event->cm_node)
- return;
-
- cm_id = event->cm_node->cm_id;
- if (!cm_id)
- return;
-
- nes_debug(NES_DBG_CM, "cm_node=%p, cm_id=%p\n", event->cm_node, cm_id);
- nesqp = cm_id->provider_data;
-
- if (!nesqp)
- return;
-
- /* notify OF layer about this connection error event */
- /* cm_id->rem_ref(cm_id); */
- nesqp->cm_id = NULL;
- cm_id->provider_data = NULL;
- cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
- cm_event.status = -ECONNRESET;
- cm_event.provider_data = cm_id->provider_data;
- cm_event.local_addr = cm_id->m_local_addr;
- cm_event.remote_addr = cm_id->m_remote_addr;
- cm_event.private_data = NULL;
- cm_event.private_data_len = 0;
-
-#ifdef CONFIG_INFINIBAND_NES_DEBUG
- {
- struct sockaddr_in *cm_event_laddr = (struct sockaddr_in *)
- &cm_event.local_addr;
- struct sockaddr_in *cm_event_raddr = (struct sockaddr_in *)
- &cm_event.remote_addr;
- nes_debug(NES_DBG_CM, "call CM_EVENT REJECTED, local_addr=%08x, remote_addr=%08x\n",
- cm_event_laddr->sin_addr.s_addr, cm_event_raddr->sin_addr.s_addr);
- }
-#endif
-
- ret = cm_id->event_handler(cm_id, &cm_event);
- nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);
- if (ret)
- printk(KERN_ERR "%s[%u] OFA CM event_handler returned, "
- "ret=%d\n", __func__, __LINE__, ret);
- cm_id->rem_ref(cm_id);
-
- rem_ref_cm_node(event->cm_node->cm_core, event->cm_node);
- return;
-}
-
-
-/**
- * cm_event_reset
- */
-static void cm_event_reset(struct nes_cm_event *event)
-{
- struct nes_qp *nesqp;
- struct iw_cm_id *cm_id;
- struct iw_cm_event cm_event;
- /* struct nes_cm_info cm_info; */
- int ret;
-
- if (!event->cm_node)
- return;
-
- if (!event->cm_node->cm_id)
- return;
-
- cm_id = event->cm_node->cm_id;
-
- nes_debug(NES_DBG_CM, "%p - cm_id = %p\n", event->cm_node, cm_id);
- nesqp = cm_id->provider_data;
- if (!nesqp)
- return;
-
- nesqp->cm_id = NULL;
- /* cm_id->provider_data = NULL; */
- cm_event.event = IW_CM_EVENT_DISCONNECT;
- cm_event.status = -ECONNRESET;
- cm_event.provider_data = cm_id->provider_data;
- cm_event.local_addr = cm_id->m_local_addr;
- cm_event.remote_addr = cm_id->m_remote_addr;
- cm_event.private_data = NULL;
- cm_event.private_data_len = 0;
-
- cm_id->add_ref(cm_id);
- ret = cm_id->event_handler(cm_id, &cm_event);
- atomic_inc(&cm_closes);
- cm_event.event = IW_CM_EVENT_CLOSE;
- cm_event.status = 0;
- cm_event.provider_data = cm_id->provider_data;
- cm_event.local_addr = cm_id->m_local_addr;
- cm_event.remote_addr = cm_id->m_remote_addr;
- cm_event.private_data = NULL;
- cm_event.private_data_len = 0;
- nes_debug(NES_DBG_CM, "NODE %p Generating CLOSE\n", event->cm_node);
- ret = cm_id->event_handler(cm_id, &cm_event);
-
- nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);
-
-
- /* notify OF layer about this connection error event */
- cm_id->rem_ref(cm_id);
-
- return;
-}
-
-
-/**
- * cm_event_mpa_req
- */
-static void cm_event_mpa_req(struct nes_cm_event *event)
-{
- struct iw_cm_id *cm_id;
- struct iw_cm_event cm_event;
- int ret;
- struct nes_cm_node *cm_node;
- struct sockaddr_in *cm_event_laddr = (struct sockaddr_in *)
- &cm_event.local_addr;
- struct sockaddr_in *cm_event_raddr = (struct sockaddr_in *)
- &cm_event.remote_addr;
-
- cm_node = event->cm_node;
- if (!cm_node)
- return;
- cm_id = cm_node->cm_id;
-
- atomic_inc(&cm_connect_reqs);
- nes_debug(NES_DBG_CM, "cm_node = %p - cm_id = %p, jiffies = %lu\n",
- cm_node, cm_id, jiffies);
-
- cm_event.event = IW_CM_EVENT_CONNECT_REQUEST;
- cm_event.status = 0;
- cm_event.provider_data = (void *)cm_node;
-
- cm_event_laddr->sin_family = AF_INET;
- cm_event_laddr->sin_port = htons(event->cm_info.loc_port);
- cm_event_laddr->sin_addr.s_addr = htonl(event->cm_info.loc_addr);
-
- cm_event_raddr->sin_family = AF_INET;
- cm_event_raddr->sin_port = htons(event->cm_info.rem_port);
- cm_event_raddr->sin_addr.s_addr = htonl(event->cm_info.rem_addr);
- cm_event.private_data = cm_node->mpa_frame_buf;
- cm_event.private_data_len = (u8)cm_node->mpa_frame_size;
- if (cm_node->mpa_frame_rev == IETF_MPA_V1) {
- cm_event.ird = NES_MAX_IRD;
- cm_event.ord = NES_MAX_ORD;
- } else {
- cm_event.ird = cm_node->ird_size;
- cm_event.ord = cm_node->ord_size;
- }
-
- ret = cm_id->event_handler(cm_id, &cm_event);
- if (ret)
- printk(KERN_ERR "%s[%u] OFA CM event_handler returned, ret=%d\n",
- __func__, __LINE__, ret);
- return;
-}
-
-
-static void cm_event_mpa_reject(struct nes_cm_event *event)
-{
- struct iw_cm_id *cm_id;
- struct iw_cm_event cm_event;
- struct nes_cm_node *cm_node;
- int ret;
- struct sockaddr_in *cm_event_laddr = (struct sockaddr_in *)
- &cm_event.local_addr;
- struct sockaddr_in *cm_event_raddr = (struct sockaddr_in *)
- &cm_event.remote_addr;
-
- cm_node = event->cm_node;
- if (!cm_node)
- return;
- cm_id = cm_node->cm_id;
-
- atomic_inc(&cm_connect_reqs);
- nes_debug(NES_DBG_CM, "cm_node = %p - cm_id = %p, jiffies = %lu\n",
- cm_node, cm_id, jiffies);
-
- cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
- cm_event.status = -ECONNREFUSED;
- cm_event.provider_data = cm_id->provider_data;
-
- cm_event_laddr->sin_family = AF_INET;
- cm_event_laddr->sin_port = htons(event->cm_info.loc_port);
- cm_event_laddr->sin_addr.s_addr = htonl(event->cm_info.loc_addr);
-
- cm_event_raddr->sin_family = AF_INET;
- cm_event_raddr->sin_port = htons(event->cm_info.rem_port);
- cm_event_raddr->sin_addr.s_addr = htonl(event->cm_info.rem_addr);
-
- cm_event.private_data = cm_node->mpa_frame_buf;
- cm_event.private_data_len = (u8)cm_node->mpa_frame_size;
-
- nes_debug(NES_DBG_CM, "call CM_EVENT_MPA_REJECTED, local_addr=%08x, "
- "remove_addr=%08x\n",
- cm_event_laddr->sin_addr.s_addr,
- cm_event_raddr->sin_addr.s_addr);
-
- ret = cm_id->event_handler(cm_id, &cm_event);
- if (ret)
- printk(KERN_ERR "%s[%u] OFA CM event_handler returned, ret=%d\n",
- __func__, __LINE__, ret);
-
- return;
-}
-
-
-static void nes_cm_event_handler(struct work_struct *);
-
-/**
- * nes_cm_post_event
- * post an event to the cm event handler
- */
-static int nes_cm_post_event(struct nes_cm_event *event)
-{
- atomic_inc(&event->cm_node->cm_core->events_posted);
- add_ref_cm_node(event->cm_node);
- event->cm_info.cm_id->add_ref(event->cm_info.cm_id);
- INIT_WORK(&event->event_work, nes_cm_event_handler);
- nes_debug(NES_DBG_CM, "cm_node=%p queue_work, event=%p\n",
- event->cm_node, event);
-
- queue_work(event->cm_node->cm_core->event_wq, &event->event_work);
-
- nes_debug(NES_DBG_CM, "Exit\n");
- return 0;
-}
-
-
-/**
- * nes_cm_event_handler
- * worker function to handle cm events
- * will free instance of nes_cm_event
- */
-static void nes_cm_event_handler(struct work_struct *work)
-{
- struct nes_cm_event *event = container_of(work, struct nes_cm_event,
- event_work);
- struct nes_cm_core *cm_core;
-
- if ((!event) || (!event->cm_node) || (!event->cm_node->cm_core))
- return;
-
- cm_core = event->cm_node->cm_core;
- nes_debug(NES_DBG_CM, "event=%p, event->type=%u, events posted=%u\n",
- event, event->type, atomic_read(&cm_core->events_posted));
-
- switch (event->type) {
- case NES_CM_EVENT_MPA_REQ:
- cm_event_mpa_req(event);
- nes_debug(NES_DBG_CM, "cm_node=%p CM Event: MPA REQUEST\n",
- event->cm_node);
- break;
- case NES_CM_EVENT_RESET:
- nes_debug(NES_DBG_CM, "cm_node = %p CM Event: RESET\n",
- event->cm_node);
- cm_event_reset(event);
- break;
- case NES_CM_EVENT_CONNECTED:
- if ((!event->cm_node->cm_id) ||
- (event->cm_node->state != NES_CM_STATE_TSA))
- break;
- cm_event_connected(event);
- nes_debug(NES_DBG_CM, "CM Event: CONNECTED\n");
- break;
- case NES_CM_EVENT_MPA_REJECT:
- if ((!event->cm_node->cm_id) ||
- (event->cm_node->state == NES_CM_STATE_TSA))
- break;
- cm_event_mpa_reject(event);
- nes_debug(NES_DBG_CM, "CM Event: REJECT\n");
- break;
-
- case NES_CM_EVENT_ABORTED:
- if ((!event->cm_node->cm_id) ||
- (event->cm_node->state == NES_CM_STATE_TSA))
- break;
- cm_event_connect_error(event);
- nes_debug(NES_DBG_CM, "CM Event: ABORTED\n");
- break;
- case NES_CM_EVENT_DROPPED_PKT:
- nes_debug(NES_DBG_CM, "CM Event: DROPPED PKT\n");
- break;
- default:
- nes_debug(NES_DBG_CM, "CM Event: UNKNOWN EVENT TYPE\n");
- break;
- }
-
- atomic_dec(&cm_core->events_posted);
- event->cm_info.cm_id->rem_ref(event->cm_info.cm_id);
- rem_ref_cm_node(cm_core, event->cm_node);
- kfree(event);
-
- return;
-}
diff --git a/drivers/infiniband/hw/nes/nes_cm.h b/drivers/infiniband/hw/nes/nes_cm.h
deleted file mode 100644
index b9cc02b4e8d5..000000000000
--- a/drivers/infiniband/hw/nes/nes_cm.h
+++ /dev/null
@@ -1,470 +0,0 @@
-/*
- * Copyright (c) 2006 - 2014 Intel Corporation. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-#ifndef NES_CM_H
-#define NES_CM_H
-
-#define QUEUE_EVENTS
-
-#define NES_MANAGE_APBVT_DEL 0
-#define NES_MANAGE_APBVT_ADD 1
-
-#define NES_MPA_REQUEST_ACCEPT 1
-#define NES_MPA_REQUEST_REJECT 2
-
-/* IETF MPA -- defines, enums, structs */
-#define IEFT_MPA_KEY_REQ "MPA ID Req Frame"
-#define IEFT_MPA_KEY_REP "MPA ID Rep Frame"
-#define IETF_MPA_KEY_SIZE 16
-#define IETF_MPA_VERSION 1
-#define IETF_MAX_PRIV_DATA_LEN 512
-#define IETF_MPA_FRAME_SIZE 20
-#define IETF_RTR_MSG_SIZE 4
-#define IETF_MPA_V2_FLAG 0x10
-
-/* IETF RTR MSG Fields */
-#define IETF_PEER_TO_PEER 0x8000
-#define IETF_FLPDU_ZERO_LEN 0x4000
-#define IETF_RDMA0_WRITE 0x8000
-#define IETF_RDMA0_READ 0x4000
-#define IETF_NO_IRD_ORD 0x3FFF
-#define NES_MAX_IRD 0x40
-#define NES_MAX_ORD 0x7F
-
-enum ietf_mpa_flags {
- IETF_MPA_FLAGS_MARKERS = 0x80, /* receive Markers */
- IETF_MPA_FLAGS_CRC = 0x40, /* receive Markers */
- IETF_MPA_FLAGS_REJECT = 0x20, /* Reject */
-};
-
-struct ietf_mpa_v1 {
- u8 key[IETF_MPA_KEY_SIZE];
- u8 flags;
- u8 rev;
- __be16 priv_data_len;
- u8 priv_data[0];
-};
-
-#define ietf_mpa_req_resp_frame ietf_mpa_frame
-
-struct ietf_rtr_msg {
- __be16 ctrl_ird;
- __be16 ctrl_ord;
-};
-
-struct ietf_mpa_v2 {
- u8 key[IETF_MPA_KEY_SIZE];
- u8 flags;
- u8 rev;
- __be16 priv_data_len;
- struct ietf_rtr_msg rtr_msg;
- u8 priv_data[0];
-};
-
-struct nes_v4_quad {
- u32 rsvd0;
- __le32 DstIpAdrIndex; /* Only most significant 5 bits are valid */
- __be32 SrcIpadr;
- __be16 TcpPorts[2]; /* src is low, dest is high */
-};
-
-struct nes_cm_node;
-enum nes_timer_type {
- NES_TIMER_TYPE_SEND,
- NES_TIMER_TYPE_RECV,
- NES_TIMER_NODE_CLEANUP,
- NES_TIMER_TYPE_CLOSE,
-};
-
-#define NES_PASSIVE_STATE_INDICATED 0
-#define NES_DO_NOT_SEND_RESET_EVENT 1
-#define NES_SEND_RESET_EVENT 2
-
-#define MAX_NES_IFS 4
-
-#define SET_ACK 1
-#define SET_SYN 2
-#define SET_FIN 4
-#define SET_RST 8
-
-#define TCP_OPTIONS_PADDING 3
-
-struct option_base {
- u8 optionnum;
- u8 length;
-};
-
-enum option_numbers {
- OPTION_NUMBER_END,
- OPTION_NUMBER_NONE,
- OPTION_NUMBER_MSS,
- OPTION_NUMBER_WINDOW_SCALE,
- OPTION_NUMBER_SACK_PERM,
- OPTION_NUMBER_SACK,
- OPTION_NUMBER_WRITE0 = 0xbc
-};
-
-struct option_mss {
- u8 optionnum;
- u8 length;
- __be16 mss;
-};
-
-struct option_windowscale {
- u8 optionnum;
- u8 length;
- u8 shiftcount;
-};
-
-union all_known_options {
- char as_end;
- struct option_base as_base;
- struct option_mss as_mss;
- struct option_windowscale as_windowscale;
-};
-
-struct nes_timer_entry {
- struct list_head list;
- unsigned long timetosend; /* jiffies */
- struct sk_buff *skb;
- u32 type;
- u32 retrycount;
- u32 retranscount;
- u32 context;
- u32 seq_num;
- u32 send_retrans;
- int close_when_complete;
- struct net_device *netdev;
-};
-
-#define NES_DEFAULT_RETRYS 64
-#define NES_DEFAULT_RETRANS 8
-#ifdef CONFIG_INFINIBAND_NES_DEBUG
-#define NES_RETRY_TIMEOUT (1000*HZ/1000)
-#else
-#define NES_RETRY_TIMEOUT (3000*HZ/1000)
-#endif
-#define NES_SHORT_TIME (10)
-#define NES_LONG_TIME (2000*HZ/1000)
-#define NES_MAX_TIMEOUT ((unsigned long) (12*HZ))
-
-#define NES_CM_HASHTABLE_SIZE 1024
-#define NES_CM_TCP_TIMER_INTERVAL 3000
-#define NES_CM_DEFAULT_MTU 1540
-#define NES_CM_DEFAULT_FRAME_CNT 10
-#define NES_CM_THREAD_STACK_SIZE 256
-#define NES_CM_DEFAULT_RCV_WND 64240 // before we know that window scaling is allowed
-#define NES_CM_DEFAULT_RCV_WND_SCALED 256960 // after we know that window scaling is allowed
-#define NES_CM_DEFAULT_RCV_WND_SCALE 2
-#define NES_CM_DEFAULT_FREE_PKTS 0x000A
-#define NES_CM_FREE_PKT_LO_WATERMARK 2
-
-#define NES_CM_DEFAULT_MSS 536
-
-#define NES_CM_DEF_SEQ 0x159bf75f
-#define NES_CM_DEF_LOCAL_ID 0x3b47
-
-#define NES_CM_DEF_SEQ2 0x18ed5740
-#define NES_CM_DEF_LOCAL_ID2 0xb807
-#define MAX_CM_BUFFER (IETF_MPA_FRAME_SIZE + IETF_RTR_MSG_SIZE + IETF_MAX_PRIV_DATA_LEN)
-
-typedef u32 nes_addr_t;
-
-#define nes_cm_tsa_context nes_qp_context
-
-struct nes_qp;
-
-/* cm node transition states */
-enum nes_cm_node_state {
- NES_CM_STATE_UNKNOWN,
- NES_CM_STATE_INITED,
- NES_CM_STATE_LISTENING,
- NES_CM_STATE_SYN_RCVD,
- NES_CM_STATE_SYN_SENT,
- NES_CM_STATE_ONE_SIDE_ESTABLISHED,
- NES_CM_STATE_ESTABLISHED,
- NES_CM_STATE_ACCEPTING,
- NES_CM_STATE_MPAREQ_SENT,
- NES_CM_STATE_MPAREQ_RCVD,
- NES_CM_STATE_MPAREJ_RCVD,
- NES_CM_STATE_TSA,
- NES_CM_STATE_FIN_WAIT1,
- NES_CM_STATE_FIN_WAIT2,
- NES_CM_STATE_CLOSE_WAIT,
- NES_CM_STATE_TIME_WAIT,
- NES_CM_STATE_LAST_ACK,
- NES_CM_STATE_CLOSING,
- NES_CM_STATE_LISTENER_DESTROYED,
- NES_CM_STATE_CLOSED
-};
-
-enum mpa_frame_version {
- IETF_MPA_V1 = 1,
- IETF_MPA_V2 = 2
-};
-
-enum mpa_frame_key {
- MPA_KEY_REQUEST,
- MPA_KEY_REPLY
-};
-
-enum send_rdma0 {
- SEND_RDMA_READ_ZERO = 1,
- SEND_RDMA_WRITE_ZERO = 2
-};
-
-enum nes_tcpip_pkt_type {
- NES_PKT_TYPE_UNKNOWN,
- NES_PKT_TYPE_SYN,
- NES_PKT_TYPE_SYNACK,
- NES_PKT_TYPE_ACK,
- NES_PKT_TYPE_FIN,
- NES_PKT_TYPE_RST
-};
-
-
-/* type of nes connection */
-enum nes_cm_conn_type {
- NES_CM_IWARP_CONN_TYPE,
-};
-
-/* CM context params */
-struct nes_cm_tcp_context {
- u8 client;
-
- u32 loc_seq_num;
- u32 loc_ack_num;
- u32 rem_ack_num;
- u32 rcv_nxt;
-
- u32 loc_id;
- u32 rem_id;
-
- u32 snd_wnd;
- u32 max_snd_wnd;
-
- u32 rcv_wnd;
- u32 mss;
- u8 snd_wscale;
- u8 rcv_wscale;
-
- struct nes_cm_tsa_context tsa_cntxt;
-};
-
-
-enum nes_cm_listener_state {
- NES_CM_LISTENER_PASSIVE_STATE = 1,
- NES_CM_LISTENER_ACTIVE_STATE = 2,
- NES_CM_LISTENER_EITHER_STATE = 3
-};
-
-struct nes_cm_listener {
- struct list_head list;
- struct nes_cm_core *cm_core;
- u8 loc_mac[ETH_ALEN];
- nes_addr_t loc_addr;
- u16 loc_port;
- struct iw_cm_id *cm_id;
- enum nes_cm_conn_type conn_type;
- atomic_t ref_count;
- struct nes_vnic *nesvnic;
- atomic_t pend_accepts_cnt;
- int backlog;
- enum nes_cm_listener_state listener_state;
- u32 reused_node;
- u8 tos;
-};
-
-/* per connection node and node state information */
-struct nes_cm_node {
- nes_addr_t loc_addr, rem_addr;
- u16 loc_port, rem_port;
-
- u8 loc_mac[ETH_ALEN];
- u8 rem_mac[ETH_ALEN];
-
- enum nes_cm_node_state state;
- struct nes_cm_tcp_context tcp_cntxt;
- struct nes_cm_core *cm_core;
- struct sk_buff_head resend_list;
- atomic_t ref_count;
- struct net_device *netdev;
-
- struct nes_cm_node *loopbackpartner;
-
- struct nes_timer_entry *send_entry;
- struct nes_timer_entry *recv_entry;
- spinlock_t retrans_list_lock;
- enum send_rdma0 send_rdma0_op;
-
- union {
- struct ietf_mpa_v1 mpa_frame;
- struct ietf_mpa_v2 mpa_v2_frame;
- u8 mpa_frame_buf[MAX_CM_BUFFER];
- };
- enum mpa_frame_version mpa_frame_rev;
- u16 ird_size;
- u16 ord_size;
- u16 mpav2_ird_ord;
-
- u16 mpa_frame_size;
- struct iw_cm_id *cm_id;
- struct list_head list;
- bool accelerated;
- struct nes_cm_listener *listener;
- enum nes_cm_conn_type conn_type;
- struct nes_vnic *nesvnic;
- int apbvt_set;
- int accept_pend;
- struct list_head timer_entry;
- struct list_head reset_entry;
- struct nes_qp *nesqp;
- atomic_t passive_state;
- u8 tos;
-};
-
-/* structure for client or CM to fill when making CM api calls. */
-/* - only need to set relevant data, based on op. */
-struct nes_cm_info {
- union {
- struct iw_cm_id *cm_id;
- struct net_device *netdev;
- };
-
- u16 loc_port;
- u16 rem_port;
- nes_addr_t loc_addr;
- nes_addr_t rem_addr;
- enum nes_cm_conn_type conn_type;
- int backlog;
-};
-
-/* CM event codes */
-enum nes_cm_event_type {
- NES_CM_EVENT_UNKNOWN,
- NES_CM_EVENT_ESTABLISHED,
- NES_CM_EVENT_MPA_REQ,
- NES_CM_EVENT_MPA_CONNECT,
- NES_CM_EVENT_MPA_ACCEPT,
- NES_CM_EVENT_MPA_REJECT,
- NES_CM_EVENT_MPA_ESTABLISHED,
- NES_CM_EVENT_CONNECTED,
- NES_CM_EVENT_CLOSED,
- NES_CM_EVENT_RESET,
- NES_CM_EVENT_DROPPED_PKT,
- NES_CM_EVENT_CLOSE_IMMED,
- NES_CM_EVENT_CLOSE_HARD,
- NES_CM_EVENT_CLOSE_CLEAN,
- NES_CM_EVENT_ABORTED,
- NES_CM_EVENT_SEND_FIRST
-};
-
-/* event to post to CM event handler */
-struct nes_cm_event {
- enum nes_cm_event_type type;
-
- struct nes_cm_info cm_info;
- struct work_struct event_work;
- struct nes_cm_node *cm_node;
-};
-
-struct nes_cm_core {
- enum nes_cm_node_state state;
-
- atomic_t listen_node_cnt;
- struct nes_cm_node listen_list;
- spinlock_t listen_list_lock;
-
- u32 mtu;
- u32 free_tx_pkt_max;
- u32 rx_pkt_posted;
- atomic_t ht_node_cnt;
- struct list_head connected_nodes;
- /* struct list_head hashtable[NES_CM_HASHTABLE_SIZE]; */
- spinlock_t ht_lock;
-
- struct timer_list tcp_timer;
-
- const struct nes_cm_ops *api;
-
- int (*post_event)(struct nes_cm_event *event);
- atomic_t events_posted;
- struct workqueue_struct *event_wq;
- struct workqueue_struct *disconn_wq;
-
- atomic_t node_cnt;
- u64 aborted_connects;
- u32 options;
-
- struct nes_cm_node *current_listen_node;
-};
-
-
-#define NES_CM_SET_PKT_SIZE (1 << 1)
-#define NES_CM_SET_FREE_PKT_Q_SIZE (1 << 2)
-
-/* CM ops/API for client interface */
-struct nes_cm_ops {
- int (*accelerated)(struct nes_cm_core *, struct nes_cm_node *);
- struct nes_cm_listener * (*listen)(struct nes_cm_core *, struct nes_vnic *,
- struct nes_cm_info *);
- int (*stop_listener)(struct nes_cm_core *, struct nes_cm_listener *);
- struct nes_cm_node * (*connect)(struct nes_cm_core *,
- struct nes_vnic *, u16, void *,
- struct nes_cm_info *);
- int (*close)(struct nes_cm_core *, struct nes_cm_node *);
- int (*accept)(struct nes_cm_core *, struct nes_cm_node *);
- int (*reject)(struct nes_cm_core *, struct nes_cm_node *);
- int (*recv_pkt)(struct nes_cm_core *, struct nes_vnic *,
- struct sk_buff *);
- int (*destroy_cm_core)(struct nes_cm_core *);
- int (*get)(struct nes_cm_core *);
- int (*set)(struct nes_cm_core *, u32, u32);
-};
-
-int schedule_nes_timer(struct nes_cm_node *, struct sk_buff *,
- enum nes_timer_type, int, int);
-
-int nes_accept(struct iw_cm_id *, struct iw_cm_conn_param *);
-int nes_reject(struct iw_cm_id *, const void *, u8);
-int nes_connect(struct iw_cm_id *, struct iw_cm_conn_param *);
-int nes_create_listen(struct iw_cm_id *, int);
-int nes_destroy_listen(struct iw_cm_id *);
-
-int nes_cm_recv(struct sk_buff *, struct net_device *);
-int nes_cm_start(void);
-int nes_cm_stop(void);
-int nes_add_ref_cm_node(struct nes_cm_node *cm_node);
-int nes_rem_ref_cm_node(struct nes_cm_node *cm_node);
-
-#endif /* NES_CM_H */
diff --git a/drivers/infiniband/hw/nes/nes_context.h b/drivers/infiniband/hw/nes/nes_context.h
deleted file mode 100644
index a69eef16d72d..000000000000
--- a/drivers/infiniband/hw/nes/nes_context.h
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (c) 2006 - 2011 Intel Corporation. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef NES_CONTEXT_H
-#define NES_CONTEXT_H
-
-struct nes_qp_context {
- __le32 misc;
- __le32 cqs;
- __le32 sq_addr_low;
- __le32 sq_addr_high;
- __le32 rq_addr_low;
- __le32 rq_addr_high;
- __le32 misc2;
- __le16 tcpPorts[2];
- __le32 ip0;
- __le32 ip1;
- __le32 ip2;
- __le32 ip3;
- __le32 mss;
- __le32 arp_index_vlan;
- __le32 tcp_state_flow_label;
- __le32 pd_index_wscale;
- __le32 keepalive;
- u32 ts_recent;
- u32 ts_age;
- __le32 snd_nxt;
- __le32 snd_wnd;
- __le32 rcv_nxt;
- __le32 rcv_wnd;
- __le32 snd_max;
- __le32 snd_una;
- u32 srtt;
- __le32 rttvar;
- __le32 ssthresh;
- __le32 cwnd;
- __le32 snd_wl1;
- __le32 snd_wl2;
- __le32 max_snd_wnd;
- __le32 ts_val_delta;
- u32 retransmit;
- u32 probe_cnt;
- u32 hte_index;
- __le32 q2_addr_low;
- __le32 q2_addr_high;
- __le32 ird_index;
- u32 Rsvd3;
- __le32 ird_ord_sizes;
- u32 mrkr_offset;
- __le32 aeq_token_low;
- __le32 aeq_token_high;
-};
-
-/* QP Context Misc Field */
-
-#define NES_QPCONTEXT_MISC_IWARP_VER_MASK 0x00000003
-#define NES_QPCONTEXT_MISC_IWARP_VER_SHIFT 0
-#define NES_QPCONTEXT_MISC_EFB_SIZE_MASK 0x000000C0
-#define NES_QPCONTEXT_MISC_EFB_SIZE_SHIFT 6
-#define NES_QPCONTEXT_MISC_RQ_SIZE_MASK 0x00000300
-#define NES_QPCONTEXT_MISC_RQ_SIZE_SHIFT 8
-#define NES_QPCONTEXT_MISC_SQ_SIZE_MASK 0x00000c00
-#define NES_QPCONTEXT_MISC_SQ_SIZE_SHIFT 10
-#define NES_QPCONTEXT_MISC_PCI_FCN_MASK 0x00007000
-#define NES_QPCONTEXT_MISC_PCI_FCN_SHIFT 12
-#define NES_QPCONTEXT_MISC_DUP_ACKS_MASK 0x00070000
-#define NES_QPCONTEXT_MISC_DUP_ACKS_SHIFT 16
-
-enum nes_qp_context_misc_bits {
- NES_QPCONTEXT_MISC_RX_WQE_SIZE = 0x00000004,
- NES_QPCONTEXT_MISC_IPV4 = 0x00000008,
- NES_QPCONTEXT_MISC_DO_NOT_FRAG = 0x00000010,
- NES_QPCONTEXT_MISC_INSERT_VLAN = 0x00000020,
- NES_QPCONTEXT_MISC_DROS = 0x00008000,
- NES_QPCONTEXT_MISC_WSCALE = 0x00080000,
- NES_QPCONTEXT_MISC_KEEPALIVE = 0x00100000,
- NES_QPCONTEXT_MISC_TIMESTAMP = 0x00200000,
- NES_QPCONTEXT_MISC_SACK = 0x00400000,
- NES_QPCONTEXT_MISC_RDMA_WRITE_EN = 0x00800000,
- NES_QPCONTEXT_MISC_RDMA_READ_EN = 0x01000000,
- NES_QPCONTEXT_MISC_WBIND_EN = 0x10000000,
- NES_QPCONTEXT_MISC_FAST_REGISTER_EN = 0x20000000,
- NES_QPCONTEXT_MISC_PRIV_EN = 0x40000000,
- NES_QPCONTEXT_MISC_NO_NAGLE = 0x80000000
-};
-
-enum nes_qp_acc_wq_sizes {
- HCONTEXT_TSA_WQ_SIZE_4 = 0,
- HCONTEXT_TSA_WQ_SIZE_32 = 1,
- HCONTEXT_TSA_WQ_SIZE_128 = 2,
- HCONTEXT_TSA_WQ_SIZE_512 = 3
-};
-
-/* QP Context Misc2 Fields */
-#define NES_QPCONTEXT_MISC2_TTL_MASK 0x000000ff
-#define NES_QPCONTEXT_MISC2_TTL_SHIFT 0
-#define NES_QPCONTEXT_MISC2_HOP_LIMIT_MASK 0x000000ff
-#define NES_QPCONTEXT_MISC2_HOP_LIMIT_SHIFT 0
-#define NES_QPCONTEXT_MISC2_LIMIT_MASK 0x00000300
-#define NES_QPCONTEXT_MISC2_LIMIT_SHIFT 8
-#define NES_QPCONTEXT_MISC2_NIC_INDEX_MASK 0x0000fc00
-#define NES_QPCONTEXT_MISC2_NIC_INDEX_SHIFT 10
-#define NES_QPCONTEXT_MISC2_SRC_IP_MASK 0x001f0000
-#define NES_QPCONTEXT_MISC2_SRC_IP_SHIFT 16
-#define NES_QPCONTEXT_MISC2_TOS_MASK 0xff000000
-#define NES_QPCONTEXT_MISC2_TOS_SHIFT 24
-#define NES_QPCONTEXT_MISC2_TRAFFIC_CLASS_MASK 0xff000000
-#define NES_QPCONTEXT_MISC2_TRAFFIC_CLASS_SHIFT 24
-
-/* QP Context Tcp State/Flow Label Fields */
-#define NES_QPCONTEXT_TCPFLOW_FLOW_LABEL_MASK 0x000fffff
-#define NES_QPCONTEXT_TCPFLOW_FLOW_LABEL_SHIFT 0
-#define NES_QPCONTEXT_TCPFLOW_TCP_STATE_MASK 0xf0000000
-#define NES_QPCONTEXT_TCPFLOW_TCP_STATE_SHIFT 28
-
-enum nes_qp_tcp_state {
- NES_QPCONTEXT_TCPSTATE_CLOSED = 1,
- NES_QPCONTEXT_TCPSTATE_EST = 5,
- NES_QPCONTEXT_TCPSTATE_TIME_WAIT = 11,
-};
-
-/* QP Context PD Index/wscale Fields */
-#define NES_QPCONTEXT_PDWSCALE_RCV_WSCALE_MASK 0x0000000f
-#define NES_QPCONTEXT_PDWSCALE_RCV_WSCALE_SHIFT 0
-#define NES_QPCONTEXT_PDWSCALE_SND_WSCALE_MASK 0x00000f00
-#define NES_QPCONTEXT_PDWSCALE_SND_WSCALE_SHIFT 8
-#define NES_QPCONTEXT_PDWSCALE_PDINDEX_MASK 0xffff0000
-#define NES_QPCONTEXT_PDWSCALE_PDINDEX_SHIFT 16
-
-/* QP Context Keepalive Fields */
-#define NES_QPCONTEXT_KEEPALIVE_DELTA_MASK 0x0000ffff
-#define NES_QPCONTEXT_KEEPALIVE_DELTA_SHIFT 0
-#define NES_QPCONTEXT_KEEPALIVE_PROBE_CNT_MASK 0x00ff0000
-#define NES_QPCONTEXT_KEEPALIVE_PROBE_CNT_SHIFT 16
-#define NES_QPCONTEXT_KEEPALIVE_INTV_MASK 0xff000000
-#define NES_QPCONTEXT_KEEPALIVE_INTV_SHIFT 24
-
-/* QP Context ORD/IRD Fields */
-#define NES_QPCONTEXT_ORDIRD_ORDSIZE_MASK 0x0000007f
-#define NES_QPCONTEXT_ORDIRD_ORDSIZE_SHIFT 0
-#define NES_QPCONTEXT_ORDIRD_IRDSIZE_MASK 0x00030000
-#define NES_QPCONTEXT_ORDIRD_IRDSIZE_SHIFT 16
-#define NES_QPCONTEXT_ORDIRD_IWARP_MODE_MASK 0x30000000
-#define NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT 28
-
-enum nes_ord_ird_bits {
- NES_QPCONTEXT_ORDIRD_WRPDU = 0x02000000,
- NES_QPCONTEXT_ORDIRD_LSMM_PRESENT = 0x04000000,
- NES_QPCONTEXT_ORDIRD_ALSMM = 0x08000000,
- NES_QPCONTEXT_ORDIRD_AAH = 0x40000000,
- NES_QPCONTEXT_ORDIRD_RNMC = 0x80000000
-};
-
-enum nes_iwarp_qp_state {
- NES_QPCONTEXT_IWARP_STATE_NONEXIST = 0,
- NES_QPCONTEXT_IWARP_STATE_IDLE = 1,
- NES_QPCONTEXT_IWARP_STATE_RTS = 2,
- NES_QPCONTEXT_IWARP_STATE_CLOSING = 3,
- NES_QPCONTEXT_IWARP_STATE_TERMINATE = 5,
- NES_QPCONTEXT_IWARP_STATE_ERROR = 6
-};
-
-
-#endif /* NES_CONTEXT_H */
diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c
deleted file mode 100644
index 5517e392bc01..000000000000
--- a/drivers/infiniband/hw/nes/nes_hw.c
+++ /dev/null
@@ -1,3887 +0,0 @@
-/*
- * Copyright (c) 2006 - 2011 Intel Corporation. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/if_vlan.h>
-#include <linux/slab.h>
-
-#include "nes.h"
-
-static int wide_ppm_offset;
-module_param(wide_ppm_offset, int, 0644);
-MODULE_PARM_DESC(wide_ppm_offset, "Increase CX4 interface clock ppm offset, 0=100ppm (default), 1=300ppm");
-
-static u32 crit_err_count;
-u32 int_mod_timer_init;
-u32 int_mod_cq_depth_256;
-u32 int_mod_cq_depth_128;
-u32 int_mod_cq_depth_32;
-u32 int_mod_cq_depth_24;
-u32 int_mod_cq_depth_16;
-u32 int_mod_cq_depth_4;
-u32 int_mod_cq_depth_1;
-static const u8 nes_max_critical_error_count = 100;
-#include "nes_cm.h"
-
-static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq);
-static void nes_init_csr_ne020(struct nes_device *nesdev, u8 hw_rev, u8 port_count);
-static int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count,
- struct nes_adapter *nesadapter, u8 OneG_Mode);
-static void nes_nic_napi_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq);
-static void nes_process_aeq(struct nes_device *nesdev, struct nes_hw_aeq *aeq);
-static void nes_process_ceq(struct nes_device *nesdev, struct nes_hw_ceq *ceq);
-static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
- struct nes_hw_aeqe *aeqe);
-static void process_critical_error(struct nes_device *nesdev);
-static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number);
-static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_Mode);
-static void nes_terminate_start_timer(struct nes_qp *nesqp);
-
-static const char *const nes_iwarp_state_str[] = {
- "Non-Existent",
- "Idle",
- "RTS",
- "Closing",
- "RSVD1",
- "Terminate",
- "Error",
- "RSVD2",
-};
-
-static const char *const nes_tcp_state_str[] = {
- "Non-Existent",
- "Closed",
- "Listen",
- "SYN Sent",
- "SYN Rcvd",
- "Established",
- "Close Wait",
- "FIN Wait 1",
- "Closing",
- "Last Ack",
- "FIN Wait 2",
- "Time Wait",
- "RSVD1",
- "RSVD2",
- "RSVD3",
- "RSVD4",
-};
-
-static inline void print_ip(struct nes_cm_node *cm_node)
-{
- unsigned char *rem_addr;
- if (cm_node) {
- rem_addr = (unsigned char *)&cm_node->rem_addr;
- printk(KERN_ERR PFX "Remote IP addr: %pI4\n", rem_addr);
- }
-}
-
-/**
- * nes_nic_init_timer_defaults
- */
-void nes_nic_init_timer_defaults(struct nes_device *nesdev, u8 jumbomode)
-{
- unsigned long flags;
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer;
-
- spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags);
-
- shared_timer->timer_in_use_min = NES_NIC_FAST_TIMER_LOW;
- shared_timer->timer_in_use_max = NES_NIC_FAST_TIMER_HIGH;
- if (jumbomode) {
- shared_timer->threshold_low = DEFAULT_JUMBO_NES_QL_LOW;
- shared_timer->threshold_target = DEFAULT_JUMBO_NES_QL_TARGET;
- shared_timer->threshold_high = DEFAULT_JUMBO_NES_QL_HIGH;
- } else {
- shared_timer->threshold_low = DEFAULT_NES_QL_LOW;
- shared_timer->threshold_target = DEFAULT_NES_QL_TARGET;
- shared_timer->threshold_high = DEFAULT_NES_QL_HIGH;
- }
-
- /* todo use netdev->mtu to set thresholds */
- spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags);
-}
-
-
-/**
- * nes_nic_init_timer
- */
-static void nes_nic_init_timer(struct nes_device *nesdev)
-{
- unsigned long flags;
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer;
-
- spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags);
-
- if (shared_timer->timer_in_use_old == 0) {
- nesdev->deepcq_count = 0;
- shared_timer->timer_direction_upward = 0;
- shared_timer->timer_direction_downward = 0;
- shared_timer->timer_in_use = NES_NIC_FAST_TIMER;
- shared_timer->timer_in_use_old = 0;
-
- }
- if (shared_timer->timer_in_use != shared_timer->timer_in_use_old) {
- shared_timer->timer_in_use_old = shared_timer->timer_in_use;
- nes_write32(nesdev->regs+NES_PERIODIC_CONTROL,
- 0x80000000 | ((u32)(shared_timer->timer_in_use*8)));
- }
- /* todo use netdev->mtu to set thresholds */
- spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags);
-}
-
-
-/**
- * nes_nic_tune_timer
- */
-static void nes_nic_tune_timer(struct nes_device *nesdev)
-{
- unsigned long flags;
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer;
- u16 cq_count = nesdev->currcq_count;
-
- spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags);
-
- if (shared_timer->cq_count_old <= cq_count)
- shared_timer->cq_direction_downward = 0;
- else
- shared_timer->cq_direction_downward++;
- shared_timer->cq_count_old = cq_count;
- if (shared_timer->cq_direction_downward > NES_NIC_CQ_DOWNWARD_TREND) {
- if (cq_count <= shared_timer->threshold_low &&
- shared_timer->threshold_low > 4) {
- shared_timer->threshold_low = shared_timer->threshold_low/2;
- shared_timer->cq_direction_downward=0;
- nesdev->currcq_count = 0;
- spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags);
- return;
- }
- }
-
- if (cq_count > 1) {
- nesdev->deepcq_count += cq_count;
- if (cq_count <= shared_timer->threshold_low) { /* increase timer gently */
- shared_timer->timer_direction_upward++;
- shared_timer->timer_direction_downward = 0;
- } else if (cq_count <= shared_timer->threshold_target) { /* balanced */
- shared_timer->timer_direction_upward = 0;
- shared_timer->timer_direction_downward = 0;
- } else if (cq_count <= shared_timer->threshold_high) { /* decrease timer gently */
- shared_timer->timer_direction_downward++;
- shared_timer->timer_direction_upward = 0;
- } else if (cq_count <= (shared_timer->threshold_high) * 2) {
- shared_timer->timer_in_use -= 2;
- shared_timer->timer_direction_upward = 0;
- shared_timer->timer_direction_downward++;
- } else {
- shared_timer->timer_in_use -= 4;
- shared_timer->timer_direction_upward = 0;
- shared_timer->timer_direction_downward++;
- }
-
- if (shared_timer->timer_direction_upward > 3 ) { /* using history */
- shared_timer->timer_in_use += 3;
- shared_timer->timer_direction_upward = 0;
- shared_timer->timer_direction_downward = 0;
- }
- if (shared_timer->timer_direction_downward > 5) { /* using history */
- shared_timer->timer_in_use -= 4 ;
- shared_timer->timer_direction_downward = 0;
- shared_timer->timer_direction_upward = 0;
- }
- }
-
- /* boundary checking */
- if (shared_timer->timer_in_use > shared_timer->threshold_high)
- shared_timer->timer_in_use = shared_timer->threshold_high;
- else if (shared_timer->timer_in_use < shared_timer->threshold_low)
- shared_timer->timer_in_use = shared_timer->threshold_low;
-
- nesdev->currcq_count = 0;
-
- spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags);
-}
-
-
-/**
- * nes_init_adapter - initialize adapter
- */
-struct nes_adapter *nes_init_adapter(struct nes_device *nesdev, u8 hw_rev) {
- struct nes_adapter *nesadapter = NULL;
- unsigned long num_pds;
- u32 u32temp;
- u32 port_count;
- u16 max_rq_wrs;
- u16 max_sq_wrs;
- u32 max_mr;
- u32 max_256pbl;
- u32 max_4kpbl;
- u32 max_qp;
- u32 max_irrq;
- u32 max_cq;
- u32 hte_index_mask;
- u32 adapter_size;
- u32 arp_table_size;
- u16 vendor_id;
- u16 device_id;
- u8 OneG_Mode;
- u8 func_index;
-
- /* search the list of existing adapters */
- list_for_each_entry(nesadapter, &nes_adapter_list, list) {
- nes_debug(NES_DBG_INIT, "Searching Adapter list for PCI devfn = 0x%X,"
- " adapter PCI slot/bus = %u/%u, pci devices PCI slot/bus = %u/%u, .\n",
- nesdev->pcidev->devfn,
- PCI_SLOT(nesadapter->devfn),
- nesadapter->bus_number,
- PCI_SLOT(nesdev->pcidev->devfn),
- nesdev->pcidev->bus->number );
- if ((PCI_SLOT(nesadapter->devfn) == PCI_SLOT(nesdev->pcidev->devfn)) &&
- (nesadapter->bus_number == nesdev->pcidev->bus->number)) {
- nesadapter->ref_count++;
- return nesadapter;
- }
- }
-
- /* no adapter found */
- num_pds = pci_resource_len(nesdev->pcidev, BAR_1) >> PAGE_SHIFT;
- if ((hw_rev != NE020_REV) && (hw_rev != NE020_REV1)) {
- nes_debug(NES_DBG_INIT, "NE020 driver detected unknown hardware revision 0x%x\n",
- hw_rev);
- return NULL;
- }
-
- nes_debug(NES_DBG_INIT, "Determine Soft Reset, QP_control=0x%x, CPU0=0x%x, CPU1=0x%x, CPU2=0x%x\n",
- nes_read_indexed(nesdev, NES_IDX_QP_CONTROL + PCI_FUNC(nesdev->pcidev->devfn) * 8),
- nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS),
- nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS + 4),
- nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS + 8));
-
- nes_debug(NES_DBG_INIT, "Reset and init NE020\n");
-
-
- if ((port_count = nes_reset_adapter_ne020(nesdev, &OneG_Mode)) == 0)
- return NULL;
-
- max_qp = nes_read_indexed(nesdev, NES_IDX_QP_CTX_SIZE);
- nes_debug(NES_DBG_INIT, "QP_CTX_SIZE=%u\n", max_qp);
-
- u32temp = nes_read_indexed(nesdev, NES_IDX_QUAD_HASH_TABLE_SIZE);
- if (max_qp > ((u32)1 << (u32temp & 0x001f))) {
- nes_debug(NES_DBG_INIT, "Reducing Max QPs to %u due to hash table size = 0x%08X\n",
- max_qp, u32temp);
- max_qp = (u32)1 << (u32temp & 0x001f);
- }
-
- hte_index_mask = ((u32)1 << ((u32temp & 0x001f)+1))-1;
- nes_debug(NES_DBG_INIT, "Max QP = %u, hte_index_mask = 0x%08X.\n",
- max_qp, hte_index_mask);
-
- u32temp = nes_read_indexed(nesdev, NES_IDX_IRRQ_COUNT);
-
- max_irrq = 1 << (u32temp & 0x001f);
-
- if (max_qp > max_irrq) {
- max_qp = max_irrq;
- nes_debug(NES_DBG_INIT, "Reducing Max QPs to %u due to Available Q1s.\n",
- max_qp);
- }
-
- /* there should be no reason to allocate more pds than qps */
- if (num_pds > max_qp)
- num_pds = max_qp;
-
- u32temp = nes_read_indexed(nesdev, NES_IDX_MRT_SIZE);
- max_mr = (u32)8192 << (u32temp & 0x7);
-
- u32temp = nes_read_indexed(nesdev, NES_IDX_PBL_REGION_SIZE);
- max_256pbl = (u32)1 << (u32temp & 0x0000001f);
- max_4kpbl = (u32)1 << ((u32temp >> 16) & 0x0000001f);
- max_cq = nes_read_indexed(nesdev, NES_IDX_CQ_CTX_SIZE);
-
- u32temp = nes_read_indexed(nesdev, NES_IDX_ARP_CACHE_SIZE);
- arp_table_size = 1 << u32temp;
-
- adapter_size = (sizeof(struct nes_adapter) +
- (sizeof(unsigned long)-1)) & (~(sizeof(unsigned long)-1));
- adapter_size += sizeof(unsigned long) * BITS_TO_LONGS(max_qp);
- adapter_size += sizeof(unsigned long) * BITS_TO_LONGS(max_mr);
- adapter_size += sizeof(unsigned long) * BITS_TO_LONGS(max_cq);
- adapter_size += sizeof(unsigned long) * BITS_TO_LONGS(num_pds);
- adapter_size += sizeof(unsigned long) * BITS_TO_LONGS(arp_table_size);
- adapter_size += sizeof(struct nes_qp **) * max_qp;
-
- /* allocate a new adapter struct */
- nesadapter = kzalloc(adapter_size, GFP_KERNEL);
- if (!nesadapter)
- return NULL;
-
- nes_debug(NES_DBG_INIT, "Allocating new nesadapter @ %p, size = %u (actual size = %u).\n",
- nesadapter, (u32)sizeof(struct nes_adapter), adapter_size);
-
- if (nes_read_eeprom_values(nesdev, nesadapter)) {
- printk(KERN_ERR PFX "Unable to read EEPROM data.\n");
- kfree(nesadapter);
- return NULL;
- }
-
- nesadapter->vendor_id = (((u32) nesadapter->mac_addr_high) << 8) |
- (nesadapter->mac_addr_low >> 24);
-
- pci_bus_read_config_word(nesdev->pcidev->bus, nesdev->pcidev->devfn,
- PCI_DEVICE_ID, &device_id);
- nesadapter->vendor_part_id = device_id;
-
- if (nes_init_serdes(nesdev, hw_rev, port_count, nesadapter,
- OneG_Mode)) {
- kfree(nesadapter);
- return NULL;
- }
- nes_init_csr_ne020(nesdev, hw_rev, port_count);
-
- memset(nesadapter->pft_mcast_map, 255,
- sizeof nesadapter->pft_mcast_map);
-
- /* populate the new nesadapter */
- nesadapter->nesdev = nesdev;
- nesadapter->devfn = nesdev->pcidev->devfn;
- nesadapter->bus_number = nesdev->pcidev->bus->number;
- nesadapter->ref_count = 1;
- nesadapter->timer_int_req = 0xffff0000;
- nesadapter->OneG_Mode = OneG_Mode;
- nesadapter->doorbell_start = nesdev->doorbell_region;
-
- /* nesadapter->tick_delta = clk_divisor; */
- nesadapter->hw_rev = hw_rev;
- nesadapter->port_count = port_count;
-
- nesadapter->max_qp = max_qp;
- nesadapter->hte_index_mask = hte_index_mask;
- nesadapter->max_irrq = max_irrq;
- nesadapter->max_mr = max_mr;
- nesadapter->max_256pbl = max_256pbl - 1;
- nesadapter->max_4kpbl = max_4kpbl - 1;
- nesadapter->max_cq = max_cq;
- nesadapter->free_256pbl = max_256pbl - 1;
- nesadapter->free_4kpbl = max_4kpbl - 1;
- nesadapter->max_pd = num_pds;
- nesadapter->arp_table_size = arp_table_size;
-
- nesadapter->et_pkt_rate_low = NES_TIMER_ENABLE_LIMIT;
- if (nes_drv_opt & NES_DRV_OPT_DISABLE_INT_MOD) {
- nesadapter->et_use_adaptive_rx_coalesce = 0;
- nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT;
- nesadapter->et_rx_coalesce_usecs_irq = interrupt_mod_interval;
- } else {
- nesadapter->et_use_adaptive_rx_coalesce = 1;
- nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT_DYNAMIC;
- nesadapter->et_rx_coalesce_usecs_irq = 0;
- printk(PFX "%s: Using Adaptive Interrupt Moderation\n", __func__);
- }
- /* Setup and enable the periodic timer */
- if (nesadapter->et_rx_coalesce_usecs_irq)
- nes_write32(nesdev->regs+NES_PERIODIC_CONTROL, 0x80000000 |
- ((u32)(nesadapter->et_rx_coalesce_usecs_irq * 8)));
- else
- nes_write32(nesdev->regs+NES_PERIODIC_CONTROL, 0x00000000);
-
- nesadapter->base_pd = 1;
-
- nesadapter->device_cap_flags = IB_DEVICE_LOCAL_DMA_LKEY |
- IB_DEVICE_MEM_WINDOW |
- IB_DEVICE_MEM_MGT_EXTENSIONS;
-
- nesadapter->allocated_qps = (unsigned long *)&(((unsigned char *)nesadapter)
- [(sizeof(struct nes_adapter)+(sizeof(unsigned long)-1))&(~(sizeof(unsigned long)-1))]);
- nesadapter->allocated_cqs = &nesadapter->allocated_qps[BITS_TO_LONGS(max_qp)];
- nesadapter->allocated_mrs = &nesadapter->allocated_cqs[BITS_TO_LONGS(max_cq)];
- nesadapter->allocated_pds = &nesadapter->allocated_mrs[BITS_TO_LONGS(max_mr)];
- nesadapter->allocated_arps = &nesadapter->allocated_pds[BITS_TO_LONGS(num_pds)];
- nesadapter->qp_table = (struct nes_qp **)(&nesadapter->allocated_arps[BITS_TO_LONGS(arp_table_size)]);
-
-
- /* mark the usual suspect QPs, MR and CQs as in use */
- for (u32temp = 0; u32temp < NES_FIRST_QPN; u32temp++) {
- set_bit(u32temp, nesadapter->allocated_qps);
- set_bit(u32temp, nesadapter->allocated_cqs);
- }
- set_bit(0, nesadapter->allocated_mrs);
-
- for (u32temp = 0; u32temp < 20; u32temp++)
- set_bit(u32temp, nesadapter->allocated_pds);
- u32temp = nes_read_indexed(nesdev, NES_IDX_QP_MAX_CFG_SIZES);
-
- max_rq_wrs = ((u32temp >> 8) & 3);
- switch (max_rq_wrs) {
- case 0:
- max_rq_wrs = 4;
- break;
- case 1:
- max_rq_wrs = 16;
- break;
- case 2:
- max_rq_wrs = 32;
- break;
- case 3:
- max_rq_wrs = 512;
- break;
- }
-
- max_sq_wrs = (u32temp & 3);
- switch (max_sq_wrs) {
- case 0:
- max_sq_wrs = 4;
- break;
- case 1:
- max_sq_wrs = 16;
- break;
- case 2:
- max_sq_wrs = 32;
- break;
- case 3:
- max_sq_wrs = 512;
- break;
- }
- nesadapter->max_qp_wr = min(max_rq_wrs, max_sq_wrs);
- nesadapter->max_irrq_wr = (u32temp >> 16) & 3;
-
- nesadapter->max_sge = 4;
- nesadapter->max_cqe = 32766;
-
- if (nes_read_eeprom_values(nesdev, nesadapter)) {
- printk(KERN_ERR PFX "Unable to read EEPROM data.\n");
- kfree(nesadapter);
- return NULL;
- }
-
- u32temp = nes_read_indexed(nesdev, NES_IDX_TCP_TIMER_CONFIG);
- nes_write_indexed(nesdev, NES_IDX_TCP_TIMER_CONFIG,
- (u32temp & 0xff000000) | (nesadapter->tcp_timer_core_clk_divisor & 0x00ffffff));
-
- /* setup port configuration */
- if (nesadapter->port_count == 1) {
- nesadapter->log_port = 0x00000000;
- if (nes_drv_opt & NES_DRV_OPT_DUAL_LOGICAL_PORT)
- nes_write_indexed(nesdev, NES_IDX_TX_POOL_SIZE, 0x00000002);
- else
- nes_write_indexed(nesdev, NES_IDX_TX_POOL_SIZE, 0x00000003);
- } else {
- if (nesadapter->phy_type[0] == NES_PHY_TYPE_PUMA_1G) {
- nesadapter->log_port = 0x000000D8;
- } else {
- if (nesadapter->port_count == 2)
- nesadapter->log_port = 0x00000044;
- else
- nesadapter->log_port = 0x000000e4;
- }
- nes_write_indexed(nesdev, NES_IDX_TX_POOL_SIZE, 0x00000003);
- }
-
- nes_write_indexed(nesdev, NES_IDX_NIC_LOGPORT_TO_PHYPORT,
- nesadapter->log_port);
- nes_debug(NES_DBG_INIT, "Probe time, LOG2PHY=%u\n",
- nes_read_indexed(nesdev, NES_IDX_NIC_LOGPORT_TO_PHYPORT));
-
- spin_lock_init(&nesadapter->resource_lock);
- spin_lock_init(&nesadapter->phy_lock);
- spin_lock_init(&nesadapter->pbl_lock);
- spin_lock_init(&nesadapter->periodic_timer_lock);
-
- INIT_LIST_HEAD(&nesadapter->nesvnic_list[0]);
- INIT_LIST_HEAD(&nesadapter->nesvnic_list[1]);
- INIT_LIST_HEAD(&nesadapter->nesvnic_list[2]);
- INIT_LIST_HEAD(&nesadapter->nesvnic_list[3]);
-
- if ((!nesadapter->OneG_Mode) && (nesadapter->port_count == 2)) {
- u32 pcs_control_status0, pcs_control_status1;
- u32 reset_value;
- u32 i = 0;
- u32 int_cnt = 0;
- u32 ext_cnt = 0;
- unsigned long flags;
- u32 j = 0;
-
- pcs_control_status0 = nes_read_indexed(nesdev,
- NES_IDX_PHY_PCS_CONTROL_STATUS0);
- pcs_control_status1 = nes_read_indexed(nesdev,
- NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200);
-
- for (i = 0; i < NES_MAX_LINK_CHECK; i++) {
- pcs_control_status0 = nes_read_indexed(nesdev,
- NES_IDX_PHY_PCS_CONTROL_STATUS0);
- pcs_control_status1 = nes_read_indexed(nesdev,
- NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200);
- if ((0x0F000100 == (pcs_control_status0 & 0x0F000100))
- || (0x0F000100 == (pcs_control_status1 & 0x0F000100)))
- int_cnt++;
- usleep_range(1000, 2000);
- }
- if (int_cnt > 1) {
- spin_lock_irqsave(&nesadapter->phy_lock, flags);
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x0000F0C8);
- mh_detected++;
- reset_value = nes_read32(nesdev->regs+NES_SOFTWARE_RESET);
- reset_value |= 0x0000003d;
- nes_write32(nesdev->regs+NES_SOFTWARE_RESET, reset_value);
-
- while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET)
- & 0x00000040) != 0x00000040) && (j++ < 5000));
- spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
-
- pcs_control_status0 = nes_read_indexed(nesdev,
- NES_IDX_PHY_PCS_CONTROL_STATUS0);
- pcs_control_status1 = nes_read_indexed(nesdev,
- NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200);
-
- for (i = 0; i < NES_MAX_LINK_CHECK; i++) {
- pcs_control_status0 = nes_read_indexed(nesdev,
- NES_IDX_PHY_PCS_CONTROL_STATUS0);
- pcs_control_status1 = nes_read_indexed(nesdev,
- NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200);
- if ((0x0F000100 == (pcs_control_status0 & 0x0F000100))
- || (0x0F000100 == (pcs_control_status1 & 0x0F000100))) {
- if (++ext_cnt > int_cnt) {
- spin_lock_irqsave(&nesadapter->phy_lock, flags);
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1,
- 0x0000F088);
- mh_detected++;
- reset_value = nes_read32(nesdev->regs+NES_SOFTWARE_RESET);
- reset_value |= 0x0000003d;
- nes_write32(nesdev->regs+NES_SOFTWARE_RESET, reset_value);
-
- while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET)
- & 0x00000040) != 0x00000040) && (j++ < 5000));
- spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
- break;
- }
- }
- usleep_range(1000, 2000);
- }
- }
- }
-
- if (nesadapter->hw_rev == NE020_REV) {
- timer_setup(&nesadapter->mh_timer, nes_mh_fix, 0);
- nesadapter->mh_timer.expires = jiffies + (HZ/5); /* 1 second */
- add_timer(&nesadapter->mh_timer);
- } else {
- nes_write32(nesdev->regs+NES_INTF_INT_STAT, 0x0f000000);
- }
-
- timer_setup(&nesadapter->lc_timer, nes_clc, 0);
- nesadapter->lc_timer.expires = jiffies + 3600 * HZ; /* 1 hour */
- add_timer(&nesadapter->lc_timer);
-
- list_add_tail(&nesadapter->list, &nes_adapter_list);
-
- for (func_index = 0; func_index < 8; func_index++) {
- pci_bus_read_config_word(nesdev->pcidev->bus,
- PCI_DEVFN(PCI_SLOT(nesdev->pcidev->devfn),
- func_index), 0, &vendor_id);
- if (vendor_id == 0xffff)
- break;
- }
- nes_debug(NES_DBG_INIT, "%s %d functions found for %s.\n", __func__,
- func_index, pci_name(nesdev->pcidev));
- nesadapter->adapter_fcn_count = func_index;
-
- return nesadapter;
-}
-
-
-/**
- * nes_reset_adapter_ne020
- */
-static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_Mode)
-{
- u32 port_count;
- u32 u32temp;
- u32 i;
-
- u32temp = nes_read32(nesdev->regs+NES_SOFTWARE_RESET);
- port_count = ((u32temp & 0x00000300) >> 8) + 1;
- /* TODO: assuming that both SERDES are set the same for now */
- *OneG_Mode = (u32temp & 0x00003c00) ? 0 : 1;
- nes_debug(NES_DBG_INIT, "Initial Software Reset = 0x%08X, port_count=%u\n",
- u32temp, port_count);
- if (*OneG_Mode)
- nes_debug(NES_DBG_INIT, "Running in 1G mode.\n");
- u32temp &= 0xff00ffc0;
- switch (port_count) {
- case 1:
- u32temp |= 0x00ee0000;
- break;
- case 2:
- u32temp |= 0x00cc0000;
- break;
- case 4:
- u32temp |= 0x00000000;
- break;
- default:
- return 0;
- break;
- }
-
- /* check and do full reset if needed */
- if (nes_read_indexed(nesdev, NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8))) {
- nes_debug(NES_DBG_INIT, "Issuing Full Soft reset = 0x%08X\n", u32temp | 0xd);
- nes_write32(nesdev->regs+NES_SOFTWARE_RESET, u32temp | 0xd);
-
- i = 0;
- while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET) & 0x00000040) == 0) && i++ < 10000)
- mdelay(1);
- if (i > 10000) {
- nes_debug(NES_DBG_INIT, "Did not see full soft reset done.\n");
- return 0;
- }
-
- i = 0;
- while ((nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS) != 0x80) && i++ < 10000)
- mdelay(1);
- if (i > 10000) {
- printk(KERN_ERR PFX "Internal CPU not ready, status = %02X\n",
- nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS));
- return 0;
- }
- }
-
- /* port reset */
- switch (port_count) {
- case 1:
- u32temp |= 0x00ee0010;
- break;
- case 2:
- u32temp |= 0x00cc0030;
- break;
- case 4:
- u32temp |= 0x00000030;
- break;
- }
-
- nes_debug(NES_DBG_INIT, "Issuing Port Soft reset = 0x%08X\n", u32temp | 0xd);
- nes_write32(nesdev->regs+NES_SOFTWARE_RESET, u32temp | 0xd);
-
- i = 0;
- while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET) & 0x00000040) == 0) && i++ < 10000)
- mdelay(1);
- if (i > 10000) {
- nes_debug(NES_DBG_INIT, "Did not see port soft reset done.\n");
- return 0;
- }
-
- /* serdes 0 */
- i = 0;
- while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0)
- & 0x0000000f)) != 0x0000000f) && i++ < 5000)
- mdelay(1);
- if (i > 5000) {
- nes_debug(NES_DBG_INIT, "Serdes 0 not ready, status=%x\n", u32temp);
- return 0;
- }
-
- /* serdes 1 */
- if (port_count > 1) {
- i = 0;
- while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS1)
- & 0x0000000f)) != 0x0000000f) && i++ < 5000)
- mdelay(1);
- if (i > 5000) {
- nes_debug(NES_DBG_INIT, "Serdes 1 not ready, status=%x\n", u32temp);
- return 0;
- }
- }
-
- return port_count;
-}
-
-
-/**
- * nes_init_serdes
- */
-static int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count,
- struct nes_adapter *nesadapter, u8 OneG_Mode)
-{
- int i;
- u32 u32temp;
- u32 sds;
-
- if (hw_rev != NE020_REV) {
- /* init serdes 0 */
- switch (nesadapter->phy_type[0]) {
- case NES_PHY_TYPE_CX4:
- if (wide_ppm_offset)
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000FFFAA);
- else
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000FF);
- break;
- case NES_PHY_TYPE_KR:
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000FF);
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_EMP0, 0x00000000);
- break;
- case NES_PHY_TYPE_PUMA_1G:
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000FF);
- sds = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0);
- sds |= 0x00000100;
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, sds);
- break;
- default:
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000FF);
- break;
- }
-
- if (!OneG_Mode)
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_HIGHZ_LANE_MODE0, 0x11110000);
-
- if (port_count < 2)
- return 0;
-
- /* init serdes 1 */
- if (!(OneG_Mode && (nesadapter->phy_type[1] != NES_PHY_TYPE_PUMA_1G)))
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL1, 0x000000FF);
-
- switch (nesadapter->phy_type[1]) {
- case NES_PHY_TYPE_ARGUS:
- case NES_PHY_TYPE_SFP_D:
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_EMP0, 0x00000000);
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_EMP1, 0x00000000);
- break;
- case NES_PHY_TYPE_CX4:
- if (wide_ppm_offset)
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL1, 0x000FFFAA);
- break;
- case NES_PHY_TYPE_KR:
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_EMP1, 0x00000000);
- break;
- case NES_PHY_TYPE_PUMA_1G:
- sds = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1);
- sds |= 0x000000100;
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, sds);
- }
- if (!OneG_Mode) {
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_HIGHZ_LANE_MODE1, 0x11110000);
- sds = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1);
- sds &= 0xFFFFFFBF;
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, sds);
- }
- } else {
- /* init serdes 0 */
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, 0x00000008);
- i = 0;
- while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0)
- & 0x0000000f)) != 0x0000000f) && i++ < 5000)
- mdelay(1);
- if (i > 5000) {
- nes_debug(NES_DBG_PHY, "Init: serdes 0 not ready, status=%x\n", u32temp);
- return 1;
- }
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_EMP0, 0x000bdef7);
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_DRIVE0, 0x9ce73000);
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_MODE0, 0x0ff00000);
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_SIGDET0, 0x00000000);
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_BYPASS0, 0x00000000);
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_LOOPBACK_CONTROL0, 0x00000000);
- if (OneG_Mode)
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_EQ_CONTROL0, 0xf0182222);
- else
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_EQ_CONTROL0, 0xf0042222);
-
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000ff);
- if (port_count > 1) {
- /* init serdes 1 */
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x00000048);
- i = 0;
- while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS1)
- & 0x0000000f)) != 0x0000000f) && (i++ < 5000))
- mdelay(1);
- if (i > 5000) {
- printk("%s: Init: serdes 1 not ready, status=%x\n", __func__, u32temp);
- /* return 1; */
- }
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_EMP1, 0x000bdef7);
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_DRIVE1, 0x9ce73000);
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_MODE1, 0x0ff00000);
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_SIGDET1, 0x00000000);
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_BYPASS1, 0x00000000);
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_LOOPBACK_CONTROL1, 0x00000000);
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_EQ_CONTROL1, 0xf0002222);
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL1, 0x000000ff);
- }
- }
- return 0;
-}
-
-
-/**
- * nes_init_csr_ne020
- * Initialize registers for ne020 hardware
- */
-static void nes_init_csr_ne020(struct nes_device *nesdev, u8 hw_rev, u8 port_count)
-{
- u32 u32temp;
-
- nes_debug(NES_DBG_INIT, "port_count=%d\n", port_count);
-
- nes_write_indexed(nesdev, 0x000001E4, 0x00000007);
- /* nes_write_indexed(nesdev, 0x000001E8, 0x000208C4); */
- nes_write_indexed(nesdev, 0x000001E8, 0x00020874);
- nes_write_indexed(nesdev, 0x000001D8, 0x00048002);
- /* nes_write_indexed(nesdev, 0x000001D8, 0x0004B002); */
- nes_write_indexed(nesdev, 0x000001FC, 0x00050005);
- nes_write_indexed(nesdev, 0x00000600, 0x55555555);
- nes_write_indexed(nesdev, 0x00000604, 0x55555555);
-
- /* TODO: move these MAC register settings to NIC bringup */
- nes_write_indexed(nesdev, 0x00002000, 0x00000001);
- nes_write_indexed(nesdev, 0x00002004, 0x00000001);
- nes_write_indexed(nesdev, 0x00002008, 0x0000FFFF);
- nes_write_indexed(nesdev, 0x0000200C, 0x00000001);
- nes_write_indexed(nesdev, 0x00002010, 0x000003c1);
- nes_write_indexed(nesdev, 0x0000201C, 0x75345678);
- if (port_count > 1) {
- nes_write_indexed(nesdev, 0x00002200, 0x00000001);
- nes_write_indexed(nesdev, 0x00002204, 0x00000001);
- nes_write_indexed(nesdev, 0x00002208, 0x0000FFFF);
- nes_write_indexed(nesdev, 0x0000220C, 0x00000001);
- nes_write_indexed(nesdev, 0x00002210, 0x000003c1);
- nes_write_indexed(nesdev, 0x0000221C, 0x75345678);
- nes_write_indexed(nesdev, 0x00000908, 0x20000001);
- }
- if (port_count > 2) {
- nes_write_indexed(nesdev, 0x00002400, 0x00000001);
- nes_write_indexed(nesdev, 0x00002404, 0x00000001);
- nes_write_indexed(nesdev, 0x00002408, 0x0000FFFF);
- nes_write_indexed(nesdev, 0x0000240C, 0x00000001);
- nes_write_indexed(nesdev, 0x00002410, 0x000003c1);
- nes_write_indexed(nesdev, 0x0000241C, 0x75345678);
- nes_write_indexed(nesdev, 0x00000910, 0x20000001);
-
- nes_write_indexed(nesdev, 0x00002600, 0x00000001);
- nes_write_indexed(nesdev, 0x00002604, 0x00000001);
- nes_write_indexed(nesdev, 0x00002608, 0x0000FFFF);
- nes_write_indexed(nesdev, 0x0000260C, 0x00000001);
- nes_write_indexed(nesdev, 0x00002610, 0x000003c1);
- nes_write_indexed(nesdev, 0x0000261C, 0x75345678);
- nes_write_indexed(nesdev, 0x00000918, 0x20000001);
- }
-
- nes_write_indexed(nesdev, 0x00005000, 0x00018000);
- /* nes_write_indexed(nesdev, 0x00005000, 0x00010000); */
- nes_write_indexed(nesdev, NES_IDX_WQM_CONFIG1, (wqm_quanta << 1) |
- 0x00000001);
- nes_write_indexed(nesdev, 0x00005008, 0x1F1F1F1F);
- nes_write_indexed(nesdev, 0x00005010, 0x1F1F1F1F);
- nes_write_indexed(nesdev, 0x00005018, 0x1F1F1F1F);
- nes_write_indexed(nesdev, 0x00005020, 0x1F1F1F1F);
- nes_write_indexed(nesdev, 0x00006090, 0xFFFFFFFF);
-
- /* TODO: move this to code, get from EEPROM */
- nes_write_indexed(nesdev, 0x00000900, 0x20000001);
- nes_write_indexed(nesdev, 0x000060C0, 0x0000028e);
- nes_write_indexed(nesdev, 0x000060C8, 0x00000020);
-
- nes_write_indexed(nesdev, 0x000001EC, 0x7b2625a0);
- /* nes_write_indexed(nesdev, 0x000001EC, 0x5f2625a0); */
-
- if (hw_rev != NE020_REV) {
- u32temp = nes_read_indexed(nesdev, 0x000008e8);
- u32temp |= 0x80000000;
- nes_write_indexed(nesdev, 0x000008e8, u32temp);
- u32temp = nes_read_indexed(nesdev, 0x000021f8);
- u32temp &= 0x7fffffff;
- u32temp |= 0x7fff0010;
- nes_write_indexed(nesdev, 0x000021f8, u32temp);
- if (port_count > 1) {
- u32temp = nes_read_indexed(nesdev, 0x000023f8);
- u32temp &= 0x7fffffff;
- u32temp |= 0x7fff0010;
- nes_write_indexed(nesdev, 0x000023f8, u32temp);
- }
- }
-}
-
-
-/**
- * nes_destroy_adapter - destroy the adapter structure
- */
-void nes_destroy_adapter(struct nes_adapter *nesadapter)
-{
- struct nes_adapter *tmp_adapter;
-
- list_for_each_entry(tmp_adapter, &nes_adapter_list, list) {
- nes_debug(NES_DBG_SHUTDOWN, "Nes Adapter list entry = 0x%p.\n",
- tmp_adapter);
- }
-
- nesadapter->ref_count--;
- if (!nesadapter->ref_count) {
- if (nesadapter->hw_rev == NE020_REV) {
- del_timer(&nesadapter->mh_timer);
- }
- del_timer(&nesadapter->lc_timer);
-
- list_del(&nesadapter->list);
- kfree(nesadapter);
- }
-}
-
-
-/**
- * nes_init_cqp
- */
-int nes_init_cqp(struct nes_device *nesdev)
-{
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- struct nes_hw_cqp_qp_context *cqp_qp_context;
- struct nes_hw_cqp_wqe *cqp_wqe;
- struct nes_hw_ceq *ceq;
- struct nes_hw_ceq *nic_ceq;
- struct nes_hw_aeq *aeq;
- void *vmem;
- dma_addr_t pmem;
- u32 count=0;
- u32 cqp_head;
- u64 u64temp;
- u32 u32temp;
-
- /* allocate CQP memory */
- /* Need to add max_cq to the aeq size once cq overflow checking is added back */
- /* SQ is 512 byte aligned, others are 256 byte aligned */
- nesdev->cqp_mem_size = 512 +
- (sizeof(struct nes_hw_cqp_wqe) * NES_CQP_SQ_SIZE) +
- (sizeof(struct nes_hw_cqe) * NES_CCQ_SIZE) +
- max(((u32)sizeof(struct nes_hw_ceqe) * NES_CCEQ_SIZE), (u32)256) +
- max(((u32)sizeof(struct nes_hw_ceqe) * NES_NIC_CEQ_SIZE), (u32)256) +
- (sizeof(struct nes_hw_aeqe) * nesadapter->max_qp) +
- sizeof(struct nes_hw_cqp_qp_context);
-
- nesdev->cqp_vbase = pci_zalloc_consistent(nesdev->pcidev,
- nesdev->cqp_mem_size,
- &nesdev->cqp_pbase);
- if (!nesdev->cqp_vbase) {
- nes_debug(NES_DBG_INIT, "Unable to allocate memory for host descriptor rings\n");
- return -ENOMEM;
- }
-
- /* Allocate a twice the number of CQP requests as the SQ size */
- nesdev->nes_cqp_requests = kzalloc(sizeof(struct nes_cqp_request) *
- 2 * NES_CQP_SQ_SIZE, GFP_KERNEL);
- if (!nesdev->nes_cqp_requests) {
- pci_free_consistent(nesdev->pcidev, nesdev->cqp_mem_size, nesdev->cqp.sq_vbase,
- nesdev->cqp.sq_pbase);
- return -ENOMEM;
- }
-
- nes_debug(NES_DBG_INIT, "Allocated CQP structures at %p (phys = %016lX), size = %u.\n",
- nesdev->cqp_vbase, (unsigned long)nesdev->cqp_pbase, nesdev->cqp_mem_size);
-
- spin_lock_init(&nesdev->cqp.lock);
- init_waitqueue_head(&nesdev->cqp.waitq);
-
- /* Setup Various Structures */
- vmem = (void *)(((unsigned long)nesdev->cqp_vbase + (512 - 1)) &
- ~(unsigned long)(512 - 1));
- pmem = (dma_addr_t)(((unsigned long long)nesdev->cqp_pbase + (512 - 1)) &
- ~(unsigned long long)(512 - 1));
-
- nesdev->cqp.sq_vbase = vmem;
- nesdev->cqp.sq_pbase = pmem;
- nesdev->cqp.sq_size = NES_CQP_SQ_SIZE;
- nesdev->cqp.sq_head = 0;
- nesdev->cqp.sq_tail = 0;
- nesdev->cqp.qp_id = PCI_FUNC(nesdev->pcidev->devfn);
-
- vmem += (sizeof(struct nes_hw_cqp_wqe) * nesdev->cqp.sq_size);
- pmem += (sizeof(struct nes_hw_cqp_wqe) * nesdev->cqp.sq_size);
-
- nesdev->ccq.cq_vbase = vmem;
- nesdev->ccq.cq_pbase = pmem;
- nesdev->ccq.cq_size = NES_CCQ_SIZE;
- nesdev->ccq.cq_head = 0;
- nesdev->ccq.ce_handler = nes_cqp_ce_handler;
- nesdev->ccq.cq_number = PCI_FUNC(nesdev->pcidev->devfn);
-
- vmem += (sizeof(struct nes_hw_cqe) * nesdev->ccq.cq_size);
- pmem += (sizeof(struct nes_hw_cqe) * nesdev->ccq.cq_size);
-
- nesdev->ceq_index = PCI_FUNC(nesdev->pcidev->devfn);
- ceq = &nesadapter->ceq[nesdev->ceq_index];
- ceq->ceq_vbase = vmem;
- ceq->ceq_pbase = pmem;
- ceq->ceq_size = NES_CCEQ_SIZE;
- ceq->ceq_head = 0;
-
- vmem += max(((u32)sizeof(struct nes_hw_ceqe) * ceq->ceq_size), (u32)256);
- pmem += max(((u32)sizeof(struct nes_hw_ceqe) * ceq->ceq_size), (u32)256);
-
- nesdev->nic_ceq_index = PCI_FUNC(nesdev->pcidev->devfn) + 8;
- nic_ceq = &nesadapter->ceq[nesdev->nic_ceq_index];
- nic_ceq->ceq_vbase = vmem;
- nic_ceq->ceq_pbase = pmem;
- nic_ceq->ceq_size = NES_NIC_CEQ_SIZE;
- nic_ceq->ceq_head = 0;
-
- vmem += max(((u32)sizeof(struct nes_hw_ceqe) * nic_ceq->ceq_size), (u32)256);
- pmem += max(((u32)sizeof(struct nes_hw_ceqe) * nic_ceq->ceq_size), (u32)256);
-
- aeq = &nesadapter->aeq[PCI_FUNC(nesdev->pcidev->devfn)];
- aeq->aeq_vbase = vmem;
- aeq->aeq_pbase = pmem;
- aeq->aeq_size = nesadapter->max_qp;
- aeq->aeq_head = 0;
-
- /* Setup QP Context */
- vmem += (sizeof(struct nes_hw_aeqe) * aeq->aeq_size);
- pmem += (sizeof(struct nes_hw_aeqe) * aeq->aeq_size);
-
- cqp_qp_context = vmem;
- cqp_qp_context->context_words[0] =
- cpu_to_le32((PCI_FUNC(nesdev->pcidev->devfn) << 12) + (2 << 10));
- cqp_qp_context->context_words[1] = 0;
- cqp_qp_context->context_words[2] = cpu_to_le32((u32)nesdev->cqp.sq_pbase);
- cqp_qp_context->context_words[3] = cpu_to_le32(((u64)nesdev->cqp.sq_pbase) >> 32);
-
-
- /* Write the address to Create CQP */
- if ((sizeof(dma_addr_t) > 4)) {
- nes_write_indexed(nesdev,
- NES_IDX_CREATE_CQP_HIGH + (PCI_FUNC(nesdev->pcidev->devfn) * 8),
- ((u64)pmem) >> 32);
- } else {
- nes_write_indexed(nesdev,
- NES_IDX_CREATE_CQP_HIGH + (PCI_FUNC(nesdev->pcidev->devfn) * 8), 0);
- }
- nes_write_indexed(nesdev,
- NES_IDX_CREATE_CQP_LOW + (PCI_FUNC(nesdev->pcidev->devfn) * 8),
- (u32)pmem);
-
- INIT_LIST_HEAD(&nesdev->cqp_avail_reqs);
- INIT_LIST_HEAD(&nesdev->cqp_pending_reqs);
-
- for (count = 0; count < 2*NES_CQP_SQ_SIZE; count++) {
- init_waitqueue_head(&nesdev->nes_cqp_requests[count].waitq);
- list_add_tail(&nesdev->nes_cqp_requests[count].list, &nesdev->cqp_avail_reqs);
- }
-
- /* Write Create CCQ WQE */
- cqp_head = nesdev->cqp.sq_head++;
- cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
- nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
- (NES_CQP_CREATE_CQ | NES_CQP_CQ_CEQ_VALID |
- NES_CQP_CQ_CHK_OVERFLOW | ((u32)nesdev->ccq.cq_size << 16)));
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX,
- (nesdev->ccq.cq_number |
- ((u32)nesdev->ceq_index << 16)));
- u64temp = (u64)nesdev->ccq.cq_pbase;
- set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_PBL_LOW_IDX, u64temp);
- cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] = 0;
- u64temp = (unsigned long)&nesdev->ccq;
- cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX] =
- cpu_to_le32((u32)(u64temp >> 1));
- cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] =
- cpu_to_le32(((u32)((u64temp) >> 33)) & 0x7FFFFFFF);
- cqp_wqe->wqe_words[NES_CQP_CQ_WQE_DOORBELL_INDEX_HIGH_IDX] = 0;
-
- /* Write Create CEQ WQE */
- cqp_head = nesdev->cqp.sq_head++;
- cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
- nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
- (NES_CQP_CREATE_CEQ + ((u32)nesdev->ceq_index << 8)));
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_CEQ_WQE_ELEMENT_COUNT_IDX, ceq->ceq_size);
- u64temp = (u64)ceq->ceq_pbase;
- set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_PBL_LOW_IDX, u64temp);
-
- /* Write Create AEQ WQE */
- cqp_head = nesdev->cqp.sq_head++;
- cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
- nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
- (NES_CQP_CREATE_AEQ + ((u32)PCI_FUNC(nesdev->pcidev->devfn) << 8)));
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_AEQ_WQE_ELEMENT_COUNT_IDX, aeq->aeq_size);
- u64temp = (u64)aeq->aeq_pbase;
- set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_PBL_LOW_IDX, u64temp);
-
- /* Write Create NIC CEQ WQE */
- cqp_head = nesdev->cqp.sq_head++;
- cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
- nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
- (NES_CQP_CREATE_CEQ + ((u32)nesdev->nic_ceq_index << 8)));
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_CEQ_WQE_ELEMENT_COUNT_IDX, nic_ceq->ceq_size);
- u64temp = (u64)nic_ceq->ceq_pbase;
- set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_PBL_LOW_IDX, u64temp);
-
- /* Poll until CCQP done */
- count = 0;
- do {
- if (count++ > 1000) {
- printk(KERN_ERR PFX "Error creating CQP\n");
- pci_free_consistent(nesdev->pcidev, nesdev->cqp_mem_size,
- nesdev->cqp_vbase, nesdev->cqp_pbase);
- return -1;
- }
- udelay(10);
- } while (!(nes_read_indexed(nesdev,
- NES_IDX_QP_CONTROL + (PCI_FUNC(nesdev->pcidev->devfn) * 8)) & (1 << 8)));
-
- nes_debug(NES_DBG_INIT, "CQP Status = 0x%08X\n", nes_read_indexed(nesdev,
- NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8)));
-
- u32temp = 0x04800000;
- nes_write32(nesdev->regs+NES_WQE_ALLOC, u32temp | nesdev->cqp.qp_id);
-
- /* wait for the CCQ, CEQ, and AEQ to get created */
- count = 0;
- do {
- if (count++ > 1000) {
- printk(KERN_ERR PFX "Error creating CCQ, CEQ, and AEQ\n");
- pci_free_consistent(nesdev->pcidev, nesdev->cqp_mem_size,
- nesdev->cqp_vbase, nesdev->cqp_pbase);
- return -1;
- }
- udelay(10);
- } while (((nes_read_indexed(nesdev,
- NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8)) & (15<<8)) != (15<<8)));
-
- /* dump the QP status value */
- nes_debug(NES_DBG_INIT, "QP Status = 0x%08X\n", nes_read_indexed(nesdev,
- NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8)));
-
- nesdev->cqp.sq_tail++;
-
- return 0;
-}
-
-
-/**
- * nes_destroy_cqp
- */
-int nes_destroy_cqp(struct nes_device *nesdev)
-{
- struct nes_hw_cqp_wqe *cqp_wqe;
- u32 count = 0;
- u32 cqp_head;
- unsigned long flags;
-
- do {
- if (count++ > 1000)
- break;
- udelay(10);
- } while (!(nesdev->cqp.sq_head == nesdev->cqp.sq_tail));
-
- /* Reset CCQ */
- nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_RESET |
- nesdev->ccq.cq_number);
-
- /* Disable device interrupts */
- nes_write32(nesdev->regs+NES_INT_MASK, 0x7fffffff);
-
- spin_lock_irqsave(&nesdev->cqp.lock, flags);
-
- /* Destroy the AEQ */
- cqp_head = nesdev->cqp.sq_head++;
- nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
- cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
- cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_AEQ |
- ((u32)PCI_FUNC(nesdev->pcidev->devfn) << 8));
- cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0;
-
- /* Destroy the NIC CEQ */
- cqp_head = nesdev->cqp.sq_head++;
- nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
- cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
- cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_CEQ |
- ((u32)nesdev->nic_ceq_index << 8));
-
- /* Destroy the CEQ */
- cqp_head = nesdev->cqp.sq_head++;
- nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
- cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
- cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_CEQ |
- (nesdev->ceq_index << 8));
-
- /* Destroy the CCQ */
- cqp_head = nesdev->cqp.sq_head++;
- nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
- cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
- cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_CQ);
- cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesdev->ccq.cq_number |
- ((u32)nesdev->ceq_index << 16));
-
- /* Destroy CQP */
- cqp_head = nesdev->cqp.sq_head++;
- nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
- cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
- cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_QP |
- NES_CQP_QP_TYPE_CQP);
- cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesdev->cqp.qp_id);
-
- barrier();
- /* Ring doorbell (5 WQEs) */
- nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x05800000 | nesdev->cqp.qp_id);
-
- spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
-
- /* wait for the CCQ, CEQ, and AEQ to get destroyed */
- count = 0;
- do {
- if (count++ > 1000) {
- printk(KERN_ERR PFX "Function%d: Error destroying CCQ, CEQ, and AEQ\n",
- PCI_FUNC(nesdev->pcidev->devfn));
- break;
- }
- udelay(10);
- } while (((nes_read_indexed(nesdev,
- NES_IDX_QP_CONTROL + (PCI_FUNC(nesdev->pcidev->devfn)*8)) & (15 << 8)) != 0));
-
- /* dump the QP status value */
- nes_debug(NES_DBG_SHUTDOWN, "Function%d: QP Status = 0x%08X\n",
- PCI_FUNC(nesdev->pcidev->devfn),
- nes_read_indexed(nesdev,
- NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8)));
-
- kfree(nesdev->nes_cqp_requests);
-
- /* Free the control structures */
- pci_free_consistent(nesdev->pcidev, nesdev->cqp_mem_size, nesdev->cqp.sq_vbase,
- nesdev->cqp.sq_pbase);
-
- return 0;
-}
-
-
-/**
- * nes_init_1g_phy
- */
-static int nes_init_1g_phy(struct nes_device *nesdev, u8 phy_type, u8 phy_index)
-{
- u32 counter = 0;
- u16 phy_data;
- int ret = 0;
-
- nes_read_1G_phy_reg(nesdev, 1, phy_index, &phy_data);
- nes_write_1G_phy_reg(nesdev, 23, phy_index, 0xb000);
-
- /* Reset the PHY */
- nes_write_1G_phy_reg(nesdev, 0, phy_index, 0x8000);
- udelay(100);
- counter = 0;
- do {
- nes_read_1G_phy_reg(nesdev, 0, phy_index, &phy_data);
- if (counter++ > 100) {
- ret = -1;
- break;
- }
- } while (phy_data & 0x8000);
-
- /* Setting no phy loopback */
- phy_data &= 0xbfff;
- phy_data |= 0x1140;
- nes_write_1G_phy_reg(nesdev, 0, phy_index, phy_data);
- nes_read_1G_phy_reg(nesdev, 0, phy_index, &phy_data);
- nes_read_1G_phy_reg(nesdev, 0x17, phy_index, &phy_data);
- nes_read_1G_phy_reg(nesdev, 0x1e, phy_index, &phy_data);
-
- /* Setting the interrupt mask */
- nes_read_1G_phy_reg(nesdev, 0x19, phy_index, &phy_data);
- nes_write_1G_phy_reg(nesdev, 0x19, phy_index, 0xffee);
- nes_read_1G_phy_reg(nesdev, 0x19, phy_index, &phy_data);
-
- /* turning on flow control */
- nes_read_1G_phy_reg(nesdev, 4, phy_index, &phy_data);
- nes_write_1G_phy_reg(nesdev, 4, phy_index, (phy_data & ~(0x03E0)) | 0xc00);
- nes_read_1G_phy_reg(nesdev, 4, phy_index, &phy_data);
-
- /* Clear Half duplex */
- nes_read_1G_phy_reg(nesdev, 9, phy_index, &phy_data);
- nes_write_1G_phy_reg(nesdev, 9, phy_index, phy_data & ~(0x0100));
- nes_read_1G_phy_reg(nesdev, 9, phy_index, &phy_data);
-
- nes_read_1G_phy_reg(nesdev, 0, phy_index, &phy_data);
- nes_write_1G_phy_reg(nesdev, 0, phy_index, phy_data | 0x0300);
-
- return ret;
-}
-
-
-/**
- * nes_init_2025_phy
- */
-static int nes_init_2025_phy(struct nes_device *nesdev, u8 phy_type, u8 phy_index)
-{
- u32 temp_phy_data = 0;
- u32 temp_phy_data2 = 0;
- u32 counter = 0;
- u32 sds;
- u32 mac_index = nesdev->mac_index;
- int ret = 0;
- unsigned int first_attempt = 1;
-
- /* Check firmware heartbeat */
- nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7ee);
- temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
- udelay(1500);
- nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7ee);
- temp_phy_data2 = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
-
- if (temp_phy_data != temp_phy_data2) {
- nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7fd);
- temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
- if ((temp_phy_data & 0xff) > 0x20)
- return 0;
- printk(PFX "Reinitialize external PHY\n");
- }
-
- /* no heartbeat, configure the PHY */
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0x0000, 0x8000);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc300, 0x0000);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc316, 0x000A);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc318, 0x0052);
-
- switch (phy_type) {
- case NES_PHY_TYPE_ARGUS:
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc316, 0x000A);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc318, 0x0052);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc302, 0x000C);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc319, 0x0008);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0027, 0x0001);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc31a, 0x0098);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0026, 0x0E00);
-
- /* setup LEDs */
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd006, 0x0007);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd007, 0x000A);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd008, 0x0009);
- break;
-
- case NES_PHY_TYPE_SFP_D:
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc316, 0x000A);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc318, 0x0052);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc302, 0x0004);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc319, 0x0038);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0027, 0x0013);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc31a, 0x0098);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0026, 0x0E00);
-
- /* setup LEDs */
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd006, 0x0007);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd007, 0x000A);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd008, 0x0009);
- break;
-
- case NES_PHY_TYPE_KR:
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc316, 0x000A);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc318, 0x0052);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc302, 0x000C);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc319, 0x0010);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0027, 0x0013);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc31a, 0x0080);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0026, 0x0E00);
-
- /* setup LEDs */
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd006, 0x000B);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd007, 0x0003);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd008, 0x0004);
-
- nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0022, 0x406D);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0023, 0x0020);
- break;
- }
-
- nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0028, 0xA528);
-
- /* Bring PHY out of reset */
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc300, 0x0002);
-
- /* Check for heartbeat */
- counter = 0;
- mdelay(690);
- nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7ee);
- temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
- do {
- if (counter++ > 150) {
- printk(PFX "No PHY heartbeat\n");
- break;
- }
- mdelay(1);
- nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7ee);
- temp_phy_data2 = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
- } while (temp_phy_data2 == temp_phy_data);
-
- /* wait for tracking */
- counter = 0;
- do {
- nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7fd);
- temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
- if (counter++ > 300) {
- if (((temp_phy_data & 0xff) == 0x0) && first_attempt) {
- first_attempt = 0;
- counter = 0;
- /* reset AMCC PHY and try again */
- nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0xe854, 0x00c0);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0xe854, 0x0040);
- continue;
- } else {
- ret = 1;
- break;
- }
- }
- mdelay(10);
- } while ((temp_phy_data & 0xff) < 0x30);
-
- /* setup signal integrity */
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd003, 0x0000);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xF00D, 0x00FE);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xF00E, 0x0032);
- if (phy_type == NES_PHY_TYPE_KR) {
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xF00F, 0x000C);
- } else {
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xF00F, 0x0002);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc314, 0x0063);
- }
-
- /* reset serdes */
- sds = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0 + mac_index * 0x200);
- sds |= 0x1;
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0 + mac_index * 0x200, sds);
- sds &= 0xfffffffe;
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0 + mac_index * 0x200, sds);
-
- counter = 0;
- while (((nes_read32(nesdev->regs + NES_SOFTWARE_RESET) & 0x00000040) != 0x00000040)
- && (counter++ < 5000))
- ;
-
- return ret;
-}
-
-
-/**
- * nes_init_phy
- */
-int nes_init_phy(struct nes_device *nesdev)
-{
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- u32 mac_index = nesdev->mac_index;
- u32 tx_config = 0;
- unsigned long flags;
- u8 phy_type = nesadapter->phy_type[mac_index];
- u8 phy_index = nesadapter->phy_index[mac_index];
- int ret = 0;
-
- tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG);
- if (phy_type == NES_PHY_TYPE_1G) {
- /* setup 1G MDIO operation */
- tx_config &= 0xFFFFFFE3;
- tx_config |= 0x04;
- } else {
- /* setup 10G MDIO operation */
- tx_config &= 0xFFFFFFE3;
- tx_config |= 0x1D;
- }
- nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config);
-
- spin_lock_irqsave(&nesdev->nesadapter->phy_lock, flags);
-
- switch (phy_type) {
- case NES_PHY_TYPE_1G:
- ret = nes_init_1g_phy(nesdev, phy_type, phy_index);
- break;
- case NES_PHY_TYPE_ARGUS:
- case NES_PHY_TYPE_SFP_D:
- case NES_PHY_TYPE_KR:
- ret = nes_init_2025_phy(nesdev, phy_type, phy_index);
- break;
- }
-
- spin_unlock_irqrestore(&nesdev->nesadapter->phy_lock, flags);
-
- return ret;
-}
-
-
-/**
- * nes_replenish_nic_rq
- */
-static void nes_replenish_nic_rq(struct nes_vnic *nesvnic)
-{
- unsigned long flags;
- dma_addr_t bus_address;
- struct sk_buff *skb;
- struct nes_hw_nic_rq_wqe *nic_rqe;
- struct nes_hw_nic *nesnic;
- struct nes_device *nesdev;
- struct nes_rskb_cb *cb;
- u32 rx_wqes_posted = 0;
-
- nesnic = &nesvnic->nic;
- nesdev = nesvnic->nesdev;
- spin_lock_irqsave(&nesnic->rq_lock, flags);
- if (nesnic->replenishing_rq !=0) {
- if (((nesnic->rq_size-1) == atomic_read(&nesvnic->rx_skbs_needed)) &&
- (atomic_read(&nesvnic->rx_skb_timer_running) == 0)) {
- atomic_set(&nesvnic->rx_skb_timer_running, 1);
- spin_unlock_irqrestore(&nesnic->rq_lock, flags);
- nesvnic->rq_wqes_timer.expires = jiffies + (HZ/2); /* 1/2 second */
- add_timer(&nesvnic->rq_wqes_timer);
- } else
- spin_unlock_irqrestore(&nesnic->rq_lock, flags);
- return;
- }
- nesnic->replenishing_rq = 1;
- spin_unlock_irqrestore(&nesnic->rq_lock, flags);
- do {
- skb = dev_alloc_skb(nesvnic->max_frame_size);
- if (skb) {
- skb->dev = nesvnic->netdev;
-
- bus_address = pci_map_single(nesdev->pcidev,
- skb->data, nesvnic->max_frame_size, PCI_DMA_FROMDEVICE);
- cb = (struct nes_rskb_cb *)&skb->cb[0];
- cb->busaddr = bus_address;
- cb->maplen = nesvnic->max_frame_size;
-
- nic_rqe = &nesnic->rq_vbase[nesvnic->nic.rq_head];
- nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] =
- cpu_to_le32(nesvnic->max_frame_size);
- nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_3_2_IDX] = 0;
- nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX] =
- cpu_to_le32((u32)bus_address);
- nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX] =
- cpu_to_le32((u32)((u64)bus_address >> 32));
- nesnic->rx_skb[nesnic->rq_head] = skb;
- nesnic->rq_head++;
- nesnic->rq_head &= nesnic->rq_size - 1;
- atomic_dec(&nesvnic->rx_skbs_needed);
- barrier();
- if (++rx_wqes_posted == 255) {
- nes_write32(nesdev->regs+NES_WQE_ALLOC, (rx_wqes_posted << 24) | nesnic->qp_id);
- rx_wqes_posted = 0;
- }
- } else {
- spin_lock_irqsave(&nesnic->rq_lock, flags);
- if (((nesnic->rq_size-1) == atomic_read(&nesvnic->rx_skbs_needed)) &&
- (atomic_read(&nesvnic->rx_skb_timer_running) == 0)) {
- atomic_set(&nesvnic->rx_skb_timer_running, 1);
- spin_unlock_irqrestore(&nesnic->rq_lock, flags);
- nesvnic->rq_wqes_timer.expires = jiffies + (HZ/2); /* 1/2 second */
- add_timer(&nesvnic->rq_wqes_timer);
- } else
- spin_unlock_irqrestore(&nesnic->rq_lock, flags);
- break;
- }
- } while (atomic_read(&nesvnic->rx_skbs_needed));
- barrier();
- if (rx_wqes_posted)
- nes_write32(nesdev->regs+NES_WQE_ALLOC, (rx_wqes_posted << 24) | nesnic->qp_id);
- nesnic->replenishing_rq = 0;
-}
-
-
-/**
- * nes_rq_wqes_timeout
- */
-static void nes_rq_wqes_timeout(struct timer_list *t)
-{
- struct nes_vnic *nesvnic = from_timer(nesvnic, t, rq_wqes_timer);
- printk("%s: Timer fired.\n", __func__);
- atomic_set(&nesvnic->rx_skb_timer_running, 0);
- if (atomic_read(&nesvnic->rx_skbs_needed))
- nes_replenish_nic_rq(nesvnic);
-}
-
-
-/**
- * nes_init_nic_qp
- */
-int nes_init_nic_qp(struct nes_device *nesdev, struct net_device *netdev)
-{
- struct nes_hw_cqp_wqe *cqp_wqe;
- struct nes_hw_nic_sq_wqe *nic_sqe;
- struct nes_hw_nic_qp_context *nic_context;
- struct sk_buff *skb;
- struct nes_hw_nic_rq_wqe *nic_rqe;
- struct nes_vnic *nesvnic = netdev_priv(netdev);
- unsigned long flags;
- void *vmem;
- dma_addr_t pmem;
- u64 u64temp;
- int ret;
- u32 cqp_head;
- u32 counter;
- u32 wqe_count;
- struct nes_rskb_cb *cb;
- u8 jumbomode=0;
-
- /* Allocate fragment, SQ, RQ, and CQ; Reuse CEQ based on the PCI function */
- nesvnic->nic_mem_size = 256 +
- (NES_NIC_WQ_SIZE * sizeof(struct nes_first_frag)) +
- (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_sq_wqe)) +
- (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_rq_wqe)) +
- (NES_NIC_WQ_SIZE * 2 * sizeof(struct nes_hw_nic_cqe)) +
- sizeof(struct nes_hw_nic_qp_context);
-
- nesvnic->nic_vbase = pci_zalloc_consistent(nesdev->pcidev,
- nesvnic->nic_mem_size,
- &nesvnic->nic_pbase);
- if (!nesvnic->nic_vbase) {
- nes_debug(NES_DBG_INIT, "Unable to allocate memory for NIC host descriptor rings\n");
- return -ENOMEM;
- }
- nes_debug(NES_DBG_INIT, "Allocated NIC QP structures at %p (phys = %016lX), size = %u.\n",
- nesvnic->nic_vbase, (unsigned long)nesvnic->nic_pbase, nesvnic->nic_mem_size);
-
- vmem = (void *)(((unsigned long)nesvnic->nic_vbase + (256 - 1)) &
- ~(unsigned long)(256 - 1));
- pmem = (dma_addr_t)(((unsigned long long)nesvnic->nic_pbase + (256 - 1)) &
- ~(unsigned long long)(256 - 1));
-
- /* Setup the first Fragment buffers */
- nesvnic->nic.first_frag_vbase = vmem;
-
- for (counter = 0; counter < NES_NIC_WQ_SIZE; counter++) {
- nesvnic->nic.frag_paddr[counter] = pmem;
- pmem += sizeof(struct nes_first_frag);
- }
-
- /* setup the SQ */
- vmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_first_frag));
-
- nesvnic->nic.sq_vbase = (void *)vmem;
- nesvnic->nic.sq_pbase = pmem;
- nesvnic->nic.sq_head = 0;
- nesvnic->nic.sq_tail = 0;
- nesvnic->nic.sq_size = NES_NIC_WQ_SIZE;
- for (counter = 0; counter < NES_NIC_WQ_SIZE; counter++) {
- nic_sqe = &nesvnic->nic.sq_vbase[counter];
- nic_sqe->wqe_words[NES_NIC_SQ_WQE_MISC_IDX] =
- cpu_to_le32(NES_NIC_SQ_WQE_DISABLE_CHKSUM |
- NES_NIC_SQ_WQE_COMPLETION);
- nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX] =
- cpu_to_le32((u32)NES_FIRST_FRAG_SIZE << 16);
- nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX] =
- cpu_to_le32((u32)nesvnic->nic.frag_paddr[counter]);
- nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX] =
- cpu_to_le32((u32)((u64)nesvnic->nic.frag_paddr[counter] >> 32));
- }
-
- nesvnic->get_cqp_request = nes_get_cqp_request;
- nesvnic->post_cqp_request = nes_post_cqp_request;
- nesvnic->mcrq_mcast_filter = NULL;
-
- spin_lock_init(&nesvnic->nic.rq_lock);
-
- /* setup the RQ */
- vmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_sq_wqe));
- pmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_sq_wqe));
-
-
- nesvnic->nic.rq_vbase = vmem;
- nesvnic->nic.rq_pbase = pmem;
- nesvnic->nic.rq_head = 0;
- nesvnic->nic.rq_tail = 0;
- nesvnic->nic.rq_size = NES_NIC_WQ_SIZE;
-
- /* setup the CQ */
- vmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_rq_wqe));
- pmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_rq_wqe));
-
- if (nesdev->nesadapter->netdev_count > 2)
- nesvnic->mcrq_qp_id = nesvnic->nic_index + 32;
- else
- nesvnic->mcrq_qp_id = nesvnic->nic.qp_id + 4;
-
- nesvnic->nic_cq.cq_vbase = vmem;
- nesvnic->nic_cq.cq_pbase = pmem;
- nesvnic->nic_cq.cq_head = 0;
- nesvnic->nic_cq.cq_size = NES_NIC_WQ_SIZE * 2;
-
- nesvnic->nic_cq.ce_handler = nes_nic_napi_ce_handler;
-
- /* Send CreateCQ request to CQP */
- spin_lock_irqsave(&nesdev->cqp.lock, flags);
- cqp_head = nesdev->cqp.sq_head;
-
- cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
- nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
-
- cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(
- NES_CQP_CREATE_CQ | NES_CQP_CQ_CEQ_VALID |
- ((u32)nesvnic->nic_cq.cq_size << 16));
- cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(
- nesvnic->nic_cq.cq_number | ((u32)nesdev->nic_ceq_index << 16));
- u64temp = (u64)nesvnic->nic_cq.cq_pbase;
- set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_PBL_LOW_IDX, u64temp);
- cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] = 0;
- u64temp = (unsigned long)&nesvnic->nic_cq;
- cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX] = cpu_to_le32((u32)(u64temp >> 1));
- cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] =
- cpu_to_le32(((u32)((u64temp) >> 33)) & 0x7FFFFFFF);
- cqp_wqe->wqe_words[NES_CQP_CQ_WQE_DOORBELL_INDEX_HIGH_IDX] = 0;
- if (++cqp_head >= nesdev->cqp.sq_size)
- cqp_head = 0;
- cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
- nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
-
- /* Send CreateQP request to CQP */
- nic_context = (void *)(&nesvnic->nic_cq.cq_vbase[nesvnic->nic_cq.cq_size]);
- nic_context->context_words[NES_NIC_CTX_MISC_IDX] =
- cpu_to_le32((u32)NES_NIC_CTX_SIZE |
- ((u32)PCI_FUNC(nesdev->pcidev->devfn) << 12));
- nes_debug(NES_DBG_INIT, "RX_WINDOW_BUFFER_PAGE_TABLE_SIZE = 0x%08X, RX_WINDOW_BUFFER_SIZE = 0x%08X\n",
- nes_read_indexed(nesdev, NES_IDX_RX_WINDOW_BUFFER_PAGE_TABLE_SIZE),
- nes_read_indexed(nesdev, NES_IDX_RX_WINDOW_BUFFER_SIZE));
- if (nes_read_indexed(nesdev, NES_IDX_RX_WINDOW_BUFFER_SIZE) != 0) {
- nic_context->context_words[NES_NIC_CTX_MISC_IDX] |= cpu_to_le32(NES_NIC_BACK_STORE);
- }
-
- u64temp = (u64)nesvnic->nic.sq_pbase;
- nic_context->context_words[NES_NIC_CTX_SQ_LOW_IDX] = cpu_to_le32((u32)u64temp);
- nic_context->context_words[NES_NIC_CTX_SQ_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32));
- u64temp = (u64)nesvnic->nic.rq_pbase;
- nic_context->context_words[NES_NIC_CTX_RQ_LOW_IDX] = cpu_to_le32((u32)u64temp);
- nic_context->context_words[NES_NIC_CTX_RQ_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32));
-
- cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_CREATE_QP |
- NES_CQP_QP_TYPE_NIC);
- cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesvnic->nic.qp_id);
- u64temp = (u64)nesvnic->nic_cq.cq_pbase +
- (nesvnic->nic_cq.cq_size * sizeof(struct nes_hw_nic_cqe));
- set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_CONTEXT_LOW_IDX, u64temp);
-
- if (++cqp_head >= nesdev->cqp.sq_size)
- cqp_head = 0;
- nesdev->cqp.sq_head = cqp_head;
-
- barrier();
-
- /* Ring doorbell (2 WQEs) */
- nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x02800000 | nesdev->cqp.qp_id);
-
- spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
- nes_debug(NES_DBG_INIT, "Waiting for create NIC QP%u to complete.\n",
- nesvnic->nic.qp_id);
-
- ret = wait_event_timeout(nesdev->cqp.waitq, (nesdev->cqp.sq_tail == cqp_head),
- NES_EVENT_TIMEOUT);
- nes_debug(NES_DBG_INIT, "Create NIC QP%u completed, wait_event_timeout ret = %u.\n",
- nesvnic->nic.qp_id, ret);
- if (!ret) {
- nes_debug(NES_DBG_INIT, "NIC QP%u create timeout expired\n", nesvnic->nic.qp_id);
- pci_free_consistent(nesdev->pcidev, nesvnic->nic_mem_size, nesvnic->nic_vbase,
- nesvnic->nic_pbase);
- return -EIO;
- }
-
- /* Populate the RQ */
- for (counter = 0; counter < (NES_NIC_WQ_SIZE - 1); counter++) {
- skb = dev_alloc_skb(nesvnic->max_frame_size);
- if (!skb) {
- nes_debug(NES_DBG_INIT, "%s: out of memory for receive skb\n", netdev->name);
-
- nes_destroy_nic_qp(nesvnic);
- return -ENOMEM;
- }
-
- skb->dev = netdev;
-
- pmem = pci_map_single(nesdev->pcidev, skb->data,
- nesvnic->max_frame_size, PCI_DMA_FROMDEVICE);
- cb = (struct nes_rskb_cb *)&skb->cb[0];
- cb->busaddr = pmem;
- cb->maplen = nesvnic->max_frame_size;
-
- nic_rqe = &nesvnic->nic.rq_vbase[counter];
- nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] = cpu_to_le32(nesvnic->max_frame_size);
- nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_3_2_IDX] = 0;
- nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX] = cpu_to_le32((u32)pmem);
- nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX] = cpu_to_le32((u32)((u64)pmem >> 32));
- nesvnic->nic.rx_skb[counter] = skb;
- }
-
- wqe_count = NES_NIC_WQ_SIZE - 1;
- nesvnic->nic.rq_head = wqe_count;
- barrier();
- do {
- counter = min(wqe_count, ((u32)255));
- wqe_count -= counter;
- nes_write32(nesdev->regs+NES_WQE_ALLOC, (counter << 24) | nesvnic->nic.qp_id);
- } while (wqe_count);
- timer_setup(&nesvnic->rq_wqes_timer, nes_rq_wqes_timeout, 0);
- nes_debug(NES_DBG_INIT, "NAPI support Enabled\n");
- if (nesdev->nesadapter->et_use_adaptive_rx_coalesce)
- {
- nes_nic_init_timer(nesdev);
- if (netdev->mtu > 1500)
- jumbomode = 1;
- nes_nic_init_timer_defaults(nesdev, jumbomode);
- }
- if ((nesdev->nesadapter->allow_unaligned_fpdus) &&
- (nes_init_mgt_qp(nesdev, netdev, nesvnic))) {
- nes_debug(NES_DBG_INIT, "%s: Out of memory for pau nic\n",
- netdev->name);
- nes_destroy_nic_qp(nesvnic);
- return -ENOMEM;
- }
-
- return 0;
-}
-
-
-/**
- * nes_destroy_nic_qp
- */
-void nes_destroy_nic_qp(struct nes_vnic *nesvnic)
-{
- u64 u64temp;
- dma_addr_t bus_address;
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_hw_cqp_wqe *cqp_wqe;
- struct nes_hw_nic_sq_wqe *nic_sqe;
- __le16 *wqe_fragment_length;
- u16 wqe_fragment_index;
- u32 cqp_head;
- u32 wqm_cfg0;
- unsigned long flags;
- struct sk_buff *rx_skb;
- struct nes_rskb_cb *cb;
- int ret;
-
- if (nesdev->nesadapter->allow_unaligned_fpdus)
- nes_destroy_mgt(nesvnic);
-
- /* clear wqe stall before destroying NIC QP */
- wqm_cfg0 = nes_read_indexed(nesdev, NES_IDX_WQM_CONFIG0);
- nes_write_indexed(nesdev, NES_IDX_WQM_CONFIG0, wqm_cfg0 & 0xFFFF7FFF);
-
- /* Free remaining NIC receive buffers */
- while (nesvnic->nic.rq_head != nesvnic->nic.rq_tail) {
- rx_skb = nesvnic->nic.rx_skb[nesvnic->nic.rq_tail];
- cb = (struct nes_rskb_cb *)&rx_skb->cb[0];
- pci_unmap_single(nesdev->pcidev, cb->busaddr, cb->maplen,
- PCI_DMA_FROMDEVICE);
-
- dev_kfree_skb(nesvnic->nic.rx_skb[nesvnic->nic.rq_tail++]);
- nesvnic->nic.rq_tail &= (nesvnic->nic.rq_size - 1);
- }
-
- /* Free remaining NIC transmit buffers */
- while (nesvnic->nic.sq_head != nesvnic->nic.sq_tail) {
- nic_sqe = &nesvnic->nic.sq_vbase[nesvnic->nic.sq_tail];
- wqe_fragment_index = 1;
- wqe_fragment_length = (__le16 *)
- &nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX];
- /* bump past the vlan tag */
- wqe_fragment_length++;
- if (le16_to_cpu(wqe_fragment_length[wqe_fragment_index]) != 0) {
- u64temp = (u64)le32_to_cpu(
- nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX+
- wqe_fragment_index*2]);
- u64temp += ((u64)le32_to_cpu(
- nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX
- + wqe_fragment_index*2]))<<32;
- bus_address = (dma_addr_t)u64temp;
- if (test_and_clear_bit(nesvnic->nic.sq_tail,
- nesvnic->nic.first_frag_overflow)) {
- pci_unmap_single(nesdev->pcidev,
- bus_address,
- le16_to_cpu(wqe_fragment_length[
- wqe_fragment_index++]),
- PCI_DMA_TODEVICE);
- }
- for (; wqe_fragment_index < 5; wqe_fragment_index++) {
- if (wqe_fragment_length[wqe_fragment_index]) {
- u64temp = le32_to_cpu(
- nic_sqe->wqe_words[
- NES_NIC_SQ_WQE_FRAG0_LOW_IDX+
- wqe_fragment_index*2]);
- u64temp += ((u64)le32_to_cpu(
- nic_sqe->wqe_words[
- NES_NIC_SQ_WQE_FRAG0_HIGH_IDX+
- wqe_fragment_index*2]))<<32;
- bus_address = (dma_addr_t)u64temp;
- pci_unmap_page(nesdev->pcidev,
- bus_address,
- le16_to_cpu(
- wqe_fragment_length[
- wqe_fragment_index]),
- PCI_DMA_TODEVICE);
- } else
- break;
- }
- }
- if (nesvnic->nic.tx_skb[nesvnic->nic.sq_tail])
- dev_kfree_skb(
- nesvnic->nic.tx_skb[nesvnic->nic.sq_tail]);
-
- nesvnic->nic.sq_tail = (nesvnic->nic.sq_tail + 1)
- & (nesvnic->nic.sq_size - 1);
- }
-
- spin_lock_irqsave(&nesdev->cqp.lock, flags);
-
- /* Destroy NIC QP */
- cqp_head = nesdev->cqp.sq_head;
- cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
- nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
-
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
- (NES_CQP_DESTROY_QP | NES_CQP_QP_TYPE_NIC));
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX,
- nesvnic->nic.qp_id);
-
- if (++cqp_head >= nesdev->cqp.sq_size)
- cqp_head = 0;
-
- cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
-
- /* Destroy NIC CQ */
- nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
- (NES_CQP_DESTROY_CQ | ((u32)nesvnic->nic_cq.cq_size << 16)));
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX,
- (nesvnic->nic_cq.cq_number | ((u32)nesdev->nic_ceq_index << 16)));
-
- if (++cqp_head >= nesdev->cqp.sq_size)
- cqp_head = 0;
-
- nesdev->cqp.sq_head = cqp_head;
- barrier();
-
- /* Ring doorbell (2 WQEs) */
- nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x02800000 | nesdev->cqp.qp_id);
-
- spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
- nes_debug(NES_DBG_SHUTDOWN, "Waiting for CQP, cqp_head=%u, cqp.sq_head=%u,"
- " cqp.sq_tail=%u, cqp.sq_size=%u\n",
- cqp_head, nesdev->cqp.sq_head,
- nesdev->cqp.sq_tail, nesdev->cqp.sq_size);
-
- ret = wait_event_timeout(nesdev->cqp.waitq, (nesdev->cqp.sq_tail == cqp_head),
- NES_EVENT_TIMEOUT);
-
- nes_debug(NES_DBG_SHUTDOWN, "Destroy NIC QP returned, wait_event_timeout ret = %u, cqp_head=%u,"
- " cqp.sq_head=%u, cqp.sq_tail=%u\n",
- ret, cqp_head, nesdev->cqp.sq_head, nesdev->cqp.sq_tail);
- if (!ret) {
- nes_debug(NES_DBG_SHUTDOWN, "NIC QP%u destroy timeout expired\n",
- nesvnic->nic.qp_id);
- }
-
- pci_free_consistent(nesdev->pcidev, nesvnic->nic_mem_size, nesvnic->nic_vbase,
- nesvnic->nic_pbase);
-
- /* restore old wqm_cfg0 value */
- nes_write_indexed(nesdev, NES_IDX_WQM_CONFIG0, wqm_cfg0);
-}
-
-/**
- * nes_napi_isr
- */
-int nes_napi_isr(struct nes_device *nesdev)
-{
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- u32 int_stat;
-
- if (nesdev->napi_isr_ran) {
- /* interrupt status has already been read in ISR */
- int_stat = nesdev->int_stat;
- } else {
- int_stat = nes_read32(nesdev->regs + NES_INT_STAT);
- nesdev->int_stat = int_stat;
- nesdev->napi_isr_ran = 1;
- }
-
- int_stat &= nesdev->int_req;
- /* iff NIC, process here, else wait for DPC */
- if ((int_stat) && ((int_stat & 0x0000ff00) == int_stat)) {
- nesdev->napi_isr_ran = 0;
- nes_write32(nesdev->regs + NES_INT_STAT,
- (int_stat &
- ~(NES_INT_INTF | NES_INT_TIMER | NES_INT_MAC0 | NES_INT_MAC1 | NES_INT_MAC2 | NES_INT_MAC3)));
-
- /* Process the CEQs */
- nes_process_ceq(nesdev, &nesdev->nesadapter->ceq[nesdev->nic_ceq_index]);
-
- if (unlikely((((nesadapter->et_rx_coalesce_usecs_irq) &&
- (!nesadapter->et_use_adaptive_rx_coalesce)) ||
- ((nesadapter->et_use_adaptive_rx_coalesce) &&
- (nesdev->deepcq_count > nesadapter->et_pkt_rate_low))))) {
- if ((nesdev->int_req & NES_INT_TIMER) == 0) {
- /* Enable Periodic timer interrupts */
- nesdev->int_req |= NES_INT_TIMER;
- /* ack any pending periodic timer interrupts so we don't get an immediate interrupt */
- /* TODO: need to also ack other unused periodic timer values, get from nesadapter */
- nes_write32(nesdev->regs+NES_TIMER_STAT,
- nesdev->timer_int_req | ~(nesdev->nesadapter->timer_int_req));
- nes_write32(nesdev->regs+NES_INTF_INT_MASK,
- ~(nesdev->intf_int_req | NES_INTF_PERIODIC_TIMER));
- }
-
- if (unlikely(nesadapter->et_use_adaptive_rx_coalesce))
- {
- nes_nic_init_timer(nesdev);
- }
- /* Enable interrupts, except CEQs */
- nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff | (~nesdev->int_req));
- } else {
- /* Enable interrupts, make sure timer is off */
- nesdev->int_req &= ~NES_INT_TIMER;
- nes_write32(nesdev->regs+NES_INTF_INT_MASK, ~(nesdev->intf_int_req));
- nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
- }
- nesdev->deepcq_count = 0;
- return 1;
- } else {
- return 0;
- }
-}
-
-static void process_critical_error(struct nes_device *nesdev)
-{
- u32 debug_error;
- u32 nes_idx_debug_error_masks0 = 0;
- u16 error_module = 0;
-
- debug_error = nes_read_indexed(nesdev, NES_IDX_DEBUG_ERROR_CONTROL_STATUS);
- printk(KERN_ERR PFX "Critical Error reported by device!!! 0x%02X\n",
- (u16)debug_error);
- nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_CONTROL_STATUS,
- 0x01010000 | (debug_error & 0x0000ffff));
- if (crit_err_count++ > 10)
- nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS1, 1 << 0x17);
- error_module = (u16) (debug_error & 0x1F00) >> 8;
- if (++nesdev->nesadapter->crit_error_count[error_module-1] >=
- nes_max_critical_error_count) {
- printk(KERN_ERR PFX "Masking off critical error for module "
- "0x%02X\n", (u16)error_module);
- nes_idx_debug_error_masks0 = nes_read_indexed(nesdev,
- NES_IDX_DEBUG_ERROR_MASKS0);
- nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS0,
- nes_idx_debug_error_masks0 | (1 << error_module));
- }
-}
-/**
- * nes_dpc
- */
-void nes_dpc(unsigned long param)
-{
- struct nes_device *nesdev = (struct nes_device *)param;
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- u32 counter;
- u32 loop_counter = 0;
- u32 int_status_bit;
- u32 int_stat;
- u32 timer_stat;
- u32 temp_int_stat;
- u32 intf_int_stat;
- u32 processed_intf_int = 0;
- u16 processed_timer_int = 0;
- u16 completion_ints = 0;
- u16 timer_ints = 0;
-
- /* nes_debug(NES_DBG_ISR, "\n"); */
-
- do {
- timer_stat = 0;
- if (nesdev->napi_isr_ran) {
- nesdev->napi_isr_ran = 0;
- int_stat = nesdev->int_stat;
- } else
- int_stat = nes_read32(nesdev->regs+NES_INT_STAT);
- if (processed_intf_int != 0)
- int_stat &= nesdev->int_req & ~NES_INT_INTF;
- else
- int_stat &= nesdev->int_req;
- if (processed_timer_int == 0) {
- processed_timer_int = 1;
- if (int_stat & NES_INT_TIMER) {
- timer_stat = nes_read32(nesdev->regs + NES_TIMER_STAT);
- if ((timer_stat & nesdev->timer_int_req) == 0) {
- int_stat &= ~NES_INT_TIMER;
- }
- }
- } else {
- int_stat &= ~NES_INT_TIMER;
- }
-
- if (int_stat) {
- if (int_stat & ~(NES_INT_INTF | NES_INT_TIMER | NES_INT_MAC0|
- NES_INT_MAC1|NES_INT_MAC2 | NES_INT_MAC3)) {
- /* Ack the interrupts */
- nes_write32(nesdev->regs+NES_INT_STAT,
- (int_stat & ~(NES_INT_INTF | NES_INT_TIMER | NES_INT_MAC0|
- NES_INT_MAC1 | NES_INT_MAC2 | NES_INT_MAC3)));
- }
-
- temp_int_stat = int_stat;
- for (counter = 0, int_status_bit = 1; counter < 16; counter++) {
- if (int_stat & int_status_bit) {
- nes_process_ceq(nesdev, &nesadapter->ceq[counter]);
- temp_int_stat &= ~int_status_bit;
- completion_ints = 1;
- }
- if (!(temp_int_stat & 0x0000ffff))
- break;
- int_status_bit <<= 1;
- }
-
- /* Process the AEQ for this pci function */
- int_status_bit = 1 << (16 + PCI_FUNC(nesdev->pcidev->devfn));
- if (int_stat & int_status_bit) {
- nes_process_aeq(nesdev, &nesadapter->aeq[PCI_FUNC(nesdev->pcidev->devfn)]);
- }
-
- /* Process the MAC interrupt for this pci function */
- int_status_bit = 1 << (24 + nesdev->mac_index);
- if (int_stat & int_status_bit) {
- nes_process_mac_intr(nesdev, nesdev->mac_index);
- }
-
- if (int_stat & NES_INT_TIMER) {
- if (timer_stat & nesdev->timer_int_req) {
- nes_write32(nesdev->regs + NES_TIMER_STAT,
- (timer_stat & nesdev->timer_int_req) |
- ~(nesdev->nesadapter->timer_int_req));
- timer_ints = 1;
- }
- }
-
- if (int_stat & NES_INT_INTF) {
- processed_intf_int = 1;
- intf_int_stat = nes_read32(nesdev->regs+NES_INTF_INT_STAT);
- intf_int_stat &= nesdev->intf_int_req;
- if (NES_INTF_INT_CRITERR & intf_int_stat) {
- process_critical_error(nesdev);
- }
- if (NES_INTF_INT_PCIERR & intf_int_stat) {
- printk(KERN_ERR PFX "PCI Error reported by device!!!\n");
- BUG();
- }
- if (NES_INTF_INT_AEQ_OFLOW & intf_int_stat) {
- printk(KERN_ERR PFX "AEQ Overflow reported by device!!!\n");
- BUG();
- }
- nes_write32(nesdev->regs+NES_INTF_INT_STAT, intf_int_stat);
- }
-
- if (int_stat & NES_INT_TSW) {
- }
- }
- /* Don't use the interface interrupt bit stay in loop */
- int_stat &= ~NES_INT_INTF | NES_INT_TIMER | NES_INT_MAC0 |
- NES_INT_MAC1 | NES_INT_MAC2 | NES_INT_MAC3;
- } while ((int_stat != 0) && (loop_counter++ < MAX_DPC_ITERATIONS));
-
- if (timer_ints == 1) {
- if ((nesadapter->et_rx_coalesce_usecs_irq) || (nesadapter->et_use_adaptive_rx_coalesce)) {
- if (completion_ints == 0) {
- nesdev->timer_only_int_count++;
- if (nesdev->timer_only_int_count>=nesadapter->timer_int_limit) {
- nesdev->timer_only_int_count = 0;
- nesdev->int_req &= ~NES_INT_TIMER;
- nes_write32(nesdev->regs + NES_INTF_INT_MASK, ~(nesdev->intf_int_req));
- nes_write32(nesdev->regs + NES_INT_MASK, ~nesdev->int_req);
- } else {
- nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff | (~nesdev->int_req));
- }
- } else {
- if (unlikely(nesadapter->et_use_adaptive_rx_coalesce))
- {
- nes_nic_init_timer(nesdev);
- }
- nesdev->timer_only_int_count = 0;
- nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff | (~nesdev->int_req));
- }
- } else {
- nesdev->timer_only_int_count = 0;
- nesdev->int_req &= ~NES_INT_TIMER;
- nes_write32(nesdev->regs+NES_INTF_INT_MASK, ~(nesdev->intf_int_req));
- nes_write32(nesdev->regs+NES_TIMER_STAT,
- nesdev->timer_int_req | ~(nesdev->nesadapter->timer_int_req));
- nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
- }
- } else {
- if ( (completion_ints == 1) &&
- (((nesadapter->et_rx_coalesce_usecs_irq) &&
- (!nesadapter->et_use_adaptive_rx_coalesce)) ||
- ((nesdev->deepcq_count > nesadapter->et_pkt_rate_low) &&
- (nesadapter->et_use_adaptive_rx_coalesce) )) ) {
- /* nes_debug(NES_DBG_ISR, "Enabling periodic timer interrupt.\n" ); */
- nesdev->timer_only_int_count = 0;
- nesdev->int_req |= NES_INT_TIMER;
- nes_write32(nesdev->regs+NES_TIMER_STAT,
- nesdev->timer_int_req | ~(nesdev->nesadapter->timer_int_req));
- nes_write32(nesdev->regs+NES_INTF_INT_MASK,
- ~(nesdev->intf_int_req | NES_INTF_PERIODIC_TIMER));
- nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff | (~nesdev->int_req));
- } else {
- nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
- }
- }
- nesdev->deepcq_count = 0;
-}
-
-
-/**
- * nes_process_ceq
- */
-static void nes_process_ceq(struct nes_device *nesdev, struct nes_hw_ceq *ceq)
-{
- u64 u64temp;
- struct nes_hw_cq *cq;
- u32 head;
- u32 ceq_size;
-
- /* nes_debug(NES_DBG_CQ, "\n"); */
- head = ceq->ceq_head;
- ceq_size = ceq->ceq_size;
-
- do {
- if (le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX]) &
- NES_CEQE_VALID) {
- u64temp = (((u64)(le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX]))) << 32) |
- ((u64)(le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_LOW_IDX])));
- u64temp <<= 1;
- cq = *((struct nes_hw_cq **)&u64temp);
- /* nes_debug(NES_DBG_CQ, "pCQ = %p\n", cq); */
- barrier();
- ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX] = 0;
-
- /* call the event handler */
- cq->ce_handler(nesdev, cq);
-
- if (++head >= ceq_size)
- head = 0;
- } else {
- break;
- }
-
- } while (1);
-
- ceq->ceq_head = head;
-}
-
-
-/**
- * nes_process_aeq
- */
-static void nes_process_aeq(struct nes_device *nesdev, struct nes_hw_aeq *aeq)
-{
- /* u64 u64temp; */
- u32 head;
- u32 aeq_size;
- u32 aeqe_misc;
- u32 aeqe_cq_id;
- struct nes_hw_aeqe volatile *aeqe;
-
- head = aeq->aeq_head;
- aeq_size = aeq->aeq_size;
-
- do {
- aeqe = &aeq->aeq_vbase[head];
- if ((le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]) & NES_AEQE_VALID) == 0)
- break;
- aeqe_misc = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]);
- aeqe_cq_id = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]);
- if (aeqe_misc & (NES_AEQE_QP|NES_AEQE_CQ)) {
- if (aeqe_cq_id >= NES_FIRST_QPN) {
- /* dealing with an accelerated QP related AE */
- /*
- * u64temp = (((u64)(le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX]))) << 32) |
- * ((u64)(le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX])));
- */
- nes_process_iwarp_aeqe(nesdev, (struct nes_hw_aeqe *)aeqe);
- } else {
- /* TODO: dealing with a CQP related AE */
- nes_debug(NES_DBG_AEQ, "Processing CQP related AE, misc = 0x%04X\n",
- (u16)(aeqe_misc >> 16));
- }
- }
-
- aeqe->aeqe_words[NES_AEQE_MISC_IDX] = 0;
-
- if (++head >= aeq_size)
- head = 0;
-
- nes_write32(nesdev->regs + NES_AEQ_ALLOC, 1 << 16);
- }
- while (1);
- aeq->aeq_head = head;
-}
-
-static void nes_reset_link(struct nes_device *nesdev, u32 mac_index)
-{
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- u32 reset_value;
- u32 i=0;
- u32 u32temp;
-
- if (nesadapter->hw_rev == NE020_REV) {
- return;
- }
- mh_detected++;
-
- reset_value = nes_read32(nesdev->regs+NES_SOFTWARE_RESET);
-
- if ((mac_index == 0) || ((mac_index == 1) && (nesadapter->OneG_Mode)))
- reset_value |= 0x0000001d;
- else
- reset_value |= 0x0000002d;
-
- if (4 <= (nesadapter->link_interrupt_count[mac_index] / ((u16)NES_MAX_LINK_INTERRUPTS))) {
- if ((!nesadapter->OneG_Mode) && (nesadapter->port_count == 2)) {
- nesadapter->link_interrupt_count[0] = 0;
- nesadapter->link_interrupt_count[1] = 0;
- u32temp = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1);
- if (0x00000040 & u32temp)
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x0000F088);
- else
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x0000F0C8);
-
- reset_value |= 0x0000003d;
- }
- nesadapter->link_interrupt_count[mac_index] = 0;
- }
-
- nes_write32(nesdev->regs+NES_SOFTWARE_RESET, reset_value);
-
- while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET)
- & 0x00000040) != 0x00000040) && (i++ < 5000));
-
- if (0x0000003d == (reset_value & 0x0000003d)) {
- u32 pcs_control_status0, pcs_control_status1;
-
- for (i = 0; i < 10; i++) {
- pcs_control_status0 = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0);
- pcs_control_status1 = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200);
- if (((0x0F000000 == (pcs_control_status0 & 0x0F000000))
- && (pcs_control_status0 & 0x00100000))
- || ((0x0F000000 == (pcs_control_status1 & 0x0F000000))
- && (pcs_control_status1 & 0x00100000)))
- continue;
- else
- break;
- }
- if (10 == i) {
- u32temp = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1);
- if (0x00000040 & u32temp)
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x0000F088);
- else
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x0000F0C8);
-
- nes_write32(nesdev->regs+NES_SOFTWARE_RESET, reset_value);
-
- while (((nes_read32(nesdev->regs + NES_SOFTWARE_RESET)
- & 0x00000040) != 0x00000040) && (i++ < 5000));
- }
- }
-}
-
-/**
- * nes_process_mac_intr
- */
-static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
-{
- unsigned long flags;
- u32 pcs_control_status;
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- struct nes_vnic *nesvnic;
- u32 mac_status;
- u32 mac_index = nesdev->mac_index;
- u32 u32temp;
- u16 phy_data;
- u16 temp_phy_data;
- u32 pcs_val = 0x0f0f0000;
- u32 pcs_mask = 0x0f1f0000;
- u32 cdr_ctrl;
-
- spin_lock_irqsave(&nesadapter->phy_lock, flags);
- if (nesadapter->mac_sw_state[mac_number] != NES_MAC_SW_IDLE) {
- spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
- return;
- }
- nesadapter->mac_sw_state[mac_number] = NES_MAC_SW_INTERRUPT;
-
- /* ack the MAC interrupt */
- mac_status = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (mac_index * 0x200));
- /* Clear the interrupt */
- nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (mac_index * 0x200), mac_status);
-
- nes_debug(NES_DBG_PHY, "MAC%u interrupt status = 0x%X.\n", mac_number, mac_status);
-
- if (mac_status & (NES_MAC_INT_LINK_STAT_CHG | NES_MAC_INT_XGMII_EXT)) {
- nesdev->link_status_interrupts++;
- if (0 == (++nesadapter->link_interrupt_count[mac_index] % ((u16)NES_MAX_LINK_INTERRUPTS)))
- nes_reset_link(nesdev, mac_index);
-
- /* read the PHY interrupt status register */
- if ((nesadapter->OneG_Mode) &&
- (nesadapter->phy_type[mac_index] != NES_PHY_TYPE_PUMA_1G)) {
- do {
- nes_read_1G_phy_reg(nesdev, 0x1a,
- nesadapter->phy_index[mac_index], &phy_data);
- nes_debug(NES_DBG_PHY, "Phy%d data from register 0x1a = 0x%X.\n",
- nesadapter->phy_index[mac_index], phy_data);
- } while (phy_data&0x8000);
-
- temp_phy_data = 0;
- do {
- nes_read_1G_phy_reg(nesdev, 0x11,
- nesadapter->phy_index[mac_index], &phy_data);
- nes_debug(NES_DBG_PHY, "Phy%d data from register 0x11 = 0x%X.\n",
- nesadapter->phy_index[mac_index], phy_data);
- if (temp_phy_data == phy_data)
- break;
- temp_phy_data = phy_data;
- } while (1);
-
- nes_read_1G_phy_reg(nesdev, 0x1e,
- nesadapter->phy_index[mac_index], &phy_data);
- nes_debug(NES_DBG_PHY, "Phy%d data from register 0x1e = 0x%X.\n",
- nesadapter->phy_index[mac_index], phy_data);
-
- nes_read_1G_phy_reg(nesdev, 1,
- nesadapter->phy_index[mac_index], &phy_data);
- nes_debug(NES_DBG_PHY, "1G phy%u data from register 1 = 0x%X\n",
- nesadapter->phy_index[mac_index], phy_data);
-
- if (temp_phy_data & 0x1000) {
- nes_debug(NES_DBG_PHY, "The Link is up according to the PHY\n");
- phy_data = 4;
- } else {
- nes_debug(NES_DBG_PHY, "The Link is down according to the PHY\n");
- }
- }
- nes_debug(NES_DBG_PHY, "Eth SERDES Common Status: 0=0x%08X, 1=0x%08X\n",
- nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0),
- nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0+0x200));
-
- if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_PUMA_1G) {
- switch (mac_index) {
- case 1:
- case 3:
- pcs_control_status = nes_read_indexed(nesdev,
- NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200);
- break;
- default:
- pcs_control_status = nes_read_indexed(nesdev,
- NES_IDX_PHY_PCS_CONTROL_STATUS0);
- break;
- }
- } else {
- pcs_control_status = nes_read_indexed(nesdev,
- NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index & 1) * 0x200));
- pcs_control_status = nes_read_indexed(nesdev,
- NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index & 1) * 0x200));
- }
-
- nes_debug(NES_DBG_PHY, "PCS PHY Control/Status%u: 0x%08X\n",
- mac_index, pcs_control_status);
- if ((nesadapter->OneG_Mode) &&
- (nesadapter->phy_type[mac_index] != NES_PHY_TYPE_PUMA_1G)) {
- u32temp = 0x01010000;
- if (nesadapter->port_count > 2) {
- u32temp |= 0x02020000;
- }
- if ((pcs_control_status & u32temp)!= u32temp) {
- phy_data = 0;
- nes_debug(NES_DBG_PHY, "PCS says the link is down\n");
- }
- } else {
- switch (nesadapter->phy_type[mac_index]) {
- case NES_PHY_TYPE_ARGUS:
- case NES_PHY_TYPE_SFP_D:
- case NES_PHY_TYPE_KR:
- /* clear the alarms */
- nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0x0008);
- nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0xc001);
- nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0xc002);
- nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0xc005);
- nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0xc006);
- nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 0x9003);
- nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 0x9004);
- nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 0x9005);
- /* check link status */
- nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 0x9003);
- temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
-
- nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 3, 0x0021);
- nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
- nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 3, 0x0021);
- phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
-
- phy_data = (!temp_phy_data && (phy_data == 0x8000)) ? 0x4 : 0x0;
-
- nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n",
- __func__, phy_data, nesadapter->mac_link_down[mac_index] ? "DOWN" : "UP");
- break;
-
- case NES_PHY_TYPE_PUMA_1G:
- if (mac_index < 2)
- pcs_val = pcs_mask = 0x01010000;
- else
- pcs_val = pcs_mask = 0x02020000;
- /* fall through */
- default:
- phy_data = (pcs_val == (pcs_control_status & pcs_mask)) ? 0x4 : 0x0;
- break;
- }
- }
-
- if (phy_data & 0x0004) {
- if (wide_ppm_offset &&
- (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_CX4) &&
- (nesadapter->hw_rev != NE020_REV)) {
- cdr_ctrl = nes_read_indexed(nesdev,
- NES_IDX_ETH_SERDES_CDR_CONTROL0 +
- mac_index * 0x200);
- nes_write_indexed(nesdev,
- NES_IDX_ETH_SERDES_CDR_CONTROL0 +
- mac_index * 0x200,
- cdr_ctrl | 0x000F0000);
- }
- nesadapter->mac_link_down[mac_index] = 0;
- list_for_each_entry(nesvnic, &nesadapter->nesvnic_list[mac_index], list) {
- nes_debug(NES_DBG_PHY, "The Link is UP!!. linkup was %d\n",
- nesvnic->linkup);
- if (nesvnic->linkup == 0) {
- printk(PFX "The Link is now up for port %s, netdev %p.\n",
- nesvnic->netdev->name, nesvnic->netdev);
- if (netif_queue_stopped(nesvnic->netdev))
- netif_start_queue(nesvnic->netdev);
- nesvnic->linkup = 1;
- netif_carrier_on(nesvnic->netdev);
-
- spin_lock(&nesvnic->port_ibevent_lock);
- if (nesvnic->of_device_registered) {
- if (nesdev->iw_status == 0) {
- nesdev->iw_status = 1;
- nes_port_ibevent(nesvnic);
- }
- }
- spin_unlock(&nesvnic->port_ibevent_lock);
- }
- }
- } else {
- if (wide_ppm_offset &&
- (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_CX4) &&
- (nesadapter->hw_rev != NE020_REV)) {
- cdr_ctrl = nes_read_indexed(nesdev,
- NES_IDX_ETH_SERDES_CDR_CONTROL0 +
- mac_index * 0x200);
- nes_write_indexed(nesdev,
- NES_IDX_ETH_SERDES_CDR_CONTROL0 +
- mac_index * 0x200,
- cdr_ctrl & 0xFFF0FFFF);
- }
- nesadapter->mac_link_down[mac_index] = 1;
- list_for_each_entry(nesvnic, &nesadapter->nesvnic_list[mac_index], list) {
- nes_debug(NES_DBG_PHY, "The Link is Down!!. linkup was %d\n",
- nesvnic->linkup);
- if (nesvnic->linkup == 1) {
- printk(PFX "The Link is now down for port %s, netdev %p.\n",
- nesvnic->netdev->name, nesvnic->netdev);
- if (!(netif_queue_stopped(nesvnic->netdev)))
- netif_stop_queue(nesvnic->netdev);
- nesvnic->linkup = 0;
- netif_carrier_off(nesvnic->netdev);
-
- spin_lock(&nesvnic->port_ibevent_lock);
- if (nesvnic->of_device_registered) {
- if (nesdev->iw_status == 1) {
- nesdev->iw_status = 0;
- nes_port_ibevent(nesvnic);
- }
- }
- spin_unlock(&nesvnic->port_ibevent_lock);
- }
- }
- }
- if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_SFP_D) {
- nesdev->link_recheck = 1;
- mod_delayed_work(system_wq, &nesdev->work,
- NES_LINK_RECHECK_DELAY);
- }
- }
-
- spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
-
- nesadapter->mac_sw_state[mac_number] = NES_MAC_SW_IDLE;
-}
-
-void nes_recheck_link_status(struct work_struct *work)
-{
- unsigned long flags;
- struct nes_device *nesdev = container_of(work, struct nes_device, work.work);
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- struct nes_vnic *nesvnic;
- u32 mac_index = nesdev->mac_index;
- u16 phy_data;
- u16 temp_phy_data;
-
- spin_lock_irqsave(&nesadapter->phy_lock, flags);
-
- /* check link status */
- nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 0x9003);
- temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
-
- nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 3, 0x0021);
- nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
- nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 3, 0x0021);
- phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
-
- phy_data = (!temp_phy_data && (phy_data == 0x8000)) ? 0x4 : 0x0;
-
- nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n",
- __func__, phy_data,
- nesadapter->mac_link_down[mac_index] ? "DOWN" : "UP");
-
- if (phy_data & 0x0004) {
- nesadapter->mac_link_down[mac_index] = 0;
- list_for_each_entry(nesvnic, &nesadapter->nesvnic_list[mac_index], list) {
- if (nesvnic->linkup == 0) {
- printk(PFX "The Link is now up for port %s, netdev %p.\n",
- nesvnic->netdev->name, nesvnic->netdev);
- if (netif_queue_stopped(nesvnic->netdev))
- netif_start_queue(nesvnic->netdev);
- nesvnic->linkup = 1;
- netif_carrier_on(nesvnic->netdev);
-
- spin_lock(&nesvnic->port_ibevent_lock);
- if (nesvnic->of_device_registered) {
- if (nesdev->iw_status == 0) {
- nesdev->iw_status = 1;
- nes_port_ibevent(nesvnic);
- }
- }
- spin_unlock(&nesvnic->port_ibevent_lock);
- }
- }
-
- } else {
- nesadapter->mac_link_down[mac_index] = 1;
- list_for_each_entry(nesvnic, &nesadapter->nesvnic_list[mac_index], list) {
- if (nesvnic->linkup == 1) {
- printk(PFX "The Link is now down for port %s, netdev %p.\n",
- nesvnic->netdev->name, nesvnic->netdev);
- if (!(netif_queue_stopped(nesvnic->netdev)))
- netif_stop_queue(nesvnic->netdev);
- nesvnic->linkup = 0;
- netif_carrier_off(nesvnic->netdev);
-
- spin_lock(&nesvnic->port_ibevent_lock);
- if (nesvnic->of_device_registered) {
- if (nesdev->iw_status == 1) {
- nesdev->iw_status = 0;
- nes_port_ibevent(nesvnic);
- }
- }
- spin_unlock(&nesvnic->port_ibevent_lock);
- }
- }
- }
- if (nesdev->link_recheck++ < NES_LINK_RECHECK_MAX)
- schedule_delayed_work(&nesdev->work, NES_LINK_RECHECK_DELAY);
- else
- nesdev->link_recheck = 0;
-
- spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
-}
-
-
-static void nes_nic_napi_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
-{
- struct nes_vnic *nesvnic = container_of(cq, struct nes_vnic, nic_cq);
-
- napi_schedule(&nesvnic->napi);
-}
-
-
-/* The MAX_RQES_TO_PROCESS defines how many max read requests to complete before
-* getting out of nic_ce_handler
-*/
-#define MAX_RQES_TO_PROCESS 384
-
-/**
- * nes_nic_ce_handler
- */
-void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
-{
- u64 u64temp;
- dma_addr_t bus_address;
- struct nes_hw_nic *nesnic;
- struct nes_vnic *nesvnic = container_of(cq, struct nes_vnic, nic_cq);
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- struct nes_hw_nic_rq_wqe *nic_rqe;
- struct nes_hw_nic_sq_wqe *nic_sqe;
- struct sk_buff *skb;
- struct sk_buff *rx_skb;
- struct nes_rskb_cb *cb;
- __le16 *wqe_fragment_length;
- u32 head;
- u32 cq_size;
- u32 rx_pkt_size;
- u32 cqe_count=0;
- u32 cqe_errv;
- u32 cqe_misc;
- u16 wqe_fragment_index = 1; /* first fragment (0) is used by copy buffer */
- u16 vlan_tag;
- u16 pkt_type;
- u16 rqes_processed = 0;
- u8 sq_cqes = 0;
-
- head = cq->cq_head;
- cq_size = cq->cq_size;
- cq->cqes_pending = 1;
- do {
- if (le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX]) &
- NES_NIC_CQE_VALID) {
- nesnic = &nesvnic->nic;
- cqe_misc = le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX]);
- if (cqe_misc & NES_NIC_CQE_SQ) {
- sq_cqes++;
- wqe_fragment_index = 1;
- nic_sqe = &nesnic->sq_vbase[nesnic->sq_tail];
- skb = nesnic->tx_skb[nesnic->sq_tail];
- wqe_fragment_length = (__le16 *)&nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX];
- /* bump past the vlan tag */
- wqe_fragment_length++;
- if (le16_to_cpu(wqe_fragment_length[wqe_fragment_index]) != 0) {
- u64temp = (u64) le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX +
- wqe_fragment_index * 2]);
- u64temp += ((u64)le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX +
- wqe_fragment_index * 2])) << 32;
- bus_address = (dma_addr_t)u64temp;
- if (test_and_clear_bit(nesnic->sq_tail, nesnic->first_frag_overflow)) {
- pci_unmap_single(nesdev->pcidev,
- bus_address,
- le16_to_cpu(wqe_fragment_length[wqe_fragment_index++]),
- PCI_DMA_TODEVICE);
- }
- for (; wqe_fragment_index < 5; wqe_fragment_index++) {
- if (wqe_fragment_length[wqe_fragment_index]) {
- u64temp = le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX +
- wqe_fragment_index * 2]);
- u64temp += ((u64)le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX
- + wqe_fragment_index * 2])) <<32;
- bus_address = (dma_addr_t)u64temp;
- pci_unmap_page(nesdev->pcidev,
- bus_address,
- le16_to_cpu(wqe_fragment_length[wqe_fragment_index]),
- PCI_DMA_TODEVICE);
- } else
- break;
- }
- }
- if (skb)
- dev_kfree_skb_any(skb);
- nesnic->sq_tail++;
- nesnic->sq_tail &= nesnic->sq_size-1;
- if (sq_cqes > 128) {
- barrier();
- /* restart the queue if it had been stopped */
- if (netif_queue_stopped(nesvnic->netdev))
- netif_wake_queue(nesvnic->netdev);
- sq_cqes = 0;
- }
- } else {
- rqes_processed ++;
-
- cq->rx_cqes_completed++;
- cq->rx_pkts_indicated++;
- rx_pkt_size = cqe_misc & 0x0000ffff;
- nic_rqe = &nesnic->rq_vbase[nesnic->rq_tail];
- /* Get the skb */
- rx_skb = nesnic->rx_skb[nesnic->rq_tail];
- nic_rqe = &nesnic->rq_vbase[nesvnic->nic.rq_tail];
- bus_address = (dma_addr_t)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX]);
- bus_address += ((u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX])) << 32;
- pci_unmap_single(nesdev->pcidev, bus_address,
- nesvnic->max_frame_size, PCI_DMA_FROMDEVICE);
- cb = (struct nes_rskb_cb *)&rx_skb->cb[0];
- cb->busaddr = 0;
- /* rx_skb->tail = rx_skb->data + rx_pkt_size; */
- /* rx_skb->len = rx_pkt_size; */
- rx_skb->len = 0; /* TODO: see if this is necessary */
- skb_put(rx_skb, rx_pkt_size);
- rx_skb->protocol = eth_type_trans(rx_skb, nesvnic->netdev);
- nesnic->rq_tail++;
- nesnic->rq_tail &= nesnic->rq_size - 1;
-
- atomic_inc(&nesvnic->rx_skbs_needed);
- if (atomic_read(&nesvnic->rx_skbs_needed) > (nesvnic->nic.rq_size>>1)) {
- nes_write32(nesdev->regs+NES_CQE_ALLOC,
- cq->cq_number | (cqe_count << 16));
- /* nesadapter->tune_timer.cq_count += cqe_count; */
- nesdev->currcq_count += cqe_count;
- cqe_count = 0;
- nes_replenish_nic_rq(nesvnic);
- }
- pkt_type = (u16)(le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_TAG_PKT_TYPE_IDX]));
- cqe_errv = (cqe_misc & NES_NIC_CQE_ERRV_MASK) >> NES_NIC_CQE_ERRV_SHIFT;
- rx_skb->ip_summed = CHECKSUM_NONE;
-
- if ((NES_PKT_TYPE_TCPV4_BITS == (pkt_type & NES_PKT_TYPE_TCPV4_MASK)) ||
- (NES_PKT_TYPE_UDPV4_BITS == (pkt_type & NES_PKT_TYPE_UDPV4_MASK))) {
- if ((cqe_errv &
- (NES_NIC_ERRV_BITS_IPV4_CSUM_ERR | NES_NIC_ERRV_BITS_TCPUDP_CSUM_ERR |
- NES_NIC_ERRV_BITS_IPH_ERR | NES_NIC_ERRV_BITS_WQE_OVERRUN)) == 0) {
- if (nesvnic->netdev->features & NETIF_F_RXCSUM)
- rx_skb->ip_summed = CHECKSUM_UNNECESSARY;
- } else
- nes_debug(NES_DBG_CQ, "%s: unsuccessfully checksummed TCP or UDP packet."
- " errv = 0x%X, pkt_type = 0x%X.\n",
- nesvnic->netdev->name, cqe_errv, pkt_type);
-
- } else if ((pkt_type & NES_PKT_TYPE_IPV4_MASK) == NES_PKT_TYPE_IPV4_BITS) {
- if ((cqe_errv &
- (NES_NIC_ERRV_BITS_IPV4_CSUM_ERR | NES_NIC_ERRV_BITS_IPH_ERR |
- NES_NIC_ERRV_BITS_WQE_OVERRUN)) == 0) {
- if (nesvnic->netdev->features & NETIF_F_RXCSUM) {
- rx_skb->ip_summed = CHECKSUM_UNNECESSARY;
- /* nes_debug(NES_DBG_CQ, "%s: Reporting successfully checksummed IPv4 packet.\n",
- nesvnic->netdev->name); */
- }
- } else
- nes_debug(NES_DBG_CQ, "%s: unsuccessfully checksummed TCP or UDP packet."
- " errv = 0x%X, pkt_type = 0x%X.\n",
- nesvnic->netdev->name, cqe_errv, pkt_type);
- }
- /* nes_debug(NES_DBG_CQ, "pkt_type=%x, APBVT_MASK=%x\n",
- pkt_type, (pkt_type & NES_PKT_TYPE_APBVT_MASK)); */
-
- if ((pkt_type & NES_PKT_TYPE_APBVT_MASK) == NES_PKT_TYPE_APBVT_BITS) {
- if (nes_cm_recv(rx_skb, nesvnic->netdev))
- rx_skb = NULL;
- }
- if (rx_skb == NULL)
- goto skip_rx_indicate0;
-
-
- if (cqe_misc & NES_NIC_CQE_TAG_VALID) {
- vlan_tag = (u16)(le32_to_cpu(
- cq->cq_vbase[head].cqe_words[NES_NIC_CQE_TAG_PKT_TYPE_IDX])
- >> 16);
- nes_debug(NES_DBG_CQ, "%s: Reporting stripped VLAN packet. Tag = 0x%04X\n",
- nesvnic->netdev->name, vlan_tag);
-
- __vlan_hwaccel_put_tag(rx_skb, htons(ETH_P_8021Q), vlan_tag);
- }
- napi_gro_receive(&nesvnic->napi, rx_skb);
-
-skip_rx_indicate0:
- ;
- /* nesvnic->netstats.rx_packets++; */
- /* nesvnic->netstats.rx_bytes += rx_pkt_size; */
- }
-
- cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX] = 0;
- /* Accounting... */
- cqe_count++;
- if (++head >= cq_size)
- head = 0;
- if (cqe_count == 255) {
- /* Replenish Nic CQ */
- nes_write32(nesdev->regs+NES_CQE_ALLOC,
- cq->cq_number | (cqe_count << 16));
- /* nesdev->nesadapter->tune_timer.cq_count += cqe_count; */
- nesdev->currcq_count += cqe_count;
- cqe_count = 0;
- }
-
- if (cq->rx_cqes_completed >= nesvnic->budget)
- break;
- } else {
- cq->cqes_pending = 0;
- break;
- }
-
- } while (1);
-
- if (sq_cqes) {
- barrier();
- /* restart the queue if it had been stopped */
- if (netif_queue_stopped(nesvnic->netdev))
- netif_wake_queue(nesvnic->netdev);
- }
- cq->cq_head = head;
- /* nes_debug(NES_DBG_CQ, "CQ%u Processed = %u cqes, new head = %u.\n",
- cq->cq_number, cqe_count, cq->cq_head); */
- cq->cqe_allocs_pending = cqe_count;
- if (unlikely(nesadapter->et_use_adaptive_rx_coalesce))
- {
- /* nesdev->nesadapter->tune_timer.cq_count += cqe_count; */
- nesdev->currcq_count += cqe_count;
- nes_nic_tune_timer(nesdev);
- }
- if (atomic_read(&nesvnic->rx_skbs_needed))
- nes_replenish_nic_rq(nesvnic);
-}
-
-
-
-/**
- * nes_cqp_ce_handler
- */
-static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq)
-{
- u64 u64temp;
- unsigned long flags;
- struct nes_hw_cqp *cqp = NULL;
- struct nes_cqp_request *cqp_request;
- struct nes_hw_cqp_wqe *cqp_wqe;
- u32 head;
- u32 cq_size;
- u32 cqe_count=0;
- u32 error_code;
- u32 opcode;
- u32 ctx_index;
- /* u32 counter; */
-
- head = cq->cq_head;
- cq_size = cq->cq_size;
-
- do {
- /* process the CQE */
- /* nes_debug(NES_DBG_CQP, "head=%u cqe_words=%08X\n", head,
- le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX])); */
-
- opcode = le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX]);
- if (opcode & NES_CQE_VALID) {
- cqp = &nesdev->cqp;
-
- error_code = le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_ERROR_CODE_IDX]);
- if (error_code) {
- nes_debug(NES_DBG_CQP, "Bad Completion code for opcode 0x%02X from CQP,"
- " Major/Minor codes = 0x%04X:%04X.\n",
- le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX])&0x3f,
- (u16)(error_code >> 16),
- (u16)error_code);
- }
-
- u64temp = (((u64)(le32_to_cpu(cq->cq_vbase[head].
- cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX]))) << 32) |
- ((u64)(le32_to_cpu(cq->cq_vbase[head].
- cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX])));
-
- cqp_request = (struct nes_cqp_request *)(unsigned long)u64temp;
- if (cqp_request) {
- if (cqp_request->waiting) {
- /* nes_debug(NES_DBG_CQP, "%s: Waking up requestor\n"); */
- cqp_request->major_code = (u16)(error_code >> 16);
- cqp_request->minor_code = (u16)error_code;
- barrier();
- cqp_request->request_done = 1;
- wake_up(&cqp_request->waitq);
- nes_put_cqp_request(nesdev, cqp_request);
- } else {
- if (cqp_request->callback)
- cqp_request->cqp_callback(nesdev, cqp_request);
- nes_free_cqp_request(nesdev, cqp_request);
- }
- } else {
- wake_up(&nesdev->cqp.waitq);
- }
-
- cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX] = 0;
- nes_write32(nesdev->regs + NES_CQE_ALLOC, cq->cq_number | (1 << 16));
- if (++cqp->sq_tail >= cqp->sq_size)
- cqp->sq_tail = 0;
-
- /* Accounting... */
- cqe_count++;
- if (++head >= cq_size)
- head = 0;
- } else {
- break;
- }
- } while (1);
- cq->cq_head = head;
-
- spin_lock_irqsave(&nesdev->cqp.lock, flags);
- while ((!list_empty(&nesdev->cqp_pending_reqs)) &&
- ((((nesdev->cqp.sq_tail+nesdev->cqp.sq_size)-nesdev->cqp.sq_head) &
- (nesdev->cqp.sq_size - 1)) != 1)) {
- cqp_request = list_entry(nesdev->cqp_pending_reqs.next,
- struct nes_cqp_request, list);
- list_del_init(&cqp_request->list);
- head = nesdev->cqp.sq_head++;
- nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
- cqp_wqe = &nesdev->cqp.sq_vbase[head];
- memcpy(cqp_wqe, &cqp_request->cqp_wqe, sizeof(*cqp_wqe));
- barrier();
-
- opcode = le32_to_cpu(cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX]);
- if ((opcode & NES_CQP_OPCODE_MASK) == NES_CQP_DOWNLOAD_SEGMENT)
- ctx_index = NES_CQP_WQE_DL_COMP_CTX_LOW_IDX;
- else
- ctx_index = NES_CQP_WQE_COMP_CTX_LOW_IDX;
- cqp_wqe->wqe_words[ctx_index] =
- cpu_to_le32((u32)((unsigned long)cqp_request));
- cqp_wqe->wqe_words[ctx_index + 1] =
- cpu_to_le32((u32)(upper_32_bits((unsigned long)cqp_request)));
- nes_debug(NES_DBG_CQP, "CQP request %p (opcode 0x%02X) put on CQPs SQ wqe%u.\n",
- cqp_request, le32_to_cpu(cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX])&0x3f, head);
- /* Ring doorbell (1 WQEs) */
- barrier();
- nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x01800000 | nesdev->cqp.qp_id);
- }
- spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
-
- /* Arm the CCQ */
- nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT |
- cq->cq_number);
- nes_read32(nesdev->regs+NES_CQE_ALLOC);
-}
-
-static u8 *locate_mpa(u8 *pkt, u32 aeq_info)
-{
- if (aeq_info & NES_AEQE_Q2_DATA_ETHERNET) {
- /* skip over ethernet header */
- pkt += ETH_HLEN;
-
- /* Skip over IP and TCP headers */
- pkt += 4 * (pkt[0] & 0x0f);
- pkt += 4 * ((pkt[12] >> 4) & 0x0f);
- }
- return pkt;
-}
-
-/* Determine if incoming error pkt is rdma layer */
-static u32 iwarp_opcode(struct nes_qp *nesqp, u32 aeq_info)
-{
- u8 *pkt;
- u16 *mpa;
- u32 opcode = 0xffffffff;
-
- if (aeq_info & NES_AEQE_Q2_DATA_WRITTEN) {
- pkt = nesqp->hwqp.q2_vbase + BAD_FRAME_OFFSET;
- mpa = (u16 *)locate_mpa(pkt, aeq_info);
- opcode = be16_to_cpu(mpa[1]) & 0xf;
- }
-
- return opcode;
-}
-
-/* Build iWARP terminate header */
-static int nes_bld_terminate_hdr(struct nes_qp *nesqp, u16 async_event_id, u32 aeq_info)
-{
- u8 *pkt = nesqp->hwqp.q2_vbase + BAD_FRAME_OFFSET;
- u16 ddp_seg_len;
- int copy_len = 0;
- u8 is_tagged = 0;
- u8 flush_code = 0;
- struct nes_terminate_hdr *termhdr;
-
- termhdr = (struct nes_terminate_hdr *)nesqp->hwqp.q2_vbase;
- memset(termhdr, 0, 64);
-
- if (aeq_info & NES_AEQE_Q2_DATA_WRITTEN) {
-
- /* Use data from offending packet to fill in ddp & rdma hdrs */
- pkt = locate_mpa(pkt, aeq_info);
- ddp_seg_len = be16_to_cpu(*(u16 *)pkt);
- if (ddp_seg_len) {
- copy_len = 2;
- termhdr->hdrct = DDP_LEN_FLAG;
- if (pkt[2] & 0x80) {
- is_tagged = 1;
- if (ddp_seg_len >= TERM_DDP_LEN_TAGGED) {
- copy_len += TERM_DDP_LEN_TAGGED;
- termhdr->hdrct |= DDP_HDR_FLAG;
- }
- } else {
- if (ddp_seg_len >= TERM_DDP_LEN_UNTAGGED) {
- copy_len += TERM_DDP_LEN_UNTAGGED;
- termhdr->hdrct |= DDP_HDR_FLAG;
- }
-
- if (ddp_seg_len >= (TERM_DDP_LEN_UNTAGGED + TERM_RDMA_LEN)) {
- if ((pkt[3] & RDMA_OPCODE_MASK) == RDMA_READ_REQ_OPCODE) {
- copy_len += TERM_RDMA_LEN;
- termhdr->hdrct |= RDMA_HDR_FLAG;
- }
- }
- }
- }
- }
-
- switch (async_event_id) {
- case NES_AEQE_AEID_AMP_UNALLOCATED_STAG:
- switch (iwarp_opcode(nesqp, aeq_info)) {
- case IWARP_OPCODE_WRITE:
- flush_code = IB_WC_LOC_PROT_ERR;
- termhdr->layer_etype = (LAYER_DDP << 4) | DDP_TAGGED_BUFFER;
- termhdr->error_code = DDP_TAGGED_INV_STAG;
- break;
- default:
- flush_code = IB_WC_REM_ACCESS_ERR;
- termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT;
- termhdr->error_code = RDMAP_INV_STAG;
- }
- break;
- case NES_AEQE_AEID_AMP_INVALID_STAG:
- flush_code = IB_WC_REM_ACCESS_ERR;
- termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT;
- termhdr->error_code = RDMAP_INV_STAG;
- break;
- case NES_AEQE_AEID_AMP_BAD_QP:
- flush_code = IB_WC_LOC_QP_OP_ERR;
- termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER;
- termhdr->error_code = DDP_UNTAGGED_INV_QN;
- break;
- case NES_AEQE_AEID_AMP_BAD_STAG_KEY:
- case NES_AEQE_AEID_AMP_BAD_STAG_INDEX:
- switch (iwarp_opcode(nesqp, aeq_info)) {
- case IWARP_OPCODE_SEND_INV:
- case IWARP_OPCODE_SEND_SE_INV:
- flush_code = IB_WC_REM_OP_ERR;
- termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_OP;
- termhdr->error_code = RDMAP_CANT_INV_STAG;
- break;
- default:
- flush_code = IB_WC_REM_ACCESS_ERR;
- termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT;
- termhdr->error_code = RDMAP_INV_STAG;
- }
- break;
- case NES_AEQE_AEID_AMP_BOUNDS_VIOLATION:
- if (aeq_info & (NES_AEQE_Q2_DATA_ETHERNET | NES_AEQE_Q2_DATA_MPA)) {
- flush_code = IB_WC_LOC_PROT_ERR;
- termhdr->layer_etype = (LAYER_DDP << 4) | DDP_TAGGED_BUFFER;
- termhdr->error_code = DDP_TAGGED_BOUNDS;
- } else {
- flush_code = IB_WC_REM_ACCESS_ERR;
- termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT;
- termhdr->error_code = RDMAP_INV_BOUNDS;
- }
- break;
- case NES_AEQE_AEID_AMP_RIGHTS_VIOLATION:
- case NES_AEQE_AEID_AMP_INVALIDATE_NO_REMOTE_ACCESS_RIGHTS:
- case NES_AEQE_AEID_PRIV_OPERATION_DENIED:
- flush_code = IB_WC_REM_ACCESS_ERR;
- termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT;
- termhdr->error_code = RDMAP_ACCESS;
- break;
- case NES_AEQE_AEID_AMP_TO_WRAP:
- flush_code = IB_WC_REM_ACCESS_ERR;
- termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT;
- termhdr->error_code = RDMAP_TO_WRAP;
- break;
- case NES_AEQE_AEID_AMP_BAD_PD:
- switch (iwarp_opcode(nesqp, aeq_info)) {
- case IWARP_OPCODE_WRITE:
- flush_code = IB_WC_LOC_PROT_ERR;
- termhdr->layer_etype = (LAYER_DDP << 4) | DDP_TAGGED_BUFFER;
- termhdr->error_code = DDP_TAGGED_UNASSOC_STAG;
- break;
- case IWARP_OPCODE_SEND_INV:
- case IWARP_OPCODE_SEND_SE_INV:
- flush_code = IB_WC_REM_ACCESS_ERR;
- termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT;
- termhdr->error_code = RDMAP_CANT_INV_STAG;
- break;
- default:
- flush_code = IB_WC_REM_ACCESS_ERR;
- termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT;
- termhdr->error_code = RDMAP_UNASSOC_STAG;
- }
- break;
- case NES_AEQE_AEID_LLP_RECEIVED_MARKER_AND_LENGTH_FIELDS_DONT_MATCH:
- flush_code = IB_WC_LOC_LEN_ERR;
- termhdr->layer_etype = (LAYER_MPA << 4) | DDP_LLP;
- termhdr->error_code = MPA_MARKER;
- break;
- case NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR:
- flush_code = IB_WC_GENERAL_ERR;
- termhdr->layer_etype = (LAYER_MPA << 4) | DDP_LLP;
- termhdr->error_code = MPA_CRC;
- break;
- case NES_AEQE_AEID_LLP_SEGMENT_TOO_LARGE:
- case NES_AEQE_AEID_LLP_SEGMENT_TOO_SMALL:
- flush_code = IB_WC_LOC_LEN_ERR;
- termhdr->layer_etype = (LAYER_DDP << 4) | DDP_CATASTROPHIC;
- termhdr->error_code = DDP_CATASTROPHIC_LOCAL;
- break;
- case NES_AEQE_AEID_DDP_LCE_LOCAL_CATASTROPHIC:
- case NES_AEQE_AEID_DDP_NO_L_BIT:
- flush_code = IB_WC_FATAL_ERR;
- termhdr->layer_etype = (LAYER_DDP << 4) | DDP_CATASTROPHIC;
- termhdr->error_code = DDP_CATASTROPHIC_LOCAL;
- break;
- case NES_AEQE_AEID_DDP_INVALID_MSN_GAP_IN_MSN:
- case NES_AEQE_AEID_DDP_INVALID_MSN_RANGE_IS_NOT_VALID:
- flush_code = IB_WC_GENERAL_ERR;
- termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER;
- termhdr->error_code = DDP_UNTAGGED_INV_MSN_RANGE;
- break;
- case NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER:
- flush_code = IB_WC_LOC_LEN_ERR;
- termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER;
- termhdr->error_code = DDP_UNTAGGED_INV_TOO_LONG;
- break;
- case NES_AEQE_AEID_DDP_UBE_INVALID_DDP_VERSION:
- flush_code = IB_WC_GENERAL_ERR;
- if (is_tagged) {
- termhdr->layer_etype = (LAYER_DDP << 4) | DDP_TAGGED_BUFFER;
- termhdr->error_code = DDP_TAGGED_INV_DDP_VER;
- } else {
- termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER;
- termhdr->error_code = DDP_UNTAGGED_INV_DDP_VER;
- }
- break;
- case NES_AEQE_AEID_DDP_UBE_INVALID_MO:
- flush_code = IB_WC_GENERAL_ERR;
- termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER;
- termhdr->error_code = DDP_UNTAGGED_INV_MO;
- break;
- case NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE:
- flush_code = IB_WC_REM_OP_ERR;
- termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER;
- termhdr->error_code = DDP_UNTAGGED_INV_MSN_NO_BUF;
- break;
- case NES_AEQE_AEID_DDP_UBE_INVALID_QN:
- flush_code = IB_WC_GENERAL_ERR;
- termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER;
- termhdr->error_code = DDP_UNTAGGED_INV_QN;
- break;
- case NES_AEQE_AEID_RDMAP_ROE_INVALID_RDMAP_VERSION:
- flush_code = IB_WC_GENERAL_ERR;
- termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_OP;
- termhdr->error_code = RDMAP_INV_RDMAP_VER;
- break;
- case NES_AEQE_AEID_RDMAP_ROE_UNEXPECTED_OPCODE:
- flush_code = IB_WC_LOC_QP_OP_ERR;
- termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_OP;
- termhdr->error_code = RDMAP_UNEXPECTED_OP;
- break;
- default:
- flush_code = IB_WC_FATAL_ERR;
- termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_OP;
- termhdr->error_code = RDMAP_UNSPECIFIED;
- break;
- }
-
- if (copy_len)
- memcpy(termhdr + 1, pkt, copy_len);
-
- if ((flush_code) && ((NES_AEQE_INBOUND_RDMA & aeq_info) == 0)) {
- if (aeq_info & NES_AEQE_SQ)
- nesqp->term_sq_flush_code = flush_code;
- else
- nesqp->term_rq_flush_code = flush_code;
- }
-
- return sizeof(struct nes_terminate_hdr) + copy_len;
-}
-
-static void nes_terminate_connection(struct nes_device *nesdev, struct nes_qp *nesqp,
- struct nes_hw_aeqe *aeqe, enum ib_event_type eventtype)
-{
- u64 context;
- unsigned long flags;
- u32 aeq_info;
- u16 async_event_id;
- u8 tcp_state;
- u8 iwarp_state;
- u32 termlen = 0;
- u32 mod_qp_flags = NES_CQP_QP_IWARP_STATE_TERMINATE |
- NES_CQP_QP_TERM_DONT_SEND_FIN;
- struct nes_adapter *nesadapter = nesdev->nesadapter;
-
- if (nesqp->term_flags & NES_TERM_SENT)
- return; /* Sanity check */
-
- aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]);
- tcp_state = (aeq_info & NES_AEQE_TCP_STATE_MASK) >> NES_AEQE_TCP_STATE_SHIFT;
- iwarp_state = (aeq_info & NES_AEQE_IWARP_STATE_MASK) >> NES_AEQE_IWARP_STATE_SHIFT;
- async_event_id = (u16)aeq_info;
-
- context = (unsigned long)nesadapter->qp_table[le32_to_cpu(
- aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]) - NES_FIRST_QPN];
- if (!context) {
- WARN_ON(!context);
- return;
- }
-
- nesqp = (struct nes_qp *)(unsigned long)context;
- spin_lock_irqsave(&nesqp->lock, flags);
- nesqp->hw_iwarp_state = iwarp_state;
- nesqp->hw_tcp_state = tcp_state;
- nesqp->last_aeq = async_event_id;
- nesqp->terminate_eventtype = eventtype;
- spin_unlock_irqrestore(&nesqp->lock, flags);
-
- if (nesadapter->send_term_ok)
- termlen = nes_bld_terminate_hdr(nesqp, async_event_id, aeq_info);
- else
- mod_qp_flags |= NES_CQP_QP_TERM_DONT_SEND_TERM_MSG;
-
- if (!nesdev->iw_status) {
- nesqp->term_flags = NES_TERM_DONE;
- nes_hw_modify_qp(nesdev, nesqp, NES_CQP_QP_IWARP_STATE_ERROR, 0, 0);
- nes_cm_disconn(nesqp);
- } else {
- nes_terminate_start_timer(nesqp);
- nesqp->term_flags |= NES_TERM_SENT;
- nes_hw_modify_qp(nesdev, nesqp, mod_qp_flags, termlen, 0);
- }
-}
-
-static void nes_terminate_send_fin(struct nes_device *nesdev,
- struct nes_qp *nesqp, struct nes_hw_aeqe *aeqe)
-{
- u32 aeq_info;
- u16 async_event_id;
- u8 tcp_state;
- u8 iwarp_state;
- unsigned long flags;
-
- aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]);
- tcp_state = (aeq_info & NES_AEQE_TCP_STATE_MASK) >> NES_AEQE_TCP_STATE_SHIFT;
- iwarp_state = (aeq_info & NES_AEQE_IWARP_STATE_MASK) >> NES_AEQE_IWARP_STATE_SHIFT;
- async_event_id = (u16)aeq_info;
-
- spin_lock_irqsave(&nesqp->lock, flags);
- nesqp->hw_iwarp_state = iwarp_state;
- nesqp->hw_tcp_state = tcp_state;
- nesqp->last_aeq = async_event_id;
- spin_unlock_irqrestore(&nesqp->lock, flags);
-
- /* Send the fin only */
- nes_hw_modify_qp(nesdev, nesqp, NES_CQP_QP_IWARP_STATE_TERMINATE |
- NES_CQP_QP_TERM_DONT_SEND_TERM_MSG, 0, 0);
-}
-
-/* Cleanup after a terminate sent or received */
-static void nes_terminate_done(struct nes_qp *nesqp, int timeout_occurred)
-{
- u32 next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR;
- unsigned long flags;
- struct nes_vnic *nesvnic = to_nesvnic(nesqp->ibqp.device);
- struct nes_device *nesdev = nesvnic->nesdev;
- u8 first_time = 0;
-
- spin_lock_irqsave(&nesqp->lock, flags);
- if (nesqp->hte_added) {
- nesqp->hte_added = 0;
- next_iwarp_state |= NES_CQP_QP_DEL_HTE;
- }
-
- first_time = (nesqp->term_flags & NES_TERM_DONE) == 0;
- nesqp->term_flags |= NES_TERM_DONE;
- spin_unlock_irqrestore(&nesqp->lock, flags);
-
- /* Make sure we go through this only once */
- if (first_time) {
- if (timeout_occurred == 0)
- del_timer(&nesqp->terminate_timer);
- else
- next_iwarp_state |= NES_CQP_QP_RESET;
-
- nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0, 0);
- nes_cm_disconn(nesqp);
- }
-}
-
-static void nes_terminate_received(struct nes_device *nesdev,
- struct nes_qp *nesqp, struct nes_hw_aeqe *aeqe)
-{
- u32 aeq_info;
- u8 *pkt;
- u32 *mpa;
- u8 ddp_ctl;
- u8 rdma_ctl;
- u16 aeq_id = 0;
-
- aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]);
- if (aeq_info & NES_AEQE_Q2_DATA_WRITTEN) {
- /* Terminate is not a performance path so the silicon */
- /* did not validate the frame - do it now */
- pkt = nesqp->hwqp.q2_vbase + BAD_FRAME_OFFSET;
- mpa = (u32 *)locate_mpa(pkt, aeq_info);
- ddp_ctl = (be32_to_cpu(mpa[0]) >> 8) & 0xff;
- rdma_ctl = be32_to_cpu(mpa[0]) & 0xff;
- if ((ddp_ctl & 0xc0) != 0x40)
- aeq_id = NES_AEQE_AEID_DDP_LCE_LOCAL_CATASTROPHIC;
- else if ((ddp_ctl & 0x03) != 1)
- aeq_id = NES_AEQE_AEID_DDP_UBE_INVALID_DDP_VERSION;
- else if (be32_to_cpu(mpa[2]) != 2)
- aeq_id = NES_AEQE_AEID_DDP_UBE_INVALID_QN;
- else if (be32_to_cpu(mpa[3]) != 1)
- aeq_id = NES_AEQE_AEID_DDP_INVALID_MSN_GAP_IN_MSN;
- else if (be32_to_cpu(mpa[4]) != 0)
- aeq_id = NES_AEQE_AEID_DDP_UBE_INVALID_MO;
- else if ((rdma_ctl & 0xc0) != 0x40)
- aeq_id = NES_AEQE_AEID_RDMAP_ROE_INVALID_RDMAP_VERSION;
-
- if (aeq_id) {
- /* Bad terminate recvd - send back a terminate */
- aeq_info = (aeq_info & 0xffff0000) | aeq_id;
- aeqe->aeqe_words[NES_AEQE_MISC_IDX] = cpu_to_le32(aeq_info);
- nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_FATAL);
- return;
- }
- }
-
- nesqp->term_flags |= NES_TERM_RCVD;
- nesqp->terminate_eventtype = IB_EVENT_QP_FATAL;
- nes_terminate_start_timer(nesqp);
- nes_terminate_send_fin(nesdev, nesqp, aeqe);
-}
-
-/* Timeout routine in case terminate fails to complete */
-void nes_terminate_timeout(struct timer_list *t)
-{
- struct nes_qp *nesqp = from_timer(nesqp, t, terminate_timer);
-
- nes_terminate_done(nesqp, 1);
-}
-
-/* Set a timer in case hw cannot complete the terminate sequence */
-static void nes_terminate_start_timer(struct nes_qp *nesqp)
-{
- mod_timer(&nesqp->terminate_timer, (jiffies + HZ));
-}
-
-/**
- * nes_process_iwarp_aeqe
- */
-static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
- struct nes_hw_aeqe *aeqe)
-{
- u64 context;
- unsigned long flags;
- struct nes_qp *nesqp;
- struct nes_hw_cq *hw_cq;
- struct nes_cq *nescq;
- int resource_allocated;
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- u32 aeq_info;
- u32 next_iwarp_state = 0;
- u32 aeqe_cq_id;
- u16 async_event_id;
- u8 tcp_state;
- u8 iwarp_state;
- struct ib_event ibevent;
-
- nes_debug(NES_DBG_AEQ, "\n");
- aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]);
- if ((NES_AEQE_INBOUND_RDMA & aeq_info) || (!(NES_AEQE_QP & aeq_info))) {
- context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]);
- context += ((u64)le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])) << 32;
- } else {
- context = (unsigned long)nesadapter->qp_table[le32_to_cpu(
- aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]) - NES_FIRST_QPN];
- BUG_ON(!context);
- }
-
- /* context is nesqp unless async_event_id == CQ ERROR */
- nesqp = (struct nes_qp *)(unsigned long)context;
- async_event_id = (u16)aeq_info;
- tcp_state = (aeq_info & NES_AEQE_TCP_STATE_MASK) >> NES_AEQE_TCP_STATE_SHIFT;
- iwarp_state = (aeq_info & NES_AEQE_IWARP_STATE_MASK) >> NES_AEQE_IWARP_STATE_SHIFT;
- nes_debug(NES_DBG_AEQ, "aeid = 0x%04X, qp-cq id = %d, aeqe = %p,"
- " Tcp state = %s, iWARP state = %s\n",
- async_event_id,
- le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]), aeqe,
- nes_tcp_state_str[tcp_state], nes_iwarp_state_str[iwarp_state]);
-
- aeqe_cq_id = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]);
- if (aeq_info & NES_AEQE_QP) {
- if (!nes_is_resource_allocated(nesadapter,
- nesadapter->allocated_qps,
- aeqe_cq_id))
- return;
- }
-
- switch (async_event_id) {
- case NES_AEQE_AEID_LLP_FIN_RECEIVED:
- if (nesqp->term_flags)
- return; /* Ignore it, wait for close complete */
-
- if (atomic_inc_return(&nesqp->close_timer_started) == 1) {
- if ((tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) &&
- (nesqp->ibqp_state == IB_QPS_RTS)) {
- spin_lock_irqsave(&nesqp->lock, flags);
- nesqp->hw_iwarp_state = iwarp_state;
- nesqp->hw_tcp_state = tcp_state;
- nesqp->last_aeq = async_event_id;
- next_iwarp_state = NES_CQP_QP_IWARP_STATE_CLOSING;
- nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_CLOSING;
- spin_unlock_irqrestore(&nesqp->lock, flags);
- nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0, 0);
- nes_cm_disconn(nesqp);
- }
- nesqp->cm_id->add_ref(nesqp->cm_id);
- schedule_nes_timer(nesqp->cm_node, (struct sk_buff *)nesqp,
- NES_TIMER_TYPE_CLOSE, 1, 0);
- nes_debug(NES_DBG_AEQ, "QP%u Not decrementing QP refcount (%d),"
- " need ae to finish up, original_last_aeq = 0x%04X."
- " last_aeq = 0x%04X, scheduling timer. TCP state = %d\n",
- nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),
- async_event_id, nesqp->last_aeq, tcp_state);
- }
- break;
- case NES_AEQE_AEID_LLP_CLOSE_COMPLETE:
- spin_lock_irqsave(&nesqp->lock, flags);
- nesqp->hw_iwarp_state = iwarp_state;
- nesqp->hw_tcp_state = tcp_state;
- nesqp->last_aeq = async_event_id;
- spin_unlock_irqrestore(&nesqp->lock, flags);
- nes_cm_disconn(nesqp);
- break;
-
- case NES_AEQE_AEID_RESET_SENT:
- tcp_state = NES_AEQE_TCP_STATE_CLOSED;
- spin_lock_irqsave(&nesqp->lock, flags);
- nesqp->hw_iwarp_state = iwarp_state;
- nesqp->hw_tcp_state = tcp_state;
- nesqp->last_aeq = async_event_id;
- nesqp->hte_added = 0;
- spin_unlock_irqrestore(&nesqp->lock, flags);
- next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR | NES_CQP_QP_DEL_HTE;
- nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0, 0);
- nes_cm_disconn(nesqp);
- break;
-
- case NES_AEQE_AEID_LLP_CONNECTION_RESET:
- if (atomic_read(&nesqp->close_timer_started))
- return;
- spin_lock_irqsave(&nesqp->lock, flags);
- nesqp->hw_iwarp_state = iwarp_state;
- nesqp->hw_tcp_state = tcp_state;
- nesqp->last_aeq = async_event_id;
- spin_unlock_irqrestore(&nesqp->lock, flags);
- nes_cm_disconn(nesqp);
- break;
-
- case NES_AEQE_AEID_TERMINATE_SENT:
- nes_terminate_send_fin(nesdev, nesqp, aeqe);
- break;
-
- case NES_AEQE_AEID_LLP_TERMINATE_RECEIVED:
- nes_terminate_received(nesdev, nesqp, aeqe);
- break;
-
- case NES_AEQE_AEID_AMP_BAD_STAG_KEY:
- case NES_AEQE_AEID_AMP_BAD_STAG_INDEX:
- case NES_AEQE_AEID_AMP_UNALLOCATED_STAG:
- case NES_AEQE_AEID_AMP_INVALID_STAG:
- case NES_AEQE_AEID_AMP_RIGHTS_VIOLATION:
- case NES_AEQE_AEID_AMP_INVALIDATE_NO_REMOTE_ACCESS_RIGHTS:
- case NES_AEQE_AEID_PRIV_OPERATION_DENIED:
- case NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER:
- case NES_AEQE_AEID_AMP_BOUNDS_VIOLATION:
- case NES_AEQE_AEID_AMP_TO_WRAP:
- printk(KERN_ERR PFX "QP[%u] async_event_id=0x%04X IB_EVENT_QP_ACCESS_ERR\n",
- nesqp->hwqp.qp_id, async_event_id);
- nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_ACCESS_ERR);
- break;
-
- case NES_AEQE_AEID_LLP_SEGMENT_TOO_LARGE:
- case NES_AEQE_AEID_LLP_SEGMENT_TOO_SMALL:
- case NES_AEQE_AEID_DDP_UBE_INVALID_MO:
- case NES_AEQE_AEID_DDP_UBE_INVALID_QN:
- if (iwarp_opcode(nesqp, aeq_info) > IWARP_OPCODE_TERM) {
- aeq_info &= 0xffff0000;
- aeq_info |= NES_AEQE_AEID_RDMAP_ROE_UNEXPECTED_OPCODE;
- aeqe->aeqe_words[NES_AEQE_MISC_IDX] = cpu_to_le32(aeq_info);
- }
- /* fall through */
- case NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE:
- case NES_AEQE_AEID_LLP_TOO_MANY_RETRIES:
- case NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE:
- case NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR:
- case NES_AEQE_AEID_AMP_BAD_QP:
- case NES_AEQE_AEID_LLP_RECEIVED_MARKER_AND_LENGTH_FIELDS_DONT_MATCH:
- case NES_AEQE_AEID_DDP_LCE_LOCAL_CATASTROPHIC:
- case NES_AEQE_AEID_DDP_NO_L_BIT:
- case NES_AEQE_AEID_DDP_INVALID_MSN_GAP_IN_MSN:
- case NES_AEQE_AEID_DDP_INVALID_MSN_RANGE_IS_NOT_VALID:
- case NES_AEQE_AEID_DDP_UBE_INVALID_DDP_VERSION:
- case NES_AEQE_AEID_RDMAP_ROE_INVALID_RDMAP_VERSION:
- case NES_AEQE_AEID_RDMAP_ROE_UNEXPECTED_OPCODE:
- case NES_AEQE_AEID_AMP_BAD_PD:
- case NES_AEQE_AEID_AMP_FASTREG_SHARED:
- case NES_AEQE_AEID_AMP_FASTREG_VALID_STAG:
- case NES_AEQE_AEID_AMP_FASTREG_MW_STAG:
- case NES_AEQE_AEID_AMP_FASTREG_INVALID_RIGHTS:
- case NES_AEQE_AEID_AMP_FASTREG_PBL_TABLE_OVERFLOW:
- case NES_AEQE_AEID_AMP_FASTREG_INVALID_LENGTH:
- case NES_AEQE_AEID_AMP_INVALIDATE_SHARED:
- case NES_AEQE_AEID_AMP_INVALIDATE_MR_WITH_BOUND_WINDOWS:
- case NES_AEQE_AEID_AMP_MWBIND_VALID_STAG:
- case NES_AEQE_AEID_AMP_MWBIND_OF_MR_STAG:
- case NES_AEQE_AEID_AMP_MWBIND_TO_ZERO_BASED_STAG:
- case NES_AEQE_AEID_AMP_MWBIND_TO_MW_STAG:
- case NES_AEQE_AEID_AMP_MWBIND_INVALID_RIGHTS:
- case NES_AEQE_AEID_AMP_MWBIND_INVALID_BOUNDS:
- case NES_AEQE_AEID_AMP_MWBIND_TO_INVALID_PARENT:
- case NES_AEQE_AEID_AMP_MWBIND_BIND_DISABLED:
- case NES_AEQE_AEID_BAD_CLOSE:
- case NES_AEQE_AEID_RDMA_READ_WHILE_ORD_ZERO:
- case NES_AEQE_AEID_STAG_ZERO_INVALID:
- case NES_AEQE_AEID_ROE_INVALID_RDMA_READ_REQUEST:
- case NES_AEQE_AEID_ROE_INVALID_RDMA_WRITE_OR_READ_RESP:
- printk(KERN_ERR PFX "QP[%u] async_event_id=0x%04X IB_EVENT_QP_FATAL\n",
- nesqp->hwqp.qp_id, async_event_id);
- print_ip(nesqp->cm_node);
- if (!atomic_read(&nesqp->close_timer_started))
- nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_FATAL);
- break;
-
- case NES_AEQE_AEID_CQ_OPERATION_ERROR:
- context <<= 1;
- nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_CQ_OPERATION_ERROR event on CQ%u, %p\n",
- le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]), (void *)(unsigned long)context);
- resource_allocated = nes_is_resource_allocated(nesadapter, nesadapter->allocated_cqs,
- le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]));
- if (resource_allocated) {
- printk(KERN_ERR PFX "%s: Processing an NES_AEQE_AEID_CQ_OPERATION_ERROR event on CQ%u\n",
- __func__, le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]));
- hw_cq = (struct nes_hw_cq *)(unsigned long)context;
- if (hw_cq) {
- nescq = container_of(hw_cq, struct nes_cq, hw_cq);
- if (nescq->ibcq.event_handler) {
- ibevent.device = nescq->ibcq.device;
- ibevent.event = IB_EVENT_CQ_ERR;
- ibevent.element.cq = &nescq->ibcq;
- nescq->ibcq.event_handler(&ibevent, nescq->ibcq.cq_context);
- }
- }
- }
- break;
-
- default:
- nes_debug(NES_DBG_AEQ, "Processing an iWARP related AE for QP, misc = 0x%04X\n",
- async_event_id);
- break;
- }
-
-}
-
-/**
- * nes_iwarp_ce_handler
- */
-void nes_iwarp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *hw_cq)
-{
- struct nes_cq *nescq = container_of(hw_cq, struct nes_cq, hw_cq);
-
- /* nes_debug(NES_DBG_CQ, "Processing completion event for iWARP CQ%u.\n",
- nescq->hw_cq.cq_number); */
- nes_write32(nesdev->regs+NES_CQ_ACK, nescq->hw_cq.cq_number);
-
- if (nescq->ibcq.comp_handler)
- nescq->ibcq.comp_handler(&nescq->ibcq, nescq->ibcq.cq_context);
-
- return;
-}
-
-
-/**
- * nes_manage_apbvt()
- */
-int nes_manage_apbvt(struct nes_vnic *nesvnic, u32 accel_local_port,
- u32 nic_index, u32 add_port)
-{
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_hw_cqp_wqe *cqp_wqe;
- struct nes_cqp_request *cqp_request;
- int ret = 0;
- u16 major_code;
-
- /* Send manage APBVT request to CQP */
- cqp_request = nes_get_cqp_request(nesdev);
- if (cqp_request == NULL) {
- nes_debug(NES_DBG_QP, "Failed to get a cqp_request.\n");
- return -ENOMEM;
- }
- cqp_request->waiting = 1;
- cqp_wqe = &cqp_request->cqp_wqe;
-
- nes_debug(NES_DBG_QP, "%s APBV for local port=%u(0x%04x), nic_index=%u\n",
- (add_port == NES_MANAGE_APBVT_ADD) ? "ADD" : "DEL",
- accel_local_port, accel_local_port, nic_index);
-
- nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, (NES_CQP_MANAGE_APBVT |
- ((add_port == NES_MANAGE_APBVT_ADD) ? NES_CQP_APBVT_ADD : 0)));
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX,
- ((nic_index << NES_CQP_APBVT_NIC_SHIFT) | accel_local_port));
-
- nes_debug(NES_DBG_QP, "Waiting for CQP completion for APBVT.\n");
-
- atomic_set(&cqp_request->refcount, 2);
- nes_post_cqp_request(nesdev, cqp_request);
-
- if (add_port == NES_MANAGE_APBVT_ADD)
- ret = wait_event_timeout(cqp_request->waitq, (cqp_request->request_done != 0),
- NES_EVENT_TIMEOUT);
- nes_debug(NES_DBG_QP, "Completed, ret=%u, CQP Major:Minor codes = 0x%04X:0x%04X\n",
- ret, cqp_request->major_code, cqp_request->minor_code);
- major_code = cqp_request->major_code;
-
- nes_put_cqp_request(nesdev, cqp_request);
-
- if (!ret)
- return -ETIME;
- else if (major_code)
- return -EIO;
- else
- return 0;
-}
-
-
-/**
- * nes_manage_arp_cache
- */
-void nes_manage_arp_cache(struct net_device *netdev, unsigned char *mac_addr,
- u32 ip_addr, u32 action)
-{
- struct nes_hw_cqp_wqe *cqp_wqe;
- struct nes_vnic *nesvnic = netdev_priv(netdev);
- struct nes_device *nesdev;
- struct nes_cqp_request *cqp_request;
- int arp_index;
-
- nesdev = nesvnic->nesdev;
- arp_index = nes_arp_table(nesdev, ip_addr, mac_addr, action);
- if (arp_index == -1) {
- return;
- }
-
- /* update the ARP entry */
- cqp_request = nes_get_cqp_request(nesdev);
- if (cqp_request == NULL) {
- nes_debug(NES_DBG_NETDEV, "Failed to get a cqp_request.\n");
- return;
- }
- cqp_request->waiting = 0;
- cqp_wqe = &cqp_request->cqp_wqe;
- nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
-
- cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(
- NES_CQP_MANAGE_ARP_CACHE | NES_CQP_ARP_PERM);
- cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |= cpu_to_le32(
- (u32)PCI_FUNC(nesdev->pcidev->devfn) << NES_CQP_ARP_AEQ_INDEX_SHIFT);
- cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(arp_index);
-
- if (action == NES_ARP_ADD) {
- cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |= cpu_to_le32(NES_CQP_ARP_VALID);
- cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_ADDR_LOW_IDX] = cpu_to_le32(
- (((u32)mac_addr[2]) << 24) | (((u32)mac_addr[3]) << 16) |
- (((u32)mac_addr[4]) << 8) | (u32)mac_addr[5]);
- cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_HIGH_IDX] = cpu_to_le32(
- (((u32)mac_addr[0]) << 8) | (u32)mac_addr[1]);
- } else {
- cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_ADDR_LOW_IDX] = 0;
- cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_HIGH_IDX] = 0;
- }
-
- nes_debug(NES_DBG_NETDEV, "Not waiting for CQP, cqp.sq_head=%u, cqp.sq_tail=%u\n",
- nesdev->cqp.sq_head, nesdev->cqp.sq_tail);
-
- atomic_set(&cqp_request->refcount, 1);
- nes_post_cqp_request(nesdev, cqp_request);
-}
-
-
-/**
- * flush_wqes
- */
-void flush_wqes(struct nes_device *nesdev, struct nes_qp *nesqp,
- u32 which_wq, u32 wait_completion)
-{
- struct nes_cqp_request *cqp_request;
- struct nes_hw_cqp_wqe *cqp_wqe;
- u32 sq_code = (NES_IWARP_CQE_MAJOR_FLUSH << 16) | NES_IWARP_CQE_MINOR_FLUSH;
- u32 rq_code = (NES_IWARP_CQE_MAJOR_FLUSH << 16) | NES_IWARP_CQE_MINOR_FLUSH;
- int ret;
-
- cqp_request = nes_get_cqp_request(nesdev);
- if (cqp_request == NULL) {
- nes_debug(NES_DBG_QP, "Failed to get a cqp_request.\n");
- return;
- }
- if (wait_completion) {
- cqp_request->waiting = 1;
- atomic_set(&cqp_request->refcount, 2);
- } else {
- cqp_request->waiting = 0;
- }
- cqp_wqe = &cqp_request->cqp_wqe;
- nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
-
- /* If wqe in error was identified, set code to be put into cqe */
- if ((nesqp->term_sq_flush_code) && (which_wq & NES_CQP_FLUSH_SQ)) {
- which_wq |= NES_CQP_FLUSH_MAJ_MIN;
- sq_code = (CQE_MAJOR_DRV << 16) | nesqp->term_sq_flush_code;
- nesqp->term_sq_flush_code = 0;
- }
-
- if ((nesqp->term_rq_flush_code) && (which_wq & NES_CQP_FLUSH_RQ)) {
- which_wq |= NES_CQP_FLUSH_MAJ_MIN;
- rq_code = (CQE_MAJOR_DRV << 16) | nesqp->term_rq_flush_code;
- nesqp->term_rq_flush_code = 0;
- }
-
- if (which_wq & NES_CQP_FLUSH_MAJ_MIN) {
- cqp_wqe->wqe_words[NES_CQP_QP_WQE_FLUSH_SQ_CODE] = cpu_to_le32(sq_code);
- cqp_wqe->wqe_words[NES_CQP_QP_WQE_FLUSH_RQ_CODE] = cpu_to_le32(rq_code);
- }
-
- cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] =
- cpu_to_le32(NES_CQP_FLUSH_WQES | which_wq);
- cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesqp->hwqp.qp_id);
-
- nes_post_cqp_request(nesdev, cqp_request);
-
- if (wait_completion) {
- /* Wait for CQP */
- ret = wait_event_timeout(cqp_request->waitq, (cqp_request->request_done != 0),
- NES_EVENT_TIMEOUT);
- nes_debug(NES_DBG_QP, "Flush SQ QP WQEs completed, ret=%u,"
- " CQP Major:Minor codes = 0x%04X:0x%04X\n",
- ret, cqp_request->major_code, cqp_request->minor_code);
- nes_put_cqp_request(nesdev, cqp_request);
- }
-}
diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h
deleted file mode 100644
index 3c56470816a8..000000000000
--- a/drivers/infiniband/hw/nes/nes_hw.h
+++ /dev/null
@@ -1,1380 +0,0 @@
-/*
-* Copyright (c) 2006 - 2011 Intel Corporation. All rights reserved.
-*
-* This software is available to you under a choice of one of two
-* licenses. You may choose to be licensed under the terms of the GNU
-* General Public License (GPL) Version 2, available from the file
-* COPYING in the main directory of this source tree, or the
-* OpenIB.org BSD license below:
-*
-* Redistribution and use in source and binary forms, with or
-* without modification, are permitted provided that the following
-* conditions are met:
-*
-* - Redistributions of source code must retain the above
-* copyright notice, this list of conditions and the following
-* disclaimer.
-*
-* - Redistributions in binary form must reproduce the above
-* copyright notice, this list of conditions and the following
-* disclaimer in the documentation and/or other materials
-* provided with the distribution.
-*
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
-* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-* SOFTWARE.
-*/
-
-#ifndef __NES_HW_H
-#define __NES_HW_H
-
-#define NES_PHY_TYPE_CX4 1
-#define NES_PHY_TYPE_1G 2
-#define NES_PHY_TYPE_ARGUS 4
-#define NES_PHY_TYPE_PUMA_1G 5
-#define NES_PHY_TYPE_PUMA_10G 6
-#define NES_PHY_TYPE_GLADIUS 7
-#define NES_PHY_TYPE_SFP_D 8
-#define NES_PHY_TYPE_KR 9
-
-#define NES_MULTICAST_PF_MAX 8
-#define NES_A0 3
-
-#define NES_ENABLE_PAU 0x07000001
-#define NES_DISABLE_PAU 0x07000000
-#define NES_PAU_COUNTER 10
-#define NES_CQP_OPCODE_MASK 0x3f
-
-enum pci_regs {
- NES_INT_STAT = 0x0000,
- NES_INT_MASK = 0x0004,
- NES_INT_PENDING = 0x0008,
- NES_INTF_INT_STAT = 0x000C,
- NES_INTF_INT_MASK = 0x0010,
- NES_TIMER_STAT = 0x0014,
- NES_PERIODIC_CONTROL = 0x0018,
- NES_ONE_SHOT_CONTROL = 0x001C,
- NES_EEPROM_COMMAND = 0x0020,
- NES_EEPROM_DATA = 0x0024,
- NES_FLASH_COMMAND = 0x0028,
- NES_FLASH_DATA = 0x002C,
- NES_SOFTWARE_RESET = 0x0030,
- NES_CQ_ACK = 0x0034,
- NES_WQE_ALLOC = 0x0040,
- NES_CQE_ALLOC = 0x0044,
- NES_AEQ_ALLOC = 0x0048
-};
-
-enum indexed_regs {
- NES_IDX_CREATE_CQP_LOW = 0x0000,
- NES_IDX_CREATE_CQP_HIGH = 0x0004,
- NES_IDX_QP_CONTROL = 0x0040,
- NES_IDX_FLM_CONTROL = 0x0080,
- NES_IDX_INT_CPU_STATUS = 0x00a0,
- NES_IDX_GPR_TRIGGER = 0x00bc,
- NES_IDX_GPIO_CONTROL = 0x00f0,
- NES_IDX_GPIO_DATA = 0x00f4,
- NES_IDX_GPR2 = 0x010c,
- NES_IDX_TCP_CONFIG0 = 0x01e4,
- NES_IDX_TCP_TIMER_CONFIG = 0x01ec,
- NES_IDX_TCP_NOW = 0x01f0,
- NES_IDX_QP_MAX_CFG_SIZES = 0x0200,
- NES_IDX_QP_CTX_SIZE = 0x0218,
- NES_IDX_TCP_TIMER_SIZE0 = 0x0238,
- NES_IDX_TCP_TIMER_SIZE1 = 0x0240,
- NES_IDX_ARP_CACHE_SIZE = 0x0258,
- NES_IDX_CQ_CTX_SIZE = 0x0260,
- NES_IDX_MRT_SIZE = 0x0278,
- NES_IDX_PBL_REGION_SIZE = 0x0280,
- NES_IDX_IRRQ_COUNT = 0x02b0,
- NES_IDX_RX_WINDOW_BUFFER_PAGE_TABLE_SIZE = 0x02f0,
- NES_IDX_RX_WINDOW_BUFFER_SIZE = 0x0300,
- NES_IDX_DST_IP_ADDR = 0x0400,
- NES_IDX_PCIX_DIAG = 0x08e8,
- NES_IDX_MPP_DEBUG = 0x0a00,
- NES_IDX_PORT_RX_DISCARDS = 0x0a30,
- NES_IDX_PORT_TX_DISCARDS = 0x0a34,
- NES_IDX_MPP_LB_DEBUG = 0x0b00,
- NES_IDX_DENALI_CTL_22 = 0x1058,
- NES_IDX_MAC_TX_CONTROL = 0x2000,
- NES_IDX_MAC_TX_CONFIG = 0x2004,
- NES_IDX_MAC_TX_PAUSE_QUANTA = 0x2008,
- NES_IDX_MAC_RX_CONTROL = 0x200c,
- NES_IDX_MAC_RX_CONFIG = 0x2010,
- NES_IDX_MAC_EXACT_MATCH_BOTTOM = 0x201c,
- NES_IDX_MAC_MDIO_CONTROL = 0x2084,
- NES_IDX_MAC_TX_OCTETS_LOW = 0x2100,
- NES_IDX_MAC_TX_OCTETS_HIGH = 0x2104,
- NES_IDX_MAC_TX_FRAMES_LOW = 0x2108,
- NES_IDX_MAC_TX_FRAMES_HIGH = 0x210c,
- NES_IDX_MAC_TX_PAUSE_FRAMES = 0x2118,
- NES_IDX_MAC_TX_ERRORS = 0x2138,
- NES_IDX_MAC_RX_OCTETS_LOW = 0x213c,
- NES_IDX_MAC_RX_OCTETS_HIGH = 0x2140,
- NES_IDX_MAC_RX_FRAMES_LOW = 0x2144,
- NES_IDX_MAC_RX_FRAMES_HIGH = 0x2148,
- NES_IDX_MAC_RX_BC_FRAMES_LOW = 0x214c,
- NES_IDX_MAC_RX_MC_FRAMES_HIGH = 0x2150,
- NES_IDX_MAC_RX_PAUSE_FRAMES = 0x2154,
- NES_IDX_MAC_RX_SHORT_FRAMES = 0x2174,
- NES_IDX_MAC_RX_OVERSIZED_FRAMES = 0x2178,
- NES_IDX_MAC_RX_JABBER_FRAMES = 0x217c,
- NES_IDX_MAC_RX_CRC_ERR_FRAMES = 0x2180,
- NES_IDX_MAC_RX_LENGTH_ERR_FRAMES = 0x2184,
- NES_IDX_MAC_RX_SYMBOL_ERR_FRAMES = 0x2188,
- NES_IDX_MAC_INT_STATUS = 0x21f0,
- NES_IDX_MAC_INT_MASK = 0x21f4,
- NES_IDX_PHY_PCS_CONTROL_STATUS0 = 0x2800,
- NES_IDX_PHY_PCS_CONTROL_STATUS1 = 0x2a00,
- NES_IDX_ETH_SERDES_COMMON_CONTROL0 = 0x2808,
- NES_IDX_ETH_SERDES_COMMON_CONTROL1 = 0x2a08,
- NES_IDX_ETH_SERDES_COMMON_STATUS0 = 0x280c,
- NES_IDX_ETH_SERDES_COMMON_STATUS1 = 0x2a0c,
- NES_IDX_ETH_SERDES_TX_EMP0 = 0x2810,
- NES_IDX_ETH_SERDES_TX_EMP1 = 0x2a10,
- NES_IDX_ETH_SERDES_TX_DRIVE0 = 0x2814,
- NES_IDX_ETH_SERDES_TX_DRIVE1 = 0x2a14,
- NES_IDX_ETH_SERDES_RX_MODE0 = 0x2818,
- NES_IDX_ETH_SERDES_RX_MODE1 = 0x2a18,
- NES_IDX_ETH_SERDES_RX_SIGDET0 = 0x281c,
- NES_IDX_ETH_SERDES_RX_SIGDET1 = 0x2a1c,
- NES_IDX_ETH_SERDES_BYPASS0 = 0x2820,
- NES_IDX_ETH_SERDES_BYPASS1 = 0x2a20,
- NES_IDX_ETH_SERDES_LOOPBACK_CONTROL0 = 0x2824,
- NES_IDX_ETH_SERDES_LOOPBACK_CONTROL1 = 0x2a24,
- NES_IDX_ETH_SERDES_RX_EQ_CONTROL0 = 0x2828,
- NES_IDX_ETH_SERDES_RX_EQ_CONTROL1 = 0x2a28,
- NES_IDX_ETH_SERDES_RX_EQ_STATUS0 = 0x282c,
- NES_IDX_ETH_SERDES_RX_EQ_STATUS1 = 0x2a2c,
- NES_IDX_ETH_SERDES_CDR_RESET0 = 0x2830,
- NES_IDX_ETH_SERDES_CDR_RESET1 = 0x2a30,
- NES_IDX_ETH_SERDES_CDR_CONTROL0 = 0x2834,
- NES_IDX_ETH_SERDES_CDR_CONTROL1 = 0x2a34,
- NES_IDX_ETH_SERDES_TX_HIGHZ_LANE_MODE0 = 0x2838,
- NES_IDX_ETH_SERDES_TX_HIGHZ_LANE_MODE1 = 0x2a38,
- NES_IDX_ENDNODE0_NSTAT_RX_DISCARD = 0x3080,
- NES_IDX_ENDNODE0_NSTAT_RX_OCTETS_LO = 0x3000,
- NES_IDX_ENDNODE0_NSTAT_RX_OCTETS_HI = 0x3004,
- NES_IDX_ENDNODE0_NSTAT_RX_FRAMES_LO = 0x3008,
- NES_IDX_ENDNODE0_NSTAT_RX_FRAMES_HI = 0x300c,
- NES_IDX_ENDNODE0_NSTAT_TX_OCTETS_LO = 0x7000,
- NES_IDX_ENDNODE0_NSTAT_TX_OCTETS_HI = 0x7004,
- NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_LO = 0x7008,
- NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_HI = 0x700c,
- NES_IDX_WQM_CONFIG0 = 0x5000,
- NES_IDX_WQM_CONFIG1 = 0x5004,
- NES_IDX_CM_CONFIG = 0x5100,
- NES_IDX_NIC_LOGPORT_TO_PHYPORT = 0x6000,
- NES_IDX_NIC_PHYPORT_TO_USW = 0x6008,
- NES_IDX_NIC_ACTIVE = 0x6010,
- NES_IDX_NIC_UNICAST_ALL = 0x6018,
- NES_IDX_NIC_MULTICAST_ALL = 0x6020,
- NES_IDX_NIC_MULTICAST_ENABLE = 0x6028,
- NES_IDX_NIC_BROADCAST_ON = 0x6030,
- NES_IDX_USED_CHUNKS_TX = 0x60b0,
- NES_IDX_TX_POOL_SIZE = 0x60b8,
- NES_IDX_QUAD_HASH_TABLE_SIZE = 0x6148,
- NES_IDX_PERFECT_FILTER_LOW = 0x6200,
- NES_IDX_PERFECT_FILTER_HIGH = 0x6204,
- NES_IDX_IPV4_TCP_REXMITS = 0x7080,
- NES_IDX_DEBUG_ERROR_CONTROL_STATUS = 0x913c,
- NES_IDX_DEBUG_ERROR_MASKS0 = 0x9140,
- NES_IDX_DEBUG_ERROR_MASKS1 = 0x9144,
- NES_IDX_DEBUG_ERROR_MASKS2 = 0x9148,
- NES_IDX_DEBUG_ERROR_MASKS3 = 0x914c,
- NES_IDX_DEBUG_ERROR_MASKS4 = 0x9150,
- NES_IDX_DEBUG_ERROR_MASKS5 = 0x9154,
-};
-
-#define NES_IDX_MAC_TX_CONFIG_ENABLE_PAUSE 1
-#define NES_IDX_MPP_DEBUG_PORT_DISABLE_PAUSE (1 << 17)
-
-enum nes_cqp_opcodes {
- NES_CQP_CREATE_QP = 0x00,
- NES_CQP_MODIFY_QP = 0x01,
- NES_CQP_DESTROY_QP = 0x02,
- NES_CQP_CREATE_CQ = 0x03,
- NES_CQP_MODIFY_CQ = 0x04,
- NES_CQP_DESTROY_CQ = 0x05,
- NES_CQP_ALLOCATE_STAG = 0x09,
- NES_CQP_REGISTER_STAG = 0x0a,
- NES_CQP_QUERY_STAG = 0x0b,
- NES_CQP_REGISTER_SHARED_STAG = 0x0c,
- NES_CQP_DEALLOCATE_STAG = 0x0d,
- NES_CQP_MANAGE_ARP_CACHE = 0x0f,
- NES_CQP_DOWNLOAD_SEGMENT = 0x10,
- NES_CQP_SUSPEND_QPS = 0x11,
- NES_CQP_UPLOAD_CONTEXT = 0x13,
- NES_CQP_CREATE_CEQ = 0x16,
- NES_CQP_DESTROY_CEQ = 0x18,
- NES_CQP_CREATE_AEQ = 0x19,
- NES_CQP_DESTROY_AEQ = 0x1b,
- NES_CQP_LMI_ACCESS = 0x20,
- NES_CQP_FLUSH_WQES = 0x22,
- NES_CQP_MANAGE_APBVT = 0x23,
- NES_CQP_MANAGE_QUAD_HASH = 0x25
-};
-
-enum nes_cqp_wqe_word_idx {
- NES_CQP_WQE_OPCODE_IDX = 0,
- NES_CQP_WQE_ID_IDX = 1,
- NES_CQP_WQE_COMP_CTX_LOW_IDX = 2,
- NES_CQP_WQE_COMP_CTX_HIGH_IDX = 3,
- NES_CQP_WQE_COMP_SCRATCH_LOW_IDX = 4,
- NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX = 5,
-};
-
-enum nes_cqp_wqe_word_download_idx { /* format differs from other cqp ops */
- NES_CQP_WQE_DL_OPCODE_IDX = 0,
- NES_CQP_WQE_DL_COMP_CTX_LOW_IDX = 1,
- NES_CQP_WQE_DL_COMP_CTX_HIGH_IDX = 2,
- NES_CQP_WQE_DL_LENGTH_0_TOTAL_IDX = 3
- /* For index values 4-15 use NES_NIC_SQ_WQE_ values */
-};
-
-enum nes_cqp_cq_wqeword_idx {
- NES_CQP_CQ_WQE_PBL_LOW_IDX = 6,
- NES_CQP_CQ_WQE_PBL_HIGH_IDX = 7,
- NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX = 8,
- NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX = 9,
- NES_CQP_CQ_WQE_DOORBELL_INDEX_HIGH_IDX = 10,
-};
-
-enum nes_cqp_stag_wqeword_idx {
- NES_CQP_STAG_WQE_PBL_BLK_COUNT_IDX = 1,
- NES_CQP_STAG_WQE_LEN_HIGH_PD_IDX = 6,
- NES_CQP_STAG_WQE_LEN_LOW_IDX = 7,
- NES_CQP_STAG_WQE_STAG_IDX = 8,
- NES_CQP_STAG_WQE_VA_LOW_IDX = 10,
- NES_CQP_STAG_WQE_VA_HIGH_IDX = 11,
- NES_CQP_STAG_WQE_PA_LOW_IDX = 12,
- NES_CQP_STAG_WQE_PA_HIGH_IDX = 13,
- NES_CQP_STAG_WQE_PBL_LEN_IDX = 14
-};
-
-#define NES_CQP_OP_LOGICAL_PORT_SHIFT 26
-#define NES_CQP_OP_IWARP_STATE_SHIFT 28
-#define NES_CQP_OP_TERMLEN_SHIFT 28
-
-enum nes_cqp_qp_bits {
- NES_CQP_QP_ARP_VALID = (1<<8),
- NES_CQP_QP_WINBUF_VALID = (1<<9),
- NES_CQP_QP_CONTEXT_VALID = (1<<10),
- NES_CQP_QP_ORD_VALID = (1<<11),
- NES_CQP_QP_WINBUF_DATAIND_EN = (1<<12),
- NES_CQP_QP_VIRT_WQS = (1<<13),
- NES_CQP_QP_DEL_HTE = (1<<14),
- NES_CQP_QP_CQS_VALID = (1<<15),
- NES_CQP_QP_TYPE_TSA = 0,
- NES_CQP_QP_TYPE_IWARP = (1<<16),
- NES_CQP_QP_TYPE_CQP = (4<<16),
- NES_CQP_QP_TYPE_NIC = (5<<16),
- NES_CQP_QP_MSS_CHG = (1<<20),
- NES_CQP_QP_STATIC_RESOURCES = (1<<21),
- NES_CQP_QP_IGNORE_MW_BOUND = (1<<22),
- NES_CQP_QP_VWQ_USE_LMI = (1<<23),
- NES_CQP_QP_IWARP_STATE_IDLE = (1<<NES_CQP_OP_IWARP_STATE_SHIFT),
- NES_CQP_QP_IWARP_STATE_RTS = (2<<NES_CQP_OP_IWARP_STATE_SHIFT),
- NES_CQP_QP_IWARP_STATE_CLOSING = (3<<NES_CQP_OP_IWARP_STATE_SHIFT),
- NES_CQP_QP_IWARP_STATE_TERMINATE = (5<<NES_CQP_OP_IWARP_STATE_SHIFT),
- NES_CQP_QP_IWARP_STATE_ERROR = (6<<NES_CQP_OP_IWARP_STATE_SHIFT),
- NES_CQP_QP_IWARP_STATE_MASK = (7<<NES_CQP_OP_IWARP_STATE_SHIFT),
- NES_CQP_QP_TERM_DONT_SEND_FIN = (1<<24),
- NES_CQP_QP_TERM_DONT_SEND_TERM_MSG = (1<<25),
- NES_CQP_QP_RESET = (1<<31),
-};
-
-enum nes_cqp_qp_wqe_word_idx {
- NES_CQP_QP_WQE_CONTEXT_LOW_IDX = 6,
- NES_CQP_QP_WQE_CONTEXT_HIGH_IDX = 7,
- NES_CQP_QP_WQE_FLUSH_SQ_CODE = 8,
- NES_CQP_QP_WQE_FLUSH_RQ_CODE = 9,
- NES_CQP_QP_WQE_NEW_MSS_IDX = 15,
-};
-
-enum nes_nic_ctx_bits {
- NES_NIC_CTX_RQ_SIZE_32 = (3<<8),
- NES_NIC_CTX_RQ_SIZE_512 = (3<<8),
- NES_NIC_CTX_SQ_SIZE_32 = (1<<10),
- NES_NIC_CTX_SQ_SIZE_512 = (3<<10),
-};
-
-enum nes_nic_qp_ctx_word_idx {
- NES_NIC_CTX_MISC_IDX = 0,
- NES_NIC_CTX_SQ_LOW_IDX = 2,
- NES_NIC_CTX_SQ_HIGH_IDX = 3,
- NES_NIC_CTX_RQ_LOW_IDX = 4,
- NES_NIC_CTX_RQ_HIGH_IDX = 5,
-};
-
-enum nes_cqp_cq_bits {
- NES_CQP_CQ_CEQE_MASK = (1<<9),
- NES_CQP_CQ_CEQ_VALID = (1<<10),
- NES_CQP_CQ_RESIZE = (1<<11),
- NES_CQP_CQ_CHK_OVERFLOW = (1<<12),
- NES_CQP_CQ_4KB_CHUNK = (1<<14),
- NES_CQP_CQ_VIRT = (1<<15),
-};
-
-enum nes_cqp_stag_bits {
- NES_CQP_STAG_VA_TO = (1<<9),
- NES_CQP_STAG_DEALLOC_PBLS = (1<<10),
- NES_CQP_STAG_PBL_BLK_SIZE = (1<<11),
- NES_CQP_STAG_MR = (1<<13),
- NES_CQP_STAG_RIGHTS_LOCAL_READ = (1<<16),
- NES_CQP_STAG_RIGHTS_LOCAL_WRITE = (1<<17),
- NES_CQP_STAG_RIGHTS_REMOTE_READ = (1<<18),
- NES_CQP_STAG_RIGHTS_REMOTE_WRITE = (1<<19),
- NES_CQP_STAG_RIGHTS_WINDOW_BIND = (1<<20),
- NES_CQP_STAG_REM_ACC_EN = (1<<21),
- NES_CQP_STAG_LEAVE_PENDING = (1<<31),
-};
-
-enum nes_cqp_ceq_wqeword_idx {
- NES_CQP_CEQ_WQE_ELEMENT_COUNT_IDX = 1,
- NES_CQP_CEQ_WQE_PBL_LOW_IDX = 6,
- NES_CQP_CEQ_WQE_PBL_HIGH_IDX = 7,
-};
-
-enum nes_cqp_ceq_bits {
- NES_CQP_CEQ_4KB_CHUNK = (1<<14),
- NES_CQP_CEQ_VIRT = (1<<15),
-};
-
-enum nes_cqp_aeq_wqeword_idx {
- NES_CQP_AEQ_WQE_ELEMENT_COUNT_IDX = 1,
- NES_CQP_AEQ_WQE_PBL_LOW_IDX = 6,
- NES_CQP_AEQ_WQE_PBL_HIGH_IDX = 7,
-};
-
-enum nes_cqp_aeq_bits {
- NES_CQP_AEQ_4KB_CHUNK = (1<<14),
- NES_CQP_AEQ_VIRT = (1<<15),
-};
-
-enum nes_cqp_lmi_wqeword_idx {
- NES_CQP_LMI_WQE_LMI_OFFSET_IDX = 1,
- NES_CQP_LMI_WQE_FRAG_LOW_IDX = 8,
- NES_CQP_LMI_WQE_FRAG_HIGH_IDX = 9,
- NES_CQP_LMI_WQE_FRAG_LEN_IDX = 10,
-};
-
-enum nes_cqp_arp_wqeword_idx {
- NES_CQP_ARP_WQE_MAC_ADDR_LOW_IDX = 6,
- NES_CQP_ARP_WQE_MAC_HIGH_IDX = 7,
- NES_CQP_ARP_WQE_REACHABILITY_MAX_IDX = 1,
-};
-
-enum nes_cqp_upload_wqeword_idx {
- NES_CQP_UPLOAD_WQE_CTXT_LOW_IDX = 6,
- NES_CQP_UPLOAD_WQE_CTXT_HIGH_IDX = 7,
- NES_CQP_UPLOAD_WQE_HTE_IDX = 8,
-};
-
-enum nes_cqp_arp_bits {
- NES_CQP_ARP_VALID = (1<<8),
- NES_CQP_ARP_PERM = (1<<9),
-};
-
-enum nes_cqp_flush_bits {
- NES_CQP_FLUSH_SQ = (1<<30),
- NES_CQP_FLUSH_RQ = (1<<31),
- NES_CQP_FLUSH_MAJ_MIN = (1<<28),
-};
-
-enum nes_cqe_opcode_bits {
- NES_CQE_STAG_VALID = (1<<6),
- NES_CQE_ERROR = (1<<7),
- NES_CQE_SQ = (1<<8),
- NES_CQE_SE = (1<<9),
- NES_CQE_PSH = (1<<29),
- NES_CQE_FIN = (1<<30),
- NES_CQE_VALID = (1<<31),
-};
-
-
-enum nes_cqe_word_idx {
- NES_CQE_PAYLOAD_LENGTH_IDX = 0,
- NES_CQE_COMP_COMP_CTX_LOW_IDX = 2,
- NES_CQE_COMP_COMP_CTX_HIGH_IDX = 3,
- NES_CQE_INV_STAG_IDX = 4,
- NES_CQE_QP_ID_IDX = 5,
- NES_CQE_ERROR_CODE_IDX = 6,
- NES_CQE_OPCODE_IDX = 7,
-};
-
-enum nes_ceqe_word_idx {
- NES_CEQE_CQ_CTX_LOW_IDX = 0,
- NES_CEQE_CQ_CTX_HIGH_IDX = 1,
-};
-
-enum nes_ceqe_status_bit {
- NES_CEQE_VALID = (1<<31),
-};
-
-enum nes_int_bits {
- NES_INT_CEQ0 = (1<<0),
- NES_INT_CEQ1 = (1<<1),
- NES_INT_CEQ2 = (1<<2),
- NES_INT_CEQ3 = (1<<3),
- NES_INT_CEQ4 = (1<<4),
- NES_INT_CEQ5 = (1<<5),
- NES_INT_CEQ6 = (1<<6),
- NES_INT_CEQ7 = (1<<7),
- NES_INT_CEQ8 = (1<<8),
- NES_INT_CEQ9 = (1<<9),
- NES_INT_CEQ10 = (1<<10),
- NES_INT_CEQ11 = (1<<11),
- NES_INT_CEQ12 = (1<<12),
- NES_INT_CEQ13 = (1<<13),
- NES_INT_CEQ14 = (1<<14),
- NES_INT_CEQ15 = (1<<15),
- NES_INT_AEQ0 = (1<<16),
- NES_INT_AEQ1 = (1<<17),
- NES_INT_AEQ2 = (1<<18),
- NES_INT_AEQ3 = (1<<19),
- NES_INT_AEQ4 = (1<<20),
- NES_INT_AEQ5 = (1<<21),
- NES_INT_AEQ6 = (1<<22),
- NES_INT_AEQ7 = (1<<23),
- NES_INT_MAC0 = (1<<24),
- NES_INT_MAC1 = (1<<25),
- NES_INT_MAC2 = (1<<26),
- NES_INT_MAC3 = (1<<27),
- NES_INT_TSW = (1<<28),
- NES_INT_TIMER = (1<<29),
- NES_INT_INTF = (1<<30),
-};
-
-enum nes_intf_int_bits {
- NES_INTF_INT_PCIERR = (1<<0),
- NES_INTF_PERIODIC_TIMER = (1<<2),
- NES_INTF_ONE_SHOT_TIMER = (1<<3),
- NES_INTF_INT_CRITERR = (1<<14),
- NES_INTF_INT_AEQ0_OFLOW = (1<<16),
- NES_INTF_INT_AEQ1_OFLOW = (1<<17),
- NES_INTF_INT_AEQ2_OFLOW = (1<<18),
- NES_INTF_INT_AEQ3_OFLOW = (1<<19),
- NES_INTF_INT_AEQ4_OFLOW = (1<<20),
- NES_INTF_INT_AEQ5_OFLOW = (1<<21),
- NES_INTF_INT_AEQ6_OFLOW = (1<<22),
- NES_INTF_INT_AEQ7_OFLOW = (1<<23),
- NES_INTF_INT_AEQ_OFLOW = (0xff<<16),
-};
-
-enum nes_mac_int_bits {
- NES_MAC_INT_LINK_STAT_CHG = (1<<1),
- NES_MAC_INT_XGMII_EXT = (1<<2),
- NES_MAC_INT_TX_UNDERFLOW = (1<<6),
- NES_MAC_INT_TX_ERROR = (1<<7),
-};
-
-enum nes_cqe_allocate_bits {
- NES_CQE_ALLOC_INC_SELECT = (1<<28),
- NES_CQE_ALLOC_NOTIFY_NEXT = (1<<29),
- NES_CQE_ALLOC_NOTIFY_SE = (1<<30),
- NES_CQE_ALLOC_RESET = (1<<31),
-};
-
-enum nes_nic_rq_wqe_word_idx {
- NES_NIC_RQ_WQE_LENGTH_1_0_IDX = 0,
- NES_NIC_RQ_WQE_LENGTH_3_2_IDX = 1,
- NES_NIC_RQ_WQE_FRAG0_LOW_IDX = 2,
- NES_NIC_RQ_WQE_FRAG0_HIGH_IDX = 3,
- NES_NIC_RQ_WQE_FRAG1_LOW_IDX = 4,
- NES_NIC_RQ_WQE_FRAG1_HIGH_IDX = 5,
- NES_NIC_RQ_WQE_FRAG2_LOW_IDX = 6,
- NES_NIC_RQ_WQE_FRAG2_HIGH_IDX = 7,
- NES_NIC_RQ_WQE_FRAG3_LOW_IDX = 8,
- NES_NIC_RQ_WQE_FRAG3_HIGH_IDX = 9,
-};
-
-enum nes_nic_sq_wqe_word_idx {
- NES_NIC_SQ_WQE_MISC_IDX = 0,
- NES_NIC_SQ_WQE_TOTAL_LENGTH_IDX = 1,
- NES_NIC_SQ_WQE_LSO_INFO_IDX = 2,
- NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX = 3,
- NES_NIC_SQ_WQE_LENGTH_2_1_IDX = 4,
- NES_NIC_SQ_WQE_LENGTH_4_3_IDX = 5,
- NES_NIC_SQ_WQE_FRAG0_LOW_IDX = 6,
- NES_NIC_SQ_WQE_FRAG0_HIGH_IDX = 7,
- NES_NIC_SQ_WQE_FRAG1_LOW_IDX = 8,
- NES_NIC_SQ_WQE_FRAG1_HIGH_IDX = 9,
- NES_NIC_SQ_WQE_FRAG2_LOW_IDX = 10,
- NES_NIC_SQ_WQE_FRAG2_HIGH_IDX = 11,
- NES_NIC_SQ_WQE_FRAG3_LOW_IDX = 12,
- NES_NIC_SQ_WQE_FRAG3_HIGH_IDX = 13,
- NES_NIC_SQ_WQE_FRAG4_LOW_IDX = 14,
- NES_NIC_SQ_WQE_FRAG4_HIGH_IDX = 15,
-};
-
-enum nes_iwarp_sq_wqe_word_idx {
- NES_IWARP_SQ_WQE_MISC_IDX = 0,
- NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX = 1,
- NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX = 2,
- NES_IWARP_SQ_WQE_COMP_CTX_HIGH_IDX = 3,
- NES_IWARP_SQ_WQE_COMP_SCRATCH_LOW_IDX = 4,
- NES_IWARP_SQ_WQE_COMP_SCRATCH_HIGH_IDX = 5,
- NES_IWARP_SQ_WQE_INV_STAG_LOW_IDX = 7,
- NES_IWARP_SQ_WQE_RDMA_TO_LOW_IDX = 8,
- NES_IWARP_SQ_WQE_RDMA_TO_HIGH_IDX = 9,
- NES_IWARP_SQ_WQE_RDMA_LENGTH_IDX = 10,
- NES_IWARP_SQ_WQE_RDMA_STAG_IDX = 11,
- NES_IWARP_SQ_WQE_IMM_DATA_START_IDX = 12,
- NES_IWARP_SQ_WQE_FRAG0_LOW_IDX = 16,
- NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX = 17,
- NES_IWARP_SQ_WQE_LENGTH0_IDX = 18,
- NES_IWARP_SQ_WQE_STAG0_IDX = 19,
- NES_IWARP_SQ_WQE_FRAG1_LOW_IDX = 20,
- NES_IWARP_SQ_WQE_FRAG1_HIGH_IDX = 21,
- NES_IWARP_SQ_WQE_LENGTH1_IDX = 22,
- NES_IWARP_SQ_WQE_STAG1_IDX = 23,
- NES_IWARP_SQ_WQE_FRAG2_LOW_IDX = 24,
- NES_IWARP_SQ_WQE_FRAG2_HIGH_IDX = 25,
- NES_IWARP_SQ_WQE_LENGTH2_IDX = 26,
- NES_IWARP_SQ_WQE_STAG2_IDX = 27,
- NES_IWARP_SQ_WQE_FRAG3_LOW_IDX = 28,
- NES_IWARP_SQ_WQE_FRAG3_HIGH_IDX = 29,
- NES_IWARP_SQ_WQE_LENGTH3_IDX = 30,
- NES_IWARP_SQ_WQE_STAG3_IDX = 31,
-};
-
-enum nes_iwarp_sq_bind_wqe_word_idx {
- NES_IWARP_SQ_BIND_WQE_MR_IDX = 6,
- NES_IWARP_SQ_BIND_WQE_MW_IDX = 7,
- NES_IWARP_SQ_BIND_WQE_LENGTH_LOW_IDX = 8,
- NES_IWARP_SQ_BIND_WQE_LENGTH_HIGH_IDX = 9,
- NES_IWARP_SQ_BIND_WQE_VA_FBO_LOW_IDX = 10,
- NES_IWARP_SQ_BIND_WQE_VA_FBO_HIGH_IDX = 11,
-};
-
-enum nes_iwarp_sq_fmr_wqe_word_idx {
- NES_IWARP_SQ_FMR_WQE_MR_STAG_IDX = 7,
- NES_IWARP_SQ_FMR_WQE_LENGTH_LOW_IDX = 8,
- NES_IWARP_SQ_FMR_WQE_LENGTH_HIGH_IDX = 9,
- NES_IWARP_SQ_FMR_WQE_VA_FBO_LOW_IDX = 10,
- NES_IWARP_SQ_FMR_WQE_VA_FBO_HIGH_IDX = 11,
- NES_IWARP_SQ_FMR_WQE_PBL_ADDR_LOW_IDX = 12,
- NES_IWARP_SQ_FMR_WQE_PBL_ADDR_HIGH_IDX = 13,
- NES_IWARP_SQ_FMR_WQE_PBL_LENGTH_IDX = 14,
-};
-
-enum nes_iwarp_sq_fmr_opcodes {
- NES_IWARP_SQ_FMR_WQE_ZERO_BASED = (1<<6),
- NES_IWARP_SQ_FMR_WQE_PAGE_SIZE_4K = (0<<7),
- NES_IWARP_SQ_FMR_WQE_PAGE_SIZE_2M = (1<<7),
- NES_IWARP_SQ_FMR_WQE_RIGHTS_ENABLE_LOCAL_READ = (1<<16),
- NES_IWARP_SQ_FMR_WQE_RIGHTS_ENABLE_LOCAL_WRITE = (1<<17),
- NES_IWARP_SQ_FMR_WQE_RIGHTS_ENABLE_REMOTE_READ = (1<<18),
- NES_IWARP_SQ_FMR_WQE_RIGHTS_ENABLE_REMOTE_WRITE = (1<<19),
- NES_IWARP_SQ_FMR_WQE_RIGHTS_ENABLE_WINDOW_BIND = (1<<20),
-};
-
-#define NES_IWARP_SQ_FMR_WQE_MR_LENGTH_HIGH_MASK 0xFF;
-
-enum nes_iwarp_sq_locinv_wqe_word_idx {
- NES_IWARP_SQ_LOCINV_WQE_INV_STAG_IDX = 6,
-};
-
-enum nes_iwarp_rq_wqe_word_idx {
- NES_IWARP_RQ_WQE_TOTAL_PAYLOAD_IDX = 1,
- NES_IWARP_RQ_WQE_COMP_CTX_LOW_IDX = 2,
- NES_IWARP_RQ_WQE_COMP_CTX_HIGH_IDX = 3,
- NES_IWARP_RQ_WQE_COMP_SCRATCH_LOW_IDX = 4,
- NES_IWARP_RQ_WQE_COMP_SCRATCH_HIGH_IDX = 5,
- NES_IWARP_RQ_WQE_FRAG0_LOW_IDX = 8,
- NES_IWARP_RQ_WQE_FRAG0_HIGH_IDX = 9,
- NES_IWARP_RQ_WQE_LENGTH0_IDX = 10,
- NES_IWARP_RQ_WQE_STAG0_IDX = 11,
- NES_IWARP_RQ_WQE_FRAG1_LOW_IDX = 12,
- NES_IWARP_RQ_WQE_FRAG1_HIGH_IDX = 13,
- NES_IWARP_RQ_WQE_LENGTH1_IDX = 14,
- NES_IWARP_RQ_WQE_STAG1_IDX = 15,
- NES_IWARP_RQ_WQE_FRAG2_LOW_IDX = 16,
- NES_IWARP_RQ_WQE_FRAG2_HIGH_IDX = 17,
- NES_IWARP_RQ_WQE_LENGTH2_IDX = 18,
- NES_IWARP_RQ_WQE_STAG2_IDX = 19,
- NES_IWARP_RQ_WQE_FRAG3_LOW_IDX = 20,
- NES_IWARP_RQ_WQE_FRAG3_HIGH_IDX = 21,
- NES_IWARP_RQ_WQE_LENGTH3_IDX = 22,
- NES_IWARP_RQ_WQE_STAG3_IDX = 23,
-};
-
-enum nes_nic_sq_wqe_bits {
- NES_NIC_SQ_WQE_PHDR_CS_READY = (1<<21),
- NES_NIC_SQ_WQE_LSO_ENABLE = (1<<22),
- NES_NIC_SQ_WQE_TAGVALUE_ENABLE = (1<<23),
- NES_NIC_SQ_WQE_DISABLE_CHKSUM = (1<<30),
- NES_NIC_SQ_WQE_COMPLETION = (1<<31),
-};
-
-enum nes_nic_cqe_word_idx {
- NES_NIC_CQE_ACCQP_ID_IDX = 0,
- NES_NIC_CQE_HASH_RCVNXT = 1,
- NES_NIC_CQE_TAG_PKT_TYPE_IDX = 2,
- NES_NIC_CQE_MISC_IDX = 3,
-};
-
-#define NES_PKT_TYPE_APBVT_BITS 0xC112
-#define NES_PKT_TYPE_APBVT_MASK 0xff3e
-
-#define NES_PKT_TYPE_PVALID_BITS 0x10000000
-#define NES_PKT_TYPE_PVALID_MASK 0x30000000
-
-#define NES_PKT_TYPE_TCPV4_BITS 0x0110
-#define NES_PKT_TYPE_TCPV4_MASK 0x3f30
-
-#define NES_PKT_TYPE_UDPV4_BITS 0x0210
-#define NES_PKT_TYPE_UDPV4_MASK 0x3f30
-
-#define NES_PKT_TYPE_IPV4_BITS 0x0010
-#define NES_PKT_TYPE_IPV4_MASK 0x3f30
-
-#define NES_PKT_TYPE_OTHER_BITS 0x0000
-#define NES_PKT_TYPE_OTHER_MASK 0x0030
-
-#define NES_NIC_CQE_ERRV_SHIFT 16
-enum nes_nic_ev_bits {
- NES_NIC_ERRV_BITS_MODE = (1<<0),
- NES_NIC_ERRV_BITS_IPV4_CSUM_ERR = (1<<1),
- NES_NIC_ERRV_BITS_TCPUDP_CSUM_ERR = (1<<2),
- NES_NIC_ERRV_BITS_WQE_OVERRUN = (1<<3),
- NES_NIC_ERRV_BITS_IPH_ERR = (1<<4),
-};
-
-enum nes_nic_cqe_bits {
- NES_NIC_CQE_ERRV_MASK = (0xff<<NES_NIC_CQE_ERRV_SHIFT),
- NES_NIC_CQE_SQ = (1<<24),
- NES_NIC_CQE_ACCQP_PORT = (1<<28),
- NES_NIC_CQE_ACCQP_VALID = (1<<29),
- NES_NIC_CQE_TAG_VALID = (1<<30),
- NES_NIC_CQE_VALID = (1<<31),
-};
-
-enum nes_aeqe_word_idx {
- NES_AEQE_COMP_CTXT_LOW_IDX = 0,
- NES_AEQE_COMP_CTXT_HIGH_IDX = 1,
- NES_AEQE_COMP_QP_CQ_ID_IDX = 2,
- NES_AEQE_MISC_IDX = 3,
-};
-
-enum nes_aeqe_bits {
- NES_AEQE_QP = (1<<16),
- NES_AEQE_CQ = (1<<17),
- NES_AEQE_SQ = (1<<18),
- NES_AEQE_INBOUND_RDMA = (1<<19),
- NES_AEQE_IWARP_STATE_MASK = (7<<20),
- NES_AEQE_TCP_STATE_MASK = (0xf<<24),
- NES_AEQE_Q2_DATA_WRITTEN = (0x3<<28),
- NES_AEQE_VALID = (1<<31),
-};
-
-#define NES_AEQE_IWARP_STATE_SHIFT 20
-#define NES_AEQE_TCP_STATE_SHIFT 24
-#define NES_AEQE_Q2_DATA_ETHERNET (1<<28)
-#define NES_AEQE_Q2_DATA_MPA (1<<29)
-
-enum nes_aeqe_iwarp_state {
- NES_AEQE_IWARP_STATE_NON_EXISTANT = 0,
- NES_AEQE_IWARP_STATE_IDLE = 1,
- NES_AEQE_IWARP_STATE_RTS = 2,
- NES_AEQE_IWARP_STATE_CLOSING = 3,
- NES_AEQE_IWARP_STATE_TERMINATE = 5,
- NES_AEQE_IWARP_STATE_ERROR = 6
-};
-
-enum nes_aeqe_tcp_state {
- NES_AEQE_TCP_STATE_NON_EXISTANT = 0,
- NES_AEQE_TCP_STATE_CLOSED = 1,
- NES_AEQE_TCP_STATE_LISTEN = 2,
- NES_AEQE_TCP_STATE_SYN_SENT = 3,
- NES_AEQE_TCP_STATE_SYN_RCVD = 4,
- NES_AEQE_TCP_STATE_ESTABLISHED = 5,
- NES_AEQE_TCP_STATE_CLOSE_WAIT = 6,
- NES_AEQE_TCP_STATE_FIN_WAIT_1 = 7,
- NES_AEQE_TCP_STATE_CLOSING = 8,
- NES_AEQE_TCP_STATE_LAST_ACK = 9,
- NES_AEQE_TCP_STATE_FIN_WAIT_2 = 10,
- NES_AEQE_TCP_STATE_TIME_WAIT = 11
-};
-
-enum nes_aeqe_aeid {
- NES_AEQE_AEID_AMP_UNALLOCATED_STAG = 0x0102,
- NES_AEQE_AEID_AMP_INVALID_STAG = 0x0103,
- NES_AEQE_AEID_AMP_BAD_QP = 0x0104,
- NES_AEQE_AEID_AMP_BAD_PD = 0x0105,
- NES_AEQE_AEID_AMP_BAD_STAG_KEY = 0x0106,
- NES_AEQE_AEID_AMP_BAD_STAG_INDEX = 0x0107,
- NES_AEQE_AEID_AMP_BOUNDS_VIOLATION = 0x0108,
- NES_AEQE_AEID_AMP_RIGHTS_VIOLATION = 0x0109,
- NES_AEQE_AEID_AMP_TO_WRAP = 0x010a,
- NES_AEQE_AEID_AMP_FASTREG_SHARED = 0x010b,
- NES_AEQE_AEID_AMP_FASTREG_VALID_STAG = 0x010c,
- NES_AEQE_AEID_AMP_FASTREG_MW_STAG = 0x010d,
- NES_AEQE_AEID_AMP_FASTREG_INVALID_RIGHTS = 0x010e,
- NES_AEQE_AEID_AMP_FASTREG_PBL_TABLE_OVERFLOW = 0x010f,
- NES_AEQE_AEID_AMP_FASTREG_INVALID_LENGTH = 0x0110,
- NES_AEQE_AEID_AMP_INVALIDATE_SHARED = 0x0111,
- NES_AEQE_AEID_AMP_INVALIDATE_NO_REMOTE_ACCESS_RIGHTS = 0x0112,
- NES_AEQE_AEID_AMP_INVALIDATE_MR_WITH_BOUND_WINDOWS = 0x0113,
- NES_AEQE_AEID_AMP_MWBIND_VALID_STAG = 0x0114,
- NES_AEQE_AEID_AMP_MWBIND_OF_MR_STAG = 0x0115,
- NES_AEQE_AEID_AMP_MWBIND_TO_ZERO_BASED_STAG = 0x0116,
- NES_AEQE_AEID_AMP_MWBIND_TO_MW_STAG = 0x0117,
- NES_AEQE_AEID_AMP_MWBIND_INVALID_RIGHTS = 0x0118,
- NES_AEQE_AEID_AMP_MWBIND_INVALID_BOUNDS = 0x0119,
- NES_AEQE_AEID_AMP_MWBIND_TO_INVALID_PARENT = 0x011a,
- NES_AEQE_AEID_AMP_MWBIND_BIND_DISABLED = 0x011b,
- NES_AEQE_AEID_BAD_CLOSE = 0x0201,
- NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE = 0x0202,
- NES_AEQE_AEID_CQ_OPERATION_ERROR = 0x0203,
- NES_AEQE_AEID_PRIV_OPERATION_DENIED = 0x0204,
- NES_AEQE_AEID_RDMA_READ_WHILE_ORD_ZERO = 0x0205,
- NES_AEQE_AEID_STAG_ZERO_INVALID = 0x0206,
- NES_AEQE_AEID_DDP_INVALID_MSN_GAP_IN_MSN = 0x0301,
- NES_AEQE_AEID_DDP_INVALID_MSN_RANGE_IS_NOT_VALID = 0x0302,
- NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER = 0x0303,
- NES_AEQE_AEID_DDP_UBE_INVALID_DDP_VERSION = 0x0304,
- NES_AEQE_AEID_DDP_UBE_INVALID_MO = 0x0305,
- NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE = 0x0306,
- NES_AEQE_AEID_DDP_UBE_INVALID_QN = 0x0307,
- NES_AEQE_AEID_DDP_NO_L_BIT = 0x0308,
- NES_AEQE_AEID_RDMAP_ROE_INVALID_RDMAP_VERSION = 0x0311,
- NES_AEQE_AEID_RDMAP_ROE_UNEXPECTED_OPCODE = 0x0312,
- NES_AEQE_AEID_ROE_INVALID_RDMA_READ_REQUEST = 0x0313,
- NES_AEQE_AEID_ROE_INVALID_RDMA_WRITE_OR_READ_RESP = 0x0314,
- NES_AEQE_AEID_INVALID_ARP_ENTRY = 0x0401,
- NES_AEQE_AEID_INVALID_TCP_OPTION_RCVD = 0x0402,
- NES_AEQE_AEID_STALE_ARP_ENTRY = 0x0403,
- NES_AEQE_AEID_LLP_CLOSE_COMPLETE = 0x0501,
- NES_AEQE_AEID_LLP_CONNECTION_RESET = 0x0502,
- NES_AEQE_AEID_LLP_FIN_RECEIVED = 0x0503,
- NES_AEQE_AEID_LLP_RECEIVED_MARKER_AND_LENGTH_FIELDS_DONT_MATCH = 0x0504,
- NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR = 0x0505,
- NES_AEQE_AEID_LLP_SEGMENT_TOO_LARGE = 0x0506,
- NES_AEQE_AEID_LLP_SEGMENT_TOO_SMALL = 0x0507,
- NES_AEQE_AEID_LLP_SYN_RECEIVED = 0x0508,
- NES_AEQE_AEID_LLP_TERMINATE_RECEIVED = 0x0509,
- NES_AEQE_AEID_LLP_TOO_MANY_RETRIES = 0x050a,
- NES_AEQE_AEID_LLP_TOO_MANY_KEEPALIVE_RETRIES = 0x050b,
- NES_AEQE_AEID_RESET_SENT = 0x0601,
- NES_AEQE_AEID_TERMINATE_SENT = 0x0602,
- NES_AEQE_AEID_DDP_LCE_LOCAL_CATASTROPHIC = 0x0700
-};
-
-enum nes_iwarp_sq_opcodes {
- NES_IWARP_SQ_WQE_WRPDU = (1<<15),
- NES_IWARP_SQ_WQE_PSH = (1<<21),
- NES_IWARP_SQ_WQE_STREAMING = (1<<23),
- NES_IWARP_SQ_WQE_IMM_DATA = (1<<28),
- NES_IWARP_SQ_WQE_READ_FENCE = (1<<29),
- NES_IWARP_SQ_WQE_LOCAL_FENCE = (1<<30),
- NES_IWARP_SQ_WQE_SIGNALED_COMPL = (1<<31),
-};
-
-enum nes_iwarp_sq_wqe_bits {
- NES_IWARP_SQ_OP_RDMAW = 0,
- NES_IWARP_SQ_OP_RDMAR = 1,
- NES_IWARP_SQ_OP_SEND = 3,
- NES_IWARP_SQ_OP_SENDINV = 4,
- NES_IWARP_SQ_OP_SENDSE = 5,
- NES_IWARP_SQ_OP_SENDSEINV = 6,
- NES_IWARP_SQ_OP_BIND = 8,
- NES_IWARP_SQ_OP_FAST_REG = 9,
- NES_IWARP_SQ_OP_LOCINV = 10,
- NES_IWARP_SQ_OP_RDMAR_LOCINV = 11,
- NES_IWARP_SQ_OP_NOP = 12,
-};
-
-enum nes_iwarp_cqe_major_code {
- NES_IWARP_CQE_MAJOR_FLUSH = 1,
- NES_IWARP_CQE_MAJOR_DRV = 0x8000
-};
-
-enum nes_iwarp_cqe_minor_code {
- NES_IWARP_CQE_MINOR_FLUSH = 1
-};
-
-#define NES_EEPROM_READ_REQUEST (1<<16)
-#define NES_MAC_ADDR_VALID (1<<20)
-
-/*
- * NES index registers init values.
- */
-struct nes_init_values {
- u32 index;
- u32 data;
- u8 wrt;
-};
-
-/*
- * NES registers in BAR0.
- */
-struct nes_pci_regs {
- u32 int_status;
- u32 int_mask;
- u32 int_pending;
- u32 intf_int_status;
- u32 intf_int_mask;
- u32 other_regs[59]; /* pad out to 256 bytes for now */
-};
-
-#define NES_CQP_SQ_SIZE 128
-#define NES_CCQ_SIZE 128
-#define NES_NIC_WQ_SIZE 512
-#define NES_NIC_CTX_SIZE ((NES_NIC_CTX_RQ_SIZE_512) | (NES_NIC_CTX_SQ_SIZE_512))
-#define NES_NIC_BACK_STORE 0x00038000
-
-struct nes_device;
-
-struct nes_hw_nic_qp_context {
- __le32 context_words[6];
-};
-
-struct nes_hw_nic_sq_wqe {
- __le32 wqe_words[16];
-};
-
-struct nes_hw_nic_rq_wqe {
- __le32 wqe_words[16];
-};
-
-struct nes_hw_nic_cqe {
- __le32 cqe_words[4];
-};
-
-struct nes_hw_cqp_qp_context {
- __le32 context_words[4];
-};
-
-struct nes_hw_cqp_wqe {
- __le32 wqe_words[16];
-};
-
-struct nes_hw_qp_wqe {
- __le32 wqe_words[32];
-};
-
-struct nes_hw_cqe {
- __le32 cqe_words[8];
-};
-
-struct nes_hw_ceqe {
- __le32 ceqe_words[2];
-};
-
-struct nes_hw_aeqe {
- __le32 aeqe_words[4];
-};
-
-struct nes_cqp_request {
- union {
- u64 cqp_callback_context;
- void *cqp_callback_pointer;
- };
- wait_queue_head_t waitq;
- struct nes_hw_cqp_wqe cqp_wqe;
- struct list_head list;
- atomic_t refcount;
- void (*cqp_callback)(struct nes_device *nesdev, struct nes_cqp_request *cqp_request);
- u16 major_code;
- u16 minor_code;
- u8 waiting;
- u8 request_done;
- u8 dynamic;
- u8 callback;
-};
-
-struct nes_hw_cqp {
- struct nes_hw_cqp_wqe *sq_vbase;
- dma_addr_t sq_pbase;
- spinlock_t lock;
- wait_queue_head_t waitq;
- u16 qp_id;
- u16 sq_head;
- u16 sq_tail;
- u16 sq_size;
-};
-
-#define NES_FIRST_FRAG_SIZE 128
-struct nes_first_frag {
- u8 buffer[NES_FIRST_FRAG_SIZE];
-};
-
-struct nes_hw_nic {
- struct nes_first_frag *first_frag_vbase; /* virtual address of first frags */
- struct nes_hw_nic_sq_wqe *sq_vbase; /* virtual address of sq */
- struct nes_hw_nic_rq_wqe *rq_vbase; /* virtual address of rq */
- struct sk_buff *tx_skb[NES_NIC_WQ_SIZE];
- struct sk_buff *rx_skb[NES_NIC_WQ_SIZE];
- dma_addr_t frag_paddr[NES_NIC_WQ_SIZE];
- unsigned long first_frag_overflow[BITS_TO_LONGS(NES_NIC_WQ_SIZE)];
- dma_addr_t sq_pbase; /* PCI memory for host rings */
- dma_addr_t rq_pbase; /* PCI memory for host rings */
-
- u16 qp_id;
- u16 sq_head;
- u16 sq_tail;
- u16 sq_size;
- u16 rq_head;
- u16 rq_tail;
- u16 rq_size;
- u8 replenishing_rq;
- u8 reserved;
-
- spinlock_t rq_lock;
-};
-
-struct nes_hw_nic_cq {
- struct nes_hw_nic_cqe volatile *cq_vbase; /* PCI memory for host rings */
- void (*ce_handler)(struct nes_device *nesdev, struct nes_hw_nic_cq *cq);
- dma_addr_t cq_pbase; /* PCI memory for host rings */
- int rx_cqes_completed;
- int cqe_allocs_pending;
- int rx_pkts_indicated;
- u16 cq_head;
- u16 cq_size;
- u16 cq_number;
- u8 cqes_pending;
-};
-
-struct nes_hw_qp {
- struct nes_hw_qp_wqe *sq_vbase; /* PCI memory for host rings */
- struct nes_hw_qp_wqe *rq_vbase; /* PCI memory for host rings */
- void *q2_vbase; /* PCI memory for host rings */
- dma_addr_t sq_pbase; /* PCI memory for host rings */
- dma_addr_t rq_pbase; /* PCI memory for host rings */
- dma_addr_t q2_pbase; /* PCI memory for host rings */
- u32 qp_id;
- u16 sq_head;
- u16 sq_tail;
- u16 sq_size;
- u16 rq_head;
- u16 rq_tail;
- u16 rq_size;
- u8 rq_encoded_size;
- u8 sq_encoded_size;
-};
-
-struct nes_hw_cq {
- struct nes_hw_cqe *cq_vbase; /* PCI memory for host rings */
- void (*ce_handler)(struct nes_device *nesdev, struct nes_hw_cq *cq);
- dma_addr_t cq_pbase; /* PCI memory for host rings */
- u16 cq_head;
- u16 cq_size;
- u16 cq_number;
-};
-
-struct nes_hw_ceq {
- struct nes_hw_ceqe volatile *ceq_vbase; /* PCI memory for host rings */
- dma_addr_t ceq_pbase; /* PCI memory for host rings */
- u16 ceq_head;
- u16 ceq_size;
-};
-
-struct nes_hw_aeq {
- struct nes_hw_aeqe volatile *aeq_vbase; /* PCI memory for host rings */
- dma_addr_t aeq_pbase; /* PCI memory for host rings */
- u16 aeq_head;
- u16 aeq_size;
-};
-
-struct nic_qp_map {
- u8 qpid;
- u8 nic_index;
- u8 logical_port;
- u8 is_hnic;
-};
-
-#define NES_CQP_ARP_AEQ_INDEX_MASK 0x000f0000
-#define NES_CQP_ARP_AEQ_INDEX_SHIFT 16
-
-#define NES_CQP_APBVT_ADD 0x00008000
-#define NES_CQP_APBVT_NIC_SHIFT 16
-
-#define NES_ARP_ADD 1
-#define NES_ARP_DELETE 2
-#define NES_ARP_RESOLVE 3
-
-#define NES_MAC_SW_IDLE 0
-#define NES_MAC_SW_INTERRUPT 1
-#define NES_MAC_SW_MH 2
-
-struct nes_arp_entry {
- u32 ip_addr;
- u8 mac_addr[ETH_ALEN];
-};
-
-#define NES_NIC_FAST_TIMER 96
-#define NES_NIC_FAST_TIMER_LOW 40
-#define NES_NIC_FAST_TIMER_HIGH 1000
-#define DEFAULT_NES_QL_HIGH 256
-#define DEFAULT_NES_QL_LOW 16
-#define DEFAULT_NES_QL_TARGET 64
-#define DEFAULT_JUMBO_NES_QL_LOW 12
-#define DEFAULT_JUMBO_NES_QL_TARGET 40
-#define DEFAULT_JUMBO_NES_QL_HIGH 128
-#define NES_NIC_CQ_DOWNWARD_TREND 16
-#define NES_PFT_SIZE 48
-
-#define NES_MGT_WQ_COUNT 32
-#define NES_MGT_CTX_SIZE ((NES_NIC_CTX_RQ_SIZE_32) | (NES_NIC_CTX_SQ_SIZE_32))
-#define NES_MGT_QP_OFFSET 36
-#define NES_MGT_QP_COUNT 4
-
-struct nes_hw_tune_timer {
- /* u16 cq_count; */
- u16 threshold_low;
- u16 threshold_target;
- u16 threshold_high;
- u16 timer_in_use;
- u16 timer_in_use_old;
- u16 timer_in_use_min;
- u16 timer_in_use_max;
- u8 timer_direction_upward;
- u8 timer_direction_downward;
- u16 cq_count_old;
- u8 cq_direction_downward;
-};
-
-#define NES_TIMER_INT_LIMIT 2
-#define NES_TIMER_INT_LIMIT_DYNAMIC 10
-#define NES_TIMER_ENABLE_LIMIT 4
-#define NES_MAX_LINK_INTERRUPTS 128
-#define NES_MAX_LINK_CHECK 200
-
-struct nes_adapter {
- u64 fw_ver;
- unsigned long *allocated_qps;
- unsigned long *allocated_cqs;
- unsigned long *allocated_mrs;
- unsigned long *allocated_pds;
- unsigned long *allocated_arps;
- struct nes_qp **qp_table;
- struct workqueue_struct *work_q;
-
- struct list_head list;
- struct list_head active_listeners;
- /* list of the netdev's associated with each logical port */
- struct list_head nesvnic_list[4];
-
- struct timer_list mh_timer;
- struct timer_list lc_timer;
- struct work_struct work;
- spinlock_t resource_lock;
- spinlock_t phy_lock;
- spinlock_t pbl_lock;
- spinlock_t periodic_timer_lock;
-
- struct nes_arp_entry arp_table[NES_MAX_ARP_TABLE_SIZE];
-
- /* Adapter CEQ and AEQs */
- struct nes_hw_ceq ceq[16];
- struct nes_hw_aeq aeq[8];
-
- struct nes_hw_tune_timer tune_timer;
-
- unsigned long doorbell_start;
-
- u32 hw_rev;
- u32 vendor_id;
- u32 vendor_part_id;
- u32 device_cap_flags;
- u32 tick_delta;
- u32 timer_int_req;
- u32 arp_table_size;
- u32 next_arp_index;
-
- u32 max_mr;
- u32 max_256pbl;
- u32 max_4kpbl;
- u32 free_256pbl;
- u32 free_4kpbl;
- u32 max_mr_size;
- u32 max_qp;
- u32 next_qp;
- u32 max_irrq;
- u32 max_qp_wr;
- u32 max_sge;
- u32 max_cq;
- u32 next_cq;
- u32 max_cqe;
- u32 max_pd;
- u32 base_pd;
- u32 next_pd;
- u32 hte_index_mask;
-
- /* EEPROM information */
- u32 rx_pool_size;
- u32 tx_pool_size;
- u32 rx_threshold;
- u32 tcp_timer_core_clk_divisor;
- u32 iwarp_config;
- u32 cm_config;
- u32 sws_timer_config;
- u32 tcp_config1;
- u32 wqm_wat;
- u32 core_clock;
- u32 firmware_version;
- u32 eeprom_version;
-
- u32 nic_rx_eth_route_err;
-
- u32 et_rx_coalesce_usecs;
- u32 et_rx_max_coalesced_frames;
- u32 et_rx_coalesce_usecs_irq;
- u32 et_rx_max_coalesced_frames_irq;
- u32 et_pkt_rate_low;
- u32 et_rx_coalesce_usecs_low;
- u32 et_rx_max_coalesced_frames_low;
- u32 et_pkt_rate_high;
- u32 et_rx_coalesce_usecs_high;
- u32 et_rx_max_coalesced_frames_high;
- u32 et_rate_sample_interval;
- u32 timer_int_limit;
- u32 wqm_quanta;
- u8 allow_unaligned_fpdus;
-
- /* Adapter base MAC address */
- u32 mac_addr_low;
- u16 mac_addr_high;
-
- u16 firmware_eeprom_offset;
- u16 software_eeprom_offset;
-
- u16 max_irrq_wr;
-
- /* pd config for each port */
- u16 pd_config_size[4];
- u16 pd_config_base[4];
-
- u16 link_interrupt_count[4];
- u8 crit_error_count[32];
-
- /* the phy index for each port */
- u8 phy_index[4];
- u8 mac_sw_state[4];
- u8 mac_link_down[4];
- u8 phy_type[4];
- u8 log_port;
-
- /* PCI information */
- struct nes_device *nesdev;
- unsigned int devfn;
- unsigned char bus_number;
- unsigned char OneG_Mode;
-
- unsigned char ref_count;
- u8 netdev_count;
- u8 netdev_max; /* from host nic address count in EEPROM */
- u8 port_count;
- u8 virtwq;
- u8 send_term_ok;
- u8 et_use_adaptive_rx_coalesce;
- u8 adapter_fcn_count;
- u8 pft_mcast_map[NES_PFT_SIZE];
-};
-
-struct nes_pbl {
- u64 *pbl_vbase;
- dma_addr_t pbl_pbase;
- struct page *page;
- unsigned long user_base;
- u32 pbl_size;
- struct list_head list;
- /* TODO: need to add list for two level tables */
-};
-
-#define NES_4K_PBL_CHUNK_SIZE 4096
-
-struct nes_fast_mr_wqe_pbl {
- u64 *kva;
- dma_addr_t paddr;
-};
-
-struct nes_listener {
- struct work_struct work;
- struct workqueue_struct *wq;
- struct nes_vnic *nesvnic;
- struct iw_cm_id *cm_id;
- struct list_head list;
- unsigned long socket;
- u8 accept_failed;
-};
-
-struct nes_ib_device;
-
-#define NES_EVENT_DELAY msecs_to_jiffies(100)
-
-struct nes_vnic {
- struct nes_ib_device *nesibdev;
- u64 sq_full;
- u64 tso_requests;
- u64 segmented_tso_requests;
- u64 linearized_skbs;
- u64 tx_sw_dropped;
- u64 endnode_nstat_rx_discard;
- u64 endnode_nstat_rx_octets;
- u64 endnode_nstat_rx_frames;
- u64 endnode_nstat_tx_octets;
- u64 endnode_nstat_tx_frames;
- u64 endnode_ipv4_tcp_retransmits;
- /* void *mem; */
- struct nes_device *nesdev;
- struct net_device *netdev;
- atomic_t rx_skbs_needed;
- atomic_t rx_skb_timer_running;
- int budget;
- u32 msg_enable;
- /* u32 tx_avail; */
- __be32 local_ipaddr;
- struct napi_struct napi;
- spinlock_t tx_lock; /* could use netdev tx lock? */
- struct timer_list rq_wqes_timer;
- u32 nic_mem_size;
- void *nic_vbase;
- dma_addr_t nic_pbase;
- struct nes_hw_nic nic;
- struct nes_hw_nic_cq nic_cq;
- u32 mcrq_qp_id;
- struct nes_ucontext *mcrq_ucontext;
- struct nes_cqp_request* (*get_cqp_request)(struct nes_device *nesdev);
- void (*post_cqp_request)(struct nes_device*, struct nes_cqp_request *);
- int (*mcrq_mcast_filter)( struct nes_vnic* nesvnic, __u8* dmi_addr );
- struct net_device_stats netstats;
- /* used to put the netdev on the adapters logical port list */
- struct list_head list;
- u16 max_frame_size;
- u8 netdev_open;
- u8 linkup;
- u8 logical_port;
- u8 netdev_index; /* might not be needed, indexes nesdev->netdev */
- u8 perfect_filter_index;
- u8 nic_index;
- u8 qp_nic_index[4];
- u8 next_qp_nic_index;
- u8 of_device_registered;
- u8 rdma_enabled;
- struct timer_list event_timer;
- enum ib_event_type delayed_event;
- enum ib_event_type last_dispatched_event;
- spinlock_t port_ibevent_lock;
- u32 mgt_mem_size;
- void *mgt_vbase;
- dma_addr_t mgt_pbase;
- struct nes_vnic_mgt *mgtvnic[NES_MGT_QP_COUNT];
- struct task_struct *mgt_thread;
- wait_queue_head_t mgt_wait_queue;
- struct sk_buff_head mgt_skb_list;
-
-};
-
-struct nes_ib_device {
- struct ib_device ibdev;
- struct nes_vnic *nesvnic;
-
- /* Virtual RNIC Limits */
- u32 max_mr;
- u32 max_qp;
- u32 max_cq;
- u32 max_pd;
- u32 num_mr;
- u32 num_qp;
- u32 num_cq;
- u32 num_pd;
-};
-
-enum nes_hdrct_flags {
- DDP_LEN_FLAG = 0x80,
- DDP_HDR_FLAG = 0x40,
- RDMA_HDR_FLAG = 0x20
-};
-
-enum nes_term_layers {
- LAYER_RDMA = 0,
- LAYER_DDP = 1,
- LAYER_MPA = 2
-};
-
-enum nes_term_error_types {
- RDMAP_CATASTROPHIC = 0,
- RDMAP_REMOTE_PROT = 1,
- RDMAP_REMOTE_OP = 2,
- DDP_CATASTROPHIC = 0,
- DDP_TAGGED_BUFFER = 1,
- DDP_UNTAGGED_BUFFER = 2,
- DDP_LLP = 3
-};
-
-enum nes_term_rdma_errors {
- RDMAP_INV_STAG = 0x00,
- RDMAP_INV_BOUNDS = 0x01,
- RDMAP_ACCESS = 0x02,
- RDMAP_UNASSOC_STAG = 0x03,
- RDMAP_TO_WRAP = 0x04,
- RDMAP_INV_RDMAP_VER = 0x05,
- RDMAP_UNEXPECTED_OP = 0x06,
- RDMAP_CATASTROPHIC_LOCAL = 0x07,
- RDMAP_CATASTROPHIC_GLOBAL = 0x08,
- RDMAP_CANT_INV_STAG = 0x09,
- RDMAP_UNSPECIFIED = 0xff
-};
-
-enum nes_term_ddp_errors {
- DDP_CATASTROPHIC_LOCAL = 0x00,
- DDP_TAGGED_INV_STAG = 0x00,
- DDP_TAGGED_BOUNDS = 0x01,
- DDP_TAGGED_UNASSOC_STAG = 0x02,
- DDP_TAGGED_TO_WRAP = 0x03,
- DDP_TAGGED_INV_DDP_VER = 0x04,
- DDP_UNTAGGED_INV_QN = 0x01,
- DDP_UNTAGGED_INV_MSN_NO_BUF = 0x02,
- DDP_UNTAGGED_INV_MSN_RANGE = 0x03,
- DDP_UNTAGGED_INV_MO = 0x04,
- DDP_UNTAGGED_INV_TOO_LONG = 0x05,
- DDP_UNTAGGED_INV_DDP_VER = 0x06
-};
-
-enum nes_term_mpa_errors {
- MPA_CLOSED = 0x01,
- MPA_CRC = 0x02,
- MPA_MARKER = 0x03,
- MPA_REQ_RSP = 0x04,
-};
-
-struct nes_terminate_hdr {
- u8 layer_etype;
- u8 error_code;
- u8 hdrct;
- u8 rsvd;
-};
-
-/* Used to determine how to fill in terminate error codes */
-#define IWARP_OPCODE_WRITE 0
-#define IWARP_OPCODE_READREQ 1
-#define IWARP_OPCODE_READRSP 2
-#define IWARP_OPCODE_SEND 3
-#define IWARP_OPCODE_SEND_INV 4
-#define IWARP_OPCODE_SEND_SE 5
-#define IWARP_OPCODE_SEND_SE_INV 6
-#define IWARP_OPCODE_TERM 7
-
-/* These values are used only during terminate processing */
-#define TERM_DDP_LEN_TAGGED 14
-#define TERM_DDP_LEN_UNTAGGED 18
-#define TERM_RDMA_LEN 28
-#define RDMA_OPCODE_MASK 0x0f
-#define RDMA_READ_REQ_OPCODE 1
-#define BAD_FRAME_OFFSET 64
-#define CQE_MAJOR_DRV 0x8000
-
-/* Used for link status recheck after interrupt processing */
-#define NES_LINK_RECHECK_DELAY msecs_to_jiffies(50)
-#define NES_LINK_RECHECK_MAX 60
-
-#endif /* __NES_HW_H */
diff --git a/drivers/infiniband/hw/nes/nes_mgt.c b/drivers/infiniband/hw/nes/nes_mgt.c
deleted file mode 100644
index cc4dce5c3e5f..000000000000
--- a/drivers/infiniband/hw/nes/nes_mgt.c
+++ /dev/null
@@ -1,1155 +0,0 @@
-/*
- * Copyright (c) 2006 - 2011 Intel-NE, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-#include <linux/skbuff.h>
-#include <linux/etherdevice.h>
-#include <linux/kthread.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>
-#include <net/tcp.h>
-#include "nes.h"
-#include "nes_mgt.h"
-
-atomic_t pau_qps_created;
-atomic_t pau_qps_destroyed;
-
-static void nes_replenish_mgt_rq(struct nes_vnic_mgt *mgtvnic)
-{
- unsigned long flags;
- dma_addr_t bus_address;
- struct sk_buff *skb;
- struct nes_hw_nic_rq_wqe *nic_rqe;
- struct nes_hw_mgt *nesmgt;
- struct nes_device *nesdev;
- struct nes_rskb_cb *cb;
- u32 rx_wqes_posted = 0;
-
- nesmgt = &mgtvnic->mgt;
- nesdev = mgtvnic->nesvnic->nesdev;
- spin_lock_irqsave(&nesmgt->rq_lock, flags);
- if (nesmgt->replenishing_rq != 0) {
- if (((nesmgt->rq_size - 1) == atomic_read(&mgtvnic->rx_skbs_needed)) &&
- (atomic_read(&mgtvnic->rx_skb_timer_running) == 0)) {
- atomic_set(&mgtvnic->rx_skb_timer_running, 1);
- spin_unlock_irqrestore(&nesmgt->rq_lock, flags);
- mgtvnic->rq_wqes_timer.expires = jiffies + (HZ / 2); /* 1/2 second */
- add_timer(&mgtvnic->rq_wqes_timer);
- } else {
- spin_unlock_irqrestore(&nesmgt->rq_lock, flags);
- }
- return;
- }
- nesmgt->replenishing_rq = 1;
- spin_unlock_irqrestore(&nesmgt->rq_lock, flags);
- do {
- skb = dev_alloc_skb(mgtvnic->nesvnic->max_frame_size);
- if (skb) {
- skb->dev = mgtvnic->nesvnic->netdev;
-
- bus_address = pci_map_single(nesdev->pcidev,
- skb->data, mgtvnic->nesvnic->max_frame_size, PCI_DMA_FROMDEVICE);
- cb = (struct nes_rskb_cb *)&skb->cb[0];
- cb->busaddr = bus_address;
- cb->maplen = mgtvnic->nesvnic->max_frame_size;
-
- nic_rqe = &nesmgt->rq_vbase[mgtvnic->mgt.rq_head];
- nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] =
- cpu_to_le32(mgtvnic->nesvnic->max_frame_size);
- nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_3_2_IDX] = 0;
- nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX] =
- cpu_to_le32((u32)bus_address);
- nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX] =
- cpu_to_le32((u32)((u64)bus_address >> 32));
- nesmgt->rx_skb[nesmgt->rq_head] = skb;
- nesmgt->rq_head++;
- nesmgt->rq_head &= nesmgt->rq_size - 1;
- atomic_dec(&mgtvnic->rx_skbs_needed);
- barrier();
- if (++rx_wqes_posted == 255) {
- nes_write32(nesdev->regs + NES_WQE_ALLOC, (rx_wqes_posted << 24) | nesmgt->qp_id);
- rx_wqes_posted = 0;
- }
- } else {
- spin_lock_irqsave(&nesmgt->rq_lock, flags);
- if (((nesmgt->rq_size - 1) == atomic_read(&mgtvnic->rx_skbs_needed)) &&
- (atomic_read(&mgtvnic->rx_skb_timer_running) == 0)) {
- atomic_set(&mgtvnic->rx_skb_timer_running, 1);
- spin_unlock_irqrestore(&nesmgt->rq_lock, flags);
- mgtvnic->rq_wqes_timer.expires = jiffies + (HZ / 2); /* 1/2 second */
- add_timer(&mgtvnic->rq_wqes_timer);
- } else {
- spin_unlock_irqrestore(&nesmgt->rq_lock, flags);
- }
- break;
- }
- } while (atomic_read(&mgtvnic->rx_skbs_needed));
- barrier();
- if (rx_wqes_posted)
- nes_write32(nesdev->regs + NES_WQE_ALLOC, (rx_wqes_posted << 24) | nesmgt->qp_id);
- nesmgt->replenishing_rq = 0;
-}
-
-/**
- * nes_mgt_rq_wqes_timeout
- */
-static void nes_mgt_rq_wqes_timeout(struct timer_list *t)
-{
- struct nes_vnic_mgt *mgtvnic = from_timer(mgtvnic, t,
- rq_wqes_timer);
-
- atomic_set(&mgtvnic->rx_skb_timer_running, 0);
- if (atomic_read(&mgtvnic->rx_skbs_needed))
- nes_replenish_mgt_rq(mgtvnic);
-}
-
-/**
- * nes_mgt_free_skb - unmap and free skb
- */
-static void nes_mgt_free_skb(struct nes_device *nesdev, struct sk_buff *skb, u32 dir)
-{
- struct nes_rskb_cb *cb;
-
- cb = (struct nes_rskb_cb *)&skb->cb[0];
- pci_unmap_single(nesdev->pcidev, cb->busaddr, cb->maplen, dir);
- cb->busaddr = 0;
- dev_kfree_skb_any(skb);
-}
-
-/**
- * nes_download_callback - handle download completions
- */
-static void nes_download_callback(struct nes_device *nesdev, struct nes_cqp_request *cqp_request)
-{
- struct pau_fpdu_info *fpdu_info = cqp_request->cqp_callback_pointer;
- struct nes_qp *nesqp = fpdu_info->nesqp;
- struct sk_buff *skb;
- int i;
-
- for (i = 0; i < fpdu_info->frag_cnt; i++) {
- skb = fpdu_info->frags[i].skb;
- if (fpdu_info->frags[i].cmplt) {
- nes_mgt_free_skb(nesdev, skb, PCI_DMA_TODEVICE);
- nes_rem_ref_cm_node(nesqp->cm_node);
- }
- }
-
- if (fpdu_info->hdr_vbase)
- pci_free_consistent(nesdev->pcidev, fpdu_info->hdr_len,
- fpdu_info->hdr_vbase, fpdu_info->hdr_pbase);
- kfree(fpdu_info);
-}
-
-/**
- * nes_get_seq - Get the seq, ack_seq and window from the packet
- */
-static u32 nes_get_seq(struct sk_buff *skb, u32 *ack, u16 *wnd, u32 *fin_rcvd, u32 *rst_rcvd)
-{
- struct nes_rskb_cb *cb = (struct nes_rskb_cb *)&skb->cb[0];
- struct iphdr *iph = (struct iphdr *)(cb->data_start + ETH_HLEN);
- struct tcphdr *tcph = (struct tcphdr *)(((char *)iph) + (4 * iph->ihl));
-
- *ack = be32_to_cpu(tcph->ack_seq);
- *wnd = be16_to_cpu(tcph->window);
- *fin_rcvd = tcph->fin;
- *rst_rcvd = tcph->rst;
- return be32_to_cpu(tcph->seq);
-}
-
-/**
- * nes_get_next_skb - Get the next skb based on where current skb is in the queue
- */
-static struct sk_buff *nes_get_next_skb(struct nes_device *nesdev, struct nes_qp *nesqp,
- struct sk_buff *skb, u32 nextseq, u32 *ack,
- u16 *wnd, u32 *fin_rcvd, u32 *rst_rcvd)
-{
- u32 seq;
- bool processacks;
- struct sk_buff *old_skb;
-
- if (skb) {
- /* Continue processing fpdu */
- skb = skb_peek_next(skb, &nesqp->pau_list);
- if (!skb)
- goto out;
- processacks = false;
- } else {
- /* Starting a new one */
- if (skb_queue_empty(&nesqp->pau_list))
- goto out;
- skb = skb_peek(&nesqp->pau_list);
- processacks = true;
- }
-
- while (1) {
- if (skb_queue_empty(&nesqp->pau_list))
- goto out;
-
- seq = nes_get_seq(skb, ack, wnd, fin_rcvd, rst_rcvd);
- if (seq == nextseq) {
- if (skb->len || processacks)
- break;
- } else if (after(seq, nextseq)) {
- goto out;
- }
-
- old_skb = skb;
- skb = skb_peek_next(skb, &nesqp->pau_list);
- skb_unlink(old_skb, &nesqp->pau_list);
- nes_mgt_free_skb(nesdev, old_skb, PCI_DMA_TODEVICE);
- nes_rem_ref_cm_node(nesqp->cm_node);
- if (!skb)
- goto out;
- }
- return skb;
-
-out:
- return NULL;
-}
-
-/**
- * get_fpdu_info - Find the next complete fpdu and return its fragments.
- */
-static int get_fpdu_info(struct nes_device *nesdev, struct nes_qp *nesqp,
- struct pau_fpdu_info **pau_fpdu_info)
-{
- struct sk_buff *skb;
- struct iphdr *iph;
- struct tcphdr *tcph;
- struct nes_rskb_cb *cb;
- struct pau_fpdu_info *fpdu_info = NULL;
- struct pau_fpdu_frag frags[MAX_FPDU_FRAGS];
- u32 fpdu_len = 0;
- u32 tmp_len;
- int frag_cnt = 0;
- u32 tot_len;
- u32 frag_tot;
- u32 ack;
- u32 fin_rcvd;
- u32 rst_rcvd;
- u16 wnd;
- int i;
- int rc = 0;
-
- *pau_fpdu_info = NULL;
-
- skb = nes_get_next_skb(nesdev, nesqp, NULL, nesqp->pau_rcv_nxt, &ack, &wnd, &fin_rcvd, &rst_rcvd);
- if (!skb)
- goto out;
-
- cb = (struct nes_rskb_cb *)&skb->cb[0];
- if (skb->len) {
- fpdu_len = be16_to_cpu(*(__be16 *) skb->data) + MPA_FRAMING;
- fpdu_len = (fpdu_len + 3) & 0xfffffffc;
- tmp_len = fpdu_len;
-
- /* See if we have all of the fpdu */
- frag_tot = 0;
- memset(&frags, 0, sizeof frags);
- for (i = 0; i < MAX_FPDU_FRAGS; i++) {
- frags[i].physaddr = cb->busaddr;
- frags[i].physaddr += skb->data - cb->data_start;
- frags[i].frag_len = min(tmp_len, skb->len);
- frags[i].skb = skb;
- frags[i].cmplt = (skb->len == frags[i].frag_len);
- frag_tot += frags[i].frag_len;
- frag_cnt++;
-
- tmp_len -= frags[i].frag_len;
- if (tmp_len == 0)
- break;
-
- skb = nes_get_next_skb(nesdev, nesqp, skb,
- nesqp->pau_rcv_nxt + frag_tot, &ack, &wnd, &fin_rcvd, &rst_rcvd);
- if (!skb)
- goto out;
- if (rst_rcvd) {
- /* rst received in the middle of fpdu */
- for (; i >= 0; i--) {
- skb_unlink(frags[i].skb, &nesqp->pau_list);
- nes_mgt_free_skb(nesdev, frags[i].skb, PCI_DMA_TODEVICE);
- }
- cb = (struct nes_rskb_cb *)&skb->cb[0];
- frags[0].physaddr = cb->busaddr;
- frags[0].physaddr += skb->data - cb->data_start;
- frags[0].frag_len = skb->len;
- frags[0].skb = skb;
- frags[0].cmplt = true;
- frag_cnt = 1;
- break;
- }
-
- cb = (struct nes_rskb_cb *)&skb->cb[0];
- }
- } else {
- /* no data */
- frags[0].physaddr = cb->busaddr;
- frags[0].frag_len = 0;
- frags[0].skb = skb;
- frags[0].cmplt = true;
- frag_cnt = 1;
- }
-
- /* Found one */
- fpdu_info = kzalloc(sizeof(*fpdu_info), GFP_ATOMIC);
- if (!fpdu_info) {
- rc = -ENOMEM;
- goto out;
- }
-
- fpdu_info->cqp_request = nes_get_cqp_request(nesdev);
- if (fpdu_info->cqp_request == NULL) {
- nes_debug(NES_DBG_PAU, "Failed to get a cqp_request.\n");
- rc = -ENOMEM;
- goto out;
- }
-
- cb = (struct nes_rskb_cb *)&frags[0].skb->cb[0];
- iph = (struct iphdr *)(cb->data_start + ETH_HLEN);
- tcph = (struct tcphdr *)(((char *)iph) + (4 * iph->ihl));
- fpdu_info->hdr_len = (((unsigned char *)tcph) + 4 * (tcph->doff)) - cb->data_start;
- fpdu_info->data_len = fpdu_len;
- tot_len = fpdu_info->hdr_len + fpdu_len - ETH_HLEN;
-
- if (frags[0].cmplt) {
- fpdu_info->hdr_pbase = cb->busaddr;
- fpdu_info->hdr_vbase = NULL;
- } else {
- fpdu_info->hdr_vbase = pci_alloc_consistent(nesdev->pcidev,
- fpdu_info->hdr_len, &fpdu_info->hdr_pbase);
- if (!fpdu_info->hdr_vbase) {
- nes_debug(NES_DBG_PAU, "Unable to allocate memory for pau first frag\n");
- rc = -ENOMEM;
- goto out;
- }
-
- /* Copy hdrs, adjusting len and seqnum */
- memcpy(fpdu_info->hdr_vbase, cb->data_start, fpdu_info->hdr_len);
- iph = (struct iphdr *)(fpdu_info->hdr_vbase + ETH_HLEN);
- tcph = (struct tcphdr *)(((char *)iph) + (4 * iph->ihl));
- }
-
- iph->tot_len = cpu_to_be16(tot_len);
- iph->saddr = cpu_to_be32(0x7f000001);
-
- tcph->seq = cpu_to_be32(nesqp->pau_rcv_nxt);
- tcph->ack_seq = cpu_to_be32(ack);
- tcph->window = cpu_to_be16(wnd);
-
- nesqp->pau_rcv_nxt += fpdu_len + fin_rcvd;
-
- memcpy(fpdu_info->frags, frags, sizeof(fpdu_info->frags));
- fpdu_info->frag_cnt = frag_cnt;
- fpdu_info->nesqp = nesqp;
- *pau_fpdu_info = fpdu_info;
-
- /* Update skb's for next pass */
- for (i = 0; i < frag_cnt; i++) {
- cb = (struct nes_rskb_cb *)&frags[i].skb->cb[0];
- skb_pull(frags[i].skb, frags[i].frag_len);
-
- if (frags[i].skb->len == 0) {
- /* Pull skb off the list - it will be freed in the callback */
- if (!skb_queue_empty(&nesqp->pau_list))
- skb_unlink(frags[i].skb, &nesqp->pau_list);
- } else {
- /* Last skb still has data so update the seq */
- iph = (struct iphdr *)(cb->data_start + ETH_HLEN);
- tcph = (struct tcphdr *)(((char *)iph) + (4 * iph->ihl));
- tcph->seq = cpu_to_be32(nesqp->pau_rcv_nxt);
- }
- }
-
-out:
- if (rc) {
- if (fpdu_info) {
- if (fpdu_info->cqp_request)
- nes_put_cqp_request(nesdev, fpdu_info->cqp_request);
- kfree(fpdu_info);
- }
- }
- return rc;
-}
-
-/**
- * forward_fpdu - send complete fpdus, one at a time
- */
-static int forward_fpdus(struct nes_vnic *nesvnic, struct nes_qp *nesqp)
-{
- struct nes_device *nesdev = nesvnic->nesdev;
- struct pau_fpdu_info *fpdu_info;
- struct nes_hw_cqp_wqe *cqp_wqe;
- struct nes_cqp_request *cqp_request;
- unsigned long flags;
- u64 u64tmp;
- u32 u32tmp;
- int rc;
-
- while (1) {
- spin_lock_irqsave(&nesqp->pau_lock, flags);
- rc = get_fpdu_info(nesdev, nesqp, &fpdu_info);
- if (rc || (fpdu_info == NULL)) {
- spin_unlock_irqrestore(&nesqp->pau_lock, flags);
- return rc;
- }
-
- cqp_request = fpdu_info->cqp_request;
- cqp_wqe = &cqp_request->cqp_wqe;
- nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_DL_OPCODE_IDX,
- NES_CQP_DOWNLOAD_SEGMENT |
- (((u32)nesvnic->logical_port) << NES_CQP_OP_LOGICAL_PORT_SHIFT));
-
- u32tmp = fpdu_info->hdr_len << 16;
- u32tmp |= fpdu_info->hdr_len + (u32)fpdu_info->data_len;
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_DL_LENGTH_0_TOTAL_IDX,
- u32tmp);
-
- u32tmp = (fpdu_info->frags[1].frag_len << 16) | fpdu_info->frags[0].frag_len;
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_LENGTH_2_1_IDX,
- u32tmp);
-
- u32tmp = (fpdu_info->frags[3].frag_len << 16) | fpdu_info->frags[2].frag_len;
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_LENGTH_4_3_IDX,
- u32tmp);
-
- u64tmp = (u64)fpdu_info->hdr_pbase;
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_FRAG0_LOW_IDX,
- lower_32_bits(u64tmp));
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_FRAG0_HIGH_IDX,
- upper_32_bits(u64tmp));
-
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_FRAG1_LOW_IDX,
- lower_32_bits(fpdu_info->frags[0].physaddr));
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_FRAG1_HIGH_IDX,
- upper_32_bits(fpdu_info->frags[0].physaddr));
-
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_FRAG2_LOW_IDX,
- lower_32_bits(fpdu_info->frags[1].physaddr));
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_FRAG2_HIGH_IDX,
- upper_32_bits(fpdu_info->frags[1].physaddr));
-
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_FRAG3_LOW_IDX,
- lower_32_bits(fpdu_info->frags[2].physaddr));
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_FRAG3_HIGH_IDX,
- upper_32_bits(fpdu_info->frags[2].physaddr));
-
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_FRAG4_LOW_IDX,
- lower_32_bits(fpdu_info->frags[3].physaddr));
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_FRAG4_HIGH_IDX,
- upper_32_bits(fpdu_info->frags[3].physaddr));
-
- cqp_request->cqp_callback_pointer = fpdu_info;
- cqp_request->callback = 1;
- cqp_request->cqp_callback = nes_download_callback;
-
- atomic_set(&cqp_request->refcount, 1);
- nes_post_cqp_request(nesdev, cqp_request);
- spin_unlock_irqrestore(&nesqp->pau_lock, flags);
- }
-
- return 0;
-}
-
-static void process_fpdus(struct nes_vnic *nesvnic, struct nes_qp *nesqp)
-{
- int again = 1;
- unsigned long flags;
-
- do {
- /* Ignore rc - if it failed, tcp retries will cause it to try again */
- forward_fpdus(nesvnic, nesqp);
-
- spin_lock_irqsave(&nesqp->pau_lock, flags);
- if (nesqp->pau_pending) {
- nesqp->pau_pending = 0;
- } else {
- nesqp->pau_busy = 0;
- again = 0;
- }
-
- spin_unlock_irqrestore(&nesqp->pau_lock, flags);
- } while (again);
-}
-
-/**
- * queue_fpdus - Handle fpdu's that hw passed up to sw
- */
-static void queue_fpdus(struct sk_buff *skb, struct nes_vnic *nesvnic, struct nes_qp *nesqp)
-{
- struct sk_buff *tmpskb;
- struct nes_rskb_cb *cb;
- struct iphdr *iph;
- struct tcphdr *tcph;
- unsigned char *tcph_end;
- u32 rcv_nxt;
- u32 rcv_wnd;
- u32 seqnum;
- u32 len;
- bool process_it = false;
- unsigned long flags;
-
- /* Move data ptr to after tcp header */
- iph = (struct iphdr *)skb->data;
- tcph = (struct tcphdr *)(((char *)iph) + (4 * iph->ihl));
- seqnum = be32_to_cpu(tcph->seq);
- tcph_end = (((char *)tcph) + (4 * tcph->doff));
-
- len = be16_to_cpu(iph->tot_len);
- if (skb->len > len)
- skb_trim(skb, len);
- skb_pull(skb, tcph_end - skb->data);
-
- /* Initialize tracking values */
- cb = (struct nes_rskb_cb *)&skb->cb[0];
- cb->seqnum = seqnum;
-
- /* Make sure data is in the receive window */
- rcv_nxt = nesqp->pau_rcv_nxt;
- rcv_wnd = le32_to_cpu(nesqp->nesqp_context->rcv_wnd);
- if (!between(seqnum, rcv_nxt, (rcv_nxt + rcv_wnd))) {
- nes_mgt_free_skb(nesvnic->nesdev, skb, PCI_DMA_TODEVICE);
- nes_rem_ref_cm_node(nesqp->cm_node);
- return;
- }
-
- spin_lock_irqsave(&nesqp->pau_lock, flags);
-
- if (nesqp->pau_busy)
- nesqp->pau_pending = 1;
- else
- nesqp->pau_busy = 1;
-
- /* Queue skb by sequence number */
- if (skb_queue_len(&nesqp->pau_list) == 0) {
- __skb_queue_head(&nesqp->pau_list, skb);
- } else {
- skb_queue_walk(&nesqp->pau_list, tmpskb) {
- cb = (struct nes_rskb_cb *)&tmpskb->cb[0];
- if (before(seqnum, cb->seqnum))
- break;
- }
- __skb_insert(skb, tmpskb->prev, tmpskb, &nesqp->pau_list);
- }
- if (nesqp->pau_state == PAU_READY)
- process_it = true;
- spin_unlock_irqrestore(&nesqp->pau_lock, flags);
-
- if (process_it)
- process_fpdus(nesvnic, nesqp);
-
- return;
-}
-
-/**
- * mgt_thread - Handle mgt skbs in a safe context
- */
-static int mgt_thread(void *context)
-{
- struct nes_vnic *nesvnic = context;
- struct sk_buff *skb;
- struct nes_rskb_cb *cb;
-
- while (!kthread_should_stop()) {
- wait_event_interruptible(nesvnic->mgt_wait_queue,
- skb_queue_len(&nesvnic->mgt_skb_list) || kthread_should_stop());
- while ((skb_queue_len(&nesvnic->mgt_skb_list)) && !kthread_should_stop()) {
- skb = skb_dequeue(&nesvnic->mgt_skb_list);
- cb = (struct nes_rskb_cb *)&skb->cb[0];
- cb->data_start = skb->data - ETH_HLEN;
- cb->busaddr = pci_map_single(nesvnic->nesdev->pcidev, cb->data_start,
- nesvnic->max_frame_size, PCI_DMA_TODEVICE);
- queue_fpdus(skb, nesvnic, cb->nesqp);
- }
- }
-
- /* Closing down so delete any entries on the queue */
- while (skb_queue_len(&nesvnic->mgt_skb_list)) {
- skb = skb_dequeue(&nesvnic->mgt_skb_list);
- cb = (struct nes_rskb_cb *)&skb->cb[0];
- nes_rem_ref_cm_node(cb->nesqp->cm_node);
- dev_kfree_skb_any(skb);
- }
- return 0;
-}
-
-/**
- * nes_queue_skbs - Queue skb so it can be handled in a thread context
- */
-void nes_queue_mgt_skbs(struct sk_buff *skb, struct nes_vnic *nesvnic, struct nes_qp *nesqp)
-{
- struct nes_rskb_cb *cb;
-
- cb = (struct nes_rskb_cb *)&skb->cb[0];
- cb->nesqp = nesqp;
- skb_queue_tail(&nesvnic->mgt_skb_list, skb);
- wake_up_interruptible(&nesvnic->mgt_wait_queue);
-}
-
-void nes_destroy_pau_qp(struct nes_device *nesdev, struct nes_qp *nesqp)
-{
- struct sk_buff *skb;
- unsigned long flags;
- atomic_inc(&pau_qps_destroyed);
-
- /* Free packets that have not yet been forwarded */
- /* Lock is acquired by skb_dequeue when removing the skb */
- spin_lock_irqsave(&nesqp->pau_lock, flags);
- while (skb_queue_len(&nesqp->pau_list)) {
- skb = skb_dequeue(&nesqp->pau_list);
- nes_mgt_free_skb(nesdev, skb, PCI_DMA_TODEVICE);
- nes_rem_ref_cm_node(nesqp->cm_node);
- }
- spin_unlock_irqrestore(&nesqp->pau_lock, flags);
-}
-
-static void nes_chg_qh_handler(struct nes_device *nesdev, struct nes_cqp_request *cqp_request)
-{
- struct pau_qh_chg *qh_chg = cqp_request->cqp_callback_pointer;
- struct nes_cqp_request *new_request;
- struct nes_hw_cqp_wqe *cqp_wqe;
- struct nes_adapter *nesadapter;
- struct nes_qp *nesqp;
- struct nes_v4_quad nes_quad;
- u32 crc_value;
- u64 u64temp;
-
- nesadapter = nesdev->nesadapter;
- nesqp = qh_chg->nesqp;
-
- /* Should we handle the bad completion */
- if (cqp_request->major_code)
- WARN(1, PFX "Invalid cqp_request major_code=0x%x\n",
- cqp_request->major_code);
-
- switch (nesqp->pau_state) {
- case PAU_DEL_QH:
- /* Old hash code deleted, now set the new one */
- nesqp->pau_state = PAU_ADD_LB_QH;
- new_request = nes_get_cqp_request(nesdev);
- if (new_request == NULL) {
- nes_debug(NES_DBG_PAU, "Failed to get a new_request.\n");
- WARN_ON(1);
- return;
- }
-
- memset(&nes_quad, 0, sizeof(nes_quad));
- nes_quad.DstIpAdrIndex =
- cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24);
- nes_quad.SrcIpadr = cpu_to_be32(0x7f000001);
- nes_quad.TcpPorts[0] = swab16(nesqp->nesqp_context->tcpPorts[1]);
- nes_quad.TcpPorts[1] = swab16(nesqp->nesqp_context->tcpPorts[0]);
-
- /* Produce hash key */
- crc_value = get_crc_value(&nes_quad);
- nesqp->hte_index = cpu_to_be32(crc_value ^ 0xffffffff);
- nes_debug(NES_DBG_PAU, "new HTE Index = 0x%08X, CRC = 0x%08X\n",
- nesqp->hte_index, nesqp->hte_index & nesadapter->hte_index_mask);
-
- nesqp->hte_index &= nesadapter->hte_index_mask;
- nesqp->nesqp_context->hte_index = cpu_to_le32(nesqp->hte_index);
- nesqp->nesqp_context->ip0 = cpu_to_le32(0x7f000001);
- nesqp->nesqp_context->rcv_nxt = cpu_to_le32(nesqp->pau_rcv_nxt);
-
- cqp_wqe = &new_request->cqp_wqe;
- nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
- set_wqe_32bit_value(cqp_wqe->wqe_words,
- NES_CQP_WQE_OPCODE_IDX, NES_CQP_MANAGE_QUAD_HASH |
- NES_CQP_QP_TYPE_IWARP | NES_CQP_QP_CONTEXT_VALID | NES_CQP_QP_IWARP_STATE_RTS);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX, nesqp->hwqp.qp_id);
- u64temp = (u64)nesqp->nesqp_context_pbase;
- set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_CONTEXT_LOW_IDX, u64temp);
-
- nes_debug(NES_DBG_PAU, "Waiting for CQP completion for adding the quad hash.\n");
-
- new_request->cqp_callback_pointer = qh_chg;
- new_request->callback = 1;
- new_request->cqp_callback = nes_chg_qh_handler;
- atomic_set(&new_request->refcount, 1);
- nes_post_cqp_request(nesdev, new_request);
- break;
-
- case PAU_ADD_LB_QH:
- /* Start processing the queued fpdu's */
- nesqp->pau_state = PAU_READY;
- process_fpdus(qh_chg->nesvnic, qh_chg->nesqp);
- kfree(qh_chg);
- break;
- }
-}
-
-/**
- * nes_change_quad_hash
- */
-static int nes_change_quad_hash(struct nes_device *nesdev,
- struct nes_vnic *nesvnic, struct nes_qp *nesqp)
-{
- struct nes_cqp_request *cqp_request = NULL;
- struct pau_qh_chg *qh_chg = NULL;
- u64 u64temp;
- struct nes_hw_cqp_wqe *cqp_wqe;
- int ret = 0;
-
- cqp_request = nes_get_cqp_request(nesdev);
- if (cqp_request == NULL) {
- nes_debug(NES_DBG_PAU, "Failed to get a cqp_request.\n");
- ret = -ENOMEM;
- goto chg_qh_err;
- }
-
- qh_chg = kmalloc(sizeof *qh_chg, GFP_ATOMIC);
- if (!qh_chg) {
- ret = -ENOMEM;
- goto chg_qh_err;
- }
- qh_chg->nesdev = nesdev;
- qh_chg->nesvnic = nesvnic;
- qh_chg->nesqp = nesqp;
- nesqp->pau_state = PAU_DEL_QH;
-
- cqp_wqe = &cqp_request->cqp_wqe;
- nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
- set_wqe_32bit_value(cqp_wqe->wqe_words,
- NES_CQP_WQE_OPCODE_IDX, NES_CQP_MANAGE_QUAD_HASH | NES_CQP_QP_DEL_HTE |
- NES_CQP_QP_TYPE_IWARP | NES_CQP_QP_CONTEXT_VALID | NES_CQP_QP_IWARP_STATE_RTS);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX, nesqp->hwqp.qp_id);
- u64temp = (u64)nesqp->nesqp_context_pbase;
- set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_CONTEXT_LOW_IDX, u64temp);
-
- nes_debug(NES_DBG_PAU, "Waiting for CQP completion for deleting the quad hash.\n");
-
- cqp_request->cqp_callback_pointer = qh_chg;
- cqp_request->callback = 1;
- cqp_request->cqp_callback = nes_chg_qh_handler;
- atomic_set(&cqp_request->refcount, 1);
- nes_post_cqp_request(nesdev, cqp_request);
-
- return ret;
-
-chg_qh_err:
- kfree(qh_chg);
- if (cqp_request)
- nes_put_cqp_request(nesdev, cqp_request);
- return ret;
-}
-
-/**
- * nes_mgt_ce_handler
- * This management code deals with any packed and unaligned (pau) fpdu's
- * that the hardware cannot handle.
- */
-static void nes_mgt_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
-{
- struct nes_vnic_mgt *mgtvnic = container_of(cq, struct nes_vnic_mgt, mgt_cq);
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- u32 head;
- u32 cq_size;
- u32 cqe_count = 0;
- u32 cqe_misc;
- u32 qp_id = 0;
- u32 skbs_needed;
- unsigned long context;
- struct nes_qp *nesqp;
- struct sk_buff *rx_skb;
- struct nes_rskb_cb *cb;
-
- head = cq->cq_head;
- cq_size = cq->cq_size;
-
- while (1) {
- cqe_misc = le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX]);
- if (!(cqe_misc & NES_NIC_CQE_VALID))
- break;
-
- nesqp = NULL;
- if (cqe_misc & NES_NIC_CQE_ACCQP_VALID) {
- qp_id = le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_ACCQP_ID_IDX]);
- qp_id &= 0x001fffff;
- if (qp_id < nesadapter->max_qp) {
- context = (unsigned long)nesadapter->qp_table[qp_id - NES_FIRST_QPN];
- nesqp = (struct nes_qp *)context;
- }
- }
-
- if (nesqp) {
- if (nesqp->pau_mode == false) {
- nesqp->pau_mode = true; /* First time for this qp */
- nesqp->pau_rcv_nxt = le32_to_cpu(
- cq->cq_vbase[head].cqe_words[NES_NIC_CQE_HASH_RCVNXT]);
- skb_queue_head_init(&nesqp->pau_list);
- spin_lock_init(&nesqp->pau_lock);
- atomic_inc(&pau_qps_created);
- nes_change_quad_hash(nesdev, mgtvnic->nesvnic, nesqp);
- }
-
- rx_skb = mgtvnic->mgt.rx_skb[mgtvnic->mgt.rq_tail];
- rx_skb->len = 0;
- skb_put(rx_skb, cqe_misc & 0x0000ffff);
- rx_skb->protocol = eth_type_trans(rx_skb, mgtvnic->nesvnic->netdev);
- cb = (struct nes_rskb_cb *)&rx_skb->cb[0];
- pci_unmap_single(nesdev->pcidev, cb->busaddr, cb->maplen, PCI_DMA_FROMDEVICE);
- cb->busaddr = 0;
- mgtvnic->mgt.rq_tail++;
- mgtvnic->mgt.rq_tail &= mgtvnic->mgt.rq_size - 1;
-
- nes_add_ref_cm_node(nesqp->cm_node);
- nes_queue_mgt_skbs(rx_skb, mgtvnic->nesvnic, nesqp);
- } else {
- printk(KERN_ERR PFX "Invalid QP %d for packed/unaligned handling\n", qp_id);
- }
-
- cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX] = 0;
- cqe_count++;
- if (++head >= cq_size)
- head = 0;
-
- if (cqe_count == 255) {
- /* Replenish mgt CQ */
- nes_write32(nesdev->regs + NES_CQE_ALLOC, cq->cq_number | (cqe_count << 16));
- nesdev->currcq_count += cqe_count;
- cqe_count = 0;
- }
-
- skbs_needed = atomic_inc_return(&mgtvnic->rx_skbs_needed);
- if (skbs_needed > (mgtvnic->mgt.rq_size >> 1))
- nes_replenish_mgt_rq(mgtvnic);
- }
-
- cq->cq_head = head;
- nes_write32(nesdev->regs + NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT |
- cq->cq_number | (cqe_count << 16));
- nes_read32(nesdev->regs + NES_CQE_ALLOC);
- nesdev->currcq_count += cqe_count;
-}
-
-/**
- * nes_init_mgt_qp
- */
-int nes_init_mgt_qp(struct nes_device *nesdev, struct net_device *netdev, struct nes_vnic *nesvnic)
-{
- struct nes_vnic_mgt *mgtvnic;
- u32 counter;
- void *vmem;
- dma_addr_t pmem;
- struct nes_hw_cqp_wqe *cqp_wqe;
- u32 cqp_head;
- unsigned long flags;
- struct nes_hw_nic_qp_context *mgt_context;
- u64 u64temp;
- struct nes_hw_nic_rq_wqe *mgt_rqe;
- struct sk_buff *skb;
- u32 wqe_count;
- struct nes_rskb_cb *cb;
- u32 mgt_mem_size;
- void *mgt_vbase;
- dma_addr_t mgt_pbase;
- int i;
- int ret;
-
- /* Allocate space the all mgt QPs once */
- mgtvnic = kcalloc(NES_MGT_QP_COUNT, sizeof(struct nes_vnic_mgt),
- GFP_KERNEL);
- if (!mgtvnic)
- return -ENOMEM;
-
- /* Allocate fragment, RQ, and CQ; Reuse CEQ based on the PCI function */
- /* We are not sending from this NIC so sq is not allocated */
- mgt_mem_size = 256 +
- (NES_MGT_WQ_COUNT * sizeof(struct nes_hw_nic_rq_wqe)) +
- (NES_MGT_WQ_COUNT * sizeof(struct nes_hw_nic_cqe)) +
- sizeof(struct nes_hw_nic_qp_context);
- mgt_mem_size = (mgt_mem_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
- mgt_vbase = pci_alloc_consistent(nesdev->pcidev, NES_MGT_QP_COUNT * mgt_mem_size, &mgt_pbase);
- if (!mgt_vbase) {
- kfree(mgtvnic);
- nes_debug(NES_DBG_INIT, "Unable to allocate memory for mgt host descriptor rings\n");
- return -ENOMEM;
- }
-
- nesvnic->mgt_mem_size = NES_MGT_QP_COUNT * mgt_mem_size;
- nesvnic->mgt_vbase = mgt_vbase;
- nesvnic->mgt_pbase = mgt_pbase;
-
- skb_queue_head_init(&nesvnic->mgt_skb_list);
- init_waitqueue_head(&nesvnic->mgt_wait_queue);
- nesvnic->mgt_thread = kthread_run(mgt_thread, nesvnic, "nes_mgt_thread");
-
- for (i = 0; i < NES_MGT_QP_COUNT; i++) {
- mgtvnic->nesvnic = nesvnic;
- mgtvnic->mgt.qp_id = nesdev->mac_index + NES_MGT_QP_OFFSET + i;
- memset(mgt_vbase, 0, mgt_mem_size);
- nes_debug(NES_DBG_INIT, "Allocated mgt QP structures at %p (phys = %016lX), size = %u.\n",
- mgt_vbase, (unsigned long)mgt_pbase, mgt_mem_size);
-
- vmem = (void *)(((unsigned long)mgt_vbase + (256 - 1)) &
- ~(unsigned long)(256 - 1));
- pmem = (dma_addr_t)(((unsigned long long)mgt_pbase + (256 - 1)) &
- ~(unsigned long long)(256 - 1));
-
- spin_lock_init(&mgtvnic->mgt.rq_lock);
-
- /* setup the RQ */
- mgtvnic->mgt.rq_vbase = vmem;
- mgtvnic->mgt.rq_pbase = pmem;
- mgtvnic->mgt.rq_head = 0;
- mgtvnic->mgt.rq_tail = 0;
- mgtvnic->mgt.rq_size = NES_MGT_WQ_COUNT;
-
- /* setup the CQ */
- vmem += (NES_MGT_WQ_COUNT * sizeof(struct nes_hw_nic_rq_wqe));
- pmem += (NES_MGT_WQ_COUNT * sizeof(struct nes_hw_nic_rq_wqe));
-
- mgtvnic->mgt_cq.cq_number = mgtvnic->mgt.qp_id;
- mgtvnic->mgt_cq.cq_vbase = vmem;
- mgtvnic->mgt_cq.cq_pbase = pmem;
- mgtvnic->mgt_cq.cq_head = 0;
- mgtvnic->mgt_cq.cq_size = NES_MGT_WQ_COUNT;
-
- mgtvnic->mgt_cq.ce_handler = nes_mgt_ce_handler;
-
- /* Send CreateCQ request to CQP */
- spin_lock_irqsave(&nesdev->cqp.lock, flags);
- cqp_head = nesdev->cqp.sq_head;
-
- cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
- nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
-
- cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(
- NES_CQP_CREATE_CQ | NES_CQP_CQ_CEQ_VALID |
- ((u32)mgtvnic->mgt_cq.cq_size << 16));
- cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(
- mgtvnic->mgt_cq.cq_number | ((u32)nesdev->ceq_index << 16));
- u64temp = (u64)mgtvnic->mgt_cq.cq_pbase;
- set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_PBL_LOW_IDX, u64temp);
- cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] = 0;
- u64temp = (unsigned long)&mgtvnic->mgt_cq;
- cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX] = cpu_to_le32((u32)(u64temp >> 1));
- cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] =
- cpu_to_le32(((u32)((u64temp) >> 33)) & 0x7FFFFFFF);
- cqp_wqe->wqe_words[NES_CQP_CQ_WQE_DOORBELL_INDEX_HIGH_IDX] = 0;
-
- if (++cqp_head >= nesdev->cqp.sq_size)
- cqp_head = 0;
- cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
- nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
-
- /* Send CreateQP request to CQP */
- mgt_context = (void *)(&mgtvnic->mgt_cq.cq_vbase[mgtvnic->mgt_cq.cq_size]);
- mgt_context->context_words[NES_NIC_CTX_MISC_IDX] =
- cpu_to_le32((u32)NES_MGT_CTX_SIZE |
- ((u32)PCI_FUNC(nesdev->pcidev->devfn) << 12));
- nes_debug(NES_DBG_INIT, "RX_WINDOW_BUFFER_PAGE_TABLE_SIZE = 0x%08X, RX_WINDOW_BUFFER_SIZE = 0x%08X\n",
- nes_read_indexed(nesdev, NES_IDX_RX_WINDOW_BUFFER_PAGE_TABLE_SIZE),
- nes_read_indexed(nesdev, NES_IDX_RX_WINDOW_BUFFER_SIZE));
- if (nes_read_indexed(nesdev, NES_IDX_RX_WINDOW_BUFFER_SIZE) != 0)
- mgt_context->context_words[NES_NIC_CTX_MISC_IDX] |= cpu_to_le32(NES_NIC_BACK_STORE);
-
- u64temp = (u64)mgtvnic->mgt.rq_pbase;
- mgt_context->context_words[NES_NIC_CTX_SQ_LOW_IDX] = cpu_to_le32((u32)u64temp);
- mgt_context->context_words[NES_NIC_CTX_SQ_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32));
- u64temp = (u64)mgtvnic->mgt.rq_pbase;
- mgt_context->context_words[NES_NIC_CTX_RQ_LOW_IDX] = cpu_to_le32((u32)u64temp);
- mgt_context->context_words[NES_NIC_CTX_RQ_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32));
-
- cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_CREATE_QP |
- NES_CQP_QP_TYPE_NIC);
- cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(mgtvnic->mgt.qp_id);
- u64temp = (u64)mgtvnic->mgt_cq.cq_pbase +
- (mgtvnic->mgt_cq.cq_size * sizeof(struct nes_hw_nic_cqe));
- set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_CONTEXT_LOW_IDX, u64temp);
-
- if (++cqp_head >= nesdev->cqp.sq_size)
- cqp_head = 0;
- nesdev->cqp.sq_head = cqp_head;
-
- barrier();
-
- /* Ring doorbell (2 WQEs) */
- nes_write32(nesdev->regs + NES_WQE_ALLOC, 0x02800000 | nesdev->cqp.qp_id);
-
- spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
- nes_debug(NES_DBG_INIT, "Waiting for create MGT QP%u to complete.\n",
- mgtvnic->mgt.qp_id);
-
- ret = wait_event_timeout(nesdev->cqp.waitq, (nesdev->cqp.sq_tail == cqp_head),
- NES_EVENT_TIMEOUT);
- nes_debug(NES_DBG_INIT, "Create MGT QP%u completed, wait_event_timeout ret = %u.\n",
- mgtvnic->mgt.qp_id, ret);
- if (!ret) {
- nes_debug(NES_DBG_INIT, "MGT QP%u create timeout expired\n", mgtvnic->mgt.qp_id);
- if (i == 0) {
- pci_free_consistent(nesdev->pcidev, nesvnic->mgt_mem_size, nesvnic->mgt_vbase,
- nesvnic->mgt_pbase);
- kfree(mgtvnic);
- } else {
- nes_destroy_mgt(nesvnic);
- }
- return -EIO;
- }
-
- /* Populate the RQ */
- for (counter = 0; counter < (NES_MGT_WQ_COUNT - 1); counter++) {
- skb = dev_alloc_skb(nesvnic->max_frame_size);
- if (!skb) {
- nes_debug(NES_DBG_INIT, "%s: out of memory for receive skb\n", netdev->name);
- return -ENOMEM;
- }
-
- skb->dev = netdev;
-
- pmem = pci_map_single(nesdev->pcidev, skb->data,
- nesvnic->max_frame_size, PCI_DMA_FROMDEVICE);
- cb = (struct nes_rskb_cb *)&skb->cb[0];
- cb->busaddr = pmem;
- cb->maplen = nesvnic->max_frame_size;
-
- mgt_rqe = &mgtvnic->mgt.rq_vbase[counter];
- mgt_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] = cpu_to_le32((u32)nesvnic->max_frame_size);
- mgt_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_3_2_IDX] = 0;
- mgt_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX] = cpu_to_le32((u32)pmem);
- mgt_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX] = cpu_to_le32((u32)((u64)pmem >> 32));
- mgtvnic->mgt.rx_skb[counter] = skb;
- }
-
- timer_setup(&mgtvnic->rq_wqes_timer, nes_mgt_rq_wqes_timeout,
- 0);
-
- wqe_count = NES_MGT_WQ_COUNT - 1;
- mgtvnic->mgt.rq_head = wqe_count;
- barrier();
- do {
- counter = min(wqe_count, ((u32)255));
- wqe_count -= counter;
- nes_write32(nesdev->regs + NES_WQE_ALLOC, (counter << 24) | mgtvnic->mgt.qp_id);
- } while (wqe_count);
-
- nes_write32(nesdev->regs + NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT |
- mgtvnic->mgt_cq.cq_number);
- nes_read32(nesdev->regs + NES_CQE_ALLOC);
-
- mgt_vbase += mgt_mem_size;
- mgt_pbase += mgt_mem_size;
- nesvnic->mgtvnic[i] = mgtvnic++;
- }
- return 0;
-}
-
-
-void nes_destroy_mgt(struct nes_vnic *nesvnic)
-{
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_vnic_mgt *mgtvnic;
- struct nes_vnic_mgt *first_mgtvnic;
- unsigned long flags;
- struct nes_hw_cqp_wqe *cqp_wqe;
- u32 cqp_head;
- struct sk_buff *rx_skb;
- int i;
- int ret;
-
- kthread_stop(nesvnic->mgt_thread);
-
- /* Free remaining NIC receive buffers */
- first_mgtvnic = nesvnic->mgtvnic[0];
- for (i = 0; i < NES_MGT_QP_COUNT; i++) {
- mgtvnic = nesvnic->mgtvnic[i];
- if (mgtvnic == NULL)
- continue;
-
- while (mgtvnic->mgt.rq_head != mgtvnic->mgt.rq_tail) {
- rx_skb = mgtvnic->mgt.rx_skb[mgtvnic->mgt.rq_tail];
- nes_mgt_free_skb(nesdev, rx_skb, PCI_DMA_FROMDEVICE);
- mgtvnic->mgt.rq_tail++;
- mgtvnic->mgt.rq_tail &= (mgtvnic->mgt.rq_size - 1);
- }
-
- spin_lock_irqsave(&nesdev->cqp.lock, flags);
-
- /* Destroy NIC QP */
- cqp_head = nesdev->cqp.sq_head;
- cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
- nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
-
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
- (NES_CQP_DESTROY_QP | NES_CQP_QP_TYPE_NIC));
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX,
- mgtvnic->mgt.qp_id);
-
- if (++cqp_head >= nesdev->cqp.sq_size)
- cqp_head = 0;
-
- cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
-
- /* Destroy NIC CQ */
- nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
- (NES_CQP_DESTROY_CQ | ((u32)mgtvnic->mgt_cq.cq_size << 16)));
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX,
- (mgtvnic->mgt_cq.cq_number | ((u32)nesdev->ceq_index << 16)));
-
- if (++cqp_head >= nesdev->cqp.sq_size)
- cqp_head = 0;
-
- nesdev->cqp.sq_head = cqp_head;
- barrier();
-
- /* Ring doorbell (2 WQEs) */
- nes_write32(nesdev->regs + NES_WQE_ALLOC, 0x02800000 | nesdev->cqp.qp_id);
-
- spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
- nes_debug(NES_DBG_SHUTDOWN, "Waiting for CQP, cqp_head=%u, cqp.sq_head=%u,"
- " cqp.sq_tail=%u, cqp.sq_size=%u\n",
- cqp_head, nesdev->cqp.sq_head,
- nesdev->cqp.sq_tail, nesdev->cqp.sq_size);
-
- ret = wait_event_timeout(nesdev->cqp.waitq, (nesdev->cqp.sq_tail == cqp_head),
- NES_EVENT_TIMEOUT);
-
- nes_debug(NES_DBG_SHUTDOWN, "Destroy MGT QP returned, wait_event_timeout ret = %u, cqp_head=%u,"
- " cqp.sq_head=%u, cqp.sq_tail=%u\n",
- ret, cqp_head, nesdev->cqp.sq_head, nesdev->cqp.sq_tail);
- if (!ret)
- nes_debug(NES_DBG_SHUTDOWN, "MGT QP%u destroy timeout expired\n",
- mgtvnic->mgt.qp_id);
-
- nesvnic->mgtvnic[i] = NULL;
- }
-
- if (nesvnic->mgt_vbase) {
- pci_free_consistent(nesdev->pcidev, nesvnic->mgt_mem_size, nesvnic->mgt_vbase,
- nesvnic->mgt_pbase);
- nesvnic->mgt_vbase = NULL;
- nesvnic->mgt_pbase = 0;
- }
-
- kfree(first_mgtvnic);
-}
diff --git a/drivers/infiniband/hw/nes/nes_mgt.h b/drivers/infiniband/hw/nes/nes_mgt.h
deleted file mode 100644
index 4f7f701c4a81..000000000000
--- a/drivers/infiniband/hw/nes/nes_mgt.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
-* Copyright (c) 2006 - 2011 Intel-NE, Inc. All rights reserved.
-*
-* This software is available to you under a choice of one of two
-* licenses. You may choose to be licensed under the terms of the GNU
-* General Public License (GPL) Version 2, available from the file
-* COPYING in the main directory of this source tree, or the
-* OpenIB.org BSD license below:
-*
-* Redistribution and use in source and binary forms, with or
-* without modification, are permitted provided that the following
-* conditions are met:
-*
-* - Redistributions of source code must retain the above
-* copyright notice, this list of conditions and the following
-* disclaimer.
-*
-* - Redistributions in binary form must reproduce the above
-* copyright notice, this list of conditions and the following
-* disclaimer in the documentation and/or other materials
-* provided with the distribution.
-*
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
-* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-* SOFTWARE.
-*/
-
-#ifndef __NES_MGT_H
-#define __NES_MGT_H
-
-#define MPA_FRAMING 6 /* length is 2 bytes, crc is 4 bytes */
-
-int nes_init_mgt_qp(struct nes_device *nesdev, struct net_device *netdev, struct nes_vnic *nesvnic);
-void nes_queue_mgt_skbs(struct sk_buff *skb, struct nes_vnic *nesvnic, struct nes_qp *nesqp);
-void nes_destroy_mgt(struct nes_vnic *nesvnic);
-void nes_destroy_pau_qp(struct nes_device *nesdev, struct nes_qp *nesqp);
-
-struct nes_hw_mgt {
- struct nes_hw_nic_rq_wqe *rq_vbase; /* virtual address of rq */
- dma_addr_t rq_pbase; /* PCI memory for host rings */
- struct sk_buff *rx_skb[NES_NIC_WQ_SIZE];
- u16 qp_id;
- u16 sq_head;
- u16 rq_head;
- u16 rq_tail;
- u16 rq_size;
- u8 replenishing_rq;
- u8 reserved;
- spinlock_t rq_lock;
-};
-
-struct nes_vnic_mgt {
- struct nes_vnic *nesvnic;
- struct nes_hw_mgt mgt;
- struct nes_hw_nic_cq mgt_cq;
- atomic_t rx_skbs_needed;
- struct timer_list rq_wqes_timer;
- atomic_t rx_skb_timer_running;
-};
-
-#define MAX_FPDU_FRAGS 4
-struct pau_fpdu_frag {
- struct sk_buff *skb;
- u64 physaddr;
- u32 frag_len;
- bool cmplt;
-};
-
-struct pau_fpdu_info {
- struct nes_qp *nesqp;
- struct nes_cqp_request *cqp_request;
- void *hdr_vbase;
- dma_addr_t hdr_pbase;
- int hdr_len;
- u16 data_len;
- u16 frag_cnt;
- struct pau_fpdu_frag frags[MAX_FPDU_FRAGS];
-};
-
-enum pau_qh_state {
- PAU_DEL_QH,
- PAU_ADD_LB_QH,
- PAU_READY
-};
-
-struct pau_qh_chg {
- struct nes_device *nesdev;
- struct nes_vnic *nesvnic;
- struct nes_qp *nesqp;
-};
-
-#endif /* __NES_MGT_H */
diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
deleted file mode 100644
index 16f33454c198..000000000000
--- a/drivers/infiniband/hw/nes/nes_nic.c
+++ /dev/null
@@ -1,1870 +0,0 @@
-/*
- * Copyright (c) 2006 - 2011 Intel Corporation. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>
-#include <linux/if_arp.h>
-#include <linux/if_vlan.h>
-#include <linux/ethtool.h>
-#include <linux/slab.h>
-#include <net/tcp.h>
-
-#include <net/inet_common.h>
-#include <linux/inet.h>
-
-#include "nes.h"
-
-static struct nic_qp_map nic_qp_mapping_0[] = {
- {16,0,0,1},{24,4,0,0},{28,8,0,0},{32,12,0,0},
- {20,2,2,1},{26,6,2,0},{30,10,2,0},{34,14,2,0},
- {18,1,1,1},{25,5,1,0},{29,9,1,0},{33,13,1,0},
- {22,3,3,1},{27,7,3,0},{31,11,3,0},{35,15,3,0}
-};
-
-static struct nic_qp_map nic_qp_mapping_1[] = {
- {18,1,1,1},{25,5,1,0},{29,9,1,0},{33,13,1,0},
- {22,3,3,1},{27,7,3,0},{31,11,3,0},{35,15,3,0}
-};
-
-static struct nic_qp_map nic_qp_mapping_2[] = {
- {20,2,2,1},{26,6,2,0},{30,10,2,0},{34,14,2,0}
-};
-
-static struct nic_qp_map nic_qp_mapping_3[] = {
- {22,3,3,1},{27,7,3,0},{31,11,3,0},{35,15,3,0}
-};
-
-static struct nic_qp_map nic_qp_mapping_4[] = {
- {28,8,0,0},{32,12,0,0}
-};
-
-static struct nic_qp_map nic_qp_mapping_5[] = {
- {29,9,1,0},{33,13,1,0}
-};
-
-static struct nic_qp_map nic_qp_mapping_6[] = {
- {30,10,2,0},{34,14,2,0}
-};
-
-static struct nic_qp_map nic_qp_mapping_7[] = {
- {31,11,3,0},{35,15,3,0}
-};
-
-static struct nic_qp_map *nic_qp_mapping_per_function[] = {
- nic_qp_mapping_0, nic_qp_mapping_1, nic_qp_mapping_2, nic_qp_mapping_3,
- nic_qp_mapping_4, nic_qp_mapping_5, nic_qp_mapping_6, nic_qp_mapping_7
-};
-
-static const u32 default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK
- | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN;
-static int debug = -1;
-static int nics_per_function = 1;
-
-/**
- * nes_netdev_poll
- */
-static int nes_netdev_poll(struct napi_struct *napi, int budget)
-{
- struct nes_vnic *nesvnic = container_of(napi, struct nes_vnic, napi);
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_hw_nic_cq *nescq = &nesvnic->nic_cq;
-
- nesvnic->budget = budget;
- nescq->cqes_pending = 0;
- nescq->rx_cqes_completed = 0;
- nescq->cqe_allocs_pending = 0;
- nescq->rx_pkts_indicated = 0;
-
- nes_nic_ce_handler(nesdev, nescq);
-
- if (nescq->cqes_pending == 0) {
- napi_complete(napi);
- /* clear out completed cqes and arm */
- nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT |
- nescq->cq_number | (nescq->cqe_allocs_pending << 16));
- nes_read32(nesdev->regs+NES_CQE_ALLOC);
- } else {
- /* clear out completed cqes but don't arm */
- nes_write32(nesdev->regs+NES_CQE_ALLOC,
- nescq->cq_number | (nescq->cqe_allocs_pending << 16));
- nes_debug(NES_DBG_NETDEV, "%s: exiting with work pending\n",
- nesvnic->netdev->name);
- }
- return nescq->rx_pkts_indicated;
-}
-
-
-/**
- * nes_netdev_open - Activate the network interface; ifconfig
- * ethx up.
- */
-static int nes_netdev_open(struct net_device *netdev)
-{
- u32 macaddr_low;
- u16 macaddr_high;
- struct nes_vnic *nesvnic = netdev_priv(netdev);
- struct nes_device *nesdev = nesvnic->nesdev;
- int ret;
- int i;
- struct nes_vnic *first_nesvnic = NULL;
- u32 nic_active_bit;
- u32 nic_active;
- struct list_head *list_pos, *list_temp;
- unsigned long flags;
-
- if (nesvnic->netdev_open == 1)
- return 0;
-
- if (netif_msg_ifup(nesvnic))
- printk(KERN_INFO PFX "%s: enabling interface\n", netdev->name);
-
- ret = nes_init_nic_qp(nesdev, netdev);
- if (ret) {
- return ret;
- }
-
- netif_carrier_off(netdev);
- netif_stop_queue(netdev);
-
- if ((!nesvnic->of_device_registered) && (nesvnic->rdma_enabled)) {
- nesvnic->nesibdev = nes_init_ofa_device(netdev);
- if (nesvnic->nesibdev == NULL) {
- printk(KERN_ERR PFX "%s: nesvnic->nesibdev alloc failed", netdev->name);
- } else {
- nesvnic->nesibdev->nesvnic = nesvnic;
- ret = nes_register_ofa_device(nesvnic->nesibdev);
- if (ret) {
- printk(KERN_ERR PFX "%s: Unable to register RDMA device, ret = %d\n",
- netdev->name, ret);
- }
- }
- }
- /* Set packet filters */
- nic_active_bit = 1 << nesvnic->nic_index;
- nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_ACTIVE);
- nic_active |= nic_active_bit;
- nes_write_indexed(nesdev, NES_IDX_NIC_ACTIVE, nic_active);
- nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_MULTICAST_ENABLE);
- nic_active |= nic_active_bit;
- nes_write_indexed(nesdev, NES_IDX_NIC_MULTICAST_ENABLE, nic_active);
- nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_BROADCAST_ON);
- nic_active |= nic_active_bit;
- nes_write_indexed(nesdev, NES_IDX_NIC_BROADCAST_ON, nic_active);
-
- macaddr_high = ((u16)netdev->dev_addr[0]) << 8;
- macaddr_high += (u16)netdev->dev_addr[1];
-
- macaddr_low = ((u32)netdev->dev_addr[2]) << 24;
- macaddr_low += ((u32)netdev->dev_addr[3]) << 16;
- macaddr_low += ((u32)netdev->dev_addr[4]) << 8;
- macaddr_low += (u32)netdev->dev_addr[5];
-
- /* Program the various MAC regs */
- for (i = 0; i < NES_MAX_PORT_COUNT; i++) {
- if (nesvnic->qp_nic_index[i] == 0xf) {
- break;
- }
- nes_debug(NES_DBG_NETDEV, "i=%d, perfect filter table index= %d, PERF FILTER LOW"
- " (Addr:%08X) = %08X, HIGH = %08X.\n",
- i, nesvnic->qp_nic_index[i],
- NES_IDX_PERFECT_FILTER_LOW+
- (nesvnic->qp_nic_index[i] * 8),
- macaddr_low,
- (u32)macaddr_high | NES_MAC_ADDR_VALID |
- ((((u32)nesvnic->nic_index) << 16)));
- nes_write_indexed(nesdev,
- NES_IDX_PERFECT_FILTER_LOW + (nesvnic->qp_nic_index[i] * 8),
- macaddr_low);
- nes_write_indexed(nesdev,
- NES_IDX_PERFECT_FILTER_HIGH + (nesvnic->qp_nic_index[i] * 8),
- (u32)macaddr_high | NES_MAC_ADDR_VALID |
- ((((u32)nesvnic->nic_index) << 16)));
- }
-
-
- nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT |
- nesvnic->nic_cq.cq_number);
- nes_read32(nesdev->regs+NES_CQE_ALLOC);
- list_for_each_safe(list_pos, list_temp, &nesdev->nesadapter->nesvnic_list[nesdev->mac_index]) {
- first_nesvnic = container_of(list_pos, struct nes_vnic, list);
- if (first_nesvnic->netdev_open == 1)
- break;
- }
- if (first_nesvnic->netdev_open == 0) {
- nes_debug(NES_DBG_INIT, "Setting up MAC interrupt mask.\n");
- nes_write_indexed(nesdev, NES_IDX_MAC_INT_MASK + (0x200 * nesdev->mac_index),
- ~(NES_MAC_INT_LINK_STAT_CHG | NES_MAC_INT_XGMII_EXT |
- NES_MAC_INT_TX_UNDERFLOW | NES_MAC_INT_TX_ERROR));
- first_nesvnic = nesvnic;
- }
-
- if (first_nesvnic->linkup) {
- /* Enable network packets */
- nesvnic->linkup = 1;
- netif_start_queue(netdev);
- netif_carrier_on(netdev);
- }
-
- spin_lock_irqsave(&nesdev->nesadapter->phy_lock, flags);
- if (nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_SFP_D) {
- nesdev->link_recheck = 1;
- mod_delayed_work(system_wq, &nesdev->work,
- NES_LINK_RECHECK_DELAY);
- }
- spin_unlock_irqrestore(&nesdev->nesadapter->phy_lock, flags);
-
- spin_lock_irqsave(&nesvnic->port_ibevent_lock, flags);
- if (nesvnic->of_device_registered) {
- nesdev->nesadapter->send_term_ok = 1;
- if (nesvnic->linkup == 1) {
- if (nesdev->iw_status == 0) {
- nesdev->iw_status = 1;
- nes_port_ibevent(nesvnic);
- }
- } else {
- nesdev->iw_status = 0;
- }
- }
- spin_unlock_irqrestore(&nesvnic->port_ibevent_lock, flags);
-
- napi_enable(&nesvnic->napi);
- nesvnic->netdev_open = 1;
-
- return 0;
-}
-
-
-/**
- * nes_netdev_stop
- */
-static int nes_netdev_stop(struct net_device *netdev)
-{
- struct nes_vnic *nesvnic = netdev_priv(netdev);
- struct nes_device *nesdev = nesvnic->nesdev;
- u32 nic_active_mask;
- u32 nic_active;
- struct nes_vnic *first_nesvnic = NULL;
- struct list_head *list_pos, *list_temp;
- unsigned long flags;
-
- nes_debug(NES_DBG_SHUTDOWN, "nesvnic=%p, nesdev=%p, netdev=%p %s\n",
- nesvnic, nesdev, netdev, netdev->name);
- if (nesvnic->netdev_open == 0)
- return 0;
-
- if (netif_msg_ifdown(nesvnic))
- printk(KERN_INFO PFX "%s: disabling interface\n", netdev->name);
- netif_carrier_off(netdev);
-
- /* Disable network packets */
- napi_disable(&nesvnic->napi);
- netif_stop_queue(netdev);
- list_for_each_safe(list_pos, list_temp, &nesdev->nesadapter->nesvnic_list[nesdev->mac_index]) {
- first_nesvnic = container_of(list_pos, struct nes_vnic, list);
- if ((first_nesvnic->netdev_open == 1) && (first_nesvnic != nesvnic))
- break;
- }
-
- if ((first_nesvnic->netdev_open == 1) && (first_nesvnic != nesvnic) &&
- (PCI_FUNC(first_nesvnic->nesdev->pcidev->devfn) !=
- PCI_FUNC(nesvnic->nesdev->pcidev->devfn))) {
- nes_write_indexed(nesdev, NES_IDX_MAC_INT_MASK+
- (0x200*nesdev->mac_index), 0xffffffff);
- nes_write_indexed(first_nesvnic->nesdev,
- NES_IDX_MAC_INT_MASK+
- (0x200*first_nesvnic->nesdev->mac_index),
- ~(NES_MAC_INT_LINK_STAT_CHG | NES_MAC_INT_XGMII_EXT |
- NES_MAC_INT_TX_UNDERFLOW | NES_MAC_INT_TX_ERROR));
- } else {
- nes_write_indexed(nesdev, NES_IDX_MAC_INT_MASK+(0x200*nesdev->mac_index), 0xffffffff);
- }
-
- nic_active_mask = ~((u32)(1 << nesvnic->nic_index));
- nes_write_indexed(nesdev, NES_IDX_PERFECT_FILTER_HIGH+
- (nesvnic->perfect_filter_index*8), 0);
- nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_ACTIVE);
- nic_active &= nic_active_mask;
- nes_write_indexed(nesdev, NES_IDX_NIC_ACTIVE, nic_active);
- nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL);
- nic_active &= nic_active_mask;
- nes_write_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL, nic_active);
- nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_MULTICAST_ENABLE);
- nic_active &= nic_active_mask;
- nes_write_indexed(nesdev, NES_IDX_NIC_MULTICAST_ENABLE, nic_active);
- nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL);
- nic_active &= nic_active_mask;
- nes_write_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL, nic_active);
- nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_BROADCAST_ON);
- nic_active &= nic_active_mask;
- nes_write_indexed(nesdev, NES_IDX_NIC_BROADCAST_ON, nic_active);
-
- spin_lock_irqsave(&nesvnic->port_ibevent_lock, flags);
- if (nesvnic->of_device_registered) {
- nesdev->nesadapter->send_term_ok = 0;
- nesdev->iw_status = 0;
- if (nesvnic->linkup == 1)
- nes_port_ibevent(nesvnic);
- }
- del_timer_sync(&nesvnic->event_timer);
- nesvnic->event_timer.function = NULL;
- spin_unlock_irqrestore(&nesvnic->port_ibevent_lock, flags);
-
- nes_destroy_nic_qp(nesvnic);
-
- nesvnic->netdev_open = 0;
-
- return 0;
-}
-
-
-/**
- * nes_nic_send
- */
-static bool nes_nic_send(struct sk_buff *skb, struct net_device *netdev)
-{
- struct nes_vnic *nesvnic = netdev_priv(netdev);
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_hw_nic *nesnic = &nesvnic->nic;
- struct nes_hw_nic_sq_wqe *nic_sqe;
- struct tcphdr *tcph;
- __le16 *wqe_fragment_length;
- u32 wqe_misc;
- u16 wqe_fragment_index = 1; /* first fragment (0) is used by copy buffer */
- u16 skb_fragment_index;
- dma_addr_t bus_address;
-
- nic_sqe = &nesnic->sq_vbase[nesnic->sq_head];
- wqe_fragment_length = (__le16 *)&nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX];
-
- /* setup the VLAN tag if present */
- if (skb_vlan_tag_present(skb)) {
- nes_debug(NES_DBG_NIC_TX, "%s: VLAN packet to send... VLAN = %08X\n",
- netdev->name, skb_vlan_tag_get(skb));
- wqe_misc = NES_NIC_SQ_WQE_TAGVALUE_ENABLE;
- wqe_fragment_length[0] = (__force __le16) skb_vlan_tag_get(skb);
- } else
- wqe_misc = 0;
-
- /* bump past the vlan tag */
- wqe_fragment_length++;
- /* wqe_fragment_address = (u64 *)&nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX]; */
- wqe_misc |= NES_NIC_SQ_WQE_COMPLETION;
-
- if (skb->ip_summed == CHECKSUM_PARTIAL) {
- if (skb_is_gso(skb)) {
- tcph = tcp_hdr(skb);
- /* nes_debug(NES_DBG_NIC_TX, "%s: TSO request... is_gso = %u seg size = %u\n",
- netdev->name, skb_is_gso(skb), skb_shinfo(skb)->gso_size); */
- wqe_misc |= NES_NIC_SQ_WQE_LSO_ENABLE | (u16)skb_shinfo(skb)->gso_size;
- set_wqe_32bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_LSO_INFO_IDX,
- ((u32)tcph->doff) |
- (((u32)(((unsigned char *)tcph) - skb->data)) << 4));
- }
- } else { /* CHECKSUM_HW */
- wqe_misc |= NES_NIC_SQ_WQE_DISABLE_CHKSUM;
- }
-
- set_wqe_32bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_TOTAL_LENGTH_IDX,
- skb->len);
- memcpy(&nesnic->first_frag_vbase[nesnic->sq_head].buffer,
- skb->data, min(((unsigned int)NES_FIRST_FRAG_SIZE), skb_headlen(skb)));
- wqe_fragment_length[0] = cpu_to_le16(min(((unsigned int)NES_FIRST_FRAG_SIZE),
- skb_headlen(skb)));
- wqe_fragment_length[1] = 0;
- if (skb_headlen(skb) > NES_FIRST_FRAG_SIZE) {
- if ((skb_shinfo(skb)->nr_frags + 1) > 4) {
- nes_debug(NES_DBG_NIC_TX, "%s: Packet with %u fragments not sent, skb_headlen=%u\n",
- netdev->name, skb_shinfo(skb)->nr_frags + 2, skb_headlen(skb));
- kfree_skb(skb);
- nesvnic->tx_sw_dropped++;
- return false;
- }
- set_bit(nesnic->sq_head, nesnic->first_frag_overflow);
- bus_address = pci_map_single(nesdev->pcidev, skb->data + NES_FIRST_FRAG_SIZE,
- skb_headlen(skb) - NES_FIRST_FRAG_SIZE, PCI_DMA_TODEVICE);
- wqe_fragment_length[wqe_fragment_index++] =
- cpu_to_le16(skb_headlen(skb) - NES_FIRST_FRAG_SIZE);
- wqe_fragment_length[wqe_fragment_index] = 0;
- set_wqe_64bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_FRAG1_LOW_IDX,
- ((u64)(bus_address)));
- nesnic->tx_skb[nesnic->sq_head] = skb;
- }
-
- if (skb_headlen(skb) == skb->len) {
- if (skb_headlen(skb) <= NES_FIRST_FRAG_SIZE) {
- nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_2_1_IDX] = 0;
- nesnic->tx_skb[nesnic->sq_head] = skb;
- }
- } else {
- /* Deal with Fragments */
- nesnic->tx_skb[nesnic->sq_head] = skb;
- for (skb_fragment_index = 0; skb_fragment_index < skb_shinfo(skb)->nr_frags;
- skb_fragment_index++) {
- skb_frag_t *frag =
- &skb_shinfo(skb)->frags[skb_fragment_index];
- bus_address = skb_frag_dma_map(&nesdev->pcidev->dev,
- frag, 0, skb_frag_size(frag),
- DMA_TO_DEVICE);
- wqe_fragment_length[wqe_fragment_index] =
- cpu_to_le16(skb_frag_size(&skb_shinfo(skb)->frags[skb_fragment_index]));
- set_wqe_64bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_FRAG0_LOW_IDX+(2*wqe_fragment_index),
- bus_address);
- wqe_fragment_index++;
- if (wqe_fragment_index < 5)
- wqe_fragment_length[wqe_fragment_index] = 0;
- }
- }
-
- set_wqe_32bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_MISC_IDX, wqe_misc);
- nesnic->sq_head++;
- nesnic->sq_head &= nesnic->sq_size - 1;
- return true;
-}
-
-
-/**
- * nes_netdev_start_xmit
- */
-static netdev_tx_t nes_netdev_start_xmit(struct sk_buff *skb, struct net_device *netdev)
-{
- struct nes_vnic *nesvnic = netdev_priv(netdev);
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_hw_nic *nesnic = &nesvnic->nic;
- struct nes_hw_nic_sq_wqe *nic_sqe;
- struct tcphdr *tcph;
- /* struct udphdr *udph; */
-#define NES_MAX_TSO_FRAGS MAX_SKB_FRAGS
- /* 64K segment plus overflow on each side */
- dma_addr_t tso_bus_address[NES_MAX_TSO_FRAGS];
- dma_addr_t bus_address;
- u32 tso_frag_index;
- u32 tso_frag_count;
- u32 tso_wqe_length;
- u32 curr_tcp_seq;
- u32 wqe_count=1;
- struct iphdr *iph;
- __le16 *wqe_fragment_length;
- u32 nr_frags;
- u32 original_first_length;
- /* u64 *wqe_fragment_address; */
- /* first fragment (0) is used by copy buffer */
- u16 wqe_fragment_index=1;
- u16 hoffset;
- u16 nhoffset;
- u16 wqes_needed;
- u16 wqes_available;
- u32 wqe_misc;
-
- /*
- * nes_debug(NES_DBG_NIC_TX, "%s Request to tx NIC packet length %u, headlen %u,"
- * " (%u frags), tso_size=%u\n",
- * netdev->name, skb->len, skb_headlen(skb),
- * skb_shinfo(skb)->nr_frags, skb_is_gso(skb));
- */
-
- if (netif_queue_stopped(netdev))
- return NETDEV_TX_BUSY;
-
- /* Check if SQ is full */
- if ((((nesnic->sq_tail+(nesnic->sq_size*2))-nesnic->sq_head) & (nesnic->sq_size - 1)) == 1) {
- if (!netif_queue_stopped(netdev)) {
- netif_stop_queue(netdev);
- barrier();
- if ((((((volatile u16)nesnic->sq_tail)+(nesnic->sq_size*2))-nesnic->sq_head) & (nesnic->sq_size - 1)) != 1) {
- netif_start_queue(netdev);
- goto sq_no_longer_full;
- }
- }
- nesvnic->sq_full++;
- return NETDEV_TX_BUSY;
- }
-
-sq_no_longer_full:
- nr_frags = skb_shinfo(skb)->nr_frags;
- if (skb_headlen(skb) > NES_FIRST_FRAG_SIZE) {
- nr_frags++;
- }
- /* Check if too many fragments */
- if (unlikely((nr_frags > 4))) {
- if (skb_is_gso(skb)) {
- nesvnic->segmented_tso_requests++;
- nesvnic->tso_requests++;
- /* Basically 4 fragments available per WQE with extended fragments */
- wqes_needed = nr_frags >> 2;
- wqes_needed += (nr_frags&3)?1:0;
- wqes_available = (((nesnic->sq_tail+nesnic->sq_size)-nesnic->sq_head) - 1) &
- (nesnic->sq_size - 1);
-
- if (unlikely(wqes_needed > wqes_available)) {
- if (!netif_queue_stopped(netdev)) {
- netif_stop_queue(netdev);
- barrier();
- wqes_available = (((((volatile u16)nesnic->sq_tail)+nesnic->sq_size)-nesnic->sq_head) - 1) &
- (nesnic->sq_size - 1);
- if (wqes_needed <= wqes_available) {
- netif_start_queue(netdev);
- goto tso_sq_no_longer_full;
- }
- }
- nesvnic->sq_full++;
- nes_debug(NES_DBG_NIC_TX, "%s: HNIC SQ full- TSO request has too many frags!\n",
- netdev->name);
- return NETDEV_TX_BUSY;
- }
-tso_sq_no_longer_full:
- /* Map all the buffers */
- for (tso_frag_count=0; tso_frag_count < skb_shinfo(skb)->nr_frags;
- tso_frag_count++) {
- skb_frag_t *frag =
- &skb_shinfo(skb)->frags[tso_frag_count];
- tso_bus_address[tso_frag_count] =
- skb_frag_dma_map(&nesdev->pcidev->dev,
- frag, 0, skb_frag_size(frag),
- DMA_TO_DEVICE);
- }
-
- tso_frag_index = 0;
- curr_tcp_seq = ntohl(tcp_hdr(skb)->seq);
- hoffset = skb_transport_header(skb) - skb->data;
- nhoffset = skb_network_header(skb) - skb->data;
- original_first_length = hoffset + ((((struct tcphdr *)skb_transport_header(skb))->doff)<<2);
-
- for (wqe_count=0; wqe_count<((u32)wqes_needed); wqe_count++) {
- tso_wqe_length = 0;
- nic_sqe = &nesnic->sq_vbase[nesnic->sq_head];
- wqe_fragment_length =
- (__le16 *)&nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX];
- /* setup the VLAN tag if present */
- if (skb_vlan_tag_present(skb)) {
- nes_debug(NES_DBG_NIC_TX, "%s: VLAN packet to send... VLAN = %08X\n",
- netdev->name,
- skb_vlan_tag_get(skb));
- wqe_misc = NES_NIC_SQ_WQE_TAGVALUE_ENABLE;
- wqe_fragment_length[0] = (__force __le16) skb_vlan_tag_get(skb);
- } else
- wqe_misc = 0;
-
- /* bump past the vlan tag */
- wqe_fragment_length++;
-
- /* Assumes header totally fits in allocated buffer and is in first fragment */
- if (original_first_length > NES_FIRST_FRAG_SIZE) {
- nes_debug(NES_DBG_NIC_TX, "ERROR: SKB header too big, headlen=%u, FIRST_FRAG_SIZE=%u\n",
- original_first_length, NES_FIRST_FRAG_SIZE);
- nes_debug(NES_DBG_NIC_TX, "%s Request to tx NIC packet length %u, headlen %u,"
- " (%u frags), is_gso = %u tso_size=%u\n",
- netdev->name,
- skb->len, skb_headlen(skb),
- skb_shinfo(skb)->nr_frags, skb_is_gso(skb), skb_shinfo(skb)->gso_size);
- }
- memcpy(&nesnic->first_frag_vbase[nesnic->sq_head].buffer,
- skb->data, min(((unsigned int)NES_FIRST_FRAG_SIZE),
- original_first_length));
- iph = (struct iphdr *)
- (&nesnic->first_frag_vbase[nesnic->sq_head].buffer[nhoffset]);
- tcph = (struct tcphdr *)
- (&nesnic->first_frag_vbase[nesnic->sq_head].buffer[hoffset]);
- if ((wqe_count+1)!=(u32)wqes_needed) {
- tcph->fin = 0;
- tcph->psh = 0;
- tcph->rst = 0;
- tcph->urg = 0;
- }
- if (wqe_count) {
- tcph->syn = 0;
- }
- tcph->seq = htonl(curr_tcp_seq);
- wqe_fragment_length[0] = cpu_to_le16(min(((unsigned int)NES_FIRST_FRAG_SIZE),
- original_first_length));
-
- wqe_fragment_index = 1;
- if ((wqe_count==0) && (skb_headlen(skb) > original_first_length)) {
- set_bit(nesnic->sq_head, nesnic->first_frag_overflow);
- bus_address = pci_map_single(nesdev->pcidev, skb->data + original_first_length,
- skb_headlen(skb) - original_first_length, PCI_DMA_TODEVICE);
- wqe_fragment_length[wqe_fragment_index++] =
- cpu_to_le16(skb_headlen(skb) - original_first_length);
- wqe_fragment_length[wqe_fragment_index] = 0;
- set_wqe_64bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_FRAG1_LOW_IDX,
- bus_address);
- tso_wqe_length += skb_headlen(skb) -
- original_first_length;
- }
- while (wqe_fragment_index < 5) {
- wqe_fragment_length[wqe_fragment_index] =
- cpu_to_le16(skb_frag_size(&skb_shinfo(skb)->frags[tso_frag_index]));
- set_wqe_64bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_FRAG0_LOW_IDX+(2*wqe_fragment_index),
- (u64)tso_bus_address[tso_frag_index]);
- wqe_fragment_index++;
- tso_wqe_length += skb_frag_size(&skb_shinfo(skb)->frags[tso_frag_index++]);
- if (wqe_fragment_index < 5)
- wqe_fragment_length[wqe_fragment_index] = 0;
- if (tso_frag_index == tso_frag_count)
- break;
- }
- if ((wqe_count+1) == (u32)wqes_needed) {
- nesnic->tx_skb[nesnic->sq_head] = skb;
- } else {
- nesnic->tx_skb[nesnic->sq_head] = NULL;
- }
- wqe_misc |= NES_NIC_SQ_WQE_COMPLETION | (u16)skb_shinfo(skb)->gso_size;
- if ((tso_wqe_length + original_first_length) > skb_shinfo(skb)->gso_size) {
- wqe_misc |= NES_NIC_SQ_WQE_LSO_ENABLE;
- } else {
- iph->tot_len = htons(tso_wqe_length + original_first_length - nhoffset);
- }
-
- set_wqe_32bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_MISC_IDX,
- wqe_misc);
- set_wqe_32bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_LSO_INFO_IDX,
- ((u32)tcph->doff) | (((u32)hoffset) << 4));
-
- set_wqe_32bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_TOTAL_LENGTH_IDX,
- tso_wqe_length + original_first_length);
- curr_tcp_seq += tso_wqe_length;
- nesnic->sq_head++;
- nesnic->sq_head &= nesnic->sq_size-1;
- }
- } else {
- hoffset = skb_transport_header(skb) - skb->data;
- nhoffset = skb_network_header(skb) - skb->data;
- if (skb_linearize(skb)) {
- nesvnic->tx_sw_dropped++;
- kfree_skb(skb);
- return NETDEV_TX_OK;
- }
- nesvnic->linearized_skbs++;
- skb_set_transport_header(skb, hoffset);
- skb_set_network_header(skb, nhoffset);
- if (!nes_nic_send(skb, netdev))
- return NETDEV_TX_OK;
- }
- } else {
- if (!nes_nic_send(skb, netdev))
- return NETDEV_TX_OK;
- }
-
- barrier();
-
- if (wqe_count)
- nes_write32(nesdev->regs+NES_WQE_ALLOC,
- (wqe_count << 24) | (1 << 23) | nesvnic->nic.qp_id);
-
- netif_trans_update(netdev);
-
- return NETDEV_TX_OK;
-}
-
-
-/**
- * nes_netdev_get_stats
- */
-static struct net_device_stats *nes_netdev_get_stats(struct net_device *netdev)
-{
- struct nes_vnic *nesvnic = netdev_priv(netdev);
- struct nes_device *nesdev = nesvnic->nesdev;
- u64 u64temp;
- u32 u32temp;
-
- u32temp = nes_read_indexed(nesdev,
- NES_IDX_ENDNODE0_NSTAT_RX_DISCARD + (nesvnic->nic_index*0x200));
- nesvnic->netstats.rx_dropped += u32temp;
- nesvnic->endnode_nstat_rx_discard += u32temp;
-
- u64temp = (u64)nes_read_indexed(nesdev,
- NES_IDX_ENDNODE0_NSTAT_RX_OCTETS_LO + (nesvnic->nic_index*0x200));
- u64temp += ((u64)nes_read_indexed(nesdev,
- NES_IDX_ENDNODE0_NSTAT_RX_OCTETS_HI + (nesvnic->nic_index*0x200))) << 32;
-
- nesvnic->endnode_nstat_rx_octets += u64temp;
- nesvnic->netstats.rx_bytes += u64temp;
-
- u64temp = (u64)nes_read_indexed(nesdev,
- NES_IDX_ENDNODE0_NSTAT_RX_FRAMES_LO + (nesvnic->nic_index*0x200));
- u64temp += ((u64)nes_read_indexed(nesdev,
- NES_IDX_ENDNODE0_NSTAT_RX_FRAMES_HI + (nesvnic->nic_index*0x200))) << 32;
-
- nesvnic->endnode_nstat_rx_frames += u64temp;
- nesvnic->netstats.rx_packets += u64temp;
-
- u64temp = (u64)nes_read_indexed(nesdev,
- NES_IDX_ENDNODE0_NSTAT_TX_OCTETS_LO + (nesvnic->nic_index*0x200));
- u64temp += ((u64)nes_read_indexed(nesdev,
- NES_IDX_ENDNODE0_NSTAT_TX_OCTETS_HI + (nesvnic->nic_index*0x200))) << 32;
-
- nesvnic->endnode_nstat_tx_octets += u64temp;
- nesvnic->netstats.tx_bytes += u64temp;
-
- u64temp = (u64)nes_read_indexed(nesdev,
- NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_LO + (nesvnic->nic_index*0x200));
- u64temp += ((u64)nes_read_indexed(nesdev,
- NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_HI + (nesvnic->nic_index*0x200))) << 32;
-
- nesvnic->endnode_nstat_tx_frames += u64temp;
- nesvnic->netstats.tx_packets += u64temp;
-
- u32temp = nes_read_indexed(nesdev,
- NES_IDX_MAC_RX_SHORT_FRAMES + (nesvnic->nesdev->mac_index*0x200));
- nesvnic->netstats.rx_dropped += u32temp;
- nesvnic->nesdev->mac_rx_errors += u32temp;
- nesvnic->nesdev->mac_rx_short_frames += u32temp;
-
- u32temp = nes_read_indexed(nesdev,
- NES_IDX_MAC_RX_OVERSIZED_FRAMES + (nesvnic->nesdev->mac_index*0x200));
- nesvnic->netstats.rx_dropped += u32temp;
- nesvnic->nesdev->mac_rx_errors += u32temp;
- nesvnic->nesdev->mac_rx_oversized_frames += u32temp;
-
- u32temp = nes_read_indexed(nesdev,
- NES_IDX_MAC_RX_JABBER_FRAMES + (nesvnic->nesdev->mac_index*0x200));
- nesvnic->netstats.rx_dropped += u32temp;
- nesvnic->nesdev->mac_rx_errors += u32temp;
- nesvnic->nesdev->mac_rx_jabber_frames += u32temp;
-
- u32temp = nes_read_indexed(nesdev,
- NES_IDX_MAC_RX_SYMBOL_ERR_FRAMES + (nesvnic->nesdev->mac_index*0x200));
- nesvnic->netstats.rx_dropped += u32temp;
- nesvnic->nesdev->mac_rx_errors += u32temp;
- nesvnic->nesdev->mac_rx_symbol_err_frames += u32temp;
-
- u32temp = nes_read_indexed(nesdev,
- NES_IDX_MAC_RX_LENGTH_ERR_FRAMES + (nesvnic->nesdev->mac_index*0x200));
- nesvnic->netstats.rx_length_errors += u32temp;
- nesvnic->nesdev->mac_rx_errors += u32temp;
-
- u32temp = nes_read_indexed(nesdev,
- NES_IDX_MAC_RX_CRC_ERR_FRAMES + (nesvnic->nesdev->mac_index*0x200));
- nesvnic->nesdev->mac_rx_errors += u32temp;
- nesvnic->nesdev->mac_rx_crc_errors += u32temp;
- nesvnic->netstats.rx_crc_errors += u32temp;
-
- u32temp = nes_read_indexed(nesdev,
- NES_IDX_MAC_TX_ERRORS + (nesvnic->nesdev->mac_index*0x200));
- nesvnic->nesdev->mac_tx_errors += u32temp;
- nesvnic->netstats.tx_errors += u32temp;
-
- return &nesvnic->netstats;
-}
-
-
-/**
- * nes_netdev_tx_timeout
- */
-static void nes_netdev_tx_timeout(struct net_device *netdev)
-{
- struct nes_vnic *nesvnic = netdev_priv(netdev);
-
- if (netif_msg_timer(nesvnic))
- nes_debug(NES_DBG_NIC_TX, "%s: tx timeout\n", netdev->name);
-}
-
-
-/**
- * nes_netdev_set_mac_address
- */
-static int nes_netdev_set_mac_address(struct net_device *netdev, void *p)
-{
- struct nes_vnic *nesvnic = netdev_priv(netdev);
- struct nes_device *nesdev = nesvnic->nesdev;
- struct sockaddr *mac_addr = p;
- int i;
- u32 macaddr_low;
- u16 macaddr_high;
-
- if (!is_valid_ether_addr(mac_addr->sa_data))
- return -EADDRNOTAVAIL;
-
- memcpy(netdev->dev_addr, mac_addr->sa_data, netdev->addr_len);
- printk(PFX "%s: Address length = %d, Address = %pM\n",
- __func__, netdev->addr_len, mac_addr->sa_data);
- macaddr_high = ((u16)netdev->dev_addr[0]) << 8;
- macaddr_high += (u16)netdev->dev_addr[1];
- macaddr_low = ((u32)netdev->dev_addr[2]) << 24;
- macaddr_low += ((u32)netdev->dev_addr[3]) << 16;
- macaddr_low += ((u32)netdev->dev_addr[4]) << 8;
- macaddr_low += (u32)netdev->dev_addr[5];
-
- for (i = 0; i < NES_MAX_PORT_COUNT; i++) {
- if (nesvnic->qp_nic_index[i] == 0xf) {
- break;
- }
- nes_write_indexed(nesdev,
- NES_IDX_PERFECT_FILTER_LOW + (nesvnic->qp_nic_index[i] * 8),
- macaddr_low);
- nes_write_indexed(nesdev,
- NES_IDX_PERFECT_FILTER_HIGH + (nesvnic->qp_nic_index[i] * 8),
- (u32)macaddr_high | NES_MAC_ADDR_VALID |
- ((((u32)nesvnic->nic_index) << 16)));
- }
- return 0;
-}
-
-
-static void set_allmulti(struct nes_device *nesdev, u32 nic_active_bit)
-{
- u32 nic_active;
-
- nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL);
- nic_active |= nic_active_bit;
- nes_write_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL, nic_active);
- nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL);
- nic_active &= ~nic_active_bit;
- nes_write_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL, nic_active);
-}
-
-#define get_addr(addrs, index) ((addrs) + (index) * ETH_ALEN)
-
-/**
- * nes_netdev_set_multicast_list
- */
-static void nes_netdev_set_multicast_list(struct net_device *netdev)
-{
- struct nes_vnic *nesvnic = netdev_priv(netdev);
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_adapter *nesadapter = nesvnic->nesdev->nesadapter;
- u32 nic_active_bit;
- u32 nic_active;
- u32 perfect_filter_register_address;
- u32 macaddr_low;
- u16 macaddr_high;
- u8 mc_all_on = 0;
- u8 mc_index;
- int mc_nic_index = -1;
- u8 pft_entries_preallocated = max(nesadapter->adapter_fcn_count *
- nics_per_function, 4);
- u8 max_pft_entries_avaiable = NES_PFT_SIZE - pft_entries_preallocated;
- unsigned long flags;
- int mc_count = netdev_mc_count(netdev);
-
- spin_lock_irqsave(&nesadapter->resource_lock, flags);
- nic_active_bit = 1 << nesvnic->nic_index;
-
- if (netdev->flags & IFF_PROMISC) {
- nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL);
- nic_active |= nic_active_bit;
- nes_write_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL, nic_active);
- nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL);
- nic_active |= nic_active_bit;
- nes_write_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL, nic_active);
- mc_all_on = 1;
- } else if ((netdev->flags & IFF_ALLMULTI) ||
- (nesvnic->nic_index > 3)) {
- set_allmulti(nesdev, nic_active_bit);
- mc_all_on = 1;
- } else {
- nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL);
- nic_active &= ~nic_active_bit;
- nes_write_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL, nic_active);
- nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL);
- nic_active &= ~nic_active_bit;
- nes_write_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL, nic_active);
- }
-
- nes_debug(NES_DBG_NIC_RX, "Number of MC entries = %d, Promiscuous = %d, All Multicast = %d.\n",
- mc_count, !!(netdev->flags & IFF_PROMISC),
- !!(netdev->flags & IFF_ALLMULTI));
- if (!mc_all_on) {
- char *addrs;
- int i;
- struct netdev_hw_addr *ha;
-
- addrs = kmalloc_array(mc_count, ETH_ALEN, GFP_ATOMIC);
- if (!addrs) {
- set_allmulti(nesdev, nic_active_bit);
- goto unlock;
- }
- i = 0;
- netdev_for_each_mc_addr(ha, netdev)
- memcpy(get_addr(addrs, i++), ha->addr, ETH_ALEN);
-
- perfect_filter_register_address = NES_IDX_PERFECT_FILTER_LOW +
- pft_entries_preallocated * 0x8;
- for (i = 0, mc_index = 0; mc_index < max_pft_entries_avaiable;
- mc_index++) {
- while (i < mc_count && nesvnic->mcrq_mcast_filter &&
- ((mc_nic_index = nesvnic->mcrq_mcast_filter(nesvnic,
- get_addr(addrs, i++))) == 0));
- if (mc_nic_index < 0)
- mc_nic_index = nesvnic->nic_index;
- while (nesadapter->pft_mcast_map[mc_index] < 16 &&
- nesadapter->pft_mcast_map[mc_index] !=
- nesvnic->nic_index &&
- mc_index < max_pft_entries_avaiable) {
- nes_debug(NES_DBG_NIC_RX,
- "mc_index=%d skipping nic_index=%d, used for=%d\n",
- mc_index, nesvnic->nic_index,
- nesadapter->pft_mcast_map[mc_index]);
- mc_index++;
- }
- if (mc_index >= max_pft_entries_avaiable)
- break;
- if (i < mc_count) {
- char *addr = get_addr(addrs, i++);
-
- nes_debug(NES_DBG_NIC_RX, "Assigning MC Address %pM to register 0x%04X nic_idx=%d\n",
- addr,
- perfect_filter_register_address+(mc_index * 8),
- mc_nic_index);
- macaddr_high = ((u8) addr[0]) << 8;
- macaddr_high += (u8) addr[1];
- macaddr_low = ((u8) addr[2]) << 24;
- macaddr_low += ((u8) addr[3]) << 16;
- macaddr_low += ((u8) addr[4]) << 8;
- macaddr_low += (u8) addr[5];
-
- nes_write_indexed(nesdev,
- perfect_filter_register_address+(mc_index * 8),
- macaddr_low);
- nes_write_indexed(nesdev,
- perfect_filter_register_address+4+(mc_index * 8),
- (u32)macaddr_high | NES_MAC_ADDR_VALID |
- ((((u32)(1<<mc_nic_index)) << 16)));
- nesadapter->pft_mcast_map[mc_index] =
- nesvnic->nic_index;
- } else {
- nes_debug(NES_DBG_NIC_RX, "Clearing MC Address at register 0x%04X\n",
- perfect_filter_register_address+(mc_index * 8));
- nes_write_indexed(nesdev,
- perfect_filter_register_address+4+(mc_index * 8),
- 0);
- nesadapter->pft_mcast_map[mc_index] = 255;
- }
- }
- kfree(addrs);
- /* PFT is not large enough */
- if (i < mc_count)
- set_allmulti(nesdev, nic_active_bit);
- }
-
-unlock:
- spin_unlock_irqrestore(&nesadapter->resource_lock, flags);
-}
-
-
-/**
- * nes_netdev_change_mtu
- */
-static int nes_netdev_change_mtu(struct net_device *netdev, int new_mtu)
-{
- struct nes_vnic *nesvnic = netdev_priv(netdev);
- struct nes_device *nesdev = nesvnic->nesdev;
- u8 jumbomode = 0;
- u32 nic_active;
- u32 nic_active_bit;
- u32 uc_all_active;
- u32 mc_all_active;
-
- netdev->mtu = new_mtu;
- nesvnic->max_frame_size = new_mtu + VLAN_ETH_HLEN;
-
- if (netdev->mtu > ETH_DATA_LEN) {
- jumbomode=1;
- }
- nes_nic_init_timer_defaults(nesdev, jumbomode);
-
- if (netif_running(netdev)) {
- nic_active_bit = 1 << nesvnic->nic_index;
- mc_all_active = nes_read_indexed(nesdev,
- NES_IDX_NIC_MULTICAST_ALL) & nic_active_bit;
- uc_all_active = nes_read_indexed(nesdev,
- NES_IDX_NIC_UNICAST_ALL) & nic_active_bit;
-
- nes_netdev_stop(netdev);
- nes_netdev_open(netdev);
-
- nic_active = nes_read_indexed(nesdev,
- NES_IDX_NIC_MULTICAST_ALL);
- nic_active |= mc_all_active;
- nes_write_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL,
- nic_active);
-
- nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL);
- nic_active |= uc_all_active;
- nes_write_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL, nic_active);
- }
-
- return 0;
-}
-
-
-static const char nes_ethtool_stringset[][ETH_GSTRING_LEN] = {
- "Link Change Interrupts",
- "Linearized SKBs",
- "T/GSO Requests",
- "Pause Frames Sent",
- "Pause Frames Received",
- "Internal Routing Errors",
- "SQ SW Dropped SKBs",
- "SQ Full",
- "Segmented TSO Requests",
- "Rx Symbol Errors",
- "Rx Jabber Errors",
- "Rx Oversized Frames",
- "Rx Short Frames",
- "Rx Length Errors",
- "Rx CRC Errors",
- "Rx Port Discard",
- "Endnode Rx Discards",
- "Endnode Rx Octets",
- "Endnode Rx Frames",
- "Endnode Tx Octets",
- "Endnode Tx Frames",
- "Tx Errors",
- "mh detected",
- "mh pauses",
- "Retransmission Count",
- "CM Connects",
- "CM Accepts",
- "Disconnects",
- "Connected Events",
- "Connect Requests",
- "CM Rejects",
- "ModifyQP Timeouts",
- "CreateQPs",
- "SW DestroyQPs",
- "DestroyQPs",
- "CM Closes",
- "CM Packets Sent",
- "CM Packets Bounced",
- "CM Packets Created",
- "CM Packets Rcvd",
- "CM Packets Dropped",
- "CM Packets Retrans",
- "CM Listens Created",
- "CM Listens Destroyed",
- "CM Backlog Drops",
- "CM Loopbacks",
- "CM Nodes Created",
- "CM Nodes Destroyed",
- "CM Accel Drops",
- "CM Resets Received",
- "Free 4Kpbls",
- "Free 256pbls",
- "Timer Inits",
- "PAU CreateQPs",
- "PAU DestroyQPs",
-};
-#define NES_ETHTOOL_STAT_COUNT ARRAY_SIZE(nes_ethtool_stringset)
-
-
-/**
- * nes_netdev_get_sset_count
- */
-static int nes_netdev_get_sset_count(struct net_device *netdev, int stringset)
-{
- if (stringset == ETH_SS_STATS)
- return NES_ETHTOOL_STAT_COUNT;
- else
- return -EINVAL;
-}
-
-
-/**
- * nes_netdev_get_strings
- */
-static void nes_netdev_get_strings(struct net_device *netdev, u32 stringset,
- u8 *ethtool_strings)
-{
- if (stringset == ETH_SS_STATS)
- memcpy(ethtool_strings,
- &nes_ethtool_stringset,
- sizeof(nes_ethtool_stringset));
-}
-
-
-/**
- * nes_netdev_get_ethtool_stats
- */
-
-static void nes_netdev_get_ethtool_stats(struct net_device *netdev,
- struct ethtool_stats *target_ethtool_stats, u64 *target_stat_values)
-{
- u64 u64temp;
- struct nes_vnic *nesvnic = netdev_priv(netdev);
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- u32 nic_count;
- u32 u32temp;
- u32 index = 0;
-
- target_ethtool_stats->n_stats = NES_ETHTOOL_STAT_COUNT;
- target_stat_values[index] = nesvnic->nesdev->link_status_interrupts;
- target_stat_values[++index] = nesvnic->linearized_skbs;
- target_stat_values[++index] = nesvnic->tso_requests;
-
- u32temp = nes_read_indexed(nesdev,
- NES_IDX_MAC_TX_PAUSE_FRAMES + (nesvnic->nesdev->mac_index*0x200));
- nesvnic->nesdev->mac_pause_frames_sent += u32temp;
- target_stat_values[++index] = nesvnic->nesdev->mac_pause_frames_sent;
-
- u32temp = nes_read_indexed(nesdev,
- NES_IDX_MAC_RX_PAUSE_FRAMES + (nesvnic->nesdev->mac_index*0x200));
- nesvnic->nesdev->mac_pause_frames_received += u32temp;
-
- u32temp = nes_read_indexed(nesdev,
- NES_IDX_PORT_RX_DISCARDS + (nesvnic->nesdev->mac_index*0x40));
- nesvnic->nesdev->port_rx_discards += u32temp;
- nesvnic->netstats.rx_dropped += u32temp;
-
- u32temp = nes_read_indexed(nesdev,
- NES_IDX_PORT_TX_DISCARDS + (nesvnic->nesdev->mac_index*0x40));
- nesvnic->nesdev->port_tx_discards += u32temp;
- nesvnic->netstats.tx_dropped += u32temp;
-
- u32temp = nes_read_indexed(nesdev,
- NES_IDX_MAC_RX_SHORT_FRAMES + (nesvnic->nesdev->mac_index*0x200));
- nesvnic->netstats.rx_dropped += u32temp;
- nesvnic->nesdev->mac_rx_errors += u32temp;
- nesvnic->nesdev->mac_rx_short_frames += u32temp;
-
- u32temp = nes_read_indexed(nesdev,
- NES_IDX_MAC_RX_OVERSIZED_FRAMES + (nesvnic->nesdev->mac_index*0x200));
- nesvnic->netstats.rx_dropped += u32temp;
- nesvnic->nesdev->mac_rx_errors += u32temp;
- nesvnic->nesdev->mac_rx_oversized_frames += u32temp;
-
- u32temp = nes_read_indexed(nesdev,
- NES_IDX_MAC_RX_JABBER_FRAMES + (nesvnic->nesdev->mac_index*0x200));
- nesvnic->netstats.rx_dropped += u32temp;
- nesvnic->nesdev->mac_rx_errors += u32temp;
- nesvnic->nesdev->mac_rx_jabber_frames += u32temp;
-
- u32temp = nes_read_indexed(nesdev,
- NES_IDX_MAC_RX_SYMBOL_ERR_FRAMES + (nesvnic->nesdev->mac_index*0x200));
- nesvnic->netstats.rx_dropped += u32temp;
- nesvnic->nesdev->mac_rx_errors += u32temp;
- nesvnic->nesdev->mac_rx_symbol_err_frames += u32temp;
-
- u32temp = nes_read_indexed(nesdev,
- NES_IDX_MAC_RX_LENGTH_ERR_FRAMES + (nesvnic->nesdev->mac_index*0x200));
- nesvnic->netstats.rx_length_errors += u32temp;
- nesvnic->nesdev->mac_rx_errors += u32temp;
-
- u32temp = nes_read_indexed(nesdev,
- NES_IDX_MAC_RX_CRC_ERR_FRAMES + (nesvnic->nesdev->mac_index*0x200));
- nesvnic->nesdev->mac_rx_errors += u32temp;
- nesvnic->nesdev->mac_rx_crc_errors += u32temp;
- nesvnic->netstats.rx_crc_errors += u32temp;
-
- u32temp = nes_read_indexed(nesdev,
- NES_IDX_MAC_TX_ERRORS + (nesvnic->nesdev->mac_index*0x200));
- nesvnic->nesdev->mac_tx_errors += u32temp;
- nesvnic->netstats.tx_errors += u32temp;
-
- for (nic_count = 0; nic_count < NES_MAX_PORT_COUNT; nic_count++) {
- if (nesvnic->qp_nic_index[nic_count] == 0xf)
- break;
-
- u32temp = nes_read_indexed(nesdev,
- NES_IDX_ENDNODE0_NSTAT_RX_DISCARD +
- (nesvnic->qp_nic_index[nic_count]*0x200));
- nesvnic->netstats.rx_dropped += u32temp;
- nesvnic->endnode_nstat_rx_discard += u32temp;
-
- u64temp = (u64)nes_read_indexed(nesdev,
- NES_IDX_ENDNODE0_NSTAT_RX_OCTETS_LO +
- (nesvnic->qp_nic_index[nic_count]*0x200));
- u64temp += ((u64)nes_read_indexed(nesdev,
- NES_IDX_ENDNODE0_NSTAT_RX_OCTETS_HI +
- (nesvnic->qp_nic_index[nic_count]*0x200))) << 32;
-
- nesvnic->endnode_nstat_rx_octets += u64temp;
- nesvnic->netstats.rx_bytes += u64temp;
-
- u64temp = (u64)nes_read_indexed(nesdev,
- NES_IDX_ENDNODE0_NSTAT_RX_FRAMES_LO +
- (nesvnic->qp_nic_index[nic_count]*0x200));
- u64temp += ((u64)nes_read_indexed(nesdev,
- NES_IDX_ENDNODE0_NSTAT_RX_FRAMES_HI +
- (nesvnic->qp_nic_index[nic_count]*0x200))) << 32;
-
- nesvnic->endnode_nstat_rx_frames += u64temp;
- nesvnic->netstats.rx_packets += u64temp;
-
- u64temp = (u64)nes_read_indexed(nesdev,
- NES_IDX_ENDNODE0_NSTAT_TX_OCTETS_LO +
- (nesvnic->qp_nic_index[nic_count]*0x200));
- u64temp += ((u64)nes_read_indexed(nesdev,
- NES_IDX_ENDNODE0_NSTAT_TX_OCTETS_HI +
- (nesvnic->qp_nic_index[nic_count]*0x200))) << 32;
-
- nesvnic->endnode_nstat_tx_octets += u64temp;
- nesvnic->netstats.tx_bytes += u64temp;
-
- u64temp = (u64)nes_read_indexed(nesdev,
- NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_LO +
- (nesvnic->qp_nic_index[nic_count]*0x200));
- u64temp += ((u64)nes_read_indexed(nesdev,
- NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_HI +
- (nesvnic->qp_nic_index[nic_count]*0x200))) << 32;
-
- nesvnic->endnode_nstat_tx_frames += u64temp;
- nesvnic->netstats.tx_packets += u64temp;
-
- u32temp = nes_read_indexed(nesdev,
- NES_IDX_IPV4_TCP_REXMITS + (nesvnic->qp_nic_index[nic_count]*0x200));
- nesvnic->endnode_ipv4_tcp_retransmits += u32temp;
- }
-
- target_stat_values[++index] = nesvnic->nesdev->mac_pause_frames_received;
- target_stat_values[++index] = nesdev->nesadapter->nic_rx_eth_route_err;
- target_stat_values[++index] = nesvnic->tx_sw_dropped;
- target_stat_values[++index] = nesvnic->sq_full;
- target_stat_values[++index] = nesvnic->segmented_tso_requests;
- target_stat_values[++index] = nesvnic->nesdev->mac_rx_symbol_err_frames;
- target_stat_values[++index] = nesvnic->nesdev->mac_rx_jabber_frames;
- target_stat_values[++index] = nesvnic->nesdev->mac_rx_oversized_frames;
- target_stat_values[++index] = nesvnic->nesdev->mac_rx_short_frames;
- target_stat_values[++index] = nesvnic->netstats.rx_length_errors;
- target_stat_values[++index] = nesvnic->nesdev->mac_rx_crc_errors;
- target_stat_values[++index] = nesvnic->nesdev->port_rx_discards;
- target_stat_values[++index] = nesvnic->endnode_nstat_rx_discard;
- target_stat_values[++index] = nesvnic->endnode_nstat_rx_octets;
- target_stat_values[++index] = nesvnic->endnode_nstat_rx_frames;
- target_stat_values[++index] = nesvnic->endnode_nstat_tx_octets;
- target_stat_values[++index] = nesvnic->endnode_nstat_tx_frames;
- target_stat_values[++index] = nesvnic->nesdev->mac_tx_errors;
- target_stat_values[++index] = mh_detected;
- target_stat_values[++index] = mh_pauses_sent;
- target_stat_values[++index] = nesvnic->endnode_ipv4_tcp_retransmits;
- target_stat_values[++index] = atomic_read(&cm_connects);
- target_stat_values[++index] = atomic_read(&cm_accepts);
- target_stat_values[++index] = atomic_read(&cm_disconnects);
- target_stat_values[++index] = atomic_read(&cm_connecteds);
- target_stat_values[++index] = atomic_read(&cm_connect_reqs);
- target_stat_values[++index] = atomic_read(&cm_rejects);
- target_stat_values[++index] = atomic_read(&mod_qp_timouts);
- target_stat_values[++index] = atomic_read(&qps_created);
- target_stat_values[++index] = atomic_read(&sw_qps_destroyed);
- target_stat_values[++index] = atomic_read(&qps_destroyed);
- target_stat_values[++index] = atomic_read(&cm_closes);
- target_stat_values[++index] = cm_packets_sent;
- target_stat_values[++index] = cm_packets_bounced;
- target_stat_values[++index] = cm_packets_created;
- target_stat_values[++index] = cm_packets_received;
- target_stat_values[++index] = cm_packets_dropped;
- target_stat_values[++index] = cm_packets_retrans;
- target_stat_values[++index] = atomic_read(&cm_listens_created);
- target_stat_values[++index] = atomic_read(&cm_listens_destroyed);
- target_stat_values[++index] = cm_backlog_drops;
- target_stat_values[++index] = atomic_read(&cm_loopbacks);
- target_stat_values[++index] = atomic_read(&cm_nodes_created);
- target_stat_values[++index] = atomic_read(&cm_nodes_destroyed);
- target_stat_values[++index] = atomic_read(&cm_accel_dropped_pkts);
- target_stat_values[++index] = atomic_read(&cm_resets_recvd);
- target_stat_values[++index] = nesadapter->free_4kpbl;
- target_stat_values[++index] = nesadapter->free_256pbl;
- target_stat_values[++index] = int_mod_timer_init;
- target_stat_values[++index] = atomic_read(&pau_qps_created);
- target_stat_values[++index] = atomic_read(&pau_qps_destroyed);
-}
-
-/**
- * nes_netdev_get_drvinfo
- */
-static void nes_netdev_get_drvinfo(struct net_device *netdev,
- struct ethtool_drvinfo *drvinfo)
-{
- struct nes_vnic *nesvnic = netdev_priv(netdev);
- struct nes_adapter *nesadapter = nesvnic->nesdev->nesadapter;
-
- strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
- strlcpy(drvinfo->bus_info, pci_name(nesvnic->nesdev->pcidev),
- sizeof(drvinfo->bus_info));
- snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
- "%u.%u", nesadapter->firmware_version >> 16,
- nesadapter->firmware_version & 0x000000ff);
- strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
-}
-
-
-/**
- * nes_netdev_set_coalesce
- */
-static int nes_netdev_set_coalesce(struct net_device *netdev,
- struct ethtool_coalesce *et_coalesce)
-{
- struct nes_vnic *nesvnic = netdev_priv(netdev);
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer;
- unsigned long flags;
-
- spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags);
- if (et_coalesce->rx_max_coalesced_frames_low) {
- shared_timer->threshold_low = et_coalesce->rx_max_coalesced_frames_low;
- }
- if (et_coalesce->rx_max_coalesced_frames_irq) {
- shared_timer->threshold_target = et_coalesce->rx_max_coalesced_frames_irq;
- }
- if (et_coalesce->rx_max_coalesced_frames_high) {
- shared_timer->threshold_high = et_coalesce->rx_max_coalesced_frames_high;
- }
- if (et_coalesce->rx_coalesce_usecs_low) {
- shared_timer->timer_in_use_min = et_coalesce->rx_coalesce_usecs_low;
- }
- if (et_coalesce->rx_coalesce_usecs_high) {
- shared_timer->timer_in_use_max = et_coalesce->rx_coalesce_usecs_high;
- }
- spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags);
-
- /* using this to drive total interrupt moderation */
- nesadapter->et_rx_coalesce_usecs_irq = et_coalesce->rx_coalesce_usecs_irq;
- if (et_coalesce->use_adaptive_rx_coalesce) {
- nesadapter->et_use_adaptive_rx_coalesce = 1;
- nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT_DYNAMIC;
- nesadapter->et_rx_coalesce_usecs_irq = 0;
- if (et_coalesce->pkt_rate_low) {
- nesadapter->et_pkt_rate_low = et_coalesce->pkt_rate_low;
- }
- } else {
- nesadapter->et_use_adaptive_rx_coalesce = 0;
- nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT;
- if (nesadapter->et_rx_coalesce_usecs_irq) {
- nes_write32(nesdev->regs+NES_PERIODIC_CONTROL,
- 0x80000000 | ((u32)(nesadapter->et_rx_coalesce_usecs_irq*8)));
- }
- }
- return 0;
-}
-
-
-/**
- * nes_netdev_get_coalesce
- */
-static int nes_netdev_get_coalesce(struct net_device *netdev,
- struct ethtool_coalesce *et_coalesce)
-{
- struct nes_vnic *nesvnic = netdev_priv(netdev);
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- struct ethtool_coalesce temp_et_coalesce;
- struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer;
- unsigned long flags;
-
- memset(&temp_et_coalesce, 0, sizeof(temp_et_coalesce));
- temp_et_coalesce.rx_coalesce_usecs_irq = nesadapter->et_rx_coalesce_usecs_irq;
- temp_et_coalesce.use_adaptive_rx_coalesce = nesadapter->et_use_adaptive_rx_coalesce;
- temp_et_coalesce.rate_sample_interval = nesadapter->et_rate_sample_interval;
- temp_et_coalesce.pkt_rate_low = nesadapter->et_pkt_rate_low;
- spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags);
- temp_et_coalesce.rx_max_coalesced_frames_low = shared_timer->threshold_low;
- temp_et_coalesce.rx_max_coalesced_frames_irq = shared_timer->threshold_target;
- temp_et_coalesce.rx_max_coalesced_frames_high = shared_timer->threshold_high;
- temp_et_coalesce.rx_coalesce_usecs_low = shared_timer->timer_in_use_min;
- temp_et_coalesce.rx_coalesce_usecs_high = shared_timer->timer_in_use_max;
- if (nesadapter->et_use_adaptive_rx_coalesce) {
- temp_et_coalesce.rx_coalesce_usecs_irq = shared_timer->timer_in_use;
- }
- spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags);
- memcpy(et_coalesce, &temp_et_coalesce, sizeof(*et_coalesce));
- return 0;
-}
-
-
-/**
- * nes_netdev_get_pauseparam
- */
-static void nes_netdev_get_pauseparam(struct net_device *netdev,
- struct ethtool_pauseparam *et_pauseparam)
-{
- struct nes_vnic *nesvnic = netdev_priv(netdev);
-
- et_pauseparam->autoneg = 0;
- et_pauseparam->rx_pause = (nesvnic->nesdev->disable_rx_flow_control == 0) ? 1:0;
- et_pauseparam->tx_pause = (nesvnic->nesdev->disable_tx_flow_control == 0) ? 1:0;
-}
-
-
-/**
- * nes_netdev_set_pauseparam
- */
-static int nes_netdev_set_pauseparam(struct net_device *netdev,
- struct ethtool_pauseparam *et_pauseparam)
-{
- struct nes_vnic *nesvnic = netdev_priv(netdev);
- struct nes_device *nesdev = nesvnic->nesdev;
- u32 u32temp;
-
- if (et_pauseparam->autoneg) {
- /* TODO: should return unsupported */
- return 0;
- }
- if ((et_pauseparam->tx_pause == 1) && (nesdev->disable_tx_flow_control == 1)) {
- u32temp = nes_read_indexed(nesdev,
- NES_IDX_MAC_TX_CONFIG + (nesdev->mac_index*0x200));
- u32temp |= NES_IDX_MAC_TX_CONFIG_ENABLE_PAUSE;
- nes_write_indexed(nesdev,
- NES_IDX_MAC_TX_CONFIG + (nesdev->mac_index*0x200), u32temp);
- nesdev->disable_tx_flow_control = 0;
- } else if ((et_pauseparam->tx_pause == 0) && (nesdev->disable_tx_flow_control == 0)) {
- u32temp = nes_read_indexed(nesdev,
- NES_IDX_MAC_TX_CONFIG + (nesdev->mac_index*0x200));
- u32temp &= ~NES_IDX_MAC_TX_CONFIG_ENABLE_PAUSE;
- nes_write_indexed(nesdev,
- NES_IDX_MAC_TX_CONFIG + (nesdev->mac_index*0x200), u32temp);
- nesdev->disable_tx_flow_control = 1;
- }
- if ((et_pauseparam->rx_pause == 1) && (nesdev->disable_rx_flow_control == 1)) {
- u32temp = nes_read_indexed(nesdev,
- NES_IDX_MPP_DEBUG + (nesdev->mac_index*0x40));
- u32temp &= ~NES_IDX_MPP_DEBUG_PORT_DISABLE_PAUSE;
- nes_write_indexed(nesdev,
- NES_IDX_MPP_DEBUG + (nesdev->mac_index*0x40), u32temp);
- nesdev->disable_rx_flow_control = 0;
- } else if ((et_pauseparam->rx_pause == 0) && (nesdev->disable_rx_flow_control == 0)) {
- u32temp = nes_read_indexed(nesdev,
- NES_IDX_MPP_DEBUG + (nesdev->mac_index*0x40));
- u32temp |= NES_IDX_MPP_DEBUG_PORT_DISABLE_PAUSE;
- nes_write_indexed(nesdev,
- NES_IDX_MPP_DEBUG + (nesdev->mac_index*0x40), u32temp);
- nesdev->disable_rx_flow_control = 1;
- }
-
- return 0;
-}
-
-
-/**
- * nes_netdev_get_settings
- */
-static int nes_netdev_get_link_ksettings(struct net_device *netdev,
- struct ethtool_link_ksettings *cmd)
-{
- struct nes_vnic *nesvnic = netdev_priv(netdev);
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- u32 mac_index = nesdev->mac_index;
- u8 phy_type = nesadapter->phy_type[mac_index];
- u8 phy_index = nesadapter->phy_index[mac_index];
- u16 phy_data;
- u32 supported, advertising;
-
- cmd->base.duplex = DUPLEX_FULL;
- cmd->base.port = PORT_MII;
-
- if (nesadapter->OneG_Mode) {
- cmd->base.speed = SPEED_1000;
- if (phy_type == NES_PHY_TYPE_PUMA_1G) {
- supported = SUPPORTED_1000baseT_Full;
- advertising = ADVERTISED_1000baseT_Full;
- cmd->base.autoneg = AUTONEG_DISABLE;
- cmd->base.phy_address = mac_index;
- } else {
- unsigned long flags;
-
- supported = SUPPORTED_1000baseT_Full
- | SUPPORTED_Autoneg;
- advertising = ADVERTISED_1000baseT_Full
- | ADVERTISED_Autoneg;
- spin_lock_irqsave(&nesadapter->phy_lock, flags);
- nes_read_1G_phy_reg(nesdev, 0, phy_index, &phy_data);
- spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
- if (phy_data & 0x1000)
- cmd->base.autoneg = AUTONEG_ENABLE;
- else
- cmd->base.autoneg = AUTONEG_DISABLE;
- cmd->base.phy_address = phy_index;
- }
- ethtool_convert_legacy_u32_to_link_mode(
- cmd->link_modes.supported, supported);
- ethtool_convert_legacy_u32_to_link_mode(
- cmd->link_modes.advertising, advertising);
- return 0;
- }
- if ((phy_type == NES_PHY_TYPE_ARGUS) ||
- (phy_type == NES_PHY_TYPE_SFP_D) ||
- (phy_type == NES_PHY_TYPE_KR)) {
- cmd->base.port = PORT_FIBRE;
- supported = SUPPORTED_FIBRE;
- advertising = ADVERTISED_FIBRE;
- cmd->base.phy_address = phy_index;
- } else {
- supported = SUPPORTED_10000baseT_Full;
- advertising = ADVERTISED_10000baseT_Full;
- cmd->base.phy_address = mac_index;
- }
- cmd->base.speed = SPEED_10000;
- cmd->base.autoneg = AUTONEG_DISABLE;
- ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
- supported);
- ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
- advertising);
-
- return 0;
-}
-
-
-/**
- * nes_netdev_set_settings
- */
-static int
-nes_netdev_set_link_ksettings(struct net_device *netdev,
- const struct ethtool_link_ksettings *cmd)
-{
- struct nes_vnic *nesvnic = netdev_priv(netdev);
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_adapter *nesadapter = nesdev->nesadapter;
-
- if ((nesadapter->OneG_Mode) &&
- (nesadapter->phy_type[nesdev->mac_index] != NES_PHY_TYPE_PUMA_1G)) {
- unsigned long flags;
- u16 phy_data;
- u8 phy_index = nesadapter->phy_index[nesdev->mac_index];
-
- spin_lock_irqsave(&nesadapter->phy_lock, flags);
- nes_read_1G_phy_reg(nesdev, 0, phy_index, &phy_data);
- if (cmd->base.autoneg) {
- /* Turn on Full duplex, Autoneg, and restart autonegotiation */
- phy_data |= 0x1300;
- } else {
- /* Turn off autoneg */
- phy_data &= ~0x1000;
- }
- nes_write_1G_phy_reg(nesdev, 0, phy_index, phy_data);
- spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
- }
-
- return 0;
-}
-
-
-static const struct ethtool_ops nes_ethtool_ops = {
- .get_link = ethtool_op_get_link,
- .get_strings = nes_netdev_get_strings,
- .get_sset_count = nes_netdev_get_sset_count,
- .get_ethtool_stats = nes_netdev_get_ethtool_stats,
- .get_drvinfo = nes_netdev_get_drvinfo,
- .get_coalesce = nes_netdev_get_coalesce,
- .set_coalesce = nes_netdev_set_coalesce,
- .get_pauseparam = nes_netdev_get_pauseparam,
- .set_pauseparam = nes_netdev_set_pauseparam,
- .get_link_ksettings = nes_netdev_get_link_ksettings,
- .set_link_ksettings = nes_netdev_set_link_ksettings,
-};
-
-static void nes_vlan_mode(struct net_device *netdev, struct nes_device *nesdev, netdev_features_t features)
-{
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- u32 u32temp;
- unsigned long flags;
-
- spin_lock_irqsave(&nesadapter->phy_lock, flags);
-
- nes_debug(NES_DBG_NETDEV, "%s: %s\n", __func__, netdev->name);
-
- /* Enable/Disable VLAN Stripping */
- u32temp = nes_read_indexed(nesdev, NES_IDX_PCIX_DIAG);
- if (features & NETIF_F_HW_VLAN_CTAG_RX)
- u32temp &= 0xfdffffff;
- else
- u32temp |= 0x02000000;
-
- nes_write_indexed(nesdev, NES_IDX_PCIX_DIAG, u32temp);
- spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
-}
-
-static netdev_features_t nes_fix_features(struct net_device *netdev, netdev_features_t features)
-{
- /*
- * Since there is no support for separate rx/tx vlan accel
- * enable/disable make sure tx flag is always in same state as rx.
- */
- if (features & NETIF_F_HW_VLAN_CTAG_RX)
- features |= NETIF_F_HW_VLAN_CTAG_TX;
- else
- features &= ~NETIF_F_HW_VLAN_CTAG_TX;
-
- return features;
-}
-
-static int nes_set_features(struct net_device *netdev, netdev_features_t features)
-{
- struct nes_vnic *nesvnic = netdev_priv(netdev);
- struct nes_device *nesdev = nesvnic->nesdev;
- u32 changed = netdev->features ^ features;
-
- if (changed & NETIF_F_HW_VLAN_CTAG_RX)
- nes_vlan_mode(netdev, nesdev, features);
-
- return 0;
-}
-
-static const struct net_device_ops nes_netdev_ops = {
- .ndo_open = nes_netdev_open,
- .ndo_stop = nes_netdev_stop,
- .ndo_start_xmit = nes_netdev_start_xmit,
- .ndo_get_stats = nes_netdev_get_stats,
- .ndo_tx_timeout = nes_netdev_tx_timeout,
- .ndo_set_mac_address = nes_netdev_set_mac_address,
- .ndo_set_rx_mode = nes_netdev_set_multicast_list,
- .ndo_change_mtu = nes_netdev_change_mtu,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_fix_features = nes_fix_features,
- .ndo_set_features = nes_set_features,
-};
-
-/**
- * nes_netdev_init - initialize network device
- */
-struct net_device *nes_netdev_init(struct nes_device *nesdev,
- void __iomem *mmio_addr)
-{
- u64 u64temp;
- struct nes_vnic *nesvnic;
- struct net_device *netdev;
- struct nic_qp_map *curr_qp_map;
- u8 phy_type = nesdev->nesadapter->phy_type[nesdev->mac_index];
-
- netdev = alloc_etherdev(sizeof(struct nes_vnic));
- if (!netdev) {
- printk(KERN_ERR PFX "nesvnic etherdev alloc failed");
- return NULL;
- }
- nesvnic = netdev_priv(netdev);
-
- nes_debug(NES_DBG_INIT, "netdev = %p, %s\n", netdev, netdev->name);
-
- SET_NETDEV_DEV(netdev, &nesdev->pcidev->dev);
-
- netdev->watchdog_timeo = NES_TX_TIMEOUT;
- netdev->irq = nesdev->pcidev->irq;
- netdev->max_mtu = NES_MAX_MTU;
- netdev->hard_header_len = ETH_HLEN;
- netdev->addr_len = ETH_ALEN;
- netdev->type = ARPHRD_ETHER;
- netdev->netdev_ops = &nes_netdev_ops;
- netdev->ethtool_ops = &nes_ethtool_ops;
- netif_napi_add(netdev, &nesvnic->napi, nes_netdev_poll, 128);
- nes_debug(NES_DBG_INIT, "Enabling VLAN Insert/Delete.\n");
-
- /* Fill in the port structure */
- nesvnic->netdev = netdev;
- nesvnic->nesdev = nesdev;
- nesvnic->msg_enable = netif_msg_init(debug, default_msg);
- nesvnic->netdev_index = nesdev->netdev_count;
- nesvnic->perfect_filter_index = nesdev->nesadapter->netdev_count;
- nesvnic->max_frame_size = netdev->mtu + netdev->hard_header_len + VLAN_HLEN;
-
- curr_qp_map = nic_qp_mapping_per_function[PCI_FUNC(nesdev->pcidev->devfn)];
- nesvnic->nic.qp_id = curr_qp_map[nesdev->netdev_count].qpid;
- nesvnic->nic_index = curr_qp_map[nesdev->netdev_count].nic_index;
- nesvnic->logical_port = curr_qp_map[nesdev->netdev_count].logical_port;
-
- /* Setup the burned in MAC address */
- u64temp = (u64)nesdev->nesadapter->mac_addr_low;
- u64temp += ((u64)nesdev->nesadapter->mac_addr_high) << 32;
- u64temp += nesvnic->nic_index;
- netdev->dev_addr[0] = (u8)(u64temp>>40);
- netdev->dev_addr[1] = (u8)(u64temp>>32);
- netdev->dev_addr[2] = (u8)(u64temp>>24);
- netdev->dev_addr[3] = (u8)(u64temp>>16);
- netdev->dev_addr[4] = (u8)(u64temp>>8);
- netdev->dev_addr[5] = (u8)u64temp;
-
- netdev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM | NETIF_F_HW_VLAN_CTAG_RX;
- if ((nesvnic->logical_port < 2) || (nesdev->nesadapter->hw_rev != NE020_REV))
- netdev->hw_features |= NETIF_F_TSO;
-
- netdev->features = netdev->hw_features | NETIF_F_HIGHDMA | NETIF_F_HW_VLAN_CTAG_TX;
-
- nes_debug(NES_DBG_INIT, "nesvnic = %p, reported features = 0x%lX, QPid = %d,"
- " nic_index = %d, logical_port = %d, mac_index = %d.\n",
- nesvnic, (unsigned long)netdev->features, nesvnic->nic.qp_id,
- nesvnic->nic_index, nesvnic->logical_port, nesdev->mac_index);
-
- if (nesvnic->nesdev->nesadapter->port_count == 1 &&
- nesvnic->nesdev->nesadapter->adapter_fcn_count == 1) {
-
- nesvnic->qp_nic_index[0] = nesvnic->nic_index;
- nesvnic->qp_nic_index[1] = nesvnic->nic_index + 1;
- if (nes_drv_opt & NES_DRV_OPT_DUAL_LOGICAL_PORT) {
- nesvnic->qp_nic_index[2] = 0xf;
- nesvnic->qp_nic_index[3] = 0xf;
- } else {
- nesvnic->qp_nic_index[2] = nesvnic->nic_index + 2;
- nesvnic->qp_nic_index[3] = nesvnic->nic_index + 3;
- }
- } else {
- if (nesvnic->nesdev->nesadapter->port_count == 2 ||
- (nesvnic->nesdev->nesadapter->port_count == 1 &&
- nesvnic->nesdev->nesadapter->adapter_fcn_count == 2)) {
- nesvnic->qp_nic_index[0] = nesvnic->nic_index;
- nesvnic->qp_nic_index[1] = nesvnic->nic_index
- + 2;
- nesvnic->qp_nic_index[2] = 0xf;
- nesvnic->qp_nic_index[3] = 0xf;
- } else {
- nesvnic->qp_nic_index[0] = nesvnic->nic_index;
- nesvnic->qp_nic_index[1] = 0xf;
- nesvnic->qp_nic_index[2] = 0xf;
- nesvnic->qp_nic_index[3] = 0xf;
- }
- }
- nesvnic->next_qp_nic_index = 0;
-
- if (nesdev->netdev_count == 0) {
- nesvnic->rdma_enabled = 1;
- } else {
- nesvnic->rdma_enabled = 0;
- }
- nesvnic->nic_cq.cq_number = nesvnic->nic.qp_id;
- timer_setup(&nesvnic->event_timer, NULL, 0);
- spin_lock_init(&nesvnic->tx_lock);
- spin_lock_init(&nesvnic->port_ibevent_lock);
- nesdev->netdev[nesdev->netdev_count] = netdev;
-
- nes_debug(NES_DBG_INIT, "Adding nesvnic (%p) to the adapters nesvnic_list for MAC%d.\n",
- nesvnic, nesdev->mac_index);
- list_add_tail(&nesvnic->list, &nesdev->nesadapter->nesvnic_list[nesdev->mac_index]);
-
- if ((nesdev->netdev_count == 0) &&
- ((PCI_FUNC(nesdev->pcidev->devfn) == nesdev->mac_index) ||
- ((phy_type == NES_PHY_TYPE_PUMA_1G) &&
- (((PCI_FUNC(nesdev->pcidev->devfn) == 1) && (nesdev->mac_index == 2)) ||
- ((PCI_FUNC(nesdev->pcidev->devfn) == 2) && (nesdev->mac_index == 1)))))) {
- u32 u32temp;
- u32 link_mask = 0;
- u32 link_val = 0;
- u16 temp_phy_data;
- u16 phy_data = 0;
- unsigned long flags;
-
- u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 +
- (0x200 * (nesdev->mac_index & 1)));
- if (phy_type != NES_PHY_TYPE_PUMA_1G) {
- u32temp |= 0x00200000;
- nes_write_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 +
- (0x200 * (nesdev->mac_index & 1)), u32temp);
- }
-
- /* Check and set linkup here. This is for back to back */
- /* configuration where second port won't get link interrupt */
- switch (phy_type) {
- case NES_PHY_TYPE_PUMA_1G:
- if (nesdev->mac_index < 2) {
- link_mask = 0x01010000;
- link_val = 0x01010000;
- } else {
- link_mask = 0x02020000;
- link_val = 0x02020000;
- }
- break;
- case NES_PHY_TYPE_SFP_D:
- spin_lock_irqsave(&nesdev->nesadapter->phy_lock, flags);
- nes_read_10G_phy_reg(nesdev,
- nesdev->nesadapter->phy_index[nesdev->mac_index],
- 1, 0x9003);
- temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
- nes_read_10G_phy_reg(nesdev,
- nesdev->nesadapter->phy_index[nesdev->mac_index],
- 3, 0x0021);
- nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
- nes_read_10G_phy_reg(nesdev,
- nesdev->nesadapter->phy_index[nesdev->mac_index],
- 3, 0x0021);
- phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
- spin_unlock_irqrestore(&nesdev->nesadapter->phy_lock, flags);
- phy_data = (!temp_phy_data && (phy_data == 0x8000)) ? 0x4 : 0x0;
- break;
- default:
- link_mask = 0x0f1f0000;
- link_val = 0x0f0f0000;
- break;
- }
-
- u32temp = nes_read_indexed(nesdev,
- NES_IDX_PHY_PCS_CONTROL_STATUS0 +
- (0x200 * (nesdev->mac_index & 1)));
-
- if (phy_type == NES_PHY_TYPE_SFP_D) {
- if (phy_data & 0x0004)
- nesvnic->linkup = 1;
- } else {
- if ((u32temp & link_mask) == link_val)
- nesvnic->linkup = 1;
- }
-
- /* clear the MAC interrupt status, assumes direct logical to physical mapping */
- u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (0x200 * nesdev->mac_index));
- nes_debug(NES_DBG_INIT, "Phy interrupt status = 0x%X.\n", u32temp);
- nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (0x200 * nesdev->mac_index), u32temp);
-
- nes_init_phy(nesdev);
- }
-
- nes_vlan_mode(netdev, nesdev, netdev->features);
-
- return netdev;
-}
-
-
-/**
- * nes_netdev_destroy - destroy network device structure
- */
-void nes_netdev_destroy(struct net_device *netdev)
-{
- struct nes_vnic *nesvnic = netdev_priv(netdev);
-
- /* make sure 'stop' method is called by Linux stack */
- /* nes_netdev_stop(netdev); */
-
- list_del(&nesvnic->list);
-
- if (nesvnic->of_device_registered) {
- nes_destroy_ofa_device(nesvnic->nesibdev);
- }
-
- free_netdev(netdev);
-}
-
-
-/**
- * nes_nic_cm_xmit -- CM calls this to send out pkts
- */
-int nes_nic_cm_xmit(struct sk_buff *skb, struct net_device *netdev)
-{
- int ret;
-
- skb->dev = netdev;
- ret = dev_queue_xmit(skb);
- if (ret) {
- nes_debug(NES_DBG_CM, "Bad return code from dev_queue_xmit %d\n", ret);
- }
-
- return ret;
-}
diff --git a/drivers/infiniband/hw/nes/nes_utils.c b/drivers/infiniband/hw/nes/nes_utils.c
deleted file mode 100644
index 21b4a8373acf..000000000000
--- a/drivers/infiniband/hw/nes/nes_utils.c
+++ /dev/null
@@ -1,916 +0,0 @@
-/*
- * Copyright (c) 2006 - 2011 Intel Corporation. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/ethtool.h>
-#include <linux/mii.h>
-#include <linux/if_vlan.h>
-#include <linux/slab.h>
-#include <linux/crc32.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/byteorder.h>
-
-#include "nes.h"
-
-static u16 nes_read16_eeprom(void __iomem *addr, u16 offset);
-
-u32 mh_detected;
-u32 mh_pauses_sent;
-
-static u32 nes_set_pau(struct nes_device *nesdev)
-{
- u32 ret = 0;
- u32 counter;
-
- nes_write_indexed(nesdev, NES_IDX_GPR2, NES_ENABLE_PAU);
- nes_write_indexed(nesdev, NES_IDX_GPR_TRIGGER, 1);
-
- for (counter = 0; counter < NES_PAU_COUNTER; counter++) {
- udelay(30);
- if (!nes_read_indexed(nesdev, NES_IDX_GPR2)) {
- printk(KERN_INFO PFX "PAU is supported.\n");
- break;
- }
- nes_write_indexed(nesdev, NES_IDX_GPR_TRIGGER, 1);
- }
- if (counter == NES_PAU_COUNTER) {
- printk(KERN_INFO PFX "PAU is not supported.\n");
- return -EPERM;
- }
- return ret;
-}
-
-/**
- * nes_read_eeprom_values -
- */
-int nes_read_eeprom_values(struct nes_device *nesdev, struct nes_adapter *nesadapter)
-{
- u32 mac_addr_low;
- u16 mac_addr_high;
- u16 eeprom_data;
- u16 eeprom_offset;
- u16 next_section_address;
- u16 sw_section_ver;
- u8 major_ver = 0;
- u8 minor_ver = 0;
-
- /* TODO: deal with EEPROM endian issues */
- if (nesadapter->firmware_eeprom_offset == 0) {
- /* Read the EEPROM Parameters */
- eeprom_data = nes_read16_eeprom(nesdev->regs, 0);
- nes_debug(NES_DBG_HW, "EEPROM Offset 0 = 0x%04X\n", eeprom_data);
- eeprom_offset = 2 + (((eeprom_data & 0x007f) << 3) <<
- ((eeprom_data & 0x0080) >> 7));
- nes_debug(NES_DBG_HW, "Firmware Offset = 0x%04X\n", eeprom_offset);
- nesadapter->firmware_eeprom_offset = eeprom_offset;
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset + 4);
- if (eeprom_data != 0x5746) {
- nes_debug(NES_DBG_HW, "Not a valid Firmware Image = 0x%04X\n", eeprom_data);
- return -1;
- }
-
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset + 2);
- nes_debug(NES_DBG_HW, "EEPROM Offset %u = 0x%04X\n",
- eeprom_offset + 2, eeprom_data);
- eeprom_offset += ((eeprom_data & 0x00ff) << 3) << ((eeprom_data & 0x0100) >> 8);
- nes_debug(NES_DBG_HW, "Software Offset = 0x%04X\n", eeprom_offset);
- nesadapter->software_eeprom_offset = eeprom_offset;
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset + 4);
- if (eeprom_data != 0x5753) {
- printk("Not a valid Software Image = 0x%04X\n", eeprom_data);
- return -1;
- }
- sw_section_ver = nes_read16_eeprom(nesdev->regs, nesadapter->software_eeprom_offset + 6);
- nes_debug(NES_DBG_HW, "Software section version number = 0x%04X\n",
- sw_section_ver);
-
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset + 2);
- nes_debug(NES_DBG_HW, "EEPROM Offset %u (next section) = 0x%04X\n",
- eeprom_offset + 2, eeprom_data);
- next_section_address = eeprom_offset + (((eeprom_data & 0x00ff) << 3) <<
- ((eeprom_data & 0x0100) >> 8));
- eeprom_data = nes_read16_eeprom(nesdev->regs, next_section_address + 4);
- if (eeprom_data != 0x414d) {
- nes_debug(NES_DBG_HW, "EEPROM Changed offset should be 0x414d but was 0x%04X\n",
- eeprom_data);
- goto no_fw_rev;
- }
- eeprom_offset = next_section_address;
-
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset + 2);
- nes_debug(NES_DBG_HW, "EEPROM Offset %u (next section) = 0x%04X\n",
- eeprom_offset + 2, eeprom_data);
- next_section_address = eeprom_offset + (((eeprom_data & 0x00ff) << 3) <<
- ((eeprom_data & 0x0100) >> 8));
- eeprom_data = nes_read16_eeprom(nesdev->regs, next_section_address + 4);
- if (eeprom_data != 0x4f52) {
- nes_debug(NES_DBG_HW, "EEPROM Changed offset should be 0x4f52 but was 0x%04X\n",
- eeprom_data);
- goto no_fw_rev;
- }
- eeprom_offset = next_section_address;
-
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset + 2);
- nes_debug(NES_DBG_HW, "EEPROM Offset %u (next section) = 0x%04X\n",
- eeprom_offset + 2, eeprom_data);
- next_section_address = eeprom_offset + ((eeprom_data & 0x00ff) << 3);
- eeprom_data = nes_read16_eeprom(nesdev->regs, next_section_address + 4);
- if (eeprom_data != 0x5746) {
- nes_debug(NES_DBG_HW, "EEPROM Changed offset should be 0x5746 but was 0x%04X\n",
- eeprom_data);
- goto no_fw_rev;
- }
- eeprom_offset = next_section_address;
-
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset + 2);
- nes_debug(NES_DBG_HW, "EEPROM Offset %u (next section) = 0x%04X\n",
- eeprom_offset + 2, eeprom_data);
- next_section_address = eeprom_offset + ((eeprom_data & 0x00ff) << 3);
- eeprom_data = nes_read16_eeprom(nesdev->regs, next_section_address + 4);
- if (eeprom_data != 0x5753) {
- nes_debug(NES_DBG_HW, "EEPROM Changed offset should be 0x5753 but was 0x%04X\n",
- eeprom_data);
- goto no_fw_rev;
- }
- eeprom_offset = next_section_address;
-
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset + 2);
- nes_debug(NES_DBG_HW, "EEPROM Offset %u (next section) = 0x%04X\n",
- eeprom_offset + 2, eeprom_data);
- next_section_address = eeprom_offset + ((eeprom_data & 0x00ff) << 3);
- eeprom_data = nes_read16_eeprom(nesdev->regs, next_section_address + 4);
- if (eeprom_data != 0x414d) {
- nes_debug(NES_DBG_HW, "EEPROM Changed offset should be 0x414d but was 0x%04X\n",
- eeprom_data);
- goto no_fw_rev;
- }
- eeprom_offset = next_section_address;
-
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset + 2);
- nes_debug(NES_DBG_HW, "EEPROM Offset %u (next section) = 0x%04X\n",
- eeprom_offset + 2, eeprom_data);
- next_section_address = eeprom_offset + ((eeprom_data & 0x00ff) << 3);
- eeprom_data = nes_read16_eeprom(nesdev->regs, next_section_address + 4);
- if (eeprom_data != 0x464e) {
- nes_debug(NES_DBG_HW, "EEPROM Changed offset should be 0x464e but was 0x%04X\n",
- eeprom_data);
- goto no_fw_rev;
- }
- eeprom_data = nes_read16_eeprom(nesdev->regs, next_section_address + 8);
- printk(PFX "Firmware version %u.%u\n", (u8)(eeprom_data>>8), (u8)eeprom_data);
- major_ver = (u8)(eeprom_data >> 8);
- minor_ver = (u8)(eeprom_data);
-
- if (nes_drv_opt & NES_DRV_OPT_DISABLE_VIRT_WQ) {
- nes_debug(NES_DBG_HW, "Virtual WQs have been disabled\n");
- } else if (((major_ver == 2) && (minor_ver > 21)) || ((major_ver > 2) && (major_ver != 255))) {
- nesadapter->virtwq = 1;
- }
- if (((major_ver == 3) && (minor_ver >= 16)) || (major_ver > 3))
- nesadapter->send_term_ok = 1;
-
- if (nes_drv_opt & NES_DRV_OPT_ENABLE_PAU) {
- if (!nes_set_pau(nesdev))
- nesadapter->allow_unaligned_fpdus = 1;
- }
-
- nesadapter->firmware_version = (((u32)(u8)(eeprom_data>>8)) << 16) +
- (u32)((u8)eeprom_data);
-
- eeprom_data = nes_read16_eeprom(nesdev->regs, next_section_address + 10);
- printk(PFX "EEPROM version %u.%u\n", (u8)(eeprom_data>>8), (u8)eeprom_data);
- nesadapter->eeprom_version = (((u32)(u8)(eeprom_data>>8)) << 16) +
- (u32)((u8)eeprom_data);
-
-no_fw_rev:
- /* eeprom is valid */
- eeprom_offset = nesadapter->software_eeprom_offset;
- eeprom_offset += 8;
- nesadapter->netdev_max = (u8)nes_read16_eeprom(nesdev->regs, eeprom_offset);
- eeprom_offset += 2;
- mac_addr_high = nes_read16_eeprom(nesdev->regs, eeprom_offset);
- eeprom_offset += 2;
- mac_addr_low = (u32)nes_read16_eeprom(nesdev->regs, eeprom_offset);
- eeprom_offset += 2;
- mac_addr_low <<= 16;
- mac_addr_low += (u32)nes_read16_eeprom(nesdev->regs, eeprom_offset);
- nes_debug(NES_DBG_HW, "Base MAC Address = 0x%04X%08X\n",
- mac_addr_high, mac_addr_low);
- nes_debug(NES_DBG_HW, "MAC Address count = %u\n", nesadapter->netdev_max);
-
- nesadapter->mac_addr_low = mac_addr_low;
- nesadapter->mac_addr_high = mac_addr_high;
-
- /* Read the Phy Type array */
- eeprom_offset += 10;
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
- nesadapter->phy_type[0] = (u8)(eeprom_data >> 8);
- nesadapter->phy_type[1] = (u8)eeprom_data;
-
- /* Read the port array */
- eeprom_offset += 2;
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
- nesadapter->phy_type[2] = (u8)(eeprom_data >> 8);
- nesadapter->phy_type[3] = (u8)eeprom_data;
- /* port_count is set by soft reset reg */
- nes_debug(NES_DBG_HW, "port_count = %u, port 0 -> %u, port 1 -> %u,"
- " port 2 -> %u, port 3 -> %u\n",
- nesadapter->port_count,
- nesadapter->phy_type[0], nesadapter->phy_type[1],
- nesadapter->phy_type[2], nesadapter->phy_type[3]);
-
- /* Read PD config array */
- eeprom_offset += 10;
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
- nesadapter->pd_config_size[0] = eeprom_data;
- eeprom_offset += 2;
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
- nesadapter->pd_config_base[0] = eeprom_data;
- nes_debug(NES_DBG_HW, "PD0 config, size=0x%04x, base=0x%04x\n",
- nesadapter->pd_config_size[0], nesadapter->pd_config_base[0]);
-
- eeprom_offset += 2;
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
- nesadapter->pd_config_size[1] = eeprom_data;
- eeprom_offset += 2;
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
- nesadapter->pd_config_base[1] = eeprom_data;
- nes_debug(NES_DBG_HW, "PD1 config, size=0x%04x, base=0x%04x\n",
- nesadapter->pd_config_size[1], nesadapter->pd_config_base[1]);
-
- eeprom_offset += 2;
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
- nesadapter->pd_config_size[2] = eeprom_data;
- eeprom_offset += 2;
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
- nesadapter->pd_config_base[2] = eeprom_data;
- nes_debug(NES_DBG_HW, "PD2 config, size=0x%04x, base=0x%04x\n",
- nesadapter->pd_config_size[2], nesadapter->pd_config_base[2]);
-
- eeprom_offset += 2;
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
- nesadapter->pd_config_size[3] = eeprom_data;
- eeprom_offset += 2;
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
- nesadapter->pd_config_base[3] = eeprom_data;
- nes_debug(NES_DBG_HW, "PD3 config, size=0x%04x, base=0x%04x\n",
- nesadapter->pd_config_size[3], nesadapter->pd_config_base[3]);
-
- /* Read Rx Pool Size */
- eeprom_offset += 22; /* 46 */
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
- eeprom_offset += 2;
- nesadapter->rx_pool_size = (((u32)eeprom_data) << 16) +
- nes_read16_eeprom(nesdev->regs, eeprom_offset);
- nes_debug(NES_DBG_HW, "rx_pool_size = 0x%08X\n", nesadapter->rx_pool_size);
-
- eeprom_offset += 2;
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
- eeprom_offset += 2;
- nesadapter->tx_pool_size = (((u32)eeprom_data) << 16) +
- nes_read16_eeprom(nesdev->regs, eeprom_offset);
- nes_debug(NES_DBG_HW, "tx_pool_size = 0x%08X\n", nesadapter->tx_pool_size);
-
- eeprom_offset += 2;
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
- eeprom_offset += 2;
- nesadapter->rx_threshold = (((u32)eeprom_data) << 16) +
- nes_read16_eeprom(nesdev->regs, eeprom_offset);
- nes_debug(NES_DBG_HW, "rx_threshold = 0x%08X\n", nesadapter->rx_threshold);
-
- eeprom_offset += 2;
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
- eeprom_offset += 2;
- nesadapter->tcp_timer_core_clk_divisor = (((u32)eeprom_data) << 16) +
- nes_read16_eeprom(nesdev->regs, eeprom_offset);
- nes_debug(NES_DBG_HW, "tcp_timer_core_clk_divisor = 0x%08X\n",
- nesadapter->tcp_timer_core_clk_divisor);
-
- eeprom_offset += 2;
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
- eeprom_offset += 2;
- nesadapter->iwarp_config = (((u32)eeprom_data) << 16) +
- nes_read16_eeprom(nesdev->regs, eeprom_offset);
- nes_debug(NES_DBG_HW, "iwarp_config = 0x%08X\n", nesadapter->iwarp_config);
-
- eeprom_offset += 2;
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
- eeprom_offset += 2;
- nesadapter->cm_config = (((u32)eeprom_data) << 16) +
- nes_read16_eeprom(nesdev->regs, eeprom_offset);
- nes_debug(NES_DBG_HW, "cm_config = 0x%08X\n", nesadapter->cm_config);
-
- eeprom_offset += 2;
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
- eeprom_offset += 2;
- nesadapter->sws_timer_config = (((u32)eeprom_data) << 16) +
- nes_read16_eeprom(nesdev->regs, eeprom_offset);
- nes_debug(NES_DBG_HW, "sws_timer_config = 0x%08X\n", nesadapter->sws_timer_config);
-
- eeprom_offset += 2;
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
- eeprom_offset += 2;
- nesadapter->tcp_config1 = (((u32)eeprom_data) << 16) +
- nes_read16_eeprom(nesdev->regs, eeprom_offset);
- nes_debug(NES_DBG_HW, "tcp_config1 = 0x%08X\n", nesadapter->tcp_config1);
-
- eeprom_offset += 2;
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
- eeprom_offset += 2;
- nesadapter->wqm_wat = (((u32)eeprom_data) << 16) +
- nes_read16_eeprom(nesdev->regs, eeprom_offset);
- nes_debug(NES_DBG_HW, "wqm_wat = 0x%08X\n", nesadapter->wqm_wat);
-
- eeprom_offset += 2;
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
- eeprom_offset += 2;
- nesadapter->core_clock = (((u32)eeprom_data) << 16) +
- nes_read16_eeprom(nesdev->regs, eeprom_offset);
- nes_debug(NES_DBG_HW, "core_clock = 0x%08X\n", nesadapter->core_clock);
-
- if ((sw_section_ver) && (nesadapter->hw_rev != NE020_REV)) {
- eeprom_offset += 2;
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
- nesadapter->phy_index[0] = (eeprom_data & 0xff00)>>8;
- nesadapter->phy_index[1] = eeprom_data & 0x00ff;
- eeprom_offset += 2;
- eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
- nesadapter->phy_index[2] = (eeprom_data & 0xff00)>>8;
- nesadapter->phy_index[3] = eeprom_data & 0x00ff;
- } else {
- nesadapter->phy_index[0] = 4;
- nesadapter->phy_index[1] = 5;
- nesadapter->phy_index[2] = 6;
- nesadapter->phy_index[3] = 7;
- }
- nes_debug(NES_DBG_HW, "Phy address map = 0 > %u, 1 > %u, 2 > %u, 3 > %u\n",
- nesadapter->phy_index[0],nesadapter->phy_index[1],
- nesadapter->phy_index[2],nesadapter->phy_index[3]);
- }
-
- return 0;
-}
-
-
-/**
- * nes_read16_eeprom
- */
-static u16 nes_read16_eeprom(void __iomem *addr, u16 offset)
-{
- writel(NES_EEPROM_READ_REQUEST + (offset >> 1),
- (void __iomem *)addr + NES_EEPROM_COMMAND);
-
- do {
- } while (readl((void __iomem *)addr + NES_EEPROM_COMMAND) &
- NES_EEPROM_READ_REQUEST);
-
- return readw((void __iomem *)addr + NES_EEPROM_DATA);
-}
-
-
-/**
- * nes_write_1G_phy_reg
- */
-void nes_write_1G_phy_reg(struct nes_device *nesdev, u8 phy_reg, u8 phy_addr, u16 data)
-{
- u32 u32temp;
- u32 counter;
-
- nes_write_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL,
- 0x50020000 | data | ((u32)phy_reg << 18) | ((u32)phy_addr << 23));
- for (counter = 0; counter < 100 ; counter++) {
- udelay(30);
- u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS);
- if (u32temp & 1) {
- /* nes_debug(NES_DBG_PHY, "Phy interrupt status = 0x%X.\n", u32temp); */
- nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS, 1);
- break;
- }
- }
- if (!(u32temp & 1))
- nes_debug(NES_DBG_PHY, "Phy is not responding. interrupt status = 0x%X.\n",
- u32temp);
-}
-
-
-/**
- * nes_read_1G_phy_reg
- * This routine only issues the read, the data must be read
- * separately.
- */
-void nes_read_1G_phy_reg(struct nes_device *nesdev, u8 phy_reg, u8 phy_addr, u16 *data)
-{
- u32 u32temp;
- u32 counter;
-
- /* nes_debug(NES_DBG_PHY, "phy addr = %d, mac_index = %d\n",
- phy_addr, nesdev->mac_index); */
-
- nes_write_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL,
- 0x60020000 | ((u32)phy_reg << 18) | ((u32)phy_addr << 23));
- for (counter = 0; counter < 100 ; counter++) {
- udelay(30);
- u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS);
- if (u32temp & 1) {
- /* nes_debug(NES_DBG_PHY, "Phy interrupt status = 0x%X.\n", u32temp); */
- nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS, 1);
- break;
- }
- }
- if (!(u32temp & 1)) {
- nes_debug(NES_DBG_PHY, "Phy is not responding. interrupt status = 0x%X.\n",
- u32temp);
- *data = 0xffff;
- } else {
- *data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
- }
-}
-
-
-/**
- * nes_write_10G_phy_reg
- */
-void nes_write_10G_phy_reg(struct nes_device *nesdev, u16 phy_addr, u8 dev_addr, u16 phy_reg,
- u16 data)
-{
- u32 port_addr;
- u32 u32temp;
- u32 counter;
-
- port_addr = phy_addr;
-
- /* set address */
- nes_write_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL,
- 0x00020000 | (u32)phy_reg | (((u32)dev_addr) << 18) | (((u32)port_addr) << 23));
- for (counter = 0; counter < 100 ; counter++) {
- udelay(30);
- u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS);
- if (u32temp & 1) {
- nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS, 1);
- break;
- }
- }
- if (!(u32temp & 1))
- nes_debug(NES_DBG_PHY, "Phy is not responding. interrupt status = 0x%X.\n",
- u32temp);
-
- /* set data */
- nes_write_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL,
- 0x10020000 | (u32)data | (((u32)dev_addr) << 18) | (((u32)port_addr) << 23));
- for (counter = 0; counter < 100 ; counter++) {
- udelay(30);
- u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS);
- if (u32temp & 1) {
- nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS, 1);
- break;
- }
- }
- if (!(u32temp & 1))
- nes_debug(NES_DBG_PHY, "Phy is not responding. interrupt status = 0x%X.\n",
- u32temp);
-}
-
-
-/**
- * nes_read_10G_phy_reg
- * This routine only issues the read, the data must be read
- * separately.
- */
-void nes_read_10G_phy_reg(struct nes_device *nesdev, u8 phy_addr, u8 dev_addr, u16 phy_reg)
-{
- u32 port_addr;
- u32 u32temp;
- u32 counter;
-
- port_addr = phy_addr;
-
- /* set address */
- nes_write_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL,
- 0x00020000 | (u32)phy_reg | (((u32)dev_addr) << 18) | (((u32)port_addr) << 23));
- for (counter = 0; counter < 100 ; counter++) {
- udelay(30);
- u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS);
- if (u32temp & 1) {
- nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS, 1);
- break;
- }
- }
- if (!(u32temp & 1))
- nes_debug(NES_DBG_PHY, "Phy is not responding. interrupt status = 0x%X.\n",
- u32temp);
-
- /* issue read */
- nes_write_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL,
- 0x30020000 | (((u32)dev_addr) << 18) | (((u32)port_addr) << 23));
- for (counter = 0; counter < 100 ; counter++) {
- udelay(30);
- u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS);
- if (u32temp & 1) {
- nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS, 1);
- break;
- }
- }
- if (!(u32temp & 1))
- nes_debug(NES_DBG_PHY, "Phy is not responding. interrupt status = 0x%X.\n",
- u32temp);
-}
-
-
-/**
- * nes_get_cqp_request
- */
-struct nes_cqp_request *nes_get_cqp_request(struct nes_device *nesdev)
-{
- unsigned long flags;
- struct nes_cqp_request *cqp_request = NULL;
-
- if (!list_empty(&nesdev->cqp_avail_reqs)) {
- spin_lock_irqsave(&nesdev->cqp.lock, flags);
- if (!list_empty(&nesdev->cqp_avail_reqs)) {
- cqp_request = list_entry(nesdev->cqp_avail_reqs.next,
- struct nes_cqp_request, list);
- list_del_init(&cqp_request->list);
- }
- spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
- }
- if (cqp_request == NULL) {
- cqp_request = kzalloc(sizeof(struct nes_cqp_request), GFP_ATOMIC);
- if (cqp_request) {
- cqp_request->dynamic = 1;
- INIT_LIST_HEAD(&cqp_request->list);
- }
- }
-
- if (cqp_request) {
- init_waitqueue_head(&cqp_request->waitq);
- cqp_request->waiting = 0;
- cqp_request->request_done = 0;
- cqp_request->callback = 0;
- init_waitqueue_head(&cqp_request->waitq);
- nes_debug(NES_DBG_CQP, "Got cqp request %p from the available list \n",
- cqp_request);
- } else
- printk(KERN_ERR PFX "%s: Could not allocated a CQP request.\n",
- __func__);
-
- return cqp_request;
-}
-
-void nes_free_cqp_request(struct nes_device *nesdev,
- struct nes_cqp_request *cqp_request)
-{
- unsigned long flags;
-
- nes_debug(NES_DBG_CQP, "CQP request %p (opcode 0x%02X) freed.\n",
- cqp_request,
- le32_to_cpu(cqp_request->cqp_wqe.wqe_words[NES_CQP_WQE_OPCODE_IDX]) & 0x3f);
-
- if (cqp_request->dynamic) {
- kfree(cqp_request);
- } else {
- spin_lock_irqsave(&nesdev->cqp.lock, flags);
- list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
- spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
- }
-}
-
-void nes_put_cqp_request(struct nes_device *nesdev,
- struct nes_cqp_request *cqp_request)
-{
- if (atomic_dec_and_test(&cqp_request->refcount))
- nes_free_cqp_request(nesdev, cqp_request);
-}
-
-
-/**
- * nes_post_cqp_request
- */
-void nes_post_cqp_request(struct nes_device *nesdev,
- struct nes_cqp_request *cqp_request)
-{
- struct nes_hw_cqp_wqe *cqp_wqe;
- unsigned long flags;
- u32 cqp_head;
- u64 u64temp;
- u32 opcode;
- int ctx_index = NES_CQP_WQE_COMP_CTX_LOW_IDX;
-
- spin_lock_irqsave(&nesdev->cqp.lock, flags);
-
- if (((((nesdev->cqp.sq_tail+(nesdev->cqp.sq_size*2))-nesdev->cqp.sq_head) &
- (nesdev->cqp.sq_size - 1)) != 1)
- && (list_empty(&nesdev->cqp_pending_reqs))) {
- cqp_head = nesdev->cqp.sq_head++;
- nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
- cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
- memcpy(cqp_wqe, &cqp_request->cqp_wqe, sizeof(*cqp_wqe));
- opcode = le32_to_cpu(cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX]);
- if ((opcode & NES_CQP_OPCODE_MASK) == NES_CQP_DOWNLOAD_SEGMENT)
- ctx_index = NES_CQP_WQE_DL_COMP_CTX_LOW_IDX;
- barrier();
- u64temp = (unsigned long)cqp_request;
- set_wqe_64bit_value(cqp_wqe->wqe_words, ctx_index, u64temp);
- nes_debug(NES_DBG_CQP, "CQP request (opcode 0x%02X), line 1 = 0x%08X put on CQPs SQ,"
- " request = %p, cqp_head = %u, cqp_tail = %u, cqp_size = %u,"
- " waiting = %d, refcount = %d.\n",
- opcode & NES_CQP_OPCODE_MASK,
- le32_to_cpu(cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX]), cqp_request,
- nesdev->cqp.sq_head, nesdev->cqp.sq_tail, nesdev->cqp.sq_size,
- cqp_request->waiting, atomic_read(&cqp_request->refcount));
-
- barrier();
-
- /* Ring doorbell (1 WQEs) */
- nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x01800000 | nesdev->cqp.qp_id);
-
- barrier();
- } else {
- nes_debug(NES_DBG_CQP, "CQP request %p (opcode 0x%02X), line 1 = 0x%08X"
- " put on the pending queue.\n",
- cqp_request,
- le32_to_cpu(cqp_request->cqp_wqe.wqe_words[NES_CQP_WQE_OPCODE_IDX])&0x3f,
- le32_to_cpu(cqp_request->cqp_wqe.wqe_words[NES_CQP_WQE_ID_IDX]));
- list_add_tail(&cqp_request->list, &nesdev->cqp_pending_reqs);
- }
-
- spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
-
- return;
-}
-
-/**
- * nes_arp_table
- */
-int nes_arp_table(struct nes_device *nesdev, u32 ip_addr, u8 *mac_addr, u32 action)
-{
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- int arp_index;
- int err = 0;
- __be32 tmp_addr;
-
- for (arp_index = 0; (u32) arp_index < nesadapter->arp_table_size; arp_index++) {
- if (nesadapter->arp_table[arp_index].ip_addr == ip_addr)
- break;
- }
-
- if (action == NES_ARP_ADD) {
- if (arp_index != nesadapter->arp_table_size) {
- return -1;
- }
-
- arp_index = 0;
- err = nes_alloc_resource(nesadapter, nesadapter->allocated_arps,
- nesadapter->arp_table_size, (u32 *)&arp_index, &nesadapter->next_arp_index, NES_RESOURCE_ARP);
- if (err) {
- nes_debug(NES_DBG_NETDEV, "nes_alloc_resource returned error = %u\n", err);
- return err;
- }
- nes_debug(NES_DBG_NETDEV, "ADD, arp_index=%d\n", arp_index);
-
- nesadapter->arp_table[arp_index].ip_addr = ip_addr;
- memcpy(nesadapter->arp_table[arp_index].mac_addr, mac_addr, ETH_ALEN);
- return arp_index;
- }
-
- /* DELETE or RESOLVE */
- if (arp_index == nesadapter->arp_table_size) {
- tmp_addr = cpu_to_be32(ip_addr);
- nes_debug(NES_DBG_NETDEV, "MAC for %pI4 not in ARP table - cannot %s\n",
- &tmp_addr, action == NES_ARP_RESOLVE ? "resolve" : "delete");
- return -1;
- }
-
- if (action == NES_ARP_RESOLVE) {
- nes_debug(NES_DBG_NETDEV, "RESOLVE, arp_index=%d\n", arp_index);
- return arp_index;
- }
-
- if (action == NES_ARP_DELETE) {
- nes_debug(NES_DBG_NETDEV, "DELETE, arp_index=%d\n", arp_index);
- nesadapter->arp_table[arp_index].ip_addr = 0;
- eth_zero_addr(nesadapter->arp_table[arp_index].mac_addr);
- nes_free_resource(nesadapter, nesadapter->allocated_arps, arp_index);
- return arp_index;
- }
-
- return -1;
-}
-
-
-/**
- * nes_mh_fix
- */
-void nes_mh_fix(struct timer_list *t)
-{
- struct nes_adapter *nesadapter = from_timer(nesadapter, t, mh_timer);
- struct nes_device *nesdev = nesadapter->nesdev;
- unsigned long flags;
- struct nes_vnic *nesvnic;
- u32 used_chunks_tx;
- u32 temp_used_chunks_tx;
- u32 temp_last_used_chunks_tx;
- u32 used_chunks_mask;
- u32 mac_tx_frames_low;
- u32 mac_tx_frames_high;
- u32 mac_tx_pauses;
- u32 reset_value;
- u32 tx_control;
- u32 tx_config;
- u32 tx_pause_quanta;
- u32 rx_control;
- u32 rx_config;
- u32 mac_exact_match;
- u32 mpp_debug;
- u32 i=0;
- u32 chunks_tx_progress = 0;
-
- spin_lock_irqsave(&nesadapter->phy_lock, flags);
- if ((nesadapter->mac_sw_state[0] != NES_MAC_SW_IDLE) || (nesadapter->mac_link_down[0])) {
- spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
- goto no_mh_work;
- }
- nesadapter->mac_sw_state[0] = NES_MAC_SW_MH;
- spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
- do {
- mac_tx_frames_low = nes_read_indexed(nesdev, NES_IDX_MAC_TX_FRAMES_LOW);
- mac_tx_frames_high = nes_read_indexed(nesdev, NES_IDX_MAC_TX_FRAMES_HIGH);
- mac_tx_pauses = nes_read_indexed(nesdev, NES_IDX_MAC_TX_PAUSE_FRAMES);
- used_chunks_tx = nes_read_indexed(nesdev, NES_IDX_USED_CHUNKS_TX);
- nesdev->mac_pause_frames_sent += mac_tx_pauses;
- used_chunks_mask = 0;
- temp_used_chunks_tx = used_chunks_tx;
- temp_last_used_chunks_tx = nesdev->last_used_chunks_tx;
-
- if (nesdev->netdev[0]) {
- nesvnic = netdev_priv(nesdev->netdev[0]);
- } else {
- break;
- }
-
- for (i=0; i<4; i++) {
- used_chunks_mask <<= 8;
- if (nesvnic->qp_nic_index[i] != 0xff) {
- used_chunks_mask |= 0xff;
- if ((temp_used_chunks_tx&0xff)<(temp_last_used_chunks_tx&0xff)) {
- chunks_tx_progress = 1;
- }
- }
- temp_used_chunks_tx >>= 8;
- temp_last_used_chunks_tx >>= 8;
- }
- if ((mac_tx_frames_low) || (mac_tx_frames_high) ||
- (!(used_chunks_tx&used_chunks_mask)) ||
- (!(nesdev->last_used_chunks_tx&used_chunks_mask)) ||
- (chunks_tx_progress) ) {
- nesdev->last_used_chunks_tx = used_chunks_tx;
- break;
- }
- nesdev->last_used_chunks_tx = used_chunks_tx;
- barrier();
-
- nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONTROL, 0x00000005);
- mh_pauses_sent++;
- mac_tx_pauses = nes_read_indexed(nesdev, NES_IDX_MAC_TX_PAUSE_FRAMES);
- if (mac_tx_pauses) {
- nesdev->mac_pause_frames_sent += mac_tx_pauses;
- break;
- }
-
- tx_control = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONTROL);
- tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG);
- tx_pause_quanta = nes_read_indexed(nesdev, NES_IDX_MAC_TX_PAUSE_QUANTA);
- rx_control = nes_read_indexed(nesdev, NES_IDX_MAC_RX_CONTROL);
- rx_config = nes_read_indexed(nesdev, NES_IDX_MAC_RX_CONFIG);
- mac_exact_match = nes_read_indexed(nesdev, NES_IDX_MAC_EXACT_MATCH_BOTTOM);
- mpp_debug = nes_read_indexed(nesdev, NES_IDX_MPP_DEBUG);
-
- /* one last ditch effort to avoid a false positive */
- mac_tx_pauses = nes_read_indexed(nesdev, NES_IDX_MAC_TX_PAUSE_FRAMES);
- if (mac_tx_pauses) {
- nesdev->last_mac_tx_pauses = nesdev->mac_pause_frames_sent;
- nes_debug(NES_DBG_HW, "failsafe caught slow outbound pause\n");
- break;
- }
- mh_detected++;
-
- nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONTROL, 0x00000000);
- nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, 0x00000000);
- reset_value = nes_read32(nesdev->regs+NES_SOFTWARE_RESET);
-
- nes_write32(nesdev->regs+NES_SOFTWARE_RESET, reset_value | 0x0000001d);
-
- while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET)
- & 0x00000040) != 0x00000040) && (i++ < 5000)) {
- /* mdelay(1); */
- }
-
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, 0x00000008);
- nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0);
-
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_EMP0, 0x000bdef7);
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_DRIVE0, 0x9ce73000);
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_MODE0, 0x0ff00000);
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_SIGDET0, 0x00000000);
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_BYPASS0, 0x00000000);
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_LOOPBACK_CONTROL0, 0x00000000);
- if (nesadapter->OneG_Mode) {
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_EQ_CONTROL0, 0xf0182222);
- } else {
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_EQ_CONTROL0, 0xf0042222);
- }
- nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_RX_EQ_STATUS0);
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000ff);
-
- nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONTROL, tx_control);
- nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config);
- nes_write_indexed(nesdev, NES_IDX_MAC_TX_PAUSE_QUANTA, tx_pause_quanta);
- nes_write_indexed(nesdev, NES_IDX_MAC_RX_CONTROL, rx_control);
- nes_write_indexed(nesdev, NES_IDX_MAC_RX_CONFIG, rx_config);
- nes_write_indexed(nesdev, NES_IDX_MAC_EXACT_MATCH_BOTTOM, mac_exact_match);
- nes_write_indexed(nesdev, NES_IDX_MPP_DEBUG, mpp_debug);
-
- } while (0);
-
- nesadapter->mac_sw_state[0] = NES_MAC_SW_IDLE;
-no_mh_work:
- nesdev->nesadapter->mh_timer.expires = jiffies + (HZ/5);
- add_timer(&nesdev->nesadapter->mh_timer);
-}
-
-/**
- * nes_clc
- */
-void nes_clc(struct timer_list *t)
-{
- struct nes_adapter *nesadapter = from_timer(nesadapter, t, lc_timer);
- unsigned long flags;
-
- spin_lock_irqsave(&nesadapter->phy_lock, flags);
- nesadapter->link_interrupt_count[0] = 0;
- nesadapter->link_interrupt_count[1] = 0;
- nesadapter->link_interrupt_count[2] = 0;
- nesadapter->link_interrupt_count[3] = 0;
- spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
-
- nesadapter->lc_timer.expires = jiffies + 3600 * HZ; /* 1 hour */
- add_timer(&nesadapter->lc_timer);
-}
-
-
-/**
- * nes_dump_mem
- */
-void nes_dump_mem(unsigned int dump_debug_level, void *addr, int length)
-{
- if (!(nes_debug_level & dump_debug_level)) {
- return;
- }
-
- if (length > 0x100) {
- nes_debug(dump_debug_level, "Length truncated from %x to %x\n", length, 0x100);
- length = 0x100;
- }
- nes_debug(dump_debug_level, "Address=0x%p, length=0x%x (%d)\n", addr, length, length);
-
- print_hex_dump(KERN_ERR, PFX, DUMP_PREFIX_NONE, 16, 1, addr, length, true);
-}
diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c
deleted file mode 100644
index 49024326a518..000000000000
--- a/drivers/infiniband/hw/nes/nes_verbs.c
+++ /dev/null
@@ -1,3759 +0,0 @@
-/*
- * Copyright (c) 2006 - 2011 Intel Corporation. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/random.h>
-#include <linux/highmem.h>
-#include <linux/slab.h>
-#include <asm/byteorder.h>
-
-#include <rdma/ib_verbs.h>
-#include <rdma/iw_cm.h>
-#include <rdma/ib_user_verbs.h>
-#include <rdma/uverbs_ioctl.h>
-
-#include "nes.h"
-
-#include <rdma/ib_umem.h>
-
-atomic_t mod_qp_timouts;
-atomic_t qps_created;
-atomic_t sw_qps_destroyed;
-
-static void nes_unregister_ofa_device(struct nes_ib_device *nesibdev);
-static int nes_dereg_mr(struct ib_mr *ib_mr, struct ib_udata *udata);
-
-/**
- * nes_alloc_mw
- */
-static struct ib_mw *nes_alloc_mw(struct ib_pd *ibpd, enum ib_mw_type type,
- struct ib_udata *udata)
-{
- struct nes_pd *nespd = to_nespd(ibpd);
- struct nes_vnic *nesvnic = to_nesvnic(ibpd->device);
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- struct nes_cqp_request *cqp_request;
- struct nes_mr *nesmr;
- struct ib_mw *ibmw;
- struct nes_hw_cqp_wqe *cqp_wqe;
- int ret;
- u32 stag;
- u32 stag_index = 0;
- u32 next_stag_index = 0;
- u32 driver_key = 0;
- u8 stag_key = 0;
-
- if (type != IB_MW_TYPE_1)
- return ERR_PTR(-EINVAL);
-
- get_random_bytes(&next_stag_index, sizeof(next_stag_index));
- stag_key = (u8)next_stag_index;
-
- driver_key = 0;
-
- next_stag_index >>= 8;
- next_stag_index %= nesadapter->max_mr;
-
- ret = nes_alloc_resource(nesadapter, nesadapter->allocated_mrs,
- nesadapter->max_mr, &stag_index, &next_stag_index, NES_RESOURCE_MW);
- if (ret) {
- return ERR_PTR(ret);
- }
-
- nesmr = kzalloc(sizeof(*nesmr), GFP_KERNEL);
- if (!nesmr) {
- nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
- return ERR_PTR(-ENOMEM);
- }
-
- stag = stag_index << 8;
- stag |= driver_key;
- stag += (u32)stag_key;
-
- nes_debug(NES_DBG_MR, "Registering STag 0x%08X, index = 0x%08X\n",
- stag, stag_index);
-
- /* Register the region with the adapter */
- cqp_request = nes_get_cqp_request(nesdev);
- if (cqp_request == NULL) {
- kfree(nesmr);
- nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
- return ERR_PTR(-ENOMEM);
- }
-
- cqp_request->waiting = 1;
- cqp_wqe = &cqp_request->cqp_wqe;
-
- cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] =
- cpu_to_le32( NES_CQP_ALLOCATE_STAG | NES_CQP_STAG_RIGHTS_REMOTE_READ |
- NES_CQP_STAG_RIGHTS_REMOTE_WRITE | NES_CQP_STAG_VA_TO |
- NES_CQP_STAG_REM_ACC_EN);
-
- nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_LEN_HIGH_PD_IDX, (nespd->pd_id & 0x00007fff));
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_STAG_IDX, stag);
-
- atomic_set(&cqp_request->refcount, 2);
- nes_post_cqp_request(nesdev, cqp_request);
-
- /* Wait for CQP */
- ret = wait_event_timeout(cqp_request->waitq, (cqp_request->request_done != 0),
- NES_EVENT_TIMEOUT);
- nes_debug(NES_DBG_MR, "Register STag 0x%08X completed, wait_event_timeout ret = %u,"
- " CQP Major:Minor codes = 0x%04X:0x%04X.\n",
- stag, ret, cqp_request->major_code, cqp_request->minor_code);
- if ((!ret) || (cqp_request->major_code)) {
- nes_put_cqp_request(nesdev, cqp_request);
- kfree(nesmr);
- nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
- if (!ret) {
- return ERR_PTR(-ETIME);
- } else {
- return ERR_PTR(-ENOMEM);
- }
- }
- nes_put_cqp_request(nesdev, cqp_request);
-
- nesmr->ibmw.rkey = stag;
- nesmr->mode = IWNES_MEMREG_TYPE_MW;
- ibmw = &nesmr->ibmw;
- nesmr->pbl_4k = 0;
- nesmr->pbls_used = 0;
-
- return ibmw;
-}
-
-
-/**
- * nes_dealloc_mw
- */
-static int nes_dealloc_mw(struct ib_mw *ibmw)
-{
- struct nes_mr *nesmr = to_nesmw(ibmw);
- struct nes_vnic *nesvnic = to_nesvnic(ibmw->device);
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- struct nes_hw_cqp_wqe *cqp_wqe;
- struct nes_cqp_request *cqp_request;
- int err = 0;
- int ret;
-
- /* Deallocate the window with the adapter */
- cqp_request = nes_get_cqp_request(nesdev);
- if (cqp_request == NULL) {
- nes_debug(NES_DBG_MR, "Failed to get a cqp_request.\n");
- return -ENOMEM;
- }
- cqp_request->waiting = 1;
- cqp_wqe = &cqp_request->cqp_wqe;
- nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, NES_CQP_DEALLOCATE_STAG);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_STAG_IDX, ibmw->rkey);
-
- atomic_set(&cqp_request->refcount, 2);
- nes_post_cqp_request(nesdev, cqp_request);
-
- /* Wait for CQP */
- nes_debug(NES_DBG_MR, "Waiting for deallocate STag 0x%08X to complete.\n",
- ibmw->rkey);
- ret = wait_event_timeout(cqp_request->waitq, (0 != cqp_request->request_done),
- NES_EVENT_TIMEOUT);
- nes_debug(NES_DBG_MR, "Deallocate STag completed, wait_event_timeout ret = %u,"
- " CQP Major:Minor codes = 0x%04X:0x%04X.\n",
- ret, cqp_request->major_code, cqp_request->minor_code);
- if (!ret)
- err = -ETIME;
- else if (cqp_request->major_code)
- err = -EIO;
-
- nes_put_cqp_request(nesdev, cqp_request);
-
- nes_free_resource(nesadapter, nesadapter->allocated_mrs,
- (ibmw->rkey & 0x0fffff00) >> 8);
- kfree(nesmr);
-
- return err;
-}
-
-
-/*
- * nes_alloc_fast_mr
- */
-static int alloc_fast_reg_mr(struct nes_device *nesdev, struct nes_pd *nespd,
- u32 stag, u32 page_count)
-{
- struct nes_hw_cqp_wqe *cqp_wqe;
- struct nes_cqp_request *cqp_request;
- unsigned long flags;
- int ret;
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- u32 opcode = 0;
- u16 major_code;
- u64 region_length = page_count * PAGE_SIZE;
-
-
- cqp_request = nes_get_cqp_request(nesdev);
- if (cqp_request == NULL) {
- nes_debug(NES_DBG_MR, "Failed to get a cqp_request.\n");
- return -ENOMEM;
- }
- nes_debug(NES_DBG_MR, "alloc_fast_reg_mr: page_count = %d, "
- "region_length = %llu\n",
- page_count, region_length);
- cqp_request->waiting = 1;
- cqp_wqe = &cqp_request->cqp_wqe;
-
- spin_lock_irqsave(&nesadapter->pbl_lock, flags);
- if (nesadapter->free_4kpbl > 0) {
- nesadapter->free_4kpbl--;
- spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
- } else {
- /* No 4kpbl's available: */
- spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
- nes_debug(NES_DBG_MR, "Out of Pbls\n");
- nes_free_cqp_request(nesdev, cqp_request);
- return -ENOMEM;
- }
-
- opcode = NES_CQP_ALLOCATE_STAG | NES_CQP_STAG_MR |
- NES_CQP_STAG_PBL_BLK_SIZE | NES_CQP_STAG_VA_TO |
- NES_CQP_STAG_REM_ACC_EN;
- /*
- * The current OFED API does not support the zero based TO option.
- * If added then need to changed the NES_CQP_STAG_VA* option. Also,
- * the API does not support that ability to have the MR set for local
- * access only when created and not allow the SQ op to override. Given
- * this the remote enable must be set here.
- */
-
- nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, opcode);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_PBL_BLK_COUNT_IDX, 1);
-
- cqp_wqe->wqe_words[NES_CQP_STAG_WQE_LEN_HIGH_PD_IDX] =
- cpu_to_le32((u32)(region_length >> 8) & 0xff000000);
- cqp_wqe->wqe_words[NES_CQP_STAG_WQE_LEN_HIGH_PD_IDX] |=
- cpu_to_le32(nespd->pd_id & 0x00007fff);
-
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_STAG_IDX, stag);
- set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_VA_LOW_IDX, 0);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_LEN_LOW_IDX, 0);
- set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_PA_LOW_IDX, 0);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_PBL_LEN_IDX, (page_count * 8));
- cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |= cpu_to_le32(NES_CQP_STAG_PBL_BLK_SIZE);
- barrier();
-
- atomic_set(&cqp_request->refcount, 2);
- nes_post_cqp_request(nesdev, cqp_request);
-
- /* Wait for CQP */
- ret = wait_event_timeout(cqp_request->waitq,
- (0 != cqp_request->request_done),
- NES_EVENT_TIMEOUT);
-
- nes_debug(NES_DBG_MR, "Allocate STag 0x%08X completed, "
- "wait_event_timeout ret = %u, CQP Major:Minor codes = "
- "0x%04X:0x%04X.\n", stag, ret, cqp_request->major_code,
- cqp_request->minor_code);
- major_code = cqp_request->major_code;
- nes_put_cqp_request(nesdev, cqp_request);
-
- if (!ret || major_code) {
- spin_lock_irqsave(&nesadapter->pbl_lock, flags);
- nesadapter->free_4kpbl++;
- spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
- }
-
- if (!ret)
- return -ETIME;
- else if (major_code)
- return -EIO;
- return 0;
-}
-
-/*
- * nes_alloc_mr
- */
-static struct ib_mr *nes_alloc_mr(struct ib_pd *ibpd, enum ib_mr_type mr_type,
- u32 max_num_sg, struct ib_udata *udata)
-{
- struct nes_pd *nespd = to_nespd(ibpd);
- struct nes_vnic *nesvnic = to_nesvnic(ibpd->device);
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_adapter *nesadapter = nesdev->nesadapter;
-
- u32 next_stag_index;
- u8 stag_key = 0;
- u32 driver_key = 0;
- int err = 0;
- u32 stag_index = 0;
- struct nes_mr *nesmr;
- u32 stag;
- int ret;
- struct ib_mr *ibmr;
-
- if (mr_type != IB_MR_TYPE_MEM_REG)
- return ERR_PTR(-EINVAL);
-
- if (max_num_sg > (NES_4K_PBL_CHUNK_SIZE / sizeof(u64)))
- return ERR_PTR(-E2BIG);
-
-/*
- * Note: Set to always use a fixed length single page entry PBL. This is to allow
- * for the fast_reg_mr operation to always know the size of the PBL.
- */
- if (max_num_sg > (NES_4K_PBL_CHUNK_SIZE / sizeof(u64)))
- return ERR_PTR(-E2BIG);
-
- get_random_bytes(&next_stag_index, sizeof(next_stag_index));
- stag_key = (u8)next_stag_index;
- next_stag_index >>= 8;
- next_stag_index %= nesadapter->max_mr;
-
- err = nes_alloc_resource(nesadapter, nesadapter->allocated_mrs,
- nesadapter->max_mr, &stag_index,
- &next_stag_index, NES_RESOURCE_FAST_MR);
- if (err)
- return ERR_PTR(err);
-
- nesmr = kzalloc(sizeof(*nesmr), GFP_KERNEL);
- if (!nesmr) {
- nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
- return ERR_PTR(-ENOMEM);
- }
-
- stag = stag_index << 8;
- stag |= driver_key;
- stag += (u32)stag_key;
-
- nes_debug(NES_DBG_MR, "Allocating STag 0x%08X index = 0x%08X\n",
- stag, stag_index);
-
- ret = alloc_fast_reg_mr(nesdev, nespd, stag, max_num_sg);
-
- if (ret == 0) {
- nesmr->ibmr.rkey = stag;
- nesmr->ibmr.lkey = stag;
- nesmr->mode = IWNES_MEMREG_TYPE_FMEM;
- ibmr = &nesmr->ibmr;
- } else {
- kfree(nesmr);
- nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
- return ERR_PTR(-ENOMEM);
- }
-
- nesmr->pages = pci_alloc_consistent(nesdev->pcidev,
- max_num_sg * sizeof(u64),
- &nesmr->paddr);
- if (!nesmr->paddr)
- goto err;
-
- nesmr->max_pages = max_num_sg;
-
- return ibmr;
-
-err:
- nes_dereg_mr(ibmr, udata);
-
- return ERR_PTR(-ENOMEM);
-}
-
-static int nes_set_page(struct ib_mr *ibmr, u64 addr)
-{
- struct nes_mr *nesmr = to_nesmr(ibmr);
-
- if (unlikely(nesmr->npages == nesmr->max_pages))
- return -ENOMEM;
-
- nesmr->pages[nesmr->npages++] = cpu_to_le64(addr);
-
- return 0;
-}
-
-static int nes_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg,
- int sg_nents, unsigned int *sg_offset)
-{
- struct nes_mr *nesmr = to_nesmr(ibmr);
-
- nesmr->npages = 0;
-
- return ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset, nes_set_page);
-}
-
-/**
- * nes_query_device
- */
-static int nes_query_device(struct ib_device *ibdev, struct ib_device_attr *props,
- struct ib_udata *uhw)
-{
- struct nes_vnic *nesvnic = to_nesvnic(ibdev);
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_ib_device *nesibdev = nesvnic->nesibdev;
-
- if (uhw->inlen || uhw->outlen)
- return -EINVAL;
-
- memset(props, 0, sizeof(*props));
- memcpy(&props->sys_image_guid, nesvnic->netdev->dev_addr, 6);
-
- props->fw_ver = nesdev->nesadapter->firmware_version;
- props->device_cap_flags = nesdev->nesadapter->device_cap_flags;
- props->vendor_id = nesdev->nesadapter->vendor_id;
- props->vendor_part_id = nesdev->nesadapter->vendor_part_id;
- props->hw_ver = nesdev->nesadapter->hw_rev;
- props->max_mr_size = 0x80000000;
- props->max_qp = nesibdev->max_qp;
- props->max_qp_wr = nesdev->nesadapter->max_qp_wr - 2;
- props->max_send_sge = nesdev->nesadapter->max_sge;
- props->max_recv_sge = nesdev->nesadapter->max_sge;
- props->max_cq = nesibdev->max_cq;
- props->max_cqe = nesdev->nesadapter->max_cqe;
- props->max_mr = nesibdev->max_mr;
- props->max_mw = nesibdev->max_mr;
- props->max_pd = nesibdev->max_pd;
- props->max_sge_rd = 1;
- switch (nesdev->nesadapter->max_irrq_wr) {
- case 0:
- props->max_qp_rd_atom = 2;
- break;
- case 1:
- props->max_qp_rd_atom = 8;
- break;
- case 2:
- props->max_qp_rd_atom = 32;
- break;
- case 3:
- props->max_qp_rd_atom = 64;
- break;
- default:
- props->max_qp_rd_atom = 0;
- }
- props->max_qp_init_rd_atom = props->max_qp_rd_atom;
- props->atomic_cap = IB_ATOMIC_NONE;
- props->max_map_per_fmr = 1;
-
- return 0;
-}
-
-
-/**
- * nes_query_port
- */
-static int nes_query_port(struct ib_device *ibdev, u8 port, struct ib_port_attr *props)
-{
- struct nes_vnic *nesvnic = to_nesvnic(ibdev);
- struct net_device *netdev = nesvnic->netdev;
-
- /* props being zeroed by the caller, avoid zeroing it here */
-
- props->max_mtu = IB_MTU_4096;
- props->active_mtu = ib_mtu_int_to_enum(netdev->mtu);
-
- props->lid = 1;
- if (netif_queue_stopped(netdev))
- props->state = IB_PORT_DOWN;
- else if (nesvnic->linkup)
- props->state = IB_PORT_ACTIVE;
- else
- props->state = IB_PORT_DOWN;
- props->port_cap_flags = IB_PORT_CM_SUP | IB_PORT_REINIT_SUP |
- IB_PORT_VENDOR_CLASS_SUP | IB_PORT_BOOT_MGMT_SUP;
- props->gid_tbl_len = 1;
- props->pkey_tbl_len = 1;
- props->active_width = IB_WIDTH_4X;
- props->active_speed = IB_SPEED_SDR;
- props->max_msg_sz = 0x80000000;
-
- return 0;
-}
-
-/**
- * nes_query_pkey
- */
-static int nes_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey)
-{
- *pkey = 0;
- return 0;
-}
-
-
-/**
- * nes_query_gid
- */
-static int nes_query_gid(struct ib_device *ibdev, u8 port,
- int index, union ib_gid *gid)
-{
- struct nes_vnic *nesvnic = to_nesvnic(ibdev);
-
- memset(&(gid->raw[0]), 0, sizeof(gid->raw));
- memcpy(&(gid->raw[0]), nesvnic->netdev->dev_addr, 6);
-
- return 0;
-}
-
-
-/**
- * nes_alloc_ucontext - Allocate the user context data structure. This keeps track
- * of all objects associated with a particular user-mode client.
- */
-static int nes_alloc_ucontext(struct ib_ucontext *uctx, struct ib_udata *udata)
-{
- struct ib_device *ibdev = uctx->device;
- struct nes_vnic *nesvnic = to_nesvnic(ibdev);
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- struct nes_alloc_ucontext_req req;
- struct nes_alloc_ucontext_resp uresp = {};
- struct nes_ucontext *nes_ucontext = to_nesucontext(uctx);
- struct nes_ib_device *nesibdev = nesvnic->nesibdev;
-
-
- if (ib_copy_from_udata(&req, udata, sizeof(struct nes_alloc_ucontext_req))) {
- printk(KERN_ERR PFX "Invalid structure size on allocate user context.\n");
- return -EINVAL;
- }
-
- if (req.userspace_ver != NES_ABI_USERSPACE_VER) {
- printk(KERN_ERR PFX "Invalid userspace driver version detected. Detected version %d, should be %d\n",
- req.userspace_ver, NES_ABI_USERSPACE_VER);
- return -EINVAL;
- }
-
-
- uresp.max_qps = nesibdev->max_qp;
- uresp.max_pds = nesibdev->max_pd;
- uresp.wq_size = nesdev->nesadapter->max_qp_wr * 2;
- uresp.virtwq = nesadapter->virtwq;
- uresp.kernel_ver = NES_ABI_KERNEL_VER;
-
- nes_ucontext->nesdev = nesdev;
- nes_ucontext->mmap_wq_offset = uresp.max_pds;
- nes_ucontext->mmap_cq_offset = nes_ucontext->mmap_wq_offset +
- ((sizeof(struct nes_hw_qp_wqe) * uresp.max_qps * 2) + PAGE_SIZE-1) /
- PAGE_SIZE;
-
-
- if (ib_copy_to_udata(udata, &uresp, sizeof(uresp)))
- return -EFAULT;
-
- INIT_LIST_HEAD(&nes_ucontext->cq_reg_mem_list);
- INIT_LIST_HEAD(&nes_ucontext->qp_reg_mem_list);
- return 0;
-}
-
-/**
- * nes_dealloc_ucontext
- */
-static void nes_dealloc_ucontext(struct ib_ucontext *context)
-{
- return;
-}
-
-/**
- * nes_mmap
- */
-static int nes_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
-{
- unsigned long index;
- struct nes_vnic *nesvnic = to_nesvnic(context->device);
- struct nes_device *nesdev = nesvnic->nesdev;
- /* struct nes_adapter *nesadapter = nesdev->nesadapter; */
- struct nes_ucontext *nes_ucontext;
- struct nes_qp *nesqp;
-
- nes_ucontext = to_nesucontext(context);
-
-
- if (vma->vm_pgoff >= nes_ucontext->mmap_wq_offset) {
- index = (vma->vm_pgoff - nes_ucontext->mmap_wq_offset) * PAGE_SIZE;
- index /= ((sizeof(struct nes_hw_qp_wqe) * nesdev->nesadapter->max_qp_wr * 2) +
- PAGE_SIZE-1) & (~(PAGE_SIZE-1));
- if (!test_bit(index, nes_ucontext->allocated_wqs)) {
- nes_debug(NES_DBG_MMAP, "wq %lu not allocated\n", index);
- return -EFAULT;
- }
- nesqp = nes_ucontext->mmap_nesqp[index];
- if (nesqp == NULL) {
- nes_debug(NES_DBG_MMAP, "wq %lu has a NULL QP base.\n", index);
- return -EFAULT;
- }
- if (remap_pfn_range(vma, vma->vm_start,
- virt_to_phys(nesqp->hwqp.sq_vbase) >> PAGE_SHIFT,
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot)) {
- nes_debug(NES_DBG_MMAP, "remap_pfn_range failed.\n");
- return -EAGAIN;
- }
- vma->vm_private_data = nesqp;
- return 0;
- } else {
- index = vma->vm_pgoff;
- if (!test_bit(index, nes_ucontext->allocated_doorbells))
- return -EFAULT;
-
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- if (io_remap_pfn_range(vma, vma->vm_start,
- (nesdev->doorbell_start +
- ((nes_ucontext->mmap_db_index[index] - nesdev->base_doorbell_index) * 4096))
- >> PAGE_SHIFT, PAGE_SIZE, vma->vm_page_prot))
- return -EAGAIN;
- vma->vm_private_data = nes_ucontext;
- return 0;
- }
-
- return -ENOSYS;
-}
-
-
-/**
- * nes_alloc_pd
- */
-static int nes_alloc_pd(struct ib_pd *pd, struct ib_udata *udata)
-{
- struct ib_device *ibdev = pd->device;
- struct nes_pd *nespd = to_nespd(pd);
- struct nes_vnic *nesvnic = to_nesvnic(ibdev);
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- struct nes_alloc_pd_resp uresp;
- u32 pd_num = 0;
- int err;
- struct nes_ucontext *nesucontext = rdma_udata_to_drv_context(
- udata, struct nes_ucontext, ibucontext);
-
- nes_debug(
- NES_DBG_PD,
- "nesvnic=%p, netdev=%p %s, ibdev=%p, context=%p, netdev refcnt=%u\n",
- nesvnic, nesdev->netdev[0], nesdev->netdev[0]->name, ibdev,
- &nesucontext->ibucontext, netdev_refcnt_read(nesvnic->netdev));
-
- err = nes_alloc_resource(nesadapter, nesadapter->allocated_pds,
- nesadapter->max_pd, &pd_num, &nesadapter->next_pd, NES_RESOURCE_PD);
- if (err)
- return err;
-
- nes_debug(NES_DBG_PD, "Allocating PD (%p) for ib device %s\n",
- nespd, dev_name(&nesvnic->nesibdev->ibdev.dev));
-
- nespd->pd_id = (pd_num << (PAGE_SHIFT-12)) + nesadapter->base_pd;
-
- if (udata) {
- nespd->mmap_db_index = find_next_zero_bit(nesucontext->allocated_doorbells,
- NES_MAX_USER_DB_REGIONS, nesucontext->first_free_db);
- nes_debug(NES_DBG_PD, "find_first_zero_biton doorbells returned %u, mapping pd_id %u.\n",
- nespd->mmap_db_index, nespd->pd_id);
- if (nespd->mmap_db_index >= NES_MAX_USER_DB_REGIONS) {
- nes_debug(NES_DBG_PD, "mmap_db_index > MAX\n");
- nes_free_resource(nesadapter, nesadapter->allocated_pds, pd_num);
- return -ENOMEM;
- }
-
- uresp.pd_id = nespd->pd_id;
- uresp.mmap_db_index = nespd->mmap_db_index;
- if (ib_copy_to_udata(udata, &uresp, sizeof (struct nes_alloc_pd_resp))) {
- nes_free_resource(nesadapter, nesadapter->allocated_pds, pd_num);
- return -EFAULT;
- }
-
- set_bit(nespd->mmap_db_index, nesucontext->allocated_doorbells);
- nesucontext->mmap_db_index[nespd->mmap_db_index] = nespd->pd_id;
- nesucontext->first_free_db = nespd->mmap_db_index + 1;
- }
-
- nes_debug(NES_DBG_PD, "PD%u structure located @%p.\n", nespd->pd_id, nespd);
- return 0;
-}
-
-
-/**
- * nes_dealloc_pd
- */
-static void nes_dealloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
-{
- struct nes_ucontext *nesucontext;
- struct nes_pd *nespd = to_nespd(ibpd);
- struct nes_vnic *nesvnic = to_nesvnic(ibpd->device);
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_adapter *nesadapter = nesdev->nesadapter;
-
- if (udata) {
- nesucontext =
- rdma_udata_to_drv_context(
- udata,
- struct nes_ucontext,
- ibucontext);
- nes_debug(NES_DBG_PD, "Clearing bit %u from allocated doorbells\n",
- nespd->mmap_db_index);
- clear_bit(nespd->mmap_db_index, nesucontext->allocated_doorbells);
- nesucontext->mmap_db_index[nespd->mmap_db_index] = 0;
- if (nesucontext->first_free_db > nespd->mmap_db_index) {
- nesucontext->first_free_db = nespd->mmap_db_index;
- }
- }
-
- nes_debug(NES_DBG_PD, "Deallocating PD%u structure located @%p.\n",
- nespd->pd_id, nespd);
- nes_free_resource(nesadapter, nesadapter->allocated_pds,
- (nespd->pd_id-nesadapter->base_pd)>>(PAGE_SHIFT-12));
-}
-
-
-/**
- * nes_get_encoded_size
- */
-static inline u8 nes_get_encoded_size(int *size)
-{
- u8 encoded_size = 0;
- if (*size <= 32) {
- *size = 32;
- encoded_size = 1;
- } else if (*size <= 128) {
- *size = 128;
- encoded_size = 2;
- } else if (*size <= 512) {
- *size = 512;
- encoded_size = 3;
- }
- return (encoded_size);
-}
-
-
-
-/**
- * nes_setup_virt_qp
- */
-static int nes_setup_virt_qp(struct nes_qp *nesqp, struct nes_pbl *nespbl,
- struct nes_vnic *nesvnic, int sq_size, int rq_size)
-{
- unsigned long flags;
- void *mem;
- __le64 *pbl = NULL;
- __le64 *tpbl;
- __le64 *pblbuffer;
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- u32 pbl_entries;
- u8 rq_pbl_entries;
- u8 sq_pbl_entries;
-
- pbl_entries = nespbl->pbl_size >> 3;
- nes_debug(NES_DBG_QP, "Userspace PBL, pbl_size=%u, pbl_entries = %d pbl_vbase=%p, pbl_pbase=%lx\n",
- nespbl->pbl_size, pbl_entries,
- (void *)nespbl->pbl_vbase,
- (unsigned long) nespbl->pbl_pbase);
- pbl = (__le64 *) nespbl->pbl_vbase; /* points to first pbl entry */
- /* now lets set the sq_vbase as well as rq_vbase addrs we will assign */
- /* the first pbl to be fro the rq_vbase... */
- rq_pbl_entries = (rq_size * sizeof(struct nes_hw_qp_wqe)) >> 12;
- sq_pbl_entries = (sq_size * sizeof(struct nes_hw_qp_wqe)) >> 12;
- nesqp->hwqp.sq_pbase = (le32_to_cpu(((__le32 *)pbl)[0])) | ((u64)((le32_to_cpu(((__le32 *)pbl)[1]))) << 32);
- if (!nespbl->page) {
- nes_debug(NES_DBG_QP, "QP nespbl->page is NULL \n");
- kfree(nespbl);
- return -ENOMEM;
- }
-
- nesqp->hwqp.sq_vbase = kmap(nespbl->page);
- nesqp->page = nespbl->page;
- if (!nesqp->hwqp.sq_vbase) {
- nes_debug(NES_DBG_QP, "QP sq_vbase kmap failed\n");
- kfree(nespbl);
- return -ENOMEM;
- }
-
- /* Now to get to sq.. we need to calculate how many */
- /* PBL entries were used by the rq.. */
- pbl += sq_pbl_entries;
- nesqp->hwqp.rq_pbase = (le32_to_cpu(((__le32 *)pbl)[0])) | ((u64)((le32_to_cpu(((__le32 *)pbl)[1]))) << 32);
- /* nesqp->hwqp.rq_vbase = bus_to_virt(*pbl); */
- /*nesqp->hwqp.rq_vbase = phys_to_virt(*pbl); */
-
- nes_debug(NES_DBG_QP, "QP sq_vbase= %p sq_pbase=%lx rq_vbase=%p rq_pbase=%lx\n",
- nesqp->hwqp.sq_vbase, (unsigned long) nesqp->hwqp.sq_pbase,
- nesqp->hwqp.rq_vbase, (unsigned long) nesqp->hwqp.rq_pbase);
- spin_lock_irqsave(&nesadapter->pbl_lock, flags);
- if (!nesadapter->free_256pbl) {
- pci_free_consistent(nesdev->pcidev, nespbl->pbl_size, nespbl->pbl_vbase,
- nespbl->pbl_pbase);
- spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
- kunmap(nesqp->page);
- kfree(nespbl);
- return -ENOMEM;
- }
- nesadapter->free_256pbl--;
- spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
-
- nesqp->pbl_vbase = pci_alloc_consistent(nesdev->pcidev, 256, &nesqp->pbl_pbase);
- pblbuffer = nesqp->pbl_vbase;
- if (!nesqp->pbl_vbase) {
- /* memory allocated during nes_reg_user_mr() */
- pci_free_consistent(nesdev->pcidev, nespbl->pbl_size, nespbl->pbl_vbase,
- nespbl->pbl_pbase);
- kfree(nespbl);
- spin_lock_irqsave(&nesadapter->pbl_lock, flags);
- nesadapter->free_256pbl++;
- spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
- kunmap(nesqp->page);
- return -ENOMEM;
- }
- memset(nesqp->pbl_vbase, 0, 256);
- /* fill in the page address in the pbl buffer.. */
- tpbl = pblbuffer + 16;
- pbl = (__le64 *)nespbl->pbl_vbase;
- while (sq_pbl_entries--)
- *tpbl++ = *pbl++;
- tpbl = pblbuffer;
- while (rq_pbl_entries--)
- *tpbl++ = *pbl++;
-
- /* done with memory allocated during nes_reg_user_mr() */
- pci_free_consistent(nesdev->pcidev, nespbl->pbl_size, nespbl->pbl_vbase,
- nespbl->pbl_pbase);
- kfree(nespbl);
-
- nesqp->qp_mem_size =
- max((u32)sizeof(struct nes_qp_context), ((u32)256)) + 256; /* this is Q2 */
- /* Round up to a multiple of a page */
- nesqp->qp_mem_size += PAGE_SIZE - 1;
- nesqp->qp_mem_size &= ~(PAGE_SIZE - 1);
-
- mem = pci_alloc_consistent(nesdev->pcidev, nesqp->qp_mem_size,
- &nesqp->hwqp.q2_pbase);
-
- if (!mem) {
- pci_free_consistent(nesdev->pcidev, 256, nesqp->pbl_vbase, nesqp->pbl_pbase);
- nesqp->pbl_vbase = NULL;
- spin_lock_irqsave(&nesadapter->pbl_lock, flags);
- nesadapter->free_256pbl++;
- spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
- kunmap(nesqp->page);
- return -ENOMEM;
- }
- nesqp->sq_kmapped = 1;
- nesqp->hwqp.q2_vbase = mem;
- mem += 256;
- memset(nesqp->hwqp.q2_vbase, 0, 256);
- nesqp->nesqp_context = mem;
- memset(nesqp->nesqp_context, 0, sizeof(*nesqp->nesqp_context));
- nesqp->nesqp_context_pbase = nesqp->hwqp.q2_pbase + 256;
-
- return 0;
-}
-
-
-/**
- * nes_setup_mmap_qp
- */
-static int nes_setup_mmap_qp(struct nes_qp *nesqp, struct nes_vnic *nesvnic,
- int sq_size, int rq_size)
-{
- void *mem;
- struct nes_device *nesdev = nesvnic->nesdev;
-
- nesqp->qp_mem_size = (sizeof(struct nes_hw_qp_wqe) * sq_size) +
- (sizeof(struct nes_hw_qp_wqe) * rq_size) +
- max((u32)sizeof(struct nes_qp_context), ((u32)256)) +
- 256; /* this is Q2 */
- /* Round up to a multiple of a page */
- nesqp->qp_mem_size += PAGE_SIZE - 1;
- nesqp->qp_mem_size &= ~(PAGE_SIZE - 1);
-
- mem = pci_alloc_consistent(nesdev->pcidev, nesqp->qp_mem_size,
- &nesqp->hwqp.sq_pbase);
- if (!mem)
- return -ENOMEM;
- nes_debug(NES_DBG_QP, "PCI consistent memory for "
- "host descriptor rings located @ %p (pa = 0x%08lX.) size = %u.\n",
- mem, (unsigned long)nesqp->hwqp.sq_pbase, nesqp->qp_mem_size);
-
- memset(mem, 0, nesqp->qp_mem_size);
-
- nesqp->hwqp.sq_vbase = mem;
- mem += sizeof(struct nes_hw_qp_wqe) * sq_size;
-
- nesqp->hwqp.rq_vbase = mem;
- nesqp->hwqp.rq_pbase = nesqp->hwqp.sq_pbase +
- sizeof(struct nes_hw_qp_wqe) * sq_size;
- mem += sizeof(struct nes_hw_qp_wqe) * rq_size;
-
- nesqp->hwqp.q2_vbase = mem;
- nesqp->hwqp.q2_pbase = nesqp->hwqp.rq_pbase +
- sizeof(struct nes_hw_qp_wqe) * rq_size;
- mem += 256;
- memset(nesqp->hwqp.q2_vbase, 0, 256);
-
- nesqp->nesqp_context = mem;
- nesqp->nesqp_context_pbase = nesqp->hwqp.q2_pbase + 256;
- memset(nesqp->nesqp_context, 0, sizeof(*nesqp->nesqp_context));
- return 0;
-}
-
-
-/**
- * nes_free_qp_mem() is to free up the qp's pci_alloc_consistent() memory.
- */
-static void nes_free_qp_mem(struct nes_device *nesdev,
- struct nes_qp *nesqp, int virt_wqs)
-{
- unsigned long flags;
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- if (!virt_wqs) {
- pci_free_consistent(nesdev->pcidev, nesqp->qp_mem_size,
- nesqp->hwqp.sq_vbase, nesqp->hwqp.sq_pbase);
- }else {
- spin_lock_irqsave(&nesadapter->pbl_lock, flags);
- nesadapter->free_256pbl++;
- spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
- pci_free_consistent(nesdev->pcidev, nesqp->qp_mem_size, nesqp->hwqp.q2_vbase, nesqp->hwqp.q2_pbase);
- pci_free_consistent(nesdev->pcidev, 256, nesqp->pbl_vbase, nesqp->pbl_pbase );
- nesqp->pbl_vbase = NULL;
- if (nesqp->sq_kmapped) {
- nesqp->sq_kmapped = 0;
- kunmap(nesqp->page);
- }
- }
-}
-
-
-/**
- * nes_create_qp
- */
-static struct ib_qp *nes_create_qp(struct ib_pd *ibpd,
- struct ib_qp_init_attr *init_attr, struct ib_udata *udata)
-{
- u64 u64temp= 0;
- u64 u64nesqp = 0;
- struct nes_pd *nespd = to_nespd(ibpd);
- struct nes_vnic *nesvnic = to_nesvnic(ibpd->device);
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- struct nes_qp *nesqp;
- struct nes_cq *nescq;
- struct nes_ucontext *nes_ucontext = rdma_udata_to_drv_context(
- udata, struct nes_ucontext, ibucontext);
- struct nes_hw_cqp_wqe *cqp_wqe;
- struct nes_cqp_request *cqp_request;
- struct nes_create_qp_req req;
- struct nes_create_qp_resp uresp;
- struct nes_pbl *nespbl = NULL;
- u32 qp_num = 0;
- u32 opcode = 0;
- /* u32 counter = 0; */
- void *mem;
- unsigned long flags;
- int ret;
- int err;
- int virt_wqs = 0;
- int sq_size;
- int rq_size;
- u8 sq_encoded_size;
- u8 rq_encoded_size;
- /* int counter; */
-
- if (init_attr->create_flags)
- return ERR_PTR(-EINVAL);
-
- atomic_inc(&qps_created);
- switch (init_attr->qp_type) {
- case IB_QPT_RC:
- if (nes_drv_opt & NES_DRV_OPT_NO_INLINE_DATA) {
- init_attr->cap.max_inline_data = 0;
- } else {
- init_attr->cap.max_inline_data = 64;
- }
- sq_size = init_attr->cap.max_send_wr;
- rq_size = init_attr->cap.max_recv_wr;
-
- /* check if the encoded sizes are OK or not... */
- sq_encoded_size = nes_get_encoded_size(&sq_size);
- rq_encoded_size = nes_get_encoded_size(&rq_size);
-
- if ((!sq_encoded_size) || (!rq_encoded_size)) {
- nes_debug(NES_DBG_QP, "ERROR bad rq (%u) or sq (%u) size\n",
- rq_size, sq_size);
- return ERR_PTR(-EINVAL);
- }
-
- init_attr->cap.max_send_wr = sq_size -2;
- init_attr->cap.max_recv_wr = rq_size -1;
- nes_debug(NES_DBG_QP, "RQ size=%u, SQ Size=%u\n", rq_size, sq_size);
-
- ret = nes_alloc_resource(nesadapter, nesadapter->allocated_qps,
- nesadapter->max_qp, &qp_num, &nesadapter->next_qp, NES_RESOURCE_QP);
- if (ret) {
- return ERR_PTR(ret);
- }
-
- /* Need 512 (actually now 1024) byte alignment on this structure */
- mem = kzalloc(sizeof(*nesqp)+NES_SW_CONTEXT_ALIGN-1, GFP_KERNEL);
- if (!mem) {
- nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
- return ERR_PTR(-ENOMEM);
- }
- u64nesqp = (unsigned long)mem;
- u64nesqp += ((u64)NES_SW_CONTEXT_ALIGN) - 1;
- u64temp = ((u64)NES_SW_CONTEXT_ALIGN) - 1;
- u64nesqp &= ~u64temp;
- nesqp = (struct nes_qp *)(unsigned long)u64nesqp;
- /* nes_debug(NES_DBG_QP, "nesqp=%p, allocated buffer=%p. Rounded to closest %u\n",
- nesqp, mem, NES_SW_CONTEXT_ALIGN); */
- nesqp->allocated_buffer = mem;
-
- if (udata) {
- if (ib_copy_from_udata(&req, udata, sizeof(struct nes_create_qp_req))) {
- nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
- kfree(nesqp->allocated_buffer);
- nes_debug(NES_DBG_QP, "ib_copy_from_udata() Failed \n");
- return ERR_PTR(-EFAULT);
- }
- if (req.user_wqe_buffers) {
- virt_wqs = 1;
- }
- if (req.user_qp_buffer)
- nesqp->nesuqp_addr = req.user_qp_buffer;
-
- nesqp->user_mode = 1;
- if (virt_wqs) {
- err = 1;
- list_for_each_entry(nespbl, &nes_ucontext->qp_reg_mem_list, list) {
- if (nespbl->user_base == (unsigned long )req.user_wqe_buffers) {
- list_del(&nespbl->list);
- err = 0;
- nes_debug(NES_DBG_QP, "Found PBL for virtual QP. nespbl=%p. user_base=0x%lx\n",
- nespbl, nespbl->user_base);
- break;
- }
- }
- if (err) {
- nes_debug(NES_DBG_QP, "Didn't Find PBL for virtual QP. address = %llx.\n",
- (long long unsigned int)req.user_wqe_buffers);
- nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
- kfree(nesqp->allocated_buffer);
- return ERR_PTR(-EFAULT);
- }
- }
-
- nesqp->mmap_sq_db_index =
- find_next_zero_bit(nes_ucontext->allocated_wqs,
- NES_MAX_USER_WQ_REGIONS, nes_ucontext->first_free_wq);
- /* nes_debug(NES_DBG_QP, "find_first_zero_biton wqs returned %u\n",
- nespd->mmap_db_index); */
- if (nesqp->mmap_sq_db_index >= NES_MAX_USER_WQ_REGIONS) {
- nes_debug(NES_DBG_QP,
- "db index > max user regions, failing create QP\n");
- nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
- if (virt_wqs) {
- pci_free_consistent(nesdev->pcidev, nespbl->pbl_size, nespbl->pbl_vbase,
- nespbl->pbl_pbase);
- kfree(nespbl);
- }
- kfree(nesqp->allocated_buffer);
- return ERR_PTR(-ENOMEM);
- }
- set_bit(nesqp->mmap_sq_db_index, nes_ucontext->allocated_wqs);
- nes_ucontext->mmap_nesqp[nesqp->mmap_sq_db_index] = nesqp;
- nes_ucontext->first_free_wq = nesqp->mmap_sq_db_index + 1;
- }
- err = (!virt_wqs) ? nes_setup_mmap_qp(nesqp, nesvnic, sq_size, rq_size) :
- nes_setup_virt_qp(nesqp, nespbl, nesvnic, sq_size, rq_size);
- if (err) {
- nes_debug(NES_DBG_QP,
- "error geting qp mem code = %d\n", err);
- nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
- kfree(nesqp->allocated_buffer);
- return ERR_PTR(-ENOMEM);
- }
-
- nesqp->hwqp.sq_size = sq_size;
- nesqp->hwqp.sq_encoded_size = sq_encoded_size;
- nesqp->hwqp.sq_head = 1;
- nesqp->hwqp.rq_size = rq_size;
- nesqp->hwqp.rq_encoded_size = rq_encoded_size;
- /* nes_debug(NES_DBG_QP, "nesqp->nesqp_context_pbase = %p\n",
- (void *)nesqp->nesqp_context_pbase);
- */
- nesqp->hwqp.qp_id = qp_num;
- nesqp->ibqp.qp_num = nesqp->hwqp.qp_id;
- nesqp->nespd = nespd;
-
- nescq = to_nescq(init_attr->send_cq);
- nesqp->nesscq = nescq;
- nescq = to_nescq(init_attr->recv_cq);
- nesqp->nesrcq = nescq;
-
- nesqp->nesqp_context->misc |= cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) <<
- NES_QPCONTEXT_MISC_PCI_FCN_SHIFT);
- nesqp->nesqp_context->misc |= cpu_to_le32((u32)nesqp->hwqp.rq_encoded_size <<
- NES_QPCONTEXT_MISC_RQ_SIZE_SHIFT);
- nesqp->nesqp_context->misc |= cpu_to_le32((u32)nesqp->hwqp.sq_encoded_size <<
- NES_QPCONTEXT_MISC_SQ_SIZE_SHIFT);
- if (!udata) {
- nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_PRIV_EN);
- nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_FAST_REGISTER_EN);
- }
- nesqp->nesqp_context->cqs = cpu_to_le32(nesqp->nesscq->hw_cq.cq_number +
- ((u32)nesqp->nesrcq->hw_cq.cq_number << 16));
- u64temp = (u64)nesqp->hwqp.sq_pbase;
- nesqp->nesqp_context->sq_addr_low = cpu_to_le32((u32)u64temp);
- nesqp->nesqp_context->sq_addr_high = cpu_to_le32((u32)(u64temp >> 32));
-
-
- if (!virt_wqs) {
- u64temp = (u64)nesqp->hwqp.sq_pbase;
- nesqp->nesqp_context->sq_addr_low = cpu_to_le32((u32)u64temp);
- nesqp->nesqp_context->sq_addr_high = cpu_to_le32((u32)(u64temp >> 32));
- u64temp = (u64)nesqp->hwqp.rq_pbase;
- nesqp->nesqp_context->rq_addr_low = cpu_to_le32((u32)u64temp);
- nesqp->nesqp_context->rq_addr_high = cpu_to_le32((u32)(u64temp >> 32));
- } else {
- u64temp = (u64)nesqp->pbl_pbase;
- nesqp->nesqp_context->rq_addr_low = cpu_to_le32((u32)u64temp);
- nesqp->nesqp_context->rq_addr_high = cpu_to_le32((u32)(u64temp >> 32));
- }
-
- /* nes_debug(NES_DBG_QP, "next_qp_nic_index=%u, using nic_index=%d\n",
- nesvnic->next_qp_nic_index,
- nesvnic->qp_nic_index[nesvnic->next_qp_nic_index]); */
- spin_lock_irqsave(&nesdev->cqp.lock, flags);
- nesqp->nesqp_context->misc2 |= cpu_to_le32(
- (u32)nesvnic->qp_nic_index[nesvnic->next_qp_nic_index] <<
- NES_QPCONTEXT_MISC2_NIC_INDEX_SHIFT);
- nesvnic->next_qp_nic_index++;
- if ((nesvnic->next_qp_nic_index > 3) ||
- (nesvnic->qp_nic_index[nesvnic->next_qp_nic_index] == 0xf)) {
- nesvnic->next_qp_nic_index = 0;
- }
- spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
-
- nesqp->nesqp_context->pd_index_wscale |= cpu_to_le32((u32)nesqp->nespd->pd_id << 16);
- u64temp = (u64)nesqp->hwqp.q2_pbase;
- nesqp->nesqp_context->q2_addr_low = cpu_to_le32((u32)u64temp);
- nesqp->nesqp_context->q2_addr_high = cpu_to_le32((u32)(u64temp >> 32));
- nesqp->nesqp_context->aeq_token_low = cpu_to_le32((u32)((unsigned long)(nesqp)));
- nesqp->nesqp_context->aeq_token_high = cpu_to_le32((u32)(upper_32_bits((unsigned long)(nesqp))));
- nesqp->nesqp_context->ird_ord_sizes = cpu_to_le32(NES_QPCONTEXT_ORDIRD_ALSMM |
- NES_QPCONTEXT_ORDIRD_AAH |
- ((((u32)nesadapter->max_irrq_wr) <<
- NES_QPCONTEXT_ORDIRD_IRDSIZE_SHIFT) & NES_QPCONTEXT_ORDIRD_IRDSIZE_MASK));
- if (disable_mpa_crc) {
- nes_debug(NES_DBG_QP, "Disabling MPA crc checking due to module option.\n");
- nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32(NES_QPCONTEXT_ORDIRD_RNMC);
- }
-
-
- /* Create the QP */
- cqp_request = nes_get_cqp_request(nesdev);
- if (cqp_request == NULL) {
- nes_debug(NES_DBG_QP, "Failed to get a cqp_request\n");
- nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
- nes_free_qp_mem(nesdev, nesqp,virt_wqs);
- kfree(nesqp->allocated_buffer);
- return ERR_PTR(-ENOMEM);
- }
- cqp_request->waiting = 1;
- cqp_wqe = &cqp_request->cqp_wqe;
-
- if (!virt_wqs) {
- opcode = NES_CQP_CREATE_QP | NES_CQP_QP_TYPE_IWARP |
- NES_CQP_QP_IWARP_STATE_IDLE;
- } else {
- opcode = NES_CQP_CREATE_QP | NES_CQP_QP_TYPE_IWARP | NES_CQP_QP_VIRT_WQS |
- NES_CQP_QP_IWARP_STATE_IDLE;
- }
- opcode |= NES_CQP_QP_CQS_VALID;
- nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, opcode);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX, nesqp->hwqp.qp_id);
-
- u64temp = (u64)nesqp->nesqp_context_pbase;
- set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_CONTEXT_LOW_IDX, u64temp);
-
- atomic_set(&cqp_request->refcount, 2);
- nes_post_cqp_request(nesdev, cqp_request);
-
- /* Wait for CQP */
- nes_debug(NES_DBG_QP, "Waiting for create iWARP QP%u to complete.\n",
- nesqp->hwqp.qp_id);
- ret = wait_event_timeout(cqp_request->waitq,
- (cqp_request->request_done != 0), NES_EVENT_TIMEOUT);
- nes_debug(NES_DBG_QP, "Create iwarp QP%u completed, wait_event_timeout ret=%u,"
- " nesdev->cqp_head = %u, nesdev->cqp.sq_tail = %u,"
- " CQP Major:Minor codes = 0x%04X:0x%04X.\n",
- nesqp->hwqp.qp_id, ret, nesdev->cqp.sq_head, nesdev->cqp.sq_tail,
- cqp_request->major_code, cqp_request->minor_code);
- if ((!ret) || (cqp_request->major_code)) {
- nes_put_cqp_request(nesdev, cqp_request);
- nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
- nes_free_qp_mem(nesdev, nesqp,virt_wqs);
- kfree(nesqp->allocated_buffer);
- if (!ret) {
- return ERR_PTR(-ETIME);
- } else {
- return ERR_PTR(-EIO);
- }
- }
-
- nes_put_cqp_request(nesdev, cqp_request);
-
- if (udata) {
- uresp.mmap_sq_db_index = nesqp->mmap_sq_db_index;
- uresp.mmap_rq_db_index = 0;
- uresp.actual_sq_size = sq_size;
- uresp.actual_rq_size = rq_size;
- uresp.qp_id = nesqp->hwqp.qp_id;
- uresp.nes_drv_opt = nes_drv_opt;
- if (ib_copy_to_udata(udata, &uresp, sizeof uresp)) {
- nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
- nes_free_qp_mem(nesdev, nesqp,virt_wqs);
- kfree(nesqp->allocated_buffer);
- return ERR_PTR(-EFAULT);
- }
- }
-
- nes_debug(NES_DBG_QP, "QP%u structure located @%p.Size = %u.\n",
- nesqp->hwqp.qp_id, nesqp, (u32)sizeof(*nesqp));
- spin_lock_init(&nesqp->lock);
- nes_add_ref(&nesqp->ibqp);
- break;
- default:
- nes_debug(NES_DBG_QP, "Invalid QP type: %d\n", init_attr->qp_type);
- return ERR_PTR(-EINVAL);
- }
- init_completion(&nesqp->sq_drained);
- init_completion(&nesqp->rq_drained);
-
- nesqp->sig_all = (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR);
- timer_setup(&nesqp->terminate_timer, nes_terminate_timeout, 0);
-
- /* update the QP table */
- nesdev->nesadapter->qp_table[nesqp->hwqp.qp_id-NES_FIRST_QPN] = nesqp;
- nes_debug(NES_DBG_QP, "netdev refcnt=%u\n",
- netdev_refcnt_read(nesvnic->netdev));
-
- return &nesqp->ibqp;
-}
-
-/**
- * nes_clean_cq
- */
-static void nes_clean_cq(struct nes_qp *nesqp, struct nes_cq *nescq)
-{
- u32 cq_head;
- u32 lo;
- u32 hi;
- u64 u64temp;
- unsigned long flags = 0;
-
- spin_lock_irqsave(&nescq->lock, flags);
-
- cq_head = nescq->hw_cq.cq_head;
- while (le32_to_cpu(nescq->hw_cq.cq_vbase[cq_head].cqe_words[NES_CQE_OPCODE_IDX]) & NES_CQE_VALID) {
- rmb();
- lo = le32_to_cpu(nescq->hw_cq.cq_vbase[cq_head].cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX]);
- hi = le32_to_cpu(nescq->hw_cq.cq_vbase[cq_head].cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX]);
- u64temp = (((u64)hi) << 32) | ((u64)lo);
- u64temp &= ~(NES_SW_CONTEXT_ALIGN-1);
- if (u64temp == (u64)(unsigned long)nesqp) {
- /* Zero the context value so cqe will be ignored */
- nescq->hw_cq.cq_vbase[cq_head].cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX] = 0;
- nescq->hw_cq.cq_vbase[cq_head].cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX] = 0;
- }
-
- if (++cq_head >= nescq->hw_cq.cq_size)
- cq_head = 0;
- }
-
- spin_unlock_irqrestore(&nescq->lock, flags);
-}
-
-
-/**
- * nes_destroy_qp
- */
-static int nes_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
-{
- struct nes_qp *nesqp = to_nesqp(ibqp);
- struct nes_ucontext *nes_ucontext;
- struct ib_qp_attr attr;
- struct iw_cm_id *cm_id;
- struct iw_cm_event cm_event;
- int ret = 0;
-
- atomic_inc(&sw_qps_destroyed);
- nesqp->destroyed = 1;
-
- /* Blow away the connection if it exists. */
- if (nesqp->ibqp_state >= IB_QPS_INIT && nesqp->ibqp_state <= IB_QPS_RTS) {
- /* if (nesqp->ibqp_state == IB_QPS_RTS) { */
- attr.qp_state = IB_QPS_ERR;
- nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL);
- }
-
- if (((nesqp->ibqp_state == IB_QPS_INIT) ||
- (nesqp->ibqp_state == IB_QPS_RTR)) && (nesqp->cm_id)) {
- cm_id = nesqp->cm_id;
- cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
- cm_event.status = -ETIMEDOUT;
- cm_event.local_addr = cm_id->local_addr;
- cm_event.remote_addr = cm_id->remote_addr;
- cm_event.private_data = NULL;
- cm_event.private_data_len = 0;
-
- nes_debug(NES_DBG_QP, "Generating a CM Timeout Event for "
- "QP%u. cm_id = %p, refcount = %u. \n",
- nesqp->hwqp.qp_id, cm_id, atomic_read(&nesqp->refcount));
-
- cm_id->rem_ref(cm_id);
- ret = cm_id->event_handler(cm_id, &cm_event);
- if (ret)
- nes_debug(NES_DBG_QP, "OFA CM event_handler returned, ret=%d\n", ret);
- }
-
- if (nesqp->user_mode) {
- if (udata) {
- nes_ucontext =
- rdma_udata_to_drv_context(
- udata,
- struct nes_ucontext,
- ibucontext);
- clear_bit(nesqp->mmap_sq_db_index, nes_ucontext->allocated_wqs);
- nes_ucontext->mmap_nesqp[nesqp->mmap_sq_db_index] = NULL;
- if (nes_ucontext->first_free_wq > nesqp->mmap_sq_db_index) {
- nes_ucontext->first_free_wq = nesqp->mmap_sq_db_index;
- }
- }
- if (nesqp->pbl_pbase && nesqp->sq_kmapped) {
- nesqp->sq_kmapped = 0;
- kunmap(nesqp->page);
- }
- } else {
- /* Clean any pending completions from the cq(s) */
- if (nesqp->nesscq)
- nes_clean_cq(nesqp, nesqp->nesscq);
-
- if ((nesqp->nesrcq) && (nesqp->nesrcq != nesqp->nesscq))
- nes_clean_cq(nesqp, nesqp->nesrcq);
- }
- nes_rem_ref(&nesqp->ibqp);
- return 0;
-}
-
-
-/**
- * nes_create_cq
- */
-static struct ib_cq *nes_create_cq(struct ib_device *ibdev,
- const struct ib_cq_init_attr *attr,
- struct ib_udata *udata)
-{
- int entries = attr->cqe;
- u64 u64temp;
- struct nes_vnic *nesvnic = to_nesvnic(ibdev);
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- struct nes_cq *nescq;
- struct nes_ucontext *nes_ucontext = NULL;
- struct nes_cqp_request *cqp_request;
- void *mem = NULL;
- struct nes_hw_cqp_wqe *cqp_wqe;
- struct nes_pbl *nespbl = NULL;
- struct nes_create_cq_req req;
- struct nes_create_cq_resp resp;
- u32 cq_num = 0;
- u32 opcode = 0;
- u32 pbl_entries = 1;
- int err;
- unsigned long flags;
- int ret;
-
- if (attr->flags)
- return ERR_PTR(-EINVAL);
-
- if (entries > nesadapter->max_cqe)
- return ERR_PTR(-EINVAL);
-
- err = nes_alloc_resource(nesadapter, nesadapter->allocated_cqs,
- nesadapter->max_cq, &cq_num, &nesadapter->next_cq, NES_RESOURCE_CQ);
- if (err) {
- return ERR_PTR(err);
- }
-
- nescq = kzalloc(sizeof(struct nes_cq), GFP_KERNEL);
- if (!nescq) {
- nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
- return ERR_PTR(-ENOMEM);
- }
-
- nescq->hw_cq.cq_size = max(entries + 1, 5);
- nescq->hw_cq.cq_number = cq_num;
- nescq->ibcq.cqe = nescq->hw_cq.cq_size - 1;
-
- if (udata) {
- struct nes_ucontext *nes_ucontext = rdma_udata_to_drv_context(
- udata, struct nes_ucontext, ibucontext);
-
- if (ib_copy_from_udata(&req, udata, sizeof (struct nes_create_cq_req))) {
- nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
- kfree(nescq);
- return ERR_PTR(-EFAULT);
- }
- nesvnic->mcrq_ucontext = nes_ucontext;
- nes_ucontext->mcrqf = req.mcrqf;
- if (nes_ucontext->mcrqf) {
- if (nes_ucontext->mcrqf & 0x80000000)
- nescq->hw_cq.cq_number = nesvnic->nic.qp_id + 28 + 2 * ((nes_ucontext->mcrqf & 0xf) - 1);
- else if (nes_ucontext->mcrqf & 0x40000000)
- nescq->hw_cq.cq_number = nes_ucontext->mcrqf & 0xffff;
- else
- nescq->hw_cq.cq_number = nesvnic->mcrq_qp_id + nes_ucontext->mcrqf-1;
- nescq->mcrqf = nes_ucontext->mcrqf;
- nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
- }
- nes_debug(NES_DBG_CQ, "CQ Virtual Address = %08lX, size = %u.\n",
- (unsigned long)req.user_cq_buffer, entries);
- err = 1;
- list_for_each_entry(nespbl, &nes_ucontext->cq_reg_mem_list, list) {
- if (nespbl->user_base == (unsigned long )req.user_cq_buffer) {
- list_del(&nespbl->list);
- err = 0;
- nes_debug(NES_DBG_CQ, "Found PBL for virtual CQ. nespbl=%p.\n",
- nespbl);
- break;
- }
- }
- if (err) {
- nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
- kfree(nescq);
- return ERR_PTR(-EFAULT);
- }
-
- pbl_entries = nespbl->pbl_size >> 3;
- nescq->cq_mem_size = 0;
- } else {
- nescq->cq_mem_size = nescq->hw_cq.cq_size * sizeof(struct nes_hw_cqe);
- nes_debug(NES_DBG_CQ, "Attempting to allocate pci memory (%u entries, %u bytes) for CQ%u.\n",
- entries, nescq->cq_mem_size, nescq->hw_cq.cq_number);
-
- /* allocate the physical buffer space */
- mem = pci_zalloc_consistent(nesdev->pcidev, nescq->cq_mem_size,
- &nescq->hw_cq.cq_pbase);
- if (!mem) {
- printk(KERN_ERR PFX "Unable to allocate pci memory for cq\n");
- nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
- kfree(nescq);
- return ERR_PTR(-ENOMEM);
- }
-
- nescq->hw_cq.cq_vbase = mem;
- nescq->hw_cq.cq_head = 0;
- nes_debug(NES_DBG_CQ, "CQ%u virtual address @ %p, phys = 0x%08X\n",
- nescq->hw_cq.cq_number, nescq->hw_cq.cq_vbase,
- (u32)nescq->hw_cq.cq_pbase);
- }
-
- nescq->hw_cq.ce_handler = nes_iwarp_ce_handler;
- spin_lock_init(&nescq->lock);
-
- /* send CreateCQ request to CQP */
- cqp_request = nes_get_cqp_request(nesdev);
- if (cqp_request == NULL) {
- nes_debug(NES_DBG_CQ, "Failed to get a cqp_request.\n");
- if (!udata)
- pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size, mem,
- nescq->hw_cq.cq_pbase);
- else {
- pci_free_consistent(nesdev->pcidev, nespbl->pbl_size,
- nespbl->pbl_vbase, nespbl->pbl_pbase);
- kfree(nespbl);
- }
-
- nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
- kfree(nescq);
- return ERR_PTR(-ENOMEM);
- }
- cqp_request->waiting = 1;
- cqp_wqe = &cqp_request->cqp_wqe;
-
- opcode = NES_CQP_CREATE_CQ | NES_CQP_CQ_CEQ_VALID |
- NES_CQP_CQ_CHK_OVERFLOW |
- NES_CQP_CQ_CEQE_MASK | ((u32)nescq->hw_cq.cq_size << 16);
-
- spin_lock_irqsave(&nesadapter->pbl_lock, flags);
-
- if (pbl_entries != 1) {
- if (pbl_entries > 32) {
- /* use 4k pbl */
- nes_debug(NES_DBG_CQ, "pbl_entries=%u, use a 4k PBL\n", pbl_entries);
- if (nesadapter->free_4kpbl == 0) {
- spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
- nes_free_cqp_request(nesdev, cqp_request);
- if (!udata)
- pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size, mem,
- nescq->hw_cq.cq_pbase);
- else {
- pci_free_consistent(nesdev->pcidev, nespbl->pbl_size,
- nespbl->pbl_vbase, nespbl->pbl_pbase);
- kfree(nespbl);
- }
- nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
- kfree(nescq);
- return ERR_PTR(-ENOMEM);
- } else {
- opcode |= (NES_CQP_CQ_VIRT | NES_CQP_CQ_4KB_CHUNK);
- nescq->virtual_cq = 2;
- nesadapter->free_4kpbl--;
- }
- } else {
- /* use 256 byte pbl */
- nes_debug(NES_DBG_CQ, "pbl_entries=%u, use a 256 byte PBL\n", pbl_entries);
- if (nesadapter->free_256pbl == 0) {
- spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
- nes_free_cqp_request(nesdev, cqp_request);
- if (!udata)
- pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size, mem,
- nescq->hw_cq.cq_pbase);
- else {
- pci_free_consistent(nesdev->pcidev, nespbl->pbl_size,
- nespbl->pbl_vbase, nespbl->pbl_pbase);
- kfree(nespbl);
- }
- nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
- kfree(nescq);
- return ERR_PTR(-ENOMEM);
- } else {
- opcode |= NES_CQP_CQ_VIRT;
- nescq->virtual_cq = 1;
- nesadapter->free_256pbl--;
- }
- }
- }
-
- spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
-
- nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, opcode);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX,
- (nescq->hw_cq.cq_number | ((u32)nesdev->ceq_index << 16)));
-
- if (udata) {
- if (pbl_entries != 1)
- u64temp = (u64)nespbl->pbl_pbase;
- else
- u64temp = le64_to_cpu(nespbl->pbl_vbase[0]);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_DOORBELL_INDEX_HIGH_IDX,
- nes_ucontext->mmap_db_index[0]);
- } else {
- u64temp = (u64)nescq->hw_cq.cq_pbase;
- cqp_wqe->wqe_words[NES_CQP_CQ_WQE_DOORBELL_INDEX_HIGH_IDX] = 0;
- }
- set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_PBL_LOW_IDX, u64temp);
- cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] = 0;
- u64temp = (u64)(unsigned long)&nescq->hw_cq;
- cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX] =
- cpu_to_le32((u32)(u64temp >> 1));
- cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] =
- cpu_to_le32(((u32)((u64temp) >> 33)) & 0x7FFFFFFF);
-
- atomic_set(&cqp_request->refcount, 2);
- nes_post_cqp_request(nesdev, cqp_request);
-
- /* Wait for CQP */
- nes_debug(NES_DBG_CQ, "Waiting for create iWARP CQ%u to complete.\n",
- nescq->hw_cq.cq_number);
- ret = wait_event_timeout(cqp_request->waitq, (0 != cqp_request->request_done),
- NES_EVENT_TIMEOUT * 2);
- nes_debug(NES_DBG_CQ, "Create iWARP CQ%u completed, wait_event_timeout ret = %d.\n",
- nescq->hw_cq.cq_number, ret);
- if ((!ret) || (cqp_request->major_code)) {
- nes_put_cqp_request(nesdev, cqp_request);
- if (!udata)
- pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size, mem,
- nescq->hw_cq.cq_pbase);
- else {
- pci_free_consistent(nesdev->pcidev, nespbl->pbl_size,
- nespbl->pbl_vbase, nespbl->pbl_pbase);
- kfree(nespbl);
- }
- nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
- kfree(nescq);
- return ERR_PTR(-EIO);
- }
- nes_put_cqp_request(nesdev, cqp_request);
-
- if (udata) {
- /* free the nespbl */
- pci_free_consistent(nesdev->pcidev, nespbl->pbl_size, nespbl->pbl_vbase,
- nespbl->pbl_pbase);
- kfree(nespbl);
- resp.cq_id = nescq->hw_cq.cq_number;
- resp.cq_size = nescq->hw_cq.cq_size;
- resp.mmap_db_index = 0;
- if (ib_copy_to_udata(udata, &resp, sizeof resp - sizeof resp.reserved)) {
- nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
- kfree(nescq);
- return ERR_PTR(-EFAULT);
- }
- }
-
- return &nescq->ibcq;
-}
-
-
-/**
- * nes_destroy_cq
- */
-static int nes_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)
-{
- struct nes_cq *nescq;
- struct nes_device *nesdev;
- struct nes_vnic *nesvnic;
- struct nes_adapter *nesadapter;
- struct nes_hw_cqp_wqe *cqp_wqe;
- struct nes_cqp_request *cqp_request;
- unsigned long flags;
- u32 opcode = 0;
- int ret;
-
- if (ib_cq == NULL)
- return 0;
-
- nescq = to_nescq(ib_cq);
- nesvnic = to_nesvnic(ib_cq->device);
- nesdev = nesvnic->nesdev;
- nesadapter = nesdev->nesadapter;
-
- nes_debug(NES_DBG_CQ, "Destroy CQ%u\n", nescq->hw_cq.cq_number);
-
- /* Send DestroyCQ request to CQP */
- cqp_request = nes_get_cqp_request(nesdev);
- if (cqp_request == NULL) {
- nes_debug(NES_DBG_CQ, "Failed to get a cqp_request.\n");
- return -ENOMEM;
- }
- cqp_request->waiting = 1;
- cqp_wqe = &cqp_request->cqp_wqe;
- opcode = NES_CQP_DESTROY_CQ | (nescq->hw_cq.cq_size << 16);
- spin_lock_irqsave(&nesadapter->pbl_lock, flags);
- if (nescq->virtual_cq == 1) {
- nesadapter->free_256pbl++;
- if (nesadapter->free_256pbl > nesadapter->max_256pbl) {
- printk(KERN_ERR PFX "%s: free 256B PBLs(%u) has exceeded the max(%u)\n",
- __func__, nesadapter->free_256pbl, nesadapter->max_256pbl);
- }
- } else if (nescq->virtual_cq == 2) {
- nesadapter->free_4kpbl++;
- if (nesadapter->free_4kpbl > nesadapter->max_4kpbl) {
- printk(KERN_ERR PFX "%s: free 4K PBLs(%u) has exceeded the max(%u)\n",
- __func__, nesadapter->free_4kpbl, nesadapter->max_4kpbl);
- }
- opcode |= NES_CQP_CQ_4KB_CHUNK;
- }
-
- spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
-
- nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, opcode);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX,
- (nescq->hw_cq.cq_number | ((u32)PCI_FUNC(nesdev->pcidev->devfn) << 16)));
- if (!nescq->mcrqf)
- nes_free_resource(nesadapter, nesadapter->allocated_cqs, nescq->hw_cq.cq_number);
-
- atomic_set(&cqp_request->refcount, 2);
- nes_post_cqp_request(nesdev, cqp_request);
-
- /* Wait for CQP */
- nes_debug(NES_DBG_CQ, "Waiting for destroy iWARP CQ%u to complete.\n",
- nescq->hw_cq.cq_number);
- ret = wait_event_timeout(cqp_request->waitq, (0 != cqp_request->request_done),
- NES_EVENT_TIMEOUT);
- nes_debug(NES_DBG_CQ, "Destroy iWARP CQ%u completed, wait_event_timeout ret = %u,"
- " CQP Major:Minor codes = 0x%04X:0x%04X.\n",
- nescq->hw_cq.cq_number, ret, cqp_request->major_code,
- cqp_request->minor_code);
- if (!ret) {
- nes_debug(NES_DBG_CQ, "iWARP CQ%u destroy timeout expired\n",
- nescq->hw_cq.cq_number);
- ret = -ETIME;
- } else if (cqp_request->major_code) {
- nes_debug(NES_DBG_CQ, "iWARP CQ%u destroy failed\n",
- nescq->hw_cq.cq_number);
- ret = -EIO;
- } else {
- ret = 0;
- }
- nes_put_cqp_request(nesdev, cqp_request);
-
- if (nescq->cq_mem_size)
- pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size,
- nescq->hw_cq.cq_vbase, nescq->hw_cq.cq_pbase);
- kfree(nescq);
-
- return ret;
-}
-
-/**
- * root_256
- */
-static u32 root_256(struct nes_device *nesdev,
- struct nes_root_vpbl *root_vpbl,
- struct nes_root_vpbl *new_root,
- u16 pbl_count_4k)
-{
- u64 leaf_pbl;
- int i, j, k;
-
- if (pbl_count_4k == 1) {
- new_root->pbl_vbase = pci_alloc_consistent(nesdev->pcidev,
- 512, &new_root->pbl_pbase);
-
- if (new_root->pbl_vbase == NULL)
- return 0;
-
- leaf_pbl = (u64)root_vpbl->pbl_pbase;
- for (i = 0; i < 16; i++) {
- new_root->pbl_vbase[i].pa_low =
- cpu_to_le32((u32)leaf_pbl);
- new_root->pbl_vbase[i].pa_high =
- cpu_to_le32((u32)((((u64)leaf_pbl) >> 32)));
- leaf_pbl += 256;
- }
- } else {
- for (i = 3; i >= 0; i--) {
- j = i * 16;
- root_vpbl->pbl_vbase[j] = root_vpbl->pbl_vbase[i];
- leaf_pbl = le32_to_cpu(root_vpbl->pbl_vbase[j].pa_low) +
- (((u64)le32_to_cpu(root_vpbl->pbl_vbase[j].pa_high))
- << 32);
- for (k = 1; k < 16; k++) {
- leaf_pbl += 256;
- root_vpbl->pbl_vbase[j + k].pa_low =
- cpu_to_le32((u32)leaf_pbl);
- root_vpbl->pbl_vbase[j + k].pa_high =
- cpu_to_le32((u32)((((u64)leaf_pbl) >> 32)));
- }
- }
- }
-
- return 1;
-}
-
-
-/**
- * nes_reg_mr
- */
-static int nes_reg_mr(struct nes_device *nesdev, struct nes_pd *nespd,
- u32 stag, u64 region_length, struct nes_root_vpbl *root_vpbl,
- dma_addr_t single_buffer, u16 pbl_count_4k,
- u16 residual_page_count_4k, int acc, u64 *iova_start,
- u16 *actual_pbl_cnt, u8 *used_4k_pbls)
-{
- struct nes_hw_cqp_wqe *cqp_wqe;
- struct nes_cqp_request *cqp_request;
- unsigned long flags;
- int ret;
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- uint pg_cnt = 0;
- u16 pbl_count_256 = 0;
- u16 pbl_count = 0;
- u8 use_256_pbls = 0;
- u8 use_4k_pbls = 0;
- u16 use_two_level = (pbl_count_4k > 1) ? 1 : 0;
- struct nes_root_vpbl new_root = { 0, NULL, NULL };
- u32 opcode = 0;
- u16 major_code;
-
- /* Register the region with the adapter */
- cqp_request = nes_get_cqp_request(nesdev);
- if (cqp_request == NULL) {
- nes_debug(NES_DBG_MR, "Failed to get a cqp_request.\n");
- return -ENOMEM;
- }
- cqp_request->waiting = 1;
- cqp_wqe = &cqp_request->cqp_wqe;
-
- if (pbl_count_4k) {
- spin_lock_irqsave(&nesadapter->pbl_lock, flags);
-
- pg_cnt = ((pbl_count_4k - 1) * 512) + residual_page_count_4k;
- pbl_count_256 = (pg_cnt + 31) / 32;
- if (pg_cnt <= 32) {
- if (pbl_count_256 <= nesadapter->free_256pbl)
- use_256_pbls = 1;
- else if (pbl_count_4k <= nesadapter->free_4kpbl)
- use_4k_pbls = 1;
- } else if (pg_cnt <= 2048) {
- if (((pbl_count_4k + use_two_level) <= nesadapter->free_4kpbl) &&
- (nesadapter->free_4kpbl > (nesadapter->max_4kpbl >> 1))) {
- use_4k_pbls = 1;
- } else if ((pbl_count_256 + 1) <= nesadapter->free_256pbl) {
- use_256_pbls = 1;
- use_two_level = 1;
- } else if ((pbl_count_4k + use_two_level) <= nesadapter->free_4kpbl) {
- use_4k_pbls = 1;
- }
- } else {
- if ((pbl_count_4k + 1) <= nesadapter->free_4kpbl)
- use_4k_pbls = 1;
- }
-
- if (use_256_pbls) {
- pbl_count = pbl_count_256;
- nesadapter->free_256pbl -= pbl_count + use_two_level;
- } else if (use_4k_pbls) {
- pbl_count = pbl_count_4k;
- nesadapter->free_4kpbl -= pbl_count + use_two_level;
- } else {
- spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
- nes_debug(NES_DBG_MR, "Out of Pbls\n");
- nes_free_cqp_request(nesdev, cqp_request);
- return -ENOMEM;
- }
-
- spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
- }
-
- if (use_256_pbls && use_two_level) {
- if (root_256(nesdev, root_vpbl, &new_root, pbl_count_4k) == 1) {
- if (new_root.pbl_pbase != 0)
- root_vpbl = &new_root;
- } else {
- spin_lock_irqsave(&nesadapter->pbl_lock, flags);
- nesadapter->free_256pbl += pbl_count_256 + use_two_level;
- use_256_pbls = 0;
-
- if (pbl_count_4k == 1)
- use_two_level = 0;
- pbl_count = pbl_count_4k;
-
- if ((pbl_count_4k + use_two_level) <= nesadapter->free_4kpbl) {
- nesadapter->free_4kpbl -= pbl_count + use_two_level;
- use_4k_pbls = 1;
- }
- spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
-
- if (use_4k_pbls == 0)
- return -ENOMEM;
- }
- }
-
- opcode = NES_CQP_REGISTER_STAG | NES_CQP_STAG_RIGHTS_LOCAL_READ |
- NES_CQP_STAG_VA_TO | NES_CQP_STAG_MR;
- if (acc & IB_ACCESS_LOCAL_WRITE)
- opcode |= NES_CQP_STAG_RIGHTS_LOCAL_WRITE;
- if (acc & IB_ACCESS_REMOTE_WRITE)
- opcode |= NES_CQP_STAG_RIGHTS_REMOTE_WRITE | NES_CQP_STAG_REM_ACC_EN;
- if (acc & IB_ACCESS_REMOTE_READ)
- opcode |= NES_CQP_STAG_RIGHTS_REMOTE_READ | NES_CQP_STAG_REM_ACC_EN;
- if (acc & IB_ACCESS_MW_BIND)
- opcode |= NES_CQP_STAG_RIGHTS_WINDOW_BIND | NES_CQP_STAG_REM_ACC_EN;
-
- nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, opcode);
- set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_VA_LOW_IDX, *iova_start);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_LEN_LOW_IDX, region_length);
-
- cqp_wqe->wqe_words[NES_CQP_STAG_WQE_LEN_HIGH_PD_IDX] =
- cpu_to_le32((u32)(region_length >> 8) & 0xff000000);
- cqp_wqe->wqe_words[NES_CQP_STAG_WQE_LEN_HIGH_PD_IDX] |=
- cpu_to_le32(nespd->pd_id & 0x00007fff);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_STAG_IDX, stag);
-
- if (pbl_count == 0) {
- set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_PA_LOW_IDX, single_buffer);
- } else {
- set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_PA_LOW_IDX, root_vpbl->pbl_pbase);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_PBL_BLK_COUNT_IDX, pbl_count);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_PBL_LEN_IDX, (pg_cnt * 8));
-
- if (use_4k_pbls)
- cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |= cpu_to_le32(NES_CQP_STAG_PBL_BLK_SIZE);
- }
- barrier();
-
- atomic_set(&cqp_request->refcount, 2);
- nes_post_cqp_request(nesdev, cqp_request);
-
- /* Wait for CQP */
- ret = wait_event_timeout(cqp_request->waitq, (0 != cqp_request->request_done),
- NES_EVENT_TIMEOUT);
- nes_debug(NES_DBG_MR, "Register STag 0x%08X completed, wait_event_timeout ret = %u,"
- " CQP Major:Minor codes = 0x%04X:0x%04X.\n",
- stag, ret, cqp_request->major_code, cqp_request->minor_code);
- major_code = cqp_request->major_code;
- nes_put_cqp_request(nesdev, cqp_request);
-
- if ((!ret || major_code) && pbl_count != 0) {
- spin_lock_irqsave(&nesadapter->pbl_lock, flags);
- if (use_256_pbls)
- nesadapter->free_256pbl += pbl_count + use_two_level;
- else if (use_4k_pbls)
- nesadapter->free_4kpbl += pbl_count + use_two_level;
- spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
- }
- if (new_root.pbl_pbase)
- pci_free_consistent(nesdev->pcidev, 512, new_root.pbl_vbase,
- new_root.pbl_pbase);
-
- if (!ret)
- return -ETIME;
- else if (major_code)
- return -EIO;
-
- *actual_pbl_cnt = pbl_count + use_two_level;
- *used_4k_pbls = use_4k_pbls;
- return 0;
-}
-
-
-/**
- * nes_reg_phys_mr
- */
-struct ib_mr *nes_reg_phys_mr(struct ib_pd *ib_pd, u64 addr, u64 size,
- int acc, u64 *iova_start)
-{
- u64 region_length;
- struct nes_pd *nespd = to_nespd(ib_pd);
- struct nes_vnic *nesvnic = to_nesvnic(ib_pd->device);
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- struct nes_mr *nesmr;
- struct ib_mr *ibmr;
- struct nes_vpbl vpbl;
- struct nes_root_vpbl root_vpbl;
- u32 stag;
- unsigned long mask;
- u32 stag_index = 0;
- u32 next_stag_index = 0;
- u32 driver_key = 0;
- int err = 0;
- int ret = 0;
- u16 pbl_count = 0;
- u8 single_page = 1;
- u8 stag_key = 0;
-
- region_length = 0;
- vpbl.pbl_vbase = NULL;
- root_vpbl.pbl_vbase = NULL;
- root_vpbl.pbl_pbase = 0;
-
- get_random_bytes(&next_stag_index, sizeof(next_stag_index));
- stag_key = (u8)next_stag_index;
-
- driver_key = 0;
-
- next_stag_index >>= 8;
- next_stag_index %= nesadapter->max_mr;
-
- if ((addr ^ *iova_start) & ~PAGE_MASK)
- return ERR_PTR(-EINVAL);
-
- err = nes_alloc_resource(nesadapter, nesadapter->allocated_mrs, nesadapter->max_mr,
- &stag_index, &next_stag_index, NES_RESOURCE_PHYS_MR);
- if (err) {
- return ERR_PTR(err);
- }
-
- nesmr = kzalloc(sizeof(*nesmr), GFP_KERNEL);
- if (!nesmr) {
- nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
- return ERR_PTR(-ENOMEM);
- }
-
- /* Allocate a 4K buffer for the PBL */
- vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev, 4096,
- &vpbl.pbl_pbase);
- nes_debug(NES_DBG_MR, "Allocating leaf PBL, va = %p, pa = 0x%016lX\n",
- vpbl.pbl_vbase, (unsigned long)vpbl.pbl_pbase);
- if (!vpbl.pbl_vbase) {
- nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
- ibmr = ERR_PTR(-ENOMEM);
- kfree(nesmr);
- goto reg_phys_err;
- }
-
-
- mask = !size;
-
- if (mask & ~PAGE_MASK) {
- nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
- nes_debug(NES_DBG_MR, "Invalid buffer addr or size\n");
- ibmr = ERR_PTR(-EINVAL);
- kfree(nesmr);
- goto reg_phys_err;
- }
-
- region_length += size;
- vpbl.pbl_vbase[0].pa_low = cpu_to_le32((u32)addr & PAGE_MASK);
- vpbl.pbl_vbase[0].pa_high = cpu_to_le32((u32)((((u64)addr) >> 32)));
-
- stag = stag_index << 8;
- stag |= driver_key;
- stag += (u32)stag_key;
-
- nes_debug(NES_DBG_MR, "Registering STag 0x%08X, VA = 0x%016lX,"
- " length = 0x%016lX, index = 0x%08X\n",
- stag, (unsigned long)*iova_start, (unsigned long)region_length, stag_index);
-
- /* Make the leaf PBL the root if only one PBL */
- root_vpbl.pbl_pbase = vpbl.pbl_pbase;
-
- if (single_page) {
- pbl_count = 0;
- } else {
- pbl_count = 1;
- }
- ret = nes_reg_mr(nesdev, nespd, stag, region_length, &root_vpbl,
- addr, pbl_count, 1, acc, iova_start,
- &nesmr->pbls_used, &nesmr->pbl_4k);
-
- if (ret == 0) {
- nesmr->ibmr.rkey = stag;
- nesmr->ibmr.lkey = stag;
- nesmr->mode = IWNES_MEMREG_TYPE_MEM;
- ibmr = &nesmr->ibmr;
- } else {
- kfree(nesmr);
- ibmr = ERR_PTR(-ENOMEM);
- }
-
-reg_phys_err:
- /* single PBL case */
- pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase, vpbl.pbl_pbase);
- return ibmr;
-}
-
-
-/**
- * nes_get_dma_mr
- */
-static struct ib_mr *nes_get_dma_mr(struct ib_pd *pd, int acc)
-{
- u64 kva = 0;
-
- nes_debug(NES_DBG_MR, "\n");
-
- return nes_reg_phys_mr(pd, 0, 0xffffffffffULL, acc, &kva);
-}
-
-/**
- * nes_reg_user_mr
- */
-static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
- u64 virt, int acc, struct ib_udata *udata)
-{
- u64 iova_start;
- __le64 *pbl;
- u64 region_length;
- dma_addr_t last_dma_addr = 0;
- dma_addr_t first_dma_addr = 0;
- struct nes_pd *nespd = to_nespd(pd);
- struct nes_vnic *nesvnic = to_nesvnic(pd->device);
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- struct ib_mr *ibmr = ERR_PTR(-EINVAL);
- struct sg_dma_page_iter dma_iter;
- struct nes_ucontext *nes_ucontext = rdma_udata_to_drv_context(
- udata, struct nes_ucontext, ibucontext);
- struct nes_pbl *nespbl;
- struct nes_mr *nesmr;
- struct ib_umem *region;
- struct nes_mem_reg_req req;
- struct nes_vpbl vpbl;
- struct nes_root_vpbl root_vpbl;
- int page_index;
- int page_count = 0;
- int err, pbl_depth = 0;
- int ret;
- u32 stag;
- u32 stag_index = 0;
- u32 next_stag_index;
- u32 driver_key;
- u32 root_pbl_index = 0;
- u32 cur_pbl_index = 0;
- u32 skip_pages;
- u16 pbl_count;
- u8 single_page = 1;
- u8 stag_key;
-
- region = ib_umem_get(udata, start, length, acc, 0);
- if (IS_ERR(region)) {
- return (struct ib_mr *)region;
- }
-
- nes_debug(NES_DBG_MR, "User base = 0x%lX, Virt base = 0x%lX, length = %u,"
- " offset = %u, page size = %lu.\n",
- (unsigned long int)start, (unsigned long int)virt, (u32)length,
- ib_umem_offset(region), BIT(region->page_shift));
-
- skip_pages = ((u32)ib_umem_offset(region)) >> 12;
-
- if (ib_copy_from_udata(&req, udata, sizeof(req))) {
- ib_umem_release(region);
- return ERR_PTR(-EFAULT);
- }
- nes_debug(NES_DBG_MR, "Memory Registration type = %08X.\n", req.reg_type);
-
- switch (req.reg_type) {
- case IWNES_MEMREG_TYPE_MEM:
- pbl_depth = 0;
- region_length = 0;
- vpbl.pbl_vbase = NULL;
- root_vpbl.pbl_vbase = NULL;
- root_vpbl.pbl_pbase = 0;
-
- get_random_bytes(&next_stag_index, sizeof(next_stag_index));
- stag_key = (u8)next_stag_index;
-
- driver_key = next_stag_index & 0x70000000;
-
- next_stag_index >>= 8;
- next_stag_index %= nesadapter->max_mr;
-
- err = nes_alloc_resource(nesadapter, nesadapter->allocated_mrs,
- nesadapter->max_mr, &stag_index, &next_stag_index, NES_RESOURCE_USER_MR);
- if (err) {
- ib_umem_release(region);
- return ERR_PTR(err);
- }
-
- nesmr = kzalloc(sizeof(*nesmr), GFP_KERNEL);
- if (!nesmr) {
- ib_umem_release(region);
- nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
- return ERR_PTR(-ENOMEM);
- }
- nesmr->region = region;
-
- for_each_sg_dma_page (region->sg_head.sgl, &dma_iter, region->nmap, 0) {
-
- region_length += PAGE_SIZE;
- region_length -= skip_pages << 12;
- skip_pages = 0;
- if ((page_count != 0) && (page_count << 12) - (ib_umem_offset(region) & (4096 - 1)) >= region->length)
- goto enough_pages;
- if ((page_count & 0x01FF) == 0) {
- if (page_count >= 1024 * 512) {
- ib_umem_release(region);
- nes_free_resource(nesadapter,
- nesadapter->allocated_mrs, stag_index);
- kfree(nesmr);
- ibmr = ERR_PTR(-E2BIG);
- goto reg_user_mr_err;
- }
- if (root_pbl_index == 1) {
- root_vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev,
- 8192, &root_vpbl.pbl_pbase);
- nes_debug(NES_DBG_MR, "Allocating root PBL, va = %p, pa = 0x%08X\n",
- root_vpbl.pbl_vbase, (unsigned int)root_vpbl.pbl_pbase);
- if (!root_vpbl.pbl_vbase) {
- ib_umem_release(region);
- pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase,
- vpbl.pbl_pbase);
- nes_free_resource(nesadapter, nesadapter->allocated_mrs,
- stag_index);
- kfree(nesmr);
- ibmr = ERR_PTR(-ENOMEM);
- goto reg_user_mr_err;
- }
- root_vpbl.leaf_vpbl = kcalloc(1024,
- sizeof(*root_vpbl.leaf_vpbl),
- GFP_KERNEL);
- if (!root_vpbl.leaf_vpbl) {
- ib_umem_release(region);
- pci_free_consistent(nesdev->pcidev, 8192, root_vpbl.pbl_vbase,
- root_vpbl.pbl_pbase);
- pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase,
- vpbl.pbl_pbase);
- nes_free_resource(nesadapter, nesadapter->allocated_mrs,
- stag_index);
- kfree(nesmr);
- ibmr = ERR_PTR(-ENOMEM);
- goto reg_user_mr_err;
- }
- root_vpbl.pbl_vbase[0].pa_low =
- cpu_to_le32((u32)vpbl.pbl_pbase);
- root_vpbl.pbl_vbase[0].pa_high =
- cpu_to_le32((u32)((((u64)vpbl.pbl_pbase) >> 32)));
- root_vpbl.leaf_vpbl[0] = vpbl;
- }
- vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev, 4096,
- &vpbl.pbl_pbase);
- nes_debug(NES_DBG_MR, "Allocating leaf PBL, va = %p, pa = 0x%08X\n",
- vpbl.pbl_vbase, (unsigned int)vpbl.pbl_pbase);
- if (!vpbl.pbl_vbase) {
- ib_umem_release(region);
- nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
- ibmr = ERR_PTR(-ENOMEM);
- kfree(nesmr);
- goto reg_user_mr_err;
- }
- if (1 <= root_pbl_index) {
- root_vpbl.pbl_vbase[root_pbl_index].pa_low =
- cpu_to_le32((u32)vpbl.pbl_pbase);
- root_vpbl.pbl_vbase[root_pbl_index].pa_high =
- cpu_to_le32((u32)((((u64)vpbl.pbl_pbase) >> 32)));
- root_vpbl.leaf_vpbl[root_pbl_index] = vpbl;
- }
- root_pbl_index++;
- cur_pbl_index = 0;
- }
- if (single_page) {
- if (page_count != 0) {
- if ((last_dma_addr + 4096) != sg_page_iter_dma_address(&dma_iter))
- single_page = 0;
- last_dma_addr = sg_page_iter_dma_address(&dma_iter);
- } else {
- first_dma_addr = sg_page_iter_dma_address(&dma_iter);
- last_dma_addr = first_dma_addr;
- }
- }
-
- vpbl.pbl_vbase[cur_pbl_index].pa_low =
- cpu_to_le32((u32)(sg_page_iter_dma_address(&dma_iter)));
- vpbl.pbl_vbase[cur_pbl_index].pa_high =
- cpu_to_le32((u32)((u64)(sg_page_iter_dma_address(&dma_iter))));
- cur_pbl_index++;
- page_count++;
- }
-
-enough_pages:
- nes_debug(NES_DBG_MR, "calculating stag, stag_index=0x%08x, driver_key=0x%08x,"
- " stag_key=0x%08x\n",
- stag_index, driver_key, stag_key);
- stag = stag_index << 8;
- stag |= driver_key;
- stag += (u32)stag_key;
-
- iova_start = virt;
- /* Make the leaf PBL the root if only one PBL */
- if (root_pbl_index == 1) {
- root_vpbl.pbl_pbase = vpbl.pbl_pbase;
- }
-
- if (single_page) {
- pbl_count = 0;
- } else {
- pbl_count = root_pbl_index;
- first_dma_addr = 0;
- }
- nes_debug(NES_DBG_MR, "Registering STag 0x%08X, VA = 0x%08X, length = 0x%08X,"
- " index = 0x%08X, region->length=0x%08llx, pbl_count = %u\n",
- stag, (unsigned int)iova_start,
- (unsigned int)region_length, stag_index,
- (unsigned long long)region->length, pbl_count);
- ret = nes_reg_mr(nesdev, nespd, stag, region->length, &root_vpbl,
- first_dma_addr, pbl_count, (u16)cur_pbl_index, acc,
- &iova_start, &nesmr->pbls_used, &nesmr->pbl_4k);
-
- nes_debug(NES_DBG_MR, "ret=%d\n", ret);
-
- if (ret == 0) {
- nesmr->ibmr.rkey = stag;
- nesmr->ibmr.lkey = stag;
- nesmr->mode = IWNES_MEMREG_TYPE_MEM;
- ibmr = &nesmr->ibmr;
- } else {
- ib_umem_release(region);
- kfree(nesmr);
- ibmr = ERR_PTR(-ENOMEM);
- }
-
-reg_user_mr_err:
- /* free the resources */
- if (root_pbl_index == 1) {
- pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase,
- vpbl.pbl_pbase);
- } else {
- for (page_index=0; page_index<root_pbl_index; page_index++) {
- pci_free_consistent(nesdev->pcidev, 4096,
- root_vpbl.leaf_vpbl[page_index].pbl_vbase,
- root_vpbl.leaf_vpbl[page_index].pbl_pbase);
- }
- kfree(root_vpbl.leaf_vpbl);
- pci_free_consistent(nesdev->pcidev, 8192, root_vpbl.pbl_vbase,
- root_vpbl.pbl_pbase);
- }
-
- nes_debug(NES_DBG_MR, "Leaving, ibmr=%p", ibmr);
-
- return ibmr;
- case IWNES_MEMREG_TYPE_QP:
- case IWNES_MEMREG_TYPE_CQ:
- if (!region->length) {
- nes_debug(NES_DBG_MR, "Unable to register zero length region for CQ\n");
- ib_umem_release(region);
- return ERR_PTR(-EINVAL);
- }
- nespbl = kzalloc(sizeof(*nespbl), GFP_KERNEL);
- if (!nespbl) {
- ib_umem_release(region);
- return ERR_PTR(-ENOMEM);
- }
- nesmr = kzalloc(sizeof(*nesmr), GFP_KERNEL);
- if (!nesmr) {
- ib_umem_release(region);
- kfree(nespbl);
- return ERR_PTR(-ENOMEM);
- }
- nesmr->region = region;
- pbl_depth = region->length >> 12;
- pbl_depth += (region->length & (4096-1)) ? 1 : 0;
- nespbl->pbl_size = pbl_depth*sizeof(u64);
- if (req.reg_type == IWNES_MEMREG_TYPE_QP) {
- nes_debug(NES_DBG_MR, "Attempting to allocate QP PBL memory");
- } else {
- nes_debug(NES_DBG_MR, "Attempting to allocate CP PBL memory");
- }
-
- nes_debug(NES_DBG_MR, " %u bytes, %u entries.\n",
- nespbl->pbl_size, pbl_depth);
- pbl = pci_alloc_consistent(nesdev->pcidev, nespbl->pbl_size,
- &nespbl->pbl_pbase);
- if (!pbl) {
- ib_umem_release(region);
- kfree(nesmr);
- kfree(nespbl);
- nes_debug(NES_DBG_MR, "Unable to allocate PBL memory\n");
- return ERR_PTR(-ENOMEM);
- }
-
- nespbl->pbl_vbase = (u64 *)pbl;
- nespbl->user_base = start;
- nes_debug(NES_DBG_MR, "Allocated PBL memory, %u bytes, pbl_pbase=%lx,"
- " pbl_vbase=%p user_base=0x%lx\n",
- nespbl->pbl_size, (unsigned long) nespbl->pbl_pbase,
- (void *) nespbl->pbl_vbase, nespbl->user_base);
-
- nespbl->page = sg_page(region->sg_head.sgl);
- for_each_sg_dma_page(region->sg_head.sgl, &dma_iter, region->nmap, 0) {
- ((__le32 *)pbl)[0] = cpu_to_le32((u32)(sg_page_iter_dma_address(&dma_iter)));
- ((__le32 *)pbl)[1] = cpu_to_le32(((u64)(sg_page_iter_dma_address(&dma_iter)))>>32);
- nes_debug(NES_DBG_MR, "pbl=%p, *pbl=0x%016llx, 0x%08x%08x\n", pbl,
- (unsigned long long)*pbl,
- le32_to_cpu(((__le32 *)pbl)[1]), le32_to_cpu(((__le32 *)pbl)[0]));
- pbl++;
- }
-
- if (req.reg_type == IWNES_MEMREG_TYPE_QP) {
- list_add_tail(&nespbl->list, &nes_ucontext->qp_reg_mem_list);
- } else {
- list_add_tail(&nespbl->list, &nes_ucontext->cq_reg_mem_list);
- }
- nesmr->ibmr.rkey = -1;
- nesmr->ibmr.lkey = -1;
- nesmr->mode = req.reg_type;
- return &nesmr->ibmr;
- }
-
- ib_umem_release(region);
- return ERR_PTR(-ENOSYS);
-}
-
-
-/**
- * nes_dereg_mr
- */
-static int nes_dereg_mr(struct ib_mr *ib_mr, struct ib_udata *udata)
-{
- struct nes_mr *nesmr = to_nesmr(ib_mr);
- struct nes_vnic *nesvnic = to_nesvnic(ib_mr->device);
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- struct nes_hw_cqp_wqe *cqp_wqe;
- struct nes_cqp_request *cqp_request;
- unsigned long flags;
- int ret;
- u16 major_code;
- u16 minor_code;
-
-
- if (nesmr->pages)
- pci_free_consistent(nesdev->pcidev,
- nesmr->max_pages * sizeof(u64),
- nesmr->pages,
- nesmr->paddr);
-
- if (nesmr->region) {
- ib_umem_release(nesmr->region);
- }
- if (nesmr->mode != IWNES_MEMREG_TYPE_MEM) {
- kfree(nesmr);
- return 0;
- }
-
- /* Deallocate the region with the adapter */
-
- cqp_request = nes_get_cqp_request(nesdev);
- if (cqp_request == NULL) {
- nes_debug(NES_DBG_MR, "Failed to get a cqp_request.\n");
- return -ENOMEM;
- }
- cqp_request->waiting = 1;
- cqp_wqe = &cqp_request->cqp_wqe;
-
- nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
- NES_CQP_DEALLOCATE_STAG | NES_CQP_STAG_VA_TO |
- NES_CQP_STAG_DEALLOC_PBLS | NES_CQP_STAG_MR);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_STAG_IDX, ib_mr->rkey);
-
- atomic_set(&cqp_request->refcount, 2);
- nes_post_cqp_request(nesdev, cqp_request);
-
- /* Wait for CQP */
- nes_debug(NES_DBG_MR, "Waiting for deallocate STag 0x%08X completed\n", ib_mr->rkey);
- ret = wait_event_timeout(cqp_request->waitq, (cqp_request->request_done != 0),
- NES_EVENT_TIMEOUT);
- nes_debug(NES_DBG_MR, "Deallocate STag 0x%08X completed, wait_event_timeout ret = %u,"
- " CQP Major:Minor codes = 0x%04X:0x%04X\n",
- ib_mr->rkey, ret, cqp_request->major_code, cqp_request->minor_code);
-
- major_code = cqp_request->major_code;
- minor_code = cqp_request->minor_code;
-
- nes_put_cqp_request(nesdev, cqp_request);
-
- if (!ret) {
- nes_debug(NES_DBG_MR, "Timeout waiting to destroy STag,"
- " ib_mr=%p, rkey = 0x%08X\n",
- ib_mr, ib_mr->rkey);
- return -ETIME;
- } else if (major_code) {
- nes_debug(NES_DBG_MR, "Error (0x%04X:0x%04X) while attempting"
- " to destroy STag, ib_mr=%p, rkey = 0x%08X\n",
- major_code, minor_code, ib_mr, ib_mr->rkey);
- return -EIO;
- }
-
- if (nesmr->pbls_used != 0) {
- spin_lock_irqsave(&nesadapter->pbl_lock, flags);
- if (nesmr->pbl_4k) {
- nesadapter->free_4kpbl += nesmr->pbls_used;
- if (nesadapter->free_4kpbl > nesadapter->max_4kpbl)
- printk(KERN_ERR PFX "free 4KB PBLs(%u) has "
- "exceeded the max(%u)\n",
- nesadapter->free_4kpbl,
- nesadapter->max_4kpbl);
- } else {
- nesadapter->free_256pbl += nesmr->pbls_used;
- if (nesadapter->free_256pbl > nesadapter->max_256pbl)
- printk(KERN_ERR PFX "free 256B PBLs(%u) has "
- "exceeded the max(%u)\n",
- nesadapter->free_256pbl,
- nesadapter->max_256pbl);
- }
- spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
- }
- nes_free_resource(nesadapter, nesadapter->allocated_mrs,
- (ib_mr->rkey & 0x0fffff00) >> 8);
-
- kfree(nesmr);
-
- return 0;
-}
-
-
-/**
- * show_rev
- */
-static ssize_t hw_rev_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct nes_ib_device *nesibdev =
- rdma_device_to_drv_device(dev, struct nes_ib_device, ibdev);
- struct nes_vnic *nesvnic = nesibdev->nesvnic;
-
- nes_debug(NES_DBG_INIT, "\n");
- return sprintf(buf, "%x\n", nesvnic->nesdev->nesadapter->hw_rev);
-}
-static DEVICE_ATTR_RO(hw_rev);
-
-/**
- * show_hca
- */
-static ssize_t hca_type_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- nes_debug(NES_DBG_INIT, "\n");
- return sprintf(buf, "NES020\n");
-}
-static DEVICE_ATTR_RO(hca_type);
-
-/**
- * show_board
- */
-static ssize_t board_id_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- nes_debug(NES_DBG_INIT, "\n");
- return sprintf(buf, "%.*s\n", 32, "NES020 Board ID");
-}
-static DEVICE_ATTR_RO(board_id);
-
-static struct attribute *nes_dev_attributes[] = {
- &dev_attr_hw_rev.attr,
- &dev_attr_hca_type.attr,
- &dev_attr_board_id.attr,
- NULL
-};
-
-static const struct attribute_group nes_attr_group = {
- .attrs = nes_dev_attributes,
-};
-
-/**
- * nes_query_qp
- */
-static int nes_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
- int attr_mask, struct ib_qp_init_attr *init_attr)
-{
- struct nes_qp *nesqp = to_nesqp(ibqp);
-
- nes_debug(NES_DBG_QP, "\n");
-
- attr->qp_access_flags = 0;
- attr->cap.max_send_wr = nesqp->hwqp.sq_size;
- attr->cap.max_recv_wr = nesqp->hwqp.rq_size;
- attr->cap.max_recv_sge = 1;
- if (nes_drv_opt & NES_DRV_OPT_NO_INLINE_DATA)
- attr->cap.max_inline_data = 0;
- else
- attr->cap.max_inline_data = 64;
-
- init_attr->event_handler = nesqp->ibqp.event_handler;
- init_attr->qp_context = nesqp->ibqp.qp_context;
- init_attr->send_cq = nesqp->ibqp.send_cq;
- init_attr->recv_cq = nesqp->ibqp.recv_cq;
- init_attr->srq = nesqp->ibqp.srq;
- init_attr->cap = attr->cap;
-
- return 0;
-}
-
-
-/**
- * nes_hw_modify_qp
- */
-int nes_hw_modify_qp(struct nes_device *nesdev, struct nes_qp *nesqp,
- u32 next_iwarp_state, u32 termlen, u32 wait_completion)
-{
- struct nes_hw_cqp_wqe *cqp_wqe;
- /* struct iw_cm_id *cm_id = nesqp->cm_id; */
- /* struct iw_cm_event cm_event; */
- struct nes_cqp_request *cqp_request;
- int ret;
- u16 major_code;
-
- nes_debug(NES_DBG_MOD_QP, "QP%u, refcount=%d\n",
- nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount));
-
- cqp_request = nes_get_cqp_request(nesdev);
- if (cqp_request == NULL) {
- nes_debug(NES_DBG_MOD_QP, "Failed to get a cqp_request.\n");
- return -ENOMEM;
- }
- if (wait_completion) {
- cqp_request->waiting = 1;
- } else {
- cqp_request->waiting = 0;
- }
- cqp_wqe = &cqp_request->cqp_wqe;
-
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
- NES_CQP_MODIFY_QP | NES_CQP_QP_TYPE_IWARP | next_iwarp_state);
- nes_debug(NES_DBG_MOD_QP, "using next_iwarp_state=%08x, wqe_words=%08x\n",
- next_iwarp_state, le32_to_cpu(cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX]));
- nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX, nesqp->hwqp.qp_id);
- set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_CONTEXT_LOW_IDX, (u64)nesqp->nesqp_context_pbase);
-
- /* If sending a terminate message, fill in the length (in words) */
- if (((next_iwarp_state & NES_CQP_QP_IWARP_STATE_MASK) == NES_CQP_QP_IWARP_STATE_TERMINATE) &&
- !(next_iwarp_state & NES_CQP_QP_TERM_DONT_SEND_TERM_MSG)) {
- termlen = ((termlen + 3) >> 2) << NES_CQP_OP_TERMLEN_SHIFT;
- set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_NEW_MSS_IDX, termlen);
- }
-
- atomic_set(&cqp_request->refcount, 2);
- nes_post_cqp_request(nesdev, cqp_request);
-
- /* Wait for CQP */
- if (wait_completion) {
- /* nes_debug(NES_DBG_MOD_QP, "Waiting for modify iWARP QP%u to complete.\n",
- nesqp->hwqp.qp_id); */
- ret = wait_event_timeout(cqp_request->waitq, (cqp_request->request_done != 0),
- NES_EVENT_TIMEOUT);
- nes_debug(NES_DBG_MOD_QP, "Modify iwarp QP%u completed, wait_event_timeout ret=%u, "
- "CQP Major:Minor codes = 0x%04X:0x%04X.\n",
- nesqp->hwqp.qp_id, ret, cqp_request->major_code, cqp_request->minor_code);
- major_code = cqp_request->major_code;
- if (major_code) {
- nes_debug(NES_DBG_MOD_QP, "Modify iwarp QP%u failed"
- "CQP Major:Minor codes = 0x%04X:0x%04X, intended next state = 0x%08X.\n",
- nesqp->hwqp.qp_id, cqp_request->major_code,
- cqp_request->minor_code, next_iwarp_state);
- }
-
- nes_put_cqp_request(nesdev, cqp_request);
-
- if (!ret)
- return -ETIME;
- else if (major_code)
- return -EIO;
- else
- return 0;
- } else {
- return 0;
- }
-}
-
-
-/**
- * nes_modify_qp
- */
-int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
- int attr_mask, struct ib_udata *udata)
-{
- struct nes_qp *nesqp = to_nesqp(ibqp);
- struct nes_vnic *nesvnic = to_nesvnic(ibqp->device);
- struct nes_device *nesdev = nesvnic->nesdev;
- /* u32 cqp_head; */
- /* u32 counter; */
- u32 next_iwarp_state = 0;
- int err;
- unsigned long qplockflags;
- int ret;
- u16 original_last_aeq;
- u8 issue_modify_qp = 0;
- u8 dont_wait = 0;
-
- nes_debug(NES_DBG_MOD_QP, "QP%u: QP State=%u, cur QP State=%u,"
- " iwarp_state=0x%X, refcount=%d\n",
- nesqp->hwqp.qp_id, attr->qp_state, nesqp->ibqp_state,
- nesqp->iwarp_state, atomic_read(&nesqp->refcount));
-
- spin_lock_irqsave(&nesqp->lock, qplockflags);
-
- nes_debug(NES_DBG_MOD_QP, "QP%u: hw_iwarp_state=0x%X, hw_tcp_state=0x%X,"
- " QP Access Flags=0x%X, attr_mask = 0x%0x\n",
- nesqp->hwqp.qp_id, nesqp->hw_iwarp_state,
- nesqp->hw_tcp_state, attr->qp_access_flags, attr_mask);
-
- if (attr_mask & IB_QP_STATE) {
- switch (attr->qp_state) {
- case IB_QPS_INIT:
- nes_debug(NES_DBG_MOD_QP, "QP%u: new state = init\n",
- nesqp->hwqp.qp_id);
- if (nesqp->iwarp_state > (u32)NES_CQP_QP_IWARP_STATE_IDLE) {
- spin_unlock_irqrestore(&nesqp->lock, qplockflags);
- return -EINVAL;
- }
- next_iwarp_state = NES_CQP_QP_IWARP_STATE_IDLE;
- issue_modify_qp = 1;
- break;
- case IB_QPS_RTR:
- nes_debug(NES_DBG_MOD_QP, "QP%u: new state = rtr\n",
- nesqp->hwqp.qp_id);
- if (nesqp->iwarp_state>(u32)NES_CQP_QP_IWARP_STATE_IDLE) {
- spin_unlock_irqrestore(&nesqp->lock, qplockflags);
- return -EINVAL;
- }
- next_iwarp_state = NES_CQP_QP_IWARP_STATE_IDLE;
- issue_modify_qp = 1;
- break;
- case IB_QPS_RTS:
- nes_debug(NES_DBG_MOD_QP, "QP%u: new state = rts\n",
- nesqp->hwqp.qp_id);
- if (nesqp->iwarp_state>(u32)NES_CQP_QP_IWARP_STATE_RTS) {
- spin_unlock_irqrestore(&nesqp->lock, qplockflags);
- return -EINVAL;
- }
- if (nesqp->cm_id == NULL) {
- nes_debug(NES_DBG_MOD_QP, "QP%u: Failing attempt to move QP to RTS without a CM_ID. \n",
- nesqp->hwqp.qp_id );
- spin_unlock_irqrestore(&nesqp->lock, qplockflags);
- return -EINVAL;
- }
- next_iwarp_state = NES_CQP_QP_IWARP_STATE_RTS;
- if (nesqp->iwarp_state != NES_CQP_QP_IWARP_STATE_RTS)
- next_iwarp_state |= NES_CQP_QP_CONTEXT_VALID |
- NES_CQP_QP_ARP_VALID | NES_CQP_QP_ORD_VALID;
- issue_modify_qp = 1;
- nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_ESTABLISHED;
- nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_RTS;
- nesqp->hte_added = 1;
- break;
- case IB_QPS_SQD:
- issue_modify_qp = 1;
- nes_debug(NES_DBG_MOD_QP, "QP%u: new state=closing. SQ head=%u, SQ tail=%u\n",
- nesqp->hwqp.qp_id, nesqp->hwqp.sq_head, nesqp->hwqp.sq_tail);
- if (nesqp->iwarp_state == (u32)NES_CQP_QP_IWARP_STATE_CLOSING) {
- spin_unlock_irqrestore(&nesqp->lock, qplockflags);
- return 0;
- } else {
- if (nesqp->iwarp_state > (u32)NES_CQP_QP_IWARP_STATE_CLOSING) {
- nes_debug(NES_DBG_MOD_QP, "QP%u: State change to closing"
- " ignored due to current iWARP state\n",
- nesqp->hwqp.qp_id);
- spin_unlock_irqrestore(&nesqp->lock, qplockflags);
- return -EINVAL;
- }
- if (nesqp->hw_iwarp_state != NES_AEQE_IWARP_STATE_RTS) {
- nes_debug(NES_DBG_MOD_QP, "QP%u: State change to closing"
- " already done based on hw state.\n",
- nesqp->hwqp.qp_id);
- issue_modify_qp = 0;
- }
- switch (nesqp->hw_iwarp_state) {
- case NES_AEQE_IWARP_STATE_CLOSING:
- next_iwarp_state = NES_CQP_QP_IWARP_STATE_CLOSING;
- break;
- case NES_AEQE_IWARP_STATE_TERMINATE:
- next_iwarp_state = NES_CQP_QP_IWARP_STATE_TERMINATE;
- break;
- case NES_AEQE_IWARP_STATE_ERROR:
- next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR;
- break;
- default:
- next_iwarp_state = NES_CQP_QP_IWARP_STATE_CLOSING;
- nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_CLOSING;
- break;
- }
- }
- break;
- case IB_QPS_SQE:
- nes_debug(NES_DBG_MOD_QP, "QP%u: new state = terminate\n",
- nesqp->hwqp.qp_id);
- if (nesqp->iwarp_state>=(u32)NES_CQP_QP_IWARP_STATE_TERMINATE) {
- spin_unlock_irqrestore(&nesqp->lock, qplockflags);
- return -EINVAL;
- }
- /* next_iwarp_state = (NES_CQP_QP_IWARP_STATE_TERMINATE | 0x02000000); */
- next_iwarp_state = NES_CQP_QP_IWARP_STATE_TERMINATE;
- nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_TERMINATE;
- issue_modify_qp = 1;
- break;
- case IB_QPS_ERR:
- case IB_QPS_RESET:
- if (nesqp->iwarp_state == (u32)NES_CQP_QP_IWARP_STATE_ERROR) {
- spin_unlock_irqrestore(&nesqp->lock, qplockflags);
- return -EINVAL;
- }
- nes_debug(NES_DBG_MOD_QP, "QP%u: new state = error\n",
- nesqp->hwqp.qp_id);
- if (nesqp->term_flags)
- del_timer(&nesqp->terminate_timer);
-
- next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR;
- /* next_iwarp_state = (NES_CQP_QP_IWARP_STATE_TERMINATE | 0x02000000); */
- if (nesqp->hte_added) {
- nes_debug(NES_DBG_MOD_QP, "set CQP_QP_DEL_HTE\n");
- next_iwarp_state |= NES_CQP_QP_DEL_HTE;
- nesqp->hte_added = 0;
- }
- if ((nesqp->hw_tcp_state > NES_AEQE_TCP_STATE_CLOSED) &&
- (nesdev->iw_status) &&
- (nesqp->hw_tcp_state != NES_AEQE_TCP_STATE_TIME_WAIT)) {
- next_iwarp_state |= NES_CQP_QP_RESET;
- } else {
- nes_debug(NES_DBG_MOD_QP, "QP%u NOT setting NES_CQP_QP_RESET since TCP state = %u\n",
- nesqp->hwqp.qp_id, nesqp->hw_tcp_state);
- dont_wait = 1;
- }
- issue_modify_qp = 1;
- nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_ERROR;
- break;
- default:
- spin_unlock_irqrestore(&nesqp->lock, qplockflags);
- return -EINVAL;
- break;
- }
-
- nesqp->ibqp_state = attr->qp_state;
- nesqp->iwarp_state = next_iwarp_state & NES_CQP_QP_IWARP_STATE_MASK;
- nes_debug(NES_DBG_MOD_QP, "Change nesqp->iwarp_state=%08x\n",
- nesqp->iwarp_state);
- }
-
- if (attr_mask & IB_QP_ACCESS_FLAGS) {
- if (attr->qp_access_flags & IB_ACCESS_LOCAL_WRITE) {
- nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_RDMA_WRITE_EN |
- NES_QPCONTEXT_MISC_RDMA_READ_EN);
- issue_modify_qp = 1;
- }
- if (attr->qp_access_flags & IB_ACCESS_REMOTE_WRITE) {
- nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_RDMA_WRITE_EN);
- issue_modify_qp = 1;
- }
- if (attr->qp_access_flags & IB_ACCESS_REMOTE_READ) {
- nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_RDMA_READ_EN);
- issue_modify_qp = 1;
- }
- if (attr->qp_access_flags & IB_ACCESS_MW_BIND) {
- nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_WBIND_EN);
- issue_modify_qp = 1;
- }
-
- if (nesqp->user_mode) {
- nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_RDMA_WRITE_EN |
- NES_QPCONTEXT_MISC_RDMA_READ_EN);
- issue_modify_qp = 1;
- }
- }
-
- original_last_aeq = nesqp->last_aeq;
- spin_unlock_irqrestore(&nesqp->lock, qplockflags);
-
- nes_debug(NES_DBG_MOD_QP, "issue_modify_qp=%u\n", issue_modify_qp);
-
- ret = 0;
-
-
- if (issue_modify_qp) {
- nes_debug(NES_DBG_MOD_QP, "call nes_hw_modify_qp\n");
- ret = nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0, 1);
- if (ret)
- nes_debug(NES_DBG_MOD_QP, "nes_hw_modify_qp (next_iwarp_state = 0x%08X)"
- " failed for QP%u.\n",
- next_iwarp_state, nesqp->hwqp.qp_id);
-
- }
-
- if ((issue_modify_qp) && (nesqp->ibqp_state > IB_QPS_RTS)) {
- nes_debug(NES_DBG_MOD_QP, "QP%u Issued ModifyQP refcount (%d),"
- " original_last_aeq = 0x%04X. last_aeq = 0x%04X.\n",
- nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),
- original_last_aeq, nesqp->last_aeq);
- if (!ret || original_last_aeq != NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) {
- if (dont_wait) {
- if (nesqp->cm_id && nesqp->hw_tcp_state != 0) {
- nes_debug(NES_DBG_MOD_QP, "QP%u Queuing fake disconnect for QP refcount (%d),"
- " original_last_aeq = 0x%04X. last_aeq = 0x%04X.\n",
- nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),
- original_last_aeq, nesqp->last_aeq);
- /* this one is for the cm_disconnect thread */
- spin_lock_irqsave(&nesqp->lock, qplockflags);
- nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
- nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT;
- spin_unlock_irqrestore(&nesqp->lock, qplockflags);
- nes_cm_disconn(nesqp);
- } else {
- nes_debug(NES_DBG_MOD_QP, "QP%u No fake disconnect, QP refcount=%d\n",
- nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount));
- }
- } else {
- spin_lock_irqsave(&nesqp->lock, qplockflags);
- if (nesqp->cm_id) {
- /* These two are for the timer thread */
- if (atomic_inc_return(&nesqp->close_timer_started) == 1) {
- nesqp->cm_id->add_ref(nesqp->cm_id);
- nes_debug(NES_DBG_MOD_QP, "QP%u Not decrementing QP refcount (%d),"
- " need ae to finish up, original_last_aeq = 0x%04X."
- " last_aeq = 0x%04X, scheduling timer.\n",
- nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),
- original_last_aeq, nesqp->last_aeq);
- schedule_nes_timer(nesqp->cm_node, (struct sk_buff *) nesqp, NES_TIMER_TYPE_CLOSE, 1, 0);
- }
- spin_unlock_irqrestore(&nesqp->lock, qplockflags);
- } else {
- spin_unlock_irqrestore(&nesqp->lock, qplockflags);
- nes_debug(NES_DBG_MOD_QP, "QP%u Not decrementing QP refcount (%d),"
- " need ae to finish up, original_last_aeq = 0x%04X."
- " last_aeq = 0x%04X.\n",
- nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),
- original_last_aeq, nesqp->last_aeq);
- }
- }
- } else {
- nes_debug(NES_DBG_MOD_QP, "QP%u Decrementing QP refcount (%d), No ae to finish up,"
- " original_last_aeq = 0x%04X. last_aeq = 0x%04X.\n",
- nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),
- original_last_aeq, nesqp->last_aeq);
- }
- } else {
- nes_debug(NES_DBG_MOD_QP, "QP%u Decrementing QP refcount (%d), No ae to finish up,"
- " original_last_aeq = 0x%04X. last_aeq = 0x%04X.\n",
- nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),
- original_last_aeq, nesqp->last_aeq);
- }
-
- err = 0;
-
- nes_debug(NES_DBG_MOD_QP, "QP%u Leaving, refcount=%d\n",
- nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount));
-
- return err;
-}
-
-static inline void
-fill_wqe_sg_send(struct nes_hw_qp_wqe *wqe, const struct ib_send_wr *ib_wr,
- u32 uselkey)
-{
- int sge_index;
- int total_payload_length = 0;
- for (sge_index = 0; sge_index < ib_wr->num_sge; sge_index++) {
- set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_FRAG0_LOW_IDX+(sge_index*4),
- ib_wr->sg_list[sge_index].addr);
- set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_LENGTH0_IDX + (sge_index*4),
- ib_wr->sg_list[sge_index].length);
- if (uselkey)
- set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_STAG0_IDX + (sge_index*4),
- (ib_wr->sg_list[sge_index].lkey));
- else
- set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_STAG0_IDX + (sge_index*4), 0);
-
- total_payload_length += ib_wr->sg_list[sge_index].length;
- }
- nes_debug(NES_DBG_IW_TX, "UC UC UC, sending total_payload_length=%u \n",
- total_payload_length);
- set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX,
- total_payload_length);
-}
-
-/**
- * nes_post_send
- */
-static int nes_post_send(struct ib_qp *ibqp, const struct ib_send_wr *ib_wr,
- const struct ib_send_wr **bad_wr)
-{
- u64 u64temp;
- unsigned long flags = 0;
- struct nes_vnic *nesvnic = to_nesvnic(ibqp->device);
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_qp *nesqp = to_nesqp(ibqp);
- struct nes_hw_qp_wqe *wqe;
- int err = 0;
- u32 qsize = nesqp->hwqp.sq_size;
- u32 head;
- u32 wqe_misc = 0;
- u32 wqe_count = 0;
- u32 counter;
-
- if (nesqp->ibqp_state > IB_QPS_RTS) {
- err = -EINVAL;
- goto out;
- }
-
- spin_lock_irqsave(&nesqp->lock, flags);
-
- head = nesqp->hwqp.sq_head;
-
- while (ib_wr) {
- /* Check for QP error */
- if (nesqp->term_flags) {
- err = -EINVAL;
- break;
- }
-
- /* Check for SQ overflow */
- if (((head + (2 * qsize) - nesqp->hwqp.sq_tail) % qsize) == (qsize - 1)) {
- err = -ENOMEM;
- break;
- }
-
- wqe = &nesqp->hwqp.sq_vbase[head];
- /* nes_debug(NES_DBG_IW_TX, "processing sq wqe for QP%u at %p, head = %u.\n",
- nesqp->hwqp.qp_id, wqe, head); */
- nes_fill_init_qp_wqe(wqe, nesqp, head);
- u64temp = (u64)(ib_wr->wr_id);
- set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_SCRATCH_LOW_IDX,
- u64temp);
- switch (ib_wr->opcode) {
- case IB_WR_SEND:
- case IB_WR_SEND_WITH_INV:
- if (IB_WR_SEND == ib_wr->opcode) {
- if (ib_wr->send_flags & IB_SEND_SOLICITED)
- wqe_misc = NES_IWARP_SQ_OP_SENDSE;
- else
- wqe_misc = NES_IWARP_SQ_OP_SEND;
- } else {
- if (ib_wr->send_flags & IB_SEND_SOLICITED)
- wqe_misc = NES_IWARP_SQ_OP_SENDSEINV;
- else
- wqe_misc = NES_IWARP_SQ_OP_SENDINV;
-
- set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_INV_STAG_LOW_IDX,
- ib_wr->ex.invalidate_rkey);
- }
-
- if (ib_wr->num_sge > nesdev->nesadapter->max_sge) {
- err = -EINVAL;
- break;
- }
-
- if (ib_wr->send_flags & IB_SEND_FENCE)
- wqe_misc |= NES_IWARP_SQ_WQE_LOCAL_FENCE;
-
- if ((ib_wr->send_flags & IB_SEND_INLINE) &&
- ((nes_drv_opt & NES_DRV_OPT_NO_INLINE_DATA) == 0) &&
- (ib_wr->sg_list[0].length <= 64)) {
- memcpy(&wqe->wqe_words[NES_IWARP_SQ_WQE_IMM_DATA_START_IDX],
- (void *)(unsigned long)ib_wr->sg_list[0].addr, ib_wr->sg_list[0].length);
- set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX,
- ib_wr->sg_list[0].length);
- wqe_misc |= NES_IWARP_SQ_WQE_IMM_DATA;
- } else {
- fill_wqe_sg_send(wqe, ib_wr, 1);
- }
-
- break;
- case IB_WR_RDMA_WRITE:
- wqe_misc = NES_IWARP_SQ_OP_RDMAW;
- if (ib_wr->num_sge > nesdev->nesadapter->max_sge) {
- nes_debug(NES_DBG_IW_TX, "Exceeded max sge, ib_wr=%u, max=%u\n",
- ib_wr->num_sge, nesdev->nesadapter->max_sge);
- err = -EINVAL;
- break;
- }
-
- if (ib_wr->send_flags & IB_SEND_FENCE)
- wqe_misc |= NES_IWARP_SQ_WQE_LOCAL_FENCE;
-
- set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_RDMA_STAG_IDX,
- rdma_wr(ib_wr)->rkey);
- set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_RDMA_TO_LOW_IDX,
- rdma_wr(ib_wr)->remote_addr);
-
- if ((ib_wr->send_flags & IB_SEND_INLINE) &&
- ((nes_drv_opt & NES_DRV_OPT_NO_INLINE_DATA) == 0) &&
- (ib_wr->sg_list[0].length <= 64)) {
- memcpy(&wqe->wqe_words[NES_IWARP_SQ_WQE_IMM_DATA_START_IDX],
- (void *)(unsigned long)ib_wr->sg_list[0].addr, ib_wr->sg_list[0].length);
- set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX,
- ib_wr->sg_list[0].length);
- wqe_misc |= NES_IWARP_SQ_WQE_IMM_DATA;
- } else {
- fill_wqe_sg_send(wqe, ib_wr, 1);
- }
-
- wqe->wqe_words[NES_IWARP_SQ_WQE_RDMA_LENGTH_IDX] =
- wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX];
- break;
- case IB_WR_RDMA_READ:
- case IB_WR_RDMA_READ_WITH_INV:
- /* iWARP only supports 1 sge for RDMA reads */
- if (ib_wr->num_sge > 1) {
- nes_debug(NES_DBG_IW_TX, "Exceeded max sge, ib_wr=%u, max=1\n",
- ib_wr->num_sge);
- err = -EINVAL;
- break;
- }
- if (ib_wr->opcode == IB_WR_RDMA_READ) {
- wqe_misc = NES_IWARP_SQ_OP_RDMAR;
- } else {
- wqe_misc = NES_IWARP_SQ_OP_RDMAR_LOCINV;
- set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_INV_STAG_LOW_IDX,
- ib_wr->ex.invalidate_rkey);
- }
-
- set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_RDMA_TO_LOW_IDX,
- rdma_wr(ib_wr)->remote_addr);
- set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_RDMA_STAG_IDX,
- rdma_wr(ib_wr)->rkey);
- set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_RDMA_LENGTH_IDX,
- ib_wr->sg_list->length);
- set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_FRAG0_LOW_IDX,
- ib_wr->sg_list->addr);
- set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_STAG0_IDX,
- ib_wr->sg_list->lkey);
- break;
- case IB_WR_LOCAL_INV:
- wqe_misc = NES_IWARP_SQ_OP_LOCINV;
- set_wqe_32bit_value(wqe->wqe_words,
- NES_IWARP_SQ_LOCINV_WQE_INV_STAG_IDX,
- ib_wr->ex.invalidate_rkey);
- break;
- case IB_WR_REG_MR:
- {
- struct nes_mr *mr = to_nesmr(reg_wr(ib_wr)->mr);
- int page_shift = ilog2(reg_wr(ib_wr)->mr->page_size);
- int flags = reg_wr(ib_wr)->access;
-
- if (mr->npages > (NES_4K_PBL_CHUNK_SIZE / sizeof(u64))) {
- nes_debug(NES_DBG_IW_TX, "SQ_FMR: bad page_list_len\n");
- err = -EINVAL;
- break;
- }
- wqe_misc = NES_IWARP_SQ_OP_FAST_REG;
- set_wqe_64bit_value(wqe->wqe_words,
- NES_IWARP_SQ_FMR_WQE_VA_FBO_LOW_IDX,
- mr->ibmr.iova);
- set_wqe_32bit_value(wqe->wqe_words,
- NES_IWARP_SQ_FMR_WQE_LENGTH_LOW_IDX,
- lower_32_bits(mr->ibmr.length));
- set_wqe_32bit_value(wqe->wqe_words,
- NES_IWARP_SQ_FMR_WQE_LENGTH_HIGH_IDX, 0);
- set_wqe_32bit_value(wqe->wqe_words,
- NES_IWARP_SQ_FMR_WQE_MR_STAG_IDX,
- reg_wr(ib_wr)->key);
-
- if (page_shift == 12) {
- wqe_misc |= NES_IWARP_SQ_FMR_WQE_PAGE_SIZE_4K;
- } else if (page_shift == 21) {
- wqe_misc |= NES_IWARP_SQ_FMR_WQE_PAGE_SIZE_2M;
- } else {
- nes_debug(NES_DBG_IW_TX, "Invalid page shift,"
- " ib_wr=%u, max=1\n", ib_wr->num_sge);
- err = -EINVAL;
- break;
- }
-
- /* Set access_flags */
- wqe_misc |= NES_IWARP_SQ_FMR_WQE_RIGHTS_ENABLE_LOCAL_READ;
- if (flags & IB_ACCESS_LOCAL_WRITE)
- wqe_misc |= NES_IWARP_SQ_FMR_WQE_RIGHTS_ENABLE_LOCAL_WRITE;
-
- if (flags & IB_ACCESS_REMOTE_WRITE)
- wqe_misc |= NES_IWARP_SQ_FMR_WQE_RIGHTS_ENABLE_REMOTE_WRITE;
-
- if (flags & IB_ACCESS_REMOTE_READ)
- wqe_misc |= NES_IWARP_SQ_FMR_WQE_RIGHTS_ENABLE_REMOTE_READ;
-
- if (flags & IB_ACCESS_MW_BIND)
- wqe_misc |= NES_IWARP_SQ_FMR_WQE_RIGHTS_ENABLE_WINDOW_BIND;
-
- /* Fill in PBL info: */
- set_wqe_64bit_value(wqe->wqe_words,
- NES_IWARP_SQ_FMR_WQE_PBL_ADDR_LOW_IDX,
- mr->paddr);
-
- set_wqe_32bit_value(wqe->wqe_words,
- NES_IWARP_SQ_FMR_WQE_PBL_LENGTH_IDX,
- mr->npages * 8);
-
- nes_debug(NES_DBG_IW_TX, "SQ_REG_MR: iova_start: %llx, "
- "length: %lld, rkey: %0x, pgl_paddr: %llx, "
- "page_list_len: %u, wqe_misc: %x\n",
- (unsigned long long) mr->ibmr.iova,
- mr->ibmr.length,
- reg_wr(ib_wr)->key,
- (unsigned long long) mr->paddr,
- mr->npages,
- wqe_misc);
- break;
- }
- default:
- /* error */
- err = -EINVAL;
- break;
- }
-
- if (err)
- break;
-
- if ((ib_wr->send_flags & IB_SEND_SIGNALED) || nesqp->sig_all)
- wqe_misc |= NES_IWARP_SQ_WQE_SIGNALED_COMPL;
-
- wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] = cpu_to_le32(wqe_misc);
-
- ib_wr = ib_wr->next;
- head++;
- wqe_count++;
- if (head >= qsize)
- head = 0;
-
- }
-
- nesqp->hwqp.sq_head = head;
- barrier();
- while (wqe_count) {
- counter = min(wqe_count, ((u32)255));
- wqe_count -= counter;
- nes_write32(nesdev->regs + NES_WQE_ALLOC,
- (counter << 24) | 0x00800000 | nesqp->hwqp.qp_id);
- }
-
- spin_unlock_irqrestore(&nesqp->lock, flags);
-
-out:
- if (err)
- *bad_wr = ib_wr;
- return err;
-}
-
-
-/**
- * nes_post_recv
- */
-static int nes_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *ib_wr,
- const struct ib_recv_wr **bad_wr)
-{
- u64 u64temp;
- unsigned long flags = 0;
- struct nes_vnic *nesvnic = to_nesvnic(ibqp->device);
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_qp *nesqp = to_nesqp(ibqp);
- struct nes_hw_qp_wqe *wqe;
- int err = 0;
- int sge_index;
- u32 qsize = nesqp->hwqp.rq_size;
- u32 head;
- u32 wqe_count = 0;
- u32 counter;
- u32 total_payload_length;
-
- if (nesqp->ibqp_state > IB_QPS_RTS) {
- err = -EINVAL;
- goto out;
- }
-
- spin_lock_irqsave(&nesqp->lock, flags);
-
- head = nesqp->hwqp.rq_head;
-
- while (ib_wr) {
- /* Check for QP error */
- if (nesqp->term_flags) {
- err = -EINVAL;
- break;
- }
-
- if (ib_wr->num_sge > nesdev->nesadapter->max_sge) {
- err = -EINVAL;
- break;
- }
- /* Check for RQ overflow */
- if (((head + (2 * qsize) - nesqp->hwqp.rq_tail) % qsize) == (qsize - 1)) {
- err = -ENOMEM;
- break;
- }
-
- nes_debug(NES_DBG_IW_RX, "ibwr sge count = %u.\n", ib_wr->num_sge);
- wqe = &nesqp->hwqp.rq_vbase[head];
-
- /* nes_debug(NES_DBG_IW_RX, "QP%u:processing rq wqe at %p, head = %u.\n",
- nesqp->hwqp.qp_id, wqe, head); */
- nes_fill_init_qp_wqe(wqe, nesqp, head);
- u64temp = (u64)(ib_wr->wr_id);
- set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_SCRATCH_LOW_IDX,
- u64temp);
- total_payload_length = 0;
- for (sge_index=0; sge_index < ib_wr->num_sge; sge_index++) {
- set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_RQ_WQE_FRAG0_LOW_IDX+(sge_index*4),
- ib_wr->sg_list[sge_index].addr);
- set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_RQ_WQE_LENGTH0_IDX+(sge_index*4),
- ib_wr->sg_list[sge_index].length);
- set_wqe_32bit_value(wqe->wqe_words,NES_IWARP_RQ_WQE_STAG0_IDX+(sge_index*4),
- ib_wr->sg_list[sge_index].lkey);
-
- total_payload_length += ib_wr->sg_list[sge_index].length;
- }
- set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_RQ_WQE_TOTAL_PAYLOAD_IDX,
- total_payload_length);
-
- ib_wr = ib_wr->next;
- head++;
- wqe_count++;
- if (head >= qsize)
- head = 0;
- }
-
- nesqp->hwqp.rq_head = head;
- barrier();
- while (wqe_count) {
- counter = min(wqe_count, ((u32)255));
- wqe_count -= counter;
- nes_write32(nesdev->regs+NES_WQE_ALLOC, (counter<<24) | nesqp->hwqp.qp_id);
- }
-
- spin_unlock_irqrestore(&nesqp->lock, flags);
-
-out:
- if (err)
- *bad_wr = ib_wr;
- return err;
-}
-
-/**
- * nes_drain_sq - drain sq
- * @ibqp: pointer to ibqp
- */
-static void nes_drain_sq(struct ib_qp *ibqp)
-{
- struct nes_qp *nesqp = to_nesqp(ibqp);
-
- if (nesqp->hwqp.sq_tail != nesqp->hwqp.sq_head)
- wait_for_completion(&nesqp->sq_drained);
-}
-
-/**
- * nes_drain_rq - drain rq
- * @ibqp: pointer to ibqp
- */
-static void nes_drain_rq(struct ib_qp *ibqp)
-{
- struct nes_qp *nesqp = to_nesqp(ibqp);
-
- if (nesqp->hwqp.rq_tail != nesqp->hwqp.rq_head)
- wait_for_completion(&nesqp->rq_drained);
-}
-
-/**
- * nes_poll_cq
- */
-static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
-{
- u64 u64temp;
- u64 wrid;
- unsigned long flags = 0;
- struct nes_vnic *nesvnic = to_nesvnic(ibcq->device);
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_cq *nescq = to_nescq(ibcq);
- struct nes_qp *nesqp;
- struct nes_hw_cqe cqe;
- u32 head;
- u32 wq_tail = 0;
- u32 cq_size;
- u32 cqe_count = 0;
- u32 wqe_index;
- u32 u32temp;
- u32 move_cq_head = 1;
- u32 err_code;
-
- nes_debug(NES_DBG_CQ, "\n");
-
- spin_lock_irqsave(&nescq->lock, flags);
-
- head = nescq->hw_cq.cq_head;
- cq_size = nescq->hw_cq.cq_size;
-
- while (cqe_count < num_entries) {
- if ((le32_to_cpu(nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX]) &
- NES_CQE_VALID) == 0)
- break;
-
- /*
- * Make sure we read CQ entry contents *after*
- * we've checked the valid bit.
- */
- rmb();
-
- cqe = nescq->hw_cq.cq_vbase[head];
- u32temp = le32_to_cpu(cqe.cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX]);
- wqe_index = u32temp & (nesdev->nesadapter->max_qp_wr - 1);
- u32temp &= ~(NES_SW_CONTEXT_ALIGN-1);
- /* parse CQE, get completion context from WQE (either rq or sq) */
- u64temp = (((u64)(le32_to_cpu(cqe.cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX])))<<32) |
- ((u64)u32temp);
-
- if (u64temp) {
- nesqp = (struct nes_qp *)(unsigned long)u64temp;
- memset(entry, 0, sizeof *entry);
- if (cqe.cqe_words[NES_CQE_ERROR_CODE_IDX] == 0) {
- entry->status = IB_WC_SUCCESS;
- } else {
- err_code = le32_to_cpu(cqe.cqe_words[NES_CQE_ERROR_CODE_IDX]);
- if (NES_IWARP_CQE_MAJOR_DRV == (err_code >> 16)) {
- entry->status = err_code & 0x0000ffff;
-
- /* The rest of the cqe's will be marked as flushed */
- nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_ERROR_CODE_IDX] =
- cpu_to_le32((NES_IWARP_CQE_MAJOR_FLUSH << 16) |
- NES_IWARP_CQE_MINOR_FLUSH);
- } else
- entry->status = IB_WC_WR_FLUSH_ERR;
- }
-
- entry->qp = &nesqp->ibqp;
- entry->src_qp = nesqp->hwqp.qp_id;
-
- if (le32_to_cpu(cqe.cqe_words[NES_CQE_OPCODE_IDX]) & NES_CQE_SQ) {
- if (nesqp->skip_lsmm) {
- nesqp->skip_lsmm = 0;
- nesqp->hwqp.sq_tail++;
- }
-
- /* Working on a SQ Completion*/
- wrid = (((u64)(cpu_to_le32((u32)nesqp->hwqp.sq_vbase[wqe_index].
- wqe_words[NES_IWARP_SQ_WQE_COMP_SCRATCH_HIGH_IDX]))) << 32) |
- ((u64)(cpu_to_le32((u32)nesqp->hwqp.sq_vbase[wqe_index].
- wqe_words[NES_IWARP_SQ_WQE_COMP_SCRATCH_LOW_IDX])));
- entry->byte_len = le32_to_cpu(nesqp->hwqp.sq_vbase[wqe_index].
- wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX]);
-
- switch (le32_to_cpu(nesqp->hwqp.sq_vbase[wqe_index].
- wqe_words[NES_IWARP_SQ_WQE_MISC_IDX]) & 0x3f) {
- case NES_IWARP_SQ_OP_RDMAW:
- nes_debug(NES_DBG_CQ, "Operation = RDMA WRITE.\n");
- entry->opcode = IB_WC_RDMA_WRITE;
- break;
- case NES_IWARP_SQ_OP_RDMAR:
- nes_debug(NES_DBG_CQ, "Operation = RDMA READ.\n");
- entry->opcode = IB_WC_RDMA_READ;
- entry->byte_len = le32_to_cpu(nesqp->hwqp.sq_vbase[wqe_index].
- wqe_words[NES_IWARP_SQ_WQE_RDMA_LENGTH_IDX]);
- break;
- case NES_IWARP_SQ_OP_SENDINV:
- case NES_IWARP_SQ_OP_SENDSEINV:
- case NES_IWARP_SQ_OP_SEND:
- case NES_IWARP_SQ_OP_SENDSE:
- nes_debug(NES_DBG_CQ, "Operation = Send.\n");
- entry->opcode = IB_WC_SEND;
- break;
- case NES_IWARP_SQ_OP_LOCINV:
- entry->opcode = IB_WC_LOCAL_INV;
- break;
- case NES_IWARP_SQ_OP_FAST_REG:
- entry->opcode = IB_WC_REG_MR;
- break;
- }
-
- nesqp->hwqp.sq_tail = (wqe_index+1)&(nesqp->hwqp.sq_size - 1);
- if ((entry->status != IB_WC_SUCCESS) && (nesqp->hwqp.sq_tail != nesqp->hwqp.sq_head)) {
- move_cq_head = 0;
- wq_tail = nesqp->hwqp.sq_tail;
- }
- } else {
- /* Working on a RQ Completion*/
- entry->byte_len = le32_to_cpu(cqe.cqe_words[NES_CQE_PAYLOAD_LENGTH_IDX]);
- wrid = ((u64)(le32_to_cpu(nesqp->hwqp.rq_vbase[wqe_index].wqe_words[NES_IWARP_RQ_WQE_COMP_SCRATCH_LOW_IDX]))) |
- ((u64)(le32_to_cpu(nesqp->hwqp.rq_vbase[wqe_index].wqe_words[NES_IWARP_RQ_WQE_COMP_SCRATCH_HIGH_IDX]))<<32);
- entry->opcode = IB_WC_RECV;
-
- nesqp->hwqp.rq_tail = (wqe_index+1)&(nesqp->hwqp.rq_size - 1);
- if ((entry->status != IB_WC_SUCCESS) && (nesqp->hwqp.rq_tail != nesqp->hwqp.rq_head)) {
- move_cq_head = 0;
- wq_tail = nesqp->hwqp.rq_tail;
- }
- }
-
- if (nesqp->iwarp_state > NES_CQP_QP_IWARP_STATE_RTS) {
- if (nesqp->hwqp.sq_tail == nesqp->hwqp.sq_head)
- complete(&nesqp->sq_drained);
- if (nesqp->hwqp.rq_tail == nesqp->hwqp.rq_head)
- complete(&nesqp->rq_drained);
- }
-
- entry->wr_id = wrid;
- entry++;
- cqe_count++;
- }
-
- if (move_cq_head) {
- nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX] = 0;
- if (++head >= cq_size)
- head = 0;
- nescq->polled_completions++;
-
- if ((nescq->polled_completions > (cq_size / 2)) ||
- (nescq->polled_completions == 255)) {
- nes_debug(NES_DBG_CQ, "CQ%u Issuing CQE Allocate since more than half of cqes"
- " are pending %u of %u.\n",
- nescq->hw_cq.cq_number, nescq->polled_completions, cq_size);
- nes_write32(nesdev->regs+NES_CQE_ALLOC,
- nescq->hw_cq.cq_number | (nescq->polled_completions << 16));
- nescq->polled_completions = 0;
- }
- } else {
- /* Update the wqe index and set status to flush */
- wqe_index = le32_to_cpu(cqe.cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX]);
- wqe_index = (wqe_index & (~(nesdev->nesadapter->max_qp_wr - 1))) | wq_tail;
- nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX] =
- cpu_to_le32(wqe_index);
- move_cq_head = 1; /* ready for next pass */
- }
- }
-
- if (nescq->polled_completions) {
- nes_write32(nesdev->regs+NES_CQE_ALLOC,
- nescq->hw_cq.cq_number | (nescq->polled_completions << 16));
- nescq->polled_completions = 0;
- }
-
- nescq->hw_cq.cq_head = head;
- nes_debug(NES_DBG_CQ, "Reporting %u completions for CQ%u.\n",
- cqe_count, nescq->hw_cq.cq_number);
-
- spin_unlock_irqrestore(&nescq->lock, flags);
-
- return cqe_count;
-}
-
-
-/**
- * nes_req_notify_cq
- */
-static int nes_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags notify_flags)
- {
- struct nes_vnic *nesvnic = to_nesvnic(ibcq->device);
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_cq *nescq = to_nescq(ibcq);
- u32 cq_arm;
-
- nes_debug(NES_DBG_CQ, "Requesting notification for CQ%u.\n",
- nescq->hw_cq.cq_number);
-
- cq_arm = nescq->hw_cq.cq_number;
- if ((notify_flags & IB_CQ_SOLICITED_MASK) == IB_CQ_NEXT_COMP)
- cq_arm |= NES_CQE_ALLOC_NOTIFY_NEXT;
- else if ((notify_flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED)
- cq_arm |= NES_CQE_ALLOC_NOTIFY_SE;
- else
- return -EINVAL;
-
- nes_write32(nesdev->regs+NES_CQE_ALLOC, cq_arm);
- nes_read32(nesdev->regs+NES_CQE_ALLOC);
-
- return 0;
-}
-
-static int nes_port_immutable(struct ib_device *ibdev, u8 port_num,
- struct ib_port_immutable *immutable)
-{
- struct ib_port_attr attr;
- int err;
-
- immutable->core_cap_flags = RDMA_CORE_PORT_IWARP;
-
- err = nes_query_port(ibdev, port_num, &attr);
- if (err)
- return err;
-
- immutable->pkey_tbl_len = attr.pkey_tbl_len;
- immutable->gid_tbl_len = attr.gid_tbl_len;
-
- return 0;
-}
-
-static void get_dev_fw_str(struct ib_device *dev, char *str)
-{
- struct nes_ib_device *nesibdev =
- container_of(dev, struct nes_ib_device, ibdev);
- struct nes_vnic *nesvnic = nesibdev->nesvnic;
-
- nes_debug(NES_DBG_INIT, "\n");
- snprintf(str, IB_FW_VERSION_NAME_MAX, "%u.%u",
- (nesvnic->nesdev->nesadapter->firmware_version >> 16),
- (nesvnic->nesdev->nesadapter->firmware_version & 0x000000ff));
-}
-
-static const struct ib_device_ops nes_dev_ops = {
- .alloc_mr = nes_alloc_mr,
- .alloc_mw = nes_alloc_mw,
- .alloc_pd = nes_alloc_pd,
- .alloc_ucontext = nes_alloc_ucontext,
- .create_cq = nes_create_cq,
- .create_qp = nes_create_qp,
- .dealloc_mw = nes_dealloc_mw,
- .dealloc_pd = nes_dealloc_pd,
- .dealloc_ucontext = nes_dealloc_ucontext,
- .dereg_mr = nes_dereg_mr,
- .destroy_cq = nes_destroy_cq,
- .destroy_qp = nes_destroy_qp,
- .drain_rq = nes_drain_rq,
- .drain_sq = nes_drain_sq,
- .get_dev_fw_str = get_dev_fw_str,
- .get_dma_mr = nes_get_dma_mr,
- .get_port_immutable = nes_port_immutable,
- .iw_accept = nes_accept,
- .iw_add_ref = nes_add_ref,
- .iw_connect = nes_connect,
- .iw_create_listen = nes_create_listen,
- .iw_destroy_listen = nes_destroy_listen,
- .iw_get_qp = nes_get_qp,
- .iw_reject = nes_reject,
- .iw_rem_ref = nes_rem_ref,
- .map_mr_sg = nes_map_mr_sg,
- .mmap = nes_mmap,
- .modify_qp = nes_modify_qp,
- .poll_cq = nes_poll_cq,
- .post_recv = nes_post_recv,
- .post_send = nes_post_send,
- .query_device = nes_query_device,
- .query_gid = nes_query_gid,
- .query_pkey = nes_query_pkey,
- .query_port = nes_query_port,
- .query_qp = nes_query_qp,
- .reg_user_mr = nes_reg_user_mr,
- .req_notify_cq = nes_req_notify_cq,
- INIT_RDMA_OBJ_SIZE(ib_pd, nes_pd, ibpd),
- INIT_RDMA_OBJ_SIZE(ib_ucontext, nes_ucontext, ibucontext),
-};
-
-/**
- * nes_init_ofa_device
- */
-struct nes_ib_device *nes_init_ofa_device(struct net_device *netdev)
-{
- struct nes_ib_device *nesibdev;
- struct nes_vnic *nesvnic = netdev_priv(netdev);
- struct nes_device *nesdev = nesvnic->nesdev;
-
- nesibdev = ib_alloc_device(nes_ib_device, ibdev);
- if (nesibdev == NULL) {
- return NULL;
- }
- nesibdev->ibdev.owner = THIS_MODULE;
-
- nesibdev->ibdev.node_type = RDMA_NODE_RNIC;
- memset(&nesibdev->ibdev.node_guid, 0, sizeof(nesibdev->ibdev.node_guid));
- memcpy(&nesibdev->ibdev.node_guid, netdev->dev_addr, 6);
-
- nesibdev->ibdev.uverbs_cmd_mask =
- (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
- (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |
- (1ull << IB_USER_VERBS_CMD_QUERY_PORT) |
- (1ull << IB_USER_VERBS_CMD_ALLOC_PD) |
- (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) |
- (1ull << IB_USER_VERBS_CMD_REG_MR) |
- (1ull << IB_USER_VERBS_CMD_DEREG_MR) |
- (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) |
- (1ull << IB_USER_VERBS_CMD_CREATE_CQ) |
- (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) |
- (1ull << IB_USER_VERBS_CMD_CREATE_AH) |
- (1ull << IB_USER_VERBS_CMD_DESTROY_AH) |
- (1ull << IB_USER_VERBS_CMD_REQ_NOTIFY_CQ) |
- (1ull << IB_USER_VERBS_CMD_CREATE_QP) |
- (1ull << IB_USER_VERBS_CMD_MODIFY_QP) |
- (1ull << IB_USER_VERBS_CMD_POLL_CQ) |
- (1ull << IB_USER_VERBS_CMD_DESTROY_QP) |
- (1ull << IB_USER_VERBS_CMD_ALLOC_MW) |
- (1ull << IB_USER_VERBS_CMD_BIND_MW) |
- (1ull << IB_USER_VERBS_CMD_DEALLOC_MW) |
- (1ull << IB_USER_VERBS_CMD_POST_RECV) |
- (1ull << IB_USER_VERBS_CMD_POST_SEND);
-
- nesibdev->ibdev.phys_port_cnt = 1;
- nesibdev->ibdev.num_comp_vectors = 1;
- nesibdev->ibdev.dev.parent = &nesdev->pcidev->dev;
-
- ib_set_device_ops(&nesibdev->ibdev, &nes_dev_ops);
- memcpy(nesibdev->ibdev.iw_ifname, netdev->name,
- sizeof(nesibdev->ibdev.iw_ifname));
-
- return nesibdev;
-}
-
-
-/**
- * nes_handle_delayed_event
- */
-static void nes_handle_delayed_event(struct timer_list *t)
-{
- struct nes_vnic *nesvnic = from_timer(nesvnic, t, event_timer);
-
- if (nesvnic->delayed_event != nesvnic->last_dispatched_event) {
- struct ib_event event;
-
- event.device = &nesvnic->nesibdev->ibdev;
- if (!event.device)
- goto stop_timer;
- event.event = nesvnic->delayed_event;
- event.element.port_num = nesvnic->logical_port + 1;
- ib_dispatch_event(&event);
- }
-
-stop_timer:
- nesvnic->event_timer.function = NULL;
-}
-
-
-void nes_port_ibevent(struct nes_vnic *nesvnic)
-{
- struct nes_ib_device *nesibdev = nesvnic->nesibdev;
- struct nes_device *nesdev = nesvnic->nesdev;
- struct ib_event event;
- event.device = &nesibdev->ibdev;
- event.element.port_num = nesvnic->logical_port + 1;
- event.event = nesdev->iw_status ? IB_EVENT_PORT_ACTIVE : IB_EVENT_PORT_ERR;
-
- if (!nesvnic->event_timer.function) {
- ib_dispatch_event(&event);
- nesvnic->last_dispatched_event = event.event;
- nesvnic->event_timer.function = nes_handle_delayed_event;
- nesvnic->event_timer.expires = jiffies + NES_EVENT_DELAY;
- add_timer(&nesvnic->event_timer);
- } else {
- mod_timer(&nesvnic->event_timer, jiffies + NES_EVENT_DELAY);
- }
- nesvnic->delayed_event = event.event;
-}
-
-
-/**
- * nes_destroy_ofa_device
- */
-void nes_destroy_ofa_device(struct nes_ib_device *nesibdev)
-{
- if (nesibdev == NULL)
- return;
-
- nes_unregister_ofa_device(nesibdev);
-
- ib_dealloc_device(&nesibdev->ibdev);
-}
-
-
-/**
- * nes_register_ofa_device
- */
-int nes_register_ofa_device(struct nes_ib_device *nesibdev)
-{
- struct nes_vnic *nesvnic = nesibdev->nesvnic;
- struct nes_device *nesdev = nesvnic->nesdev;
- struct nes_adapter *nesadapter = nesdev->nesadapter;
- int ret;
-
- rdma_set_device_sysfs_group(&nesvnic->nesibdev->ibdev, &nes_attr_group);
- nesvnic->nesibdev->ibdev.driver_id = RDMA_DRIVER_NES;
- ret = ib_register_device(&nesvnic->nesibdev->ibdev, "nes%d");
- if (ret) {
- return ret;
- }
-
- /* Get the resources allocated to this device */
- nesibdev->max_cq = (nesadapter->max_cq-NES_FIRST_QPN) / nesadapter->port_count;
- nesibdev->max_mr = nesadapter->max_mr / nesadapter->port_count;
- nesibdev->max_qp = (nesadapter->max_qp-NES_FIRST_QPN) / nesadapter->port_count;
- nesibdev->max_pd = nesadapter->max_pd / nesadapter->port_count;
-
- nesvnic->of_device_registered = 1;
-
- return 0;
-}
-
-
-/**
- * nes_unregister_ofa_device
- */
-static void nes_unregister_ofa_device(struct nes_ib_device *nesibdev)
-{
- struct nes_vnic *nesvnic = nesibdev->nesvnic;
-
- if (nesvnic->of_device_registered)
- ib_unregister_device(&nesibdev->ibdev);
-
- nesvnic->of_device_registered = 0;
-}
diff --git a/drivers/infiniband/hw/nes/nes_verbs.h b/drivers/infiniband/hw/nes/nes_verbs.h
deleted file mode 100644
index 114a9b59fefd..000000000000
--- a/drivers/infiniband/hw/nes/nes_verbs.h
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (c) 2006 - 2011 Intel Corporation. All rights reserved.
- * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-#ifndef NES_VERBS_H
-#define NES_VERBS_H
-
-struct nes_device;
-
-#define NES_MAX_USER_DB_REGIONS 4096
-#define NES_MAX_USER_WQ_REGIONS 4096
-
-#define NES_TERM_SENT 0x01
-#define NES_TERM_RCVD 0x02
-#define NES_TERM_DONE 0x04
-
-struct nes_ucontext {
- struct ib_ucontext ibucontext;
- struct nes_device *nesdev;
- unsigned long mmap_wq_offset;
- unsigned long mmap_cq_offset; /* to be removed */
- int index; /* rnic index (minor) */
- unsigned long allocated_doorbells[BITS_TO_LONGS(NES_MAX_USER_DB_REGIONS)];
- u16 mmap_db_index[NES_MAX_USER_DB_REGIONS];
- u16 first_free_db;
- unsigned long allocated_wqs[BITS_TO_LONGS(NES_MAX_USER_WQ_REGIONS)];
- struct nes_qp *mmap_nesqp[NES_MAX_USER_WQ_REGIONS];
- u16 first_free_wq;
- struct list_head cq_reg_mem_list;
- struct list_head qp_reg_mem_list;
- u32 mcrqf;
-};
-
-struct nes_pd {
- struct ib_pd ibpd;
- u16 pd_id;
- atomic_t sqp_count;
- u16 mmap_db_index;
-};
-
-struct nes_mr {
- union {
- struct ib_mr ibmr;
- struct ib_mw ibmw;
- struct ib_fmr ibfmr;
- };
- struct ib_umem *region;
- u16 pbls_used;
- u8 mode;
- u8 pbl_4k;
- __le64 *pages;
- dma_addr_t paddr;
- u32 max_pages;
- u32 npages;
-};
-
-struct nes_hw_pb {
- __le32 pa_low;
- __le32 pa_high;
-};
-
-struct nes_vpbl {
- dma_addr_t pbl_pbase;
- struct nes_hw_pb *pbl_vbase;
-};
-
-struct nes_root_vpbl {
- dma_addr_t pbl_pbase;
- struct nes_hw_pb *pbl_vbase;
- struct nes_vpbl *leaf_vpbl;
-};
-
-struct nes_fmr {
- struct nes_mr nesmr;
- u32 leaf_pbl_cnt;
- struct nes_root_vpbl root_vpbl;
- struct ib_qp *ib_qp;
- int access_rights;
- struct ib_fmr_attr attr;
-};
-
-struct nes_av;
-
-struct nes_cq {
- struct ib_cq ibcq;
- struct nes_hw_cq hw_cq;
- u32 polled_completions;
- u32 cq_mem_size;
- spinlock_t lock;
- u8 virtual_cq;
- u8 pad[3];
- u32 mcrqf;
-};
-
-struct nes_wq {
- spinlock_t lock;
-};
-
-struct disconn_work {
- struct work_struct work;
- struct nes_qp *nesqp;
-};
-
-struct iw_cm_id;
-struct ietf_mpa_frame;
-
-struct nes_qp {
- struct ib_qp ibqp;
- void *allocated_buffer;
- struct iw_cm_id *cm_id;
- struct nes_cq *nesscq;
- struct nes_cq *nesrcq;
- struct nes_pd *nespd;
- void *cm_node; /* handle of the node this QP is associated with */
- void *ietf_frame;
- u8 ietf_frame_size;
- dma_addr_t ietf_frame_pbase;
- struct ib_mr *lsmm_mr;
- struct nes_hw_qp hwqp;
- struct work_struct work;
- enum ib_qp_state ibqp_state;
- u32 iwarp_state;
- u32 hte_index;
- u32 last_aeq;
- u32 qp_mem_size;
- atomic_t refcount;
- atomic_t close_timer_started;
- u32 mmap_sq_db_index;
- u32 mmap_rq_db_index;
- spinlock_t lock;
- spinlock_t pau_lock;
- struct nes_qp_context *nesqp_context;
- dma_addr_t nesqp_context_pbase;
- void *pbl_vbase;
- dma_addr_t pbl_pbase;
- struct page *page;
- struct timer_list terminate_timer;
- enum ib_event_type terminate_eventtype;
- struct sk_buff_head pau_list;
- u32 pau_rcv_nxt;
- u16 active_conn:1;
- u16 skip_lsmm:1;
- u16 user_mode:1;
- u16 hte_added:1;
- u16 flush_issued:1;
- u16 destroyed:1;
- u16 sig_all:1;
- u16 pau_mode:1;
- u16 rsvd:8;
- u16 private_data_len;
- u16 term_sq_flush_code;
- u16 term_rq_flush_code;
- u8 hw_iwarp_state;
- u8 hw_tcp_state;
- u8 term_flags;
- u8 sq_kmapped;
- u8 pau_busy;
- u8 pau_pending;
- u8 pau_state;
- __u64 nesuqp_addr;
- struct completion sq_drained;
- struct completion rq_drained;
-};
-
-struct ib_mr *nes_reg_phys_mr(struct ib_pd *ib_pd,
- u64 addr, u64 size, int acc, u64 *iova_start);
-
-#endif /* NES_VERBS_H */
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
index 5127e2ea4bdd..d82d3ec3649e 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
@@ -1351,7 +1351,6 @@ static int ocrdma_mbx_get_ctrl_attribs(struct ocrdma_dev *dev)
mqe->u.nonemb_req.sge[0].pa_hi = (u32) upper_32_bits(dma.pa);
mqe->u.nonemb_req.sge[0].len = dma.size;
- memset(dma.va, 0, dma.size);
ocrdma_init_mch((struct ocrdma_mbx_hdr *)dma.va,
OCRDMA_CMD_GET_CTRL_ATTRIBUTES,
OCRDMA_SUBSYS_COMMON,
@@ -1690,7 +1689,6 @@ static int ocrdma_mbx_create_ah_tbl(struct ocrdma_dev *dev)
goto mem_err_ah;
dev->av_tbl.pa = pa;
dev->av_tbl.num_ah = max_ah;
- memset(dev->av_tbl.va, 0, dev->av_tbl.size);
pbes = (struct ocrdma_pbe *)dev->av_tbl.pbl.va;
for (i = 0; i < dev->av_tbl.size / OCRDMA_MIN_Q_PAGE_SIZE; i++) {
@@ -1888,14 +1886,13 @@ mem_err:
return status;
}
-int ocrdma_mbx_destroy_cq(struct ocrdma_dev *dev, struct ocrdma_cq *cq)
+void ocrdma_mbx_destroy_cq(struct ocrdma_dev *dev, struct ocrdma_cq *cq)
{
- int status = -ENOMEM;
struct ocrdma_destroy_cq *cmd;
cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_DELETE_CQ, sizeof(*cmd));
if (!cmd)
- return status;
+ return;
ocrdma_init_mch(&cmd->req, OCRDMA_CMD_DELETE_CQ,
OCRDMA_SUBSYS_COMMON, sizeof(*cmd));
@@ -1903,11 +1900,10 @@ int ocrdma_mbx_destroy_cq(struct ocrdma_dev *dev, struct ocrdma_cq *cq)
(cq->id << OCRDMA_DESTROY_CQ_QID_SHIFT) &
OCRDMA_DESTROY_CQ_QID_MASK;
- status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
ocrdma_unbind_eq(dev, cq->eqn);
dma_free_coherent(&dev->nic_info.pdev->dev, cq->len, cq->va, cq->pa);
kfree(cmd);
- return status;
}
int ocrdma_mbx_alloc_lkey(struct ocrdma_dev *dev, struct ocrdma_hw_mr *hwmr,
@@ -2905,7 +2901,6 @@ static int ocrdma_mbx_get_dcbx_config(struct ocrdma_dev *dev, u32 ptype,
mqe_sge->pa_hi = (u32) upper_32_bits(pa);
mqe_sge->len = cmd.hdr.pyld_len;
- memset(req, 0, sizeof(struct ocrdma_get_dcbx_cfg_req));
ocrdma_init_mch(&req->hdr, OCRDMA_CMD_GET_DCBX_CONFIG,
OCRDMA_SUBSYS_DCBX, cmd.hdr.pyld_len);
req->param_type = ptype;
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_hw.h b/drivers/infiniband/hw/ocrdma/ocrdma_hw.h
index 06ec59326a90..12c23a7652b9 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_hw.h
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_hw.h
@@ -122,7 +122,7 @@ int ocrdma_reg_mr(struct ocrdma_dev *, struct ocrdma_hw_mr *hwmr,
u32 pd_id, int acc);
int ocrdma_mbx_create_cq(struct ocrdma_dev *, struct ocrdma_cq *,
int entries, int dpp_cq, u16 pd_id);
-int ocrdma_mbx_destroy_cq(struct ocrdma_dev *, struct ocrdma_cq *);
+void ocrdma_mbx_destroy_cq(struct ocrdma_dev *dev, struct ocrdma_cq *cq);
int ocrdma_mbx_create_qp(struct ocrdma_qp *, struct ib_qp_init_attr *attrs,
u8 enable_dpp_cq, u16 dpp_cq_id, u16 *dpp_offset,
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_main.c b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
index fc6c0962dea9..c15cfc6cef81 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_main.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
@@ -144,6 +144,10 @@ static const struct attribute_group ocrdma_attr_group = {
};
static const struct ib_device_ops ocrdma_dev_ops = {
+ .owner = THIS_MODULE,
+ .driver_id = RDMA_DRIVER_OCRDMA,
+ .uverbs_abi_ver = OCRDMA_ABI_VERSION,
+
.alloc_mr = ocrdma_alloc_mr,
.alloc_pd = ocrdma_alloc_pd,
.alloc_ucontext = ocrdma_alloc_ucontext,
@@ -178,6 +182,7 @@ static const struct ib_device_ops ocrdma_dev_ops = {
.resize_cq = ocrdma_resize_cq,
INIT_RDMA_OBJ_SIZE(ib_ah, ocrdma_ah, ibah),
+ INIT_RDMA_OBJ_SIZE(ib_cq, ocrdma_cq, ibcq),
INIT_RDMA_OBJ_SIZE(ib_pd, ocrdma_pd, ibpd),
INIT_RDMA_OBJ_SIZE(ib_ucontext, ocrdma_ucontext, ibucontext),
};
@@ -200,8 +205,6 @@ static int ocrdma_register_device(struct ocrdma_dev *dev)
BUILD_BUG_ON(sizeof(OCRDMA_NODE_DESC) > IB_DEVICE_NODE_DESC_MAX);
memcpy(dev->ibdev.node_desc, OCRDMA_NODE_DESC,
sizeof(OCRDMA_NODE_DESC));
- dev->ibdev.owner = THIS_MODULE;
- dev->ibdev.uverbs_abi_ver = OCRDMA_ABI_VERSION;
dev->ibdev.uverbs_cmd_mask =
OCRDMA_UVERBS(GET_CONTEXT) |
OCRDMA_UVERBS(QUERY_DEVICE) |
@@ -249,7 +252,6 @@ static int ocrdma_register_device(struct ocrdma_dev *dev)
ib_set_device_ops(&dev->ibdev, &ocrdma_dev_srq_ops);
}
rdma_set_device_sysfs_group(&dev->ibdev, &ocrdma_attr_group);
- dev->ibdev.driver_id = RDMA_DRIVER_OCRDMA;
ret = ib_device_set_netdev(&dev->ibdev, dev->nic_info.netdev, 1);
if (ret)
return ret;
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
index 35ec87015792..bccc11378109 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
@@ -925,8 +925,7 @@ int ocrdma_dereg_mr(struct ib_mr *ib_mr, struct ib_udata *udata)
ocrdma_free_mr_pbl_tbl(dev, &mr->hwmr);
/* it could be user registered memory. */
- if (mr->umem)
- ib_umem_release(mr->umem);
+ ib_umem_release(mr->umem);
kfree(mr);
/* Don't stop cleanup, in case FW is unresponsive */
@@ -977,12 +976,12 @@ err:
return status;
}
-struct ib_cq *ocrdma_create_cq(struct ib_device *ibdev,
- const struct ib_cq_init_attr *attr,
- struct ib_udata *udata)
+int ocrdma_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata)
{
+ struct ib_device *ibdev = ibcq->device;
int entries = attr->cqe;
- struct ocrdma_cq *cq;
+ struct ocrdma_cq *cq = get_ocrdma_cq(ibcq);
struct ocrdma_dev *dev = get_ocrdma_dev(ibdev);
struct ocrdma_ucontext *uctx = rdma_udata_to_drv_context(
udata, struct ocrdma_ucontext, ibucontext);
@@ -991,16 +990,13 @@ struct ib_cq *ocrdma_create_cq(struct ib_device *ibdev,
struct ocrdma_create_cq_ureq ureq;
if (attr->flags)
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
if (udata) {
if (ib_copy_from_udata(&ureq, udata, sizeof(ureq)))
- return ERR_PTR(-EFAULT);
+ return -EFAULT;
} else
ureq.dpp_cq = 0;
- cq = kzalloc(sizeof(*cq), GFP_KERNEL);
- if (!cq)
- return ERR_PTR(-ENOMEM);
spin_lock_init(&cq->cq_lock);
spin_lock_init(&cq->comp_handler_lock);
@@ -1011,10 +1007,9 @@ struct ib_cq *ocrdma_create_cq(struct ib_device *ibdev,
pd_id = uctx->cntxt_pd->id;
status = ocrdma_mbx_create_cq(dev, cq, entries, ureq.dpp_cq, pd_id);
- if (status) {
- kfree(cq);
- return ERR_PTR(status);
- }
+ if (status)
+ return status;
+
if (udata) {
status = ocrdma_copy_cq_uresp(dev, cq, udata);
if (status)
@@ -1022,12 +1017,11 @@ struct ib_cq *ocrdma_create_cq(struct ib_device *ibdev,
}
cq->phase = OCRDMA_CQE_VALID;
dev->cq_tbl[cq->id] = cq;
- return &cq->ibcq;
+ return 0;
ctx_err:
ocrdma_mbx_destroy_cq(dev, cq);
- kfree(cq);
- return ERR_PTR(status);
+ return status;
}
int ocrdma_resize_cq(struct ib_cq *ibcq, int new_cnt,
@@ -1070,7 +1064,7 @@ static void ocrdma_flush_cq(struct ocrdma_cq *cq)
spin_unlock_irqrestore(&cq->cq_lock, flags);
}
-int ocrdma_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
+void ocrdma_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
{
struct ocrdma_cq *cq = get_ocrdma_cq(ibcq);
struct ocrdma_eq *eq = NULL;
@@ -1080,14 +1074,13 @@ int ocrdma_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
dev->cq_tbl[cq->id] = NULL;
indx = ocrdma_get_eq_table_index(dev, cq->eqn);
- BUG_ON(indx == -EINVAL);
eq = &dev->eq_tbl[indx];
irq = ocrdma_get_irq(dev, eq);
synchronize_irq(irq);
ocrdma_flush_cq(cq);
- (void)ocrdma_mbx_destroy_cq(dev, cq);
+ ocrdma_mbx_destroy_cq(dev, cq);
if (cq->ucontext) {
pdid = cq->ucontext->cntxt_pd->id;
ocrdma_del_mmap(cq->ucontext, (u64) cq->pa,
@@ -1096,9 +1089,6 @@ int ocrdma_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
ocrdma_get_db_addr(dev, pdid),
dev->nic_info.db_page_size);
}
-
- kfree(cq);
- return 0;
}
static int ocrdma_add_qpn_map(struct ocrdma_dev *dev, struct ocrdma_qp *qp)
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.h b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.h
index d76aae7ed0d3..32488da1b752 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.h
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.h
@@ -71,11 +71,10 @@ int ocrdma_mmap(struct ib_ucontext *, struct vm_area_struct *vma);
int ocrdma_alloc_pd(struct ib_pd *pd, struct ib_udata *udata);
void ocrdma_dealloc_pd(struct ib_pd *pd, struct ib_udata *udata);
-struct ib_cq *ocrdma_create_cq(struct ib_device *ibdev,
- const struct ib_cq_init_attr *attr,
- struct ib_udata *udata);
+int ocrdma_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata);
int ocrdma_resize_cq(struct ib_cq *, int cqe, struct ib_udata *);
-int ocrdma_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata);
+void ocrdma_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata);
struct ib_qp *ocrdma_create_qp(struct ib_pd *,
struct ib_qp_init_attr *attrs,
diff --git a/drivers/infiniband/hw/qedr/main.c b/drivers/infiniband/hw/qedr/main.c
index 083c2c00a8e9..533157a2a3be 100644
--- a/drivers/infiniband/hw/qedr/main.c
+++ b/drivers/infiniband/hw/qedr/main.c
@@ -183,6 +183,10 @@ static void qedr_roce_register_device(struct qedr_dev *dev)
}
static const struct ib_device_ops qedr_dev_ops = {
+ .owner = THIS_MODULE,
+ .driver_id = RDMA_DRIVER_QEDR,
+ .uverbs_abi_ver = QEDR_ABI_VERSION,
+
.alloc_mr = qedr_alloc_mr,
.alloc_pd = qedr_alloc_pd,
.alloc_ucontext = qedr_alloc_ucontext,
@@ -220,6 +224,7 @@ static const struct ib_device_ops qedr_dev_ops = {
.resize_cq = qedr_resize_cq,
INIT_RDMA_OBJ_SIZE(ib_ah, qedr_ah, ibah),
+ INIT_RDMA_OBJ_SIZE(ib_cq, qedr_cq, ibcq),
INIT_RDMA_OBJ_SIZE(ib_pd, qedr_pd, ibpd),
INIT_RDMA_OBJ_SIZE(ib_srq, qedr_srq, ibsrq),
INIT_RDMA_OBJ_SIZE(ib_ucontext, qedr_ucontext, ibucontext),
@@ -231,8 +236,6 @@ static int qedr_register_device(struct qedr_dev *dev)
dev->ibdev.node_guid = dev->attr.node_guid;
memcpy(dev->ibdev.node_desc, QEDR_NODE_DESC, sizeof(QEDR_NODE_DESC));
- dev->ibdev.owner = THIS_MODULE;
- dev->ibdev.uverbs_abi_ver = QEDR_ABI_VERSION;
dev->ibdev.uverbs_cmd_mask = QEDR_UVERBS(GET_CONTEXT) |
QEDR_UVERBS(QUERY_DEVICE) |
@@ -274,7 +277,6 @@ static int qedr_register_device(struct qedr_dev *dev)
rdma_set_device_sysfs_group(&dev->ibdev, &qedr_attr_group);
ib_set_device_ops(&dev->ibdev, &qedr_dev_ops);
- dev->ibdev.driver_id = RDMA_DRIVER_QEDR;
rc = ib_device_set_netdev(&dev->ibdev, dev->ndev, 1);
if (rc)
return rc;
@@ -312,7 +314,8 @@ static void qedr_free_mem_sb(struct qedr_dev *dev,
struct qed_sb_info *sb_info, int sb_id)
{
if (sb_info->sb_virt) {
- dev->ops->common->sb_release(dev->cdev, sb_info, sb_id);
+ dev->ops->common->sb_release(dev->cdev, sb_info, sb_id,
+ QED_SB_TYPE_CNQ);
dma_free_coherent(&dev->pdev->dev, sizeof(*sb_info->sb_virt),
(void *)sb_info->sb_virt, sb_info->sb_phys);
}
@@ -504,11 +507,13 @@ static irqreturn_t qedr_irq_handler(int irq, void *handle)
static void qedr_sync_free_irqs(struct qedr_dev *dev)
{
u32 vector;
+ u16 idx;
int i;
for (i = 0; i < dev->int_info.used_cnt; i++) {
if (dev->int_info.msix_cnt) {
- vector = dev->int_info.msix[i * dev->num_hwfns].vector;
+ idx = i * dev->num_hwfns + dev->affin_hwfn_idx;
+ vector = dev->int_info.msix[idx].vector;
synchronize_irq(vector);
free_irq(vector, &dev->cnq_array[i]);
}
@@ -520,6 +525,7 @@ static void qedr_sync_free_irqs(struct qedr_dev *dev)
static int qedr_req_msix_irqs(struct qedr_dev *dev)
{
int i, rc = 0;
+ u16 idx;
if (dev->num_cnq > dev->int_info.msix_cnt) {
DP_ERR(dev,
@@ -529,7 +535,8 @@ static int qedr_req_msix_irqs(struct qedr_dev *dev)
}
for (i = 0; i < dev->num_cnq; i++) {
- rc = request_irq(dev->int_info.msix[i * dev->num_hwfns].vector,
+ idx = i * dev->num_hwfns + dev->affin_hwfn_idx;
+ rc = request_irq(dev->int_info.msix[idx].vector,
qedr_irq_handler, 0, dev->cnq_array[i].name,
&dev->cnq_array[i]);
if (rc) {
@@ -866,6 +873,16 @@ static struct qedr_dev *qedr_add(struct qed_dev *cdev, struct pci_dev *pdev,
dev->user_dpm_enabled = dev_info.user_dpm_enabled;
dev->rdma_type = dev_info.rdma_type;
dev->num_hwfns = dev_info.common.num_hwfns;
+
+ if (IS_IWARP(dev) && QEDR_IS_CMT(dev)) {
+ rc = dev->ops->iwarp_set_engine_affin(cdev, false);
+ if (rc) {
+ DP_ERR(dev, "iWARP is disabled over a 100g device Enabling it may impact L2 performance. To enable it run devlink dev param set <dev> name iwarp_cmt value true cmode runtime\n");
+ goto init_err;
+ }
+ }
+ dev->affin_hwfn_idx = dev->ops->common->get_affin_hwfn_idx(cdev);
+
dev->rdma_ctx = dev->ops->rdma_get_rdma_ctx(cdev);
dev->num_cnq = dev->ops->rdma_get_min_cnq_msix(cdev);
@@ -926,6 +943,10 @@ static void qedr_remove(struct qedr_dev *dev)
qedr_stop_hw(dev);
qedr_sync_free_irqs(dev);
qedr_free_resources(dev);
+
+ if (IS_IWARP(dev) && QEDR_IS_CMT(dev))
+ dev->ops->iwarp_set_engine_affin(dev->cdev, true);
+
ib_dealloc_device(&dev->ibdev);
}
diff --git a/drivers/infiniband/hw/qedr/qedr.h b/drivers/infiniband/hw/qedr/qedr.h
index 6175d1e98717..a92ca22e5de1 100644
--- a/drivers/infiniband/hw/qedr/qedr.h
+++ b/drivers/infiniband/hw/qedr/qedr.h
@@ -157,6 +157,8 @@ struct qedr_dev {
u32 dp_module;
u8 dp_level;
u8 num_hwfns;
+#define QEDR_IS_CMT(dev) ((dev)->num_hwfns > 1)
+ u8 affin_hwfn_idx;
u8 gsi_ll2_handle;
uint wq_multiplier;
diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c
index 3d7bde19838e..27d90a84ea01 100644
--- a/drivers/infiniband/hw/qedr/verbs.c
+++ b/drivers/infiniband/hw/qedr/verbs.c
@@ -159,54 +159,47 @@ int qedr_query_device(struct ib_device *ibdev,
return 0;
}
-#define QEDR_SPEED_SDR (1)
-#define QEDR_SPEED_DDR (2)
-#define QEDR_SPEED_QDR (4)
-#define QEDR_SPEED_FDR10 (8)
-#define QEDR_SPEED_FDR (16)
-#define QEDR_SPEED_EDR (32)
-
static inline void get_link_speed_and_width(int speed, u8 *ib_speed,
u8 *ib_width)
{
switch (speed) {
case 1000:
- *ib_speed = QEDR_SPEED_SDR;
+ *ib_speed = IB_SPEED_SDR;
*ib_width = IB_WIDTH_1X;
break;
case 10000:
- *ib_speed = QEDR_SPEED_QDR;
+ *ib_speed = IB_SPEED_QDR;
*ib_width = IB_WIDTH_1X;
break;
case 20000:
- *ib_speed = QEDR_SPEED_DDR;
+ *ib_speed = IB_SPEED_DDR;
*ib_width = IB_WIDTH_4X;
break;
case 25000:
- *ib_speed = QEDR_SPEED_EDR;
+ *ib_speed = IB_SPEED_EDR;
*ib_width = IB_WIDTH_1X;
break;
case 40000:
- *ib_speed = QEDR_SPEED_QDR;
+ *ib_speed = IB_SPEED_QDR;
*ib_width = IB_WIDTH_4X;
break;
case 50000:
- *ib_speed = QEDR_SPEED_QDR;
- *ib_width = IB_WIDTH_4X;
+ *ib_speed = IB_SPEED_HDR;
+ *ib_width = IB_WIDTH_1X;
break;
case 100000:
- *ib_speed = QEDR_SPEED_EDR;
+ *ib_speed = IB_SPEED_EDR;
*ib_width = IB_WIDTH_4X;
break;
default:
/* Unsupported */
- *ib_speed = QEDR_SPEED_SDR;
+ *ib_speed = IB_SPEED_SDR;
*ib_width = IB_WIDTH_1X;
}
}
@@ -813,20 +806,20 @@ int qedr_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags)
return 0;
}
-struct ib_cq *qedr_create_cq(struct ib_device *ibdev,
- const struct ib_cq_init_attr *attr,
- struct ib_udata *udata)
+int qedr_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata)
{
+ struct ib_device *ibdev = ibcq->device;
struct qedr_ucontext *ctx = rdma_udata_to_drv_context(
udata, struct qedr_ucontext, ibucontext);
struct qed_rdma_destroy_cq_out_params destroy_oparams;
struct qed_rdma_destroy_cq_in_params destroy_iparams;
struct qedr_dev *dev = get_qedr_dev(ibdev);
struct qed_rdma_create_cq_in_params params;
- struct qedr_create_cq_ureq ureq;
+ struct qedr_create_cq_ureq ureq = {};
int vector = attr->comp_vector;
int entries = attr->cqe;
- struct qedr_cq *cq;
+ struct qedr_cq *cq = get_qedr_cq(ibcq);
int chain_entries;
int page_cnt;
u64 pbl_ptr;
@@ -841,18 +834,13 @@ struct ib_cq *qedr_create_cq(struct ib_device *ibdev,
DP_ERR(dev,
"create cq: the number of entries %d is too high. Must be equal or below %d.\n",
entries, QEDR_MAX_CQES);
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
}
chain_entries = qedr_align_cq_entries(entries);
chain_entries = min_t(int, chain_entries, QEDR_MAX_CQES);
- cq = kzalloc(sizeof(*cq), GFP_KERNEL);
- if (!cq)
- return ERR_PTR(-ENOMEM);
-
if (udata) {
- memset(&ureq, 0, sizeof(ureq));
if (ib_copy_from_udata(&ureq, udata, sizeof(ureq))) {
DP_ERR(dev,
"create cq: problem copying data from user space\n");
@@ -930,7 +918,7 @@ struct ib_cq *qedr_create_cq(struct ib_device *ibdev,
"create cq: icid=0x%0x, addr=%p, size(entries)=0x%0x\n",
cq->icid, cq, params.cq_size);
- return &cq->ibcq;
+ return 0;
err3:
destroy_iparams.icid = cq->icid;
@@ -945,8 +933,7 @@ err1:
if (udata)
ib_umem_release(cq->q.umem);
err0:
- kfree(cq);
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
}
int qedr_resize_cq(struct ib_cq *ibcq, int new_cnt, struct ib_udata *udata)
@@ -962,14 +949,13 @@ int qedr_resize_cq(struct ib_cq *ibcq, int new_cnt, struct ib_udata *udata)
#define QEDR_DESTROY_CQ_MAX_ITERATIONS (10)
#define QEDR_DESTROY_CQ_ITER_DURATION (10)
-int qedr_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
+void qedr_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
{
struct qedr_dev *dev = get_qedr_dev(ibcq->device);
struct qed_rdma_destroy_cq_out_params oparams;
struct qed_rdma_destroy_cq_in_params iparams;
struct qedr_cq *cq = get_qedr_cq(ibcq);
int iter;
- int rc;
DP_DEBUG(dev, QEDR_MSG_CQ, "destroy cq %p (icid=%d)\n", cq, cq->icid);
@@ -977,13 +963,10 @@ int qedr_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
/* GSIs CQs are handled by driver, so they don't exist in the FW */
if (cq->cq_type == QEDR_CQ_TYPE_GSI)
- goto done;
+ return;
iparams.icid = cq->icid;
- rc = dev->ops->rdma_destroy_cq(dev->rdma_ctx, &iparams, &oparams);
- if (rc)
- return rc;
-
+ dev->ops->rdma_destroy_cq(dev->rdma_ctx, &iparams, &oparams);
dev->ops->common->chain_free(dev->cdev, &cq->pbl);
if (udata) {
@@ -1014,27 +997,11 @@ int qedr_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
iter--;
}
- if (oparams.num_cq_notif != cq->cnq_notif)
- goto err;
-
/* Note that we don't need to have explicit code to wait for the
* completion of the event handler because it is invoked from the EQ.
* Since the destroy CQ ramrod has also been received on the EQ we can
* be certain that there's no event handler in process.
*/
-done:
- cq->sig = ~cq->sig;
-
- kfree(cq);
-
- return 0;
-
-err:
- DP_ERR(dev,
- "CQ %p (icid=%d) not freed, expecting %d ints but got %d ints\n",
- cq, cq->icid, oparams.num_cq_notif, cq->cnq_notif);
-
- return -EINVAL;
}
static inline int get_gid_info_from_table(struct ib_qp *ibqp,
@@ -1605,12 +1572,10 @@ qedr_iwarp_populate_user_qp(struct qedr_dev *dev,
static void qedr_cleanup_user(struct qedr_dev *dev, struct qedr_qp *qp)
{
- if (qp->usq.umem)
- ib_umem_release(qp->usq.umem);
+ ib_umem_release(qp->usq.umem);
qp->usq.umem = NULL;
- if (qp->urq.umem)
- ib_umem_release(qp->urq.umem);
+ ib_umem_release(qp->urq.umem);
qp->urq.umem = NULL;
}
@@ -2713,8 +2678,7 @@ int qedr_dereg_mr(struct ib_mr *ib_mr, struct ib_udata *udata)
qedr_free_pbl(dev, &mr->info.pbl_info, mr->info.pbl_table);
/* it could be user registered memory. */
- if (mr->umem)
- ib_umem_release(mr->umem);
+ ib_umem_release(mr->umem);
kfree(mr);
diff --git a/drivers/infiniband/hw/qedr/verbs.h b/drivers/infiniband/hw/qedr/verbs.h
index 9328c80375ef..9aaa90283d6e 100644
--- a/drivers/infiniband/hw/qedr/verbs.h
+++ b/drivers/infiniband/hw/qedr/verbs.h
@@ -50,11 +50,10 @@ int qedr_mmap(struct ib_ucontext *, struct vm_area_struct *vma);
int qedr_alloc_pd(struct ib_pd *pd, struct ib_udata *udata);
void qedr_dealloc_pd(struct ib_pd *pd, struct ib_udata *udata);
-struct ib_cq *qedr_create_cq(struct ib_device *ibdev,
- const struct ib_cq_init_attr *attr,
- struct ib_udata *udata);
+int qedr_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata);
int qedr_resize_cq(struct ib_cq *, int cqe, struct ib_udata *);
-int qedr_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata);
+void qedr_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata);
int qedr_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags);
struct ib_qp *qedr_create_qp(struct ib_pd *, struct ib_qp_init_attr *attrs,
struct ib_udata *);
diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c
index 78fa634de98a..27b6e664e59d 100644
--- a/drivers/infiniband/hw/qib/qib_file_ops.c
+++ b/drivers/infiniband/hw/qib/qib_file_ops.c
@@ -1142,7 +1142,7 @@ static __poll_t qib_poll(struct file *fp, struct poll_table_struct *pt)
static void assign_ctxt_affinity(struct file *fp, struct qib_devdata *dd)
{
struct qib_filedata *fd = fp->private_data;
- const unsigned int weight = cpumask_weight(&current->cpus_allowed);
+ const unsigned int weight = current->nr_cpus_allowed;
const struct cpumask *local_mask = cpumask_of_pcibus(dd->pcidev->bus);
int local_cpu;
@@ -1623,9 +1623,8 @@ static int qib_assign_ctxt(struct file *fp, const struct qib_user_info *uinfo)
ret = find_free_ctxt(i_minor - 1, fp, uinfo);
else {
int unit;
- const unsigned int cpu = cpumask_first(&current->cpus_allowed);
- const unsigned int weight =
- cpumask_weight(&current->cpus_allowed);
+ const unsigned int cpu = cpumask_first(current->cpus_ptr);
+ const unsigned int weight = current->nr_cpus_allowed;
if (weight == 1 && !test_bit(cpu, qib_cpulist))
if (!find_hca(cpu, &unit) && unit >= 0)
diff --git a/drivers/infiniband/hw/qib/qib_fs.c b/drivers/infiniband/hw/qib/qib_fs.c
index ceb42d948412..41a569558a15 100644
--- a/drivers/infiniband/hw/qib/qib_fs.c
+++ b/drivers/infiniband/hw/qib/qib_fs.c
@@ -34,6 +34,7 @@
#include <linux/module.h>
#include <linux/fs.h>
+#include <linux/fs_context.h>
#include <linux/mount.h>
#include <linux/pagemap.h>
#include <linux/init.h>
@@ -506,7 +507,7 @@ bail:
* after device init. The direct add_cntr_files() call handles adding
* them from the init code, when the fs is already mounted.
*/
-static int qibfs_fill_super(struct super_block *sb, void *data, int silent)
+static int qibfs_fill_super(struct super_block *sb, struct fs_context *fc)
{
struct qib_devdata *dd;
unsigned long index;
@@ -534,17 +535,24 @@ bail:
return ret;
}
-static struct dentry *qibfs_mount(struct file_system_type *fs_type, int flags,
- const char *dev_name, void *data)
+static int qibfs_get_tree(struct fs_context *fc)
{
- struct dentry *ret;
-
- ret = mount_single(fs_type, flags, data, qibfs_fill_super);
- if (!IS_ERR(ret))
- qib_super = ret->d_sb;
+ int ret = get_tree_single(fc, qibfs_fill_super);
+ if (ret == 0)
+ qib_super = fc->root->d_sb;
return ret;
}
+static const struct fs_context_operations qibfs_context_ops = {
+ .get_tree = qibfs_get_tree,
+};
+
+static int qibfs_init_fs_context(struct fs_context *fc)
+{
+ fc->ops = &qibfs_context_ops;
+ return 0;
+}
+
static void qibfs_kill_super(struct super_block *s)
{
kill_litter_super(s);
@@ -583,7 +591,7 @@ int qibfs_remove(struct qib_devdata *dd)
static struct file_system_type qibfs_fs_type = {
.owner = THIS_MODULE,
.name = "ipathfs",
- .mount = qibfs_mount,
+ .init_fs_context = qibfs_init_fs_context,
.kill_sb = qibfs_kill_super,
};
MODULE_ALIAS_FS("ipathfs");
diff --git a/drivers/infiniband/hw/qib/qib_qp.c b/drivers/infiniband/hw/qib/qib_qp.c
index a81905df2d0f..8d0563ef5be1 100644
--- a/drivers/infiniband/hw/qib/qib_qp.c
+++ b/drivers/infiniband/hw/qib/qib_qp.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 - 2017 Intel Corporation. All rights reserved.
+ * Copyright (c) 2012 - 2019 Intel Corporation. All rights reserved.
* Copyright (c) 2006 - 2012 QLogic Corporation. * All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
@@ -398,7 +398,7 @@ int qib_check_send_wqe(struct rvt_qp *qp,
case IB_QPT_SMI:
case IB_QPT_GSI:
case IB_QPT_UD:
- ah = ibah_to_rvtah(wqe->ud_wr.ah);
+ ah = rvt_get_swqe_ah(wqe);
if (wqe->length > (1 << ah->log_pmtu))
return -EINVAL;
/* progress hint */
diff --git a/drivers/infiniband/hw/qib/qib_rc.c b/drivers/infiniband/hw/qib/qib_rc.c
index 2ac4c67f5ba1..1d5e2d4ee257 100644
--- a/drivers/infiniband/hw/qib/qib_rc.c
+++ b/drivers/infiniband/hw/qib/qib_rc.c
@@ -921,20 +921,11 @@ void qib_rc_send_complete(struct rvt_qp *qp, struct ib_header *hdr)
rvt_add_retry_timer(qp);
while (qp->s_last != qp->s_acked) {
- u32 s_last;
-
wqe = rvt_get_swqe_ptr(qp, qp->s_last);
if (qib_cmp24(wqe->lpsn, qp->s_sending_psn) >= 0 &&
qib_cmp24(qp->s_sending_psn, qp->s_sending_hpsn) <= 0)
break;
- s_last = qp->s_last;
- if (++s_last >= qp->s_size)
- s_last = 0;
- qp->s_last = s_last;
- /* see post_send() */
- barrier();
- rvt_put_qp_swqe(qp, wqe);
- rvt_qp_swqe_complete(qp,
+ rvt_qp_complete_swqe(qp,
wqe,
ib_qib_wc_opcode[wqe->wr.opcode],
IB_WC_SUCCESS);
@@ -972,21 +963,12 @@ static struct rvt_swqe *do_rc_completion(struct rvt_qp *qp,
* is finished.
*/
if (qib_cmp24(wqe->lpsn, qp->s_sending_psn) < 0 ||
- qib_cmp24(qp->s_sending_psn, qp->s_sending_hpsn) > 0) {
- u32 s_last;
-
- rvt_put_qp_swqe(qp, wqe);
- s_last = qp->s_last;
- if (++s_last >= qp->s_size)
- s_last = 0;
- qp->s_last = s_last;
- /* see post_send() */
- barrier();
- rvt_qp_swqe_complete(qp,
+ qib_cmp24(qp->s_sending_psn, qp->s_sending_hpsn) > 0)
+ rvt_qp_complete_swqe(qp,
wqe,
ib_qib_wc_opcode[wqe->wr.opcode],
IB_WC_SUCCESS);
- } else
+ else
this_cpu_inc(*ibp->rvp.rc_delayed_comp);
qp->s_retry = qp->s_retry_cnt;
@@ -1909,8 +1891,7 @@ send_last:
wc.dlid_path_bits = 0;
wc.port_num = 0;
/* Signal completion event if the solicited bit is set. */
- rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc,
- ib_bth_is_solicited(ohdr));
+ rvt_recv_cq(qp, &wc, ib_bth_is_solicited(ohdr));
break;
case OP(RDMA_WRITE_FIRST):
diff --git a/drivers/infiniband/hw/qib/qib_uc.c b/drivers/infiniband/hw/qib/qib_uc.c
index 30c70ad0f4bf..e17b91e2c22a 100644
--- a/drivers/infiniband/hw/qib/qib_uc.c
+++ b/drivers/infiniband/hw/qib/qib_uc.c
@@ -400,8 +400,7 @@ last_imm:
wc.dlid_path_bits = 0;
wc.port_num = 0;
/* Signal completion event if the solicited bit is set. */
- rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc,
- ib_bth_is_solicited(ohdr));
+ rvt_recv_cq(qp, &wc, ib_bth_is_solicited(ohdr));
break;
case OP(RDMA_WRITE_FIRST):
diff --git a/drivers/infiniband/hw/qib/qib_ud.c b/drivers/infiniband/hw/qib/qib_ud.c
index 5cdedba2d164..93ca21347959 100644
--- a/drivers/infiniband/hw/qib/qib_ud.c
+++ b/drivers/infiniband/hw/qib/qib_ud.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2012 - 2019 Intel Corporation. All rights reserved.
* Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
@@ -63,7 +64,7 @@ static void qib_ud_loopback(struct rvt_qp *sqp, struct rvt_swqe *swqe)
enum ib_qp_type sqptype, dqptype;
rcu_read_lock();
- qp = rvt_lookup_qpn(rdi, &ibp->rvp, swqe->ud_wr.remote_qpn);
+ qp = rvt_lookup_qpn(rdi, &ibp->rvp, rvt_get_swqe_remote_qpn(swqe));
if (!qp) {
ibp->rvp.n_pkt_drops++;
goto drop;
@@ -80,7 +81,7 @@ static void qib_ud_loopback(struct rvt_qp *sqp, struct rvt_swqe *swqe)
goto drop;
}
- ah_attr = &ibah_to_rvtah(swqe->ud_wr.ah)->attr;
+ ah_attr = rvt_get_swqe_ah_attr(swqe);
ppd = ppd_from_ibp(ibp);
if (qp->ibqp.qp_num > 1) {
@@ -110,8 +111,8 @@ static void qib_ud_loopback(struct rvt_qp *sqp, struct rvt_swqe *swqe)
if (qp->ibqp.qp_num) {
u32 qkey;
- qkey = (int)swqe->ud_wr.remote_qkey < 0 ?
- sqp->qkey : swqe->ud_wr.remote_qkey;
+ qkey = (int)rvt_get_swqe_remote_qkey(swqe) < 0 ?
+ sqp->qkey : rvt_get_swqe_remote_qkey(swqe);
if (unlikely(qkey != qp->qkey))
goto drop;
}
@@ -203,15 +204,14 @@ static void qib_ud_loopback(struct rvt_qp *sqp, struct rvt_swqe *swqe)
wc.qp = &qp->ibqp;
wc.src_qp = sqp->ibqp.qp_num;
wc.pkey_index = qp->ibqp.qp_type == IB_QPT_GSI ?
- swqe->ud_wr.pkey_index : 0;
+ rvt_get_swqe_pkey_index(swqe) : 0;
wc.slid = ppd->lid | (rdma_ah_get_path_bits(ah_attr) &
((1 << ppd->lmc) - 1));
wc.sl = rdma_ah_get_sl(ah_attr);
wc.dlid_path_bits = rdma_ah_get_dlid(ah_attr) & ((1 << ppd->lmc) - 1);
wc.port_num = qp->port_num;
/* Signal completion event if the solicited bit is set. */
- rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc,
- swqe->wr.send_flags & IB_SEND_SOLICITED);
+ rvt_recv_cq(qp, &wc, swqe->wr.send_flags & IB_SEND_SOLICITED);
ibp->rvp.n_loop_pkts++;
bail_unlock:
spin_unlock_irqrestore(&qp->r_lock, flags);
@@ -271,7 +271,7 @@ int qib_make_ud_req(struct rvt_qp *qp, unsigned long *flags)
/* Construct the header. */
ibp = to_iport(qp->ibqp.device, qp->port_num);
ppd = ppd_from_ibp(ibp);
- ah_attr = &ibah_to_rvtah(wqe->ud_wr.ah)->attr;
+ ah_attr = rvt_get_swqe_ah_attr(wqe);
if (rdma_ah_get_dlid(ah_attr) >= be16_to_cpu(IB_MULTICAST_LID_BASE)) {
if (rdma_ah_get_dlid(ah_attr) !=
be16_to_cpu(IB_LID_PERMISSIVE))
@@ -363,7 +363,7 @@ int qib_make_ud_req(struct rvt_qp *qp, unsigned long *flags)
bth0 |= extra_bytes << 20;
bth0 |= qp->ibqp.qp_type == IB_QPT_SMI ? QIB_DEFAULT_P_KEY :
qib_get_pkey(ibp, qp->ibqp.qp_type == IB_QPT_GSI ?
- wqe->ud_wr.pkey_index : qp->s_pkey_index);
+ rvt_get_swqe_pkey_index(wqe) : qp->s_pkey_index);
ohdr->bth[0] = cpu_to_be32(bth0);
/*
* Use the multicast QP if the destination LID is a multicast LID.
@@ -372,14 +372,15 @@ int qib_make_ud_req(struct rvt_qp *qp, unsigned long *flags)
be16_to_cpu(IB_MULTICAST_LID_BASE) &&
rdma_ah_get_dlid(ah_attr) != be16_to_cpu(IB_LID_PERMISSIVE) ?
cpu_to_be32(QIB_MULTICAST_QPN) :
- cpu_to_be32(wqe->ud_wr.remote_qpn);
+ cpu_to_be32(rvt_get_swqe_remote_qpn(wqe));
ohdr->bth[2] = cpu_to_be32(wqe->psn & QIB_PSN_MASK);
/*
* Qkeys with the high order bit set mean use the
* qkey from the QP context instead of the WR (see 10.2.5).
*/
- ohdr->u.ud.deth[0] = cpu_to_be32((int)wqe->ud_wr.remote_qkey < 0 ?
- qp->qkey : wqe->ud_wr.remote_qkey);
+ ohdr->u.ud.deth[0] =
+ cpu_to_be32((int)rvt_get_swqe_remote_qkey(wqe) < 0 ? qp->qkey :
+ rvt_get_swqe_remote_qkey(wqe));
ohdr->u.ud.deth[1] = cpu_to_be32(qp->ibqp.qp_num);
done:
@@ -573,8 +574,7 @@ void qib_ud_rcv(struct qib_ibport *ibp, struct ib_header *hdr,
dlid & ((1 << ppd_from_ibp(ibp)->lmc) - 1);
wc.port_num = qp->port_num;
/* Signal completion event if the solicited bit is set. */
- rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc,
- ib_bth_is_solicited(ohdr));
+ rvt_recv_cq(qp, &wc, ib_bth_is_solicited(ohdr));
return;
drop:
diff --git a/drivers/infiniband/hw/qib/qib_user_pages.c b/drivers/infiniband/hw/qib/qib_user_pages.c
index f712fb7fa82f..bfbfbb7e0ff4 100644
--- a/drivers/infiniband/hw/qib/qib_user_pages.c
+++ b/drivers/infiniband/hw/qib/qib_user_pages.c
@@ -40,13 +40,10 @@
static void __qib_release_user_pages(struct page **p, size_t num_pages,
int dirty)
{
- size_t i;
-
- for (i = 0; i < num_pages; i++) {
- if (dirty)
- set_page_dirty_lock(p[i]);
- put_page(p[i]);
- }
+ if (dirty)
+ put_user_pages_dirty_lock(p, num_pages);
+ else
+ put_user_pages(p, num_pages);
}
/**
diff --git a/drivers/infiniband/hw/qib/qib_user_sdma.c b/drivers/infiniband/hw/qib/qib_user_sdma.c
index 0c204776263f..05190edc2611 100644
--- a/drivers/infiniband/hw/qib/qib_user_sdma.c
+++ b/drivers/infiniband/hw/qib/qib_user_sdma.c
@@ -317,7 +317,7 @@ static int qib_user_sdma_page_to_frags(const struct qib_devdata *dd,
* the caller can ignore this page.
*/
if (put) {
- put_page(page);
+ put_user_page(page);
} else {
/* coalesce case */
kunmap(page);
@@ -631,7 +631,7 @@ static void qib_user_sdma_free_pkt_frag(struct device *dev,
kunmap(pkt->addr[i].page);
if (pkt->addr[i].put_page)
- put_page(pkt->addr[i].page);
+ put_user_page(pkt->addr[i].page);
else
__free_page(pkt->addr[i].page);
} else if (pkt->addr[i].kvaddr) {
@@ -706,7 +706,7 @@ static int qib_user_sdma_pin_pages(const struct qib_devdata *dd,
/* if error, return all pages not managed by pkt */
free_pages:
while (i < j)
- put_page(pages[i++]);
+ put_user_page(pages[i++]);
done:
return ret;
@@ -904,10 +904,11 @@ static int qib_user_sdma_queue_pkts(const struct qib_devdata *dd,
}
if (frag_size) {
- int pktsize, tidsmsize, n;
+ int tidsmsize, n;
+ size_t pktsize;
n = npages*((2*PAGE_SIZE/frag_size)+1);
- pktsize = sizeof(*pkt) + sizeof(pkt->addr[0])*n;
+ pktsize = struct_size(pkt, addr, n);
/*
* Determine if this is tid-sdma or just sdma.
diff --git a/drivers/infiniband/hw/qib/qib_verbs.c b/drivers/infiniband/hw/qib/qib_verbs.c
index 2c4e569ce438..33778d451b82 100644
--- a/drivers/infiniband/hw/qib/qib_verbs.c
+++ b/drivers/infiniband/hw/qib/qib_verbs.c
@@ -1480,6 +1480,9 @@ static void qib_fill_device_attr(struct qib_devdata *dd)
}
static const struct ib_device_ops qib_dev_ops = {
+ .owner = THIS_MODULE,
+ .driver_id = RDMA_DRIVER_QIB,
+
.init_port = qib_create_port_files,
.modify_device = qib_modify_device,
.process_mad = qib_process_mad,
@@ -1543,7 +1546,6 @@ int qib_register_ib_device(struct qib_devdata *dd)
if (!ib_qib_sys_image_guid)
ib_qib_sys_image_guid = ppd->guid;
- ibdev->owner = THIS_MODULE;
ibdev->node_guid = ppd->guid;
ibdev->phys_port_cnt = dd->num_pports;
ibdev->dev.parent = &dd->pcidev->dev;
@@ -1614,7 +1616,7 @@ int qib_register_ib_device(struct qib_devdata *dd)
rdma_set_device_sysfs_group(&dd->verbs_dev.rdi.ibdev, &qib_attr_group);
ib_set_device_ops(ibdev, &qib_dev_ops);
- ret = rvt_register_device(&dd->verbs_dev.rdi, RDMA_DRIVER_QIB);
+ ret = rvt_register_device(&dd->verbs_dev.rdi);
if (ret)
goto err_tx;
diff --git a/drivers/infiniband/hw/usnic/usnic_ib.h b/drivers/infiniband/hw/usnic/usnic_ib.h
index 525bf272671e..84dd682d2334 100644
--- a/drivers/infiniband/hw/usnic/usnic_ib.h
+++ b/drivers/infiniband/hw/usnic/usnic_ib.h
@@ -61,6 +61,10 @@ struct usnic_ib_pd {
struct usnic_uiom_pd *umem_pd;
};
+struct usnic_ib_cq {
+ struct ib_cq ibcq;
+};
+
struct usnic_ib_mr {
struct ib_mr ibmr;
struct usnic_uiom_reg *umem;
diff --git a/drivers/infiniband/hw/usnic/usnic_ib_main.c b/drivers/infiniband/hw/usnic/usnic_ib_main.c
index d88d9f8a7f9a..03f54eb9404b 100644
--- a/drivers/infiniband/hw/usnic/usnic_ib_main.c
+++ b/drivers/infiniband/hw/usnic/usnic_ib_main.c
@@ -329,6 +329,10 @@ static void usnic_get_dev_fw_str(struct ib_device *device, char *str)
}
static const struct ib_device_ops usnic_dev_ops = {
+ .owner = THIS_MODULE,
+ .driver_id = RDMA_DRIVER_USNIC,
+ .uverbs_abi_ver = USNIC_UVERBS_ABI_VERSION,
+
.alloc_pd = usnic_ib_alloc_pd,
.alloc_ucontext = usnic_ib_alloc_ucontext,
.create_cq = usnic_ib_create_cq,
@@ -350,6 +354,7 @@ static const struct ib_device_ops usnic_dev_ops = {
.query_qp = usnic_ib_query_qp,
.reg_user_mr = usnic_ib_reg_mr,
INIT_RDMA_OBJ_SIZE(ib_pd, usnic_ib_pd, ibpd),
+ INIT_RDMA_OBJ_SIZE(ib_cq, usnic_ib_cq, ibcq),
INIT_RDMA_OBJ_SIZE(ib_ucontext, usnic_ib_ucontext, ibucontext),
};
@@ -384,12 +389,10 @@ static void *usnic_ib_device_add(struct pci_dev *dev)
us_ibdev->pdev = dev;
us_ibdev->netdev = pci_get_drvdata(dev);
- us_ibdev->ib_dev.owner = THIS_MODULE;
us_ibdev->ib_dev.node_type = RDMA_NODE_USNIC_UDP;
us_ibdev->ib_dev.phys_port_cnt = USNIC_IB_PORT_CNT;
us_ibdev->ib_dev.num_comp_vectors = USNIC_IB_NUM_COMP_VECTORS;
us_ibdev->ib_dev.dev.parent = &dev->dev;
- us_ibdev->ib_dev.uverbs_abi_ver = USNIC_UVERBS_ABI_VERSION;
us_ibdev->ib_dev.uverbs_cmd_mask =
(1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
@@ -412,7 +415,6 @@ static void *usnic_ib_device_add(struct pci_dev *dev)
ib_set_device_ops(&us_ibdev->ib_dev, &usnic_dev_ops);
- us_ibdev->ib_dev.driver_id = RDMA_DRIVER_USNIC;
rdma_set_device_sysfs_group(&us_ibdev->ib_dev, &usnic_attr_group);
ret = ib_device_set_netdev(&us_ibdev->ib_dev, us_ibdev->netdev, 1);
@@ -427,11 +429,16 @@ static void *usnic_ib_device_add(struct pci_dev *dev)
if (netif_carrier_ok(us_ibdev->netdev))
usnic_fwd_carrier_up(us_ibdev->ufdev);
- ind = in_dev_get(netdev);
- if (ind->ifa_list)
- usnic_fwd_add_ipaddr(us_ibdev->ufdev,
- ind->ifa_list->ifa_address);
- in_dev_put(ind);
+ rcu_read_lock();
+ ind = __in_dev_get_rcu(netdev);
+ if (ind) {
+ const struct in_ifaddr *ifa;
+
+ ifa = rcu_dereference(ind->ifa_list);
+ if (ifa)
+ usnic_fwd_add_ipaddr(us_ibdev->ufdev, ifa->ifa_address);
+ }
+ rcu_read_unlock();
usnic_mac_ip_to_gid(us_ibdev->netdev->perm_addr,
us_ibdev->ufdev->inaddr, &gid.raw[0]);
diff --git a/drivers/infiniband/hw/usnic/usnic_ib_verbs.c b/drivers/infiniband/hw/usnic/usnic_ib_verbs.c
index e9352750e029..eeb07b245ef9 100644
--- a/drivers/infiniband/hw/usnic/usnic_ib_verbs.c
+++ b/drivers/infiniband/hw/usnic/usnic_ib_verbs.c
@@ -587,28 +587,18 @@ out_unlock:
return status;
}
-struct ib_cq *usnic_ib_create_cq(struct ib_device *ibdev,
- const struct ib_cq_init_attr *attr,
- struct ib_udata *udata)
+int usnic_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata)
{
- struct ib_cq *cq;
-
- usnic_dbg("\n");
if (attr->flags)
- return ERR_PTR(-EINVAL);
-
- cq = kzalloc(sizeof(*cq), GFP_KERNEL);
- if (!cq)
- return ERR_PTR(-EBUSY);
+ return -EINVAL;
- return cq;
+ return 0;
}
-int usnic_ib_destroy_cq(struct ib_cq *cq, struct ib_udata *udata)
+void usnic_ib_destroy_cq(struct ib_cq *cq, struct ib_udata *udata)
{
- usnic_dbg("\n");
- kfree(cq);
- return 0;
+ return;
}
struct ib_mr *usnic_ib_reg_mr(struct ib_pd *pd, u64 start, u64 length,
diff --git a/drivers/infiniband/hw/usnic/usnic_ib_verbs.h b/drivers/infiniband/hw/usnic/usnic_ib_verbs.h
index 028f322f8e9b..2aedf78c13cf 100644
--- a/drivers/infiniband/hw/usnic/usnic_ib_verbs.h
+++ b/drivers/infiniband/hw/usnic/usnic_ib_verbs.h
@@ -58,10 +58,9 @@ struct ib_qp *usnic_ib_create_qp(struct ib_pd *pd,
int usnic_ib_destroy_qp(struct ib_qp *qp, struct ib_udata *udata);
int usnic_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
int attr_mask, struct ib_udata *udata);
-struct ib_cq *usnic_ib_create_cq(struct ib_device *ibdev,
- const struct ib_cq_init_attr *attr,
- struct ib_udata *udata);
-int usnic_ib_destroy_cq(struct ib_cq *cq, struct ib_udata *udata);
+int usnic_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata);
+void usnic_ib_destroy_cq(struct ib_cq *cq, struct ib_udata *udata);
struct ib_mr *usnic_ib_reg_mr(struct ib_pd *pd, u64 start, u64 length,
u64 virt_addr, int access_flags,
struct ib_udata *udata);
diff --git a/drivers/infiniband/hw/usnic/usnic_uiom.c b/drivers/infiniband/hw/usnic/usnic_uiom.c
index e312f522a66d..0b0237d41613 100644
--- a/drivers/infiniband/hw/usnic/usnic_uiom.c
+++ b/drivers/infiniband/hw/usnic/usnic_uiom.c
@@ -75,9 +75,10 @@ static void usnic_uiom_put_pages(struct list_head *chunk_list, int dirty)
for_each_sg(chunk->page_list, sg, chunk->nents, i) {
page = sg_page(sg);
pa = sg_phys(sg);
- if (!PageDirty(page) && dirty)
- set_page_dirty_lock(page);
- put_page(page);
+ if (dirty)
+ put_user_pages_dirty_lock(&page, 1);
+ else
+ put_user_page(page);
usnic_dbg("pa: %pa\n", &pa);
}
kfree(chunk);
diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma.h b/drivers/infiniband/hw/vmw_pvrdma/pvrdma.h
index 3c633ab58052..c142f5e7f25f 100644
--- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma.h
+++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma.h
@@ -456,7 +456,7 @@ static inline enum pvrdma_wr_opcode ib_wr_opcode_to_pvrdma(enum ib_wr_opcode op)
return PVRDMA_WR_MASKED_ATOMIC_CMP_AND_SWP;
case IB_WR_MASKED_ATOMIC_FETCH_AND_ADD:
return PVRDMA_WR_MASKED_ATOMIC_FETCH_AND_ADD;
- case IB_WR_REG_SIG_MR:
+ case IB_WR_REG_MR_INTEGRITY:
return PVRDMA_WR_REG_SIG_MR;
default:
return PVRDMA_WR_ERROR;
diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c
index d7deb19a2800..7800e6930502 100644
--- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c
+++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c
@@ -92,20 +92,19 @@ int pvrdma_req_notify_cq(struct ib_cq *ibcq,
/**
* pvrdma_create_cq - create completion queue
- * @ibdev: the device
+ * @ibcq: Allocated CQ
* @attr: completion queue attributes
* @udata: user data
*
- * @return: ib_cq completion queue pointer on success,
- * otherwise returns negative errno.
+ * @return: 0 on success
*/
-struct ib_cq *pvrdma_create_cq(struct ib_device *ibdev,
- const struct ib_cq_init_attr *attr,
- struct ib_udata *udata)
+int pvrdma_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata)
{
+ struct ib_device *ibdev = ibcq->device;
int entries = attr->cqe;
struct pvrdma_dev *dev = to_vdev(ibdev);
- struct pvrdma_cq *cq;
+ struct pvrdma_cq *cq = to_vcq(ibcq);
int ret;
int npages;
unsigned long flags;
@@ -113,7 +112,7 @@ struct ib_cq *pvrdma_create_cq(struct ib_device *ibdev,
union pvrdma_cmd_resp rsp;
struct pvrdma_cmd_create_cq *cmd = &req.create_cq;
struct pvrdma_cmd_create_cq_resp *resp = &rsp.create_cq_resp;
- struct pvrdma_create_cq_resp cq_resp = {0};
+ struct pvrdma_create_cq_resp cq_resp = {};
struct pvrdma_create_cq ucmd;
struct pvrdma_ucontext *context = rdma_udata_to_drv_context(
udata, struct pvrdma_ucontext, ibucontext);
@@ -122,16 +121,10 @@ struct ib_cq *pvrdma_create_cq(struct ib_device *ibdev,
entries = roundup_pow_of_two(entries);
if (entries < 1 || entries > dev->dsr->caps.max_cqe)
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
if (!atomic_add_unless(&dev->num_cqs, 1, dev->dsr->caps.max_cq))
- return ERR_PTR(-ENOMEM);
-
- cq = kzalloc(sizeof(*cq), GFP_KERNEL);
- if (!cq) {
- atomic_dec(&dev->num_cqs);
- return ERR_PTR(-ENOMEM);
- }
+ return -ENOMEM;
cq->ibcq.cqe = entries;
cq->is_kernel = !udata;
@@ -211,22 +204,19 @@ struct ib_cq *pvrdma_create_cq(struct ib_device *ibdev,
dev_warn(&dev->pdev->dev,
"failed to copy back udata\n");
pvrdma_destroy_cq(&cq->ibcq, udata);
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
}
}
- return &cq->ibcq;
+ return 0;
err_page_dir:
pvrdma_page_dir_cleanup(dev, &cq->pdir);
err_umem:
- if (!cq->is_kernel)
- ib_umem_release(cq->umem);
+ ib_umem_release(cq->umem);
err_cq:
atomic_dec(&dev->num_cqs);
- kfree(cq);
-
- return ERR_PTR(ret);
+ return ret;
}
static void pvrdma_free_cq(struct pvrdma_dev *dev, struct pvrdma_cq *cq)
@@ -235,21 +225,17 @@ static void pvrdma_free_cq(struct pvrdma_dev *dev, struct pvrdma_cq *cq)
complete(&cq->free);
wait_for_completion(&cq->free);
- if (!cq->is_kernel)
- ib_umem_release(cq->umem);
+ ib_umem_release(cq->umem);
pvrdma_page_dir_cleanup(dev, &cq->pdir);
- kfree(cq);
}
/**
* pvrdma_destroy_cq - destroy completion queue
* @cq: the completion queue to destroy.
* @udata: user data or null for kernel object
- *
- * @return: 0 for success.
*/
-int pvrdma_destroy_cq(struct ib_cq *cq, struct ib_udata *udata)
+void pvrdma_destroy_cq(struct ib_cq *cq, struct ib_udata *udata)
{
struct pvrdma_cq *vcq = to_vcq(cq);
union pvrdma_cmd_req req;
@@ -275,8 +261,6 @@ int pvrdma_destroy_cq(struct ib_cq *cq, struct ib_udata *udata)
pvrdma_free_cq(dev, vcq);
atomic_dec(&dev->num_cqs);
-
- return ret;
}
static inline struct pvrdma_cqe *get_cqe(struct pvrdma_cq *cq, int i)
diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c
index 40182297f87f..e580ae9cc55a 100644
--- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c
+++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c
@@ -144,6 +144,10 @@ static int pvrdma_port_immutable(struct ib_device *ibdev, u8 port_num,
}
static const struct ib_device_ops pvrdma_dev_ops = {
+ .owner = THIS_MODULE,
+ .driver_id = RDMA_DRIVER_VMW_PVRDMA,
+ .uverbs_abi_ver = PVRDMA_UVERBS_ABI_VERSION,
+
.add_gid = pvrdma_add_gid,
.alloc_mr = pvrdma_alloc_mr,
.alloc_pd = pvrdma_alloc_pd,
@@ -178,6 +182,7 @@ static const struct ib_device_ops pvrdma_dev_ops = {
.req_notify_cq = pvrdma_req_notify_cq,
INIT_RDMA_OBJ_SIZE(ib_ah, pvrdma_ah, ibah),
+ INIT_RDMA_OBJ_SIZE(ib_cq, pvrdma_cq, ibcq),
INIT_RDMA_OBJ_SIZE(ib_pd, pvrdma_pd, ibpd),
INIT_RDMA_OBJ_SIZE(ib_ucontext, pvrdma_ucontext, ibucontext),
};
@@ -198,10 +203,8 @@ static int pvrdma_register_device(struct pvrdma_dev *dev)
dev->ib_dev.node_guid = dev->dsr->caps.node_guid;
dev->sys_image_guid = dev->dsr->caps.sys_image_guid;
dev->flags = 0;
- dev->ib_dev.owner = THIS_MODULE;
dev->ib_dev.num_comp_vectors = 1;
dev->ib_dev.dev.parent = &dev->pdev->dev;
- dev->ib_dev.uverbs_abi_ver = PVRDMA_UVERBS_ABI_VERSION;
dev->ib_dev.uverbs_cmd_mask =
(1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
(1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |
@@ -261,7 +264,6 @@ static int pvrdma_register_device(struct pvrdma_dev *dev)
if (!dev->srq_tbl)
goto err_qp_free;
}
- dev->ib_dev.driver_id = RDMA_DRIVER_VMW_PVRDMA;
ret = ib_device_set_netdev(&dev->ib_dev, dev->netdev, 1);
if (ret)
return ret;
diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_mr.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_mr.c
index 65dc47ffb8f3..f3a3d22ee8d7 100644
--- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_mr.c
+++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_mr.c
@@ -290,8 +290,7 @@ int pvrdma_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
"could not deregister mem region, error: %d\n", ret);
pvrdma_page_dir_cleanup(dev, &mr->pdir);
- if (mr->umem)
- ib_umem_release(mr->umem);
+ ib_umem_release(mr->umem);
kfree(mr->pages);
kfree(mr);
diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c
index 0eaaead5baec..bca6a58a442e 100644
--- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c
+++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c
@@ -391,12 +391,8 @@ struct ib_qp *pvrdma_create_qp(struct ib_pd *pd,
err_pdir:
pvrdma_page_dir_cleanup(dev, &qp->pdir);
err_umem:
- if (!qp->is_kernel) {
- if (qp->rumem)
- ib_umem_release(qp->rumem);
- if (qp->sumem)
- ib_umem_release(qp->sumem);
- }
+ ib_umem_release(qp->rumem);
+ ib_umem_release(qp->sumem);
err_qp:
kfree(qp);
atomic_dec(&dev->num_qps);
@@ -429,12 +425,8 @@ static void pvrdma_free_qp(struct pvrdma_qp *qp)
complete(&qp->free);
wait_for_completion(&qp->free);
- if (!qp->is_kernel) {
- if (qp->rumem)
- ib_umem_release(qp->rumem);
- if (qp->sumem)
- ib_umem_release(qp->sumem);
- }
+ ib_umem_release(qp->rumem);
+ ib_umem_release(qp->sumem);
pvrdma_page_dir_cleanup(dev, &qp->pdir);
diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.h b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.h
index 9d7b021e1c59..e4a48f5c0c85 100644
--- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.h
+++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.h
@@ -409,10 +409,9 @@ struct ib_mr *pvrdma_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type,
u32 max_num_sg, struct ib_udata *udata);
int pvrdma_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg,
int sg_nents, unsigned int *sg_offset);
-struct ib_cq *pvrdma_create_cq(struct ib_device *ibdev,
- const struct ib_cq_init_attr *attr,
- struct ib_udata *udata);
-int pvrdma_destroy_cq(struct ib_cq *cq, struct ib_udata *udata);
+int pvrdma_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata);
+void pvrdma_destroy_cq(struct ib_cq *cq, struct ib_udata *udata);
int pvrdma_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc);
int pvrdma_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags);
int pvrdma_create_ah(struct ib_ah *ah, struct rdma_ah_attr *ah_attr, u32 flags,
diff --git a/drivers/infiniband/sw/Makefile b/drivers/infiniband/sw/Makefile
index ab48a9b60844..68e0230f8f31 100644
--- a/drivers/infiniband/sw/Makefile
+++ b/drivers/infiniband/sw/Makefile
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_INFINIBAND_RDMAVT) += rdmavt/
obj-$(CONFIG_RDMA_RXE) += rxe/
+obj-$(CONFIG_RDMA_SIW) += siw/
diff --git a/drivers/infiniband/sw/rdmavt/ah.c b/drivers/infiniband/sw/rdmavt/ah.c
index 0e147b32cbe9..fe99da0ff060 100644
--- a/drivers/infiniband/sw/rdmavt/ah.c
+++ b/drivers/infiniband/sw/rdmavt/ah.c
@@ -1,5 +1,5 @@
/*
- * Copyright(c) 2016 Intel Corporation.
+ * Copyright(c) 2016 - 2019 Intel Corporation.
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
@@ -119,8 +119,6 @@ int rvt_create_ah(struct ib_ah *ibah, struct rdma_ah_attr *ah_attr,
rdma_copy_ah_attr(&ah->attr, ah_attr);
- atomic_set(&ah->refcount, 0);
-
if (dev->driver_f.notify_new_ah)
dev->driver_f.notify_new_ah(ibah->device, ah_attr, ah);
@@ -141,8 +139,6 @@ void rvt_destroy_ah(struct ib_ah *ibah, u32 destroy_flags)
struct rvt_ah *ah = ibah_to_rvtah(ibah);
unsigned long flags;
- WARN_ON_ONCE(atomic_read(&ah->refcount));
-
spin_lock_irqsave(&dev->n_ahs_lock, flags);
dev->n_ahs_allocated--;
spin_unlock_irqrestore(&dev->n_ahs_lock, flags);
diff --git a/drivers/infiniband/sw/rdmavt/cq.c b/drivers/infiniband/sw/rdmavt/cq.c
index a06e6da7a026..a85571a4cf57 100644
--- a/drivers/infiniband/sw/rdmavt/cq.c
+++ b/drivers/infiniband/sw/rdmavt/cq.c
@@ -60,22 +60,39 @@ static struct workqueue_struct *comp_vector_wq;
* @solicited: true if @entry is solicited
*
* This may be called with qp->s_lock held.
+ *
+ * Return: return true on success, else return
+ * false if cq is full.
*/
-void rvt_cq_enter(struct rvt_cq *cq, struct ib_wc *entry, bool solicited)
+bool rvt_cq_enter(struct rvt_cq *cq, struct ib_wc *entry, bool solicited)
{
- struct rvt_cq_wc *wc;
+ struct ib_uverbs_wc *uqueue = NULL;
+ struct ib_wc *kqueue = NULL;
+ struct rvt_cq_wc *u_wc = NULL;
+ struct rvt_k_cq_wc *k_wc = NULL;
unsigned long flags;
u32 head;
u32 next;
+ u32 tail;
spin_lock_irqsave(&cq->lock, flags);
+ if (cq->ip) {
+ u_wc = cq->queue;
+ uqueue = &u_wc->uqueue[0];
+ head = RDMA_READ_UAPI_ATOMIC(u_wc->head);
+ tail = RDMA_READ_UAPI_ATOMIC(u_wc->tail);
+ } else {
+ k_wc = cq->kqueue;
+ kqueue = &k_wc->kqueue[0];
+ head = k_wc->head;
+ tail = k_wc->tail;
+ }
+
/*
- * Note that the head pointer might be writable by user processes.
- * Take care to verify it is a sane value.
+ * Note that the head pointer might be writable by
+ * user processes.Take care to verify it is a sane value.
*/
- wc = cq->queue;
- head = wc->head;
if (head >= (unsigned)cq->ibcq.cqe) {
head = cq->ibcq.cqe;
next = 0;
@@ -83,7 +100,12 @@ void rvt_cq_enter(struct rvt_cq *cq, struct ib_wc *entry, bool solicited)
next = head + 1;
}
- if (unlikely(next == wc->tail)) {
+ if (unlikely(next == tail || cq->cq_full)) {
+ struct rvt_dev_info *rdi = cq->rdi;
+
+ if (!cq->cq_full)
+ rvt_pr_err_ratelimited(rdi, "CQ is full!\n");
+ cq->cq_full = true;
spin_unlock_irqrestore(&cq->lock, flags);
if (cq->ibcq.event_handler) {
struct ib_event ev;
@@ -93,30 +115,30 @@ void rvt_cq_enter(struct rvt_cq *cq, struct ib_wc *entry, bool solicited)
ev.event = IB_EVENT_CQ_ERR;
cq->ibcq.event_handler(&ev, cq->ibcq.cq_context);
}
- return;
+ return false;
}
trace_rvt_cq_enter(cq, entry, head);
- if (cq->ip) {
- wc->uqueue[head].wr_id = entry->wr_id;
- wc->uqueue[head].status = entry->status;
- wc->uqueue[head].opcode = entry->opcode;
- wc->uqueue[head].vendor_err = entry->vendor_err;
- wc->uqueue[head].byte_len = entry->byte_len;
- wc->uqueue[head].ex.imm_data = entry->ex.imm_data;
- wc->uqueue[head].qp_num = entry->qp->qp_num;
- wc->uqueue[head].src_qp = entry->src_qp;
- wc->uqueue[head].wc_flags = entry->wc_flags;
- wc->uqueue[head].pkey_index = entry->pkey_index;
- wc->uqueue[head].slid = ib_lid_cpu16(entry->slid);
- wc->uqueue[head].sl = entry->sl;
- wc->uqueue[head].dlid_path_bits = entry->dlid_path_bits;
- wc->uqueue[head].port_num = entry->port_num;
+ if (uqueue) {
+ uqueue[head].wr_id = entry->wr_id;
+ uqueue[head].status = entry->status;
+ uqueue[head].opcode = entry->opcode;
+ uqueue[head].vendor_err = entry->vendor_err;
+ uqueue[head].byte_len = entry->byte_len;
+ uqueue[head].ex.imm_data = entry->ex.imm_data;
+ uqueue[head].qp_num = entry->qp->qp_num;
+ uqueue[head].src_qp = entry->src_qp;
+ uqueue[head].wc_flags = entry->wc_flags;
+ uqueue[head].pkey_index = entry->pkey_index;
+ uqueue[head].slid = ib_lid_cpu16(entry->slid);
+ uqueue[head].sl = entry->sl;
+ uqueue[head].dlid_path_bits = entry->dlid_path_bits;
+ uqueue[head].port_num = entry->port_num;
/* Make sure entry is written before the head index. */
- smp_wmb();
+ RDMA_WRITE_UAPI_ATOMIC(u_wc->head, next);
} else {
- wc->kqueue[head] = *entry;
+ kqueue[head] = *entry;
+ k_wc->head = next;
}
- wc->head = next;
if (cq->notify == IB_CQ_NEXT_COMP ||
(cq->notify == IB_CQ_SOLICITED &&
@@ -132,6 +154,7 @@ void rvt_cq_enter(struct rvt_cq *cq, struct ib_wc *entry, bool solicited)
}
spin_unlock_irqrestore(&cq->lock, flags);
+ return true;
}
EXPORT_SYMBOL(rvt_cq_enter);
@@ -166,43 +189,38 @@ static void send_complete(struct work_struct *work)
/**
* rvt_create_cq - create a completion queue
- * @ibdev: the device this completion queue is attached to
+ * @ibcq: Allocated CQ
* @attr: creation attributes
* @udata: user data for libibverbs.so
*
* Called by ib_create_cq() in the generic verbs code.
*
- * Return: pointer to the completion queue or negative errno values
- * for failure.
+ * Return: 0 on success
*/
-struct ib_cq *rvt_create_cq(struct ib_device *ibdev,
- const struct ib_cq_init_attr *attr,
- struct ib_udata *udata)
+int rvt_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata)
{
+ struct ib_device *ibdev = ibcq->device;
struct rvt_dev_info *rdi = ib_to_rvt(ibdev);
- struct rvt_cq *cq;
- struct rvt_cq_wc *wc;
- struct ib_cq *ret;
+ struct rvt_cq *cq = ibcq_to_rvtcq(ibcq);
+ struct rvt_cq_wc *u_wc = NULL;
+ struct rvt_k_cq_wc *k_wc = NULL;
u32 sz;
unsigned int entries = attr->cqe;
int comp_vector = attr->comp_vector;
+ int err;
if (attr->flags)
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
if (entries < 1 || entries > rdi->dparms.props.max_cqe)
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
if (comp_vector < 0)
comp_vector = 0;
comp_vector = comp_vector % rdi->ibdev.num_comp_vectors;
- /* Allocate the completion queue structure. */
- cq = kzalloc_node(sizeof(*cq), GFP_KERNEL, rdi->dparms.node);
- if (!cq)
- return ERR_PTR(-ENOMEM);
-
/*
* Allocate the completion queue entries and head/tail pointers.
* This is allocated separately so that it can be resized and
@@ -210,17 +228,18 @@ struct ib_cq *rvt_create_cq(struct ib_device *ibdev,
* We need to use vmalloc() in order to support mmap and large
* numbers of entries.
*/
- sz = sizeof(*wc);
- if (udata && udata->outlen >= sizeof(__u64))
- sz += sizeof(struct ib_uverbs_wc) * (entries + 1);
- else
- sz += sizeof(struct ib_wc) * (entries + 1);
- wc = udata ?
- vmalloc_user(sz) :
- vzalloc_node(sz, rdi->dparms.node);
- if (!wc) {
- ret = ERR_PTR(-ENOMEM);
- goto bail_cq;
+ if (udata && udata->outlen >= sizeof(__u64)) {
+ sz = sizeof(struct ib_uverbs_wc) * (entries + 1);
+ sz += sizeof(*u_wc);
+ u_wc = vmalloc_user(sz);
+ if (!u_wc)
+ return -ENOMEM;
+ } else {
+ sz = sizeof(struct ib_wc) * (entries + 1);
+ sz += sizeof(*k_wc);
+ k_wc = vzalloc_node(sz, rdi->dparms.node);
+ if (!k_wc)
+ return -ENOMEM;
}
/*
@@ -228,26 +247,22 @@ struct ib_cq *rvt_create_cq(struct ib_device *ibdev,
* See rvt_mmap() for details.
*/
if (udata && udata->outlen >= sizeof(__u64)) {
- int err;
-
- cq->ip = rvt_create_mmap_info(rdi, sz, udata, wc);
+ cq->ip = rvt_create_mmap_info(rdi, sz, udata, u_wc);
if (!cq->ip) {
- ret = ERR_PTR(-ENOMEM);
+ err = -ENOMEM;
goto bail_wc;
}
err = ib_copy_to_udata(udata, &cq->ip->offset,
sizeof(cq->ip->offset));
- if (err) {
- ret = ERR_PTR(err);
+ if (err)
goto bail_ip;
- }
}
spin_lock_irq(&rdi->n_cqs_lock);
if (rdi->n_cqs_allocated == rdi->dparms.props.max_cq) {
spin_unlock_irq(&rdi->n_cqs_lock);
- ret = ERR_PTR(-ENOMEM);
+ err = -ENOMEM;
goto bail_ip;
}
@@ -277,21 +292,20 @@ struct ib_cq *rvt_create_cq(struct ib_device *ibdev,
cq->notify = RVT_CQ_NONE;
spin_lock_init(&cq->lock);
INIT_WORK(&cq->comptask, send_complete);
- cq->queue = wc;
-
- ret = &cq->ibcq;
+ if (u_wc)
+ cq->queue = u_wc;
+ else
+ cq->kqueue = k_wc;
trace_rvt_create_cq(cq, attr);
- goto done;
+ return 0;
bail_ip:
kfree(cq->ip);
bail_wc:
- vfree(wc);
-bail_cq:
- kfree(cq);
-done:
- return ret;
+ vfree(u_wc);
+ vfree(k_wc);
+ return err;
}
/**
@@ -300,10 +314,8 @@ done:
* @udata: user data or NULL for kernel object
*
* Called by ib_destroy_cq() in the generic verbs code.
- *
- * Return: always 0
*/
-int rvt_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
+void rvt_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
{
struct rvt_cq *cq = ibcq_to_rvtcq(ibcq);
struct rvt_dev_info *rdi = cq->rdi;
@@ -316,9 +328,6 @@ int rvt_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
kref_put(&cq->ip->ref, rvt_release_mmap_info);
else
vfree(cq->queue);
- kfree(cq);
-
- return 0;
}
/**
@@ -345,9 +354,16 @@ int rvt_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags notify_flags)
if (cq->notify != IB_CQ_NEXT_COMP)
cq->notify = notify_flags & IB_CQ_SOLICITED_MASK;
- if ((notify_flags & IB_CQ_REPORT_MISSED_EVENTS) &&
- cq->queue->head != cq->queue->tail)
- ret = 1;
+ if (notify_flags & IB_CQ_REPORT_MISSED_EVENTS) {
+ if (cq->queue) {
+ if (RDMA_READ_UAPI_ATOMIC(cq->queue->head) !=
+ RDMA_READ_UAPI_ATOMIC(cq->queue->tail))
+ ret = 1;
+ } else {
+ if (cq->kqueue->head != cq->kqueue->tail)
+ ret = 1;
+ }
+ }
spin_unlock_irqrestore(&cq->lock, flags);
@@ -363,12 +379,14 @@ int rvt_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags notify_flags)
int rvt_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
{
struct rvt_cq *cq = ibcq_to_rvtcq(ibcq);
- struct rvt_cq_wc *old_wc;
- struct rvt_cq_wc *wc;
u32 head, tail, n;
int ret;
u32 sz;
struct rvt_dev_info *rdi = cq->rdi;
+ struct rvt_cq_wc *u_wc = NULL;
+ struct rvt_cq_wc *old_u_wc = NULL;
+ struct rvt_k_cq_wc *k_wc = NULL;
+ struct rvt_k_cq_wc *old_k_wc = NULL;
if (cqe < 1 || cqe > rdi->dparms.props.max_cqe)
return -EINVAL;
@@ -376,17 +394,19 @@ int rvt_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
/*
* Need to use vmalloc() if we want to support large #s of entries.
*/
- sz = sizeof(*wc);
- if (udata && udata->outlen >= sizeof(__u64))
- sz += sizeof(struct ib_uverbs_wc) * (cqe + 1);
- else
- sz += sizeof(struct ib_wc) * (cqe + 1);
- wc = udata ?
- vmalloc_user(sz) :
- vzalloc_node(sz, rdi->dparms.node);
- if (!wc)
- return -ENOMEM;
-
+ if (udata && udata->outlen >= sizeof(__u64)) {
+ sz = sizeof(struct ib_uverbs_wc) * (cqe + 1);
+ sz += sizeof(*u_wc);
+ u_wc = vmalloc_user(sz);
+ if (!u_wc)
+ return -ENOMEM;
+ } else {
+ sz = sizeof(struct ib_wc) * (cqe + 1);
+ sz += sizeof(*k_wc);
+ k_wc = vzalloc_node(sz, rdi->dparms.node);
+ if (!k_wc)
+ return -ENOMEM;
+ }
/* Check that we can write the offset to mmap. */
if (udata && udata->outlen >= sizeof(__u64)) {
__u64 offset = 0;
@@ -401,11 +421,18 @@ int rvt_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
* Make sure head and tail are sane since they
* might be user writable.
*/
- old_wc = cq->queue;
- head = old_wc->head;
+ if (u_wc) {
+ old_u_wc = cq->queue;
+ head = RDMA_READ_UAPI_ATOMIC(old_u_wc->head);
+ tail = RDMA_READ_UAPI_ATOMIC(old_u_wc->tail);
+ } else {
+ old_k_wc = cq->kqueue;
+ head = old_k_wc->head;
+ tail = old_k_wc->tail;
+ }
+
if (head > (u32)cq->ibcq.cqe)
head = (u32)cq->ibcq.cqe;
- tail = old_wc->tail;
if (tail > (u32)cq->ibcq.cqe)
tail = (u32)cq->ibcq.cqe;
if (head < tail)
@@ -417,27 +444,36 @@ int rvt_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
goto bail_unlock;
}
for (n = 0; tail != head; n++) {
- if (cq->ip)
- wc->uqueue[n] = old_wc->uqueue[tail];
+ if (u_wc)
+ u_wc->uqueue[n] = old_u_wc->uqueue[tail];
else
- wc->kqueue[n] = old_wc->kqueue[tail];
+ k_wc->kqueue[n] = old_k_wc->kqueue[tail];
if (tail == (u32)cq->ibcq.cqe)
tail = 0;
else
tail++;
}
cq->ibcq.cqe = cqe;
- wc->head = n;
- wc->tail = 0;
- cq->queue = wc;
+ if (u_wc) {
+ RDMA_WRITE_UAPI_ATOMIC(u_wc->head, n);
+ RDMA_WRITE_UAPI_ATOMIC(u_wc->tail, 0);
+ cq->queue = u_wc;
+ } else {
+ k_wc->head = n;
+ k_wc->tail = 0;
+ cq->kqueue = k_wc;
+ }
spin_unlock_irq(&cq->lock);
- vfree(old_wc);
+ if (u_wc)
+ vfree(old_u_wc);
+ else
+ vfree(old_k_wc);
if (cq->ip) {
struct rvt_mmap_info *ip = cq->ip;
- rvt_update_mmap_info(rdi, ip, sz, wc);
+ rvt_update_mmap_info(rdi, ip, sz, u_wc);
/*
* Return the offset to mmap.
@@ -461,7 +497,9 @@ int rvt_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
bail_unlock:
spin_unlock_irq(&cq->lock);
bail_free:
- vfree(wc);
+ vfree(u_wc);
+ vfree(k_wc);
+
return ret;
}
@@ -479,7 +517,7 @@ bail_free:
int rvt_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
{
struct rvt_cq *cq = ibcq_to_rvtcq(ibcq);
- struct rvt_cq_wc *wc;
+ struct rvt_k_cq_wc *wc;
unsigned long flags;
int npolled;
u32 tail;
@@ -490,7 +528,7 @@ int rvt_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
spin_lock_irqsave(&cq->lock, flags);
- wc = cq->queue;
+ wc = cq->kqueue;
tail = wc->tail;
if (tail > (u32)cq->ibcq.cqe)
tail = (u32)cq->ibcq.cqe;
diff --git a/drivers/infiniband/sw/rdmavt/cq.h b/drivers/infiniband/sw/rdmavt/cq.h
index 3ad6faf18ecb..5e26a2eb19a4 100644
--- a/drivers/infiniband/sw/rdmavt/cq.h
+++ b/drivers/infiniband/sw/rdmavt/cq.h
@@ -51,10 +51,9 @@
#include <rdma/rdma_vt.h>
#include <rdma/rdmavt_cq.h>
-struct ib_cq *rvt_create_cq(struct ib_device *ibdev,
- const struct ib_cq_init_attr *attr,
- struct ib_udata *udata);
-int rvt_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata);
+int rvt_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata);
+void rvt_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata);
int rvt_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags notify_flags);
int rvt_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata);
int rvt_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry);
diff --git a/drivers/infiniband/sw/rdmavt/mr.c b/drivers/infiniband/sw/rdmavt/mr.c
index f48240f66b8f..a6a39f01dca3 100644
--- a/drivers/infiniband/sw/rdmavt/mr.c
+++ b/drivers/infiniband/sw/rdmavt/mr.c
@@ -562,8 +562,7 @@ int rvt_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
if (ret)
goto out;
rvt_deinit_mregion(&mr->mr);
- if (mr->umem)
- ib_umem_release(mr->umem);
+ ib_umem_release(mr->umem);
kfree(mr);
out:
return ret;
@@ -613,8 +612,8 @@ static int rvt_set_page(struct ib_mr *ibmr, u64 addr)
n = mapped_segs % RVT_SEGSZ;
mr->mr.map[m]->segs[n].vaddr = (void *)addr;
mr->mr.map[m]->segs[n].length = ps;
- trace_rvt_mr_page_seg(&mr->mr, m, n, (void *)addr, ps);
mr->mr.length += ps;
+ trace_rvt_mr_page_seg(&mr->mr, m, n, (void *)addr, ps);
return 0;
}
@@ -643,6 +642,7 @@ int rvt_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg,
mr->mr.iova = ibmr->iova;
mr->mr.offset = ibmr->iova - (u64)mr->mr.map[0]->segs[0].vaddr;
mr->mr.length = (size_t)ibmr->length;
+ trace_rvt_map_mr_sg(ibmr, sg_nents, sg_offset);
return ret;
}
diff --git a/drivers/infiniband/sw/rdmavt/qp.c b/drivers/infiniband/sw/rdmavt/qp.c
index c5a50614a6c6..0b0a241c57ff 100644
--- a/drivers/infiniband/sw/rdmavt/qp.c
+++ b/drivers/infiniband/sw/rdmavt/qp.c
@@ -1,5 +1,5 @@
/*
- * Copyright(c) 2016 - 2018 Intel Corporation.
+ * Copyright(c) 2016 - 2019 Intel Corporation.
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
@@ -58,6 +58,8 @@
#include "vt.h"
#include "trace.h"
+#define RVT_RWQ_COUNT_THRESHOLD 16
+
static void rvt_rc_timeout(struct timer_list *t);
/*
@@ -803,6 +805,47 @@ static void rvt_remove_qp(struct rvt_dev_info *rdi, struct rvt_qp *qp)
}
/**
+ * rvt_alloc_rq - allocate memory for user or kernel buffer
+ * @rq: receive queue data structure
+ * @size: number of request queue entries
+ * @node: The NUMA node
+ * @udata: True if user data is available or not false
+ *
+ * Return: If memory allocation failed, return -ENONEM
+ * This function is used by both shared receive
+ * queues and non-shared receive queues to allocate
+ * memory.
+ */
+int rvt_alloc_rq(struct rvt_rq *rq, u32 size, int node,
+ struct ib_udata *udata)
+{
+ if (udata) {
+ rq->wq = vmalloc_user(sizeof(struct rvt_rwq) + size);
+ if (!rq->wq)
+ goto bail;
+ /* need kwq with no buffers */
+ rq->kwq = kzalloc_node(sizeof(*rq->kwq), GFP_KERNEL, node);
+ if (!rq->kwq)
+ goto bail;
+ rq->kwq->curr_wq = rq->wq->wq;
+ } else {
+ /* need kwq with buffers */
+ rq->kwq =
+ vzalloc_node(sizeof(struct rvt_krwq) + size, node);
+ if (!rq->kwq)
+ goto bail;
+ rq->kwq->curr_wq = rq->kwq->wq;
+ }
+
+ spin_lock_init(&rq->kwq->p_lock);
+ spin_lock_init(&rq->kwq->c_lock);
+ return 0;
+bail:
+ rvt_free_rq(rq);
+ return -ENOMEM;
+}
+
+/**
* rvt_init_qp - initialize the QP state to the reset state
* @qp: the QP to init or reinit
* @type: the QP type
@@ -852,10 +895,8 @@ static void rvt_init_qp(struct rvt_dev_info *rdi, struct rvt_qp *qp,
qp->s_tail_ack_queue = 0;
qp->s_acked_ack_queue = 0;
qp->s_num_rd_atomic = 0;
- if (qp->r_rq.wq) {
- qp->r_rq.wq->head = 0;
- qp->r_rq.wq->tail = 0;
- }
+ if (qp->r_rq.kwq)
+ qp->r_rq.kwq->count = qp->r_rq.size;
qp->r_sge.num_sge = 0;
atomic_set(&qp->s_reserved_used, 0);
}
@@ -928,6 +969,61 @@ static void rvt_free_qpn(struct rvt_qpn_table *qpt, u32 qpn)
}
/**
+ * get_allowed_ops - Given a QP type return the appropriate allowed OP
+ * @type: valid, supported, QP type
+ */
+static u8 get_allowed_ops(enum ib_qp_type type)
+{
+ return type == IB_QPT_RC ? IB_OPCODE_RC : type == IB_QPT_UC ?
+ IB_OPCODE_UC : IB_OPCODE_UD;
+}
+
+/**
+ * free_ud_wq_attr - Clean up AH attribute cache for UD QPs
+ * @qp: Valid QP with allowed_ops set
+ *
+ * The rvt_swqe data structure being used is a union, so this is
+ * only valid for UD QPs.
+ */
+static void free_ud_wq_attr(struct rvt_qp *qp)
+{
+ struct rvt_swqe *wqe;
+ int i;
+
+ for (i = 0; qp->allowed_ops == IB_OPCODE_UD && i < qp->s_size; i++) {
+ wqe = rvt_get_swqe_ptr(qp, i);
+ kfree(wqe->ud_wr.attr);
+ wqe->ud_wr.attr = NULL;
+ }
+}
+
+/**
+ * alloc_ud_wq_attr - AH attribute cache for UD QPs
+ * @qp: Valid QP with allowed_ops set
+ * @node: Numa node for allocation
+ *
+ * The rvt_swqe data structure being used is a union, so this is
+ * only valid for UD QPs.
+ */
+static int alloc_ud_wq_attr(struct rvt_qp *qp, int node)
+{
+ struct rvt_swqe *wqe;
+ int i;
+
+ for (i = 0; qp->allowed_ops == IB_OPCODE_UD && i < qp->s_size; i++) {
+ wqe = rvt_get_swqe_ptr(qp, i);
+ wqe->ud_wr.attr = kzalloc_node(sizeof(*wqe->ud_wr.attr),
+ GFP_KERNEL, node);
+ if (!wqe->ud_wr.attr) {
+ free_ud_wq_attr(qp);
+ return -ENOMEM;
+ }
+ }
+
+ return 0;
+}
+
+/**
* rvt_create_qp - create a queue pair for a device
* @ibpd: the protection domain who's device we create the queue pair for
* @init_attr: the attributes of the queue pair
@@ -989,9 +1085,7 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
case IB_QPT_UC:
case IB_QPT_RC:
case IB_QPT_UD:
- sz = sizeof(struct rvt_sge) *
- init_attr->cap.max_send_sge +
- sizeof(struct rvt_swqe);
+ sz = struct_size(swq, sg_list, init_attr->cap.max_send_sge);
swq = vzalloc_node(array_size(sz, sqsize), rdi->dparms.node);
if (!swq)
return ERR_PTR(-ENOMEM);
@@ -1011,6 +1105,7 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
rdi->dparms.node);
if (!qp)
goto bail_swq;
+ qp->allowed_ops = get_allowed_ops(init_attr->qp_type);
RCU_INIT_POINTER(qp->next, NULL);
if (init_attr->qp_type == IB_QPT_RC) {
@@ -1048,17 +1143,12 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
qp->r_rq.max_sge = init_attr->cap.max_recv_sge;
sz = (sizeof(struct ib_sge) * qp->r_rq.max_sge) +
sizeof(struct rvt_rwqe);
- if (udata)
- qp->r_rq.wq = vmalloc_user(
- sizeof(struct rvt_rwq) +
- qp->r_rq.size * sz);
- else
- qp->r_rq.wq = vzalloc_node(
- sizeof(struct rvt_rwq) +
- qp->r_rq.size * sz,
- rdi->dparms.node);
- if (!qp->r_rq.wq)
+ err = rvt_alloc_rq(&qp->r_rq, qp->r_rq.size * sz,
+ rdi->dparms.node, udata);
+ if (err) {
+ ret = ERR_PTR(err);
goto bail_driver_priv;
+ }
}
/*
@@ -1068,7 +1158,6 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
spin_lock_init(&qp->r_lock);
spin_lock_init(&qp->s_hlock);
spin_lock_init(&qp->s_lock);
- spin_lock_init(&qp->r_rq.lock);
atomic_set(&qp->refcount, 0);
atomic_set(&qp->local_ops_pending, 0);
init_waitqueue_head(&qp->wait);
@@ -1080,6 +1169,11 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
qp->s_max_sge = init_attr->cap.max_send_sge;
if (init_attr->sq_sig_type == IB_SIGNAL_REQ_WR)
qp->s_flags = RVT_S_SIGNAL_REQ_WR;
+ err = alloc_ud_wq_attr(qp, rdi->dparms.node);
+ if (err) {
+ ret = (ERR_PTR(err));
+ goto bail_driver_priv;
+ }
err = alloc_qpn(rdi, &rdi->qp_dev->qpn_table,
init_attr->qp_type,
@@ -1172,28 +1266,6 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
ret = &qp->ibqp;
- /*
- * We have our QP and its good, now keep track of what types of opcodes
- * can be processed on this QP. We do this by keeping track of what the
- * 3 high order bits of the opcode are.
- */
- switch (init_attr->qp_type) {
- case IB_QPT_SMI:
- case IB_QPT_GSI:
- case IB_QPT_UD:
- qp->allowed_ops = IB_OPCODE_UD;
- break;
- case IB_QPT_RC:
- qp->allowed_ops = IB_OPCODE_RC;
- break;
- case IB_QPT_UC:
- qp->allowed_ops = IB_OPCODE_UC;
- break;
- default:
- ret = ERR_PTR(-EINVAL);
- goto bail_ip;
- }
-
return ret;
bail_ip:
@@ -1204,8 +1276,8 @@ bail_qpn:
rvt_free_qpn(&rdi->qp_dev->qpn_table, qp->ibqp.qp_num);
bail_rq_wq:
- if (!qp->ip)
- vfree(qp->r_rq.wq);
+ rvt_free_rq(&qp->r_rq);
+ free_ud_wq_attr(qp);
bail_driver_priv:
rdi->driver_f.qp_priv_free(rdi, qp);
@@ -1271,19 +1343,26 @@ int rvt_error_qp(struct rvt_qp *qp, enum ib_wc_status err)
}
wc.status = IB_WC_WR_FLUSH_ERR;
- if (qp->r_rq.wq) {
- struct rvt_rwq *wq;
+ if (qp->r_rq.kwq) {
u32 head;
u32 tail;
-
- spin_lock(&qp->r_rq.lock);
-
+ struct rvt_rwq *wq = NULL;
+ struct rvt_krwq *kwq = NULL;
+
+ spin_lock(&qp->r_rq.kwq->c_lock);
+ /* qp->ip used to validate if there is a user buffer mmaped */
+ if (qp->ip) {
+ wq = qp->r_rq.wq;
+ head = RDMA_READ_UAPI_ATOMIC(wq->head);
+ tail = RDMA_READ_UAPI_ATOMIC(wq->tail);
+ } else {
+ kwq = qp->r_rq.kwq;
+ head = kwq->head;
+ tail = kwq->tail;
+ }
/* sanity check pointers before trusting them */
- wq = qp->r_rq.wq;
- head = wq->head;
if (head >= qp->r_rq.size)
head = 0;
- tail = wq->tail;
if (tail >= qp->r_rq.size)
tail = 0;
while (tail != head) {
@@ -1292,9 +1371,11 @@ int rvt_error_qp(struct rvt_qp *qp, enum ib_wc_status err)
tail = 0;
rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc, 1);
}
- wq->tail = tail;
-
- spin_unlock(&qp->r_rq.lock);
+ if (qp->ip)
+ RDMA_WRITE_UAPI_ATOMIC(wq->tail, tail);
+ else
+ kwq->tail = tail;
+ spin_unlock(&qp->r_rq.kwq->c_lock);
} else if (qp->ibqp.event_handler) {
ret = 1;
}
@@ -1636,12 +1717,12 @@ int rvt_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
if (qp->ip)
kref_put(&qp->ip->ref, rvt_release_mmap_info);
- else
- vfree(qp->r_rq.wq);
+ kvfree(qp->r_rq.kwq);
rdi->driver_f.qp_priv_free(rdi, qp);
kfree(qp->s_ack_queue);
rdma_destroy_ah_attr(&qp->remote_ah_attr);
rdma_destroy_ah_attr(&qp->alt_ah_attr);
+ free_ud_wq_attr(qp);
vfree(qp->s_wq);
kfree(qp);
return 0;
@@ -1723,7 +1804,7 @@ int rvt_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr,
const struct ib_recv_wr **bad_wr)
{
struct rvt_qp *qp = ibqp_to_rvtqp(ibqp);
- struct rvt_rwq *wq = qp->r_rq.wq;
+ struct rvt_krwq *wq = qp->r_rq.kwq;
unsigned long flags;
int qp_err_flush = (ib_rvt_state_ops[qp->state] & RVT_FLUSH_RECV) &&
!qp->ibqp.srq;
@@ -1744,12 +1825,12 @@ int rvt_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr,
return -EINVAL;
}
- spin_lock_irqsave(&qp->r_rq.lock, flags);
+ spin_lock_irqsave(&qp->r_rq.kwq->p_lock, flags);
next = wq->head + 1;
if (next >= qp->r_rq.size)
next = 0;
- if (next == wq->tail) {
- spin_unlock_irqrestore(&qp->r_rq.lock, flags);
+ if (next == READ_ONCE(wq->tail)) {
+ spin_unlock_irqrestore(&qp->r_rq.kwq->p_lock, flags);
*bad_wr = wr;
return -ENOMEM;
}
@@ -1766,16 +1847,18 @@ int rvt_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr,
wqe = rvt_get_rwqe_ptr(&qp->r_rq, wq->head);
wqe->wr_id = wr->wr_id;
wqe->num_sge = wr->num_sge;
- for (i = 0; i < wr->num_sge; i++)
- wqe->sg_list[i] = wr->sg_list[i];
+ for (i = 0; i < wr->num_sge; i++) {
+ wqe->sg_list[i].addr = wr->sg_list[i].addr;
+ wqe->sg_list[i].length = wr->sg_list[i].length;
+ wqe->sg_list[i].lkey = wr->sg_list[i].lkey;
+ }
/*
* Make sure queue entry is written
* before the head index.
*/
- smp_wmb();
- wq->head = next;
+ smp_store_release(&wq->head, next);
}
- spin_unlock_irqrestore(&qp->r_rq.lock, flags);
+ spin_unlock_irqrestore(&qp->r_rq.kwq->p_lock, flags);
}
return 0;
}
@@ -1856,10 +1939,9 @@ static inline int rvt_qp_is_avail(
/* see rvt_qp_wqe_unreserve() */
smp_mb__before_atomic();
- reserved_used = atomic_read(&qp->s_reserved_used);
if (unlikely(reserved_op)) {
/* see rvt_qp_wqe_unreserve() */
- smp_mb__before_atomic();
+ reserved_used = atomic_read(&qp->s_reserved_used);
if (reserved_used >= rdi->dparms.reserved_operations)
return -ENOMEM;
return 0;
@@ -1867,14 +1949,13 @@ static inline int rvt_qp_is_avail(
/* non-reserved operations */
if (likely(qp->s_avail))
return 0;
- slast = READ_ONCE(qp->s_last);
+ /* See rvt_qp_complete_swqe() */
+ slast = smp_load_acquire(&qp->s_last);
if (qp->s_head >= slast)
avail = qp->s_size - (qp->s_head - slast);
else
avail = slast - qp->s_head;
- /* see rvt_qp_wqe_unreserve() */
- smp_mb__before_atomic();
reserved_used = atomic_read(&qp->s_reserved_used);
avail = avail - 1 -
(rdi->dparms.reserved_operations - reserved_used);
@@ -2011,10 +2092,10 @@ static int rvt_post_one_wr(struct rvt_qp *qp,
*/
log_pmtu = qp->log_pmtu;
if (qp->allowed_ops == IB_OPCODE_UD) {
- struct rvt_ah *ah = ibah_to_rvtah(wqe->ud_wr.ah);
+ struct rvt_ah *ah = rvt_get_swqe_ah(wqe);
log_pmtu = ah->log_pmtu;
- atomic_inc(&ibah_to_rvtah(ud_wr(wr)->ah)->refcount);
+ rdma_copy_ah_attr(wqe->ud_wr.attr, &ah->attr);
}
if (rdi->post_parms[wr->opcode].flags & RVT_OPERATION_LOCAL) {
@@ -2059,7 +2140,7 @@ static int rvt_post_one_wr(struct rvt_qp *qp,
bail_inval_free_ref:
if (qp->allowed_ops == IB_OPCODE_UD)
- atomic_dec(&ibah_to_rvtah(ud_wr(wr)->ah)->refcount);
+ rdma_destroy_ah_attr(wqe->ud_wr.attr);
bail_inval_free:
/* release mr holds */
while (j) {
@@ -2145,7 +2226,7 @@ int rvt_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr,
const struct ib_recv_wr **bad_wr)
{
struct rvt_srq *srq = ibsrq_to_rvtsrq(ibsrq);
- struct rvt_rwq *wq;
+ struct rvt_krwq *wq;
unsigned long flags;
for (; wr; wr = wr->next) {
@@ -2158,13 +2239,13 @@ int rvt_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr,
return -EINVAL;
}
- spin_lock_irqsave(&srq->rq.lock, flags);
- wq = srq->rq.wq;
+ spin_lock_irqsave(&srq->rq.kwq->p_lock, flags);
+ wq = srq->rq.kwq;
next = wq->head + 1;
if (next >= srq->rq.size)
next = 0;
- if (next == wq->tail) {
- spin_unlock_irqrestore(&srq->rq.lock, flags);
+ if (next == READ_ONCE(wq->tail)) {
+ spin_unlock_irqrestore(&srq->rq.kwq->p_lock, flags);
*bad_wr = wr;
return -ENOMEM;
}
@@ -2172,17 +2253,35 @@ int rvt_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr,
wqe = rvt_get_rwqe_ptr(&srq->rq, wq->head);
wqe->wr_id = wr->wr_id;
wqe->num_sge = wr->num_sge;
- for (i = 0; i < wr->num_sge; i++)
- wqe->sg_list[i] = wr->sg_list[i];
+ for (i = 0; i < wr->num_sge; i++) {
+ wqe->sg_list[i].addr = wr->sg_list[i].addr;
+ wqe->sg_list[i].length = wr->sg_list[i].length;
+ wqe->sg_list[i].lkey = wr->sg_list[i].lkey;
+ }
/* Make sure queue entry is written before the head index. */
- smp_wmb();
- wq->head = next;
- spin_unlock_irqrestore(&srq->rq.lock, flags);
+ smp_store_release(&wq->head, next);
+ spin_unlock_irqrestore(&srq->rq.kwq->p_lock, flags);
}
return 0;
}
/*
+ * rvt used the internal kernel struct as part of its ABI, for now make sure
+ * the kernel struct does not change layout. FIXME: rvt should never cast the
+ * user struct to a kernel struct.
+ */
+static struct ib_sge *rvt_cast_sge(struct rvt_wqe_sge *sge)
+{
+ BUILD_BUG_ON(offsetof(struct ib_sge, addr) !=
+ offsetof(struct rvt_wqe_sge, addr));
+ BUILD_BUG_ON(offsetof(struct ib_sge, length) !=
+ offsetof(struct rvt_wqe_sge, length));
+ BUILD_BUG_ON(offsetof(struct ib_sge, lkey) !=
+ offsetof(struct rvt_wqe_sge, lkey));
+ return (struct ib_sge *)sge;
+}
+
+/*
* Validate a RWQE and fill in the SGE state.
* Return 1 if OK.
*/
@@ -2205,7 +2304,7 @@ static int init_sge(struct rvt_qp *qp, struct rvt_rwqe *wqe)
continue;
/* Check LKEY */
ret = rvt_lkey_ok(rkt, pd, j ? &ss->sg_list[j - 1] : &ss->sge,
- NULL, &wqe->sg_list[i],
+ NULL, rvt_cast_sge(&wqe->sg_list[i]),
IB_ACCESS_LOCAL_WRITE);
if (unlikely(ret <= 0))
goto bad_lkey;
@@ -2234,6 +2333,50 @@ bad_lkey:
}
/**
+ * get_count - count numbers of request work queue entries
+ * in circular buffer
+ * @rq: data structure for request queue entry
+ * @tail: tail indices of the circular buffer
+ * @head: head indices of the circular buffer
+ *
+ * Return - total number of entries in the circular buffer
+ */
+static u32 get_count(struct rvt_rq *rq, u32 tail, u32 head)
+{
+ u32 count;
+
+ count = head;
+
+ if (count >= rq->size)
+ count = 0;
+ if (count < tail)
+ count += rq->size - tail;
+ else
+ count -= tail;
+
+ return count;
+}
+
+/**
+ * get_rvt_head - get head indices of the circular buffer
+ * @rq: data structure for request queue entry
+ * @ip: the QP
+ *
+ * Return - head index value
+ */
+static inline u32 get_rvt_head(struct rvt_rq *rq, void *ip)
+{
+ u32 head;
+
+ if (ip)
+ head = RDMA_READ_UAPI_ATOMIC(rq->wq->head);
+ else
+ head = rq->kwq->head;
+
+ return head;
+}
+
+/**
* rvt_get_rwqe - copy the next RWQE into the QP's RWQE
* @qp: the QP
* @wr_id_only: update qp->r_wr_id only, not qp->r_sge
@@ -2247,39 +2390,54 @@ int rvt_get_rwqe(struct rvt_qp *qp, bool wr_id_only)
{
unsigned long flags;
struct rvt_rq *rq;
+ struct rvt_krwq *kwq = NULL;
struct rvt_rwq *wq;
struct rvt_srq *srq;
struct rvt_rwqe *wqe;
void (*handler)(struct ib_event *, void *);
u32 tail;
+ u32 head;
int ret;
+ void *ip = NULL;
if (qp->ibqp.srq) {
srq = ibsrq_to_rvtsrq(qp->ibqp.srq);
handler = srq->ibsrq.event_handler;
rq = &srq->rq;
+ ip = srq->ip;
} else {
srq = NULL;
handler = NULL;
rq = &qp->r_rq;
+ ip = qp->ip;
}
- spin_lock_irqsave(&rq->lock, flags);
+ spin_lock_irqsave(&rq->kwq->c_lock, flags);
if (!(ib_rvt_state_ops[qp->state] & RVT_PROCESS_RECV_OK)) {
ret = 0;
goto unlock;
}
+ kwq = rq->kwq;
+ if (ip) {
+ wq = rq->wq;
+ tail = RDMA_READ_UAPI_ATOMIC(wq->tail);
+ } else {
+ tail = kwq->tail;
+ }
- wq = rq->wq;
- tail = wq->tail;
/* Validate tail before using it since it is user writable. */
if (tail >= rq->size)
tail = 0;
- if (unlikely(tail == wq->head)) {
+
+ if (kwq->count < RVT_RWQ_COUNT_THRESHOLD) {
+ head = get_rvt_head(rq, ip);
+ kwq->count = get_count(rq, tail, head);
+ }
+ if (unlikely(kwq->count == 0)) {
ret = 0;
goto unlock;
}
- /* Make sure entry is read after head index is read. */
+ /* Make sure entry is read after the count is read. */
smp_rmb();
wqe = rvt_get_rwqe_ptr(rq, tail);
/*
@@ -2289,43 +2447,41 @@ int rvt_get_rwqe(struct rvt_qp *qp, bool wr_id_only)
*/
if (++tail >= rq->size)
tail = 0;
- wq->tail = tail;
+ if (ip)
+ RDMA_WRITE_UAPI_ATOMIC(wq->tail, tail);
+ else
+ kwq->tail = tail;
if (!wr_id_only && !init_sge(qp, wqe)) {
ret = -1;
goto unlock;
}
qp->r_wr_id = wqe->wr_id;
+ kwq->count--;
ret = 1;
set_bit(RVT_R_WRID_VALID, &qp->r_aflags);
if (handler) {
- u32 n;
-
/*
* Validate head pointer value and compute
* the number of remaining WQEs.
*/
- n = wq->head;
- if (n >= rq->size)
- n = 0;
- if (n < tail)
- n += rq->size - tail;
- else
- n -= tail;
- if (n < srq->limit) {
- struct ib_event ev;
-
- srq->limit = 0;
- spin_unlock_irqrestore(&rq->lock, flags);
- ev.device = qp->ibqp.device;
- ev.element.srq = qp->ibqp.srq;
- ev.event = IB_EVENT_SRQ_LIMIT_REACHED;
- handler(&ev, srq->ibsrq.srq_context);
- goto bail;
+ if (kwq->count < srq->limit) {
+ kwq->count = get_count(rq, tail, get_rvt_head(rq, ip));
+ if (kwq->count < srq->limit) {
+ struct ib_event ev;
+
+ srq->limit = 0;
+ spin_unlock_irqrestore(&rq->kwq->c_lock, flags);
+ ev.device = qp->ibqp.device;
+ ev.element.srq = qp->ibqp.srq;
+ ev.event = IB_EVENT_SRQ_LIMIT_REACHED;
+ handler(&ev, srq->ibsrq.srq_context);
+ goto bail;
+ }
}
}
unlock:
- spin_unlock_irqrestore(&rq->lock, flags);
+ spin_unlock_irqrestore(&rq->kwq->c_lock, flags);
bail:
return ret;
}
@@ -2667,27 +2823,16 @@ void rvt_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe,
enum ib_wc_status status)
{
u32 old_last, last;
- struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device);
+ struct rvt_dev_info *rdi;
if (!(ib_rvt_state_ops[qp->state] & RVT_PROCESS_OR_FLUSH_SEND))
return;
+ rdi = ib_to_rvt(qp->ibqp.device);
- last = qp->s_last;
- old_last = last;
- trace_rvt_qp_send_completion(qp, wqe, last);
- if (++last >= qp->s_size)
- last = 0;
- trace_rvt_qp_send_completion(qp, wqe, last);
- qp->s_last = last;
- /* See post_send() */
- barrier();
- rvt_put_qp_swqe(qp, wqe);
-
- rvt_qp_swqe_complete(qp,
- wqe,
- rdi->wc_opcode[wqe->wr.opcode],
- status);
-
+ old_last = qp->s_last;
+ trace_rvt_qp_send_completion(qp, wqe, old_last);
+ last = rvt_qp_complete_swqe(qp, wqe, rdi->wc_opcode[wqe->wr.opcode],
+ status);
if (qp->s_acked == old_last)
qp->s_acked = last;
if (qp->s_cur == old_last)
@@ -3021,8 +3166,7 @@ do_write:
wc.sl = rdma_ah_get_sl(&qp->remote_ah_attr);
wc.port_num = 1;
/* Signal completion event if the solicited bit is set. */
- rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc,
- wqe->wr.send_flags & IB_SEND_SOLICITED);
+ rvt_recv_cq(qp, &wc, wqe->wr.send_flags & IB_SEND_SOLICITED);
send_comp:
spin_unlock_irqrestore(&qp->r_lock, flags);
diff --git a/drivers/infiniband/sw/rdmavt/qp.h b/drivers/infiniband/sw/rdmavt/qp.h
index 6db1619389b0..2cdba1283bf6 100644
--- a/drivers/infiniband/sw/rdmavt/qp.h
+++ b/drivers/infiniband/sw/rdmavt/qp.h
@@ -68,4 +68,6 @@ int rvt_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr,
const struct ib_recv_wr **bad_wr);
int rvt_wss_init(struct rvt_dev_info *rdi);
void rvt_wss_exit(struct rvt_dev_info *rdi);
+int rvt_alloc_rq(struct rvt_rq *rq, u32 size, int node,
+ struct ib_udata *udata);
#endif /* DEF_RVTQP_H */
diff --git a/drivers/infiniband/sw/rdmavt/rc.c b/drivers/infiniband/sw/rdmavt/rc.c
index 09f0cf538be6..890d7b760d2e 100644
--- a/drivers/infiniband/sw/rdmavt/rc.c
+++ b/drivers/infiniband/sw/rdmavt/rc.c
@@ -104,26 +104,33 @@ __be32 rvt_compute_aeth(struct rvt_qp *qp)
} else {
u32 min, max, x;
u32 credits;
- struct rvt_rwq *wq = qp->r_rq.wq;
u32 head;
u32 tail;
- /* sanity check pointers before trusting them */
- head = wq->head;
- if (head >= qp->r_rq.size)
- head = 0;
- tail = wq->tail;
- if (tail >= qp->r_rq.size)
- tail = 0;
- /*
- * Compute the number of credits available (RWQEs).
- * There is a small chance that the pair of reads are
- * not atomic, which is OK, since the fuzziness is
- * resolved as further ACKs go out.
- */
- credits = head - tail;
- if ((int)credits < 0)
- credits += qp->r_rq.size;
+ credits = READ_ONCE(qp->r_rq.kwq->count);
+ if (credits == 0) {
+ /* sanity check pointers before trusting them */
+ if (qp->ip) {
+ head = RDMA_READ_UAPI_ATOMIC(qp->r_rq.wq->head);
+ tail = RDMA_READ_UAPI_ATOMIC(qp->r_rq.wq->tail);
+ } else {
+ head = READ_ONCE(qp->r_rq.kwq->head);
+ tail = READ_ONCE(qp->r_rq.kwq->tail);
+ }
+ if (head >= qp->r_rq.size)
+ head = 0;
+ if (tail >= qp->r_rq.size)
+ tail = 0;
+ /*
+ * Compute the number of credits available (RWQEs).
+ * There is a small chance that the pair of reads are
+ * not atomic, which is OK, since the fuzziness is
+ * resolved as further ACKs go out.
+ */
+ credits = head - tail;
+ if ((int)credits < 0)
+ credits += qp->r_rq.size;
+ }
/*
* Binary search the credit table to find the code to
* use.
diff --git a/drivers/infiniband/sw/rdmavt/srq.c b/drivers/infiniband/sw/rdmavt/srq.c
index 8d6b3e764255..24fef021d51d 100644
--- a/drivers/infiniband/sw/rdmavt/srq.c
+++ b/drivers/infiniband/sw/rdmavt/srq.c
@@ -52,7 +52,7 @@
#include "srq.h"
#include "vt.h"
-
+#include "qp.h"
/**
* rvt_driver_srq_init - init srq resources on a per driver basis
* @rdi: rvt dev structure
@@ -97,11 +97,8 @@ int rvt_create_srq(struct ib_srq *ibsrq, struct ib_srq_init_attr *srq_init_attr,
srq->rq.max_sge = srq_init_attr->attr.max_sge;
sz = sizeof(struct ib_sge) * srq->rq.max_sge +
sizeof(struct rvt_rwqe);
- srq->rq.wq = udata ?
- vmalloc_user(sizeof(struct rvt_rwq) + srq->rq.size * sz) :
- vzalloc_node(sizeof(struct rvt_rwq) + srq->rq.size * sz,
- dev->dparms.node);
- if (!srq->rq.wq) {
+ if (rvt_alloc_rq(&srq->rq, srq->rq.size * sz,
+ dev->dparms.node, udata)) {
ret = -ENOMEM;
goto bail_srq;
}
@@ -152,7 +149,7 @@ int rvt_create_srq(struct ib_srq *ibsrq, struct ib_srq_init_attr *srq_init_attr,
bail_ip:
kfree(srq->ip);
bail_wq:
- vfree(srq->rq.wq);
+ rvt_free_rq(&srq->rq);
bail_srq:
return ret;
}
@@ -172,11 +169,12 @@ int rvt_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
{
struct rvt_srq *srq = ibsrq_to_rvtsrq(ibsrq);
struct rvt_dev_info *dev = ib_to_rvt(ibsrq->device);
- struct rvt_rwq *wq;
+ struct rvt_rq tmp_rq = {};
int ret = 0;
if (attr_mask & IB_SRQ_MAX_WR) {
- struct rvt_rwq *owq;
+ struct rvt_krwq *okwq = NULL;
+ struct rvt_rwq *owq = NULL;
struct rvt_rwqe *p;
u32 sz, size, n, head, tail;
@@ -185,17 +183,12 @@ int rvt_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
((attr_mask & IB_SRQ_LIMIT) ?
attr->srq_limit : srq->limit) > attr->max_wr)
return -EINVAL;
-
sz = sizeof(struct rvt_rwqe) +
srq->rq.max_sge * sizeof(struct ib_sge);
size = attr->max_wr + 1;
- wq = udata ?
- vmalloc_user(sizeof(struct rvt_rwq) + size * sz) :
- vzalloc_node(sizeof(struct rvt_rwq) + size * sz,
- dev->dparms.node);
- if (!wq)
+ if (rvt_alloc_rq(&tmp_rq, size * sz, dev->dparms.node,
+ udata))
return -ENOMEM;
-
/* Check that we can write the offset to mmap. */
if (udata && udata->inlen >= sizeof(__u64)) {
__u64 offset_addr;
@@ -213,14 +206,20 @@ int rvt_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
goto bail_free;
}
- spin_lock_irq(&srq->rq.lock);
+ spin_lock_irq(&srq->rq.kwq->c_lock);
/*
* validate head and tail pointer values and compute
* the number of remaining WQEs.
*/
- owq = srq->rq.wq;
- head = owq->head;
- tail = owq->tail;
+ if (udata) {
+ owq = srq->rq.wq;
+ head = RDMA_READ_UAPI_ATOMIC(owq->head);
+ tail = RDMA_READ_UAPI_ATOMIC(owq->tail);
+ } else {
+ okwq = srq->rq.kwq;
+ head = okwq->head;
+ tail = okwq->tail;
+ }
if (head >= srq->rq.size || tail >= srq->rq.size) {
ret = -EINVAL;
goto bail_unlock;
@@ -235,7 +234,7 @@ int rvt_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
goto bail_unlock;
}
n = 0;
- p = wq->wq;
+ p = tmp_rq.kwq->curr_wq;
while (tail != head) {
struct rvt_rwqe *wqe;
int i;
@@ -250,22 +249,29 @@ int rvt_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
if (++tail >= srq->rq.size)
tail = 0;
}
- srq->rq.wq = wq;
+ srq->rq.kwq = tmp_rq.kwq;
+ if (udata) {
+ srq->rq.wq = tmp_rq.wq;
+ RDMA_WRITE_UAPI_ATOMIC(tmp_rq.wq->head, n);
+ RDMA_WRITE_UAPI_ATOMIC(tmp_rq.wq->tail, 0);
+ } else {
+ tmp_rq.kwq->head = n;
+ tmp_rq.kwq->tail = 0;
+ }
srq->rq.size = size;
- wq->head = n;
- wq->tail = 0;
if (attr_mask & IB_SRQ_LIMIT)
srq->limit = attr->srq_limit;
- spin_unlock_irq(&srq->rq.lock);
+ spin_unlock_irq(&srq->rq.kwq->c_lock);
vfree(owq);
+ kvfree(okwq);
if (srq->ip) {
struct rvt_mmap_info *ip = srq->ip;
struct rvt_dev_info *dev = ib_to_rvt(srq->ibsrq.device);
u32 s = sizeof(struct rvt_rwq) + size * sz;
- rvt_update_mmap_info(dev, ip, s, wq);
+ rvt_update_mmap_info(dev, ip, s, tmp_rq.wq);
/*
* Return the offset to mmap.
@@ -289,19 +295,19 @@ int rvt_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
spin_unlock_irq(&dev->pending_lock);
}
} else if (attr_mask & IB_SRQ_LIMIT) {
- spin_lock_irq(&srq->rq.lock);
+ spin_lock_irq(&srq->rq.kwq->c_lock);
if (attr->srq_limit >= srq->rq.size)
ret = -EINVAL;
else
srq->limit = attr->srq_limit;
- spin_unlock_irq(&srq->rq.lock);
+ spin_unlock_irq(&srq->rq.kwq->c_lock);
}
return ret;
bail_unlock:
- spin_unlock_irq(&srq->rq.lock);
+ spin_unlock_irq(&srq->rq.kwq->c_lock);
bail_free:
- vfree(wq);
+ rvt_free_rq(&tmp_rq);
return ret;
}
@@ -336,6 +342,5 @@ void rvt_destroy_srq(struct ib_srq *ibsrq, struct ib_udata *udata)
spin_unlock(&dev->n_srqs_lock);
if (srq->ip)
kref_put(&srq->ip->ref, rvt_release_mmap_info);
- else
- vfree(srq->rq.wq);
+ kvfree(srq->rq.kwq);
}
diff --git a/drivers/infiniband/sw/rdmavt/trace_mr.h b/drivers/infiniband/sw/rdmavt/trace_mr.h
index 976e482930a3..95b8a0e3b8bd 100644
--- a/drivers/infiniband/sw/rdmavt/trace_mr.h
+++ b/drivers/infiniband/sw/rdmavt/trace_mr.h
@@ -54,6 +54,8 @@
#include <rdma/rdma_vt.h>
#include <rdma/rdmavt_mr.h>
+#include "mr.h"
+
#undef TRACE_SYSTEM
#define TRACE_SYSTEM rvt_mr
DECLARE_EVENT_CLASS(
@@ -64,8 +66,12 @@ DECLARE_EVENT_CLASS(
RDI_DEV_ENTRY(ib_to_rvt(mr->pd->device))
__field(void *, vaddr)
__field(struct page *, page)
+ __field(u64, iova)
+ __field(u64, user_base)
__field(size_t, len)
+ __field(size_t, length)
__field(u32, lkey)
+ __field(u32, offset)
__field(u16, m)
__field(u16, n)
),
@@ -73,18 +79,28 @@ DECLARE_EVENT_CLASS(
RDI_DEV_ASSIGN(ib_to_rvt(mr->pd->device));
__entry->vaddr = v;
__entry->page = virt_to_page(v);
+ __entry->iova = mr->iova;
+ __entry->user_base = mr->user_base;
+ __entry->lkey = mr->lkey;
__entry->m = m;
__entry->n = n;
__entry->len = len;
+ __entry->length = mr->length;
+ __entry->offset = mr->offset;
),
TP_printk(
- "[%s] vaddr %p page %p m %u n %u len %ld",
+ "[%s] lkey %x iova %llx user_base %llx mr_len %lu vaddr %llx page %p m %u n %u len %lu off %u",
__get_str(dev),
- __entry->vaddr,
+ __entry->lkey,
+ __entry->iova,
+ __entry->user_base,
+ __entry->length,
+ (unsigned long long)__entry->vaddr,
__entry->page,
__entry->m,
__entry->n,
- __entry->len
+ __entry->len,
+ __entry->offset
)
);
@@ -165,6 +181,40 @@ DEFINE_EVENT(
TP_PROTO(struct rvt_sge *sge, struct ib_sge *isge),
TP_ARGS(sge, isge));
+TRACE_EVENT(
+ rvt_map_mr_sg,
+ TP_PROTO(struct ib_mr *ibmr, int sg_nents, unsigned int *sg_offset),
+ TP_ARGS(ibmr, sg_nents, sg_offset),
+ TP_STRUCT__entry(
+ RDI_DEV_ENTRY(ib_to_rvt(to_imr(ibmr)->mr.pd->device))
+ __field(u64, iova)
+ __field(u64, ibmr_iova)
+ __field(u64, user_base)
+ __field(u64, ibmr_length)
+ __field(int, sg_nents)
+ __field(uint, sg_offset)
+ ),
+ TP_fast_assign(
+ RDI_DEV_ASSIGN(ib_to_rvt(to_imr(ibmr)->mr.pd->device))
+ __entry->ibmr_iova = ibmr->iova;
+ __entry->iova = to_imr(ibmr)->mr.iova;
+ __entry->user_base = to_imr(ibmr)->mr.user_base;
+ __entry->ibmr_length = to_imr(ibmr)->mr.length;
+ __entry->sg_nents = sg_nents;
+ __entry->sg_offset = sg_offset ? *sg_offset : 0;
+ ),
+ TP_printk(
+ "[%s] ibmr_iova %llx iova %llx user_base %llx length %llx sg_nents %d sg_offset %u",
+ __get_str(dev),
+ __entry->ibmr_iova,
+ __entry->iova,
+ __entry->user_base,
+ __entry->ibmr_length,
+ __entry->sg_nents,
+ __entry->sg_offset
+ )
+);
+
#endif /* __RVT_TRACE_MR_H */
#undef TRACE_INCLUDE_PATH
diff --git a/drivers/infiniband/sw/rdmavt/vt.c b/drivers/infiniband/sw/rdmavt/vt.c
index 9546a837a8ac..18da1e1ea979 100644
--- a/drivers/infiniband/sw/rdmavt/vt.c
+++ b/drivers/infiniband/sw/rdmavt/vt.c
@@ -382,6 +382,8 @@ enum {
};
static const struct ib_device_ops rvt_dev_ops = {
+ .uverbs_abi_ver = RVT_UVERBS_ABI_VERSION,
+
.alloc_fmr = rvt_alloc_fmr,
.alloc_mr = rvt_alloc_mr,
.alloc_pd = rvt_alloc_pd,
@@ -427,6 +429,7 @@ static const struct ib_device_ops rvt_dev_ops = {
.unmap_fmr = rvt_unmap_fmr,
INIT_RDMA_OBJ_SIZE(ib_ah, rvt_ah, ibah),
+ INIT_RDMA_OBJ_SIZE(ib_cq, rvt_cq, ibcq),
INIT_RDMA_OBJ_SIZE(ib_pd, rvt_pd, ibpd),
INIT_RDMA_OBJ_SIZE(ib_srq, rvt_srq, ibsrq),
INIT_RDMA_OBJ_SIZE(ib_ucontext, rvt_ucontext, ibucontext),
@@ -530,7 +533,7 @@ static noinline int check_support(struct rvt_dev_info *rdi, int verb)
*
* Return: 0 on success otherwise an errno.
*/
-int rvt_register_device(struct rvt_dev_info *rdi, u32 driver_id)
+int rvt_register_device(struct rvt_dev_info *rdi)
{
int ret = 0, i;
@@ -600,7 +603,6 @@ int rvt_register_device(struct rvt_dev_info *rdi, u32 driver_id)
* exactly which functions rdmavt supports, nor do they know the ABI
* version, so we do all of this sort of stuff here.
*/
- rdi->ibdev.uverbs_abi_ver = RVT_UVERBS_ABI_VERSION;
rdi->ibdev.uverbs_cmd_mask =
(1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
(1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |
@@ -636,7 +638,6 @@ int rvt_register_device(struct rvt_dev_info *rdi, u32 driver_id)
if (!rdi->ibdev.num_comp_vectors)
rdi->ibdev.num_comp_vectors = 1;
- rdi->ibdev.driver_id = driver_id;
/* We are now good to announce we exist */
ret = ib_register_device(&rdi->ibdev, dev_name(&rdi->ibdev.dev));
if (ret) {
diff --git a/drivers/infiniband/sw/rdmavt/vt.h b/drivers/infiniband/sw/rdmavt/vt.h
index 0675ea6c3872..d19ff817c2c7 100644
--- a/drivers/infiniband/sw/rdmavt/vt.h
+++ b/drivers/infiniband/sw/rdmavt/vt.h
@@ -78,6 +78,12 @@
fmt, \
##__VA_ARGS__)
+#define rvt_pr_err_ratelimited(rdi, fmt, ...) \
+ __rvt_pr_err_ratelimited((rdi)->driver_f.get_pci_dev(rdi), \
+ rvt_get_ibdev_name(rdi), \
+ fmt, \
+ ##__VA_ARGS__)
+
#define __rvt_pr_info(pdev, name, fmt, ...) \
dev_info(&pdev->dev, "%s: " fmt, name, ##__VA_ARGS__)
@@ -87,6 +93,9 @@
#define __rvt_pr_err(pdev, name, fmt, ...) \
dev_err(&pdev->dev, "%s: " fmt, name, ##__VA_ARGS__)
+#define __rvt_pr_err_ratelimited(pdev, name, fmt, ...) \
+ dev_err_ratelimited(&(pdev)->dev, "%s: " fmt, name, ##__VA_ARGS__)
+
static inline int ibport_num_to_idx(struct ib_device *ibdev, u8 port_num)
{
struct rvt_dev_info *rdi = ib_to_rvt(ibdev);
diff --git a/drivers/infiniband/sw/rxe/rxe_comp.c b/drivers/infiniband/sw/rxe/rxe_comp.c
index 00eb99d3df86..116cafc9afcf 100644
--- a/drivers/infiniband/sw/rxe/rxe_comp.c
+++ b/drivers/infiniband/sw/rxe/rxe_comp.c
@@ -558,7 +558,7 @@ int rxe_completer(void *arg)
{
struct rxe_qp *qp = (struct rxe_qp *)arg;
struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
- struct rxe_send_wqe *wqe = wqe;
+ struct rxe_send_wqe *wqe = NULL;
struct sk_buff *skb = NULL;
struct rxe_pkt_info *pkt = NULL;
enum comp_state state;
diff --git a/drivers/infiniband/sw/rxe/rxe_mr.c b/drivers/infiniband/sw/rxe/rxe_mr.c
index f501f72489d8..ea6a819b7167 100644
--- a/drivers/infiniband/sw/rxe/rxe_mr.c
+++ b/drivers/infiniband/sw/rxe/rxe_mr.c
@@ -96,8 +96,7 @@ void rxe_mem_cleanup(struct rxe_pool_entry *arg)
struct rxe_mem *mem = container_of(arg, typeof(*mem), pelem);
int i;
- if (mem->umem)
- ib_umem_release(mem->umem);
+ ib_umem_release(mem->umem);
if (mem->map) {
for (i = 0; i < mem->num_map; i++)
diff --git a/drivers/infiniband/sw/rxe/rxe_pool.c b/drivers/infiniband/sw/rxe/rxe_pool.c
index 56cf18af016a..fbcbac52290b 100644
--- a/drivers/infiniband/sw/rxe/rxe_pool.c
+++ b/drivers/infiniband/sw/rxe/rxe_pool.c
@@ -72,6 +72,7 @@ struct rxe_type_info rxe_type_info[RXE_NUM_TYPES] = {
[RXE_TYPE_CQ] = {
.name = "rxe-cq",
.size = sizeof(struct rxe_cq),
+ .flags = RXE_POOL_NO_ALLOC,
.cleanup = rxe_cq_cleanup,
},
[RXE_TYPE_MR] = {
diff --git a/drivers/infiniband/sw/rxe/rxe_resp.c b/drivers/infiniband/sw/rxe/rxe_resp.c
index aca9f60f9b21..1cbfbd98eb22 100644
--- a/drivers/infiniband/sw/rxe/rxe_resp.c
+++ b/drivers/infiniband/sw/rxe/rxe_resp.c
@@ -431,6 +431,7 @@ static enum resp_states check_rkey(struct rxe_qp *qp,
qp->resp.va = reth_va(pkt);
qp->resp.rkey = reth_rkey(pkt);
qp->resp.resid = reth_len(pkt);
+ qp->resp.length = reth_len(pkt);
}
access = (pkt->mask & RXE_READ_MASK) ? IB_ACCESS_REMOTE_READ
: IB_ACCESS_REMOTE_WRITE;
@@ -856,7 +857,9 @@ static enum resp_states do_complete(struct rxe_qp *qp,
pkt->mask & RXE_WRITE_MASK) ?
IB_WC_RECV_RDMA_WITH_IMM : IB_WC_RECV;
wc->vendor_err = 0;
- wc->byte_len = wqe->dma.length - wqe->dma.resid;
+ wc->byte_len = (pkt->mask & RXE_IMMDT_MASK &&
+ pkt->mask & RXE_WRITE_MASK) ?
+ qp->resp.length : wqe->dma.length - wqe->dma.resid;
/* fields after byte_len are different between kernel and user
* space
diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.c b/drivers/infiniband/sw/rxe/rxe_verbs.c
index 8c3e2a18cfe4..4ebdfcf4d33e 100644
--- a/drivers/infiniband/sw/rxe/rxe_verbs.c
+++ b/drivers/infiniband/sw/rxe/rxe_verbs.c
@@ -778,55 +778,43 @@ err1:
return err;
}
-static struct ib_cq *rxe_create_cq(struct ib_device *dev,
- const struct ib_cq_init_attr *attr,
- struct ib_udata *udata)
+static int rxe_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata)
{
int err;
+ struct ib_device *dev = ibcq->device;
struct rxe_dev *rxe = to_rdev(dev);
- struct rxe_cq *cq;
+ struct rxe_cq *cq = to_rcq(ibcq);
struct rxe_create_cq_resp __user *uresp = NULL;
if (udata) {
if (udata->outlen < sizeof(*uresp))
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
uresp = udata->outbuf;
}
if (attr->flags)
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
err = rxe_cq_chk_attr(rxe, NULL, attr->cqe, attr->comp_vector);
if (err)
- goto err1;
-
- cq = rxe_alloc(&rxe->cq_pool);
- if (!cq) {
- err = -ENOMEM;
- goto err1;
- }
+ return err;
err = rxe_cq_from_init(rxe, cq, attr->cqe, attr->comp_vector, udata,
uresp);
if (err)
- goto err2;
-
- return &cq->ibcq;
+ return err;
-err2:
- rxe_drop_ref(cq);
-err1:
- return ERR_PTR(err);
+ return rxe_add_to_pool(&rxe->cq_pool, &cq->pelem);
}
-static int rxe_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
+static void rxe_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
{
struct rxe_cq *cq = to_rcq(ibcq);
rxe_cq_disable(cq);
rxe_drop_ref(cq);
- return 0;
}
static int rxe_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
@@ -1111,6 +1099,10 @@ static int rxe_enable_driver(struct ib_device *ib_dev)
}
static const struct ib_device_ops rxe_dev_ops = {
+ .owner = THIS_MODULE,
+ .driver_id = RDMA_DRIVER_RXE,
+ .uverbs_abi_ver = RXE_UVERBS_ABI_VERSION,
+
.alloc_hw_stats = rxe_ib_alloc_hw_stats,
.alloc_mr = rxe_alloc_mr,
.alloc_pd = rxe_alloc_pd,
@@ -1157,6 +1149,7 @@ static const struct ib_device_ops rxe_dev_ops = {
.resize_cq = rxe_resize_cq,
INIT_RDMA_OBJ_SIZE(ib_ah, rxe_ah, ibah),
+ INIT_RDMA_OBJ_SIZE(ib_cq, rxe_cq, ibcq),
INIT_RDMA_OBJ_SIZE(ib_pd, rxe_pd, ibpd),
INIT_RDMA_OBJ_SIZE(ib_srq, rxe_srq, ibsrq),
INIT_RDMA_OBJ_SIZE(ib_ucontext, rxe_ucontext, ibuc),
@@ -1170,7 +1163,6 @@ int rxe_register_device(struct rxe_dev *rxe, const char *ibdev_name)
strlcpy(dev->node_desc, "rxe", sizeof(dev->node_desc));
- dev->owner = THIS_MODULE;
dev->node_type = RDMA_NODE_IB_CA;
dev->phys_port_cnt = 1;
dev->num_comp_vectors = num_possible_cpus();
@@ -1182,7 +1174,6 @@ int rxe_register_device(struct rxe_dev *rxe, const char *ibdev_name)
dma_coerce_mask_and_coherent(&dev->dev,
dma_get_required_mask(&dev->dev));
- dev->uverbs_abi_ver = RXE_UVERBS_ABI_VERSION;
dev->uverbs_cmd_mask = BIT_ULL(IB_USER_VERBS_CMD_GET_CONTEXT)
| BIT_ULL(IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL)
| BIT_ULL(IB_USER_VERBS_CMD_QUERY_DEVICE)
@@ -1230,7 +1221,6 @@ int rxe_register_device(struct rxe_dev *rxe, const char *ibdev_name)
rxe->tfm = tfm;
rdma_set_device_sysfs_group(dev, &rxe_attr_group);
- dev->driver_id = RDMA_DRIVER_RXE;
err = ib_register_device(dev, ibdev_name);
if (err)
pr_warn("%s failed with error %d\n", __func__, err);
diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.h b/drivers/infiniband/sw/rxe/rxe_verbs.h
index e8be7f44e3be..5c4b2239129c 100644
--- a/drivers/infiniband/sw/rxe/rxe_verbs.h
+++ b/drivers/infiniband/sw/rxe/rxe_verbs.h
@@ -85,8 +85,8 @@ struct rxe_cqe {
};
struct rxe_cq {
- struct rxe_pool_entry pelem;
struct ib_cq ibcq;
+ struct rxe_pool_entry pelem;
struct rxe_queue *queue;
spinlock_t cq_lock;
u8 notify;
@@ -213,6 +213,7 @@ struct rxe_resp_info {
struct rxe_mem *mr;
u32 resid;
u32 rkey;
+ u32 length;
u64 atomic_orig;
/* SRQ only */
diff --git a/drivers/infiniband/sw/siw/Kconfig b/drivers/infiniband/sw/siw/Kconfig
new file mode 100644
index 000000000000..dace276aea14
--- /dev/null
+++ b/drivers/infiniband/sw/siw/Kconfig
@@ -0,0 +1,18 @@
+config RDMA_SIW
+ tristate "Software RDMA over TCP/IP (iWARP) driver"
+ depends on INET && INFINIBAND && LIBCRC32C && 64BIT
+ select DMA_VIRT_OPS
+ help
+ This driver implements the iWARP RDMA transport over
+ the Linux TCP/IP network stack. It enables a system with a
+ standard Ethernet adapter to interoperate with a iWARP
+ adapter or with another system running the SIW driver.
+ (See also RXE which is a similar software driver for RoCE.)
+
+ The driver interfaces with the Linux RDMA stack and
+ implements both a kernel and user space RDMA verbs API.
+ The user space verbs API requires a support
+ library named libsiw which is loaded by the generic user
+ space verbs API, libibverbs. To implement RDMA over
+ TCP/IP, the driver further interfaces with the Linux
+ in-kernel TCP socket layer.
diff --git a/drivers/infiniband/sw/siw/Makefile b/drivers/infiniband/sw/siw/Makefile
new file mode 100644
index 000000000000..f5f7e3867889
--- /dev/null
+++ b/drivers/infiniband/sw/siw/Makefile
@@ -0,0 +1,11 @@
+obj-$(CONFIG_RDMA_SIW) += siw.o
+
+siw-y := \
+ siw_cm.o \
+ siw_cq.o \
+ siw_main.o \
+ siw_mem.o \
+ siw_qp.o \
+ siw_qp_tx.o \
+ siw_qp_rx.o \
+ siw_verbs.o
diff --git a/drivers/infiniband/sw/siw/iwarp.h b/drivers/infiniband/sw/siw/iwarp.h
new file mode 100644
index 000000000000..e8a04d9c89cb
--- /dev/null
+++ b/drivers/infiniband/sw/siw/iwarp.h
@@ -0,0 +1,380 @@
+/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
+
+/* Authors: Bernard Metzler <bmt@zurich.ibm.com> */
+/* Copyright (c) 2008-2019, IBM Corporation */
+
+#ifndef _IWARP_H
+#define _IWARP_H
+
+#include <rdma/rdma_user_cm.h> /* RDMA_MAX_PRIVATE_DATA */
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+#define RDMAP_VERSION 1
+#define DDP_VERSION 1
+#define MPA_REVISION_1 1
+#define MPA_REVISION_2 2
+#define MPA_MAX_PRIVDATA RDMA_MAX_PRIVATE_DATA
+#define MPA_KEY_REQ "MPA ID Req Frame"
+#define MPA_KEY_REP "MPA ID Rep Frame"
+#define MPA_IRD_ORD_MASK 0x3fff
+
+struct mpa_rr_params {
+ __be16 bits;
+ __be16 pd_len;
+};
+
+/*
+ * MPA request/response header bits & fields
+ */
+enum {
+ MPA_RR_FLAG_MARKERS = cpu_to_be16(0x8000),
+ MPA_RR_FLAG_CRC = cpu_to_be16(0x4000),
+ MPA_RR_FLAG_REJECT = cpu_to_be16(0x2000),
+ MPA_RR_FLAG_ENHANCED = cpu_to_be16(0x1000),
+ MPA_RR_FLAG_GSO_EXP = cpu_to_be16(0x0800),
+ MPA_RR_MASK_REVISION = cpu_to_be16(0x00ff)
+};
+
+/*
+ * MPA request/reply header
+ */
+struct mpa_rr {
+ __u8 key[16];
+ struct mpa_rr_params params;
+};
+
+static inline void __mpa_rr_set_revision(__be16 *bits, u8 rev)
+{
+ *bits = (*bits & ~MPA_RR_MASK_REVISION) |
+ (cpu_to_be16(rev) & MPA_RR_MASK_REVISION);
+}
+
+static inline u8 __mpa_rr_revision(__be16 mpa_rr_bits)
+{
+ __be16 rev = mpa_rr_bits & MPA_RR_MASK_REVISION;
+
+ return be16_to_cpu(rev);
+}
+
+enum mpa_v2_ctrl {
+ MPA_V2_PEER_TO_PEER = cpu_to_be16(0x8000),
+ MPA_V2_ZERO_LENGTH_RTR = cpu_to_be16(0x4000),
+ MPA_V2_RDMA_WRITE_RTR = cpu_to_be16(0x8000),
+ MPA_V2_RDMA_READ_RTR = cpu_to_be16(0x4000),
+ MPA_V2_RDMA_NO_RTR = cpu_to_be16(0x0000),
+ MPA_V2_MASK_IRD_ORD = cpu_to_be16(0x3fff)
+};
+
+struct mpa_v2_data {
+ __be16 ird;
+ __be16 ord;
+};
+
+struct mpa_marker {
+ __be16 rsvd;
+ __be16 fpdu_hmd; /* FPDU header-marker distance (= MPA's FPDUPTR) */
+};
+
+/*
+ * maximum MPA trailer
+ */
+struct mpa_trailer {
+ __u8 pad[4];
+ __be32 crc;
+};
+
+#define MPA_HDR_SIZE 2
+#define MPA_CRC_SIZE 4
+
+/*
+ * Common portion of iWARP headers (MPA, DDP, RDMAP)
+ * for any FPDU
+ */
+struct iwarp_ctrl {
+ __be16 mpa_len;
+ __be16 ddp_rdmap_ctrl;
+};
+
+/*
+ * DDP/RDMAP Hdr bits & fields
+ */
+enum {
+ DDP_FLAG_TAGGED = cpu_to_be16(0x8000),
+ DDP_FLAG_LAST = cpu_to_be16(0x4000),
+ DDP_MASK_RESERVED = cpu_to_be16(0x3C00),
+ DDP_MASK_VERSION = cpu_to_be16(0x0300),
+ RDMAP_MASK_VERSION = cpu_to_be16(0x00C0),
+ RDMAP_MASK_RESERVED = cpu_to_be16(0x0030),
+ RDMAP_MASK_OPCODE = cpu_to_be16(0x000f)
+};
+
+static inline u8 __ddp_get_version(struct iwarp_ctrl *ctrl)
+{
+ return be16_to_cpu(ctrl->ddp_rdmap_ctrl & DDP_MASK_VERSION) >> 8;
+}
+
+static inline void __ddp_set_version(struct iwarp_ctrl *ctrl, u8 version)
+{
+ ctrl->ddp_rdmap_ctrl =
+ (ctrl->ddp_rdmap_ctrl & ~DDP_MASK_VERSION) |
+ (cpu_to_be16((u16)version << 8) & DDP_MASK_VERSION);
+}
+
+static inline u8 __rdmap_get_version(struct iwarp_ctrl *ctrl)
+{
+ __be16 ver = ctrl->ddp_rdmap_ctrl & RDMAP_MASK_VERSION;
+
+ return be16_to_cpu(ver) >> 6;
+}
+
+static inline void __rdmap_set_version(struct iwarp_ctrl *ctrl, u8 version)
+{
+ ctrl->ddp_rdmap_ctrl = (ctrl->ddp_rdmap_ctrl & ~RDMAP_MASK_VERSION) |
+ (cpu_to_be16(version << 6) & RDMAP_MASK_VERSION);
+}
+
+static inline u8 __rdmap_get_opcode(struct iwarp_ctrl *ctrl)
+{
+ return be16_to_cpu(ctrl->ddp_rdmap_ctrl & RDMAP_MASK_OPCODE);
+}
+
+static inline void __rdmap_set_opcode(struct iwarp_ctrl *ctrl, u8 opcode)
+{
+ ctrl->ddp_rdmap_ctrl = (ctrl->ddp_rdmap_ctrl & ~RDMAP_MASK_OPCODE) |
+ (cpu_to_be16(opcode) & RDMAP_MASK_OPCODE);
+}
+
+struct iwarp_rdma_write {
+ struct iwarp_ctrl ctrl;
+ __be32 sink_stag;
+ __be64 sink_to;
+};
+
+struct iwarp_rdma_rreq {
+ struct iwarp_ctrl ctrl;
+ __be32 rsvd;
+ __be32 ddp_qn;
+ __be32 ddp_msn;
+ __be32 ddp_mo;
+ __be32 sink_stag;
+ __be64 sink_to;
+ __be32 read_size;
+ __be32 source_stag;
+ __be64 source_to;
+};
+
+struct iwarp_rdma_rresp {
+ struct iwarp_ctrl ctrl;
+ __be32 sink_stag;
+ __be64 sink_to;
+};
+
+struct iwarp_send {
+ struct iwarp_ctrl ctrl;
+ __be32 rsvd;
+ __be32 ddp_qn;
+ __be32 ddp_msn;
+ __be32 ddp_mo;
+};
+
+struct iwarp_send_inv {
+ struct iwarp_ctrl ctrl;
+ __be32 inval_stag;
+ __be32 ddp_qn;
+ __be32 ddp_msn;
+ __be32 ddp_mo;
+};
+
+struct iwarp_terminate {
+ struct iwarp_ctrl ctrl;
+ __be32 rsvd;
+ __be32 ddp_qn;
+ __be32 ddp_msn;
+ __be32 ddp_mo;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __be32 layer : 4;
+ __be32 etype : 4;
+ __be32 ecode : 8;
+ __be32 flag_m : 1;
+ __be32 flag_d : 1;
+ __be32 flag_r : 1;
+ __be32 reserved : 13;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ __be32 reserved : 13;
+ __be32 flag_r : 1;
+ __be32 flag_d : 1;
+ __be32 flag_m : 1;
+ __be32 ecode : 8;
+ __be32 etype : 4;
+ __be32 layer : 4;
+#else
+#error "undefined byte order"
+#endif
+};
+
+/*
+ * Terminate Hdr bits & fields
+ */
+enum {
+ TERM_MASK_LAYER = cpu_to_be32(0xf0000000),
+ TERM_MASK_ETYPE = cpu_to_be32(0x0f000000),
+ TERM_MASK_ECODE = cpu_to_be32(0x00ff0000),
+ TERM_FLAG_M = cpu_to_be32(0x00008000),
+ TERM_FLAG_D = cpu_to_be32(0x00004000),
+ TERM_FLAG_R = cpu_to_be32(0x00002000),
+ TERM_MASK_RESVD = cpu_to_be32(0x00001fff)
+};
+
+static inline u8 __rdmap_term_layer(struct iwarp_terminate *term)
+{
+ return term->layer;
+}
+
+static inline void __rdmap_term_set_layer(struct iwarp_terminate *term,
+ u8 layer)
+{
+ term->layer = layer & 0xf;
+}
+
+static inline u8 __rdmap_term_etype(struct iwarp_terminate *term)
+{
+ return term->etype;
+}
+
+static inline void __rdmap_term_set_etype(struct iwarp_terminate *term,
+ u8 etype)
+{
+ term->etype = etype & 0xf;
+}
+
+static inline u8 __rdmap_term_ecode(struct iwarp_terminate *term)
+{
+ return term->ecode;
+}
+
+static inline void __rdmap_term_set_ecode(struct iwarp_terminate *term,
+ u8 ecode)
+{
+ term->ecode = ecode;
+}
+
+/*
+ * Common portion of iWARP headers (MPA, DDP, RDMAP)
+ * for an FPDU carrying an untagged DDP segment
+ */
+struct iwarp_ctrl_untagged {
+ struct iwarp_ctrl ctrl;
+ __be32 rsvd;
+ __be32 ddp_qn;
+ __be32 ddp_msn;
+ __be32 ddp_mo;
+};
+
+/*
+ * Common portion of iWARP headers (MPA, DDP, RDMAP)
+ * for an FPDU carrying a tagged DDP segment
+ */
+struct iwarp_ctrl_tagged {
+ struct iwarp_ctrl ctrl;
+ __be32 ddp_stag;
+ __be64 ddp_to;
+};
+
+union iwarp_hdr {
+ struct iwarp_ctrl ctrl;
+ struct iwarp_ctrl_untagged c_untagged;
+ struct iwarp_ctrl_tagged c_tagged;
+ struct iwarp_rdma_write rwrite;
+ struct iwarp_rdma_rreq rreq;
+ struct iwarp_rdma_rresp rresp;
+ struct iwarp_terminate terminate;
+ struct iwarp_send send;
+ struct iwarp_send_inv send_inv;
+};
+
+enum term_elayer {
+ TERM_ERROR_LAYER_RDMAP = 0x00,
+ TERM_ERROR_LAYER_DDP = 0x01,
+ TERM_ERROR_LAYER_LLP = 0x02 /* eg., MPA */
+};
+
+enum ddp_etype {
+ DDP_ETYPE_CATASTROPHIC = 0x0,
+ DDP_ETYPE_TAGGED_BUF = 0x1,
+ DDP_ETYPE_UNTAGGED_BUF = 0x2,
+ DDP_ETYPE_RSVD = 0x3
+};
+
+enum ddp_ecode {
+ /* unspecified, set to zero */
+ DDP_ECODE_CATASTROPHIC = 0x00,
+ /* Tagged Buffer Errors */
+ DDP_ECODE_T_INVALID_STAG = 0x00,
+ DDP_ECODE_T_BASE_BOUNDS = 0x01,
+ DDP_ECODE_T_STAG_NOT_ASSOC = 0x02,
+ DDP_ECODE_T_TO_WRAP = 0x03,
+ DDP_ECODE_T_VERSION = 0x04,
+ /* Untagged Buffer Errors */
+ DDP_ECODE_UT_INVALID_QN = 0x01,
+ DDP_ECODE_UT_INVALID_MSN_NOBUF = 0x02,
+ DDP_ECODE_UT_INVALID_MSN_RANGE = 0x03,
+ DDP_ECODE_UT_INVALID_MO = 0x04,
+ DDP_ECODE_UT_MSG_TOOLONG = 0x05,
+ DDP_ECODE_UT_VERSION = 0x06
+};
+
+enum rdmap_untagged_qn {
+ RDMAP_UNTAGGED_QN_SEND = 0,
+ RDMAP_UNTAGGED_QN_RDMA_READ = 1,
+ RDMAP_UNTAGGED_QN_TERMINATE = 2,
+ RDMAP_UNTAGGED_QN_COUNT = 3
+};
+
+enum rdmap_etype {
+ RDMAP_ETYPE_CATASTROPHIC = 0x0,
+ RDMAP_ETYPE_REMOTE_PROTECTION = 0x1,
+ RDMAP_ETYPE_REMOTE_OPERATION = 0x2
+};
+
+enum rdmap_ecode {
+ RDMAP_ECODE_INVALID_STAG = 0x00,
+ RDMAP_ECODE_BASE_BOUNDS = 0x01,
+ RDMAP_ECODE_ACCESS_RIGHTS = 0x02,
+ RDMAP_ECODE_STAG_NOT_ASSOC = 0x03,
+ RDMAP_ECODE_TO_WRAP = 0x04,
+ RDMAP_ECODE_VERSION = 0x05,
+ RDMAP_ECODE_OPCODE = 0x06,
+ RDMAP_ECODE_CATASTROPHIC_STREAM = 0x07,
+ RDMAP_ECODE_CATASTROPHIC_GLOBAL = 0x08,
+ RDMAP_ECODE_CANNOT_INVALIDATE = 0x09,
+ RDMAP_ECODE_UNSPECIFIED = 0xff
+};
+
+enum llp_ecode {
+ LLP_ECODE_TCP_STREAM_LOST = 0x01, /* How to transfer this ?? */
+ LLP_ECODE_RECEIVED_CRC = 0x02,
+ LLP_ECODE_FPDU_START = 0x03,
+ LLP_ECODE_INVALID_REQ_RESP = 0x04,
+
+ /* Errors for Enhanced Connection Establishment only */
+ LLP_ECODE_LOCAL_CATASTROPHIC = 0x05,
+ LLP_ECODE_INSUFFICIENT_IRD = 0x06,
+ LLP_ECODE_NO_MATCHING_RTR = 0x07
+};
+
+enum llp_etype { LLP_ETYPE_MPA = 0x00 };
+
+enum rdma_opcode {
+ RDMAP_RDMA_WRITE = 0x0,
+ RDMAP_RDMA_READ_REQ = 0x1,
+ RDMAP_RDMA_READ_RESP = 0x2,
+ RDMAP_SEND = 0x3,
+ RDMAP_SEND_INVAL = 0x4,
+ RDMAP_SEND_SE = 0x5,
+ RDMAP_SEND_SE_INVAL = 0x6,
+ RDMAP_TERMINATE = 0x7,
+ RDMAP_NOT_SUPPORTED = RDMAP_TERMINATE + 1
+};
+
+#endif
diff --git a/drivers/infiniband/sw/siw/siw.h b/drivers/infiniband/sw/siw/siw.h
new file mode 100644
index 000000000000..03fd7b2f595f
--- /dev/null
+++ b/drivers/infiniband/sw/siw/siw.h
@@ -0,0 +1,745 @@
+/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
+
+/* Authors: Bernard Metzler <bmt@zurich.ibm.com> */
+/* Copyright (c) 2008-2019, IBM Corporation */
+
+#ifndef _SIW_H
+#define _SIW_H
+
+#include <rdma/ib_verbs.h>
+#include <linux/socket.h>
+#include <linux/skbuff.h>
+#include <crypto/hash.h>
+#include <linux/crc32.h>
+#include <linux/crc32c.h>
+
+#include <rdma/siw-abi.h>
+#include "iwarp.h"
+
+#define SIW_VENDOR_ID 0x626d74 /* ascii 'bmt' for now */
+#define SIW_VENDORT_PART_ID 0
+#define SIW_MAX_QP (1024 * 100)
+#define SIW_MAX_QP_WR (1024 * 32)
+#define SIW_MAX_ORD_QP 128
+#define SIW_MAX_IRD_QP 128
+#define SIW_MAX_SGE_PBL 256 /* max num sge's for PBL */
+#define SIW_MAX_SGE_RD 1 /* iwarp limitation. we could relax */
+#define SIW_MAX_CQ (1024 * 100)
+#define SIW_MAX_CQE (SIW_MAX_QP_WR * 100)
+#define SIW_MAX_MR (SIW_MAX_QP * 10)
+#define SIW_MAX_PD SIW_MAX_QP
+#define SIW_MAX_MW 0 /* to be set if MW's are supported */
+#define SIW_MAX_FMR SIW_MAX_MR
+#define SIW_MAX_SRQ SIW_MAX_QP
+#define SIW_MAX_SRQ_WR (SIW_MAX_QP_WR * 10)
+#define SIW_MAX_CONTEXT SIW_MAX_PD
+
+/* Min number of bytes for using zero copy transmit */
+#define SENDPAGE_THRESH PAGE_SIZE
+
+/* Maximum number of frames which can be send in one SQ processing */
+#define SQ_USER_MAXBURST 100
+
+/* Maximum number of consecutive IRQ elements which get served
+ * if SQ has pending work. Prevents starving local SQ processing
+ * by serving peer Read Requests.
+ */
+#define SIW_IRQ_MAXBURST_SQ_ACTIVE 4
+
+struct siw_dev_cap {
+ int max_qp;
+ int max_qp_wr;
+ int max_ord; /* max. outbound read queue depth */
+ int max_ird; /* max. inbound read queue depth */
+ int max_sge;
+ int max_sge_rd;
+ int max_cq;
+ int max_cqe;
+ int max_mr;
+ int max_pd;
+ int max_mw;
+ int max_fmr;
+ int max_srq;
+ int max_srq_wr;
+ int max_srq_sge;
+};
+
+struct siw_pd {
+ struct ib_pd base_pd;
+};
+
+struct siw_device {
+ struct ib_device base_dev;
+ struct net_device *netdev;
+ struct siw_dev_cap attrs;
+
+ u32 vendor_part_id;
+ int numa_node;
+
+ /* physical port state (only one port per device) */
+ enum ib_port_state state;
+
+ spinlock_t lock;
+
+ struct xarray qp_xa;
+ struct xarray mem_xa;
+
+ struct list_head cep_list;
+ struct list_head qp_list;
+
+ /* active objects statistics to enforce limits */
+ atomic_t num_qp;
+ atomic_t num_cq;
+ atomic_t num_pd;
+ atomic_t num_mr;
+ atomic_t num_srq;
+ atomic_t num_ctx;
+
+ struct work_struct netdev_down;
+};
+
+struct siw_uobj {
+ void *addr;
+ u32 size;
+};
+
+struct siw_ucontext {
+ struct ib_ucontext base_ucontext;
+ struct siw_device *sdev;
+
+ /* xarray of user mappable objects */
+ struct xarray xa;
+ u32 uobj_nextkey;
+};
+
+/*
+ * The RDMA core does not define LOCAL_READ access, which is always
+ * enabled implictely.
+ */
+#define IWARP_ACCESS_MASK \
+ (IB_ACCESS_LOCAL_WRITE | IB_ACCESS_REMOTE_WRITE | \
+ IB_ACCESS_REMOTE_READ)
+
+/*
+ * siw presentation of user memory registered as source
+ * or target of RDMA operations.
+ */
+
+struct siw_page_chunk {
+ struct page **plist;
+};
+
+struct siw_umem {
+ struct siw_page_chunk *page_chunk;
+ int num_pages;
+ bool writable;
+ u64 fp_addr; /* First page base address */
+ struct mm_struct *owning_mm;
+};
+
+struct siw_pble {
+ u64 addr; /* Address of assigned user buffer */
+ u64 size; /* Size of this entry */
+ u64 pbl_off; /* Total offset from start of PBL */
+};
+
+struct siw_pbl {
+ unsigned int num_buf;
+ unsigned int max_buf;
+ struct siw_pble pbe[1];
+};
+
+struct siw_mr;
+
+/*
+ * Generic memory representation for registered siw memory.
+ * Memory lookup always via higher 24 bit of STag (STag index).
+ */
+struct siw_mem {
+ struct siw_device *sdev;
+ struct kref ref;
+ u64 va; /* VA of memory */
+ u64 len; /* length of the memory buffer in bytes */
+ u32 stag; /* iWarp memory access steering tag */
+ u8 stag_valid; /* VALID or INVALID */
+ u8 is_pbl; /* PBL or user space mem */
+ u8 is_mw; /* Memory Region or Memory Window */
+ enum ib_access_flags perms; /* local/remote READ & WRITE */
+ union {
+ struct siw_umem *umem;
+ struct siw_pbl *pbl;
+ void *mem_obj;
+ };
+ struct ib_pd *pd;
+};
+
+struct siw_mr {
+ struct ib_mr base_mr;
+ struct siw_mem *mem;
+ struct rcu_head rcu;
+};
+
+/*
+ * Error codes for local or remote
+ * access to registered memory
+ */
+enum siw_access_state {
+ E_ACCESS_OK,
+ E_STAG_INVALID,
+ E_BASE_BOUNDS,
+ E_ACCESS_PERM,
+ E_PD_MISMATCH
+};
+
+enum siw_wr_state {
+ SIW_WR_IDLE,
+ SIW_WR_QUEUED, /* processing has not started yet */
+ SIW_WR_INPROGRESS /* initiated processing of the WR */
+};
+
+/* The WQE currently being processed (RX or TX) */
+struct siw_wqe {
+ /* Copy of applications SQE or RQE */
+ union {
+ struct siw_sqe sqe;
+ struct siw_rqe rqe;
+ };
+ struct siw_mem *mem[SIW_MAX_SGE]; /* per sge's resolved mem */
+ enum siw_wr_state wr_status;
+ enum siw_wc_status wc_status;
+ u32 bytes; /* total bytes to process */
+ u32 processed; /* bytes processed */
+};
+
+struct siw_cq {
+ struct ib_cq base_cq;
+ spinlock_t lock;
+ u64 *notify;
+ struct siw_cqe *queue;
+ u32 cq_put;
+ u32 cq_get;
+ u32 num_cqe;
+ bool kernel_verbs;
+ u32 xa_cq_index; /* mmap information for CQE array */
+ u32 id; /* For debugging only */
+};
+
+enum siw_qp_state {
+ SIW_QP_STATE_IDLE,
+ SIW_QP_STATE_RTR,
+ SIW_QP_STATE_RTS,
+ SIW_QP_STATE_CLOSING,
+ SIW_QP_STATE_TERMINATE,
+ SIW_QP_STATE_ERROR,
+ SIW_QP_STATE_COUNT
+};
+
+enum siw_qp_flags {
+ SIW_RDMA_BIND_ENABLED = (1 << 0),
+ SIW_RDMA_WRITE_ENABLED = (1 << 1),
+ SIW_RDMA_READ_ENABLED = (1 << 2),
+ SIW_SIGNAL_ALL_WR = (1 << 3),
+ SIW_MPA_CRC = (1 << 4),
+ SIW_QP_IN_DESTROY = (1 << 5)
+};
+
+enum siw_qp_attr_mask {
+ SIW_QP_ATTR_STATE = (1 << 0),
+ SIW_QP_ATTR_ACCESS_FLAGS = (1 << 1),
+ SIW_QP_ATTR_LLP_HANDLE = (1 << 2),
+ SIW_QP_ATTR_ORD = (1 << 3),
+ SIW_QP_ATTR_IRD = (1 << 4),
+ SIW_QP_ATTR_SQ_SIZE = (1 << 5),
+ SIW_QP_ATTR_RQ_SIZE = (1 << 6),
+ SIW_QP_ATTR_MPA = (1 << 7)
+};
+
+struct siw_srq {
+ struct ib_srq base_srq;
+ spinlock_t lock;
+ u32 max_sge;
+ u32 limit; /* low watermark for async event */
+ struct siw_rqe *recvq;
+ u32 rq_put;
+ u32 rq_get;
+ u32 num_rqe; /* max # of wqe's allowed */
+ u32 xa_srq_index; /* mmap information for SRQ array */
+ char armed; /* inform user if limit hit */
+ char kernel_verbs; /* '1' if kernel client */
+};
+
+struct siw_qp_attrs {
+ enum siw_qp_state state;
+ u32 sq_size;
+ u32 rq_size;
+ u32 orq_size;
+ u32 irq_size;
+ u32 sq_max_sges;
+ u32 rq_max_sges;
+ enum siw_qp_flags flags;
+
+ struct socket *sk;
+};
+
+enum siw_tx_ctx {
+ SIW_SEND_HDR, /* start or continue sending HDR */
+ SIW_SEND_DATA, /* start or continue sending DDP payload */
+ SIW_SEND_TRAILER, /* start or continue sending TRAILER */
+ SIW_SEND_SHORT_FPDU/* send whole FPDU hdr|data|trailer at once */
+};
+
+enum siw_rx_state {
+ SIW_GET_HDR, /* await new hdr or within hdr */
+ SIW_GET_DATA_START, /* start of inbound DDP payload */
+ SIW_GET_DATA_MORE, /* continuation of (misaligned) DDP payload */
+ SIW_GET_TRAILER/* await new trailer or within trailer */
+};
+
+struct siw_rx_stream {
+ struct sk_buff *skb;
+ int skb_new; /* pending unread bytes in skb */
+ int skb_offset; /* offset in skb */
+ int skb_copied; /* processed bytes in skb */
+
+ union iwarp_hdr hdr;
+ struct mpa_trailer trailer;
+
+ enum siw_rx_state state;
+
+ /*
+ * For each FPDU, main RX loop runs through 3 stages:
+ * Receiving protocol headers, placing DDP payload and receiving
+ * trailer information (CRC + possibly padding).
+ * Next two variables keep state on receive status of the
+ * current FPDU part (hdr, data, trailer).
+ */
+ int fpdu_part_rcvd; /* bytes in pkt part copied */
+ int fpdu_part_rem; /* bytes in pkt part not seen */
+
+ /*
+ * Next expected DDP MSN for each QN +
+ * expected steering tag +
+ * expected DDP tagget offset (all HBO)
+ */
+ u32 ddp_msn[RDMAP_UNTAGGED_QN_COUNT];
+ u32 ddp_stag;
+ u64 ddp_to;
+ u32 inval_stag; /* Stag to be invalidated */
+
+ struct shash_desc *mpa_crc_hd;
+ u8 rx_suspend : 1;
+ u8 pad : 2; /* # of pad bytes expected */
+ u8 rdmap_op : 4; /* opcode of current frame */
+};
+
+struct siw_rx_fpdu {
+ /*
+ * Local destination memory of inbound RDMA operation.
+ * Valid, according to wqe->wr_status
+ */
+ struct siw_wqe wqe_active;
+
+ unsigned int pbl_idx; /* Index into current PBL */
+ unsigned int sge_idx; /* current sge in rx */
+ unsigned int sge_off; /* already rcvd in curr. sge */
+
+ char first_ddp_seg; /* this is the first DDP seg */
+ char more_ddp_segs; /* more DDP segs expected */
+ u8 prev_rdmap_op : 4; /* opcode of prev frame */
+};
+
+/*
+ * Shorthands for short packets w/o payload
+ * to be transmitted more efficient.
+ */
+struct siw_send_pkt {
+ struct iwarp_send send;
+ __be32 crc;
+};
+
+struct siw_write_pkt {
+ struct iwarp_rdma_write write;
+ __be32 crc;
+};
+
+struct siw_rreq_pkt {
+ struct iwarp_rdma_rreq rreq;
+ __be32 crc;
+};
+
+struct siw_rresp_pkt {
+ struct iwarp_rdma_rresp rresp;
+ __be32 crc;
+};
+
+struct siw_iwarp_tx {
+ union {
+ union iwarp_hdr hdr;
+
+ /* Generic part of FPDU header */
+ struct iwarp_ctrl ctrl;
+ struct iwarp_ctrl_untagged c_untagged;
+ struct iwarp_ctrl_tagged c_tagged;
+
+ /* FPDU headers */
+ struct iwarp_rdma_write rwrite;
+ struct iwarp_rdma_rreq rreq;
+ struct iwarp_rdma_rresp rresp;
+ struct iwarp_terminate terminate;
+ struct iwarp_send send;
+ struct iwarp_send_inv send_inv;
+
+ /* complete short FPDUs */
+ struct siw_send_pkt send_pkt;
+ struct siw_write_pkt write_pkt;
+ struct siw_rreq_pkt rreq_pkt;
+ struct siw_rresp_pkt rresp_pkt;
+ } pkt;
+
+ struct mpa_trailer trailer;
+ /* DDP MSN for untagged messages */
+ u32 ddp_msn[RDMAP_UNTAGGED_QN_COUNT];
+
+ enum siw_tx_ctx state;
+ u16 ctrl_len; /* ddp+rdmap hdr */
+ u16 ctrl_sent;
+ int burst;
+ int bytes_unsent; /* ddp payload bytes */
+
+ struct shash_desc *mpa_crc_hd;
+
+ u8 do_crc : 1; /* do crc for segment */
+ u8 use_sendpage : 1; /* send w/o copy */
+ u8 tx_suspend : 1; /* stop sending DDP segs. */
+ u8 pad : 2; /* # pad in current fpdu */
+ u8 orq_fence : 1; /* ORQ full or Send fenced */
+ u8 in_syscall : 1; /* TX out of user context */
+ u8 zcopy_tx : 1; /* Use TCP_SENDPAGE if possible */
+ u8 gso_seg_limit; /* Maximum segments for GSO, 0 = unbound */
+
+ u16 fpdu_len; /* len of FPDU to tx */
+ unsigned int tcp_seglen; /* remaining tcp seg space */
+
+ struct siw_wqe wqe_active;
+
+ int pbl_idx; /* Index into current PBL */
+ int sge_idx; /* current sge in tx */
+ u32 sge_off; /* already sent in curr. sge */
+};
+
+struct siw_qp {
+ struct siw_device *sdev;
+ struct ib_qp *ib_qp;
+ struct kref ref;
+ u32 qp_num;
+ struct list_head devq;
+ int tx_cpu;
+ bool kernel_verbs;
+ struct siw_qp_attrs attrs;
+
+ struct siw_cep *cep;
+ struct rw_semaphore state_lock;
+
+ struct ib_pd *pd;
+ struct siw_cq *scq;
+ struct siw_cq *rcq;
+ struct siw_srq *srq;
+
+ struct siw_iwarp_tx tx_ctx; /* Transmit context */
+ spinlock_t sq_lock;
+ struct siw_sqe *sendq; /* send queue element array */
+ uint32_t sq_get; /* consumer index into sq array */
+ uint32_t sq_put; /* kernel prod. index into sq array */
+ struct llist_node tx_list;
+
+ struct siw_sqe *orq; /* outbound read queue element array */
+ spinlock_t orq_lock;
+ uint32_t orq_get; /* consumer index into orq array */
+ uint32_t orq_put; /* shared producer index for ORQ */
+
+ struct siw_rx_stream rx_stream;
+ struct siw_rx_fpdu *rx_fpdu;
+ struct siw_rx_fpdu rx_tagged;
+ struct siw_rx_fpdu rx_untagged;
+ spinlock_t rq_lock;
+ struct siw_rqe *recvq; /* recv queue element array */
+ uint32_t rq_get; /* consumer index into rq array */
+ uint32_t rq_put; /* kernel prod. index into rq array */
+
+ struct siw_sqe *irq; /* inbound read queue element array */
+ uint32_t irq_get; /* consumer index into irq array */
+ uint32_t irq_put; /* producer index into irq array */
+ int irq_burst;
+
+ struct { /* information to be carried in TERMINATE pkt, if valid */
+ u8 valid;
+ u8 in_tx;
+ u8 layer : 4, etype : 4;
+ u8 ecode;
+ } term_info;
+ u32 xa_sq_index; /* mmap information for SQE array */
+ u32 xa_rq_index; /* mmap information for RQE array */
+ struct rcu_head rcu;
+};
+
+struct siw_base_qp {
+ struct ib_qp base_qp;
+ struct siw_qp *qp;
+};
+
+/* helper macros */
+#define rx_qp(rx) container_of(rx, struct siw_qp, rx_stream)
+#define tx_qp(tx) container_of(tx, struct siw_qp, tx_ctx)
+#define tx_wqe(qp) (&(qp)->tx_ctx.wqe_active)
+#define rx_wqe(rctx) (&(rctx)->wqe_active)
+#define rx_mem(rctx) ((rctx)->wqe_active.mem[0])
+#define tx_type(wqe) ((wqe)->sqe.opcode)
+#define rx_type(wqe) ((wqe)->rqe.opcode)
+#define tx_flags(wqe) ((wqe)->sqe.flags)
+
+struct iwarp_msg_info {
+ int hdr_len;
+ struct iwarp_ctrl ctrl;
+ int (*rx_data)(struct siw_qp *qp);
+};
+
+/* Global siw parameters. Currently set in siw_main.c */
+extern const bool zcopy_tx;
+extern const bool try_gso;
+extern const bool loopback_enabled;
+extern const bool mpa_crc_required;
+extern const bool mpa_crc_strict;
+extern const bool siw_tcp_nagle;
+extern u_char mpa_version;
+extern const bool peer_to_peer;
+extern struct task_struct *siw_tx_thread[];
+
+extern struct crypto_shash *siw_crypto_shash;
+extern struct iwarp_msg_info iwarp_pktinfo[RDMAP_TERMINATE + 1];
+
+/* QP general functions */
+int siw_qp_modify(struct siw_qp *qp, struct siw_qp_attrs *attr,
+ enum siw_qp_attr_mask mask);
+int siw_qp_mpa_rts(struct siw_qp *qp, enum mpa_v2_ctrl ctrl);
+void siw_qp_llp_close(struct siw_qp *qp);
+void siw_qp_cm_drop(struct siw_qp *qp, int schedule);
+void siw_send_terminate(struct siw_qp *qp);
+
+void siw_qp_get_ref(struct ib_qp *qp);
+void siw_qp_put_ref(struct ib_qp *qp);
+int siw_qp_add(struct siw_device *sdev, struct siw_qp *qp);
+void siw_free_qp(struct kref *ref);
+
+void siw_init_terminate(struct siw_qp *qp, enum term_elayer layer,
+ u8 etype, u8 ecode, int in_tx);
+enum ddp_ecode siw_tagged_error(enum siw_access_state state);
+enum rdmap_ecode siw_rdmap_error(enum siw_access_state state);
+
+void siw_read_to_orq(struct siw_sqe *rreq, struct siw_sqe *sqe);
+int siw_sqe_complete(struct siw_qp *qp, struct siw_sqe *sqe, u32 bytes,
+ enum siw_wc_status status);
+int siw_rqe_complete(struct siw_qp *qp, struct siw_rqe *rqe, u32 bytes,
+ u32 inval_stag, enum siw_wc_status status);
+void siw_qp_llp_data_ready(struct sock *sk);
+void siw_qp_llp_write_space(struct sock *sk);
+
+/* QP TX path functions */
+int siw_run_sq(void *arg);
+int siw_qp_sq_process(struct siw_qp *qp);
+int siw_sq_start(struct siw_qp *qp);
+int siw_activate_tx(struct siw_qp *qp);
+void siw_stop_tx_thread(int nr_cpu);
+int siw_get_tx_cpu(struct siw_device *sdev);
+void siw_put_tx_cpu(int cpu);
+
+/* QP RX path functions */
+int siw_proc_send(struct siw_qp *qp);
+int siw_proc_rreq(struct siw_qp *qp);
+int siw_proc_rresp(struct siw_qp *qp);
+int siw_proc_write(struct siw_qp *qp);
+int siw_proc_terminate(struct siw_qp *qp);
+
+int siw_tcp_rx_data(read_descriptor_t *rd_desc, struct sk_buff *skb,
+ unsigned int off, size_t len);
+
+static inline void set_rx_fpdu_context(struct siw_qp *qp, u8 opcode)
+{
+ if (opcode == RDMAP_RDMA_WRITE || opcode == RDMAP_RDMA_READ_RESP)
+ qp->rx_fpdu = &qp->rx_tagged;
+ else
+ qp->rx_fpdu = &qp->rx_untagged;
+
+ qp->rx_stream.rdmap_op = opcode;
+}
+
+static inline struct siw_ucontext *to_siw_ctx(struct ib_ucontext *base_ctx)
+{
+ return container_of(base_ctx, struct siw_ucontext, base_ucontext);
+}
+
+static inline struct siw_base_qp *to_siw_base_qp(struct ib_qp *base_qp)
+{
+ return container_of(base_qp, struct siw_base_qp, base_qp);
+}
+
+static inline struct siw_qp *to_siw_qp(struct ib_qp *base_qp)
+{
+ return to_siw_base_qp(base_qp)->qp;
+}
+
+static inline struct siw_cq *to_siw_cq(struct ib_cq *base_cq)
+{
+ return container_of(base_cq, struct siw_cq, base_cq);
+}
+
+static inline struct siw_srq *to_siw_srq(struct ib_srq *base_srq)
+{
+ return container_of(base_srq, struct siw_srq, base_srq);
+}
+
+static inline struct siw_device *to_siw_dev(struct ib_device *base_dev)
+{
+ return container_of(base_dev, struct siw_device, base_dev);
+}
+
+static inline struct siw_mr *to_siw_mr(struct ib_mr *base_mr)
+{
+ return container_of(base_mr, struct siw_mr, base_mr);
+}
+
+static inline struct siw_qp *siw_qp_id2obj(struct siw_device *sdev, int id)
+{
+ struct siw_qp *qp;
+
+ rcu_read_lock();
+ qp = xa_load(&sdev->qp_xa, id);
+ if (likely(qp && kref_get_unless_zero(&qp->ref))) {
+ rcu_read_unlock();
+ return qp;
+ }
+ rcu_read_unlock();
+ return NULL;
+}
+
+static inline u32 qp_id(struct siw_qp *qp)
+{
+ return qp->qp_num;
+}
+
+static inline void siw_qp_get(struct siw_qp *qp)
+{
+ kref_get(&qp->ref);
+}
+
+static inline void siw_qp_put(struct siw_qp *qp)
+{
+ kref_put(&qp->ref, siw_free_qp);
+}
+
+static inline int siw_sq_empty(struct siw_qp *qp)
+{
+ struct siw_sqe *sqe = &qp->sendq[qp->sq_get % qp->attrs.sq_size];
+
+ return READ_ONCE(sqe->flags) == 0;
+}
+
+static inline struct siw_sqe *sq_get_next(struct siw_qp *qp)
+{
+ struct siw_sqe *sqe = &qp->sendq[qp->sq_get % qp->attrs.sq_size];
+
+ if (READ_ONCE(sqe->flags) & SIW_WQE_VALID)
+ return sqe;
+
+ return NULL;
+}
+
+static inline struct siw_sqe *orq_get_current(struct siw_qp *qp)
+{
+ return &qp->orq[qp->orq_get % qp->attrs.orq_size];
+}
+
+static inline struct siw_sqe *orq_get_tail(struct siw_qp *qp)
+{
+ return &qp->orq[qp->orq_put % qp->attrs.orq_size];
+}
+
+static inline struct siw_sqe *orq_get_free(struct siw_qp *qp)
+{
+ struct siw_sqe *orq_e = orq_get_tail(qp);
+
+ if (orq_e && READ_ONCE(orq_e->flags) == 0)
+ return orq_e;
+
+ return NULL;
+}
+
+static inline int siw_orq_empty(struct siw_qp *qp)
+{
+ return qp->orq[qp->orq_get % qp->attrs.orq_size].flags == 0 ? 1 : 0;
+}
+
+static inline struct siw_sqe *irq_alloc_free(struct siw_qp *qp)
+{
+ struct siw_sqe *irq_e = &qp->irq[qp->irq_put % qp->attrs.irq_size];
+
+ if (READ_ONCE(irq_e->flags) == 0) {
+ qp->irq_put++;
+ return irq_e;
+ }
+ return NULL;
+}
+
+static inline __wsum siw_csum_update(const void *buff, int len, __wsum sum)
+{
+ return (__force __wsum)crc32c((__force __u32)sum, buff, len);
+}
+
+static inline __wsum siw_csum_combine(__wsum csum, __wsum csum2, int offset,
+ int len)
+{
+ return (__force __wsum)__crc32c_le_combine((__force __u32)csum,
+ (__force __u32)csum2, len);
+}
+
+static inline void siw_crc_skb(struct siw_rx_stream *srx, unsigned int len)
+{
+ const struct skb_checksum_ops siw_cs_ops = {
+ .update = siw_csum_update,
+ .combine = siw_csum_combine,
+ };
+ __wsum crc = *(u32 *)shash_desc_ctx(srx->mpa_crc_hd);
+
+ crc = __skb_checksum(srx->skb, srx->skb_offset, len, crc,
+ &siw_cs_ops);
+ *(u32 *)shash_desc_ctx(srx->mpa_crc_hd) = crc;
+}
+
+#define siw_dbg(ibdev, fmt, ...) \
+ ibdev_dbg(ibdev, "%s: " fmt, __func__, ##__VA_ARGS__)
+
+#define siw_dbg_qp(qp, fmt, ...) \
+ ibdev_dbg(&qp->sdev->base_dev, "QP[%u] %s: " fmt, qp_id(qp), __func__, \
+ ##__VA_ARGS__)
+
+#define siw_dbg_cq(cq, fmt, ...) \
+ ibdev_dbg(cq->base_cq.device, "CQ[%u] %s: " fmt, cq->id, __func__, \
+ ##__VA_ARGS__)
+
+#define siw_dbg_pd(pd, fmt, ...) \
+ ibdev_dbg(pd->device, "PD[%u] %s: " fmt, pd->res.id, __func__, \
+ ##__VA_ARGS__)
+
+#define siw_dbg_mem(mem, fmt, ...) \
+ ibdev_dbg(&mem->sdev->base_dev, \
+ "MEM[0x%08x] %s: " fmt, mem->stag, __func__, ##__VA_ARGS__)
+
+#define siw_dbg_cep(cep, fmt, ...) \
+ ibdev_dbg(&cep->sdev->base_dev, "CEP[0x%p] %s: " fmt, \
+ cep, __func__, ##__VA_ARGS__)
+
+void siw_cq_flush(struct siw_cq *cq);
+void siw_sq_flush(struct siw_qp *qp);
+void siw_rq_flush(struct siw_qp *qp);
+int siw_reap_cqe(struct siw_cq *cq, struct ib_wc *wc);
+
+#endif
diff --git a/drivers/infiniband/sw/siw/siw_cm.c b/drivers/infiniband/sw/siw/siw_cm.c
new file mode 100644
index 000000000000..a7cde98e73e8
--- /dev/null
+++ b/drivers/infiniband/sw/siw/siw_cm.c
@@ -0,0 +1,2070 @@
+// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause
+
+/* Authors: Bernard Metzler <bmt@zurich.ibm.com> */
+/* Fredy Neeser */
+/* Greg Joyce <greg@opengridcomputing.com> */
+/* Copyright (c) 2008-2019, IBM Corporation */
+/* Copyright (c) 2017, Open Grid Computing, Inc. */
+
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/net.h>
+#include <linux/inetdevice.h>
+#include <net/addrconf.h>
+#include <linux/workqueue.h>
+#include <net/sock.h>
+#include <net/tcp.h>
+#include <linux/inet.h>
+#include <linux/tcp.h>
+
+#include <rdma/iw_cm.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_user_verbs.h>
+
+#include "siw.h"
+#include "siw_cm.h"
+
+/*
+ * Set to any combination of
+ * MPA_V2_RDMA_NO_RTR, MPA_V2_RDMA_READ_RTR, MPA_V2_RDMA_WRITE_RTR
+ */
+static __be16 rtr_type = MPA_V2_RDMA_READ_RTR | MPA_V2_RDMA_WRITE_RTR;
+static const bool relaxed_ird_negotiation = 1;
+
+static void siw_cm_llp_state_change(struct sock *s);
+static void siw_cm_llp_data_ready(struct sock *s);
+static void siw_cm_llp_write_space(struct sock *s);
+static void siw_cm_llp_error_report(struct sock *s);
+static int siw_cm_upcall(struct siw_cep *cep, enum iw_cm_event_type reason,
+ int status);
+
+static void siw_sk_assign_cm_upcalls(struct sock *sk)
+{
+ write_lock_bh(&sk->sk_callback_lock);
+ sk->sk_state_change = siw_cm_llp_state_change;
+ sk->sk_data_ready = siw_cm_llp_data_ready;
+ sk->sk_write_space = siw_cm_llp_write_space;
+ sk->sk_error_report = siw_cm_llp_error_report;
+ write_unlock_bh(&sk->sk_callback_lock);
+}
+
+static void siw_sk_save_upcalls(struct sock *sk)
+{
+ struct siw_cep *cep = sk_to_cep(sk);
+
+ write_lock_bh(&sk->sk_callback_lock);
+ cep->sk_state_change = sk->sk_state_change;
+ cep->sk_data_ready = sk->sk_data_ready;
+ cep->sk_write_space = sk->sk_write_space;
+ cep->sk_error_report = sk->sk_error_report;
+ write_unlock_bh(&sk->sk_callback_lock);
+}
+
+static void siw_sk_restore_upcalls(struct sock *sk, struct siw_cep *cep)
+{
+ sk->sk_state_change = cep->sk_state_change;
+ sk->sk_data_ready = cep->sk_data_ready;
+ sk->sk_write_space = cep->sk_write_space;
+ sk->sk_error_report = cep->sk_error_report;
+ sk->sk_user_data = NULL;
+}
+
+static void siw_qp_socket_assoc(struct siw_cep *cep, struct siw_qp *qp)
+{
+ struct socket *s = cep->sock;
+ struct sock *sk = s->sk;
+
+ write_lock_bh(&sk->sk_callback_lock);
+
+ qp->attrs.sk = s;
+ sk->sk_data_ready = siw_qp_llp_data_ready;
+ sk->sk_write_space = siw_qp_llp_write_space;
+
+ write_unlock_bh(&sk->sk_callback_lock);
+}
+
+static void siw_socket_disassoc(struct socket *s)
+{
+ struct sock *sk = s->sk;
+ struct siw_cep *cep;
+
+ if (sk) {
+ write_lock_bh(&sk->sk_callback_lock);
+ cep = sk_to_cep(sk);
+ if (cep) {
+ siw_sk_restore_upcalls(sk, cep);
+ siw_cep_put(cep);
+ } else {
+ pr_warn("siw: cannot restore sk callbacks: no ep\n");
+ }
+ write_unlock_bh(&sk->sk_callback_lock);
+ } else {
+ pr_warn("siw: cannot restore sk callbacks: no sk\n");
+ }
+}
+
+static void siw_rtr_data_ready(struct sock *sk)
+{
+ struct siw_cep *cep;
+ struct siw_qp *qp = NULL;
+ read_descriptor_t rd_desc;
+
+ read_lock(&sk->sk_callback_lock);
+
+ cep = sk_to_cep(sk);
+ if (!cep) {
+ WARN(1, "No connection endpoint\n");
+ goto out;
+ }
+ qp = sk_to_qp(sk);
+
+ memset(&rd_desc, 0, sizeof(rd_desc));
+ rd_desc.arg.data = qp;
+ rd_desc.count = 1;
+
+ tcp_read_sock(sk, &rd_desc, siw_tcp_rx_data);
+ /*
+ * Check if first frame was successfully processed.
+ * Signal connection full establishment if yes.
+ * Failed data processing would have already scheduled
+ * connection drop.
+ */
+ if (!qp->rx_stream.rx_suspend)
+ siw_cm_upcall(cep, IW_CM_EVENT_ESTABLISHED, 0);
+out:
+ read_unlock(&sk->sk_callback_lock);
+ if (qp)
+ siw_qp_socket_assoc(cep, qp);
+}
+
+static void siw_sk_assign_rtr_upcalls(struct siw_cep *cep)
+{
+ struct sock *sk = cep->sock->sk;
+
+ write_lock_bh(&sk->sk_callback_lock);
+ sk->sk_data_ready = siw_rtr_data_ready;
+ sk->sk_write_space = siw_qp_llp_write_space;
+ write_unlock_bh(&sk->sk_callback_lock);
+}
+
+static void siw_cep_socket_assoc(struct siw_cep *cep, struct socket *s)
+{
+ cep->sock = s;
+ siw_cep_get(cep);
+ s->sk->sk_user_data = cep;
+
+ siw_sk_save_upcalls(s->sk);
+ siw_sk_assign_cm_upcalls(s->sk);
+}
+
+static struct siw_cep *siw_cep_alloc(struct siw_device *sdev)
+{
+ struct siw_cep *cep = kzalloc(sizeof(*cep), GFP_KERNEL);
+ unsigned long flags;
+
+ if (!cep)
+ return NULL;
+
+ INIT_LIST_HEAD(&cep->listenq);
+ INIT_LIST_HEAD(&cep->devq);
+ INIT_LIST_HEAD(&cep->work_freelist);
+
+ kref_init(&cep->ref);
+ cep->state = SIW_EPSTATE_IDLE;
+ init_waitqueue_head(&cep->waitq);
+ spin_lock_init(&cep->lock);
+ cep->sdev = sdev;
+ cep->enhanced_rdma_conn_est = false;
+
+ spin_lock_irqsave(&sdev->lock, flags);
+ list_add_tail(&cep->devq, &sdev->cep_list);
+ spin_unlock_irqrestore(&sdev->lock, flags);
+
+ siw_dbg_cep(cep, "new endpoint\n");
+ return cep;
+}
+
+static void siw_cm_free_work(struct siw_cep *cep)
+{
+ struct list_head *w, *tmp;
+ struct siw_cm_work *work;
+
+ list_for_each_safe(w, tmp, &cep->work_freelist) {
+ work = list_entry(w, struct siw_cm_work, list);
+ list_del(&work->list);
+ kfree(work);
+ }
+}
+
+static void siw_cancel_mpatimer(struct siw_cep *cep)
+{
+ spin_lock_bh(&cep->lock);
+ if (cep->mpa_timer) {
+ if (cancel_delayed_work(&cep->mpa_timer->work)) {
+ siw_cep_put(cep);
+ kfree(cep->mpa_timer); /* not needed again */
+ }
+ cep->mpa_timer = NULL;
+ }
+ spin_unlock_bh(&cep->lock);
+}
+
+static void siw_put_work(struct siw_cm_work *work)
+{
+ INIT_LIST_HEAD(&work->list);
+ spin_lock_bh(&work->cep->lock);
+ list_add(&work->list, &work->cep->work_freelist);
+ spin_unlock_bh(&work->cep->lock);
+}
+
+static void siw_cep_set_inuse(struct siw_cep *cep)
+{
+ unsigned long flags;
+ int rv;
+retry:
+ spin_lock_irqsave(&cep->lock, flags);
+
+ if (cep->in_use) {
+ spin_unlock_irqrestore(&cep->lock, flags);
+ rv = wait_event_interruptible(cep->waitq, !cep->in_use);
+ if (signal_pending(current))
+ flush_signals(current);
+ goto retry;
+ } else {
+ cep->in_use = 1;
+ spin_unlock_irqrestore(&cep->lock, flags);
+ }
+}
+
+static void siw_cep_set_free(struct siw_cep *cep)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cep->lock, flags);
+ cep->in_use = 0;
+ spin_unlock_irqrestore(&cep->lock, flags);
+
+ wake_up(&cep->waitq);
+}
+
+static void __siw_cep_dealloc(struct kref *ref)
+{
+ struct siw_cep *cep = container_of(ref, struct siw_cep, ref);
+ struct siw_device *sdev = cep->sdev;
+ unsigned long flags;
+
+ WARN_ON(cep->listen_cep);
+
+ /* kfree(NULL) is safe */
+ kfree(cep->mpa.pdata);
+ spin_lock_bh(&cep->lock);
+ if (!list_empty(&cep->work_freelist))
+ siw_cm_free_work(cep);
+ spin_unlock_bh(&cep->lock);
+
+ spin_lock_irqsave(&sdev->lock, flags);
+ list_del(&cep->devq);
+ spin_unlock_irqrestore(&sdev->lock, flags);
+
+ siw_dbg_cep(cep, "free endpoint\n");
+ kfree(cep);
+}
+
+static struct siw_cm_work *siw_get_work(struct siw_cep *cep)
+{
+ struct siw_cm_work *work = NULL;
+
+ spin_lock_bh(&cep->lock);
+ if (!list_empty(&cep->work_freelist)) {
+ work = list_entry(cep->work_freelist.next, struct siw_cm_work,
+ list);
+ list_del_init(&work->list);
+ }
+ spin_unlock_bh(&cep->lock);
+ return work;
+}
+
+static int siw_cm_alloc_work(struct siw_cep *cep, int num)
+{
+ struct siw_cm_work *work;
+
+ while (num--) {
+ work = kmalloc(sizeof(*work), GFP_KERNEL);
+ if (!work) {
+ if (!(list_empty(&cep->work_freelist)))
+ siw_cm_free_work(cep);
+ return -ENOMEM;
+ }
+ work->cep = cep;
+ INIT_LIST_HEAD(&work->list);
+ list_add(&work->list, &cep->work_freelist);
+ }
+ return 0;
+}
+
+/*
+ * siw_cm_upcall()
+ *
+ * Upcall to IWCM to inform about async connection events
+ */
+static int siw_cm_upcall(struct siw_cep *cep, enum iw_cm_event_type reason,
+ int status)
+{
+ struct iw_cm_event event;
+ struct iw_cm_id *id;
+
+ memset(&event, 0, sizeof(event));
+ event.status = status;
+ event.event = reason;
+
+ if (reason == IW_CM_EVENT_CONNECT_REQUEST) {
+ event.provider_data = cep;
+ id = cep->listen_cep->cm_id;
+ } else {
+ id = cep->cm_id;
+ }
+ /* Signal IRD and ORD */
+ if (reason == IW_CM_EVENT_ESTABLISHED ||
+ reason == IW_CM_EVENT_CONNECT_REPLY) {
+ /* Signal negotiated IRD/ORD values we will use */
+ event.ird = cep->ird;
+ event.ord = cep->ord;
+ } else if (reason == IW_CM_EVENT_CONNECT_REQUEST) {
+ event.ird = cep->ord;
+ event.ord = cep->ird;
+ }
+ /* Signal private data and address information */
+ if (reason == IW_CM_EVENT_CONNECT_REQUEST ||
+ reason == IW_CM_EVENT_CONNECT_REPLY) {
+ u16 pd_len = be16_to_cpu(cep->mpa.hdr.params.pd_len);
+
+ if (pd_len) {
+ /*
+ * hand over MPA private data
+ */
+ event.private_data_len = pd_len;
+ event.private_data = cep->mpa.pdata;
+
+ /* Hide MPA V2 IRD/ORD control */
+ if (cep->enhanced_rdma_conn_est) {
+ event.private_data_len -=
+ sizeof(struct mpa_v2_data);
+ event.private_data +=
+ sizeof(struct mpa_v2_data);
+ }
+ }
+ getname_local(cep->sock, &event.local_addr);
+ getname_peer(cep->sock, &event.remote_addr);
+ }
+ siw_dbg_cep(cep, "[QP %u]: id 0x%p, reason=%d, status=%d\n",
+ cep->qp ? qp_id(cep->qp) : -1, id, reason, status);
+
+ return id->event_handler(id, &event);
+}
+
+/*
+ * siw_qp_cm_drop()
+ *
+ * Drops established LLP connection if present and not already
+ * scheduled for dropping. Called from user context, SQ workqueue
+ * or receive IRQ. Caller signals if socket can be immediately
+ * closed (basically, if not in IRQ).
+ */
+void siw_qp_cm_drop(struct siw_qp *qp, int schedule)
+{
+ struct siw_cep *cep = qp->cep;
+
+ qp->rx_stream.rx_suspend = 1;
+ qp->tx_ctx.tx_suspend = 1;
+
+ if (!qp->cep)
+ return;
+
+ if (schedule) {
+ siw_cm_queue_work(cep, SIW_CM_WORK_CLOSE_LLP);
+ } else {
+ siw_cep_set_inuse(cep);
+
+ if (cep->state == SIW_EPSTATE_CLOSED) {
+ siw_dbg_cep(cep, "already closed\n");
+ goto out;
+ }
+ siw_dbg_cep(cep, "immediate close, state %d\n", cep->state);
+
+ if (qp->term_info.valid)
+ siw_send_terminate(qp);
+
+ if (cep->cm_id) {
+ switch (cep->state) {
+ case SIW_EPSTATE_AWAIT_MPAREP:
+ siw_cm_upcall(cep, IW_CM_EVENT_CONNECT_REPLY,
+ -EINVAL);
+ break;
+
+ case SIW_EPSTATE_RDMA_MODE:
+ siw_cm_upcall(cep, IW_CM_EVENT_CLOSE, 0);
+ break;
+
+ case SIW_EPSTATE_IDLE:
+ case SIW_EPSTATE_LISTENING:
+ case SIW_EPSTATE_CONNECTING:
+ case SIW_EPSTATE_AWAIT_MPAREQ:
+ case SIW_EPSTATE_RECVD_MPAREQ:
+ case SIW_EPSTATE_CLOSED:
+ default:
+ break;
+ }
+ cep->cm_id->rem_ref(cep->cm_id);
+ cep->cm_id = NULL;
+ siw_cep_put(cep);
+ }
+ cep->state = SIW_EPSTATE_CLOSED;
+
+ if (cep->sock) {
+ siw_socket_disassoc(cep->sock);
+ /*
+ * Immediately close socket
+ */
+ sock_release(cep->sock);
+ cep->sock = NULL;
+ }
+ if (cep->qp) {
+ cep->qp = NULL;
+ siw_qp_put(qp);
+ }
+out:
+ siw_cep_set_free(cep);
+ }
+}
+
+void siw_cep_put(struct siw_cep *cep)
+{
+ WARN_ON(kref_read(&cep->ref) < 1);
+ kref_put(&cep->ref, __siw_cep_dealloc);
+}
+
+void siw_cep_get(struct siw_cep *cep)
+{
+ kref_get(&cep->ref);
+}
+
+/*
+ * Expects params->pd_len in host byte order
+ */
+static int siw_send_mpareqrep(struct siw_cep *cep, const void *pdata, u8 pd_len)
+{
+ struct socket *s = cep->sock;
+ struct mpa_rr *rr = &cep->mpa.hdr;
+ struct kvec iov[3];
+ struct msghdr msg;
+ int rv;
+ int iovec_num = 0;
+ int mpa_len;
+
+ memset(&msg, 0, sizeof(msg));
+
+ iov[iovec_num].iov_base = rr;
+ iov[iovec_num].iov_len = sizeof(*rr);
+ mpa_len = sizeof(*rr);
+
+ if (cep->enhanced_rdma_conn_est) {
+ iovec_num++;
+ iov[iovec_num].iov_base = &cep->mpa.v2_ctrl;
+ iov[iovec_num].iov_len = sizeof(cep->mpa.v2_ctrl);
+ mpa_len += sizeof(cep->mpa.v2_ctrl);
+ }
+ if (pd_len) {
+ iovec_num++;
+ iov[iovec_num].iov_base = (char *)pdata;
+ iov[iovec_num].iov_len = pd_len;
+ mpa_len += pd_len;
+ }
+ if (cep->enhanced_rdma_conn_est)
+ pd_len += sizeof(cep->mpa.v2_ctrl);
+
+ rr->params.pd_len = cpu_to_be16(pd_len);
+
+ rv = kernel_sendmsg(s, &msg, iov, iovec_num + 1, mpa_len);
+
+ return rv < 0 ? rv : 0;
+}
+
+/*
+ * Receive MPA Request/Reply header.
+ *
+ * Returns 0 if complete MPA Request/Reply header including
+ * eventual private data was received. Returns -EAGAIN if
+ * header was partially received or negative error code otherwise.
+ *
+ * Context: May be called in process context only
+ */
+static int siw_recv_mpa_rr(struct siw_cep *cep)
+{
+ struct mpa_rr *hdr = &cep->mpa.hdr;
+ struct socket *s = cep->sock;
+ u16 pd_len;
+ int rcvd, to_rcv;
+
+ if (cep->mpa.bytes_rcvd < sizeof(struct mpa_rr)) {
+ rcvd = ksock_recv(s, (char *)hdr + cep->mpa.bytes_rcvd,
+ sizeof(struct mpa_rr) - cep->mpa.bytes_rcvd,
+ 0);
+ if (rcvd <= 0)
+ return -ECONNABORTED;
+
+ cep->mpa.bytes_rcvd += rcvd;
+
+ if (cep->mpa.bytes_rcvd < sizeof(struct mpa_rr))
+ return -EAGAIN;
+
+ if (be16_to_cpu(hdr->params.pd_len) > MPA_MAX_PRIVDATA)
+ return -EPROTO;
+ }
+ pd_len = be16_to_cpu(hdr->params.pd_len);
+
+ /*
+ * At least the MPA Request/Reply header (frame not including
+ * private data) has been received.
+ * Receive (or continue receiving) any private data.
+ */
+ to_rcv = pd_len - (cep->mpa.bytes_rcvd - sizeof(struct mpa_rr));
+
+ if (!to_rcv) {
+ /*
+ * We must have hdr->params.pd_len == 0 and thus received a
+ * complete MPA Request/Reply frame.
+ * Check against peer protocol violation.
+ */
+ u32 word;
+
+ rcvd = ksock_recv(s, (char *)&word, sizeof(word), MSG_DONTWAIT);
+ if (rcvd == -EAGAIN)
+ return 0;
+
+ if (rcvd == 0) {
+ siw_dbg_cep(cep, "peer EOF\n");
+ return -EPIPE;
+ }
+ if (rcvd < 0) {
+ siw_dbg_cep(cep, "error: %d\n", rcvd);
+ return rcvd;
+ }
+ siw_dbg_cep(cep, "peer sent extra data: %d\n", rcvd);
+
+ return -EPROTO;
+ }
+
+ /*
+ * At this point, we must have hdr->params.pd_len != 0.
+ * A private data buffer gets allocated if hdr->params.pd_len != 0.
+ */
+ if (!cep->mpa.pdata) {
+ cep->mpa.pdata = kmalloc(pd_len + 4, GFP_KERNEL);
+ if (!cep->mpa.pdata)
+ return -ENOMEM;
+ }
+ rcvd = ksock_recv(
+ s, cep->mpa.pdata + cep->mpa.bytes_rcvd - sizeof(struct mpa_rr),
+ to_rcv + 4, MSG_DONTWAIT);
+
+ if (rcvd < 0)
+ return rcvd;
+
+ if (rcvd > to_rcv)
+ return -EPROTO;
+
+ cep->mpa.bytes_rcvd += rcvd;
+
+ if (to_rcv == rcvd) {
+ siw_dbg_cep(cep, "%d bytes private data received\n", pd_len);
+ return 0;
+ }
+ return -EAGAIN;
+}
+
+/*
+ * siw_proc_mpareq()
+ *
+ * Read MPA Request from socket and signal new connection to IWCM
+ * if success. Caller must hold lock on corresponding listening CEP.
+ */
+static int siw_proc_mpareq(struct siw_cep *cep)
+{
+ struct mpa_rr *req;
+ int version, rv;
+ u16 pd_len;
+
+ rv = siw_recv_mpa_rr(cep);
+ if (rv)
+ return rv;
+
+ req = &cep->mpa.hdr;
+
+ version = __mpa_rr_revision(req->params.bits);
+ pd_len = be16_to_cpu(req->params.pd_len);
+
+ if (version > MPA_REVISION_2)
+ /* allow for 0, 1, and 2 only */
+ return -EPROTO;
+
+ if (memcmp(req->key, MPA_KEY_REQ, 16))
+ return -EPROTO;
+
+ /* Prepare for sending MPA reply */
+ memcpy(req->key, MPA_KEY_REP, 16);
+
+ if (version == MPA_REVISION_2 &&
+ (req->params.bits & MPA_RR_FLAG_ENHANCED)) {
+ /*
+ * MPA version 2 must signal IRD/ORD values and P2P mode
+ * in private data if header flag MPA_RR_FLAG_ENHANCED
+ * is set.
+ */
+ if (pd_len < sizeof(struct mpa_v2_data))
+ goto reject_conn;
+
+ cep->enhanced_rdma_conn_est = true;
+ }
+
+ /* MPA Markers: currently not supported. Marker TX to be added. */
+ if (req->params.bits & MPA_RR_FLAG_MARKERS)
+ goto reject_conn;
+
+ if (req->params.bits & MPA_RR_FLAG_CRC) {
+ /*
+ * RFC 5044, page 27: CRC MUST be used if peer requests it.
+ * siw specific: 'mpa_crc_strict' parameter to reject
+ * connection with CRC if local CRC off enforced by
+ * 'mpa_crc_strict' module parameter.
+ */
+ if (!mpa_crc_required && mpa_crc_strict)
+ goto reject_conn;
+
+ /* Enable CRC if requested by module parameter */
+ if (mpa_crc_required)
+ req->params.bits |= MPA_RR_FLAG_CRC;
+ }
+ if (cep->enhanced_rdma_conn_est) {
+ struct mpa_v2_data *v2 = (struct mpa_v2_data *)cep->mpa.pdata;
+
+ /*
+ * Peer requested ORD becomes requested local IRD,
+ * peer requested IRD becomes requested local ORD.
+ * IRD and ORD get limited by global maximum values.
+ */
+ cep->ord = ntohs(v2->ird) & MPA_IRD_ORD_MASK;
+ cep->ord = min(cep->ord, SIW_MAX_ORD_QP);
+ cep->ird = ntohs(v2->ord) & MPA_IRD_ORD_MASK;
+ cep->ird = min(cep->ird, SIW_MAX_IRD_QP);
+
+ /* May get overwritten by locally negotiated values */
+ cep->mpa.v2_ctrl.ird = htons(cep->ird);
+ cep->mpa.v2_ctrl.ord = htons(cep->ord);
+
+ /*
+ * Support for peer sent zero length Write or Read to
+ * let local side enter RTS. Writes are preferred.
+ * Sends would require pre-posting a Receive and are
+ * not supported.
+ * Propose zero length Write if none of Read and Write
+ * is indicated.
+ */
+ if (v2->ird & MPA_V2_PEER_TO_PEER) {
+ cep->mpa.v2_ctrl.ird |= MPA_V2_PEER_TO_PEER;
+
+ if (v2->ord & MPA_V2_RDMA_WRITE_RTR)
+ cep->mpa.v2_ctrl.ord |= MPA_V2_RDMA_WRITE_RTR;
+ else if (v2->ord & MPA_V2_RDMA_READ_RTR)
+ cep->mpa.v2_ctrl.ord |= MPA_V2_RDMA_READ_RTR;
+ else
+ cep->mpa.v2_ctrl.ord |= MPA_V2_RDMA_WRITE_RTR;
+ }
+ }
+
+ cep->state = SIW_EPSTATE_RECVD_MPAREQ;
+
+ /* Keep reference until IWCM accepts/rejects */
+ siw_cep_get(cep);
+ rv = siw_cm_upcall(cep, IW_CM_EVENT_CONNECT_REQUEST, 0);
+ if (rv)
+ siw_cep_put(cep);
+
+ return rv;
+
+reject_conn:
+ siw_dbg_cep(cep, "reject: crc %d:%d:%d, m %d:%d\n",
+ req->params.bits & MPA_RR_FLAG_CRC ? 1 : 0,
+ mpa_crc_required, mpa_crc_strict,
+ req->params.bits & MPA_RR_FLAG_MARKERS ? 1 : 0, 0);
+
+ req->params.bits &= ~MPA_RR_FLAG_MARKERS;
+ req->params.bits |= MPA_RR_FLAG_REJECT;
+
+ if (!mpa_crc_required && mpa_crc_strict)
+ req->params.bits &= ~MPA_RR_FLAG_CRC;
+
+ if (pd_len)
+ kfree(cep->mpa.pdata);
+
+ cep->mpa.pdata = NULL;
+
+ siw_send_mpareqrep(cep, NULL, 0);
+
+ return -EOPNOTSUPP;
+}
+
+static int siw_proc_mpareply(struct siw_cep *cep)
+{
+ struct siw_qp_attrs qp_attrs;
+ enum siw_qp_attr_mask qp_attr_mask;
+ struct siw_qp *qp = cep->qp;
+ struct mpa_rr *rep;
+ int rv;
+ u16 rep_ord;
+ u16 rep_ird;
+ bool ird_insufficient = false;
+ enum mpa_v2_ctrl mpa_p2p_mode = MPA_V2_RDMA_NO_RTR;
+
+ rv = siw_recv_mpa_rr(cep);
+ if (rv != -EAGAIN)
+ siw_cancel_mpatimer(cep);
+ if (rv)
+ goto out_err;
+
+ rep = &cep->mpa.hdr;
+
+ if (__mpa_rr_revision(rep->params.bits) > MPA_REVISION_2) {
+ /* allow for 0, 1, and 2 only */
+ rv = -EPROTO;
+ goto out_err;
+ }
+ if (memcmp(rep->key, MPA_KEY_REP, 16)) {
+ siw_init_terminate(qp, TERM_ERROR_LAYER_LLP, LLP_ETYPE_MPA,
+ LLP_ECODE_INVALID_REQ_RESP, 0);
+ siw_send_terminate(qp);
+ rv = -EPROTO;
+ goto out_err;
+ }
+ if (rep->params.bits & MPA_RR_FLAG_REJECT) {
+ siw_dbg_cep(cep, "got mpa reject\n");
+ siw_cm_upcall(cep, IW_CM_EVENT_CONNECT_REPLY, -ECONNRESET);
+
+ return -ECONNRESET;
+ }
+ if (try_gso && rep->params.bits & MPA_RR_FLAG_GSO_EXP) {
+ siw_dbg_cep(cep, "peer allows GSO on TX\n");
+ qp->tx_ctx.gso_seg_limit = 0;
+ }
+ if ((rep->params.bits & MPA_RR_FLAG_MARKERS) ||
+ (mpa_crc_required && !(rep->params.bits & MPA_RR_FLAG_CRC)) ||
+ (mpa_crc_strict && !mpa_crc_required &&
+ (rep->params.bits & MPA_RR_FLAG_CRC))) {
+ siw_dbg_cep(cep, "reply unsupp: crc %d:%d:%d, m %d:%d\n",
+ rep->params.bits & MPA_RR_FLAG_CRC ? 1 : 0,
+ mpa_crc_required, mpa_crc_strict,
+ rep->params.bits & MPA_RR_FLAG_MARKERS ? 1 : 0, 0);
+
+ siw_cm_upcall(cep, IW_CM_EVENT_CONNECT_REPLY, -ECONNREFUSED);
+
+ return -EINVAL;
+ }
+ if (cep->enhanced_rdma_conn_est) {
+ struct mpa_v2_data *v2;
+
+ if (__mpa_rr_revision(rep->params.bits) < MPA_REVISION_2 ||
+ !(rep->params.bits & MPA_RR_FLAG_ENHANCED)) {
+ /*
+ * Protocol failure: The responder MUST reply with
+ * MPA version 2 and MUST set MPA_RR_FLAG_ENHANCED.
+ */
+ siw_dbg_cep(cep, "mpa reply error: vers %d, enhcd %d\n",
+ __mpa_rr_revision(rep->params.bits),
+ rep->params.bits & MPA_RR_FLAG_ENHANCED ?
+ 1 :
+ 0);
+
+ siw_cm_upcall(cep, IW_CM_EVENT_CONNECT_REPLY,
+ -ECONNRESET);
+ return -EINVAL;
+ }
+ v2 = (struct mpa_v2_data *)cep->mpa.pdata;
+ rep_ird = ntohs(v2->ird) & MPA_IRD_ORD_MASK;
+ rep_ord = ntohs(v2->ord) & MPA_IRD_ORD_MASK;
+
+ if (cep->ird < rep_ord &&
+ (relaxed_ird_negotiation == false ||
+ rep_ord > cep->sdev->attrs.max_ird)) {
+ siw_dbg_cep(cep, "ird %d, rep_ord %d, max_ord %d\n",
+ cep->ird, rep_ord,
+ cep->sdev->attrs.max_ord);
+ ird_insufficient = true;
+ }
+ if (cep->ord > rep_ird && relaxed_ird_negotiation == false) {
+ siw_dbg_cep(cep, "ord %d, rep_ird %d\n", cep->ord,
+ rep_ird);
+ ird_insufficient = true;
+ }
+ /*
+ * Always report negotiated peer values to user,
+ * even if IRD/ORD negotiation failed
+ */
+ cep->ird = rep_ord;
+ cep->ord = rep_ird;
+
+ if (ird_insufficient) {
+ /*
+ * If the initiator IRD is insuffient for the
+ * responder ORD, send a TERM.
+ */
+ siw_init_terminate(qp, TERM_ERROR_LAYER_LLP,
+ LLP_ETYPE_MPA,
+ LLP_ECODE_INSUFFICIENT_IRD, 0);
+ siw_send_terminate(qp);
+ rv = -ENOMEM;
+ goto out_err;
+ }
+ if (cep->mpa.v2_ctrl_req.ird & MPA_V2_PEER_TO_PEER)
+ mpa_p2p_mode =
+ cep->mpa.v2_ctrl_req.ord &
+ (MPA_V2_RDMA_WRITE_RTR | MPA_V2_RDMA_READ_RTR);
+
+ /*
+ * Check if we requested P2P mode, and if peer agrees
+ */
+ if (mpa_p2p_mode != MPA_V2_RDMA_NO_RTR) {
+ if ((mpa_p2p_mode & v2->ord) == 0) {
+ /*
+ * We requested RTR mode(s), but the peer
+ * did not pick any mode we support.
+ */
+ siw_dbg_cep(cep,
+ "rtr mode: req %2x, got %2x\n",
+ mpa_p2p_mode,
+ v2->ord & (MPA_V2_RDMA_WRITE_RTR |
+ MPA_V2_RDMA_READ_RTR));
+
+ siw_init_terminate(qp, TERM_ERROR_LAYER_LLP,
+ LLP_ETYPE_MPA,
+ LLP_ECODE_NO_MATCHING_RTR,
+ 0);
+ siw_send_terminate(qp);
+ rv = -EPROTO;
+ goto out_err;
+ }
+ mpa_p2p_mode = v2->ord & (MPA_V2_RDMA_WRITE_RTR |
+ MPA_V2_RDMA_READ_RTR);
+ }
+ }
+ memset(&qp_attrs, 0, sizeof(qp_attrs));
+
+ if (rep->params.bits & MPA_RR_FLAG_CRC)
+ qp_attrs.flags = SIW_MPA_CRC;
+
+ qp_attrs.irq_size = cep->ird;
+ qp_attrs.orq_size = cep->ord;
+ qp_attrs.sk = cep->sock;
+ qp_attrs.state = SIW_QP_STATE_RTS;
+
+ qp_attr_mask = SIW_QP_ATTR_STATE | SIW_QP_ATTR_LLP_HANDLE |
+ SIW_QP_ATTR_ORD | SIW_QP_ATTR_IRD | SIW_QP_ATTR_MPA;
+
+ /* Move socket RX/TX under QP control */
+ down_write(&qp->state_lock);
+ if (qp->attrs.state > SIW_QP_STATE_RTR) {
+ rv = -EINVAL;
+ up_write(&qp->state_lock);
+ goto out_err;
+ }
+ rv = siw_qp_modify(qp, &qp_attrs, qp_attr_mask);
+
+ siw_qp_socket_assoc(cep, qp);
+
+ up_write(&qp->state_lock);
+
+ /* Send extra RDMA frame to trigger peer RTS if negotiated */
+ if (mpa_p2p_mode != MPA_V2_RDMA_NO_RTR) {
+ rv = siw_qp_mpa_rts(qp, mpa_p2p_mode);
+ if (rv)
+ goto out_err;
+ }
+ if (!rv) {
+ rv = siw_cm_upcall(cep, IW_CM_EVENT_CONNECT_REPLY, 0);
+ if (!rv)
+ cep->state = SIW_EPSTATE_RDMA_MODE;
+
+ return 0;
+ }
+
+out_err:
+ siw_cm_upcall(cep, IW_CM_EVENT_CONNECT_REPLY, -EINVAL);
+
+ return rv;
+}
+
+/*
+ * siw_accept_newconn - accept an incoming pending connection
+ *
+ */
+static void siw_accept_newconn(struct siw_cep *cep)
+{
+ struct socket *s = cep->sock;
+ struct socket *new_s = NULL;
+ struct siw_cep *new_cep = NULL;
+ int rv = 0; /* debug only. should disappear */
+
+ if (cep->state != SIW_EPSTATE_LISTENING)
+ goto error;
+
+ new_cep = siw_cep_alloc(cep->sdev);
+ if (!new_cep)
+ goto error;
+
+ /*
+ * 4: Allocate a sufficient number of work elements
+ * to allow concurrent handling of local + peer close
+ * events, MPA header processing + MPA timeout.
+ */
+ if (siw_cm_alloc_work(new_cep, 4) != 0)
+ goto error;
+
+ /*
+ * Copy saved socket callbacks from listening CEP
+ * and assign new socket with new CEP
+ */
+ new_cep->sk_state_change = cep->sk_state_change;
+ new_cep->sk_data_ready = cep->sk_data_ready;
+ new_cep->sk_write_space = cep->sk_write_space;
+ new_cep->sk_error_report = cep->sk_error_report;
+
+ rv = kernel_accept(s, &new_s, O_NONBLOCK);
+ if (rv != 0) {
+ /*
+ * Connection already aborted by peer..?
+ */
+ siw_dbg_cep(cep, "kernel_accept() error: %d\n", rv);
+ goto error;
+ }
+ new_cep->sock = new_s;
+ siw_cep_get(new_cep);
+ new_s->sk->sk_user_data = new_cep;
+
+ siw_dbg_cep(cep, "listen socket 0x%p, new 0x%p\n", s, new_s);
+
+ if (siw_tcp_nagle == false) {
+ int val = 1;
+
+ rv = kernel_setsockopt(new_s, SOL_TCP, TCP_NODELAY,
+ (char *)&val, sizeof(val));
+ if (rv) {
+ siw_dbg_cep(cep, "setsockopt NODELAY error: %d\n", rv);
+ goto error;
+ }
+ }
+ new_cep->state = SIW_EPSTATE_AWAIT_MPAREQ;
+
+ rv = siw_cm_queue_work(new_cep, SIW_CM_WORK_MPATIMEOUT);
+ if (rv)
+ goto error;
+ /*
+ * See siw_proc_mpareq() etc. for the use of new_cep->listen_cep.
+ */
+ new_cep->listen_cep = cep;
+ siw_cep_get(cep);
+
+ if (atomic_read(&new_s->sk->sk_rmem_alloc)) {
+ /*
+ * MPA REQ already queued
+ */
+ siw_dbg_cep(cep, "immediate mpa request\n");
+
+ siw_cep_set_inuse(new_cep);
+ rv = siw_proc_mpareq(new_cep);
+ siw_cep_set_free(new_cep);
+
+ if (rv != -EAGAIN) {
+ siw_cep_put(cep);
+ new_cep->listen_cep = NULL;
+ if (rv)
+ goto error;
+ }
+ }
+ return;
+
+error:
+ if (new_cep)
+ siw_cep_put(new_cep);
+
+ if (new_s) {
+ siw_socket_disassoc(new_s);
+ sock_release(new_s);
+ new_cep->sock = NULL;
+ }
+ siw_dbg_cep(cep, "error %d\n", rv);
+}
+
+static void siw_cm_work_handler(struct work_struct *w)
+{
+ struct siw_cm_work *work;
+ struct siw_cep *cep;
+ int release_cep = 0, rv = 0;
+
+ work = container_of(w, struct siw_cm_work, work.work);
+ cep = work->cep;
+
+ siw_dbg_cep(cep, "[QP %u]: work type: %d, state %d\n",
+ cep->qp ? qp_id(cep->qp) : -1, work->type, cep->state);
+
+ siw_cep_set_inuse(cep);
+
+ switch (work->type) {
+ case SIW_CM_WORK_ACCEPT:
+ siw_accept_newconn(cep);
+ break;
+
+ case SIW_CM_WORK_READ_MPAHDR:
+ if (cep->state == SIW_EPSTATE_AWAIT_MPAREQ) {
+ if (cep->listen_cep) {
+ siw_cep_set_inuse(cep->listen_cep);
+
+ if (cep->listen_cep->state ==
+ SIW_EPSTATE_LISTENING)
+ rv = siw_proc_mpareq(cep);
+ else
+ rv = -EFAULT;
+
+ siw_cep_set_free(cep->listen_cep);
+
+ if (rv != -EAGAIN) {
+ siw_cep_put(cep->listen_cep);
+ cep->listen_cep = NULL;
+ if (rv)
+ siw_cep_put(cep);
+ }
+ }
+ } else if (cep->state == SIW_EPSTATE_AWAIT_MPAREP) {
+ rv = siw_proc_mpareply(cep);
+ } else {
+ /*
+ * CEP already moved out of MPA handshake.
+ * any connection management already done.
+ * silently ignore the mpa packet.
+ */
+ if (cep->state == SIW_EPSTATE_RDMA_MODE) {
+ cep->sock->sk->sk_data_ready(cep->sock->sk);
+ siw_dbg_cep(cep, "already in RDMA mode");
+ } else {
+ siw_dbg_cep(cep, "out of state: %d\n",
+ cep->state);
+ }
+ }
+ if (rv && rv != EAGAIN)
+ release_cep = 1;
+ break;
+
+ case SIW_CM_WORK_CLOSE_LLP:
+ /*
+ * QP scheduled LLP close
+ */
+ if (cep->qp && cep->qp->term_info.valid)
+ siw_send_terminate(cep->qp);
+
+ if (cep->cm_id)
+ siw_cm_upcall(cep, IW_CM_EVENT_CLOSE, 0);
+
+ release_cep = 1;
+ break;
+
+ case SIW_CM_WORK_PEER_CLOSE:
+ if (cep->cm_id) {
+ if (cep->state == SIW_EPSTATE_AWAIT_MPAREP) {
+ /*
+ * MPA reply not received, but connection drop
+ */
+ siw_cm_upcall(cep, IW_CM_EVENT_CONNECT_REPLY,
+ -ECONNRESET);
+ } else if (cep->state == SIW_EPSTATE_RDMA_MODE) {
+ /*
+ * NOTE: IW_CM_EVENT_DISCONNECT is given just
+ * to transition IWCM into CLOSING.
+ */
+ siw_cm_upcall(cep, IW_CM_EVENT_DISCONNECT, 0);
+ siw_cm_upcall(cep, IW_CM_EVENT_CLOSE, 0);
+ }
+ /*
+ * for other states there is no connection
+ * known to the IWCM.
+ */
+ } else {
+ if (cep->state == SIW_EPSTATE_RECVD_MPAREQ) {
+ /*
+ * Wait for the ulp/CM to call accept/reject
+ */
+ siw_dbg_cep(cep,
+ "mpa req recvd, wait for ULP\n");
+ } else if (cep->state == SIW_EPSTATE_AWAIT_MPAREQ) {
+ /*
+ * Socket close before MPA request received.
+ */
+ siw_dbg_cep(cep, "no mpareq: drop listener\n");
+ siw_cep_put(cep->listen_cep);
+ cep->listen_cep = NULL;
+ }
+ }
+ release_cep = 1;
+ break;
+
+ case SIW_CM_WORK_MPATIMEOUT:
+ cep->mpa_timer = NULL;
+
+ if (cep->state == SIW_EPSTATE_AWAIT_MPAREP) {
+ /*
+ * MPA request timed out:
+ * Hide any partially received private data and signal
+ * timeout
+ */
+ cep->mpa.hdr.params.pd_len = 0;
+
+ if (cep->cm_id)
+ siw_cm_upcall(cep, IW_CM_EVENT_CONNECT_REPLY,
+ -ETIMEDOUT);
+ release_cep = 1;
+
+ } else if (cep->state == SIW_EPSTATE_AWAIT_MPAREQ) {
+ /*
+ * No MPA request received after peer TCP stream setup.
+ */
+ if (cep->listen_cep) {
+ siw_cep_put(cep->listen_cep);
+ cep->listen_cep = NULL;
+ }
+ release_cep = 1;
+ }
+ break;
+
+ default:
+ WARN(1, "Undefined CM work type: %d\n", work->type);
+ }
+ if (release_cep) {
+ siw_dbg_cep(cep,
+ "release: timer=%s, QP[%u], id 0x%p\n",
+ cep->mpa_timer ? "y" : "n",
+ cep->qp ? qp_id(cep->qp) : -1, cep->cm_id);
+
+ siw_cancel_mpatimer(cep);
+
+ cep->state = SIW_EPSTATE_CLOSED;
+
+ if (cep->qp) {
+ struct siw_qp *qp = cep->qp;
+ /*
+ * Serialize a potential race with application
+ * closing the QP and calling siw_qp_cm_drop()
+ */
+ siw_qp_get(qp);
+ siw_cep_set_free(cep);
+
+ siw_qp_llp_close(qp);
+ siw_qp_put(qp);
+
+ siw_cep_set_inuse(cep);
+ cep->qp = NULL;
+ siw_qp_put(qp);
+ }
+ if (cep->sock) {
+ siw_socket_disassoc(cep->sock);
+ sock_release(cep->sock);
+ cep->sock = NULL;
+ }
+ if (cep->cm_id) {
+ cep->cm_id->rem_ref(cep->cm_id);
+ cep->cm_id = NULL;
+ siw_cep_put(cep);
+ }
+ }
+ siw_cep_set_free(cep);
+ siw_put_work(work);
+ siw_cep_put(cep);
+}
+
+static struct workqueue_struct *siw_cm_wq;
+
+int siw_cm_queue_work(struct siw_cep *cep, enum siw_work_type type)
+{
+ struct siw_cm_work *work = siw_get_work(cep);
+ unsigned long delay = 0;
+
+ if (!work) {
+ siw_dbg_cep(cep, "failed with no work available\n");
+ return -ENOMEM;
+ }
+ work->type = type;
+ work->cep = cep;
+
+ siw_cep_get(cep);
+
+ INIT_DELAYED_WORK(&work->work, siw_cm_work_handler);
+
+ if (type == SIW_CM_WORK_MPATIMEOUT) {
+ cep->mpa_timer = work;
+
+ if (cep->state == SIW_EPSTATE_AWAIT_MPAREP)
+ delay = MPAREQ_TIMEOUT;
+ else
+ delay = MPAREP_TIMEOUT;
+ }
+ siw_dbg_cep(cep, "[QP %u]: work type: %d, work 0x%p, timeout %lu\n",
+ cep->qp ? qp_id(cep->qp) : -1, type, work, delay);
+
+ queue_delayed_work(siw_cm_wq, &work->work, delay);
+
+ return 0;
+}
+
+static void siw_cm_llp_data_ready(struct sock *sk)
+{
+ struct siw_cep *cep;
+
+ read_lock(&sk->sk_callback_lock);
+
+ cep = sk_to_cep(sk);
+ if (!cep) {
+ WARN_ON(1);
+ goto out;
+ }
+ siw_dbg_cep(cep, "state: %d\n", cep->state);
+
+ switch (cep->state) {
+ case SIW_EPSTATE_RDMA_MODE:
+ /* fall through */
+ case SIW_EPSTATE_LISTENING:
+ break;
+
+ case SIW_EPSTATE_AWAIT_MPAREQ:
+ /* fall through */
+ case SIW_EPSTATE_AWAIT_MPAREP:
+ siw_cm_queue_work(cep, SIW_CM_WORK_READ_MPAHDR);
+ break;
+
+ default:
+ siw_dbg_cep(cep, "unexpected data, state %d\n", cep->state);
+ break;
+ }
+out:
+ read_unlock(&sk->sk_callback_lock);
+}
+
+static void siw_cm_llp_write_space(struct sock *sk)
+{
+ struct siw_cep *cep = sk_to_cep(sk);
+
+ if (cep)
+ siw_dbg_cep(cep, "state: %d\n", cep->state);
+}
+
+static void siw_cm_llp_error_report(struct sock *sk)
+{
+ struct siw_cep *cep = sk_to_cep(sk);
+
+ if (cep) {
+ siw_dbg_cep(cep, "error %d, socket state: %d, cep state: %d\n",
+ sk->sk_err, sk->sk_state, cep->state);
+ cep->sk_error_report(sk);
+ }
+}
+
+static void siw_cm_llp_state_change(struct sock *sk)
+{
+ struct siw_cep *cep;
+ void (*orig_state_change)(struct sock *s);
+
+ read_lock(&sk->sk_callback_lock);
+
+ cep = sk_to_cep(sk);
+ if (!cep) {
+ /* endpoint already disassociated */
+ read_unlock(&sk->sk_callback_lock);
+ return;
+ }
+ orig_state_change = cep->sk_state_change;
+
+ siw_dbg_cep(cep, "state: %d\n", cep->state);
+
+ switch (sk->sk_state) {
+ case TCP_ESTABLISHED:
+ /*
+ * handle accepting socket as special case where only
+ * new connection is possible
+ */
+ siw_cm_queue_work(cep, SIW_CM_WORK_ACCEPT);
+ break;
+
+ case TCP_CLOSE:
+ case TCP_CLOSE_WAIT:
+ if (cep->qp)
+ cep->qp->tx_ctx.tx_suspend = 1;
+ siw_cm_queue_work(cep, SIW_CM_WORK_PEER_CLOSE);
+ break;
+
+ default:
+ siw_dbg_cep(cep, "unexpected socket state %d\n", sk->sk_state);
+ }
+ read_unlock(&sk->sk_callback_lock);
+ orig_state_change(sk);
+}
+
+static int kernel_bindconnect(struct socket *s, struct sockaddr *laddr,
+ struct sockaddr *raddr)
+{
+ int rv, flags = 0, s_val = 1;
+ size_t size = laddr->sa_family == AF_INET ?
+ sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
+
+ /*
+ * Make address available again asap.
+ */
+ rv = kernel_setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&s_val,
+ sizeof(s_val));
+ if (rv < 0)
+ return rv;
+
+ rv = s->ops->bind(s, laddr, size);
+ if (rv < 0)
+ return rv;
+
+ rv = s->ops->connect(s, raddr, size, flags);
+
+ return rv < 0 ? rv : 0;
+}
+
+int siw_connect(struct iw_cm_id *id, struct iw_cm_conn_param *params)
+{
+ struct siw_device *sdev = to_siw_dev(id->device);
+ struct siw_qp *qp;
+ struct siw_cep *cep = NULL;
+ struct socket *s = NULL;
+ struct sockaddr *laddr = (struct sockaddr *)&id->local_addr,
+ *raddr = (struct sockaddr *)&id->remote_addr;
+ bool p2p_mode = peer_to_peer, v4 = true;
+ u16 pd_len = params->private_data_len;
+ int version = mpa_version, rv;
+
+ if (pd_len > MPA_MAX_PRIVDATA)
+ return -EINVAL;
+
+ if (params->ird > sdev->attrs.max_ird ||
+ params->ord > sdev->attrs.max_ord)
+ return -ENOMEM;
+
+ if (laddr->sa_family == AF_INET6)
+ v4 = false;
+ else if (laddr->sa_family != AF_INET)
+ return -EAFNOSUPPORT;
+
+ /*
+ * Respect any iwarp port mapping: Use mapped remote address
+ * if valid. Local address must not be mapped, since siw
+ * uses kernel TCP stack.
+ */
+ if ((v4 && to_sockaddr_in(id->remote_addr).sin_port != 0) ||
+ to_sockaddr_in6(id->remote_addr).sin6_port != 0)
+ raddr = (struct sockaddr *)&id->m_remote_addr;
+
+ qp = siw_qp_id2obj(sdev, params->qpn);
+ if (!qp) {
+ WARN(1, "[QP %u] does not exist\n", params->qpn);
+ rv = -EINVAL;
+ goto error;
+ }
+ if (v4)
+ siw_dbg_qp(qp,
+ "id 0x%p, pd_len %d, laddr %pI4 %d, raddr %pI4 %d\n",
+ id, pd_len,
+ &((struct sockaddr_in *)(laddr))->sin_addr,
+ ntohs(((struct sockaddr_in *)(laddr))->sin_port),
+ &((struct sockaddr_in *)(raddr))->sin_addr,
+ ntohs(((struct sockaddr_in *)(raddr))->sin_port));
+ else
+ siw_dbg_qp(qp,
+ "id 0x%p, pd_len %d, laddr %pI6 %d, raddr %pI6 %d\n",
+ id, pd_len,
+ &((struct sockaddr_in6 *)(laddr))->sin6_addr,
+ ntohs(((struct sockaddr_in6 *)(laddr))->sin6_port),
+ &((struct sockaddr_in6 *)(raddr))->sin6_addr,
+ ntohs(((struct sockaddr_in6 *)(raddr))->sin6_port));
+
+ rv = sock_create(v4 ? AF_INET : AF_INET6, SOCK_STREAM, IPPROTO_TCP, &s);
+ if (rv < 0)
+ goto error;
+
+ /*
+ * NOTE: For simplification, connect() is called in blocking
+ * mode. Might be reconsidered for async connection setup at
+ * TCP level.
+ */
+ rv = kernel_bindconnect(s, laddr, raddr);
+ if (rv != 0) {
+ siw_dbg_qp(qp, "kernel_bindconnect: error %d\n", rv);
+ goto error;
+ }
+ if (siw_tcp_nagle == false) {
+ int val = 1;
+
+ rv = kernel_setsockopt(s, SOL_TCP, TCP_NODELAY, (char *)&val,
+ sizeof(val));
+ if (rv) {
+ siw_dbg_qp(qp, "setsockopt NODELAY error: %d\n", rv);
+ goto error;
+ }
+ }
+ cep = siw_cep_alloc(sdev);
+ if (!cep) {
+ rv = -ENOMEM;
+ goto error;
+ }
+ siw_cep_set_inuse(cep);
+
+ /* Associate QP with CEP */
+ siw_cep_get(cep);
+ qp->cep = cep;
+
+ /* siw_qp_get(qp) already done by QP lookup */
+ cep->qp = qp;
+
+ id->add_ref(id);
+ cep->cm_id = id;
+
+ /*
+ * 4: Allocate a sufficient number of work elements
+ * to allow concurrent handling of local + peer close
+ * events, MPA header processing + MPA timeout.
+ */
+ rv = siw_cm_alloc_work(cep, 4);
+ if (rv != 0) {
+ rv = -ENOMEM;
+ goto error;
+ }
+ cep->ird = params->ird;
+ cep->ord = params->ord;
+
+ if (p2p_mode && cep->ord == 0)
+ cep->ord = 1;
+
+ cep->state = SIW_EPSTATE_CONNECTING;
+
+ /*
+ * Associate CEP with socket
+ */
+ siw_cep_socket_assoc(cep, s);
+
+ cep->state = SIW_EPSTATE_AWAIT_MPAREP;
+
+ /*
+ * Set MPA Request bits: CRC if required, no MPA Markers,
+ * MPA Rev. according to module parameter 'mpa_version', Key 'Request'.
+ */
+ cep->mpa.hdr.params.bits = 0;
+ if (version > MPA_REVISION_2) {
+ pr_warn("Setting MPA version to %u\n", MPA_REVISION_2);
+ version = MPA_REVISION_2;
+ /* Adjust also module parameter */
+ mpa_version = MPA_REVISION_2;
+ }
+ __mpa_rr_set_revision(&cep->mpa.hdr.params.bits, version);
+
+ if (try_gso)
+ cep->mpa.hdr.params.bits |= MPA_RR_FLAG_GSO_EXP;
+
+ if (mpa_crc_required)
+ cep->mpa.hdr.params.bits |= MPA_RR_FLAG_CRC;
+
+ /*
+ * If MPA version == 2:
+ * o Include ORD and IRD.
+ * o Indicate peer-to-peer mode, if required by module
+ * parameter 'peer_to_peer'.
+ */
+ if (version == MPA_REVISION_2) {
+ cep->enhanced_rdma_conn_est = true;
+ cep->mpa.hdr.params.bits |= MPA_RR_FLAG_ENHANCED;
+
+ cep->mpa.v2_ctrl.ird = htons(cep->ird);
+ cep->mpa.v2_ctrl.ord = htons(cep->ord);
+
+ if (p2p_mode) {
+ cep->mpa.v2_ctrl.ird |= MPA_V2_PEER_TO_PEER;
+ cep->mpa.v2_ctrl.ord |= rtr_type;
+ }
+ /* Remember own P2P mode requested */
+ cep->mpa.v2_ctrl_req.ird = cep->mpa.v2_ctrl.ird;
+ cep->mpa.v2_ctrl_req.ord = cep->mpa.v2_ctrl.ord;
+ }
+ memcpy(cep->mpa.hdr.key, MPA_KEY_REQ, 16);
+
+ rv = siw_send_mpareqrep(cep, params->private_data, pd_len);
+ /*
+ * Reset private data.
+ */
+ cep->mpa.hdr.params.pd_len = 0;
+
+ if (rv >= 0) {
+ rv = siw_cm_queue_work(cep, SIW_CM_WORK_MPATIMEOUT);
+ if (!rv) {
+ siw_dbg_cep(cep, "id 0x%p, [QP %u]: exit\n", id,
+ qp_id(qp));
+ siw_cep_set_free(cep);
+ return 0;
+ }
+ }
+error:
+ siw_dbg_qp(qp, "failed: %d\n", rv);
+
+ if (cep) {
+ siw_socket_disassoc(s);
+ sock_release(s);
+ cep->sock = NULL;
+
+ cep->qp = NULL;
+
+ cep->cm_id = NULL;
+ id->rem_ref(id);
+ siw_cep_put(cep);
+
+ qp->cep = NULL;
+ siw_cep_put(cep);
+
+ cep->state = SIW_EPSTATE_CLOSED;
+
+ siw_cep_set_free(cep);
+
+ siw_cep_put(cep);
+
+ } else if (s) {
+ sock_release(s);
+ }
+ siw_qp_put(qp);
+
+ return rv;
+}
+
+/*
+ * siw_accept - Let SoftiWARP accept an RDMA connection request
+ *
+ * @id: New connection management id to be used for accepted
+ * connection request
+ * @params: Connection parameters provided by ULP for accepting connection
+ *
+ * Transition QP to RTS state, associate new CM id @id with accepted CEP
+ * and get prepared for TCP input by installing socket callbacks.
+ * Then send MPA Reply and generate the "connection established" event.
+ * Socket callbacks must be installed before sending MPA Reply, because
+ * the latter may cause a first RDMA message to arrive from the RDMA Initiator
+ * side very quickly, at which time the socket callbacks must be ready.
+ */
+int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params)
+{
+ struct siw_device *sdev = to_siw_dev(id->device);
+ struct siw_cep *cep = (struct siw_cep *)id->provider_data;
+ struct siw_qp *qp;
+ struct siw_qp_attrs qp_attrs;
+ int rv, max_priv_data = MPA_MAX_PRIVDATA;
+ bool wait_for_peer_rts = false;
+
+ siw_cep_set_inuse(cep);
+ siw_cep_put(cep);
+
+ /* Free lingering inbound private data */
+ if (cep->mpa.hdr.params.pd_len) {
+ cep->mpa.hdr.params.pd_len = 0;
+ kfree(cep->mpa.pdata);
+ cep->mpa.pdata = NULL;
+ }
+ siw_cancel_mpatimer(cep);
+
+ if (cep->state != SIW_EPSTATE_RECVD_MPAREQ) {
+ siw_dbg_cep(cep, "id 0x%p: out of state\n", id);
+
+ siw_cep_set_free(cep);
+ siw_cep_put(cep);
+
+ return -ECONNRESET;
+ }
+ qp = siw_qp_id2obj(sdev, params->qpn);
+ if (!qp) {
+ WARN(1, "[QP %d] does not exist\n", params->qpn);
+ siw_cep_set_free(cep);
+ siw_cep_put(cep);
+
+ return -EINVAL;
+ }
+ down_write(&qp->state_lock);
+ if (qp->attrs.state > SIW_QP_STATE_RTR) {
+ rv = -EINVAL;
+ up_write(&qp->state_lock);
+ goto error;
+ }
+ siw_dbg_cep(cep, "id 0x%p\n", id);
+
+ if (try_gso && cep->mpa.hdr.params.bits & MPA_RR_FLAG_GSO_EXP) {
+ siw_dbg_cep(cep, "peer allows GSO on TX\n");
+ qp->tx_ctx.gso_seg_limit = 0;
+ }
+ if (params->ord > sdev->attrs.max_ord ||
+ params->ird > sdev->attrs.max_ird) {
+ siw_dbg_cep(
+ cep,
+ "id 0x%p, [QP %u]: ord %d (max %d), ird %d (max %d)\n",
+ id, qp_id(qp), params->ord, sdev->attrs.max_ord,
+ params->ird, sdev->attrs.max_ird);
+ rv = -EINVAL;
+ up_write(&qp->state_lock);
+ goto error;
+ }
+ if (cep->enhanced_rdma_conn_est)
+ max_priv_data -= sizeof(struct mpa_v2_data);
+
+ if (params->private_data_len > max_priv_data) {
+ siw_dbg_cep(
+ cep,
+ "id 0x%p, [QP %u]: private data length: %d (max %d)\n",
+ id, qp_id(qp), params->private_data_len, max_priv_data);
+ rv = -EINVAL;
+ up_write(&qp->state_lock);
+ goto error;
+ }
+ if (cep->enhanced_rdma_conn_est) {
+ if (params->ord > cep->ord) {
+ if (relaxed_ird_negotiation) {
+ params->ord = cep->ord;
+ } else {
+ cep->ird = params->ird;
+ cep->ord = params->ord;
+ rv = -EINVAL;
+ up_write(&qp->state_lock);
+ goto error;
+ }
+ }
+ if (params->ird < cep->ird) {
+ if (relaxed_ird_negotiation &&
+ cep->ird <= sdev->attrs.max_ird)
+ params->ird = cep->ird;
+ else {
+ rv = -ENOMEM;
+ up_write(&qp->state_lock);
+ goto error;
+ }
+ }
+ if (cep->mpa.v2_ctrl.ord &
+ (MPA_V2_RDMA_WRITE_RTR | MPA_V2_RDMA_READ_RTR))
+ wait_for_peer_rts = true;
+ /*
+ * Signal back negotiated IRD and ORD values
+ */
+ cep->mpa.v2_ctrl.ord =
+ htons(params->ord & MPA_IRD_ORD_MASK) |
+ (cep->mpa.v2_ctrl.ord & ~MPA_V2_MASK_IRD_ORD);
+ cep->mpa.v2_ctrl.ird =
+ htons(params->ird & MPA_IRD_ORD_MASK) |
+ (cep->mpa.v2_ctrl.ird & ~MPA_V2_MASK_IRD_ORD);
+ }
+ cep->ird = params->ird;
+ cep->ord = params->ord;
+
+ cep->cm_id = id;
+ id->add_ref(id);
+
+ memset(&qp_attrs, 0, sizeof(qp_attrs));
+ qp_attrs.orq_size = cep->ord;
+ qp_attrs.irq_size = cep->ird;
+ qp_attrs.sk = cep->sock;
+ if (cep->mpa.hdr.params.bits & MPA_RR_FLAG_CRC)
+ qp_attrs.flags = SIW_MPA_CRC;
+ qp_attrs.state = SIW_QP_STATE_RTS;
+
+ siw_dbg_cep(cep, "id 0x%p, [QP%u]: moving to rts\n", id, qp_id(qp));
+
+ /* Associate QP with CEP */
+ siw_cep_get(cep);
+ qp->cep = cep;
+
+ /* siw_qp_get(qp) already done by QP lookup */
+ cep->qp = qp;
+
+ cep->state = SIW_EPSTATE_RDMA_MODE;
+
+ /* Move socket RX/TX under QP control */
+ rv = siw_qp_modify(qp, &qp_attrs,
+ SIW_QP_ATTR_STATE | SIW_QP_ATTR_LLP_HANDLE |
+ SIW_QP_ATTR_ORD | SIW_QP_ATTR_IRD |
+ SIW_QP_ATTR_MPA);
+ up_write(&qp->state_lock);
+
+ if (rv)
+ goto error;
+
+ siw_dbg_cep(cep, "id 0x%p, [QP %u]: send mpa reply, %d byte pdata\n",
+ id, qp_id(qp), params->private_data_len);
+
+ rv = siw_send_mpareqrep(cep, params->private_data,
+ params->private_data_len);
+ if (rv != 0)
+ goto error;
+
+ if (wait_for_peer_rts) {
+ siw_sk_assign_rtr_upcalls(cep);
+ } else {
+ siw_qp_socket_assoc(cep, qp);
+ rv = siw_cm_upcall(cep, IW_CM_EVENT_ESTABLISHED, 0);
+ if (rv)
+ goto error;
+ }
+ siw_cep_set_free(cep);
+
+ return 0;
+error:
+ siw_socket_disassoc(cep->sock);
+ sock_release(cep->sock);
+ cep->sock = NULL;
+
+ cep->state = SIW_EPSTATE_CLOSED;
+
+ if (cep->cm_id) {
+ cep->cm_id->rem_ref(id);
+ cep->cm_id = NULL;
+ }
+ if (qp->cep) {
+ siw_cep_put(cep);
+ qp->cep = NULL;
+ }
+ cep->qp = NULL;
+ siw_qp_put(qp);
+
+ siw_cep_set_free(cep);
+ siw_cep_put(cep);
+
+ return rv;
+}
+
+/*
+ * siw_reject()
+ *
+ * Local connection reject case. Send private data back to peer,
+ * close connection and dereference connection id.
+ */
+int siw_reject(struct iw_cm_id *id, const void *pdata, u8 pd_len)
+{
+ struct siw_cep *cep = (struct siw_cep *)id->provider_data;
+
+ siw_cep_set_inuse(cep);
+ siw_cep_put(cep);
+
+ siw_cancel_mpatimer(cep);
+
+ if (cep->state != SIW_EPSTATE_RECVD_MPAREQ) {
+ siw_dbg_cep(cep, "id 0x%p: out of state\n", id);
+
+ siw_cep_set_free(cep);
+ siw_cep_put(cep); /* put last reference */
+
+ return -ECONNRESET;
+ }
+ siw_dbg_cep(cep, "id 0x%p, cep->state %d, pd_len %d\n", id, cep->state,
+ pd_len);
+
+ if (__mpa_rr_revision(cep->mpa.hdr.params.bits) >= MPA_REVISION_1) {
+ cep->mpa.hdr.params.bits |= MPA_RR_FLAG_REJECT; /* reject */
+ siw_send_mpareqrep(cep, pdata, pd_len);
+ }
+ siw_socket_disassoc(cep->sock);
+ sock_release(cep->sock);
+ cep->sock = NULL;
+
+ cep->state = SIW_EPSTATE_CLOSED;
+
+ siw_cep_set_free(cep);
+ siw_cep_put(cep);
+
+ return 0;
+}
+
+static int siw_listen_address(struct iw_cm_id *id, int backlog,
+ struct sockaddr *laddr, int addr_family)
+{
+ struct socket *s;
+ struct siw_cep *cep = NULL;
+ struct siw_device *sdev = to_siw_dev(id->device);
+ int rv = 0, s_val;
+
+ rv = sock_create(addr_family, SOCK_STREAM, IPPROTO_TCP, &s);
+ if (rv < 0)
+ return rv;
+
+ /*
+ * Allow binding local port when still in TIME_WAIT from last close.
+ */
+ s_val = 1;
+ rv = kernel_setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&s_val,
+ sizeof(s_val));
+ if (rv) {
+ siw_dbg(id->device, "id 0x%p: setsockopt error: %d\n", id, rv);
+ goto error;
+ }
+ rv = s->ops->bind(s, laddr, addr_family == AF_INET ?
+ sizeof(struct sockaddr_in) :
+ sizeof(struct sockaddr_in6));
+ if (rv) {
+ siw_dbg(id->device, "id 0x%p: socket bind error: %d\n", id, rv);
+ goto error;
+ }
+ cep = siw_cep_alloc(sdev);
+ if (!cep) {
+ rv = -ENOMEM;
+ goto error;
+ }
+ siw_cep_socket_assoc(cep, s);
+
+ rv = siw_cm_alloc_work(cep, backlog);
+ if (rv) {
+ siw_dbg(id->device,
+ "id 0x%p: alloc_work error %d, backlog %d\n", id,
+ rv, backlog);
+ goto error;
+ }
+ rv = s->ops->listen(s, backlog);
+ if (rv) {
+ siw_dbg(id->device, "id 0x%p: listen error %d\n", id, rv);
+ goto error;
+ }
+ cep->cm_id = id;
+ id->add_ref(id);
+
+ /*
+ * In case of a wildcard rdma_listen on a multi-homed device,
+ * a listener's IWCM id is associated with more than one listening CEP.
+ *
+ * We currently use id->provider_data in three different ways:
+ *
+ * o For a listener's IWCM id, id->provider_data points to
+ * the list_head of the list of listening CEPs.
+ * Uses: siw_create_listen(), siw_destroy_listen()
+ *
+ * o For each accepted passive-side IWCM id, id->provider_data
+ * points to the CEP itself. This is a consequence of
+ * - siw_cm_upcall() setting event.provider_data = cep and
+ * - the IWCM's cm_conn_req_handler() setting provider_data of the
+ * new passive-side IWCM id equal to event.provider_data
+ * Uses: siw_accept(), siw_reject()
+ *
+ * o For an active-side IWCM id, id->provider_data is not used at all.
+ *
+ */
+ if (!id->provider_data) {
+ id->provider_data =
+ kmalloc(sizeof(struct list_head), GFP_KERNEL);
+ if (!id->provider_data) {
+ rv = -ENOMEM;
+ goto error;
+ }
+ INIT_LIST_HEAD((struct list_head *)id->provider_data);
+ }
+ list_add_tail(&cep->listenq, (struct list_head *)id->provider_data);
+ cep->state = SIW_EPSTATE_LISTENING;
+
+ if (addr_family == AF_INET)
+ siw_dbg(id->device, "Listen at laddr %pI4 %u\n",
+ &(((struct sockaddr_in *)laddr)->sin_addr),
+ ((struct sockaddr_in *)laddr)->sin_port);
+ else
+ siw_dbg(id->device, "Listen at laddr %pI6 %u\n",
+ &(((struct sockaddr_in6 *)laddr)->sin6_addr),
+ ((struct sockaddr_in6 *)laddr)->sin6_port);
+
+ return 0;
+
+error:
+ siw_dbg(id->device, "failed: %d\n", rv);
+
+ if (cep) {
+ siw_cep_set_inuse(cep);
+
+ if (cep->cm_id) {
+ cep->cm_id->rem_ref(cep->cm_id);
+ cep->cm_id = NULL;
+ }
+ cep->sock = NULL;
+ siw_socket_disassoc(s);
+ cep->state = SIW_EPSTATE_CLOSED;
+
+ siw_cep_set_free(cep);
+ siw_cep_put(cep);
+ }
+ sock_release(s);
+
+ return rv;
+}
+
+static void siw_drop_listeners(struct iw_cm_id *id)
+{
+ struct list_head *p, *tmp;
+
+ /*
+ * In case of a wildcard rdma_listen on a multi-homed device,
+ * a listener's IWCM id is associated with more than one listening CEP.
+ */
+ list_for_each_safe(p, tmp, (struct list_head *)id->provider_data) {
+ struct siw_cep *cep = list_entry(p, struct siw_cep, listenq);
+
+ list_del(p);
+
+ siw_dbg_cep(cep, "id 0x%p: drop cep, state %d\n", id,
+ cep->state);
+
+ siw_cep_set_inuse(cep);
+
+ if (cep->cm_id) {
+ cep->cm_id->rem_ref(cep->cm_id);
+ cep->cm_id = NULL;
+ }
+ if (cep->sock) {
+ siw_socket_disassoc(cep->sock);
+ sock_release(cep->sock);
+ cep->sock = NULL;
+ }
+ cep->state = SIW_EPSTATE_CLOSED;
+ siw_cep_set_free(cep);
+ siw_cep_put(cep);
+ }
+}
+
+/*
+ * siw_create_listen - Create resources for a listener's IWCM ID @id
+ *
+ * Listens on the socket addresses id->local_addr and id->remote_addr.
+ *
+ * If the listener's @id provides a specific local IP address, at most one
+ * listening socket is created and associated with @id.
+ *
+ * If the listener's @id provides the wildcard (zero) local IP address,
+ * a separate listen is performed for each local IP address of the device
+ * by creating a listening socket and binding to that local IP address.
+ *
+ */
+int siw_create_listen(struct iw_cm_id *id, int backlog)
+{
+ struct net_device *dev = to_siw_dev(id->device)->netdev;
+ int rv = 0, listeners = 0;
+
+ siw_dbg(id->device, "id 0x%p: backlog %d\n", id, backlog);
+
+ /*
+ * For each attached address of the interface, create a
+ * listening socket, if id->local_addr is the wildcard
+ * IP address or matches the IP address.
+ */
+ if (id->local_addr.ss_family == AF_INET) {
+ struct in_device *in_dev = in_dev_get(dev);
+ struct sockaddr_in s_laddr, *s_raddr;
+ const struct in_ifaddr *ifa;
+
+ memcpy(&s_laddr, &id->local_addr, sizeof(s_laddr));
+ s_raddr = (struct sockaddr_in *)&id->remote_addr;
+
+ siw_dbg(id->device,
+ "id 0x%p: laddr %pI4:%d, raddr %pI4:%d\n",
+ id, &s_laddr.sin_addr, ntohs(s_laddr.sin_port),
+ &s_raddr->sin_addr, ntohs(s_raddr->sin_port));
+
+ rtnl_lock();
+ in_dev_for_each_ifa_rtnl(ifa, in_dev) {
+ if (ipv4_is_zeronet(s_laddr.sin_addr.s_addr) ||
+ s_laddr.sin_addr.s_addr == ifa->ifa_address) {
+ s_laddr.sin_addr.s_addr = ifa->ifa_address;
+
+ rv = siw_listen_address(id, backlog,
+ (struct sockaddr *)&s_laddr,
+ AF_INET);
+ if (!rv)
+ listeners++;
+ }
+ }
+ rtnl_unlock();
+ in_dev_put(in_dev);
+ } else if (id->local_addr.ss_family == AF_INET6) {
+ struct inet6_dev *in6_dev = in6_dev_get(dev);
+ struct inet6_ifaddr *ifp;
+ struct sockaddr_in6 *s_laddr = &to_sockaddr_in6(id->local_addr),
+ *s_raddr = &to_sockaddr_in6(id->remote_addr);
+
+ siw_dbg(id->device,
+ "id 0x%p: laddr %pI6:%d, raddr %pI6:%d\n",
+ id, &s_laddr->sin6_addr, ntohs(s_laddr->sin6_port),
+ &s_raddr->sin6_addr, ntohs(s_raddr->sin6_port));
+
+ read_lock_bh(&in6_dev->lock);
+ list_for_each_entry(ifp, &in6_dev->addr_list, if_list) {
+ struct sockaddr_in6 bind_addr;
+
+ if (ipv6_addr_any(&s_laddr->sin6_addr) ||
+ ipv6_addr_equal(&s_laddr->sin6_addr, &ifp->addr)) {
+ bind_addr.sin6_family = AF_INET6;
+ bind_addr.sin6_port = s_laddr->sin6_port;
+ bind_addr.sin6_flowinfo = 0;
+ bind_addr.sin6_addr = ifp->addr;
+ bind_addr.sin6_scope_id = dev->ifindex;
+
+ rv = siw_listen_address(id, backlog,
+ (struct sockaddr *)&bind_addr,
+ AF_INET6);
+ if (!rv)
+ listeners++;
+ }
+ }
+ read_unlock_bh(&in6_dev->lock);
+
+ in6_dev_put(in6_dev);
+ } else {
+ return -EAFNOSUPPORT;
+ }
+ if (listeners)
+ rv = 0;
+ else if (!rv)
+ rv = -EINVAL;
+
+ siw_dbg(id->device, "id 0x%p: %s\n", id, rv ? "FAIL" : "OK");
+
+ return rv;
+}
+
+int siw_destroy_listen(struct iw_cm_id *id)
+{
+ siw_dbg(id->device, "id 0x%p\n", id);
+
+ if (!id->provider_data) {
+ siw_dbg(id->device, "id 0x%p: no cep(s)\n", id);
+ return 0;
+ }
+ siw_drop_listeners(id);
+ kfree(id->provider_data);
+ id->provider_data = NULL;
+
+ return 0;
+}
+
+int siw_cm_init(void)
+{
+ /*
+ * create_single_workqueue for strict ordering
+ */
+ siw_cm_wq = create_singlethread_workqueue("siw_cm_wq");
+ if (!siw_cm_wq)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void siw_cm_exit(void)
+{
+ if (siw_cm_wq) {
+ flush_workqueue(siw_cm_wq);
+ destroy_workqueue(siw_cm_wq);
+ }
+}
diff --git a/drivers/infiniband/sw/siw/siw_cm.h b/drivers/infiniband/sw/siw/siw_cm.h
new file mode 100644
index 000000000000..8c59cb3e2868
--- /dev/null
+++ b/drivers/infiniband/sw/siw/siw_cm.h
@@ -0,0 +1,133 @@
+/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
+
+/* Authors: Bernard Metzler <bmt@zurich.ibm.com> */
+/* Greg Joyce <greg@opengridcomputing.com> */
+/* Copyright (c) 2008-2019, IBM Corporation */
+/* Copyright (c) 2017, Open Grid Computing, Inc. */
+
+#ifndef _SIW_CM_H
+#define _SIW_CM_H
+
+#include <net/sock.h>
+#include <linux/tcp.h>
+
+#include <rdma/iw_cm.h>
+
+enum siw_cep_state {
+ SIW_EPSTATE_IDLE = 1,
+ SIW_EPSTATE_LISTENING,
+ SIW_EPSTATE_CONNECTING,
+ SIW_EPSTATE_AWAIT_MPAREQ,
+ SIW_EPSTATE_RECVD_MPAREQ,
+ SIW_EPSTATE_AWAIT_MPAREP,
+ SIW_EPSTATE_RDMA_MODE,
+ SIW_EPSTATE_CLOSED
+};
+
+struct siw_mpa_info {
+ struct mpa_rr hdr; /* peer mpa hdr in host byte order */
+ struct mpa_v2_data v2_ctrl;
+ struct mpa_v2_data v2_ctrl_req;
+ char *pdata;
+ int bytes_rcvd;
+};
+
+struct siw_device;
+
+struct siw_cep {
+ struct iw_cm_id *cm_id;
+ struct siw_device *sdev;
+ struct list_head devq;
+ spinlock_t lock;
+ struct kref ref;
+ int in_use;
+ wait_queue_head_t waitq;
+ enum siw_cep_state state;
+
+ struct list_head listenq;
+ struct siw_cep *listen_cep;
+
+ struct siw_qp *qp;
+ struct socket *sock;
+
+ struct siw_cm_work *mpa_timer;
+ struct list_head work_freelist;
+
+ struct siw_mpa_info mpa;
+ int ord;
+ int ird;
+ bool enhanced_rdma_conn_est;
+
+ /* Saved upcalls of socket */
+ void (*sk_state_change)(struct sock *sk);
+ void (*sk_data_ready)(struct sock *sk);
+ void (*sk_write_space)(struct sock *sk);
+ void (*sk_error_report)(struct sock *sk);
+};
+
+/*
+ * Connection initiator waits 10 seconds to receive an
+ * MPA reply after sending out MPA request. Reponder waits for
+ * 5 seconds for MPA request to arrive if new TCP connection
+ * was set up.
+ */
+#define MPAREQ_TIMEOUT (HZ * 10)
+#define MPAREP_TIMEOUT (HZ * 5)
+
+enum siw_work_type {
+ SIW_CM_WORK_ACCEPT = 1,
+ SIW_CM_WORK_READ_MPAHDR,
+ SIW_CM_WORK_CLOSE_LLP, /* close socket */
+ SIW_CM_WORK_PEER_CLOSE, /* socket indicated peer close */
+ SIW_CM_WORK_MPATIMEOUT
+};
+
+struct siw_cm_work {
+ struct delayed_work work;
+ struct list_head list;
+ enum siw_work_type type;
+ struct siw_cep *cep;
+};
+
+#define to_sockaddr_in(a) (*(struct sockaddr_in *)(&(a)))
+#define to_sockaddr_in6(a) (*(struct sockaddr_in6 *)(&(a)))
+
+static inline int getname_peer(struct socket *s, struct sockaddr_storage *a)
+{
+ return s->ops->getname(s, (struct sockaddr *)a, 1);
+}
+
+static inline int getname_local(struct socket *s, struct sockaddr_storage *a)
+{
+ return s->ops->getname(s, (struct sockaddr *)a, 0);
+}
+
+static inline int ksock_recv(struct socket *sock, char *buf, size_t size,
+ int flags)
+{
+ struct kvec iov = { buf, size };
+ struct msghdr msg = { .msg_name = NULL, .msg_flags = flags };
+
+ return kernel_recvmsg(sock, &msg, &iov, 1, size, flags);
+}
+
+int siw_connect(struct iw_cm_id *id, struct iw_cm_conn_param *parm);
+int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *param);
+int siw_reject(struct iw_cm_id *id, const void *data, u8 len);
+int siw_create_listen(struct iw_cm_id *id, int backlog);
+int siw_destroy_listen(struct iw_cm_id *id);
+
+void siw_cep_get(struct siw_cep *cep);
+void siw_cep_put(struct siw_cep *cep);
+int siw_cm_queue_work(struct siw_cep *cep, enum siw_work_type type);
+
+int siw_cm_init(void);
+void siw_cm_exit(void);
+
+/*
+ * TCP socket interface
+ */
+#define sk_to_qp(sk) (((struct siw_cep *)((sk)->sk_user_data))->qp)
+#define sk_to_cep(sk) ((struct siw_cep *)((sk)->sk_user_data))
+
+#endif
diff --git a/drivers/infiniband/sw/siw/siw_cq.c b/drivers/infiniband/sw/siw/siw_cq.c
new file mode 100644
index 000000000000..e381ae9b7d62
--- /dev/null
+++ b/drivers/infiniband/sw/siw/siw_cq.c
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause
+
+/* Authors: Bernard Metzler <bmt@zurich.ibm.com> */
+/* Copyright (c) 2008-2019, IBM Corporation */
+
+#include <linux/errno.h>
+#include <linux/types.h>
+
+#include <rdma/ib_verbs.h>
+
+#include "siw.h"
+
+static int map_wc_opcode[SIW_NUM_OPCODES] = {
+ [SIW_OP_WRITE] = IB_WC_RDMA_WRITE,
+ [SIW_OP_SEND] = IB_WC_SEND,
+ [SIW_OP_SEND_WITH_IMM] = IB_WC_SEND,
+ [SIW_OP_READ] = IB_WC_RDMA_READ,
+ [SIW_OP_READ_LOCAL_INV] = IB_WC_RDMA_READ,
+ [SIW_OP_COMP_AND_SWAP] = IB_WC_COMP_SWAP,
+ [SIW_OP_FETCH_AND_ADD] = IB_WC_FETCH_ADD,
+ [SIW_OP_INVAL_STAG] = IB_WC_LOCAL_INV,
+ [SIW_OP_REG_MR] = IB_WC_REG_MR,
+ [SIW_OP_RECEIVE] = IB_WC_RECV,
+ [SIW_OP_READ_RESPONSE] = -1 /* not used */
+};
+
+static struct {
+ enum siw_wc_status siw;
+ enum ib_wc_status ib;
+} map_cqe_status[SIW_NUM_WC_STATUS] = {
+ { SIW_WC_SUCCESS, IB_WC_SUCCESS },
+ { SIW_WC_LOC_LEN_ERR, IB_WC_LOC_LEN_ERR },
+ { SIW_WC_LOC_PROT_ERR, IB_WC_LOC_PROT_ERR },
+ { SIW_WC_LOC_QP_OP_ERR, IB_WC_LOC_QP_OP_ERR },
+ { SIW_WC_WR_FLUSH_ERR, IB_WC_WR_FLUSH_ERR },
+ { SIW_WC_BAD_RESP_ERR, IB_WC_BAD_RESP_ERR },
+ { SIW_WC_LOC_ACCESS_ERR, IB_WC_LOC_ACCESS_ERR },
+ { SIW_WC_REM_ACCESS_ERR, IB_WC_REM_ACCESS_ERR },
+ { SIW_WC_REM_INV_REQ_ERR, IB_WC_REM_INV_REQ_ERR },
+ { SIW_WC_GENERAL_ERR, IB_WC_GENERAL_ERR }
+};
+
+/*
+ * Reap one CQE from the CQ. Only used by kernel clients
+ * during CQ normal operation. Might be called during CQ
+ * flush for user mapped CQE array as well.
+ */
+int siw_reap_cqe(struct siw_cq *cq, struct ib_wc *wc)
+{
+ struct siw_cqe *cqe;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cq->lock, flags);
+
+ cqe = &cq->queue[cq->cq_get % cq->num_cqe];
+ if (READ_ONCE(cqe->flags) & SIW_WQE_VALID) {
+ memset(wc, 0, sizeof(*wc));
+ wc->wr_id = cqe->id;
+ wc->status = map_cqe_status[cqe->status].ib;
+ wc->opcode = map_wc_opcode[cqe->opcode];
+ wc->byte_len = cqe->bytes;
+
+ /*
+ * During CQ flush, also user land CQE's may get
+ * reaped here, which do not hold a QP reference
+ * and do not qualify for memory extension verbs.
+ */
+ if (likely(cq->kernel_verbs)) {
+ if (cqe->flags & SIW_WQE_REM_INVAL) {
+ wc->ex.invalidate_rkey = cqe->inval_stag;
+ wc->wc_flags = IB_WC_WITH_INVALIDATE;
+ }
+ wc->qp = cqe->base_qp;
+ siw_dbg_cq(cq, "idx %u, type %d, flags %2x, id 0x%p\n",
+ cq->cq_get % cq->num_cqe, cqe->opcode,
+ cqe->flags, (void *)cqe->id);
+ }
+ WRITE_ONCE(cqe->flags, 0);
+ cq->cq_get++;
+
+ spin_unlock_irqrestore(&cq->lock, flags);
+
+ return 1;
+ }
+ spin_unlock_irqrestore(&cq->lock, flags);
+
+ return 0;
+}
+
+/*
+ * siw_cq_flush()
+ *
+ * Flush all CQ elements.
+ */
+void siw_cq_flush(struct siw_cq *cq)
+{
+ struct ib_wc wc;
+
+ while (siw_reap_cqe(cq, &wc))
+ ;
+}
diff --git a/drivers/infiniband/sw/siw/siw_main.c b/drivers/infiniband/sw/siw/siw_main.c
new file mode 100644
index 000000000000..f55c4e80aea4
--- /dev/null
+++ b/drivers/infiniband/sw/siw/siw_main.c
@@ -0,0 +1,685 @@
+// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause
+
+/* Authors: Bernard Metzler <bmt@zurich.ibm.com> */
+/* Copyright (c) 2008-2019, IBM Corporation */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <net/net_namespace.h>
+#include <linux/rtnetlink.h>
+#include <linux/if_arp.h>
+#include <linux/list.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_user_verbs.h>
+#include <rdma/rdma_netlink.h>
+#include <linux/kthread.h>
+
+#include "siw.h"
+#include "siw_verbs.h"
+
+MODULE_AUTHOR("Bernard Metzler");
+MODULE_DESCRIPTION("Software iWARP Driver");
+MODULE_LICENSE("Dual BSD/GPL");
+
+/* transmit from user buffer, if possible */
+const bool zcopy_tx = true;
+
+/* Restrict usage of GSO, if hardware peer iwarp is unable to process
+ * large packets. try_gso = true lets siw try to use local GSO,
+ * if peer agrees. Not using GSO severly limits siw maximum tx bandwidth.
+ */
+const bool try_gso;
+
+/* Attach siw also with loopback devices */
+const bool loopback_enabled = true;
+
+/* We try to negotiate CRC on, if true */
+const bool mpa_crc_required;
+
+/* MPA CRC on/off enforced */
+const bool mpa_crc_strict;
+
+/* Control TCP_NODELAY socket option */
+const bool siw_tcp_nagle;
+
+/* Select MPA version to be used during connection setup */
+u_char mpa_version = MPA_REVISION_2;
+
+/* Selects MPA P2P mode (additional handshake during connection
+ * setup, if true.
+ */
+const bool peer_to_peer;
+
+struct task_struct *siw_tx_thread[NR_CPUS];
+struct crypto_shash *siw_crypto_shash;
+
+static int siw_device_register(struct siw_device *sdev, const char *name)
+{
+ struct ib_device *base_dev = &sdev->base_dev;
+ static int dev_id = 1;
+ int rv;
+
+ rv = ib_register_device(base_dev, name);
+ if (rv) {
+ pr_warn("siw: device registration error %d\n", rv);
+ return rv;
+ }
+ sdev->vendor_part_id = dev_id++;
+
+ siw_dbg(base_dev, "HWaddr=%pM\n", sdev->netdev->dev_addr);
+
+ return 0;
+}
+
+static void siw_device_cleanup(struct ib_device *base_dev)
+{
+ struct siw_device *sdev = to_siw_dev(base_dev);
+
+ xa_destroy(&sdev->qp_xa);
+ xa_destroy(&sdev->mem_xa);
+}
+
+static int siw_create_tx_threads(void)
+{
+ int cpu, assigned = 0;
+
+ for_each_online_cpu(cpu) {
+ /* Skip HT cores */
+ if (cpu % cpumask_weight(topology_sibling_cpumask(cpu)))
+ continue;
+
+ siw_tx_thread[cpu] =
+ kthread_create(siw_run_sq, (unsigned long *)(long)cpu,
+ "siw_tx/%d", cpu);
+ if (IS_ERR(siw_tx_thread[cpu])) {
+ siw_tx_thread[cpu] = NULL;
+ continue;
+ }
+ kthread_bind(siw_tx_thread[cpu], cpu);
+
+ wake_up_process(siw_tx_thread[cpu]);
+ assigned++;
+ }
+ return assigned;
+}
+
+static int siw_dev_qualified(struct net_device *netdev)
+{
+ /*
+ * Additional hardware support can be added here
+ * (e.g. ARPHRD_FDDI, ARPHRD_ATM, ...) - see
+ * <linux/if_arp.h> for type identifiers.
+ */
+ if (netdev->type == ARPHRD_ETHER || netdev->type == ARPHRD_IEEE802 ||
+ (netdev->type == ARPHRD_LOOPBACK && loopback_enabled))
+ return 1;
+
+ return 0;
+}
+
+static DEFINE_PER_CPU(atomic_t, siw_use_cnt);
+
+static struct {
+ struct cpumask **tx_valid_cpus;
+ int num_nodes;
+} siw_cpu_info;
+
+static int siw_init_cpulist(void)
+{
+ int i, num_nodes = num_possible_nodes();
+
+ memset(siw_tx_thread, 0, sizeof(siw_tx_thread));
+
+ siw_cpu_info.num_nodes = num_nodes;
+
+ siw_cpu_info.tx_valid_cpus =
+ kcalloc(num_nodes, sizeof(struct cpumask *), GFP_KERNEL);
+ if (!siw_cpu_info.tx_valid_cpus) {
+ siw_cpu_info.num_nodes = 0;
+ return -ENOMEM;
+ }
+ for (i = 0; i < siw_cpu_info.num_nodes; i++) {
+ siw_cpu_info.tx_valid_cpus[i] =
+ kzalloc(sizeof(struct cpumask), GFP_KERNEL);
+ if (!siw_cpu_info.tx_valid_cpus[i])
+ goto out_err;
+
+ cpumask_clear(siw_cpu_info.tx_valid_cpus[i]);
+ }
+ for_each_possible_cpu(i)
+ cpumask_set_cpu(i, siw_cpu_info.tx_valid_cpus[cpu_to_node(i)]);
+
+ return 0;
+
+out_err:
+ siw_cpu_info.num_nodes = 0;
+ while (i) {
+ kfree(siw_cpu_info.tx_valid_cpus[i]);
+ siw_cpu_info.tx_valid_cpus[i--] = NULL;
+ }
+ kfree(siw_cpu_info.tx_valid_cpus);
+ siw_cpu_info.tx_valid_cpus = NULL;
+
+ return -ENOMEM;
+}
+
+static void siw_destroy_cpulist(void)
+{
+ int i = 0;
+
+ while (i < siw_cpu_info.num_nodes)
+ kfree(siw_cpu_info.tx_valid_cpus[i++]);
+
+ kfree(siw_cpu_info.tx_valid_cpus);
+}
+
+/*
+ * Choose CPU with least number of active QP's from NUMA node of
+ * TX interface.
+ */
+int siw_get_tx_cpu(struct siw_device *sdev)
+{
+ const struct cpumask *tx_cpumask;
+ int i, num_cpus, cpu, min_use, node = sdev->numa_node, tx_cpu = -1;
+
+ if (node < 0)
+ tx_cpumask = cpu_online_mask;
+ else
+ tx_cpumask = siw_cpu_info.tx_valid_cpus[node];
+
+ num_cpus = cpumask_weight(tx_cpumask);
+ if (!num_cpus) {
+ /* no CPU on this NUMA node */
+ tx_cpumask = cpu_online_mask;
+ num_cpus = cpumask_weight(tx_cpumask);
+ }
+ if (!num_cpus)
+ goto out;
+
+ cpu = cpumask_first(tx_cpumask);
+
+ for (i = 0, min_use = SIW_MAX_QP; i < num_cpus;
+ i++, cpu = cpumask_next(cpu, tx_cpumask)) {
+ int usage;
+
+ /* Skip any cores which have no TX thread */
+ if (!siw_tx_thread[cpu])
+ continue;
+
+ usage = atomic_read(&per_cpu(siw_use_cnt, cpu));
+ if (usage <= min_use) {
+ tx_cpu = cpu;
+ min_use = usage;
+ }
+ }
+ siw_dbg(&sdev->base_dev,
+ "tx cpu %d, node %d, %d qp's\n", tx_cpu, node, min_use);
+
+out:
+ if (tx_cpu >= 0)
+ atomic_inc(&per_cpu(siw_use_cnt, tx_cpu));
+ else
+ pr_warn("siw: no tx cpu found\n");
+
+ return tx_cpu;
+}
+
+void siw_put_tx_cpu(int cpu)
+{
+ atomic_dec(&per_cpu(siw_use_cnt, cpu));
+}
+
+static struct ib_qp *siw_get_base_qp(struct ib_device *base_dev, int id)
+{
+ struct siw_qp *qp = siw_qp_id2obj(to_siw_dev(base_dev), id);
+
+ if (qp) {
+ /*
+ * siw_qp_id2obj() increments object reference count
+ */
+ siw_qp_put(qp);
+ return qp->ib_qp;
+ }
+ return NULL;
+}
+
+static void siw_verbs_sq_flush(struct ib_qp *base_qp)
+{
+ struct siw_qp *qp = to_siw_qp(base_qp);
+
+ down_write(&qp->state_lock);
+ siw_sq_flush(qp);
+ up_write(&qp->state_lock);
+}
+
+static void siw_verbs_rq_flush(struct ib_qp *base_qp)
+{
+ struct siw_qp *qp = to_siw_qp(base_qp);
+
+ down_write(&qp->state_lock);
+ siw_rq_flush(qp);
+ up_write(&qp->state_lock);
+}
+
+static const struct ib_device_ops siw_device_ops = {
+ .owner = THIS_MODULE,
+ .uverbs_abi_ver = SIW_ABI_VERSION,
+ .driver_id = RDMA_DRIVER_SIW,
+
+ .alloc_mr = siw_alloc_mr,
+ .alloc_pd = siw_alloc_pd,
+ .alloc_ucontext = siw_alloc_ucontext,
+ .create_cq = siw_create_cq,
+ .create_qp = siw_create_qp,
+ .create_srq = siw_create_srq,
+ .dealloc_driver = siw_device_cleanup,
+ .dealloc_pd = siw_dealloc_pd,
+ .dealloc_ucontext = siw_dealloc_ucontext,
+ .dereg_mr = siw_dereg_mr,
+ .destroy_cq = siw_destroy_cq,
+ .destroy_qp = siw_destroy_qp,
+ .destroy_srq = siw_destroy_srq,
+ .drain_rq = siw_verbs_rq_flush,
+ .drain_sq = siw_verbs_sq_flush,
+ .get_dma_mr = siw_get_dma_mr,
+ .get_port_immutable = siw_get_port_immutable,
+ .iw_accept = siw_accept,
+ .iw_add_ref = siw_qp_get_ref,
+ .iw_connect = siw_connect,
+ .iw_create_listen = siw_create_listen,
+ .iw_destroy_listen = siw_destroy_listen,
+ .iw_get_qp = siw_get_base_qp,
+ .iw_reject = siw_reject,
+ .iw_rem_ref = siw_qp_put_ref,
+ .map_mr_sg = siw_map_mr_sg,
+ .mmap = siw_mmap,
+ .modify_qp = siw_verbs_modify_qp,
+ .modify_srq = siw_modify_srq,
+ .poll_cq = siw_poll_cq,
+ .post_recv = siw_post_receive,
+ .post_send = siw_post_send,
+ .post_srq_recv = siw_post_srq_recv,
+ .query_device = siw_query_device,
+ .query_gid = siw_query_gid,
+ .query_pkey = siw_query_pkey,
+ .query_port = siw_query_port,
+ .query_qp = siw_query_qp,
+ .query_srq = siw_query_srq,
+ .req_notify_cq = siw_req_notify_cq,
+ .reg_user_mr = siw_reg_user_mr,
+
+ INIT_RDMA_OBJ_SIZE(ib_cq, siw_cq, base_cq),
+ INIT_RDMA_OBJ_SIZE(ib_pd, siw_pd, base_pd),
+ INIT_RDMA_OBJ_SIZE(ib_srq, siw_srq, base_srq),
+ INIT_RDMA_OBJ_SIZE(ib_ucontext, siw_ucontext, base_ucontext),
+};
+
+static struct siw_device *siw_device_create(struct net_device *netdev)
+{
+ struct siw_device *sdev = NULL;
+ struct ib_device *base_dev;
+ struct device *parent = netdev->dev.parent;
+ int rv;
+
+ if (!parent) {
+ /*
+ * The loopback device has no parent device,
+ * so it appears as a top-level device. To support
+ * loopback device connectivity, take this device
+ * as the parent device. Skip all other devices
+ * w/o parent device.
+ */
+ if (netdev->type != ARPHRD_LOOPBACK) {
+ pr_warn("siw: device %s error: no parent device\n",
+ netdev->name);
+ return NULL;
+ }
+ parent = &netdev->dev;
+ }
+ sdev = ib_alloc_device(siw_device, base_dev);
+ if (!sdev)
+ return NULL;
+
+ base_dev = &sdev->base_dev;
+
+ sdev->netdev = netdev;
+
+ if (netdev->type != ARPHRD_LOOPBACK) {
+ memcpy(&base_dev->node_guid, netdev->dev_addr, 6);
+ } else {
+ /*
+ * The loopback device does not have a HW address,
+ * but connection mangagement lib expects gid != 0
+ */
+ size_t gidlen = min_t(size_t, strlen(base_dev->name), 6);
+
+ memcpy(&base_dev->node_guid, base_dev->name, gidlen);
+ }
+ base_dev->uverbs_cmd_mask =
+ (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_PORT) |
+ (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
+ (1ull << IB_USER_VERBS_CMD_ALLOC_PD) |
+ (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) |
+ (1ull << IB_USER_VERBS_CMD_REG_MR) |
+ (1ull << IB_USER_VERBS_CMD_DEREG_MR) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_CQ) |
+ (1ull << IB_USER_VERBS_CMD_POLL_CQ) |
+ (1ull << IB_USER_VERBS_CMD_REQ_NOTIFY_CQ) |
+ (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_QP) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_QP) |
+ (1ull << IB_USER_VERBS_CMD_MODIFY_QP) |
+ (1ull << IB_USER_VERBS_CMD_DESTROY_QP) |
+ (1ull << IB_USER_VERBS_CMD_POST_SEND) |
+ (1ull << IB_USER_VERBS_CMD_POST_RECV) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_SRQ) |
+ (1ull << IB_USER_VERBS_CMD_POST_SRQ_RECV) |
+ (1ull << IB_USER_VERBS_CMD_MODIFY_SRQ) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_SRQ) |
+ (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ);
+
+ base_dev->node_type = RDMA_NODE_RNIC;
+ memcpy(base_dev->node_desc, SIW_NODE_DESC_COMMON,
+ sizeof(SIW_NODE_DESC_COMMON));
+
+ /*
+ * Current model (one-to-one device association):
+ * One Softiwarp device per net_device or, equivalently,
+ * per physical port.
+ */
+ base_dev->phys_port_cnt = 1;
+ base_dev->dev.parent = parent;
+ base_dev->dev.dma_ops = &dma_virt_ops;
+ base_dev->num_comp_vectors = num_possible_cpus();
+
+ ib_set_device_ops(base_dev, &siw_device_ops);
+ rv = ib_device_set_netdev(base_dev, netdev, 1);
+ if (rv)
+ goto error;
+
+ memcpy(base_dev->iw_ifname, netdev->name,
+ sizeof(base_dev->iw_ifname));
+
+ /* Disable TCP port mapping */
+ base_dev->iw_driver_flags = IW_F_NO_PORT_MAP,
+
+ sdev->attrs.max_qp = SIW_MAX_QP;
+ sdev->attrs.max_qp_wr = SIW_MAX_QP_WR;
+ sdev->attrs.max_ord = SIW_MAX_ORD_QP;
+ sdev->attrs.max_ird = SIW_MAX_IRD_QP;
+ sdev->attrs.max_sge = SIW_MAX_SGE;
+ sdev->attrs.max_sge_rd = SIW_MAX_SGE_RD;
+ sdev->attrs.max_cq = SIW_MAX_CQ;
+ sdev->attrs.max_cqe = SIW_MAX_CQE;
+ sdev->attrs.max_mr = SIW_MAX_MR;
+ sdev->attrs.max_pd = SIW_MAX_PD;
+ sdev->attrs.max_mw = SIW_MAX_MW;
+ sdev->attrs.max_fmr = SIW_MAX_FMR;
+ sdev->attrs.max_srq = SIW_MAX_SRQ;
+ sdev->attrs.max_srq_wr = SIW_MAX_SRQ_WR;
+ sdev->attrs.max_srq_sge = SIW_MAX_SGE;
+
+ xa_init_flags(&sdev->qp_xa, XA_FLAGS_ALLOC1);
+ xa_init_flags(&sdev->mem_xa, XA_FLAGS_ALLOC1);
+
+ INIT_LIST_HEAD(&sdev->cep_list);
+ INIT_LIST_HEAD(&sdev->qp_list);
+
+ atomic_set(&sdev->num_ctx, 0);
+ atomic_set(&sdev->num_srq, 0);
+ atomic_set(&sdev->num_qp, 0);
+ atomic_set(&sdev->num_cq, 0);
+ atomic_set(&sdev->num_mr, 0);
+ atomic_set(&sdev->num_pd, 0);
+
+ sdev->numa_node = dev_to_node(parent);
+ spin_lock_init(&sdev->lock);
+
+ return sdev;
+error:
+ ib_dealloc_device(base_dev);
+
+ return NULL;
+}
+
+/*
+ * Network link becomes unavailable. Mark all
+ * affected QP's accordingly.
+ */
+static void siw_netdev_down(struct work_struct *work)
+{
+ struct siw_device *sdev =
+ container_of(work, struct siw_device, netdev_down);
+
+ struct siw_qp_attrs qp_attrs;
+ struct list_head *pos, *tmp;
+
+ memset(&qp_attrs, 0, sizeof(qp_attrs));
+ qp_attrs.state = SIW_QP_STATE_ERROR;
+
+ list_for_each_safe(pos, tmp, &sdev->qp_list) {
+ struct siw_qp *qp = list_entry(pos, struct siw_qp, devq);
+
+ down_write(&qp->state_lock);
+ WARN_ON(siw_qp_modify(qp, &qp_attrs, SIW_QP_ATTR_STATE));
+ up_write(&qp->state_lock);
+ }
+ ib_device_put(&sdev->base_dev);
+}
+
+static void siw_device_goes_down(struct siw_device *sdev)
+{
+ if (ib_device_try_get(&sdev->base_dev)) {
+ INIT_WORK(&sdev->netdev_down, siw_netdev_down);
+ schedule_work(&sdev->netdev_down);
+ }
+}
+
+static int siw_netdev_event(struct notifier_block *nb, unsigned long event,
+ void *arg)
+{
+ struct net_device *netdev = netdev_notifier_info_to_dev(arg);
+ struct ib_device *base_dev;
+ struct siw_device *sdev;
+
+ dev_dbg(&netdev->dev, "siw: event %lu\n", event);
+
+ if (dev_net(netdev) != &init_net)
+ return NOTIFY_OK;
+
+ base_dev = ib_device_get_by_netdev(netdev, RDMA_DRIVER_SIW);
+ if (!base_dev)
+ return NOTIFY_OK;
+
+ sdev = to_siw_dev(base_dev);
+
+ switch (event) {
+ case NETDEV_UP:
+ sdev->state = IB_PORT_ACTIVE;
+ siw_port_event(sdev, 1, IB_EVENT_PORT_ACTIVE);
+ break;
+
+ case NETDEV_GOING_DOWN:
+ siw_device_goes_down(sdev);
+ break;
+
+ case NETDEV_DOWN:
+ sdev->state = IB_PORT_DOWN;
+ siw_port_event(sdev, 1, IB_EVENT_PORT_ERR);
+ break;
+
+ case NETDEV_REGISTER:
+ /*
+ * Device registration now handled only by
+ * rdma netlink commands. So it shall be impossible
+ * to end up here with a valid siw device.
+ */
+ siw_dbg(base_dev, "unexpected NETDEV_REGISTER event\n");
+ break;
+
+ case NETDEV_UNREGISTER:
+ ib_unregister_device_queued(&sdev->base_dev);
+ break;
+
+ case NETDEV_CHANGEADDR:
+ siw_port_event(sdev, 1, IB_EVENT_LID_CHANGE);
+ break;
+ /*
+ * Todo: Below netdev events are currently not handled.
+ */
+ case NETDEV_CHANGEMTU:
+ case NETDEV_CHANGE:
+ break;
+
+ default:
+ break;
+ }
+ ib_device_put(&sdev->base_dev);
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block siw_netdev_nb = {
+ .notifier_call = siw_netdev_event,
+};
+
+static int siw_newlink(const char *basedev_name, struct net_device *netdev)
+{
+ struct ib_device *base_dev;
+ struct siw_device *sdev = NULL;
+ int rv = -ENOMEM;
+
+ if (!siw_dev_qualified(netdev))
+ return -EINVAL;
+
+ base_dev = ib_device_get_by_netdev(netdev, RDMA_DRIVER_SIW);
+ if (base_dev) {
+ ib_device_put(base_dev);
+ return -EEXIST;
+ }
+ sdev = siw_device_create(netdev);
+ if (sdev) {
+ dev_dbg(&netdev->dev, "siw: new device\n");
+
+ if (netif_running(netdev) && netif_carrier_ok(netdev))
+ sdev->state = IB_PORT_ACTIVE;
+ else
+ sdev->state = IB_PORT_DOWN;
+
+ rv = siw_device_register(sdev, basedev_name);
+ if (rv)
+ ib_dealloc_device(&sdev->base_dev);
+ }
+ return rv;
+}
+
+static struct rdma_link_ops siw_link_ops = {
+ .type = "siw",
+ .newlink = siw_newlink,
+};
+
+/*
+ * siw_init_module - Initialize Softiwarp module and register with netdev
+ * subsystem.
+ */
+static __init int siw_init_module(void)
+{
+ int rv;
+ int nr_cpu;
+
+ if (SENDPAGE_THRESH < SIW_MAX_INLINE) {
+ pr_info("siw: sendpage threshold too small: %u\n",
+ (int)SENDPAGE_THRESH);
+ rv = -EINVAL;
+ goto out_error;
+ }
+ rv = siw_init_cpulist();
+ if (rv)
+ goto out_error;
+
+ rv = siw_cm_init();
+ if (rv)
+ goto out_error;
+
+ if (!siw_create_tx_threads()) {
+ pr_info("siw: Could not start any TX thread\n");
+ goto out_error;
+ }
+ /*
+ * Locate CRC32 algorithm. If unsuccessful, fail
+ * loading siw only, if CRC is required.
+ */
+ siw_crypto_shash = crypto_alloc_shash("crc32c", 0, 0);
+ if (IS_ERR(siw_crypto_shash)) {
+ pr_info("siw: Loading CRC32c failed: %ld\n",
+ PTR_ERR(siw_crypto_shash));
+ siw_crypto_shash = NULL;
+ if (mpa_crc_required) {
+ rv = -EOPNOTSUPP;
+ goto out_error;
+ }
+ }
+ rv = register_netdevice_notifier(&siw_netdev_nb);
+ if (rv)
+ goto out_error;
+
+ rdma_link_register(&siw_link_ops);
+
+ pr_info("SoftiWARP attached\n");
+ return 0;
+
+out_error:
+ for (nr_cpu = 0; nr_cpu < nr_cpu_ids; nr_cpu++) {
+ if (siw_tx_thread[nr_cpu]) {
+ siw_stop_tx_thread(nr_cpu);
+ siw_tx_thread[nr_cpu] = NULL;
+ }
+ }
+ if (siw_crypto_shash)
+ crypto_free_shash(siw_crypto_shash);
+
+ pr_info("SoftIWARP attach failed. Error: %d\n", rv);
+
+ siw_cm_exit();
+ siw_destroy_cpulist();
+
+ return rv;
+}
+
+static void __exit siw_exit_module(void)
+{
+ int cpu;
+
+ for_each_possible_cpu(cpu) {
+ if (siw_tx_thread[cpu]) {
+ siw_stop_tx_thread(cpu);
+ siw_tx_thread[cpu] = NULL;
+ }
+ }
+ unregister_netdevice_notifier(&siw_netdev_nb);
+ rdma_link_unregister(&siw_link_ops);
+ ib_unregister_driver(RDMA_DRIVER_SIW);
+
+ siw_cm_exit();
+
+ siw_destroy_cpulist();
+
+ if (siw_crypto_shash)
+ crypto_free_shash(siw_crypto_shash);
+
+ pr_info("SoftiWARP detached\n");
+}
+
+module_init(siw_init_module);
+module_exit(siw_exit_module);
+
+MODULE_ALIAS_RDMA_LINK("siw");
diff --git a/drivers/infiniband/sw/siw/siw_mem.c b/drivers/infiniband/sw/siw/siw_mem.c
new file mode 100644
index 000000000000..67171c82b0c4
--- /dev/null
+++ b/drivers/infiniband/sw/siw/siw_mem.c
@@ -0,0 +1,460 @@
+// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause
+
+/* Authors: Bernard Metzler <bmt@zurich.ibm.com> */
+/* Copyright (c) 2008-2019, IBM Corporation */
+
+#include <linux/gfp.h>
+#include <rdma/ib_verbs.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/sched/mm.h>
+#include <linux/resource.h>
+
+#include "siw.h"
+#include "siw_mem.h"
+
+/*
+ * Stag lookup is based on its index part only (24 bits).
+ * The code avoids special Stag of zero and tries to randomize
+ * STag values between 1 and SIW_STAG_MAX_INDEX.
+ */
+int siw_mem_add(struct siw_device *sdev, struct siw_mem *m)
+{
+ struct xa_limit limit = XA_LIMIT(1, 0x00ffffff);
+ u32 id, next;
+
+ get_random_bytes(&next, 4);
+ next &= 0x00ffffff;
+
+ if (xa_alloc_cyclic(&sdev->mem_xa, &id, m, limit, &next,
+ GFP_KERNEL) < 0)
+ return -ENOMEM;
+
+ /* Set the STag index part */
+ m->stag = id << 8;
+
+ siw_dbg_mem(m, "new MEM object\n");
+
+ return 0;
+}
+
+/*
+ * siw_mem_id2obj()
+ *
+ * resolves memory from stag given by id. might be called from:
+ * o process context before sending out of sgl, or
+ * o in softirq when resolving target memory
+ */
+struct siw_mem *siw_mem_id2obj(struct siw_device *sdev, int stag_index)
+{
+ struct siw_mem *mem;
+
+ rcu_read_lock();
+ mem = xa_load(&sdev->mem_xa, stag_index);
+ if (likely(mem && kref_get_unless_zero(&mem->ref))) {
+ rcu_read_unlock();
+ return mem;
+ }
+ rcu_read_unlock();
+
+ return NULL;
+}
+
+static void siw_free_plist(struct siw_page_chunk *chunk, int num_pages,
+ bool dirty)
+{
+ struct page **p = chunk->plist;
+
+ while (num_pages--) {
+ if (!PageDirty(*p) && dirty)
+ put_user_pages_dirty_lock(p, 1);
+ else
+ put_user_page(*p);
+ p++;
+ }
+}
+
+void siw_umem_release(struct siw_umem *umem, bool dirty)
+{
+ struct mm_struct *mm_s = umem->owning_mm;
+ int i, num_pages = umem->num_pages;
+
+ for (i = 0; num_pages; i++) {
+ int to_free = min_t(int, PAGES_PER_CHUNK, num_pages);
+
+ siw_free_plist(&umem->page_chunk[i], to_free,
+ umem->writable && dirty);
+ kfree(umem->page_chunk[i].plist);
+ num_pages -= to_free;
+ }
+ atomic64_sub(umem->num_pages, &mm_s->pinned_vm);
+
+ mmdrop(mm_s);
+ kfree(umem->page_chunk);
+ kfree(umem);
+}
+
+int siw_mr_add_mem(struct siw_mr *mr, struct ib_pd *pd, void *mem_obj,
+ u64 start, u64 len, int rights)
+{
+ struct siw_device *sdev = to_siw_dev(pd->device);
+ struct siw_mem *mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ struct xa_limit limit = XA_LIMIT(1, 0x00ffffff);
+ u32 id, next;
+
+ if (!mem)
+ return -ENOMEM;
+
+ mem->mem_obj = mem_obj;
+ mem->stag_valid = 0;
+ mem->sdev = sdev;
+ mem->va = start;
+ mem->len = len;
+ mem->pd = pd;
+ mem->perms = rights & IWARP_ACCESS_MASK;
+ kref_init(&mem->ref);
+
+ mr->mem = mem;
+
+ get_random_bytes(&next, 4);
+ next &= 0x00ffffff;
+
+ if (xa_alloc_cyclic(&sdev->mem_xa, &id, mem, limit, &next,
+ GFP_KERNEL) < 0) {
+ kfree(mem);
+ return -ENOMEM;
+ }
+ /* Set the STag index part */
+ mem->stag = id << 8;
+ mr->base_mr.lkey = mr->base_mr.rkey = mem->stag;
+
+ return 0;
+}
+
+void siw_mr_drop_mem(struct siw_mr *mr)
+{
+ struct siw_mem *mem = mr->mem, *found;
+
+ mem->stag_valid = 0;
+
+ /* make STag invalid visible asap */
+ smp_mb();
+
+ found = xa_erase(&mem->sdev->mem_xa, mem->stag >> 8);
+ WARN_ON(found != mem);
+ siw_mem_put(mem);
+}
+
+void siw_free_mem(struct kref *ref)
+{
+ struct siw_mem *mem = container_of(ref, struct siw_mem, ref);
+
+ siw_dbg_mem(mem, "free mem, pbl: %s\n", mem->is_pbl ? "y" : "n");
+
+ if (!mem->is_mw && mem->mem_obj) {
+ if (mem->is_pbl == 0)
+ siw_umem_release(mem->umem, true);
+ else
+ kfree(mem->pbl);
+ }
+ kfree(mem);
+}
+
+/*
+ * siw_check_mem()
+ *
+ * Check protection domain, STAG state, access permissions and
+ * address range for memory object.
+ *
+ * @pd: Protection Domain memory should belong to
+ * @mem: memory to be checked
+ * @addr: starting addr of mem
+ * @perms: requested access permissions
+ * @len: len of memory interval to be checked
+ *
+ */
+int siw_check_mem(struct ib_pd *pd, struct siw_mem *mem, u64 addr,
+ enum ib_access_flags perms, int len)
+{
+ if (!mem->stag_valid) {
+ siw_dbg_pd(pd, "STag 0x%08x invalid\n", mem->stag);
+ return -E_STAG_INVALID;
+ }
+ if (mem->pd != pd) {
+ siw_dbg_pd(pd, "STag 0x%08x: PD mismatch\n", mem->stag);
+ return -E_PD_MISMATCH;
+ }
+ /*
+ * check access permissions
+ */
+ if ((mem->perms & perms) < perms) {
+ siw_dbg_pd(pd, "permissions 0x%08x < 0x%08x\n",
+ mem->perms, perms);
+ return -E_ACCESS_PERM;
+ }
+ /*
+ * Check if access falls into valid memory interval.
+ */
+ if (addr < mem->va || addr + len > mem->va + mem->len) {
+ siw_dbg_pd(pd, "MEM interval len %d\n", len);
+ siw_dbg_pd(pd, "[0x%016llx, 0x%016llx] out of bounds\n",
+ (unsigned long long)addr,
+ (unsigned long long)(addr + len));
+ siw_dbg_pd(pd, "[0x%016llx, 0x%016llx] STag=0x%08x\n",
+ (unsigned long long)mem->va,
+ (unsigned long long)(mem->va + mem->len),
+ mem->stag);
+
+ return -E_BASE_BOUNDS;
+ }
+ return E_ACCESS_OK;
+}
+
+/*
+ * siw_check_sge()
+ *
+ * Check SGE for access rights in given interval
+ *
+ * @pd: Protection Domain memory should belong to
+ * @sge: SGE to be checked
+ * @mem: location of memory reference within array
+ * @perms: requested access permissions
+ * @off: starting offset in SGE
+ * @len: len of memory interval to be checked
+ *
+ * NOTE: Function references SGE's memory object (mem->obj)
+ * if not yet done. New reference is kept if check went ok and
+ * released if check failed. If mem->obj is already valid, no new
+ * lookup is being done and mem is not released it check fails.
+ */
+int siw_check_sge(struct ib_pd *pd, struct siw_sge *sge, struct siw_mem *mem[],
+ enum ib_access_flags perms, u32 off, int len)
+{
+ struct siw_device *sdev = to_siw_dev(pd->device);
+ struct siw_mem *new = NULL;
+ int rv = E_ACCESS_OK;
+
+ if (len + off > sge->length) {
+ rv = -E_BASE_BOUNDS;
+ goto fail;
+ }
+ if (*mem == NULL) {
+ new = siw_mem_id2obj(sdev, sge->lkey >> 8);
+ if (unlikely(!new)) {
+ siw_dbg_pd(pd, "STag unknown: 0x%08x\n", sge->lkey);
+ rv = -E_STAG_INVALID;
+ goto fail;
+ }
+ *mem = new;
+ }
+ /* Check if user re-registered with different STag key */
+ if (unlikely((*mem)->stag != sge->lkey)) {
+ siw_dbg_mem((*mem), "STag mismatch: 0x%08x\n", sge->lkey);
+ rv = -E_STAG_INVALID;
+ goto fail;
+ }
+ rv = siw_check_mem(pd, *mem, sge->laddr + off, perms, len);
+ if (unlikely(rv))
+ goto fail;
+
+ return 0;
+
+fail:
+ if (new) {
+ *mem = NULL;
+ siw_mem_put(new);
+ }
+ return rv;
+}
+
+void siw_wqe_put_mem(struct siw_wqe *wqe, enum siw_opcode op)
+{
+ switch (op) {
+ case SIW_OP_SEND:
+ case SIW_OP_WRITE:
+ case SIW_OP_SEND_WITH_IMM:
+ case SIW_OP_SEND_REMOTE_INV:
+ case SIW_OP_READ:
+ case SIW_OP_READ_LOCAL_INV:
+ if (!(wqe->sqe.flags & SIW_WQE_INLINE))
+ siw_unref_mem_sgl(wqe->mem, wqe->sqe.num_sge);
+ break;
+
+ case SIW_OP_RECEIVE:
+ siw_unref_mem_sgl(wqe->mem, wqe->rqe.num_sge);
+ break;
+
+ case SIW_OP_READ_RESPONSE:
+ siw_unref_mem_sgl(wqe->mem, 1);
+ break;
+
+ default:
+ /*
+ * SIW_OP_INVAL_STAG and SIW_OP_REG_MR
+ * do not hold memory references
+ */
+ break;
+ }
+}
+
+int siw_invalidate_stag(struct ib_pd *pd, u32 stag)
+{
+ struct siw_device *sdev = to_siw_dev(pd->device);
+ struct siw_mem *mem = siw_mem_id2obj(sdev, stag >> 8);
+ int rv = 0;
+
+ if (unlikely(!mem)) {
+ siw_dbg_pd(pd, "STag 0x%08x unknown\n", stag);
+ return -EINVAL;
+ }
+ if (unlikely(mem->pd != pd)) {
+ siw_dbg_pd(pd, "PD mismatch for STag 0x%08x\n", stag);
+ rv = -EACCES;
+ goto out;
+ }
+ /*
+ * Per RDMA verbs definition, an STag may already be in invalid
+ * state if invalidation is requested. So no state check here.
+ */
+ mem->stag_valid = 0;
+
+ siw_dbg_pd(pd, "STag 0x%08x now invalid\n", stag);
+out:
+ siw_mem_put(mem);
+ return rv;
+}
+
+/*
+ * Gets physical address backed by PBL element. Address is referenced
+ * by linear byte offset into list of variably sized PB elements.
+ * Optionally, provides remaining len within current element, and
+ * current PBL index for later resume at same element.
+ */
+u64 siw_pbl_get_buffer(struct siw_pbl *pbl, u64 off, int *len, int *idx)
+{
+ int i = idx ? *idx : 0;
+
+ while (i < pbl->num_buf) {
+ struct siw_pble *pble = &pbl->pbe[i];
+
+ if (pble->pbl_off + pble->size > off) {
+ u64 pble_off = off - pble->pbl_off;
+
+ if (len)
+ *len = pble->size - pble_off;
+ if (idx)
+ *idx = i;
+
+ return pble->addr + pble_off;
+ }
+ i++;
+ }
+ if (len)
+ *len = 0;
+ return 0;
+}
+
+struct siw_pbl *siw_pbl_alloc(u32 num_buf)
+{
+ struct siw_pbl *pbl;
+ int buf_size = sizeof(*pbl);
+
+ if (num_buf == 0)
+ return ERR_PTR(-EINVAL);
+
+ buf_size += ((num_buf - 1) * sizeof(struct siw_pble));
+
+ pbl = kzalloc(buf_size, GFP_KERNEL);
+ if (!pbl)
+ return ERR_PTR(-ENOMEM);
+
+ pbl->max_buf = num_buf;
+
+ return pbl;
+}
+
+struct siw_umem *siw_umem_get(u64 start, u64 len, bool writable)
+{
+ struct siw_umem *umem;
+ struct mm_struct *mm_s;
+ u64 first_page_va;
+ unsigned long mlock_limit;
+ unsigned int foll_flags = FOLL_WRITE;
+ int num_pages, num_chunks, i, rv = 0;
+
+ if (!can_do_mlock())
+ return ERR_PTR(-EPERM);
+
+ if (!len)
+ return ERR_PTR(-EINVAL);
+
+ first_page_va = start & PAGE_MASK;
+ num_pages = PAGE_ALIGN(start + len - first_page_va) >> PAGE_SHIFT;
+ num_chunks = (num_pages >> CHUNK_SHIFT) + 1;
+
+ umem = kzalloc(sizeof(*umem), GFP_KERNEL);
+ if (!umem)
+ return ERR_PTR(-ENOMEM);
+
+ mm_s = current->mm;
+ umem->owning_mm = mm_s;
+ umem->writable = writable;
+
+ mmgrab(mm_s);
+
+ if (!writable)
+ foll_flags |= FOLL_FORCE;
+
+ down_read(&mm_s->mmap_sem);
+
+ mlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
+
+ if (num_pages + atomic64_read(&mm_s->pinned_vm) > mlock_limit) {
+ rv = -ENOMEM;
+ goto out_sem_up;
+ }
+ umem->fp_addr = first_page_va;
+
+ umem->page_chunk =
+ kcalloc(num_chunks, sizeof(struct siw_page_chunk), GFP_KERNEL);
+ if (!umem->page_chunk) {
+ rv = -ENOMEM;
+ goto out_sem_up;
+ }
+ for (i = 0; num_pages; i++) {
+ int got, nents = min_t(int, num_pages, PAGES_PER_CHUNK);
+
+ umem->page_chunk[i].plist =
+ kcalloc(nents, sizeof(struct page *), GFP_KERNEL);
+ if (!umem->page_chunk[i].plist) {
+ rv = -ENOMEM;
+ goto out_sem_up;
+ }
+ got = 0;
+ while (nents) {
+ struct page **plist = &umem->page_chunk[i].plist[got];
+
+ rv = get_user_pages(first_page_va, nents,
+ foll_flags | FOLL_LONGTERM,
+ plist, NULL);
+ if (rv < 0)
+ goto out_sem_up;
+
+ umem->num_pages += rv;
+ atomic64_add(rv, &mm_s->pinned_vm);
+ first_page_va += rv * PAGE_SIZE;
+ nents -= rv;
+ got += rv;
+ }
+ num_pages -= got;
+ }
+out_sem_up:
+ up_read(&mm_s->mmap_sem);
+
+ if (rv > 0)
+ return umem;
+
+ siw_umem_release(umem, false);
+
+ return ERR_PTR(rv);
+}
diff --git a/drivers/infiniband/sw/siw/siw_mem.h b/drivers/infiniband/sw/siw/siw_mem.h
new file mode 100644
index 000000000000..f43daf280891
--- /dev/null
+++ b/drivers/infiniband/sw/siw/siw_mem.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
+
+/* Authors: Bernard Metzler <bmt@zurich.ibm.com> */
+/* Copyright (c) 2008-2019, IBM Corporation */
+
+#ifndef _SIW_MEM_H
+#define _SIW_MEM_H
+
+struct siw_umem *siw_umem_get(u64 start, u64 len, bool writable);
+void siw_umem_release(struct siw_umem *umem, bool dirty);
+struct siw_pbl *siw_pbl_alloc(u32 num_buf);
+u64 siw_pbl_get_buffer(struct siw_pbl *pbl, u64 off, int *len, int *idx);
+struct siw_mem *siw_mem_id2obj(struct siw_device *sdev, int stag_index);
+int siw_mem_add(struct siw_device *sdev, struct siw_mem *m);
+int siw_invalidate_stag(struct ib_pd *pd, u32 stag);
+int siw_check_mem(struct ib_pd *pd, struct siw_mem *mem, u64 addr,
+ enum ib_access_flags perms, int len);
+int siw_check_sge(struct ib_pd *pd, struct siw_sge *sge,
+ struct siw_mem *mem[], enum ib_access_flags perms,
+ u32 off, int len);
+void siw_wqe_put_mem(struct siw_wqe *wqe, enum siw_opcode op);
+int siw_mr_add_mem(struct siw_mr *mr, struct ib_pd *pd, void *mem_obj,
+ u64 start, u64 len, int rights);
+void siw_mr_drop_mem(struct siw_mr *mr);
+void siw_free_mem(struct kref *ref);
+
+static inline void siw_mem_put(struct siw_mem *mem)
+{
+ kref_put(&mem->ref, siw_free_mem);
+}
+
+static inline struct siw_mr *siw_mem2mr(struct siw_mem *m)
+{
+ return container_of(m, struct siw_mr, mem);
+}
+
+static inline void siw_unref_mem_sgl(struct siw_mem **mem, unsigned int num_sge)
+{
+ while (num_sge) {
+ if (*mem == NULL)
+ break;
+
+ siw_mem_put(*mem);
+ *mem = NULL;
+ mem++;
+ num_sge--;
+ }
+}
+
+#define CHUNK_SHIFT 9 /* sets number of pages per chunk */
+#define PAGES_PER_CHUNK (_AC(1, UL) << CHUNK_SHIFT)
+#define CHUNK_MASK (~(PAGES_PER_CHUNK - 1))
+#define PAGE_CHUNK_SIZE (PAGES_PER_CHUNK * sizeof(struct page *))
+
+/*
+ * siw_get_upage()
+ *
+ * Get page pointer for address on given umem.
+ *
+ * @umem: two dimensional list of page pointers
+ * @addr: user virtual address
+ */
+static inline struct page *siw_get_upage(struct siw_umem *umem, u64 addr)
+{
+ unsigned int page_idx = (addr - umem->fp_addr) >> PAGE_SHIFT,
+ chunk_idx = page_idx >> CHUNK_SHIFT,
+ page_in_chunk = page_idx & ~CHUNK_MASK;
+
+ if (likely(page_idx < umem->num_pages))
+ return umem->page_chunk[chunk_idx].plist[page_in_chunk];
+
+ return NULL;
+}
+#endif
diff --git a/drivers/infiniband/sw/siw/siw_qp.c b/drivers/infiniband/sw/siw/siw_qp.c
new file mode 100644
index 000000000000..11383d9f95ef
--- /dev/null
+++ b/drivers/infiniband/sw/siw/siw_qp.c
@@ -0,0 +1,1322 @@
+// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause
+
+/* Authors: Bernard Metzler <bmt@zurich.ibm.com> */
+/* Copyright (c) 2008-2019, IBM Corporation */
+
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/net.h>
+#include <linux/scatterlist.h>
+#include <linux/llist.h>
+#include <asm/barrier.h>
+#include <net/tcp.h>
+
+#include "siw.h"
+#include "siw_verbs.h"
+#include "siw_mem.h"
+
+static char siw_qp_state_to_string[SIW_QP_STATE_COUNT][sizeof "TERMINATE"] = {
+ [SIW_QP_STATE_IDLE] = "IDLE",
+ [SIW_QP_STATE_RTR] = "RTR",
+ [SIW_QP_STATE_RTS] = "RTS",
+ [SIW_QP_STATE_CLOSING] = "CLOSING",
+ [SIW_QP_STATE_TERMINATE] = "TERMINATE",
+ [SIW_QP_STATE_ERROR] = "ERROR"
+};
+
+/*
+ * iWARP (RDMAP, DDP and MPA) parameters as well as Softiwarp settings on a
+ * per-RDMAP message basis. Please keep order of initializer. All MPA len
+ * is initialized to minimum packet size.
+ */
+struct iwarp_msg_info iwarp_pktinfo[RDMAP_TERMINATE + 1] = {
+ { /* RDMAP_RDMA_WRITE */
+ .hdr_len = sizeof(struct iwarp_rdma_write),
+ .ctrl.mpa_len = htons(sizeof(struct iwarp_rdma_write) - 2),
+ .ctrl.ddp_rdmap_ctrl = DDP_FLAG_TAGGED | DDP_FLAG_LAST |
+ cpu_to_be16(DDP_VERSION << 8) |
+ cpu_to_be16(RDMAP_VERSION << 6) |
+ cpu_to_be16(RDMAP_RDMA_WRITE),
+ .rx_data = siw_proc_write },
+ { /* RDMAP_RDMA_READ_REQ */
+ .hdr_len = sizeof(struct iwarp_rdma_rreq),
+ .ctrl.mpa_len = htons(sizeof(struct iwarp_rdma_rreq) - 2),
+ .ctrl.ddp_rdmap_ctrl = DDP_FLAG_LAST | cpu_to_be16(DDP_VERSION << 8) |
+ cpu_to_be16(RDMAP_VERSION << 6) |
+ cpu_to_be16(RDMAP_RDMA_READ_REQ),
+ .rx_data = siw_proc_rreq },
+ { /* RDMAP_RDMA_READ_RESP */
+ .hdr_len = sizeof(struct iwarp_rdma_rresp),
+ .ctrl.mpa_len = htons(sizeof(struct iwarp_rdma_rresp) - 2),
+ .ctrl.ddp_rdmap_ctrl = DDP_FLAG_TAGGED | DDP_FLAG_LAST |
+ cpu_to_be16(DDP_VERSION << 8) |
+ cpu_to_be16(RDMAP_VERSION << 6) |
+ cpu_to_be16(RDMAP_RDMA_READ_RESP),
+ .rx_data = siw_proc_rresp },
+ { /* RDMAP_SEND */
+ .hdr_len = sizeof(struct iwarp_send),
+ .ctrl.mpa_len = htons(sizeof(struct iwarp_send) - 2),
+ .ctrl.ddp_rdmap_ctrl = DDP_FLAG_LAST | cpu_to_be16(DDP_VERSION << 8) |
+ cpu_to_be16(RDMAP_VERSION << 6) |
+ cpu_to_be16(RDMAP_SEND),
+ .rx_data = siw_proc_send },
+ { /* RDMAP_SEND_INVAL */
+ .hdr_len = sizeof(struct iwarp_send_inv),
+ .ctrl.mpa_len = htons(sizeof(struct iwarp_send_inv) - 2),
+ .ctrl.ddp_rdmap_ctrl = DDP_FLAG_LAST | cpu_to_be16(DDP_VERSION << 8) |
+ cpu_to_be16(RDMAP_VERSION << 6) |
+ cpu_to_be16(RDMAP_SEND_INVAL),
+ .rx_data = siw_proc_send },
+ { /* RDMAP_SEND_SE */
+ .hdr_len = sizeof(struct iwarp_send),
+ .ctrl.mpa_len = htons(sizeof(struct iwarp_send) - 2),
+ .ctrl.ddp_rdmap_ctrl = DDP_FLAG_LAST | cpu_to_be16(DDP_VERSION << 8) |
+ cpu_to_be16(RDMAP_VERSION << 6) |
+ cpu_to_be16(RDMAP_SEND_SE),
+ .rx_data = siw_proc_send },
+ { /* RDMAP_SEND_SE_INVAL */
+ .hdr_len = sizeof(struct iwarp_send_inv),
+ .ctrl.mpa_len = htons(sizeof(struct iwarp_send_inv) - 2),
+ .ctrl.ddp_rdmap_ctrl = DDP_FLAG_LAST | cpu_to_be16(DDP_VERSION << 8) |
+ cpu_to_be16(RDMAP_VERSION << 6) |
+ cpu_to_be16(RDMAP_SEND_SE_INVAL),
+ .rx_data = siw_proc_send },
+ { /* RDMAP_TERMINATE */
+ .hdr_len = sizeof(struct iwarp_terminate),
+ .ctrl.mpa_len = htons(sizeof(struct iwarp_terminate) - 2),
+ .ctrl.ddp_rdmap_ctrl = DDP_FLAG_LAST | cpu_to_be16(DDP_VERSION << 8) |
+ cpu_to_be16(RDMAP_VERSION << 6) |
+ cpu_to_be16(RDMAP_TERMINATE),
+ .rx_data = siw_proc_terminate }
+};
+
+void siw_qp_llp_data_ready(struct sock *sk)
+{
+ struct siw_qp *qp;
+
+ read_lock(&sk->sk_callback_lock);
+
+ if (unlikely(!sk->sk_user_data || !sk_to_qp(sk)))
+ goto done;
+
+ qp = sk_to_qp(sk);
+
+ if (likely(!qp->rx_stream.rx_suspend &&
+ down_read_trylock(&qp->state_lock))) {
+ read_descriptor_t rd_desc = { .arg.data = qp, .count = 1 };
+
+ if (likely(qp->attrs.state == SIW_QP_STATE_RTS))
+ /*
+ * Implements data receive operation during
+ * socket callback. TCP gracefully catches
+ * the case where there is nothing to receive
+ * (not calling siw_tcp_rx_data() then).
+ */
+ tcp_read_sock(sk, &rd_desc, siw_tcp_rx_data);
+
+ up_read(&qp->state_lock);
+ } else {
+ siw_dbg_qp(qp, "unable to process RX, suspend: %d\n",
+ qp->rx_stream.rx_suspend);
+ }
+done:
+ read_unlock(&sk->sk_callback_lock);
+}
+
+void siw_qp_llp_close(struct siw_qp *qp)
+{
+ siw_dbg_qp(qp, "enter llp close, state = %s\n",
+ siw_qp_state_to_string[qp->attrs.state]);
+
+ down_write(&qp->state_lock);
+
+ qp->rx_stream.rx_suspend = 1;
+ qp->tx_ctx.tx_suspend = 1;
+ qp->attrs.sk = NULL;
+
+ switch (qp->attrs.state) {
+ case SIW_QP_STATE_RTS:
+ case SIW_QP_STATE_RTR:
+ case SIW_QP_STATE_IDLE:
+ case SIW_QP_STATE_TERMINATE:
+ qp->attrs.state = SIW_QP_STATE_ERROR;
+ break;
+ /*
+ * SIW_QP_STATE_CLOSING:
+ *
+ * This is a forced close. shall the QP be moved to
+ * ERROR or IDLE ?
+ */
+ case SIW_QP_STATE_CLOSING:
+ if (tx_wqe(qp)->wr_status == SIW_WR_IDLE)
+ qp->attrs.state = SIW_QP_STATE_ERROR;
+ else
+ qp->attrs.state = SIW_QP_STATE_IDLE;
+ break;
+
+ default:
+ siw_dbg_qp(qp, "llp close: no state transition needed: %s\n",
+ siw_qp_state_to_string[qp->attrs.state]);
+ break;
+ }
+ siw_sq_flush(qp);
+ siw_rq_flush(qp);
+
+ /*
+ * Dereference closing CEP
+ */
+ if (qp->cep) {
+ siw_cep_put(qp->cep);
+ qp->cep = NULL;
+ }
+
+ up_write(&qp->state_lock);
+
+ siw_dbg_qp(qp, "llp close exit: state %s\n",
+ siw_qp_state_to_string[qp->attrs.state]);
+}
+
+/*
+ * socket callback routine informing about newly available send space.
+ * Function schedules SQ work for processing SQ items.
+ */
+void siw_qp_llp_write_space(struct sock *sk)
+{
+ struct siw_cep *cep = sk_to_cep(sk);
+
+ cep->sk_write_space(sk);
+
+ if (!test_bit(SOCK_NOSPACE, &sk->sk_socket->flags))
+ (void)siw_sq_start(cep->qp);
+}
+
+static int siw_qp_readq_init(struct siw_qp *qp, int irq_size, int orq_size)
+{
+ irq_size = roundup_pow_of_two(irq_size);
+ orq_size = roundup_pow_of_two(orq_size);
+
+ qp->attrs.irq_size = irq_size;
+ qp->attrs.orq_size = orq_size;
+
+ qp->irq = vzalloc(irq_size * sizeof(struct siw_sqe));
+ if (!qp->irq) {
+ siw_dbg_qp(qp, "irq malloc for %d failed\n", irq_size);
+ qp->attrs.irq_size = 0;
+ return -ENOMEM;
+ }
+ qp->orq = vzalloc(orq_size * sizeof(struct siw_sqe));
+ if (!qp->orq) {
+ siw_dbg_qp(qp, "orq malloc for %d failed\n", orq_size);
+ qp->attrs.orq_size = 0;
+ qp->attrs.irq_size = 0;
+ vfree(qp->irq);
+ return -ENOMEM;
+ }
+ siw_dbg_qp(qp, "ORD %d, IRD %d\n", orq_size, irq_size);
+ return 0;
+}
+
+static int siw_qp_enable_crc(struct siw_qp *qp)
+{
+ struct siw_rx_stream *c_rx = &qp->rx_stream;
+ struct siw_iwarp_tx *c_tx = &qp->tx_ctx;
+ int size = crypto_shash_descsize(siw_crypto_shash) +
+ sizeof(struct shash_desc);
+
+ if (siw_crypto_shash == NULL)
+ return -ENOENT;
+
+ c_tx->mpa_crc_hd = kzalloc(size, GFP_KERNEL);
+ c_rx->mpa_crc_hd = kzalloc(size, GFP_KERNEL);
+ if (!c_tx->mpa_crc_hd || !c_rx->mpa_crc_hd) {
+ kfree(c_tx->mpa_crc_hd);
+ kfree(c_rx->mpa_crc_hd);
+ c_tx->mpa_crc_hd = NULL;
+ c_rx->mpa_crc_hd = NULL;
+ return -ENOMEM;
+ }
+ c_tx->mpa_crc_hd->tfm = siw_crypto_shash;
+ c_rx->mpa_crc_hd->tfm = siw_crypto_shash;
+
+ return 0;
+}
+
+/*
+ * Send a non signalled READ or WRITE to peer side as negotiated
+ * with MPAv2 P2P setup protocol. The work request is only created
+ * as a current active WR and does not consume Send Queue space.
+ *
+ * Caller must hold QP state lock.
+ */
+int siw_qp_mpa_rts(struct siw_qp *qp, enum mpa_v2_ctrl ctrl)
+{
+ struct siw_wqe *wqe = tx_wqe(qp);
+ unsigned long flags;
+ int rv = 0;
+
+ spin_lock_irqsave(&qp->sq_lock, flags);
+
+ if (unlikely(wqe->wr_status != SIW_WR_IDLE)) {
+ spin_unlock_irqrestore(&qp->sq_lock, flags);
+ return -EIO;
+ }
+ memset(wqe->mem, 0, sizeof(*wqe->mem) * SIW_MAX_SGE);
+
+ wqe->wr_status = SIW_WR_QUEUED;
+ wqe->sqe.flags = 0;
+ wqe->sqe.num_sge = 1;
+ wqe->sqe.sge[0].length = 0;
+ wqe->sqe.sge[0].laddr = 0;
+ wqe->sqe.sge[0].lkey = 0;
+ /*
+ * While it must not be checked for inbound zero length
+ * READ/WRITE, some HW may treat STag 0 special.
+ */
+ wqe->sqe.rkey = 1;
+ wqe->sqe.raddr = 0;
+ wqe->processed = 0;
+
+ if (ctrl & MPA_V2_RDMA_WRITE_RTR)
+ wqe->sqe.opcode = SIW_OP_WRITE;
+ else if (ctrl & MPA_V2_RDMA_READ_RTR) {
+ struct siw_sqe *rreq;
+
+ wqe->sqe.opcode = SIW_OP_READ;
+
+ spin_lock(&qp->orq_lock);
+
+ rreq = orq_get_free(qp);
+ if (rreq) {
+ siw_read_to_orq(rreq, &wqe->sqe);
+ qp->orq_put++;
+ } else
+ rv = -EIO;
+
+ spin_unlock(&qp->orq_lock);
+ } else
+ rv = -EINVAL;
+
+ if (rv)
+ wqe->wr_status = SIW_WR_IDLE;
+
+ spin_unlock_irqrestore(&qp->sq_lock, flags);
+
+ if (!rv)
+ rv = siw_sq_start(qp);
+
+ return rv;
+}
+
+/*
+ * Map memory access error to DDP tagged error
+ */
+enum ddp_ecode siw_tagged_error(enum siw_access_state state)
+{
+ switch (state) {
+ case E_STAG_INVALID:
+ return DDP_ECODE_T_INVALID_STAG;
+ case E_BASE_BOUNDS:
+ return DDP_ECODE_T_BASE_BOUNDS;
+ case E_PD_MISMATCH:
+ return DDP_ECODE_T_STAG_NOT_ASSOC;
+ case E_ACCESS_PERM:
+ /*
+ * RFC 5041 (DDP) lacks an ecode for insufficient access
+ * permissions. 'Invalid STag' seem to be the closest
+ * match though.
+ */
+ return DDP_ECODE_T_INVALID_STAG;
+ default:
+ WARN_ON(1);
+ return DDP_ECODE_T_INVALID_STAG;
+ }
+}
+
+/*
+ * Map memory access error to RDMAP protection error
+ */
+enum rdmap_ecode siw_rdmap_error(enum siw_access_state state)
+{
+ switch (state) {
+ case E_STAG_INVALID:
+ return RDMAP_ECODE_INVALID_STAG;
+ case E_BASE_BOUNDS:
+ return RDMAP_ECODE_BASE_BOUNDS;
+ case E_PD_MISMATCH:
+ return RDMAP_ECODE_STAG_NOT_ASSOC;
+ case E_ACCESS_PERM:
+ return RDMAP_ECODE_ACCESS_RIGHTS;
+ default:
+ return RDMAP_ECODE_UNSPECIFIED;
+ }
+}
+
+void siw_init_terminate(struct siw_qp *qp, enum term_elayer layer, u8 etype,
+ u8 ecode, int in_tx)
+{
+ if (!qp->term_info.valid) {
+ memset(&qp->term_info, 0, sizeof(qp->term_info));
+ qp->term_info.layer = layer;
+ qp->term_info.etype = etype;
+ qp->term_info.ecode = ecode;
+ qp->term_info.in_tx = in_tx;
+ qp->term_info.valid = 1;
+ }
+ siw_dbg_qp(qp, "init TERM: layer %d, type %d, code %d, in tx %s\n",
+ layer, etype, ecode, in_tx ? "yes" : "no");
+}
+
+/*
+ * Send a TERMINATE message, as defined in RFC's 5040/5041/5044/6581.
+ * Sending TERMINATE messages is best effort - such messages
+ * can only be send if the QP is still connected and it does
+ * not have another outbound message in-progress, i.e. the
+ * TERMINATE message must not interfer with an incomplete current
+ * transmit operation.
+ */
+void siw_send_terminate(struct siw_qp *qp)
+{
+ struct kvec iov[3];
+ struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_EOR };
+ struct iwarp_terminate *term = NULL;
+ union iwarp_hdr *err_hdr = NULL;
+ struct socket *s = qp->attrs.sk;
+ struct siw_rx_stream *srx = &qp->rx_stream;
+ union iwarp_hdr *rx_hdr = &srx->hdr;
+ u32 crc = 0;
+ int num_frags, len_terminate, rv;
+
+ if (!qp->term_info.valid)
+ return;
+
+ qp->term_info.valid = 0;
+
+ if (tx_wqe(qp)->wr_status == SIW_WR_INPROGRESS) {
+ siw_dbg_qp(qp, "cannot send TERMINATE: op %d in progress\n",
+ tx_type(tx_wqe(qp)));
+ return;
+ }
+ if (!s && qp->cep)
+ /* QP not yet in RTS. Take socket from connection end point */
+ s = qp->cep->sock;
+
+ if (!s) {
+ siw_dbg_qp(qp, "cannot send TERMINATE: not connected\n");
+ return;
+ }
+
+ term = kzalloc(sizeof(*term), GFP_KERNEL);
+ if (!term)
+ return;
+
+ term->ddp_qn = cpu_to_be32(RDMAP_UNTAGGED_QN_TERMINATE);
+ term->ddp_mo = 0;
+ term->ddp_msn = cpu_to_be32(1);
+
+ iov[0].iov_base = term;
+ iov[0].iov_len = sizeof(*term);
+
+ if ((qp->term_info.layer == TERM_ERROR_LAYER_DDP) ||
+ ((qp->term_info.layer == TERM_ERROR_LAYER_RDMAP) &&
+ (qp->term_info.etype != RDMAP_ETYPE_CATASTROPHIC))) {
+ err_hdr = kzalloc(sizeof(*err_hdr), GFP_KERNEL);
+ if (!err_hdr) {
+ kfree(term);
+ return;
+ }
+ }
+ memcpy(&term->ctrl, &iwarp_pktinfo[RDMAP_TERMINATE].ctrl,
+ sizeof(struct iwarp_ctrl));
+
+ __rdmap_term_set_layer(term, qp->term_info.layer);
+ __rdmap_term_set_etype(term, qp->term_info.etype);
+ __rdmap_term_set_ecode(term, qp->term_info.ecode);
+
+ switch (qp->term_info.layer) {
+ case TERM_ERROR_LAYER_RDMAP:
+ if (qp->term_info.etype == RDMAP_ETYPE_CATASTROPHIC)
+ /* No additional DDP/RDMAP header to be included */
+ break;
+
+ if (qp->term_info.etype == RDMAP_ETYPE_REMOTE_PROTECTION) {
+ /*
+ * Complete RDMAP frame will get attached, and
+ * DDP segment length is valid
+ */
+ term->flag_m = 1;
+ term->flag_d = 1;
+ term->flag_r = 1;
+
+ if (qp->term_info.in_tx) {
+ struct iwarp_rdma_rreq *rreq;
+ struct siw_wqe *wqe = tx_wqe(qp);
+
+ /* Inbound RREQ error, detected during
+ * RRESP creation. Take state from
+ * current TX work queue element to
+ * reconstruct peers RREQ.
+ */
+ rreq = (struct iwarp_rdma_rreq *)err_hdr;
+
+ memcpy(&rreq->ctrl,
+ &iwarp_pktinfo[RDMAP_RDMA_READ_REQ].ctrl,
+ sizeof(struct iwarp_ctrl));
+
+ rreq->rsvd = 0;
+ rreq->ddp_qn =
+ htonl(RDMAP_UNTAGGED_QN_RDMA_READ);
+
+ /* Provide RREQ's MSN as kept aside */
+ rreq->ddp_msn = htonl(wqe->sqe.sge[0].length);
+
+ rreq->ddp_mo = htonl(wqe->processed);
+ rreq->sink_stag = htonl(wqe->sqe.rkey);
+ rreq->sink_to = cpu_to_be64(wqe->sqe.raddr);
+ rreq->read_size = htonl(wqe->sqe.sge[0].length);
+ rreq->source_stag = htonl(wqe->sqe.sge[0].lkey);
+ rreq->source_to =
+ cpu_to_be64(wqe->sqe.sge[0].laddr);
+
+ iov[1].iov_base = rreq;
+ iov[1].iov_len = sizeof(*rreq);
+
+ rx_hdr = (union iwarp_hdr *)rreq;
+ } else {
+ /* Take RDMAP/DDP information from
+ * current (failed) inbound frame.
+ */
+ iov[1].iov_base = rx_hdr;
+
+ if (__rdmap_get_opcode(&rx_hdr->ctrl) ==
+ RDMAP_RDMA_READ_REQ)
+ iov[1].iov_len =
+ sizeof(struct iwarp_rdma_rreq);
+ else /* SEND type */
+ iov[1].iov_len =
+ sizeof(struct iwarp_send);
+ }
+ } else {
+ /* Do not report DDP hdr information if packet
+ * layout is unknown
+ */
+ if ((qp->term_info.ecode == RDMAP_ECODE_VERSION) ||
+ (qp->term_info.ecode == RDMAP_ECODE_OPCODE))
+ break;
+
+ iov[1].iov_base = rx_hdr;
+
+ /* Only DDP frame will get attached */
+ if (rx_hdr->ctrl.ddp_rdmap_ctrl & DDP_FLAG_TAGGED)
+ iov[1].iov_len =
+ sizeof(struct iwarp_rdma_write);
+ else
+ iov[1].iov_len = sizeof(struct iwarp_send);
+
+ term->flag_m = 1;
+ term->flag_d = 1;
+ }
+ term->ctrl.mpa_len = cpu_to_be16(iov[1].iov_len);
+ break;
+
+ case TERM_ERROR_LAYER_DDP:
+ /* Report error encountered while DDP processing.
+ * This can only happen as a result of inbound
+ * DDP processing
+ */
+
+ /* Do not report DDP hdr information if packet
+ * layout is unknown
+ */
+ if (((qp->term_info.etype == DDP_ETYPE_TAGGED_BUF) &&
+ (qp->term_info.ecode == DDP_ECODE_T_VERSION)) ||
+ ((qp->term_info.etype == DDP_ETYPE_UNTAGGED_BUF) &&
+ (qp->term_info.ecode == DDP_ECODE_UT_VERSION)))
+ break;
+
+ iov[1].iov_base = rx_hdr;
+
+ if (rx_hdr->ctrl.ddp_rdmap_ctrl & DDP_FLAG_TAGGED)
+ iov[1].iov_len = sizeof(struct iwarp_ctrl_tagged);
+ else
+ iov[1].iov_len = sizeof(struct iwarp_ctrl_untagged);
+
+ term->flag_m = 1;
+ term->flag_d = 1;
+ break;
+
+ default:
+ break;
+ }
+ if (term->flag_m || term->flag_d || term->flag_r) {
+ iov[2].iov_base = &crc;
+ iov[2].iov_len = sizeof(crc);
+ len_terminate = sizeof(*term) + iov[1].iov_len + MPA_CRC_SIZE;
+ num_frags = 3;
+ } else {
+ iov[1].iov_base = &crc;
+ iov[1].iov_len = sizeof(crc);
+ len_terminate = sizeof(*term) + MPA_CRC_SIZE;
+ num_frags = 2;
+ }
+
+ /* Adjust DDP Segment Length parameter, if valid */
+ if (term->flag_m) {
+ u32 real_ddp_len = be16_to_cpu(rx_hdr->ctrl.mpa_len);
+ enum rdma_opcode op = __rdmap_get_opcode(&rx_hdr->ctrl);
+
+ real_ddp_len -= iwarp_pktinfo[op].hdr_len - MPA_HDR_SIZE;
+ rx_hdr->ctrl.mpa_len = cpu_to_be16(real_ddp_len);
+ }
+
+ term->ctrl.mpa_len =
+ cpu_to_be16(len_terminate - (MPA_HDR_SIZE + MPA_CRC_SIZE));
+ if (qp->tx_ctx.mpa_crc_hd) {
+ crypto_shash_init(qp->tx_ctx.mpa_crc_hd);
+ if (crypto_shash_update(qp->tx_ctx.mpa_crc_hd,
+ (u8 *)iov[0].iov_base,
+ iov[0].iov_len))
+ goto out;
+
+ if (num_frags == 3) {
+ if (crypto_shash_update(qp->tx_ctx.mpa_crc_hd,
+ (u8 *)iov[1].iov_base,
+ iov[1].iov_len))
+ goto out;
+ }
+ crypto_shash_final(qp->tx_ctx.mpa_crc_hd, (u8 *)&crc);
+ }
+
+ rv = kernel_sendmsg(s, &msg, iov, num_frags, len_terminate);
+ siw_dbg_qp(qp, "sent TERM: %s, layer %d, type %d, code %d (%d bytes)\n",
+ rv == len_terminate ? "success" : "failure",
+ __rdmap_term_layer(term), __rdmap_term_etype(term),
+ __rdmap_term_ecode(term), rv);
+out:
+ kfree(term);
+ kfree(err_hdr);
+}
+
+/*
+ * Handle all attrs other than state
+ */
+static void siw_qp_modify_nonstate(struct siw_qp *qp,
+ struct siw_qp_attrs *attrs,
+ enum siw_qp_attr_mask mask)
+{
+ if (mask & SIW_QP_ATTR_ACCESS_FLAGS) {
+ if (attrs->flags & SIW_RDMA_BIND_ENABLED)
+ qp->attrs.flags |= SIW_RDMA_BIND_ENABLED;
+ else
+ qp->attrs.flags &= ~SIW_RDMA_BIND_ENABLED;
+
+ if (attrs->flags & SIW_RDMA_WRITE_ENABLED)
+ qp->attrs.flags |= SIW_RDMA_WRITE_ENABLED;
+ else
+ qp->attrs.flags &= ~SIW_RDMA_WRITE_ENABLED;
+
+ if (attrs->flags & SIW_RDMA_READ_ENABLED)
+ qp->attrs.flags |= SIW_RDMA_READ_ENABLED;
+ else
+ qp->attrs.flags &= ~SIW_RDMA_READ_ENABLED;
+ }
+}
+
+static int siw_qp_nextstate_from_idle(struct siw_qp *qp,
+ struct siw_qp_attrs *attrs,
+ enum siw_qp_attr_mask mask)
+{
+ int rv = 0;
+
+ switch (attrs->state) {
+ case SIW_QP_STATE_RTS:
+ if (attrs->flags & SIW_MPA_CRC) {
+ rv = siw_qp_enable_crc(qp);
+ if (rv)
+ break;
+ }
+ if (!(mask & SIW_QP_ATTR_LLP_HANDLE)) {
+ siw_dbg_qp(qp, "no socket\n");
+ rv = -EINVAL;
+ break;
+ }
+ if (!(mask & SIW_QP_ATTR_MPA)) {
+ siw_dbg_qp(qp, "no MPA\n");
+ rv = -EINVAL;
+ break;
+ }
+ /*
+ * Initialize iWARP TX state
+ */
+ qp->tx_ctx.ddp_msn[RDMAP_UNTAGGED_QN_SEND] = 0;
+ qp->tx_ctx.ddp_msn[RDMAP_UNTAGGED_QN_RDMA_READ] = 0;
+ qp->tx_ctx.ddp_msn[RDMAP_UNTAGGED_QN_TERMINATE] = 0;
+
+ /*
+ * Initialize iWARP RX state
+ */
+ qp->rx_stream.ddp_msn[RDMAP_UNTAGGED_QN_SEND] = 1;
+ qp->rx_stream.ddp_msn[RDMAP_UNTAGGED_QN_RDMA_READ] = 1;
+ qp->rx_stream.ddp_msn[RDMAP_UNTAGGED_QN_TERMINATE] = 1;
+
+ /*
+ * init IRD free queue, caller has already checked
+ * limits.
+ */
+ rv = siw_qp_readq_init(qp, attrs->irq_size,
+ attrs->orq_size);
+ if (rv)
+ break;
+
+ qp->attrs.sk = attrs->sk;
+ qp->attrs.state = SIW_QP_STATE_RTS;
+
+ siw_dbg_qp(qp, "enter RTS: crc=%s, ord=%u, ird=%u\n",
+ attrs->flags & SIW_MPA_CRC ? "y" : "n",
+ qp->attrs.orq_size, qp->attrs.irq_size);
+ break;
+
+ case SIW_QP_STATE_ERROR:
+ siw_rq_flush(qp);
+ qp->attrs.state = SIW_QP_STATE_ERROR;
+ if (qp->cep) {
+ siw_cep_put(qp->cep);
+ qp->cep = NULL;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return rv;
+}
+
+static int siw_qp_nextstate_from_rts(struct siw_qp *qp,
+ struct siw_qp_attrs *attrs)
+{
+ int drop_conn = 0;
+
+ switch (attrs->state) {
+ case SIW_QP_STATE_CLOSING:
+ /*
+ * Verbs: move to IDLE if SQ and ORQ are empty.
+ * Move to ERROR otherwise. But first of all we must
+ * close the connection. So we keep CLOSING or ERROR
+ * as a transient state, schedule connection drop work
+ * and wait for the socket state change upcall to
+ * come back closed.
+ */
+ if (tx_wqe(qp)->wr_status == SIW_WR_IDLE) {
+ qp->attrs.state = SIW_QP_STATE_CLOSING;
+ } else {
+ qp->attrs.state = SIW_QP_STATE_ERROR;
+ siw_sq_flush(qp);
+ }
+ siw_rq_flush(qp);
+
+ drop_conn = 1;
+ break;
+
+ case SIW_QP_STATE_TERMINATE:
+ qp->attrs.state = SIW_QP_STATE_TERMINATE;
+
+ siw_init_terminate(qp, TERM_ERROR_LAYER_RDMAP,
+ RDMAP_ETYPE_CATASTROPHIC,
+ RDMAP_ECODE_UNSPECIFIED, 1);
+ drop_conn = 1;
+ break;
+
+ case SIW_QP_STATE_ERROR:
+ /*
+ * This is an emergency close.
+ *
+ * Any in progress transmit operation will get
+ * cancelled.
+ * This will likely result in a protocol failure,
+ * if a TX operation is in transit. The caller
+ * could unconditional wait to give the current
+ * operation a chance to complete.
+ * Esp., how to handle the non-empty IRQ case?
+ * The peer was asking for data transfer at a valid
+ * point in time.
+ */
+ siw_sq_flush(qp);
+ siw_rq_flush(qp);
+ qp->attrs.state = SIW_QP_STATE_ERROR;
+ drop_conn = 1;
+ break;
+
+ default:
+ break;
+ }
+ return drop_conn;
+}
+
+static void siw_qp_nextstate_from_term(struct siw_qp *qp,
+ struct siw_qp_attrs *attrs)
+{
+ switch (attrs->state) {
+ case SIW_QP_STATE_ERROR:
+ siw_rq_flush(qp);
+ qp->attrs.state = SIW_QP_STATE_ERROR;
+
+ if (tx_wqe(qp)->wr_status != SIW_WR_IDLE)
+ siw_sq_flush(qp);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static int siw_qp_nextstate_from_close(struct siw_qp *qp,
+ struct siw_qp_attrs *attrs)
+{
+ int rv = 0;
+
+ switch (attrs->state) {
+ case SIW_QP_STATE_IDLE:
+ WARN_ON(tx_wqe(qp)->wr_status != SIW_WR_IDLE);
+ qp->attrs.state = SIW_QP_STATE_IDLE;
+ break;
+
+ case SIW_QP_STATE_CLOSING:
+ /*
+ * The LLP may already moved the QP to closing
+ * due to graceful peer close init
+ */
+ break;
+
+ case SIW_QP_STATE_ERROR:
+ /*
+ * QP was moved to CLOSING by LLP event
+ * not yet seen by user.
+ */
+ qp->attrs.state = SIW_QP_STATE_ERROR;
+
+ if (tx_wqe(qp)->wr_status != SIW_WR_IDLE)
+ siw_sq_flush(qp);
+
+ siw_rq_flush(qp);
+ break;
+
+ default:
+ siw_dbg_qp(qp, "state transition undefined: %s => %s\n",
+ siw_qp_state_to_string[qp->attrs.state],
+ siw_qp_state_to_string[attrs->state]);
+
+ rv = -ECONNABORTED;
+ }
+ return rv;
+}
+
+/*
+ * Caller must hold qp->state_lock
+ */
+int siw_qp_modify(struct siw_qp *qp, struct siw_qp_attrs *attrs,
+ enum siw_qp_attr_mask mask)
+{
+ int drop_conn = 0, rv = 0;
+
+ if (!mask)
+ return 0;
+
+ siw_dbg_qp(qp, "state: %s => %s\n",
+ siw_qp_state_to_string[qp->attrs.state],
+ siw_qp_state_to_string[attrs->state]);
+
+ if (mask != SIW_QP_ATTR_STATE)
+ siw_qp_modify_nonstate(qp, attrs, mask);
+
+ if (!(mask & SIW_QP_ATTR_STATE))
+ return 0;
+
+ switch (qp->attrs.state) {
+ case SIW_QP_STATE_IDLE:
+ case SIW_QP_STATE_RTR:
+ rv = siw_qp_nextstate_from_idle(qp, attrs, mask);
+ break;
+
+ case SIW_QP_STATE_RTS:
+ drop_conn = siw_qp_nextstate_from_rts(qp, attrs);
+ break;
+
+ case SIW_QP_STATE_TERMINATE:
+ siw_qp_nextstate_from_term(qp, attrs);
+ break;
+
+ case SIW_QP_STATE_CLOSING:
+ siw_qp_nextstate_from_close(qp, attrs);
+ break;
+ default:
+ break;
+ }
+ if (drop_conn)
+ siw_qp_cm_drop(qp, 0);
+
+ return rv;
+}
+
+void siw_read_to_orq(struct siw_sqe *rreq, struct siw_sqe *sqe)
+{
+ rreq->id = sqe->id;
+ rreq->opcode = sqe->opcode;
+ rreq->sge[0].laddr = sqe->sge[0].laddr;
+ rreq->sge[0].length = sqe->sge[0].length;
+ rreq->sge[0].lkey = sqe->sge[0].lkey;
+ rreq->sge[1].lkey = sqe->sge[1].lkey;
+ rreq->flags = sqe->flags | SIW_WQE_VALID;
+ rreq->num_sge = 1;
+}
+
+/*
+ * Must be called with SQ locked.
+ * To avoid complete SQ starvation by constant inbound READ requests,
+ * the active IRQ will not be served after qp->irq_burst, if the
+ * SQ has pending work.
+ */
+int siw_activate_tx(struct siw_qp *qp)
+{
+ struct siw_sqe *irqe, *sqe;
+ struct siw_wqe *wqe = tx_wqe(qp);
+ int rv = 1;
+
+ irqe = &qp->irq[qp->irq_get % qp->attrs.irq_size];
+
+ if (irqe->flags & SIW_WQE_VALID) {
+ sqe = sq_get_next(qp);
+
+ /*
+ * Avoid local WQE processing starvation in case
+ * of constant inbound READ request stream
+ */
+ if (sqe && ++qp->irq_burst >= SIW_IRQ_MAXBURST_SQ_ACTIVE) {
+ qp->irq_burst = 0;
+ goto skip_irq;
+ }
+ memset(wqe->mem, 0, sizeof(*wqe->mem) * SIW_MAX_SGE);
+ wqe->wr_status = SIW_WR_QUEUED;
+
+ /* start READ RESPONSE */
+ wqe->sqe.opcode = SIW_OP_READ_RESPONSE;
+ wqe->sqe.flags = 0;
+ if (irqe->num_sge) {
+ wqe->sqe.num_sge = 1;
+ wqe->sqe.sge[0].length = irqe->sge[0].length;
+ wqe->sqe.sge[0].laddr = irqe->sge[0].laddr;
+ wqe->sqe.sge[0].lkey = irqe->sge[0].lkey;
+ } else {
+ wqe->sqe.num_sge = 0;
+ }
+
+ /* Retain original RREQ's message sequence number for
+ * potential error reporting cases.
+ */
+ wqe->sqe.sge[1].length = irqe->sge[1].length;
+
+ wqe->sqe.rkey = irqe->rkey;
+ wqe->sqe.raddr = irqe->raddr;
+
+ wqe->processed = 0;
+ qp->irq_get++;
+
+ /* mark current IRQ entry free */
+ smp_store_mb(irqe->flags, 0);
+
+ goto out;
+ }
+ sqe = sq_get_next(qp);
+ if (sqe) {
+skip_irq:
+ memset(wqe->mem, 0, sizeof(*wqe->mem) * SIW_MAX_SGE);
+ wqe->wr_status = SIW_WR_QUEUED;
+
+ /* First copy SQE to kernel private memory */
+ memcpy(&wqe->sqe, sqe, sizeof(*sqe));
+
+ if (wqe->sqe.opcode >= SIW_NUM_OPCODES) {
+ rv = -EINVAL;
+ goto out;
+ }
+ if (wqe->sqe.flags & SIW_WQE_INLINE) {
+ if (wqe->sqe.opcode != SIW_OP_SEND &&
+ wqe->sqe.opcode != SIW_OP_WRITE) {
+ rv = -EINVAL;
+ goto out;
+ }
+ if (wqe->sqe.sge[0].length > SIW_MAX_INLINE) {
+ rv = -EINVAL;
+ goto out;
+ }
+ wqe->sqe.sge[0].laddr = (u64)&wqe->sqe.sge[1];
+ wqe->sqe.sge[0].lkey = 0;
+ wqe->sqe.num_sge = 1;
+ }
+ if (wqe->sqe.flags & SIW_WQE_READ_FENCE) {
+ /* A READ cannot be fenced */
+ if (unlikely(wqe->sqe.opcode == SIW_OP_READ ||
+ wqe->sqe.opcode ==
+ SIW_OP_READ_LOCAL_INV)) {
+ siw_dbg_qp(qp, "cannot fence read\n");
+ rv = -EINVAL;
+ goto out;
+ }
+ spin_lock(&qp->orq_lock);
+
+ if (!siw_orq_empty(qp)) {
+ qp->tx_ctx.orq_fence = 1;
+ rv = 0;
+ }
+ spin_unlock(&qp->orq_lock);
+
+ } else if (wqe->sqe.opcode == SIW_OP_READ ||
+ wqe->sqe.opcode == SIW_OP_READ_LOCAL_INV) {
+ struct siw_sqe *rreq;
+
+ wqe->sqe.num_sge = 1;
+
+ spin_lock(&qp->orq_lock);
+
+ rreq = orq_get_free(qp);
+ if (rreq) {
+ /*
+ * Make an immediate copy in ORQ to be ready
+ * to process loopback READ reply
+ */
+ siw_read_to_orq(rreq, &wqe->sqe);
+ qp->orq_put++;
+ } else {
+ qp->tx_ctx.orq_fence = 1;
+ rv = 0;
+ }
+ spin_unlock(&qp->orq_lock);
+ }
+
+ /* Clear SQE, can be re-used by application */
+ smp_store_mb(sqe->flags, 0);
+ qp->sq_get++;
+ } else {
+ rv = 0;
+ }
+out:
+ if (unlikely(rv < 0)) {
+ siw_dbg_qp(qp, "error %d\n", rv);
+ wqe->wr_status = SIW_WR_IDLE;
+ }
+ return rv;
+}
+
+/*
+ * Check if current CQ state qualifies for calling CQ completion
+ * handler. Must be called with CQ lock held.
+ */
+static bool siw_cq_notify_now(struct siw_cq *cq, u32 flags)
+{
+ u64 cq_notify;
+
+ if (!cq->base_cq.comp_handler)
+ return false;
+
+ cq_notify = READ_ONCE(*cq->notify);
+
+ if ((cq_notify & SIW_NOTIFY_NEXT_COMPLETION) ||
+ ((cq_notify & SIW_NOTIFY_SOLICITED) &&
+ (flags & SIW_WQE_SOLICITED))) {
+ /* dis-arm CQ */
+ smp_store_mb(*cq->notify, SIW_NOTIFY_NOT);
+
+ return true;
+ }
+ return false;
+}
+
+int siw_sqe_complete(struct siw_qp *qp, struct siw_sqe *sqe, u32 bytes,
+ enum siw_wc_status status)
+{
+ struct siw_cq *cq = qp->scq;
+ int rv = 0;
+
+ if (cq) {
+ u32 sqe_flags = sqe->flags;
+ struct siw_cqe *cqe;
+ u32 idx;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cq->lock, flags);
+
+ idx = cq->cq_put % cq->num_cqe;
+ cqe = &cq->queue[idx];
+
+ if (!READ_ONCE(cqe->flags)) {
+ bool notify;
+
+ cqe->id = sqe->id;
+ cqe->opcode = sqe->opcode;
+ cqe->status = status;
+ cqe->imm_data = 0;
+ cqe->bytes = bytes;
+
+ if (cq->kernel_verbs)
+ cqe->base_qp = qp->ib_qp;
+ else
+ cqe->qp_id = qp_id(qp);
+
+ /* mark CQE valid for application */
+ WRITE_ONCE(cqe->flags, SIW_WQE_VALID);
+ /* recycle SQE */
+ smp_store_mb(sqe->flags, 0);
+
+ cq->cq_put++;
+ notify = siw_cq_notify_now(cq, sqe_flags);
+
+ spin_unlock_irqrestore(&cq->lock, flags);
+
+ if (notify) {
+ siw_dbg_cq(cq, "Call completion handler\n");
+ cq->base_cq.comp_handler(&cq->base_cq,
+ cq->base_cq.cq_context);
+ }
+ } else {
+ spin_unlock_irqrestore(&cq->lock, flags);
+ rv = -ENOMEM;
+ siw_cq_event(cq, IB_EVENT_CQ_ERR);
+ }
+ } else {
+ /* recycle SQE */
+ smp_store_mb(sqe->flags, 0);
+ }
+ return rv;
+}
+
+int siw_rqe_complete(struct siw_qp *qp, struct siw_rqe *rqe, u32 bytes,
+ u32 inval_stag, enum siw_wc_status status)
+{
+ struct siw_cq *cq = qp->rcq;
+ int rv = 0;
+
+ if (cq) {
+ struct siw_cqe *cqe;
+ u32 idx;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cq->lock, flags);
+
+ idx = cq->cq_put % cq->num_cqe;
+ cqe = &cq->queue[idx];
+
+ if (!READ_ONCE(cqe->flags)) {
+ bool notify;
+ u8 cqe_flags = SIW_WQE_VALID;
+
+ cqe->id = rqe->id;
+ cqe->opcode = SIW_OP_RECEIVE;
+ cqe->status = status;
+ cqe->imm_data = 0;
+ cqe->bytes = bytes;
+
+ if (cq->kernel_verbs) {
+ cqe->base_qp = qp->ib_qp;
+ if (inval_stag) {
+ cqe_flags |= SIW_WQE_REM_INVAL;
+ cqe->inval_stag = inval_stag;
+ }
+ } else {
+ cqe->qp_id = qp_id(qp);
+ }
+ /* mark CQE valid for application */
+ WRITE_ONCE(cqe->flags, cqe_flags);
+ /* recycle RQE */
+ smp_store_mb(rqe->flags, 0);
+
+ cq->cq_put++;
+ notify = siw_cq_notify_now(cq, SIW_WQE_SIGNALLED);
+
+ spin_unlock_irqrestore(&cq->lock, flags);
+
+ if (notify) {
+ siw_dbg_cq(cq, "Call completion handler\n");
+ cq->base_cq.comp_handler(&cq->base_cq,
+ cq->base_cq.cq_context);
+ }
+ } else {
+ spin_unlock_irqrestore(&cq->lock, flags);
+ rv = -ENOMEM;
+ siw_cq_event(cq, IB_EVENT_CQ_ERR);
+ }
+ } else {
+ /* recycle RQE */
+ smp_store_mb(rqe->flags, 0);
+ }
+ return rv;
+}
+
+/*
+ * siw_sq_flush()
+ *
+ * Flush SQ and ORRQ entries to CQ.
+ *
+ * Must be called with QP state write lock held.
+ * Therefore, SQ and ORQ lock must not be taken.
+ */
+void siw_sq_flush(struct siw_qp *qp)
+{
+ struct siw_sqe *sqe;
+ struct siw_wqe *wqe = tx_wqe(qp);
+ int async_event = 0;
+
+ /*
+ * Start with completing any work currently on the ORQ
+ */
+ while (qp->attrs.orq_size) {
+ sqe = &qp->orq[qp->orq_get % qp->attrs.orq_size];
+ if (!READ_ONCE(sqe->flags))
+ break;
+
+ if (siw_sqe_complete(qp, sqe, 0, SIW_WC_WR_FLUSH_ERR) != 0)
+ break;
+
+ WRITE_ONCE(sqe->flags, 0);
+ qp->orq_get++;
+ }
+ /*
+ * Flush an in-progress WQE if present
+ */
+ if (wqe->wr_status != SIW_WR_IDLE) {
+ siw_dbg_qp(qp, "flush current SQE, type %d, status %d\n",
+ tx_type(wqe), wqe->wr_status);
+
+ siw_wqe_put_mem(wqe, tx_type(wqe));
+
+ if (tx_type(wqe) != SIW_OP_READ_RESPONSE &&
+ ((tx_type(wqe) != SIW_OP_READ &&
+ tx_type(wqe) != SIW_OP_READ_LOCAL_INV) ||
+ wqe->wr_status == SIW_WR_QUEUED))
+ /*
+ * An in-progress Read Request is already in
+ * the ORQ
+ */
+ siw_sqe_complete(qp, &wqe->sqe, wqe->bytes,
+ SIW_WC_WR_FLUSH_ERR);
+
+ wqe->wr_status = SIW_WR_IDLE;
+ }
+ /*
+ * Flush the Send Queue
+ */
+ while (qp->attrs.sq_size) {
+ sqe = &qp->sendq[qp->sq_get % qp->attrs.sq_size];
+ if (!READ_ONCE(sqe->flags))
+ break;
+
+ async_event = 1;
+ if (siw_sqe_complete(qp, sqe, 0, SIW_WC_WR_FLUSH_ERR) != 0)
+ /*
+ * Shall IB_EVENT_SQ_DRAINED be supressed if work
+ * completion fails?
+ */
+ break;
+
+ WRITE_ONCE(sqe->flags, 0);
+ qp->sq_get++;
+ }
+ if (async_event)
+ siw_qp_event(qp, IB_EVENT_SQ_DRAINED);
+}
+
+/*
+ * siw_rq_flush()
+ *
+ * Flush recv queue entries to CQ. Also
+ * takes care of pending active tagged and untagged
+ * inbound transfers, which have target memory
+ * referenced.
+ *
+ * Must be called with QP state write lock held.
+ * Therefore, RQ lock must not be taken.
+ */
+void siw_rq_flush(struct siw_qp *qp)
+{
+ struct siw_wqe *wqe = &qp->rx_untagged.wqe_active;
+
+ /*
+ * Flush an in-progress untagged operation if present
+ */
+ if (wqe->wr_status != SIW_WR_IDLE) {
+ siw_dbg_qp(qp, "flush current rqe, type %d, status %d\n",
+ rx_type(wqe), wqe->wr_status);
+
+ siw_wqe_put_mem(wqe, rx_type(wqe));
+
+ if (rx_type(wqe) == SIW_OP_RECEIVE) {
+ siw_rqe_complete(qp, &wqe->rqe, wqe->bytes,
+ 0, SIW_WC_WR_FLUSH_ERR);
+ } else if (rx_type(wqe) != SIW_OP_READ &&
+ rx_type(wqe) != SIW_OP_READ_RESPONSE &&
+ rx_type(wqe) != SIW_OP_WRITE) {
+ siw_sqe_complete(qp, &wqe->sqe, 0, SIW_WC_WR_FLUSH_ERR);
+ }
+ wqe->wr_status = SIW_WR_IDLE;
+ }
+ wqe = &qp->rx_tagged.wqe_active;
+
+ if (wqe->wr_status != SIW_WR_IDLE) {
+ siw_wqe_put_mem(wqe, rx_type(wqe));
+ wqe->wr_status = SIW_WR_IDLE;
+ }
+ /*
+ * Flush the Receive Queue
+ */
+ while (qp->attrs.rq_size) {
+ struct siw_rqe *rqe =
+ &qp->recvq[qp->rq_get % qp->attrs.rq_size];
+
+ if (!READ_ONCE(rqe->flags))
+ break;
+
+ if (siw_rqe_complete(qp, rqe, 0, 0, SIW_WC_WR_FLUSH_ERR) != 0)
+ break;
+
+ WRITE_ONCE(rqe->flags, 0);
+ qp->rq_get++;
+ }
+}
+
+int siw_qp_add(struct siw_device *sdev, struct siw_qp *qp)
+{
+ int rv = xa_alloc(&sdev->qp_xa, &qp->ib_qp->qp_num, qp, xa_limit_32b,
+ GFP_KERNEL);
+
+ if (!rv) {
+ kref_init(&qp->ref);
+ qp->sdev = sdev;
+ qp->qp_num = qp->ib_qp->qp_num;
+ siw_dbg_qp(qp, "new QP\n");
+ }
+ return rv;
+}
+
+void siw_free_qp(struct kref *ref)
+{
+ struct siw_qp *found, *qp = container_of(ref, struct siw_qp, ref);
+ struct siw_device *sdev = qp->sdev;
+ unsigned long flags;
+
+ if (qp->cep)
+ siw_cep_put(qp->cep);
+
+ found = xa_erase(&sdev->qp_xa, qp_id(qp));
+ WARN_ON(found != qp);
+ spin_lock_irqsave(&sdev->lock, flags);
+ list_del(&qp->devq);
+ spin_unlock_irqrestore(&sdev->lock, flags);
+
+ vfree(qp->sendq);
+ vfree(qp->recvq);
+ vfree(qp->irq);
+ vfree(qp->orq);
+
+ siw_put_tx_cpu(qp->tx_cpu);
+
+ atomic_dec(&sdev->num_qp);
+ siw_dbg_qp(qp, "free QP\n");
+ kfree_rcu(qp, rcu);
+}
diff --git a/drivers/infiniband/sw/siw/siw_qp_rx.c b/drivers/infiniband/sw/siw/siw_qp_rx.c
new file mode 100644
index 000000000000..f87657a11657
--- /dev/null
+++ b/drivers/infiniband/sw/siw/siw_qp_rx.c
@@ -0,0 +1,1458 @@
+// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause
+
+/* Authors: Bernard Metzler <bmt@zurich.ibm.com> */
+/* Copyright (c) 2008-2019, IBM Corporation */
+
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/net.h>
+#include <linux/scatterlist.h>
+#include <linux/highmem.h>
+
+#include <rdma/iw_cm.h>
+#include <rdma/ib_verbs.h>
+
+#include "siw.h"
+#include "siw_verbs.h"
+#include "siw_mem.h"
+
+/*
+ * siw_rx_umem()
+ *
+ * Receive data of @len into target referenced by @dest_addr.
+ *
+ * @srx: Receive Context
+ * @umem: siw representation of target memory
+ * @dest_addr: user virtual address
+ * @len: number of bytes to place
+ */
+static int siw_rx_umem(struct siw_rx_stream *srx, struct siw_umem *umem,
+ u64 dest_addr, int len)
+{
+ int copied = 0;
+
+ while (len) {
+ struct page *p;
+ int pg_off, bytes, rv;
+ void *dest;
+
+ p = siw_get_upage(umem, dest_addr);
+ if (unlikely(!p)) {
+ pr_warn("siw: %s: [QP %u]: bogus addr: %p, %p\n",
+ __func__, qp_id(rx_qp(srx)),
+ (void *)dest_addr, (void *)umem->fp_addr);
+ /* siw internal error */
+ srx->skb_copied += copied;
+ srx->skb_new -= copied;
+
+ return -EFAULT;
+ }
+ pg_off = dest_addr & ~PAGE_MASK;
+ bytes = min(len, (int)PAGE_SIZE - pg_off);
+
+ siw_dbg_qp(rx_qp(srx), "page %p, bytes=%u\n", p, bytes);
+
+ dest = kmap_atomic(p);
+ rv = skb_copy_bits(srx->skb, srx->skb_offset, dest + pg_off,
+ bytes);
+
+ if (unlikely(rv)) {
+ kunmap_atomic(dest);
+ srx->skb_copied += copied;
+ srx->skb_new -= copied;
+
+ pr_warn("siw: [QP %u]: %s, len %d, page %p, rv %d\n",
+ qp_id(rx_qp(srx)), __func__, len, p, rv);
+
+ return -EFAULT;
+ }
+ if (srx->mpa_crc_hd) {
+ if (rx_qp(srx)->kernel_verbs) {
+ crypto_shash_update(srx->mpa_crc_hd,
+ (u8 *)(dest + pg_off), bytes);
+ kunmap_atomic(dest);
+ } else {
+ kunmap_atomic(dest);
+ /*
+ * Do CRC on original, not target buffer.
+ * Some user land applications may
+ * concurrently write the target buffer,
+ * which would yield a broken CRC.
+ * Walking the skb twice is very ineffcient.
+ * Folding the CRC into skb_copy_bits()
+ * would be much better, but is currently
+ * not supported.
+ */
+ siw_crc_skb(srx, bytes);
+ }
+ } else {
+ kunmap_atomic(dest);
+ }
+ srx->skb_offset += bytes;
+ copied += bytes;
+ len -= bytes;
+ dest_addr += bytes;
+ pg_off = 0;
+ }
+ srx->skb_copied += copied;
+ srx->skb_new -= copied;
+
+ return copied;
+}
+
+static int siw_rx_kva(struct siw_rx_stream *srx, void *kva, int len)
+{
+ int rv;
+
+ siw_dbg_qp(rx_qp(srx), "kva: 0x%p, len: %u\n", kva, len);
+
+ rv = skb_copy_bits(srx->skb, srx->skb_offset, kva, len);
+ if (unlikely(rv)) {
+ pr_warn("siw: [QP %u]: %s, len %d, kva 0x%p, rv %d\n",
+ qp_id(rx_qp(srx)), __func__, len, kva, rv);
+
+ return rv;
+ }
+ if (srx->mpa_crc_hd)
+ crypto_shash_update(srx->mpa_crc_hd, (u8 *)kva, len);
+
+ srx->skb_offset += len;
+ srx->skb_copied += len;
+ srx->skb_new -= len;
+
+ return len;
+}
+
+static int siw_rx_pbl(struct siw_rx_stream *srx, int *pbl_idx,
+ struct siw_mem *mem, u64 addr, int len)
+{
+ struct siw_pbl *pbl = mem->pbl;
+ u64 offset = addr - mem->va;
+ int copied = 0;
+
+ while (len) {
+ int bytes;
+ u64 buf_addr =
+ siw_pbl_get_buffer(pbl, offset, &bytes, pbl_idx);
+ if (!buf_addr)
+ break;
+
+ bytes = min(bytes, len);
+ if (siw_rx_kva(srx, (void *)buf_addr, bytes) == bytes) {
+ copied += bytes;
+ offset += bytes;
+ len -= bytes;
+ } else {
+ break;
+ }
+ }
+ return copied;
+}
+
+/*
+ * siw_rresp_check_ntoh()
+ *
+ * Check incoming RRESP fragment header against expected
+ * header values and update expected values for potential next
+ * fragment.
+ *
+ * NOTE: This function must be called only if a RRESP DDP segment
+ * starts but not for fragmented consecutive pieces of an
+ * already started DDP segment.
+ */
+static int siw_rresp_check_ntoh(struct siw_rx_stream *srx,
+ struct siw_rx_fpdu *frx)
+{
+ struct iwarp_rdma_rresp *rresp = &srx->hdr.rresp;
+ struct siw_wqe *wqe = &frx->wqe_active;
+ enum ddp_ecode ecode;
+
+ u32 sink_stag = be32_to_cpu(rresp->sink_stag);
+ u64 sink_to = be64_to_cpu(rresp->sink_to);
+
+ if (frx->first_ddp_seg) {
+ srx->ddp_stag = wqe->sqe.sge[0].lkey;
+ srx->ddp_to = wqe->sqe.sge[0].laddr;
+ frx->pbl_idx = 0;
+ }
+ /* Below checks extend beyond the semantics of DDP, and
+ * into RDMAP:
+ * We check if the read response matches exactly the
+ * read request which was send to the remote peer to
+ * trigger this read response. RFC5040/5041 do not
+ * always have a proper error code for the detected
+ * error cases. We choose 'base or bounds error' for
+ * cases where the inbound STag is valid, but offset
+ * or length do not match our response receive state.
+ */
+ if (unlikely(srx->ddp_stag != sink_stag)) {
+ pr_warn("siw: [QP %u]: rresp stag: %08x != %08x\n",
+ qp_id(rx_qp(srx)), sink_stag, srx->ddp_stag);
+ ecode = DDP_ECODE_T_INVALID_STAG;
+ goto error;
+ }
+ if (unlikely(srx->ddp_to != sink_to)) {
+ pr_warn("siw: [QP %u]: rresp off: %016llx != %016llx\n",
+ qp_id(rx_qp(srx)), (unsigned long long)sink_to,
+ (unsigned long long)srx->ddp_to);
+ ecode = DDP_ECODE_T_BASE_BOUNDS;
+ goto error;
+ }
+ if (unlikely(!frx->more_ddp_segs &&
+ (wqe->processed + srx->fpdu_part_rem != wqe->bytes))) {
+ pr_warn("siw: [QP %u]: rresp len: %d != %d\n",
+ qp_id(rx_qp(srx)),
+ wqe->processed + srx->fpdu_part_rem, wqe->bytes);
+ ecode = DDP_ECODE_T_BASE_BOUNDS;
+ goto error;
+ }
+ return 0;
+error:
+ siw_init_terminate(rx_qp(srx), TERM_ERROR_LAYER_DDP,
+ DDP_ETYPE_TAGGED_BUF, ecode, 0);
+ return -EINVAL;
+}
+
+/*
+ * siw_write_check_ntoh()
+ *
+ * Check incoming WRITE fragment header against expected
+ * header values and update expected values for potential next
+ * fragment
+ *
+ * NOTE: This function must be called only if a WRITE DDP segment
+ * starts but not for fragmented consecutive pieces of an
+ * already started DDP segment.
+ */
+static int siw_write_check_ntoh(struct siw_rx_stream *srx,
+ struct siw_rx_fpdu *frx)
+{
+ struct iwarp_rdma_write *write = &srx->hdr.rwrite;
+ enum ddp_ecode ecode;
+
+ u32 sink_stag = be32_to_cpu(write->sink_stag);
+ u64 sink_to = be64_to_cpu(write->sink_to);
+
+ if (frx->first_ddp_seg) {
+ srx->ddp_stag = sink_stag;
+ srx->ddp_to = sink_to;
+ frx->pbl_idx = 0;
+ } else {
+ if (unlikely(srx->ddp_stag != sink_stag)) {
+ pr_warn("siw: [QP %u]: write stag: %08x != %08x\n",
+ qp_id(rx_qp(srx)), sink_stag,
+ srx->ddp_stag);
+ ecode = DDP_ECODE_T_INVALID_STAG;
+ goto error;
+ }
+ if (unlikely(srx->ddp_to != sink_to)) {
+ pr_warn("siw: [QP %u]: write off: %016llx != %016llx\n",
+ qp_id(rx_qp(srx)),
+ (unsigned long long)sink_to,
+ (unsigned long long)srx->ddp_to);
+ ecode = DDP_ECODE_T_BASE_BOUNDS;
+ goto error;
+ }
+ }
+ return 0;
+error:
+ siw_init_terminate(rx_qp(srx), TERM_ERROR_LAYER_DDP,
+ DDP_ETYPE_TAGGED_BUF, ecode, 0);
+ return -EINVAL;
+}
+
+/*
+ * siw_send_check_ntoh()
+ *
+ * Check incoming SEND fragment header against expected
+ * header values and update expected MSN if no next
+ * fragment expected
+ *
+ * NOTE: This function must be called only if a SEND DDP segment
+ * starts but not for fragmented consecutive pieces of an
+ * already started DDP segment.
+ */
+static int siw_send_check_ntoh(struct siw_rx_stream *srx,
+ struct siw_rx_fpdu *frx)
+{
+ struct iwarp_send_inv *send = &srx->hdr.send_inv;
+ struct siw_wqe *wqe = &frx->wqe_active;
+ enum ddp_ecode ecode;
+
+ u32 ddp_msn = be32_to_cpu(send->ddp_msn);
+ u32 ddp_mo = be32_to_cpu(send->ddp_mo);
+ u32 ddp_qn = be32_to_cpu(send->ddp_qn);
+
+ if (unlikely(ddp_qn != RDMAP_UNTAGGED_QN_SEND)) {
+ pr_warn("siw: [QP %u]: invalid ddp qn %d for send\n",
+ qp_id(rx_qp(srx)), ddp_qn);
+ ecode = DDP_ECODE_UT_INVALID_QN;
+ goto error;
+ }
+ if (unlikely(ddp_msn != srx->ddp_msn[RDMAP_UNTAGGED_QN_SEND])) {
+ pr_warn("siw: [QP %u]: send msn: %u != %u\n",
+ qp_id(rx_qp(srx)), ddp_msn,
+ srx->ddp_msn[RDMAP_UNTAGGED_QN_SEND]);
+ ecode = DDP_ECODE_UT_INVALID_MSN_RANGE;
+ goto error;
+ }
+ if (unlikely(ddp_mo != wqe->processed)) {
+ pr_warn("siw: [QP %u], send mo: %u != %u\n",
+ qp_id(rx_qp(srx)), ddp_mo, wqe->processed);
+ ecode = DDP_ECODE_UT_INVALID_MO;
+ goto error;
+ }
+ if (frx->first_ddp_seg) {
+ /* initialize user memory write position */
+ frx->sge_idx = 0;
+ frx->sge_off = 0;
+ frx->pbl_idx = 0;
+
+ /* only valid for SEND_INV and SEND_SE_INV operations */
+ srx->inval_stag = be32_to_cpu(send->inval_stag);
+ }
+ if (unlikely(wqe->bytes < wqe->processed + srx->fpdu_part_rem)) {
+ siw_dbg_qp(rx_qp(srx), "receive space short: %d - %d < %d\n",
+ wqe->bytes, wqe->processed, srx->fpdu_part_rem);
+ wqe->wc_status = SIW_WC_LOC_LEN_ERR;
+ ecode = DDP_ECODE_UT_INVALID_MSN_NOBUF;
+ goto error;
+ }
+ return 0;
+error:
+ siw_init_terminate(rx_qp(srx), TERM_ERROR_LAYER_DDP,
+ DDP_ETYPE_UNTAGGED_BUF, ecode, 0);
+ return -EINVAL;
+}
+
+static struct siw_wqe *siw_rqe_get(struct siw_qp *qp)
+{
+ struct siw_rqe *rqe;
+ struct siw_srq *srq;
+ struct siw_wqe *wqe = NULL;
+ bool srq_event = false;
+ unsigned long flags;
+
+ srq = qp->srq;
+ if (srq) {
+ spin_lock_irqsave(&srq->lock, flags);
+ if (unlikely(!srq->num_rqe))
+ goto out;
+
+ rqe = &srq->recvq[srq->rq_get % srq->num_rqe];
+ } else {
+ if (unlikely(!qp->recvq))
+ goto out;
+
+ rqe = &qp->recvq[qp->rq_get % qp->attrs.rq_size];
+ }
+ if (likely(rqe->flags == SIW_WQE_VALID)) {
+ int num_sge = rqe->num_sge;
+
+ if (likely(num_sge <= SIW_MAX_SGE)) {
+ int i = 0;
+
+ wqe = rx_wqe(&qp->rx_untagged);
+ rx_type(wqe) = SIW_OP_RECEIVE;
+ wqe->wr_status = SIW_WR_INPROGRESS;
+ wqe->bytes = 0;
+ wqe->processed = 0;
+
+ wqe->rqe.id = rqe->id;
+ wqe->rqe.num_sge = num_sge;
+
+ while (i < num_sge) {
+ wqe->rqe.sge[i].laddr = rqe->sge[i].laddr;
+ wqe->rqe.sge[i].lkey = rqe->sge[i].lkey;
+ wqe->rqe.sge[i].length = rqe->sge[i].length;
+ wqe->bytes += wqe->rqe.sge[i].length;
+ wqe->mem[i] = NULL;
+ i++;
+ }
+ /* can be re-used by appl */
+ smp_store_mb(rqe->flags, 0);
+ } else {
+ siw_dbg_qp(qp, "too many sge's: %d\n", rqe->num_sge);
+ if (srq)
+ spin_unlock_irqrestore(&srq->lock, flags);
+ return NULL;
+ }
+ if (!srq) {
+ qp->rq_get++;
+ } else {
+ if (srq->armed) {
+ /* Test SRQ limit */
+ u32 off = (srq->rq_get + srq->limit) %
+ srq->num_rqe;
+ struct siw_rqe *rqe2 = &srq->recvq[off];
+
+ if (!(rqe2->flags & SIW_WQE_VALID)) {
+ srq->armed = 0;
+ srq_event = true;
+ }
+ }
+ srq->rq_get++;
+ }
+ }
+out:
+ if (srq) {
+ spin_unlock_irqrestore(&srq->lock, flags);
+ if (srq_event)
+ siw_srq_event(srq, IB_EVENT_SRQ_LIMIT_REACHED);
+ }
+ return wqe;
+}
+
+/*
+ * siw_proc_send:
+ *
+ * Process one incoming SEND and place data into memory referenced by
+ * receive wqe.
+ *
+ * Function supports partially received sends (suspending/resuming
+ * current receive wqe processing)
+ *
+ * return value:
+ * 0: reached the end of a DDP segment
+ * -EAGAIN: to be called again to finish the DDP segment
+ */
+int siw_proc_send(struct siw_qp *qp)
+{
+ struct siw_rx_stream *srx = &qp->rx_stream;
+ struct siw_rx_fpdu *frx = &qp->rx_untagged;
+ struct siw_wqe *wqe;
+ u32 data_bytes; /* all data bytes available */
+ u32 rcvd_bytes; /* sum of data bytes rcvd */
+ int rv = 0;
+
+ if (frx->first_ddp_seg) {
+ wqe = siw_rqe_get(qp);
+ if (unlikely(!wqe)) {
+ siw_init_terminate(qp, TERM_ERROR_LAYER_DDP,
+ DDP_ETYPE_UNTAGGED_BUF,
+ DDP_ECODE_UT_INVALID_MSN_NOBUF, 0);
+ return -ENOENT;
+ }
+ } else {
+ wqe = rx_wqe(frx);
+ }
+ if (srx->state == SIW_GET_DATA_START) {
+ rv = siw_send_check_ntoh(srx, frx);
+ if (unlikely(rv)) {
+ siw_qp_event(qp, IB_EVENT_QP_FATAL);
+ return rv;
+ }
+ if (!srx->fpdu_part_rem) /* zero length SEND */
+ return 0;
+ }
+ data_bytes = min(srx->fpdu_part_rem, srx->skb_new);
+ rcvd_bytes = 0;
+
+ /* A zero length SEND will skip below loop */
+ while (data_bytes) {
+ struct ib_pd *pd;
+ struct siw_mem **mem, *mem_p;
+ struct siw_sge *sge;
+ u32 sge_bytes; /* data bytes avail for SGE */
+
+ sge = &wqe->rqe.sge[frx->sge_idx];
+
+ if (!sge->length) {
+ /* just skip empty sge's */
+ frx->sge_idx++;
+ frx->sge_off = 0;
+ frx->pbl_idx = 0;
+ continue;
+ }
+ sge_bytes = min(data_bytes, sge->length - frx->sge_off);
+ mem = &wqe->mem[frx->sge_idx];
+
+ /*
+ * check with QP's PD if no SRQ present, SRQ's PD otherwise
+ */
+ pd = qp->srq == NULL ? qp->pd : qp->srq->base_srq.pd;
+
+ rv = siw_check_sge(pd, sge, mem, IB_ACCESS_LOCAL_WRITE,
+ frx->sge_off, sge_bytes);
+ if (unlikely(rv)) {
+ siw_init_terminate(qp, TERM_ERROR_LAYER_DDP,
+ DDP_ETYPE_CATASTROPHIC,
+ DDP_ECODE_CATASTROPHIC, 0);
+
+ siw_qp_event(qp, IB_EVENT_QP_ACCESS_ERR);
+ break;
+ }
+ mem_p = *mem;
+ if (mem_p->mem_obj == NULL)
+ rv = siw_rx_kva(srx,
+ (void *)(sge->laddr + frx->sge_off),
+ sge_bytes);
+ else if (!mem_p->is_pbl)
+ rv = siw_rx_umem(srx, mem_p->umem,
+ sge->laddr + frx->sge_off, sge_bytes);
+ else
+ rv = siw_rx_pbl(srx, &frx->pbl_idx, mem_p,
+ sge->laddr + frx->sge_off, sge_bytes);
+
+ if (unlikely(rv != sge_bytes)) {
+ wqe->processed += rcvd_bytes;
+
+ siw_init_terminate(qp, TERM_ERROR_LAYER_DDP,
+ DDP_ETYPE_CATASTROPHIC,
+ DDP_ECODE_CATASTROPHIC, 0);
+ return -EINVAL;
+ }
+ frx->sge_off += rv;
+
+ if (frx->sge_off == sge->length) {
+ frx->sge_idx++;
+ frx->sge_off = 0;
+ frx->pbl_idx = 0;
+ }
+ data_bytes -= rv;
+ rcvd_bytes += rv;
+
+ srx->fpdu_part_rem -= rv;
+ srx->fpdu_part_rcvd += rv;
+ }
+ wqe->processed += rcvd_bytes;
+
+ if (!srx->fpdu_part_rem)
+ return 0;
+
+ return (rv < 0) ? rv : -EAGAIN;
+}
+
+/*
+ * siw_proc_write:
+ *
+ * Place incoming WRITE after referencing and checking target buffer
+
+ * Function supports partially received WRITEs (suspending/resuming
+ * current receive processing)
+ *
+ * return value:
+ * 0: reached the end of a DDP segment
+ * -EAGAIN: to be called again to finish the DDP segment
+ */
+int siw_proc_write(struct siw_qp *qp)
+{
+ struct siw_rx_stream *srx = &qp->rx_stream;
+ struct siw_rx_fpdu *frx = &qp->rx_tagged;
+ struct siw_mem *mem;
+ int bytes, rv;
+
+ if (srx->state == SIW_GET_DATA_START) {
+ if (!srx->fpdu_part_rem) /* zero length WRITE */
+ return 0;
+
+ rv = siw_write_check_ntoh(srx, frx);
+ if (unlikely(rv)) {
+ siw_qp_event(qp, IB_EVENT_QP_FATAL);
+ return rv;
+ }
+ }
+ bytes = min(srx->fpdu_part_rem, srx->skb_new);
+
+ if (frx->first_ddp_seg) {
+ struct siw_wqe *wqe = rx_wqe(frx);
+
+ rx_mem(frx) = siw_mem_id2obj(qp->sdev, srx->ddp_stag >> 8);
+ if (unlikely(!rx_mem(frx))) {
+ siw_dbg_qp(qp,
+ "sink stag not found/invalid, stag 0x%08x\n",
+ srx->ddp_stag);
+
+ siw_init_terminate(qp, TERM_ERROR_LAYER_DDP,
+ DDP_ETYPE_TAGGED_BUF,
+ DDP_ECODE_T_INVALID_STAG, 0);
+ return -EINVAL;
+ }
+ wqe->rqe.num_sge = 1;
+ rx_type(wqe) = SIW_OP_WRITE;
+ wqe->wr_status = SIW_WR_INPROGRESS;
+ }
+ mem = rx_mem(frx);
+
+ /*
+ * Check if application re-registered memory with different
+ * key field of STag.
+ */
+ if (unlikely(mem->stag != srx->ddp_stag)) {
+ siw_init_terminate(qp, TERM_ERROR_LAYER_DDP,
+ DDP_ETYPE_TAGGED_BUF,
+ DDP_ECODE_T_INVALID_STAG, 0);
+ return -EINVAL;
+ }
+ rv = siw_check_mem(qp->pd, mem, srx->ddp_to + srx->fpdu_part_rcvd,
+ IB_ACCESS_REMOTE_WRITE, bytes);
+ if (unlikely(rv)) {
+ siw_init_terminate(qp, TERM_ERROR_LAYER_DDP,
+ DDP_ETYPE_TAGGED_BUF, siw_tagged_error(-rv),
+ 0);
+
+ siw_qp_event(qp, IB_EVENT_QP_ACCESS_ERR);
+
+ return -EINVAL;
+ }
+
+ if (mem->mem_obj == NULL)
+ rv = siw_rx_kva(srx,
+ (void *)(srx->ddp_to + srx->fpdu_part_rcvd),
+ bytes);
+ else if (!mem->is_pbl)
+ rv = siw_rx_umem(srx, mem->umem,
+ srx->ddp_to + srx->fpdu_part_rcvd, bytes);
+ else
+ rv = siw_rx_pbl(srx, &frx->pbl_idx, mem,
+ srx->ddp_to + srx->fpdu_part_rcvd, bytes);
+
+ if (unlikely(rv != bytes)) {
+ siw_init_terminate(qp, TERM_ERROR_LAYER_DDP,
+ DDP_ETYPE_CATASTROPHIC,
+ DDP_ECODE_CATASTROPHIC, 0);
+ return -EINVAL;
+ }
+ srx->fpdu_part_rem -= rv;
+ srx->fpdu_part_rcvd += rv;
+
+ if (!srx->fpdu_part_rem) {
+ srx->ddp_to += srx->fpdu_part_rcvd;
+ return 0;
+ }
+ return -EAGAIN;
+}
+
+/*
+ * Inbound RREQ's cannot carry user data.
+ */
+int siw_proc_rreq(struct siw_qp *qp)
+{
+ struct siw_rx_stream *srx = &qp->rx_stream;
+
+ if (!srx->fpdu_part_rem)
+ return 0;
+
+ pr_warn("siw: [QP %u]: rreq with mpa len %d\n", qp_id(qp),
+ be16_to_cpu(srx->hdr.ctrl.mpa_len));
+
+ return -EPROTO;
+}
+
+/*
+ * siw_init_rresp:
+ *
+ * Process inbound RDMA READ REQ. Produce a pseudo READ RESPONSE WQE.
+ * Put it at the tail of the IRQ, if there is another WQE currently in
+ * transmit processing. If not, make it the current WQE to be processed
+ * and schedule transmit processing.
+ *
+ * Can be called from softirq context and from process
+ * context (RREAD socket loopback case!)
+ *
+ * return value:
+ * 0: success,
+ * failure code otherwise
+ */
+
+static int siw_init_rresp(struct siw_qp *qp, struct siw_rx_stream *srx)
+{
+ struct siw_wqe *tx_work = tx_wqe(qp);
+ struct siw_sqe *resp;
+
+ uint64_t raddr = be64_to_cpu(srx->hdr.rreq.sink_to),
+ laddr = be64_to_cpu(srx->hdr.rreq.source_to);
+ uint32_t length = be32_to_cpu(srx->hdr.rreq.read_size),
+ lkey = be32_to_cpu(srx->hdr.rreq.source_stag),
+ rkey = be32_to_cpu(srx->hdr.rreq.sink_stag),
+ msn = be32_to_cpu(srx->hdr.rreq.ddp_msn);
+
+ int run_sq = 1, rv = 0;
+ unsigned long flags;
+
+ if (unlikely(msn != srx->ddp_msn[RDMAP_UNTAGGED_QN_RDMA_READ])) {
+ siw_init_terminate(qp, TERM_ERROR_LAYER_DDP,
+ DDP_ETYPE_UNTAGGED_BUF,
+ DDP_ECODE_UT_INVALID_MSN_RANGE, 0);
+ return -EPROTO;
+ }
+ spin_lock_irqsave(&qp->sq_lock, flags);
+
+ if (tx_work->wr_status == SIW_WR_IDLE) {
+ /*
+ * immediately schedule READ response w/o
+ * consuming IRQ entry: IRQ must be empty.
+ */
+ tx_work->processed = 0;
+ tx_work->mem[0] = NULL;
+ tx_work->wr_status = SIW_WR_QUEUED;
+ resp = &tx_work->sqe;
+ } else {
+ resp = irq_alloc_free(qp);
+ run_sq = 0;
+ }
+ if (likely(resp)) {
+ resp->opcode = SIW_OP_READ_RESPONSE;
+
+ resp->sge[0].length = length;
+ resp->sge[0].laddr = laddr;
+ resp->sge[0].lkey = lkey;
+
+ /* Keep aside message sequence number for potential
+ * error reporting during Read Response generation.
+ */
+ resp->sge[1].length = msn;
+
+ resp->raddr = raddr;
+ resp->rkey = rkey;
+ resp->num_sge = length ? 1 : 0;
+
+ /* RRESP now valid as current TX wqe or placed into IRQ */
+ smp_store_mb(resp->flags, SIW_WQE_VALID);
+ } else {
+ pr_warn("siw: [QP %u]: irq %d exceeded %d\n", qp_id(qp),
+ qp->irq_put % qp->attrs.irq_size, qp->attrs.irq_size);
+
+ siw_init_terminate(qp, TERM_ERROR_LAYER_RDMAP,
+ RDMAP_ETYPE_REMOTE_OPERATION,
+ RDMAP_ECODE_CATASTROPHIC_STREAM, 0);
+ rv = -EPROTO;
+ }
+
+ spin_unlock_irqrestore(&qp->sq_lock, flags);
+
+ if (run_sq)
+ rv = siw_sq_start(qp);
+
+ return rv;
+}
+
+/*
+ * Only called at start of Read.Resonse processing.
+ * Transfer pending Read from tip of ORQ into currrent rx wqe,
+ * but keep ORQ entry valid until Read.Response processing done.
+ * No Queue locking needed.
+ */
+static int siw_orqe_start_rx(struct siw_qp *qp)
+{
+ struct siw_sqe *orqe;
+ struct siw_wqe *wqe = NULL;
+
+ /* make sure ORQ indices are current */
+ smp_mb();
+
+ orqe = orq_get_current(qp);
+ if (READ_ONCE(orqe->flags) & SIW_WQE_VALID) {
+ /* RRESP is a TAGGED RDMAP operation */
+ wqe = rx_wqe(&qp->rx_tagged);
+ wqe->sqe.id = orqe->id;
+ wqe->sqe.opcode = orqe->opcode;
+ wqe->sqe.sge[0].laddr = orqe->sge[0].laddr;
+ wqe->sqe.sge[0].lkey = orqe->sge[0].lkey;
+ wqe->sqe.sge[0].length = orqe->sge[0].length;
+ wqe->sqe.flags = orqe->flags;
+ wqe->sqe.num_sge = 1;
+ wqe->bytes = orqe->sge[0].length;
+ wqe->processed = 0;
+ wqe->mem[0] = NULL;
+ /* make sure WQE is completely written before valid */
+ smp_wmb();
+ wqe->wr_status = SIW_WR_INPROGRESS;
+
+ return 0;
+ }
+ return -EPROTO;
+}
+
+/*
+ * siw_proc_rresp:
+ *
+ * Place incoming RRESP data into memory referenced by RREQ WQE
+ * which is at the tip of the ORQ
+ *
+ * Function supports partially received RRESP's (suspending/resuming
+ * current receive processing)
+ */
+int siw_proc_rresp(struct siw_qp *qp)
+{
+ struct siw_rx_stream *srx = &qp->rx_stream;
+ struct siw_rx_fpdu *frx = &qp->rx_tagged;
+ struct siw_wqe *wqe = rx_wqe(frx);
+ struct siw_mem **mem, *mem_p;
+ struct siw_sge *sge;
+ int bytes, rv;
+
+ if (frx->first_ddp_seg) {
+ if (unlikely(wqe->wr_status != SIW_WR_IDLE)) {
+ pr_warn("siw: [QP %u]: proc RRESP: status %d, op %d\n",
+ qp_id(qp), wqe->wr_status, wqe->sqe.opcode);
+ rv = -EPROTO;
+ goto error_term;
+ }
+ /*
+ * fetch pending RREQ from orq
+ */
+ rv = siw_orqe_start_rx(qp);
+ if (rv) {
+ pr_warn("siw: [QP %u]: ORQ empty at idx %d\n",
+ qp_id(qp), qp->orq_get % qp->attrs.orq_size);
+ goto error_term;
+ }
+ rv = siw_rresp_check_ntoh(srx, frx);
+ if (unlikely(rv)) {
+ siw_qp_event(qp, IB_EVENT_QP_FATAL);
+ return rv;
+ }
+ } else {
+ if (unlikely(wqe->wr_status != SIW_WR_INPROGRESS)) {
+ pr_warn("siw: [QP %u]: resume RRESP: status %d\n",
+ qp_id(qp), wqe->wr_status);
+ rv = -EPROTO;
+ goto error_term;
+ }
+ }
+ if (!srx->fpdu_part_rem) /* zero length RRESPONSE */
+ return 0;
+
+ sge = wqe->sqe.sge; /* there is only one */
+ mem = &wqe->mem[0];
+
+ if (!(*mem)) {
+ /*
+ * check target memory which resolves memory on first fragment
+ */
+ rv = siw_check_sge(qp->pd, sge, mem, IB_ACCESS_LOCAL_WRITE, 0,
+ wqe->bytes);
+ if (unlikely(rv)) {
+ siw_dbg_qp(qp, "target mem check: %d\n", rv);
+ wqe->wc_status = SIW_WC_LOC_PROT_ERR;
+
+ siw_init_terminate(qp, TERM_ERROR_LAYER_DDP,
+ DDP_ETYPE_TAGGED_BUF,
+ siw_tagged_error(-rv), 0);
+
+ siw_qp_event(qp, IB_EVENT_QP_ACCESS_ERR);
+
+ return -EINVAL;
+ }
+ }
+ mem_p = *mem;
+
+ bytes = min(srx->fpdu_part_rem, srx->skb_new);
+
+ if (mem_p->mem_obj == NULL)
+ rv = siw_rx_kva(srx, (void *)(sge->laddr + wqe->processed),
+ bytes);
+ else if (!mem_p->is_pbl)
+ rv = siw_rx_umem(srx, mem_p->umem, sge->laddr + wqe->processed,
+ bytes);
+ else
+ rv = siw_rx_pbl(srx, &frx->pbl_idx, mem_p,
+ sge->laddr + wqe->processed, bytes);
+ if (rv != bytes) {
+ wqe->wc_status = SIW_WC_GENERAL_ERR;
+ rv = -EINVAL;
+ goto error_term;
+ }
+ srx->fpdu_part_rem -= rv;
+ srx->fpdu_part_rcvd += rv;
+ wqe->processed += rv;
+
+ if (!srx->fpdu_part_rem) {
+ srx->ddp_to += srx->fpdu_part_rcvd;
+ return 0;
+ }
+ return -EAGAIN;
+
+error_term:
+ siw_init_terminate(qp, TERM_ERROR_LAYER_DDP, DDP_ETYPE_CATASTROPHIC,
+ DDP_ECODE_CATASTROPHIC, 0);
+ return rv;
+}
+
+int siw_proc_terminate(struct siw_qp *qp)
+{
+ struct siw_rx_stream *srx = &qp->rx_stream;
+ struct sk_buff *skb = srx->skb;
+ struct iwarp_terminate *term = &srx->hdr.terminate;
+ union iwarp_hdr term_info;
+ u8 *infop = (u8 *)&term_info;
+ enum rdma_opcode op;
+ u16 to_copy = sizeof(struct iwarp_ctrl);
+
+ pr_warn("siw: got TERMINATE. layer %d, type %d, code %d\n",
+ __rdmap_term_layer(term), __rdmap_term_etype(term),
+ __rdmap_term_ecode(term));
+
+ if (be32_to_cpu(term->ddp_qn) != RDMAP_UNTAGGED_QN_TERMINATE ||
+ be32_to_cpu(term->ddp_msn) !=
+ qp->rx_stream.ddp_msn[RDMAP_UNTAGGED_QN_TERMINATE] ||
+ be32_to_cpu(term->ddp_mo) != 0) {
+ pr_warn("siw: rx bogus TERM [QN x%08x, MSN x%08x, MO x%08x]\n",
+ be32_to_cpu(term->ddp_qn), be32_to_cpu(term->ddp_msn),
+ be32_to_cpu(term->ddp_mo));
+ return -ECONNRESET;
+ }
+ /*
+ * Receive remaining pieces of TERM if indicated
+ */
+ if (!term->flag_m)
+ return -ECONNRESET;
+
+ /* Do not take the effort to reassemble a network fragmented
+ * TERM message
+ */
+ if (srx->skb_new < sizeof(struct iwarp_ctrl_tagged))
+ return -ECONNRESET;
+
+ memset(infop, 0, sizeof(term_info));
+
+ skb_copy_bits(skb, srx->skb_offset, infop, to_copy);
+
+ op = __rdmap_get_opcode(&term_info.ctrl);
+ if (op >= RDMAP_TERMINATE)
+ goto out;
+
+ infop += to_copy;
+ srx->skb_offset += to_copy;
+ srx->skb_new -= to_copy;
+ srx->skb_copied += to_copy;
+ srx->fpdu_part_rcvd += to_copy;
+ srx->fpdu_part_rem -= to_copy;
+
+ to_copy = iwarp_pktinfo[op].hdr_len - to_copy;
+
+ /* Again, no network fragmented TERM's */
+ if (to_copy + MPA_CRC_SIZE > srx->skb_new)
+ return -ECONNRESET;
+
+ skb_copy_bits(skb, srx->skb_offset, infop, to_copy);
+
+ if (term->flag_r) {
+ siw_dbg_qp(qp, "TERM reports RDMAP hdr type %u, len %u (%s)\n",
+ op, be16_to_cpu(term_info.ctrl.mpa_len),
+ term->flag_m ? "valid" : "invalid");
+ } else if (term->flag_d) {
+ siw_dbg_qp(qp, "TERM reports DDP hdr type %u, len %u (%s)\n",
+ op, be16_to_cpu(term_info.ctrl.mpa_len),
+ term->flag_m ? "valid" : "invalid");
+ }
+out:
+ srx->skb_new -= to_copy;
+ srx->skb_offset += to_copy;
+ srx->skb_copied += to_copy;
+ srx->fpdu_part_rcvd += to_copy;
+ srx->fpdu_part_rem -= to_copy;
+
+ return -ECONNRESET;
+}
+
+static int siw_get_trailer(struct siw_qp *qp, struct siw_rx_stream *srx)
+{
+ struct sk_buff *skb = srx->skb;
+ u8 *tbuf = (u8 *)&srx->trailer.crc - srx->pad;
+ __wsum crc_in, crc_own = 0;
+
+ siw_dbg_qp(qp, "expected %d, available %d, pad %u\n",
+ srx->fpdu_part_rem, srx->skb_new, srx->pad);
+
+ if (srx->skb_new < srx->fpdu_part_rem)
+ return -EAGAIN;
+
+ skb_copy_bits(skb, srx->skb_offset, tbuf, srx->fpdu_part_rem);
+
+ if (srx->mpa_crc_hd && srx->pad)
+ crypto_shash_update(srx->mpa_crc_hd, tbuf, srx->pad);
+
+ srx->skb_new -= srx->fpdu_part_rem;
+ srx->skb_offset += srx->fpdu_part_rem;
+ srx->skb_copied += srx->fpdu_part_rem;
+
+ if (!srx->mpa_crc_hd)
+ return 0;
+
+ /*
+ * CRC32 is computed, transmitted and received directly in NBO,
+ * so there's never a reason to convert byte order.
+ */
+ crypto_shash_final(srx->mpa_crc_hd, (u8 *)&crc_own);
+ crc_in = (__force __wsum)srx->trailer.crc;
+
+ if (unlikely(crc_in != crc_own)) {
+ pr_warn("siw: crc error. in: %08x, own %08x, op %u\n",
+ crc_in, crc_own, qp->rx_stream.rdmap_op);
+
+ siw_init_terminate(qp, TERM_ERROR_LAYER_LLP,
+ LLP_ETYPE_MPA,
+ LLP_ECODE_RECEIVED_CRC, 0);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+#define MIN_DDP_HDR sizeof(struct iwarp_ctrl_tagged)
+
+static int siw_get_hdr(struct siw_rx_stream *srx)
+{
+ struct sk_buff *skb = srx->skb;
+ struct siw_qp *qp = rx_qp(srx);
+ struct iwarp_ctrl *c_hdr = &srx->hdr.ctrl;
+ struct siw_rx_fpdu *frx;
+ u8 opcode;
+ int bytes;
+
+ if (srx->fpdu_part_rcvd < MIN_DDP_HDR) {
+ /*
+ * copy a mimimum sized (tagged) DDP frame control part
+ */
+ bytes = min_t(int, srx->skb_new,
+ MIN_DDP_HDR - srx->fpdu_part_rcvd);
+
+ skb_copy_bits(skb, srx->skb_offset,
+ (char *)c_hdr + srx->fpdu_part_rcvd, bytes);
+
+ srx->fpdu_part_rcvd += bytes;
+
+ srx->skb_new -= bytes;
+ srx->skb_offset += bytes;
+ srx->skb_copied += bytes;
+
+ if (srx->fpdu_part_rcvd < MIN_DDP_HDR)
+ return -EAGAIN;
+
+ if (unlikely(__ddp_get_version(c_hdr) != DDP_VERSION)) {
+ enum ddp_etype etype;
+ enum ddp_ecode ecode;
+
+ pr_warn("siw: received ddp version unsupported %d\n",
+ __ddp_get_version(c_hdr));
+
+ if (c_hdr->ddp_rdmap_ctrl & DDP_FLAG_TAGGED) {
+ etype = DDP_ETYPE_TAGGED_BUF;
+ ecode = DDP_ECODE_T_VERSION;
+ } else {
+ etype = DDP_ETYPE_UNTAGGED_BUF;
+ ecode = DDP_ECODE_UT_VERSION;
+ }
+ siw_init_terminate(rx_qp(srx), TERM_ERROR_LAYER_DDP,
+ etype, ecode, 0);
+ return -EINVAL;
+ }
+ if (unlikely(__rdmap_get_version(c_hdr) != RDMAP_VERSION)) {
+ pr_warn("siw: received rdmap version unsupported %d\n",
+ __rdmap_get_version(c_hdr));
+
+ siw_init_terminate(rx_qp(srx), TERM_ERROR_LAYER_RDMAP,
+ RDMAP_ETYPE_REMOTE_OPERATION,
+ RDMAP_ECODE_VERSION, 0);
+ return -EINVAL;
+ }
+ opcode = __rdmap_get_opcode(c_hdr);
+
+ if (opcode > RDMAP_TERMINATE) {
+ pr_warn("siw: received unknown packet type %u\n",
+ opcode);
+
+ siw_init_terminate(rx_qp(srx), TERM_ERROR_LAYER_RDMAP,
+ RDMAP_ETYPE_REMOTE_OPERATION,
+ RDMAP_ECODE_OPCODE, 0);
+ return -EINVAL;
+ }
+ siw_dbg_qp(rx_qp(srx), "new header, opcode %u\n", opcode);
+ } else {
+ opcode = __rdmap_get_opcode(c_hdr);
+ }
+ set_rx_fpdu_context(qp, opcode);
+ frx = qp->rx_fpdu;
+
+ /*
+ * Figure out len of current hdr: variable length of
+ * iwarp hdr may force us to copy hdr information in
+ * two steps. Only tagged DDP messages are already
+ * completely received.
+ */
+ if (iwarp_pktinfo[opcode].hdr_len > sizeof(struct iwarp_ctrl_tagged)) {
+ bytes = iwarp_pktinfo[opcode].hdr_len - MIN_DDP_HDR;
+
+ if (srx->skb_new < bytes)
+ return -EAGAIN;
+
+ skb_copy_bits(skb, srx->skb_offset,
+ (char *)c_hdr + srx->fpdu_part_rcvd, bytes);
+
+ srx->fpdu_part_rcvd += bytes;
+
+ srx->skb_new -= bytes;
+ srx->skb_offset += bytes;
+ srx->skb_copied += bytes;
+ }
+
+ /*
+ * DDP/RDMAP header receive completed. Check if the current
+ * DDP segment starts a new RDMAP message or continues a previously
+ * started RDMAP message.
+ *
+ * Alternating reception of DDP segments (or FPDUs) from incomplete
+ * tagged and untagged RDMAP messages is supported, as long as
+ * the current tagged or untagged message gets eventually completed
+ * w/o intersection from another message of the same type
+ * (tagged/untagged). E.g., a WRITE can get intersected by a SEND,
+ * but not by a READ RESPONSE etc.
+ */
+ if (srx->mpa_crc_hd) {
+ /*
+ * Restart CRC computation
+ */
+ crypto_shash_init(srx->mpa_crc_hd);
+ crypto_shash_update(srx->mpa_crc_hd, (u8 *)c_hdr,
+ srx->fpdu_part_rcvd);
+ }
+ if (frx->more_ddp_segs) {
+ frx->first_ddp_seg = 0;
+ if (frx->prev_rdmap_op != opcode) {
+ pr_warn("siw: packet intersection: %u : %u\n",
+ frx->prev_rdmap_op, opcode);
+ /*
+ * The last inbound RDMA operation of same type
+ * (tagged or untagged) is left unfinished.
+ * To complete it in error, make it the current
+ * operation again, even with the header already
+ * overwritten. For error handling, only the opcode
+ * and current rx context are relevant.
+ */
+ set_rx_fpdu_context(qp, frx->prev_rdmap_op);
+ __rdmap_set_opcode(c_hdr, frx->prev_rdmap_op);
+ return -EPROTO;
+ }
+ } else {
+ frx->prev_rdmap_op = opcode;
+ frx->first_ddp_seg = 1;
+ }
+ frx->more_ddp_segs = c_hdr->ddp_rdmap_ctrl & DDP_FLAG_LAST ? 0 : 1;
+
+ return 0;
+}
+
+static int siw_check_tx_fence(struct siw_qp *qp)
+{
+ struct siw_wqe *tx_waiting = tx_wqe(qp);
+ struct siw_sqe *rreq;
+ int resume_tx = 0, rv = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&qp->orq_lock, flags);
+
+ rreq = orq_get_current(qp);
+
+ /* free current orq entry */
+ WRITE_ONCE(rreq->flags, 0);
+
+ if (qp->tx_ctx.orq_fence) {
+ if (unlikely(tx_waiting->wr_status != SIW_WR_QUEUED)) {
+ pr_warn("siw: [QP %u]: fence resume: bad status %d\n",
+ qp_id(qp), tx_waiting->wr_status);
+ rv = -EPROTO;
+ goto out;
+ }
+ /* resume SQ processing */
+ if (tx_waiting->sqe.opcode == SIW_OP_READ ||
+ tx_waiting->sqe.opcode == SIW_OP_READ_LOCAL_INV) {
+ rreq = orq_get_tail(qp);
+ if (unlikely(!rreq)) {
+ pr_warn("siw: [QP %u]: no ORQE\n", qp_id(qp));
+ rv = -EPROTO;
+ goto out;
+ }
+ siw_read_to_orq(rreq, &tx_waiting->sqe);
+
+ qp->orq_put++;
+ qp->tx_ctx.orq_fence = 0;
+ resume_tx = 1;
+
+ } else if (siw_orq_empty(qp)) {
+ qp->tx_ctx.orq_fence = 0;
+ resume_tx = 1;
+ } else {
+ pr_warn("siw: [QP %u]: fence resume: orq idx: %d:%d\n",
+ qp_id(qp), qp->orq_get, qp->orq_put);
+ rv = -EPROTO;
+ }
+ }
+ qp->orq_get++;
+out:
+ spin_unlock_irqrestore(&qp->orq_lock, flags);
+
+ if (resume_tx)
+ rv = siw_sq_start(qp);
+
+ return rv;
+}
+
+/*
+ * siw_rdmap_complete()
+ *
+ * Complete processing of an RDMA message after receiving all
+ * DDP segmens or ABort processing after encountering error case.
+ *
+ * o SENDs + RRESPs will need for completion,
+ * o RREQs need for READ RESPONSE initialization
+ * o WRITEs need memory dereferencing
+ *
+ * TODO: Failed WRITEs need local error to be surfaced.
+ */
+static int siw_rdmap_complete(struct siw_qp *qp, int error)
+{
+ struct siw_rx_stream *srx = &qp->rx_stream;
+ struct siw_wqe *wqe = rx_wqe(qp->rx_fpdu);
+ enum siw_wc_status wc_status = wqe->wc_status;
+ u8 opcode = __rdmap_get_opcode(&srx->hdr.ctrl);
+ int rv = 0;
+
+ switch (opcode) {
+ case RDMAP_SEND_SE:
+ case RDMAP_SEND_SE_INVAL:
+ wqe->rqe.flags |= SIW_WQE_SOLICITED;
+ /* Fall through */
+
+ case RDMAP_SEND:
+ case RDMAP_SEND_INVAL:
+ if (wqe->wr_status == SIW_WR_IDLE)
+ break;
+
+ srx->ddp_msn[RDMAP_UNTAGGED_QN_SEND]++;
+
+ if (error != 0 && wc_status == SIW_WC_SUCCESS)
+ wc_status = SIW_WC_GENERAL_ERR;
+ /*
+ * Handle STag invalidation request
+ */
+ if (wc_status == SIW_WC_SUCCESS &&
+ (opcode == RDMAP_SEND_INVAL ||
+ opcode == RDMAP_SEND_SE_INVAL)) {
+ rv = siw_invalidate_stag(qp->pd, srx->inval_stag);
+ if (rv) {
+ siw_init_terminate(
+ qp, TERM_ERROR_LAYER_RDMAP,
+ rv == -EACCES ?
+ RDMAP_ETYPE_REMOTE_PROTECTION :
+ RDMAP_ETYPE_REMOTE_OPERATION,
+ RDMAP_ECODE_CANNOT_INVALIDATE, 0);
+
+ wc_status = SIW_WC_REM_INV_REQ_ERR;
+ }
+ rv = siw_rqe_complete(qp, &wqe->rqe, wqe->processed,
+ rv ? 0 : srx->inval_stag,
+ wc_status);
+ } else {
+ rv = siw_rqe_complete(qp, &wqe->rqe, wqe->processed,
+ 0, wc_status);
+ }
+ siw_wqe_put_mem(wqe, SIW_OP_RECEIVE);
+ break;
+
+ case RDMAP_RDMA_READ_RESP:
+ if (wqe->wr_status == SIW_WR_IDLE)
+ break;
+
+ if (error != 0) {
+ if ((srx->state == SIW_GET_HDR &&
+ qp->rx_fpdu->first_ddp_seg) || error == -ENODATA)
+ /* possible RREQ in ORQ left untouched */
+ break;
+
+ if (wc_status == SIW_WC_SUCCESS)
+ wc_status = SIW_WC_GENERAL_ERR;
+ } else if (qp->kernel_verbs &&
+ rx_type(wqe) == SIW_OP_READ_LOCAL_INV) {
+ /*
+ * Handle any STag invalidation request
+ */
+ rv = siw_invalidate_stag(qp->pd, wqe->sqe.sge[0].lkey);
+ if (rv) {
+ siw_init_terminate(qp, TERM_ERROR_LAYER_RDMAP,
+ RDMAP_ETYPE_CATASTROPHIC,
+ RDMAP_ECODE_UNSPECIFIED, 0);
+
+ if (wc_status == SIW_WC_SUCCESS) {
+ wc_status = SIW_WC_GENERAL_ERR;
+ error = rv;
+ }
+ }
+ }
+ /*
+ * All errors turn the wqe into signalled.
+ */
+ if ((wqe->sqe.flags & SIW_WQE_SIGNALLED) || error != 0)
+ rv = siw_sqe_complete(qp, &wqe->sqe, wqe->processed,
+ wc_status);
+ siw_wqe_put_mem(wqe, SIW_OP_READ);
+
+ if (!error)
+ rv = siw_check_tx_fence(qp);
+ else
+ /* Disable current ORQ eleement */
+ WRITE_ONCE(orq_get_current(qp)->flags, 0);
+ break;
+
+ case RDMAP_RDMA_READ_REQ:
+ if (!error) {
+ rv = siw_init_rresp(qp, srx);
+ srx->ddp_msn[RDMAP_UNTAGGED_QN_RDMA_READ]++;
+ }
+ break;
+
+ case RDMAP_RDMA_WRITE:
+ if (wqe->wr_status == SIW_WR_IDLE)
+ break;
+
+ /*
+ * Free References from memory object if
+ * attached to receive context (inbound WRITE).
+ * While a zero-length WRITE is allowed,
+ * no memory reference got created.
+ */
+ if (rx_mem(&qp->rx_tagged)) {
+ siw_mem_put(rx_mem(&qp->rx_tagged));
+ rx_mem(&qp->rx_tagged) = NULL;
+ }
+ break;
+
+ default:
+ break;
+ }
+ wqe->wr_status = SIW_WR_IDLE;
+
+ return rv;
+}
+
+/*
+ * siw_tcp_rx_data()
+ *
+ * Main routine to consume inbound TCP payload
+ *
+ * @rd_desc: read descriptor
+ * @skb: socket buffer
+ * @off: offset in skb
+ * @len: skb->len - offset : payload in skb
+ */
+int siw_tcp_rx_data(read_descriptor_t *rd_desc, struct sk_buff *skb,
+ unsigned int off, size_t len)
+{
+ struct siw_qp *qp = rd_desc->arg.data;
+ struct siw_rx_stream *srx = &qp->rx_stream;
+ int rv;
+
+ srx->skb = skb;
+ srx->skb_new = skb->len - off;
+ srx->skb_offset = off;
+ srx->skb_copied = 0;
+
+ siw_dbg_qp(qp, "new data, len %d\n", srx->skb_new);
+
+ while (srx->skb_new) {
+ int run_completion = 1;
+
+ if (unlikely(srx->rx_suspend)) {
+ /* Do not process any more data */
+ srx->skb_copied += srx->skb_new;
+ break;
+ }
+ switch (srx->state) {
+ case SIW_GET_HDR:
+ rv = siw_get_hdr(srx);
+ if (!rv) {
+ srx->fpdu_part_rem =
+ be16_to_cpu(srx->hdr.ctrl.mpa_len) -
+ srx->fpdu_part_rcvd + MPA_HDR_SIZE;
+
+ if (srx->fpdu_part_rem)
+ srx->pad = -srx->fpdu_part_rem & 0x3;
+ else
+ srx->pad = 0;
+
+ srx->state = SIW_GET_DATA_START;
+ srx->fpdu_part_rcvd = 0;
+ }
+ break;
+
+ case SIW_GET_DATA_MORE:
+ /*
+ * Another data fragment of the same DDP segment.
+ * Setting first_ddp_seg = 0 avoids repeating
+ * initializations that shall occur only once per
+ * DDP segment.
+ */
+ qp->rx_fpdu->first_ddp_seg = 0;
+ /* Fall through */
+
+ case SIW_GET_DATA_START:
+ /*
+ * Headers will be checked by the opcode-specific
+ * data receive function below.
+ */
+ rv = iwarp_pktinfo[qp->rx_stream.rdmap_op].rx_data(qp);
+ if (!rv) {
+ int mpa_len =
+ be16_to_cpu(srx->hdr.ctrl.mpa_len)
+ + MPA_HDR_SIZE;
+
+ srx->fpdu_part_rem = (-mpa_len & 0x3)
+ + MPA_CRC_SIZE;
+ srx->fpdu_part_rcvd = 0;
+ srx->state = SIW_GET_TRAILER;
+ } else {
+ if (unlikely(rv == -ECONNRESET))
+ run_completion = 0;
+ else
+ srx->state = SIW_GET_DATA_MORE;
+ }
+ break;
+
+ case SIW_GET_TRAILER:
+ /*
+ * read CRC + any padding
+ */
+ rv = siw_get_trailer(qp, srx);
+ if (likely(!rv)) {
+ /*
+ * FPDU completed.
+ * complete RDMAP message if last fragment
+ */
+ srx->state = SIW_GET_HDR;
+ srx->fpdu_part_rcvd = 0;
+
+ if (!(srx->hdr.ctrl.ddp_rdmap_ctrl &
+ DDP_FLAG_LAST))
+ /* more frags */
+ break;
+
+ rv = siw_rdmap_complete(qp, 0);
+ run_completion = 0;
+ }
+ break;
+
+ default:
+ pr_warn("QP[%u]: RX out of state\n", qp_id(qp));
+ rv = -EPROTO;
+ run_completion = 0;
+ }
+ if (unlikely(rv != 0 && rv != -EAGAIN)) {
+ if ((srx->state > SIW_GET_HDR ||
+ qp->rx_fpdu->more_ddp_segs) && run_completion)
+ siw_rdmap_complete(qp, rv);
+
+ siw_dbg_qp(qp, "rx error %d, rx state %d\n", rv,
+ srx->state);
+
+ siw_qp_cm_drop(qp, 1);
+
+ break;
+ }
+ if (rv) {
+ siw_dbg_qp(qp, "fpdu fragment, state %d, missing %d\n",
+ srx->state, srx->fpdu_part_rem);
+ break;
+ }
+ }
+ return srx->skb_copied;
+}
diff --git a/drivers/infiniband/sw/siw/siw_qp_tx.c b/drivers/infiniband/sw/siw/siw_qp_tx.c
new file mode 100644
index 000000000000..43020d2040fc
--- /dev/null
+++ b/drivers/infiniband/sw/siw/siw_qp_tx.c
@@ -0,0 +1,1269 @@
+// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause
+
+/* Authors: Bernard Metzler <bmt@zurich.ibm.com> */
+/* Copyright (c) 2008-2019, IBM Corporation */
+
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/net.h>
+#include <linux/scatterlist.h>
+#include <linux/highmem.h>
+#include <net/tcp.h>
+
+#include <rdma/iw_cm.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_user_verbs.h>
+
+#include "siw.h"
+#include "siw_verbs.h"
+#include "siw_mem.h"
+
+#define MAX_HDR_INLINE \
+ (((uint32_t)(sizeof(struct siw_rreq_pkt) - \
+ sizeof(struct iwarp_send))) & 0xF8)
+
+static struct page *siw_get_pblpage(struct siw_mem *mem, u64 addr, int *idx)
+{
+ struct siw_pbl *pbl = mem->pbl;
+ u64 offset = addr - mem->va;
+ u64 paddr = siw_pbl_get_buffer(pbl, offset, NULL, idx);
+
+ if (paddr)
+ return virt_to_page(paddr);
+
+ return NULL;
+}
+
+/*
+ * Copy short payload at provided destination payload address
+ */
+static int siw_try_1seg(struct siw_iwarp_tx *c_tx, u64 paddr)
+{
+ struct siw_wqe *wqe = &c_tx->wqe_active;
+ struct siw_sge *sge = &wqe->sqe.sge[0];
+ u32 bytes = sge->length;
+
+ if (bytes > MAX_HDR_INLINE || wqe->sqe.num_sge != 1)
+ return MAX_HDR_INLINE + 1;
+
+ if (!bytes)
+ return 0;
+
+ if (tx_flags(wqe) & SIW_WQE_INLINE) {
+ memcpy((void *)paddr, &wqe->sqe.sge[1], bytes);
+ } else {
+ struct siw_mem *mem = wqe->mem[0];
+
+ if (!mem->mem_obj) {
+ /* Kernel client using kva */
+ memcpy((void *)paddr, (void *)sge->laddr, bytes);
+ } else if (c_tx->in_syscall) {
+ if (copy_from_user((void *)paddr,
+ (const void __user *)sge->laddr,
+ bytes))
+ return -EFAULT;
+ } else {
+ unsigned int off = sge->laddr & ~PAGE_MASK;
+ struct page *p;
+ char *buffer;
+ int pbl_idx = 0;
+
+ if (!mem->is_pbl)
+ p = siw_get_upage(mem->umem, sge->laddr);
+ else
+ p = siw_get_pblpage(mem, sge->laddr, &pbl_idx);
+
+ if (unlikely(!p))
+ return -EFAULT;
+
+ buffer = kmap_atomic(p);
+
+ if (likely(PAGE_SIZE - off >= bytes)) {
+ memcpy((void *)paddr, buffer + off, bytes);
+ kunmap_atomic(buffer);
+ } else {
+ unsigned long part = bytes - (PAGE_SIZE - off);
+
+ memcpy((void *)paddr, buffer + off, part);
+ kunmap_atomic(buffer);
+
+ if (!mem->is_pbl)
+ p = siw_get_upage(mem->umem,
+ sge->laddr + part);
+ else
+ p = siw_get_pblpage(mem,
+ sge->laddr + part,
+ &pbl_idx);
+ if (unlikely(!p))
+ return -EFAULT;
+
+ buffer = kmap_atomic(p);
+ memcpy((void *)(paddr + part), buffer,
+ bytes - part);
+ kunmap_atomic(buffer);
+ }
+ }
+ }
+ return (int)bytes;
+}
+
+#define PKT_FRAGMENTED 1
+#define PKT_COMPLETE 0
+
+/*
+ * siw_qp_prepare_tx()
+ *
+ * Prepare tx state for sending out one fpdu. Builds complete pkt
+ * if no user data or only immediate data are present.
+ *
+ * returns PKT_COMPLETE if complete pkt built, PKT_FRAGMENTED otherwise.
+ */
+static int siw_qp_prepare_tx(struct siw_iwarp_tx *c_tx)
+{
+ struct siw_wqe *wqe = &c_tx->wqe_active;
+ char *crc = NULL;
+ int data = 0;
+
+ switch (tx_type(wqe)) {
+ case SIW_OP_READ:
+ case SIW_OP_READ_LOCAL_INV:
+ memcpy(&c_tx->pkt.ctrl,
+ &iwarp_pktinfo[RDMAP_RDMA_READ_REQ].ctrl,
+ sizeof(struct iwarp_ctrl));
+
+ c_tx->pkt.rreq.rsvd = 0;
+ c_tx->pkt.rreq.ddp_qn = htonl(RDMAP_UNTAGGED_QN_RDMA_READ);
+ c_tx->pkt.rreq.ddp_msn =
+ htonl(++c_tx->ddp_msn[RDMAP_UNTAGGED_QN_RDMA_READ]);
+ c_tx->pkt.rreq.ddp_mo = 0;
+ c_tx->pkt.rreq.sink_stag = htonl(wqe->sqe.sge[0].lkey);
+ c_tx->pkt.rreq.sink_to =
+ cpu_to_be64(wqe->sqe.sge[0].laddr);
+ c_tx->pkt.rreq.source_stag = htonl(wqe->sqe.rkey);
+ c_tx->pkt.rreq.source_to = cpu_to_be64(wqe->sqe.raddr);
+ c_tx->pkt.rreq.read_size = htonl(wqe->sqe.sge[0].length);
+
+ c_tx->ctrl_len = sizeof(struct iwarp_rdma_rreq);
+ crc = (char *)&c_tx->pkt.rreq_pkt.crc;
+ break;
+
+ case SIW_OP_SEND:
+ if (tx_flags(wqe) & SIW_WQE_SOLICITED)
+ memcpy(&c_tx->pkt.ctrl,
+ &iwarp_pktinfo[RDMAP_SEND_SE].ctrl,
+ sizeof(struct iwarp_ctrl));
+ else
+ memcpy(&c_tx->pkt.ctrl, &iwarp_pktinfo[RDMAP_SEND].ctrl,
+ sizeof(struct iwarp_ctrl));
+
+ c_tx->pkt.send.ddp_qn = RDMAP_UNTAGGED_QN_SEND;
+ c_tx->pkt.send.ddp_msn =
+ htonl(++c_tx->ddp_msn[RDMAP_UNTAGGED_QN_SEND]);
+ c_tx->pkt.send.ddp_mo = 0;
+
+ c_tx->pkt.send_inv.inval_stag = 0;
+
+ c_tx->ctrl_len = sizeof(struct iwarp_send);
+
+ crc = (char *)&c_tx->pkt.send_pkt.crc;
+ data = siw_try_1seg(c_tx, (u64)crc);
+ break;
+
+ case SIW_OP_SEND_REMOTE_INV:
+ if (tx_flags(wqe) & SIW_WQE_SOLICITED)
+ memcpy(&c_tx->pkt.ctrl,
+ &iwarp_pktinfo[RDMAP_SEND_SE_INVAL].ctrl,
+ sizeof(struct iwarp_ctrl));
+ else
+ memcpy(&c_tx->pkt.ctrl,
+ &iwarp_pktinfo[RDMAP_SEND_INVAL].ctrl,
+ sizeof(struct iwarp_ctrl));
+
+ c_tx->pkt.send.ddp_qn = RDMAP_UNTAGGED_QN_SEND;
+ c_tx->pkt.send.ddp_msn =
+ htonl(++c_tx->ddp_msn[RDMAP_UNTAGGED_QN_SEND]);
+ c_tx->pkt.send.ddp_mo = 0;
+
+ c_tx->pkt.send_inv.inval_stag = cpu_to_be32(wqe->sqe.rkey);
+
+ c_tx->ctrl_len = sizeof(struct iwarp_send_inv);
+
+ crc = (char *)&c_tx->pkt.send_pkt.crc;
+ data = siw_try_1seg(c_tx, (u64)crc);
+ break;
+
+ case SIW_OP_WRITE:
+ memcpy(&c_tx->pkt.ctrl, &iwarp_pktinfo[RDMAP_RDMA_WRITE].ctrl,
+ sizeof(struct iwarp_ctrl));
+
+ c_tx->pkt.rwrite.sink_stag = htonl(wqe->sqe.rkey);
+ c_tx->pkt.rwrite.sink_to = cpu_to_be64(wqe->sqe.raddr);
+ c_tx->ctrl_len = sizeof(struct iwarp_rdma_write);
+
+ crc = (char *)&c_tx->pkt.write_pkt.crc;
+ data = siw_try_1seg(c_tx, (u64)crc);
+ break;
+
+ case SIW_OP_READ_RESPONSE:
+ memcpy(&c_tx->pkt.ctrl,
+ &iwarp_pktinfo[RDMAP_RDMA_READ_RESP].ctrl,
+ sizeof(struct iwarp_ctrl));
+
+ /* NBO */
+ c_tx->pkt.rresp.sink_stag = cpu_to_be32(wqe->sqe.rkey);
+ c_tx->pkt.rresp.sink_to = cpu_to_be64(wqe->sqe.raddr);
+
+ c_tx->ctrl_len = sizeof(struct iwarp_rdma_rresp);
+
+ crc = (char *)&c_tx->pkt.write_pkt.crc;
+ data = siw_try_1seg(c_tx, (u64)crc);
+ break;
+
+ default:
+ siw_dbg_qp(tx_qp(c_tx), "stale wqe type %d\n", tx_type(wqe));
+ return -EOPNOTSUPP;
+ }
+ if (unlikely(data < 0))
+ return data;
+
+ c_tx->ctrl_sent = 0;
+
+ if (data <= MAX_HDR_INLINE) {
+ if (data) {
+ wqe->processed = data;
+
+ c_tx->pkt.ctrl.mpa_len =
+ htons(c_tx->ctrl_len + data - MPA_HDR_SIZE);
+
+ /* Add pad, if needed */
+ data += -(int)data & 0x3;
+ /* advance CRC location after payload */
+ crc += data;
+ c_tx->ctrl_len += data;
+
+ if (!(c_tx->pkt.ctrl.ddp_rdmap_ctrl & DDP_FLAG_TAGGED))
+ c_tx->pkt.c_untagged.ddp_mo = 0;
+ else
+ c_tx->pkt.c_tagged.ddp_to =
+ cpu_to_be64(wqe->sqe.raddr);
+ }
+
+ *(u32 *)crc = 0;
+ /*
+ * Do complete CRC if enabled and short packet
+ */
+ if (c_tx->mpa_crc_hd) {
+ crypto_shash_init(c_tx->mpa_crc_hd);
+ if (crypto_shash_update(c_tx->mpa_crc_hd,
+ (u8 *)&c_tx->pkt,
+ c_tx->ctrl_len))
+ return -EINVAL;
+ crypto_shash_final(c_tx->mpa_crc_hd, (u8 *)crc);
+ }
+ c_tx->ctrl_len += MPA_CRC_SIZE;
+
+ return PKT_COMPLETE;
+ }
+ c_tx->ctrl_len += MPA_CRC_SIZE;
+ c_tx->sge_idx = 0;
+ c_tx->sge_off = 0;
+ c_tx->pbl_idx = 0;
+
+ /*
+ * Allow direct sending out of user buffer if WR is non signalled
+ * and payload is over threshold.
+ * Per RDMA verbs, the application should not change the send buffer
+ * until the work completed. In iWarp, work completion is only
+ * local delivery to TCP. TCP may reuse the buffer for
+ * retransmission. Changing unsent data also breaks the CRC,
+ * if applied.
+ */
+ if (c_tx->zcopy_tx && wqe->bytes >= SENDPAGE_THRESH &&
+ !(tx_flags(wqe) & SIW_WQE_SIGNALLED))
+ c_tx->use_sendpage = 1;
+ else
+ c_tx->use_sendpage = 0;
+
+ return PKT_FRAGMENTED;
+}
+
+/*
+ * Send out one complete control type FPDU, or header of FPDU carrying
+ * data. Used for fixed sized packets like Read.Requests or zero length
+ * SENDs, WRITEs, READ.Responses, or header only.
+ */
+static int siw_tx_ctrl(struct siw_iwarp_tx *c_tx, struct socket *s,
+ int flags)
+{
+ struct msghdr msg = { .msg_flags = flags };
+ struct kvec iov = { .iov_base =
+ (char *)&c_tx->pkt.ctrl + c_tx->ctrl_sent,
+ .iov_len = c_tx->ctrl_len - c_tx->ctrl_sent };
+
+ int rv = kernel_sendmsg(s, &msg, &iov, 1,
+ c_tx->ctrl_len - c_tx->ctrl_sent);
+
+ if (rv >= 0) {
+ c_tx->ctrl_sent += rv;
+
+ if (c_tx->ctrl_sent == c_tx->ctrl_len)
+ rv = 0;
+ else
+ rv = -EAGAIN;
+ }
+ return rv;
+}
+
+/*
+ * 0copy TCP transmit interface: Use do_tcp_sendpages.
+ *
+ * Using sendpage to push page by page appears to be less efficient
+ * than using sendmsg, even if data are copied.
+ *
+ * A general performance limitation might be the extra four bytes
+ * trailer checksum segment to be pushed after user data.
+ */
+static int siw_tcp_sendpages(struct socket *s, struct page **page, int offset,
+ size_t size)
+{
+ struct sock *sk = s->sk;
+ int i = 0, rv = 0, sent = 0,
+ flags = MSG_MORE | MSG_DONTWAIT | MSG_SENDPAGE_NOTLAST;
+
+ while (size) {
+ size_t bytes = min_t(size_t, PAGE_SIZE - offset, size);
+
+ if (size + offset <= PAGE_SIZE)
+ flags = MSG_MORE | MSG_DONTWAIT;
+
+ tcp_rate_check_app_limited(sk);
+try_page_again:
+ lock_sock(sk);
+ rv = do_tcp_sendpages(sk, page[i], offset, bytes, flags);
+ release_sock(sk);
+
+ if (rv > 0) {
+ size -= rv;
+ sent += rv;
+ if (rv != bytes) {
+ offset += rv;
+ bytes -= rv;
+ goto try_page_again;
+ }
+ offset = 0;
+ } else {
+ if (rv == -EAGAIN || rv == 0)
+ break;
+ return rv;
+ }
+ i++;
+ }
+ return sent;
+}
+
+/*
+ * siw_0copy_tx()
+ *
+ * Pushes list of pages to TCP socket. If pages from multiple
+ * SGE's, all referenced pages of each SGE are pushed in one
+ * shot.
+ */
+static int siw_0copy_tx(struct socket *s, struct page **page,
+ struct siw_sge *sge, unsigned int offset,
+ unsigned int size)
+{
+ int i = 0, sent = 0, rv;
+ int sge_bytes = min(sge->length - offset, size);
+
+ offset = (sge->laddr + offset) & ~PAGE_MASK;
+
+ while (sent != size) {
+ rv = siw_tcp_sendpages(s, &page[i], offset, sge_bytes);
+ if (rv >= 0) {
+ sent += rv;
+ if (size == sent || sge_bytes > rv)
+ break;
+
+ i += PAGE_ALIGN(sge_bytes + offset) >> PAGE_SHIFT;
+ sge++;
+ sge_bytes = min(sge->length, size - sent);
+ offset = sge->laddr & ~PAGE_MASK;
+ } else {
+ sent = rv;
+ break;
+ }
+ }
+ return sent;
+}
+
+#define MAX_TRAILER (MPA_CRC_SIZE + 4)
+
+static void siw_unmap_pages(struct page **pages, int hdr_len, int num_maps)
+{
+ if (hdr_len) {
+ ++pages;
+ --num_maps;
+ }
+ while (num_maps-- > 0) {
+ kunmap(*pages);
+ pages++;
+ }
+}
+
+/*
+ * siw_tx_hdt() tries to push a complete packet to TCP where all
+ * packet fragments are referenced by the elements of one iovec.
+ * For the data portion, each involved page must be referenced by
+ * one extra element. All sge's data can be non-aligned to page
+ * boundaries. Two more elements are referencing iWARP header
+ * and trailer:
+ * MAX_ARRAY = 64KB/PAGE_SIZE + 1 + (2 * (SIW_MAX_SGE - 1) + HDR + TRL
+ */
+#define MAX_ARRAY ((0xffff / PAGE_SIZE) + 1 + (2 * (SIW_MAX_SGE - 1) + 2))
+
+/*
+ * Write out iov referencing hdr, data and trailer of current FPDU.
+ * Update transmit state dependent on write return status
+ */
+static int siw_tx_hdt(struct siw_iwarp_tx *c_tx, struct socket *s)
+{
+ struct siw_wqe *wqe = &c_tx->wqe_active;
+ struct siw_sge *sge = &wqe->sqe.sge[c_tx->sge_idx];
+ struct kvec iov[MAX_ARRAY];
+ struct page *page_array[MAX_ARRAY];
+ struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_EOR };
+
+ int seg = 0, do_crc = c_tx->do_crc, is_kva = 0, rv;
+ unsigned int data_len = c_tx->bytes_unsent, hdr_len = 0, trl_len = 0,
+ sge_off = c_tx->sge_off, sge_idx = c_tx->sge_idx,
+ pbl_idx = c_tx->pbl_idx;
+
+ if (c_tx->state == SIW_SEND_HDR) {
+ if (c_tx->use_sendpage) {
+ rv = siw_tx_ctrl(c_tx, s, MSG_DONTWAIT | MSG_MORE);
+ if (rv)
+ goto done;
+
+ c_tx->state = SIW_SEND_DATA;
+ } else {
+ iov[0].iov_base =
+ (char *)&c_tx->pkt.ctrl + c_tx->ctrl_sent;
+ iov[0].iov_len = hdr_len =
+ c_tx->ctrl_len - c_tx->ctrl_sent;
+ seg = 1;
+ }
+ }
+
+ wqe->processed += data_len;
+
+ while (data_len) { /* walk the list of SGE's */
+ unsigned int sge_len = min(sge->length - sge_off, data_len);
+ unsigned int fp_off = (sge->laddr + sge_off) & ~PAGE_MASK;
+ struct siw_mem *mem;
+
+ if (!(tx_flags(wqe) & SIW_WQE_INLINE)) {
+ mem = wqe->mem[sge_idx];
+ if (!mem->mem_obj)
+ is_kva = 1;
+ } else {
+ is_kva = 1;
+ }
+ if (is_kva && !c_tx->use_sendpage) {
+ /*
+ * tx from kernel virtual address: either inline data
+ * or memory region with assigned kernel buffer
+ */
+ iov[seg].iov_base = (void *)(sge->laddr + sge_off);
+ iov[seg].iov_len = sge_len;
+
+ if (do_crc)
+ crypto_shash_update(c_tx->mpa_crc_hd,
+ iov[seg].iov_base,
+ sge_len);
+ sge_off += sge_len;
+ data_len -= sge_len;
+ seg++;
+ goto sge_done;
+ }
+
+ while (sge_len) {
+ size_t plen = min((int)PAGE_SIZE - fp_off, sge_len);
+
+ if (!is_kva) {
+ struct page *p;
+
+ if (mem->is_pbl)
+ p = siw_get_pblpage(
+ mem, sge->laddr + sge_off,
+ &pbl_idx);
+ else
+ p = siw_get_upage(mem->umem,
+ sge->laddr + sge_off);
+ if (unlikely(!p)) {
+ if (hdr_len)
+ seg--;
+ if (!c_tx->use_sendpage && seg) {
+ siw_unmap_pages(page_array,
+ hdr_len, seg);
+ }
+ wqe->processed -= c_tx->bytes_unsent;
+ rv = -EFAULT;
+ goto done_crc;
+ }
+ page_array[seg] = p;
+
+ if (!c_tx->use_sendpage) {
+ iov[seg].iov_base = kmap(p) + fp_off;
+ iov[seg].iov_len = plen;
+ if (do_crc)
+ crypto_shash_update(
+ c_tx->mpa_crc_hd,
+ iov[seg].iov_base,
+ plen);
+ } else if (do_crc)
+ crypto_shash_update(
+ c_tx->mpa_crc_hd,
+ page_address(p) + fp_off,
+ plen);
+ } else {
+ u64 pa = ((sge->laddr + sge_off) & PAGE_MASK);
+
+ page_array[seg] = virt_to_page(pa);
+ if (do_crc)
+ crypto_shash_update(
+ c_tx->mpa_crc_hd,
+ (void *)(sge->laddr + sge_off),
+ plen);
+ }
+
+ sge_len -= plen;
+ sge_off += plen;
+ data_len -= plen;
+ fp_off = 0;
+
+ if (++seg > (int)MAX_ARRAY) {
+ siw_dbg_qp(tx_qp(c_tx), "to many fragments\n");
+ if (!is_kva && !c_tx->use_sendpage) {
+ siw_unmap_pages(page_array, hdr_len,
+ seg - 1);
+ }
+ wqe->processed -= c_tx->bytes_unsent;
+ rv = -EMSGSIZE;
+ goto done_crc;
+ }
+ }
+sge_done:
+ /* Update SGE variables at end of SGE */
+ if (sge_off == sge->length &&
+ (data_len != 0 || wqe->processed < wqe->bytes)) {
+ sge_idx++;
+ sge++;
+ sge_off = 0;
+ }
+ }
+ /* trailer */
+ if (likely(c_tx->state != SIW_SEND_TRAILER)) {
+ iov[seg].iov_base = &c_tx->trailer.pad[4 - c_tx->pad];
+ iov[seg].iov_len = trl_len = MAX_TRAILER - (4 - c_tx->pad);
+ } else {
+ iov[seg].iov_base = &c_tx->trailer.pad[c_tx->ctrl_sent];
+ iov[seg].iov_len = trl_len = MAX_TRAILER - c_tx->ctrl_sent;
+ }
+
+ if (c_tx->pad) {
+ *(u32 *)c_tx->trailer.pad = 0;
+ if (do_crc)
+ crypto_shash_update(c_tx->mpa_crc_hd,
+ (u8 *)&c_tx->trailer.crc - c_tx->pad,
+ c_tx->pad);
+ }
+ if (!c_tx->mpa_crc_hd)
+ c_tx->trailer.crc = 0;
+ else if (do_crc)
+ crypto_shash_final(c_tx->mpa_crc_hd, (u8 *)&c_tx->trailer.crc);
+
+ data_len = c_tx->bytes_unsent;
+
+ if (c_tx->use_sendpage) {
+ rv = siw_0copy_tx(s, page_array, &wqe->sqe.sge[c_tx->sge_idx],
+ c_tx->sge_off, data_len);
+ if (rv == data_len) {
+ rv = kernel_sendmsg(s, &msg, &iov[seg], 1, trl_len);
+ if (rv > 0)
+ rv += data_len;
+ else
+ rv = data_len;
+ }
+ } else {
+ rv = kernel_sendmsg(s, &msg, iov, seg + 1,
+ hdr_len + data_len + trl_len);
+ if (!is_kva)
+ siw_unmap_pages(page_array, hdr_len, seg);
+ }
+ if (rv < (int)hdr_len) {
+ /* Not even complete hdr pushed or negative rv */
+ wqe->processed -= data_len;
+ if (rv >= 0) {
+ c_tx->ctrl_sent += rv;
+ rv = -EAGAIN;
+ }
+ goto done_crc;
+ }
+ rv -= hdr_len;
+
+ if (rv >= (int)data_len) {
+ /* all user data pushed to TCP or no data to push */
+ if (data_len > 0 && wqe->processed < wqe->bytes) {
+ /* Save the current state for next tx */
+ c_tx->sge_idx = sge_idx;
+ c_tx->sge_off = sge_off;
+ c_tx->pbl_idx = pbl_idx;
+ }
+ rv -= data_len;
+
+ if (rv == trl_len) /* all pushed */
+ rv = 0;
+ else {
+ c_tx->state = SIW_SEND_TRAILER;
+ c_tx->ctrl_len = MAX_TRAILER;
+ c_tx->ctrl_sent = rv + 4 - c_tx->pad;
+ c_tx->bytes_unsent = 0;
+ rv = -EAGAIN;
+ }
+
+ } else if (data_len > 0) {
+ /* Maybe some user data pushed to TCP */
+ c_tx->state = SIW_SEND_DATA;
+ wqe->processed -= data_len - rv;
+
+ if (rv) {
+ /*
+ * Some bytes out. Recompute tx state based
+ * on old state and bytes pushed
+ */
+ unsigned int sge_unsent;
+
+ c_tx->bytes_unsent -= rv;
+ sge = &wqe->sqe.sge[c_tx->sge_idx];
+ sge_unsent = sge->length - c_tx->sge_off;
+
+ while (sge_unsent <= rv) {
+ rv -= sge_unsent;
+ c_tx->sge_idx++;
+ c_tx->sge_off = 0;
+ sge++;
+ sge_unsent = sge->length;
+ }
+ c_tx->sge_off += rv;
+ }
+ rv = -EAGAIN;
+ }
+done_crc:
+ c_tx->do_crc = 0;
+done:
+ return rv;
+}
+
+static void siw_update_tcpseg(struct siw_iwarp_tx *c_tx,
+ struct socket *s)
+{
+ struct tcp_sock *tp = tcp_sk(s->sk);
+
+ if (tp->gso_segs) {
+ if (c_tx->gso_seg_limit == 0)
+ c_tx->tcp_seglen = tp->mss_cache * tp->gso_segs;
+ else
+ c_tx->tcp_seglen =
+ tp->mss_cache *
+ min_t(u16, c_tx->gso_seg_limit, tp->gso_segs);
+ } else {
+ c_tx->tcp_seglen = tp->mss_cache;
+ }
+ /* Loopback may give odd numbers */
+ c_tx->tcp_seglen &= 0xfffffff8;
+}
+
+/*
+ * siw_prepare_fpdu()
+ *
+ * Prepares transmit context to send out one FPDU if FPDU will contain
+ * user data and user data are not immediate data.
+ * Computes maximum FPDU length to fill up TCP MSS if possible.
+ *
+ * @qp: QP from which to transmit
+ * @wqe: Current WQE causing transmission
+ *
+ * TODO: Take into account real available sendspace on socket
+ * to avoid header misalignment due to send pausing within
+ * fpdu transmission
+ */
+static void siw_prepare_fpdu(struct siw_qp *qp, struct siw_wqe *wqe)
+{
+ struct siw_iwarp_tx *c_tx = &qp->tx_ctx;
+ int data_len;
+
+ c_tx->ctrl_len =
+ iwarp_pktinfo[__rdmap_get_opcode(&c_tx->pkt.ctrl)].hdr_len;
+ c_tx->ctrl_sent = 0;
+
+ /*
+ * Update target buffer offset if any
+ */
+ if (!(c_tx->pkt.ctrl.ddp_rdmap_ctrl & DDP_FLAG_TAGGED))
+ /* Untagged message */
+ c_tx->pkt.c_untagged.ddp_mo = cpu_to_be32(wqe->processed);
+ else /* Tagged message */
+ c_tx->pkt.c_tagged.ddp_to =
+ cpu_to_be64(wqe->sqe.raddr + wqe->processed);
+
+ data_len = wqe->bytes - wqe->processed;
+ if (data_len + c_tx->ctrl_len + MPA_CRC_SIZE > c_tx->tcp_seglen) {
+ /* Trim DDP payload to fit into current TCP segment */
+ data_len = c_tx->tcp_seglen - (c_tx->ctrl_len + MPA_CRC_SIZE);
+ c_tx->pkt.ctrl.ddp_rdmap_ctrl &= ~DDP_FLAG_LAST;
+ c_tx->pad = 0;
+ } else {
+ c_tx->pkt.ctrl.ddp_rdmap_ctrl |= DDP_FLAG_LAST;
+ c_tx->pad = -data_len & 0x3;
+ }
+ c_tx->bytes_unsent = data_len;
+
+ c_tx->pkt.ctrl.mpa_len =
+ htons(c_tx->ctrl_len + data_len - MPA_HDR_SIZE);
+
+ /*
+ * Init MPA CRC computation
+ */
+ if (c_tx->mpa_crc_hd) {
+ crypto_shash_init(c_tx->mpa_crc_hd);
+ crypto_shash_update(c_tx->mpa_crc_hd, (u8 *)&c_tx->pkt,
+ c_tx->ctrl_len);
+ c_tx->do_crc = 1;
+ }
+}
+
+/*
+ * siw_check_sgl_tx()
+ *
+ * Check permissions for a list of SGE's (SGL).
+ * A successful check will have all memory referenced
+ * for transmission resolved and assigned to the WQE.
+ *
+ * @pd: Protection Domain SGL should belong to
+ * @wqe: WQE to be checked
+ * @perms: requested access permissions
+ *
+ */
+
+static int siw_check_sgl_tx(struct ib_pd *pd, struct siw_wqe *wqe,
+ enum ib_access_flags perms)
+{
+ struct siw_sge *sge = &wqe->sqe.sge[0];
+ int i, len, num_sge = wqe->sqe.num_sge;
+
+ if (unlikely(num_sge > SIW_MAX_SGE))
+ return -EINVAL;
+
+ for (i = 0, len = 0; num_sge; num_sge--, i++, sge++) {
+ /*
+ * rdma verbs: do not check stag for a zero length sge
+ */
+ if (sge->length) {
+ int rv = siw_check_sge(pd, sge, &wqe->mem[i], perms, 0,
+ sge->length);
+
+ if (unlikely(rv != E_ACCESS_OK))
+ return rv;
+ }
+ len += sge->length;
+ }
+ return len;
+}
+
+/*
+ * siw_qp_sq_proc_tx()
+ *
+ * Process one WQE which needs transmission on the wire.
+ */
+static int siw_qp_sq_proc_tx(struct siw_qp *qp, struct siw_wqe *wqe)
+{
+ struct siw_iwarp_tx *c_tx = &qp->tx_ctx;
+ struct socket *s = qp->attrs.sk;
+ int rv = 0, burst_len = qp->tx_ctx.burst;
+ enum rdmap_ecode ecode = RDMAP_ECODE_CATASTROPHIC_STREAM;
+
+ if (unlikely(wqe->wr_status == SIW_WR_IDLE))
+ return 0;
+
+ if (!burst_len)
+ burst_len = SQ_USER_MAXBURST;
+
+ if (wqe->wr_status == SIW_WR_QUEUED) {
+ if (!(wqe->sqe.flags & SIW_WQE_INLINE)) {
+ if (tx_type(wqe) == SIW_OP_READ_RESPONSE)
+ wqe->sqe.num_sge = 1;
+
+ if (tx_type(wqe) != SIW_OP_READ &&
+ tx_type(wqe) != SIW_OP_READ_LOCAL_INV) {
+ /*
+ * Reference memory to be tx'd w/o checking
+ * access for LOCAL_READ permission, since
+ * not defined in RDMA core.
+ */
+ rv = siw_check_sgl_tx(qp->pd, wqe, 0);
+ if (rv < 0) {
+ if (tx_type(wqe) ==
+ SIW_OP_READ_RESPONSE)
+ ecode = siw_rdmap_error(-rv);
+ rv = -EINVAL;
+ goto tx_error;
+ }
+ wqe->bytes = rv;
+ } else {
+ wqe->bytes = 0;
+ }
+ } else {
+ wqe->bytes = wqe->sqe.sge[0].length;
+ if (!qp->kernel_verbs) {
+ if (wqe->bytes > SIW_MAX_INLINE) {
+ rv = -EINVAL;
+ goto tx_error;
+ }
+ wqe->sqe.sge[0].laddr = (u64)&wqe->sqe.sge[1];
+ }
+ }
+ wqe->wr_status = SIW_WR_INPROGRESS;
+ wqe->processed = 0;
+
+ siw_update_tcpseg(c_tx, s);
+
+ rv = siw_qp_prepare_tx(c_tx);
+ if (rv == PKT_FRAGMENTED) {
+ c_tx->state = SIW_SEND_HDR;
+ siw_prepare_fpdu(qp, wqe);
+ } else if (rv == PKT_COMPLETE) {
+ c_tx->state = SIW_SEND_SHORT_FPDU;
+ } else {
+ goto tx_error;
+ }
+ }
+
+next_segment:
+ siw_dbg_qp(qp, "wr type %d, state %d, data %u, sent %u, id %llx\n",
+ tx_type(wqe), wqe->wr_status, wqe->bytes, wqe->processed,
+ wqe->sqe.id);
+
+ if (--burst_len == 0) {
+ rv = -EINPROGRESS;
+ goto tx_done;
+ }
+ if (c_tx->state == SIW_SEND_SHORT_FPDU) {
+ enum siw_opcode tx_type = tx_type(wqe);
+ unsigned int msg_flags;
+
+ if (siw_sq_empty(qp) || !siw_tcp_nagle || burst_len == 1)
+ /*
+ * End current TCP segment, if SQ runs empty,
+ * or siw_tcp_nagle is not set, or we bail out
+ * soon due to no burst credit left.
+ */
+ msg_flags = MSG_DONTWAIT;
+ else
+ msg_flags = MSG_DONTWAIT | MSG_MORE;
+
+ rv = siw_tx_ctrl(c_tx, s, msg_flags);
+
+ if (!rv && tx_type != SIW_OP_READ &&
+ tx_type != SIW_OP_READ_LOCAL_INV)
+ wqe->processed = wqe->bytes;
+
+ goto tx_done;
+
+ } else {
+ rv = siw_tx_hdt(c_tx, s);
+ }
+ if (!rv) {
+ /*
+ * One segment sent. Processing completed if last
+ * segment, Do next segment otherwise.
+ */
+ if (unlikely(c_tx->tx_suspend)) {
+ /*
+ * Verbs, 6.4.: Try stopping sending after a full
+ * DDP segment if the connection goes down
+ * (== peer halfclose)
+ */
+ rv = -ECONNABORTED;
+ goto tx_done;
+ }
+ if (c_tx->pkt.ctrl.ddp_rdmap_ctrl & DDP_FLAG_LAST) {
+ siw_dbg_qp(qp, "WQE completed\n");
+ goto tx_done;
+ }
+ c_tx->state = SIW_SEND_HDR;
+
+ siw_update_tcpseg(c_tx, s);
+
+ siw_prepare_fpdu(qp, wqe);
+ goto next_segment;
+ }
+tx_done:
+ qp->tx_ctx.burst = burst_len;
+ return rv;
+
+tx_error:
+ if (ecode != RDMAP_ECODE_CATASTROPHIC_STREAM)
+ siw_init_terminate(qp, TERM_ERROR_LAYER_RDMAP,
+ RDMAP_ETYPE_REMOTE_PROTECTION, ecode, 1);
+ else
+ siw_init_terminate(qp, TERM_ERROR_LAYER_RDMAP,
+ RDMAP_ETYPE_CATASTROPHIC,
+ RDMAP_ECODE_UNSPECIFIED, 1);
+ return rv;
+}
+
+static int siw_fastreg_mr(struct ib_pd *pd, struct siw_sqe *sqe)
+{
+ struct ib_mr *base_mr = (struct ib_mr *)sqe->base_mr;
+ struct siw_device *sdev = to_siw_dev(pd->device);
+ struct siw_mem *mem = siw_mem_id2obj(sdev, sqe->rkey >> 8);
+ int rv = 0;
+
+ siw_dbg_pd(pd, "STag 0x%08x\n", sqe->rkey);
+
+ if (unlikely(!mem || !base_mr)) {
+ pr_warn("siw: fastreg: STag 0x%08x unknown\n", sqe->rkey);
+ return -EINVAL;
+ }
+ if (unlikely(base_mr->rkey >> 8 != sqe->rkey >> 8)) {
+ pr_warn("siw: fastreg: STag 0x%08x: bad MR\n", sqe->rkey);
+ rv = -EINVAL;
+ goto out;
+ }
+ if (unlikely(mem->pd != pd)) {
+ pr_warn("siw: fastreg: PD mismatch\n");
+ rv = -EINVAL;
+ goto out;
+ }
+ if (unlikely(mem->stag_valid)) {
+ pr_warn("siw: fastreg: STag 0x%08x already valid\n", sqe->rkey);
+ rv = -EINVAL;
+ goto out;
+ }
+ /* Refresh STag since user may have changed key part */
+ mem->stag = sqe->rkey;
+ mem->perms = sqe->access;
+
+ siw_dbg_mem(mem, "STag now valid, MR va: 0x%016llx -> 0x%016llx\n",
+ mem->va, base_mr->iova);
+ mem->va = base_mr->iova;
+ mem->stag_valid = 1;
+out:
+ siw_mem_put(mem);
+ return rv;
+}
+
+static int siw_qp_sq_proc_local(struct siw_qp *qp, struct siw_wqe *wqe)
+{
+ int rv;
+
+ switch (tx_type(wqe)) {
+ case SIW_OP_REG_MR:
+ rv = siw_fastreg_mr(qp->pd, &wqe->sqe);
+ break;
+
+ case SIW_OP_INVAL_STAG:
+ rv = siw_invalidate_stag(qp->pd, wqe->sqe.rkey);
+ break;
+
+ default:
+ rv = -EINVAL;
+ }
+ return rv;
+}
+
+/*
+ * siw_qp_sq_process()
+ *
+ * Core TX path routine for RDMAP/DDP/MPA using a TCP kernel socket.
+ * Sends RDMAP payload for the current SQ WR @wqe of @qp in one or more
+ * MPA FPDUs, each containing a DDP segment.
+ *
+ * SQ processing may occur in user context as a result of posting
+ * new WQE's or from siw_sq_work_handler() context. Processing in
+ * user context is limited to non-kernel verbs users.
+ *
+ * SQ processing may get paused anytime, possibly in the middle of a WR
+ * or FPDU, if insufficient send space is available. SQ processing
+ * gets resumed from siw_sq_work_handler(), if send space becomes
+ * available again.
+ *
+ * Must be called with the QP state read-locked.
+ *
+ * Note:
+ * An outbound RREQ can be satisfied by the corresponding RRESP
+ * _before_ it gets assigned to the ORQ. This happens regularly
+ * in RDMA READ via loopback case. Since both outbound RREQ and
+ * inbound RRESP can be handled by the same CPU, locking the ORQ
+ * is dead-lock prone and thus not an option. With that, the
+ * RREQ gets assigned to the ORQ _before_ being sent - see
+ * siw_activate_tx() - and pulled back in case of send failure.
+ */
+int siw_qp_sq_process(struct siw_qp *qp)
+{
+ struct siw_wqe *wqe = tx_wqe(qp);
+ enum siw_opcode tx_type;
+ unsigned long flags;
+ int rv = 0;
+
+ siw_dbg_qp(qp, "enter for type %d\n", tx_type(wqe));
+
+next_wqe:
+ /*
+ * Stop QP processing if SQ state changed
+ */
+ if (unlikely(qp->tx_ctx.tx_suspend)) {
+ siw_dbg_qp(qp, "tx suspended\n");
+ goto done;
+ }
+ tx_type = tx_type(wqe);
+
+ if (tx_type <= SIW_OP_READ_RESPONSE)
+ rv = siw_qp_sq_proc_tx(qp, wqe);
+ else
+ rv = siw_qp_sq_proc_local(qp, wqe);
+
+ if (!rv) {
+ /*
+ * WQE processing done
+ */
+ switch (tx_type) {
+ case SIW_OP_SEND:
+ case SIW_OP_SEND_REMOTE_INV:
+ case SIW_OP_WRITE:
+ siw_wqe_put_mem(wqe, tx_type);
+ /* Fall through */
+
+ case SIW_OP_INVAL_STAG:
+ case SIW_OP_REG_MR:
+ if (tx_flags(wqe) & SIW_WQE_SIGNALLED)
+ siw_sqe_complete(qp, &wqe->sqe, wqe->bytes,
+ SIW_WC_SUCCESS);
+ break;
+
+ case SIW_OP_READ:
+ case SIW_OP_READ_LOCAL_INV:
+ /*
+ * already enqueued to ORQ queue
+ */
+ break;
+
+ case SIW_OP_READ_RESPONSE:
+ siw_wqe_put_mem(wqe, tx_type);
+ break;
+
+ default:
+ WARN(1, "undefined WQE type %d\n", tx_type);
+ rv = -EINVAL;
+ goto done;
+ }
+
+ spin_lock_irqsave(&qp->sq_lock, flags);
+ wqe->wr_status = SIW_WR_IDLE;
+ rv = siw_activate_tx(qp);
+ spin_unlock_irqrestore(&qp->sq_lock, flags);
+
+ if (rv <= 0)
+ goto done;
+
+ goto next_wqe;
+
+ } else if (rv == -EAGAIN) {
+ siw_dbg_qp(qp, "sq paused: hd/tr %d of %d, data %d\n",
+ qp->tx_ctx.ctrl_sent, qp->tx_ctx.ctrl_len,
+ qp->tx_ctx.bytes_unsent);
+ rv = 0;
+ goto done;
+ } else if (rv == -EINPROGRESS) {
+ rv = siw_sq_start(qp);
+ goto done;
+ } else {
+ /*
+ * WQE processing failed.
+ * Verbs 8.3.2:
+ * o It turns any WQE into a signalled WQE.
+ * o Local catastrophic error must be surfaced
+ * o QP must be moved into Terminate state: done by code
+ * doing socket state change processing
+ *
+ * o TODO: Termination message must be sent.
+ * o TODO: Implement more precise work completion errors,
+ * see enum ib_wc_status in ib_verbs.h
+ */
+ siw_dbg_qp(qp, "wqe type %d processing failed: %d\n",
+ tx_type(wqe), rv);
+
+ spin_lock_irqsave(&qp->sq_lock, flags);
+ /*
+ * RREQ may have already been completed by inbound RRESP!
+ */
+ if (tx_type == SIW_OP_READ ||
+ tx_type == SIW_OP_READ_LOCAL_INV) {
+ /* Cleanup pending entry in ORQ */
+ qp->orq_put--;
+ qp->orq[qp->orq_put % qp->attrs.orq_size].flags = 0;
+ }
+ spin_unlock_irqrestore(&qp->sq_lock, flags);
+ /*
+ * immediately suspends further TX processing
+ */
+ if (!qp->tx_ctx.tx_suspend)
+ siw_qp_cm_drop(qp, 0);
+
+ switch (tx_type) {
+ case SIW_OP_SEND:
+ case SIW_OP_SEND_REMOTE_INV:
+ case SIW_OP_SEND_WITH_IMM:
+ case SIW_OP_WRITE:
+ case SIW_OP_READ:
+ case SIW_OP_READ_LOCAL_INV:
+ siw_wqe_put_mem(wqe, tx_type);
+ /* Fall through */
+
+ case SIW_OP_INVAL_STAG:
+ case SIW_OP_REG_MR:
+ siw_sqe_complete(qp, &wqe->sqe, wqe->bytes,
+ SIW_WC_LOC_QP_OP_ERR);
+
+ siw_qp_event(qp, IB_EVENT_QP_FATAL);
+
+ break;
+
+ case SIW_OP_READ_RESPONSE:
+ siw_dbg_qp(qp, "proc. read.response failed: %d\n", rv);
+
+ siw_qp_event(qp, IB_EVENT_QP_REQ_ERR);
+
+ siw_wqe_put_mem(wqe, SIW_OP_READ_RESPONSE);
+
+ break;
+
+ default:
+ WARN(1, "undefined WQE type %d\n", tx_type);
+ rv = -EINVAL;
+ }
+ wqe->wr_status = SIW_WR_IDLE;
+ }
+done:
+ return rv;
+}
+
+static void siw_sq_resume(struct siw_qp *qp)
+{
+ if (down_read_trylock(&qp->state_lock)) {
+ if (likely(qp->attrs.state == SIW_QP_STATE_RTS &&
+ !qp->tx_ctx.tx_suspend)) {
+ int rv = siw_qp_sq_process(qp);
+
+ up_read(&qp->state_lock);
+
+ if (unlikely(rv < 0)) {
+ siw_dbg_qp(qp, "SQ task failed: err %d\n", rv);
+
+ if (!qp->tx_ctx.tx_suspend)
+ siw_qp_cm_drop(qp, 0);
+ }
+ } else {
+ up_read(&qp->state_lock);
+ }
+ } else {
+ siw_dbg_qp(qp, "Resume SQ while QP locked\n");
+ }
+ siw_qp_put(qp);
+}
+
+struct tx_task_t {
+ struct llist_head active;
+ wait_queue_head_t waiting;
+};
+
+static DEFINE_PER_CPU(struct tx_task_t, siw_tx_task_g);
+
+void siw_stop_tx_thread(int nr_cpu)
+{
+ kthread_stop(siw_tx_thread[nr_cpu]);
+ wake_up(&per_cpu(siw_tx_task_g, nr_cpu).waiting);
+}
+
+int siw_run_sq(void *data)
+{
+ const int nr_cpu = (unsigned int)(long)data;
+ struct llist_node *active;
+ struct siw_qp *qp;
+ struct tx_task_t *tx_task = &per_cpu(siw_tx_task_g, nr_cpu);
+
+ init_llist_head(&tx_task->active);
+ init_waitqueue_head(&tx_task->waiting);
+
+ while (1) {
+ struct llist_node *fifo_list = NULL;
+
+ wait_event_interruptible(tx_task->waiting,
+ !llist_empty(&tx_task->active) ||
+ kthread_should_stop());
+
+ if (kthread_should_stop())
+ break;
+
+ active = llist_del_all(&tx_task->active);
+ /*
+ * llist_del_all returns a list with newest entry first.
+ * Re-order list for fairness among QP's.
+ */
+ while (active) {
+ struct llist_node *tmp = active;
+
+ active = llist_next(active);
+ tmp->next = fifo_list;
+ fifo_list = tmp;
+ }
+ while (fifo_list) {
+ qp = container_of(fifo_list, struct siw_qp, tx_list);
+ fifo_list = llist_next(fifo_list);
+ qp->tx_list.next = NULL;
+
+ siw_sq_resume(qp);
+ }
+ }
+ active = llist_del_all(&tx_task->active);
+ if (active) {
+ llist_for_each_entry(qp, active, tx_list) {
+ qp->tx_list.next = NULL;
+ siw_sq_resume(qp);
+ }
+ }
+ return 0;
+}
+
+int siw_sq_start(struct siw_qp *qp)
+{
+ if (tx_wqe(qp)->wr_status == SIW_WR_IDLE)
+ return 0;
+
+ if (unlikely(!cpu_online(qp->tx_cpu))) {
+ siw_put_tx_cpu(qp->tx_cpu);
+ qp->tx_cpu = siw_get_tx_cpu(qp->sdev);
+ if (qp->tx_cpu < 0) {
+ pr_warn("siw: no tx cpu available\n");
+
+ return -EIO;
+ }
+ }
+ siw_qp_get(qp);
+
+ llist_add(&qp->tx_list, &per_cpu(siw_tx_task_g, qp->tx_cpu).active);
+
+ wake_up(&per_cpu(siw_tx_task_g, qp->tx_cpu).waiting);
+
+ return 0;
+}
diff --git a/drivers/infiniband/sw/siw/siw_verbs.c b/drivers/infiniband/sw/siw/siw_verbs.c
new file mode 100644
index 000000000000..32dc79d0e898
--- /dev/null
+++ b/drivers/infiniband/sw/siw/siw_verbs.c
@@ -0,0 +1,1760 @@
+// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause
+
+/* Authors: Bernard Metzler <bmt@zurich.ibm.com> */
+/* Copyright (c) 2008-2019, IBM Corporation */
+
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/vmalloc.h>
+#include <linux/xarray.h>
+
+#include <rdma/iw_cm.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_user_verbs.h>
+#include <rdma/uverbs_ioctl.h>
+
+#include "siw.h"
+#include "siw_verbs.h"
+#include "siw_mem.h"
+
+static int ib_qp_state_to_siw_qp_state[IB_QPS_ERR + 1] = {
+ [IB_QPS_RESET] = SIW_QP_STATE_IDLE,
+ [IB_QPS_INIT] = SIW_QP_STATE_IDLE,
+ [IB_QPS_RTR] = SIW_QP_STATE_RTR,
+ [IB_QPS_RTS] = SIW_QP_STATE_RTS,
+ [IB_QPS_SQD] = SIW_QP_STATE_CLOSING,
+ [IB_QPS_SQE] = SIW_QP_STATE_TERMINATE,
+ [IB_QPS_ERR] = SIW_QP_STATE_ERROR
+};
+
+static char ib_qp_state_to_string[IB_QPS_ERR + 1][sizeof("RESET")] = {
+ [IB_QPS_RESET] = "RESET", [IB_QPS_INIT] = "INIT", [IB_QPS_RTR] = "RTR",
+ [IB_QPS_RTS] = "RTS", [IB_QPS_SQD] = "SQD", [IB_QPS_SQE] = "SQE",
+ [IB_QPS_ERR] = "ERR"
+};
+
+static u32 siw_create_uobj(struct siw_ucontext *uctx, void *vaddr, u32 size)
+{
+ struct siw_uobj *uobj;
+ struct xa_limit limit = XA_LIMIT(0, SIW_UOBJ_MAX_KEY);
+ u32 key;
+
+ uobj = kzalloc(sizeof(*uobj), GFP_KERNEL);
+ if (!uobj)
+ return SIW_INVAL_UOBJ_KEY;
+
+ if (xa_alloc_cyclic(&uctx->xa, &key, uobj, limit, &uctx->uobj_nextkey,
+ GFP_KERNEL) < 0) {
+ kfree(uobj);
+ return SIW_INVAL_UOBJ_KEY;
+ }
+ uobj->size = PAGE_ALIGN(size);
+ uobj->addr = vaddr;
+
+ return key;
+}
+
+static struct siw_uobj *siw_get_uobj(struct siw_ucontext *uctx,
+ unsigned long off, u32 size)
+{
+ struct siw_uobj *uobj = xa_load(&uctx->xa, off);
+
+ if (uobj && uobj->size == size)
+ return uobj;
+
+ return NULL;
+}
+
+int siw_mmap(struct ib_ucontext *ctx, struct vm_area_struct *vma)
+{
+ struct siw_ucontext *uctx = to_siw_ctx(ctx);
+ struct siw_uobj *uobj;
+ unsigned long off = vma->vm_pgoff;
+ int size = vma->vm_end - vma->vm_start;
+ int rv = -EINVAL;
+
+ /*
+ * Must be page aligned
+ */
+ if (vma->vm_start & (PAGE_SIZE - 1)) {
+ pr_warn("siw: mmap not page aligned\n");
+ goto out;
+ }
+ uobj = siw_get_uobj(uctx, off, size);
+ if (!uobj) {
+ siw_dbg(&uctx->sdev->base_dev, "mmap lookup failed: %lu, %u\n",
+ off, size);
+ goto out;
+ }
+ rv = remap_vmalloc_range(vma, uobj->addr, 0);
+ if (rv)
+ pr_warn("remap_vmalloc_range failed: %lu, %u\n", off, size);
+out:
+ return rv;
+}
+
+int siw_alloc_ucontext(struct ib_ucontext *base_ctx, struct ib_udata *udata)
+{
+ struct siw_device *sdev = to_siw_dev(base_ctx->device);
+ struct siw_ucontext *ctx = to_siw_ctx(base_ctx);
+ struct siw_uresp_alloc_ctx uresp = {};
+ int rv;
+
+ if (atomic_inc_return(&sdev->num_ctx) > SIW_MAX_CONTEXT) {
+ rv = -ENOMEM;
+ goto err_out;
+ }
+ xa_init_flags(&ctx->xa, XA_FLAGS_ALLOC);
+ ctx->uobj_nextkey = 0;
+ ctx->sdev = sdev;
+
+ uresp.dev_id = sdev->vendor_part_id;
+
+ if (udata->outlen < sizeof(uresp)) {
+ rv = -EINVAL;
+ goto err_out;
+ }
+ rv = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
+ if (rv)
+ goto err_out;
+
+ siw_dbg(base_ctx->device, "success. now %d context(s)\n",
+ atomic_read(&sdev->num_ctx));
+
+ return 0;
+
+err_out:
+ atomic_dec(&sdev->num_ctx);
+ siw_dbg(base_ctx->device, "failure %d. now %d context(s)\n", rv,
+ atomic_read(&sdev->num_ctx));
+
+ return rv;
+}
+
+void siw_dealloc_ucontext(struct ib_ucontext *base_ctx)
+{
+ struct siw_ucontext *uctx = to_siw_ctx(base_ctx);
+ void *entry;
+ unsigned long index;
+
+ /*
+ * Make sure all user mmap objects are gone. Since QP, CQ
+ * and SRQ destroy routines destroy related objects, nothing
+ * should be found here.
+ */
+ xa_for_each(&uctx->xa, index, entry) {
+ kfree(xa_erase(&uctx->xa, index));
+ pr_warn("siw: dropping orphaned uobj at %lu\n", index);
+ }
+ xa_destroy(&uctx->xa);
+ atomic_dec(&uctx->sdev->num_ctx);
+}
+
+int siw_query_device(struct ib_device *base_dev, struct ib_device_attr *attr,
+ struct ib_udata *udata)
+{
+ struct siw_device *sdev = to_siw_dev(base_dev);
+
+ if (udata->inlen || udata->outlen)
+ return -EINVAL;
+
+ memset(attr, 0, sizeof(*attr));
+
+ /* Revisit atomic caps if RFC 7306 gets supported */
+ attr->atomic_cap = 0;
+ attr->device_cap_flags =
+ IB_DEVICE_MEM_MGT_EXTENSIONS | IB_DEVICE_ALLOW_USER_UNREG;
+ attr->max_cq = sdev->attrs.max_cq;
+ attr->max_cqe = sdev->attrs.max_cqe;
+ attr->max_fast_reg_page_list_len = SIW_MAX_SGE_PBL;
+ attr->max_fmr = sdev->attrs.max_fmr;
+ attr->max_mr = sdev->attrs.max_mr;
+ attr->max_mw = sdev->attrs.max_mw;
+ attr->max_mr_size = ~0ull;
+ attr->max_pd = sdev->attrs.max_pd;
+ attr->max_qp = sdev->attrs.max_qp;
+ attr->max_qp_init_rd_atom = sdev->attrs.max_ird;
+ attr->max_qp_rd_atom = sdev->attrs.max_ord;
+ attr->max_qp_wr = sdev->attrs.max_qp_wr;
+ attr->max_recv_sge = sdev->attrs.max_sge;
+ attr->max_res_rd_atom = sdev->attrs.max_qp * sdev->attrs.max_ird;
+ attr->max_send_sge = sdev->attrs.max_sge;
+ attr->max_sge_rd = sdev->attrs.max_sge_rd;
+ attr->max_srq = sdev->attrs.max_srq;
+ attr->max_srq_sge = sdev->attrs.max_srq_sge;
+ attr->max_srq_wr = sdev->attrs.max_srq_wr;
+ attr->page_size_cap = PAGE_SIZE;
+ attr->vendor_id = SIW_VENDOR_ID;
+ attr->vendor_part_id = sdev->vendor_part_id;
+
+ memcpy(&attr->sys_image_guid, sdev->netdev->dev_addr, 6);
+
+ return 0;
+}
+
+int siw_query_port(struct ib_device *base_dev, u8 port,
+ struct ib_port_attr *attr)
+{
+ struct siw_device *sdev = to_siw_dev(base_dev);
+
+ memset(attr, 0, sizeof(*attr));
+
+ attr->active_mtu = attr->max_mtu;
+ attr->active_speed = 2;
+ attr->active_width = 2;
+ attr->gid_tbl_len = 1;
+ attr->max_msg_sz = -1;
+ attr->max_mtu = ib_mtu_int_to_enum(sdev->netdev->mtu);
+ attr->phys_state = sdev->state == IB_PORT_ACTIVE ? 5 : 3;
+ attr->pkey_tbl_len = 1;
+ attr->port_cap_flags = IB_PORT_CM_SUP | IB_PORT_DEVICE_MGMT_SUP;
+ attr->state = sdev->state;
+ /*
+ * All zero
+ *
+ * attr->lid = 0;
+ * attr->bad_pkey_cntr = 0;
+ * attr->qkey_viol_cntr = 0;
+ * attr->sm_lid = 0;
+ * attr->lmc = 0;
+ * attr->max_vl_num = 0;
+ * attr->sm_sl = 0;
+ * attr->subnet_timeout = 0;
+ * attr->init_type_repy = 0;
+ */
+ return 0;
+}
+
+int siw_get_port_immutable(struct ib_device *base_dev, u8 port,
+ struct ib_port_immutable *port_immutable)
+{
+ struct ib_port_attr attr;
+ int rv = siw_query_port(base_dev, port, &attr);
+
+ if (rv)
+ return rv;
+
+ port_immutable->pkey_tbl_len = attr.pkey_tbl_len;
+ port_immutable->gid_tbl_len = attr.gid_tbl_len;
+ port_immutable->core_cap_flags = RDMA_CORE_PORT_IWARP;
+
+ return 0;
+}
+
+int siw_query_pkey(struct ib_device *base_dev, u8 port, u16 idx, u16 *pkey)
+{
+ /* Report the default pkey */
+ *pkey = 0xffff;
+ return 0;
+}
+
+int siw_query_gid(struct ib_device *base_dev, u8 port, int idx,
+ union ib_gid *gid)
+{
+ struct siw_device *sdev = to_siw_dev(base_dev);
+
+ /* subnet_prefix == interface_id == 0; */
+ memset(gid, 0, sizeof(*gid));
+ memcpy(&gid->raw[0], sdev->netdev->dev_addr, 6);
+
+ return 0;
+}
+
+int siw_alloc_pd(struct ib_pd *pd, struct ib_udata *udata)
+{
+ struct siw_device *sdev = to_siw_dev(pd->device);
+
+ if (atomic_inc_return(&sdev->num_pd) > SIW_MAX_PD) {
+ atomic_dec(&sdev->num_pd);
+ return -ENOMEM;
+ }
+ siw_dbg_pd(pd, "now %d PD's(s)\n", atomic_read(&sdev->num_pd));
+
+ return 0;
+}
+
+void siw_dealloc_pd(struct ib_pd *pd, struct ib_udata *udata)
+{
+ struct siw_device *sdev = to_siw_dev(pd->device);
+
+ siw_dbg_pd(pd, "free PD\n");
+ atomic_dec(&sdev->num_pd);
+}
+
+void siw_qp_get_ref(struct ib_qp *base_qp)
+{
+ siw_qp_get(to_siw_qp(base_qp));
+}
+
+void siw_qp_put_ref(struct ib_qp *base_qp)
+{
+ siw_qp_put(to_siw_qp(base_qp));
+}
+
+/*
+ * siw_create_qp()
+ *
+ * Create QP of requested size on given device.
+ *
+ * @pd: Protection Domain
+ * @attrs: Initial QP attributes.
+ * @udata: used to provide QP ID, SQ and RQ size back to user.
+ */
+
+struct ib_qp *siw_create_qp(struct ib_pd *pd,
+ struct ib_qp_init_attr *attrs,
+ struct ib_udata *udata)
+{
+ struct siw_qp *qp = NULL;
+ struct siw_base_qp *siw_base_qp = NULL;
+ struct ib_device *base_dev = pd->device;
+ struct siw_device *sdev = to_siw_dev(base_dev);
+ struct siw_ucontext *uctx =
+ rdma_udata_to_drv_context(udata, struct siw_ucontext,
+ base_ucontext);
+ struct siw_cq *scq = NULL, *rcq = NULL;
+ unsigned long flags;
+ int num_sqe, num_rqe, rv = 0;
+
+ siw_dbg(base_dev, "create new QP\n");
+
+ if (atomic_inc_return(&sdev->num_qp) > SIW_MAX_QP) {
+ siw_dbg(base_dev, "too many QP's\n");
+ rv = -ENOMEM;
+ goto err_out;
+ }
+ if (attrs->qp_type != IB_QPT_RC) {
+ siw_dbg(base_dev, "only RC QP's supported\n");
+ rv = -EINVAL;
+ goto err_out;
+ }
+ if ((attrs->cap.max_send_wr > SIW_MAX_QP_WR) ||
+ (attrs->cap.max_recv_wr > SIW_MAX_QP_WR) ||
+ (attrs->cap.max_send_sge > SIW_MAX_SGE) ||
+ (attrs->cap.max_recv_sge > SIW_MAX_SGE)) {
+ siw_dbg(base_dev, "QP size error\n");
+ rv = -EINVAL;
+ goto err_out;
+ }
+ if (attrs->cap.max_inline_data > SIW_MAX_INLINE) {
+ siw_dbg(base_dev, "max inline send: %d > %d\n",
+ attrs->cap.max_inline_data, (int)SIW_MAX_INLINE);
+ rv = -EINVAL;
+ goto err_out;
+ }
+ /*
+ * NOTE: we allow for zero element SQ and RQ WQE's SGL's
+ * but not for a QP unable to hold any WQE (SQ + RQ)
+ */
+ if (attrs->cap.max_send_wr + attrs->cap.max_recv_wr == 0) {
+ siw_dbg(base_dev, "QP must have send or receive queue\n");
+ rv = -EINVAL;
+ goto err_out;
+ }
+ scq = to_siw_cq(attrs->send_cq);
+ rcq = to_siw_cq(attrs->recv_cq);
+
+ if (!scq || (!rcq && !attrs->srq)) {
+ siw_dbg(base_dev, "send CQ or receive CQ invalid\n");
+ rv = -EINVAL;
+ goto err_out;
+ }
+ siw_base_qp = kzalloc(sizeof(*siw_base_qp), GFP_KERNEL);
+ if (!siw_base_qp) {
+ rv = -ENOMEM;
+ goto err_out;
+ }
+ qp = kzalloc(sizeof(*qp), GFP_KERNEL);
+ if (!qp) {
+ rv = -ENOMEM;
+ goto err_out;
+ }
+ siw_base_qp->qp = qp;
+ qp->ib_qp = &siw_base_qp->base_qp;
+
+ init_rwsem(&qp->state_lock);
+ spin_lock_init(&qp->sq_lock);
+ spin_lock_init(&qp->rq_lock);
+ spin_lock_init(&qp->orq_lock);
+
+ qp->kernel_verbs = !udata;
+ qp->xa_sq_index = SIW_INVAL_UOBJ_KEY;
+ qp->xa_rq_index = SIW_INVAL_UOBJ_KEY;
+
+ rv = siw_qp_add(sdev, qp);
+ if (rv)
+ goto err_out;
+
+ /* All queue indices are derived from modulo operations
+ * on a free running 'get' (consumer) and 'put' (producer)
+ * unsigned counter. Having queue sizes at power of two
+ * avoids handling counter wrap around.
+ */
+ num_sqe = roundup_pow_of_two(attrs->cap.max_send_wr);
+ num_rqe = roundup_pow_of_two(attrs->cap.max_recv_wr);
+
+ if (qp->kernel_verbs)
+ qp->sendq = vzalloc(num_sqe * sizeof(struct siw_sqe));
+ else
+ qp->sendq = vmalloc_user(num_sqe * sizeof(struct siw_sqe));
+
+ if (qp->sendq == NULL) {
+ siw_dbg(base_dev, "SQ size %d alloc failed\n", num_sqe);
+ rv = -ENOMEM;
+ goto err_out_xa;
+ }
+ if (attrs->sq_sig_type != IB_SIGNAL_REQ_WR) {
+ if (attrs->sq_sig_type == IB_SIGNAL_ALL_WR)
+ qp->attrs.flags |= SIW_SIGNAL_ALL_WR;
+ else {
+ rv = -EINVAL;
+ goto err_out_xa;
+ }
+ }
+ qp->pd = pd;
+ qp->scq = scq;
+ qp->rcq = rcq;
+
+ if (attrs->srq) {
+ /*
+ * SRQ support.
+ * Verbs 6.3.7: ignore RQ size, if SRQ present
+ * Verbs 6.3.5: do not check PD of SRQ against PD of QP
+ */
+ qp->srq = to_siw_srq(attrs->srq);
+ qp->attrs.rq_size = 0;
+ siw_dbg(base_dev, "QP [%u]: [SRQ 0x%p] attached\n",
+ qp->qp_num, qp->srq);
+ } else if (num_rqe) {
+ if (qp->kernel_verbs)
+ qp->recvq = vzalloc(num_rqe * sizeof(struct siw_rqe));
+ else
+ qp->recvq =
+ vmalloc_user(num_rqe * sizeof(struct siw_rqe));
+
+ if (qp->recvq == NULL) {
+ siw_dbg(base_dev, "RQ size %d alloc failed\n", num_rqe);
+ rv = -ENOMEM;
+ goto err_out_xa;
+ }
+ qp->attrs.rq_size = num_rqe;
+ }
+ qp->attrs.sq_size = num_sqe;
+ qp->attrs.sq_max_sges = attrs->cap.max_send_sge;
+ qp->attrs.rq_max_sges = attrs->cap.max_recv_sge;
+
+ /* Make those two tunables fixed for now. */
+ qp->tx_ctx.gso_seg_limit = 1;
+ qp->tx_ctx.zcopy_tx = zcopy_tx;
+
+ qp->attrs.state = SIW_QP_STATE_IDLE;
+
+ if (udata) {
+ struct siw_uresp_create_qp uresp = {};
+
+ uresp.num_sqe = num_sqe;
+ uresp.num_rqe = num_rqe;
+ uresp.qp_id = qp_id(qp);
+
+ if (qp->sendq) {
+ qp->xa_sq_index =
+ siw_create_uobj(uctx, qp->sendq,
+ num_sqe * sizeof(struct siw_sqe));
+ }
+ if (qp->recvq) {
+ qp->xa_rq_index =
+ siw_create_uobj(uctx, qp->recvq,
+ num_rqe * sizeof(struct siw_rqe));
+ }
+ if (qp->xa_sq_index == SIW_INVAL_UOBJ_KEY ||
+ qp->xa_rq_index == SIW_INVAL_UOBJ_KEY) {
+ rv = -ENOMEM;
+ goto err_out_xa;
+ }
+ uresp.sq_key = qp->xa_sq_index << PAGE_SHIFT;
+ uresp.rq_key = qp->xa_rq_index << PAGE_SHIFT;
+
+ if (udata->outlen < sizeof(uresp)) {
+ rv = -EINVAL;
+ goto err_out_xa;
+ }
+ rv = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
+ if (rv)
+ goto err_out_xa;
+ }
+ qp->tx_cpu = siw_get_tx_cpu(sdev);
+ if (qp->tx_cpu < 0) {
+ rv = -EINVAL;
+ goto err_out_xa;
+ }
+ INIT_LIST_HEAD(&qp->devq);
+ spin_lock_irqsave(&sdev->lock, flags);
+ list_add_tail(&qp->devq, &sdev->qp_list);
+ spin_unlock_irqrestore(&sdev->lock, flags);
+
+ return qp->ib_qp;
+
+err_out_xa:
+ xa_erase(&sdev->qp_xa, qp_id(qp));
+err_out:
+ kfree(siw_base_qp);
+
+ if (qp) {
+ if (qp->xa_sq_index != SIW_INVAL_UOBJ_KEY)
+ kfree(xa_erase(&uctx->xa, qp->xa_sq_index));
+ if (qp->xa_rq_index != SIW_INVAL_UOBJ_KEY)
+ kfree(xa_erase(&uctx->xa, qp->xa_rq_index));
+
+ vfree(qp->sendq);
+ vfree(qp->recvq);
+ kfree(qp);
+ }
+ atomic_dec(&sdev->num_qp);
+
+ return ERR_PTR(rv);
+}
+
+/*
+ * Minimum siw_query_qp() verb interface.
+ *
+ * @qp_attr_mask is not used but all available information is provided
+ */
+int siw_query_qp(struct ib_qp *base_qp, struct ib_qp_attr *qp_attr,
+ int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr)
+{
+ struct siw_qp *qp;
+ struct siw_device *sdev;
+
+ if (base_qp && qp_attr && qp_init_attr) {
+ qp = to_siw_qp(base_qp);
+ sdev = to_siw_dev(base_qp->device);
+ } else {
+ return -EINVAL;
+ }
+ qp_attr->cap.max_inline_data = SIW_MAX_INLINE;
+ qp_attr->cap.max_send_wr = qp->attrs.sq_size;
+ qp_attr->cap.max_send_sge = qp->attrs.sq_max_sges;
+ qp_attr->cap.max_recv_wr = qp->attrs.rq_size;
+ qp_attr->cap.max_recv_sge = qp->attrs.rq_max_sges;
+ qp_attr->path_mtu = ib_mtu_int_to_enum(sdev->netdev->mtu);
+ qp_attr->max_rd_atomic = qp->attrs.irq_size;
+ qp_attr->max_dest_rd_atomic = qp->attrs.orq_size;
+
+ qp_attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE |
+ IB_ACCESS_REMOTE_WRITE |
+ IB_ACCESS_REMOTE_READ;
+
+ qp_init_attr->qp_type = base_qp->qp_type;
+ qp_init_attr->send_cq = base_qp->send_cq;
+ qp_init_attr->recv_cq = base_qp->recv_cq;
+ qp_init_attr->srq = base_qp->srq;
+
+ qp_init_attr->cap = qp_attr->cap;
+
+ return 0;
+}
+
+int siw_verbs_modify_qp(struct ib_qp *base_qp, struct ib_qp_attr *attr,
+ int attr_mask, struct ib_udata *udata)
+{
+ struct siw_qp_attrs new_attrs;
+ enum siw_qp_attr_mask siw_attr_mask = 0;
+ struct siw_qp *qp = to_siw_qp(base_qp);
+ int rv = 0;
+
+ if (!attr_mask)
+ return 0;
+
+ memset(&new_attrs, 0, sizeof(new_attrs));
+
+ if (attr_mask & IB_QP_ACCESS_FLAGS) {
+ siw_attr_mask = SIW_QP_ATTR_ACCESS_FLAGS;
+
+ if (attr->qp_access_flags & IB_ACCESS_REMOTE_READ)
+ new_attrs.flags |= SIW_RDMA_READ_ENABLED;
+ if (attr->qp_access_flags & IB_ACCESS_REMOTE_WRITE)
+ new_attrs.flags |= SIW_RDMA_WRITE_ENABLED;
+ if (attr->qp_access_flags & IB_ACCESS_MW_BIND)
+ new_attrs.flags |= SIW_RDMA_BIND_ENABLED;
+ }
+ if (attr_mask & IB_QP_STATE) {
+ siw_dbg_qp(qp, "desired IB QP state: %s\n",
+ ib_qp_state_to_string[attr->qp_state]);
+
+ new_attrs.state = ib_qp_state_to_siw_qp_state[attr->qp_state];
+
+ if (new_attrs.state > SIW_QP_STATE_RTS)
+ qp->tx_ctx.tx_suspend = 1;
+
+ siw_attr_mask |= SIW_QP_ATTR_STATE;
+ }
+ if (!siw_attr_mask)
+ goto out;
+
+ down_write(&qp->state_lock);
+
+ rv = siw_qp_modify(qp, &new_attrs, siw_attr_mask);
+
+ up_write(&qp->state_lock);
+out:
+ return rv;
+}
+
+int siw_destroy_qp(struct ib_qp *base_qp, struct ib_udata *udata)
+{
+ struct siw_qp *qp = to_siw_qp(base_qp);
+ struct siw_base_qp *siw_base_qp = to_siw_base_qp(base_qp);
+ struct siw_ucontext *uctx =
+ rdma_udata_to_drv_context(udata, struct siw_ucontext,
+ base_ucontext);
+ struct siw_qp_attrs qp_attrs;
+
+ siw_dbg_qp(qp, "state %d, cep 0x%p\n", qp->attrs.state, qp->cep);
+
+ /*
+ * Mark QP as in process of destruction to prevent from
+ * any async callbacks to RDMA core
+ */
+ qp->attrs.flags |= SIW_QP_IN_DESTROY;
+ qp->rx_stream.rx_suspend = 1;
+
+ if (uctx && qp->xa_sq_index != SIW_INVAL_UOBJ_KEY)
+ kfree(xa_erase(&uctx->xa, qp->xa_sq_index));
+ if (uctx && qp->xa_rq_index != SIW_INVAL_UOBJ_KEY)
+ kfree(xa_erase(&uctx->xa, qp->xa_rq_index));
+
+ down_write(&qp->state_lock);
+
+ qp_attrs.state = SIW_QP_STATE_ERROR;
+ siw_qp_modify(qp, &qp_attrs, SIW_QP_ATTR_STATE);
+
+ if (qp->cep) {
+ siw_cep_put(qp->cep);
+ qp->cep = NULL;
+ }
+ up_write(&qp->state_lock);
+
+ kfree(qp->tx_ctx.mpa_crc_hd);
+ kfree(qp->rx_stream.mpa_crc_hd);
+
+ qp->scq = qp->rcq = NULL;
+
+ siw_qp_put(qp);
+ kfree(siw_base_qp);
+
+ return 0;
+}
+
+/*
+ * siw_copy_inline_sgl()
+ *
+ * Prepare sgl of inlined data for sending. For userland callers
+ * function checks if given buffer addresses and len's are within
+ * process context bounds.
+ * Data from all provided sge's are copied together into the wqe,
+ * referenced by a single sge.
+ */
+static int siw_copy_inline_sgl(const struct ib_send_wr *core_wr,
+ struct siw_sqe *sqe)
+{
+ struct ib_sge *core_sge = core_wr->sg_list;
+ void *kbuf = &sqe->sge[1];
+ int num_sge = core_wr->num_sge, bytes = 0;
+
+ sqe->sge[0].laddr = (u64)kbuf;
+ sqe->sge[0].lkey = 0;
+
+ while (num_sge--) {
+ if (!core_sge->length) {
+ core_sge++;
+ continue;
+ }
+ bytes += core_sge->length;
+ if (bytes > SIW_MAX_INLINE) {
+ bytes = -EINVAL;
+ break;
+ }
+ memcpy(kbuf, (void *)(uintptr_t)core_sge->addr,
+ core_sge->length);
+
+ kbuf += core_sge->length;
+ core_sge++;
+ }
+ sqe->sge[0].length = bytes > 0 ? bytes : 0;
+ sqe->num_sge = bytes > 0 ? 1 : 0;
+
+ return bytes;
+}
+
+/*
+ * siw_post_send()
+ *
+ * Post a list of S-WR's to a SQ.
+ *
+ * @base_qp: Base QP contained in siw QP
+ * @wr: Null terminated list of user WR's
+ * @bad_wr: Points to failing WR in case of synchronous failure.
+ */
+int siw_post_send(struct ib_qp *base_qp, const struct ib_send_wr *wr,
+ const struct ib_send_wr **bad_wr)
+{
+ struct siw_qp *qp = to_siw_qp(base_qp);
+ struct siw_wqe *wqe = tx_wqe(qp);
+
+ unsigned long flags;
+ int rv = 0;
+
+ /*
+ * Try to acquire QP state lock. Must be non-blocking
+ * to accommodate kernel clients needs.
+ */
+ if (!down_read_trylock(&qp->state_lock)) {
+ *bad_wr = wr;
+ siw_dbg_qp(qp, "QP locked, state %d\n", qp->attrs.state);
+ return -ENOTCONN;
+ }
+ if (unlikely(qp->attrs.state != SIW_QP_STATE_RTS)) {
+ up_read(&qp->state_lock);
+ *bad_wr = wr;
+ siw_dbg_qp(qp, "QP out of state %d\n", qp->attrs.state);
+ return -ENOTCONN;
+ }
+ if (wr && !qp->kernel_verbs) {
+ siw_dbg_qp(qp, "wr must be empty for user mapped sq\n");
+ up_read(&qp->state_lock);
+ *bad_wr = wr;
+ return -EINVAL;
+ }
+ spin_lock_irqsave(&qp->sq_lock, flags);
+
+ while (wr) {
+ u32 idx = qp->sq_put % qp->attrs.sq_size;
+ struct siw_sqe *sqe = &qp->sendq[idx];
+
+ if (sqe->flags) {
+ siw_dbg_qp(qp, "sq full\n");
+ rv = -ENOMEM;
+ break;
+ }
+ if (wr->num_sge > qp->attrs.sq_max_sges) {
+ siw_dbg_qp(qp, "too many sge's: %d\n", wr->num_sge);
+ rv = -EINVAL;
+ break;
+ }
+ sqe->id = wr->wr_id;
+
+ if ((wr->send_flags & IB_SEND_SIGNALED) ||
+ (qp->attrs.flags & SIW_SIGNAL_ALL_WR))
+ sqe->flags |= SIW_WQE_SIGNALLED;
+
+ if (wr->send_flags & IB_SEND_FENCE)
+ sqe->flags |= SIW_WQE_READ_FENCE;
+
+ switch (wr->opcode) {
+ case IB_WR_SEND:
+ case IB_WR_SEND_WITH_INV:
+ if (wr->send_flags & IB_SEND_SOLICITED)
+ sqe->flags |= SIW_WQE_SOLICITED;
+
+ if (!(wr->send_flags & IB_SEND_INLINE)) {
+ siw_copy_sgl(wr->sg_list, sqe->sge,
+ wr->num_sge);
+ sqe->num_sge = wr->num_sge;
+ } else {
+ rv = siw_copy_inline_sgl(wr, sqe);
+ if (rv <= 0) {
+ rv = -EINVAL;
+ break;
+ }
+ sqe->flags |= SIW_WQE_INLINE;
+ sqe->num_sge = 1;
+ }
+ if (wr->opcode == IB_WR_SEND)
+ sqe->opcode = SIW_OP_SEND;
+ else {
+ sqe->opcode = SIW_OP_SEND_REMOTE_INV;
+ sqe->rkey = wr->ex.invalidate_rkey;
+ }
+ break;
+
+ case IB_WR_RDMA_READ_WITH_INV:
+ case IB_WR_RDMA_READ:
+ /*
+ * iWarp restricts RREAD sink to SGL containing
+ * 1 SGE only. we could relax to SGL with multiple
+ * elements referring the SAME ltag or even sending
+ * a private per-rreq tag referring to a checked
+ * local sgl with MULTIPLE ltag's.
+ */
+ if (unlikely(wr->num_sge != 1)) {
+ rv = -EINVAL;
+ break;
+ }
+ siw_copy_sgl(wr->sg_list, &sqe->sge[0], 1);
+ /*
+ * NOTE: zero length RREAD is allowed!
+ */
+ sqe->raddr = rdma_wr(wr)->remote_addr;
+ sqe->rkey = rdma_wr(wr)->rkey;
+ sqe->num_sge = 1;
+
+ if (wr->opcode == IB_WR_RDMA_READ)
+ sqe->opcode = SIW_OP_READ;
+ else
+ sqe->opcode = SIW_OP_READ_LOCAL_INV;
+ break;
+
+ case IB_WR_RDMA_WRITE:
+ if (!(wr->send_flags & IB_SEND_INLINE)) {
+ siw_copy_sgl(wr->sg_list, &sqe->sge[0],
+ wr->num_sge);
+ sqe->num_sge = wr->num_sge;
+ } else {
+ rv = siw_copy_inline_sgl(wr, sqe);
+ if (unlikely(rv < 0)) {
+ rv = -EINVAL;
+ break;
+ }
+ sqe->flags |= SIW_WQE_INLINE;
+ sqe->num_sge = 1;
+ }
+ sqe->raddr = rdma_wr(wr)->remote_addr;
+ sqe->rkey = rdma_wr(wr)->rkey;
+ sqe->opcode = SIW_OP_WRITE;
+ break;
+
+ case IB_WR_REG_MR:
+ sqe->base_mr = (uint64_t)reg_wr(wr)->mr;
+ sqe->rkey = reg_wr(wr)->key;
+ sqe->access = reg_wr(wr)->access & IWARP_ACCESS_MASK;
+ sqe->opcode = SIW_OP_REG_MR;
+ break;
+
+ case IB_WR_LOCAL_INV:
+ sqe->rkey = wr->ex.invalidate_rkey;
+ sqe->opcode = SIW_OP_INVAL_STAG;
+ break;
+
+ default:
+ siw_dbg_qp(qp, "ib wr type %d unsupported\n",
+ wr->opcode);
+ rv = -EINVAL;
+ break;
+ }
+ siw_dbg_qp(qp, "opcode %d, flags 0x%x, wr_id 0x%p\n",
+ sqe->opcode, sqe->flags, (void *)sqe->id);
+
+ if (unlikely(rv < 0))
+ break;
+
+ /* make SQE only valid after completely written */
+ smp_wmb();
+ sqe->flags |= SIW_WQE_VALID;
+
+ qp->sq_put++;
+ wr = wr->next;
+ }
+
+ /*
+ * Send directly if SQ processing is not in progress.
+ * Eventual immediate errors (rv < 0) do not affect the involved
+ * RI resources (Verbs, 8.3.1) and thus do not prevent from SQ
+ * processing, if new work is already pending. But rv must be passed
+ * to caller.
+ */
+ if (wqe->wr_status != SIW_WR_IDLE) {
+ spin_unlock_irqrestore(&qp->sq_lock, flags);
+ goto skip_direct_sending;
+ }
+ rv = siw_activate_tx(qp);
+ spin_unlock_irqrestore(&qp->sq_lock, flags);
+
+ if (rv <= 0)
+ goto skip_direct_sending;
+
+ if (qp->kernel_verbs) {
+ rv = siw_sq_start(qp);
+ } else {
+ qp->tx_ctx.in_syscall = 1;
+
+ if (siw_qp_sq_process(qp) != 0 && !(qp->tx_ctx.tx_suspend))
+ siw_qp_cm_drop(qp, 0);
+
+ qp->tx_ctx.in_syscall = 0;
+ }
+skip_direct_sending:
+
+ up_read(&qp->state_lock);
+
+ if (rv >= 0)
+ return 0;
+ /*
+ * Immediate error
+ */
+ siw_dbg_qp(qp, "error %d\n", rv);
+
+ *bad_wr = wr;
+ return rv;
+}
+
+/*
+ * siw_post_receive()
+ *
+ * Post a list of R-WR's to a RQ.
+ *
+ * @base_qp: Base QP contained in siw QP
+ * @wr: Null terminated list of user WR's
+ * @bad_wr: Points to failing WR in case of synchronous failure.
+ */
+int siw_post_receive(struct ib_qp *base_qp, const struct ib_recv_wr *wr,
+ const struct ib_recv_wr **bad_wr)
+{
+ struct siw_qp *qp = to_siw_qp(base_qp);
+ unsigned long flags;
+ int rv = 0;
+
+ if (qp->srq) {
+ *bad_wr = wr;
+ return -EOPNOTSUPP; /* what else from errno.h? */
+ }
+ /*
+ * Try to acquire QP state lock. Must be non-blocking
+ * to accommodate kernel clients needs.
+ */
+ if (!down_read_trylock(&qp->state_lock)) {
+ *bad_wr = wr;
+ return -ENOTCONN;
+ }
+ if (!qp->kernel_verbs) {
+ siw_dbg_qp(qp, "no kernel post_recv for user mapped sq\n");
+ up_read(&qp->state_lock);
+ *bad_wr = wr;
+ return -EINVAL;
+ }
+ if (qp->attrs.state > SIW_QP_STATE_RTS) {
+ up_read(&qp->state_lock);
+ *bad_wr = wr;
+ return -EINVAL;
+ }
+ /*
+ * Serialize potentially multiple producers.
+ * Not needed for single threaded consumer side.
+ */
+ spin_lock_irqsave(&qp->rq_lock, flags);
+
+ while (wr) {
+ u32 idx = qp->rq_put % qp->attrs.rq_size;
+ struct siw_rqe *rqe = &qp->recvq[idx];
+
+ if (rqe->flags) {
+ siw_dbg_qp(qp, "RQ full\n");
+ rv = -ENOMEM;
+ break;
+ }
+ if (wr->num_sge > qp->attrs.rq_max_sges) {
+ siw_dbg_qp(qp, "too many sge's: %d\n", wr->num_sge);
+ rv = -EINVAL;
+ break;
+ }
+ rqe->id = wr->wr_id;
+ rqe->num_sge = wr->num_sge;
+ siw_copy_sgl(wr->sg_list, rqe->sge, wr->num_sge);
+
+ /* make sure RQE is completely written before valid */
+ smp_wmb();
+
+ rqe->flags = SIW_WQE_VALID;
+
+ qp->rq_put++;
+ wr = wr->next;
+ }
+ spin_unlock_irqrestore(&qp->rq_lock, flags);
+
+ up_read(&qp->state_lock);
+
+ if (rv < 0) {
+ siw_dbg_qp(qp, "error %d\n", rv);
+ *bad_wr = wr;
+ }
+ return rv > 0 ? 0 : rv;
+}
+
+void siw_destroy_cq(struct ib_cq *base_cq, struct ib_udata *udata)
+{
+ struct siw_cq *cq = to_siw_cq(base_cq);
+ struct siw_device *sdev = to_siw_dev(base_cq->device);
+ struct siw_ucontext *ctx =
+ rdma_udata_to_drv_context(udata, struct siw_ucontext,
+ base_ucontext);
+
+ siw_dbg_cq(cq, "free CQ resources\n");
+
+ siw_cq_flush(cq);
+
+ if (ctx && cq->xa_cq_index != SIW_INVAL_UOBJ_KEY)
+ kfree(xa_erase(&ctx->xa, cq->xa_cq_index));
+
+ atomic_dec(&sdev->num_cq);
+
+ vfree(cq->queue);
+}
+
+/*
+ * siw_create_cq()
+ *
+ * Populate CQ of requested size
+ *
+ * @base_cq: CQ as allocated by RDMA midlayer
+ * @attr: Initial CQ attributes
+ * @udata: relates to user context
+ */
+
+int siw_create_cq(struct ib_cq *base_cq, const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata)
+{
+ struct siw_device *sdev = to_siw_dev(base_cq->device);
+ struct siw_cq *cq = to_siw_cq(base_cq);
+ int rv, size = attr->cqe;
+
+ if (atomic_inc_return(&sdev->num_cq) > SIW_MAX_CQ) {
+ siw_dbg(base_cq->device, "too many CQ's\n");
+ rv = -ENOMEM;
+ goto err_out;
+ }
+ if (size < 1 || size > sdev->attrs.max_cqe) {
+ siw_dbg(base_cq->device, "CQ size error: %d\n", size);
+ rv = -EINVAL;
+ goto err_out;
+ }
+ size = roundup_pow_of_two(size);
+ cq->base_cq.cqe = size;
+ cq->num_cqe = size;
+ cq->xa_cq_index = SIW_INVAL_UOBJ_KEY;
+
+ if (!udata) {
+ cq->kernel_verbs = 1;
+ cq->queue = vzalloc(size * sizeof(struct siw_cqe) +
+ sizeof(struct siw_cq_ctrl));
+ } else {
+ cq->queue = vmalloc_user(size * sizeof(struct siw_cqe) +
+ sizeof(struct siw_cq_ctrl));
+ }
+ if (cq->queue == NULL) {
+ rv = -ENOMEM;
+ goto err_out;
+ }
+ get_random_bytes(&cq->id, 4);
+ siw_dbg(base_cq->device, "new CQ [%u]\n", cq->id);
+
+ spin_lock_init(&cq->lock);
+
+ cq->notify = &((struct siw_cq_ctrl *)&cq->queue[size])->notify;
+
+ if (udata) {
+ struct siw_uresp_create_cq uresp = {};
+ struct siw_ucontext *ctx =
+ rdma_udata_to_drv_context(udata, struct siw_ucontext,
+ base_ucontext);
+
+ cq->xa_cq_index =
+ siw_create_uobj(ctx, cq->queue,
+ size * sizeof(struct siw_cqe) +
+ sizeof(struct siw_cq_ctrl));
+ if (cq->xa_cq_index == SIW_INVAL_UOBJ_KEY) {
+ rv = -ENOMEM;
+ goto err_out;
+ }
+ uresp.cq_key = cq->xa_cq_index << PAGE_SHIFT;
+ uresp.cq_id = cq->id;
+ uresp.num_cqe = size;
+
+ if (udata->outlen < sizeof(uresp)) {
+ rv = -EINVAL;
+ goto err_out;
+ }
+ rv = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
+ if (rv)
+ goto err_out;
+ }
+ return 0;
+
+err_out:
+ siw_dbg(base_cq->device, "CQ creation failed: %d", rv);
+
+ if (cq && cq->queue) {
+ struct siw_ucontext *ctx =
+ rdma_udata_to_drv_context(udata, struct siw_ucontext,
+ base_ucontext);
+ if (cq->xa_cq_index != SIW_INVAL_UOBJ_KEY)
+ kfree(xa_erase(&ctx->xa, cq->xa_cq_index));
+ vfree(cq->queue);
+ }
+ atomic_dec(&sdev->num_cq);
+
+ return rv;
+}
+
+/*
+ * siw_poll_cq()
+ *
+ * Reap CQ entries if available and copy work completion status into
+ * array of WC's provided by caller. Returns number of reaped CQE's.
+ *
+ * @base_cq: Base CQ contained in siw CQ.
+ * @num_cqe: Maximum number of CQE's to reap.
+ * @wc: Array of work completions to be filled by siw.
+ */
+int siw_poll_cq(struct ib_cq *base_cq, int num_cqe, struct ib_wc *wc)
+{
+ struct siw_cq *cq = to_siw_cq(base_cq);
+ int i;
+
+ for (i = 0; i < num_cqe; i++) {
+ if (!siw_reap_cqe(cq, wc))
+ break;
+ wc++;
+ }
+ return i;
+}
+
+/*
+ * siw_req_notify_cq()
+ *
+ * Request notification for new CQE's added to that CQ.
+ * Defined flags:
+ * o SIW_CQ_NOTIFY_SOLICITED lets siw trigger a notification
+ * event if a WQE with notification flag set enters the CQ
+ * o SIW_CQ_NOTIFY_NEXT_COMP lets siw trigger a notification
+ * event if a WQE enters the CQ.
+ * o IB_CQ_REPORT_MISSED_EVENTS: return value will provide the
+ * number of not reaped CQE's regardless of its notification
+ * type and current or new CQ notification settings.
+ *
+ * @base_cq: Base CQ contained in siw CQ.
+ * @flags: Requested notification flags.
+ */
+int siw_req_notify_cq(struct ib_cq *base_cq, enum ib_cq_notify_flags flags)
+{
+ struct siw_cq *cq = to_siw_cq(base_cq);
+
+ siw_dbg_cq(cq, "flags: 0x%02x\n", flags);
+
+ if ((flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED)
+ /* CQ event for next solicited completion */
+ smp_store_mb(*cq->notify, SIW_NOTIFY_SOLICITED);
+ else
+ /* CQ event for any signalled completion */
+ smp_store_mb(*cq->notify, SIW_NOTIFY_ALL);
+
+ if (flags & IB_CQ_REPORT_MISSED_EVENTS)
+ return cq->cq_put - cq->cq_get;
+
+ return 0;
+}
+
+/*
+ * siw_dereg_mr()
+ *
+ * Release Memory Region.
+ *
+ * @base_mr: Base MR contained in siw MR.
+ * @udata: points to user context, unused.
+ */
+int siw_dereg_mr(struct ib_mr *base_mr, struct ib_udata *udata)
+{
+ struct siw_mr *mr = to_siw_mr(base_mr);
+ struct siw_device *sdev = to_siw_dev(base_mr->device);
+
+ siw_dbg_mem(mr->mem, "deregister MR\n");
+
+ atomic_dec(&sdev->num_mr);
+
+ siw_mr_drop_mem(mr);
+ kfree_rcu(mr, rcu);
+
+ return 0;
+}
+
+/*
+ * siw_reg_user_mr()
+ *
+ * Register Memory Region.
+ *
+ * @pd: Protection Domain
+ * @start: starting address of MR (virtual address)
+ * @len: len of MR
+ * @rnic_va: not used by siw
+ * @rights: MR access rights
+ * @udata: user buffer to communicate STag and Key.
+ */
+struct ib_mr *siw_reg_user_mr(struct ib_pd *pd, u64 start, u64 len,
+ u64 rnic_va, int rights, struct ib_udata *udata)
+{
+ struct siw_mr *mr = NULL;
+ struct siw_umem *umem = NULL;
+ struct siw_ureq_reg_mr ureq;
+ struct siw_device *sdev = to_siw_dev(pd->device);
+
+ unsigned long mem_limit = rlimit(RLIMIT_MEMLOCK);
+ int rv;
+
+ siw_dbg_pd(pd, "start: 0x%016llx, va: 0x%016llx, len: %llu\n",
+ (unsigned long long)start, (unsigned long long)rnic_va,
+ (unsigned long long)len);
+
+ if (atomic_inc_return(&sdev->num_mr) > SIW_MAX_MR) {
+ siw_dbg_pd(pd, "too many mr's\n");
+ rv = -ENOMEM;
+ goto err_out;
+ }
+ if (!len) {
+ rv = -EINVAL;
+ goto err_out;
+ }
+ if (mem_limit != RLIM_INFINITY) {
+ unsigned long num_pages =
+ (PAGE_ALIGN(len + (start & ~PAGE_MASK))) >> PAGE_SHIFT;
+ mem_limit >>= PAGE_SHIFT;
+
+ if (num_pages > mem_limit - current->mm->locked_vm) {
+ siw_dbg_pd(pd, "pages req %lu, max %lu, lock %lu\n",
+ num_pages, mem_limit,
+ current->mm->locked_vm);
+ rv = -ENOMEM;
+ goto err_out;
+ }
+ }
+ umem = siw_umem_get(start, len, ib_access_writable(rights));
+ if (IS_ERR(umem)) {
+ rv = PTR_ERR(umem);
+ siw_dbg_pd(pd, "getting user memory failed: %d\n", rv);
+ umem = NULL;
+ goto err_out;
+ }
+ mr = kzalloc(sizeof(*mr), GFP_KERNEL);
+ if (!mr) {
+ rv = -ENOMEM;
+ goto err_out;
+ }
+ rv = siw_mr_add_mem(mr, pd, umem, start, len, rights);
+ if (rv)
+ goto err_out;
+
+ if (udata) {
+ struct siw_uresp_reg_mr uresp = {};
+ struct siw_mem *mem = mr->mem;
+
+ if (udata->inlen < sizeof(ureq)) {
+ rv = -EINVAL;
+ goto err_out;
+ }
+ rv = ib_copy_from_udata(&ureq, udata, sizeof(ureq));
+ if (rv)
+ goto err_out;
+
+ mr->base_mr.lkey |= ureq.stag_key;
+ mr->base_mr.rkey |= ureq.stag_key;
+ mem->stag |= ureq.stag_key;
+ uresp.stag = mem->stag;
+
+ if (udata->outlen < sizeof(uresp)) {
+ rv = -EINVAL;
+ goto err_out;
+ }
+ rv = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
+ if (rv)
+ goto err_out;
+ }
+ mr->mem->stag_valid = 1;
+
+ return &mr->base_mr;
+
+err_out:
+ atomic_dec(&sdev->num_mr);
+ if (mr) {
+ if (mr->mem)
+ siw_mr_drop_mem(mr);
+ kfree_rcu(mr, rcu);
+ } else {
+ if (umem)
+ siw_umem_release(umem, false);
+ }
+ return ERR_PTR(rv);
+}
+
+struct ib_mr *siw_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type,
+ u32 max_sge, struct ib_udata *udata)
+{
+ struct siw_device *sdev = to_siw_dev(pd->device);
+ struct siw_mr *mr = NULL;
+ struct siw_pbl *pbl = NULL;
+ int rv;
+
+ if (atomic_inc_return(&sdev->num_mr) > SIW_MAX_MR) {
+ siw_dbg_pd(pd, "too many mr's\n");
+ rv = -ENOMEM;
+ goto err_out;
+ }
+ if (mr_type != IB_MR_TYPE_MEM_REG) {
+ siw_dbg_pd(pd, "mr type %d unsupported\n", mr_type);
+ rv = -EOPNOTSUPP;
+ goto err_out;
+ }
+ if (max_sge > SIW_MAX_SGE_PBL) {
+ siw_dbg_pd(pd, "too many sge's: %d\n", max_sge);
+ rv = -ENOMEM;
+ goto err_out;
+ }
+ pbl = siw_pbl_alloc(max_sge);
+ if (IS_ERR(pbl)) {
+ rv = PTR_ERR(pbl);
+ siw_dbg_pd(pd, "pbl allocation failed: %d\n", rv);
+ pbl = NULL;
+ goto err_out;
+ }
+ mr = kzalloc(sizeof(*mr), GFP_KERNEL);
+ if (!mr) {
+ rv = -ENOMEM;
+ goto err_out;
+ }
+ rv = siw_mr_add_mem(mr, pd, pbl, 0, max_sge * PAGE_SIZE, 0);
+ if (rv)
+ goto err_out;
+
+ mr->mem->is_pbl = 1;
+
+ siw_dbg_pd(pd, "[MEM %u]: success\n", mr->mem->stag);
+
+ return &mr->base_mr;
+
+err_out:
+ atomic_dec(&sdev->num_mr);
+
+ if (!mr) {
+ kfree(pbl);
+ } else {
+ if (mr->mem)
+ siw_mr_drop_mem(mr);
+ kfree_rcu(mr, rcu);
+ }
+ siw_dbg_pd(pd, "failed: %d\n", rv);
+
+ return ERR_PTR(rv);
+}
+
+/* Just used to count number of pages being mapped */
+static int siw_set_pbl_page(struct ib_mr *base_mr, u64 buf_addr)
+{
+ return 0;
+}
+
+int siw_map_mr_sg(struct ib_mr *base_mr, struct scatterlist *sl, int num_sle,
+ unsigned int *sg_off)
+{
+ struct scatterlist *slp;
+ struct siw_mr *mr = to_siw_mr(base_mr);
+ struct siw_mem *mem = mr->mem;
+ struct siw_pbl *pbl = mem->pbl;
+ struct siw_pble *pble;
+ u64 pbl_size;
+ int i, rv;
+
+ if (!pbl) {
+ siw_dbg_mem(mem, "no PBL allocated\n");
+ return -EINVAL;
+ }
+ pble = pbl->pbe;
+
+ if (pbl->max_buf < num_sle) {
+ siw_dbg_mem(mem, "too many SGE's: %d > %d\n",
+ mem->pbl->max_buf, num_sle);
+ return -ENOMEM;
+ }
+ for_each_sg(sl, slp, num_sle, i) {
+ if (sg_dma_len(slp) == 0) {
+ siw_dbg_mem(mem, "empty SGE\n");
+ return -EINVAL;
+ }
+ if (i == 0) {
+ pble->addr = sg_dma_address(slp);
+ pble->size = sg_dma_len(slp);
+ pble->pbl_off = 0;
+ pbl_size = pble->size;
+ pbl->num_buf = 1;
+ } else {
+ /* Merge PBL entries if adjacent */
+ if (pble->addr + pble->size == sg_dma_address(slp)) {
+ pble->size += sg_dma_len(slp);
+ } else {
+ pble++;
+ pbl->num_buf++;
+ pble->addr = sg_dma_address(slp);
+ pble->size = sg_dma_len(slp);
+ pble->pbl_off = pbl_size;
+ }
+ pbl_size += sg_dma_len(slp);
+ }
+ siw_dbg_mem(mem,
+ "sge[%d], size %llu, addr 0x%016llx, total %llu\n",
+ i, pble->size, pble->addr, pbl_size);
+ }
+ rv = ib_sg_to_pages(base_mr, sl, num_sle, sg_off, siw_set_pbl_page);
+ if (rv > 0) {
+ mem->len = base_mr->length;
+ mem->va = base_mr->iova;
+ siw_dbg_mem(mem,
+ "%llu bytes, start 0x%016llx, %u SLE to %u entries\n",
+ mem->len, mem->va, num_sle, pbl->num_buf);
+ }
+ return rv;
+}
+
+/*
+ * siw_get_dma_mr()
+ *
+ * Create a (empty) DMA memory region, where no umem is attached.
+ */
+struct ib_mr *siw_get_dma_mr(struct ib_pd *pd, int rights)
+{
+ struct siw_device *sdev = to_siw_dev(pd->device);
+ struct siw_mr *mr = NULL;
+ int rv;
+
+ if (atomic_inc_return(&sdev->num_mr) > SIW_MAX_MR) {
+ siw_dbg_pd(pd, "too many mr's\n");
+ rv = -ENOMEM;
+ goto err_out;
+ }
+ mr = kzalloc(sizeof(*mr), GFP_KERNEL);
+ if (!mr) {
+ rv = -ENOMEM;
+ goto err_out;
+ }
+ rv = siw_mr_add_mem(mr, pd, NULL, 0, ULONG_MAX, rights);
+ if (rv)
+ goto err_out;
+
+ mr->mem->stag_valid = 1;
+
+ siw_dbg_pd(pd, "[MEM %u]: success\n", mr->mem->stag);
+
+ return &mr->base_mr;
+
+err_out:
+ if (rv)
+ kfree(mr);
+
+ atomic_dec(&sdev->num_mr);
+
+ return ERR_PTR(rv);
+}
+
+/*
+ * siw_create_srq()
+ *
+ * Create Shared Receive Queue of attributes @init_attrs
+ * within protection domain given by @pd.
+ *
+ * @base_srq: Base SRQ contained in siw SRQ.
+ * @init_attrs: SRQ init attributes.
+ * @udata: points to user context
+ */
+int siw_create_srq(struct ib_srq *base_srq,
+ struct ib_srq_init_attr *init_attrs, struct ib_udata *udata)
+{
+ struct siw_srq *srq = to_siw_srq(base_srq);
+ struct ib_srq_attr *attrs = &init_attrs->attr;
+ struct siw_device *sdev = to_siw_dev(base_srq->device);
+ struct siw_ucontext *ctx =
+ rdma_udata_to_drv_context(udata, struct siw_ucontext,
+ base_ucontext);
+ int rv;
+
+ if (atomic_inc_return(&sdev->num_srq) > SIW_MAX_SRQ) {
+ siw_dbg_pd(base_srq->pd, "too many SRQ's\n");
+ rv = -ENOMEM;
+ goto err_out;
+ }
+ if (attrs->max_wr == 0 || attrs->max_wr > SIW_MAX_SRQ_WR ||
+ attrs->max_sge > SIW_MAX_SGE || attrs->srq_limit > attrs->max_wr) {
+ rv = -EINVAL;
+ goto err_out;
+ }
+ srq->max_sge = attrs->max_sge;
+ srq->num_rqe = roundup_pow_of_two(attrs->max_wr);
+ srq->xa_srq_index = SIW_INVAL_UOBJ_KEY;
+ srq->limit = attrs->srq_limit;
+ if (srq->limit)
+ srq->armed = 1;
+
+ srq->kernel_verbs = !udata;
+
+ if (udata)
+ srq->recvq =
+ vmalloc_user(srq->num_rqe * sizeof(struct siw_rqe));
+ else
+ srq->recvq = vzalloc(srq->num_rqe * sizeof(struct siw_rqe));
+
+ if (srq->recvq == NULL) {
+ rv = -ENOMEM;
+ goto err_out;
+ }
+ if (udata) {
+ struct siw_uresp_create_srq uresp = {};
+
+ srq->xa_srq_index = siw_create_uobj(
+ ctx, srq->recvq, srq->num_rqe * sizeof(struct siw_rqe));
+
+ if (srq->xa_srq_index == SIW_INVAL_UOBJ_KEY) {
+ rv = -ENOMEM;
+ goto err_out;
+ }
+ uresp.srq_key = srq->xa_srq_index;
+ uresp.num_rqe = srq->num_rqe;
+
+ if (udata->outlen < sizeof(uresp)) {
+ rv = -EINVAL;
+ goto err_out;
+ }
+ rv = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
+ if (rv)
+ goto err_out;
+ }
+ spin_lock_init(&srq->lock);
+
+ siw_dbg_pd(base_srq->pd, "[SRQ 0x%p]: success\n", srq);
+
+ return 0;
+
+err_out:
+ if (srq->recvq) {
+ if (ctx && srq->xa_srq_index != SIW_INVAL_UOBJ_KEY)
+ kfree(xa_erase(&ctx->xa, srq->xa_srq_index));
+ vfree(srq->recvq);
+ }
+ atomic_dec(&sdev->num_srq);
+
+ return rv;
+}
+
+/*
+ * siw_modify_srq()
+ *
+ * Modify SRQ. The caller may resize SRQ and/or set/reset notification
+ * limit and (re)arm IB_EVENT_SRQ_LIMIT_REACHED notification.
+ *
+ * NOTE: it is unclear if RDMA core allows for changing the MAX_SGE
+ * parameter. siw_modify_srq() does not check the attrs->max_sge param.
+ */
+int siw_modify_srq(struct ib_srq *base_srq, struct ib_srq_attr *attrs,
+ enum ib_srq_attr_mask attr_mask, struct ib_udata *udata)
+{
+ struct siw_srq *srq = to_siw_srq(base_srq);
+ unsigned long flags;
+ int rv = 0;
+
+ spin_lock_irqsave(&srq->lock, flags);
+
+ if (attr_mask & IB_SRQ_MAX_WR) {
+ /* resize request not yet supported */
+ rv = -EOPNOTSUPP;
+ goto out;
+ }
+ if (attr_mask & IB_SRQ_LIMIT) {
+ if (attrs->srq_limit) {
+ if (unlikely(attrs->srq_limit > srq->num_rqe)) {
+ rv = -EINVAL;
+ goto out;
+ }
+ srq->armed = 1;
+ } else {
+ srq->armed = 0;
+ }
+ srq->limit = attrs->srq_limit;
+ }
+out:
+ spin_unlock_irqrestore(&srq->lock, flags);
+
+ return rv;
+}
+
+/*
+ * siw_query_srq()
+ *
+ * Query SRQ attributes.
+ */
+int siw_query_srq(struct ib_srq *base_srq, struct ib_srq_attr *attrs)
+{
+ struct siw_srq *srq = to_siw_srq(base_srq);
+ unsigned long flags;
+
+ spin_lock_irqsave(&srq->lock, flags);
+
+ attrs->max_wr = srq->num_rqe;
+ attrs->max_sge = srq->max_sge;
+ attrs->srq_limit = srq->limit;
+
+ spin_unlock_irqrestore(&srq->lock, flags);
+
+ return 0;
+}
+
+/*
+ * siw_destroy_srq()
+ *
+ * Destroy SRQ.
+ * It is assumed that the SRQ is not referenced by any
+ * QP anymore - the code trusts the RDMA core environment to keep track
+ * of QP references.
+ */
+void siw_destroy_srq(struct ib_srq *base_srq, struct ib_udata *udata)
+{
+ struct siw_srq *srq = to_siw_srq(base_srq);
+ struct siw_device *sdev = to_siw_dev(base_srq->device);
+ struct siw_ucontext *ctx =
+ rdma_udata_to_drv_context(udata, struct siw_ucontext,
+ base_ucontext);
+
+ if (ctx && srq->xa_srq_index != SIW_INVAL_UOBJ_KEY)
+ kfree(xa_erase(&ctx->xa, srq->xa_srq_index));
+
+ vfree(srq->recvq);
+ atomic_dec(&sdev->num_srq);
+}
+
+/*
+ * siw_post_srq_recv()
+ *
+ * Post a list of receive queue elements to SRQ.
+ * NOTE: The function does not check or lock a certain SRQ state
+ * during the post operation. The code simply trusts the
+ * RDMA core environment.
+ *
+ * @base_srq: Base SRQ contained in siw SRQ
+ * @wr: List of R-WR's
+ * @bad_wr: Updated to failing WR if posting fails.
+ */
+int siw_post_srq_recv(struct ib_srq *base_srq, const struct ib_recv_wr *wr,
+ const struct ib_recv_wr **bad_wr)
+{
+ struct siw_srq *srq = to_siw_srq(base_srq);
+ unsigned long flags;
+ int rv = 0;
+
+ if (unlikely(!srq->kernel_verbs)) {
+ siw_dbg_pd(base_srq->pd,
+ "[SRQ 0x%p]: no kernel post_recv for mapped srq\n",
+ srq);
+ rv = -EINVAL;
+ goto out;
+ }
+ /*
+ * Serialize potentially multiple producers.
+ * Also needed to serialize potentially multiple
+ * consumers.
+ */
+ spin_lock_irqsave(&srq->lock, flags);
+
+ while (wr) {
+ u32 idx = srq->rq_put % srq->num_rqe;
+ struct siw_rqe *rqe = &srq->recvq[idx];
+
+ if (rqe->flags) {
+ siw_dbg_pd(base_srq->pd, "SRQ full\n");
+ rv = -ENOMEM;
+ break;
+ }
+ if (unlikely(wr->num_sge > srq->max_sge)) {
+ siw_dbg_pd(base_srq->pd,
+ "[SRQ 0x%p]: too many sge's: %d\n", srq,
+ wr->num_sge);
+ rv = -EINVAL;
+ break;
+ }
+ rqe->id = wr->wr_id;
+ rqe->num_sge = wr->num_sge;
+ siw_copy_sgl(wr->sg_list, rqe->sge, wr->num_sge);
+
+ /* Make sure S-RQE is completely written before valid */
+ smp_wmb();
+
+ rqe->flags = SIW_WQE_VALID;
+
+ srq->rq_put++;
+ wr = wr->next;
+ }
+ spin_unlock_irqrestore(&srq->lock, flags);
+out:
+ if (unlikely(rv < 0)) {
+ siw_dbg_pd(base_srq->pd, "[SRQ 0x%p]: error %d\n", srq, rv);
+ *bad_wr = wr;
+ }
+ return rv;
+}
+
+void siw_qp_event(struct siw_qp *qp, enum ib_event_type etype)
+{
+ struct ib_event event;
+ struct ib_qp *base_qp = qp->ib_qp;
+
+ /*
+ * Do not report asynchronous errors on QP which gets
+ * destroyed via verbs interface (siw_destroy_qp())
+ */
+ if (qp->attrs.flags & SIW_QP_IN_DESTROY)
+ return;
+
+ event.event = etype;
+ event.device = base_qp->device;
+ event.element.qp = base_qp;
+
+ if (base_qp->event_handler) {
+ siw_dbg_qp(qp, "reporting event %d\n", etype);
+ base_qp->event_handler(&event, base_qp->qp_context);
+ }
+}
+
+void siw_cq_event(struct siw_cq *cq, enum ib_event_type etype)
+{
+ struct ib_event event;
+ struct ib_cq *base_cq = &cq->base_cq;
+
+ event.event = etype;
+ event.device = base_cq->device;
+ event.element.cq = base_cq;
+
+ if (base_cq->event_handler) {
+ siw_dbg_cq(cq, "reporting CQ event %d\n", etype);
+ base_cq->event_handler(&event, base_cq->cq_context);
+ }
+}
+
+void siw_srq_event(struct siw_srq *srq, enum ib_event_type etype)
+{
+ struct ib_event event;
+ struct ib_srq *base_srq = &srq->base_srq;
+
+ event.event = etype;
+ event.device = base_srq->device;
+ event.element.srq = base_srq;
+
+ if (base_srq->event_handler) {
+ siw_dbg_pd(srq->base_srq.pd,
+ "reporting SRQ event %d\n", etype);
+ base_srq->event_handler(&event, base_srq->srq_context);
+ }
+}
+
+void siw_port_event(struct siw_device *sdev, u8 port, enum ib_event_type etype)
+{
+ struct ib_event event;
+
+ event.event = etype;
+ event.device = &sdev->base_dev;
+ event.element.port_num = port;
+
+ siw_dbg(&sdev->base_dev, "reporting port event %d\n", etype);
+
+ ib_dispatch_event(&event);
+}
diff --git a/drivers/infiniband/sw/siw/siw_verbs.h b/drivers/infiniband/sw/siw/siw_verbs.h
new file mode 100644
index 000000000000..1910869281cb
--- /dev/null
+++ b/drivers/infiniband/sw/siw/siw_verbs.h
@@ -0,0 +1,91 @@
+/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
+
+/* Authors: Bernard Metzler <bmt@zurich.ibm.com> */
+/* Copyright (c) 2008-2019, IBM Corporation */
+
+#ifndef _SIW_VERBS_H
+#define _SIW_VERBS_H
+
+#include <linux/errno.h>
+
+#include <rdma/iw_cm.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_user_verbs.h>
+
+#include "siw.h"
+#include "siw_cm.h"
+
+/*
+ * siw_copy_sgl()
+ *
+ * Copy SGL from RDMA core representation to local
+ * representation.
+ */
+static inline void siw_copy_sgl(struct ib_sge *sge, struct siw_sge *siw_sge,
+ int num_sge)
+{
+ while (num_sge--) {
+ siw_sge->laddr = sge->addr;
+ siw_sge->length = sge->length;
+ siw_sge->lkey = sge->lkey;
+
+ siw_sge++;
+ sge++;
+ }
+}
+
+int siw_alloc_ucontext(struct ib_ucontext *base_ctx, struct ib_udata *udata);
+void siw_dealloc_ucontext(struct ib_ucontext *base_ctx);
+int siw_query_port(struct ib_device *base_dev, u8 port,
+ struct ib_port_attr *attr);
+int siw_get_port_immutable(struct ib_device *base_dev, u8 port,
+ struct ib_port_immutable *port_immutable);
+int siw_query_device(struct ib_device *base_dev, struct ib_device_attr *attr,
+ struct ib_udata *udata);
+int siw_create_cq(struct ib_cq *base_cq, const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata);
+int siw_query_port(struct ib_device *base_dev, u8 port,
+ struct ib_port_attr *attr);
+int siw_query_pkey(struct ib_device *base_dev, u8 port, u16 idx, u16 *pkey);
+int siw_query_gid(struct ib_device *base_dev, u8 port, int idx,
+ union ib_gid *gid);
+int siw_alloc_pd(struct ib_pd *base_pd, struct ib_udata *udata);
+void siw_dealloc_pd(struct ib_pd *base_pd, struct ib_udata *udata);
+struct ib_qp *siw_create_qp(struct ib_pd *base_pd,
+ struct ib_qp_init_attr *attr,
+ struct ib_udata *udata);
+int siw_query_qp(struct ib_qp *base_qp, struct ib_qp_attr *qp_attr,
+ int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr);
+int siw_verbs_modify_qp(struct ib_qp *base_qp, struct ib_qp_attr *attr,
+ int attr_mask, struct ib_udata *udata);
+int siw_destroy_qp(struct ib_qp *base_qp, struct ib_udata *udata);
+int siw_post_send(struct ib_qp *base_qp, const struct ib_send_wr *wr,
+ const struct ib_send_wr **bad_wr);
+int siw_post_receive(struct ib_qp *base_qp, const struct ib_recv_wr *wr,
+ const struct ib_recv_wr **bad_wr);
+void siw_destroy_cq(struct ib_cq *base_cq, struct ib_udata *udata);
+int siw_poll_cq(struct ib_cq *base_cq, int num_entries, struct ib_wc *wc);
+int siw_req_notify_cq(struct ib_cq *base_cq, enum ib_cq_notify_flags flags);
+struct ib_mr *siw_reg_user_mr(struct ib_pd *base_pd, u64 start, u64 len,
+ u64 rnic_va, int rights, struct ib_udata *udata);
+struct ib_mr *siw_alloc_mr(struct ib_pd *base_pd, enum ib_mr_type mr_type,
+ u32 max_sge, struct ib_udata *udata);
+struct ib_mr *siw_get_dma_mr(struct ib_pd *base_pd, int rights);
+int siw_map_mr_sg(struct ib_mr *base_mr, struct scatterlist *sl, int num_sle,
+ unsigned int *sg_off);
+int siw_dereg_mr(struct ib_mr *base_mr, struct ib_udata *udata);
+int siw_create_srq(struct ib_srq *base_srq, struct ib_srq_init_attr *attr,
+ struct ib_udata *udata);
+int siw_modify_srq(struct ib_srq *base_srq, struct ib_srq_attr *attr,
+ enum ib_srq_attr_mask mask, struct ib_udata *udata);
+int siw_query_srq(struct ib_srq *base_srq, struct ib_srq_attr *attr);
+void siw_destroy_srq(struct ib_srq *base_srq, struct ib_udata *udata);
+int siw_post_srq_recv(struct ib_srq *base_srq, const struct ib_recv_wr *wr,
+ const struct ib_recv_wr **bad_wr);
+int siw_mmap(struct ib_ucontext *ctx, struct vm_area_struct *vma);
+void siw_qp_event(struct siw_qp *qp, enum ib_event_type type);
+void siw_cq_event(struct siw_cq *cq, enum ib_event_type type);
+void siw_srq_event(struct siw_srq *srq, enum ib_event_type type);
+void siw_port_event(struct siw_device *dev, u8 port, enum ib_event_type type);
+
+#endif
diff --git a/drivers/infiniband/ulp/ipoib/Kconfig b/drivers/infiniband/ulp/ipoib/Kconfig
index 4760ce465d89..7af68604af77 100644
--- a/drivers/infiniband/ulp/ipoib/Kconfig
+++ b/drivers/infiniband/ulp/ipoib/Kconfig
@@ -7,7 +7,7 @@ config INFINIBAND_IPOIB
transports IP packets over InfiniBand so you can use your IB
device as a fancy NIC.
- See Documentation/infiniband/ipoib.txt for more information
+ See Documentation/infiniband/ipoib.rst for more information
config INFINIBAND_IPOIB_CM
bool "IP-over-InfiniBand Connected Mode support"
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index aa9dcfc36cd3..c59e00a0881f 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -1153,7 +1153,6 @@ static int ipoib_cm_tx_init(struct ipoib_cm_tx *p, u32 qpn,
ret = -ENOMEM;
goto err_tx;
}
- memset(p->tx_ring, 0, ipoib_sendq_size * sizeof(*p->tx_ring));
p->qp = ipoib_cm_create_tx_qp(p->dev, p);
memalloc_noio_restore(noio_flag);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
index 83429925dfc6..63e4f9d15fd9 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
@@ -138,7 +138,6 @@ static void ipoib_get_strings(struct net_device __always_unused *dev,
p += ETH_GSTRING_LEN;
}
break;
- case ETH_SS_TEST:
default:
break;
}
@@ -149,7 +148,6 @@ static int ipoib_get_sset_count(struct net_device __always_unused *dev,
switch (sset) {
case ETH_SS_STATS:
return IPOIB_GLOBAL_STATS_LEN;
- case ETH_SS_TEST:
default:
break;
}
@@ -222,6 +220,7 @@ static const struct ethtool_ops ipoib_ethtool_ops = {
.get_strings = ipoib_get_strings,
.get_ethtool_stats = ipoib_get_ethtool_stats,
.get_sset_count = ipoib_get_sset_count,
+ .get_link = ethtool_op_get_link,
};
void ipoib_set_ethtool_ops(struct net_device *dev)
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 9b5e11d3fb85..ac0583ff280d 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -1893,12 +1893,6 @@ static void ipoib_child_init(struct net_device *ndev)
struct ipoib_dev_priv *priv = ipoib_priv(ndev);
struct ipoib_dev_priv *ppriv = ipoib_priv(priv->parent);
- dev_hold(priv->parent);
-
- down_write(&ppriv->vlan_rwsem);
- list_add_tail(&priv->list, &ppriv->child_intfs);
- up_write(&ppriv->vlan_rwsem);
-
priv->max_ib_mtu = ppriv->max_ib_mtu;
set_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags);
memcpy(priv->dev->dev_addr, ppriv->dev->dev_addr, INFINIBAND_ALEN);
@@ -1941,6 +1935,17 @@ static int ipoib_ndo_init(struct net_device *ndev)
if (rc) {
pr_warn("%s: failed to initialize device: %s port %d (ret = %d)\n",
priv->ca->name, priv->dev->name, priv->port, rc);
+ return rc;
+ }
+
+ if (priv->parent) {
+ struct ipoib_dev_priv *ppriv = ipoib_priv(priv->parent);
+
+ dev_hold(priv->parent);
+
+ down_write(&ppriv->vlan_rwsem);
+ list_add_tail(&priv->list, &ppriv->child_intfs);
+ up_write(&ppriv->vlan_rwsem);
}
return 0;
@@ -1958,6 +1963,14 @@ static void ipoib_ndo_uninit(struct net_device *dev)
*/
WARN_ON(!list_empty(&priv->child_intfs));
+ if (priv->parent) {
+ struct ipoib_dev_priv *ppriv = ipoib_priv(priv->parent);
+
+ down_write(&ppriv->vlan_rwsem);
+ list_del(&priv->list);
+ up_write(&ppriv->vlan_rwsem);
+ }
+
ipoib_neigh_hash_uninit(dev);
ipoib_ib_dev_cleanup(dev);
@@ -1969,15 +1982,8 @@ static void ipoib_ndo_uninit(struct net_device *dev)
priv->wq = NULL;
}
- if (priv->parent) {
- struct ipoib_dev_priv *ppriv = ipoib_priv(priv->parent);
-
- down_write(&ppriv->vlan_rwsem);
- list_del(&priv->list);
- up_write(&ppriv->vlan_rwsem);
-
+ if (priv->parent)
dev_put(priv->parent);
- }
}
static int ipoib_set_vf_link_state(struct net_device *dev, int vf, int link_state)
@@ -1998,6 +2004,7 @@ static int ipoib_get_vf_config(struct net_device *dev, int vf,
return err;
ivf->vf = vf;
+ memcpy(ivf->mac, dev->dev_addr, dev->addr_len);
return 0;
}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
index ba09068f6200..b69304d28f06 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
@@ -260,11 +260,8 @@ void ipoib_transport_dev_cleanup(struct net_device *dev)
priv->qp = NULL;
}
- if (ib_destroy_cq(priv->send_cq))
- ipoib_warn(priv, "ib_cq_destroy (send) failed\n");
-
- if (ib_destroy_cq(priv->recv_cq))
- ipoib_warn(priv, "ib_cq_destroy (recv) failed\n");
+ ib_destroy_cq(priv->send_cq);
+ ib_destroy_cq(priv->recv_cq);
}
void ipoib_event(struct ib_event_handler *handler,
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index 9c185a8dabd3..c7a3d75fb308 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -205,7 +205,8 @@ iser_initialize_task_headers(struct iscsi_task *task,
goto out;
}
- tx_desc->wr_idx = 0;
+ tx_desc->inv_wr.next = NULL;
+ tx_desc->reg_wr.wr.next = NULL;
tx_desc->mapped = true;
tx_desc->dma_addr = dma_addr;
tx_desc->tx_sg[0].addr = tx_desc->dma_addr;
@@ -406,13 +407,10 @@ static u8
iscsi_iser_check_protection(struct iscsi_task *task, sector_t *sector)
{
struct iscsi_iser_task *iser_task = task->dd_data;
+ enum iser_data_dir dir = iser_task->dir[ISER_DIR_IN] ?
+ ISER_DIR_IN : ISER_DIR_OUT;
- if (iser_task->dir[ISER_DIR_IN])
- return iser_check_task_pi_status(iser_task, ISER_DIR_IN,
- sector);
- else
- return iser_check_task_pi_status(iser_task, ISER_DIR_OUT,
- sector);
+ return iser_check_task_pi_status(iser_task, dir, sector);
}
/**
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h
index 36d525110fd2..39bf213444cb 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.h
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -225,14 +225,6 @@ enum iser_desc_type {
ISCSI_TX_DATAOUT
};
-/* Maximum number of work requests per task:
- * Data memory region local invalidate + fast registration
- * Protection memory region local invalidate + fast registration
- * Signature memory region local invalidate + fast registration
- * PDU send
- */
-#define ISER_MAX_WRS 7
-
/**
* struct iser_tx_desc - iSER TX descriptor
*
@@ -245,11 +237,9 @@ enum iser_desc_type {
* unsolicited data-out or control
* @num_sge: number sges used on this TX task
* @mapped: Is the task header mapped
- * @wr_idx: Current WR index
- * @wrs: Array of WRs per task
- * @data_reg: Data buffer registration details
- * @prot_reg: Protection buffer registration details
- * @sig_attrs: Signature attributes
+ * reg_wr: registration WR
+ * send_wr: send WR
+ * inv_wr: invalidate WR
*/
struct iser_tx_desc {
struct iser_ctrl iser_header;
@@ -260,15 +250,9 @@ struct iser_tx_desc {
int num_sge;
struct ib_cqe cqe;
bool mapped;
- u8 wr_idx;
- union iser_wr {
- struct ib_send_wr send;
- struct ib_reg_wr fast_reg;
- struct ib_sig_handover_wr sig;
- } wrs[ISER_MAX_WRS];
- struct iser_mem_reg data_reg;
- struct iser_mem_reg prot_reg;
- struct ib_sig_attrs sig_attrs;
+ struct ib_reg_wr reg_wr;
+ struct ib_send_wr send_wr;
+ struct ib_send_wr inv_wr;
};
#define ISER_RX_PAD_SIZE (256 - (ISER_RX_PAYLOAD_SIZE + \
@@ -388,6 +372,7 @@ struct iser_device {
*
* @mr: memory region
* @fmr_pool: pool of fmrs
+ * @sig_mr: signature memory region
* @page_vec: fast reg page list used by fmr pool
* @mr_valid: is mr valid indicator
*/
@@ -396,36 +381,22 @@ struct iser_reg_resources {
struct ib_mr *mr;
struct ib_fmr_pool *fmr_pool;
};
+ struct ib_mr *sig_mr;
struct iser_page_vec *page_vec;
u8 mr_valid:1;
};
/**
- * struct iser_pi_context - Protection information context
- *
- * @rsc: protection buffer registration resources
- * @sig_mr: signature enable memory region
- * @sig_mr_valid: is sig_mr valid indicator
- * @sig_protected: is region protected indicator
- */
-struct iser_pi_context {
- struct iser_reg_resources rsc;
- struct ib_mr *sig_mr;
- u8 sig_mr_valid:1;
- u8 sig_protected:1;
-};
-
-/**
* struct iser_fr_desc - Fast registration descriptor
*
* @list: entry in connection fastreg pool
* @rsc: data buffer registration resources
- * @pi_ctx: protection information context
+ * @sig_protected: is region protected indicator
*/
struct iser_fr_desc {
struct list_head list;
struct iser_reg_resources rsc;
- struct iser_pi_context *pi_ctx;
+ bool sig_protected;
struct list_head all_list;
};
@@ -674,21 +645,6 @@ void
iser_reg_desc_put_fmr(struct ib_conn *ib_conn,
struct iser_fr_desc *desc);
-static inline struct ib_send_wr *
-iser_tx_next_wr(struct iser_tx_desc *tx_desc)
-{
- struct ib_send_wr *cur_wr = &tx_desc->wrs[tx_desc->wr_idx].send;
- struct ib_send_wr *last_wr;
-
- if (tx_desc->wr_idx) {
- last_wr = &tx_desc->wrs[tx_desc->wr_idx - 1].send;
- last_wr->next = cur_wr;
- }
- tx_desc->wr_idx++;
-
- return cur_wr;
-}
-
static inline struct iser_conn *
to_iser_conn(struct ib_conn *ib_conn)
{
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
index 96af06cfe0af..5cbb4b3a0566 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -592,15 +592,14 @@ void iser_login_rsp(struct ib_cq *cq, struct ib_wc *wc)
static inline int
iser_inv_desc(struct iser_fr_desc *desc, u32 rkey)
{
- if (likely(rkey == desc->rsc.mr->rkey)) {
- desc->rsc.mr_valid = 0;
- } else if (likely(desc->pi_ctx && rkey == desc->pi_ctx->sig_mr->rkey)) {
- desc->pi_ctx->sig_mr_valid = 0;
- } else {
+ if (unlikely((!desc->sig_protected && rkey != desc->rsc.mr->rkey) ||
+ (desc->sig_protected && rkey != desc->rsc.sig_mr->rkey))) {
iser_err("Bogus remote invalidation for rkey %#x\n", rkey);
return -EINVAL;
}
+ desc->rsc.mr_valid = 0;
+
return 0;
}
@@ -750,6 +749,9 @@ void iser_task_rdma_init(struct iscsi_iser_task *iser_task)
iser_task->prot[ISER_DIR_IN].data_len = 0;
iser_task->prot[ISER_DIR_OUT].data_len = 0;
+ iser_task->prot[ISER_DIR_IN].dma_nents = 0;
+ iser_task->prot[ISER_DIR_OUT].dma_nents = 0;
+
memset(&iser_task->rdma_reg[ISER_DIR_IN], 0,
sizeof(struct iser_mem_reg));
memset(&iser_task->rdma_reg[ISER_DIR_OUT], 0,
diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c
index 2ba70729d7b0..2cc89a9b9e9b 100644
--- a/drivers/infiniband/ulp/iser/iser_memory.c
+++ b/drivers/infiniband/ulp/iser/iser_memory.c
@@ -302,8 +302,7 @@ void iser_unreg_mem_fastreg(struct iscsi_iser_task *iser_task,
}
static void
-iser_set_dif_domain(struct scsi_cmnd *sc, struct ib_sig_attrs *sig_attrs,
- struct ib_sig_domain *domain)
+iser_set_dif_domain(struct scsi_cmnd *sc, struct ib_sig_domain *domain)
{
domain->sig_type = IB_SIG_TYPE_T10_DIF;
domain->sig.dif.pi_interval = scsi_prot_interval(sc);
@@ -326,21 +325,21 @@ iser_set_sig_attrs(struct scsi_cmnd *sc, struct ib_sig_attrs *sig_attrs)
case SCSI_PROT_WRITE_INSERT:
case SCSI_PROT_READ_STRIP:
sig_attrs->mem.sig_type = IB_SIG_TYPE_NONE;
- iser_set_dif_domain(sc, sig_attrs, &sig_attrs->wire);
+ iser_set_dif_domain(sc, &sig_attrs->wire);
sig_attrs->wire.sig.dif.bg_type = IB_T10DIF_CRC;
break;
case SCSI_PROT_READ_INSERT:
case SCSI_PROT_WRITE_STRIP:
sig_attrs->wire.sig_type = IB_SIG_TYPE_NONE;
- iser_set_dif_domain(sc, sig_attrs, &sig_attrs->mem);
+ iser_set_dif_domain(sc, &sig_attrs->mem);
sig_attrs->mem.sig.dif.bg_type = sc->prot_flags & SCSI_PROT_IP_CHECKSUM ?
IB_T10DIF_CSUM : IB_T10DIF_CRC;
break;
case SCSI_PROT_READ_PASS:
case SCSI_PROT_WRITE_PASS:
- iser_set_dif_domain(sc, sig_attrs, &sig_attrs->wire);
+ iser_set_dif_domain(sc, &sig_attrs->wire);
sig_attrs->wire.sig.dif.bg_type = IB_T10DIF_CRC;
- iser_set_dif_domain(sc, sig_attrs, &sig_attrs->mem);
+ iser_set_dif_domain(sc, &sig_attrs->mem);
sig_attrs->mem.sig.dif.bg_type = sc->prot_flags & SCSI_PROT_IP_CHECKSUM ?
IB_T10DIF_CSUM : IB_T10DIF_CRC;
break;
@@ -366,27 +365,29 @@ iser_set_prot_checks(struct scsi_cmnd *sc, u8 *mask)
static inline void
iser_inv_rkey(struct ib_send_wr *inv_wr,
struct ib_mr *mr,
- struct ib_cqe *cqe)
+ struct ib_cqe *cqe,
+ struct ib_send_wr *next_wr)
{
inv_wr->opcode = IB_WR_LOCAL_INV;
inv_wr->wr_cqe = cqe;
inv_wr->ex.invalidate_rkey = mr->rkey;
inv_wr->send_flags = 0;
inv_wr->num_sge = 0;
+ inv_wr->next = next_wr;
}
static int
iser_reg_sig_mr(struct iscsi_iser_task *iser_task,
- struct iser_pi_context *pi_ctx,
- struct iser_mem_reg *data_reg,
- struct iser_mem_reg *prot_reg,
+ struct iser_data_buf *mem,
+ struct iser_data_buf *sig_mem,
+ struct iser_reg_resources *rsc,
struct iser_mem_reg *sig_reg)
{
struct iser_tx_desc *tx_desc = &iser_task->desc;
- struct ib_sig_attrs *sig_attrs = &tx_desc->sig_attrs;
struct ib_cqe *cqe = &iser_task->iser_conn->ib_conn.reg_cqe;
- struct ib_sig_handover_wr *wr;
- struct ib_mr *mr = pi_ctx->sig_mr;
+ struct ib_mr *mr = rsc->sig_mr;
+ struct ib_sig_attrs *sig_attrs = mr->sig_attrs;
+ struct ib_reg_wr *wr = &tx_desc->reg_wr;
int ret;
memset(sig_attrs, 0, sizeof(*sig_attrs));
@@ -396,33 +397,36 @@ iser_reg_sig_mr(struct iscsi_iser_task *iser_task,
iser_set_prot_checks(iser_task->sc, &sig_attrs->check_mask);
- if (pi_ctx->sig_mr_valid)
- iser_inv_rkey(iser_tx_next_wr(tx_desc), mr, cqe);
+ if (rsc->mr_valid)
+ iser_inv_rkey(&tx_desc->inv_wr, mr, cqe, &wr->wr);
ib_update_fast_reg_key(mr, ib_inc_rkey(mr->rkey));
- wr = container_of(iser_tx_next_wr(tx_desc), struct ib_sig_handover_wr,
- wr);
- wr->wr.opcode = IB_WR_REG_SIG_MR;
+ ret = ib_map_mr_sg_pi(mr, mem->sg, mem->dma_nents, NULL,
+ sig_mem->sg, sig_mem->dma_nents, NULL, SZ_4K);
+ if (unlikely(ret)) {
+ iser_err("failed to map PI sg (%d)\n",
+ mem->dma_nents + sig_mem->dma_nents);
+ goto err;
+ }
+
+ memset(wr, 0, sizeof(*wr));
+ wr->wr.next = &tx_desc->send_wr;
+ wr->wr.opcode = IB_WR_REG_MR_INTEGRITY;
wr->wr.wr_cqe = cqe;
- wr->wr.sg_list = &data_reg->sge;
- wr->wr.num_sge = 1;
+ wr->wr.num_sge = 0;
wr->wr.send_flags = 0;
- wr->sig_attrs = sig_attrs;
- wr->sig_mr = mr;
- if (scsi_prot_sg_count(iser_task->sc))
- wr->prot = &prot_reg->sge;
- else
- wr->prot = NULL;
- wr->access_flags = IB_ACCESS_LOCAL_WRITE |
- IB_ACCESS_REMOTE_READ |
- IB_ACCESS_REMOTE_WRITE;
- pi_ctx->sig_mr_valid = 1;
+ wr->mr = mr;
+ wr->key = mr->rkey;
+ wr->access = IB_ACCESS_LOCAL_WRITE |
+ IB_ACCESS_REMOTE_READ |
+ IB_ACCESS_REMOTE_WRITE;
+ rsc->mr_valid = 1;
sig_reg->sge.lkey = mr->lkey;
sig_reg->rkey = mr->rkey;
- sig_reg->sge.addr = 0;
- sig_reg->sge.length = scsi_transfer_length(iser_task->sc);
+ sig_reg->sge.addr = mr->iova;
+ sig_reg->sge.length = mr->length;
iser_dbg("lkey=0x%x rkey=0x%x addr=0x%llx length=%u\n",
sig_reg->sge.lkey, sig_reg->rkey, sig_reg->sge.addr,
@@ -439,11 +443,11 @@ static int iser_fast_reg_mr(struct iscsi_iser_task *iser_task,
struct iser_tx_desc *tx_desc = &iser_task->desc;
struct ib_cqe *cqe = &iser_task->iser_conn->ib_conn.reg_cqe;
struct ib_mr *mr = rsc->mr;
- struct ib_reg_wr *wr;
+ struct ib_reg_wr *wr = &tx_desc->reg_wr;
int n;
if (rsc->mr_valid)
- iser_inv_rkey(iser_tx_next_wr(tx_desc), mr, cqe);
+ iser_inv_rkey(&tx_desc->inv_wr, mr, cqe, &wr->wr);
ib_update_fast_reg_key(mr, ib_inc_rkey(mr->rkey));
@@ -454,7 +458,7 @@ static int iser_fast_reg_mr(struct iscsi_iser_task *iser_task,
return n < 0 ? n : -EINVAL;
}
- wr = container_of(iser_tx_next_wr(tx_desc), struct ib_reg_wr, wr);
+ wr->wr.next = &tx_desc->send_wr;
wr->wr.opcode = IB_WR_REG_MR;
wr->wr.wr_cqe = cqe;
wr->wr.send_flags = 0;
@@ -479,21 +483,6 @@ static int iser_fast_reg_mr(struct iscsi_iser_task *iser_task,
}
static int
-iser_reg_prot_sg(struct iscsi_iser_task *task,
- struct iser_data_buf *mem,
- struct iser_fr_desc *desc,
- bool use_dma_key,
- struct iser_mem_reg *reg)
-{
- struct iser_device *device = task->iser_conn->ib_conn.device;
-
- if (use_dma_key)
- return iser_reg_dma(device, mem, reg);
-
- return device->reg_ops->reg_mem(task, mem, &desc->pi_ctx->rsc, reg);
-}
-
-static int
iser_reg_data_sg(struct iscsi_iser_task *task,
struct iser_data_buf *mem,
struct iser_fr_desc *desc,
@@ -516,7 +505,6 @@ int iser_reg_rdma_mem(struct iscsi_iser_task *task,
struct iser_device *device = ib_conn->device;
struct iser_data_buf *mem = &task->data[dir];
struct iser_mem_reg *reg = &task->rdma_reg[dir];
- struct iser_mem_reg *data_reg;
struct iser_fr_desc *desc = NULL;
bool use_dma_key;
int err;
@@ -529,32 +517,17 @@ int iser_reg_rdma_mem(struct iscsi_iser_task *task,
reg->mem_h = desc;
}
- if (scsi_get_prot_op(task->sc) == SCSI_PROT_NORMAL)
- data_reg = reg;
- else
- data_reg = &task->desc.data_reg;
-
- err = iser_reg_data_sg(task, mem, desc, use_dma_key, data_reg);
- if (unlikely(err))
- goto err_reg;
-
- if (scsi_get_prot_op(task->sc) != SCSI_PROT_NORMAL) {
- struct iser_mem_reg *prot_reg = &task->desc.prot_reg;
-
- if (scsi_prot_sg_count(task->sc)) {
- mem = &task->prot[dir];
- err = iser_reg_prot_sg(task, mem, desc,
- use_dma_key, prot_reg);
- if (unlikely(err))
- goto err_reg;
- }
-
- err = iser_reg_sig_mr(task, desc->pi_ctx, data_reg,
- prot_reg, reg);
+ if (scsi_get_prot_op(task->sc) == SCSI_PROT_NORMAL) {
+ err = iser_reg_data_sg(task, mem, desc, use_dma_key, reg);
+ if (unlikely(err))
+ goto err_reg;
+ } else {
+ err = iser_reg_sig_mr(task, mem, &task->prot[dir],
+ &desc->rsc, reg);
if (unlikely(err))
goto err_reg;
- desc->pi_ctx->sig_protected = 1;
+ desc->sig_protected = 1;
}
return 0;
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index 4ff3d98fa6a4..a6548de0e218 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -233,116 +233,63 @@ void iser_free_fmr_pool(struct ib_conn *ib_conn)
kfree(desc);
}
-static int
-iser_alloc_reg_res(struct iser_device *device,
- struct ib_pd *pd,
- struct iser_reg_resources *res,
- unsigned int size)
+static struct iser_fr_desc *
+iser_create_fastreg_desc(struct iser_device *device,
+ struct ib_pd *pd,
+ bool pi_enable,
+ unsigned int size)
{
+ struct iser_fr_desc *desc;
struct ib_device *ib_dev = device->ib_device;
enum ib_mr_type mr_type;
int ret;
+ desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+ if (!desc)
+ return ERR_PTR(-ENOMEM);
+
if (ib_dev->attrs.device_cap_flags & IB_DEVICE_SG_GAPS_REG)
mr_type = IB_MR_TYPE_SG_GAPS;
else
mr_type = IB_MR_TYPE_MEM_REG;
- res->mr = ib_alloc_mr(pd, mr_type, size);
- if (IS_ERR(res->mr)) {
- ret = PTR_ERR(res->mr);
+ desc->rsc.mr = ib_alloc_mr(pd, mr_type, size);
+ if (IS_ERR(desc->rsc.mr)) {
+ ret = PTR_ERR(desc->rsc.mr);
iser_err("Failed to allocate ib_fast_reg_mr err=%d\n", ret);
- return ret;
+ goto err_alloc_mr;
}
- res->mr_valid = 0;
-
- return 0;
-}
-static void
-iser_free_reg_res(struct iser_reg_resources *rsc)
-{
- ib_dereg_mr(rsc->mr);
-}
-
-static int
-iser_alloc_pi_ctx(struct iser_device *device,
- struct ib_pd *pd,
- struct iser_fr_desc *desc,
- unsigned int size)
-{
- struct iser_pi_context *pi_ctx = NULL;
- int ret;
-
- desc->pi_ctx = kzalloc(sizeof(*desc->pi_ctx), GFP_KERNEL);
- if (!desc->pi_ctx)
- return -ENOMEM;
-
- pi_ctx = desc->pi_ctx;
-
- ret = iser_alloc_reg_res(device, pd, &pi_ctx->rsc, size);
- if (ret) {
- iser_err("failed to allocate reg_resources\n");
- goto alloc_reg_res_err;
- }
-
- pi_ctx->sig_mr = ib_alloc_mr(pd, IB_MR_TYPE_SIGNATURE, 2);
- if (IS_ERR(pi_ctx->sig_mr)) {
- ret = PTR_ERR(pi_ctx->sig_mr);
- goto sig_mr_failure;
+ if (pi_enable) {
+ desc->rsc.sig_mr = ib_alloc_mr_integrity(pd, size, size);
+ if (IS_ERR(desc->rsc.sig_mr)) {
+ ret = PTR_ERR(desc->rsc.sig_mr);
+ iser_err("Failed to allocate sig_mr err=%d\n", ret);
+ goto err_alloc_mr_integrity;
+ }
}
- pi_ctx->sig_mr_valid = 0;
- desc->pi_ctx->sig_protected = 0;
-
- return 0;
+ desc->rsc.mr_valid = 0;
-sig_mr_failure:
- iser_free_reg_res(&pi_ctx->rsc);
-alloc_reg_res_err:
- kfree(desc->pi_ctx);
+ return desc;
- return ret;
-}
+err_alloc_mr_integrity:
+ ib_dereg_mr(desc->rsc.mr);
+err_alloc_mr:
+ kfree(desc);
-static void
-iser_free_pi_ctx(struct iser_pi_context *pi_ctx)
-{
- iser_free_reg_res(&pi_ctx->rsc);
- ib_dereg_mr(pi_ctx->sig_mr);
- kfree(pi_ctx);
+ return ERR_PTR(ret);
}
-static struct iser_fr_desc *
-iser_create_fastreg_desc(struct iser_device *device,
- struct ib_pd *pd,
- bool pi_enable,
- unsigned int size)
+static void iser_destroy_fastreg_desc(struct iser_fr_desc *desc)
{
- struct iser_fr_desc *desc;
- int ret;
-
- desc = kzalloc(sizeof(*desc), GFP_KERNEL);
- if (!desc)
- return ERR_PTR(-ENOMEM);
-
- ret = iser_alloc_reg_res(device, pd, &desc->rsc, size);
- if (ret)
- goto reg_res_alloc_failure;
+ struct iser_reg_resources *res = &desc->rsc;
- if (pi_enable) {
- ret = iser_alloc_pi_ctx(device, pd, desc, size);
- if (ret)
- goto pi_ctx_alloc_failure;
+ ib_dereg_mr(res->mr);
+ if (res->sig_mr) {
+ ib_dereg_mr(res->sig_mr);
+ res->sig_mr = NULL;
}
-
- return desc;
-
-pi_ctx_alloc_failure:
- iser_free_reg_res(&desc->rsc);
-reg_res_alloc_failure:
kfree(desc);
-
- return ERR_PTR(ret);
}
/**
@@ -399,10 +346,7 @@ void iser_free_fastreg_pool(struct ib_conn *ib_conn)
list_for_each_entry_safe(desc, tmp, &fr_pool->all_list, all_list) {
list_del(&desc->all_list);
- iser_free_reg_res(&desc->rsc);
- if (desc->pi_ctx)
- iser_free_pi_ctx(desc->pi_ctx);
- kfree(desc);
+ iser_destroy_fastreg_desc(desc);
++i;
}
@@ -455,7 +399,7 @@ static int iser_create_ib_conn_res(struct ib_conn *ib_conn)
init_attr.qp_type = IB_QPT_RC;
if (ib_conn->pi_support) {
init_attr.cap.max_send_wr = ISER_QP_SIG_MAX_REQ_DTOS + 1;
- init_attr.create_flags |= IB_QP_CREATE_SIGNATURE_EN;
+ init_attr.create_flags |= IB_QP_CREATE_INTEGRITY_EN;
iser_conn->max_cmds =
ISER_GET_MAX_XMIT_CMDS(ISER_QP_SIG_MAX_REQ_DTOS);
} else {
@@ -707,6 +651,7 @@ iser_calc_scsi_params(struct iser_conn *iser_conn,
struct ib_device_attr *attr = &device->ib_device->attrs;
unsigned short sg_tablesize, sup_sg_tablesize;
unsigned short reserved_mr_pages;
+ u32 max_num_sg;
/*
* FRs without SG_GAPS or FMRs can only map up to a (device) page per
@@ -720,12 +665,17 @@ iser_calc_scsi_params(struct iser_conn *iser_conn,
else
reserved_mr_pages = 1;
+ if (iser_conn->ib_conn.pi_support)
+ max_num_sg = attr->max_pi_fast_reg_page_list_len;
+ else
+ max_num_sg = attr->max_fast_reg_page_list_len;
+
sg_tablesize = DIV_ROUND_UP(max_sectors * 512, SIZE_4K);
if (attr->device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS)
sup_sg_tablesize =
min_t(
uint, ISCSI_ISER_MAX_SG_TABLESIZE,
- attr->max_fast_reg_page_list_len - reserved_mr_pages);
+ max_num_sg - reserved_mr_pages);
else
sup_sg_tablesize = ISCSI_ISER_MAX_SG_TABLESIZE;
@@ -762,7 +712,7 @@ static void iser_addr_handler(struct rdma_cm_id *cma_id)
/* connection T10-PI support */
if (iser_pi_enable) {
if (!(device->ib_device->attrs.device_cap_flags &
- IB_DEVICE_SIGNATURE_HANDOVER)) {
+ IB_DEVICE_INTEGRITY_HANDOVER)) {
iser_warn("T10-PI requested but not supported on %s, "
"continue without T10-PI\n",
dev_name(&ib_conn->device->ib_device->dev));
@@ -1087,7 +1037,8 @@ int iser_post_recvm(struct iser_conn *iser_conn, int count)
int iser_post_send(struct ib_conn *ib_conn, struct iser_tx_desc *tx_desc,
bool signal)
{
- struct ib_send_wr *wr = iser_tx_next_wr(tx_desc);
+ struct ib_send_wr *wr = &tx_desc->send_wr;
+ struct ib_send_wr *first_wr;
int ib_ret;
ib_dma_sync_single_for_device(ib_conn->device->ib_device,
@@ -1101,7 +1052,14 @@ int iser_post_send(struct ib_conn *ib_conn, struct iser_tx_desc *tx_desc,
wr->opcode = IB_WR_SEND;
wr->send_flags = signal ? IB_SEND_SIGNALED : 0;
- ib_ret = ib_post_send(ib_conn->qp, &tx_desc->wrs[0].send, NULL);
+ if (tx_desc->inv_wr.next)
+ first_wr = &tx_desc->inv_wr;
+ else if (tx_desc->reg_wr.wr.next)
+ first_wr = &tx_desc->reg_wr.wr;
+ else
+ first_wr = wr;
+
+ ib_ret = ib_post_send(ib_conn->qp, first_wr, NULL);
if (ib_ret)
iser_err("ib_post_send failed, ret:%d opcode:%d\n",
ib_ret, wr->opcode);
@@ -1118,9 +1076,9 @@ u8 iser_check_task_pi_status(struct iscsi_iser_task *iser_task,
struct ib_mr_status mr_status;
int ret;
- if (desc && desc->pi_ctx->sig_protected) {
- desc->pi_ctx->sig_protected = 0;
- ret = ib_check_mr_status(desc->pi_ctx->sig_mr,
+ if (desc && desc->sig_protected) {
+ desc->sig_protected = 0;
+ ret = ib_check_mr_status(desc->rsc.sig_mr,
IB_MR_CHECK_SIG_STATUS, &mr_status);
if (ret) {
pr_err("ib_check_mr_status failed, ret %d\n", ret);
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c
index 0205cf142b2f..a1a035270cab 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.c
+++ b/drivers/infiniband/ulp/isert/ib_isert.c
@@ -133,7 +133,7 @@ isert_create_qp(struct isert_conn *isert_conn,
attr.sq_sig_type = IB_SIGNAL_REQ_WR;
attr.qp_type = IB_QPT_RC;
if (device->pi_capable)
- attr.create_flags |= IB_QP_CREATE_SIGNATURE_EN;
+ attr.create_flags |= IB_QP_CREATE_INTEGRITY_EN;
ret = rdma_create_qp(cma_id, device->pd, &attr);
if (ret) {
@@ -309,7 +309,7 @@ isert_create_device_ib_res(struct isert_device *device)
/* Check signature cap */
device->pi_capable = ib_dev->attrs.device_cap_flags &
- IB_DEVICE_SIGNATURE_HANDOVER ? true : false;
+ IB_DEVICE_INTEGRITY_HANDOVER ? true : false;
return 0;
@@ -1669,7 +1669,7 @@ isert_rdma_write_done(struct ib_cq *cq, struct ib_wc *wc)
isert_dbg("Cmd %p\n", isert_cmd);
- ret = isert_check_pi_status(cmd, isert_cmd->rw.sig->sig_mr);
+ ret = isert_check_pi_status(cmd, isert_cmd->rw.reg->mr);
isert_rdma_rw_ctx_destroy(isert_cmd, isert_conn);
if (ret) {
@@ -1715,7 +1715,7 @@ isert_rdma_read_done(struct ib_cq *cq, struct ib_wc *wc)
iscsit_stop_dataout_timer(cmd);
if (isert_prot_cmd(isert_conn, se_cmd))
- ret = isert_check_pi_status(se_cmd, isert_cmd->rw.sig->sig_mr);
+ ret = isert_check_pi_status(se_cmd, isert_cmd->rw.reg->mr);
isert_rdma_rw_ctx_destroy(isert_cmd, isert_conn);
cmd->write_data_done = 0;
@@ -2059,8 +2059,7 @@ isert_put_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
}
static inline void
-isert_set_dif_domain(struct se_cmd *se_cmd, struct ib_sig_attrs *sig_attrs,
- struct ib_sig_domain *domain)
+isert_set_dif_domain(struct se_cmd *se_cmd, struct ib_sig_domain *domain)
{
domain->sig_type = IB_SIG_TYPE_T10_DIF;
domain->sig.dif.bg_type = IB_T10DIF_CRC;
@@ -2088,17 +2087,17 @@ isert_set_sig_attrs(struct se_cmd *se_cmd, struct ib_sig_attrs *sig_attrs)
case TARGET_PROT_DIN_INSERT:
case TARGET_PROT_DOUT_STRIP:
sig_attrs->mem.sig_type = IB_SIG_TYPE_NONE;
- isert_set_dif_domain(se_cmd, sig_attrs, &sig_attrs->wire);
+ isert_set_dif_domain(se_cmd, &sig_attrs->wire);
break;
case TARGET_PROT_DOUT_INSERT:
case TARGET_PROT_DIN_STRIP:
sig_attrs->wire.sig_type = IB_SIG_TYPE_NONE;
- isert_set_dif_domain(se_cmd, sig_attrs, &sig_attrs->mem);
+ isert_set_dif_domain(se_cmd, &sig_attrs->mem);
break;
case TARGET_PROT_DIN_PASS:
case TARGET_PROT_DOUT_PASS:
- isert_set_dif_domain(se_cmd, sig_attrs, &sig_attrs->wire);
- isert_set_dif_domain(se_cmd, sig_attrs, &sig_attrs->mem);
+ isert_set_dif_domain(se_cmd, &sig_attrs->wire);
+ isert_set_dif_domain(se_cmd, &sig_attrs->mem);
break;
default:
isert_err("Unsupported PI operation %d\n", se_cmd->prot_op);
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 4305da2c9037..c7bd96edce80 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -2340,7 +2340,6 @@ static void srp_handle_qp_err(struct ib_cq *cq, struct ib_wc *wc,
static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)
{
struct srp_target_port *target = host_to_target(shost);
- struct srp_rport *rport = target->rport;
struct srp_rdma_ch *ch;
struct srp_request *req;
struct srp_iu *iu;
@@ -2350,16 +2349,6 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)
u32 tag;
u16 idx;
int len, ret;
- const bool in_scsi_eh = !in_interrupt() && current == shost->ehandler;
-
- /*
- * The SCSI EH thread is the only context from which srp_queuecommand()
- * can get invoked for blocked devices (SDEV_BLOCK /
- * SDEV_CREATED_BLOCK). Avoid racing with srp_reconnect_rport() by
- * locking the rport mutex if invoked from inside the SCSI EH.
- */
- if (in_scsi_eh)
- mutex_lock(&rport->mutex);
scmnd->result = srp_chkready(target->rport);
if (unlikely(scmnd->result))
@@ -2428,13 +2417,7 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)
goto err_unmap;
}
- ret = 0;
-
-unlock_rport:
- if (in_scsi_eh)
- mutex_unlock(&rport->mutex);
-
- return ret;
+ return 0;
err_unmap:
srp_unmap_data(scmnd, ch, req);
@@ -2456,7 +2439,7 @@ err:
ret = SCSI_MLQUEUE_HOST_BUSY;
}
- goto unlock_rport;
+ return ret;
}
/*
@@ -3483,13 +3466,14 @@ static const match_table_t srp_opt_tokens = {
* @net: [in] Network namespace.
* @sa: [out] Address family, IP address and port number.
* @addr_port_str: [in] IP address and port number.
+ * @has_port: [out] Whether or not @addr_port_str includes a port number.
*
* Parse the following address formats:
* - IPv4: <ip_address>:<port>, e.g. 1.2.3.4:5.
* - IPv6: \[<ipv6_address>\]:<port>, e.g. [1::2:3%4]:5.
*/
static int srp_parse_in(struct net *net, struct sockaddr_storage *sa,
- const char *addr_port_str)
+ const char *addr_port_str, bool *has_port)
{
char *addr_end, *addr = kstrdup(addr_port_str, GFP_KERNEL);
char *port_str;
@@ -3498,9 +3482,12 @@ static int srp_parse_in(struct net *net, struct sockaddr_storage *sa,
if (!addr)
return -ENOMEM;
port_str = strrchr(addr, ':');
- if (!port_str)
- return -EINVAL;
- *port_str++ = '\0';
+ if (port_str && strchr(port_str, ']'))
+ port_str = NULL;
+ if (port_str)
+ *port_str++ = '\0';
+ if (has_port)
+ *has_port = port_str != NULL;
ret = inet_pton_with_scope(net, AF_INET, addr, port_str, sa);
if (ret && addr[0]) {
addr_end = addr + strlen(addr) - 1;
@@ -3522,6 +3509,7 @@ static int srp_parse_options(struct net *net, const char *buf,
char *p;
substring_t args[MAX_OPT_ARGS];
unsigned long long ull;
+ bool has_port;
int opt_mask = 0;
int token;
int ret = -EINVAL;
@@ -3620,7 +3608,8 @@ static int srp_parse_options(struct net *net, const char *buf,
ret = -ENOMEM;
goto out;
}
- ret = srp_parse_in(net, &target->rdma_cm.src.ss, p);
+ ret = srp_parse_in(net, &target->rdma_cm.src.ss, p,
+ NULL);
if (ret < 0) {
pr_warn("bad source parameter '%s'\n", p);
kfree(p);
@@ -3636,7 +3625,10 @@ static int srp_parse_options(struct net *net, const char *buf,
ret = -ENOMEM;
goto out;
}
- ret = srp_parse_in(net, &target->rdma_cm.dst.ss, p);
+ ret = srp_parse_in(net, &target->rdma_cm.dst.ss, p,
+ &has_port);
+ if (!has_port)
+ ret = -EINVAL;
if (ret < 0) {
pr_warn("bad dest parameter '%s'\n", p);
kfree(p);
diff --git a/drivers/input/apm-power.c b/drivers/input/apm-power.c
index 650177a3c858..70a9e1dfba33 100644
--- a/drivers/input/apm-power.c
+++ b/drivers/input/apm-power.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Input Power Event -> APM Bridge
*
* Copyright (c) 2007 Richard Purdie
- *
- * 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.
- *
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index d1e25aba8212..867c2cfd0038 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Event char devices, giving access to raw input device events.
*
* Copyright (c) 1999-2002 Vojtech Pavlik
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
index 73862a836062..61fa7e724172 100644
--- a/drivers/input/gameport/gameport.c
+++ b/drivers/input/gameport/gameport.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic gameport layer
*
@@ -5,11 +6,6 @@
* Copyright (c) 2005 Dmitry Torokhov
*/
-/*
- * 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.
- */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/input/input-compat.c b/drivers/input/input-compat.c
index fda8d6d2a268..2ccd3eedbd67 100644
--- a/drivers/input/input-compat.c
+++ b/drivers/input/input-compat.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* 32bit compatibility wrappers for the input subsystem.
*
* Very heavily based on evdev.c - Copyright (c) 1999-2002 Vojtech Pavlik
- *
- * 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.
*/
#include <linux/export.h>
diff --git a/drivers/input/input-compat.h b/drivers/input/input-compat.h
index 08cd755e73fd..3b7bb12b023b 100644
--- a/drivers/input/input-compat.h
+++ b/drivers/input/input-compat.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _INPUT_COMPAT_H
#define _INPUT_COMPAT_H
@@ -5,10 +6,6 @@
* 32bit compatibility wrappers for the input subsystem.
*
* Very heavily based on evdev.c - Copyright (c) 1999-2002 Vojtech Pavlik
- *
- * 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.
*/
#include <linux/compiler.h>
diff --git a/drivers/input/input-leds.c b/drivers/input/input-leds.c
index 99cc784e1264..0b11990ade46 100644
--- a/drivers/input/input-leds.c
+++ b/drivers/input/input-leds.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LED support for the input layer
*
* Copyright 2010-2015 Samuel Thibault <samuel.thibault@ens-lyon.org>
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c
index 6c7326c93721..a81e14148407 100644
--- a/drivers/input/input-mt.c
+++ b/drivers/input/input-mt.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Input Multitouch Library
*
* Copyright (c) 2008-2010 Henrik Rydberg
- *
- * 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.
*/
#include <linux/input/mt.h>
diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c
index 78df5a74822e..9bf1c9aeb4c4 100644
--- a/drivers/input/input-polldev.c
+++ b/drivers/input/input-polldev.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic implementation of a polled input device
* Copyright (c) 2007 Dmitry Torokhov
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 3304aaaffe87..7f3c5fcb9ed6 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* The input core
*
* Copyright (c) 1999-2002 Vojtech Pavlik
*/
-/*
- * 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.
- */
#define pr_fmt(fmt) KBUILD_BASENAME ": " fmt
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index ac21c050fdb0..a2b5fbba2d3b 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -808,6 +808,7 @@ static bool joydev_dev_is_blacklisted(struct input_dev *dev)
static bool joydev_dev_is_absolute_mouse(struct input_dev *dev)
{
DECLARE_BITMAP(jd_scratch, KEY_CNT);
+ bool ev_match = false;
BUILD_BUG_ON(ABS_CNT > KEY_CNT || EV_CNT > KEY_CNT);
@@ -826,17 +827,36 @@ static bool joydev_dev_is_absolute_mouse(struct input_dev *dev)
* considered to be an absolute mouse if the following is
* true:
*
- * 1) Event types are exactly EV_ABS, EV_KEY and EV_SYN.
+ * 1) Event types are exactly
+ * EV_ABS, EV_KEY and EV_SYN
+ * or
+ * EV_ABS, EV_KEY, EV_SYN and EV_MSC
+ * or
+ * EV_ABS, EV_KEY, EV_SYN, EV_MSC and EV_REL.
* 2) Absolute events are exactly ABS_X and ABS_Y.
* 3) Keys are exactly BTN_LEFT, BTN_RIGHT and BTN_MIDDLE.
* 4) Device is not on "Amiga" bus.
*/
bitmap_zero(jd_scratch, EV_CNT);
+ /* VMware VMMouse, HP ILO2 */
__set_bit(EV_ABS, jd_scratch);
__set_bit(EV_KEY, jd_scratch);
__set_bit(EV_SYN, jd_scratch);
- if (!bitmap_equal(jd_scratch, dev->evbit, EV_CNT))
+ if (bitmap_equal(jd_scratch, dev->evbit, EV_CNT))
+ ev_match = true;
+
+ /* HP ILO2, AMI BMC firmware */
+ __set_bit(EV_MSC, jd_scratch);
+ if (bitmap_equal(jd_scratch, dev->evbit, EV_CNT))
+ ev_match = true;
+
+ /* VMware Virtual USB Mouse, QEMU USB Tablet, ATEN BMC firmware */
+ __set_bit(EV_REL, jd_scratch);
+ if (bitmap_equal(jd_scratch, dev->evbit, EV_CNT))
+ ev_match = true;
+
+ if (!ev_match)
return false;
bitmap_zero(jd_scratch, ABS_CNT);
diff --git a/drivers/input/joystick/iforce/Kconfig b/drivers/input/joystick/iforce/Kconfig
index 62dcc5b71641..f002fb88f2e7 100644
--- a/drivers/input/joystick/iforce/Kconfig
+++ b/drivers/input/joystick/iforce/Kconfig
@@ -14,15 +14,15 @@ config JOYSTICK_IFORCE
module will be called iforce.
config JOYSTICK_IFORCE_USB
- bool "I-Force USB joysticks and wheels"
- depends on JOYSTICK_IFORCE && (JOYSTICK_IFORCE=m || USB=y) && USB
+ tristate "I-Force USB joysticks and wheels"
+ depends on JOYSTICK_IFORCE && USB
help
Say Y here if you have an I-Force joystick or steering wheel
connected to your USB port.
config JOYSTICK_IFORCE_232
- bool "I-Force Serial joysticks and wheels"
- depends on JOYSTICK_IFORCE && (JOYSTICK_IFORCE=m || SERIO=y) && SERIO
+ tristate "I-Force Serial joysticks and wheels"
+ depends on JOYSTICK_IFORCE && SERIO
help
Say Y here if you have an I-Force joystick or steering wheel
connected to your serial (COM) port.
diff --git a/drivers/input/joystick/iforce/Makefile b/drivers/input/joystick/iforce/Makefile
index fa79a49d7ca1..dbbe7c04010d 100644
--- a/drivers/input/joystick/iforce/Makefile
+++ b/drivers/input/joystick/iforce/Makefile
@@ -5,8 +5,7 @@
# By Johann Deneux <johann.deneux@gmail.com>
#
-obj-$(CONFIG_JOYSTICK_IFORCE) += iforce.o
-
+obj-$(CONFIG_JOYSTICK_IFORCE) += iforce.o
iforce-y := iforce-ff.o iforce-main.o iforce-packets.o
-iforce-$(CONFIG_JOYSTICK_IFORCE_232) += iforce-serio.o
-iforce-$(CONFIG_JOYSTICK_IFORCE_USB) += iforce-usb.o
+obj-$(CONFIG_JOYSTICK_IFORCE_232) += iforce-serio.o
+obj-$(CONFIG_JOYSTICK_IFORCE_USB) += iforce-usb.o
diff --git a/drivers/input/joystick/iforce/iforce-ff.c b/drivers/input/joystick/iforce/iforce-ff.c
index 2ed7da7d1f3e..4cadebd8b9c4 100644
--- a/drivers/input/joystick/iforce/iforce-ff.c
+++ b/drivers/input/joystick/iforce/iforce-ff.c
@@ -372,12 +372,12 @@ int iforce_upload_periodic(struct iforce *iforce, struct ff_effect *effect, stru
}
switch (effect->u.periodic.waveform) {
- case FF_SQUARE: wave_code = 0x20; break;
- case FF_TRIANGLE: wave_code = 0x21; break;
- case FF_SINE: wave_code = 0x22; break;
- case FF_SAW_UP: wave_code = 0x23; break;
- case FF_SAW_DOWN: wave_code = 0x24; break;
- default: wave_code = 0x20; break;
+ case FF_SQUARE: wave_code = 0x20; break;
+ case FF_TRIANGLE: wave_code = 0x21; break;
+ case FF_SINE: wave_code = 0x22; break;
+ case FF_SAW_UP: wave_code = 0x23; break;
+ case FF_SAW_DOWN: wave_code = 0x24; break;
+ default: wave_code = 0x20; break;
}
if (!old || need_core(old, effect)) {
@@ -476,9 +476,9 @@ int iforce_upload_condition(struct iforce *iforce, struct ff_effect *effect, str
int core_err = 0;
switch (effect->type) {
- case FF_SPRING: type = 0x40; break;
- case FF_DAMPER: type = 0x41; break;
- default: return -1;
+ case FF_SPRING: type = 0x40; break;
+ case FF_DAMPER: type = 0x41; break;
+ default: return -1;
}
if (!old || need_condition_modifier(iforce, old, effect)) {
diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c
index 55f5b7bb4cac..9a5f90da06ec 100644
--- a/drivers/input/joystick/iforce/iforce-main.c
+++ b/drivers/input/joystick/iforce/iforce-main.c
@@ -9,10 +9,11 @@
/*
*/
+#include <asm/unaligned.h>
#include "iforce.h"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <johann.deneux@gmail.com>");
-MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver");
+MODULE_DESCRIPTION("Core I-Force joysticks and wheels driver");
MODULE_LICENSE("GPL");
static signed short btn_joystick[] =
@@ -55,6 +56,7 @@ static struct iforce_device iforce_device[] = {
{ 0x05ef, 0x8888, "AVB Top Shot Force Feedback Racing Wheel", btn_wheel, abs_wheel, ff_iforce }, //?
{ 0x061c, 0xc0a4, "ACT LABS Force RS", btn_wheel, abs_wheel, ff_iforce }, //?
{ 0x061c, 0xc084, "ACT LABS Force RS", btn_wheel, abs_wheel, ff_iforce },
+ { 0x06a3, 0xff04, "Saitek R440 Force Wheel", btn_wheel, abs_wheel, ff_iforce }, //?
{ 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback", btn_wheel, abs_wheel, ff_iforce }, //?
{ 0x06f8, 0x0001, "Guillemot Jet Leader Force Feedback", btn_joystick, abs_joystick_rudder, ff_iforce },
{ 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel", btn_wheel, abs_wheel, ff_iforce }, //?
@@ -120,22 +122,21 @@ static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect,
* Upload the effect
*/
switch (effect->type) {
+ case FF_PERIODIC:
+ ret = iforce_upload_periodic(iforce, effect, old);
+ break;
- case FF_PERIODIC:
- ret = iforce_upload_periodic(iforce, effect, old);
- break;
-
- case FF_CONSTANT:
- ret = iforce_upload_constant(iforce, effect, old);
- break;
+ case FF_CONSTANT:
+ ret = iforce_upload_constant(iforce, effect, old);
+ break;
- case FF_SPRING:
- case FF_DAMPER:
- ret = iforce_upload_condition(iforce, effect, old);
- break;
+ case FF_SPRING:
+ case FF_DAMPER:
+ ret = iforce_upload_condition(iforce, effect, old);
+ break;
- default:
- return -EINVAL;
+ default:
+ return -EINVAL;
}
if (ret == 0) {
@@ -173,15 +174,7 @@ static int iforce_open(struct input_dev *dev)
{
struct iforce *iforce = input_get_drvdata(dev);
- switch (iforce->bus) {
-#ifdef CONFIG_JOYSTICK_IFORCE_USB
- case IFORCE_USB:
- iforce->irq->dev = iforce->usbdev;
- if (usb_submit_urb(iforce->irq, GFP_KERNEL))
- return -EIO;
- break;
-#endif
- }
+ iforce->xport_ops->start_io(iforce);
if (test_bit(EV_FF, dev->evbit)) {
/* Enable force feedback */
@@ -214,27 +207,17 @@ static void iforce_close(struct input_dev *dev)
!test_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags));
}
- switch (iforce->bus) {
-#ifdef CONFIG_JOYSTICK_IFORCE_USB
- case IFORCE_USB:
- usb_kill_urb(iforce->irq);
- usb_kill_urb(iforce->out);
- usb_kill_urb(iforce->ctrl);
- break;
-#endif
-#ifdef CONFIG_JOYSTICK_IFORCE_232
- case IFORCE_232:
- //TODO: Wait for the last packets to be sent
- break;
-#endif
- }
+ iforce->xport_ops->stop_io(iforce);
}
-int iforce_init_device(struct iforce *iforce)
+int iforce_init_device(struct device *parent, u16 bustype,
+ struct iforce *iforce)
{
struct input_dev *input_dev;
struct ff_device *ff;
- unsigned char c[] = "CEOV";
+ u8 c[] = "CEOV";
+ u8 buf[IFORCE_MAX_LENGTH];
+ size_t len;
int i, error;
int ff_effects = 0;
@@ -252,20 +235,8 @@ int iforce_init_device(struct iforce *iforce)
* Input device fields.
*/
- switch (iforce->bus) {
-#ifdef CONFIG_JOYSTICK_IFORCE_USB
- case IFORCE_USB:
- input_dev->id.bustype = BUS_USB;
- input_dev->dev.parent = &iforce->usbdev->dev;
- break;
-#endif
-#ifdef CONFIG_JOYSTICK_IFORCE_232
- case IFORCE_232:
- input_dev->id.bustype = BUS_RS232;
- input_dev->dev.parent = &iforce->serio->dev;
- break;
-#endif
- }
+ input_dev->id.bustype = bustype;
+ input_dev->dev.parent = parent;
input_set_drvdata(input_dev, iforce);
@@ -290,7 +261,7 @@ int iforce_init_device(struct iforce *iforce)
*/
for (i = 0; i < 20; i++)
- if (!iforce_get_id_packet(iforce, "O"))
+ if (!iforce_get_id_packet(iforce, 'O', buf, &len))
break;
if (i == 20) { /* 5 seconds */
@@ -304,23 +275,23 @@ int iforce_init_device(struct iforce *iforce)
* Get device info.
*/
- if (!iforce_get_id_packet(iforce, "M"))
- input_dev->id.vendor = (iforce->edata[2] << 8) | iforce->edata[1];
+ if (!iforce_get_id_packet(iforce, 'M', buf, &len) || len < 3)
+ input_dev->id.vendor = get_unaligned_le16(buf + 1);
else
dev_warn(&iforce->dev->dev, "Device does not respond to id packet M\n");
- if (!iforce_get_id_packet(iforce, "P"))
- input_dev->id.product = (iforce->edata[2] << 8) | iforce->edata[1];
+ if (!iforce_get_id_packet(iforce, 'P', buf, &len) || len < 3)
+ input_dev->id.product = get_unaligned_le16(buf + 1);
else
dev_warn(&iforce->dev->dev, "Device does not respond to id packet P\n");
- if (!iforce_get_id_packet(iforce, "B"))
- iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1];
+ if (!iforce_get_id_packet(iforce, 'B', buf, &len) || len < 3)
+ iforce->device_memory.end = get_unaligned_le16(buf + 1);
else
dev_warn(&iforce->dev->dev, "Device does not respond to id packet B\n");
- if (!iforce_get_id_packet(iforce, "N"))
- ff_effects = iforce->edata[1];
+ if (!iforce_get_id_packet(iforce, 'N', buf, &len) || len < 2)
+ ff_effects = buf[1];
else
dev_warn(&iforce->dev->dev, "Device does not respond to id packet N\n");
@@ -336,8 +307,9 @@ int iforce_init_device(struct iforce *iforce)
*/
for (i = 0; c[i]; i++)
- if (!iforce_get_id_packet(iforce, c + i))
- iforce_dump_packet(iforce, "info", iforce->ecmd, iforce->edata);
+ if (!iforce_get_id_packet(iforce, c[i], buf, &len))
+ iforce_dump_packet(iforce, "info",
+ (FF_CMD_QUERY & 0xff00) | len, buf);
/*
* Disable spring, enable force feedback.
@@ -371,34 +343,29 @@ int iforce_init_device(struct iforce *iforce)
signed short t = iforce->type->abs[i];
switch (t) {
+ case ABS_X:
+ case ABS_Y:
+ case ABS_WHEEL:
+ input_set_abs_params(input_dev, t, -1920, 1920, 16, 128);
+ set_bit(t, input_dev->ffbit);
+ break;
- case ABS_X:
- case ABS_Y:
- case ABS_WHEEL:
-
- input_set_abs_params(input_dev, t, -1920, 1920, 16, 128);
- set_bit(t, input_dev->ffbit);
- break;
-
- case ABS_THROTTLE:
- case ABS_GAS:
- case ABS_BRAKE:
-
- input_set_abs_params(input_dev, t, 0, 255, 0, 0);
- break;
-
- case ABS_RUDDER:
-
- input_set_abs_params(input_dev, t, -128, 127, 0, 0);
- break;
+ case ABS_THROTTLE:
+ case ABS_GAS:
+ case ABS_BRAKE:
+ input_set_abs_params(input_dev, t, 0, 255, 0, 0);
+ break;
- case ABS_HAT0X:
- case ABS_HAT0Y:
- case ABS_HAT1X:
- case ABS_HAT1Y:
+ case ABS_RUDDER:
+ input_set_abs_params(input_dev, t, -128, 127, 0, 0);
+ break;
- input_set_abs_params(input_dev, t, -1, 1, 0, 0);
- break;
+ case ABS_HAT0X:
+ case ABS_HAT0Y:
+ case ABS_HAT1X:
+ case ABS_HAT1Y:
+ input_set_abs_params(input_dev, t, -1, 1, 0, 0);
+ break;
}
}
@@ -431,35 +398,4 @@ int iforce_init_device(struct iforce *iforce)
fail: input_free_device(input_dev);
return error;
}
-
-static int __init iforce_init(void)
-{
- int err = 0;
-
-#ifdef CONFIG_JOYSTICK_IFORCE_USB
- err = usb_register(&iforce_usb_driver);
- if (err)
- return err;
-#endif
-#ifdef CONFIG_JOYSTICK_IFORCE_232
- err = serio_register_driver(&iforce_serio_drv);
-#ifdef CONFIG_JOYSTICK_IFORCE_USB
- if (err)
- usb_deregister(&iforce_usb_driver);
-#endif
-#endif
- return err;
-}
-
-static void __exit iforce_exit(void)
-{
-#ifdef CONFIG_JOYSTICK_IFORCE_USB
- usb_deregister(&iforce_usb_driver);
-#endif
-#ifdef CONFIG_JOYSTICK_IFORCE_232
- serio_unregister_driver(&iforce_serio_drv);
-#endif
-}
-
-module_init(iforce_init);
-module_exit(iforce_exit);
+EXPORT_SYMBOL(iforce_init_device);
diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c
index 42cd9730e4cc..b313e38b2c3a 100644
--- a/drivers/input/joystick/iforce/iforce-packets.c
+++ b/drivers/input/joystick/iforce/iforce-packets.c
@@ -9,6 +9,7 @@
/*
*/
+#include <asm/unaligned.h>
#include "iforce.h"
static struct {
@@ -79,27 +80,12 @@ int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data)
/*
* If necessary, start the transmission
*/
- switch (iforce->bus) {
+ if (empty)
+ iforce->xport_ops->xmit(iforce);
-#ifdef CONFIG_JOYSTICK_IFORCE_232
- case IFORCE_232:
- if (empty)
- iforce_serial_xmit(iforce);
- break;
-#endif
-#ifdef CONFIG_JOYSTICK_IFORCE_USB
- case IFORCE_USB:
-
- if (iforce->usbdev && empty &&
- !test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) {
-
- iforce_usb_xmit(iforce);
- }
- break;
-#endif
- }
return 0;
}
+EXPORT_SYMBOL(iforce_send_packet);
/* Start or stop an effect */
int iforce_control_playback(struct iforce* iforce, u16 id, unsigned int value)
@@ -133,157 +119,96 @@ static int mark_core_as_ready(struct iforce *iforce, unsigned short addr)
return -1;
}
-void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data)
+static void iforce_report_hats_buttons(struct iforce *iforce, u8 *data)
{
struct input_dev *dev = iforce->dev;
int i;
- static int being_used = 0;
- if (being_used)
- dev_warn(&iforce->dev->dev,
- "re-entrant call to iforce_process %d\n", being_used);
- being_used++;
-
-#ifdef CONFIG_JOYSTICK_IFORCE_232
- if (HI(iforce->expect_packet) == HI(cmd)) {
- iforce->expect_packet = 0;
- iforce->ecmd = cmd;
- memcpy(iforce->edata, data, IFORCE_MAX_LENGTH);
- }
-#endif
- wake_up(&iforce->wait);
+ input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x);
+ input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y);
- if (!iforce->type) {
- being_used--;
- return;
- }
-
- switch (HI(cmd)) {
-
- case 0x01: /* joystick position data */
- case 0x03: /* wheel position data */
- if (HI(cmd) == 1) {
- input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0]));
- input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2]));
- input_report_abs(dev, ABS_THROTTLE, 255 - data[4]);
- if (LO(cmd) >= 8 && test_bit(ABS_RUDDER ,dev->absbit))
- input_report_abs(dev, ABS_RUDDER, (__s8)data[7]);
- } else {
- input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0]));
- input_report_abs(dev, ABS_GAS, 255 - data[2]);
- input_report_abs(dev, ABS_BRAKE, 255 - data[3]);
- }
+ for (i = 0; iforce->type->btn[i] >= 0; i++)
+ input_report_key(dev, iforce->type->btn[i],
+ data[(i >> 3) + 5] & (1 << (i & 7)));
- input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x);
- input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y);
-
- for (i = 0; iforce->type->btn[i] >= 0; i++)
- input_report_key(dev, iforce->type->btn[i], data[(i >> 3) + 5] & (1 << (i & 7)));
-
- /* If there are untouched bits left, interpret them as the second hat */
- if (i <= 8) {
- int btns = data[6];
- if (test_bit(ABS_HAT1X, dev->absbit)) {
- if (btns & 8) input_report_abs(dev, ABS_HAT1X, -1);
- else if (btns & 2) input_report_abs(dev, ABS_HAT1X, 1);
- else input_report_abs(dev, ABS_HAT1X, 0);
- }
- if (test_bit(ABS_HAT1Y, dev->absbit)) {
- if (btns & 1) input_report_abs(dev, ABS_HAT1Y, -1);
- else if (btns & 4) input_report_abs(dev, ABS_HAT1Y, 1);
- else input_report_abs(dev, ABS_HAT1Y, 0);
- }
- }
+ /* If there are untouched bits left, interpret them as the second hat */
+ if (i <= 8) {
+ u8 btns = data[6];
- input_sync(dev);
-
- break;
-
- case 0x02: /* status report */
- input_report_key(dev, BTN_DEAD, data[0] & 0x02);
- input_sync(dev);
+ if (test_bit(ABS_HAT1X, dev->absbit)) {
+ if (btns & BIT(3))
+ input_report_abs(dev, ABS_HAT1X, -1);
+ else if (btns & BIT(1))
+ input_report_abs(dev, ABS_HAT1X, 1);
+ else
+ input_report_abs(dev, ABS_HAT1X, 0);
+ }
- /* Check if an effect was just started or stopped */
- i = data[1] & 0x7f;
- if (data[1] & 0x80) {
- if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
- /* Report play event */
- input_report_ff_status(dev, i, FF_STATUS_PLAYING);
- }
- } else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
- /* Report stop event */
- input_report_ff_status(dev, i, FF_STATUS_STOPPED);
- }
- if (LO(cmd) > 3) {
- int j;
- for (j = 3; j < LO(cmd); j += 2)
- mark_core_as_ready(iforce, data[j] | (data[j+1]<<8));
- }
- break;
+ if (test_bit(ABS_HAT1Y, dev->absbit)) {
+ if (btns & BIT(0))
+ input_report_abs(dev, ABS_HAT1Y, -1);
+ else if (btns & BIT(2))
+ input_report_abs(dev, ABS_HAT1Y, 1);
+ else
+ input_report_abs(dev, ABS_HAT1Y, 0);
+ }
}
- being_used--;
}
-int iforce_get_id_packet(struct iforce *iforce, char *packet)
+void iforce_process_packet(struct iforce *iforce,
+ u8 packet_id, u8 *data, size_t len)
{
- switch (iforce->bus) {
+ struct input_dev *dev = iforce->dev;
+ int i, j;
- case IFORCE_USB: {
-#ifdef CONFIG_JOYSTICK_IFORCE_USB
- int status;
+ switch (packet_id) {
- iforce->cr.bRequest = packet[0];
- iforce->ctrl->dev = iforce->usbdev;
+ case 0x01: /* joystick position data */
+ input_report_abs(dev, ABS_X,
+ (__s16) get_unaligned_le16(data));
+ input_report_abs(dev, ABS_Y,
+ (__s16) get_unaligned_le16(data + 2));
+ input_report_abs(dev, ABS_THROTTLE, 255 - data[4]);
- status = usb_submit_urb(iforce->ctrl, GFP_KERNEL);
- if (status) {
- dev_err(&iforce->intf->dev,
- "usb_submit_urb failed %d\n", status);
- return -1;
- }
+ if (len >= 8 && test_bit(ABS_RUDDER ,dev->absbit))
+ input_report_abs(dev, ABS_RUDDER, (__s8)data[7]);
- wait_event_interruptible_timeout(iforce->wait,
- iforce->ctrl->status != -EINPROGRESS, HZ);
+ iforce_report_hats_buttons(iforce, data);
- if (iforce->ctrl->status) {
- dev_dbg(&iforce->intf->dev,
- "iforce->ctrl->status = %d\n",
- iforce->ctrl->status);
- usb_unlink_urb(iforce->ctrl);
- return -1;
- }
-#else
- printk(KERN_DEBUG "iforce_get_id_packet: iforce->bus = USB!\n");
-#endif
- }
+ input_sync(dev);
break;
- case IFORCE_232:
+ case 0x03: /* wheel position data */
+ input_report_abs(dev, ABS_WHEEL,
+ (__s16) get_unaligned_le16(data));
+ input_report_abs(dev, ABS_GAS, 255 - data[2]);
+ input_report_abs(dev, ABS_BRAKE, 255 - data[3]);
-#ifdef CONFIG_JOYSTICK_IFORCE_232
- iforce->expect_packet = FF_CMD_QUERY;
- iforce_send_packet(iforce, FF_CMD_QUERY, packet);
+ iforce_report_hats_buttons(iforce, data);
- wait_event_interruptible_timeout(iforce->wait,
- !iforce->expect_packet, HZ);
+ input_sync(dev);
+ break;
+
+ case 0x02: /* status report */
+ input_report_key(dev, BTN_DEAD, data[0] & 0x02);
+ input_sync(dev);
- if (iforce->expect_packet) {
- iforce->expect_packet = 0;
- return -1;
+ /* Check if an effect was just started or stopped */
+ i = data[1] & 0x7f;
+ if (data[1] & 0x80) {
+ if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
+ /* Report play event */
+ input_report_ff_status(dev, i, FF_STATUS_PLAYING);
+ }
+ } else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
+ /* Report stop event */
+ input_report_ff_status(dev, i, FF_STATUS_STOPPED);
}
-#else
- dev_err(&iforce->dev->dev,
- "iforce_get_id_packet: iforce->bus = SERIO!\n");
-#endif
- break;
- default:
- dev_err(&iforce->dev->dev,
- "iforce_get_id_packet: iforce->bus = %d\n",
- iforce->bus);
+ for (j = 3; j < len; j += 2)
+ mark_core_as_ready(iforce, get_unaligned_le16(data + j));
+
break;
}
-
- return -(iforce->edata[0] != packet[0]);
}
-
+EXPORT_SYMBOL(iforce_process_packet);
diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c
index 65a4fe26324f..bbe31e0b759f 100644
--- a/drivers/input/joystick/iforce/iforce-serio.c
+++ b/drivers/input/joystick/iforce/iforce-serio.c
@@ -9,10 +9,26 @@
/*
*/
+#include <linux/serio.h>
#include "iforce.h"
-void iforce_serial_xmit(struct iforce *iforce)
+struct iforce_serio {
+ struct iforce iforce;
+
+ struct serio *serio;
+ int idx, pkt, len, id;
+ u8 csum;
+ u8 expect_packet;
+ u8 cmd_response[IFORCE_MAX_LENGTH];
+ u8 cmd_response_len;
+ u8 data_in[IFORCE_MAX_LENGTH];
+};
+
+static void iforce_serio_xmit(struct iforce *iforce)
{
+ struct iforce_serio *iforce_serio = container_of(iforce,
+ struct iforce_serio,
+ iforce);
unsigned char cs;
int i;
unsigned long flags;
@@ -33,19 +49,20 @@ again:
cs = 0x2b;
- serio_write(iforce->serio, 0x2b);
+ serio_write(iforce_serio->serio, 0x2b);
- serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]);
+ serio_write(iforce_serio->serio, iforce->xmit.buf[iforce->xmit.tail]);
cs ^= iforce->xmit.buf[iforce->xmit.tail];
XMIT_INC(iforce->xmit.tail, 1);
for (i=iforce->xmit.buf[iforce->xmit.tail]; i >= 0; --i) {
- serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]);
+ serio_write(iforce_serio->serio,
+ iforce->xmit.buf[iforce->xmit.tail]);
cs ^= iforce->xmit.buf[iforce->xmit.tail];
XMIT_INC(iforce->xmit.tail, 1);
}
- serio_write(iforce->serio, cs);
+ serio_write(iforce_serio->serio, cs);
if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags))
goto again;
@@ -55,54 +72,118 @@ again:
spin_unlock_irqrestore(&iforce->xmit_lock, flags);
}
+static int iforce_serio_get_id(struct iforce *iforce, u8 id,
+ u8 *response_data, size_t *response_len)
+{
+ struct iforce_serio *iforce_serio = container_of(iforce,
+ struct iforce_serio,
+ iforce);
+
+ iforce_serio->expect_packet = HI(FF_CMD_QUERY);
+ iforce_serio->cmd_response_len = 0;
+
+ iforce_send_packet(iforce, FF_CMD_QUERY, &id);
+
+ wait_event_interruptible_timeout(iforce->wait,
+ !iforce_serio->expect_packet, HZ);
+
+ if (iforce_serio->expect_packet) {
+ iforce_serio->expect_packet = 0;
+ return -ETIMEDOUT;
+ }
+
+ if (iforce_serio->cmd_response[0] != id)
+ return -EIO;
+
+ memcpy(response_data, iforce_serio->cmd_response,
+ iforce_serio->cmd_response_len);
+ *response_len = iforce_serio->cmd_response_len;
+
+ return 0;
+}
+
+static int iforce_serio_start_io(struct iforce *iforce)
+{
+ /* No special handling required */
+ return 0;
+}
+
+static void iforce_serio_stop_io(struct iforce *iforce)
+{
+ //TODO: Wait for the last packets to be sent
+}
+
+static const struct iforce_xport_ops iforce_serio_xport_ops = {
+ .xmit = iforce_serio_xmit,
+ .get_id = iforce_serio_get_id,
+ .start_io = iforce_serio_start_io,
+ .stop_io = iforce_serio_stop_io,
+};
+
static void iforce_serio_write_wakeup(struct serio *serio)
{
struct iforce *iforce = serio_get_drvdata(serio);
- iforce_serial_xmit(iforce);
+ iforce_serio_xmit(iforce);
}
static irqreturn_t iforce_serio_irq(struct serio *serio,
- unsigned char data, unsigned int flags)
+ unsigned char data, unsigned int flags)
{
- struct iforce *iforce = serio_get_drvdata(serio);
+ struct iforce_serio *iforce_serio = serio_get_drvdata(serio);
+ struct iforce *iforce = &iforce_serio->iforce;
- if (!iforce->pkt) {
+ if (!iforce_serio->pkt) {
if (data == 0x2b)
- iforce->pkt = 1;
+ iforce_serio->pkt = 1;
goto out;
}
- if (!iforce->id) {
+ if (!iforce_serio->id) {
if (data > 3 && data != 0xff)
- iforce->pkt = 0;
+ iforce_serio->pkt = 0;
else
- iforce->id = data;
+ iforce_serio->id = data;
goto out;
}
- if (!iforce->len) {
+ if (!iforce_serio->len) {
if (data > IFORCE_MAX_LENGTH) {
- iforce->pkt = 0;
- iforce->id = 0;
+ iforce_serio->pkt = 0;
+ iforce_serio->id = 0;
} else {
- iforce->len = data;
+ iforce_serio->len = data;
}
goto out;
}
- if (iforce->idx < iforce->len) {
- iforce->csum += iforce->data[iforce->idx++] = data;
+ if (iforce_serio->idx < iforce_serio->len) {
+ iforce_serio->data_in[iforce_serio->idx++] = data;
+ iforce_serio->csum += data;
goto out;
}
- if (iforce->idx == iforce->len) {
- iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data);
- iforce->pkt = 0;
- iforce->id = 0;
- iforce->len = 0;
- iforce->idx = 0;
- iforce->csum = 0;
+ if (iforce_serio->idx == iforce_serio->len) {
+ /* Handle command completion */
+ if (iforce_serio->expect_packet == iforce_serio->id) {
+ iforce_serio->expect_packet = 0;
+ memcpy(iforce_serio->cmd_response,
+ iforce_serio->data_in, IFORCE_MAX_LENGTH);
+ iforce_serio->cmd_response_len = iforce_serio->len;
+
+ /* Signal that command is done */
+ wake_up(&iforce->wait);
+ } else if (likely(iforce->type)) {
+ iforce_process_packet(iforce, iforce_serio->id,
+ iforce_serio->data_in,
+ iforce_serio->len);
+ }
+
+ iforce_serio->pkt = 0;
+ iforce_serio->id = 0;
+ iforce_serio->len = 0;
+ iforce_serio->idx = 0;
+ iforce_serio->csum = 0;
}
out:
return IRQ_HANDLED;
@@ -110,23 +191,23 @@ out:
static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv)
{
- struct iforce *iforce;
+ struct iforce_serio *iforce_serio;
int err;
- iforce = kzalloc(sizeof(struct iforce), GFP_KERNEL);
- if (!iforce)
+ iforce_serio = kzalloc(sizeof(*iforce_serio), GFP_KERNEL);
+ if (!iforce_serio)
return -ENOMEM;
- iforce->bus = IFORCE_232;
- iforce->serio = serio;
+ iforce_serio->iforce.xport_ops = &iforce_serio_xport_ops;
- serio_set_drvdata(serio, iforce);
+ iforce_serio->serio = serio;
+ serio_set_drvdata(serio, iforce_serio);
err = serio_open(serio, drv);
if (err)
goto fail1;
- err = iforce_init_device(iforce);
+ err = iforce_init_device(&serio->dev, BUS_RS232, &iforce_serio->iforce);
if (err)
goto fail2;
@@ -134,18 +215,18 @@ static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv)
fail2: serio_close(serio);
fail1: serio_set_drvdata(serio, NULL);
- kfree(iforce);
+ kfree(iforce_serio);
return err;
}
static void iforce_serio_disconnect(struct serio *serio)
{
- struct iforce *iforce = serio_get_drvdata(serio);
+ struct iforce_serio *iforce_serio = serio_get_drvdata(serio);
- input_unregister_device(iforce->dev);
+ input_unregister_device(iforce_serio->iforce.dev);
serio_close(serio);
serio_set_drvdata(serio, NULL);
- kfree(iforce);
+ kfree(iforce_serio);
}
static const struct serio_device_id iforce_serio_ids[] = {
@@ -171,3 +252,9 @@ struct serio_driver iforce_serio_drv = {
.connect = iforce_serio_connect,
.disconnect = iforce_serio_disconnect,
};
+
+module_serio_driver(iforce_serio_drv);
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <johann.deneux@gmail.com>");
+MODULE_DESCRIPTION("RS232 I-Force joysticks and wheels driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c
index f1569ae8381b..ade376bfb79f 100644
--- a/drivers/input/joystick/iforce/iforce-usb.c
+++ b/drivers/input/joystick/iforce/iforce-usb.c
@@ -9,10 +9,24 @@
/*
*/
+#include <linux/usb.h>
#include "iforce.h"
-void iforce_usb_xmit(struct iforce *iforce)
+struct iforce_usb {
+ struct iforce iforce;
+
+ struct usb_device *usbdev;
+ struct usb_interface *intf;
+ struct urb *irq, *out;
+
+ u8 data_in[IFORCE_MAX_LENGTH] ____cacheline_aligned;
+ u8 data_out[IFORCE_MAX_LENGTH] ____cacheline_aligned;
+};
+
+static void __iforce_usb_xmit(struct iforce *iforce)
{
+ struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb,
+ iforce);
int n, c;
unsigned long flags;
@@ -24,31 +38,32 @@ void iforce_usb_xmit(struct iforce *iforce)
return;
}
- ((char *)iforce->out->transfer_buffer)[0] = iforce->xmit.buf[iforce->xmit.tail];
+ ((char *)iforce_usb->out->transfer_buffer)[0] = iforce->xmit.buf[iforce->xmit.tail];
XMIT_INC(iforce->xmit.tail, 1);
n = iforce->xmit.buf[iforce->xmit.tail];
XMIT_INC(iforce->xmit.tail, 1);
- iforce->out->transfer_buffer_length = n + 1;
- iforce->out->dev = iforce->usbdev;
+ iforce_usb->out->transfer_buffer_length = n + 1;
+ iforce_usb->out->dev = iforce_usb->usbdev;
/* Copy rest of data then */
c = CIRC_CNT_TO_END(iforce->xmit.head, iforce->xmit.tail, XMIT_SIZE);
if (n < c) c=n;
- memcpy(iforce->out->transfer_buffer + 1,
+ memcpy(iforce_usb->out->transfer_buffer + 1,
&iforce->xmit.buf[iforce->xmit.tail],
c);
if (n != c) {
- memcpy(iforce->out->transfer_buffer + 1 + c,
+ memcpy(iforce_usb->out->transfer_buffer + 1 + c,
&iforce->xmit.buf[0],
n-c);
}
XMIT_INC(iforce->xmit.tail, n);
- if ( (n=usb_submit_urb(iforce->out, GFP_ATOMIC)) ) {
+ if ( (n=usb_submit_urb(iforce_usb->out, GFP_ATOMIC)) ) {
clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
- dev_warn(&iforce->intf->dev, "usb_submit_urb failed %d\n", n);
+ dev_warn(&iforce_usb->intf->dev,
+ "usb_submit_urb failed %d\n", n);
}
/* The IFORCE_XMIT_RUNNING bit is not cleared here. That's intended.
@@ -57,10 +72,77 @@ void iforce_usb_xmit(struct iforce *iforce)
spin_unlock_irqrestore(&iforce->xmit_lock, flags);
}
+static void iforce_usb_xmit(struct iforce *iforce)
+{
+ if (!test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags))
+ __iforce_usb_xmit(iforce);
+}
+
+static int iforce_usb_get_id(struct iforce *iforce, u8 id,
+ u8 *response_data, size_t *response_len)
+{
+ struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb,
+ iforce);
+ u8 *buf;
+ int status;
+
+ buf = kmalloc(IFORCE_MAX_LENGTH, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ status = usb_control_msg(iforce_usb->usbdev,
+ usb_rcvctrlpipe(iforce_usb->usbdev, 0),
+ id,
+ USB_TYPE_VENDOR | USB_DIR_IN |
+ USB_RECIP_INTERFACE,
+ 0, 0, buf, IFORCE_MAX_LENGTH, HZ);
+ if (status < 0) {
+ dev_err(&iforce_usb->intf->dev,
+ "usb_submit_urb failed: %d\n", status);
+ } else if (buf[0] != id) {
+ status = -EIO;
+ } else {
+ memcpy(response_data, buf, status);
+ *response_len = status;
+ status = 0;
+ }
+
+ kfree(buf);
+ return status;
+}
+
+static int iforce_usb_start_io(struct iforce *iforce)
+{
+ struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb,
+ iforce);
+
+ if (usb_submit_urb(iforce_usb->irq, GFP_KERNEL))
+ return -EIO;
+
+ return 0;
+}
+
+static void iforce_usb_stop_io(struct iforce *iforce)
+{
+ struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb,
+ iforce);
+
+ usb_kill_urb(iforce_usb->irq);
+ usb_kill_urb(iforce_usb->out);
+}
+
+static const struct iforce_xport_ops iforce_usb_xport_ops = {
+ .xmit = iforce_usb_xmit,
+ .get_id = iforce_usb_get_id,
+ .start_io = iforce_usb_start_io,
+ .stop_io = iforce_usb_stop_io,
+};
+
static void iforce_usb_irq(struct urb *urb)
{
- struct iforce *iforce = urb->context;
- struct device *dev = &iforce->intf->dev;
+ struct iforce_usb *iforce_usb = urb->context;
+ struct iforce *iforce = &iforce_usb->iforce;
+ struct device *dev = &iforce_usb->intf->dev;
int status;
switch (urb->status) {
@@ -80,11 +162,11 @@ static void iforce_usb_irq(struct urb *urb)
goto exit;
}
- iforce_process_packet(iforce,
- (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1);
+ iforce_process_packet(iforce, iforce_usb->data_in[0],
+ iforce_usb->data_in + 1, urb->actual_length - 1);
exit:
- status = usb_submit_urb (urb, GFP_ATOMIC);
+ status = usb_submit_urb(urb, GFP_ATOMIC);
if (status)
dev_err(dev, "%s - usb_submit_urb failed with result %d\n",
__func__, status);
@@ -92,35 +174,28 @@ exit:
static void iforce_usb_out(struct urb *urb)
{
- struct iforce *iforce = urb->context;
+ struct iforce_usb *iforce_usb = urb->context;
+ struct iforce *iforce = &iforce_usb->iforce;
if (urb->status) {
clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
- dev_dbg(&iforce->intf->dev, "urb->status %d, exiting\n",
+ dev_dbg(&iforce_usb->intf->dev, "urb->status %d, exiting\n",
urb->status);
return;
}
- iforce_usb_xmit(iforce);
+ __iforce_usb_xmit(iforce);
wake_up(&iforce->wait);
}
-static void iforce_usb_ctrl(struct urb *urb)
-{
- struct iforce *iforce = urb->context;
- if (urb->status) return;
- iforce->ecmd = 0xff00 | urb->actual_length;
- wake_up(&iforce->wait);
-}
-
static int iforce_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(intf);
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *epirq, *epout;
- struct iforce *iforce;
+ struct iforce_usb *iforce_usb;
int err = -ENOMEM;
interface = intf->cur_altsetting;
@@ -131,48 +206,45 @@ static int iforce_usb_probe(struct usb_interface *intf,
epirq = &interface->endpoint[0].desc;
epout = &interface->endpoint[1].desc;
- if (!(iforce = kzalloc(sizeof(struct iforce) + 32, GFP_KERNEL)))
- goto fail;
-
- if (!(iforce->irq = usb_alloc_urb(0, GFP_KERNEL)))
+ iforce_usb = kzalloc(sizeof(*iforce_usb), GFP_KERNEL);
+ if (!iforce_usb)
goto fail;
- if (!(iforce->out = usb_alloc_urb(0, GFP_KERNEL)))
+ iforce_usb->irq = usb_alloc_urb(0, GFP_KERNEL);
+ if (!iforce_usb->irq)
goto fail;
- if (!(iforce->ctrl = usb_alloc_urb(0, GFP_KERNEL)))
+ iforce_usb->out = usb_alloc_urb(0, GFP_KERNEL);
+ if (!iforce_usb->out)
goto fail;
- iforce->bus = IFORCE_USB;
- iforce->usbdev = dev;
- iforce->intf = intf;
-
- iforce->cr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE;
- iforce->cr.wIndex = 0;
- iforce->cr.wLength = cpu_to_le16(16);
+ iforce_usb->iforce.xport_ops = &iforce_usb_xport_ops;
- usb_fill_int_urb(iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress),
- iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval);
+ iforce_usb->usbdev = dev;
+ iforce_usb->intf = intf;
- usb_fill_int_urb(iforce->out, dev, usb_sndintpipe(dev, epout->bEndpointAddress),
- iforce + 1, 32, iforce_usb_out, iforce, epout->bInterval);
+ usb_fill_int_urb(iforce_usb->irq, dev,
+ usb_rcvintpipe(dev, epirq->bEndpointAddress),
+ iforce_usb->data_in, sizeof(iforce_usb->data_in),
+ iforce_usb_irq, iforce_usb, epirq->bInterval);
- usb_fill_control_urb(iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0),
- (void*) &iforce->cr, iforce->edata, 16, iforce_usb_ctrl, iforce);
+ usb_fill_int_urb(iforce_usb->out, dev,
+ usb_sndintpipe(dev, epout->bEndpointAddress),
+ iforce_usb->data_out, sizeof(iforce_usb->data_out),
+ iforce_usb_out, iforce_usb, epout->bInterval);
- err = iforce_init_device(iforce);
+ err = iforce_init_device(&intf->dev, BUS_USB, &iforce_usb->iforce);
if (err)
goto fail;
- usb_set_intfdata(intf, iforce);
+ usb_set_intfdata(intf, iforce_usb);
return 0;
fail:
- if (iforce) {
- usb_free_urb(iforce->irq);
- usb_free_urb(iforce->out);
- usb_free_urb(iforce->ctrl);
- kfree(iforce);
+ if (iforce_usb) {
+ usb_free_urb(iforce_usb->irq);
+ usb_free_urb(iforce_usb->out);
+ kfree(iforce_usb);
}
return err;
@@ -180,17 +252,16 @@ fail:
static void iforce_usb_disconnect(struct usb_interface *intf)
{
- struct iforce *iforce = usb_get_intfdata(intf);
+ struct iforce_usb *iforce_usb = usb_get_intfdata(intf);
usb_set_intfdata(intf, NULL);
- input_unregister_device(iforce->dev);
+ input_unregister_device(iforce_usb->iforce.dev);
- usb_free_urb(iforce->irq);
- usb_free_urb(iforce->out);
- usb_free_urb(iforce->ctrl);
+ usb_free_urb(iforce_usb->irq);
+ usb_free_urb(iforce_usb->out);
- kfree(iforce);
+ kfree(iforce_usb);
}
static const struct usb_device_id iforce_usb_ids[] = {
@@ -202,6 +273,7 @@ static const struct usb_device_id iforce_usb_ids[] = {
{ USB_DEVICE(0x05ef, 0x8888) }, /* AVB Top Shot FFB Racing Wheel */
{ USB_DEVICE(0x061c, 0xc0a4) }, /* ACT LABS Force RS */
{ USB_DEVICE(0x061c, 0xc084) }, /* ACT LABS Force RS */
+ { USB_DEVICE(0x06a3, 0xff04) }, /* Saitek R440 Force Wheel */
{ USB_DEVICE(0x06f8, 0x0001) }, /* Guillemot Race Leader Force Feedback */
{ USB_DEVICE(0x06f8, 0x0003) }, /* Guillemot Jet Leader Force Feedback */
{ USB_DEVICE(0x06f8, 0x0004) }, /* Guillemot Force Feedback Racing Wheel */
@@ -217,3 +289,9 @@ struct usb_driver iforce_usb_driver = {
.disconnect = iforce_usb_disconnect,
.id_table = iforce_usb_ids,
};
+
+module_usb_driver(iforce_usb_driver);
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <johann.deneux@gmail.com>");
+MODULE_DESCRIPTION("USB I-Force joysticks and wheels driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h
index f1681706f526..9cfa460466aa 100644
--- a/drivers/input/joystick/iforce/iforce.h
+++ b/drivers/input/joystick/iforce/iforce.h
@@ -14,8 +14,6 @@
#include <linux/input.h>
#include <linux/module.h>
#include <linux/spinlock.h>
-#include <linux/usb.h>
-#include <linux/serio.h>
#include <linux/circ_buf.h>
#include <linux/mutex.h>
@@ -28,10 +26,6 @@
#define IFORCE_MAX_LENGTH 16
-/* iforce::bus */
-#define IFORCE_232 1
-#define IFORCE_USB 2
-
#define IFORCE_EFFECTS_MAX 32
/* Each force feedback effect is made of one core effect, which can be
@@ -81,27 +75,21 @@ struct iforce_device {
signed short *ff;
};
+struct iforce;
+
+struct iforce_xport_ops {
+ void (*xmit)(struct iforce *iforce);
+ int (*get_id)(struct iforce *iforce, u8 id,
+ u8 *response_data, size_t *response_len);
+ int (*start_io)(struct iforce *iforce);
+ void (*stop_io)(struct iforce *iforce);
+};
+
struct iforce {
struct input_dev *dev; /* Input device interface */
struct iforce_device *type;
- int bus;
-
- unsigned char data[IFORCE_MAX_LENGTH];
- unsigned char edata[IFORCE_MAX_LENGTH];
- u16 ecmd;
- u16 expect_packet;
-
-#ifdef CONFIG_JOYSTICK_IFORCE_232
- struct serio *serio; /* RS232 transfer */
- int idx, pkt, len, id;
- unsigned char csum;
-#endif
-#ifdef CONFIG_JOYSTICK_IFORCE_USB
- struct usb_device *usbdev; /* USB transfer */
- struct usb_interface *intf;
- struct urb *irq, *out, *ctrl;
- struct usb_ctrlrequest cr;
-#endif
+ const struct iforce_xport_ops *xport_ops;
+
spinlock_t xmit_lock;
/* Buffer used for asynchronous sending of bytes to the device */
struct circ_buf xmit;
@@ -127,23 +115,24 @@ struct iforce {
/* Encode a time value */
#define TIME_SCALE(a) (a)
+static inline int iforce_get_id_packet(struct iforce *iforce, u8 id,
+ u8 *response_data, size_t *response_len)
+{
+ return iforce->xport_ops->get_id(iforce, id,
+ response_data, response_len);
+}
/* Public functions */
-/* iforce-serio.c */
-void iforce_serial_xmit(struct iforce *iforce);
-
-/* iforce-usb.c */
-void iforce_usb_xmit(struct iforce *iforce);
-
/* iforce-main.c */
-int iforce_init_device(struct iforce *iforce);
+int iforce_init_device(struct device *parent, u16 bustype,
+ struct iforce *iforce);
/* iforce-packets.c */
int iforce_control_playback(struct iforce*, u16 id, unsigned int);
-void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data);
+void iforce_process_packet(struct iforce *iforce,
+ u8 packet_id, u8 *data, size_t len);
int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data);
void iforce_dump_packet(struct iforce *iforce, char *msg, u16 cmd, unsigned char *data);
-int iforce_get_id_packet(struct iforce *iforce, char *packet);
/* iforce-ff.c */
int iforce_upload_periodic(struct iforce *, struct ff_effect *, struct ff_effect *);
diff --git a/drivers/input/joystick/walkera0701.c b/drivers/input/joystick/walkera0701.c
index dce313dc260a..56abc8c6c763 100644
--- a/drivers/input/joystick/walkera0701.c
+++ b/drivers/input/joystick/walkera0701.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Parallel port to Walkera WK-0701 TX joystick
*
@@ -6,11 +7,6 @@
* More about driver: <file:Documentation/input/devices/walkera0701.rst>
*/
-/*
- * 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.
-*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/input/keyboard/adc-keys.c b/drivers/input/keyboard/adc-keys.c
index c255af21e71a..9885fd56f5f9 100644
--- a/drivers/input/keyboard/adc-keys.c
+++ b/drivers/input/keyboard/adc-keys.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Input driver for resistor ladder connected on ADC
*
* Copyright (c) 2016 Alexandre Belloni
- *
- * 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.
*/
#include <linux/err.h>
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index 3ad93e3e2f4c..7e3eae54c192 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AT and PS/2 keyboard driver
*
* Copyright (c) 1999-2002 Vojtech Pavlik
*/
-/*
- * 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.
- */
/*
* This driver can handle standard AT keyboards and PS/2 keyboards in
diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c
index 73686c2460ce..688e2bef682e 100644
--- a/drivers/input/keyboard/cap11xx.c
+++ b/drivers/input/keyboard/cap11xx.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Input driver for Microchip CAP11xx based capacitive touch sensors
*
* (c) 2014 Daniel Mack <linux@zonque.org>
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c
index d56001181598..38cb6d82d8fe 100644
--- a/drivers/input/keyboard/cros_ec_keyb.c
+++ b/drivers/input/keyboard/cros_ec_keyb.c
@@ -237,7 +237,7 @@ static int cros_ec_keyb_work(struct notifier_block *nb,
if (queued_during_suspend && !device_may_wakeup(ckdev->dev))
return NOTIFY_OK;
- switch (ckdev->ec->event_data.event_type) {
+ switch (ckdev->ec->event_data.event_type & EC_MKBP_EVENT_TYPE_MASK) {
case EC_MKBP_EVENT_KEY_MATRIX:
pm_wakeup_event(ckdev->dev, 0);
diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c
index 575dac52f7b4..7c70492d9d6b 100644
--- a/drivers/input/keyboard/ep93xx_keypad.c
+++ b/drivers/input/keyboard/ep93xx_keypad.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for the Cirrus EP93xx matrix keypad controller.
*
@@ -5,10 +6,6 @@
*
* Based on the pxa27x matrix keypad controller by Rodolfo Giometti.
*
- * 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.
- *
* NOTE:
*
* The 3-key reset is triggered by pressing the 3 keys in
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index 6cd199e8a370..03f4d152f6b7 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for keys on GPIO lines capable of generating interrupts.
*
* Copyright 2005 Phil Blundell
* Copyright 2010, 2011 David Jander <david@protonic.nl>
- *
- * 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.
*/
#include <linux/module.h>
@@ -774,7 +771,6 @@ static int gpio_keys_probe(struct platform_device *pdev)
struct fwnode_handle *child = NULL;
struct gpio_keys_drvdata *ddata;
struct input_dev *input;
- size_t size;
int i, error;
int wakeup = 0;
@@ -784,9 +780,8 @@ static int gpio_keys_probe(struct platform_device *pdev)
return PTR_ERR(pdata);
}
- size = sizeof(struct gpio_keys_drvdata) +
- pdata->nbuttons * sizeof(struct gpio_button_data);
- ddata = devm_kzalloc(dev, size, GFP_KERNEL);
+ ddata = devm_kzalloc(dev, struct_size(ddata, data, pdata->nbuttons),
+ GFP_KERNEL);
if (!ddata) {
dev_err(dev, "failed to allocate state\n");
return -ENOMEM;
diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c
index edc7262103b9..465eecfa6b3f 100644
--- a/drivers/input/keyboard/gpio_keys_polled.c
+++ b/drivers/input/keyboard/gpio_keys_polled.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for buttons on GPIO lines not capable of generating interrupts
*
@@ -9,10 +10,6 @@
*
* also was based on: /drivers/input/keyboard/gpio_keys.c
* Copyright 2005 Phil Blundell
- *
- * 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.
*/
#include <linux/kernel.h>
@@ -168,6 +165,8 @@ gpio_keys_polled_get_devtree_pdata(struct device *dev)
pdata->rep = device_property_present(dev, "autorepeat");
device_property_read_u32(dev, "poll-interval", &pdata->poll_interval);
+ device_property_read_string(dev, "label", &pdata->name);
+
device_for_each_child_node(dev, child) {
if (fwnode_property_read_u32(child, "linux,code",
&button->code)) {
@@ -235,7 +234,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
struct gpio_keys_polled_dev *bdev;
struct input_polled_dev *poll_dev;
struct input_dev *input;
- size_t size;
int error;
int i;
@@ -250,9 +248,8 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
return -EINVAL;
}
- size = sizeof(struct gpio_keys_polled_dev) +
- pdata->nbuttons * sizeof(struct gpio_keys_button_data);
- bdev = devm_kzalloc(dev, size, GFP_KERNEL);
+ bdev = devm_kzalloc(dev, struct_size(bdev, data, pdata->nbuttons),
+ GFP_KERNEL);
if (!bdev) {
dev_err(dev, "no memory for private data\n");
return -ENOMEM;
@@ -272,7 +269,7 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
input = poll_dev->input;
- input->name = pdev->name;
+ input->name = pdata->name ?: pdev->name;
input->phys = DRV_NAME"/input0";
input->id.bustype = BUS_HOST;
diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c
index 539cb670de41..97500a2de2d5 100644
--- a/drivers/input/keyboard/imx_keypad.c
+++ b/drivers/input/keyboard/imx_keypad.c
@@ -422,7 +422,6 @@ static int imx_keypad_probe(struct platform_device *pdev)
dev_get_platdata(&pdev->dev);
struct imx_keypad *keypad;
struct input_dev *input_dev;
- struct resource *res;
int irq, error, i, row, col;
if (!keymap_data && !pdev->dev.of_node) {
@@ -455,8 +454,7 @@ static int imx_keypad_probe(struct platform_device *pdev)
timer_setup(&keypad->check_matrix_timer,
imx_keypad_check_for_events, 0);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- keypad->mmio_base = devm_ioremap_resource(&pdev->dev, res);
+ keypad->mmio_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(keypad->mmio_base))
return PTR_ERR(keypad->mmio_base);
@@ -526,11 +524,12 @@ static int imx_keypad_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused imx_kbd_suspend(struct device *dev)
+static int __maybe_unused imx_kbd_noirq_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct imx_keypad *kbd = platform_get_drvdata(pdev);
struct input_dev *input_dev = kbd->input_dev;
+ unsigned short reg_val = readw(kbd->mmio_base + KPSR);
/* imx kbd can wake up system even clock is disabled */
mutex_lock(&input_dev->mutex);
@@ -540,13 +539,20 @@ static int __maybe_unused imx_kbd_suspend(struct device *dev)
mutex_unlock(&input_dev->mutex);
- if (device_may_wakeup(&pdev->dev))
+ if (device_may_wakeup(&pdev->dev)) {
+ if (reg_val & KBD_STAT_KPKD)
+ reg_val |= KBD_STAT_KRIE;
+ if (reg_val & KBD_STAT_KPKR)
+ reg_val |= KBD_STAT_KDIE;
+ writew(reg_val, kbd->mmio_base + KPSR);
+
enable_irq_wake(kbd->irq);
+ }
return 0;
}
-static int __maybe_unused imx_kbd_resume(struct device *dev)
+static int __maybe_unused imx_kbd_noirq_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct imx_keypad *kbd = platform_get_drvdata(pdev);
@@ -570,7 +576,9 @@ err_clk:
return ret;
}
-static SIMPLE_DEV_PM_OPS(imx_kbd_pm_ops, imx_kbd_suspend, imx_kbd_resume);
+static const struct dev_pm_ops imx_kbd_pm_ops = {
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx_kbd_noirq_suspend, imx_kbd_noirq_resume)
+};
static struct platform_driver imx_keypad_driver = {
.driver = {
diff --git a/drivers/input/keyboard/ipaq-micro-keys.c b/drivers/input/keyboard/ipaq-micro-keys.c
index 602900d1f937..e3f9e445e880 100644
--- a/drivers/input/keyboard/ipaq-micro-keys.c
+++ b/drivers/input/keyboard/ipaq-micro-keys.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
- * 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.
*
* h3600 atmel micro companion support, key subdevice
* based on previous kernel 2.4 version
* Author : Alessandro Gardich <gremlin@gremlin.it>
* Author : Linus Walleij <linus.walleij@linaro.org>
- *
*/
#include <linux/module.h>
#include <linux/init.h>
diff --git a/drivers/input/keyboard/jornada680_kbd.c b/drivers/input/keyboard/jornada680_kbd.c
index 0116ac99f44c..4232aa876d2e 100644
--- a/drivers/input/keyboard/jornada680_kbd.c
+++ b/drivers/input/keyboard/jornada680_kbd.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/input/keyboard/jornada680_kbd.c
*
@@ -10,10 +11,6 @@
* Split from drivers/input/keyboard/hp600_keyb.c
* Copyright (C) 2000 Yaegashi Takeshi (hp6xx kbd scan routine and translation table)
* Copyright (C) 2000 Niibe Yutaka (HP620 Keyb translation table)
- *
- * 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.
*/
#include <linux/device.h>
diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c
index 1277c39f9482..cd9af5221c3d 100644
--- a/drivers/input/keyboard/jornada720_kbd.c
+++ b/drivers/input/keyboard/jornada720_kbd.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/input/keyboard/jornada720_kbd.c
*
@@ -9,11 +10,6 @@
Filip Zyzniewsk <Filip.Zyzniewski@tefnet.plX
* based on (C) 2004 jornada 720 kbd driver by
Alex Lange <chicken@handhelds.org>
- *
- * 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.
- *
*/
#include <linux/device.h>
#include <linux/errno.h>
diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c
index 3d1cb7bf5e35..30924b57058f 100644
--- a/drivers/input/keyboard/matrix_keypad.c
+++ b/drivers/input/keyboard/matrix_keypad.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* GPIO driven matrix keyboard driver
*
* Copyright (c) 2008 Marek Vasut <marek.vasut@gmail.com>
*
* Based on corgikbd.c
- *
- * 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.
- *
*/
#include <linux/types.h>
diff --git a/drivers/input/keyboard/max7359_keypad.c b/drivers/input/keyboard/max7359_keypad.c
index cd44d22d8770..62ce93462955 100644
--- a/drivers/input/keyboard/max7359_keypad.c
+++ b/drivers/input/keyboard/max7359_keypad.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* max7359_keypad.c - MAX7359 Key Switch Controller Driver
*
@@ -6,10 +7,6 @@
*
* Based on pxa27x_keypad.c
*
- * 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.
- *
* Datasheet: http://www.maxim-ic.com/quick_view2.cfm/qv_pk/5456
*/
diff --git a/drivers/input/keyboard/mpr121_touchkey.c b/drivers/input/keyboard/mpr121_touchkey.c
index 884a74d8a7ed..e9ceaa16b46a 100644
--- a/drivers/input/keyboard/mpr121_touchkey.c
+++ b/drivers/input/keyboard/mpr121_touchkey.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Touchkey driver for Freescale MPR121 Controllor
*
@@ -5,11 +6,6 @@
* Author: Zhang Jiejing <jiejing.zhang@freescale.com>
*
* Based on mcs_touchkey.c
- *
- * 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.
- *
*/
#include <linux/bitops.h>
diff --git a/drivers/input/keyboard/nspire-keypad.c b/drivers/input/keyboard/nspire-keypad.c
index c7f26fa3034c..57eac91ecd76 100644
--- a/drivers/input/keyboard/nspire-keypad.c
+++ b/drivers/input/keyboard/nspire-keypad.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au>
- *
- * 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.
*/
#include <linux/input/matrix_keypad.h>
diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c
index d0bdaeadf86d..39023664d2f2 100644
--- a/drivers/input/keyboard/pxa27x_keypad.c
+++ b/drivers/input/keyboard/pxa27x_keypad.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/input/keyboard/pxa27x_keypad.c
*
@@ -9,10 +10,6 @@
* Based on a previous implementations by Kevin O'Connor
* <kevin_at_koconnor.net> and Alex Osborne <bobofdoom@gmail.com> and
* on some suggestions by Nicolas Pitre <nico@fluxnic.net>.
- *
- * 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.
*/
diff --git a/drivers/input/keyboard/pxa930_rotary.c b/drivers/input/keyboard/pxa930_rotary.c
index 1cf5211fddaa..585e7765cbf0 100644
--- a/drivers/input/keyboard/pxa930_rotary.c
+++ b/drivers/input/keyboard/pxa930_rotary.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for the enhanced rotary controller on pxa930 and pxa935
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c
index 7abf03b4cc9c..08ba41a81f14 100644
--- a/drivers/input/keyboard/sh_keysc.c
+++ b/drivers/input/keyboard/sh_keysc.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* SuperH KEYSC Keypad Driver
*
* Copyright (C) 2008 Magnus Damm
*
* Based on gpio_keys.c, Copyright 2005 Phil Blundell
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/input/keyboard/st-keyscan.c b/drivers/input/keyboard/st-keyscan.c
index 3b85631fde91..f097128b93fe 100644
--- a/drivers/input/keyboard/st-keyscan.c
+++ b/drivers/input/keyboard/st-keyscan.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* STMicroelectronics Key Scanning driver
*
@@ -5,10 +6,6 @@
* Author: Stuart Menefy <stuart.menefy@st.com>
*
* Based on sh_keysc.c, copyright 2008 Magnus Damm
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/input/keyboard/stmpe-keypad.c b/drivers/input/keyboard/stmpe-keypad.c
index d69e631cfa0a..7bf97285e30c 100644
--- a/drivers/input/keyboard/stmpe-keypad.c
+++ b/drivers/input/keyboard/stmpe-keypad.c
@@ -1,7 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) ST-Ericsson SA 2010
*
- * License Terms: GNU General Public License, version 2
* Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
*/
diff --git a/drivers/input/keyboard/tc3589x-keypad.c b/drivers/input/keyboard/tc3589x-keypad.c
index ec0070e97090..89b9575dc75d 100644
--- a/drivers/input/keyboard/tc3589x-keypad.c
+++ b/drivers/input/keyboard/tc3589x-keypad.c
@@ -1,11 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) ST-Ericsson SA 2010
*
* Author: Jayeeta Banerjee <jayeeta.banerjee@stericsson.com>
* Author: Sundar Iyer <sundar.iyer@stericsson.com>
*
- * License Terms: GNU General Public License, version 2
- *
* TC35893 MFD Keypad Controller driver
*/
diff --git a/drivers/input/keyboard/tca6416-keypad.c b/drivers/input/keyboard/tca6416-keypad.c
index cdeef180aead..2a14769de637 100644
--- a/drivers/input/keyboard/tca6416-keypad.c
+++ b/drivers/input/keyboard/tca6416-keypad.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for keys on TCA6416 I2C IO expander
*
* Copyright (C) 2010 Texas Instruments
*
* Author : Sriramakrishnan.A.G. <srk@ti.com>
- *
- * 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.
*/
#include <linux/types.h>
diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c
index 6da607d3b811..3bbd7e652533 100644
--- a/drivers/input/keyboard/tca8418_keypad.c
+++ b/drivers/input/keyboard/tca8418_keypad.c
@@ -266,7 +266,7 @@ static int tca8418_keypad_probe(struct i2c_client *client,
struct tca8418_keypad *keypad_data;
struct input_dev *input;
u32 rows = 0, cols = 0;
- int error, row_shift, max_keys;
+ int error, row_shift;
u8 reg;
/* Check i2c driver capabilities */
@@ -291,7 +291,6 @@ static int tca8418_keypad_probe(struct i2c_client *client,
}
row_shift = get_count_order(cols);
- max_keys = rows << row_shift;
/* Allocate memory for keypad_data and input device */
keypad_data = devm_kzalloc(dev, sizeof(*keypad_data), GFP_KERNEL);
diff --git a/drivers/input/keyboard/tm2-touchkey.c b/drivers/input/keyboard/tm2-touchkey.c
index d4455f3a5cf1..14b55bacdd0f 100644
--- a/drivers/input/keyboard/tm2-touchkey.c
+++ b/drivers/input/keyboard/tm2-touchkey.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TM2 touchkey device driver
*
@@ -6,10 +7,6 @@
*
* Author: Beomho Seo <beomho.seo@samsung.com>
* Author: Jaechul Lee <jcsing.lee@samsung.com>
- *
- * 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.
*/
#include <linux/bitops.h>
diff --git a/drivers/input/misc/apanel.c b/drivers/input/misc/apanel.c
index c1e66f45d552..53ec40d1b90d 100644
--- a/drivers/input/misc/apanel.c
+++ b/drivers/input/misc/apanel.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Fujitsu Lifebook Application Panel button drive
*
* Copyright (C) 2007 Stephen Hemminger <shemminger@linux-foundation.org>
* Copyright (C) 2001-2003 Jochen Eisinger <jochen@penguin-breeder.org>
*
- * 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.
- *
* Many Fujitsu Lifebook laptops have a small panel of buttons that are
* accessible via the i2c/smbus interface. This driver polls those
* buttons and generates input events.
diff --git a/drivers/input/misc/arizona-haptics.c b/drivers/input/misc/arizona-haptics.c
index 21dc1b8b2a4a..5fa1c9438a85 100644
--- a/drivers/input/misc/arizona-haptics.c
+++ b/drivers/input/misc/arizona-haptics.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Arizona haptics driver
*
* Copyright 2012 Wolfson Microelectronics plc
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c
index d8fd58fdf050..305f0160506a 100644
--- a/drivers/input/misc/ati_remote2.c
+++ b/drivers/input/misc/ati_remote2.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ati_remote2 - ATI/Philips USB RF remote driver
*
* Copyright (C) 2005-2008 Ville Syrjala <syrjala@sci.fi>
* Copyright (C) 2007-2008 Peter Stokes <linux@dadeos.co.uk>
- *
- * 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.
*/
#include <linux/usb/input.h>
diff --git a/drivers/input/misc/cma3000_d0x.c b/drivers/input/misc/cma3000_d0x.c
index c7d00748277b..e6feb73bb52b 100644
--- a/drivers/input/misc/cma3000_d0x.c
+++ b/drivers/input/misc/cma3000_d0x.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* VTI CMA3000_D0x Accelerometer driver
*
* Copyright (C) 2010 Texas Instruments
* Author: Hemanth V <hemanthv@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/types.h>
diff --git a/drivers/input/misc/cma3000_d0x.h b/drivers/input/misc/cma3000_d0x.h
index 2304ce306e1c..05ad42a564df 100644
--- a/drivers/input/misc/cma3000_d0x.h
+++ b/drivers/input/misc/cma3000_d0x.h
@@ -1,20 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* VTI CMA3000_D0x Accelerometer driver
*
* Copyright (C) 2010 Texas Instruments
* Author: Hemanth V <hemanthv@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _INPUT_CMA3000_H
diff --git a/drivers/input/misc/cma3000_d0x_i2c.c b/drivers/input/misc/cma3000_d0x_i2c.c
index c7021916b64b..03fb49127c3a 100644
--- a/drivers/input/misc/cma3000_d0x_i2c.c
+++ b/drivers/input/misc/cma3000_d0x_i2c.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Implements I2C interface for VTI CMA300_D0x Accelerometer driver
*
* Copyright (C) 2010 Texas Instruments
* Author: Hemanth V <hemanthv@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
diff --git a/drivers/input/misc/da9063_onkey.c b/drivers/input/misc/da9063_onkey.c
index 9d39679372c5..fd355cf59397 100644
--- a/drivers/input/misc/da9063_onkey.c
+++ b/drivers/input/misc/da9063_onkey.c
@@ -13,7 +13,6 @@
#include <linux/regmap.h>
#include <linux/of.h>
#include <linux/mfd/da9063/core.h>
-#include <linux/mfd/da9063/pdata.h>
#include <linux/mfd/da9063/registers.h>
#include <linux/mfd/da9062/core.h>
#include <linux/mfd/da9062/registers.h>
@@ -192,8 +191,6 @@ static void da9063_cancel_poll(void *data)
static int da9063_onkey_probe(struct platform_device *pdev)
{
- struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent);
- struct da9063_pdata *pdata = dev_get_platdata(da9063->dev);
struct da9063_onkey *onkey;
const struct of_device_id *match;
int irq;
@@ -220,12 +217,8 @@ static int da9063_onkey_probe(struct platform_device *pdev)
return -ENXIO;
}
- if (pdata)
- onkey->key_power = pdata->key_power;
- else
- onkey->key_power =
- !of_property_read_bool(pdev->dev.of_node,
- "dlg,disable-key-power");
+ onkey->key_power = !of_property_read_bool(pdev->dev.of_node,
+ "dlg,disable-key-power");
onkey->input = devm_input_allocate_device(&pdev->dev);
if (!onkey->input) {
diff --git a/drivers/input/misc/gp2ap002a00f.c b/drivers/input/misc/gp2ap002a00f.c
index c6a29e57b5e4..90abda8eea67 100644
--- a/drivers/input/misc/gp2ap002a00f.c
+++ b/drivers/input/misc/gp2ap002a00f.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Sony Ericsson Mobile Communications Inc.
*
* Author: Courtney Cavin <courtney.cavin@sonyericsson.com>
* Prepared for up-stream by: Oskar Andero <oskar.andero@sonyericsson.com>
- *
- * 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.
*/
#include <linux/i2c.h>
diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c
index 74cf3b612f05..d8dbfc030d0f 100644
--- a/drivers/input/misc/ims-pcu.c
+++ b/drivers/input/misc/ims-pcu.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for IMS Passenger Control Unit Devices
*
* Copyright (C) 2013 The IMS Company
- *
- * 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.
*/
#include <linux/completion.h>
diff --git a/drivers/input/misc/ixp4xx-beeper.c b/drivers/input/misc/ixp4xx-beeper.c
index 4776273fa10b..794ecc9a552d 100644
--- a/drivers/input/misc/ixp4xx-beeper.c
+++ b/drivers/input/misc/ixp4xx-beeper.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic IXP4xx beeper driver
*
@@ -8,11 +9,6 @@
*
* Author: Alessandro Zummo <a.zummo@towertech.it>
* Maintainers: http://www.nslu2-linux.org/
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/input/misc/m68kspkr.c b/drivers/input/misc/m68kspkr.c
index 312d63623038..25fcf1467151 100644
--- a/drivers/input/misc/m68kspkr.c
+++ b/drivers/input/misc/m68kspkr.c
@@ -1,17 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* m68k beeper driver for Linux
*
* Copyright (c) 2002 Richard Zidlicky
* Copyright (c) 2002 Vojtech Pavlik
* Copyright (c) 1992 Orest Zborowski
- *
*/
-/*
- * 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
- */
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/input/misc/max77650-onkey.c b/drivers/input/misc/max77650-onkey.c
index fbf6caab7217..4d875f2ac13d 100644
--- a/drivers/input/misc/max77650-onkey.c
+++ b/drivers/input/misc/max77650-onkey.c
@@ -119,3 +119,4 @@ module_platform_driver(max77650_onkey_driver);
MODULE_DESCRIPTION("MAXIM 77650/77651 ONKEY driver");
MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:max77650-onkey");
diff --git a/drivers/input/misc/pcap_keys.c b/drivers/input/misc/pcap_keys.c
index 3b81daf67726..b5a53636d7e2 100644
--- a/drivers/input/misc/pcap_keys.c
+++ b/drivers/input/misc/pcap_keys.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Input driver for PCAP events:
* * Power key
* * Headphone button
*
* Copyright (c) 2008,2009 Ilya Petrov <ilya.muromec@gmail.com>
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c
index 56ddba21de84..e5e0d8ba80e1 100644
--- a/drivers/input/misc/pcspkr.c
+++ b/drivers/input/misc/pcspkr.c
@@ -1,16 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* PC Speaker beeper driver for Linux
*
* Copyright (c) 2002 Vojtech Pavlik
* Copyright (c) 1992 Orest Zborowski
- *
*/
-/*
- * 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
- */
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/input/misc/regulator-haptic.c b/drivers/input/misc/regulator-haptic.c
index a1db1e5040dc..a661e77545c5 100644
--- a/drivers/input/misc/regulator-haptic.c
+++ b/drivers/input/misc/regulator-haptic.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Regulator haptic driver
*
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
* Author: Jaewon Kim <jaewon02.kim@samsung.com>
* Author: Hyunhee Kim <hyunhee.kim@samsung.com>
- *
- * 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.
*/
#include <linux/input.h>
diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c
index d748897bf5e9..6d613f2a017c 100644
--- a/drivers/input/misc/rotary_encoder.c
+++ b/drivers/input/misc/rotary_encoder.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* rotary_encoder.c
*
@@ -8,10 +9,6 @@
*
* A generic driver for rotary encoders connected to GPIO lines.
* See file:Documentation/input/devices/rotary-encoder.rst for more information
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index 2ed559dd5e25..84051f20b18a 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -1038,13 +1038,31 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
#ifdef CONFIG_COMPAT
-#define UI_SET_PHYS_COMPAT _IOW(UINPUT_IOCTL_BASE, 108, compat_uptr_t)
+/*
+ * These IOCTLs change their size and thus their numbers between
+ * 32 and 64 bits.
+ */
+#define UI_SET_PHYS_COMPAT \
+ _IOW(UINPUT_IOCTL_BASE, 108, compat_uptr_t)
+#define UI_BEGIN_FF_UPLOAD_COMPAT \
+ _IOWR(UINPUT_IOCTL_BASE, 200, struct uinput_ff_upload_compat)
+#define UI_END_FF_UPLOAD_COMPAT \
+ _IOW(UINPUT_IOCTL_BASE, 201, struct uinput_ff_upload_compat)
static long uinput_compat_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
- if (cmd == UI_SET_PHYS_COMPAT)
+ switch (cmd) {
+ case UI_SET_PHYS_COMPAT:
cmd = UI_SET_PHYS;
+ break;
+ case UI_BEGIN_FF_UPLOAD_COMPAT:
+ cmd = UI_BEGIN_FF_UPLOAD;
+ break;
+ case UI_END_FF_UPLOAD_COMPAT:
+ cmd = UI_END_FF_UPLOAD;
+ break;
+ }
return uinput_ioctl_handler(file, cmd, arg, compat_ptr(arg));
}
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 0a6f7ca883e7..8996323ce8d9 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ALPS touchpad PS/2 mouse driver
*
@@ -9,10 +10,6 @@
*
* ALPS detection, tap switching and status querying info is taken from
* tpconfig utility (by C. Scott Ananian and Bruce Kall).
- *
- * 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.
*/
#include <linux/slab.h>
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index 79b6d69d1486..f4bab629739c 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* ALPS touchpad PS/2 mouse driver
*
* Copyright (c) 2003 Peter Osterlund <petero2@telia.com>
* Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
- *
- * 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.
*/
#ifndef _ALPS_H
diff --git a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c
index a33437c480e3..a50e50354832 100644
--- a/drivers/input/mouse/amimouse.c
+++ b/drivers/input/mouse/amimouse.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Amiga mouse driver for Linux/m68k
*
@@ -11,11 +12,6 @@
* Russell King
*/
-/*
- * 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
- */
#include <linux/module.h>
#include <linux/init.h>
diff --git a/drivers/input/mouse/atarimouse.c b/drivers/input/mouse/atarimouse.c
index 96f2f51604bd..b1219cc4d9a2 100644
--- a/drivers/input/mouse/atarimouse.c
+++ b/drivers/input/mouse/atarimouse.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Atari mouse driver for Linux/m68k
*
@@ -7,7 +8,6 @@
* Amiga mouse driver for Linux/m68k
*
* Copyright (c) 2000-2002 Vojtech Pavlik
- *
*/
/*
* The low level init and interrupt stuff is handled in arch/mm68k/atari/atakeyb.c
@@ -34,11 +34,6 @@
*/
-/*
- * 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
- */
#include <linux/module.h>
#include <linux/init.h>
diff --git a/drivers/input/mouse/byd.c b/drivers/input/mouse/byd.c
index f2aabf7f906f..6e0c5f5a2713 100644
--- a/drivers/input/mouse/byd.c
+++ b/drivers/input/mouse/byd.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* BYD TouchPad PS/2 mouse driver
*
@@ -6,10 +7,6 @@
* Copyright (C) 2015 Tai Chi Minh Ralph Eastwood
* Copyright (C) 2015 Martin Wimpress
* Copyright (C) 2015 Jay Kuri
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/input/mouse/cypress_ps2.c b/drivers/input/mouse/cypress_ps2.c
index 21bad3e75fee..5f868009d35b 100644
--- a/drivers/input/mouse/cypress_ps2.c
+++ b/drivers/input/mouse/cypress_ps2.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Cypress Trackpad PS/2 mouse driver
*
@@ -9,10 +10,6 @@
* Additional contributors include:
* Kamal Mostafa <kamal@canonical.com>
* Kyle Fazzari <git@status.e4ward.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/input/mouse/elan_i2c.h b/drivers/input/mouse/elan_i2c.h
index 243e0fa6e3e3..a9074ac9364f 100644
--- a/drivers/input/mouse/elan_i2c.h
+++ b/drivers/input/mouse/elan_i2c.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Elan I2C/SMBus Touchpad driver
*
@@ -9,10 +10,6 @@
* copyright (c) 2011-2012 Cypress Semiconductor, Inc.
* copyright (c) 2011-2012 Google, 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.
- *
* Trademarks are the property of their respective owners.
*/
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index f9525d6f0bfe..d9b103a81a79 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Elan I2C/SMBus Touchpad driver
*
@@ -11,10 +12,6 @@
* copyright (c) 2011-2012 Cypress Semiconductor, Inc.
* copyright (c) 2011-2012 Google, 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.
- *
* Trademarks are the property of their respective owners.
*/
@@ -37,6 +34,7 @@
#include <linux/completion.h>
#include <linux/of.h>
#include <linux/property.h>
+#include <linux/input/elan-i2c-ids.h>
#include <linux/regulator/consumer.h>
#include <asm/unaligned.h>
@@ -99,6 +97,7 @@ struct elan_tp_data {
u8 max_baseline;
bool baseline_ready;
u8 clickpad;
+ bool middle_button;
};
static int elan_get_fwinfo(u16 ic_type, u16 *validpage_count,
@@ -366,27 +365,62 @@ static unsigned int elan_convert_resolution(u8 val)
static int elan_query_device_parameters(struct elan_tp_data *data)
{
+ struct i2c_client *client = data->client;
unsigned int x_traces, y_traces;
+ u32 x_mm, y_mm;
u8 hw_x_res, hw_y_res;
int error;
- error = data->ops->get_max(data->client, &data->max_x, &data->max_y);
- if (error)
- return error;
-
- error = data->ops->get_num_traces(data->client, &x_traces, &y_traces);
- if (error)
- return error;
+ if (device_property_read_u32(&client->dev,
+ "touchscreen-size-x", &data->max_x) ||
+ device_property_read_u32(&client->dev,
+ "touchscreen-size-y", &data->max_y)) {
+ error = data->ops->get_max(data->client,
+ &data->max_x,
+ &data->max_y);
+ if (error)
+ return error;
+ } else {
+ /* size is the maximum + 1 */
+ --data->max_x;
+ --data->max_y;
+ }
+ if (device_property_read_u32(&client->dev,
+ "elan,x_traces",
+ &x_traces) ||
+ device_property_read_u32(&client->dev,
+ "elan,y_traces",
+ &y_traces)) {
+ error = data->ops->get_num_traces(data->client,
+ &x_traces, &y_traces);
+ if (error)
+ return error;
+ }
data->width_x = data->max_x / x_traces;
data->width_y = data->max_y / y_traces;
- error = data->ops->get_resolution(data->client, &hw_x_res, &hw_y_res);
- if (error)
- return error;
+ if (device_property_read_u32(&client->dev,
+ "touchscreen-x-mm", &x_mm) ||
+ device_property_read_u32(&client->dev,
+ "touchscreen-y-mm", &y_mm)) {
+ error = data->ops->get_resolution(data->client,
+ &hw_x_res, &hw_y_res);
+ if (error)
+ return error;
+
+ data->x_res = elan_convert_resolution(hw_x_res);
+ data->y_res = elan_convert_resolution(hw_y_res);
+ } else {
+ data->x_res = (data->max_x + 1) / x_mm;
+ data->y_res = (data->max_y + 1) / y_mm;
+ }
- data->x_res = elan_convert_resolution(hw_x_res);
- data->y_res = elan_convert_resolution(hw_y_res);
+ if (device_property_read_bool(&client->dev, "elan,clickpad"))
+ data->clickpad = 1;
+
+ if (device_property_read_bool(&client->dev, "elan,middle-button"))
+ data->middle_button = true;
return 0;
}
@@ -926,8 +960,9 @@ static void elan_report_absolute(struct elan_tp_data *data, u8 *packet)
finger_data += ETP_FINGER_DATA_LEN;
}
- input_report_key(input, BTN_LEFT, tp_info & 0x01);
- input_report_key(input, BTN_RIGHT, tp_info & 0x02);
+ input_report_key(input, BTN_LEFT, tp_info & BIT(0));
+ input_report_key(input, BTN_MIDDLE, tp_info & BIT(2));
+ input_report_key(input, BTN_RIGHT, tp_info & BIT(1));
input_report_abs(input, ABS_DISTANCE, hover_event != 0);
input_mt_report_pointer_emulation(input, true);
input_sync(input);
@@ -981,6 +1016,8 @@ static irqreturn_t elan_isr(int irq, void *dev_id)
if (error)
goto out;
+ pm_wakeup_event(dev, 0);
+
switch (report[ETP_REPORT_ID_OFFSET]) {
case ETP_REPORT_ID:
elan_report_absolute(data, report);
@@ -1059,10 +1096,13 @@ static int elan_setup_input_device(struct elan_tp_data *data)
__set_bit(EV_ABS, input->evbit);
__set_bit(INPUT_PROP_POINTER, input->propbit);
- if (data->clickpad)
+ if (data->clickpad) {
__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
- else
+ } else {
__set_bit(BTN_RIGHT, input->keybit);
+ if (data->middle_button)
+ __set_bit(BTN_MIDDLE, input->keybit);
+ }
__set_bit(BTN_LEFT, input->keybit);
/* Set up ST parameters */
@@ -1333,55 +1373,6 @@ static const struct i2c_device_id elan_id[] = {
MODULE_DEVICE_TABLE(i2c, elan_id);
#ifdef CONFIG_ACPI
-static const struct acpi_device_id elan_acpi_id[] = {
- { "ELAN0000", 0 },
- { "ELAN0100", 0 },
- { "ELAN0600", 0 },
- { "ELAN0601", 0 },
- { "ELAN0602", 0 },
- { "ELAN0603", 0 },
- { "ELAN0604", 0 },
- { "ELAN0605", 0 },
- { "ELAN0606", 0 },
- { "ELAN0607", 0 },
- { "ELAN0608", 0 },
- { "ELAN0609", 0 },
- { "ELAN060B", 0 },
- { "ELAN060C", 0 },
- { "ELAN060F", 0 },
- { "ELAN0610", 0 },
- { "ELAN0611", 0 },
- { "ELAN0612", 0 },
- { "ELAN0615", 0 },
- { "ELAN0616", 0 },
- { "ELAN0617", 0 },
- { "ELAN0618", 0 },
- { "ELAN0619", 0 },
- { "ELAN061A", 0 },
- { "ELAN061B", 0 },
- { "ELAN061C", 0 },
- { "ELAN061D", 0 },
- { "ELAN061E", 0 },
- { "ELAN061F", 0 },
- { "ELAN0620", 0 },
- { "ELAN0621", 0 },
- { "ELAN0622", 0 },
- { "ELAN0623", 0 },
- { "ELAN0624", 0 },
- { "ELAN0625", 0 },
- { "ELAN0626", 0 },
- { "ELAN0627", 0 },
- { "ELAN0628", 0 },
- { "ELAN0629", 0 },
- { "ELAN062A", 0 },
- { "ELAN062B", 0 },
- { "ELAN062C", 0 },
- { "ELAN062D", 0 },
- { "ELAN0631", 0 },
- { "ELAN0632", 0 },
- { "ELAN1000", 0 },
- { }
-};
MODULE_DEVICE_TABLE(acpi, elan_acpi_id);
#endif
diff --git a/drivers/input/mouse/elan_i2c_i2c.c b/drivers/input/mouse/elan_i2c_i2c.c
index e19eb60b3d2f..058b35b1f9a9 100644
--- a/drivers/input/mouse/elan_i2c_i2c.c
+++ b/drivers/input/mouse/elan_i2c_i2c.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Elan I2C/SMBus Touchpad driver - I2C interface
*
@@ -9,10 +10,6 @@
* copyright (c) 2011-2012 Cypress Semiconductor, Inc.
* copyright (c) 2011-2012 Google, 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.
- *
* Trademarks are the property of their respective owners.
*/
diff --git a/drivers/input/mouse/elan_i2c_smbus.c b/drivers/input/mouse/elan_i2c_smbus.c
index 88e315d2cfd3..8c3185d54c73 100644
--- a/drivers/input/mouse/elan_i2c_smbus.c
+++ b/drivers/input/mouse/elan_i2c_smbus.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Elan I2C/SMBus Touchpad driver - SMBus interface
*
@@ -9,10 +10,6 @@
* copyright (c) 2011-2012 Cypress Semiconductor, Inc.
* copyright (c) 2011-2012 Google, 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.
- *
* Trademarks are the property of their respective owners.
*/
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index a7f8b1614559..2d8434b7b623 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Elantech Touchpad driver (v6)
*
* Copyright (C) 2007-2009 Arjan Opmeer <arjan@opmeer.net>
*
- * 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.
- *
* Trademarks are the property of their respective owners.
*/
@@ -230,6 +227,52 @@ static void elantech_packet_dump(struct psmouse *psmouse)
}
/*
+ * Advertise INPUT_PROP_BUTTONPAD for clickpads. The testing of bit 12 in
+ * fw_version for this is based on the following fw_version & caps table:
+ *
+ * Laptop-model: fw_version: caps: buttons:
+ * Acer S3 0x461f00 10, 13, 0e clickpad
+ * Acer S7-392 0x581f01 50, 17, 0d clickpad
+ * Acer V5-131 0x461f02 01, 16, 0c clickpad
+ * Acer V5-551 0x461f00 ? clickpad
+ * Asus K53SV 0x450f01 78, 15, 0c 2 hw buttons
+ * Asus G46VW 0x460f02 00, 18, 0c 2 hw buttons
+ * Asus G750JX 0x360f00 00, 16, 0c 2 hw buttons
+ * Asus TP500LN 0x381f17 10, 14, 0e clickpad
+ * Asus X750JN 0x381f17 10, 14, 0e clickpad
+ * Asus UX31 0x361f00 20, 15, 0e clickpad
+ * Asus UX32VD 0x361f02 00, 15, 0e clickpad
+ * Avatar AVIU-145A2 0x361f00 ? clickpad
+ * Fujitsu CELSIUS H760 0x570f02 40, 14, 0c 3 hw buttons (**)
+ * Fujitsu CELSIUS H780 0x5d0f02 41, 16, 0d 3 hw buttons (**)
+ * Fujitsu LIFEBOOK E544 0x470f00 d0, 12, 09 2 hw buttons
+ * Fujitsu LIFEBOOK E546 0x470f00 50, 12, 09 2 hw buttons
+ * Fujitsu LIFEBOOK E547 0x470f00 50, 12, 09 2 hw buttons
+ * Fujitsu LIFEBOOK E554 0x570f01 40, 14, 0c 2 hw buttons
+ * Fujitsu LIFEBOOK E557 0x570f01 40, 14, 0c 2 hw buttons
+ * Fujitsu T725 0x470f01 05, 12, 09 2 hw buttons
+ * Fujitsu H730 0x570f00 c0, 14, 0c 3 hw buttons (**)
+ * Gigabyte U2442 0x450f01 58, 17, 0c 2 hw buttons
+ * Lenovo L430 0x350f02 b9, 15, 0c 2 hw buttons (*)
+ * Lenovo L530 0x350f02 b9, 15, 0c 2 hw buttons (*)
+ * Samsung NF210 0x150b00 78, 14, 0a 2 hw buttons
+ * Samsung NP770Z5E 0x575f01 10, 15, 0f clickpad
+ * Samsung NP700Z5B 0x361f06 21, 15, 0f clickpad
+ * Samsung NP900X3E-A02 0x575f03 ? clickpad
+ * Samsung NP-QX410 0x851b00 19, 14, 0c clickpad
+ * Samsung RC512 0x450f00 08, 15, 0c 2 hw buttons
+ * Samsung RF710 0x450f00 ? 2 hw buttons
+ * System76 Pangolin 0x250f01 ? 2 hw buttons
+ * (*) + 3 trackpoint buttons
+ * (**) + 0 trackpoint buttons
+ * Note: Lenovo L430 and Lenovo L530 have the same fw_version/caps
+ */
+static inline int elantech_is_buttonpad(struct elantech_device_info *info)
+{
+ return info->fw_version & 0x001000;
+}
+
+/*
* Interpret complete data packets and report absolute mode input events for
* hardware version 1. (4 byte packets)
*/
@@ -526,7 +569,7 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse,
input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
/* For clickpads map both buttons to BTN_LEFT */
- if (etd->info.fw_version & 0x001000)
+ if (elantech_is_buttonpad(&etd->info))
input_report_key(dev, BTN_LEFT, packet[0] & 0x03);
else
psmouse_report_standard_buttons(dev, packet[0]);
@@ -544,7 +587,7 @@ static void elantech_input_sync_v4(struct psmouse *psmouse)
unsigned char *packet = psmouse->packet;
/* For clickpads map both buttons to BTN_LEFT */
- if (etd->info.fw_version & 0x001000)
+ if (elantech_is_buttonpad(&etd->info))
input_report_key(dev, BTN_LEFT, packet[0] & 0x03);
else
psmouse_report_standard_buttons(dev, packet[0]);
@@ -994,88 +1037,6 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse)
return rc;
}
-static int elantech_set_range(struct psmouse *psmouse,
- unsigned int *x_min, unsigned int *y_min,
- unsigned int *x_max, unsigned int *y_max,
- unsigned int *width)
-{
- struct elantech_data *etd = psmouse->private;
- struct elantech_device_info *info = &etd->info;
- unsigned char param[3];
- unsigned char traces;
-
- switch (info->hw_version) {
- case 1:
- *x_min = ETP_XMIN_V1;
- *y_min = ETP_YMIN_V1;
- *x_max = ETP_XMAX_V1;
- *y_max = ETP_YMAX_V1;
- break;
-
- case 2:
- if (info->fw_version == 0x020800 ||
- info->fw_version == 0x020b00 ||
- info->fw_version == 0x020030) {
- *x_min = ETP_XMIN_V2;
- *y_min = ETP_YMIN_V2;
- *x_max = ETP_XMAX_V2;
- *y_max = ETP_YMAX_V2;
- } else {
- int i;
- int fixed_dpi;
-
- i = (info->fw_version > 0x020800 &&
- info->fw_version < 0x020900) ? 1 : 2;
-
- if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param))
- return -1;
-
- fixed_dpi = param[1] & 0x10;
-
- if (((info->fw_version >> 16) == 0x14) && fixed_dpi) {
- if (info->send_cmd(psmouse, ETP_SAMPLE_QUERY, param))
- return -1;
-
- *x_max = (info->capabilities[1] - i) * param[1] / 2;
- *y_max = (info->capabilities[2] - i) * param[2] / 2;
- } else if (info->fw_version == 0x040216) {
- *x_max = 819;
- *y_max = 405;
- } else if (info->fw_version == 0x040219 || info->fw_version == 0x040215) {
- *x_max = 900;
- *y_max = 500;
- } else {
- *x_max = (info->capabilities[1] - i) * 64;
- *y_max = (info->capabilities[2] - i) * 64;
- }
- }
- break;
-
- case 3:
- if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param))
- return -1;
-
- *x_max = (0x0f & param[0]) << 8 | param[1];
- *y_max = (0xf0 & param[0]) << 4 | param[2];
- break;
-
- case 4:
- if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param))
- return -1;
-
- *x_max = (0x0f & param[0]) << 8 | param[1];
- *y_max = (0xf0 & param[0]) << 4 | param[2];
- traces = info->capabilities[1];
- if ((traces < 2) || (traces > *x_max))
- return -1;
-
- *width = *x_max / (traces - 1);
- break;
- }
-
- return 0;
-}
-
/*
* (value from firmware) * 10 + 790 = dpi
* we also have to convert dpi to dots/mm (*10/254 to avoid floating point)
@@ -1102,53 +1063,12 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse,
return 0;
}
-/*
- * Advertise INPUT_PROP_BUTTONPAD for clickpads. The testing of bit 12 in
- * fw_version for this is based on the following fw_version & caps table:
- *
- * Laptop-model: fw_version: caps: buttons:
- * Acer S3 0x461f00 10, 13, 0e clickpad
- * Acer S7-392 0x581f01 50, 17, 0d clickpad
- * Acer V5-131 0x461f02 01, 16, 0c clickpad
- * Acer V5-551 0x461f00 ? clickpad
- * Asus K53SV 0x450f01 78, 15, 0c 2 hw buttons
- * Asus G46VW 0x460f02 00, 18, 0c 2 hw buttons
- * Asus G750JX 0x360f00 00, 16, 0c 2 hw buttons
- * Asus TP500LN 0x381f17 10, 14, 0e clickpad
- * Asus X750JN 0x381f17 10, 14, 0e clickpad
- * Asus UX31 0x361f00 20, 15, 0e clickpad
- * Asus UX32VD 0x361f02 00, 15, 0e clickpad
- * Avatar AVIU-145A2 0x361f00 ? clickpad
- * Fujitsu CELSIUS H760 0x570f02 40, 14, 0c 3 hw buttons (**)
- * Fujitsu CELSIUS H780 0x5d0f02 41, 16, 0d 3 hw buttons (**)
- * Fujitsu LIFEBOOK E544 0x470f00 d0, 12, 09 2 hw buttons
- * Fujitsu LIFEBOOK E546 0x470f00 50, 12, 09 2 hw buttons
- * Fujitsu LIFEBOOK E547 0x470f00 50, 12, 09 2 hw buttons
- * Fujitsu LIFEBOOK E554 0x570f01 40, 14, 0c 2 hw buttons
- * Fujitsu LIFEBOOK E557 0x570f01 40, 14, 0c 2 hw buttons
- * Fujitsu T725 0x470f01 05, 12, 09 2 hw buttons
- * Fujitsu H730 0x570f00 c0, 14, 0c 3 hw buttons (**)
- * Gigabyte U2442 0x450f01 58, 17, 0c 2 hw buttons
- * Lenovo L430 0x350f02 b9, 15, 0c 2 hw buttons (*)
- * Lenovo L530 0x350f02 b9, 15, 0c 2 hw buttons (*)
- * Samsung NF210 0x150b00 78, 14, 0a 2 hw buttons
- * Samsung NP770Z5E 0x575f01 10, 15, 0f clickpad
- * Samsung NP700Z5B 0x361f06 21, 15, 0f clickpad
- * Samsung NP900X3E-A02 0x575f03 ? clickpad
- * Samsung NP-QX410 0x851b00 19, 14, 0c clickpad
- * Samsung RC512 0x450f00 08, 15, 0c 2 hw buttons
- * Samsung RF710 0x450f00 ? 2 hw buttons
- * System76 Pangolin 0x250f01 ? 2 hw buttons
- * (*) + 3 trackpoint buttons
- * (**) + 0 trackpoint buttons
- * Note: Lenovo L430 and Lenovo L530 have the same fw_version/caps
- */
static void elantech_set_buttonpad_prop(struct psmouse *psmouse)
{
struct input_dev *dev = psmouse->dev;
struct elantech_data *etd = psmouse->private;
- if (etd->info.fw_version & 0x001000) {
+ if (elantech_is_buttonpad(&etd->info)) {
__set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
__clear_bit(BTN_RIGHT, dev->keybit);
}
@@ -1184,14 +1104,6 @@ static const struct dmi_system_id elantech_dmi_has_middle_button[] = {
{ }
};
-static const char * const middle_button_pnp_ids[] = {
- "LEN2131", /* ThinkPad P52 w/ NFC */
- "LEN2132", /* ThinkPad P52 */
- "LEN2133", /* ThinkPad P72 w/ NFC */
- "LEN2134", /* ThinkPad P72 */
- NULL
-};
-
/*
* Set the appropriate event bits for the input subsystem
*/
@@ -1200,10 +1112,9 @@ static int elantech_set_input_params(struct psmouse *psmouse)
struct input_dev *dev = psmouse->dev;
struct elantech_data *etd = psmouse->private;
struct elantech_device_info *info = &etd->info;
- unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0, width = 0;
-
- if (elantech_set_range(psmouse, &x_min, &y_min, &x_max, &y_max, &width))
- return -1;
+ unsigned int x_min = info->x_min, y_min = info->y_min,
+ x_max = info->x_max, y_max = info->y_max,
+ width = info->width;
__set_bit(INPUT_PROP_POINTER, dev->propbit);
__set_bit(EV_KEY, dev->evbit);
@@ -1211,8 +1122,7 @@ static int elantech_set_input_params(struct psmouse *psmouse)
__clear_bit(EV_REL, dev->evbit);
__set_bit(BTN_LEFT, dev->keybit);
- if (dmi_check_system(elantech_dmi_has_middle_button) ||
- psmouse_matches_pnp_id(psmouse, middle_button_pnp_ids))
+ if (info->has_middle_button)
__set_bit(BTN_MIDDLE, dev->keybit);
__set_bit(BTN_RIGHT, dev->keybit);
@@ -1687,6 +1597,7 @@ static int elantech_query_info(struct psmouse *psmouse,
struct elantech_device_info *info)
{
unsigned char param[3];
+ unsigned char traces;
memset(info, 0, sizeof(*info));
@@ -1755,6 +1666,90 @@ static int elantech_query_info(struct psmouse *psmouse,
}
}
+ /* query range information */
+ switch (info->hw_version) {
+ case 1:
+ info->x_min = ETP_XMIN_V1;
+ info->y_min = ETP_YMIN_V1;
+ info->x_max = ETP_XMAX_V1;
+ info->y_max = ETP_YMAX_V1;
+ break;
+
+ case 2:
+ if (info->fw_version == 0x020800 ||
+ info->fw_version == 0x020b00 ||
+ info->fw_version == 0x020030) {
+ info->x_min = ETP_XMIN_V2;
+ info->y_min = ETP_YMIN_V2;
+ info->x_max = ETP_XMAX_V2;
+ info->y_max = ETP_YMAX_V2;
+ } else {
+ int i;
+ int fixed_dpi;
+
+ i = (info->fw_version > 0x020800 &&
+ info->fw_version < 0x020900) ? 1 : 2;
+
+ if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param))
+ return -EINVAL;
+
+ fixed_dpi = param[1] & 0x10;
+
+ if (((info->fw_version >> 16) == 0x14) && fixed_dpi) {
+ if (info->send_cmd(psmouse, ETP_SAMPLE_QUERY, param))
+ return -EINVAL;
+
+ info->x_max = (info->capabilities[1] - i) * param[1] / 2;
+ info->y_max = (info->capabilities[2] - i) * param[2] / 2;
+ } else if (info->fw_version == 0x040216) {
+ info->x_max = 819;
+ info->y_max = 405;
+ } else if (info->fw_version == 0x040219 || info->fw_version == 0x040215) {
+ info->x_max = 900;
+ info->y_max = 500;
+ } else {
+ info->x_max = (info->capabilities[1] - i) * 64;
+ info->y_max = (info->capabilities[2] - i) * 64;
+ }
+ }
+ break;
+
+ case 3:
+ if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param))
+ return -EINVAL;
+
+ info->x_max = (0x0f & param[0]) << 8 | param[1];
+ info->y_max = (0xf0 & param[0]) << 4 | param[2];
+ break;
+
+ case 4:
+ if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param))
+ return -EINVAL;
+
+ info->x_max = (0x0f & param[0]) << 8 | param[1];
+ info->y_max = (0xf0 & param[0]) << 4 | param[2];
+ traces = info->capabilities[1];
+ if ((traces < 2) || (traces > info->x_max))
+ return -EINVAL;
+
+ info->width = info->x_max / (traces - 1);
+
+ /* column number of traces */
+ info->x_traces = traces;
+
+ /* row number of traces */
+ traces = info->capabilities[2];
+ if ((traces >= 2) && (traces <= info->y_max))
+ info->y_traces = traces;
+
+ break;
+ }
+
+ /* check for the middle button: DMI matching or new v4 firmwares */
+ info->has_middle_button = dmi_check_system(elantech_dmi_has_middle_button) ||
+ (ETP_NEW_IC_SMBUS_HOST_NOTIFY(info->fw_version) &&
+ !elantech_is_buttonpad(info));
+
return 0;
}
@@ -1781,10 +1776,6 @@ static const char * const i2c_blacklist_pnp_ids[] = {
* These are known to not be working properly as bits are missing
* in elan_i2c.
*/
- "LEN2131", /* ThinkPad P52 w/ NFC */
- "LEN2132", /* ThinkPad P52 */
- "LEN2133", /* ThinkPad P72 w/ NFC */
- "LEN2134", /* ThinkPad P72 */
NULL
};
@@ -1792,17 +1783,45 @@ static int elantech_create_smbus(struct psmouse *psmouse,
struct elantech_device_info *info,
bool leave_breadcrumbs)
{
- const struct property_entry i2c_properties[] = {
- PROPERTY_ENTRY_BOOL("elan,trackpoint"),
- { },
- };
+ struct property_entry i2c_props[11] = {};
struct i2c_board_info smbus_board = {
I2C_BOARD_INFO("elan_i2c", 0x15),
.flags = I2C_CLIENT_HOST_NOTIFY,
};
+ unsigned int idx = 0;
+
+ smbus_board.properties = i2c_props;
+
+ i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-size-x",
+ info->x_max + 1);
+ i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-size-y",
+ info->y_max + 1);
+ i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-min-x",
+ info->x_min);
+ i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-min-y",
+ info->y_min);
+ if (info->x_res)
+ i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-x-mm",
+ (info->x_max + 1) / info->x_res);
+ if (info->y_res)
+ i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-y-mm",
+ (info->y_max + 1) / info->y_res);
if (info->has_trackpoint)
- smbus_board.properties = i2c_properties;
+ i2c_props[idx++] = PROPERTY_ENTRY_BOOL("elan,trackpoint");
+
+ if (info->has_middle_button)
+ i2c_props[idx++] = PROPERTY_ENTRY_BOOL("elan,middle-button");
+
+ if (info->x_traces)
+ i2c_props[idx++] = PROPERTY_ENTRY_U32("elan,x_traces",
+ info->x_traces);
+ if (info->y_traces)
+ i2c_props[idx++] = PROPERTY_ENTRY_U32("elan,y_traces",
+ info->y_traces);
+
+ if (elantech_is_buttonpad(info))
+ i2c_props[idx++] = PROPERTY_ENTRY_BOOL("elan,clickpad");
return psmouse_smbus_init(psmouse, &smbus_board, NULL, 0, false,
leave_breadcrumbs);
diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h
index 119727085a60..46343998522b 100644
--- a/drivers/input/mouse/elantech.h
+++ b/drivers/input/mouse/elantech.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Elantech Touchpad driver (v6)
*
* Copyright (C) 2007-2009 Arjan Opmeer <arjan@opmeer.net>
*
- * 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.
- *
* Trademarks are the property of their respective owners.
*/
@@ -144,8 +141,15 @@ struct elantech_device_info {
unsigned char debug;
unsigned char hw_version;
unsigned int fw_version;
+ unsigned int x_min;
+ unsigned int y_min;
+ unsigned int x_max;
+ unsigned int y_max;
unsigned int x_res;
unsigned int y_res;
+ unsigned int x_traces;
+ unsigned int y_traces;
+ unsigned int width;
unsigned int bus;
bool paritycheck;
bool jumpy_cursor;
@@ -153,6 +157,7 @@ struct elantech_device_info {
bool crc_enabled;
bool set_hw_resolution;
bool has_trackpoint;
+ bool has_middle_button;
int (*send_cmd)(struct psmouse *psmouse, unsigned char c,
unsigned char *param);
};
diff --git a/drivers/input/mouse/gpio_mouse.c b/drivers/input/mouse/gpio_mouse.c
index a26d8be6f795..461436f6f087 100644
--- a/drivers/input/mouse/gpio_mouse.c
+++ b/drivers/input/mouse/gpio_mouse.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for simulating a mouse on GPIO lines.
*
* Copyright (C) 2007 Atmel Corporation
* Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c
index 015509e0b140..72a083f3fc4a 100644
--- a/drivers/input/mouse/hgpk.c
+++ b/drivers/input/mouse/hgpk.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* OLPC HGPK (XO-1) touchpad PS/2 mouse driver
*
@@ -12,10 +13,6 @@
* Copyright (c) 2003-2005 Peter Osterlund <petero2@telia.com>
* Copyright (c) 2004 Dmitry Torokhov <dtor@mail.ru>
* Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
- *
- * 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.
*/
/*
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c
index a5765f747c02..bd9955730176 100644
--- a/drivers/input/mouse/lifebook.c
+++ b/drivers/input/mouse/lifebook.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Fujitsu B-series Lifebook PS/2 TouchScreen driver
*
@@ -6,10 +7,6 @@
*
* TouchScreen detection, absolute mode setting and packet layout is taken from
* Harald Hoyer's description of the device.
- *
- * 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.
*/
#include <linux/input.h>
diff --git a/drivers/input/mouse/lifebook.h b/drivers/input/mouse/lifebook.h
index 0baf02a70a99..573f2ca1983d 100644
--- a/drivers/input/mouse/lifebook.h
+++ b/drivers/input/mouse/lifebook.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Fujitsu B-series Lifebook PS/2 TouchScreen driver
*
* Copyright (c) 2005 Vojtech Pavlik
- *
- * 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.
*/
#ifndef _LIFEBOOK_H
diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c
index 3d5637e6fa5f..ed5a848dba9d 100644
--- a/drivers/input/mouse/logips2pp.c
+++ b/drivers/input/mouse/logips2pp.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Logitech PS/2++ mouse driver
*
* Copyright (c) 1999-2003 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2003 Eric Wong <eric@yhbt.net>
- *
- * 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.
*/
#include <linux/bitops.h>
diff --git a/drivers/input/mouse/logips2pp.h b/drivers/input/mouse/logips2pp.h
index bf629453e095..5f9344135f70 100644
--- a/drivers/input/mouse/logips2pp.h
+++ b/drivers/input/mouse/logips2pp.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Logitech PS/2++ mouse driver header
*
* Copyright (c) 2003 Vojtech Pavlik <vojtech@suse.cz>
- *
- * 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.
*/
#ifndef _LOGIPS2PP_H
diff --git a/drivers/input/mouse/navpoint.c b/drivers/input/mouse/navpoint.c
index d6e8f58a1de3..0b75248c8380 100644
--- a/drivers/input/mouse/navpoint.c
+++ b/drivers/input/mouse/navpoint.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Synaptics NavPoint (PXA27x SSP/SPI) driver.
*
* Copyright (C) 2012 Paul Parsons <lost.distance@yahoo.com>
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 94f7ca5ad077..527ae0b9a191 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* PS/2 mouse driver
*
@@ -5,11 +6,6 @@
* Copyright (c) 2003-2004 Dmitry Torokhov
*/
-/*
- * 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.
- */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define psmouse_fmt(fmt) fmt
diff --git a/drivers/input/mouse/psmouse-smbus.c b/drivers/input/mouse/psmouse-smbus.c
index 852d4b486ddb..027efdd2b2ad 100644
--- a/drivers/input/mouse/psmouse-smbus.c
+++ b/drivers/input/mouse/psmouse-smbus.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2017 Red Hat, 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/input/mouse/pxa930_trkball.c b/drivers/input/mouse/pxa930_trkball.c
index 9b4d9a59e229..87bac8cff6f7 100644
--- a/drivers/input/mouse/pxa930_trkball.c
+++ b/drivers/input/mouse/pxa930_trkball.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* PXA930 track ball mouse driver
*
* Copyright (C) 2007 Marvell International Ltd.
* 2008-02-28: Yong Yao <yaoyong@marvell.com>
* initial version
- *
- * 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.
*/
#include <linux/input.h>
diff --git a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c
index 21c60fea5d31..6774029e0a1a 100644
--- a/drivers/input/mouse/rpcmouse.c
+++ b/drivers/input/mouse/rpcmouse.c
@@ -1,15 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Acorn RiscPC mouse driver for Linux/ARM
*
* Copyright (c) 2000-2002 Vojtech Pavlik
* Copyright (C) 1996-2002 Russell King
- *
*/
/*
- * 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.
*
* This handles the Acorn RiscPCs mouse. We basically have a couple of
* hardware registers that track the sensor count for the X-Y movement and
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index b6da0c1267e3..1080c0c49815 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Synaptics TouchPad PS/2 mouse driver
*
@@ -16,10 +17,6 @@
* Copyright (c) 1998-2000 Bruce Kalk <kall@compass.com>
* code for the special synaptics commands (from the tpconfig-source)
*
- * 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.
- *
* Trademarks are the property of their respective owners.
*/
@@ -176,9 +173,12 @@ static const char * const smbus_pnp_ids[] = {
"LEN0072", /* X1 Carbon Gen 5 (2017) - Elan/ALPS trackpoint */
"LEN0073", /* X1 Carbon G5 (Elantech) */
"LEN0092", /* X1 Carbon 6 */
+ "LEN0093", /* T480 */
"LEN0096", /* X280 */
"LEN0097", /* X280 -> ALPS trackpoint */
"LEN200f", /* T450s */
+ "LEN2054", /* E480 */
+ "LEN2055", /* E580 */
"SYN3052", /* HP EliteBook 840 G4 */
"SYN3221", /* HP 15-ay000 */
NULL
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
index fc00e005c611..08533d1b1b16 100644
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Synaptics TouchPad PS/2 mouse driver
- *
- * 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.
*/
#ifndef _SYNAPTICS_H
diff --git a/drivers/input/mouse/touchkit_ps2.h b/drivers/input/mouse/touchkit_ps2.h
index 2efe9ea29d0c..5acb76464a5b 100644
--- a/drivers/input/mouse/touchkit_ps2.h
+++ b/drivers/input/mouse/touchkit_ps2.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/* ----------------------------------------------------------------------------
* touchkit_ps2.h -- Driver for eGalax TouchKit PS/2 Touchscreens
*
* Copyright (C) 2005 by Stefan Lucke
* Copyright (c) 2005 Vojtech Pavlik
- *
- * 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.
*/
#ifndef _TOUCHKIT_PS2_H
diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c
index 6590d10f166f..3eefee2ee2a1 100644
--- a/drivers/input/mouse/trackpoint.c
+++ b/drivers/input/mouse/trackpoint.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Stephen Evanchik <evanchsa@gmail.com>
*
- * 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.
- *
* Trademarks are the property of their respective owners.
*/
diff --git a/drivers/input/mouse/trackpoint.h b/drivers/input/mouse/trackpoint.h
index 10a039148234..0afffe8d824f 100644
--- a/drivers/input/mouse/trackpoint.h
+++ b/drivers/input/mouse/trackpoint.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* IBM TrackPoint PS/2 mouse driver
*
* Stephen Evanchik <evanchsa@gmail.com>
- *
- * 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.
*/
#ifndef _TRACKPOINT_H
diff --git a/drivers/input/mouse/vmmouse.c b/drivers/input/mouse/vmmouse.c
index 1ae5c1ef3f5b..871e5b5ab129 100644
--- a/drivers/input/mouse/vmmouse.c
+++ b/drivers/input/mouse/vmmouse.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for Virtual PS/2 Mouse on VMware and QEMU hypervisors.
*
* Copyright (C) 2014, VMware, Inc. All Rights Reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
* Twin device code is hugely inspired by the ALPS driver.
* Authors:
* Dmitry Torokhov <dmitry.torokhov@gmail.com>
diff --git a/drivers/input/mouse/vmmouse.h b/drivers/input/mouse/vmmouse.h
index 6f126017a24c..774549a12930 100644
--- a/drivers/input/mouse/vmmouse.h
+++ b/drivers/input/mouse/vmmouse.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Driver for Virtual PS/2 Mouse on VMware and QEMU hypervisors.
*
* Copyright (C) 2014, VMware, Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#ifndef _VMMOUSE_H
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index 412fa71245af..505c562a5daa 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Input driver to ExplorerPS/2 device driver module.
*
* Copyright (c) 1999-2002 Vojtech Pavlik
* Copyright (c) 2004 Dmitry Torokhov
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -561,7 +558,7 @@ static int mousedev_open(struct inode *inode, struct file *file)
goto err_free_client;
file->private_data = client;
- nonseekable_open(inode, file);
+ stream_open(inode, file);
return 0;
diff --git a/drivers/input/rmi4/rmi_2d_sensor.c b/drivers/input/rmi4/rmi_2d_sensor.c
index 8eeffa066022..ea549efe4bc4 100644
--- a/drivers/input/rmi4/rmi_2d_sensor.c
+++ b/drivers/input/rmi4/rmi_2d_sensor.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/input/rmi4/rmi_2d_sensor.h b/drivers/input/rmi4/rmi_2d_sensor.h
index c871bef4dac0..7d335d809710 100644
--- a/drivers/input/rmi4/rmi_2d_sensor.h
+++ b/drivers/input/rmi4/rmi_2d_sensor.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
- *
- * 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.
*/
#ifndef _RMI_2D_SENSOR_H
diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c
index bd0d5ff01b08..af706a583656 100644
--- a/drivers/input/rmi4/rmi_bus.c
+++ b/drivers/input/rmi4/rmi_bus.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/input/rmi4/rmi_bus.h b/drivers/input/rmi4/rmi_bus.h
index 96383eab41ba..25df6320f9f1 100644
--- a/drivers/input/rmi4/rmi_bus.h
+++ b/drivers/input/rmi4/rmi_bus.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
- *
- * 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.
*/
#ifndef _RMI_BUS_H
diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c
index 7fb358f96195..772493b1f665 100644
--- a/drivers/input/rmi4/rmi_driver.c
+++ b/drivers/input/rmi4/rmi_driver.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
@@ -8,10 +9,6 @@
*
* http://www.synaptics.com/sites/default/files/
* 511-000136-01-Rev-E-RMI4-Interfacing-Guide.pdf
- *
- * 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.
*/
#include <linux/bitmap.h>
diff --git a/drivers/input/rmi4/rmi_driver.h b/drivers/input/rmi4/rmi_driver.h
index d31793ae83f0..65bfaa95e193 100644
--- a/drivers/input/rmi4/rmi_driver.h
+++ b/drivers/input/rmi4/rmi_driver.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
- *
- * 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.
*/
#ifndef _RMI_DRIVER_H
diff --git a/drivers/input/rmi4/rmi_f01.c b/drivers/input/rmi4/rmi_f01.c
index 4edaa14fe878..e623c956376e 100644
--- a/drivers/input/rmi4/rmi_f01.c
+++ b/drivers/input/rmi4/rmi_f01.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/input/rmi4/rmi_f03.c b/drivers/input/rmi4/rmi_f03.c
index aaa1edc95522..c194b1664b10 100644
--- a/drivers/input/rmi4/rmi_f03.c
+++ b/drivers/input/rmi4/rmi_f03.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2015-2016 Red Hat
* Copyright (C) 2015 Lyude Paul <thatslyude@gmail.com>
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/input/rmi4/rmi_f11.c b/drivers/input/rmi4/rmi_f11.c
index 93901ebd122a..f28a7158b2ef 100644
--- a/drivers/input/rmi4/rmi_f11.c
+++ b/drivers/input/rmi4/rmi_f11.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2011-2015 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/input/rmi4/rmi_f12.c b/drivers/input/rmi4/rmi_f12.c
index 5c7f48915779..d20a5d6780d1 100644
--- a/drivers/input/rmi4/rmi_f12.c
+++ b/drivers/input/rmi4/rmi_f12.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012-2016 Synaptics Incorporated
- *
- * 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.
*/
#include <linux/input.h>
#include <linux/input/mt.h>
@@ -73,7 +70,6 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
int pitch_y = 0;
int rx_receivers = 0;
int tx_receivers = 0;
- int sensor_flags = 0;
item = rmi_get_register_desc_item(&f12->control_reg_desc, 8);
if (!item) {
@@ -129,10 +125,9 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
offset += 2;
}
- if (rmi_register_desc_has_subpacket(item, 4)) {
- sensor_flags = buf[offset];
+ /* Skip over sensor flags */
+ if (rmi_register_desc_has_subpacket(item, 4))
offset += 1;
- }
sensor->x_mm = (pitch_x * rx_receivers) >> 12;
sensor->y_mm = (pitch_y * tx_receivers) >> 12;
diff --git a/drivers/input/rmi4/rmi_f30.c b/drivers/input/rmi4/rmi_f30.c
index 5e3ed5ac0c3e..a90dad1d9ac7 100644
--- a/drivers/input/rmi4/rmi_f30.c
+++ b/drivers/input/rmi4/rmi_f30.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012-2016 Synaptics Incorporated
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/input/rmi4/rmi_f34.c b/drivers/input/rmi4/rmi_f34.c
index 87a7d4ba382d..e5dca9868f87 100644
--- a/drivers/input/rmi4/rmi_f34.c
+++ b/drivers/input/rmi4/rmi_f34.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2007-2016, Synaptics Incorporated
* Copyright (C) 2016 Zodiac Inflight Innovations
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/input/rmi4/rmi_f34.h b/drivers/input/rmi4/rmi_f34.h
index 32c4e9581c68..99faa8c2269d 100644
--- a/drivers/input/rmi4/rmi_f34.h
+++ b/drivers/input/rmi4/rmi_f34.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2007-2016, Synaptics Incorporated
* Copyright (C) 2016 Zodiac Inflight Innovations
- *
- * 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.
*/
#ifndef _RMI_F34_H
diff --git a/drivers/input/rmi4/rmi_f34v7.c b/drivers/input/rmi4/rmi_f34v7.c
index 3991d2943660..a4cabf52740c 100644
--- a/drivers/input/rmi4/rmi_f34v7.c
+++ b/drivers/input/rmi4/rmi_f34v7.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2016, Zodiac Inflight Innovations
* Copyright (c) 2007-2016, Synaptics Incorporated
* Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
* Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
- *
- * 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.
*/
#include <linux/bitops.h>
diff --git a/drivers/input/rmi4/rmi_f54.c b/drivers/input/rmi4/rmi_f54.c
index 516fea06ed59..710b02595486 100644
--- a/drivers/input/rmi4/rmi_f54.c
+++ b/drivers/input/rmi4/rmi_f54.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012-2015 Synaptics Incorporated
* Copyright (C) 2016 Zodiac Inflight Innovations
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/input/rmi4/rmi_f55.c b/drivers/input/rmi4/rmi_f55.c
index 37390ca6a924..488adaca4dd0 100644
--- a/drivers/input/rmi4/rmi_f55.c
+++ b/drivers/input/rmi4/rmi_f55.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012-2015 Synaptics Incorporated
* Copyright (C) 2016 Zodiac Inflight Innovations
- *
- * 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.
*/
#include <linux/bitops.h>
diff --git a/drivers/input/rmi4/rmi_i2c.c b/drivers/input/rmi4/rmi_i2c.c
index d4b3f9d0dc2e..a95c2c9bcab4 100644
--- a/drivers/input/rmi4/rmi_i2c.c
+++ b/drivers/input/rmi4/rmi_i2c.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
- *
- * 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.
*/
#include <linux/i2c.h>
diff --git a/drivers/input/rmi4/rmi_smbus.c b/drivers/input/rmi4/rmi_smbus.c
index b6ccf39c6a7b..2407ea43de59 100644
--- a/drivers/input/rmi4/rmi_smbus.c
+++ b/drivers/input/rmi4/rmi_smbus.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2015 - 2016 Red Hat, Inc
* Copyright (c) 2011, 2012 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/input/rmi4/rmi_spi.c b/drivers/input/rmi4/rmi_spi.c
index 33b8c6e7ac0a..27b68dc79b18 100644
--- a/drivers/input/rmi4/rmi_spi.c
+++ b/drivers/input/rmi4/rmi_spi.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/input/serio/altera_ps2.c b/drivers/input/serio/altera_ps2.c
index 131d7826dc6b..379e9240c2b3 100644
--- a/drivers/input/serio/altera_ps2.c
+++ b/drivers/input/serio/altera_ps2.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Altera University Program PS2 controller driver
*
@@ -5,10 +6,6 @@
*
* Based on sa1111ps2.c, which is:
* Copyright (C) 2002 Russell King
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/input/serio/ams_delta_serio.c b/drivers/input/serio/ams_delta_serio.c
index f8663d7891f2..1c0be299f179 100644
--- a/drivers/input/serio/ams_delta_serio.c
+++ b/drivers/input/serio/ams_delta_serio.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Amstrad E3 (Delta) keyboard port driver
*
* Copyright (c) 2006 Matt Callow
* Copyright (c) 2010 Janusz Krzysztofik
*
- * 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.
- *
* Thanks to Cliff Lawson for his help
*
* The Amstrad Delta keyboard (aka mailboard) uses normal PC-AT style serial
diff --git a/drivers/input/serio/arc_ps2.c b/drivers/input/serio/arc_ps2.c
index 99e57a418753..443194a2b9e3 100644
--- a/drivers/input/serio/arc_ps2.c
+++ b/drivers/input/serio/arc_ps2.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
*
- * 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.
- *
* Driver is originally developed by Pavel Sokolov <psokolov@synopsys.com>
*/
diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h
index 34da81c006b6..da0bf85321de 100644
--- a/drivers/input/serio/i8042-io.h
+++ b/drivers/input/serio/i8042-io.h
@@ -1,11 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _I8042_IO_H
#define _I8042_IO_H
-/*
- * 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.
- */
/*
* Names.
diff --git a/drivers/input/serio/i8042-ip22io.h b/drivers/input/serio/i8042-ip22io.h
index 08a1c10a1448..6c7efa01745c 100644
--- a/drivers/input/serio/i8042-ip22io.h
+++ b/drivers/input/serio/i8042-ip22io.h
@@ -1,14 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _I8042_IP22_H
#define _I8042_IP22_H
#include <asm/sgi/ioc.h>
#include <asm/sgi/ip22.h>
-/*
- * 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.
- */
/*
* Names.
diff --git a/drivers/input/serio/i8042-jazzio.h b/drivers/input/serio/i8042-jazzio.h
index 13fd7108eb28..4c2a96f9128c 100644
--- a/drivers/input/serio/i8042-jazzio.h
+++ b/drivers/input/serio/i8042-jazzio.h
@@ -1,13 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _I8042_JAZZ_H
#define _I8042_JAZZ_H
#include <asm/jazz.h>
-/*
- * 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.
- */
/*
* Names.
diff --git a/drivers/input/serio/i8042-ppcio.h b/drivers/input/serio/i8042-ppcio.h
index 1aabea43329e..391f94d9e47d 100644
--- a/drivers/input/serio/i8042-ppcio.h
+++ b/drivers/input/serio/i8042-ppcio.h
@@ -1,11 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _I8042_PPCIO_H
#define _I8042_PPCIO_H
-/*
- * 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.
- */
#if defined(CONFIG_WALNUT)
diff --git a/drivers/input/serio/i8042-snirm.h b/drivers/input/serio/i8042-snirm.h
index 409a9341143d..4b7136704338 100644
--- a/drivers/input/serio/i8042-snirm.h
+++ b/drivers/input/serio/i8042-snirm.h
@@ -1,13 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _I8042_SNIRM_H
#define _I8042_SNIRM_H
#include <asm/sni.h>
-/*
- * 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.
- */
/*
* Names.
diff --git a/drivers/input/serio/i8042-unicore32io.h b/drivers/input/serio/i8042-unicore32io.h
index 455747552f85..50bb3ed94b56 100644
--- a/drivers/input/serio/i8042-unicore32io.h
+++ b/drivers/input/serio/i8042-unicore32io.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Code specific to PKUnity SoC and UniCore ISA
*
* Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
* Copyright (C) 2001-2011 Guan Xuetao
- *
- * 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.
*/
#ifndef _I8042_UNICORE32_H
#define _I8042_UNICORE32_H
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 136f6e7bf797..dc974c288e88 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -1,11 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _I8042_X86IA64IO_H
#define _I8042_X86IA64IO_H
-/*
- * 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.
- */
#ifdef CONFIG_X86
#include <asm/x86_init.h>
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index 6462f1798fbb..b695094290ab 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* i8042 keyboard and mouse controller driver for Linux
*
* Copyright (c) 1999-2004 Vojtech Pavlik
*/
-/*
- * 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.
- */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -1410,7 +1406,7 @@ static void __init i8042_register_ports(void)
* behavior on many platforms using suspend-to-RAM (ACPI S3)
* by default.
*/
- if (pm_suspend_via_s2idle() && i == I8042_KBD_PORT_NO)
+ if (pm_suspend_default_s2idle() && i == I8042_KBD_PORT_NO)
device_set_wakeup_enable(&serio->dev, true);
}
}
diff --git a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h
index 1db0a40c9bab..38dc27ad3c18 100644
--- a/drivers/input/serio/i8042.h
+++ b/drivers/input/serio/i8042.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _I8042_H
#define _I8042_H
/*
* Copyright (c) 1999-2002 Vojtech Pavlik
- *
- * 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.
*/
/*
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
index 22b8e05aa36c..a8c94a940a79 100644
--- a/drivers/input/serio/libps2.c
+++ b/drivers/input/serio/libps2.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* PS/2 driver library
*
@@ -5,11 +6,6 @@
* Copyright (c) 2004 Dmitry Torokhov
*/
-/*
- * 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.
- */
#include <linux/delay.h>
#include <linux/module.h>
diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c
index e365c5f4cbc9..629e15089c21 100644
--- a/drivers/input/serio/maceps2.c
+++ b/drivers/input/serio/maceps2.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* SGI O2 MACE PS2 controller driver for linux
*
* Copyright (C) 2002 Vivien Chappelier
- *
- * 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
*/
#include <linux/module.h>
#include <linux/init.h>
diff --git a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c
index 1edfac78d4ac..ddbbd4afb4a2 100644
--- a/drivers/input/serio/parkbd.c
+++ b/drivers/input/serio/parkbd.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Parallel port to Keyboard port adapter driver for Linux
*
* Copyright (c) 1999-2004 Vojtech Pavlik
*/
-/*
- * 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.
- */
/*
* To connect an AT or XT keyboard to the parallel port, a fairly simple adapter
diff --git a/drivers/input/serio/ps2-gpio.c b/drivers/input/serio/ps2-gpio.c
index 5e8d8384aa2a..e0f18469d01b 100644
--- a/drivers/input/serio/ps2-gpio.c
+++ b/drivers/input/serio/ps2-gpio.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* GPIO based serio bus driver for bit banging the PS/2 protocol
*
* Author: Danilo Krummrich <danilokrummrich@dk-develop.de>
- *
- * 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.
*/
#include <linux/gpio/consumer.h>
diff --git a/drivers/input/serio/ps2mult.c b/drivers/input/serio/ps2mult.c
index a76fb64f03db..0071dd5ebcc2 100644
--- a/drivers/input/serio/ps2mult.c
+++ b/drivers/input/serio/ps2mult.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TQC PS/2 Multiplexer driver
*
* Copyright (C) 2010 Dmitry Eremin-Solenikov
- *
- * 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.
*/
diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c
index 17b7fbecd9fe..e9647ebff187 100644
--- a/drivers/input/serio/serio_raw.c
+++ b/drivers/input/serio/serio_raw.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Raw serio device providing access to a raw byte stream from underlying
* serio port. Closely emulates behavior of pre-2.6 /dev/psaux device
*
* Copyright (c) 2004 Dmitry Torokhov
- *
- * 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.
*/
#include <linux/kref.h>
diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
index 5977b8a34ebe..8ac970a423de 100644
--- a/drivers/input/serio/serport.c
+++ b/drivers/input/serio/serport.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Input device TTY line discipline
*
@@ -7,11 +8,6 @@
* 'serial io port' abstraction that the input device drivers use.
*/
-/*
- * 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.
- */
#include <linux/uaccess.h>
#include <linux/kernel.h>
diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c
index 0cad5e7c559b..530fd15eaeca 100644
--- a/drivers/input/sparse-keymap.c
+++ b/drivers/input/sparse-keymap.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic support for sparse keymaps
*
@@ -7,10 +8,6 @@
* Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
* Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
* Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
- *
- * 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.
*/
#include <linux/input.h>
diff --git a/drivers/input/touchscreen/88pm860x-ts.c b/drivers/input/touchscreen/88pm860x-ts.c
index 3486d9403805..1d1bbc8da949 100644
--- a/drivers/input/touchscreen/88pm860x-ts.c
+++ b/drivers/input/touchscreen/88pm860x-ts.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Touchscreen driver for Marvell 88PM860x
*
* Copyright (C) 2009 Marvell International Ltd.
* Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- * 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.
*/
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index a2f45aefce08..accbbe8d2966 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ADS7846 based touchscreen and sensor driver
*
@@ -12,10 +13,6 @@
* Copyright (C) 2002 MontaVista Software
* Copyright (C) 2004 Texas Instruments
* Copyright (C) 2005 Dirk Behme
- *
- * 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.
*/
#include <linux/types.h>
#include <linux/hwmon.h>
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 19378f200c63..4a5f482cf1af 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -256,16 +256,6 @@ enum v4l_dbg_inputs {
MXT_V4L_INPUT_MAX,
};
-static const struct v4l2_file_operations mxt_video_fops = {
- .owner = THIS_MODULE,
- .open = v4l2_fh_open,
- .release = vb2_fop_release,
- .unlocked_ioctl = video_ioctl2,
- .read = vb2_fop_read,
- .mmap = vb2_fop_mmap,
- .poll = vb2_fop_poll,
-};
-
enum mxt_suspend_mode {
MXT_SUSPEND_DEEP_SLEEP = 0,
MXT_SUSPEND_T9_CTRL = 1,
@@ -1521,7 +1511,8 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw)
} else if (config_crc == data->config_crc) {
dev_dbg(dev, "Config CRC 0x%06X: OK\n",
data->config_crc);
- return 0;
+ ret = 0;
+ goto release_raw;
} else {
dev_info(dev, "Config CRC 0x%06X: does not match file 0x%06X\n",
data->config_crc, config_crc);
@@ -2218,6 +2209,16 @@ recheck:
}
#ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT_T37
+static const struct v4l2_file_operations mxt_video_fops = {
+ .owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .unlocked_ioctl = video_ioctl2,
+ .read = vb2_fop_read,
+ .mmap = vb2_fop_mmap,
+ .poll = vb2_fop_poll,
+};
+
static u16 mxt_get_debug_value(struct mxt_data *data, unsigned int x,
unsigned int y)
{
diff --git a/drivers/input/touchscreen/da9034-ts.c b/drivers/input/touchscreen/da9034-ts.c
index 8264822dc4b9..2943f6a58388 100644
--- a/drivers/input/touchscreen/da9034-ts.c
+++ b/drivers/input/touchscreen/da9034-ts.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Touchscreen driver for Dialog Semiconductor DA9034
*
@@ -5,10 +6,6 @@
* Fengwei Yin <fengwei.yin@marvell.com>
* Bin Yang <bin.yang@marvell.com>
* Eric Miao <eric.miao@marvell.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/input/touchscreen/dynapro.c b/drivers/input/touchscreen/dynapro.c
index 5b1b66fffbe3..dc07fca7c5ed 100644
--- a/drivers/input/touchscreen/dynapro.c
+++ b/drivers/input/touchscreen/dynapro.c
@@ -1,17 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Dynapro serial touchscreen driver
*
* Copyright (c) 2009 Tias Guns
* Based on the inexio driver (c) Vojtech Pavlik and Dan Streetman and
* Richard Lemon
- *
*/
-/*
- * 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.
- */
/*
* 2009/09/19 Tias Guns <tias@ulyssis.org>
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index c639ebce914c..3cc4341bbdff 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -27,6 +27,7 @@
#include <linux/gpio/consumer.h>
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
+#include <asm/unaligned.h>
#define WORK_REGISTER_THRESHOLD 0x00
#define WORK_REGISTER_REPORT_RATE 0x08
@@ -228,7 +229,6 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
for (i = 0; i < tsdata->max_support_points; i++) {
u8 *buf = &rdbuf[i * tplen + offset];
- bool down;
type = buf[0] >> 6;
/* ignore Reserved events */
@@ -239,23 +239,19 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
if (tsdata->version == EDT_M06 && type == TOUCH_EVENT_DOWN)
continue;
- x = ((buf[0] << 8) | buf[1]) & 0x0fff;
- y = ((buf[2] << 8) | buf[3]) & 0x0fff;
+ x = get_unaligned_be16(buf) & 0x0fff;
+ y = get_unaligned_be16(buf + 2) & 0x0fff;
/* The FT5x26 send the y coordinate first */
if (tsdata->version == EV_FT)
swap(x, y);
id = (buf[2] >> 4) & 0x0f;
- down = type != TOUCH_EVENT_UP;
input_mt_slot(tsdata->input, id);
- input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER, down);
-
- if (!down)
- continue;
-
- touchscreen_report_pos(tsdata->input, &tsdata->prop, x, y,
- true);
+ if (input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER,
+ type != TOUCH_EVENT_UP))
+ touchscreen_report_pos(tsdata->input, &tsdata->prop,
+ x, y, true);
}
input_mt_report_pointer_emulation(tsdata->input, true);
diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c
index c6b85ba7f991..2e1404cd09ec 100644
--- a/drivers/input/touchscreen/eeti_ts.c
+++ b/drivers/input/touchscreen/eeti_ts.c
@@ -28,6 +28,7 @@ struct eeti_ts {
struct input_dev *input;
struct gpio_desc *attn_gpio;
struct touchscreen_properties props;
+ struct mutex mutex;
bool running;
};
@@ -62,42 +63,80 @@ static void eeti_ts_report_event(struct eeti_ts *eeti, u8 *buf)
input_sync(eeti->input);
}
+static int eeti_ts_read(struct eeti_ts *eeti)
+{
+ int len, error;
+ char buf[6];
+
+ len = i2c_master_recv(eeti->client, buf, sizeof(buf));
+ if (len != sizeof(buf)) {
+ error = len < 0 ? len : -EIO;
+ dev_err(&eeti->client->dev,
+ "failed to read touchscreen data: %d\n",
+ error);
+ return error;
+ }
+
+ /* Motion packet */
+ if (buf[0] & 0x80)
+ eeti_ts_report_event(eeti, buf);
+
+ return 0;
+}
+
static irqreturn_t eeti_ts_isr(int irq, void *dev_id)
{
struct eeti_ts *eeti = dev_id;
- int len;
int error;
- char buf[6];
+
+ mutex_lock(&eeti->mutex);
do {
- len = i2c_master_recv(eeti->client, buf, sizeof(buf));
- if (len != sizeof(buf)) {
- error = len < 0 ? len : -EIO;
- dev_err(&eeti->client->dev,
- "failed to read touchscreen data: %d\n",
- error);
+ /*
+ * If we have attention GPIO, trust it. Otherwise we'll read
+ * once and exit. We assume that in this case we are using
+ * level triggered interrupt and it will get raised again
+ * if/when there is more data.
+ */
+ if (eeti->attn_gpio &&
+ !gpiod_get_value_cansleep(eeti->attn_gpio)) {
break;
}
- if (buf[0] & 0x80) {
- /* Motion packet */
- eeti_ts_report_event(eeti, buf);
- }
- } while (eeti->running &&
- eeti->attn_gpio && gpiod_get_value_cansleep(eeti->attn_gpio));
+ error = eeti_ts_read(eeti);
+ if (error)
+ break;
+
+ } while (eeti->running && eeti->attn_gpio);
+ mutex_unlock(&eeti->mutex);
return IRQ_HANDLED;
}
static void eeti_ts_start(struct eeti_ts *eeti)
{
+ mutex_lock(&eeti->mutex);
+
eeti->running = true;
- wmb();
enable_irq(eeti->client->irq);
+
+ /*
+ * Kick the controller in case we are using edge interrupt and
+ * we missed our edge while interrupt was disabled. We expect
+ * the attention GPIO to be wired in this case.
+ */
+ if (eeti->attn_gpio && gpiod_get_value_cansleep(eeti->attn_gpio))
+ eeti_ts_read(eeti);
+
+ mutex_unlock(&eeti->mutex);
}
static void eeti_ts_stop(struct eeti_ts *eeti)
{
+ /*
+ * Not locking here, just setting a flag and expect that the
+ * interrupt thread will notice the flag eventually.
+ */
eeti->running = false;
wmb();
disable_irq(eeti->client->irq);
@@ -140,6 +179,8 @@ static int eeti_ts_probe(struct i2c_client *client,
return -ENOMEM;
}
+ mutex_init(&eeti->mutex);
+
input = devm_input_allocate_device(dev);
if (!input) {
dev_err(dev, "Failed to allocate input device.\n");
diff --git a/drivers/input/touchscreen/egalax_ts_serial.c b/drivers/input/touchscreen/egalax_ts_serial.c
index 657bbae608c8..375922d3a6d1 100644
--- a/drivers/input/touchscreen/egalax_ts_serial.c
+++ b/drivers/input/touchscreen/egalax_ts_serial.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* EETI Egalax serial touchscreen driver
*
@@ -8,11 +9,6 @@
* Hampshire serial touchscreen driver (Copyright (c) 2010 Adam Bennett)
*/
-/*
- * 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.
- */
#include <linux/errno.h>
#include <linux/kernel.h>
diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c
index f2cb23121833..d4ad24ea54c8 100644
--- a/drivers/input/touchscreen/elants_i2c.c
+++ b/drivers/input/touchscreen/elants_i2c.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Elan Microelectronics touch panels with I2C interface
*
@@ -10,7 +11,6 @@
* Copyright (c) 2010-2012 Benjamin Tissoires <benjamin.tissoires@gmail.com>
* Copyright (c) 2010-2012 Ecole Nationale de l'Aviation Civile, France
*
- *
* This code is partly based on i2c-hid.c:
*
* Copyright (c) 2012 Benjamin Tissoires <benjamin.tissoires@gmail.com>
@@ -18,11 +18,6 @@
* Copyright (c) 2012 Red Hat, Inc
*/
-/*
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- */
#include <linux/module.h>
#include <linux/input.h>
diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c
index 7f2942f3cec6..d6772a2c2d09 100644
--- a/drivers/input/touchscreen/elo.c
+++ b/drivers/input/touchscreen/elo.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Elo serial touchscreen driver
*
* Copyright (c) 2004 Vojtech Pavlik
*/
-/*
- * 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.
- */
/*
* This driver can handle serial Elo touchscreens using either the Elo standard
diff --git a/drivers/input/touchscreen/exc3000.c b/drivers/input/touchscreen/exc3000.c
index 37437a53cd1a..e007e2e8f626 100644
--- a/drivers/input/touchscreen/exc3000.c
+++ b/drivers/input/touchscreen/exc3000.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for I2C connected EETI EXC3000 multiple touch controller
*
* Copyright (C) 2017 Ahmet Inan <inan@distec.de>
*
* minimal implementation based on egalax_ts.c and egalax_i2c.c
- *
- * 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.
*/
#include <linux/bitops.h>
diff --git a/drivers/input/touchscreen/fujitsu_ts.c b/drivers/input/touchscreen/fujitsu_ts.c
index a0fbb454499d..3b0b8fccc3f0 100644
--- a/drivers/input/touchscreen/fujitsu_ts.c
+++ b/drivers/input/touchscreen/fujitsu_ts.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Fujitsu serial touchscreen driver
*
* Copyright (c) Dmitry Torokhov <dtor@mail.ru>
*/
-/*
- * 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.
- */
#include <linux/errno.h>
#include <linux/kernel.h>
diff --git a/drivers/input/touchscreen/hampshire.c b/drivers/input/touchscreen/hampshire.c
index eb052d559e54..5c4d877564ee 100644
--- a/drivers/input/touchscreen/hampshire.c
+++ b/drivers/input/touchscreen/hampshire.c
@@ -1,16 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Hampshire serial touchscreen driver
*
* Copyright (c) 2010 Adam Bennett
* Based on the dynapro driver (c) Tias Guns
- *
*/
-/*
- * 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.
- */
/*
* 2010/04/08 Adam Bennett <abennett72@gmail.com>
diff --git a/drivers/input/touchscreen/hideep.c b/drivers/input/touchscreen/hideep.c
index f1cd4dd9a4a3..84fbbf415c43 100644
--- a/drivers/input/touchscreen/hideep.c
+++ b/drivers/input/touchscreen/hideep.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012-2017 Hideep, 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 Foudation.
*/
#include <linux/module.h>
diff --git a/drivers/input/touchscreen/htcpen.c b/drivers/input/touchscreen/htcpen.c
index 8fd909285877..2f261a34f9c2 100644
--- a/drivers/input/touchscreen/htcpen.c
+++ b/drivers/input/touchscreen/htcpen.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* HTC Shift touchscreen driver
*
* Copyright (C) 2008 Pau Oliva Fora <pof@eslack.org>
- *
- * 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.
*/
#include <linux/errno.h>
diff --git a/drivers/input/touchscreen/imx6ul_tsc.c b/drivers/input/touchscreen/imx6ul_tsc.c
index c10fc594f94d..e04eecd65bbb 100644
--- a/drivers/input/touchscreen/imx6ul_tsc.c
+++ b/drivers/input/touchscreen/imx6ul_tsc.c
@@ -364,8 +364,6 @@ static int imx6ul_tsc_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
struct imx6ul_tsc *tsc;
struct input_dev *input_dev;
- struct resource *tsc_mem;
- struct resource *adc_mem;
int err;
int tsc_irq;
int adc_irq;
@@ -403,16 +401,14 @@ static int imx6ul_tsc_probe(struct platform_device *pdev)
return err;
}
- tsc_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- tsc->tsc_regs = devm_ioremap_resource(&pdev->dev, tsc_mem);
+ tsc->tsc_regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(tsc->tsc_regs)) {
err = PTR_ERR(tsc->tsc_regs);
dev_err(&pdev->dev, "failed to remap tsc memory: %d\n", err);
return err;
}
- adc_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- tsc->adc_regs = devm_ioremap_resource(&pdev->dev, adc_mem);
+ tsc->adc_regs = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(tsc->adc_regs)) {
err = PTR_ERR(tsc->adc_regs);
dev_err(&pdev->dev, "failed to remap adc memory: %d\n", err);
diff --git a/drivers/input/touchscreen/inexio.c b/drivers/input/touchscreen/inexio.c
index 13bd0bf580a7..1d7e4c3966ce 100644
--- a/drivers/input/touchscreen/inexio.c
+++ b/drivers/input/touchscreen/inexio.c
@@ -1,16 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* iNexio serial touchscreen driver
*
* Copyright (c) 2008 Richard Lemon
* Based on the mtouch driver (c) Vojtech Pavlik and Dan Streetman
- *
*/
-/*
- * 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.
- */
/*
* 2008/06/19 Richard Lemon <richard@codelemon.com>
diff --git a/drivers/input/touchscreen/ipaq-micro-ts.c b/drivers/input/touchscreen/ipaq-micro-ts.c
index 33c134820ef9..5c3977e1af6f 100644
--- a/drivers/input/touchscreen/ipaq-micro-ts.c
+++ b/drivers/input/touchscreen/ipaq-micro-ts.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
- * 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.
*
* h3600 atmel micro companion support, touchscreen subdevice
* Author : Alessandro Gardich <gremlin@gremlin.it>
* Author : Dmitry Artamonow <mad_soft@inbox.ru>
* Author : Linus Walleij <linus.walleij@linaro.org>
- *
*/
#include <asm/byteorder.h>
diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c
index b832fe062645..5875bb1099a8 100644
--- a/drivers/input/touchscreen/iqs5xx.c
+++ b/drivers/input/touchscreen/iqs5xx.c
@@ -502,14 +502,6 @@ static int iqs5xx_axis_init(struct i2c_client *client)
input_set_capability(input, EV_ABS, ABS_MT_POSITION_Y);
input_set_capability(input, EV_ABS, ABS_MT_PRESSURE);
- error = input_mt_init_slots(input,
- IQS5XX_NUM_CONTACTS, INPUT_MT_DIRECT);
- if (error) {
- dev_err(&client->dev,
- "Failed to initialize slots: %d\n", error);
- return error;
- }
-
input_set_drvdata(input, iqs5xx);
iqs5xx->input = input;
}
@@ -591,9 +583,19 @@ static int iqs5xx_axis_init(struct i2c_client *client)
if (error)
return error;
- return iqs5xx_write_word(client,
- prop.swap_x_y ? IQS5XX_X_RES : IQS5XX_Y_RES,
- max_y);
+ error = iqs5xx_write_word(client,
+ prop.swap_x_y ? IQS5XX_X_RES : IQS5XX_Y_RES,
+ max_y);
+ if (error)
+ return error;
+
+ error = input_mt_init_slots(iqs5xx->input, IQS5XX_NUM_CONTACTS,
+ INPUT_MT_DIRECT);
+ if (error)
+ dev_err(&client->dev, "Failed to initialize slots: %d\n",
+ error);
+
+ return error;
}
static int iqs5xx_dev_init(struct i2c_client *client)
@@ -1054,8 +1056,6 @@ static int iqs5xx_probe(struct i2c_client *client,
if (!iqs5xx)
return -ENOMEM;
- dev_set_drvdata(&client->dev, iqs5xx);
-
i2c_set_clientdata(client, iqs5xx);
iqs5xx->client = client;
diff --git a/drivers/input/touchscreen/jornada720_ts.c b/drivers/input/touchscreen/jornada720_ts.c
index 729b3c89324c..974521102178 100644
--- a/drivers/input/touchscreen/jornada720_ts.c
+++ b/drivers/input/touchscreen/jornada720_ts.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/input/touchscreen/jornada720_ts.c
*
@@ -6,10 +7,6 @@
* Copyright (C) 2006 Filip Zyzniewski <filip.zyzniewski@tefnet.pl>
* based on HP Jornada 56x touchscreen driver by Alex Lange <chicken@handhelds.org>
*
- * 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.
- *
* HP Jornada 710/720/729 Touchscreen Driver
*/
diff --git a/drivers/input/touchscreen/mc13783_ts.c b/drivers/input/touchscreen/mc13783_ts.c
index ef64f36c5ffc..ae0d978c83bf 100644
--- a/drivers/input/touchscreen/mc13783_ts.c
+++ b/drivers/input/touchscreen/mc13783_ts.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for the Freescale Semiconductor MC13783 touchscreen.
*
@@ -6,10 +7,6 @@
*
* Initial development of this code was funded by
* Phytec Messtechnik GmbH, http://www.phytec.de/
- *
- * 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.
*/
#include <linux/platform_device.h>
#include <linux/mfd/mc13783.h>
diff --git a/drivers/input/touchscreen/mk712.c b/drivers/input/touchscreen/mk712.c
index c179060525ae..753d9cc1de1f 100644
--- a/drivers/input/touchscreen/mk712.c
+++ b/drivers/input/touchscreen/mk712.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ICS MK712 touchscreen controller driver
*
@@ -6,11 +7,6 @@
* Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
*/
-/*
- * 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.
- */
/*
* This driver supports the ICS MicroClock MK712 TouchScreen controller,
diff --git a/drivers/input/touchscreen/mtouch.c b/drivers/input/touchscreen/mtouch.c
index 8278a9058640..28e449eea318 100644
--- a/drivers/input/touchscreen/mtouch.c
+++ b/drivers/input/touchscreen/mtouch.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* MicroTouch (3M) serial touchscreen driver
*
* Copyright (c) 2004 Vojtech Pavlik
*/
-/*
- * 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.
- */
/*
* 2005/02/19 Dan Streetman <ddstreet@ieee.org>
diff --git a/drivers/input/touchscreen/of_touchscreen.c b/drivers/input/touchscreen/of_touchscreen.c
index 6d241d45e312..e16ec4c7043a 100644
--- a/drivers/input/touchscreen/of_touchscreen.c
+++ b/drivers/input/touchscreen/of_touchscreen.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic DT helper functions for touchscreen devices
*
* Copyright (c) 2014 Sebastian Reichel <sre@kernel.org>
- *
- * 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.
- *
*/
#include <linux/property.h>
diff --git a/drivers/input/touchscreen/pcap_ts.c b/drivers/input/touchscreen/pcap_ts.c
index 0e3fc419a3cf..b2da0194e02a 100644
--- a/drivers/input/touchscreen/pcap_ts.c
+++ b/drivers/input/touchscreen/pcap_ts.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for Motorola PCAP2 touchscreen as found in the EZX phone platform.
*
* Copyright (C) 2006 Harald Welte <laforge@openezx.org>
* Copyright (C) 2009 Daniel Ribeiro <drwyrm@gmail.com>
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c
index 6e6d7fd98cd2..12abb3b36128 100644
--- a/drivers/input/touchscreen/penmount.c
+++ b/drivers/input/touchscreen/penmount.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Penmount serial touchscreen driver
*
@@ -8,11 +9,6 @@
* Copyright (c) 2004 Vojtech Pavlik
*/
-/*
- * 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.
- */
#include <linux/errno.h>
#include <linux/kernel.h>
diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c
index a67d5e93fb77..ad8b6a2bfd36 100644
--- a/drivers/input/touchscreen/silead.c
+++ b/drivers/input/touchscreen/silead.c
@@ -609,6 +609,7 @@ static const struct acpi_device_id silead_ts_acpi_match[] = {
{ "MSSL1680", 0 },
{ "MSSL0001", 0 },
{ "MSSL0002", 0 },
+ { "MSSL0017", 0 },
{ }
};
MODULE_DEVICE_TABLE(acpi, silead_ts_acpi_match);
diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c
index 92f6e1ae23a2..f11ba7f2dca7 100644
--- a/drivers/input/touchscreen/sun4i-ts.c
+++ b/drivers/input/touchscreen/sun4i-ts.c
@@ -22,7 +22,7 @@
* in the kernel). So this driver offers straight forward, reliable single
* touch functionality only.
*
- * s.a. A20 User Manual "1.15 TP" (Documentation/arm/sunxi/README)
+ * s.a. A20 User Manual "1.15 TP" (Documentation/arm/sunxi.rst)
* (looks like the description in the A20 User Manual v1.3 is better
* than the one in the A10 User Manual v.1.5)
*/
diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c
index 8c8ac4dff0d5..00cb1ba2d364 100644
--- a/drivers/input/touchscreen/sur40.c
+++ b/drivers/input/touchscreen/sur40.c
@@ -929,10 +929,6 @@ static int sur40_vidioc_querycap(struct file *file, void *priv,
strlcpy(cap->driver, DRIVER_SHORT, sizeof(cap->driver));
strlcpy(cap->card, DRIVER_LONG, sizeof(cap->card));
usb_make_path(sur40->usbdev, cap->bus_info, sizeof(cap->bus_info));
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TOUCH |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -1162,6 +1158,8 @@ static const struct video_device sur40_video_device = {
.fops = &sur40_video_fops,
.ioctl_ops = &sur40_video_ioctl_ops,
.release = video_device_release_empty,
+ .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TOUCH |
+ V4L2_CAP_READWRITE | V4L2_CAP_STREAMING,
};
/* USB-specific object needed to register this driver with the USB subsystem. */
diff --git a/drivers/input/touchscreen/sx8654.c b/drivers/input/touchscreen/sx8654.c
index dbdf4898aa17..de85e57b2486 100644
--- a/drivers/input/touchscreen/sx8654.c
+++ b/drivers/input/touchscreen/sx8654.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for Semtech SX8654 I2C touchscreen controller.
*
@@ -21,10 +22,6 @@
* Copyright (C) 2002 MontaVista Software
* Copyright (C) 2004 Texas Instruments
* Copyright (C) 2005 Dirk Behme
- *
- * 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.
*/
#include <linux/bitops.h>
diff --git a/drivers/input/touchscreen/touchit213.c b/drivers/input/touchscreen/touchit213.c
index 98a16698be8e..fb49687da405 100644
--- a/drivers/input/touchscreen/touchit213.c
+++ b/drivers/input/touchscreen/touchit213.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Sahara TouchIT-213 serial touchscreen driver
*
@@ -9,11 +10,6 @@
* and Dan Streetman <ddstreet@ieee.org>
*/
-/*
- * 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.
- */
#include <linux/errno.h>
#include <linux/kernel.h>
diff --git a/drivers/input/touchscreen/touchright.c b/drivers/input/touchscreen/touchright.c
index 45c325c33f21..3cd58a13e44f 100644
--- a/drivers/input/touchscreen/touchright.c
+++ b/drivers/input/touchscreen/touchright.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Touchright serial touchscreen driver
*
@@ -8,11 +9,6 @@
* and Dan Streetman <ddstreet@ieee.org>
*/
-/*
- * 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.
- */
#include <linux/errno.h>
#include <linux/kernel.h>
diff --git a/drivers/input/touchscreen/touchwin.c b/drivers/input/touchscreen/touchwin.c
index 2ba6b4ca28cb..bde3c6ee3c60 100644
--- a/drivers/input/touchscreen/touchwin.c
+++ b/drivers/input/touchscreen/touchwin.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Touchwindow serial touchscreen driver
*
@@ -8,11 +9,6 @@
* and Dan Streetman <ddstreet@ieee.org>
*/
-/*
- * 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.
- */
/*
* 2005/02/19 Rick Koch:
diff --git a/drivers/input/touchscreen/tsc2007.h b/drivers/input/touchscreen/tsc2007.h
index 30fdf5b04a6b..91c60bf6dcaf 100644
--- a/drivers/input/touchscreen/tsc2007.h
+++ b/drivers/input/touchscreen/tsc2007.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2008 MtekVision Co., Ltd.
@@ -13,10 +14,6 @@
* Copyright (C) 2002 MontaVista Software
* Copyright (C) 2004 Texas Instruments
* Copyright (C) 2005 Dirk Behme
- *
- * 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.
*/
#ifndef _TSC2007_H
diff --git a/drivers/input/touchscreen/tsc2007_core.c b/drivers/input/touchscreen/tsc2007_core.c
index 8342e0c48a53..3b80abfc1eca 100644
--- a/drivers/input/touchscreen/tsc2007_core.c
+++ b/drivers/input/touchscreen/tsc2007_core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/input/touchscreen/tsc2007.c
*
@@ -14,10 +15,6 @@
* Copyright (C) 2002 MontaVista Software
* Copyright (C) 2004 Texas Instruments
* Copyright (C) 2005 Dirk Behme
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/input/touchscreen/tsc2007_iio.c b/drivers/input/touchscreen/tsc2007_iio.c
index e27a956f5f2b..3b0e3fa87d4c 100644
--- a/drivers/input/touchscreen/tsc2007_iio.c
+++ b/drivers/input/touchscreen/tsc2007_iio.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2016 Golden Delicious Comp. GmbH&Co. KG
* Nikolaus Schaller <hns@goldelico.com>
- *
- * 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.
*/
#include <linux/i2c.h>
diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c
index 1a86cbd9326f..807d39e18091 100644
--- a/drivers/input/touchscreen/ucb1400_ts.c
+++ b/drivers/input/touchscreen/ucb1400_ts.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Philips UCB1400 touchscreen driver
*
@@ -9,10 +10,6 @@
* If something doesn't work and it worked before spliting, e-mail me,
* dont bother Nicolas please ;-)
*
- * 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.
- *
* This code is heavily based on ucb1x00-*.c copyrighted by Russell King
* covering the UCB1100, UCB1200 and UCB1300.. Support for the UCB1400 has
* been made separate from ucb1x00-core/ucb1x00-ts on Russell's request.
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 83664db5221d..e15cdcd8cb3c 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -473,4 +473,15 @@ config HYPERV_IOMMU
Stub IOMMU driver to handle IRQs as to allow Hyper-V Linux
guests to run with x2APIC mode enabled.
+config VIRTIO_IOMMU
+ bool "Virtio IOMMU driver"
+ depends on VIRTIO=y
+ depends on ARM64
+ select IOMMU_API
+ select INTERVAL_TREE
+ help
+ Para-virtualised IOMMU driver with virtio.
+
+ Say Y here if you intend to run this kernel as a guest.
+
endif # IOMMU_SUPPORT
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 8c71a15e986b..f13f36ae1af6 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -33,3 +33,4 @@ obj-$(CONFIG_FSL_PAMU) += fsl_pamu.o fsl_pamu_domain.o
obj-$(CONFIG_S390_IOMMU) += s390-iommu.o
obj-$(CONFIG_QCOM_IOMMU) += qcom_iommu.o
obj-$(CONFIG_HYPERV_IOMMU) += hyperv-iommu.o
+obj-$(CONFIG_VIRTIO_IOMMU) += virtio-iommu.o
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index dce1d8d2e8a4..73740b969e62 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -619,9 +619,9 @@ retry:
pasid = ((event[0] >> 16) & 0xFFFF)
| ((event[1] << 6) & 0xF0000);
tag = event[1] & 0x03FF;
- dev_err(dev, "Event logged [INVALID_PPR_REQUEST device=%02x:%02x.%x pasid=0x%05x address=0x%llx flags=0x%04x]\n",
+ dev_err(dev, "Event logged [INVALID_PPR_REQUEST device=%02x:%02x.%x pasid=0x%05x address=0x%llx flags=0x%04x tag=0x%03x]\n",
PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
- pasid, address, flags);
+ pasid, address, flags, tag);
break;
default:
dev_err(dev, "Event logged [UNKNOWN event[0]=0x%08x event[1]=0x%08x event[2]=0x%08x event[3]=0x%08x\n",
@@ -1295,6 +1295,16 @@ static void domain_flush_complete(struct protection_domain *domain)
}
}
+/* Flush the not present cache if it exists */
+static void domain_flush_np_cache(struct protection_domain *domain,
+ dma_addr_t iova, size_t size)
+{
+ if (unlikely(amd_iommu_np_cache)) {
+ domain_flush_pages(domain, iova, size);
+ domain_flush_complete(domain);
+ }
+}
+
/*
* This function flushes the DTEs for all devices in domain
@@ -2377,10 +2387,7 @@ static dma_addr_t __map_single(struct device *dev,
}
address += offset;
- if (unlikely(amd_iommu_np_cache)) {
- domain_flush_pages(&dma_dom->domain, address, size);
- domain_flush_complete(&dma_dom->domain);
- }
+ domain_flush_np_cache(&dma_dom->domain, address, size);
out:
return address;
@@ -2559,6 +2566,9 @@ static int map_sg(struct device *dev, struct scatterlist *sglist,
s->dma_length = s->length;
}
+ if (s)
+ domain_flush_np_cache(domain, s->dma_address, s->dma_length);
+
return nelems;
out_unmap:
@@ -2597,7 +2607,7 @@ static void unmap_sg(struct device *dev, struct scatterlist *sglist,
struct protection_domain *domain;
struct dma_ops_domain *dma_dom;
unsigned long startaddr;
- int npages = 2;
+ int npages;
domain = get_domain(dev);
if (IS_ERR(domain))
@@ -3039,6 +3049,8 @@ static int amd_iommu_map(struct iommu_domain *dom, unsigned long iova,
ret = iommu_map_page(domain, iova, paddr, page_size, prot, GFP_KERNEL);
mutex_unlock(&domain->api_lock);
+ domain_flush_np_cache(domain, iova, page_size);
+
return ret;
}
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 07d84dbab564..eb104c719629 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -406,6 +406,9 @@ static void iommu_enable(struct amd_iommu *iommu)
static void iommu_disable(struct amd_iommu *iommu)
{
+ if (!iommu->mmio_base)
+ return;
+
/* Disable command buffer */
iommu_feature_disable(iommu, CONTROL_CMDBUF_EN);
@@ -2325,15 +2328,6 @@ static void __init free_iommu_resources(void)
amd_iommu_dev_table = NULL;
free_iommu_all();
-
-#ifdef CONFIG_GART_IOMMU
- /*
- * We failed to initialize the AMD IOMMU - try fallback to GART
- * if possible.
- */
- gart_iommu_init();
-
-#endif
}
/* SB IOAPIC is always on this device in AMD systems */
@@ -2625,8 +2619,6 @@ static int __init state_next(void)
init_state = ret ? IOMMU_INIT_ERROR : IOMMU_ACPI_FINISHED;
if (init_state == IOMMU_ACPI_FINISHED && amd_iommu_disabled) {
pr_info("AMD IOMMU disabled on kernel command-line\n");
- free_dma_resources();
- free_iommu_resources();
init_state = IOMMU_CMDLINE_DISABLED;
ret = -EINVAL;
}
@@ -2667,6 +2659,19 @@ static int __init state_next(void)
BUG();
}
+ if (ret) {
+ free_dma_resources();
+ if (!irq_remapping_enabled) {
+ disable_iommus();
+ free_iommu_resources();
+ } else {
+ struct amd_iommu *iommu;
+
+ uninit_device_table_dma();
+ for_each_iommu(iommu)
+ iommu_flush_all_caches(iommu);
+ }
+ }
return ret;
}
@@ -2740,17 +2745,15 @@ static int __init amd_iommu_init(void)
int ret;
ret = iommu_go_to_state(IOMMU_INITIALIZED);
- if (ret) {
- free_dma_resources();
- if (!irq_remapping_enabled) {
- disable_iommus();
- free_iommu_resources();
- } else {
- uninit_device_table_dma();
- for_each_iommu(iommu)
- iommu_flush_all_caches(iommu);
- }
+#ifdef CONFIG_GART_IOMMU
+ if (ret && list_empty(&amd_iommu_list)) {
+ /*
+ * We failed to initialize the AMD IOMMU - try fallback
+ * to GART if possible.
+ */
+ gart_iommu_init();
}
+#endif
for_each_iommu(iommu)
amd_iommu_debugfs_setup(iommu);
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index 4d5a694f02c2..a9a9fabd3968 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -192,6 +192,13 @@
#define Q_BASE_ADDR_MASK GENMASK_ULL(51, 5)
#define Q_BASE_LOG2SIZE GENMASK(4, 0)
+/* Ensure DMA allocations are naturally aligned */
+#ifdef CONFIG_CMA_ALIGNMENT
+#define Q_MAX_SZ_SHIFT (PAGE_SHIFT + CONFIG_CMA_ALIGNMENT)
+#else
+#define Q_MAX_SZ_SHIFT (PAGE_SHIFT + MAX_ORDER - 1)
+#endif
+
/*
* Stream table.
*
@@ -289,8 +296,9 @@
FIELD_GET(ARM64_TCR_##fld, tcr))
/* Command queue */
-#define CMDQ_ENT_DWORDS 2
-#define CMDQ_MAX_SZ_SHIFT 8
+#define CMDQ_ENT_SZ_SHIFT 4
+#define CMDQ_ENT_DWORDS ((1 << CMDQ_ENT_SZ_SHIFT) >> 3)
+#define CMDQ_MAX_SZ_SHIFT (Q_MAX_SZ_SHIFT - CMDQ_ENT_SZ_SHIFT)
#define CMDQ_CONS_ERR GENMASK(30, 24)
#define CMDQ_ERR_CERROR_NONE_IDX 0
@@ -336,14 +344,16 @@
#define CMDQ_SYNC_1_MSIADDR_MASK GENMASK_ULL(51, 2)
/* Event queue */
-#define EVTQ_ENT_DWORDS 4
-#define EVTQ_MAX_SZ_SHIFT 7
+#define EVTQ_ENT_SZ_SHIFT 5
+#define EVTQ_ENT_DWORDS ((1 << EVTQ_ENT_SZ_SHIFT) >> 3)
+#define EVTQ_MAX_SZ_SHIFT (Q_MAX_SZ_SHIFT - EVTQ_ENT_SZ_SHIFT)
#define EVTQ_0_ID GENMASK_ULL(7, 0)
/* PRI queue */
-#define PRIQ_ENT_DWORDS 2
-#define PRIQ_MAX_SZ_SHIFT 8
+#define PRIQ_ENT_SZ_SHIFT 4
+#define PRIQ_ENT_DWORDS ((1 << PRIQ_ENT_SZ_SHIFT) >> 3)
+#define PRIQ_MAX_SZ_SHIFT (Q_MAX_SZ_SHIFT - PRIQ_ENT_SZ_SHIFT)
#define PRIQ_0_SID GENMASK_ULL(31, 0)
#define PRIQ_0_SSID GENMASK_ULL(51, 32)
@@ -798,7 +808,7 @@ static int queue_remove_raw(struct arm_smmu_queue *q, u64 *ent)
/* High-level queue accessors */
static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent)
{
- memset(cmd, 0, CMDQ_ENT_DWORDS << 3);
+ memset(cmd, 0, 1 << CMDQ_ENT_SZ_SHIFT);
cmd[0] |= FIELD_PREP(CMDQ_0_OP, ent->opcode);
switch (ent->opcode) {
@@ -1785,13 +1795,11 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain)
.pgsize_bitmap = smmu->pgsize_bitmap,
.ias = ias,
.oas = oas,
+ .coherent_walk = smmu->features & ARM_SMMU_FEAT_COHERENCY,
.tlb = &arm_smmu_gather_ops,
.iommu_dev = smmu->dev,
};
- if (smmu->features & ARM_SMMU_FEAT_COHERENCY)
- pgtbl_cfg.quirks = IO_PGTABLE_QUIRK_NO_DMA;
-
if (smmu_domain->non_strict)
pgtbl_cfg.quirks |= IO_PGTABLE_QUIRK_NON_STRICT;
@@ -1884,9 +1892,13 @@ static int arm_smmu_enable_ats(struct arm_smmu_master *master)
static void arm_smmu_disable_ats(struct arm_smmu_master *master)
{
+ struct arm_smmu_cmdq_ent cmd;
+
if (!master->ats_enabled || !dev_is_pci(master->dev))
return;
+ arm_smmu_atc_inv_to_cmd(0, 0, 0, &cmd);
+ arm_smmu_atc_inv_master(master, &cmd);
pci_disable_ats(to_pci_dev(master->dev));
master->ats_enabled = false;
}
@@ -1906,7 +1918,6 @@ static void arm_smmu_detach_dev(struct arm_smmu_master *master)
master->domain = NULL;
arm_smmu_install_ste_for_dev(master);
- /* Disabling ATS invalidates all ATC entries */
arm_smmu_disable_ats(master);
}
@@ -2023,7 +2034,7 @@ arm_smmu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova)
static struct platform_driver arm_smmu_driver;
-static int arm_smmu_match_node(struct device *dev, void *data)
+static int arm_smmu_match_node(struct device *dev, const void *data)
{
return dev->fwnode == data;
}
@@ -2270,17 +2281,32 @@ static int arm_smmu_init_one_queue(struct arm_smmu_device *smmu,
struct arm_smmu_queue *q,
unsigned long prod_off,
unsigned long cons_off,
- size_t dwords)
+ size_t dwords, const char *name)
{
- size_t qsz = ((1 << q->max_n_shift) * dwords) << 3;
+ size_t qsz;
+
+ do {
+ qsz = ((1 << q->max_n_shift) * dwords) << 3;
+ q->base = dmam_alloc_coherent(smmu->dev, qsz, &q->base_dma,
+ GFP_KERNEL);
+ if (q->base || qsz < PAGE_SIZE)
+ break;
+
+ q->max_n_shift--;
+ } while (1);
- q->base = dmam_alloc_coherent(smmu->dev, qsz, &q->base_dma, GFP_KERNEL);
if (!q->base) {
- dev_err(smmu->dev, "failed to allocate queue (0x%zx bytes)\n",
- qsz);
+ dev_err(smmu->dev,
+ "failed to allocate queue (0x%zx bytes) for %s\n",
+ qsz, name);
return -ENOMEM;
}
+ if (!WARN_ON(q->base_dma & (qsz - 1))) {
+ dev_info(smmu->dev, "allocated %u entries for %s\n",
+ 1 << q->max_n_shift, name);
+ }
+
q->prod_reg = arm_smmu_page1_fixup(prod_off, smmu);
q->cons_reg = arm_smmu_page1_fixup(cons_off, smmu);
q->ent_dwords = dwords;
@@ -2300,13 +2326,15 @@ static int arm_smmu_init_queues(struct arm_smmu_device *smmu)
/* cmdq */
spin_lock_init(&smmu->cmdq.lock);
ret = arm_smmu_init_one_queue(smmu, &smmu->cmdq.q, ARM_SMMU_CMDQ_PROD,
- ARM_SMMU_CMDQ_CONS, CMDQ_ENT_DWORDS);
+ ARM_SMMU_CMDQ_CONS, CMDQ_ENT_DWORDS,
+ "cmdq");
if (ret)
return ret;
/* evtq */
ret = arm_smmu_init_one_queue(smmu, &smmu->evtq.q, ARM_SMMU_EVTQ_PROD,
- ARM_SMMU_EVTQ_CONS, EVTQ_ENT_DWORDS);
+ ARM_SMMU_EVTQ_CONS, EVTQ_ENT_DWORDS,
+ "evtq");
if (ret)
return ret;
@@ -2315,7 +2343,8 @@ static int arm_smmu_init_queues(struct arm_smmu_device *smmu)
return 0;
return arm_smmu_init_one_queue(smmu, &smmu->priq.q, ARM_SMMU_PRIQ_PROD,
- ARM_SMMU_PRIQ_CONS, PRIQ_ENT_DWORDS);
+ ARM_SMMU_PRIQ_CONS, PRIQ_ENT_DWORDS,
+ "priq");
}
static int arm_smmu_init_l1_strtab(struct arm_smmu_device *smmu)
@@ -2879,7 +2908,7 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
return -ENXIO;
}
- /* Queue sizes, capped at 4k */
+ /* Queue sizes, capped to ensure natural alignment */
smmu->cmdq.q.max_n_shift = min_t(u32, CMDQ_MAX_SZ_SHIFT,
FIELD_GET(IDR1_CMDQS, reg));
if (!smmu->cmdq.q.max_n_shift) {
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 586dd5a46d9f..64977c131ee6 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -892,13 +892,11 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
.pgsize_bitmap = smmu->pgsize_bitmap,
.ias = ias,
.oas = oas,
+ .coherent_walk = smmu->features & ARM_SMMU_FEAT_COHERENT_WALK,
.tlb = smmu_domain->tlb_ops,
.iommu_dev = smmu->dev,
};
- if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK)
- pgtbl_cfg.quirks = IO_PGTABLE_QUIRK_NO_DMA;
-
if (smmu_domain->non_strict)
pgtbl_cfg.quirks |= IO_PGTABLE_QUIRK_NON_STRICT;
@@ -1428,7 +1426,7 @@ static bool arm_smmu_capable(enum iommu_cap cap)
}
}
-static int arm_smmu_match_node(struct device *dev, void *data)
+static int arm_smmu_match_node(struct device *dev, const void *data)
{
return dev->fwnode == data;
}
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index 129c4badf9ae..a7f9c3edbcb2 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* A fairly generic DMA-API to IOMMU-API glue layer.
*
@@ -5,23 +6,13 @@
*
* based in part on arch/arm/mm/dma-mapping.c:
* Copyright (C) 2000-2004 Russell King
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/acpi_iort.h>
#include <linux/device.h>
+#include <linux/dma-contiguous.h>
#include <linux/dma-iommu.h>
+#include <linux/dma-noncoherent.h>
#include <linux/gfp.h>
#include <linux/huge_mm.h>
#include <linux/iommu.h>
@@ -78,11 +69,6 @@ static struct iommu_dma_cookie *cookie_alloc(enum iommu_dma_cookie_type type)
return cookie;
}
-int iommu_dma_init(void)
-{
- return iova_cache_get();
-}
-
/**
* iommu_get_dma_cookie - Acquire DMA-API resources for a domain
* @domain: IOMMU domain to prepare for DMA-API usage
@@ -240,8 +226,8 @@ resv_iova:
start = window->res->end - window->offset + 1;
/* If window is last entry */
if (window->node.next == &bridge->dma_ranges &&
- end != ~(dma_addr_t)0) {
- end = ~(dma_addr_t)0;
+ end != ~(phys_addr_t)0) {
+ end = ~(phys_addr_t)0;
goto resv_iova;
}
}
@@ -313,7 +299,7 @@ static void iommu_dma_flush_iotlb_all(struct iova_domain *iovad)
* to ensure it is an invalid IOVA. It is safe to reinitialise a domain, but
* any change which could make prior IOVAs invalid will fail.
*/
-int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base,
+static int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base,
u64 size, struct device *dev)
{
struct iommu_dma_cookie *cookie = domain->iova_cookie;
@@ -364,7 +350,6 @@ int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base,
return iova_reserve_iommu_regions(dev, domain);
}
-EXPORT_SYMBOL(iommu_dma_init_domain);
/**
* dma_info_to_prot - Translate DMA API directions and attributes to IOMMU API
@@ -375,7 +360,7 @@ EXPORT_SYMBOL(iommu_dma_init_domain);
*
* Return: corresponding IOMMU API page protection flags
*/
-int dma_info_to_prot(enum dma_data_direction dir, bool coherent,
+static int dma_info_to_prot(enum dma_data_direction dir, bool coherent,
unsigned long attrs)
{
int prot = coherent ? IOMMU_CACHE : 0;
@@ -452,9 +437,10 @@ static void iommu_dma_free_iova(struct iommu_dma_cookie *cookie,
size >> iova_shift(iovad));
}
-static void __iommu_dma_unmap(struct iommu_domain *domain, dma_addr_t dma_addr,
+static void __iommu_dma_unmap(struct device *dev, dma_addr_t dma_addr,
size_t size)
{
+ struct iommu_domain *domain = iommu_get_dma_domain(dev);
struct iommu_dma_cookie *cookie = domain->iova_cookie;
struct iova_domain *iovad = &cookie->iovad;
size_t iova_off = iova_offset(iovad, dma_addr);
@@ -468,6 +454,30 @@ static void __iommu_dma_unmap(struct iommu_domain *domain, dma_addr_t dma_addr,
iommu_dma_free_iova(cookie, dma_addr, size);
}
+static dma_addr_t __iommu_dma_map(struct device *dev, phys_addr_t phys,
+ size_t size, int prot)
+{
+ struct iommu_domain *domain = iommu_get_dma_domain(dev);
+ struct iommu_dma_cookie *cookie = domain->iova_cookie;
+ size_t iova_off = 0;
+ dma_addr_t iova;
+
+ if (cookie->type == IOMMU_DMA_IOVA_COOKIE) {
+ iova_off = iova_offset(&cookie->iovad, phys);
+ size = iova_align(&cookie->iovad, size + iova_off);
+ }
+
+ iova = iommu_dma_alloc_iova(domain, size, dma_get_mask(dev), dev);
+ if (!iova)
+ return DMA_MAPPING_ERROR;
+
+ if (iommu_map(domain, iova, phys - iova_off, size, prot)) {
+ iommu_dma_free_iova(cookie, iova, size);
+ return DMA_MAPPING_ERROR;
+ }
+ return iova + iova_off;
+}
+
static void __iommu_dma_free_pages(struct page **pages, int count)
{
while (count--)
@@ -533,55 +543,45 @@ static struct page **__iommu_dma_alloc_pages(struct device *dev,
return pages;
}
-/**
- * iommu_dma_free - Free a buffer allocated by iommu_dma_alloc()
- * @dev: Device which owns this buffer
- * @pages: Array of buffer pages as returned by iommu_dma_alloc()
- * @size: Size of buffer in bytes
- * @handle: DMA address of buffer
- *
- * Frees both the pages associated with the buffer, and the array
- * describing them
- */
-void iommu_dma_free(struct device *dev, struct page **pages, size_t size,
- dma_addr_t *handle)
+static struct page **__iommu_dma_get_pages(void *cpu_addr)
{
- __iommu_dma_unmap(iommu_get_dma_domain(dev), *handle, size);
- __iommu_dma_free_pages(pages, PAGE_ALIGN(size) >> PAGE_SHIFT);
- *handle = DMA_MAPPING_ERROR;
+ struct vm_struct *area = find_vm_area(cpu_addr);
+
+ if (!area || !area->pages)
+ return NULL;
+ return area->pages;
}
/**
- * iommu_dma_alloc - Allocate and map a buffer contiguous in IOVA space
+ * iommu_dma_alloc_remap - Allocate and map a buffer contiguous in IOVA space
* @dev: Device to allocate memory for. Must be a real device
* attached to an iommu_dma_domain
* @size: Size of buffer in bytes
+ * @dma_handle: Out argument for allocated DMA handle
* @gfp: Allocation flags
* @attrs: DMA attributes for this allocation
- * @prot: IOMMU mapping flags
- * @handle: Out argument for allocated DMA handle
- * @flush_page: Arch callback which must ensure PAGE_SIZE bytes from the
- * given VA/PA are visible to the given non-coherent device.
*
* If @size is less than PAGE_SIZE, then a full CPU page will be allocated,
* but an IOMMU which supports smaller pages might not map the whole thing.
*
- * Return: Array of struct page pointers describing the buffer,
- * or NULL on failure.
+ * Return: Mapped virtual address, or NULL on failure.
*/
-struct page **iommu_dma_alloc(struct device *dev, size_t size, gfp_t gfp,
- unsigned long attrs, int prot, dma_addr_t *handle,
- void (*flush_page)(struct device *, const void *, phys_addr_t))
+static void *iommu_dma_alloc_remap(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs)
{
struct iommu_domain *domain = iommu_get_dma_domain(dev);
struct iommu_dma_cookie *cookie = domain->iova_cookie;
struct iova_domain *iovad = &cookie->iovad;
+ bool coherent = dev_is_dma_coherent(dev);
+ int ioprot = dma_info_to_prot(DMA_BIDIRECTIONAL, coherent, attrs);
+ pgprot_t prot = arch_dma_mmap_pgprot(dev, PAGE_KERNEL, attrs);
+ unsigned int count, min_size, alloc_sizes = domain->pgsize_bitmap;
struct page **pages;
struct sg_table sgt;
dma_addr_t iova;
- unsigned int count, min_size, alloc_sizes = domain->pgsize_bitmap;
+ void *vaddr;
- *handle = DMA_MAPPING_ERROR;
+ *dma_handle = DMA_MAPPING_ERROR;
min_size = alloc_sizes & -alloc_sizes;
if (min_size < PAGE_SIZE) {
@@ -607,26 +607,29 @@ struct page **iommu_dma_alloc(struct device *dev, size_t size, gfp_t gfp,
if (sg_alloc_table_from_pages(&sgt, pages, count, 0, size, GFP_KERNEL))
goto out_free_iova;
- if (!(prot & IOMMU_CACHE)) {
- struct sg_mapping_iter miter;
- /*
- * The CPU-centric flushing implied by SG_MITER_TO_SG isn't
- * sufficient here, so skip it by using the "wrong" direction.
- */
- sg_miter_start(&miter, sgt.sgl, sgt.orig_nents, SG_MITER_FROM_SG);
- while (sg_miter_next(&miter))
- flush_page(dev, miter.addr, page_to_phys(miter.page));
- sg_miter_stop(&miter);
+ if (!(ioprot & IOMMU_CACHE)) {
+ struct scatterlist *sg;
+ int i;
+
+ for_each_sg(sgt.sgl, sg, sgt.orig_nents, i)
+ arch_dma_prep_coherent(sg_page(sg), sg->length);
}
- if (iommu_map_sg(domain, iova, sgt.sgl, sgt.orig_nents, prot)
+ if (iommu_map_sg(domain, iova, sgt.sgl, sgt.orig_nents, ioprot)
< size)
goto out_free_sg;
- *handle = iova;
+ vaddr = dma_common_pages_remap(pages, size, VM_USERMAP, prot,
+ __builtin_return_address(0));
+ if (!vaddr)
+ goto out_unmap;
+
+ *dma_handle = iova;
sg_free_table(&sgt);
- return pages;
+ return vaddr;
+out_unmap:
+ __iommu_dma_unmap(dev, iova, size);
out_free_sg:
sg_free_table(&sgt);
out_free_iova:
@@ -637,54 +640,94 @@ out_free_pages:
}
/**
- * iommu_dma_mmap - Map a buffer into provided user VMA
- * @pages: Array representing buffer from iommu_dma_alloc()
+ * __iommu_dma_mmap - Map a buffer into provided user VMA
+ * @pages: Array representing buffer from __iommu_dma_alloc()
* @size: Size of buffer in bytes
* @vma: VMA describing requested userspace mapping
*
* Maps the pages of the buffer in @pages into @vma. The caller is responsible
* for verifying the correct size and protection of @vma beforehand.
*/
-
-int iommu_dma_mmap(struct page **pages, size_t size, struct vm_area_struct *vma)
+static int __iommu_dma_mmap(struct page **pages, size_t size,
+ struct vm_area_struct *vma)
{
return vm_map_pages(vma, pages, PAGE_ALIGN(size) >> PAGE_SHIFT);
}
-static dma_addr_t __iommu_dma_map(struct device *dev, phys_addr_t phys,
- size_t size, int prot, struct iommu_domain *domain)
+static void iommu_dma_sync_single_for_cpu(struct device *dev,
+ dma_addr_t dma_handle, size_t size, enum dma_data_direction dir)
{
- struct iommu_dma_cookie *cookie = domain->iova_cookie;
- size_t iova_off = 0;
- dma_addr_t iova;
+ phys_addr_t phys;
- if (cookie->type == IOMMU_DMA_IOVA_COOKIE) {
- iova_off = iova_offset(&cookie->iovad, phys);
- size = iova_align(&cookie->iovad, size + iova_off);
- }
+ if (dev_is_dma_coherent(dev))
+ return;
- iova = iommu_dma_alloc_iova(domain, size, dma_get_mask(dev), dev);
- if (!iova)
- return DMA_MAPPING_ERROR;
+ phys = iommu_iova_to_phys(iommu_get_dma_domain(dev), dma_handle);
+ arch_sync_dma_for_cpu(dev, phys, size, dir);
+}
- if (iommu_map(domain, iova, phys - iova_off, size, prot)) {
- iommu_dma_free_iova(cookie, iova, size);
- return DMA_MAPPING_ERROR;
- }
- return iova + iova_off;
+static void iommu_dma_sync_single_for_device(struct device *dev,
+ dma_addr_t dma_handle, size_t size, enum dma_data_direction dir)
+{
+ phys_addr_t phys;
+
+ if (dev_is_dma_coherent(dev))
+ return;
+
+ phys = iommu_iova_to_phys(iommu_get_dma_domain(dev), dma_handle);
+ arch_sync_dma_for_device(dev, phys, size, dir);
+}
+
+static void iommu_dma_sync_sg_for_cpu(struct device *dev,
+ struct scatterlist *sgl, int nelems,
+ enum dma_data_direction dir)
+{
+ struct scatterlist *sg;
+ int i;
+
+ if (dev_is_dma_coherent(dev))
+ return;
+
+ for_each_sg(sgl, sg, nelems, i)
+ arch_sync_dma_for_cpu(dev, sg_phys(sg), sg->length, dir);
+}
+
+static void iommu_dma_sync_sg_for_device(struct device *dev,
+ struct scatterlist *sgl, int nelems,
+ enum dma_data_direction dir)
+{
+ struct scatterlist *sg;
+ int i;
+
+ if (dev_is_dma_coherent(dev))
+ return;
+
+ for_each_sg(sgl, sg, nelems, i)
+ arch_sync_dma_for_device(dev, sg_phys(sg), sg->length, dir);
}
-dma_addr_t iommu_dma_map_page(struct device *dev, struct page *page,
- unsigned long offset, size_t size, int prot)
+static dma_addr_t iommu_dma_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size, enum dma_data_direction dir,
+ unsigned long attrs)
{
- return __iommu_dma_map(dev, page_to_phys(page) + offset, size, prot,
- iommu_get_dma_domain(dev));
+ phys_addr_t phys = page_to_phys(page) + offset;
+ bool coherent = dev_is_dma_coherent(dev);
+ int prot = dma_info_to_prot(dir, coherent, attrs);
+ dma_addr_t dma_handle;
+
+ dma_handle =__iommu_dma_map(dev, phys, size, prot);
+ if (!coherent && !(attrs & DMA_ATTR_SKIP_CPU_SYNC) &&
+ dma_handle != DMA_MAPPING_ERROR)
+ arch_sync_dma_for_device(dev, phys, size, dir);
+ return dma_handle;
}
-void iommu_dma_unmap_page(struct device *dev, dma_addr_t handle, size_t size,
- enum dma_data_direction dir, unsigned long attrs)
+static void iommu_dma_unmap_page(struct device *dev, dma_addr_t dma_handle,
+ size_t size, enum dma_data_direction dir, unsigned long attrs)
{
- __iommu_dma_unmap(iommu_get_dma_domain(dev), handle, size);
+ if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
+ iommu_dma_sync_single_for_cpu(dev, dma_handle, size, dir);
+ __iommu_dma_unmap(dev, dma_handle, size);
}
/*
@@ -769,18 +812,22 @@ static void __invalidate_sg(struct scatterlist *sg, int nents)
* impedance-matching, to be able to hand off a suitably-aligned list,
* but still preserve the original offsets and sizes for the caller.
*/
-int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg,
- int nents, int prot)
+static int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir, unsigned long attrs)
{
struct iommu_domain *domain = iommu_get_dma_domain(dev);
struct iommu_dma_cookie *cookie = domain->iova_cookie;
struct iova_domain *iovad = &cookie->iovad;
struct scatterlist *s, *prev = NULL;
+ int prot = dma_info_to_prot(dir, dev_is_dma_coherent(dev), attrs);
dma_addr_t iova;
size_t iova_len = 0;
unsigned long mask = dma_get_seg_boundary(dev);
int i;
+ if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
+ iommu_dma_sync_sg_for_device(dev, sg, nents, dir);
+
/*
* Work out how much IOVA space we need, and align the segments to
* IOVA granules for the IOMMU driver to handle. With some clever
@@ -840,12 +887,16 @@ out_restore_sg:
return 0;
}
-void iommu_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
- enum dma_data_direction dir, unsigned long attrs)
+static void iommu_dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir, unsigned long attrs)
{
dma_addr_t start, end;
struct scatterlist *tmp;
int i;
+
+ if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
+ iommu_dma_sync_sg_for_cpu(dev, sg, nents, dir);
+
/*
* The scatterlist segments are mapped into a single
* contiguous IOVA allocation, so this is incredibly easy.
@@ -857,21 +908,225 @@ void iommu_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
sg = tmp;
}
end = sg_dma_address(sg) + sg_dma_len(sg);
- __iommu_dma_unmap(iommu_get_dma_domain(dev), start, end - start);
+ __iommu_dma_unmap(dev, start, end - start);
}
-dma_addr_t iommu_dma_map_resource(struct device *dev, phys_addr_t phys,
+static dma_addr_t iommu_dma_map_resource(struct device *dev, phys_addr_t phys,
size_t size, enum dma_data_direction dir, unsigned long attrs)
{
return __iommu_dma_map(dev, phys, size,
- dma_info_to_prot(dir, false, attrs) | IOMMU_MMIO,
- iommu_get_dma_domain(dev));
+ dma_info_to_prot(dir, false, attrs) | IOMMU_MMIO);
}
-void iommu_dma_unmap_resource(struct device *dev, dma_addr_t handle,
+static void iommu_dma_unmap_resource(struct device *dev, dma_addr_t handle,
size_t size, enum dma_data_direction dir, unsigned long attrs)
{
- __iommu_dma_unmap(iommu_get_dma_domain(dev), handle, size);
+ __iommu_dma_unmap(dev, handle, size);
+}
+
+static void __iommu_dma_free(struct device *dev, size_t size, void *cpu_addr)
+{
+ size_t alloc_size = PAGE_ALIGN(size);
+ int count = alloc_size >> PAGE_SHIFT;
+ struct page *page = NULL, **pages = NULL;
+
+ /* Non-coherent atomic allocation? Easy */
+ if (IS_ENABLED(CONFIG_DMA_DIRECT_REMAP) &&
+ dma_free_from_pool(cpu_addr, alloc_size))
+ return;
+
+ if (IS_ENABLED(CONFIG_DMA_REMAP) && is_vmalloc_addr(cpu_addr)) {
+ /*
+ * If it the address is remapped, then it's either non-coherent
+ * or highmem CMA, or an iommu_dma_alloc_remap() construction.
+ */
+ pages = __iommu_dma_get_pages(cpu_addr);
+ if (!pages)
+ page = vmalloc_to_page(cpu_addr);
+ dma_common_free_remap(cpu_addr, alloc_size, VM_USERMAP);
+ } else {
+ /* Lowmem means a coherent atomic or CMA allocation */
+ page = virt_to_page(cpu_addr);
+ }
+
+ if (pages)
+ __iommu_dma_free_pages(pages, count);
+ if (page)
+ dma_free_contiguous(dev, page, alloc_size);
+}
+
+static void iommu_dma_free(struct device *dev, size_t size, void *cpu_addr,
+ dma_addr_t handle, unsigned long attrs)
+{
+ __iommu_dma_unmap(dev, handle, size);
+ __iommu_dma_free(dev, size, cpu_addr);
+}
+
+static void *iommu_dma_alloc_pages(struct device *dev, size_t size,
+ struct page **pagep, gfp_t gfp, unsigned long attrs)
+{
+ bool coherent = dev_is_dma_coherent(dev);
+ size_t alloc_size = PAGE_ALIGN(size);
+ struct page *page = NULL;
+ void *cpu_addr;
+
+ page = dma_alloc_contiguous(dev, alloc_size, gfp);
+ if (!page)
+ return NULL;
+
+ if (IS_ENABLED(CONFIG_DMA_REMAP) && (!coherent || PageHighMem(page))) {
+ pgprot_t prot = arch_dma_mmap_pgprot(dev, PAGE_KERNEL, attrs);
+
+ cpu_addr = dma_common_contiguous_remap(page, alloc_size,
+ VM_USERMAP, prot, __builtin_return_address(0));
+ if (!cpu_addr)
+ goto out_free_pages;
+
+ if (!coherent)
+ arch_dma_prep_coherent(page, size);
+ } else {
+ cpu_addr = page_address(page);
+ }
+
+ *pagep = page;
+ memset(cpu_addr, 0, alloc_size);
+ return cpu_addr;
+out_free_pages:
+ dma_free_contiguous(dev, page, alloc_size);
+ return NULL;
+}
+
+static void *iommu_dma_alloc(struct device *dev, size_t size,
+ dma_addr_t *handle, gfp_t gfp, unsigned long attrs)
+{
+ bool coherent = dev_is_dma_coherent(dev);
+ int ioprot = dma_info_to_prot(DMA_BIDIRECTIONAL, coherent, attrs);
+ struct page *page = NULL;
+ void *cpu_addr;
+
+ gfp |= __GFP_ZERO;
+
+ if (IS_ENABLED(CONFIG_DMA_REMAP) && gfpflags_allow_blocking(gfp) &&
+ !(attrs & DMA_ATTR_FORCE_CONTIGUOUS))
+ return iommu_dma_alloc_remap(dev, size, handle, gfp, attrs);
+
+ if (IS_ENABLED(CONFIG_DMA_DIRECT_REMAP) &&
+ !gfpflags_allow_blocking(gfp) && !coherent)
+ cpu_addr = dma_alloc_from_pool(PAGE_ALIGN(size), &page, gfp);
+ else
+ cpu_addr = iommu_dma_alloc_pages(dev, size, &page, gfp, attrs);
+ if (!cpu_addr)
+ return NULL;
+
+ *handle = __iommu_dma_map(dev, page_to_phys(page), size, ioprot);
+ if (*handle == DMA_MAPPING_ERROR) {
+ __iommu_dma_free(dev, size, cpu_addr);
+ return NULL;
+ }
+
+ return cpu_addr;
+}
+
+static int iommu_dma_mmap(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size,
+ unsigned long attrs)
+{
+ unsigned long nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
+ unsigned long pfn, off = vma->vm_pgoff;
+ int ret;
+
+ vma->vm_page_prot = arch_dma_mmap_pgprot(dev, vma->vm_page_prot, attrs);
+
+ if (dma_mmap_from_dev_coherent(dev, vma, cpu_addr, size, &ret))
+ return ret;
+
+ if (off >= nr_pages || vma_pages(vma) > nr_pages - off)
+ return -ENXIO;
+
+ if (IS_ENABLED(CONFIG_DMA_REMAP) && is_vmalloc_addr(cpu_addr)) {
+ struct page **pages = __iommu_dma_get_pages(cpu_addr);
+
+ if (pages)
+ return __iommu_dma_mmap(pages, size, vma);
+ pfn = vmalloc_to_pfn(cpu_addr);
+ } else {
+ pfn = page_to_pfn(virt_to_page(cpu_addr));
+ }
+
+ return remap_pfn_range(vma, vma->vm_start, pfn + off,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot);
+}
+
+static int iommu_dma_get_sgtable(struct device *dev, struct sg_table *sgt,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size,
+ unsigned long attrs)
+{
+ struct page *page;
+ int ret;
+
+ if (IS_ENABLED(CONFIG_DMA_REMAP) && is_vmalloc_addr(cpu_addr)) {
+ struct page **pages = __iommu_dma_get_pages(cpu_addr);
+
+ if (pages) {
+ return sg_alloc_table_from_pages(sgt, pages,
+ PAGE_ALIGN(size) >> PAGE_SHIFT,
+ 0, size, GFP_KERNEL);
+ }
+
+ page = vmalloc_to_page(cpu_addr);
+ } else {
+ page = virt_to_page(cpu_addr);
+ }
+
+ ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
+ if (!ret)
+ sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0);
+ return ret;
+}
+
+static const struct dma_map_ops iommu_dma_ops = {
+ .alloc = iommu_dma_alloc,
+ .free = iommu_dma_free,
+ .mmap = iommu_dma_mmap,
+ .get_sgtable = iommu_dma_get_sgtable,
+ .map_page = iommu_dma_map_page,
+ .unmap_page = iommu_dma_unmap_page,
+ .map_sg = iommu_dma_map_sg,
+ .unmap_sg = iommu_dma_unmap_sg,
+ .sync_single_for_cpu = iommu_dma_sync_single_for_cpu,
+ .sync_single_for_device = iommu_dma_sync_single_for_device,
+ .sync_sg_for_cpu = iommu_dma_sync_sg_for_cpu,
+ .sync_sg_for_device = iommu_dma_sync_sg_for_device,
+ .map_resource = iommu_dma_map_resource,
+ .unmap_resource = iommu_dma_unmap_resource,
+};
+
+/*
+ * The IOMMU core code allocates the default DMA domain, which the underlying
+ * IOMMU driver needs to support via the dma-iommu layer.
+ */
+void iommu_setup_dma_ops(struct device *dev, u64 dma_base, u64 size)
+{
+ struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
+
+ if (!domain)
+ goto out_err;
+
+ /*
+ * The IOMMU core code allocates the default DMA domain, which the
+ * underlying IOMMU driver needs to support via the dma-iommu layer.
+ */
+ if (domain->type == IOMMU_DOMAIN_DMA) {
+ if (iommu_dma_init_domain(domain, dma_base, size, dev))
+ goto out_err;
+ dev->dma_ops = &iommu_dma_ops;
+ }
+
+ return;
+out_err:
+ pr_warn("Failed to set up IOMMU for device %s; retaining platform DMA ops\n",
+ dev_name(dev));
}
static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev,
@@ -892,7 +1147,7 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev,
if (!msi_page)
return NULL;
- iova = __iommu_dma_map(dev, msi_addr, size, prot, domain);
+ iova = __iommu_dma_map(dev, msi_addr, size, prot);
if (iova == DMA_MAPPING_ERROR)
goto out_free_page;
@@ -954,3 +1209,9 @@ void iommu_dma_compose_msi_msg(struct msi_desc *desc,
msg->address_lo &= cookie_msi_granule(domain->iova_cookie) - 1;
msg->address_lo += lower_32_bits(msi_page->iova);
}
+
+static int iommu_dma_init(void)
+{
+ return iova_cache_get();
+}
+arch_initcall(iommu_dma_init);
diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 05c6bc099d62..b0c1e5f9daae 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2011,2016 Samsung Electronics Co., Ltd.
* http://www.samsung.com
- *
- * 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.
*/
#ifdef CONFIG_EXYNOS_IOMMU_DEBUG
diff --git a/drivers/iommu/intel-iommu-debugfs.c b/drivers/iommu/intel-iommu-debugfs.c
index 7fabf9b1c2dc..73a552914455 100644
--- a/drivers/iommu/intel-iommu-debugfs.c
+++ b/drivers/iommu/intel-iommu-debugfs.c
@@ -14,6 +14,17 @@
#include <asm/irq_remapping.h>
+#include "intel-pasid.h"
+
+struct tbl_walk {
+ u16 bus;
+ u16 devfn;
+ u32 pasid;
+ struct root_entry *rt_entry;
+ struct context_entry *ctx_entry;
+ struct pasid_entry *pasid_tbl_entry;
+};
+
struct iommu_regset {
int offset;
const char *regs;
@@ -131,16 +142,86 @@ out:
}
DEFINE_SHOW_ATTRIBUTE(iommu_regset);
-static void ctx_tbl_entry_show(struct seq_file *m, struct intel_iommu *iommu,
- int bus)
+static inline void print_tbl_walk(struct seq_file *m)
{
- struct context_entry *context;
- int devfn;
+ struct tbl_walk *tbl_wlk = m->private;
+
+ seq_printf(m, "%02x:%02x.%x\t0x%016llx:0x%016llx\t0x%016llx:0x%016llx\t",
+ tbl_wlk->bus, PCI_SLOT(tbl_wlk->devfn),
+ PCI_FUNC(tbl_wlk->devfn), tbl_wlk->rt_entry->hi,
+ tbl_wlk->rt_entry->lo, tbl_wlk->ctx_entry->hi,
+ tbl_wlk->ctx_entry->lo);
+
+ /*
+ * A legacy mode DMAR doesn't support PASID, hence default it to -1
+ * indicating that it's invalid. Also, default all PASID related fields
+ * to 0.
+ */
+ if (!tbl_wlk->pasid_tbl_entry)
+ seq_printf(m, "%-6d\t0x%016llx:0x%016llx:0x%016llx\n", -1,
+ (u64)0, (u64)0, (u64)0);
+ else
+ seq_printf(m, "%-6d\t0x%016llx:0x%016llx:0x%016llx\n",
+ tbl_wlk->pasid, tbl_wlk->pasid_tbl_entry->val[0],
+ tbl_wlk->pasid_tbl_entry->val[1],
+ tbl_wlk->pasid_tbl_entry->val[2]);
+}
- seq_printf(m, " Context Table Entries for Bus: %d\n", bus);
- seq_puts(m, " Entry\tB:D.F\tHigh\tLow\n");
+static void pasid_tbl_walk(struct seq_file *m, struct pasid_entry *tbl_entry,
+ u16 dir_idx)
+{
+ struct tbl_walk *tbl_wlk = m->private;
+ u8 tbl_idx;
+
+ for (tbl_idx = 0; tbl_idx < PASID_TBL_ENTRIES; tbl_idx++) {
+ if (pasid_pte_is_present(tbl_entry)) {
+ tbl_wlk->pasid_tbl_entry = tbl_entry;
+ tbl_wlk->pasid = (dir_idx << PASID_PDE_SHIFT) + tbl_idx;
+ print_tbl_walk(m);
+ }
+
+ tbl_entry++;
+ }
+}
+
+static void pasid_dir_walk(struct seq_file *m, u64 pasid_dir_ptr,
+ u16 pasid_dir_size)
+{
+ struct pasid_dir_entry *dir_entry = phys_to_virt(pasid_dir_ptr);
+ struct pasid_entry *pasid_tbl;
+ u16 dir_idx;
+
+ for (dir_idx = 0; dir_idx < pasid_dir_size; dir_idx++) {
+ pasid_tbl = get_pasid_table_from_pde(dir_entry);
+ if (pasid_tbl)
+ pasid_tbl_walk(m, pasid_tbl, dir_idx);
+
+ dir_entry++;
+ }
+}
+
+static void ctx_tbl_walk(struct seq_file *m, struct intel_iommu *iommu, u16 bus)
+{
+ struct context_entry *context;
+ u16 devfn, pasid_dir_size;
+ u64 pasid_dir_ptr;
for (devfn = 0; devfn < 256; devfn++) {
+ struct tbl_walk tbl_wlk = {0};
+
+ /*
+ * Scalable mode root entry points to upper scalable mode
+ * context table and lower scalable mode context table. Each
+ * scalable mode context table has 128 context entries where as
+ * legacy mode context table has 256 context entries. So in
+ * scalable mode, the context entries for former 128 devices are
+ * in the lower scalable mode context table, while the latter
+ * 128 devices are in the upper scalable mode context table.
+ * In scalable mode, when devfn > 127, iommu_context_addr()
+ * automatically refers to upper scalable mode context table and
+ * hence the caller doesn't have to worry about differences
+ * between scalable mode and non scalable mode.
+ */
context = iommu_context_addr(iommu, bus, devfn, 0);
if (!context)
return;
@@ -148,33 +229,41 @@ static void ctx_tbl_entry_show(struct seq_file *m, struct intel_iommu *iommu,
if (!context_present(context))
continue;
- seq_printf(m, " %-5d\t%02x:%02x.%x\t%-6llx\t%llx\n", devfn,
- bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
- context[0].hi, context[0].lo);
+ tbl_wlk.bus = bus;
+ tbl_wlk.devfn = devfn;
+ tbl_wlk.rt_entry = &iommu->root_entry[bus];
+ tbl_wlk.ctx_entry = context;
+ m->private = &tbl_wlk;
+
+ if (pasid_supported(iommu) && is_pasid_enabled(context)) {
+ pasid_dir_ptr = context->lo & VTD_PAGE_MASK;
+ pasid_dir_size = get_pasid_dir_size(context);
+ pasid_dir_walk(m, pasid_dir_ptr, pasid_dir_size);
+ continue;
+ }
+
+ print_tbl_walk(m);
}
}
-static void root_tbl_entry_show(struct seq_file *m, struct intel_iommu *iommu)
+static void root_tbl_walk(struct seq_file *m, struct intel_iommu *iommu)
{
unsigned long flags;
- int bus;
+ u16 bus;
spin_lock_irqsave(&iommu->lock, flags);
- seq_printf(m, "IOMMU %s: Root Table Address:%llx\n", iommu->name,
+ seq_printf(m, "IOMMU %s: Root Table Address: 0x%llx\n", iommu->name,
(u64)virt_to_phys(iommu->root_entry));
- seq_puts(m, "Root Table Entries:\n");
+ seq_puts(m, "B.D.F\tRoot_entry\t\t\t\tContext_entry\t\t\t\tPASID\tPASID_table_entry\n");
- for (bus = 0; bus < 256; bus++) {
- if (!(iommu->root_entry[bus].lo & 1))
- continue;
+ /*
+ * No need to check if the root entry is present or not because
+ * iommu_context_addr() performs the same check before returning
+ * context entry.
+ */
+ for (bus = 0; bus < 256; bus++)
+ ctx_tbl_walk(m, iommu, bus);
- seq_printf(m, " Bus: %d H: %llx L: %llx\n", bus,
- iommu->root_entry[bus].hi,
- iommu->root_entry[bus].lo);
-
- ctx_tbl_entry_show(m, iommu, bus);
- seq_putc(m, '\n');
- }
spin_unlock_irqrestore(&iommu->lock, flags);
}
@@ -185,7 +274,7 @@ static int dmar_translation_struct_show(struct seq_file *m, void *unused)
rcu_read_lock();
for_each_active_iommu(iommu, drhd) {
- root_tbl_entry_show(m, iommu);
+ root_tbl_walk(m, iommu);
seq_putc(m, '\n');
}
rcu_read_unlock();
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 56297298d6ee..ac4172c02244 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -294,14 +294,16 @@ static inline void context_clear_entry(struct context_entry *context)
static struct dmar_domain *si_domain;
static int hw_pass_through = 1;
+/* si_domain contains mulitple devices */
+#define DOMAIN_FLAG_STATIC_IDENTITY BIT(0)
+
/*
- * Domain represents a virtual machine, more than one devices
- * across iommus may be owned in one domain, e.g. kvm guest.
+ * This is a DMA domain allocated through the iommu domain allocation
+ * interface. But one or more devices belonging to this domain have
+ * been chosen to use a private domain. We should avoid to use the
+ * map/unmap/iova_to_phys APIs on it.
*/
-#define DOMAIN_FLAG_VIRTUAL_MACHINE (1 << 0)
-
-/* si_domain contains mulitple devices */
-#define DOMAIN_FLAG_STATIC_IDENTITY (1 << 1)
+#define DOMAIN_FLAG_LOSE_CHILDREN BIT(1)
#define for_each_domain_iommu(idx, domain) \
for (idx = 0; idx < g_num_of_iommus; idx++) \
@@ -314,7 +316,6 @@ struct dmar_rmrr_unit {
u64 end_address; /* reserved end address */
struct dmar_dev_scope *devices; /* target devices */
int devices_cnt; /* target device count */
- struct iommu_resv_region *resv; /* reserved region handle */
};
struct dmar_atsr_unit {
@@ -342,6 +343,9 @@ static void domain_context_clear(struct intel_iommu *iommu,
struct device *dev);
static int domain_detach_iommu(struct dmar_domain *domain,
struct intel_iommu *iommu);
+static bool device_is_rmrr_locked(struct device *dev);
+static int intel_iommu_attach_device(struct iommu_domain *domain,
+ struct device *dev);
#ifdef CONFIG_INTEL_IOMMU_DEFAULT_ON
int dmar_disabled = 0;
@@ -349,6 +353,7 @@ int dmar_disabled = 0;
int dmar_disabled = 1;
#endif /*CONFIG_INTEL_IOMMU_DEFAULT_ON*/
+int intel_iommu_sm;
int intel_iommu_enabled = 0;
EXPORT_SYMBOL_GPL(intel_iommu_enabled);
@@ -356,21 +361,17 @@ static int dmar_map_gfx = 1;
static int dmar_forcedac;
static int intel_iommu_strict;
static int intel_iommu_superpage = 1;
-static int intel_iommu_sm;
static int iommu_identity_mapping;
#define IDENTMAP_ALL 1
#define IDENTMAP_GFX 2
#define IDENTMAP_AZALIA 4
-#define sm_supported(iommu) (intel_iommu_sm && ecap_smts((iommu)->ecap))
-#define pasid_supported(iommu) (sm_supported(iommu) && \
- ecap_pasid((iommu)->ecap))
-
int intel_iommu_gfx_mapped;
EXPORT_SYMBOL_GPL(intel_iommu_gfx_mapped);
#define DUMMY_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-1))
+#define DEFER_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-2))
static DEFINE_SPINLOCK(device_domain_lock);
static LIST_HEAD(device_domain_list);
@@ -535,22 +536,11 @@ static inline void free_devinfo_mem(void *vaddr)
kmem_cache_free(iommu_devinfo_cache, vaddr);
}
-static inline int domain_type_is_vm(struct dmar_domain *domain)
-{
- return domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE;
-}
-
static inline int domain_type_is_si(struct dmar_domain *domain)
{
return domain->flags & DOMAIN_FLAG_STATIC_IDENTITY;
}
-static inline int domain_type_is_vm_or_si(struct dmar_domain *domain)
-{
- return domain->flags & (DOMAIN_FLAG_VIRTUAL_MACHINE |
- DOMAIN_FLAG_STATIC_IDENTITY);
-}
-
static inline int domain_pfn_supported(struct dmar_domain *domain,
unsigned long pfn)
{
@@ -598,7 +588,9 @@ struct intel_iommu *domain_get_iommu(struct dmar_domain *domain)
int iommu_id;
/* si_domain and vm domain should not get here. */
- BUG_ON(domain_type_is_vm_or_si(domain));
+ if (WARN_ON(domain->domain.type != IOMMU_DOMAIN_DMA))
+ return NULL;
+
for_each_domain_iommu(iommu_id, domain)
break;
@@ -729,12 +721,39 @@ static int iommu_dummy(struct device *dev)
return dev->archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO;
}
+/**
+ * is_downstream_to_pci_bridge - test if a device belongs to the PCI
+ * sub-hierarchy of a candidate PCI-PCI bridge
+ * @dev: candidate PCI device belonging to @bridge PCI sub-hierarchy
+ * @bridge: the candidate PCI-PCI bridge
+ *
+ * Return: true if @dev belongs to @bridge PCI sub-hierarchy, else false.
+ */
+static bool
+is_downstream_to_pci_bridge(struct device *dev, struct device *bridge)
+{
+ struct pci_dev *pdev, *pbridge;
+
+ if (!dev_is_pci(dev) || !dev_is_pci(bridge))
+ return false;
+
+ pdev = to_pci_dev(dev);
+ pbridge = to_pci_dev(bridge);
+
+ if (pbridge->subordinate &&
+ pbridge->subordinate->number <= pdev->bus->number &&
+ pbridge->subordinate->busn_res.end >= pdev->bus->number)
+ return true;
+
+ return false;
+}
+
static struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn)
{
struct dmar_drhd_unit *drhd = NULL;
struct intel_iommu *iommu;
struct device *tmp;
- struct pci_dev *ptmp, *pdev = NULL;
+ struct pci_dev *pdev = NULL;
u16 segment = 0;
int i;
@@ -780,13 +799,7 @@ static struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devf
goto out;
}
- if (!pdev || !dev_is_pci(tmp))
- continue;
-
- ptmp = to_pci_dev(tmp);
- if (ptmp->subordinate &&
- ptmp->subordinate->number <= pdev->bus->number &&
- ptmp->subordinate->busn_res.end >= pdev->bus->number)
+ if (is_downstream_to_pci_bridge(dev, tmp))
goto got_pdev;
}
@@ -908,7 +921,6 @@ static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
return pte;
}
-
/* return address's pte at specific level */
static struct dma_pte *dma_pfn_level_pte(struct dmar_domain *domain,
unsigned long pfn,
@@ -1577,7 +1589,6 @@ static void iommu_disable_translation(struct intel_iommu *iommu)
raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
}
-
static int iommu_init_domains(struct intel_iommu *iommu)
{
u32 ndomains, nlongs;
@@ -1615,8 +1626,6 @@ static int iommu_init_domains(struct intel_iommu *iommu)
return -ENOMEM;
}
-
-
/*
* If Caching mode is set, then invalid translations are tagged
* with domain-id 0, hence we need to pre-allocate it. We also
@@ -1646,32 +1655,15 @@ static void disable_dmar_iommu(struct intel_iommu *iommu)
if (!iommu->domains || !iommu->domain_ids)
return;
-again:
spin_lock_irqsave(&device_domain_lock, flags);
list_for_each_entry_safe(info, tmp, &device_domain_list, global) {
- struct dmar_domain *domain;
-
if (info->iommu != iommu)
continue;
if (!info->dev || !info->domain)
continue;
- domain = info->domain;
-
__dmar_remove_one_dev_info(info);
-
- if (!domain_type_is_vm_or_si(domain)) {
- /*
- * The domain_exit() function can't be called under
- * device_domain_lock, as it takes this lock itself.
- * So release the lock here and re-run the loop
- * afterwards.
- */
- spin_unlock_irqrestore(&device_domain_lock, flags);
- domain_exit(domain);
- goto again;
- }
}
spin_unlock_irqrestore(&device_domain_lock, flags);
@@ -1841,71 +1833,12 @@ static inline int guestwidth_to_adjustwidth(int gaw)
return agaw;
}
-static int domain_init(struct dmar_domain *domain, struct intel_iommu *iommu,
- int guest_width)
-{
- int adjust_width, agaw;
- unsigned long sagaw;
- int err;
-
- init_iova_domain(&domain->iovad, VTD_PAGE_SIZE, IOVA_START_PFN);
-
- err = init_iova_flush_queue(&domain->iovad,
- iommu_flush_iova, iova_entry_free);
- if (err)
- return err;
-
- domain_reserve_special_ranges(domain);
-
- /* calculate AGAW */
- if (guest_width > cap_mgaw(iommu->cap))
- guest_width = cap_mgaw(iommu->cap);
- domain->gaw = guest_width;
- adjust_width = guestwidth_to_adjustwidth(guest_width);
- agaw = width_to_agaw(adjust_width);
- sagaw = cap_sagaw(iommu->cap);
- if (!test_bit(agaw, &sagaw)) {
- /* hardware doesn't support it, choose a bigger one */
- pr_debug("Hardware doesn't support agaw %d\n", agaw);
- agaw = find_next_bit(&sagaw, 5, agaw);
- if (agaw >= 5)
- return -ENODEV;
- }
- domain->agaw = agaw;
-
- if (ecap_coherent(iommu->ecap))
- domain->iommu_coherency = 1;
- else
- domain->iommu_coherency = 0;
-
- if (ecap_sc_support(iommu->ecap))
- domain->iommu_snooping = 1;
- else
- domain->iommu_snooping = 0;
-
- if (intel_iommu_superpage)
- domain->iommu_superpage = fls(cap_super_page_val(iommu->cap));
- else
- domain->iommu_superpage = 0;
-
- domain->nid = iommu->node;
-
- /* always allocate the top pgd */
- domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
- if (!domain->pgd)
- return -ENOMEM;
- __iommu_flush_cache(iommu, domain->pgd, PAGE_SIZE);
- return 0;
-}
-
static void domain_exit(struct dmar_domain *domain)
{
struct page *freelist;
/* Remove associated devices and clear attached or cached domains */
- rcu_read_lock();
domain_remove_dev_info(domain);
- rcu_read_unlock();
/* destroy iovas */
put_iova_domain(&domain->iovad);
@@ -2336,7 +2269,7 @@ static int domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
struct scatterlist *sg, unsigned long phys_pfn,
unsigned long nr_pages, int prot)
{
- int ret;
+ int iommu_id, ret;
struct intel_iommu *iommu;
/* Do the real mapping first */
@@ -2344,18 +2277,8 @@ static int domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
if (ret)
return ret;
- /* Notify about the new mapping */
- if (domain_type_is_vm(domain)) {
- /* VM typed domains can have more than one IOMMUs */
- int iommu_id;
-
- for_each_domain_iommu(iommu_id, domain) {
- iommu = g_iommus[iommu_id];
- __mapping_notify_one(iommu, domain, iov_pfn, nr_pages);
- }
- } else {
- /* General domains only have one IOMMU */
- iommu = domain_get_iommu(domain);
+ for_each_domain_iommu(iommu_id, domain) {
+ iommu = g_iommus[iommu_id];
__mapping_notify_one(iommu, domain, iov_pfn, nr_pages);
}
@@ -2435,8 +2358,18 @@ static struct dmar_domain *find_domain(struct device *dev)
{
struct device_domain_info *info;
+ if (unlikely(dev->archdata.iommu == DEFER_DEVICE_DOMAIN_INFO)) {
+ struct iommu_domain *domain;
+
+ dev->archdata.iommu = NULL;
+ domain = iommu_get_domain_for_dev(dev);
+ if (domain)
+ intel_iommu_attach_device(domain, dev);
+ }
+
/* No lock here, assumes no domain exit in normal case */
info = dev->archdata.iommu;
+
if (likely(info))
return info->domain;
return NULL;
@@ -2504,7 +2437,6 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu,
}
}
- spin_lock(&iommu->lock);
spin_lock_irqsave(&device_domain_lock, flags);
if (dev)
found = find_domain(dev);
@@ -2520,16 +2452,17 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu,
if (found) {
spin_unlock_irqrestore(&device_domain_lock, flags);
- spin_unlock(&iommu->lock);
free_devinfo_mem(info);
/* Caller must free the original domain */
return found;
}
+ spin_lock(&iommu->lock);
ret = domain_attach_iommu(domain, iommu);
+ spin_unlock(&iommu->lock);
+
if (ret) {
spin_unlock_irqrestore(&device_domain_lock, flags);
- spin_unlock(&iommu->lock);
free_devinfo_mem(info);
return NULL;
}
@@ -2539,7 +2472,6 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu,
if (dev)
dev->archdata.iommu = info;
spin_unlock_irqrestore(&device_domain_lock, flags);
- spin_unlock(&iommu->lock);
/* PASID table is mandatory for a PCI device in scalable mode. */
if (dev && dev_is_pci(dev) && sm_supported(iommu)) {
@@ -2581,6 +2513,31 @@ static int get_last_alias(struct pci_dev *pdev, u16 alias, void *opaque)
return 0;
}
+static int domain_init(struct dmar_domain *domain, int guest_width)
+{
+ int adjust_width;
+
+ init_iova_domain(&domain->iovad, VTD_PAGE_SIZE, IOVA_START_PFN);
+ domain_reserve_special_ranges(domain);
+
+ /* calculate AGAW */
+ domain->gaw = guest_width;
+ adjust_width = guestwidth_to_adjustwidth(guest_width);
+ domain->agaw = width_to_agaw(adjust_width);
+
+ domain->iommu_coherency = 0;
+ domain->iommu_snooping = 0;
+ domain->iommu_superpage = 0;
+ domain->max_addr = 0;
+
+ /* always allocate the top pgd */
+ domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
+ if (!domain->pgd)
+ return -ENOMEM;
+ domain_flush_cache(domain, domain->pgd, PAGE_SIZE);
+ return 0;
+}
+
static struct dmar_domain *find_or_alloc_domain(struct device *dev, int gaw)
{
struct device_domain_info *info;
@@ -2618,13 +2575,20 @@ static struct dmar_domain *find_or_alloc_domain(struct device *dev, int gaw)
domain = alloc_domain(0);
if (!domain)
return NULL;
- if (domain_init(domain, iommu, gaw)) {
+
+ if (domain_init(domain, gaw)) {
domain_exit(domain);
return NULL;
}
-out:
+ if (init_iova_flush_queue(&domain->iovad,
+ iommu_flush_iova,
+ iova_entry_free)) {
+ pr_warn("iova flush queue initialization failed\n");
+ intel_iommu_strict = 1;
+ }
+out:
return domain;
}
@@ -2664,29 +2628,6 @@ static struct dmar_domain *set_domain_for_dev(struct device *dev,
return domain;
}
-static struct dmar_domain *get_domain_for_dev(struct device *dev, int gaw)
-{
- struct dmar_domain *domain, *tmp;
-
- domain = find_domain(dev);
- if (domain)
- goto out;
-
- domain = find_or_alloc_domain(dev, gaw);
- if (!domain)
- goto out;
-
- tmp = set_domain_for_dev(dev, domain);
- if (!tmp || domain != tmp) {
- domain_exit(domain);
- domain = tmp;
- }
-
-out:
-
- return domain;
-}
-
static int iommu_domain_identity_map(struct dmar_domain *domain,
unsigned long long start,
unsigned long long end)
@@ -2751,75 +2692,21 @@ static int domain_prepare_identity_map(struct device *dev,
return iommu_domain_identity_map(domain, start, end);
}
-static int iommu_prepare_identity_map(struct device *dev,
- unsigned long long start,
- unsigned long long end)
-{
- struct dmar_domain *domain;
- int ret;
-
- domain = get_domain_for_dev(dev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
- if (!domain)
- return -ENOMEM;
-
- ret = domain_prepare_identity_map(dev, domain, start, end);
- if (ret)
- domain_exit(domain);
-
- return ret;
-}
-
-static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
- struct device *dev)
-{
- if (dev->archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
- return 0;
- return iommu_prepare_identity_map(dev, rmrr->base_address,
- rmrr->end_address);
-}
-
-#ifdef CONFIG_INTEL_IOMMU_FLOPPY_WA
-static inline void iommu_prepare_isa(void)
-{
- struct pci_dev *pdev;
- int ret;
-
- pdev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
- if (!pdev)
- return;
-
- pr_info("Prepare 0-16MiB unity mapping for LPC\n");
- ret = iommu_prepare_identity_map(&pdev->dev, 0, 16*1024*1024 - 1);
-
- if (ret)
- pr_err("Failed to create 0-16MiB identity map - floppy might not work\n");
-
- pci_dev_put(pdev);
-}
-#else
-static inline void iommu_prepare_isa(void)
-{
- return;
-}
-#endif /* !CONFIG_INTEL_IOMMU_FLPY_WA */
-
-static int md_domain_init(struct dmar_domain *domain, int guest_width);
-
static int __init si_domain_init(int hw)
{
- int nid, ret;
+ struct dmar_rmrr_unit *rmrr;
+ struct device *dev;
+ int i, nid, ret;
si_domain = alloc_domain(DOMAIN_FLAG_STATIC_IDENTITY);
if (!si_domain)
return -EFAULT;
- if (md_domain_init(si_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
+ if (domain_init(si_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
domain_exit(si_domain);
return -EFAULT;
}
- pr_debug("Identity mapping domain allocated\n");
-
if (hw)
return 0;
@@ -2835,6 +2722,31 @@ static int __init si_domain_init(int hw)
}
}
+ /*
+ * Normally we use DMA domains for devices which have RMRRs. But we
+ * loose this requirement for graphic and usb devices. Identity map
+ * the RMRRs for graphic and USB devices so that they could use the
+ * si_domain.
+ */
+ for_each_rmrr_units(rmrr) {
+ for_each_active_dev_scope(rmrr->devices, rmrr->devices_cnt,
+ i, dev) {
+ unsigned long long start = rmrr->base_address;
+ unsigned long long end = rmrr->end_address;
+
+ if (device_is_rmrr_locked(dev))
+ continue;
+
+ if (WARN_ON(end < start ||
+ end >> agaw_to_width(si_domain->agaw)))
+ continue;
+
+ ret = iommu_domain_identity_map(si_domain, start, end);
+ if (ret)
+ return ret;
+ }
+ }
+
return 0;
}
@@ -2842,9 +2754,6 @@ static int identity_mapping(struct device *dev)
{
struct device_domain_info *info;
- if (likely(!iommu_identity_mapping))
- return 0;
-
info = dev->archdata.iommu;
if (info && info != DUMMY_DEVICE_DOMAIN_INFO)
return (info->domain == si_domain);
@@ -2883,7 +2792,8 @@ static bool device_has_rmrr(struct device *dev)
*/
for_each_active_dev_scope(rmrr->devices,
rmrr->devices_cnt, i, tmp)
- if (tmp == dev) {
+ if (tmp == dev ||
+ is_downstream_to_pci_bridge(dev, tmp)) {
rcu_read_unlock();
return true;
}
@@ -2892,6 +2802,35 @@ static bool device_has_rmrr(struct device *dev)
return false;
}
+/**
+ * device_rmrr_is_relaxable - Test whether the RMRR of this device
+ * is relaxable (ie. is allowed to be not enforced under some conditions)
+ * @dev: device handle
+ *
+ * We assume that PCI USB devices with RMRRs have them largely
+ * for historical reasons and that the RMRR space is not actively used post
+ * boot. This exclusion may change if vendors begin to abuse it.
+ *
+ * The same exception is made for graphics devices, with the requirement that
+ * any use of the RMRR regions will be torn down before assigning the device
+ * to a guest.
+ *
+ * Return: true if the RMRR is relaxable, false otherwise
+ */
+static bool device_rmrr_is_relaxable(struct device *dev)
+{
+ struct pci_dev *pdev;
+
+ if (!dev_is_pci(dev))
+ return false;
+
+ pdev = to_pci_dev(dev);
+ if (IS_USB_DEVICE(pdev) || IS_GFX_DEVICE(pdev))
+ return true;
+ else
+ return false;
+}
+
/*
* There are a couple cases where we need to restrict the functionality of
* devices associated with RMRRs. The first is when evaluating a device for
@@ -2906,52 +2845,51 @@ static bool device_has_rmrr(struct device *dev)
* We therefore prevent devices associated with an RMRR from participating in
* the IOMMU API, which eliminates them from device assignment.
*
- * In both cases we assume that PCI USB devices with RMRRs have them largely
- * for historical reasons and that the RMRR space is not actively used post
- * boot. This exclusion may change if vendors begin to abuse it.
- *
- * The same exception is made for graphics devices, with the requirement that
- * any use of the RMRR regions will be torn down before assigning the device
- * to a guest.
+ * In both cases, devices which have relaxable RMRRs are not concerned by this
+ * restriction. See device_rmrr_is_relaxable comment.
*/
static bool device_is_rmrr_locked(struct device *dev)
{
if (!device_has_rmrr(dev))
return false;
- if (dev_is_pci(dev)) {
- struct pci_dev *pdev = to_pci_dev(dev);
-
- if (IS_USB_DEVICE(pdev) || IS_GFX_DEVICE(pdev))
- return false;
- }
+ if (device_rmrr_is_relaxable(dev))
+ return false;
return true;
}
-static int iommu_should_identity_map(struct device *dev, int startup)
+/*
+ * Return the required default domain type for a specific device.
+ *
+ * @dev: the device in query
+ * @startup: true if this is during early boot
+ *
+ * Returns:
+ * - IOMMU_DOMAIN_DMA: device requires a dynamic mapping domain
+ * - IOMMU_DOMAIN_IDENTITY: device requires an identical mapping domain
+ * - 0: both identity and dynamic domains work for this device
+ */
+static int device_def_domain_type(struct device *dev)
{
if (dev_is_pci(dev)) {
struct pci_dev *pdev = to_pci_dev(dev);
if (device_is_rmrr_locked(dev))
- return 0;
+ return IOMMU_DOMAIN_DMA;
/*
* Prevent any device marked as untrusted from getting
* placed into the statically identity mapping domain.
*/
if (pdev->untrusted)
- return 0;
+ return IOMMU_DOMAIN_DMA;
if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev))
- return 1;
+ return IOMMU_DOMAIN_IDENTITY;
if ((iommu_identity_mapping & IDENTMAP_GFX) && IS_GFX_DEVICE(pdev))
- return 1;
-
- if (!(iommu_identity_mapping & IDENTMAP_ALL))
- return 0;
+ return IOMMU_DOMAIN_IDENTITY;
/*
* We want to start off with all devices in the 1:1 domain, and
@@ -2972,94 +2910,18 @@ static int iommu_should_identity_map(struct device *dev, int startup)
*/
if (!pci_is_pcie(pdev)) {
if (!pci_is_root_bus(pdev->bus))
- return 0;
+ return IOMMU_DOMAIN_DMA;
if (pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI)
- return 0;
+ return IOMMU_DOMAIN_DMA;
} else if (pci_pcie_type(pdev) == PCI_EXP_TYPE_PCI_BRIDGE)
- return 0;
+ return IOMMU_DOMAIN_DMA;
} else {
if (device_has_rmrr(dev))
- return 0;
- }
-
- /*
- * At boot time, we don't yet know if devices will be 64-bit capable.
- * Assume that they will — if they turn out not to be, then we can
- * take them out of the 1:1 domain later.
- */
- if (!startup) {
- /*
- * If the device's dma_mask is less than the system's memory
- * size then this is not a candidate for identity mapping.
- */
- u64 dma_mask = *dev->dma_mask;
-
- if (dev->coherent_dma_mask &&
- dev->coherent_dma_mask < dma_mask)
- dma_mask = dev->coherent_dma_mask;
-
- return dma_mask >= dma_get_required_mask(dev);
- }
-
- return 1;
-}
-
-static int __init dev_prepare_static_identity_mapping(struct device *dev, int hw)
-{
- int ret;
-
- if (!iommu_should_identity_map(dev, 1))
- return 0;
-
- ret = domain_add_dev_info(si_domain, dev);
- if (!ret)
- dev_info(dev, "%s identity mapping\n",
- hw ? "Hardware" : "Software");
- else if (ret == -ENODEV)
- /* device not associated with an iommu */
- ret = 0;
-
- return ret;
-}
-
-
-static int __init iommu_prepare_static_identity_mapping(int hw)
-{
- struct pci_dev *pdev = NULL;
- struct dmar_drhd_unit *drhd;
- /* To avoid a -Wunused-but-set-variable warning. */
- struct intel_iommu *iommu __maybe_unused;
- struct device *dev;
- int i;
- int ret = 0;
-
- for_each_pci_dev(pdev) {
- ret = dev_prepare_static_identity_mapping(&pdev->dev, hw);
- if (ret)
- return ret;
+ return IOMMU_DOMAIN_DMA;
}
- for_each_active_iommu(iommu, drhd)
- for_each_active_dev_scope(drhd->devices, drhd->devices_cnt, i, dev) {
- struct acpi_device_physical_node *pn;
- struct acpi_device *adev;
-
- if (dev->bus != &acpi_bus_type)
- continue;
-
- adev= to_acpi_device(dev);
- mutex_lock(&adev->physical_node_lock);
- list_for_each_entry(pn, &adev->physical_node_list, node) {
- ret = dev_prepare_static_identity_mapping(pn->dev, hw);
- if (ret)
- break;
- }
- mutex_unlock(&adev->physical_node_lock);
- if (ret)
- return ret;
- }
-
- return 0;
+ return (iommu_identity_mapping & IDENTMAP_ALL) ?
+ IOMMU_DOMAIN_IDENTITY : 0;
}
static void intel_iommu_init_qi(struct intel_iommu *iommu)
@@ -3284,11 +3146,8 @@ out_unmap:
static int __init init_dmars(void)
{
struct dmar_drhd_unit *drhd;
- struct dmar_rmrr_unit *rmrr;
- bool copied_tables = false;
- struct device *dev;
struct intel_iommu *iommu;
- int i, ret;
+ int ret;
/*
* for each drhd
@@ -3321,7 +3180,12 @@ static int __init init_dmars(void)
goto error;
}
- for_each_active_iommu(iommu, drhd) {
+ for_each_iommu(iommu, drhd) {
+ if (drhd->ignored) {
+ iommu_disable_translation(iommu);
+ continue;
+ }
+
/*
* Find the max pasid size of all IOMMU's in the system.
* We need to ensure the system pasid table is no bigger
@@ -3381,7 +3245,6 @@ static int __init init_dmars(void)
} else {
pr_info("Copied translation tables from previous kernel for %s\n",
iommu->name);
- copied_tables = true;
}
}
@@ -3417,62 +3280,9 @@ static int __init init_dmars(void)
check_tylersburg_isoch();
- if (iommu_identity_mapping) {
- ret = si_domain_init(hw_pass_through);
- if (ret)
- goto free_iommu;
- }
-
-
- /*
- * If we copied translations from a previous kernel in the kdump
- * case, we can not assign the devices to domains now, as that
- * would eliminate the old mappings. So skip this part and defer
- * the assignment to device driver initialization time.
- */
- if (copied_tables)
- goto domains_done;
-
- /*
- * If pass through is not set or not enabled, setup context entries for
- * identity mappings for rmrr, gfx, and isa and may fall back to static
- * identity mapping if iommu_identity_mapping is set.
- */
- if (iommu_identity_mapping) {
- ret = iommu_prepare_static_identity_mapping(hw_pass_through);
- if (ret) {
- pr_crit("Failed to setup IOMMU pass-through\n");
- goto free_iommu;
- }
- }
- /*
- * For each rmrr
- * for each dev attached to rmrr
- * do
- * locate drhd for dev, alloc domain for dev
- * allocate free domain
- * allocate page table entries for rmrr
- * if context not allocated for bus
- * allocate and init context
- * set present in root table for this bus
- * init context with domain, translation etc
- * endfor
- * endfor
- */
- pr_info("Setting RMRR:\n");
- for_each_rmrr_units(rmrr) {
- /* some BIOS lists non-exist devices in DMAR table. */
- for_each_active_dev_scope(rmrr->devices, rmrr->devices_cnt,
- i, dev) {
- ret = iommu_prepare_rmrr_dev(rmrr, dev);
- if (ret)
- pr_err("Mapping reserved region failed\n");
- }
- }
-
- iommu_prepare_isa();
-
-domains_done:
+ ret = si_domain_init(hw_pass_through);
+ if (ret)
+ goto free_iommu;
/*
* for each drhd
@@ -3510,11 +3320,6 @@ domains_done:
ret = dmar_set_interrupt(iommu);
if (ret)
goto free_iommu;
-
- if (!translation_pre_enabled(iommu))
- iommu_enable_translation(iommu);
-
- iommu_disable_protect_mem_regions(iommu);
}
return 0;
@@ -3564,16 +3369,17 @@ static unsigned long intel_alloc_iova(struct device *dev,
return iova_pfn;
}
-struct dmar_domain *get_valid_domain_for_dev(struct device *dev)
+static struct dmar_domain *get_private_domain_for_dev(struct device *dev)
{
struct dmar_domain *domain, *tmp;
struct dmar_rmrr_unit *rmrr;
struct device *i_dev;
int i, ret;
+ /* Device shouldn't be attached by any domains. */
domain = find_domain(dev);
if (domain)
- goto out;
+ return NULL;
domain = find_or_alloc_domain(dev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
if (!domain)
@@ -3603,10 +3409,10 @@ struct dmar_domain *get_valid_domain_for_dev(struct device *dev)
}
out:
-
if (!domain)
dev_err(dev, "Allocating domain failed\n");
-
+ else
+ domain->domain.type = IOMMU_DOMAIN_DMA;
return domain;
}
@@ -3614,17 +3420,19 @@ out:
/* Check if the dev needs to go through non-identity map and unmap process.*/
static bool iommu_need_mapping(struct device *dev)
{
- int found;
+ int ret;
if (iommu_dummy(dev))
return false;
- if (!iommu_identity_mapping)
- return true;
+ ret = identity_mapping(dev);
+ if (ret) {
+ u64 dma_mask = *dev->dma_mask;
- found = identity_mapping(dev);
- if (found) {
- if (iommu_should_identity_map(dev, 0))
+ if (dev->coherent_dma_mask && dev->coherent_dma_mask < dma_mask)
+ dma_mask = dev->coherent_dma_mask;
+
+ if (dma_mask >= dma_get_required_mask(dev))
return false;
/*
@@ -3632,17 +3440,20 @@ static bool iommu_need_mapping(struct device *dev)
* non-identity mapping.
*/
dmar_remove_one_dev_info(dev);
- dev_info(dev, "32bit DMA uses non-identity mapping\n");
- } else {
- /*
- * In case of a detached 64 bit DMA device from vm, the device
- * is put into si_domain for identity mapping.
- */
- if (iommu_should_identity_map(dev, 0) &&
- !domain_add_dev_info(si_domain, dev)) {
- dev_info(dev, "64bit DMA uses identity mapping\n");
- return false;
+ ret = iommu_request_dma_domain_for_dev(dev);
+ if (ret) {
+ struct iommu_domain *domain;
+ struct dmar_domain *dmar_domain;
+
+ domain = iommu_get_domain_for_dev(dev);
+ if (domain) {
+ dmar_domain = to_dmar_domain(domain);
+ dmar_domain->flags |= DOMAIN_FLAG_LOSE_CHILDREN;
+ }
+ get_private_domain_for_dev(dev);
}
+
+ dev_info(dev, "32bit DMA uses non-identity mapping\n");
}
return true;
@@ -3661,7 +3472,7 @@ static dma_addr_t __intel_map_single(struct device *dev, phys_addr_t paddr,
BUG_ON(dir == DMA_NONE);
- domain = get_valid_domain_for_dev(dev);
+ domain = find_domain(dev);
if (!domain)
return DMA_MAPPING_ERROR;
@@ -3876,7 +3687,7 @@ static int intel_map_sg(struct device *dev, struct scatterlist *sglist, int nele
if (!iommu_need_mapping(dev))
return dma_direct_map_sg(dev, sglist, nelems, dir, attrs);
- domain = get_valid_domain_for_dev(dev);
+ domain = find_domain(dev);
if (!domain)
return 0;
@@ -4195,13 +4006,10 @@ static void __init init_iommu_pm_ops(void)
static inline void init_iommu_pm_ops(void) {}
#endif /* CONFIG_PM */
-
int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header, void *arg)
{
struct acpi_dmar_reserved_memory *rmrr;
- int prot = DMA_PTE_READ|DMA_PTE_WRITE;
struct dmar_rmrr_unit *rmrru;
- size_t length;
rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
if (!rmrru)
@@ -4212,23 +4020,15 @@ int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header, void *arg)
rmrru->base_address = rmrr->base_address;
rmrru->end_address = rmrr->end_address;
- length = rmrr->end_address - rmrr->base_address + 1;
- rmrru->resv = iommu_alloc_resv_region(rmrr->base_address, length, prot,
- IOMMU_RESV_DIRECT);
- if (!rmrru->resv)
- goto free_rmrru;
-
rmrru->devices = dmar_alloc_dev_scope((void *)(rmrr + 1),
((void *)rmrr) + rmrr->header.length,
&rmrru->devices_cnt);
if (rmrru->devices_cnt && rmrru->devices == NULL)
- goto free_all;
+ goto free_rmrru;
list_add(&rmrru->list, &dmar_rmrr_units);
return 0;
-free_all:
- kfree(rmrru->resv);
free_rmrru:
kfree(rmrru);
out:
@@ -4446,7 +4246,6 @@ static void intel_iommu_free_dmars(void)
list_for_each_entry_safe(rmrru, rmrr_n, &dmar_rmrr_units, list) {
list_del(&rmrru->list);
dmar_free_dev_scope(&rmrru->devices, &rmrru->devices_cnt);
- kfree(rmrru->resv);
kfree(rmrru);
}
@@ -4551,42 +4350,6 @@ int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info)
return 0;
}
-/*
- * Here we only respond to action of unbound device from driver.
- *
- * Added device is not attached to its DMAR domain here yet. That will happen
- * when mapping the device to iova.
- */
-static int device_notifier(struct notifier_block *nb,
- unsigned long action, void *data)
-{
- struct device *dev = data;
- struct dmar_domain *domain;
-
- if (iommu_dummy(dev))
- return 0;
-
- if (action == BUS_NOTIFY_REMOVED_DEVICE) {
- domain = find_domain(dev);
- if (!domain)
- return 0;
-
- dmar_remove_one_dev_info(dev);
- if (!domain_type_is_vm_or_si(domain) &&
- list_empty(&domain->devices))
- domain_exit(domain);
- } else if (action == BUS_NOTIFY_ADD_DEVICE) {
- if (iommu_should_identity_map(dev, 1))
- domain_add_dev_info(si_domain, dev);
- }
-
- return 0;
-}
-
-static struct notifier_block device_nb = {
- .notifier_call = device_notifier,
-};
-
static int intel_iommu_memory_notifier(struct notifier_block *nb,
unsigned long val, void *v)
{
@@ -4813,6 +4576,49 @@ static int __init platform_optin_force_iommu(void)
return 1;
}
+static int __init probe_acpi_namespace_devices(void)
+{
+ struct dmar_drhd_unit *drhd;
+ /* To avoid a -Wunused-but-set-variable warning. */
+ struct intel_iommu *iommu __maybe_unused;
+ struct device *dev;
+ int i, ret = 0;
+
+ for_each_active_iommu(iommu, drhd) {
+ for_each_active_dev_scope(drhd->devices,
+ drhd->devices_cnt, i, dev) {
+ struct acpi_device_physical_node *pn;
+ struct iommu_group *group;
+ struct acpi_device *adev;
+
+ if (dev->bus != &acpi_bus_type)
+ continue;
+
+ adev = to_acpi_device(dev);
+ mutex_lock(&adev->physical_node_lock);
+ list_for_each_entry(pn,
+ &adev->physical_node_list, node) {
+ group = iommu_group_get(pn->dev);
+ if (group) {
+ iommu_group_put(group);
+ continue;
+ }
+
+ pn->dev->bus->iommu_ops = &intel_iommu_ops;
+ ret = iommu_probe_device(pn->dev);
+ if (ret)
+ break;
+ }
+ mutex_unlock(&adev->physical_node_lock);
+
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
int __init intel_iommu_init(void)
{
int ret = -ENODEV;
@@ -4902,7 +4708,6 @@ int __init intel_iommu_init(void)
goto out_free_reserved_range;
}
up_write(&dmar_global_lock);
- pr_info("Intel(R) Virtualization Technology for Directed I/O\n");
#if defined(CONFIG_X86) && defined(CONFIG_SWIOTLB)
swiotlb = 0;
@@ -4920,11 +4725,25 @@ int __init intel_iommu_init(void)
}
bus_set_iommu(&pci_bus_type, &intel_iommu_ops);
- bus_register_notifier(&pci_bus_type, &device_nb);
if (si_domain && !hw_pass_through)
register_memory_notifier(&intel_iommu_memory_nb);
cpuhp_setup_state(CPUHP_IOMMU_INTEL_DEAD, "iommu/intel:dead", NULL,
intel_iommu_cpu_dead);
+
+ down_read(&dmar_global_lock);
+ if (probe_acpi_namespace_devices())
+ pr_warn("ACPI name space devices didn't probe correctly\n");
+ up_read(&dmar_global_lock);
+
+ /* Finally, we enable the DMA remapping hardware. */
+ for_each_iommu(iommu, drhd) {
+ if (!drhd->ignored && !translation_pre_enabled(iommu))
+ iommu_enable_translation(iommu);
+
+ iommu_disable_protect_mem_regions(iommu);
+ }
+ pr_info("Intel(R) Virtualization Technology for Directed I/O\n");
+
intel_iommu_enabled = 1;
intel_iommu_debugfs_init();
@@ -4963,6 +4782,7 @@ static void domain_context_clear(struct intel_iommu *iommu, struct device *dev)
static void __dmar_remove_one_dev_info(struct device_domain_info *info)
{
+ struct dmar_domain *domain;
struct intel_iommu *iommu;
unsigned long flags;
@@ -4972,6 +4792,7 @@ static void __dmar_remove_one_dev_info(struct device_domain_info *info)
return;
iommu = info->iommu;
+ domain = info->domain;
if (info->dev) {
if (dev_is_pci(info->dev) && sm_supported(iommu))
@@ -4986,9 +4807,14 @@ static void __dmar_remove_one_dev_info(struct device_domain_info *info)
unlink_domain_info(info);
spin_lock_irqsave(&iommu->lock, flags);
- domain_detach_iommu(info->domain, iommu);
+ domain_detach_iommu(domain, iommu);
spin_unlock_irqrestore(&iommu->lock, flags);
+ /* free the private domain */
+ if (domain->flags & DOMAIN_FLAG_LOSE_CHILDREN &&
+ !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY))
+ domain_exit(info->domain);
+
free_devinfo_mem(info);
}
@@ -5003,62 +4829,55 @@ static void dmar_remove_one_dev_info(struct device *dev)
spin_unlock_irqrestore(&device_domain_lock, flags);
}
-static int md_domain_init(struct dmar_domain *domain, int guest_width)
-{
- int adjust_width;
-
- init_iova_domain(&domain->iovad, VTD_PAGE_SIZE, IOVA_START_PFN);
- domain_reserve_special_ranges(domain);
-
- /* calculate AGAW */
- domain->gaw = guest_width;
- adjust_width = guestwidth_to_adjustwidth(guest_width);
- domain->agaw = width_to_agaw(adjust_width);
-
- domain->iommu_coherency = 0;
- domain->iommu_snooping = 0;
- domain->iommu_superpage = 0;
- domain->max_addr = 0;
-
- /* always allocate the top pgd */
- domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
- if (!domain->pgd)
- return -ENOMEM;
- domain_flush_cache(domain, domain->pgd, PAGE_SIZE);
- return 0;
-}
-
static struct iommu_domain *intel_iommu_domain_alloc(unsigned type)
{
struct dmar_domain *dmar_domain;
struct iommu_domain *domain;
- if (type != IOMMU_DOMAIN_UNMANAGED)
- return NULL;
+ switch (type) {
+ case IOMMU_DOMAIN_DMA:
+ /* fallthrough */
+ case IOMMU_DOMAIN_UNMANAGED:
+ dmar_domain = alloc_domain(0);
+ if (!dmar_domain) {
+ pr_err("Can't allocate dmar_domain\n");
+ return NULL;
+ }
+ if (domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
+ pr_err("Domain initialization failed\n");
+ domain_exit(dmar_domain);
+ return NULL;
+ }
- dmar_domain = alloc_domain(DOMAIN_FLAG_VIRTUAL_MACHINE);
- if (!dmar_domain) {
- pr_err("Can't allocate dmar_domain\n");
- return NULL;
- }
- if (md_domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
- pr_err("Domain initialization failed\n");
- domain_exit(dmar_domain);
+ if (type == IOMMU_DOMAIN_DMA &&
+ init_iova_flush_queue(&dmar_domain->iovad,
+ iommu_flush_iova, iova_entry_free)) {
+ pr_warn("iova flush queue initialization failed\n");
+ intel_iommu_strict = 1;
+ }
+
+ domain_update_iommu_cap(dmar_domain);
+
+ domain = &dmar_domain->domain;
+ domain->geometry.aperture_start = 0;
+ domain->geometry.aperture_end =
+ __DOMAIN_MAX_ADDR(dmar_domain->gaw);
+ domain->geometry.force_aperture = true;
+
+ return domain;
+ case IOMMU_DOMAIN_IDENTITY:
+ return &si_domain->domain;
+ default:
return NULL;
}
- domain_update_iommu_cap(dmar_domain);
- domain = &dmar_domain->domain;
- domain->geometry.aperture_start = 0;
- domain->geometry.aperture_end = __DOMAIN_MAX_ADDR(dmar_domain->gaw);
- domain->geometry.force_aperture = true;
-
- return domain;
+ return NULL;
}
static void intel_iommu_domain_free(struct iommu_domain *domain)
{
- domain_exit(to_dmar_domain(domain));
+ if (domain != &si_domain->domain)
+ domain_exit(to_dmar_domain(domain));
}
/*
@@ -5234,7 +5053,8 @@ static int intel_iommu_attach_device(struct iommu_domain *domain,
{
int ret;
- if (device_is_rmrr_locked(dev)) {
+ if (domain->type == IOMMU_DOMAIN_UNMANAGED &&
+ device_is_rmrr_locked(dev)) {
dev_warn(dev, "Device is ineligible for IOMMU domain attach due to platform RMRR requirement. Contact your platform vendor.\n");
return -EPERM;
}
@@ -5247,15 +5067,8 @@ static int intel_iommu_attach_device(struct iommu_domain *domain,
struct dmar_domain *old_domain;
old_domain = find_domain(dev);
- if (old_domain) {
- rcu_read_lock();
+ if (old_domain)
dmar_remove_one_dev_info(dev);
- rcu_read_unlock();
-
- if (!domain_type_is_vm_or_si(old_domain) &&
- list_empty(&old_domain->devices))
- domain_exit(old_domain);
- }
}
ret = prepare_domain_attach_device(domain, dev);
@@ -5301,6 +5114,9 @@ static int intel_iommu_map(struct iommu_domain *domain,
int prot = 0;
int ret;
+ if (dmar_domain->flags & DOMAIN_FLAG_LOSE_CHILDREN)
+ return -EINVAL;
+
if (iommu_prot & IOMMU_READ)
prot |= DMA_PTE_READ;
if (iommu_prot & IOMMU_WRITE)
@@ -5342,6 +5158,8 @@ static size_t intel_iommu_unmap(struct iommu_domain *domain,
/* Cope with horrid API which requires us to unmap more than the
size argument if it happens to be a large-page mapping. */
BUG_ON(!pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, &level));
+ if (dmar_domain->flags & DOMAIN_FLAG_LOSE_CHILDREN)
+ return 0;
if (size < VTD_PAGE_SIZE << level_to_offset_bits(level))
size = VTD_PAGE_SIZE << level_to_offset_bits(level);
@@ -5373,6 +5191,9 @@ static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
int level = 0;
u64 phys = 0;
+ if (dmar_domain->flags & DOMAIN_FLAG_LOSE_CHILDREN)
+ return 0;
+
pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, &level);
if (pte)
phys = dma_pte_addr(pte);
@@ -5428,9 +5249,12 @@ static bool intel_iommu_capable(enum iommu_cap cap)
static int intel_iommu_add_device(struct device *dev)
{
+ struct dmar_domain *dmar_domain;
+ struct iommu_domain *domain;
struct intel_iommu *iommu;
struct iommu_group *group;
u8 bus, devfn;
+ int ret;
iommu = device_to_iommu(dev, &bus, &devfn);
if (!iommu)
@@ -5438,12 +5262,45 @@ static int intel_iommu_add_device(struct device *dev)
iommu_device_link(&iommu->iommu, dev);
+ if (translation_pre_enabled(iommu))
+ dev->archdata.iommu = DEFER_DEVICE_DOMAIN_INFO;
+
group = iommu_group_get_for_dev(dev);
if (IS_ERR(group))
return PTR_ERR(group);
iommu_group_put(group);
+
+ domain = iommu_get_domain_for_dev(dev);
+ dmar_domain = to_dmar_domain(domain);
+ if (domain->type == IOMMU_DOMAIN_DMA) {
+ if (device_def_domain_type(dev) == IOMMU_DOMAIN_IDENTITY) {
+ ret = iommu_request_dm_for_dev(dev);
+ if (ret) {
+ dmar_domain->flags |= DOMAIN_FLAG_LOSE_CHILDREN;
+ domain_add_dev_info(si_domain, dev);
+ dev_info(dev,
+ "Device uses a private identity domain.\n");
+ }
+ }
+ } else {
+ if (device_def_domain_type(dev) == IOMMU_DOMAIN_DMA) {
+ ret = iommu_request_dma_domain_for_dev(dev);
+ if (ret) {
+ dmar_domain->flags |= DOMAIN_FLAG_LOSE_CHILDREN;
+ if (!get_private_domain_for_dev(dev)) {
+ dev_warn(dev,
+ "Failed to get a private domain.\n");
+ return -ENOMEM;
+ }
+
+ dev_info(dev,
+ "Device uses a private dma domain.\n");
+ }
+ }
+ }
+
return 0;
}
@@ -5464,22 +5321,51 @@ static void intel_iommu_remove_device(struct device *dev)
static void intel_iommu_get_resv_regions(struct device *device,
struct list_head *head)
{
+ int prot = DMA_PTE_READ | DMA_PTE_WRITE;
struct iommu_resv_region *reg;
struct dmar_rmrr_unit *rmrr;
struct device *i_dev;
int i;
- rcu_read_lock();
+ down_read(&dmar_global_lock);
for_each_rmrr_units(rmrr) {
for_each_active_dev_scope(rmrr->devices, rmrr->devices_cnt,
i, i_dev) {
- if (i_dev != device)
+ struct iommu_resv_region *resv;
+ enum iommu_resv_type type;
+ size_t length;
+
+ if (i_dev != device &&
+ !is_downstream_to_pci_bridge(device, i_dev))
continue;
- list_add_tail(&rmrr->resv->list, head);
+ length = rmrr->end_address - rmrr->base_address + 1;
+
+ type = device_rmrr_is_relaxable(device) ?
+ IOMMU_RESV_DIRECT_RELAXABLE : IOMMU_RESV_DIRECT;
+
+ resv = iommu_alloc_resv_region(rmrr->base_address,
+ length, prot, type);
+ if (!resv)
+ break;
+
+ list_add_tail(&resv->list, head);
}
}
- rcu_read_unlock();
+ up_read(&dmar_global_lock);
+
+#ifdef CONFIG_INTEL_IOMMU_FLOPPY_WA
+ if (dev_is_pci(device)) {
+ struct pci_dev *pdev = to_pci_dev(device);
+
+ if ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA) {
+ reg = iommu_alloc_resv_region(0, 1UL << 24, 0,
+ IOMMU_RESV_DIRECT);
+ if (reg)
+ list_add_tail(&reg->list, head);
+ }
+ }
+#endif /* CONFIG_INTEL_IOMMU_FLOPPY_WA */
reg = iommu_alloc_resv_region(IOAPIC_RANGE_START,
IOAPIC_RANGE_END - IOAPIC_RANGE_START + 1,
@@ -5494,10 +5380,8 @@ static void intel_iommu_put_resv_regions(struct device *dev,
{
struct iommu_resv_region *entry, *next;
- list_for_each_entry_safe(entry, next, head, list) {
- if (entry->type == IOMMU_RESV_MSI)
- kfree(entry);
- }
+ list_for_each_entry_safe(entry, next, head, list)
+ kfree(entry);
}
int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct device *dev)
@@ -5509,7 +5393,7 @@ int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct device *dev)
u64 ctx_lo;
int ret;
- domain = get_valid_domain_for_dev(dev);
+ domain = find_domain(dev);
if (!domain)
return -EINVAL;
@@ -5551,6 +5435,19 @@ int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct device *dev)
return ret;
}
+static void intel_iommu_apply_resv_region(struct device *dev,
+ struct iommu_domain *domain,
+ struct iommu_resv_region *region)
+{
+ struct dmar_domain *dmar_domain = to_dmar_domain(domain);
+ unsigned long start, end;
+
+ start = IOVA_PFN(region->start);
+ end = IOVA_PFN(region->start + region->length - 1);
+
+ WARN_ON_ONCE(!reserve_iova(&dmar_domain->iovad, start, end));
+}
+
#ifdef CONFIG_INTEL_IOMMU_SVM
struct intel_iommu *intel_svm_device_to_iommu(struct device *dev)
{
@@ -5700,6 +5597,12 @@ intel_iommu_aux_get_pasid(struct iommu_domain *domain, struct device *dev)
dmar_domain->default_pasid : -EINVAL;
}
+static bool intel_iommu_is_attach_deferred(struct iommu_domain *domain,
+ struct device *dev)
+{
+ return dev->archdata.iommu == DEFER_DEVICE_DOMAIN_INFO;
+}
+
const struct iommu_ops intel_iommu_ops = {
.capable = intel_iommu_capable,
.domain_alloc = intel_iommu_domain_alloc,
@@ -5716,11 +5619,13 @@ const struct iommu_ops intel_iommu_ops = {
.remove_device = intel_iommu_remove_device,
.get_resv_regions = intel_iommu_get_resv_regions,
.put_resv_regions = intel_iommu_put_resv_regions,
+ .apply_resv_region = intel_iommu_apply_resv_region,
.device_group = pci_device_group,
.dev_has_feat = intel_iommu_dev_has_feat,
.dev_feat_enabled = intel_iommu_dev_feat_enabled,
.dev_enable_feat = intel_iommu_dev_enable_feat,
.dev_disable_feat = intel_iommu_dev_disable_feat,
+ .is_attach_deferred = intel_iommu_is_attach_deferred,
.pgsize_bitmap = INTEL_IOMMU_PGSIZES,
};
diff --git a/drivers/iommu/intel-pasid.c b/drivers/iommu/intel-pasid.c
index fe51d8af457f..040a445be300 100644
--- a/drivers/iommu/intel-pasid.c
+++ b/drivers/iommu/intel-pasid.c
@@ -169,23 +169,6 @@ attach_out:
return 0;
}
-/* Get PRESENT bit of a PASID directory entry. */
-static inline bool
-pasid_pde_is_present(struct pasid_dir_entry *pde)
-{
- return READ_ONCE(pde->val) & PASID_PTE_PRESENT;
-}
-
-/* Get PASID table from a PASID directory entry. */
-static inline struct pasid_entry *
-get_pasid_table_from_pde(struct pasid_dir_entry *pde)
-{
- if (!pasid_pde_is_present(pde))
- return NULL;
-
- return phys_to_virt(READ_ONCE(pde->val) & PDE_PFN_MASK);
-}
-
void intel_pasid_free_table(struct device *dev)
{
struct device_domain_info *info;
diff --git a/drivers/iommu/intel-pasid.h b/drivers/iommu/intel-pasid.h
index 23537b3f34e3..fc8cd8f17de1 100644
--- a/drivers/iommu/intel-pasid.h
+++ b/drivers/iommu/intel-pasid.h
@@ -18,6 +18,10 @@
#define PDE_PFN_MASK PAGE_MASK
#define PASID_PDE_SHIFT 6
#define MAX_NR_PASID_BITS 20
+#define PASID_TBL_ENTRIES BIT(PASID_PDE_SHIFT)
+
+#define is_pasid_enabled(entry) (((entry)->lo >> 3) & 0x1)
+#define get_pasid_dir_size(entry) (1 << ((((entry)->lo >> 9) & 0x7) + 7))
/*
* Domain ID reserved for pasid entries programmed for first-level
@@ -49,6 +53,28 @@ struct pasid_table {
struct list_head dev; /* device list */
};
+/* Get PRESENT bit of a PASID directory entry. */
+static inline bool pasid_pde_is_present(struct pasid_dir_entry *pde)
+{
+ return READ_ONCE(pde->val) & PASID_PTE_PRESENT;
+}
+
+/* Get PASID table from a PASID directory entry. */
+static inline struct pasid_entry *
+get_pasid_table_from_pde(struct pasid_dir_entry *pde)
+{
+ if (!pasid_pde_is_present(pde))
+ return NULL;
+
+ return phys_to_virt(READ_ONCE(pde->val) & PDE_PFN_MASK);
+}
+
+/* Get PRESENT bit of a PASID table entry. */
+static inline bool pasid_pte_is_present(struct pasid_entry *pte)
+{
+ return READ_ONCE(pte->val[0]) & PASID_PTE_PRESENT;
+}
+
extern u32 intel_pasid_max_id;
int intel_pasid_alloc_id(void *ptr, int start, int end, gfp_t gfp);
void intel_pasid_free_id(int pasid);
diff --git a/drivers/iommu/intel-svm.c b/drivers/iommu/intel-svm.c
index eceaa7e968ae..780de0caafe8 100644
--- a/drivers/iommu/intel-svm.c
+++ b/drivers/iommu/intel-svm.c
@@ -366,6 +366,21 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_
}
list_add_tail(&svm->list, &global_svm_list);
+ } else {
+ /*
+ * Binding a new device with existing PASID, need to setup
+ * the PASID entry.
+ */
+ spin_lock(&iommu->lock);
+ ret = intel_pasid_setup_first_level(iommu, dev,
+ mm ? mm->pgd : init_mm.pgd,
+ svm->pasid, FLPT_DEFAULT_DID,
+ mm ? 0 : PASID_FLAG_SUPERVISOR_MODE);
+ spin_unlock(&iommu->lock);
+ if (ret) {
+ kfree(sdev);
+ goto out;
+ }
}
list_add_rcu(&sdev->list, &svm->devs);
diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c
index 4160aa9f3f80..4786ca061e31 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -101,7 +101,7 @@ static void init_ir_status(struct intel_iommu *iommu)
iommu->flags |= VTD_FLAG_IRQ_REMAP_PRE_ENABLED;
}
-static int alloc_irte(struct intel_iommu *iommu, int irq,
+static int alloc_irte(struct intel_iommu *iommu,
struct irq_2_iommu *irq_iommu, u16 count)
{
struct ir_table *table = iommu->ir_table;
@@ -1374,7 +1374,7 @@ static int intel_irq_remapping_alloc(struct irq_domain *domain,
goto out_free_parent;
down_read(&dmar_global_lock);
- index = alloc_irte(iommu, virq, &data->irq_2_iommu, nr_irqs);
+ index = alloc_irte(iommu, &data->irq_2_iommu, nr_irqs);
up_read(&dmar_global_lock);
if (index < 0) {
pr_warn("Failed to allocate IRTE\n");
diff --git a/drivers/iommu/io-pgtable-arm-v7s.c b/drivers/iommu/io-pgtable-arm-v7s.c
index 9a8a8870e267..0fc8dfab2abf 100644
--- a/drivers/iommu/io-pgtable-arm-v7s.c
+++ b/drivers/iommu/io-pgtable-arm-v7s.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* CPU-agnostic ARM page table allocator.
*
@@ -14,18 +15,6 @@
* - PXN
* - Domains
*
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
* Copyright (C) 2014-2015 ARM Limited
* Copyright (c) 2014-2015 MediaTek Inc.
*/
@@ -215,7 +204,7 @@ static void *__arm_v7s_alloc_table(int lvl, gfp_t gfp,
dev_err(dev, "Page table does not fit in PTE: %pa", &phys);
goto out_free;
}
- if (table && !(cfg->quirks & IO_PGTABLE_QUIRK_NO_DMA)) {
+ if (table && !cfg->coherent_walk) {
dma = dma_map_single(dev, table, size, DMA_TO_DEVICE);
if (dma_mapping_error(dev, dma))
goto out_free;
@@ -249,7 +238,7 @@ static void __arm_v7s_free_table(void *table, int lvl,
struct device *dev = cfg->iommu_dev;
size_t size = ARM_V7S_TABLE_SIZE(lvl);
- if (!(cfg->quirks & IO_PGTABLE_QUIRK_NO_DMA))
+ if (!cfg->coherent_walk)
dma_unmap_single(dev, __arm_v7s_dma_addr(table), size,
DMA_TO_DEVICE);
if (lvl == 1)
@@ -261,7 +250,7 @@ static void __arm_v7s_free_table(void *table, int lvl,
static void __arm_v7s_pte_sync(arm_v7s_iopte *ptep, int num_entries,
struct io_pgtable_cfg *cfg)
{
- if (cfg->quirks & IO_PGTABLE_QUIRK_NO_DMA)
+ if (cfg->coherent_walk)
return;
dma_sync_single_for_device(cfg->iommu_dev, __arm_v7s_dma_addr(ptep),
@@ -727,7 +716,6 @@ static struct io_pgtable *arm_v7s_alloc_pgtable(struct io_pgtable_cfg *cfg,
IO_PGTABLE_QUIRK_NO_PERMS |
IO_PGTABLE_QUIRK_TLBI_ON_MAP |
IO_PGTABLE_QUIRK_ARM_MTK_4GB |
- IO_PGTABLE_QUIRK_NO_DMA |
IO_PGTABLE_QUIRK_NON_STRICT))
return NULL;
@@ -790,8 +778,11 @@ static struct io_pgtable *arm_v7s_alloc_pgtable(struct io_pgtable_cfg *cfg,
/* TTBRs */
cfg->arm_v7s_cfg.ttbr[0] = virt_to_phys(data->pgd) |
ARM_V7S_TTBR_S | ARM_V7S_TTBR_NOS |
- ARM_V7S_TTBR_IRGN_ATTR(ARM_V7S_RGN_WBWA) |
- ARM_V7S_TTBR_ORGN_ATTR(ARM_V7S_RGN_WBWA);
+ (cfg->coherent_walk ?
+ (ARM_V7S_TTBR_IRGN_ATTR(ARM_V7S_RGN_WBWA) |
+ ARM_V7S_TTBR_ORGN_ATTR(ARM_V7S_RGN_WBWA)) :
+ (ARM_V7S_TTBR_IRGN_ATTR(ARM_V7S_RGN_NC) |
+ ARM_V7S_TTBR_ORGN_ATTR(ARM_V7S_RGN_NC)));
cfg->arm_v7s_cfg.ttbr[1] = 0;
return &data->iop;
@@ -846,7 +837,8 @@ static int __init arm_v7s_do_selftests(void)
.tlb = &dummy_tlb_ops,
.oas = 32,
.ias = 32,
- .quirks = IO_PGTABLE_QUIRK_ARM_NS | IO_PGTABLE_QUIRK_NO_DMA,
+ .coherent_walk = true,
+ .quirks = IO_PGTABLE_QUIRK_ARM_NS,
.pgsize_bitmap = SZ_4K | SZ_64K | SZ_1M | SZ_16M,
};
unsigned int iova, size, iova_start;
diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
index 4e21efbc4459..161a7d56264d 100644
--- a/drivers/iommu/io-pgtable-arm.c
+++ b/drivers/iommu/io-pgtable-arm.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* CPU-agnostic ARM page table allocator.
*
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
* Copyright (C) 2014 ARM Limited
*
* Author: Will Deacon <will.deacon@arm.com>
@@ -167,10 +156,12 @@
#define ARM_LPAE_MAIR_ATTR_MASK 0xff
#define ARM_LPAE_MAIR_ATTR_DEVICE 0x04
#define ARM_LPAE_MAIR_ATTR_NC 0x44
+#define ARM_LPAE_MAIR_ATTR_INC_OWBRWA 0xf4
#define ARM_LPAE_MAIR_ATTR_WBRWA 0xff
#define ARM_LPAE_MAIR_ATTR_IDX_NC 0
#define ARM_LPAE_MAIR_ATTR_IDX_CACHE 1
#define ARM_LPAE_MAIR_ATTR_IDX_DEV 2
+#define ARM_LPAE_MAIR_ATTR_IDX_INC_OCACHE 3
#define ARM_MALI_LPAE_TTBR_ADRMODE_TABLE (3u << 0)
#define ARM_MALI_LPAE_TTBR_READ_INNER BIT(2)
@@ -250,7 +241,7 @@ static void *__arm_lpae_alloc_pages(size_t size, gfp_t gfp,
return NULL;
pages = page_address(p);
- if (!(cfg->quirks & IO_PGTABLE_QUIRK_NO_DMA)) {
+ if (!cfg->coherent_walk) {
dma = dma_map_single(dev, pages, size, DMA_TO_DEVICE);
if (dma_mapping_error(dev, dma))
goto out_free;
@@ -276,7 +267,7 @@ out_free:
static void __arm_lpae_free_pages(void *pages, size_t size,
struct io_pgtable_cfg *cfg)
{
- if (!(cfg->quirks & IO_PGTABLE_QUIRK_NO_DMA))
+ if (!cfg->coherent_walk)
dma_unmap_single(cfg->iommu_dev, __arm_lpae_dma_addr(pages),
size, DMA_TO_DEVICE);
free_pages((unsigned long)pages, get_order(size));
@@ -294,7 +285,7 @@ static void __arm_lpae_set_pte(arm_lpae_iopte *ptep, arm_lpae_iopte pte,
{
*ptep = pte;
- if (!(cfg->quirks & IO_PGTABLE_QUIRK_NO_DMA))
+ if (!cfg->coherent_walk)
__arm_lpae_sync_pte(ptep, cfg);
}
@@ -372,8 +363,7 @@ static arm_lpae_iopte arm_lpae_install_table(arm_lpae_iopte *table,
old = cmpxchg64_relaxed(ptep, curr, new);
- if ((cfg->quirks & IO_PGTABLE_QUIRK_NO_DMA) ||
- (old & ARM_LPAE_PTE_SW_SYNC))
+ if (cfg->coherent_walk || (old & ARM_LPAE_PTE_SW_SYNC))
return old;
/* Even if it's not ours, there's no point waiting; just kick it */
@@ -414,8 +404,7 @@ static int __arm_lpae_map(struct arm_lpae_io_pgtable *data, unsigned long iova,
pte = arm_lpae_install_table(cptep, ptep, 0, cfg);
if (pte)
__arm_lpae_free_pages(cptep, tblsz, cfg);
- } else if (!(cfg->quirks & IO_PGTABLE_QUIRK_NO_DMA) &&
- !(pte & ARM_LPAE_PTE_SW_SYNC)) {
+ } else if (!cfg->coherent_walk && !(pte & ARM_LPAE_PTE_SW_SYNC)) {
__arm_lpae_sync_pte(ptep, cfg);
}
@@ -470,6 +459,9 @@ static arm_lpae_iopte arm_lpae_prot_to_pte(struct arm_lpae_io_pgtable *data,
else if (prot & IOMMU_CACHE)
pte |= (ARM_LPAE_MAIR_ATTR_IDX_CACHE
<< ARM_LPAE_PTE_ATTRINDX_SHIFT);
+ else if (prot & IOMMU_QCOM_SYS_CACHE)
+ pte |= (ARM_LPAE_MAIR_ATTR_IDX_INC_OCACHE
+ << ARM_LPAE_PTE_ATTRINDX_SHIFT);
}
if (prot & IOMMU_NOEXEC)
@@ -794,7 +786,7 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie)
u64 reg;
struct arm_lpae_io_pgtable *data;
- if (cfg->quirks & ~(IO_PGTABLE_QUIRK_ARM_NS | IO_PGTABLE_QUIRK_NO_DMA |
+ if (cfg->quirks & ~(IO_PGTABLE_QUIRK_ARM_NS |
IO_PGTABLE_QUIRK_NON_STRICT))
return NULL;
@@ -803,9 +795,15 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie)
return NULL;
/* TCR */
- reg = (ARM_LPAE_TCR_SH_IS << ARM_LPAE_TCR_SH0_SHIFT) |
- (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_IRGN0_SHIFT) |
- (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_ORGN0_SHIFT);
+ if (cfg->coherent_walk) {
+ reg = (ARM_LPAE_TCR_SH_IS << ARM_LPAE_TCR_SH0_SHIFT) |
+ (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_IRGN0_SHIFT) |
+ (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_ORGN0_SHIFT);
+ } else {
+ reg = (ARM_LPAE_TCR_SH_OS << ARM_LPAE_TCR_SH0_SHIFT) |
+ (ARM_LPAE_TCR_RGN_NC << ARM_LPAE_TCR_IRGN0_SHIFT) |
+ (ARM_LPAE_TCR_RGN_NC << ARM_LPAE_TCR_ORGN0_SHIFT);
+ }
switch (ARM_LPAE_GRANULE(data)) {
case SZ_4K:
@@ -857,7 +855,9 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie)
(ARM_LPAE_MAIR_ATTR_WBRWA
<< ARM_LPAE_MAIR_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_CACHE)) |
(ARM_LPAE_MAIR_ATTR_DEVICE
- << ARM_LPAE_MAIR_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_DEV));
+ << ARM_LPAE_MAIR_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_DEV)) |
+ (ARM_LPAE_MAIR_ATTR_INC_OWBRWA
+ << ARM_LPAE_MAIR_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_INC_OCACHE));
cfg->arm_lpae_s1_cfg.mair[0] = reg;
cfg->arm_lpae_s1_cfg.mair[1] = 0;
@@ -887,8 +887,7 @@ arm_64_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie)
struct arm_lpae_io_pgtable *data;
/* The NS quirk doesn't apply at stage 2 */
- if (cfg->quirks & ~(IO_PGTABLE_QUIRK_NO_DMA |
- IO_PGTABLE_QUIRK_NON_STRICT))
+ if (cfg->quirks & ~(IO_PGTABLE_QUIRK_NON_STRICT))
return NULL;
data = arm_lpae_alloc_pgtable(cfg);
@@ -1223,7 +1222,7 @@ static int __init arm_lpae_do_selftests(void)
struct io_pgtable_cfg cfg = {
.tlb = &dummy_tlb_ops,
.oas = 48,
- .quirks = IO_PGTABLE_QUIRK_NO_DMA,
+ .coherent_walk = true,
};
for (i = 0; i < ARRAY_SIZE(pgsize); ++i) {
diff --git a/drivers/iommu/io-pgtable.c b/drivers/iommu/io-pgtable.c
index 5227cfdbb65b..ced53e5b72b5 100644
--- a/drivers/iommu/io-pgtable.c
+++ b/drivers/iommu/io-pgtable.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic page table allocator for IOMMUs.
*
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
* Copyright (C) 2014 ARM Limited
*
* Author: Will Deacon <will.deacon@arm.com>
diff --git a/drivers/iommu/iommu-sysfs.c b/drivers/iommu/iommu-sysfs.c
index 44127d54e943..e436ff813e7e 100644
--- a/drivers/iommu/iommu-sysfs.c
+++ b/drivers/iommu/iommu-sysfs.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* IOMMU sysfs class support
*
* Copyright (C) 2014 Red Hat, Inc. All rights reserved.
* Author: Alex Williamson <alex.williamson@redhat.com>
- *
- * 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.
*/
#include <linux/device.h>
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 9f0a2844371c..0c674d80c37f 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -61,10 +61,11 @@ struct iommu_group_attribute {
};
static const char * const iommu_group_resv_type_string[] = {
- [IOMMU_RESV_DIRECT] = "direct",
- [IOMMU_RESV_RESERVED] = "reserved",
- [IOMMU_RESV_MSI] = "msi",
- [IOMMU_RESV_SW_MSI] = "msi",
+ [IOMMU_RESV_DIRECT] = "direct",
+ [IOMMU_RESV_DIRECT_RELAXABLE] = "direct-relaxable",
+ [IOMMU_RESV_RESERVED] = "reserved",
+ [IOMMU_RESV_MSI] = "msi",
+ [IOMMU_RESV_SW_MSI] = "msi",
};
#define IOMMU_GROUP_ATTR(_name, _mode, _show, _store) \
@@ -95,15 +96,43 @@ void iommu_device_unregister(struct iommu_device *iommu)
spin_unlock(&iommu_device_lock);
}
+static struct iommu_param *iommu_get_dev_param(struct device *dev)
+{
+ struct iommu_param *param = dev->iommu_param;
+
+ if (param)
+ return param;
+
+ param = kzalloc(sizeof(*param), GFP_KERNEL);
+ if (!param)
+ return NULL;
+
+ mutex_init(&param->lock);
+ dev->iommu_param = param;
+ return param;
+}
+
+static void iommu_free_dev_param(struct device *dev)
+{
+ kfree(dev->iommu_param);
+ dev->iommu_param = NULL;
+}
+
int iommu_probe_device(struct device *dev)
{
const struct iommu_ops *ops = dev->bus->iommu_ops;
- int ret = -EINVAL;
+ int ret;
WARN_ON(dev->iommu_group);
+ if (!ops)
+ return -EINVAL;
- if (ops)
- ret = ops->add_device(dev);
+ if (!iommu_get_dev_param(dev))
+ return -ENOMEM;
+
+ ret = ops->add_device(dev);
+ if (ret)
+ iommu_free_dev_param(dev);
return ret;
}
@@ -114,6 +143,8 @@ void iommu_release_device(struct device *dev)
if (dev->iommu_group)
ops->remove_device(dev);
+
+ iommu_free_dev_param(dev);
}
static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus,
@@ -225,18 +256,21 @@ static int iommu_insert_resv_region(struct iommu_resv_region *new,
pos = pos->next;
} else if ((start >= a) && (end <= b)) {
if (new->type == type)
- goto done;
+ return 0;
else
pos = pos->next;
} else {
if (new->type == type) {
phys_addr_t new_start = min(a, start);
phys_addr_t new_end = max(b, end);
+ int ret;
list_del(&entry->list);
entry->start = new_start;
entry->length = new_end - new_start + 1;
- iommu_insert_resv_region(entry, regions);
+ ret = iommu_insert_resv_region(entry, regions);
+ kfree(entry);
+ return ret;
} else {
pos = pos->next;
}
@@ -249,7 +283,6 @@ insert:
return -ENOMEM;
list_add_tail(&region->list, pos);
-done:
return 0;
}
@@ -561,7 +594,8 @@ static int iommu_group_create_direct_mappings(struct iommu_group *group,
start = ALIGN(entry->start, pg_size);
end = ALIGN(entry->start + entry->length, pg_size);
- if (entry->type != IOMMU_RESV_DIRECT)
+ if (entry->type != IOMMU_RESV_DIRECT &&
+ entry->type != IOMMU_RESV_DIRECT_RELAXABLE)
continue;
for (addr = start; addr < end; addr += pg_size) {
@@ -843,6 +877,206 @@ int iommu_group_unregister_notifier(struct iommu_group *group,
EXPORT_SYMBOL_GPL(iommu_group_unregister_notifier);
/**
+ * iommu_register_device_fault_handler() - Register a device fault handler
+ * @dev: the device
+ * @handler: the fault handler
+ * @data: private data passed as argument to the handler
+ *
+ * When an IOMMU fault event is received, this handler gets called with the
+ * fault event and data as argument. The handler should return 0 on success. If
+ * the fault is recoverable (IOMMU_FAULT_PAGE_REQ), the consumer should also
+ * complete the fault by calling iommu_page_response() with one of the following
+ * response code:
+ * - IOMMU_PAGE_RESP_SUCCESS: retry the translation
+ * - IOMMU_PAGE_RESP_INVALID: terminate the fault
+ * - IOMMU_PAGE_RESP_FAILURE: terminate the fault and stop reporting
+ * page faults if possible.
+ *
+ * Return 0 if the fault handler was installed successfully, or an error.
+ */
+int iommu_register_device_fault_handler(struct device *dev,
+ iommu_dev_fault_handler_t handler,
+ void *data)
+{
+ struct iommu_param *param = dev->iommu_param;
+ int ret = 0;
+
+ if (!param)
+ return -EINVAL;
+
+ mutex_lock(&param->lock);
+ /* Only allow one fault handler registered for each device */
+ if (param->fault_param) {
+ ret = -EBUSY;
+ goto done_unlock;
+ }
+
+ get_device(dev);
+ param->fault_param = kzalloc(sizeof(*param->fault_param), GFP_KERNEL);
+ if (!param->fault_param) {
+ put_device(dev);
+ ret = -ENOMEM;
+ goto done_unlock;
+ }
+ param->fault_param->handler = handler;
+ param->fault_param->data = data;
+ mutex_init(&param->fault_param->lock);
+ INIT_LIST_HEAD(&param->fault_param->faults);
+
+done_unlock:
+ mutex_unlock(&param->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(iommu_register_device_fault_handler);
+
+/**
+ * iommu_unregister_device_fault_handler() - Unregister the device fault handler
+ * @dev: the device
+ *
+ * Remove the device fault handler installed with
+ * iommu_register_device_fault_handler().
+ *
+ * Return 0 on success, or an error.
+ */
+int iommu_unregister_device_fault_handler(struct device *dev)
+{
+ struct iommu_param *param = dev->iommu_param;
+ int ret = 0;
+
+ if (!param)
+ return -EINVAL;
+
+ mutex_lock(&param->lock);
+
+ if (!param->fault_param)
+ goto unlock;
+
+ /* we cannot unregister handler if there are pending faults */
+ if (!list_empty(&param->fault_param->faults)) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ kfree(param->fault_param);
+ param->fault_param = NULL;
+ put_device(dev);
+unlock:
+ mutex_unlock(&param->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(iommu_unregister_device_fault_handler);
+
+/**
+ * iommu_report_device_fault() - Report fault event to device driver
+ * @dev: the device
+ * @evt: fault event data
+ *
+ * Called by IOMMU drivers when a fault is detected, typically in a threaded IRQ
+ * handler. When this function fails and the fault is recoverable, it is the
+ * caller's responsibility to complete the fault.
+ *
+ * Return 0 on success, or an error.
+ */
+int iommu_report_device_fault(struct device *dev, struct iommu_fault_event *evt)
+{
+ struct iommu_param *param = dev->iommu_param;
+ struct iommu_fault_event *evt_pending = NULL;
+ struct iommu_fault_param *fparam;
+ int ret = 0;
+
+ if (!param || !evt)
+ return -EINVAL;
+
+ /* we only report device fault if there is a handler registered */
+ mutex_lock(&param->lock);
+ fparam = param->fault_param;
+ if (!fparam || !fparam->handler) {
+ ret = -EINVAL;
+ goto done_unlock;
+ }
+
+ if (evt->fault.type == IOMMU_FAULT_PAGE_REQ &&
+ (evt->fault.prm.flags & IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE)) {
+ evt_pending = kmemdup(evt, sizeof(struct iommu_fault_event),
+ GFP_KERNEL);
+ if (!evt_pending) {
+ ret = -ENOMEM;
+ goto done_unlock;
+ }
+ mutex_lock(&fparam->lock);
+ list_add_tail(&evt_pending->list, &fparam->faults);
+ mutex_unlock(&fparam->lock);
+ }
+
+ ret = fparam->handler(&evt->fault, fparam->data);
+ if (ret && evt_pending) {
+ mutex_lock(&fparam->lock);
+ list_del(&evt_pending->list);
+ mutex_unlock(&fparam->lock);
+ kfree(evt_pending);
+ }
+done_unlock:
+ mutex_unlock(&param->lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(iommu_report_device_fault);
+
+int iommu_page_response(struct device *dev,
+ struct iommu_page_response *msg)
+{
+ bool pasid_valid;
+ int ret = -EINVAL;
+ struct iommu_fault_event *evt;
+ struct iommu_fault_page_request *prm;
+ struct iommu_param *param = dev->iommu_param;
+ struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
+
+ if (!domain || !domain->ops->page_response)
+ return -ENODEV;
+
+ if (!param || !param->fault_param)
+ return -EINVAL;
+
+ if (msg->version != IOMMU_PAGE_RESP_VERSION_1 ||
+ msg->flags & ~IOMMU_PAGE_RESP_PASID_VALID)
+ return -EINVAL;
+
+ /* Only send response if there is a fault report pending */
+ mutex_lock(&param->fault_param->lock);
+ if (list_empty(&param->fault_param->faults)) {
+ dev_warn_ratelimited(dev, "no pending PRQ, drop response\n");
+ goto done_unlock;
+ }
+ /*
+ * Check if we have a matching page request pending to respond,
+ * otherwise return -EINVAL
+ */
+ list_for_each_entry(evt, &param->fault_param->faults, list) {
+ prm = &evt->fault.prm;
+ pasid_valid = prm->flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID;
+
+ if ((pasid_valid && prm->pasid != msg->pasid) ||
+ prm->grpid != msg->grpid)
+ continue;
+
+ /* Sanitize the reply */
+ msg->flags = pasid_valid ? IOMMU_PAGE_RESP_PASID_VALID : 0;
+
+ ret = domain->ops->page_response(dev, evt, msg);
+ list_del(&evt->list);
+ kfree(evt);
+ break;
+ }
+
+done_unlock:
+ mutex_unlock(&param->fault_param->lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(iommu_page_response);
+
+/**
* iommu_group_id - Return ID for a group
* @group: the group to ID
*
@@ -1895,24 +2129,23 @@ struct iommu_resv_region *iommu_alloc_resv_region(phys_addr_t start,
return region;
}
-/* Request that a device is direct mapped by the IOMMU */
-int iommu_request_dm_for_dev(struct device *dev)
+static int
+request_default_domain_for_dev(struct device *dev, unsigned long type)
{
- struct iommu_domain *dm_domain;
+ struct iommu_domain *domain;
struct iommu_group *group;
int ret;
/* Device must already be in a group before calling this function */
- group = iommu_group_get_for_dev(dev);
- if (IS_ERR(group))
- return PTR_ERR(group);
+ group = iommu_group_get(dev);
+ if (!group)
+ return -EINVAL;
mutex_lock(&group->mutex);
/* Check if the default domain is already direct mapped */
ret = 0;
- if (group->default_domain &&
- group->default_domain->type == IOMMU_DOMAIN_IDENTITY)
+ if (group->default_domain && group->default_domain->type == type)
goto out;
/* Don't change mappings of existing devices */
@@ -1922,23 +2155,26 @@ int iommu_request_dm_for_dev(struct device *dev)
/* Allocate a direct mapped domain */
ret = -ENOMEM;
- dm_domain = __iommu_domain_alloc(dev->bus, IOMMU_DOMAIN_IDENTITY);
- if (!dm_domain)
+ domain = __iommu_domain_alloc(dev->bus, type);
+ if (!domain)
goto out;
/* Attach the device to the domain */
- ret = __iommu_attach_group(dm_domain, group);
+ ret = __iommu_attach_group(domain, group);
if (ret) {
- iommu_domain_free(dm_domain);
+ iommu_domain_free(domain);
goto out;
}
+ iommu_group_create_direct_mappings(group, dev);
+
/* Make the direct mapped domain the default for this group */
if (group->default_domain)
iommu_domain_free(group->default_domain);
- group->default_domain = dm_domain;
+ group->default_domain = domain;
- dev_info(dev, "Using iommu direct mapping\n");
+ dev_info(dev, "Using iommu %s mapping\n",
+ type == IOMMU_DOMAIN_DMA ? "dma" : "direct");
ret = 0;
out:
@@ -1948,6 +2184,18 @@ out:
return ret;
}
+/* Request that a device is direct mapped by the IOMMU */
+int iommu_request_dm_for_dev(struct device *dev)
+{
+ return request_default_domain_for_dev(dev, IOMMU_DOMAIN_IDENTITY);
+}
+
+/* Request that a device can't be direct mapped by the IOMMU */
+int iommu_request_dma_domain_for_dev(struct device *dev)
+{
+ return request_default_domain_for_dev(dev, IOMMU_DOMAIN_DMA);
+}
+
const struct iommu_ops *iommu_ops_from_fwnode(struct fwnode_handle *fwnode)
{
const struct iommu_ops *ops = NULL;
diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c
index 9a380c10655e..ad0098c0c87c 100644
--- a/drivers/iommu/ipmmu-vmsa.c
+++ b/drivers/iommu/ipmmu-vmsa.c
@@ -36,12 +36,16 @@
#define arm_iommu_detach_device(...) do {} while (0)
#endif
-#define IPMMU_CTX_MAX 8
+#define IPMMU_CTX_MAX 8U
+#define IPMMU_CTX_INVALID -1
+
+#define IPMMU_UTLB_MAX 48U
struct ipmmu_features {
bool use_ns_alias_offset;
bool has_cache_leaf_nodes;
unsigned int number_of_contexts;
+ unsigned int num_utlbs;
bool setup_imbuscr;
bool twobit_imttbcr_sl0;
bool reserved_context;
@@ -53,11 +57,11 @@ struct ipmmu_vmsa_device {
struct iommu_device iommu;
struct ipmmu_vmsa_device *root;
const struct ipmmu_features *features;
- unsigned int num_utlbs;
unsigned int num_ctx;
spinlock_t lock; /* Protects ctx and domains[] */
DECLARE_BITMAP(ctx, IPMMU_CTX_MAX);
struct ipmmu_vmsa_domain *domains[IPMMU_CTX_MAX];
+ s8 utlb_ctx[IPMMU_UTLB_MAX];
struct iommu_group *group;
struct dma_iommu_mapping *mapping;
@@ -186,7 +190,8 @@ static struct ipmmu_vmsa_device *to_ipmmu(struct device *dev)
#define IMMAIR_ATTR_IDX_WBRWA 1
#define IMMAIR_ATTR_IDX_DEV 2
-#define IMEAR 0x0030
+#define IMELAR 0x0030 /* IMEAR on R-Car Gen2 */
+#define IMEUAR 0x0034 /* R-Car Gen3 only */
#define IMPCTR 0x0200
#define IMPSTR 0x0208
@@ -334,6 +339,7 @@ static void ipmmu_utlb_enable(struct ipmmu_vmsa_domain *domain,
ipmmu_write(mmu, IMUCTR(utlb),
IMUCTR_TTSEL_MMU(domain->context_id) | IMUCTR_FLUSH |
IMUCTR_MMUEN);
+ mmu->utlb_ctx[utlb] = domain->context_id;
}
/*
@@ -345,6 +351,7 @@ static void ipmmu_utlb_disable(struct ipmmu_vmsa_domain *domain,
struct ipmmu_vmsa_device *mmu = domain->mmu;
ipmmu_write(mmu, IMUCTR(utlb), 0);
+ mmu->utlb_ctx[utlb] = IPMMU_CTX_INVALID;
}
static void ipmmu_tlb_flush_all(void *cookie)
@@ -403,52 +410,10 @@ static void ipmmu_domain_free_context(struct ipmmu_vmsa_device *mmu,
spin_unlock_irqrestore(&mmu->lock, flags);
}
-static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain)
+static void ipmmu_domain_setup_context(struct ipmmu_vmsa_domain *domain)
{
u64 ttbr;
u32 tmp;
- int ret;
-
- /*
- * Allocate the page table operations.
- *
- * VMSA states in section B3.6.3 "Control of Secure or Non-secure memory
- * access, Long-descriptor format" that the NStable bit being set in a
- * table descriptor will result in the NStable and NS bits of all child
- * entries being ignored and considered as being set. The IPMMU seems
- * not to comply with this, as it generates a secure access page fault
- * if any of the NStable and NS bits isn't set when running in
- * non-secure mode.
- */
- domain->cfg.quirks = IO_PGTABLE_QUIRK_ARM_NS;
- domain->cfg.pgsize_bitmap = SZ_1G | SZ_2M | SZ_4K;
- domain->cfg.ias = 32;
- domain->cfg.oas = 40;
- domain->cfg.tlb = &ipmmu_gather_ops;
- domain->io_domain.geometry.aperture_end = DMA_BIT_MASK(32);
- domain->io_domain.geometry.force_aperture = true;
- /*
- * TODO: Add support for coherent walk through CCI with DVM and remove
- * cache handling. For now, delegate it to the io-pgtable code.
- */
- domain->cfg.iommu_dev = domain->mmu->root->dev;
-
- /*
- * Find an unused context.
- */
- ret = ipmmu_domain_allocate_context(domain->mmu->root, domain);
- if (ret < 0)
- return ret;
-
- domain->context_id = ret;
-
- domain->iop = alloc_io_pgtable_ops(ARM_32_LPAE_S1, &domain->cfg,
- domain);
- if (!domain->iop) {
- ipmmu_domain_free_context(domain->mmu->root,
- domain->context_id);
- return -EINVAL;
- }
/* TTBR0 */
ttbr = domain->cfg.arm_lpae_s1_cfg.ttbr[0];
@@ -494,7 +459,55 @@ static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain)
*/
ipmmu_ctx_write_all(domain, IMCTR,
IMCTR_INTEN | IMCTR_FLUSH | IMCTR_MMUEN);
+}
+
+static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain)
+{
+ int ret;
+
+ /*
+ * Allocate the page table operations.
+ *
+ * VMSA states in section B3.6.3 "Control of Secure or Non-secure memory
+ * access, Long-descriptor format" that the NStable bit being set in a
+ * table descriptor will result in the NStable and NS bits of all child
+ * entries being ignored and considered as being set. The IPMMU seems
+ * not to comply with this, as it generates a secure access page fault
+ * if any of the NStable and NS bits isn't set when running in
+ * non-secure mode.
+ */
+ domain->cfg.quirks = IO_PGTABLE_QUIRK_ARM_NS;
+ domain->cfg.pgsize_bitmap = SZ_1G | SZ_2M | SZ_4K;
+ domain->cfg.ias = 32;
+ domain->cfg.oas = 40;
+ domain->cfg.tlb = &ipmmu_gather_ops;
+ domain->io_domain.geometry.aperture_end = DMA_BIT_MASK(32);
+ domain->io_domain.geometry.force_aperture = true;
+ /*
+ * TODO: Add support for coherent walk through CCI with DVM and remove
+ * cache handling. For now, delegate it to the io-pgtable code.
+ */
+ domain->cfg.coherent_walk = false;
+ domain->cfg.iommu_dev = domain->mmu->root->dev;
+
+ /*
+ * Find an unused context.
+ */
+ ret = ipmmu_domain_allocate_context(domain->mmu->root, domain);
+ if (ret < 0)
+ return ret;
+
+ domain->context_id = ret;
+
+ domain->iop = alloc_io_pgtable_ops(ARM_32_LPAE_S1, &domain->cfg,
+ domain);
+ if (!domain->iop) {
+ ipmmu_domain_free_context(domain->mmu->root,
+ domain->context_id);
+ return -EINVAL;
+ }
+ ipmmu_domain_setup_context(domain);
return 0;
}
@@ -522,14 +535,16 @@ static irqreturn_t ipmmu_domain_irq(struct ipmmu_vmsa_domain *domain)
{
const u32 err_mask = IMSTR_MHIT | IMSTR_ABORT | IMSTR_PF | IMSTR_TF;
struct ipmmu_vmsa_device *mmu = domain->mmu;
+ unsigned long iova;
u32 status;
- u32 iova;
status = ipmmu_ctx_read_root(domain, IMSTR);
if (!(status & err_mask))
return IRQ_NONE;
- iova = ipmmu_ctx_read_root(domain, IMEAR);
+ iova = ipmmu_ctx_read_root(domain, IMELAR);
+ if (IS_ENABLED(CONFIG_64BIT))
+ iova |= (u64)ipmmu_ctx_read_root(domain, IMEUAR) << 32;
/*
* Clear the error status flags. Unlike traditional interrupt flag
@@ -541,10 +556,10 @@ static irqreturn_t ipmmu_domain_irq(struct ipmmu_vmsa_domain *domain)
/* Log fatal errors. */
if (status & IMSTR_MHIT)
- dev_err_ratelimited(mmu->dev, "Multiple TLB hits @0x%08x\n",
+ dev_err_ratelimited(mmu->dev, "Multiple TLB hits @0x%lx\n",
iova);
if (status & IMSTR_ABORT)
- dev_err_ratelimited(mmu->dev, "Page Table Walk Abort @0x%08x\n",
+ dev_err_ratelimited(mmu->dev, "Page Table Walk Abort @0x%lx\n",
iova);
if (!(status & (IMSTR_PF | IMSTR_TF)))
@@ -560,7 +575,7 @@ static irqreturn_t ipmmu_domain_irq(struct ipmmu_vmsa_domain *domain)
return IRQ_HANDLED;
dev_err_ratelimited(mmu->dev,
- "Unhandled fault: status 0x%08x iova 0x%08x\n",
+ "Unhandled fault: status 0x%08x iova 0x%lx\n",
status, iova);
return IRQ_HANDLED;
@@ -885,27 +900,37 @@ error:
static int ipmmu_add_device(struct device *dev)
{
+ struct ipmmu_vmsa_device *mmu = to_ipmmu(dev);
struct iommu_group *group;
+ int ret;
/*
* Only let through devices that have been verified in xlate()
*/
- if (!to_ipmmu(dev))
+ if (!mmu)
return -ENODEV;
- if (IS_ENABLED(CONFIG_ARM) && !IS_ENABLED(CONFIG_IOMMU_DMA))
- return ipmmu_init_arm_mapping(dev);
+ if (IS_ENABLED(CONFIG_ARM) && !IS_ENABLED(CONFIG_IOMMU_DMA)) {
+ ret = ipmmu_init_arm_mapping(dev);
+ if (ret)
+ return ret;
+ } else {
+ group = iommu_group_get_for_dev(dev);
+ if (IS_ERR(group))
+ return PTR_ERR(group);
- group = iommu_group_get_for_dev(dev);
- if (IS_ERR(group))
- return PTR_ERR(group);
+ iommu_group_put(group);
+ }
- iommu_group_put(group);
+ iommu_device_link(&mmu->iommu, dev);
return 0;
}
static void ipmmu_remove_device(struct device *dev)
{
+ struct ipmmu_vmsa_device *mmu = to_ipmmu(dev);
+
+ iommu_device_unlink(&mmu->iommu, dev);
arm_iommu_detach_device(dev);
iommu_group_remove_device(dev);
}
@@ -959,6 +984,7 @@ static const struct ipmmu_features ipmmu_features_default = {
.use_ns_alias_offset = true,
.has_cache_leaf_nodes = false,
.number_of_contexts = 1, /* software only tested with one context */
+ .num_utlbs = 32,
.setup_imbuscr = true,
.twobit_imttbcr_sl0 = false,
.reserved_context = false,
@@ -968,6 +994,7 @@ static const struct ipmmu_features ipmmu_features_rcar_gen3 = {
.use_ns_alias_offset = false,
.has_cache_leaf_nodes = true,
.number_of_contexts = 8,
+ .num_utlbs = 48,
.setup_imbuscr = false,
.twobit_imttbcr_sl0 = true,
.reserved_context = true,
@@ -1020,10 +1047,10 @@ static int ipmmu_probe(struct platform_device *pdev)
}
mmu->dev = &pdev->dev;
- mmu->num_utlbs = 48;
spin_lock_init(&mmu->lock);
bitmap_zero(mmu->ctx, IPMMU_CTX_MAX);
mmu->features = of_device_get_match_data(&pdev->dev);
+ memset(mmu->utlb_ctx, IPMMU_CTX_INVALID, mmu->features->num_utlbs);
dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40));
/* Map I/O memory and request IRQ. */
@@ -1047,8 +1074,7 @@ static int ipmmu_probe(struct platform_device *pdev)
if (mmu->features->use_ns_alias_offset)
mmu->base += IM_NS_ALIAS_OFFSET;
- mmu->num_ctx = min_t(unsigned int, IPMMU_CTX_MAX,
- mmu->features->number_of_contexts);
+ mmu->num_ctx = min(IPMMU_CTX_MAX, mmu->features->number_of_contexts);
irq = platform_get_irq(pdev, 0);
@@ -1140,10 +1166,48 @@ static int ipmmu_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int ipmmu_resume_noirq(struct device *dev)
+{
+ struct ipmmu_vmsa_device *mmu = dev_get_drvdata(dev);
+ unsigned int i;
+
+ /* Reset root MMU and restore contexts */
+ if (ipmmu_is_root(mmu)) {
+ ipmmu_device_reset(mmu);
+
+ for (i = 0; i < mmu->num_ctx; i++) {
+ if (!mmu->domains[i])
+ continue;
+
+ ipmmu_domain_setup_context(mmu->domains[i]);
+ }
+ }
+
+ /* Re-enable active micro-TLBs */
+ for (i = 0; i < mmu->features->num_utlbs; i++) {
+ if (mmu->utlb_ctx[i] == IPMMU_CTX_INVALID)
+ continue;
+
+ ipmmu_utlb_enable(mmu->root->domains[mmu->utlb_ctx[i]], i);
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops ipmmu_pm = {
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, ipmmu_resume_noirq)
+};
+#define DEV_PM_OPS &ipmmu_pm
+#else
+#define DEV_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
static struct platform_driver ipmmu_driver = {
.driver = {
.name = "ipmmu-vmsa",
.of_match_table = of_match_ptr(ipmmu_of_ids),
+ .pm = DEV_PM_OPS,
},
.probe = ipmmu_probe,
.remove = ipmmu_remove,
diff --git a/drivers/iommu/omap-iommu-debug.c b/drivers/iommu/omap-iommu-debug.c
index 4abc0ef522a8..8e19bfa94121 100644
--- a/drivers/iommu/omap-iommu-debug.c
+++ b/drivers/iommu/omap-iommu-debug.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* omap iommu: debugfs interface
*
* Copyright (C) 2008-2009 Nokia Corporation
*
* Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
- *
- * 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.
*/
#include <linux/err.h>
@@ -239,17 +236,6 @@ DEBUG_FOPS_RO(regs);
DEFINE_SHOW_ATTRIBUTE(tlb);
DEFINE_SHOW_ATTRIBUTE(pagetable);
-#define __DEBUG_ADD_FILE(attr, mode) \
- { \
- struct dentry *dent; \
- dent = debugfs_create_file(#attr, mode, obj->debug_dir, \
- obj, &attr##_fops); \
- if (!dent) \
- goto err; \
- }
-
-#define DEBUG_ADD_FILE_RO(name) __DEBUG_ADD_FILE(name, 0400)
-
void omap_iommu_debugfs_add(struct omap_iommu *obj)
{
struct dentry *d;
@@ -257,23 +243,13 @@ void omap_iommu_debugfs_add(struct omap_iommu *obj)
if (!iommu_debug_root)
return;
- obj->debug_dir = debugfs_create_dir(obj->name, iommu_debug_root);
- if (!obj->debug_dir)
- return;
-
- d = debugfs_create_u32("nr_tlb_entries", 0400, obj->debug_dir,
- &obj->nr_tlb_entries);
- if (!d)
- return;
-
- DEBUG_ADD_FILE_RO(regs);
- DEBUG_ADD_FILE_RO(tlb);
- DEBUG_ADD_FILE_RO(pagetable);
+ d = debugfs_create_dir(obj->name, iommu_debug_root);
+ obj->debug_dir = d;
- return;
-
-err:
- debugfs_remove_recursive(obj->debug_dir);
+ debugfs_create_u32("nr_tlb_entries", 0400, d, &obj->nr_tlb_entries);
+ debugfs_create_file("regs", 0400, d, obj, &regs_fops);
+ debugfs_create_file("tlb", 0400, d, obj, &tlb_fops);
+ debugfs_create_file("pagetable", 0400, d, obj, &pagetable_fops);
}
void omap_iommu_debugfs_remove(struct omap_iommu *obj)
@@ -287,8 +263,6 @@ void omap_iommu_debugfs_remove(struct omap_iommu *obj)
void __init omap_iommu_debugfs_init(void)
{
iommu_debug_root = debugfs_create_dir("omap_iommu", NULL);
- if (!iommu_debug_root)
- pr_err("can't create debugfs dir\n");
}
void __exit omap_iommu_debugfs_exit(void)
diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
index d2fb347aa4ff..dfb961d8c21b 100644
--- a/drivers/iommu/omap-iommu.c
+++ b/drivers/iommu/omap-iommu.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* omap iommu: tlb and pagetable primitives
*
@@ -6,10 +7,6 @@
*
* Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>,
* Paul Mundt and Toshihiro Kobayashi
- *
- * 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.
*/
#include <linux/dma-mapping.h>
@@ -38,8 +35,7 @@
static const struct iommu_ops omap_iommu_ops;
-#define to_iommu(dev) \
- ((struct omap_iommu *)platform_get_drvdata(to_platform_device(dev)))
+#define to_iommu(dev) ((struct omap_iommu *)dev_get_drvdata(dev))
/* bitmap of the page sizes currently supported */
#define OMAP_IOMMU_PGSIZES (SZ_4K | SZ_64K | SZ_1M | SZ_16M)
diff --git a/drivers/iommu/omap-iommu.h b/drivers/iommu/omap-iommu.h
index 1703159ef5af..09968a02d291 100644
--- a/drivers/iommu/omap-iommu.h
+++ b/drivers/iommu/omap-iommu.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* omap iommu: main structures
*
* Copyright (C) 2008-2009 Nokia Corporation
*
* Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
- *
- * 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.
*/
#ifndef _OMAP_IOMMU_H
diff --git a/drivers/iommu/omap-iopgtable.h b/drivers/iommu/omap-iopgtable.h
index 01a315227bf0..1a4adb59a859 100644
--- a/drivers/iommu/omap-iopgtable.h
+++ b/drivers/iommu/omap-iopgtable.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* omap iommu: pagetable definitions
*
* Copyright (C) 2008-2010 Nokia Corporation
*
* Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
- *
- * 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.
*/
#ifndef _OMAP_IOPGTABLE_H
diff --git a/drivers/iommu/qcom_iommu.c b/drivers/iommu/qcom_iommu.c
index 8cdd3f059513..34d0b9783b3e 100644
--- a/drivers/iommu/qcom_iommu.c
+++ b/drivers/iommu/qcom_iommu.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* IOMMU API for QCOM secure IOMMUs. Somewhat based on arm-smmu.c
*
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
* Copyright (C) 2013 ARM Limited
* Copyright (C) 2017 Red Hat
*/
diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index 77d4bd93fe4b..dc26d74d79c2 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* IOMMU API for Rockchip
*
* Module Authors: Simon Xue <xxm@rock-chips.com>
* Daniel Kurtz <djkurtz@chromium.org>
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 463ee08f7d3a..c4a652b227f8 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011-2014 NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/bitops.h>
diff --git a/drivers/iommu/virtio-iommu.c b/drivers/iommu/virtio-iommu.c
new file mode 100644
index 000000000000..433f4d2ee956
--- /dev/null
+++ b/drivers/iommu/virtio-iommu.c
@@ -0,0 +1,1158 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Virtio driver for the paravirtualized IOMMU
+ *
+ * Copyright (C) 2018 Arm Limited
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/amba/bus.h>
+#include <linux/delay.h>
+#include <linux/dma-iommu.h>
+#include <linux/freezer.h>
+#include <linux/interval_tree.h>
+#include <linux/iommu.h>
+#include <linux/module.h>
+#include <linux/of_iommu.h>
+#include <linux/of_platform.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/virtio.h>
+#include <linux/virtio_config.h>
+#include <linux/virtio_ids.h>
+#include <linux/wait.h>
+
+#include <uapi/linux/virtio_iommu.h>
+
+#define MSI_IOVA_BASE 0x8000000
+#define MSI_IOVA_LENGTH 0x100000
+
+#define VIOMMU_REQUEST_VQ 0
+#define VIOMMU_EVENT_VQ 1
+#define VIOMMU_NR_VQS 2
+
+struct viommu_dev {
+ struct iommu_device iommu;
+ struct device *dev;
+ struct virtio_device *vdev;
+
+ struct ida domain_ids;
+
+ struct virtqueue *vqs[VIOMMU_NR_VQS];
+ spinlock_t request_lock;
+ struct list_head requests;
+ void *evts;
+
+ /* Device configuration */
+ struct iommu_domain_geometry geometry;
+ u64 pgsize_bitmap;
+ u8 domain_bits;
+ u32 probe_size;
+};
+
+struct viommu_mapping {
+ phys_addr_t paddr;
+ struct interval_tree_node iova;
+ u32 flags;
+};
+
+struct viommu_domain {
+ struct iommu_domain domain;
+ struct viommu_dev *viommu;
+ struct mutex mutex; /* protects viommu pointer */
+ unsigned int id;
+
+ spinlock_t mappings_lock;
+ struct rb_root_cached mappings;
+
+ unsigned long nr_endpoints;
+};
+
+struct viommu_endpoint {
+ struct device *dev;
+ struct viommu_dev *viommu;
+ struct viommu_domain *vdomain;
+ struct list_head resv_regions;
+};
+
+struct viommu_request {
+ struct list_head list;
+ void *writeback;
+ unsigned int write_offset;
+ unsigned int len;
+ char buf[];
+};
+
+#define VIOMMU_FAULT_RESV_MASK 0xffffff00
+
+struct viommu_event {
+ union {
+ u32 head;
+ struct virtio_iommu_fault fault;
+ };
+};
+
+#define to_viommu_domain(domain) \
+ container_of(domain, struct viommu_domain, domain)
+
+static int viommu_get_req_errno(void *buf, size_t len)
+{
+ struct virtio_iommu_req_tail *tail = buf + len - sizeof(*tail);
+
+ switch (tail->status) {
+ case VIRTIO_IOMMU_S_OK:
+ return 0;
+ case VIRTIO_IOMMU_S_UNSUPP:
+ return -ENOSYS;
+ case VIRTIO_IOMMU_S_INVAL:
+ return -EINVAL;
+ case VIRTIO_IOMMU_S_RANGE:
+ return -ERANGE;
+ case VIRTIO_IOMMU_S_NOENT:
+ return -ENOENT;
+ case VIRTIO_IOMMU_S_FAULT:
+ return -EFAULT;
+ case VIRTIO_IOMMU_S_IOERR:
+ case VIRTIO_IOMMU_S_DEVERR:
+ default:
+ return -EIO;
+ }
+}
+
+static void viommu_set_req_status(void *buf, size_t len, int status)
+{
+ struct virtio_iommu_req_tail *tail = buf + len - sizeof(*tail);
+
+ tail->status = status;
+}
+
+static off_t viommu_get_write_desc_offset(struct viommu_dev *viommu,
+ struct virtio_iommu_req_head *req,
+ size_t len)
+{
+ size_t tail_size = sizeof(struct virtio_iommu_req_tail);
+
+ if (req->type == VIRTIO_IOMMU_T_PROBE)
+ return len - viommu->probe_size - tail_size;
+
+ return len - tail_size;
+}
+
+/*
+ * __viommu_sync_req - Complete all in-flight requests
+ *
+ * Wait for all added requests to complete. When this function returns, all
+ * requests that were in-flight at the time of the call have completed.
+ */
+static int __viommu_sync_req(struct viommu_dev *viommu)
+{
+ int ret = 0;
+ unsigned int len;
+ size_t write_len;
+ struct viommu_request *req;
+ struct virtqueue *vq = viommu->vqs[VIOMMU_REQUEST_VQ];
+
+ assert_spin_locked(&viommu->request_lock);
+
+ virtqueue_kick(vq);
+
+ while (!list_empty(&viommu->requests)) {
+ len = 0;
+ req = virtqueue_get_buf(vq, &len);
+ if (!req)
+ continue;
+
+ if (!len)
+ viommu_set_req_status(req->buf, req->len,
+ VIRTIO_IOMMU_S_IOERR);
+
+ write_len = req->len - req->write_offset;
+ if (req->writeback && len == write_len)
+ memcpy(req->writeback, req->buf + req->write_offset,
+ write_len);
+
+ list_del(&req->list);
+ kfree(req);
+ }
+
+ return ret;
+}
+
+static int viommu_sync_req(struct viommu_dev *viommu)
+{
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&viommu->request_lock, flags);
+ ret = __viommu_sync_req(viommu);
+ if (ret)
+ dev_dbg(viommu->dev, "could not sync requests (%d)\n", ret);
+ spin_unlock_irqrestore(&viommu->request_lock, flags);
+
+ return ret;
+}
+
+/*
+ * __viommu_add_request - Add one request to the queue
+ * @buf: pointer to the request buffer
+ * @len: length of the request buffer
+ * @writeback: copy data back to the buffer when the request completes.
+ *
+ * Add a request to the queue. Only synchronize the queue if it's already full.
+ * Otherwise don't kick the queue nor wait for requests to complete.
+ *
+ * When @writeback is true, data written by the device, including the request
+ * status, is copied into @buf after the request completes. This is unsafe if
+ * the caller allocates @buf on stack and drops the lock between add_req() and
+ * sync_req().
+ *
+ * Return 0 if the request was successfully added to the queue.
+ */
+static int __viommu_add_req(struct viommu_dev *viommu, void *buf, size_t len,
+ bool writeback)
+{
+ int ret;
+ off_t write_offset;
+ struct viommu_request *req;
+ struct scatterlist top_sg, bottom_sg;
+ struct scatterlist *sg[2] = { &top_sg, &bottom_sg };
+ struct virtqueue *vq = viommu->vqs[VIOMMU_REQUEST_VQ];
+
+ assert_spin_locked(&viommu->request_lock);
+
+ write_offset = viommu_get_write_desc_offset(viommu, buf, len);
+ if (write_offset <= 0)
+ return -EINVAL;
+
+ req = kzalloc(sizeof(*req) + len, GFP_ATOMIC);
+ if (!req)
+ return -ENOMEM;
+
+ req->len = len;
+ if (writeback) {
+ req->writeback = buf + write_offset;
+ req->write_offset = write_offset;
+ }
+ memcpy(&req->buf, buf, write_offset);
+
+ sg_init_one(&top_sg, req->buf, write_offset);
+ sg_init_one(&bottom_sg, req->buf + write_offset, len - write_offset);
+
+ ret = virtqueue_add_sgs(vq, sg, 1, 1, req, GFP_ATOMIC);
+ if (ret == -ENOSPC) {
+ /* If the queue is full, sync and retry */
+ if (!__viommu_sync_req(viommu))
+ ret = virtqueue_add_sgs(vq, sg, 1, 1, req, GFP_ATOMIC);
+ }
+ if (ret)
+ goto err_free;
+
+ list_add_tail(&req->list, &viommu->requests);
+ return 0;
+
+err_free:
+ kfree(req);
+ return ret;
+}
+
+static int viommu_add_req(struct viommu_dev *viommu, void *buf, size_t len)
+{
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&viommu->request_lock, flags);
+ ret = __viommu_add_req(viommu, buf, len, false);
+ if (ret)
+ dev_dbg(viommu->dev, "could not add request: %d\n", ret);
+ spin_unlock_irqrestore(&viommu->request_lock, flags);
+
+ return ret;
+}
+
+/*
+ * Send a request and wait for it to complete. Return the request status (as an
+ * errno)
+ */
+static int viommu_send_req_sync(struct viommu_dev *viommu, void *buf,
+ size_t len)
+{
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&viommu->request_lock, flags);
+
+ ret = __viommu_add_req(viommu, buf, len, true);
+ if (ret) {
+ dev_dbg(viommu->dev, "could not add request (%d)\n", ret);
+ goto out_unlock;
+ }
+
+ ret = __viommu_sync_req(viommu);
+ if (ret) {
+ dev_dbg(viommu->dev, "could not sync requests (%d)\n", ret);
+ /* Fall-through (get the actual request status) */
+ }
+
+ ret = viommu_get_req_errno(buf, len);
+out_unlock:
+ spin_unlock_irqrestore(&viommu->request_lock, flags);
+ return ret;
+}
+
+/*
+ * viommu_add_mapping - add a mapping to the internal tree
+ *
+ * On success, return the new mapping. Otherwise return NULL.
+ */
+static int viommu_add_mapping(struct viommu_domain *vdomain, unsigned long iova,
+ phys_addr_t paddr, size_t size, u32 flags)
+{
+ unsigned long irqflags;
+ struct viommu_mapping *mapping;
+
+ mapping = kzalloc(sizeof(*mapping), GFP_ATOMIC);
+ if (!mapping)
+ return -ENOMEM;
+
+ mapping->paddr = paddr;
+ mapping->iova.start = iova;
+ mapping->iova.last = iova + size - 1;
+ mapping->flags = flags;
+
+ spin_lock_irqsave(&vdomain->mappings_lock, irqflags);
+ interval_tree_insert(&mapping->iova, &vdomain->mappings);
+ spin_unlock_irqrestore(&vdomain->mappings_lock, irqflags);
+
+ return 0;
+}
+
+/*
+ * viommu_del_mappings - remove mappings from the internal tree
+ *
+ * @vdomain: the domain
+ * @iova: start of the range
+ * @size: size of the range. A size of 0 corresponds to the entire address
+ * space.
+ *
+ * On success, returns the number of unmapped bytes (>= size)
+ */
+static size_t viommu_del_mappings(struct viommu_domain *vdomain,
+ unsigned long iova, size_t size)
+{
+ size_t unmapped = 0;
+ unsigned long flags;
+ unsigned long last = iova + size - 1;
+ struct viommu_mapping *mapping = NULL;
+ struct interval_tree_node *node, *next;
+
+ spin_lock_irqsave(&vdomain->mappings_lock, flags);
+ next = interval_tree_iter_first(&vdomain->mappings, iova, last);
+ while (next) {
+ node = next;
+ mapping = container_of(node, struct viommu_mapping, iova);
+ next = interval_tree_iter_next(node, iova, last);
+
+ /* Trying to split a mapping? */
+ if (mapping->iova.start < iova)
+ break;
+
+ /*
+ * Virtio-iommu doesn't allow UNMAP to split a mapping created
+ * with a single MAP request, so remove the full mapping.
+ */
+ unmapped += mapping->iova.last - mapping->iova.start + 1;
+
+ interval_tree_remove(node, &vdomain->mappings);
+ kfree(mapping);
+ }
+ spin_unlock_irqrestore(&vdomain->mappings_lock, flags);
+
+ return unmapped;
+}
+
+/*
+ * viommu_replay_mappings - re-send MAP requests
+ *
+ * When reattaching a domain that was previously detached from all endpoints,
+ * mappings were deleted from the device. Re-create the mappings available in
+ * the internal tree.
+ */
+static int viommu_replay_mappings(struct viommu_domain *vdomain)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct viommu_mapping *mapping;
+ struct interval_tree_node *node;
+ struct virtio_iommu_req_map map;
+
+ spin_lock_irqsave(&vdomain->mappings_lock, flags);
+ node = interval_tree_iter_first(&vdomain->mappings, 0, -1UL);
+ while (node) {
+ mapping = container_of(node, struct viommu_mapping, iova);
+ map = (struct virtio_iommu_req_map) {
+ .head.type = VIRTIO_IOMMU_T_MAP,
+ .domain = cpu_to_le32(vdomain->id),
+ .virt_start = cpu_to_le64(mapping->iova.start),
+ .virt_end = cpu_to_le64(mapping->iova.last),
+ .phys_start = cpu_to_le64(mapping->paddr),
+ .flags = cpu_to_le32(mapping->flags),
+ };
+
+ ret = viommu_send_req_sync(vdomain->viommu, &map, sizeof(map));
+ if (ret)
+ break;
+
+ node = interval_tree_iter_next(node, 0, -1UL);
+ }
+ spin_unlock_irqrestore(&vdomain->mappings_lock, flags);
+
+ return ret;
+}
+
+static int viommu_add_resv_mem(struct viommu_endpoint *vdev,
+ struct virtio_iommu_probe_resv_mem *mem,
+ size_t len)
+{
+ size_t size;
+ u64 start64, end64;
+ phys_addr_t start, end;
+ struct iommu_resv_region *region = NULL;
+ unsigned long prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO;
+
+ start = start64 = le64_to_cpu(mem->start);
+ end = end64 = le64_to_cpu(mem->end);
+ size = end64 - start64 + 1;
+
+ /* Catch any overflow, including the unlikely end64 - start64 + 1 = 0 */
+ if (start != start64 || end != end64 || size < end64 - start64)
+ return -EOVERFLOW;
+
+ if (len < sizeof(*mem))
+ return -EINVAL;
+
+ switch (mem->subtype) {
+ default:
+ dev_warn(vdev->dev, "unknown resv mem subtype 0x%x\n",
+ mem->subtype);
+ /* Fall-through */
+ case VIRTIO_IOMMU_RESV_MEM_T_RESERVED:
+ region = iommu_alloc_resv_region(start, size, 0,
+ IOMMU_RESV_RESERVED);
+ break;
+ case VIRTIO_IOMMU_RESV_MEM_T_MSI:
+ region = iommu_alloc_resv_region(start, size, prot,
+ IOMMU_RESV_MSI);
+ break;
+ }
+ if (!region)
+ return -ENOMEM;
+
+ list_add(&vdev->resv_regions, &region->list);
+ return 0;
+}
+
+static int viommu_probe_endpoint(struct viommu_dev *viommu, struct device *dev)
+{
+ int ret;
+ u16 type, len;
+ size_t cur = 0;
+ size_t probe_len;
+ struct virtio_iommu_req_probe *probe;
+ struct virtio_iommu_probe_property *prop;
+ struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+ struct viommu_endpoint *vdev = fwspec->iommu_priv;
+
+ if (!fwspec->num_ids)
+ return -EINVAL;
+
+ probe_len = sizeof(*probe) + viommu->probe_size +
+ sizeof(struct virtio_iommu_req_tail);
+ probe = kzalloc(probe_len, GFP_KERNEL);
+ if (!probe)
+ return -ENOMEM;
+
+ probe->head.type = VIRTIO_IOMMU_T_PROBE;
+ /*
+ * For now, assume that properties of an endpoint that outputs multiple
+ * IDs are consistent. Only probe the first one.
+ */
+ probe->endpoint = cpu_to_le32(fwspec->ids[0]);
+
+ ret = viommu_send_req_sync(viommu, probe, probe_len);
+ if (ret)
+ goto out_free;
+
+ prop = (void *)probe->properties;
+ type = le16_to_cpu(prop->type) & VIRTIO_IOMMU_PROBE_T_MASK;
+
+ while (type != VIRTIO_IOMMU_PROBE_T_NONE &&
+ cur < viommu->probe_size) {
+ len = le16_to_cpu(prop->length) + sizeof(*prop);
+
+ switch (type) {
+ case VIRTIO_IOMMU_PROBE_T_RESV_MEM:
+ ret = viommu_add_resv_mem(vdev, (void *)prop, len);
+ break;
+ default:
+ dev_err(dev, "unknown viommu prop 0x%x\n", type);
+ }
+
+ if (ret)
+ dev_err(dev, "failed to parse viommu prop 0x%x\n", type);
+
+ cur += len;
+ if (cur >= viommu->probe_size)
+ break;
+
+ prop = (void *)probe->properties + cur;
+ type = le16_to_cpu(prop->type) & VIRTIO_IOMMU_PROBE_T_MASK;
+ }
+
+out_free:
+ kfree(probe);
+ return ret;
+}
+
+static int viommu_fault_handler(struct viommu_dev *viommu,
+ struct virtio_iommu_fault *fault)
+{
+ char *reason_str;
+
+ u8 reason = fault->reason;
+ u32 flags = le32_to_cpu(fault->flags);
+ u32 endpoint = le32_to_cpu(fault->endpoint);
+ u64 address = le64_to_cpu(fault->address);
+
+ switch (reason) {
+ case VIRTIO_IOMMU_FAULT_R_DOMAIN:
+ reason_str = "domain";
+ break;
+ case VIRTIO_IOMMU_FAULT_R_MAPPING:
+ reason_str = "page";
+ break;
+ case VIRTIO_IOMMU_FAULT_R_UNKNOWN:
+ default:
+ reason_str = "unknown";
+ break;
+ }
+
+ /* TODO: find EP by ID and report_iommu_fault */
+ if (flags & VIRTIO_IOMMU_FAULT_F_ADDRESS)
+ dev_err_ratelimited(viommu->dev, "%s fault from EP %u at %#llx [%s%s%s]\n",
+ reason_str, endpoint, address,
+ flags & VIRTIO_IOMMU_FAULT_F_READ ? "R" : "",
+ flags & VIRTIO_IOMMU_FAULT_F_WRITE ? "W" : "",
+ flags & VIRTIO_IOMMU_FAULT_F_EXEC ? "X" : "");
+ else
+ dev_err_ratelimited(viommu->dev, "%s fault from EP %u\n",
+ reason_str, endpoint);
+ return 0;
+}
+
+static void viommu_event_handler(struct virtqueue *vq)
+{
+ int ret;
+ unsigned int len;
+ struct scatterlist sg[1];
+ struct viommu_event *evt;
+ struct viommu_dev *viommu = vq->vdev->priv;
+
+ while ((evt = virtqueue_get_buf(vq, &len)) != NULL) {
+ if (len > sizeof(*evt)) {
+ dev_err(viommu->dev,
+ "invalid event buffer (len %u != %zu)\n",
+ len, sizeof(*evt));
+ } else if (!(evt->head & VIOMMU_FAULT_RESV_MASK)) {
+ viommu_fault_handler(viommu, &evt->fault);
+ }
+
+ sg_init_one(sg, evt, sizeof(*evt));
+ ret = virtqueue_add_inbuf(vq, sg, 1, evt, GFP_ATOMIC);
+ if (ret)
+ dev_err(viommu->dev, "could not add event buffer\n");
+ }
+
+ virtqueue_kick(vq);
+}
+
+/* IOMMU API */
+
+static struct iommu_domain *viommu_domain_alloc(unsigned type)
+{
+ struct viommu_domain *vdomain;
+
+ if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA)
+ return NULL;
+
+ vdomain = kzalloc(sizeof(*vdomain), GFP_KERNEL);
+ if (!vdomain)
+ return NULL;
+
+ mutex_init(&vdomain->mutex);
+ spin_lock_init(&vdomain->mappings_lock);
+ vdomain->mappings = RB_ROOT_CACHED;
+
+ if (type == IOMMU_DOMAIN_DMA &&
+ iommu_get_dma_cookie(&vdomain->domain)) {
+ kfree(vdomain);
+ return NULL;
+ }
+
+ return &vdomain->domain;
+}
+
+static int viommu_domain_finalise(struct viommu_dev *viommu,
+ struct iommu_domain *domain)
+{
+ int ret;
+ struct viommu_domain *vdomain = to_viommu_domain(domain);
+ unsigned int max_domain = viommu->domain_bits > 31 ? ~0 :
+ (1U << viommu->domain_bits) - 1;
+
+ vdomain->viommu = viommu;
+
+ domain->pgsize_bitmap = viommu->pgsize_bitmap;
+ domain->geometry = viommu->geometry;
+
+ ret = ida_alloc_max(&viommu->domain_ids, max_domain, GFP_KERNEL);
+ if (ret >= 0)
+ vdomain->id = (unsigned int)ret;
+
+ return ret > 0 ? 0 : ret;
+}
+
+static void viommu_domain_free(struct iommu_domain *domain)
+{
+ struct viommu_domain *vdomain = to_viommu_domain(domain);
+
+ iommu_put_dma_cookie(domain);
+
+ /* Free all remaining mappings (size 2^64) */
+ viommu_del_mappings(vdomain, 0, 0);
+
+ if (vdomain->viommu)
+ ida_free(&vdomain->viommu->domain_ids, vdomain->id);
+
+ kfree(vdomain);
+}
+
+static int viommu_attach_dev(struct iommu_domain *domain, struct device *dev)
+{
+ int i;
+ int ret = 0;
+ struct virtio_iommu_req_attach req;
+ struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+ struct viommu_endpoint *vdev = fwspec->iommu_priv;
+ struct viommu_domain *vdomain = to_viommu_domain(domain);
+
+ mutex_lock(&vdomain->mutex);
+ if (!vdomain->viommu) {
+ /*
+ * Properly initialize the domain now that we know which viommu
+ * owns it.
+ */
+ ret = viommu_domain_finalise(vdev->viommu, domain);
+ } else if (vdomain->viommu != vdev->viommu) {
+ dev_err(dev, "cannot attach to foreign vIOMMU\n");
+ ret = -EXDEV;
+ }
+ mutex_unlock(&vdomain->mutex);
+
+ if (ret)
+ return ret;
+
+ /*
+ * In the virtio-iommu device, when attaching the endpoint to a new
+ * domain, it is detached from the old one and, if as as a result the
+ * old domain isn't attached to any endpoint, all mappings are removed
+ * from the old domain and it is freed.
+ *
+ * In the driver the old domain still exists, and its mappings will be
+ * recreated if it gets reattached to an endpoint. Otherwise it will be
+ * freed explicitly.
+ *
+ * vdev->vdomain is protected by group->mutex
+ */
+ if (vdev->vdomain)
+ vdev->vdomain->nr_endpoints--;
+
+ req = (struct virtio_iommu_req_attach) {
+ .head.type = VIRTIO_IOMMU_T_ATTACH,
+ .domain = cpu_to_le32(vdomain->id),
+ };
+
+ for (i = 0; i < fwspec->num_ids; i++) {
+ req.endpoint = cpu_to_le32(fwspec->ids[i]);
+
+ ret = viommu_send_req_sync(vdomain->viommu, &req, sizeof(req));
+ if (ret)
+ return ret;
+ }
+
+ if (!vdomain->nr_endpoints) {
+ /*
+ * This endpoint is the first to be attached to the domain.
+ * Replay existing mappings (e.g. SW MSI).
+ */
+ ret = viommu_replay_mappings(vdomain);
+ if (ret)
+ return ret;
+ }
+
+ vdomain->nr_endpoints++;
+ vdev->vdomain = vdomain;
+
+ return 0;
+}
+
+static int viommu_map(struct iommu_domain *domain, unsigned long iova,
+ phys_addr_t paddr, size_t size, int prot)
+{
+ int ret;
+ int flags;
+ struct virtio_iommu_req_map map;
+ struct viommu_domain *vdomain = to_viommu_domain(domain);
+
+ flags = (prot & IOMMU_READ ? VIRTIO_IOMMU_MAP_F_READ : 0) |
+ (prot & IOMMU_WRITE ? VIRTIO_IOMMU_MAP_F_WRITE : 0) |
+ (prot & IOMMU_MMIO ? VIRTIO_IOMMU_MAP_F_MMIO : 0);
+
+ ret = viommu_add_mapping(vdomain, iova, paddr, size, flags);
+ if (ret)
+ return ret;
+
+ map = (struct virtio_iommu_req_map) {
+ .head.type = VIRTIO_IOMMU_T_MAP,
+ .domain = cpu_to_le32(vdomain->id),
+ .virt_start = cpu_to_le64(iova),
+ .phys_start = cpu_to_le64(paddr),
+ .virt_end = cpu_to_le64(iova + size - 1),
+ .flags = cpu_to_le32(flags),
+ };
+
+ if (!vdomain->nr_endpoints)
+ return 0;
+
+ ret = viommu_send_req_sync(vdomain->viommu, &map, sizeof(map));
+ if (ret)
+ viommu_del_mappings(vdomain, iova, size);
+
+ return ret;
+}
+
+static size_t viommu_unmap(struct iommu_domain *domain, unsigned long iova,
+ size_t size)
+{
+ int ret = 0;
+ size_t unmapped;
+ struct virtio_iommu_req_unmap unmap;
+ struct viommu_domain *vdomain = to_viommu_domain(domain);
+
+ unmapped = viommu_del_mappings(vdomain, iova, size);
+ if (unmapped < size)
+ return 0;
+
+ /* Device already removed all mappings after detach. */
+ if (!vdomain->nr_endpoints)
+ return unmapped;
+
+ unmap = (struct virtio_iommu_req_unmap) {
+ .head.type = VIRTIO_IOMMU_T_UNMAP,
+ .domain = cpu_to_le32(vdomain->id),
+ .virt_start = cpu_to_le64(iova),
+ .virt_end = cpu_to_le64(iova + unmapped - 1),
+ };
+
+ ret = viommu_add_req(vdomain->viommu, &unmap, sizeof(unmap));
+ return ret ? 0 : unmapped;
+}
+
+static phys_addr_t viommu_iova_to_phys(struct iommu_domain *domain,
+ dma_addr_t iova)
+{
+ u64 paddr = 0;
+ unsigned long flags;
+ struct viommu_mapping *mapping;
+ struct interval_tree_node *node;
+ struct viommu_domain *vdomain = to_viommu_domain(domain);
+
+ spin_lock_irqsave(&vdomain->mappings_lock, flags);
+ node = interval_tree_iter_first(&vdomain->mappings, iova, iova);
+ if (node) {
+ mapping = container_of(node, struct viommu_mapping, iova);
+ paddr = mapping->paddr + (iova - mapping->iova.start);
+ }
+ spin_unlock_irqrestore(&vdomain->mappings_lock, flags);
+
+ return paddr;
+}
+
+static void viommu_iotlb_sync(struct iommu_domain *domain)
+{
+ struct viommu_domain *vdomain = to_viommu_domain(domain);
+
+ viommu_sync_req(vdomain->viommu);
+}
+
+static void viommu_get_resv_regions(struct device *dev, struct list_head *head)
+{
+ struct iommu_resv_region *entry, *new_entry, *msi = NULL;
+ struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+ struct viommu_endpoint *vdev = fwspec->iommu_priv;
+ int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO;
+
+ list_for_each_entry(entry, &vdev->resv_regions, list) {
+ if (entry->type == IOMMU_RESV_MSI)
+ msi = entry;
+
+ new_entry = kmemdup(entry, sizeof(*entry), GFP_KERNEL);
+ if (!new_entry)
+ return;
+ list_add_tail(&new_entry->list, head);
+ }
+
+ /*
+ * If the device didn't register any bypass MSI window, add a
+ * software-mapped region.
+ */
+ if (!msi) {
+ msi = iommu_alloc_resv_region(MSI_IOVA_BASE, MSI_IOVA_LENGTH,
+ prot, IOMMU_RESV_SW_MSI);
+ if (!msi)
+ return;
+
+ list_add_tail(&msi->list, head);
+ }
+
+ iommu_dma_get_resv_regions(dev, head);
+}
+
+static void viommu_put_resv_regions(struct device *dev, struct list_head *head)
+{
+ struct iommu_resv_region *entry, *next;
+
+ list_for_each_entry_safe(entry, next, head, list)
+ kfree(entry);
+}
+
+static struct iommu_ops viommu_ops;
+static struct virtio_driver virtio_iommu_drv;
+
+static int viommu_match_node(struct device *dev, const void *data)
+{
+ return dev->parent->fwnode == data;
+}
+
+static struct viommu_dev *viommu_get_by_fwnode(struct fwnode_handle *fwnode)
+{
+ struct device *dev = driver_find_device(&virtio_iommu_drv.driver, NULL,
+ fwnode, viommu_match_node);
+ put_device(dev);
+
+ return dev ? dev_to_virtio(dev)->priv : NULL;
+}
+
+static int viommu_add_device(struct device *dev)
+{
+ int ret;
+ struct iommu_group *group;
+ struct viommu_endpoint *vdev;
+ struct viommu_dev *viommu = NULL;
+ struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+
+ if (!fwspec || fwspec->ops != &viommu_ops)
+ return -ENODEV;
+
+ viommu = viommu_get_by_fwnode(fwspec->iommu_fwnode);
+ if (!viommu)
+ return -ENODEV;
+
+ vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
+ if (!vdev)
+ return -ENOMEM;
+
+ vdev->dev = dev;
+ vdev->viommu = viommu;
+ INIT_LIST_HEAD(&vdev->resv_regions);
+ fwspec->iommu_priv = vdev;
+
+ if (viommu->probe_size) {
+ /* Get additional information for this endpoint */
+ ret = viommu_probe_endpoint(viommu, dev);
+ if (ret)
+ goto err_free_dev;
+ }
+
+ ret = iommu_device_link(&viommu->iommu, dev);
+ if (ret)
+ goto err_free_dev;
+
+ /*
+ * Last step creates a default domain and attaches to it. Everything
+ * must be ready.
+ */
+ group = iommu_group_get_for_dev(dev);
+ if (IS_ERR(group)) {
+ ret = PTR_ERR(group);
+ goto err_unlink_dev;
+ }
+
+ iommu_group_put(group);
+
+ return PTR_ERR_OR_ZERO(group);
+
+err_unlink_dev:
+ iommu_device_unlink(&viommu->iommu, dev);
+err_free_dev:
+ viommu_put_resv_regions(dev, &vdev->resv_regions);
+ kfree(vdev);
+
+ return ret;
+}
+
+static void viommu_remove_device(struct device *dev)
+{
+ struct viommu_endpoint *vdev;
+ struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+
+ if (!fwspec || fwspec->ops != &viommu_ops)
+ return;
+
+ vdev = fwspec->iommu_priv;
+
+ iommu_group_remove_device(dev);
+ iommu_device_unlink(&vdev->viommu->iommu, dev);
+ viommu_put_resv_regions(dev, &vdev->resv_regions);
+ kfree(vdev);
+}
+
+static struct iommu_group *viommu_device_group(struct device *dev)
+{
+ if (dev_is_pci(dev))
+ return pci_device_group(dev);
+ else
+ return generic_device_group(dev);
+}
+
+static int viommu_of_xlate(struct device *dev, struct of_phandle_args *args)
+{
+ return iommu_fwspec_add_ids(dev, args->args, 1);
+}
+
+static struct iommu_ops viommu_ops = {
+ .domain_alloc = viommu_domain_alloc,
+ .domain_free = viommu_domain_free,
+ .attach_dev = viommu_attach_dev,
+ .map = viommu_map,
+ .unmap = viommu_unmap,
+ .iova_to_phys = viommu_iova_to_phys,
+ .iotlb_sync = viommu_iotlb_sync,
+ .add_device = viommu_add_device,
+ .remove_device = viommu_remove_device,
+ .device_group = viommu_device_group,
+ .get_resv_regions = viommu_get_resv_regions,
+ .put_resv_regions = viommu_put_resv_regions,
+ .of_xlate = viommu_of_xlate,
+};
+
+static int viommu_init_vqs(struct viommu_dev *viommu)
+{
+ struct virtio_device *vdev = dev_to_virtio(viommu->dev);
+ const char *names[] = { "request", "event" };
+ vq_callback_t *callbacks[] = {
+ NULL, /* No async requests */
+ viommu_event_handler,
+ };
+
+ return virtio_find_vqs(vdev, VIOMMU_NR_VQS, viommu->vqs, callbacks,
+ names, NULL);
+}
+
+static int viommu_fill_evtq(struct viommu_dev *viommu)
+{
+ int i, ret;
+ struct scatterlist sg[1];
+ struct viommu_event *evts;
+ struct virtqueue *vq = viommu->vqs[VIOMMU_EVENT_VQ];
+ size_t nr_evts = vq->num_free;
+
+ viommu->evts = evts = devm_kmalloc_array(viommu->dev, nr_evts,
+ sizeof(*evts), GFP_KERNEL);
+ if (!evts)
+ return -ENOMEM;
+
+ for (i = 0; i < nr_evts; i++) {
+ sg_init_one(sg, &evts[i], sizeof(*evts));
+ ret = virtqueue_add_inbuf(vq, sg, 1, &evts[i], GFP_KERNEL);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int viommu_probe(struct virtio_device *vdev)
+{
+ struct device *parent_dev = vdev->dev.parent;
+ struct viommu_dev *viommu = NULL;
+ struct device *dev = &vdev->dev;
+ u64 input_start = 0;
+ u64 input_end = -1UL;
+ int ret;
+
+ if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1) ||
+ !virtio_has_feature(vdev, VIRTIO_IOMMU_F_MAP_UNMAP))
+ return -ENODEV;
+
+ viommu = devm_kzalloc(dev, sizeof(*viommu), GFP_KERNEL);
+ if (!viommu)
+ return -ENOMEM;
+
+ spin_lock_init(&viommu->request_lock);
+ ida_init(&viommu->domain_ids);
+ viommu->dev = dev;
+ viommu->vdev = vdev;
+ INIT_LIST_HEAD(&viommu->requests);
+
+ ret = viommu_init_vqs(viommu);
+ if (ret)
+ return ret;
+
+ virtio_cread(vdev, struct virtio_iommu_config, page_size_mask,
+ &viommu->pgsize_bitmap);
+
+ if (!viommu->pgsize_bitmap) {
+ ret = -EINVAL;
+ goto err_free_vqs;
+ }
+
+ viommu->domain_bits = 32;
+
+ /* Optional features */
+ virtio_cread_feature(vdev, VIRTIO_IOMMU_F_INPUT_RANGE,
+ struct virtio_iommu_config, input_range.start,
+ &input_start);
+
+ virtio_cread_feature(vdev, VIRTIO_IOMMU_F_INPUT_RANGE,
+ struct virtio_iommu_config, input_range.end,
+ &input_end);
+
+ virtio_cread_feature(vdev, VIRTIO_IOMMU_F_DOMAIN_BITS,
+ struct virtio_iommu_config, domain_bits,
+ &viommu->domain_bits);
+
+ virtio_cread_feature(vdev, VIRTIO_IOMMU_F_PROBE,
+ struct virtio_iommu_config, probe_size,
+ &viommu->probe_size);
+
+ viommu->geometry = (struct iommu_domain_geometry) {
+ .aperture_start = input_start,
+ .aperture_end = input_end,
+ .force_aperture = true,
+ };
+
+ viommu_ops.pgsize_bitmap = viommu->pgsize_bitmap;
+
+ virtio_device_ready(vdev);
+
+ /* Populate the event queue with buffers */
+ ret = viommu_fill_evtq(viommu);
+ if (ret)
+ goto err_free_vqs;
+
+ ret = iommu_device_sysfs_add(&viommu->iommu, dev, NULL, "%s",
+ virtio_bus_name(vdev));
+ if (ret)
+ goto err_free_vqs;
+
+ iommu_device_set_ops(&viommu->iommu, &viommu_ops);
+ iommu_device_set_fwnode(&viommu->iommu, parent_dev->fwnode);
+
+ iommu_device_register(&viommu->iommu);
+
+#ifdef CONFIG_PCI
+ if (pci_bus_type.iommu_ops != &viommu_ops) {
+ pci_request_acs();
+ ret = bus_set_iommu(&pci_bus_type, &viommu_ops);
+ if (ret)
+ goto err_unregister;
+ }
+#endif
+#ifdef CONFIG_ARM_AMBA
+ if (amba_bustype.iommu_ops != &viommu_ops) {
+ ret = bus_set_iommu(&amba_bustype, &viommu_ops);
+ if (ret)
+ goto err_unregister;
+ }
+#endif
+ if (platform_bus_type.iommu_ops != &viommu_ops) {
+ ret = bus_set_iommu(&platform_bus_type, &viommu_ops);
+ if (ret)
+ goto err_unregister;
+ }
+
+ vdev->priv = viommu;
+
+ dev_info(dev, "input address: %u bits\n",
+ order_base_2(viommu->geometry.aperture_end));
+ dev_info(dev, "page mask: %#llx\n", viommu->pgsize_bitmap);
+
+ return 0;
+
+err_unregister:
+ iommu_device_sysfs_remove(&viommu->iommu);
+ iommu_device_unregister(&viommu->iommu);
+err_free_vqs:
+ vdev->config->del_vqs(vdev);
+
+ return ret;
+}
+
+static void viommu_remove(struct virtio_device *vdev)
+{
+ struct viommu_dev *viommu = vdev->priv;
+
+ iommu_device_sysfs_remove(&viommu->iommu);
+ iommu_device_unregister(&viommu->iommu);
+
+ /* Stop all virtqueues */
+ vdev->config->reset(vdev);
+ vdev->config->del_vqs(vdev);
+
+ dev_info(&vdev->dev, "device removed\n");
+}
+
+static void viommu_config_changed(struct virtio_device *vdev)
+{
+ dev_warn(&vdev->dev, "config changed\n");
+}
+
+static unsigned int features[] = {
+ VIRTIO_IOMMU_F_MAP_UNMAP,
+ VIRTIO_IOMMU_F_DOMAIN_BITS,
+ VIRTIO_IOMMU_F_INPUT_RANGE,
+ VIRTIO_IOMMU_F_PROBE,
+};
+
+static struct virtio_device_id id_table[] = {
+ { VIRTIO_ID_IOMMU, VIRTIO_DEV_ANY_ID },
+ { 0 },
+};
+
+static struct virtio_driver virtio_iommu_drv = {
+ .driver.name = KBUILD_MODNAME,
+ .driver.owner = THIS_MODULE,
+ .id_table = id_table,
+ .feature_table = features,
+ .feature_table_size = ARRAY_SIZE(features),
+ .probe = viommu_probe,
+ .remove = viommu_remove,
+ .config_changed = viommu_config_changed,
+};
+
+module_virtio_driver(virtio_iommu_drv);
+
+MODULE_DESCRIPTION("Virtio IOMMU driver");
+MODULE_AUTHOR("Jean-Philippe Brucker <jean-philippe.brucker@arm.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/ipack/devices/ipoctal.h b/drivers/ipack/devices/ipoctal.h
index 920537883238..75f83ba774a4 100644
--- a/drivers/ipack/devices/ipoctal.h
+++ b/drivers/ipack/devices/ipoctal.h
@@ -15,7 +15,6 @@
#define NR_CHANNELS 8
#define IPOCTAL_MAX_BOARDS 16
#define MAX_DEVICES (NR_CHANNELS * IPOCTAL_MAX_BOARDS)
-#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
/**
* struct ipoctal_stats -- Stats since last reset
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 659c5e0fb835..80e10f4e213a 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -15,10 +15,10 @@ config ARM_GIC_PM
bool
depends on PM
select ARM_GIC
- select PM_CLK
config ARM_GIC_MAX_NR
int
+ depends on ARM_GIC
default 2 if ARCH_REALVIEW
default 1
@@ -87,6 +87,14 @@ config ALPINE_MSI
select PCI_MSI
select GENERIC_IRQ_CHIP
+config AL_FIC
+ bool "Amazon's Annapurna Labs Fabric Interrupt Controller"
+ depends on OF || COMPILE_TEST
+ select GENERIC_IRQ_CHIP
+ select IRQ_DOMAIN
+ help
+ Support Amazon's Annapurna Labs Fabric Interrupt Controller.
+
config ATMEL_AIC_IRQ
bool
select GENERIC_IRQ_CHIP
@@ -217,13 +225,26 @@ config RDA_INTC
select IRQ_DOMAIN
config RENESAS_INTC_IRQPIN
- bool
+ bool "Renesas INTC External IRQ Pin Support" if COMPILE_TEST
select IRQ_DOMAIN
+ help
+ Enable support for the Renesas Interrupt Controller for external
+ interrupt pins, as found on SH/R-Mobile and R-Car Gen1 SoCs.
config RENESAS_IRQC
- bool
+ bool "Renesas R-Mobile APE6 and R-Car IRQC support" if COMPILE_TEST
select GENERIC_IRQ_CHIP
select IRQ_DOMAIN
+ help
+ Enable support for the Renesas Interrupt Controller for external
+ devices, as found on R-Mobile APE6, R-Car Gen2, and R-Car Gen3 SoCs.
+
+config RENESAS_RZA1_IRQC
+ bool "Renesas RZ/A1 IRQC support" if COMPILE_TEST
+ select IRQ_DOMAIN_HIERARCHY
+ help
+ Enable support for the Renesas RZ/A1 Interrupt Controller, to use up
+ to 8 external interrupts with configurable sense select.
config ST_IRQCHIP
bool
@@ -299,8 +320,11 @@ config RENESAS_H8300H_INTC
select IRQ_DOMAIN
config RENESAS_H8S_INTC
- bool
+ bool "Renesas H8S Interrupt Controller Support" if COMPILE_TEST
select IRQ_DOMAIN
+ help
+ Enable support for the Renesas H8/300 Interrupt Controller, as found
+ on Renesas H8S SoCs.
config IMX_GPCV2
bool
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 606a003a0000..8d0fcec6ab23 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_IRQCHIP) += irqchip.o
+obj-$(CONFIG_AL_FIC) += irq-al-fic.o
obj-$(CONFIG_ALPINE_MSI) += irq-alpine-msi.o
obj-$(CONFIG_ATH79) += irq-ath79-cpu.o
obj-$(CONFIG_ATH79) += irq-ath79-misc.o
@@ -49,6 +50,7 @@ obj-$(CONFIG_JCORE_AIC) += irq-jcore-aic.o
obj-$(CONFIG_RDA_INTC) += irq-rda-intc.o
obj-$(CONFIG_RENESAS_INTC_IRQPIN) += irq-renesas-intc-irqpin.o
obj-$(CONFIG_RENESAS_IRQC) += irq-renesas-irqc.o
+obj-$(CONFIG_RENESAS_RZA1_IRQC) += irq-renesas-rza1.o
obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o
obj-$(CONFIG_ARCH_NSPIRE) += irq-zevio.o
obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o
diff --git a/drivers/irqchip/exynos-combiner.c b/drivers/irqchip/exynos-combiner.c
index b78a169c9c83..0b85d9a3fbff 100644
--- a/drivers/irqchip/exynos-combiner.c
+++ b/drivers/irqchip/exynos-combiner.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Combiner irqchip for EXYNOS
- *
- * 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.
*/
#include <linux/err.h>
#include <linux/export.h>
diff --git a/drivers/irqchip/irq-al-fic.c b/drivers/irqchip/irq-al-fic.c
new file mode 100644
index 000000000000..1a57cee3efab
--- /dev/null
+++ b/drivers/irqchip/irq-al-fic.c
@@ -0,0 +1,278 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+/* FIC Registers */
+#define AL_FIC_CAUSE 0x00
+#define AL_FIC_MASK 0x10
+#define AL_FIC_CONTROL 0x28
+
+#define CONTROL_TRIGGER_RISING BIT(3)
+#define CONTROL_MASK_MSI_X BIT(5)
+
+#define NR_FIC_IRQS 32
+
+MODULE_AUTHOR("Talel Shenhar");
+MODULE_DESCRIPTION("Amazon's Annapurna Labs Interrupt Controller Driver");
+MODULE_LICENSE("GPL v2");
+
+enum al_fic_state {
+ AL_FIC_UNCONFIGURED = 0,
+ AL_FIC_CONFIGURED_LEVEL,
+ AL_FIC_CONFIGURED_RISING_EDGE,
+};
+
+struct al_fic {
+ void __iomem *base;
+ struct irq_domain *domain;
+ const char *name;
+ unsigned int parent_irq;
+ enum al_fic_state state;
+};
+
+static void al_fic_set_trigger(struct al_fic *fic,
+ struct irq_chip_generic *gc,
+ enum al_fic_state new_state)
+{
+ irq_flow_handler_t handler;
+ u32 control = readl_relaxed(fic->base + AL_FIC_CONTROL);
+
+ if (new_state == AL_FIC_CONFIGURED_LEVEL) {
+ handler = handle_level_irq;
+ control &= ~CONTROL_TRIGGER_RISING;
+ } else {
+ handler = handle_edge_irq;
+ control |= CONTROL_TRIGGER_RISING;
+ }
+ gc->chip_types->handler = handler;
+ fic->state = new_state;
+ writel_relaxed(control, fic->base + AL_FIC_CONTROL);
+}
+
+static int al_fic_irq_set_type(struct irq_data *data, unsigned int flow_type)
+{
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
+ struct al_fic *fic = gc->private;
+ enum al_fic_state new_state;
+ int ret = 0;
+
+ irq_gc_lock(gc);
+
+ if (((flow_type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_HIGH) &&
+ ((flow_type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_EDGE_RISING)) {
+ pr_debug("fic doesn't support flow type %d\n", flow_type);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ new_state = (flow_type & IRQ_TYPE_LEVEL_HIGH) ?
+ AL_FIC_CONFIGURED_LEVEL : AL_FIC_CONFIGURED_RISING_EDGE;
+
+ /*
+ * A given FIC instance can be either all level or all edge triggered.
+ * This is generally fixed depending on what pieces of HW it's wired up
+ * to.
+ *
+ * We configure it based on the sensitivity of the first source
+ * being setup, and reject any subsequent attempt at configuring it in a
+ * different way.
+ */
+ if (fic->state == AL_FIC_UNCONFIGURED) {
+ al_fic_set_trigger(fic, gc, new_state);
+ } else if (fic->state != new_state) {
+ pr_debug("fic %s state already configured to %d\n",
+ fic->name, fic->state);
+ ret = -EINVAL;
+ goto err;
+ }
+
+err:
+ irq_gc_unlock(gc);
+
+ return ret;
+}
+
+static void al_fic_irq_handler(struct irq_desc *desc)
+{
+ struct al_fic *fic = irq_desc_get_handler_data(desc);
+ struct irq_domain *domain = fic->domain;
+ struct irq_chip *irqchip = irq_desc_get_chip(desc);
+ struct irq_chip_generic *gc = irq_get_domain_generic_chip(domain, 0);
+ unsigned long pending;
+ unsigned int irq;
+ u32 hwirq;
+
+ chained_irq_enter(irqchip, desc);
+
+ pending = readl_relaxed(fic->base + AL_FIC_CAUSE);
+ pending &= ~gc->mask_cache;
+
+ for_each_set_bit(hwirq, &pending, NR_FIC_IRQS) {
+ irq = irq_find_mapping(domain, hwirq);
+ generic_handle_irq(irq);
+ }
+
+ chained_irq_exit(irqchip, desc);
+}
+
+static int al_fic_register(struct device_node *node,
+ struct al_fic *fic)
+{
+ struct irq_chip_generic *gc;
+ int ret;
+
+ fic->domain = irq_domain_add_linear(node,
+ NR_FIC_IRQS,
+ &irq_generic_chip_ops,
+ fic);
+ if (!fic->domain) {
+ pr_err("fail to add irq domain\n");
+ return -ENOMEM;
+ }
+
+ ret = irq_alloc_domain_generic_chips(fic->domain,
+ NR_FIC_IRQS,
+ 1, fic->name,
+ handle_level_irq,
+ 0, 0, IRQ_GC_INIT_MASK_CACHE);
+ if (ret) {
+ pr_err("fail to allocate generic chip (%d)\n", ret);
+ goto err_domain_remove;
+ }
+
+ gc = irq_get_domain_generic_chip(fic->domain, 0);
+ gc->reg_base = fic->base;
+ gc->chip_types->regs.mask = AL_FIC_MASK;
+ gc->chip_types->regs.ack = AL_FIC_CAUSE;
+ gc->chip_types->chip.irq_mask = irq_gc_mask_set_bit;
+ gc->chip_types->chip.irq_unmask = irq_gc_mask_clr_bit;
+ gc->chip_types->chip.irq_ack = irq_gc_ack_clr_bit;
+ gc->chip_types->chip.irq_set_type = al_fic_irq_set_type;
+ gc->chip_types->chip.flags = IRQCHIP_SKIP_SET_WAKE;
+ gc->private = fic;
+
+ irq_set_chained_handler_and_data(fic->parent_irq,
+ al_fic_irq_handler,
+ fic);
+ return 0;
+
+err_domain_remove:
+ irq_domain_remove(fic->domain);
+
+ return ret;
+}
+
+/*
+ * al_fic_wire_init() - initialize and configure fic in wire mode
+ * @of_node: optional pointer to interrupt controller's device tree node.
+ * @base: mmio to fic register
+ * @name: name of the fic
+ * @parent_irq: interrupt of parent
+ *
+ * This API will configure the fic hardware to to work in wire mode.
+ * In wire mode, fic hardware is generating a wire ("wired") interrupt.
+ * Interrupt can be generated based on positive edge or level - configuration is
+ * to be determined based on connected hardware to this fic.
+ */
+static struct al_fic *al_fic_wire_init(struct device_node *node,
+ void __iomem *base,
+ const char *name,
+ unsigned int parent_irq)
+{
+ struct al_fic *fic;
+ int ret;
+ u32 control = CONTROL_MASK_MSI_X;
+
+ fic = kzalloc(sizeof(*fic), GFP_KERNEL);
+ if (!fic)
+ return ERR_PTR(-ENOMEM);
+
+ fic->base = base;
+ fic->parent_irq = parent_irq;
+ fic->name = name;
+
+ /* mask out all interrupts */
+ writel_relaxed(0xFFFFFFFF, fic->base + AL_FIC_MASK);
+
+ /* clear any pending interrupt */
+ writel_relaxed(0, fic->base + AL_FIC_CAUSE);
+
+ writel_relaxed(control, fic->base + AL_FIC_CONTROL);
+
+ ret = al_fic_register(node, fic);
+ if (ret) {
+ pr_err("fail to register irqchip\n");
+ goto err_free;
+ }
+
+ pr_debug("%s initialized successfully in Legacy mode (parent-irq=%u)\n",
+ fic->name, parent_irq);
+
+ return fic;
+
+err_free:
+ kfree(fic);
+ return ERR_PTR(ret);
+}
+
+static int __init al_fic_init_dt(struct device_node *node,
+ struct device_node *parent)
+{
+ int ret;
+ void __iomem *base;
+ unsigned int parent_irq;
+ struct al_fic *fic;
+
+ if (!parent) {
+ pr_err("%s: unsupported - device require a parent\n",
+ node->name);
+ return -EINVAL;
+ }
+
+ base = of_iomap(node, 0);
+ if (!base) {
+ pr_err("%s: fail to map memory\n", node->name);
+ return -ENOMEM;
+ }
+
+ parent_irq = irq_of_parse_and_map(node, 0);
+ if (!parent_irq) {
+ pr_err("%s: fail to map irq\n", node->name);
+ ret = -EINVAL;
+ goto err_unmap;
+ }
+
+ fic = al_fic_wire_init(node,
+ base,
+ node->name,
+ parent_irq);
+ if (IS_ERR(fic)) {
+ pr_err("%s: fail to initialize irqchip (%lu)\n",
+ node->name,
+ PTR_ERR(fic));
+ ret = PTR_ERR(fic);
+ goto err_irq_dispose;
+ }
+
+ return 0;
+
+err_irq_dispose:
+ irq_dispose_mapping(parent_irq);
+err_unmap:
+ iounmap(base);
+
+ return ret;
+}
+
+IRQCHIP_DECLARE(al_fic, "amazon,al-fic", al_fic_init_dt);
diff --git a/drivers/irqchip/irq-aspeed-i2c-ic.c b/drivers/irqchip/irq-aspeed-i2c-ic.c
index f20200af0992..8d591c179f81 100644
--- a/drivers/irqchip/irq-aspeed-i2c-ic.c
+++ b/drivers/irqchip/irq-aspeed-i2c-ic.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Aspeed 24XX/25XX I2C Interrupt Controller.
*
* Copyright (C) 2012-2017 ASPEED Technology Inc.
* Copyright 2017 IBM Corporation
* Copyright 2017 Google, 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.
*/
#include <linux/irq.h>
diff --git a/drivers/irqchip/irq-ath79-cpu.c b/drivers/irqchip/irq-ath79-cpu.c
index befe93c5a51a..923e4bba3776 100644
--- a/drivers/irqchip/irq-ath79-cpu.c
+++ b/drivers/irqchip/irq-ath79-cpu.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Atheros AR71xx/AR724x/AR913x specific interrupt handling
*
@@ -7,10 +8,6 @@
* Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
*
* Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP
- *
- * 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.
*/
#include <linux/interrupt.h>
diff --git a/drivers/irqchip/irq-ath79-misc.c b/drivers/irqchip/irq-ath79-misc.c
index 0390603170b4..3d641bb6f3f1 100644
--- a/drivers/irqchip/irq-ath79-misc.c
+++ b/drivers/irqchip/irq-ath79-misc.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Atheros AR71xx/AR724x/AR913x MISC interrupt controller
*
@@ -7,10 +8,6 @@
* Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
*
* Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP
- *
- * 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.
*/
#include <linux/irqchip.h>
diff --git a/drivers/irqchip/irq-bcm6345-l1.c b/drivers/irqchip/irq-bcm6345-l1.c
index 43f8abe40878..e3483789f4df 100644
--- a/drivers/irqchip/irq-bcm6345-l1.c
+++ b/drivers/irqchip/irq-bcm6345-l1.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Broadcom BCM6345 style Level 1 interrupt controller driver
*
* Copyright (C) 2014 Broadcom Corporation
* Copyright 2015 Simon Arlott
*
- * 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.
- *
* This is based on the BCM7038 (which supports SMP) but with a single
* enable register instead of separate mask/set/clear registers.
*
diff --git a/drivers/irqchip/irq-bcm7038-l1.c b/drivers/irqchip/irq-bcm7038-l1.c
index 0acebac1920b..fc75c61233aa 100644
--- a/drivers/irqchip/irq-bcm7038-l1.c
+++ b/drivers/irqchip/irq-bcm7038-l1.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Broadcom BCM7038 style Level 1 interrupt controller driver
*
* Copyright (C) 2014 Broadcom Corporation
* Author: Kevin Cernekee
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c
index 541bdca9f4af..586df3587be0 100644
--- a/drivers/irqchip/irq-bcm7120-l2.c
+++ b/drivers/irqchip/irq-bcm7120-l2.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Broadcom BCM7120 style Level 2 interrupt controller driver
*
* Copyright (C) 2014 Broadcom Corporation
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/irqchip/irq-crossbar.c b/drivers/irqchip/irq-crossbar.c
index 99d97d7e3fd7..a05a7501e107 100644
--- a/drivers/irqchip/irq-crossbar.c
+++ b/drivers/irqchip/irq-crossbar.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/irqchip/irq-crossbar.c
*
* Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
* Author: Sricharan R <r.sricharan@ti.com>
- *
- * 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.
- *
*/
#include <linux/err.h>
#include <linux/io.h>
diff --git a/drivers/irqchip/irq-csky-mpintc.c b/drivers/irqchip/irq-csky-mpintc.c
index c67c961ab6cc..a1534edef7fa 100644
--- a/drivers/irqchip/irq-csky-mpintc.c
+++ b/drivers/irqchip/irq-csky-mpintc.c
@@ -32,8 +32,8 @@ static void __iomem *INTCL_base;
#define INTCG_CIDSTR 0x1000
#define INTCL_PICTLR 0x0
+#define INTCL_CFGR 0x14
#define INTCL_SIGR 0x60
-#define INTCL_HPPIR 0x68
#define INTCL_RDYIR 0x6c
#define INTCL_SENR 0xa0
#define INTCL_CENR 0xa4
@@ -41,21 +41,49 @@ static void __iomem *INTCL_base;
static DEFINE_PER_CPU(void __iomem *, intcl_reg);
+static unsigned long *__trigger;
+
+#define IRQ_OFFSET(irq) ((irq < COMM_IRQ_BASE) ? irq : (irq - COMM_IRQ_BASE))
+
+#define TRIG_BYTE_OFFSET(i) ((((i) * 2) / 32) * 4)
+#define TRIG_BIT_OFFSET(i) (((i) * 2) % 32)
+
+#define TRIG_VAL(trigger, irq) (trigger << TRIG_BIT_OFFSET(IRQ_OFFSET(irq)))
+#define TRIG_VAL_MSK(irq) (~(3 << TRIG_BIT_OFFSET(IRQ_OFFSET(irq))))
+
+#define TRIG_BASE(irq) \
+ (TRIG_BYTE_OFFSET(IRQ_OFFSET(irq)) + ((irq < COMM_IRQ_BASE) ? \
+ (this_cpu_read(intcl_reg) + INTCL_CFGR) : (INTCG_base + INTCG_CICFGR)))
+
+static DEFINE_SPINLOCK(setup_lock);
+static void setup_trigger(unsigned long irq, unsigned long trigger)
+{
+ unsigned int tmp;
+
+ spin_lock(&setup_lock);
+
+ /* setup trigger */
+ tmp = readl_relaxed(TRIG_BASE(irq)) & TRIG_VAL_MSK(irq);
+
+ writel_relaxed(tmp | TRIG_VAL(trigger, irq), TRIG_BASE(irq));
+
+ spin_unlock(&setup_lock);
+}
+
static void csky_mpintc_handler(struct pt_regs *regs)
{
void __iomem *reg_base = this_cpu_read(intcl_reg);
- do {
- handle_domain_irq(root_domain,
- readl_relaxed(reg_base + INTCL_RDYIR),
- regs);
- } while (readl_relaxed(reg_base + INTCL_HPPIR) & BIT(31));
+ handle_domain_irq(root_domain,
+ readl_relaxed(reg_base + INTCL_RDYIR), regs);
}
static void csky_mpintc_enable(struct irq_data *d)
{
void __iomem *reg_base = this_cpu_read(intcl_reg);
+ setup_trigger(d->hwirq, __trigger[d->hwirq]);
+
writel_relaxed(d->hwirq, reg_base + INTCL_SENR);
}
@@ -73,6 +101,28 @@ static void csky_mpintc_eoi(struct irq_data *d)
writel_relaxed(d->hwirq, reg_base + INTCL_CACR);
}
+static int csky_mpintc_set_type(struct irq_data *d, unsigned int type)
+{
+ switch (type & IRQ_TYPE_SENSE_MASK) {
+ case IRQ_TYPE_LEVEL_HIGH:
+ __trigger[d->hwirq] = 0;
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ __trigger[d->hwirq] = 1;
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ __trigger[d->hwirq] = 2;
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ __trigger[d->hwirq] = 3;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
#ifdef CONFIG_SMP
static int csky_irq_set_affinity(struct irq_data *d,
const struct cpumask *mask_val,
@@ -89,8 +139,19 @@ static int csky_irq_set_affinity(struct irq_data *d,
if (cpu >= nr_cpu_ids)
return -EINVAL;
- /* Enable interrupt destination */
- cpu |= BIT(31);
+ /*
+ * The csky,mpintc could support auto irq deliver, but it only
+ * could deliver external irq to one cpu or all cpus. So it
+ * doesn't support deliver external irq to a group of cpus
+ * with cpu_mask.
+ * SO we only use auto deliver mode when affinity mask_val is
+ * equal to cpu_present_mask.
+ *
+ */
+ if (cpumask_equal(mask_val, cpu_present_mask))
+ cpu = 0;
+ else
+ cpu |= BIT(31);
writel_relaxed(cpu, INTCG_base + INTCG_CIDSTR + offset);
@@ -105,6 +166,7 @@ static struct irq_chip csky_irq_chip = {
.irq_eoi = csky_mpintc_eoi,
.irq_enable = csky_mpintc_enable,
.irq_disable = csky_mpintc_disable,
+ .irq_set_type = csky_mpintc_set_type,
#ifdef CONFIG_SMP
.irq_set_affinity = csky_irq_set_affinity,
#endif
@@ -125,9 +187,26 @@ static int csky_irqdomain_map(struct irq_domain *d, unsigned int irq,
return 0;
}
+static int csky_irq_domain_xlate_cells(struct irq_domain *d,
+ struct device_node *ctrlr, const u32 *intspec,
+ unsigned int intsize, unsigned long *out_hwirq,
+ unsigned int *out_type)
+{
+ if (WARN_ON(intsize < 1))
+ return -EINVAL;
+
+ *out_hwirq = intspec[0];
+ if (intsize > 1)
+ *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
+ else
+ *out_type = IRQ_TYPE_LEVEL_HIGH;
+
+ return 0;
+}
+
static const struct irq_domain_ops csky_irqdomain_ops = {
.map = csky_irqdomain_map,
- .xlate = irq_domain_xlate_onecell,
+ .xlate = csky_irq_domain_xlate_cells,
};
#ifdef CONFIG_SMP
@@ -161,6 +240,10 @@ csky_mpintc_init(struct device_node *node, struct device_node *parent)
if (ret < 0)
nr_irq = INTC_IRQS;
+ __trigger = kcalloc(nr_irq, sizeof(unsigned long), GFP_KERNEL);
+ if (__trigger == NULL)
+ return -ENXIO;
+
if (INTCG_base == NULL) {
INTCG_base = ioremap(mfcr("cr<31, 14>"),
INTCL_SIZE*nr_cpu_ids + INTCG_SIZE);
diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c
index 3c93c6f4d1f1..b0a8215a13fc 100644
--- a/drivers/irqchip/irq-gic-common.c
+++ b/drivers/irqchip/irq-gic-common.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2002 ARM Limited, All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/interrupt.h>
diff --git a/drivers/irqchip/irq-gic-common.h b/drivers/irqchip/irq-gic-common.h
index 97e58fb6c232..5a46b6b57750 100644
--- a/drivers/irqchip/irq-gic-common.h
+++ b/drivers/irqchip/irq-gic-common.h
@@ -1,17 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2002 ARM Limited, All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _IRQ_GIC_COMMON_H
diff --git a/drivers/irqchip/irq-gic-pm.c b/drivers/irqchip/irq-gic-pm.c
index c4aac0977d8a..1337ceceb59b 100644
--- a/drivers/irqchip/irq-gic-pm.c
+++ b/drivers/irqchip/irq-gic-pm.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2016 NVIDIA CORPORATION, All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
#include <linux/clk.h>
diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c
index 3c77ab676e54..7338f90b2f9e 100644
--- a/drivers/irqchip/irq-gic-v2m.c
+++ b/drivers/irqchip/irq-gic-v2m.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ARM GIC v2m MSI(-X) support
* Support for Message Signaled Interrupts for systems that
@@ -7,10 +8,6 @@
* Authors: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
* Harish Kasiviswanathan <harish.kasiviswanathan@amd.com>
* Brandon Anderson <brandon.anderson@amd.com>
- *
- * 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.
*/
#define pr_fmt(fmt) "GICv2m: " fmt
@@ -56,6 +53,7 @@
/* List of flags for specific v2m implementation */
#define GICV2M_NEEDS_SPI_OFFSET 0x00000001
+#define GICV2M_GRAVITON_ADDRESS_ONLY 0x00000002
static LIST_HEAD(v2m_nodes);
static DEFINE_SPINLOCK(v2m_lock);
@@ -98,15 +96,26 @@ static struct msi_domain_info gicv2m_msi_domain_info = {
.chip = &gicv2m_msi_irq_chip,
};
+static phys_addr_t gicv2m_get_msi_addr(struct v2m_data *v2m, int hwirq)
+{
+ if (v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY)
+ return v2m->res.start | ((hwirq - 32) << 3);
+ else
+ return v2m->res.start + V2M_MSI_SETSPI_NS;
+}
+
static void gicv2m_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
{
struct v2m_data *v2m = irq_data_get_irq_chip_data(data);
- phys_addr_t addr = v2m->res.start + V2M_MSI_SETSPI_NS;
+ phys_addr_t addr = gicv2m_get_msi_addr(v2m, data->hwirq);
msg->address_hi = upper_32_bits(addr);
msg->address_lo = lower_32_bits(addr);
- msg->data = data->hwirq;
+ if (v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY)
+ msg->data = 0;
+ else
+ msg->data = data->hwirq;
if (v2m->flags & GICV2M_NEEDS_SPI_OFFSET)
msg->data -= v2m->spi_offset;
@@ -188,7 +197,7 @@ static int gicv2m_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
hwirq = v2m->spi_start + offset;
err = iommu_dma_prepare_msi(info->desc,
- v2m->res.start + V2M_MSI_SETSPI_NS);
+ gicv2m_get_msi_addr(v2m, hwirq));
if (err)
return err;
@@ -307,7 +316,7 @@ static int gicv2m_allocate_domains(struct irq_domain *parent)
static int __init gicv2m_init_one(struct fwnode_handle *fwnode,
u32 spi_start, u32 nr_spis,
- struct resource *res)
+ struct resource *res, u32 flags)
{
int ret;
struct v2m_data *v2m;
@@ -320,6 +329,7 @@ static int __init gicv2m_init_one(struct fwnode_handle *fwnode,
INIT_LIST_HEAD(&v2m->entry);
v2m->fwnode = fwnode;
+ v2m->flags = flags;
memcpy(&v2m->res, res, sizeof(struct resource));
@@ -334,7 +344,14 @@ static int __init gicv2m_init_one(struct fwnode_handle *fwnode,
v2m->spi_start = spi_start;
v2m->nr_spis = nr_spis;
} else {
- u32 typer = readl_relaxed(v2m->base + V2M_MSI_TYPER);
+ u32 typer;
+
+ /* Graviton should always have explicit spi_start/nr_spis */
+ if (v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY) {
+ ret = -EINVAL;
+ goto err_iounmap;
+ }
+ typer = readl_relaxed(v2m->base + V2M_MSI_TYPER);
v2m->spi_start = V2M_MSI_TYPER_BASE_SPI(typer);
v2m->nr_spis = V2M_MSI_TYPER_NUM_SPI(typer);
@@ -355,18 +372,21 @@ static int __init gicv2m_init_one(struct fwnode_handle *fwnode,
*
* Broadom NS2 GICv2m implementation has an erratum where the MSI data
* is 'spi_number - 32'
+ *
+ * Reading that register fails on the Graviton implementation
*/
- switch (readl_relaxed(v2m->base + V2M_MSI_IIDR)) {
- case XGENE_GICV2M_MSI_IIDR:
- v2m->flags |= GICV2M_NEEDS_SPI_OFFSET;
- v2m->spi_offset = v2m->spi_start;
- break;
- case BCM_NS2_GICV2M_MSI_IIDR:
- v2m->flags |= GICV2M_NEEDS_SPI_OFFSET;
- v2m->spi_offset = 32;
- break;
+ if (!(v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY)) {
+ switch (readl_relaxed(v2m->base + V2M_MSI_IIDR)) {
+ case XGENE_GICV2M_MSI_IIDR:
+ v2m->flags |= GICV2M_NEEDS_SPI_OFFSET;
+ v2m->spi_offset = v2m->spi_start;
+ break;
+ case BCM_NS2_GICV2M_MSI_IIDR:
+ v2m->flags |= GICV2M_NEEDS_SPI_OFFSET;
+ v2m->spi_offset = 32;
+ break;
+ }
}
-
v2m->bm = kcalloc(BITS_TO_LONGS(v2m->nr_spis), sizeof(long),
GFP_KERNEL);
if (!v2m->bm) {
@@ -419,7 +439,8 @@ static int __init gicv2m_of_init(struct fwnode_handle *parent_handle,
pr_info("DT overriding V2M MSI_TYPER (base:%u, num:%u)\n",
spi_start, nr_spis);
- ret = gicv2m_init_one(&child->fwnode, spi_start, nr_spis, &res);
+ ret = gicv2m_init_one(&child->fwnode, spi_start, nr_spis,
+ &res, 0);
if (ret) {
of_node_put(child);
break;
@@ -451,6 +472,25 @@ static struct fwnode_handle *gicv2m_get_fwnode(struct device *dev)
return data->fwnode;
}
+static bool acpi_check_amazon_graviton_quirks(void)
+{
+ static struct acpi_table_madt *madt;
+ acpi_status status;
+ bool rc = false;
+
+#define ACPI_AMZN_OEM_ID "AMAZON"
+
+ status = acpi_get_table(ACPI_SIG_MADT, 0,
+ (struct acpi_table_header **)&madt);
+
+ if (ACPI_FAILURE(status) || !madt)
+ return rc;
+ rc = !memcmp(madt->header.oem_id, ACPI_AMZN_OEM_ID, ACPI_OEM_ID_SIZE);
+ acpi_put_table((struct acpi_table_header *)madt);
+
+ return rc;
+}
+
static int __init
acpi_parse_madt_msi(union acpi_subtable_headers *header,
const unsigned long end)
@@ -460,6 +500,7 @@ acpi_parse_madt_msi(union acpi_subtable_headers *header,
u32 spi_start = 0, nr_spis = 0;
struct acpi_madt_generic_msi_frame *m;
struct fwnode_handle *fwnode;
+ u32 flags = 0;
m = (struct acpi_madt_generic_msi_frame *)header;
if (BAD_MADT_ENTRY(m, end))
@@ -469,6 +510,13 @@ acpi_parse_madt_msi(union acpi_subtable_headers *header,
res.end = m->base_address + SZ_4K - 1;
res.flags = IORESOURCE_MEM;
+ if (acpi_check_amazon_graviton_quirks()) {
+ pr_info("applying Amazon Graviton quirk\n");
+ res.end = res.start + SZ_8K - 1;
+ flags |= GICV2M_GRAVITON_ADDRESS_ONLY;
+ gicv2m_msi_domain_info.flags &= ~MSI_FLAG_MULTI_PCI_MSI;
+ }
+
if (m->flags & ACPI_MADT_OVERRIDE_SPI_VALUES) {
spi_start = m->spi_base;
nr_spis = m->spi_count;
@@ -483,7 +531,7 @@ acpi_parse_madt_msi(union acpi_subtable_headers *header,
return -EINVAL;
}
- ret = gicv2m_init_one(fwnode, spi_start, nr_spis, &res);
+ ret = gicv2m_init_one(fwnode, spi_start, nr_spis, &res, flags);
if (ret)
irq_domain_free_fwnode(fwnode);
diff --git a/drivers/irqchip/irq-gic-v3-its-pci-msi.c b/drivers/irqchip/irq-gic-v3-its-pci-msi.c
index c81d5b81da56..229d586c3d7a 100644
--- a/drivers/irqchip/irq-gic-v3-its-pci-msi.c
+++ b/drivers/irqchip/irq-gic-v3-its-pci-msi.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013-2015 ARM Limited, All Rights Reserved.
* Author: Marc Zyngier <marc.zyngier@arm.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/acpi_iort.h>
diff --git a/drivers/irqchip/irq-gic-v3-its-platform-msi.c b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
index 9cdcda5bb3bd..daa6d5053bc3 100644
--- a/drivers/irqchip/irq-gic-v3-its-platform-msi.c
+++ b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013-2015 ARM Limited, All Rights Reserved.
* Author: Marc Zyngier <marc.zyngier@arm.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/acpi_iort.h>
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index cfb9b4e5f914..730fbe0e2a9d 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013-2017 ARM Limited, All Rights Reserved.
* Author: Marc Zyngier <marc.zyngier@arm.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/acpi.h>
@@ -196,7 +185,7 @@ static struct its_collection *dev_event_to_col(struct its_device *its_dev,
static struct its_collection *valid_col(struct its_collection *col)
{
- if (WARN_ON_ONCE(col->target_address & GENMASK_ULL(0, 15)))
+ if (WARN_ON_ONCE(col->target_address & GENMASK_ULL(15, 0)))
return NULL;
return col;
@@ -744,32 +733,43 @@ static void its_flush_cmd(struct its_node *its, struct its_cmd_block *cmd)
}
static int its_wait_for_range_completion(struct its_node *its,
- struct its_cmd_block *from,
+ u64 prev_idx,
struct its_cmd_block *to)
{
- u64 rd_idx, from_idx, to_idx;
+ u64 rd_idx, to_idx, linear_idx;
u32 count = 1000000; /* 1s! */
- from_idx = its_cmd_ptr_to_offset(its, from);
+ /* Linearize to_idx if the command set has wrapped around */
to_idx = its_cmd_ptr_to_offset(its, to);
+ if (to_idx < prev_idx)
+ to_idx += ITS_CMD_QUEUE_SZ;
+
+ linear_idx = prev_idx;
while (1) {
+ s64 delta;
+
rd_idx = readl_relaxed(its->base + GITS_CREADR);
- /* Direct case */
- if (from_idx < to_idx && rd_idx >= to_idx)
- break;
+ /*
+ * Compute the read pointer progress, taking the
+ * potential wrap-around into account.
+ */
+ delta = rd_idx - prev_idx;
+ if (rd_idx < prev_idx)
+ delta += ITS_CMD_QUEUE_SZ;
- /* Wrapped case */
- if (from_idx >= to_idx && rd_idx >= to_idx && rd_idx < from_idx)
+ linear_idx += delta;
+ if (linear_idx >= to_idx)
break;
count--;
if (!count) {
- pr_err_ratelimited("ITS queue timeout (%llu %llu %llu)\n",
- from_idx, to_idx, rd_idx);
+ pr_err_ratelimited("ITS queue timeout (%llu %llu)\n",
+ to_idx, linear_idx);
return -1;
}
+ prev_idx = rd_idx;
cpu_relax();
udelay(1);
}
@@ -786,6 +786,7 @@ void name(struct its_node *its, \
struct its_cmd_block *cmd, *sync_cmd, *next_cmd; \
synctype *sync_obj; \
unsigned long flags; \
+ u64 rd_idx; \
\
raw_spin_lock_irqsave(&its->lock, flags); \
\
@@ -807,10 +808,11 @@ void name(struct its_node *its, \
} \
\
post: \
+ rd_idx = readl_relaxed(its->base + GITS_CREADR); \
next_cmd = its_post_commands(its); \
raw_spin_unlock_irqrestore(&its->lock, flags); \
\
- if (its_wait_for_range_completion(its, cmd, next_cmd)) \
+ if (its_wait_for_range_completion(its, rd_idx, next_cmd)) \
pr_err_ratelimited("ITS cmd %ps failed\n", builder); \
}
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index f44cd89cfc40..9bca4896fa6f 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013-2017 ARM Limited, All Rights Reserved.
* Author: Marc Zyngier <marc.zyngier@arm.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define pr_fmt(fmt) "GICv3: " fmt
@@ -472,8 +461,12 @@ static void gic_deactivate_unhandled(u32 irqnr)
static inline void gic_handle_nmi(u32 irqnr, struct pt_regs *regs)
{
+ bool irqs_enabled = interrupts_enabled(regs);
int err;
+ if (irqs_enabled)
+ nmi_enter();
+
if (static_branch_likely(&supports_deactivate_key))
gic_write_eoir(irqnr);
/*
@@ -485,6 +478,9 @@ static inline void gic_handle_nmi(u32 irqnr, struct pt_regs *regs)
err = handle_domain_nmi(gic_data.domain, irqnr, regs);
if (err)
gic_deactivate_unhandled(irqnr);
+
+ if (irqs_enabled)
+ nmi_exit();
}
static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
@@ -1343,6 +1339,9 @@ static int __init gic_init_bases(void __iomem *dist_base,
if (gic_dist_supports_lpis()) {
its_init(handle, &gic_data.rdists, gic_data.domain);
its_cpu_init();
+ } else {
+ if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
+ gicv2m_init(handle, gic_data.domain);
}
if (gic_prio_masking_enabled()) {
diff --git a/drivers/irqchip/irq-gic-v4.c b/drivers/irqchip/irq-gic-v4.c
index dba9d67cb9c1..563e87ed0766 100644
--- a/drivers/irqchip/irq-gic-v4.c
+++ b/drivers/irqchip/irq-gic-v4.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2016,2017 ARM Limited, All Rights Reserved.
* Author: Marc Zyngier <marc.zyngier@arm.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/interrupt.h>
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index c6dbe5018972..e45f45e68720 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2002 ARM Limited, All Rights Reserved.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* Interrupt architecture for the GIC:
*
* o There is one Interrupt Distributor, which receives interrupts
diff --git a/drivers/irqchip/irq-hip04.c b/drivers/irqchip/irq-hip04.c
index 5b4fd2f4e5f8..cf705827599c 100644
--- a/drivers/irqchip/irq-hip04.c
+++ b/drivers/irqchip/irq-hip04.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Hisilicon HiP04 INTC
*
@@ -5,10 +6,6 @@
* Copyright (c) 2013-2014 Hisilicon Ltd.
* Copyright (c) 2013-2014 Linaro Ltd.
*
- * 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.
- *
* Interrupt architecture for the HIP04 INTC:
*
* o There is one Interrupt Distributor, which receives interrupts
diff --git a/drivers/irqchip/irq-imx-gpcv2.c b/drivers/irqchip/irq-imx-gpcv2.c
index 66501ea4fd75..bf2237ac5d09 100644
--- a/drivers/irqchip/irq-imx-gpcv2.c
+++ b/drivers/irqchip/irq-imx-gpcv2.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2015 Freescale Semiconductor, 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.
*/
#include <linux/of_address.h>
diff --git a/drivers/irqchip/irq-ixp4xx.c b/drivers/irqchip/irq-ixp4xx.c
index d576809429ac..6751c35b7e1d 100644
--- a/drivers/irqchip/irq-ixp4xx.c
+++ b/drivers/irqchip/irq-ixp4xx.c
@@ -252,10 +252,10 @@ static const struct ixp4xx_irq_chunk ixp4xx_irq_chunks[] = {
* @fwnode: Corresponding fwnode abstraction for this controller
* @is_356: if this is an IXP43x, IXP45x or IXP46x SoC variant
*/
-static int ixp4xx_irq_setup(struct ixp4xx_irq *ixi,
- void __iomem *irqbase,
- struct fwnode_handle *fwnode,
- bool is_356)
+static int __init ixp4xx_irq_setup(struct ixp4xx_irq *ixi,
+ void __iomem *irqbase,
+ struct fwnode_handle *fwnode,
+ bool is_356)
{
int nr_irqs;
diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c
index 669d29105772..61dbfda08527 100644
--- a/drivers/irqchip/irq-ls-scfg-msi.c
+++ b/drivers/irqchip/irq-ls-scfg-msi.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Freescale SCFG MSI(-X) support
*
* Copyright (C) 2016 Freescale Semiconductor.
*
* Author: Minghuan Lian <Minghuan.Lian@nxp.com>
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index 98b6e1d4b1a6..3dd28382d5f5 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2015 Hisilicon Limited, All Rights Reserved.
* Author: Jun Ma <majun258@huawei.com>
* Author: Yun Wu <wuyun.wu@huawei.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/acpi.h>
@@ -355,8 +344,7 @@ static int mbigen_device_probe(struct platform_device *pdev)
err = -EINVAL;
if (err) {
- dev_err(&pdev->dev, "Failed to create mbi-gen@%p irqdomain",
- mgn_chip->base);
+ dev_err(&pdev->dev, "Failed to create mbi-gen irqdomain\n");
return err;
}
diff --git a/drivers/irqchip/irq-meson-gpio.c b/drivers/irqchip/irq-meson-gpio.c
index 7b531fd075b8..dcdc23b9dce6 100644
--- a/drivers/irqchip/irq-meson-gpio.c
+++ b/drivers/irqchip/irq-meson-gpio.c
@@ -1,22 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2015 Endless Mobile, Inc.
* Author: Carlo Caione <carlo@endlessm.com>
* Copyright (c) 2016 BayLibre, SAS.
* Author: Jerome Brunet <jbrunet@baylibre.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- * The full GNU General Public License is included in this distribution
- * in the file called COPYING.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -73,6 +60,7 @@ static const struct of_device_id meson_irq_gpio_matches[] = {
{ .compatible = "amlogic,meson-gxbb-gpio-intc", .data = &gxbb_params },
{ .compatible = "amlogic,meson-gxl-gpio-intc", .data = &gxl_params },
{ .compatible = "amlogic,meson-axg-gpio-intc", .data = &axg_params },
+ { .compatible = "amlogic,meson-g12a-gpio-intc", .data = &axg_params },
{ }
};
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
index d32268cc1174..f3985469c221 100644
--- a/drivers/irqchip/irq-mips-gic.c
+++ b/drivers/irqchip/irq-mips-gic.c
@@ -388,7 +388,7 @@ static void gic_all_vpes_irq_cpu_online(struct irq_data *d)
intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
cd = irq_data_get_irq_chip_data(d);
- write_gic_vl_map(intr, cd->map);
+ write_gic_vl_map(mips_gic_vx_map_reg(intr), cd->map);
if (cd->mask)
write_gic_vl_smask(BIT(intr));
}
@@ -517,7 +517,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
spin_lock_irqsave(&gic_lock, flags);
for_each_online_cpu(cpu) {
write_gic_vl_other(mips_cm_vp_id(cpu));
- write_gic_vo_map(intr, map);
+ write_gic_vo_map(mips_gic_vx_map_reg(intr), map);
}
spin_unlock_irqrestore(&gic_lock, flags);
diff --git a/drivers/irqchip/irq-mmp.c b/drivers/irqchip/irq-mmp.c
index 8eed478f3b7e..14618dc0bd39 100644
--- a/drivers/irqchip/irq-mmp.c
+++ b/drivers/irqchip/irq-mmp.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/arch/arm/mach-mmp/irq.c
*
@@ -6,10 +7,6 @@
*
* Author: Bin Yang <bin.yang@marvell.com>
* Haojian Zhuang <haojian.zhuang@gmail.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/irqchip/irq-nvic.c b/drivers/irqchip/irq-nvic.c
index b1777104fd9f..a166d30deea2 100644
--- a/drivers/irqchip/irq-nvic.c
+++ b/drivers/irqchip/irq-nvic.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/irq/irq-nvic.c
*
* Copyright (C) 2008 ARM Limited, All Rights Reserved.
* Copyright (C) 2013 Pengutronix
*
- * 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.
- *
* Support for the Nested Vectored Interrupt Controller found on the
* ARMv7-M CPUs (Cortex-M3/M4)
*/
diff --git a/drivers/irqchip/irq-partition-percpu.c b/drivers/irqchip/irq-partition-percpu.c
index 1f7cc5933cd5..0c4c8ed7064e 100644
--- a/drivers/irqchip/irq-partition-percpu.c
+++ b/drivers/irqchip/irq-partition-percpu.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2016 ARM Limited, All Rights Reserved.
* Author: Marc Zyngier <marc.zyngier@arm.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/bitops.h>
diff --git a/drivers/irqchip/irq-renesas-intc-irqpin.c b/drivers/irqchip/irq-renesas-intc-irqpin.c
index 04c05a18600c..f82bc60a6793 100644
--- a/drivers/irqchip/irq-renesas-intc-irqpin.c
+++ b/drivers/irqchip/irq-renesas-intc-irqpin.c
@@ -508,7 +508,8 @@ static int intc_irqpin_probe(struct platform_device *pdev)
}
irq_chip = &p->irq_chip;
- irq_chip->name = name;
+ irq_chip->name = "intc-irqpin";
+ irq_chip->parent_device = dev;
irq_chip->irq_mask = disable_fn;
irq_chip->irq_unmask = enable_fn;
irq_chip->irq_set_type = intc_irqpin_irq_set_type;
diff --git a/drivers/irqchip/irq-renesas-irqc.c b/drivers/irqchip/irq-renesas-irqc.c
index a449a7c839b3..11abc09ef76c 100644
--- a/drivers/irqchip/irq-renesas-irqc.c
+++ b/drivers/irqchip/irq-renesas-irqc.c
@@ -7,7 +7,6 @@
#include <linux/init.h>
#include <linux/platform_device.h>
-#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/io.h>
@@ -48,7 +47,7 @@ struct irqc_priv {
void __iomem *cpu_int_base;
struct irqc_irq irq[IRQC_IRQ_MAX];
unsigned int number_of_irqs;
- struct platform_device *pdev;
+ struct device *dev;
struct irq_chip_generic *gc;
struct irq_domain *irq_domain;
atomic_t wakeup_path;
@@ -61,8 +60,7 @@ static struct irqc_priv *irq_data_to_priv(struct irq_data *data)
static void irqc_dbg(struct irqc_irq *i, char *str)
{
- dev_dbg(&i->p->pdev->dev, "%s (%d:%d)\n",
- str, i->requested_irq, i->hw_irq);
+ dev_dbg(i->p->dev, "%s (%d:%d)\n", str, i->requested_irq, i->hw_irq);
}
static unsigned char irqc_sense[IRQ_TYPE_SENSE_MASK + 1] = {
@@ -125,33 +123,22 @@ static irqreturn_t irqc_irq_handler(int irq, void *dev_id)
static int irqc_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
+ const char *name = dev_name(dev);
struct irqc_priv *p;
- struct resource *io;
struct resource *irq;
- const char *name = dev_name(&pdev->dev);
int ret;
int k;
- p = kzalloc(sizeof(*p), GFP_KERNEL);
- if (!p) {
- dev_err(&pdev->dev, "failed to allocate driver data\n");
- ret = -ENOMEM;
- goto err0;
- }
+ p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
- p->pdev = pdev;
+ p->dev = dev;
platform_set_drvdata(pdev, p);
- pm_runtime_enable(&pdev->dev);
- pm_runtime_get_sync(&pdev->dev);
-
- /* get hold of manadatory IOMEM */
- io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!io) {
- dev_err(&pdev->dev, "not enough IOMEM resources\n");
- ret = -EINVAL;
- goto err1;
- }
+ pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
/* allow any number of IRQs between 1 and IRQC_IRQ_MAX */
for (k = 0; k < IRQC_IRQ_MAX; k++) {
@@ -166,42 +153,41 @@ static int irqc_probe(struct platform_device *pdev)
p->number_of_irqs = k;
if (p->number_of_irqs < 1) {
- dev_err(&pdev->dev, "not enough IRQ resources\n");
+ dev_err(dev, "not enough IRQ resources\n");
ret = -EINVAL;
- goto err1;
+ goto err_runtime_pm_disable;
}
/* ioremap IOMEM and setup read/write callbacks */
- p->iomem = ioremap_nocache(io->start, resource_size(io));
- if (!p->iomem) {
- dev_err(&pdev->dev, "failed to remap IOMEM\n");
- ret = -ENXIO;
- goto err2;
+ p->iomem = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(p->iomem)) {
+ ret = PTR_ERR(p->iomem);
+ goto err_runtime_pm_disable;
}
p->cpu_int_base = p->iomem + IRQC_INT_CPU_BASE(0); /* SYS-SPI */
- p->irq_domain = irq_domain_add_linear(pdev->dev.of_node,
- p->number_of_irqs,
+ p->irq_domain = irq_domain_add_linear(dev->of_node, p->number_of_irqs,
&irq_generic_chip_ops, p);
if (!p->irq_domain) {
ret = -ENXIO;
- dev_err(&pdev->dev, "cannot initialize irq domain\n");
- goto err2;
+ dev_err(dev, "cannot initialize irq domain\n");
+ goto err_runtime_pm_disable;
}
ret = irq_alloc_domain_generic_chips(p->irq_domain, p->number_of_irqs,
- 1, name, handle_level_irq,
+ 1, "irqc", handle_level_irq,
0, 0, IRQ_GC_INIT_NESTED_LOCK);
if (ret) {
- dev_err(&pdev->dev, "cannot allocate generic chip\n");
- goto err3;
+ dev_err(dev, "cannot allocate generic chip\n");
+ goto err_remove_domain;
}
p->gc = irq_get_domain_generic_chip(p->irq_domain, 0);
p->gc->reg_base = p->cpu_int_base;
p->gc->chip_types[0].regs.enable = IRQC_EN_SET;
p->gc->chip_types[0].regs.disable = IRQC_EN_STS;
+ p->gc->chip_types[0].chip.parent_device = dev;
p->gc->chip_types[0].chip.irq_mask = irq_gc_mask_disable_reg;
p->gc->chip_types[0].chip.irq_unmask = irq_gc_unmask_enable_reg;
p->gc->chip_types[0].chip.irq_set_type = irqc_irq_set_type;
@@ -210,46 +196,33 @@ static int irqc_probe(struct platform_device *pdev)
/* request interrupts one by one */
for (k = 0; k < p->number_of_irqs; k++) {
- if (request_irq(p->irq[k].requested_irq, irqc_irq_handler,
- 0, name, &p->irq[k])) {
- dev_err(&pdev->dev, "failed to request IRQ\n");
+ if (devm_request_irq(dev, p->irq[k].requested_irq,
+ irqc_irq_handler, 0, name, &p->irq[k])) {
+ dev_err(dev, "failed to request IRQ\n");
ret = -ENOENT;
- goto err4;
+ goto err_remove_domain;
}
}
- dev_info(&pdev->dev, "driving %d irqs\n", p->number_of_irqs);
+ dev_info(dev, "driving %d irqs\n", p->number_of_irqs);
return 0;
-err4:
- while (--k >= 0)
- free_irq(p->irq[k].requested_irq, &p->irq[k]);
-err3:
+err_remove_domain:
irq_domain_remove(p->irq_domain);
-err2:
- iounmap(p->iomem);
-err1:
- pm_runtime_put(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
- kfree(p);
-err0:
+err_runtime_pm_disable:
+ pm_runtime_put(dev);
+ pm_runtime_disable(dev);
return ret;
}
static int irqc_remove(struct platform_device *pdev)
{
struct irqc_priv *p = platform_get_drvdata(pdev);
- int k;
-
- for (k = 0; k < p->number_of_irqs; k++)
- free_irq(p->irq[k].requested_irq, &p->irq[k]);
irq_domain_remove(p->irq_domain);
- iounmap(p->iomem);
pm_runtime_put(&pdev->dev);
pm_runtime_disable(&pdev->dev);
- kfree(p);
return 0;
}
diff --git a/drivers/irqchip/irq-renesas-rza1.c b/drivers/irqchip/irq-renesas-rza1.c
new file mode 100644
index 000000000000..b0d46ac42b89
--- /dev/null
+++ b/drivers/irqchip/irq-renesas-rza1.c
@@ -0,0 +1,284 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas RZ/A1 IRQC Driver
+ *
+ * Copyright (C) 2019 Glider bvba
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irqdomain.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#define IRQC_NUM_IRQ 8
+
+#define ICR0 0 /* Interrupt Control Register 0 */
+
+#define ICR0_NMIL BIT(15) /* NMI Input Level (0=low, 1=high) */
+#define ICR0_NMIE BIT(8) /* Edge Select (0=falling, 1=rising) */
+#define ICR0_NMIF BIT(1) /* NMI Interrupt Request */
+
+#define ICR1 2 /* Interrupt Control Register 1 */
+
+#define ICR1_IRQS(n, sense) ((sense) << ((n) * 2)) /* IRQ Sense Select */
+#define ICR1_IRQS_LEVEL_LOW 0
+#define ICR1_IRQS_EDGE_FALLING 1
+#define ICR1_IRQS_EDGE_RISING 2
+#define ICR1_IRQS_EDGE_BOTH 3
+#define ICR1_IRQS_MASK(n) ICR1_IRQS((n), 3)
+
+#define IRQRR 4 /* IRQ Interrupt Request Register */
+
+
+struct rza1_irqc_priv {
+ struct device *dev;
+ void __iomem *base;
+ struct irq_chip chip;
+ struct irq_domain *irq_domain;
+ struct of_phandle_args map[IRQC_NUM_IRQ];
+};
+
+static struct rza1_irqc_priv *irq_data_to_priv(struct irq_data *data)
+{
+ return data->domain->host_data;
+}
+
+static void rza1_irqc_eoi(struct irq_data *d)
+{
+ struct rza1_irqc_priv *priv = irq_data_to_priv(d);
+ u16 bit = BIT(irqd_to_hwirq(d));
+ u16 tmp;
+
+ tmp = readw_relaxed(priv->base + IRQRR);
+ if (tmp & bit)
+ writew_relaxed(GENMASK(IRQC_NUM_IRQ - 1, 0) & ~bit,
+ priv->base + IRQRR);
+
+ irq_chip_eoi_parent(d);
+}
+
+static int rza1_irqc_set_type(struct irq_data *d, unsigned int type)
+{
+ struct rza1_irqc_priv *priv = irq_data_to_priv(d);
+ unsigned int hw_irq = irqd_to_hwirq(d);
+ u16 sense, tmp;
+
+ switch (type & IRQ_TYPE_SENSE_MASK) {
+ case IRQ_TYPE_LEVEL_LOW:
+ sense = ICR1_IRQS_LEVEL_LOW;
+ break;
+
+ case IRQ_TYPE_EDGE_FALLING:
+ sense = ICR1_IRQS_EDGE_FALLING;
+ break;
+
+ case IRQ_TYPE_EDGE_RISING:
+ sense = ICR1_IRQS_EDGE_RISING;
+ break;
+
+ case IRQ_TYPE_EDGE_BOTH:
+ sense = ICR1_IRQS_EDGE_BOTH;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ tmp = readw_relaxed(priv->base + ICR1);
+ tmp &= ~ICR1_IRQS_MASK(hw_irq);
+ tmp |= ICR1_IRQS(hw_irq, sense);
+ writew_relaxed(tmp, priv->base + ICR1);
+ return 0;
+}
+
+static int rza1_irqc_alloc(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs, void *arg)
+{
+ struct rza1_irqc_priv *priv = domain->host_data;
+ struct irq_fwspec *fwspec = arg;
+ unsigned int hwirq = fwspec->param[0];
+ struct irq_fwspec spec;
+ unsigned int i;
+ int ret;
+
+ ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, &priv->chip,
+ priv);
+ if (ret)
+ return ret;
+
+ spec.fwnode = &priv->dev->of_node->fwnode;
+ spec.param_count = priv->map[hwirq].args_count;
+ for (i = 0; i < spec.param_count; i++)
+ spec.param[i] = priv->map[hwirq].args[i];
+
+ return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &spec);
+}
+
+static int rza1_irqc_translate(struct irq_domain *domain,
+ struct irq_fwspec *fwspec, unsigned long *hwirq,
+ unsigned int *type)
+{
+ if (fwspec->param_count != 2 || fwspec->param[0] >= IRQC_NUM_IRQ)
+ return -EINVAL;
+
+ *hwirq = fwspec->param[0];
+ *type = fwspec->param[1];
+ return 0;
+}
+
+static const struct irq_domain_ops rza1_irqc_domain_ops = {
+ .alloc = rza1_irqc_alloc,
+ .translate = rza1_irqc_translate,
+};
+
+static int rza1_irqc_parse_map(struct rza1_irqc_priv *priv,
+ struct device_node *gic_node)
+{
+ unsigned int imaplen, i, j, ret;
+ struct device *dev = priv->dev;
+ struct device_node *ipar;
+ const __be32 *imap;
+ u32 intsize;
+
+ imap = of_get_property(dev->of_node, "interrupt-map", &imaplen);
+ if (!imap)
+ return -EINVAL;
+
+ for (i = 0; i < IRQC_NUM_IRQ; i++) {
+ if (imaplen < 3)
+ return -EINVAL;
+
+ /* Check interrupt number, ignore sense */
+ if (be32_to_cpup(imap) != i)
+ return -EINVAL;
+
+ ipar = of_find_node_by_phandle(be32_to_cpup(imap + 2));
+ if (ipar != gic_node) {
+ of_node_put(ipar);
+ return -EINVAL;
+ }
+
+ imap += 3;
+ imaplen -= 3;
+
+ ret = of_property_read_u32(ipar, "#interrupt-cells", &intsize);
+ of_node_put(ipar);
+ if (ret)
+ return ret;
+
+ if (imaplen < intsize)
+ return -EINVAL;
+
+ priv->map[i].args_count = intsize;
+ for (j = 0; j < intsize; j++)
+ priv->map[i].args[j] = be32_to_cpup(imap++);
+
+ imaplen -= intsize;
+ }
+
+ return 0;
+}
+
+static int rza1_irqc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct irq_domain *parent = NULL;
+ struct device_node *gic_node;
+ struct rza1_irqc_priv *priv;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, priv);
+ priv->dev = dev;
+
+ priv->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ gic_node = of_irq_find_parent(np);
+ if (gic_node)
+ parent = irq_find_host(gic_node);
+
+ if (!parent) {
+ dev_err(dev, "cannot find parent domain\n");
+ ret = -ENODEV;
+ goto out_put_node;
+ }
+
+ ret = rza1_irqc_parse_map(priv, gic_node);
+ if (ret) {
+ dev_err(dev, "cannot parse %s: %d\n", "interrupt-map", ret);
+ goto out_put_node;
+ }
+
+ priv->chip.name = "rza1-irqc",
+ priv->chip.irq_mask = irq_chip_mask_parent,
+ priv->chip.irq_unmask = irq_chip_unmask_parent,
+ priv->chip.irq_eoi = rza1_irqc_eoi,
+ priv->chip.irq_retrigger = irq_chip_retrigger_hierarchy,
+ priv->chip.irq_set_type = rza1_irqc_set_type,
+ priv->chip.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE;
+
+ priv->irq_domain = irq_domain_add_hierarchy(parent, 0, IRQC_NUM_IRQ,
+ np, &rza1_irqc_domain_ops,
+ priv);
+ if (!priv->irq_domain) {
+ dev_err(dev, "cannot initialize irq domain\n");
+ ret = -ENOMEM;
+ }
+
+out_put_node:
+ of_node_put(gic_node);
+ return ret;
+}
+
+static int rza1_irqc_remove(struct platform_device *pdev)
+{
+ struct rza1_irqc_priv *priv = platform_get_drvdata(pdev);
+
+ irq_domain_remove(priv->irq_domain);
+ return 0;
+}
+
+static const struct of_device_id rza1_irqc_dt_ids[] = {
+ { .compatible = "renesas,rza1-irqc" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rza1_irqc_dt_ids);
+
+static struct platform_driver rza1_irqc_device_driver = {
+ .probe = rza1_irqc_probe,
+ .remove = rza1_irqc_remove,
+ .driver = {
+ .name = "renesas_rza1_irqc",
+ .of_match_table = rza1_irqc_dt_ids,
+ }
+};
+
+static int __init rza1_irqc_init(void)
+{
+ return platform_driver_register(&rza1_irqc_device_driver);
+}
+postcore_initcall(rza1_irqc_init);
+
+static void __exit rza1_irqc_exit(void)
+{
+ platform_driver_unregister(&rza1_irqc_device_driver);
+}
+module_exit(rza1_irqc_exit);
+
+MODULE_AUTHOR("Geert Uytterhoeven <geert+renesas@glider.be>");
+MODULE_DESCRIPTION("Renesas RZ/A1 IRQC Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/irqchip/irq-sa11x0.c b/drivers/irqchip/irq-sa11x0.c
index 61bb28d7b19b..dbccc7dafbf8 100644
--- a/drivers/irqchip/irq-sa11x0.c
+++ b/drivers/irqchip/irq-sa11x0.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2015 Dmitry Eremin-Solenikov
* Copyright (C) 1999-2001 Nicolas Pitre
*
* Generic IRQ handling for the SA11x0.
- *
- * 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.
*/
#include <linux/init.h>
#include <linux/module.h>
diff --git a/drivers/irqchip/irq-sni-exiu.c b/drivers/irqchip/irq-sni-exiu.c
index 1927b2f36ff6..1d027623c776 100644
--- a/drivers/irqchip/irq-sni-exiu.c
+++ b/drivers/irqchip/irq-sni-exiu.c
@@ -1,15 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for Socionext External Interrupt Unit (EXIU)
*
- * Copyright (c) 2017 Linaro, Ltd. <ard.biesheuvel@linaro.org>
+ * Copyright (c) 2017-2019 Linaro, Ltd. <ard.biesheuvel@linaro.org>
*
* Based on irq-tegra.c:
* Copyright (C) 2011 Google, Inc.
* Copyright (C) 2010,2013, NVIDIA Corporation
- *
- * 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.
*/
#include <linux/interrupt.h>
@@ -20,6 +17,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
+#include <linux/platform_device.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
@@ -134,9 +132,13 @@ static int exiu_domain_translate(struct irq_domain *domain,
*hwirq = fwspec->param[1] - info->spi_base;
*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
- return 0;
+ } else {
+ if (fwspec->param_count != 2)
+ return -EINVAL;
+ *hwirq = fwspec->param[0];
+ *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
}
- return -EINVAL;
+ return 0;
}
static int exiu_domain_alloc(struct irq_domain *dom, unsigned int virq,
@@ -147,16 +149,21 @@ static int exiu_domain_alloc(struct irq_domain *dom, unsigned int virq,
struct exiu_irq_data *info = dom->host_data;
irq_hw_number_t hwirq;
- if (fwspec->param_count != 3)
- return -EINVAL; /* Not GIC compliant */
- if (fwspec->param[0] != GIC_SPI)
- return -EINVAL; /* No PPI should point to this domain */
+ parent_fwspec = *fwspec;
+ if (is_of_node(dom->parent->fwnode)) {
+ if (fwspec->param_count != 3)
+ return -EINVAL; /* Not GIC compliant */
+ if (fwspec->param[0] != GIC_SPI)
+ return -EINVAL; /* No PPI should point to this domain */
+ hwirq = fwspec->param[1] - info->spi_base;
+ } else {
+ hwirq = fwspec->param[0];
+ parent_fwspec.param[0] = hwirq + info->spi_base + 32;
+ }
WARN_ON(nr_irqs != 1);
- hwirq = fwspec->param[1] - info->spi_base;
irq_domain_set_hwirq_and_chip(dom, virq, hwirq, &exiu_irq_chip, info);
- parent_fwspec = *fwspec;
parent_fwspec.fwnode = dom->parent->fwnode;
return irq_domain_alloc_irqs_parent(dom, virq, nr_irqs, &parent_fwspec);
}
@@ -167,35 +174,23 @@ static const struct irq_domain_ops exiu_domain_ops = {
.free = irq_domain_free_irqs_common,
};
-static int __init exiu_init(struct device_node *node,
- struct device_node *parent)
+static struct exiu_irq_data *exiu_init(const struct fwnode_handle *fwnode,
+ struct resource *res)
{
- struct irq_domain *parent_domain, *domain;
struct exiu_irq_data *data;
int err;
- if (!parent) {
- pr_err("%pOF: no parent, giving up\n", node);
- return -ENODEV;
- }
-
- parent_domain = irq_find_host(parent);
- if (!parent_domain) {
- pr_err("%pOF: unable to obtain parent domain\n", node);
- return -ENXIO;
- }
-
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
- if (of_property_read_u32(node, "socionext,spi-base", &data->spi_base)) {
- pr_err("%pOF: failed to parse 'spi-base' property\n", node);
+ if (fwnode_property_read_u32_array(fwnode, "socionext,spi-base",
+ &data->spi_base, 1)) {
err = -ENODEV;
goto out_free;
}
- data->base = of_iomap(node, 0);
+ data->base = ioremap(res->start, resource_size(res));
if (!data->base) {
err = -ENODEV;
goto out_free;
@@ -205,11 +200,44 @@ static int __init exiu_init(struct device_node *node,
writel_relaxed(0xFFFFFFFF, data->base + EIREQCLR);
writel_relaxed(0xFFFFFFFF, data->base + EIMASK);
+ return data;
+
+out_free:
+ kfree(data);
+ return ERR_PTR(err);
+}
+
+static int __init exiu_dt_init(struct device_node *node,
+ struct device_node *parent)
+{
+ struct irq_domain *parent_domain, *domain;
+ struct exiu_irq_data *data;
+ struct resource res;
+
+ if (!parent) {
+ pr_err("%pOF: no parent, giving up\n", node);
+ return -ENODEV;
+ }
+
+ parent_domain = irq_find_host(parent);
+ if (!parent_domain) {
+ pr_err("%pOF: unable to obtain parent domain\n", node);
+ return -ENXIO;
+ }
+
+ if (of_address_to_resource(node, 0, &res)) {
+ pr_err("%pOF: failed to parse memory resource\n", node);
+ return -ENXIO;
+ }
+
+ data = exiu_init(of_node_to_fwnode(node), &res);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
domain = irq_domain_add_hierarchy(parent_domain, 0, NUM_IRQS, node,
&exiu_domain_ops, data);
if (!domain) {
pr_err("%pOF: failed to allocate domain\n", node);
- err = -ENOMEM;
goto out_unmap;
}
@@ -220,8 +248,57 @@ static int __init exiu_init(struct device_node *node,
out_unmap:
iounmap(data->base);
-out_free:
kfree(data);
- return err;
+ return -ENOMEM;
+}
+IRQCHIP_DECLARE(exiu, "socionext,synquacer-exiu", exiu_dt_init);
+
+#ifdef CONFIG_ACPI
+static int exiu_acpi_probe(struct platform_device *pdev)
+{
+ struct irq_domain *domain;
+ struct exiu_irq_data *data;
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to parse memory resource\n");
+ return -ENXIO;
+ }
+
+ data = exiu_init(dev_fwnode(&pdev->dev), res);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ domain = acpi_irq_create_hierarchy(0, NUM_IRQS, dev_fwnode(&pdev->dev),
+ &exiu_domain_ops, data);
+ if (!domain) {
+ dev_err(&pdev->dev, "failed to create IRQ domain\n");
+ goto out_unmap;
+ }
+
+ dev_info(&pdev->dev, "%d interrupts forwarded\n", NUM_IRQS);
+
+ return 0;
+
+out_unmap:
+ iounmap(data->base);
+ kfree(data);
+ return -ENOMEM;
}
-IRQCHIP_DECLARE(exiu, "socionext,synquacer-exiu", exiu_init);
+
+static const struct acpi_device_id exiu_acpi_ids[] = {
+ { "SCX0008" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(acpi, exiu_acpi_ids);
+
+static struct platform_driver exiu_driver = {
+ .driver = {
+ .name = "exiu",
+ .acpi_match_table = exiu_acpi_ids,
+ },
+ .probe = exiu_acpi_probe,
+};
+builtin_platform_driver(exiu_driver);
+#endif
diff --git a/drivers/irqchip/irq-st.c b/drivers/irqchip/irq-st.c
index 5e0e250db0be..801551e46a7b 100644
--- a/drivers/irqchip/irq-st.c
+++ b/drivers/irqchip/irq-st.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 STMicroelectronics – All Rights Reserved
*
* Author: Lee Jones <lee.jones@linaro.org>
*
* This is a re-write of Christophe Kerello's PMU driver.
- *
- * 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.
*/
#include <dt-bindings/interrupt-controller/irq-st.h>
diff --git a/drivers/irqchip/irq-ti-sci-inta.c b/drivers/irqchip/irq-ti-sci-inta.c
index 011b60a49e3f..ef4d625d2d80 100644
--- a/drivers/irqchip/irq-ti-sci-inta.c
+++ b/drivers/irqchip/irq-ti-sci-inta.c
@@ -159,9 +159,9 @@ static struct ti_sci_inta_vint_desc *ti_sci_inta_alloc_parent_irq(struct irq_dom
parent_fwspec.param[1] = vint_desc->vint_id;
parent_virq = irq_create_fwspec_mapping(&parent_fwspec);
- if (parent_virq <= 0) {
+ if (parent_virq == 0) {
kfree(vint_desc);
- return ERR_PTR(parent_virq);
+ return ERR_PTR(-EINVAL);
}
vint_desc->parent_virq = parent_virq;
diff --git a/drivers/irqchip/irq-vf610-mscm-ir.c b/drivers/irqchip/irq-vf610-mscm-ir.c
index 56b5e3cb9de2..2b9a8ba58e26 100644
--- a/drivers/irqchip/irq-vf610-mscm-ir.c
+++ b/drivers/irqchip/irq-vf610-mscm-ir.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014-2015 Toradex AG
* Author: Stefan Agner <stefan@agner.ch>
*
- * 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.
- *
- *
* IRQ chip driver for MSCM interrupt router available on Vybrid SoC's.
* The interrupt router is between the CPU's interrupt controller and the
* peripheral. The router allows to route the peripheral interrupts to
diff --git a/drivers/irqchip/irq-zevio.c b/drivers/irqchip/irq-zevio.c
index cb9d8ec37507..5a7efeb3892d 100644
--- a/drivers/irqchip/irq-zevio.c
+++ b/drivers/irqchip/irq-zevio.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/irqchip/irq-zevio.c
*
* Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au>
- *
- * 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.
- *
*/
#include <linux/io.h>
diff --git a/drivers/irqchip/qcom-irq-combiner.c b/drivers/irqchip/qcom-irq-combiner.c
index 067337ab3f20..d88e993aa66d 100644
--- a/drivers/irqchip/qcom-irq-combiner.c
+++ b/drivers/irqchip/qcom-irq-combiner.c
@@ -229,7 +229,6 @@ static int get_registers(struct platform_device *pdev, struct combiner *comb)
static int __init combiner_probe(struct platform_device *pdev)
{
struct combiner *combiner;
- size_t alloc_sz;
int nregs;
int err;
@@ -239,8 +238,8 @@ static int __init combiner_probe(struct platform_device *pdev)
return -EINVAL;
}
- alloc_sz = sizeof(*combiner) + sizeof(struct combiner_reg) * nregs;
- combiner = devm_kzalloc(&pdev->dev, alloc_sz, GFP_KERNEL);
+ combiner = devm_kzalloc(&pdev->dev, struct_size(combiner, regs, nregs),
+ GFP_KERNEL);
if (!combiner)
return -ENOMEM;
diff --git a/drivers/isdn/Kconfig b/drivers/isdn/Kconfig
index 1ca4d70d198a..be8387c0eeef 100644
--- a/drivers/isdn/Kconfig
+++ b/drivers/isdn/Kconfig
@@ -21,59 +21,8 @@ menuconfig ISDN
if ISDN
-menuconfig ISDN_I4L
- tristate "Old ISDN4Linux (deprecated)"
- depends on TTY
- ---help---
- This driver allows you to use an ISDN adapter for networking
- connections and as dialin/out device. The isdn-tty's have a built
- in AT-compatible modem emulator. Network devices support autodial,
- channel-bundling, callback and caller-authentication without having
- a daemon running. A reduced T.70 protocol is supported with tty's
- suitable for German BTX. On D-Channel, the protocols EDSS1
- (Euro-ISDN) and 1TR6 (German style) are supported. See
- <file:Documentation/isdn/README> for more information.
-
- ISDN support in the linux kernel is moving towards a new API,
- called CAPI (Common ISDN Application Programming Interface).
- Therefore the old ISDN4Linux layer will eventually become obsolete.
- It is still available, though, for use with adapters that are not
- supported by the new CAPI subsystem yet.
-
-source "drivers/isdn/i4l/Kconfig"
-
-menuconfig ISDN_CAPI
- tristate "CAPI 2.0 subsystem"
- help
- This provides CAPI (the Common ISDN Application Programming
- Interface) Version 2.0, a standard making it easy for programs to
- access ISDN hardware in a device independent way. (For details see
- <http://www.capi.org/>.) CAPI supports making and accepting voice
- and data connections, controlling call options and protocols,
- as well as ISDN supplementary services like call forwarding or
- three-party conferences (if supported by the specific hardware
- driver).
-
- Select this option and the appropriate hardware driver below if
- you have an ISDN adapter supported by the CAPI subsystem.
-
-if ISDN_CAPI
-
source "drivers/isdn/capi/Kconfig"
-source "drivers/isdn/hardware/Kconfig"
-
-endif # ISDN_CAPI
-
-source "drivers/isdn/gigaset/Kconfig"
-
-source "drivers/isdn/hysdn/Kconfig"
-
source "drivers/isdn/mISDN/Kconfig"
-config ISDN_HDLC
- tristate
- select CRC_CCITT
- select BITREVERSE
-
endif # ISDN
diff --git a/drivers/isdn/Makefile b/drivers/isdn/Makefile
index e7d3d8f2ad5a..63baf27a2c79 100644
--- a/drivers/isdn/Makefile
+++ b/drivers/isdn/Makefile
@@ -3,12 +3,6 @@
# Object files in subdirectories
-obj-$(CONFIG_ISDN_I4L) += i4l/
obj-$(CONFIG_ISDN_CAPI) += capi/
obj-$(CONFIG_MISDN) += mISDN/
obj-$(CONFIG_ISDN) += hardware/
-obj-$(CONFIG_ISDN_DIVERSION) += divert/
-obj-$(CONFIG_ISDN_DRV_HISAX) += hisax/
-obj-$(CONFIG_ISDN_DRV_LOOP) += isdnloop/
-obj-$(CONFIG_HYSDN) += hysdn/
-obj-$(CONFIG_ISDN_DRV_GIGASET) += gigaset/
diff --git a/drivers/isdn/capi/Kconfig b/drivers/isdn/capi/Kconfig
index abaadce376c5..573fea5500ce 100644
--- a/drivers/isdn/capi/Kconfig
+++ b/drivers/isdn/capi/Kconfig
@@ -1,4 +1,22 @@
# SPDX-License-Identifier: GPL-2.0-only
+menuconfig ISDN_CAPI
+ tristate "CAPI 2.0 subsystem"
+ help
+ This provides CAPI (the Common ISDN Application Programming
+ Interface) Version 2.0, a standard making it easy for programs to
+ access ISDN hardware in a device independent way. (For details see
+ <http://www.capi.org/>.) CAPI supports making and accepting voice
+ and data connections, controlling call options and protocols,
+ as well as ISDN supplementary services like call forwarding or
+ three-party conferences (if supported by the specific hardware
+ driver).
+
+ This subsystem requires a hardware specific driver.
+ See CONFIG_BT_CMTP for the last remaining regular driver
+ in the kernel that uses the CAPI subsystem.
+
+if ISDN_CAPI
+
config CAPI_TRACE
bool "CAPI trace support"
default y
@@ -27,15 +45,6 @@ config ISDN_CAPI_MIDDLEWARE
device. If you want to use pppd with pppdcapiplugin to dial up to
your ISP, say Y here.
-config ISDN_CAPI_CAPIDRV
- tristate "CAPI2.0 capidrv interface support"
- depends on ISDN_I4L
- help
- This option provides the glue code to hook up CAPI driven cards to
- the legacy isdn4linux link layer. If you have a card which is
- supported by a CAPI driver, but still want to use old features like
- ippp interfaces or ttyI emulation, say Y/M here.
-
config ISDN_CAPI_CAPIDRV_VERBOSE
bool "Verbose reason code reporting"
depends on ISDN_CAPI_CAPIDRV
@@ -43,3 +52,5 @@ config ISDN_CAPI_CAPIDRV_VERBOSE
If you say Y here, the capidrv interface will give verbose reasons
for disconnecting. This will increase the size of the kernel by 7 KB.
If unsure, say N.
+
+endif
diff --git a/drivers/isdn/capi/Makefile b/drivers/isdn/capi/Makefile
index 06da3ed2c40a..d299f3e75f89 100644
--- a/drivers/isdn/capi/Makefile
+++ b/drivers/isdn/capi/Makefile
@@ -13,3 +13,5 @@ obj-$(CONFIG_ISDN_CAPI_CAPIDRV) += capidrv.o
kernelcapi-y := kcapi.o capiutil.o capilib.o
kernelcapi-$(CONFIG_PROC_FS) += kcapi_proc.o
+
+ccflags-y += -I$(srctree)/$(src)/../include -I$(srctree)/$(src)/../include/uapi
diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c
deleted file mode 100644
index e8949f3dcae1..000000000000
--- a/drivers/isdn/capi/capidrv.c
+++ /dev/null
@@ -1,2525 +0,0 @@
-/* $Id: capidrv.c,v 1.1.2.2 2004/01/12 23:17:24 keil Exp $
- *
- * ISDN4Linux Driver, using capi20 interface (kernelcapi)
- *
- * Copyright 1997 by Carsten Paeth <calle@calle.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/compiler.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/fcntl.h>
-#include <linux/fs.h>
-#include <linux/signal.h>
-#include <linux/mm.h>
-#include <linux/timer.h>
-#include <linux/wait.h>
-#include <linux/skbuff.h>
-#include <linux/isdn.h>
-#include <linux/isdnif.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/capi.h>
-#include <linux/kernelcapi.h>
-#include <linux/ctype.h>
-#include <linux/init.h>
-#include <linux/moduleparam.h>
-
-#include <linux/isdn/capiutil.h>
-#include <linux/isdn/capicmd.h>
-#include "capidrv.h"
-
-static int debugmode = 0;
-
-MODULE_DESCRIPTION("CAPI4Linux: Interface to ISDN4Linux");
-MODULE_AUTHOR("Carsten Paeth");
-MODULE_LICENSE("GPL");
-module_param(debugmode, uint, S_IRUGO | S_IWUSR);
-
-/* -------- type definitions ----------------------------------------- */
-
-
-struct capidrv_contr {
-
- struct capidrv_contr *next;
- struct module *owner;
- u32 contrnr;
- char name[20];
-
- /*
- * for isdn4linux
- */
- isdn_if interface;
- int myid;
-
- /*
- * LISTEN state
- */
- int state;
- u32 cipmask;
- u32 cipmask2;
- struct timer_list listentimer;
-
- /*
- * ID of capi message sent
- */
- u16 msgid;
-
- /*
- * B-Channels
- */
- int nbchan;
- struct capidrv_bchan {
- struct capidrv_contr *contr;
- u8 msn[ISDN_MSNLEN];
- int l2;
- int l3;
- u8 num[ISDN_MSNLEN];
- u8 mynum[ISDN_MSNLEN];
- int si1;
- int si2;
- int incoming;
- int disconnecting;
- struct capidrv_plci {
- struct capidrv_plci *next;
- u32 plci;
- u32 ncci; /* ncci for CONNECT_ACTIVE_IND */
- u16 msgid; /* to identfy CONNECT_CONF */
- int chan;
- int state;
- int leasedline;
- struct capidrv_ncci {
- struct capidrv_ncci *next;
- struct capidrv_plci *plcip;
- u32 ncci;
- u16 msgid; /* to identfy CONNECT_B3_CONF */
- int chan;
- int state;
- int oldstate;
- /* */
- u16 datahandle;
- struct ncci_datahandle_queue {
- struct ncci_datahandle_queue *next;
- u16 datahandle;
- int len;
- } *ackqueue;
- } *ncci_list;
- } *plcip;
- struct capidrv_ncci *nccip;
- } *bchans;
-
- struct capidrv_plci *plci_list;
-
- /* for q931 data */
- u8 q931_buf[4096];
- u8 *q931_read;
- u8 *q931_write;
- u8 *q931_end;
-};
-
-
-struct capidrv_data {
- struct capi20_appl ap;
- int ncontr;
- struct capidrv_contr *contr_list;
-};
-
-typedef struct capidrv_plci capidrv_plci;
-typedef struct capidrv_ncci capidrv_ncci;
-typedef struct capidrv_contr capidrv_contr;
-typedef struct capidrv_data capidrv_data;
-typedef struct capidrv_bchan capidrv_bchan;
-
-/* -------- data definitions ----------------------------------------- */
-
-static capidrv_data global;
-static DEFINE_SPINLOCK(global_lock);
-
-static void handle_dtrace_data(capidrv_contr *card,
- int send, int level2, u8 *data, u16 len);
-
-/* -------- convert functions ---------------------------------------- */
-
-static inline u32 b1prot(int l2, int l3)
-{
- switch (l2) {
- case ISDN_PROTO_L2_X75I:
- case ISDN_PROTO_L2_X75UI:
- case ISDN_PROTO_L2_X75BUI:
- return 0;
- case ISDN_PROTO_L2_HDLC:
- default:
- return 0;
- case ISDN_PROTO_L2_TRANS:
- return 1;
- case ISDN_PROTO_L2_V11096:
- case ISDN_PROTO_L2_V11019:
- case ISDN_PROTO_L2_V11038:
- return 2;
- case ISDN_PROTO_L2_FAX:
- return 4;
- case ISDN_PROTO_L2_MODEM:
- return 8;
- }
-}
-
-static inline u32 b2prot(int l2, int l3)
-{
- switch (l2) {
- case ISDN_PROTO_L2_X75I:
- case ISDN_PROTO_L2_X75UI:
- case ISDN_PROTO_L2_X75BUI:
- default:
- return 0;
- case ISDN_PROTO_L2_HDLC:
- case ISDN_PROTO_L2_TRANS:
- case ISDN_PROTO_L2_V11096:
- case ISDN_PROTO_L2_V11019:
- case ISDN_PROTO_L2_V11038:
- case ISDN_PROTO_L2_MODEM:
- return 1;
- case ISDN_PROTO_L2_FAX:
- return 4;
- }
-}
-
-static inline u32 b3prot(int l2, int l3)
-{
- switch (l2) {
- case ISDN_PROTO_L2_X75I:
- case ISDN_PROTO_L2_X75UI:
- case ISDN_PROTO_L2_X75BUI:
- case ISDN_PROTO_L2_HDLC:
- case ISDN_PROTO_L2_TRANS:
- case ISDN_PROTO_L2_V11096:
- case ISDN_PROTO_L2_V11019:
- case ISDN_PROTO_L2_V11038:
- case ISDN_PROTO_L2_MODEM:
- default:
- return 0;
- case ISDN_PROTO_L2_FAX:
- return 4;
- }
-}
-
-static _cstruct b1config_async_v110(u16 rate)
-{
- /* CAPI-Spec "B1 Configuration" */
- static unsigned char buf[9];
- buf[0] = 8; /* len */
- /* maximum bitrate */
- buf[1] = rate & 0xff; buf[2] = (rate >> 8) & 0xff;
- buf[3] = 8; buf[4] = 0; /* 8 bits per character */
- buf[5] = 0; buf[6] = 0; /* parity none */
- buf[7] = 0; buf[8] = 0; /* 1 stop bit */
- return buf;
-}
-
-static _cstruct b1config(int l2, int l3)
-{
- switch (l2) {
- case ISDN_PROTO_L2_X75I:
- case ISDN_PROTO_L2_X75UI:
- case ISDN_PROTO_L2_X75BUI:
- case ISDN_PROTO_L2_HDLC:
- case ISDN_PROTO_L2_TRANS:
- default:
- return NULL;
- case ISDN_PROTO_L2_V11096:
- return b1config_async_v110(9600);
- case ISDN_PROTO_L2_V11019:
- return b1config_async_v110(19200);
- case ISDN_PROTO_L2_V11038:
- return b1config_async_v110(38400);
- }
-}
-
-static inline u16 si2cip(u8 si1, u8 si2)
-{
- static const u8 cip[17][5] =
- {
- /* 0 1 2 3 4 */
- {0, 0, 0, 0, 0}, /*0 */
- {16, 16, 4, 26, 16}, /*1 */
- {17, 17, 17, 4, 4}, /*2 */
- {2, 2, 2, 2, 2}, /*3 */
- {18, 18, 18, 18, 18}, /*4 */
- {2, 2, 2, 2, 2}, /*5 */
- {0, 0, 0, 0, 0}, /*6 */
- {2, 2, 2, 2, 2}, /*7 */
- {2, 2, 2, 2, 2}, /*8 */
- {21, 21, 21, 21, 21}, /*9 */
- {19, 19, 19, 19, 19}, /*10 */
- {0, 0, 0, 0, 0}, /*11 */
- {0, 0, 0, 0, 0}, /*12 */
- {0, 0, 0, 0, 0}, /*13 */
- {0, 0, 0, 0, 0}, /*14 */
- {22, 22, 22, 22, 22}, /*15 */
- {27, 27, 27, 28, 27} /*16 */
- };
- if (si1 > 16)
- si1 = 0;
- if (si2 > 4)
- si2 = 0;
-
- return (u16) cip[si1][si2];
-}
-
-static inline u8 cip2si1(u16 cipval)
-{
- static const u8 si[32] =
- {7, 1, 7, 7, 1, 1, 7, 7, /*0-7 */
- 7, 1, 0, 0, 0, 0, 0, 0, /*8-15 */
- 1, 2, 4, 10, 9, 9, 15, 7, /*16-23 */
- 7, 7, 1, 16, 16, 0, 0, 0}; /*24-31 */
-
- if (cipval > 31)
- cipval = 0; /* .... */
- return si[cipval];
-}
-
-static inline u8 cip2si2(u16 cipval)
-{
- static const u8 si[32] =
- {0, 0, 0, 0, 2, 3, 0, 0, /*0-7 */
- 0, 3, 0, 0, 0, 0, 0, 0, /*8-15 */
- 1, 2, 0, 0, 9, 0, 0, 0, /*16-23 */
- 0, 0, 3, 2, 3, 0, 0, 0}; /*24-31 */
-
- if (cipval > 31)
- cipval = 0; /* .... */
- return si[cipval];
-}
-
-
-/* -------- controller management ------------------------------------- */
-
-static inline capidrv_contr *findcontrbydriverid(int driverid)
-{
- unsigned long flags;
- capidrv_contr *p;
-
- spin_lock_irqsave(&global_lock, flags);
- for (p = global.contr_list; p; p = p->next)
- if (p->myid == driverid)
- break;
- spin_unlock_irqrestore(&global_lock, flags);
- return p;
-}
-
-static capidrv_contr *findcontrbynumber(u32 contr)
-{
- unsigned long flags;
- capidrv_contr *p = global.contr_list;
-
- spin_lock_irqsave(&global_lock, flags);
- for (p = global.contr_list; p; p = p->next)
- if (p->contrnr == contr)
- break;
- spin_unlock_irqrestore(&global_lock, flags);
- return p;
-}
-
-
-/* -------- plci management ------------------------------------------ */
-
-static capidrv_plci *new_plci(capidrv_contr *card, int chan)
-{
- capidrv_plci *plcip;
-
- plcip = kzalloc(sizeof(capidrv_plci), GFP_ATOMIC);
-
- if (plcip == NULL)
- return NULL;
-
- plcip->state = ST_PLCI_NONE;
- plcip->plci = 0;
- plcip->msgid = 0;
- plcip->chan = chan;
- plcip->next = card->plci_list;
- card->plci_list = plcip;
- card->bchans[chan].plcip = plcip;
-
- return plcip;
-}
-
-static capidrv_plci *find_plci_by_plci(capidrv_contr *card, u32 plci)
-{
- capidrv_plci *p;
- for (p = card->plci_list; p; p = p->next)
- if (p->plci == plci)
- return p;
- return NULL;
-}
-
-static capidrv_plci *find_plci_by_msgid(capidrv_contr *card, u16 msgid)
-{
- capidrv_plci *p;
- for (p = card->plci_list; p; p = p->next)
- if (p->msgid == msgid)
- return p;
- return NULL;
-}
-
-static capidrv_plci *find_plci_by_ncci(capidrv_contr *card, u32 ncci)
-{
- capidrv_plci *p;
- for (p = card->plci_list; p; p = p->next)
- if (p->plci == (ncci & 0xffff))
- return p;
- return NULL;
-}
-
-static void free_plci(capidrv_contr *card, capidrv_plci *plcip)
-{
- capidrv_plci **pp;
-
- for (pp = &card->plci_list; *pp; pp = &(*pp)->next) {
- if (*pp == plcip) {
- *pp = (*pp)->next;
- card->bchans[plcip->chan].plcip = NULL;
- card->bchans[plcip->chan].disconnecting = 0;
- card->bchans[plcip->chan].incoming = 0;
- kfree(plcip);
- return;
- }
- }
- printk(KERN_ERR "capidrv-%d: free_plci %p (0x%x) not found, Huh?\n",
- card->contrnr, plcip, plcip->plci);
-}
-
-/* -------- ncci management ------------------------------------------ */
-
-static inline capidrv_ncci *new_ncci(capidrv_contr *card,
- capidrv_plci *plcip,
- u32 ncci)
-{
- capidrv_ncci *nccip;
-
- nccip = kzalloc(sizeof(capidrv_ncci), GFP_ATOMIC);
-
- if (nccip == NULL)
- return NULL;
-
- nccip->ncci = ncci;
- nccip->state = ST_NCCI_NONE;
- nccip->plcip = plcip;
- nccip->chan = plcip->chan;
- nccip->datahandle = 0;
-
- nccip->next = plcip->ncci_list;
- plcip->ncci_list = nccip;
-
- card->bchans[plcip->chan].nccip = nccip;
-
- return nccip;
-}
-
-static inline capidrv_ncci *find_ncci(capidrv_contr *card, u32 ncci)
-{
- capidrv_plci *plcip;
- capidrv_ncci *p;
-
- if ((plcip = find_plci_by_ncci(card, ncci)) == NULL)
- return NULL;
-
- for (p = plcip->ncci_list; p; p = p->next)
- if (p->ncci == ncci)
- return p;
- return NULL;
-}
-
-static inline capidrv_ncci *find_ncci_by_msgid(capidrv_contr *card,
- u32 ncci, u16 msgid)
-{
- capidrv_plci *plcip;
- capidrv_ncci *p;
-
- if ((plcip = find_plci_by_ncci(card, ncci)) == NULL)
- return NULL;
-
- for (p = plcip->ncci_list; p; p = p->next)
- if (p->msgid == msgid)
- return p;
- return NULL;
-}
-
-static void free_ncci(capidrv_contr *card, struct capidrv_ncci *nccip)
-{
- struct capidrv_ncci **pp;
-
- for (pp = &(nccip->plcip->ncci_list); *pp; pp = &(*pp)->next) {
- if (*pp == nccip) {
- *pp = (*pp)->next;
- break;
- }
- }
- card->bchans[nccip->chan].nccip = NULL;
- kfree(nccip);
-}
-
-static int capidrv_add_ack(struct capidrv_ncci *nccip,
- u16 datahandle, int len)
-{
- struct ncci_datahandle_queue *n, **pp;
-
- n = kmalloc(sizeof(struct ncci_datahandle_queue), GFP_ATOMIC);
- if (!n) {
- printk(KERN_ERR "capidrv: kmalloc ncci_datahandle failed\n");
- return -1;
- }
- n->next = NULL;
- n->datahandle = datahandle;
- n->len = len;
- for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next);
- *pp = n;
- return 0;
-}
-
-static int capidrv_del_ack(struct capidrv_ncci *nccip, u16 datahandle)
-{
- struct ncci_datahandle_queue **pp, *p;
- int len;
-
- for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) {
- if ((*pp)->datahandle == datahandle) {
- p = *pp;
- len = p->len;
- *pp = (*pp)->next;
- kfree(p);
- return len;
- }
- }
- return -1;
-}
-
-/* -------- convert and send capi message ---------------------------- */
-
-static void send_message(capidrv_contr *card, _cmsg *cmsg)
-{
- struct sk_buff *skb;
- size_t len;
-
- if (capi_cmsg2message(cmsg, cmsg->buf)) {
- printk(KERN_ERR "capidrv::send_message: parser failure\n");
- return;
- }
- len = CAPIMSG_LEN(cmsg->buf);
- skb = alloc_skb(len, GFP_ATOMIC);
- if (!skb) {
- printk(KERN_ERR "capidrv::send_message: can't allocate mem\n");
- return;
- }
- skb_put_data(skb, cmsg->buf, len);
- if (capi20_put_message(&global.ap, skb) != CAPI_NOERROR)
- kfree_skb(skb);
-}
-
-/* -------- state machine -------------------------------------------- */
-
-struct listenstatechange {
- int actstate;
- int nextstate;
- int event;
-};
-
-static struct listenstatechange listentable[] =
-{
- {ST_LISTEN_NONE, ST_LISTEN_WAIT_CONF, EV_LISTEN_REQ},
- {ST_LISTEN_ACTIVE, ST_LISTEN_ACTIVE_WAIT_CONF, EV_LISTEN_REQ},
- {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_ERROR},
- {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_ERROR},
- {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY},
- {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY},
- {ST_LISTEN_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK},
- {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK},
- {},
-};
-
-static void listen_change_state(capidrv_contr *card, int event)
-{
- struct listenstatechange *p = listentable;
- while (p->event) {
- if (card->state == p->actstate && p->event == event) {
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: listen_change_state %d -> %d\n",
- card->contrnr, card->state, p->nextstate);
- card->state = p->nextstate;
- return;
- }
- p++;
- }
- printk(KERN_ERR "capidrv-%d: listen_change_state state=%d event=%d ????\n",
- card->contrnr, card->state, event);
-
-}
-
-/* ------------------------------------------------------------------ */
-
-static void p0(capidrv_contr *card, capidrv_plci *plci)
-{
- isdn_ctrl cmd;
-
- card->bchans[plci->chan].contr = NULL;
- cmd.command = ISDN_STAT_DHUP;
- cmd.driver = card->myid;
- cmd.arg = plci->chan;
- card->interface.statcallb(&cmd);
- free_plci(card, plci);
-}
-
-/* ------------------------------------------------------------------ */
-
-struct plcistatechange {
- int actstate;
- int nextstate;
- int event;
- void (*changefunc)(capidrv_contr *card, capidrv_plci *plci);
-};
-
-static struct plcistatechange plcitable[] =
-{
- /* P-0 */
- {ST_PLCI_NONE, ST_PLCI_OUTGOING, EV_PLCI_CONNECT_REQ, NULL},
- {ST_PLCI_NONE, ST_PLCI_ALLOCATED, EV_PLCI_FACILITY_IND_UP, NULL},
- {ST_PLCI_NONE, ST_PLCI_INCOMING, EV_PLCI_CONNECT_IND, NULL},
- {ST_PLCI_NONE, ST_PLCI_RESUMEING, EV_PLCI_RESUME_REQ, NULL},
- /* P-0.1 */
- {ST_PLCI_OUTGOING, ST_PLCI_NONE, EV_PLCI_CONNECT_CONF_ERROR, p0},
- {ST_PLCI_OUTGOING, ST_PLCI_ALLOCATED, EV_PLCI_CONNECT_CONF_OK, NULL},
- /* P-1 */
- {ST_PLCI_ALLOCATED, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, NULL},
- {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
- {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
- {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
- /* P-ACT */
- {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
- {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
- {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
- {ST_PLCI_ACTIVE, ST_PLCI_HELD, EV_PLCI_HOLD_IND, NULL},
- {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_SUSPEND_IND, NULL},
- /* P-2 */
- {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, NULL},
- {ST_PLCI_INCOMING, ST_PLCI_FACILITY_IND, EV_PLCI_FACILITY_IND_UP, NULL},
- {ST_PLCI_INCOMING, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_RESP, NULL},
- {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
- {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
- {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
- {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CD_IND, NULL},
- /* P-3 */
- {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, NULL},
- {ST_PLCI_FACILITY_IND, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_ACTIVE_IND, NULL},
- {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
- {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
- {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
- /* P-4 */
- {ST_PLCI_ACCEPTING, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, NULL},
- {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
- {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
- {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
- /* P-5 */
- {ST_PLCI_DISCONNECTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
- /* P-6 */
- {ST_PLCI_DISCONNECTED, ST_PLCI_NONE, EV_PLCI_DISCONNECT_RESP, p0},
- /* P-0.Res */
- {ST_PLCI_RESUMEING, ST_PLCI_NONE, EV_PLCI_RESUME_CONF_ERROR, p0},
- {ST_PLCI_RESUMEING, ST_PLCI_RESUME, EV_PLCI_RESUME_CONF_OK, NULL},
- /* P-RES */
- {ST_PLCI_RESUME, ST_PLCI_ACTIVE, EV_PLCI_RESUME_IND, NULL},
- /* P-HELD */
- {ST_PLCI_HELD, ST_PLCI_ACTIVE, EV_PLCI_RETRIEVE_IND, NULL},
- {},
-};
-
-static void plci_change_state(capidrv_contr *card, capidrv_plci *plci, int event)
-{
- struct plcistatechange *p = plcitable;
- while (p->event) {
- if (plci->state == p->actstate && p->event == event) {
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: plci_change_state:0x%x %d -> %d\n",
- card->contrnr, plci->plci, plci->state, p->nextstate);
- plci->state = p->nextstate;
- if (p->changefunc)
- p->changefunc(card, plci);
- return;
- }
- p++;
- }
- printk(KERN_ERR "capidrv-%d: plci_change_state:0x%x state=%d event=%d ????\n",
- card->contrnr, plci->plci, plci->state, event);
-}
-
-/* ------------------------------------------------------------------ */
-
-static _cmsg cmsg;
-
-static void n0(capidrv_contr *card, capidrv_ncci *ncci)
-{
- isdn_ctrl cmd;
-
- capi_fill_DISCONNECT_REQ(&cmsg,
- global.ap.applid,
- card->msgid++,
- ncci->plcip->plci,
- NULL, /* BChannelinformation */
- NULL, /* Keypadfacility */
- NULL, /* Useruserdata */ /* $$$$ */
- NULL /* Facilitydataarray */
- );
- plci_change_state(card, ncci->plcip, EV_PLCI_DISCONNECT_REQ);
- send_message(card, &cmsg);
-
- cmd.command = ISDN_STAT_BHUP;
- cmd.driver = card->myid;
- cmd.arg = ncci->chan;
- card->interface.statcallb(&cmd);
- free_ncci(card, ncci);
-}
-
-/* ------------------------------------------------------------------ */
-
-struct nccistatechange {
- int actstate;
- int nextstate;
- int event;
- void (*changefunc)(capidrv_contr *card, capidrv_ncci *ncci);
-};
-
-static struct nccistatechange nccitable[] =
-{
- /* N-0 */
- {ST_NCCI_NONE, ST_NCCI_OUTGOING, EV_NCCI_CONNECT_B3_REQ, NULL},
- {ST_NCCI_NONE, ST_NCCI_INCOMING, EV_NCCI_CONNECT_B3_IND, NULL},
- /* N-0.1 */
- {ST_NCCI_OUTGOING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_CONF_OK, NULL},
- {ST_NCCI_OUTGOING, ST_NCCI_NONE, EV_NCCI_CONNECT_B3_CONF_ERROR, n0},
- /* N-1 */
- {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_CONNECT_B3_REJECT, NULL},
- {ST_NCCI_INCOMING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_RESP, NULL},
- {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
- {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL},
- /* N-2 */
- {ST_NCCI_ALLOCATED, ST_NCCI_ACTIVE, EV_NCCI_CONNECT_B3_ACTIVE_IND, NULL},
- {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
- {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL},
- /* N-ACT */
- {ST_NCCI_ACTIVE, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, NULL},
- {ST_NCCI_ACTIVE, ST_NCCI_RESETING, EV_NCCI_RESET_B3_REQ, NULL},
- {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
- {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL},
- /* N-3 */
- {ST_NCCI_RESETING, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, NULL},
- {ST_NCCI_RESETING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
- {ST_NCCI_RESETING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL},
- /* N-4 */
- {ST_NCCI_DISCONNECTING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
- {ST_NCCI_DISCONNECTING, ST_NCCI_PREVIOUS, EV_NCCI_DISCONNECT_B3_CONF_ERROR, NULL},
- /* N-5 */
- {ST_NCCI_DISCONNECTED, ST_NCCI_NONE, EV_NCCI_DISCONNECT_B3_RESP, n0},
- {},
-};
-
-static void ncci_change_state(capidrv_contr *card, capidrv_ncci *ncci, int event)
-{
- struct nccistatechange *p = nccitable;
- while (p->event) {
- if (ncci->state == p->actstate && p->event == event) {
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: ncci_change_state:0x%x %d -> %d\n",
- card->contrnr, ncci->ncci, ncci->state, p->nextstate);
- if (p->nextstate == ST_NCCI_PREVIOUS) {
- ncci->state = ncci->oldstate;
- ncci->oldstate = p->actstate;
- } else {
- ncci->oldstate = p->actstate;
- ncci->state = p->nextstate;
- }
- if (p->changefunc)
- p->changefunc(card, ncci);
- return;
- }
- p++;
- }
- printk(KERN_ERR "capidrv-%d: ncci_change_state:0x%x state=%d event=%d ????\n",
- card->contrnr, ncci->ncci, ncci->state, event);
-}
-
-/* ------------------------------------------------------------------- */
-
-static inline int new_bchan(capidrv_contr *card)
-{
- int i;
- for (i = 0; i < card->nbchan; i++) {
- if (card->bchans[i].plcip == NULL) {
- card->bchans[i].disconnecting = 0;
- return i;
- }
- }
- return -1;
-}
-
-/* ------------------------------------------------------------------- */
-static char *capi_info2str(u16 reason)
-{
-#ifndef CONFIG_ISDN_CAPI_CAPIDRV_VERBOSE
- return "..";
-#else
- switch (reason) {
-
-/*-- informative values (corresponding message was processed) -----*/
- case 0x0001:
- return "NCPI not supported by current protocol, NCPI ignored";
- case 0x0002:
- return "Flags not supported by current protocol, flags ignored";
- case 0x0003:
- return "Alert already sent by another application";
-
-/*-- error information concerning CAPI_REGISTER -----*/
- case 0x1001:
- return "Too many applications";
- case 0x1002:
- return "Logical block size too small, must be at least 128 Bytes";
- case 0x1003:
- return "Buffer exceeds 64 kByte";
- case 0x1004:
- return "Message buffer size too small, must be at least 1024 Bytes";
- case 0x1005:
- return "Max. number of logical connections not supported";
- case 0x1006:
- return "Reserved";
- case 0x1007:
- return "The message could not be accepted because of an internal busy condition";
- case 0x1008:
- return "OS resource error (no memory ?)";
- case 0x1009:
- return "CAPI not installed";
- case 0x100A:
- return "Controller does not support external equipment";
- case 0x100B:
- return "Controller does only support external equipment";
-
-/*-- error information concerning message exchange functions -----*/
- case 0x1101:
- return "Illegal application number";
- case 0x1102:
- return "Illegal command or subcommand or message length less than 12 bytes";
- case 0x1103:
- return "The message could not be accepted because of a queue full condition !! The error code does not imply that CAPI cannot receive messages directed to another controller, PLCI or NCCI";
- case 0x1104:
- return "Queue is empty";
- case 0x1105:
- return "Queue overflow, a message was lost !! This indicates a configuration error. The only recovery from this error is to perform a CAPI_RELEASE";
- case 0x1106:
- return "Unknown notification parameter";
- case 0x1107:
- return "The Message could not be accepted because of an internal busy condition";
- case 0x1108:
- return "OS Resource error (no memory ?)";
- case 0x1109:
- return "CAPI not installed";
- case 0x110A:
- return "Controller does not support external equipment";
- case 0x110B:
- return "Controller does only support external equipment";
-
-/*-- error information concerning resource / coding problems -----*/
- case 0x2001:
- return "Message not supported in current state";
- case 0x2002:
- return "Illegal Controller / PLCI / NCCI";
- case 0x2003:
- return "Out of PLCI";
- case 0x2004:
- return "Out of NCCI";
- case 0x2005:
- return "Out of LISTEN";
- case 0x2006:
- return "Out of FAX resources (protocol T.30)";
- case 0x2007:
- return "Illegal message parameter coding";
-
-/*-- error information concerning requested services -----*/
- case 0x3001:
- return "B1 protocol not supported";
- case 0x3002:
- return "B2 protocol not supported";
- case 0x3003:
- return "B3 protocol not supported";
- case 0x3004:
- return "B1 protocol parameter not supported";
- case 0x3005:
- return "B2 protocol parameter not supported";
- case 0x3006:
- return "B3 protocol parameter not supported";
- case 0x3007:
- return "B protocol combination not supported";
- case 0x3008:
- return "NCPI not supported";
- case 0x3009:
- return "CIP Value unknown";
- case 0x300A:
- return "Flags not supported (reserved bits)";
- case 0x300B:
- return "Facility not supported";
- case 0x300C:
- return "Data length not supported by current protocol";
- case 0x300D:
- return "Reset procedure not supported by current protocol";
-
-/*-- informations about the clearing of a physical connection -----*/
- case 0x3301:
- return "Protocol error layer 1 (broken line or B-channel removed by signalling protocol)";
- case 0x3302:
- return "Protocol error layer 2";
- case 0x3303:
- return "Protocol error layer 3";
- case 0x3304:
- return "Another application got that call";
-/*-- T.30 specific reasons -----*/
- case 0x3311:
- return "Connecting not successful (remote station is no FAX G3 machine)";
- case 0x3312:
- return "Connecting not successful (training error)";
- case 0x3313:
- return "Disconnected before transfer (remote station does not support transfer mode, e.g. resolution)";
- case 0x3314:
- return "Disconnected during transfer (remote abort)";
- case 0x3315:
- return "Disconnected during transfer (remote procedure error, e.g. unsuccessful repetition of T.30 commands)";
- case 0x3316:
- return "Disconnected during transfer (local tx data underrun)";
- case 0x3317:
- return "Disconnected during transfer (local rx data overflow)";
- case 0x3318:
- return "Disconnected during transfer (local abort)";
- case 0x3319:
- return "Illegal parameter coding (e.g. SFF coding error)";
-
-/*-- disconnect causes from the network according to ETS 300 102-1/Q.931 -----*/
- case 0x3481: return "Unallocated (unassigned) number";
- case 0x3482: return "No route to specified transit network";
- case 0x3483: return "No route to destination";
- case 0x3486: return "Channel unacceptable";
- case 0x3487:
- return "Call awarded and being delivered in an established channel";
- case 0x3490: return "Normal call clearing";
- case 0x3491: return "User busy";
- case 0x3492: return "No user responding";
- case 0x3493: return "No answer from user (user alerted)";
- case 0x3495: return "Call rejected";
- case 0x3496: return "Number changed";
- case 0x349A: return "Non-selected user clearing";
- case 0x349B: return "Destination out of order";
- case 0x349C: return "Invalid number format";
- case 0x349D: return "Facility rejected";
- case 0x349E: return "Response to STATUS ENQUIRY";
- case 0x349F: return "Normal, unspecified";
- case 0x34A2: return "No circuit / channel available";
- case 0x34A6: return "Network out of order";
- case 0x34A9: return "Temporary failure";
- case 0x34AA: return "Switching equipment congestion";
- case 0x34AB: return "Access information discarded";
- case 0x34AC: return "Requested circuit / channel not available";
- case 0x34AF: return "Resources unavailable, unspecified";
- case 0x34B1: return "Quality of service unavailable";
- case 0x34B2: return "Requested facility not subscribed";
- case 0x34B9: return "Bearer capability not authorized";
- case 0x34BA: return "Bearer capability not presently available";
- case 0x34BF: return "Service or option not available, unspecified";
- case 0x34C1: return "Bearer capability not implemented";
- case 0x34C2: return "Channel type not implemented";
- case 0x34C5: return "Requested facility not implemented";
- case 0x34C6: return "Only restricted digital information bearer capability is available";
- case 0x34CF: return "Service or option not implemented, unspecified";
- case 0x34D1: return "Invalid call reference value";
- case 0x34D2: return "Identified channel does not exist";
- case 0x34D3: return "A suspended call exists, but this call identity does not";
- case 0x34D4: return "Call identity in use";
- case 0x34D5: return "No call suspended";
- case 0x34D6: return "Call having the requested call identity has been cleared";
- case 0x34D8: return "Incompatible destination";
- case 0x34DB: return "Invalid transit network selection";
- case 0x34DF: return "Invalid message, unspecified";
- case 0x34E0: return "Mandatory information element is missing";
- case 0x34E1: return "Message type non-existent or not implemented";
- case 0x34E2: return "Message not compatible with call state or message type non-existent or not implemented";
- case 0x34E3: return "Information element non-existent or not implemented";
- case 0x34E4: return "Invalid information element contents";
- case 0x34E5: return "Message not compatible with call state";
- case 0x34E6: return "Recovery on timer expiry";
- case 0x34EF: return "Protocol error, unspecified";
- case 0x34FF: return "Interworking, unspecified";
-
- default: return "No additional information";
- }
-#endif
-}
-
-static void handle_controller(_cmsg *cmsg)
-{
- capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
-
- if (!card) {
- printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrController & 0x7f);
- return;
- }
- switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
-
- case CAPI_LISTEN_CONF: /* Controller */
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: listenconf Info=0x%4x (%s) cipmask=0x%x\n",
- card->contrnr, cmsg->Info, capi_info2str(cmsg->Info), card->cipmask);
- if (cmsg->Info) {
- listen_change_state(card, EV_LISTEN_CONF_ERROR);
- } else if (card->cipmask == 0) {
- listen_change_state(card, EV_LISTEN_CONF_EMPTY);
- } else {
- listen_change_state(card, EV_LISTEN_CONF_OK);
- }
- break;
-
- case CAPI_MANUFACTURER_IND: /* Controller */
- if (cmsg->ManuID == 0x214D5641
- && cmsg->Class == 0
- && cmsg->Function == 1) {
- u8 *data = cmsg->ManuData + 3;
- u16 len = cmsg->ManuData[0];
- u16 layer;
- int direction;
- if (len == 255) {
- len = (cmsg->ManuData[1] | (cmsg->ManuData[2] << 8));
- data += 2;
- }
- len -= 2;
- layer = ((*(data - 1)) << 8) | *(data - 2);
- if (layer & 0x300)
- direction = (layer & 0x200) ? 0 : 1;
- else direction = (layer & 0x800) ? 0 : 1;
- if (layer & 0x0C00) {
- if ((layer & 0xff) == 0x80) {
- handle_dtrace_data(card, direction, 1, data, len);
- break;
- }
- } else if ((layer & 0xff) < 0x80) {
- handle_dtrace_data(card, direction, 0, data, len);
- break;
- }
- printk(KERN_INFO "capidrv-%d: %s from controller 0x%x layer 0x%x, ignored\n",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrController, layer);
- break;
- }
- goto ignored;
- case CAPI_MANUFACTURER_CONF: /* Controller */
- if (cmsg->ManuID == 0x214D5641) {
- char *s = NULL;
- switch (cmsg->Class) {
- case 0: break;
- case 1: s = "unknown class"; break;
- case 2: s = "unknown function"; break;
- default: s = "unknown error"; break;
- }
- if (s)
- printk(KERN_INFO "capidrv-%d: %s from controller 0x%x function %d: %s\n",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrController,
- cmsg->Function, s);
- break;
- }
- goto ignored;
- case CAPI_FACILITY_IND: /* Controller/plci/ncci */
- goto ignored;
- case CAPI_FACILITY_CONF: /* Controller/plci/ncci */
- goto ignored;
- case CAPI_INFO_IND: /* Controller/plci */
- goto ignored;
- case CAPI_INFO_CONF: /* Controller/plci */
- goto ignored;
-
- default:
- printk(KERN_ERR "capidrv-%d: got %s from controller 0x%x ???",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrController);
- }
- return;
-
-ignored:
- printk(KERN_INFO "capidrv-%d: %s from controller 0x%x ignored\n",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrController);
-}
-
-static void handle_incoming_call(capidrv_contr *card, _cmsg *cmsg)
-{
- capidrv_plci *plcip;
- capidrv_bchan *bchan;
- isdn_ctrl cmd;
- int chan;
-
- if ((chan = new_bchan(card)) == -1) {
- printk(KERN_ERR "capidrv-%d: incoming call on not existing bchan ?\n", card->contrnr);
- return;
- }
- bchan = &card->bchans[chan];
- if ((plcip = new_plci(card, chan)) == NULL) {
- printk(KERN_ERR "capidrv-%d: incoming call: no memory, sorry.\n", card->contrnr);
- return;
- }
- bchan->incoming = 1;
- plcip->plci = cmsg->adr.adrPLCI;
- plci_change_state(card, plcip, EV_PLCI_CONNECT_IND);
-
- cmd.command = ISDN_STAT_ICALL;
- cmd.driver = card->myid;
- cmd.arg = chan;
- memset(&cmd.parm.setup, 0, sizeof(cmd.parm.setup));
- strncpy(cmd.parm.setup.phone,
- cmsg->CallingPartyNumber + 3,
- cmsg->CallingPartyNumber[0] - 2);
- strncpy(cmd.parm.setup.eazmsn,
- cmsg->CalledPartyNumber + 2,
- cmsg->CalledPartyNumber[0] - 1);
- cmd.parm.setup.si1 = cip2si1(cmsg->CIPValue);
- cmd.parm.setup.si2 = cip2si2(cmsg->CIPValue);
- cmd.parm.setup.plan = cmsg->CallingPartyNumber[1];
- cmd.parm.setup.screen = cmsg->CallingPartyNumber[2];
-
- printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s\n",
- card->contrnr,
- cmd.parm.setup.phone,
- cmd.parm.setup.si1,
- cmd.parm.setup.si2,
- cmd.parm.setup.eazmsn);
-
- if (cmd.parm.setup.si1 == 1 && cmd.parm.setup.si2 != 0) {
- printk(KERN_INFO "capidrv-%d: patching si2=%d to 0 for VBOX\n",
- card->contrnr,
- cmd.parm.setup.si2);
- cmd.parm.setup.si2 = 0;
- }
-
- switch (card->interface.statcallb(&cmd)) {
- case 0:
- case 3:
- /* No device matching this call.
- * and isdn_common.c has send a HANGUP command
- * which is ignored in state ST_PLCI_INCOMING,
- * so we send RESP to ignore the call
- */
- capi_cmsg_answer(cmsg);
- cmsg->Reject = 1; /* ignore */
- plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
- send_message(card, cmsg);
- printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s ignored\n",
- card->contrnr,
- cmd.parm.setup.phone,
- cmd.parm.setup.si1,
- cmd.parm.setup.si2,
- cmd.parm.setup.eazmsn);
- break;
- case 1:
- /* At least one device matching this call (RING on ttyI)
- * HL-driver may send ALERTING on the D-channel in this
- * case.
- * really means: RING on ttyI or a net interface
- * accepted this call already.
- *
- * If the call was accepted, state has already changed,
- * and CONNECT_RESP already sent.
- */
- if (plcip->state == ST_PLCI_INCOMING) {
- printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s tty alerting\n",
- card->contrnr,
- cmd.parm.setup.phone,
- cmd.parm.setup.si1,
- cmd.parm.setup.si2,
- cmd.parm.setup.eazmsn);
- capi_fill_ALERT_REQ(cmsg,
- global.ap.applid,
- card->msgid++,
- plcip->plci, /* adr */
- NULL,/* BChannelinformation */
- NULL,/* Keypadfacility */
- NULL,/* Useruserdata */
- NULL /* Facilitydataarray */
- );
- plcip->msgid = cmsg->Messagenumber;
- send_message(card, cmsg);
- } else {
- printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s on netdev\n",
- card->contrnr,
- cmd.parm.setup.phone,
- cmd.parm.setup.si1,
- cmd.parm.setup.si2,
- cmd.parm.setup.eazmsn);
- }
- break;
-
- case 2: /* Call will be rejected. */
- capi_cmsg_answer(cmsg);
- cmsg->Reject = 2; /* reject call, normal call clearing */
- plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
- send_message(card, cmsg);
- break;
-
- default:
- /* An error happened. (Invalid parameters for example.) */
- capi_cmsg_answer(cmsg);
- cmsg->Reject = 8; /* reject call,
- destination out of order */
- plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
- send_message(card, cmsg);
- break;
- }
- return;
-}
-
-static void handle_plci(_cmsg *cmsg)
-{
- capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
- capidrv_plci *plcip;
- isdn_ctrl cmd;
- _cdebbuf *cdb;
-
- if (!card) {
- printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrController & 0x7f);
- return;
- }
- switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
-
- case CAPI_DISCONNECT_IND: /* plci */
- if (cmsg->Reason) {
- printk(KERN_INFO "capidrv-%d: %s reason 0x%x (%s) for plci 0x%x\n",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->Reason, capi_info2str(cmsg->Reason), cmsg->adr.adrPLCI);
- }
- if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI))) {
- capi_cmsg_answer(cmsg);
- send_message(card, cmsg);
- goto notfound;
- }
- card->bchans[plcip->chan].disconnecting = 1;
- plci_change_state(card, plcip, EV_PLCI_DISCONNECT_IND);
- capi_cmsg_answer(cmsg);
- plci_change_state(card, plcip, EV_PLCI_DISCONNECT_RESP);
- send_message(card, cmsg);
- break;
-
- case CAPI_DISCONNECT_CONF: /* plci */
- if (cmsg->Info) {
- printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->Info, capi_info2str(cmsg->Info),
- cmsg->adr.adrPLCI);
- }
- if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
- goto notfound;
-
- card->bchans[plcip->chan].disconnecting = 1;
- break;
-
- case CAPI_ALERT_CONF: /* plci */
- if (cmsg->Info) {
- printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->Info, capi_info2str(cmsg->Info),
- cmsg->adr.adrPLCI);
- }
- break;
-
- case CAPI_CONNECT_IND: /* plci */
- handle_incoming_call(card, cmsg);
- break;
-
- case CAPI_CONNECT_CONF: /* plci */
- if (cmsg->Info) {
- printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->Info, capi_info2str(cmsg->Info),
- cmsg->adr.adrPLCI);
- }
- if (!(plcip = find_plci_by_msgid(card, cmsg->Messagenumber)))
- goto notfound;
-
- plcip->plci = cmsg->adr.adrPLCI;
- if (cmsg->Info) {
- plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_ERROR);
- } else {
- plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_OK);
- }
- break;
-
- case CAPI_CONNECT_ACTIVE_IND: /* plci */
-
- if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
- goto notfound;
-
- if (card->bchans[plcip->chan].incoming) {
- capi_cmsg_answer(cmsg);
- plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND);
- send_message(card, cmsg);
- } else {
- capidrv_ncci *nccip;
- capi_cmsg_answer(cmsg);
- send_message(card, cmsg);
-
- nccip = new_ncci(card, plcip, cmsg->adr.adrPLCI);
-
- if (!nccip) {
- printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n", card->contrnr);
- break; /* $$$$ */
- }
- capi_fill_CONNECT_B3_REQ(cmsg,
- global.ap.applid,
- card->msgid++,
- plcip->plci, /* adr */
- NULL /* NCPI */
- );
- nccip->msgid = cmsg->Messagenumber;
- plci_change_state(card, plcip,
- EV_PLCI_CONNECT_ACTIVE_IND);
- ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_REQ);
- send_message(card, cmsg);
- cmd.command = ISDN_STAT_DCONN;
- cmd.driver = card->myid;
- cmd.arg = plcip->chan;
- card->interface.statcallb(&cmd);
- }
- break;
-
- case CAPI_INFO_IND: /* Controller/plci */
-
- if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
- goto notfound;
-
- if (cmsg->InfoNumber == 0x4000) {
- if (cmsg->InfoElement[0] == 4) {
- cmd.command = ISDN_STAT_CINF;
- cmd.driver = card->myid;
- cmd.arg = plcip->chan;
- sprintf(cmd.parm.num, "%lu",
- (unsigned long)
- ((u32) cmsg->InfoElement[1]
- | ((u32) (cmsg->InfoElement[2]) << 8)
- | ((u32) (cmsg->InfoElement[3]) << 16)
- | ((u32) (cmsg->InfoElement[4]) << 24)));
- card->interface.statcallb(&cmd);
- break;
- }
- }
- cdb = capi_cmsg2str(cmsg);
- if (cdb) {
- printk(KERN_WARNING "capidrv-%d: %s\n",
- card->contrnr, cdb->buf);
- cdebbuf_free(cdb);
- } else
- printk(KERN_WARNING "capidrv-%d: CAPI_INFO_IND InfoNumber %x not handled\n",
- card->contrnr, cmsg->InfoNumber);
-
- break;
-
- case CAPI_CONNECT_ACTIVE_CONF: /* plci */
- goto ignored;
- case CAPI_SELECT_B_PROTOCOL_CONF: /* plci */
- goto ignored;
- case CAPI_FACILITY_IND: /* Controller/plci/ncci */
- goto ignored;
- case CAPI_FACILITY_CONF: /* Controller/plci/ncci */
- goto ignored;
-
- case CAPI_INFO_CONF: /* Controller/plci */
- goto ignored;
-
- default:
- printk(KERN_ERR "capidrv-%d: got %s for plci 0x%x ???",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrPLCI);
- }
- return;
-ignored:
- printk(KERN_INFO "capidrv-%d: %s for plci 0x%x ignored\n",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrPLCI);
- return;
-notfound:
- printk(KERN_ERR "capidrv-%d: %s: plci 0x%x not found\n",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrPLCI);
- return;
-}
-
-static void handle_ncci(_cmsg *cmsg)
-{
- capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
- capidrv_plci *plcip;
- capidrv_ncci *nccip;
- isdn_ctrl cmd;
- int len;
-
- if (!card) {
- printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrController & 0x7f);
- return;
- }
- switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
-
- case CAPI_CONNECT_B3_ACTIVE_IND: /* ncci */
- if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
- goto notfound;
-
- capi_cmsg_answer(cmsg);
- ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_ACTIVE_IND);
- send_message(card, cmsg);
-
- cmd.command = ISDN_STAT_BCONN;
- cmd.driver = card->myid;
- cmd.arg = nccip->chan;
- card->interface.statcallb(&cmd);
-
- printk(KERN_INFO "capidrv-%d: chan %d up with ncci 0x%x\n",
- card->contrnr, nccip->chan, nccip->ncci);
- break;
-
- case CAPI_CONNECT_B3_ACTIVE_CONF: /* ncci */
- goto ignored;
-
- case CAPI_CONNECT_B3_IND: /* ncci */
-
- plcip = find_plci_by_ncci(card, cmsg->adr.adrNCCI);
- if (plcip) {
- nccip = new_ncci(card, plcip, cmsg->adr.adrNCCI);
- if (nccip) {
- ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_IND);
- capi_fill_CONNECT_B3_RESP(cmsg,
- global.ap.applid,
- card->msgid++,
- nccip->ncci, /* adr */
- 0, /* Reject */
- NULL /* NCPI */
- );
- ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_RESP);
- send_message(card, cmsg);
- break;
- }
- printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n", card->contrnr);
- } else {
- printk(KERN_ERR "capidrv-%d: %s: plci for ncci 0x%x not found\n",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrNCCI);
- }
- capi_fill_CONNECT_B3_RESP(cmsg,
- global.ap.applid,
- card->msgid++,
- cmsg->adr.adrNCCI,
- 2, /* Reject */
- NULL /* NCPI */
- );
- send_message(card, cmsg);
- break;
-
- case CAPI_CONNECT_B3_CONF: /* ncci */
-
- if (!(nccip = find_ncci_by_msgid(card,
- cmsg->adr.adrNCCI,
- cmsg->Messagenumber)))
- goto notfound;
-
- nccip->ncci = cmsg->adr.adrNCCI;
- if (cmsg->Info) {
- printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for ncci 0x%x\n",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->Info, capi_info2str(cmsg->Info),
- cmsg->adr.adrNCCI);
- }
-
- if (cmsg->Info)
- ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_CONF_ERROR);
- else
- ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_CONF_OK);
- break;
-
- case CAPI_CONNECT_B3_T90_ACTIVE_IND: /* ncci */
- capi_cmsg_answer(cmsg);
- send_message(card, cmsg);
- break;
-
- case CAPI_DATA_B3_IND: /* ncci */
- /* handled in handle_data() */
- goto ignored;
-
- case CAPI_DATA_B3_CONF: /* ncci */
- if (cmsg->Info) {
- printk(KERN_WARNING "CAPI_DATA_B3_CONF: Info %x - %s\n",
- cmsg->Info, capi_info2str(cmsg->Info));
- }
- if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
- goto notfound;
-
- len = capidrv_del_ack(nccip, cmsg->DataHandle);
- if (len < 0)
- break;
- cmd.command = ISDN_STAT_BSENT;
- cmd.driver = card->myid;
- cmd.arg = nccip->chan;
- cmd.parm.length = len;
- card->interface.statcallb(&cmd);
- break;
-
- case CAPI_DISCONNECT_B3_IND: /* ncci */
- if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
- goto notfound;
-
- card->bchans[nccip->chan].disconnecting = 1;
- ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_IND);
- capi_cmsg_answer(cmsg);
- ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_RESP);
- send_message(card, cmsg);
- break;
-
- case CAPI_DISCONNECT_B3_CONF: /* ncci */
- if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
- goto notfound;
- if (cmsg->Info) {
- printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for ncci 0x%x\n",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->Info, capi_info2str(cmsg->Info),
- cmsg->adr.adrNCCI);
- ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_CONF_ERROR);
- }
- break;
-
- case CAPI_RESET_B3_IND: /* ncci */
- if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
- goto notfound;
- ncci_change_state(card, nccip, EV_NCCI_RESET_B3_IND);
- capi_cmsg_answer(cmsg);
- send_message(card, cmsg);
- break;
-
- case CAPI_RESET_B3_CONF: /* ncci */
- goto ignored; /* $$$$ */
-
- case CAPI_FACILITY_IND: /* Controller/plci/ncci */
- goto ignored;
- case CAPI_FACILITY_CONF: /* Controller/plci/ncci */
- goto ignored;
-
- default:
- printk(KERN_ERR "capidrv-%d: got %s for ncci 0x%x ???",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrNCCI);
- }
- return;
-ignored:
- printk(KERN_INFO "capidrv-%d: %s for ncci 0x%x ignored\n",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrNCCI);
- return;
-notfound:
- printk(KERN_ERR "capidrv-%d: %s: ncci 0x%x not found\n",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrNCCI);
-}
-
-
-static void handle_data(_cmsg *cmsg, struct sk_buff *skb)
-{
- capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
- capidrv_ncci *nccip;
-
- if (!card) {
- printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrController & 0x7f);
- kfree_skb(skb);
- return;
- }
- if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) {
- printk(KERN_ERR "capidrv-%d: %s: ncci 0x%x not found\n",
- card->contrnr,
- capi_cmd2str(cmsg->Command, cmsg->Subcommand),
- cmsg->adr.adrNCCI);
- kfree_skb(skb);
- return;
- }
- (void) skb_pull(skb, CAPIMSG_LEN(skb->data));
- card->interface.rcvcallb_skb(card->myid, nccip->chan, skb);
- capi_cmsg_answer(cmsg);
- send_message(card, cmsg);
-}
-
-static _cmsg s_cmsg;
-
-static void capidrv_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
-{
- if (capi_message2cmsg(&s_cmsg, skb->data)) {
- printk(KERN_ERR "capidrv: applid=%d: received invalid message\n",
- ap->applid);
- kfree_skb(skb);
- return;
- }
- if (debugmode > 3) {
- _cdebbuf *cdb = capi_cmsg2str(&s_cmsg);
-
- if (cdb) {
- printk(KERN_DEBUG "%s: applid=%d %s\n", __func__,
- ap->applid, cdb->buf);
- cdebbuf_free(cdb);
- } else
- printk(KERN_DEBUG "%s: applid=%d %s not traced\n",
- __func__, ap->applid,
- capi_cmd2str(s_cmsg.Command, s_cmsg.Subcommand));
- }
- if (s_cmsg.Command == CAPI_DATA_B3
- && s_cmsg.Subcommand == CAPI_IND) {
- handle_data(&s_cmsg, skb);
- return;
- }
- if ((s_cmsg.adr.adrController & 0xffffff00) == 0)
- handle_controller(&s_cmsg);
- else if ((s_cmsg.adr.adrPLCI & 0xffff0000) == 0)
- handle_plci(&s_cmsg);
- else
- handle_ncci(&s_cmsg);
- /*
- * data of skb used in s_cmsg,
- * free data when s_cmsg is not used again
- * thanks to Lars Heete <hel@admin.de>
- */
- kfree_skb(skb);
-}
-
-/* ------------------------------------------------------------------- */
-
-#define PUTBYTE_TO_STATUS(card, byte) \
- do { \
- *(card)->q931_write++ = (byte); \
- if ((card)->q931_write > (card)->q931_end) \
- (card)->q931_write = (card)->q931_buf; \
- } while (0)
-
-static void handle_dtrace_data(capidrv_contr *card,
- int send, int level2, u8 *data, u16 len)
-{
- u8 *p, *end;
- isdn_ctrl cmd;
-
- if (!len) {
- printk(KERN_DEBUG "capidrv-%d: avmb1_q931_data: len == %d\n",
- card->contrnr, len);
- return;
- }
-
- if (level2) {
- PUTBYTE_TO_STATUS(card, 'D');
- PUTBYTE_TO_STATUS(card, '2');
- PUTBYTE_TO_STATUS(card, send ? '>' : '<');
- PUTBYTE_TO_STATUS(card, ':');
- } else {
- PUTBYTE_TO_STATUS(card, 'D');
- PUTBYTE_TO_STATUS(card, '3');
- PUTBYTE_TO_STATUS(card, send ? '>' : '<');
- PUTBYTE_TO_STATUS(card, ':');
- }
-
- for (p = data, end = data + len; p < end; p++) {
- PUTBYTE_TO_STATUS(card, ' ');
- PUTBYTE_TO_STATUS(card, hex_asc_hi(*p));
- PUTBYTE_TO_STATUS(card, hex_asc_lo(*p));
- }
- PUTBYTE_TO_STATUS(card, '\n');
-
- cmd.command = ISDN_STAT_STAVAIL;
- cmd.driver = card->myid;
- cmd.arg = len * 3 + 5;
- card->interface.statcallb(&cmd);
-}
-
-/* ------------------------------------------------------------------- */
-
-static _cmsg cmdcmsg;
-
-static int capidrv_ioctl(isdn_ctrl *c, capidrv_contr *card)
-{
- switch (c->arg) {
- case 1:
- debugmode = (int)(*((unsigned int *)c->parm.num));
- printk(KERN_DEBUG "capidrv-%d: debugmode=%d\n",
- card->contrnr, debugmode);
- return 0;
- default:
- printk(KERN_DEBUG "capidrv-%d: capidrv_ioctl(%ld) called ??\n",
- card->contrnr, c->arg);
- return -EINVAL;
- }
- return -EINVAL;
-}
-
-/*
- * Handle leased lines (CAPI-Bundling)
- */
-
-struct internal_bchannelinfo {
- unsigned short channelalloc;
- unsigned short operation;
- unsigned char cmask[31];
-};
-
-static int decodeFVteln(char *teln, unsigned long *bmaskp, int *activep)
-{
- unsigned long bmask = 0;
- int active = !0;
- char *s;
- int i;
-
- if (strncmp(teln, "FV:", 3) != 0)
- return 1;
- s = teln + 3;
- while (*s && *s == ' ') s++;
- if (!*s) return -2;
- if (*s == 'p' || *s == 'P') {
- active = 0;
- s++;
- }
- if (*s == 'a' || *s == 'A') {
- active = !0;
- s++;
- }
- while (*s) {
- int digit1 = 0;
- int digit2 = 0;
- char *endp;
-
- digit1 = simple_strtoul(s, &endp, 10);
- if (s == endp)
- return -3;
- s = endp;
-
- if (digit1 <= 0 || digit1 > 30) return -4;
- if (*s == 0 || *s == ',' || *s == ' ') {
- bmask |= (1 << digit1);
- digit1 = 0;
- if (*s) s++;
- continue;
- }
- if (*s != '-') return -5;
- s++;
-
- digit2 = simple_strtoul(s, &endp, 10);
- if (s == endp)
- return -3;
- s = endp;
-
- if (digit2 <= 0 || digit2 > 30) return -4;
- if (*s == 0 || *s == ',' || *s == ' ') {
- if (digit1 > digit2)
- for (i = digit2; i <= digit1; i++)
- bmask |= (1 << i);
- else
- for (i = digit1; i <= digit2; i++)
- bmask |= (1 << i);
- digit1 = digit2 = 0;
- if (*s) s++;
- continue;
- }
- return -6;
- }
- if (activep) *activep = active;
- if (bmaskp) *bmaskp = bmask;
- return 0;
-}
-
-static int FVteln2capi20(char *teln, u8 AdditionalInfo[1 + 2 + 2 + 31])
-{
- unsigned long bmask;
- int active;
- int rc, i;
-
- rc = decodeFVteln(teln, &bmask, &active);
- if (rc) return rc;
- /* Length */
- AdditionalInfo[0] = 2 + 2 + 31;
- /* Channel: 3 => use channel allocation */
- AdditionalInfo[1] = 3; AdditionalInfo[2] = 0;
- /* Operation: 0 => DTE mode, 1 => DCE mode */
- if (active) {
- AdditionalInfo[3] = 0; AdditionalInfo[4] = 0;
- } else {
- AdditionalInfo[3] = 1; AdditionalInfo[4] = 0;
- }
- /* Channel mask array */
- AdditionalInfo[5] = 0; /* no D-Channel */
- for (i = 1; i <= 30; i++)
- AdditionalInfo[5 + i] = (bmask & (1 << i)) ? 0xff : 0;
- return 0;
-}
-
-static int capidrv_command(isdn_ctrl *c, capidrv_contr *card)
-{
- isdn_ctrl cmd;
- struct capidrv_bchan *bchan;
- struct capidrv_plci *plcip;
- u8 AdditionalInfo[1 + 2 + 2 + 31];
- int rc, isleasedline = 0;
-
- if (c->command == ISDN_CMD_IOCTL)
- return capidrv_ioctl(c, card);
-
- switch (c->command) {
- case ISDN_CMD_DIAL: {
- u8 calling[ISDN_MSNLEN + 3];
- u8 called[ISDN_MSNLEN + 2];
-
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_DIAL(ch=%ld,\"%s,%d,%d,%s\")\n",
- card->contrnr,
- c->arg,
- c->parm.setup.phone,
- c->parm.setup.si1,
- c->parm.setup.si2,
- c->parm.setup.eazmsn);
-
- bchan = &card->bchans[c->arg % card->nbchan];
-
- if (bchan->plcip) {
- printk(KERN_ERR "capidrv-%d: dail ch=%ld,\"%s,%d,%d,%s\" in use (plci=0x%x)\n",
- card->contrnr,
- c->arg,
- c->parm.setup.phone,
- c->parm.setup.si1,
- c->parm.setup.si2,
- c->parm.setup.eazmsn,
- bchan->plcip->plci);
- return 0;
- }
- bchan->si1 = c->parm.setup.si1;
- bchan->si2 = c->parm.setup.si2;
-
- strncpy(bchan->num, c->parm.setup.phone, sizeof(bchan->num));
- strncpy(bchan->mynum, c->parm.setup.eazmsn, sizeof(bchan->mynum));
- rc = FVteln2capi20(bchan->num, AdditionalInfo);
- isleasedline = (rc == 0);
- if (rc < 0)
- printk(KERN_ERR "capidrv-%d: WARNING: invalid leased linedefinition \"%s\"\n", card->contrnr, bchan->num);
-
- if (isleasedline) {
- calling[0] = 0;
- called[0] = 0;
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: connecting leased line\n", card->contrnr);
- } else {
- calling[0] = strlen(bchan->mynum) + 2;
- calling[1] = 0;
- calling[2] = 0x80;
- strncpy(calling + 3, bchan->mynum, ISDN_MSNLEN);
- called[0] = strlen(bchan->num) + 1;
- called[1] = 0x80;
- strncpy(called + 2, bchan->num, ISDN_MSNLEN);
- }
-
- capi_fill_CONNECT_REQ(&cmdcmsg,
- global.ap.applid,
- card->msgid++,
- card->contrnr, /* adr */
- si2cip(bchan->si1, bchan->si2), /* cipvalue */
- called, /* CalledPartyNumber */
- calling, /* CallingPartyNumber */
- NULL, /* CalledPartySubaddress */
- NULL, /* CallingPartySubaddress */
- b1prot(bchan->l2, bchan->l3), /* B1protocol */
- b2prot(bchan->l2, bchan->l3), /* B2protocol */
- b3prot(bchan->l2, bchan->l3), /* B3protocol */
- b1config(bchan->l2, bchan->l3), /* B1configuration */
- NULL, /* B2configuration */
- NULL, /* B3configuration */
- NULL, /* BC */
- NULL, /* LLC */
- NULL, /* HLC */
- /* BChannelinformation */
- isleasedline ? AdditionalInfo : NULL,
- NULL, /* Keypadfacility */
- NULL, /* Useruserdata */
- NULL /* Facilitydataarray */
- );
- if ((plcip = new_plci(card, (c->arg % card->nbchan))) == NULL) {
- cmd.command = ISDN_STAT_DHUP;
- cmd.driver = card->myid;
- cmd.arg = (c->arg % card->nbchan);
- card->interface.statcallb(&cmd);
- return -1;
- }
- plcip->msgid = cmdcmsg.Messagenumber;
- plcip->leasedline = isleasedline;
- plci_change_state(card, plcip, EV_PLCI_CONNECT_REQ);
- send_message(card, &cmdcmsg);
- return 0;
- }
-
- case ISDN_CMD_ACCEPTD:
-
- bchan = &card->bchans[c->arg % card->nbchan];
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTD(ch=%ld) l2=%d l3=%d\n",
- card->contrnr,
- c->arg, bchan->l2, bchan->l3);
-
- capi_fill_CONNECT_RESP(&cmdcmsg,
- global.ap.applid,
- card->msgid++,
- bchan->plcip->plci, /* adr */
- 0, /* Reject */
- b1prot(bchan->l2, bchan->l3), /* B1protocol */
- b2prot(bchan->l2, bchan->l3), /* B2protocol */
- b3prot(bchan->l2, bchan->l3), /* B3protocol */
- b1config(bchan->l2, bchan->l3), /* B1configuration */
- NULL, /* B2configuration */
- NULL, /* B3configuration */
- NULL, /* ConnectedNumber */
- NULL, /* ConnectedSubaddress */
- NULL, /* LLC */
- NULL, /* BChannelinformation */
- NULL, /* Keypadfacility */
- NULL, /* Useruserdata */
- NULL /* Facilitydataarray */
- );
- if (capi_cmsg2message(&cmdcmsg, cmdcmsg.buf)) {
- printk(KERN_ERR "capidrv-%d: capidrv_command: parser failure\n",
- card->contrnr);
- return -EINVAL;
- }
- plci_change_state(card, bchan->plcip, EV_PLCI_CONNECT_RESP);
- send_message(card, &cmdcmsg);
- return 0;
-
- case ISDN_CMD_ACCEPTB:
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTB(ch=%ld)\n",
- card->contrnr,
- c->arg);
- return -ENOSYS;
-
- case ISDN_CMD_HANGUP:
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_HANGUP(ch=%ld)\n",
- card->contrnr,
- c->arg);
- bchan = &card->bchans[c->arg % card->nbchan];
-
- if (bchan->disconnecting) {
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: chan %ld already disconnecting ...\n",
- card->contrnr,
- c->arg);
- return 0;
- }
- if (bchan->nccip) {
- bchan->disconnecting = 1;
- capi_fill_DISCONNECT_B3_REQ(&cmdcmsg,
- global.ap.applid,
- card->msgid++,
- bchan->nccip->ncci,
- NULL /* NCPI */
- );
- ncci_change_state(card, bchan->nccip, EV_NCCI_DISCONNECT_B3_REQ);
- send_message(card, &cmdcmsg);
- return 0;
- } else if (bchan->plcip) {
- if (bchan->plcip->state == ST_PLCI_INCOMING) {
- /*
- * just ignore, we a called from
- * isdn_status_callback(),
- * which will return 0 or 2, this is handled
- * by the CONNECT_IND handler
- */
- bchan->disconnecting = 1;
- return 0;
- } else if (bchan->plcip->plci) {
- bchan->disconnecting = 1;
- capi_fill_DISCONNECT_REQ(&cmdcmsg,
- global.ap.applid,
- card->msgid++,
- bchan->plcip->plci,
- NULL, /* BChannelinformation */
- NULL, /* Keypadfacility */
- NULL, /* Useruserdata */
- NULL /* Facilitydataarray */
- );
- plci_change_state(card, bchan->plcip, EV_PLCI_DISCONNECT_REQ);
- send_message(card, &cmdcmsg);
- return 0;
- } else {
- printk(KERN_ERR "capidrv-%d: chan %ld disconnect request while waiting for CONNECT_CONF\n",
- card->contrnr,
- c->arg);
- return -EINVAL;
- }
- }
- printk(KERN_ERR "capidrv-%d: chan %ld disconnect request on free channel\n",
- card->contrnr,
- c->arg);
- return -EINVAL;
-/* ready */
-
- case ISDN_CMD_SETL2:
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: set L2 on chan %ld to %ld\n",
- card->contrnr,
- (c->arg & 0xff), (c->arg >> 8));
- bchan = &card->bchans[(c->arg & 0xff) % card->nbchan];
- bchan->l2 = (c->arg >> 8);
- return 0;
-
- case ISDN_CMD_SETL3:
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: set L3 on chan %ld to %ld\n",
- card->contrnr,
- (c->arg & 0xff), (c->arg >> 8));
- bchan = &card->bchans[(c->arg & 0xff) % card->nbchan];
- bchan->l3 = (c->arg >> 8);
- return 0;
-
- case ISDN_CMD_SETEAZ:
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: set EAZ \"%s\" on chan %ld\n",
- card->contrnr,
- c->parm.num, c->arg);
- bchan = &card->bchans[c->arg % card->nbchan];
- strncpy(bchan->msn, c->parm.num, ISDN_MSNLEN);
- return 0;
-
- case ISDN_CMD_CLREAZ:
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: clearing EAZ on chan %ld\n",
- card->contrnr, c->arg);
- bchan = &card->bchans[c->arg % card->nbchan];
- bchan->msn[0] = 0;
- return 0;
-
- default:
- printk(KERN_ERR "capidrv-%d: ISDN_CMD_%d, Huh?\n",
- card->contrnr, c->command);
- return -EINVAL;
- }
- return 0;
-}
-
-static int if_command(isdn_ctrl *c)
-{
- capidrv_contr *card = findcontrbydriverid(c->driver);
-
- if (card)
- return capidrv_command(c, card);
-
- printk(KERN_ERR
- "capidrv: if_command %d called with invalid driverId %d!\n",
- c->command, c->driver);
- return -ENODEV;
-}
-
-static _cmsg sendcmsg;
-
-static int if_sendbuf(int id, int channel, int doack, struct sk_buff *skb)
-{
- capidrv_contr *card = findcontrbydriverid(id);
- capidrv_bchan *bchan;
- capidrv_ncci *nccip;
- int len = skb->len;
- int msglen;
- u16 errcode;
- u16 datahandle;
- u32 data;
-
- if (!card) {
- printk(KERN_ERR "capidrv: if_sendbuf called with invalid driverId %d!\n",
- id);
- return 0;
- }
- if (debugmode > 4)
- printk(KERN_DEBUG "capidrv-%d: sendbuf len=%d skb=%p doack=%d\n",
- card->contrnr, len, skb, doack);
- bchan = &card->bchans[channel % card->nbchan];
- nccip = bchan->nccip;
- if (!nccip || nccip->state != ST_NCCI_ACTIVE) {
- printk(KERN_ERR "capidrv-%d: if_sendbuf: %s:%d: chan not up!\n",
- card->contrnr, card->name, channel);
- return 0;
- }
- datahandle = nccip->datahandle;
-
- /*
- * Here we copy pointer skb->data into the 32-bit 'Data' field.
- * The 'Data' field is not used in practice in linux kernel
- * (neither in 32 or 64 bit), but should have some value,
- * since a CAPI message trace will display it.
- *
- * The correct value in the 32 bit case is the address of the
- * data, in 64 bit it makes no sense, we use 0 there.
- */
-
-#ifdef CONFIG_64BIT
- data = 0;
-#else
- data = (unsigned long) skb->data;
-#endif
-
- capi_fill_DATA_B3_REQ(&sendcmsg, global.ap.applid, card->msgid++,
- nccip->ncci, /* adr */
- data, /* Data */
- skb->len, /* DataLength */
- datahandle, /* DataHandle */
- 0 /* Flags */
- );
-
- if (capidrv_add_ack(nccip, datahandle, doack ? (int)skb->len : -1) < 0)
- return 0;
-
- if (capi_cmsg2message(&sendcmsg, sendcmsg.buf)) {
- printk(KERN_ERR "capidrv-%d: if_sendbuf: parser failure\n",
- card->contrnr);
- return -EINVAL;
- }
- msglen = CAPIMSG_LEN(sendcmsg.buf);
- if (skb_headroom(skb) < msglen) {
- struct sk_buff *nskb = skb_realloc_headroom(skb, msglen);
- if (!nskb) {
- printk(KERN_ERR "capidrv-%d: if_sendbuf: no memory\n",
- card->contrnr);
- (void)capidrv_del_ack(nccip, datahandle);
- return 0;
- }
- printk(KERN_DEBUG "capidrv-%d: only %d bytes headroom, need %d\n",
- card->contrnr, skb_headroom(skb), msglen);
- memcpy(skb_push(nskb, msglen), sendcmsg.buf, msglen);
- errcode = capi20_put_message(&global.ap, nskb);
- if (errcode == CAPI_NOERROR) {
- dev_kfree_skb(skb);
- nccip->datahandle++;
- return len;
- }
- if (debugmode > 3)
- printk(KERN_DEBUG "capidrv-%d: sendbuf putmsg ret(%x) - %s\n",
- card->contrnr, errcode, capi_info2str(errcode));
- (void)capidrv_del_ack(nccip, datahandle);
- dev_kfree_skb(nskb);
- return errcode == CAPI_SENDQUEUEFULL ? 0 : -1;
- } else {
- memcpy(skb_push(skb, msglen), sendcmsg.buf, msglen);
- errcode = capi20_put_message(&global.ap, skb);
- if (errcode == CAPI_NOERROR) {
- nccip->datahandle++;
- return len;
- }
- if (debugmode > 3)
- printk(KERN_DEBUG "capidrv-%d: sendbuf putmsg ret(%x) - %s\n",
- card->contrnr, errcode, capi_info2str(errcode));
- skb_pull(skb, msglen);
- (void)capidrv_del_ack(nccip, datahandle);
- return errcode == CAPI_SENDQUEUEFULL ? 0 : -1;
- }
-}
-
-static int if_readstat(u8 __user *buf, int len, int id, int channel)
-{
- capidrv_contr *card = findcontrbydriverid(id);
- int count;
- u8 __user *p;
-
- if (!card) {
- printk(KERN_ERR "capidrv: if_readstat called with invalid driverId %d!\n",
- id);
- return -ENODEV;
- }
-
- for (p = buf, count = 0; count < len; p++, count++) {
- if (put_user(*card->q931_read++, p))
- return -EFAULT;
- if (card->q931_read > card->q931_end)
- card->q931_read = card->q931_buf;
- }
- return count;
-
-}
-
-static void enable_dchannel_trace(capidrv_contr *card)
-{
- u8 manufacturer[CAPI_MANUFACTURER_LEN];
- capi_version version;
- u16 contr = card->contrnr;
- u16 errcode;
- u16 avmversion[3];
-
- errcode = capi20_get_manufacturer(contr, manufacturer);
- if (errcode != CAPI_NOERROR) {
- printk(KERN_ERR "%s: can't get manufacturer (0x%x)\n",
- card->name, errcode);
- return;
- }
- if (strstr(manufacturer, "AVM") == NULL) {
- printk(KERN_ERR "%s: not from AVM, no d-channel trace possible (%s)\n",
- card->name, manufacturer);
- return;
- }
- errcode = capi20_get_version(contr, &version);
- if (errcode != CAPI_NOERROR) {
- printk(KERN_ERR "%s: can't get version (0x%x)\n",
- card->name, errcode);
- return;
- }
- avmversion[0] = (version.majormanuversion >> 4) & 0x0f;
- avmversion[1] = (version.majormanuversion << 4) & 0xf0;
- avmversion[1] |= (version.minormanuversion >> 4) & 0x0f;
- avmversion[2] |= version.minormanuversion & 0x0f;
-
- if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 5)) {
- printk(KERN_INFO "%s: D2 trace enabled\n", card->name);
- capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.ap.applid,
- card->msgid++,
- contr,
- 0x214D5641, /* ManuID */
- 0, /* Class */
- 1, /* Function */
- (_cstruct)"\004\200\014\000\000");
- } else {
- printk(KERN_INFO "%s: D3 trace enabled\n", card->name);
- capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.ap.applid,
- card->msgid++,
- contr,
- 0x214D5641, /* ManuID */
- 0, /* Class */
- 1, /* Function */
- (_cstruct)"\004\002\003\000\000");
- }
- send_message(card, &cmdcmsg);
-}
-
-
-static void send_listen(capidrv_contr *card)
-{
- capi_fill_LISTEN_REQ(&cmdcmsg, global.ap.applid,
- card->msgid++,
- card->contrnr, /* controller */
- 1 << 6, /* Infomask */
- card->cipmask,
- card->cipmask2,
- NULL, NULL);
- listen_change_state(card, EV_LISTEN_REQ);
- send_message(card, &cmdcmsg);
-}
-
-static void listentimerfunc(struct timer_list *t)
-{
- capidrv_contr *card = from_timer(card, t, listentimer);
- if (card->state != ST_LISTEN_NONE && card->state != ST_LISTEN_ACTIVE)
- printk(KERN_ERR "%s: controller dead ??\n", card->name);
- send_listen(card);
- mod_timer(&card->listentimer, jiffies + 60 * HZ);
-}
-
-
-static int capidrv_addcontr(u16 contr, struct capi_profile *profp)
-{
- capidrv_contr *card;
- unsigned long flags;
- isdn_ctrl cmd;
- char id[20];
- int i;
-
- sprintf(id, "capidrv-%d", contr);
- if (!try_module_get(THIS_MODULE)) {
- printk(KERN_WARNING "capidrv: (%s) Could not reserve module\n", id);
- return -1;
- }
- if (!(card = kzalloc(sizeof(capidrv_contr), GFP_ATOMIC))) {
- printk(KERN_WARNING
- "capidrv: (%s) Could not allocate contr-struct.\n", id);
- return -1;
- }
- card->owner = THIS_MODULE;
- timer_setup(&card->listentimer, listentimerfunc, 0);
- strcpy(card->name, id);
- card->contrnr = contr;
- card->nbchan = profp->nbchannel;
- card->bchans = kmalloc_array(card->nbchan, sizeof(capidrv_bchan),
- GFP_ATOMIC);
- if (!card->bchans) {
- printk(KERN_WARNING
- "capidrv: (%s) Could not allocate bchan-structs.\n", id);
- module_put(card->owner);
- kfree(card);
- return -1;
- }
- card->interface.channels = profp->nbchannel;
- card->interface.maxbufsize = 2048;
- card->interface.command = if_command;
- card->interface.writebuf_skb = if_sendbuf;
- card->interface.writecmd = NULL;
- card->interface.readstat = if_readstat;
- card->interface.features =
- ISDN_FEATURE_L2_HDLC |
- ISDN_FEATURE_L2_TRANS |
- ISDN_FEATURE_L3_TRANS |
- ISDN_FEATURE_P_UNKNOWN |
- ISDN_FEATURE_L2_X75I |
- ISDN_FEATURE_L2_X75UI |
- ISDN_FEATURE_L2_X75BUI;
- if (profp->support1 & (1 << 2))
- card->interface.features |=
- ISDN_FEATURE_L2_V11096 |
- ISDN_FEATURE_L2_V11019 |
- ISDN_FEATURE_L2_V11038;
- if (profp->support1 & (1 << 8))
- card->interface.features |= ISDN_FEATURE_L2_MODEM;
- card->interface.hl_hdrlen = 22; /* len of DATA_B3_REQ */
- strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);
-
-
- card->q931_read = card->q931_buf;
- card->q931_write = card->q931_buf;
- card->q931_end = card->q931_buf + sizeof(card->q931_buf) - 1;
-
- if (!register_isdn(&card->interface)) {
- printk(KERN_ERR "capidrv: Unable to register contr %s\n", id);
- kfree(card->bchans);
- module_put(card->owner);
- kfree(card);
- return -1;
- }
- card->myid = card->interface.channels;
- memset(card->bchans, 0, sizeof(capidrv_bchan) * card->nbchan);
- for (i = 0; i < card->nbchan; i++) {
- card->bchans[i].contr = card;
- }
-
- spin_lock_irqsave(&global_lock, flags);
- card->next = global.contr_list;
- global.contr_list = card;
- global.ncontr++;
- spin_unlock_irqrestore(&global_lock, flags);
-
- cmd.command = ISDN_STAT_RUN;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
-
- card->cipmask = 0x1FFF03FF; /* any */
- card->cipmask2 = 0;
-
- send_listen(card);
- mod_timer(&card->listentimer, jiffies + 60 * HZ);
-
- printk(KERN_INFO "%s: now up (%d B channels)\n",
- card->name, card->nbchan);
-
- enable_dchannel_trace(card);
-
- return 0;
-}
-
-static int capidrv_delcontr(u16 contr)
-{
- capidrv_contr **pp, *card;
- unsigned long flags;
- isdn_ctrl cmd;
-
- spin_lock_irqsave(&global_lock, flags);
- for (card = global.contr_list; card; card = card->next) {
- if (card->contrnr == contr)
- break;
- }
- if (!card) {
- spin_unlock_irqrestore(&global_lock, flags);
- printk(KERN_ERR "capidrv: delcontr: no contr %u\n", contr);
- return -1;
- }
-
- /* FIXME: maybe a race condition the card should be removed
- * here from global list /kkeil
- */
- spin_unlock_irqrestore(&global_lock, flags);
-
- del_timer(&card->listentimer);
-
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: id=%d unloading\n",
- card->contrnr, card->myid);
-
- cmd.command = ISDN_STAT_STOP;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
-
- while (card->nbchan) {
-
- cmd.command = ISDN_STAT_DISCH;
- cmd.driver = card->myid;
- cmd.arg = card->nbchan - 1;
- cmd.parm.num[0] = 0;
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: id=%d disable chan=%ld\n",
- card->contrnr, card->myid, cmd.arg);
- card->interface.statcallb(&cmd);
-
- if (card->bchans[card->nbchan - 1].nccip)
- free_ncci(card, card->bchans[card->nbchan - 1].nccip);
- if (card->bchans[card->nbchan - 1].plcip)
- free_plci(card, card->bchans[card->nbchan - 1].plcip);
- if (card->plci_list)
- printk(KERN_ERR "capidrv: bug in free_plci()\n");
- card->nbchan--;
- }
- kfree(card->bchans);
- card->bchans = NULL;
-
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: id=%d isdn unload\n",
- card->contrnr, card->myid);
-
- cmd.command = ISDN_STAT_UNLOAD;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
-
- if (debugmode)
- printk(KERN_DEBUG "capidrv-%d: id=%d remove contr from list\n",
- card->contrnr, card->myid);
-
- spin_lock_irqsave(&global_lock, flags);
- for (pp = &global.contr_list; *pp; pp = &(*pp)->next) {
- if (*pp == card) {
- *pp = (*pp)->next;
- card->next = NULL;
- global.ncontr--;
- break;
- }
- }
- spin_unlock_irqrestore(&global_lock, flags);
-
- module_put(card->owner);
- printk(KERN_INFO "%s: now down.\n", card->name);
- kfree(card);
- return 0;
-}
-
-
-static int
-lower_callback(struct notifier_block *nb, unsigned long val, void *v)
-{
- capi_profile profile;
- u32 contr = (long)v;
-
- switch (val) {
- case CAPICTR_UP:
- printk(KERN_INFO "capidrv: controller %hu up\n", contr);
- if (capi20_get_profile(contr, &profile) == CAPI_NOERROR)
- (void) capidrv_addcontr(contr, &profile);
- break;
- case CAPICTR_DOWN:
- printk(KERN_INFO "capidrv: controller %hu down\n", contr);
- (void) capidrv_delcontr(contr);
- break;
- }
- return NOTIFY_OK;
-}
-
-/*
- * /proc/capi/capidrv:
- * nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
- */
-static int __maybe_unused capidrv_proc_show(struct seq_file *m, void *v)
-{
- seq_printf(m, "%lu %lu %lu %lu\n",
- global.ap.nrecvctlpkt,
- global.ap.nrecvdatapkt,
- global.ap.nsentctlpkt,
- global.ap.nsentdatapkt);
- return 0;
-}
-
-static void __init proc_init(void)
-{
- proc_create_single("capi/capidrv", 0, NULL, capidrv_proc_show);
-}
-
-static void __exit proc_exit(void)
-{
- remove_proc_entry("capi/capidrv", NULL);
-}
-
-static struct notifier_block capictr_nb = {
- .notifier_call = lower_callback,
-};
-
-static int __init capidrv_init(void)
-{
- capi_profile profile;
- u32 ncontr, contr;
- u16 errcode;
-
- global.ap.rparam.level3cnt = -2; /* number of bchannels twice */
- global.ap.rparam.datablkcnt = 16;
- global.ap.rparam.datablklen = 2048;
-
- global.ap.recv_message = capidrv_recv_message;
- errcode = capi20_register(&global.ap);
- if (errcode) {
- return -EIO;
- }
-
- register_capictr_notifier(&capictr_nb);
-
- errcode = capi20_get_profile(0, &profile);
- if (errcode != CAPI_NOERROR) {
- unregister_capictr_notifier(&capictr_nb);
- capi20_release(&global.ap);
- return -EIO;
- }
-
- ncontr = profile.ncontroller;
- for (contr = 1; contr <= ncontr; contr++) {
- errcode = capi20_get_profile(contr, &profile);
- if (errcode != CAPI_NOERROR)
- continue;
- (void) capidrv_addcontr(contr, &profile);
- }
- proc_init();
-
- return 0;
-}
-
-static void __exit capidrv_exit(void)
-{
- unregister_capictr_notifier(&capictr_nb);
- capi20_release(&global.ap);
-
- proc_exit();
-}
-
-module_init(capidrv_init);
-module_exit(capidrv_exit);
diff --git a/drivers/isdn/capi/capidrv.h b/drivers/isdn/capi/capidrv.h
deleted file mode 100644
index 4466b2e0176d..000000000000
--- a/drivers/isdn/capi/capidrv.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/* $Id: capidrv.h,v 1.2.8.2 2001/09/23 22:24:33 kai Exp $
- *
- * ISDN4Linux Driver, using capi20 interface (kernelcapi)
- *
- * Copyright 1997 by Carsten Paeth <calle@calle.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef __CAPIDRV_H__
-#define __CAPIDRV_H__
-
-/*
- * LISTEN state machine
- */
-#define ST_LISTEN_NONE 0 /* L-0 */
-#define ST_LISTEN_WAIT_CONF 1 /* L-0.1 */
-#define ST_LISTEN_ACTIVE 2 /* L-1 */
-#define ST_LISTEN_ACTIVE_WAIT_CONF 3 /* L-1.1 */
-
-
-#define EV_LISTEN_REQ 1 /* L-0 -> L-0.1
- L-1 -> L-1.1 */
-#define EV_LISTEN_CONF_ERROR 2 /* L-0.1 -> L-0
- L-1.1 -> L-1 */
-#define EV_LISTEN_CONF_EMPTY 3 /* L-0.1 -> L-0
- L-1.1 -> L-0 */
-#define EV_LISTEN_CONF_OK 4 /* L-0.1 -> L-1
- L-1.1 -> L.1 */
-
-/*
- * per plci state machine
- */
-#define ST_PLCI_NONE 0 /* P-0 */
-#define ST_PLCI_OUTGOING 1 /* P-0.1 */
-#define ST_PLCI_ALLOCATED 2 /* P-1 */
-#define ST_PLCI_ACTIVE 3 /* P-ACT */
-#define ST_PLCI_INCOMING 4 /* P-2 */
-#define ST_PLCI_FACILITY_IND 5 /* P-3 */
-#define ST_PLCI_ACCEPTING 6 /* P-4 */
-#define ST_PLCI_DISCONNECTING 7 /* P-5 */
-#define ST_PLCI_DISCONNECTED 8 /* P-6 */
-#define ST_PLCI_RESUMEING 9 /* P-0.Res */
-#define ST_PLCI_RESUME 10 /* P-Res */
-#define ST_PLCI_HELD 11 /* P-HELD */
-
-#define EV_PLCI_CONNECT_REQ 1 /* P-0 -> P-0.1
- */
-#define EV_PLCI_CONNECT_CONF_ERROR 2 /* P-0.1 -> P-0
- */
-#define EV_PLCI_CONNECT_CONF_OK 3 /* P-0.1 -> P-1
- */
-#define EV_PLCI_FACILITY_IND_UP 4 /* P-0 -> P-1
- */
-#define EV_PLCI_CONNECT_IND 5 /* P-0 -> P-2
- */
-#define EV_PLCI_CONNECT_ACTIVE_IND 6 /* P-1 -> P-ACT
- */
-#define EV_PLCI_CONNECT_REJECT 7 /* P-2 -> P-5
- P-3 -> P-5
- */
-#define EV_PLCI_DISCONNECT_REQ 8 /* P-1 -> P-5
- P-2 -> P-5
- P-3 -> P-5
- P-4 -> P-5
- P-ACT -> P-5
- P-Res -> P-5 (*)
- P-HELD -> P-5 (*)
- */
-#define EV_PLCI_DISCONNECT_IND 9 /* P-1 -> P-6
- P-2 -> P-6
- P-3 -> P-6
- P-4 -> P-6
- P-5 -> P-6
- P-ACT -> P-6
- P-Res -> P-6 (*)
- P-HELD -> P-6 (*)
- */
-#define EV_PLCI_FACILITY_IND_DOWN 10 /* P-0.1 -> P-5
- P-1 -> P-5
- P-ACT -> P-5
- P-2 -> P-5
- P-3 -> P-5
- P-4 -> P-5
- */
-#define EV_PLCI_DISCONNECT_RESP 11 /* P-6 -> P-0
- */
-#define EV_PLCI_CONNECT_RESP 12 /* P-6 -> P-0
- */
-
-#define EV_PLCI_RESUME_REQ 13 /* P-0 -> P-0.Res
- */
-#define EV_PLCI_RESUME_CONF_OK 14 /* P-0.Res -> P-Res
- */
-#define EV_PLCI_RESUME_CONF_ERROR 15 /* P-0.Res -> P-0
- */
-#define EV_PLCI_RESUME_IND 16 /* P-Res -> P-ACT
- */
-#define EV_PLCI_HOLD_IND 17 /* P-ACT -> P-HELD
- */
-#define EV_PLCI_RETRIEVE_IND 18 /* P-HELD -> P-ACT
- */
-#define EV_PLCI_SUSPEND_IND 19 /* P-ACT -> P-5
- */
-#define EV_PLCI_CD_IND 20 /* P-2 -> P-5
- */
-
-/*
- * per ncci state machine
- */
-#define ST_NCCI_PREVIOUS -1
-#define ST_NCCI_NONE 0 /* N-0 */
-#define ST_NCCI_OUTGOING 1 /* N-0.1 */
-#define ST_NCCI_INCOMING 2 /* N-1 */
-#define ST_NCCI_ALLOCATED 3 /* N-2 */
-#define ST_NCCI_ACTIVE 4 /* N-ACT */
-#define ST_NCCI_RESETING 5 /* N-3 */
-#define ST_NCCI_DISCONNECTING 6 /* N-4 */
-#define ST_NCCI_DISCONNECTED 7 /* N-5 */
-
-#define EV_NCCI_CONNECT_B3_REQ 1 /* N-0 -> N-0.1 */
-#define EV_NCCI_CONNECT_B3_IND 2 /* N-0 -> N.1 */
-#define EV_NCCI_CONNECT_B3_CONF_OK 3 /* N-0.1 -> N.2 */
-#define EV_NCCI_CONNECT_B3_CONF_ERROR 4 /* N-0.1 -> N.0 */
-#define EV_NCCI_CONNECT_B3_REJECT 5 /* N-1 -> N-4 */
-#define EV_NCCI_CONNECT_B3_RESP 6 /* N-1 -> N-2 */
-#define EV_NCCI_CONNECT_B3_ACTIVE_IND 7 /* N-2 -> N-ACT */
-#define EV_NCCI_RESET_B3_REQ 8 /* N-ACT -> N-3 */
-#define EV_NCCI_RESET_B3_IND 9 /* N-3 -> N-ACT */
-#define EV_NCCI_DISCONNECT_B3_IND 10 /* N-4 -> N.5 */
-#define EV_NCCI_DISCONNECT_B3_CONF_ERROR 11 /* N-4 -> previous */
-#define EV_NCCI_DISCONNECT_B3_REQ 12 /* N-1 -> N-4
- N-2 -> N-4
- N-3 -> N-4
- N-ACT -> N-4 */
-#define EV_NCCI_DISCONNECT_B3_RESP 13 /* N-5 -> N-0 */
-
-#endif /* __CAPIDRV_H__ */
diff --git a/drivers/isdn/divert/Makefile b/drivers/isdn/divert/Makefile
deleted file mode 100644
index 07684fe53537..000000000000
--- a/drivers/isdn/divert/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-# Makefile for the dss1_divert ISDN module
-
-# Each configuration option enables a list of files.
-
-obj-$(CONFIG_ISDN_DIVERSION) += dss1_divert.o
-
-# Multipart objects.
-
-dss1_divert-y := isdn_divert.o divert_procfs.o divert_init.o
diff --git a/drivers/isdn/divert/divert_init.c b/drivers/isdn/divert/divert_init.c
deleted file mode 100644
index 267dede13bfd..000000000000
--- a/drivers/isdn/divert/divert_init.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/* $Id divert_init.c,v 1.5.6.2 2001/01/24 22:18:17 kai Exp $
- *
- * Module init for DSS1 diversion services for i4l.
- *
- * Copyright 1999 by Werner Cornelius (werner@isdn4linux.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-
-#include "isdn_divert.h"
-
-MODULE_DESCRIPTION("ISDN4Linux: Call diversion support");
-MODULE_AUTHOR("Werner Cornelius");
-MODULE_LICENSE("GPL");
-
-/****************************************/
-/* structure containing interface to hl */
-/****************************************/
-isdn_divert_if divert_if = {
- DIVERT_IF_MAGIC, /* magic value */
- DIVERT_CMD_REG, /* register cmd */
- ll_callback, /* callback routine from ll */
- NULL, /* command still not specified */
- NULL, /* drv_to_name */
- NULL, /* name_to_drv */
-};
-
-/*************************/
-/* Module interface code */
-/* no cmd line parms */
-/*************************/
-static int __init divert_init(void)
-{
- int i;
-
- if (divert_dev_init()) {
- printk(KERN_WARNING "dss1_divert: cannot install device, not loaded\n");
- return (-EIO);
- }
- if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR) {
- divert_dev_deinit();
- printk(KERN_WARNING "dss1_divert: error %d registering module, not loaded\n", i);
- return (-EIO);
- }
- printk(KERN_INFO "dss1_divert module successfully installed\n");
- return (0);
-}
-
-/**********************/
-/* Module deinit code */
-/**********************/
-static void __exit divert_exit(void)
-{
- unsigned long flags;
- int i;
-
- spin_lock_irqsave(&divert_lock, flags);
- divert_if.cmd = DIVERT_CMD_REL; /* release */
- if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR) {
- printk(KERN_WARNING "dss1_divert: error %d releasing module\n", i);
- spin_unlock_irqrestore(&divert_lock, flags);
- return;
- }
- if (divert_dev_deinit()) {
- printk(KERN_WARNING "dss1_divert: device busy, remove cancelled\n");
- spin_unlock_irqrestore(&divert_lock, flags);
- return;
- }
- spin_unlock_irqrestore(&divert_lock, flags);
- deleterule(-1); /* delete all rules and free mem */
- deleteprocs();
- printk(KERN_INFO "dss1_divert module successfully removed \n");
-}
-
-module_init(divert_init);
-module_exit(divert_exit);
diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c
deleted file mode 100644
index 342585e04fd3..000000000000
--- a/drivers/isdn/divert/divert_procfs.c
+++ /dev/null
@@ -1,336 +0,0 @@
-/* $Id: divert_procfs.c,v 1.11.6.2 2001/09/23 22:24:36 kai Exp $
- *
- * Filesystem handling for the diversion supplementary services.
- *
- * Copyright 1998 by Werner Cornelius (werner@isdn4linux.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/module.h>
-#include <linux/poll.h>
-#include <linux/slab.h>
-#ifdef CONFIG_PROC_FS
-#include <linux/proc_fs.h>
-#else
-#include <linux/fs.h>
-#endif
-#include <linux/sched.h>
-#include <linux/isdnif.h>
-#include <net/net_namespace.h>
-#include <linux/mutex.h>
-#include "isdn_divert.h"
-
-
-/*********************************/
-/* Variables for interface queue */
-/*********************************/
-ulong if_used = 0; /* number of interface users */
-static DEFINE_MUTEX(isdn_divert_mutex);
-static struct divert_info *divert_info_head = NULL; /* head of queue */
-static struct divert_info *divert_info_tail = NULL; /* pointer to last entry */
-static DEFINE_SPINLOCK(divert_info_lock);/* lock for queue */
-static wait_queue_head_t rd_queue;
-
-/*********************************/
-/* put an info buffer into queue */
-/*********************************/
-void
-put_info_buffer(char *cp)
-{
- struct divert_info *ib;
- unsigned long flags;
-
- if (if_used <= 0)
- return;
- if (!cp)
- return;
- if (!*cp)
- return;
- if (!(ib = kmalloc(sizeof(struct divert_info) + strlen(cp), GFP_ATOMIC)))
- return; /* no memory */
- strcpy(ib->info_start, cp); /* set output string */
- ib->next = NULL;
- spin_lock_irqsave(&divert_info_lock, flags);
- ib->usage_cnt = if_used;
- if (!divert_info_head)
- divert_info_head = ib; /* new head */
- else
- divert_info_tail->next = ib; /* follows existing messages */
- divert_info_tail = ib; /* new tail */
-
- /* delete old entrys */
- while (divert_info_head->next) {
- if ((divert_info_head->usage_cnt <= 0) &&
- (divert_info_head->next->usage_cnt <= 0)) {
- ib = divert_info_head;
- divert_info_head = divert_info_head->next;
- kfree(ib);
- } else
- break;
- } /* divert_info_head->next */
- spin_unlock_irqrestore(&divert_info_lock, flags);
- wake_up_interruptible(&(rd_queue));
-} /* put_info_buffer */
-
-#ifdef CONFIG_PROC_FS
-
-/**********************************/
-/* deflection device read routine */
-/**********************************/
-static ssize_t
-isdn_divert_read(struct file *file, char __user *buf, size_t count, loff_t *off)
-{
- struct divert_info *inf;
- int len;
-
- if (!(inf = *((struct divert_info **) file->private_data))) {
- if (file->f_flags & O_NONBLOCK)
- return -EAGAIN;
- wait_event_interruptible(rd_queue, (inf =
- *((struct divert_info **) file->private_data)));
- }
- if (!inf)
- return (0);
-
- inf->usage_cnt--; /* new usage count */
- file->private_data = &inf->next; /* next structure */
- if ((len = strlen(inf->info_start)) <= count) {
- if (copy_to_user(buf, inf->info_start, len))
- return -EFAULT;
- *off += len;
- return (len);
- }
- return (0);
-} /* isdn_divert_read */
-
-/**********************************/
-/* deflection device write routine */
-/**********************************/
-static ssize_t
-isdn_divert_write(struct file *file, const char __user *buf, size_t count, loff_t *off)
-{
- return (-ENODEV);
-} /* isdn_divert_write */
-
-
-/***************************************/
-/* select routines for various kernels */
-/***************************************/
-static __poll_t
-isdn_divert_poll(struct file *file, poll_table *wait)
-{
- __poll_t mask = 0;
-
- poll_wait(file, &(rd_queue), wait);
- /* mask = EPOLLOUT | EPOLLWRNORM; */
- if (*((struct divert_info **) file->private_data)) {
- mask |= EPOLLIN | EPOLLRDNORM;
- }
- return mask;
-} /* isdn_divert_poll */
-
-/****************/
-/* Open routine */
-/****************/
-static int
-isdn_divert_open(struct inode *ino, struct file *filep)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&divert_info_lock, flags);
- if_used++;
- if (divert_info_head)
- filep->private_data = &(divert_info_tail->next);
- else
- filep->private_data = &divert_info_head;
- spin_unlock_irqrestore(&divert_info_lock, flags);
- /* start_divert(); */
- return nonseekable_open(ino, filep);
-} /* isdn_divert_open */
-
-/*******************/
-/* close routine */
-/*******************/
-static int
-isdn_divert_close(struct inode *ino, struct file *filep)
-{
- struct divert_info *inf;
- unsigned long flags;
-
- spin_lock_irqsave(&divert_info_lock, flags);
- if_used--;
- inf = *((struct divert_info **) filep->private_data);
- while (inf) {
- inf->usage_cnt--;
- inf = inf->next;
- }
- if (if_used <= 0)
- while (divert_info_head) {
- inf = divert_info_head;
- divert_info_head = divert_info_head->next;
- kfree(inf);
- }
- spin_unlock_irqrestore(&divert_info_lock, flags);
- return (0);
-} /* isdn_divert_close */
-
-/*********/
-/* IOCTL */
-/*********/
-static int isdn_divert_ioctl_unlocked(struct file *file, uint cmd, ulong arg)
-{
- divert_ioctl dioctl;
- int i;
- unsigned long flags;
- divert_rule *rulep;
- char *cp;
-
- if (copy_from_user(&dioctl, (void __user *) arg, sizeof(dioctl)))
- return -EFAULT;
-
- switch (cmd) {
- case IIOCGETVER:
- dioctl.drv_version = DIVERT_IIOC_VERSION; /* set version */
- break;
-
- case IIOCGETDRV:
- if ((dioctl.getid.drvid = divert_if.name_to_drv(dioctl.getid.drvnam)) < 0)
- return (-EINVAL);
- break;
-
- case IIOCGETNAM:
- cp = divert_if.drv_to_name(dioctl.getid.drvid);
- if (!cp)
- return (-EINVAL);
- if (!*cp)
- return (-EINVAL);
- strcpy(dioctl.getid.drvnam, cp);
- break;
-
- case IIOCGETRULE:
- if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx)))
- return (-EINVAL);
- dioctl.getsetrule.rule = *rulep; /* copy data */
- break;
-
- case IIOCMODRULE:
- if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx)))
- return (-EINVAL);
- spin_lock_irqsave(&divert_lock, flags);
- *rulep = dioctl.getsetrule.rule; /* copy data */
- spin_unlock_irqrestore(&divert_lock, flags);
- return (0); /* no copy required */
- break;
-
- case IIOCINSRULE:
- return (insertrule(dioctl.getsetrule.ruleidx, &dioctl.getsetrule.rule));
- break;
-
- case IIOCDELRULE:
- return (deleterule(dioctl.getsetrule.ruleidx));
- break;
-
- case IIOCDODFACT:
- return (deflect_extern_action(dioctl.fwd_ctrl.subcmd,
- dioctl.fwd_ctrl.callid,
- dioctl.fwd_ctrl.to_nr));
-
- case IIOCDOCFACT:
- case IIOCDOCFDIS:
- case IIOCDOCFINT:
- if (!divert_if.drv_to_name(dioctl.cf_ctrl.drvid))
- return (-EINVAL); /* invalid driver */
- if (strnlen(dioctl.cf_ctrl.msn, sizeof(dioctl.cf_ctrl.msn)) ==
- sizeof(dioctl.cf_ctrl.msn))
- return -EINVAL;
- if (strnlen(dioctl.cf_ctrl.fwd_nr, sizeof(dioctl.cf_ctrl.fwd_nr)) ==
- sizeof(dioctl.cf_ctrl.fwd_nr))
- return -EINVAL;
- if ((i = cf_command(dioctl.cf_ctrl.drvid,
- (cmd == IIOCDOCFACT) ? 1 : (cmd == IIOCDOCFDIS) ? 0 : 2,
- dioctl.cf_ctrl.cfproc,
- dioctl.cf_ctrl.msn,
- dioctl.cf_ctrl.service,
- dioctl.cf_ctrl.fwd_nr,
- &dioctl.cf_ctrl.procid)))
- return (i);
- break;
-
- default:
- return (-EINVAL);
- } /* switch cmd */
- return copy_to_user((void __user *)arg, &dioctl, sizeof(dioctl)) ? -EFAULT : 0;
-} /* isdn_divert_ioctl */
-
-static long isdn_divert_ioctl(struct file *file, uint cmd, ulong arg)
-{
- long ret;
-
- mutex_lock(&isdn_divert_mutex);
- ret = isdn_divert_ioctl_unlocked(file, cmd, arg);
- mutex_unlock(&isdn_divert_mutex);
-
- return ret;
-}
-
-static const struct file_operations isdn_fops =
-{
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = isdn_divert_read,
- .write = isdn_divert_write,
- .poll = isdn_divert_poll,
- .unlocked_ioctl = isdn_divert_ioctl,
- .open = isdn_divert_open,
- .release = isdn_divert_close,
-};
-
-/****************************/
-/* isdn subdir in /proc/net */
-/****************************/
-static struct proc_dir_entry *isdn_proc_entry = NULL;
-static struct proc_dir_entry *isdn_divert_entry = NULL;
-#endif /* CONFIG_PROC_FS */
-
-/***************************************************************************/
-/* divert_dev_init must be called before the proc filesystem may be used */
-/***************************************************************************/
-int
-divert_dev_init(void)
-{
-
- init_waitqueue_head(&rd_queue);
-
-#ifdef CONFIG_PROC_FS
- isdn_proc_entry = proc_mkdir("isdn", init_net.proc_net);
- if (!isdn_proc_entry)
- return (-1);
- isdn_divert_entry = proc_create("divert", S_IFREG | S_IRUGO,
- isdn_proc_entry, &isdn_fops);
- if (!isdn_divert_entry) {
- remove_proc_entry("isdn", init_net.proc_net);
- return (-1);
- }
-#endif /* CONFIG_PROC_FS */
-
- return (0);
-} /* divert_dev_init */
-
-/***************************************************************************/
-/* divert_dev_deinit must be called before leaving isdn when included as */
-/* a module. */
-/***************************************************************************/
-int
-divert_dev_deinit(void)
-{
-
-#ifdef CONFIG_PROC_FS
- remove_proc_entry("divert", isdn_proc_entry);
- remove_proc_entry("isdn", init_net.proc_net);
-#endif /* CONFIG_PROC_FS */
-
- return (0);
-} /* divert_dev_deinit */
diff --git a/drivers/isdn/divert/isdn_divert.c b/drivers/isdn/divert/isdn_divert.c
deleted file mode 100644
index 5620fd2c6009..000000000000
--- a/drivers/isdn/divert/isdn_divert.c
+++ /dev/null
@@ -1,846 +0,0 @@
-/* $Id: isdn_divert.c,v 1.6.6.3 2001/09/23 22:24:36 kai Exp $
- *
- * DSS1 main diversion supplementary handling for i4l.
- *
- * Copyright 1999 by Werner Cornelius (werner@isdn4linux.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/proc_fs.h>
-#include <linux/slab.h>
-#include <linux/timer.h>
-#include <linux/jiffies.h>
-
-#include "isdn_divert.h"
-
-/**********************************/
-/* structure keeping calling info */
-/**********************************/
-struct call_struc {
- isdn_ctrl ics; /* delivered setup + driver parameters */
- ulong divert_id; /* Id delivered to user */
- unsigned char akt_state; /* actual state */
- char deflect_dest[35]; /* deflection destination */
- struct timer_list timer; /* timer control structure */
- char info[90]; /* device info output */
- struct call_struc *next; /* pointer to next entry */
- struct call_struc *prev;
-};
-
-
-/********************************************/
-/* structure keeping deflection table entry */
-/********************************************/
-struct deflect_struc {
- struct deflect_struc *next, *prev;
- divert_rule rule; /* used rule */
-};
-
-
-/*****************************************/
-/* variables for main diversion services */
-/*****************************************/
-/* diversion/deflection processes */
-static struct call_struc *divert_head = NULL; /* head of remembered entrys */
-static ulong next_id = 1; /* next info id */
-static struct deflect_struc *table_head = NULL;
-static struct deflect_struc *table_tail = NULL;
-static unsigned char extern_wait_max = 4; /* maximum wait in s for external process */
-
-DEFINE_SPINLOCK(divert_lock);
-
-/***************************/
-/* timer callback function */
-/***************************/
-static void deflect_timer_expire(struct timer_list *t)
-{
- unsigned long flags;
- struct call_struc *cs = from_timer(cs, t, timer);
-
- spin_lock_irqsave(&divert_lock, flags);
- del_timer(&cs->timer); /* delete active timer */
- spin_unlock_irqrestore(&divert_lock, flags);
-
- switch (cs->akt_state) {
- case DEFLECT_PROCEED:
- cs->ics.command = ISDN_CMD_HANGUP; /* cancel action */
- divert_if.ll_cmd(&cs->ics);
- spin_lock_irqsave(&divert_lock, flags);
- cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
- cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
- add_timer(&cs->timer);
- spin_unlock_irqrestore(&divert_lock, flags);
- break;
-
- case DEFLECT_ALERT:
- cs->ics.command = ISDN_CMD_REDIR; /* protocol */
- strlcpy(cs->ics.parm.setup.phone, cs->deflect_dest, sizeof(cs->ics.parm.setup.phone));
- strcpy(cs->ics.parm.setup.eazmsn, "Testtext delayed");
- divert_if.ll_cmd(&cs->ics);
- spin_lock_irqsave(&divert_lock, flags);
- cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
- cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
- add_timer(&cs->timer);
- spin_unlock_irqrestore(&divert_lock, flags);
- break;
-
- case DEFLECT_AUTODEL:
- default:
- spin_lock_irqsave(&divert_lock, flags);
- if (cs->prev)
- cs->prev->next = cs->next; /* forward link */
- else
- divert_head = cs->next;
- if (cs->next)
- cs->next->prev = cs->prev; /* back link */
- spin_unlock_irqrestore(&divert_lock, flags);
- kfree(cs);
- return;
-
- } /* switch */
-} /* deflect_timer_func */
-
-
-/*****************************************/
-/* handle call forwarding de/activations */
-/* 0 = deact, 1 = act, 2 = interrogate */
-/*****************************************/
-int cf_command(int drvid, int mode,
- u_char proc, char *msn,
- u_char service, char *fwd_nr, ulong *procid)
-{
- unsigned long flags;
- int retval, msnlen;
- int fwd_len;
- char *p, *ielenp, tmp[60];
- struct call_struc *cs;
-
- if (strchr(msn, '.')) return (-EINVAL); /* subaddress not allowed in msn */
- if ((proc & 0x7F) > 2) return (-EINVAL);
- proc &= 3;
- p = tmp;
- *p++ = 0x30; /* enumeration */
- ielenp = p++; /* remember total length position */
- *p++ = 0xa; /* proc tag */
- *p++ = 1; /* length */
- *p++ = proc & 0x7F; /* procedure to de/activate/interrogate */
- *p++ = 0xa; /* service tag */
- *p++ = 1; /* length */
- *p++ = service; /* service to handle */
-
- if (mode == 1) {
- if (!*fwd_nr) return (-EINVAL); /* destination missing */
- if (strchr(fwd_nr, '.')) return (-EINVAL); /* subaddress not allowed */
- fwd_len = strlen(fwd_nr);
- *p++ = 0x30; /* number enumeration */
- *p++ = fwd_len + 2; /* complete forward to len */
- *p++ = 0x80; /* fwd to nr */
- *p++ = fwd_len; /* length of number */
- strcpy(p, fwd_nr); /* copy number */
- p += fwd_len; /* pointer beyond fwd */
- } /* activate */
-
- msnlen = strlen(msn);
- *p++ = 0x80; /* msn number */
- if (msnlen > 1) {
- *p++ = msnlen; /* length */
- strcpy(p, msn);
- p += msnlen;
- } else
- *p++ = 0;
-
- *ielenp = p - ielenp - 1; /* set total IE length */
-
- /* allocate mem for information struct */
- if (!(cs = kmalloc(sizeof(struct call_struc), GFP_ATOMIC)))
- return (-ENOMEM); /* no memory */
- timer_setup(&cs->timer, deflect_timer_expire, 0);
- cs->info[0] = '\0';
- cs->ics.driver = drvid;
- cs->ics.command = ISDN_CMD_PROT_IO; /* protocol specific io */
- cs->ics.arg = DSS1_CMD_INVOKE; /* invoke supplementary service */
- cs->ics.parm.dss1_io.proc = (mode == 1) ? 7 : (mode == 2) ? 11 : 8; /* operation */
- cs->ics.parm.dss1_io.timeout = 4000; /* from ETS 300 207-1 */
- cs->ics.parm.dss1_io.datalen = p - tmp; /* total len */
- cs->ics.parm.dss1_io.data = tmp; /* start of buffer */
-
- spin_lock_irqsave(&divert_lock, flags);
- cs->ics.parm.dss1_io.ll_id = next_id++; /* id for callback */
- spin_unlock_irqrestore(&divert_lock, flags);
- *procid = cs->ics.parm.dss1_io.ll_id;
-
- sprintf(cs->info, "%d 0x%lx %s%s 0 %s %02x %d%s%s\n",
- (!mode) ? DIVERT_DEACTIVATE : (mode == 1) ? DIVERT_ACTIVATE : DIVERT_REPORT,
- cs->ics.parm.dss1_io.ll_id,
- (mode != 2) ? "" : "0 ",
- divert_if.drv_to_name(cs->ics.driver),
- msn,
- service & 0xFF,
- proc,
- (mode != 1) ? "" : " 0 ",
- (mode != 1) ? "" : fwd_nr);
-
- retval = divert_if.ll_cmd(&cs->ics); /* execute command */
-
- if (!retval) {
- cs->prev = NULL;
- spin_lock_irqsave(&divert_lock, flags);
- cs->next = divert_head;
- divert_head = cs;
- spin_unlock_irqrestore(&divert_lock, flags);
- } else
- kfree(cs);
- return (retval);
-} /* cf_command */
-
-
-/****************************************/
-/* handle a external deflection command */
-/****************************************/
-int deflect_extern_action(u_char cmd, ulong callid, char *to_nr)
-{
- struct call_struc *cs;
- isdn_ctrl ic;
- unsigned long flags;
- int i;
-
- if ((cmd & 0x7F) > 2) return (-EINVAL); /* invalid command */
- cs = divert_head; /* start of parameter list */
- while (cs) {
- if (cs->divert_id == callid) break; /* found */
- cs = cs->next;
- } /* search entry */
- if (!cs) return (-EINVAL); /* invalid callid */
-
- ic.driver = cs->ics.driver;
- ic.arg = cs->ics.arg;
- i = -EINVAL;
- if (cs->akt_state == DEFLECT_AUTODEL) return (i); /* no valid call */
- switch (cmd & 0x7F) {
- case 0: /* hangup */
- del_timer(&cs->timer);
- ic.command = ISDN_CMD_HANGUP;
- i = divert_if.ll_cmd(&ic);
- spin_lock_irqsave(&divert_lock, flags);
- cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
- cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
- add_timer(&cs->timer);
- spin_unlock_irqrestore(&divert_lock, flags);
- break;
-
- case 1: /* alert */
- if (cs->akt_state == DEFLECT_ALERT) return (0);
- cmd &= 0x7F; /* never wait */
- del_timer(&cs->timer);
- ic.command = ISDN_CMD_ALERT;
- if ((i = divert_if.ll_cmd(&ic))) {
- spin_lock_irqsave(&divert_lock, flags);
- cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
- cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
- add_timer(&cs->timer);
- spin_unlock_irqrestore(&divert_lock, flags);
- } else
- cs->akt_state = DEFLECT_ALERT;
- break;
-
- case 2: /* redir */
- del_timer(&cs->timer);
- strlcpy(cs->ics.parm.setup.phone, to_nr, sizeof(cs->ics.parm.setup.phone));
- strcpy(cs->ics.parm.setup.eazmsn, "Testtext manual");
- ic.command = ISDN_CMD_REDIR;
- if ((i = divert_if.ll_cmd(&ic))) {
- spin_lock_irqsave(&divert_lock, flags);
- cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
- cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
- add_timer(&cs->timer);
- spin_unlock_irqrestore(&divert_lock, flags);
- } else
- cs->akt_state = DEFLECT_ALERT;
- break;
-
- } /* switch */
- return (i);
-} /* deflect_extern_action */
-
-/********************************/
-/* insert a new rule before idx */
-/********************************/
-int insertrule(int idx, divert_rule *newrule)
-{
- struct deflect_struc *ds, *ds1 = NULL;
- unsigned long flags;
-
- if (!(ds = kmalloc(sizeof(struct deflect_struc), GFP_KERNEL)))
- return (-ENOMEM); /* no memory */
-
- ds->rule = *newrule; /* set rule */
-
- spin_lock_irqsave(&divert_lock, flags);
-
- if (idx >= 0) {
- ds1 = table_head;
- while ((ds1) && (idx > 0))
- { idx--;
- ds1 = ds1->next;
- }
- if (!ds1) idx = -1;
- }
-
- if (idx < 0) {
- ds->prev = table_tail; /* previous entry */
- ds->next = NULL; /* end of chain */
- if (ds->prev)
- ds->prev->next = ds; /* last forward */
- else
- table_head = ds; /* is first entry */
- table_tail = ds; /* end of queue */
- } else {
- ds->next = ds1; /* next entry */
- ds->prev = ds1->prev; /* prev entry */
- ds1->prev = ds; /* backward chain old element */
- if (!ds->prev)
- table_head = ds; /* first element */
- }
-
- spin_unlock_irqrestore(&divert_lock, flags);
- return (0);
-} /* insertrule */
-
-/***********************************/
-/* delete the rule at position idx */
-/***********************************/
-int deleterule(int idx)
-{
- struct deflect_struc *ds, *ds1;
- unsigned long flags;
-
- if (idx < 0) {
- spin_lock_irqsave(&divert_lock, flags);
- ds = table_head;
- table_head = NULL;
- table_tail = NULL;
- spin_unlock_irqrestore(&divert_lock, flags);
- while (ds) {
- ds1 = ds;
- ds = ds->next;
- kfree(ds1);
- }
- return (0);
- }
-
- spin_lock_irqsave(&divert_lock, flags);
- ds = table_head;
-
- while ((ds) && (idx > 0)) {
- idx--;
- ds = ds->next;
- }
-
- if (!ds) {
- spin_unlock_irqrestore(&divert_lock, flags);
- return (-EINVAL);
- }
-
- if (ds->next)
- ds->next->prev = ds->prev; /* backward chain */
- else
- table_tail = ds->prev; /* end of chain */
-
- if (ds->prev)
- ds->prev->next = ds->next; /* forward chain */
- else
- table_head = ds->next; /* start of chain */
-
- spin_unlock_irqrestore(&divert_lock, flags);
- kfree(ds);
- return (0);
-} /* deleterule */
-
-/*******************************************/
-/* get a pointer to a specific rule number */
-/*******************************************/
-divert_rule *getruleptr(int idx)
-{
- struct deflect_struc *ds = table_head;
-
- if (idx < 0) return (NULL);
- while ((ds) && (idx >= 0)) {
- if (!(idx--)) {
- return (&ds->rule);
- break;
- }
- ds = ds->next;
- }
- return (NULL);
-} /* getruleptr */
-
-/*************************************************/
-/* called from common module on an incoming call */
-/*************************************************/
-static int isdn_divert_icall(isdn_ctrl *ic)
-{
- int retval = 0;
- unsigned long flags;
- struct call_struc *cs = NULL;
- struct deflect_struc *dv;
- char *p, *p1;
- u_char accept;
-
- /* first check the internal deflection table */
- for (dv = table_head; dv; dv = dv->next) {
- /* scan table */
- if (((dv->rule.callopt == 1) && (ic->command == ISDN_STAT_ICALLW)) ||
- ((dv->rule.callopt == 2) && (ic->command == ISDN_STAT_ICALL)))
- continue; /* call option check */
- if (!(dv->rule.drvid & (1L << ic->driver)))
- continue; /* driver not matching */
- if ((dv->rule.si1) && (dv->rule.si1 != ic->parm.setup.si1))
- continue; /* si1 not matching */
- if ((dv->rule.si2) && (dv->rule.si2 != ic->parm.setup.si2))
- continue; /* si2 not matching */
-
- p = dv->rule.my_msn;
- p1 = ic->parm.setup.eazmsn;
- accept = 0;
- while (*p) {
- /* complete compare */
- if (*p == '-') {
- accept = 1; /* call accepted */
- break;
- }
- if (*p++ != *p1++)
- break; /* not accepted */
- if ((!*p) && (!*p1))
- accept = 1;
- } /* complete compare */
- if (!accept) continue; /* not accepted */
-
- if ((strcmp(dv->rule.caller, "0")) ||
- (ic->parm.setup.phone[0])) {
- p = dv->rule.caller;
- p1 = ic->parm.setup.phone;
- accept = 0;
- while (*p) {
- /* complete compare */
- if (*p == '-') {
- accept = 1; /* call accepted */
- break;
- }
- if (*p++ != *p1++)
- break; /* not accepted */
- if ((!*p) && (!*p1))
- accept = 1;
- } /* complete compare */
- if (!accept) continue; /* not accepted */
- }
-
- switch (dv->rule.action) {
- case DEFLECT_IGNORE:
- return 0;
-
- case DEFLECT_ALERT:
- case DEFLECT_PROCEED:
- case DEFLECT_REPORT:
- case DEFLECT_REJECT:
- if (dv->rule.action == DEFLECT_PROCEED)
- if ((!if_used) || ((!extern_wait_max) && (!dv->rule.waittime)))
- return (0); /* no external deflection needed */
- if (!(cs = kmalloc(sizeof(struct call_struc), GFP_ATOMIC)))
- return (0); /* no memory */
- timer_setup(&cs->timer, deflect_timer_expire, 0);
- cs->info[0] = '\0';
-
- cs->ics = *ic; /* copy incoming data */
- if (!cs->ics.parm.setup.phone[0]) strcpy(cs->ics.parm.setup.phone, "0");
- if (!cs->ics.parm.setup.eazmsn[0]) strcpy(cs->ics.parm.setup.eazmsn, "0");
- cs->ics.parm.setup.screen = dv->rule.screen;
- if (dv->rule.waittime)
- cs->timer.expires = jiffies + (HZ * dv->rule.waittime);
- else if (dv->rule.action == DEFLECT_PROCEED)
- cs->timer.expires = jiffies + (HZ * extern_wait_max);
- else
- cs->timer.expires = 0;
- cs->akt_state = dv->rule.action;
- spin_lock_irqsave(&divert_lock, flags);
- cs->divert_id = next_id++; /* new sequence number */
- spin_unlock_irqrestore(&divert_lock, flags);
- cs->prev = NULL;
- if (cs->akt_state == DEFLECT_ALERT) {
- strcpy(cs->deflect_dest, dv->rule.to_nr);
- if (!cs->timer.expires) {
- strcpy(ic->parm.setup.eazmsn,
- "Testtext direct");
- ic->parm.setup.screen = dv->rule.screen;
- strlcpy(ic->parm.setup.phone, dv->rule.to_nr, sizeof(ic->parm.setup.phone));
- cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
- cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
- retval = 5;
- } else
- retval = 1; /* alerting */
- } else {
- cs->deflect_dest[0] = '\0';
- retval = 4; /* only proceed */
- }
- snprintf(cs->info, sizeof(cs->info),
- "%d 0x%lx %s %s %s %s 0x%x 0x%x %d %d %s\n",
- cs->akt_state,
- cs->divert_id,
- divert_if.drv_to_name(cs->ics.driver),
- (ic->command == ISDN_STAT_ICALLW) ? "1" : "0",
- cs->ics.parm.setup.phone,
- cs->ics.parm.setup.eazmsn,
- cs->ics.parm.setup.si1,
- cs->ics.parm.setup.si2,
- cs->ics.parm.setup.screen,
- dv->rule.waittime,
- cs->deflect_dest);
- if ((dv->rule.action == DEFLECT_REPORT) ||
- (dv->rule.action == DEFLECT_REJECT)) {
- put_info_buffer(cs->info);
- kfree(cs); /* remove */
- return ((dv->rule.action == DEFLECT_REPORT) ? 0 : 2); /* nothing to do */
- }
- break;
-
- default:
- return 0; /* ignore call */
- } /* switch action */
- break; /* will break the 'for' looping */
- } /* scan_table */
-
- if (cs) {
- cs->prev = NULL;
- spin_lock_irqsave(&divert_lock, flags);
- cs->next = divert_head;
- divert_head = cs;
- if (cs->timer.expires) add_timer(&cs->timer);
- spin_unlock_irqrestore(&divert_lock, flags);
-
- put_info_buffer(cs->info);
- return (retval);
- } else
- return (0);
-} /* isdn_divert_icall */
-
-
-void deleteprocs(void)
-{
- struct call_struc *cs, *cs1;
- unsigned long flags;
-
- spin_lock_irqsave(&divert_lock, flags);
- cs = divert_head;
- divert_head = NULL;
- while (cs) {
- del_timer(&cs->timer);
- cs1 = cs;
- cs = cs->next;
- kfree(cs1);
- }
- spin_unlock_irqrestore(&divert_lock, flags);
-} /* deleteprocs */
-
-/****************************************************/
-/* put a address including address type into buffer */
-/****************************************************/
-static int put_address(char *st, u_char *p, int len)
-{
- u_char retval = 0;
- u_char adr_typ = 0; /* network standard */
-
- if (len < 2) return (retval);
- if (*p == 0xA1) {
- retval = *(++p) + 2; /* total length */
- if (retval > len) return (0); /* too short */
- len = retval - 2; /* remaining length */
- if (len < 3) return (0);
- if ((*(++p) != 0x0A) || (*(++p) != 1)) return (0);
- adr_typ = *(++p);
- len -= 3;
- p++;
- if (len < 2) return (0);
- if (*p++ != 0x12) return (0);
- if (*p > len) return (0); /* check number length */
- len = *p++;
- } else if (*p == 0x80) {
- retval = *(++p) + 2; /* total length */
- if (retval > len) return (0);
- len = retval - 2;
- p++;
- } else
- return (0); /* invalid address information */
-
- sprintf(st, "%d ", adr_typ);
- st += strlen(st);
- if (!len)
- *st++ = '-';
- else
- while (len--)
- *st++ = *p++;
- *st = '\0';
- return (retval);
-} /* put_address */
-
-/*************************************/
-/* report a successful interrogation */
-/*************************************/
-static int interrogate_success(isdn_ctrl *ic, struct call_struc *cs)
-{
- char *src = ic->parm.dss1_io.data;
- int restlen = ic->parm.dss1_io.datalen;
- int cnt = 1;
- u_char n, n1;
- char st[90], *p, *stp;
-
- if (restlen < 2) return (-100); /* frame too short */
- if (*src++ != 0x30) return (-101);
- if ((n = *src++) > 0x81) return (-102); /* invalid length field */
- restlen -= 2; /* remaining bytes */
- if (n == 0x80) {
- if (restlen < 2) return (-103);
- if ((*(src + restlen - 1)) || (*(src + restlen - 2))) return (-104);
- restlen -= 2;
- } else if (n == 0x81) {
- n = *src++;
- restlen--;
- if (n > restlen) return (-105);
- restlen = n;
- } else if (n > restlen)
- return (-106);
- else
- restlen = n; /* standard format */
- if (restlen < 3) return (-107); /* no procedure */
- if ((*src++ != 2) || (*src++ != 1) || (*src++ != 0x0B)) return (-108);
- restlen -= 3;
- if (restlen < 2) return (-109); /* list missing */
- if (*src == 0x31) {
- src++;
- if ((n = *src++) > 0x81) return (-110); /* invalid length field */
- restlen -= 2; /* remaining bytes */
- if (n == 0x80) {
- if (restlen < 2) return (-111);
- if ((*(src + restlen - 1)) || (*(src + restlen - 2))) return (-112);
- restlen -= 2;
- } else if (n == 0x81) {
- n = *src++;
- restlen--;
- if (n > restlen) return (-113);
- restlen = n;
- } else if (n > restlen)
- return (-114);
- else
- restlen = n; /* standard format */
- } /* result list header */
-
- while (restlen >= 2) {
- stp = st;
- sprintf(stp, "%d 0x%lx %d %s ", DIVERT_REPORT, ic->parm.dss1_io.ll_id,
- cnt++, divert_if.drv_to_name(ic->driver));
- stp += strlen(stp);
- if (*src++ != 0x30) return (-115); /* invalid enum */
- n = *src++;
- restlen -= 2;
- if (n > restlen) return (-116); /* enum length wrong */
- restlen -= n;
- p = src; /* one entry */
- src += n;
- if (!(n1 = put_address(stp, p, n & 0xFF))) continue;
- stp += strlen(stp);
- p += n1;
- n -= n1;
- if (n < 6) continue; /* no service and proc */
- if ((*p++ != 0x0A) || (*p++ != 1)) continue;
- sprintf(stp, " 0x%02x ", (*p++) & 0xFF);
- stp += strlen(stp);
- if ((*p++ != 0x0A) || (*p++ != 1)) continue;
- sprintf(stp, "%d ", (*p++) & 0xFF);
- stp += strlen(stp);
- n -= 6;
- if (n > 2) {
- if (*p++ != 0x30) continue;
- if (*p > (n - 2)) continue;
- n = *p++;
- if (!(n1 = put_address(stp, p, n & 0xFF))) continue;
- stp += strlen(stp);
- }
- sprintf(stp, "\n");
- put_info_buffer(st);
- } /* while restlen */
- if (restlen) return (-117);
- return (0);
-} /* interrogate_success */
-
-/*********************************************/
-/* callback for protocol specific extensions */
-/*********************************************/
-static int prot_stat_callback(isdn_ctrl *ic)
-{
- struct call_struc *cs, *cs1;
- int i;
- unsigned long flags;
-
- cs = divert_head; /* start of list */
- cs1 = NULL;
- while (cs) {
- if (ic->driver == cs->ics.driver) {
- switch (cs->ics.arg) {
- case DSS1_CMD_INVOKE:
- if ((cs->ics.parm.dss1_io.ll_id == ic->parm.dss1_io.ll_id) &&
- (cs->ics.parm.dss1_io.hl_id == ic->parm.dss1_io.hl_id)) {
- switch (ic->arg) {
- case DSS1_STAT_INVOKE_ERR:
- sprintf(cs->info, "128 0x%lx 0x%x\n",
- ic->parm.dss1_io.ll_id,
- ic->parm.dss1_io.timeout);
- put_info_buffer(cs->info);
- break;
-
- case DSS1_STAT_INVOKE_RES:
- switch (cs->ics.parm.dss1_io.proc) {
- case 7:
- case 8:
- put_info_buffer(cs->info);
- break;
-
- case 11:
- i = interrogate_success(ic, cs);
- if (i)
- sprintf(cs->info, "%d 0x%lx %d\n", DIVERT_REPORT,
- ic->parm.dss1_io.ll_id, i);
- put_info_buffer(cs->info);
- break;
-
- default:
- printk(KERN_WARNING "dss1_divert: unknown proc %d\n", cs->ics.parm.dss1_io.proc);
- break;
- }
-
- break;
-
- default:
- printk(KERN_WARNING "dss1_divert unknown invoke answer %lx\n", ic->arg);
- break;
- }
- cs1 = cs; /* remember structure */
- cs = NULL;
- continue; /* abort search */
- } /* id found */
- break;
-
- case DSS1_CMD_INVOKE_ABORT:
- printk(KERN_WARNING "dss1_divert unhandled invoke abort\n");
- break;
-
- default:
- printk(KERN_WARNING "dss1_divert unknown cmd 0x%lx\n", cs->ics.arg);
- break;
- } /* switch ics.arg */
- cs = cs->next;
- } /* driver ok */
- }
-
- if (!cs1) {
- printk(KERN_WARNING "dss1_divert unhandled process\n");
- return (0);
- }
-
- if (cs1->ics.driver == -1) {
- spin_lock_irqsave(&divert_lock, flags);
- del_timer(&cs1->timer);
- if (cs1->prev)
- cs1->prev->next = cs1->next; /* forward link */
- else
- divert_head = cs1->next;
- if (cs1->next)
- cs1->next->prev = cs1->prev; /* back link */
- spin_unlock_irqrestore(&divert_lock, flags);
- kfree(cs1);
- }
-
- return (0);
-} /* prot_stat_callback */
-
-
-/***************************/
-/* status callback from HL */
-/***************************/
-static int isdn_divert_stat_callback(isdn_ctrl *ic)
-{
- struct call_struc *cs, *cs1;
- unsigned long flags;
- int retval;
-
- retval = -1;
- cs = divert_head; /* start of list */
- while (cs) {
- if ((ic->driver == cs->ics.driver) &&
- (ic->arg == cs->ics.arg)) {
- switch (ic->command) {
- case ISDN_STAT_DHUP:
- sprintf(cs->info, "129 0x%lx\n", cs->divert_id);
- del_timer(&cs->timer);
- cs->ics.driver = -1;
- break;
-
- case ISDN_STAT_CAUSE:
- sprintf(cs->info, "130 0x%lx %s\n", cs->divert_id, ic->parm.num);
- break;
-
- case ISDN_STAT_REDIR:
- sprintf(cs->info, "131 0x%lx\n", cs->divert_id);
- del_timer(&cs->timer);
- cs->ics.driver = -1;
- break;
-
- default:
- sprintf(cs->info, "999 0x%lx 0x%x\n", cs->divert_id, (int)(ic->command));
- break;
- }
- put_info_buffer(cs->info);
- retval = 0;
- }
- cs1 = cs;
- cs = cs->next;
- if (cs1->ics.driver == -1) {
- spin_lock_irqsave(&divert_lock, flags);
- if (cs1->prev)
- cs1->prev->next = cs1->next; /* forward link */
- else
- divert_head = cs1->next;
- if (cs1->next)
- cs1->next->prev = cs1->prev; /* back link */
- spin_unlock_irqrestore(&divert_lock, flags);
- kfree(cs1);
- }
- }
- return (retval); /* not found */
-} /* isdn_divert_stat_callback */
-
-
-/********************/
-/* callback from ll */
-/********************/
-int ll_callback(isdn_ctrl *ic)
-{
- switch (ic->command) {
- case ISDN_STAT_ICALL:
- case ISDN_STAT_ICALLW:
- return (isdn_divert_icall(ic));
- break;
-
- case ISDN_STAT_PROT:
- if ((ic->arg & 0xFF) == ISDN_PTYPE_EURO) {
- if (ic->arg != DSS1_STAT_INVOKE_BRD)
- return (prot_stat_callback(ic));
- else
- return (0); /* DSS1 invoke broadcast */
- } else
- return (-1); /* protocol not euro */
-
- default:
- return (isdn_divert_stat_callback(ic));
- }
-} /* ll_callback */
diff --git a/drivers/isdn/divert/isdn_divert.h b/drivers/isdn/divert/isdn_divert.h
deleted file mode 100644
index 55033dd872c0..000000000000
--- a/drivers/isdn/divert/isdn_divert.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/* $Id: isdn_divert.h,v 1.5.6.1 2001/09/23 22:24:36 kai Exp $
- *
- * Header for the diversion supplementary ioctl interface.
- *
- * Copyright 1998 by Werner Cornelius (werner@ikt.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/ioctl.h>
-#include <linux/types.h>
-
-/******************************************/
-/* IOCTL codes for interface to user prog */
-/******************************************/
-#define DIVERT_IIOC_VERSION 0x01 /* actual version */
-#define IIOCGETVER _IO('I', 1) /* get version of interface */
-#define IIOCGETDRV _IO('I', 2) /* get driver number */
-#define IIOCGETNAM _IO('I', 3) /* get driver name */
-#define IIOCGETRULE _IO('I', 4) /* read one rule */
-#define IIOCMODRULE _IO('I', 5) /* modify/replace a rule */
-#define IIOCINSRULE _IO('I', 6) /* insert/append one rule */
-#define IIOCDELRULE _IO('I', 7) /* delete a rule */
-#define IIOCDODFACT _IO('I', 8) /* hangup/reject/alert/immediately deflect a call */
-#define IIOCDOCFACT _IO('I', 9) /* activate control forwarding in PBX */
-#define IIOCDOCFDIS _IO('I', 10) /* deactivate control forwarding in PBX */
-#define IIOCDOCFINT _IO('I', 11) /* interrogate control forwarding in PBX */
-
-/*************************************/
-/* states reported through interface */
-/*************************************/
-#define DEFLECT_IGNORE 0 /* ignore incoming call */
-#define DEFLECT_REPORT 1 /* only report */
-#define DEFLECT_PROCEED 2 /* deflect when externally triggered */
-#define DEFLECT_ALERT 3 /* alert and deflect after delay */
-#define DEFLECT_REJECT 4 /* reject immediately */
-#define DIVERT_ACTIVATE 5 /* diversion activate */
-#define DIVERT_DEACTIVATE 6 /* diversion deactivate */
-#define DIVERT_REPORT 7 /* interrogation result */
-#define DEFLECT_AUTODEL 255 /* only for internal use */
-
-#define DEFLECT_ALL_IDS 0xFFFFFFFF /* all drivers selected */
-
-typedef struct {
- ulong drvid; /* driver ids, bit mapped */
- char my_msn[35]; /* desired msn, subaddr allowed */
- char caller[35]; /* caller id, partial string with * + subaddr allowed */
- char to_nr[35]; /* deflected to number incl. subaddress */
- u_char si1, si2; /* service indicators, si1=bitmask, si1+2 0 = all */
- u_char screen; /* screening: 0 = no info, 1 = info, 2 = nfo with nr */
- u_char callopt; /* option for call handling:
- 0 = all calls
- 1 = only non waiting calls
- 2 = only waiting calls */
- u_char action; /* desired action:
- 0 = don't report call -> ignore
- 1 = report call, do not allow/proceed for deflection
- 2 = report call, send proceed, wait max waittime secs
- 3 = report call, alert and deflect after waittime
- 4 = report call, reject immediately
- actions 1-2 only take place if interface is opened
- */
- u_char waittime; /* maximum wait time for proceeding */
-} divert_rule;
-
-typedef union {
- int drv_version; /* return of driver version */
- struct {
- int drvid; /* id of driver */
- char drvnam[30]; /* name of driver */
- } getid;
- struct {
- int ruleidx; /* index of rule */
- divert_rule rule; /* rule parms */
- } getsetrule;
- struct {
- u_char subcmd; /* 0 = hangup/reject,
- 1 = alert,
- 2 = deflect */
- ulong callid; /* id of call delivered by ascii output */
- char to_nr[35]; /* destination when deflect,
- else uus1 string (maxlen 31),
- data from rule used if empty */
- } fwd_ctrl;
- struct {
- int drvid; /* id of driver */
- u_char cfproc; /* cfu = 0, cfb = 1, cfnr = 2 */
- ulong procid; /* process id returned when no error */
- u_char service; /* basically coded service, 0 = all */
- char msn[25]; /* desired msn, empty = all */
- char fwd_nr[35];/* forwarded to number + subaddress */
- } cf_ctrl;
-} divert_ioctl;
-
-#ifdef __KERNEL__
-
-#include <linux/isdnif.h>
-#include <linux/isdn_divertif.h>
-
-#define AUTODEL_TIME 30 /* timeout in s to delete internal entries */
-
-/**************************************************/
-/* structure keeping ascii info for device output */
-/**************************************************/
-struct divert_info {
- struct divert_info *next;
- ulong usage_cnt; /* number of files still to work */
- char info_start[2]; /* info string start */
-};
-
-
-/**************/
-/* Prototypes */
-/**************/
-extern spinlock_t divert_lock;
-
-extern ulong if_used; /* number of interface users */
-extern int divert_dev_deinit(void);
-extern int divert_dev_init(void);
-extern void put_info_buffer(char *);
-extern int ll_callback(isdn_ctrl *);
-extern isdn_divert_if divert_if;
-extern divert_rule *getruleptr(int);
-extern int insertrule(int, divert_rule *);
-extern int deleterule(int);
-extern void deleteprocs(void);
-extern int deflect_extern_action(u_char, ulong, char *);
-extern int cf_command(int, int, u_char, char *, u_char, char *, ulong *);
-
-#endif /* __KERNEL__ */
diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c
deleted file mode 100644
index 335b8ce2bb06..000000000000
--- a/drivers/isdn/gigaset/i4l.c
+++ /dev/null
@@ -1,692 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Stuff used by all variants of the driver
- *
- * Copyright (c) 2001 by Stefan Eilers,
- * Hansjoerg Lipp <hjlipp@web.de>,
- * Tilman Schmidt <tilman@imap.cc>.
- *
- * =====================================================================
- * =====================================================================
- */
-
-#include "gigaset.h"
-#include <linux/isdnif.h>
-#include <linux/export.h>
-
-#define SBUFSIZE 4096 /* sk_buff payload size */
-#define TRANSBUFSIZE 768 /* bytes per skb for transparent receive */
-#define HW_HDR_LEN 2 /* Header size used to store ack info */
-#define MAX_BUF_SIZE (SBUFSIZE - HW_HDR_LEN) /* max data packet from LL */
-
-/* == Handling of I4L IO =====================================================*/
-
-/* writebuf_from_LL
- * called by LL to transmit data on an open channel
- * inserts the buffer data into the send queue and starts the transmission
- * Note that this operation must not sleep!
- * When the buffer is processed completely, gigaset_skb_sent() should be called.
- * parameters:
- * driverID driver ID as assigned by LL
- * channel channel number
- * ack if != 0 LL wants to be notified on completion via
- * statcallb(ISDN_STAT_BSENT)
- * skb skb containing data to send
- * return value:
- * number of accepted bytes
- * 0 if temporarily unable to accept data (out of buffer space)
- * <0 on error (eg. -EINVAL)
- */
-static int writebuf_from_LL(int driverID, int channel, int ack,
- struct sk_buff *skb)
-{
- struct cardstate *cs = gigaset_get_cs_by_id(driverID);
- struct bc_state *bcs;
- unsigned char *ack_header;
- unsigned len;
-
- if (!cs) {
- pr_err("%s: invalid driver ID (%d)\n", __func__, driverID);
- return -ENODEV;
- }
- if (channel < 0 || channel >= cs->channels) {
- dev_err(cs->dev, "%s: invalid channel ID (%d)\n",
- __func__, channel);
- return -ENODEV;
- }
- bcs = &cs->bcs[channel];
-
- /* can only handle linear sk_buffs */
- if (skb_linearize(skb) < 0) {
- dev_err(cs->dev, "%s: skb_linearize failed\n", __func__);
- return -ENOMEM;
- }
- len = skb->len;
-
- gig_dbg(DEBUG_LLDATA,
- "Receiving data from LL (id: %d, ch: %d, ack: %d, sz: %d)",
- driverID, channel, ack, len);
-
- if (!len) {
- if (ack)
- dev_notice(cs->dev, "%s: not ACKing empty packet\n",
- __func__);
- return 0;
- }
- if (len > MAX_BUF_SIZE) {
- dev_err(cs->dev, "%s: packet too large (%d bytes)\n",
- __func__, len);
- return -EINVAL;
- }
-
- /* set up acknowledgement header */
- if (skb_headroom(skb) < HW_HDR_LEN) {
- /* should never happen */
- dev_err(cs->dev, "%s: insufficient skb headroom\n", __func__);
- return -ENOMEM;
- }
- skb_set_mac_header(skb, -HW_HDR_LEN);
- skb->mac_len = HW_HDR_LEN;
- ack_header = skb_mac_header(skb);
- if (ack) {
- ack_header[0] = len & 0xff;
- ack_header[1] = len >> 8;
- } else {
- ack_header[0] = ack_header[1] = 0;
- }
- gig_dbg(DEBUG_MCMD, "skb: len=%u, ack=%d: %02x %02x",
- len, ack, ack_header[0], ack_header[1]);
-
- /* pass to device-specific module */
- return cs->ops->send_skb(bcs, skb);
-}
-
-/**
- * gigaset_skb_sent() - acknowledge sending an skb
- * @bcs: B channel descriptor structure.
- * @skb: sent data.
- *
- * Called by hardware module {bas,ser,usb}_gigaset when the data in a
- * skb has been successfully sent, for signalling completion to the LL.
- */
-void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb)
-{
- isdn_if *iif = bcs->cs->iif;
- unsigned char *ack_header = skb_mac_header(skb);
- unsigned len;
- isdn_ctrl response;
-
- ++bcs->trans_up;
-
- if (skb->len)
- dev_warn(bcs->cs->dev, "%s: skb->len==%d\n",
- __func__, skb->len);
-
- len = ack_header[0] + ((unsigned) ack_header[1] << 8);
- if (len) {
- gig_dbg(DEBUG_MCMD, "ACKing to LL (id: %d, ch: %d, sz: %u)",
- bcs->cs->myid, bcs->channel, len);
-
- response.driver = bcs->cs->myid;
- response.command = ISDN_STAT_BSENT;
- response.arg = bcs->channel;
- response.parm.length = len;
- iif->statcallb(&response);
- }
-}
-EXPORT_SYMBOL_GPL(gigaset_skb_sent);
-
-/**
- * gigaset_skb_rcvd() - pass received skb to LL
- * @bcs: B channel descriptor structure.
- * @skb: received data.
- *
- * Called by hardware module {bas,ser,usb}_gigaset when user data has
- * been successfully received, for passing to the LL.
- * Warning: skb must not be accessed anymore!
- */
-void gigaset_skb_rcvd(struct bc_state *bcs, struct sk_buff *skb)
-{
- isdn_if *iif = bcs->cs->iif;
-
- iif->rcvcallb_skb(bcs->cs->myid, bcs->channel, skb);
- bcs->trans_down++;
-}
-EXPORT_SYMBOL_GPL(gigaset_skb_rcvd);
-
-/**
- * gigaset_isdn_rcv_err() - signal receive error
- * @bcs: B channel descriptor structure.
- *
- * Called by hardware module {bas,ser,usb}_gigaset when a receive error
- * has occurred, for signalling to the LL.
- */
-void gigaset_isdn_rcv_err(struct bc_state *bcs)
-{
- isdn_if *iif = bcs->cs->iif;
- isdn_ctrl response;
-
- /* if currently ignoring packets, just count down */
- if (bcs->ignore) {
- bcs->ignore--;
- return;
- }
-
- /* update statistics */
- bcs->corrupted++;
-
- /* error -> LL */
- gig_dbg(DEBUG_CMD, "sending L1ERR");
- response.driver = bcs->cs->myid;
- response.command = ISDN_STAT_L1ERR;
- response.arg = bcs->channel;
- response.parm.errcode = ISDN_STAT_L1ERR_RECV;
- iif->statcallb(&response);
-}
-EXPORT_SYMBOL_GPL(gigaset_isdn_rcv_err);
-
-/* This function will be called by LL to send commands
- * NOTE: LL ignores the returned value, for commands other than ISDN_CMD_IOCTL,
- * so don't put too much effort into it.
- */
-static int command_from_LL(isdn_ctrl *cntrl)
-{
- struct cardstate *cs;
- struct bc_state *bcs;
- int retval = 0;
- char **commands;
- int ch;
- int i;
- size_t l;
-
- gig_dbg(DEBUG_CMD, "driver: %d, command: %d, arg: 0x%lx",
- cntrl->driver, cntrl->command, cntrl->arg);
-
- cs = gigaset_get_cs_by_id(cntrl->driver);
- if (cs == NULL) {
- pr_err("%s: invalid driver ID (%d)\n", __func__, cntrl->driver);
- return -ENODEV;
- }
- ch = cntrl->arg & 0xff;
-
- switch (cntrl->command) {
- case ISDN_CMD_IOCTL:
- dev_warn(cs->dev, "ISDN_CMD_IOCTL not supported\n");
- return -EINVAL;
-
- case ISDN_CMD_DIAL:
- gig_dbg(DEBUG_CMD,
- "ISDN_CMD_DIAL (phone: %s, msn: %s, si1: %d, si2: %d)",
- cntrl->parm.setup.phone, cntrl->parm.setup.eazmsn,
- cntrl->parm.setup.si1, cntrl->parm.setup.si2);
-
- if (ch >= cs->channels) {
- dev_err(cs->dev,
- "ISDN_CMD_DIAL: invalid channel (%d)\n", ch);
- return -EINVAL;
- }
- bcs = cs->bcs + ch;
- if (gigaset_get_channel(bcs) < 0) {
- dev_err(cs->dev, "ISDN_CMD_DIAL: channel not free\n");
- return -EBUSY;
- }
- switch (bcs->proto2) {
- case L2_HDLC:
- bcs->rx_bufsize = SBUFSIZE;
- break;
- default: /* assume transparent */
- bcs->rx_bufsize = TRANSBUFSIZE;
- }
- dev_kfree_skb(bcs->rx_skb);
- gigaset_new_rx_skb(bcs);
-
- commands = kcalloc(AT_NUM, sizeof(*commands), GFP_ATOMIC);
- if (!commands) {
- gigaset_free_channel(bcs);
- dev_err(cs->dev, "ISDN_CMD_DIAL: out of memory\n");
- return -ENOMEM;
- }
-
- l = 3 + strlen(cntrl->parm.setup.phone);
- commands[AT_DIAL] = kmalloc(l, GFP_ATOMIC);
- if (!commands[AT_DIAL])
- goto oom;
- if (cntrl->parm.setup.phone[0] == '*' &&
- cntrl->parm.setup.phone[1] == '*') {
- /* internal call: translate ** prefix to CTP value */
- commands[AT_TYPE] = kstrdup("^SCTP=0\r", GFP_ATOMIC);
- if (!commands[AT_TYPE])
- goto oom;
- snprintf(commands[AT_DIAL], l,
- "D%s\r", cntrl->parm.setup.phone + 2);
- } else {
- commands[AT_TYPE] = kstrdup("^SCTP=1\r", GFP_ATOMIC);
- if (!commands[AT_TYPE])
- goto oom;
- snprintf(commands[AT_DIAL], l,
- "D%s\r", cntrl->parm.setup.phone);
- }
-
- l = strlen(cntrl->parm.setup.eazmsn);
- if (l) {
- l += 8;
- commands[AT_MSN] = kmalloc(l, GFP_ATOMIC);
- if (!commands[AT_MSN])
- goto oom;
- snprintf(commands[AT_MSN], l, "^SMSN=%s\r",
- cntrl->parm.setup.eazmsn);
- }
-
- switch (cntrl->parm.setup.si1) {
- case 1: /* audio */
- /* BC = 9090A3: 3.1 kHz audio, A-law */
- commands[AT_BC] = kstrdup("^SBC=9090A3\r", GFP_ATOMIC);
- if (!commands[AT_BC])
- goto oom;
- break;
- case 7: /* data */
- default: /* hope the app knows what it is doing */
- /* BC = 8890: unrestricted digital information */
- commands[AT_BC] = kstrdup("^SBC=8890\r", GFP_ATOMIC);
- if (!commands[AT_BC])
- goto oom;
- }
- /* ToDo: other si1 values, inspect si2, set HLC/LLC */
-
- commands[AT_PROTO] = kmalloc(9, GFP_ATOMIC);
- if (!commands[AT_PROTO])
- goto oom;
- snprintf(commands[AT_PROTO], 9, "^SBPR=%u\r", bcs->proto2);
-
- commands[AT_ISO] = kmalloc(9, GFP_ATOMIC);
- if (!commands[AT_ISO])
- goto oom;
- snprintf(commands[AT_ISO], 9, "^SISO=%u\r",
- (unsigned) bcs->channel + 1);
-
- if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, commands,
- bcs->at_state.seq_index, NULL)) {
- for (i = 0; i < AT_NUM; ++i)
- kfree(commands[i]);
- kfree(commands);
- gigaset_free_channel(bcs);
- return -ENOMEM;
- }
- gigaset_schedule_event(cs);
- break;
- case ISDN_CMD_ACCEPTD:
- gig_dbg(DEBUG_CMD, "ISDN_CMD_ACCEPTD");
- if (ch >= cs->channels) {
- dev_err(cs->dev,
- "ISDN_CMD_ACCEPTD: invalid channel (%d)\n", ch);
- return -EINVAL;
- }
- bcs = cs->bcs + ch;
- switch (bcs->proto2) {
- case L2_HDLC:
- bcs->rx_bufsize = SBUFSIZE;
- break;
- default: /* assume transparent */
- bcs->rx_bufsize = TRANSBUFSIZE;
- }
- dev_kfree_skb(bcs->rx_skb);
- gigaset_new_rx_skb(bcs);
- if (!gigaset_add_event(cs, &bcs->at_state,
- EV_ACCEPT, NULL, 0, NULL))
- return -ENOMEM;
- gigaset_schedule_event(cs);
-
- break;
- case ISDN_CMD_HANGUP:
- gig_dbg(DEBUG_CMD, "ISDN_CMD_HANGUP");
- if (ch >= cs->channels) {
- dev_err(cs->dev,
- "ISDN_CMD_HANGUP: invalid channel (%d)\n", ch);
- return -EINVAL;
- }
- bcs = cs->bcs + ch;
- if (!gigaset_add_event(cs, &bcs->at_state,
- EV_HUP, NULL, 0, NULL))
- return -ENOMEM;
- gigaset_schedule_event(cs);
-
- break;
- case ISDN_CMD_CLREAZ: /* Do not signal incoming signals */
- dev_info(cs->dev, "ignoring ISDN_CMD_CLREAZ\n");
- break;
- case ISDN_CMD_SETEAZ: /* Signal incoming calls for given MSN */
- dev_info(cs->dev, "ignoring ISDN_CMD_SETEAZ (%s)\n",
- cntrl->parm.num);
- break;
- case ISDN_CMD_SETL2: /* Set L2 to given protocol */
- if (ch >= cs->channels) {
- dev_err(cs->dev,
- "ISDN_CMD_SETL2: invalid channel (%d)\n", ch);
- return -EINVAL;
- }
- bcs = cs->bcs + ch;
- if (bcs->chstate & CHS_D_UP) {
- dev_err(cs->dev,
- "ISDN_CMD_SETL2: channel active (%d)\n", ch);
- return -EINVAL;
- }
- switch (cntrl->arg >> 8) {
- case ISDN_PROTO_L2_HDLC:
- gig_dbg(DEBUG_CMD, "ISDN_CMD_SETL2: setting L2_HDLC");
- bcs->proto2 = L2_HDLC;
- break;
- case ISDN_PROTO_L2_TRANS:
- gig_dbg(DEBUG_CMD, "ISDN_CMD_SETL2: setting L2_VOICE");
- bcs->proto2 = L2_VOICE;
- break;
- default:
- dev_err(cs->dev,
- "ISDN_CMD_SETL2: unsupported protocol (%lu)\n",
- cntrl->arg >> 8);
- return -EINVAL;
- }
- break;
- case ISDN_CMD_SETL3: /* Set L3 to given protocol */
- gig_dbg(DEBUG_CMD, "ISDN_CMD_SETL3");
- if (ch >= cs->channels) {
- dev_err(cs->dev,
- "ISDN_CMD_SETL3: invalid channel (%d)\n", ch);
- return -EINVAL;
- }
-
- if (cntrl->arg >> 8 != ISDN_PROTO_L3_TRANS) {
- dev_err(cs->dev,
- "ISDN_CMD_SETL3: unsupported protocol (%lu)\n",
- cntrl->arg >> 8);
- return -EINVAL;
- }
-
- break;
-
- default:
- gig_dbg(DEBUG_CMD, "unknown command %d from LL",
- cntrl->command);
- return -EINVAL;
- }
-
- return retval;
-
-oom:
- dev_err(bcs->cs->dev, "out of memory\n");
- for (i = 0; i < AT_NUM; ++i)
- kfree(commands[i]);
- kfree(commands);
- gigaset_free_channel(bcs);
- return -ENOMEM;
-}
-
-static void gigaset_i4l_cmd(struct cardstate *cs, int cmd)
-{
- isdn_if *iif = cs->iif;
- isdn_ctrl command;
-
- command.driver = cs->myid;
- command.command = cmd;
- command.arg = 0;
- iif->statcallb(&command);
-}
-
-static void gigaset_i4l_channel_cmd(struct bc_state *bcs, int cmd)
-{
- isdn_if *iif = bcs->cs->iif;
- isdn_ctrl command;
-
- command.driver = bcs->cs->myid;
- command.command = cmd;
- command.arg = bcs->channel;
- iif->statcallb(&command);
-}
-
-/**
- * gigaset_isdn_icall() - signal incoming call
- * @at_state: connection state structure.
- *
- * Called by main module to notify the LL that an incoming call has been
- * received. @at_state contains the parameters of the call.
- *
- * Return value: call disposition (ICALL_*)
- */
-int gigaset_isdn_icall(struct at_state_t *at_state)
-{
- struct cardstate *cs = at_state->cs;
- struct bc_state *bcs = at_state->bcs;
- isdn_if *iif = cs->iif;
- isdn_ctrl response;
- int retval;
-
- /* fill ICALL structure */
- response.parm.setup.si1 = 0; /* default: unknown */
- response.parm.setup.si2 = 0;
- response.parm.setup.screen = 0;
- response.parm.setup.plan = 0;
- if (!at_state->str_var[STR_ZBC]) {
- /* no BC (internal call): assume speech, A-law */
- response.parm.setup.si1 = 1;
- } else if (!strcmp(at_state->str_var[STR_ZBC], "8890")) {
- /* unrestricted digital information */
- response.parm.setup.si1 = 7;
- } else if (!strcmp(at_state->str_var[STR_ZBC], "8090A3")) {
- /* speech, A-law */
- response.parm.setup.si1 = 1;
- } else if (!strcmp(at_state->str_var[STR_ZBC], "9090A3")) {
- /* 3,1 kHz audio, A-law */
- response.parm.setup.si1 = 1;
- response.parm.setup.si2 = 2;
- } else {
- dev_warn(cs->dev, "RING ignored - unsupported BC %s\n",
- at_state->str_var[STR_ZBC]);
- return ICALL_IGNORE;
- }
- if (at_state->str_var[STR_NMBR]) {
- strlcpy(response.parm.setup.phone, at_state->str_var[STR_NMBR],
- sizeof response.parm.setup.phone);
- } else
- response.parm.setup.phone[0] = 0;
- if (at_state->str_var[STR_ZCPN]) {
- strlcpy(response.parm.setup.eazmsn, at_state->str_var[STR_ZCPN],
- sizeof response.parm.setup.eazmsn);
- } else
- response.parm.setup.eazmsn[0] = 0;
-
- if (!bcs) {
- dev_notice(cs->dev, "no channel for incoming call\n");
- response.command = ISDN_STAT_ICALLW;
- response.arg = 0;
- } else {
- gig_dbg(DEBUG_CMD, "Sending ICALL");
- response.command = ISDN_STAT_ICALL;
- response.arg = bcs->channel;
- }
- response.driver = cs->myid;
- retval = iif->statcallb(&response);
- gig_dbg(DEBUG_CMD, "Response: %d", retval);
- switch (retval) {
- case 0: /* no takers */
- return ICALL_IGNORE;
- case 1: /* alerting */
- bcs->chstate |= CHS_NOTIFY_LL;
- return ICALL_ACCEPT;
- case 2: /* reject */
- return ICALL_REJECT;
- case 3: /* incomplete */
- dev_warn(cs->dev,
- "LL requested unsupported feature: Incomplete Number\n");
- return ICALL_IGNORE;
- case 4: /* proceeding */
- /* Gigaset will send ALERTING anyway.
- * There doesn't seem to be a way to avoid this.
- */
- return ICALL_ACCEPT;
- case 5: /* deflect */
- dev_warn(cs->dev,
- "LL requested unsupported feature: Call Deflection\n");
- return ICALL_IGNORE;
- default:
- dev_err(cs->dev, "LL error %d on ICALL\n", retval);
- return ICALL_IGNORE;
- }
-}
-
-/**
- * gigaset_isdn_connD() - signal D channel connect
- * @bcs: B channel descriptor structure.
- *
- * Called by main module to notify the LL that the D channel connection has
- * been established.
- */
-void gigaset_isdn_connD(struct bc_state *bcs)
-{
- gig_dbg(DEBUG_CMD, "sending DCONN");
- gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DCONN);
-}
-
-/**
- * gigaset_isdn_hupD() - signal D channel hangup
- * @bcs: B channel descriptor structure.
- *
- * Called by main module to notify the LL that the D channel connection has
- * been shut down.
- */
-void gigaset_isdn_hupD(struct bc_state *bcs)
-{
- gig_dbg(DEBUG_CMD, "sending DHUP");
- gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DHUP);
-}
-
-/**
- * gigaset_isdn_connB() - signal B channel connect
- * @bcs: B channel descriptor structure.
- *
- * Called by main module to notify the LL that the B channel connection has
- * been established.
- */
-void gigaset_isdn_connB(struct bc_state *bcs)
-{
- gig_dbg(DEBUG_CMD, "sending BCONN");
- gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BCONN);
-}
-
-/**
- * gigaset_isdn_hupB() - signal B channel hangup
- * @bcs: B channel descriptor structure.
- *
- * Called by main module to notify the LL that the B channel connection has
- * been shut down.
- */
-void gigaset_isdn_hupB(struct bc_state *bcs)
-{
- gig_dbg(DEBUG_CMD, "sending BHUP");
- gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BHUP);
-}
-
-/**
- * gigaset_isdn_start() - signal device availability
- * @cs: device descriptor structure.
- *
- * Called by main module to notify the LL that the device is available for
- * use.
- */
-void gigaset_isdn_start(struct cardstate *cs)
-{
- gig_dbg(DEBUG_CMD, "sending RUN");
- gigaset_i4l_cmd(cs, ISDN_STAT_RUN);
-}
-
-/**
- * gigaset_isdn_stop() - signal device unavailability
- * @cs: device descriptor structure.
- *
- * Called by main module to notify the LL that the device is no longer
- * available for use.
- */
-void gigaset_isdn_stop(struct cardstate *cs)
-{
- gig_dbg(DEBUG_CMD, "sending STOP");
- gigaset_i4l_cmd(cs, ISDN_STAT_STOP);
-}
-
-/**
- * gigaset_isdn_regdev() - register to LL
- * @cs: device descriptor structure.
- * @isdnid: device name.
- *
- * Return value: 0 on success, error code < 0 on failure
- */
-int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid)
-{
- isdn_if *iif;
-
- iif = kmalloc(sizeof *iif, GFP_KERNEL);
- if (!iif) {
- pr_err("out of memory\n");
- return -ENOMEM;
- }
-
- if (snprintf(iif->id, sizeof iif->id, "%s_%u", isdnid, cs->minor_index)
- >= sizeof iif->id) {
- pr_err("ID too long: %s\n", isdnid);
- kfree(iif);
- return -EINVAL;
- }
-
- iif->owner = THIS_MODULE;
- iif->channels = cs->channels;
- iif->maxbufsize = MAX_BUF_SIZE;
- iif->features = ISDN_FEATURE_L2_TRANS |
- ISDN_FEATURE_L2_HDLC |
- ISDN_FEATURE_L2_X75I |
- ISDN_FEATURE_L3_TRANS |
- ISDN_FEATURE_P_EURO;
- iif->hl_hdrlen = HW_HDR_LEN; /* Area for storing ack */
- iif->command = command_from_LL;
- iif->writebuf_skb = writebuf_from_LL;
- iif->writecmd = NULL; /* Don't support isdnctrl */
- iif->readstat = NULL; /* Don't support isdnctrl */
- iif->rcvcallb_skb = NULL; /* Will be set by LL */
- iif->statcallb = NULL; /* Will be set by LL */
-
- if (!register_isdn(iif)) {
- pr_err("register_isdn failed\n");
- kfree(iif);
- return -EINVAL;
- }
-
- cs->iif = iif;
- cs->myid = iif->channels; /* Set my device id */
- cs->hw_hdr_len = HW_HDR_LEN;
- return 0;
-}
-
-/**
- * gigaset_isdn_unregdev() - unregister device from LL
- * @cs: device descriptor structure.
- */
-void gigaset_isdn_unregdev(struct cardstate *cs)
-{
- gig_dbg(DEBUG_CMD, "sending UNLOAD");
- gigaset_i4l_cmd(cs, ISDN_STAT_UNLOAD);
- kfree(cs->iif);
- cs->iif = NULL;
-}
-
-/**
- * gigaset_isdn_regdrv() - register driver to LL
- */
-void gigaset_isdn_regdrv(void)
-{
- pr_info("ISDN4Linux interface\n");
- /* nothing to do */
-}
-
-/**
- * gigaset_isdn_unregdrv() - unregister driver from LL
- */
-void gigaset_isdn_unregdrv(void)
-{
- /* nothing to do */
-}
diff --git a/drivers/isdn/hardware/Kconfig b/drivers/isdn/hardware/Kconfig
deleted file mode 100644
index 0d609b5fcf01..000000000000
--- a/drivers/isdn/hardware/Kconfig
+++ /dev/null
@@ -1,8 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# ISDN hardware drivers
-#
-comment "CAPI hardware drivers"
-
-source "drivers/isdn/hardware/avm/Kconfig"
-
diff --git a/drivers/isdn/hardware/Makefile b/drivers/isdn/hardware/Makefile
index a43760a0a4f5..96f9eb2e46ba 100644
--- a/drivers/isdn/hardware/Makefile
+++ b/drivers/isdn/hardware/Makefile
@@ -3,5 +3,4 @@
# Object files in subdirectories
-obj-$(CONFIG_CAPI_AVM) += avm/
obj-$(CONFIG_MISDN) += mISDN/
diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig
index a7a34a85b970..304f50c08da2 100644
--- a/drivers/isdn/hardware/mISDN/Kconfig
+++ b/drivers/isdn/hardware/mISDN/Kconfig
@@ -79,11 +79,14 @@ config MISDN_NETJET
depends on PCI
depends on TTY
select MISDN_IPAC
- select ISDN_HDLC
- select ISDN_I4L
+ select MISDN_HDLC
help
Enable support for Traverse Technologies NETJet PCI cards.
+config MISDN_HDLC
+ tristate
+ select CRC_CCITT
+ select BITREVERSE
config MISDN_IPAC
tristate
diff --git a/drivers/isdn/hardware/mISDN/Makefile b/drivers/isdn/hardware/mISDN/Makefile
index 422f9fd8ab9a..3f50f8c4753f 100644
--- a/drivers/isdn/hardware/mISDN/Makefile
+++ b/drivers/isdn/hardware/mISDN/Makefile
@@ -15,3 +15,5 @@ obj-$(CONFIG_MISDN_NETJET) += netjet.o
# chip modules
obj-$(CONFIG_MISDN_IPAC) += mISDNipac.o
obj-$(CONFIG_MISDN_ISAR) += mISDNisar.o
+
+obj-$(CONFIG_MISDN_HDLC) += isdnhdlc.o
diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c
index 4c99739b937e..0e224232f746 100644
--- a/drivers/isdn/hardware/mISDN/hfcsusb.c
+++ b/drivers/isdn/hardware/mISDN/hfcsusb.c
@@ -1955,6 +1955,9 @@ hfcsusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
/* get endpoint base */
idx = ((ep_addr & 0x7f) - 1) * 2;
+ if (idx > 15)
+ return -EIO;
+
if (ep_addr & 0x80)
idx++;
attr = ep->desc.bmAttributes;
diff --git a/drivers/isdn/i4l/isdnhdlc.c b/drivers/isdn/hardware/mISDN/isdnhdlc.c
index 382a6b24e6a3..9fea16ed3dd8 100644
--- a/drivers/isdn/i4l/isdnhdlc.c
+++ b/drivers/isdn/hardware/mISDN/isdnhdlc.c
@@ -12,8 +12,8 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/crc-ccitt.h>
-#include <linux/isdn/hdlc.h>
#include <linux/bitrev.h>
+#include "isdnhdlc.h"
/*-------------------------------------------------------------------*/
diff --git a/drivers/isdn/hardware/mISDN/isdnhdlc.h b/drivers/isdn/hardware/mISDN/isdnhdlc.h
new file mode 100644
index 000000000000..fe2c1279c139
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/isdnhdlc.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * hdlc.h -- General purpose ISDN HDLC decoder.
+ *
+ * Implementation of a HDLC decoder/encoder in software.
+ * Necessary because some ISDN devices don't have HDLC
+ * controllers.
+ *
+ * Copyright (C)
+ * 2009 Karsten Keil <keil@b1-systems.de>
+ * 2002 Wolfgang Mües <wolfgang@iksw-muees.de>
+ * 2001 Frode Isaksen <fisaksen@bewan.com>
+ * 2001 Kai Germaschewski <kai.germaschewski@gmx.de>
+ */
+
+#ifndef __ISDNHDLC_H__
+#define __ISDNHDLC_H__
+
+struct isdnhdlc_vars {
+ int bit_shift;
+ int hdlc_bits1;
+ int data_bits;
+ int ffbit_shift; /* encoding only */
+ int state;
+ int dstpos;
+
+ u16 crc;
+
+ u8 cbin;
+ u8 shift_reg;
+ u8 ffvalue;
+
+ /* set if transferring data */
+ u32 data_received:1;
+ /* set if D channel (send idle instead of flags) */
+ u32 dchannel:1;
+ /* set if 56K adaptation */
+ u32 do_adapt56:1;
+ /* set if in closing phase (need to send CRC + flag) */
+ u32 do_closing:1;
+ /* set if data is bitreverse */
+ u32 do_bitreverse:1;
+};
+
+/* Feature Flags */
+#define HDLC_56KBIT 0x01
+#define HDLC_DCHANNEL 0x02
+#define HDLC_BITREVERSE 0x04
+
+/*
+ The return value from isdnhdlc_decode is
+ the frame length, 0 if no complete frame was decoded,
+ or a negative error number
+*/
+#define HDLC_FRAMING_ERROR 1
+#define HDLC_CRC_ERROR 2
+#define HDLC_LENGTH_ERROR 3
+
+extern void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features);
+
+extern int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src,
+ int slen, int *count, u8 *dst, int dsize);
+
+extern void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, u32 features);
+
+extern int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src,
+ u16 slen, int *count, u8 *dst, int dsize);
+
+#endif /* __ISDNHDLC_H__ */
diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c
index 5c9e38ba52ea..4e30affd1a7c 100644
--- a/drivers/isdn/hardware/mISDN/netjet.c
+++ b/drivers/isdn/hardware/mISDN/netjet.c
@@ -16,7 +16,7 @@
#include "ipac.h"
#include "iohelper.h"
#include "netjet.h"
-#include <linux/isdn/hdlc.h>
+#include "isdnhdlc.h"
#define NETJET_REV "2.0"
diff --git a/drivers/isdn/hisax/Kconfig b/drivers/isdn/hisax/Kconfig
deleted file mode 100644
index 43d98ccf5ff6..000000000000
--- a/drivers/isdn/hisax/Kconfig
+++ /dev/null
@@ -1,423 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-
-menu "Passive cards"
-
-config ISDN_DRV_HISAX
- tristate "HiSax SiemensChipSet driver support"
- select CRC_CCITT
- ---help---
- This is a driver supporting the Siemens chipset on various
- ISDN-cards (like AVM A1, Elsa ISDN cards, Teles S0-16.0, Teles
- S0-16.3, Teles S0-8, Teles/Creatix PnP, ITK micro ix1 and many
- compatibles).
-
- HiSax is just the name of this driver, not the name of any hardware.
-
- If you have a card with such a chipset, you should say Y here and
- also to the configuration option of the driver for your particular
- card, below.
-
-if ISDN_DRV_HISAX
-
-comment "D-channel protocol features"
-
-config HISAX_EURO
- bool "HiSax Support for EURO/DSS1"
- help
- Say Y or N according to the D-channel protocol which your local
- telephone service company provides.
-
- The call control protocol E-DSS1 is used in most European countries.
- If unsure, say Y.
-
-config DE_AOC
- bool "Support for german chargeinfo"
- depends on HISAX_EURO
- help
- If you want that the HiSax hardware driver sends messages to the
- upper level of the isdn code on each AOCD (Advice Of Charge, During
- the call -- transmission of the fee information during a call) and
- on each AOCE (Advice Of Charge, at the End of the call --
- transmission of fee information at the end of the call), say Y here.
- This works only in Germany.
-
-config HISAX_NO_SENDCOMPLETE
- bool "Disable sending complete"
- depends on HISAX_EURO
- help
- If you have trouble with some ugly exchanges or you live in
- Australia select this option.
-
-config HISAX_NO_LLC
- bool "Disable sending low layer compatibility"
- depends on HISAX_EURO
- help
- If you have trouble with some ugly exchanges try to select this
- option.
-
-config HISAX_NO_KEYPAD
- bool "Disable keypad protocol option"
- depends on HISAX_EURO
- help
- If you like to send special dial strings including * or # without
- using the keypad protocol, select this option.
-
-config HISAX_1TR6
- bool "HiSax Support for german 1TR6"
- help
- Say Y or N according to the D-channel protocol which your local
- telephone service company provides.
-
- 1TR6 is an old call control protocol which was used in Germany
- before E-DSS1 was established. Nowadays, all new lines in Germany
- use E-DSS1.
-
-config HISAX_NI1
- bool "HiSax Support for US NI1"
- help
- Enable this if you like to use ISDN in US on a NI1 basic rate
- interface.
-
-config HISAX_MAX_CARDS
- int "Maximum number of cards supported by HiSax"
- default "8"
- help
- This option allows you to specify the maximum number of cards which
- the HiSax driver will be able to handle.
-
-comment "HiSax supported cards"
-
-config HISAX_16_0
- bool "Teles 16.0/8.0"
- depends on ISA
- help
- This enables HiSax support for the Teles ISDN-cards S0-16.0, S0-8
- and many compatibles.
-
- See <file:Documentation/isdn/README.HiSax> on how to configure it
- using the different cards, a different D-channel protocol, or
- non-standard IRQ/port/shmem settings.
-
-config HISAX_16_3
- bool "Teles 16.3 or PNP or PCMCIA"
- help
- This enables HiSax support for the Teles ISDN-cards S0-16.3 the
- Teles/Creatix PnP and the Teles PCMCIA.
-
- See <file:Documentation/isdn/README.HiSax> on how to configure it
- using the different cards, a different D-channel protocol, or
- non-standard IRQ/port settings.
-
-config HISAX_TELESPCI
- bool "Teles PCI"
- depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || (XTENSA && !CPU_LITTLE_ENDIAN)))
- help
- This enables HiSax support for the Teles PCI.
- See <file:Documentation/isdn/README.HiSax> on how to configure it.
-
-config HISAX_S0BOX
- bool "Teles S0Box"
- help
- This enables HiSax support for the Teles/Creatix parallel port
- S0BOX. See <file:Documentation/isdn/README.HiSax> on how to
- configure it.
-
-config HISAX_AVM_A1
- bool "AVM A1 (Fritz)"
- depends on ISA
- help
- This enables HiSax support for the AVM A1 (aka "Fritz").
-
- See <file:Documentation/isdn/README.HiSax> on how to configure it
- using the different cards, a different D-channel protocol, or
- non-standard IRQ/port settings.
-
-config HISAX_FRITZPCI
- bool "AVM PnP/PCI (Fritz!PnP/PCI)"
- depends on BROKEN || !PPC64
- help
- This enables HiSax support for the AVM "Fritz!PnP" and "Fritz!PCI".
- See <file:Documentation/isdn/README.HiSax> on how to configure it.
-
-config HISAX_AVM_A1_PCMCIA
- bool "AVM A1 PCMCIA (Fritz)"
- help
- This enables HiSax support for the AVM A1 "Fritz!PCMCIA").
- See <file:Documentation/isdn/README.HiSax> on how to configure it.
-
-config HISAX_ELSA
- bool "Elsa cards"
- help
- This enables HiSax support for the Elsa Mircolink ISA cards, for the
- Elsa Quickstep series cards and Elsa PCMCIA.
-
- See <file:Documentation/isdn/README.HiSax> on how to configure it
- using the different cards, a different D-channel protocol, or
- non-standard IRQ/port settings.
-
-config HISAX_IX1MICROR2
- bool "ITK ix1-micro Revision 2"
- depends on ISA
- help
- This enables HiSax support for the ITK ix1-micro Revision 2 card.
-
- See <file:Documentation/isdn/README.HiSax> on how to configure it
- using the different cards, a different D-channel protocol, or
- non-standard IRQ/port settings.
-
-config HISAX_DIEHLDIVA
- bool "Eicon.Diehl Diva cards"
- help
- This enables HiSax support for the Eicon.Diehl Diva none PRO
- versions passive ISDN cards.
-
- See <file:Documentation/isdn/README.HiSax> on how to configure it
- using the different cards, a different D-channel protocol, or
- non-standard IRQ/port settings.
-
-config HISAX_ASUSCOM
- bool "ASUSCOM ISA cards"
- depends on ISA
- help
- This enables HiSax support for the AsusCom and their OEM versions
- passive ISDN ISA cards.
-
- See <file:Documentation/isdn/README.HiSax> on how to configure it
- using the different cards, a different D-channel protocol, or
- non-standard IRQ/port settings.
-
-config HISAX_TELEINT
- bool "TELEINT cards"
- depends on ISA
- help
- This enables HiSax support for the TELEINT SA1 semiactiv ISDN card.
-
- See <file:Documentation/isdn/README.HiSax> on how to configure it
- using the different cards, a different D-channel protocol, or
- non-standard IRQ/port settings.
-
-config HISAX_HFCS
- bool "HFC-S based cards"
- depends on ISA
- help
- This enables HiSax support for the HFC-S 2BDS0 based cards, like
- teles 16.3c.
-
- See <file:Documentation/isdn/README.HiSax> on how to configure it
- using the different cards, a different D-channel protocol, or
- non-standard IRQ/port settings.
-
-config HISAX_SEDLBAUER
- bool "Sedlbauer cards"
- help
- This enables HiSax support for the Sedlbauer passive ISDN cards.
-
- See <file:Documentation/isdn/README.HiSax> on how to configure it
- using the different cards, a different D-channel protocol, or
- non-standard IRQ/port settings.
-
-config HISAX_SPORTSTER
- bool "USR Sportster internal TA"
- depends on ISA
- help
- This enables HiSax support for the USR Sportster internal TA card.
-
- See <file:Documentation/isdn/README.HiSax> on how to configure it
- using a different D-channel protocol, or non-standard IRQ/port
- settings.
-
-config HISAX_MIC
- bool "MIC card"
- depends on ISA
- help
- This enables HiSax support for the ITH MIC card.
-
- See <file:Documentation/isdn/README.HiSax> on how to configure it
- using a different D-channel protocol, or non-standard IRQ/port
- settings.
-
-config HISAX_NETJET
- bool "NETjet card"
- depends on PCI && (BROKEN || !(PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || (XTENSA && !CPU_LITTLE_ENDIAN) || MICROBLAZE))
- depends on VIRT_TO_BUS
- help
- This enables HiSax support for the NetJet from Traverse
- Technologies.
-
- See <file:Documentation/isdn/README.HiSax> on how to configure it
- using a different D-channel protocol, or non-standard IRQ/port
- settings.
-
-config HISAX_NETJET_U
- bool "NETspider U card"
- depends on PCI && (BROKEN || !(PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || (XTENSA && !CPU_LITTLE_ENDIAN) || MICROBLAZE))
- depends on VIRT_TO_BUS
- help
- This enables HiSax support for the Netspider U interface ISDN card
- from Traverse Technologies.
- See <file:Documentation/isdn/README.HiSax> on how to configure it
- using a different D-channel protocol, or non-standard IRQ/port
- settings.
-
-config HISAX_NICCY
- bool "Niccy PnP/PCI card"
- help
- This enables HiSax support for the Dr. Neuhaus Niccy PnP or PCI.
-
- See <file:Documentation/isdn/README.HiSax> on how to configure it
- using a different D-channel protocol, or non-standard IRQ/port
- settings.
-
-config HISAX_ISURF
- bool "Siemens I-Surf card"
- depends on ISA
- help
- This enables HiSax support for the Siemens I-Talk/I-Surf card with
- ISAR chip.
- See <file:Documentation/isdn/README.HiSax> on how to configure it
- using a different D-channel protocol, or non-standard IRQ/port
- settings.
-
-config HISAX_HSTSAPHIR
- bool "HST Saphir card"
- depends on ISA
- help
- This enables HiSax support for the HST Saphir card.
-
- See <file:Documentation/isdn/README.HiSax> on how to configure it
- using a different D-channel protocol, or non-standard IRQ/port
- settings.
-
-config HISAX_BKM_A4T
- bool "Telekom A4T card"
- depends on PCI
- help
- This enables HiSax support for the Telekom A4T card.
-
- See <file:Documentation/isdn/README.HiSax> on how to configure it
- using a different D-channel protocol, or non-standard IRQ/port
- settings.
-
-config HISAX_SCT_QUADRO
- bool "Scitel Quadro card"
- depends on PCI
- help
- This enables HiSax support for the Scitel Quadro card.
-
- See <file:Documentation/isdn/README.HiSax> on how to configure it
- using a different D-channel protocol, or non-standard IRQ/port
- settings.
-
-config HISAX_GAZEL
- bool "Gazel cards"
- help
- This enables HiSax support for the Gazel cards.
-
- See <file:Documentation/isdn/README.HiSax> on how to configure it
- using a different D-channel protocol, or non-standard IRQ/port
- settings.
-
-config HISAX_HFC_PCI
- bool "HFC PCI-Bus cards"
- depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || (XTENSA && !CPU_LITTLE_ENDIAN)))
- help
- This enables HiSax support for the HFC-S PCI 2BDS0 based cards.
-
- For more information see under
- <file:Documentation/isdn/README.hfc-pci>.
-
-config HISAX_W6692
- bool "Winbond W6692 based cards"
- depends on PCI
- help
- This enables HiSax support for Winbond W6692 based PCI ISDN cards.
-
- See <file:Documentation/isdn/README.HiSax> on how to configure it
- using a different D-channel protocol, or non-standard IRQ/port
- settings.
-
-config HISAX_HFC_SX
- bool "HFC-S+, HFC-SP, HFC-PCMCIA cards"
- help
- This enables HiSax support for the HFC-S+, HFC-SP and HFC-PCMCIA
- cards. This code is not finished yet.
-
-config HISAX_ENTERNOW_PCI
- bool "Formula-n enter:now PCI card"
- depends on HISAX_NETJET && PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || (XTENSA && !CPU_LITTLE_ENDIAN)))
- help
- This enables HiSax support for the Formula-n enter:now PCI
- ISDN card.
-
-config HISAX_DEBUG
- bool "HiSax debugging"
- help
- This enables debugging code in the new-style HiSax drivers, i.e.
- the ST5481 USB driver currently.
- If in doubt, say yes.
-
-comment "HiSax PCMCIA card service modules"
-
-config HISAX_SEDLBAUER_CS
- tristate "Sedlbauer PCMCIA cards"
- depends on PCMCIA && HISAX_SEDLBAUER
- help
- This enables the PCMCIA client driver for the Sedlbauer Speed Star
- and Speed Star II cards.
-
-config HISAX_ELSA_CS
- tristate "ELSA PCMCIA MicroLink cards"
- depends on PCMCIA && HISAX_ELSA
- help
- This enables the PCMCIA client driver for the Elsa PCMCIA MicroLink
- card.
-
-config HISAX_AVM_A1_CS
- tristate "AVM A1 PCMCIA cards"
- depends on PCMCIA && ISDN_DRV_HISAX
- help
- This enables the PCMCIA client driver for the AVM A1 / Fritz!Card
- PCMCIA cards.
-
-config HISAX_TELES_CS
- tristate "TELES PCMCIA cards"
- depends on PCMCIA && HISAX_16_3
- help
- This enables the PCMCIA client driver for the Teles PCMCIA cards.
-
-comment "HiSax sub driver modules"
-
-config HISAX_ST5481
- tristate "ST5481 USB ISDN modem"
- depends on USB
- select ISDN_HDLC
- select CRC_CCITT
- select BITREVERSE
- help
- This enables the driver for ST5481 based USB ISDN adapters,
- e.g. the BeWan Gazel 128 USB
-
-config HISAX_HFCUSB
- tristate "HFC USB based ISDN modems"
- depends on USB
- help
- This enables the driver for HFC USB based ISDN modems.
-
-config HISAX_HFC4S8S
- tristate "HFC-4S/8S based ISDN cards"
- help
- This enables the driver for HFC-4S/8S based ISDN cards.
-
-config HISAX_FRITZ_PCIPNP
- tristate "AVM Fritz!Card PCI/PCIv2/PnP support"
- depends on PCI
- help
- This enables the driver for the AVM Fritz!Card PCI,
- Fritz!Card PCI v2 and Fritz!Card PnP.
- (the latter also needs you to select "ISA Plug and Play support"
- from the menu "Plug and Play configuration")
-
-endif
-
-endmenu
-
diff --git a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile
deleted file mode 100644
index 3eca9d23f1c2..000000000000
--- a/drivers/isdn/hisax/Makefile
+++ /dev/null
@@ -1,60 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-# Makefile for the hisax ISDN device driver
-
-# The target object and module list name.
-
-# Define maximum number of cards
-
-ccflags-y := -DHISAX_MAX_CARDS=$(CONFIG_HISAX_MAX_CARDS)
-
-obj-$(CONFIG_ISDN_DRV_HISAX) += hisax.o
-obj-$(CONFIG_HISAX_SEDLBAUER_CS) += sedlbauer_cs.o
-obj-$(CONFIG_HISAX_ELSA_CS) += elsa_cs.o
-obj-$(CONFIG_HISAX_AVM_A1_CS) += avma1_cs.o
-obj-$(CONFIG_HISAX_TELES_CS) += teles_cs.o
-obj-$(CONFIG_HISAX_ST5481) += hisax_st5481.o
-obj-$(CONFIG_HISAX_HFCUSB) += hfc_usb.o
-obj-$(CONFIG_HISAX_HFC4S8S) += hfc4s8s_l1.o
-obj-$(CONFIG_HISAX_FRITZ_PCIPNP) += hisax_isac.o hisax_fcpcipnp.o
-
-# Multipart objects.
-
-hisax_st5481-y := st5481_init.o st5481_usb.o st5481_d.o \
- st5481_b.o
-
-hisax-y := config.o isdnl1.o tei.o isdnl2.o isdnl3.o \
- lmgr.o q931.o callc.o fsm.o
-hisax-$(CONFIG_HISAX_EURO) += l3dss1.o
-hisax-$(CONFIG_HISAX_NI1) += l3ni1.o
-hisax-$(CONFIG_HISAX_1TR6) += l3_1tr6.o
-
-hisax-$(CONFIG_HISAX_16_0) += teles0.o isac.o arcofi.o hscx.o
-hisax-$(CONFIG_HISAX_16_3) += teles3.o isac.o arcofi.o hscx.o
-hisax-$(CONFIG_HISAX_TELESPCI) += telespci.o isac.o arcofi.o hscx.o
-hisax-$(CONFIG_HISAX_S0BOX) += s0box.o isac.o arcofi.o hscx.o
-hisax-$(CONFIG_HISAX_AVM_A1) += avm_a1.o isac.o arcofi.o hscx.o
-hisax-$(CONFIG_HISAX_AVM_A1_PCMCIA) += avm_a1p.o isac.o arcofi.o hscx.o
-hisax-$(CONFIG_HISAX_FRITZPCI) += avm_pci.o isac.o arcofi.o
-hisax-$(CONFIG_HISAX_ELSA) += elsa.o isac.o arcofi.o hscx.o
-hisax-$(CONFIG_HISAX_IX1MICROR2) += ix1_micro.o isac.o arcofi.o hscx.o
-hisax-$(CONFIG_HISAX_DIEHLDIVA) += diva.o isac.o arcofi.o hscx.o ipacx.o
-hisax-$(CONFIG_HISAX_ASUSCOM) += asuscom.o isac.o arcofi.o hscx.o
-hisax-$(CONFIG_HISAX_TELEINT) += teleint.o isac.o arcofi.o hfc_2bs0.o
-hisax-$(CONFIG_HISAX_SEDLBAUER) += sedlbauer.o isac.o arcofi.o hscx.o \
- isar.o
-hisax-$(CONFIG_HISAX_SPORTSTER) += sportster.o isac.o arcofi.o hscx.o
-hisax-$(CONFIG_HISAX_MIC) += mic.o isac.o arcofi.o hscx.o
-hisax-$(CONFIG_HISAX_NETJET) += nj_s.o netjet.o isac.o arcofi.o
-hisax-$(CONFIG_HISAX_NETJET_U) += nj_u.o netjet.o icc.o
-hisax-$(CONFIG_HISAX_HFCS) += hfcscard.o hfc_2bds0.o
-hisax-$(CONFIG_HISAX_HFC_PCI) += hfc_pci.o
-hisax-$(CONFIG_HISAX_HFC_SX) += hfc_sx.o
-hisax-$(CONFIG_HISAX_NICCY) += niccy.o isac.o arcofi.o hscx.o
-hisax-$(CONFIG_HISAX_ISURF) += isurf.o isac.o arcofi.o isar.o
-hisax-$(CONFIG_HISAX_HSTSAPHIR) += saphir.o isac.o arcofi.o hscx.o
-hisax-$(CONFIG_HISAX_BKM_A4T) += bkm_a4t.o isac.o arcofi.o jade.o
-hisax-$(CONFIG_HISAX_SCT_QUADRO) += bkm_a8.o isac.o arcofi.o hscx.o
-hisax-$(CONFIG_HISAX_GAZEL) += gazel.o isac.o arcofi.o hscx.o
-hisax-$(CONFIG_HISAX_W6692) += w6692.o
-hisax-$(CONFIG_HISAX_ENTERNOW_PCI) += enternow_pci.o amd7930_fn.o
-
diff --git a/drivers/isdn/hisax/amd7930_fn.c b/drivers/isdn/hisax/amd7930_fn.c
deleted file mode 100644
index 6c336366128c..000000000000
--- a/drivers/isdn/hisax/amd7930_fn.c
+++ /dev/null
@@ -1,794 +0,0 @@
-/* gerdes_amd7930.c,v 0.99 2001/10/02
- *
- * gerdes_amd7930.c Amd 79C30A and 79C32A specific routines
- * (based on HiSax driver by Karsten Keil)
- *
- * Author Christoph Ersfeld <info@formula-n.de>
- * Formula-n Europe AG (www.formula-n.com)
- * previously Gerdes AG
- *
- *
- * This file is (c) under GNU PUBLIC LICENSE
- *
- *
- * Notes:
- * Version 0.99 is the first release of this driver and there are
- * certainly a few bugs.
- *
- * Please don't report any malfunction to me without sending
- * (compressed) debug-logs.
- * It would be nearly impossible to retrace it.
- *
- * Log D-channel-processing as follows:
- *
- * 1. Load hisax with card-specific parameters, this example ist for
- * Formula-n enter:now ISDN PCI and compatible
- * (f.e. Gerdes Power ISDN PCI)
- *
- * modprobe hisax type=41 protocol=2 id=gerdes
- *
- * if you chose an other value for id, you need to modify the
- * code below, too.
- *
- * 2. set debug-level
- *
- * hisaxctrl gerdes 1 0x3ff
- * hisaxctrl gerdes 11 0x4f
- * cat /dev/isdnctrl >> ~/log &
- *
- * Please take also a look into /var/log/messages if there is
- * anything importand concerning HISAX.
- *
- *
- * Credits:
- * Programming the driver for Formula-n enter:now ISDN PCI and
- * necessary this driver for the used Amd 7930 D-channel-controller
- * was spnsored by Formula-n Europe AG.
- * Thanks to Karsten Keil and Petr Novak, who gave me support in
- * Hisax-specific questions.
- * I want so say special thanks to Carl-Friedrich Braun, who had to
- * answer a lot of questions about generally ISDN and about handling
- * of the Amd-Chip.
- *
- */
-
-
-#include "hisax.h"
-#include "isdnl1.h"
-#include "isac.h"
-#include "amd7930_fn.h"
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/gfp.h>
-
-static void Amd7930_new_ph(struct IsdnCardState *cs);
-
-static WORD initAMD[] = {
- 0x0100,
-
- 0x00A5, 3, 0x01, 0x40, 0x58, // LPR, LMR1, LMR2
- 0x0086, 1, 0x0B, // DMR1 (D-Buffer TH-Interrupts on)
- 0x0087, 1, 0xFF, // DMR2
- 0x0092, 1, 0x03, // EFCR (extended mode d-channel-fifo on)
- 0x0090, 4, 0xFE, 0xFF, 0x02, 0x0F, // FRAR4, SRAR4, DMR3, DMR4 (address recognition )
- 0x0084, 2, 0x80, 0x00, // DRLR
- 0x00C0, 1, 0x47, // PPCR1
- 0x00C8, 1, 0x01, // PPCR2
-
- 0x0102,
- 0x0107,
- 0x01A1, 1,
- 0x0121, 1,
- 0x0189, 2,
-
- 0x0045, 4, 0x61, 0x72, 0x00, 0x00, // MCR1, MCR2, MCR3, MCR4
- 0x0063, 2, 0x08, 0x08, // GX
- 0x0064, 2, 0x08, 0x08, // GR
- 0x0065, 2, 0x99, 0x00, // GER
- 0x0066, 2, 0x7C, 0x8B, // STG
- 0x0067, 2, 0x00, 0x00, // FTGR1, FTGR2
- 0x0068, 2, 0x20, 0x20, // ATGR1, ATGR2
- 0x0069, 1, 0x4F, // MMR1
- 0x006A, 1, 0x00, // MMR2
- 0x006C, 1, 0x40, // MMR3
- 0x0021, 1, 0x02, // INIT
- 0x00A3, 1, 0x40, // LMR1
-
- 0xFFFF
-};
-
-
-static void /* macro wWordAMD */
-WriteWordAmd7930(struct IsdnCardState *cs, BYTE reg, WORD val)
-{
- wByteAMD(cs, 0x00, reg);
- wByteAMD(cs, 0x01, LOBYTE(val));
- wByteAMD(cs, 0x01, HIBYTE(val));
-}
-
-static WORD /* macro rWordAMD */
-ReadWordAmd7930(struct IsdnCardState *cs, BYTE reg)
-{
- WORD res;
- /* direct access register */
- if (reg < 8) {
- res = rByteAMD(cs, reg);
- res += 256 * rByteAMD(cs, reg);
- }
- /* indirect access register */
- else {
- wByteAMD(cs, 0x00, reg);
- res = rByteAMD(cs, 0x01);
- res += 256 * rByteAMD(cs, 0x01);
- }
- return (res);
-}
-
-
-static void
-Amd7930_ph_command(struct IsdnCardState *cs, u_char command, char *s)
-{
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "AMD7930: %s: ph_command 0x%02X", s, command);
-
- cs->dc.amd7930.lmr1 = command;
- wByteAMD(cs, 0xA3, command);
-}
-
-
-
-static BYTE i430States[] = {
-// to reset F3 F4 F5 F6 F7 F8 AR from
- 0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00, // init
- 0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00, // reset
- 0x01, 0x02, 0x00, 0x00, 0x00, 0x09, 0x05, 0x04, // F3
- 0x01, 0x02, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, // F4
- 0x01, 0x02, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, // F5
- 0x01, 0x03, 0x00, 0x00, 0x00, 0x06, 0x05, 0x00, // F6
- 0x11, 0x13, 0x00, 0x00, 0x1B, 0x00, 0x15, 0x00, // F7
- 0x01, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, // F8
- 0x01, 0x03, 0x00, 0x00, 0x00, 0x09, 0x00, 0x0A}; // AR
-
-
-/* Row init - reset F3 F4 F5 F6 F7 F8 AR */
-static BYTE stateHelper[] = { 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
-
-
-
-
-static void
-Amd7930_get_state(struct IsdnCardState *cs) {
- BYTE lsr = rByteAMD(cs, 0xA1);
- cs->dc.amd7930.ph_state = (lsr & 0x7) + 2;
- Amd7930_new_ph(cs);
-}
-
-
-
-static void
-Amd7930_new_ph(struct IsdnCardState *cs)
-{
- u_char index = stateHelper[cs->dc.amd7930.old_state] * 8 + stateHelper[cs->dc.amd7930.ph_state] - 1;
- u_char message = i430States[index];
-
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "AMD7930: new_ph %d, old_ph %d, message %d, index %d",
- cs->dc.amd7930.ph_state, cs->dc.amd7930.old_state, message & 0x0f, index);
-
- cs->dc.amd7930.old_state = cs->dc.amd7930.ph_state;
-
- /* abort transmit if nessesary */
- if ((message & 0xf0) && (cs->tx_skb)) {
- wByteAMD(cs, 0x21, 0xC2);
- wByteAMD(cs, 0x21, 0x02);
- }
-
- switch (message & 0x0f) {
-
- case (1):
- l1_msg(cs, HW_RESET | INDICATION, NULL);
- Amd7930_get_state(cs);
- break;
- case (2): /* init, Card starts in F3 */
- l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
- break;
- case (3):
- l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
- break;
- case (4):
- l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
- Amd7930_ph_command(cs, 0x50, "HW_ENABLE REQUEST");
- break;
- case (5):
- l1_msg(cs, HW_RSYNC | INDICATION, NULL);
- break;
- case (6):
- l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
- break;
- case (7): /* init, Card starts in F7 */
- l1_msg(cs, HW_RSYNC | INDICATION, NULL);
- l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
- break;
- case (8):
- l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
- /* fall through */
- case (9):
- Amd7930_ph_command(cs, 0x40, "HW_ENABLE REQ cleared if set");
- l1_msg(cs, HW_RSYNC | INDICATION, NULL);
- l1_msg(cs, HW_INFO2 | INDICATION, NULL);
- l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
- break;
- case (10):
- Amd7930_ph_command(cs, 0x40, "T3 expired, HW_ENABLE REQ cleared");
- cs->dc.amd7930.old_state = 3;
- break;
- case (11):
- l1_msg(cs, HW_INFO2 | INDICATION, NULL);
- break;
- default:
- break;
- }
-}
-
-
-
-static void
-Amd7930_bh(struct work_struct *work)
-{
- struct IsdnCardState *cs =
- container_of(work, struct IsdnCardState, tqueue);
- struct PStack *stptr;
-
- if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
- if (cs->debug)
- debugl1(cs, "Amd7930: bh, D-Channel Busy cleared");
- stptr = cs->stlist;
- while (stptr != NULL) {
- stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
- stptr = stptr->next;
- }
- }
- if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "AMD7930: bh, D_L1STATECHANGE");
- Amd7930_new_ph(cs);
- }
-
- if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) {
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "AMD7930: bh, D_RCVBUFREADY");
- DChannel_proc_rcv(cs);
- }
-
- if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) {
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "AMD7930: bh, D_XMTBUFREADY");
- DChannel_proc_xmt(cs);
- }
-}
-
-static void
-Amd7930_empty_Dfifo(struct IsdnCardState *cs, int flag)
-{
-
- BYTE stat, der;
- BYTE *ptr;
- struct sk_buff *skb;
-
-
- if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
- debugl1(cs, "Amd7930: empty_Dfifo");
-
-
- ptr = cs->rcvbuf + cs->rcvidx;
-
- /* AMD interrupts off */
- AmdIrqOff(cs);
-
- /* read D-Channel-Fifo*/
- stat = rByteAMD(cs, 0x07); // DSR2
-
- /* while Data in Fifo ... */
- while ((stat & 2) && ((ptr-cs->rcvbuf) < MAX_DFRAME_LEN_L1)) {
- *ptr = rByteAMD(cs, 0x04); // DCRB
- ptr++;
- stat = rByteAMD(cs, 0x07); // DSR2
- cs->rcvidx = ptr - cs->rcvbuf;
-
- /* Paket ready? */
- if (stat & 1) {
-
- der = rWordAMD(cs, 0x03);
-
- /* no errors, packet ok */
- if (!der && !flag) {
- rWordAMD(cs, 0x89); // clear DRCR
-
- if ((cs->rcvidx) > 0) {
- if (!(skb = alloc_skb(cs->rcvidx, GFP_ATOMIC)))
- printk(KERN_WARNING "HiSax: Amd7930: empty_Dfifo, D receive out of memory!\n");
- else {
- /* Debugging */
- if (cs->debug & L1_DEB_ISAC_FIFO) {
- char *t = cs->dlog;
-
- t += sprintf(t, "Amd7930: empty_Dfifo cnt: %d |", cs->rcvidx);
- QuickHex(t, cs->rcvbuf, cs->rcvidx);
- debugl1(cs, "%s", cs->dlog);
- }
- /* moves received data in sk-buffer */
- skb_put_data(skb, cs->rcvbuf,
- cs->rcvidx);
- skb_queue_tail(&cs->rq, skb);
- }
- }
-
- }
- /* throw damaged packets away, reset receive-buffer, indicate RX */
- ptr = cs->rcvbuf;
- cs->rcvidx = 0;
- schedule_event(cs, D_RCVBUFREADY);
- }
- }
- /* Packet to long, overflow */
- if (cs->rcvidx >= MAX_DFRAME_LEN_L1) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "AMD7930: empty_Dfifo L2-Framelength overrun");
- cs->rcvidx = 0;
- return;
- }
- /* AMD interrupts on */
- AmdIrqOn(cs);
-}
-
-
-static void
-Amd7930_fill_Dfifo(struct IsdnCardState *cs)
-{
-
- WORD dtcrr, dtcrw, len, count;
- BYTE txstat, dmr3;
- BYTE *ptr, *deb_ptr;
-
- if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
- debugl1(cs, "Amd7930: fill_Dfifo");
-
- if ((!cs->tx_skb) || (cs->tx_skb->len <= 0))
- return;
-
- dtcrw = 0;
- if (!cs->dc.amd7930.tx_xmtlen)
- /* new Frame */
- len = dtcrw = cs->tx_skb->len;
- /* continue frame */
- else len = cs->dc.amd7930.tx_xmtlen;
-
-
- /* AMD interrupts off */
- AmdIrqOff(cs);
-
- deb_ptr = ptr = cs->tx_skb->data;
-
- /* while free place in tx-fifo available and data in sk-buffer */
- txstat = 0x10;
- while ((txstat & 0x10) && (cs->tx_cnt < len)) {
- wByteAMD(cs, 0x04, *ptr);
- ptr++;
- cs->tx_cnt++;
- txstat = rByteAMD(cs, 0x07);
- }
- count = ptr - cs->tx_skb->data;
- skb_pull(cs->tx_skb, count);
-
-
- dtcrr = rWordAMD(cs, 0x85); // DTCR
- dmr3 = rByteAMD(cs, 0x8E);
-
- if (cs->debug & L1_DEB_ISAC) {
- debugl1(cs, "Amd7930: fill_Dfifo, DMR3: 0x%02X, DTCR read: 0x%04X write: 0x%02X 0x%02X", dmr3, dtcrr, LOBYTE(dtcrw), HIBYTE(dtcrw));
- }
-
- /* writeing of dtcrw starts transmit */
- if (!cs->dc.amd7930.tx_xmtlen) {
- wWordAMD(cs, 0x85, dtcrw);
- cs->dc.amd7930.tx_xmtlen = dtcrw;
- }
-
- if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
- debugl1(cs, "Amd7930: fill_Dfifo dbusytimer running");
- del_timer(&cs->dbusytimer);
- }
- cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ) / 1000);
- add_timer(&cs->dbusytimer);
-
- if (cs->debug & L1_DEB_ISAC_FIFO) {
- char *t = cs->dlog;
-
- t += sprintf(t, "Amd7930: fill_Dfifo cnt: %d |", count);
- QuickHex(t, deb_ptr, count);
- debugl1(cs, "%s", cs->dlog);
- }
- /* AMD interrupts on */
- AmdIrqOn(cs);
-}
-
-
-void Amd7930_interrupt(struct IsdnCardState *cs, BYTE irflags)
-{
- BYTE dsr1, dsr2, lsr;
- WORD der;
-
- while (irflags)
- {
-
- dsr1 = rByteAMD(cs, 0x02);
- der = rWordAMD(cs, 0x03);
- dsr2 = rByteAMD(cs, 0x07);
- lsr = rByteAMD(cs, 0xA1);
-
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "Amd7930: interrupt: flags: 0x%02X, DSR1: 0x%02X, DSR2: 0x%02X, LSR: 0x%02X, DER=0x%04X", irflags, dsr1, dsr2, lsr, der);
-
- /* D error -> read DER and DSR2 bit 2 */
- if (der || (dsr2 & 4)) {
-
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "Amd7930: interrupt: D error DER=0x%04X", der);
-
- /* RX, TX abort if collision detected */
- if (der & 2) {
- wByteAMD(cs, 0x21, 0xC2);
- wByteAMD(cs, 0x21, 0x02);
- if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
- del_timer(&cs->dbusytimer);
- if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
- schedule_event(cs, D_CLEARBUSY);
- /* restart frame */
- if (cs->tx_skb) {
- skb_push(cs->tx_skb, cs->tx_cnt);
- cs->tx_cnt = 0;
- cs->dc.amd7930.tx_xmtlen = 0;
- Amd7930_fill_Dfifo(cs);
- } else {
- printk(KERN_WARNING "HiSax: Amd7930 D-Collision, no skb\n");
- debugl1(cs, "Amd7930: interrupt: D-Collision, no skb");
- }
- }
- /* remove damaged data from fifo */
- Amd7930_empty_Dfifo(cs, 1);
-
- if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
- del_timer(&cs->dbusytimer);
- if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
- schedule_event(cs, D_CLEARBUSY);
- /* restart TX-Frame */
- if (cs->tx_skb) {
- skb_push(cs->tx_skb, cs->tx_cnt);
- cs->tx_cnt = 0;
- cs->dc.amd7930.tx_xmtlen = 0;
- Amd7930_fill_Dfifo(cs);
- }
- }
-
- /* D TX FIFO empty -> fill */
- if (irflags & 1) {
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "Amd7930: interrupt: clear Timer and fill D-TX-FIFO if data");
-
- /* AMD interrupts off */
- AmdIrqOff(cs);
-
- if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
- del_timer(&cs->dbusytimer);
- if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
- schedule_event(cs, D_CLEARBUSY);
- if (cs->tx_skb) {
- if (cs->tx_skb->len)
- Amd7930_fill_Dfifo(cs);
- }
- /* AMD interrupts on */
- AmdIrqOn(cs);
- }
-
-
- /* D RX FIFO full or tiny packet in Fifo -> empty */
- if ((irflags & 2) || (dsr1 & 2)) {
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "Amd7930: interrupt: empty D-FIFO");
- Amd7930_empty_Dfifo(cs, 0);
- }
-
-
- /* D-Frame transmit complete */
- if (dsr1 & 64) {
- if (cs->debug & L1_DEB_ISAC) {
- debugl1(cs, "Amd7930: interrupt: transmit packet ready");
- }
- /* AMD interrupts off */
- AmdIrqOff(cs);
-
- if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
- del_timer(&cs->dbusytimer);
- if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
- schedule_event(cs, D_CLEARBUSY);
-
- if (cs->tx_skb) {
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "Amd7930: interrupt: TX-Packet ready, freeing skb");
- dev_kfree_skb_irq(cs->tx_skb);
- cs->tx_cnt = 0;
- cs->dc.amd7930.tx_xmtlen = 0;
- cs->tx_skb = NULL;
- }
- if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "Amd7930: interrupt: TX-Packet ready, next packet dequeued");
- cs->tx_cnt = 0;
- cs->dc.amd7930.tx_xmtlen = 0;
- Amd7930_fill_Dfifo(cs);
- }
- else
- schedule_event(cs, D_XMTBUFREADY);
- /* AMD interrupts on */
- AmdIrqOn(cs);
- }
-
- /* LIU status interrupt -> read LSR, check statechanges */
- if (lsr & 0x38) {
- /* AMD interrupts off */
- AmdIrqOff(cs);
-
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "Amd: interrupt: LSR=0x%02X, LIU is in state %d", lsr, ((lsr & 0x7) + 2));
-
- cs->dc.amd7930.ph_state = (lsr & 0x7) + 2;
-
- schedule_event(cs, D_L1STATECHANGE);
- /* AMD interrupts on */
- AmdIrqOn(cs);
- }
-
- /* reads Interrupt-Register again. If there is a new interrupt-flag: restart handler */
- irflags = rByteAMD(cs, 0x00);
- }
-
-}
-
-static void
-Amd7930_l1hw(struct PStack *st, int pr, void *arg)
-{
- struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
- struct sk_buff *skb = arg;
- u_long flags;
-
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "Amd7930: l1hw called, pr: 0x%04X", pr);
-
- switch (pr) {
- case (PH_DATA | REQUEST):
- if (cs->debug & DEB_DLOG_HEX)
- LogFrame(cs, skb->data, skb->len);
- if (cs->debug & DEB_DLOG_VERBOSE)
- dlogframe(cs, skb, 0);
- spin_lock_irqsave(&cs->lock, flags);
- if (cs->tx_skb) {
- skb_queue_tail(&cs->sq, skb);
-#ifdef L2FRAME_DEBUG /* psa */
- if (cs->debug & L1_DEB_LAPD)
- Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA Queued", 0);
-#endif
- } else {
- cs->tx_skb = skb;
- cs->tx_cnt = 0;
- cs->dc.amd7930.tx_xmtlen = 0;
-#ifdef L2FRAME_DEBUG /* psa */
- if (cs->debug & L1_DEB_LAPD)
- Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA", 0);
-#endif
- Amd7930_fill_Dfifo(cs);
- }
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (PH_PULL | INDICATION):
- spin_lock_irqsave(&cs->lock, flags);
- if (cs->tx_skb) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "Amd7930: l1hw: l2l1 tx_skb exist this shouldn't happen");
- skb_queue_tail(&cs->sq, skb);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- }
- if (cs->debug & DEB_DLOG_HEX)
- LogFrame(cs, skb->data, skb->len);
- if (cs->debug & DEB_DLOG_VERBOSE)
- dlogframe(cs, skb, 0);
- cs->tx_skb = skb;
- cs->tx_cnt = 0;
- cs->dc.amd7930.tx_xmtlen = 0;
-#ifdef L2FRAME_DEBUG /* psa */
- if (cs->debug & L1_DEB_LAPD)
- Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA_PULLED", 0);
-#endif
- Amd7930_fill_Dfifo(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (PH_PULL | REQUEST):
-#ifdef L2FRAME_DEBUG /* psa */
- if (cs->debug & L1_DEB_LAPD)
- debugl1(cs, "Amd7930: l1hw: -> PH_REQUEST_PULL, skb: %s", (cs->tx_skb) ? "yes" : "no");
-#endif
- if (!cs->tx_skb) {
- test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
- } else
- test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- break;
- case (HW_RESET | REQUEST):
- spin_lock_irqsave(&cs->lock, flags);
- if (cs->dc.amd7930.ph_state == 8) {
- /* b-channels off, PH-AR cleared
- * change to F3 */
- Amd7930_ph_command(cs, 0x20, "HW_RESET REQUEST"); //LMR1 bit 5
- spin_unlock_irqrestore(&cs->lock, flags);
- } else {
- Amd7930_ph_command(cs, 0x40, "HW_RESET REQUEST");
- cs->dc.amd7930.ph_state = 2;
- spin_unlock_irqrestore(&cs->lock, flags);
- Amd7930_new_ph(cs);
- }
- break;
- case (HW_ENABLE | REQUEST):
- cs->dc.amd7930.ph_state = 9;
- Amd7930_new_ph(cs);
- break;
- case (HW_INFO3 | REQUEST):
- // automatic
- break;
- case (HW_TESTLOOP | REQUEST):
- /* not implemented yet */
- break;
- case (HW_DEACTIVATE | RESPONSE):
- skb_queue_purge(&cs->rq);
- skb_queue_purge(&cs->sq);
- if (cs->tx_skb) {
- dev_kfree_skb(cs->tx_skb);
- cs->tx_skb = NULL;
- }
- if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
- del_timer(&cs->dbusytimer);
- if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
- schedule_event(cs, D_CLEARBUSY);
- break;
- default:
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "Amd7930: l1hw: unknown %04x", pr);
- break;
- }
-}
-
-static void
-setstack_Amd7930(struct PStack *st, struct IsdnCardState *cs)
-{
-
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "Amd7930: setstack called");
-
- st->l1.l1hw = Amd7930_l1hw;
-}
-
-
-static void
-DC_Close_Amd7930(struct IsdnCardState *cs) {
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "Amd7930: DC_Close called");
-}
-
-
-static void
-dbusy_timer_handler(struct timer_list *t)
-{
- struct IsdnCardState *cs = from_timer(cs, t, dbusytimer);
- u_long flags;
- struct PStack *stptr;
- WORD dtcr, der;
- BYTE dsr1, dsr2;
-
-
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "Amd7930: dbusy_timer expired!");
-
- if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
- spin_lock_irqsave(&cs->lock, flags);
- /* D Transmit Byte Count Register:
- * Counts down packet's number of Bytes, 0 if packet ready */
- dtcr = rWordAMD(cs, 0x85);
- dsr1 = rByteAMD(cs, 0x02);
- dsr2 = rByteAMD(cs, 0x07);
- der = rWordAMD(cs, 0x03);
-
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "Amd7930: dbusy_timer_handler: DSR1=0x%02X, DSR2=0x%02X, DER=0x%04X, cs->tx_skb->len=%u, tx_stat=%u, dtcr=%u, cs->tx_cnt=%u", dsr1, dsr2, der, cs->tx_skb->len, cs->dc.amd7930.tx_xmtlen, dtcr, cs->tx_cnt);
-
- if ((cs->dc.amd7930.tx_xmtlen - dtcr) < cs->tx_cnt) { /* D-Channel Busy */
- test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
- stptr = cs->stlist;
- spin_unlock_irqrestore(&cs->lock, flags);
- while (stptr != NULL) {
- stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
- stptr = stptr->next;
- }
-
- } else {
- /* discard frame; reset transceiver */
- test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
- if (cs->tx_skb) {
- dev_kfree_skb_any(cs->tx_skb);
- cs->tx_cnt = 0;
- cs->tx_skb = NULL;
- cs->dc.amd7930.tx_xmtlen = 0;
- } else {
- printk(KERN_WARNING "HiSax: Amd7930: D-Channel Busy no skb\n");
- debugl1(cs, "Amd7930: D-Channel Busy no skb");
-
- }
- /* Transmitter reset, abort transmit */
- wByteAMD(cs, 0x21, 0x82);
- wByteAMD(cs, 0x21, 0x02);
- spin_unlock_irqrestore(&cs->lock, flags);
- cs->irq_func(cs->irq, cs);
-
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "Amd7930: dbusy_timer_handler: Transmitter reset");
- }
- }
-}
-
-
-
-void Amd7930_init(struct IsdnCardState *cs)
-{
- WORD *ptr;
- BYTE cmd, cnt;
-
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "Amd7930: initamd called");
-
- cs->dc.amd7930.tx_xmtlen = 0;
- cs->dc.amd7930.old_state = 0;
- cs->dc.amd7930.lmr1 = 0x40;
- cs->dc.amd7930.ph_command = Amd7930_ph_command;
- cs->setstack_d = setstack_Amd7930;
- cs->DC_Close = DC_Close_Amd7930;
-
- /* AMD Initialisation */
- for (ptr = initAMD; *ptr != 0xFFFF; ) {
- cmd = LOBYTE(*ptr);
-
- /* read */
- if (*ptr++ >= 0x100) {
- if (cmd < 8)
- /* reset register */
- rByteAMD(cs, cmd);
- else {
- wByteAMD(cs, 0x00, cmd);
- for (cnt = *ptr++; cnt > 0; cnt--)
- rByteAMD(cs, 0x01);
- }
- }
- /* write */
- else if (cmd < 8)
- wByteAMD(cs, cmd, LOBYTE(*ptr++));
-
- else {
- wByteAMD(cs, 0x00, cmd);
- for (cnt = *ptr++; cnt > 0; cnt--)
- wByteAMD(cs, 0x01, LOBYTE(*ptr++));
- }
- }
-}
-
-void setup_Amd7930(struct IsdnCardState *cs)
-{
- INIT_WORK(&cs->tqueue, Amd7930_bh);
- timer_setup(&cs->dbusytimer, dbusy_timer_handler, 0);
-}
diff --git a/drivers/isdn/hisax/amd7930_fn.h b/drivers/isdn/hisax/amd7930_fn.h
deleted file mode 100644
index 1f4d80c5e5a6..000000000000
--- a/drivers/isdn/hisax/amd7930_fn.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* drivers/isdn/hisax/amd7930_fn.h
- *
- * gerdes_amd7930.h Header-file included by
- * gerdes_amd7930.c
- *
- * Author Christoph Ersfeld <info@formula-n.de>
- * Formula-n Europe AG (www.formula-n.com)
- * previously Gerdes AG
- *
- *
- * This file is (c) under GNU PUBLIC LICENSE
- */
-
-
-
-
-#define BYTE unsigned char
-#define WORD unsigned int
-#define rByteAMD(cs, reg) cs->readisac(cs, reg)
-#define wByteAMD(cs, reg, val) cs->writeisac(cs, reg, val)
-#define rWordAMD(cs, reg) ReadWordAmd7930(cs, reg)
-#define wWordAMD(cs, reg, val) WriteWordAmd7930(cs, reg, val)
-#define HIBYTE(w) ((unsigned char)((w & 0xff00) / 256))
-#define LOBYTE(w) ((unsigned char)(w & 0x00ff))
-
-#define AmdIrqOff(cs) cs->dc.amd7930.setIrqMask(cs, 0)
-#define AmdIrqOn(cs) cs->dc.amd7930.setIrqMask(cs, 1)
-
-#define AMD_CR 0x00
-#define AMD_DR 0x01
-
-
-#define DBUSY_TIMER_VALUE 80
-
-extern void Amd7930_interrupt(struct IsdnCardState *, unsigned char);
-extern void Amd7930_init(struct IsdnCardState *);
-extern void setup_Amd7930(struct IsdnCardState *);
diff --git a/drivers/isdn/hisax/arcofi.c b/drivers/isdn/hisax/arcofi.c
deleted file mode 100644
index 2f784f96d439..000000000000
--- a/drivers/isdn/hisax/arcofi.c
+++ /dev/null
@@ -1,131 +0,0 @@
-/* $Id: arcofi.c,v 1.14.2.3 2004/01/13 14:31:24 keil Exp $
- *
- * Ansteuerung ARCOFI 2165
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/sched.h>
-#include "hisax.h"
-#include "isdnl1.h"
-#include "isac.h"
-#include "arcofi.h"
-
-#define ARCOFI_TIMER_VALUE 20
-
-static void
-add_arcofi_timer(struct IsdnCardState *cs) {
- if (test_and_set_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) {
- del_timer(&cs->dc.isac.arcofitimer);
- }
- cs->dc.isac.arcofitimer.expires = jiffies + ((ARCOFI_TIMER_VALUE * HZ) / 1000);
- add_timer(&cs->dc.isac.arcofitimer);
-}
-
-static void
-send_arcofi(struct IsdnCardState *cs) {
- add_arcofi_timer(cs);
- cs->dc.isac.mon_txp = 0;
- cs->dc.isac.mon_txc = cs->dc.isac.arcofi_list->len;
- memcpy(cs->dc.isac.mon_tx, cs->dc.isac.arcofi_list->msg, cs->dc.isac.mon_txc);
- switch (cs->dc.isac.arcofi_bc) {
- case 0: break;
- case 1: cs->dc.isac.mon_tx[1] |= 0x40;
- break;
- default: break;
- }
- cs->dc.isac.mocr &= 0x0f;
- cs->dc.isac.mocr |= 0xa0;
- cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
- (void) cs->readisac(cs, ISAC_MOSR);
- cs->writeisac(cs, ISAC_MOX1, cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]);
- cs->dc.isac.mocr |= 0x10;
- cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
-}
-
-int
-arcofi_fsm(struct IsdnCardState *cs, int event, void *data) {
- if (cs->debug & L1_DEB_MONITOR) {
- debugl1(cs, "arcofi state %d event %d", cs->dc.isac.arcofi_state, event);
- }
- if (event == ARCOFI_TIMEOUT) {
- cs->dc.isac.arcofi_state = ARCOFI_NOP;
- test_and_set_bit(FLG_ARCOFI_ERROR, &cs->HW_Flags);
- wake_up(&cs->dc.isac.arcofi_wait);
- return (1);
- }
- switch (cs->dc.isac.arcofi_state) {
- case ARCOFI_NOP:
- if (event == ARCOFI_START) {
- cs->dc.isac.arcofi_list = data;
- cs->dc.isac.arcofi_state = ARCOFI_TRANSMIT;
- send_arcofi(cs);
- }
- break;
- case ARCOFI_TRANSMIT:
- if (event == ARCOFI_TX_END) {
- if (cs->dc.isac.arcofi_list->receive) {
- add_arcofi_timer(cs);
- cs->dc.isac.arcofi_state = ARCOFI_RECEIVE;
- } else {
- if (cs->dc.isac.arcofi_list->next) {
- cs->dc.isac.arcofi_list =
- cs->dc.isac.arcofi_list->next;
- send_arcofi(cs);
- } else {
- if (test_and_clear_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) {
- del_timer(&cs->dc.isac.arcofitimer);
- }
- cs->dc.isac.arcofi_state = ARCOFI_NOP;
- wake_up(&cs->dc.isac.arcofi_wait);
- }
- }
- }
- break;
- case ARCOFI_RECEIVE:
- if (event == ARCOFI_RX_END) {
- if (cs->dc.isac.arcofi_list->next) {
- cs->dc.isac.arcofi_list =
- cs->dc.isac.arcofi_list->next;
- cs->dc.isac.arcofi_state = ARCOFI_TRANSMIT;
- send_arcofi(cs);
- } else {
- if (test_and_clear_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) {
- del_timer(&cs->dc.isac.arcofitimer);
- }
- cs->dc.isac.arcofi_state = ARCOFI_NOP;
- wake_up(&cs->dc.isac.arcofi_wait);
- }
- }
- break;
- default:
- debugl1(cs, "Arcofi unknown state %x", cs->dc.isac.arcofi_state);
- return (2);
- }
- return (0);
-}
-
-static void
-arcofi_timer(struct timer_list *t) {
- struct IsdnCardState *cs = from_timer(cs, t, dc.isac.arcofitimer);
- arcofi_fsm(cs, ARCOFI_TIMEOUT, NULL);
-}
-
-void
-clear_arcofi(struct IsdnCardState *cs) {
- if (test_and_clear_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) {
- del_timer(&cs->dc.isac.arcofitimer);
- }
-}
-
-void
-init_arcofi(struct IsdnCardState *cs) {
- timer_setup(&cs->dc.isac.arcofitimer, arcofi_timer, 0);
- init_waitqueue_head(&cs->dc.isac.arcofi_wait);
- test_and_set_bit(HW_ARCOFI, &cs->HW_Flags);
-}
diff --git a/drivers/isdn/hisax/arcofi.h b/drivers/isdn/hisax/arcofi.h
deleted file mode 100644
index b9c77529fabf..000000000000
--- a/drivers/isdn/hisax/arcofi.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* $Id: arcofi.h,v 1.6.6.2 2001/09/23 22:24:46 kai Exp $
- *
- * Ansteuerung ARCOFI 2165
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#define ARCOFI_USE 1
-
-/* states */
-#define ARCOFI_NOP 0
-#define ARCOFI_TRANSMIT 1
-#define ARCOFI_RECEIVE 2
-/* events */
-#define ARCOFI_START 1
-#define ARCOFI_TX_END 2
-#define ARCOFI_RX_END 3
-#define ARCOFI_TIMEOUT 4
-
-extern int arcofi_fsm(struct IsdnCardState *cs, int event, void *data);
-extern void init_arcofi(struct IsdnCardState *cs);
-extern void clear_arcofi(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/asuscom.c b/drivers/isdn/hisax/asuscom.c
deleted file mode 100644
index 74c871495e81..000000000000
--- a/drivers/isdn/hisax/asuscom.c
+++ /dev/null
@@ -1,423 +0,0 @@
-/* $Id: asuscom.c,v 1.14.2.4 2004/01/13 23:48:39 keil Exp $
- *
- * low level stuff for ASUSCOM NETWORK INC. ISDNLink cards
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Thanks to ASUSCOM NETWORK INC. Taiwan and Dynalink NL for information
- *
- */
-
-#include <linux/init.h>
-#include <linux/isapnp.h>
-#include "hisax.h"
-#include "isac.h"
-#include "ipac.h"
-#include "hscx.h"
-#include "isdnl1.h"
-
-static const char *Asuscom_revision = "$Revision: 1.14.2.4 $";
-
-#define byteout(addr, val) outb(val, addr)
-#define bytein(addr) inb(addr)
-
-#define ASUS_ISAC 0
-#define ASUS_HSCX 1
-#define ASUS_ADR 2
-#define ASUS_CTRL_U7 3
-#define ASUS_CTRL_POTS 5
-
-#define ASUS_IPAC_ALE 0
-#define ASUS_IPAC_DATA 1
-
-#define ASUS_ISACHSCX 1
-#define ASUS_IPAC 2
-
-/* CARD_ADR (Write) */
-#define ASUS_RESET 0x80 /* Bit 7 Reset-Leitung */
-
-static inline u_char
-readreg(unsigned int ale, unsigned int adr, u_char off)
-{
- register u_char ret;
-
- byteout(ale, off);
- ret = bytein(adr);
- return (ret);
-}
-
-static inline void
-readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
-{
- byteout(ale, off);
- insb(adr, data, size);
-}
-
-
-static inline void
-writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
-{
- byteout(ale, off);
- byteout(adr, data);
-}
-
-static inline void
-writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
-{
- byteout(ale, off);
- outsb(adr, data, size);
-}
-
-/* Interface functions */
-
-static u_char
-ReadISAC(struct IsdnCardState *cs, u_char offset)
-{
- return (readreg(cs->hw.asus.adr, cs->hw.asus.isac, offset));
-}
-
-static void
-WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
-{
- writereg(cs->hw.asus.adr, cs->hw.asus.isac, offset, value);
-}
-
-static void
-ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- readfifo(cs->hw.asus.adr, cs->hw.asus.isac, 0, data, size);
-}
-
-static void
-WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- writefifo(cs->hw.asus.adr, cs->hw.asus.isac, 0, data, size);
-}
-
-static u_char
-ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset)
-{
- return (readreg(cs->hw.asus.adr, cs->hw.asus.isac, offset | 0x80));
-}
-
-static void
-WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value)
-{
- writereg(cs->hw.asus.adr, cs->hw.asus.isac, offset | 0x80, value);
-}
-
-static void
-ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size)
-{
- readfifo(cs->hw.asus.adr, cs->hw.asus.isac, 0x80, data, size);
-}
-
-static void
-WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size)
-{
- writefifo(cs->hw.asus.adr, cs->hw.asus.isac, 0x80, data, size);
-}
-
-static u_char
-ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
-{
- return (readreg(cs->hw.asus.adr,
- cs->hw.asus.hscx, offset + (hscx ? 0x40 : 0)));
-}
-
-static void
-WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
-{
- writereg(cs->hw.asus.adr,
- cs->hw.asus.hscx, offset + (hscx ? 0x40 : 0), value);
-}
-
-/*
- * fast interrupt HSCX stuff goes here
- */
-
-#define READHSCX(cs, nr, reg) readreg(cs->hw.asus.adr, \
- cs->hw.asus.hscx, reg + (nr ? 0x40 : 0))
-#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.asus.adr, \
- cs->hw.asus.hscx, reg + (nr ? 0x40 : 0), data)
-
-#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.asus.adr, \
- cs->hw.asus.hscx, (nr ? 0x40 : 0), ptr, cnt)
-
-#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.asus.adr, \
- cs->hw.asus.hscx, (nr ? 0x40 : 0), ptr, cnt)
-
-#include "hscx_irq.c"
-
-static irqreturn_t
-asuscom_interrupt(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_char val;
- u_long flags;
-
- spin_lock_irqsave(&cs->lock, flags);
- val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40);
-Start_HSCX:
- if (val)
- hscx_int_main(cs, val);
- val = readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA);
-Start_ISAC:
- if (val)
- isac_interrupt(cs, val);
- val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40);
- if (val) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "HSCX IntStat after IntRoutine");
- goto Start_HSCX;
- }
- val = readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA);
- if (val) {
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ISAC IntStat after IntRoutine");
- goto Start_ISAC;
- }
- writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK, 0xFF);
- writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK + 0x40, 0xFF);
- writereg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_MASK, 0xFF);
- writereg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_MASK, 0x0);
- writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK, 0x0);
- writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK + 0x40, 0x0);
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static irqreturn_t
-asuscom_interrupt_ipac(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_char ista, val, icnt = 5;
- u_long flags;
-
- spin_lock_irqsave(&cs->lock, flags);
- ista = readreg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ISTA);
-Start_IPAC:
- if (cs->debug & L1_DEB_IPAC)
- debugl1(cs, "IPAC ISTA %02X", ista);
- if (ista & 0x0f) {
- val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40);
- if (ista & 0x01)
- val |= 0x01;
- if (ista & 0x04)
- val |= 0x02;
- if (ista & 0x08)
- val |= 0x04;
- if (val)
- hscx_int_main(cs, val);
- }
- if (ista & 0x20) {
- val = 0xfe & readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA | 0x80);
- if (val) {
- isac_interrupt(cs, val);
- }
- }
- if (ista & 0x10) {
- val = 0x01;
- isac_interrupt(cs, val);
- }
- ista = readreg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ISTA);
- if ((ista & 0x3f) && icnt) {
- icnt--;
- goto Start_IPAC;
- }
- if (!icnt)
- printk(KERN_WARNING "ASUS IRQ LOOP\n");
- writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xFF);
- writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xC0);
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static void
-release_io_asuscom(struct IsdnCardState *cs)
-{
- int bytecnt = 8;
-
- if (cs->hw.asus.cfg_reg)
- release_region(cs->hw.asus.cfg_reg, bytecnt);
-}
-
-static void
-reset_asuscom(struct IsdnCardState *cs)
-{
- if (cs->subtyp == ASUS_IPAC)
- writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x20);
- else
- byteout(cs->hw.asus.adr, ASUS_RESET); /* Reset On */
- mdelay(10);
- if (cs->subtyp == ASUS_IPAC)
- writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x0);
- else
- byteout(cs->hw.asus.adr, 0); /* Reset Off */
- mdelay(10);
- if (cs->subtyp == ASUS_IPAC) {
- writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_CONF, 0x0);
- writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ACFG, 0xff);
- writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_AOE, 0x0);
- writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xc0);
- writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_PCFG, 0x12);
- }
-}
-
-static int
-Asus_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
- u_long flags;
-
- switch (mt) {
- case CARD_RESET:
- spin_lock_irqsave(&cs->lock, flags);
- reset_asuscom(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_RELEASE:
- release_io_asuscom(cs);
- return (0);
- case CARD_INIT:
- spin_lock_irqsave(&cs->lock, flags);
- cs->debug |= L1_DEB_IPAC;
- inithscxisac(cs, 3);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_TEST:
- return (0);
- }
- return (0);
-}
-
-#ifdef __ISAPNP__
-static struct isapnp_device_id asus_ids[] = {
- { ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688),
- ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688),
- (unsigned long) "Asus1688 PnP" },
- { ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1690),
- ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1690),
- (unsigned long) "Asus1690 PnP" },
- { ISAPNP_VENDOR('S', 'I', 'E'), ISAPNP_FUNCTION(0x0020),
- ISAPNP_VENDOR('S', 'I', 'E'), ISAPNP_FUNCTION(0x0020),
- (unsigned long) "Isurf2 PnP" },
- { ISAPNP_VENDOR('E', 'L', 'F'), ISAPNP_FUNCTION(0x0000),
- ISAPNP_VENDOR('E', 'L', 'F'), ISAPNP_FUNCTION(0x0000),
- (unsigned long) "Iscas TE320" },
- { 0, }
-};
-
-static struct isapnp_device_id *ipid = &asus_ids[0];
-static struct pnp_card *pnp_c = NULL;
-#endif
-
-int setup_asuscom(struct IsdnCard *card)
-{
- int bytecnt;
- struct IsdnCardState *cs = card->cs;
- u_char val;
- char tmp[64];
-
- strcpy(tmp, Asuscom_revision);
- printk(KERN_INFO "HiSax: Asuscom ISDNLink driver Rev. %s\n", HiSax_getrev(tmp));
- if (cs->typ != ISDN_CTYPE_ASUSCOM)
- return (0);
-#ifdef __ISAPNP__
- if (!card->para[1] && isapnp_present()) {
- struct pnp_dev *pnp_d;
- while (ipid->card_vendor) {
- if ((pnp_c = pnp_find_card(ipid->card_vendor,
- ipid->card_device, pnp_c))) {
- pnp_d = NULL;
- if ((pnp_d = pnp_find_dev(pnp_c,
- ipid->vendor, ipid->function, pnp_d))) {
- int err;
-
- printk(KERN_INFO "HiSax: %s detected\n",
- (char *)ipid->driver_data);
- pnp_disable_dev(pnp_d);
- err = pnp_activate_dev(pnp_d);
- if (err < 0) {
- printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __func__, err);
- return (0);
- }
- card->para[1] = pnp_port_start(pnp_d, 0);
- card->para[0] = pnp_irq(pnp_d, 0);
- if (card->para[0] == -1 || !card->para[1]) {
- printk(KERN_ERR "AsusPnP:some resources are missing %ld/%lx\n",
- card->para[0], card->para[1]);
- pnp_disable_dev(pnp_d);
- return (0);
- }
- break;
- } else {
- printk(KERN_ERR "AsusPnP: PnP error card found, no device\n");
- }
- }
- ipid++;
- pnp_c = NULL;
- }
- if (!ipid->card_vendor) {
- printk(KERN_INFO "AsusPnP: no ISAPnP card found\n");
- return (0);
- }
- }
-#endif
- bytecnt = 8;
- cs->hw.asus.cfg_reg = card->para[1];
- cs->irq = card->para[0];
- if (!request_region(cs->hw.asus.cfg_reg, bytecnt, "asuscom isdn")) {
- printk(KERN_WARNING
- "HiSax: ISDNLink config port %x-%x already in use\n",
- cs->hw.asus.cfg_reg,
- cs->hw.asus.cfg_reg + bytecnt);
- return (0);
- }
- printk(KERN_INFO "ISDNLink: defined at 0x%x IRQ %d\n",
- cs->hw.asus.cfg_reg, cs->irq);
- setup_isac(cs);
- cs->BC_Read_Reg = &ReadHSCX;
- cs->BC_Write_Reg = &WriteHSCX;
- cs->BC_Send_Data = &hscx_fill_fifo;
- cs->cardmsg = &Asus_card_msg;
- val = readreg(cs->hw.asus.cfg_reg + ASUS_IPAC_ALE,
- cs->hw.asus.cfg_reg + ASUS_IPAC_DATA, IPAC_ID);
- if ((val == 1) || (val == 2)) {
- cs->subtyp = ASUS_IPAC;
- cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_IPAC_ALE;
- cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_IPAC_DATA;
- cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_IPAC_DATA;
- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
- cs->readisac = &ReadISAC_IPAC;
- cs->writeisac = &WriteISAC_IPAC;
- cs->readisacfifo = &ReadISACfifo_IPAC;
- cs->writeisacfifo = &WriteISACfifo_IPAC;
- cs->irq_func = &asuscom_interrupt_ipac;
- printk(KERN_INFO "Asus: IPAC version %x\n", val);
- } else {
- cs->subtyp = ASUS_ISACHSCX;
- cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_ADR;
- cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_ISAC;
- cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_HSCX;
- cs->hw.asus.u7 = cs->hw.asus.cfg_reg + ASUS_CTRL_U7;
- cs->hw.asus.pots = cs->hw.asus.cfg_reg + ASUS_CTRL_POTS;
- cs->readisac = &ReadISAC;
- cs->writeisac = &WriteISAC;
- cs->readisacfifo = &ReadISACfifo;
- cs->writeisacfifo = &WriteISACfifo;
- cs->irq_func = &asuscom_interrupt;
- ISACVersion(cs, "ISDNLink:");
- if (HscxVersion(cs, "ISDNLink:")) {
- printk(KERN_WARNING
- "ISDNLink: wrong HSCX versions check IO address\n");
- release_io_asuscom(cs);
- return (0);
- }
- }
- return (1);
-}
diff --git a/drivers/isdn/hisax/avm_a1.c b/drivers/isdn/hisax/avm_a1.c
deleted file mode 100644
index 7dd74087ad72..000000000000
--- a/drivers/isdn/hisax/avm_a1.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/* $Id: avm_a1.c,v 2.15.2.4 2004/01/13 21:46:03 keil Exp $
- *
- * low level stuff for AVM A1 (Fritz) isdn cards
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/init.h>
-#include "hisax.h"
-#include "isac.h"
-#include "hscx.h"
-#include "isdnl1.h"
-
-static const char *avm_revision = "$Revision: 2.15.2.4 $";
-
-#define AVM_A1_STAT_ISAC 0x01
-#define AVM_A1_STAT_HSCX 0x02
-#define AVM_A1_STAT_TIMER 0x04
-
-#define byteout(addr, val) outb(val, addr)
-#define bytein(addr) inb(addr)
-
-static inline u_char
-readreg(unsigned int adr, u_char off)
-{
- return (bytein(adr + off));
-}
-
-static inline void
-writereg(unsigned int adr, u_char off, u_char data)
-{
- byteout(adr + off, data);
-}
-
-
-static inline void
-read_fifo(unsigned int adr, u_char *data, int size)
-{
- insb(adr, data, size);
-}
-
-static void
-write_fifo(unsigned int adr, u_char *data, int size)
-{
- outsb(adr, data, size);
-}
-
-/* Interface functions */
-
-static u_char
-ReadISAC(struct IsdnCardState *cs, u_char offset)
-{
- return (readreg(cs->hw.avm.isac, offset));
-}
-
-static void
-WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
-{
- writereg(cs->hw.avm.isac, offset, value);
-}
-
-static void
-ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- read_fifo(cs->hw.avm.isacfifo, data, size);
-}
-
-static void
-WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- write_fifo(cs->hw.avm.isacfifo, data, size);
-}
-
-static u_char
-ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
-{
- return (readreg(cs->hw.avm.hscx[hscx], offset));
-}
-
-static void
-WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
-{
- writereg(cs->hw.avm.hscx[hscx], offset, value);
-}
-
-/*
- * fast interrupt HSCX stuff goes here
- */
-
-#define READHSCX(cs, nr, reg) readreg(cs->hw.avm.hscx[nr], reg)
-#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.avm.hscx[nr], reg, data)
-#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.avm.hscxfifo[nr], ptr, cnt)
-#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.avm.hscxfifo[nr], ptr, cnt)
-
-#include "hscx_irq.c"
-
-static irqreturn_t
-avm_a1_interrupt(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_char val, sval;
- u_long flags;
-
- spin_lock_irqsave(&cs->lock, flags);
- while (((sval = bytein(cs->hw.avm.cfg_reg)) & 0xf) != 0x7) {
- if (!(sval & AVM_A1_STAT_TIMER)) {
- byteout(cs->hw.avm.cfg_reg, 0x1E);
- sval = bytein(cs->hw.avm.cfg_reg);
- } else if (cs->debug & L1_DEB_INTSTAT)
- debugl1(cs, "avm IntStatus %x", sval);
- if (!(sval & AVM_A1_STAT_HSCX)) {
- val = readreg(cs->hw.avm.hscx[1], HSCX_ISTA);
- if (val)
- hscx_int_main(cs, val);
- }
- if (!(sval & AVM_A1_STAT_ISAC)) {
- val = readreg(cs->hw.avm.isac, ISAC_ISTA);
- if (val)
- isac_interrupt(cs, val);
- }
- }
- writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0xFF);
- writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0xFF);
- writereg(cs->hw.avm.isac, ISAC_MASK, 0xFF);
- writereg(cs->hw.avm.isac, ISAC_MASK, 0x0);
- writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0x0);
- writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0x0);
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static inline void
-release_ioregs(struct IsdnCardState *cs, int mask)
-{
- release_region(cs->hw.avm.cfg_reg, 8);
- if (mask & 1)
- release_region(cs->hw.avm.isac + 32, 32);
- if (mask & 2)
- release_region(cs->hw.avm.isacfifo, 1);
- if (mask & 4)
- release_region(cs->hw.avm.hscx[0] + 32, 32);
- if (mask & 8)
- release_region(cs->hw.avm.hscxfifo[0], 1);
- if (mask & 0x10)
- release_region(cs->hw.avm.hscx[1] + 32, 32);
- if (mask & 0x20)
- release_region(cs->hw.avm.hscxfifo[1], 1);
-}
-
-static int
-AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
- u_long flags;
-
- switch (mt) {
- case CARD_RESET:
- return (0);
- case CARD_RELEASE:
- release_ioregs(cs, 0x3f);
- return (0);
- case CARD_INIT:
- spin_lock_irqsave(&cs->lock, flags);
- inithscxisac(cs, 1);
- byteout(cs->hw.avm.cfg_reg, 0x16);
- byteout(cs->hw.avm.cfg_reg, 0x1E);
- inithscxisac(cs, 2);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_TEST:
- return (0);
- }
- return (0);
-}
-
-int setup_avm_a1(struct IsdnCard *card)
-{
- u_char val;
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
-
- strcpy(tmp, avm_revision);
- printk(KERN_INFO "HiSax: AVM driver Rev. %s\n", HiSax_getrev(tmp));
- if (cs->typ != ISDN_CTYPE_A1)
- return (0);
-
- cs->hw.avm.cfg_reg = card->para[1] + 0x1800;
- cs->hw.avm.isac = card->para[1] + 0x1400 - 0x20;
- cs->hw.avm.hscx[0] = card->para[1] + 0x400 - 0x20;
- cs->hw.avm.hscx[1] = card->para[1] + 0xc00 - 0x20;
- cs->hw.avm.isacfifo = card->para[1] + 0x1000;
- cs->hw.avm.hscxfifo[0] = card->para[1];
- cs->hw.avm.hscxfifo[1] = card->para[1] + 0x800;
- cs->irq = card->para[0];
- if (!request_region(cs->hw.avm.cfg_reg, 8, "avm cfg")) {
- printk(KERN_WARNING
- "HiSax: AVM A1 config port %x-%x already in use\n",
- cs->hw.avm.cfg_reg,
- cs->hw.avm.cfg_reg + 8);
- return (0);
- }
- if (!request_region(cs->hw.avm.isac + 32, 32, "HiSax isac")) {
- printk(KERN_WARNING
- "HiSax: AVM A1 isac ports %x-%x already in use\n",
- cs->hw.avm.isac + 32,
- cs->hw.avm.isac + 64);
- release_ioregs(cs, 0);
- return (0);
- }
- if (!request_region(cs->hw.avm.isacfifo, 1, "HiSax isac fifo")) {
- printk(KERN_WARNING
- "HiSax: AVM A1 isac fifo port %x already in use\n",
- cs->hw.avm.isacfifo);
- release_ioregs(cs, 1);
- return (0);
- }
- if (!request_region(cs->hw.avm.hscx[0] + 32, 32, "HiSax hscx A")) {
- printk(KERN_WARNING
- "HiSax: AVM A1 hscx A ports %x-%x already in use\n",
- cs->hw.avm.hscx[0] + 32,
- cs->hw.avm.hscx[0] + 64);
- release_ioregs(cs, 3);
- return (0);
- }
- if (!request_region(cs->hw.avm.hscxfifo[0], 1, "HiSax hscx A fifo")) {
- printk(KERN_WARNING
- "HiSax: AVM A1 hscx A fifo port %x already in use\n",
- cs->hw.avm.hscxfifo[0]);
- release_ioregs(cs, 7);
- return (0);
- }
- if (!request_region(cs->hw.avm.hscx[1] + 32, 32, "HiSax hscx B")) {
- printk(KERN_WARNING
- "HiSax: AVM A1 hscx B ports %x-%x already in use\n",
- cs->hw.avm.hscx[1] + 32,
- cs->hw.avm.hscx[1] + 64);
- release_ioregs(cs, 0xf);
- return (0);
- }
- if (!request_region(cs->hw.avm.hscxfifo[1], 1, "HiSax hscx B fifo")) {
- printk(KERN_WARNING
- "HiSax: AVM A1 hscx B fifo port %x already in use\n",
- cs->hw.avm.hscxfifo[1]);
- release_ioregs(cs, 0x1f);
- return (0);
- }
- byteout(cs->hw.avm.cfg_reg, 0x0);
- HZDELAY(HZ / 5 + 1);
- byteout(cs->hw.avm.cfg_reg, 0x1);
- HZDELAY(HZ / 5 + 1);
- byteout(cs->hw.avm.cfg_reg, 0x0);
- HZDELAY(HZ / 5 + 1);
- val = cs->irq;
- if (val == 9)
- val = 2;
- byteout(cs->hw.avm.cfg_reg + 1, val);
- HZDELAY(HZ / 5 + 1);
- byteout(cs->hw.avm.cfg_reg, 0x0);
- HZDELAY(HZ / 5 + 1);
-
- val = bytein(cs->hw.avm.cfg_reg);
- printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
- cs->hw.avm.cfg_reg, val);
- val = bytein(cs->hw.avm.cfg_reg + 3);
- printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
- cs->hw.avm.cfg_reg + 3, val);
- val = bytein(cs->hw.avm.cfg_reg + 2);
- printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
- cs->hw.avm.cfg_reg + 2, val);
- val = bytein(cs->hw.avm.cfg_reg);
- printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
- cs->hw.avm.cfg_reg, val);
-
- printk(KERN_INFO "HiSax: AVM A1 config irq:%d cfg:0x%X\n",
- cs->irq,
- cs->hw.avm.cfg_reg);
- printk(KERN_INFO
- "HiSax: isac:0x%X/0x%X\n",
- cs->hw.avm.isac + 32, cs->hw.avm.isacfifo);
- printk(KERN_INFO
- "HiSax: hscx A:0x%X/0x%X hscx B:0x%X/0x%X\n",
- cs->hw.avm.hscx[0] + 32, cs->hw.avm.hscxfifo[0],
- cs->hw.avm.hscx[1] + 32, cs->hw.avm.hscxfifo[1]);
-
- cs->readisac = &ReadISAC;
- cs->writeisac = &WriteISAC;
- cs->readisacfifo = &ReadISACfifo;
- cs->writeisacfifo = &WriteISACfifo;
- cs->BC_Read_Reg = &ReadHSCX;
- cs->BC_Write_Reg = &WriteHSCX;
- cs->BC_Send_Data = &hscx_fill_fifo;
- setup_isac(cs);
- cs->cardmsg = &AVM_card_msg;
- cs->irq_func = &avm_a1_interrupt;
- ISACVersion(cs, "AVM A1:");
- if (HscxVersion(cs, "AVM A1:")) {
- printk(KERN_WARNING
- "AVM A1: wrong HSCX versions check IO address\n");
- release_ioregs(cs, 0x3f);
- return (0);
- }
- return (1);
-}
diff --git a/drivers/isdn/hisax/avm_a1p.c b/drivers/isdn/hisax/avm_a1p.c
deleted file mode 100644
index bc52d54ff5e1..000000000000
--- a/drivers/isdn/hisax/avm_a1p.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/* $Id: avm_a1p.c,v 2.9.2.5 2004/01/24 20:47:19 keil Exp $
- *
- * low level stuff for the following AVM cards:
- * A1 PCMCIA
- * FRITZ!Card PCMCIA
- * FRITZ!Card PCMCIA 2.0
- *
- * Author Carsten Paeth
- * Copyright by Carsten Paeth <calle@calle.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/init.h>
-#include "hisax.h"
-#include "isac.h"
-#include "hscx.h"
-#include "isdnl1.h"
-
-/* register offsets */
-#define ADDRREG_OFFSET 0x02
-#define DATAREG_OFFSET 0x03
-#define ASL0_OFFSET 0x04
-#define ASL1_OFFSET 0x05
-#define MODREG_OFFSET 0x06
-#define VERREG_OFFSET 0x07
-
-/* address offsets */
-#define ISAC_FIFO_OFFSET 0x00
-#define ISAC_REG_OFFSET 0x20
-#define HSCX_CH_DIFF 0x40
-#define HSCX_FIFO_OFFSET 0x80
-#define HSCX_REG_OFFSET 0xa0
-
-/* read bits ASL0 */
-#define ASL0_R_TIMER 0x10 /* active low */
-#define ASL0_R_ISAC 0x20 /* active low */
-#define ASL0_R_HSCX 0x40 /* active low */
-#define ASL0_R_TESTBIT 0x80
-#define ASL0_R_IRQPENDING (ASL0_R_ISAC | ASL0_R_HSCX | ASL0_R_TIMER)
-
-/* write bits ASL0 */
-#define ASL0_W_RESET 0x01
-#define ASL0_W_TDISABLE 0x02
-#define ASL0_W_TRESET 0x04
-#define ASL0_W_IRQENABLE 0x08
-#define ASL0_W_TESTBIT 0x80
-
-/* write bits ASL1 */
-#define ASL1_W_LED0 0x10
-#define ASL1_W_LED1 0x20
-#define ASL1_W_ENABLE_S0 0xC0
-
-#define byteout(addr, val) outb(val, addr)
-#define bytein(addr) inb(addr)
-
-static const char *avm_revision = "$Revision: 2.9.2.5 $";
-
-static inline u_char
-ReadISAC(struct IsdnCardState *cs, u_char offset)
-{
- u_char ret;
-
- offset -= 0x20;
- byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, ISAC_REG_OFFSET + offset);
- ret = bytein(cs->hw.avm.cfg_reg + DATAREG_OFFSET);
- return ret;
-}
-
-static inline void
-WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
-{
- offset -= 0x20;
- byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, ISAC_REG_OFFSET + offset);
- byteout(cs->hw.avm.cfg_reg + DATAREG_OFFSET, value);
-}
-
-static inline void
-ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, ISAC_FIFO_OFFSET);
- insb(cs->hw.avm.cfg_reg + DATAREG_OFFSET, data, size);
-}
-
-static inline void
-WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, ISAC_FIFO_OFFSET);
- outsb(cs->hw.avm.cfg_reg + DATAREG_OFFSET, data, size);
-}
-
-static inline u_char
-ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
-{
- u_char ret;
-
- offset -= 0x20;
- byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET,
- HSCX_REG_OFFSET + hscx * HSCX_CH_DIFF + offset);
- ret = bytein(cs->hw.avm.cfg_reg + DATAREG_OFFSET);
- return ret;
-}
-
-static inline void
-WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
-{
- offset -= 0x20;
- byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET,
- HSCX_REG_OFFSET + hscx * HSCX_CH_DIFF + offset);
- byteout(cs->hw.avm.cfg_reg + DATAREG_OFFSET, value);
-}
-
-static inline void
-ReadHSCXfifo(struct IsdnCardState *cs, int hscx, u_char *data, int size)
-{
- byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET,
- HSCX_FIFO_OFFSET + hscx * HSCX_CH_DIFF);
- insb(cs->hw.avm.cfg_reg + DATAREG_OFFSET, data, size);
-}
-
-static inline void
-WriteHSCXfifo(struct IsdnCardState *cs, int hscx, u_char *data, int size)
-{
- byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET,
- HSCX_FIFO_OFFSET + hscx * HSCX_CH_DIFF);
- outsb(cs->hw.avm.cfg_reg + DATAREG_OFFSET, data, size);
-}
-
-/*
- * fast interrupt HSCX stuff goes here
- */
-
-#define READHSCX(cs, nr, reg) ReadHSCX(cs, nr, reg)
-#define WRITEHSCX(cs, nr, reg, data) WriteHSCX(cs, nr, reg, data)
-#define READHSCXFIFO(cs, nr, ptr, cnt) ReadHSCXfifo(cs, nr, ptr, cnt)
-#define WRITEHSCXFIFO(cs, nr, ptr, cnt) WriteHSCXfifo(cs, nr, ptr, cnt)
-
-#include "hscx_irq.c"
-
-static irqreturn_t
-avm_a1p_interrupt(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_char val, sval;
- u_long flags;
-
- spin_lock_irqsave(&cs->lock, flags);
- while ((sval = (~bytein(cs->hw.avm.cfg_reg + ASL0_OFFSET) & ASL0_R_IRQPENDING))) {
- if (cs->debug & L1_DEB_INTSTAT)
- debugl1(cs, "avm IntStatus %x", sval);
- if (sval & ASL0_R_HSCX) {
- val = ReadHSCX(cs, 1, HSCX_ISTA);
- if (val)
- hscx_int_main(cs, val);
- }
- if (sval & ASL0_R_ISAC) {
- val = ReadISAC(cs, ISAC_ISTA);
- if (val)
- isac_interrupt(cs, val);
- }
- }
- WriteHSCX(cs, 0, HSCX_MASK, 0xff);
- WriteHSCX(cs, 1, HSCX_MASK, 0xff);
- WriteISAC(cs, ISAC_MASK, 0xff);
- WriteISAC(cs, ISAC_MASK, 0x00);
- WriteHSCX(cs, 0, HSCX_MASK, 0x00);
- WriteHSCX(cs, 1, HSCX_MASK, 0x00);
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static int
-AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
- u_long flags;
-
- switch (mt) {
- case CARD_RESET:
- spin_lock_irqsave(&cs->lock, flags);
- byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, 0x00);
- HZDELAY(HZ / 5 + 1);
- byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, ASL0_W_RESET);
- HZDELAY(HZ / 5 + 1);
- byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, 0x00);
- spin_unlock_irqrestore(&cs->lock, flags);
- return 0;
-
- case CARD_RELEASE:
- /* free_irq is done in HiSax_closecard(). */
- /* free_irq(cs->irq, cs); */
- return 0;
-
- case CARD_INIT:
- spin_lock_irqsave(&cs->lock, flags);
- byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, ASL0_W_TDISABLE | ASL0_W_TRESET | ASL0_W_IRQENABLE);
- clear_pending_isac_ints(cs);
- clear_pending_hscx_ints(cs);
- inithscxisac(cs, 1);
- inithscxisac(cs, 2);
- spin_unlock_irqrestore(&cs->lock, flags);
- return 0;
-
- case CARD_TEST:
- /* we really don't need it for the PCMCIA Version */
- return 0;
-
- default:
- /* all card drivers ignore others, so we do the same */
- return 0;
- }
- return 0;
-}
-
-int setup_avm_a1_pcmcia(struct IsdnCard *card)
-{
- u_char model, vers;
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
-
-
- strcpy(tmp, avm_revision);
- printk(KERN_INFO "HiSax: AVM A1 PCMCIA driver Rev. %s\n",
- HiSax_getrev(tmp));
- if (cs->typ != ISDN_CTYPE_A1_PCMCIA)
- return (0);
-
- cs->hw.avm.cfg_reg = card->para[1];
- cs->irq = card->para[0];
-
-
- byteout(cs->hw.avm.cfg_reg + ASL1_OFFSET, ASL1_W_ENABLE_S0);
- byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, 0x00);
- HZDELAY(HZ / 5 + 1);
- byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, ASL0_W_RESET);
- HZDELAY(HZ / 5 + 1);
- byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, 0x00);
-
- byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, ASL0_W_TDISABLE | ASL0_W_TRESET);
-
- model = bytein(cs->hw.avm.cfg_reg + MODREG_OFFSET);
- vers = bytein(cs->hw.avm.cfg_reg + VERREG_OFFSET);
-
- printk(KERN_INFO "AVM A1 PCMCIA: io 0x%x irq %d model %d version %d\n",
- cs->hw.avm.cfg_reg, cs->irq, model, vers);
-
- setup_isac(cs);
- cs->readisac = &ReadISAC;
- cs->writeisac = &WriteISAC;
- cs->readisacfifo = &ReadISACfifo;
- cs->writeisacfifo = &WriteISACfifo;
- cs->BC_Read_Reg = &ReadHSCX;
- cs->BC_Write_Reg = &WriteHSCX;
- cs->BC_Send_Data = &hscx_fill_fifo;
- cs->cardmsg = &AVM_card_msg;
- cs->irq_flags = IRQF_SHARED;
- cs->irq_func = &avm_a1p_interrupt;
-
- ISACVersion(cs, "AVM A1 PCMCIA:");
- if (HscxVersion(cs, "AVM A1 PCMCIA:")) {
- printk(KERN_WARNING
- "AVM A1 PCMCIA: wrong HSCX versions check IO address\n");
- return (0);
- }
- return (1);
-}
diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c
deleted file mode 100644
index b161456c942e..000000000000
--- a/drivers/isdn/hisax/avm_pci.c
+++ /dev/null
@@ -1,904 +0,0 @@
-/* $Id: avm_pci.c,v 1.29.2.4 2004/02/11 13:21:32 keil Exp $
- *
- * low level stuff for AVM Fritz!PCI and ISA PnP isdn cards
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Thanks to AVM, Berlin for information
- *
- */
-
-#include <linux/init.h>
-#include "hisax.h"
-#include "isac.h"
-#include "isdnl1.h"
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <linux/isapnp.h>
-#include <linux/interrupt.h>
-
-static const char *avm_pci_rev = "$Revision: 1.29.2.4 $";
-
-#define AVM_FRITZ_PCI 1
-#define AVM_FRITZ_PNP 2
-
-#define HDLC_FIFO 0x0
-#define HDLC_STATUS 0x4
-
-#define AVM_HDLC_1 0x00
-#define AVM_HDLC_2 0x01
-#define AVM_ISAC_FIFO 0x02
-#define AVM_ISAC_REG_LOW 0x04
-#define AVM_ISAC_REG_HIGH 0x06
-
-#define AVM_STATUS0_IRQ_ISAC 0x01
-#define AVM_STATUS0_IRQ_HDLC 0x02
-#define AVM_STATUS0_IRQ_TIMER 0x04
-#define AVM_STATUS0_IRQ_MASK 0x07
-
-#define AVM_STATUS0_RESET 0x01
-#define AVM_STATUS0_DIS_TIMER 0x02
-#define AVM_STATUS0_RES_TIMER 0x04
-#define AVM_STATUS0_ENA_IRQ 0x08
-#define AVM_STATUS0_TESTBIT 0x10
-
-#define AVM_STATUS1_INT_SEL 0x0f
-#define AVM_STATUS1_ENA_IOM 0x80
-
-#define HDLC_MODE_ITF_FLG 0x01
-#define HDLC_MODE_TRANS 0x02
-#define HDLC_MODE_CCR_7 0x04
-#define HDLC_MODE_CCR_16 0x08
-#define HDLC_MODE_TESTLOOP 0x80
-
-#define HDLC_INT_XPR 0x80
-#define HDLC_INT_XDU 0x40
-#define HDLC_INT_RPR 0x20
-#define HDLC_INT_MASK 0xE0
-
-#define HDLC_STAT_RME 0x01
-#define HDLC_STAT_RDO 0x10
-#define HDLC_STAT_CRCVFRRAB 0x0E
-#define HDLC_STAT_CRCVFR 0x06
-#define HDLC_STAT_RML_MASK 0x3f00
-
-#define HDLC_CMD_XRS 0x80
-#define HDLC_CMD_XME 0x01
-#define HDLC_CMD_RRS 0x20
-#define HDLC_CMD_XML_MASK 0x3f00
-
-
-/* Interface functions */
-
-static u_char
-ReadISAC(struct IsdnCardState *cs, u_char offset)
-{
- register u_char idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW;
- register u_char val;
-
- outb(idx, cs->hw.avm.cfg_reg + 4);
- val = inb(cs->hw.avm.isac + (offset & 0xf));
- return (val);
-}
-
-static void
-WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
-{
- register u_char idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW;
-
- outb(idx, cs->hw.avm.cfg_reg + 4);
- outb(value, cs->hw.avm.isac + (offset & 0xf));
-}
-
-static void
-ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- outb(AVM_ISAC_FIFO, cs->hw.avm.cfg_reg + 4);
- insb(cs->hw.avm.isac, data, size);
-}
-
-static void
-WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- outb(AVM_ISAC_FIFO, cs->hw.avm.cfg_reg + 4);
- outsb(cs->hw.avm.isac, data, size);
-}
-
-static inline u_int
-ReadHDLCPCI(struct IsdnCardState *cs, int chan, u_char offset)
-{
- register u_int idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
- register u_int val;
-
- outl(idx, cs->hw.avm.cfg_reg + 4);
- val = inl(cs->hw.avm.isac + offset);
- return (val);
-}
-
-static inline void
-WriteHDLCPCI(struct IsdnCardState *cs, int chan, u_char offset, u_int value)
-{
- register u_int idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
-
- outl(idx, cs->hw.avm.cfg_reg + 4);
- outl(value, cs->hw.avm.isac + offset);
-}
-
-static inline u_char
-ReadHDLCPnP(struct IsdnCardState *cs, int chan, u_char offset)
-{
- register u_char idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
- register u_char val;
-
- outb(idx, cs->hw.avm.cfg_reg + 4);
- val = inb(cs->hw.avm.isac + offset);
- return (val);
-}
-
-static inline void
-WriteHDLCPnP(struct IsdnCardState *cs, int chan, u_char offset, u_char value)
-{
- register u_char idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
-
- outb(idx, cs->hw.avm.cfg_reg + 4);
- outb(value, cs->hw.avm.isac + offset);
-}
-
-static u_char
-ReadHDLC_s(struct IsdnCardState *cs, int chan, u_char offset)
-{
- return (0xff & ReadHDLCPCI(cs, chan, offset));
-}
-
-static void
-WriteHDLC_s(struct IsdnCardState *cs, int chan, u_char offset, u_char value)
-{
- WriteHDLCPCI(cs, chan, offset, value);
-}
-
-static inline
-struct BCState *Sel_BCS(struct IsdnCardState *cs, int channel)
-{
- if (cs->bcs[0].mode && (cs->bcs[0].channel == channel))
- return (&cs->bcs[0]);
- else if (cs->bcs[1].mode && (cs->bcs[1].channel == channel))
- return (&cs->bcs[1]);
- else
- return (NULL);
-}
-
-static void
-write_ctrl(struct BCState *bcs, int which) {
-
- if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs, "hdlc %c wr%x ctrl %x",
- 'A' + bcs->channel, which, bcs->hw.hdlc.ctrl.ctrl);
- if (bcs->cs->subtyp == AVM_FRITZ_PCI) {
- WriteHDLCPCI(bcs->cs, bcs->channel, HDLC_STATUS, bcs->hw.hdlc.ctrl.ctrl);
- } else {
- if (which & 4)
- WriteHDLCPnP(bcs->cs, bcs->channel, HDLC_STATUS + 2,
- bcs->hw.hdlc.ctrl.sr.mode);
- if (which & 2)
- WriteHDLCPnP(bcs->cs, bcs->channel, HDLC_STATUS + 1,
- bcs->hw.hdlc.ctrl.sr.xml);
- if (which & 1)
- WriteHDLCPnP(bcs->cs, bcs->channel, HDLC_STATUS,
- bcs->hw.hdlc.ctrl.sr.cmd);
- }
-}
-
-static void
-modehdlc(struct BCState *bcs, int mode, int bc)
-{
- struct IsdnCardState *cs = bcs->cs;
- int hdlc = bcs->channel;
-
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hdlc %c mode %d --> %d ichan %d --> %d",
- 'A' + hdlc, bcs->mode, mode, hdlc, bc);
- bcs->hw.hdlc.ctrl.ctrl = 0;
- switch (mode) {
- case (-1): /* used for init */
- bcs->mode = 1;
- bcs->channel = bc;
- bc = 0;
- /* fall through */
- case (L1_MODE_NULL):
- if (bcs->mode == L1_MODE_NULL)
- return;
- bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
- bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_TRANS;
- write_ctrl(bcs, 5);
- bcs->mode = L1_MODE_NULL;
- bcs->channel = bc;
- break;
- case (L1_MODE_TRANS):
- bcs->mode = mode;
- bcs->channel = bc;
- bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
- bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_TRANS;
- write_ctrl(bcs, 5);
- bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS;
- write_ctrl(bcs, 1);
- bcs->hw.hdlc.ctrl.sr.cmd = 0;
- schedule_event(bcs, B_XMTBUFREADY);
- break;
- case (L1_MODE_HDLC):
- bcs->mode = mode;
- bcs->channel = bc;
- bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
- bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_ITF_FLG;
- write_ctrl(bcs, 5);
- bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS;
- write_ctrl(bcs, 1);
- bcs->hw.hdlc.ctrl.sr.cmd = 0;
- schedule_event(bcs, B_XMTBUFREADY);
- break;
- }
-}
-
-static inline void
-hdlc_empty_fifo(struct BCState *bcs, int count)
-{
- register u_int *ptr;
- u_char *p;
- u_char idx = bcs->channel ? AVM_HDLC_2 : AVM_HDLC_1;
- int cnt = 0;
- struct IsdnCardState *cs = bcs->cs;
-
- if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
- debugl1(cs, "hdlc_empty_fifo %d", count);
- if (bcs->hw.hdlc.rcvidx + count > HSCX_BUFMAX) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "hdlc_empty_fifo: incoming packet too large");
- return;
- }
- p = bcs->hw.hdlc.rcvbuf + bcs->hw.hdlc.rcvidx;
- ptr = (u_int *)p;
- bcs->hw.hdlc.rcvidx += count;
- if (cs->subtyp == AVM_FRITZ_PCI) {
- outl(idx, cs->hw.avm.cfg_reg + 4);
- while (cnt < count) {
-#ifdef __powerpc__
- *ptr++ = in_be32((unsigned *)(cs->hw.avm.isac + _IO_BASE));
-#else
- *ptr++ = inl(cs->hw.avm.isac);
-#endif /* __powerpc__ */
- cnt += 4;
- }
- } else {
- outb(idx, cs->hw.avm.cfg_reg + 4);
- while (cnt < count) {
- *p++ = inb(cs->hw.avm.isac);
- cnt++;
- }
- }
- if (cs->debug & L1_DEB_HSCX_FIFO) {
- char *t = bcs->blog;
-
- if (cs->subtyp == AVM_FRITZ_PNP)
- p = (u_char *) ptr;
- t += sprintf(t, "hdlc_empty_fifo %c cnt %d",
- bcs->channel ? 'B' : 'A', count);
- QuickHex(t, p, count);
- debugl1(cs, "%s", bcs->blog);
- }
-}
-
-static inline void
-hdlc_fill_fifo(struct BCState *bcs)
-{
- struct IsdnCardState *cs = bcs->cs;
- int count, cnt = 0;
- int fifo_size = 32;
- u_char *p;
- u_int *ptr;
-
- if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
- debugl1(cs, "hdlc_fill_fifo");
- if (!bcs->tx_skb)
- return;
- if (bcs->tx_skb->len <= 0)
- return;
-
- bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_XME;
- if (bcs->tx_skb->len > fifo_size) {
- count = fifo_size;
- } else {
- count = bcs->tx_skb->len;
- if (bcs->mode != L1_MODE_TRANS)
- bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XME;
- }
- if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
- debugl1(cs, "hdlc_fill_fifo %d/%u", count, bcs->tx_skb->len);
- p = bcs->tx_skb->data;
- ptr = (u_int *)p;
- skb_pull(bcs->tx_skb, count);
- bcs->tx_cnt -= count;
- bcs->hw.hdlc.count += count;
- bcs->hw.hdlc.ctrl.sr.xml = ((count == fifo_size) ? 0 : count);
- write_ctrl(bcs, 3); /* sets the correct index too */
- if (cs->subtyp == AVM_FRITZ_PCI) {
- while (cnt < count) {
-#ifdef __powerpc__
- out_be32((unsigned *)(cs->hw.avm.isac + _IO_BASE), *ptr++);
-#else
- outl(*ptr++, cs->hw.avm.isac);
-#endif /* __powerpc__ */
- cnt += 4;
- }
- } else {
- while (cnt < count) {
- outb(*p++, cs->hw.avm.isac);
- cnt++;
- }
- }
- if (cs->debug & L1_DEB_HSCX_FIFO) {
- char *t = bcs->blog;
-
- if (cs->subtyp == AVM_FRITZ_PNP)
- p = (u_char *) ptr;
- t += sprintf(t, "hdlc_fill_fifo %c cnt %d",
- bcs->channel ? 'B' : 'A', count);
- QuickHex(t, p, count);
- debugl1(cs, "%s", bcs->blog);
- }
-}
-
-static void
-HDLC_irq(struct BCState *bcs, u_int stat) {
- int len;
- struct sk_buff *skb;
-
- if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs, "ch%d stat %#x", bcs->channel, stat);
- if (stat & HDLC_INT_RPR) {
- if (stat & HDLC_STAT_RDO) {
- if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs, "RDO");
- else
- debugl1(bcs->cs, "ch%d stat %#x", bcs->channel, stat);
- bcs->hw.hdlc.ctrl.sr.xml = 0;
- bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_RRS;
- write_ctrl(bcs, 1);
- bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_RRS;
- write_ctrl(bcs, 1);
- bcs->hw.hdlc.rcvidx = 0;
- } else {
- if (!(len = (stat & HDLC_STAT_RML_MASK) >> 8))
- len = 32;
- hdlc_empty_fifo(bcs, len);
- if ((stat & HDLC_STAT_RME) || (bcs->mode == L1_MODE_TRANS)) {
- if (((stat & HDLC_STAT_CRCVFRRAB) == HDLC_STAT_CRCVFR) ||
- (bcs->mode == L1_MODE_TRANS)) {
- if (!(skb = dev_alloc_skb(bcs->hw.hdlc.rcvidx)))
- printk(KERN_WARNING "HDLC: receive out of memory\n");
- else {
- skb_put_data(skb,
- bcs->hw.hdlc.rcvbuf,
- bcs->hw.hdlc.rcvidx);
- skb_queue_tail(&bcs->rqueue, skb);
- }
- bcs->hw.hdlc.rcvidx = 0;
- schedule_event(bcs, B_RCVBUFREADY);
- } else {
- if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs, "invalid frame");
- else
- debugl1(bcs->cs, "ch%d invalid frame %#x", bcs->channel, stat);
- bcs->hw.hdlc.rcvidx = 0;
- }
- }
- }
- }
- if (stat & HDLC_INT_XDU) {
- /* Here we lost an TX interrupt, so
- * restart transmitting the whole frame.
- */
- if (bcs->tx_skb) {
- skb_push(bcs->tx_skb, bcs->hw.hdlc.count);
- bcs->tx_cnt += bcs->hw.hdlc.count;
- bcs->hw.hdlc.count = 0;
- if (bcs->cs->debug & L1_DEB_WARN)
- debugl1(bcs->cs, "ch%d XDU", bcs->channel);
- } else if (bcs->cs->debug & L1_DEB_WARN)
- debugl1(bcs->cs, "ch%d XDU without skb", bcs->channel);
- bcs->hw.hdlc.ctrl.sr.xml = 0;
- bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XRS;
- write_ctrl(bcs, 1);
- bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_XRS;
- write_ctrl(bcs, 1);
- hdlc_fill_fifo(bcs);
- } else if (stat & HDLC_INT_XPR) {
- if (bcs->tx_skb) {
- if (bcs->tx_skb->len) {
- hdlc_fill_fifo(bcs);
- return;
- } else {
- if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
- (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
- u_long flags;
- spin_lock_irqsave(&bcs->aclock, flags);
- bcs->ackcnt += bcs->hw.hdlc.count;
- spin_unlock_irqrestore(&bcs->aclock, flags);
- schedule_event(bcs, B_ACKPENDING);
- }
- dev_kfree_skb_irq(bcs->tx_skb);
- bcs->hw.hdlc.count = 0;
- bcs->tx_skb = NULL;
- }
- }
- if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
- bcs->hw.hdlc.count = 0;
- test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
- hdlc_fill_fifo(bcs);
- } else {
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- schedule_event(bcs, B_XMTBUFREADY);
- }
- }
-}
-
-static inline void
-HDLC_irq_main(struct IsdnCardState *cs)
-{
- u_int stat;
- struct BCState *bcs;
-
- if (cs->subtyp == AVM_FRITZ_PCI) {
- stat = ReadHDLCPCI(cs, 0, HDLC_STATUS);
- } else {
- stat = ReadHDLCPnP(cs, 0, HDLC_STATUS);
- if (stat & HDLC_INT_RPR)
- stat |= (ReadHDLCPnP(cs, 0, HDLC_STATUS + 1)) << 8;
- }
- if (stat & HDLC_INT_MASK) {
- if (!(bcs = Sel_BCS(cs, 0))) {
- if (cs->debug)
- debugl1(cs, "hdlc spurious channel 0 IRQ");
- } else
- HDLC_irq(bcs, stat);
- }
- if (cs->subtyp == AVM_FRITZ_PCI) {
- stat = ReadHDLCPCI(cs, 1, HDLC_STATUS);
- } else {
- stat = ReadHDLCPnP(cs, 1, HDLC_STATUS);
- if (stat & HDLC_INT_RPR)
- stat |= (ReadHDLCPnP(cs, 1, HDLC_STATUS + 1)) << 8;
- }
- if (stat & HDLC_INT_MASK) {
- if (!(bcs = Sel_BCS(cs, 1))) {
- if (cs->debug)
- debugl1(cs, "hdlc spurious channel 1 IRQ");
- } else
- HDLC_irq(bcs, stat);
- }
-}
-
-static void
-hdlc_l2l1(struct PStack *st, int pr, void *arg)
-{
- struct BCState *bcs = st->l1.bcs;
- struct sk_buff *skb = arg;
- u_long flags;
-
- switch (pr) {
- case (PH_DATA | REQUEST):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- if (bcs->tx_skb) {
- skb_queue_tail(&bcs->squeue, skb);
- } else {
- bcs->tx_skb = skb;
- test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->hw.hdlc.count = 0;
- bcs->cs->BC_Send_Data(bcs);
- }
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- break;
- case (PH_PULL | INDICATION):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- if (bcs->tx_skb) {
- printk(KERN_WARNING "hdlc_l2l1: this shouldn't happen\n");
- } else {
- test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->tx_skb = skb;
- bcs->hw.hdlc.count = 0;
- bcs->cs->BC_Send_Data(bcs);
- }
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- break;
- case (PH_PULL | REQUEST):
- if (!bcs->tx_skb) {
- test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
- } else
- test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- break;
- case (PH_ACTIVATE | REQUEST):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
- modehdlc(bcs, st->l1.mode, st->l1.bc);
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- l1_msg_b(st, pr, arg);
- break;
- case (PH_DEACTIVATE | REQUEST):
- l1_msg_b(st, pr, arg);
- break;
- case (PH_DEACTIVATE | CONFIRM):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- modehdlc(bcs, 0, st->l1.bc);
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
- break;
- }
-}
-
-static void
-close_hdlcstate(struct BCState *bcs)
-{
- modehdlc(bcs, 0, 0);
- if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
- kfree(bcs->hw.hdlc.rcvbuf);
- bcs->hw.hdlc.rcvbuf = NULL;
- kfree(bcs->blog);
- bcs->blog = NULL;
- skb_queue_purge(&bcs->rqueue);
- skb_queue_purge(&bcs->squeue);
- if (bcs->tx_skb) {
- dev_kfree_skb_any(bcs->tx_skb);
- bcs->tx_skb = NULL;
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- }
- }
-}
-
-static int
-open_hdlcstate(struct IsdnCardState *cs, struct BCState *bcs)
-{
- if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
- if (!(bcs->hw.hdlc.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
- printk(KERN_WARNING
- "HiSax: No memory for hdlc.rcvbuf\n");
- return (1);
- }
- if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
- printk(KERN_WARNING
- "HiSax: No memory for bcs->blog\n");
- test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
- kfree(bcs->hw.hdlc.rcvbuf);
- bcs->hw.hdlc.rcvbuf = NULL;
- return (2);
- }
- skb_queue_head_init(&bcs->rqueue);
- skb_queue_head_init(&bcs->squeue);
- }
- bcs->tx_skb = NULL;
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->event = 0;
- bcs->hw.hdlc.rcvidx = 0;
- bcs->tx_cnt = 0;
- return (0);
-}
-
-static int
-setstack_hdlc(struct PStack *st, struct BCState *bcs)
-{
- bcs->channel = st->l1.bc;
- if (open_hdlcstate(st->l1.hardware, bcs))
- return (-1);
- st->l1.bcs = bcs;
- st->l2.l2l1 = hdlc_l2l1;
- setstack_manager(st);
- bcs->st = st;
- setstack_l1_B(st);
- return (0);
-}
-
-#if 0
-void __init
-clear_pending_hdlc_ints(struct IsdnCardState *cs)
-{
- u_int val;
-
- if (cs->subtyp == AVM_FRITZ_PCI) {
- val = ReadHDLCPCI(cs, 0, HDLC_STATUS);
- debugl1(cs, "HDLC 1 STA %x", val);
- val = ReadHDLCPCI(cs, 1, HDLC_STATUS);
- debugl1(cs, "HDLC 2 STA %x", val);
- } else {
- val = ReadHDLCPnP(cs, 0, HDLC_STATUS);
- debugl1(cs, "HDLC 1 STA %x", val);
- val = ReadHDLCPnP(cs, 0, HDLC_STATUS + 1);
- debugl1(cs, "HDLC 1 RML %x", val);
- val = ReadHDLCPnP(cs, 0, HDLC_STATUS + 2);
- debugl1(cs, "HDLC 1 MODE %x", val);
- val = ReadHDLCPnP(cs, 0, HDLC_STATUS + 3);
- debugl1(cs, "HDLC 1 VIN %x", val);
- val = ReadHDLCPnP(cs, 1, HDLC_STATUS);
- debugl1(cs, "HDLC 2 STA %x", val);
- val = ReadHDLCPnP(cs, 1, HDLC_STATUS + 1);
- debugl1(cs, "HDLC 2 RML %x", val);
- val = ReadHDLCPnP(cs, 1, HDLC_STATUS + 2);
- debugl1(cs, "HDLC 2 MODE %x", val);
- val = ReadHDLCPnP(cs, 1, HDLC_STATUS + 3);
- debugl1(cs, "HDLC 2 VIN %x", val);
- }
-}
-#endif /* 0 */
-
-static void
-inithdlc(struct IsdnCardState *cs)
-{
- cs->bcs[0].BC_SetStack = setstack_hdlc;
- cs->bcs[1].BC_SetStack = setstack_hdlc;
- cs->bcs[0].BC_Close = close_hdlcstate;
- cs->bcs[1].BC_Close = close_hdlcstate;
- modehdlc(cs->bcs, -1, 0);
- modehdlc(cs->bcs + 1, -1, 1);
-}
-
-static irqreturn_t
-avm_pcipnp_interrupt(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_long flags;
- u_char val;
- u_char sval;
-
- spin_lock_irqsave(&cs->lock, flags);
- sval = inb(cs->hw.avm.cfg_reg + 2);
- if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK) {
- /* possible a shared IRQ reqest */
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_NONE;
- }
- if (!(sval & AVM_STATUS0_IRQ_ISAC)) {
- val = ReadISAC(cs, ISAC_ISTA);
- isac_interrupt(cs, val);
- }
- if (!(sval & AVM_STATUS0_IRQ_HDLC)) {
- HDLC_irq_main(cs);
- }
- WriteISAC(cs, ISAC_MASK, 0xFF);
- WriteISAC(cs, ISAC_MASK, 0x0);
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static void
-reset_avmpcipnp(struct IsdnCardState *cs)
-{
- printk(KERN_INFO "AVM PCI/PnP: reset\n");
- outb(AVM_STATUS0_RESET | AVM_STATUS0_DIS_TIMER, cs->hw.avm.cfg_reg + 2);
- mdelay(10);
- outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER | AVM_STATUS0_ENA_IRQ, cs->hw.avm.cfg_reg + 2);
- outb(AVM_STATUS1_ENA_IOM | cs->irq, cs->hw.avm.cfg_reg + 3);
- mdelay(10);
- printk(KERN_INFO "AVM PCI/PnP: S1 %x\n", inb(cs->hw.avm.cfg_reg + 3));
-}
-
-static int
-AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
- u_long flags;
-
- switch (mt) {
- case CARD_RESET:
- spin_lock_irqsave(&cs->lock, flags);
- reset_avmpcipnp(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_RELEASE:
- outb(0, cs->hw.avm.cfg_reg + 2);
- release_region(cs->hw.avm.cfg_reg, 32);
- return (0);
- case CARD_INIT:
- spin_lock_irqsave(&cs->lock, flags);
- reset_avmpcipnp(cs);
- clear_pending_isac_ints(cs);
- initisac(cs);
- inithdlc(cs);
- outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER,
- cs->hw.avm.cfg_reg + 2);
- WriteISAC(cs, ISAC_MASK, 0);
- outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER |
- AVM_STATUS0_ENA_IRQ, cs->hw.avm.cfg_reg + 2);
- /* RESET Receiver and Transmitter */
- WriteISAC(cs, ISAC_CMDR, 0x41);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_TEST:
- return (0);
- }
- return (0);
-}
-
-static int avm_setup_rest(struct IsdnCardState *cs)
-{
- u_int val, ver;
-
- cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10;
- if (!request_region(cs->hw.avm.cfg_reg, 32,
- (cs->subtyp == AVM_FRITZ_PCI) ? "avm PCI" : "avm PnP")) {
- printk(KERN_WARNING
- "HiSax: Fritz!PCI/PNP config port %x-%x already in use\n",
- cs->hw.avm.cfg_reg,
- cs->hw.avm.cfg_reg + 31);
- return (0);
- }
- switch (cs->subtyp) {
- case AVM_FRITZ_PCI:
- val = inl(cs->hw.avm.cfg_reg);
- printk(KERN_INFO "AVM PCI: stat %#x\n", val);
- printk(KERN_INFO "AVM PCI: Class %X Rev %d\n",
- val & 0xff, (val >> 8) & 0xff);
- cs->BC_Read_Reg = &ReadHDLC_s;
- cs->BC_Write_Reg = &WriteHDLC_s;
- break;
- case AVM_FRITZ_PNP:
- val = inb(cs->hw.avm.cfg_reg);
- ver = inb(cs->hw.avm.cfg_reg + 1);
- printk(KERN_INFO "AVM PnP: Class %X Rev %d\n", val, ver);
- cs->BC_Read_Reg = &ReadHDLCPnP;
- cs->BC_Write_Reg = &WriteHDLCPnP;
- break;
- default:
- printk(KERN_WARNING "AVM unknown subtype %d\n", cs->subtyp);
- return (0);
- }
- printk(KERN_INFO "HiSax: %s config irq:%d base:0x%X\n",
- (cs->subtyp == AVM_FRITZ_PCI) ? "AVM Fritz!PCI" : "AVM Fritz!PnP",
- cs->irq, cs->hw.avm.cfg_reg);
-
- setup_isac(cs);
- cs->readisac = &ReadISAC;
- cs->writeisac = &WriteISAC;
- cs->readisacfifo = &ReadISACfifo;
- cs->writeisacfifo = &WriteISACfifo;
- cs->BC_Send_Data = &hdlc_fill_fifo;
- cs->cardmsg = &AVM_card_msg;
- cs->irq_func = &avm_pcipnp_interrupt;
- cs->writeisac(cs, ISAC_MASK, 0xFF);
- ISACVersion(cs, (cs->subtyp == AVM_FRITZ_PCI) ? "AVM PCI:" : "AVM PnP:");
- return (1);
-}
-
-#ifndef __ISAPNP__
-
-static int avm_pnp_setup(struct IsdnCardState *cs)
-{
- return (1); /* no-op: success */
-}
-
-#else
-
-static struct pnp_card *pnp_avm_c = NULL;
-
-static int avm_pnp_setup(struct IsdnCardState *cs)
-{
- struct pnp_dev *pnp_avm_d = NULL;
-
- if (!isapnp_present())
- return (1); /* no-op: success */
-
- if ((pnp_avm_c = pnp_find_card(
- ISAPNP_VENDOR('A', 'V', 'M'),
- ISAPNP_FUNCTION(0x0900), pnp_avm_c))) {
- if ((pnp_avm_d = pnp_find_dev(pnp_avm_c,
- ISAPNP_VENDOR('A', 'V', 'M'),
- ISAPNP_FUNCTION(0x0900), pnp_avm_d))) {
- int err;
-
- pnp_disable_dev(pnp_avm_d);
- err = pnp_activate_dev(pnp_avm_d);
- if (err < 0) {
- printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __func__, err);
- return (0);
- }
- cs->hw.avm.cfg_reg =
- pnp_port_start(pnp_avm_d, 0);
- cs->irq = pnp_irq(pnp_avm_d, 0);
- if (cs->irq == -1) {
- printk(KERN_ERR "FritzPnP:No IRQ\n");
- return (0);
- }
- if (!cs->hw.avm.cfg_reg) {
- printk(KERN_ERR "FritzPnP:No IO address\n");
- return (0);
- }
- cs->subtyp = AVM_FRITZ_PNP;
-
- return (2); /* goto 'ready' label */
- }
- }
-
- return (1);
-}
-
-#endif /* __ISAPNP__ */
-
-#ifndef CONFIG_PCI
-
-static int avm_pci_setup(struct IsdnCardState *cs)
-{
- return (1); /* no-op: success */
-}
-
-#else
-
-static struct pci_dev *dev_avm = NULL;
-
-static int avm_pci_setup(struct IsdnCardState *cs)
-{
- if ((dev_avm = hisax_find_pci_device(PCI_VENDOR_ID_AVM,
- PCI_DEVICE_ID_AVM_A1, dev_avm))) {
-
- if (pci_enable_device(dev_avm))
- return (0);
-
- cs->irq = dev_avm->irq;
- if (!cs->irq) {
- printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n");
- return (0);
- }
-
- cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1);
- if (!cs->hw.avm.cfg_reg) {
- printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n");
- return (0);
- }
-
- cs->subtyp = AVM_FRITZ_PCI;
- } else {
- printk(KERN_WARNING "FritzPCI: No PCI card found\n");
- return (0);
- }
-
- cs->irq_flags |= IRQF_SHARED;
-
- return (1);
-}
-
-#endif /* CONFIG_PCI */
-
-int setup_avm_pcipnp(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
- int rc;
-
- strcpy(tmp, avm_pci_rev);
- printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp));
-
- if (cs->typ != ISDN_CTYPE_FRITZPCI)
- return (0);
-
- if (card->para[1]) {
- /* old manual method */
- cs->hw.avm.cfg_reg = card->para[1];
- cs->irq = card->para[0];
- cs->subtyp = AVM_FRITZ_PNP;
- goto ready;
- }
-
- rc = avm_pnp_setup(cs);
- if (rc < 1)
- return (0);
- if (rc == 2)
- goto ready;
-
- rc = avm_pci_setup(cs);
- if (rc < 1)
- return (0);
-
-ready:
- return avm_setup_rest(cs);
-}
diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c
deleted file mode 100644
index baad94ec1f4a..000000000000
--- a/drivers/isdn/hisax/avma1_cs.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * PCMCIA client driver for AVM A1 / Fritz!PCMCIA
- *
- * Author Carsten Paeth
- * Copyright 1998-2001 by Carsten Paeth <calle@calle.in-berlin.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/module.h>
-
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <asm/io.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ds.h>
-#include "hisax_cfg.h"
-
-MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for AVM A1/Fritz!PCMCIA cards");
-MODULE_AUTHOR("Carsten Paeth");
-MODULE_LICENSE("GPL");
-
-
-/*====================================================================*/
-
-/* Parameters that can be set with 'insmod' */
-
-static int isdnprot = 2;
-
-module_param(isdnprot, int, 0);
-
-/*====================================================================*/
-
-static int avma1cs_config(struct pcmcia_device *link);
-static void avma1cs_release(struct pcmcia_device *link);
-static void avma1cs_detach(struct pcmcia_device *p_dev);
-
-static int avma1cs_probe(struct pcmcia_device *p_dev)
-{
- dev_dbg(&p_dev->dev, "avma1cs_attach()\n");
-
- /* General socket configuration */
- p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
- p_dev->config_index = 1;
- p_dev->config_regs = PRESENT_OPTION;
-
- return avma1cs_config(p_dev);
-} /* avma1cs_attach */
-
-static void avma1cs_detach(struct pcmcia_device *link)
-{
- dev_dbg(&link->dev, "avma1cs_detach(0x%p)\n", link);
- avma1cs_release(link);
- kfree(link->priv);
-} /* avma1cs_detach */
-
-static int avma1cs_configcheck(struct pcmcia_device *p_dev, void *priv_data)
-{
- p_dev->resource[0]->end = 16;
- p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
- p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
- p_dev->io_lines = 5;
-
- return pcmcia_request_io(p_dev);
-}
-
-
-static int avma1cs_config(struct pcmcia_device *link)
-{
- int i = -1;
- char devname[128];
- IsdnCard_t icard;
- int busy = 0;
-
- dev_dbg(&link->dev, "avma1cs_config(0x%p)\n", link);
-
- devname[0] = 0;
- if (link->prod_id[1])
- strlcpy(devname, link->prod_id[1], sizeof(devname));
-
- if (pcmcia_loop_config(link, avma1cs_configcheck, NULL))
- return -ENODEV;
-
- do {
- /*
- * allocate an interrupt line
- */
- if (!link->irq) {
- /* undo */
- pcmcia_disable_device(link);
- break;
- }
-
- /*
- * configure the PCMCIA socket
- */
- i = pcmcia_enable_device(link);
- if (i != 0) {
- pcmcia_disable_device(link);
- break;
- }
-
- } while (0);
-
- /* If any step failed, release any partially configured state */
- if (i != 0) {
- avma1cs_release(link);
- return -ENODEV;
- }
-
- icard.para[0] = link->irq;
- icard.para[1] = link->resource[0]->start;
- icard.protocol = isdnprot;
- icard.typ = ISDN_CTYPE_A1_PCMCIA;
-
- i = hisax_init_pcmcia(link, &busy, &icard);
- if (i < 0) {
- printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 "
- "PCMCIA %d at i/o %#x\n", i,
- (unsigned int) link->resource[0]->start);
- avma1cs_release(link);
- return -ENODEV;
- }
- link->priv = (void *) (unsigned long) i;
-
- return 0;
-} /* avma1cs_config */
-
-static void avma1cs_release(struct pcmcia_device *link)
-{
- unsigned long minor = (unsigned long) link->priv;
-
- dev_dbg(&link->dev, "avma1cs_release(0x%p)\n", link);
-
- /* now unregister function with hisax */
- HiSax_closecard(minor);
-
- pcmcia_disable_device(link);
-} /* avma1cs_release */
-
-static const struct pcmcia_device_id avma1cs_ids[] = {
- PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb),
- PCMCIA_DEVICE_PROD_ID12("ISDN", "CARD", 0x8d9761c8, 0x01c5aa7b),
- PCMCIA_DEVICE_NULL
-};
-MODULE_DEVICE_TABLE(pcmcia, avma1cs_ids);
-
-static struct pcmcia_driver avma1cs_driver = {
- .owner = THIS_MODULE,
- .name = "avma1_cs",
- .probe = avma1cs_probe,
- .remove = avma1cs_detach,
- .id_table = avma1cs_ids,
-};
-module_pcmcia_driver(avma1cs_driver);
diff --git a/drivers/isdn/hisax/bkm_a4t.c b/drivers/isdn/hisax/bkm_a4t.c
deleted file mode 100644
index c360164bde1b..000000000000
--- a/drivers/isdn/hisax/bkm_a4t.c
+++ /dev/null
@@ -1,358 +0,0 @@
-/* $Id: bkm_a4t.c,v 1.22.2.4 2004/01/14 16:04:48 keil Exp $
- *
- * low level stuff for T-Berkom A4T
- *
- * Author Roland Klabunde
- * Copyright by Roland Klabunde <R.Klabunde@Berkom.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-
-#include <linux/init.h>
-#include "hisax.h"
-#include "isac.h"
-#include "hscx.h"
-#include "jade.h"
-#include "isdnl1.h"
-#include <linux/pci.h>
-#include "bkm_ax.h"
-
-static const char *bkm_a4t_revision = "$Revision: 1.22.2.4 $";
-
-
-static inline u_char
-readreg(unsigned int ale, unsigned long adr, u_char off)
-{
- register u_int ret;
- unsigned int *po = (unsigned int *) adr; /* Postoffice */
-
- *po = (GCS_2 | PO_WRITE | off);
- __WAITI20__(po);
- *po = (ale | PO_READ);
- __WAITI20__(po);
- ret = *po;
- return ((unsigned char) ret);
-}
-
-
-static inline void
-readfifo(unsigned int ale, unsigned long adr, u_char off, u_char *data, int size)
-{
- int i;
- for (i = 0; i < size; i++)
- *data++ = readreg(ale, adr, off);
-}
-
-
-static inline void
-writereg(unsigned int ale, unsigned long adr, u_char off, u_char data)
-{
- unsigned int *po = (unsigned int *) adr; /* Postoffice */
- *po = (GCS_2 | PO_WRITE | off);
- __WAITI20__(po);
- *po = (ale | PO_WRITE | data);
- __WAITI20__(po);
-}
-
-
-static inline void
-writefifo(unsigned int ale, unsigned long adr, u_char off, u_char *data, int size)
-{
- int i;
-
- for (i = 0; i < size; i++)
- writereg(ale, adr, off, *data++);
-}
-
-
-/* Interface functions */
-
-static u_char
-ReadISAC(struct IsdnCardState *cs, u_char offset)
-{
- return (readreg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, offset));
-}
-
-static void
-WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
-{
- writereg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, offset, value);
-}
-
-static void
-ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- readfifo(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, 0, data, size);
-}
-
-static void
-WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- writefifo(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, 0, data, size);
-}
-
-static u_char
-ReadJADE(struct IsdnCardState *cs, int jade, u_char offset)
-{
- return (readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, offset + (jade == -1 ? 0 : (jade ? 0xC0 : 0x80))));
-}
-
-static void
-WriteJADE(struct IsdnCardState *cs, int jade, u_char offset, u_char value)
-{
- writereg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, offset + (jade == -1 ? 0 : (jade ? 0xC0 : 0x80)), value);
-}
-
-/*
- * fast interrupt JADE stuff goes here
- */
-
-#define READJADE(cs, nr, reg) readreg(cs->hw.ax.jade_ale, \
- cs->hw.ax.jade_adr, reg + (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)))
-#define WRITEJADE(cs, nr, reg, data) writereg(cs->hw.ax.jade_ale, \
- cs->hw.ax.jade_adr, reg + (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), data)
-
-#define READJADEFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ax.jade_ale, \
- cs->hw.ax.jade_adr, (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), ptr, cnt)
-#define WRITEJADEFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ax.jade_ale, \
- cs->hw.ax.jade_adr, (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), ptr, cnt)
-
-#include "jade_irq.c"
-
-static irqreturn_t
-bkm_interrupt(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_char val = 0;
- u_long flags;
- I20_REGISTER_FILE *pI20_Regs;
-
- spin_lock_irqsave(&cs->lock, flags);
- pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
-
- /* ISDN interrupt pending? */
- if (pI20_Regs->i20IntStatus & intISDN) {
- /* Reset the ISDN interrupt */
- pI20_Regs->i20IntStatus = intISDN;
- /* Disable ISDN interrupt */
- pI20_Regs->i20IntCtrl &= ~intISDN;
- /* Channel A first */
- val = readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, jade_HDLC_ISR + 0x80);
- if (val) {
- jade_int_main(cs, val, 0);
- }
- /* Channel B */
- val = readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, jade_HDLC_ISR + 0xC0);
- if (val) {
- jade_int_main(cs, val, 1);
- }
- /* D-Channel */
- val = readreg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, ISAC_ISTA);
- if (val) {
- isac_interrupt(cs, val);
- }
- /* Reenable ISDN interrupt */
- pI20_Regs->i20IntCtrl |= intISDN;
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
- } else {
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_NONE;
- }
-}
-
-static void
-release_io_bkm(struct IsdnCardState *cs)
-{
- if (cs->hw.ax.base) {
- iounmap((void *) cs->hw.ax.base);
- cs->hw.ax.base = 0;
- }
-}
-
-static void
-enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable)
-{
- if (cs->typ == ISDN_CTYPE_BKM_A4T) {
- I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
- if (bEnable)
- pI20_Regs->i20IntCtrl |= (intISDN | intPCI);
- else
- /* CAUTION: This disables the video capture driver too */
- pI20_Regs->i20IntCtrl &= ~(intISDN | intPCI);
- }
-}
-
-static void
-reset_bkm(struct IsdnCardState *cs)
-{
- if (cs->typ == ISDN_CTYPE_BKM_A4T) {
- I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
- /* Issue the I20 soft reset */
- pI20_Regs->i20SysControl = 0xFF; /* all in */
- mdelay(10);
- /* Remove the soft reset */
- pI20_Regs->i20SysControl = sysRESET | 0xFF;
- mdelay(10);
- /* Set our configuration */
- pI20_Regs->i20SysControl = sysRESET | sysCFG;
- /* Issue ISDN reset */
- pI20_Regs->i20GuestControl = guestWAIT_CFG |
- g_A4T_JADE_RES |
- g_A4T_ISAR_RES |
- g_A4T_ISAC_RES |
- g_A4T_JADE_BOOTR |
- g_A4T_ISAR_BOOTR;
- mdelay(10);
-
- /* Remove RESET state from ISDN */
- pI20_Regs->i20GuestControl &= ~(g_A4T_ISAC_RES |
- g_A4T_JADE_RES |
- g_A4T_ISAR_RES);
- mdelay(10);
- }
-}
-
-static int
-BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
- u_long flags;
-
- switch (mt) {
- case CARD_RESET:
- /* Disable ints */
- spin_lock_irqsave(&cs->lock, flags);
- enable_bkm_int(cs, 0);
- reset_bkm(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_RELEASE:
- /* Sanity */
- spin_lock_irqsave(&cs->lock, flags);
- enable_bkm_int(cs, 0);
- reset_bkm(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- release_io_bkm(cs);
- return (0);
- case CARD_INIT:
- spin_lock_irqsave(&cs->lock, flags);
- clear_pending_isac_ints(cs);
- clear_pending_jade_ints(cs);
- initisac(cs);
- initjade(cs);
- /* Enable ints */
- enable_bkm_int(cs, 1);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_TEST:
- return (0);
- }
- return (0);
-}
-
-static int a4t_pci_probe(struct pci_dev *dev_a4t, struct IsdnCardState *cs,
- u_int *found, u_int *pci_memaddr)
-{
- u16 sub_sys;
- u16 sub_vendor;
-
- sub_vendor = dev_a4t->subsystem_vendor;
- sub_sys = dev_a4t->subsystem_device;
- if ((sub_sys == PCI_DEVICE_ID_BERKOM_A4T) && (sub_vendor == PCI_VENDOR_ID_BERKOM)) {
- if (pci_enable_device(dev_a4t))
- return (0); /* end loop & function */
- *found = 1;
- *pci_memaddr = pci_resource_start(dev_a4t, 0);
- cs->irq = dev_a4t->irq;
- return (1); /* end loop */
- }
-
- return (-1); /* continue looping */
-}
-
-static int a4t_cs_init(struct IsdnCard *card, struct IsdnCardState *cs,
- u_int pci_memaddr)
-{
- I20_REGISTER_FILE *pI20_Regs;
-
- if (!cs->irq) { /* IRQ range check ?? */
- printk(KERN_WARNING "HiSax: Telekom A4T: No IRQ\n");
- return (0);
- }
- cs->hw.ax.base = (long) ioremap(pci_memaddr, 4096);
- /* Check suspecious address */
- pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
- if ((pI20_Regs->i20IntStatus & 0x8EFFFFFF) != 0) {
- printk(KERN_WARNING "HiSax: Telekom A4T address "
- "%lx-%lx suspicious\n",
- cs->hw.ax.base, cs->hw.ax.base + 4096);
- iounmap((void *) cs->hw.ax.base);
- cs->hw.ax.base = 0;
- return (0);
- }
- cs->hw.ax.isac_adr = cs->hw.ax.base + PO_OFFSET;
- cs->hw.ax.jade_adr = cs->hw.ax.base + PO_OFFSET;
- cs->hw.ax.isac_ale = GCS_1;
- cs->hw.ax.jade_ale = GCS_3;
-
- printk(KERN_INFO "HiSax: Telekom A4T: Card configured at "
- "0x%lX IRQ %d\n",
- cs->hw.ax.base, cs->irq);
-
- setup_isac(cs);
- cs->readisac = &ReadISAC;
- cs->writeisac = &WriteISAC;
- cs->readisacfifo = &ReadISACfifo;
- cs->writeisacfifo = &WriteISACfifo;
- cs->BC_Read_Reg = &ReadJADE;
- cs->BC_Write_Reg = &WriteJADE;
- cs->BC_Send_Data = &jade_fill_fifo;
- cs->cardmsg = &BKM_card_msg;
- cs->irq_func = &bkm_interrupt;
- cs->irq_flags |= IRQF_SHARED;
- ISACVersion(cs, "Telekom A4T:");
- /* Jade version */
- JadeVersion(cs, "Telekom A4T:");
-
- return (1);
-}
-
-static struct pci_dev *dev_a4t = NULL;
-
-int setup_bkm_a4t(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
- u_int pci_memaddr = 0, found = 0;
- int ret;
-
- strcpy(tmp, bkm_a4t_revision);
- printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp));
- if (cs->typ == ISDN_CTYPE_BKM_A4T) {
- cs->subtyp = BKM_A4T;
- } else
- return (0);
-
- while ((dev_a4t = hisax_find_pci_device(PCI_VENDOR_ID_ZORAN,
- PCI_DEVICE_ID_ZORAN_36120, dev_a4t))) {
- ret = a4t_pci_probe(dev_a4t, cs, &found, &pci_memaddr);
- if (!ret)
- return (0);
- if (ret > 0)
- break;
- }
- if (!found) {
- printk(KERN_WARNING "HiSax: Telekom A4T: Card not found\n");
- return (0);
- }
- if (!pci_memaddr) {
- printk(KERN_WARNING "HiSax: Telekom A4T: "
- "No Memory base address\n");
- return (0);
- }
-
- return a4t_cs_init(card, cs, pci_memaddr);
-}
diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c
deleted file mode 100644
index dd663ea57ec6..000000000000
--- a/drivers/isdn/hisax/bkm_a8.c
+++ /dev/null
@@ -1,433 +0,0 @@
-/* $Id: bkm_a8.c,v 1.22.2.4 2004/01/15 14:02:34 keil Exp $
- *
- * low level stuff for Scitel Quadro (4*S0, passive)
- *
- * Author Roland Klabunde
- * Copyright by Roland Klabunde <R.Klabunde@Berkom.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-
-#include <linux/init.h>
-#include "hisax.h"
-#include "isac.h"
-#include "ipac.h"
-#include "hscx.h"
-#include "isdnl1.h"
-#include <linux/pci.h>
-#include "bkm_ax.h"
-
-#define ATTEMPT_PCI_REMAPPING /* Required for PLX rev 1 */
-
-static const char sct_quadro_revision[] = "$Revision: 1.22.2.4 $";
-
-static const char *sct_quadro_subtypes[] =
-{
- "",
- "#1",
- "#2",
- "#3",
- "#4"
-};
-
-
-#define wordout(addr, val) outw(val, addr)
-#define wordin(addr) inw(addr)
-
-static inline u_char
-readreg(unsigned int ale, unsigned int adr, u_char off)
-{
- register u_char ret;
- wordout(ale, off);
- ret = wordin(adr) & 0xFF;
- return (ret);
-}
-
-static inline void
-readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
-{
- int i;
- wordout(ale, off);
- for (i = 0; i < size; i++)
- data[i] = wordin(adr) & 0xFF;
-}
-
-
-static inline void
-writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
-{
- wordout(ale, off);
- wordout(adr, data);
-}
-
-static inline void
-writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
-{
- int i;
- wordout(ale, off);
- for (i = 0; i < size; i++)
- wordout(adr, data[i]);
-}
-
-/* Interface functions */
-
-static u_char
-ReadISAC(struct IsdnCardState *cs, u_char offset)
-{
- return (readreg(cs->hw.ax.base, cs->hw.ax.data_adr, offset | 0x80));
-}
-
-static void
-WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
-{
- writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset | 0x80, value);
-}
-
-static void
-ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- readfifo(cs->hw.ax.base, cs->hw.ax.data_adr, 0x80, data, size);
-}
-
-static void
-WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- writefifo(cs->hw.ax.base, cs->hw.ax.data_adr, 0x80, data, size);
-}
-
-
-static u_char
-ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
-{
- return (readreg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0)));
-}
-
-static void
-WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
-{
- writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0), value);
-}
-
-/* Set the specific ipac to active */
-static void
-set_ipac_active(struct IsdnCardState *cs, u_int active)
-{
- /* set irq mask */
- writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK,
- active ? 0xc0 : 0xff);
-}
-
-/*
- * fast interrupt HSCX stuff goes here
- */
-
-#define READHSCX(cs, nr, reg) readreg(cs->hw.ax.base, \
- cs->hw.ax.data_adr, reg + (nr ? 0x40 : 0))
-#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.ax.base, \
- cs->hw.ax.data_adr, reg + (nr ? 0x40 : 0), data)
-#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ax.base, \
- cs->hw.ax.data_adr, (nr ? 0x40 : 0), ptr, cnt)
-#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ax.base, \
- cs->hw.ax.data_adr, (nr ? 0x40 : 0), ptr, cnt)
-
-#include "hscx_irq.c"
-
-static irqreturn_t
-bkm_interrupt_ipac(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_char ista, val, icnt = 5;
- u_long flags;
-
- spin_lock_irqsave(&cs->lock, flags);
- ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA);
- if (!(ista & 0x3f)) { /* not this IPAC */
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_NONE;
- }
-Start_IPAC:
- if (cs->debug & L1_DEB_IPAC)
- debugl1(cs, "IPAC ISTA %02X", ista);
- if (ista & 0x0f) {
- val = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, HSCX_ISTA + 0x40);
- if (ista & 0x01)
- val |= 0x01;
- if (ista & 0x04)
- val |= 0x02;
- if (ista & 0x08)
- val |= 0x04;
- if (val) {
- hscx_int_main(cs, val);
- }
- }
- if (ista & 0x20) {
- val = 0xfe & readreg(cs->hw.ax.base, cs->hw.ax.data_adr, ISAC_ISTA | 0x80);
- if (val) {
- isac_interrupt(cs, val);
- }
- }
- if (ista & 0x10) {
- val = 0x01;
- isac_interrupt(cs, val);
- }
- ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA);
- if ((ista & 0x3f) && icnt) {
- icnt--;
- goto Start_IPAC;
- }
- if (!icnt)
- printk(KERN_WARNING "HiSax: Scitel Quadro (%s) IRQ LOOP\n",
- sct_quadro_subtypes[cs->subtyp]);
- writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xFF);
- writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xC0);
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static void
-release_io_sct_quadro(struct IsdnCardState *cs)
-{
- release_region(cs->hw.ax.base & 0xffffffc0, 128);
- if (cs->subtyp == SCT_1)
- release_region(cs->hw.ax.plx_adr, 64);
-}
-
-static void
-enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable)
-{
- if (cs->typ == ISDN_CTYPE_SCT_QUADRO) {
- if (bEnable)
- wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) | 0x41));
- else
- wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) & ~0x41));
- }
-}
-
-static void
-reset_bkm(struct IsdnCardState *cs)
-{
- if (cs->subtyp == SCT_1) {
- wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) & ~4));
- mdelay(10);
- /* Remove the soft reset */
- wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) | 4));
- mdelay(10);
- }
-}
-
-static int
-BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
- u_long flags;
-
- switch (mt) {
- case CARD_RESET:
- spin_lock_irqsave(&cs->lock, flags);
- /* Disable ints */
- set_ipac_active(cs, 0);
- enable_bkm_int(cs, 0);
- reset_bkm(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_RELEASE:
- /* Sanity */
- spin_lock_irqsave(&cs->lock, flags);
- set_ipac_active(cs, 0);
- enable_bkm_int(cs, 0);
- spin_unlock_irqrestore(&cs->lock, flags);
- release_io_sct_quadro(cs);
- return (0);
- case CARD_INIT:
- spin_lock_irqsave(&cs->lock, flags);
- cs->debug |= L1_DEB_IPAC;
- set_ipac_active(cs, 1);
- inithscxisac(cs, 3);
- /* Enable ints */
- enable_bkm_int(cs, 1);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_TEST:
- return (0);
- }
- return (0);
-}
-
-static int sct_alloc_io(u_int adr, u_int len)
-{
- if (!request_region(adr, len, "scitel")) {
- printk(KERN_WARNING
- "HiSax: Scitel port %#x-%#x already in use\n",
- adr, adr + len);
- return (1);
- }
- return (0);
-}
-
-static struct pci_dev *dev_a8 = NULL;
-static u16 sub_vendor_id = 0;
-static u16 sub_sys_id = 0;
-static u_char pci_bus = 0;
-static u_char pci_device_fn = 0;
-static u_char pci_irq = 0;
-
-int setup_sct_quadro(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
- u_int found = 0;
- u_int pci_ioaddr1, pci_ioaddr2, pci_ioaddr3, pci_ioaddr4, pci_ioaddr5;
-
- strcpy(tmp, sct_quadro_revision);
- printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp));
- if (cs->typ == ISDN_CTYPE_SCT_QUADRO) {
- cs->subtyp = SCT_1; /* Preset */
- } else
- return (0);
-
- /* Identify subtype by para[0] */
- if (card->para[0] >= SCT_1 && card->para[0] <= SCT_4)
- cs->subtyp = card->para[0];
- else {
- printk(KERN_WARNING "HiSax: Scitel Quadro: Invalid "
- "subcontroller in configuration, default to 1\n");
- return (0);
- }
- if ((cs->subtyp != SCT_1) && ((sub_sys_id != PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO) ||
- (sub_vendor_id != PCI_VENDOR_ID_BERKOM)))
- return (0);
- if (cs->subtyp == SCT_1) {
- while ((dev_a8 = hisax_find_pci_device(PCI_VENDOR_ID_PLX,
- PCI_DEVICE_ID_PLX_9050, dev_a8))) {
-
- sub_vendor_id = dev_a8->subsystem_vendor;
- sub_sys_id = dev_a8->subsystem_device;
- if ((sub_sys_id == PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO) &&
- (sub_vendor_id == PCI_VENDOR_ID_BERKOM)) {
- if (pci_enable_device(dev_a8))
- return (0);
- pci_ioaddr1 = pci_resource_start(dev_a8, 1);
- pci_irq = dev_a8->irq;
- pci_bus = dev_a8->bus->number;
- pci_device_fn = dev_a8->devfn;
- found = 1;
- break;
- }
- }
- if (!found) {
- printk(KERN_WARNING "HiSax: Scitel Quadro (%s): "
- "Card not found\n",
- sct_quadro_subtypes[cs->subtyp]);
- return (0);
- }
-#ifdef ATTEMPT_PCI_REMAPPING
-/* HACK: PLX revision 1 bug: PLX address bit 7 must not be set */
- if ((pci_ioaddr1 & 0x80) && (dev_a8->revision == 1)) {
- printk(KERN_WARNING "HiSax: Scitel Quadro (%s): "
- "PLX rev 1, remapping required!\n",
- sct_quadro_subtypes[cs->subtyp]);
- /* Restart PCI negotiation */
- pci_write_config_dword(dev_a8, PCI_BASE_ADDRESS_1, (u_int)-1);
- /* Move up by 0x80 byte */
- pci_ioaddr1 += 0x80;
- pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK;
- pci_write_config_dword(dev_a8, PCI_BASE_ADDRESS_1, pci_ioaddr1);
- dev_a8->resource[1].start = pci_ioaddr1;
- }
-#endif /* End HACK */
- }
- if (!pci_irq) { /* IRQ range check ?? */
- printk(KERN_WARNING "HiSax: Scitel Quadro (%s): No IRQ\n",
- sct_quadro_subtypes[cs->subtyp]);
- return (0);
- }
- pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_1, &pci_ioaddr1);
- pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_2, &pci_ioaddr2);
- pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_3, &pci_ioaddr3);
- pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_4, &pci_ioaddr4);
- pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_5, &pci_ioaddr5);
- if (!pci_ioaddr1 || !pci_ioaddr2 || !pci_ioaddr3 || !pci_ioaddr4 || !pci_ioaddr5) {
- printk(KERN_WARNING "HiSax: Scitel Quadro (%s): "
- "No IO base address(es)\n",
- sct_quadro_subtypes[cs->subtyp]);
- return (0);
- }
- pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK;
- pci_ioaddr2 &= PCI_BASE_ADDRESS_IO_MASK;
- pci_ioaddr3 &= PCI_BASE_ADDRESS_IO_MASK;
- pci_ioaddr4 &= PCI_BASE_ADDRESS_IO_MASK;
- pci_ioaddr5 &= PCI_BASE_ADDRESS_IO_MASK;
- /* Take over */
- cs->irq = pci_irq;
- cs->irq_flags |= IRQF_SHARED;
- /* pci_ioaddr1 is unique to all subdevices */
- /* pci_ioaddr2 is for the fourth subdevice only */
- /* pci_ioaddr3 is for the third subdevice only */
- /* pci_ioaddr4 is for the second subdevice only */
- /* pci_ioaddr5 is for the first subdevice only */
- cs->hw.ax.plx_adr = pci_ioaddr1;
- /* Enter all ipac_base addresses */
- switch (cs->subtyp) {
- case 1:
- cs->hw.ax.base = pci_ioaddr5 + 0x00;
- if (sct_alloc_io(pci_ioaddr1, 128))
- return (0);
- if (sct_alloc_io(pci_ioaddr5, 64))
- return (0);
- /* disable all IPAC */
- writereg(pci_ioaddr5, pci_ioaddr5 + 4,
- IPAC_MASK, 0xFF);
- writereg(pci_ioaddr4 + 0x08, pci_ioaddr4 + 0x0c,
- IPAC_MASK, 0xFF);
- writereg(pci_ioaddr3 + 0x10, pci_ioaddr3 + 0x14,
- IPAC_MASK, 0xFF);
- writereg(pci_ioaddr2 + 0x20, pci_ioaddr2 + 0x24,
- IPAC_MASK, 0xFF);
- break;
- case 2:
- cs->hw.ax.base = pci_ioaddr4 + 0x08;
- if (sct_alloc_io(pci_ioaddr4, 64))
- return (0);
- break;
- case 3:
- cs->hw.ax.base = pci_ioaddr3 + 0x10;
- if (sct_alloc_io(pci_ioaddr3, 64))
- return (0);
- break;
- case 4:
- cs->hw.ax.base = pci_ioaddr2 + 0x20;
- if (sct_alloc_io(pci_ioaddr2, 64))
- return (0);
- break;
- }
- /* For isac and hscx data path */
- cs->hw.ax.data_adr = cs->hw.ax.base + 4;
-
- printk(KERN_INFO "HiSax: Scitel Quadro (%s) configured at "
- "0x%.4lX, 0x%.4lX, 0x%.4lX and IRQ %d\n",
- sct_quadro_subtypes[cs->subtyp],
- cs->hw.ax.plx_adr,
- cs->hw.ax.base,
- cs->hw.ax.data_adr,
- cs->irq);
-
- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
-
- cs->readisac = &ReadISAC;
- cs->writeisac = &WriteISAC;
- cs->readisacfifo = &ReadISACfifo;
- cs->writeisacfifo = &WriteISACfifo;
-
- cs->BC_Read_Reg = &ReadHSCX;
- cs->BC_Write_Reg = &WriteHSCX;
- cs->BC_Send_Data = &hscx_fill_fifo;
- cs->cardmsg = &BKM_card_msg;
- cs->irq_func = &bkm_interrupt_ipac;
-
- printk(KERN_INFO "HiSax: Scitel Quadro (%s): IPAC Version %d\n",
- sct_quadro_subtypes[cs->subtyp],
- readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID));
- return (1);
-}
diff --git a/drivers/isdn/hisax/bkm_ax.h b/drivers/isdn/hisax/bkm_ax.h
deleted file mode 100644
index 27ff8a88679b..000000000000
--- a/drivers/isdn/hisax/bkm_ax.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/* $Id: bkm_ax.h,v 1.5.6.3 2001/09/23 22:24:46 kai Exp $
- *
- * low level decls for T-Berkom cards A4T and Scitel Quadro (4*S0, passive)
- *
- * Author Roland Klabunde
- * Copyright by Roland Klabunde <R.Klabunde@Berkom.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef __BKM_AX_H__
-#define __BKM_AX_H__
-
-/* Supported boards (subtypes) */
-#define SCT_1 1
-#define SCT_2 2
-#define SCT_3 3
-#define SCT_4 4
-#define BKM_A4T 5
-
-#define PLX_ADDR_PLX 0x14 /* Addr PLX configuration */
-#define PLX_ADDR_ISAC 0x18 /* Addr ISAC */
-#define PLX_ADDR_HSCX 0x1C /* Addr HSCX */
-#define PLX_ADDR_ALE 0x20 /* Addr ALE */
-#define PLX_ADDR_ALEPLUS 0x24 /* Next Addr behind ALE */
-
-#define PLX_SUBVEN 0x2C /* Offset SubVendor */
-#define PLX_SUBSYS 0x2E /* Offset SubSystem */
-
-
-/* Application specific registers I20 (Siemens SZB6120H) */
-typedef struct {
- /* Video front end horizontal configuration register */
- volatile u_int i20VFEHorzCfg; /* Offset 00 */
- /* Video front end vertical configuration register */
- volatile u_int i20VFEVertCfg; /* Offset 04 */
- /* Video front end scaler and pixel format register */
- volatile u_int i20VFEScaler; /* Offset 08 */
- /* Video display top register */
- volatile u_int i20VDispTop; /* Offset 0C */
- /* Video display bottom register */
- volatile u_int i20VDispBottom; /* Offset 10 */
- /* Video stride, status and frame grab register */
- volatile u_int i20VidFrameGrab;/* Offset 14 */
- /* Video display configuration register */
- volatile u_int i20VDispCfg; /* Offset 18 */
- /* Video masking map top */
- volatile u_int i20VMaskTop; /* Offset 1C */
- /* Video masking map bottom */
- volatile u_int i20VMaskBottom; /* Offset 20 */
- /* Overlay control register */
- volatile u_int i20OvlyControl; /* Offset 24 */
- /* System, PCI and general purpose pins control register */
- volatile u_int i20SysControl; /* Offset 28 */
-#define sysRESET 0x01000000 /* bit 24:Softreset (Low) */
- /* GPIO 4...0: Output fixed for our cfg! */
-#define sysCFG 0x000000E0 /* GPIO 7,6,5: Input */
- /* General purpose pins and guest bus control register */
- volatile u_int i20GuestControl;/* Offset 2C */
-#define guestWAIT_CFG 0x00005555 /* 4 PCI waits for all */
-#define guestISDN_INT_E 0x01000000 /* ISDN Int en (low) */
-#define guestVID_INT_E 0x02000000 /* Video interrupt en (low) */
-#define guestADI1_INT_R 0x04000000 /* ADI #1 int req (low) */
-#define guestADI2_INT_R 0x08000000 /* ADI #2 int req (low) */
-#define guestISDN_RES 0x10000000 /* ISDN reset bit (high) */
-#define guestADI1_INT_S 0x20000000 /* ADI #1 int pending (low) */
-#define guestADI2_INT_S 0x40000000 /* ADI #2 int pending (low) */
-#define guestISDN_INT_S 0x80000000 /* ISAC int pending (low) */
-
-#define g_A4T_JADE_RES 0x01000000 /* JADE Reset (High) */
-#define g_A4T_ISAR_RES 0x02000000 /* ISAR Reset (High) */
-#define g_A4T_ISAC_RES 0x04000000 /* ISAC Reset (High) */
-#define g_A4T_JADE_BOOTR 0x08000000 /* JADE enable boot SRAM (Low) NOT USED */
-#define g_A4T_ISAR_BOOTR 0x10000000 /* ISAR enable boot SRAM (Low) NOT USED */
-#define g_A4T_JADE_INT_S 0x20000000 /* JADE interrupt pnd (Low) */
-#define g_A4T_ISAR_INT_S 0x40000000 /* ISAR interrupt pnd (Low) */
-#define g_A4T_ISAC_INT_S 0x80000000 /* ISAC interrupt pnd (Low) */
-
- volatile u_int i20CodeSource; /* Offset 30 */
- volatile u_int i20CodeXferCtrl;/* Offset 34 */
- volatile u_int i20CodeMemPtr; /* Offset 38 */
-
- volatile u_int i20IntStatus; /* Offset 3C */
- volatile u_int i20IntCtrl; /* Offset 40 */
-#define intISDN 0x40000000 /* GIRQ1En (ISAC/ADI) (High) */
-#define intVID 0x20000000 /* GIRQ0En (VSYNC) (High) */
-#define intCOD 0x10000000 /* CodRepIrqEn (High) */
-#define intPCI 0x01000000 /* PCI IntA enable (High) */
-
- volatile u_int i20I2CCtrl; /* Offset 44 */
-} I20_REGISTER_FILE, *PI20_REGISTER_FILE;
-
-/*
- * Postoffice structure for A4T
- *
- */
-#define PO_OFFSET 0x00000200 /* Postoffice offset from base */
-
-#define GCS_0 0x00000000 /* Guest bus chip selects */
-#define GCS_1 0x00100000
-#define GCS_2 0x00200000
-#define GCS_3 0x00300000
-
-#define PO_READ 0x00000000 /* R/W from/to guest bus */
-#define PO_WRITE 0x00800000
-
-#define PO_PEND 0x02000000
-
-#define POSTOFFICE(postoffice) *(volatile unsigned int *)(postoffice)
-
-/* Wait unlimited (don't worry) */
-#define __WAITI20__(postoffice) \
- do { \
- while ((POSTOFFICE(postoffice) & PO_PEND)) ; \
- } while (0)
-
-#endif /* __BKM_AX_H__ */
diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c
deleted file mode 100644
index 9ee06328784c..000000000000
--- a/drivers/isdn/hisax/callc.c
+++ /dev/null
@@ -1,1792 +0,0 @@
-/* $Id: callc.c,v 2.59.2.4 2004/02/11 13:21:32 keil Exp $
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * For changes and modifications please read
- * Documentation/isdn/HiSax.cert
- *
- * based on the teles driver from Jan den Ouden
- *
- * Thanks to Jan den Ouden
- * Fritz Elfert
- *
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include "hisax.h"
-#include <linux/isdn/capicmd.h>
-
-const char *lli_revision = "$Revision: 2.59.2.4 $";
-
-extern struct IsdnCard cards[];
-
-static int init_b_st(struct Channel *chanp, int incoming);
-static void release_b_st(struct Channel *chanp);
-
-static struct Fsm callcfsm;
-static int chancount;
-
-/* experimental REJECT after ALERTING for CALLBACK to beat the 4s delay */
-#define ALERT_REJECT 0
-
-/* Value to delay the sending of the first B-channel packet after CONNECT
- * here is no value given by ITU, but experience shows that 300 ms will
- * work on many networks, if you or your other side is behind local exchanges
- * a greater value may be recommented. If the delay is to short the first paket
- * will be lost and autodetect on many comercial routers goes wrong !
- * You can adjust this value on runtime with
- * hisaxctrl <id> 2 <value>
- * value is in milliseconds
- */
-#define DEFAULT_B_DELAY 300
-
-/* Flags for remembering action done in lli */
-
-#define FLG_START_B 0
-
-/*
- * Find card with given driverId
- */
-static inline struct IsdnCardState *
-hisax_findcard(int driverid)
-{
- int i;
-
- for (i = 0; i < nrcards; i++)
- if (cards[i].cs)
- if (cards[i].cs->myid == driverid)
- return (cards[i].cs);
- return (struct IsdnCardState *) 0;
-}
-
-static __printf(3, 4) void
- link_debug(struct Channel *chanp, int direction, char *fmt, ...)
-{
- va_list args;
- char tmp[16];
-
- va_start(args, fmt);
- sprintf(tmp, "Ch%d %s ", chanp->chan,
- direction ? "LL->HL" : "HL->LL");
- VHiSax_putstatus(chanp->cs, tmp, fmt, args);
- va_end(args);
-}
-
-enum {
- ST_NULL, /* 0 inactive */
- ST_OUT_DIAL, /* 1 outgoing, SETUP send; awaiting confirm */
- ST_IN_WAIT_LL, /* 2 incoming call received; wait for LL confirm */
- ST_IN_ALERT_SENT, /* 3 incoming call received; ALERT send */
- ST_IN_WAIT_CONN_ACK, /* 4 incoming CONNECT send; awaiting CONN_ACK */
- ST_WAIT_BCONN, /* 5 CONNECT/CONN_ACK received, awaiting b-channel prot. estbl. */
- ST_ACTIVE, /* 6 active, b channel prot. established */
- ST_WAIT_BRELEASE, /* 7 call clear. (initiator), awaiting b channel prot. rel. */
- ST_WAIT_BREL_DISC, /* 8 call clear. (receiver), DISCONNECT req. received */
- ST_WAIT_DCOMMAND, /* 9 call clear. (receiver), awaiting DCHANNEL message */
- ST_WAIT_DRELEASE, /* 10 DISCONNECT sent, awaiting RELEASE */
- ST_WAIT_D_REL_CNF, /* 11 RELEASE sent, awaiting RELEASE confirm */
- ST_IN_PROCEED_SEND, /* 12 incoming call, proceeding send */
-};
-
-
-#define STATE_COUNT (ST_IN_PROCEED_SEND + 1)
-
-static char *strState[] =
-{
- "ST_NULL",
- "ST_OUT_DIAL",
- "ST_IN_WAIT_LL",
- "ST_IN_ALERT_SENT",
- "ST_IN_WAIT_CONN_ACK",
- "ST_WAIT_BCONN",
- "ST_ACTIVE",
- "ST_WAIT_BRELEASE",
- "ST_WAIT_BREL_DISC",
- "ST_WAIT_DCOMMAND",
- "ST_WAIT_DRELEASE",
- "ST_WAIT_D_REL_CNF",
- "ST_IN_PROCEED_SEND",
-};
-
-enum {
- EV_DIAL, /* 0 */
- EV_SETUP_CNF, /* 1 */
- EV_ACCEPTB, /* 2 */
- EV_DISCONNECT_IND, /* 3 */
- EV_RELEASE, /* 4 */
- EV_LEASED, /* 5 */
- EV_LEASED_REL, /* 6 */
- EV_SETUP_IND, /* 7 */
- EV_ACCEPTD, /* 8 */
- EV_SETUP_CMPL_IND, /* 9 */
- EV_BC_EST, /* 10 */
- EV_WRITEBUF, /* 11 */
- EV_HANGUP, /* 12 */
- EV_BC_REL, /* 13 */
- EV_CINF, /* 14 */
- EV_SUSPEND, /* 15 */
- EV_RESUME, /* 16 */
- EV_NOSETUP_RSP, /* 17 */
- EV_SETUP_ERR, /* 18 */
- EV_CONNECT_ERR, /* 19 */
- EV_PROCEED, /* 20 */
- EV_ALERT, /* 21 */
- EV_REDIR, /* 22 */
-};
-
-#define EVENT_COUNT (EV_REDIR + 1)
-
-static char *strEvent[] =
-{
- "EV_DIAL",
- "EV_SETUP_CNF",
- "EV_ACCEPTB",
- "EV_DISCONNECT_IND",
- "EV_RELEASE",
- "EV_LEASED",
- "EV_LEASED_REL",
- "EV_SETUP_IND",
- "EV_ACCEPTD",
- "EV_SETUP_CMPL_IND",
- "EV_BC_EST",
- "EV_WRITEBUF",
- "EV_HANGUP",
- "EV_BC_REL",
- "EV_CINF",
- "EV_SUSPEND",
- "EV_RESUME",
- "EV_NOSETUP_RSP",
- "EV_SETUP_ERR",
- "EV_CONNECT_ERR",
- "EV_PROCEED",
- "EV_ALERT",
- "EV_REDIR",
-};
-
-
-static inline void
-HL_LL(struct Channel *chanp, int command)
-{
- isdn_ctrl ic;
-
- ic.driver = chanp->cs->myid;
- ic.command = command;
- ic.arg = chanp->chan;
- chanp->cs->iif.statcallb(&ic);
-}
-
-static inline void
-lli_deliver_cause(struct Channel *chanp)
-{
- isdn_ctrl ic;
-
- if (!chanp->proc)
- return;
- if (chanp->proc->para.cause == NO_CAUSE)
- return;
- ic.driver = chanp->cs->myid;
- ic.command = ISDN_STAT_CAUSE;
- ic.arg = chanp->chan;
- if (chanp->cs->protocol == ISDN_PTYPE_EURO)
- sprintf(ic.parm.num, "E%02X%02X", chanp->proc->para.loc & 0x7f,
- chanp->proc->para.cause & 0x7f);
- else
- sprintf(ic.parm.num, "%02X%02X", chanp->proc->para.loc & 0x7f,
- chanp->proc->para.cause & 0x7f);
- chanp->cs->iif.statcallb(&ic);
-}
-
-static inline void
-lli_close(struct FsmInst *fi)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmChangeState(fi, ST_NULL);
- chanp->Flags = 0;
- chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
-}
-
-static void
-lli_leased_in(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
- int ret;
-
- if (!chanp->leased)
- return;
- chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan);
- FsmChangeState(fi, ST_IN_WAIT_LL);
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_ICALL_LEASED");
- ic.driver = chanp->cs->myid;
- ic.command = ((chanp->chan < 2) ? ISDN_STAT_ICALL : ISDN_STAT_ICALLW);
- ic.arg = chanp->chan;
- ic.parm.setup.si1 = 7;
- ic.parm.setup.si2 = 0;
- ic.parm.setup.plan = 0;
- ic.parm.setup.screen = 0;
- sprintf(ic.parm.setup.eazmsn, "%d", chanp->chan + 1);
- sprintf(ic.parm.setup.phone, "LEASED%d", chanp->cs->myid);
- ret = chanp->cs->iif.statcallb(&ic);
- if (chanp->debug & 1)
- link_debug(chanp, 1, "statcallb ret=%d", ret);
- if (!ret) {
- chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
- FsmChangeState(fi, ST_NULL);
- }
-}
-
-
-/*
- * Dial out
- */
-static void
-lli_init_bchan_out(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmChangeState(fi, ST_WAIT_BCONN);
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_DCONN");
- HL_LL(chanp, ISDN_STAT_DCONN);
- init_b_st(chanp, 0);
- chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL);
-}
-
-static void
-lli_prep_dialout(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmDelTimer(&chanp->drel_timer, 60);
- FsmDelTimer(&chanp->dial_timer, 73);
- chanp->l2_active_protocol = chanp->l2_protocol;
- chanp->incoming = 0;
- chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan);
- if (chanp->leased) {
- lli_init_bchan_out(fi, event, arg);
- } else {
- FsmChangeState(fi, ST_OUT_DIAL);
- chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | REQUEST, chanp);
- }
-}
-
-static void
-lli_resume(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmDelTimer(&chanp->drel_timer, 60);
- FsmDelTimer(&chanp->dial_timer, 73);
- chanp->l2_active_protocol = chanp->l2_protocol;
- chanp->incoming = 0;
- chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan);
- if (chanp->leased) {
- lli_init_bchan_out(fi, event, arg);
- } else {
- FsmChangeState(fi, ST_OUT_DIAL);
- chanp->d_st->lli.l4l3(chanp->d_st, CC_RESUME | REQUEST, chanp);
- }
-}
-
-static void
-lli_go_active(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
-
-
- FsmChangeState(fi, ST_ACTIVE);
- chanp->data_open = !0;
- if (chanp->bcs->conmsg)
- strcpy(ic.parm.num, chanp->bcs->conmsg);
- else
- ic.parm.num[0] = 0;
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_BCONN %s", ic.parm.num);
- ic.driver = chanp->cs->myid;
- ic.command = ISDN_STAT_BCONN;
- ic.arg = chanp->chan;
- chanp->cs->iif.statcallb(&ic);
- chanp->cs->cardmsg(chanp->cs, MDL_INFO_CONN, (void *) (long)chanp->chan);
-}
-
-
-/*
- * RESUME
- */
-
-/* incoming call */
-
-static void
-lli_deliver_call(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
- int ret;
-
- chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan);
- /*
- * Report incoming calls only once to linklevel, use CallFlags
- * which is set to 3 with each broadcast message in isdnl1.c
- * and resetted if a interface answered the STAT_ICALL.
- */
- if (1) { /* for only one TEI */
- FsmChangeState(fi, ST_IN_WAIT_LL);
- if (chanp->debug & 1)
- link_debug(chanp, 0, (chanp->chan < 2) ? "STAT_ICALL" : "STAT_ICALLW");
- ic.driver = chanp->cs->myid;
- ic.command = ((chanp->chan < 2) ? ISDN_STAT_ICALL : ISDN_STAT_ICALLW);
-
- ic.arg = chanp->chan;
- /*
- * No need to return "unknown" for calls without OAD,
- * cause that's handled in linklevel now (replaced by '0')
- */
- memcpy(&ic.parm.setup, &chanp->proc->para.setup, sizeof(setup_parm));
- ret = chanp->cs->iif.statcallb(&ic);
- if (chanp->debug & 1)
- link_debug(chanp, 1, "statcallb ret=%d", ret);
-
- switch (ret) {
- case 1: /* OK, someone likes this call */
- FsmDelTimer(&chanp->drel_timer, 61);
- FsmChangeState(fi, ST_IN_ALERT_SENT);
- chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
- break;
- case 5: /* direct redirect */
- case 4: /* Proceeding desired */
- FsmDelTimer(&chanp->drel_timer, 61);
- FsmChangeState(fi, ST_IN_PROCEED_SEND);
- chanp->d_st->lli.l4l3(chanp->d_st, CC_PROCEED_SEND | REQUEST, chanp->proc);
- if (ret == 5) {
- memcpy(&chanp->setup, &ic.parm.setup, sizeof(setup_parm));
- chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc);
- }
- break;
- case 2: /* Rejecting Call */
- break;
- case 3: /* incomplete number */
- FsmDelTimer(&chanp->drel_timer, 61);
- chanp->d_st->lli.l4l3(chanp->d_st, CC_MORE_INFO | REQUEST, chanp->proc);
- break;
- case 0: /* OK, nobody likes this call */
- default: /* statcallb problems */
- chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc);
- chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
- FsmChangeState(fi, ST_NULL);
- break;
- }
- } else {
- chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc);
- chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
- }
-}
-
-static void
-lli_send_dconnect(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmChangeState(fi, ST_IN_WAIT_CONN_ACK);
- chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc);
-}
-
-static void
-lli_send_alert(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmChangeState(fi, ST_IN_ALERT_SENT);
- chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
-}
-
-static void
-lli_send_redir(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc);
-}
-
-static void
-lli_init_bchan_in(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmChangeState(fi, ST_WAIT_BCONN);
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_DCONN");
- HL_LL(chanp, ISDN_STAT_DCONN);
- chanp->l2_active_protocol = chanp->l2_protocol;
- chanp->incoming = !0;
- init_b_st(chanp, !0);
- chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL);
-}
-
-static void
-lli_setup_rsp(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- if (chanp->leased) {
- lli_init_bchan_in(fi, event, arg);
- } else {
- FsmChangeState(fi, ST_IN_WAIT_CONN_ACK);
-#ifdef WANT_ALERT
- chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
-#endif
- chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc);
- }
-}
-
-/* Call suspend */
-
-static void
-lli_suspend(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->d_st->lli.l4l3(chanp->d_st, CC_SUSPEND | REQUEST, chanp->proc);
-}
-
-/* Call clearing */
-
-static void
-lli_leased_hup(struct FsmInst *fi, struct Channel *chanp)
-{
- isdn_ctrl ic;
-
- ic.driver = chanp->cs->myid;
- ic.command = ISDN_STAT_CAUSE;
- ic.arg = chanp->chan;
- sprintf(ic.parm.num, "L0010");
- chanp->cs->iif.statcallb(&ic);
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_DHUP");
- HL_LL(chanp, ISDN_STAT_DHUP);
- lli_close(fi);
-}
-
-static void
-lli_disconnect_req(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- if (chanp->leased) {
- lli_leased_hup(fi, chanp);
- } else {
- FsmChangeState(fi, ST_WAIT_DRELEASE);
- if (chanp->proc)
- chanp->proc->para.cause = 0x10; /* Normal Call Clearing */
- chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST,
- chanp->proc);
- }
-}
-
-static void
-lli_disconnect_reject(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- if (chanp->leased) {
- lli_leased_hup(fi, chanp);
- } else {
- FsmChangeState(fi, ST_WAIT_DRELEASE);
- if (chanp->proc)
- chanp->proc->para.cause = 0x15; /* Call Rejected */
- chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST,
- chanp->proc);
- }
-}
-
-static void
-lli_dhup_close(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- if (chanp->leased) {
- lli_leased_hup(fi, chanp);
- } else {
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_DHUP");
- lli_deliver_cause(chanp);
- HL_LL(chanp, ISDN_STAT_DHUP);
- lli_close(fi);
- }
-}
-
-static void
-lli_reject_req(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- if (chanp->leased) {
- lli_leased_hup(fi, chanp);
- return;
- }
-#ifndef ALERT_REJECT
- if (chanp->proc)
- chanp->proc->para.cause = 0x15; /* Call Rejected */
- chanp->d_st->lli.l4l3(chanp->d_st, CC_REJECT | REQUEST, chanp->proc);
- lli_dhup_close(fi, event, arg);
-#else
- FsmRestartTimer(&chanp->drel_timer, 40, EV_HANGUP, NULL, 63);
- FsmChangeState(fi, ST_IN_ALERT_SENT);
- chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
-#endif
-}
-
-static void
-lli_disconn_bchan(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->data_open = 0;
- FsmChangeState(fi, ST_WAIT_BRELEASE);
- chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
-}
-
-static void
-lli_start_disc(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- if (chanp->leased) {
- lli_leased_hup(fi, chanp);
- } else {
- lli_disconnect_req(fi, event, arg);
- }
-}
-
-static void
-lli_rel_b_disc(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- release_b_st(chanp);
- lli_start_disc(fi, event, arg);
-}
-
-static void
-lli_bhup_disc(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_BHUP");
- HL_LL(chanp, ISDN_STAT_BHUP);
- lli_rel_b_disc(fi, event, arg);
-}
-
-static void
-lli_bhup_rel_b(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmChangeState(fi, ST_WAIT_DCOMMAND);
- chanp->data_open = 0;
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_BHUP");
- HL_LL(chanp, ISDN_STAT_BHUP);
- release_b_st(chanp);
-}
-
-static void
-lli_release_bchan(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->data_open = 0;
- FsmChangeState(fi, ST_WAIT_BREL_DISC);
- chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
-}
-
-
-static void
-lli_rel_b_dhup(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- release_b_st(chanp);
- lli_dhup_close(fi, event, arg);
-}
-
-static void
-lli_bhup_dhup(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_BHUP");
- HL_LL(chanp, ISDN_STAT_BHUP);
- lli_rel_b_dhup(fi, event, arg);
-}
-
-static void
-lli_abort(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->data_open = 0;
- chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
- lli_bhup_dhup(fi, event, arg);
-}
-
-static void
-lli_release_req(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- if (chanp->leased) {
- lli_leased_hup(fi, chanp);
- } else {
- FsmChangeState(fi, ST_WAIT_D_REL_CNF);
- chanp->d_st->lli.l4l3(chanp->d_st, CC_RELEASE | REQUEST,
- chanp->proc);
- }
-}
-
-static void
-lli_rel_b_release_req(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- release_b_st(chanp);
- lli_release_req(fi, event, arg);
-}
-
-static void
-lli_bhup_release_req(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_BHUP");
- HL_LL(chanp, ISDN_STAT_BHUP);
- lli_rel_b_release_req(fi, event, arg);
-}
-
-
-/* processing charge info */
-static void
-lli_charge_info(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
-
- ic.driver = chanp->cs->myid;
- ic.command = ISDN_STAT_CINF;
- ic.arg = chanp->chan;
- sprintf(ic.parm.num, "%d", chanp->proc->para.chargeinfo);
- chanp->cs->iif.statcallb(&ic);
-}
-
-/* error procedures */
-
-static void
-lli_dchan_not_ready(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_DHUP");
- HL_LL(chanp, ISDN_STAT_DHUP);
-}
-
-static void
-lli_no_setup_rsp(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_DHUP");
- HL_LL(chanp, ISDN_STAT_DHUP);
- lli_close(fi);
-}
-
-static void
-lli_error(struct FsmInst *fi, int event, void *arg)
-{
- FsmChangeState(fi, ST_WAIT_DRELEASE);
-}
-
-static void
-lli_failure_l(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
-
- FsmChangeState(fi, ST_NULL);
- ic.driver = chanp->cs->myid;
- ic.command = ISDN_STAT_CAUSE;
- ic.arg = chanp->chan;
- sprintf(ic.parm.num, "L%02X%02X", 0, 0x2f);
- chanp->cs->iif.statcallb(&ic);
- HL_LL(chanp, ISDN_STAT_DHUP);
- chanp->Flags = 0;
- chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
-}
-
-static void
-lli_rel_b_fail(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- release_b_st(chanp);
- lli_failure_l(fi, event, arg);
-}
-
-static void
-lli_bhup_fail(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_BHUP");
- HL_LL(chanp, ISDN_STAT_BHUP);
- lli_rel_b_fail(fi, event, arg);
-}
-
-static void
-lli_failure_a(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->data_open = 0;
- chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
- lli_bhup_fail(fi, event, arg);
-}
-
-/* *INDENT-OFF* */
-static struct FsmNode fnlist[] __initdata =
-{
- {ST_NULL, EV_DIAL, lli_prep_dialout},
- {ST_NULL, EV_RESUME, lli_resume},
- {ST_NULL, EV_SETUP_IND, lli_deliver_call},
- {ST_NULL, EV_LEASED, lli_leased_in},
- {ST_OUT_DIAL, EV_SETUP_CNF, lli_init_bchan_out},
- {ST_OUT_DIAL, EV_HANGUP, lli_disconnect_req},
- {ST_OUT_DIAL, EV_DISCONNECT_IND, lli_release_req},
- {ST_OUT_DIAL, EV_RELEASE, lli_dhup_close},
- {ST_OUT_DIAL, EV_NOSETUP_RSP, lli_no_setup_rsp},
- {ST_OUT_DIAL, EV_SETUP_ERR, lli_error},
- {ST_IN_WAIT_LL, EV_LEASED_REL, lli_failure_l},
- {ST_IN_WAIT_LL, EV_ACCEPTD, lli_setup_rsp},
- {ST_IN_WAIT_LL, EV_HANGUP, lli_reject_req},
- {ST_IN_WAIT_LL, EV_DISCONNECT_IND, lli_release_req},
- {ST_IN_WAIT_LL, EV_RELEASE, lli_dhup_close},
- {ST_IN_WAIT_LL, EV_SETUP_IND, lli_deliver_call},
- {ST_IN_WAIT_LL, EV_SETUP_ERR, lli_error},
- {ST_IN_ALERT_SENT, EV_SETUP_CMPL_IND, lli_init_bchan_in},
- {ST_IN_ALERT_SENT, EV_ACCEPTD, lli_send_dconnect},
- {ST_IN_ALERT_SENT, EV_HANGUP, lli_disconnect_reject},
- {ST_IN_ALERT_SENT, EV_DISCONNECT_IND, lli_release_req},
- {ST_IN_ALERT_SENT, EV_RELEASE, lli_dhup_close},
- {ST_IN_ALERT_SENT, EV_REDIR, lli_send_redir},
- {ST_IN_PROCEED_SEND, EV_REDIR, lli_send_redir},
- {ST_IN_PROCEED_SEND, EV_ALERT, lli_send_alert},
- {ST_IN_PROCEED_SEND, EV_ACCEPTD, lli_send_dconnect},
- {ST_IN_PROCEED_SEND, EV_HANGUP, lli_disconnect_reject},
- {ST_IN_PROCEED_SEND, EV_DISCONNECT_IND, lli_dhup_close},
- {ST_IN_ALERT_SENT, EV_RELEASE, lli_dhup_close},
- {ST_IN_WAIT_CONN_ACK, EV_SETUP_CMPL_IND, lli_init_bchan_in},
- {ST_IN_WAIT_CONN_ACK, EV_HANGUP, lli_disconnect_req},
- {ST_IN_WAIT_CONN_ACK, EV_DISCONNECT_IND, lli_release_req},
- {ST_IN_WAIT_CONN_ACK, EV_RELEASE, lli_dhup_close},
- {ST_IN_WAIT_CONN_ACK, EV_CONNECT_ERR, lli_error},
- {ST_WAIT_BCONN, EV_BC_EST, lli_go_active},
- {ST_WAIT_BCONN, EV_BC_REL, lli_rel_b_disc},
- {ST_WAIT_BCONN, EV_HANGUP, lli_rel_b_disc},
- {ST_WAIT_BCONN, EV_DISCONNECT_IND, lli_rel_b_release_req},
- {ST_WAIT_BCONN, EV_RELEASE, lli_rel_b_dhup},
- {ST_WAIT_BCONN, EV_LEASED_REL, lli_rel_b_fail},
- {ST_WAIT_BCONN, EV_CINF, lli_charge_info},
- {ST_ACTIVE, EV_CINF, lli_charge_info},
- {ST_ACTIVE, EV_BC_REL, lli_bhup_rel_b},
- {ST_ACTIVE, EV_SUSPEND, lli_suspend},
- {ST_ACTIVE, EV_HANGUP, lli_disconn_bchan},
- {ST_ACTIVE, EV_DISCONNECT_IND, lli_release_bchan},
- {ST_ACTIVE, EV_RELEASE, lli_abort},
- {ST_ACTIVE, EV_LEASED_REL, lli_failure_a},
- {ST_WAIT_BRELEASE, EV_BC_REL, lli_bhup_disc},
- {ST_WAIT_BRELEASE, EV_DISCONNECT_IND, lli_bhup_release_req},
- {ST_WAIT_BRELEASE, EV_RELEASE, lli_bhup_dhup},
- {ST_WAIT_BRELEASE, EV_LEASED_REL, lli_bhup_fail},
- {ST_WAIT_BREL_DISC, EV_BC_REL, lli_bhup_release_req},
- {ST_WAIT_BREL_DISC, EV_RELEASE, lli_bhup_dhup},
- {ST_WAIT_DCOMMAND, EV_HANGUP, lli_start_disc},
- {ST_WAIT_DCOMMAND, EV_DISCONNECT_IND, lli_release_req},
- {ST_WAIT_DCOMMAND, EV_RELEASE, lli_dhup_close},
- {ST_WAIT_DCOMMAND, EV_LEASED_REL, lli_failure_l},
- {ST_WAIT_DRELEASE, EV_RELEASE, lli_dhup_close},
- {ST_WAIT_DRELEASE, EV_DIAL, lli_dchan_not_ready},
- /* ETS 300-104 16.1 */
- {ST_WAIT_D_REL_CNF, EV_RELEASE, lli_dhup_close},
- {ST_WAIT_D_REL_CNF, EV_DIAL, lli_dchan_not_ready},
-};
-/* *INDENT-ON* */
-
-int __init
-CallcNew(void)
-{
- callcfsm.state_count = STATE_COUNT;
- callcfsm.event_count = EVENT_COUNT;
- callcfsm.strEvent = strEvent;
- callcfsm.strState = strState;
- return FsmNew(&callcfsm, fnlist, ARRAY_SIZE(fnlist));
-}
-
-void
-CallcFree(void)
-{
- FsmFree(&callcfsm);
-}
-
-static void
-release_b_st(struct Channel *chanp)
-{
- struct PStack *st = chanp->b_st;
-
- if (test_and_clear_bit(FLG_START_B, &chanp->Flags)) {
- chanp->bcs->BC_Close(chanp->bcs);
- switch (chanp->l2_active_protocol) {
- case (ISDN_PROTO_L2_X75I):
- releasestack_isdnl2(st);
- break;
- case (ISDN_PROTO_L2_HDLC):
- case (ISDN_PROTO_L2_HDLC_56K):
- case (ISDN_PROTO_L2_TRANS):
- case (ISDN_PROTO_L2_MODEM):
- case (ISDN_PROTO_L2_FAX):
- releasestack_transl2(st);
- break;
- }
- }
-}
-
-static struct Channel
-*selectfreechannel(struct PStack *st, int bch)
-{
- struct IsdnCardState *cs = st->l1.hardware;
- struct Channel *chanp = st->lli.userdata;
- int i;
-
- if (test_bit(FLG_TWO_DCHAN, &cs->HW_Flags))
- i = 1;
- else
- i = 0;
-
- if (!bch) {
- i = 2; /* virtual channel */
- chanp += 2;
- }
-
- while (i < ((bch) ? cs->chanlimit : (2 + MAX_WAITING_CALLS))) {
- if (chanp->fi.state == ST_NULL)
- return (chanp);
- chanp++;
- i++;
- }
-
- if (bch) /* number of channels is limited */ {
- i = 2; /* virtual channel */
- chanp = st->lli.userdata;
- chanp += i;
- while (i < (2 + MAX_WAITING_CALLS)) {
- if (chanp->fi.state == ST_NULL)
- return (chanp);
- chanp++;
- i++;
- }
- }
- return (NULL);
-}
-
-static void stat_redir_result(struct IsdnCardState *cs, int chan, ulong result)
-{ isdn_ctrl ic;
-
- ic.driver = cs->myid;
- ic.command = ISDN_STAT_REDIR;
- ic.arg = chan;
- ic.parm.num[0] = result;
- cs->iif.statcallb(&ic);
-} /* stat_redir_result */
-
-static void
-dchan_l3l4(struct PStack *st, int pr, void *arg)
-{
- struct l3_process *pc = arg;
- struct IsdnCardState *cs = st->l1.hardware;
- struct Channel *chanp;
-
- if (!pc)
- return;
-
- if (pr == (CC_SETUP | INDICATION)) {
- if (!(chanp = selectfreechannel(pc->st, pc->para.bchannel))) {
- pc->para.cause = 0x11; /* User busy */
- pc->st->lli.l4l3(pc->st, CC_REJECT | REQUEST, pc);
- } else {
- chanp->proc = pc;
- pc->chan = chanp;
- FsmEvent(&chanp->fi, EV_SETUP_IND, NULL);
- }
- return;
- }
- if (!(chanp = pc->chan))
- return;
-
- switch (pr) {
- case (CC_MORE_INFO | INDICATION):
- FsmEvent(&chanp->fi, EV_SETUP_IND, NULL);
- break;
- case (CC_DISCONNECT | INDICATION):
- FsmEvent(&chanp->fi, EV_DISCONNECT_IND, NULL);
- break;
- case (CC_RELEASE | CONFIRM):
- FsmEvent(&chanp->fi, EV_RELEASE, NULL);
- break;
- case (CC_SUSPEND | CONFIRM):
- FsmEvent(&chanp->fi, EV_RELEASE, NULL);
- break;
- case (CC_RESUME | CONFIRM):
- FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL);
- break;
- case (CC_RESUME_ERR):
- FsmEvent(&chanp->fi, EV_RELEASE, NULL);
- break;
- case (CC_RELEASE | INDICATION):
- FsmEvent(&chanp->fi, EV_RELEASE, NULL);
- break;
- case (CC_SETUP_COMPL | INDICATION):
- FsmEvent(&chanp->fi, EV_SETUP_CMPL_IND, NULL);
- break;
- case (CC_SETUP | CONFIRM):
- FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL);
- break;
- case (CC_CHARGE | INDICATION):
- FsmEvent(&chanp->fi, EV_CINF, NULL);
- break;
- case (CC_NOSETUP_RSP):
- FsmEvent(&chanp->fi, EV_NOSETUP_RSP, NULL);
- break;
- case (CC_SETUP_ERR):
- FsmEvent(&chanp->fi, EV_SETUP_ERR, NULL);
- break;
- case (CC_CONNECT_ERR):
- FsmEvent(&chanp->fi, EV_CONNECT_ERR, NULL);
- break;
- case (CC_RELEASE_ERR):
- FsmEvent(&chanp->fi, EV_RELEASE, NULL);
- break;
- case (CC_PROCEED_SEND | INDICATION):
- case (CC_PROCEEDING | INDICATION):
- case (CC_ALERTING | INDICATION):
- case (CC_PROGRESS | INDICATION):
- case (CC_NOTIFY | INDICATION):
- break;
- case (CC_REDIR | INDICATION):
- stat_redir_result(cs, chanp->chan, pc->redir_result);
- break;
- default:
- if (chanp->debug & 0x800) {
- HiSax_putstatus(chanp->cs, "Ch",
- "%d L3->L4 unknown primitiv %#x",
- chanp->chan, pr);
- }
- }
-}
-
-static void
-dummy_pstack(struct PStack *st, int pr, void *arg) {
- printk(KERN_WARNING"call to dummy_pstack pr=%04x arg %lx\n", pr, (long)arg);
-}
-
-static int
-init_PStack(struct PStack **stp) {
- *stp = kmalloc(sizeof(struct PStack), GFP_KERNEL);
- if (!*stp)
- return -ENOMEM;
- (*stp)->next = NULL;
- (*stp)->l1.l1l2 = dummy_pstack;
- (*stp)->l1.l1hw = dummy_pstack;
- (*stp)->l1.l1tei = dummy_pstack;
- (*stp)->l2.l2tei = dummy_pstack;
- (*stp)->l2.l2l1 = dummy_pstack;
- (*stp)->l2.l2l3 = dummy_pstack;
- (*stp)->l3.l3l2 = dummy_pstack;
- (*stp)->l3.l3ml3 = dummy_pstack;
- (*stp)->l3.l3l4 = dummy_pstack;
- (*stp)->lli.l4l3 = dummy_pstack;
- (*stp)->ma.layer = dummy_pstack;
- return 0;
-}
-
-static int
-init_d_st(struct Channel *chanp)
-{
- struct PStack *st;
- struct IsdnCardState *cs = chanp->cs;
- char tmp[16];
- int err;
-
- err = init_PStack(&chanp->d_st);
- if (err)
- return err;
- st = chanp->d_st;
- st->next = NULL;
- HiSax_addlist(cs, st);
- setstack_HiSax(st, cs);
- st->l2.sap = 0;
- st->l2.tei = -1;
- st->l2.flag = 0;
- test_and_set_bit(FLG_MOD128, &st->l2.flag);
- test_and_set_bit(FLG_LAPD, &st->l2.flag);
- test_and_set_bit(FLG_ORIG, &st->l2.flag);
- st->l2.maxlen = MAX_DFRAME_LEN;
- st->l2.window = 1;
- st->l2.T200 = 1000; /* 1000 milliseconds */
- st->l2.N200 = 3; /* try 3 times */
- st->l2.T203 = 10000; /* 10000 milliseconds */
- if (test_bit(FLG_TWO_DCHAN, &cs->HW_Flags))
- sprintf(tmp, "DCh%d Q.921 ", chanp->chan);
- else
- sprintf(tmp, "DCh Q.921 ");
- setstack_isdnl2(st, tmp);
- setstack_l3dc(st, chanp);
- st->lli.userdata = chanp;
- st->l3.l3l4 = dchan_l3l4;
-
- return 0;
-}
-
-static __printf(2, 3) void
- callc_debug(struct FsmInst *fi, char *fmt, ...)
-{
- va_list args;
- struct Channel *chanp = fi->userdata;
- char tmp[16];
-
- va_start(args, fmt);
- sprintf(tmp, "Ch%d callc ", chanp->chan);
- VHiSax_putstatus(chanp->cs, tmp, fmt, args);
- va_end(args);
-}
-
-static int
-init_chan(int chan, struct IsdnCardState *csta)
-{
- struct Channel *chanp = csta->channel + chan;
- int err;
-
- chanp->cs = csta;
- chanp->bcs = csta->bcs + chan;
- chanp->chan = chan;
- chanp->incoming = 0;
- chanp->debug = 0;
- chanp->Flags = 0;
- chanp->leased = 0;
- err = init_PStack(&chanp->b_st);
- if (err)
- return err;
- chanp->b_st->l1.delay = DEFAULT_B_DELAY;
- chanp->fi.fsm = &callcfsm;
- chanp->fi.state = ST_NULL;
- chanp->fi.debug = 0;
- chanp->fi.userdata = chanp;
- chanp->fi.printdebug = callc_debug;
- FsmInitTimer(&chanp->fi, &chanp->dial_timer);
- FsmInitTimer(&chanp->fi, &chanp->drel_timer);
- if (!chan || (test_bit(FLG_TWO_DCHAN, &csta->HW_Flags) && chan < 2)) {
- err = init_d_st(chanp);
- if (err)
- return err;
- } else {
- chanp->d_st = csta->channel->d_st;
- }
- chanp->data_open = 0;
- return 0;
-}
-
-int
-CallcNewChan(struct IsdnCardState *csta) {
- int i, err;
-
- chancount += 2;
- err = init_chan(0, csta);
- if (err)
- return err;
- err = init_chan(1, csta);
- if (err)
- return err;
- printk(KERN_INFO "HiSax: 2 channels added\n");
-
- for (i = 0; i < MAX_WAITING_CALLS; i++) {
- err = init_chan(i + 2, csta);
- if (err)
- return err;
- }
- printk(KERN_INFO "HiSax: MAX_WAITING_CALLS added\n");
- if (test_bit(FLG_PTP, &csta->channel->d_st->l2.flag)) {
- printk(KERN_INFO "LAYER2 WATCHING ESTABLISH\n");
- csta->channel->d_st->lli.l4l3(csta->channel->d_st,
- DL_ESTABLISH | REQUEST, NULL);
- }
- return (0);
-}
-
-static void
-release_d_st(struct Channel *chanp)
-{
- struct PStack *st = chanp->d_st;
-
- if (!st)
- return;
- releasestack_isdnl2(st);
- releasestack_isdnl3(st);
- HiSax_rmlist(st->l1.hardware, st);
- kfree(st);
- chanp->d_st = NULL;
-}
-
-void
-CallcFreeChan(struct IsdnCardState *csta)
-{
- int i;
-
- for (i = 0; i < 2; i++) {
- FsmDelTimer(&csta->channel[i].drel_timer, 74);
- FsmDelTimer(&csta->channel[i].dial_timer, 75);
- if (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags))
- release_d_st(csta->channel + i);
- if (csta->channel[i].b_st) {
- release_b_st(csta->channel + i);
- kfree(csta->channel[i].b_st);
- csta->channel[i].b_st = NULL;
- } else
- printk(KERN_WARNING "CallcFreeChan b_st ch%d already freed\n", i);
- if (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) {
- release_d_st(csta->channel + i);
- } else
- csta->channel[i].d_st = NULL;
- }
-}
-
-static void
-lldata_handler(struct PStack *st, int pr, void *arg)
-{
- struct Channel *chanp = (struct Channel *) st->lli.userdata;
- struct sk_buff *skb = arg;
-
- switch (pr) {
- case (DL_DATA | INDICATION):
- if (chanp->data_open) {
- if (chanp->debug & 0x800)
- link_debug(chanp, 0, "lldata: %d", skb->len);
- chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb);
- } else {
- link_debug(chanp, 0, "lldata: channel not open");
- dev_kfree_skb(skb);
- }
- break;
- case (DL_ESTABLISH | INDICATION):
- case (DL_ESTABLISH | CONFIRM):
- FsmEvent(&chanp->fi, EV_BC_EST, NULL);
- break;
- case (DL_RELEASE | INDICATION):
- case (DL_RELEASE | CONFIRM):
- FsmEvent(&chanp->fi, EV_BC_REL, NULL);
- break;
- default:
- printk(KERN_WARNING "lldata_handler unknown primitive %#x\n",
- pr);
- break;
- }
-}
-
-static void
-lltrans_handler(struct PStack *st, int pr, void *arg)
-{
- struct Channel *chanp = (struct Channel *) st->lli.userdata;
- struct sk_buff *skb = arg;
-
- switch (pr) {
- case (PH_DATA | INDICATION):
- if (chanp->data_open) {
- if (chanp->debug & 0x800)
- link_debug(chanp, 0, "lltrans: %d", skb->len);
- chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb);
- } else {
- link_debug(chanp, 0, "lltrans: channel not open");
- dev_kfree_skb(skb);
- }
- break;
- case (PH_ACTIVATE | INDICATION):
- case (PH_ACTIVATE | CONFIRM):
- FsmEvent(&chanp->fi, EV_BC_EST, NULL);
- break;
- case (PH_DEACTIVATE | INDICATION):
- case (PH_DEACTIVATE | CONFIRM):
- FsmEvent(&chanp->fi, EV_BC_REL, NULL);
- break;
- default:
- printk(KERN_WARNING "lltrans_handler unknown primitive %#x\n",
- pr);
- break;
- }
-}
-
-void
-lli_writewakeup(struct PStack *st, int len)
-{
- struct Channel *chanp = st->lli.userdata;
- isdn_ctrl ic;
-
- if (chanp->debug & 0x800)
- link_debug(chanp, 0, "llwakeup: %d", len);
- ic.driver = chanp->cs->myid;
- ic.command = ISDN_STAT_BSENT;
- ic.arg = chanp->chan;
- ic.parm.length = len;
- chanp->cs->iif.statcallb(&ic);
-}
-
-static int
-init_b_st(struct Channel *chanp, int incoming)
-{
- struct PStack *st = chanp->b_st;
- struct IsdnCardState *cs = chanp->cs;
- char tmp[16];
-
- st->l1.hardware = cs;
- if (chanp->leased)
- st->l1.bc = chanp->chan & 1;
- else
- st->l1.bc = chanp->proc->para.bchannel - 1;
- switch (chanp->l2_active_protocol) {
- case (ISDN_PROTO_L2_X75I):
- case (ISDN_PROTO_L2_HDLC):
- st->l1.mode = L1_MODE_HDLC;
- break;
- case (ISDN_PROTO_L2_HDLC_56K):
- st->l1.mode = L1_MODE_HDLC_56K;
- break;
- case (ISDN_PROTO_L2_TRANS):
- st->l1.mode = L1_MODE_TRANS;
- break;
- case (ISDN_PROTO_L2_MODEM):
- st->l1.mode = L1_MODE_V32;
- break;
- case (ISDN_PROTO_L2_FAX):
- st->l1.mode = L1_MODE_FAX;
- break;
- }
- chanp->bcs->conmsg = NULL;
- if (chanp->bcs->BC_SetStack(st, chanp->bcs))
- return (-1);
- st->l2.flag = 0;
- test_and_set_bit(FLG_LAPB, &st->l2.flag);
- st->l2.maxlen = MAX_DATA_SIZE;
- if (!incoming)
- test_and_set_bit(FLG_ORIG, &st->l2.flag);
- st->l2.T200 = 1000; /* 1000 milliseconds */
- st->l2.window = 7;
- st->l2.N200 = 4; /* try 4 times */
- st->l2.T203 = 5000; /* 5000 milliseconds */
- st->l3.debug = 0;
- switch (chanp->l2_active_protocol) {
- case (ISDN_PROTO_L2_X75I):
- sprintf(tmp, "Ch%d X.75", chanp->chan);
- setstack_isdnl2(st, tmp);
- setstack_l3bc(st, chanp);
- st->l2.l2l3 = lldata_handler;
- st->lli.userdata = chanp;
- test_and_clear_bit(FLG_LLI_L1WAKEUP, &st->lli.flag);
- test_and_set_bit(FLG_LLI_L2WAKEUP, &st->lli.flag);
- st->l2.l2m.debug = chanp->debug & 16;
- st->l2.debug = chanp->debug & 64;
- break;
- case (ISDN_PROTO_L2_HDLC):
- case (ISDN_PROTO_L2_HDLC_56K):
- case (ISDN_PROTO_L2_TRANS):
- case (ISDN_PROTO_L2_MODEM):
- case (ISDN_PROTO_L2_FAX):
- st->l1.l1l2 = lltrans_handler;
- st->lli.userdata = chanp;
- test_and_set_bit(FLG_LLI_L1WAKEUP, &st->lli.flag);
- test_and_clear_bit(FLG_LLI_L2WAKEUP, &st->lli.flag);
- setstack_transl2(st);
- setstack_l3bc(st, chanp);
- break;
- }
- test_and_set_bit(FLG_START_B, &chanp->Flags);
- return (0);
-}
-
-static void
-leased_l4l3(struct PStack *st, int pr, void *arg)
-{
- struct Channel *chanp = (struct Channel *) st->lli.userdata;
- struct sk_buff *skb = arg;
-
- switch (pr) {
- case (DL_DATA | REQUEST):
- link_debug(chanp, 0, "leased line d-channel DATA");
- dev_kfree_skb(skb);
- break;
- case (DL_ESTABLISH | REQUEST):
- st->l2.l2l1(st, PH_ACTIVATE | REQUEST, NULL);
- break;
- case (DL_RELEASE | REQUEST):
- break;
- default:
- printk(KERN_WARNING "transd_l4l3 unknown primitive %#x\n",
- pr);
- break;
- }
-}
-
-static void
-leased_l1l2(struct PStack *st, int pr, void *arg)
-{
- struct Channel *chanp = (struct Channel *) st->lli.userdata;
- struct sk_buff *skb = arg;
- int i, event = EV_LEASED_REL;
-
- switch (pr) {
- case (PH_DATA | INDICATION):
- link_debug(chanp, 0, "leased line d-channel DATA");
- dev_kfree_skb(skb);
- break;
- case (PH_ACTIVATE | INDICATION):
- case (PH_ACTIVATE | CONFIRM):
- event = EV_LEASED;
- /* fall through */
- case (PH_DEACTIVATE | INDICATION):
- case (PH_DEACTIVATE | CONFIRM):
- if (test_bit(FLG_TWO_DCHAN, &chanp->cs->HW_Flags))
- i = 1;
- else
- i = 0;
- while (i < 2) {
- FsmEvent(&chanp->fi, event, NULL);
- chanp++;
- i++;
- }
- break;
- default:
- printk(KERN_WARNING
- "transd_l1l2 unknown primitive %#x\n", pr);
- break;
- }
-}
-
-static void
-distr_debug(struct IsdnCardState *csta, int debugflags)
-{
- int i;
- struct Channel *chanp = csta->channel;
-
- for (i = 0; i < (2 + MAX_WAITING_CALLS); i++) {
- chanp[i].debug = debugflags;
- chanp[i].fi.debug = debugflags & 2;
- chanp[i].d_st->l2.l2m.debug = debugflags & 8;
- chanp[i].b_st->l2.l2m.debug = debugflags & 0x10;
- chanp[i].d_st->l2.debug = debugflags & 0x20;
- chanp[i].b_st->l2.debug = debugflags & 0x40;
- chanp[i].d_st->l3.l3m.debug = debugflags & 0x80;
- chanp[i].b_st->l3.l3m.debug = debugflags & 0x100;
- chanp[i].b_st->ma.tei_m.debug = debugflags & 0x200;
- chanp[i].b_st->ma.debug = debugflags & 0x200;
- chanp[i].d_st->l1.l1m.debug = debugflags & 0x1000;
- chanp[i].b_st->l1.l1m.debug = debugflags & 0x2000;
- }
- if (debugflags & 4)
- csta->debug |= DEB_DLOG_HEX;
- else
- csta->debug &= ~DEB_DLOG_HEX;
-}
-
-static char tmpbuf[256];
-
-static void
-capi_debug(struct Channel *chanp, capi_msg *cm)
-{
- char *t = tmpbuf;
-
- t += QuickHex(t, (u_char *)cm, (cm->Length > 50) ? 50 : cm->Length);
- t--;
- *t = 0;
- HiSax_putstatus(chanp->cs, "Ch", "%d CAPIMSG %s", chanp->chan, tmpbuf);
-}
-
-static void
-lli_got_fac_req(struct Channel *chanp, capi_msg *cm) {
- if ((cm->para[0] != 3) || (cm->para[1] != 0))
- return;
- if (cm->para[2] < 3)
- return;
- if (cm->para[4] != 0)
- return;
- switch (cm->para[3]) {
- case 4: /* Suspend */
- strncpy(chanp->setup.phone, &cm->para[5], cm->para[5] + 1);
- FsmEvent(&chanp->fi, EV_SUSPEND, cm);
- break;
- case 5: /* Resume */
- strncpy(chanp->setup.phone, &cm->para[5], cm->para[5] + 1);
- if (chanp->fi.state == ST_NULL) {
- FsmEvent(&chanp->fi, EV_RESUME, cm);
- } else {
- FsmDelTimer(&chanp->dial_timer, 72);
- FsmAddTimer(&chanp->dial_timer, 80, EV_RESUME, cm, 73);
- }
- break;
- }
-}
-
-static void
-lli_got_manufacturer(struct Channel *chanp, struct IsdnCardState *cs, capi_msg *cm) {
- if ((cs->typ == ISDN_CTYPE_ELSA) || (cs->typ == ISDN_CTYPE_ELSA_PNP) ||
- (cs->typ == ISDN_CTYPE_ELSA_PCI)) {
- if (cs->hw.elsa.MFlag) {
- cs->cardmsg(cs, CARD_AUX_IND, cm->para);
- }
- }
-}
-
-
-/***************************************************************/
-/* Limit the available number of channels for the current card */
-/***************************************************************/
-static int
-set_channel_limit(struct IsdnCardState *cs, int chanmax)
-{
- isdn_ctrl ic;
- int i, ii;
-
- if ((chanmax < 0) || (chanmax > 2))
- return (-EINVAL);
- cs->chanlimit = 0;
- for (ii = 0; ii < 2; ii++) {
- ic.driver = cs->myid;
- ic.command = ISDN_STAT_DISCH;
- ic.arg = ii;
- if (ii >= chanmax)
- ic.parm.num[0] = 0; /* disabled */
- else
- ic.parm.num[0] = 1; /* enabled */
- i = cs->iif.statcallb(&ic);
- if (i) return (-EINVAL);
- if (ii < chanmax)
- cs->chanlimit++;
- }
- return (0);
-} /* set_channel_limit */
-
-int
-HiSax_command(isdn_ctrl *ic)
-{
- struct IsdnCardState *csta = hisax_findcard(ic->driver);
- struct PStack *st;
- struct Channel *chanp;
- int i;
- u_int num;
-
- if (!csta) {
- printk(KERN_ERR
- "HiSax: if_command %d called with invalid driverId %d!\n",
- ic->command, ic->driver);
- return -ENODEV;
- }
- switch (ic->command) {
- case (ISDN_CMD_SETEAZ):
- chanp = csta->channel + ic->arg;
- break;
- case (ISDN_CMD_SETL2):
- chanp = csta->channel + (ic->arg & 0xff);
- if (chanp->debug & 1)
- link_debug(chanp, 1, "SETL2 card %d %ld",
- csta->cardnr + 1, ic->arg >> 8);
- chanp->l2_protocol = ic->arg >> 8;
- break;
- case (ISDN_CMD_SETL3):
- chanp = csta->channel + (ic->arg & 0xff);
- if (chanp->debug & 1)
- link_debug(chanp, 1, "SETL3 card %d %ld",
- csta->cardnr + 1, ic->arg >> 8);
- chanp->l3_protocol = ic->arg >> 8;
- break;
- case (ISDN_CMD_DIAL):
- chanp = csta->channel + (ic->arg & 0xff);
- if (chanp->debug & 1)
- link_debug(chanp, 1, "DIAL %s -> %s (%d,%d)",
- ic->parm.setup.eazmsn, ic->parm.setup.phone,
- ic->parm.setup.si1, ic->parm.setup.si2);
- memcpy(&chanp->setup, &ic->parm.setup, sizeof(setup_parm));
- if (!strcmp(chanp->setup.eazmsn, "0"))
- chanp->setup.eazmsn[0] = '\0';
- /* this solution is dirty and may be change, if
- * we make a callreference based callmanager */
- if (chanp->fi.state == ST_NULL) {
- FsmEvent(&chanp->fi, EV_DIAL, NULL);
- } else {
- FsmDelTimer(&chanp->dial_timer, 70);
- FsmAddTimer(&chanp->dial_timer, 50, EV_DIAL, NULL, 71);
- }
- break;
- case (ISDN_CMD_ACCEPTB):
- chanp = csta->channel + ic->arg;
- if (chanp->debug & 1)
- link_debug(chanp, 1, "ACCEPTB");
- FsmEvent(&chanp->fi, EV_ACCEPTB, NULL);
- break;
- case (ISDN_CMD_ACCEPTD):
- chanp = csta->channel + ic->arg;
- memcpy(&chanp->setup, &ic->parm.setup, sizeof(setup_parm));
- if (chanp->debug & 1)
- link_debug(chanp, 1, "ACCEPTD");
- FsmEvent(&chanp->fi, EV_ACCEPTD, NULL);
- break;
- case (ISDN_CMD_HANGUP):
- chanp = csta->channel + ic->arg;
- if (chanp->debug & 1)
- link_debug(chanp, 1, "HANGUP");
- FsmEvent(&chanp->fi, EV_HANGUP, NULL);
- break;
- case (CAPI_PUT_MESSAGE):
- chanp = csta->channel + ic->arg;
- if (chanp->debug & 1)
- capi_debug(chanp, &ic->parm.cmsg);
- if (ic->parm.cmsg.Length < 8)
- break;
- switch (ic->parm.cmsg.Command) {
- case CAPI_FACILITY:
- if (ic->parm.cmsg.Subcommand == CAPI_REQ)
- lli_got_fac_req(chanp, &ic->parm.cmsg);
- break;
- case CAPI_MANUFACTURER:
- if (ic->parm.cmsg.Subcommand == CAPI_REQ)
- lli_got_manufacturer(chanp, csta, &ic->parm.cmsg);
- break;
- default:
- break;
- }
- break;
- case (ISDN_CMD_IOCTL):
- switch (ic->arg) {
- case (0):
- num = *(unsigned int *) ic->parm.num;
- HiSax_reportcard(csta->cardnr, num);
- break;
- case (1):
- num = *(unsigned int *) ic->parm.num;
- distr_debug(csta, num);
- printk(KERN_DEBUG "HiSax: debugging flags card %d set to %x\n",
- csta->cardnr + 1, num);
- HiSax_putstatus(csta, "debugging flags ",
- "card %d set to %x", csta->cardnr + 1, num);
- break;
- case (2):
- num = *(unsigned int *) ic->parm.num;
- csta->channel[0].b_st->l1.delay = num;
- csta->channel[1].b_st->l1.delay = num;
- HiSax_putstatus(csta, "delay ", "card %d set to %d ms",
- csta->cardnr + 1, num);
- printk(KERN_DEBUG "HiSax: delay card %d set to %d ms\n",
- csta->cardnr + 1, num);
- break;
- case (5): /* set card in leased mode */
- num = *(unsigned int *) ic->parm.num;
- if ((num < 1) || (num > 2)) {
- HiSax_putstatus(csta, "Set LEASED ",
- "wrong channel %d", num);
- printk(KERN_WARNING "HiSax: Set LEASED wrong channel %d\n",
- num);
- } else {
- num--;
- chanp = csta->channel + num;
- chanp->leased = 1;
- HiSax_putstatus(csta, "Card",
- "%d channel %d set leased mode\n",
- csta->cardnr + 1, num + 1);
- chanp->d_st->l1.l1l2 = leased_l1l2;
- chanp->d_st->lli.l4l3 = leased_l4l3;
- chanp->d_st->lli.l4l3(chanp->d_st,
- DL_ESTABLISH | REQUEST, NULL);
- }
- break;
- case (6): /* set B-channel test loop */
- num = *(unsigned int *) ic->parm.num;
- if (csta->stlist)
- csta->stlist->l2.l2l1(csta->stlist,
- PH_TESTLOOP | REQUEST, (void *) (long)num);
- break;
- case (7): /* set card in PTP mode */
- num = *(unsigned int *) ic->parm.num;
- if (test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) {
- printk(KERN_ERR "HiSax PTP mode only with one TEI possible\n");
- } else if (num) {
- test_and_set_bit(FLG_PTP, &csta->channel[0].d_st->l2.flag);
- test_and_set_bit(FLG_FIXED_TEI, &csta->channel[0].d_st->l2.flag);
- csta->channel[0].d_st->l2.tei = 0;
- HiSax_putstatus(csta, "set card ", "in PTP mode");
- printk(KERN_DEBUG "HiSax: set card in PTP mode\n");
- printk(KERN_INFO "LAYER2 WATCHING ESTABLISH\n");
- csta->channel[0].d_st->lli.l4l3(csta->channel[0].d_st,
- DL_ESTABLISH | REQUEST, NULL);
- } else {
- test_and_clear_bit(FLG_PTP, &csta->channel[0].d_st->l2.flag);
- test_and_clear_bit(FLG_FIXED_TEI, &csta->channel[0].d_st->l2.flag);
- HiSax_putstatus(csta, "set card ", "in PTMP mode");
- printk(KERN_DEBUG "HiSax: set card in PTMP mode\n");
- }
- break;
- case (8): /* set card in FIXED TEI mode */
- num = *(unsigned int *)ic->parm.num;
- chanp = csta->channel + (num & 1);
- num = num >> 1;
- if (num == 127) {
- test_and_clear_bit(FLG_FIXED_TEI, &chanp->d_st->l2.flag);
- chanp->d_st->l2.tei = -1;
- HiSax_putstatus(csta, "set card ", "in VAR TEI mode");
- printk(KERN_DEBUG "HiSax: set card in VAR TEI mode\n");
- } else {
- test_and_set_bit(FLG_FIXED_TEI, &chanp->d_st->l2.flag);
- chanp->d_st->l2.tei = num;
- HiSax_putstatus(csta, "set card ", "in FIXED TEI (%d) mode", num);
- printk(KERN_DEBUG "HiSax: set card in FIXED TEI (%d) mode\n",
- num);
- }
- chanp->d_st->lli.l4l3(chanp->d_st,
- DL_ESTABLISH | REQUEST, NULL);
- break;
- case (11):
- num = csta->debug & DEB_DLOG_HEX;
- csta->debug = *(unsigned int *) ic->parm.num;
- csta->debug |= num;
- HiSax_putstatus(cards[0].cs, "l1 debugging ",
- "flags card %d set to %x",
- csta->cardnr + 1, csta->debug);
- printk(KERN_DEBUG "HiSax: l1 debugging flags card %d set to %x\n",
- csta->cardnr + 1, csta->debug);
- break;
- case (13):
- csta->channel[0].d_st->l3.debug = *(unsigned int *) ic->parm.num;
- csta->channel[1].d_st->l3.debug = *(unsigned int *) ic->parm.num;
- HiSax_putstatus(cards[0].cs, "l3 debugging ",
- "flags card %d set to %x\n", csta->cardnr + 1,
- *(unsigned int *) ic->parm.num);
- printk(KERN_DEBUG "HiSax: l3 debugging flags card %d set to %x\n",
- csta->cardnr + 1, *(unsigned int *) ic->parm.num);
- break;
- case (10):
- i = *(unsigned int *) ic->parm.num;
- return (set_channel_limit(csta, i));
- default:
- if (csta->auxcmd)
- return (csta->auxcmd(csta, ic));
- printk(KERN_DEBUG "HiSax: invalid ioctl %d\n",
- (int) ic->arg);
- return (-EINVAL);
- }
- break;
-
- case (ISDN_CMD_PROCEED):
- chanp = csta->channel + ic->arg;
- if (chanp->debug & 1)
- link_debug(chanp, 1, "PROCEED");
- FsmEvent(&chanp->fi, EV_PROCEED, NULL);
- break;
-
- case (ISDN_CMD_ALERT):
- chanp = csta->channel + ic->arg;
- if (chanp->debug & 1)
- link_debug(chanp, 1, "ALERT");
- FsmEvent(&chanp->fi, EV_ALERT, NULL);
- break;
-
- case (ISDN_CMD_REDIR):
- chanp = csta->channel + ic->arg;
- if (chanp->debug & 1)
- link_debug(chanp, 1, "REDIR");
- memcpy(&chanp->setup, &ic->parm.setup, sizeof(setup_parm));
- FsmEvent(&chanp->fi, EV_REDIR, NULL);
- break;
-
- /* protocol specific io commands */
- case (ISDN_CMD_PROT_IO):
- for (st = csta->stlist; st; st = st->next)
- if (st->protocol == (ic->arg & 0xFF))
- return (st->lli.l4l3_proto(st, ic));
- return (-EINVAL);
- break;
- default:
- if (csta->auxcmd)
- return (csta->auxcmd(csta, ic));
- return (-EINVAL);
- }
- return (0);
-}
-
-int
-HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb)
-{
- struct IsdnCardState *csta = hisax_findcard(id);
- struct Channel *chanp;
- struct PStack *st;
- int len = skb->len;
- struct sk_buff *nskb;
-
- if (!csta) {
- printk(KERN_ERR
- "HiSax: if_sendbuf called with invalid driverId!\n");
- return -ENODEV;
- }
- chanp = csta->channel + chan;
- st = chanp->b_st;
- if (!chanp->data_open) {
- link_debug(chanp, 1, "writebuf: channel not open");
- return -EIO;
- }
- if (len > MAX_DATA_SIZE) {
- link_debug(chanp, 1, "writebuf: packet too large (%d bytes)", len);
- printk(KERN_WARNING "HiSax_writebuf: packet too large (%d bytes) !\n",
- len);
- return -EINVAL;
- }
- if (len) {
- if ((len + chanp->bcs->tx_cnt) > MAX_DATA_MEM) {
- /* Must return 0 here, since this is not an error
- * but a temporary lack of resources.
- */
- if (chanp->debug & 0x800)
- link_debug(chanp, 1, "writebuf: no buffers for %d bytes", len);
- return 0;
- } else if (chanp->debug & 0x800)
- link_debug(chanp, 1, "writebuf %d/%d/%d", len, chanp->bcs->tx_cnt, MAX_DATA_MEM);
- nskb = skb_clone(skb, GFP_ATOMIC);
- if (nskb) {
- nskb->truesize = nskb->len;
- if (!ack)
- nskb->pkt_type = PACKET_NOACK;
- if (chanp->l2_active_protocol == ISDN_PROTO_L2_X75I)
- st->l3.l3l2(st, DL_DATA | REQUEST, nskb);
- else {
- chanp->bcs->tx_cnt += len;
- st->l2.l2l1(st, PH_DATA | REQUEST, nskb);
- }
- dev_kfree_skb(skb);
- } else
- len = 0;
- }
- return (len);
-}
diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
deleted file mode 100644
index de965115a183..000000000000
--- a/drivers/isdn/hisax/config.c
+++ /dev/null
@@ -1,1993 +0,0 @@
-/* $Id: config.c,v 2.84.2.5 2004/02/11 13:21:33 keil Exp $
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- * by Kai Germaschewski <kai.germaschewski@gmx.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * For changes and modifications please read
- * Documentation/isdn/HiSax.cert
- *
- * based on the teles driver from Jan den Ouden
- *
- */
-
-#include <linux/types.h>
-#include <linux/stddef.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include "hisax.h"
-#include <linux/module.h>
-#include <linux/kernel_stat.h>
-#include <linux/workqueue.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#define HISAX_STATUS_BUFSIZE 4096
-
-/*
- * This structure array contains one entry per card. An entry looks
- * like this:
- *
- * { type, protocol, p0, p1, p2, NULL }
- *
- * type
- * 1 Teles 16.0 p0=irq p1=membase p2=iobase
- * 2 Teles 8.0 p0=irq p1=membase
- * 3 Teles 16.3 p0=irq p1=iobase
- * 4 Creatix PNP p0=irq p1=IO0 (ISAC) p2=IO1 (HSCX)
- * 5 AVM A1 (Fritz) p0=irq p1=iobase
- * 6 ELSA PC [p0=iobase] or nothing (autodetect)
- * 7 ELSA Quickstep p0=irq p1=iobase
- * 8 Teles PCMCIA p0=irq p1=iobase
- * 9 ITK ix1-micro p0=irq p1=iobase
- * 10 ELSA PCMCIA p0=irq p1=iobase
- * 11 Eicon.Diehl Diva p0=irq p1=iobase
- * 12 Asuscom ISDNLink p0=irq p1=iobase
- * 13 Teleint p0=irq p1=iobase
- * 14 Teles 16.3c p0=irq p1=iobase
- * 15 Sedlbauer speed p0=irq p1=iobase
- * 15 Sedlbauer PC/104 p0=irq p1=iobase
- * 15 Sedlbauer speed pci no parameter
- * 16 USR Sportster internal p0=irq p1=iobase
- * 17 MIC card p0=irq p1=iobase
- * 18 ELSA Quickstep 1000PCI no parameter
- * 19 Compaq ISDN S0 ISA card p0=irq p1=IO0 (HSCX) p2=IO1 (ISAC) p3=IO2
- * 20 Travers Technologies NETjet-S PCI card
- * 21 TELES PCI no parameter
- * 22 Sedlbauer Speed Star p0=irq p1=iobase
- * 23 reserved
- * 24 Dr Neuhaus Niccy PnP/PCI card p0=irq p1=IO0 p2=IO1 (PnP only)
- * 25 Teles S0Box p0=irq p1=iobase (from isapnp setup)
- * 26 AVM A1 PCMCIA (Fritz) p0=irq p1=iobase
- * 27 AVM PnP/PCI p0=irq p1=iobase (PCI no parameter)
- * 28 Sedlbauer Speed Fax+ p0=irq p1=iobase (from isapnp setup)
- * 29 Siemens I-Surf p0=irq p1=iobase p2=memory (from isapnp setup)
- * 30 ACER P10 p0=irq p1=iobase (from isapnp setup)
- * 31 HST Saphir p0=irq p1=iobase
- * 32 Telekom A4T none
- * 33 Scitel Quadro p0=subcontroller (4*S0, subctrl 1...4)
- * 34 Gazel ISDN cards
- * 35 HFC 2BDS0 PCI none
- * 36 Winbond 6692 PCI none
- * 37 HFC 2BDS0 S+/SP p0=irq p1=iobase
- * 38 Travers Technologies NETspider-U PCI card
- * 39 HFC 2BDS0-SP PCMCIA p0=irq p1=iobase
- * 40 hotplug interface
- * 41 Formula-n enter:now ISDN PCI a/b none
- *
- * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 or ISDN_PTYPE_NI1
- *
- *
- */
-
-const char *CardType[] = {
- "No Card", "Teles 16.0", "Teles 8.0", "Teles 16.3",
- "Creatix/Teles PnP", "AVM A1", "Elsa ML", "Elsa Quickstep",
- "Teles PCMCIA", "ITK ix1-micro Rev.2", "Elsa PCMCIA",
- "Eicon.Diehl Diva", "ISDNLink", "TeleInt", "Teles 16.3c",
- "Sedlbauer Speed Card", "USR Sportster", "ith mic Linux",
- "Elsa PCI", "Compaq ISA", "NETjet-S", "Teles PCI",
- "Sedlbauer Speed Star (PCMCIA)", "AMD 7930", "NICCY", "S0Box",
- "AVM A1 (PCMCIA)", "AVM Fritz PnP/PCI", "Sedlbauer Speed Fax +",
- "Siemens I-Surf", "Acer P10", "HST Saphir", "Telekom A4T",
- "Scitel Quadro", "Gazel", "HFC 2BDS0 PCI", "Winbond 6692",
- "HFC 2BDS0 SX", "NETspider-U", "HFC-2BDS0-SP PCMCIA",
- "Hotplug", "Formula-n enter:now PCI a/b",
-};
-
-#ifdef CONFIG_HISAX_ELSA
-#define DEFAULT_CARD ISDN_CTYPE_ELSA
-#define DEFAULT_CFG {0, 0, 0, 0}
-#endif
-
-#ifdef CONFIG_HISAX_AVM_A1
-#undef DEFAULT_CARD
-#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_A1
-#define DEFAULT_CFG {10, 0x340, 0, 0}
-#endif
-
-#ifdef CONFIG_HISAX_AVM_A1_PCMCIA
-#undef DEFAULT_CARD
-#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_A1_PCMCIA
-#define DEFAULT_CFG {11, 0x170, 0, 0}
-#endif
-
-#ifdef CONFIG_HISAX_FRITZPCI
-#undef DEFAULT_CARD
-#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_FRITZPCI
-#define DEFAULT_CFG {0, 0, 0, 0}
-#endif
-
-#ifdef CONFIG_HISAX_16_3
-#undef DEFAULT_CARD
-#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_16_3
-#define DEFAULT_CFG {15, 0x180, 0, 0}
-#endif
-
-#ifdef CONFIG_HISAX_S0BOX
-#undef DEFAULT_CARD
-#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_S0BOX
-#define DEFAULT_CFG {7, 0x378, 0, 0}
-#endif
-
-#ifdef CONFIG_HISAX_16_0
-#undef DEFAULT_CARD
-#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_16_0
-#define DEFAULT_CFG {15, 0xd0000, 0xd80, 0}
-#endif
-
-#ifdef CONFIG_HISAX_TELESPCI
-#undef DEFAULT_CARD
-#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_TELESPCI
-#define DEFAULT_CFG {0, 0, 0, 0}
-#endif
-
-#ifdef CONFIG_HISAX_IX1MICROR2
-#undef DEFAULT_CARD
-#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_IX1MICROR2
-#define DEFAULT_CFG {5, 0x390, 0, 0}
-#endif
-
-#ifdef CONFIG_HISAX_DIEHLDIVA
-#undef DEFAULT_CARD
-#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_DIEHLDIVA
-#define DEFAULT_CFG {0, 0x0, 0, 0}
-#endif
-
-#ifdef CONFIG_HISAX_ASUSCOM
-#undef DEFAULT_CARD
-#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_ASUSCOM
-#define DEFAULT_CFG {5, 0x200, 0, 0}
-#endif
-
-#ifdef CONFIG_HISAX_TELEINT
-#undef DEFAULT_CARD
-#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_TELEINT
-#define DEFAULT_CFG {5, 0x300, 0, 0}
-#endif
-
-#ifdef CONFIG_HISAX_SEDLBAUER
-#undef DEFAULT_CARD
-#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_SEDLBAUER
-#define DEFAULT_CFG {11, 0x270, 0, 0}
-#endif
-
-#ifdef CONFIG_HISAX_SPORTSTER
-#undef DEFAULT_CARD
-#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_SPORTSTER
-#define DEFAULT_CFG {7, 0x268, 0, 0}
-#endif
-
-#ifdef CONFIG_HISAX_MIC
-#undef DEFAULT_CARD
-#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_MIC
-#define DEFAULT_CFG {12, 0x3e0, 0, 0}
-#endif
-
-#ifdef CONFIG_HISAX_NETJET
-#undef DEFAULT_CARD
-#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_NETJET_S
-#define DEFAULT_CFG {0, 0, 0, 0}
-#endif
-
-#ifdef CONFIG_HISAX_HFCS
-#undef DEFAULT_CARD
-#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_TELES3C
-#define DEFAULT_CFG {5, 0x500, 0, 0}
-#endif
-
-#ifdef CONFIG_HISAX_HFC_PCI
-#undef DEFAULT_CARD
-#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_HFC_PCI
-#define DEFAULT_CFG {0, 0, 0, 0}
-#endif
-
-#ifdef CONFIG_HISAX_HFC_SX
-#undef DEFAULT_CARD
-#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_HFC_SX
-#define DEFAULT_CFG {5, 0x2E0, 0, 0}
-#endif
-
-#ifdef CONFIG_HISAX_NICCY
-#undef DEFAULT_CARD
-#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_NICCY
-#define DEFAULT_CFG {0, 0x0, 0, 0}
-#endif
-
-#ifdef CONFIG_HISAX_ISURF
-#undef DEFAULT_CARD
-#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_ISURF
-#define DEFAULT_CFG {5, 0x100, 0xc8000, 0}
-#endif
-
-#ifdef CONFIG_HISAX_HSTSAPHIR
-#undef DEFAULT_CARD
-#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_HSTSAPHIR
-#define DEFAULT_CFG {5, 0x250, 0, 0}
-#endif
-
-#ifdef CONFIG_HISAX_BKM_A4T
-#undef DEFAULT_CARD
-#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_BKM_A4T
-#define DEFAULT_CFG {0, 0x0, 0, 0}
-#endif
-
-#ifdef CONFIG_HISAX_SCT_QUADRO
-#undef DEFAULT_CARD
-#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_SCT_QUADRO
-#define DEFAULT_CFG {1, 0x0, 0, 0}
-#endif
-
-#ifdef CONFIG_HISAX_GAZEL
-#undef DEFAULT_CARD
-#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_GAZEL
-#define DEFAULT_CFG {15, 0x180, 0, 0}
-#endif
-
-#ifdef CONFIG_HISAX_W6692
-#undef DEFAULT_CARD
-#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_W6692
-#define DEFAULT_CFG {0, 0, 0, 0}
-#endif
-
-#ifdef CONFIG_HISAX_NETJET_U
-#undef DEFAULT_CARD
-#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_NETJET_U
-#define DEFAULT_CFG {0, 0, 0, 0}
-#endif
-
-#ifdef CONFIG_HISAX_1TR6
-#define DEFAULT_PROTO ISDN_PTYPE_1TR6
-#define DEFAULT_PROTO_NAME "1TR6"
-#endif
-#ifdef CONFIG_HISAX_NI1
-#undef DEFAULT_PROTO
-#define DEFAULT_PROTO ISDN_PTYPE_NI1
-#undef DEFAULT_PROTO_NAME
-#define DEFAULT_PROTO_NAME "NI1"
-#endif
-#ifdef CONFIG_HISAX_EURO
-#undef DEFAULT_PROTO
-#define DEFAULT_PROTO ISDN_PTYPE_EURO
-#undef DEFAULT_PROTO_NAME
-#define DEFAULT_PROTO_NAME "EURO"
-#endif
-#ifndef DEFAULT_PROTO
-#define DEFAULT_PROTO ISDN_PTYPE_UNKNOWN
-#define DEFAULT_PROTO_NAME "UNKNOWN"
-#endif
-#ifndef DEFAULT_CARD
-#define DEFAULT_CARD 0
-#define DEFAULT_CFG {0, 0, 0, 0}
-#endif
-
-#define FIRST_CARD { \
- DEFAULT_CARD, \
- DEFAULT_PROTO, \
- DEFAULT_CFG, \
- NULL, \
- }
-
-struct IsdnCard cards[HISAX_MAX_CARDS] = {
- FIRST_CARD,
-};
-
-#define HISAX_IDSIZE (HISAX_MAX_CARDS * 8)
-static char HiSaxID[HISAX_IDSIZE] = { 0, };
-
-static char *HiSax_id = HiSaxID;
-#ifdef MODULE
-/* Variables for insmod */
-static int type[HISAX_MAX_CARDS] = { 0, };
-static int protocol[HISAX_MAX_CARDS] = { 0, };
-static int io[HISAX_MAX_CARDS] = { 0, };
-#undef IO0_IO1
-#ifdef CONFIG_HISAX_16_3
-#define IO0_IO1
-#endif
-#ifdef CONFIG_HISAX_NICCY
-#undef IO0_IO1
-#define IO0_IO1
-#endif
-#ifdef IO0_IO1
-static int io0[HISAX_MAX_CARDS] = { 0, };
-static int io1[HISAX_MAX_CARDS] = { 0, };
-#endif
-static int irq[HISAX_MAX_CARDS] = { 0, };
-static int mem[HISAX_MAX_CARDS] = { 0, };
-static char *id = HiSaxID;
-
-MODULE_DESCRIPTION("ISDN4Linux: Driver for passive ISDN cards");
-MODULE_AUTHOR("Karsten Keil");
-MODULE_LICENSE("GPL");
-module_param_array(type, int, NULL, 0);
-module_param_array(protocol, int, NULL, 0);
-module_param_hw_array(io, int, ioport, NULL, 0);
-module_param_hw_array(irq, int, irq, NULL, 0);
-module_param_hw_array(mem, int, iomem, NULL, 0);
-module_param(id, charp, 0);
-#ifdef IO0_IO1
-module_param_hw_array(io0, int, ioport, NULL, 0);
-module_param_hw_array(io1, int, ioport, NULL, 0);
-#endif
-#endif /* MODULE */
-
-int nrcards;
-
-char *HiSax_getrev(const char *revision)
-{
- char *rev;
- char *p;
-
- if ((p = strchr(revision, ':'))) {
- rev = p + 2;
- p = strchr(rev, '$');
- *--p = 0;
- } else
- rev = "???";
- return rev;
-}
-
-static void __init HiSaxVersion(void)
-{
- char tmp[64];
-
- printk(KERN_INFO "HiSax: Linux Driver for passive ISDN cards\n");
-#ifdef MODULE
- printk(KERN_INFO "HiSax: Version 3.5 (module)\n");
-#else
- printk(KERN_INFO "HiSax: Version 3.5 (kernel)\n");
-#endif
- strcpy(tmp, l1_revision);
- printk(KERN_INFO "HiSax: Layer1 Revision %s\n", HiSax_getrev(tmp));
- strcpy(tmp, l2_revision);
- printk(KERN_INFO "HiSax: Layer2 Revision %s\n", HiSax_getrev(tmp));
- strcpy(tmp, tei_revision);
- printk(KERN_INFO "HiSax: TeiMgr Revision %s\n", HiSax_getrev(tmp));
- strcpy(tmp, l3_revision);
- printk(KERN_INFO "HiSax: Layer3 Revision %s\n", HiSax_getrev(tmp));
- strcpy(tmp, lli_revision);
- printk(KERN_INFO "HiSax: LinkLayer Revision %s\n",
- HiSax_getrev(tmp));
-}
-
-#ifndef MODULE
-#define MAX_ARG (HISAX_MAX_CARDS * 5)
-static int __init HiSax_setup(char *line)
-{
- int i, j, argc;
- int ints[MAX_ARG + 1];
- char *str;
-
- str = get_options(line, MAX_ARG, ints);
- argc = ints[0];
- printk(KERN_DEBUG "HiSax_setup: argc(%d) str(%s)\n", argc, str);
- i = 0;
- j = 1;
- while (argc && (i < HISAX_MAX_CARDS)) {
- cards[i].protocol = DEFAULT_PROTO;
- if (argc) {
- cards[i].typ = ints[j];
- j++;
- argc--;
- }
- if (argc) {
- cards[i].protocol = ints[j];
- j++;
- argc--;
- }
- if (argc) {
- cards[i].para[0] = ints[j];
- j++;
- argc--;
- }
- if (argc) {
- cards[i].para[1] = ints[j];
- j++;
- argc--;
- }
- if (argc) {
- cards[i].para[2] = ints[j];
- j++;
- argc--;
- }
- i++;
- }
- if (str && *str) {
- if (strlen(str) < HISAX_IDSIZE)
- strcpy(HiSaxID, str);
- else
- printk(KERN_WARNING "HiSax: ID too long!");
- } else
- strcpy(HiSaxID, "HiSax");
-
- HiSax_id = HiSaxID;
- return 1;
-}
-
-__setup("hisax=", HiSax_setup);
-#endif /* MODULES */
-
-#if CARD_TELES0
-extern int setup_teles0(struct IsdnCard *card);
-#endif
-
-#if CARD_TELES3
-extern int setup_teles3(struct IsdnCard *card);
-#endif
-
-#if CARD_S0BOX
-extern int setup_s0box(struct IsdnCard *card);
-#endif
-
-#if CARD_TELESPCI
-extern int setup_telespci(struct IsdnCard *card);
-#endif
-
-#if CARD_AVM_A1
-extern int setup_avm_a1(struct IsdnCard *card);
-#endif
-
-#if CARD_AVM_A1_PCMCIA
-extern int setup_avm_a1_pcmcia(struct IsdnCard *card);
-#endif
-
-#if CARD_FRITZPCI
-extern int setup_avm_pcipnp(struct IsdnCard *card);
-#endif
-
-#if CARD_ELSA
-extern int setup_elsa(struct IsdnCard *card);
-#endif
-
-#if CARD_IX1MICROR2
-extern int setup_ix1micro(struct IsdnCard *card);
-#endif
-
-#if CARD_DIEHLDIVA
-extern int setup_diva(struct IsdnCard *card);
-#endif
-
-#if CARD_ASUSCOM
-extern int setup_asuscom(struct IsdnCard *card);
-#endif
-
-#if CARD_TELEINT
-extern int setup_TeleInt(struct IsdnCard *card);
-#endif
-
-#if CARD_SEDLBAUER
-extern int setup_sedlbauer(struct IsdnCard *card);
-#endif
-
-#if CARD_SPORTSTER
-extern int setup_sportster(struct IsdnCard *card);
-#endif
-
-#if CARD_MIC
-extern int setup_mic(struct IsdnCard *card);
-#endif
-
-#if CARD_NETJET_S
-extern int setup_netjet_s(struct IsdnCard *card);
-#endif
-
-#if CARD_HFCS
-extern int setup_hfcs(struct IsdnCard *card);
-#endif
-
-#if CARD_HFC_PCI
-extern int setup_hfcpci(struct IsdnCard *card);
-#endif
-
-#if CARD_HFC_SX
-extern int setup_hfcsx(struct IsdnCard *card);
-#endif
-
-#if CARD_NICCY
-extern int setup_niccy(struct IsdnCard *card);
-#endif
-
-#if CARD_ISURF
-extern int setup_isurf(struct IsdnCard *card);
-#endif
-
-#if CARD_HSTSAPHIR
-extern int setup_saphir(struct IsdnCard *card);
-#endif
-
-#if CARD_BKM_A4T
-extern int setup_bkm_a4t(struct IsdnCard *card);
-#endif
-
-#if CARD_SCT_QUADRO
-extern int setup_sct_quadro(struct IsdnCard *card);
-#endif
-
-#if CARD_GAZEL
-extern int setup_gazel(struct IsdnCard *card);
-#endif
-
-#if CARD_W6692
-extern int setup_w6692(struct IsdnCard *card);
-#endif
-
-#if CARD_NETJET_U
-extern int setup_netjet_u(struct IsdnCard *card);
-#endif
-
-#if CARD_FN_ENTERNOW_PCI
-extern int setup_enternow_pci(struct IsdnCard *card);
-#endif
-
-/*
- * Find card with given driverId
- */
-static inline struct IsdnCardState *hisax_findcard(int driverid)
-{
- int i;
-
- for (i = 0; i < nrcards; i++)
- if (cards[i].cs)
- if (cards[i].cs->myid == driverid)
- return cards[i].cs;
- return NULL;
-}
-
-/*
- * Find card with given card number
- */
-#if 0
-struct IsdnCardState *hisax_get_card(int cardnr)
-{
- if ((cardnr <= nrcards) && (cardnr > 0))
- if (cards[cardnr - 1].cs)
- return cards[cardnr - 1].cs;
- return NULL;
-}
-#endif /* 0 */
-
-static int HiSax_readstatus(u_char __user *buf, int len, int id, int channel)
-{
- int count, cnt;
- u_char __user *p = buf;
- struct IsdnCardState *cs = hisax_findcard(id);
-
- if (cs) {
- if (len > HISAX_STATUS_BUFSIZE) {
- printk(KERN_WARNING
- "HiSax: status overflow readstat %d/%d\n",
- len, HISAX_STATUS_BUFSIZE);
- }
- count = cs->status_end - cs->status_read + 1;
- if (count >= len)
- count = len;
- if (copy_to_user(p, cs->status_read, count))
- return -EFAULT;
- cs->status_read += count;
- if (cs->status_read > cs->status_end)
- cs->status_read = cs->status_buf;
- p += count;
- count = len - count;
- while (count) {
- if (count > HISAX_STATUS_BUFSIZE)
- cnt = HISAX_STATUS_BUFSIZE;
- else
- cnt = count;
- if (copy_to_user(p, cs->status_read, cnt))
- return -EFAULT;
- p += cnt;
- cs->status_read += cnt % HISAX_STATUS_BUFSIZE;
- count -= cnt;
- }
- return len;
- } else {
- printk(KERN_ERR
- "HiSax: if_readstatus called with invalid driverId!\n");
- return -ENODEV;
- }
-}
-
-int jiftime(char *s, long mark)
-{
- s += 8;
-
- *s-- = '\0';
- *s-- = mark % 10 + '0';
- mark /= 10;
- *s-- = mark % 10 + '0';
- mark /= 10;
- *s-- = '.';
- *s-- = mark % 10 + '0';
- mark /= 10;
- *s-- = mark % 6 + '0';
- mark /= 6;
- *s-- = ':';
- *s-- = mark % 10 + '0';
- mark /= 10;
- *s-- = mark % 10 + '0';
- return 8;
-}
-
-static u_char tmpbuf[HISAX_STATUS_BUFSIZE];
-
-void VHiSax_putstatus(struct IsdnCardState *cs, char *head, const char *fmt,
- va_list args)
-{
- /* if head == NULL the fmt contains the full info */
-
- u_long flags;
- int count, i;
- u_char *p;
- isdn_ctrl ic;
- int len;
- const u_char *data;
-
- if (!cs) {
- printk(KERN_WARNING "HiSax: No CardStatus for message");
- return;
- }
- spin_lock_irqsave(&cs->statlock, flags);
- if (head) {
- p = tmpbuf;
- p += jiftime(p, jiffies);
- p += sprintf(p, " %s", head);
- p += vsprintf(p, fmt, args);
- *p++ = '\n';
- *p = 0;
- len = p - tmpbuf;
- data = tmpbuf;
- } else {
- data = fmt;
- len = strlen(fmt);
- }
- if (len > HISAX_STATUS_BUFSIZE) {
- spin_unlock_irqrestore(&cs->statlock, flags);
- printk(KERN_WARNING "HiSax: status overflow %d/%d\n",
- len, HISAX_STATUS_BUFSIZE);
- return;
- }
- count = len;
- i = cs->status_end - cs->status_write + 1;
- if (i >= len)
- i = len;
- len -= i;
- memcpy(cs->status_write, data, i);
- cs->status_write += i;
- if (cs->status_write > cs->status_end)
- cs->status_write = cs->status_buf;
- if (len) {
- memcpy(cs->status_write, data + i, len);
- cs->status_write += len;
- }
-#ifdef KERNELSTACK_DEBUG
- i = (ulong) & len - current->kernel_stack_page;
- sprintf(tmpbuf, "kstack %s %lx use %ld\n", current->comm,
- current->kernel_stack_page, i);
- len = strlen(tmpbuf);
- for (p = tmpbuf, i = len; i > 0; i--, p++) {
- *cs->status_write++ = *p;
- if (cs->status_write > cs->status_end)
- cs->status_write = cs->status_buf;
- count++;
- }
-#endif
- spin_unlock_irqrestore(&cs->statlock, flags);
- if (count) {
- ic.command = ISDN_STAT_STAVAIL;
- ic.driver = cs->myid;
- ic.arg = count;
- cs->iif.statcallb(&ic);
- }
-}
-
-void HiSax_putstatus(struct IsdnCardState *cs, char *head, const char *fmt, ...)
-{
- va_list args;
-
- va_start(args, fmt);
- VHiSax_putstatus(cs, head, fmt, args);
- va_end(args);
-}
-
-int ll_run(struct IsdnCardState *cs, int addfeatures)
-{
- isdn_ctrl ic;
-
- ic.driver = cs->myid;
- ic.command = ISDN_STAT_RUN;
- cs->iif.features |= addfeatures;
- cs->iif.statcallb(&ic);
- return 0;
-}
-
-static void ll_stop(struct IsdnCardState *cs)
-{
- isdn_ctrl ic;
-
- ic.command = ISDN_STAT_STOP;
- ic.driver = cs->myid;
- cs->iif.statcallb(&ic);
- // CallcFreeChan(cs);
-}
-
-static void ll_unload(struct IsdnCardState *cs)
-{
- isdn_ctrl ic;
-
- ic.command = ISDN_STAT_UNLOAD;
- ic.driver = cs->myid;
- cs->iif.statcallb(&ic);
- kfree(cs->status_buf);
- cs->status_read = NULL;
- cs->status_write = NULL;
- cs->status_end = NULL;
- kfree(cs->dlog);
- cs->dlog = NULL;
-}
-
-static void closecard(int cardnr)
-{
- struct IsdnCardState *csta = cards[cardnr].cs;
-
- if (csta->bcs->BC_Close != NULL) {
- csta->bcs->BC_Close(csta->bcs + 1);
- csta->bcs->BC_Close(csta->bcs);
- }
-
- skb_queue_purge(&csta->rq);
- skb_queue_purge(&csta->sq);
- kfree(csta->rcvbuf);
- csta->rcvbuf = NULL;
- if (csta->tx_skb) {
- dev_kfree_skb(csta->tx_skb);
- csta->tx_skb = NULL;
- }
- if (csta->DC_Close != NULL) {
- csta->DC_Close(csta);
- }
- if (csta->cardmsg)
- csta->cardmsg(csta, CARD_RELEASE, NULL);
- if (csta->dbusytimer.function != NULL) // FIXME?
- del_timer(&csta->dbusytimer);
- ll_unload(csta);
-}
-
-static irqreturn_t card_irq(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- irqreturn_t ret = cs->irq_func(intno, cs);
-
- if (ret == IRQ_HANDLED)
- cs->irq_cnt++;
- return ret;
-}
-
-static int init_card(struct IsdnCardState *cs)
-{
- int irq_cnt, cnt = 3, ret;
-
- if (!cs->irq) {
- ret = cs->cardmsg(cs, CARD_INIT, NULL);
- return (ret);
- }
- irq_cnt = cs->irq_cnt = 0;
- printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ],
- cs->irq, irq_cnt);
- if (request_irq(cs->irq, card_irq, cs->irq_flags, "HiSax", cs)) {
- printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n",
- cs->irq);
- return 1;
- }
- while (cnt) {
- cs->cardmsg(cs, CARD_INIT, NULL);
- /* Timeout 10ms */
- msleep(10);
- printk(KERN_INFO "%s: IRQ %d count %d\n",
- CardType[cs->typ], cs->irq, cs->irq_cnt);
- if (cs->irq_cnt == irq_cnt) {
- printk(KERN_WARNING
- "%s: IRQ(%d) getting no interrupts during init %d\n",
- CardType[cs->typ], cs->irq, 4 - cnt);
- if (cnt == 1) {
- free_irq(cs->irq, cs);
- return 2;
- } else {
- cs->cardmsg(cs, CARD_RESET, NULL);
- cnt--;
- }
- } else {
- cs->cardmsg(cs, CARD_TEST, NULL);
- return 0;
- }
- }
- return 3;
-}
-
-static int hisax_cs_setup_card(struct IsdnCard *card)
-{
- int ret;
-
- switch (card->typ) {
-#if CARD_TELES0
- case ISDN_CTYPE_16_0:
- case ISDN_CTYPE_8_0:
- ret = setup_teles0(card);
- break;
-#endif
-#if CARD_TELES3
- case ISDN_CTYPE_16_3:
- case ISDN_CTYPE_PNP:
- case ISDN_CTYPE_TELESPCMCIA:
- case ISDN_CTYPE_COMPAQ_ISA:
- ret = setup_teles3(card);
- break;
-#endif
-#if CARD_S0BOX
- case ISDN_CTYPE_S0BOX:
- ret = setup_s0box(card);
- break;
-#endif
-#if CARD_TELESPCI
- case ISDN_CTYPE_TELESPCI:
- ret = setup_telespci(card);
- break;
-#endif
-#if CARD_AVM_A1
- case ISDN_CTYPE_A1:
- ret = setup_avm_a1(card);
- break;
-#endif
-#if CARD_AVM_A1_PCMCIA
- case ISDN_CTYPE_A1_PCMCIA:
- ret = setup_avm_a1_pcmcia(card);
- break;
-#endif
-#if CARD_FRITZPCI
- case ISDN_CTYPE_FRITZPCI:
- ret = setup_avm_pcipnp(card);
- break;
-#endif
-#if CARD_ELSA
- case ISDN_CTYPE_ELSA:
- case ISDN_CTYPE_ELSA_PNP:
- case ISDN_CTYPE_ELSA_PCMCIA:
- case ISDN_CTYPE_ELSA_PCI:
- ret = setup_elsa(card);
- break;
-#endif
-#if CARD_IX1MICROR2
- case ISDN_CTYPE_IX1MICROR2:
- ret = setup_ix1micro(card);
- break;
-#endif
-#if CARD_DIEHLDIVA
- case ISDN_CTYPE_DIEHLDIVA:
- ret = setup_diva(card);
- break;
-#endif
-#if CARD_ASUSCOM
- case ISDN_CTYPE_ASUSCOM:
- ret = setup_asuscom(card);
- break;
-#endif
-#if CARD_TELEINT
- case ISDN_CTYPE_TELEINT:
- ret = setup_TeleInt(card);
- break;
-#endif
-#if CARD_SEDLBAUER
- case ISDN_CTYPE_SEDLBAUER:
- case ISDN_CTYPE_SEDLBAUER_PCMCIA:
- case ISDN_CTYPE_SEDLBAUER_FAX:
- ret = setup_sedlbauer(card);
- break;
-#endif
-#if CARD_SPORTSTER
- case ISDN_CTYPE_SPORTSTER:
- ret = setup_sportster(card);
- break;
-#endif
-#if CARD_MIC
- case ISDN_CTYPE_MIC:
- ret = setup_mic(card);
- break;
-#endif
-#if CARD_NETJET_S
- case ISDN_CTYPE_NETJET_S:
- ret = setup_netjet_s(card);
- break;
-#endif
-#if CARD_HFCS
- case ISDN_CTYPE_TELES3C:
- case ISDN_CTYPE_ACERP10:
- ret = setup_hfcs(card);
- break;
-#endif
-#if CARD_HFC_PCI
- case ISDN_CTYPE_HFC_PCI:
- ret = setup_hfcpci(card);
- break;
-#endif
-#if CARD_HFC_SX
- case ISDN_CTYPE_HFC_SX:
- ret = setup_hfcsx(card);
- break;
-#endif
-#if CARD_NICCY
- case ISDN_CTYPE_NICCY:
- ret = setup_niccy(card);
- break;
-#endif
-#if CARD_ISURF
- case ISDN_CTYPE_ISURF:
- ret = setup_isurf(card);
- break;
-#endif
-#if CARD_HSTSAPHIR
- case ISDN_CTYPE_HSTSAPHIR:
- ret = setup_saphir(card);
- break;
-#endif
-#if CARD_BKM_A4T
- case ISDN_CTYPE_BKM_A4T:
- ret = setup_bkm_a4t(card);
- break;
-#endif
-#if CARD_SCT_QUADRO
- case ISDN_CTYPE_SCT_QUADRO:
- ret = setup_sct_quadro(card);
- break;
-#endif
-#if CARD_GAZEL
- case ISDN_CTYPE_GAZEL:
- ret = setup_gazel(card);
- break;
-#endif
-#if CARD_W6692
- case ISDN_CTYPE_W6692:
- ret = setup_w6692(card);
- break;
-#endif
-#if CARD_NETJET_U
- case ISDN_CTYPE_NETJET_U:
- ret = setup_netjet_u(card);
- break;
-#endif
-#if CARD_FN_ENTERNOW_PCI
- case ISDN_CTYPE_ENTERNOW:
- ret = setup_enternow_pci(card);
- break;
-#endif
- case ISDN_CTYPE_DYNAMIC:
- ret = 2;
- break;
- default:
- printk(KERN_WARNING
- "HiSax: Support for %s Card not selected\n",
- CardType[card->typ]);
- ret = 0;
- break;
- }
-
- return ret;
-}
-
-static int hisax_cs_new(int cardnr, char *id, struct IsdnCard *card,
- struct IsdnCardState **cs_out, int *busy_flag,
- struct module *lockowner)
-{
- struct IsdnCardState *cs;
-
- *cs_out = NULL;
-
- cs = kzalloc(sizeof(struct IsdnCardState), GFP_KERNEL);
- if (!cs) {
- printk(KERN_WARNING
- "HiSax: No memory for IsdnCardState(card %d)\n",
- cardnr + 1);
- goto out;
- }
- card->cs = cs;
- spin_lock_init(&cs->statlock);
- spin_lock_init(&cs->lock);
- cs->chanlimit = 2; /* maximum B-channel number */
- cs->logecho = 0; /* No echo logging */
- cs->cardnr = cardnr;
- cs->debug = L1_DEB_WARN;
- cs->HW_Flags = 0;
- cs->busy_flag = busy_flag;
- cs->irq_flags = I4L_IRQ_FLAG;
-#if TEI_PER_CARD
- if (card->protocol == ISDN_PTYPE_NI1)
- test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
-#else
- test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
-#endif
- cs->protocol = card->protocol;
-
- if (card->typ <= 0 || card->typ > ISDN_CTYPE_COUNT) {
- printk(KERN_WARNING
- "HiSax: Card Type %d out of range\n", card->typ);
- goto outf_cs;
- }
- if (!(cs->dlog = kmalloc(MAX_DLOG_SPACE, GFP_KERNEL))) {
- printk(KERN_WARNING
- "HiSax: No memory for dlog(card %d)\n", cardnr + 1);
- goto outf_cs;
- }
- if (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_KERNEL))) {
- printk(KERN_WARNING
- "HiSax: No memory for status_buf(card %d)\n",
- cardnr + 1);
- goto outf_dlog;
- }
- cs->stlist = NULL;
- cs->status_read = cs->status_buf;
- cs->status_write = cs->status_buf;
- cs->status_end = cs->status_buf + HISAX_STATUS_BUFSIZE - 1;
- cs->typ = card->typ;
-#ifdef MODULE
- cs->iif.owner = lockowner;
-#endif
- strcpy(cs->iif.id, id);
- cs->iif.channels = 2;
- cs->iif.maxbufsize = MAX_DATA_SIZE;
- cs->iif.hl_hdrlen = MAX_HEADER_LEN;
- cs->iif.features =
- ISDN_FEATURE_L2_X75I |
- ISDN_FEATURE_L2_HDLC |
- ISDN_FEATURE_L2_HDLC_56K |
- ISDN_FEATURE_L2_TRANS |
- ISDN_FEATURE_L3_TRANS |
-#ifdef CONFIG_HISAX_1TR6
- ISDN_FEATURE_P_1TR6 |
-#endif
-#ifdef CONFIG_HISAX_EURO
- ISDN_FEATURE_P_EURO |
-#endif
-#ifdef CONFIG_HISAX_NI1
- ISDN_FEATURE_P_NI1 |
-#endif
- 0;
-
- cs->iif.command = HiSax_command;
- cs->iif.writecmd = NULL;
- cs->iif.writebuf_skb = HiSax_writebuf_skb;
- cs->iif.readstat = HiSax_readstatus;
- register_isdn(&cs->iif);
- cs->myid = cs->iif.channels;
-
- *cs_out = cs;
- return 1; /* success */
-
-outf_dlog:
- kfree(cs->dlog);
-outf_cs:
- kfree(cs);
- card->cs = NULL;
-out:
- return 0; /* error */
-}
-
-static int hisax_cs_setup(int cardnr, struct IsdnCard *card,
- struct IsdnCardState *cs)
-{
- int ret;
-
- if (!(cs->rcvbuf = kmalloc(MAX_DFRAME_LEN_L1, GFP_KERNEL))) {
- printk(KERN_WARNING "HiSax: No memory for isac rcvbuf\n");
- ll_unload(cs);
- goto outf_cs;
- }
- cs->rcvidx = 0;
- cs->tx_skb = NULL;
- cs->tx_cnt = 0;
- cs->event = 0;
-
- skb_queue_head_init(&cs->rq);
- skb_queue_head_init(&cs->sq);
-
- init_bcstate(cs, 0);
- init_bcstate(cs, 1);
-
- /* init_card only handles interrupts which are not */
- /* used here for the loadable driver */
- switch (card->typ) {
- case ISDN_CTYPE_DYNAMIC:
- ret = 0;
- break;
- default:
- ret = init_card(cs);
- break;
- }
- if (ret) {
- closecard(cardnr);
- goto outf_cs;
- }
- init_tei(cs, cs->protocol);
- ret = CallcNewChan(cs);
- if (ret) {
- closecard(cardnr);
- goto outf_cs;
- }
- /* ISAR needs firmware download first */
- if (!test_bit(HW_ISAR, &cs->HW_Flags))
- ll_run(cs, 0);
-
- return 1;
-
-outf_cs:
- kfree(cs);
- card->cs = NULL;
- return 0;
-}
-
-static int checkcard(int cardnr, char *id, int *busy_flag,
- struct module *lockowner, hisax_setup_func_t card_setup)
-{
- int ret;
- struct IsdnCard *card = cards + cardnr;
- struct IsdnCardState *cs;
-
- ret = hisax_cs_new(cardnr, id, card, &cs, busy_flag, lockowner);
- if (!ret)
- return 0;
-
- printk(KERN_INFO
- "HiSax: Card %d Protocol %s Id=%s (%d)\n", cardnr + 1,
- (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" :
- (card->protocol == ISDN_PTYPE_EURO) ? "EDSS1" :
- (card->protocol == ISDN_PTYPE_LEASED) ? "LEASED" :
- (card->protocol == ISDN_PTYPE_NI1) ? "NI1" :
- "NONE", cs->iif.id, cs->myid);
-
- ret = card_setup(card);
- if (!ret) {
- ll_unload(cs);
- goto outf_cs;
- }
-
- ret = hisax_cs_setup(cardnr, card, cs);
- goto out;
-
-outf_cs:
- kfree(cs);
- card->cs = NULL;
-out:
- return ret;
-}
-
-static void HiSax_shiftcards(int idx)
-{
- int i;
-
- for (i = idx; i < (HISAX_MAX_CARDS - 1); i++)
- memcpy(&cards[i], &cards[i + 1], sizeof(cards[i]));
-}
-
-static int __init HiSax_inithardware(int *busy_flag)
-{
- int foundcards = 0;
- int i = 0;
- int t = ',';
- int flg = 0;
- char *id;
- char *next_id = HiSax_id;
- char ids[20];
-
- if (strchr(HiSax_id, ','))
- t = ',';
- else if (strchr(HiSax_id, '%'))
- t = '%';
-
- while (i < nrcards) {
- if (cards[i].typ < 1)
- break;
- id = next_id;
- if ((next_id = strchr(id, t))) {
- *next_id++ = 0;
- strcpy(ids, id);
- flg = i + 1;
- } else {
- next_id = id;
- if (flg >= i)
- strcpy(ids, id);
- else
- sprintf(ids, "%s%d", id, i);
- }
- if (checkcard(i, ids, busy_flag, THIS_MODULE,
- hisax_cs_setup_card)) {
- foundcards++;
- i++;
- } else {
- /* make sure we don't oops the module */
- if (cards[i].typ > 0 && cards[i].typ <= ISDN_CTYPE_COUNT) {
- printk(KERN_WARNING
- "HiSax: Card %s not installed !\n",
- CardType[cards[i].typ]);
- }
- HiSax_shiftcards(i);
- nrcards--;
- }
- }
- return foundcards;
-}
-
-void HiSax_closecard(int cardnr)
-{
- int i, last = nrcards - 1;
-
- if (cardnr > last || cardnr < 0)
- return;
- if (cards[cardnr].cs) {
- ll_stop(cards[cardnr].cs);
- release_tei(cards[cardnr].cs);
- CallcFreeChan(cards[cardnr].cs);
-
- closecard(cardnr);
- if (cards[cardnr].cs->irq)
- free_irq(cards[cardnr].cs->irq, cards[cardnr].cs);
- kfree((void *) cards[cardnr].cs);
- cards[cardnr].cs = NULL;
- }
- i = cardnr;
- while (i <= last) {
- cards[i] = cards[i + 1];
- i++;
- }
- nrcards--;
-}
-
-void HiSax_reportcard(int cardnr, int sel)
-{
- struct IsdnCardState *cs = cards[cardnr].cs;
-
- printk(KERN_DEBUG "HiSax: reportcard No %d\n", cardnr + 1);
- printk(KERN_DEBUG "HiSax: Type %s\n", CardType[cs->typ]);
- printk(KERN_DEBUG "HiSax: debuglevel %x\n", cs->debug);
- printk(KERN_DEBUG "HiSax: HiSax_reportcard address 0x%px\n",
- HiSax_reportcard);
- printk(KERN_DEBUG "HiSax: cs 0x%px\n", cs);
- printk(KERN_DEBUG "HiSax: HW_Flags %lx bc0 flg %lx bc1 flg %lx\n",
- cs->HW_Flags, cs->bcs[0].Flag, cs->bcs[1].Flag);
- printk(KERN_DEBUG "HiSax: bcs 0 mode %d ch%d\n",
- cs->bcs[0].mode, cs->bcs[0].channel);
- printk(KERN_DEBUG "HiSax: bcs 1 mode %d ch%d\n",
- cs->bcs[1].mode, cs->bcs[1].channel);
-#ifdef ERROR_STATISTIC
- printk(KERN_DEBUG "HiSax: dc errors(rx,crc,tx) %d,%d,%d\n",
- cs->err_rx, cs->err_crc, cs->err_tx);
- printk(KERN_DEBUG
- "HiSax: bc0 errors(inv,rdo,crc,tx) %d,%d,%d,%d\n",
- cs->bcs[0].err_inv, cs->bcs[0].err_rdo, cs->bcs[0].err_crc,
- cs->bcs[0].err_tx);
- printk(KERN_DEBUG
- "HiSax: bc1 errors(inv,rdo,crc,tx) %d,%d,%d,%d\n",
- cs->bcs[1].err_inv, cs->bcs[1].err_rdo, cs->bcs[1].err_crc,
- cs->bcs[1].err_tx);
- if (sel == 99) {
- cs->err_rx = 0;
- cs->err_crc = 0;
- cs->err_tx = 0;
- cs->bcs[0].err_inv = 0;
- cs->bcs[0].err_rdo = 0;
- cs->bcs[0].err_crc = 0;
- cs->bcs[0].err_tx = 0;
- cs->bcs[1].err_inv = 0;
- cs->bcs[1].err_rdo = 0;
- cs->bcs[1].err_crc = 0;
- cs->bcs[1].err_tx = 0;
- }
-#endif
-}
-
-static int __init HiSax_init(void)
-{
- int i, retval;
-#ifdef MODULE
- int j;
- int nzproto = 0;
-#endif
-
- HiSaxVersion();
- retval = CallcNew();
- if (retval)
- goto out;
- retval = Isdnl3New();
- if (retval)
- goto out_callc;
- retval = Isdnl2New();
- if (retval)
- goto out_isdnl3;
- retval = TeiNew();
- if (retval)
- goto out_isdnl2;
- retval = Isdnl1New();
- if (retval)
- goto out_tei;
-
-#ifdef MODULE
- if (!type[0]) {
- /* We 'll register drivers later, but init basic functions */
- for (i = 0; i < HISAX_MAX_CARDS; i++)
- cards[i].typ = 0;
- return 0;
- }
-#ifdef CONFIG_HISAX_ELSA
- if (type[0] == ISDN_CTYPE_ELSA_PCMCIA) {
- /* we have exported and return in this case */
- return 0;
- }
-#endif
-#ifdef CONFIG_HISAX_SEDLBAUER
- if (type[0] == ISDN_CTYPE_SEDLBAUER_PCMCIA) {
- /* we have to export and return in this case */
- return 0;
- }
-#endif
-#ifdef CONFIG_HISAX_AVM_A1_PCMCIA
- if (type[0] == ISDN_CTYPE_A1_PCMCIA) {
- /* we have to export and return in this case */
- return 0;
- }
-#endif
-#ifdef CONFIG_HISAX_HFC_SX
- if (type[0] == ISDN_CTYPE_HFC_SP_PCMCIA) {
- /* we have to export and return in this case */
- return 0;
- }
-#endif
-#endif
- nrcards = 0;
-#ifdef MODULE
- if (id) /* If id= string used */
- HiSax_id = id;
- for (i = j = 0; j < HISAX_MAX_CARDS; i++) {
- cards[j].typ = type[i];
- if (protocol[i]) {
- cards[j].protocol = protocol[i];
- nzproto++;
- } else {
- cards[j].protocol = DEFAULT_PROTO;
- }
- switch (type[i]) {
- case ISDN_CTYPE_16_0:
- cards[j].para[0] = irq[i];
- cards[j].para[1] = mem[i];
- cards[j].para[2] = io[i];
- break;
-
- case ISDN_CTYPE_8_0:
- cards[j].para[0] = irq[i];
- cards[j].para[1] = mem[i];
- break;
-
-#ifdef IO0_IO1
- case ISDN_CTYPE_PNP:
- case ISDN_CTYPE_NICCY:
- cards[j].para[0] = irq[i];
- cards[j].para[1] = io0[i];
- cards[j].para[2] = io1[i];
- break;
- case ISDN_CTYPE_COMPAQ_ISA:
- cards[j].para[0] = irq[i];
- cards[j].para[1] = io0[i];
- cards[j].para[2] = io1[i];
- cards[j].para[3] = io[i];
- break;
-#endif
- case ISDN_CTYPE_ELSA:
- case ISDN_CTYPE_HFC_PCI:
- cards[j].para[0] = io[i];
- break;
- case ISDN_CTYPE_16_3:
- case ISDN_CTYPE_TELESPCMCIA:
- case ISDN_CTYPE_A1:
- case ISDN_CTYPE_A1_PCMCIA:
- case ISDN_CTYPE_ELSA_PNP:
- case ISDN_CTYPE_ELSA_PCMCIA:
- case ISDN_CTYPE_IX1MICROR2:
- case ISDN_CTYPE_DIEHLDIVA:
- case ISDN_CTYPE_ASUSCOM:
- case ISDN_CTYPE_TELEINT:
- case ISDN_CTYPE_SEDLBAUER:
- case ISDN_CTYPE_SEDLBAUER_PCMCIA:
- case ISDN_CTYPE_SEDLBAUER_FAX:
- case ISDN_CTYPE_SPORTSTER:
- case ISDN_CTYPE_MIC:
- case ISDN_CTYPE_TELES3C:
- case ISDN_CTYPE_ACERP10:
- case ISDN_CTYPE_S0BOX:
- case ISDN_CTYPE_FRITZPCI:
- case ISDN_CTYPE_HSTSAPHIR:
- case ISDN_CTYPE_GAZEL:
- case ISDN_CTYPE_HFC_SX:
- case ISDN_CTYPE_HFC_SP_PCMCIA:
- cards[j].para[0] = irq[i];
- cards[j].para[1] = io[i];
- break;
- case ISDN_CTYPE_ISURF:
- cards[j].para[0] = irq[i];
- cards[j].para[1] = io[i];
- cards[j].para[2] = mem[i];
- break;
- case ISDN_CTYPE_ELSA_PCI:
- case ISDN_CTYPE_NETJET_S:
- case ISDN_CTYPE_TELESPCI:
- case ISDN_CTYPE_W6692:
- case ISDN_CTYPE_NETJET_U:
- break;
- case ISDN_CTYPE_BKM_A4T:
- break;
- case ISDN_CTYPE_SCT_QUADRO:
- if (irq[i]) {
- cards[j].para[0] = irq[i];
- } else {
- /* QUADRO is a 4 BRI card */
- cards[j++].para[0] = 1;
- /* we need to check if further cards can be added */
- if (j < HISAX_MAX_CARDS) {
- cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
- cards[j].protocol = protocol[i];
- cards[j++].para[0] = 2;
- }
- if (j < HISAX_MAX_CARDS) {
- cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
- cards[j].protocol = protocol[i];
- cards[j++].para[0] = 3;
- }
- if (j < HISAX_MAX_CARDS) {
- cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
- cards[j].protocol = protocol[i];
- cards[j].para[0] = 4;
- }
- }
- break;
- }
- j++;
- }
- if (!nzproto) {
- printk(KERN_WARNING
- "HiSax: Warning - no protocol specified\n");
- printk(KERN_WARNING "HiSax: using protocol %s\n",
- DEFAULT_PROTO_NAME);
- }
-#endif
- if (!HiSax_id)
- HiSax_id = HiSaxID;
- if (!HiSaxID[0])
- strcpy(HiSaxID, "HiSax");
- for (i = 0; i < HISAX_MAX_CARDS; i++)
- if (cards[i].typ > 0)
- nrcards++;
- printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
- nrcards, (nrcards > 1) ? "s" : "");
-
- /* Install only, if at least one card found */
- if (!HiSax_inithardware(NULL))
- return -ENODEV;
- return 0;
-
-out_tei:
- TeiFree();
-out_isdnl2:
- Isdnl2Free();
-out_isdnl3:
- Isdnl3Free();
-out_callc:
- CallcFree();
-out:
- return retval;
-}
-
-static void __exit HiSax_exit(void)
-{
- int cardnr = nrcards - 1;
-
- while (cardnr >= 0)
- HiSax_closecard(cardnr--);
- Isdnl1Free();
- TeiFree();
- Isdnl2Free();
- Isdnl3Free();
- CallcFree();
- printk(KERN_INFO "HiSax module removed\n");
-}
-
-int hisax_init_pcmcia(void *pcm_iob, int *busy_flag, struct IsdnCard *card)
-{
- u_char ids[16];
- int ret = -1;
-
- cards[nrcards] = *card;
- if (nrcards)
- sprintf(ids, "HiSax%d", nrcards);
- else
- sprintf(ids, "HiSax");
- if (!checkcard(nrcards, ids, busy_flag, THIS_MODULE,
- hisax_cs_setup_card))
- goto error;
-
- ret = nrcards;
- nrcards++;
-error:
- return ret;
-}
-EXPORT_SYMBOL(hisax_init_pcmcia);
-
-EXPORT_SYMBOL(HiSax_closecard);
-
-#include "hisax_if.h"
-
-EXPORT_SYMBOL(hisax_register);
-EXPORT_SYMBOL(hisax_unregister);
-
-static void hisax_d_l1l2(struct hisax_if *ifc, int pr, void *arg);
-static void hisax_b_l1l2(struct hisax_if *ifc, int pr, void *arg);
-static void hisax_d_l2l1(struct PStack *st, int pr, void *arg);
-static void hisax_b_l2l1(struct PStack *st, int pr, void *arg);
-static int hisax_cardmsg(struct IsdnCardState *cs, int mt, void *arg);
-static int hisax_bc_setstack(struct PStack *st, struct BCState *bcs);
-static void hisax_bc_close(struct BCState *bcs);
-static void hisax_bh(struct work_struct *work);
-static void EChannel_proc_rcv(struct hisax_d_if *d_if);
-
-static int hisax_setup_card_dynamic(struct IsdnCard *card)
-{
- return 2;
-}
-
-int hisax_register(struct hisax_d_if *hisax_d_if, struct hisax_b_if *b_if[],
- char *name, int protocol)
-{
- int i, retval;
- char id[20];
- struct IsdnCardState *cs;
-
- for (i = 0; i < HISAX_MAX_CARDS; i++) {
- if (!cards[i].typ)
- break;
- }
-
- if (i >= HISAX_MAX_CARDS)
- return -EBUSY;
-
- cards[i].typ = ISDN_CTYPE_DYNAMIC;
- cards[i].protocol = protocol;
- sprintf(id, "%s%d", name, i);
- nrcards++;
- retval = checkcard(i, id, NULL, hisax_d_if->owner,
- hisax_setup_card_dynamic);
- if (retval == 0) { // yuck
- cards[i].typ = 0;
- nrcards--;
- return -EINVAL;
- }
- cs = cards[i].cs;
- hisax_d_if->cs = cs;
- cs->hw.hisax_d_if = hisax_d_if;
- cs->cardmsg = hisax_cardmsg;
- INIT_WORK(&cs->tqueue, hisax_bh);
- cs->channel[0].d_st->l2.l2l1 = hisax_d_l2l1;
- for (i = 0; i < 2; i++) {
- cs->bcs[i].BC_SetStack = hisax_bc_setstack;
- cs->bcs[i].BC_Close = hisax_bc_close;
-
- b_if[i]->ifc.l1l2 = hisax_b_l1l2;
-
- hisax_d_if->b_if[i] = b_if[i];
- }
- hisax_d_if->ifc.l1l2 = hisax_d_l1l2;
- skb_queue_head_init(&hisax_d_if->erq);
- clear_bit(0, &hisax_d_if->ph_state);
-
- return 0;
-}
-
-void hisax_unregister(struct hisax_d_if *hisax_d_if)
-{
- cards[hisax_d_if->cs->cardnr].typ = 0;
- HiSax_closecard(hisax_d_if->cs->cardnr);
- skb_queue_purge(&hisax_d_if->erq);
-}
-
-#include "isdnl1.h"
-
-static void hisax_sched_event(struct IsdnCardState *cs, int event)
-{
- test_and_set_bit(event, &cs->event);
- schedule_work(&cs->tqueue);
-}
-
-static void hisax_bh(struct work_struct *work)
-{
- struct IsdnCardState *cs =
- container_of(work, struct IsdnCardState, tqueue);
- struct PStack *st;
- int pr;
-
- if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
- DChannel_proc_rcv(cs);
- if (test_and_clear_bit(E_RCVBUFREADY, &cs->event))
- EChannel_proc_rcv(cs->hw.hisax_d_if);
- if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
- if (test_bit(0, &cs->hw.hisax_d_if->ph_state))
- pr = PH_ACTIVATE | INDICATION;
- else
- pr = PH_DEACTIVATE | INDICATION;
- for (st = cs->stlist; st; st = st->next)
- st->l1.l1l2(st, pr, NULL);
-
- }
-}
-
-static void hisax_b_sched_event(struct BCState *bcs, int event)
-{
- test_and_set_bit(event, &bcs->event);
- schedule_work(&bcs->tqueue);
-}
-
-static inline void D_L2L1(struct hisax_d_if *d_if, int pr, void *arg)
-{
- struct hisax_if *ifc = (struct hisax_if *) d_if;
- ifc->l2l1(ifc, pr, arg);
-}
-
-static inline void B_L2L1(struct hisax_b_if *b_if, int pr, void *arg)
-{
- struct hisax_if *ifc = (struct hisax_if *) b_if;
- ifc->l2l1(ifc, pr, arg);
-}
-
-static void hisax_d_l1l2(struct hisax_if *ifc, int pr, void *arg)
-{
- struct hisax_d_if *d_if = (struct hisax_d_if *) ifc;
- struct IsdnCardState *cs = d_if->cs;
- struct PStack *st;
- struct sk_buff *skb;
-
- switch (pr) {
- case PH_ACTIVATE | INDICATION:
- set_bit(0, &d_if->ph_state);
- hisax_sched_event(cs, D_L1STATECHANGE);
- break;
- case PH_DEACTIVATE | INDICATION:
- clear_bit(0, &d_if->ph_state);
- hisax_sched_event(cs, D_L1STATECHANGE);
- break;
- case PH_DATA | INDICATION:
- skb_queue_tail(&cs->rq, arg);
- hisax_sched_event(cs, D_RCVBUFREADY);
- break;
- case PH_DATA | CONFIRM:
- skb = skb_dequeue(&cs->sq);
- if (skb) {
- D_L2L1(d_if, PH_DATA | REQUEST, skb);
- break;
- }
- clear_bit(FLG_L1_DBUSY, &cs->HW_Flags);
- for (st = cs->stlist; st; st = st->next) {
- if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags)) {
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
- break;
- }
- }
- break;
- case PH_DATA_E | INDICATION:
- skb_queue_tail(&d_if->erq, arg);
- hisax_sched_event(cs, E_RCVBUFREADY);
- break;
- default:
- printk("pr %#x\n", pr);
- break;
- }
-}
-
-static void hisax_b_l1l2(struct hisax_if *ifc, int pr, void *arg)
-{
- struct hisax_b_if *b_if = (struct hisax_b_if *) ifc;
- struct BCState *bcs = b_if->bcs;
- struct PStack *st = bcs->st;
- struct sk_buff *skb;
-
- // FIXME use isdnl1?
- switch (pr) {
- case PH_ACTIVATE | INDICATION:
- st->l1.l1l2(st, pr, NULL);
- break;
- case PH_DEACTIVATE | INDICATION:
- st->l1.l1l2(st, pr, NULL);
- clear_bit(BC_FLG_BUSY, &bcs->Flag);
- skb_queue_purge(&bcs->squeue);
- bcs->hw.b_if = NULL;
- break;
- case PH_DATA | INDICATION:
- skb_queue_tail(&bcs->rqueue, arg);
- hisax_b_sched_event(bcs, B_RCVBUFREADY);
- break;
- case PH_DATA | CONFIRM:
- bcs->tx_cnt -= (long)arg;
- if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag)) {
- u_long flags;
- spin_lock_irqsave(&bcs->aclock, flags);
- bcs->ackcnt += (long)arg;
- spin_unlock_irqrestore(&bcs->aclock, flags);
- schedule_event(bcs, B_ACKPENDING);
- }
- skb = skb_dequeue(&bcs->squeue);
- if (skb) {
- B_L2L1(b_if, PH_DATA | REQUEST, skb);
- break;
- }
- clear_bit(BC_FLG_BUSY, &bcs->Flag);
- if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags)) {
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
- }
- break;
- default:
- printk("hisax_b_l1l2 pr %#x\n", pr);
- break;
- }
-}
-
-static void hisax_d_l2l1(struct PStack *st, int pr, void *arg)
-{
- struct IsdnCardState *cs = st->l1.hardware;
- struct hisax_d_if *hisax_d_if = cs->hw.hisax_d_if;
- struct sk_buff *skb = arg;
-
- switch (pr) {
- case PH_DATA | REQUEST:
- case PH_PULL | INDICATION:
- if (cs->debug & DEB_DLOG_HEX)
- LogFrame(cs, skb->data, skb->len);
- if (cs->debug & DEB_DLOG_VERBOSE)
- dlogframe(cs, skb, 0);
- Logl2Frame(cs, skb, "PH_DATA_REQ", 0);
- // FIXME lock?
- if (!test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags))
- D_L2L1(hisax_d_if, PH_DATA | REQUEST, skb);
- else
- skb_queue_tail(&cs->sq, skb);
- break;
- case PH_PULL | REQUEST:
- if (!test_bit(FLG_L1_DBUSY, &cs->HW_Flags))
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
- else
- set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- break;
- default:
- D_L2L1(hisax_d_if, pr, arg);
- break;
- }
-}
-
-static int hisax_cardmsg(struct IsdnCardState *cs, int mt, void *arg)
-{
- return 0;
-}
-
-static void hisax_b_l2l1(struct PStack *st, int pr, void *arg)
-{
- struct BCState *bcs = st->l1.bcs;
- struct hisax_b_if *b_if = bcs->hw.b_if;
-
- switch (pr) {
- case PH_ACTIVATE | REQUEST:
- B_L2L1(b_if, pr, (void *)(unsigned long)st->l1.mode);
- break;
- case PH_DATA | REQUEST:
- case PH_PULL | INDICATION:
- // FIXME lock?
- if (!test_and_set_bit(BC_FLG_BUSY, &bcs->Flag)) {
- B_L2L1(b_if, PH_DATA | REQUEST, arg);
- } else {
- skb_queue_tail(&bcs->squeue, arg);
- }
- break;
- case PH_PULL | REQUEST:
- if (!test_bit(BC_FLG_BUSY, &bcs->Flag))
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
- else
- set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- break;
- case PH_DEACTIVATE | REQUEST:
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- skb_queue_purge(&bcs->squeue);
- /* fall through */
- default:
- B_L2L1(b_if, pr, arg);
- break;
- }
-}
-
-static int hisax_bc_setstack(struct PStack *st, struct BCState *bcs)
-{
- struct IsdnCardState *cs = st->l1.hardware;
- struct hisax_d_if *hisax_d_if = cs->hw.hisax_d_if;
-
- bcs->channel = st->l1.bc;
-
- bcs->hw.b_if = hisax_d_if->b_if[st->l1.bc];
- hisax_d_if->b_if[st->l1.bc]->bcs = bcs;
-
- st->l1.bcs = bcs;
- st->l2.l2l1 = hisax_b_l2l1;
- setstack_manager(st);
- bcs->st = st;
- setstack_l1_B(st);
- skb_queue_head_init(&bcs->rqueue);
- skb_queue_head_init(&bcs->squeue);
- return 0;
-}
-
-static void hisax_bc_close(struct BCState *bcs)
-{
- struct hisax_b_if *b_if = bcs->hw.b_if;
-
- if (b_if)
- B_L2L1(b_if, PH_DEACTIVATE | REQUEST, NULL);
-}
-
-static void EChannel_proc_rcv(struct hisax_d_if *d_if)
-{
- struct IsdnCardState *cs = d_if->cs;
- u_char *ptr;
- struct sk_buff *skb;
-
- while ((skb = skb_dequeue(&d_if->erq)) != NULL) {
- if (cs->debug & DEB_DLOG_HEX) {
- ptr = cs->dlog;
- if ((skb->len) < MAX_DLOG_SPACE / 3 - 10) {
- *ptr++ = 'E';
- *ptr++ = 'C';
- *ptr++ = 'H';
- *ptr++ = 'O';
- *ptr++ = ':';
- ptr += QuickHex(ptr, skb->data, skb->len);
- ptr--;
- *ptr++ = '\n';
- *ptr = 0;
- HiSax_putstatus(cs, NULL, cs->dlog);
- } else
- HiSax_putstatus(cs, "LogEcho: ",
- "warning Frame too big (%d)",
- skb->len);
- }
- dev_kfree_skb_any(skb);
- }
-}
-
-#ifdef CONFIG_PCI
-#include <linux/pci.h>
-
-static const struct pci_device_id hisax_pci_tbl[] __used = {
-#ifdef CONFIG_HISAX_FRITZPCI
- {PCI_VDEVICE(AVM, PCI_DEVICE_ID_AVM_A1) },
-#endif
-#ifdef CONFIG_HISAX_DIEHLDIVA
- {PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA20) },
- {PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA20_U) },
- {PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA201) },
-/*##########################################################################*/
- {PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA202) },
-/*##########################################################################*/
-#endif
-#ifdef CONFIG_HISAX_ELSA
- {PCI_VDEVICE(ELSA, PCI_DEVICE_ID_ELSA_MICROLINK) },
- {PCI_VDEVICE(ELSA, PCI_DEVICE_ID_ELSA_QS3000) },
-#endif
-#ifdef CONFIG_HISAX_GAZEL
- {PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_R685) },
- {PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_R753) },
- {PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_DJINN_ITOO) },
- {PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_OLITEC) },
-#endif
-#ifdef CONFIG_HISAX_SCT_QUADRO
- {PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_9050) },
-#endif
-#ifdef CONFIG_HISAX_NICCY
- {PCI_VDEVICE(SATSAGEM, PCI_DEVICE_ID_SATSAGEM_NICCY) },
-#endif
-#ifdef CONFIG_HISAX_SEDLBAUER
- {PCI_VDEVICE(TIGERJET, PCI_DEVICE_ID_TIGERJET_100) },
-#endif
-#if defined(CONFIG_HISAX_NETJET) || defined(CONFIG_HISAX_NETJET_U)
- {PCI_VDEVICE(TIGERJET, PCI_DEVICE_ID_TIGERJET_300) },
-#endif
-#if defined(CONFIG_HISAX_TELESPCI) || defined(CONFIG_HISAX_SCT_QUADRO)
- {PCI_VDEVICE(ZORAN, PCI_DEVICE_ID_ZORAN_36120) },
-#endif
-#ifdef CONFIG_HISAX_W6692
- {PCI_VDEVICE(DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH) },
- {PCI_VDEVICE(WINBOND2, PCI_DEVICE_ID_WINBOND2_6692) },
-#endif
-#ifdef CONFIG_HISAX_HFC_PCI
- {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_2BD0) },
- {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B000) },
- {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B006) },
- {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B007) },
- {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B008) },
- {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B009) },
- {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00A) },
- {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00B) },
- {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00C) },
- {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B100) },
- {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B700) },
- {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B701) },
- {PCI_VDEVICE(ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1) },
- {PCI_VDEVICE(ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675) },
- {PCI_VDEVICE(BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT) },
- {PCI_VDEVICE(BERKOM, PCI_DEVICE_ID_BERKOM_A1T) },
- {PCI_VDEVICE(ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575) },
- {PCI_VDEVICE(ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0) },
- {PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E) },
- {PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_E) },
- {PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A) },
- {PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_A) },
-#endif
- { } /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(pci, hisax_pci_tbl);
-#endif /* CONFIG_PCI */
-
-module_init(HiSax_init);
-module_exit(HiSax_exit);
-
-EXPORT_SYMBOL(FsmNew);
-EXPORT_SYMBOL(FsmFree);
-EXPORT_SYMBOL(FsmEvent);
-EXPORT_SYMBOL(FsmChangeState);
-EXPORT_SYMBOL(FsmInitTimer);
-EXPORT_SYMBOL(FsmDelTimer);
-EXPORT_SYMBOL(FsmRestartTimer);
diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c
deleted file mode 100644
index d23df7a7784d..000000000000
--- a/drivers/isdn/hisax/diva.c
+++ /dev/null
@@ -1,1282 +0,0 @@
-/* $Id: diva.c,v 1.33.2.6 2004/02/11 13:21:33 keil Exp $
- *
- * low level stuff for Eicon.Diehl Diva Family ISDN cards
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * For changes and modifications please read
- * Documentation/isdn/HiSax.cert
- *
- * Thanks to Eicon Technology for documents and information
- *
- */
-
-#include <linux/init.h>
-#include "hisax.h"
-#include "isac.h"
-#include "hscx.h"
-#include "ipac.h"
-#include "ipacx.h"
-#include "isdnl1.h"
-#include <linux/pci.h>
-#include <linux/isapnp.h>
-
-static const char *Diva_revision = "$Revision: 1.33.2.6 $";
-
-#define byteout(addr, val) outb(val, addr)
-#define bytein(addr) inb(addr)
-
-#define DIVA_HSCX_DATA 0
-#define DIVA_HSCX_ADR 4
-#define DIVA_ISA_ISAC_DATA 2
-#define DIVA_ISA_ISAC_ADR 6
-#define DIVA_ISA_CTRL 7
-#define DIVA_IPAC_ADR 0
-#define DIVA_IPAC_DATA 1
-
-#define DIVA_PCI_ISAC_DATA 8
-#define DIVA_PCI_ISAC_ADR 0xc
-#define DIVA_PCI_CTRL 0x10
-
-/* SUB Types */
-#define DIVA_ISA 1
-#define DIVA_PCI 2
-#define DIVA_IPAC_ISA 3
-#define DIVA_IPAC_PCI 4
-#define DIVA_IPACX_PCI 5
-
-/* CTRL (Read) */
-#define DIVA_IRQ_STAT 0x01
-#define DIVA_EEPROM_SDA 0x02
-
-/* CTRL (Write) */
-#define DIVA_IRQ_REQ 0x01
-#define DIVA_RESET 0x08
-#define DIVA_EEPROM_CLK 0x40
-#define DIVA_PCI_LED_A 0x10
-#define DIVA_PCI_LED_B 0x20
-#define DIVA_ISA_LED_A 0x20
-#define DIVA_ISA_LED_B 0x40
-#define DIVA_IRQ_CLR 0x80
-
-/* Siemens PITA */
-#define PITA_MISC_REG 0x1c
-#ifdef __BIG_ENDIAN
-#define PITA_PARA_SOFTRESET 0x00000001
-#define PITA_SER_SOFTRESET 0x00000002
-#define PITA_PARA_MPX_MODE 0x00000004
-#define PITA_INT0_ENABLE 0x00000200
-#else
-#define PITA_PARA_SOFTRESET 0x01000000
-#define PITA_SER_SOFTRESET 0x02000000
-#define PITA_PARA_MPX_MODE 0x04000000
-#define PITA_INT0_ENABLE 0x00020000
-#endif
-#define PITA_INT0_STATUS 0x02
-
-static inline u_char
-readreg(unsigned int ale, unsigned int adr, u_char off)
-{
- register u_char ret;
-
- byteout(ale, off);
- ret = bytein(adr);
- return (ret);
-}
-
-static inline void
-readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
-{
- byteout(ale, off);
- insb(adr, data, size);
-}
-
-
-static inline void
-writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
-{
- byteout(ale, off);
- byteout(adr, data);
-}
-
-static inline void
-writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
-{
- byteout(ale, off);
- outsb(adr, data, size);
-}
-
-static inline u_char
-memreadreg(unsigned long adr, u_char off)
-{
- return (*((unsigned char *)
- (((unsigned int *)adr) + off)));
-}
-
-static inline void
-memwritereg(unsigned long adr, u_char off, u_char data)
-{
- register u_char *p;
-
- p = (unsigned char *)(((unsigned int *)adr) + off);
- *p = data;
-}
-
-/* Interface functions */
-
-static u_char
-ReadISAC(struct IsdnCardState *cs, u_char offset)
-{
- return (readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset));
-}
-
-static void
-WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
-{
- writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset, value);
-}
-
-static void
-ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- readfifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0, data, size);
-}
-
-static void
-WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- writefifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0, data, size);
-}
-
-static u_char
-ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset)
-{
- return (readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset + 0x80));
-}
-
-static void
-WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value)
-{
- writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset | 0x80, value);
-}
-
-static void
-ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size)
-{
- readfifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0x80, data, size);
-}
-
-static void
-WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size)
-{
- writefifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0x80, data, size);
-}
-
-static u_char
-ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
-{
- return (readreg(cs->hw.diva.hscx_adr,
- cs->hw.diva.hscx, offset + (hscx ? 0x40 : 0)));
-}
-
-static void
-WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
-{
- writereg(cs->hw.diva.hscx_adr,
- cs->hw.diva.hscx, offset + (hscx ? 0x40 : 0), value);
-}
-
-static u_char
-MemReadISAC_IPAC(struct IsdnCardState *cs, u_char offset)
-{
- return (memreadreg(cs->hw.diva.cfg_reg, offset + 0x80));
-}
-
-static void
-MemWriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value)
-{
- memwritereg(cs->hw.diva.cfg_reg, offset | 0x80, value);
-}
-
-static void
-MemReadISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size)
-{
- while (size--)
- *data++ = memreadreg(cs->hw.diva.cfg_reg, 0x80);
-}
-
-static void
-MemWriteISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size)
-{
- while (size--)
- memwritereg(cs->hw.diva.cfg_reg, 0x80, *data++);
-}
-
-static u_char
-MemReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
-{
- return (memreadreg(cs->hw.diva.cfg_reg, offset + (hscx ? 0x40 : 0)));
-}
-
-static void
-MemWriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
-{
- memwritereg(cs->hw.diva.cfg_reg, offset + (hscx ? 0x40 : 0), value);
-}
-
-/* IO-Functions for IPACX type cards */
-static u_char
-MemReadISAC_IPACX(struct IsdnCardState *cs, u_char offset)
-{
- return (memreadreg(cs->hw.diva.cfg_reg, offset));
-}
-
-static void
-MemWriteISAC_IPACX(struct IsdnCardState *cs, u_char offset, u_char value)
-{
- memwritereg(cs->hw.diva.cfg_reg, offset, value);
-}
-
-static void
-MemReadISACfifo_IPACX(struct IsdnCardState *cs, u_char *data, int size)
-{
- while (size--)
- *data++ = memreadreg(cs->hw.diva.cfg_reg, 0);
-}
-
-static void
-MemWriteISACfifo_IPACX(struct IsdnCardState *cs, u_char *data, int size)
-{
- while (size--)
- memwritereg(cs->hw.diva.cfg_reg, 0, *data++);
-}
-
-static u_char
-MemReadHSCX_IPACX(struct IsdnCardState *cs, int hscx, u_char offset)
-{
- return (memreadreg(cs->hw.diva.cfg_reg, offset +
- (hscx ? IPACX_OFF_B2 : IPACX_OFF_B1)));
-}
-
-static void
-MemWriteHSCX_IPACX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
-{
- memwritereg(cs->hw.diva.cfg_reg, offset +
- (hscx ? IPACX_OFF_B2 : IPACX_OFF_B1), value);
-}
-
-/*
- * fast interrupt HSCX stuff goes here
- */
-
-#define READHSCX(cs, nr, reg) readreg(cs->hw.diva.hscx_adr, \
- cs->hw.diva.hscx, reg + (nr ? 0x40 : 0))
-#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.diva.hscx_adr, \
- cs->hw.diva.hscx, reg + (nr ? 0x40 : 0), data)
-
-#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.diva.hscx_adr, \
- cs->hw.diva.hscx, (nr ? 0x40 : 0), ptr, cnt)
-
-#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.diva.hscx_adr, \
- cs->hw.diva.hscx, (nr ? 0x40 : 0), ptr, cnt)
-
-#include "hscx_irq.c"
-
-static irqreturn_t
-diva_interrupt(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_char val, sval;
- u_long flags;
- int cnt = 5;
-
- spin_lock_irqsave(&cs->lock, flags);
- while (((sval = bytein(cs->hw.diva.ctrl)) & DIVA_IRQ_REQ) && cnt) {
- val = readreg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_ISTA + 0x40);
- if (val)
- hscx_int_main(cs, val);
- val = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_ISTA);
- if (val)
- isac_interrupt(cs, val);
- cnt--;
- }
- if (!cnt)
- printk(KERN_WARNING "Diva: IRQ LOOP\n");
- writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK, 0xFF);
- writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK + 0x40, 0xFF);
- writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_MASK, 0xFF);
- writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_MASK, 0x0);
- writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK, 0x0);
- writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK + 0x40, 0x0);
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static irqreturn_t
-diva_irq_ipac_isa(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_char ista, val;
- u_long flags;
- int icnt = 5;
-
- spin_lock_irqsave(&cs->lock, flags);
- ista = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ISTA);
-Start_IPACISA:
- if (cs->debug & L1_DEB_IPAC)
- debugl1(cs, "IPAC ISTA %02X", ista);
- if (ista & 0x0f) {
- val = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, HSCX_ISTA + 0x40);
- if (ista & 0x01)
- val |= 0x01;
- if (ista & 0x04)
- val |= 0x02;
- if (ista & 0x08)
- val |= 0x04;
- if (val)
- hscx_int_main(cs, val);
- }
- if (ista & 0x20) {
- val = 0xfe & readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_ISTA + 0x80);
- if (val) {
- isac_interrupt(cs, val);
- }
- }
- if (ista & 0x10) {
- val = 0x01;
- isac_interrupt(cs, val);
- }
- ista = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ISTA);
- if ((ista & 0x3f) && icnt) {
- icnt--;
- goto Start_IPACISA;
- }
- if (!icnt)
- printk(KERN_WARNING "DIVA IPAC IRQ LOOP\n");
- writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xFF);
- writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xC0);
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static inline void
-MemwaitforCEC(struct IsdnCardState *cs, int hscx)
-{
- int to = 50;
-
- while ((MemReadHSCX(cs, hscx, HSCX_STAR) & 0x04) && to) {
- udelay(1);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "HiSax: waitforCEC timeout\n");
-}
-
-
-static inline void
-MemwaitforXFW(struct IsdnCardState *cs, int hscx)
-{
- int to = 50;
-
- while (((MemReadHSCX(cs, hscx, HSCX_STAR) & 0x44) != 0x40) && to) {
- udelay(1);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "HiSax: waitforXFW timeout\n");
-}
-
-static inline void
-MemWriteHSCXCMDR(struct IsdnCardState *cs, int hscx, u_char data)
-{
- MemwaitforCEC(cs, hscx);
- MemWriteHSCX(cs, hscx, HSCX_CMDR, data);
-}
-
-static void
-Memhscx_empty_fifo(struct BCState *bcs, int count)
-{
- u_char *ptr;
- struct IsdnCardState *cs = bcs->cs;
- int cnt;
-
- if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
- debugl1(cs, "hscx_empty_fifo");
-
- if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "hscx_empty_fifo: incoming packet too large");
- MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);
- bcs->hw.hscx.rcvidx = 0;
- return;
- }
- ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
- cnt = count;
- while (cnt--)
- *ptr++ = memreadreg(cs->hw.diva.cfg_reg, bcs->hw.hscx.hscx ? 0x40 : 0);
- MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);
- ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
- bcs->hw.hscx.rcvidx += count;
- if (cs->debug & L1_DEB_HSCX_FIFO) {
- char *t = bcs->blog;
-
- t += sprintf(t, "hscx_empty_fifo %c cnt %d",
- bcs->hw.hscx.hscx ? 'B' : 'A', count);
- QuickHex(t, ptr, count);
- debugl1(cs, "%s", bcs->blog);
- }
-}
-
-static void
-Memhscx_fill_fifo(struct BCState *bcs)
-{
- struct IsdnCardState *cs = bcs->cs;
- int more, count, cnt;
- int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags) ? 64 : 32;
- u_char *ptr, *p;
-
- if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
- debugl1(cs, "hscx_fill_fifo");
-
- if (!bcs->tx_skb)
- return;
- if (bcs->tx_skb->len <= 0)
- return;
-
- more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
- if (bcs->tx_skb->len > fifo_size) {
- more = !0;
- count = fifo_size;
- } else
- count = bcs->tx_skb->len;
- cnt = count;
- MemwaitforXFW(cs, bcs->hw.hscx.hscx);
- p = ptr = bcs->tx_skb->data;
- skb_pull(bcs->tx_skb, count);
- bcs->tx_cnt -= count;
- bcs->hw.hscx.count += count;
- while (cnt--)
- memwritereg(cs->hw.diva.cfg_reg, bcs->hw.hscx.hscx ? 0x40 : 0,
- *p++);
- MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, more ? 0x8 : 0xa);
- if (cs->debug & L1_DEB_HSCX_FIFO) {
- char *t = bcs->blog;
-
- t += sprintf(t, "hscx_fill_fifo %c cnt %d",
- bcs->hw.hscx.hscx ? 'B' : 'A', count);
- QuickHex(t, ptr, count);
- debugl1(cs, "%s", bcs->blog);
- }
-}
-
-static void
-Memhscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
-{
- u_char r;
- struct BCState *bcs = cs->bcs + hscx;
- struct sk_buff *skb;
- int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags) ? 64 : 32;
- int count;
-
- if (!test_bit(BC_FLG_INIT, &bcs->Flag))
- return;
-
- if (val & 0x80) { /* RME */
- r = MemReadHSCX(cs, hscx, HSCX_RSTA);
- if ((r & 0xf0) != 0xa0) {
- if (!(r & 0x80))
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "HSCX invalid frame");
- if ((r & 0x40) && bcs->mode)
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "HSCX RDO mode=%d",
- bcs->mode);
- if (!(r & 0x20))
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "HSCX CRC error");
- MemWriteHSCXCMDR(cs, hscx, 0x80);
- } else {
- count = MemReadHSCX(cs, hscx, HSCX_RBCL) & (
- test_bit(HW_IPAC, &cs->HW_Flags) ? 0x3f : 0x1f);
- if (count == 0)
- count = fifo_size;
- Memhscx_empty_fifo(bcs, count);
- if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
- if (cs->debug & L1_DEB_HSCX_FIFO)
- debugl1(cs, "HX Frame %d", count);
- if (!(skb = dev_alloc_skb(count)))
- printk(KERN_WARNING "HSCX: receive out of memory\n");
- else {
- skb_put_data(skb, bcs->hw.hscx.rcvbuf,
- count);
- skb_queue_tail(&bcs->rqueue, skb);
- }
- }
- }
- bcs->hw.hscx.rcvidx = 0;
- schedule_event(bcs, B_RCVBUFREADY);
- }
- if (val & 0x40) { /* RPF */
- Memhscx_empty_fifo(bcs, fifo_size);
- if (bcs->mode == L1_MODE_TRANS) {
- /* receive audio data */
- if (!(skb = dev_alloc_skb(fifo_size)))
- printk(KERN_WARNING "HiSax: receive out of memory\n");
- else {
- skb_put_data(skb, bcs->hw.hscx.rcvbuf,
- fifo_size);
- skb_queue_tail(&bcs->rqueue, skb);
- }
- bcs->hw.hscx.rcvidx = 0;
- schedule_event(bcs, B_RCVBUFREADY);
- }
- }
- if (val & 0x10) { /* XPR */
- if (bcs->tx_skb) {
- if (bcs->tx_skb->len) {
- Memhscx_fill_fifo(bcs);
- return;
- } else {
- if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
- (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
- u_long flags;
- spin_lock_irqsave(&bcs->aclock, flags);
- bcs->ackcnt += bcs->hw.hscx.count;
- spin_unlock_irqrestore(&bcs->aclock, flags);
- schedule_event(bcs, B_ACKPENDING);
- }
- dev_kfree_skb_irq(bcs->tx_skb);
- bcs->hw.hscx.count = 0;
- bcs->tx_skb = NULL;
- }
- }
- if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
- bcs->hw.hscx.count = 0;
- test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
- Memhscx_fill_fifo(bcs);
- } else {
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- schedule_event(bcs, B_XMTBUFREADY);
- }
- }
-}
-
-static inline void
-Memhscx_int_main(struct IsdnCardState *cs, u_char val)
-{
-
- u_char exval;
- struct BCState *bcs;
-
- if (val & 0x01) { // EXB
- bcs = cs->bcs + 1;
- exval = MemReadHSCX(cs, 1, HSCX_EXIR);
- if (exval & 0x40) {
- if (bcs->mode == 1)
- Memhscx_fill_fifo(bcs);
- else {
- /* Here we lost an TX interrupt, so
- * restart transmitting the whole frame.
- */
- if (bcs->tx_skb) {
- skb_push(bcs->tx_skb, bcs->hw.hscx.count);
- bcs->tx_cnt += bcs->hw.hscx.count;
- bcs->hw.hscx.count = 0;
- }
- MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "HSCX B EXIR %x Lost TX", exval);
- }
- } else if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "HSCX B EXIR %x", exval);
- }
- if (val & 0xf8) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "HSCX B interrupt %x", val);
- Memhscx_interrupt(cs, val, 1);
- }
- if (val & 0x02) { // EXA
- bcs = cs->bcs;
- exval = MemReadHSCX(cs, 0, HSCX_EXIR);
- if (exval & 0x40) {
- if (bcs->mode == L1_MODE_TRANS)
- Memhscx_fill_fifo(bcs);
- else {
- /* Here we lost an TX interrupt, so
- * restart transmitting the whole frame.
- */
- if (bcs->tx_skb) {
- skb_push(bcs->tx_skb, bcs->hw.hscx.count);
- bcs->tx_cnt += bcs->hw.hscx.count;
- bcs->hw.hscx.count = 0;
- }
- MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "HSCX A EXIR %x Lost TX", exval);
- }
- } else if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "HSCX A EXIR %x", exval);
- }
- if (val & 0x04) { // ICA
- exval = MemReadHSCX(cs, 0, HSCX_ISTA);
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "HSCX A interrupt %x", exval);
- Memhscx_interrupt(cs, exval, 0);
- }
-}
-
-static irqreturn_t
-diva_irq_ipac_pci(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_char ista, val;
- int icnt = 5;
- u_char *cfg;
- u_long flags;
-
- spin_lock_irqsave(&cs->lock, flags);
- cfg = (u_char *) cs->hw.diva.pci_cfg;
- val = *cfg;
- if (!(val & PITA_INT0_STATUS)) {
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_NONE; /* other shared IRQ */
- }
- *cfg = PITA_INT0_STATUS; /* Reset pending INT0 */
- ista = memreadreg(cs->hw.diva.cfg_reg, IPAC_ISTA);
-Start_IPACPCI:
- if (cs->debug & L1_DEB_IPAC)
- debugl1(cs, "IPAC ISTA %02X", ista);
- if (ista & 0x0f) {
- val = memreadreg(cs->hw.diva.cfg_reg, HSCX_ISTA + 0x40);
- if (ista & 0x01)
- val |= 0x01;
- if (ista & 0x04)
- val |= 0x02;
- if (ista & 0x08)
- val |= 0x04;
- if (val)
- Memhscx_int_main(cs, val);
- }
- if (ista & 0x20) {
- val = 0xfe & memreadreg(cs->hw.diva.cfg_reg, ISAC_ISTA + 0x80);
- if (val) {
- isac_interrupt(cs, val);
- }
- }
- if (ista & 0x10) {
- val = 0x01;
- isac_interrupt(cs, val);
- }
- ista = memreadreg(cs->hw.diva.cfg_reg, IPAC_ISTA);
- if ((ista & 0x3f) && icnt) {
- icnt--;
- goto Start_IPACPCI;
- }
- if (!icnt)
- printk(KERN_WARNING "DIVA IPAC PCI IRQ LOOP\n");
- memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xFF);
- memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xC0);
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static irqreturn_t
-diva_irq_ipacx_pci(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_char val;
- u_char *cfg;
- u_long flags;
-
- spin_lock_irqsave(&cs->lock, flags);
- cfg = (u_char *) cs->hw.diva.pci_cfg;
- val = *cfg;
- if (!(val & PITA_INT0_STATUS)) {
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_NONE; // other shared IRQ
- }
- interrupt_ipacx(cs); // handler for chip
- *cfg = PITA_INT0_STATUS; // Reset PLX interrupt
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static void
-release_io_diva(struct IsdnCardState *cs)
-{
- int bytecnt;
-
- if ((cs->subtyp == DIVA_IPAC_PCI) ||
- (cs->subtyp == DIVA_IPACX_PCI)) {
- u_int *cfg = (unsigned int *)cs->hw.diva.pci_cfg;
-
- *cfg = 0; /* disable INT0/1 */
- *cfg = 2; /* reset pending INT0 */
- if (cs->hw.diva.cfg_reg)
- iounmap((void *)cs->hw.diva.cfg_reg);
- if (cs->hw.diva.pci_cfg)
- iounmap((void *)cs->hw.diva.pci_cfg);
- return;
- } else if (cs->subtyp != DIVA_IPAC_ISA) {
- del_timer(&cs->hw.diva.tl);
- if (cs->hw.diva.cfg_reg)
- byteout(cs->hw.diva.ctrl, 0); /* LED off, Reset */
- }
- if ((cs->subtyp == DIVA_ISA) || (cs->subtyp == DIVA_IPAC_ISA))
- bytecnt = 8;
- else
- bytecnt = 32;
- if (cs->hw.diva.cfg_reg) {
- release_region(cs->hw.diva.cfg_reg, bytecnt);
- }
-}
-
-static void
-iounmap_diva(struct IsdnCardState *cs)
-{
- if ((cs->subtyp == DIVA_IPAC_PCI) || (cs->subtyp == DIVA_IPACX_PCI)) {
- if (cs->hw.diva.cfg_reg) {
- iounmap((void *)cs->hw.diva.cfg_reg);
- cs->hw.diva.cfg_reg = 0;
- }
- if (cs->hw.diva.pci_cfg) {
- iounmap((void *)cs->hw.diva.pci_cfg);
- cs->hw.diva.pci_cfg = 0;
- }
- }
-
- return;
-}
-
-static void
-reset_diva(struct IsdnCardState *cs)
-{
- if (cs->subtyp == DIVA_IPAC_ISA) {
- writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x20);
- mdelay(10);
- writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x00);
- mdelay(10);
- writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xc0);
- } else if (cs->subtyp == DIVA_IPAC_PCI) {
- unsigned int *ireg = (unsigned int *)(cs->hw.diva.pci_cfg +
- PITA_MISC_REG);
- *ireg = PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE;
- mdelay(10);
- *ireg = PITA_PARA_MPX_MODE;
- mdelay(10);
- memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xc0);
- } else if (cs->subtyp == DIVA_IPACX_PCI) {
- unsigned int *ireg = (unsigned int *)(cs->hw.diva.pci_cfg +
- PITA_MISC_REG);
- *ireg = PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE;
- mdelay(10);
- *ireg = PITA_PARA_MPX_MODE | PITA_SER_SOFTRESET;
- mdelay(10);
- MemWriteISAC_IPACX(cs, IPACX_MASK, 0xff); // Interrupts off
- } else { /* DIVA 2.0 */
- cs->hw.diva.ctrl_reg = 0; /* Reset On */
- byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
- mdelay(10);
- cs->hw.diva.ctrl_reg |= DIVA_RESET; /* Reset Off */
- byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
- mdelay(10);
- if (cs->subtyp == DIVA_ISA)
- cs->hw.diva.ctrl_reg |= DIVA_ISA_LED_A;
- else {
- /* Workaround PCI9060 */
- byteout(cs->hw.diva.pci_cfg + 0x69, 9);
- cs->hw.diva.ctrl_reg |= DIVA_PCI_LED_A;
- }
- byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
- }
-}
-
-#define DIVA_ASSIGN 1
-
-static void
-diva_led_handler(struct timer_list *t)
-{
- struct IsdnCardState *cs = from_timer(cs, t, hw.diva.tl);
- int blink = 0;
-
- if ((cs->subtyp == DIVA_IPAC_ISA) ||
- (cs->subtyp == DIVA_IPAC_PCI) ||
- (cs->subtyp == DIVA_IPACX_PCI))
- return;
- del_timer(&cs->hw.diva.tl);
- if (cs->hw.diva.status & DIVA_ASSIGN)
- cs->hw.diva.ctrl_reg |= (DIVA_ISA == cs->subtyp) ?
- DIVA_ISA_LED_A : DIVA_PCI_LED_A;
- else {
- cs->hw.diva.ctrl_reg ^= (DIVA_ISA == cs->subtyp) ?
- DIVA_ISA_LED_A : DIVA_PCI_LED_A;
- blink = 250;
- }
- if (cs->hw.diva.status & 0xf000)
- cs->hw.diva.ctrl_reg |= (DIVA_ISA == cs->subtyp) ?
- DIVA_ISA_LED_B : DIVA_PCI_LED_B;
- else if (cs->hw.diva.status & 0x0f00) {
- cs->hw.diva.ctrl_reg ^= (DIVA_ISA == cs->subtyp) ?
- DIVA_ISA_LED_B : DIVA_PCI_LED_B;
- blink = 500;
- } else
- cs->hw.diva.ctrl_reg &= ~((DIVA_ISA == cs->subtyp) ?
- DIVA_ISA_LED_B : DIVA_PCI_LED_B);
-
- byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
- if (blink) {
- cs->hw.diva.tl.expires = jiffies + ((blink * HZ) / 1000);
- add_timer(&cs->hw.diva.tl);
- }
-}
-
-static int
-Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
- u_int *ireg;
- u_long flags;
-
- switch (mt) {
- case CARD_RESET:
- spin_lock_irqsave(&cs->lock, flags);
- reset_diva(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_RELEASE:
- release_io_diva(cs);
- return (0);
- case CARD_INIT:
- spin_lock_irqsave(&cs->lock, flags);
- reset_diva(cs);
- if (cs->subtyp == DIVA_IPACX_PCI) {
- ireg = (unsigned int *)cs->hw.diva.pci_cfg;
- *ireg = PITA_INT0_ENABLE;
- init_ipacx(cs, 3); // init chip and enable interrupts
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- }
- if (cs->subtyp == DIVA_IPAC_PCI) {
- ireg = (unsigned int *)cs->hw.diva.pci_cfg;
- *ireg = PITA_INT0_ENABLE;
- }
- inithscxisac(cs, 3);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_TEST:
- return (0);
- case (MDL_REMOVE | REQUEST):
- cs->hw.diva.status = 0;
- break;
- case (MDL_ASSIGN | REQUEST):
- cs->hw.diva.status |= DIVA_ASSIGN;
- break;
- case MDL_INFO_SETUP:
- if ((long)arg)
- cs->hw.diva.status |= 0x0200;
- else
- cs->hw.diva.status |= 0x0100;
- break;
- case MDL_INFO_CONN:
- if ((long)arg)
- cs->hw.diva.status |= 0x2000;
- else
- cs->hw.diva.status |= 0x1000;
- break;
- case MDL_INFO_REL:
- if ((long)arg) {
- cs->hw.diva.status &= ~0x2000;
- cs->hw.diva.status &= ~0x0200;
- } else {
- cs->hw.diva.status &= ~0x1000;
- cs->hw.diva.status &= ~0x0100;
- }
- break;
- }
- if ((cs->subtyp != DIVA_IPAC_ISA) &&
- (cs->subtyp != DIVA_IPAC_PCI) &&
- (cs->subtyp != DIVA_IPACX_PCI)) {
- spin_lock_irqsave(&cs->lock, flags);
- diva_led_handler(&cs->hw.diva.tl);
- spin_unlock_irqrestore(&cs->lock, flags);
- }
- return (0);
-}
-
-static int setup_diva_common(struct IsdnCardState *cs)
-{
- int bytecnt;
- u_char val;
-
- if ((cs->subtyp == DIVA_ISA) || (cs->subtyp == DIVA_IPAC_ISA))
- bytecnt = 8;
- else
- bytecnt = 32;
-
- printk(KERN_INFO
- "Diva: %s card configured at %#lx IRQ %d\n",
- (cs->subtyp == DIVA_PCI) ? "PCI" :
- (cs->subtyp == DIVA_ISA) ? "ISA" :
- (cs->subtyp == DIVA_IPAC_ISA) ? "IPAC ISA" :
- (cs->subtyp == DIVA_IPAC_PCI) ? "IPAC PCI" : "IPACX PCI",
- cs->hw.diva.cfg_reg, cs->irq);
- if ((cs->subtyp == DIVA_IPAC_PCI) ||
- (cs->subtyp == DIVA_IPACX_PCI) ||
- (cs->subtyp == DIVA_PCI))
- printk(KERN_INFO "Diva: %s space at %#lx\n",
- (cs->subtyp == DIVA_PCI) ? "PCI" :
- (cs->subtyp == DIVA_IPAC_PCI) ? "IPAC PCI" : "IPACX PCI",
- cs->hw.diva.pci_cfg);
- if ((cs->subtyp != DIVA_IPAC_PCI) &&
- (cs->subtyp != DIVA_IPACX_PCI)) {
- if (!request_region(cs->hw.diva.cfg_reg, bytecnt, "diva isdn")) {
- printk(KERN_WARNING
- "HiSax: %s config port %lx-%lx already in use\n",
- "diva",
- cs->hw.diva.cfg_reg,
- cs->hw.diva.cfg_reg + bytecnt);
- iounmap_diva(cs);
- return (0);
- }
- }
- cs->BC_Read_Reg = &ReadHSCX;
- cs->BC_Write_Reg = &WriteHSCX;
- cs->BC_Send_Data = &hscx_fill_fifo;
- cs->cardmsg = &Diva_card_msg;
- setup_isac(cs);
- if (cs->subtyp == DIVA_IPAC_ISA) {
- cs->readisac = &ReadISAC_IPAC;
- cs->writeisac = &WriteISAC_IPAC;
- cs->readisacfifo = &ReadISACfifo_IPAC;
- cs->writeisacfifo = &WriteISACfifo_IPAC;
- cs->irq_func = &diva_irq_ipac_isa;
- val = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ID);
- printk(KERN_INFO "Diva: IPAC version %x\n", val);
- } else if (cs->subtyp == DIVA_IPAC_PCI) {
- cs->readisac = &MemReadISAC_IPAC;
- cs->writeisac = &MemWriteISAC_IPAC;
- cs->readisacfifo = &MemReadISACfifo_IPAC;
- cs->writeisacfifo = &MemWriteISACfifo_IPAC;
- cs->BC_Read_Reg = &MemReadHSCX;
- cs->BC_Write_Reg = &MemWriteHSCX;
- cs->BC_Send_Data = &Memhscx_fill_fifo;
- cs->irq_func = &diva_irq_ipac_pci;
- val = memreadreg(cs->hw.diva.cfg_reg, IPAC_ID);
- printk(KERN_INFO "Diva: IPAC version %x\n", val);
- } else if (cs->subtyp == DIVA_IPACX_PCI) {
- cs->readisac = &MemReadISAC_IPACX;
- cs->writeisac = &MemWriteISAC_IPACX;
- cs->readisacfifo = &MemReadISACfifo_IPACX;
- cs->writeisacfifo = &MemWriteISACfifo_IPACX;
- cs->BC_Read_Reg = &MemReadHSCX_IPACX;
- cs->BC_Write_Reg = &MemWriteHSCX_IPACX;
- cs->BC_Send_Data = NULL; // function located in ipacx module
- cs->irq_func = &diva_irq_ipacx_pci;
- printk(KERN_INFO "Diva: IPACX Design Id: %x\n",
- MemReadISAC_IPACX(cs, IPACX_ID) & 0x3F);
- } else { /* DIVA 2.0 */
- timer_setup(&cs->hw.diva.tl, diva_led_handler, 0);
- cs->readisac = &ReadISAC;
- cs->writeisac = &WriteISAC;
- cs->readisacfifo = &ReadISACfifo;
- cs->writeisacfifo = &WriteISACfifo;
- cs->irq_func = &diva_interrupt;
- ISACVersion(cs, "Diva:");
- if (HscxVersion(cs, "Diva:")) {
- printk(KERN_WARNING
- "Diva: wrong HSCX versions check IO address\n");
- release_io_diva(cs);
- return (0);
- }
- }
- return (1);
-}
-
-#ifdef CONFIG_ISA
-
-static int setup_diva_isa(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
- u_char val;
-
- if (!card->para[1])
- return (-1); /* card not found; continue search */
-
- cs->hw.diva.ctrl_reg = 0;
- cs->hw.diva.cfg_reg = card->para[1];
- val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR,
- cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID);
- printk(KERN_INFO "Diva: IPAC version %x\n", val);
- if ((val == 1) || (val == 2)) {
- cs->subtyp = DIVA_IPAC_ISA;
- cs->hw.diva.ctrl = 0;
- cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA;
- cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA;
- cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR;
- cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR;
- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
- } else {
- cs->subtyp = DIVA_ISA;
- cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL;
- cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA;
- cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA;
- cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR;
- cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR;
- }
- cs->irq = card->para[0];
-
- return (1); /* card found */
-}
-
-#else /* if !CONFIG_ISA */
-
-static int setup_diva_isa(struct IsdnCard *card)
-{
- return (-1); /* card not found; continue search */
-}
-
-#endif /* CONFIG_ISA */
-
-#ifdef __ISAPNP__
-static struct isapnp_device_id diva_ids[] = {
- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
- ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
- (unsigned long) "Diva picola" },
- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
- ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51),
- (unsigned long) "Diva picola" },
- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
- ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
- (unsigned long) "Diva 2.0" },
- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
- ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71),
- (unsigned long) "Diva 2.0" },
- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
- ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
- (unsigned long) "Diva 2.01" },
- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
- ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1),
- (unsigned long) "Diva 2.01" },
- { 0, }
-};
-
-static struct isapnp_device_id *ipid = &diva_ids[0];
-static struct pnp_card *pnp_c = NULL;
-
-static int setup_diva_isapnp(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
- struct pnp_dev *pnp_d;
-
- if (!isapnp_present())
- return (-1); /* card not found; continue search */
-
- while (ipid->card_vendor) {
- if ((pnp_c = pnp_find_card(ipid->card_vendor,
- ipid->card_device, pnp_c))) {
- pnp_d = NULL;
- if ((pnp_d = pnp_find_dev(pnp_c,
- ipid->vendor, ipid->function, pnp_d))) {
- int err;
-
- printk(KERN_INFO "HiSax: %s detected\n",
- (char *)ipid->driver_data);
- pnp_disable_dev(pnp_d);
- err = pnp_activate_dev(pnp_d);
- if (err < 0) {
- printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __func__, err);
- return (0);
- }
- card->para[1] = pnp_port_start(pnp_d, 0);
- card->para[0] = pnp_irq(pnp_d, 0);
- if (card->para[0] == -1 || !card->para[1]) {
- printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n",
- card->para[0], card->para[1]);
- pnp_disable_dev(pnp_d);
- return (0);
- }
- cs->hw.diva.cfg_reg = card->para[1];
- cs->irq = card->para[0];
- if (ipid->function == ISAPNP_FUNCTION(0xA1)) {
- cs->subtyp = DIVA_IPAC_ISA;
- cs->hw.diva.ctrl = 0;
- cs->hw.diva.isac =
- card->para[1] + DIVA_IPAC_DATA;
- cs->hw.diva.hscx =
- card->para[1] + DIVA_IPAC_DATA;
- cs->hw.diva.isac_adr =
- card->para[1] + DIVA_IPAC_ADR;
- cs->hw.diva.hscx_adr =
- card->para[1] + DIVA_IPAC_ADR;
- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
- } else {
- cs->subtyp = DIVA_ISA;
- cs->hw.diva.ctrl =
- card->para[1] + DIVA_ISA_CTRL;
- cs->hw.diva.isac =
- card->para[1] + DIVA_ISA_ISAC_DATA;
- cs->hw.diva.hscx =
- card->para[1] + DIVA_HSCX_DATA;
- cs->hw.diva.isac_adr =
- card->para[1] + DIVA_ISA_ISAC_ADR;
- cs->hw.diva.hscx_adr =
- card->para[1] + DIVA_HSCX_ADR;
- }
- return (1); /* card found */
- } else {
- printk(KERN_ERR "Diva PnP: PnP error card found, no device\n");
- return (0);
- }
- }
- ipid++;
- pnp_c = NULL;
- }
-
- return (-1); /* card not found; continue search */
-}
-
-#else /* if !ISAPNP */
-
-static int setup_diva_isapnp(struct IsdnCard *card)
-{
- return (-1); /* card not found; continue search */
-}
-
-#endif /* ISAPNP */
-
-#ifdef CONFIG_PCI
-static struct pci_dev *dev_diva = NULL;
-static struct pci_dev *dev_diva_u = NULL;
-static struct pci_dev *dev_diva201 = NULL;
-static struct pci_dev *dev_diva202 = NULL;
-
-static int setup_diva_pci(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
-
- cs->subtyp = 0;
- if ((dev_diva = hisax_find_pci_device(PCI_VENDOR_ID_EICON,
- PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) {
- if (pci_enable_device(dev_diva))
- return (0);
- cs->subtyp = DIVA_PCI;
- cs->irq = dev_diva->irq;
- cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2);
- } else if ((dev_diva_u = hisax_find_pci_device(PCI_VENDOR_ID_EICON,
- PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) {
- if (pci_enable_device(dev_diva_u))
- return (0);
- cs->subtyp = DIVA_PCI;
- cs->irq = dev_diva_u->irq;
- cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2);
- } else if ((dev_diva201 = hisax_find_pci_device(PCI_VENDOR_ID_EICON,
- PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) {
- if (pci_enable_device(dev_diva201))
- return (0);
- cs->subtyp = DIVA_IPAC_PCI;
- cs->irq = dev_diva201->irq;
- cs->hw.diva.pci_cfg =
- (ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096);
- cs->hw.diva.cfg_reg =
- (ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096);
- } else if ((dev_diva202 = hisax_find_pci_device(PCI_VENDOR_ID_EICON,
- PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) {
- if (pci_enable_device(dev_diva202))
- return (0);
- cs->subtyp = DIVA_IPACX_PCI;
- cs->irq = dev_diva202->irq;
- cs->hw.diva.pci_cfg =
- (ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096);
- cs->hw.diva.cfg_reg =
- (ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096);
- } else {
- return (-1); /* card not found; continue search */
- }
-
- if (!cs->irq) {
- printk(KERN_WARNING "Diva: No IRQ for PCI card found\n");
- iounmap_diva(cs);
- return (0);
- }
-
- if (!cs->hw.diva.cfg_reg) {
- printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n");
- iounmap_diva(cs);
- return (0);
- }
- cs->irq_flags |= IRQF_SHARED;
-
- if ((cs->subtyp == DIVA_IPAC_PCI) ||
- (cs->subtyp == DIVA_IPACX_PCI)) {
- cs->hw.diva.ctrl = 0;
- cs->hw.diva.isac = 0;
- cs->hw.diva.hscx = 0;
- cs->hw.diva.isac_adr = 0;
- cs->hw.diva.hscx_adr = 0;
- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
- } else {
- cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL;
- cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA;
- cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA;
- cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR;
- cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR;
- }
-
- return (1); /* card found */
-}
-
-#else /* if !CONFIG_PCI */
-
-static int setup_diva_pci(struct IsdnCard *card)
-{
- return (-1); /* card not found; continue search */
-}
-
-#endif /* CONFIG_PCI */
-
-int setup_diva(struct IsdnCard *card)
-{
- int rc, have_card = 0;
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
-
- strcpy(tmp, Diva_revision);
- printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp));
- if (cs->typ != ISDN_CTYPE_DIEHLDIVA)
- return (0);
- cs->hw.diva.status = 0;
-
- rc = setup_diva_isa(card);
- if (!rc)
- return rc;
- if (rc > 0) {
- have_card = 1;
- goto ready;
- }
-
- rc = setup_diva_isapnp(card);
- if (!rc)
- return rc;
- if (rc > 0) {
- have_card = 1;
- goto ready;
- }
-
- rc = setup_diva_pci(card);
- if (!rc)
- return rc;
- if (rc > 0)
- have_card = 1;
-
-ready:
- if (!have_card) {
- printk(KERN_WARNING "Diva: No ISA, ISAPNP or PCI card found\n");
- return (0);
- }
-
- return setup_diva_common(card->cs);
-}
diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c
deleted file mode 100644
index 0754c0743790..000000000000
--- a/drivers/isdn/hisax/elsa.c
+++ /dev/null
@@ -1,1245 +0,0 @@
-/* $Id: elsa.c,v 2.32.2.4 2004/01/24 20:47:21 keil Exp $
- *
- * low level stuff for Elsa isdn cards
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * For changes and modifications please read
- * Documentation/isdn/HiSax.cert
- *
- * Thanks to Elsa GmbH for documents and information
- *
- * Klaus Lichtenwalder (Klaus.Lichtenwalder@WebForum.DE)
- * for ELSA PCMCIA support
- *
- */
-
-#include <linux/init.h>
-#include <linux/slab.h>
-#include "hisax.h"
-#include "arcofi.h"
-#include "isac.h"
-#include "ipac.h"
-#include "hscx.h"
-#include "isdnl1.h"
-#include <linux/pci.h>
-#include <linux/isapnp.h>
-#include <linux/serial.h>
-#include <linux/serial_reg.h>
-
-static const char *Elsa_revision = "$Revision: 2.32.2.4 $";
-static const char *Elsa_Types[] =
-{"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro",
- "PCMCIA", "QS 1000", "QS 3000", "Microlink PCI", "QS 3000 PCI",
- "PCMCIA-IPAC" };
-
-static const char *ITACVer[] =
-{"?0?", "?1?", "?2?", "?3?", "?4?", "V2.2",
- "B1", "A1"};
-
-#define byteout(addr, val) outb(val, addr)
-#define bytein(addr) inb(addr)
-
-#define ELSA_ISAC 0
-#define ELSA_ISAC_PCM 1
-#define ELSA_ITAC 1
-#define ELSA_HSCX 2
-#define ELSA_ALE 3
-#define ELSA_ALE_PCM 4
-#define ELSA_CONTROL 4
-#define ELSA_CONFIG 5
-#define ELSA_START_TIMER 6
-#define ELSA_TRIG_IRQ 7
-
-#define ELSA_PC 1
-#define ELSA_PCC8 2
-#define ELSA_PCC16 3
-#define ELSA_PCF 4
-#define ELSA_PCFPRO 5
-#define ELSA_PCMCIA 6
-#define ELSA_QS1000 7
-#define ELSA_QS3000 8
-#define ELSA_QS1000PCI 9
-#define ELSA_QS3000PCI 10
-#define ELSA_PCMCIA_IPAC 11
-
-/* PCI stuff */
-#define ELSA_PCI_IRQ_MASK 0x04
-
-/* ITAC Registeradressen (only Microlink PC) */
-#define ITAC_SYS 0x34
-#define ITAC_ISEN 0x48
-#define ITAC_RFIE 0x4A
-#define ITAC_XFIE 0x4C
-#define ITAC_SCIE 0x4E
-#define ITAC_STIE 0x46
-
-/*** ***
- *** Makros als Befehle fuer die Kartenregister ***
- *** (mehrere Befehle werden durch Bit-Oderung kombiniert) ***
- *** ***/
-
-/* Config-Register (Read) */
-#define ELIRQF_TIMER_RUN 0x02 /* Bit 1 des Config-Reg */
-#define ELIRQF_TIMER_RUN_PCC8 0x01 /* Bit 0 des Config-Reg bei PCC */
-#define ELSA_IRQ_IDX 0x38 /* Bit 3,4,5 des Config-Reg */
-#define ELSA_IRQ_IDX_PCC8 0x30 /* Bit 4,5 des Config-Reg */
-#define ELSA_IRQ_IDX_PC 0x0c /* Bit 2,3 des Config-Reg */
-
-/* Control-Register (Write) */
-#define ELSA_LINE_LED 0x02 /* Bit 1 Gelbe LED */
-#define ELSA_STAT_LED 0x08 /* Bit 3 Gruene LED */
-#define ELSA_ISDN_RESET 0x20 /* Bit 5 Reset-Leitung */
-#define ELSA_ENA_TIMER_INT 0x80 /* Bit 7 Freigabe Timer Interrupt */
-
-/* ALE-Register (Read) */
-#define ELSA_HW_RELEASE 0x07 /* Bit 0-2 Hardwarerkennung */
-#define ELSA_S0_POWER_BAD 0x08 /* Bit 3 S0-Bus Spannung fehlt */
-
-/* Status Flags */
-#define ELIRQF_TIMER_AKTIV 1
-#define ELSA_BAD_PWR 2
-#define ELSA_ASSIGN 4
-
-#define RS_ISR_PASS_LIMIT 256
-#define FLG_MODEM_ACTIVE 1
-/* IPAC AUX */
-#define ELSA_IPAC_LINE_LED 0x40 /* Bit 6 Gelbe LED */
-#define ELSA_IPAC_STAT_LED 0x80 /* Bit 7 Gruene LED */
-
-#if ARCOFI_USE
-static struct arcofi_msg ARCOFI_XOP_F =
-{NULL,0,2,{0xa1,0x3f,0,0,0,0,0,0,0,0}}; /* Normal OP */
-static struct arcofi_msg ARCOFI_XOP_1 =
-{&ARCOFI_XOP_F,0,2,{0xa1,0x31,0,0,0,0,0,0,0,0}}; /* PWR UP */
-static struct arcofi_msg ARCOFI_SOP_F =
-{&ARCOFI_XOP_1,0,10,{0xa1,0x1f,0x00,0x50,0x10,0x00,0x00,0x80,0x02,0x12}};
-static struct arcofi_msg ARCOFI_COP_9 =
-{&ARCOFI_SOP_F,0,10,{0xa1,0x29,0x80,0xcb,0xe9,0x88,0x00,0xc8,0xd8,0x80}}; /* RX */
-static struct arcofi_msg ARCOFI_COP_8 =
-{&ARCOFI_COP_9,0,10,{0xa1,0x28,0x49,0x31,0x8,0x13,0x6e,0x88,0x2a,0x61}}; /* TX */
-static struct arcofi_msg ARCOFI_COP_7 =
-{&ARCOFI_COP_8,0,4,{0xa1,0x27,0x80,0x80,0,0,0,0,0,0}}; /* GZ */
-static struct arcofi_msg ARCOFI_COP_6 =
-{&ARCOFI_COP_7,0,6,{0xa1,0x26,0,0,0x82,0x7c,0,0,0,0}}; /* GRL GRH */
-static struct arcofi_msg ARCOFI_COP_5 =
-{&ARCOFI_COP_6,0,4,{0xa1,0x25,0xbb,0x4a,0,0,0,0,0,0}}; /* GTX */
-static struct arcofi_msg ARCOFI_VERSION =
-{NULL,1,2,{0xa0,0,0,0,0,0,0,0,0,0}};
-static struct arcofi_msg ARCOFI_XOP_0 =
-{NULL,0,2,{0xa1,0x30,0,0,0,0,0,0,0,0}}; /* PWR Down */
-
-static void set_arcofi(struct IsdnCardState *cs, int bc);
-
-#include "elsa_ser.c"
-#endif /* ARCOFI_USE */
-
-static inline u_char
-readreg(unsigned int ale, unsigned int adr, u_char off)
-{
- register u_char ret;
-
- byteout(ale, off);
- ret = bytein(adr);
- return (ret);
-}
-
-static inline void
-readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
-{
- byteout(ale, off);
- insb(adr, data, size);
-}
-
-
-static inline void
-writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
-{
- byteout(ale, off);
- byteout(adr, data);
-}
-
-static inline void
-writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
-{
- byteout(ale, off);
- outsb(adr, data, size);
-}
-
-/* Interface functions */
-
-static u_char
-ReadISAC(struct IsdnCardState *cs, u_char offset)
-{
- return (readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset));
-}
-
-static void
-WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
-{
- writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset, value);
-}
-
-static void
-ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- readfifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0, data, size);
-}
-
-static void
-WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- writefifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0, data, size);
-}
-
-static u_char
-ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset)
-{
- return (readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset + 0x80));
-}
-
-static void
-WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value)
-{
- writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset | 0x80, value);
-}
-
-static void
-ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size)
-{
- readfifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0x80, data, size);
-}
-
-static void
-WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size)
-{
- writefifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0x80, data, size);
-}
-
-static u_char
-ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
-{
- return (readreg(cs->hw.elsa.ale,
- cs->hw.elsa.hscx, offset + (hscx ? 0x40 : 0)));
-}
-
-static void
-WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
-{
- writereg(cs->hw.elsa.ale,
- cs->hw.elsa.hscx, offset + (hscx ? 0x40 : 0), value);
-}
-
-static inline u_char
-readitac(struct IsdnCardState *cs, u_char off)
-{
- register u_char ret;
-
- byteout(cs->hw.elsa.ale, off);
- ret = bytein(cs->hw.elsa.itac);
- return (ret);
-}
-
-static inline void
-writeitac(struct IsdnCardState *cs, u_char off, u_char data)
-{
- byteout(cs->hw.elsa.ale, off);
- byteout(cs->hw.elsa.itac, data);
-}
-
-static inline int
-TimerRun(struct IsdnCardState *cs)
-{
- register u_char v;
-
- v = bytein(cs->hw.elsa.cfg);
- if ((cs->subtyp == ELSA_QS1000) || (cs->subtyp == ELSA_QS3000))
- return (0 == (v & ELIRQF_TIMER_RUN));
- else if (cs->subtyp == ELSA_PCC8)
- return (v & ELIRQF_TIMER_RUN_PCC8);
- return (v & ELIRQF_TIMER_RUN);
-}
-/*
- * fast interrupt HSCX stuff goes here
- */
-
-#define READHSCX(cs, nr, reg) readreg(cs->hw.elsa.ale, \
- cs->hw.elsa.hscx, reg + (nr ? 0x40 : 0))
-#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.elsa.ale, \
- cs->hw.elsa.hscx, reg + (nr ? 0x40 : 0), data)
-
-#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.elsa.ale, \
- cs->hw.elsa.hscx, (nr ? 0x40 : 0), ptr, cnt)
-
-#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.elsa.ale, \
- cs->hw.elsa.hscx, (nr ? 0x40 : 0), ptr, cnt)
-
-#include "hscx_irq.c"
-
-static irqreturn_t
-elsa_interrupt(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_long flags;
- u_char val;
- int icnt = 5;
-
- if ((cs->typ == ISDN_CTYPE_ELSA_PCMCIA) && (*cs->busy_flag == 1)) {
- /* The card tends to generate interrupts while being removed
- causing us to just crash the kernel. bad. */
- printk(KERN_WARNING "Elsa: card not available!\n");
- return IRQ_NONE;
- }
- spin_lock_irqsave(&cs->lock, flags);
-#if ARCOFI_USE
- if (cs->hw.elsa.MFlag) {
- val = serial_inp(cs, UART_IIR);
- if (!(val & UART_IIR_NO_INT)) {
- debugl1(cs, "IIR %02x", val);
- rs_interrupt_elsa(cs);
- }
- }
-#endif
- val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40);
-Start_HSCX:
- if (val) {
- hscx_int_main(cs, val);
- }
- val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA);
-Start_ISAC:
- if (val) {
- isac_interrupt(cs, val);
- }
- val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40);
- if (val && icnt) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "HSCX IntStat after IntRoutine");
- icnt--;
- goto Start_HSCX;
- }
- val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA);
- if (val && icnt) {
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ISAC IntStat after IntRoutine");
- icnt--;
- goto Start_ISAC;
- }
- if (!icnt)
- printk(KERN_WARNING"ELSA IRQ LOOP\n");
- writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK, 0xFF);
- writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK + 0x40, 0xFF);
- writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_MASK, 0xFF);
- if (cs->hw.elsa.status & ELIRQF_TIMER_AKTIV) {
- if (!TimerRun(cs)) {
- /* Timer Restart */
- byteout(cs->hw.elsa.timer, 0);
- cs->hw.elsa.counter++;
- }
- }
-#if ARCOFI_USE
- if (cs->hw.elsa.MFlag) {
- val = serial_inp(cs, UART_MCR);
- val ^= 0x8;
- serial_outp(cs, UART_MCR, val);
- val = serial_inp(cs, UART_MCR);
- val ^= 0x8;
- serial_outp(cs, UART_MCR, val);
- }
-#endif
- if (cs->hw.elsa.trig)
- byteout(cs->hw.elsa.trig, 0x00);
- writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK, 0x0);
- writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK + 0x40, 0x0);
- writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_MASK, 0x0);
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static irqreturn_t
-elsa_interrupt_ipac(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_long flags;
- u_char ista, val;
- int icnt = 5;
-
- spin_lock_irqsave(&cs->lock, flags);
- if (cs->subtyp == ELSA_QS1000PCI || cs->subtyp == ELSA_QS3000PCI) {
- val = bytein(cs->hw.elsa.cfg + 0x4c); /* PCI IRQ */
- if (!(val & ELSA_PCI_IRQ_MASK)) {
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_NONE;
- }
- }
-#if ARCOFI_USE
- if (cs->hw.elsa.MFlag) {
- val = serial_inp(cs, UART_IIR);
- if (!(val & UART_IIR_NO_INT)) {
- debugl1(cs, "IIR %02x", val);
- rs_interrupt_elsa(cs);
- }
- }
-#endif
- ista = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ISTA);
-Start_IPAC:
- if (cs->debug & L1_DEB_IPAC)
- debugl1(cs, "IPAC ISTA %02X", ista);
- if (ista & 0x0f) {
- val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40);
- if (ista & 0x01)
- val |= 0x01;
- if (ista & 0x04)
- val |= 0x02;
- if (ista & 0x08)
- val |= 0x04;
- if (val)
- hscx_int_main(cs, val);
- }
- if (ista & 0x20) {
- val = 0xfe & readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA + 0x80);
- if (val) {
- isac_interrupt(cs, val);
- }
- }
- if (ista & 0x10) {
- val = 0x01;
- isac_interrupt(cs, val);
- }
- ista = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ISTA);
- if ((ista & 0x3f) && icnt) {
- icnt--;
- goto Start_IPAC;
- }
- if (!icnt)
- printk(KERN_WARNING "ELSA IRQ LOOP\n");
- writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xFF);
- writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xC0);
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static void
-release_io_elsa(struct IsdnCardState *cs)
-{
- int bytecnt = 8;
-
- del_timer(&cs->hw.elsa.tl);
-#if ARCOFI_USE
- clear_arcofi(cs);
-#endif
- if (cs->hw.elsa.ctrl)
- byteout(cs->hw.elsa.ctrl, 0); /* LEDs Out */
- if (cs->subtyp == ELSA_QS1000PCI) {
- byteout(cs->hw.elsa.cfg + 0x4c, 0x01); /* disable IRQ */
- writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff);
- bytecnt = 2;
- release_region(cs->hw.elsa.cfg, 0x80);
- }
- if (cs->subtyp == ELSA_QS3000PCI) {
- byteout(cs->hw.elsa.cfg + 0x4c, 0x03); /* disable ELSA PCI IRQ */
- writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff);
- release_region(cs->hw.elsa.cfg, 0x80);
- }
- if (cs->subtyp == ELSA_PCMCIA_IPAC) {
- writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff);
- }
- if ((cs->subtyp == ELSA_PCFPRO) ||
- (cs->subtyp == ELSA_QS3000) ||
- (cs->subtyp == ELSA_PCF) ||
- (cs->subtyp == ELSA_QS3000PCI)) {
- bytecnt = 16;
-#if ARCOFI_USE
- release_modem(cs);
-#endif
- }
- if (cs->hw.elsa.base)
- release_region(cs->hw.elsa.base, bytecnt);
-}
-
-static void
-reset_elsa(struct IsdnCardState *cs)
-{
- if (cs->hw.elsa.timer) {
- /* Wait 1 Timer */
- byteout(cs->hw.elsa.timer, 0);
- while (TimerRun(cs));
- cs->hw.elsa.ctrl_reg |= 0x50;
- cs->hw.elsa.ctrl_reg &= ~ELSA_ISDN_RESET; /* Reset On */
- byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
- /* Wait 1 Timer */
- byteout(cs->hw.elsa.timer, 0);
- while (TimerRun(cs));
- cs->hw.elsa.ctrl_reg |= ELSA_ISDN_RESET; /* Reset Off */
- byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
- /* Wait 1 Timer */
- byteout(cs->hw.elsa.timer, 0);
- while (TimerRun(cs));
- if (cs->hw.elsa.trig)
- byteout(cs->hw.elsa.trig, 0xff);
- }
- if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI) || (cs->subtyp == ELSA_PCMCIA_IPAC)) {
- writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x20);
- mdelay(10);
- writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x00);
- writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xc0);
- mdelay(10);
- if (cs->subtyp != ELSA_PCMCIA_IPAC) {
- writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ACFG, 0x0);
- writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_AOE, 0x3c);
- } else {
- writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_PCFG, 0x10);
- writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ACFG, 0x4);
- writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_AOE, 0xf8);
- }
- writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff);
- if (cs->subtyp == ELSA_QS1000PCI)
- byteout(cs->hw.elsa.cfg + 0x4c, 0x41); /* enable ELSA PCI IRQ */
- else if (cs->subtyp == ELSA_QS3000PCI)
- byteout(cs->hw.elsa.cfg + 0x4c, 0x43); /* enable ELSA PCI IRQ */
- }
-}
-
-#if ARCOFI_USE
-
-static void
-set_arcofi(struct IsdnCardState *cs, int bc) {
- cs->dc.isac.arcofi_bc = bc;
- arcofi_fsm(cs, ARCOFI_START, &ARCOFI_COP_5);
- wait_event_interruptible(cs->dc.isac.arcofi_wait,
- cs->dc.isac.arcofi_state == ARCOFI_NOP);
-}
-
-static int
-check_arcofi(struct IsdnCardState *cs)
-{
- int arcofi_present = 0;
- char tmp[40];
- char *t;
- u_char *p;
-
- if (!cs->dc.isac.mon_tx)
- if (!(cs->dc.isac.mon_tx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "ISAC MON TX out of buffers!");
- return (0);
- }
- cs->dc.isac.arcofi_bc = 0;
- arcofi_fsm(cs, ARCOFI_START, &ARCOFI_VERSION);
- wait_event_interruptible(cs->dc.isac.arcofi_wait,
- cs->dc.isac.arcofi_state == ARCOFI_NOP);
- if (!test_and_clear_bit(FLG_ARCOFI_ERROR, &cs->HW_Flags)) {
- debugl1(cs, "Arcofi response received %d bytes", cs->dc.isac.mon_rxp);
- p = cs->dc.isac.mon_rx;
- t = tmp;
- t += sprintf(tmp, "Arcofi data");
- QuickHex(t, p, cs->dc.isac.mon_rxp);
- debugl1(cs, "%s", tmp);
- if ((cs->dc.isac.mon_rxp == 2) && (cs->dc.isac.mon_rx[0] == 0xa0)) {
- switch (cs->dc.isac.mon_rx[1]) {
- case 0x80:
- debugl1(cs, "Arcofi 2160 detected");
- arcofi_present = 1;
- break;
- case 0x82:
- debugl1(cs, "Arcofi 2165 detected");
- arcofi_present = 2;
- break;
- case 0x84:
- debugl1(cs, "Arcofi 2163 detected");
- arcofi_present = 3;
- break;
- default:
- debugl1(cs, "unknown Arcofi response");
- break;
- }
- } else
- debugl1(cs, "undefined Monitor response");
- cs->dc.isac.mon_rxp = 0;
- } else if (cs->dc.isac.mon_tx) {
- debugl1(cs, "Arcofi not detected");
- }
- if (arcofi_present) {
- if (cs->subtyp == ELSA_QS1000) {
- cs->subtyp = ELSA_QS3000;
- printk(KERN_INFO
- "Elsa: %s detected modem at 0x%lx\n",
- Elsa_Types[cs->subtyp],
- cs->hw.elsa.base + 8);
- release_region(cs->hw.elsa.base, 8);
- if (!request_region(cs->hw.elsa.base, 16, "elsa isdn modem")) {
- printk(KERN_WARNING
- "HiSax: %s config port %lx-%lx already in use\n",
- Elsa_Types[cs->subtyp],
- cs->hw.elsa.base + 8,
- cs->hw.elsa.base + 16);
- }
- } else if (cs->subtyp == ELSA_PCC16) {
- cs->subtyp = ELSA_PCF;
- printk(KERN_INFO
- "Elsa: %s detected modem at 0x%lx\n",
- Elsa_Types[cs->subtyp],
- cs->hw.elsa.base + 8);
- release_region(cs->hw.elsa.base, 8);
- if (!request_region(cs->hw.elsa.base, 16, "elsa isdn modem")) {
- printk(KERN_WARNING
- "HiSax: %s config port %lx-%lx already in use\n",
- Elsa_Types[cs->subtyp],
- cs->hw.elsa.base + 8,
- cs->hw.elsa.base + 16);
- }
- } else
- printk(KERN_INFO
- "Elsa: %s detected modem at 0x%lx\n",
- Elsa_Types[cs->subtyp],
- cs->hw.elsa.base + 8);
- arcofi_fsm(cs, ARCOFI_START, &ARCOFI_XOP_0);
- wait_event_interruptible(cs->dc.isac.arcofi_wait,
- cs->dc.isac.arcofi_state == ARCOFI_NOP);
- return (1);
- }
- return (0);
-}
-#endif /* ARCOFI_USE */
-
-static void
-elsa_led_handler(struct timer_list *t)
-{
- struct IsdnCardState *cs = from_timer(cs, t, hw.elsa.tl);
- int blink = 0;
-
- if (cs->subtyp == ELSA_PCMCIA || cs->subtyp == ELSA_PCMCIA_IPAC)
- return;
- del_timer(&cs->hw.elsa.tl);
- if (cs->hw.elsa.status & ELSA_ASSIGN)
- cs->hw.elsa.ctrl_reg |= ELSA_STAT_LED;
- else if (cs->hw.elsa.status & ELSA_BAD_PWR)
- cs->hw.elsa.ctrl_reg &= ~ELSA_STAT_LED;
- else {
- cs->hw.elsa.ctrl_reg ^= ELSA_STAT_LED;
- blink = 250;
- }
- if (cs->hw.elsa.status & 0xf000)
- cs->hw.elsa.ctrl_reg |= ELSA_LINE_LED;
- else if (cs->hw.elsa.status & 0x0f00) {
- cs->hw.elsa.ctrl_reg ^= ELSA_LINE_LED;
- blink = 500;
- } else
- cs->hw.elsa.ctrl_reg &= ~ELSA_LINE_LED;
-
- if ((cs->subtyp == ELSA_QS1000PCI) ||
- (cs->subtyp == ELSA_QS3000PCI)) {
- u_char led = 0xff;
- if (cs->hw.elsa.ctrl_reg & ELSA_LINE_LED)
- led ^= ELSA_IPAC_LINE_LED;
- if (cs->hw.elsa.ctrl_reg & ELSA_STAT_LED)
- led ^= ELSA_IPAC_STAT_LED;
- writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, led);
- } else
- byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
- if (blink) {
- cs->hw.elsa.tl.expires = jiffies + ((blink * HZ) / 1000);
- add_timer(&cs->hw.elsa.tl);
- }
-}
-
-static int
-Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
- int ret = 0;
- u_long flags;
-
- switch (mt) {
- case CARD_RESET:
- spin_lock_irqsave(&cs->lock, flags);
- reset_elsa(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_RELEASE:
- release_io_elsa(cs);
- return (0);
- case CARD_INIT:
- spin_lock_irqsave(&cs->lock, flags);
- cs->debug |= L1_DEB_IPAC;
- reset_elsa(cs);
- inithscxisac(cs, 1);
- if ((cs->subtyp == ELSA_QS1000) ||
- (cs->subtyp == ELSA_QS3000))
- {
- byteout(cs->hw.elsa.timer, 0);
- }
- if (cs->hw.elsa.trig)
- byteout(cs->hw.elsa.trig, 0xff);
- inithscxisac(cs, 2);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_TEST:
- if ((cs->subtyp == ELSA_PCMCIA) ||
- (cs->subtyp == ELSA_PCMCIA_IPAC) ||
- (cs->subtyp == ELSA_QS1000PCI)) {
- return (0);
- } else if (cs->subtyp == ELSA_QS3000PCI) {
- ret = 0;
- } else {
- spin_lock_irqsave(&cs->lock, flags);
- cs->hw.elsa.counter = 0;
- cs->hw.elsa.ctrl_reg |= ELSA_ENA_TIMER_INT;
- cs->hw.elsa.status |= ELIRQF_TIMER_AKTIV;
- byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
- byteout(cs->hw.elsa.timer, 0);
- spin_unlock_irqrestore(&cs->lock, flags);
- msleep(110);
- spin_lock_irqsave(&cs->lock, flags);
- cs->hw.elsa.ctrl_reg &= ~ELSA_ENA_TIMER_INT;
- byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
- cs->hw.elsa.status &= ~ELIRQF_TIMER_AKTIV;
- spin_unlock_irqrestore(&cs->lock, flags);
- printk(KERN_INFO "Elsa: %d timer tics in 110 msek\n",
- cs->hw.elsa.counter);
- if ((cs->hw.elsa.counter > 10) &&
- (cs->hw.elsa.counter < 16)) {
- printk(KERN_INFO "Elsa: timer and irq OK\n");
- ret = 0;
- } else {
- printk(KERN_WARNING
- "Elsa: timer tic problem (%d/12) maybe an IRQ(%d) conflict\n",
- cs->hw.elsa.counter, cs->irq);
- ret = 1;
- }
- }
-#if ARCOFI_USE
- if (check_arcofi(cs)) {
- init_modem(cs);
- }
-#endif
- elsa_led_handler(&cs->hw.elsa.tl);
- return (ret);
- case (MDL_REMOVE | REQUEST):
- cs->hw.elsa.status &= 0;
- break;
- case (MDL_ASSIGN | REQUEST):
- cs->hw.elsa.status |= ELSA_ASSIGN;
- break;
- case MDL_INFO_SETUP:
- if ((long) arg)
- cs->hw.elsa.status |= 0x0200;
- else
- cs->hw.elsa.status |= 0x0100;
- break;
- case MDL_INFO_CONN:
- if ((long) arg)
- cs->hw.elsa.status |= 0x2000;
- else
- cs->hw.elsa.status |= 0x1000;
- break;
- case MDL_INFO_REL:
- if ((long) arg) {
- cs->hw.elsa.status &= ~0x2000;
- cs->hw.elsa.status &= ~0x0200;
- } else {
- cs->hw.elsa.status &= ~0x1000;
- cs->hw.elsa.status &= ~0x0100;
- }
- break;
-#if ARCOFI_USE
- case CARD_AUX_IND:
- if (cs->hw.elsa.MFlag) {
- int len;
- u_char *msg;
-
- if (!arg)
- return (0);
- msg = arg;
- len = *msg;
- msg++;
- modem_write_cmd(cs, msg, len);
- }
- break;
-#endif
- }
- if (cs->typ == ISDN_CTYPE_ELSA) {
- int pwr = bytein(cs->hw.elsa.ale);
- if (pwr & 0x08)
- cs->hw.elsa.status |= ELSA_BAD_PWR;
- else
- cs->hw.elsa.status &= ~ELSA_BAD_PWR;
- }
- elsa_led_handler(&cs->hw.elsa.tl);
- return (ret);
-}
-
-static unsigned char
-probe_elsa_adr(unsigned int adr, int typ)
-{
- int i, in1, in2, p16_1 = 0, p16_2 = 0, p8_1 = 0, p8_2 = 0, pc_1 = 0,
- pc_2 = 0, pfp_1 = 0, pfp_2 = 0;
-
- /* In case of the elsa pcmcia card, this region is in use,
- reserved for us by the card manager. So we do not check it
- here, it would fail. */
- if (typ != ISDN_CTYPE_ELSA_PCMCIA) {
- if (request_region(adr, 8, "elsa card")) {
- release_region(adr, 8);
- } else {
- printk(KERN_WARNING
- "Elsa: Probing Port 0x%x: already in use\n", adr);
- return (0);
- }
- }
- for (i = 0; i < 16; i++) {
- in1 = inb(adr + ELSA_CONFIG); /* 'toggelt' bei */
- in2 = inb(adr + ELSA_CONFIG); /* jedem Zugriff */
- p16_1 += 0x04 & in1;
- p16_2 += 0x04 & in2;
- p8_1 += 0x02 & in1;
- p8_2 += 0x02 & in2;
- pc_1 += 0x01 & in1;
- pc_2 += 0x01 & in2;
- pfp_1 += 0x40 & in1;
- pfp_2 += 0x40 & in2;
- }
- printk(KERN_INFO "Elsa: Probing IO 0x%x", adr);
- if (65 == ++p16_1 * ++p16_2) {
- printk(" PCC-16/PCF found\n");
- return (ELSA_PCC16);
- } else if (1025 == ++pfp_1 * ++pfp_2) {
- printk(" PCF-Pro found\n");
- return (ELSA_PCFPRO);
- } else if (33 == ++p8_1 * ++p8_2) {
- printk(" PCC8 found\n");
- return (ELSA_PCC8);
- } else if (17 == ++pc_1 * ++pc_2) {
- printk(" PC found\n");
- return (ELSA_PC);
- } else {
- printk(" failed\n");
- return (0);
- }
-}
-
-static unsigned int
-probe_elsa(struct IsdnCardState *cs)
-{
- int i;
- unsigned int CARD_portlist[] =
- {0x160, 0x170, 0x260, 0x360, 0};
-
- for (i = 0; CARD_portlist[i]; i++) {
- if ((cs->subtyp = probe_elsa_adr(CARD_portlist[i], cs->typ)))
- break;
- }
- return (CARD_portlist[i]);
-}
-
-static int setup_elsa_isa(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
- u_char val;
-
- cs->hw.elsa.base = card->para[0];
- printk(KERN_INFO "Elsa: Microlink IO probing\n");
- if (cs->hw.elsa.base) {
- if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base,
- cs->typ))) {
- printk(KERN_WARNING
- "Elsa: no Elsa Microlink at %#lx\n",
- cs->hw.elsa.base);
- return (0);
- }
- } else
- cs->hw.elsa.base = probe_elsa(cs);
-
- if (!cs->hw.elsa.base) {
- printk(KERN_WARNING
- "No Elsa Microlink found\n");
- return (0);
- }
-
- cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
- cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
- cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
- cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
- cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC;
- cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
- cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
- cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
- val = bytein(cs->hw.elsa.cfg);
- if (cs->subtyp == ELSA_PC) {
- const u_char CARD_IrqTab[8] =
- {7, 3, 5, 9, 0, 0, 0, 0};
- cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2];
- } else if (cs->subtyp == ELSA_PCC8) {
- const u_char CARD_IrqTab[8] =
- {7, 3, 5, 9, 0, 0, 0, 0};
- cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4];
- } else {
- const u_char CARD_IrqTab[8] =
- {15, 10, 15, 3, 11, 5, 11, 9};
- cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3];
- }
- val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE;
- if (val < 3)
- val |= 8;
- val += 'A' - 3;
- if (val == 'B' || val == 'C')
- val ^= 1;
- if ((cs->subtyp == ELSA_PCFPRO) && (val == 'G'))
- val = 'C';
- printk(KERN_INFO
- "Elsa: %s found at %#lx Rev.:%c IRQ %d\n",
- Elsa_Types[cs->subtyp],
- cs->hw.elsa.base,
- val, cs->irq);
- val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD;
- if (val) {
- printk(KERN_WARNING
- "Elsa: Microlink S0 bus power bad\n");
- cs->hw.elsa.status |= ELSA_BAD_PWR;
- }
-
- return (1);
-}
-
-#ifdef __ISAPNP__
-static struct isapnp_device_id elsa_ids[] = {
- { ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0133),
- ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0133),
- (unsigned long) "Elsa QS1000" },
- { ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0134),
- ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0134),
- (unsigned long) "Elsa QS3000" },
- { 0, }
-};
-
-static struct isapnp_device_id *ipid = &elsa_ids[0];
-static struct pnp_card *pnp_c = NULL;
-#endif /* __ISAPNP__ */
-
-static int setup_elsa_isapnp(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
-
-#ifdef __ISAPNP__
- if (!card->para[1] && isapnp_present()) {
- struct pnp_dev *pnp_d;
- while (ipid->card_vendor) {
- if ((pnp_c = pnp_find_card(ipid->card_vendor,
- ipid->card_device, pnp_c))) {
- pnp_d = NULL;
- if ((pnp_d = pnp_find_dev(pnp_c,
- ipid->vendor, ipid->function, pnp_d))) {
- int err;
-
- printk(KERN_INFO "HiSax: %s detected\n",
- (char *)ipid->driver_data);
- pnp_disable_dev(pnp_d);
- err = pnp_activate_dev(pnp_d);
- if (err < 0) {
- printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __func__, err);
- return (0);
- }
- card->para[1] = pnp_port_start(pnp_d, 0);
- card->para[0] = pnp_irq(pnp_d, 0);
-
- if (card->para[0] == -1 || !card->para[1]) {
- printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n",
- card->para[0], card->para[1]);
- pnp_disable_dev(pnp_d);
- return (0);
- }
- if (ipid->function == ISAPNP_FUNCTION(0x133))
- cs->subtyp = ELSA_QS1000;
- else
- cs->subtyp = ELSA_QS3000;
- break;
- } else {
- printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n");
- return (0);
- }
- }
- ipid++;
- pnp_c = NULL;
- }
- if (!ipid->card_vendor) {
- printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n");
- return (0);
- }
- }
-#endif /* __ISAPNP__ */
-
- if (card->para[1] && card->para[0]) {
- cs->hw.elsa.base = card->para[1];
- cs->irq = card->para[0];
- if (!cs->subtyp)
- cs->subtyp = ELSA_QS1000;
- } else {
- printk(KERN_ERR "Elsa PnP: no parameter\n");
- }
- cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
- cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
- cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
- cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
- cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
- cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
- cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
- printk(KERN_INFO
- "Elsa: %s defined at %#lx IRQ %d\n",
- Elsa_Types[cs->subtyp],
- cs->hw.elsa.base,
- cs->irq);
-
- return (1);
-}
-
-static void setup_elsa_pcmcia(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
- u_char val;
-
- cs->hw.elsa.base = card->para[1];
- cs->irq = card->para[0];
- val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID);
- if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */
- cs->subtyp = ELSA_PCMCIA_IPAC;
- cs->hw.elsa.ale = cs->hw.elsa.base + 0;
- cs->hw.elsa.isac = cs->hw.elsa.base + 2;
- cs->hw.elsa.hscx = cs->hw.elsa.base + 2;
- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
- } else {
- cs->subtyp = ELSA_PCMCIA;
- cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM;
- cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM;
- cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
- }
- cs->hw.elsa.timer = 0;
- cs->hw.elsa.trig = 0;
- cs->hw.elsa.ctrl = 0;
- cs->irq_flags |= IRQF_SHARED;
- printk(KERN_INFO
- "Elsa: %s defined at %#lx IRQ %d\n",
- Elsa_Types[cs->subtyp],
- cs->hw.elsa.base,
- cs->irq);
-}
-
-#ifdef CONFIG_PCI
-static struct pci_dev *dev_qs1000 = NULL;
-static struct pci_dev *dev_qs3000 = NULL;
-
-static int setup_elsa_pci(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
-
- cs->subtyp = 0;
- if ((dev_qs1000 = hisax_find_pci_device(PCI_VENDOR_ID_ELSA,
- PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) {
- if (pci_enable_device(dev_qs1000))
- return (0);
- cs->subtyp = ELSA_QS1000PCI;
- cs->irq = dev_qs1000->irq;
- cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1);
- cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3);
- } else if ((dev_qs3000 = hisax_find_pci_device(PCI_VENDOR_ID_ELSA,
- PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) {
- if (pci_enable_device(dev_qs3000))
- return (0);
- cs->subtyp = ELSA_QS3000PCI;
- cs->irq = dev_qs3000->irq;
- cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1);
- cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3);
- } else {
- printk(KERN_WARNING "Elsa: No PCI card found\n");
- return (0);
- }
- if (!cs->irq) {
- printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n");
- return (0);
- }
-
- if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) {
- printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n");
- return (0);
- }
- if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) {
- printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n");
- printk(KERN_WARNING "Elsa: If your system hangs now, read\n");
- printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n");
- }
- cs->hw.elsa.ale = cs->hw.elsa.base;
- cs->hw.elsa.isac = cs->hw.elsa.base + 1;
- cs->hw.elsa.hscx = cs->hw.elsa.base + 1;
- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
- cs->hw.elsa.timer = 0;
- cs->hw.elsa.trig = 0;
- cs->irq_flags |= IRQF_SHARED;
- printk(KERN_INFO
- "Elsa: %s defined at %#lx/0x%x IRQ %d\n",
- Elsa_Types[cs->subtyp],
- cs->hw.elsa.base,
- cs->hw.elsa.cfg,
- cs->irq);
-
- return (1);
-}
-
-#else
-
-static int setup_elsa_pci(struct IsdnCard *card)
-{
- return (1);
-}
-#endif /* CONFIG_PCI */
-
-static int setup_elsa_common(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
- u_char val;
- int bytecnt;
-
- switch (cs->subtyp) {
- case ELSA_PC:
- case ELSA_PCC8:
- case ELSA_PCC16:
- case ELSA_QS1000:
- case ELSA_PCMCIA:
- case ELSA_PCMCIA_IPAC:
- bytecnt = 8;
- break;
- case ELSA_PCFPRO:
- case ELSA_PCF:
- case ELSA_QS3000:
- case ELSA_QS3000PCI:
- bytecnt = 16;
- break;
- case ELSA_QS1000PCI:
- bytecnt = 2;
- break;
- default:
- printk(KERN_WARNING
- "Unknown ELSA subtype %d\n", cs->subtyp);
- return (0);
- }
- /* In case of the elsa pcmcia card, this region is in use,
- reserved for us by the card manager. So we do not check it
- here, it would fail. */
- if (cs->typ != ISDN_CTYPE_ELSA_PCMCIA && !request_region(cs->hw.elsa.base, bytecnt, "elsa isdn")) {
- printk(KERN_WARNING
- "HiSax: ELSA config port %#lx-%#lx already in use\n",
- cs->hw.elsa.base,
- cs->hw.elsa.base + bytecnt);
- return (0);
- }
- if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) {
- if (!request_region(cs->hw.elsa.cfg, 0x80, "elsa isdn pci")) {
- printk(KERN_WARNING
- "HiSax: ELSA pci port %x-%x already in use\n",
- cs->hw.elsa.cfg,
- cs->hw.elsa.cfg + 0x80);
- release_region(cs->hw.elsa.base, bytecnt);
- return (0);
- }
- }
-#if ARCOFI_USE
- init_arcofi(cs);
-#endif
- setup_isac(cs);
- timer_setup(&cs->hw.elsa.tl, elsa_led_handler, 0);
- /* Teste Timer */
- if (cs->hw.elsa.timer) {
- byteout(cs->hw.elsa.trig, 0xff);
- byteout(cs->hw.elsa.timer, 0);
- if (!TimerRun(cs)) {
- byteout(cs->hw.elsa.timer, 0); /* 2. Versuch */
- if (!TimerRun(cs)) {
- printk(KERN_WARNING
- "Elsa: timer do not start\n");
- release_io_elsa(cs);
- return (0);
- }
- }
- HZDELAY((HZ / 100) + 1); /* wait >=10 ms */
- if (TimerRun(cs)) {
- printk(KERN_WARNING "Elsa: timer do not run down\n");
- release_io_elsa(cs);
- return (0);
- }
- printk(KERN_INFO "Elsa: timer OK; resetting card\n");
- }
- cs->BC_Read_Reg = &ReadHSCX;
- cs->BC_Write_Reg = &WriteHSCX;
- cs->BC_Send_Data = &hscx_fill_fifo;
- cs->cardmsg = &Elsa_card_msg;
- if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI) || (cs->subtyp == ELSA_PCMCIA_IPAC)) {
- cs->readisac = &ReadISAC_IPAC;
- cs->writeisac = &WriteISAC_IPAC;
- cs->readisacfifo = &ReadISACfifo_IPAC;
- cs->writeisacfifo = &WriteISACfifo_IPAC;
- cs->irq_func = &elsa_interrupt_ipac;
- val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ID);
- printk(KERN_INFO "Elsa: IPAC version %x\n", val);
- } else {
- cs->readisac = &ReadISAC;
- cs->writeisac = &WriteISAC;
- cs->readisacfifo = &ReadISACfifo;
- cs->writeisacfifo = &WriteISACfifo;
- cs->irq_func = &elsa_interrupt;
- ISACVersion(cs, "Elsa:");
- if (HscxVersion(cs, "Elsa:")) {
- printk(KERN_WARNING
- "Elsa: wrong HSCX versions check IO address\n");
- release_io_elsa(cs);
- return (0);
- }
- }
- if (cs->subtyp == ELSA_PC) {
- val = readitac(cs, ITAC_SYS);
- printk(KERN_INFO "Elsa: ITAC version %s\n", ITACVer[val & 7]);
- writeitac(cs, ITAC_ISEN, 0);
- writeitac(cs, ITAC_RFIE, 0);
- writeitac(cs, ITAC_XFIE, 0);
- writeitac(cs, ITAC_SCIE, 0);
- writeitac(cs, ITAC_STIE, 0);
- }
- return (1);
-}
-
-int setup_elsa(struct IsdnCard *card)
-{
- int rc;
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
-
- strcpy(tmp, Elsa_revision);
- printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp));
- cs->hw.elsa.ctrl_reg = 0;
- cs->hw.elsa.status = 0;
- cs->hw.elsa.MFlag = 0;
- cs->subtyp = 0;
-
- if (cs->typ == ISDN_CTYPE_ELSA) {
- rc = setup_elsa_isa(card);
- if (!rc)
- return (0);
-
- } else if (cs->typ == ISDN_CTYPE_ELSA_PNP) {
- rc = setup_elsa_isapnp(card);
- if (!rc)
- return (0);
-
- } else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA)
- setup_elsa_pcmcia(card);
-
- else if (cs->typ == ISDN_CTYPE_ELSA_PCI) {
- rc = setup_elsa_pci(card);
- if (!rc)
- return (0);
-
- } else
- return (0);
-
- return setup_elsa_common(card);
-}
diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c
deleted file mode 100644
index 40f6fad79de3..000000000000
--- a/drivers/isdn/hisax/elsa_cs.c
+++ /dev/null
@@ -1,218 +0,0 @@
-/*======================================================================
-
- An elsa_cs PCMCIA client driver
-
- This driver is for the Elsa PCM ISDN Cards, i.e. the MicroLink
-
-
- The contents of this file are subject to the Mozilla Public
- License Version 1.1 (the "License"); you may not use this file
- except in compliance with the License. You may obtain a copy of
- the License at http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS
- IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- implied. See the License for the specific language governing
- rights and limitations under the License.
-
- The initial developer of the original code is David A. Hinds
- <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
- are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
-
- Modifications from dummy_cs.c are Copyright (C) 1999-2001 Klaus
- Lichtenwalder <Lichtenwalder@ACM.org>. All Rights Reserved.
-
- Alternatively, the contents of this file may be used under the
- terms of the GNU General Public License version 2 (the "GPL"), in
- which case the provisions of the GPL are applicable instead of the
- above. If you wish to allow the use of your version of this file
- only under the terms of the GPL and not to allow others to use
- your version of this file under the MPL, indicate your decision
- by deleting the provisions above and replace them with the notice
- and other provisions required by the GPL. If you do not delete
- the provisions above, a recipient may use your version of this
- file under either the MPL or the GPL.
-
- ======================================================================*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/ioport.h>
-#include <asm/io.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ds.h>
-#include "hisax_cfg.h"
-
-MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Elsa PCM cards");
-MODULE_AUTHOR("Klaus Lichtenwalder");
-MODULE_LICENSE("Dual MPL/GPL");
-
-
-/*====================================================================*/
-
-/* Parameters that can be set with 'insmod' */
-
-static int protocol = 2; /* EURO-ISDN Default */
-module_param(protocol, int, 0);
-
-static int elsa_cs_config(struct pcmcia_device *link);
-static void elsa_cs_release(struct pcmcia_device *link);
-static void elsa_cs_detach(struct pcmcia_device *p_dev);
-
-typedef struct local_info_t {
- struct pcmcia_device *p_dev;
- int busy;
- int cardnr;
-} local_info_t;
-
-static int elsa_cs_probe(struct pcmcia_device *link)
-{
- local_info_t *local;
-
- dev_dbg(&link->dev, "elsa_cs_attach()\n");
-
- /* Allocate space for private device-specific data */
- local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
- if (!local) return -ENOMEM;
-
- local->p_dev = link;
- link->priv = local;
-
- local->cardnr = -1;
-
- return elsa_cs_config(link);
-} /* elsa_cs_attach */
-
-static void elsa_cs_detach(struct pcmcia_device *link)
-{
- local_info_t *info = link->priv;
-
- dev_dbg(&link->dev, "elsa_cs_detach(0x%p)\n", link);
-
- info->busy = 1;
- elsa_cs_release(link);
-
- kfree(info);
-} /* elsa_cs_detach */
-
-static int elsa_cs_configcheck(struct pcmcia_device *p_dev, void *priv_data)
-{
- int j;
-
- p_dev->io_lines = 3;
- p_dev->resource[0]->end = 8;
- p_dev->resource[0]->flags &= IO_DATA_PATH_WIDTH;
- p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-
- if ((p_dev->resource[0]->end) && p_dev->resource[0]->start) {
- printk(KERN_INFO "(elsa_cs: looks like the 96 model)\n");
- if (!pcmcia_request_io(p_dev))
- return 0;
- } else {
- printk(KERN_INFO "(elsa_cs: looks like the 97 model)\n");
- for (j = 0x2f0; j > 0x100; j -= 0x10) {
- p_dev->resource[0]->start = j;
- if (!pcmcia_request_io(p_dev))
- return 0;
- }
- }
- return -ENODEV;
-}
-
-static int elsa_cs_config(struct pcmcia_device *link)
-{
- int i;
- IsdnCard_t icard;
-
- dev_dbg(&link->dev, "elsa_config(0x%p)\n", link);
-
- link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
-
- i = pcmcia_loop_config(link, elsa_cs_configcheck, NULL);
- if (i != 0)
- goto failed;
-
- if (!link->irq)
- goto failed;
-
- i = pcmcia_enable_device(link);
- if (i != 0)
- goto failed;
-
- icard.para[0] = link->irq;
- icard.para[1] = link->resource[0]->start;
- icard.protocol = protocol;
- icard.typ = ISDN_CTYPE_ELSA_PCMCIA;
-
- i = hisax_init_pcmcia(link, &(((local_info_t *)link->priv)->busy), &icard);
- if (i < 0) {
- printk(KERN_ERR "elsa_cs: failed to initialize Elsa "
- "PCMCIA %d with %pR\n", i, link->resource[0]);
- elsa_cs_release(link);
- } else
- ((local_info_t *)link->priv)->cardnr = i;
-
- return 0;
-failed:
- elsa_cs_release(link);
- return -ENODEV;
-} /* elsa_cs_config */
-
-static void elsa_cs_release(struct pcmcia_device *link)
-{
- local_info_t *local = link->priv;
-
- dev_dbg(&link->dev, "elsa_cs_release(0x%p)\n", link);
-
- if (local) {
- if (local->cardnr >= 0) {
- /* no unregister function with hisax */
- HiSax_closecard(local->cardnr);
- }
- }
-
- pcmcia_disable_device(link);
-} /* elsa_cs_release */
-
-static int elsa_suspend(struct pcmcia_device *link)
-{
- local_info_t *dev = link->priv;
-
- dev->busy = 1;
-
- return 0;
-}
-
-static int elsa_resume(struct pcmcia_device *link)
-{
- local_info_t *dev = link->priv;
-
- dev->busy = 0;
-
- return 0;
-}
-
-static const struct pcmcia_device_id elsa_ids[] = {
- PCMCIA_DEVICE_PROD_ID12("ELSA AG (Aachen, Germany)", "MicroLink ISDN/MC ", 0x983de2c4, 0x333ba257),
- PCMCIA_DEVICE_PROD_ID12("ELSA GmbH, Aachen", "MicroLink ISDN/MC ", 0x639e5718, 0x333ba257),
- PCMCIA_DEVICE_NULL
-};
-MODULE_DEVICE_TABLE(pcmcia, elsa_ids);
-
-static struct pcmcia_driver elsa_cs_driver = {
- .owner = THIS_MODULE,
- .name = "elsa_cs",
- .probe = elsa_cs_probe,
- .remove = elsa_cs_detach,
- .id_table = elsa_ids,
- .suspend = elsa_suspend,
- .resume = elsa_resume,
-};
-module_pcmcia_driver(elsa_cs_driver);
diff --git a/drivers/isdn/hisax/elsa_ser.c b/drivers/isdn/hisax/elsa_ser.c
deleted file mode 100644
index 999effd7a276..000000000000
--- a/drivers/isdn/hisax/elsa_ser.c
+++ /dev/null
@@ -1,659 +0,0 @@
-/* $Id: elsa_ser.c,v 2.14.2.3 2004/02/11 13:21:33 keil Exp $
- *
- * stuff for the serial modem on ELSA cards
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/serial.h>
-#include <linux/serial_reg.h>
-#include <linux/slab.h>
-
-#define MAX_MODEM_BUF 256
-#define WAKEUP_CHARS (MAX_MODEM_BUF / 2)
-#define RS_ISR_PASS_LIMIT 256
-#define BASE_BAUD (1843200 / 16)
-
-//#define SERIAL_DEBUG_OPEN 1
-//#define SERIAL_DEBUG_INTR 1
-//#define SERIAL_DEBUG_FLOW 1
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_INTR
-#undef SERIAL_DEBUG_FLOW
-#undef SERIAL_DEBUG_REG
-//#define SERIAL_DEBUG_REG 1
-
-#ifdef SERIAL_DEBUG_REG
-static u_char deb[32];
-const char *ModemIn[] = {"RBR", "IER", "IIR", "LCR", "MCR", "LSR", "MSR", "SCR"};
-const char *ModemOut[] = {"THR", "IER", "FCR", "LCR", "MCR", "LSR", "MSR", "SCR"};
-#endif
-
-static char *MInit_1 = "AT&F&C1E0&D2\r\0";
-static char *MInit_2 = "ATL2M1S64=13\r\0";
-static char *MInit_3 = "AT+FCLASS=0\r\0";
-static char *MInit_4 = "ATV1S2=128X1\r\0";
-static char *MInit_5 = "AT\\V8\\N3\r\0";
-static char *MInit_6 = "ATL0M0&G0%E1\r\0";
-static char *MInit_7 = "AT%L1%M0%C3\r\0";
-
-static char *MInit_speed28800 = "AT%G0%B28800\r\0";
-
-static char *MInit_dialout = "ATs7=60 x1 d\r\0";
-static char *MInit_dialin = "ATs7=60 x1 a\r\0";
-
-
-static inline unsigned int serial_in(struct IsdnCardState *cs, int offset)
-{
-#ifdef SERIAL_DEBUG_REG
- u_int val = inb(cs->hw.elsa.base + 8 + offset);
- debugl1(cs, "in %s %02x", ModemIn[offset], val);
- return (val);
-#else
- return inb(cs->hw.elsa.base + 8 + offset);
-#endif
-}
-
-static inline unsigned int serial_inp(struct IsdnCardState *cs, int offset)
-{
-#ifdef SERIAL_DEBUG_REG
-#ifdef ELSA_SERIAL_NOPAUSE_IO
- u_int val = inb(cs->hw.elsa.base + 8 + offset);
- debugl1(cs, "inp %s %02x", ModemIn[offset], val);
-#else
- u_int val = inb_p(cs->hw.elsa.base + 8 + offset);
- debugl1(cs, "inP %s %02x", ModemIn[offset], val);
-#endif
- return (val);
-#else
-#ifdef ELSA_SERIAL_NOPAUSE_IO
- return inb(cs->hw.elsa.base + 8 + offset);
-#else
- return inb_p(cs->hw.elsa.base + 8 + offset);
-#endif
-#endif
-}
-
-static inline void serial_out(struct IsdnCardState *cs, int offset, int value)
-{
-#ifdef SERIAL_DEBUG_REG
- debugl1(cs, "out %s %02x", ModemOut[offset], value);
-#endif
- outb(value, cs->hw.elsa.base + 8 + offset);
-}
-
-static inline void serial_outp(struct IsdnCardState *cs, int offset,
- int value)
-{
-#ifdef SERIAL_DEBUG_REG
-#ifdef ELSA_SERIAL_NOPAUSE_IO
- debugl1(cs, "outp %s %02x", ModemOut[offset], value);
-#else
- debugl1(cs, "outP %s %02x", ModemOut[offset], value);
-#endif
-#endif
-#ifdef ELSA_SERIAL_NOPAUSE_IO
- outb(value, cs->hw.elsa.base + 8 + offset);
-#else
- outb_p(value, cs->hw.elsa.base + 8 + offset);
-#endif
-}
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static void change_speed(struct IsdnCardState *cs, int baud)
-{
- int quot = 0, baud_base;
- unsigned cval, fcr = 0;
-
-
- /* byte size and parity */
- cval = 0x03;
- /* Determine divisor based on baud rate */
- baud_base = BASE_BAUD;
- quot = baud_base / baud;
- /* If the quotient is ever zero, default to 9600 bps */
- if (!quot)
- quot = baud_base / 9600;
-
- /* Set up FIFO's */
- if ((baud_base / quot) < 2400)
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
- else
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
- serial_outp(cs, UART_FCR, fcr);
- /* CTS flow control flag and modem status interrupts */
- cs->hw.elsa.IER &= ~UART_IER_MSI;
- cs->hw.elsa.IER |= UART_IER_MSI;
- serial_outp(cs, UART_IER, cs->hw.elsa.IER);
-
- debugl1(cs, "modem quot=0x%x", quot);
- serial_outp(cs, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
- serial_outp(cs, UART_DLL, quot & 0xff); /* LS of divisor */
- serial_outp(cs, UART_DLM, quot >> 8); /* MS of divisor */
- serial_outp(cs, UART_LCR, cval); /* reset DLAB */
- serial_inp(cs, UART_RX);
-}
-
-static int mstartup(struct IsdnCardState *cs)
-{
- int retval = 0;
-
- /*
- * Clear the FIFO buffers and disable them
- * (they will be reenabled in change_speed())
- */
- serial_outp(cs, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT));
-
- /*
- * At this point there's no way the LSR could still be 0xFF;
- * if it is, then bail out, because there's likely no UART
- * here.
- */
- if (serial_inp(cs, UART_LSR) == 0xff) {
- retval = -ENODEV;
- goto errout;
- }
-
- /*
- * Clear the interrupt registers.
- */
- (void) serial_inp(cs, UART_RX);
- (void) serial_inp(cs, UART_IIR);
- (void) serial_inp(cs, UART_MSR);
-
- /*
- * Now, initialize the UART
- */
- serial_outp(cs, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */
-
- cs->hw.elsa.MCR = 0;
- cs->hw.elsa.MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
- serial_outp(cs, UART_MCR, cs->hw.elsa.MCR);
-
- /*
- * Finally, enable interrupts
- */
- cs->hw.elsa.IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
- serial_outp(cs, UART_IER, cs->hw.elsa.IER); /* enable interrupts */
-
- /*
- * And clear the interrupt registers again for luck.
- */
- (void)serial_inp(cs, UART_LSR);
- (void)serial_inp(cs, UART_RX);
- (void)serial_inp(cs, UART_IIR);
- (void)serial_inp(cs, UART_MSR);
-
- cs->hw.elsa.transcnt = cs->hw.elsa.transp = 0;
- cs->hw.elsa.rcvcnt = cs->hw.elsa.rcvp = 0;
-
- /*
- * and set the speed of the serial port
- */
- change_speed(cs, BASE_BAUD);
- cs->hw.elsa.MFlag = 1;
-errout:
- return retval;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void mshutdown(struct IsdnCardState *cs)
-{
-
-#ifdef SERIAL_DEBUG_OPEN
- printk(KERN_DEBUG"Shutting down serial ....");
-#endif
-
- /*
- * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
- * here so the queue might never be waken up
- */
-
- cs->hw.elsa.IER = 0;
- serial_outp(cs, UART_IER, 0x00); /* disable all intrs */
- cs->hw.elsa.MCR &= ~UART_MCR_OUT2;
-
- /* disable break condition */
- serial_outp(cs, UART_LCR, serial_inp(cs, UART_LCR) & ~UART_LCR_SBC);
-
- cs->hw.elsa.MCR &= ~(UART_MCR_DTR | UART_MCR_RTS);
- serial_outp(cs, UART_MCR, cs->hw.elsa.MCR);
-
- /* disable FIFO's */
- serial_outp(cs, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT));
- serial_inp(cs, UART_RX); /* read data port to reset things */
-
-#ifdef SERIAL_DEBUG_OPEN
- printk(" done\n");
-#endif
-}
-
-static inline int
-write_modem(struct BCState *bcs) {
- int ret = 0;
- struct IsdnCardState *cs = bcs->cs;
- int count, len, fp;
-
- if (!bcs->tx_skb)
- return 0;
- if (bcs->tx_skb->len <= 0)
- return 0;
- len = bcs->tx_skb->len;
- if (len > MAX_MODEM_BUF - cs->hw.elsa.transcnt)
- len = MAX_MODEM_BUF - cs->hw.elsa.transcnt;
- fp = cs->hw.elsa.transcnt + cs->hw.elsa.transp;
- fp &= (MAX_MODEM_BUF - 1);
- count = len;
- if (count > MAX_MODEM_BUF - fp) {
- count = MAX_MODEM_BUF - fp;
- skb_copy_from_linear_data(bcs->tx_skb,
- cs->hw.elsa.transbuf + fp, count);
- skb_pull(bcs->tx_skb, count);
- cs->hw.elsa.transcnt += count;
- ret = count;
- count = len - count;
- fp = 0;
- }
- skb_copy_from_linear_data(bcs->tx_skb,
- cs->hw.elsa.transbuf + fp, count);
- skb_pull(bcs->tx_skb, count);
- cs->hw.elsa.transcnt += count;
- ret += count;
-
- if (cs->hw.elsa.transcnt &&
- !(cs->hw.elsa.IER & UART_IER_THRI)) {
- cs->hw.elsa.IER |= UART_IER_THRI;
- serial_outp(cs, UART_IER, cs->hw.elsa.IER);
- }
- return (ret);
-}
-
-static inline void
-modem_fill(struct BCState *bcs) {
-
- if (bcs->tx_skb) {
- if (bcs->tx_skb->len) {
- write_modem(bcs);
- return;
- } else {
- if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
- (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
- u_long flags;
- spin_lock_irqsave(&bcs->aclock, flags);
- bcs->ackcnt += bcs->hw.hscx.count;
- spin_unlock_irqrestore(&bcs->aclock, flags);
- schedule_event(bcs, B_ACKPENDING);
- }
- dev_kfree_skb_any(bcs->tx_skb);
- bcs->tx_skb = NULL;
- }
- }
- if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
- bcs->hw.hscx.count = 0;
- test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
- write_modem(bcs);
- } else {
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- schedule_event(bcs, B_XMTBUFREADY);
- }
-}
-
-static inline void receive_chars(struct IsdnCardState *cs,
- int *status)
-{
- unsigned char ch;
- struct sk_buff *skb;
-
- do {
- ch = serial_in(cs, UART_RX);
- if (cs->hw.elsa.rcvcnt >= MAX_MODEM_BUF)
- break;
- cs->hw.elsa.rcvbuf[cs->hw.elsa.rcvcnt++] = ch;
-#ifdef SERIAL_DEBUG_INTR
- printk("DR%02x:%02x...", ch, *status);
-#endif
- if (*status & (UART_LSR_BI | UART_LSR_PE |
- UART_LSR_FE | UART_LSR_OE)) {
-
-#ifdef SERIAL_DEBUG_INTR
- printk("handling exept....");
-#endif
- }
- *status = serial_inp(cs, UART_LSR);
- } while (*status & UART_LSR_DR);
- if (cs->hw.elsa.MFlag == 2) {
- if (!(skb = dev_alloc_skb(cs->hw.elsa.rcvcnt)))
- printk(KERN_WARNING "ElsaSER: receive out of memory\n");
- else {
- skb_put_data(skb, cs->hw.elsa.rcvbuf,
- cs->hw.elsa.rcvcnt);
- skb_queue_tail(&cs->hw.elsa.bcs->rqueue, skb);
- }
- schedule_event(cs->hw.elsa.bcs, B_RCVBUFREADY);
- } else {
- char tmp[128];
- char *t = tmp;
-
- t += sprintf(t, "modem read cnt %d", cs->hw.elsa.rcvcnt);
- QuickHex(t, cs->hw.elsa.rcvbuf, cs->hw.elsa.rcvcnt);
- debugl1(cs, "%s", tmp);
- }
- cs->hw.elsa.rcvcnt = 0;
-}
-
-static inline void transmit_chars(struct IsdnCardState *cs, int *intr_done)
-{
- int count;
-
- debugl1(cs, "transmit_chars: p(%x) cnt(%x)", cs->hw.elsa.transp,
- cs->hw.elsa.transcnt);
-
- if (cs->hw.elsa.transcnt <= 0) {
- cs->hw.elsa.IER &= ~UART_IER_THRI;
- serial_out(cs, UART_IER, cs->hw.elsa.IER);
- return;
- }
- count = 16;
- do {
- serial_outp(cs, UART_TX, cs->hw.elsa.transbuf[cs->hw.elsa.transp++]);
- if (cs->hw.elsa.transp >= MAX_MODEM_BUF)
- cs->hw.elsa.transp = 0;
- if (--cs->hw.elsa.transcnt <= 0)
- break;
- } while (--count > 0);
- if ((cs->hw.elsa.transcnt < WAKEUP_CHARS) && (cs->hw.elsa.MFlag == 2))
- modem_fill(cs->hw.elsa.bcs);
-
-#ifdef SERIAL_DEBUG_INTR
- printk("THRE...");
-#endif
- if (intr_done)
- *intr_done = 0;
- if (cs->hw.elsa.transcnt <= 0) {
- cs->hw.elsa.IER &= ~UART_IER_THRI;
- serial_outp(cs, UART_IER, cs->hw.elsa.IER);
- }
-}
-
-
-static void rs_interrupt_elsa(struct IsdnCardState *cs)
-{
- int status, iir, msr;
- int pass_counter = 0;
-
-#ifdef SERIAL_DEBUG_INTR
- printk(KERN_DEBUG "rs_interrupt_single(%d)...", cs->irq);
-#endif
-
- do {
- status = serial_inp(cs, UART_LSR);
- debugl1(cs, "rs LSR %02x", status);
-#ifdef SERIAL_DEBUG_INTR
- printk("status = %x...", status);
-#endif
- if (status & UART_LSR_DR)
- receive_chars(cs, &status);
- if (status & UART_LSR_THRE)
- transmit_chars(cs, NULL);
- if (pass_counter++ > RS_ISR_PASS_LIMIT) {
- printk("rs_single loop break.\n");
- break;
- }
- iir = serial_inp(cs, UART_IIR);
- debugl1(cs, "rs IIR %02x", iir);
- if ((iir & 0xf) == 0) {
- msr = serial_inp(cs, UART_MSR);
- debugl1(cs, "rs MSR %02x", msr);
- }
- } while (!(iir & UART_IIR_NO_INT));
-#ifdef SERIAL_DEBUG_INTR
- printk("end.\n");
-#endif
-}
-
-extern int open_hscxstate(struct IsdnCardState *cs, struct BCState *bcs);
-extern void modehscx(struct BCState *bcs, int mode, int bc);
-extern void hscx_l2l1(struct PStack *st, int pr, void *arg);
-
-static void
-close_elsastate(struct BCState *bcs)
-{
- modehscx(bcs, 0, bcs->channel);
- if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
- if (bcs->hw.hscx.rcvbuf) {
- if (bcs->mode != L1_MODE_MODEM)
- kfree(bcs->hw.hscx.rcvbuf);
- bcs->hw.hscx.rcvbuf = NULL;
- }
- skb_queue_purge(&bcs->rqueue);
- skb_queue_purge(&bcs->squeue);
- if (bcs->tx_skb) {
- dev_kfree_skb_any(bcs->tx_skb);
- bcs->tx_skb = NULL;
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- }
- }
-}
-
-static void
-modem_write_cmd(struct IsdnCardState *cs, u_char *buf, int len) {
- int count, fp;
- u_char *msg = buf;
-
- if (!len)
- return;
- if (len > (MAX_MODEM_BUF - cs->hw.elsa.transcnt)) {
- return;
- }
- fp = cs->hw.elsa.transcnt + cs->hw.elsa.transp;
- fp &= (MAX_MODEM_BUF - 1);
- count = len;
- if (count > MAX_MODEM_BUF - fp) {
- count = MAX_MODEM_BUF - fp;
- memcpy(cs->hw.elsa.transbuf + fp, msg, count);
- cs->hw.elsa.transcnt += count;
- msg += count;
- count = len - count;
- fp = 0;
- }
- memcpy(cs->hw.elsa.transbuf + fp, msg, count);
- cs->hw.elsa.transcnt += count;
- if (cs->hw.elsa.transcnt &&
- !(cs->hw.elsa.IER & UART_IER_THRI)) {
- cs->hw.elsa.IER |= UART_IER_THRI;
- serial_outp(cs, UART_IER, cs->hw.elsa.IER);
- }
-}
-
-static void
-modem_set_init(struct IsdnCardState *cs) {
- int timeout;
-
-#define RCV_DELAY 20
- modem_write_cmd(cs, MInit_1, strlen(MInit_1));
- timeout = 1000;
- while (timeout-- && cs->hw.elsa.transcnt)
- udelay(1000);
- debugl1(cs, "msi tout=%d", timeout);
- mdelay(RCV_DELAY);
- modem_write_cmd(cs, MInit_2, strlen(MInit_2));
- timeout = 1000;
- while (timeout-- && cs->hw.elsa.transcnt)
- udelay(1000);
- debugl1(cs, "msi tout=%d", timeout);
- mdelay(RCV_DELAY);
- modem_write_cmd(cs, MInit_3, strlen(MInit_3));
- timeout = 1000;
- while (timeout-- && cs->hw.elsa.transcnt)
- udelay(1000);
- debugl1(cs, "msi tout=%d", timeout);
- mdelay(RCV_DELAY);
- modem_write_cmd(cs, MInit_4, strlen(MInit_4));
- timeout = 1000;
- while (timeout-- && cs->hw.elsa.transcnt)
- udelay(1000);
- debugl1(cs, "msi tout=%d", timeout);
- mdelay(RCV_DELAY);
- modem_write_cmd(cs, MInit_5, strlen(MInit_5));
- timeout = 1000;
- while (timeout-- && cs->hw.elsa.transcnt)
- udelay(1000);
- debugl1(cs, "msi tout=%d", timeout);
- mdelay(RCV_DELAY);
- modem_write_cmd(cs, MInit_6, strlen(MInit_6));
- timeout = 1000;
- while (timeout-- && cs->hw.elsa.transcnt)
- udelay(1000);
- debugl1(cs, "msi tout=%d", timeout);
- mdelay(RCV_DELAY);
- modem_write_cmd(cs, MInit_7, strlen(MInit_7));
- timeout = 1000;
- while (timeout-- && cs->hw.elsa.transcnt)
- udelay(1000);
- debugl1(cs, "msi tout=%d", timeout);
- mdelay(RCV_DELAY);
-}
-
-static void
-modem_set_dial(struct IsdnCardState *cs, int outgoing) {
- int timeout;
-#define RCV_DELAY 20
-
- modem_write_cmd(cs, MInit_speed28800, strlen(MInit_speed28800));
- timeout = 1000;
- while (timeout-- && cs->hw.elsa.transcnt)
- udelay(1000);
- debugl1(cs, "msi tout=%d", timeout);
- mdelay(RCV_DELAY);
- if (outgoing)
- modem_write_cmd(cs, MInit_dialout, strlen(MInit_dialout));
- else
- modem_write_cmd(cs, MInit_dialin, strlen(MInit_dialin));
- timeout = 1000;
- while (timeout-- && cs->hw.elsa.transcnt)
- udelay(1000);
- debugl1(cs, "msi tout=%d", timeout);
- mdelay(RCV_DELAY);
-}
-
-static void
-modem_l2l1(struct PStack *st, int pr, void *arg)
-{
- struct BCState *bcs = st->l1.bcs;
- struct sk_buff *skb = arg;
- u_long flags;
-
- if (pr == (PH_DATA | REQUEST)) {
- spin_lock_irqsave(&bcs->cs->lock, flags);
- if (bcs->tx_skb) {
- skb_queue_tail(&bcs->squeue, skb);
- } else {
- bcs->tx_skb = skb;
- test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->hw.hscx.count = 0;
- write_modem(bcs);
- }
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- } else if (pr == (PH_ACTIVATE | REQUEST)) {
- test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
- st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
- set_arcofi(bcs->cs, st->l1.bc);
- mstartup(bcs->cs);
- modem_set_dial(bcs->cs, test_bit(FLG_ORIG, &st->l2.flag));
- bcs->cs->hw.elsa.MFlag = 2;
- } else if (pr == (PH_DEACTIVATE | REQUEST)) {
- test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
- bcs->cs->dc.isac.arcofi_bc = st->l1.bc;
- arcofi_fsm(bcs->cs, ARCOFI_START, &ARCOFI_XOP_0);
- wait_event_interruptible(bcs->cs->dc.isac.arcofi_wait,
- bcs->cs->dc.isac.arcofi_state == ARCOFI_NOP);
- bcs->cs->hw.elsa.MFlag = 1;
- } else {
- printk(KERN_WARNING "ElsaSer: unknown pr %x\n", pr);
- }
-}
-
-static int
-setstack_elsa(struct PStack *st, struct BCState *bcs)
-{
-
- bcs->channel = st->l1.bc;
- switch (st->l1.mode) {
- case L1_MODE_HDLC:
- case L1_MODE_TRANS:
- if (open_hscxstate(st->l1.hardware, bcs))
- return (-1);
- st->l2.l2l1 = hscx_l2l1;
- break;
- case L1_MODE_MODEM:
- bcs->mode = L1_MODE_MODEM;
- if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
- bcs->hw.hscx.rcvbuf = bcs->cs->hw.elsa.rcvbuf;
- skb_queue_head_init(&bcs->rqueue);
- skb_queue_head_init(&bcs->squeue);
- }
- bcs->tx_skb = NULL;
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->event = 0;
- bcs->hw.hscx.rcvidx = 0;
- bcs->tx_cnt = 0;
- bcs->cs->hw.elsa.bcs = bcs;
- st->l2.l2l1 = modem_l2l1;
- break;
- }
- st->l1.bcs = bcs;
- setstack_manager(st);
- bcs->st = st;
- setstack_l1_B(st);
- return (0);
-}
-
-static void
-init_modem(struct IsdnCardState *cs) {
-
- cs->bcs[0].BC_SetStack = setstack_elsa;
- cs->bcs[1].BC_SetStack = setstack_elsa;
- cs->bcs[0].BC_Close = close_elsastate;
- cs->bcs[1].BC_Close = close_elsastate;
- if (!(cs->hw.elsa.rcvbuf = kmalloc(MAX_MODEM_BUF,
- GFP_ATOMIC))) {
- printk(KERN_WARNING
- "Elsa: No modem mem hw.elsa.rcvbuf\n");
- return;
- }
- if (!(cs->hw.elsa.transbuf = kmalloc(MAX_MODEM_BUF,
- GFP_ATOMIC))) {
- printk(KERN_WARNING
- "Elsa: No modem mem hw.elsa.transbuf\n");
- kfree(cs->hw.elsa.rcvbuf);
- cs->hw.elsa.rcvbuf = NULL;
- return;
- }
- if (mstartup(cs)) {
- printk(KERN_WARNING "Elsa: problem startup modem\n");
- }
- modem_set_init(cs);
-}
-
-static void
-release_modem(struct IsdnCardState *cs) {
-
- cs->hw.elsa.MFlag = 0;
- if (cs->hw.elsa.transbuf) {
- if (cs->hw.elsa.rcvbuf) {
- mshutdown(cs);
- kfree(cs->hw.elsa.rcvbuf);
- cs->hw.elsa.rcvbuf = NULL;
- }
- kfree(cs->hw.elsa.transbuf);
- cs->hw.elsa.transbuf = NULL;
- }
-}
diff --git a/drivers/isdn/hisax/enternow_pci.c b/drivers/isdn/hisax/enternow_pci.c
deleted file mode 100644
index e8d431a8302d..000000000000
--- a/drivers/isdn/hisax/enternow_pci.c
+++ /dev/null
@@ -1,420 +0,0 @@
-/* enternow_pci.c,v 0.99 2001/10/02
- *
- * enternow_pci.c Card-specific routines for
- * Formula-n enter:now ISDN PCI ab
- * Gerdes AG Power ISDN PCI
- * Woerltronic SA 16 PCI
- * (based on HiSax driver by Karsten Keil)
- *
- * Author Christoph Ersfeld <info@formula-n.de>
- * Formula-n Europe AG (www.formula-n.com)
- * previously Gerdes AG
- *
- *
- * This file is (c) under GNU PUBLIC LICENSE
- *
- * Notes:
- * This driver interfaces to netjet.c which performs B-channel
- * processing.
- *
- * Version 0.99 is the first release of this driver and there are
- * certainly a few bugs.
- * It isn't testet on linux 2.4 yet, so consider this code to be
- * beta.
- *
- * Please don't report me any malfunction without sending
- * (compressed) debug-logs.
- * It would be nearly impossible to retrace it.
- *
- * Log D-channel-processing as follows:
- *
- * 1. Load hisax with card-specific parameters, this example ist for
- * Formula-n enter:now ISDN PCI and compatible
- * (f.e. Gerdes Power ISDN PCI)
- *
- * modprobe hisax type=41 protocol=2 id=gerdes
- *
- * if you chose an other value for id, you need to modify the
- * code below, too.
- *
- * 2. set debug-level
- *
- * hisaxctrl gerdes 1 0x3ff
- * hisaxctrl gerdes 11 0x4f
- * cat /dev/isdnctrl >> ~/log &
- *
- * Please take also a look into /var/log/messages if there is
- * anything importand concerning HISAX.
- *
- *
- * Credits:
- * Programming the driver for Formula-n enter:now ISDN PCI and
- * necessary the driver for the used Amd 7930 D-channel-controller
- * was spnsored by Formula-n Europe AG.
- * Thanks to Karsten Keil and Petr Novak, who gave me support in
- * Hisax-specific questions.
- * I want so say special thanks to Carl-Friedrich Braun, who had to
- * answer a lot of questions about generally ISDN and about handling
- * of the Amd-Chip.
- *
- */
-
-
-#include "hisax.h"
-#include "isac.h"
-#include "isdnl1.h"
-#include "amd7930_fn.h"
-#include <linux/interrupt.h>
-#include <linux/ppp_defs.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include "netjet.h"
-
-
-
-static const char *enternow_pci_rev = "$Revision: 1.1.4.5 $";
-
-
-/* for PowerISDN PCI */
-#define TJ_AMD_IRQ 0x20
-#define TJ_LED1 0x40
-#define TJ_LED2 0x80
-
-
-/* The window to [the] AMD [chip]...
- * From address hw.njet.base + TJ_AMD_PORT onwards, the AMD
- * maps [consecutive/multiple] 8 bits into the TigerJet I/O space
- * -> 0x01 of the AMD at hw.njet.base + 0C4 */
-#define TJ_AMD_PORT 0xC0
-
-
-
-/* *************************** I/O-Interface functions ************************************* */
-
-
-/* cs->readisac, macro rByteAMD */
-static unsigned char
-ReadByteAmd7930(struct IsdnCardState *cs, unsigned char offset)
-{
- /* direct register */
- if (offset < 8)
- return (inb(cs->hw.njet.isac + 4 * offset));
-
- /* indirect register */
- else {
- outb(offset, cs->hw.njet.isac + 4 * AMD_CR);
- return (inb(cs->hw.njet.isac + 4 * AMD_DR));
- }
-}
-
-/* cs->writeisac, macro wByteAMD */
-static void
-WriteByteAmd7930(struct IsdnCardState *cs, unsigned char offset, unsigned char value)
-{
- /* direct register */
- if (offset < 8)
- outb(value, cs->hw.njet.isac + 4 * offset);
-
- /* indirect register */
- else {
- outb(offset, cs->hw.njet.isac + 4 * AMD_CR);
- outb(value, cs->hw.njet.isac + 4 * AMD_DR);
- }
-}
-
-
-static void
-enpci_setIrqMask(struct IsdnCardState *cs, unsigned char val) {
- if (!val)
- outb(0x00, cs->hw.njet.base + NETJET_IRQMASK1);
- else
- outb(TJ_AMD_IRQ, cs->hw.njet.base + NETJET_IRQMASK1);
-}
-
-
-static unsigned char dummyrr(struct IsdnCardState *cs, int chan, unsigned char off)
-{
- return (5);
-}
-
-static void dummywr(struct IsdnCardState *cs, int chan, unsigned char off, unsigned char value)
-{
-
-}
-
-
-/* ******************************************************************************** */
-
-
-static void
-reset_enpci(struct IsdnCardState *cs)
-{
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "enter:now PCI: reset");
-
- /* Reset on, (also for AMD) */
- cs->hw.njet.ctrl_reg = 0x07;
- outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL);
- mdelay(20);
- /* Reset off */
- cs->hw.njet.ctrl_reg = 0x30;
- outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL);
- /* 20ms delay */
- mdelay(20);
- cs->hw.njet.auxd = 0; // LED-status
- cs->hw.njet.dmactrl = 0;
- outb(~TJ_AMD_IRQ, cs->hw.njet.base + NETJET_AUXCTRL);
- outb(TJ_AMD_IRQ, cs->hw.njet.base + NETJET_IRQMASK1);
- outb(cs->hw.njet.auxd, cs->hw.njet.auxa); // LED off
-}
-
-
-static int
-enpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
- u_long flags;
- unsigned char *chan;
-
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "enter:now PCI: card_msg: 0x%04X", mt);
-
- switch (mt) {
- case CARD_RESET:
- spin_lock_irqsave(&cs->lock, flags);
- reset_enpci(cs);
- Amd7930_init(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case CARD_RELEASE:
- release_io_netjet(cs);
- break;
- case CARD_INIT:
- reset_enpci(cs);
- inittiger(cs);
- /* irq must be on here */
- Amd7930_init(cs);
- break;
- case CARD_TEST:
- break;
- case MDL_ASSIGN:
- /* TEI assigned, LED1 on */
- cs->hw.njet.auxd = TJ_AMD_IRQ << 1;
- outb(cs->hw.njet.auxd, cs->hw.njet.base + NETJET_AUXDATA);
- break;
- case MDL_REMOVE:
- /* TEI removed, LEDs off */
- cs->hw.njet.auxd = 0;
- outb(0x00, cs->hw.njet.base + NETJET_AUXDATA);
- break;
- case MDL_BC_ASSIGN:
- /* activate B-channel */
- chan = (unsigned char *)arg;
-
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "enter:now PCI: assign phys. BC %d in AMD LMR1", *chan);
-
- cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 | (*chan + 1)), "MDL_BC_ASSIGN");
- /* at least one b-channel in use, LED 2 on */
- cs->hw.njet.auxd |= TJ_AMD_IRQ << 2;
- outb(cs->hw.njet.auxd, cs->hw.njet.base + NETJET_AUXDATA);
- break;
- case MDL_BC_RELEASE:
- /* deactivate B-channel */
- chan = (unsigned char *)arg;
-
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "enter:now PCI: release phys. BC %d in Amd LMR1", *chan);
-
- cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 & ~(*chan + 1)), "MDL_BC_RELEASE");
- /* no b-channel active -> LED2 off */
- if (!(cs->dc.amd7930.lmr1 & 3)) {
- cs->hw.njet.auxd &= ~(TJ_AMD_IRQ << 2);
- outb(cs->hw.njet.auxd, cs->hw.njet.base + NETJET_AUXDATA);
- }
- break;
- default:
- break;
-
- }
- return (0);
-}
-
-static irqreturn_t
-enpci_interrupt(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- unsigned char s0val, s1val, ir;
- u_long flags;
-
- spin_lock_irqsave(&cs->lock, flags);
- s1val = inb(cs->hw.njet.base + NETJET_IRQSTAT1);
-
- /* AMD threw an interrupt */
- if (!(s1val & TJ_AMD_IRQ)) {
- /* read and clear interrupt-register */
- ir = ReadByteAmd7930(cs, 0x00);
- Amd7930_interrupt(cs, ir);
- s1val = 1;
- } else
- s1val = 0;
- s0val = inb(cs->hw.njet.base + NETJET_IRQSTAT0);
- if ((s0val | s1val) == 0) { // shared IRQ
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_NONE;
- }
- if (s0val)
- outb(s0val, cs->hw.njet.base + NETJET_IRQSTAT0);
-
- /* DMA-Interrupt: B-channel-stuff */
- /* set bits in sval to indicate which page is free */
- if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) <
- inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ))
- /* the 2nd write page is free */
- s0val = 0x08;
- else /* the 1st write page is free */
- s0val = 0x04;
- if (inl(cs->hw.njet.base + NETJET_DMA_READ_ADR) <
- inl(cs->hw.njet.base + NETJET_DMA_READ_IRQ))
- /* the 2nd read page is free */
- s0val = s0val | 0x02;
- else /* the 1st read page is free */
- s0val = s0val | 0x01;
- if (s0val != cs->hw.njet.last_is0) /* we have a DMA interrupt */
- {
- if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
- }
- cs->hw.njet.irqstat0 = s0val;
- if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) !=
- (cs->hw.njet.last_is0 & NETJET_IRQM0_READ))
- /* we have a read dma int */
- read_tiger(cs);
- if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) !=
- (cs->hw.njet.last_is0 & NETJET_IRQM0_WRITE))
- /* we have a write dma int */
- write_tiger(cs);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- }
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static int en_pci_probe(struct pci_dev *dev_netjet, struct IsdnCardState *cs)
-{
- if (pci_enable_device(dev_netjet))
- return (0);
- cs->irq = dev_netjet->irq;
- if (!cs->irq) {
- printk(KERN_WARNING "enter:now PCI: No IRQ for PCI card found\n");
- return (0);
- }
- cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
- if (!cs->hw.njet.base) {
- printk(KERN_WARNING "enter:now PCI: No IO-Adr for PCI card found\n");
- return (0);
- }
- /* checks Sub-Vendor ID because system crashes with Traverse-Card */
- if ((dev_netjet->subsystem_vendor != 0x55) ||
- (dev_netjet->subsystem_device != 0x02)) {
- printk(KERN_WARNING "enter:now: You tried to load this driver with an incompatible TigerJet-card\n");
- printk(KERN_WARNING "Use type=20 for Traverse NetJet PCI Card.\n");
- return (0);
- }
-
- return (1);
-}
-
-static void en_cs_init(struct IsdnCard *card, struct IsdnCardState *cs)
-{
- cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
- cs->hw.njet.isac = cs->hw.njet.base + 0xC0; // Fenster zum AMD
-
- /* Reset an */
- cs->hw.njet.ctrl_reg = 0x07; // geändert von 0xff
- outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL);
- /* 20 ms Pause */
- mdelay(20);
-
- cs->hw.njet.ctrl_reg = 0x30; /* Reset Off and status read clear */
- outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL);
- mdelay(10);
-
- cs->hw.njet.auxd = 0x00; // war 0xc0
- cs->hw.njet.dmactrl = 0;
-
- outb(~TJ_AMD_IRQ, cs->hw.njet.base + NETJET_AUXCTRL);
- outb(TJ_AMD_IRQ, cs->hw.njet.base + NETJET_IRQMASK1);
- outb(cs->hw.njet.auxd, cs->hw.njet.auxa);
-}
-
-static int en_cs_init_rest(struct IsdnCard *card, struct IsdnCardState *cs)
-{
- const int bytecnt = 256;
-
- printk(KERN_INFO
- "enter:now PCI: PCI card configured at 0x%lx IRQ %d\n",
- cs->hw.njet.base, cs->irq);
- if (!request_region(cs->hw.njet.base, bytecnt, "Fn_ISDN")) {
- printk(KERN_WARNING
- "HiSax: enter:now config port %lx-%lx already in use\n",
- cs->hw.njet.base,
- cs->hw.njet.base + bytecnt);
- return (0);
- }
-
- setup_Amd7930(cs);
- cs->hw.njet.last_is0 = 0;
- /* macro rByteAMD */
- cs->readisac = &ReadByteAmd7930;
- /* macro wByteAMD */
- cs->writeisac = &WriteByteAmd7930;
- cs->dc.amd7930.setIrqMask = &enpci_setIrqMask;
-
- cs->BC_Read_Reg = &dummyrr;
- cs->BC_Write_Reg = &dummywr;
- cs->BC_Send_Data = &netjet_fill_dma;
- cs->cardmsg = &enpci_card_msg;
- cs->irq_func = &enpci_interrupt;
- cs->irq_flags |= IRQF_SHARED;
-
- return (1);
-}
-
-static struct pci_dev *dev_netjet = NULL;
-
-/* called by config.c */
-int setup_enternow_pci(struct IsdnCard *card)
-{
- int ret;
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
-
-#ifdef __BIG_ENDIAN
-#error "not running on big endian machines now"
-#endif
-
- strcpy(tmp, enternow_pci_rev);
- printk(KERN_INFO "HiSax: Formula-n Europe AG enter:now ISDN PCI driver Rev. %s\n", HiSax_getrev(tmp));
- if (cs->typ != ISDN_CTYPE_ENTERNOW)
- return (0);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
-
- for (;;)
- {
- if ((dev_netjet = hisax_find_pci_device(PCI_VENDOR_ID_TIGERJET,
- PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) {
- ret = en_pci_probe(dev_netjet, cs);
- if (!ret)
- return (0);
- } else {
- printk(KERN_WARNING "enter:now PCI: No PCI card found\n");
- return (0);
- }
-
- en_cs_init(card, cs);
- break;
- }
-
- return en_cs_init_rest(card, cs);
-}
diff --git a/drivers/isdn/hisax/fsm.c b/drivers/isdn/hisax/fsm.c
deleted file mode 100644
index 80ba82f77c63..000000000000
--- a/drivers/isdn/hisax/fsm.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/* $Id: fsm.c,v 1.14.6.4 2001/09/23 22:24:47 kai Exp $
- *
- * Finite state machine
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- * by Kai Germaschewski <kai.germaschewski@gmx.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Thanks to Jan den Ouden
- * Fritz Elfert
- *
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include "hisax.h"
-
-#define FSM_TIMER_DEBUG 0
-
-int
-FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount)
-{
- int i;
-
- fsm->jumpmatrix =
- kzalloc(array3_size(sizeof(FSMFNPTR), fsm->state_count,
- fsm->event_count),
- GFP_KERNEL);
- if (!fsm->jumpmatrix)
- return -ENOMEM;
-
- for (i = 0; i < fncount; i++)
- if ((fnlist[i].state >= fsm->state_count) || (fnlist[i].event >= fsm->event_count)) {
- printk(KERN_ERR "FsmNew Error line %d st(%ld/%ld) ev(%ld/%ld)\n",
- i, (long)fnlist[i].state, (long)fsm->state_count,
- (long)fnlist[i].event, (long)fsm->event_count);
- } else
- fsm->jumpmatrix[fsm->state_count * fnlist[i].event +
- fnlist[i].state] = (FSMFNPTR)fnlist[i].routine;
- return 0;
-}
-
-void
-FsmFree(struct Fsm *fsm)
-{
- kfree((void *) fsm->jumpmatrix);
-}
-
-int
-FsmEvent(struct FsmInst *fi, int event, void *arg)
-{
- FSMFNPTR r;
-
- if ((fi->state >= fi->fsm->state_count) || (event >= fi->fsm->event_count)) {
- printk(KERN_ERR "FsmEvent Error st(%ld/%ld) ev(%d/%ld)\n",
- (long)fi->state, (long)fi->fsm->state_count, event, (long)fi->fsm->event_count);
- return (1);
- }
- r = fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state];
- if (r) {
- if (fi->debug)
- fi->printdebug(fi, "State %s Event %s",
- fi->fsm->strState[fi->state],
- fi->fsm->strEvent[event]);
- r(fi, event, arg);
- return (0);
- } else {
- if (fi->debug)
- fi->printdebug(fi, "State %s Event %s no routine",
- fi->fsm->strState[fi->state],
- fi->fsm->strEvent[event]);
- return (!0);
- }
-}
-
-void
-FsmChangeState(struct FsmInst *fi, int newstate)
-{
- fi->state = newstate;
- if (fi->debug)
- fi->printdebug(fi, "ChangeState %s",
- fi->fsm->strState[newstate]);
-}
-
-static void
-FsmExpireTimer(struct timer_list *t)
-{
- struct FsmTimer *ft = from_timer(ft, t, tl);
-#if FSM_TIMER_DEBUG
- if (ft->fi->debug)
- ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft);
-#endif
- FsmEvent(ft->fi, ft->event, ft->arg);
-}
-
-void
-FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft)
-{
- ft->fi = fi;
-#if FSM_TIMER_DEBUG
- if (ft->fi->debug)
- ft->fi->printdebug(ft->fi, "FsmInitTimer %lx", (long) ft);
-#endif
- timer_setup(&ft->tl, FsmExpireTimer, 0);
-}
-
-void
-FsmDelTimer(struct FsmTimer *ft, int where)
-{
-#if FSM_TIMER_DEBUG
- if (ft->fi->debug)
- ft->fi->printdebug(ft->fi, "FsmDelTimer %lx %d", (long) ft, where);
-#endif
- del_timer(&ft->tl);
-}
-
-int
-FsmAddTimer(struct FsmTimer *ft,
- int millisec, int event, void *arg, int where)
-{
-
-#if FSM_TIMER_DEBUG
- if (ft->fi->debug)
- ft->fi->printdebug(ft->fi, "FsmAddTimer %lx %d %d",
- (long) ft, millisec, where);
-#endif
-
- if (timer_pending(&ft->tl)) {
- printk(KERN_WARNING "FsmAddTimer: timer already active!\n");
- ft->fi->printdebug(ft->fi, "FsmAddTimer already active!");
- return -1;
- }
- ft->event = event;
- ft->arg = arg;
- ft->tl.expires = jiffies + (millisec * HZ) / 1000;
- add_timer(&ft->tl);
- return 0;
-}
-
-void
-FsmRestartTimer(struct FsmTimer *ft,
- int millisec, int event, void *arg, int where)
-{
-
-#if FSM_TIMER_DEBUG
- if (ft->fi->debug)
- ft->fi->printdebug(ft->fi, "FsmRestartTimer %lx %d %d",
- (long) ft, millisec, where);
-#endif
-
- if (timer_pending(&ft->tl))
- del_timer(&ft->tl);
- ft->event = event;
- ft->arg = arg;
- ft->tl.expires = jiffies + (millisec * HZ) / 1000;
- add_timer(&ft->tl);
-}
diff --git a/drivers/isdn/hisax/fsm.h b/drivers/isdn/hisax/fsm.h
deleted file mode 100644
index 8c7385619a46..000000000000
--- a/drivers/isdn/hisax/fsm.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* $Id: fsm.h,v 1.3.2.2 2001/09/23 22:24:47 kai Exp $
- *
- * Finite state machine
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- * by Kai Germaschewski <kai.germaschewski@gmx.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef __FSM_H__
-#define __FSM_H__
-
-#include <linux/timer.h>
-
-struct FsmInst;
-
-typedef void (*FSMFNPTR)(struct FsmInst *, int, void *);
-
-struct Fsm {
- FSMFNPTR *jumpmatrix;
- int state_count, event_count;
- char **strEvent, **strState;
-};
-
-struct FsmInst {
- struct Fsm *fsm;
- int state;
- int debug;
- void *userdata;
- int userint;
- void (*printdebug) (struct FsmInst *, char *, ...);
-};
-
-struct FsmNode {
- int state, event;
- void (*routine) (struct FsmInst *, int, void *);
-};
-
-struct FsmTimer {
- struct FsmInst *fi;
- struct timer_list tl;
- int event;
- void *arg;
-};
-
-int FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount);
-void FsmFree(struct Fsm *fsm);
-int FsmEvent(struct FsmInst *fi, int event, void *arg);
-void FsmChangeState(struct FsmInst *fi, int newstate);
-void FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft);
-int FsmAddTimer(struct FsmTimer *ft, int millisec, int event,
- void *arg, int where);
-void FsmRestartTimer(struct FsmTimer *ft, int millisec, int event,
- void *arg, int where);
-void FsmDelTimer(struct FsmTimer *ft, int where);
-
-#endif
diff --git a/drivers/isdn/hisax/gazel.c b/drivers/isdn/hisax/gazel.c
deleted file mode 100644
index a6d8af02354a..000000000000
--- a/drivers/isdn/hisax/gazel.c
+++ /dev/null
@@ -1,691 +0,0 @@
-/* $Id: gazel.c,v 2.19.2.4 2004/01/14 16:04:48 keil Exp $
- *
- * low level stuff for Gazel isdn cards
- *
- * Author BeWan Systems
- * based on source code from Karsten Keil
- * Copyright by BeWan Systems
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/init.h>
-#include "hisax.h"
-#include "isac.h"
-#include "hscx.h"
-#include "isdnl1.h"
-#include "ipac.h"
-#include <linux/pci.h>
-
-static const char *gazel_revision = "$Revision: 2.19.2.4 $";
-
-#define R647 1
-#define R685 2
-#define R753 3
-#define R742 4
-
-#define PLX_CNTRL 0x50 /* registre de controle PLX */
-#define RESET_GAZEL 0x4
-#define RESET_9050 0x40000000
-#define PLX_INCSR 0x4C /* registre d'IT du 9050 */
-#define INT_ISAC_EN 0x8 /* 1 = enable IT isac */
-#define INT_ISAC 0x20 /* 1 = IT isac en cours */
-#define INT_HSCX_EN 0x1 /* 1 = enable IT hscx */
-#define INT_HSCX 0x4 /* 1 = IT hscx en cours */
-#define INT_PCI_EN 0x40 /* 1 = enable IT PCI */
-#define INT_IPAC_EN 0x3 /* enable IT ipac */
-
-
-#define byteout(addr, val) outb(val, addr)
-#define bytein(addr) inb(addr)
-
-static inline u_char
-readreg(unsigned int adr, u_short off)
-{
- return bytein(adr + off);
-}
-
-static inline void
-writereg(unsigned int adr, u_short off, u_char data)
-{
- byteout(adr + off, data);
-}
-
-
-static inline void
-read_fifo(unsigned int adr, u_char *data, int size)
-{
- insb(adr, data, size);
-}
-
-static void
-write_fifo(unsigned int adr, u_char *data, int size)
-{
- outsb(adr, data, size);
-}
-
-static inline u_char
-readreg_ipac(unsigned int adr, u_short off)
-{
- register u_char ret;
-
- byteout(adr, off);
- ret = bytein(adr + 4);
- return ret;
-}
-
-static inline void
-writereg_ipac(unsigned int adr, u_short off, u_char data)
-{
- byteout(adr, off);
- byteout(adr + 4, data);
-}
-
-
-static inline void
-read_fifo_ipac(unsigned int adr, u_short off, u_char *data, int size)
-{
- byteout(adr, off);
- insb(adr + 4, data, size);
-}
-
-static void
-write_fifo_ipac(unsigned int adr, u_short off, u_char *data, int size)
-{
- byteout(adr, off);
- outsb(adr + 4, data, size);
-}
-
-/* Interface functions */
-
-static u_char
-ReadISAC(struct IsdnCardState *cs, u_char offset)
-{
- u_short off2 = offset;
-
- switch (cs->subtyp) {
- case R647:
- off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf));
- /* fall through */
- case R685:
- return (readreg(cs->hw.gazel.isac, off2));
- case R753:
- case R742:
- return (readreg_ipac(cs->hw.gazel.ipac, 0x80 + off2));
- }
- return 0;
-}
-
-static void
-WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
-{
- u_short off2 = offset;
-
- switch (cs->subtyp) {
- case R647:
- off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf));
- /* fall through */
- case R685:
- writereg(cs->hw.gazel.isac, off2, value);
- break;
- case R753:
- case R742:
- writereg_ipac(cs->hw.gazel.ipac, 0x80 + off2, value);
- break;
- }
-}
-
-static void
-ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- switch (cs->subtyp) {
- case R647:
- case R685:
- read_fifo(cs->hw.gazel.isacfifo, data, size);
- break;
- case R753:
- case R742:
- read_fifo_ipac(cs->hw.gazel.ipac, 0x80, data, size);
- break;
- }
-}
-
-static void
-WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- switch (cs->subtyp) {
- case R647:
- case R685:
- write_fifo(cs->hw.gazel.isacfifo, data, size);
- break;
- case R753:
- case R742:
- write_fifo_ipac(cs->hw.gazel.ipac, 0x80, data, size);
- break;
- }
-}
-
-static void
-ReadHSCXfifo(struct IsdnCardState *cs, int hscx, u_char *data, int size)
-{
- switch (cs->subtyp) {
- case R647:
- case R685:
- read_fifo(cs->hw.gazel.hscxfifo[hscx], data, size);
- break;
- case R753:
- case R742:
- read_fifo_ipac(cs->hw.gazel.ipac, hscx * 0x40, data, size);
- break;
- }
-}
-
-static void
-WriteHSCXfifo(struct IsdnCardState *cs, int hscx, u_char *data, int size)
-{
- switch (cs->subtyp) {
- case R647:
- case R685:
- write_fifo(cs->hw.gazel.hscxfifo[hscx], data, size);
- break;
- case R753:
- case R742:
- write_fifo_ipac(cs->hw.gazel.ipac, hscx * 0x40, data, size);
- break;
- }
-}
-
-static u_char
-ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
-{
- u_short off2 = offset;
-
- switch (cs->subtyp) {
- case R647:
- off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf));
- /* fall through */
- case R685:
- return (readreg(cs->hw.gazel.hscx[hscx], off2));
- case R753:
- case R742:
- return (readreg_ipac(cs->hw.gazel.ipac, hscx * 0x40 + off2));
- }
- return 0;
-}
-
-static void
-WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
-{
- u_short off2 = offset;
-
- switch (cs->subtyp) {
- case R647:
- off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf));
- /* fall through */
- case R685:
- writereg(cs->hw.gazel.hscx[hscx], off2, value);
- break;
- case R753:
- case R742:
- writereg_ipac(cs->hw.gazel.ipac, hscx * 0x40 + off2, value);
- break;
- }
-}
-
-/*
- * fast interrupt HSCX stuff goes here
- */
-
-#define READHSCX(cs, nr, reg) ReadHSCX(cs, nr, reg)
-#define WRITEHSCX(cs, nr, reg, data) WriteHSCX(cs, nr, reg, data)
-#define READHSCXFIFO(cs, nr, ptr, cnt) ReadHSCXfifo(cs, nr, ptr, cnt)
-#define WRITEHSCXFIFO(cs, nr, ptr, cnt) WriteHSCXfifo(cs, nr, ptr, cnt)
-
-#include "hscx_irq.c"
-
-static irqreturn_t
-gazel_interrupt(int intno, void *dev_id)
-{
-#define MAXCOUNT 5
- struct IsdnCardState *cs = dev_id;
- u_char valisac, valhscx;
- int count = 0;
- u_long flags;
-
- spin_lock_irqsave(&cs->lock, flags);
- do {
- valhscx = ReadHSCX(cs, 1, HSCX_ISTA);
- if (valhscx)
- hscx_int_main(cs, valhscx);
- valisac = ReadISAC(cs, ISAC_ISTA);
- if (valisac)
- isac_interrupt(cs, valisac);
- count++;
- } while ((valhscx || valisac) && (count < MAXCOUNT));
-
- WriteHSCX(cs, 0, HSCX_MASK, 0xFF);
- WriteHSCX(cs, 1, HSCX_MASK, 0xFF);
- WriteISAC(cs, ISAC_MASK, 0xFF);
- WriteISAC(cs, ISAC_MASK, 0x0);
- WriteHSCX(cs, 0, HSCX_MASK, 0x0);
- WriteHSCX(cs, 1, HSCX_MASK, 0x0);
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-
-static irqreturn_t
-gazel_interrupt_ipac(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_char ista, val;
- int count = 0;
- u_long flags;
-
- spin_lock_irqsave(&cs->lock, flags);
- ista = ReadISAC(cs, IPAC_ISTA - 0x80);
- do {
- if (ista & 0x0f) {
- val = ReadHSCX(cs, 1, HSCX_ISTA);
- if (ista & 0x01)
- val |= 0x01;
- if (ista & 0x04)
- val |= 0x02;
- if (ista & 0x08)
- val |= 0x04;
- if (val) {
- hscx_int_main(cs, val);
- }
- }
- if (ista & 0x20) {
- val = 0xfe & ReadISAC(cs, ISAC_ISTA);
- if (val) {
- isac_interrupt(cs, val);
- }
- }
- if (ista & 0x10) {
- val = 0x01;
- isac_interrupt(cs, val);
- }
- ista = ReadISAC(cs, IPAC_ISTA - 0x80);
- count++;
- }
- while ((ista & 0x3f) && (count < MAXCOUNT));
-
- WriteISAC(cs, IPAC_MASK - 0x80, 0xFF);
- WriteISAC(cs, IPAC_MASK - 0x80, 0xC0);
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static void
-release_io_gazel(struct IsdnCardState *cs)
-{
- unsigned int i;
-
- switch (cs->subtyp) {
- case R647:
- for (i = 0x0000; i < 0xC000; i += 0x1000)
- release_region(i + cs->hw.gazel.hscx[0], 16);
- release_region(0xC000 + cs->hw.gazel.hscx[0], 1);
- break;
-
- case R685:
- release_region(cs->hw.gazel.hscx[0], 0x100);
- release_region(cs->hw.gazel.cfg_reg, 0x80);
- break;
-
- case R753:
- release_region(cs->hw.gazel.ipac, 0x8);
- release_region(cs->hw.gazel.cfg_reg, 0x80);
- break;
-
- case R742:
- release_region(cs->hw.gazel.ipac, 8);
- break;
- }
-}
-
-static int
-reset_gazel(struct IsdnCardState *cs)
-{
- unsigned long plxcntrl, addr = cs->hw.gazel.cfg_reg;
-
- switch (cs->subtyp) {
- case R647:
- writereg(addr, 0, 0);
- HZDELAY(10);
- writereg(addr, 0, 1);
- HZDELAY(2);
- break;
- case R685:
- plxcntrl = inl(addr + PLX_CNTRL);
- plxcntrl |= (RESET_9050 + RESET_GAZEL);
- outl(plxcntrl, addr + PLX_CNTRL);
- plxcntrl &= ~(RESET_9050 + RESET_GAZEL);
- HZDELAY(4);
- outl(plxcntrl, addr + PLX_CNTRL);
- HZDELAY(10);
- outb(INT_ISAC_EN + INT_HSCX_EN + INT_PCI_EN, addr + PLX_INCSR);
- break;
- case R753:
- plxcntrl = inl(addr + PLX_CNTRL);
- plxcntrl |= (RESET_9050 + RESET_GAZEL);
- outl(plxcntrl, addr + PLX_CNTRL);
- plxcntrl &= ~(RESET_9050 + RESET_GAZEL);
- WriteISAC(cs, IPAC_POTA2 - 0x80, 0x20);
- HZDELAY(4);
- outl(plxcntrl, addr + PLX_CNTRL);
- HZDELAY(10);
- WriteISAC(cs, IPAC_POTA2 - 0x80, 0x00);
- WriteISAC(cs, IPAC_ACFG - 0x80, 0xff);
- WriteISAC(cs, IPAC_AOE - 0x80, 0x0);
- WriteISAC(cs, IPAC_MASK - 0x80, 0xff);
- WriteISAC(cs, IPAC_CONF - 0x80, 0x1);
- outb(INT_IPAC_EN + INT_PCI_EN, addr + PLX_INCSR);
- WriteISAC(cs, IPAC_MASK - 0x80, 0xc0);
- break;
- case R742:
- WriteISAC(cs, IPAC_POTA2 - 0x80, 0x20);
- HZDELAY(4);
- WriteISAC(cs, IPAC_POTA2 - 0x80, 0x00);
- WriteISAC(cs, IPAC_ACFG - 0x80, 0xff);
- WriteISAC(cs, IPAC_AOE - 0x80, 0x0);
- WriteISAC(cs, IPAC_MASK - 0x80, 0xff);
- WriteISAC(cs, IPAC_CONF - 0x80, 0x1);
- WriteISAC(cs, IPAC_MASK - 0x80, 0xc0);
- break;
- }
- return (0);
-}
-
-static int
-Gazel_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
- u_long flags;
-
- switch (mt) {
- case CARD_RESET:
- spin_lock_irqsave(&cs->lock, flags);
- reset_gazel(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_RELEASE:
- release_io_gazel(cs);
- return (0);
- case CARD_INIT:
- spin_lock_irqsave(&cs->lock, flags);
- inithscxisac(cs, 1);
- if ((cs->subtyp == R647) || (cs->subtyp == R685)) {
- int i;
- for (i = 0; i < (2 + MAX_WAITING_CALLS); i++) {
- cs->bcs[i].hw.hscx.tsaxr0 = 0x1f;
- cs->bcs[i].hw.hscx.tsaxr1 = 0x23;
- }
- }
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_TEST:
- return (0);
- }
- return (0);
-}
-
-static int
-reserve_regions(struct IsdnCard *card, struct IsdnCardState *cs)
-{
- unsigned int i, j, base = 0, adr = 0, len = 0;
-
- switch (cs->subtyp) {
- case R647:
- base = cs->hw.gazel.hscx[0];
- if (!request_region(adr = (0xC000 + base), len = 1, "gazel"))
- goto error;
- for (i = 0x0000; i < 0xC000; i += 0x1000) {
- if (!request_region(adr = (i + base), len = 16, "gazel"))
- goto error;
- }
- if (i != 0xC000) {
- for (j = 0; j < i; j += 0x1000)
- release_region(j + base, 16);
- release_region(0xC000 + base, 1);
- goto error;
- }
- break;
-
- case R685:
- if (!request_region(adr = cs->hw.gazel.hscx[0], len = 0x100, "gazel"))
- goto error;
- if (!request_region(adr = cs->hw.gazel.cfg_reg, len = 0x80, "gazel")) {
- release_region(cs->hw.gazel.hscx[0], 0x100);
- goto error;
- }
- break;
-
- case R753:
- if (!request_region(adr = cs->hw.gazel.ipac, len = 0x8, "gazel"))
- goto error;
- if (!request_region(adr = cs->hw.gazel.cfg_reg, len = 0x80, "gazel")) {
- release_region(cs->hw.gazel.ipac, 8);
- goto error;
- }
- break;
-
- case R742:
- if (!request_region(adr = cs->hw.gazel.ipac, len = 0x8, "gazel"))
- goto error;
- break;
- }
-
- return 0;
-
-error:
- printk(KERN_WARNING "Gazel: io ports 0x%x-0x%x already in use\n",
- adr, adr + len);
- return 1;
-}
-
-static int setup_gazelisa(struct IsdnCard *card, struct IsdnCardState *cs)
-{
- printk(KERN_INFO "Gazel: ISA PnP card automatic recognition\n");
- // we got an irq parameter, assume it is an ISA card
- // R742 decodes address even in not started...
- // R647 returns FF if not present or not started
- // eventually needs improvment
- if (readreg_ipac(card->para[1], IPAC_ID) == 1)
- cs->subtyp = R742;
- else
- cs->subtyp = R647;
-
- setup_isac(cs);
- cs->hw.gazel.cfg_reg = card->para[1] + 0xC000;
- cs->hw.gazel.ipac = card->para[1];
- cs->hw.gazel.isac = card->para[1] + 0x8000;
- cs->hw.gazel.hscx[0] = card->para[1];
- cs->hw.gazel.hscx[1] = card->para[1] + 0x4000;
- cs->irq = card->para[0];
- cs->hw.gazel.isacfifo = cs->hw.gazel.isac;
- cs->hw.gazel.hscxfifo[0] = cs->hw.gazel.hscx[0];
- cs->hw.gazel.hscxfifo[1] = cs->hw.gazel.hscx[1];
-
- switch (cs->subtyp) {
- case R647:
- printk(KERN_INFO "Gazel: Card ISA R647/R648 found\n");
- cs->dc.isac.adf2 = 0x87;
- printk(KERN_INFO
- "Gazel: config irq:%d isac:0x%X cfg:0x%X\n",
- cs->irq, cs->hw.gazel.isac, cs->hw.gazel.cfg_reg);
- printk(KERN_INFO
- "Gazel: hscx A:0x%X hscx B:0x%X\n",
- cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]);
-
- break;
- case R742:
- printk(KERN_INFO "Gazel: Card ISA R742 found\n");
- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
- printk(KERN_INFO
- "Gazel: config irq:%d ipac:0x%X\n",
- cs->irq, cs->hw.gazel.ipac);
- break;
- }
-
- return (0);
-}
-
-#ifdef CONFIG_PCI
-static struct pci_dev *dev_tel = NULL;
-
-static int setup_gazelpci(struct IsdnCardState *cs)
-{
- u_int pci_ioaddr0 = 0, pci_ioaddr1 = 0;
- u_char pci_irq = 0, found;
- u_int nbseek, seekcard;
-
- printk(KERN_WARNING "Gazel: PCI card automatic recognition\n");
-
- found = 0;
- seekcard = PCI_DEVICE_ID_PLX_R685;
- for (nbseek = 0; nbseek < 4; nbseek++) {
- if ((dev_tel = hisax_find_pci_device(PCI_VENDOR_ID_PLX,
- seekcard, dev_tel))) {
- if (pci_enable_device(dev_tel))
- return 1;
- pci_irq = dev_tel->irq;
- pci_ioaddr0 = pci_resource_start(dev_tel, 1);
- pci_ioaddr1 = pci_resource_start(dev_tel, 2);
- found = 1;
- }
- if (found)
- break;
- else {
- switch (seekcard) {
- case PCI_DEVICE_ID_PLX_R685:
- seekcard = PCI_DEVICE_ID_PLX_R753;
- break;
- case PCI_DEVICE_ID_PLX_R753:
- seekcard = PCI_DEVICE_ID_PLX_DJINN_ITOO;
- break;
- case PCI_DEVICE_ID_PLX_DJINN_ITOO:
- seekcard = PCI_DEVICE_ID_PLX_OLITEC;
- break;
- }
- }
- }
- if (!found) {
- printk(KERN_WARNING "Gazel: No PCI card found\n");
- return (1);
- }
- if (!pci_irq) {
- printk(KERN_WARNING "Gazel: No IRQ for PCI card found\n");
- return 1;
- }
- cs->hw.gazel.pciaddr[0] = pci_ioaddr0;
- cs->hw.gazel.pciaddr[1] = pci_ioaddr1;
- setup_isac(cs);
- pci_ioaddr1 &= 0xfffe;
- cs->hw.gazel.cfg_reg = pci_ioaddr0 & 0xfffe;
- cs->hw.gazel.ipac = pci_ioaddr1;
- cs->hw.gazel.isac = pci_ioaddr1 + 0x80;
- cs->hw.gazel.hscx[0] = pci_ioaddr1;
- cs->hw.gazel.hscx[1] = pci_ioaddr1 + 0x40;
- cs->hw.gazel.isacfifo = cs->hw.gazel.isac;
- cs->hw.gazel.hscxfifo[0] = cs->hw.gazel.hscx[0];
- cs->hw.gazel.hscxfifo[1] = cs->hw.gazel.hscx[1];
- cs->irq = pci_irq;
- cs->irq_flags |= IRQF_SHARED;
-
- switch (seekcard) {
- case PCI_DEVICE_ID_PLX_R685:
- printk(KERN_INFO "Gazel: Card PCI R685 found\n");
- cs->subtyp = R685;
- cs->dc.isac.adf2 = 0x87;
- printk(KERN_INFO
- "Gazel: config irq:%d isac:0x%X cfg:0x%X\n",
- cs->irq, cs->hw.gazel.isac, cs->hw.gazel.cfg_reg);
- printk(KERN_INFO
- "Gazel: hscx A:0x%X hscx B:0x%X\n",
- cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]);
- break;
- case PCI_DEVICE_ID_PLX_R753:
- case PCI_DEVICE_ID_PLX_DJINN_ITOO:
- case PCI_DEVICE_ID_PLX_OLITEC:
- printk(KERN_INFO "Gazel: Card PCI R753 found\n");
- cs->subtyp = R753;
- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
- printk(KERN_INFO
- "Gazel: config irq:%d ipac:0x%X cfg:0x%X\n",
- cs->irq, cs->hw.gazel.ipac, cs->hw.gazel.cfg_reg);
- break;
- }
-
- return (0);
-}
-#endif /* CONFIG_PCI */
-
-int setup_gazel(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
- u_char val;
-
- strcpy(tmp, gazel_revision);
- printk(KERN_INFO "Gazel: Driver Revision %s\n", HiSax_getrev(tmp));
-
- if (cs->typ != ISDN_CTYPE_GAZEL)
- return (0);
-
- if (card->para[0]) {
- if (setup_gazelisa(card, cs))
- return (0);
- } else {
-
-#ifdef CONFIG_PCI
- if (setup_gazelpci(cs))
- return (0);
-#else
- printk(KERN_WARNING "Gazel: Card PCI requested and NO_PCI_BIOS, unable to config\n");
- return (0);
-#endif /* CONFIG_PCI */
- }
-
- if (reserve_regions(card, cs)) {
- return (0);
- }
- if (reset_gazel(cs)) {
- printk(KERN_WARNING "Gazel: wrong IRQ\n");
- release_io_gazel(cs);
- return (0);
- }
- cs->readisac = &ReadISAC;
- cs->writeisac = &WriteISAC;
- cs->readisacfifo = &ReadISACfifo;
- cs->writeisacfifo = &WriteISACfifo;
- cs->BC_Read_Reg = &ReadHSCX;
- cs->BC_Write_Reg = &WriteHSCX;
- cs->BC_Send_Data = &hscx_fill_fifo;
- cs->cardmsg = &Gazel_card_msg;
-
- switch (cs->subtyp) {
- case R647:
- case R685:
- cs->irq_func = &gazel_interrupt;
- ISACVersion(cs, "Gazel:");
- if (HscxVersion(cs, "Gazel:")) {
- printk(KERN_WARNING
- "Gazel: wrong HSCX versions check IO address\n");
- release_io_gazel(cs);
- return (0);
- }
- break;
- case R742:
- case R753:
- cs->irq_func = &gazel_interrupt_ipac;
- val = ReadISAC(cs, IPAC_ID - 0x80);
- printk(KERN_INFO "Gazel: IPAC version %x\n", val);
- break;
- }
-
- return (1);
-}
diff --git a/drivers/isdn/hisax/hfc4s8s_l1.c b/drivers/isdn/hisax/hfc4s8s_l1.c
deleted file mode 100644
index e9bb8fb67ad0..000000000000
--- a/drivers/isdn/hisax/hfc4s8s_l1.c
+++ /dev/null
@@ -1,1584 +0,0 @@
-/*************************************************************************/
-/* $Id: hfc4s8s_l1.c,v 1.10 2005/02/09 16:31:09 martinb1 Exp $ */
-/* HFC-4S/8S low layer interface for Cologne Chip HFC-4S/8S isdn chips */
-/* The low layer (L1) is implemented as a loadable module for usage with */
-/* the HiSax isdn driver for passive cards. */
-/* */
-/* Author: Werner Cornelius */
-/* (C) 2003 Cornelius Consult (werner@cornelius-consult.de) */
-/* */
-/* Driver maintained by Cologne Chip */
-/* - Martin Bachem, support@colognechip.com */
-/* */
-/* This driver only works with chip revisions >= 1, older revision 0 */
-/* engineering samples (only first manufacturer sample cards) will not */
-/* work and are rejected by the driver. */
-/* */
-/* This file distributed under the GNU GPL. */
-/* */
-/* See Version History at the end of this file */
-/* */
-/*************************************************************************/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/timer.h>
-#include <linux/skbuff.h>
-#include <linux/wait.h>
-#include <asm/io.h>
-#include "hisax_if.h"
-#include "hfc4s8s_l1.h"
-
-static const char hfc4s8s_rev[] = "Revision: 1.10";
-
-/***************************************************************/
-/* adjustable transparent mode fifo threshold */
-/* The value defines the used fifo threshold with the equation */
-/* */
-/* notify number of bytes = 2 * 2 ^ TRANS_FIFO_THRES */
-/* */
-/* The default value is 5 which results in a buffer size of 64 */
-/* and an interrupt rate of 8ms. */
-/* The maximum value is 7 due to fifo size restrictions. */
-/* Values below 3-4 are not recommended due to high interrupt */
-/* load of the processor. For non critical applications the */
-/* value should be raised to 7 to reduce any interrupt overhead*/
-/***************************************************************/
-#define TRANS_FIFO_THRES 5
-
-/*************/
-/* constants */
-/*************/
-#define CLOCKMODE_0 0 /* ext. 24.576 MhZ clk freq, int. single clock mode */
-#define CLOCKMODE_1 1 /* ext. 49.576 MhZ clk freq, int. single clock mode */
-#define CHIP_ID_SHIFT 4
-#define HFC_MAX_ST 8
-#define MAX_D_FRAME_SIZE 270
-#define MAX_B_FRAME_SIZE 1536
-#define TRANS_TIMER_MODE (TRANS_FIFO_THRES & 0xf)
-#define TRANS_FIFO_BYTES (2 << TRANS_FIFO_THRES)
-#define MAX_F_CNT 0x0f
-
-#define CLKDEL_NT 0x6c
-#define CLKDEL_TE 0xf
-#define CTRL0_NT 4
-#define CTRL0_TE 0
-
-#define L1_TIMER_T4 2 /* minimum in jiffies */
-#define L1_TIMER_T3 (7 * HZ) /* activation timeout */
-#define L1_TIMER_T1 ((120 * HZ) / 1000) /* NT mode deactivation timeout */
-
-
-/******************/
-/* types and vars */
-/******************/
-static int card_cnt;
-
-/* private driver_data */
-typedef struct {
- int chip_id;
- int clock_mode;
- int max_st_ports;
- char *device_name;
-} hfc4s8s_param;
-
-static const struct pci_device_id hfc4s8s_ids[] = {
- {.vendor = PCI_VENDOR_ID_CCD,
- .device = PCI_DEVICE_ID_4S,
- .subvendor = 0x1397,
- .subdevice = 0x08b4,
- .driver_data =
- (unsigned long) &((hfc4s8s_param) {CHIP_ID_4S, CLOCKMODE_0, 4,
- "HFC-4S Evaluation Board"}),
- },
- {.vendor = PCI_VENDOR_ID_CCD,
- .device = PCI_DEVICE_ID_8S,
- .subvendor = 0x1397,
- .subdevice = 0x16b8,
- .driver_data =
- (unsigned long) &((hfc4s8s_param) {CHIP_ID_8S, CLOCKMODE_0, 8,
- "HFC-8S Evaluation Board"}),
- },
- {.vendor = PCI_VENDOR_ID_CCD,
- .device = PCI_DEVICE_ID_4S,
- .subvendor = 0x1397,
- .subdevice = 0xb520,
- .driver_data =
- (unsigned long) &((hfc4s8s_param) {CHIP_ID_4S, CLOCKMODE_1, 4,
- "IOB4ST"}),
- },
- {.vendor = PCI_VENDOR_ID_CCD,
- .device = PCI_DEVICE_ID_8S,
- .subvendor = 0x1397,
- .subdevice = 0xb522,
- .driver_data =
- (unsigned long) &((hfc4s8s_param) {CHIP_ID_8S, CLOCKMODE_1, 8,
- "IOB8ST"}),
- },
- {}
-};
-
-MODULE_DEVICE_TABLE(pci, hfc4s8s_ids);
-
-MODULE_AUTHOR("Werner Cornelius, werner@cornelius-consult.de");
-MODULE_DESCRIPTION("ISDN layer 1 for Cologne Chip HFC-4S/8S chips");
-MODULE_LICENSE("GPL");
-
-/***********/
-/* layer 1 */
-/***********/
-struct hfc4s8s_btype {
- spinlock_t lock;
- struct hisax_b_if b_if;
- struct hfc4s8s_l1 *l1p;
- struct sk_buff_head tx_queue;
- struct sk_buff *tx_skb;
- struct sk_buff *rx_skb;
- __u8 *rx_ptr;
- int tx_cnt;
- int bchan;
- int mode;
-};
-
-struct _hfc4s8s_hw;
-
-struct hfc4s8s_l1 {
- spinlock_t lock;
- struct _hfc4s8s_hw *hw; /* pointer to hardware area */
- int l1_state; /* actual l1 state */
- struct timer_list l1_timer; /* layer 1 timer structure */
- int nt_mode; /* set to nt mode */
- int st_num; /* own index */
- int enabled; /* interface is enabled */
- struct sk_buff_head d_tx_queue; /* send queue */
- int tx_cnt; /* bytes to send */
- struct hisax_d_if d_if; /* D-channel interface */
- struct hfc4s8s_btype b_ch[2]; /* B-channel data */
- struct hisax_b_if *b_table[2];
-};
-
-/**********************/
-/* hardware structure */
-/**********************/
-typedef struct _hfc4s8s_hw {
- spinlock_t lock;
-
- int cardnum;
- int ifnum;
- int iobase;
- int nt_mode;
- u_char *membase;
- u_char *hw_membase;
- void *pdev;
- int max_fifo;
- hfc4s8s_param driver_data;
- int irq;
- int fifo_sched_cnt;
- struct work_struct tqueue;
- struct hfc4s8s_l1 l1[HFC_MAX_ST];
- char card_name[60];
- struct {
- u_char r_irq_ctrl;
- u_char r_ctrl0;
- volatile u_char r_irq_statech; /* active isdn l1 status */
- u_char r_irqmsk_statchg; /* enabled isdn status ints */
- u_char r_irq_fifo_blx[8]; /* fifo status registers */
- u_char fifo_rx_trans_enables[8]; /* mask for enabled transparent rx fifos */
- u_char fifo_slow_timer_service[8]; /* mask for fifos needing slower timer service */
- volatile u_char r_irq_oview; /* contents of overview register */
- volatile u_char timer_irq;
- int timer_usg_cnt; /* number of channels using timer */
- } mr;
-} hfc4s8s_hw;
-
-
-
-/* inline functions io mapped */
-static inline void
-SetRegAddr(hfc4s8s_hw *a, u_char b)
-{
- outb(b, (a->iobase) + 4);
-}
-
-static inline u_char
-GetRegAddr(hfc4s8s_hw *a)
-{
- return (inb((volatile u_int) (a->iobase + 4)));
-}
-
-
-static inline void
-Write_hfc8(hfc4s8s_hw *a, u_char b, u_char c)
-{
- SetRegAddr(a, b);
- outb(c, a->iobase);
-}
-
-static inline void
-fWrite_hfc8(hfc4s8s_hw *a, u_char c)
-{
- outb(c, a->iobase);
-}
-
-static inline void
-fWrite_hfc32(hfc4s8s_hw *a, u_long c)
-{
- outl(c, a->iobase);
-}
-
-static inline u_char
-Read_hfc8(hfc4s8s_hw *a, u_char b)
-{
- SetRegAddr(a, b);
- return (inb((volatile u_int) a->iobase));
-}
-
-static inline u_char
-fRead_hfc8(hfc4s8s_hw *a)
-{
- return (inb((volatile u_int) a->iobase));
-}
-
-
-static inline u_short
-Read_hfc16(hfc4s8s_hw *a, u_char b)
-{
- SetRegAddr(a, b);
- return (inw((volatile u_int) a->iobase));
-}
-
-static inline u_long
-fRead_hfc32(hfc4s8s_hw *a)
-{
- return (inl((volatile u_int) a->iobase));
-}
-
-static inline void
-wait_busy(hfc4s8s_hw *a)
-{
- SetRegAddr(a, R_STATUS);
- while (inb((volatile u_int) a->iobase) & M_BUSY);
-}
-
-#define PCI_ENA_REGIO 0x01
-
-/******************************************************/
-/* function to read critical counter registers that */
-/* may be updated by the chip during read */
-/******************************************************/
-static u_char
-Read_hfc8_stable(hfc4s8s_hw *hw, int reg)
-{
- u_char ref8;
- u_char in8;
- ref8 = Read_hfc8(hw, reg);
- while (((in8 = Read_hfc8(hw, reg)) != ref8)) {
- ref8 = in8;
- }
- return in8;
-}
-
-static int
-Read_hfc16_stable(hfc4s8s_hw *hw, int reg)
-{
- int ref16;
- int in16;
-
- ref16 = Read_hfc16(hw, reg);
- while (((in16 = Read_hfc16(hw, reg)) != ref16)) {
- ref16 = in16;
- }
- return in16;
-}
-
-/*****************************/
-/* D-channel call from HiSax */
-/*****************************/
-static void
-dch_l2l1(struct hisax_d_if *iface, int pr, void *arg)
-{
- struct hfc4s8s_l1 *l1 = iface->ifc.priv;
- struct sk_buff *skb = (struct sk_buff *) arg;
- u_long flags;
-
- switch (pr) {
-
- case (PH_DATA | REQUEST):
- if (!l1->enabled) {
- dev_kfree_skb(skb);
- break;
- }
- spin_lock_irqsave(&l1->lock, flags);
- skb_queue_tail(&l1->d_tx_queue, skb);
- if ((skb_queue_len(&l1->d_tx_queue) == 1) &&
- (l1->tx_cnt <= 0)) {
- l1->hw->mr.r_irq_fifo_blx[l1->st_num] |=
- 0x10;
- spin_unlock_irqrestore(&l1->lock, flags);
- schedule_work(&l1->hw->tqueue);
- } else
- spin_unlock_irqrestore(&l1->lock, flags);
- break;
-
- case (PH_ACTIVATE | REQUEST):
- if (!l1->enabled)
- break;
- if (!l1->nt_mode) {
- if (l1->l1_state < 6) {
- spin_lock_irqsave(&l1->lock,
- flags);
-
- Write_hfc8(l1->hw, R_ST_SEL,
- l1->st_num);
- Write_hfc8(l1->hw, A_ST_WR_STA,
- 0x60);
- mod_timer(&l1->l1_timer,
- jiffies + L1_TIMER_T3);
- spin_unlock_irqrestore(&l1->lock,
- flags);
- } else if (l1->l1_state == 7)
- l1->d_if.ifc.l1l2(&l1->d_if.ifc,
- PH_ACTIVATE |
- INDICATION,
- NULL);
- } else {
- if (l1->l1_state != 3) {
- spin_lock_irqsave(&l1->lock,
- flags);
- Write_hfc8(l1->hw, R_ST_SEL,
- l1->st_num);
- Write_hfc8(l1->hw, A_ST_WR_STA,
- 0x60);
- spin_unlock_irqrestore(&l1->lock,
- flags);
- } else if (l1->l1_state == 3)
- l1->d_if.ifc.l1l2(&l1->d_if.ifc,
- PH_ACTIVATE |
- INDICATION,
- NULL);
- }
- break;
-
- default:
- printk(KERN_INFO
- "HFC-4S/8S: Unknown D-chan cmd 0x%x received, ignored\n",
- pr);
- break;
- }
- if (!l1->enabled)
- l1->d_if.ifc.l1l2(&l1->d_if.ifc,
- PH_DEACTIVATE | INDICATION, NULL);
-} /* dch_l2l1 */
-
-/*****************************/
-/* B-channel call from HiSax */
-/*****************************/
-static void
-bch_l2l1(struct hisax_if *ifc, int pr, void *arg)
-{
- struct hfc4s8s_btype *bch = ifc->priv;
- struct hfc4s8s_l1 *l1 = bch->l1p;
- struct sk_buff *skb = (struct sk_buff *) arg;
- long mode = (long) arg;
- u_long flags;
-
- switch (pr) {
-
- case (PH_DATA | REQUEST):
- if (!l1->enabled || (bch->mode == L1_MODE_NULL)) {
- dev_kfree_skb(skb);
- break;
- }
- spin_lock_irqsave(&l1->lock, flags);
- skb_queue_tail(&bch->tx_queue, skb);
- if (!bch->tx_skb && (bch->tx_cnt <= 0)) {
- l1->hw->mr.r_irq_fifo_blx[l1->st_num] |=
- ((bch->bchan == 1) ? 1 : 4);
- spin_unlock_irqrestore(&l1->lock, flags);
- schedule_work(&l1->hw->tqueue);
- } else
- spin_unlock_irqrestore(&l1->lock, flags);
- break;
-
- case (PH_ACTIVATE | REQUEST):
- case (PH_DEACTIVATE | REQUEST):
- if (!l1->enabled)
- break;
- if (pr == (PH_DEACTIVATE | REQUEST))
- mode = L1_MODE_NULL;
-
- switch (mode) {
- case L1_MODE_HDLC:
- spin_lock_irqsave(&l1->lock,
- flags);
- l1->hw->mr.timer_usg_cnt++;
- l1->hw->mr.
- fifo_slow_timer_service[l1->
- st_num]
- |=
- ((bch->bchan ==
- 1) ? 0x2 : 0x8);
- Write_hfc8(l1->hw, R_FIFO,
- (l1->st_num * 8 +
- ((bch->bchan ==
- 1) ? 0 : 2)));
- wait_busy(l1->hw);
- Write_hfc8(l1->hw, A_CON_HDLC, 0xc); /* HDLC mode, flag fill, connect ST */
- Write_hfc8(l1->hw, A_SUBCH_CFG, 0); /* 8 bits */
- Write_hfc8(l1->hw, A_IRQ_MSK, 1); /* enable TX interrupts for hdlc */
- Write_hfc8(l1->hw, A_INC_RES_FIFO, 2); /* reset fifo */
- wait_busy(l1->hw);
-
- Write_hfc8(l1->hw, R_FIFO,
- (l1->st_num * 8 +
- ((bch->bchan ==
- 1) ? 1 : 3)));
- wait_busy(l1->hw);
- Write_hfc8(l1->hw, A_CON_HDLC, 0xc); /* HDLC mode, flag fill, connect ST */
- Write_hfc8(l1->hw, A_SUBCH_CFG, 0); /* 8 bits */
- Write_hfc8(l1->hw, A_IRQ_MSK, 1); /* enable RX interrupts for hdlc */
- Write_hfc8(l1->hw, A_INC_RES_FIFO, 2); /* reset fifo */
-
- Write_hfc8(l1->hw, R_ST_SEL,
- l1->st_num);
- l1->hw->mr.r_ctrl0 |=
- (bch->bchan & 3);
- Write_hfc8(l1->hw, A_ST_CTRL0,
- l1->hw->mr.r_ctrl0);
- bch->mode = L1_MODE_HDLC;
- spin_unlock_irqrestore(&l1->lock,
- flags);
-
- bch->b_if.ifc.l1l2(&bch->b_if.ifc,
- PH_ACTIVATE |
- INDICATION,
- NULL);
- break;
-
- case L1_MODE_TRANS:
- spin_lock_irqsave(&l1->lock,
- flags);
- l1->hw->mr.
- fifo_rx_trans_enables[l1->
- st_num]
- |=
- ((bch->bchan ==
- 1) ? 0x2 : 0x8);
- l1->hw->mr.timer_usg_cnt++;
- Write_hfc8(l1->hw, R_FIFO,
- (l1->st_num * 8 +
- ((bch->bchan ==
- 1) ? 0 : 2)));
- wait_busy(l1->hw);
- Write_hfc8(l1->hw, A_CON_HDLC, 0xf); /* Transparent mode, 1 fill, connect ST */
- Write_hfc8(l1->hw, A_SUBCH_CFG, 0); /* 8 bits */
- Write_hfc8(l1->hw, A_IRQ_MSK, 0); /* disable TX interrupts */
- Write_hfc8(l1->hw, A_INC_RES_FIFO, 2); /* reset fifo */
- wait_busy(l1->hw);
-
- Write_hfc8(l1->hw, R_FIFO,
- (l1->st_num * 8 +
- ((bch->bchan ==
- 1) ? 1 : 3)));
- wait_busy(l1->hw);
- Write_hfc8(l1->hw, A_CON_HDLC, 0xf); /* Transparent mode, 1 fill, connect ST */
- Write_hfc8(l1->hw, A_SUBCH_CFG, 0); /* 8 bits */
- Write_hfc8(l1->hw, A_IRQ_MSK, 0); /* disable RX interrupts */
- Write_hfc8(l1->hw, A_INC_RES_FIFO, 2); /* reset fifo */
-
- Write_hfc8(l1->hw, R_ST_SEL,
- l1->st_num);
- l1->hw->mr.r_ctrl0 |=
- (bch->bchan & 3);
- Write_hfc8(l1->hw, A_ST_CTRL0,
- l1->hw->mr.r_ctrl0);
- bch->mode = L1_MODE_TRANS;
- spin_unlock_irqrestore(&l1->lock,
- flags);
-
- bch->b_if.ifc.l1l2(&bch->b_if.ifc,
- PH_ACTIVATE |
- INDICATION,
- NULL);
- break;
-
- default:
- if (bch->mode == L1_MODE_NULL)
- break;
- spin_lock_irqsave(&l1->lock,
- flags);
- l1->hw->mr.
- fifo_slow_timer_service[l1->
- st_num]
- &=
- ~((bch->bchan ==
- 1) ? 0x3 : 0xc);
- l1->hw->mr.
- fifo_rx_trans_enables[l1->
- st_num]
- &=
- ~((bch->bchan ==
- 1) ? 0x3 : 0xc);
- l1->hw->mr.timer_usg_cnt--;
- Write_hfc8(l1->hw, R_FIFO,
- (l1->st_num * 8 +
- ((bch->bchan ==
- 1) ? 0 : 2)));
- wait_busy(l1->hw);
- Write_hfc8(l1->hw, A_IRQ_MSK, 0); /* disable TX interrupts */
- wait_busy(l1->hw);
- Write_hfc8(l1->hw, R_FIFO,
- (l1->st_num * 8 +
- ((bch->bchan ==
- 1) ? 1 : 3)));
- wait_busy(l1->hw);
- Write_hfc8(l1->hw, A_IRQ_MSK, 0); /* disable RX interrupts */
- Write_hfc8(l1->hw, R_ST_SEL,
- l1->st_num);
- l1->hw->mr.r_ctrl0 &=
- ~(bch->bchan & 3);
- Write_hfc8(l1->hw, A_ST_CTRL0,
- l1->hw->mr.r_ctrl0);
- spin_unlock_irqrestore(&l1->lock,
- flags);
-
- bch->mode = L1_MODE_NULL;
- bch->b_if.ifc.l1l2(&bch->b_if.ifc,
- PH_DEACTIVATE |
- INDICATION,
- NULL);
- if (bch->tx_skb) {
- dev_kfree_skb(bch->tx_skb);
- bch->tx_skb = NULL;
- }
- if (bch->rx_skb) {
- dev_kfree_skb(bch->rx_skb);
- bch->rx_skb = NULL;
- }
- skb_queue_purge(&bch->tx_queue);
- bch->tx_cnt = 0;
- bch->rx_ptr = NULL;
- break;
- }
-
- /* timer is only used when at least one b channel */
- /* is set up to transparent mode */
- if (l1->hw->mr.timer_usg_cnt) {
- Write_hfc8(l1->hw, R_IRQMSK_MISC,
- M_TI_IRQMSK);
- } else {
- Write_hfc8(l1->hw, R_IRQMSK_MISC, 0);
- }
-
- break;
-
- default:
- printk(KERN_INFO
- "HFC-4S/8S: Unknown B-chan cmd 0x%x received, ignored\n",
- pr);
- break;
- }
- if (!l1->enabled)
- bch->b_if.ifc.l1l2(&bch->b_if.ifc,
- PH_DEACTIVATE | INDICATION, NULL);
-} /* bch_l2l1 */
-
-/**************************/
-/* layer 1 timer function */
-/**************************/
-static void
-hfc_l1_timer(struct timer_list *t)
-{
- struct hfc4s8s_l1 *l1 = from_timer(l1, t, l1_timer);
- u_long flags;
-
- if (!l1->enabled)
- return;
-
- spin_lock_irqsave(&l1->lock, flags);
- if (l1->nt_mode) {
- l1->l1_state = 1;
- Write_hfc8(l1->hw, R_ST_SEL, l1->st_num);
- Write_hfc8(l1->hw, A_ST_WR_STA, 0x11);
- spin_unlock_irqrestore(&l1->lock, flags);
- l1->d_if.ifc.l1l2(&l1->d_if.ifc,
- PH_DEACTIVATE | INDICATION, NULL);
- spin_lock_irqsave(&l1->lock, flags);
- l1->l1_state = 1;
- Write_hfc8(l1->hw, A_ST_WR_STA, 0x1);
- spin_unlock_irqrestore(&l1->lock, flags);
- } else {
- /* activation timed out */
- Write_hfc8(l1->hw, R_ST_SEL, l1->st_num);
- Write_hfc8(l1->hw, A_ST_WR_STA, 0x13);
- spin_unlock_irqrestore(&l1->lock, flags);
- l1->d_if.ifc.l1l2(&l1->d_if.ifc,
- PH_DEACTIVATE | INDICATION, NULL);
- spin_lock_irqsave(&l1->lock, flags);
- Write_hfc8(l1->hw, R_ST_SEL, l1->st_num);
- Write_hfc8(l1->hw, A_ST_WR_STA, 0x3);
- spin_unlock_irqrestore(&l1->lock, flags);
- }
-} /* hfc_l1_timer */
-
-/****************************************/
-/* a complete D-frame has been received */
-/****************************************/
-static void
-rx_d_frame(struct hfc4s8s_l1 *l1p, int ech)
-{
- int z1, z2;
- u_char f1, f2, df;
- struct sk_buff *skb;
- u_char *cp;
-
-
- if (!l1p->enabled)
- return;
- do {
- /* E/D RX fifo */
- Write_hfc8(l1p->hw, R_FIFO,
- (l1p->st_num * 8 + ((ech) ? 7 : 5)));
- wait_busy(l1p->hw);
-
- f1 = Read_hfc8_stable(l1p->hw, A_F1);
- f2 = Read_hfc8(l1p->hw, A_F2);
-
- if (f1 < f2)
- df = MAX_F_CNT + 1 + f1 - f2;
- else
- df = f1 - f2;
-
- if (!df)
- return; /* no complete frame in fifo */
-
- z1 = Read_hfc16_stable(l1p->hw, A_Z1);
- z2 = Read_hfc16(l1p->hw, A_Z2);
-
- z1 = z1 - z2 + 1;
- if (z1 < 0)
- z1 += 384;
-
- if (!(skb = dev_alloc_skb(MAX_D_FRAME_SIZE))) {
- printk(KERN_INFO
- "HFC-4S/8S: Could not allocate D/E "
- "channel receive buffer");
- Write_hfc8(l1p->hw, A_INC_RES_FIFO, 2);
- wait_busy(l1p->hw);
- return;
- }
-
- if (((z1 < 4) || (z1 > MAX_D_FRAME_SIZE))) {
- if (skb)
- dev_kfree_skb(skb);
- /* remove errornous D frame */
- if (df == 1) {
- /* reset fifo */
- Write_hfc8(l1p->hw, A_INC_RES_FIFO, 2);
- wait_busy(l1p->hw);
- return;
- } else {
- /* read errornous D frame */
- SetRegAddr(l1p->hw, A_FIFO_DATA0);
-
- while (z1 >= 4) {
- fRead_hfc32(l1p->hw);
- z1 -= 4;
- }
-
- while (z1--)
- fRead_hfc8(l1p->hw);
-
- Write_hfc8(l1p->hw, A_INC_RES_FIFO, 1);
- wait_busy(l1p->hw);
- return;
- }
- }
-
- cp = skb->data;
-
- SetRegAddr(l1p->hw, A_FIFO_DATA0);
-
- while (z1 >= 4) {
- *((unsigned long *) cp) = fRead_hfc32(l1p->hw);
- cp += 4;
- z1 -= 4;
- }
-
- while (z1--)
- *cp++ = fRead_hfc8(l1p->hw);
-
- Write_hfc8(l1p->hw, A_INC_RES_FIFO, 1); /* increment f counter */
- wait_busy(l1p->hw);
-
- if (*(--cp)) {
- dev_kfree_skb(skb);
- } else {
- skb->len = (cp - skb->data) - 2;
- if (ech)
- l1p->d_if.ifc.l1l2(&l1p->d_if.ifc,
- PH_DATA_E | INDICATION,
- skb);
- else
- l1p->d_if.ifc.l1l2(&l1p->d_if.ifc,
- PH_DATA | INDICATION,
- skb);
- }
- } while (1);
-} /* rx_d_frame */
-
-/*************************************************************/
-/* a B-frame has been received (perhaps not fully completed) */
-/*************************************************************/
-static void
-rx_b_frame(struct hfc4s8s_btype *bch)
-{
- int z1, z2, hdlc_complete;
- u_char f1, f2;
- struct hfc4s8s_l1 *l1 = bch->l1p;
- struct sk_buff *skb;
-
- if (!l1->enabled || (bch->mode == L1_MODE_NULL))
- return;
-
- do {
- /* RX Fifo */
- Write_hfc8(l1->hw, R_FIFO,
- (l1->st_num * 8 + ((bch->bchan == 1) ? 1 : 3)));
- wait_busy(l1->hw);
-
- if (bch->mode == L1_MODE_HDLC) {
- f1 = Read_hfc8_stable(l1->hw, A_F1);
- f2 = Read_hfc8(l1->hw, A_F2);
- hdlc_complete = ((f1 ^ f2) & MAX_F_CNT);
- } else
- hdlc_complete = 0;
- z1 = Read_hfc16_stable(l1->hw, A_Z1);
- z2 = Read_hfc16(l1->hw, A_Z2);
- z1 = (z1 - z2);
- if (hdlc_complete)
- z1++;
- if (z1 < 0)
- z1 += 384;
-
- if (!z1)
- break;
-
- if (!(skb = bch->rx_skb)) {
- if (!
- (skb =
- dev_alloc_skb((bch->mode ==
- L1_MODE_TRANS) ? z1
- : (MAX_B_FRAME_SIZE + 3)))) {
- printk(KERN_ERR
- "HFC-4S/8S: Could not allocate B "
- "channel receive buffer");
- return;
- }
- bch->rx_ptr = skb->data;
- bch->rx_skb = skb;
- }
-
- skb->len = (bch->rx_ptr - skb->data) + z1;
-
- /* HDLC length check */
- if ((bch->mode == L1_MODE_HDLC) &&
- ((hdlc_complete && (skb->len < 4)) ||
- (skb->len > (MAX_B_FRAME_SIZE + 3)))) {
-
- skb->len = 0;
- bch->rx_ptr = skb->data;
- Write_hfc8(l1->hw, A_INC_RES_FIFO, 2); /* reset fifo */
- wait_busy(l1->hw);
- return;
- }
- SetRegAddr(l1->hw, A_FIFO_DATA0);
-
- while (z1 >= 4) {
- *((unsigned long *) bch->rx_ptr) =
- fRead_hfc32(l1->hw);
- bch->rx_ptr += 4;
- z1 -= 4;
- }
-
- while (z1--)
- *(bch->rx_ptr++) = fRead_hfc8(l1->hw);
-
- if (hdlc_complete) {
- /* increment f counter */
- Write_hfc8(l1->hw, A_INC_RES_FIFO, 1);
- wait_busy(l1->hw);
-
- /* hdlc crc check */
- bch->rx_ptr--;
- if (*bch->rx_ptr) {
- skb->len = 0;
- bch->rx_ptr = skb->data;
- continue;
- }
- skb->len -= 3;
- }
- if (hdlc_complete || (bch->mode == L1_MODE_TRANS)) {
- bch->rx_skb = NULL;
- bch->rx_ptr = NULL;
- bch->b_if.ifc.l1l2(&bch->b_if.ifc,
- PH_DATA | INDICATION, skb);
- }
-
- } while (1);
-} /* rx_b_frame */
-
-/********************************************/
-/* a D-frame has been/should be transmitted */
-/********************************************/
-static void
-tx_d_frame(struct hfc4s8s_l1 *l1p)
-{
- struct sk_buff *skb;
- u_char f1, f2;
- u_char *cp;
- long cnt;
-
- if (l1p->l1_state != 7)
- return;
-
- /* TX fifo */
- Write_hfc8(l1p->hw, R_FIFO, (l1p->st_num * 8 + 4));
- wait_busy(l1p->hw);
-
- f1 = Read_hfc8(l1p->hw, A_F1);
- f2 = Read_hfc8_stable(l1p->hw, A_F2);
-
- if ((f1 ^ f2) & MAX_F_CNT)
- return; /* fifo is still filled */
-
- if (l1p->tx_cnt > 0) {
- cnt = l1p->tx_cnt;
- l1p->tx_cnt = 0;
- l1p->d_if.ifc.l1l2(&l1p->d_if.ifc, PH_DATA | CONFIRM,
- (void *) cnt);
- }
-
- if ((skb = skb_dequeue(&l1p->d_tx_queue))) {
- cp = skb->data;
- cnt = skb->len;
- SetRegAddr(l1p->hw, A_FIFO_DATA0);
-
- while (cnt >= 4) {
- SetRegAddr(l1p->hw, A_FIFO_DATA0);
- fWrite_hfc32(l1p->hw, *(unsigned long *) cp);
- cp += 4;
- cnt -= 4;
- }
-
- while (cnt--)
- fWrite_hfc8(l1p->hw, *cp++);
-
- l1p->tx_cnt = skb->truesize;
- Write_hfc8(l1p->hw, A_INC_RES_FIFO, 1); /* increment f counter */
- wait_busy(l1p->hw);
-
- dev_kfree_skb(skb);
- }
-} /* tx_d_frame */
-
-/******************************************************/
-/* a B-frame may be transmitted (or is not completed) */
-/******************************************************/
-static void
-tx_b_frame(struct hfc4s8s_btype *bch)
-{
- struct sk_buff *skb;
- struct hfc4s8s_l1 *l1 = bch->l1p;
- u_char *cp;
- int cnt, max, hdlc_num;
- long ack_len = 0;
-
- if (!l1->enabled || (bch->mode == L1_MODE_NULL))
- return;
-
- /* TX fifo */
- Write_hfc8(l1->hw, R_FIFO,
- (l1->st_num * 8 + ((bch->bchan == 1) ? 0 : 2)));
- wait_busy(l1->hw);
- do {
-
- if (bch->mode == L1_MODE_HDLC) {
- hdlc_num = Read_hfc8(l1->hw, A_F1) & MAX_F_CNT;
- hdlc_num -=
- (Read_hfc8_stable(l1->hw, A_F2) & MAX_F_CNT);
- if (hdlc_num < 0)
- hdlc_num += 16;
- if (hdlc_num >= 15)
- break; /* fifo still filled up with hdlc frames */
- } else
- hdlc_num = 0;
-
- if (!(skb = bch->tx_skb)) {
- if (!(skb = skb_dequeue(&bch->tx_queue))) {
- l1->hw->mr.fifo_slow_timer_service[l1->
- st_num]
- &= ~((bch->bchan == 1) ? 1 : 4);
- break; /* list empty */
- }
- bch->tx_skb = skb;
- bch->tx_cnt = 0;
- }
-
- if (!hdlc_num)
- l1->hw->mr.fifo_slow_timer_service[l1->st_num] |=
- ((bch->bchan == 1) ? 1 : 4);
- else
- l1->hw->mr.fifo_slow_timer_service[l1->st_num] &=
- ~((bch->bchan == 1) ? 1 : 4);
-
- max = Read_hfc16_stable(l1->hw, A_Z2);
- max -= Read_hfc16(l1->hw, A_Z1);
- if (max <= 0)
- max += 384;
- max--;
-
- if (max < 16)
- break; /* don't write to small amounts of bytes */
-
- cnt = skb->len - bch->tx_cnt;
- if (cnt > max)
- cnt = max;
- cp = skb->data + bch->tx_cnt;
- bch->tx_cnt += cnt;
-
- SetRegAddr(l1->hw, A_FIFO_DATA0);
- while (cnt >= 4) {
- fWrite_hfc32(l1->hw, *(unsigned long *) cp);
- cp += 4;
- cnt -= 4;
- }
-
- while (cnt--)
- fWrite_hfc8(l1->hw, *cp++);
-
- if (bch->tx_cnt >= skb->len) {
- if (bch->mode == L1_MODE_HDLC) {
- /* increment f counter */
- Write_hfc8(l1->hw, A_INC_RES_FIFO, 1);
- }
- ack_len += skb->truesize;
- bch->tx_skb = NULL;
- bch->tx_cnt = 0;
- dev_kfree_skb(skb);
- } else
- /* Re-Select */
- Write_hfc8(l1->hw, R_FIFO,
- (l1->st_num * 8 +
- ((bch->bchan == 1) ? 0 : 2)));
- wait_busy(l1->hw);
- } while (1);
-
- if (ack_len)
- bch->b_if.ifc.l1l2((struct hisax_if *) &bch->b_if,
- PH_DATA | CONFIRM, (void *) ack_len);
-} /* tx_b_frame */
-
-/*************************************/
-/* bottom half handler for interrupt */
-/*************************************/
-static void
-hfc4s8s_bh(struct work_struct *work)
-{
- hfc4s8s_hw *hw = container_of(work, hfc4s8s_hw, tqueue);
- u_char b;
- struct hfc4s8s_l1 *l1p;
- volatile u_char *fifo_stat;
- int idx;
-
- /* handle layer 1 state changes */
- b = 1;
- l1p = hw->l1;
- while (b) {
- if ((b & hw->mr.r_irq_statech)) {
- /* reset l1 event */
- hw->mr.r_irq_statech &= ~b;
- if (l1p->enabled) {
- if (l1p->nt_mode) {
- u_char oldstate = l1p->l1_state;
-
- Write_hfc8(l1p->hw, R_ST_SEL,
- l1p->st_num);
- l1p->l1_state =
- Read_hfc8(l1p->hw,
- A_ST_RD_STA) & 0xf;
-
- if ((oldstate == 3)
- && (l1p->l1_state != 3))
- l1p->d_if.ifc.l1l2(&l1p->
- d_if.
- ifc,
- PH_DEACTIVATE
- |
- INDICATION,
- NULL);
-
- if (l1p->l1_state != 2) {
- del_timer(&l1p->l1_timer);
- if (l1p->l1_state == 3) {
- l1p->d_if.ifc.
- l1l2(&l1p->
- d_if.ifc,
- PH_ACTIVATE
- |
- INDICATION,
- NULL);
- }
- } else {
- /* allow transition */
- Write_hfc8(hw, A_ST_WR_STA,
- M_SET_G2_G3);
- mod_timer(&l1p->l1_timer,
- jiffies +
- L1_TIMER_T1);
- }
- printk(KERN_INFO
- "HFC-4S/8S: NT ch %d l1 state %d -> %d\n",
- l1p->st_num, oldstate,
- l1p->l1_state);
- } else {
- u_char oldstate = l1p->l1_state;
-
- Write_hfc8(l1p->hw, R_ST_SEL,
- l1p->st_num);
- l1p->l1_state =
- Read_hfc8(l1p->hw,
- A_ST_RD_STA) & 0xf;
-
- if (((l1p->l1_state == 3) &&
- ((oldstate == 7) ||
- (oldstate == 8))) ||
- ((timer_pending
- (&l1p->l1_timer))
- && (l1p->l1_state == 8))) {
- mod_timer(&l1p->l1_timer,
- L1_TIMER_T4 +
- jiffies);
- } else {
- if (l1p->l1_state == 7) {
- del_timer(&l1p->
- l1_timer);
- l1p->d_if.ifc.
- l1l2(&l1p->
- d_if.ifc,
- PH_ACTIVATE
- |
- INDICATION,
- NULL);
- tx_d_frame(l1p);
- }
- if (l1p->l1_state == 3) {
- if (oldstate != 3)
- l1p->d_if.
- ifc.
- l1l2
- (&l1p->
- d_if.
- ifc,
- PH_DEACTIVATE
- |
- INDICATION,
- NULL);
- }
- }
- printk(KERN_INFO
- "HFC-4S/8S: TE %d ch %d l1 state %d -> %d\n",
- l1p->hw->cardnum,
- l1p->st_num, oldstate,
- l1p->l1_state);
- }
- }
- }
- b <<= 1;
- l1p++;
- }
-
- /* now handle the fifos */
- idx = 0;
- fifo_stat = hw->mr.r_irq_fifo_blx;
- l1p = hw->l1;
- while (idx < hw->driver_data.max_st_ports) {
-
- if (hw->mr.timer_irq) {
- *fifo_stat |= hw->mr.fifo_rx_trans_enables[idx];
- if (hw->fifo_sched_cnt <= 0) {
- *fifo_stat |=
- hw->mr.fifo_slow_timer_service[l1p->
- st_num];
- }
- }
- /* ignore fifo 6 (TX E fifo) */
- *fifo_stat &= 0xff - 0x40;
-
- while (*fifo_stat) {
-
- if (!l1p->nt_mode) {
- /* RX Fifo has data to read */
- if ((*fifo_stat & 0x20)) {
- *fifo_stat &= ~0x20;
- rx_d_frame(l1p, 0);
- }
- /* E Fifo has data to read */
- if ((*fifo_stat & 0x80)) {
- *fifo_stat &= ~0x80;
- rx_d_frame(l1p, 1);
- }
- /* TX Fifo completed send */
- if ((*fifo_stat & 0x10)) {
- *fifo_stat &= ~0x10;
- tx_d_frame(l1p);
- }
- }
- /* B1 RX Fifo has data to read */
- if ((*fifo_stat & 0x2)) {
- *fifo_stat &= ~0x2;
- rx_b_frame(l1p->b_ch);
- }
- /* B1 TX Fifo has send completed */
- if ((*fifo_stat & 0x1)) {
- *fifo_stat &= ~0x1;
- tx_b_frame(l1p->b_ch);
- }
- /* B2 RX Fifo has data to read */
- if ((*fifo_stat & 0x8)) {
- *fifo_stat &= ~0x8;
- rx_b_frame(l1p->b_ch + 1);
- }
- /* B2 TX Fifo has send completed */
- if ((*fifo_stat & 0x4)) {
- *fifo_stat &= ~0x4;
- tx_b_frame(l1p->b_ch + 1);
- }
- }
- fifo_stat++;
- l1p++;
- idx++;
- }
-
- if (hw->fifo_sched_cnt <= 0)
- hw->fifo_sched_cnt += (1 << (7 - TRANS_TIMER_MODE));
- hw->mr.timer_irq = 0; /* clear requested timer irq */
-} /* hfc4s8s_bh */
-
-/*********************/
-/* interrupt handler */
-/*********************/
-static irqreturn_t
-hfc4s8s_interrupt(int intno, void *dev_id)
-{
- hfc4s8s_hw *hw = dev_id;
- u_char b, ovr;
- volatile u_char *ovp;
- int idx;
- u_char old_ioreg;
-
- if (!hw || !(hw->mr.r_irq_ctrl & M_GLOB_IRQ_EN))
- return IRQ_NONE;
-
- /* read current selected regsister */
- old_ioreg = GetRegAddr(hw);
-
- /* Layer 1 State change */
- hw->mr.r_irq_statech |=
- (Read_hfc8(hw, R_SCI) & hw->mr.r_irqmsk_statchg);
- if (!
- (b = (Read_hfc8(hw, R_STATUS) & (M_MISC_IRQSTA | M_FR_IRQSTA)))
- && !hw->mr.r_irq_statech) {
- SetRegAddr(hw, old_ioreg);
- return IRQ_NONE;
- }
-
- /* timer event */
- if (Read_hfc8(hw, R_IRQ_MISC) & M_TI_IRQ) {
- hw->mr.timer_irq = 1;
- hw->fifo_sched_cnt--;
- }
-
- /* FIFO event */
- if ((ovr = Read_hfc8(hw, R_IRQ_OVIEW))) {
- hw->mr.r_irq_oview |= ovr;
- idx = R_IRQ_FIFO_BL0;
- ovp = hw->mr.r_irq_fifo_blx;
- while (ovr) {
- if ((ovr & 1)) {
- *ovp |= Read_hfc8(hw, idx);
- }
- ovp++;
- idx++;
- ovr >>= 1;
- }
- }
-
- /* queue the request to allow other cards to interrupt */
- schedule_work(&hw->tqueue);
-
- SetRegAddr(hw, old_ioreg);
- return IRQ_HANDLED;
-} /* hfc4s8s_interrupt */
-
-/***********************************************************************/
-/* reset the complete chip, don't release the chips irq but disable it */
-/***********************************************************************/
-static void
-chipreset(hfc4s8s_hw *hw)
-{
- u_long flags;
-
- spin_lock_irqsave(&hw->lock, flags);
- Write_hfc8(hw, R_CTRL, 0); /* use internal RAM */
- Write_hfc8(hw, R_RAM_MISC, 0); /* 32k*8 RAM */
- Write_hfc8(hw, R_FIFO_MD, 0); /* fifo mode 386 byte/fifo simple mode */
- Write_hfc8(hw, R_CIRM, M_SRES); /* reset chip */
- hw->mr.r_irq_ctrl = 0; /* interrupt is inactive */
- spin_unlock_irqrestore(&hw->lock, flags);
-
- udelay(3);
- Write_hfc8(hw, R_CIRM, 0); /* disable reset */
- wait_busy(hw);
-
- Write_hfc8(hw, R_PCM_MD0, M_PCM_MD); /* master mode */
- Write_hfc8(hw, R_RAM_MISC, M_FZ_MD); /* transmit fifo option */
- if (hw->driver_data.clock_mode == 1)
- Write_hfc8(hw, R_BRG_PCM_CFG, M_PCM_CLK); /* PCM clk / 2 */
- Write_hfc8(hw, R_TI_WD, TRANS_TIMER_MODE); /* timer interval */
-
- memset(&hw->mr, 0, sizeof(hw->mr));
-} /* chipreset */
-
-/********************************************/
-/* disable/enable hardware in nt or te mode */
-/********************************************/
-static void
-hfc_hardware_enable(hfc4s8s_hw *hw, int enable, int nt_mode)
-{
- u_long flags;
- char if_name[40];
- int i;
-
- if (enable) {
- /* save system vars */
- hw->nt_mode = nt_mode;
-
- /* enable fifo and state irqs, but not global irq enable */
- hw->mr.r_irq_ctrl = M_FIFO_IRQ;
- Write_hfc8(hw, R_IRQ_CTRL, hw->mr.r_irq_ctrl);
- hw->mr.r_irqmsk_statchg = 0;
- Write_hfc8(hw, R_SCI_MSK, hw->mr.r_irqmsk_statchg);
- Write_hfc8(hw, R_PWM_MD, 0x80);
- Write_hfc8(hw, R_PWM1, 26);
- if (!nt_mode)
- Write_hfc8(hw, R_ST_SYNC, M_AUTO_SYNC);
-
- /* enable the line interfaces and fifos */
- for (i = 0; i < hw->driver_data.max_st_ports; i++) {
- hw->mr.r_irqmsk_statchg |= (1 << i);
- Write_hfc8(hw, R_SCI_MSK, hw->mr.r_irqmsk_statchg);
- Write_hfc8(hw, R_ST_SEL, i);
- Write_hfc8(hw, A_ST_CLK_DLY,
- ((nt_mode) ? CLKDEL_NT : CLKDEL_TE));
- hw->mr.r_ctrl0 = ((nt_mode) ? CTRL0_NT : CTRL0_TE);
- Write_hfc8(hw, A_ST_CTRL0, hw->mr.r_ctrl0);
- Write_hfc8(hw, A_ST_CTRL2, 3);
- Write_hfc8(hw, A_ST_WR_STA, 0); /* enable state machine */
-
- hw->l1[i].enabled = 1;
- hw->l1[i].nt_mode = nt_mode;
-
- if (!nt_mode) {
- /* setup E-fifo */
- Write_hfc8(hw, R_FIFO, i * 8 + 7); /* E fifo */
- wait_busy(hw);
- Write_hfc8(hw, A_CON_HDLC, 0x11); /* HDLC mode, 1 fill, connect ST */
- Write_hfc8(hw, A_SUBCH_CFG, 2); /* only 2 bits */
- Write_hfc8(hw, A_IRQ_MSK, 1); /* enable interrupt */
- Write_hfc8(hw, A_INC_RES_FIFO, 2); /* reset fifo */
- wait_busy(hw);
-
- /* setup D RX-fifo */
- Write_hfc8(hw, R_FIFO, i * 8 + 5); /* RX fifo */
- wait_busy(hw);
- Write_hfc8(hw, A_CON_HDLC, 0x11); /* HDLC mode, 1 fill, connect ST */
- Write_hfc8(hw, A_SUBCH_CFG, 2); /* only 2 bits */
- Write_hfc8(hw, A_IRQ_MSK, 1); /* enable interrupt */
- Write_hfc8(hw, A_INC_RES_FIFO, 2); /* reset fifo */
- wait_busy(hw);
-
- /* setup D TX-fifo */
- Write_hfc8(hw, R_FIFO, i * 8 + 4); /* TX fifo */
- wait_busy(hw);
- Write_hfc8(hw, A_CON_HDLC, 0x11); /* HDLC mode, 1 fill, connect ST */
- Write_hfc8(hw, A_SUBCH_CFG, 2); /* only 2 bits */
- Write_hfc8(hw, A_IRQ_MSK, 1); /* enable interrupt */
- Write_hfc8(hw, A_INC_RES_FIFO, 2); /* reset fifo */
- wait_busy(hw);
- }
-
- sprintf(if_name, "hfc4s8s_%d%d_", hw->cardnum, i);
-
- if (hisax_register
- (&hw->l1[i].d_if, hw->l1[i].b_table, if_name,
- ((nt_mode) ? 3 : 2))) {
-
- hw->l1[i].enabled = 0;
- hw->mr.r_irqmsk_statchg &= ~(1 << i);
- Write_hfc8(hw, R_SCI_MSK,
- hw->mr.r_irqmsk_statchg);
- printk(KERN_INFO
- "HFC-4S/8S: Unable to register S/T device %s, break\n",
- if_name);
- break;
- }
- }
- spin_lock_irqsave(&hw->lock, flags);
- hw->mr.r_irq_ctrl |= M_GLOB_IRQ_EN;
- Write_hfc8(hw, R_IRQ_CTRL, hw->mr.r_irq_ctrl);
- spin_unlock_irqrestore(&hw->lock, flags);
- } else {
- /* disable hardware */
- spin_lock_irqsave(&hw->lock, flags);
- hw->mr.r_irq_ctrl &= ~M_GLOB_IRQ_EN;
- Write_hfc8(hw, R_IRQ_CTRL, hw->mr.r_irq_ctrl);
- spin_unlock_irqrestore(&hw->lock, flags);
-
- for (i = hw->driver_data.max_st_ports - 1; i >= 0; i--) {
- hw->l1[i].enabled = 0;
- hisax_unregister(&hw->l1[i].d_if);
- del_timer(&hw->l1[i].l1_timer);
- skb_queue_purge(&hw->l1[i].d_tx_queue);
- skb_queue_purge(&hw->l1[i].b_ch[0].tx_queue);
- skb_queue_purge(&hw->l1[i].b_ch[1].tx_queue);
- }
- chipreset(hw);
- }
-} /* hfc_hardware_enable */
-
-/******************************************/
-/* disable memory mapped ports / io ports */
-/******************************************/
-static void
-release_pci_ports(hfc4s8s_hw *hw)
-{
- pci_write_config_word(hw->pdev, PCI_COMMAND, 0);
- if (hw->iobase)
- release_region(hw->iobase, 8);
-}
-
-/*****************************************/
-/* enable memory mapped ports / io ports */
-/*****************************************/
-static void
-enable_pci_ports(hfc4s8s_hw *hw)
-{
- pci_write_config_word(hw->pdev, PCI_COMMAND, PCI_ENA_REGIO);
-}
-
-/*************************************/
-/* initialise the HFC-4s/8s hardware */
-/* return 0 on success. */
-/*************************************/
-static int
-setup_instance(hfc4s8s_hw *hw)
-{
- int err = -EIO;
- int i;
-
- for (i = 0; i < HFC_MAX_ST; i++) {
- struct hfc4s8s_l1 *l1p;
-
- l1p = hw->l1 + i;
- spin_lock_init(&l1p->lock);
- l1p->hw = hw;
- timer_setup(&l1p->l1_timer, hfc_l1_timer, 0);
- l1p->st_num = i;
- skb_queue_head_init(&l1p->d_tx_queue);
- l1p->d_if.ifc.priv = hw->l1 + i;
- l1p->d_if.ifc.l2l1 = (void *) dch_l2l1;
-
- spin_lock_init(&l1p->b_ch[0].lock);
- l1p->b_ch[0].b_if.ifc.l2l1 = (void *) bch_l2l1;
- l1p->b_ch[0].b_if.ifc.priv = (void *) &l1p->b_ch[0];
- l1p->b_ch[0].l1p = hw->l1 + i;
- l1p->b_ch[0].bchan = 1;
- l1p->b_table[0] = &l1p->b_ch[0].b_if;
- skb_queue_head_init(&l1p->b_ch[0].tx_queue);
-
- spin_lock_init(&l1p->b_ch[1].lock);
- l1p->b_ch[1].b_if.ifc.l2l1 = (void *) bch_l2l1;
- l1p->b_ch[1].b_if.ifc.priv = (void *) &l1p->b_ch[1];
- l1p->b_ch[1].l1p = hw->l1 + i;
- l1p->b_ch[1].bchan = 2;
- l1p->b_table[1] = &l1p->b_ch[1].b_if;
- skb_queue_head_init(&l1p->b_ch[1].tx_queue);
- }
-
- enable_pci_ports(hw);
- chipreset(hw);
-
- i = Read_hfc8(hw, R_CHIP_ID) >> CHIP_ID_SHIFT;
- if (i != hw->driver_data.chip_id) {
- printk(KERN_INFO
- "HFC-4S/8S: invalid chip id 0x%x instead of 0x%x, card ignored\n",
- i, hw->driver_data.chip_id);
- goto out;
- }
-
- i = Read_hfc8(hw, R_CHIP_RV) & 0xf;
- if (!i) {
- printk(KERN_INFO
- "HFC-4S/8S: chip revision 0 not supported, card ignored\n");
- goto out;
- }
-
- INIT_WORK(&hw->tqueue, hfc4s8s_bh);
-
- if (request_irq
- (hw->irq, hfc4s8s_interrupt, IRQF_SHARED, hw->card_name, hw)) {
- printk(KERN_INFO
- "HFC-4S/8S: unable to alloc irq %d, card ignored\n",
- hw->irq);
- goto out;
- }
- printk(KERN_INFO
- "HFC-4S/8S: found PCI card at iobase 0x%x, irq %d\n",
- hw->iobase, hw->irq);
-
- hfc_hardware_enable(hw, 1, 0);
-
- return (0);
-
-out:
- hw->irq = 0;
- release_pci_ports(hw);
- kfree(hw);
- return (err);
-}
-
-/*****************************************/
-/* PCI hotplug interface: probe new card */
-/*****************************************/
-static int
-hfc4s8s_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- int err = -ENOMEM;
- hfc4s8s_param *driver_data = (hfc4s8s_param *) ent->driver_data;
- hfc4s8s_hw *hw;
-
- if (!(hw = kzalloc(sizeof(hfc4s8s_hw), GFP_ATOMIC))) {
- printk(KERN_ERR "No kmem for HFC-4S/8S card\n");
- return (err);
- }
-
- hw->pdev = pdev;
- err = pci_enable_device(pdev);
-
- if (err)
- goto out;
-
- hw->cardnum = card_cnt;
- sprintf(hw->card_name, "hfc4s8s_%d", hw->cardnum);
- printk(KERN_INFO "HFC-4S/8S: found adapter %s (%s) at %s\n",
- driver_data->device_name, hw->card_name, pci_name(pdev));
-
- spin_lock_init(&hw->lock);
-
- hw->driver_data = *driver_data;
- hw->irq = pdev->irq;
- hw->iobase = pci_resource_start(pdev, 0);
-
- if (!request_region(hw->iobase, 8, hw->card_name)) {
- printk(KERN_INFO
- "HFC-4S/8S: failed to request address space at 0x%04x\n",
- hw->iobase);
- err = -EBUSY;
- goto out;
- }
-
- pci_set_drvdata(pdev, hw);
- err = setup_instance(hw);
- if (!err)
- card_cnt++;
- return (err);
-
-out:
- kfree(hw);
- return (err);
-}
-
-/**************************************/
-/* PCI hotplug interface: remove card */
-/**************************************/
-static void
-hfc4s8s_remove(struct pci_dev *pdev)
-{
- hfc4s8s_hw *hw = pci_get_drvdata(pdev);
-
- printk(KERN_INFO "HFC-4S/8S: removing card %d\n", hw->cardnum);
- hfc_hardware_enable(hw, 0, 0);
-
- if (hw->irq)
- free_irq(hw->irq, hw);
- hw->irq = 0;
- release_pci_ports(hw);
-
- card_cnt--;
- pci_disable_device(pdev);
- kfree(hw);
- return;
-}
-
-static struct pci_driver hfc4s8s_driver = {
- .name = "hfc4s8s_l1",
- .probe = hfc4s8s_probe,
- .remove = hfc4s8s_remove,
- .id_table = hfc4s8s_ids,
-};
-
-/**********************/
-/* driver Module init */
-/**********************/
-static int __init
-hfc4s8s_module_init(void)
-{
- int err;
-
- printk(KERN_INFO
- "HFC-4S/8S: Layer 1 driver module for HFC-4S/8S isdn chips, %s\n",
- hfc4s8s_rev);
- printk(KERN_INFO
- "HFC-4S/8S: (C) 2003 Cornelius Consult, www.cornelius-consult.de\n");
-
- card_cnt = 0;
-
- err = pci_register_driver(&hfc4s8s_driver);
- if (err < 0) {
- goto out;
- }
- printk(KERN_INFO "HFC-4S/8S: found %d cards\n", card_cnt);
-
- return 0;
-out:
- return (err);
-} /* hfc4s8s_init_hw */
-
-/*************************************/
-/* driver module exit : */
-/* release the HFC-4s/8s hardware */
-/*************************************/
-static void __exit
-hfc4s8s_module_exit(void)
-{
- pci_unregister_driver(&hfc4s8s_driver);
- printk(KERN_INFO "HFC-4S/8S: module removed\n");
-} /* hfc4s8s_release_hw */
-
-module_init(hfc4s8s_module_init);
-module_exit(hfc4s8s_module_exit);
diff --git a/drivers/isdn/hisax/hfc4s8s_l1.h b/drivers/isdn/hisax/hfc4s8s_l1.h
deleted file mode 100644
index 4665b9d5df16..000000000000
--- a/drivers/isdn/hisax/hfc4s8s_l1.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/***************************************************************/
-/* $Id: hfc4s8s_l1.h,v 1.1 2005/02/02 17:28:55 martinb1 Exp $ */
-/* */
-/* This file is a minimal required extraction of hfc48scu.h */
-/* (Genero 3.2, HFC XML 1.7a for HFC-E1, HFC-4S and HFC-8S) */
-/* */
-/* To get this complete register description contact */
-/* Cologne Chip AG : */
-/* Internet: http://www.colognechip.com/ */
-/* E-Mail: info@colognechip.com */
-/***************************************************************/
-
-#ifndef _HFC4S8S_L1_H_
-#define _HFC4S8S_L1_H_
-
-
-/*
- * include Genero generated HFC-4S/8S header file hfc48scu.h
- * for complete register description. This will define _HFC48SCU_H_
- * to prevent redefinitions
- */
-
-// #include "hfc48scu.h"
-
-#ifndef _HFC48SCU_H_
-#define _HFC48SCU_H_
-
-#ifndef PCI_VENDOR_ID_CCD
-#define PCI_VENDOR_ID_CCD 0x1397
-#endif
-
-#define CHIP_ID_4S 0x0C
-#define CHIP_ID_8S 0x08
-#define PCI_DEVICE_ID_4S 0x08B4
-#define PCI_DEVICE_ID_8S 0x16B8
-
-#define R_IRQ_MISC 0x11
-#define M_TI_IRQ 0x02
-#define A_ST_RD_STA 0x30
-#define A_ST_WR_STA 0x30
-#define M_SET_G2_G3 0x80
-#define A_ST_CTRL0 0x31
-#define A_ST_CTRL2 0x33
-#define A_ST_CLK_DLY 0x37
-#define A_Z1 0x04
-#define A_Z2 0x06
-#define R_CIRM 0x00
-#define M_SRES 0x08
-#define R_CTRL 0x01
-#define R_BRG_PCM_CFG 0x02
-#define M_PCM_CLK 0x20
-#define R_RAM_MISC 0x0C
-#define M_FZ_MD 0x80
-#define R_FIFO_MD 0x0D
-#define A_INC_RES_FIFO 0x0E
-#define R_FIFO 0x0F
-#define A_F1 0x0C
-#define A_F2 0x0D
-#define R_IRQ_OVIEW 0x10
-#define R_CHIP_ID 0x16
-#define R_STATUS 0x1C
-#define M_BUSY 0x01
-#define M_MISC_IRQSTA 0x40
-#define M_FR_IRQSTA 0x80
-#define R_CHIP_RV 0x1F
-#define R_IRQ_CTRL 0x13
-#define M_FIFO_IRQ 0x01
-#define M_GLOB_IRQ_EN 0x08
-#define R_PCM_MD0 0x14
-#define M_PCM_MD 0x01
-#define A_FIFO_DATA0 0x80
-#define R_TI_WD 0x1A
-#define R_PWM1 0x39
-#define R_PWM_MD 0x46
-#define R_IRQ_FIFO_BL0 0xC8
-#define A_CON_HDLC 0xFA
-#define A_SUBCH_CFG 0xFB
-#define A_IRQ_MSK 0xFF
-#define R_SCI_MSK 0x12
-#define R_ST_SEL 0x16
-#define R_ST_SYNC 0x17
-#define M_AUTO_SYNC 0x08
-#define R_SCI 0x12
-#define R_IRQMSK_MISC 0x11
-#define M_TI_IRQMSK 0x02
-
-#endif /* _HFC4S8S_L1_H_ */
-#endif /* _HFC48SCU_H_ */
diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c
deleted file mode 100644
index 3715fa0343db..000000000000
--- a/drivers/isdn/hisax/hfc_2bds0.c
+++ /dev/null
@@ -1,1078 +0,0 @@
-/* $Id: hfc_2bds0.c,v 1.18.2.6 2004/02/11 13:21:33 keil Exp $
- *
- * specific routines for CCD's HFC 2BDS0
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include "hisax.h"
-#include "hfc_2bds0.h"
-#include "isdnl1.h"
-#include <linux/interrupt.h>
-/*
- #define KDEBUG_DEF
- #include "kdebug.h"
-*/
-
-#define byteout(addr, val) outb(val, addr)
-#define bytein(addr) inb(addr)
-
-static void
-dummyf(struct IsdnCardState *cs, u_char *data, int size)
-{
- printk(KERN_WARNING "HiSax: hfcd dummy fifo called\n");
-}
-
-static inline u_char
-ReadReg(struct IsdnCardState *cs, int data, u_char reg)
-{
- register u_char ret;
-
- if (data) {
- if (cs->hw.hfcD.cip != reg) {
- cs->hw.hfcD.cip = reg;
- byteout(cs->hw.hfcD.addr | 1, reg);
- }
- ret = bytein(cs->hw.hfcD.addr);
-#ifdef HFC_REG_DEBUG
- if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2))
- debugl1(cs, "t3c RD %02x %02x", reg, ret);
-#endif
- } else
- ret = bytein(cs->hw.hfcD.addr | 1);
- return (ret);
-}
-
-static inline void
-WriteReg(struct IsdnCardState *cs, int data, u_char reg, u_char value)
-{
- if (cs->hw.hfcD.cip != reg) {
- cs->hw.hfcD.cip = reg;
- byteout(cs->hw.hfcD.addr | 1, reg);
- }
- if (data)
- byteout(cs->hw.hfcD.addr, value);
-#ifdef HFC_REG_DEBUG
- if (cs->debug & L1_DEB_HSCX_FIFO && (data != HFCD_DATA_NODEB))
- debugl1(cs, "t3c W%c %02x %02x", data ? 'D' : 'C', reg, value);
-#endif
-}
-
-/* Interface functions */
-
-static u_char
-readreghfcd(struct IsdnCardState *cs, u_char offset)
-{
- return (ReadReg(cs, HFCD_DATA, offset));
-}
-
-static void
-writereghfcd(struct IsdnCardState *cs, u_char offset, u_char value)
-{
- WriteReg(cs, HFCD_DATA, offset, value);
-}
-
-static inline int
-WaitForBusy(struct IsdnCardState *cs)
-{
- int to = 130;
-
- while (!(ReadReg(cs, HFCD_DATA, HFCD_STAT) & HFCD_BUSY) && to) {
- udelay(1);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "HiSax: WaitForBusy timeout\n");
- return (to);
-}
-
-static inline int
-WaitNoBusy(struct IsdnCardState *cs)
-{
- int to = 130;
-
- while ((ReadReg(cs, HFCD_STATUS, HFCD_STATUS) & HFCD_BUSY) && to) {
- udelay(1);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "HiSax: WaitNoBusy timeout\n");
- return (to);
-}
-
-static int
-SelFiFo(struct IsdnCardState *cs, u_char FiFo)
-{
- u_char cip;
-
- if (cs->hw.hfcD.fifo == FiFo)
- return (1);
- switch (FiFo) {
- case 0: cip = HFCB_FIFO | HFCB_Z1 | HFCB_SEND | HFCB_B1;
- break;
- case 1: cip = HFCB_FIFO | HFCB_Z1 | HFCB_REC | HFCB_B1;
- break;
- case 2: cip = HFCB_FIFO | HFCB_Z1 | HFCB_SEND | HFCB_B2;
- break;
- case 3: cip = HFCB_FIFO | HFCB_Z1 | HFCB_REC | HFCB_B2;
- break;
- case 4: cip = HFCD_FIFO | HFCD_Z1 | HFCD_SEND;
- break;
- case 5: cip = HFCD_FIFO | HFCD_Z1 | HFCD_REC;
- break;
- default:
- debugl1(cs, "SelFiFo Error");
- return (0);
- }
- cs->hw.hfcD.fifo = FiFo;
- WaitNoBusy(cs);
- cs->BC_Write_Reg(cs, HFCD_DATA, cip, 0);
- WaitForBusy(cs);
- return (2);
-}
-
-static int
-GetFreeFifoBytes_B(struct BCState *bcs)
-{
- int s;
-
- if (bcs->hw.hfc.f1 == bcs->hw.hfc.f2)
- return (bcs->cs->hw.hfcD.bfifosize);
- s = bcs->hw.hfc.send[bcs->hw.hfc.f1] - bcs->hw.hfc.send[bcs->hw.hfc.f2];
- if (s <= 0)
- s += bcs->cs->hw.hfcD.bfifosize;
- s = bcs->cs->hw.hfcD.bfifosize - s;
- return (s);
-}
-
-static int
-GetFreeFifoBytes_D(struct IsdnCardState *cs)
-{
- int s;
-
- if (cs->hw.hfcD.f1 == cs->hw.hfcD.f2)
- return (cs->hw.hfcD.dfifosize);
- s = cs->hw.hfcD.send[cs->hw.hfcD.f1] - cs->hw.hfcD.send[cs->hw.hfcD.f2];
- if (s <= 0)
- s += cs->hw.hfcD.dfifosize;
- s = cs->hw.hfcD.dfifosize - s;
- return (s);
-}
-
-static int
-ReadZReg(struct IsdnCardState *cs, u_char reg)
-{
- int val;
-
- WaitNoBusy(cs);
- val = 256 * ReadReg(cs, HFCD_DATA, reg | HFCB_Z_HIGH);
- WaitNoBusy(cs);
- val += ReadReg(cs, HFCD_DATA, reg | HFCB_Z_LOW);
- return (val);
-}
-
-static struct sk_buff
-*hfc_empty_fifo(struct BCState *bcs, int count)
-{
- u_char *ptr;
- struct sk_buff *skb;
- struct IsdnCardState *cs = bcs->cs;
- int idx;
- int chksum;
- u_char stat, cip;
-
- if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
- debugl1(cs, "hfc_empty_fifo");
- idx = 0;
- if (count > HSCX_BUFMAX + 3) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "hfc_empty_fifo: incoming packet too large");
- cip = HFCB_FIFO | HFCB_FIFO_OUT | HFCB_REC | HFCB_CHANNEL(bcs->channel);
- while (idx++ < count) {
- WaitNoBusy(cs);
- ReadReg(cs, HFCD_DATA_NODEB, cip);
- }
- skb = NULL;
- } else if (count < 4) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "hfc_empty_fifo: incoming packet too small");
- cip = HFCB_FIFO | HFCB_FIFO_OUT | HFCB_REC | HFCB_CHANNEL(bcs->channel);
-#ifdef ERROR_STATISTIC
- bcs->err_inv++;
-#endif
- while ((idx++ < count) && WaitNoBusy(cs))
- ReadReg(cs, HFCD_DATA_NODEB, cip);
- skb = NULL;
- } else if (!(skb = dev_alloc_skb(count - 3)))
- printk(KERN_WARNING "HFC: receive out of memory\n");
- else {
- ptr = skb_put(skb, count - 3);
- idx = 0;
- cip = HFCB_FIFO | HFCB_FIFO_OUT | HFCB_REC | HFCB_CHANNEL(bcs->channel);
- while (idx < (count - 3)) {
- if (!WaitNoBusy(cs))
- break;
- *ptr = ReadReg(cs, HFCD_DATA_NODEB, cip);
- ptr++;
- idx++;
- }
- if (idx != count - 3) {
- debugl1(cs, "RFIFO BUSY error");
- printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel);
- dev_kfree_skb_irq(skb);
- skb = NULL;
- } else {
- WaitNoBusy(cs);
- chksum = (ReadReg(cs, HFCD_DATA, cip) << 8);
- WaitNoBusy(cs);
- chksum += ReadReg(cs, HFCD_DATA, cip);
- WaitNoBusy(cs);
- stat = ReadReg(cs, HFCD_DATA, cip);
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc_empty_fifo %d chksum %x stat %x",
- bcs->channel, chksum, stat);
- if (stat) {
- debugl1(cs, "FIFO CRC error");
- dev_kfree_skb_irq(skb);
- skb = NULL;
-#ifdef ERROR_STATISTIC
- bcs->err_crc++;
-#endif
- }
- }
- }
- WaitForBusy(cs);
- WaitNoBusy(cs);
- stat = ReadReg(cs, HFCD_DATA, HFCB_FIFO | HFCB_F2_INC |
- HFCB_REC | HFCB_CHANNEL(bcs->channel));
- WaitForBusy(cs);
- return (skb);
-}
-
-static void
-hfc_fill_fifo(struct BCState *bcs)
-{
- struct IsdnCardState *cs = bcs->cs;
- int idx, fcnt;
- int count;
- u_char cip;
-
- if (!bcs->tx_skb)
- return;
- if (bcs->tx_skb->len <= 0)
- return;
- SelFiFo(cs, HFCB_SEND | HFCB_CHANNEL(bcs->channel));
- cip = HFCB_FIFO | HFCB_F1 | HFCB_SEND | HFCB_CHANNEL(bcs->channel);
- WaitNoBusy(cs);
- bcs->hw.hfc.f1 = ReadReg(cs, HFCD_DATA, cip);
- WaitNoBusy(cs);
- cip = HFCB_FIFO | HFCB_F2 | HFCB_SEND | HFCB_CHANNEL(bcs->channel);
- WaitNoBusy(cs);
- bcs->hw.hfc.f2 = ReadReg(cs, HFCD_DATA, cip);
- bcs->hw.hfc.send[bcs->hw.hfc.f1] = ReadZReg(cs, HFCB_FIFO | HFCB_Z1 | HFCB_SEND | HFCB_CHANNEL(bcs->channel));
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)",
- bcs->channel, bcs->hw.hfc.f1, bcs->hw.hfc.f2,
- bcs->hw.hfc.send[bcs->hw.hfc.f1]);
- fcnt = bcs->hw.hfc.f1 - bcs->hw.hfc.f2;
- if (fcnt < 0)
- fcnt += 32;
- if (fcnt > 30) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc_fill_fifo more as 30 frames");
- return;
- }
- count = GetFreeFifoBytes_B(bcs);
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc_fill_fifo %d count(%u/%d),%lx",
- bcs->channel, bcs->tx_skb->len,
- count, current->state);
- if (count < bcs->tx_skb->len) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc_fill_fifo no fifo mem");
- return;
- }
- cip = HFCB_FIFO | HFCB_FIFO_IN | HFCB_SEND | HFCB_CHANNEL(bcs->channel);
- idx = 0;
- WaitForBusy(cs);
- WaitNoBusy(cs);
- WriteReg(cs, HFCD_DATA_NODEB, cip, bcs->tx_skb->data[idx++]);
- while (idx < bcs->tx_skb->len) {
- if (!WaitNoBusy(cs))
- break;
- WriteReg(cs, HFCD_DATA_NODEB, cip, bcs->tx_skb->data[idx]);
- idx++;
- }
- if (idx != bcs->tx_skb->len) {
- debugl1(cs, "FIFO Send BUSY error");
- printk(KERN_WARNING "HFC S FIFO channel %d BUSY Error\n", bcs->channel);
- } else {
- bcs->tx_cnt -= bcs->tx_skb->len;
- if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
- (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
- u_long flags;
- spin_lock_irqsave(&bcs->aclock, flags);
- bcs->ackcnt += bcs->tx_skb->len;
- spin_unlock_irqrestore(&bcs->aclock, flags);
- schedule_event(bcs, B_ACKPENDING);
- }
- dev_kfree_skb_any(bcs->tx_skb);
- bcs->tx_skb = NULL;
- }
- WaitForBusy(cs);
- WaitNoBusy(cs);
- ReadReg(cs, HFCD_DATA, HFCB_FIFO | HFCB_F1_INC | HFCB_SEND | HFCB_CHANNEL(bcs->channel));
- WaitForBusy(cs);
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- return;
-}
-
-static void
-hfc_send_data(struct BCState *bcs)
-{
- struct IsdnCardState *cs = bcs->cs;
-
- if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- hfc_fill_fifo(bcs);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- } else
- debugl1(cs, "send_data %d blocked", bcs->channel);
-}
-
-static void
-main_rec_2bds0(struct BCState *bcs)
-{
- struct IsdnCardState *cs = bcs->cs;
- int z1, z2, rcnt;
- u_char f1, f2, cip;
- int receive, count = 5;
- struct sk_buff *skb;
-
-Begin:
- count--;
- if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- debugl1(cs, "rec_data %d blocked", bcs->channel);
- return;
- }
- SelFiFo(cs, HFCB_REC | HFCB_CHANNEL(bcs->channel));
- cip = HFCB_FIFO | HFCB_F1 | HFCB_REC | HFCB_CHANNEL(bcs->channel);
- WaitNoBusy(cs);
- f1 = ReadReg(cs, HFCD_DATA, cip);
- cip = HFCB_FIFO | HFCB_F2 | HFCB_REC | HFCB_CHANNEL(bcs->channel);
- WaitNoBusy(cs);
- f2 = ReadReg(cs, HFCD_DATA, cip);
- if (f1 != f2) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc rec %d f1(%d) f2(%d)",
- bcs->channel, f1, f2);
- z1 = ReadZReg(cs, HFCB_FIFO | HFCB_Z1 | HFCB_REC | HFCB_CHANNEL(bcs->channel));
- z2 = ReadZReg(cs, HFCB_FIFO | HFCB_Z2 | HFCB_REC | HFCB_CHANNEL(bcs->channel));
- rcnt = z1 - z2;
- if (rcnt < 0)
- rcnt += cs->hw.hfcD.bfifosize;
- rcnt++;
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc rec %d z1(%x) z2(%x) cnt(%d)",
- bcs->channel, z1, z2, rcnt);
- if ((skb = hfc_empty_fifo(bcs, rcnt))) {
- skb_queue_tail(&bcs->rqueue, skb);
- schedule_event(bcs, B_RCVBUFREADY);
- }
- rcnt = f1 - f2;
- if (rcnt < 0)
- rcnt += 32;
- if (rcnt > 1)
- receive = 1;
- else
- receive = 0;
- } else
- receive = 0;
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- if (count && receive)
- goto Begin;
- return;
-}
-
-static void
-mode_2bs0(struct BCState *bcs, int mode, int bc)
-{
- struct IsdnCardState *cs = bcs->cs;
-
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "HFCD bchannel mode %d bchan %d/%d",
- mode, bc, bcs->channel);
- bcs->mode = mode;
- bcs->channel = bc;
- switch (mode) {
- case (L1_MODE_NULL):
- if (bc) {
- cs->hw.hfcD.conn |= 0x18;
- cs->hw.hfcD.sctrl &= ~SCTRL_B2_ENA;
- } else {
- cs->hw.hfcD.conn |= 0x3;
- cs->hw.hfcD.sctrl &= ~SCTRL_B1_ENA;
- }
- break;
- case (L1_MODE_TRANS):
- if (bc) {
- cs->hw.hfcD.ctmt |= 2;
- cs->hw.hfcD.conn &= ~0x18;
- cs->hw.hfcD.sctrl |= SCTRL_B2_ENA;
- } else {
- cs->hw.hfcD.ctmt |= 1;
- cs->hw.hfcD.conn &= ~0x3;
- cs->hw.hfcD.sctrl |= SCTRL_B1_ENA;
- }
- break;
- case (L1_MODE_HDLC):
- if (bc) {
- cs->hw.hfcD.ctmt &= ~2;
- cs->hw.hfcD.conn &= ~0x18;
- cs->hw.hfcD.sctrl |= SCTRL_B2_ENA;
- } else {
- cs->hw.hfcD.ctmt &= ~1;
- cs->hw.hfcD.conn &= ~0x3;
- cs->hw.hfcD.sctrl |= SCTRL_B1_ENA;
- }
- break;
- }
- WriteReg(cs, HFCD_DATA, HFCD_SCTRL, cs->hw.hfcD.sctrl);
- WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt);
- WriteReg(cs, HFCD_DATA, HFCD_CONN, cs->hw.hfcD.conn);
-}
-
-static void
-hfc_l2l1(struct PStack *st, int pr, void *arg)
-{
- struct BCState *bcs = st->l1.bcs;
- struct sk_buff *skb = arg;
- u_long flags;
-
- switch (pr) {
- case (PH_DATA | REQUEST):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- if (bcs->tx_skb) {
- skb_queue_tail(&bcs->squeue, skb);
- } else {
- bcs->tx_skb = skb;
-// test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->cs->BC_Send_Data(bcs);
- }
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- break;
- case (PH_PULL | INDICATION):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- if (bcs->tx_skb) {
- printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n");
- } else {
-// test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->tx_skb = skb;
- bcs->cs->BC_Send_Data(bcs);
- }
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- break;
- case (PH_PULL | REQUEST):
- if (!bcs->tx_skb) {
- test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
- } else
- test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- break;
- case (PH_ACTIVATE | REQUEST):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
- mode_2bs0(bcs, st->l1.mode, st->l1.bc);
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- l1_msg_b(st, pr, arg);
- break;
- case (PH_DEACTIVATE | REQUEST):
- l1_msg_b(st, pr, arg);
- break;
- case (PH_DEACTIVATE | CONFIRM):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- mode_2bs0(bcs, 0, st->l1.bc);
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
- break;
- }
-}
-
-static void
-close_2bs0(struct BCState *bcs)
-{
- mode_2bs0(bcs, 0, bcs->channel);
- if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
- skb_queue_purge(&bcs->rqueue);
- skb_queue_purge(&bcs->squeue);
- if (bcs->tx_skb) {
- dev_kfree_skb_any(bcs->tx_skb);
- bcs->tx_skb = NULL;
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- }
- }
-}
-
-static int
-open_hfcstate(struct IsdnCardState *cs, struct BCState *bcs)
-{
- if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
- skb_queue_head_init(&bcs->rqueue);
- skb_queue_head_init(&bcs->squeue);
- }
- bcs->tx_skb = NULL;
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->event = 0;
- bcs->tx_cnt = 0;
- return (0);
-}
-
-static int
-setstack_2b(struct PStack *st, struct BCState *bcs)
-{
- bcs->channel = st->l1.bc;
- if (open_hfcstate(st->l1.hardware, bcs))
- return (-1);
- st->l1.bcs = bcs;
- st->l2.l2l1 = hfc_l2l1;
- setstack_manager(st);
- bcs->st = st;
- setstack_l1_B(st);
- return (0);
-}
-
-static void
-hfcd_bh(struct work_struct *work)
-{
- struct IsdnCardState *cs =
- container_of(work, struct IsdnCardState, tqueue);
-
- if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
- switch (cs->dc.hfcd.ph_state) {
- case (0):
- l1_msg(cs, HW_RESET | INDICATION, NULL);
- break;
- case (3):
- l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
- break;
- case (8):
- l1_msg(cs, HW_RSYNC | INDICATION, NULL);
- break;
- case (6):
- l1_msg(cs, HW_INFO2 | INDICATION, NULL);
- break;
- case (7):
- l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
- break;
- default:
- break;
- }
- }
- if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
- DChannel_proc_rcv(cs);
- if (test_and_clear_bit(D_XMTBUFREADY, &cs->event))
- DChannel_proc_xmt(cs);
-}
-
-static
-int receive_dmsg(struct IsdnCardState *cs)
-{
- struct sk_buff *skb;
- int idx;
- int rcnt, z1, z2;
- u_char stat, cip, f1, f2;
- int chksum;
- int count = 5;
- u_char *ptr;
-
- if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- debugl1(cs, "rec_dmsg blocked");
- return (1);
- }
- SelFiFo(cs, 4 | HFCD_REC);
- cip = HFCD_FIFO | HFCD_F1 | HFCD_REC;
- WaitNoBusy(cs);
- f1 = cs->readisac(cs, cip) & 0xf;
- cip = HFCD_FIFO | HFCD_F2 | HFCD_REC;
- WaitNoBusy(cs);
- f2 = cs->readisac(cs, cip) & 0xf;
- while ((f1 != f2) && count--) {
- z1 = ReadZReg(cs, HFCD_FIFO | HFCD_Z1 | HFCD_REC);
- z2 = ReadZReg(cs, HFCD_FIFO | HFCD_Z2 | HFCD_REC);
- rcnt = z1 - z2;
- if (rcnt < 0)
- rcnt += cs->hw.hfcD.dfifosize;
- rcnt++;
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "hfcd recd f1(%d) f2(%d) z1(%x) z2(%x) cnt(%d)",
- f1, f2, z1, z2, rcnt);
- idx = 0;
- cip = HFCD_FIFO | HFCD_FIFO_OUT | HFCD_REC;
- if (rcnt > MAX_DFRAME_LEN + 3) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "empty_fifo d: incoming packet too large");
- while (idx < rcnt) {
- if (!(WaitNoBusy(cs)))
- break;
- ReadReg(cs, HFCD_DATA_NODEB, cip);
- idx++;
- }
- } else if (rcnt < 4) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "empty_fifo d: incoming packet too small");
- while ((idx++ < rcnt) && WaitNoBusy(cs))
- ReadReg(cs, HFCD_DATA_NODEB, cip);
- } else if ((skb = dev_alloc_skb(rcnt - 3))) {
- ptr = skb_put(skb, rcnt - 3);
- while (idx < (rcnt - 3)) {
- if (!(WaitNoBusy(cs)))
- break;
- *ptr = ReadReg(cs, HFCD_DATA_NODEB, cip);
- idx++;
- ptr++;
- }
- if (idx != (rcnt - 3)) {
- debugl1(cs, "RFIFO D BUSY error");
- printk(KERN_WARNING "HFC DFIFO channel BUSY Error\n");
- dev_kfree_skb_irq(skb);
- skb = NULL;
-#ifdef ERROR_STATISTIC
- cs->err_rx++;
-#endif
- } else {
- WaitNoBusy(cs);
- chksum = (ReadReg(cs, HFCD_DATA, cip) << 8);
- WaitNoBusy(cs);
- chksum += ReadReg(cs, HFCD_DATA, cip);
- WaitNoBusy(cs);
- stat = ReadReg(cs, HFCD_DATA, cip);
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "empty_dfifo chksum %x stat %x",
- chksum, stat);
- if (stat) {
- debugl1(cs, "FIFO CRC error");
- dev_kfree_skb_irq(skb);
- skb = NULL;
-#ifdef ERROR_STATISTIC
- cs->err_crc++;
-#endif
- } else {
- skb_queue_tail(&cs->rq, skb);
- schedule_event(cs, D_RCVBUFREADY);
- }
- }
- } else
- printk(KERN_WARNING "HFC: D receive out of memory\n");
- WaitForBusy(cs);
- cip = HFCD_FIFO | HFCD_F2_INC | HFCD_REC;
- WaitNoBusy(cs);
- stat = ReadReg(cs, HFCD_DATA, cip);
- WaitForBusy(cs);
- cip = HFCD_FIFO | HFCD_F2 | HFCD_REC;
- WaitNoBusy(cs);
- f2 = cs->readisac(cs, cip) & 0xf;
- }
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- return (1);
-}
-
-static void
-hfc_fill_dfifo(struct IsdnCardState *cs)
-{
- int idx, fcnt;
- int count;
- u_char cip;
-
- if (!cs->tx_skb)
- return;
- if (cs->tx_skb->len <= 0)
- return;
-
- SelFiFo(cs, 4 | HFCD_SEND);
- cip = HFCD_FIFO | HFCD_F1 | HFCD_SEND;
- WaitNoBusy(cs);
- cs->hw.hfcD.f1 = ReadReg(cs, HFCD_DATA, cip) & 0xf;
- WaitNoBusy(cs);
- cip = HFCD_FIFO | HFCD_F2 | HFCD_SEND;
- cs->hw.hfcD.f2 = ReadReg(cs, HFCD_DATA, cip) & 0xf;
- cs->hw.hfcD.send[cs->hw.hfcD.f1] = ReadZReg(cs, HFCD_FIFO | HFCD_Z1 | HFCD_SEND);
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "hfc_fill_Dfifo f1(%d) f2(%d) z1(%x)",
- cs->hw.hfcD.f1, cs->hw.hfcD.f2,
- cs->hw.hfcD.send[cs->hw.hfcD.f1]);
- fcnt = cs->hw.hfcD.f1 - cs->hw.hfcD.f2;
- if (fcnt < 0)
- fcnt += 16;
- if (fcnt > 14) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc_fill_Dfifo more as 14 frames");
- return;
- }
- count = GetFreeFifoBytes_D(cs);
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "hfc_fill_Dfifo count(%u/%d)",
- cs->tx_skb->len, count);
- if (count < cs->tx_skb->len) {
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "hfc_fill_Dfifo no fifo mem");
- return;
- }
- cip = HFCD_FIFO | HFCD_FIFO_IN | HFCD_SEND;
- idx = 0;
- WaitForBusy(cs);
- WaitNoBusy(cs);
- WriteReg(cs, HFCD_DATA_NODEB, cip, cs->tx_skb->data[idx++]);
- while (idx < cs->tx_skb->len) {
- if (!(WaitNoBusy(cs)))
- break;
- WriteReg(cs, HFCD_DATA_NODEB, cip, cs->tx_skb->data[idx]);
- idx++;
- }
- if (idx != cs->tx_skb->len) {
- debugl1(cs, "DFIFO Send BUSY error");
- printk(KERN_WARNING "HFC S DFIFO channel BUSY Error\n");
- }
- WaitForBusy(cs);
- WaitNoBusy(cs);
- ReadReg(cs, HFCD_DATA, HFCD_FIFO | HFCD_F1_INC | HFCD_SEND);
- dev_kfree_skb_any(cs->tx_skb);
- cs->tx_skb = NULL;
- WaitForBusy(cs);
- return;
-}
-
-static
-struct BCState *Sel_BCS(struct IsdnCardState *cs, int channel)
-{
- if (cs->bcs[0].mode && (cs->bcs[0].channel == channel))
- return (&cs->bcs[0]);
- else if (cs->bcs[1].mode && (cs->bcs[1].channel == channel))
- return (&cs->bcs[1]);
- else
- return (NULL);
-}
-
-void
-hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val)
-{
- u_char exval;
- struct BCState *bcs;
- int count = 15;
-
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "HFCD irq %x %s", val,
- test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ?
- "locked" : "unlocked");
- val &= cs->hw.hfcD.int_m1;
- if (val & 0x40) { /* TE state machine irq */
- exval = cs->readisac(cs, HFCD_STATES) & 0xf;
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcd.ph_state,
- exval);
- cs->dc.hfcd.ph_state = exval;
- schedule_event(cs, D_L1STATECHANGE);
- val &= ~0x40;
- }
- while (val) {
- if (test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- cs->hw.hfcD.int_s1 |= val;
- return;
- }
- if (cs->hw.hfcD.int_s1 & 0x18) {
- exval = val;
- val = cs->hw.hfcD.int_s1;
- cs->hw.hfcD.int_s1 = exval;
- }
- if (val & 0x08) {
- if (!(bcs = Sel_BCS(cs, 0))) {
- if (cs->debug)
- debugl1(cs, "hfcd spurious 0x08 IRQ");
- } else
- main_rec_2bds0(bcs);
- }
- if (val & 0x10) {
- if (!(bcs = Sel_BCS(cs, 1))) {
- if (cs->debug)
- debugl1(cs, "hfcd spurious 0x10 IRQ");
- } else
- main_rec_2bds0(bcs);
- }
- if (val & 0x01) {
- if (!(bcs = Sel_BCS(cs, 0))) {
- if (cs->debug)
- debugl1(cs, "hfcd spurious 0x01 IRQ");
- } else {
- if (bcs->tx_skb) {
- if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- hfc_fill_fifo(bcs);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- } else
- debugl1(cs, "fill_data %d blocked", bcs->channel);
- } else {
- if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
- if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- hfc_fill_fifo(bcs);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- } else
- debugl1(cs, "fill_data %d blocked", bcs->channel);
- } else {
- schedule_event(bcs, B_XMTBUFREADY);
- }
- }
- }
- }
- if (val & 0x02) {
- if (!(bcs = Sel_BCS(cs, 1))) {
- if (cs->debug)
- debugl1(cs, "hfcd spurious 0x02 IRQ");
- } else {
- if (bcs->tx_skb) {
- if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- hfc_fill_fifo(bcs);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- } else
- debugl1(cs, "fill_data %d blocked", bcs->channel);
- } else {
- if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
- if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- hfc_fill_fifo(bcs);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- } else
- debugl1(cs, "fill_data %d blocked", bcs->channel);
- } else {
- schedule_event(bcs, B_XMTBUFREADY);
- }
- }
- }
- }
- if (val & 0x20) { /* receive dframe */
- receive_dmsg(cs);
- }
- if (val & 0x04) { /* dframe transmitted */
- if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
- del_timer(&cs->dbusytimer);
- if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
- schedule_event(cs, D_CLEARBUSY);
- if (cs->tx_skb) {
- if (cs->tx_skb->len) {
- if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- hfc_fill_dfifo(cs);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- } else {
- debugl1(cs, "hfc_fill_dfifo irq blocked");
- }
- goto afterXPR;
- } else {
- dev_kfree_skb_irq(cs->tx_skb);
- cs->tx_cnt = 0;
- cs->tx_skb = NULL;
- }
- }
- if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
- cs->tx_cnt = 0;
- if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- hfc_fill_dfifo(cs);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- } else {
- debugl1(cs, "hfc_fill_dfifo irq blocked");
- }
- } else
- schedule_event(cs, D_XMTBUFREADY);
- }
- afterXPR:
- if (cs->hw.hfcD.int_s1 && count--) {
- val = cs->hw.hfcD.int_s1;
- cs->hw.hfcD.int_s1 = 0;
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "HFCD irq %x loop %d", val, 15-count);
- } else
- val = 0;
- }
-}
-
-static void
-HFCD_l1hw(struct PStack *st, int pr, void *arg)
-{
- struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
- struct sk_buff *skb = arg;
- u_long flags;
-
- switch (pr) {
- case (PH_DATA | REQUEST):
- if (cs->debug & DEB_DLOG_HEX)
- LogFrame(cs, skb->data, skb->len);
- if (cs->debug & DEB_DLOG_VERBOSE)
- dlogframe(cs, skb, 0);
- spin_lock_irqsave(&cs->lock, flags);
- if (cs->tx_skb) {
- skb_queue_tail(&cs->sq, skb);
-#ifdef L2FRAME_DEBUG /* psa */
- if (cs->debug & L1_DEB_LAPD)
- Logl2Frame(cs, skb, "PH_DATA Queued", 0);
-#endif
- } else {
- cs->tx_skb = skb;
- cs->tx_cnt = 0;
-#ifdef L2FRAME_DEBUG /* psa */
- if (cs->debug & L1_DEB_LAPD)
- Logl2Frame(cs, skb, "PH_DATA", 0);
-#endif
- if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- hfc_fill_dfifo(cs);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- } else
- debugl1(cs, "hfc_fill_dfifo blocked");
-
- }
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (PH_PULL | INDICATION):
- spin_lock_irqsave(&cs->lock, flags);
- if (cs->tx_skb) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
- skb_queue_tail(&cs->sq, skb);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- }
- if (cs->debug & DEB_DLOG_HEX)
- LogFrame(cs, skb->data, skb->len);
- if (cs->debug & DEB_DLOG_VERBOSE)
- dlogframe(cs, skb, 0);
- cs->tx_skb = skb;
- cs->tx_cnt = 0;
-#ifdef L2FRAME_DEBUG /* psa */
- if (cs->debug & L1_DEB_LAPD)
- Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
-#endif
- if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- hfc_fill_dfifo(cs);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- } else
- debugl1(cs, "hfc_fill_dfifo blocked");
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (PH_PULL | REQUEST):
-#ifdef L2FRAME_DEBUG /* psa */
- if (cs->debug & L1_DEB_LAPD)
- debugl1(cs, "-> PH_REQUEST_PULL");
-#endif
- if (!cs->tx_skb) {
- test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
- } else
- test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- break;
- case (HW_RESET | REQUEST):
- spin_lock_irqsave(&cs->lock, flags);
- cs->writeisac(cs, HFCD_STATES, HFCD_LOAD_STATE | 3); /* HFC ST 3 */
- udelay(6);
- cs->writeisac(cs, HFCD_STATES, 3); /* HFC ST 2 */
- cs->hw.hfcD.mst_m |= HFCD_MASTER;
- cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
- cs->writeisac(cs, HFCD_STATES, HFCD_ACTIVATE | HFCD_DO_ACTION);
- spin_unlock_irqrestore(&cs->lock, flags);
- l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
- break;
- case (HW_ENABLE | REQUEST):
- spin_lock_irqsave(&cs->lock, flags);
- cs->writeisac(cs, HFCD_STATES, HFCD_ACTIVATE | HFCD_DO_ACTION);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (HW_DEACTIVATE | REQUEST):
- spin_lock_irqsave(&cs->lock, flags);
- cs->hw.hfcD.mst_m &= ~HFCD_MASTER;
- cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (HW_INFO3 | REQUEST):
- spin_lock_irqsave(&cs->lock, flags);
- cs->hw.hfcD.mst_m |= HFCD_MASTER;
- cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- default:
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "hfcd_l1hw unknown pr %4x", pr);
- break;
- }
-}
-
-static void
-setstack_hfcd(struct PStack *st, struct IsdnCardState *cs)
-{
- st->l1.l1hw = HFCD_l1hw;
-}
-
-static void
-hfc_dbusy_timer(struct timer_list *t)
-{
-}
-
-static unsigned int
-*init_send_hfcd(int cnt)
-{
- int i;
- unsigned *send;
-
- if (!(send = kmalloc_array(cnt, sizeof(unsigned int), GFP_ATOMIC))) {
- printk(KERN_WARNING
- "HiSax: No memory for hfcd.send\n");
- return (NULL);
- }
- for (i = 0; i < cnt; i++)
- send[i] = 0x1fff;
- return (send);
-}
-
-void
-init2bds0(struct IsdnCardState *cs)
-{
- cs->setstack_d = setstack_hfcd;
- if (!cs->hw.hfcD.send)
- cs->hw.hfcD.send = init_send_hfcd(16);
- if (!cs->bcs[0].hw.hfc.send)
- cs->bcs[0].hw.hfc.send = init_send_hfcd(32);
- if (!cs->bcs[1].hw.hfc.send)
- cs->bcs[1].hw.hfc.send = init_send_hfcd(32);
- cs->BC_Send_Data = &hfc_send_data;
- cs->bcs[0].BC_SetStack = setstack_2b;
- cs->bcs[1].BC_SetStack = setstack_2b;
- cs->bcs[0].BC_Close = close_2bs0;
- cs->bcs[1].BC_Close = close_2bs0;
- mode_2bs0(cs->bcs, 0, 0);
- mode_2bs0(cs->bcs + 1, 0, 1);
-}
-
-void
-release2bds0(struct IsdnCardState *cs)
-{
- kfree(cs->bcs[0].hw.hfc.send);
- cs->bcs[0].hw.hfc.send = NULL;
- kfree(cs->bcs[1].hw.hfc.send);
- cs->bcs[1].hw.hfc.send = NULL;
- kfree(cs->hw.hfcD.send);
- cs->hw.hfcD.send = NULL;
-}
-
-void
-set_cs_func(struct IsdnCardState *cs)
-{
- cs->readisac = &readreghfcd;
- cs->writeisac = &writereghfcd;
- cs->readisacfifo = &dummyf;
- cs->writeisacfifo = &dummyf;
- cs->BC_Read_Reg = &ReadReg;
- cs->BC_Write_Reg = &WriteReg;
- timer_setup(&cs->dbusytimer, hfc_dbusy_timer, 0);
- INIT_WORK(&cs->tqueue, hfcd_bh);
-}
diff --git a/drivers/isdn/hisax/hfc_2bds0.h b/drivers/isdn/hisax/hfc_2bds0.h
deleted file mode 100644
index 8c7582a3c51e..000000000000
--- a/drivers/isdn/hisax/hfc_2bds0.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/* $Id: hfc_2bds0.h,v 1.6.2.2 2004/01/12 22:52:26 keil Exp $
- *
- * specific defines for CCD's HFC 2BDS0
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#define HFCD_CIRM 0x18
-#define HFCD_CTMT 0x19
-#define HFCD_INT_M1 0x1A
-#define HFCD_INT_M2 0x1B
-#define HFCD_INT_S1 0x1E
-#define HFCD_STAT 0x1C
-#define HFCD_STAT_DISB 0x1D
-#define HFCD_STATES 0x30
-#define HFCD_SCTRL 0x31
-#define HFCD_TEST 0x32
-#define HFCD_SQ 0x34
-#define HFCD_CLKDEL 0x37
-#define HFCD_MST_MODE 0x2E
-#define HFCD_CONN 0x2F
-
-#define HFCD_FIFO 0x80
-#define HFCD_Z1 0x10
-#define HFCD_Z2 0x18
-#define HFCD_Z_LOW 0x00
-#define HFCD_Z_HIGH 0x04
-#define HFCD_F1_INC 0x12
-#define HFCD_FIFO_IN 0x16
-#define HFCD_F1 0x1a
-#define HFCD_F2 0x1e
-#define HFCD_F2_INC 0x22
-#define HFCD_FIFO_OUT 0x26
-#define HFCD_REC 0x01
-#define HFCD_SEND 0x00
-
-#define HFCB_FIFO 0x80
-#define HFCB_Z1 0x00
-#define HFCB_Z2 0x08
-#define HFCB_Z_LOW 0x00
-#define HFCB_Z_HIGH 0x04
-#define HFCB_F1_INC 0x28
-#define HFCB_FIFO_IN 0x2c
-#define HFCB_F1 0x30
-#define HFCB_F2 0x34
-#define HFCB_F2_INC 0x38
-#define HFCB_FIFO_OUT 0x3c
-#define HFCB_REC 0x01
-#define HFCB_SEND 0x00
-#define HFCB_B1 0x00
-#define HFCB_B2 0x02
-#define HFCB_CHANNEL(ch) (ch ? HFCB_B2 : HFCB_B1)
-
-#define HFCD_STATUS 0
-#define HFCD_DATA 1
-#define HFCD_DATA_NODEB 2
-
-/* Status (READ) */
-#define HFCD_BUSY 0x01
-#define HFCD_BUSY_NBUSY 0x04
-#define HFCD_TIMER_ELAP 0x10
-#define HFCD_STATINT 0x20
-#define HFCD_FRAMEINT 0x40
-#define HFCD_ANYINT 0x80
-
-/* CTMT (Write) */
-#define HFCD_CLTIMER 0x80
-#define HFCD_TIM25 0x00
-#define HFCD_TIM50 0x08
-#define HFCD_TIM400 0x10
-#define HFCD_TIM800 0x18
-#define HFCD_AUTO_TIMER 0x20
-#define HFCD_TRANSB2 0x02
-#define HFCD_TRANSB1 0x01
-
-/* CIRM (Write) */
-#define HFCD_RESET 0x08
-#define HFCD_MEM8K 0x10
-#define HFCD_INTA 0x01
-#define HFCD_INTB 0x02
-#define HFCD_INTC 0x03
-#define HFCD_INTD 0x04
-#define HFCD_INTE 0x05
-#define HFCD_INTF 0x06
-
-/* INT_M1;INT_S1 */
-#define HFCD_INTS_B1TRANS 0x01
-#define HFCD_INTS_B2TRANS 0x02
-#define HFCD_INTS_DTRANS 0x04
-#define HFCD_INTS_B1REC 0x08
-#define HFCD_INTS_B2REC 0x10
-#define HFCD_INTS_DREC 0x20
-#define HFCD_INTS_L1STATE 0x40
-#define HFCD_INTS_TIMER 0x80
-
-/* INT_M2 */
-#define HFCD_IRQ_ENABLE 0x08
-
-/* STATES */
-#define HFCD_LOAD_STATE 0x10
-#define HFCD_ACTIVATE 0x20
-#define HFCD_DO_ACTION 0x40
-
-/* HFCD_MST_MODE */
-#define HFCD_MASTER 0x01
-
-/* HFCD_SCTRL */
-#define SCTRL_B1_ENA 0x01
-#define SCTRL_B2_ENA 0x02
-#define SCTRL_LOW_PRIO 0x08
-#define SCTRL_SQ_ENA 0x10
-#define SCTRL_TEST 0x20
-#define SCTRL_NONE_CAP 0x40
-#define SCTRL_PWR_DOWN 0x80
-
-/* HFCD_TEST */
-#define HFCD_AUTO_AWAKE 0x01
-
-extern void main_irq_2bds0(struct BCState *bcs);
-extern void init2bds0(struct IsdnCardState *cs);
-extern void release2bds0(struct IsdnCardState *cs);
-extern void hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val);
-extern void set_cs_func(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/hfc_2bs0.c b/drivers/isdn/hisax/hfc_2bs0.c
deleted file mode 100644
index 34d59992839a..000000000000
--- a/drivers/isdn/hisax/hfc_2bs0.c
+++ /dev/null
@@ -1,591 +0,0 @@
-/* $Id: hfc_2bs0.c,v 1.20.2.6 2004/02/11 13:21:33 keil Exp $
- *
- * specific routines for CCD's HFC 2BS0
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/init.h>
-#include "hisax.h"
-#include "hfc_2bs0.h"
-#include "isac.h"
-#include "isdnl1.h"
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-
-static inline int
-WaitForBusy(struct IsdnCardState *cs)
-{
- int to = 130;
- u_char val;
-
- while (!(cs->BC_Read_Reg(cs, HFC_STATUS, 0) & HFC_BUSY) && to) {
- val = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2 |
- (cs->hw.hfc.cip & 3));
- udelay(1);
- to--;
- }
- if (!to) {
- printk(KERN_WARNING "HiSax: %s timeout\n", __func__);
- return (0);
- } else
- return (to);
-}
-
-static inline int
-WaitNoBusy(struct IsdnCardState *cs)
-{
- int to = 125;
-
- while ((cs->BC_Read_Reg(cs, HFC_STATUS, 0) & HFC_BUSY) && to) {
- udelay(1);
- to--;
- }
- if (!to) {
- printk(KERN_WARNING "HiSax: waitforBusy timeout\n");
- return (0);
- } else
- return (to);
-}
-
-static int
-GetFreeFifoBytes(struct BCState *bcs)
-{
- int s;
-
- if (bcs->hw.hfc.f1 == bcs->hw.hfc.f2)
- return (bcs->cs->hw.hfc.fifosize);
- s = bcs->hw.hfc.send[bcs->hw.hfc.f1] - bcs->hw.hfc.send[bcs->hw.hfc.f2];
- if (s <= 0)
- s += bcs->cs->hw.hfc.fifosize;
- s = bcs->cs->hw.hfc.fifosize - s;
- return (s);
-}
-
-static int
-ReadZReg(struct BCState *bcs, u_char reg)
-{
- int val;
-
- WaitNoBusy(bcs->cs);
- val = 256 * bcs->cs->BC_Read_Reg(bcs->cs, HFC_DATA, reg | HFC_CIP | HFC_Z_HIGH);
- WaitNoBusy(bcs->cs);
- val += bcs->cs->BC_Read_Reg(bcs->cs, HFC_DATA, reg | HFC_CIP | HFC_Z_LOW);
- return (val);
-}
-
-static void
-hfc_clear_fifo(struct BCState *bcs)
-{
- struct IsdnCardState *cs = bcs->cs;
- int idx, cnt;
- int rcnt, z1, z2;
- u_char cip, f1, f2;
-
- if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
- debugl1(cs, "hfc_clear_fifo");
- cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel);
- if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) {
- cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip);
- WaitForBusy(cs);
- }
- WaitNoBusy(cs);
- f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
- cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel);
- WaitNoBusy(cs);
- f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
- z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel));
- z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel));
- cnt = 32;
- while (((f1 != f2) || (z1 != z2)) && cnt--) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc clear %d f1(%d) f2(%d)",
- bcs->channel, f1, f2);
- rcnt = z1 - z2;
- if (rcnt < 0)
- rcnt += cs->hw.hfc.fifosize;
- if (rcnt)
- rcnt++;
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc clear %d z1(%x) z2(%x) cnt(%d)",
- bcs->channel, z1, z2, rcnt);
- cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
- idx = 0;
- while ((idx < rcnt) && WaitNoBusy(cs)) {
- cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
- idx++;
- }
- if (f1 != f2) {
- WaitNoBusy(cs);
- cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
- HFC_CHANNEL(bcs->channel));
- WaitForBusy(cs);
- }
- cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel);
- WaitNoBusy(cs);
- f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
- cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel);
- WaitNoBusy(cs);
- f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
- z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel));
- z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel));
- }
- return;
-}
-
-
-static struct sk_buff
-*
-hfc_empty_fifo(struct BCState *bcs, int count)
-{
- u_char *ptr;
- struct sk_buff *skb;
- struct IsdnCardState *cs = bcs->cs;
- int idx;
- int chksum;
- u_char stat, cip;
-
- if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
- debugl1(cs, "hfc_empty_fifo");
- idx = 0;
- if (count > HSCX_BUFMAX + 3) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "hfc_empty_fifo: incoming packet too large");
- cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
- while ((idx++ < count) && WaitNoBusy(cs))
- cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
- WaitNoBusy(cs);
- stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
- HFC_CHANNEL(bcs->channel));
- WaitForBusy(cs);
- return (NULL);
- }
- if ((count < 4) && (bcs->mode != L1_MODE_TRANS)) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "hfc_empty_fifo: incoming packet too small");
- cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
- while ((idx++ < count) && WaitNoBusy(cs))
- cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
- WaitNoBusy(cs);
- stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
- HFC_CHANNEL(bcs->channel));
- WaitForBusy(cs);
-#ifdef ERROR_STATISTIC
- bcs->err_inv++;
-#endif
- return (NULL);
- }
- if (bcs->mode == L1_MODE_TRANS)
- count -= 1;
- else
- count -= 3;
- if (!(skb = dev_alloc_skb(count)))
- printk(KERN_WARNING "HFC: receive out of memory\n");
- else {
- ptr = skb_put(skb, count);
- idx = 0;
- cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
- while ((idx < count) && WaitNoBusy(cs)) {
- *ptr++ = cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
- idx++;
- }
- if (idx != count) {
- debugl1(cs, "RFIFO BUSY error");
- printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel);
- dev_kfree_skb_any(skb);
- if (bcs->mode != L1_MODE_TRANS) {
- WaitNoBusy(cs);
- stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
- HFC_CHANNEL(bcs->channel));
- WaitForBusy(cs);
- }
- return (NULL);
- }
- if (bcs->mode != L1_MODE_TRANS) {
- WaitNoBusy(cs);
- chksum = (cs->BC_Read_Reg(cs, HFC_DATA, cip) << 8);
- WaitNoBusy(cs);
- chksum += cs->BC_Read_Reg(cs, HFC_DATA, cip);
- WaitNoBusy(cs);
- stat = cs->BC_Read_Reg(cs, HFC_DATA, cip);
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc_empty_fifo %d chksum %x stat %x",
- bcs->channel, chksum, stat);
- if (stat) {
- debugl1(cs, "FIFO CRC error");
- dev_kfree_skb_any(skb);
- skb = NULL;
-#ifdef ERROR_STATISTIC
- bcs->err_crc++;
-#endif
- }
- WaitNoBusy(cs);
- stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
- HFC_CHANNEL(bcs->channel));
- WaitForBusy(cs);
- }
- }
- return (skb);
-}
-
-static void
-hfc_fill_fifo(struct BCState *bcs)
-{
- struct IsdnCardState *cs = bcs->cs;
- int idx, fcnt;
- int count;
- int z1, z2;
- u_char cip;
-
- if (!bcs->tx_skb)
- return;
- if (bcs->tx_skb->len <= 0)
- return;
-
- cip = HFC_CIP | HFC_F1 | HFC_SEND | HFC_CHANNEL(bcs->channel);
- if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) {
- cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip);
- WaitForBusy(cs);
- }
- WaitNoBusy(cs);
- if (bcs->mode != L1_MODE_TRANS) {
- bcs->hw.hfc.f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
- cip = HFC_CIP | HFC_F2 | HFC_SEND | HFC_CHANNEL(bcs->channel);
- WaitNoBusy(cs);
- bcs->hw.hfc.f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
- bcs->hw.hfc.send[bcs->hw.hfc.f1] = ReadZReg(bcs, HFC_Z1 | HFC_SEND | HFC_CHANNEL(bcs->channel));
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)",
- bcs->channel, bcs->hw.hfc.f1, bcs->hw.hfc.f2,
- bcs->hw.hfc.send[bcs->hw.hfc.f1]);
- fcnt = bcs->hw.hfc.f1 - bcs->hw.hfc.f2;
- if (fcnt < 0)
- fcnt += 32;
- if (fcnt > 30) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc_fill_fifo more as 30 frames");
- return;
- }
- count = GetFreeFifoBytes(bcs);
- }
- else {
- WaitForBusy(cs);
- z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel));
- z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel));
- count = z1 - z2;
- if (count < 0)
- count += cs->hw.hfc.fifosize;
- } /* L1_MODE_TRANS */
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc_fill_fifo %d count(%u/%d)",
- bcs->channel, bcs->tx_skb->len,
- count);
- if (count < bcs->tx_skb->len) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc_fill_fifo no fifo mem");
- return;
- }
- cip = HFC_CIP | HFC_FIFO_IN | HFC_SEND | HFC_CHANNEL(bcs->channel);
- idx = 0;
- while ((idx < bcs->tx_skb->len) && WaitNoBusy(cs))
- cs->BC_Write_Reg(cs, HFC_DATA_NODEB, cip, bcs->tx_skb->data[idx++]);
- if (idx != bcs->tx_skb->len) {
- debugl1(cs, "FIFO Send BUSY error");
- printk(KERN_WARNING "HFC S FIFO channel %d BUSY Error\n", bcs->channel);
- } else {
- count = bcs->tx_skb->len;
- bcs->tx_cnt -= count;
- if (PACKET_NOACK == bcs->tx_skb->pkt_type)
- count = -1;
- dev_kfree_skb_any(bcs->tx_skb);
- bcs->tx_skb = NULL;
- if (bcs->mode != L1_MODE_TRANS) {
- WaitForBusy(cs);
- WaitNoBusy(cs);
- cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F1_INC | HFC_SEND | HFC_CHANNEL(bcs->channel));
- }
- if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
- (count >= 0)) {
- u_long flags;
- spin_lock_irqsave(&bcs->aclock, flags);
- bcs->ackcnt += count;
- spin_unlock_irqrestore(&bcs->aclock, flags);
- schedule_event(bcs, B_ACKPENDING);
- }
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- }
- return;
-}
-
-void
-main_irq_hfc(struct BCState *bcs)
-{
- struct IsdnCardState *cs = bcs->cs;
- int z1, z2, rcnt;
- u_char f1, f2, cip;
- int receive, transmit, count = 5;
- struct sk_buff *skb;
-
-Begin:
- count--;
- cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel);
- if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) {
- cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip);
- WaitForBusy(cs);
- }
- WaitNoBusy(cs);
- receive = 0;
- if (bcs->mode == L1_MODE_HDLC) {
- f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
- cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel);
- WaitNoBusy(cs);
- f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
- if (f1 != f2) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc rec %d f1(%d) f2(%d)",
- bcs->channel, f1, f2);
- receive = 1;
- }
- }
- if (receive || (bcs->mode == L1_MODE_TRANS)) {
- WaitForBusy(cs);
- z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel));
- z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel));
- rcnt = z1 - z2;
- if (rcnt < 0)
- rcnt += cs->hw.hfc.fifosize;
- if ((bcs->mode == L1_MODE_HDLC) || (rcnt)) {
- rcnt++;
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc rec %d z1(%x) z2(%x) cnt(%d)",
- bcs->channel, z1, z2, rcnt);
- /* sti(); */
- if ((skb = hfc_empty_fifo(bcs, rcnt))) {
- skb_queue_tail(&bcs->rqueue, skb);
- schedule_event(bcs, B_RCVBUFREADY);
- }
- }
- receive = 1;
- }
- if (bcs->tx_skb) {
- transmit = 1;
- test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
- hfc_fill_fifo(bcs);
- if (test_bit(BC_FLG_BUSY, &bcs->Flag))
- transmit = 0;
- } else {
- if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
- transmit = 1;
- test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
- hfc_fill_fifo(bcs);
- if (test_bit(BC_FLG_BUSY, &bcs->Flag))
- transmit = 0;
- } else {
- transmit = 0;
- schedule_event(bcs, B_XMTBUFREADY);
- }
- }
- if ((receive || transmit) && count)
- goto Begin;
- return;
-}
-
-static void
-mode_hfc(struct BCState *bcs, int mode, int bc)
-{
- struct IsdnCardState *cs = bcs->cs;
-
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "HFC 2BS0 mode %d bchan %d/%d",
- mode, bc, bcs->channel);
- bcs->mode = mode;
- bcs->channel = bc;
-
- switch (mode) {
- case (L1_MODE_NULL):
- if (bc) {
- cs->hw.hfc.ctmt &= ~1;
- cs->hw.hfc.isac_spcr &= ~0x03;
- }
- else {
- cs->hw.hfc.ctmt &= ~2;
- cs->hw.hfc.isac_spcr &= ~0x0c;
- }
- break;
- case (L1_MODE_TRANS):
- cs->hw.hfc.ctmt &= ~(1 << bc); /* set HDLC mode */
- cs->BC_Write_Reg(cs, HFC_STATUS, cs->hw.hfc.ctmt, cs->hw.hfc.ctmt);
- hfc_clear_fifo(bcs); /* complete fifo clear */
- if (bc) {
- cs->hw.hfc.ctmt |= 1;
- cs->hw.hfc.isac_spcr &= ~0x03;
- cs->hw.hfc.isac_spcr |= 0x02;
- } else {
- cs->hw.hfc.ctmt |= 2;
- cs->hw.hfc.isac_spcr &= ~0x0c;
- cs->hw.hfc.isac_spcr |= 0x08;
- }
- break;
- case (L1_MODE_HDLC):
- if (bc) {
- cs->hw.hfc.ctmt &= ~1;
- cs->hw.hfc.isac_spcr &= ~0x03;
- cs->hw.hfc.isac_spcr |= 0x02;
- } else {
- cs->hw.hfc.ctmt &= ~2;
- cs->hw.hfc.isac_spcr &= ~0x0c;
- cs->hw.hfc.isac_spcr |= 0x08;
- }
- break;
- }
- cs->BC_Write_Reg(cs, HFC_STATUS, cs->hw.hfc.ctmt, cs->hw.hfc.ctmt);
- cs->writeisac(cs, ISAC_SPCR, cs->hw.hfc.isac_spcr);
- if (mode == L1_MODE_HDLC)
- hfc_clear_fifo(bcs);
-}
-
-static void
-hfc_l2l1(struct PStack *st, int pr, void *arg)
-{
- struct BCState *bcs = st->l1.bcs;
- struct sk_buff *skb = arg;
- u_long flags;
-
- switch (pr) {
- case (PH_DATA | REQUEST):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- if (bcs->tx_skb) {
- skb_queue_tail(&bcs->squeue, skb);
- } else {
- bcs->tx_skb = skb;
- test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->cs->BC_Send_Data(bcs);
- }
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- break;
- case (PH_PULL | INDICATION):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- if (bcs->tx_skb) {
- printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n");
- } else {
- test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->tx_skb = skb;
- bcs->cs->BC_Send_Data(bcs);
- }
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- break;
- case (PH_PULL | REQUEST):
- if (!bcs->tx_skb) {
- test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
- } else
- test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- break;
- case (PH_ACTIVATE | REQUEST):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
- mode_hfc(bcs, st->l1.mode, st->l1.bc);
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- l1_msg_b(st, pr, arg);
- break;
- case (PH_DEACTIVATE | REQUEST):
- l1_msg_b(st, pr, arg);
- break;
- case (PH_DEACTIVATE | CONFIRM):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- mode_hfc(bcs, 0, st->l1.bc);
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
- break;
- }
-}
-
-
-static void
-close_hfcstate(struct BCState *bcs)
-{
- mode_hfc(bcs, 0, bcs->channel);
- if (test_bit(BC_FLG_INIT, &bcs->Flag)) {
- skb_queue_purge(&bcs->rqueue);
- skb_queue_purge(&bcs->squeue);
- if (bcs->tx_skb) {
- dev_kfree_skb_any(bcs->tx_skb);
- bcs->tx_skb = NULL;
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- }
- }
- test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
-}
-
-static int
-open_hfcstate(struct IsdnCardState *cs, struct BCState *bcs)
-{
- if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
- skb_queue_head_init(&bcs->rqueue);
- skb_queue_head_init(&bcs->squeue);
- }
- bcs->tx_skb = NULL;
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->event = 0;
- bcs->tx_cnt = 0;
- return (0);
-}
-
-static int
-setstack_hfc(struct PStack *st, struct BCState *bcs)
-{
- bcs->channel = st->l1.bc;
- if (open_hfcstate(st->l1.hardware, bcs))
- return (-1);
- st->l1.bcs = bcs;
- st->l2.l2l1 = hfc_l2l1;
- setstack_manager(st);
- bcs->st = st;
- setstack_l1_B(st);
- return (0);
-}
-
-static void
-init_send(struct BCState *bcs)
-{
- int i;
-
- bcs->hw.hfc.send = kmalloc_array(32, sizeof(unsigned int), GFP_ATOMIC);
- if (!bcs->hw.hfc.send) {
- printk(KERN_WARNING
- "HiSax: No memory for hfc.send\n");
- return;
- }
- for (i = 0; i < 32; i++)
- bcs->hw.hfc.send[i] = 0x1fff;
-}
-
-void
-inithfc(struct IsdnCardState *cs)
-{
- init_send(&cs->bcs[0]);
- init_send(&cs->bcs[1]);
- cs->BC_Send_Data = &hfc_fill_fifo;
- cs->bcs[0].BC_SetStack = setstack_hfc;
- cs->bcs[1].BC_SetStack = setstack_hfc;
- cs->bcs[0].BC_Close = close_hfcstate;
- cs->bcs[1].BC_Close = close_hfcstate;
- mode_hfc(cs->bcs, 0, 0);
- mode_hfc(cs->bcs + 1, 0, 0);
-}
-
-void
-releasehfc(struct IsdnCardState *cs)
-{
- kfree(cs->bcs[0].hw.hfc.send);
- cs->bcs[0].hw.hfc.send = NULL;
- kfree(cs->bcs[1].hw.hfc.send);
- cs->bcs[1].hw.hfc.send = NULL;
-}
diff --git a/drivers/isdn/hisax/hfc_2bs0.h b/drivers/isdn/hisax/hfc_2bs0.h
deleted file mode 100644
index 1510096363dc..000000000000
--- a/drivers/isdn/hisax/hfc_2bs0.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* $Id: hfc_2bs0.h,v 1.5.2.2 2004/01/12 22:52:26 keil Exp $
- *
- * specific defines for CCD's HFC 2BS0
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#define HFC_CTMT 0xe0
-#define HFC_CIRM 0xc0
-#define HFC_CIP 0x80
-#define HFC_Z1 0x00
-#define HFC_Z2 0x08
-#define HFC_Z_LOW 0x00
-#define HFC_Z_HIGH 0x04
-#define HFC_F1_INC 0x28
-#define HFC_FIFO_IN 0x2c
-#define HFC_F1 0x30
-#define HFC_F2 0x34
-#define HFC_F2_INC 0x38
-#define HFC_FIFO_OUT 0x3c
-#define HFC_B1 0x00
-#define HFC_B2 0x02
-#define HFC_REC 0x01
-#define HFC_SEND 0x00
-#define HFC_CHANNEL(ch) (ch ? HFC_B2 : HFC_B1)
-
-#define HFC_STATUS 0
-#define HFC_DATA 1
-#define HFC_DATA_NODEB 2
-
-/* Status (READ) */
-#define HFC_BUSY 0x01
-#define HFC_TIMINT 0x02
-#define HFC_EXTINT 0x04
-
-/* CTMT (Write) */
-#define HFC_CLTIMER 0x10
-#define HFC_TIM50MS 0x08
-#define HFC_TIMIRQE 0x04
-#define HFC_TRANSB2 0x02
-#define HFC_TRANSB1 0x01
-
-/* CIRM (Write) */
-#define HFC_RESET 0x08
-#define HFC_MEM8K 0x10
-#define HFC_INTA 0x01
-#define HFC_INTB 0x02
-#define HFC_INTC 0x03
-#define HFC_INTD 0x04
-#define HFC_INTE 0x05
-#define HFC_INTF 0x06
-
-extern void main_irq_hfc(struct BCState *bcs);
-extern void inithfc(struct IsdnCardState *cs);
-extern void releasehfc(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
deleted file mode 100644
index 71a8312592d6..000000000000
--- a/drivers/isdn/hisax/hfc_pci.c
+++ /dev/null
@@ -1,1755 +0,0 @@
-/* $Id: hfc_pci.c,v 1.48.2.4 2004/02/11 13:21:33 keil Exp $
- *
- * low level driver for CCD's hfc-pci based cards
- *
- * Author Werner Cornelius
- * based on existing driver for CCD hfc ISA cards
- * Copyright by Werner Cornelius <werner@isdn4linux.de>
- * by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * For changes and modifications please read
- * Documentation/isdn/HiSax.cert
- *
- */
-
-#include <linux/init.h>
-#include "hisax.h"
-#include "hfc_pci.h"
-#include "isdnl1.h"
-#include <linux/pci.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-
-static const char *hfcpci_revision = "$Revision: 1.48.2.4 $";
-
-/* table entry in the PCI devices list */
-typedef struct {
- int vendor_id;
- int device_id;
- char *vendor_name;
- char *card_name;
-} PCI_ENTRY;
-
-#define NT_T1_COUNT 20 /* number of 3.125ms interrupts for G2 timeout */
-#define CLKDEL_TE 0x0e /* CLKDEL in TE mode */
-#define CLKDEL_NT 0x6c /* CLKDEL in NT mode */
-
-static const PCI_ENTRY id_list[] =
-{
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_2BD0, "CCD/Billion/Asuscom", "2BD0"},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B000, "Billion", "B000"},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B006, "Billion", "B006"},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B007, "Billion", "B007"},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B008, "Billion", "B008"},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B009, "Billion", "B009"},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00A, "Billion", "B00A"},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00B, "Billion", "B00B"},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00C, "Billion", "B00C"},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B100, "Seyeon", "B100"},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B700, "Primux II S0", "B700"},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B701, "Primux II S0 NT", "B701"},
- {PCI_VENDOR_ID_ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1, "Abocom/Magitek", "2BD1"},
- {PCI_VENDOR_ID_ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675, "Asuscom/Askey", "675"},
- {PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT, "German telekom", "T-Concept"},
- {PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_A1T, "German telekom", "A1T"},
- {PCI_VENDOR_ID_ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575, "Motorola MC145575", "MC145575"},
- {PCI_VENDOR_ID_ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0, "Zoltrix", "2BD0"},
- {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E, "Digi International", "Digi DataFire Micro V IOM2 (Europe)"},
- {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_E, "Digi International", "Digi DataFire Micro V (Europe)"},
- {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A, "Digi International", "Digi DataFire Micro V IOM2 (North America)"},
- {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_A, "Digi International", "Digi DataFire Micro V (North America)"},
- {PCI_VENDOR_ID_SITECOM, PCI_DEVICE_ID_SITECOM_DC105V2, "Sitecom Europe", "DC-105 ISDN PCI"},
- {0, 0, NULL, NULL},
-};
-
-
-/******************************************/
-/* free hardware resources used by driver */
-/******************************************/
-static void
-release_io_hfcpci(struct IsdnCardState *cs)
-{
- printk(KERN_INFO "HiSax: release hfcpci at %p\n",
- cs->hw.hfcpci.pci_io);
- cs->hw.hfcpci.int_m2 = 0; /* interrupt output off ! */
- Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
- Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET); /* Reset On */
- mdelay(10);
- Write_hfc(cs, HFCPCI_CIRM, 0); /* Reset Off */
- mdelay(10);
- Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
- pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, 0); /* disable memory mapped ports + busmaster */
- del_timer(&cs->hw.hfcpci.timer);
- pci_free_consistent(cs->hw.hfcpci.dev, 0x8000,
- cs->hw.hfcpci.fifos, cs->hw.hfcpci.dma);
- cs->hw.hfcpci.fifos = NULL;
- iounmap(cs->hw.hfcpci.pci_io);
-}
-
-/********************************************************************************/
-/* function called to reset the HFC PCI chip. A complete software reset of chip */
-/* and fifos is done. */
-/********************************************************************************/
-static void
-reset_hfcpci(struct IsdnCardState *cs)
-{
- pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, PCI_ENA_MEMIO); /* enable memory mapped ports, disable busmaster */
- cs->hw.hfcpci.int_m2 = 0; /* interrupt output off ! */
- Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
-
- printk(KERN_INFO "HFC_PCI: resetting card\n");
- pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, PCI_ENA_MEMIO + PCI_ENA_MASTER); /* enable memory ports + busmaster */
- Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET); /* Reset On */
- mdelay(10);
- Write_hfc(cs, HFCPCI_CIRM, 0); /* Reset Off */
- mdelay(10);
- if (Read_hfc(cs, HFCPCI_STATUS) & 2)
- printk(KERN_WARNING "HFC-PCI init bit busy\n");
-
- cs->hw.hfcpci.fifo_en = 0x30; /* only D fifos enabled */
- Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
-
- cs->hw.hfcpci.trm = 0 + HFCPCI_BTRANS_THRESMASK; /* no echo connect , threshold */
- Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm);
-
- Write_hfc(cs, HFCPCI_CLKDEL, CLKDEL_TE); /* ST-Bit delay for TE-Mode */
- cs->hw.hfcpci.sctrl_e = HFCPCI_AUTO_AWAKE;
- Write_hfc(cs, HFCPCI_SCTRL_E, cs->hw.hfcpci.sctrl_e); /* S/T Auto awake */
- cs->hw.hfcpci.bswapped = 0; /* no exchange */
- cs->hw.hfcpci.nt_mode = 0; /* we are in TE mode */
- cs->hw.hfcpci.ctmt = HFCPCI_TIM3_125 | HFCPCI_AUTO_TIMER;
- Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt);
-
- cs->hw.hfcpci.int_m1 = HFCPCI_INTS_DTRANS | HFCPCI_INTS_DREC |
- HFCPCI_INTS_L1STATE | HFCPCI_INTS_TIMER;
- Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
-
- /* Clear already pending ints */
- Read_hfc(cs, HFCPCI_INT_S1);
-
- Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 2); /* HFC ST 2 */
- udelay(10);
- Write_hfc(cs, HFCPCI_STATES, 2); /* HFC ST 2 */
- cs->hw.hfcpci.mst_m = HFCPCI_MASTER; /* HFC Master Mode */
-
- Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m);
- cs->hw.hfcpci.sctrl = 0x40; /* set tx_lo mode, error in datasheet ! */
- Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl);
- cs->hw.hfcpci.sctrl_r = 0;
- Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r);
-
- /* Init GCI/IOM2 in master mode */
- /* Slots 0 and 1 are set for B-chan 1 and 2 */
- /* D- and monitor/CI channel are not enabled */
- /* STIO1 is used as output for data, B1+B2 from ST->IOM+HFC */
- /* STIO2 is used as data input, B1+B2 from IOM->ST */
- /* ST B-channel send disabled -> continuous 1s */
- /* The IOM slots are always enabled */
- cs->hw.hfcpci.conn = 0x36; /* set data flow directions */
- Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
- Write_hfc(cs, HFCPCI_B1_SSL, 0x80); /* B1-Slot 0 STIO1 out enabled */
- Write_hfc(cs, HFCPCI_B2_SSL, 0x81); /* B2-Slot 1 STIO1 out enabled */
- Write_hfc(cs, HFCPCI_B1_RSL, 0x80); /* B1-Slot 0 STIO2 in enabled */
- Write_hfc(cs, HFCPCI_B2_RSL, 0x81); /* B2-Slot 1 STIO2 in enabled */
-
- /* Finally enable IRQ output */
- cs->hw.hfcpci.int_m2 = HFCPCI_IRQ_ENABLE;
- Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
- Read_hfc(cs, HFCPCI_INT_S1);
-}
-
-/***************************************************/
-/* Timer function called when kernel timer expires */
-/***************************************************/
-static void
-hfcpci_Timer(struct timer_list *t)
-{
- struct IsdnCardState *cs = from_timer(cs, t, hw.hfcpci.timer);
- cs->hw.hfcpci.timer.expires = jiffies + 75;
- /* WD RESET */
-/* WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcpci.ctmt | 0x80);
- add_timer(&cs->hw.hfcpci.timer);
-*/
-}
-
-
-/*********************************/
-/* schedule a new D-channel task */
-/*********************************/
-static void
-sched_event_D_pci(struct IsdnCardState *cs, int event)
-{
- test_and_set_bit(event, &cs->event);
- schedule_work(&cs->tqueue);
-}
-
-/*********************************/
-/* schedule a new b_channel task */
-/*********************************/
-static void
-hfcpci_sched_event(struct BCState *bcs, int event)
-{
- test_and_set_bit(event, &bcs->event);
- schedule_work(&bcs->tqueue);
-}
-
-/************************************************/
-/* select a b-channel entry matching and active */
-/************************************************/
-static
-struct BCState *
-Sel_BCS(struct IsdnCardState *cs, int channel)
-{
- if (cs->bcs[0].mode && (cs->bcs[0].channel == channel))
- return (&cs->bcs[0]);
- else if (cs->bcs[1].mode && (cs->bcs[1].channel == channel))
- return (&cs->bcs[1]);
- else
- return (NULL);
-}
-
-/***************************************/
-/* clear the desired B-channel rx fifo */
-/***************************************/
-static void hfcpci_clear_fifo_rx(struct IsdnCardState *cs, int fifo)
-{ u_char fifo_state;
- bzfifo_type *bzr;
-
- if (fifo) {
- bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2;
- fifo_state = cs->hw.hfcpci.fifo_en & HFCPCI_FIFOEN_B2RX;
- } else {
- bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b1;
- fifo_state = cs->hw.hfcpci.fifo_en & HFCPCI_FIFOEN_B1RX;
- }
- if (fifo_state)
- cs->hw.hfcpci.fifo_en ^= fifo_state;
- Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
- cs->hw.hfcpci.last_bfifo_cnt[fifo] = 0;
- bzr->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1;
- bzr->za[MAX_B_FRAMES].z2 = bzr->za[MAX_B_FRAMES].z1;
- bzr->f1 = MAX_B_FRAMES;
- bzr->f2 = bzr->f1; /* init F pointers to remain constant */
- if (fifo_state)
- cs->hw.hfcpci.fifo_en |= fifo_state;
- Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
-}
-
-/***************************************/
-/* clear the desired B-channel tx fifo */
-/***************************************/
-static void hfcpci_clear_fifo_tx(struct IsdnCardState *cs, int fifo)
-{ u_char fifo_state;
- bzfifo_type *bzt;
-
- if (fifo) {
- bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b2;
- fifo_state = cs->hw.hfcpci.fifo_en & HFCPCI_FIFOEN_B2TX;
- } else {
- bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b1;
- fifo_state = cs->hw.hfcpci.fifo_en & HFCPCI_FIFOEN_B1TX;
- }
- if (fifo_state)
- cs->hw.hfcpci.fifo_en ^= fifo_state;
- Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
- bzt->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1;
- bzt->za[MAX_B_FRAMES].z2 = bzt->za[MAX_B_FRAMES].z1;
- bzt->f1 = MAX_B_FRAMES;
- bzt->f2 = bzt->f1; /* init F pointers to remain constant */
- if (fifo_state)
- cs->hw.hfcpci.fifo_en |= fifo_state;
- Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
-}
-
-/*********************************************/
-/* read a complete B-frame out of the buffer */
-/*********************************************/
-static struct sk_buff
-*
-hfcpci_empty_fifo(struct BCState *bcs, bzfifo_type *bz, u_char *bdata, int count)
-{
- u_char *ptr, *ptr1, new_f2;
- struct sk_buff *skb;
- struct IsdnCardState *cs = bcs->cs;
- int maxlen, new_z2;
- z_type *zp;
-
- if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
- debugl1(cs, "hfcpci_empty_fifo");
- zp = &bz->za[bz->f2]; /* point to Z-Regs */
- new_z2 = zp->z2 + count; /* new position in fifo */
- if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
- new_z2 -= B_FIFO_SIZE; /* buffer wrap */
- new_f2 = (bz->f2 + 1) & MAX_B_FRAMES;
- if ((count > HSCX_BUFMAX + 3) || (count < 4) ||
- (*(bdata + (zp->z1 - B_SUB_VAL)))) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "hfcpci_empty_fifo: incoming packet invalid length %d or crc", count);
-#ifdef ERROR_STATISTIC
- bcs->err_inv++;
-#endif
- bz->za[new_f2].z2 = new_z2;
- bz->f2 = new_f2; /* next buffer */
- skb = NULL;
- } else if (!(skb = dev_alloc_skb(count - 3)))
- printk(KERN_WARNING "HFCPCI: receive out of memory\n");
- else {
- count -= 3;
- ptr = skb_put(skb, count);
-
- if (zp->z2 + count <= B_FIFO_SIZE + B_SUB_VAL)
- maxlen = count; /* complete transfer */
- else
- maxlen = B_FIFO_SIZE + B_SUB_VAL - zp->z2; /* maximum */
-
- ptr1 = bdata + (zp->z2 - B_SUB_VAL); /* start of data */
- memcpy(ptr, ptr1, maxlen); /* copy data */
- count -= maxlen;
-
- if (count) { /* rest remaining */
- ptr += maxlen;
- ptr1 = bdata; /* start of buffer */
- memcpy(ptr, ptr1, count); /* rest */
- }
- bz->za[new_f2].z2 = new_z2;
- bz->f2 = new_f2; /* next buffer */
-
- }
- return (skb);
-}
-
-/*******************************/
-/* D-channel receive procedure */
-/*******************************/
-static
-int
-receive_dmsg(struct IsdnCardState *cs)
-{
- struct sk_buff *skb;
- int maxlen;
- int rcnt, total;
- int count = 5;
- u_char *ptr, *ptr1;
- dfifo_type *df;
- z_type *zp;
-
- df = &((fifo_area *) (cs->hw.hfcpci.fifos))->d_chan.d_rx;
- if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- debugl1(cs, "rec_dmsg blocked");
- return (1);
- }
- while (((df->f1 & D_FREG_MASK) != (df->f2 & D_FREG_MASK)) && count--) {
- zp = &df->za[df->f2 & D_FREG_MASK];
- rcnt = zp->z1 - zp->z2;
- if (rcnt < 0)
- rcnt += D_FIFO_SIZE;
- rcnt++;
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "hfcpci recd f1(%d) f2(%d) z1(%x) z2(%x) cnt(%d)",
- df->f1, df->f2, zp->z1, zp->z2, rcnt);
-
- if ((rcnt > MAX_DFRAME_LEN + 3) || (rcnt < 4) ||
- (df->data[zp->z1])) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "empty_fifo hfcpci packet inv. len %d or crc %d", rcnt, df->data[zp->z1]);
-#ifdef ERROR_STATISTIC
- cs->err_rx++;
-#endif
- df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1); /* next buffer */
- df->za[df->f2 & D_FREG_MASK].z2 = (zp->z2 + rcnt) & (D_FIFO_SIZE - 1);
- } else if ((skb = dev_alloc_skb(rcnt - 3))) {
- total = rcnt;
- rcnt -= 3;
- ptr = skb_put(skb, rcnt);
-
- if (zp->z2 + rcnt <= D_FIFO_SIZE)
- maxlen = rcnt; /* complete transfer */
- else
- maxlen = D_FIFO_SIZE - zp->z2; /* maximum */
-
- ptr1 = df->data + zp->z2; /* start of data */
- memcpy(ptr, ptr1, maxlen); /* copy data */
- rcnt -= maxlen;
-
- if (rcnt) { /* rest remaining */
- ptr += maxlen;
- ptr1 = df->data; /* start of buffer */
- memcpy(ptr, ptr1, rcnt); /* rest */
- }
- df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1); /* next buffer */
- df->za[df->f2 & D_FREG_MASK].z2 = (zp->z2 + total) & (D_FIFO_SIZE - 1);
-
- skb_queue_tail(&cs->rq, skb);
- sched_event_D_pci(cs, D_RCVBUFREADY);
- } else
- printk(KERN_WARNING "HFC-PCI: D receive out of memory\n");
- }
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- return (1);
-}
-
-/*******************************************************************************/
-/* check for transparent receive data and read max one threshold size if avail */
-/*******************************************************************************/
-static int
-hfcpci_empty_fifo_trans(struct BCState *bcs, bzfifo_type *bz, u_char *bdata)
-{
- unsigned short *z1r, *z2r;
- int new_z2, fcnt, maxlen;
- struct sk_buff *skb;
- u_char *ptr, *ptr1;
-
- z1r = &bz->za[MAX_B_FRAMES].z1; /* pointer to z reg */
- z2r = z1r + 1;
-
- if (!(fcnt = *z1r - *z2r))
- return (0); /* no data avail */
-
- if (fcnt <= 0)
- fcnt += B_FIFO_SIZE; /* bytes actually buffered */
- if (fcnt > HFCPCI_BTRANS_THRESHOLD)
- fcnt = HFCPCI_BTRANS_THRESHOLD; /* limit size */
-
- new_z2 = *z2r + fcnt; /* new position in fifo */
- if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
- new_z2 -= B_FIFO_SIZE; /* buffer wrap */
-
- if (!(skb = dev_alloc_skb(fcnt)))
- printk(KERN_WARNING "HFCPCI: receive out of memory\n");
- else {
- ptr = skb_put(skb, fcnt);
- if (*z2r + fcnt <= B_FIFO_SIZE + B_SUB_VAL)
- maxlen = fcnt; /* complete transfer */
- else
- maxlen = B_FIFO_SIZE + B_SUB_VAL - *z2r; /* maximum */
-
- ptr1 = bdata + (*z2r - B_SUB_VAL); /* start of data */
- memcpy(ptr, ptr1, maxlen); /* copy data */
- fcnt -= maxlen;
-
- if (fcnt) { /* rest remaining */
- ptr += maxlen;
- ptr1 = bdata; /* start of buffer */
- memcpy(ptr, ptr1, fcnt); /* rest */
- }
- skb_queue_tail(&bcs->rqueue, skb);
- hfcpci_sched_event(bcs, B_RCVBUFREADY);
- }
-
- *z2r = new_z2; /* new position */
- return (1);
-} /* hfcpci_empty_fifo_trans */
-
-/**********************************/
-/* B-channel main receive routine */
-/**********************************/
-static void
-main_rec_hfcpci(struct BCState *bcs)
-{
- struct IsdnCardState *cs = bcs->cs;
- int rcnt, real_fifo;
- int receive, count = 5;
- struct sk_buff *skb;
- bzfifo_type *bz;
- u_char *bdata;
- z_type *zp;
-
-
- if ((bcs->channel) && (!cs->hw.hfcpci.bswapped)) {
- bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2;
- bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxdat_b2;
- real_fifo = 1;
- } else {
- bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b1;
- bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxdat_b1;
- real_fifo = 0;
- }
-Begin:
- count--;
- if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- debugl1(cs, "rec_data %d blocked", bcs->channel);
- return;
- }
- if (bz->f1 != bz->f2) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfcpci rec %d f1(%d) f2(%d)",
- bcs->channel, bz->f1, bz->f2);
- zp = &bz->za[bz->f2];
-
- rcnt = zp->z1 - zp->z2;
- if (rcnt < 0)
- rcnt += B_FIFO_SIZE;
- rcnt++;
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfcpci rec %d z1(%x) z2(%x) cnt(%d)",
- bcs->channel, zp->z1, zp->z2, rcnt);
- if ((skb = hfcpci_empty_fifo(bcs, bz, bdata, rcnt))) {
- skb_queue_tail(&bcs->rqueue, skb);
- hfcpci_sched_event(bcs, B_RCVBUFREADY);
- }
- rcnt = bz->f1 - bz->f2;
- if (rcnt < 0)
- rcnt += MAX_B_FRAMES + 1;
- if (cs->hw.hfcpci.last_bfifo_cnt[real_fifo] > rcnt + 1) {
- rcnt = 0;
- hfcpci_clear_fifo_rx(cs, real_fifo);
- }
- cs->hw.hfcpci.last_bfifo_cnt[real_fifo] = rcnt;
- if (rcnt > 1)
- receive = 1;
- else
- receive = 0;
- } else if (bcs->mode == L1_MODE_TRANS)
- receive = hfcpci_empty_fifo_trans(bcs, bz, bdata);
- else
- receive = 0;
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- if (count && receive)
- goto Begin;
-}
-
-/**************************/
-/* D-channel send routine */
-/**************************/
-static void
-hfcpci_fill_dfifo(struct IsdnCardState *cs)
-{
- int fcnt;
- int count, new_z1, maxlen;
- dfifo_type *df;
- u_char *src, *dst, new_f1;
-
- if (!cs->tx_skb)
- return;
- if (cs->tx_skb->len <= 0)
- return;
-
- df = &((fifo_area *) (cs->hw.hfcpci.fifos))->d_chan.d_tx;
-
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "hfcpci_fill_Dfifo f1(%d) f2(%d) z1(f1)(%x)",
- df->f1, df->f2,
- df->za[df->f1 & D_FREG_MASK].z1);
- fcnt = df->f1 - df->f2; /* frame count actually buffered */
- if (fcnt < 0)
- fcnt += (MAX_D_FRAMES + 1); /* if wrap around */
- if (fcnt > (MAX_D_FRAMES - 1)) {
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "hfcpci_fill_Dfifo more as 14 frames");
-#ifdef ERROR_STATISTIC
- cs->err_tx++;
-#endif
- return;
- }
- /* now determine free bytes in FIFO buffer */
- count = df->za[df->f2 & D_FREG_MASK].z2 - df->za[df->f1 & D_FREG_MASK].z1 - 1;
- if (count <= 0)
- count += D_FIFO_SIZE; /* count now contains available bytes */
-
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "hfcpci_fill_Dfifo count(%u/%d)",
- cs->tx_skb->len, count);
- if (count < cs->tx_skb->len) {
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "hfcpci_fill_Dfifo no fifo mem");
- return;
- }
- count = cs->tx_skb->len; /* get frame len */
- new_z1 = (df->za[df->f1 & D_FREG_MASK].z1 + count) & (D_FIFO_SIZE - 1);
- new_f1 = ((df->f1 + 1) & D_FREG_MASK) | (D_FREG_MASK + 1);
- src = cs->tx_skb->data; /* source pointer */
- dst = df->data + df->za[df->f1 & D_FREG_MASK].z1;
- maxlen = D_FIFO_SIZE - df->za[df->f1 & D_FREG_MASK].z1; /* end fifo */
- if (maxlen > count)
- maxlen = count; /* limit size */
- memcpy(dst, src, maxlen); /* first copy */
-
- count -= maxlen; /* remaining bytes */
- if (count) {
- dst = df->data; /* start of buffer */
- src += maxlen; /* new position */
- memcpy(dst, src, count);
- }
- df->za[new_f1 & D_FREG_MASK].z1 = new_z1; /* for next buffer */
- df->za[df->f1 & D_FREG_MASK].z1 = new_z1; /* new pos actual buffer */
- df->f1 = new_f1; /* next frame */
-
- dev_kfree_skb_any(cs->tx_skb);
- cs->tx_skb = NULL;
-}
-
-/**************************/
-/* B-channel send routine */
-/**************************/
-static void
-hfcpci_fill_fifo(struct BCState *bcs)
-{
- struct IsdnCardState *cs = bcs->cs;
- int maxlen, fcnt;
- int count, new_z1;
- bzfifo_type *bz;
- u_char *bdata;
- u_char new_f1, *src, *dst;
- unsigned short *z1t, *z2t;
-
- if (!bcs->tx_skb)
- return;
- if (bcs->tx_skb->len <= 0)
- return;
-
- if ((bcs->channel) && (!cs->hw.hfcpci.bswapped)) {
- bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b2;
- bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txdat_b2;
- } else {
- bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b1;
- bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txdat_b1;
- }
-
- if (bcs->mode == L1_MODE_TRANS) {
- z1t = &bz->za[MAX_B_FRAMES].z1;
- z2t = z1t + 1;
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfcpci_fill_fifo_trans %d z1(%x) z2(%x)",
- bcs->channel, *z1t, *z2t);
- fcnt = *z2t - *z1t;
- if (fcnt <= 0)
- fcnt += B_FIFO_SIZE; /* fcnt contains available bytes in fifo */
- fcnt = B_FIFO_SIZE - fcnt; /* remaining bytes to send */
-
- while ((fcnt < 2 * HFCPCI_BTRANS_THRESHOLD) && (bcs->tx_skb)) {
- if (bcs->tx_skb->len < B_FIFO_SIZE - fcnt) {
- /* data is suitable for fifo */
- count = bcs->tx_skb->len;
-
- new_z1 = *z1t + count; /* new buffer Position */
- if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
- new_z1 -= B_FIFO_SIZE; /* buffer wrap */
- src = bcs->tx_skb->data; /* source pointer */
- dst = bdata + (*z1t - B_SUB_VAL);
- maxlen = (B_FIFO_SIZE + B_SUB_VAL) - *z1t; /* end of fifo */
- if (maxlen > count)
- maxlen = count; /* limit size */
- memcpy(dst, src, maxlen); /* first copy */
-
- count -= maxlen; /* remaining bytes */
- if (count) {
- dst = bdata; /* start of buffer */
- src += maxlen; /* new position */
- memcpy(dst, src, count);
- }
- bcs->tx_cnt -= bcs->tx_skb->len;
- fcnt += bcs->tx_skb->len;
- *z1t = new_z1; /* now send data */
- } else if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfcpci_fill_fifo_trans %d frame length %d discarded",
- bcs->channel, bcs->tx_skb->len);
-
- if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
- (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
- u_long flags;
- spin_lock_irqsave(&bcs->aclock, flags);
- bcs->ackcnt += bcs->tx_skb->len;
- spin_unlock_irqrestore(&bcs->aclock, flags);
- schedule_event(bcs, B_ACKPENDING);
- }
-
- dev_consume_skb_any(bcs->tx_skb);
- bcs->tx_skb = skb_dequeue(&bcs->squeue); /* fetch next data */
- }
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- return;
- }
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfcpci_fill_fifo_hdlc %d f1(%d) f2(%d) z1(f1)(%x)",
- bcs->channel, bz->f1, bz->f2,
- bz->za[bz->f1].z1);
-
- fcnt = bz->f1 - bz->f2; /* frame count actually buffered */
- if (fcnt < 0)
- fcnt += (MAX_B_FRAMES + 1); /* if wrap around */
- if (fcnt > (MAX_B_FRAMES - 1)) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfcpci_fill_Bfifo more as 14 frames");
- return;
- }
- /* now determine free bytes in FIFO buffer */
- count = bz->za[bz->f2].z2 - bz->za[bz->f1].z1 - 1;
- if (count <= 0)
- count += B_FIFO_SIZE; /* count now contains available bytes */
-
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfcpci_fill_fifo %d count(%u/%d),%lx",
- bcs->channel, bcs->tx_skb->len,
- count, current->state);
-
- if (count < bcs->tx_skb->len) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfcpci_fill_fifo no fifo mem");
- return;
- }
- count = bcs->tx_skb->len; /* get frame len */
- new_z1 = bz->za[bz->f1].z1 + count; /* new buffer Position */
- if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
- new_z1 -= B_FIFO_SIZE; /* buffer wrap */
-
- new_f1 = ((bz->f1 + 1) & MAX_B_FRAMES);
- src = bcs->tx_skb->data; /* source pointer */
- dst = bdata + (bz->za[bz->f1].z1 - B_SUB_VAL);
- maxlen = (B_FIFO_SIZE + B_SUB_VAL) - bz->za[bz->f1].z1; /* end fifo */
- if (maxlen > count)
- maxlen = count; /* limit size */
- memcpy(dst, src, maxlen); /* first copy */
-
- count -= maxlen; /* remaining bytes */
- if (count) {
- dst = bdata; /* start of buffer */
- src += maxlen; /* new position */
- memcpy(dst, src, count);
- }
- bcs->tx_cnt -= bcs->tx_skb->len;
- if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
- (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
- u_long flags;
- spin_lock_irqsave(&bcs->aclock, flags);
- bcs->ackcnt += bcs->tx_skb->len;
- spin_unlock_irqrestore(&bcs->aclock, flags);
- schedule_event(bcs, B_ACKPENDING);
- }
-
- bz->za[new_f1].z1 = new_z1; /* for next buffer */
- bz->f1 = new_f1; /* next frame */
-
- dev_kfree_skb_any(bcs->tx_skb);
- bcs->tx_skb = NULL;
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
-}
-
-/**********************************************/
-/* D-channel l1 state call for leased NT-mode */
-/**********************************************/
-static void
-dch_nt_l2l1(struct PStack *st, int pr, void *arg)
-{
- struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
-
- switch (pr) {
- case (PH_DATA | REQUEST):
- case (PH_PULL | REQUEST):
- case (PH_PULL | INDICATION):
- st->l1.l1hw(st, pr, arg);
- break;
- case (PH_ACTIVATE | REQUEST):
- st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
- break;
- case (PH_TESTLOOP | REQUEST):
- if (1 & (long) arg)
- debugl1(cs, "PH_TEST_LOOP B1");
- if (2 & (long) arg)
- debugl1(cs, "PH_TEST_LOOP B2");
- if (!(3 & (long) arg))
- debugl1(cs, "PH_TEST_LOOP DISABLED");
- st->l1.l1hw(st, HW_TESTLOOP | REQUEST, arg);
- break;
- default:
- if (cs->debug)
- debugl1(cs, "dch_nt_l2l1 msg %04X unhandled", pr);
- break;
- }
-}
-
-
-
-/***********************/
-/* set/reset echo mode */
-/***********************/
-static int
-hfcpci_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic)
-{
- u_long flags;
- int i = *(unsigned int *) ic->parm.num;
-
- if ((ic->arg == 98) &&
- (!(cs->hw.hfcpci.int_m1 & (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC + HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC)))) {
- spin_lock_irqsave(&cs->lock, flags);
- Write_hfc(cs, HFCPCI_CLKDEL, CLKDEL_NT); /* ST-Bit delay for NT-Mode */
- Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 0); /* HFC ST G0 */
- udelay(10);
- cs->hw.hfcpci.sctrl |= SCTRL_MODE_NT;
- Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl); /* set NT-mode */
- udelay(10);
- Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 1); /* HFC ST G1 */
- udelay(10);
- Write_hfc(cs, HFCPCI_STATES, 1 | HFCPCI_ACTIVATE | HFCPCI_DO_ACTION);
- cs->dc.hfcpci.ph_state = 1;
- cs->hw.hfcpci.nt_mode = 1;
- cs->hw.hfcpci.nt_timer = 0;
- cs->stlist->l2.l2l1 = dch_nt_l2l1;
- spin_unlock_irqrestore(&cs->lock, flags);
- debugl1(cs, "NT mode activated");
- return (0);
- }
- if ((cs->chanlimit > 1) || (cs->hw.hfcpci.bswapped) ||
- (cs->hw.hfcpci.nt_mode) || (ic->arg != 12))
- return (-EINVAL);
-
- spin_lock_irqsave(&cs->lock, flags);
- if (i) {
- cs->logecho = 1;
- cs->hw.hfcpci.trm |= 0x20; /* enable echo chan */
- cs->hw.hfcpci.int_m1 |= HFCPCI_INTS_B2REC;
- cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2RX;
- } else {
- cs->logecho = 0;
- cs->hw.hfcpci.trm &= ~0x20; /* disable echo chan */
- cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_B2REC;
- cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2RX;
- }
- cs->hw.hfcpci.sctrl_r &= ~SCTRL_B2_ENA;
- cs->hw.hfcpci.sctrl &= ~SCTRL_B2_ENA;
- cs->hw.hfcpci.conn |= 0x10; /* B2-IOM -> B2-ST */
- cs->hw.hfcpci.ctmt &= ~2;
- Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt);
- Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r);
- Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl);
- Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
- Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm);
- Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
- Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
-} /* hfcpci_auxcmd */
-
-/*****************************/
-/* E-channel receive routine */
-/*****************************/
-static void
-receive_emsg(struct IsdnCardState *cs)
-{
- int rcnt;
- int receive, count = 5;
- bzfifo_type *bz;
- u_char *bdata;
- z_type *zp;
- u_char *ptr, *ptr1, new_f2;
- int total, maxlen, new_z2;
- u_char e_buffer[256];
-
- bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2;
- bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxdat_b2;
-Begin:
- count--;
- if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- debugl1(cs, "echo_rec_data blocked");
- return;
- }
- if (bz->f1 != bz->f2) {
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "hfcpci e_rec f1(%d) f2(%d)",
- bz->f1, bz->f2);
- zp = &bz->za[bz->f2];
-
- rcnt = zp->z1 - zp->z2;
- if (rcnt < 0)
- rcnt += B_FIFO_SIZE;
- rcnt++;
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "hfcpci e_rec z1(%x) z2(%x) cnt(%d)",
- zp->z1, zp->z2, rcnt);
- new_z2 = zp->z2 + rcnt; /* new position in fifo */
- if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
- new_z2 -= B_FIFO_SIZE; /* buffer wrap */
- new_f2 = (bz->f2 + 1) & MAX_B_FRAMES;
- if ((rcnt > 256 + 3) || (count < 4) ||
- (*(bdata + (zp->z1 - B_SUB_VAL)))) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "hfcpci_empty_echan: incoming packet invalid length %d or crc", rcnt);
- bz->za[new_f2].z2 = new_z2;
- bz->f2 = new_f2; /* next buffer */
- } else {
- total = rcnt;
- rcnt -= 3;
- ptr = e_buffer;
-
- if (zp->z2 <= B_FIFO_SIZE + B_SUB_VAL)
- maxlen = rcnt; /* complete transfer */
- else
- maxlen = B_FIFO_SIZE + B_SUB_VAL - zp->z2; /* maximum */
-
- ptr1 = bdata + (zp->z2 - B_SUB_VAL); /* start of data */
- memcpy(ptr, ptr1, maxlen); /* copy data */
- rcnt -= maxlen;
-
- if (rcnt) { /* rest remaining */
- ptr += maxlen;
- ptr1 = bdata; /* start of buffer */
- memcpy(ptr, ptr1, rcnt); /* rest */
- }
- bz->za[new_f2].z2 = new_z2;
- bz->f2 = new_f2; /* next buffer */
- if (cs->debug & DEB_DLOG_HEX) {
- ptr = cs->dlog;
- if ((total - 3) < MAX_DLOG_SPACE / 3 - 10) {
- *ptr++ = 'E';
- *ptr++ = 'C';
- *ptr++ = 'H';
- *ptr++ = 'O';
- *ptr++ = ':';
- ptr += QuickHex(ptr, e_buffer, total - 3);
- ptr--;
- *ptr++ = '\n';
- *ptr = 0;
- HiSax_putstatus(cs, NULL, cs->dlog);
- } else
- HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", total - 3);
- }
- }
-
- rcnt = bz->f1 - bz->f2;
- if (rcnt < 0)
- rcnt += MAX_B_FRAMES + 1;
- if (rcnt > 1)
- receive = 1;
- else
- receive = 0;
- } else
- receive = 0;
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- if (count && receive)
- goto Begin;
-} /* receive_emsg */
-
-/*********************/
-/* Interrupt handler */
-/*********************/
-static irqreturn_t
-hfcpci_interrupt(int intno, void *dev_id)
-{
- u_long flags;
- struct IsdnCardState *cs = dev_id;
- u_char exval;
- struct BCState *bcs;
- int count = 15;
- u_char val, stat;
-
- if (!(cs->hw.hfcpci.int_m2 & 0x08)) {
- debugl1(cs, "HFC-PCI: int_m2 %x not initialised", cs->hw.hfcpci.int_m2);
- return IRQ_NONE; /* not initialised */
- }
- spin_lock_irqsave(&cs->lock, flags);
- if (HFCPCI_ANYINT & (stat = Read_hfc(cs, HFCPCI_STATUS))) {
- val = Read_hfc(cs, HFCPCI_INT_S1);
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "HFC-PCI: stat(%02x) s1(%02x)", stat, val);
- } else {
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_NONE;
- }
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "HFC-PCI irq %x %s", val,
- test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ?
- "locked" : "unlocked");
- val &= cs->hw.hfcpci.int_m1;
- if (val & 0x40) { /* state machine irq */
- exval = Read_hfc(cs, HFCPCI_STATES) & 0xf;
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcpci.ph_state,
- exval);
- cs->dc.hfcpci.ph_state = exval;
- sched_event_D_pci(cs, D_L1STATECHANGE);
- val &= ~0x40;
- }
- if (val & 0x80) { /* timer irq */
- if (cs->hw.hfcpci.nt_mode) {
- if ((--cs->hw.hfcpci.nt_timer) < 0)
- sched_event_D_pci(cs, D_L1STATECHANGE);
- }
- val &= ~0x80;
- Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt | HFCPCI_CLTIMER);
- }
- while (val) {
- if (test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- cs->hw.hfcpci.int_s1 |= val;
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
- }
- if (cs->hw.hfcpci.int_s1 & 0x18) {
- exval = val;
- val = cs->hw.hfcpci.int_s1;
- cs->hw.hfcpci.int_s1 = exval;
- }
- if (val & 0x08) {
- if (!(bcs = Sel_BCS(cs, cs->hw.hfcpci.bswapped ? 1 : 0))) {
- if (cs->debug)
- debugl1(cs, "hfcpci spurious 0x08 IRQ");
- } else
- main_rec_hfcpci(bcs);
- }
- if (val & 0x10) {
- if (cs->logecho)
- receive_emsg(cs);
- else if (!(bcs = Sel_BCS(cs, 1))) {
- if (cs->debug)
- debugl1(cs, "hfcpci spurious 0x10 IRQ");
- } else
- main_rec_hfcpci(bcs);
- }
- if (val & 0x01) {
- if (!(bcs = Sel_BCS(cs, cs->hw.hfcpci.bswapped ? 1 : 0))) {
- if (cs->debug)
- debugl1(cs, "hfcpci spurious 0x01 IRQ");
- } else {
- if (bcs->tx_skb) {
- if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- hfcpci_fill_fifo(bcs);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- } else
- debugl1(cs, "fill_data %d blocked", bcs->channel);
- } else {
- if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
- if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- hfcpci_fill_fifo(bcs);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- } else
- debugl1(cs, "fill_data %d blocked", bcs->channel);
- } else {
- hfcpci_sched_event(bcs, B_XMTBUFREADY);
- }
- }
- }
- }
- if (val & 0x02) {
- if (!(bcs = Sel_BCS(cs, 1))) {
- if (cs->debug)
- debugl1(cs, "hfcpci spurious 0x02 IRQ");
- } else {
- if (bcs->tx_skb) {
- if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- hfcpci_fill_fifo(bcs);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- } else
- debugl1(cs, "fill_data %d blocked", bcs->channel);
- } else {
- if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
- if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- hfcpci_fill_fifo(bcs);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- } else
- debugl1(cs, "fill_data %d blocked", bcs->channel);
- } else {
- hfcpci_sched_event(bcs, B_XMTBUFREADY);
- }
- }
- }
- }
- if (val & 0x20) { /* receive dframe */
- receive_dmsg(cs);
- }
- if (val & 0x04) { /* dframe transmitted */
- if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
- del_timer(&cs->dbusytimer);
- if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
- sched_event_D_pci(cs, D_CLEARBUSY);
- if (cs->tx_skb) {
- if (cs->tx_skb->len) {
- if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- hfcpci_fill_dfifo(cs);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- } else {
- debugl1(cs, "hfcpci_fill_dfifo irq blocked");
- }
- goto afterXPR;
- } else {
- dev_kfree_skb_irq(cs->tx_skb);
- cs->tx_cnt = 0;
- cs->tx_skb = NULL;
- }
- }
- if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
- cs->tx_cnt = 0;
- if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- hfcpci_fill_dfifo(cs);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- } else {
- debugl1(cs, "hfcpci_fill_dfifo irq blocked");
- }
- } else
- sched_event_D_pci(cs, D_XMTBUFREADY);
- }
- afterXPR:
- if (cs->hw.hfcpci.int_s1 && count--) {
- val = cs->hw.hfcpci.int_s1;
- cs->hw.hfcpci.int_s1 = 0;
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "HFC-PCI irq %x loop %d", val, 15 - count);
- } else
- val = 0;
- }
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-/********************************************************************/
-/* timer callback for D-chan busy resolution. Currently no function */
-/********************************************************************/
-static void
-hfcpci_dbusy_timer(struct timer_list *t)
-{
-}
-
-/*************************************/
-/* Layer 1 D-channel hardware access */
-/*************************************/
-static void
-HFCPCI_l1hw(struct PStack *st, int pr, void *arg)
-{
- u_long flags;
- struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
- struct sk_buff *skb = arg;
-
- switch (pr) {
- case (PH_DATA | REQUEST):
- if (cs->debug & DEB_DLOG_HEX)
- LogFrame(cs, skb->data, skb->len);
- if (cs->debug & DEB_DLOG_VERBOSE)
- dlogframe(cs, skb, 0);
- spin_lock_irqsave(&cs->lock, flags);
- if (cs->tx_skb) {
- skb_queue_tail(&cs->sq, skb);
-#ifdef L2FRAME_DEBUG /* psa */
- if (cs->debug & L1_DEB_LAPD)
- Logl2Frame(cs, skb, "PH_DATA Queued", 0);
-#endif
- } else {
- cs->tx_skb = skb;
- cs->tx_cnt = 0;
-#ifdef L2FRAME_DEBUG /* psa */
- if (cs->debug & L1_DEB_LAPD)
- Logl2Frame(cs, skb, "PH_DATA", 0);
-#endif
- if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- hfcpci_fill_dfifo(cs);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- } else
- debugl1(cs, "hfcpci_fill_dfifo blocked");
-
- }
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (PH_PULL | INDICATION):
- spin_lock_irqsave(&cs->lock, flags);
- if (cs->tx_skb) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
- skb_queue_tail(&cs->sq, skb);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- }
- if (cs->debug & DEB_DLOG_HEX)
- LogFrame(cs, skb->data, skb->len);
- if (cs->debug & DEB_DLOG_VERBOSE)
- dlogframe(cs, skb, 0);
- cs->tx_skb = skb;
- cs->tx_cnt = 0;
-#ifdef L2FRAME_DEBUG /* psa */
- if (cs->debug & L1_DEB_LAPD)
- Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
-#endif
- if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- hfcpci_fill_dfifo(cs);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- } else
- debugl1(cs, "hfcpci_fill_dfifo blocked");
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (PH_PULL | REQUEST):
-#ifdef L2FRAME_DEBUG /* psa */
- if (cs->debug & L1_DEB_LAPD)
- debugl1(cs, "-> PH_REQUEST_PULL");
-#endif
- spin_lock_irqsave(&cs->lock, flags);
- if (!cs->tx_skb) {
- test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
- } else
- test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (HW_RESET | REQUEST):
- spin_lock_irqsave(&cs->lock, flags);
- Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 3); /* HFC ST 3 */
- udelay(6);
- Write_hfc(cs, HFCPCI_STATES, 3); /* HFC ST 2 */
- cs->hw.hfcpci.mst_m |= HFCPCI_MASTER;
- Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m);
- Write_hfc(cs, HFCPCI_STATES, HFCPCI_ACTIVATE | HFCPCI_DO_ACTION);
- spin_unlock_irqrestore(&cs->lock, flags);
- l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
- break;
- case (HW_ENABLE | REQUEST):
- spin_lock_irqsave(&cs->lock, flags);
- Write_hfc(cs, HFCPCI_STATES, HFCPCI_DO_ACTION);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (HW_DEACTIVATE | REQUEST):
- spin_lock_irqsave(&cs->lock, flags);
- cs->hw.hfcpci.mst_m &= ~HFCPCI_MASTER;
- Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (HW_INFO3 | REQUEST):
- spin_lock_irqsave(&cs->lock, flags);
- cs->hw.hfcpci.mst_m |= HFCPCI_MASTER;
- Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (HW_TESTLOOP | REQUEST):
- spin_lock_irqsave(&cs->lock, flags);
- switch ((long) arg) {
- case (1):
- Write_hfc(cs, HFCPCI_B1_SSL, 0x80); /* tx slot */
- Write_hfc(cs, HFCPCI_B1_RSL, 0x80); /* rx slot */
- cs->hw.hfcpci.conn = (cs->hw.hfcpci.conn & ~7) | 1;
- Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
- break;
-
- case (2):
- Write_hfc(cs, HFCPCI_B2_SSL, 0x81); /* tx slot */
- Write_hfc(cs, HFCPCI_B2_RSL, 0x81); /* rx slot */
- cs->hw.hfcpci.conn = (cs->hw.hfcpci.conn & ~0x38) | 0x08;
- Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
- break;
-
- default:
- spin_unlock_irqrestore(&cs->lock, flags);
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "hfcpci_l1hw loop invalid %4lx", (long) arg);
- return;
- }
- cs->hw.hfcpci.trm |= 0x80; /* enable IOM-loop */
- Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- default:
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "hfcpci_l1hw unknown pr %4x", pr);
- break;
- }
-}
-
-/***********************************************/
-/* called during init setting l1 stack pointer */
-/***********************************************/
-static void
-setstack_hfcpci(struct PStack *st, struct IsdnCardState *cs)
-{
- st->l1.l1hw = HFCPCI_l1hw;
-}
-
-/**************************************/
-/* send B-channel data if not blocked */
-/**************************************/
-static void
-hfcpci_send_data(struct BCState *bcs)
-{
- struct IsdnCardState *cs = bcs->cs;
-
- if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- hfcpci_fill_fifo(bcs);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- } else
- debugl1(cs, "send_data %d blocked", bcs->channel);
-}
-
-/***************************************************************/
-/* activate/deactivate hardware for selected channels and mode */
-/***************************************************************/
-static void
-mode_hfcpci(struct BCState *bcs, int mode, int bc)
-{
- struct IsdnCardState *cs = bcs->cs;
- int fifo2;
-
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "HFCPCI bchannel mode %d bchan %d/%d",
- mode, bc, bcs->channel);
- bcs->mode = mode;
- bcs->channel = bc;
- fifo2 = bc;
- if (cs->chanlimit > 1) {
- cs->hw.hfcpci.bswapped = 0; /* B1 and B2 normal mode */
- cs->hw.hfcpci.sctrl_e &= ~0x80;
- } else {
- if (bc) {
- if (mode != L1_MODE_NULL) {
- cs->hw.hfcpci.bswapped = 1; /* B1 and B2 exchanged */
- cs->hw.hfcpci.sctrl_e |= 0x80;
- } else {
- cs->hw.hfcpci.bswapped = 0; /* B1 and B2 normal mode */
- cs->hw.hfcpci.sctrl_e &= ~0x80;
- }
- fifo2 = 0;
- } else {
- cs->hw.hfcpci.bswapped = 0; /* B1 and B2 normal mode */
- cs->hw.hfcpci.sctrl_e &= ~0x80;
- }
- }
- switch (mode) {
- case (L1_MODE_NULL):
- if (bc) {
- cs->hw.hfcpci.sctrl &= ~SCTRL_B2_ENA;
- cs->hw.hfcpci.sctrl_r &= ~SCTRL_B2_ENA;
- } else {
- cs->hw.hfcpci.sctrl &= ~SCTRL_B1_ENA;
- cs->hw.hfcpci.sctrl_r &= ~SCTRL_B1_ENA;
- }
- if (fifo2) {
- cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2;
- cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
- } else {
- cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B1;
- cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
- }
- break;
- case (L1_MODE_TRANS):
- hfcpci_clear_fifo_rx(cs, fifo2);
- hfcpci_clear_fifo_tx(cs, fifo2);
- if (bc) {
- cs->hw.hfcpci.sctrl |= SCTRL_B2_ENA;
- cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA;
- } else {
- cs->hw.hfcpci.sctrl |= SCTRL_B1_ENA;
- cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA;
- }
- if (fifo2) {
- cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2;
- cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
- cs->hw.hfcpci.ctmt |= 2;
- cs->hw.hfcpci.conn &= ~0x18;
- } else {
- cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B1;
- cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
- cs->hw.hfcpci.ctmt |= 1;
- cs->hw.hfcpci.conn &= ~0x03;
- }
- break;
- case (L1_MODE_HDLC):
- hfcpci_clear_fifo_rx(cs, fifo2);
- hfcpci_clear_fifo_tx(cs, fifo2);
- if (bc) {
- cs->hw.hfcpci.sctrl |= SCTRL_B2_ENA;
- cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA;
- } else {
- cs->hw.hfcpci.sctrl |= SCTRL_B1_ENA;
- cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA;
- }
- if (fifo2) {
- cs->hw.hfcpci.last_bfifo_cnt[1] = 0;
- cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2;
- cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
- cs->hw.hfcpci.ctmt &= ~2;
- cs->hw.hfcpci.conn &= ~0x18;
- } else {
- cs->hw.hfcpci.last_bfifo_cnt[0] = 0;
- cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B1;
- cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
- cs->hw.hfcpci.ctmt &= ~1;
- cs->hw.hfcpci.conn &= ~0x03;
- }
- break;
- case (L1_MODE_EXTRN):
- if (bc) {
- cs->hw.hfcpci.conn |= 0x10;
- cs->hw.hfcpci.sctrl |= SCTRL_B2_ENA;
- cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA;
- cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2;
- cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
- } else {
- cs->hw.hfcpci.conn |= 0x02;
- cs->hw.hfcpci.sctrl |= SCTRL_B1_ENA;
- cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA;
- cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B1;
- cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
- }
- break;
- }
- Write_hfc(cs, HFCPCI_SCTRL_E, cs->hw.hfcpci.sctrl_e);
- Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
- Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
- Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl);
- Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r);
- Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt);
- Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
-}
-
-/******************************/
-/* Layer2 -> Layer 1 Transfer */
-/******************************/
-static void
-hfcpci_l2l1(struct PStack *st, int pr, void *arg)
-{
- struct BCState *bcs = st->l1.bcs;
- u_long flags;
- struct sk_buff *skb = arg;
-
- switch (pr) {
- case (PH_DATA | REQUEST):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- if (bcs->tx_skb) {
- skb_queue_tail(&bcs->squeue, skb);
- } else {
- bcs->tx_skb = skb;
-// test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->cs->BC_Send_Data(bcs);
- }
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- break;
- case (PH_PULL | INDICATION):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- if (bcs->tx_skb) {
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n");
- break;
- }
-// test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->tx_skb = skb;
- bcs->cs->BC_Send_Data(bcs);
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- break;
- case (PH_PULL | REQUEST):
- if (!bcs->tx_skb) {
- test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
- } else
- test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- break;
- case (PH_ACTIVATE | REQUEST):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
- mode_hfcpci(bcs, st->l1.mode, st->l1.bc);
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- l1_msg_b(st, pr, arg);
- break;
- case (PH_DEACTIVATE | REQUEST):
- l1_msg_b(st, pr, arg);
- break;
- case (PH_DEACTIVATE | CONFIRM):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- mode_hfcpci(bcs, 0, st->l1.bc);
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
- break;
- }
-}
-
-/******************************************/
-/* deactivate B-channel access and queues */
-/******************************************/
-static void
-close_hfcpci(struct BCState *bcs)
-{
- mode_hfcpci(bcs, 0, bcs->channel);
- if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
- skb_queue_purge(&bcs->rqueue);
- skb_queue_purge(&bcs->squeue);
- if (bcs->tx_skb) {
- dev_kfree_skb_any(bcs->tx_skb);
- bcs->tx_skb = NULL;
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- }
- }
-}
-
-/*************************************/
-/* init B-channel queues and control */
-/*************************************/
-static int
-open_hfcpcistate(struct IsdnCardState *cs, struct BCState *bcs)
-{
- if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
- skb_queue_head_init(&bcs->rqueue);
- skb_queue_head_init(&bcs->squeue);
- }
- bcs->tx_skb = NULL;
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->event = 0;
- bcs->tx_cnt = 0;
- return (0);
-}
-
-/*********************************/
-/* inits the stack for B-channel */
-/*********************************/
-static int
-setstack_2b(struct PStack *st, struct BCState *bcs)
-{
- bcs->channel = st->l1.bc;
- if (open_hfcpcistate(st->l1.hardware, bcs))
- return (-1);
- st->l1.bcs = bcs;
- st->l2.l2l1 = hfcpci_l2l1;
- setstack_manager(st);
- bcs->st = st;
- setstack_l1_B(st);
- return (0);
-}
-
-/***************************/
-/* handle L1 state changes */
-/***************************/
-static void
-hfcpci_bh(struct work_struct *work)
-{
- struct IsdnCardState *cs =
- container_of(work, struct IsdnCardState, tqueue);
- u_long flags;
-// struct PStack *stptr;
-
- if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
- if (!cs->hw.hfcpci.nt_mode)
- switch (cs->dc.hfcpci.ph_state) {
- case (0):
- l1_msg(cs, HW_RESET | INDICATION, NULL);
- break;
- case (3):
- l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
- break;
- case (8):
- l1_msg(cs, HW_RSYNC | INDICATION, NULL);
- break;
- case (6):
- l1_msg(cs, HW_INFO2 | INDICATION, NULL);
- break;
- case (7):
- l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
- break;
- default:
- break;
- } else {
- spin_lock_irqsave(&cs->lock, flags);
- switch (cs->dc.hfcpci.ph_state) {
- case (2):
- if (cs->hw.hfcpci.nt_timer < 0) {
- cs->hw.hfcpci.nt_timer = 0;
- cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER;
- Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
- /* Clear already pending ints */
- Read_hfc(cs, HFCPCI_INT_S1);
- Write_hfc(cs, HFCPCI_STATES, 4 | HFCPCI_LOAD_STATE);
- udelay(10);
- Write_hfc(cs, HFCPCI_STATES, 4);
- cs->dc.hfcpci.ph_state = 4;
- } else {
- cs->hw.hfcpci.int_m1 |= HFCPCI_INTS_TIMER;
- Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
- cs->hw.hfcpci.ctmt &= ~HFCPCI_AUTO_TIMER;
- cs->hw.hfcpci.ctmt |= HFCPCI_TIM3_125;
- Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt | HFCPCI_CLTIMER);
- Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt | HFCPCI_CLTIMER);
- cs->hw.hfcpci.nt_timer = NT_T1_COUNT;
- Write_hfc(cs, HFCPCI_STATES, 2 | HFCPCI_NT_G2_G3); /* allow G2 -> G3 transition */
- }
- break;
- case (1):
- case (3):
- case (4):
- cs->hw.hfcpci.nt_timer = 0;
- cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER;
- Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
- break;
- default:
- break;
- }
- spin_unlock_irqrestore(&cs->lock, flags);
- }
- }
- if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
- DChannel_proc_rcv(cs);
- if (test_and_clear_bit(D_XMTBUFREADY, &cs->event))
- DChannel_proc_xmt(cs);
-}
-
-
-/********************************/
-/* called for card init message */
-/********************************/
-static void
-inithfcpci(struct IsdnCardState *cs)
-{
- cs->bcs[0].BC_SetStack = setstack_2b;
- cs->bcs[1].BC_SetStack = setstack_2b;
- cs->bcs[0].BC_Close = close_hfcpci;
- cs->bcs[1].BC_Close = close_hfcpci;
- timer_setup(&cs->dbusytimer, hfcpci_dbusy_timer, 0);
- mode_hfcpci(cs->bcs, 0, 0);
- mode_hfcpci(cs->bcs + 1, 0, 1);
-}
-
-
-
-/*******************************************/
-/* handle card messages from control layer */
-/*******************************************/
-static int
-hfcpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
- u_long flags;
-
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "HFCPCI: card_msg %x", mt);
- switch (mt) {
- case CARD_RESET:
- spin_lock_irqsave(&cs->lock, flags);
- reset_hfcpci(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_RELEASE:
- release_io_hfcpci(cs);
- return (0);
- case CARD_INIT:
- spin_lock_irqsave(&cs->lock, flags);
- inithfcpci(cs);
- reset_hfcpci(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- msleep(80); /* Timeout 80ms */
- /* now switch timer interrupt off */
- spin_lock_irqsave(&cs->lock, flags);
- cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER;
- Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
- /* reinit mode reg */
- Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_TEST:
- return (0);
- }
- return (0);
-}
-
-
-/* this variable is used as card index when more than one cards are present */
-static struct pci_dev *dev_hfcpci = NULL;
-
-int
-setup_hfcpci(struct IsdnCard *card)
-{
- u_long flags;
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
- int i;
- struct pci_dev *tmp_hfcpci = NULL;
-
- strcpy(tmp, hfcpci_revision);
- printk(KERN_INFO "HiSax: HFC-PCI driver Rev. %s\n", HiSax_getrev(tmp));
-
- cs->hw.hfcpci.int_s1 = 0;
- cs->dc.hfcpci.ph_state = 0;
- cs->hw.hfcpci.fifo = 255;
- if (cs->typ != ISDN_CTYPE_HFC_PCI)
- return (0);
-
- i = 0;
- while (id_list[i].vendor_id) {
- tmp_hfcpci = hisax_find_pci_device(id_list[i].vendor_id,
- id_list[i].device_id,
- dev_hfcpci);
- i++;
- if (tmp_hfcpci) {
- dma_addr_t dma_mask = DMA_BIT_MASK(32) & ~0x7fffUL;
- if (pci_enable_device(tmp_hfcpci))
- continue;
- if (pci_set_dma_mask(tmp_hfcpci, dma_mask)) {
- printk(KERN_WARNING
- "HiSax hfc_pci: No suitable DMA available.\n");
- continue;
- }
- if (pci_set_consistent_dma_mask(tmp_hfcpci, dma_mask)) {
- printk(KERN_WARNING
- "HiSax hfc_pci: No suitable consistent DMA available.\n");
- continue;
- }
- pci_set_master(tmp_hfcpci);
- if ((card->para[0]) && (card->para[0] != (tmp_hfcpci->resource[0].start & PCI_BASE_ADDRESS_IO_MASK)))
- continue;
- else
- break;
- }
- }
-
- if (!tmp_hfcpci) {
- printk(KERN_WARNING "HFC-PCI: No PCI card found\n");
- return (0);
- }
-
- i--;
- dev_hfcpci = tmp_hfcpci; /* old device */
- cs->hw.hfcpci.dev = dev_hfcpci;
- cs->irq = dev_hfcpci->irq;
- if (!cs->irq) {
- printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n");
- return (0);
- }
- cs->hw.hfcpci.pci_io = ioremap(dev_hfcpci->resource[1].start, 256);
- printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n", id_list[i].vendor_name, id_list[i].card_name);
-
- if (!cs->hw.hfcpci.pci_io) {
- printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n");
- return (0);
- }
-
- /* Allocate memory for FIFOS */
- cs->hw.hfcpci.fifos = pci_alloc_consistent(cs->hw.hfcpci.dev,
- 0x8000, &cs->hw.hfcpci.dma);
- if (!cs->hw.hfcpci.fifos) {
- printk(KERN_WARNING "HFC-PCI: Error allocating FIFO memory!\n");
- return 0;
- }
- if (cs->hw.hfcpci.dma & 0x7fff) {
- printk(KERN_WARNING
- "HFC-PCI: Error DMA memory not on 32K boundary (%lx)\n",
- (u_long)cs->hw.hfcpci.dma);
- pci_free_consistent(cs->hw.hfcpci.dev, 0x8000,
- cs->hw.hfcpci.fifos, cs->hw.hfcpci.dma);
- return 0;
- }
- pci_write_config_dword(cs->hw.hfcpci.dev, 0x80, (u32)cs->hw.hfcpci.dma);
- printk(KERN_INFO
- "HFC-PCI: defined at mem %p fifo %p(%lx) IRQ %d HZ %d\n",
- cs->hw.hfcpci.pci_io,
- cs->hw.hfcpci.fifos,
- (u_long)cs->hw.hfcpci.dma,
- cs->irq, HZ);
-
- spin_lock_irqsave(&cs->lock, flags);
-
- pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, PCI_ENA_MEMIO); /* enable memory mapped ports, disable busmaster */
- cs->hw.hfcpci.int_m2 = 0; /* disable alle interrupts */
- cs->hw.hfcpci.int_m1 = 0;
- Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
- Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
- /* At this point the needed PCI config is done */
- /* fifos are still not enabled */
-
- INIT_WORK(&cs->tqueue, hfcpci_bh);
- cs->setstack_d = setstack_hfcpci;
- cs->BC_Send_Data = &hfcpci_send_data;
- cs->readisac = NULL;
- cs->writeisac = NULL;
- cs->readisacfifo = NULL;
- cs->writeisacfifo = NULL;
- cs->BC_Read_Reg = NULL;
- cs->BC_Write_Reg = NULL;
- cs->irq_func = &hfcpci_interrupt;
- cs->irq_flags |= IRQF_SHARED;
- timer_setup(&cs->hw.hfcpci.timer, hfcpci_Timer, 0);
- cs->cardmsg = &hfcpci_card_msg;
- cs->auxcmd = &hfcpci_auxcmd;
-
- spin_unlock_irqrestore(&cs->lock, flags);
-
- return (1);
-}
diff --git a/drivers/isdn/hisax/hfc_pci.h b/drivers/isdn/hisax/hfc_pci.h
deleted file mode 100644
index 4c3b3ba35726..000000000000
--- a/drivers/isdn/hisax/hfc_pci.h
+++ /dev/null
@@ -1,235 +0,0 @@
-/* $Id: hfc_pci.h,v 1.10.2.2 2004/01/12 22:52:26 keil Exp $
- *
- * specific defines for CCD's HFC 2BDS0 PCI chips
- *
- * Author Werner Cornelius
- * Copyright by Werner Cornelius <werner@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-/*********************************************/
-/* thresholds for transparent B-channel mode */
-/* change mask and threshold simultaneously */
-/*********************************************/
-#define HFCPCI_BTRANS_THRESHOLD 128
-#define HFCPCI_BTRANS_THRESMASK 0x00
-
-
-
-/* defines for PCI config */
-
-#define PCI_ENA_MEMIO 0x02
-#define PCI_ENA_MASTER 0x04
-
-
-/* GCI/IOM bus monitor registers */
-
-#define HCFPCI_C_I 0x08
-#define HFCPCI_TRxR 0x0C
-#define HFCPCI_MON1_D 0x28
-#define HFCPCI_MON2_D 0x2C
-
-
-/* GCI/IOM bus timeslot registers */
-
-#define HFCPCI_B1_SSL 0x80
-#define HFCPCI_B2_SSL 0x84
-#define HFCPCI_AUX1_SSL 0x88
-#define HFCPCI_AUX2_SSL 0x8C
-#define HFCPCI_B1_RSL 0x90
-#define HFCPCI_B2_RSL 0x94
-#define HFCPCI_AUX1_RSL 0x98
-#define HFCPCI_AUX2_RSL 0x9C
-
-/* GCI/IOM bus data registers */
-
-#define HFCPCI_B1_D 0xA0
-#define HFCPCI_B2_D 0xA4
-#define HFCPCI_AUX1_D 0xA8
-#define HFCPCI_AUX2_D 0xAC
-
-/* GCI/IOM bus configuration registers */
-
-#define HFCPCI_MST_EMOD 0xB4
-#define HFCPCI_MST_MODE 0xB8
-#define HFCPCI_CONNECT 0xBC
-
-
-/* Interrupt and status registers */
-
-#define HFCPCI_FIFO_EN 0x44
-#define HFCPCI_TRM 0x48
-#define HFCPCI_B_MODE 0x4C
-#define HFCPCI_CHIP_ID 0x58
-#define HFCPCI_CIRM 0x60
-#define HFCPCI_CTMT 0x64
-#define HFCPCI_INT_M1 0x68
-#define HFCPCI_INT_M2 0x6C
-#define HFCPCI_INT_S1 0x78
-#define HFCPCI_INT_S2 0x7C
-#define HFCPCI_STATUS 0x70
-
-/* S/T section registers */
-
-#define HFCPCI_STATES 0xC0
-#define HFCPCI_SCTRL 0xC4
-#define HFCPCI_SCTRL_E 0xC8
-#define HFCPCI_SCTRL_R 0xCC
-#define HFCPCI_SQ 0xD0
-#define HFCPCI_CLKDEL 0xDC
-#define HFCPCI_B1_REC 0xF0
-#define HFCPCI_B1_SEND 0xF0
-#define HFCPCI_B2_REC 0xF4
-#define HFCPCI_B2_SEND 0xF4
-#define HFCPCI_D_REC 0xF8
-#define HFCPCI_D_SEND 0xF8
-#define HFCPCI_E_REC 0xFC
-
-
-/* bits in status register (READ) */
-#define HFCPCI_PCI_PROC 0x02
-#define HFCPCI_NBUSY 0x04
-#define HFCPCI_TIMER_ELAP 0x10
-#define HFCPCI_STATINT 0x20
-#define HFCPCI_FRAMEINT 0x40
-#define HFCPCI_ANYINT 0x80
-
-/* bits in CTMT (Write) */
-#define HFCPCI_CLTIMER 0x80
-#define HFCPCI_TIM3_125 0x04
-#define HFCPCI_TIM25 0x10
-#define HFCPCI_TIM50 0x14
-#define HFCPCI_TIM400 0x18
-#define HFCPCI_TIM800 0x1C
-#define HFCPCI_AUTO_TIMER 0x20
-#define HFCPCI_TRANSB2 0x02
-#define HFCPCI_TRANSB1 0x01
-
-/* bits in CIRM (Write) */
-#define HFCPCI_AUX_MSK 0x07
-#define HFCPCI_RESET 0x08
-#define HFCPCI_B1_REV 0x40
-#define HFCPCI_B2_REV 0x80
-
-/* bits in INT_M1 and INT_S1 */
-#define HFCPCI_INTS_B1TRANS 0x01
-#define HFCPCI_INTS_B2TRANS 0x02
-#define HFCPCI_INTS_DTRANS 0x04
-#define HFCPCI_INTS_B1REC 0x08
-#define HFCPCI_INTS_B2REC 0x10
-#define HFCPCI_INTS_DREC 0x20
-#define HFCPCI_INTS_L1STATE 0x40
-#define HFCPCI_INTS_TIMER 0x80
-
-/* bits in INT_M2 */
-#define HFCPCI_PROC_TRANS 0x01
-#define HFCPCI_GCI_I_CHG 0x02
-#define HFCPCI_GCI_MON_REC 0x04
-#define HFCPCI_IRQ_ENABLE 0x08
-#define HFCPCI_PMESEL 0x80
-
-/* bits in STATES */
-#define HFCPCI_STATE_MSK 0x0F
-#define HFCPCI_LOAD_STATE 0x10
-#define HFCPCI_ACTIVATE 0x20
-#define HFCPCI_DO_ACTION 0x40
-#define HFCPCI_NT_G2_G3 0x80
-
-/* bits in HFCD_MST_MODE */
-#define HFCPCI_MASTER 0x01
-#define HFCPCI_SLAVE 0x00
-/* remaining bits are for codecs control */
-
-/* bits in HFCD_SCTRL */
-#define SCTRL_B1_ENA 0x01
-#define SCTRL_B2_ENA 0x02
-#define SCTRL_MODE_TE 0x00
-#define SCTRL_MODE_NT 0x04
-#define SCTRL_LOW_PRIO 0x08
-#define SCTRL_SQ_ENA 0x10
-#define SCTRL_TEST 0x20
-#define SCTRL_NONE_CAP 0x40
-#define SCTRL_PWR_DOWN 0x80
-
-/* bits in SCTRL_E */
-#define HFCPCI_AUTO_AWAKE 0x01
-#define HFCPCI_DBIT_1 0x04
-#define HFCPCI_IGNORE_COL 0x08
-#define HFCPCI_CHG_B1_B2 0x80
-
-/****************************/
-/* bits in FIFO_EN register */
-/****************************/
-#define HFCPCI_FIFOEN_B1 0x03
-#define HFCPCI_FIFOEN_B2 0x0C
-#define HFCPCI_FIFOEN_DTX 0x10
-#define HFCPCI_FIFOEN_B1TX 0x01
-#define HFCPCI_FIFOEN_B1RX 0x02
-#define HFCPCI_FIFOEN_B2TX 0x04
-#define HFCPCI_FIFOEN_B2RX 0x08
-
-
-/***********************************/
-/* definitions of fifo memory area */
-/***********************************/
-#define MAX_D_FRAMES 15
-#define MAX_B_FRAMES 31
-#define B_SUB_VAL 0x200
-#define B_FIFO_SIZE (0x2000 - B_SUB_VAL)
-#define D_FIFO_SIZE 512
-#define D_FREG_MASK 0xF
-
-typedef struct {
- unsigned short z1; /* Z1 pointer 16 Bit */
- unsigned short z2; /* Z2 pointer 16 Bit */
-} z_type;
-
-typedef struct {
- u_char data[D_FIFO_SIZE]; /* FIFO data space */
- u_char fill1[0x20A0 - D_FIFO_SIZE]; /* reserved, do not use */
- u_char f1, f2; /* f pointers */
- u_char fill2[0x20C0 - 0x20A2]; /* reserved, do not use */
- z_type za[MAX_D_FRAMES + 1]; /* mask index with D_FREG_MASK for access */
- u_char fill3[0x4000 - 0x2100]; /* align 16K */
-} dfifo_type;
-
-typedef struct {
- z_type za[MAX_B_FRAMES + 1]; /* only range 0x0..0x1F allowed */
- u_char f1, f2; /* f pointers */
- u_char fill[0x2100 - 0x2082]; /* alignment */
-} bzfifo_type;
-
-
-typedef union {
- struct {
- dfifo_type d_tx; /* D-send channel */
- dfifo_type d_rx; /* D-receive channel */
- } d_chan;
- struct {
- u_char fill1[0x200];
- u_char txdat_b1[B_FIFO_SIZE];
- bzfifo_type txbz_b1;
-
- bzfifo_type txbz_b2;
- u_char txdat_b2[B_FIFO_SIZE];
-
- u_char fill2[D_FIFO_SIZE];
-
- u_char rxdat_b1[B_FIFO_SIZE];
- bzfifo_type rxbz_b1;
-
- bzfifo_type rxbz_b2;
- u_char rxdat_b2[B_FIFO_SIZE];
- } b_chans;
- u_char fill[32768];
-} fifo_area;
-
-
-#define Write_hfc(a, b, c) (writeb(c, (a->hw.hfcpci.pci_io) + b))
-#define Read_hfc(a, b) (readb((a->hw.hfcpci.pci_io) + b))
-
-extern void main_irq_hcpci(struct BCState *bcs);
-extern void releasehfcpci(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c
deleted file mode 100644
index 12af628d9b2c..000000000000
--- a/drivers/isdn/hisax/hfc_sx.c
+++ /dev/null
@@ -1,1517 +0,0 @@
-/* $Id: hfc_sx.c,v 1.12.2.5 2004/02/11 13:21:33 keil Exp $
- *
- * level driver for Cologne Chip Designs hfc-s+/sp based cards
- *
- * Author Werner Cornelius
- * based on existing driver for CCD HFC PCI cards
- * Copyright by Werner Cornelius <werner@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/init.h>
-#include "hisax.h"
-#include "hfc_sx.h"
-#include "isdnl1.h"
-#include <linux/interrupt.h>
-#include <linux/isapnp.h>
-#include <linux/slab.h>
-
-static const char *hfcsx_revision = "$Revision: 1.12.2.5 $";
-
-/***************************************/
-/* IRQ-table for CCDs demo board */
-/* IRQs 6,5,10,11,12,15 are supported */
-/***************************************/
-
-/* Teles 16.3c Vendor Id TAG2620, Version 1.0, Vendor version 2.1
- *
- * Thanks to Uwe Wisniewski
- *
- * ISA-SLOT Signal PIN
- * B25 IRQ3 92 IRQ_G
- * B23 IRQ5 94 IRQ_A
- * B4 IRQ2/9 95 IRQ_B
- * D3 IRQ10 96 IRQ_C
- * D4 IRQ11 97 IRQ_D
- * D5 IRQ12 98 IRQ_E
- * D6 IRQ15 99 IRQ_F
- */
-
-#undef CCD_DEMO_BOARD
-#ifdef CCD_DEMO_BOARD
-static u_char ccd_sp_irqtab[16] = {
- 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 3, 4, 5, 0, 0, 6
-};
-#else /* Teles 16.3c */
-static u_char ccd_sp_irqtab[16] = {
- 0, 0, 0, 7, 0, 1, 0, 0, 0, 2, 3, 4, 5, 0, 0, 6
-};
-#endif
-#define NT_T1_COUNT 20 /* number of 3.125ms interrupts for G2 timeout */
-
-#define byteout(addr, val) outb(val, addr)
-#define bytein(addr) inb(addr)
-
-/******************************/
-/* In/Out access to registers */
-/******************************/
-static inline void
-Write_hfc(struct IsdnCardState *cs, u_char regnum, u_char val)
-{
- byteout(cs->hw.hfcsx.base + 1, regnum);
- byteout(cs->hw.hfcsx.base, val);
-}
-
-static inline u_char
-Read_hfc(struct IsdnCardState *cs, u_char regnum)
-{
- u_char ret;
-
- byteout(cs->hw.hfcsx.base + 1, regnum);
- ret = bytein(cs->hw.hfcsx.base);
- return (ret);
-}
-
-
-/**************************************************/
-/* select a fifo and remember which one for reuse */
-/**************************************************/
-static void
-fifo_select(struct IsdnCardState *cs, u_char fifo)
-{
- if (fifo == cs->hw.hfcsx.last_fifo)
- return; /* still valid */
-
- byteout(cs->hw.hfcsx.base + 1, HFCSX_FIF_SEL);
- byteout(cs->hw.hfcsx.base, fifo);
- while (bytein(cs->hw.hfcsx.base + 1) & 1); /* wait for busy */
- udelay(4);
- byteout(cs->hw.hfcsx.base, fifo);
- while (bytein(cs->hw.hfcsx.base + 1) & 1); /* wait for busy */
-}
-
-/******************************************/
-/* reset the specified fifo to defaults. */
-/* If its a send fifo init needed markers */
-/******************************************/
-static void
-reset_fifo(struct IsdnCardState *cs, u_char fifo)
-{
- fifo_select(cs, fifo); /* first select the fifo */
- byteout(cs->hw.hfcsx.base + 1, HFCSX_CIRM);
- byteout(cs->hw.hfcsx.base, cs->hw.hfcsx.cirm | 0x80); /* reset cmd */
- udelay(1);
- while (bytein(cs->hw.hfcsx.base + 1) & 1); /* wait for busy */
-}
-
-
-/*************************************************************/
-/* write_fifo writes the skb contents to the desired fifo */
-/* if no space is available or an error occurs 0 is returned */
-/* the skb is not released in any way. */
-/*************************************************************/
-static int
-write_fifo(struct IsdnCardState *cs, struct sk_buff *skb, u_char fifo, int trans_max)
-{
- unsigned short *msp;
- int fifo_size, count, z1, z2;
- u_char f_msk, f1, f2, *src;
-
- if (skb->len <= 0) return (0);
- if (fifo & 1) return (0); /* no write fifo */
-
- fifo_select(cs, fifo);
- if (fifo & 4) {
- fifo_size = D_FIFO_SIZE; /* D-channel */
- f_msk = MAX_D_FRAMES;
- if (trans_max) return (0); /* only HDLC */
- }
- else {
- fifo_size = cs->hw.hfcsx.b_fifo_size; /* B-channel */
- f_msk = MAX_B_FRAMES;
- }
-
- z1 = Read_hfc(cs, HFCSX_FIF_Z1H);
- z1 = ((z1 << 8) | Read_hfc(cs, HFCSX_FIF_Z1L));
-
- /* Check for transparent mode */
- if (trans_max) {
- z2 = Read_hfc(cs, HFCSX_FIF_Z2H);
- z2 = ((z2 << 8) | Read_hfc(cs, HFCSX_FIF_Z2L));
- count = z2 - z1;
- if (count <= 0)
- count += fifo_size; /* free bytes */
- if (count < skb->len + 1) return (0); /* no room */
- count = fifo_size - count; /* bytes still not send */
- if (count > 2 * trans_max) return (0); /* delay to long */
- count = skb->len;
- src = skb->data;
- while (count--)
- Write_hfc(cs, HFCSX_FIF_DWR, *src++);
- return (1); /* success */
- }
-
- msp = ((struct hfcsx_extra *)(cs->hw.hfcsx.extra))->marker;
- msp += (((fifo >> 1) & 3) * (MAX_B_FRAMES + 1));
- f1 = Read_hfc(cs, HFCSX_FIF_F1) & f_msk;
- f2 = Read_hfc(cs, HFCSX_FIF_F2) & f_msk;
-
- count = f1 - f2; /* frame count actually buffered */
- if (count < 0)
- count += (f_msk + 1); /* if wrap around */
- if (count > f_msk - 1) {
- if (cs->debug & L1_DEB_ISAC_FIFO)
- debugl1(cs, "hfcsx_write_fifo %d more as %d frames", fifo, f_msk - 1);
- return (0);
- }
-
- *(msp + f1) = z1; /* remember marker */
-
- if (cs->debug & L1_DEB_ISAC_FIFO)
- debugl1(cs, "hfcsx_write_fifo %d f1(%x) f2(%x) z1(f1)(%x)",
- fifo, f1, f2, z1);
- /* now determine free bytes in FIFO buffer */
- count = *(msp + f2) - z1;
- if (count <= 0)
- count += fifo_size; /* count now contains available bytes */
-
- if (cs->debug & L1_DEB_ISAC_FIFO)
- debugl1(cs, "hfcsx_write_fifo %d count(%u/%d)",
- fifo, skb->len, count);
- if (count < skb->len) {
- if (cs->debug & L1_DEB_ISAC_FIFO)
- debugl1(cs, "hfcsx_write_fifo %d no fifo mem", fifo);
- return (0);
- }
-
- count = skb->len; /* get frame len */
- src = skb->data; /* source pointer */
- while (count--)
- Write_hfc(cs, HFCSX_FIF_DWR, *src++);
-
- Read_hfc(cs, HFCSX_FIF_INCF1); /* increment F1 */
- udelay(1);
- while (bytein(cs->hw.hfcsx.base + 1) & 1); /* wait for busy */
- return (1);
-}
-
-/***************************************************************/
-/* read_fifo reads data to an skb from the desired fifo */
-/* if no data is available or an error occurs NULL is returned */
-/* the skb is not released in any way. */
-/***************************************************************/
-static struct sk_buff *
-read_fifo(struct IsdnCardState *cs, u_char fifo, int trans_max)
-{ int fifo_size, count, z1, z2;
- u_char f_msk, f1, f2, *dst;
- struct sk_buff *skb;
-
- if (!(fifo & 1)) return (NULL); /* no read fifo */
- fifo_select(cs, fifo);
- if (fifo & 4) {
- fifo_size = D_FIFO_SIZE; /* D-channel */
- f_msk = MAX_D_FRAMES;
- if (trans_max) return (NULL); /* only hdlc */
- }
- else {
- fifo_size = cs->hw.hfcsx.b_fifo_size; /* B-channel */
- f_msk = MAX_B_FRAMES;
- }
-
- /* transparent mode */
- if (trans_max) {
- z1 = Read_hfc(cs, HFCSX_FIF_Z1H);
- z1 = ((z1 << 8) | Read_hfc(cs, HFCSX_FIF_Z1L));
- z2 = Read_hfc(cs, HFCSX_FIF_Z2H);
- z2 = ((z2 << 8) | Read_hfc(cs, HFCSX_FIF_Z2L));
- /* now determine bytes in actual FIFO buffer */
- count = z1 - z2;
- if (count <= 0)
- count += fifo_size; /* count now contains buffered bytes */
- count++;
- if (count > trans_max)
- count = trans_max; /* limit length */
- skb = dev_alloc_skb(count);
- if (skb) {
- dst = skb_put(skb, count);
- while (count--)
- *dst++ = Read_hfc(cs, HFCSX_FIF_DRD);
- return skb;
- } else
- return NULL; /* no memory */
- }
-
- do {
- f1 = Read_hfc(cs, HFCSX_FIF_F1) & f_msk;
- f2 = Read_hfc(cs, HFCSX_FIF_F2) & f_msk;
-
- if (f1 == f2) return (NULL); /* no frame available */
-
- z1 = Read_hfc(cs, HFCSX_FIF_Z1H);
- z1 = ((z1 << 8) | Read_hfc(cs, HFCSX_FIF_Z1L));
- z2 = Read_hfc(cs, HFCSX_FIF_Z2H);
- z2 = ((z2 << 8) | Read_hfc(cs, HFCSX_FIF_Z2L));
-
- if (cs->debug & L1_DEB_ISAC_FIFO)
- debugl1(cs, "hfcsx_read_fifo %d f1(%x) f2(%x) z1(f2)(%x) z2(f2)(%x)",
- fifo, f1, f2, z1, z2);
- /* now determine bytes in actual FIFO buffer */
- count = z1 - z2;
- if (count <= 0)
- count += fifo_size; /* count now contains buffered bytes */
- count++;
-
- if (cs->debug & L1_DEB_ISAC_FIFO)
- debugl1(cs, "hfcsx_read_fifo %d count %u)",
- fifo, count);
-
- if ((count > fifo_size) || (count < 4)) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "hfcsx_read_fifo %d packet inv. len %d ", fifo , count);
- while (count) {
- count--; /* empty fifo */
- Read_hfc(cs, HFCSX_FIF_DRD);
- }
- skb = NULL;
- } else
- if ((skb = dev_alloc_skb(count - 3))) {
- count -= 3;
- dst = skb_put(skb, count);
-
- while (count--)
- *dst++ = Read_hfc(cs, HFCSX_FIF_DRD);
-
- Read_hfc(cs, HFCSX_FIF_DRD); /* CRC 1 */
- Read_hfc(cs, HFCSX_FIF_DRD); /* CRC 2 */
- if (Read_hfc(cs, HFCSX_FIF_DRD)) {
- dev_kfree_skb_irq(skb);
- if (cs->debug & L1_DEB_ISAC_FIFO)
- debugl1(cs, "hfcsx_read_fifo %d crc error", fifo);
- skb = NULL;
- }
- } else {
- printk(KERN_WARNING "HFC-SX: receive out of memory\n");
- return (NULL);
- }
-
- Read_hfc(cs, HFCSX_FIF_INCF2); /* increment F2 */
- udelay(1);
- while (bytein(cs->hw.hfcsx.base + 1) & 1); /* wait for busy */
- udelay(1);
- } while (!skb); /* retry in case of crc error */
- return (skb);
-}
-
-/******************************************/
-/* free hardware resources used by driver */
-/******************************************/
-static void
-release_io_hfcsx(struct IsdnCardState *cs)
-{
- cs->hw.hfcsx.int_m2 = 0; /* interrupt output off ! */
- Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2);
- Write_hfc(cs, HFCSX_CIRM, HFCSX_RESET); /* Reset On */
- msleep(30); /* Timeout 30ms */
- Write_hfc(cs, HFCSX_CIRM, 0); /* Reset Off */
- del_timer(&cs->hw.hfcsx.timer);
- release_region(cs->hw.hfcsx.base, 2); /* release IO-Block */
- kfree(cs->hw.hfcsx.extra);
- cs->hw.hfcsx.extra = NULL;
-}
-
-/**********************************************************/
-/* set_fifo_size determines the size of the RAM and FIFOs */
-/* returning 0 -> need to reset the chip again. */
-/**********************************************************/
-static int set_fifo_size(struct IsdnCardState *cs)
-{
-
- if (cs->hw.hfcsx.b_fifo_size) return (1); /* already determined */
-
- if ((cs->hw.hfcsx.chip >> 4) == 9) {
- cs->hw.hfcsx.b_fifo_size = B_FIFO_SIZE_32K;
- return (1);
- }
-
- cs->hw.hfcsx.b_fifo_size = B_FIFO_SIZE_8K;
- cs->hw.hfcsx.cirm |= 0x10; /* only 8K of ram */
- return (0);
-
-}
-
-/********************************************************************************/
-/* function called to reset the HFC SX chip. A complete software reset of chip */
-/* and fifos is done. */
-/********************************************************************************/
-static void
-reset_hfcsx(struct IsdnCardState *cs)
-{
- cs->hw.hfcsx.int_m2 = 0; /* interrupt output off ! */
- Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2);
-
- printk(KERN_INFO "HFC_SX: resetting card\n");
- while (1) {
- Write_hfc(cs, HFCSX_CIRM, HFCSX_RESET | cs->hw.hfcsx.cirm); /* Reset */
- mdelay(30);
- Write_hfc(cs, HFCSX_CIRM, cs->hw.hfcsx.cirm); /* Reset Off */
- mdelay(20);
- if (Read_hfc(cs, HFCSX_STATUS) & 2)
- printk(KERN_WARNING "HFC-SX init bit busy\n");
- cs->hw.hfcsx.last_fifo = 0xff; /* invalidate */
- if (!set_fifo_size(cs)) continue;
- break;
- }
-
- cs->hw.hfcsx.trm = 0 + HFCSX_BTRANS_THRESMASK; /* no echo connect , threshold */
- Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm);
-
- Write_hfc(cs, HFCSX_CLKDEL, 0x0e); /* ST-Bit delay for TE-Mode */
- cs->hw.hfcsx.sctrl_e = HFCSX_AUTO_AWAKE;
- Write_hfc(cs, HFCSX_SCTRL_E, cs->hw.hfcsx.sctrl_e); /* S/T Auto awake */
- cs->hw.hfcsx.bswapped = 0; /* no exchange */
- cs->hw.hfcsx.nt_mode = 0; /* we are in TE mode */
- cs->hw.hfcsx.ctmt = HFCSX_TIM3_125 | HFCSX_AUTO_TIMER;
- Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt);
-
- cs->hw.hfcsx.int_m1 = HFCSX_INTS_DTRANS | HFCSX_INTS_DREC |
- HFCSX_INTS_L1STATE | HFCSX_INTS_TIMER;
- Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
-
- /* Clear already pending ints */
- Read_hfc(cs, HFCSX_INT_S1);
-
- Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 2); /* HFC ST 2 */
- udelay(10);
- Write_hfc(cs, HFCSX_STATES, 2); /* HFC ST 2 */
- cs->hw.hfcsx.mst_m = HFCSX_MASTER; /* HFC Master Mode */
-
- Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m);
- cs->hw.hfcsx.sctrl = 0x40; /* set tx_lo mode, error in datasheet ! */
- Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl);
- cs->hw.hfcsx.sctrl_r = 0;
- Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.sctrl_r);
-
- /* Init GCI/IOM2 in master mode */
- /* Slots 0 and 1 are set for B-chan 1 and 2 */
- /* D- and monitor/CI channel are not enabled */
- /* STIO1 is used as output for data, B1+B2 from ST->IOM+HFC */
- /* STIO2 is used as data input, B1+B2 from IOM->ST */
- /* ST B-channel send disabled -> continuous 1s */
- /* The IOM slots are always enabled */
- cs->hw.hfcsx.conn = 0x36; /* set data flow directions */
- Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn);
- Write_hfc(cs, HFCSX_B1_SSL, 0x80); /* B1-Slot 0 STIO1 out enabled */
- Write_hfc(cs, HFCSX_B2_SSL, 0x81); /* B2-Slot 1 STIO1 out enabled */
- Write_hfc(cs, HFCSX_B1_RSL, 0x80); /* B1-Slot 0 STIO2 in enabled */
- Write_hfc(cs, HFCSX_B2_RSL, 0x81); /* B2-Slot 1 STIO2 in enabled */
-
- /* Finally enable IRQ output */
- cs->hw.hfcsx.int_m2 = HFCSX_IRQ_ENABLE;
- Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2);
- Read_hfc(cs, HFCSX_INT_S2);
-}
-
-/***************************************************/
-/* Timer function called when kernel timer expires */
-/***************************************************/
-static void
-hfcsx_Timer(struct timer_list *t)
-{
- struct IsdnCardState *cs = from_timer(cs, t, hw.hfcsx.timer);
- cs->hw.hfcsx.timer.expires = jiffies + 75;
- /* WD RESET */
-/* WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcsx.ctmt | 0x80);
- add_timer(&cs->hw.hfcsx.timer);
-*/
-}
-
-/************************************************/
-/* select a b-channel entry matching and active */
-/************************************************/
-static
-struct BCState *
-Sel_BCS(struct IsdnCardState *cs, int channel)
-{
- if (cs->bcs[0].mode && (cs->bcs[0].channel == channel))
- return (&cs->bcs[0]);
- else if (cs->bcs[1].mode && (cs->bcs[1].channel == channel))
- return (&cs->bcs[1]);
- else
- return (NULL);
-}
-
-/*******************************/
-/* D-channel receive procedure */
-/*******************************/
-static
-int
-receive_dmsg(struct IsdnCardState *cs)
-{
- struct sk_buff *skb;
- int count = 5;
-
- if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- debugl1(cs, "rec_dmsg blocked");
- return (1);
- }
-
- do {
- skb = read_fifo(cs, HFCSX_SEL_D_RX, 0);
- if (skb) {
- skb_queue_tail(&cs->rq, skb);
- schedule_event(cs, D_RCVBUFREADY);
- }
- } while (--count && skb);
-
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- return (1);
-}
-
-/**********************************/
-/* B-channel main receive routine */
-/**********************************/
-static void
-main_rec_hfcsx(struct BCState *bcs)
-{
- struct IsdnCardState *cs = bcs->cs;
- int count = 5;
- struct sk_buff *skb;
-
-Begin:
- count--;
- if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- debugl1(cs, "rec_data %d blocked", bcs->channel);
- return;
- }
- skb = read_fifo(cs, ((bcs->channel) && (!cs->hw.hfcsx.bswapped)) ?
- HFCSX_SEL_B2_RX : HFCSX_SEL_B1_RX,
- (bcs->mode == L1_MODE_TRANS) ?
- HFCSX_BTRANS_THRESHOLD : 0);
-
- if (skb) {
- skb_queue_tail(&bcs->rqueue, skb);
- schedule_event(bcs, B_RCVBUFREADY);
- }
-
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- if (count && skb)
- goto Begin;
- return;
-}
-
-/**************************/
-/* D-channel send routine */
-/**************************/
-static void
-hfcsx_fill_dfifo(struct IsdnCardState *cs)
-{
- if (!cs->tx_skb)
- return;
- if (cs->tx_skb->len <= 0)
- return;
-
- if (write_fifo(cs, cs->tx_skb, HFCSX_SEL_D_TX, 0)) {
- dev_kfree_skb_any(cs->tx_skb);
- cs->tx_skb = NULL;
- }
- return;
-}
-
-/**************************/
-/* B-channel send routine */
-/**************************/
-static void
-hfcsx_fill_fifo(struct BCState *bcs)
-{
- struct IsdnCardState *cs = bcs->cs;
-
- if (!bcs->tx_skb)
- return;
- if (bcs->tx_skb->len <= 0)
- return;
-
- if (write_fifo(cs, bcs->tx_skb,
- ((bcs->channel) && (!cs->hw.hfcsx.bswapped)) ?
- HFCSX_SEL_B2_TX : HFCSX_SEL_B1_TX,
- (bcs->mode == L1_MODE_TRANS) ?
- HFCSX_BTRANS_THRESHOLD : 0)) {
-
- bcs->tx_cnt -= bcs->tx_skb->len;
- if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
- (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
- u_long flags;
- spin_lock_irqsave(&bcs->aclock, flags);
- bcs->ackcnt += bcs->tx_skb->len;
- spin_unlock_irqrestore(&bcs->aclock, flags);
- schedule_event(bcs, B_ACKPENDING);
- }
- dev_kfree_skb_any(bcs->tx_skb);
- bcs->tx_skb = NULL;
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- }
-}
-
-/**********************************************/
-/* D-channel l1 state call for leased NT-mode */
-/**********************************************/
-static void
-dch_nt_l2l1(struct PStack *st, int pr, void *arg)
-{
- struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
-
- switch (pr) {
- case (PH_DATA | REQUEST):
- case (PH_PULL | REQUEST):
- case (PH_PULL | INDICATION):
- st->l1.l1hw(st, pr, arg);
- break;
- case (PH_ACTIVATE | REQUEST):
- st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
- break;
- case (PH_TESTLOOP | REQUEST):
- if (1 & (long) arg)
- debugl1(cs, "PH_TEST_LOOP B1");
- if (2 & (long) arg)
- debugl1(cs, "PH_TEST_LOOP B2");
- if (!(3 & (long) arg))
- debugl1(cs, "PH_TEST_LOOP DISABLED");
- st->l1.l1hw(st, HW_TESTLOOP | REQUEST, arg);
- break;
- default:
- if (cs->debug)
- debugl1(cs, "dch_nt_l2l1 msg %04X unhandled", pr);
- break;
- }
-}
-
-
-
-/***********************/
-/* set/reset echo mode */
-/***********************/
-static int
-hfcsx_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic)
-{
- unsigned long flags;
- int i = *(unsigned int *) ic->parm.num;
-
- if ((ic->arg == 98) &&
- (!(cs->hw.hfcsx.int_m1 & (HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC + HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC)))) {
- spin_lock_irqsave(&cs->lock, flags);
- Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 0); /* HFC ST G0 */
- udelay(10);
- cs->hw.hfcsx.sctrl |= SCTRL_MODE_NT;
- Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl); /* set NT-mode */
- udelay(10);
- Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 1); /* HFC ST G1 */
- udelay(10);
- Write_hfc(cs, HFCSX_STATES, 1 | HFCSX_ACTIVATE | HFCSX_DO_ACTION);
- cs->dc.hfcsx.ph_state = 1;
- cs->hw.hfcsx.nt_mode = 1;
- cs->hw.hfcsx.nt_timer = 0;
- spin_unlock_irqrestore(&cs->lock, flags);
- cs->stlist->l2.l2l1 = dch_nt_l2l1;
- debugl1(cs, "NT mode activated");
- return (0);
- }
- if ((cs->chanlimit > 1) || (cs->hw.hfcsx.bswapped) ||
- (cs->hw.hfcsx.nt_mode) || (ic->arg != 12))
- return (-EINVAL);
-
- if (i) {
- cs->logecho = 1;
- cs->hw.hfcsx.trm |= 0x20; /* enable echo chan */
- cs->hw.hfcsx.int_m1 |= HFCSX_INTS_B2REC;
- /* reset Channel !!!!! */
- } else {
- cs->logecho = 0;
- cs->hw.hfcsx.trm &= ~0x20; /* disable echo chan */
- cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_B2REC;
- }
- cs->hw.hfcsx.sctrl_r &= ~SCTRL_B2_ENA;
- cs->hw.hfcsx.sctrl &= ~SCTRL_B2_ENA;
- cs->hw.hfcsx.conn |= 0x10; /* B2-IOM -> B2-ST */
- cs->hw.hfcsx.ctmt &= ~2;
- spin_lock_irqsave(&cs->lock, flags);
- Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt);
- Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.sctrl_r);
- Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl);
- Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn);
- Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm);
- Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
-} /* hfcsx_auxcmd */
-
-/*****************************/
-/* E-channel receive routine */
-/*****************************/
-static void
-receive_emsg(struct IsdnCardState *cs)
-{
- int count = 5;
- u_char *ptr;
- struct sk_buff *skb;
-
- if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- debugl1(cs, "echo_rec_data blocked");
- return;
- }
- do {
- skb = read_fifo(cs, HFCSX_SEL_B2_RX, 0);
- if (skb) {
- if (cs->debug & DEB_DLOG_HEX) {
- ptr = cs->dlog;
- if ((skb->len) < MAX_DLOG_SPACE / 3 - 10) {
- *ptr++ = 'E';
- *ptr++ = 'C';
- *ptr++ = 'H';
- *ptr++ = 'O';
- *ptr++ = ':';
- ptr += QuickHex(ptr, skb->data, skb->len);
- ptr--;
- *ptr++ = '\n';
- *ptr = 0;
- HiSax_putstatus(cs, NULL, cs->dlog);
- } else
- HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", skb->len);
- }
- dev_kfree_skb_any(skb);
- }
- } while (--count && skb);
-
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- return;
-} /* receive_emsg */
-
-
-/*********************/
-/* Interrupt handler */
-/*********************/
-static irqreturn_t
-hfcsx_interrupt(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_char exval;
- struct BCState *bcs;
- int count = 15;
- u_long flags;
- u_char val, stat;
-
- if (!(cs->hw.hfcsx.int_m2 & 0x08))
- return IRQ_NONE; /* not initialised */
-
- spin_lock_irqsave(&cs->lock, flags);
- if (HFCSX_ANYINT & (stat = Read_hfc(cs, HFCSX_STATUS))) {
- val = Read_hfc(cs, HFCSX_INT_S1);
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "HFC-SX: stat(%02x) s1(%02x)", stat, val);
- } else {
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_NONE;
- }
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "HFC-SX irq %x %s", val,
- test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ?
- "locked" : "unlocked");
- val &= cs->hw.hfcsx.int_m1;
- if (val & 0x40) { /* state machine irq */
- exval = Read_hfc(cs, HFCSX_STATES) & 0xf;
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcsx.ph_state,
- exval);
- cs->dc.hfcsx.ph_state = exval;
- schedule_event(cs, D_L1STATECHANGE);
- val &= ~0x40;
- }
- if (val & 0x80) { /* timer irq */
- if (cs->hw.hfcsx.nt_mode) {
- if ((--cs->hw.hfcsx.nt_timer) < 0)
- schedule_event(cs, D_L1STATECHANGE);
- }
- val &= ~0x80;
- Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt | HFCSX_CLTIMER);
- }
- while (val) {
- if (test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- cs->hw.hfcsx.int_s1 |= val;
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
- }
- if (cs->hw.hfcsx.int_s1 & 0x18) {
- exval = val;
- val = cs->hw.hfcsx.int_s1;
- cs->hw.hfcsx.int_s1 = exval;
- }
- if (val & 0x08) {
- if (!(bcs = Sel_BCS(cs, cs->hw.hfcsx.bswapped ? 1 : 0))) {
- if (cs->debug)
- debugl1(cs, "hfcsx spurious 0x08 IRQ");
- } else
- main_rec_hfcsx(bcs);
- }
- if (val & 0x10) {
- if (cs->logecho)
- receive_emsg(cs);
- else if (!(bcs = Sel_BCS(cs, 1))) {
- if (cs->debug)
- debugl1(cs, "hfcsx spurious 0x10 IRQ");
- } else
- main_rec_hfcsx(bcs);
- }
- if (val & 0x01) {
- if (!(bcs = Sel_BCS(cs, cs->hw.hfcsx.bswapped ? 1 : 0))) {
- if (cs->debug)
- debugl1(cs, "hfcsx spurious 0x01 IRQ");
- } else {
- if (bcs->tx_skb) {
- if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- hfcsx_fill_fifo(bcs);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- } else
- debugl1(cs, "fill_data %d blocked", bcs->channel);
- } else {
- if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
- if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- hfcsx_fill_fifo(bcs);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- } else
- debugl1(cs, "fill_data %d blocked", bcs->channel);
- } else {
- schedule_event(bcs, B_XMTBUFREADY);
- }
- }
- }
- }
- if (val & 0x02) {
- if (!(bcs = Sel_BCS(cs, 1))) {
- if (cs->debug)
- debugl1(cs, "hfcsx spurious 0x02 IRQ");
- } else {
- if (bcs->tx_skb) {
- if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- hfcsx_fill_fifo(bcs);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- } else
- debugl1(cs, "fill_data %d blocked", bcs->channel);
- } else {
- if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
- if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- hfcsx_fill_fifo(bcs);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- } else
- debugl1(cs, "fill_data %d blocked", bcs->channel);
- } else {
- schedule_event(bcs, B_XMTBUFREADY);
- }
- }
- }
- }
- if (val & 0x20) { /* receive dframe */
- receive_dmsg(cs);
- }
- if (val & 0x04) { /* dframe transmitted */
- if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
- del_timer(&cs->dbusytimer);
- if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
- schedule_event(cs, D_CLEARBUSY);
- if (cs->tx_skb) {
- if (cs->tx_skb->len) {
- if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- hfcsx_fill_dfifo(cs);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- } else {
- debugl1(cs, "hfcsx_fill_dfifo irq blocked");
- }
- goto afterXPR;
- } else {
- dev_kfree_skb_irq(cs->tx_skb);
- cs->tx_cnt = 0;
- cs->tx_skb = NULL;
- }
- }
- if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
- cs->tx_cnt = 0;
- if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- hfcsx_fill_dfifo(cs);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- } else {
- debugl1(cs, "hfcsx_fill_dfifo irq blocked");
- }
- } else
- schedule_event(cs, D_XMTBUFREADY);
- }
- afterXPR:
- if (cs->hw.hfcsx.int_s1 && count--) {
- val = cs->hw.hfcsx.int_s1;
- cs->hw.hfcsx.int_s1 = 0;
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "HFC-SX irq %x loop %d", val, 15 - count);
- } else
- val = 0;
- }
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-/********************************************************************/
-/* timer callback for D-chan busy resolution. Currently no function */
-/********************************************************************/
-static void
-hfcsx_dbusy_timer(struct timer_list *t)
-{
-}
-
-/*************************************/
-/* Layer 1 D-channel hardware access */
-/*************************************/
-static void
-HFCSX_l1hw(struct PStack *st, int pr, void *arg)
-{
- struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
- struct sk_buff *skb = arg;
- u_long flags;
-
- switch (pr) {
- case (PH_DATA | REQUEST):
- if (cs->debug & DEB_DLOG_HEX)
- LogFrame(cs, skb->data, skb->len);
- if (cs->debug & DEB_DLOG_VERBOSE)
- dlogframe(cs, skb, 0);
- spin_lock_irqsave(&cs->lock, flags);
- if (cs->tx_skb) {
- skb_queue_tail(&cs->sq, skb);
-#ifdef L2FRAME_DEBUG /* psa */
- if (cs->debug & L1_DEB_LAPD)
- Logl2Frame(cs, skb, "PH_DATA Queued", 0);
-#endif
- } else {
- cs->tx_skb = skb;
- cs->tx_cnt = 0;
-#ifdef L2FRAME_DEBUG /* psa */
- if (cs->debug & L1_DEB_LAPD)
- Logl2Frame(cs, skb, "PH_DATA", 0);
-#endif
- if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- hfcsx_fill_dfifo(cs);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- } else
- debugl1(cs, "hfcsx_fill_dfifo blocked");
-
- }
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (PH_PULL | INDICATION):
- spin_lock_irqsave(&cs->lock, flags);
- if (cs->tx_skb) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
- skb_queue_tail(&cs->sq, skb);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- }
- if (cs->debug & DEB_DLOG_HEX)
- LogFrame(cs, skb->data, skb->len);
- if (cs->debug & DEB_DLOG_VERBOSE)
- dlogframe(cs, skb, 0);
- cs->tx_skb = skb;
- cs->tx_cnt = 0;
-#ifdef L2FRAME_DEBUG /* psa */
- if (cs->debug & L1_DEB_LAPD)
- Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
-#endif
- if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- hfcsx_fill_dfifo(cs);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- } else
- debugl1(cs, "hfcsx_fill_dfifo blocked");
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (PH_PULL | REQUEST):
-#ifdef L2FRAME_DEBUG /* psa */
- if (cs->debug & L1_DEB_LAPD)
- debugl1(cs, "-> PH_REQUEST_PULL");
-#endif
- if (!cs->tx_skb) {
- test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
- } else
- test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- break;
- case (HW_RESET | REQUEST):
- spin_lock_irqsave(&cs->lock, flags);
- Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 3); /* HFC ST 3 */
- udelay(6);
- Write_hfc(cs, HFCSX_STATES, 3); /* HFC ST 2 */
- cs->hw.hfcsx.mst_m |= HFCSX_MASTER;
- Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m);
- Write_hfc(cs, HFCSX_STATES, HFCSX_ACTIVATE | HFCSX_DO_ACTION);
- spin_unlock_irqrestore(&cs->lock, flags);
- l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
- break;
- case (HW_ENABLE | REQUEST):
- spin_lock_irqsave(&cs->lock, flags);
- Write_hfc(cs, HFCSX_STATES, HFCSX_ACTIVATE | HFCSX_DO_ACTION);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (HW_DEACTIVATE | REQUEST):
- spin_lock_irqsave(&cs->lock, flags);
- cs->hw.hfcsx.mst_m &= ~HFCSX_MASTER;
- Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (HW_INFO3 | REQUEST):
- spin_lock_irqsave(&cs->lock, flags);
- cs->hw.hfcsx.mst_m |= HFCSX_MASTER;
- Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (HW_TESTLOOP | REQUEST):
- spin_lock_irqsave(&cs->lock, flags);
- switch ((long) arg) {
- case (1):
- Write_hfc(cs, HFCSX_B1_SSL, 0x80); /* tx slot */
- Write_hfc(cs, HFCSX_B1_RSL, 0x80); /* rx slot */
- cs->hw.hfcsx.conn = (cs->hw.hfcsx.conn & ~7) | 1;
- Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn);
- break;
- case (2):
- Write_hfc(cs, HFCSX_B2_SSL, 0x81); /* tx slot */
- Write_hfc(cs, HFCSX_B2_RSL, 0x81); /* rx slot */
- cs->hw.hfcsx.conn = (cs->hw.hfcsx.conn & ~0x38) | 0x08;
- Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn);
- break;
- default:
- spin_unlock_irqrestore(&cs->lock, flags);
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "hfcsx_l1hw loop invalid %4lx", (unsigned long)arg);
- return;
- }
- cs->hw.hfcsx.trm |= 0x80; /* enable IOM-loop */
- Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- default:
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "hfcsx_l1hw unknown pr %4x", pr);
- break;
- }
-}
-
-/***********************************************/
-/* called during init setting l1 stack pointer */
-/***********************************************/
-static void
-setstack_hfcsx(struct PStack *st, struct IsdnCardState *cs)
-{
- st->l1.l1hw = HFCSX_l1hw;
-}
-
-/**************************************/
-/* send B-channel data if not blocked */
-/**************************************/
-static void
-hfcsx_send_data(struct BCState *bcs)
-{
- struct IsdnCardState *cs = bcs->cs;
-
- if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- hfcsx_fill_fifo(bcs);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- } else
- debugl1(cs, "send_data %d blocked", bcs->channel);
-}
-
-/***************************************************************/
-/* activate/deactivate hardware for selected channels and mode */
-/***************************************************************/
-static void
-mode_hfcsx(struct BCState *bcs, int mode, int bc)
-{
- struct IsdnCardState *cs = bcs->cs;
- int fifo2;
-
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "HFCSX bchannel mode %d bchan %d/%d",
- mode, bc, bcs->channel);
- bcs->mode = mode;
- bcs->channel = bc;
- fifo2 = bc;
- if (cs->chanlimit > 1) {
- cs->hw.hfcsx.bswapped = 0; /* B1 and B2 normal mode */
- cs->hw.hfcsx.sctrl_e &= ~0x80;
- } else {
- if (bc) {
- if (mode != L1_MODE_NULL) {
- cs->hw.hfcsx.bswapped = 1; /* B1 and B2 exchanged */
- cs->hw.hfcsx.sctrl_e |= 0x80;
- } else {
- cs->hw.hfcsx.bswapped = 0; /* B1 and B2 normal mode */
- cs->hw.hfcsx.sctrl_e &= ~0x80;
- }
- fifo2 = 0;
- } else {
- cs->hw.hfcsx.bswapped = 0; /* B1 and B2 normal mode */
- cs->hw.hfcsx.sctrl_e &= ~0x80;
- }
- }
- switch (mode) {
- case (L1_MODE_NULL):
- if (bc) {
- cs->hw.hfcsx.sctrl &= ~SCTRL_B2_ENA;
- cs->hw.hfcsx.sctrl_r &= ~SCTRL_B2_ENA;
- } else {
- cs->hw.hfcsx.sctrl &= ~SCTRL_B1_ENA;
- cs->hw.hfcsx.sctrl_r &= ~SCTRL_B1_ENA;
- }
- if (fifo2) {
- cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC);
- } else {
- cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC);
- }
- break;
- case (L1_MODE_TRANS):
- if (bc) {
- cs->hw.hfcsx.sctrl |= SCTRL_B2_ENA;
- cs->hw.hfcsx.sctrl_r |= SCTRL_B2_ENA;
- } else {
- cs->hw.hfcsx.sctrl |= SCTRL_B1_ENA;
- cs->hw.hfcsx.sctrl_r |= SCTRL_B1_ENA;
- }
- if (fifo2) {
- cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC);
- cs->hw.hfcsx.ctmt |= 2;
- cs->hw.hfcsx.conn &= ~0x18;
- } else {
- cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC);
- cs->hw.hfcsx.ctmt |= 1;
- cs->hw.hfcsx.conn &= ~0x03;
- }
- break;
- case (L1_MODE_HDLC):
- if (bc) {
- cs->hw.hfcsx.sctrl |= SCTRL_B2_ENA;
- cs->hw.hfcsx.sctrl_r |= SCTRL_B2_ENA;
- } else {
- cs->hw.hfcsx.sctrl |= SCTRL_B1_ENA;
- cs->hw.hfcsx.sctrl_r |= SCTRL_B1_ENA;
- }
- if (fifo2) {
- cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC);
- cs->hw.hfcsx.ctmt &= ~2;
- cs->hw.hfcsx.conn &= ~0x18;
- } else {
- cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC);
- cs->hw.hfcsx.ctmt &= ~1;
- cs->hw.hfcsx.conn &= ~0x03;
- }
- break;
- case (L1_MODE_EXTRN):
- if (bc) {
- cs->hw.hfcsx.conn |= 0x10;
- cs->hw.hfcsx.sctrl |= SCTRL_B2_ENA;
- cs->hw.hfcsx.sctrl_r |= SCTRL_B2_ENA;
- cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC);
- } else {
- cs->hw.hfcsx.conn |= 0x02;
- cs->hw.hfcsx.sctrl |= SCTRL_B1_ENA;
- cs->hw.hfcsx.sctrl_r |= SCTRL_B1_ENA;
- cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC);
- }
- break;
- }
- Write_hfc(cs, HFCSX_SCTRL_E, cs->hw.hfcsx.sctrl_e);
- Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
- Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl);
- Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.sctrl_r);
- Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt);
- Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn);
- if (mode != L1_MODE_EXTRN) {
- reset_fifo(cs, fifo2 ? HFCSX_SEL_B2_RX : HFCSX_SEL_B1_RX);
- reset_fifo(cs, fifo2 ? HFCSX_SEL_B2_TX : HFCSX_SEL_B1_TX);
- }
-}
-
-/******************************/
-/* Layer2 -> Layer 1 Transfer */
-/******************************/
-static void
-hfcsx_l2l1(struct PStack *st, int pr, void *arg)
-{
- struct BCState *bcs = st->l1.bcs;
- struct sk_buff *skb = arg;
- u_long flags;
-
- switch (pr) {
- case (PH_DATA | REQUEST):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- if (bcs->tx_skb) {
- skb_queue_tail(&bcs->squeue, skb);
- } else {
- bcs->tx_skb = skb;
-// test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->cs->BC_Send_Data(bcs);
- }
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- break;
- case (PH_PULL | INDICATION):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- if (bcs->tx_skb) {
- printk(KERN_WARNING "%s: this shouldn't happen\n",
- __func__);
- } else {
-// test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->tx_skb = skb;
- bcs->cs->BC_Send_Data(bcs);
- }
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- break;
- case (PH_PULL | REQUEST):
- if (!bcs->tx_skb) {
- test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
- } else
- test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- break;
- case (PH_ACTIVATE | REQUEST):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
- mode_hfcsx(bcs, st->l1.mode, st->l1.bc);
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- l1_msg_b(st, pr, arg);
- break;
- case (PH_DEACTIVATE | REQUEST):
- l1_msg_b(st, pr, arg);
- break;
- case (PH_DEACTIVATE | CONFIRM):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- mode_hfcsx(bcs, 0, st->l1.bc);
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
- break;
- }
-}
-
-/******************************************/
-/* deactivate B-channel access and queues */
-/******************************************/
-static void
-close_hfcsx(struct BCState *bcs)
-{
- mode_hfcsx(bcs, 0, bcs->channel);
- if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
- skb_queue_purge(&bcs->rqueue);
- skb_queue_purge(&bcs->squeue);
- if (bcs->tx_skb) {
- dev_kfree_skb_any(bcs->tx_skb);
- bcs->tx_skb = NULL;
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- }
- }
-}
-
-/*************************************/
-/* init B-channel queues and control */
-/*************************************/
-static int
-open_hfcsxstate(struct IsdnCardState *cs, struct BCState *bcs)
-{
- if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
- skb_queue_head_init(&bcs->rqueue);
- skb_queue_head_init(&bcs->squeue);
- }
- bcs->tx_skb = NULL;
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->event = 0;
- bcs->tx_cnt = 0;
- return (0);
-}
-
-/*********************************/
-/* inits the stack for B-channel */
-/*********************************/
-static int
-setstack_2b(struct PStack *st, struct BCState *bcs)
-{
- bcs->channel = st->l1.bc;
- if (open_hfcsxstate(st->l1.hardware, bcs))
- return (-1);
- st->l1.bcs = bcs;
- st->l2.l2l1 = hfcsx_l2l1;
- setstack_manager(st);
- bcs->st = st;
- setstack_l1_B(st);
- return (0);
-}
-
-/***************************/
-/* handle L1 state changes */
-/***************************/
-static void
-hfcsx_bh(struct work_struct *work)
-{
- struct IsdnCardState *cs =
- container_of(work, struct IsdnCardState, tqueue);
- u_long flags;
-
- if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
- if (!cs->hw.hfcsx.nt_mode)
- switch (cs->dc.hfcsx.ph_state) {
- case (0):
- l1_msg(cs, HW_RESET | INDICATION, NULL);
- break;
- case (3):
- l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
- break;
- case (8):
- l1_msg(cs, HW_RSYNC | INDICATION, NULL);
- break;
- case (6):
- l1_msg(cs, HW_INFO2 | INDICATION, NULL);
- break;
- case (7):
- l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
- break;
- default:
- break;
- } else {
- switch (cs->dc.hfcsx.ph_state) {
- case (2):
- spin_lock_irqsave(&cs->lock, flags);
- if (cs->hw.hfcsx.nt_timer < 0) {
- cs->hw.hfcsx.nt_timer = 0;
- cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER;
- Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
- /* Clear already pending ints */
- Read_hfc(cs, HFCSX_INT_S1);
-
- Write_hfc(cs, HFCSX_STATES, 4 | HFCSX_LOAD_STATE);
- udelay(10);
- Write_hfc(cs, HFCSX_STATES, 4);
- cs->dc.hfcsx.ph_state = 4;
- } else {
- cs->hw.hfcsx.int_m1 |= HFCSX_INTS_TIMER;
- Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
- cs->hw.hfcsx.ctmt &= ~HFCSX_AUTO_TIMER;
- cs->hw.hfcsx.ctmt |= HFCSX_TIM3_125;
- Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt | HFCSX_CLTIMER);
- Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt | HFCSX_CLTIMER);
- cs->hw.hfcsx.nt_timer = NT_T1_COUNT;
- Write_hfc(cs, HFCSX_STATES, 2 | HFCSX_NT_G2_G3); /* allow G2 -> G3 transition */
- }
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (1):
- case (3):
- case (4):
- spin_lock_irqsave(&cs->lock, flags);
- cs->hw.hfcsx.nt_timer = 0;
- cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER;
- Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- default:
- break;
- }
- }
- }
- if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
- DChannel_proc_rcv(cs);
- if (test_and_clear_bit(D_XMTBUFREADY, &cs->event))
- DChannel_proc_xmt(cs);
-}
-
-
-/********************************/
-/* called for card init message */
-/********************************/
-static void inithfcsx(struct IsdnCardState *cs)
-{
- cs->setstack_d = setstack_hfcsx;
- cs->BC_Send_Data = &hfcsx_send_data;
- cs->bcs[0].BC_SetStack = setstack_2b;
- cs->bcs[1].BC_SetStack = setstack_2b;
- cs->bcs[0].BC_Close = close_hfcsx;
- cs->bcs[1].BC_Close = close_hfcsx;
- mode_hfcsx(cs->bcs, 0, 0);
- mode_hfcsx(cs->bcs + 1, 0, 1);
-}
-
-
-
-/*******************************************/
-/* handle card messages from control layer */
-/*******************************************/
-static int
-hfcsx_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
- u_long flags;
-
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "HFCSX: card_msg %x", mt);
- switch (mt) {
- case CARD_RESET:
- spin_lock_irqsave(&cs->lock, flags);
- reset_hfcsx(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_RELEASE:
- release_io_hfcsx(cs);
- return (0);
- case CARD_INIT:
- spin_lock_irqsave(&cs->lock, flags);
- inithfcsx(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- msleep(80); /* Timeout 80ms */
- /* now switch timer interrupt off */
- spin_lock_irqsave(&cs->lock, flags);
- cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER;
- Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
- /* reinit mode reg */
- Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_TEST:
- return (0);
- }
- return (0);
-}
-
-#ifdef __ISAPNP__
-static struct isapnp_device_id hfc_ids[] = {
- { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2620),
- ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2620),
- (unsigned long) "Teles 16.3c2" },
- { 0, }
-};
-
-static struct isapnp_device_id *ipid = &hfc_ids[0];
-static struct pnp_card *pnp_c = NULL;
-#endif
-
-int setup_hfcsx(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
-
- strcpy(tmp, hfcsx_revision);
- printk(KERN_INFO "HiSax: HFC-SX driver Rev. %s\n", HiSax_getrev(tmp));
-#ifdef __ISAPNP__
- if (!card->para[1] && isapnp_present()) {
- struct pnp_dev *pnp_d;
- while (ipid->card_vendor) {
- if ((pnp_c = pnp_find_card(ipid->card_vendor,
- ipid->card_device, pnp_c))) {
- pnp_d = NULL;
- if ((pnp_d = pnp_find_dev(pnp_c,
- ipid->vendor, ipid->function, pnp_d))) {
- int err;
-
- printk(KERN_INFO "HiSax: %s detected\n",
- (char *)ipid->driver_data);
- pnp_disable_dev(pnp_d);
- err = pnp_activate_dev(pnp_d);
- if (err < 0) {
- printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __func__, err);
- return (0);
- }
- card->para[1] = pnp_port_start(pnp_d, 0);
- card->para[0] = pnp_irq(pnp_d, 0);
- if (card->para[0] == -1 || !card->para[1]) {
- printk(KERN_ERR "HFC PnP:some resources are missing %ld/%lx\n",
- card->para[0], card->para[1]);
- pnp_disable_dev(pnp_d);
- return (0);
- }
- break;
- } else {
- printk(KERN_ERR "HFC PnP: PnP error card found, no device\n");
- }
- }
- ipid++;
- pnp_c = NULL;
- }
- if (!ipid->card_vendor) {
- printk(KERN_INFO "HFC PnP: no ISAPnP card found\n");
- return (0);
- }
- }
-#endif
- cs->hw.hfcsx.base = card->para[1] & 0xfffe;
- cs->irq = card->para[0];
- cs->hw.hfcsx.int_s1 = 0;
- cs->dc.hfcsx.ph_state = 0;
- cs->hw.hfcsx.fifo = 255;
- if ((cs->typ == ISDN_CTYPE_HFC_SX) ||
- (cs->typ == ISDN_CTYPE_HFC_SP_PCMCIA)) {
- if ((!cs->hw.hfcsx.base) || !request_region(cs->hw.hfcsx.base, 2, "HFCSX isdn")) {
- printk(KERN_WARNING
- "HiSax: HFC-SX io-base %#lx already in use\n",
- cs->hw.hfcsx.base);
- return (0);
- }
- byteout(cs->hw.hfcsx.base, cs->hw.hfcsx.base & 0xFF);
- byteout(cs->hw.hfcsx.base + 1,
- ((cs->hw.hfcsx.base >> 8) & 3) | 0x54);
- udelay(10);
- cs->hw.hfcsx.chip = Read_hfc(cs, HFCSX_CHIP_ID);
- switch (cs->hw.hfcsx.chip >> 4) {
- case 1:
- tmp[0] = '+';
- break;
- case 9:
- tmp[0] = 'P';
- break;
- default:
- printk(KERN_WARNING
- "HFC-SX: invalid chip id 0x%x\n",
- cs->hw.hfcsx.chip >> 4);
- release_region(cs->hw.hfcsx.base, 2);
- return (0);
- }
- if (!ccd_sp_irqtab[cs->irq & 0xF]) {
- printk(KERN_WARNING
- "HFC_SX: invalid irq %d specified\n", cs->irq & 0xF);
- release_region(cs->hw.hfcsx.base, 2);
- return (0);
- }
- if (!(cs->hw.hfcsx.extra =
- kmalloc(sizeof(struct hfcsx_extra), GFP_ATOMIC))) {
- release_region(cs->hw.hfcsx.base, 2);
- printk(KERN_WARNING "HFC-SX: unable to allocate memory\n");
- return (0);
- }
- printk(KERN_INFO "HFC-S%c chip detected at base 0x%x IRQ %d HZ %d\n",
- tmp[0], (u_int) cs->hw.hfcsx.base, cs->irq, HZ);
- cs->hw.hfcsx.int_m2 = 0; /* disable alle interrupts */
- cs->hw.hfcsx.int_m1 = 0;
- Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
- Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2);
- } else
- return (0); /* no valid card type */
-
- timer_setup(&cs->dbusytimer, hfcsx_dbusy_timer, 0);
- INIT_WORK(&cs->tqueue, hfcsx_bh);
- cs->readisac = NULL;
- cs->writeisac = NULL;
- cs->readisacfifo = NULL;
- cs->writeisacfifo = NULL;
- cs->BC_Read_Reg = NULL;
- cs->BC_Write_Reg = NULL;
- cs->irq_func = &hfcsx_interrupt;
-
- cs->hw.hfcsx.b_fifo_size = 0; /* fifo size still unknown */
- cs->hw.hfcsx.cirm = ccd_sp_irqtab[cs->irq & 0xF]; /* RAM not evaluated */
- timer_setup(&cs->hw.hfcsx.timer, hfcsx_Timer, 0);
-
- reset_hfcsx(cs);
- cs->cardmsg = &hfcsx_card_msg;
- cs->auxcmd = &hfcsx_auxcmd;
- return (1);
-}
diff --git a/drivers/isdn/hisax/hfc_sx.h b/drivers/isdn/hisax/hfc_sx.h
deleted file mode 100644
index eee85dbb0883..000000000000
--- a/drivers/isdn/hisax/hfc_sx.h
+++ /dev/null
@@ -1,196 +0,0 @@
-/* $Id: hfc_sx.h,v 1.2.6.1 2001/09/23 22:24:48 kai Exp $
- *
- * specific defines for CCD's HFC 2BDS0 S+,SP chips
- *
- * Author Werner Cornelius
- * based on existing driver for CCD HFC PCI cards
- * Copyright by Werner Cornelius <werner@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-/*********************************************/
-/* thresholds for transparent B-channel mode */
-/* change mask and threshold simultaneously */
-/*********************************************/
-#define HFCSX_BTRANS_THRESHOLD 128
-#define HFCSX_BTRANS_THRESMASK 0x00
-
-/* GCI/IOM bus monitor registers */
-
-#define HFCSX_C_I 0x02
-#define HFCSX_TRxR 0x03
-#define HFCSX_MON1_D 0x0A
-#define HFCSX_MON2_D 0x0B
-
-
-/* GCI/IOM bus timeslot registers */
-
-#define HFCSX_B1_SSL 0x20
-#define HFCSX_B2_SSL 0x21
-#define HFCSX_AUX1_SSL 0x22
-#define HFCSX_AUX2_SSL 0x23
-#define HFCSX_B1_RSL 0x24
-#define HFCSX_B2_RSL 0x25
-#define HFCSX_AUX1_RSL 0x26
-#define HFCSX_AUX2_RSL 0x27
-
-/* GCI/IOM bus data registers */
-
-#define HFCSX_B1_D 0x28
-#define HFCSX_B2_D 0x29
-#define HFCSX_AUX1_D 0x2A
-#define HFCSX_AUX2_D 0x2B
-
-/* GCI/IOM bus configuration registers */
-
-#define HFCSX_MST_EMOD 0x2D
-#define HFCSX_MST_MODE 0x2E
-#define HFCSX_CONNECT 0x2F
-
-
-/* Interrupt and status registers */
-
-#define HFCSX_TRM 0x12
-#define HFCSX_B_MODE 0x13
-#define HFCSX_CHIP_ID 0x16
-#define HFCSX_CIRM 0x18
-#define HFCSX_CTMT 0x19
-#define HFCSX_INT_M1 0x1A
-#define HFCSX_INT_M2 0x1B
-#define HFCSX_INT_S1 0x1E
-#define HFCSX_INT_S2 0x1F
-#define HFCSX_STATUS 0x1C
-
-/* S/T section registers */
-
-#define HFCSX_STATES 0x30
-#define HFCSX_SCTRL 0x31
-#define HFCSX_SCTRL_E 0x32
-#define HFCSX_SCTRL_R 0x33
-#define HFCSX_SQ 0x34
-#define HFCSX_CLKDEL 0x37
-#define HFCSX_B1_REC 0x3C
-#define HFCSX_B1_SEND 0x3C
-#define HFCSX_B2_REC 0x3D
-#define HFCSX_B2_SEND 0x3D
-#define HFCSX_D_REC 0x3E
-#define HFCSX_D_SEND 0x3E
-#define HFCSX_E_REC 0x3F
-
-/****************/
-/* FIFO section */
-/****************/
-#define HFCSX_FIF_SEL 0x10
-#define HFCSX_FIF_Z1L 0x80
-#define HFCSX_FIF_Z1H 0x84
-#define HFCSX_FIF_Z2L 0x88
-#define HFCSX_FIF_Z2H 0x8C
-#define HFCSX_FIF_INCF1 0xA8
-#define HFCSX_FIF_DWR 0xAC
-#define HFCSX_FIF_F1 0xB0
-#define HFCSX_FIF_F2 0xB4
-#define HFCSX_FIF_INCF2 0xB8
-#define HFCSX_FIF_DRD 0xBC
-
-/* bits in status register (READ) */
-#define HFCSX_SX_PROC 0x02
-#define HFCSX_NBUSY 0x04
-#define HFCSX_TIMER_ELAP 0x10
-#define HFCSX_STATINT 0x20
-#define HFCSX_FRAMEINT 0x40
-#define HFCSX_ANYINT 0x80
-
-/* bits in CTMT (Write) */
-#define HFCSX_CLTIMER 0x80
-#define HFCSX_TIM3_125 0x04
-#define HFCSX_TIM25 0x10
-#define HFCSX_TIM50 0x14
-#define HFCSX_TIM400 0x18
-#define HFCSX_TIM800 0x1C
-#define HFCSX_AUTO_TIMER 0x20
-#define HFCSX_TRANSB2 0x02
-#define HFCSX_TRANSB1 0x01
-
-/* bits in CIRM (Write) */
-#define HFCSX_IRQ_SELMSK 0x07
-#define HFCSX_IRQ_SELDIS 0x00
-#define HFCSX_RESET 0x08
-#define HFCSX_FIFO_RESET 0x80
-
-
-/* bits in INT_M1 and INT_S1 */
-#define HFCSX_INTS_B1TRANS 0x01
-#define HFCSX_INTS_B2TRANS 0x02
-#define HFCSX_INTS_DTRANS 0x04
-#define HFCSX_INTS_B1REC 0x08
-#define HFCSX_INTS_B2REC 0x10
-#define HFCSX_INTS_DREC 0x20
-#define HFCSX_INTS_L1STATE 0x40
-#define HFCSX_INTS_TIMER 0x80
-
-/* bits in INT_M2 */
-#define HFCSX_PROC_TRANS 0x01
-#define HFCSX_GCI_I_CHG 0x02
-#define HFCSX_GCI_MON_REC 0x04
-#define HFCSX_IRQ_ENABLE 0x08
-
-/* bits in STATES */
-#define HFCSX_STATE_MSK 0x0F
-#define HFCSX_LOAD_STATE 0x10
-#define HFCSX_ACTIVATE 0x20
-#define HFCSX_DO_ACTION 0x40
-#define HFCSX_NT_G2_G3 0x80
-
-/* bits in HFCD_MST_MODE */
-#define HFCSX_MASTER 0x01
-#define HFCSX_SLAVE 0x00
-/* remaining bits are for codecs control */
-
-/* bits in HFCD_SCTRL */
-#define SCTRL_B1_ENA 0x01
-#define SCTRL_B2_ENA 0x02
-#define SCTRL_MODE_TE 0x00
-#define SCTRL_MODE_NT 0x04
-#define SCTRL_LOW_PRIO 0x08
-#define SCTRL_SQ_ENA 0x10
-#define SCTRL_TEST 0x20
-#define SCTRL_NONE_CAP 0x40
-#define SCTRL_PWR_DOWN 0x80
-
-/* bits in SCTRL_E */
-#define HFCSX_AUTO_AWAKE 0x01
-#define HFCSX_DBIT_1 0x04
-#define HFCSX_IGNORE_COL 0x08
-#define HFCSX_CHG_B1_B2 0x80
-
-/**********************************/
-/* definitions for FIFO selection */
-/**********************************/
-#define HFCSX_SEL_D_RX 5
-#define HFCSX_SEL_D_TX 4
-#define HFCSX_SEL_B1_RX 1
-#define HFCSX_SEL_B1_TX 0
-#define HFCSX_SEL_B2_RX 3
-#define HFCSX_SEL_B2_TX 2
-
-#define MAX_D_FRAMES 15
-#define MAX_B_FRAMES 31
-#define B_SUB_VAL_32K 0x0200
-#define B_FIFO_SIZE_32K (0x2000 - B_SUB_VAL_32K)
-#define B_SUB_VAL_8K 0x1A00
-#define B_FIFO_SIZE_8K (0x2000 - B_SUB_VAL_8K)
-#define D_FIFO_SIZE 512
-#define D_FREG_MASK 0xF
-
-/************************************************************/
-/* structure holding additional dynamic data -> send marker */
-/************************************************************/
-struct hfcsx_extra {
- unsigned short marker[2 * (MAX_B_FRAMES + 1) + (MAX_D_FRAMES + 1)];
-};
-
-extern void main_irq_hfcsx(struct BCState *bcs);
-extern void releasehfcsx(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c
deleted file mode 100644
index b6e58c11c288..000000000000
--- a/drivers/isdn/hisax/hfc_usb.c
+++ /dev/null
@@ -1,1594 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * hfc_usb.c
- *
- * $Id: hfc_usb.c,v 2.3.2.24 2007/10/14 08:40:29 mbachem Exp $
- *
- * modular HiSax ISDN driver for Colognechip HFC-S USB chip
- *
- * Authors : Peter Sprenger (sprenger@moving-bytes.de)
- * Martin Bachem (m.bachem@gmx.de, info@colognechip.com)
- *
- * based on the first hfc_usb driver of
- * Werner Cornelius (werner@isdn-development.de)
- *
- * See Version Histroy at the bottom of this file
- */
-
-#include <linux/types.h>
-#include <linux/stddef.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/kernel_stat.h>
-#include <linux/usb.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/moduleparam.h>
-#include <linux/slab.h>
-#include "hisax.h"
-#include "hisax_if.h"
-#include "hfc_usb.h"
-
-static const char *hfcusb_revision =
- "$Revision: 2.3.2.24 $ $Date: 2007/10/14 08:40:29 $ ";
-
-/* Hisax debug support
- * debug flags defined in hfc_usb.h as HFCUSB_DBG_[*]
- */
-#define __debug_variable hfc_debug
-#include "hisax_debug.h"
-static u_int debug;
-module_param(debug, uint, 0);
-static int hfc_debug;
-
-
-/* private vendor specific data */
-typedef struct {
- __u8 led_scheme; // led display scheme
- signed short led_bits[8]; // array of 8 possible LED bitmask settings
- char *vend_name; // device name
-} hfcsusb_vdata;
-
-/* VID/PID device list */
-static const struct usb_device_id hfcusb_idtab[] = {
- {
- USB_DEVICE(0x0959, 0x2bd0),
- .driver_info = (unsigned long) &((hfcsusb_vdata)
- {LED_OFF, {4, 0, 2, 1},
- "ISDN USB TA (Cologne Chip HFC-S USB based)"}),
- },
- {
- USB_DEVICE(0x0675, 0x1688),
- .driver_info = (unsigned long) &((hfcsusb_vdata)
- {LED_SCHEME1, {1, 2, 0, 0},
- "DrayTek miniVigor 128 USB ISDN TA"}),
- },
- {
- USB_DEVICE(0x07b0, 0x0007),
- .driver_info = (unsigned long) &((hfcsusb_vdata)
- {LED_SCHEME1, {0x80, -64, -32, -16},
- "Billion tiny USB ISDN TA 128"}),
- },
- {
- USB_DEVICE(0x0742, 0x2008),
- .driver_info = (unsigned long) &((hfcsusb_vdata)
- {LED_SCHEME1, {4, 0, 2, 1},
- "Stollmann USB TA"}),
- },
- {
- USB_DEVICE(0x0742, 0x2009),
- .driver_info = (unsigned long) &((hfcsusb_vdata)
- {LED_SCHEME1, {4, 0, 2, 1},
- "Aceex USB ISDN TA"}),
- },
- {
- USB_DEVICE(0x0742, 0x200A),
- .driver_info = (unsigned long) &((hfcsusb_vdata)
- {LED_SCHEME1, {4, 0, 2, 1},
- "OEM USB ISDN TA"}),
- },
- {
- USB_DEVICE(0x08e3, 0x0301),
- .driver_info = (unsigned long) &((hfcsusb_vdata)
- {LED_SCHEME1, {2, 0, 1, 4},
- "Olitec USB RNIS"}),
- },
- {
- USB_DEVICE(0x07fa, 0x0846),
- .driver_info = (unsigned long) &((hfcsusb_vdata)
- {LED_SCHEME1, {0x80, -64, -32, -16},
- "Bewan Modem RNIS USB"}),
- },
- {
- USB_DEVICE(0x07fa, 0x0847),
- .driver_info = (unsigned long) &((hfcsusb_vdata)
- {LED_SCHEME1, {0x80, -64, -32, -16},
- "Djinn Numeris USB"}),
- },
- {
- USB_DEVICE(0x07b0, 0x0006),
- .driver_info = (unsigned long) &((hfcsusb_vdata)
- {LED_SCHEME1, {0x80, -64, -32, -16},
- "Twister ISDN TA"}),
- },
- {
- USB_DEVICE(0x071d, 0x1005),
- .driver_info = (unsigned long) &((hfcsusb_vdata)
- {LED_SCHEME1, {0x02, 0, 0x01, 0x04},
- "Eicon DIVA USB 4.0"}),
- },
- { }
-};
-
-/* structure defining input+output fifos (interrupt/bulk mode) */
-struct usb_fifo; /* forward definition */
-typedef struct iso_urb_struct {
- struct urb *purb;
- __u8 buffer[ISO_BUFFER_SIZE]; /* buffer incoming/outgoing data */
- struct usb_fifo *owner_fifo; /* pointer to owner fifo */
-} iso_urb_struct;
-
-struct hfcusb_data; /* forward definition */
-
-typedef struct usb_fifo {
- int fifonum; /* fifo index attached to this structure */
- int active; /* fifo is currently active */
- struct hfcusb_data *hfc; /* pointer to main structure */
- int pipe; /* address of endpoint */
- __u8 usb_packet_maxlen; /* maximum length for usb transfer */
- unsigned int max_size; /* maximum size of receive/send packet */
- __u8 intervall; /* interrupt interval */
- struct sk_buff *skbuff; /* actual used buffer */
- struct urb *urb; /* transfer structure for usb routines */
- __u8 buffer[128]; /* buffer incoming/outgoing data */
- int bit_line; /* how much bits are in the fifo? */
-
- volatile __u8 usb_transfer_mode; /* switched between ISO and INT */
- iso_urb_struct iso[2]; /* need two urbs to have one always for pending */
- struct hisax_if *hif; /* hisax interface */
- int delete_flg; /* only delete skbuff once */
- int last_urblen; /* remember length of last packet */
-} usb_fifo;
-
-/* structure holding all data for one device */
-typedef struct hfcusb_data {
- /* HiSax Interface for loadable Layer1 drivers */
- struct hisax_d_if d_if; /* see hisax_if.h */
- struct hisax_b_if b_if[2]; /* see hisax_if.h */
- int protocol;
-
- struct usb_device *dev; /* our device */
- int if_used; /* used interface number */
- int alt_used; /* used alternate config */
- int ctrl_paksize; /* control pipe packet size */
- int ctrl_in_pipe, /* handles for control pipe */
- ctrl_out_pipe;
- int cfg_used; /* configuration index used */
- int vend_idx; /* vendor found */
- int b_mode[2]; /* B-channel mode */
- int l1_activated; /* layer 1 activated */
- int disc_flag; /* TRUE if device was disonnected to avoid some USB actions */
- int packet_size, iso_packet_size;
-
- /* control pipe background handling */
- ctrl_buft ctrl_buff[HFC_CTRL_BUFSIZE]; /* buffer holding queued data */
- volatile int ctrl_in_idx, ctrl_out_idx, ctrl_cnt; /* input/output pointer + count */
- struct urb *ctrl_urb; /* transfer structure for control channel */
-
- struct usb_ctrlrequest ctrl_write; /* buffer for control write request */
- struct usb_ctrlrequest ctrl_read; /* same for read request */
-
- __u8 old_led_state, led_state;
-
- volatile __u8 threshold_mask; /* threshold actually reported */
- volatile __u8 bch_enables; /* or mask for sctrl_r and sctrl register values */
-
- usb_fifo fifos[HFCUSB_NUM_FIFOS]; /* structure holding all fifo data */
-
- volatile __u8 l1_state; /* actual l1 state */
- struct timer_list t3_timer; /* timer 3 for activation/deactivation */
- struct timer_list t4_timer; /* timer 4 for activation/deactivation */
-} hfcusb_data;
-
-
-static void collect_rx_frame(usb_fifo *fifo, __u8 *data, int len,
- int finish);
-
-static inline const char *
-symbolic(struct hfcusb_symbolic_list list[], const int num)
-{
- int i;
- for (i = 0; list[i].name != NULL; i++)
- if (list[i].num == num)
- return (list[i].name);
- return "<unknown ERROR>";
-}
-
-static void
-ctrl_start_transfer(hfcusb_data *hfc)
-{
- if (hfc->ctrl_cnt) {
- hfc->ctrl_urb->pipe = hfc->ctrl_out_pipe;
- hfc->ctrl_urb->setup_packet = (u_char *)&hfc->ctrl_write;
- hfc->ctrl_urb->transfer_buffer = NULL;
- hfc->ctrl_urb->transfer_buffer_length = 0;
- hfc->ctrl_write.wIndex =
- cpu_to_le16(hfc->ctrl_buff[hfc->ctrl_out_idx].hfc_reg);
- hfc->ctrl_write.wValue =
- cpu_to_le16(hfc->ctrl_buff[hfc->ctrl_out_idx].reg_val);
-
- usb_submit_urb(hfc->ctrl_urb, GFP_ATOMIC); /* start transfer */
- }
-} /* ctrl_start_transfer */
-
-static int
-queue_control_request(hfcusb_data *hfc, __u8 reg, __u8 val, int action)
-{
- ctrl_buft *buf;
-
- if (hfc->ctrl_cnt >= HFC_CTRL_BUFSIZE)
- return (1); /* no space left */
- buf = &hfc->ctrl_buff[hfc->ctrl_in_idx]; /* pointer to new index */
- buf->hfc_reg = reg;
- buf->reg_val = val;
- buf->action = action;
- if (++hfc->ctrl_in_idx >= HFC_CTRL_BUFSIZE)
- hfc->ctrl_in_idx = 0; /* pointer wrap */
- if (++hfc->ctrl_cnt == 1)
- ctrl_start_transfer(hfc);
- return (0);
-}
-
-static void
-ctrl_complete(struct urb *urb)
-{
- hfcusb_data *hfc = (hfcusb_data *) urb->context;
-
- urb->dev = hfc->dev;
- if (hfc->ctrl_cnt) {
- hfc->ctrl_cnt--; /* decrement actual count */
- if (++hfc->ctrl_out_idx >= HFC_CTRL_BUFSIZE)
- hfc->ctrl_out_idx = 0; /* pointer wrap */
-
- ctrl_start_transfer(hfc); /* start next transfer */
- }
-}
-
-/* write led data to auxport & invert if necessary */
-static void
-write_led(hfcusb_data *hfc, __u8 led_state)
-{
- if (led_state != hfc->old_led_state) {
- hfc->old_led_state = led_state;
- queue_control_request(hfc, HFCUSB_P_DATA, led_state, 1);
- }
-}
-
-static void
-set_led_bit(hfcusb_data *hfc, signed short led_bits, int on)
-{
- if (on) {
- if (led_bits < 0)
- hfc->led_state &= ~abs(led_bits);
- else
- hfc->led_state |= led_bits;
- } else {
- if (led_bits < 0)
- hfc->led_state |= abs(led_bits);
- else
- hfc->led_state &= ~led_bits;
- }
-}
-
-/* handle LED requests */
-static void
-handle_led(hfcusb_data *hfc, int event)
-{
- hfcsusb_vdata *driver_info =
- (hfcsusb_vdata *) hfcusb_idtab[hfc->vend_idx].driver_info;
-
- /* if no scheme -> no LED action */
- if (driver_info->led_scheme == LED_OFF)
- return;
-
- switch (event) {
- case LED_POWER_ON:
- set_led_bit(hfc, driver_info->led_bits[0], 1);
- set_led_bit(hfc, driver_info->led_bits[1], 0);
- set_led_bit(hfc, driver_info->led_bits[2], 0);
- set_led_bit(hfc, driver_info->led_bits[3], 0);
- break;
- case LED_POWER_OFF:
- set_led_bit(hfc, driver_info->led_bits[0], 0);
- set_led_bit(hfc, driver_info->led_bits[1], 0);
- set_led_bit(hfc, driver_info->led_bits[2], 0);
- set_led_bit(hfc, driver_info->led_bits[3], 0);
- break;
- case LED_S0_ON:
- set_led_bit(hfc, driver_info->led_bits[1], 1);
- break;
- case LED_S0_OFF:
- set_led_bit(hfc, driver_info->led_bits[1], 0);
- break;
- case LED_B1_ON:
- set_led_bit(hfc, driver_info->led_bits[2], 1);
- break;
- case LED_B1_OFF:
- set_led_bit(hfc, driver_info->led_bits[2], 0);
- break;
- case LED_B2_ON:
- set_led_bit(hfc, driver_info->led_bits[3], 1);
- break;
- case LED_B2_OFF:
- set_led_bit(hfc, driver_info->led_bits[3], 0);
- break;
- }
- write_led(hfc, hfc->led_state);
-}
-
-/* ISDN l1 timer T3 expires */
-static void
-l1_timer_expire_t3(struct timer_list *t)
-{
- hfcusb_data *hfc = from_timer(hfc, t, t3_timer);
- hfc->d_if.ifc.l1l2(&hfc->d_if.ifc, PH_DEACTIVATE | INDICATION,
- NULL);
-
- DBG(HFCUSB_DBG_STATES,
- "HFC-S USB: PH_DEACTIVATE | INDICATION sent (T3 expire)");
-
- hfc->l1_activated = 0;
- handle_led(hfc, LED_S0_OFF);
- /* deactivate : */
- queue_control_request(hfc, HFCUSB_STATES, 0x10, 1);
- queue_control_request(hfc, HFCUSB_STATES, 3, 1);
-}
-
-/* ISDN l1 timer T4 expires */
-static void
-l1_timer_expire_t4(struct timer_list *t)
-{
- hfcusb_data *hfc = from_timer(hfc, t, t4_timer);
- hfc->d_if.ifc.l1l2(&hfc->d_if.ifc, PH_DEACTIVATE | INDICATION,
- NULL);
-
- DBG(HFCUSB_DBG_STATES,
- "HFC-S USB: PH_DEACTIVATE | INDICATION sent (T4 expire)");
-
- hfc->l1_activated = 0;
- handle_led(hfc, LED_S0_OFF);
-}
-
-/* S0 state changed */
-static void
-s0_state_handler(hfcusb_data *hfc, __u8 state)
-{
- __u8 old_state;
-
- old_state = hfc->l1_state;
- if (state == old_state || state < 1 || state > 8)
- return;
-
- DBG(HFCUSB_DBG_STATES, "HFC-S USB: S0 statechange(%d -> %d)",
- old_state, state);
-
- if (state < 4 || state == 7 || state == 8) {
- if (timer_pending(&hfc->t3_timer))
- del_timer(&hfc->t3_timer);
- DBG(HFCUSB_DBG_STATES, "HFC-S USB: T3 deactivated");
- }
- if (state >= 7) {
- if (timer_pending(&hfc->t4_timer))
- del_timer(&hfc->t4_timer);
- DBG(HFCUSB_DBG_STATES, "HFC-S USB: T4 deactivated");
- }
-
- if (state == 7 && !hfc->l1_activated) {
- hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,
- PH_ACTIVATE | INDICATION, NULL);
- DBG(HFCUSB_DBG_STATES, "HFC-S USB: PH_ACTIVATE | INDICATION sent");
- hfc->l1_activated = 1;
- handle_led(hfc, LED_S0_ON);
- } else if (state <= 3 /* && activated */) {
- if (old_state == 7 || old_state == 8) {
- DBG(HFCUSB_DBG_STATES, "HFC-S USB: T4 activated");
- if (!timer_pending(&hfc->t4_timer)) {
- hfc->t4_timer.expires =
- jiffies + (HFC_TIMER_T4 * HZ) / 1000;
- add_timer(&hfc->t4_timer);
- }
- } else {
- hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,
- PH_DEACTIVATE | INDICATION,
- NULL);
- DBG(HFCUSB_DBG_STATES,
- "HFC-S USB: PH_DEACTIVATE | INDICATION sent");
- hfc->l1_activated = 0;
- handle_led(hfc, LED_S0_OFF);
- }
- }
- hfc->l1_state = state;
-}
-
-static void
-fill_isoc_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe,
- void *buf, int num_packets, int packet_size, int interval,
- usb_complete_t complete, void *context)
-{
- int k;
-
- usb_fill_int_urb(urb, dev, pipe, buf, packet_size * num_packets,
- complete, context, interval);
-
- urb->number_of_packets = num_packets;
- urb->transfer_flags = URB_ISO_ASAP;
- urb->actual_length = 0;
- for (k = 0; k < num_packets; k++) {
- urb->iso_frame_desc[k].offset = packet_size * k;
- urb->iso_frame_desc[k].length = packet_size;
- urb->iso_frame_desc[k].actual_length = 0;
- }
-}
-
-/* allocs urbs and start isoc transfer with two pending urbs to avoid
- * gaps in the transfer chain
- */
-static int
-start_isoc_chain(usb_fifo *fifo, int num_packets_per_urb,
- usb_complete_t complete, int packet_size)
-{
- int i, k, errcode;
-
- DBG(HFCUSB_DBG_INIT, "HFC-S USB: starting ISO-URBs for fifo:%d\n",
- fifo->fifonum);
-
- /* allocate Memory for Iso out Urbs */
- for (i = 0; i < 2; i++) {
- if (!(fifo->iso[i].purb)) {
- fifo->iso[i].purb =
- usb_alloc_urb(num_packets_per_urb, GFP_KERNEL);
- if (!(fifo->iso[i].purb)) {
- printk(KERN_INFO
- "alloc urb for fifo %i failed!!!",
- fifo->fifonum);
- }
- fifo->iso[i].owner_fifo = (struct usb_fifo *) fifo;
-
- /* Init the first iso */
- if (ISO_BUFFER_SIZE >=
- (fifo->usb_packet_maxlen *
- num_packets_per_urb)) {
- fill_isoc_urb(fifo->iso[i].purb,
- fifo->hfc->dev, fifo->pipe,
- fifo->iso[i].buffer,
- num_packets_per_urb,
- fifo->usb_packet_maxlen,
- fifo->intervall, complete,
- &fifo->iso[i]);
- memset(fifo->iso[i].buffer, 0,
- sizeof(fifo->iso[i].buffer));
- /* defining packet delimeters in fifo->buffer */
- for (k = 0; k < num_packets_per_urb; k++) {
- fifo->iso[i].purb->
- iso_frame_desc[k].offset =
- k * packet_size;
- fifo->iso[i].purb->
- iso_frame_desc[k].length =
- packet_size;
- }
- } else {
- printk(KERN_INFO
- "HFC-S USB: ISO Buffer size to small!\n");
- }
- }
- fifo->bit_line = BITLINE_INF;
-
- errcode = usb_submit_urb(fifo->iso[i].purb, GFP_KERNEL);
- fifo->active = (errcode >= 0) ? 1 : 0;
- if (errcode < 0)
- printk(KERN_INFO "HFC-S USB: usb_submit_urb URB nr:%d, error(%i): '%s'\n",
- i, errcode, symbolic(urb_errlist, errcode));
- }
- return (fifo->active);
-}
-
-/* stops running iso chain and frees their pending urbs */
-static void
-stop_isoc_chain(usb_fifo *fifo)
-{
- int i;
-
- for (i = 0; i < 2; i++) {
- if (fifo->iso[i].purb) {
- DBG(HFCUSB_DBG_INIT,
- "HFC-S USB: Stopping iso chain for fifo %i.%i",
- fifo->fifonum, i);
- usb_kill_urb(fifo->iso[i].purb);
- usb_free_urb(fifo->iso[i].purb);
- fifo->iso[i].purb = NULL;
- }
- }
-
- usb_kill_urb(fifo->urb);
- usb_free_urb(fifo->urb);
- fifo->urb = NULL;
- fifo->active = 0;
-}
-
-/* defines how much ISO packets are handled in one URB */
-static int iso_packets[8] =
-{ ISOC_PACKETS_B, ISOC_PACKETS_B, ISOC_PACKETS_B, ISOC_PACKETS_B,
- ISOC_PACKETS_D, ISOC_PACKETS_D, ISOC_PACKETS_D, ISOC_PACKETS_D
-};
-
-static void
-tx_iso_complete(struct urb *urb)
-{
- iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context;
- usb_fifo *fifo = context_iso_urb->owner_fifo;
- hfcusb_data *hfc = fifo->hfc;
- int k, tx_offset, num_isoc_packets, sink, len, current_len,
- errcode;
- int frame_complete, transp_mode, fifon, status;
- __u8 threshbit;
-
- fifon = fifo->fifonum;
- status = urb->status;
-
- tx_offset = 0;
-
- /* ISO transfer only partially completed,
- look at individual frame status for details */
- if (status == -EXDEV) {
- DBG(HFCUSB_DBG_VERBOSE_USB, "HFC-S USB: tx_iso_complete with -EXDEV"
- ", urb->status %d, fifonum %d\n",
- status, fifon);
-
- for (k = 0; k < iso_packets[fifon]; ++k) {
- errcode = urb->iso_frame_desc[k].status;
- if (errcode)
- DBG(HFCUSB_DBG_VERBOSE_USB, "HFC-S USB: tx_iso_complete "
- "packet %i, status: %i\n",
- k, errcode);
- }
-
- // clear status, so go on with ISO transfers
- status = 0;
- }
-
- if (fifo->active && !status) {
- transp_mode = 0;
- if (fifon < 4 && hfc->b_mode[fifon / 2] == L1_MODE_TRANS)
- transp_mode = 1;
-
- /* is FifoFull-threshold set for our channel? */
- threshbit = (hfc->threshold_mask & (1 << fifon));
- num_isoc_packets = iso_packets[fifon];
-
- /* predict dataflow to avoid fifo overflow */
- if (fifon >= HFCUSB_D_TX) {
- sink = (threshbit) ? SINK_DMIN : SINK_DMAX;
- } else {
- sink = (threshbit) ? SINK_MIN : SINK_MAX;
- }
- fill_isoc_urb(urb, fifo->hfc->dev, fifo->pipe,
- context_iso_urb->buffer, num_isoc_packets,
- fifo->usb_packet_maxlen, fifo->intervall,
- tx_iso_complete, urb->context);
- memset(context_iso_urb->buffer, 0,
- sizeof(context_iso_urb->buffer));
- frame_complete = 0;
-
- /* Generate next ISO Packets */
- for (k = 0; k < num_isoc_packets; ++k) {
- if (fifo->skbuff) {
- len = fifo->skbuff->len;
- /* we lower data margin every msec */
- fifo->bit_line -= sink;
- current_len = (0 - fifo->bit_line) / 8;
- /* maximum 15 byte for every ISO packet makes our life easier */
- if (current_len > 14)
- current_len = 14;
- current_len =
- (len <=
- current_len) ? len : current_len;
- /* how much bit do we put on the line? */
- fifo->bit_line += current_len * 8;
-
- context_iso_urb->buffer[tx_offset] = 0;
- if (current_len == len) {
- if (!transp_mode) {
- /* here frame completion */
- context_iso_urb->
- buffer[tx_offset] = 1;
- /* add 2 byte flags and 16bit CRC at end of ISDN frame */
- fifo->bit_line += 32;
- }
- frame_complete = 1;
- }
-
- memcpy(context_iso_urb->buffer +
- tx_offset + 1, fifo->skbuff->data,
- current_len);
- skb_pull(fifo->skbuff, current_len);
-
- /* define packet delimeters within the URB buffer */
- urb->iso_frame_desc[k].offset = tx_offset;
- urb->iso_frame_desc[k].length =
- current_len + 1;
-
- tx_offset += (current_len + 1);
- } else {
- urb->iso_frame_desc[k].offset =
- tx_offset++;
-
- urb->iso_frame_desc[k].length = 1;
- fifo->bit_line -= sink; /* we lower data margin every msec */
-
- if (fifo->bit_line < BITLINE_INF) {
- fifo->bit_line = BITLINE_INF;
- }
- }
-
- if (frame_complete) {
- fifo->delete_flg = 1;
- fifo->hif->l1l2(fifo->hif,
- PH_DATA | CONFIRM,
- (void *) (unsigned long) fifo->skbuff->
- truesize);
- if (fifo->skbuff && fifo->delete_flg) {
- dev_kfree_skb_any(fifo->skbuff);
- fifo->skbuff = NULL;
- fifo->delete_flg = 0;
- }
- frame_complete = 0;
- }
- }
- errcode = usb_submit_urb(urb, GFP_ATOMIC);
- if (errcode < 0) {
- printk(KERN_INFO
- "HFC-S USB: error submitting ISO URB: %d\n",
- errcode);
- }
- } else {
- if (status && !hfc->disc_flag) {
- printk(KERN_INFO
- "HFC-S USB: tx_iso_complete: error(%i): '%s', fifonum=%d\n",
- status, symbolic(urb_errlist, status), fifon);
- }
- }
-}
-
-static void
-rx_iso_complete(struct urb *urb)
-{
- iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context;
- usb_fifo *fifo = context_iso_urb->owner_fifo;
- hfcusb_data *hfc = fifo->hfc;
- int k, len, errcode, offset, num_isoc_packets, fifon, maxlen,
- status;
- unsigned int iso_status;
- __u8 *buf;
- static __u8 eof[8];
-
- fifon = fifo->fifonum;
- status = urb->status;
-
- if (urb->status == -EOVERFLOW) {
- DBG(HFCUSB_DBG_VERBOSE_USB,
- "HFC-USB: ignoring USB DATAOVERRUN fifo(%i)", fifon);
- status = 0;
- }
-
- /* ISO transfer only partially completed,
- look at individual frame status for details */
- if (status == -EXDEV) {
- DBG(HFCUSB_DBG_VERBOSE_USB, "HFC-S USB: rx_iso_complete with -EXDEV "
- "urb->status %d, fifonum %d\n",
- status, fifon);
- status = 0;
- }
-
- if (fifo->active && !status) {
- num_isoc_packets = iso_packets[fifon];
- maxlen = fifo->usb_packet_maxlen;
- for (k = 0; k < num_isoc_packets; ++k) {
- len = urb->iso_frame_desc[k].actual_length;
- offset = urb->iso_frame_desc[k].offset;
- buf = context_iso_urb->buffer + offset;
- iso_status = urb->iso_frame_desc[k].status;
-
- if (iso_status && !hfc->disc_flag)
- DBG(HFCUSB_DBG_VERBOSE_USB,
- "HFC-S USB: rx_iso_complete "
- "ISO packet %i, status: %i\n",
- k, iso_status);
-
- if (fifon == HFCUSB_D_RX) {
- DBG(HFCUSB_DBG_VERBOSE_USB,
- "HFC-S USB: ISO-D-RX lst_urblen:%2d "
- "act_urblen:%2d max-urblen:%2d EOF:0x%0x",
- fifo->last_urblen, len, maxlen,
- eof[5]);
-
- DBG_PACKET(HFCUSB_DBG_VERBOSE_USB, buf, len);
- }
-
- if (fifo->last_urblen != maxlen) {
- /* the threshold mask is in the 2nd status byte */
- hfc->threshold_mask = buf[1];
- /* care for L1 state only for D-Channel
- to avoid overlapped iso completions */
- if (fifon == HFCUSB_D_RX) {
- /* the S0 state is in the upper half
- of the 1st status byte */
- s0_state_handler(hfc, buf[0] >> 4);
- }
- eof[fifon] = buf[0] & 1;
- if (len > 2)
- collect_rx_frame(fifo, buf + 2,
- len - 2,
- (len < maxlen) ?
- eof[fifon] : 0);
- } else {
- collect_rx_frame(fifo, buf, len,
- (len <
- maxlen) ? eof[fifon] :
- 0);
- }
- fifo->last_urblen = len;
- }
-
- fill_isoc_urb(urb, fifo->hfc->dev, fifo->pipe,
- context_iso_urb->buffer, num_isoc_packets,
- fifo->usb_packet_maxlen, fifo->intervall,
- rx_iso_complete, urb->context);
- errcode = usb_submit_urb(urb, GFP_ATOMIC);
- if (errcode < 0) {
- printk(KERN_ERR
- "HFC-S USB: error submitting ISO URB: %d\n",
- errcode);
- }
- } else {
- if (status && !hfc->disc_flag) {
- printk(KERN_ERR
- "HFC-S USB: rx_iso_complete : "
- "urb->status %d, fifonum %d\n",
- status, fifon);
- }
- }
-}
-
-/* collect rx data from INT- and ISO-URBs */
-static void
-collect_rx_frame(usb_fifo *fifo, __u8 *data, int len, int finish)
-{
- hfcusb_data *hfc = fifo->hfc;
- int transp_mode, fifon;
-
- fifon = fifo->fifonum;
- transp_mode = 0;
- if (fifon < 4 && hfc->b_mode[fifon / 2] == L1_MODE_TRANS)
- transp_mode = 1;
-
- if (!fifo->skbuff) {
- fifo->skbuff = dev_alloc_skb(fifo->max_size + 3);
- if (!fifo->skbuff) {
- printk(KERN_ERR
- "HFC-S USB: cannot allocate buffer for fifo(%d)\n",
- fifon);
- return;
- }
- }
- if (len) {
- if (fifo->skbuff->len + len < fifo->max_size) {
- skb_put_data(fifo->skbuff, data, len);
- } else {
- DBG(HFCUSB_DBG_FIFO_ERR,
- "HCF-USB: got frame exceeded fifo->max_size(%d) fifo(%d)",
- fifo->max_size, fifon);
- DBG_SKB(HFCUSB_DBG_VERBOSE_USB, fifo->skbuff);
- skb_trim(fifo->skbuff, 0);
- }
- }
- if (transp_mode && fifo->skbuff->len >= 128) {
- fifo->hif->l1l2(fifo->hif, PH_DATA | INDICATION,
- fifo->skbuff);
- fifo->skbuff = NULL;
- return;
- }
- /* we have a complete hdlc packet */
- if (finish) {
- if (fifo->skbuff->len > 3 &&
- !fifo->skbuff->data[fifo->skbuff->len - 1]) {
-
- if (fifon == HFCUSB_D_RX) {
- DBG(HFCUSB_DBG_DCHANNEL,
- "HFC-S USB: D-RX len(%d)", fifo->skbuff->len);
- DBG_SKB(HFCUSB_DBG_DCHANNEL, fifo->skbuff);
- }
-
- /* remove CRC & status */
- skb_trim(fifo->skbuff, fifo->skbuff->len - 3);
- if (fifon == HFCUSB_PCM_RX) {
- fifo->hif->l1l2(fifo->hif,
- PH_DATA_E | INDICATION,
- fifo->skbuff);
- } else
- fifo->hif->l1l2(fifo->hif,
- PH_DATA | INDICATION,
- fifo->skbuff);
- fifo->skbuff = NULL; /* buffer was freed from upper layer */
- } else {
- DBG(HFCUSB_DBG_FIFO_ERR,
- "HFC-S USB: ERROR frame len(%d) fifo(%d)",
- fifo->skbuff->len, fifon);
- DBG_SKB(HFCUSB_DBG_VERBOSE_USB, fifo->skbuff);
- skb_trim(fifo->skbuff, 0);
- }
- }
-}
-
-static void
-rx_int_complete(struct urb *urb)
-{
- int len;
- int status;
- __u8 *buf, maxlen, fifon;
- usb_fifo *fifo = (usb_fifo *) urb->context;
- hfcusb_data *hfc = fifo->hfc;
- static __u8 eof[8];
-
- urb->dev = hfc->dev; /* security init */
-
- fifon = fifo->fifonum;
- if ((!fifo->active) || (urb->status)) {
- DBG(HFCUSB_DBG_INIT, "HFC-S USB: RX-Fifo %i is going down (%i)",
- fifon, urb->status);
-
- fifo->urb->interval = 0; /* cancel automatic rescheduling */
- if (fifo->skbuff) {
- dev_kfree_skb_any(fifo->skbuff);
- fifo->skbuff = NULL;
- }
- return;
- }
- len = urb->actual_length;
- buf = fifo->buffer;
- maxlen = fifo->usb_packet_maxlen;
-
- if (fifon == HFCUSB_D_RX) {
- DBG(HFCUSB_DBG_VERBOSE_USB,
- "HFC-S USB: INT-D-RX lst_urblen:%2d "
- "act_urblen:%2d max-urblen:%2d EOF:0x%0x",
- fifo->last_urblen, len, maxlen,
- eof[5]);
- DBG_PACKET(HFCUSB_DBG_VERBOSE_USB, buf, len);
- }
-
- if (fifo->last_urblen != fifo->usb_packet_maxlen) {
- /* the threshold mask is in the 2nd status byte */
- hfc->threshold_mask = buf[1];
- /* the S0 state is in the upper half of the 1st status byte */
- s0_state_handler(hfc, buf[0] >> 4);
- eof[fifon] = buf[0] & 1;
- /* if we have more than the 2 status bytes -> collect data */
- if (len > 2)
- collect_rx_frame(fifo, buf + 2,
- urb->actual_length - 2,
- (len < maxlen) ? eof[fifon] : 0);
- } else {
- collect_rx_frame(fifo, buf, urb->actual_length,
- (len < maxlen) ? eof[fifon] : 0);
- }
- fifo->last_urblen = urb->actual_length;
- status = usb_submit_urb(urb, GFP_ATOMIC);
- if (status) {
- printk(KERN_INFO
- "HFC-S USB: %s error resubmitting URB fifo(%d)\n",
- __func__, fifon);
- }
-}
-
-/* start initial INT-URB for certain fifo */
-static void
-start_int_fifo(usb_fifo *fifo)
-{
- int errcode;
-
- DBG(HFCUSB_DBG_INIT, "HFC-S USB: starting RX INT-URB for fifo:%d\n",
- fifo->fifonum);
-
- if (!fifo->urb) {
- fifo->urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!fifo->urb)
- return;
- }
- usb_fill_int_urb(fifo->urb, fifo->hfc->dev, fifo->pipe,
- fifo->buffer, fifo->usb_packet_maxlen,
- rx_int_complete, fifo, fifo->intervall);
- fifo->active = 1; /* must be marked active */
- errcode = usb_submit_urb(fifo->urb, GFP_KERNEL);
- if (errcode) {
- printk(KERN_ERR "HFC-S USB: submit URB error(%s): status:%i\n",
- __func__, errcode);
- fifo->active = 0;
- fifo->skbuff = NULL;
- }
-}
-
-static void
-setup_bchannel(hfcusb_data *hfc, int channel, int mode)
-{
- __u8 val, idx_table[2] = { 0, 2 };
-
- if (hfc->disc_flag) {
- return;
- }
- DBG(HFCUSB_DBG_STATES, "HFC-S USB: setting channel %d to mode %d",
- channel, mode);
- hfc->b_mode[channel] = mode;
-
- /* setup CON_HDLC */
- val = 0;
- if (mode != L1_MODE_NULL)
- val = 8; /* enable fifo? */
- if (mode == L1_MODE_TRANS)
- val |= 2; /* set transparent bit */
-
- /* set FIFO to transmit register */
- queue_control_request(hfc, HFCUSB_FIFO, idx_table[channel], 1);
- queue_control_request(hfc, HFCUSB_CON_HDLC, val, 1);
- /* reset fifo */
- queue_control_request(hfc, HFCUSB_INC_RES_F, 2, 1);
- /* set FIFO to receive register */
- queue_control_request(hfc, HFCUSB_FIFO, idx_table[channel] + 1, 1);
- queue_control_request(hfc, HFCUSB_CON_HDLC, val, 1);
- /* reset fifo */
- queue_control_request(hfc, HFCUSB_INC_RES_F, 2, 1);
-
- val = 0x40;
- if (hfc->b_mode[0])
- val |= 1;
- if (hfc->b_mode[1])
- val |= 2;
- queue_control_request(hfc, HFCUSB_SCTRL, val, 1);
-
- val = 0;
- if (hfc->b_mode[0])
- val |= 1;
- if (hfc->b_mode[1])
- val |= 2;
- queue_control_request(hfc, HFCUSB_SCTRL_R, val, 1);
-
- if (mode == L1_MODE_NULL) {
- if (channel)
- handle_led(hfc, LED_B2_OFF);
- else
- handle_led(hfc, LED_B1_OFF);
- } else {
- if (channel)
- handle_led(hfc, LED_B2_ON);
- else
- handle_led(hfc, LED_B1_ON);
- }
-}
-
-static void
-hfc_usb_l2l1(struct hisax_if *my_hisax_if, int pr, void *arg)
-{
- usb_fifo *fifo = my_hisax_if->priv;
- hfcusb_data *hfc = fifo->hfc;
-
- switch (pr) {
- case PH_ACTIVATE | REQUEST:
- if (fifo->fifonum == HFCUSB_D_TX) {
- DBG(HFCUSB_DBG_STATES,
- "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_ACTIVATE | REQUEST");
-
- if (hfc->l1_state != 3
- && hfc->l1_state != 7) {
- hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,
- PH_DEACTIVATE |
- INDICATION,
- NULL);
- DBG(HFCUSB_DBG_STATES,
- "HFC-S USB: PH_DEACTIVATE | INDICATION sent (not state 3 or 7)");
- } else {
- if (hfc->l1_state == 7) { /* l1 already active */
- hfc->d_if.ifc.l1l2(&hfc->
- d_if.
- ifc,
- PH_ACTIVATE
- |
- INDICATION,
- NULL);
- DBG(HFCUSB_DBG_STATES,
- "HFC-S USB: PH_ACTIVATE | INDICATION sent again ;)");
- } else {
- /* force sending sending INFO1 */
- queue_control_request(hfc,
- HFCUSB_STATES,
- 0x14,
- 1);
- mdelay(1);
- /* start l1 activation */
- queue_control_request(hfc,
- HFCUSB_STATES,
- 0x04,
- 1);
- if (!timer_pending
- (&hfc->t3_timer)) {
- hfc->t3_timer.
- expires =
- jiffies +
- (HFC_TIMER_T3 *
- HZ) / 1000;
- add_timer(&hfc->
- t3_timer);
- }
- }
- }
- } else {
- DBG(HFCUSB_DBG_STATES,
- "HFC_USB: hfc_usb_d_l2l1 B-chan: PH_ACTIVATE | REQUEST");
- setup_bchannel(hfc,
- (fifo->fifonum ==
- HFCUSB_B1_TX) ? 0 : 1,
- (long) arg);
- fifo->hif->l1l2(fifo->hif,
- PH_ACTIVATE | INDICATION,
- NULL);
- }
- break;
- case PH_DEACTIVATE | REQUEST:
- if (fifo->fifonum == HFCUSB_D_TX) {
- DBG(HFCUSB_DBG_STATES,
- "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_DEACTIVATE | REQUEST");
- } else {
- DBG(HFCUSB_DBG_STATES,
- "HFC_USB: hfc_usb_d_l2l1 Bx-chan: PH_DEACTIVATE | REQUEST");
- setup_bchannel(hfc,
- (fifo->fifonum ==
- HFCUSB_B1_TX) ? 0 : 1,
- (int) L1_MODE_NULL);
- fifo->hif->l1l2(fifo->hif,
- PH_DEACTIVATE | INDICATION,
- NULL);
- }
- break;
- case PH_DATA | REQUEST:
- if (fifo->skbuff && fifo->delete_flg) {
- dev_kfree_skb_any(fifo->skbuff);
- fifo->skbuff = NULL;
- fifo->delete_flg = 0;
- }
- fifo->skbuff = arg; /* we have a new buffer */
- break;
- default:
- DBG(HFCUSB_DBG_STATES,
- "HFC_USB: hfc_usb_d_l2l1: unknown state : %#x", pr);
- break;
- }
-}
-
-/* initial init HFC-S USB chip registers, HiSax interface, USB URBs */
-static int
-hfc_usb_init(hfcusb_data *hfc)
-{
- usb_fifo *fifo;
- int i;
- u_char b;
- struct hisax_b_if *p_b_if[2];
-
- /* check the chip id */
- if (read_usb(hfc, HFCUSB_CHIP_ID, &b) != 1) {
- printk(KERN_INFO "HFC-USB: cannot read chip id\n");
- return (1);
- }
- if (b != HFCUSB_CHIPID) {
- printk(KERN_INFO "HFC-S USB: Invalid chip id 0x%02x\n", b);
- return (1);
- }
-
- /* first set the needed config, interface and alternate */
- usb_set_interface(hfc->dev, hfc->if_used, hfc->alt_used);
-
- /* do Chip reset */
- write_usb(hfc, HFCUSB_CIRM, 8);
- /* aux = output, reset off */
- write_usb(hfc, HFCUSB_CIRM, 0x10);
-
- /* set USB_SIZE to match wMaxPacketSize for INT or BULK transfers */
- write_usb(hfc, HFCUSB_USB_SIZE,
- (hfc->packet_size / 8) | ((hfc->packet_size / 8) << 4));
-
- /* set USB_SIZE_I to match wMaxPacketSize for ISO transfers */
- write_usb(hfc, HFCUSB_USB_SIZE_I, hfc->iso_packet_size);
-
- /* enable PCM/GCI master mode */
- write_usb(hfc, HFCUSB_MST_MODE1, 0); /* set default values */
- write_usb(hfc, HFCUSB_MST_MODE0, 1); /* enable master mode */
-
- /* init the fifos */
- write_usb(hfc, HFCUSB_F_THRES,
- (HFCUSB_TX_THRESHOLD /
- 8) | ((HFCUSB_RX_THRESHOLD / 8) << 4));
-
- fifo = hfc->fifos;
- for (i = 0; i < HFCUSB_NUM_FIFOS; i++) {
- write_usb(hfc, HFCUSB_FIFO, i); /* select the desired fifo */
- fifo[i].skbuff = NULL; /* init buffer pointer */
- fifo[i].max_size =
- (i <= HFCUSB_B2_RX) ? MAX_BCH_SIZE : MAX_DFRAME_LEN;
- fifo[i].last_urblen = 0;
- /* set 2 bit for D- & E-channel */
- write_usb(hfc, HFCUSB_HDLC_PAR,
- ((i <= HFCUSB_B2_RX) ? 0 : 2));
- /* rx hdlc, enable IFF for D-channel */
- write_usb(hfc, HFCUSB_CON_HDLC,
- ((i == HFCUSB_D_TX) ? 0x09 : 0x08));
- write_usb(hfc, HFCUSB_INC_RES_F, 2); /* reset the fifo */
- }
-
- write_usb(hfc, HFCUSB_CLKDEL, 0x0f); /* clock delay value */
- write_usb(hfc, HFCUSB_STATES, 3 | 0x10); /* set deactivated mode */
- write_usb(hfc, HFCUSB_STATES, 3); /* enable state machine */
-
- write_usb(hfc, HFCUSB_SCTRL_R, 0); /* disable both B receivers */
- write_usb(hfc, HFCUSB_SCTRL, 0x40); /* disable B transmitters + capacitive mode */
-
- /* set both B-channel to not connected */
- hfc->b_mode[0] = L1_MODE_NULL;
- hfc->b_mode[1] = L1_MODE_NULL;
-
- hfc->l1_activated = 0;
- hfc->disc_flag = 0;
- hfc->led_state = 0;
- hfc->old_led_state = 0;
-
- /* init the t3 timer */
- timer_setup(&hfc->t3_timer, l1_timer_expire_t3, 0);
-
- /* init the t4 timer */
- timer_setup(&hfc->t4_timer, l1_timer_expire_t4, 0);
-
- /* init the background machinery for control requests */
- hfc->ctrl_read.bRequestType = 0xc0;
- hfc->ctrl_read.bRequest = 1;
- hfc->ctrl_read.wLength = cpu_to_le16(1);
- hfc->ctrl_write.bRequestType = 0x40;
- hfc->ctrl_write.bRequest = 0;
- hfc->ctrl_write.wLength = 0;
- usb_fill_control_urb(hfc->ctrl_urb,
- hfc->dev,
- hfc->ctrl_out_pipe,
- (u_char *)&hfc->ctrl_write,
- NULL, 0, ctrl_complete, hfc);
- /* Init All Fifos */
- for (i = 0; i < HFCUSB_NUM_FIFOS; i++) {
- hfc->fifos[i].iso[0].purb = NULL;
- hfc->fifos[i].iso[1].purb = NULL;
- hfc->fifos[i].active = 0;
- }
- /* register Modul to upper Hisax Layers */
- hfc->d_if.owner = THIS_MODULE;
- hfc->d_if.ifc.priv = &hfc->fifos[HFCUSB_D_TX];
- hfc->d_if.ifc.l2l1 = hfc_usb_l2l1;
- for (i = 0; i < 2; i++) {
- hfc->b_if[i].ifc.priv = &hfc->fifos[HFCUSB_B1_TX + i * 2];
- hfc->b_if[i].ifc.l2l1 = hfc_usb_l2l1;
- p_b_if[i] = &hfc->b_if[i];
- }
- /* default Prot: EURO ISDN, should be a module_param */
- hfc->protocol = 2;
- i = hisax_register(&hfc->d_if, p_b_if, "hfc_usb", hfc->protocol);
- if (i) {
- printk(KERN_INFO "HFC-S USB: hisax_register -> %d\n", i);
- return i;
- }
-
-#ifdef CONFIG_HISAX_DEBUG
- hfc_debug = debug;
-#endif
-
- for (i = 0; i < 4; i++)
- hfc->fifos[i].hif = &p_b_if[i / 2]->ifc;
- for (i = 4; i < 8; i++)
- hfc->fifos[i].hif = &hfc->d_if.ifc;
-
- /* 3 (+1) INT IN + 3 ISO OUT */
- if (hfc->cfg_used == CNF_3INT3ISO || hfc->cfg_used == CNF_4INT3ISO) {
- start_int_fifo(hfc->fifos + HFCUSB_D_RX);
- if (hfc->fifos[HFCUSB_PCM_RX].pipe)
- start_int_fifo(hfc->fifos + HFCUSB_PCM_RX);
- start_int_fifo(hfc->fifos + HFCUSB_B1_RX);
- start_int_fifo(hfc->fifos + HFCUSB_B2_RX);
- }
- /* 3 (+1) ISO IN + 3 ISO OUT */
- if (hfc->cfg_used == CNF_3ISO3ISO || hfc->cfg_used == CNF_4ISO3ISO) {
- start_isoc_chain(hfc->fifos + HFCUSB_D_RX, ISOC_PACKETS_D,
- rx_iso_complete, 16);
- if (hfc->fifos[HFCUSB_PCM_RX].pipe)
- start_isoc_chain(hfc->fifos + HFCUSB_PCM_RX,
- ISOC_PACKETS_D, rx_iso_complete,
- 16);
- start_isoc_chain(hfc->fifos + HFCUSB_B1_RX, ISOC_PACKETS_B,
- rx_iso_complete, 16);
- start_isoc_chain(hfc->fifos + HFCUSB_B2_RX, ISOC_PACKETS_B,
- rx_iso_complete, 16);
- }
-
- start_isoc_chain(hfc->fifos + HFCUSB_D_TX, ISOC_PACKETS_D,
- tx_iso_complete, 1);
- start_isoc_chain(hfc->fifos + HFCUSB_B1_TX, ISOC_PACKETS_B,
- tx_iso_complete, 1);
- start_isoc_chain(hfc->fifos + HFCUSB_B2_TX, ISOC_PACKETS_B,
- tx_iso_complete, 1);
-
- handle_led(hfc, LED_POWER_ON);
-
- return (0);
-}
-
-/* initial callback for each plugged USB device */
-static int
-hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
- struct usb_device *dev = interface_to_usbdev(intf);
- hfcusb_data *context;
- struct usb_host_interface *iface = intf->cur_altsetting;
- struct usb_host_interface *iface_used = NULL;
- struct usb_host_endpoint *ep;
- int ifnum = iface->desc.bInterfaceNumber;
- int i, idx, alt_idx, probe_alt_setting, vend_idx, cfg_used, *vcf,
- attr, cfg_found, cidx, ep_addr;
- int cmptbl[16], small_match, iso_packet_size, packet_size,
- alt_used = 0;
- hfcsusb_vdata *driver_info;
-
- vend_idx = 0xffff;
- for (i = 0; hfcusb_idtab[i].idVendor; i++) {
- if ((le16_to_cpu(dev->descriptor.idVendor) == hfcusb_idtab[i].idVendor)
- && (le16_to_cpu(dev->descriptor.idProduct) == hfcusb_idtab[i].idProduct)) {
- vend_idx = i;
- continue;
- }
- }
-
- printk(KERN_INFO
- "HFC-S USB: probing interface(%d) actalt(%d) minor(%d)\n",
- ifnum, iface->desc.bAlternateSetting, intf->minor);
-
- if (vend_idx != 0xffff) {
- /* if vendor and product ID is OK, start probing alternate settings */
- alt_idx = 0;
- small_match = 0xffff;
-
- /* default settings */
- iso_packet_size = 16;
- packet_size = 64;
-
- while (alt_idx < intf->num_altsetting) {
- iface = intf->altsetting + alt_idx;
- probe_alt_setting = iface->desc.bAlternateSetting;
- cfg_used = 0;
-
- /* check for config EOL element */
- while (validconf[cfg_used][0]) {
- cfg_found = 1;
- vcf = validconf[cfg_used];
- /* first endpoint descriptor */
- ep = iface->endpoint;
-
- memcpy(cmptbl, vcf, 16 * sizeof(int));
-
- /* check for all endpoints in this alternate setting */
- for (i = 0; i < iface->desc.bNumEndpoints;
- i++) {
- ep_addr =
- ep->desc.bEndpointAddress;
- /* get endpoint base */
- idx = ((ep_addr & 0x7f) - 1) * 2;
- if (ep_addr & 0x80)
- idx++;
- attr = ep->desc.bmAttributes;
- if (cmptbl[idx] == EP_NUL) {
- cfg_found = 0;
- }
- if (attr == USB_ENDPOINT_XFER_INT
- && cmptbl[idx] == EP_INT)
- cmptbl[idx] = EP_NUL;
- if (attr == USB_ENDPOINT_XFER_BULK
- && cmptbl[idx] == EP_BLK)
- cmptbl[idx] = EP_NUL;
- if (attr == USB_ENDPOINT_XFER_ISOC
- && cmptbl[idx] == EP_ISO)
- cmptbl[idx] = EP_NUL;
-
- /* check if all INT endpoints match minimum interval */
- if ((attr == USB_ENDPOINT_XFER_INT)
- && (ep->desc.bInterval < vcf[17])) {
- cfg_found = 0;
- }
- ep++;
- }
- for (i = 0; i < 16; i++) {
- /* all entries must be EP_NOP or EP_NUL for a valid config */
- if (cmptbl[i] != EP_NOP
- && cmptbl[i] != EP_NUL)
- cfg_found = 0;
- }
- if (cfg_found) {
- if (cfg_used < small_match) {
- small_match = cfg_used;
- alt_used =
- probe_alt_setting;
- iface_used = iface;
- }
- }
- cfg_used++;
- }
- alt_idx++;
- } /* (alt_idx < intf->num_altsetting) */
-
- /* found a valid USB Ta Endpint config */
- if (small_match != 0xffff) {
- iface = iface_used;
- if (!(context = kzalloc(sizeof(hfcusb_data), GFP_KERNEL)))
- return (-ENOMEM); /* got no mem */
-
- ep = iface->endpoint;
- vcf = validconf[small_match];
-
- for (i = 0; i < iface->desc.bNumEndpoints; i++) {
- ep_addr = ep->desc.bEndpointAddress;
- /* get endpoint base */
- idx = ((ep_addr & 0x7f) - 1) * 2;
- if (ep_addr & 0x80)
- idx++;
- cidx = idx & 7;
- attr = ep->desc.bmAttributes;
-
- /* init Endpoints */
- if (vcf[idx] != EP_NOP
- && vcf[idx] != EP_NUL) {
- switch (attr) {
- case USB_ENDPOINT_XFER_INT:
- context->
- fifos[cidx].
- pipe =
- usb_rcvintpipe
- (dev,
- ep->desc.
- bEndpointAddress);
- context->
- fifos[cidx].
- usb_transfer_mode
- = USB_INT;
- packet_size =
- le16_to_cpu(ep->desc.wMaxPacketSize);
- break;
- case USB_ENDPOINT_XFER_BULK:
- if (ep_addr & 0x80)
- context->
- fifos
- [cidx].
- pipe =
- usb_rcvbulkpipe
- (dev,
- ep->
- desc.
- bEndpointAddress);
- else
- context->
- fifos
- [cidx].
- pipe =
- usb_sndbulkpipe
- (dev,
- ep->
- desc.
- bEndpointAddress);
- context->
- fifos[cidx].
- usb_transfer_mode
- = USB_BULK;
- packet_size =
- le16_to_cpu(ep->desc.wMaxPacketSize);
- break;
- case USB_ENDPOINT_XFER_ISOC:
- if (ep_addr & 0x80)
- context->
- fifos
- [cidx].
- pipe =
- usb_rcvisocpipe
- (dev,
- ep->
- desc.
- bEndpointAddress);
- else
- context->
- fifos
- [cidx].
- pipe =
- usb_sndisocpipe
- (dev,
- ep->
- desc.
- bEndpointAddress);
- context->
- fifos[cidx].
- usb_transfer_mode
- = USB_ISOC;
- iso_packet_size =
- le16_to_cpu(ep->desc.wMaxPacketSize);
- break;
- default:
- context->
- fifos[cidx].
- pipe = 0;
- } /* switch attribute */
-
- if (context->fifos[cidx].pipe) {
- context->fifos[cidx].
- fifonum = cidx;
- context->fifos[cidx].hfc =
- context;
- context->fifos[cidx].usb_packet_maxlen =
- le16_to_cpu(ep->desc.wMaxPacketSize);
- context->fifos[cidx].
- intervall =
- ep->desc.bInterval;
- context->fifos[cidx].
- skbuff = NULL;
- }
- }
- ep++;
- }
- context->dev = dev; /* save device */
- context->if_used = ifnum; /* save used interface */
- context->alt_used = alt_used; /* and alternate config */
- context->ctrl_paksize = dev->descriptor.bMaxPacketSize0; /* control size */
- context->cfg_used = vcf[16]; /* store used config */
- context->vend_idx = vend_idx; /* store found vendor */
- context->packet_size = packet_size;
- context->iso_packet_size = iso_packet_size;
-
- /* create the control pipes needed for register access */
- context->ctrl_in_pipe =
- usb_rcvctrlpipe(context->dev, 0);
- context->ctrl_out_pipe =
- usb_sndctrlpipe(context->dev, 0);
-
- driver_info = (hfcsusb_vdata *)
- hfcusb_idtab[vend_idx].driver_info;
-
- context->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);
-
- if (!context->ctrl_urb) {
- pr_warn("%s: No memory for control urb\n",
- driver_info->vend_name);
- kfree(context);
- return -ENOMEM;
- }
-
- pr_info("HFC-S USB: detected \"%s\"\n",
- driver_info->vend_name);
-
- DBG(HFCUSB_DBG_INIT,
- "HFC-S USB: Endpoint-Config: %s (if=%d alt=%d), E-Channel(%d)",
- conf_str[small_match], context->if_used,
- context->alt_used,
- validconf[small_match][18]);
-
- /* init the chip and register the driver */
- if (hfc_usb_init(context)) {
- usb_kill_urb(context->ctrl_urb);
- usb_free_urb(context->ctrl_urb);
- context->ctrl_urb = NULL;
- kfree(context);
- return (-EIO);
- }
- usb_set_intfdata(intf, context);
- return (0);
- }
- } else {
- printk(KERN_INFO
- "HFC-S USB: no valid vendor found in USB descriptor\n");
- }
- return (-EIO);
-}
-
-/* callback for unplugged USB device */
-static void
-hfc_usb_disconnect(struct usb_interface *intf)
-{
- hfcusb_data *context = usb_get_intfdata(intf);
- int i;
-
- handle_led(context, LED_POWER_OFF);
- schedule_timeout(HZ / 100);
-
- printk(KERN_INFO "HFC-S USB: device disconnect\n");
- context->disc_flag = 1;
- usb_set_intfdata(intf, NULL);
-
- if (timer_pending(&context->t3_timer))
- del_timer(&context->t3_timer);
- if (timer_pending(&context->t4_timer))
- del_timer(&context->t4_timer);
-
- /* tell all fifos to terminate */
- for (i = 0; i < HFCUSB_NUM_FIFOS; i++) {
- if (context->fifos[i].usb_transfer_mode == USB_ISOC) {
- if (context->fifos[i].active > 0) {
- stop_isoc_chain(&context->fifos[i]);
- DBG(HFCUSB_DBG_INIT,
- "HFC-S USB: %s stopping ISOC chain Fifo(%i)",
- __func__, i);
- }
- } else {
- if (context->fifos[i].active > 0) {
- context->fifos[i].active = 0;
- DBG(HFCUSB_DBG_INIT,
- "HFC-S USB: %s unlinking URB for Fifo(%i)",
- __func__, i);
- }
- usb_kill_urb(context->fifos[i].urb);
- usb_free_urb(context->fifos[i].urb);
- context->fifos[i].urb = NULL;
- }
- context->fifos[i].active = 0;
- }
- usb_kill_urb(context->ctrl_urb);
- usb_free_urb(context->ctrl_urb);
- context->ctrl_urb = NULL;
- hisax_unregister(&context->d_if);
- kfree(context); /* free our structure again */
-}
-
-static struct usb_driver hfc_drv = {
- .name = "hfc_usb",
- .id_table = hfcusb_idtab,
- .probe = hfc_usb_probe,
- .disconnect = hfc_usb_disconnect,
- .disable_hub_initiated_lpm = 1,
-};
-
-static void __exit
-hfc_usb_mod_exit(void)
-{
- usb_deregister(&hfc_drv); /* release our driver */
- printk(KERN_INFO "HFC-S USB: module removed\n");
-}
-
-static int __init
-hfc_usb_mod_init(void)
-{
- char revstr[30], datestr[30], dummy[30];
-#ifndef CONFIG_HISAX_DEBUG
- hfc_debug = debug;
-#endif
- sscanf(hfcusb_revision,
- "%s %s $ %s %s %s $ ", dummy, revstr,
- dummy, datestr, dummy);
- printk(KERN_INFO
- "HFC-S USB: driver module revision %s date %s loaded, (debug=%i)\n",
- revstr, datestr, debug);
- if (usb_register(&hfc_drv)) {
- printk(KERN_INFO
- "HFC-S USB: Unable to register HFC-S USB module at usb stack\n");
- return (-1); /* unable to register */
- }
- return (0);
-}
-
-module_init(hfc_usb_mod_init);
-module_exit(hfc_usb_mod_exit);
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(usb, hfcusb_idtab);
diff --git a/drivers/isdn/hisax/hfc_usb.h b/drivers/isdn/hisax/hfc_usb.h
deleted file mode 100644
index 9a212330e8a8..000000000000
--- a/drivers/isdn/hisax/hfc_usb.h
+++ /dev/null
@@ -1,208 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * hfc_usb.h
- *
- * $Id: hfc_usb.h,v 1.1.2.5 2007/08/20 14:36:03 mbachem Exp $
- */
-
-#ifndef __HFC_USB_H__
-#define __HFC_USB_H__
-
-#define DRIVER_AUTHOR "Peter Sprenger (sprenger@moving-byters.de)"
-#define DRIVER_DESC "HFC-S USB based HiSAX ISDN driver"
-
-
-#define HFC_CTRL_TIMEOUT 20 /* 5ms timeout writing/reading regs */
-#define HFC_TIMER_T3 8000 /* timeout for l1 activation timer */
-#define HFC_TIMER_T4 500 /* time for state change interval */
-
-#define HFCUSB_L1_STATECHANGE 0 /* L1 state changed */
-#define HFCUSB_L1_DRX 1 /* D-frame received */
-#define HFCUSB_L1_ERX 2 /* E-frame received */
-#define HFCUSB_L1_DTX 4 /* D-frames completed */
-
-#define MAX_BCH_SIZE 2048 /* allowed B-channel packet size */
-
-#define HFCUSB_RX_THRESHOLD 64 /* threshold for fifo report bit rx */
-#define HFCUSB_TX_THRESHOLD 64 /* threshold for fifo report bit tx */
-
-#define HFCUSB_CHIP_ID 0x16 /* Chip ID register index */
-#define HFCUSB_CIRM 0x00 /* cirm register index */
-#define HFCUSB_USB_SIZE 0x07 /* int length register */
-#define HFCUSB_USB_SIZE_I 0x06 /* iso length register */
-#define HFCUSB_F_CROSS 0x0b /* bit order register */
-#define HFCUSB_CLKDEL 0x37 /* bit delay register */
-#define HFCUSB_CON_HDLC 0xfa /* channel connect register */
-#define HFCUSB_HDLC_PAR 0xfb
-#define HFCUSB_SCTRL 0x31 /* S-bus control register (tx) */
-#define HFCUSB_SCTRL_E 0x32 /* same for E and special funcs */
-#define HFCUSB_SCTRL_R 0x33 /* S-bus control register (rx) */
-#define HFCUSB_F_THRES 0x0c /* threshold register */
-#define HFCUSB_FIFO 0x0f /* fifo select register */
-#define HFCUSB_F_USAGE 0x1a /* fifo usage register */
-#define HFCUSB_MST_MODE0 0x14
-#define HFCUSB_MST_MODE1 0x15
-#define HFCUSB_P_DATA 0x1f
-#define HFCUSB_INC_RES_F 0x0e
-#define HFCUSB_STATES 0x30
-
-#define HFCUSB_CHIPID 0x40 /* ID value of HFC-S USB */
-
-
-/* fifo registers */
-#define HFCUSB_NUM_FIFOS 8 /* maximum number of fifos */
-#define HFCUSB_B1_TX 0 /* index for B1 transmit bulk/int */
-#define HFCUSB_B1_RX 1 /* index for B1 receive bulk/int */
-#define HFCUSB_B2_TX 2
-#define HFCUSB_B2_RX 3
-#define HFCUSB_D_TX 4
-#define HFCUSB_D_RX 5
-#define HFCUSB_PCM_TX 6
-#define HFCUSB_PCM_RX 7
-
-/*
- * used to switch snd_transfer_mode for different TA modes e.g. the Billion USB TA just
- * supports ISO out, while the Cologne Chip EVAL TA just supports BULK out
- */
-#define USB_INT 0
-#define USB_BULK 1
-#define USB_ISOC 2
-
-#define ISOC_PACKETS_D 8
-#define ISOC_PACKETS_B 8
-#define ISO_BUFFER_SIZE 128
-
-/* Fifo flow Control for TX ISO */
-#define SINK_MAX 68
-#define SINK_MIN 48
-#define SINK_DMIN 12
-#define SINK_DMAX 18
-#define BITLINE_INF (-64 * 8)
-
-/* HFC-S USB register access by Control-URSs */
-#define write_usb(a, b, c) usb_control_msg((a)->dev, (a)->ctrl_out_pipe, 0, 0x40, (c), (b), NULL, 0, HFC_CTRL_TIMEOUT)
-#define read_usb(a, b, c) usb_control_msg((a)->dev, (a)->ctrl_in_pipe, 1, 0xC0, 0, (b), (c), 1, HFC_CTRL_TIMEOUT)
-#define HFC_CTRL_BUFSIZE 32
-
-/* entry and size of output/input control buffer */
-typedef struct {
- __u8 hfc_reg; /* register number */
- __u8 reg_val; /* value to be written (or read) */
- int action; /* data for action handler */
-} ctrl_buft;
-
-/* Debugging Flags */
-#define HFCUSB_DBG_INIT 0x0001
-#define HFCUSB_DBG_STATES 0x0002
-#define HFCUSB_DBG_DCHANNEL 0x0080
-#define HFCUSB_DBG_FIFO_ERR 0x4000
-#define HFCUSB_DBG_VERBOSE_USB 0x8000
-
-/*
- * URB error codes:
- * Used to represent a list of values and their respective symbolic names
- */
-struct hfcusb_symbolic_list {
- const int num;
- const char *name;
-};
-
-static struct hfcusb_symbolic_list urb_errlist[] = {
- {-ENOMEM, "No memory for allocation of internal structures"},
- {-ENOSPC, "The host controller's bandwidth is already consumed"},
- {-ENOENT, "URB was canceled by unlink_urb"},
- {-EXDEV, "ISO transfer only partially completed"},
- {-EAGAIN, "Too match scheduled for the future"},
- {-ENXIO, "URB already queued"},
- {-EFBIG, "Too much ISO frames requested"},
- {-ENOSR, "Buffer error (overrun)"},
- {-EPIPE, "Specified endpoint is stalled (device not responding)"},
- {-EOVERFLOW, "Babble (bad cable?)"},
- {-EPROTO, "Bit-stuff error (bad cable?)"},
- {-EILSEQ, "CRC/Timeout"},
- {-ETIMEDOUT, "NAK (device does not respond)"},
- {-ESHUTDOWN, "Device unplugged"},
- {-1, NULL}
-};
-
-
-/*
- * device dependent information to support different
- * ISDN Ta's using the HFC-S USB chip
- */
-
-/* USB descriptor need to contain one of the following EndPoint combination: */
-#define CNF_4INT3ISO 1 // 4 INT IN, 3 ISO OUT
-#define CNF_3INT3ISO 2 // 3 INT IN, 3 ISO OUT
-#define CNF_4ISO3ISO 3 // 4 ISO IN, 3 ISO OUT
-#define CNF_3ISO3ISO 4 // 3 ISO IN, 3 ISO OUT
-
-#define EP_NUL 1 // Endpoint at this position not allowed
-#define EP_NOP 2 // all type of endpoints allowed at this position
-#define EP_ISO 3 // Isochron endpoint mandatory at this position
-#define EP_BLK 4 // Bulk endpoint mandatory at this position
-#define EP_INT 5 // Interrupt endpoint mandatory at this position
-
-/*
- * List of all supported endpoint configuration sets, used to find the
- * best matching endpoint configuration within a devices' USB descriptor.
- * We need at least 3 RX endpoints, and 3 TX endpoints, either
- * INT-in and ISO-out, or ISO-in and ISO-out)
- * with 4 RX endpoints even E-Channel logging is possible
- */
-static int validconf[][19] = {
- // INT in, ISO out config
- {EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NOP, EP_INT,
- EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_NUL, EP_NUL,
- CNF_4INT3ISO, 2, 1},
- {EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_NUL,
- EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_NUL, EP_NUL,
- CNF_3INT3ISO, 2, 0},
- // ISO in, ISO out config
- {EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL,
- EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_NOP, EP_ISO,
- CNF_4ISO3ISO, 2, 1},
- {EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL,
- EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_NUL, EP_NUL,
- CNF_3ISO3ISO, 2, 0},
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} // EOL element
-};
-
-#ifdef CONFIG_HISAX_DEBUG
-// string description of chosen config
-static char *conf_str[] = {
- "4 Interrupt IN + 3 Isochron OUT",
- "3 Interrupt IN + 3 Isochron OUT",
- "4 Isochron IN + 3 Isochron OUT",
- "3 Isochron IN + 3 Isochron OUT"
-};
-#endif
-
-typedef struct {
- int vendor; // vendor id
- int prod_id; // product id
- char *vend_name; // vendor string
- __u8 led_scheme; // led display scheme
- signed short led_bits[8]; // array of 8 possible LED bitmask settings
-} vendor_data;
-
-#define LED_OFF 0 // no LED support
-#define LED_SCHEME1 1 // LED standard scheme
-#define LED_SCHEME2 2 // not used yet...
-
-#define LED_POWER_ON 1
-#define LED_POWER_OFF 2
-#define LED_S0_ON 3
-#define LED_S0_OFF 4
-#define LED_B1_ON 5
-#define LED_B1_OFF 6
-#define LED_B1_DATA 7
-#define LED_B2_ON 8
-#define LED_B2_OFF 9
-#define LED_B2_DATA 10
-
-#define LED_NORMAL 0 // LEDs are normal
-#define LED_INVERTED 1 // LEDs are inverted
-
-
-#endif // __HFC_USB_H__
diff --git a/drivers/isdn/hisax/hfcscard.c b/drivers/isdn/hisax/hfcscard.c
deleted file mode 100644
index 91b5219499ca..000000000000
--- a/drivers/isdn/hisax/hfcscard.c
+++ /dev/null
@@ -1,261 +0,0 @@
-/* $Id: hfcscard.c,v 1.10.2.4 2004/01/14 16:04:48 keil Exp $
- *
- * low level stuff for hfcs based cards (Teles3c, ACER P10)
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/init.h>
-#include <linux/isapnp.h>
-#include "hisax.h"
-#include "hfc_2bds0.h"
-#include "isdnl1.h"
-
-static const char *hfcs_revision = "$Revision: 1.10.2.4 $";
-
-static irqreturn_t
-hfcs_interrupt(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_char val, stat;
- u_long flags;
-
- spin_lock_irqsave(&cs->lock, flags);
- if ((HFCD_ANYINT | HFCD_BUSY_NBUSY) &
- (stat = cs->BC_Read_Reg(cs, HFCD_DATA, HFCD_STAT))) {
- val = cs->BC_Read_Reg(cs, HFCD_DATA, HFCD_INT_S1);
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "HFCS: stat(%02x) s1(%02x)", stat, val);
- hfc2bds0_interrupt(cs, val);
- } else {
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "HFCS: irq_no_irq stat(%02x)", stat);
- }
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static void
-hfcs_Timer(struct timer_list *t)
-{
- struct IsdnCardState *cs = from_timer(cs, t, hw.hfcD.timer);
- cs->hw.hfcD.timer.expires = jiffies + 75;
- /* WD RESET */
-/* WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt | 0x80);
- add_timer(&cs->hw.hfcD.timer);
-*/
-}
-
-static void
-release_io_hfcs(struct IsdnCardState *cs)
-{
- release2bds0(cs);
- del_timer(&cs->hw.hfcD.timer);
- if (cs->hw.hfcD.addr)
- release_region(cs->hw.hfcD.addr, 2);
-}
-
-static void
-reset_hfcs(struct IsdnCardState *cs)
-{
- printk(KERN_INFO "HFCS: resetting card\n");
- cs->hw.hfcD.cirm = HFCD_RESET;
- if (cs->typ == ISDN_CTYPE_TELES3C)
- cs->hw.hfcD.cirm |= HFCD_MEM8K;
- cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset On */
- mdelay(10);
- cs->hw.hfcD.cirm = 0;
- if (cs->typ == ISDN_CTYPE_TELES3C)
- cs->hw.hfcD.cirm |= HFCD_MEM8K;
- cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset Off */
- mdelay(10);
- if (cs->typ == ISDN_CTYPE_TELES3C)
- cs->hw.hfcD.cirm |= HFCD_INTB;
- else if (cs->typ == ISDN_CTYPE_ACERP10)
- cs->hw.hfcD.cirm |= HFCD_INTA;
- cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm);
- cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CLKDEL, 0x0e);
- cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_TEST, HFCD_AUTO_AWAKE); /* S/T Auto awake */
- cs->hw.hfcD.ctmt = HFCD_TIM25 | HFCD_AUTO_TIMER;
- cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt);
- cs->hw.hfcD.int_m2 = HFCD_IRQ_ENABLE;
- cs->hw.hfcD.int_m1 = HFCD_INTS_B1TRANS | HFCD_INTS_B2TRANS |
- HFCD_INTS_DTRANS | HFCD_INTS_B1REC | HFCD_INTS_B2REC |
- HFCD_INTS_DREC | HFCD_INTS_L1STATE;
- cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_INT_M1, cs->hw.hfcD.int_m1);
- cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_INT_M2, cs->hw.hfcD.int_m2);
- cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_STATES, HFCD_LOAD_STATE | 2); /* HFC ST 2 */
- udelay(10);
- cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_STATES, 2); /* HFC ST 2 */
- cs->hw.hfcD.mst_m = HFCD_MASTER;
- cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m); /* HFC Master */
- cs->hw.hfcD.sctrl = 0;
- cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_SCTRL, cs->hw.hfcD.sctrl);
-}
-
-static int
-hfcs_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
- u_long flags;
- int delay;
-
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "HFCS: card_msg %x", mt);
- switch (mt) {
- case CARD_RESET:
- spin_lock_irqsave(&cs->lock, flags);
- reset_hfcs(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_RELEASE:
- release_io_hfcs(cs);
- return (0);
- case CARD_INIT:
- delay = (75 * HZ) / 100 + 1;
- mod_timer(&cs->hw.hfcD.timer, jiffies + delay);
- spin_lock_irqsave(&cs->lock, flags);
- reset_hfcs(cs);
- init2bds0(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- delay = (80 * HZ) / 1000 + 1;
- msleep(80);
- spin_lock_irqsave(&cs->lock, flags);
- cs->hw.hfcD.ctmt |= HFCD_TIM800;
- cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt);
- cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_TEST:
- return (0);
- }
- return (0);
-}
-
-#ifdef __ISAPNP__
-static struct isapnp_device_id hfc_ids[] = {
- { ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114),
- ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114),
- (unsigned long) "Acer P10" },
- { ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0002),
- ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0002),
- (unsigned long) "Billion 2" },
- { ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0001),
- ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0001),
- (unsigned long) "Billion 1" },
- { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x7410),
- ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x7410),
- (unsigned long) "IStar PnP" },
- { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2610),
- ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2610),
- (unsigned long) "Teles 16.3c" },
- { ISAPNP_VENDOR('S', 'F', 'M'), ISAPNP_FUNCTION(0x0001),
- ISAPNP_VENDOR('S', 'F', 'M'), ISAPNP_FUNCTION(0x0001),
- (unsigned long) "Tornado Tipa C" },
- { ISAPNP_VENDOR('K', 'Y', 'E'), ISAPNP_FUNCTION(0x0001),
- ISAPNP_VENDOR('K', 'Y', 'E'), ISAPNP_FUNCTION(0x0001),
- (unsigned long) "Genius Speed Surfer" },
- { 0, }
-};
-
-static struct isapnp_device_id *ipid = &hfc_ids[0];
-static struct pnp_card *pnp_c = NULL;
-#endif
-
-int setup_hfcs(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
-
- strcpy(tmp, hfcs_revision);
- printk(KERN_INFO "HiSax: HFC-S driver Rev. %s\n", HiSax_getrev(tmp));
-
-#ifdef __ISAPNP__
- if (!card->para[1] && isapnp_present()) {
- struct pnp_dev *pnp_d;
- while (ipid->card_vendor) {
- if ((pnp_c = pnp_find_card(ipid->card_vendor,
- ipid->card_device, pnp_c))) {
- pnp_d = NULL;
- if ((pnp_d = pnp_find_dev(pnp_c,
- ipid->vendor, ipid->function, pnp_d))) {
- int err;
-
- printk(KERN_INFO "HiSax: %s detected\n",
- (char *)ipid->driver_data);
- pnp_disable_dev(pnp_d);
- err = pnp_activate_dev(pnp_d);
- if (err < 0) {
- printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __func__, err);
- return (0);
- }
- card->para[1] = pnp_port_start(pnp_d, 0);
- card->para[0] = pnp_irq(pnp_d, 0);
- if (card->para[0] == -1 || !card->para[1]) {
- printk(KERN_ERR "HFC PnP:some resources are missing %ld/%lx\n",
- card->para[0], card->para[1]);
- pnp_disable_dev(pnp_d);
- return (0);
- }
- break;
- } else {
- printk(KERN_ERR "HFC PnP: PnP error card found, no device\n");
- }
- }
- ipid++;
- pnp_c = NULL;
- }
- if (!ipid->card_vendor) {
- printk(KERN_INFO "HFC PnP: no ISAPnP card found\n");
- return (0);
- }
- }
-#endif
- cs->hw.hfcD.addr = card->para[1] & 0xfffe;
- cs->irq = card->para[0];
- cs->hw.hfcD.cip = 0;
- cs->hw.hfcD.int_s1 = 0;
- cs->hw.hfcD.send = NULL;
- cs->bcs[0].hw.hfc.send = NULL;
- cs->bcs[1].hw.hfc.send = NULL;
- cs->hw.hfcD.dfifosize = 512;
- cs->dc.hfcd.ph_state = 0;
- cs->hw.hfcD.fifo = 255;
- if (cs->typ == ISDN_CTYPE_TELES3C) {
- cs->hw.hfcD.bfifosize = 1024 + 512;
- } else if (cs->typ == ISDN_CTYPE_ACERP10) {
- cs->hw.hfcD.bfifosize = 7 * 1024 + 512;
- } else
- return (0);
- if (!request_region(cs->hw.hfcD.addr, 2, "HFCS isdn")) {
- printk(KERN_WARNING
- "HiSax: %s config port %x-%x already in use\n",
- CardType[card->typ],
- cs->hw.hfcD.addr,
- cs->hw.hfcD.addr + 2);
- return (0);
- }
- printk(KERN_INFO
- "HFCS: defined at 0x%x IRQ %d HZ %d\n",
- cs->hw.hfcD.addr,
- cs->irq, HZ);
- if (cs->typ == ISDN_CTYPE_TELES3C) {
- /* Teles 16.3c IO ADR is 0x200 | YY0U (YY Bit 15/14 address) */
- outb(0x00, cs->hw.hfcD.addr);
- outb(0x56, cs->hw.hfcD.addr | 1);
- } else if (cs->typ == ISDN_CTYPE_ACERP10) {
- /* Acer P10 IO ADR is 0x300 */
- outb(0x00, cs->hw.hfcD.addr);
- outb(0x57, cs->hw.hfcD.addr | 1);
- }
- set_cs_func(cs);
- timer_setup(&cs->hw.hfcD.timer, hfcs_Timer, 0);
- cs->cardmsg = &hfcs_card_msg;
- cs->irq_func = &hfcs_interrupt;
- return (1);
-}
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
deleted file mode 100644
index 40080e06421c..000000000000
--- a/drivers/isdn/hisax/hisax.h
+++ /dev/null
@@ -1,1352 +0,0 @@
-/* $Id: hisax.h,v 2.64.2.4 2004/02/11 13:21:33 keil Exp $
- *
- * Basic declarations, defines and prototypes
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/major.h>
-#include <asm/io.h>
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/timer.h>
-#include <linux/wait.h>
-#include <linux/isdnif.h>
-#include <linux/tty.h>
-#include <linux/serial_reg.h>
-#include <linux/netdevice.h>
-
-#define ERROR_STATISTIC
-
-#define REQUEST 0
-#define CONFIRM 1
-#define INDICATION 2
-#define RESPONSE 3
-
-#define HW_ENABLE 0x0000
-#define HW_RESET 0x0004
-#define HW_POWERUP 0x0008
-#define HW_ACTIVATE 0x0010
-#define HW_DEACTIVATE 0x0018
-
-#define HW_INFO1 0x0010
-#define HW_INFO2 0x0020
-#define HW_INFO3 0x0030
-#define HW_INFO4 0x0040
-#define HW_INFO4_P8 0x0040
-#define HW_INFO4_P10 0x0048
-#define HW_RSYNC 0x0060
-#define HW_TESTLOOP 0x0070
-#define CARD_RESET 0x00F0
-#define CARD_INIT 0x00F2
-#define CARD_RELEASE 0x00F3
-#define CARD_TEST 0x00F4
-#define CARD_AUX_IND 0x00F5
-
-#define PH_ACTIVATE 0x0100
-#define PH_DEACTIVATE 0x0110
-#define PH_DATA 0x0120
-#define PH_PULL 0x0130
-#define PH_TESTLOOP 0x0140
-#define PH_PAUSE 0x0150
-#define MPH_ACTIVATE 0x0180
-#define MPH_DEACTIVATE 0x0190
-#define MPH_INFORMATION 0x01A0
-
-#define DL_ESTABLISH 0x0200
-#define DL_RELEASE 0x0210
-#define DL_DATA 0x0220
-#define DL_FLUSH 0x0224
-#define DL_UNIT_DATA 0x0230
-
-#define MDL_BC_RELEASE 0x0278 // Formula-n enter:now
-#define MDL_BC_ASSIGN 0x027C // Formula-n enter:now
-#define MDL_ASSIGN 0x0280
-#define MDL_REMOVE 0x0284
-#define MDL_ERROR 0x0288
-#define MDL_INFO_SETUP 0x02E0
-#define MDL_INFO_CONN 0x02E4
-#define MDL_INFO_REL 0x02E8
-
-#define CC_SETUP 0x0300
-#define CC_RESUME 0x0304
-#define CC_MORE_INFO 0x0310
-#define CC_IGNORE 0x0320
-#define CC_REJECT 0x0324
-#define CC_SETUP_COMPL 0x0330
-#define CC_PROCEEDING 0x0340
-#define CC_ALERTING 0x0344
-#define CC_PROGRESS 0x0348
-#define CC_CONNECT 0x0350
-#define CC_CHARGE 0x0354
-#define CC_NOTIFY 0x0358
-#define CC_DISCONNECT 0x0360
-#define CC_RELEASE 0x0368
-#define CC_SUSPEND 0x0370
-#define CC_PROCEED_SEND 0x0374
-#define CC_REDIR 0x0378
-#define CC_T302 0x0382
-#define CC_T303 0x0383
-#define CC_T304 0x0384
-#define CC_T305 0x0385
-#define CC_T308_1 0x0388
-#define CC_T308_2 0x038A
-#define CC_T309 0x0309
-#define CC_T310 0x0390
-#define CC_T313 0x0393
-#define CC_T318 0x0398
-#define CC_T319 0x0399
-#define CC_TSPID 0x03A0
-#define CC_NOSETUP_RSP 0x03E0
-#define CC_SETUP_ERR 0x03E1
-#define CC_SUSPEND_ERR 0x03E2
-#define CC_RESUME_ERR 0x03E3
-#define CC_CONNECT_ERR 0x03E4
-#define CC_RELEASE_ERR 0x03E5
-#define CC_RESTART 0x03F4
-#define CC_TDSS1_IO 0x13F4 /* DSS1 IO user timer */
-#define CC_TNI1_IO 0x13F5 /* NI1 IO user timer */
-
-/* define maximum number of possible waiting incoming calls */
-#define MAX_WAITING_CALLS 2
-
-
-#ifdef __KERNEL__
-
-extern const char *CardType[];
-extern int nrcards;
-
-extern const char *l1_revision;
-extern const char *l2_revision;
-extern const char *l3_revision;
-extern const char *lli_revision;
-extern const char *tei_revision;
-
-/* include l3dss1 & ni1 specific process structures, but no other defines */
-#ifdef CONFIG_HISAX_EURO
-#define l3dss1_process
-#include "l3dss1.h"
-#undef l3dss1_process
-#endif /* CONFIG_HISAX_EURO */
-
-#ifdef CONFIG_HISAX_NI1
-#define l3ni1_process
-#include "l3ni1.h"
-#undef l3ni1_process
-#endif /* CONFIG_HISAX_NI1 */
-
-#define MAX_DFRAME_LEN 260
-#define MAX_DFRAME_LEN_L1 300
-#define HSCX_BUFMAX 4096
-#define MAX_DATA_SIZE (HSCX_BUFMAX - 4)
-#define MAX_DATA_MEM (HSCX_BUFMAX + 64)
-#define RAW_BUFMAX (((HSCX_BUFMAX * 6) / 5) + 5)
-#define MAX_HEADER_LEN 4
-#define MAX_WINDOW 8
-#define MAX_MON_FRAME 32
-#define MAX_DLOG_SPACE 2048
-#define MAX_BLOG_SPACE 256
-
-/* #define I4L_IRQ_FLAG SA_INTERRUPT */
-#define I4L_IRQ_FLAG 0
-
-/*
- * Statemachine
- */
-
-struct FsmInst;
-
-typedef void (*FSMFNPTR)(struct FsmInst *, int, void *);
-
-struct Fsm {
- FSMFNPTR *jumpmatrix;
- int state_count, event_count;
- char **strEvent, **strState;
-};
-
-struct FsmInst {
- struct Fsm *fsm;
- int state;
- int debug;
- void *userdata;
- int userint;
- void (*printdebug) (struct FsmInst *, char *, ...);
-};
-
-struct FsmNode {
- int state, event;
- void (*routine) (struct FsmInst *, int, void *);
-};
-
-struct FsmTimer {
- struct FsmInst *fi;
- struct timer_list tl;
- int event;
- void *arg;
-};
-
-struct L3Timer {
- struct l3_process *pc;
- struct timer_list tl;
- int event;
-};
-
-#define FLG_L1_ACTIVATING 1
-#define FLG_L1_ACTIVATED 2
-#define FLG_L1_DEACTTIMER 3
-#define FLG_L1_ACTTIMER 4
-#define FLG_L1_T3RUN 5
-#define FLG_L1_PULL_REQ 6
-#define FLG_L1_UINT 7
-
-struct Layer1 {
- void *hardware;
- struct BCState *bcs;
- struct PStack **stlistp;
- unsigned long Flags;
- struct FsmInst l1m;
- struct FsmTimer timer;
- void (*l1l2) (struct PStack *, int, void *);
- void (*l1hw) (struct PStack *, int, void *);
- void (*l1tei) (struct PStack *, int, void *);
- int mode, bc;
- int delay;
-};
-
-#define GROUP_TEI 127
-#define TEI_SAPI 63
-#define CTRL_SAPI 0
-#define PACKET_NOACK 7
-
-/* Layer2 Flags */
-
-#define FLG_LAPB 0
-#define FLG_LAPD 1
-#define FLG_ORIG 2
-#define FLG_MOD128 3
-#define FLG_PEND_REL 4
-#define FLG_L3_INIT 5
-#define FLG_T200_RUN 6
-#define FLG_ACK_PEND 7
-#define FLG_REJEXC 8
-#define FLG_OWN_BUSY 9
-#define FLG_PEER_BUSY 10
-#define FLG_DCHAN_BUSY 11
-#define FLG_L1_ACTIV 12
-#define FLG_ESTAB_PEND 13
-#define FLG_PTP 14
-#define FLG_FIXED_TEI 15
-#define FLG_L2BLOCK 16
-
-struct Layer2 {
- int tei;
- int sap;
- int maxlen;
- u_long flag;
- spinlock_t lock;
- u_int vs, va, vr;
- int rc;
- unsigned int window;
- unsigned int sow;
- struct sk_buff *windowar[MAX_WINDOW];
- struct sk_buff_head i_queue;
- struct sk_buff_head ui_queue;
- void (*l2l1) (struct PStack *, int, void *);
- void (*l2l3) (struct PStack *, int, void *);
- void (*l2tei) (struct PStack *, int, void *);
- struct FsmInst l2m;
- struct FsmTimer t200, t203;
- int T200, N200, T203;
- int debug;
- char debug_id[16];
-};
-
-struct Layer3 {
- void (*l3l4) (struct PStack *, int, void *);
- void (*l3ml3) (struct PStack *, int, void *);
- void (*l3l2) (struct PStack *, int, void *);
- struct FsmInst l3m;
- struct FsmTimer l3m_timer;
- struct sk_buff_head squeue;
- struct l3_process *proc;
- struct l3_process *global;
- int N303;
- int debug;
- char debug_id[8];
-};
-
-struct LLInterface {
- void (*l4l3) (struct PStack *, int, void *);
- int (*l4l3_proto) (struct PStack *, isdn_ctrl *);
- void *userdata;
- u_long flag;
-};
-
-#define FLG_LLI_L1WAKEUP 1
-#define FLG_LLI_L2WAKEUP 2
-
-struct Management {
- int ri;
- struct FsmInst tei_m;
- struct FsmTimer t202;
- int T202, N202, debug;
- void (*layer) (struct PStack *, int, void *);
-};
-
-#define NO_CAUSE 254
-
-struct Param {
- u_char cause;
- u_char loc;
- u_char diag[6];
- int bchannel;
- int chargeinfo;
- int spv; /* SPV Flag */
- setup_parm setup; /* from isdnif.h numbers and Serviceindicator */
- u_char moderate; /* transfer mode and rate (bearer octet 4) */
-};
-
-
-struct PStack {
- struct PStack *next;
- struct Layer1 l1;
- struct Layer2 l2;
- struct Layer3 l3;
- struct LLInterface lli;
- struct Management ma;
- int protocol; /* EDSS1, 1TR6 or NI1 */
-
- /* protocol specific data fields */
- union
- { u_char uuuu; /* only as dummy */
-#ifdef CONFIG_HISAX_EURO
- dss1_stk_priv dss1; /* private dss1 data */
-#endif /* CONFIG_HISAX_EURO */
-#ifdef CONFIG_HISAX_NI1
- ni1_stk_priv ni1; /* private ni1 data */
-#endif /* CONFIG_HISAX_NI1 */
- } prot;
-};
-
-struct l3_process {
- int callref;
- int state;
- struct L3Timer timer;
- int N303;
- int debug;
- struct Param para;
- struct Channel *chan;
- struct PStack *st;
- struct l3_process *next;
- ulong redir_result;
-
- /* protocol specific data fields */
- union
- { u_char uuuu; /* only when euro not defined, avoiding empty union */
-#ifdef CONFIG_HISAX_EURO
- dss1_proc_priv dss1; /* private dss1 data */
-#endif /* CONFIG_HISAX_EURO */
-#ifdef CONFIG_HISAX_NI1
- ni1_proc_priv ni1; /* private ni1 data */
-#endif /* CONFIG_HISAX_NI1 */
- } prot;
-};
-
-struct hscx_hw {
- int hscx;
- int rcvidx;
- int count; /* Current skb sent count */
- u_char *rcvbuf; /* B-Channel receive Buffer */
- u_char tsaxr0;
- u_char tsaxr1;
-};
-
-struct w6692B_hw {
- int bchan;
- int rcvidx;
- int count; /* Current skb sent count */
- u_char *rcvbuf; /* B-Channel receive Buffer */
-};
-
-struct isar_reg {
- unsigned long Flags;
- volatile u_char bstat;
- volatile u_char iis;
- volatile u_char cmsb;
- volatile u_char clsb;
- volatile u_char par[8];
-};
-
-struct isar_hw {
- int dpath;
- int rcvidx;
- int txcnt;
- int mml;
- u_char state;
- u_char cmd;
- u_char mod;
- u_char newcmd;
- u_char newmod;
- char try_mod;
- struct timer_list ftimer;
- u_char *rcvbuf; /* B-Channel receive Buffer */
- u_char conmsg[16];
- struct isar_reg *reg;
-};
-
-struct hdlc_stat_reg {
-#ifdef __BIG_ENDIAN
- u_char fill;
- u_char mode;
- u_char xml;
- u_char cmd;
-#else
- u_char cmd;
- u_char xml;
- u_char mode;
- u_char fill;
-#endif
-} __attribute__((packed));
-
-struct hdlc_hw {
- union {
- u_int ctrl;
- struct hdlc_stat_reg sr;
- } ctrl;
- u_int stat;
- int rcvidx;
- int count; /* Current skb sent count */
- u_char *rcvbuf; /* B-Channel receive Buffer */
-};
-
-struct hfcB_hw {
- unsigned int *send;
- int f1;
- int f2;
-};
-
-struct tiger_hw {
- u_int *send;
- u_int *s_irq;
- u_int *s_end;
- u_int *sendp;
- u_int *rec;
- int free;
- u_char *rcvbuf;
- u_char *sendbuf;
- u_char *sp;
- int sendcnt;
- u_int s_tot;
- u_int r_bitcnt;
- u_int r_tot;
- u_int r_err;
- u_int r_fcs;
- u_char r_state;
- u_char r_one;
- u_char r_val;
- u_char s_state;
-};
-
-struct amd7930_hw {
- u_char *tx_buff;
- u_char *rv_buff;
- int rv_buff_in;
- int rv_buff_out;
- struct sk_buff *rv_skb;
- struct hdlc_state *hdlc_state;
- struct work_struct tq_rcv;
- struct work_struct tq_xmt;
-};
-
-#define BC_FLG_INIT 1
-#define BC_FLG_ACTIV 2
-#define BC_FLG_BUSY 3
-#define BC_FLG_NOFRAME 4
-#define BC_FLG_HALF 5
-#define BC_FLG_EMPTY 6
-#define BC_FLG_ORIG 7
-#define BC_FLG_DLEETX 8
-#define BC_FLG_LASTDLE 9
-#define BC_FLG_FIRST 10
-#define BC_FLG_LASTDATA 11
-#define BC_FLG_NMD_DATA 12
-#define BC_FLG_FTI_RUN 13
-#define BC_FLG_LL_OK 14
-#define BC_FLG_LL_CONN 15
-#define BC_FLG_FTI_FTS 16
-#define BC_FLG_FRH_WAIT 17
-
-#define L1_MODE_NULL 0
-#define L1_MODE_TRANS 1
-#define L1_MODE_HDLC 2
-#define L1_MODE_EXTRN 3
-#define L1_MODE_HDLC_56K 4
-#define L1_MODE_MODEM 7
-#define L1_MODE_V32 8
-#define L1_MODE_FAX 9
-
-struct BCState {
- int channel;
- int mode;
- u_long Flag;
- struct IsdnCardState *cs;
- int tx_cnt; /* B-Channel transmit counter */
- struct sk_buff *tx_skb; /* B-Channel transmit Buffer */
- struct sk_buff_head rqueue; /* B-Channel receive Queue */
- struct sk_buff_head squeue; /* B-Channel send Queue */
- int ackcnt;
- spinlock_t aclock;
- struct PStack *st;
- u_char *blog;
- u_char *conmsg;
- struct timer_list transbusy;
- struct work_struct tqueue;
- u_long event;
- int (*BC_SetStack) (struct PStack *, struct BCState *);
- void (*BC_Close) (struct BCState *);
-#ifdef ERROR_STATISTIC
- int err_crc;
- int err_tx;
- int err_rdo;
- int err_inv;
-#endif
- union {
- struct hscx_hw hscx;
- struct hdlc_hw hdlc;
- struct isar_hw isar;
- struct hfcB_hw hfc;
- struct tiger_hw tiger;
- struct amd7930_hw amd7930;
- struct w6692B_hw w6692;
- struct hisax_b_if *b_if;
- } hw;
-};
-
-struct Channel {
- struct PStack *b_st, *d_st;
- struct IsdnCardState *cs;
- struct BCState *bcs;
- int chan;
- int incoming;
- struct FsmInst fi;
- struct FsmTimer drel_timer, dial_timer;
- int debug;
- int l2_protocol, l2_active_protocol;
- int l3_protocol;
- int data_open;
- struct l3_process *proc;
- setup_parm setup; /* from isdnif.h numbers and Serviceindicator */
- u_long Flags; /* for remembering action done in l4 */
- int leased;
-};
-
-struct elsa_hw {
- struct pci_dev *dev;
- unsigned long base;
- unsigned int cfg;
- unsigned int ctrl;
- unsigned int ale;
- unsigned int isac;
- unsigned int itac;
- unsigned int hscx;
- unsigned int trig;
- unsigned int timer;
- unsigned int counter;
- unsigned int status;
- struct timer_list tl;
- unsigned int MFlag;
- struct BCState *bcs;
- u_char *transbuf;
- u_char *rcvbuf;
- unsigned int transp;
- unsigned int rcvp;
- unsigned int transcnt;
- unsigned int rcvcnt;
- u_char IER;
- u_char FCR;
- u_char LCR;
- u_char MCR;
- u_char ctrl_reg;
-};
-
-struct teles3_hw {
- unsigned int cfg_reg;
- signed int isac;
- signed int hscx[2];
- signed int isacfifo;
- signed int hscxfifo[2];
-};
-
-struct teles0_hw {
- unsigned int cfg_reg;
- void __iomem *membase;
- unsigned long phymem;
-};
-
-struct avm_hw {
- unsigned int cfg_reg;
- unsigned int isac;
- unsigned int hscx[2];
- unsigned int isacfifo;
- unsigned int hscxfifo[2];
- unsigned int counter;
- struct pci_dev *dev;
-};
-
-struct ix1_hw {
- unsigned int cfg_reg;
- unsigned int isac_ale;
- unsigned int isac;
- unsigned int hscx_ale;
- unsigned int hscx;
-};
-
-struct diva_hw {
- unsigned long cfg_reg;
- unsigned long pci_cfg;
- unsigned int ctrl;
- unsigned long isac_adr;
- unsigned int isac;
- unsigned long hscx_adr;
- unsigned int hscx;
- unsigned int status;
- struct timer_list tl;
- u_char ctrl_reg;
- struct pci_dev *dev;
-};
-
-struct asus_hw {
- unsigned int cfg_reg;
- unsigned int adr;
- unsigned int isac;
- unsigned int hscx;
- unsigned int u7;
- unsigned int pots;
-};
-
-
-struct hfc_hw {
- unsigned int addr;
- unsigned int fifosize;
- unsigned char cirm;
- unsigned char ctmt;
- unsigned char cip;
- u_char isac_spcr;
- struct timer_list timer;
-};
-
-struct sedl_hw {
- unsigned int cfg_reg;
- unsigned int adr;
- unsigned int isac;
- unsigned int hscx;
- unsigned int reset_on;
- unsigned int reset_off;
- struct isar_reg isar;
- unsigned int chip;
- unsigned int bus;
- struct pci_dev *dev;
-};
-
-struct spt_hw {
- unsigned int cfg_reg;
- unsigned int isac;
- unsigned int hscx[2];
- unsigned char res_irq;
-};
-
-struct mic_hw {
- unsigned int cfg_reg;
- unsigned int adr;
- unsigned int isac;
- unsigned int hscx;
-};
-
-struct njet_hw {
- unsigned long base;
- unsigned int isac;
- unsigned int auxa;
- unsigned char auxd;
- unsigned char dmactrl;
- unsigned char ctrl_reg;
- unsigned char irqmask0;
- unsigned char irqstat0;
- unsigned char last_is0;
- struct pci_dev *dev;
-};
-
-struct hfcPCI_hw {
- unsigned char cirm;
- unsigned char ctmt;
- unsigned char conn;
- unsigned char mst_m;
- unsigned char int_m1;
- unsigned char int_m2;
- unsigned char int_s1;
- unsigned char sctrl;
- unsigned char sctrl_r;
- unsigned char sctrl_e;
- unsigned char trm;
- unsigned char stat;
- unsigned char fifo;
- unsigned char fifo_en;
- unsigned char bswapped;
- unsigned char nt_mode;
- int nt_timer;
- struct pci_dev *dev;
- void __iomem *pci_io; /* start of PCI IO memory */
- dma_addr_t dma; /* dma handle for Fifos */
- void *fifos; /* FIFO memory */
- int last_bfifo_cnt[2]; /* marker saving last b-fifo frame count */
- struct timer_list timer;
-};
-
-struct hfcSX_hw {
- unsigned long base;
- unsigned char cirm;
- unsigned char ctmt;
- unsigned char conn;
- unsigned char mst_m;
- unsigned char int_m1;
- unsigned char int_m2;
- unsigned char int_s1;
- unsigned char sctrl;
- unsigned char sctrl_r;
- unsigned char sctrl_e;
- unsigned char trm;
- unsigned char stat;
- unsigned char fifo;
- unsigned char bswapped;
- unsigned char nt_mode;
- unsigned char chip;
- int b_fifo_size;
- unsigned char last_fifo;
- void *extra;
- int nt_timer;
- struct timer_list timer;
-};
-
-struct hfcD_hw {
- unsigned int addr;
- unsigned int bfifosize;
- unsigned int dfifosize;
- unsigned char cirm;
- unsigned char ctmt;
- unsigned char cip;
- unsigned char conn;
- unsigned char mst_m;
- unsigned char int_m1;
- unsigned char int_m2;
- unsigned char int_s1;
- unsigned char sctrl;
- unsigned char stat;
- unsigned char fifo;
- unsigned char f1;
- unsigned char f2;
- unsigned int *send;
- struct timer_list timer;
-};
-
-struct isurf_hw {
- unsigned int reset;
- unsigned long phymem;
- void __iomem *isac;
- void __iomem *isar;
- struct isar_reg isar_r;
-};
-
-struct saphir_hw {
- struct pci_dev *dev;
- unsigned int cfg_reg;
- unsigned int ale;
- unsigned int isac;
- unsigned int hscx;
- struct timer_list timer;
-};
-
-struct bkm_hw {
- struct pci_dev *dev;
- unsigned long base;
- /* A4T stuff */
- unsigned long isac_adr;
- unsigned int isac_ale;
- unsigned long jade_adr;
- unsigned int jade_ale;
- /* Scitel Quadro stuff */
- unsigned long plx_adr;
- unsigned long data_adr;
-};
-
-struct gazel_hw {
- struct pci_dev *dev;
- unsigned int cfg_reg;
- unsigned int pciaddr[2];
- signed int ipac;
- signed int isac;
- signed int hscx[2];
- signed int isacfifo;
- signed int hscxfifo[2];
- unsigned char timeslot;
- unsigned char iom2;
-};
-
-struct w6692_hw {
- struct pci_dev *dev;
- unsigned int iobase;
- struct timer_list timer;
-};
-
-struct arcofi_msg {
- struct arcofi_msg *next;
- u_char receive;
- u_char len;
- u_char msg[10];
-};
-
-struct isac_chip {
- int ph_state;
- u_char *mon_tx;
- u_char *mon_rx;
- int mon_txp;
- int mon_txc;
- int mon_rxp;
- struct arcofi_msg *arcofi_list;
- struct timer_list arcofitimer;
- wait_queue_head_t arcofi_wait;
- u_char arcofi_bc;
- u_char arcofi_state;
- u_char mocr;
- u_char adf2;
-};
-
-struct hfcd_chip {
- int ph_state;
-};
-
-struct hfcpci_chip {
- int ph_state;
-};
-
-struct hfcsx_chip {
- int ph_state;
-};
-
-struct w6692_chip {
- int ph_state;
-};
-
-struct amd7930_chip {
- u_char lmr1;
- u_char ph_state;
- u_char old_state;
- u_char flg_t3;
- unsigned int tx_xmtlen;
- struct timer_list timer3;
- void (*ph_command) (struct IsdnCardState *, u_char, char *);
- void (*setIrqMask) (struct IsdnCardState *, u_char);
-};
-
-struct icc_chip {
- int ph_state;
- u_char *mon_tx;
- u_char *mon_rx;
- int mon_txp;
- int mon_txc;
- int mon_rxp;
- struct arcofi_msg *arcofi_list;
- struct timer_list arcofitimer;
- wait_queue_head_t arcofi_wait;
- u_char arcofi_bc;
- u_char arcofi_state;
- u_char mocr;
- u_char adf2;
-};
-
-#define HW_IOM1 0
-#define HW_IPAC 1
-#define HW_ISAR 2
-#define HW_ARCOFI 3
-#define FLG_TWO_DCHAN 4
-#define FLG_L1_DBUSY 5
-#define FLG_DBUSY_TIMER 6
-#define FLG_LOCK_ATOMIC 7
-#define FLG_ARCOFI_TIMER 8
-#define FLG_ARCOFI_ERROR 9
-#define FLG_HW_L1_UINT 10
-
-struct IsdnCardState {
- spinlock_t lock;
- u_char typ;
- u_char subtyp;
- int protocol;
- u_int irq;
- u_long irq_flags;
- u_long HW_Flags;
- int *busy_flag;
- int chanlimit; /* limited number of B-chans to use */
- int logecho; /* log echo if supported by card */
- union {
- struct elsa_hw elsa;
- struct teles0_hw teles0;
- struct teles3_hw teles3;
- struct avm_hw avm;
- struct ix1_hw ix1;
- struct diva_hw diva;
- struct asus_hw asus;
- struct hfc_hw hfc;
- struct sedl_hw sedl;
- struct spt_hw spt;
- struct mic_hw mic;
- struct njet_hw njet;
- struct hfcD_hw hfcD;
- struct hfcPCI_hw hfcpci;
- struct hfcSX_hw hfcsx;
- struct ix1_hw niccy;
- struct isurf_hw isurf;
- struct saphir_hw saphir;
- struct bkm_hw ax;
- struct gazel_hw gazel;
- struct w6692_hw w6692;
- struct hisax_d_if *hisax_d_if;
- } hw;
- int myid;
- isdn_if iif;
- spinlock_t statlock;
- u_char *status_buf;
- u_char *status_read;
- u_char *status_write;
- u_char *status_end;
- u_char (*readisac) (struct IsdnCardState *, u_char);
- void (*writeisac) (struct IsdnCardState *, u_char, u_char);
- void (*readisacfifo) (struct IsdnCardState *, u_char *, int);
- void (*writeisacfifo) (struct IsdnCardState *, u_char *, int);
- u_char (*BC_Read_Reg) (struct IsdnCardState *, int, u_char);
- void (*BC_Write_Reg) (struct IsdnCardState *, int, u_char, u_char);
- void (*BC_Send_Data) (struct BCState *);
- int (*cardmsg) (struct IsdnCardState *, int, void *);
- void (*setstack_d) (struct PStack *, struct IsdnCardState *);
- void (*DC_Close) (struct IsdnCardState *);
- irq_handler_t irq_func;
- int (*auxcmd) (struct IsdnCardState *, isdn_ctrl *);
- struct Channel channel[2 + MAX_WAITING_CALLS];
- struct BCState bcs[2 + MAX_WAITING_CALLS];
- struct PStack *stlist;
- struct sk_buff_head rq, sq; /* D-channel queues */
- int cardnr;
- char *dlog;
- int debug;
- union {
- struct isac_chip isac;
- struct hfcd_chip hfcd;
- struct hfcpci_chip hfcpci;
- struct hfcsx_chip hfcsx;
- struct w6692_chip w6692;
- struct amd7930_chip amd7930;
- struct icc_chip icc;
- } dc;
- u_char *rcvbuf;
- int rcvidx;
- struct sk_buff *tx_skb;
- int tx_cnt;
- u_long event;
- struct work_struct tqueue;
- struct timer_list dbusytimer;
- unsigned int irq_cnt;
-#ifdef ERROR_STATISTIC
- int err_crc;
- int err_tx;
- int err_rx;
-#endif
-};
-
-
-#define schedule_event(s, ev) do { test_and_set_bit(ev, &s->event); schedule_work(&s->tqueue); } while (0)
-
-#define MON0_RX 1
-#define MON1_RX 2
-#define MON0_TX 4
-#define MON1_TX 8
-
-
-#ifdef ISDN_CHIP_ISAC
-#undef ISDN_CHIP_ISAC
-#endif
-
-#ifdef CONFIG_HISAX_16_0
-#define CARD_TELES0 1
-#ifndef ISDN_CHIP_ISAC
-#define ISDN_CHIP_ISAC 1
-#endif
-#else
-#define CARD_TELES0 0
-#endif
-
-#ifdef CONFIG_HISAX_16_3
-#define CARD_TELES3 1
-#ifndef ISDN_CHIP_ISAC
-#define ISDN_CHIP_ISAC 1
-#endif
-#else
-#define CARD_TELES3 0
-#endif
-
-#ifdef CONFIG_HISAX_TELESPCI
-#define CARD_TELESPCI 1
-#ifndef ISDN_CHIP_ISAC
-#define ISDN_CHIP_ISAC 1
-#endif
-#else
-#define CARD_TELESPCI 0
-#endif
-
-#ifdef CONFIG_HISAX_AVM_A1
-#define CARD_AVM_A1 1
-#ifndef ISDN_CHIP_ISAC
-#define ISDN_CHIP_ISAC 1
-#endif
-#else
-#define CARD_AVM_A1 0
-#endif
-
-#ifdef CONFIG_HISAX_AVM_A1_PCMCIA
-#define CARD_AVM_A1_PCMCIA 1
-#ifndef ISDN_CHIP_ISAC
-#define ISDN_CHIP_ISAC 1
-#endif
-#else
-#define CARD_AVM_A1_PCMCIA 0
-#endif
-
-#ifdef CONFIG_HISAX_FRITZPCI
-#define CARD_FRITZPCI 1
-#ifndef ISDN_CHIP_ISAC
-#define ISDN_CHIP_ISAC 1
-#endif
-#else
-#define CARD_FRITZPCI 0
-#endif
-
-#ifdef CONFIG_HISAX_ELSA
-#define CARD_ELSA 1
-#ifndef ISDN_CHIP_ISAC
-#define ISDN_CHIP_ISAC 1
-#endif
-#else
-#define CARD_ELSA 0
-#endif
-
-#ifdef CONFIG_HISAX_IX1MICROR2
-#define CARD_IX1MICROR2 1
-#ifndef ISDN_CHIP_ISAC
-#define ISDN_CHIP_ISAC 1
-#endif
-#else
-#define CARD_IX1MICROR2 0
-#endif
-
-#ifdef CONFIG_HISAX_DIEHLDIVA
-#define CARD_DIEHLDIVA 1
-#ifndef ISDN_CHIP_ISAC
-#define ISDN_CHIP_ISAC 1
-#endif
-#else
-#define CARD_DIEHLDIVA 0
-#endif
-
-#ifdef CONFIG_HISAX_ASUSCOM
-#define CARD_ASUSCOM 1
-#ifndef ISDN_CHIP_ISAC
-#define ISDN_CHIP_ISAC 1
-#endif
-#else
-#define CARD_ASUSCOM 0
-#endif
-
-#ifdef CONFIG_HISAX_TELEINT
-#define CARD_TELEINT 1
-#ifndef ISDN_CHIP_ISAC
-#define ISDN_CHIP_ISAC 1
-#endif
-#else
-#define CARD_TELEINT 0
-#endif
-
-#ifdef CONFIG_HISAX_SEDLBAUER
-#define CARD_SEDLBAUER 1
-#ifndef ISDN_CHIP_ISAC
-#define ISDN_CHIP_ISAC 1
-#endif
-#else
-#define CARD_SEDLBAUER 0
-#endif
-
-#ifdef CONFIG_HISAX_SPORTSTER
-#define CARD_SPORTSTER 1
-#ifndef ISDN_CHIP_ISAC
-#define ISDN_CHIP_ISAC 1
-#endif
-#else
-#define CARD_SPORTSTER 0
-#endif
-
-#ifdef CONFIG_HISAX_MIC
-#define CARD_MIC 1
-#ifndef ISDN_CHIP_ISAC
-#define ISDN_CHIP_ISAC 1
-#endif
-#else
-#define CARD_MIC 0
-#endif
-
-#ifdef CONFIG_HISAX_NETJET
-#define CARD_NETJET_S 1
-#ifndef ISDN_CHIP_ISAC
-#define ISDN_CHIP_ISAC 1
-#endif
-#else
-#define CARD_NETJET_S 0
-#endif
-
-#ifdef CONFIG_HISAX_HFCS
-#define CARD_HFCS 1
-#else
-#define CARD_HFCS 0
-#endif
-
-#ifdef CONFIG_HISAX_HFC_PCI
-#define CARD_HFC_PCI 1
-#else
-#define CARD_HFC_PCI 0
-#endif
-
-#ifdef CONFIG_HISAX_HFC_SX
-#define CARD_HFC_SX 1
-#else
-#define CARD_HFC_SX 0
-#endif
-
-#ifdef CONFIG_HISAX_NICCY
-#define CARD_NICCY 1
-#ifndef ISDN_CHIP_ISAC
-#define ISDN_CHIP_ISAC 1
-#endif
-#else
-#define CARD_NICCY 0
-#endif
-
-#ifdef CONFIG_HISAX_ISURF
-#define CARD_ISURF 1
-#ifndef ISDN_CHIP_ISAC
-#define ISDN_CHIP_ISAC 1
-#endif
-#else
-#define CARD_ISURF 0
-#endif
-
-#ifdef CONFIG_HISAX_S0BOX
-#define CARD_S0BOX 1
-#ifndef ISDN_CHIP_ISAC
-#define ISDN_CHIP_ISAC 1
-#endif
-#else
-#define CARD_S0BOX 0
-#endif
-
-#ifdef CONFIG_HISAX_HSTSAPHIR
-#define CARD_HSTSAPHIR 1
-#ifndef ISDN_CHIP_ISAC
-#define ISDN_CHIP_ISAC 1
-#endif
-#else
-#define CARD_HSTSAPHIR 0
-#endif
-
-#ifdef CONFIG_HISAX_BKM_A4T
-#define CARD_BKM_A4T 1
-#ifndef ISDN_CHIP_ISAC
-#define ISDN_CHIP_ISAC 1
-#endif
-#else
-#define CARD_BKM_A4T 0
-#endif
-
-#ifdef CONFIG_HISAX_SCT_QUADRO
-#define CARD_SCT_QUADRO 1
-#ifndef ISDN_CHIP_ISAC
-#define ISDN_CHIP_ISAC 1
-#endif
-#else
-#define CARD_SCT_QUADRO 0
-#endif
-
-#ifdef CONFIG_HISAX_GAZEL
-#define CARD_GAZEL 1
-#ifndef ISDN_CHIP_ISAC
-#define ISDN_CHIP_ISAC 1
-#endif
-#else
-#define CARD_GAZEL 0
-#endif
-
-#ifdef CONFIG_HISAX_W6692
-#define CARD_W6692 1
-#ifndef ISDN_CHIP_W6692
-#define ISDN_CHIP_W6692 1
-#endif
-#else
-#define CARD_W6692 0
-#endif
-
-#ifdef CONFIG_HISAX_NETJET_U
-#define CARD_NETJET_U 1
-#ifndef ISDN_CHIP_ICC
-#define ISDN_CHIP_ICC 1
-#endif
-#ifndef HISAX_UINTERFACE
-#define HISAX_UINTERFACE 1
-#endif
-#else
-#define CARD_NETJET_U 0
-#endif
-
-#ifdef CONFIG_HISAX_ENTERNOW_PCI
-#define CARD_FN_ENTERNOW_PCI 1
-#else
-#define CARD_FN_ENTERNOW_PCI 0
-#endif
-
-#define TEI_PER_CARD 1
-
-/* L1 Debug */
-#define L1_DEB_WARN 0x01
-#define L1_DEB_INTSTAT 0x02
-#define L1_DEB_ISAC 0x04
-#define L1_DEB_ISAC_FIFO 0x08
-#define L1_DEB_HSCX 0x10
-#define L1_DEB_HSCX_FIFO 0x20
-#define L1_DEB_LAPD 0x40
-#define L1_DEB_IPAC 0x80
-#define L1_DEB_RECEIVE_FRAME 0x100
-#define L1_DEB_MONITOR 0x200
-#define DEB_DLOG_HEX 0x400
-#define DEB_DLOG_VERBOSE 0x800
-
-#define L2FRAME_DEBUG
-
-#ifdef L2FRAME_DEBUG
-extern void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, int dir);
-#endif
-
-#include "hisax_cfg.h"
-
-void init_bcstate(struct IsdnCardState *cs, int bc);
-
-void setstack_HiSax(struct PStack *st, struct IsdnCardState *cs);
-void HiSax_addlist(struct IsdnCardState *sp, struct PStack *st);
-void HiSax_rmlist(struct IsdnCardState *sp, struct PStack *st);
-
-void setstack_l1_B(struct PStack *st);
-
-void setstack_tei(struct PStack *st);
-void setstack_manager(struct PStack *st);
-
-void setstack_isdnl2(struct PStack *st, char *debug_id);
-void releasestack_isdnl2(struct PStack *st);
-void setstack_transl2(struct PStack *st);
-void releasestack_transl2(struct PStack *st);
-void lli_writewakeup(struct PStack *st, int len);
-
-void setstack_l3dc(struct PStack *st, struct Channel *chanp);
-void setstack_l3bc(struct PStack *st, struct Channel *chanp);
-void releasestack_isdnl3(struct PStack *st);
-
-u_char *findie(u_char *p, int size, u_char ie, int wanted_set);
-int getcallref(u_char *p);
-int newcallref(void);
-
-int FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount);
-void FsmFree(struct Fsm *fsm);
-int FsmEvent(struct FsmInst *fi, int event, void *arg);
-void FsmChangeState(struct FsmInst *fi, int newstate);
-void FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft);
-int FsmAddTimer(struct FsmTimer *ft, int millisec, int event,
- void *arg, int where);
-void FsmRestartTimer(struct FsmTimer *ft, int millisec, int event,
- void *arg, int where);
-void FsmDelTimer(struct FsmTimer *ft, int where);
-int jiftime(char *s, long mark);
-
-int HiSax_command(isdn_ctrl *ic);
-int HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb);
-__printf(3, 4)
-void HiSax_putstatus(struct IsdnCardState *cs, char *head, const char *fmt, ...);
-__printf(3, 0)
-void VHiSax_putstatus(struct IsdnCardState *cs, char *head, const char *fmt, va_list args);
-void HiSax_reportcard(int cardnr, int sel);
-int QuickHex(char *txt, u_char *p, int cnt);
-void LogFrame(struct IsdnCardState *cs, u_char *p, int size);
-void dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir);
-void iecpy(u_char *dest, u_char *iestart, int ieoffset);
-#endif /* __KERNEL__ */
-
-/*
- * Busywait delay for `jiffs' jiffies
- */
-#define HZDELAY(jiffs) do { \
- int tout = jiffs; \
- \
- while (tout--) { \
- int loops = USEC_PER_SEC / HZ; \
- while (loops--) \
- udelay(1); \
- } \
- } while (0)
-
-int ll_run(struct IsdnCardState *cs, int addfeatures);
-int CallcNew(void);
-void CallcFree(void);
-int CallcNewChan(struct IsdnCardState *cs);
-void CallcFreeChan(struct IsdnCardState *cs);
-int Isdnl1New(void);
-void Isdnl1Free(void);
-int Isdnl2New(void);
-void Isdnl2Free(void);
-int Isdnl3New(void);
-void Isdnl3Free(void);
-void init_tei(struct IsdnCardState *cs, int protocol);
-void release_tei(struct IsdnCardState *cs);
-char *HiSax_getrev(const char *revision);
-int TeiNew(void);
-void TeiFree(void);
-
-#ifdef CONFIG_PCI
-
-#include <linux/pci.h>
-
-/* adaptation wrapper for old usage
- * WARNING! This is unfit for use in a PCI hotplug environment,
- * as the returned PCI device can disappear at any moment in time.
- * Callers should be converted to use pci_get_device() instead.
- */
-static inline struct pci_dev *hisax_find_pci_device(unsigned int vendor,
- unsigned int device,
- struct pci_dev *from)
-{
- struct pci_dev *pdev;
-
- pci_dev_get(from);
- pdev = pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
- pci_dev_put(pdev);
- return pdev;
-}
-
-#endif
diff --git a/drivers/isdn/hisax/hisax_cfg.h b/drivers/isdn/hisax/hisax_cfg.h
deleted file mode 100644
index 487dcfe9e718..000000000000
--- a/drivers/isdn/hisax/hisax_cfg.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/* $Id: hisax_cfg.h,v 1.1.2.1 2004/01/24 20:47:23 keil Exp $
- * define of the basic HiSax configuration structures
- * and pcmcia interface
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#define ISDN_CTYPE_16_0 1
-#define ISDN_CTYPE_8_0 2
-#define ISDN_CTYPE_16_3 3
-#define ISDN_CTYPE_PNP 4
-#define ISDN_CTYPE_A1 5
-#define ISDN_CTYPE_ELSA 6
-#define ISDN_CTYPE_ELSA_PNP 7
-#define ISDN_CTYPE_TELESPCMCIA 8
-#define ISDN_CTYPE_IX1MICROR2 9
-#define ISDN_CTYPE_ELSA_PCMCIA 10
-#define ISDN_CTYPE_DIEHLDIVA 11
-#define ISDN_CTYPE_ASUSCOM 12
-#define ISDN_CTYPE_TELEINT 13
-#define ISDN_CTYPE_TELES3C 14
-#define ISDN_CTYPE_SEDLBAUER 15
-#define ISDN_CTYPE_SPORTSTER 16
-#define ISDN_CTYPE_MIC 17
-#define ISDN_CTYPE_ELSA_PCI 18
-#define ISDN_CTYPE_COMPAQ_ISA 19
-#define ISDN_CTYPE_NETJET_S 20
-#define ISDN_CTYPE_TELESPCI 21
-#define ISDN_CTYPE_SEDLBAUER_PCMCIA 22
-#define ISDN_CTYPE_AMD7930 23
-#define ISDN_CTYPE_NICCY 24
-#define ISDN_CTYPE_S0BOX 25
-#define ISDN_CTYPE_A1_PCMCIA 26
-#define ISDN_CTYPE_FRITZPCI 27
-#define ISDN_CTYPE_SEDLBAUER_FAX 28
-#define ISDN_CTYPE_ISURF 29
-#define ISDN_CTYPE_ACERP10 30
-#define ISDN_CTYPE_HSTSAPHIR 31
-#define ISDN_CTYPE_BKM_A4T 32
-#define ISDN_CTYPE_SCT_QUADRO 33
-#define ISDN_CTYPE_GAZEL 34
-#define ISDN_CTYPE_HFC_PCI 35
-#define ISDN_CTYPE_W6692 36
-#define ISDN_CTYPE_HFC_SX 37
-#define ISDN_CTYPE_NETJET_U 38
-#define ISDN_CTYPE_HFC_SP_PCMCIA 39
-#define ISDN_CTYPE_DYNAMIC 40
-#define ISDN_CTYPE_ENTERNOW 41
-#define ISDN_CTYPE_COUNT 41
-
-typedef struct IsdnCardState IsdnCardState_t;
-typedef struct IsdnCard IsdnCard_t;
-
-struct IsdnCard {
- int typ;
- int protocol; /* EDSS1, 1TR6 or NI1 */
- unsigned long para[4];
- IsdnCardState_t *cs;
-};
-
-typedef int (*hisax_setup_func_t)(struct IsdnCard *card);
-
-extern void HiSax_closecard(int);
-extern int hisax_init_pcmcia(void *, int *, IsdnCard_t *);
diff --git a/drivers/isdn/hisax/hisax_debug.h b/drivers/isdn/hisax/hisax_debug.h
deleted file mode 100644
index 7b3093d0856a..000000000000
--- a/drivers/isdn/hisax/hisax_debug.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Common debugging macros for use with the hisax driver
- *
- * Author Frode Isaksen
- * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
- * 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * How to use:
- *
- * Before including this file, you need to
- * #define __debug_variable my_debug
- * where my_debug is a variable in your code which
- * determines the debug bitmask.
- *
- * If CONFIG_HISAX_DEBUG is not set, all macros evaluate to nothing
- *
- */
-
-#ifndef __HISAX_DEBUG_H__
-#define __HISAX_DEBUG_H__
-
-
-#ifdef CONFIG_HISAX_DEBUG
-
-#define DBG(level, format, arg...) do { \
- if (level & __debug_variable) \
- printk(KERN_DEBUG "%s: " format "\n" , __func__ , ## arg); \
- } while (0)
-
-#define DBG_PACKET(level, data, count) \
- if (level & __debug_variable) dump_packet(__func__, data, count)
-
-#define DBG_SKB(level, skb) \
- if ((level & __debug_variable) && skb) dump_packet(__func__, skb->data, skb->len)
-
-
-static void __attribute__((unused))
-dump_packet(const char *name, const u_char *data, int pkt_len)
-{
-#define DUMP_HDR_SIZE 20
-#define DUMP_TLR_SIZE 8
- if (pkt_len) {
- int i, len1, len2;
-
- printk(KERN_DEBUG "%s: length=%d,data=", name, pkt_len);
-
- if (pkt_len > DUMP_HDR_SIZE + DUMP_TLR_SIZE) {
- len1 = DUMP_HDR_SIZE;
- len2 = DUMP_TLR_SIZE;
- } else {
- len1 = pkt_len > DUMP_HDR_SIZE ? DUMP_HDR_SIZE : pkt_len;
- len2 = 0;
- }
- for (i = 0; i < len1; ++i) {
- printk("%.2x", data[i]);
- }
- if (len2) {
- printk("..");
- for (i = pkt_len-DUMP_TLR_SIZE; i < pkt_len; ++i) {
- printk("%.2x", data[i]);
- }
- }
- printk("\n");
- }
-#undef DUMP_HDR_SIZE
-#undef DUMP_TLR_SIZE
-}
-
-#else
-
-#define DBG(level, format, arg...) do {} while (0)
-#define DBG_PACKET(level, data, count) do {} while (0)
-#define DBG_SKB(level, skb) do {} while (0)
-
-#endif
-
-#endif
diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.c b/drivers/isdn/hisax/hisax_fcpcipnp.c
deleted file mode 100644
index 7a7137d8664b..000000000000
--- a/drivers/isdn/hisax/hisax_fcpcipnp.c
+++ /dev/null
@@ -1,1024 +0,0 @@
-/*
- * Driver for AVM Fritz!PCI, Fritz!PCI v2, Fritz!PnP ISDN cards
- *
- * Author Kai Germaschewski
- * Copyright 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
- * 2001 by Karsten Keil <keil@isdn4linux.de>
- *
- * based upon Karsten Keil's original avm_pci.c driver
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Thanks to Wizard Computersysteme GmbH, Bremervoerde and
- * SoHaNet Technology GmbH, Berlin
- * for supporting the development of this driver
- */
-
-
-/* TODO:
- *
- * o POWER PC
- * o clean up debugging
- * o tx_skb at PH_DEACTIVATE time
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/isapnp.h>
-#include <linux/kmod.h>
-#include <linux/slab.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/delay.h>
-
-#include <asm/io.h>
-
-#include "hisax_fcpcipnp.h"
-
-// debugging cruft
-#define __debug_variable debug
-#include "hisax_debug.h"
-
-#ifdef CONFIG_HISAX_DEBUG
-static int debug = 0;
-/* static int hdlcfifosize = 32; */
-module_param(debug, int, 0);
-/* module_param(hdlcfifosize, int, 0); */
-#endif
-
-MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>");
-MODULE_DESCRIPTION("AVM Fritz!PCI/PnP ISDN driver");
-
-static const struct pci_device_id fcpci_ids[] = {
- { .vendor = PCI_VENDOR_ID_AVM,
- .device = PCI_DEVICE_ID_AVM_A1,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (unsigned long) "Fritz!Card PCI",
- },
- { .vendor = PCI_VENDOR_ID_AVM,
- .device = PCI_DEVICE_ID_AVM_A1_V2,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (unsigned long) "Fritz!Card PCI v2" },
- {}
-};
-
-MODULE_DEVICE_TABLE(pci, fcpci_ids);
-
-#ifdef CONFIG_PNP
-static struct pnp_device_id fcpnp_ids[] = {
- {
- .id = "AVM0900",
- .driver_data = (unsigned long) "Fritz!Card PnP",
- },
- { .id = "" }
-};
-
-MODULE_DEVICE_TABLE(pnp, fcpnp_ids);
-#endif
-
-static int protocol = 2; /* EURO-ISDN Default */
-module_param(protocol, int, 0);
-MODULE_LICENSE("GPL");
-
-// ----------------------------------------------------------------------
-
-#define AVM_INDEX 0x04
-#define AVM_DATA 0x10
-
-#define AVM_IDX_HDLC_1 0x00
-#define AVM_IDX_HDLC_2 0x01
-#define AVM_IDX_ISAC_FIFO 0x02
-#define AVM_IDX_ISAC_REG_LOW 0x04
-#define AVM_IDX_ISAC_REG_HIGH 0x06
-
-#define AVM_STATUS0 0x02
-
-#define AVM_STATUS0_IRQ_ISAC 0x01
-#define AVM_STATUS0_IRQ_HDLC 0x02
-#define AVM_STATUS0_IRQ_TIMER 0x04
-#define AVM_STATUS0_IRQ_MASK 0x07
-
-#define AVM_STATUS0_RESET 0x01
-#define AVM_STATUS0_DIS_TIMER 0x02
-#define AVM_STATUS0_RES_TIMER 0x04
-#define AVM_STATUS0_ENA_IRQ 0x08
-#define AVM_STATUS0_TESTBIT 0x10
-
-#define AVM_STATUS1 0x03
-#define AVM_STATUS1_ENA_IOM 0x80
-
-#define HDLC_FIFO 0x0
-#define HDLC_STATUS 0x4
-#define HDLC_CTRL 0x4
-
-#define HDLC_MODE_ITF_FLG 0x01
-#define HDLC_MODE_TRANS 0x02
-#define HDLC_MODE_CCR_7 0x04
-#define HDLC_MODE_CCR_16 0x08
-#define HDLC_MODE_TESTLOOP 0x80
-
-#define HDLC_INT_XPR 0x80
-#define HDLC_INT_XDU 0x40
-#define HDLC_INT_RPR 0x20
-#define HDLC_INT_MASK 0xE0
-
-#define HDLC_STAT_RME 0x01
-#define HDLC_STAT_RDO 0x10
-#define HDLC_STAT_CRCVFRRAB 0x0E
-#define HDLC_STAT_CRCVFR 0x06
-#define HDLC_STAT_RML_MASK 0xff00
-
-#define HDLC_CMD_XRS 0x80
-#define HDLC_CMD_XME 0x01
-#define HDLC_CMD_RRS 0x20
-#define HDLC_CMD_XML_MASK 0xff00
-
-#define AVM_HDLC_FIFO_1 0x10
-#define AVM_HDLC_FIFO_2 0x18
-
-#define AVM_HDLC_STATUS_1 0x14
-#define AVM_HDLC_STATUS_2 0x1c
-
-#define AVM_ISACSX_INDEX 0x04
-#define AVM_ISACSX_DATA 0x08
-
-// ----------------------------------------------------------------------
-// Fritz!PCI
-
-static unsigned char fcpci_read_isac(struct isac *isac, unsigned char offset)
-{
- struct fritz_adapter *adapter = isac->priv;
- unsigned char idx = (offset > 0x2f) ?
- AVM_IDX_ISAC_REG_HIGH : AVM_IDX_ISAC_REG_LOW;
- unsigned char val;
- unsigned long flags;
-
- spin_lock_irqsave(&adapter->hw_lock, flags);
- outb(idx, adapter->io + AVM_INDEX);
- val = inb(adapter->io + AVM_DATA + (offset & 0xf));
- spin_unlock_irqrestore(&adapter->hw_lock, flags);
- DBG(0x1000, " port %#x, value %#x",
- offset, val);
- return val;
-}
-
-static void fcpci_write_isac(struct isac *isac, unsigned char offset,
- unsigned char value)
-{
- struct fritz_adapter *adapter = isac->priv;
- unsigned char idx = (offset > 0x2f) ?
- AVM_IDX_ISAC_REG_HIGH : AVM_IDX_ISAC_REG_LOW;
- unsigned long flags;
-
- DBG(0x1000, " port %#x, value %#x",
- offset, value);
- spin_lock_irqsave(&adapter->hw_lock, flags);
- outb(idx, adapter->io + AVM_INDEX);
- outb(value, adapter->io + AVM_DATA + (offset & 0xf));
- spin_unlock_irqrestore(&adapter->hw_lock, flags);
-}
-
-static void fcpci_read_isac_fifo(struct isac *isac, unsigned char *data,
- int size)
-{
- struct fritz_adapter *adapter = isac->priv;
- unsigned long flags;
-
- spin_lock_irqsave(&adapter->hw_lock, flags);
- outb(AVM_IDX_ISAC_FIFO, adapter->io + AVM_INDEX);
- insb(adapter->io + AVM_DATA, data, size);
- spin_unlock_irqrestore(&adapter->hw_lock, flags);
-}
-
-static void fcpci_write_isac_fifo(struct isac *isac, unsigned char *data,
- int size)
-{
- struct fritz_adapter *adapter = isac->priv;
- unsigned long flags;
-
- spin_lock_irqsave(&adapter->hw_lock, flags);
- outb(AVM_IDX_ISAC_FIFO, adapter->io + AVM_INDEX);
- outsb(adapter->io + AVM_DATA, data, size);
- spin_unlock_irqrestore(&adapter->hw_lock, flags);
-}
-
-static u32 fcpci_read_hdlc_status(struct fritz_adapter *adapter, int nr)
-{
- u32 val;
- int idx = nr ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1;
- unsigned long flags;
-
- spin_lock_irqsave(&adapter->hw_lock, flags);
- outl(idx, adapter->io + AVM_INDEX);
- val = inl(adapter->io + AVM_DATA + HDLC_STATUS);
- spin_unlock_irqrestore(&adapter->hw_lock, flags);
- return val;
-}
-
-static void __fcpci_write_ctrl(struct fritz_bcs *bcs, int which)
-{
- struct fritz_adapter *adapter = bcs->adapter;
- int idx = bcs->channel ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1;
-
- DBG(0x40, "hdlc %c wr%x ctrl %x",
- 'A' + bcs->channel, which, bcs->ctrl.ctrl);
-
- outl(idx, adapter->io + AVM_INDEX);
- outl(bcs->ctrl.ctrl, adapter->io + AVM_DATA + HDLC_CTRL);
-}
-
-static void fcpci_write_ctrl(struct fritz_bcs *bcs, int which)
-{
- struct fritz_adapter *adapter = bcs->adapter;
- unsigned long flags;
-
- spin_lock_irqsave(&adapter->hw_lock, flags);
- __fcpci_write_ctrl(bcs, which);
- spin_unlock_irqrestore(&adapter->hw_lock, flags);
-}
-
-// ----------------------------------------------------------------------
-// Fritz!PCI v2
-
-static unsigned char fcpci2_read_isac(struct isac *isac, unsigned char offset)
-{
- struct fritz_adapter *adapter = isac->priv;
- unsigned char val;
- unsigned long flags;
-
- spin_lock_irqsave(&adapter->hw_lock, flags);
- outl(offset, adapter->io + AVM_ISACSX_INDEX);
- val = inl(adapter->io + AVM_ISACSX_DATA);
- spin_unlock_irqrestore(&adapter->hw_lock, flags);
- DBG(0x1000, " port %#x, value %#x",
- offset, val);
-
- return val;
-}
-
-static void fcpci2_write_isac(struct isac *isac, unsigned char offset,
- unsigned char value)
-{
- struct fritz_adapter *adapter = isac->priv;
- unsigned long flags;
-
- DBG(0x1000, " port %#x, value %#x",
- offset, value);
- spin_lock_irqsave(&adapter->hw_lock, flags);
- outl(offset, adapter->io + AVM_ISACSX_INDEX);
- outl(value, adapter->io + AVM_ISACSX_DATA);
- spin_unlock_irqrestore(&adapter->hw_lock, flags);
-}
-
-static void fcpci2_read_isac_fifo(struct isac *isac, unsigned char *data,
- int size)
-{
- struct fritz_adapter *adapter = isac->priv;
- int i;
- unsigned long flags;
-
- spin_lock_irqsave(&adapter->hw_lock, flags);
- outl(0, adapter->io + AVM_ISACSX_INDEX);
- for (i = 0; i < size; i++)
- data[i] = inl(adapter->io + AVM_ISACSX_DATA);
- spin_unlock_irqrestore(&adapter->hw_lock, flags);
-}
-
-static void fcpci2_write_isac_fifo(struct isac *isac, unsigned char *data,
- int size)
-{
- struct fritz_adapter *adapter = isac->priv;
- int i;
- unsigned long flags;
-
- spin_lock_irqsave(&adapter->hw_lock, flags);
- outl(0, adapter->io + AVM_ISACSX_INDEX);
- for (i = 0; i < size; i++)
- outl(data[i], adapter->io + AVM_ISACSX_DATA);
- spin_unlock_irqrestore(&adapter->hw_lock, flags);
-}
-
-static u32 fcpci2_read_hdlc_status(struct fritz_adapter *adapter, int nr)
-{
- int offset = nr ? AVM_HDLC_STATUS_2 : AVM_HDLC_STATUS_1;
-
- return inl(adapter->io + offset);
-}
-
-static void fcpci2_write_ctrl(struct fritz_bcs *bcs, int which)
-{
- struct fritz_adapter *adapter = bcs->adapter;
- int offset = bcs->channel ? AVM_HDLC_STATUS_2 : AVM_HDLC_STATUS_1;
-
- DBG(0x40, "hdlc %c wr%x ctrl %x",
- 'A' + bcs->channel, which, bcs->ctrl.ctrl);
-
- outl(bcs->ctrl.ctrl, adapter->io + offset);
-}
-
-// ----------------------------------------------------------------------
-// Fritz!PnP (ISAC access as for Fritz!PCI)
-
-static u32 fcpnp_read_hdlc_status(struct fritz_adapter *adapter, int nr)
-{
- unsigned char idx = nr ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1;
- u32 val;
- unsigned long flags;
-
- spin_lock_irqsave(&adapter->hw_lock, flags);
- outb(idx, adapter->io + AVM_INDEX);
- val = inb(adapter->io + AVM_DATA + HDLC_STATUS);
- if (val & HDLC_INT_RPR)
- val |= inb(adapter->io + AVM_DATA + HDLC_STATUS + 1) << 8;
- spin_unlock_irqrestore(&adapter->hw_lock, flags);
- return val;
-}
-
-static void __fcpnp_write_ctrl(struct fritz_bcs *bcs, int which)
-{
- struct fritz_adapter *adapter = bcs->adapter;
- unsigned char idx = bcs->channel ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1;
-
- DBG(0x40, "hdlc %c wr%x ctrl %x",
- 'A' + bcs->channel, which, bcs->ctrl.ctrl);
-
- outb(idx, adapter->io + AVM_INDEX);
- if (which & 4)
- outb(bcs->ctrl.sr.mode,
- adapter->io + AVM_DATA + HDLC_STATUS + 2);
- if (which & 2)
- outb(bcs->ctrl.sr.xml,
- adapter->io + AVM_DATA + HDLC_STATUS + 1);
- if (which & 1)
- outb(bcs->ctrl.sr.cmd,
- adapter->io + AVM_DATA + HDLC_STATUS + 0);
-}
-
-static void fcpnp_write_ctrl(struct fritz_bcs *bcs, int which)
-{
- struct fritz_adapter *adapter = bcs->adapter;
- unsigned long flags;
-
- spin_lock_irqsave(&adapter->hw_lock, flags);
- __fcpnp_write_ctrl(bcs, which);
- spin_unlock_irqrestore(&adapter->hw_lock, flags);
-}
-
-// ----------------------------------------------------------------------
-
-static inline void B_L1L2(struct fritz_bcs *bcs, int pr, void *arg)
-{
- struct hisax_if *ifc = (struct hisax_if *) &bcs->b_if;
-
- DBG(2, "pr %#x", pr);
- ifc->l1l2(ifc, pr, arg);
-}
-
-static void hdlc_fill_fifo(struct fritz_bcs *bcs)
-{
- struct fritz_adapter *adapter = bcs->adapter;
- struct sk_buff *skb = bcs->tx_skb;
- int count;
- unsigned long flags;
- unsigned char *p;
-
- DBG(0x40, "hdlc_fill_fifo");
-
- BUG_ON(skb->len == 0);
-
- bcs->ctrl.sr.cmd &= ~HDLC_CMD_XME;
- if (bcs->tx_skb->len > bcs->fifo_size) {
- count = bcs->fifo_size;
- } else {
- count = bcs->tx_skb->len;
- if (bcs->mode != L1_MODE_TRANS)
- bcs->ctrl.sr.cmd |= HDLC_CMD_XME;
- }
- DBG(0x40, "hdlc_fill_fifo %d/%d", count, bcs->tx_skb->len);
- p = bcs->tx_skb->data;
- skb_pull(bcs->tx_skb, count);
- bcs->tx_cnt += count;
- bcs->ctrl.sr.xml = ((count == bcs->fifo_size) ? 0 : count);
-
- switch (adapter->type) {
- case AVM_FRITZ_PCI:
- spin_lock_irqsave(&adapter->hw_lock, flags);
- // sets the correct AVM_INDEX, too
- __fcpci_write_ctrl(bcs, 3);
- outsl(adapter->io + AVM_DATA + HDLC_FIFO,
- p, (count + 3) / 4);
- spin_unlock_irqrestore(&adapter->hw_lock, flags);
- break;
- case AVM_FRITZ_PCIV2:
- fcpci2_write_ctrl(bcs, 3);
- outsl(adapter->io +
- (bcs->channel ? AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1),
- p, (count + 3) / 4);
- break;
- case AVM_FRITZ_PNP:
- spin_lock_irqsave(&adapter->hw_lock, flags);
- // sets the correct AVM_INDEX, too
- __fcpnp_write_ctrl(bcs, 3);
- outsb(adapter->io + AVM_DATA, p, count);
- spin_unlock_irqrestore(&adapter->hw_lock, flags);
- break;
- }
-}
-
-static inline void hdlc_empty_fifo(struct fritz_bcs *bcs, int count)
-{
- struct fritz_adapter *adapter = bcs->adapter;
- unsigned char *p;
- unsigned char idx = bcs->channel ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1;
-
- DBG(0x10, "hdlc_empty_fifo %d", count);
- if (bcs->rcvidx + count > HSCX_BUFMAX) {
- DBG(0x10, "hdlc_empty_fifo: incoming packet too large");
- return;
- }
- p = bcs->rcvbuf + bcs->rcvidx;
- bcs->rcvidx += count;
- switch (adapter->type) {
- case AVM_FRITZ_PCI:
- spin_lock(&adapter->hw_lock);
- outl(idx, adapter->io + AVM_INDEX);
- insl(adapter->io + AVM_DATA + HDLC_FIFO,
- p, (count + 3) / 4);
- spin_unlock(&adapter->hw_lock);
- break;
- case AVM_FRITZ_PCIV2:
- insl(adapter->io +
- (bcs->channel ? AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1),
- p, (count + 3) / 4);
- break;
- case AVM_FRITZ_PNP:
- spin_lock(&adapter->hw_lock);
- outb(idx, adapter->io + AVM_INDEX);
- insb(adapter->io + AVM_DATA, p, count);
- spin_unlock(&adapter->hw_lock);
- break;
- }
-}
-
-static inline void hdlc_rpr_irq(struct fritz_bcs *bcs, u32 stat)
-{
- struct fritz_adapter *adapter = bcs->adapter;
- struct sk_buff *skb;
- int len;
-
- if (stat & HDLC_STAT_RDO) {
- DBG(0x10, "RDO");
- bcs->ctrl.sr.xml = 0;
- bcs->ctrl.sr.cmd |= HDLC_CMD_RRS;
- adapter->write_ctrl(bcs, 1);
- bcs->ctrl.sr.cmd &= ~HDLC_CMD_RRS;
- adapter->write_ctrl(bcs, 1);
- bcs->rcvidx = 0;
- return;
- }
-
- len = (stat & HDLC_STAT_RML_MASK) >> 8;
- if (len == 0)
- len = bcs->fifo_size;
-
- hdlc_empty_fifo(bcs, len);
-
- if ((stat & HDLC_STAT_RME) || (bcs->mode == L1_MODE_TRANS)) {
- if (((stat & HDLC_STAT_CRCVFRRAB) == HDLC_STAT_CRCVFR) ||
- (bcs->mode == L1_MODE_TRANS)) {
- skb = dev_alloc_skb(bcs->rcvidx);
- if (!skb) {
- printk(KERN_WARNING "HDLC: receive out of memory\n");
- } else {
- skb_put_data(skb, bcs->rcvbuf, bcs->rcvidx);
- DBG_SKB(1, skb);
- B_L1L2(bcs, PH_DATA | INDICATION, skb);
- }
- bcs->rcvidx = 0;
- } else {
- DBG(0x10, "ch%d invalid frame %#x",
- bcs->channel, stat);
- bcs->rcvidx = 0;
- }
- }
-}
-
-static inline void hdlc_xdu_irq(struct fritz_bcs *bcs)
-{
- struct fritz_adapter *adapter = bcs->adapter;
-
-
- /* Here we lost an TX interrupt, so
- * restart transmitting the whole frame.
- */
- bcs->ctrl.sr.xml = 0;
- bcs->ctrl.sr.cmd |= HDLC_CMD_XRS;
- adapter->write_ctrl(bcs, 1);
- bcs->ctrl.sr.cmd &= ~HDLC_CMD_XRS;
-
- if (!bcs->tx_skb) {
- DBG(0x10, "XDU without skb");
- adapter->write_ctrl(bcs, 1);
- return;
- }
- /* only hdlc restarts the frame, transparent mode must continue */
- if (bcs->mode == L1_MODE_HDLC) {
- skb_push(bcs->tx_skb, bcs->tx_cnt);
- bcs->tx_cnt = 0;
- }
-}
-
-static inline void hdlc_xpr_irq(struct fritz_bcs *bcs)
-{
- struct sk_buff *skb;
-
- skb = bcs->tx_skb;
- if (!skb)
- return;
-
- if (skb->len) {
- hdlc_fill_fifo(bcs);
- return;
- }
- bcs->tx_cnt = 0;
- bcs->tx_skb = NULL;
- B_L1L2(bcs, PH_DATA | CONFIRM, (void *)(unsigned long)skb->truesize);
- dev_kfree_skb_irq(skb);
-}
-
-static void hdlc_irq_one(struct fritz_bcs *bcs, u32 stat)
-{
- DBG(0x10, "ch%d stat %#x", bcs->channel, stat);
- if (stat & HDLC_INT_RPR) {
- DBG(0x10, "RPR");
- hdlc_rpr_irq(bcs, stat);
- }
- if (stat & HDLC_INT_XDU) {
- DBG(0x10, "XDU");
- hdlc_xdu_irq(bcs);
- hdlc_xpr_irq(bcs);
- return;
- }
- if (stat & HDLC_INT_XPR) {
- DBG(0x10, "XPR");
- hdlc_xpr_irq(bcs);
- }
-}
-
-static inline void hdlc_irq(struct fritz_adapter *adapter)
-{
- int nr;
- u32 stat;
-
- for (nr = 0; nr < 2; nr++) {
- stat = adapter->read_hdlc_status(adapter, nr);
- DBG(0x10, "HDLC %c stat %#x", 'A' + nr, stat);
- if (stat & HDLC_INT_MASK)
- hdlc_irq_one(&adapter->bcs[nr], stat);
- }
-}
-
-static void modehdlc(struct fritz_bcs *bcs, int mode)
-{
- struct fritz_adapter *adapter = bcs->adapter;
-
- DBG(0x40, "hdlc %c mode %d --> %d",
- 'A' + bcs->channel, bcs->mode, mode);
-
- if (bcs->mode == mode)
- return;
-
- bcs->fifo_size = 32;
- bcs->ctrl.ctrl = 0;
- bcs->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
- switch (mode) {
- case L1_MODE_NULL:
- bcs->ctrl.sr.mode = HDLC_MODE_TRANS;
- adapter->write_ctrl(bcs, 5);
- break;
- case L1_MODE_TRANS:
- case L1_MODE_HDLC:
- bcs->rcvidx = 0;
- bcs->tx_cnt = 0;
- bcs->tx_skb = NULL;
- if (mode == L1_MODE_TRANS) {
- bcs->ctrl.sr.mode = HDLC_MODE_TRANS;
- } else {
- bcs->ctrl.sr.mode = HDLC_MODE_ITF_FLG;
- }
- adapter->write_ctrl(bcs, 5);
- bcs->ctrl.sr.cmd = HDLC_CMD_XRS;
- adapter->write_ctrl(bcs, 1);
- bcs->ctrl.sr.cmd = 0;
- break;
- }
- bcs->mode = mode;
-}
-
-static void fritz_b_l2l1(struct hisax_if *ifc, int pr, void *arg)
-{
- struct fritz_bcs *bcs = ifc->priv;
- struct sk_buff *skb = arg;
- int mode;
-
- DBG(0x10, "pr %#x", pr);
-
- switch (pr) {
- case PH_DATA | REQUEST:
- BUG_ON(bcs->tx_skb);
- bcs->tx_skb = skb;
- DBG_SKB(1, skb);
- hdlc_fill_fifo(bcs);
- break;
- case PH_ACTIVATE | REQUEST:
- mode = (long) arg;
- DBG(4, "B%d,PH_ACTIVATE_REQUEST %d", bcs->channel + 1, mode);
- modehdlc(bcs, mode);
- B_L1L2(bcs, PH_ACTIVATE | INDICATION, NULL);
- break;
- case PH_DEACTIVATE | REQUEST:
- DBG(4, "B%d,PH_DEACTIVATE_REQUEST", bcs->channel + 1);
- modehdlc(bcs, L1_MODE_NULL);
- B_L1L2(bcs, PH_DEACTIVATE | INDICATION, NULL);
- break;
- }
-}
-
-// ----------------------------------------------------------------------
-
-static irqreturn_t
-fcpci2_irq(int intno, void *dev)
-{
- struct fritz_adapter *adapter = dev;
- unsigned char val;
-
- val = inb(adapter->io + AVM_STATUS0);
- if (!(val & AVM_STATUS0_IRQ_MASK))
- /* hopefully a shared IRQ reqest */
- return IRQ_NONE;
- DBG(2, "STATUS0 %#x", val);
- if (val & AVM_STATUS0_IRQ_ISAC)
- isacsx_irq(&adapter->isac);
- if (val & AVM_STATUS0_IRQ_HDLC)
- hdlc_irq(adapter);
- if (val & AVM_STATUS0_IRQ_ISAC)
- isacsx_irq(&adapter->isac);
- return IRQ_HANDLED;
-}
-
-static irqreturn_t
-fcpci_irq(int intno, void *dev)
-{
- struct fritz_adapter *adapter = dev;
- unsigned char sval;
-
- sval = inb(adapter->io + 2);
- if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK)
- /* possibly a shared IRQ reqest */
- return IRQ_NONE;
- DBG(2, "sval %#x", sval);
- if (!(sval & AVM_STATUS0_IRQ_ISAC))
- isac_irq(&adapter->isac);
-
- if (!(sval & AVM_STATUS0_IRQ_HDLC))
- hdlc_irq(adapter);
- return IRQ_HANDLED;
-}
-
-// ----------------------------------------------------------------------
-
-static inline void fcpci2_init(struct fritz_adapter *adapter)
-{
- outb(AVM_STATUS0_RES_TIMER, adapter->io + AVM_STATUS0);
- outb(AVM_STATUS0_ENA_IRQ, adapter->io + AVM_STATUS0);
-
-}
-
-static inline void fcpci_init(struct fritz_adapter *adapter)
-{
- outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER |
- AVM_STATUS0_ENA_IRQ, adapter->io + AVM_STATUS0);
-
- outb(AVM_STATUS1_ENA_IOM | adapter->irq,
- adapter->io + AVM_STATUS1);
- mdelay(10);
-}
-
-// ----------------------------------------------------------------------
-
-static int fcpcipnp_setup(struct fritz_adapter *adapter)
-{
- u32 val = 0;
- int retval;
-
- DBG(1, "");
-
- isac_init(&adapter->isac); // FIXME is this okay now
-
- retval = -EBUSY;
- if (!request_region(adapter->io, 32, "fcpcipnp"))
- goto err;
-
- switch (adapter->type) {
- case AVM_FRITZ_PCIV2:
- case AVM_FRITZ_PCI:
- val = inl(adapter->io);
- break;
- case AVM_FRITZ_PNP:
- val = inb(adapter->io);
- val |= inb(adapter->io + 1) << 8;
- break;
- }
-
- DBG(1, "stat %#x Class %X Rev %d",
- val, val & 0xff, (val >> 8) & 0xff);
-
- spin_lock_init(&adapter->hw_lock);
- adapter->isac.priv = adapter;
- switch (adapter->type) {
- case AVM_FRITZ_PCIV2:
- adapter->isac.read_isac = &fcpci2_read_isac;
- adapter->isac.write_isac = &fcpci2_write_isac;
- adapter->isac.read_isac_fifo = &fcpci2_read_isac_fifo;
- adapter->isac.write_isac_fifo = &fcpci2_write_isac_fifo;
-
- adapter->read_hdlc_status = &fcpci2_read_hdlc_status;
- adapter->write_ctrl = &fcpci2_write_ctrl;
- break;
- case AVM_FRITZ_PCI:
- adapter->isac.read_isac = &fcpci_read_isac;
- adapter->isac.write_isac = &fcpci_write_isac;
- adapter->isac.read_isac_fifo = &fcpci_read_isac_fifo;
- adapter->isac.write_isac_fifo = &fcpci_write_isac_fifo;
-
- adapter->read_hdlc_status = &fcpci_read_hdlc_status;
- adapter->write_ctrl = &fcpci_write_ctrl;
- break;
- case AVM_FRITZ_PNP:
- adapter->isac.read_isac = &fcpci_read_isac;
- adapter->isac.write_isac = &fcpci_write_isac;
- adapter->isac.read_isac_fifo = &fcpci_read_isac_fifo;
- adapter->isac.write_isac_fifo = &fcpci_write_isac_fifo;
-
- adapter->read_hdlc_status = &fcpnp_read_hdlc_status;
- adapter->write_ctrl = &fcpnp_write_ctrl;
- break;
- }
-
- // Reset
- outb(0, adapter->io + AVM_STATUS0);
- mdelay(10);
- outb(AVM_STATUS0_RESET, adapter->io + AVM_STATUS0);
- mdelay(10);
- outb(0, adapter->io + AVM_STATUS0);
- mdelay(10);
-
- switch (adapter->type) {
- case AVM_FRITZ_PCIV2:
- retval = request_irq(adapter->irq, fcpci2_irq, IRQF_SHARED,
- "fcpcipnp", adapter);
- break;
- case AVM_FRITZ_PCI:
- retval = request_irq(adapter->irq, fcpci_irq, IRQF_SHARED,
- "fcpcipnp", adapter);
- break;
- case AVM_FRITZ_PNP:
- retval = request_irq(adapter->irq, fcpci_irq, 0,
- "fcpcipnp", adapter);
- break;
- }
- if (retval)
- goto err_region;
-
- switch (adapter->type) {
- case AVM_FRITZ_PCIV2:
- fcpci2_init(adapter);
- isacsx_setup(&adapter->isac);
- break;
- case AVM_FRITZ_PCI:
- case AVM_FRITZ_PNP:
- fcpci_init(adapter);
- isac_setup(&adapter->isac);
- break;
- }
- val = adapter->read_hdlc_status(adapter, 0);
- DBG(0x20, "HDLC A STA %x", val);
- val = adapter->read_hdlc_status(adapter, 1);
- DBG(0x20, "HDLC B STA %x", val);
-
- adapter->bcs[0].mode = -1;
- adapter->bcs[1].mode = -1;
- modehdlc(&adapter->bcs[0], L1_MODE_NULL);
- modehdlc(&adapter->bcs[1], L1_MODE_NULL);
-
- return 0;
-
-err_region:
- release_region(adapter->io, 32);
-err:
- return retval;
-}
-
-static void fcpcipnp_release(struct fritz_adapter *adapter)
-{
- DBG(1, "");
-
- outb(0, adapter->io + AVM_STATUS0);
- free_irq(adapter->irq, adapter);
- release_region(adapter->io, 32);
-}
-
-// ----------------------------------------------------------------------
-
-static struct fritz_adapter *new_adapter(void)
-{
- struct fritz_adapter *adapter;
- struct hisax_b_if *b_if[2];
- int i;
-
- adapter = kzalloc(sizeof(struct fritz_adapter), GFP_KERNEL);
- if (!adapter)
- return NULL;
-
- adapter->isac.hisax_d_if.owner = THIS_MODULE;
- adapter->isac.hisax_d_if.ifc.priv = &adapter->isac;
- adapter->isac.hisax_d_if.ifc.l2l1 = isac_d_l2l1;
-
- for (i = 0; i < 2; i++) {
- adapter->bcs[i].adapter = adapter;
- adapter->bcs[i].channel = i;
- adapter->bcs[i].b_if.ifc.priv = &adapter->bcs[i];
- adapter->bcs[i].b_if.ifc.l2l1 = fritz_b_l2l1;
- }
-
- for (i = 0; i < 2; i++)
- b_if[i] = &adapter->bcs[i].b_if;
-
- if (hisax_register(&adapter->isac.hisax_d_if, b_if, "fcpcipnp",
- protocol) != 0) {
- kfree(adapter);
- adapter = NULL;
- }
-
- return adapter;
-}
-
-static void delete_adapter(struct fritz_adapter *adapter)
-{
- hisax_unregister(&adapter->isac.hisax_d_if);
- kfree(adapter);
-}
-
-static int fcpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- struct fritz_adapter *adapter;
- int retval;
-
- retval = -ENOMEM;
- adapter = new_adapter();
- if (!adapter)
- goto err;
-
- pci_set_drvdata(pdev, adapter);
-
- if (pdev->device == PCI_DEVICE_ID_AVM_A1_V2)
- adapter->type = AVM_FRITZ_PCIV2;
- else
- adapter->type = AVM_FRITZ_PCI;
-
- retval = pci_enable_device(pdev);
- if (retval)
- goto err_free;
-
- adapter->io = pci_resource_start(pdev, 1);
- adapter->irq = pdev->irq;
-
- printk(KERN_INFO "hisax_fcpcipnp: found adapter %s at %s\n",
- (char *) ent->driver_data, pci_name(pdev));
-
- retval = fcpcipnp_setup(adapter);
- if (retval)
- goto err_free;
-
- return 0;
-
-err_free:
- delete_adapter(adapter);
-err:
- return retval;
-}
-
-#ifdef CONFIG_PNP
-static int fcpnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
-{
- struct fritz_adapter *adapter;
- int retval;
-
- if (!pdev)
- return (-ENODEV);
-
- retval = -ENOMEM;
- adapter = new_adapter();
- if (!adapter)
- goto err;
-
- pnp_set_drvdata(pdev, adapter);
-
- adapter->type = AVM_FRITZ_PNP;
-
- pnp_disable_dev(pdev);
- retval = pnp_activate_dev(pdev);
- if (retval < 0) {
- printk(KERN_WARNING "%s: pnp_activate_dev(%s) ret(%d)\n", __func__,
- (char *)dev_id->driver_data, retval);
- goto err_free;
- }
- adapter->io = pnp_port_start(pdev, 0);
- adapter->irq = pnp_irq(pdev, 0);
- if (!adapter->io || adapter->irq == -1)
- goto err_free;
-
- printk(KERN_INFO "hisax_fcpcipnp: found adapter %s at IO %#x irq %d\n",
- (char *) dev_id->driver_data, adapter->io, adapter->irq);
-
- retval = fcpcipnp_setup(adapter);
- if (retval)
- goto err_free;
-
- return 0;
-
-err_free:
- delete_adapter(adapter);
-err:
- return retval;
-}
-
-static void fcpnp_remove(struct pnp_dev *pdev)
-{
- struct fritz_adapter *adapter = pnp_get_drvdata(pdev);
-
- if (adapter) {
- fcpcipnp_release(adapter);
- delete_adapter(adapter);
- }
- pnp_disable_dev(pdev);
-}
-
-static struct pnp_driver fcpnp_driver = {
- .name = "fcpnp",
- .probe = fcpnp_probe,
- .remove = fcpnp_remove,
- .id_table = fcpnp_ids,
-};
-#endif
-
-static void fcpci_remove(struct pci_dev *pdev)
-{
- struct fritz_adapter *adapter = pci_get_drvdata(pdev);
-
- fcpcipnp_release(adapter);
- pci_disable_device(pdev);
- delete_adapter(adapter);
-}
-
-static struct pci_driver fcpci_driver = {
- .name = "fcpci",
- .probe = fcpci_probe,
- .remove = fcpci_remove,
- .id_table = fcpci_ids,
-};
-
-static int __init hisax_fcpcipnp_init(void)
-{
- int retval;
-
- printk(KERN_INFO "hisax_fcpcipnp: Fritz!Card PCI/PCIv2/PnP ISDN driver v0.0.1\n");
-
- retval = pci_register_driver(&fcpci_driver);
- if (retval)
- return retval;
-#ifdef CONFIG_PNP
- retval = pnp_register_driver(&fcpnp_driver);
- if (retval < 0) {
- pci_unregister_driver(&fcpci_driver);
- return retval;
- }
-#endif
- return 0;
-}
-
-static void __exit hisax_fcpcipnp_exit(void)
-{
-#ifdef CONFIG_PNP
- pnp_unregister_driver(&fcpnp_driver);
-#endif
- pci_unregister_driver(&fcpci_driver);
-}
-
-module_init(hisax_fcpcipnp_init);
-module_exit(hisax_fcpcipnp_exit);
diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.h b/drivers/isdn/hisax/hisax_fcpcipnp.h
deleted file mode 100644
index 1f64e9937aa1..000000000000
--- a/drivers/isdn/hisax/hisax_fcpcipnp.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#include "hisax_if.h"
-#include "hisax_isac.h"
-#include <linux/pci.h>
-
-#define HSCX_BUFMAX 4096
-
-enum {
- AVM_FRITZ_PCI,
- AVM_FRITZ_PNP,
- AVM_FRITZ_PCIV2,
-};
-
-struct hdlc_stat_reg {
-#ifdef __BIG_ENDIAN
- u_char fill;
- u_char mode;
- u_char xml;
- u_char cmd;
-#else
- u_char cmd;
- u_char xml;
- u_char mode;
- u_char fill;
-#endif
-} __attribute__((packed));
-
-struct fritz_bcs {
- struct hisax_b_if b_if;
- struct fritz_adapter *adapter;
- int mode;
- int channel;
-
- union {
- u_int ctrl;
- struct hdlc_stat_reg sr;
- } ctrl;
- u_int stat;
- int rcvidx;
- int fifo_size;
- u_char rcvbuf[HSCX_BUFMAX]; /* B-Channel receive Buffer */
-
- int tx_cnt; /* B-Channel transmit counter */
- struct sk_buff *tx_skb; /* B-Channel transmit Buffer */
-};
-
-struct fritz_adapter {
- int type;
- spinlock_t hw_lock;
- unsigned int io;
- unsigned int irq;
- struct isac isac;
-
- struct fritz_bcs bcs[2];
-
- u32 (*read_hdlc_status) (struct fritz_adapter *adapter, int nr);
- void (*write_ctrl) (struct fritz_bcs *bcs, int which);
-};
diff --git a/drivers/isdn/hisax/hisax_if.h b/drivers/isdn/hisax/hisax_if.h
deleted file mode 100644
index 7098d6bd5ff2..000000000000
--- a/drivers/isdn/hisax/hisax_if.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Interface between low level (hardware) drivers and
- * HiSax protocol stack
- *
- * Author Kai Germaschewski
- * Copyright 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef __HISAX_IF_H__
-#define __HISAX_IF_H__
-
-#include <linux/skbuff.h>
-
-#define REQUEST 0
-#define CONFIRM 1
-#define INDICATION 2
-#define RESPONSE 3
-
-#define PH_ACTIVATE 0x0100
-#define PH_DEACTIVATE 0x0110
-#define PH_DATA 0x0120
-#define PH_PULL 0x0130
-#define PH_DATA_E 0x0140
-
-#define L1_MODE_NULL 0
-#define L1_MODE_TRANS 1
-#define L1_MODE_HDLC 2
-#define L1_MODE_EXTRN 3
-#define L1_MODE_HDLC_56K 4
-#define L1_MODE_MODEM 7
-#define L1_MODE_V32 8
-#define L1_MODE_FAX 9
-
-struct hisax_if {
- void *priv; // private to driver
- void (*l1l2)(struct hisax_if *, int pr, void *arg);
- void (*l2l1)(struct hisax_if *, int pr, void *arg);
-};
-
-struct hisax_b_if {
- struct hisax_if ifc;
-
- // private to hisax
- struct BCState *bcs;
-};
-
-struct hisax_d_if {
- struct hisax_if ifc;
-
- // private to hisax
- struct module *owner;
- struct IsdnCardState *cs;
- struct hisax_b_if *b_if[2];
- struct sk_buff_head erq;
- unsigned long ph_state;
-};
-
-int hisax_register(struct hisax_d_if *hisax_if, struct hisax_b_if *b_if[],
- char *name, int protocol);
-void hisax_unregister(struct hisax_d_if *hisax_if);
-
-#endif
diff --git a/drivers/isdn/hisax/hisax_isac.c b/drivers/isdn/hisax/hisax_isac.c
deleted file mode 100644
index 0f36375478c5..000000000000
--- a/drivers/isdn/hisax/hisax_isac.c
+++ /dev/null
@@ -1,895 +0,0 @@
-/*
- * Driver for ISAC-S and ISAC-SX
- * ISDN Subscriber Access Controller for Terminals
- *
- * Author Kai Germaschewski
- * Copyright 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
- * 2001 by Karsten Keil <keil@isdn4linux.de>
- *
- * based upon Karsten Keil's original isac.c driver
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Thanks to Wizard Computersysteme GmbH, Bremervoerde and
- * SoHaNet Technology GmbH, Berlin
- * for supporting the development of this driver
- */
-
-/* TODO:
- * specifically handle level vs edge triggered?
- */
-
-#include <linux/module.h>
-#include <linux/gfp.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include "hisax_isac.h"
-
-// debugging cruft
-
-#define __debug_variable debug
-#include "hisax_debug.h"
-
-#ifdef CONFIG_HISAX_DEBUG
-static int debug = 1;
-module_param(debug, int, 0);
-
-static char *ISACVer[] = {
- "2086/2186 V1.1",
- "2085 B1",
- "2085 B2",
- "2085 V2.3"
-};
-#endif
-
-MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>");
-MODULE_DESCRIPTION("ISAC/ISAC-SX driver");
-MODULE_LICENSE("GPL");
-
-#define DBG_WARN 0x0001
-#define DBG_IRQ 0x0002
-#define DBG_L1M 0x0004
-#define DBG_PR 0x0008
-#define DBG_RFIFO 0x0100
-#define DBG_RPACKET 0x0200
-#define DBG_XFIFO 0x1000
-#define DBG_XPACKET 0x2000
-
-// we need to distinguish ISAC-S and ISAC-SX
-#define TYPE_ISAC 0x00
-#define TYPE_ISACSX 0x01
-
-// registers etc.
-#define ISAC_MASK 0x20
-#define ISAC_ISTA 0x20
-#define ISAC_ISTA_EXI 0x01
-#define ISAC_ISTA_SIN 0x02
-#define ISAC_ISTA_CISQ 0x04
-#define ISAC_ISTA_XPR 0x10
-#define ISAC_ISTA_RSC 0x20
-#define ISAC_ISTA_RPF 0x40
-#define ISAC_ISTA_RME 0x80
-
-#define ISAC_STAR 0x21
-#define ISAC_CMDR 0x21
-#define ISAC_CMDR_XRES 0x01
-#define ISAC_CMDR_XME 0x02
-#define ISAC_CMDR_XTF 0x08
-#define ISAC_CMDR_RRES 0x40
-#define ISAC_CMDR_RMC 0x80
-
-#define ISAC_EXIR 0x24
-#define ISAC_EXIR_MOS 0x04
-#define ISAC_EXIR_XDU 0x40
-#define ISAC_EXIR_XMR 0x80
-
-#define ISAC_ADF2 0x39
-#define ISAC_SPCR 0x30
-#define ISAC_ADF1 0x38
-
-#define ISAC_CIR0 0x31
-#define ISAC_CIX0 0x31
-#define ISAC_CIR0_CIC0 0x02
-#define ISAC_CIR0_CIC1 0x01
-
-#define ISAC_CIR1 0x33
-#define ISAC_CIX1 0x33
-#define ISAC_STCR 0x37
-#define ISAC_MODE 0x22
-
-#define ISAC_RSTA 0x27
-#define ISAC_RSTA_RDO 0x40
-#define ISAC_RSTA_CRC 0x20
-#define ISAC_RSTA_RAB 0x10
-
-#define ISAC_RBCL 0x25
-#define ISAC_RBCH 0x2A
-#define ISAC_TIMR 0x23
-#define ISAC_SQXR 0x3b
-#define ISAC_MOSR 0x3a
-#define ISAC_MOCR 0x3a
-#define ISAC_MOR0 0x32
-#define ISAC_MOX0 0x32
-#define ISAC_MOR1 0x34
-#define ISAC_MOX1 0x34
-
-#define ISAC_RBCH_XAC 0x80
-
-#define ISAC_CMD_TIM 0x0
-#define ISAC_CMD_RES 0x1
-#define ISAC_CMD_SSP 0x2
-#define ISAC_CMD_SCP 0x3
-#define ISAC_CMD_AR8 0x8
-#define ISAC_CMD_AR10 0x9
-#define ISAC_CMD_ARL 0xa
-#define ISAC_CMD_DI 0xf
-
-#define ISACSX_MASK 0x60
-#define ISACSX_ISTA 0x60
-#define ISACSX_ISTA_ICD 0x01
-#define ISACSX_ISTA_CIC 0x10
-
-#define ISACSX_MASKD 0x20
-#define ISACSX_ISTAD 0x20
-#define ISACSX_ISTAD_XDU 0x04
-#define ISACSX_ISTAD_XMR 0x08
-#define ISACSX_ISTAD_XPR 0x10
-#define ISACSX_ISTAD_RFO 0x20
-#define ISACSX_ISTAD_RPF 0x40
-#define ISACSX_ISTAD_RME 0x80
-
-#define ISACSX_CMDRD 0x21
-#define ISACSX_CMDRD_XRES 0x01
-#define ISACSX_CMDRD_XME 0x02
-#define ISACSX_CMDRD_XTF 0x08
-#define ISACSX_CMDRD_RRES 0x40
-#define ISACSX_CMDRD_RMC 0x80
-
-#define ISACSX_MODED 0x22
-
-#define ISACSX_RBCLD 0x26
-
-#define ISACSX_RSTAD 0x28
-#define ISACSX_RSTAD_RAB 0x10
-#define ISACSX_RSTAD_CRC 0x20
-#define ISACSX_RSTAD_RDO 0x40
-#define ISACSX_RSTAD_VFR 0x80
-
-#define ISACSX_CIR0 0x2e
-#define ISACSX_CIR0_CIC0 0x08
-#define ISACSX_CIX0 0x2e
-
-#define ISACSX_TR_CONF0 0x30
-
-#define ISACSX_TR_CONF2 0x32
-
-static struct Fsm l1fsm;
-
-enum {
- ST_L1_RESET,
- ST_L1_F3_PDOWN,
- ST_L1_F3_PUP,
- ST_L1_F3_PEND_DEACT,
- ST_L1_F4,
- ST_L1_F5,
- ST_L1_F6,
- ST_L1_F7,
- ST_L1_F8,
-};
-
-#define L1_STATE_COUNT (ST_L1_F8 + 1)
-
-static char *strL1State[] =
-{
- "ST_L1_RESET",
- "ST_L1_F3_PDOWN",
- "ST_L1_F3_PUP",
- "ST_L1_F3_PEND_DEACT",
- "ST_L1_F4",
- "ST_L1_F5",
- "ST_L1_F6",
- "ST_L1_F7",
- "ST_L1_F8",
-};
-
-enum {
- EV_PH_DR, // 0000
- EV_PH_RES, // 0001
- EV_PH_TMA, // 0010
- EV_PH_SLD, // 0011
- EV_PH_RSY, // 0100
- EV_PH_DR6, // 0101
- EV_PH_EI, // 0110
- EV_PH_PU, // 0111
- EV_PH_AR, // 1000
- EV_PH_9, // 1001
- EV_PH_ARL, // 1010
- EV_PH_CVR, // 1011
- EV_PH_AI8, // 1100
- EV_PH_AI10, // 1101
- EV_PH_AIL, // 1110
- EV_PH_DC, // 1111
- EV_PH_ACTIVATE_REQ,
- EV_PH_DEACTIVATE_REQ,
- EV_TIMER3,
-};
-
-#define L1_EVENT_COUNT (EV_TIMER3 + 1)
-
-static char *strL1Event[] =
-{
- "EV_PH_DR", // 0000
- "EV_PH_RES", // 0001
- "EV_PH_TMA", // 0010
- "EV_PH_SLD", // 0011
- "EV_PH_RSY", // 0100
- "EV_PH_DR6", // 0101
- "EV_PH_EI", // 0110
- "EV_PH_PU", // 0111
- "EV_PH_AR", // 1000
- "EV_PH_9", // 1001
- "EV_PH_ARL", // 1010
- "EV_PH_CVR", // 1011
- "EV_PH_AI8", // 1100
- "EV_PH_AI10", // 1101
- "EV_PH_AIL", // 1110
- "EV_PH_DC", // 1111
- "EV_PH_ACTIVATE_REQ",
- "EV_PH_DEACTIVATE_REQ",
- "EV_TIMER3",
-};
-
-static inline void D_L1L2(struct isac *isac, int pr, void *arg)
-{
- struct hisax_if *ifc = (struct hisax_if *) &isac->hisax_d_if;
-
- DBG(DBG_PR, "pr %#x", pr);
- ifc->l1l2(ifc, pr, arg);
-}
-
-static void ph_command(struct isac *isac, unsigned int command)
-{
- DBG(DBG_L1M, "ph_command %#x", command);
- switch (isac->type) {
- case TYPE_ISAC:
- isac->write_isac(isac, ISAC_CIX0, (command << 2) | 3);
- break;
- case TYPE_ISACSX:
- isac->write_isac(isac, ISACSX_CIX0, (command << 4) | (7 << 1));
- break;
- }
-}
-
-// ----------------------------------------------------------------------
-
-static void l1_di(struct FsmInst *fi, int event, void *arg)
-{
- struct isac *isac = fi->userdata;
-
- FsmChangeState(fi, ST_L1_RESET);
- ph_command(isac, ISAC_CMD_DI);
-}
-
-static void l1_di_deact_ind(struct FsmInst *fi, int event, void *arg)
-{
- struct isac *isac = fi->userdata;
-
- FsmChangeState(fi, ST_L1_RESET);
- D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
- ph_command(isac, ISAC_CMD_DI);
-}
-
-static void l1_go_f3pdown(struct FsmInst *fi, int event, void *arg)
-{
- FsmChangeState(fi, ST_L1_F3_PDOWN);
-}
-
-static void l1_go_f3pend_deact_ind(struct FsmInst *fi, int event, void *arg)
-{
- struct isac *isac = fi->userdata;
-
- FsmChangeState(fi, ST_L1_F3_PEND_DEACT);
- D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
- ph_command(isac, ISAC_CMD_DI);
-}
-
-static void l1_go_f3pend(struct FsmInst *fi, int event, void *arg)
-{
- struct isac *isac = fi->userdata;
-
- FsmChangeState(fi, ST_L1_F3_PEND_DEACT);
- ph_command(isac, ISAC_CMD_DI);
-}
-
-static void l1_go_f4(struct FsmInst *fi, int event, void *arg)
-{
- FsmChangeState(fi, ST_L1_F4);
-}
-
-static void l1_go_f5(struct FsmInst *fi, int event, void *arg)
-{
- FsmChangeState(fi, ST_L1_F5);
-}
-
-static void l1_go_f6(struct FsmInst *fi, int event, void *arg)
-{
- FsmChangeState(fi, ST_L1_F6);
-}
-
-static void l1_go_f6_deact_ind(struct FsmInst *fi, int event, void *arg)
-{
- struct isac *isac = fi->userdata;
-
- FsmChangeState(fi, ST_L1_F6);
- D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
-}
-
-static void l1_go_f7_act_ind(struct FsmInst *fi, int event, void *arg)
-{
- struct isac *isac = fi->userdata;
-
- FsmDelTimer(&isac->timer, 0);
- FsmChangeState(fi, ST_L1_F7);
- ph_command(isac, ISAC_CMD_AR8);
- D_L1L2(isac, PH_ACTIVATE | INDICATION, NULL);
-}
-
-static void l1_go_f8(struct FsmInst *fi, int event, void *arg)
-{
- FsmChangeState(fi, ST_L1_F8);
-}
-
-static void l1_go_f8_deact_ind(struct FsmInst *fi, int event, void *arg)
-{
- struct isac *isac = fi->userdata;
-
- FsmChangeState(fi, ST_L1_F8);
- D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
-}
-
-static void l1_ar8(struct FsmInst *fi, int event, void *arg)
-{
- struct isac *isac = fi->userdata;
-
- FsmRestartTimer(&isac->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
- ph_command(isac, ISAC_CMD_AR8);
-}
-
-static void l1_timer3(struct FsmInst *fi, int event, void *arg)
-{
- struct isac *isac = fi->userdata;
-
- ph_command(isac, ISAC_CMD_DI);
- D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
-}
-
-// state machines according to data sheet PSB 2186 / 3186
-
-static struct FsmNode L1FnList[] __initdata =
-{
- {ST_L1_RESET, EV_PH_RES, l1_di},
- {ST_L1_RESET, EV_PH_EI, l1_di},
- {ST_L1_RESET, EV_PH_DC, l1_go_f3pdown},
- {ST_L1_RESET, EV_PH_AR, l1_go_f6},
- {ST_L1_RESET, EV_PH_AI8, l1_go_f7_act_ind},
-
- {ST_L1_F3_PDOWN, EV_PH_RES, l1_di},
- {ST_L1_F3_PDOWN, EV_PH_EI, l1_di},
- {ST_L1_F3_PDOWN, EV_PH_AR, l1_go_f6},
- {ST_L1_F3_PDOWN, EV_PH_RSY, l1_go_f5},
- {ST_L1_F3_PDOWN, EV_PH_PU, l1_go_f4},
- {ST_L1_F3_PDOWN, EV_PH_AI8, l1_go_f7_act_ind},
- {ST_L1_F3_PDOWN, EV_PH_ACTIVATE_REQ, l1_ar8},
- {ST_L1_F3_PDOWN, EV_TIMER3, l1_timer3},
-
- {ST_L1_F3_PEND_DEACT, EV_PH_RES, l1_di},
- {ST_L1_F3_PEND_DEACT, EV_PH_EI, l1_di},
- {ST_L1_F3_PEND_DEACT, EV_PH_DC, l1_go_f3pdown},
- {ST_L1_F3_PEND_DEACT, EV_PH_RSY, l1_go_f5},
- {ST_L1_F3_PEND_DEACT, EV_PH_AR, l1_go_f6},
- {ST_L1_F3_PEND_DEACT, EV_PH_AI8, l1_go_f7_act_ind},
-
- {ST_L1_F4, EV_PH_RES, l1_di},
- {ST_L1_F4, EV_PH_EI, l1_di},
- {ST_L1_F4, EV_PH_RSY, l1_go_f5},
- {ST_L1_F4, EV_PH_AI8, l1_go_f7_act_ind},
- {ST_L1_F4, EV_TIMER3, l1_timer3},
- {ST_L1_F4, EV_PH_DC, l1_go_f3pdown},
-
- {ST_L1_F5, EV_PH_RES, l1_di},
- {ST_L1_F5, EV_PH_EI, l1_di},
- {ST_L1_F5, EV_PH_AR, l1_go_f6},
- {ST_L1_F5, EV_PH_AI8, l1_go_f7_act_ind},
- {ST_L1_F5, EV_TIMER3, l1_timer3},
- {ST_L1_F5, EV_PH_DR, l1_go_f3pend},
- {ST_L1_F5, EV_PH_DC, l1_go_f3pdown},
-
- {ST_L1_F6, EV_PH_RES, l1_di},
- {ST_L1_F6, EV_PH_EI, l1_di},
- {ST_L1_F6, EV_PH_RSY, l1_go_f8},
- {ST_L1_F6, EV_PH_AI8, l1_go_f7_act_ind},
- {ST_L1_F6, EV_PH_DR6, l1_go_f3pend},
- {ST_L1_F6, EV_TIMER3, l1_timer3},
- {ST_L1_F6, EV_PH_DC, l1_go_f3pdown},
-
- {ST_L1_F7, EV_PH_RES, l1_di_deact_ind},
- {ST_L1_F7, EV_PH_EI, l1_di_deact_ind},
- {ST_L1_F7, EV_PH_AR, l1_go_f6_deact_ind},
- {ST_L1_F7, EV_PH_RSY, l1_go_f8_deact_ind},
- {ST_L1_F7, EV_PH_DR, l1_go_f3pend_deact_ind},
-
- {ST_L1_F8, EV_PH_RES, l1_di},
- {ST_L1_F8, EV_PH_EI, l1_di},
- {ST_L1_F8, EV_PH_AR, l1_go_f6},
- {ST_L1_F8, EV_PH_DR, l1_go_f3pend},
- {ST_L1_F8, EV_PH_AI8, l1_go_f7_act_ind},
- {ST_L1_F8, EV_TIMER3, l1_timer3},
- {ST_L1_F8, EV_PH_DC, l1_go_f3pdown},
-};
-
-static void l1m_debug(struct FsmInst *fi, char *fmt, ...)
-{
- va_list args;
- char buf[256];
-
- va_start(args, fmt);
- vsnprintf(buf, sizeof(buf), fmt, args);
- DBG(DBG_L1M, "%s", buf);
- va_end(args);
-}
-
-static void isac_version(struct isac *cs)
-{
- int val;
-
- val = cs->read_isac(cs, ISAC_RBCH);
- DBG(1, "ISAC version (%x): %s", val, ISACVer[(val >> 5) & 3]);
-}
-
-static void isac_empty_fifo(struct isac *isac, int count)
-{
- // this also works for isacsx, since
- // CMDR(D) register works the same
- u_char *ptr;
-
- DBG(DBG_IRQ, "count %d", count);
-
- if ((isac->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
- DBG(DBG_WARN, "overrun %d", isac->rcvidx + count);
- isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
- isac->rcvidx = 0;
- return;
- }
- ptr = isac->rcvbuf + isac->rcvidx;
- isac->rcvidx += count;
- isac->read_isac_fifo(isac, ptr, count);
- isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
- DBG_PACKET(DBG_RFIFO, ptr, count);
-}
-
-static void isac_fill_fifo(struct isac *isac)
-{
- // this also works for isacsx, since
- // CMDR(D) register works the same
-
- int count;
- unsigned char cmd;
- u_char *ptr;
-
- BUG_ON(!isac->tx_skb);
-
- count = isac->tx_skb->len;
- BUG_ON(count <= 0);
-
- DBG(DBG_IRQ, "count %d", count);
-
- if (count > 0x20) {
- count = 0x20;
- cmd = ISAC_CMDR_XTF;
- } else {
- cmd = ISAC_CMDR_XTF | ISAC_CMDR_XME;
- }
-
- ptr = isac->tx_skb->data;
- skb_pull(isac->tx_skb, count);
- isac->tx_cnt += count;
- DBG_PACKET(DBG_XFIFO, ptr, count);
- isac->write_isac_fifo(isac, ptr, count);
- isac->write_isac(isac, ISAC_CMDR, cmd);
-}
-
-static void isac_retransmit(struct isac *isac)
-{
- if (!isac->tx_skb) {
- DBG(DBG_WARN, "no skb");
- return;
- }
- skb_push(isac->tx_skb, isac->tx_cnt);
- isac->tx_cnt = 0;
-}
-
-
-static inline void isac_cisq_interrupt(struct isac *isac)
-{
- unsigned char val;
-
- val = isac->read_isac(isac, ISAC_CIR0);
- DBG(DBG_IRQ, "CIR0 %#x", val);
- if (val & ISAC_CIR0_CIC0) {
- DBG(DBG_IRQ, "CODR0 %#x", (val >> 2) & 0xf);
- FsmEvent(&isac->l1m, (val >> 2) & 0xf, NULL);
- }
- if (val & ISAC_CIR0_CIC1) {
- val = isac->read_isac(isac, ISAC_CIR1);
- DBG(DBG_WARN, "ISAC CIR1 %#x", val);
- }
-}
-
-static inline void isac_rme_interrupt(struct isac *isac)
-{
- unsigned char val;
- int count;
- struct sk_buff *skb;
-
- val = isac->read_isac(isac, ISAC_RSTA);
- if ((val & (ISAC_RSTA_RDO | ISAC_RSTA_CRC | ISAC_RSTA_RAB))
- != ISAC_RSTA_CRC) {
- DBG(DBG_WARN, "RSTA %#x, dropped", val);
- isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
- goto out;
- }
-
- count = isac->read_isac(isac, ISAC_RBCL) & 0x1f;
- DBG(DBG_IRQ, "RBCL %#x", count);
- if (count == 0)
- count = 0x20;
-
- isac_empty_fifo(isac, count);
- count = isac->rcvidx;
- if (count < 1) {
- DBG(DBG_WARN, "count %d < 1", count);
- goto out;
- }
-
- skb = alloc_skb(count, GFP_ATOMIC);
- if (!skb) {
- DBG(DBG_WARN, "no memory, dropping\n");
- goto out;
- }
- skb_put_data(skb, isac->rcvbuf, count);
- DBG_SKB(DBG_RPACKET, skb);
- D_L1L2(isac, PH_DATA | INDICATION, skb);
-out:
- isac->rcvidx = 0;
-}
-
-static inline void isac_xpr_interrupt(struct isac *isac)
-{
- if (!isac->tx_skb)
- return;
-
- if (isac->tx_skb->len > 0) {
- isac_fill_fifo(isac);
- return;
- }
- dev_kfree_skb_irq(isac->tx_skb);
- isac->tx_cnt = 0;
- isac->tx_skb = NULL;
- D_L1L2(isac, PH_DATA | CONFIRM, NULL);
-}
-
-static inline void isac_exi_interrupt(struct isac *isac)
-{
- unsigned char val;
-
- val = isac->read_isac(isac, ISAC_EXIR);
- DBG(2, "EXIR %#x", val);
-
- if (val & ISAC_EXIR_XMR) {
- DBG(DBG_WARN, "ISAC XMR");
- isac_retransmit(isac);
- }
- if (val & ISAC_EXIR_XDU) {
- DBG(DBG_WARN, "ISAC XDU");
- isac_retransmit(isac);
- }
- if (val & ISAC_EXIR_MOS) { /* MOS */
- DBG(DBG_WARN, "MOS");
- val = isac->read_isac(isac, ISAC_MOSR);
- DBG(2, "ISAC MOSR %#x", val);
- }
-}
-
-void isac_irq(struct isac *isac)
-{
- unsigned char val;
-
- val = isac->read_isac(isac, ISAC_ISTA);
- DBG(DBG_IRQ, "ISTA %#x", val);
-
- if (val & ISAC_ISTA_EXI) {
- DBG(DBG_IRQ, "EXI");
- isac_exi_interrupt(isac);
- }
- if (val & ISAC_ISTA_XPR) {
- DBG(DBG_IRQ, "XPR");
- isac_xpr_interrupt(isac);
- }
- if (val & ISAC_ISTA_RME) {
- DBG(DBG_IRQ, "RME");
- isac_rme_interrupt(isac);
- }
- if (val & ISAC_ISTA_RPF) {
- DBG(DBG_IRQ, "RPF");
- isac_empty_fifo(isac, 0x20);
- }
- if (val & ISAC_ISTA_CISQ) {
- DBG(DBG_IRQ, "CISQ");
- isac_cisq_interrupt(isac);
- }
- if (val & ISAC_ISTA_RSC) {
- DBG(DBG_WARN, "RSC");
- }
- if (val & ISAC_ISTA_SIN) {
- DBG(DBG_WARN, "SIN");
- }
- isac->write_isac(isac, ISAC_MASK, 0xff);
- isac->write_isac(isac, ISAC_MASK, 0x00);
-}
-
-// ======================================================================
-
-static inline void isacsx_cic_interrupt(struct isac *isac)
-{
- unsigned char val;
-
- val = isac->read_isac(isac, ISACSX_CIR0);
- DBG(DBG_IRQ, "CIR0 %#x", val);
- if (val & ISACSX_CIR0_CIC0) {
- DBG(DBG_IRQ, "CODR0 %#x", val >> 4);
- FsmEvent(&isac->l1m, val >> 4, NULL);
- }
-}
-
-static inline void isacsx_rme_interrupt(struct isac *isac)
-{
- int count;
- struct sk_buff *skb;
- unsigned char val;
-
- val = isac->read_isac(isac, ISACSX_RSTAD);
- if ((val & (ISACSX_RSTAD_VFR |
- ISACSX_RSTAD_RDO |
- ISACSX_RSTAD_CRC |
- ISACSX_RSTAD_RAB))
- != (ISACSX_RSTAD_VFR | ISACSX_RSTAD_CRC)) {
- DBG(DBG_WARN, "RSTAD %#x, dropped", val);
- isac->write_isac(isac, ISACSX_CMDRD, ISACSX_CMDRD_RMC);
- goto out;
- }
-
- count = isac->read_isac(isac, ISACSX_RBCLD) & 0x1f;
- DBG(DBG_IRQ, "RBCLD %#x", count);
- if (count == 0)
- count = 0x20;
-
- isac_empty_fifo(isac, count);
- // strip trailing status byte
- count = isac->rcvidx - 1;
- if (count < 1) {
- DBG(DBG_WARN, "count %d < 1", count);
- goto out;
- }
-
- skb = dev_alloc_skb(count);
- if (!skb) {
- DBG(DBG_WARN, "no memory, dropping");
- goto out;
- }
- skb_put_data(skb, isac->rcvbuf, count);
- DBG_SKB(DBG_RPACKET, skb);
- D_L1L2(isac, PH_DATA | INDICATION, skb);
-out:
- isac->rcvidx = 0;
-}
-
-static inline void isacsx_xpr_interrupt(struct isac *isac)
-{
- if (!isac->tx_skb)
- return;
-
- if (isac->tx_skb->len > 0) {
- isac_fill_fifo(isac);
- return;
- }
- dev_kfree_skb_irq(isac->tx_skb);
- isac->tx_skb = NULL;
- isac->tx_cnt = 0;
- D_L1L2(isac, PH_DATA | CONFIRM, NULL);
-}
-
-static inline void isacsx_icd_interrupt(struct isac *isac)
-{
- unsigned char val;
-
- val = isac->read_isac(isac, ISACSX_ISTAD);
- DBG(DBG_IRQ, "ISTAD %#x", val);
- if (val & ISACSX_ISTAD_XDU) {
- DBG(DBG_WARN, "ISTAD XDU");
- isac_retransmit(isac);
- }
- if (val & ISACSX_ISTAD_XMR) {
- DBG(DBG_WARN, "ISTAD XMR");
- isac_retransmit(isac);
- }
- if (val & ISACSX_ISTAD_XPR) {
- DBG(DBG_IRQ, "ISTAD XPR");
- isacsx_xpr_interrupt(isac);
- }
- if (val & ISACSX_ISTAD_RFO) {
- DBG(DBG_WARN, "ISTAD RFO");
- isac->write_isac(isac, ISACSX_CMDRD, ISACSX_CMDRD_RMC);
- }
- if (val & ISACSX_ISTAD_RME) {
- DBG(DBG_IRQ, "ISTAD RME");
- isacsx_rme_interrupt(isac);
- }
- if (val & ISACSX_ISTAD_RPF) {
- DBG(DBG_IRQ, "ISTAD RPF");
- isac_empty_fifo(isac, 0x20);
- }
-}
-
-void isacsx_irq(struct isac *isac)
-{
- unsigned char val;
-
- val = isac->read_isac(isac, ISACSX_ISTA);
- DBG(DBG_IRQ, "ISTA %#x", val);
-
- if (val & ISACSX_ISTA_ICD)
- isacsx_icd_interrupt(isac);
- if (val & ISACSX_ISTA_CIC)
- isacsx_cic_interrupt(isac);
-}
-
-void isac_init(struct isac *isac)
-{
- isac->tx_skb = NULL;
- isac->l1m.fsm = &l1fsm;
- isac->l1m.state = ST_L1_RESET;
-#ifdef CONFIG_HISAX_DEBUG
- isac->l1m.debug = 1;
-#else
- isac->l1m.debug = 0;
-#endif
- isac->l1m.userdata = isac;
- isac->l1m.printdebug = l1m_debug;
- FsmInitTimer(&isac->l1m, &isac->timer);
-}
-
-void isac_setup(struct isac *isac)
-{
- int val, eval;
-
- isac->type = TYPE_ISAC;
- isac_version(isac);
-
- ph_command(isac, ISAC_CMD_RES);
-
- isac->write_isac(isac, ISAC_MASK, 0xff);
- isac->mocr = 0xaa;
- if (test_bit(ISAC_IOM1, &isac->flags)) {
- /* IOM 1 Mode */
- isac->write_isac(isac, ISAC_ADF2, 0x0);
- isac->write_isac(isac, ISAC_SPCR, 0xa);
- isac->write_isac(isac, ISAC_ADF1, 0x2);
- isac->write_isac(isac, ISAC_STCR, 0x70);
- isac->write_isac(isac, ISAC_MODE, 0xc9);
- } else {
- /* IOM 2 Mode */
- if (!isac->adf2)
- isac->adf2 = 0x80;
- isac->write_isac(isac, ISAC_ADF2, isac->adf2);
- isac->write_isac(isac, ISAC_SQXR, 0x2f);
- isac->write_isac(isac, ISAC_SPCR, 0x00);
- isac->write_isac(isac, ISAC_STCR, 0x70);
- isac->write_isac(isac, ISAC_MODE, 0xc9);
- isac->write_isac(isac, ISAC_TIMR, 0x00);
- isac->write_isac(isac, ISAC_ADF1, 0x00);
- }
- val = isac->read_isac(isac, ISAC_STAR);
- DBG(2, "ISAC STAR %x", val);
- val = isac->read_isac(isac, ISAC_MODE);
- DBG(2, "ISAC MODE %x", val);
- val = isac->read_isac(isac, ISAC_ADF2);
- DBG(2, "ISAC ADF2 %x", val);
- val = isac->read_isac(isac, ISAC_ISTA);
- DBG(2, "ISAC ISTA %x", val);
- if (val & 0x01) {
- eval = isac->read_isac(isac, ISAC_EXIR);
- DBG(2, "ISAC EXIR %x", eval);
- }
- val = isac->read_isac(isac, ISAC_CIR0);
- DBG(2, "ISAC CIR0 %x", val);
- FsmEvent(&isac->l1m, (val >> 2) & 0xf, NULL);
-
- isac->write_isac(isac, ISAC_MASK, 0x0);
- // RESET Receiver and Transmitter
- isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_XRES | ISAC_CMDR_RRES);
-}
-
-void isacsx_setup(struct isac *isac)
-{
- isac->type = TYPE_ISACSX;
- // clear LDD
- isac->write_isac(isac, ISACSX_TR_CONF0, 0x00);
- // enable transmitter
- isac->write_isac(isac, ISACSX_TR_CONF2, 0x00);
- // transparent mode 0, RAC, stop/go
- isac->write_isac(isac, ISACSX_MODED, 0xc9);
- // all HDLC IRQ unmasked
- isac->write_isac(isac, ISACSX_MASKD, 0x03);
- // unmask ICD, CID IRQs
- isac->write_isac(isac, ISACSX_MASK,
- ~(ISACSX_ISTA_ICD | ISACSX_ISTA_CIC));
-}
-
-void isac_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg)
-{
- struct isac *isac = hisax_d_if->priv;
- struct sk_buff *skb = arg;
-
- DBG(DBG_PR, "pr %#x", pr);
-
- switch (pr) {
- case PH_ACTIVATE | REQUEST:
- FsmEvent(&isac->l1m, EV_PH_ACTIVATE_REQ, NULL);
- break;
- case PH_DEACTIVATE | REQUEST:
- FsmEvent(&isac->l1m, EV_PH_DEACTIVATE_REQ, NULL);
- break;
- case PH_DATA | REQUEST:
- DBG(DBG_PR, "PH_DATA REQUEST len %d", skb->len);
- DBG_SKB(DBG_XPACKET, skb);
- if (isac->l1m.state != ST_L1_F7) {
- DBG(1, "L1 wrong state %d\n", isac->l1m.state);
- dev_kfree_skb(skb);
- break;
- }
- BUG_ON(isac->tx_skb);
-
- isac->tx_skb = skb;
- isac_fill_fifo(isac);
- break;
- }
-}
-
-static int __init hisax_isac_init(void)
-{
- printk(KERN_INFO "hisax_isac: ISAC-S/ISAC-SX ISDN driver v0.1.0\n");
-
- l1fsm.state_count = L1_STATE_COUNT;
- l1fsm.event_count = L1_EVENT_COUNT;
- l1fsm.strState = strL1State;
- l1fsm.strEvent = strL1Event;
- return FsmNew(&l1fsm, L1FnList, ARRAY_SIZE(L1FnList));
-}
-
-static void __exit hisax_isac_exit(void)
-{
- FsmFree(&l1fsm);
-}
-
-EXPORT_SYMBOL(isac_init);
-EXPORT_SYMBOL(isac_d_l2l1);
-
-EXPORT_SYMBOL(isacsx_setup);
-EXPORT_SYMBOL(isacsx_irq);
-
-EXPORT_SYMBOL(isac_setup);
-EXPORT_SYMBOL(isac_irq);
-
-module_init(hisax_isac_init);
-module_exit(hisax_isac_exit);
diff --git a/drivers/isdn/hisax/hisax_isac.h b/drivers/isdn/hisax/hisax_isac.h
deleted file mode 100644
index d7301da97991..000000000000
--- a/drivers/isdn/hisax/hisax_isac.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __HISAX_ISAC_H__
-#define __HISAX_ISAC_H__
-
-#include <linux/kernel.h>
-#include "fsm.h"
-#include "hisax_if.h"
-
-#define TIMER3_VALUE 7000
-#define MAX_DFRAME_LEN_L1 300
-
-#define ISAC_IOM1 0
-
-struct isac {
- void *priv;
-
- u_long flags;
- struct hisax_d_if hisax_d_if;
- struct FsmInst l1m;
- struct FsmTimer timer;
- u_char mocr;
- u_char adf2;
- int type;
-
- u_char rcvbuf[MAX_DFRAME_LEN_L1];
- int rcvidx;
-
- struct sk_buff *tx_skb;
- int tx_cnt;
-
- u_char (*read_isac) (struct isac *, u_char);
- void (*write_isac) (struct isac *, u_char, u_char);
- void (*read_isac_fifo) (struct isac *, u_char *, int);
- void (*write_isac_fifo)(struct isac *, u_char *, int);
-};
-
-void isac_init(struct isac *isac);
-void isac_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg);
-
-void isac_setup(struct isac *isac);
-void isac_irq(struct isac *isac);
-
-void isacsx_setup(struct isac *isac);
-void isacsx_irq(struct isac *isac);
-
-#endif
diff --git a/drivers/isdn/hisax/hscx.c b/drivers/isdn/hisax/hscx.c
deleted file mode 100644
index 3e305fec0ed9..000000000000
--- a/drivers/isdn/hisax/hscx.c
+++ /dev/null
@@ -1,277 +0,0 @@
-/* $Id: hscx.c,v 1.24.2.4 2004/01/24 20:47:23 keil Exp $
- *
- * HSCX specific routines
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/init.h>
-#include "hisax.h"
-#include "hscx.h"
-#include "isac.h"
-#include "isdnl1.h"
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-
-static char *HSCXVer[] =
-{"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7",
- "?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"};
-
-int
-HscxVersion(struct IsdnCardState *cs, char *s)
-{
- int verA, verB;
-
- verA = cs->BC_Read_Reg(cs, 0, HSCX_VSTR) & 0xf;
- verB = cs->BC_Read_Reg(cs, 1, HSCX_VSTR) & 0xf;
- printk(KERN_INFO "%s HSCX version A: %s B: %s\n", s,
- HSCXVer[verA], HSCXVer[verB]);
- if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf))
- return (1);
- else
- return (0);
-}
-
-void
-modehscx(struct BCState *bcs, int mode, int bc)
-{
- struct IsdnCardState *cs = bcs->cs;
- int hscx = bcs->hw.hscx.hscx;
-
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hscx %c mode %d ichan %d",
- 'A' + hscx, mode, bc);
- bcs->mode = mode;
- bcs->channel = bc;
- cs->BC_Write_Reg(cs, hscx, HSCX_XAD1, 0xFF);
- cs->BC_Write_Reg(cs, hscx, HSCX_XAD2, 0xFF);
- cs->BC_Write_Reg(cs, hscx, HSCX_RAH2, 0xFF);
- cs->BC_Write_Reg(cs, hscx, HSCX_XBCH, 0x0);
- cs->BC_Write_Reg(cs, hscx, HSCX_RLCR, 0x0);
- cs->BC_Write_Reg(cs, hscx, HSCX_CCR1,
- test_bit(HW_IPAC, &cs->HW_Flags) ? 0x82 : 0x85);
- cs->BC_Write_Reg(cs, hscx, HSCX_CCR2, 0x30);
- cs->BC_Write_Reg(cs, hscx, HSCX_XCCR, 7);
- cs->BC_Write_Reg(cs, hscx, HSCX_RCCR, 7);
-
- /* Switch IOM 1 SSI */
- if (test_bit(HW_IOM1, &cs->HW_Flags) && (hscx == 0))
- bc = 1 - bc;
-
- if (bc == 0) {
- cs->BC_Write_Reg(cs, hscx, HSCX_TSAX,
- test_bit(HW_IOM1, &cs->HW_Flags) ? 0x7 : bcs->hw.hscx.tsaxr0);
- cs->BC_Write_Reg(cs, hscx, HSCX_TSAR,
- test_bit(HW_IOM1, &cs->HW_Flags) ? 0x7 : bcs->hw.hscx.tsaxr0);
- } else {
- cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, bcs->hw.hscx.tsaxr1);
- cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, bcs->hw.hscx.tsaxr1);
- }
- switch (mode) {
- case (L1_MODE_NULL):
- cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, 0x1f);
- cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, 0x1f);
- cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0x84);
- break;
- case (L1_MODE_TRANS):
- cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0xe4);
- break;
- case (L1_MODE_HDLC):
- cs->BC_Write_Reg(cs, hscx, HSCX_CCR1,
- test_bit(HW_IPAC, &cs->HW_Flags) ? 0x8a : 0x8d);
- cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0x8c);
- break;
- }
- if (mode)
- cs->BC_Write_Reg(cs, hscx, HSCX_CMDR, 0x41);
- cs->BC_Write_Reg(cs, hscx, HSCX_ISTA, 0x00);
-}
-
-void
-hscx_l2l1(struct PStack *st, int pr, void *arg)
-{
- struct BCState *bcs = st->l1.bcs;
- u_long flags;
- struct sk_buff *skb = arg;
-
- switch (pr) {
- case (PH_DATA | REQUEST):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- if (bcs->tx_skb) {
- skb_queue_tail(&bcs->squeue, skb);
- } else {
- bcs->tx_skb = skb;
- test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->hw.hscx.count = 0;
- bcs->cs->BC_Send_Data(bcs);
- }
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- break;
- case (PH_PULL | INDICATION):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- if (bcs->tx_skb) {
- printk(KERN_WARNING "hscx_l2l1: this shouldn't happen\n");
- } else {
- test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->tx_skb = skb;
- bcs->hw.hscx.count = 0;
- bcs->cs->BC_Send_Data(bcs);
- }
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- break;
- case (PH_PULL | REQUEST):
- if (!bcs->tx_skb) {
- test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
- } else
- test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- break;
- case (PH_ACTIVATE | REQUEST):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
- modehscx(bcs, st->l1.mode, st->l1.bc);
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- l1_msg_b(st, pr, arg);
- break;
- case (PH_DEACTIVATE | REQUEST):
- l1_msg_b(st, pr, arg);
- break;
- case (PH_DEACTIVATE | CONFIRM):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- modehscx(bcs, 0, st->l1.bc);
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
- break;
- }
-}
-
-static void
-close_hscxstate(struct BCState *bcs)
-{
- modehscx(bcs, 0, bcs->channel);
- if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
- kfree(bcs->hw.hscx.rcvbuf);
- bcs->hw.hscx.rcvbuf = NULL;
- kfree(bcs->blog);
- bcs->blog = NULL;
- skb_queue_purge(&bcs->rqueue);
- skb_queue_purge(&bcs->squeue);
- if (bcs->tx_skb) {
- dev_kfree_skb_any(bcs->tx_skb);
- bcs->tx_skb = NULL;
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- }
- }
-}
-
-int
-open_hscxstate(struct IsdnCardState *cs, struct BCState *bcs)
-{
- if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
- if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
- printk(KERN_WARNING
- "HiSax: No memory for hscx.rcvbuf\n");
- test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
- return (1);
- }
- if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
- printk(KERN_WARNING
- "HiSax: No memory for bcs->blog\n");
- test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
- kfree(bcs->hw.hscx.rcvbuf);
- bcs->hw.hscx.rcvbuf = NULL;
- return (2);
- }
- skb_queue_head_init(&bcs->rqueue);
- skb_queue_head_init(&bcs->squeue);
- }
- bcs->tx_skb = NULL;
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->event = 0;
- bcs->hw.hscx.rcvidx = 0;
- bcs->tx_cnt = 0;
- return (0);
-}
-
-static int
-setstack_hscx(struct PStack *st, struct BCState *bcs)
-{
- bcs->channel = st->l1.bc;
- if (open_hscxstate(st->l1.hardware, bcs))
- return (-1);
- st->l1.bcs = bcs;
- st->l2.l2l1 = hscx_l2l1;
- setstack_manager(st);
- bcs->st = st;
- setstack_l1_B(st);
- return (0);
-}
-
-void
-clear_pending_hscx_ints(struct IsdnCardState *cs)
-{
- int val, eval;
-
- val = cs->BC_Read_Reg(cs, 1, HSCX_ISTA);
- debugl1(cs, "HSCX B ISTA %x", val);
- if (val & 0x01) {
- eval = cs->BC_Read_Reg(cs, 1, HSCX_EXIR);
- debugl1(cs, "HSCX B EXIR %x", eval);
- }
- if (val & 0x02) {
- eval = cs->BC_Read_Reg(cs, 0, HSCX_EXIR);
- debugl1(cs, "HSCX A EXIR %x", eval);
- }
- val = cs->BC_Read_Reg(cs, 0, HSCX_ISTA);
- debugl1(cs, "HSCX A ISTA %x", val);
- val = cs->BC_Read_Reg(cs, 1, HSCX_STAR);
- debugl1(cs, "HSCX B STAR %x", val);
- val = cs->BC_Read_Reg(cs, 0, HSCX_STAR);
- debugl1(cs, "HSCX A STAR %x", val);
- /* disable all IRQ */
- cs->BC_Write_Reg(cs, 0, HSCX_MASK, 0xFF);
- cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0xFF);
-}
-
-void
-inithscx(struct IsdnCardState *cs)
-{
- cs->bcs[0].BC_SetStack = setstack_hscx;
- cs->bcs[1].BC_SetStack = setstack_hscx;
- cs->bcs[0].BC_Close = close_hscxstate;
- cs->bcs[1].BC_Close = close_hscxstate;
- cs->bcs[0].hw.hscx.hscx = 0;
- cs->bcs[1].hw.hscx.hscx = 1;
- cs->bcs[0].hw.hscx.tsaxr0 = 0x2f;
- cs->bcs[0].hw.hscx.tsaxr1 = 3;
- cs->bcs[1].hw.hscx.tsaxr0 = 0x2f;
- cs->bcs[1].hw.hscx.tsaxr1 = 3;
- modehscx(cs->bcs, 0, 0);
- modehscx(cs->bcs + 1, 0, 0);
-}
-
-void
-inithscxisac(struct IsdnCardState *cs, int part)
-{
- if (part & 1) {
- clear_pending_isac_ints(cs);
- clear_pending_hscx_ints(cs);
- initisac(cs);
- inithscx(cs);
- }
- if (part & 2) {
- /* Reenable all IRQ */
- cs->writeisac(cs, ISAC_MASK, 0);
- cs->BC_Write_Reg(cs, 0, HSCX_MASK, 0);
- cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0);
- /* RESET Receiver and Transmitter */
- cs->writeisac(cs, ISAC_CMDR, 0x41);
- }
-}
diff --git a/drivers/isdn/hisax/hscx.h b/drivers/isdn/hisax/hscx.h
deleted file mode 100644
index 1148b4bbe711..000000000000
--- a/drivers/isdn/hisax/hscx.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* $Id: hscx.h,v 1.8.2.2 2004/01/12 22:52:26 keil Exp $
- *
- * HSCX specific defines
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-/* All Registers original Siemens Spec */
-
-#define HSCX_ISTA 0x20
-#define HSCX_CCR1 0x2f
-#define HSCX_CCR2 0x2c
-#define HSCX_TSAR 0x31
-#define HSCX_TSAX 0x30
-#define HSCX_XCCR 0x32
-#define HSCX_RCCR 0x33
-#define HSCX_MODE 0x22
-#define HSCX_CMDR 0x21
-#define HSCX_EXIR 0x24
-#define HSCX_XAD1 0x24
-#define HSCX_XAD2 0x25
-#define HSCX_RAH2 0x27
-#define HSCX_RSTA 0x27
-#define HSCX_TIMR 0x23
-#define HSCX_STAR 0x21
-#define HSCX_RBCL 0x25
-#define HSCX_XBCH 0x2d
-#define HSCX_VSTR 0x2e
-#define HSCX_RLCR 0x2e
-#define HSCX_MASK 0x20
-
-extern int HscxVersion(struct IsdnCardState *cs, char *s);
-extern void modehscx(struct BCState *bcs, int mode, int bc);
-extern void clear_pending_hscx_ints(struct IsdnCardState *cs);
-extern void inithscx(struct IsdnCardState *cs);
-extern void inithscxisac(struct IsdnCardState *cs, int part);
diff --git a/drivers/isdn/hisax/hscx_irq.c b/drivers/isdn/hisax/hscx_irq.c
deleted file mode 100644
index 0d7e783c8bef..000000000000
--- a/drivers/isdn/hisax/hscx_irq.c
+++ /dev/null
@@ -1,294 +0,0 @@
-/* $Id: hscx_irq.c,v 1.18.2.3 2004/02/11 13:21:34 keil Exp $
- *
- * low level b-channel stuff for Siemens HSCX
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * This is an include file for fast inline IRQ stuff
- *
- */
-
-
-static inline void
-waitforCEC(struct IsdnCardState *cs, int hscx)
-{
- int to = 50;
-
- while ((READHSCX(cs, hscx, HSCX_STAR) & 0x04) && to) {
- udelay(1);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "HiSax: waitforCEC timeout\n");
-}
-
-
-static inline void
-waitforXFW(struct IsdnCardState *cs, int hscx)
-{
- int to = 50;
-
- while (((READHSCX(cs, hscx, HSCX_STAR) & 0x44) != 0x40) && to) {
- udelay(1);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "HiSax: waitforXFW timeout\n");
-}
-
-static inline void
-WriteHSCXCMDR(struct IsdnCardState *cs, int hscx, u_char data)
-{
- waitforCEC(cs, hscx);
- WRITEHSCX(cs, hscx, HSCX_CMDR, data);
-}
-
-
-
-static void
-hscx_empty_fifo(struct BCState *bcs, int count)
-{
- u_char *ptr;
- struct IsdnCardState *cs = bcs->cs;
-
- if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
- debugl1(cs, "hscx_empty_fifo");
-
- if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "hscx_empty_fifo: incoming packet too large");
- WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);
- bcs->hw.hscx.rcvidx = 0;
- return;
- }
- ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
- bcs->hw.hscx.rcvidx += count;
- READHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
- WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);
- if (cs->debug & L1_DEB_HSCX_FIFO) {
- char *t = bcs->blog;
-
- t += sprintf(t, "hscx_empty_fifo %c cnt %d",
- bcs->hw.hscx.hscx ? 'B' : 'A', count);
- QuickHex(t, ptr, count);
- debugl1(cs, "%s", bcs->blog);
- }
-}
-
-static void
-hscx_fill_fifo(struct BCState *bcs)
-{
- struct IsdnCardState *cs = bcs->cs;
- int more, count;
- int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags) ? 64 : 32;
- u_char *ptr;
-
- if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
- debugl1(cs, "hscx_fill_fifo");
-
- if (!bcs->tx_skb)
- return;
- if (bcs->tx_skb->len <= 0)
- return;
-
- more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
- if (bcs->tx_skb->len > fifo_size) {
- more = !0;
- count = fifo_size;
- } else
- count = bcs->tx_skb->len;
-
- waitforXFW(cs, bcs->hw.hscx.hscx);
- ptr = bcs->tx_skb->data;
- skb_pull(bcs->tx_skb, count);
- bcs->tx_cnt -= count;
- bcs->hw.hscx.count += count;
- WRITEHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
- WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, more ? 0x8 : 0xa);
- if (cs->debug & L1_DEB_HSCX_FIFO) {
- char *t = bcs->blog;
-
- t += sprintf(t, "hscx_fill_fifo %c cnt %d",
- bcs->hw.hscx.hscx ? 'B' : 'A', count);
- QuickHex(t, ptr, count);
- debugl1(cs, "%s", bcs->blog);
- }
-}
-
-static void
-hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
-{
- u_char r;
- struct BCState *bcs = cs->bcs + hscx;
- struct sk_buff *skb;
- int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags) ? 64 : 32;
- int count;
-
- if (!test_bit(BC_FLG_INIT, &bcs->Flag))
- return;
-
- if (val & 0x80) { /* RME */
- r = READHSCX(cs, hscx, HSCX_RSTA);
- if ((r & 0xf0) != 0xa0) {
- if (!(r & 0x80)) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "HSCX invalid frame");
-#ifdef ERROR_STATISTIC
- bcs->err_inv++;
-#endif
- }
- if ((r & 0x40) && bcs->mode) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "HSCX RDO mode=%d",
- bcs->mode);
-#ifdef ERROR_STATISTIC
- bcs->err_rdo++;
-#endif
- }
- if (!(r & 0x20)) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "HSCX CRC error");
-#ifdef ERROR_STATISTIC
- bcs->err_crc++;
-#endif
- }
- WriteHSCXCMDR(cs, hscx, 0x80);
- } else {
- count = READHSCX(cs, hscx, HSCX_RBCL) & (
- test_bit(HW_IPAC, &cs->HW_Flags) ? 0x3f : 0x1f);
- if (count == 0)
- count = fifo_size;
- hscx_empty_fifo(bcs, count);
- if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
- if (cs->debug & L1_DEB_HSCX_FIFO)
- debugl1(cs, "HX Frame %d", count);
- if (!(skb = dev_alloc_skb(count)))
- printk(KERN_WARNING "HSCX: receive out of memory\n");
- else {
- skb_put_data(skb, bcs->hw.hscx.rcvbuf,
- count);
- skb_queue_tail(&bcs->rqueue, skb);
- }
- }
- }
- bcs->hw.hscx.rcvidx = 0;
- schedule_event(bcs, B_RCVBUFREADY);
- }
- if (val & 0x40) { /* RPF */
- hscx_empty_fifo(bcs, fifo_size);
- if (bcs->mode == L1_MODE_TRANS) {
- /* receive audio data */
- if (!(skb = dev_alloc_skb(fifo_size)))
- printk(KERN_WARNING "HiSax: receive out of memory\n");
- else {
- skb_put_data(skb, bcs->hw.hscx.rcvbuf,
- fifo_size);
- skb_queue_tail(&bcs->rqueue, skb);
- }
- bcs->hw.hscx.rcvidx = 0;
- schedule_event(bcs, B_RCVBUFREADY);
- }
- }
- if (val & 0x10) { /* XPR */
- if (bcs->tx_skb) {
- if (bcs->tx_skb->len) {
- hscx_fill_fifo(bcs);
- return;
- } else {
- if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
- (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
- u_long flags;
- spin_lock_irqsave(&bcs->aclock, flags);
- bcs->ackcnt += bcs->hw.hscx.count;
- spin_unlock_irqrestore(&bcs->aclock, flags);
- schedule_event(bcs, B_ACKPENDING);
- }
- dev_kfree_skb_irq(bcs->tx_skb);
- bcs->hw.hscx.count = 0;
- bcs->tx_skb = NULL;
- }
- }
- if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
- bcs->hw.hscx.count = 0;
- test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
- hscx_fill_fifo(bcs);
- } else {
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- schedule_event(bcs, B_XMTBUFREADY);
- }
- }
-}
-
-static void
-hscx_int_main(struct IsdnCardState *cs, u_char val)
-{
-
- u_char exval;
- struct BCState *bcs;
-
- if (val & 0x01) {
- bcs = cs->bcs + 1;
- exval = READHSCX(cs, 1, HSCX_EXIR);
- if (exval & 0x40) {
- if (bcs->mode == 1)
- hscx_fill_fifo(bcs);
- else {
-#ifdef ERROR_STATISTIC
- bcs->err_tx++;
-#endif
- /* Here we lost an TX interrupt, so
- * restart transmitting the whole frame.
- */
- if (bcs->tx_skb) {
- skb_push(bcs->tx_skb, bcs->hw.hscx.count);
- bcs->tx_cnt += bcs->hw.hscx.count;
- bcs->hw.hscx.count = 0;
- }
- WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "HSCX B EXIR %x Lost TX", exval);
- }
- } else if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "HSCX B EXIR %x", exval);
- }
- if (val & 0xf8) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "HSCX B interrupt %x", val);
- hscx_interrupt(cs, val, 1);
- }
- if (val & 0x02) {
- bcs = cs->bcs;
- exval = READHSCX(cs, 0, HSCX_EXIR);
- if (exval & 0x40) {
- if (bcs->mode == L1_MODE_TRANS)
- hscx_fill_fifo(bcs);
- else {
- /* Here we lost an TX interrupt, so
- * restart transmitting the whole frame.
- */
-#ifdef ERROR_STATISTIC
- bcs->err_tx++;
-#endif
- if (bcs->tx_skb) {
- skb_push(bcs->tx_skb, bcs->hw.hscx.count);
- bcs->tx_cnt += bcs->hw.hscx.count;
- bcs->hw.hscx.count = 0;
- }
- WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "HSCX A EXIR %x Lost TX", exval);
- }
- } else if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "HSCX A EXIR %x", exval);
- }
- if (val & 0x04) {
- exval = READHSCX(cs, 0, HSCX_ISTA);
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "HSCX A interrupt %x", exval);
- hscx_interrupt(cs, exval, 0);
- }
-}
diff --git a/drivers/isdn/hisax/icc.c b/drivers/isdn/hisax/icc.c
deleted file mode 100644
index 831dd1bb81ef..000000000000
--- a/drivers/isdn/hisax/icc.c
+++ /dev/null
@@ -1,680 +0,0 @@
-/* $Id: icc.c,v 1.8.2.3 2004/01/13 14:31:25 keil Exp $
- *
- * ICC specific routines
- *
- * Author Matt Henderson & Guy Ellis
- * Copyright by Traverse Technologies Pty Ltd, www.travers.com.au
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * 1999.6.25 Initial implementation of routines for Siemens ISDN
- * Communication Controller PEB 2070 based on the ISAC routines
- * written by Karsten Keil.
- *
- */
-
-#include <linux/init.h>
-#include "hisax.h"
-#include "icc.h"
-// #include "arcofi.h"
-#include "isdnl1.h"
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-
-#define DBUSY_TIMER_VALUE 80
-#define ARCOFI_USE 0
-
-static char *ICCVer[] =
-{"2070 A1/A3", "2070 B1", "2070 B2/B3", "2070 V2.4"};
-
-void
-ICCVersion(struct IsdnCardState *cs, char *s)
-{
- int val;
-
- val = cs->readisac(cs, ICC_RBCH);
- printk(KERN_INFO "%s ICC version (%x): %s\n", s, val, ICCVer[(val >> 5) & 3]);
-}
-
-static void
-ph_command(struct IsdnCardState *cs, unsigned int command)
-{
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ph_command %x", command);
- cs->writeisac(cs, ICC_CIX0, (command << 2) | 3);
-}
-
-
-static void
-icc_new_ph(struct IsdnCardState *cs)
-{
- switch (cs->dc.icc.ph_state) {
- case (ICC_IND_EI1):
- ph_command(cs, ICC_CMD_DI);
- l1_msg(cs, HW_RESET | INDICATION, NULL);
- break;
- case (ICC_IND_DC):
- l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
- break;
- case (ICC_IND_DR):
- l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
- break;
- case (ICC_IND_PU):
- l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
- break;
- case (ICC_IND_FJ):
- l1_msg(cs, HW_RSYNC | INDICATION, NULL);
- break;
- case (ICC_IND_AR):
- l1_msg(cs, HW_INFO2 | INDICATION, NULL);
- break;
- case (ICC_IND_AI):
- l1_msg(cs, HW_INFO4 | INDICATION, NULL);
- break;
- default:
- break;
- }
-}
-
-static void
-icc_bh(struct work_struct *work)
-{
- struct IsdnCardState *cs =
- container_of(work, struct IsdnCardState, tqueue);
- struct PStack *stptr;
-
- if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
- if (cs->debug)
- debugl1(cs, "D-Channel Busy cleared");
- stptr = cs->stlist;
- while (stptr != NULL) {
- stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
- stptr = stptr->next;
- }
- }
- if (test_and_clear_bit(D_L1STATECHANGE, &cs->event))
- icc_new_ph(cs);
- if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
- DChannel_proc_rcv(cs);
- if (test_and_clear_bit(D_XMTBUFREADY, &cs->event))
- DChannel_proc_xmt(cs);
-#if ARCOFI_USE
- if (!test_bit(HW_ARCOFI, &cs->HW_Flags))
- return;
- if (test_and_clear_bit(D_RX_MON1, &cs->event))
- arcofi_fsm(cs, ARCOFI_RX_END, NULL);
- if (test_and_clear_bit(D_TX_MON1, &cs->event))
- arcofi_fsm(cs, ARCOFI_TX_END, NULL);
-#endif
-}
-
-static void
-icc_empty_fifo(struct IsdnCardState *cs, int count)
-{
- u_char *ptr;
-
- if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
- debugl1(cs, "icc_empty_fifo");
-
- if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "icc_empty_fifo overrun %d",
- cs->rcvidx + count);
- cs->writeisac(cs, ICC_CMDR, 0x80);
- cs->rcvidx = 0;
- return;
- }
- ptr = cs->rcvbuf + cs->rcvidx;
- cs->rcvidx += count;
- cs->readisacfifo(cs, ptr, count);
- cs->writeisac(cs, ICC_CMDR, 0x80);
- if (cs->debug & L1_DEB_ISAC_FIFO) {
- char *t = cs->dlog;
-
- t += sprintf(t, "icc_empty_fifo cnt %d", count);
- QuickHex(t, ptr, count);
- debugl1(cs, "%s", cs->dlog);
- }
-}
-
-static void
-icc_fill_fifo(struct IsdnCardState *cs)
-{
- int count, more;
- u_char *ptr;
-
- if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
- debugl1(cs, "icc_fill_fifo");
-
- if (!cs->tx_skb)
- return;
-
- count = cs->tx_skb->len;
- if (count <= 0)
- return;
-
- more = 0;
- if (count > 32) {
- more = !0;
- count = 32;
- }
- ptr = cs->tx_skb->data;
- skb_pull(cs->tx_skb, count);
- cs->tx_cnt += count;
- cs->writeisacfifo(cs, ptr, count);
- cs->writeisac(cs, ICC_CMDR, more ? 0x8 : 0xa);
- if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
- debugl1(cs, "icc_fill_fifo dbusytimer running");
- del_timer(&cs->dbusytimer);
- }
- cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
- add_timer(&cs->dbusytimer);
- if (cs->debug & L1_DEB_ISAC_FIFO) {
- char *t = cs->dlog;
-
- t += sprintf(t, "icc_fill_fifo cnt %d", count);
- QuickHex(t, ptr, count);
- debugl1(cs, "%s", cs->dlog);
- }
-}
-
-void
-icc_interrupt(struct IsdnCardState *cs, u_char val)
-{
- u_char exval, v1;
- struct sk_buff *skb;
- unsigned int count;
-
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ICC interrupt %x", val);
- if (val & 0x80) { /* RME */
- exval = cs->readisac(cs, ICC_RSTA);
- if ((exval & 0x70) != 0x20) {
- if (exval & 0x40) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "ICC RDO");
-#ifdef ERROR_STATISTIC
- cs->err_rx++;
-#endif
- }
- if (!(exval & 0x20)) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "ICC CRC error");
-#ifdef ERROR_STATISTIC
- cs->err_crc++;
-#endif
- }
- cs->writeisac(cs, ICC_CMDR, 0x80);
- } else {
- count = cs->readisac(cs, ICC_RBCL) & 0x1f;
- if (count == 0)
- count = 32;
- icc_empty_fifo(cs, count);
- if ((count = cs->rcvidx) > 0) {
- cs->rcvidx = 0;
- if (!(skb = alloc_skb(count, GFP_ATOMIC)))
- printk(KERN_WARNING "HiSax: D receive out of memory\n");
- else {
- skb_put_data(skb, cs->rcvbuf, count);
- skb_queue_tail(&cs->rq, skb);
- }
- }
- }
- cs->rcvidx = 0;
- schedule_event(cs, D_RCVBUFREADY);
- }
- if (val & 0x40) { /* RPF */
- icc_empty_fifo(cs, 32);
- }
- if (val & 0x20) { /* RSC */
- /* never */
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "ICC RSC interrupt");
- }
- if (val & 0x10) { /* XPR */
- if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
- del_timer(&cs->dbusytimer);
- if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
- schedule_event(cs, D_CLEARBUSY);
- if (cs->tx_skb) {
- if (cs->tx_skb->len) {
- icc_fill_fifo(cs);
- goto afterXPR;
- } else {
- dev_kfree_skb_irq(cs->tx_skb);
- cs->tx_cnt = 0;
- cs->tx_skb = NULL;
- }
- }
- if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
- cs->tx_cnt = 0;
- icc_fill_fifo(cs);
- } else
- schedule_event(cs, D_XMTBUFREADY);
- }
-afterXPR:
- if (val & 0x04) { /* CISQ */
- exval = cs->readisac(cs, ICC_CIR0);
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ICC CIR0 %02X", exval);
- if (exval & 2) {
- cs->dc.icc.ph_state = (exval >> 2) & 0xf;
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ph_state change %x", cs->dc.icc.ph_state);
- schedule_event(cs, D_L1STATECHANGE);
- }
- if (exval & 1) {
- exval = cs->readisac(cs, ICC_CIR1);
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ICC CIR1 %02X", exval);
- }
- }
- if (val & 0x02) { /* SIN */
- /* never */
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "ICC SIN interrupt");
- }
- if (val & 0x01) { /* EXI */
- exval = cs->readisac(cs, ICC_EXIR);
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "ICC EXIR %02x", exval);
- if (exval & 0x80) { /* XMR */
- debugl1(cs, "ICC XMR");
- printk(KERN_WARNING "HiSax: ICC XMR\n");
- }
- if (exval & 0x40) { /* XDU */
- debugl1(cs, "ICC XDU");
- printk(KERN_WARNING "HiSax: ICC XDU\n");
-#ifdef ERROR_STATISTIC
- cs->err_tx++;
-#endif
- if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
- del_timer(&cs->dbusytimer);
- if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
- schedule_event(cs, D_CLEARBUSY);
- if (cs->tx_skb) { /* Restart frame */
- skb_push(cs->tx_skb, cs->tx_cnt);
- cs->tx_cnt = 0;
- icc_fill_fifo(cs);
- } else {
- printk(KERN_WARNING "HiSax: ICC XDU no skb\n");
- debugl1(cs, "ICC XDU no skb");
- }
- }
- if (exval & 0x04) { /* MOS */
- v1 = cs->readisac(cs, ICC_MOSR);
- if (cs->debug & L1_DEB_MONITOR)
- debugl1(cs, "ICC MOSR %02x", v1);
-#if ARCOFI_USE
- if (v1 & 0x08) {
- if (!cs->dc.icc.mon_rx) {
- if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "ICC MON RX out of memory!");
- cs->dc.icc.mocr &= 0xf0;
- cs->dc.icc.mocr |= 0x0a;
- cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
- goto afterMONR0;
- } else
- cs->dc.icc.mon_rxp = 0;
- }
- if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) {
- cs->dc.icc.mocr &= 0xf0;
- cs->dc.icc.mocr |= 0x0a;
- cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
- cs->dc.icc.mon_rxp = 0;
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "ICC MON RX overflow!");
- goto afterMONR0;
- }
- cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR0);
- if (cs->debug & L1_DEB_MONITOR)
- debugl1(cs, "ICC MOR0 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp - 1]);
- if (cs->dc.icc.mon_rxp == 1) {
- cs->dc.icc.mocr |= 0x04;
- cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
- }
- }
- afterMONR0:
- if (v1 & 0x80) {
- if (!cs->dc.icc.mon_rx) {
- if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "ICC MON RX out of memory!");
- cs->dc.icc.mocr &= 0x0f;
- cs->dc.icc.mocr |= 0xa0;
- cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
- goto afterMONR1;
- } else
- cs->dc.icc.mon_rxp = 0;
- }
- if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) {
- cs->dc.icc.mocr &= 0x0f;
- cs->dc.icc.mocr |= 0xa0;
- cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
- cs->dc.icc.mon_rxp = 0;
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "ICC MON RX overflow!");
- goto afterMONR1;
- }
- cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR1);
- if (cs->debug & L1_DEB_MONITOR)
- debugl1(cs, "ICC MOR1 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp - 1]);
- cs->dc.icc.mocr |= 0x40;
- cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
- }
- afterMONR1:
- if (v1 & 0x04) {
- cs->dc.icc.mocr &= 0xf0;
- cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
- cs->dc.icc.mocr |= 0x0a;
- cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
- schedule_event(cs, D_RX_MON0);
- }
- if (v1 & 0x40) {
- cs->dc.icc.mocr &= 0x0f;
- cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
- cs->dc.icc.mocr |= 0xa0;
- cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
- schedule_event(cs, D_RX_MON1);
- }
- if (v1 & 0x02) {
- if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc &&
- (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) &&
- !(v1 & 0x08))) {
- cs->dc.icc.mocr &= 0xf0;
- cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
- cs->dc.icc.mocr |= 0x0a;
- cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
- if (cs->dc.icc.mon_txc &&
- (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc))
- schedule_event(cs, D_TX_MON0);
- goto AfterMOX0;
- }
- if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) {
- schedule_event(cs, D_TX_MON0);
- goto AfterMOX0;
- }
- cs->writeisac(cs, ICC_MOX0,
- cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]);
- if (cs->debug & L1_DEB_MONITOR)
- debugl1(cs, "ICC %02x -> MOX0", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp - 1]);
- }
- AfterMOX0:
- if (v1 & 0x20) {
- if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc &&
- (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) &&
- !(v1 & 0x80))) {
- cs->dc.icc.mocr &= 0x0f;
- cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
- cs->dc.icc.mocr |= 0xa0;
- cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
- if (cs->dc.icc.mon_txc &&
- (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc))
- schedule_event(cs, D_TX_MON1);
- goto AfterMOX1;
- }
- if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) {
- schedule_event(cs, D_TX_MON1);
- goto AfterMOX1;
- }
- cs->writeisac(cs, ICC_MOX1,
- cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]);
- if (cs->debug & L1_DEB_MONITOR)
- debugl1(cs, "ICC %02x -> MOX1", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp - 1]);
- }
- AfterMOX1: ;
-#endif
- }
- }
-}
-
-static void
-ICC_l1hw(struct PStack *st, int pr, void *arg)
-{
- struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
- struct sk_buff *skb = arg;
- u_long flags;
- int val;
-
- switch (pr) {
- case (PH_DATA | REQUEST):
- if (cs->debug & DEB_DLOG_HEX)
- LogFrame(cs, skb->data, skb->len);
- if (cs->debug & DEB_DLOG_VERBOSE)
- dlogframe(cs, skb, 0);
- spin_lock_irqsave(&cs->lock, flags);
- if (cs->tx_skb) {
- skb_queue_tail(&cs->sq, skb);
-#ifdef L2FRAME_DEBUG /* psa */
- if (cs->debug & L1_DEB_LAPD)
- Logl2Frame(cs, skb, "PH_DATA Queued", 0);
-#endif
- } else {
- cs->tx_skb = skb;
- cs->tx_cnt = 0;
-#ifdef L2FRAME_DEBUG /* psa */
- if (cs->debug & L1_DEB_LAPD)
- Logl2Frame(cs, skb, "PH_DATA", 0);
-#endif
- icc_fill_fifo(cs);
- }
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (PH_PULL | INDICATION):
- spin_lock_irqsave(&cs->lock, flags);
- if (cs->tx_skb) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
- skb_queue_tail(&cs->sq, skb);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- }
- if (cs->debug & DEB_DLOG_HEX)
- LogFrame(cs, skb->data, skb->len);
- if (cs->debug & DEB_DLOG_VERBOSE)
- dlogframe(cs, skb, 0);
- cs->tx_skb = skb;
- cs->tx_cnt = 0;
-#ifdef L2FRAME_DEBUG /* psa */
- if (cs->debug & L1_DEB_LAPD)
- Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
-#endif
- icc_fill_fifo(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (PH_PULL | REQUEST):
-#ifdef L2FRAME_DEBUG /* psa */
- if (cs->debug & L1_DEB_LAPD)
- debugl1(cs, "-> PH_REQUEST_PULL");
-#endif
- if (!cs->tx_skb) {
- test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
- } else
- test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- break;
- case (HW_RESET | REQUEST):
- spin_lock_irqsave(&cs->lock, flags);
- if ((cs->dc.icc.ph_state == ICC_IND_EI1) ||
- (cs->dc.icc.ph_state == ICC_IND_DR))
- ph_command(cs, ICC_CMD_DI);
- else
- ph_command(cs, ICC_CMD_RES);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (HW_ENABLE | REQUEST):
- spin_lock_irqsave(&cs->lock, flags);
- ph_command(cs, ICC_CMD_DI);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (HW_INFO1 | REQUEST):
- spin_lock_irqsave(&cs->lock, flags);
- ph_command(cs, ICC_CMD_AR);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (HW_INFO3 | REQUEST):
- spin_lock_irqsave(&cs->lock, flags);
- ph_command(cs, ICC_CMD_AI);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (HW_TESTLOOP | REQUEST):
- spin_lock_irqsave(&cs->lock, flags);
- val = 0;
- if (1 & (long) arg)
- val |= 0x0c;
- if (2 & (long) arg)
- val |= 0x3;
- if (test_bit(HW_IOM1, &cs->HW_Flags)) {
- /* IOM 1 Mode */
- if (!val) {
- cs->writeisac(cs, ICC_SPCR, 0xa);
- cs->writeisac(cs, ICC_ADF1, 0x2);
- } else {
- cs->writeisac(cs, ICC_SPCR, val);
- cs->writeisac(cs, ICC_ADF1, 0xa);
- }
- } else {
- /* IOM 2 Mode */
- cs->writeisac(cs, ICC_SPCR, val);
- if (val)
- cs->writeisac(cs, ICC_ADF1, 0x8);
- else
- cs->writeisac(cs, ICC_ADF1, 0x0);
- }
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (HW_DEACTIVATE | RESPONSE):
- skb_queue_purge(&cs->rq);
- skb_queue_purge(&cs->sq);
- if (cs->tx_skb) {
- dev_kfree_skb_any(cs->tx_skb);
- cs->tx_skb = NULL;
- }
- if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
- del_timer(&cs->dbusytimer);
- if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
- schedule_event(cs, D_CLEARBUSY);
- break;
- default:
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "icc_l1hw unknown %04x", pr);
- break;
- }
-}
-
-static void
-setstack_icc(struct PStack *st, struct IsdnCardState *cs)
-{
- st->l1.l1hw = ICC_l1hw;
-}
-
-static void
-DC_Close_icc(struct IsdnCardState *cs) {
- kfree(cs->dc.icc.mon_rx);
- cs->dc.icc.mon_rx = NULL;
- kfree(cs->dc.icc.mon_tx);
- cs->dc.icc.mon_tx = NULL;
-}
-
-static void
-dbusy_timer_handler(struct timer_list *t)
-{
- struct IsdnCardState *cs = from_timer(cs, t, dbusytimer);
- struct PStack *stptr;
- int rbch, star;
-
- if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
- rbch = cs->readisac(cs, ICC_RBCH);
- star = cs->readisac(cs, ICC_STAR);
- if (cs->debug)
- debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x",
- rbch, star);
- if (rbch & ICC_RBCH_XAC) { /* D-Channel Busy */
- test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
- stptr = cs->stlist;
- while (stptr != NULL) {
- stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
- stptr = stptr->next;
- }
- } else {
- /* discard frame; reset transceiver */
- test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
- if (cs->tx_skb) {
- dev_kfree_skb_any(cs->tx_skb);
- cs->tx_cnt = 0;
- cs->tx_skb = NULL;
- } else {
- printk(KERN_WARNING "HiSax: ICC D-Channel Busy no skb\n");
- debugl1(cs, "D-Channel Busy no skb");
- }
- cs->writeisac(cs, ICC_CMDR, 0x01); /* Transmitter reset */
- cs->irq_func(cs->irq, cs);
- }
- }
-}
-
-void
-initicc(struct IsdnCardState *cs)
-{
- cs->setstack_d = setstack_icc;
- cs->DC_Close = DC_Close_icc;
- cs->dc.icc.mon_tx = NULL;
- cs->dc.icc.mon_rx = NULL;
- cs->writeisac(cs, ICC_MASK, 0xff);
- cs->dc.icc.mocr = 0xaa;
- if (test_bit(HW_IOM1, &cs->HW_Flags)) {
- /* IOM 1 Mode */
- cs->writeisac(cs, ICC_ADF2, 0x0);
- cs->writeisac(cs, ICC_SPCR, 0xa);
- cs->writeisac(cs, ICC_ADF1, 0x2);
- cs->writeisac(cs, ICC_STCR, 0x70);
- cs->writeisac(cs, ICC_MODE, 0xc9);
- } else {
- /* IOM 2 Mode */
- if (!cs->dc.icc.adf2)
- cs->dc.icc.adf2 = 0x80;
- cs->writeisac(cs, ICC_ADF2, cs->dc.icc.adf2);
- cs->writeisac(cs, ICC_SQXR, 0xa0);
- cs->writeisac(cs, ICC_SPCR, 0x20);
- cs->writeisac(cs, ICC_STCR, 0x70);
- cs->writeisac(cs, ICC_MODE, 0xca);
- cs->writeisac(cs, ICC_TIMR, 0x00);
- cs->writeisac(cs, ICC_ADF1, 0x20);
- }
- ph_command(cs, ICC_CMD_RES);
- cs->writeisac(cs, ICC_MASK, 0x0);
- ph_command(cs, ICC_CMD_DI);
-}
-
-void
-clear_pending_icc_ints(struct IsdnCardState *cs)
-{
- int val, eval;
-
- val = cs->readisac(cs, ICC_STAR);
- debugl1(cs, "ICC STAR %x", val);
- val = cs->readisac(cs, ICC_MODE);
- debugl1(cs, "ICC MODE %x", val);
- val = cs->readisac(cs, ICC_ADF2);
- debugl1(cs, "ICC ADF2 %x", val);
- val = cs->readisac(cs, ICC_ISTA);
- debugl1(cs, "ICC ISTA %x", val);
- if (val & 0x01) {
- eval = cs->readisac(cs, ICC_EXIR);
- debugl1(cs, "ICC EXIR %x", eval);
- }
- val = cs->readisac(cs, ICC_CIR0);
- debugl1(cs, "ICC CIR0 %x", val);
- cs->dc.icc.ph_state = (val >> 2) & 0xf;
- schedule_event(cs, D_L1STATECHANGE);
- /* Disable all IRQ */
- cs->writeisac(cs, ICC_MASK, 0xFF);
-}
-
-void setup_icc(struct IsdnCardState *cs)
-{
- INIT_WORK(&cs->tqueue, icc_bh);
- timer_setup(&cs->dbusytimer, dbusy_timer_handler, 0);
-}
diff --git a/drivers/isdn/hisax/icc.h b/drivers/isdn/hisax/icc.h
deleted file mode 100644
index f367df5d3669..000000000000
--- a/drivers/isdn/hisax/icc.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* $Id: icc.h,v 1.4.2.2 2004/01/12 22:52:26 keil Exp $
- *
- * ICC specific routines
- *
- * Author Matt Henderson & Guy Ellis
- * Copyright by Traverse Technologies Pty Ltd, www.travers.com.au
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * 1999.7.14 Initial implementation of routines for Siemens ISDN
- * Communication Controller PEB 2070 based on the ISAC routines
- * written by Karsten Keil.
- */
-
-/* All Registers original Siemens Spec */
-
-#define ICC_MASK 0x20
-#define ICC_ISTA 0x20
-#define ICC_STAR 0x21
-#define ICC_CMDR 0x21
-#define ICC_EXIR 0x24
-#define ICC_ADF2 0x39
-#define ICC_SPCR 0x30
-#define ICC_ADF1 0x38
-#define ICC_CIR0 0x31
-#define ICC_CIX0 0x31
-#define ICC_CIR1 0x33
-#define ICC_CIX1 0x33
-#define ICC_STCR 0x37
-#define ICC_MODE 0x22
-#define ICC_RSTA 0x27
-#define ICC_RBCL 0x25
-#define ICC_RBCH 0x2A
-#define ICC_TIMR 0x23
-#define ICC_SQXR 0x3b
-#define ICC_MOSR 0x3a
-#define ICC_MOCR 0x3a
-#define ICC_MOR0 0x32
-#define ICC_MOX0 0x32
-#define ICC_MOR1 0x34
-#define ICC_MOX1 0x34
-
-#define ICC_RBCH_XAC 0x80
-
-#define ICC_CMD_TIM 0x0
-#define ICC_CMD_RES 0x1
-#define ICC_CMD_DU 0x3
-#define ICC_CMD_EI1 0x4
-#define ICC_CMD_SSP 0x5
-#define ICC_CMD_DT 0x6
-#define ICC_CMD_AR 0x8
-#define ICC_CMD_ARL 0xA
-#define ICC_CMD_AI 0xC
-#define ICC_CMD_DI 0xF
-
-#define ICC_IND_DR 0x0
-#define ICC_IND_FJ 0x2
-#define ICC_IND_EI1 0x4
-#define ICC_IND_INT 0x6
-#define ICC_IND_PU 0x7
-#define ICC_IND_AR 0x8
-#define ICC_IND_ARL 0xA
-#define ICC_IND_AI 0xC
-#define ICC_IND_AIL 0xE
-#define ICC_IND_DC 0xF
-
-extern void ICCVersion(struct IsdnCardState *cs, char *s);
-extern void initicc(struct IsdnCardState *cs);
-extern void icc_interrupt(struct IsdnCardState *cs, u_char val);
-extern void clear_pending_icc_ints(struct IsdnCardState *cs);
-extern void setup_icc(struct IsdnCardState *);
diff --git a/drivers/isdn/hisax/ipac.h b/drivers/isdn/hisax/ipac.h
deleted file mode 100644
index 4f937f02ee34..000000000000
--- a/drivers/isdn/hisax/ipac.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* $Id: ipac.h,v 1.7.2.2 2004/01/12 22:52:26 keil Exp $
- *
- * IPAC specific defines
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-/* All Registers original Siemens Spec */
-
-#define IPAC_CONF 0xC0
-#define IPAC_MASK 0xC1
-#define IPAC_ISTA 0xC1
-#define IPAC_ID 0xC2
-#define IPAC_ACFG 0xC3
-#define IPAC_AOE 0xC4
-#define IPAC_ARX 0xC5
-#define IPAC_ATX 0xC5
-#define IPAC_PITA1 0xC6
-#define IPAC_PITA2 0xC7
-#define IPAC_POTA1 0xC8
-#define IPAC_POTA2 0xC9
-#define IPAC_PCFG 0xCA
-#define IPAC_SCFG 0xCB
-#define IPAC_TIMR2 0xCC
diff --git a/drivers/isdn/hisax/ipacx.c b/drivers/isdn/hisax/ipacx.c
deleted file mode 100644
index c7086c1534bd..000000000000
--- a/drivers/isdn/hisax/ipacx.c
+++ /dev/null
@@ -1,913 +0,0 @@
-/*
- *
- * IPACX specific routines
- *
- * Author Joerg Petersohn
- * Derived from hisax_isac.c, isac.c, hscx.c and others
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include "hisax_if.h"
-#include "hisax.h"
-#include "isdnl1.h"
-#include "ipacx.h"
-
-#define DBUSY_TIMER_VALUE 80
-#define TIMER3_VALUE 7000
-#define MAX_DFRAME_LEN_L1 300
-#define B_FIFO_SIZE 64
-#define D_FIFO_SIZE 32
-
-
-// ipacx interrupt mask values
-#define _MASK_IMASK 0x2E // global mask
-#define _MASKB_IMASK 0x0B
-#define _MASKD_IMASK 0x03 // all on
-
-//----------------------------------------------------------
-// local function declarations
-//----------------------------------------------------------
-static void ph_command(struct IsdnCardState *cs, unsigned int command);
-static inline void cic_int(struct IsdnCardState *cs);
-static void dch_l2l1(struct PStack *st, int pr, void *arg);
-static void dbusy_timer_handler(struct timer_list *t);
-static void dch_empty_fifo(struct IsdnCardState *cs, int count);
-static void dch_fill_fifo(struct IsdnCardState *cs);
-static inline void dch_int(struct IsdnCardState *cs);
-static void dch_setstack(struct PStack *st, struct IsdnCardState *cs);
-static void dch_init(struct IsdnCardState *cs);
-static void bch_l2l1(struct PStack *st, int pr, void *arg);
-static void bch_empty_fifo(struct BCState *bcs, int count);
-static void bch_fill_fifo(struct BCState *bcs);
-static void bch_int(struct IsdnCardState *cs, u_char hscx);
-static void bch_mode(struct BCState *bcs, int mode, int bc);
-static void bch_close_state(struct BCState *bcs);
-static int bch_open_state(struct IsdnCardState *cs, struct BCState *bcs);
-static int bch_setstack(struct PStack *st, struct BCState *bcs);
-static void bch_init(struct IsdnCardState *cs, int hscx);
-static void clear_pending_ints(struct IsdnCardState *cs);
-
-//----------------------------------------------------------
-// Issue Layer 1 command to chip
-//----------------------------------------------------------
-static void
-ph_command(struct IsdnCardState *cs, unsigned int command)
-{
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ph_command (%#x) in (%#x)", command,
- cs->dc.isac.ph_state);
-//###################################
-// printk(KERN_INFO "ph_command (%#x)\n", command);
-//###################################
- cs->writeisac(cs, IPACX_CIX0, (command << 4) | 0x0E);
-}
-
-//----------------------------------------------------------
-// Transceiver interrupt handler
-//----------------------------------------------------------
-static inline void
-cic_int(struct IsdnCardState *cs)
-{
- u_char event;
-
- event = cs->readisac(cs, IPACX_CIR0) >> 4;
- if (cs->debug & L1_DEB_ISAC) debugl1(cs, "cic_int(event=%#x)", event);
-//#########################################
-// printk(KERN_INFO "cic_int(%x)\n", event);
-//#########################################
- cs->dc.isac.ph_state = event;
- schedule_event(cs, D_L1STATECHANGE);
-}
-
-//==========================================================
-// D channel functions
-//==========================================================
-
-//----------------------------------------------------------
-// Command entry point
-//----------------------------------------------------------
-static void
-dch_l2l1(struct PStack *st, int pr, void *arg)
-{
- struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
- struct sk_buff *skb = arg;
- u_char cda1_cr;
-
- switch (pr) {
- case (PH_DATA | REQUEST):
- if (cs->debug & DEB_DLOG_HEX) LogFrame(cs, skb->data, skb->len);
- if (cs->debug & DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0);
- if (cs->tx_skb) {
- skb_queue_tail(&cs->sq, skb);
-#ifdef L2FRAME_DEBUG
- if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA Queued", 0);
-#endif
- } else {
- cs->tx_skb = skb;
- cs->tx_cnt = 0;
-#ifdef L2FRAME_DEBUG
- if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA", 0);
-#endif
- dch_fill_fifo(cs);
- }
- break;
-
- case (PH_PULL | INDICATION):
- if (cs->tx_skb) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
- skb_queue_tail(&cs->sq, skb);
- break;
- }
- if (cs->debug & DEB_DLOG_HEX) LogFrame(cs, skb->data, skb->len);
- if (cs->debug & DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0);
- cs->tx_skb = skb;
- cs->tx_cnt = 0;
-#ifdef L2FRAME_DEBUG
- if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
-#endif
- dch_fill_fifo(cs);
- break;
-
- case (PH_PULL | REQUEST):
-#ifdef L2FRAME_DEBUG
- if (cs->debug & L1_DEB_LAPD) debugl1(cs, "-> PH_REQUEST_PULL");
-#endif
- if (!cs->tx_skb) {
- clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
- } else
- set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- break;
-
- case (HW_RESET | REQUEST):
- case (HW_ENABLE | REQUEST):
- if ((cs->dc.isac.ph_state == IPACX_IND_RES) ||
- (cs->dc.isac.ph_state == IPACX_IND_DR) ||
- (cs->dc.isac.ph_state == IPACX_IND_DC))
- ph_command(cs, IPACX_CMD_TIM);
- else
- ph_command(cs, IPACX_CMD_RES);
- break;
-
- case (HW_INFO3 | REQUEST):
- ph_command(cs, IPACX_CMD_AR8);
- break;
-
- case (HW_TESTLOOP | REQUEST):
- cs->writeisac(cs, IPACX_CDA_TSDP10, 0x80); // Timeslot 0 is B1
- cs->writeisac(cs, IPACX_CDA_TSDP11, 0x81); // Timeslot 0 is B1
- cda1_cr = cs->readisac(cs, IPACX_CDA1_CR);
- (void) cs->readisac(cs, IPACX_CDA2_CR);
- if ((long)arg & 1) { // loop B1
- cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr | 0x0a);
- }
- else { // B1 off
- cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr & ~0x0a);
- }
- if ((long)arg & 2) { // loop B2
- cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr | 0x14);
- }
- else { // B2 off
- cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr & ~0x14);
- }
- break;
-
- case (HW_DEACTIVATE | RESPONSE):
- skb_queue_purge(&cs->rq);
- skb_queue_purge(&cs->sq);
- if (cs->tx_skb) {
- dev_kfree_skb_any(cs->tx_skb);
- cs->tx_skb = NULL;
- }
- if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
- del_timer(&cs->dbusytimer);
- break;
-
- default:
- if (cs->debug & L1_DEB_WARN) debugl1(cs, "dch_l2l1 unknown %04x", pr);
- break;
- }
-}
-
-//----------------------------------------------------------
-//----------------------------------------------------------
-static void
-dbusy_timer_handler(struct timer_list *t)
-{
- struct IsdnCardState *cs = from_timer(cs, t, dbusytimer);
- struct PStack *st;
- int rbchd, stard;
-
- if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
- rbchd = cs->readisac(cs, IPACX_RBCHD);
- stard = cs->readisac(cs, IPACX_STARD);
- if (cs->debug)
- debugl1(cs, "D-Channel Busy RBCHD %02x STARD %02x", rbchd, stard);
- if (!(stard & 0x40)) { // D-Channel Busy
- set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
- for (st = cs->stlist; st; st = st->next) {
- st->l1.l1l2(st, PH_PAUSE | INDICATION, NULL); // flow control on
- }
- } else {
- // seems we lost an interrupt; reset transceiver */
- clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
- if (cs->tx_skb) {
- dev_kfree_skb_any(cs->tx_skb);
- cs->tx_cnt = 0;
- cs->tx_skb = NULL;
- } else {
- printk(KERN_WARNING "HiSax: ISAC D-Channel Busy no skb\n");
- debugl1(cs, "D-Channel Busy no skb");
- }
- cs->writeisac(cs, IPACX_CMDRD, 0x01); // Tx reset, generates XPR
- }
- }
-}
-
-//----------------------------------------------------------
-// Fill buffer from receive FIFO
-//----------------------------------------------------------
-static void
-dch_empty_fifo(struct IsdnCardState *cs, int count)
-{
- u_char *ptr;
-
- if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
- debugl1(cs, "dch_empty_fifo()");
-
- // message too large, remove
- if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "dch_empty_fifo() incoming message too large");
- cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC
- cs->rcvidx = 0;
- return;
- }
-
- ptr = cs->rcvbuf + cs->rcvidx;
- cs->rcvidx += count;
-
- cs->readisacfifo(cs, ptr, count);
- cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC
-
- if (cs->debug & L1_DEB_ISAC_FIFO) {
- char *t = cs->dlog;
-
- t += sprintf(t, "dch_empty_fifo() cnt %d", count);
- QuickHex(t, ptr, count);
- debugl1(cs, "%s", cs->dlog);
- }
-}
-
-//----------------------------------------------------------
-// Fill transmit FIFO
-//----------------------------------------------------------
-static void
-dch_fill_fifo(struct IsdnCardState *cs)
-{
- int count;
- u_char cmd, *ptr;
-
- if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
- debugl1(cs, "dch_fill_fifo()");
-
- if (!cs->tx_skb) return;
- count = cs->tx_skb->len;
- if (count <= 0) return;
-
- if (count > D_FIFO_SIZE) {
- count = D_FIFO_SIZE;
- cmd = 0x08; // XTF
- } else {
- cmd = 0x0A; // XTF | XME
- }
-
- ptr = cs->tx_skb->data;
- skb_pull(cs->tx_skb, count);
- cs->tx_cnt += count;
- cs->writeisacfifo(cs, ptr, count);
- cs->writeisac(cs, IPACX_CMDRD, cmd);
-
- // set timeout for transmission contol
- if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
- debugl1(cs, "dch_fill_fifo dbusytimer running");
- del_timer(&cs->dbusytimer);
- }
- cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
- add_timer(&cs->dbusytimer);
-
- if (cs->debug & L1_DEB_ISAC_FIFO) {
- char *t = cs->dlog;
-
- t += sprintf(t, "dch_fill_fifo() cnt %d", count);
- QuickHex(t, ptr, count);
- debugl1(cs, "%s", cs->dlog);
- }
-}
-
-//----------------------------------------------------------
-// D channel interrupt handler
-//----------------------------------------------------------
-static inline void
-dch_int(struct IsdnCardState *cs)
-{
- struct sk_buff *skb;
- u_char istad, rstad;
- int count;
-
- istad = cs->readisac(cs, IPACX_ISTAD);
-//##############################################
-// printk(KERN_WARNING "dch_int(istad=%02x)\n", istad);
-//##############################################
-
- if (istad & 0x80) { // RME
- rstad = cs->readisac(cs, IPACX_RSTAD);
- if ((rstad & 0xf0) != 0xa0) { // !(VFR && !RDO && CRC && !RAB)
- if (!(rstad & 0x80))
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "dch_int(): invalid frame");
- if ((rstad & 0x40))
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "dch_int(): RDO");
- if (!(rstad & 0x20))
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "dch_int(): CRC error");
- cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC
- } else { // received frame ok
- count = cs->readisac(cs, IPACX_RBCLD);
- if (count) count--; // RSTAB is last byte
- count &= D_FIFO_SIZE - 1;
- if (count == 0) count = D_FIFO_SIZE;
- dch_empty_fifo(cs, count);
- if ((count = cs->rcvidx) > 0) {
- cs->rcvidx = 0;
- if (!(skb = dev_alloc_skb(count)))
- printk(KERN_WARNING "HiSax dch_int(): receive out of memory\n");
- else {
- skb_put_data(skb, cs->rcvbuf, count);
- skb_queue_tail(&cs->rq, skb);
- }
- }
- }
- cs->rcvidx = 0;
- schedule_event(cs, D_RCVBUFREADY);
- }
-
- if (istad & 0x40) { // RPF
- dch_empty_fifo(cs, D_FIFO_SIZE);
- }
-
- if (istad & 0x20) { // RFO
- if (cs->debug & L1_DEB_WARN) debugl1(cs, "dch_int(): RFO");
- cs->writeisac(cs, IPACX_CMDRD, 0x40); //RRES
- }
-
- if (istad & 0x10) { // XPR
- if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
- del_timer(&cs->dbusytimer);
- if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
- schedule_event(cs, D_CLEARBUSY);
- if (cs->tx_skb) {
- if (cs->tx_skb->len) {
- dch_fill_fifo(cs);
- goto afterXPR;
- }
- else {
- dev_kfree_skb_irq(cs->tx_skb);
- cs->tx_skb = NULL;
- cs->tx_cnt = 0;
- }
- }
- if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
- cs->tx_cnt = 0;
- dch_fill_fifo(cs);
- }
- else {
- schedule_event(cs, D_XMTBUFREADY);
- }
- }
-afterXPR:
-
- if (istad & 0x0C) { // XDU or XMR
- if (cs->debug & L1_DEB_WARN) debugl1(cs, "dch_int(): XDU");
- if (cs->tx_skb) {
- skb_push(cs->tx_skb, cs->tx_cnt); // retransmit
- cs->tx_cnt = 0;
- dch_fill_fifo(cs);
- } else {
- printk(KERN_WARNING "HiSax: ISAC XDU no skb\n");
- debugl1(cs, "ISAC XDU no skb");
- }
- }
-}
-
-//----------------------------------------------------------
-//----------------------------------------------------------
-static void
-dch_setstack(struct PStack *st, struct IsdnCardState *cs)
-{
- st->l1.l1hw = dch_l2l1;
-}
-
-//----------------------------------------------------------
-//----------------------------------------------------------
-static void
-dch_init(struct IsdnCardState *cs)
-{
- printk(KERN_INFO "HiSax: IPACX ISDN driver v0.1.0\n");
-
- cs->setstack_d = dch_setstack;
-
- timer_setup(&cs->dbusytimer, dbusy_timer_handler, 0);
-
- cs->writeisac(cs, IPACX_TR_CONF0, 0x00); // clear LDD
- cs->writeisac(cs, IPACX_TR_CONF2, 0x00); // enable transmitter
- cs->writeisac(cs, IPACX_MODED, 0xC9); // transparent mode 0, RAC, stop/go
- cs->writeisac(cs, IPACX_MON_CR, 0x00); // disable monitor channel
-}
-
-
-//==========================================================
-// B channel functions
-//==========================================================
-
-//----------------------------------------------------------
-// Entry point for commands
-//----------------------------------------------------------
-static void
-bch_l2l1(struct PStack *st, int pr, void *arg)
-{
- struct BCState *bcs = st->l1.bcs;
- struct sk_buff *skb = arg;
- u_long flags;
-
- switch (pr) {
- case (PH_DATA | REQUEST):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- if (bcs->tx_skb) {
- skb_queue_tail(&bcs->squeue, skb);
- } else {
- bcs->tx_skb = skb;
- set_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->hw.hscx.count = 0;
- bch_fill_fifo(bcs);
- }
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- break;
- case (PH_PULL | INDICATION):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- if (bcs->tx_skb) {
- printk(KERN_WARNING "HiSax bch_l2l1(): this shouldn't happen\n");
- } else {
- set_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->tx_skb = skb;
- bcs->hw.hscx.count = 0;
- bch_fill_fifo(bcs);
- }
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- break;
- case (PH_PULL | REQUEST):
- if (!bcs->tx_skb) {
- clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
- } else
- set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- break;
- case (PH_ACTIVATE | REQUEST):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- set_bit(BC_FLG_ACTIV, &bcs->Flag);
- bch_mode(bcs, st->l1.mode, st->l1.bc);
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- l1_msg_b(st, pr, arg);
- break;
- case (PH_DEACTIVATE | REQUEST):
- l1_msg_b(st, pr, arg);
- break;
- case (PH_DEACTIVATE | CONFIRM):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- clear_bit(BC_FLG_ACTIV, &bcs->Flag);
- clear_bit(BC_FLG_BUSY, &bcs->Flag);
- bch_mode(bcs, 0, st->l1.bc);
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
- break;
- }
-}
-
-//----------------------------------------------------------
-// Read B channel fifo to receive buffer
-//----------------------------------------------------------
-static void
-bch_empty_fifo(struct BCState *bcs, int count)
-{
- u_char *ptr, hscx;
- struct IsdnCardState *cs;
- int cnt;
-
- cs = bcs->cs;
- hscx = bcs->hw.hscx.hscx;
- if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
- debugl1(cs, "bch_empty_fifo()");
-
- // message too large, remove
- if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "bch_empty_fifo() incoming packet too large");
- cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80); // RMC
- bcs->hw.hscx.rcvidx = 0;
- return;
- }
-
- ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
- cnt = count;
- while (cnt--) *ptr++ = cs->BC_Read_Reg(cs, hscx, IPACX_RFIFOB);
- cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80); // RMC
-
- ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
- bcs->hw.hscx.rcvidx += count;
-
- if (cs->debug & L1_DEB_HSCX_FIFO) {
- char *t = bcs->blog;
-
- t += sprintf(t, "bch_empty_fifo() B-%d cnt %d", hscx, count);
- QuickHex(t, ptr, count);
- debugl1(cs, "%s", bcs->blog);
- }
-}
-
-//----------------------------------------------------------
-// Fill buffer to transmit FIFO
-//----------------------------------------------------------
-static void
-bch_fill_fifo(struct BCState *bcs)
-{
- struct IsdnCardState *cs;
- int more, count, cnt;
- u_char *ptr, *p, hscx;
-
- cs = bcs->cs;
- if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
- debugl1(cs, "bch_fill_fifo()");
-
- if (!bcs->tx_skb) return;
- if (bcs->tx_skb->len <= 0) return;
-
- hscx = bcs->hw.hscx.hscx;
- more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
- if (bcs->tx_skb->len > B_FIFO_SIZE) {
- more = 1;
- count = B_FIFO_SIZE;
- } else {
- count = bcs->tx_skb->len;
- }
- cnt = count;
-
- p = ptr = bcs->tx_skb->data;
- skb_pull(bcs->tx_skb, count);
- bcs->tx_cnt -= count;
- bcs->hw.hscx.count += count;
- while (cnt--) cs->BC_Write_Reg(cs, hscx, IPACX_XFIFOB, *p++);
- cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, (more ? 0x08 : 0x0a));
-
- if (cs->debug & L1_DEB_HSCX_FIFO) {
- char *t = bcs->blog;
-
- t += sprintf(t, "%s() B-%d cnt %d", __func__, hscx, count);
- QuickHex(t, ptr, count);
- debugl1(cs, "%s", bcs->blog);
- }
-}
-
-//----------------------------------------------------------
-// B channel interrupt handler
-//----------------------------------------------------------
-static void
-bch_int(struct IsdnCardState *cs, u_char hscx)
-{
- u_char istab;
- struct BCState *bcs;
- struct sk_buff *skb;
- int count;
- u_char rstab;
-
- bcs = cs->bcs + hscx;
- istab = cs->BC_Read_Reg(cs, hscx, IPACX_ISTAB);
-//##############################################
-// printk(KERN_WARNING "bch_int(istab=%02x)\n", istab);
-//##############################################
- if (!test_bit(BC_FLG_INIT, &bcs->Flag)) return;
-
- if (istab & 0x80) { // RME
- rstab = cs->BC_Read_Reg(cs, hscx, IPACX_RSTAB);
- if ((rstab & 0xf0) != 0xa0) { // !(VFR && !RDO && CRC && !RAB)
- if (!(rstab & 0x80))
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "bch_int() B-%d: invalid frame", hscx);
- if ((rstab & 0x40) && (bcs->mode != L1_MODE_NULL))
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "bch_int() B-%d: RDO mode=%d", hscx, bcs->mode);
- if (!(rstab & 0x20))
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "bch_int() B-%d: CRC error", hscx);
- cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80); // RMC
- }
- else { // received frame ok
- count = cs->BC_Read_Reg(cs, hscx, IPACX_RBCLB) & (B_FIFO_SIZE - 1);
- if (count == 0) count = B_FIFO_SIZE;
- bch_empty_fifo(bcs, count);
- if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
- if (cs->debug & L1_DEB_HSCX_FIFO)
- debugl1(cs, "bch_int Frame %d", count);
- if (!(skb = dev_alloc_skb(count)))
- printk(KERN_WARNING "HiSax bch_int(): receive frame out of memory\n");
- else {
- skb_put_data(skb, bcs->hw.hscx.rcvbuf,
- count);
- skb_queue_tail(&bcs->rqueue, skb);
- }
- }
- }
- bcs->hw.hscx.rcvidx = 0;
- schedule_event(bcs, B_RCVBUFREADY);
- }
-
- if (istab & 0x40) { // RPF
- bch_empty_fifo(bcs, B_FIFO_SIZE);
-
- if (bcs->mode == L1_MODE_TRANS) { // queue every chunk
- // receive transparent audio data
- if (!(skb = dev_alloc_skb(B_FIFO_SIZE)))
- printk(KERN_WARNING "HiSax bch_int(): receive transparent out of memory\n");
- else {
- skb_put_data(skb, bcs->hw.hscx.rcvbuf,
- B_FIFO_SIZE);
- skb_queue_tail(&bcs->rqueue, skb);
- }
- bcs->hw.hscx.rcvidx = 0;
- schedule_event(bcs, B_RCVBUFREADY);
- }
- }
-
- if (istab & 0x20) { // RFO
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "bch_int() B-%d: RFO error", hscx);
- cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x40); // RRES
- }
-
- if (istab & 0x10) { // XPR
- if (bcs->tx_skb) {
- if (bcs->tx_skb->len) {
- bch_fill_fifo(bcs);
- goto afterXPR;
- } else {
- if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
- (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
- u_long flags;
- spin_lock_irqsave(&bcs->aclock, flags);
- bcs->ackcnt += bcs->hw.hscx.count;
- spin_unlock_irqrestore(&bcs->aclock, flags);
- schedule_event(bcs, B_ACKPENDING);
- }
- }
- dev_kfree_skb_irq(bcs->tx_skb);
- bcs->hw.hscx.count = 0;
- bcs->tx_skb = NULL;
- }
- if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
- bcs->hw.hscx.count = 0;
- set_bit(BC_FLG_BUSY, &bcs->Flag);
- bch_fill_fifo(bcs);
- } else {
- clear_bit(BC_FLG_BUSY, &bcs->Flag);
- schedule_event(bcs, B_XMTBUFREADY);
- }
- }
-afterXPR:
-
- if (istab & 0x04) { // XDU
- if (bcs->mode == L1_MODE_TRANS) {
- bch_fill_fifo(bcs);
- }
- else {
- if (bcs->tx_skb) { // restart transmitting the whole frame
- skb_push(bcs->tx_skb, bcs->hw.hscx.count);
- bcs->tx_cnt += bcs->hw.hscx.count;
- bcs->hw.hscx.count = 0;
- }
- cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x01); // XRES
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "bch_int() B-%d XDU error", hscx);
- }
- }
-}
-
-//----------------------------------------------------------
-//----------------------------------------------------------
-static void
-bch_mode(struct BCState *bcs, int mode, int bc)
-{
- struct IsdnCardState *cs = bcs->cs;
- int hscx = bcs->hw.hscx.hscx;
-
- bc = bc ? 1 : 0; // in case bc is greater than 1
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "mode_bch() switch B-%d mode %d chan %d", hscx, mode, bc);
- bcs->mode = mode;
- bcs->channel = bc;
-
- // map controller to according timeslot
- if (!hscx)
- {
- cs->writeisac(cs, IPACX_BCHA_TSDP_BC1, 0x80 | bc);
- cs->writeisac(cs, IPACX_BCHA_CR, 0x88);
- }
- else
- {
- cs->writeisac(cs, IPACX_BCHB_TSDP_BC1, 0x80 | bc);
- cs->writeisac(cs, IPACX_BCHB_CR, 0x88);
- }
-
- switch (mode) {
- case (L1_MODE_NULL):
- cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0xC0); // rec off
- cs->BC_Write_Reg(cs, hscx, IPACX_EXMB, 0x30); // std adj.
- cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, 0xFF); // ints off
- cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41); // validate adjustments
- break;
- case (L1_MODE_TRANS):
- cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0x88); // ext transp mode
- cs->BC_Write_Reg(cs, hscx, IPACX_EXMB, 0x00); // xxx00000
- cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41); // validate adjustments
- cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, _MASKB_IMASK);
- break;
- case (L1_MODE_HDLC):
- cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0xC8); // transp mode 0
- cs->BC_Write_Reg(cs, hscx, IPACX_EXMB, 0x01); // idle=hdlc flags crc enabled
- cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41); // validate adjustments
- cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, _MASKB_IMASK);
- break;
- }
-}
-
-//----------------------------------------------------------
-//----------------------------------------------------------
-static void
-bch_close_state(struct BCState *bcs)
-{
- bch_mode(bcs, 0, bcs->channel);
- if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
- kfree(bcs->hw.hscx.rcvbuf);
- bcs->hw.hscx.rcvbuf = NULL;
- kfree(bcs->blog);
- bcs->blog = NULL;
- skb_queue_purge(&bcs->rqueue);
- skb_queue_purge(&bcs->squeue);
- if (bcs->tx_skb) {
- dev_kfree_skb_any(bcs->tx_skb);
- bcs->tx_skb = NULL;
- clear_bit(BC_FLG_BUSY, &bcs->Flag);
- }
- }
-}
-
-//----------------------------------------------------------
-//----------------------------------------------------------
-static int
-bch_open_state(struct IsdnCardState *cs, struct BCState *bcs)
-{
- if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
- if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
- printk(KERN_WARNING
- "HiSax open_bchstate(): No memory for hscx.rcvbuf\n");
- clear_bit(BC_FLG_INIT, &bcs->Flag);
- return (1);
- }
- if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
- printk(KERN_WARNING
- "HiSax open_bchstate: No memory for bcs->blog\n");
- clear_bit(BC_FLG_INIT, &bcs->Flag);
- kfree(bcs->hw.hscx.rcvbuf);
- bcs->hw.hscx.rcvbuf = NULL;
- return (2);
- }
- skb_queue_head_init(&bcs->rqueue);
- skb_queue_head_init(&bcs->squeue);
- }
- bcs->tx_skb = NULL;
- clear_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->event = 0;
- bcs->hw.hscx.rcvidx = 0;
- bcs->tx_cnt = 0;
- return (0);
-}
-
-//----------------------------------------------------------
-//----------------------------------------------------------
-static int
-bch_setstack(struct PStack *st, struct BCState *bcs)
-{
- bcs->channel = st->l1.bc;
- if (bch_open_state(st->l1.hardware, bcs)) return (-1);
- st->l1.bcs = bcs;
- st->l2.l2l1 = bch_l2l1;
- setstack_manager(st);
- bcs->st = st;
- setstack_l1_B(st);
- return (0);
-}
-
-//----------------------------------------------------------
-//----------------------------------------------------------
-static void
-bch_init(struct IsdnCardState *cs, int hscx)
-{
- cs->bcs[hscx].BC_SetStack = bch_setstack;
- cs->bcs[hscx].BC_Close = bch_close_state;
- cs->bcs[hscx].hw.hscx.hscx = hscx;
- cs->bcs[hscx].cs = cs;
- bch_mode(cs->bcs + hscx, 0, hscx);
-}
-
-
-//==========================================================
-// Shared functions
-//==========================================================
-
-//----------------------------------------------------------
-// Main interrupt handler
-//----------------------------------------------------------
-void
-interrupt_ipacx(struct IsdnCardState *cs)
-{
- u_char ista;
-
- while ((ista = cs->readisac(cs, IPACX_ISTA))) {
-//#################################################
-// printk(KERN_WARNING "interrupt_ipacx(ista=%02x)\n", ista);
-//#################################################
- if (ista & 0x80) bch_int(cs, 0); // B channel interrupts
- if (ista & 0x40) bch_int(cs, 1);
-
- if (ista & 0x01) dch_int(cs); // D channel
- if (ista & 0x10) cic_int(cs); // Layer 1 state
- }
-}
-
-//----------------------------------------------------------
-// Clears chip interrupt status
-//----------------------------------------------------------
-static void
-clear_pending_ints(struct IsdnCardState *cs)
-{
- int ista;
-
- // all interrupts off
- cs->writeisac(cs, IPACX_MASK, 0xff);
- cs->writeisac(cs, IPACX_MASKD, 0xff);
- cs->BC_Write_Reg(cs, 0, IPACX_MASKB, 0xff);
- cs->BC_Write_Reg(cs, 1, IPACX_MASKB, 0xff);
-
- ista = cs->readisac(cs, IPACX_ISTA);
- if (ista & 0x80) cs->BC_Read_Reg(cs, 0, IPACX_ISTAB);
- if (ista & 0x40) cs->BC_Read_Reg(cs, 1, IPACX_ISTAB);
- if (ista & 0x10) cs->readisac(cs, IPACX_CIR0);
- if (ista & 0x01) cs->readisac(cs, IPACX_ISTAD);
-}
-
-//----------------------------------------------------------
-// Does chip configuration work
-// Work to do depends on bit mask in part
-//----------------------------------------------------------
-void
-init_ipacx(struct IsdnCardState *cs, int part)
-{
- if (part & 1) { // initialise chip
-//##################################################
-// printk(KERN_INFO "init_ipacx(%x)\n", part);
-//##################################################
- clear_pending_ints(cs);
- bch_init(cs, 0);
- bch_init(cs, 1);
- dch_init(cs);
- }
- if (part & 2) { // reenable all interrupts and start chip
- cs->BC_Write_Reg(cs, 0, IPACX_MASKB, _MASKB_IMASK);
- cs->BC_Write_Reg(cs, 1, IPACX_MASKB, _MASKB_IMASK);
- cs->writeisac(cs, IPACX_MASKD, _MASKD_IMASK);
- cs->writeisac(cs, IPACX_MASK, _MASK_IMASK); // global mask register
-
- // reset HDLC Transmitters/receivers
- cs->writeisac(cs, IPACX_CMDRD, 0x41);
- cs->BC_Write_Reg(cs, 0, IPACX_CMDRB, 0x41);
- cs->BC_Write_Reg(cs, 1, IPACX_CMDRB, 0x41);
- ph_command(cs, IPACX_CMD_RES);
- }
-}
-
-//----------------- end of file -----------------------
diff --git a/drivers/isdn/hisax/ipacx.h b/drivers/isdn/hisax/ipacx.h
deleted file mode 100644
index e8a22e8f34b6..000000000000
--- a/drivers/isdn/hisax/ipacx.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- *
- * IPACX specific defines
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-/* All Registers original Siemens Spec */
-
-#ifndef INCLUDE_IPACX_H
-#define INCLUDE_IPACX_H
-
-/* D-channel registers */
-#define IPACX_RFIFOD 0x00 /* RD */
-#define IPACX_XFIFOD 0x00 /* WR */
-#define IPACX_ISTAD 0x20 /* RD */
-#define IPACX_MASKD 0x20 /* WR */
-#define IPACX_STARD 0x21 /* RD */
-#define IPACX_CMDRD 0x21 /* WR */
-#define IPACX_MODED 0x22 /* RD/WR */
-#define IPACX_EXMD1 0x23 /* RD/WR */
-#define IPACX_TIMR1 0x24 /* RD/WR */
-#define IPACX_SAP1 0x25 /* WR */
-#define IPACX_SAP2 0x26 /* WR */
-#define IPACX_RBCLD 0x26 /* RD */
-#define IPACX_RBCHD 0x27 /* RD */
-#define IPACX_TEI1 0x27 /* WR */
-#define IPACX_TEI2 0x28 /* WR */
-#define IPACX_RSTAD 0x28 /* RD */
-#define IPACX_TMD 0x29 /* RD/WR */
-#define IPACX_CIR0 0x2E /* RD */
-#define IPACX_CIX0 0x2E /* WR */
-#define IPACX_CIR1 0x2F /* RD */
-#define IPACX_CIX1 0x2F /* WR */
-
-/* Transceiver registers */
-#define IPACX_TR_CONF0 0x30 /* RD/WR */
-#define IPACX_TR_CONF1 0x31 /* RD/WR */
-#define IPACX_TR_CONF2 0x32 /* RD/WR */
-#define IPACX_TR_STA 0x33 /* RD */
-#define IPACX_TR_CMD 0x34 /* RD/WR */
-#define IPACX_SQRR1 0x35 /* RD */
-#define IPACX_SQXR1 0x35 /* WR */
-#define IPACX_SQRR2 0x36 /* RD */
-#define IPACX_SQXR2 0x36 /* WR */
-#define IPACX_SQRR3 0x37 /* RD */
-#define IPACX_SQXR3 0x37 /* WR */
-#define IPACX_ISTATR 0x38 /* RD */
-#define IPACX_MASKTR 0x39 /* RD/WR */
-#define IPACX_TR_MODE 0x3A /* RD/WR */
-#define IPACX_ACFG1 0x3C /* RD/WR */
-#define IPACX_ACFG2 0x3D /* RD/WR */
-#define IPACX_AOE 0x3E /* RD/WR */
-#define IPACX_ARX 0x3F /* RD */
-#define IPACX_ATX 0x3F /* WR */
-
-/* IOM: Timeslot, DPS, CDA */
-#define IPACX_CDA10 0x40 /* RD/WR */
-#define IPACX_CDA11 0x41 /* RD/WR */
-#define IPACX_CDA20 0x42 /* RD/WR */
-#define IPACX_CDA21 0x43 /* RD/WR */
-#define IPACX_CDA_TSDP10 0x44 /* RD/WR */
-#define IPACX_CDA_TSDP11 0x45 /* RD/WR */
-#define IPACX_CDA_TSDP20 0x46 /* RD/WR */
-#define IPACX_CDA_TSDP21 0x47 /* RD/WR */
-#define IPACX_BCHA_TSDP_BC1 0x48 /* RD/WR */
-#define IPACX_BCHA_TSDP_BC2 0x49 /* RD/WR */
-#define IPACX_BCHB_TSDP_BC1 0x4A /* RD/WR */
-#define IPACX_BCHB_TSDP_BC2 0x4B /* RD/WR */
-#define IPACX_TR_TSDP_BC1 0x4C /* RD/WR */
-#define IPACX_TR_TSDP_BC2 0x4D /* RD/WR */
-#define IPACX_CDA1_CR 0x4E /* RD/WR */
-#define IPACX_CDA2_CR 0x4F /* RD/WR */
-
-/* IOM: Contol, Sync transfer, Monitor */
-#define IPACX_TR_CR 0x50 /* RD/WR */
-#define IPACX_TRC_CR 0x50 /* RD/WR */
-#define IPACX_BCHA_CR 0x51 /* RD/WR */
-#define IPACX_BCHB_CR 0x52 /* RD/WR */
-#define IPACX_DCI_CR 0x53 /* RD/WR */
-#define IPACX_DCIC_CR 0x53 /* RD/WR */
-#define IPACX_MON_CR 0x54 /* RD/WR */
-#define IPACX_SDS1_CR 0x55 /* RD/WR */
-#define IPACX_SDS2_CR 0x56 /* RD/WR */
-#define IPACX_IOM_CR 0x57 /* RD/WR */
-#define IPACX_STI 0x58 /* RD */
-#define IPACX_ASTI 0x58 /* WR */
-#define IPACX_MSTI 0x59 /* RD/WR */
-#define IPACX_SDS_CONF 0x5A /* RD/WR */
-#define IPACX_MCDA 0x5B /* RD */
-#define IPACX_MOR 0x5C /* RD */
-#define IPACX_MOX 0x5C /* WR */
-#define IPACX_MOSR 0x5D /* RD */
-#define IPACX_MOCR 0x5E /* RD/WR */
-#define IPACX_MSTA 0x5F /* RD */
-#define IPACX_MCONF 0x5F /* WR */
-
-/* Interrupt and general registers */
-#define IPACX_ISTA 0x60 /* RD */
-#define IPACX_MASK 0x60 /* WR */
-#define IPACX_AUXI 0x61 /* RD */
-#define IPACX_AUXM 0x61 /* WR */
-#define IPACX_MODE1 0x62 /* RD/WR */
-#define IPACX_MODE2 0x63 /* RD/WR */
-#define IPACX_ID 0x64 /* RD */
-#define IPACX_SRES 0x64 /* WR */
-#define IPACX_TIMR2 0x65 /* RD/WR */
-
-/* B-channel registers */
-#define IPACX_OFF_B1 0x70
-#define IPACX_OFF_B2 0x80
-
-#define IPACX_ISTAB 0x00 /* RD */
-#define IPACX_MASKB 0x00 /* WR */
-#define IPACX_STARB 0x01 /* RD */
-#define IPACX_CMDRB 0x01 /* WR */
-#define IPACX_MODEB 0x02 /* RD/WR */
-#define IPACX_EXMB 0x03 /* RD/WR */
-#define IPACX_RAH1 0x05 /* WR */
-#define IPACX_RAH2 0x06 /* WR */
-#define IPACX_RBCLB 0x06 /* RD */
-#define IPACX_RBCHB 0x07 /* RD */
-#define IPACX_RAL1 0x07 /* WR */
-#define IPACX_RAL2 0x08 /* WR */
-#define IPACX_RSTAB 0x08 /* RD */
-#define IPACX_TMB 0x09 /* RD/WR */
-#define IPACX_RFIFOB 0x0A /*- RD */
-#define IPACX_XFIFOB 0x0A /*- WR */
-
-/* Layer 1 Commands */
-#define IPACX_CMD_TIM 0x0
-#define IPACX_CMD_RES 0x1
-#define IPACX_CMD_SSP 0x2
-#define IPACX_CMD_SCP 0x3
-#define IPACX_CMD_AR8 0x8
-#define IPACX_CMD_AR10 0x9
-#define IPACX_CMD_ARL 0xa
-#define IPACX_CMD_DI 0xf
-
-/* Layer 1 Indications */
-#define IPACX_IND_DR 0x0
-#define IPACX_IND_RES 0x1
-#define IPACX_IND_TMA 0x2
-#define IPACX_IND_SLD 0x3
-#define IPACX_IND_RSY 0x4
-#define IPACX_IND_DR6 0x5
-#define IPACX_IND_PU 0x7
-#define IPACX_IND_AR 0x8
-#define IPACX_IND_ARL 0xa
-#define IPACX_IND_CVR 0xb
-#define IPACX_IND_AI8 0xc
-#define IPACX_IND_AI10 0xd
-#define IPACX_IND_AIL 0xe
-#define IPACX_IND_DC 0xf
-
-extern void init_ipacx(struct IsdnCardState *, int);
-extern void interrupt_ipacx(struct IsdnCardState *);
-extern void setup_isac(struct IsdnCardState *);
-
-#endif
diff --git a/drivers/isdn/hisax/isac.c b/drivers/isdn/hisax/isac.c
deleted file mode 100644
index bd40e0671ded..000000000000
--- a/drivers/isdn/hisax/isac.c
+++ /dev/null
@@ -1,681 +0,0 @@
-/* $Id: isac.c,v 1.31.2.3 2004/01/13 14:31:25 keil Exp $
- *
- * ISAC specific routines
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * For changes and modifications please read
- * Documentation/isdn/HiSax.cert
- *
- */
-
-#include "hisax.h"
-#include "isac.h"
-#include "arcofi.h"
-#include "isdnl1.h"
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-
-#define DBUSY_TIMER_VALUE 80
-#define ARCOFI_USE 1
-
-static char *ISACVer[] =
-{"2086/2186 V1.1", "2085 B1", "2085 B2",
- "2085 V2.3"};
-
-void ISACVersion(struct IsdnCardState *cs, char *s)
-{
- int val;
-
- val = cs->readisac(cs, ISAC_RBCH);
- printk(KERN_INFO "%s ISAC version (%x): %s\n", s, val, ISACVer[(val >> 5) & 3]);
-}
-
-static void
-ph_command(struct IsdnCardState *cs, unsigned int command)
-{
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ph_command %x", command);
- cs->writeisac(cs, ISAC_CIX0, (command << 2) | 3);
-}
-
-
-static void
-isac_new_ph(struct IsdnCardState *cs)
-{
- switch (cs->dc.isac.ph_state) {
- case (ISAC_IND_RS):
- case (ISAC_IND_EI):
- ph_command(cs, ISAC_CMD_DUI);
- l1_msg(cs, HW_RESET | INDICATION, NULL);
- break;
- case (ISAC_IND_DID):
- l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
- break;
- case (ISAC_IND_DR):
- l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
- break;
- case (ISAC_IND_PU):
- l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
- break;
- case (ISAC_IND_RSY):
- l1_msg(cs, HW_RSYNC | INDICATION, NULL);
- break;
- case (ISAC_IND_ARD):
- l1_msg(cs, HW_INFO2 | INDICATION, NULL);
- break;
- case (ISAC_IND_AI8):
- l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
- break;
- case (ISAC_IND_AI10):
- l1_msg(cs, HW_INFO4_P10 | INDICATION, NULL);
- break;
- default:
- break;
- }
-}
-
-static void
-isac_bh(struct work_struct *work)
-{
- struct IsdnCardState *cs =
- container_of(work, struct IsdnCardState, tqueue);
- struct PStack *stptr;
-
- if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
- if (cs->debug)
- debugl1(cs, "D-Channel Busy cleared");
- stptr = cs->stlist;
- while (stptr != NULL) {
- stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
- stptr = stptr->next;
- }
- }
- if (test_and_clear_bit(D_L1STATECHANGE, &cs->event))
- isac_new_ph(cs);
- if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
- DChannel_proc_rcv(cs);
- if (test_and_clear_bit(D_XMTBUFREADY, &cs->event))
- DChannel_proc_xmt(cs);
-#if ARCOFI_USE
- if (!test_bit(HW_ARCOFI, &cs->HW_Flags))
- return;
- if (test_and_clear_bit(D_RX_MON1, &cs->event))
- arcofi_fsm(cs, ARCOFI_RX_END, NULL);
- if (test_and_clear_bit(D_TX_MON1, &cs->event))
- arcofi_fsm(cs, ARCOFI_TX_END, NULL);
-#endif
-}
-
-static void
-isac_empty_fifo(struct IsdnCardState *cs, int count)
-{
- u_char *ptr;
-
- if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
- debugl1(cs, "isac_empty_fifo");
-
- if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "isac_empty_fifo overrun %d",
- cs->rcvidx + count);
- cs->writeisac(cs, ISAC_CMDR, 0x80);
- cs->rcvidx = 0;
- return;
- }
- ptr = cs->rcvbuf + cs->rcvidx;
- cs->rcvidx += count;
- cs->readisacfifo(cs, ptr, count);
- cs->writeisac(cs, ISAC_CMDR, 0x80);
- if (cs->debug & L1_DEB_ISAC_FIFO) {
- char *t = cs->dlog;
-
- t += sprintf(t, "isac_empty_fifo cnt %d", count);
- QuickHex(t, ptr, count);
- debugl1(cs, "%s", cs->dlog);
- }
-}
-
-static void
-isac_fill_fifo(struct IsdnCardState *cs)
-{
- int count, more;
- u_char *ptr;
-
- if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
- debugl1(cs, "isac_fill_fifo");
-
- if (!cs->tx_skb)
- return;
-
- count = cs->tx_skb->len;
- if (count <= 0)
- return;
-
- more = 0;
- if (count > 32) {
- more = !0;
- count = 32;
- }
- ptr = cs->tx_skb->data;
- skb_pull(cs->tx_skb, count);
- cs->tx_cnt += count;
- cs->writeisacfifo(cs, ptr, count);
- cs->writeisac(cs, ISAC_CMDR, more ? 0x8 : 0xa);
- if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
- debugl1(cs, "isac_fill_fifo dbusytimer running");
- del_timer(&cs->dbusytimer);
- }
- cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
- add_timer(&cs->dbusytimer);
- if (cs->debug & L1_DEB_ISAC_FIFO) {
- char *t = cs->dlog;
-
- t += sprintf(t, "isac_fill_fifo cnt %d", count);
- QuickHex(t, ptr, count);
- debugl1(cs, "%s", cs->dlog);
- }
-}
-
-void
-isac_interrupt(struct IsdnCardState *cs, u_char val)
-{
- u_char exval, v1;
- struct sk_buff *skb;
- unsigned int count;
-
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ISAC interrupt %x", val);
- if (val & 0x80) { /* RME */
- exval = cs->readisac(cs, ISAC_RSTA);
- if ((exval & 0x70) != 0x20) {
- if (exval & 0x40) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "ISAC RDO");
-#ifdef ERROR_STATISTIC
- cs->err_rx++;
-#endif
- }
- if (!(exval & 0x20)) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "ISAC CRC error");
-#ifdef ERROR_STATISTIC
- cs->err_crc++;
-#endif
- }
- cs->writeisac(cs, ISAC_CMDR, 0x80);
- } else {
- count = cs->readisac(cs, ISAC_RBCL) & 0x1f;
- if (count == 0)
- count = 32;
- isac_empty_fifo(cs, count);
- count = cs->rcvidx;
- if (count > 0) {
- cs->rcvidx = 0;
- skb = alloc_skb(count, GFP_ATOMIC);
- if (!skb)
- printk(KERN_WARNING "HiSax: D receive out of memory\n");
- else {
- skb_put_data(skb, cs->rcvbuf, count);
- skb_queue_tail(&cs->rq, skb);
- }
- }
- }
- cs->rcvidx = 0;
- schedule_event(cs, D_RCVBUFREADY);
- }
- if (val & 0x40) { /* RPF */
- isac_empty_fifo(cs, 32);
- }
- if (val & 0x20) { /* RSC */
- /* never */
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "ISAC RSC interrupt");
- }
- if (val & 0x10) { /* XPR */
- if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
- del_timer(&cs->dbusytimer);
- if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
- schedule_event(cs, D_CLEARBUSY);
- if (cs->tx_skb) {
- if (cs->tx_skb->len) {
- isac_fill_fifo(cs);
- goto afterXPR;
- } else {
- dev_kfree_skb_irq(cs->tx_skb);
- cs->tx_cnt = 0;
- cs->tx_skb = NULL;
- }
- }
- cs->tx_skb = skb_dequeue(&cs->sq);
- if (cs->tx_skb) {
- cs->tx_cnt = 0;
- isac_fill_fifo(cs);
- } else
- schedule_event(cs, D_XMTBUFREADY);
- }
-afterXPR:
- if (val & 0x04) { /* CISQ */
- exval = cs->readisac(cs, ISAC_CIR0);
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ISAC CIR0 %02X", exval);
- if (exval & 2) {
- cs->dc.isac.ph_state = (exval >> 2) & 0xf;
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ph_state change %x", cs->dc.isac.ph_state);
- schedule_event(cs, D_L1STATECHANGE);
- }
- if (exval & 1) {
- exval = cs->readisac(cs, ISAC_CIR1);
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ISAC CIR1 %02X", exval);
- }
- }
- if (val & 0x02) { /* SIN */
- /* never */
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "ISAC SIN interrupt");
- }
- if (val & 0x01) { /* EXI */
- exval = cs->readisac(cs, ISAC_EXIR);
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "ISAC EXIR %02x", exval);
- if (exval & 0x80) { /* XMR */
- debugl1(cs, "ISAC XMR");
- printk(KERN_WARNING "HiSax: ISAC XMR\n");
- }
- if (exval & 0x40) { /* XDU */
- debugl1(cs, "ISAC XDU");
- printk(KERN_WARNING "HiSax: ISAC XDU\n");
-#ifdef ERROR_STATISTIC
- cs->err_tx++;
-#endif
- if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
- del_timer(&cs->dbusytimer);
- if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
- schedule_event(cs, D_CLEARBUSY);
- if (cs->tx_skb) { /* Restart frame */
- skb_push(cs->tx_skb, cs->tx_cnt);
- cs->tx_cnt = 0;
- isac_fill_fifo(cs);
- } else {
- printk(KERN_WARNING "HiSax: ISAC XDU no skb\n");
- debugl1(cs, "ISAC XDU no skb");
- }
- }
- if (exval & 0x04) { /* MOS */
- v1 = cs->readisac(cs, ISAC_MOSR);
- if (cs->debug & L1_DEB_MONITOR)
- debugl1(cs, "ISAC MOSR %02x", v1);
-#if ARCOFI_USE
- if (v1 & 0x08) {
- if (!cs->dc.isac.mon_rx) {
- cs->dc.isac.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC);
- if (!cs->dc.isac.mon_rx) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "ISAC MON RX out of memory!");
- cs->dc.isac.mocr &= 0xf0;
- cs->dc.isac.mocr |= 0x0a;
- cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
- goto afterMONR0;
- } else
- cs->dc.isac.mon_rxp = 0;
- }
- if (cs->dc.isac.mon_rxp >= MAX_MON_FRAME) {
- cs->dc.isac.mocr &= 0xf0;
- cs->dc.isac.mocr |= 0x0a;
- cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
- cs->dc.isac.mon_rxp = 0;
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "ISAC MON RX overflow!");
- goto afterMONR0;
- }
- cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = cs->readisac(cs, ISAC_MOR0);
- if (cs->debug & L1_DEB_MONITOR)
- debugl1(cs, "ISAC MOR0 %02x", cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp - 1]);
- if (cs->dc.isac.mon_rxp == 1) {
- cs->dc.isac.mocr |= 0x04;
- cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
- }
- }
- afterMONR0:
- if (v1 & 0x80) {
- if (!cs->dc.isac.mon_rx) {
- cs->dc.isac.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC);
- if (!cs->dc.isac.mon_rx) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "ISAC MON RX out of memory!");
- cs->dc.isac.mocr &= 0x0f;
- cs->dc.isac.mocr |= 0xa0;
- cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
- goto afterMONR1;
- } else
- cs->dc.isac.mon_rxp = 0;
- }
- if (cs->dc.isac.mon_rxp >= MAX_MON_FRAME) {
- cs->dc.isac.mocr &= 0x0f;
- cs->dc.isac.mocr |= 0xa0;
- cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
- cs->dc.isac.mon_rxp = 0;
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "ISAC MON RX overflow!");
- goto afterMONR1;
- }
- cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = cs->readisac(cs, ISAC_MOR1);
- if (cs->debug & L1_DEB_MONITOR)
- debugl1(cs, "ISAC MOR1 %02x", cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp - 1]);
- cs->dc.isac.mocr |= 0x40;
- cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
- }
- afterMONR1:
- if (v1 & 0x04) {
- cs->dc.isac.mocr &= 0xf0;
- cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
- cs->dc.isac.mocr |= 0x0a;
- cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
- schedule_event(cs, D_RX_MON0);
- }
- if (v1 & 0x40) {
- cs->dc.isac.mocr &= 0x0f;
- cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
- cs->dc.isac.mocr |= 0xa0;
- cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
- schedule_event(cs, D_RX_MON1);
- }
- if (v1 & 0x02) {
- if ((!cs->dc.isac.mon_tx) || (cs->dc.isac.mon_txc &&
- (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc) &&
- !(v1 & 0x08))) {
- cs->dc.isac.mocr &= 0xf0;
- cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
- cs->dc.isac.mocr |= 0x0a;
- cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
- if (cs->dc.isac.mon_txc &&
- (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc))
- schedule_event(cs, D_TX_MON0);
- goto AfterMOX0;
- }
- if (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) {
- schedule_event(cs, D_TX_MON0);
- goto AfterMOX0;
- }
- cs->writeisac(cs, ISAC_MOX0,
- cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]);
- if (cs->debug & L1_DEB_MONITOR)
- debugl1(cs, "ISAC %02x -> MOX0", cs->dc.isac.mon_tx[cs->dc.isac.mon_txp - 1]);
- }
- AfterMOX0:
- if (v1 & 0x20) {
- if ((!cs->dc.isac.mon_tx) || (cs->dc.isac.mon_txc &&
- (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc) &&
- !(v1 & 0x80))) {
- cs->dc.isac.mocr &= 0x0f;
- cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
- cs->dc.isac.mocr |= 0xa0;
- cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
- if (cs->dc.isac.mon_txc &&
- (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc))
- schedule_event(cs, D_TX_MON1);
- goto AfterMOX1;
- }
- if (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) {
- schedule_event(cs, D_TX_MON1);
- goto AfterMOX1;
- }
- cs->writeisac(cs, ISAC_MOX1,
- cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]);
- if (cs->debug & L1_DEB_MONITOR)
- debugl1(cs, "ISAC %02x -> MOX1", cs->dc.isac.mon_tx[cs->dc.isac.mon_txp - 1]);
- }
- AfterMOX1:;
-#endif
- }
- }
-}
-
-static void
-ISAC_l1hw(struct PStack *st, int pr, void *arg)
-{
- struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
- struct sk_buff *skb = arg;
- u_long flags;
- int val;
-
- switch (pr) {
- case (PH_DATA | REQUEST):
- if (cs->debug & DEB_DLOG_HEX)
- LogFrame(cs, skb->data, skb->len);
- if (cs->debug & DEB_DLOG_VERBOSE)
- dlogframe(cs, skb, 0);
- spin_lock_irqsave(&cs->lock, flags);
- if (cs->tx_skb) {
- skb_queue_tail(&cs->sq, skb);
-#ifdef L2FRAME_DEBUG /* psa */
- if (cs->debug & L1_DEB_LAPD)
- Logl2Frame(cs, skb, "PH_DATA Queued", 0);
-#endif
- } else {
- cs->tx_skb = skb;
- cs->tx_cnt = 0;
-#ifdef L2FRAME_DEBUG /* psa */
- if (cs->debug & L1_DEB_LAPD)
- Logl2Frame(cs, skb, "PH_DATA", 0);
-#endif
- isac_fill_fifo(cs);
- }
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (PH_PULL | INDICATION):
- spin_lock_irqsave(&cs->lock, flags);
- if (cs->tx_skb) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
- skb_queue_tail(&cs->sq, skb);
- } else {
- if (cs->debug & DEB_DLOG_HEX)
- LogFrame(cs, skb->data, skb->len);
- if (cs->debug & DEB_DLOG_VERBOSE)
- dlogframe(cs, skb, 0);
- cs->tx_skb = skb;
- cs->tx_cnt = 0;
-#ifdef L2FRAME_DEBUG /* psa */
- if (cs->debug & L1_DEB_LAPD)
- Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
-#endif
- isac_fill_fifo(cs);
- }
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (PH_PULL | REQUEST):
-#ifdef L2FRAME_DEBUG /* psa */
- if (cs->debug & L1_DEB_LAPD)
- debugl1(cs, "-> PH_REQUEST_PULL");
-#endif
- if (!cs->tx_skb) {
- test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
- } else
- test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- break;
- case (HW_RESET | REQUEST):
- spin_lock_irqsave(&cs->lock, flags);
- if ((cs->dc.isac.ph_state == ISAC_IND_EI) ||
- (cs->dc.isac.ph_state == ISAC_IND_DR) ||
- (cs->dc.isac.ph_state == ISAC_IND_RS))
- ph_command(cs, ISAC_CMD_TIM);
- else
- ph_command(cs, ISAC_CMD_RS);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (HW_ENABLE | REQUEST):
- spin_lock_irqsave(&cs->lock, flags);
- ph_command(cs, ISAC_CMD_TIM);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (HW_INFO3 | REQUEST):
- spin_lock_irqsave(&cs->lock, flags);
- ph_command(cs, ISAC_CMD_AR8);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (HW_TESTLOOP | REQUEST):
- spin_lock_irqsave(&cs->lock, flags);
- val = 0;
- if (1 & (long) arg)
- val |= 0x0c;
- if (2 & (long) arg)
- val |= 0x3;
- if (test_bit(HW_IOM1, &cs->HW_Flags)) {
- /* IOM 1 Mode */
- if (!val) {
- cs->writeisac(cs, ISAC_SPCR, 0xa);
- cs->writeisac(cs, ISAC_ADF1, 0x2);
- } else {
- cs->writeisac(cs, ISAC_SPCR, val);
- cs->writeisac(cs, ISAC_ADF1, 0xa);
- }
- } else {
- /* IOM 2 Mode */
- cs->writeisac(cs, ISAC_SPCR, val);
- if (val)
- cs->writeisac(cs, ISAC_ADF1, 0x8);
- else
- cs->writeisac(cs, ISAC_ADF1, 0x0);
- }
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (HW_DEACTIVATE | RESPONSE):
- skb_queue_purge(&cs->rq);
- skb_queue_purge(&cs->sq);
- if (cs->tx_skb) {
- dev_kfree_skb_any(cs->tx_skb);
- cs->tx_skb = NULL;
- }
- if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
- del_timer(&cs->dbusytimer);
- if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
- schedule_event(cs, D_CLEARBUSY);
- break;
- default:
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "isac_l1hw unknown %04x", pr);
- break;
- }
-}
-
-static void
-setstack_isac(struct PStack *st, struct IsdnCardState *cs)
-{
- st->l1.l1hw = ISAC_l1hw;
-}
-
-static void
-DC_Close_isac(struct IsdnCardState *cs)
-{
- kfree(cs->dc.isac.mon_rx);
- cs->dc.isac.mon_rx = NULL;
- kfree(cs->dc.isac.mon_tx);
- cs->dc.isac.mon_tx = NULL;
-}
-
-static void
-dbusy_timer_handler(struct timer_list *t)
-{
- struct IsdnCardState *cs = from_timer(cs, t, dbusytimer);
- struct PStack *stptr;
- int rbch, star;
-
- if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
- rbch = cs->readisac(cs, ISAC_RBCH);
- star = cs->readisac(cs, ISAC_STAR);
- if (cs->debug)
- debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x",
- rbch, star);
- if (rbch & ISAC_RBCH_XAC) { /* D-Channel Busy */
- test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
- stptr = cs->stlist;
- while (stptr != NULL) {
- stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
- stptr = stptr->next;
- }
- } else {
- /* discard frame; reset transceiver */
- test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
- if (cs->tx_skb) {
- dev_kfree_skb_any(cs->tx_skb);
- cs->tx_cnt = 0;
- cs->tx_skb = NULL;
- } else {
- printk(KERN_WARNING "HiSax: ISAC D-Channel Busy no skb\n");
- debugl1(cs, "D-Channel Busy no skb");
- }
- cs->writeisac(cs, ISAC_CMDR, 0x01); /* Transmitter reset */
- cs->irq_func(cs->irq, cs);
- }
- }
-}
-
-void initisac(struct IsdnCardState *cs)
-{
- cs->setstack_d = setstack_isac;
- cs->DC_Close = DC_Close_isac;
- cs->dc.isac.mon_tx = NULL;
- cs->dc.isac.mon_rx = NULL;
- cs->writeisac(cs, ISAC_MASK, 0xff);
- cs->dc.isac.mocr = 0xaa;
- if (test_bit(HW_IOM1, &cs->HW_Flags)) {
- /* IOM 1 Mode */
- cs->writeisac(cs, ISAC_ADF2, 0x0);
- cs->writeisac(cs, ISAC_SPCR, 0xa);
- cs->writeisac(cs, ISAC_ADF1, 0x2);
- cs->writeisac(cs, ISAC_STCR, 0x70);
- cs->writeisac(cs, ISAC_MODE, 0xc9);
- } else {
- /* IOM 2 Mode */
- if (!cs->dc.isac.adf2)
- cs->dc.isac.adf2 = 0x80;
- cs->writeisac(cs, ISAC_ADF2, cs->dc.isac.adf2);
- cs->writeisac(cs, ISAC_SQXR, 0x2f);
- cs->writeisac(cs, ISAC_SPCR, 0x00);
- cs->writeisac(cs, ISAC_STCR, 0x70);
- cs->writeisac(cs, ISAC_MODE, 0xc9);
- cs->writeisac(cs, ISAC_TIMR, 0x00);
- cs->writeisac(cs, ISAC_ADF1, 0x00);
- }
- ph_command(cs, ISAC_CMD_RS);
- cs->writeisac(cs, ISAC_MASK, 0x0);
-}
-
-void clear_pending_isac_ints(struct IsdnCardState *cs)
-{
- int val, eval;
-
- val = cs->readisac(cs, ISAC_STAR);
- debugl1(cs, "ISAC STAR %x", val);
- val = cs->readisac(cs, ISAC_MODE);
- debugl1(cs, "ISAC MODE %x", val);
- val = cs->readisac(cs, ISAC_ADF2);
- debugl1(cs, "ISAC ADF2 %x", val);
- val = cs->readisac(cs, ISAC_ISTA);
- debugl1(cs, "ISAC ISTA %x", val);
- if (val & 0x01) {
- eval = cs->readisac(cs, ISAC_EXIR);
- debugl1(cs, "ISAC EXIR %x", eval);
- }
- val = cs->readisac(cs, ISAC_CIR0);
- debugl1(cs, "ISAC CIR0 %x", val);
- cs->dc.isac.ph_state = (val >> 2) & 0xf;
- schedule_event(cs, D_L1STATECHANGE);
- /* Disable all IRQ */
- cs->writeisac(cs, ISAC_MASK, 0xFF);
-}
-
-void setup_isac(struct IsdnCardState *cs)
-{
- INIT_WORK(&cs->tqueue, isac_bh);
- timer_setup(&cs->dbusytimer, dbusy_timer_handler, 0);
-}
diff --git a/drivers/isdn/hisax/isac.h b/drivers/isdn/hisax/isac.h
deleted file mode 100644
index 04f16b91b822..000000000000
--- a/drivers/isdn/hisax/isac.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/* $Id: isac.h,v 1.9.2.2 2004/01/12 22:52:27 keil Exp $
- *
- * ISAC specific defines
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-/* All Registers original Siemens Spec */
-
-#define ISAC_MASK 0x20
-#define ISAC_ISTA 0x20
-#define ISAC_STAR 0x21
-#define ISAC_CMDR 0x21
-#define ISAC_EXIR 0x24
-#define ISAC_ADF2 0x39
-#define ISAC_SPCR 0x30
-#define ISAC_ADF1 0x38
-#define ISAC_CIR0 0x31
-#define ISAC_CIX0 0x31
-#define ISAC_CIR1 0x33
-#define ISAC_CIX1 0x33
-#define ISAC_STCR 0x37
-#define ISAC_MODE 0x22
-#define ISAC_RSTA 0x27
-#define ISAC_RBCL 0x25
-#define ISAC_RBCH 0x2A
-#define ISAC_TIMR 0x23
-#define ISAC_SQXR 0x3b
-#define ISAC_MOSR 0x3a
-#define ISAC_MOCR 0x3a
-#define ISAC_MOR0 0x32
-#define ISAC_MOX0 0x32
-#define ISAC_MOR1 0x34
-#define ISAC_MOX1 0x34
-
-#define ISAC_RBCH_XAC 0x80
-
-#define ISAC_CMD_TIM 0x0
-#define ISAC_CMD_RS 0x1
-#define ISAC_CMD_SCZ 0x4
-#define ISAC_CMD_SSZ 0x2
-#define ISAC_CMD_AR8 0x8
-#define ISAC_CMD_AR10 0x9
-#define ISAC_CMD_ARL 0xA
-#define ISAC_CMD_DUI 0xF
-
-#define ISAC_IND_RS 0x1
-#define ISAC_IND_PU 0x7
-#define ISAC_IND_DR 0x0
-#define ISAC_IND_SD 0x2
-#define ISAC_IND_DIS 0x3
-#define ISAC_IND_EI 0x6
-#define ISAC_IND_RSY 0x4
-#define ISAC_IND_ARD 0x8
-#define ISAC_IND_TI 0xA
-#define ISAC_IND_ATI 0xB
-#define ISAC_IND_AI8 0xC
-#define ISAC_IND_AI10 0xD
-#define ISAC_IND_DID 0xF
-
-extern void ISACVersion(struct IsdnCardState *, char *);
-extern void setup_isac(struct IsdnCardState *);
-extern void initisac(struct IsdnCardState *);
-extern void isac_interrupt(struct IsdnCardState *, u_char);
-extern void clear_pending_isac_ints(struct IsdnCardState *);
diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c
deleted file mode 100644
index 82c1879f5664..000000000000
--- a/drivers/isdn/hisax/isar.c
+++ /dev/null
@@ -1,1910 +0,0 @@
-/* $Id: isar.c,v 1.22.2.6 2004/02/11 13:21:34 keil Exp $
- *
- * isar.c ISAR (Siemens PSB 7110) specific routines
- *
- * Author Karsten Keil (keil@isdn4linux.de)
- *
- * This file is (c) under GNU General Public License
- *
- */
-
-#include <linux/init.h>
-#include "hisax.h"
-#include "isar.h"
-#include "isdnl1.h"
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-
-#define DBG_LOADFIRM 0
-#define DUMP_MBOXFRAME 2
-
-#define DLE 0x10
-#define ETX 0x03
-
-#define FAXMODCNT 13
-static const u_char faxmodulation[] = {3, 24, 48, 72, 73, 74, 96, 97, 98, 121, 122, 145, 146};
-static u_int modmask = 0x1fff;
-static int frm_extra_delay = 2;
-static int para_TOA = 6;
-static const u_char *FC1_CMD[] = {"FAE", "FTS", "FRS", "FTM", "FRM", "FTH", "FRH", "CTRL"};
-
-static void isar_setup(struct IsdnCardState *cs);
-static void isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para);
-static void ll_deliver_faxstat(struct BCState *bcs, u_char status);
-
-static inline int
-waitforHIA(struct IsdnCardState *cs, int timeout)
-{
-
- while ((cs->BC_Read_Reg(cs, 0, ISAR_HIA) & 1) && timeout) {
- udelay(1);
- timeout--;
- }
- if (!timeout)
- printk(KERN_WARNING "HiSax: ISAR waitforHIA timeout\n");
- return (timeout);
-}
-
-
-static int
-sendmsg(struct IsdnCardState *cs, u_char his, u_char creg, u_char len,
- u_char *msg)
-{
- int i;
-
- if (!waitforHIA(cs, 4000))
- return (0);
-#if DUMP_MBOXFRAME
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "sendmsg(%02x,%02x,%d)", his, creg, len);
-#endif
- cs->BC_Write_Reg(cs, 0, ISAR_CTRL_H, creg);
- cs->BC_Write_Reg(cs, 0, ISAR_CTRL_L, len);
- cs->BC_Write_Reg(cs, 0, ISAR_WADR, 0);
- if (msg && len) {
- cs->BC_Write_Reg(cs, 1, ISAR_MBOX, msg[0]);
- for (i = 1; i < len; i++)
- cs->BC_Write_Reg(cs, 2, ISAR_MBOX, msg[i]);
-#if DUMP_MBOXFRAME > 1
- if (cs->debug & L1_DEB_HSCX_FIFO) {
- char tmp[256], *t;
-
- i = len;
- while (i > 0) {
- t = tmp;
- t += sprintf(t, "sendmbox cnt %d", len);
- QuickHex(t, &msg[len-i], (i > 64) ? 64 : i);
- debugl1(cs, "%s", tmp);
- i -= 64;
- }
- }
-#endif
- }
- cs->BC_Write_Reg(cs, 1, ISAR_HIS, his);
- waitforHIA(cs, 10000);
- return (1);
-}
-
-/* Call only with IRQ disabled !!! */
-static inline void
-rcv_mbox(struct IsdnCardState *cs, struct isar_reg *ireg, u_char *msg)
-{
- int i;
-
- cs->BC_Write_Reg(cs, 1, ISAR_RADR, 0);
- if (msg && ireg->clsb) {
- msg[0] = cs->BC_Read_Reg(cs, 1, ISAR_MBOX);
- for (i = 1; i < ireg->clsb; i++)
- msg[i] = cs->BC_Read_Reg(cs, 2, ISAR_MBOX);
-#if DUMP_MBOXFRAME > 1
- if (cs->debug & L1_DEB_HSCX_FIFO) {
- char tmp[256], *t;
-
- i = ireg->clsb;
- while (i > 0) {
- t = tmp;
- t += sprintf(t, "rcv_mbox cnt %d", ireg->clsb);
- QuickHex(t, &msg[ireg->clsb - i], (i > 64) ? 64 : i);
- debugl1(cs, "%s", tmp);
- i -= 64;
- }
- }
-#endif
- }
- cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
-}
-
-/* Call only with IRQ disabled !!! */
-static inline void
-get_irq_infos(struct IsdnCardState *cs, struct isar_reg *ireg)
-{
- ireg->iis = cs->BC_Read_Reg(cs, 1, ISAR_IIS);
- ireg->cmsb = cs->BC_Read_Reg(cs, 1, ISAR_CTRL_H);
- ireg->clsb = cs->BC_Read_Reg(cs, 1, ISAR_CTRL_L);
-#if DUMP_MBOXFRAME
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "irq_stat(%02x,%02x,%d)", ireg->iis, ireg->cmsb,
- ireg->clsb);
-#endif
-}
-
-static int
-waitrecmsg(struct IsdnCardState *cs, u_char *len,
- u_char *msg, int maxdelay)
-{
- int timeout = 0;
- struct isar_reg *ir = cs->bcs[0].hw.isar.reg;
-
-
- while ((!(cs->BC_Read_Reg(cs, 0, ISAR_IRQBIT) & ISAR_IRQSTA)) &&
- (timeout++ < maxdelay))
- udelay(1);
- if (timeout > maxdelay) {
- printk(KERN_WARNING"isar recmsg IRQSTA timeout\n");
- return (0);
- }
- get_irq_infos(cs, ir);
- rcv_mbox(cs, ir, msg);
- *len = ir->clsb;
- return (1);
-}
-
-int
-ISARVersion(struct IsdnCardState *cs, char *s)
-{
- int ver;
- u_char msg[] = ISAR_MSG_HWVER;
- u_char tmp[64];
- u_char len;
- u_long flags;
- int debug;
-
- cs->cardmsg(cs, CARD_RESET, NULL);
- spin_lock_irqsave(&cs->lock, flags);
- /* disable ISAR IRQ */
- cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0);
- debug = cs->debug;
- cs->debug &= ~(L1_DEB_HSCX | L1_DEB_HSCX_FIFO);
- if (!sendmsg(cs, ISAR_HIS_VNR, 0, 3, msg)) {
- spin_unlock_irqrestore(&cs->lock, flags);
- return (-1);
- }
- if (!waitrecmsg(cs, &len, tmp, 100000)) {
- spin_unlock_irqrestore(&cs->lock, flags);
- return (-2);
- }
- cs->debug = debug;
- if (cs->bcs[0].hw.isar.reg->iis == ISAR_IIS_VNR) {
- if (len == 1) {
- ver = tmp[0] & 0xf;
- printk(KERN_INFO "%s ISAR version %d\n", s, ver);
- } else
- ver = -3;
- } else
- ver = -4;
- spin_unlock_irqrestore(&cs->lock, flags);
- return (ver);
-}
-
-static int
-isar_load_firmware(struct IsdnCardState *cs, u_char __user *buf)
-{
- int cfu_ret, ret, size, cnt, debug;
- u_char len, nom, noc;
- u_short sadr, left, *sp;
- u_char __user *p = buf;
- u_char *msg, *tmpmsg, *mp, tmp[64];
- u_long flags;
- struct isar_reg *ireg = cs->bcs[0].hw.isar.reg;
-
- struct {u_short sadr;
- u_short len;
- u_short d_key;
- } blk_head;
-
-#define BLK_HEAD_SIZE 6
- if (1 != (ret = ISARVersion(cs, "Testing"))) {
- printk(KERN_ERR"isar_load_firmware wrong isar version %d\n", ret);
- return (1);
- }
- debug = cs->debug;
-#if DBG_LOADFIRM < 2
- cs->debug &= ~(L1_DEB_HSCX | L1_DEB_HSCX_FIFO);
-#endif
-
- cfu_ret = copy_from_user(&size, p, sizeof(int));
- if (cfu_ret) {
- printk(KERN_ERR "isar_load_firmware copy_from_user ret %d\n", cfu_ret);
- return -EFAULT;
- }
- p += sizeof(int);
- printk(KERN_DEBUG"isar_load_firmware size: %d\n", size);
- cnt = 0;
- /* disable ISAR IRQ */
- cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0);
- if (!(msg = kmalloc(256, GFP_KERNEL))) {
- printk(KERN_ERR"isar_load_firmware no buffer\n");
- return (1);
- }
- if (!(tmpmsg = kmalloc(256, GFP_KERNEL))) {
- printk(KERN_ERR"isar_load_firmware no tmp buffer\n");
- kfree(msg);
- return (1);
- }
- spin_lock_irqsave(&cs->lock, flags);
- /* disable ISAR IRQ */
- cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0);
- spin_unlock_irqrestore(&cs->lock, flags);
- while (cnt < size) {
- if ((ret = copy_from_user(&blk_head, p, BLK_HEAD_SIZE))) {
- printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret);
- goto reterror;
- }
-#ifdef __BIG_ENDIAN
- sadr = (blk_head.sadr & 0xff) * 256 + blk_head.sadr / 256;
- blk_head.sadr = sadr;
- sadr = (blk_head.len & 0xff) * 256 + blk_head.len / 256;
- blk_head.len = sadr;
- sadr = (blk_head.d_key & 0xff) * 256 + blk_head.d_key / 256;
- blk_head.d_key = sadr;
-#endif /* __BIG_ENDIAN */
- cnt += BLK_HEAD_SIZE;
- p += BLK_HEAD_SIZE;
- printk(KERN_DEBUG"isar firmware block (%#x,%5d,%#x)\n",
- blk_head.sadr, blk_head.len, blk_head.d_key & 0xff);
- sadr = blk_head.sadr;
- left = blk_head.len;
- spin_lock_irqsave(&cs->lock, flags);
- if (!sendmsg(cs, ISAR_HIS_DKEY, blk_head.d_key & 0xff, 0, NULL)) {
- printk(KERN_ERR"isar sendmsg dkey failed\n");
- ret = 1; goto reterr_unlock;
- }
- if (!waitrecmsg(cs, &len, tmp, 100000)) {
- printk(KERN_ERR"isar waitrecmsg dkey failed\n");
- ret = 1; goto reterr_unlock;
- }
- if ((ireg->iis != ISAR_IIS_DKEY) || ireg->cmsb || len) {
- printk(KERN_ERR"isar wrong dkey response (%x,%x,%x)\n",
- ireg->iis, ireg->cmsb, len);
- ret = 1; goto reterr_unlock;
- }
- spin_unlock_irqrestore(&cs->lock, flags);
- while (left > 0) {
- if (left > 126)
- noc = 126;
- else
- noc = left;
- nom = 2 * noc;
- mp = msg;
- *mp++ = sadr / 256;
- *mp++ = sadr % 256;
- left -= noc;
- *mp++ = noc;
- if ((ret = copy_from_user(tmpmsg, p, nom))) {
- printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret);
- goto reterror;
- }
- p += nom;
- cnt += nom;
- nom += 3;
- sp = (u_short *)tmpmsg;
-#if DBG_LOADFIRM
- printk(KERN_DEBUG"isar: load %3d words at %04x left %d\n",
- noc, sadr, left);
-#endif
- sadr += noc;
- while (noc) {
-#ifdef __BIG_ENDIAN
- *mp++ = *sp % 256;
- *mp++ = *sp / 256;
-#else
- *mp++ = *sp / 256;
- *mp++ = *sp % 256;
-#endif /* __BIG_ENDIAN */
- sp++;
- noc--;
- }
- spin_lock_irqsave(&cs->lock, flags);
- if (!sendmsg(cs, ISAR_HIS_FIRM, 0, nom, msg)) {
- printk(KERN_ERR"isar sendmsg prog failed\n");
- ret = 1; goto reterr_unlock;
- }
- if (!waitrecmsg(cs, &len, tmp, 100000)) {
- printk(KERN_ERR"isar waitrecmsg prog failed\n");
- ret = 1; goto reterr_unlock;
- }
- if ((ireg->iis != ISAR_IIS_FIRM) || ireg->cmsb || len) {
- printk(KERN_ERR"isar wrong prog response (%x,%x,%x)\n",
- ireg->iis, ireg->cmsb, len);
- ret = 1; goto reterr_unlock;
- }
- spin_unlock_irqrestore(&cs->lock, flags);
- }
- printk(KERN_DEBUG"isar firmware block %5d words loaded\n",
- blk_head.len);
- }
- /* 10ms delay */
- cnt = 10;
- while (cnt--)
- udelay(1000);
- msg[0] = 0xff;
- msg[1] = 0xfe;
- ireg->bstat = 0;
- spin_lock_irqsave(&cs->lock, flags);
- if (!sendmsg(cs, ISAR_HIS_STDSP, 0, 2, msg)) {
- printk(KERN_ERR"isar sendmsg start dsp failed\n");
- ret = 1; goto reterr_unlock;
- }
- if (!waitrecmsg(cs, &len, tmp, 100000)) {
- printk(KERN_ERR"isar waitrecmsg start dsp failed\n");
- ret = 1; goto reterr_unlock;
- }
- if ((ireg->iis != ISAR_IIS_STDSP) || ireg->cmsb || len) {
- printk(KERN_ERR"isar wrong start dsp response (%x,%x,%x)\n",
- ireg->iis, ireg->cmsb, len);
- ret = 1; goto reterr_unlock;
- } else
- printk(KERN_DEBUG"isar start dsp success\n");
- /* NORMAL mode entered */
- /* Enable IRQs of ISAR */
- cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, ISAR_IRQSTA);
- spin_unlock_irqrestore(&cs->lock, flags);
- cnt = 1000; /* max 1s */
- while ((!ireg->bstat) && cnt) {
- udelay(1000);
- cnt--;
- }
- if (!cnt) {
- printk(KERN_ERR"isar no general status event received\n");
- ret = 1; goto reterror;
- } else {
- printk(KERN_DEBUG"isar general status event %x\n",
- ireg->bstat);
- }
- /* 10ms delay */
- cnt = 10;
- while (cnt--)
- udelay(1000);
- spin_lock_irqsave(&cs->lock, flags);
- ireg->iis = 0;
- if (!sendmsg(cs, ISAR_HIS_DIAG, ISAR_CTRL_STST, 0, NULL)) {
- printk(KERN_ERR"isar sendmsg self tst failed\n");
- ret = 1; goto reterr_unlock;
- }
- cnt = 10000; /* max 100 ms */
- spin_unlock_irqrestore(&cs->lock, flags);
- while ((ireg->iis != ISAR_IIS_DIAG) && cnt) {
- udelay(10);
- cnt--;
- }
- udelay(1000);
- if (!cnt) {
- printk(KERN_ERR"isar no self tst response\n");
- ret = 1; goto reterror;
- }
- if ((ireg->cmsb == ISAR_CTRL_STST) && (ireg->clsb == 1)
- && (ireg->par[0] == 0)) {
- printk(KERN_DEBUG"isar selftest OK\n");
- } else {
- printk(KERN_DEBUG"isar selftest not OK %x/%x/%x\n",
- ireg->cmsb, ireg->clsb, ireg->par[0]);
- ret = 1; goto reterror;
- }
- spin_lock_irqsave(&cs->lock, flags);
- ireg->iis = 0;
- if (!sendmsg(cs, ISAR_HIS_DIAG, ISAR_CTRL_SWVER, 0, NULL)) {
- printk(KERN_ERR"isar RQST SVN failed\n");
- ret = 1; goto reterr_unlock;
- }
- spin_unlock_irqrestore(&cs->lock, flags);
- cnt = 30000; /* max 300 ms */
- while ((ireg->iis != ISAR_IIS_DIAG) && cnt) {
- udelay(10);
- cnt--;
- }
- udelay(1000);
- if (!cnt) {
- printk(KERN_ERR"isar no SVN response\n");
- ret = 1; goto reterror;
- } else {
- if ((ireg->cmsb == ISAR_CTRL_SWVER) && (ireg->clsb == 1))
- printk(KERN_DEBUG"isar software version %#x\n",
- ireg->par[0]);
- else {
- printk(KERN_ERR"isar wrong swver response (%x,%x) cnt(%d)\n",
- ireg->cmsb, ireg->clsb, cnt);
- ret = 1; goto reterror;
- }
- }
- spin_lock_irqsave(&cs->lock, flags);
- cs->debug = debug;
- isar_setup(cs);
-
- ret = 0;
-reterr_unlock:
- spin_unlock_irqrestore(&cs->lock, flags);
-reterror:
- cs->debug = debug;
- if (ret)
- /* disable ISAR IRQ */
- cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0);
- kfree(msg);
- kfree(tmpmsg);
- return (ret);
-}
-
-#define B_LL_NOCARRIER 8
-#define B_LL_CONNECT 9
-#define B_LL_OK 10
-
-static void
-isar_bh(struct work_struct *work)
-{
- struct BCState *bcs = container_of(work, struct BCState, tqueue);
-
- BChannel_bh(work);
- if (test_and_clear_bit(B_LL_NOCARRIER, &bcs->event))
- ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_NOCARR);
- if (test_and_clear_bit(B_LL_CONNECT, &bcs->event))
- ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT);
- if (test_and_clear_bit(B_LL_OK, &bcs->event))
- ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_OK);
-}
-
-static void
-send_DLE_ETX(struct BCState *bcs)
-{
- u_char dleetx[2] = {DLE, ETX};
- struct sk_buff *skb;
-
- if ((skb = dev_alloc_skb(2))) {
- skb_put_data(skb, dleetx, 2);
- skb_queue_tail(&bcs->rqueue, skb);
- schedule_event(bcs, B_RCVBUFREADY);
- } else {
- printk(KERN_WARNING "HiSax: skb out of memory\n");
- }
-}
-
-static inline int
-dle_count(unsigned char *buf, int len)
-{
- int count = 0;
-
- while (len--)
- if (*buf++ == DLE)
- count++;
- return count;
-}
-
-static inline void
-insert_dle(unsigned char *dest, unsigned char *src, int count) {
- /* <DLE> in input stream have to be flagged as <DLE><DLE> */
- while (count--) {
- *dest++ = *src;
- if (*src++ == DLE)
- *dest++ = DLE;
- }
-}
-
-static void
-isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs)
-{
- u_char *ptr;
- struct sk_buff *skb;
- struct isar_reg *ireg = bcs->hw.isar.reg;
-
- if (!ireg->clsb) {
- debugl1(cs, "isar zero len frame");
- cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
- return;
- }
- switch (bcs->mode) {
- case L1_MODE_NULL:
- debugl1(cs, "isar mode 0 spurious IIS_RDATA %x/%x/%x",
- ireg->iis, ireg->cmsb, ireg->clsb);
- printk(KERN_WARNING"isar mode 0 spurious IIS_RDATA %x/%x/%x\n",
- ireg->iis, ireg->cmsb, ireg->clsb);
- cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
- break;
- case L1_MODE_TRANS:
- case L1_MODE_V32:
- if ((skb = dev_alloc_skb(ireg->clsb))) {
- rcv_mbox(cs, ireg, (u_char *)skb_put(skb, ireg->clsb));
- skb_queue_tail(&bcs->rqueue, skb);
- schedule_event(bcs, B_RCVBUFREADY);
- } else {
- printk(KERN_WARNING "HiSax: skb out of memory\n");
- cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
- }
- break;
- case L1_MODE_HDLC:
- if ((bcs->hw.isar.rcvidx + ireg->clsb) > HSCX_BUFMAX) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "isar_rcv_frame: incoming packet too large");
- cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
- bcs->hw.isar.rcvidx = 0;
- } else if (ireg->cmsb & HDLC_ERROR) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "isar frame error %x len %d",
- ireg->cmsb, ireg->clsb);
-#ifdef ERROR_STATISTIC
- if (ireg->cmsb & HDLC_ERR_RER)
- bcs->err_inv++;
- if (ireg->cmsb & HDLC_ERR_CER)
- bcs->err_crc++;
-#endif
- bcs->hw.isar.rcvidx = 0;
- cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
- } else {
- if (ireg->cmsb & HDLC_FSD)
- bcs->hw.isar.rcvidx = 0;
- ptr = bcs->hw.isar.rcvbuf + bcs->hw.isar.rcvidx;
- bcs->hw.isar.rcvidx += ireg->clsb;
- rcv_mbox(cs, ireg, ptr);
- if (ireg->cmsb & HDLC_FED) {
- if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "isar frame to short %d",
- bcs->hw.isar.rcvidx);
- } else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx - 2))) {
- printk(KERN_WARNING "ISAR: receive out of memory\n");
- } else {
- skb_put_data(skb, bcs->hw.isar.rcvbuf,
- bcs->hw.isar.rcvidx - 2);
- skb_queue_tail(&bcs->rqueue, skb);
- schedule_event(bcs, B_RCVBUFREADY);
- }
- bcs->hw.isar.rcvidx = 0;
- }
- }
- break;
- case L1_MODE_FAX:
- if (bcs->hw.isar.state != STFAX_ACTIV) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "isar_rcv_frame: not ACTIV");
- cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
- bcs->hw.isar.rcvidx = 0;
- break;
- }
- if (bcs->hw.isar.cmd == PCTRL_CMD_FRM) {
- rcv_mbox(cs, ireg, bcs->hw.isar.rcvbuf);
- bcs->hw.isar.rcvidx = ireg->clsb +
- dle_count(bcs->hw.isar.rcvbuf, ireg->clsb);
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "isar_rcv_frame: raw(%d) dle(%d)",
- ireg->clsb, bcs->hw.isar.rcvidx);
- if ((skb = dev_alloc_skb(bcs->hw.isar.rcvidx))) {
- insert_dle((u_char *)skb_put(skb, bcs->hw.isar.rcvidx),
- bcs->hw.isar.rcvbuf, ireg->clsb);
- skb_queue_tail(&bcs->rqueue, skb);
- schedule_event(bcs, B_RCVBUFREADY);
- if (ireg->cmsb & SART_NMD) { /* ABORT */
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "isar_rcv_frame: no more data");
- bcs->hw.isar.rcvidx = 0;
- send_DLE_ETX(bcs);
- sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) |
- ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC,
- 0, NULL);
- bcs->hw.isar.state = STFAX_ESCAPE;
- schedule_event(bcs, B_LL_NOCARRIER);
- }
- } else {
- printk(KERN_WARNING "HiSax: skb out of memory\n");
- }
- break;
- }
- if (bcs->hw.isar.cmd != PCTRL_CMD_FRH) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "isar_rcv_frame: unknown fax mode %x",
- bcs->hw.isar.cmd);
- cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
- bcs->hw.isar.rcvidx = 0;
- break;
- }
- /* PCTRL_CMD_FRH */
- if ((bcs->hw.isar.rcvidx + ireg->clsb) > HSCX_BUFMAX) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "isar_rcv_frame: incoming packet too large");
- cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
- bcs->hw.isar.rcvidx = 0;
- } else if (ireg->cmsb & HDLC_ERROR) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "isar frame error %x len %d",
- ireg->cmsb, ireg->clsb);
- bcs->hw.isar.rcvidx = 0;
- cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
- } else {
- if (ireg->cmsb & HDLC_FSD) {
- bcs->hw.isar.rcvidx = 0;
- }
- ptr = bcs->hw.isar.rcvbuf + bcs->hw.isar.rcvidx;
- bcs->hw.isar.rcvidx += ireg->clsb;
- rcv_mbox(cs, ireg, ptr);
- if (ireg->cmsb & HDLC_FED) {
- int len = bcs->hw.isar.rcvidx +
- dle_count(bcs->hw.isar.rcvbuf, bcs->hw.isar.rcvidx);
- if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "isar frame to short %d",
- bcs->hw.isar.rcvidx);
- printk(KERN_WARNING "ISAR: frame to short %d\n",
- bcs->hw.isar.rcvidx);
- } else if (!(skb = dev_alloc_skb(len))) {
- printk(KERN_WARNING "ISAR: receive out of memory\n");
- } else {
- insert_dle((u_char *)skb_put(skb, len),
- bcs->hw.isar.rcvbuf,
- bcs->hw.isar.rcvidx);
- skb_queue_tail(&bcs->rqueue, skb);
- schedule_event(bcs, B_RCVBUFREADY);
- send_DLE_ETX(bcs);
- schedule_event(bcs, B_LL_OK);
- test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag);
- }
- bcs->hw.isar.rcvidx = 0;
- }
- }
- if (ireg->cmsb & SART_NMD) { /* ABORT */
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "isar_rcv_frame: no more data");
- bcs->hw.isar.rcvidx = 0;
- sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) |
- ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL);
- bcs->hw.isar.state = STFAX_ESCAPE;
- if (test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag)) {
- send_DLE_ETX(bcs);
- schedule_event(bcs, B_LL_NOCARRIER);
- }
- }
- break;
- default:
- printk(KERN_ERR"isar_rcv_frame mode (%x)error\n", bcs->mode);
- cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
- break;
- }
-}
-
-void
-isar_fill_fifo(struct BCState *bcs)
-{
- struct IsdnCardState *cs = bcs->cs;
- int count;
- u_char msb;
- u_char *ptr;
-
- if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
- debugl1(cs, "isar_fill_fifo");
- if (!bcs->tx_skb)
- return;
- if (bcs->tx_skb->len <= 0)
- return;
- if (!(bcs->hw.isar.reg->bstat &
- (bcs->hw.isar.dpath == 1 ? BSTAT_RDM1 : BSTAT_RDM2)))
- return;
- if (bcs->tx_skb->len > bcs->hw.isar.mml) {
- msb = 0;
- count = bcs->hw.isar.mml;
- } else {
- count = bcs->tx_skb->len;
- msb = HDLC_FED;
- }
- ptr = bcs->tx_skb->data;
- if (!bcs->hw.isar.txcnt) {
- msb |= HDLC_FST;
- if ((bcs->mode == L1_MODE_FAX) &&
- (bcs->hw.isar.cmd == PCTRL_CMD_FTH)) {
- if (bcs->tx_skb->len > 1) {
- if ((ptr[0] == 0xff) && (ptr[1] == 0x13))
- /* last frame */
- test_and_set_bit(BC_FLG_LASTDATA,
- &bcs->Flag);
- }
- }
- }
- skb_pull(bcs->tx_skb, count);
- bcs->tx_cnt -= count;
- bcs->hw.isar.txcnt += count;
- switch (bcs->mode) {
- case L1_MODE_NULL:
- printk(KERN_ERR"isar_fill_fifo wrong mode 0\n");
- break;
- case L1_MODE_TRANS:
- case L1_MODE_V32:
- sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA,
- 0, count, ptr);
- break;
- case L1_MODE_HDLC:
- sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA,
- msb, count, ptr);
- break;
- case L1_MODE_FAX:
- if (bcs->hw.isar.state != STFAX_ACTIV) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "isar_fill_fifo: not ACTIV");
- } else if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) {
- sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA,
- msb, count, ptr);
- } else if (bcs->hw.isar.cmd == PCTRL_CMD_FTM) {
- sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA,
- 0, count, ptr);
- } else {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "isar_fill_fifo: not FTH/FTM");
- }
- break;
- default:
- if (cs->debug)
- debugl1(cs, "isar_fill_fifo mode(%x) error", bcs->mode);
- printk(KERN_ERR"isar_fill_fifo mode(%x) error\n", bcs->mode);
- break;
- }
-}
-
-static inline
-struct BCState *sel_bcs_isar(struct IsdnCardState *cs, u_char dpath)
-{
- if ((!dpath) || (dpath == 3))
- return (NULL);
- if (cs->bcs[0].hw.isar.dpath == dpath)
- return (&cs->bcs[0]);
- if (cs->bcs[1].hw.isar.dpath == dpath)
- return (&cs->bcs[1]);
- return (NULL);
-}
-
-static void
-send_frames(struct BCState *bcs)
-{
- if (bcs->tx_skb) {
- if (bcs->tx_skb->len) {
- isar_fill_fifo(bcs);
- return;
- } else {
- if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
- (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
- u_long flags;
- spin_lock_irqsave(&bcs->aclock, flags);
- bcs->ackcnt += bcs->hw.isar.txcnt;
- spin_unlock_irqrestore(&bcs->aclock, flags);
- schedule_event(bcs, B_ACKPENDING);
- }
- if (bcs->mode == L1_MODE_FAX) {
- if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) {
- if (test_bit(BC_FLG_LASTDATA, &bcs->Flag)) {
- test_and_set_bit(BC_FLG_NMD_DATA, &bcs->Flag);
- }
- } else if (bcs->hw.isar.cmd == PCTRL_CMD_FTM) {
- if (test_bit(BC_FLG_DLEETX, &bcs->Flag)) {
- test_and_set_bit(BC_FLG_LASTDATA, &bcs->Flag);
- test_and_set_bit(BC_FLG_NMD_DATA, &bcs->Flag);
- }
- }
- }
- dev_kfree_skb_any(bcs->tx_skb);
- bcs->hw.isar.txcnt = 0;
- bcs->tx_skb = NULL;
- }
- }
- if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
- bcs->hw.isar.txcnt = 0;
- test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
- isar_fill_fifo(bcs);
- } else {
- if (test_and_clear_bit(BC_FLG_DLEETX, &bcs->Flag)) {
- if (test_and_clear_bit(BC_FLG_LASTDATA, &bcs->Flag)) {
- if (test_and_clear_bit(BC_FLG_NMD_DATA, &bcs->Flag)) {
- u_char dummy = 0;
- sendmsg(bcs->cs, SET_DPS(bcs->hw.isar.dpath) |
- ISAR_HIS_SDATA, 0x01, 1, &dummy);
- }
- test_and_set_bit(BC_FLG_LL_OK, &bcs->Flag);
- } else {
- schedule_event(bcs, B_LL_CONNECT);
- }
- }
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- schedule_event(bcs, B_XMTBUFREADY);
- }
-}
-
-static inline void
-check_send(struct IsdnCardState *cs, u_char rdm)
-{
- struct BCState *bcs;
-
- if (rdm & BSTAT_RDM1) {
- if ((bcs = sel_bcs_isar(cs, 1))) {
- if (bcs->mode) {
- send_frames(bcs);
- }
- }
- }
- if (rdm & BSTAT_RDM2) {
- if ((bcs = sel_bcs_isar(cs, 2))) {
- if (bcs->mode) {
- send_frames(bcs);
- }
- }
- }
-
-}
-
-static const char *dmril[] = {"NO SPEED", "1200/75", "NODEF2", "75/1200",
- "NODEF4", "300", "600", "1200", "2400",
- "4800", "7200", "9600nt", "9600t", "12000",
- "14400", "WRONG"};
-static const char *dmrim[] = {"NO MOD", "NO DEF", "V32/V32b", "V22", "V21",
- "Bell103", "V23", "Bell202", "V17", "V29",
- "V27ter"};
-
-static void
-isar_pump_status_rsp(struct BCState *bcs, struct isar_reg *ireg) {
- struct IsdnCardState *cs = bcs->cs;
- u_char ril = ireg->par[0];
- u_char rim;
-
- if (!test_and_clear_bit(ISAR_RATE_REQ, &bcs->hw.isar.reg->Flags))
- return;
- if (ril > 14) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "wrong pstrsp ril=%d", ril);
- ril = 15;
- }
- switch (ireg->par[1]) {
- case 0:
- rim = 0;
- break;
- case 0x20:
- rim = 2;
- break;
- case 0x40:
- rim = 3;
- break;
- case 0x41:
- rim = 4;
- break;
- case 0x51:
- rim = 5;
- break;
- case 0x61:
- rim = 6;
- break;
- case 0x71:
- rim = 7;
- break;
- case 0x82:
- rim = 8;
- break;
- case 0x92:
- rim = 9;
- break;
- case 0xa2:
- rim = 10;
- break;
- default:
- rim = 1;
- break;
- }
- sprintf(bcs->hw.isar.conmsg, "%s %s", dmril[ril], dmrim[rim]);
- bcs->conmsg = bcs->hw.isar.conmsg;
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "pump strsp %s", bcs->conmsg);
-}
-
-static void
-isar_pump_statev_modem(struct BCState *bcs, u_char devt) {
- struct IsdnCardState *cs = bcs->cs;
- u_char dps = SET_DPS(bcs->hw.isar.dpath);
-
- switch (devt) {
- case PSEV_10MS_TIMER:
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "pump stev TIMER");
- break;
- case PSEV_CON_ON:
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "pump stev CONNECT");
- l1_msg_b(bcs->st, PH_ACTIVATE | REQUEST, NULL);
- break;
- case PSEV_CON_OFF:
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "pump stev NO CONNECT");
- sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
- l1_msg_b(bcs->st, PH_DEACTIVATE | REQUEST, NULL);
- break;
- case PSEV_V24_OFF:
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "pump stev V24 OFF");
- break;
- case PSEV_CTS_ON:
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "pump stev CTS ON");
- break;
- case PSEV_CTS_OFF:
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "pump stev CTS OFF");
- break;
- case PSEV_DCD_ON:
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "pump stev CARRIER ON");
- test_and_set_bit(ISAR_RATE_REQ, &bcs->hw.isar.reg->Flags);
- sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
- break;
- case PSEV_DCD_OFF:
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "pump stev CARRIER OFF");
- break;
- case PSEV_DSR_ON:
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "pump stev DSR ON");
- break;
- case PSEV_DSR_OFF:
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "pump stev DSR_OFF");
- break;
- case PSEV_REM_RET:
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "pump stev REMOTE RETRAIN");
- break;
- case PSEV_REM_REN:
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "pump stev REMOTE RENEGOTIATE");
- break;
- case PSEV_GSTN_CLR:
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "pump stev GSTN CLEAR");
- break;
- default:
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "unknown pump stev %x", devt);
- break;
- }
-}
-
-static void
-ll_deliver_faxstat(struct BCState *bcs, u_char status)
-{
- isdn_ctrl ic;
- struct Channel *chanp = (struct Channel *) bcs->st->lli.userdata;
-
- if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs, "HL->LL FAXIND %x", status);
- ic.driver = bcs->cs->myid;
- ic.command = ISDN_STAT_FAXIND;
- ic.arg = chanp->chan;
- ic.parm.aux.cmd = status;
- bcs->cs->iif.statcallb(&ic);
-}
-
-static void
-isar_pump_statev_fax(struct BCState *bcs, u_char devt) {
- struct IsdnCardState *cs = bcs->cs;
- u_char dps = SET_DPS(bcs->hw.isar.dpath);
- u_char p1;
-
- switch (devt) {
- case PSEV_10MS_TIMER:
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "pump stev TIMER");
- break;
- case PSEV_RSP_READY:
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "pump stev RSP_READY");
- bcs->hw.isar.state = STFAX_READY;
- l1_msg_b(bcs->st, PH_ACTIVATE | REQUEST, NULL);
- if (test_bit(BC_FLG_ORIG, &bcs->Flag)) {
- isar_pump_cmd(bcs, ISDN_FAX_CLASS1_FRH, 3);
- } else {
- isar_pump_cmd(bcs, ISDN_FAX_CLASS1_FTH, 3);
- }
- break;
- case PSEV_LINE_TX_H:
- if (bcs->hw.isar.state == STFAX_LINE) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "pump stev LINE_TX_H");
- bcs->hw.isar.state = STFAX_CONT;
- sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL);
- } else {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "pump stev LINE_TX_H wrong st %x",
- bcs->hw.isar.state);
- }
- break;
- case PSEV_LINE_RX_H:
- if (bcs->hw.isar.state == STFAX_LINE) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "pump stev LINE_RX_H");
- bcs->hw.isar.state = STFAX_CONT;
- sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL);
- } else {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "pump stev LINE_RX_H wrong st %x",
- bcs->hw.isar.state);
- }
- break;
- case PSEV_LINE_TX_B:
- if (bcs->hw.isar.state == STFAX_LINE) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "pump stev LINE_TX_B");
- bcs->hw.isar.state = STFAX_CONT;
- sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL);
- } else {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "pump stev LINE_TX_B wrong st %x",
- bcs->hw.isar.state);
- }
- break;
- case PSEV_LINE_RX_B:
- if (bcs->hw.isar.state == STFAX_LINE) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "pump stev LINE_RX_B");
- bcs->hw.isar.state = STFAX_CONT;
- sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL);
- } else {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "pump stev LINE_RX_B wrong st %x",
- bcs->hw.isar.state);
- }
- break;
- case PSEV_RSP_CONN:
- if (bcs->hw.isar.state == STFAX_CONT) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "pump stev RSP_CONN");
- bcs->hw.isar.state = STFAX_ACTIV;
- test_and_set_bit(ISAR_RATE_REQ, &bcs->hw.isar.reg->Flags);
- sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
- if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) {
- /* 1s Flags before data */
- if (test_and_set_bit(BC_FLG_FTI_RUN, &bcs->Flag))
- del_timer(&bcs->hw.isar.ftimer);
- /* 1000 ms */
- bcs->hw.isar.ftimer.expires =
- jiffies + ((1000 * HZ) / 1000);
- test_and_set_bit(BC_FLG_LL_CONN,
- &bcs->Flag);
- add_timer(&bcs->hw.isar.ftimer);
- } else {
- schedule_event(bcs, B_LL_CONNECT);
- }
- } else {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "pump stev RSP_CONN wrong st %x",
- bcs->hw.isar.state);
- }
- break;
- case PSEV_FLAGS_DET:
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "pump stev FLAGS_DET");
- break;
- case PSEV_RSP_DISC:
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "pump stev RSP_DISC");
- if (bcs->hw.isar.state == STFAX_ESCAPE) {
- p1 = 5;
- switch (bcs->hw.isar.newcmd) {
- case 0:
- bcs->hw.isar.state = STFAX_READY;
- break;
- case PCTRL_CMD_FTM:
- p1 = 2;
- /* fall through */
- case PCTRL_CMD_FTH:
- sendmsg(cs, dps | ISAR_HIS_PUMPCTRL,
- PCTRL_CMD_SILON, 1, &p1);
- bcs->hw.isar.state = STFAX_SILDET;
- break;
- case PCTRL_CMD_FRM:
- if (frm_extra_delay)
- mdelay(frm_extra_delay);
- /* fall through */
- case PCTRL_CMD_FRH:
- p1 = bcs->hw.isar.mod = bcs->hw.isar.newmod;
- bcs->hw.isar.newmod = 0;
- bcs->hw.isar.cmd = bcs->hw.isar.newcmd;
- bcs->hw.isar.newcmd = 0;
- sendmsg(cs, dps | ISAR_HIS_PUMPCTRL,
- bcs->hw.isar.cmd, 1, &p1);
- bcs->hw.isar.state = STFAX_LINE;
- bcs->hw.isar.try_mod = 3;
- break;
- default:
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "RSP_DISC unknown newcmd %x", bcs->hw.isar.newcmd);
- break;
- }
- } else if (bcs->hw.isar.state == STFAX_ACTIV) {
- if (test_and_clear_bit(BC_FLG_LL_OK, &bcs->Flag)) {
- schedule_event(bcs, B_LL_OK);
- } else if (bcs->hw.isar.cmd == PCTRL_CMD_FRM) {
- send_DLE_ETX(bcs);
- schedule_event(bcs, B_LL_NOCARRIER);
- } else {
- ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_FCERROR);
- }
- bcs->hw.isar.state = STFAX_READY;
- } else {
- bcs->hw.isar.state = STFAX_READY;
- ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_FCERROR);
- }
- break;
- case PSEV_RSP_SILDET:
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "pump stev RSP_SILDET");
- if (bcs->hw.isar.state == STFAX_SILDET) {
- p1 = bcs->hw.isar.mod = bcs->hw.isar.newmod;
- bcs->hw.isar.newmod = 0;
- bcs->hw.isar.cmd = bcs->hw.isar.newcmd;
- bcs->hw.isar.newcmd = 0;
- sendmsg(cs, dps | ISAR_HIS_PUMPCTRL,
- bcs->hw.isar.cmd, 1, &p1);
- bcs->hw.isar.state = STFAX_LINE;
- bcs->hw.isar.try_mod = 3;
- }
- break;
- case PSEV_RSP_SILOFF:
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "pump stev RSP_SILOFF");
- break;
- case PSEV_RSP_FCERR:
- if (bcs->hw.isar.state == STFAX_LINE) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "pump stev RSP_FCERR try %d",
- bcs->hw.isar.try_mod);
- if (bcs->hw.isar.try_mod--) {
- sendmsg(cs, dps | ISAR_HIS_PUMPCTRL,
- bcs->hw.isar.cmd, 1,
- &bcs->hw.isar.mod);
- break;
- }
- }
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "pump stev RSP_FCERR");
- bcs->hw.isar.state = STFAX_ESCAPE;
- sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL);
- ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_FCERROR);
- break;
- default:
- break;
- }
-}
-
-static char debbuf[128];
-
-void
-isar_int_main(struct IsdnCardState *cs)
-{
- struct isar_reg *ireg = cs->bcs[0].hw.isar.reg;
- struct BCState *bcs;
-
- get_irq_infos(cs, ireg);
- switch (ireg->iis & ISAR_IIS_MSCMSD) {
- case ISAR_IIS_RDATA:
- if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) {
- isar_rcv_frame(cs, bcs);
- } else {
- debugl1(cs, "isar spurious IIS_RDATA %x/%x/%x",
- ireg->iis, ireg->cmsb, ireg->clsb);
- cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
- }
- break;
- case ISAR_IIS_GSTEV:
- cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
- ireg->bstat |= ireg->cmsb;
- check_send(cs, ireg->cmsb);
- break;
- case ISAR_IIS_BSTEV:
-#ifdef ERROR_STATISTIC
- if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) {
- if (ireg->cmsb == BSTEV_TBO)
- bcs->err_tx++;
- if (ireg->cmsb == BSTEV_RBO)
- bcs->err_rdo++;
- }
-#endif
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "Buffer STEV dpath%d msb(%x)",
- ireg->iis >> 6, ireg->cmsb);
- cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
- break;
- case ISAR_IIS_PSTEV:
- if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) {
- rcv_mbox(cs, ireg, (u_char *)ireg->par);
- if (bcs->mode == L1_MODE_V32) {
- isar_pump_statev_modem(bcs, ireg->cmsb);
- } else if (bcs->mode == L1_MODE_FAX) {
- isar_pump_statev_fax(bcs, ireg->cmsb);
- } else if (ireg->cmsb == PSEV_10MS_TIMER) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "pump stev TIMER");
- } else {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "isar IIS_PSTEV pmode %d stat %x",
- bcs->mode, ireg->cmsb);
- }
- } else {
- debugl1(cs, "isar spurious IIS_PSTEV %x/%x/%x",
- ireg->iis, ireg->cmsb, ireg->clsb);
- cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
- }
- break;
- case ISAR_IIS_PSTRSP:
- if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) {
- rcv_mbox(cs, ireg, (u_char *)ireg->par);
- isar_pump_status_rsp(bcs, ireg);
- } else {
- debugl1(cs, "isar spurious IIS_PSTRSP %x/%x/%x",
- ireg->iis, ireg->cmsb, ireg->clsb);
- cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
- }
- break;
- case ISAR_IIS_DIAG:
- case ISAR_IIS_BSTRSP:
- case ISAR_IIS_IOM2RSP:
- rcv_mbox(cs, ireg, (u_char *)ireg->par);
- if ((cs->debug & (L1_DEB_HSCX | L1_DEB_HSCX_FIFO))
- == L1_DEB_HSCX) {
- u_char *tp = debbuf;
-
- tp += sprintf(debbuf, "msg iis(%x) msb(%x)",
- ireg->iis, ireg->cmsb);
- QuickHex(tp, (u_char *)ireg->par, ireg->clsb);
- debugl1(cs, "%s", debbuf);
- }
- break;
- case ISAR_IIS_INVMSG:
- rcv_mbox(cs, ireg, debbuf);
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "invalid msg his:%x",
- ireg->cmsb);
- break;
- default:
- rcv_mbox(cs, ireg, debbuf);
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "unhandled msg iis(%x) ctrl(%x/%x)",
- ireg->iis, ireg->cmsb, ireg->clsb);
- break;
- }
-}
-
-static void
-ftimer_handler(struct timer_list *t) {
- struct BCState *bcs = from_timer(bcs, t, hw.isar.ftimer);
- if (bcs->cs->debug)
- debugl1(bcs->cs, "ftimer flags %04lx",
- bcs->Flag);
- test_and_clear_bit(BC_FLG_FTI_RUN, &bcs->Flag);
- if (test_and_clear_bit(BC_FLG_LL_CONN, &bcs->Flag)) {
- schedule_event(bcs, B_LL_CONNECT);
- }
- if (test_and_clear_bit(BC_FLG_FTI_FTS, &bcs->Flag)) {
- schedule_event(bcs, B_LL_OK);
- }
-}
-
-static void
-setup_pump(struct BCState *bcs) {
- struct IsdnCardState *cs = bcs->cs;
- u_char dps = SET_DPS(bcs->hw.isar.dpath);
- u_char ctrl, param[6];
-
- switch (bcs->mode) {
- case L1_MODE_NULL:
- case L1_MODE_TRANS:
- case L1_MODE_HDLC:
- sendmsg(cs, dps | ISAR_HIS_PUMPCFG, PMOD_BYPASS, 0, NULL);
- break;
- case L1_MODE_V32:
- ctrl = PMOD_DATAMODEM;
- if (test_bit(BC_FLG_ORIG, &bcs->Flag)) {
- ctrl |= PCTRL_ORIG;
- param[5] = PV32P6_CTN;
- } else {
- param[5] = PV32P6_ATN;
- }
- param[0] = para_TOA; /* 6 db */
- param[1] = PV32P2_V23R | PV32P2_V22A | PV32P2_V22B |
- PV32P2_V22C | PV32P2_V21 | PV32P2_BEL;
- param[2] = PV32P3_AMOD | PV32P3_V32B | PV32P3_V23B;
- param[3] = PV32P4_UT144;
- param[4] = PV32P5_UT144;
- sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 6, param);
- break;
- case L1_MODE_FAX:
- ctrl = PMOD_FAX;
- if (test_bit(BC_FLG_ORIG, &bcs->Flag)) {
- ctrl |= PCTRL_ORIG;
- param[1] = PFAXP2_CTN;
- } else {
- param[1] = PFAXP2_ATN;
- }
- param[0] = para_TOA; /* 6 db */
- sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param);
- bcs->hw.isar.state = STFAX_NULL;
- bcs->hw.isar.newcmd = 0;
- bcs->hw.isar.newmod = 0;
- test_and_set_bit(BC_FLG_FTI_RUN, &bcs->Flag);
- break;
- }
- udelay(1000);
- sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
- udelay(1000);
-}
-
-static void
-setup_sart(struct BCState *bcs) {
- struct IsdnCardState *cs = bcs->cs;
- u_char dps = SET_DPS(bcs->hw.isar.dpath);
- u_char ctrl, param[2];
-
- switch (bcs->mode) {
- case L1_MODE_NULL:
- sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_DISABLE, 0,
- NULL);
- break;
- case L1_MODE_TRANS:
- sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_BINARY, 2,
- "\0\0");
- break;
- case L1_MODE_HDLC:
- param[0] = 0;
- sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, 1,
- param);
- break;
- case L1_MODE_V32:
- ctrl = SMODE_V14 | SCTRL_HDMC_BOTH;
- param[0] = S_P1_CHS_8;
- param[1] = S_P2_BFT_DEF;
- sendmsg(cs, dps | ISAR_HIS_SARTCFG, ctrl, 2,
- param);
- break;
- case L1_MODE_FAX:
- /* SART must not configured with FAX */
- break;
- }
- udelay(1000);
- sendmsg(cs, dps | ISAR_HIS_BSTREQ, 0, 0, NULL);
- udelay(1000);
-}
-
-static void
-setup_iom2(struct BCState *bcs) {
- struct IsdnCardState *cs = bcs->cs;
- u_char dps = SET_DPS(bcs->hw.isar.dpath);
- u_char cmsb = IOM_CTRL_ENA, msg[5] = {IOM_P1_TXD, 0, 0, 0, 0};
-
- if (bcs->channel)
- msg[1] = msg[3] = 1;
- switch (bcs->mode) {
- case L1_MODE_NULL:
- cmsb = 0;
- /* dummy slot */
- msg[1] = msg[3] = bcs->hw.isar.dpath + 2;
- break;
- case L1_MODE_TRANS:
- case L1_MODE_HDLC:
- break;
- case L1_MODE_V32:
- case L1_MODE_FAX:
- cmsb |= IOM_CTRL_ALAW | IOM_CTRL_RCV;
- break;
- }
- sendmsg(cs, dps | ISAR_HIS_IOM2CFG, cmsb, 5, msg);
- udelay(1000);
- sendmsg(cs, dps | ISAR_HIS_IOM2REQ, 0, 0, NULL);
- udelay(1000);
-}
-
-static int
-modeisar(struct BCState *bcs, int mode, int bc)
-{
- struct IsdnCardState *cs = bcs->cs;
-
- /* Here we are selecting the best datapath for requested mode */
- if (bcs->mode == L1_MODE_NULL) { /* New Setup */
- bcs->channel = bc;
- switch (mode) {
- case L1_MODE_NULL: /* init */
- if (!bcs->hw.isar.dpath)
- /* no init for dpath 0 */
- return (0);
- break;
- case L1_MODE_TRANS:
- case L1_MODE_HDLC:
- /* best is datapath 2 */
- if (!test_and_set_bit(ISAR_DP2_USE,
- &bcs->hw.isar.reg->Flags))
- bcs->hw.isar.dpath = 2;
- else if (!test_and_set_bit(ISAR_DP1_USE,
- &bcs->hw.isar.reg->Flags))
- bcs->hw.isar.dpath = 1;
- else {
- printk(KERN_WARNING"isar modeisar both paths in use\n");
- return (1);
- }
- break;
- case L1_MODE_V32:
- case L1_MODE_FAX:
- /* only datapath 1 */
- if (!test_and_set_bit(ISAR_DP1_USE,
- &bcs->hw.isar.reg->Flags))
- bcs->hw.isar.dpath = 1;
- else {
- printk(KERN_WARNING"isar modeisar analog functions only with DP1\n");
- debugl1(cs, "isar modeisar analog functions only with DP1");
- return (1);
- }
- break;
- }
- }
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "isar dp%d mode %d->%d ichan %d",
- bcs->hw.isar.dpath, bcs->mode, mode, bc);
- bcs->mode = mode;
- setup_pump(bcs);
- setup_iom2(bcs);
- setup_sart(bcs);
- if (bcs->mode == L1_MODE_NULL) {
- /* Clear resources */
- if (bcs->hw.isar.dpath == 1)
- test_and_clear_bit(ISAR_DP1_USE, &bcs->hw.isar.reg->Flags);
- else if (bcs->hw.isar.dpath == 2)
- test_and_clear_bit(ISAR_DP2_USE, &bcs->hw.isar.reg->Flags);
- bcs->hw.isar.dpath = 0;
- }
- return (0);
-}
-
-static void
-isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para)
-{
- struct IsdnCardState *cs = bcs->cs;
- u_char dps = SET_DPS(bcs->hw.isar.dpath);
- u_char ctrl = 0, nom = 0, p1 = 0;
-
- switch (cmd) {
- case ISDN_FAX_CLASS1_FTM:
- test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag);
- if (bcs->hw.isar.state == STFAX_READY) {
- p1 = para;
- ctrl = PCTRL_CMD_FTM;
- nom = 1;
- bcs->hw.isar.state = STFAX_LINE;
- bcs->hw.isar.cmd = ctrl;
- bcs->hw.isar.mod = para;
- bcs->hw.isar.newmod = 0;
- bcs->hw.isar.newcmd = 0;
- bcs->hw.isar.try_mod = 3;
- } else if ((bcs->hw.isar.state == STFAX_ACTIV) &&
- (bcs->hw.isar.cmd == PCTRL_CMD_FTM) &&
- (bcs->hw.isar.mod == para)) {
- ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT);
- } else {
- bcs->hw.isar.newmod = para;
- bcs->hw.isar.newcmd = PCTRL_CMD_FTM;
- nom = 0;
- ctrl = PCTRL_CMD_ESC;
- bcs->hw.isar.state = STFAX_ESCAPE;
- }
- break;
- case ISDN_FAX_CLASS1_FTH:
- test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag);
- if (bcs->hw.isar.state == STFAX_READY) {
- p1 = para;
- ctrl = PCTRL_CMD_FTH;
- nom = 1;
- bcs->hw.isar.state = STFAX_LINE;
- bcs->hw.isar.cmd = ctrl;
- bcs->hw.isar.mod = para;
- bcs->hw.isar.newmod = 0;
- bcs->hw.isar.newcmd = 0;
- bcs->hw.isar.try_mod = 3;
- } else if ((bcs->hw.isar.state == STFAX_ACTIV) &&
- (bcs->hw.isar.cmd == PCTRL_CMD_FTH) &&
- (bcs->hw.isar.mod == para)) {
- ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT);
- } else {
- bcs->hw.isar.newmod = para;
- bcs->hw.isar.newcmd = PCTRL_CMD_FTH;
- nom = 0;
- ctrl = PCTRL_CMD_ESC;
- bcs->hw.isar.state = STFAX_ESCAPE;
- }
- break;
- case ISDN_FAX_CLASS1_FRM:
- test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag);
- if (bcs->hw.isar.state == STFAX_READY) {
- p1 = para;
- ctrl = PCTRL_CMD_FRM;
- nom = 1;
- bcs->hw.isar.state = STFAX_LINE;
- bcs->hw.isar.cmd = ctrl;
- bcs->hw.isar.mod = para;
- bcs->hw.isar.newmod = 0;
- bcs->hw.isar.newcmd = 0;
- bcs->hw.isar.try_mod = 3;
- } else if ((bcs->hw.isar.state == STFAX_ACTIV) &&
- (bcs->hw.isar.cmd == PCTRL_CMD_FRM) &&
- (bcs->hw.isar.mod == para)) {
- ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT);
- } else {
- bcs->hw.isar.newmod = para;
- bcs->hw.isar.newcmd = PCTRL_CMD_FRM;
- nom = 0;
- ctrl = PCTRL_CMD_ESC;
- bcs->hw.isar.state = STFAX_ESCAPE;
- }
- break;
- case ISDN_FAX_CLASS1_FRH:
- test_and_set_bit(BC_FLG_FRH_WAIT, &bcs->Flag);
- if (bcs->hw.isar.state == STFAX_READY) {
- p1 = para;
- ctrl = PCTRL_CMD_FRH;
- nom = 1;
- bcs->hw.isar.state = STFAX_LINE;
- bcs->hw.isar.cmd = ctrl;
- bcs->hw.isar.mod = para;
- bcs->hw.isar.newmod = 0;
- bcs->hw.isar.newcmd = 0;
- bcs->hw.isar.try_mod = 3;
- } else if ((bcs->hw.isar.state == STFAX_ACTIV) &&
- (bcs->hw.isar.cmd == PCTRL_CMD_FRH) &&
- (bcs->hw.isar.mod == para)) {
- ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT);
- } else {
- bcs->hw.isar.newmod = para;
- bcs->hw.isar.newcmd = PCTRL_CMD_FRH;
- nom = 0;
- ctrl = PCTRL_CMD_ESC;
- bcs->hw.isar.state = STFAX_ESCAPE;
- }
- break;
- case ISDN_FAXPUMP_HALT:
- bcs->hw.isar.state = STFAX_NULL;
- nom = 0;
- ctrl = PCTRL_CMD_HALT;
- break;
- }
- if (ctrl)
- sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, ctrl, nom, &p1);
-}
-
-static void
-isar_setup(struct IsdnCardState *cs)
-{
- u_char msg;
- int i;
-
- /* Dpath 1, 2 */
- msg = 61;
- for (i = 0; i < 2; i++) {
- /* Buffer Config */
- sendmsg(cs, (i ? ISAR_HIS_DPS2 : ISAR_HIS_DPS1) |
- ISAR_HIS_P12CFG, 4, 1, &msg);
- cs->bcs[i].hw.isar.mml = msg;
- cs->bcs[i].mode = 0;
- cs->bcs[i].hw.isar.dpath = i + 1;
- modeisar(&cs->bcs[i], 0, 0);
- INIT_WORK(&cs->bcs[i].tqueue, isar_bh);
- }
-}
-
-static void
-isar_l2l1(struct PStack *st, int pr, void *arg)
-{
- struct BCState *bcs = st->l1.bcs;
- struct sk_buff *skb = arg;
- int ret;
- u_long flags;
-
- switch (pr) {
- case (PH_DATA | REQUEST):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- if (bcs->tx_skb) {
- skb_queue_tail(&bcs->squeue, skb);
- } else {
- bcs->tx_skb = skb;
- test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
- if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs, "DRQ set BC_FLG_BUSY");
- bcs->hw.isar.txcnt = 0;
- bcs->cs->BC_Send_Data(bcs);
- }
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- break;
- case (PH_PULL | INDICATION):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- if (bcs->tx_skb) {
- printk(KERN_WARNING "isar_l2l1: this shouldn't happen\n");
- } else {
- test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
- if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs, "PUI set BC_FLG_BUSY");
- bcs->tx_skb = skb;
- bcs->hw.isar.txcnt = 0;
- bcs->cs->BC_Send_Data(bcs);
- }
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- break;
- case (PH_PULL | REQUEST):
- if (!bcs->tx_skb) {
- test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
- } else
- test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- break;
- case (PH_ACTIVATE | REQUEST):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
- bcs->hw.isar.conmsg[0] = 0;
- if (test_bit(FLG_ORIG, &st->l2.flag))
- test_and_set_bit(BC_FLG_ORIG, &bcs->Flag);
- else
- test_and_clear_bit(BC_FLG_ORIG, &bcs->Flag);
- switch (st->l1.mode) {
- case L1_MODE_TRANS:
- case L1_MODE_HDLC:
- ret = modeisar(bcs, st->l1.mode, st->l1.bc);
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- if (ret)
- l1_msg_b(st, PH_DEACTIVATE | REQUEST, arg);
- else
- l1_msg_b(st, PH_ACTIVATE | REQUEST, arg);
- break;
- case L1_MODE_V32:
- case L1_MODE_FAX:
- ret = modeisar(bcs, st->l1.mode, st->l1.bc);
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- if (ret)
- l1_msg_b(st, PH_DEACTIVATE | REQUEST, arg);
- break;
- default:
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- break;
- }
- break;
- case (PH_DEACTIVATE | REQUEST):
- l1_msg_b(st, pr, arg);
- break;
- case (PH_DEACTIVATE | CONFIRM):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- switch (st->l1.mode) {
- case L1_MODE_TRANS:
- case L1_MODE_HDLC:
- case L1_MODE_V32:
- break;
- case L1_MODE_FAX:
- isar_pump_cmd(bcs, ISDN_FAXPUMP_HALT, 0);
- break;
- }
- test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs, "PDAC clear BC_FLG_BUSY");
- modeisar(bcs, 0, st->l1.bc);
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
- break;
- }
-}
-
-static void
-close_isarstate(struct BCState *bcs)
-{
- modeisar(bcs, 0, bcs->channel);
- if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
- kfree(bcs->hw.isar.rcvbuf);
- bcs->hw.isar.rcvbuf = NULL;
- skb_queue_purge(&bcs->rqueue);
- skb_queue_purge(&bcs->squeue);
- if (bcs->tx_skb) {
- dev_kfree_skb_any(bcs->tx_skb);
- bcs->tx_skb = NULL;
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs, "closeisar clear BC_FLG_BUSY");
- }
- }
- del_timer(&bcs->hw.isar.ftimer);
-}
-
-static int
-open_isarstate(struct IsdnCardState *cs, struct BCState *bcs)
-{
- if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
- if (!(bcs->hw.isar.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
- printk(KERN_WARNING
- "HiSax: No memory for isar.rcvbuf\n");
- return (1);
- }
- skb_queue_head_init(&bcs->rqueue);
- skb_queue_head_init(&bcs->squeue);
- }
- bcs->tx_skb = NULL;
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "openisar clear BC_FLG_BUSY");
- bcs->event = 0;
- bcs->hw.isar.rcvidx = 0;
- bcs->tx_cnt = 0;
- return (0);
-}
-
-static int
-setstack_isar(struct PStack *st, struct BCState *bcs)
-{
- bcs->channel = st->l1.bc;
- if (open_isarstate(st->l1.hardware, bcs))
- return (-1);
- st->l1.bcs = bcs;
- st->l2.l2l1 = isar_l2l1;
- setstack_manager(st);
- bcs->st = st;
- setstack_l1_B(st);
- return (0);
-}
-
-int
-isar_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) {
- u_long adr;
- int features, i;
- struct BCState *bcs;
-
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "isar_auxcmd cmd/ch %x/%ld", ic->command, ic->arg);
- switch (ic->command) {
- case (ISDN_CMD_FAXCMD):
- bcs = cs->channel[ic->arg].bcs;
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "isar_auxcmd cmd/subcmd %d/%d",
- ic->parm.aux.cmd, ic->parm.aux.subcmd);
- switch (ic->parm.aux.cmd) {
- case ISDN_FAX_CLASS1_CTRL:
- if (ic->parm.aux.subcmd == ETX)
- test_and_set_bit(BC_FLG_DLEETX,
- &bcs->Flag);
- break;
- case ISDN_FAX_CLASS1_FTS:
- if (ic->parm.aux.subcmd == AT_QUERY) {
- ic->command = ISDN_STAT_FAXIND;
- ic->parm.aux.cmd = ISDN_FAX_CLASS1_OK;
- cs->iif.statcallb(ic);
- return (0);
- } else if (ic->parm.aux.subcmd == AT_EQ_QUERY) {
- strcpy(ic->parm.aux.para, "0-255");
- ic->command = ISDN_STAT_FAXIND;
- ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY;
- cs->iif.statcallb(ic);
- return (0);
- } else if (ic->parm.aux.subcmd == AT_EQ_VALUE) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "isar_auxcmd %s=%d",
- FC1_CMD[ic->parm.aux.cmd], ic->parm.aux.para[0]);
- if (bcs->hw.isar.state == STFAX_READY) {
- if (!ic->parm.aux.para[0]) {
- ic->command = ISDN_STAT_FAXIND;
- ic->parm.aux.cmd = ISDN_FAX_CLASS1_OK;
- cs->iif.statcallb(ic);
- return (0);
- }
- if (!test_and_set_bit(BC_FLG_FTI_RUN, &bcs->Flag)) {
- /* n*10 ms */
- bcs->hw.isar.ftimer.expires =
- jiffies + ((ic->parm.aux.para[0] * 10 * HZ) / 1000);
- test_and_set_bit(BC_FLG_FTI_FTS, &bcs->Flag);
- add_timer(&bcs->hw.isar.ftimer);
- return (0);
- } else {
- if (cs->debug)
- debugl1(cs, "isar FTS=%d and FTI busy",
- ic->parm.aux.para[0]);
- }
- } else {
- if (cs->debug)
- debugl1(cs, "isar FTS=%d and isar.state not ready(%x)",
- ic->parm.aux.para[0], bcs->hw.isar.state);
- }
- ic->command = ISDN_STAT_FAXIND;
- ic->parm.aux.cmd = ISDN_FAX_CLASS1_ERROR;
- cs->iif.statcallb(ic);
- }
- break;
- case ISDN_FAX_CLASS1_FRM:
- case ISDN_FAX_CLASS1_FRH:
- case ISDN_FAX_CLASS1_FTM:
- case ISDN_FAX_CLASS1_FTH:
- if (ic->parm.aux.subcmd == AT_QUERY) {
- sprintf(ic->parm.aux.para,
- "%d", bcs->hw.isar.mod);
- ic->command = ISDN_STAT_FAXIND;
- ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY;
- cs->iif.statcallb(ic);
- return (0);
- } else if (ic->parm.aux.subcmd == AT_EQ_QUERY) {
- char *p = ic->parm.aux.para;
- for (i = 0; i < FAXMODCNT; i++)
- if ((1 << i) & modmask)
- p += sprintf(p, "%d,", faxmodulation[i]);
- p--;
- *p = 0;
- ic->command = ISDN_STAT_FAXIND;
- ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY;
- cs->iif.statcallb(ic);
- return (0);
- } else if (ic->parm.aux.subcmd == AT_EQ_VALUE) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "isar_auxcmd %s=%d",
- FC1_CMD[ic->parm.aux.cmd], ic->parm.aux.para[0]);
- for (i = 0; i < FAXMODCNT; i++)
- if (faxmodulation[i] == ic->parm.aux.para[0])
- break;
- if ((i < FAXMODCNT) && ((1 << i) & modmask) &&
- test_bit(BC_FLG_INIT, &bcs->Flag)) {
- isar_pump_cmd(bcs,
- ic->parm.aux.cmd,
- ic->parm.aux.para[0]);
- return (0);
- }
- }
- /* wrong modulation or not activ */
- /* fall through */
- default:
- ic->command = ISDN_STAT_FAXIND;
- ic->parm.aux.cmd = ISDN_FAX_CLASS1_ERROR;
- cs->iif.statcallb(ic);
- }
- break;
- case (ISDN_CMD_IOCTL):
- switch (ic->arg) {
- case 9: /* load firmware */
- features = ISDN_FEATURE_L2_MODEM |
- ISDN_FEATURE_L2_FAX |
- ISDN_FEATURE_L3_FCLASS1;
- memcpy(&adr, ic->parm.num, sizeof(ulong));
- if (isar_load_firmware(cs, (u_char __user *)adr))
- return (1);
- else
- ll_run(cs, features);
- break;
- case 20:
- features = *(unsigned int *) ic->parm.num;
- printk(KERN_DEBUG "HiSax: max modulation old(%04x) new(%04x)\n",
- modmask, features);
- modmask = features;
- break;
- case 21:
- features = *(unsigned int *) ic->parm.num;
- printk(KERN_DEBUG "HiSax: FRM extra delay old(%d) new(%d) ms\n",
- frm_extra_delay, features);
- if (features >= 0)
- frm_extra_delay = features;
- break;
- case 22:
- features = *(unsigned int *) ic->parm.num;
- printk(KERN_DEBUG "HiSax: TOA old(%d) new(%d) db\n",
- para_TOA, features);
- if (features >= 0 && features < 32)
- para_TOA = features;
- break;
- default:
- printk(KERN_DEBUG "HiSax: invalid ioctl %d\n",
- (int) ic->arg);
- return (-EINVAL);
- }
- break;
- default:
- return (-EINVAL);
- }
- return (0);
-}
-
-void initisar(struct IsdnCardState *cs)
-{
- cs->bcs[0].BC_SetStack = setstack_isar;
- cs->bcs[1].BC_SetStack = setstack_isar;
- cs->bcs[0].BC_Close = close_isarstate;
- cs->bcs[1].BC_Close = close_isarstate;
- timer_setup(&cs->bcs[0].hw.isar.ftimer, ftimer_handler, 0);
- timer_setup(&cs->bcs[1].hw.isar.ftimer, ftimer_handler, 0);
-}
diff --git a/drivers/isdn/hisax/isar.h b/drivers/isdn/hisax/isar.h
deleted file mode 100644
index 0f4d101faf37..000000000000
--- a/drivers/isdn/hisax/isar.h
+++ /dev/null
@@ -1,222 +0,0 @@
-/* $Id: isar.h,v 1.11.2.2 2004/01/12 22:52:27 keil Exp $
- *
- * ISAR (Siemens PSB 7110) specific defines
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#define ISAR_IRQMSK 0x04
-#define ISAR_IRQSTA 0x04
-#define ISAR_IRQBIT 0x75
-#define ISAR_CTRL_H 0x61
-#define ISAR_CTRL_L 0x60
-#define ISAR_IIS 0x58
-#define ISAR_IIA 0x58
-#define ISAR_HIS 0x50
-#define ISAR_HIA 0x50
-#define ISAR_MBOX 0x4c
-#define ISAR_WADR 0x4a
-#define ISAR_RADR 0x48
-
-#define ISAR_HIS_VNR 0x14
-#define ISAR_HIS_DKEY 0x02
-#define ISAR_HIS_FIRM 0x1e
-#define ISAR_HIS_STDSP 0x08
-#define ISAR_HIS_DIAG 0x05
-#define ISAR_HIS_WAITSTATE 0x27
-#define ISAR_HIS_TIMERIRQ 0x25
-#define ISAR_HIS_P0CFG 0x3c
-#define ISAR_HIS_P12CFG 0x24
-#define ISAR_HIS_SARTCFG 0x25
-#define ISAR_HIS_PUMPCFG 0x26
-#define ISAR_HIS_PUMPCTRL 0x2a
-#define ISAR_HIS_IOM2CFG 0x27
-#define ISAR_HIS_IOM2REQ 0x07
-#define ISAR_HIS_IOM2CTRL 0x2b
-#define ISAR_HIS_BSTREQ 0x0c
-#define ISAR_HIS_PSTREQ 0x0e
-#define ISAR_HIS_SDATA 0x20
-#define ISAR_HIS_DPS1 0x40
-#define ISAR_HIS_DPS2 0x80
-#define SET_DPS(x) ((x << 6) & 0xc0)
-
-#define ISAR_CMD_TIMERIRQ_OFF 0x20
-#define ISAR_CMD_TIMERIRQ_ON 0x21
-
-
-#define ISAR_IIS_MSCMSD 0x3f
-#define ISAR_IIS_VNR 0x15
-#define ISAR_IIS_DKEY 0x03
-#define ISAR_IIS_FIRM 0x1f
-#define ISAR_IIS_STDSP 0x09
-#define ISAR_IIS_DIAG 0x25
-#define ISAR_IIS_GSTEV 0x00
-#define ISAR_IIS_BSTEV 0x28
-#define ISAR_IIS_BSTRSP 0x2c
-#define ISAR_IIS_PSTRSP 0x2e
-#define ISAR_IIS_PSTEV 0x2a
-#define ISAR_IIS_IOM2RSP 0x27
-#define ISAR_IIS_RDATA 0x20
-#define ISAR_IIS_INVMSG 0x3f
-
-#define ISAR_CTRL_SWVER 0x10
-#define ISAR_CTRL_STST 0x40
-
-#define ISAR_MSG_HWVER {0x20, 0, 1}
-
-#define ISAR_DP1_USE 1
-#define ISAR_DP2_USE 2
-#define ISAR_RATE_REQ 3
-
-#define PMOD_DISABLE 0
-#define PMOD_FAX 1
-#define PMOD_DATAMODEM 2
-#define PMOD_HALFDUPLEX 3
-#define PMOD_V110 4
-#define PMOD_DTMF 5
-#define PMOD_DTMF_TRANS 6
-#define PMOD_BYPASS 7
-
-#define PCTRL_ORIG 0x80
-#define PV32P2_V23R 0x40
-#define PV32P2_V22A 0x20
-#define PV32P2_V22B 0x10
-#define PV32P2_V22C 0x08
-#define PV32P2_V21 0x02
-#define PV32P2_BEL 0x01
-
-// LSB MSB in ISAR doc wrong !!! Arghhh
-#define PV32P3_AMOD 0x80
-#define PV32P3_V32B 0x02
-#define PV32P3_V23B 0x01
-#define PV32P4_48 0x11
-#define PV32P5_48 0x05
-#define PV32P4_UT48 0x11
-#define PV32P5_UT48 0x0d
-#define PV32P4_96 0x11
-#define PV32P5_96 0x03
-#define PV32P4_UT96 0x11
-#define PV32P5_UT96 0x0f
-#define PV32P4_B96 0x91
-#define PV32P5_B96 0x0b
-#define PV32P4_UTB96 0xd1
-#define PV32P5_UTB96 0x0f
-#define PV32P4_120 0xb1
-#define PV32P5_120 0x09
-#define PV32P4_UT120 0xf1
-#define PV32P5_UT120 0x0f
-#define PV32P4_144 0x99
-#define PV32P5_144 0x09
-#define PV32P4_UT144 0xf9
-#define PV32P5_UT144 0x0f
-#define PV32P6_CTN 0x01
-#define PV32P6_ATN 0x02
-
-#define PFAXP2_CTN 0x01
-#define PFAXP2_ATN 0x04
-
-#define PSEV_10MS_TIMER 0x02
-#define PSEV_CON_ON 0x18
-#define PSEV_CON_OFF 0x19
-#define PSEV_V24_OFF 0x20
-#define PSEV_CTS_ON 0x21
-#define PSEV_CTS_OFF 0x22
-#define PSEV_DCD_ON 0x23
-#define PSEV_DCD_OFF 0x24
-#define PSEV_DSR_ON 0x25
-#define PSEV_DSR_OFF 0x26
-#define PSEV_REM_RET 0xcc
-#define PSEV_REM_REN 0xcd
-#define PSEV_GSTN_CLR 0xd4
-
-#define PSEV_RSP_READY 0xbc
-#define PSEV_LINE_TX_H 0xb3
-#define PSEV_LINE_TX_B 0xb2
-#define PSEV_LINE_RX_H 0xb1
-#define PSEV_LINE_RX_B 0xb0
-#define PSEV_RSP_CONN 0xb5
-#define PSEV_RSP_DISC 0xb7
-#define PSEV_RSP_FCERR 0xb9
-#define PSEV_RSP_SILDET 0xbe
-#define PSEV_RSP_SILOFF 0xab
-#define PSEV_FLAGS_DET 0xba
-
-#define PCTRL_CMD_FTH 0xa7
-#define PCTRL_CMD_FRH 0xa5
-#define PCTRL_CMD_FTM 0xa8
-#define PCTRL_CMD_FRM 0xa6
-#define PCTRL_CMD_SILON 0xac
-#define PCTRL_CMD_CONT 0xa2
-#define PCTRL_CMD_ESC 0xa4
-#define PCTRL_CMD_SILOFF 0xab
-#define PCTRL_CMD_HALT 0xa9
-
-#define PCTRL_LOC_RET 0xcf
-#define PCTRL_LOC_REN 0xce
-
-#define SMODE_DISABLE 0
-#define SMODE_V14 2
-#define SMODE_HDLC 3
-#define SMODE_BINARY 4
-#define SMODE_FSK_V14 5
-
-#define SCTRL_HDMC_BOTH 0x00
-#define SCTRL_HDMC_DTX 0x80
-#define SCTRL_HDMC_DRX 0x40
-#define S_P1_OVSP 0x40
-#define S_P1_SNP 0x20
-#define S_P1_EOP 0x10
-#define S_P1_EDP 0x08
-#define S_P1_NSB 0x04
-#define S_P1_CHS_8 0x03
-#define S_P1_CHS_7 0x02
-#define S_P1_CHS_6 0x01
-#define S_P1_CHS_5 0x00
-
-#define S_P2_BFT_DEF 0x10
-
-#define IOM_CTRL_ENA 0x80
-#define IOM_CTRL_NOPCM 0x00
-#define IOM_CTRL_ALAW 0x02
-#define IOM_CTRL_ULAW 0x04
-#define IOM_CTRL_RCV 0x01
-
-#define IOM_P1_TXD 0x10
-
-#define HDLC_FED 0x40
-#define HDLC_FSD 0x20
-#define HDLC_FST 0x20
-#define HDLC_ERROR 0x1c
-#define HDLC_ERR_FAD 0x10
-#define HDLC_ERR_RER 0x08
-#define HDLC_ERR_CER 0x04
-#define SART_NMD 0x01
-
-#define BSTAT_RDM0 0x1
-#define BSTAT_RDM1 0x2
-#define BSTAT_RDM2 0x4
-#define BSTAT_RDM3 0x8
-#define BSTEV_TBO 0x1f
-#define BSTEV_RBO 0x2f
-
-/* FAX State Machine */
-#define STFAX_NULL 0
-#define STFAX_READY 1
-#define STFAX_LINE 2
-#define STFAX_CONT 3
-#define STFAX_ACTIV 4
-#define STFAX_ESCAPE 5
-#define STFAX_SILDET 6
-
-#define ISDN_FAXPUMP_HALT 100
-
-extern int ISARVersion(struct IsdnCardState *cs, char *s);
-extern void isar_int_main(struct IsdnCardState *cs);
-extern void initisar(struct IsdnCardState *cs);
-extern void isar_fill_fifo(struct BCState *bcs);
-extern int isar_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic);
diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c
deleted file mode 100644
index a560842c0e48..000000000000
--- a/drivers/isdn/hisax/isdnl1.c
+++ /dev/null
@@ -1,930 +0,0 @@
-/* $Id: isdnl1.c,v 2.46.2.5 2004/02/11 13:21:34 keil Exp $
- *
- * common low level stuff for Siemens Chipsetbased isdn cards
- *
- * Author Karsten Keil
- * based on the teles driver from Jan den Ouden
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * For changes and modifications please read
- * Documentation/isdn/HiSax.cert
- *
- * Thanks to Jan den Ouden
- * Fritz Elfert
- * Beat Doebeli
- *
- */
-
-#include <linux/init.h>
-#include <linux/gfp.h>
-#include "hisax.h"
-#include "isdnl1.h"
-
-const char *l1_revision = "$Revision: 2.46.2.5 $";
-
-#define TIMER3_VALUE 7000
-
-static struct Fsm l1fsm_b;
-static struct Fsm l1fsm_s;
-
-enum {
- ST_L1_F2,
- ST_L1_F3,
- ST_L1_F4,
- ST_L1_F5,
- ST_L1_F6,
- ST_L1_F7,
- ST_L1_F8,
-};
-
-#define L1S_STATE_COUNT (ST_L1_F8 + 1)
-
-static char *strL1SState[] =
-{
- "ST_L1_F2",
- "ST_L1_F3",
- "ST_L1_F4",
- "ST_L1_F5",
- "ST_L1_F6",
- "ST_L1_F7",
- "ST_L1_F8",
-};
-
-#ifdef HISAX_UINTERFACE
-static
-struct Fsm l1fsm_u =
-{NULL, 0, 0, NULL, NULL};
-
-enum {
- ST_L1_RESET,
- ST_L1_DEACT,
- ST_L1_SYNC2,
- ST_L1_TRANS,
-};
-
-#define L1U_STATE_COUNT (ST_L1_TRANS + 1)
-
-static char *strL1UState[] =
-{
- "ST_L1_RESET",
- "ST_L1_DEACT",
- "ST_L1_SYNC2",
- "ST_L1_TRANS",
-};
-#endif
-
-enum {
- ST_L1_NULL,
- ST_L1_WAIT_ACT,
- ST_L1_WAIT_DEACT,
- ST_L1_ACTIV,
-};
-
-#define L1B_STATE_COUNT (ST_L1_ACTIV + 1)
-
-static char *strL1BState[] =
-{
- "ST_L1_NULL",
- "ST_L1_WAIT_ACT",
- "ST_L1_WAIT_DEACT",
- "ST_L1_ACTIV",
-};
-
-enum {
- EV_PH_ACTIVATE,
- EV_PH_DEACTIVATE,
- EV_RESET_IND,
- EV_DEACT_CNF,
- EV_DEACT_IND,
- EV_POWER_UP,
- EV_RSYNC_IND,
- EV_INFO2_IND,
- EV_INFO4_IND,
- EV_TIMER_DEACT,
- EV_TIMER_ACT,
- EV_TIMER3,
-};
-
-#define L1_EVENT_COUNT (EV_TIMER3 + 1)
-
-static char *strL1Event[] =
-{
- "EV_PH_ACTIVATE",
- "EV_PH_DEACTIVATE",
- "EV_RESET_IND",
- "EV_DEACT_CNF",
- "EV_DEACT_IND",
- "EV_POWER_UP",
- "EV_RSYNC_IND",
- "EV_INFO2_IND",
- "EV_INFO4_IND",
- "EV_TIMER_DEACT",
- "EV_TIMER_ACT",
- "EV_TIMER3",
-};
-
-void
-debugl1(struct IsdnCardState *cs, char *fmt, ...)
-{
- va_list args;
- char tmp[8];
-
- va_start(args, fmt);
- sprintf(tmp, "Card%d ", cs->cardnr + 1);
- VHiSax_putstatus(cs, tmp, fmt, args);
- va_end(args);
-}
-
-static void
-l1m_debug(struct FsmInst *fi, char *fmt, ...)
-{
- va_list args;
- struct PStack *st = fi->userdata;
- struct IsdnCardState *cs = st->l1.hardware;
- char tmp[8];
-
- va_start(args, fmt);
- sprintf(tmp, "Card%d ", cs->cardnr + 1);
- VHiSax_putstatus(cs, tmp, fmt, args);
- va_end(args);
-}
-
-static void
-L1activated(struct IsdnCardState *cs)
-{
- struct PStack *st;
-
- st = cs->stlist;
- while (st) {
- if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags))
- st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
- else
- st->l1.l1l2(st, PH_ACTIVATE | INDICATION, NULL);
- st = st->next;
- }
-}
-
-static void
-L1deactivated(struct IsdnCardState *cs)
-{
- struct PStack *st;
-
- st = cs->stlist;
- while (st) {
- if (test_bit(FLG_L1_DBUSY, &cs->HW_Flags))
- st->l1.l1l2(st, PH_PAUSE | CONFIRM, NULL);
- st->l1.l1l2(st, PH_DEACTIVATE | INDICATION, NULL);
- st = st->next;
- }
- test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags);
-}
-
-void
-DChannel_proc_xmt(struct IsdnCardState *cs)
-{
- struct PStack *stptr;
-
- if (cs->tx_skb)
- return;
-
- stptr = cs->stlist;
- while (stptr != NULL) {
- if (test_and_clear_bit(FLG_L1_PULL_REQ, &stptr->l1.Flags)) {
- stptr->l1.l1l2(stptr, PH_PULL | CONFIRM, NULL);
- break;
- } else
- stptr = stptr->next;
- }
-}
-
-void
-DChannel_proc_rcv(struct IsdnCardState *cs)
-{
- struct sk_buff *skb, *nskb;
- struct PStack *stptr = cs->stlist;
- int found, tei, sapi;
-
- if (stptr)
- if (test_bit(FLG_L1_ACTTIMER, &stptr->l1.Flags))
- FsmEvent(&stptr->l1.l1m, EV_TIMER_ACT, NULL);
- while ((skb = skb_dequeue(&cs->rq))) {
-#ifdef L2FRAME_DEBUG /* psa */
- if (cs->debug & L1_DEB_LAPD)
- Logl2Frame(cs, skb, "PH_DATA", 1);
-#endif
- stptr = cs->stlist;
- if (skb->len < 3) {
- debugl1(cs, "D-channel frame too short(%d)", skb->len);
- dev_kfree_skb(skb);
- return;
- }
- if ((skb->data[0] & 1) || !(skb->data[1] & 1)) {
- debugl1(cs, "D-channel frame wrong EA0/EA1");
- dev_kfree_skb(skb);
- return;
- }
- sapi = skb->data[0] >> 2;
- tei = skb->data[1] >> 1;
- if (cs->debug & DEB_DLOG_HEX)
- LogFrame(cs, skb->data, skb->len);
- if (cs->debug & DEB_DLOG_VERBOSE)
- dlogframe(cs, skb, 1);
- if (tei == GROUP_TEI) {
- if (sapi == CTRL_SAPI) { /* sapi 0 */
- while (stptr != NULL) {
- if ((nskb = skb_clone(skb, GFP_ATOMIC)))
- stptr->l1.l1l2(stptr, PH_DATA | INDICATION, nskb);
- else
- printk(KERN_WARNING "HiSax: isdn broadcast buffer shortage\n");
- stptr = stptr->next;
- }
- } else if (sapi == TEI_SAPI) {
- while (stptr != NULL) {
- if ((nskb = skb_clone(skb, GFP_ATOMIC)))
- stptr->l1.l1tei(stptr, PH_DATA | INDICATION, nskb);
- else
- printk(KERN_WARNING "HiSax: tei broadcast buffer shortage\n");
- stptr = stptr->next;
- }
- }
- dev_kfree_skb(skb);
- } else if (sapi == CTRL_SAPI) { /* sapi 0 */
- found = 0;
- while (stptr != NULL)
- if (tei == stptr->l2.tei) {
- stptr->l1.l1l2(stptr, PH_DATA | INDICATION, skb);
- found = !0;
- break;
- } else
- stptr = stptr->next;
- if (!found)
- dev_kfree_skb(skb);
- } else
- dev_kfree_skb(skb);
- }
-}
-
-static void
-BChannel_proc_xmt(struct BCState *bcs)
-{
- struct PStack *st = bcs->st;
-
- if (test_bit(BC_FLG_BUSY, &bcs->Flag)) {
- debugl1(bcs->cs, "BC_BUSY Error");
- return;
- }
-
- if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags))
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
- if (!test_bit(BC_FLG_ACTIV, &bcs->Flag)) {
- if (!test_bit(BC_FLG_BUSY, &bcs->Flag) &&
- skb_queue_empty(&bcs->squeue)) {
- st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL);
- }
- }
-}
-
-static void
-BChannel_proc_rcv(struct BCState *bcs)
-{
- struct sk_buff *skb;
-
- if (bcs->st->l1.l1m.state == ST_L1_WAIT_ACT) {
- FsmDelTimer(&bcs->st->l1.timer, 4);
- FsmEvent(&bcs->st->l1.l1m, EV_TIMER_ACT, NULL);
- }
- while ((skb = skb_dequeue(&bcs->rqueue))) {
- bcs->st->l1.l1l2(bcs->st, PH_DATA | INDICATION, skb);
- }
-}
-
-static void
-BChannel_proc_ack(struct BCState *bcs)
-{
- u_long flags;
- int ack;
-
- spin_lock_irqsave(&bcs->aclock, flags);
- ack = bcs->ackcnt;
- bcs->ackcnt = 0;
- spin_unlock_irqrestore(&bcs->aclock, flags);
- if (ack)
- lli_writewakeup(bcs->st, ack);
-}
-
-void
-BChannel_bh(struct work_struct *work)
-{
- struct BCState *bcs = container_of(work, struct BCState, tqueue);
-
- if (!bcs)
- return;
- if (test_and_clear_bit(B_RCVBUFREADY, &bcs->event))
- BChannel_proc_rcv(bcs);
- if (test_and_clear_bit(B_XMTBUFREADY, &bcs->event))
- BChannel_proc_xmt(bcs);
- if (test_and_clear_bit(B_ACKPENDING, &bcs->event))
- BChannel_proc_ack(bcs);
-}
-
-void
-HiSax_addlist(struct IsdnCardState *cs,
- struct PStack *st)
-{
- st->next = cs->stlist;
- cs->stlist = st;
-}
-
-void
-HiSax_rmlist(struct IsdnCardState *cs,
- struct PStack *st)
-{
- struct PStack *p;
-
- FsmDelTimer(&st->l1.timer, 0);
- if (cs->stlist == st)
- cs->stlist = st->next;
- else {
- p = cs->stlist;
- while (p)
- if (p->next == st) {
- p->next = st->next;
- return;
- } else
- p = p->next;
- }
-}
-
-void
-init_bcstate(struct IsdnCardState *cs, int bc)
-{
- struct BCState *bcs = cs->bcs + bc;
-
- bcs->cs = cs;
- bcs->channel = bc;
- INIT_WORK(&bcs->tqueue, BChannel_bh);
- spin_lock_init(&bcs->aclock);
- bcs->BC_SetStack = NULL;
- bcs->BC_Close = NULL;
- bcs->Flag = 0;
-}
-
-#ifdef L2FRAME_DEBUG /* psa */
-
-static char *
-l2cmd(u_char cmd)
-{
- switch (cmd & ~0x10) {
- case 1:
- return "RR";
- case 5:
- return "RNR";
- case 9:
- return "REJ";
- case 0x6f:
- return "SABME";
- case 0x0f:
- return "DM";
- case 3:
- return "UI";
- case 0x43:
- return "DISC";
- case 0x63:
- return "UA";
- case 0x87:
- return "FRMR";
- case 0xaf:
- return "XID";
- default:
- if (!(cmd & 1))
- return "I";
- else
- return "invalid command";
- }
-}
-
-static char tmpdeb[32];
-
-static char *
-l2frames(u_char *ptr)
-{
- switch (ptr[2] & ~0x10) {
- case 1:
- case 5:
- case 9:
- sprintf(tmpdeb, "%s[%d](nr %d)", l2cmd(ptr[2]), ptr[3] & 1, ptr[3] >> 1);
- break;
- case 0x6f:
- case 0x0f:
- case 3:
- case 0x43:
- case 0x63:
- case 0x87:
- case 0xaf:
- sprintf(tmpdeb, "%s[%d]", l2cmd(ptr[2]), (ptr[2] & 0x10) >> 4);
- break;
- default:
- if (!(ptr[2] & 1)) {
- sprintf(tmpdeb, "I[%d](ns %d, nr %d)", ptr[3] & 1, ptr[2] >> 1, ptr[3] >> 1);
- break;
- } else
- return "invalid command";
- }
-
-
- return tmpdeb;
-}
-
-void
-Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, int dir)
-{
- u_char *ptr;
-
- ptr = skb->data;
-
- if (ptr[0] & 1 || !(ptr[1] & 1))
- debugl1(cs, "Address not LAPD");
- else
- debugl1(cs, "%s %s: %s%c (sapi %d, tei %d)",
- (dir ? "<-" : "->"), buf, l2frames(ptr),
- ((ptr[0] & 2) >> 1) == dir ? 'C' : 'R', ptr[0] >> 2, ptr[1] >> 1);
-}
-#endif
-
-static void
-l1_reset(struct FsmInst *fi, int event, void *arg)
-{
- FsmChangeState(fi, ST_L1_F3);
-}
-
-static void
-l1_deact_cnf(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- FsmChangeState(fi, ST_L1_F3);
- if (test_bit(FLG_L1_ACTIVATING, &st->l1.Flags))
- st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL);
-}
-
-static void
-l1_deact_req_s(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- FsmChangeState(fi, ST_L1_F3);
- FsmRestartTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2);
- test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags);
-}
-
-static void
-l1_power_up_s(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- if (test_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) {
- FsmChangeState(fi, ST_L1_F4);
- st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL);
- FsmRestartTimer(&st->l1.timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
- test_and_set_bit(FLG_L1_T3RUN, &st->l1.Flags);
- } else
- FsmChangeState(fi, ST_L1_F3);
-}
-
-static void
-l1_go_F5(struct FsmInst *fi, int event, void *arg)
-{
- FsmChangeState(fi, ST_L1_F5);
-}
-
-static void
-l1_go_F8(struct FsmInst *fi, int event, void *arg)
-{
- FsmChangeState(fi, ST_L1_F8);
-}
-
-static void
-l1_info2_ind(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
-#ifdef HISAX_UINTERFACE
- if (test_bit(FLG_L1_UINT, &st->l1.Flags))
- FsmChangeState(fi, ST_L1_SYNC2);
- else
-#endif
- FsmChangeState(fi, ST_L1_F6);
- st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL);
-}
-
-static void
-l1_info4_ind(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
-#ifdef HISAX_UINTERFACE
- if (test_bit(FLG_L1_UINT, &st->l1.Flags))
- FsmChangeState(fi, ST_L1_TRANS);
- else
-#endif
- FsmChangeState(fi, ST_L1_F7);
- st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL);
- if (test_and_clear_bit(FLG_L1_DEACTTIMER, &st->l1.Flags))
- FsmDelTimer(&st->l1.timer, 4);
- if (!test_bit(FLG_L1_ACTIVATED, &st->l1.Flags)) {
- if (test_and_clear_bit(FLG_L1_T3RUN, &st->l1.Flags))
- FsmDelTimer(&st->l1.timer, 3);
- FsmRestartTimer(&st->l1.timer, 110, EV_TIMER_ACT, NULL, 2);
- test_and_set_bit(FLG_L1_ACTTIMER, &st->l1.Flags);
- }
-}
-
-static void
-l1_timer3(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- test_and_clear_bit(FLG_L1_T3RUN, &st->l1.Flags);
- if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags))
- L1deactivated(st->l1.hardware);
-
-#ifdef HISAX_UINTERFACE
- if (!test_bit(FLG_L1_UINT, &st->l1.Flags))
-#endif
- if (st->l1.l1m.state != ST_L1_F6) {
- FsmChangeState(fi, ST_L1_F3);
- st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL);
- }
-}
-
-static void
-l1_timer_act(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- test_and_clear_bit(FLG_L1_ACTTIMER, &st->l1.Flags);
- test_and_set_bit(FLG_L1_ACTIVATED, &st->l1.Flags);
- L1activated(st->l1.hardware);
-}
-
-static void
-l1_timer_deact(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- test_and_clear_bit(FLG_L1_DEACTTIMER, &st->l1.Flags);
- test_and_clear_bit(FLG_L1_ACTIVATED, &st->l1.Flags);
- L1deactivated(st->l1.hardware);
- st->l1.l1hw(st, HW_DEACTIVATE | RESPONSE, NULL);
-}
-
-static void
-l1_activate_s(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- st->l1.l1hw(st, HW_RESET | REQUEST, NULL);
-}
-
-static void
-l1_activate_no(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- if ((!test_bit(FLG_L1_DEACTTIMER, &st->l1.Flags)) && (!test_bit(FLG_L1_T3RUN, &st->l1.Flags))) {
- test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags);
- L1deactivated(st->l1.hardware);
- }
-}
-
-static struct FsmNode L1SFnList[] __initdata =
-{
- {ST_L1_F3, EV_PH_ACTIVATE, l1_activate_s},
- {ST_L1_F6, EV_PH_ACTIVATE, l1_activate_no},
- {ST_L1_F8, EV_PH_ACTIVATE, l1_activate_no},
- {ST_L1_F3, EV_RESET_IND, l1_reset},
- {ST_L1_F4, EV_RESET_IND, l1_reset},
- {ST_L1_F5, EV_RESET_IND, l1_reset},
- {ST_L1_F6, EV_RESET_IND, l1_reset},
- {ST_L1_F7, EV_RESET_IND, l1_reset},
- {ST_L1_F8, EV_RESET_IND, l1_reset},
- {ST_L1_F3, EV_DEACT_CNF, l1_deact_cnf},
- {ST_L1_F4, EV_DEACT_CNF, l1_deact_cnf},
- {ST_L1_F5, EV_DEACT_CNF, l1_deact_cnf},
- {ST_L1_F6, EV_DEACT_CNF, l1_deact_cnf},
- {ST_L1_F7, EV_DEACT_CNF, l1_deact_cnf},
- {ST_L1_F8, EV_DEACT_CNF, l1_deact_cnf},
- {ST_L1_F6, EV_DEACT_IND, l1_deact_req_s},
- {ST_L1_F7, EV_DEACT_IND, l1_deact_req_s},
- {ST_L1_F8, EV_DEACT_IND, l1_deact_req_s},
- {ST_L1_F3, EV_POWER_UP, l1_power_up_s},
- {ST_L1_F4, EV_RSYNC_IND, l1_go_F5},
- {ST_L1_F6, EV_RSYNC_IND, l1_go_F8},
- {ST_L1_F7, EV_RSYNC_IND, l1_go_F8},
- {ST_L1_F3, EV_INFO2_IND, l1_info2_ind},
- {ST_L1_F4, EV_INFO2_IND, l1_info2_ind},
- {ST_L1_F5, EV_INFO2_IND, l1_info2_ind},
- {ST_L1_F7, EV_INFO2_IND, l1_info2_ind},
- {ST_L1_F8, EV_INFO2_IND, l1_info2_ind},
- {ST_L1_F3, EV_INFO4_IND, l1_info4_ind},
- {ST_L1_F4, EV_INFO4_IND, l1_info4_ind},
- {ST_L1_F5, EV_INFO4_IND, l1_info4_ind},
- {ST_L1_F6, EV_INFO4_IND, l1_info4_ind},
- {ST_L1_F8, EV_INFO4_IND, l1_info4_ind},
- {ST_L1_F3, EV_TIMER3, l1_timer3},
- {ST_L1_F4, EV_TIMER3, l1_timer3},
- {ST_L1_F5, EV_TIMER3, l1_timer3},
- {ST_L1_F6, EV_TIMER3, l1_timer3},
- {ST_L1_F8, EV_TIMER3, l1_timer3},
- {ST_L1_F7, EV_TIMER_ACT, l1_timer_act},
- {ST_L1_F3, EV_TIMER_DEACT, l1_timer_deact},
- {ST_L1_F4, EV_TIMER_DEACT, l1_timer_deact},
- {ST_L1_F5, EV_TIMER_DEACT, l1_timer_deact},
- {ST_L1_F6, EV_TIMER_DEACT, l1_timer_deact},
- {ST_L1_F7, EV_TIMER_DEACT, l1_timer_deact},
- {ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact},
-};
-
-#ifdef HISAX_UINTERFACE
-static void
-l1_deact_req_u(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- FsmChangeState(fi, ST_L1_RESET);
- FsmRestartTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2);
- test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags);
- st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL);
-}
-
-static void
-l1_power_up_u(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- FsmRestartTimer(&st->l1.timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
- test_and_set_bit(FLG_L1_T3RUN, &st->l1.Flags);
-}
-
-static void
-l1_info0_ind(struct FsmInst *fi, int event, void *arg)
-{
- FsmChangeState(fi, ST_L1_DEACT);
-}
-
-static void
-l1_activate_u(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- st->l1.l1hw(st, HW_INFO1 | REQUEST, NULL);
-}
-
-static struct FsmNode L1UFnList[] __initdata =
-{
- {ST_L1_RESET, EV_DEACT_IND, l1_deact_req_u},
- {ST_L1_DEACT, EV_DEACT_IND, l1_deact_req_u},
- {ST_L1_SYNC2, EV_DEACT_IND, l1_deact_req_u},
- {ST_L1_TRANS, EV_DEACT_IND, l1_deact_req_u},
- {ST_L1_DEACT, EV_PH_ACTIVATE, l1_activate_u},
- {ST_L1_DEACT, EV_POWER_UP, l1_power_up_u},
- {ST_L1_DEACT, EV_INFO2_IND, l1_info2_ind},
- {ST_L1_TRANS, EV_INFO2_IND, l1_info2_ind},
- {ST_L1_RESET, EV_DEACT_CNF, l1_info0_ind},
- {ST_L1_DEACT, EV_INFO4_IND, l1_info4_ind},
- {ST_L1_SYNC2, EV_INFO4_IND, l1_info4_ind},
- {ST_L1_RESET, EV_INFO4_IND, l1_info4_ind},
- {ST_L1_DEACT, EV_TIMER3, l1_timer3},
- {ST_L1_SYNC2, EV_TIMER3, l1_timer3},
- {ST_L1_TRANS, EV_TIMER_ACT, l1_timer_act},
- {ST_L1_DEACT, EV_TIMER_DEACT, l1_timer_deact},
- {ST_L1_SYNC2, EV_TIMER_DEACT, l1_timer_deact},
- {ST_L1_RESET, EV_TIMER_DEACT, l1_timer_deact},
-};
-
-#endif
-
-static void
-l1b_activate(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- FsmChangeState(fi, ST_L1_WAIT_ACT);
- FsmRestartTimer(&st->l1.timer, st->l1.delay, EV_TIMER_ACT, NULL, 2);
-}
-
-static void
-l1b_deactivate(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- FsmChangeState(fi, ST_L1_WAIT_DEACT);
- FsmRestartTimer(&st->l1.timer, 10, EV_TIMER_DEACT, NULL, 2);
-}
-
-static void
-l1b_timer_act(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- FsmChangeState(fi, ST_L1_ACTIV);
- st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
-}
-
-static void
-l1b_timer_deact(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- FsmChangeState(fi, ST_L1_NULL);
- st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL);
-}
-
-static struct FsmNode L1BFnList[] __initdata =
-{
- {ST_L1_NULL, EV_PH_ACTIVATE, l1b_activate},
- {ST_L1_WAIT_ACT, EV_TIMER_ACT, l1b_timer_act},
- {ST_L1_ACTIV, EV_PH_DEACTIVATE, l1b_deactivate},
- {ST_L1_WAIT_DEACT, EV_TIMER_DEACT, l1b_timer_deact},
-};
-
-int __init
-Isdnl1New(void)
-{
- int retval;
-
- l1fsm_s.state_count = L1S_STATE_COUNT;
- l1fsm_s.event_count = L1_EVENT_COUNT;
- l1fsm_s.strEvent = strL1Event;
- l1fsm_s.strState = strL1SState;
- retval = FsmNew(&l1fsm_s, L1SFnList, ARRAY_SIZE(L1SFnList));
- if (retval)
- return retval;
-
- l1fsm_b.state_count = L1B_STATE_COUNT;
- l1fsm_b.event_count = L1_EVENT_COUNT;
- l1fsm_b.strEvent = strL1Event;
- l1fsm_b.strState = strL1BState;
- retval = FsmNew(&l1fsm_b, L1BFnList, ARRAY_SIZE(L1BFnList));
- if (retval) {
- FsmFree(&l1fsm_s);
- return retval;
- }
-#ifdef HISAX_UINTERFACE
- l1fsm_u.state_count = L1U_STATE_COUNT;
- l1fsm_u.event_count = L1_EVENT_COUNT;
- l1fsm_u.strEvent = strL1Event;
- l1fsm_u.strState = strL1UState;
- retval = FsmNew(&l1fsm_u, L1UFnList, ARRAY_SIZE(L1UFnList));
- if (retval) {
- FsmFree(&l1fsm_s);
- FsmFree(&l1fsm_b);
- return retval;
- }
-#endif
- return 0;
-}
-
-void Isdnl1Free(void)
-{
-#ifdef HISAX_UINTERFACE
- FsmFree(&l1fsm_u);
-#endif
- FsmFree(&l1fsm_s);
- FsmFree(&l1fsm_b);
-}
-
-static void
-dch_l2l1(struct PStack *st, int pr, void *arg)
-{
- struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
-
- switch (pr) {
- case (PH_DATA | REQUEST):
- case (PH_PULL | REQUEST):
- case (PH_PULL | INDICATION):
- st->l1.l1hw(st, pr, arg);
- break;
- case (PH_ACTIVATE | REQUEST):
- if (cs->debug)
- debugl1(cs, "PH_ACTIVATE_REQ %s",
- st->l1.l1m.fsm->strState[st->l1.l1m.state]);
- if (test_bit(FLG_L1_ACTIVATED, &st->l1.Flags))
- st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
- else {
- test_and_set_bit(FLG_L1_ACTIVATING, &st->l1.Flags);
- FsmEvent(&st->l1.l1m, EV_PH_ACTIVATE, arg);
- }
- break;
- case (PH_TESTLOOP | REQUEST):
- if (1 & (long) arg)
- debugl1(cs, "PH_TEST_LOOP B1");
- if (2 & (long) arg)
- debugl1(cs, "PH_TEST_LOOP B2");
- if (!(3 & (long) arg))
- debugl1(cs, "PH_TEST_LOOP DISABLED");
- st->l1.l1hw(st, HW_TESTLOOP | REQUEST, arg);
- break;
- default:
- if (cs->debug)
- debugl1(cs, "dch_l2l1 msg %04X unhandled", pr);
- break;
- }
-}
-
-void
-l1_msg(struct IsdnCardState *cs, int pr, void *arg) {
- struct PStack *st;
-
- st = cs->stlist;
-
- while (st) {
- switch (pr) {
- case (HW_RESET | INDICATION):
- FsmEvent(&st->l1.l1m, EV_RESET_IND, arg);
- break;
- case (HW_DEACTIVATE | CONFIRM):
- FsmEvent(&st->l1.l1m, EV_DEACT_CNF, arg);
- break;
- case (HW_DEACTIVATE | INDICATION):
- FsmEvent(&st->l1.l1m, EV_DEACT_IND, arg);
- break;
- case (HW_POWERUP | CONFIRM):
- FsmEvent(&st->l1.l1m, EV_POWER_UP, arg);
- break;
- case (HW_RSYNC | INDICATION):
- FsmEvent(&st->l1.l1m, EV_RSYNC_IND, arg);
- break;
- case (HW_INFO2 | INDICATION):
- FsmEvent(&st->l1.l1m, EV_INFO2_IND, arg);
- break;
- case (HW_INFO4_P8 | INDICATION):
- case (HW_INFO4_P10 | INDICATION):
- FsmEvent(&st->l1.l1m, EV_INFO4_IND, arg);
- break;
- default:
- if (cs->debug)
- debugl1(cs, "%s %04X unhandled", __func__, pr);
- break;
- }
- st = st->next;
- }
-}
-
-void
-l1_msg_b(struct PStack *st, int pr, void *arg) {
- switch (pr) {
- case (PH_ACTIVATE | REQUEST):
- FsmEvent(&st->l1.l1m, EV_PH_ACTIVATE, NULL);
- break;
- case (PH_DEACTIVATE | REQUEST):
- FsmEvent(&st->l1.l1m, EV_PH_DEACTIVATE, NULL);
- break;
- }
-}
-
-void
-setstack_HiSax(struct PStack *st, struct IsdnCardState *cs)
-{
- st->l1.hardware = cs;
- st->protocol = cs->protocol;
- st->l1.l1m.fsm = &l1fsm_s;
- st->l1.l1m.state = ST_L1_F3;
- st->l1.Flags = 0;
-#ifdef HISAX_UINTERFACE
- if (test_bit(FLG_HW_L1_UINT, &cs->HW_Flags)) {
- st->l1.l1m.fsm = &l1fsm_u;
- st->l1.l1m.state = ST_L1_RESET;
- st->l1.Flags = FLG_L1_UINT;
- }
-#endif
- st->l1.l1m.debug = cs->debug;
- st->l1.l1m.userdata = st;
- st->l1.l1m.userint = 0;
- st->l1.l1m.printdebug = l1m_debug;
- FsmInitTimer(&st->l1.l1m, &st->l1.timer);
- setstack_tei(st);
- setstack_manager(st);
- st->l1.stlistp = &(cs->stlist);
- st->l2.l2l1 = dch_l2l1;
- if (cs->setstack_d)
- cs->setstack_d(st, cs);
-}
-
-void
-setstack_l1_B(struct PStack *st)
-{
- struct IsdnCardState *cs = st->l1.hardware;
-
- st->l1.l1m.fsm = &l1fsm_b;
- st->l1.l1m.state = ST_L1_NULL;
- st->l1.l1m.debug = cs->debug;
- st->l1.l1m.userdata = st;
- st->l1.l1m.userint = 0;
- st->l1.l1m.printdebug = l1m_debug;
- st->l1.Flags = 0;
- FsmInitTimer(&st->l1.l1m, &st->l1.timer);
-}
diff --git a/drivers/isdn/hisax/isdnl1.h b/drivers/isdn/hisax/isdnl1.h
deleted file mode 100644
index 66ddcab19bba..000000000000
--- a/drivers/isdn/hisax/isdnl1.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* $Id: isdnl1.h,v 2.12.2.3 2004/02/11 13:21:34 keil Exp $
- *
- * Layer 1 defines
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#define D_RCVBUFREADY 0
-#define D_XMTBUFREADY 1
-#define D_L1STATECHANGE 2
-#define D_CLEARBUSY 3
-#define D_RX_MON0 4
-#define D_RX_MON1 5
-#define D_TX_MON0 6
-#define D_TX_MON1 7
-#define E_RCVBUFREADY 8
-
-#define B_RCVBUFREADY 0
-#define B_XMTBUFREADY 1
-#define B_ACKPENDING 2
-
-__printf(2, 3)
-void debugl1(struct IsdnCardState *cs, char *fmt, ...);
-void DChannel_proc_xmt(struct IsdnCardState *cs);
-void DChannel_proc_rcv(struct IsdnCardState *cs);
-void l1_msg(struct IsdnCardState *cs, int pr, void *arg);
-void l1_msg_b(struct PStack *st, int pr, void *arg);
-void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf,
- int dir);
-void BChannel_bh(struct work_struct *work);
diff --git a/drivers/isdn/hisax/isdnl2.c b/drivers/isdn/hisax/isdnl2.c
deleted file mode 100644
index 1a40ed04cb52..000000000000
--- a/drivers/isdn/hisax/isdnl2.c
+++ /dev/null
@@ -1,1839 +0,0 @@
-/* $Id: isdnl2.c,v 2.30.2.4 2004/02/11 13:21:34 keil Exp $
- *
- * Author Karsten Keil
- * based on the teles driver from Jan den Ouden
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * For changes and modifications please read
- * Documentation/isdn/HiSax.cert
- *
- * Thanks to Jan den Ouden
- * Fritz Elfert
- *
- */
-
-#include <linux/init.h>
-#include <linux/gfp.h>
-#include "hisax.h"
-#include "isdnl2.h"
-
-const char *l2_revision = "$Revision: 2.30.2.4 $";
-
-static void l2m_debug(struct FsmInst *fi, char *fmt, ...);
-
-static struct Fsm l2fsm;
-
-enum {
- ST_L2_1,
- ST_L2_2,
- ST_L2_3,
- ST_L2_4,
- ST_L2_5,
- ST_L2_6,
- ST_L2_7,
- ST_L2_8,
-};
-
-#define L2_STATE_COUNT (ST_L2_8 + 1)
-
-static char *strL2State[] =
-{
- "ST_L2_1",
- "ST_L2_2",
- "ST_L2_3",
- "ST_L2_4",
- "ST_L2_5",
- "ST_L2_6",
- "ST_L2_7",
- "ST_L2_8",
-};
-
-enum {
- EV_L2_UI,
- EV_L2_SABME,
- EV_L2_DISC,
- EV_L2_DM,
- EV_L2_UA,
- EV_L2_FRMR,
- EV_L2_SUPER,
- EV_L2_I,
- EV_L2_DL_DATA,
- EV_L2_ACK_PULL,
- EV_L2_DL_UNIT_DATA,
- EV_L2_DL_ESTABLISH_REQ,
- EV_L2_DL_RELEASE_REQ,
- EV_L2_MDL_ASSIGN,
- EV_L2_MDL_REMOVE,
- EV_L2_MDL_ERROR,
- EV_L1_DEACTIVATE,
- EV_L2_T200,
- EV_L2_T203,
- EV_L2_SET_OWN_BUSY,
- EV_L2_CLEAR_OWN_BUSY,
- EV_L2_FRAME_ERROR,
-};
-
-#define L2_EVENT_COUNT (EV_L2_FRAME_ERROR + 1)
-
-static char *strL2Event[] =
-{
- "EV_L2_UI",
- "EV_L2_SABME",
- "EV_L2_DISC",
- "EV_L2_DM",
- "EV_L2_UA",
- "EV_L2_FRMR",
- "EV_L2_SUPER",
- "EV_L2_I",
- "EV_L2_DL_DATA",
- "EV_L2_ACK_PULL",
- "EV_L2_DL_UNIT_DATA",
- "EV_L2_DL_ESTABLISH_REQ",
- "EV_L2_DL_RELEASE_REQ",
- "EV_L2_MDL_ASSIGN",
- "EV_L2_MDL_REMOVE",
- "EV_L2_MDL_ERROR",
- "EV_L1_DEACTIVATE",
- "EV_L2_T200",
- "EV_L2_T203",
- "EV_L2_SET_OWN_BUSY",
- "EV_L2_CLEAR_OWN_BUSY",
- "EV_L2_FRAME_ERROR",
-};
-
-static int l2addrsize(struct Layer2 *l2);
-
-static void
-set_peer_busy(struct Layer2 *l2) {
- test_and_set_bit(FLG_PEER_BUSY, &l2->flag);
- if (!skb_queue_empty(&l2->i_queue) ||
- !skb_queue_empty(&l2->ui_queue))
- test_and_set_bit(FLG_L2BLOCK, &l2->flag);
-}
-
-static void
-clear_peer_busy(struct Layer2 *l2) {
- if (test_and_clear_bit(FLG_PEER_BUSY, &l2->flag))
- test_and_clear_bit(FLG_L2BLOCK, &l2->flag);
-}
-
-static void
-InitWin(struct Layer2 *l2)
-{
- int i;
-
- for (i = 0; i < MAX_WINDOW; i++)
- l2->windowar[i] = NULL;
-}
-
-static int
-freewin1(struct Layer2 *l2)
-{
- int i, cnt = 0;
-
- for (i = 0; i < MAX_WINDOW; i++) {
- if (l2->windowar[i]) {
- cnt++;
- dev_kfree_skb(l2->windowar[i]);
- l2->windowar[i] = NULL;
- }
- }
- return cnt;
-}
-
-static inline void
-freewin(struct PStack *st)
-{
- freewin1(&st->l2);
-}
-
-static void
-ReleaseWin(struct Layer2 *l2)
-{
- int cnt;
-
- if ((cnt = freewin1(l2)))
- printk(KERN_WARNING "isdl2 freed %d skbuffs in release\n", cnt);
-}
-
-static inline unsigned int
-cansend(struct PStack *st)
-{
- unsigned int p1;
-
- if (test_bit(FLG_MOD128, &st->l2.flag))
- p1 = (st->l2.vs - st->l2.va) % 128;
- else
- p1 = (st->l2.vs - st->l2.va) % 8;
- return ((p1 < st->l2.window) && !test_bit(FLG_PEER_BUSY, &st->l2.flag));
-}
-
-static inline void
-clear_exception(struct Layer2 *l2)
-{
- test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
- test_and_clear_bit(FLG_REJEXC, &l2->flag);
- test_and_clear_bit(FLG_OWN_BUSY, &l2->flag);
- clear_peer_busy(l2);
-}
-
-static inline int
-l2headersize(struct Layer2 *l2, int ui)
-{
- return (((test_bit(FLG_MOD128, &l2->flag) && (!ui)) ? 2 : 1) +
- (test_bit(FLG_LAPD, &l2->flag) ? 2 : 1));
-}
-
-inline int
-l2addrsize(struct Layer2 *l2)
-{
- return (test_bit(FLG_LAPD, &l2->flag) ? 2 : 1);
-}
-
-static int
-sethdraddr(struct Layer2 *l2, u_char *header, int rsp)
-{
- u_char *ptr = header;
- int crbit = rsp;
-
- if (test_bit(FLG_LAPD, &l2->flag)) {
- *ptr++ = (l2->sap << 2) | (rsp ? 2 : 0);
- *ptr++ = (l2->tei << 1) | 1;
- return (2);
- } else {
- if (test_bit(FLG_ORIG, &l2->flag))
- crbit = !crbit;
- if (crbit)
- *ptr++ = 1;
- else
- *ptr++ = 3;
- return (1);
- }
-}
-
-static inline void
-enqueue_super(struct PStack *st,
- struct sk_buff *skb)
-{
- if (test_bit(FLG_LAPB, &st->l2.flag))
- st->l1.bcs->tx_cnt += skb->len;
- st->l2.l2l1(st, PH_DATA | REQUEST, skb);
-}
-
-#define enqueue_ui(a, b) enqueue_super(a, b)
-
-static inline int
-IsUI(u_char *data)
-{
- return ((data[0] & 0xef) == UI);
-}
-
-static inline int
-IsUA(u_char *data)
-{
- return ((data[0] & 0xef) == UA);
-}
-
-static inline int
-IsDM(u_char *data)
-{
- return ((data[0] & 0xef) == DM);
-}
-
-static inline int
-IsDISC(u_char *data)
-{
- return ((data[0] & 0xef) == DISC);
-}
-
-static inline int
-IsSFrame(u_char *data, struct PStack *st)
-{
- register u_char d = *data;
-
- if (!test_bit(FLG_MOD128, &st->l2.flag))
- d &= 0xf;
- return (((d & 0xf3) == 1) && ((d & 0x0c) != 0x0c));
-}
-
-static inline int
-IsSABME(u_char *data, struct PStack *st)
-{
- u_char d = data[0] & ~0x10;
-
- return (test_bit(FLG_MOD128, &st->l2.flag) ? d == SABME : d == SABM);
-}
-
-static inline int
-IsREJ(u_char *data, struct PStack *st)
-{
- return (test_bit(FLG_MOD128, &st->l2.flag) ? data[0] == REJ : (data[0] & 0xf) == REJ);
-}
-
-static inline int
-IsFRMR(u_char *data)
-{
- return ((data[0] & 0xef) == FRMR);
-}
-
-static inline int
-IsRNR(u_char *data, struct PStack *st)
-{
- return (test_bit(FLG_MOD128, &st->l2.flag) ? data[0] == RNR : (data[0] & 0xf) == RNR);
-}
-
-static int
-iframe_error(struct PStack *st, struct sk_buff *skb)
-{
- int i = l2addrsize(&st->l2) + (test_bit(FLG_MOD128, &st->l2.flag) ? 2 : 1);
- int rsp = *skb->data & 0x2;
-
- if (test_bit(FLG_ORIG, &st->l2.flag))
- rsp = !rsp;
-
- if (rsp)
- return 'L';
-
-
- if (skb->len < i)
- return 'N';
-
- if ((skb->len - i) > st->l2.maxlen)
- return 'O';
-
-
- return 0;
-}
-
-static int
-super_error(struct PStack *st, struct sk_buff *skb)
-{
- if (skb->len != l2addrsize(&st->l2) +
- (test_bit(FLG_MOD128, &st->l2.flag) ? 2 : 1))
- return 'N';
-
- return 0;
-}
-
-static int
-unnum_error(struct PStack *st, struct sk_buff *skb, int wantrsp)
-{
- int rsp = (*skb->data & 0x2) >> 1;
- if (test_bit(FLG_ORIG, &st->l2.flag))
- rsp = !rsp;
-
- if (rsp != wantrsp)
- return 'L';
-
- if (skb->len != l2addrsize(&st->l2) + 1)
- return 'N';
-
- return 0;
-}
-
-static int
-UI_error(struct PStack *st, struct sk_buff *skb)
-{
- int rsp = *skb->data & 0x2;
- if (test_bit(FLG_ORIG, &st->l2.flag))
- rsp = !rsp;
-
- if (rsp)
- return 'L';
-
- if (skb->len > st->l2.maxlen + l2addrsize(&st->l2) + 1)
- return 'O';
-
- return 0;
-}
-
-static int
-FRMR_error(struct PStack *st, struct sk_buff *skb)
-{
- int headers = l2addrsize(&st->l2) + 1;
- u_char *datap = skb->data + headers;
- int rsp = *skb->data & 0x2;
-
- if (test_bit(FLG_ORIG, &st->l2.flag))
- rsp = !rsp;
-
- if (!rsp)
- return 'L';
-
- if (test_bit(FLG_MOD128, &st->l2.flag)) {
- if (skb->len < headers + 5)
- return 'N';
- else
- l2m_debug(&st->l2.l2m, "FRMR information %2x %2x %2x %2x %2x",
- datap[0], datap[1], datap[2],
- datap[3], datap[4]);
- } else {
- if (skb->len < headers + 3)
- return 'N';
- else
- l2m_debug(&st->l2.l2m, "FRMR information %2x %2x %2x",
- datap[0], datap[1], datap[2]);
- }
-
- return 0;
-}
-
-static unsigned int
-legalnr(struct PStack *st, unsigned int nr)
-{
- struct Layer2 *l2 = &st->l2;
-
- if (test_bit(FLG_MOD128, &l2->flag))
- return ((nr - l2->va) % 128) <= ((l2->vs - l2->va) % 128);
- else
- return ((nr - l2->va) % 8) <= ((l2->vs - l2->va) % 8);
-}
-
-static void
-setva(struct PStack *st, unsigned int nr)
-{
- struct Layer2 *l2 = &st->l2;
- int len;
- u_long flags;
-
- spin_lock_irqsave(&l2->lock, flags);
- while (l2->va != nr) {
- (l2->va)++;
- if (test_bit(FLG_MOD128, &l2->flag))
- l2->va %= 128;
- else
- l2->va %= 8;
- len = l2->windowar[l2->sow]->len;
- if (PACKET_NOACK == l2->windowar[l2->sow]->pkt_type)
- len = -1;
- dev_kfree_skb(l2->windowar[l2->sow]);
- l2->windowar[l2->sow] = NULL;
- l2->sow = (l2->sow + 1) % l2->window;
- spin_unlock_irqrestore(&l2->lock, flags);
- if (test_bit(FLG_LLI_L2WAKEUP, &st->lli.flag) && (len >= 0))
- lli_writewakeup(st, len);
- spin_lock_irqsave(&l2->lock, flags);
- }
- spin_unlock_irqrestore(&l2->lock, flags);
-}
-
-static void
-send_uframe(struct PStack *st, u_char cmd, u_char cr)
-{
- struct sk_buff *skb;
- u_char tmp[MAX_HEADER_LEN];
- int i;
-
- i = sethdraddr(&st->l2, tmp, cr);
- tmp[i++] = cmd;
- if (!(skb = alloc_skb(i, GFP_ATOMIC))) {
- printk(KERN_WARNING "isdl2 can't alloc sbbuff for send_uframe\n");
- return;
- }
- skb_put_data(skb, tmp, i);
- enqueue_super(st, skb);
-}
-
-static inline u_char
-get_PollFlag(struct PStack *st, struct sk_buff *skb)
-{
- return (skb->data[l2addrsize(&(st->l2))] & 0x10);
-}
-
-static inline u_char
-get_PollFlagFree(struct PStack *st, struct sk_buff *skb)
-{
- u_char PF;
-
- PF = get_PollFlag(st, skb);
- dev_kfree_skb(skb);
- return (PF);
-}
-
-static inline void
-start_t200(struct PStack *st, int i)
-{
- FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, i);
- test_and_set_bit(FLG_T200_RUN, &st->l2.flag);
-}
-
-static inline void
-restart_t200(struct PStack *st, int i)
-{
- FsmRestartTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, i);
- test_and_set_bit(FLG_T200_RUN, &st->l2.flag);
-}
-
-static inline void
-stop_t200(struct PStack *st, int i)
-{
- if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
- FsmDelTimer(&st->l2.t200, i);
-}
-
-static inline void
-st5_dl_release_l2l3(struct PStack *st)
-{
- int pr;
-
- if (test_and_clear_bit(FLG_PEND_REL, &st->l2.flag))
- pr = DL_RELEASE | CONFIRM;
- else
- pr = DL_RELEASE | INDICATION;
-
- st->l2.l2l3(st, pr, NULL);
-}
-
-static inline void
-lapb_dl_release_l2l3(struct PStack *st, int f)
-{
- if (test_bit(FLG_LAPB, &st->l2.flag))
- st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
- st->l2.l2l3(st, DL_RELEASE | f, NULL);
-}
-
-static void
-establishlink(struct FsmInst *fi)
-{
- struct PStack *st = fi->userdata;
- u_char cmd;
-
- clear_exception(&st->l2);
- st->l2.rc = 0;
- cmd = (test_bit(FLG_MOD128, &st->l2.flag) ? SABME : SABM) | 0x10;
- send_uframe(st, cmd, CMD);
- FsmDelTimer(&st->l2.t203, 1);
- restart_t200(st, 1);
- test_and_clear_bit(FLG_PEND_REL, &st->l2.flag);
- freewin(st);
- FsmChangeState(fi, ST_L2_5);
-}
-
-static void
-l2_mdl_error_ua(struct FsmInst *fi, int event, void *arg)
-{
- struct sk_buff *skb = arg;
- struct PStack *st = fi->userdata;
-
- if (get_PollFlagFree(st, skb))
- st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'C');
- else
- st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'D');
-}
-
-static void
-l2_mdl_error_dm(struct FsmInst *fi, int event, void *arg)
-{
- struct sk_buff *skb = arg;
- struct PStack *st = fi->userdata;
-
- if (get_PollFlagFree(st, skb))
- st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'B');
- else {
- st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'E');
- establishlink(fi);
- test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
- }
-}
-
-static void
-l2_st8_mdl_error_dm(struct FsmInst *fi, int event, void *arg)
-{
- struct sk_buff *skb = arg;
- struct PStack *st = fi->userdata;
-
- if (get_PollFlagFree(st, skb))
- st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'B');
- else {
- st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'E');
- }
- establishlink(fi);
- test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
-}
-
-static void
-l2_go_st3(struct FsmInst *fi, int event, void *arg)
-{
- FsmChangeState(fi, ST_L2_3);
-}
-
-static void
-l2_mdl_assign(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- FsmChangeState(fi, ST_L2_3);
- st->l2.l2tei(st, MDL_ASSIGN | INDICATION, NULL);
-}
-
-static void
-l2_queue_ui_assign(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
-
- skb_queue_tail(&st->l2.ui_queue, skb);
- FsmChangeState(fi, ST_L2_2);
- st->l2.l2tei(st, MDL_ASSIGN | INDICATION, NULL);
-}
-
-static void
-l2_queue_ui(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
-
- skb_queue_tail(&st->l2.ui_queue, skb);
-}
-
-static void
-tx_ui(struct PStack *st)
-{
- struct sk_buff *skb;
- u_char header[MAX_HEADER_LEN];
- int i;
-
- i = sethdraddr(&(st->l2), header, CMD);
- header[i++] = UI;
- while ((skb = skb_dequeue(&st->l2.ui_queue))) {
- memcpy(skb_push(skb, i), header, i);
- enqueue_ui(st, skb);
- }
-}
-
-static void
-l2_send_ui(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
-
- skb_queue_tail(&st->l2.ui_queue, skb);
- tx_ui(st);
-}
-
-static void
-l2_got_ui(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
-
- skb_pull(skb, l2headersize(&st->l2, 1));
- st->l2.l2l3(st, DL_UNIT_DATA | INDICATION, skb);
-/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- * in states 1-3 for broadcast
- */
-
-
-}
-
-static void
-l2_establish(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- establishlink(fi);
- test_and_set_bit(FLG_L3_INIT, &st->l2.flag);
-}
-
-static void
-l2_discard_i_setl3(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- skb_queue_purge(&st->l2.i_queue);
- test_and_set_bit(FLG_L3_INIT, &st->l2.flag);
- test_and_clear_bit(FLG_PEND_REL, &st->l2.flag);
-}
-
-static void
-l2_l3_reestablish(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- skb_queue_purge(&st->l2.i_queue);
- establishlink(fi);
- test_and_set_bit(FLG_L3_INIT, &st->l2.flag);
-}
-
-static void
-l2_release(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL);
-}
-
-static void
-l2_pend_rel(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- test_and_set_bit(FLG_PEND_REL, &st->l2.flag);
-}
-
-static void
-l2_disconnect(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- skb_queue_purge(&st->l2.i_queue);
- freewin(st);
- FsmChangeState(fi, ST_L2_6);
- st->l2.rc = 0;
- send_uframe(st, DISC | 0x10, CMD);
- FsmDelTimer(&st->l2.t203, 1);
- restart_t200(st, 2);
-}
-
-static void
-l2_start_multi(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
-
- send_uframe(st, UA | get_PollFlagFree(st, skb), RSP);
-
- clear_exception(&st->l2);
- st->l2.vs = 0;
- st->l2.va = 0;
- st->l2.vr = 0;
- st->l2.sow = 0;
- FsmChangeState(fi, ST_L2_7);
- FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 3);
-
- st->l2.l2l3(st, DL_ESTABLISH | INDICATION, NULL);
-}
-
-static void
-l2_send_UA(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
-
- send_uframe(st, UA | get_PollFlagFree(st, skb), RSP);
-}
-
-static void
-l2_send_DM(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
-
- send_uframe(st, DM | get_PollFlagFree(st, skb), RSP);
-}
-
-static void
-l2_restart_multi(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
- int est = 0, state;
-
- state = fi->state;
-
- send_uframe(st, UA | get_PollFlagFree(st, skb), RSP);
-
- st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'F');
-
- if (st->l2.vs != st->l2.va) {
- skb_queue_purge(&st->l2.i_queue);
- est = 1;
- }
-
- clear_exception(&st->l2);
- st->l2.vs = 0;
- st->l2.va = 0;
- st->l2.vr = 0;
- st->l2.sow = 0;
- FsmChangeState(fi, ST_L2_7);
- stop_t200(st, 3);
- FsmRestartTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 3);
-
- if (est)
- st->l2.l2l3(st, DL_ESTABLISH | INDICATION, NULL);
-
- if ((ST_L2_7 == state) || (ST_L2_8 == state))
- if (!skb_queue_empty(&st->l2.i_queue) && cansend(st))
- st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
-}
-
-static void
-l2_stop_multi(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
-
- FsmChangeState(fi, ST_L2_4);
- FsmDelTimer(&st->l2.t203, 3);
- stop_t200(st, 4);
-
- send_uframe(st, UA | get_PollFlagFree(st, skb), RSP);
-
- skb_queue_purge(&st->l2.i_queue);
- freewin(st);
- lapb_dl_release_l2l3(st, INDICATION);
-}
-
-static void
-l2_connected(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
- int pr = -1;
-
- if (!get_PollFlag(st, skb)) {
- l2_mdl_error_ua(fi, event, arg);
- return;
- }
- dev_kfree_skb(skb);
-
- if (test_and_clear_bit(FLG_PEND_REL, &st->l2.flag))
- l2_disconnect(fi, event, arg);
-
- if (test_and_clear_bit(FLG_L3_INIT, &st->l2.flag)) {
- pr = DL_ESTABLISH | CONFIRM;
- } else if (st->l2.vs != st->l2.va) {
- skb_queue_purge(&st->l2.i_queue);
- pr = DL_ESTABLISH | INDICATION;
- }
-
- stop_t200(st, 5);
-
- st->l2.vr = 0;
- st->l2.vs = 0;
- st->l2.va = 0;
- st->l2.sow = 0;
- FsmChangeState(fi, ST_L2_7);
- FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 4);
-
- if (pr != -1)
- st->l2.l2l3(st, pr, NULL);
-
- if (!skb_queue_empty(&st->l2.i_queue) && cansend(st))
- st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
-}
-
-static void
-l2_released(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
-
- if (!get_PollFlag(st, skb)) {
- l2_mdl_error_ua(fi, event, arg);
- return;
- }
- dev_kfree_skb(skb);
-
- stop_t200(st, 6);
- lapb_dl_release_l2l3(st, CONFIRM);
- FsmChangeState(fi, ST_L2_4);
-}
-
-static void
-l2_reestablish(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
-
- if (!get_PollFlagFree(st, skb)) {
- establishlink(fi);
- test_and_set_bit(FLG_L3_INIT, &st->l2.flag);
- }
-}
-
-static void
-l2_st5_dm_release(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
-
- if (get_PollFlagFree(st, skb)) {
- stop_t200(st, 7);
- if (!test_bit(FLG_L3_INIT, &st->l2.flag))
- skb_queue_purge(&st->l2.i_queue);
- if (test_bit(FLG_LAPB, &st->l2.flag))
- st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
- st5_dl_release_l2l3(st);
- FsmChangeState(fi, ST_L2_4);
- }
-}
-
-static void
-l2_st6_dm_release(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
-
- if (get_PollFlagFree(st, skb)) {
- stop_t200(st, 8);
- lapb_dl_release_l2l3(st, CONFIRM);
- FsmChangeState(fi, ST_L2_4);
- }
-}
-
-static inline void
-enquiry_cr(struct PStack *st, u_char typ, u_char cr, u_char pf)
-{
- struct sk_buff *skb;
- struct Layer2 *l2;
- u_char tmp[MAX_HEADER_LEN];
- int i;
-
- l2 = &st->l2;
- i = sethdraddr(l2, tmp, cr);
- if (test_bit(FLG_MOD128, &l2->flag)) {
- tmp[i++] = typ;
- tmp[i++] = (l2->vr << 1) | (pf ? 1 : 0);
- } else
- tmp[i++] = (l2->vr << 5) | typ | (pf ? 0x10 : 0);
- if (!(skb = alloc_skb(i, GFP_ATOMIC))) {
- printk(KERN_WARNING "isdl2 can't alloc sbbuff for enquiry_cr\n");
- return;
- }
- skb_put_data(skb, tmp, i);
- enqueue_super(st, skb);
-}
-
-static inline void
-enquiry_response(struct PStack *st)
-{
- if (test_bit(FLG_OWN_BUSY, &st->l2.flag))
- enquiry_cr(st, RNR, RSP, 1);
- else
- enquiry_cr(st, RR, RSP, 1);
- test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
-}
-
-static inline void
-transmit_enquiry(struct PStack *st)
-{
- if (test_bit(FLG_OWN_BUSY, &st->l2.flag))
- enquiry_cr(st, RNR, CMD, 1);
- else
- enquiry_cr(st, RR, CMD, 1);
- test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
- start_t200(st, 9);
-}
-
-
-static void
-nrerrorrecovery(struct FsmInst *fi)
-{
- struct PStack *st = fi->userdata;
-
- st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'J');
- establishlink(fi);
- test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
-}
-
-static void
-invoke_retransmission(struct PStack *st, unsigned int nr)
-{
- struct Layer2 *l2 = &st->l2;
- u_int p1;
- u_long flags;
-
- spin_lock_irqsave(&l2->lock, flags);
- if (l2->vs != nr) {
- while (l2->vs != nr) {
- (l2->vs)--;
- if (test_bit(FLG_MOD128, &l2->flag)) {
- l2->vs %= 128;
- p1 = (l2->vs - l2->va) % 128;
- } else {
- l2->vs %= 8;
- p1 = (l2->vs - l2->va) % 8;
- }
- p1 = (p1 + l2->sow) % l2->window;
- if (test_bit(FLG_LAPB, &l2->flag))
- st->l1.bcs->tx_cnt += l2->windowar[p1]->len + l2headersize(l2, 0);
- skb_queue_head(&l2->i_queue, l2->windowar[p1]);
- l2->windowar[p1] = NULL;
- }
- spin_unlock_irqrestore(&l2->lock, flags);
- st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
- return;
- }
- spin_unlock_irqrestore(&l2->lock, flags);
-}
-
-static void
-l2_st7_got_super(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
- int PollFlag, rsp, typ = RR;
- unsigned int nr;
- struct Layer2 *l2 = &st->l2;
-
- rsp = *skb->data & 0x2;
- if (test_bit(FLG_ORIG, &l2->flag))
- rsp = !rsp;
-
- skb_pull(skb, l2addrsize(l2));
- if (IsRNR(skb->data, st)) {
- set_peer_busy(l2);
- typ = RNR;
- } else
- clear_peer_busy(l2);
- if (IsREJ(skb->data, st))
- typ = REJ;
-
- if (test_bit(FLG_MOD128, &l2->flag)) {
- PollFlag = (skb->data[1] & 0x1) == 0x1;
- nr = skb->data[1] >> 1;
- } else {
- PollFlag = (skb->data[0] & 0x10);
- nr = (skb->data[0] >> 5) & 0x7;
- }
- dev_kfree_skb(skb);
-
- if (PollFlag) {
- if (rsp)
- st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'A');
- else
- enquiry_response(st);
- }
- if (legalnr(st, nr)) {
- if (typ == REJ) {
- setva(st, nr);
- invoke_retransmission(st, nr);
- stop_t200(st, 10);
- if (FsmAddTimer(&st->l2.t203, st->l2.T203,
- EV_L2_T203, NULL, 6))
- l2m_debug(&st->l2.l2m, "Restart T203 ST7 REJ");
- } else if ((nr == l2->vs) && (typ == RR)) {
- setva(st, nr);
- stop_t200(st, 11);
- FsmRestartTimer(&st->l2.t203, st->l2.T203,
- EV_L2_T203, NULL, 7);
- } else if ((l2->va != nr) || (typ == RNR)) {
- setva(st, nr);
- if (typ != RR) FsmDelTimer(&st->l2.t203, 9);
- restart_t200(st, 12);
- }
- if (!skb_queue_empty(&st->l2.i_queue) && (typ == RR))
- st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
- } else
- nrerrorrecovery(fi);
-}
-
-static void
-l2_feed_i_if_reest(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
-
- if (test_bit(FLG_LAPB, &st->l2.flag))
- st->l1.bcs->tx_cnt += skb->len + l2headersize(&st->l2, 0);
- if (!test_bit(FLG_L3_INIT, &st->l2.flag))
- skb_queue_tail(&st->l2.i_queue, skb);
- else
- dev_kfree_skb(skb);
-}
-
-static void
-l2_feed_i_pull(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
-
- if (test_bit(FLG_LAPB, &st->l2.flag))
- st->l1.bcs->tx_cnt += skb->len + l2headersize(&st->l2, 0);
- skb_queue_tail(&st->l2.i_queue, skb);
- st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
-}
-
-static void
-l2_feed_iqueue(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
-
- if (test_bit(FLG_LAPB, &st->l2.flag))
- st->l1.bcs->tx_cnt += skb->len + l2headersize(&st->l2, 0);
- skb_queue_tail(&st->l2.i_queue, skb);
-}
-
-static void
-l2_got_iframe(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
- struct Layer2 *l2 = &(st->l2);
- int PollFlag, ns, i;
- unsigned int nr;
-
- i = l2addrsize(l2);
- if (test_bit(FLG_MOD128, &l2->flag)) {
- PollFlag = ((skb->data[i + 1] & 0x1) == 0x1);
- ns = skb->data[i] >> 1;
- nr = (skb->data[i + 1] >> 1) & 0x7f;
- } else {
- PollFlag = (skb->data[i] & 0x10);
- ns = (skb->data[i] >> 1) & 0x7;
- nr = (skb->data[i] >> 5) & 0x7;
- }
- if (test_bit(FLG_OWN_BUSY, &l2->flag)) {
- dev_kfree_skb(skb);
- if (PollFlag) enquiry_response(st);
- } else if (l2->vr == ns) {
- (l2->vr)++;
- if (test_bit(FLG_MOD128, &l2->flag))
- l2->vr %= 128;
- else
- l2->vr %= 8;
- test_and_clear_bit(FLG_REJEXC, &l2->flag);
-
- if (PollFlag)
- enquiry_response(st);
- else
- test_and_set_bit(FLG_ACK_PEND, &l2->flag);
- skb_pull(skb, l2headersize(l2, 0));
- st->l2.l2l3(st, DL_DATA | INDICATION, skb);
- } else {
- /* n(s)!=v(r) */
- dev_kfree_skb(skb);
- if (test_and_set_bit(FLG_REJEXC, &l2->flag)) {
- if (PollFlag)
- enquiry_response(st);
- } else {
- enquiry_cr(st, REJ, RSP, PollFlag);
- test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
- }
- }
-
- if (legalnr(st, nr)) {
- if (!test_bit(FLG_PEER_BUSY, &st->l2.flag) && (fi->state == ST_L2_7)) {
- if (nr == st->l2.vs) {
- stop_t200(st, 13);
- FsmRestartTimer(&st->l2.t203, st->l2.T203,
- EV_L2_T203, NULL, 7);
- } else if (nr != st->l2.va)
- restart_t200(st, 14);
- }
- setva(st, nr);
- } else {
- nrerrorrecovery(fi);
- return;
- }
-
- if (!skb_queue_empty(&st->l2.i_queue) && (fi->state == ST_L2_7))
- st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
- if (test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag))
- enquiry_cr(st, RR, RSP, 0);
-}
-
-static void
-l2_got_tei(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- st->l2.tei = (long) arg;
-
- if (fi->state == ST_L2_3) {
- establishlink(fi);
- test_and_set_bit(FLG_L3_INIT, &st->l2.flag);
- } else
- FsmChangeState(fi, ST_L2_4);
- if (!skb_queue_empty(&st->l2.ui_queue))
- tx_ui(st);
-}
-
-static void
-l2_st5_tout_200(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- if (test_bit(FLG_LAPD, &st->l2.flag) &&
- test_bit(FLG_DCHAN_BUSY, &st->l2.flag)) {
- FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9);
- } else if (st->l2.rc == st->l2.N200) {
- FsmChangeState(fi, ST_L2_4);
- test_and_clear_bit(FLG_T200_RUN, &st->l2.flag);
- skb_queue_purge(&st->l2.i_queue);
- st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'G');
- if (test_bit(FLG_LAPB, &st->l2.flag))
- st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
- st5_dl_release_l2l3(st);
- } else {
- st->l2.rc++;
- FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9);
- send_uframe(st, (test_bit(FLG_MOD128, &st->l2.flag) ? SABME : SABM)
- | 0x10, CMD);
- }
-}
-
-static void
-l2_st6_tout_200(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- if (test_bit(FLG_LAPD, &st->l2.flag) &&
- test_bit(FLG_DCHAN_BUSY, &st->l2.flag)) {
- FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9);
- } else if (st->l2.rc == st->l2.N200) {
- FsmChangeState(fi, ST_L2_4);
- test_and_clear_bit(FLG_T200_RUN, &st->l2.flag);
- st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'H');
- lapb_dl_release_l2l3(st, CONFIRM);
- } else {
- st->l2.rc++;
- FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200,
- NULL, 9);
- send_uframe(st, DISC | 0x10, CMD);
- }
-}
-
-static void
-l2_st7_tout_200(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- if (test_bit(FLG_LAPD, &st->l2.flag) &&
- test_bit(FLG_DCHAN_BUSY, &st->l2.flag)) {
- FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9);
- return;
- }
- test_and_clear_bit(FLG_T200_RUN, &st->l2.flag);
- st->l2.rc = 0;
- FsmChangeState(fi, ST_L2_8);
-
- transmit_enquiry(st);
- st->l2.rc++;
-}
-
-static void
-l2_st8_tout_200(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- if (test_bit(FLG_LAPD, &st->l2.flag) &&
- test_bit(FLG_DCHAN_BUSY, &st->l2.flag)) {
- FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9);
- return;
- }
- test_and_clear_bit(FLG_T200_RUN, &st->l2.flag);
- if (st->l2.rc == st->l2.N200) {
- st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'I');
- establishlink(fi);
- test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
- } else {
- transmit_enquiry(st);
- st->l2.rc++;
- }
-}
-
-static void
-l2_st7_tout_203(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- if (test_bit(FLG_LAPD, &st->l2.flag) &&
- test_bit(FLG_DCHAN_BUSY, &st->l2.flag)) {
- FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 9);
- return;
- }
- FsmChangeState(fi, ST_L2_8);
- transmit_enquiry(st);
- st->l2.rc = 0;
-}
-
-static void
-l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb, *nskb;
- struct Layer2 *l2 = &st->l2;
- u_char header[MAX_HEADER_LEN];
- int i, hdr_space_needed;
- int unsigned p1;
- u_long flags;
-
- if (!cansend(st))
- return;
-
- skb = skb_dequeue(&l2->i_queue);
- if (!skb)
- return;
-
- hdr_space_needed = l2headersize(l2, 0);
- nskb = skb_realloc_headroom(skb, hdr_space_needed);
- if (!nskb) {
- skb_queue_head(&l2->i_queue, skb);
- return;
- }
- spin_lock_irqsave(&l2->lock, flags);
- if (test_bit(FLG_MOD128, &l2->flag))
- p1 = (l2->vs - l2->va) % 128;
- else
- p1 = (l2->vs - l2->va) % 8;
- p1 = (p1 + l2->sow) % l2->window;
- if (l2->windowar[p1]) {
- printk(KERN_WARNING "isdnl2 try overwrite ack queue entry %d\n",
- p1);
- dev_kfree_skb(l2->windowar[p1]);
- }
- l2->windowar[p1] = skb;
-
- i = sethdraddr(&st->l2, header, CMD);
-
- if (test_bit(FLG_MOD128, &l2->flag)) {
- header[i++] = l2->vs << 1;
- header[i++] = l2->vr << 1;
- l2->vs = (l2->vs + 1) % 128;
- } else {
- header[i++] = (l2->vr << 5) | (l2->vs << 1);
- l2->vs = (l2->vs + 1) % 8;
- }
- spin_unlock_irqrestore(&l2->lock, flags);
- memcpy(skb_push(nskb, i), header, i);
- st->l2.l2l1(st, PH_PULL | INDICATION, nskb);
- test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
- if (!test_and_set_bit(FLG_T200_RUN, &st->l2.flag)) {
- FsmDelTimer(&st->l2.t203, 13);
- FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 11);
- }
- if (!skb_queue_empty(&l2->i_queue) && cansend(st))
- st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
-}
-
-static void
-l2_st8_got_super(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
- int PollFlag, rsp, rnr = 0;
- unsigned int nr;
- struct Layer2 *l2 = &st->l2;
-
- rsp = *skb->data & 0x2;
- if (test_bit(FLG_ORIG, &l2->flag))
- rsp = !rsp;
-
- skb_pull(skb, l2addrsize(l2));
-
- if (IsRNR(skb->data, st)) {
- set_peer_busy(l2);
- rnr = 1;
- } else
- clear_peer_busy(l2);
-
- if (test_bit(FLG_MOD128, &l2->flag)) {
- PollFlag = (skb->data[1] & 0x1) == 0x1;
- nr = skb->data[1] >> 1;
- } else {
- PollFlag = (skb->data[0] & 0x10);
- nr = (skb->data[0] >> 5) & 0x7;
- }
- dev_kfree_skb(skb);
-
- if (rsp && PollFlag) {
- if (legalnr(st, nr)) {
- if (rnr) {
- restart_t200(st, 15);
- } else {
- stop_t200(st, 16);
- FsmAddTimer(&l2->t203, l2->T203,
- EV_L2_T203, NULL, 5);
- setva(st, nr);
- }
- invoke_retransmission(st, nr);
- FsmChangeState(fi, ST_L2_7);
- if (!skb_queue_empty(&l2->i_queue) && cansend(st))
- st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
- } else
- nrerrorrecovery(fi);
- } else {
- if (!rsp && PollFlag)
- enquiry_response(st);
- if (legalnr(st, nr)) {
- setva(st, nr);
- } else
- nrerrorrecovery(fi);
- }
-}
-
-static void
-l2_got_FRMR(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
-
- skb_pull(skb, l2addrsize(&st->l2) + 1);
-
- if (!(skb->data[0] & 1) || ((skb->data[0] & 3) == 1) || /* I or S */
- (IsUA(skb->data) && (fi->state == ST_L2_7))) {
- st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'K');
- establishlink(fi);
- test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
- }
- dev_kfree_skb(skb);
-}
-
-static void
-l2_st24_tei_remove(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- skb_queue_purge(&st->l2.ui_queue);
- st->l2.tei = -1;
- FsmChangeState(fi, ST_L2_1);
-}
-
-static void
-l2_st3_tei_remove(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- skb_queue_purge(&st->l2.ui_queue);
- st->l2.tei = -1;
- st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
- FsmChangeState(fi, ST_L2_1);
-}
-
-static void
-l2_st5_tei_remove(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- skb_queue_purge(&st->l2.i_queue);
- skb_queue_purge(&st->l2.ui_queue);
- freewin(st);
- st->l2.tei = -1;
- stop_t200(st, 17);
- st5_dl_release_l2l3(st);
- FsmChangeState(fi, ST_L2_1);
-}
-
-static void
-l2_st6_tei_remove(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- skb_queue_purge(&st->l2.ui_queue);
- st->l2.tei = -1;
- stop_t200(st, 18);
- st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL);
- FsmChangeState(fi, ST_L2_1);
-}
-
-static void
-l2_tei_remove(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- skb_queue_purge(&st->l2.i_queue);
- skb_queue_purge(&st->l2.ui_queue);
- freewin(st);
- st->l2.tei = -1;
- stop_t200(st, 17);
- FsmDelTimer(&st->l2.t203, 19);
- st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
- FsmChangeState(fi, ST_L2_1);
-}
-
-static void
-l2_st14_persistent_da(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- skb_queue_purge(&st->l2.i_queue);
- skb_queue_purge(&st->l2.ui_queue);
- if (test_and_clear_bit(FLG_ESTAB_PEND, &st->l2.flag))
- st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
-}
-
-static void
-l2_st5_persistent_da(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- skb_queue_purge(&st->l2.i_queue);
- skb_queue_purge(&st->l2.ui_queue);
- freewin(st);
- stop_t200(st, 19);
- st5_dl_release_l2l3(st);
- FsmChangeState(fi, ST_L2_4);
-}
-
-static void
-l2_st6_persistent_da(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- skb_queue_purge(&st->l2.ui_queue);
- stop_t200(st, 20);
- st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL);
- FsmChangeState(fi, ST_L2_4);
-}
-
-static void
-l2_persistent_da(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- skb_queue_purge(&st->l2.i_queue);
- skb_queue_purge(&st->l2.ui_queue);
- freewin(st);
- stop_t200(st, 19);
- FsmDelTimer(&st->l2.t203, 19);
- st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
- FsmChangeState(fi, ST_L2_4);
-}
-
-static void
-l2_set_own_busy(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- if (!test_and_set_bit(FLG_OWN_BUSY, &st->l2.flag)) {
- enquiry_cr(st, RNR, RSP, 0);
- test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
- }
-}
-
-static void
-l2_clear_own_busy(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- if (!test_and_clear_bit(FLG_OWN_BUSY, &st->l2.flag)) {
- enquiry_cr(st, RR, RSP, 0);
- test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
- }
-}
-
-static void
-l2_frame_error(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- st->ma.layer(st, MDL_ERROR | INDICATION, arg);
-}
-
-static void
-l2_frame_error_reest(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- st->ma.layer(st, MDL_ERROR | INDICATION, arg);
- establishlink(fi);
- test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
-}
-
-static struct FsmNode L2FnList[] __initdata =
-{
- {ST_L2_1, EV_L2_DL_ESTABLISH_REQ, l2_mdl_assign},
- {ST_L2_2, EV_L2_DL_ESTABLISH_REQ, l2_go_st3},
- {ST_L2_4, EV_L2_DL_ESTABLISH_REQ, l2_establish},
- {ST_L2_5, EV_L2_DL_ESTABLISH_REQ, l2_discard_i_setl3},
- {ST_L2_7, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish},
- {ST_L2_8, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish},
- {ST_L2_4, EV_L2_DL_RELEASE_REQ, l2_release},
- {ST_L2_5, EV_L2_DL_RELEASE_REQ, l2_pend_rel},
- {ST_L2_7, EV_L2_DL_RELEASE_REQ, l2_disconnect},
- {ST_L2_8, EV_L2_DL_RELEASE_REQ, l2_disconnect},
- {ST_L2_5, EV_L2_DL_DATA, l2_feed_i_if_reest},
- {ST_L2_7, EV_L2_DL_DATA, l2_feed_i_pull},
- {ST_L2_8, EV_L2_DL_DATA, l2_feed_iqueue},
- {ST_L2_1, EV_L2_DL_UNIT_DATA, l2_queue_ui_assign},
- {ST_L2_2, EV_L2_DL_UNIT_DATA, l2_queue_ui},
- {ST_L2_3, EV_L2_DL_UNIT_DATA, l2_queue_ui},
- {ST_L2_4, EV_L2_DL_UNIT_DATA, l2_send_ui},
- {ST_L2_5, EV_L2_DL_UNIT_DATA, l2_send_ui},
- {ST_L2_6, EV_L2_DL_UNIT_DATA, l2_send_ui},
- {ST_L2_7, EV_L2_DL_UNIT_DATA, l2_send_ui},
- {ST_L2_8, EV_L2_DL_UNIT_DATA, l2_send_ui},
- {ST_L2_1, EV_L2_MDL_ASSIGN, l2_got_tei},
- {ST_L2_2, EV_L2_MDL_ASSIGN, l2_got_tei},
- {ST_L2_3, EV_L2_MDL_ASSIGN, l2_got_tei},
- {ST_L2_2, EV_L2_MDL_ERROR, l2_st24_tei_remove},
- {ST_L2_3, EV_L2_MDL_ERROR, l2_st3_tei_remove},
- {ST_L2_4, EV_L2_MDL_REMOVE, l2_st24_tei_remove},
- {ST_L2_5, EV_L2_MDL_REMOVE, l2_st5_tei_remove},
- {ST_L2_6, EV_L2_MDL_REMOVE, l2_st6_tei_remove},
- {ST_L2_7, EV_L2_MDL_REMOVE, l2_tei_remove},
- {ST_L2_8, EV_L2_MDL_REMOVE, l2_tei_remove},
- {ST_L2_4, EV_L2_SABME, l2_start_multi},
- {ST_L2_5, EV_L2_SABME, l2_send_UA},
- {ST_L2_6, EV_L2_SABME, l2_send_DM},
- {ST_L2_7, EV_L2_SABME, l2_restart_multi},
- {ST_L2_8, EV_L2_SABME, l2_restart_multi},
- {ST_L2_4, EV_L2_DISC, l2_send_DM},
- {ST_L2_5, EV_L2_DISC, l2_send_DM},
- {ST_L2_6, EV_L2_DISC, l2_send_UA},
- {ST_L2_7, EV_L2_DISC, l2_stop_multi},
- {ST_L2_8, EV_L2_DISC, l2_stop_multi},
- {ST_L2_4, EV_L2_UA, l2_mdl_error_ua},
- {ST_L2_5, EV_L2_UA, l2_connected},
- {ST_L2_6, EV_L2_UA, l2_released},
- {ST_L2_7, EV_L2_UA, l2_mdl_error_ua},
- {ST_L2_8, EV_L2_UA, l2_mdl_error_ua},
- {ST_L2_4, EV_L2_DM, l2_reestablish},
- {ST_L2_5, EV_L2_DM, l2_st5_dm_release},
- {ST_L2_6, EV_L2_DM, l2_st6_dm_release},
- {ST_L2_7, EV_L2_DM, l2_mdl_error_dm},
- {ST_L2_8, EV_L2_DM, l2_st8_mdl_error_dm},
- {ST_L2_1, EV_L2_UI, l2_got_ui},
- {ST_L2_2, EV_L2_UI, l2_got_ui},
- {ST_L2_3, EV_L2_UI, l2_got_ui},
- {ST_L2_4, EV_L2_UI, l2_got_ui},
- {ST_L2_5, EV_L2_UI, l2_got_ui},
- {ST_L2_6, EV_L2_UI, l2_got_ui},
- {ST_L2_7, EV_L2_UI, l2_got_ui},
- {ST_L2_8, EV_L2_UI, l2_got_ui},
- {ST_L2_7, EV_L2_FRMR, l2_got_FRMR},
- {ST_L2_8, EV_L2_FRMR, l2_got_FRMR},
- {ST_L2_7, EV_L2_SUPER, l2_st7_got_super},
- {ST_L2_8, EV_L2_SUPER, l2_st8_got_super},
- {ST_L2_7, EV_L2_I, l2_got_iframe},
- {ST_L2_8, EV_L2_I, l2_got_iframe},
- {ST_L2_5, EV_L2_T200, l2_st5_tout_200},
- {ST_L2_6, EV_L2_T200, l2_st6_tout_200},
- {ST_L2_7, EV_L2_T200, l2_st7_tout_200},
- {ST_L2_8, EV_L2_T200, l2_st8_tout_200},
- {ST_L2_7, EV_L2_T203, l2_st7_tout_203},
- {ST_L2_7, EV_L2_ACK_PULL, l2_pull_iqueue},
- {ST_L2_7, EV_L2_SET_OWN_BUSY, l2_set_own_busy},
- {ST_L2_8, EV_L2_SET_OWN_BUSY, l2_set_own_busy},
- {ST_L2_7, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy},
- {ST_L2_8, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy},
- {ST_L2_4, EV_L2_FRAME_ERROR, l2_frame_error},
- {ST_L2_5, EV_L2_FRAME_ERROR, l2_frame_error},
- {ST_L2_6, EV_L2_FRAME_ERROR, l2_frame_error},
- {ST_L2_7, EV_L2_FRAME_ERROR, l2_frame_error_reest},
- {ST_L2_8, EV_L2_FRAME_ERROR, l2_frame_error_reest},
- {ST_L2_1, EV_L1_DEACTIVATE, l2_st14_persistent_da},
- {ST_L2_2, EV_L1_DEACTIVATE, l2_st24_tei_remove},
- {ST_L2_3, EV_L1_DEACTIVATE, l2_st3_tei_remove},
- {ST_L2_4, EV_L1_DEACTIVATE, l2_st14_persistent_da},
- {ST_L2_5, EV_L1_DEACTIVATE, l2_st5_persistent_da},
- {ST_L2_6, EV_L1_DEACTIVATE, l2_st6_persistent_da},
- {ST_L2_7, EV_L1_DEACTIVATE, l2_persistent_da},
- {ST_L2_8, EV_L1_DEACTIVATE, l2_persistent_da},
-};
-
-static void
-isdnl2_l1l2(struct PStack *st, int pr, void *arg)
-{
- struct sk_buff *skb = arg;
- u_char *datap;
- int ret = 1, len;
- int c = 0;
-
- switch (pr) {
- case (PH_DATA | INDICATION):
- datap = skb->data;
- len = l2addrsize(&st->l2);
- if (skb->len > len)
- datap += len;
- else {
- FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *) 'N');
- dev_kfree_skb(skb);
- return;
- }
- if (!(*datap & 1)) { /* I-Frame */
- if (!(c = iframe_error(st, skb)))
- ret = FsmEvent(&st->l2.l2m, EV_L2_I, skb);
- } else if (IsSFrame(datap, st)) { /* S-Frame */
- if (!(c = super_error(st, skb)))
- ret = FsmEvent(&st->l2.l2m, EV_L2_SUPER, skb);
- } else if (IsUI(datap)) {
- if (!(c = UI_error(st, skb)))
- ret = FsmEvent(&st->l2.l2m, EV_L2_UI, skb);
- } else if (IsSABME(datap, st)) {
- if (!(c = unnum_error(st, skb, CMD)))
- ret = FsmEvent(&st->l2.l2m, EV_L2_SABME, skb);
- } else if (IsUA(datap)) {
- if (!(c = unnum_error(st, skb, RSP)))
- ret = FsmEvent(&st->l2.l2m, EV_L2_UA, skb);
- } else if (IsDISC(datap)) {
- if (!(c = unnum_error(st, skb, CMD)))
- ret = FsmEvent(&st->l2.l2m, EV_L2_DISC, skb);
- } else if (IsDM(datap)) {
- if (!(c = unnum_error(st, skb, RSP)))
- ret = FsmEvent(&st->l2.l2m, EV_L2_DM, skb);
- } else if (IsFRMR(datap)) {
- if (!(c = FRMR_error(st, skb)))
- ret = FsmEvent(&st->l2.l2m, EV_L2_FRMR, skb);
- } else {
- FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *) 'L');
- dev_kfree_skb(skb);
- ret = 0;
- }
- if (c) {
- dev_kfree_skb(skb);
- FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *)(long)c);
- ret = 0;
- }
- if (ret)
- dev_kfree_skb(skb);
- break;
- case (PH_PULL | CONFIRM):
- FsmEvent(&st->l2.l2m, EV_L2_ACK_PULL, arg);
- break;
- case (PH_PAUSE | INDICATION):
- test_and_set_bit(FLG_DCHAN_BUSY, &st->l2.flag);
- break;
- case (PH_PAUSE | CONFIRM):
- test_and_clear_bit(FLG_DCHAN_BUSY, &st->l2.flag);
- break;
- case (PH_ACTIVATE | CONFIRM):
- case (PH_ACTIVATE | INDICATION):
- test_and_set_bit(FLG_L1_ACTIV, &st->l2.flag);
- if (test_and_clear_bit(FLG_ESTAB_PEND, &st->l2.flag))
- FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH_REQ, arg);
- break;
- case (PH_DEACTIVATE | INDICATION):
- case (PH_DEACTIVATE | CONFIRM):
- test_and_clear_bit(FLG_L1_ACTIV, &st->l2.flag);
- FsmEvent(&st->l2.l2m, EV_L1_DEACTIVATE, arg);
- break;
- default:
- l2m_debug(&st->l2.l2m, "l2 unknown pr %04x", pr);
- break;
- }
-}
-
-static void
-isdnl2_l3l2(struct PStack *st, int pr, void *arg)
-{
- switch (pr) {
- case (DL_DATA | REQUEST):
- if (FsmEvent(&st->l2.l2m, EV_L2_DL_DATA, arg)) {
- dev_kfree_skb((struct sk_buff *) arg);
- }
- break;
- case (DL_UNIT_DATA | REQUEST):
- if (FsmEvent(&st->l2.l2m, EV_L2_DL_UNIT_DATA, arg)) {
- dev_kfree_skb((struct sk_buff *) arg);
- }
- break;
- case (DL_ESTABLISH | REQUEST):
- if (test_bit(FLG_L1_ACTIV, &st->l2.flag)) {
- if (test_bit(FLG_LAPD, &st->l2.flag) ||
- test_bit(FLG_ORIG, &st->l2.flag)) {
- FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH_REQ, arg);
- }
- } else {
- if (test_bit(FLG_LAPD, &st->l2.flag) ||
- test_bit(FLG_ORIG, &st->l2.flag)) {
- test_and_set_bit(FLG_ESTAB_PEND, &st->l2.flag);
- }
- st->l2.l2l1(st, PH_ACTIVATE, NULL);
- }
- break;
- case (DL_RELEASE | REQUEST):
- if (test_bit(FLG_LAPB, &st->l2.flag)) {
- st->l2.l2l1(st, PH_DEACTIVATE, NULL);
- }
- FsmEvent(&st->l2.l2m, EV_L2_DL_RELEASE_REQ, arg);
- break;
- case (MDL_ASSIGN | REQUEST):
- FsmEvent(&st->l2.l2m, EV_L2_MDL_ASSIGN, arg);
- break;
- case (MDL_REMOVE | REQUEST):
- FsmEvent(&st->l2.l2m, EV_L2_MDL_REMOVE, arg);
- break;
- case (MDL_ERROR | RESPONSE):
- FsmEvent(&st->l2.l2m, EV_L2_MDL_ERROR, arg);
- break;
- }
-}
-
-void
-releasestack_isdnl2(struct PStack *st)
-{
- FsmDelTimer(&st->l2.t200, 21);
- FsmDelTimer(&st->l2.t203, 16);
- skb_queue_purge(&st->l2.i_queue);
- skb_queue_purge(&st->l2.ui_queue);
- ReleaseWin(&st->l2);
-}
-
-static void
-l2m_debug(struct FsmInst *fi, char *fmt, ...)
-{
- va_list args;
- struct PStack *st = fi->userdata;
-
- va_start(args, fmt);
- VHiSax_putstatus(st->l1.hardware, st->l2.debug_id, fmt, args);
- va_end(args);
-}
-
-void
-setstack_isdnl2(struct PStack *st, char *debug_id)
-{
- spin_lock_init(&st->l2.lock);
- st->l1.l1l2 = isdnl2_l1l2;
- st->l3.l3l2 = isdnl2_l3l2;
-
- skb_queue_head_init(&st->l2.i_queue);
- skb_queue_head_init(&st->l2.ui_queue);
- InitWin(&st->l2);
- st->l2.debug = 0;
-
- st->l2.l2m.fsm = &l2fsm;
- if (test_bit(FLG_LAPB, &st->l2.flag))
- st->l2.l2m.state = ST_L2_4;
- else
- st->l2.l2m.state = ST_L2_1;
- st->l2.l2m.debug = 0;
- st->l2.l2m.userdata = st;
- st->l2.l2m.userint = 0;
- st->l2.l2m.printdebug = l2m_debug;
- strcpy(st->l2.debug_id, debug_id);
-
- FsmInitTimer(&st->l2.l2m, &st->l2.t200);
- FsmInitTimer(&st->l2.l2m, &st->l2.t203);
-}
-
-static void
-transl2_l3l2(struct PStack *st, int pr, void *arg)
-{
- switch (pr) {
- case (DL_DATA | REQUEST):
- case (DL_UNIT_DATA | REQUEST):
- st->l2.l2l1(st, PH_DATA | REQUEST, arg);
- break;
- case (DL_ESTABLISH | REQUEST):
- st->l2.l2l1(st, PH_ACTIVATE | REQUEST, NULL);
- break;
- case (DL_RELEASE | REQUEST):
- st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
- break;
- }
-}
-
-void
-setstack_transl2(struct PStack *st)
-{
- st->l3.l3l2 = transl2_l3l2;
-}
-
-void
-releasestack_transl2(struct PStack *st)
-{
-}
-
-int __init
-Isdnl2New(void)
-{
- l2fsm.state_count = L2_STATE_COUNT;
- l2fsm.event_count = L2_EVENT_COUNT;
- l2fsm.strEvent = strL2Event;
- l2fsm.strState = strL2State;
- return FsmNew(&l2fsm, L2FnList, ARRAY_SIZE(L2FnList));
-}
-
-void
-Isdnl2Free(void)
-{
- FsmFree(&l2fsm);
-}
diff --git a/drivers/isdn/hisax/isdnl2.h b/drivers/isdn/hisax/isdnl2.h
deleted file mode 100644
index 7e447fb8ed1d..000000000000
--- a/drivers/isdn/hisax/isdnl2.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/* $Id: isdnl2.h,v 1.3.6.2 2001/09/23 22:24:49 kai Exp $
- *
- * Layer 2 defines
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#define RR 0x01
-#define RNR 0x05
-#define REJ 0x09
-#define SABME 0x6f
-#define SABM 0x2f
-#define DM 0x0f
-#define UI 0x03
-#define DISC 0x43
-#define UA 0x63
-#define FRMR 0x87
-#define XID 0xaf
-
-#define CMD 0
-#define RSP 1
-
-#define LC_FLUSH_WAIT 1
diff --git a/drivers/isdn/hisax/isdnl3.c b/drivers/isdn/hisax/isdnl3.c
deleted file mode 100644
index bb3f9ec62749..000000000000
--- a/drivers/isdn/hisax/isdnl3.c
+++ /dev/null
@@ -1,594 +0,0 @@
-/* $Id: isdnl3.c,v 2.22.2.3 2004/01/13 14:31:25 keil Exp $
- *
- * Author Karsten Keil
- * based on the teles driver from Jan den Ouden
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * For changes and modifications please read
- * Documentation/isdn/HiSax.cert
- *
- * Thanks to Jan den Ouden
- * Fritz Elfert
- *
- */
-
-#include <linux/init.h>
-#include <linux/slab.h>
-#include "hisax.h"
-#include "isdnl3.h"
-
-const char *l3_revision = "$Revision: 2.22.2.3 $";
-
-static struct Fsm l3fsm;
-
-enum {
- ST_L3_LC_REL,
- ST_L3_LC_ESTAB_WAIT,
- ST_L3_LC_REL_DELAY,
- ST_L3_LC_REL_WAIT,
- ST_L3_LC_ESTAB,
-};
-
-#define L3_STATE_COUNT (ST_L3_LC_ESTAB + 1)
-
-static char *strL3State[] =
-{
- "ST_L3_LC_REL",
- "ST_L3_LC_ESTAB_WAIT",
- "ST_L3_LC_REL_DELAY",
- "ST_L3_LC_REL_WAIT",
- "ST_L3_LC_ESTAB",
-};
-
-enum {
- EV_ESTABLISH_REQ,
- EV_ESTABLISH_IND,
- EV_ESTABLISH_CNF,
- EV_RELEASE_REQ,
- EV_RELEASE_CNF,
- EV_RELEASE_IND,
- EV_TIMEOUT,
-};
-
-#define L3_EVENT_COUNT (EV_TIMEOUT + 1)
-
-static char *strL3Event[] =
-{
- "EV_ESTABLISH_REQ",
- "EV_ESTABLISH_IND",
- "EV_ESTABLISH_CNF",
- "EV_RELEASE_REQ",
- "EV_RELEASE_CNF",
- "EV_RELEASE_IND",
- "EV_TIMEOUT",
-};
-
-static __printf(2, 3) void
- l3m_debug(struct FsmInst *fi, char *fmt, ...)
-{
- va_list args;
- struct PStack *st = fi->userdata;
-
- va_start(args, fmt);
- VHiSax_putstatus(st->l1.hardware, st->l3.debug_id, fmt, args);
- va_end(args);
-}
-
-u_char *
-findie(u_char *p, int size, u_char ie, int wanted_set)
-{
- int l, codeset, maincodeset;
- u_char *pend = p + size;
-
- /* skip protocol discriminator, callref and message type */
- p++;
- l = (*p++) & 0xf;
- p += l;
- p++;
- codeset = 0;
- maincodeset = 0;
- /* while there are bytes left... */
- while (p < pend) {
- if ((*p & 0xf0) == 0x90) {
- codeset = *p & 0x07;
- if (!(*p & 0x08))
- maincodeset = codeset;
- }
- if (*p & 0x80)
- p++;
- else {
- if (codeset == wanted_set) {
- if (*p == ie)
- { /* improved length check (Werner Cornelius) */
- if ((pend - p) < 2)
- return (NULL);
- if (*(p + 1) > (pend - (p + 2)))
- return (NULL);
- return (p);
- }
-
- if (*p > ie)
- return (NULL);
- }
- p++;
- l = *p++;
- p += l;
- codeset = maincodeset;
- }
- }
- return (NULL);
-}
-
-int
-getcallref(u_char *p)
-{
- int l, cr = 0;
-
- p++; /* prot discr */
- if (*p & 0xfe) /* wrong callref BRI only 1 octet*/
- return (-2);
- l = 0xf & *p++; /* callref length */
- if (!l) /* dummy CallRef */
- return (-1);
- cr = *p++;
- return (cr);
-}
-
-static int OrigCallRef = 0;
-
-int
-newcallref(void)
-{
- if (OrigCallRef == 127)
- OrigCallRef = 1;
- else
- OrigCallRef++;
- return (OrigCallRef);
-}
-
-void
-newl3state(struct l3_process *pc, int state)
-{
- if (pc->debug & L3_DEB_STATE)
- l3_debug(pc->st, "%s cr %d %d --> %d", __func__,
- pc->callref & 0x7F,
- pc->state, state);
- pc->state = state;
-}
-
-static void
-L3ExpireTimer(struct timer_list *timer)
-{
- struct L3Timer *t = from_timer(t, timer, tl);
- t->pc->st->lli.l4l3(t->pc->st, t->event, t->pc);
-}
-
-void
-L3InitTimer(struct l3_process *pc, struct L3Timer *t)
-{
- t->pc = pc;
- timer_setup(&t->tl, L3ExpireTimer, 0);
-}
-
-void
-L3DelTimer(struct L3Timer *t)
-{
- del_timer(&t->tl);
-}
-
-int
-L3AddTimer(struct L3Timer *t,
- int millisec, int event)
-{
- if (timer_pending(&t->tl)) {
- printk(KERN_WARNING "L3AddTimer: timer already active!\n");
- return -1;
- }
- t->event = event;
- t->tl.expires = jiffies + (millisec * HZ) / 1000;
- add_timer(&t->tl);
- return 0;
-}
-
-void
-StopAllL3Timer(struct l3_process *pc)
-{
- L3DelTimer(&pc->timer);
-}
-
-struct sk_buff *
-l3_alloc_skb(int len)
-{
- struct sk_buff *skb;
-
- if (!(skb = alloc_skb(len + MAX_HEADER_LEN, GFP_ATOMIC))) {
- printk(KERN_WARNING "HiSax: No skb for D-channel\n");
- return (NULL);
- }
- skb_reserve(skb, MAX_HEADER_LEN);
- return (skb);
-}
-
-static void
-no_l3_proto(struct PStack *st, int pr, void *arg)
-{
- struct sk_buff *skb = arg;
-
- HiSax_putstatus(st->l1.hardware, "L3", "no D protocol");
- if (skb) {
- dev_kfree_skb(skb);
- }
-}
-
-static int
-no_l3_proto_spec(struct PStack *st, isdn_ctrl *ic)
-{
- printk(KERN_WARNING "HiSax: no specific protocol handler for proto %lu\n", ic->arg & 0xFF);
- return (-1);
-}
-
-struct l3_process
-*getl3proc(struct PStack *st, int cr)
-{
- struct l3_process *p = st->l3.proc;
-
- while (p)
- if (p->callref == cr)
- return (p);
- else
- p = p->next;
- return (NULL);
-}
-
-struct l3_process
-*new_l3_process(struct PStack *st, int cr)
-{
- struct l3_process *p, *np;
-
- if (!(p = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) {
- printk(KERN_ERR "HiSax can't get memory for cr %d\n", cr);
- return (NULL);
- }
- if (!st->l3.proc)
- st->l3.proc = p;
- else {
- np = st->l3.proc;
- while (np->next)
- np = np->next;
- np->next = p;
- }
- p->next = NULL;
- p->debug = st->l3.debug;
- p->callref = cr;
- p->state = 0;
- p->chan = NULL;
- p->st = st;
- p->N303 = st->l3.N303;
- L3InitTimer(p, &p->timer);
- return (p);
-};
-
-void
-release_l3_process(struct l3_process *p)
-{
- struct l3_process *np, *pp = NULL;
-
- if (!p)
- return;
- np = p->st->l3.proc;
- while (np) {
- if (np == p) {
- StopAllL3Timer(p);
- if (pp)
- pp->next = np->next;
- else if (!(p->st->l3.proc = np->next) &&
- !test_bit(FLG_PTP, &p->st->l2.flag)) {
- if (p->debug)
- l3_debug(p->st, "release_l3_process: last process");
- if (skb_queue_empty(&p->st->l3.squeue)) {
- if (p->debug)
- l3_debug(p->st, "release_l3_process: release link");
- if (p->st->protocol != ISDN_PTYPE_NI1)
- FsmEvent(&p->st->l3.l3m, EV_RELEASE_REQ, NULL);
- else
- FsmEvent(&p->st->l3.l3m, EV_RELEASE_IND, NULL);
- } else {
- if (p->debug)
- l3_debug(p->st, "release_l3_process: not release link");
- }
- }
- kfree(p);
- return;
- }
- pp = np;
- np = np->next;
- }
- printk(KERN_ERR "HiSax internal L3 error CR(%d) not in list\n", p->callref);
- l3_debug(p->st, "HiSax internal L3 error CR(%d) not in list", p->callref);
-};
-
-static void
-l3ml3p(struct PStack *st, int pr)
-{
- struct l3_process *p = st->l3.proc;
- struct l3_process *np;
-
- while (p) {
- /* p might be kfreed under us, so we need to save where we want to go on */
- np = p->next;
- st->l3.l3ml3(st, pr, p);
- p = np;
- }
-}
-
-void
-setstack_l3dc(struct PStack *st, struct Channel *chanp)
-{
- char tmp[64];
-
- st->l3.proc = NULL;
- st->l3.global = NULL;
- skb_queue_head_init(&st->l3.squeue);
- st->l3.l3m.fsm = &l3fsm;
- st->l3.l3m.state = ST_L3_LC_REL;
- st->l3.l3m.debug = 1;
- st->l3.l3m.userdata = st;
- st->l3.l3m.userint = 0;
- st->l3.l3m.printdebug = l3m_debug;
- FsmInitTimer(&st->l3.l3m, &st->l3.l3m_timer);
- strcpy(st->l3.debug_id, "L3DC ");
- st->lli.l4l3_proto = no_l3_proto_spec;
-
-#ifdef CONFIG_HISAX_EURO
- if (st->protocol == ISDN_PTYPE_EURO) {
- setstack_dss1(st);
- } else
-#endif
-#ifdef CONFIG_HISAX_NI1
- if (st->protocol == ISDN_PTYPE_NI1) {
- setstack_ni1(st);
- } else
-#endif
-#ifdef CONFIG_HISAX_1TR6
- if (st->protocol == ISDN_PTYPE_1TR6) {
- setstack_1tr6(st);
- } else
-#endif
- if (st->protocol == ISDN_PTYPE_LEASED) {
- st->lli.l4l3 = no_l3_proto;
- st->l2.l2l3 = no_l3_proto;
- st->l3.l3ml3 = no_l3_proto;
- printk(KERN_INFO "HiSax: Leased line mode\n");
- } else {
- st->lli.l4l3 = no_l3_proto;
- st->l2.l2l3 = no_l3_proto;
- st->l3.l3ml3 = no_l3_proto;
- sprintf(tmp, "protocol %s not supported",
- (st->protocol == ISDN_PTYPE_1TR6) ? "1tr6" :
- (st->protocol == ISDN_PTYPE_EURO) ? "euro" :
- (st->protocol == ISDN_PTYPE_NI1) ? "ni1" :
- "unknown");
- printk(KERN_WARNING "HiSax: %s\n", tmp);
- st->protocol = -1;
- }
-}
-
-static void
-isdnl3_trans(struct PStack *st, int pr, void *arg) {
- st->l3.l3l2(st, pr, arg);
-}
-
-void
-releasestack_isdnl3(struct PStack *st)
-{
- while (st->l3.proc)
- release_l3_process(st->l3.proc);
- if (st->l3.global) {
- StopAllL3Timer(st->l3.global);
- kfree(st->l3.global);
- st->l3.global = NULL;
- }
- FsmDelTimer(&st->l3.l3m_timer, 54);
- skb_queue_purge(&st->l3.squeue);
-}
-
-void
-setstack_l3bc(struct PStack *st, struct Channel *chanp)
-{
-
- st->l3.proc = NULL;
- st->l3.global = NULL;
- skb_queue_head_init(&st->l3.squeue);
- st->l3.l3m.fsm = &l3fsm;
- st->l3.l3m.state = ST_L3_LC_REL;
- st->l3.l3m.debug = 1;
- st->l3.l3m.userdata = st;
- st->l3.l3m.userint = 0;
- st->l3.l3m.printdebug = l3m_debug;
- strcpy(st->l3.debug_id, "L3BC ");
- st->lli.l4l3 = isdnl3_trans;
-}
-
-#define DREL_TIMER_VALUE 40000
-
-static void
-lc_activate(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- FsmChangeState(fi, ST_L3_LC_ESTAB_WAIT);
- st->l3.l3l2(st, DL_ESTABLISH | REQUEST, NULL);
-}
-
-static void
-lc_connect(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
- int dequeued = 0;
-
- FsmChangeState(fi, ST_L3_LC_ESTAB);
- while ((skb = skb_dequeue(&st->l3.squeue))) {
- st->l3.l3l2(st, DL_DATA | REQUEST, skb);
- dequeued++;
- }
- if ((!st->l3.proc) && dequeued) {
- if (st->l3.debug)
- l3_debug(st, "lc_connect: release link");
- FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL);
- } else
- l3ml3p(st, DL_ESTABLISH | INDICATION);
-}
-
-static void
-lc_connected(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
- int dequeued = 0;
-
- FsmDelTimer(&st->l3.l3m_timer, 51);
- FsmChangeState(fi, ST_L3_LC_ESTAB);
- while ((skb = skb_dequeue(&st->l3.squeue))) {
- st->l3.l3l2(st, DL_DATA | REQUEST, skb);
- dequeued++;
- }
- if ((!st->l3.proc) && dequeued) {
- if (st->l3.debug)
- l3_debug(st, "lc_connected: release link");
- FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL);
- } else
- l3ml3p(st, DL_ESTABLISH | CONFIRM);
-}
-
-static void
-lc_start_delay(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- FsmChangeState(fi, ST_L3_LC_REL_DELAY);
- FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 50);
-}
-
-static void
-lc_start_delay_check(struct FsmInst *fi, int event, void *arg)
-/* 20/09/00 - GE timer not user for NI-1 as layer 2 should stay up */
-{
- struct PStack *st = fi->userdata;
-
- FsmChangeState(fi, ST_L3_LC_REL_DELAY);
- /* 19/09/00 - GE timer not user for NI-1 */
- if (st->protocol != ISDN_PTYPE_NI1)
- FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 50);
-}
-
-static void
-lc_release_req(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- if (test_bit(FLG_L2BLOCK, &st->l2.flag)) {
- if (st->l3.debug)
- l3_debug(st, "lc_release_req: l2 blocked");
- /* restart release timer */
- FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 51);
- } else {
- FsmChangeState(fi, ST_L3_LC_REL_WAIT);
- st->l3.l3l2(st, DL_RELEASE | REQUEST, NULL);
- }
-}
-
-static void
-lc_release_ind(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- FsmDelTimer(&st->l3.l3m_timer, 52);
- FsmChangeState(fi, ST_L3_LC_REL);
- skb_queue_purge(&st->l3.squeue);
- l3ml3p(st, DL_RELEASE | INDICATION);
-}
-
-static void
-lc_release_cnf(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- FsmChangeState(fi, ST_L3_LC_REL);
- skb_queue_purge(&st->l3.squeue);
- l3ml3p(st, DL_RELEASE | CONFIRM);
-}
-
-
-/* *INDENT-OFF* */
-static struct FsmNode L3FnList[] __initdata =
-{
- {ST_L3_LC_REL, EV_ESTABLISH_REQ, lc_activate},
- {ST_L3_LC_REL, EV_ESTABLISH_IND, lc_connect},
- {ST_L3_LC_REL, EV_ESTABLISH_CNF, lc_connect},
- {ST_L3_LC_ESTAB_WAIT, EV_ESTABLISH_CNF, lc_connected},
- {ST_L3_LC_ESTAB_WAIT, EV_RELEASE_REQ, lc_start_delay},
- {ST_L3_LC_ESTAB_WAIT, EV_RELEASE_IND, lc_release_ind},
- {ST_L3_LC_ESTAB, EV_RELEASE_IND, lc_release_ind},
- {ST_L3_LC_ESTAB, EV_RELEASE_REQ, lc_start_delay_check},
- {ST_L3_LC_REL_DELAY, EV_RELEASE_IND, lc_release_ind},
- {ST_L3_LC_REL_DELAY, EV_ESTABLISH_REQ, lc_connected},
- {ST_L3_LC_REL_DELAY, EV_TIMEOUT, lc_release_req},
- {ST_L3_LC_REL_WAIT, EV_RELEASE_CNF, lc_release_cnf},
- {ST_L3_LC_REL_WAIT, EV_ESTABLISH_REQ, lc_activate},
-};
-/* *INDENT-ON* */
-
-void
-l3_msg(struct PStack *st, int pr, void *arg)
-{
- switch (pr) {
- case (DL_DATA | REQUEST):
- if (st->l3.l3m.state == ST_L3_LC_ESTAB) {
- st->l3.l3l2(st, pr, arg);
- } else {
- struct sk_buff *skb = arg;
-
- skb_queue_tail(&st->l3.squeue, skb);
- FsmEvent(&st->l3.l3m, EV_ESTABLISH_REQ, NULL);
- }
- break;
- case (DL_ESTABLISH | REQUEST):
- FsmEvent(&st->l3.l3m, EV_ESTABLISH_REQ, NULL);
- break;
- case (DL_ESTABLISH | CONFIRM):
- FsmEvent(&st->l3.l3m, EV_ESTABLISH_CNF, NULL);
- break;
- case (DL_ESTABLISH | INDICATION):
- FsmEvent(&st->l3.l3m, EV_ESTABLISH_IND, NULL);
- break;
- case (DL_RELEASE | INDICATION):
- FsmEvent(&st->l3.l3m, EV_RELEASE_IND, NULL);
- break;
- case (DL_RELEASE | CONFIRM):
- FsmEvent(&st->l3.l3m, EV_RELEASE_CNF, NULL);
- break;
- case (DL_RELEASE | REQUEST):
- FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL);
- break;
- }
-}
-
-int __init
-Isdnl3New(void)
-{
- l3fsm.state_count = L3_STATE_COUNT;
- l3fsm.event_count = L3_EVENT_COUNT;
- l3fsm.strEvent = strL3Event;
- l3fsm.strState = strL3State;
- return FsmNew(&l3fsm, L3FnList, ARRAY_SIZE(L3FnList));
-}
-
-void
-Isdnl3Free(void)
-{
- FsmFree(&l3fsm);
-}
diff --git a/drivers/isdn/hisax/isdnl3.h b/drivers/isdn/hisax/isdnl3.h
deleted file mode 100644
index 0edc99d40dc2..000000000000
--- a/drivers/isdn/hisax/isdnl3.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* $Id: isdnl3.h,v 2.6.6.2 2001/09/23 22:24:49 kai Exp $
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#define SBIT(state) (1 << state)
-#define ALL_STATES 0x03ffffff
-
-#define PROTO_DIS_EURO 0x08
-
-#define L3_DEB_WARN 0x01
-#define L3_DEB_PROTERR 0x02
-#define L3_DEB_STATE 0x04
-#define L3_DEB_CHARGE 0x08
-#define L3_DEB_CHECK 0x10
-#define L3_DEB_SI 0x20
-
-struct stateentry {
- int state;
- int primitive;
- void (*rout) (struct l3_process *, u8, void *);
-};
-
-#define l3_debug(st, fmt, args...) HiSax_putstatus(st->l1.hardware, "l3 ", fmt, ## args)
-
-struct PStack;
-
-void newl3state(struct l3_process *pc, int state);
-void L3InitTimer(struct l3_process *pc, struct L3Timer *t);
-void L3DelTimer(struct L3Timer *t);
-int L3AddTimer(struct L3Timer *t, int millisec, int event);
-void StopAllL3Timer(struct l3_process *pc);
-struct sk_buff *l3_alloc_skb(int len);
-struct l3_process *new_l3_process(struct PStack *st, int cr);
-void release_l3_process(struct l3_process *p);
-struct l3_process *getl3proc(struct PStack *st, int cr);
-void l3_msg(struct PStack *st, int pr, void *arg);
-void setstack_dss1(struct PStack *st);
-void setstack_ni1(struct PStack *st);
-void setstack_1tr6(struct PStack *st);
diff --git a/drivers/isdn/hisax/isurf.c b/drivers/isdn/hisax/isurf.c
deleted file mode 100644
index 53e299be4304..000000000000
--- a/drivers/isdn/hisax/isurf.c
+++ /dev/null
@@ -1,305 +0,0 @@
-/* $Id: isurf.c,v 1.12.2.4 2004/01/13 21:46:03 keil Exp $
- *
- * low level stuff for Siemens I-Surf/I-Talk cards
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/init.h>
-#include "hisax.h"
-#include "isac.h"
-#include "isar.h"
-#include "isdnl1.h"
-#include <linux/isapnp.h>
-
-static const char *ISurf_revision = "$Revision: 1.12.2.4 $";
-
-#define byteout(addr, val) outb(val, addr)
-#define bytein(addr) inb(addr)
-
-#define ISURF_ISAR_RESET 1
-#define ISURF_ISAC_RESET 2
-#define ISURF_ISAR_EA 4
-#define ISURF_ARCOFI_RESET 8
-#define ISURF_RESET (ISURF_ISAR_RESET | ISURF_ISAC_RESET | ISURF_ARCOFI_RESET)
-
-#define ISURF_ISAR_OFFSET 0
-#define ISURF_ISAC_OFFSET 0x100
-#define ISURF_IOMEM_SIZE 0x400
-/* Interface functions */
-
-static u_char
-ReadISAC(struct IsdnCardState *cs, u_char offset)
-{
- return (readb(cs->hw.isurf.isac + offset));
-}
-
-static void
-WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
-{
- writeb(value, cs->hw.isurf.isac + offset); mb();
-}
-
-static void
-ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- register int i;
- for (i = 0; i < size; i++)
- data[i] = readb(cs->hw.isurf.isac);
-}
-
-static void
-WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- register int i;
- for (i = 0; i < size; i++) {
- writeb(data[i], cs->hw.isurf.isac); mb();
- }
-}
-
-/* ISAR access routines
- * mode = 0 access with IRQ on
- * mode = 1 access with IRQ off
- * mode = 2 access with IRQ off and using last offset
- */
-
-static u_char
-ReadISAR(struct IsdnCardState *cs, int mode, u_char offset)
-{
- return (readb(cs->hw.isurf.isar + offset));
-}
-
-static void
-WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value)
-{
- writeb(value, cs->hw.isurf.isar + offset); mb();
-}
-
-static irqreturn_t
-isurf_interrupt(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_char val;
- int cnt = 5;
- u_long flags;
-
- spin_lock_irqsave(&cs->lock, flags);
- val = readb(cs->hw.isurf.isar + ISAR_IRQBIT);
-Start_ISAR:
- if (val & ISAR_IRQSTA)
- isar_int_main(cs);
- val = readb(cs->hw.isurf.isac + ISAC_ISTA);
-Start_ISAC:
- if (val)
- isac_interrupt(cs, val);
- val = readb(cs->hw.isurf.isar + ISAR_IRQBIT);
- if ((val & ISAR_IRQSTA) && --cnt) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "ISAR IntStat after IntRoutine");
- goto Start_ISAR;
- }
- val = readb(cs->hw.isurf.isac + ISAC_ISTA);
- if (val && --cnt) {
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ISAC IntStat after IntRoutine");
- goto Start_ISAC;
- }
- if (!cnt)
- printk(KERN_WARNING "ISurf IRQ LOOP\n");
-
- writeb(0, cs->hw.isurf.isar + ISAR_IRQBIT); mb();
- writeb(0xFF, cs->hw.isurf.isac + ISAC_MASK); mb();
- writeb(0, cs->hw.isurf.isac + ISAC_MASK); mb();
- writeb(ISAR_IRQMSK, cs->hw.isurf.isar + ISAR_IRQBIT); mb();
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static void
-release_io_isurf(struct IsdnCardState *cs)
-{
- release_region(cs->hw.isurf.reset, 1);
- iounmap(cs->hw.isurf.isar);
- release_mem_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE);
-}
-
-static void
-reset_isurf(struct IsdnCardState *cs, u_char chips)
-{
- printk(KERN_INFO "ISurf: resetting card\n");
-
- byteout(cs->hw.isurf.reset, chips); /* Reset On */
- mdelay(10);
- byteout(cs->hw.isurf.reset, ISURF_ISAR_EA); /* Reset Off */
- mdelay(10);
-}
-
-static int
-ISurf_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
- u_long flags;
-
- switch (mt) {
- case CARD_RESET:
- spin_lock_irqsave(&cs->lock, flags);
- reset_isurf(cs, ISURF_RESET);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_RELEASE:
- release_io_isurf(cs);
- return (0);
- case CARD_INIT:
- spin_lock_irqsave(&cs->lock, flags);
- reset_isurf(cs, ISURF_RESET);
- clear_pending_isac_ints(cs);
- writeb(0, cs->hw.isurf.isar + ISAR_IRQBIT); mb();
- initisac(cs);
- initisar(cs);
- /* Reenable ISAC IRQ */
- cs->writeisac(cs, ISAC_MASK, 0);
- /* RESET Receiver and Transmitter */
- cs->writeisac(cs, ISAC_CMDR, 0x41);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_TEST:
- return (0);
- }
- return (0);
-}
-
-static int
-isurf_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) {
- int ret;
- u_long flags;
-
- if ((ic->command == ISDN_CMD_IOCTL) && (ic->arg == 9)) {
- ret = isar_auxcmd(cs, ic);
- spin_lock_irqsave(&cs->lock, flags);
- if (!ret) {
- reset_isurf(cs, ISURF_ISAR_EA | ISURF_ISAC_RESET |
- ISURF_ARCOFI_RESET);
- initisac(cs);
- cs->writeisac(cs, ISAC_MASK, 0);
- cs->writeisac(cs, ISAC_CMDR, 0x41);
- }
- spin_unlock_irqrestore(&cs->lock, flags);
- return (ret);
- }
- return (isar_auxcmd(cs, ic));
-}
-
-#ifdef __ISAPNP__
-static struct pnp_card *pnp_c = NULL;
-#endif
-
-int setup_isurf(struct IsdnCard *card)
-{
- int ver;
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
-
- strcpy(tmp, ISurf_revision);
- printk(KERN_INFO "HiSax: ISurf driver Rev. %s\n", HiSax_getrev(tmp));
-
- if (cs->typ != ISDN_CTYPE_ISURF)
- return (0);
- if (card->para[1] && card->para[2]) {
- cs->hw.isurf.reset = card->para[1];
- cs->hw.isurf.phymem = card->para[2];
- cs->irq = card->para[0];
- } else {
-#ifdef __ISAPNP__
- if (isapnp_present()) {
- struct pnp_dev *pnp_d = NULL;
- int err;
-
- cs->subtyp = 0;
- if ((pnp_c = pnp_find_card(
- ISAPNP_VENDOR('S', 'I', 'E'),
- ISAPNP_FUNCTION(0x0010), pnp_c))) {
- if (!(pnp_d = pnp_find_dev(pnp_c,
- ISAPNP_VENDOR('S', 'I', 'E'),
- ISAPNP_FUNCTION(0x0010), pnp_d))) {
- printk(KERN_ERR "ISurfPnP: PnP error card found, no device\n");
- return (0);
- }
- pnp_disable_dev(pnp_d);
- err = pnp_activate_dev(pnp_d);
- if (err < 0) {
- pr_warn("%s: pnp_activate_dev ret=%d\n",
- __func__, err);
- return 0;
- }
- cs->hw.isurf.reset = pnp_port_start(pnp_d, 0);
- cs->hw.isurf.phymem = pnp_mem_start(pnp_d, 1);
- cs->irq = pnp_irq(pnp_d, 0);
- if (cs->irq == -1 || !cs->hw.isurf.reset || !cs->hw.isurf.phymem) {
- printk(KERN_ERR "ISurfPnP:some resources are missing %d/%x/%lx\n",
- cs->irq, cs->hw.isurf.reset, cs->hw.isurf.phymem);
- pnp_disable_dev(pnp_d);
- return (0);
- }
- } else {
- printk(KERN_INFO "ISurfPnP: no ISAPnP card found\n");
- return (0);
- }
- } else {
- printk(KERN_INFO "ISurfPnP: no ISAPnP bus found\n");
- return (0);
- }
-#else
- printk(KERN_WARNING "HiSax: Siemens I-Surf port/mem not set\n");
- return (0);
-#endif
- }
- if (!request_region(cs->hw.isurf.reset, 1, "isurf isdn")) {
- printk(KERN_WARNING
- "HiSax: Siemens I-Surf config port %x already in use\n",
- cs->hw.isurf.reset);
- return (0);
- }
- if (!request_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE, "isurf iomem")) {
- printk(KERN_WARNING "HiSax: Siemens I-Surf memory region "
- "%lx-%lx already in use\n",
- cs->hw.isurf.phymem,
- cs->hw.isurf.phymem + ISURF_IOMEM_SIZE);
- release_region(cs->hw.isurf.reset, 1);
- return (0);
- }
- cs->hw.isurf.isar = ioremap(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE);
- cs->hw.isurf.isac = cs->hw.isurf.isar + ISURF_ISAC_OFFSET;
- printk(KERN_INFO
- "ISurf: defined at 0x%x 0x%lx IRQ %d\n",
- cs->hw.isurf.reset,
- cs->hw.isurf.phymem,
- cs->irq);
-
- setup_isac(cs);
- cs->cardmsg = &ISurf_card_msg;
- cs->irq_func = &isurf_interrupt;
- cs->auxcmd = &isurf_auxcmd;
- cs->readisac = &ReadISAC;
- cs->writeisac = &WriteISAC;
- cs->readisacfifo = &ReadISACfifo;
- cs->writeisacfifo = &WriteISACfifo;
- cs->bcs[0].hw.isar.reg = &cs->hw.isurf.isar_r;
- cs->bcs[1].hw.isar.reg = &cs->hw.isurf.isar_r;
- test_and_set_bit(HW_ISAR, &cs->HW_Flags);
- ISACVersion(cs, "ISurf:");
- cs->BC_Read_Reg = &ReadISAR;
- cs->BC_Write_Reg = &WriteISAR;
- cs->BC_Send_Data = &isar_fill_fifo;
- ver = ISARVersion(cs, "ISurf:");
- if (ver < 0) {
- printk(KERN_WARNING
- "ISurf: wrong ISAR version (ret = %d)\n", ver);
- release_io_isurf(cs);
- return (0);
- }
- return (1);
-}
diff --git a/drivers/isdn/hisax/ix1_micro.c b/drivers/isdn/hisax/ix1_micro.c
deleted file mode 100644
index bfb79f3f0a49..000000000000
--- a/drivers/isdn/hisax/ix1_micro.c
+++ /dev/null
@@ -1,316 +0,0 @@
-/* $Id: ix1_micro.c,v 2.12.2.4 2004/01/13 23:48:39 keil Exp $
- *
- * low level stuff for ITK ix1-micro Rev.2 isdn cards
- * derived from the original file teles3.c from Karsten Keil
- *
- * Author Klaus-Peter Nischke
- * Copyright by Klaus-Peter Nischke, ITK AG
- * <klaus@nischke.do.eunet.de>
- * by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Klaus-Peter Nischke
- * Deusener Str. 287
- * 44369 Dortmund
- * Germany
- */
-
-#include <linux/init.h>
-#include <linux/isapnp.h>
-#include "hisax.h"
-#include "isac.h"
-#include "hscx.h"
-#include "isdnl1.h"
-
-static const char *ix1_revision = "$Revision: 2.12.2.4 $";
-
-#define byteout(addr, val) outb(val, addr)
-#define bytein(addr) inb(addr)
-
-#define SPECIAL_PORT_OFFSET 3
-
-#define ISAC_COMMAND_OFFSET 2
-#define ISAC_DATA_OFFSET 0
-#define HSCX_COMMAND_OFFSET 2
-#define HSCX_DATA_OFFSET 1
-
-#define TIMEOUT 50
-
-static inline u_char
-readreg(unsigned int ale, unsigned int adr, u_char off)
-{
- register u_char ret;
-
- byteout(ale, off);
- ret = bytein(adr);
- return (ret);
-}
-
-static inline void
-readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
-{
- byteout(ale, off);
- insb(adr, data, size);
-}
-
-
-static inline void
-writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
-{
- byteout(ale, off);
- byteout(adr, data);
-}
-
-static inline void
-writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
-{
- byteout(ale, off);
- outsb(adr, data, size);
-}
-
-/* Interface functions */
-
-static u_char
-ReadISAC(struct IsdnCardState *cs, u_char offset)
-{
- return (readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, offset));
-}
-
-static void
-WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
-{
- writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, offset, value);
-}
-
-static void
-ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- readfifo(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, 0, data, size);
-}
-
-static void
-WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- writefifo(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, 0, data, size);
-}
-
-static u_char
-ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
-{
- return (readreg(cs->hw.ix1.hscx_ale,
- cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0)));
-}
-
-static void
-WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
-{
- writereg(cs->hw.ix1.hscx_ale,
- cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0), value);
-}
-
-#define READHSCX(cs, nr, reg) readreg(cs->hw.ix1.hscx_ale, \
- cs->hw.ix1.hscx, reg + (nr ? 0x40 : 0))
-#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.ix1.hscx_ale, \
- cs->hw.ix1.hscx, reg + (nr ? 0x40 : 0), data)
-
-#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ix1.hscx_ale, \
- cs->hw.ix1.hscx, (nr ? 0x40 : 0), ptr, cnt)
-
-#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ix1.hscx_ale, \
- cs->hw.ix1.hscx, (nr ? 0x40 : 0), ptr, cnt)
-
-#include "hscx_irq.c"
-
-static irqreturn_t
-ix1micro_interrupt(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_char val;
- u_long flags;
-
- spin_lock_irqsave(&cs->lock, flags);
- val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40);
-Start_HSCX:
- if (val)
- hscx_int_main(cs, val);
- val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA);
-Start_ISAC:
- if (val)
- isac_interrupt(cs, val);
- val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40);
- if (val) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "HSCX IntStat after IntRoutine");
- goto Start_HSCX;
- }
- val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA);
- if (val) {
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ISAC IntStat after IntRoutine");
- goto Start_ISAC;
- }
- writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0xFF);
- writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0xFF);
- writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0xFF);
- writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0);
- writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0);
- writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0);
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static void
-release_io_ix1micro(struct IsdnCardState *cs)
-{
- if (cs->hw.ix1.cfg_reg)
- release_region(cs->hw.ix1.cfg_reg, 4);
-}
-
-static void
-ix1_reset(struct IsdnCardState *cs)
-{
- int cnt;
-
- /* reset isac */
- cnt = 3 * (HZ / 10) + 1;
- while (cnt--) {
- byteout(cs->hw.ix1.cfg_reg + SPECIAL_PORT_OFFSET, 1);
- HZDELAY(1); /* wait >=10 ms */
- }
- byteout(cs->hw.ix1.cfg_reg + SPECIAL_PORT_OFFSET, 0);
-}
-
-static int
-ix1_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
- u_long flags;
-
- switch (mt) {
- case CARD_RESET:
- spin_lock_irqsave(&cs->lock, flags);
- ix1_reset(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_RELEASE:
- release_io_ix1micro(cs);
- return (0);
- case CARD_INIT:
- spin_lock_irqsave(&cs->lock, flags);
- ix1_reset(cs);
- inithscxisac(cs, 3);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_TEST:
- return (0);
- }
- return (0);
-}
-
-#ifdef __ISAPNP__
-static struct isapnp_device_id itk_ids[] = {
- { ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25),
- ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25),
- (unsigned long) "ITK micro 2" },
- { ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x29),
- ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x29),
- (unsigned long) "ITK micro 2." },
- { 0, }
-};
-
-static struct isapnp_device_id *ipid = &itk_ids[0];
-static struct pnp_card *pnp_c = NULL;
-#endif
-
-
-int setup_ix1micro(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
-
- strcpy(tmp, ix1_revision);
- printk(KERN_INFO "HiSax: ITK IX1 driver Rev. %s\n", HiSax_getrev(tmp));
- if (cs->typ != ISDN_CTYPE_IX1MICROR2)
- return (0);
-
-#ifdef __ISAPNP__
- if (!card->para[1] && isapnp_present()) {
- struct pnp_dev *pnp_d;
- while (ipid->card_vendor) {
- if ((pnp_c = pnp_find_card(ipid->card_vendor,
- ipid->card_device, pnp_c))) {
- pnp_d = NULL;
- if ((pnp_d = pnp_find_dev(pnp_c,
- ipid->vendor, ipid->function, pnp_d))) {
- int err;
-
- printk(KERN_INFO "HiSax: %s detected\n",
- (char *)ipid->driver_data);
- pnp_disable_dev(pnp_d);
- err = pnp_activate_dev(pnp_d);
- if (err < 0) {
- printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __func__, err);
- return (0);
- }
- card->para[1] = pnp_port_start(pnp_d, 0);
- card->para[0] = pnp_irq(pnp_d, 0);
- if (card->para[0] == -1 || !card->para[1]) {
- printk(KERN_ERR "ITK PnP:some resources are missing %ld/%lx\n",
- card->para[0], card->para[1]);
- pnp_disable_dev(pnp_d);
- return (0);
- }
- break;
- } else {
- printk(KERN_ERR "ITK PnP: PnP error card found, no device\n");
- }
- }
- ipid++;
- pnp_c = NULL;
- }
- if (!ipid->card_vendor) {
- printk(KERN_INFO "ITK PnP: no ISAPnP card found\n");
- return (0);
- }
- }
-#endif
- /* IO-Ports */
- cs->hw.ix1.isac_ale = card->para[1] + ISAC_COMMAND_OFFSET;
- cs->hw.ix1.hscx_ale = card->para[1] + HSCX_COMMAND_OFFSET;
- cs->hw.ix1.isac = card->para[1] + ISAC_DATA_OFFSET;
- cs->hw.ix1.hscx = card->para[1] + HSCX_DATA_OFFSET;
- cs->hw.ix1.cfg_reg = card->para[1];
- cs->irq = card->para[0];
- if (cs->hw.ix1.cfg_reg) {
- if (!request_region(cs->hw.ix1.cfg_reg, 4, "ix1micro cfg")) {
- printk(KERN_WARNING
- "HiSax: ITK ix1-micro Rev.2 config port "
- "%x-%x already in use\n",
- cs->hw.ix1.cfg_reg,
- cs->hw.ix1.cfg_reg + 4);
- return (0);
- }
- }
- printk(KERN_INFO "HiSax: ITK ix1-micro Rev.2 config irq:%d io:0x%X\n",
- cs->irq, cs->hw.ix1.cfg_reg);
- setup_isac(cs);
- cs->readisac = &ReadISAC;
- cs->writeisac = &WriteISAC;
- cs->readisacfifo = &ReadISACfifo;
- cs->writeisacfifo = &WriteISACfifo;
- cs->BC_Read_Reg = &ReadHSCX;
- cs->BC_Write_Reg = &WriteHSCX;
- cs->BC_Send_Data = &hscx_fill_fifo;
- cs->cardmsg = &ix1_card_msg;
- cs->irq_func = &ix1micro_interrupt;
- ISACVersion(cs, "ix1-Micro:");
- if (HscxVersion(cs, "ix1-Micro:")) {
- printk(KERN_WARNING
- "ix1-Micro: wrong HSCX versions check IO address\n");
- release_io_ix1micro(cs);
- return (0);
- }
- return (1);
-}
diff --git a/drivers/isdn/hisax/jade.c b/drivers/isdn/hisax/jade.c
deleted file mode 100644
index e2ae7871a209..000000000000
--- a/drivers/isdn/hisax/jade.c
+++ /dev/null
@@ -1,305 +0,0 @@
-/* $Id: jade.c,v 1.9.2.4 2004/01/14 16:04:48 keil Exp $
- *
- * JADE stuff (derived from original hscx.c)
- *
- * Author Roland Klabunde
- * Copyright by Roland Klabunde <R.Klabunde@Berkom.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-
-#include <linux/init.h>
-#include "hisax.h"
-#include "hscx.h"
-#include "jade.h"
-#include "isdnl1.h"
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-
-
-int
-JadeVersion(struct IsdnCardState *cs, char *s)
-{
- int ver;
- int to = 50;
- cs->BC_Write_Reg(cs, -1, 0x50, 0x19);
- while (to) {
- udelay(1);
- ver = cs->BC_Read_Reg(cs, -1, 0x60);
- to--;
- if (ver)
- break;
- if (!to) {
- printk(KERN_INFO "%s JADE version not obtainable\n", s);
- return (0);
- }
- }
- /* Wait for the JADE */
- udelay(10);
- /* Read version */
- ver = cs->BC_Read_Reg(cs, -1, 0x60);
- printk(KERN_INFO "%s JADE version: %d\n", s, ver);
- return (1);
-}
-
-/* Write to indirect accessible jade register set */
-static void
-jade_write_indirect(struct IsdnCardState *cs, u_char reg, u_char value)
-{
- int to = 50;
- u_char ret;
-
- /* Write the data */
- cs->BC_Write_Reg(cs, -1, COMM_JADE + 1, value);
- /* Say JADE we wanna write indirect reg 'reg' */
- cs->BC_Write_Reg(cs, -1, COMM_JADE, reg);
- to = 50;
- /* Wait for RDY goes high */
- while (to) {
- udelay(1);
- ret = cs->BC_Read_Reg(cs, -1, COMM_JADE);
- to--;
- if (ret & 1)
- /* Got acknowledge */
- break;
- if (!to) {
- printk(KERN_INFO "Can not see ready bit from JADE DSP (reg=0x%X, value=0x%X)\n", reg, value);
- return;
- }
- }
-}
-
-
-
-static void
-modejade(struct BCState *bcs, int mode, int bc)
-{
- struct IsdnCardState *cs = bcs->cs;
- int jade = bcs->hw.hscx.hscx;
-
- if (cs->debug & L1_DEB_HSCX) {
- debugl1(cs, "jade %c mode %d ichan %d", 'A' + jade, mode, bc);
- }
- bcs->mode = mode;
- bcs->channel = bc;
-
- cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, (mode == L1_MODE_TRANS ? jadeMODE_TMO : 0x00));
- cs->BC_Write_Reg(cs, jade, jade_HDLC_CCR0, (jadeCCR0_PU | jadeCCR0_ITF));
- cs->BC_Write_Reg(cs, jade, jade_HDLC_CCR1, 0x00);
-
- jade_write_indirect(cs, jade_HDLC1SERRXPATH, 0x08);
- jade_write_indirect(cs, jade_HDLC2SERRXPATH, 0x08);
- jade_write_indirect(cs, jade_HDLC1SERTXPATH, 0x00);
- jade_write_indirect(cs, jade_HDLC2SERTXPATH, 0x00);
-
- cs->BC_Write_Reg(cs, jade, jade_HDLC_XCCR, 0x07);
- cs->BC_Write_Reg(cs, jade, jade_HDLC_RCCR, 0x07);
-
- if (bc == 0) {
- cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAX, 0x00);
- cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAR, 0x00);
- } else {
- cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAX, 0x04);
- cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAR, 0x04);
- }
- switch (mode) {
- case (L1_MODE_NULL):
- cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, jadeMODE_TMO);
- break;
- case (L1_MODE_TRANS):
- cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, (jadeMODE_TMO | jadeMODE_RAC | jadeMODE_XAC));
- break;
- case (L1_MODE_HDLC):
- cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, (jadeMODE_RAC | jadeMODE_XAC));
- break;
- }
- if (mode) {
- cs->BC_Write_Reg(cs, jade, jade_HDLC_RCMD, (jadeRCMD_RRES | jadeRCMD_RMC));
- cs->BC_Write_Reg(cs, jade, jade_HDLC_XCMD, jadeXCMD_XRES);
- /* Unmask ints */
- cs->BC_Write_Reg(cs, jade, jade_HDLC_IMR, 0xF8);
- }
- else
- /* Mask ints */
- cs->BC_Write_Reg(cs, jade, jade_HDLC_IMR, 0x00);
-}
-
-static void
-jade_l2l1(struct PStack *st, int pr, void *arg)
-{
- struct BCState *bcs = st->l1.bcs;
- struct sk_buff *skb = arg;
- u_long flags;
-
- switch (pr) {
- case (PH_DATA | REQUEST):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- if (bcs->tx_skb) {
- skb_queue_tail(&bcs->squeue, skb);
- } else {
- bcs->tx_skb = skb;
- test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->hw.hscx.count = 0;
- bcs->cs->BC_Send_Data(bcs);
- }
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- break;
- case (PH_PULL | INDICATION):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- if (bcs->tx_skb) {
- printk(KERN_WARNING "jade_l2l1: this shouldn't happen\n");
- } else {
- test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->tx_skb = skb;
- bcs->hw.hscx.count = 0;
- bcs->cs->BC_Send_Data(bcs);
- }
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- break;
- case (PH_PULL | REQUEST):
- if (!bcs->tx_skb) {
- test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
- } else
- test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- break;
- case (PH_ACTIVATE | REQUEST):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
- modejade(bcs, st->l1.mode, st->l1.bc);
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- l1_msg_b(st, pr, arg);
- break;
- case (PH_DEACTIVATE | REQUEST):
- l1_msg_b(st, pr, arg);
- break;
- case (PH_DEACTIVATE | CONFIRM):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- modejade(bcs, 0, st->l1.bc);
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
- break;
- }
-}
-
-static void
-close_jadestate(struct BCState *bcs)
-{
- modejade(bcs, 0, bcs->channel);
- if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
- kfree(bcs->hw.hscx.rcvbuf);
- bcs->hw.hscx.rcvbuf = NULL;
- kfree(bcs->blog);
- bcs->blog = NULL;
- skb_queue_purge(&bcs->rqueue);
- skb_queue_purge(&bcs->squeue);
- if (bcs->tx_skb) {
- dev_kfree_skb_any(bcs->tx_skb);
- bcs->tx_skb = NULL;
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- }
- }
-}
-
-static int
-open_jadestate(struct IsdnCardState *cs, struct BCState *bcs)
-{
- if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
- if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
- printk(KERN_WARNING
- "HiSax: No memory for hscx.rcvbuf\n");
- test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
- return (1);
- }
- if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
- printk(KERN_WARNING
- "HiSax: No memory for bcs->blog\n");
- test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
- kfree(bcs->hw.hscx.rcvbuf);
- bcs->hw.hscx.rcvbuf = NULL;
- return (2);
- }
- skb_queue_head_init(&bcs->rqueue);
- skb_queue_head_init(&bcs->squeue);
- }
- bcs->tx_skb = NULL;
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->event = 0;
- bcs->hw.hscx.rcvidx = 0;
- bcs->tx_cnt = 0;
- return (0);
-}
-
-
-static int
-setstack_jade(struct PStack *st, struct BCState *bcs)
-{
- bcs->channel = st->l1.bc;
- if (open_jadestate(st->l1.hardware, bcs))
- return (-1);
- st->l1.bcs = bcs;
- st->l2.l2l1 = jade_l2l1;
- setstack_manager(st);
- bcs->st = st;
- setstack_l1_B(st);
- return (0);
-}
-
-void
-clear_pending_jade_ints(struct IsdnCardState *cs)
-{
- int val;
-
- cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0x00);
- cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0x00);
-
- val = cs->BC_Read_Reg(cs, 1, jade_HDLC_ISR);
- debugl1(cs, "jade B ISTA %x", val);
- val = cs->BC_Read_Reg(cs, 0, jade_HDLC_ISR);
- debugl1(cs, "jade A ISTA %x", val);
- val = cs->BC_Read_Reg(cs, 1, jade_HDLC_STAR);
- debugl1(cs, "jade B STAR %x", val);
- val = cs->BC_Read_Reg(cs, 0, jade_HDLC_STAR);
- debugl1(cs, "jade A STAR %x", val);
- /* Unmask ints */
- cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0xF8);
- cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0xF8);
-}
-
-void
-initjade(struct IsdnCardState *cs)
-{
- cs->bcs[0].BC_SetStack = setstack_jade;
- cs->bcs[1].BC_SetStack = setstack_jade;
- cs->bcs[0].BC_Close = close_jadestate;
- cs->bcs[1].BC_Close = close_jadestate;
- cs->bcs[0].hw.hscx.hscx = 0;
- cs->bcs[1].hw.hscx.hscx = 1;
-
- /* Stop DSP audio tx/rx */
- jade_write_indirect(cs, 0x11, 0x0f);
- jade_write_indirect(cs, 0x17, 0x2f);
-
- /* Transparent Mode, RxTx inactive, No Test, No RFS/TFS */
- cs->BC_Write_Reg(cs, 0, jade_HDLC_MODE, jadeMODE_TMO);
- cs->BC_Write_Reg(cs, 1, jade_HDLC_MODE, jadeMODE_TMO);
- /* Power down, 1-Idle, RxTx least significant bit first */
- cs->BC_Write_Reg(cs, 0, jade_HDLC_CCR0, 0x00);
- cs->BC_Write_Reg(cs, 1, jade_HDLC_CCR0, 0x00);
- /* Mask all interrupts */
- cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0x00);
- cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0x00);
- /* Setup host access to hdlc controller */
- jade_write_indirect(cs, jade_HDLCCNTRACCESS, (jadeINDIRECT_HAH1 | jadeINDIRECT_HAH2));
- /* Unmask HDLC int (don't forget DSP int later on)*/
- cs->BC_Write_Reg(cs, -1, jade_INT, (jadeINT_HDLC1 | jadeINT_HDLC2));
-
- /* once again TRANSPARENT */
- modejade(cs->bcs, 0, 0);
- modejade(cs->bcs + 1, 0, 0);
-}
diff --git a/drivers/isdn/hisax/jade.h b/drivers/isdn/hisax/jade.h
deleted file mode 100644
index 4b98096a5858..000000000000
--- a/drivers/isdn/hisax/jade.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/* $Id: jade.h,v 1.5.2.3 2004/01/14 16:04:48 keil Exp $
- *
- * JADE specific defines
- *
- * Author Roland Klabunde
- * Copyright by Roland Klabunde <R.Klabunde@Berkom.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-/* All Registers original Siemens Spec */
-#ifndef __JADE_H__
-#define __JADE_H__
-
-/* Special registers for access to indirect accessible JADE regs */
-#define DIRECT_IO_JADE 0x0000 /* Jade direct io access area */
-#define COMM_JADE 0x0040 /* Jade communication area */
-
-/********************************************************************/
-/* JADE-HDLC registers */
-/********************************************************************/
-#define jade_HDLC_RFIFO 0x00 /* R */
-#define jade_HDLC_XFIFO 0x00 /* W */
-
-#define jade_HDLC_STAR 0x20 /* R */
-#define jadeSTAR_XDOV 0x80
-#define jadeSTAR_XFW 0x40 /* Does not work*/
-#define jadeSTAR_XCEC 0x20
-#define jadeSTAR_RCEC 0x10
-#define jadeSTAR_BSY 0x08
-#define jadeSTAR_RNA 0x04
-#define jadeSTAR_STR 0x02
-#define jadeSTAR_STX 0x01
-
-#define jade_HDLC_XCMD 0x20 /* W */
-#define jadeXCMD_XF 0x80
-#define jadeXCMD_XME 0x40
-#define jadeXCMD_XRES 0x20
-#define jadeXCMD_STX 0x01
-
-#define jade_HDLC_RSTA 0x21 /* R */
-#define jadeRSTA_VFR 0x80
-#define jadeRSTA_RDO 0x40
-#define jadeRSTA_CRC 0x20
-#define jadeRSTA_RAB 0x10
-#define jadeRSTA_MASK 0xF0
-
-#define jade_HDLC_MODE 0x22 /* RW*/
-#define jadeMODE_TMO 0x80
-#define jadeMODE_RAC 0x40
-#define jadeMODE_XAC 0x20
-#define jadeMODE_TLP 0x10
-#define jadeMODE_ERFS 0x02
-#define jadeMODE_ETFS 0x01
-
-#define jade_HDLC_RBCH 0x24 /* R */
-
-#define jade_HDLC_RBCL 0x25 /* R */
-#define jade_HDLC_RCMD 0x25 /* W */
-#define jadeRCMD_RMC 0x80
-#define jadeRCMD_RRES 0x40
-#define jadeRCMD_RMD 0x20
-#define jadeRCMD_STR 0x02
-
-#define jade_HDLC_CCR0 0x26 /* RW*/
-#define jadeCCR0_PU 0x80
-#define jadeCCR0_ITF 0x40
-#define jadeCCR0_C32 0x20
-#define jadeCCR0_CRL 0x10
-#define jadeCCR0_RCRC 0x08
-#define jadeCCR0_XCRC 0x04
-#define jadeCCR0_RMSB 0x02
-#define jadeCCR0_XMSB 0x01
-
-#define jade_HDLC_CCR1 0x27 /* RW*/
-#define jadeCCR1_RCS0 0x80
-#define jadeCCR1_RCONT 0x40
-#define jadeCCR1_RFDIS 0x20
-#define jadeCCR1_XCS0 0x10
-#define jadeCCR1_XCONT 0x08
-#define jadeCCR1_XFDIS 0x04
-
-#define jade_HDLC_TSAR 0x28 /* RW*/
-#define jade_HDLC_TSAX 0x29 /* RW*/
-#define jade_HDLC_RCCR 0x2A /* RW*/
-#define jade_HDLC_XCCR 0x2B /* RW*/
-
-#define jade_HDLC_ISR 0x2C /* R */
-#define jade_HDLC_IMR 0x2C /* W */
-#define jadeISR_RME 0x80
-#define jadeISR_RPF 0x40
-#define jadeISR_RFO 0x20
-#define jadeISR_XPR 0x10
-#define jadeISR_XDU 0x08
-#define jadeISR_ALLS 0x04
-
-#define jade_INT 0x75
-#define jadeINT_HDLC1 0x02
-#define jadeINT_HDLC2 0x01
-#define jadeINT_DSP 0x04
-#define jade_INTR 0x70
-
-/********************************************************************/
-/* Indirect accessible JADE registers of common interest */
-/********************************************************************/
-#define jade_CHIPVERSIONNR 0x00 /* Does not work*/
-
-#define jade_HDLCCNTRACCESS 0x10
-#define jadeINDIRECT_HAH1 0x02
-#define jadeINDIRECT_HAH2 0x01
-
-#define jade_HDLC1SERRXPATH 0x1D
-#define jade_HDLC1SERTXPATH 0x1E
-#define jade_HDLC2SERRXPATH 0x1F
-#define jade_HDLC2SERTXPATH 0x20
-#define jadeINDIRECT_SLIN1 0x10
-#define jadeINDIRECT_SLIN0 0x08
-#define jadeINDIRECT_LMOD1 0x04
-#define jadeINDIRECT_LMOD0 0x02
-#define jadeINDIRECT_HHR 0x01
-#define jadeINDIRECT_HHX 0x01
-
-#define jade_RXAUDIOCH1CFG 0x11
-#define jade_RXAUDIOCH2CFG 0x14
-#define jade_TXAUDIOCH1CFG 0x17
-#define jade_TXAUDIOCH2CFG 0x1A
-
-extern int JadeVersion(struct IsdnCardState *cs, char *s);
-extern void clear_pending_jade_ints(struct IsdnCardState *cs);
-extern void initjade(struct IsdnCardState *cs);
-
-#endif /* __JADE_H__ */
diff --git a/drivers/isdn/hisax/jade_irq.c b/drivers/isdn/hisax/jade_irq.c
deleted file mode 100644
index a89e2df911c5..000000000000
--- a/drivers/isdn/hisax/jade_irq.c
+++ /dev/null
@@ -1,238 +0,0 @@
-/* $Id: jade_irq.c,v 1.7.2.4 2004/02/11 13:21:34 keil Exp $
- *
- * Low level JADE IRQ stuff (derived from original hscx_irq.c)
- *
- * Author Roland Klabunde
- * Copyright by Roland Klabunde <R.Klabunde@Berkom.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-static inline void
-waitforCEC(struct IsdnCardState *cs, int jade, int reg)
-{
- int to = 50;
- int mask = (reg == jade_HDLC_XCMD ? jadeSTAR_XCEC : jadeSTAR_RCEC);
- while ((READJADE(cs, jade, jade_HDLC_STAR) & mask) && to) {
- udelay(1);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "HiSax: waitforCEC (jade) timeout\n");
-}
-
-
-static inline void
-waitforXFW(struct IsdnCardState *cs, int jade)
-{
- /* Does not work on older jade versions, don't care */
-}
-
-static inline void
-WriteJADECMDR(struct IsdnCardState *cs, int jade, int reg, u_char data)
-{
- waitforCEC(cs, jade, reg);
- WRITEJADE(cs, jade, reg, data);
-}
-
-
-
-static void
-jade_empty_fifo(struct BCState *bcs, int count)
-{
- u_char *ptr;
- struct IsdnCardState *cs = bcs->cs;
-
- if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
- debugl1(cs, "jade_empty_fifo");
-
- if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "jade_empty_fifo: incoming packet too large");
- WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC);
- bcs->hw.hscx.rcvidx = 0;
- return;
- }
- ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
- bcs->hw.hscx.rcvidx += count;
- READJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
- WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC);
- if (cs->debug & L1_DEB_HSCX_FIFO) {
- char *t = bcs->blog;
-
- t += sprintf(t, "jade_empty_fifo %c cnt %d",
- bcs->hw.hscx.hscx ? 'B' : 'A', count);
- QuickHex(t, ptr, count);
- debugl1(cs, "%s", bcs->blog);
- }
-}
-
-static void
-jade_fill_fifo(struct BCState *bcs)
-{
- struct IsdnCardState *cs = bcs->cs;
- int more, count;
- int fifo_size = 32;
- u_char *ptr;
-
- if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
- debugl1(cs, "jade_fill_fifo");
-
- if (!bcs->tx_skb)
- return;
- if (bcs->tx_skb->len <= 0)
- return;
-
- more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
- if (bcs->tx_skb->len > fifo_size) {
- more = !0;
- count = fifo_size;
- } else
- count = bcs->tx_skb->len;
-
- waitforXFW(cs, bcs->hw.hscx.hscx);
- ptr = bcs->tx_skb->data;
- skb_pull(bcs->tx_skb, count);
- bcs->tx_cnt -= count;
- bcs->hw.hscx.count += count;
- WRITEJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
- WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, more ? jadeXCMD_XF : (jadeXCMD_XF | jadeXCMD_XME));
- if (cs->debug & L1_DEB_HSCX_FIFO) {
- char *t = bcs->blog;
-
- t += sprintf(t, "jade_fill_fifo %c cnt %d",
- bcs->hw.hscx.hscx ? 'B' : 'A', count);
- QuickHex(t, ptr, count);
- debugl1(cs, "%s", bcs->blog);
- }
-}
-
-
-static void
-jade_interrupt(struct IsdnCardState *cs, u_char val, u_char jade)
-{
- u_char r;
- struct BCState *bcs = cs->bcs + jade;
- struct sk_buff *skb;
- int fifo_size = 32;
- int count;
- int i_jade = (int) jade; /* To satisfy the compiler */
-
- if (!test_bit(BC_FLG_INIT, &bcs->Flag))
- return;
-
- if (val & 0x80) { /* RME */
- r = READJADE(cs, i_jade, jade_HDLC_RSTA);
- if ((r & 0xf0) != 0xa0) {
- if (!(r & 0x80))
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "JADE %s invalid frame", (jade ? "B" : "A"));
- if ((r & 0x40) && bcs->mode)
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "JADE %c RDO mode=%d", 'A' + jade, bcs->mode);
- if (!(r & 0x20))
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "JADE %c CRC error", 'A' + jade);
- WriteJADECMDR(cs, jade, jade_HDLC_RCMD, jadeRCMD_RMC);
- } else {
- count = READJADE(cs, i_jade, jade_HDLC_RBCL) & 0x1F;
- if (count == 0)
- count = fifo_size;
- jade_empty_fifo(bcs, count);
- if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
- if (cs->debug & L1_DEB_HSCX_FIFO)
- debugl1(cs, "HX Frame %d", count);
- if (!(skb = dev_alloc_skb(count)))
- printk(KERN_WARNING "JADE %s receive out of memory\n", (jade ? "B" : "A"));
- else {
- skb_put_data(skb, bcs->hw.hscx.rcvbuf,
- count);
- skb_queue_tail(&bcs->rqueue, skb);
- }
- }
- }
- bcs->hw.hscx.rcvidx = 0;
- schedule_event(bcs, B_RCVBUFREADY);
- }
- if (val & 0x40) { /* RPF */
- jade_empty_fifo(bcs, fifo_size);
- if (bcs->mode == L1_MODE_TRANS) {
- /* receive audio data */
- if (!(skb = dev_alloc_skb(fifo_size)))
- printk(KERN_WARNING "HiSax: receive out of memory\n");
- else {
- skb_put_data(skb, bcs->hw.hscx.rcvbuf,
- fifo_size);
- skb_queue_tail(&bcs->rqueue, skb);
- }
- bcs->hw.hscx.rcvidx = 0;
- schedule_event(bcs, B_RCVBUFREADY);
- }
- }
- if (val & 0x10) { /* XPR */
- if (bcs->tx_skb) {
- if (bcs->tx_skb->len) {
- jade_fill_fifo(bcs);
- return;
- } else {
- if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
- (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
- u_long flags;
- spin_lock_irqsave(&bcs->aclock, flags);
- bcs->ackcnt += bcs->hw.hscx.count;
- spin_unlock_irqrestore(&bcs->aclock, flags);
- schedule_event(bcs, B_ACKPENDING);
- }
- dev_kfree_skb_irq(bcs->tx_skb);
- bcs->hw.hscx.count = 0;
- bcs->tx_skb = NULL;
- }
- }
- if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
- bcs->hw.hscx.count = 0;
- test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
- jade_fill_fifo(bcs);
- } else {
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- schedule_event(bcs, B_XMTBUFREADY);
- }
- }
-}
-
-static inline void
-jade_int_main(struct IsdnCardState *cs, u_char val, int jade)
-{
- struct BCState *bcs;
- bcs = cs->bcs + jade;
-
- if (val & jadeISR_RFO) {
- /* handled with RDO */
- val &= ~jadeISR_RFO;
- }
- if (val & jadeISR_XDU) {
- /* relevant in HDLC mode only */
- /* don't reset XPR here */
- if (bcs->mode == 1)
- jade_fill_fifo(bcs);
- else {
- /* Here we lost an TX interrupt, so
- * restart transmitting the whole frame.
- */
- if (bcs->tx_skb) {
- skb_push(bcs->tx_skb, bcs->hw.hscx.count);
- bcs->tx_cnt += bcs->hw.hscx.count;
- bcs->hw.hscx.count = 0;
- }
- WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, jadeXCMD_XRES);
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "JADE %c EXIR %x Lost TX", 'A' + jade, val);
- }
- }
- if (val & (jadeISR_RME | jadeISR_RPF | jadeISR_XPR)) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "JADE %c interrupt %x", 'A' + jade, val);
- jade_interrupt(cs, val, jade);
- }
-}
diff --git a/drivers/isdn/hisax/l3_1tr6.c b/drivers/isdn/hisax/l3_1tr6.c
deleted file mode 100644
index 98f60d1523f4..000000000000
--- a/drivers/isdn/hisax/l3_1tr6.c
+++ /dev/null
@@ -1,932 +0,0 @@
-/* $Id: l3_1tr6.c,v 2.15.2.3 2004/01/13 14:31:25 keil Exp $
- *
- * German 1TR6 D-channel protocol
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * For changes and modifications please read
- * Documentation/isdn/HiSax.cert
- *
- */
-
-#include "hisax.h"
-#include "l3_1tr6.h"
-#include "isdnl3.h"
-#include <linux/ctype.h>
-
-extern char *HiSax_getrev(const char *revision);
-static const char *l3_1tr6_revision = "$Revision: 2.15.2.3 $";
-
-#define MsgHead(ptr, cref, mty, dis) \
- *ptr++ = dis; \
- *ptr++ = 0x1; \
- *ptr++ = cref ^ 0x80; \
- *ptr++ = mty
-
-static void
-l3_1TR6_message(struct l3_process *pc, u_char mt, u_char pd)
-{
- struct sk_buff *skb;
- u_char *p;
-
- if (!(skb = l3_alloc_skb(4)))
- return;
- p = skb_put(skb, 4);
- MsgHead(p, pc->callref, mt, pd);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
-}
-
-static void
-l3_1tr6_release_req(struct l3_process *pc, u_char pr, void *arg)
-{
- StopAllL3Timer(pc);
- newl3state(pc, 19);
- l3_1TR6_message(pc, MT_N1_REL, PROTO_DIS_N1);
- L3AddTimer(&pc->timer, T308, CC_T308_1);
-}
-
-static void
-l3_1tr6_invalid(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
-
- dev_kfree_skb(skb);
- l3_1tr6_release_req(pc, 0, NULL);
-}
-
-static void
-l3_1tr6_error(struct l3_process *pc, u_char *msg, struct sk_buff *skb)
-{
- dev_kfree_skb(skb);
- if (pc->st->l3.debug & L3_DEB_WARN)
- l3_debug(pc->st, "%s", msg);
- l3_1tr6_release_req(pc, 0, NULL);
-}
-
-static void
-l3_1tr6_setup_req(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb;
- u_char tmp[128];
- u_char *p = tmp;
- u_char *teln;
- u_char *eaz;
- u_char channel = 0;
- int l;
-
- MsgHead(p, pc->callref, MT_N1_SETUP, PROTO_DIS_N1);
- teln = pc->para.setup.phone;
- pc->para.spv = 0;
- if (!isdigit(*teln)) {
- switch (0x5f & *teln) {
- case 'S':
- pc->para.spv = 1;
- break;
- case 'C':
- channel = 0x08;
- /* fall through */
- case 'P':
- channel |= 0x80;
- teln++;
- if (*teln == '1')
- channel |= 0x01;
- else
- channel |= 0x02;
- break;
- default:
- if (pc->st->l3.debug & L3_DEB_WARN)
- l3_debug(pc->st, "Wrong MSN Code");
- break;
- }
- teln++;
- }
- if (channel) {
- *p++ = 0x18; /* channel indicator */
- *p++ = 1;
- *p++ = channel;
- }
- if (pc->para.spv) { /* SPV ? */
- /* NSF SPV */
- *p++ = WE0_netSpecFac;
- *p++ = 4; /* Laenge */
- *p++ = 0;
- *p++ = FAC_SPV; /* SPV */
- *p++ = pc->para.setup.si1; /* 0 for all Services */
- *p++ = pc->para.setup.si2; /* 0 for all Services */
- *p++ = WE0_netSpecFac;
- *p++ = 4; /* Laenge */
- *p++ = 0;
- *p++ = FAC_Activate; /* aktiviere SPV (default) */
- *p++ = pc->para.setup.si1; /* 0 for all Services */
- *p++ = pc->para.setup.si2; /* 0 for all Services */
- }
- eaz = pc->para.setup.eazmsn;
- if (*eaz) {
- *p++ = WE0_origAddr;
- *p++ = strlen(eaz) + 1;
- /* Classify as AnyPref. */
- *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
- while (*eaz)
- *p++ = *eaz++ & 0x7f;
- }
- *p++ = WE0_destAddr;
- *p++ = strlen(teln) + 1;
- /* Classify as AnyPref. */
- *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
- while (*teln)
- *p++ = *teln++ & 0x7f;
-
- *p++ = WE_Shift_F6;
- /* Codesatz 6 fuer Service */
- *p++ = WE6_serviceInd;
- *p++ = 2; /* len=2 info,info2 */
- *p++ = pc->para.setup.si1;
- *p++ = pc->para.setup.si2;
-
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- skb_put_data(skb, tmp, l);
- L3DelTimer(&pc->timer);
- L3AddTimer(&pc->timer, T303, CC_T303);
- newl3state(pc, 1);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
-}
-
-static void
-l3_1tr6_setup(struct l3_process *pc, u_char pr, void *arg)
-{
- u_char *p;
- int bcfound = 0;
- struct sk_buff *skb = arg;
-
- /* Channel Identification */
- p = findie(skb->data, skb->len, WE0_chanID, 0);
- if (p) {
- if (p[1] != 1) {
- l3_1tr6_error(pc, "setup wrong chanID len", skb);
- return;
- }
- if ((p[2] & 0xf4) != 0x80) {
- l3_1tr6_error(pc, "setup wrong WE0_chanID", skb);
- return;
- }
- if ((pc->para.bchannel = p[2] & 0x3))
- bcfound++;
- } else {
- l3_1tr6_error(pc, "missing setup chanID", skb);
- return;
- }
-
- p = skb->data;
- if ((p = findie(p, skb->len, WE6_serviceInd, 6))) {
- pc->para.setup.si1 = p[2];
- pc->para.setup.si2 = p[3];
- } else {
- l3_1tr6_error(pc, "missing setup SI", skb);
- return;
- }
-
- p = skb->data;
- if ((p = findie(p, skb->len, WE0_destAddr, 0)))
- iecpy(pc->para.setup.eazmsn, p, 1);
- else
- pc->para.setup.eazmsn[0] = 0;
-
- p = skb->data;
- if ((p = findie(p, skb->len, WE0_origAddr, 0))) {
- iecpy(pc->para.setup.phone, p, 1);
- } else
- pc->para.setup.phone[0] = 0;
-
- p = skb->data;
- pc->para.spv = 0;
- if ((p = findie(p, skb->len, WE0_netSpecFac, 0))) {
- if ((FAC_SPV == p[3]) || (FAC_Activate == p[3]))
- pc->para.spv = 1;
- }
- dev_kfree_skb(skb);
-
- /* Signal all services, linklevel takes care of Service-Indicator */
- if (bcfound) {
- if ((pc->para.setup.si1 != 7) && (pc->st->l3.debug & L3_DEB_WARN)) {
- l3_debug(pc->st, "non-digital call: %s -> %s",
- pc->para.setup.phone,
- pc->para.setup.eazmsn);
- }
- newl3state(pc, 6);
- pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc);
- } else
- release_l3_process(pc);
-}
-
-static void
-l3_1tr6_setup_ack(struct l3_process *pc, u_char pr, void *arg)
-{
- u_char *p;
- struct sk_buff *skb = arg;
-
- L3DelTimer(&pc->timer);
- p = skb->data;
- newl3state(pc, 2);
- if ((p = findie(p, skb->len, WE0_chanID, 0))) {
- if (p[1] != 1) {
- l3_1tr6_error(pc, "setup_ack wrong chanID len", skb);
- return;
- }
- if ((p[2] & 0xf4) != 0x80) {
- l3_1tr6_error(pc, "setup_ack wrong WE0_chanID", skb);
- return;
- }
- pc->para.bchannel = p[2] & 0x3;
- } else {
- l3_1tr6_error(pc, "missing setup_ack WE0_chanID", skb);
- return;
- }
- dev_kfree_skb(skb);
- L3AddTimer(&pc->timer, T304, CC_T304);
- pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
-}
-
-static void
-l3_1tr6_call_sent(struct l3_process *pc, u_char pr, void *arg)
-{
- u_char *p;
- struct sk_buff *skb = arg;
-
- L3DelTimer(&pc->timer);
- p = skb->data;
- if ((p = findie(p, skb->len, WE0_chanID, 0))) {
- if (p[1] != 1) {
- l3_1tr6_error(pc, "call sent wrong chanID len", skb);
- return;
- }
- if ((p[2] & 0xf4) != 0x80) {
- l3_1tr6_error(pc, "call sent wrong WE0_chanID", skb);
- return;
- }
- if ((pc->state == 2) && (pc->para.bchannel != (p[2] & 0x3))) {
- l3_1tr6_error(pc, "call sent wrong chanID value", skb);
- return;
- }
- pc->para.bchannel = p[2] & 0x3;
- } else {
- l3_1tr6_error(pc, "missing call sent WE0_chanID", skb);
- return;
- }
- dev_kfree_skb(skb);
- L3AddTimer(&pc->timer, T310, CC_T310);
- newl3state(pc, 3);
- pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc);
-}
-
-static void
-l3_1tr6_alert(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
-
- dev_kfree_skb(skb);
- L3DelTimer(&pc->timer); /* T304 */
- newl3state(pc, 4);
- pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc);
-}
-
-static void
-l3_1tr6_info(struct l3_process *pc, u_char pr, void *arg)
-{
- u_char *p;
- int i, tmpcharge = 0;
- char a_charge[8];
- struct sk_buff *skb = arg;
-
- p = skb->data;
- if ((p = findie(p, skb->len, WE6_chargingInfo, 6))) {
- iecpy(a_charge, p, 1);
- for (i = 0; i < strlen(a_charge); i++) {
- tmpcharge *= 10;
- tmpcharge += a_charge[i] & 0xf;
- }
- if (tmpcharge > pc->para.chargeinfo) {
- pc->para.chargeinfo = tmpcharge;
- pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc);
- }
- if (pc->st->l3.debug & L3_DEB_CHARGE) {
- l3_debug(pc->st, "charging info %d",
- pc->para.chargeinfo);
- }
- } else if (pc->st->l3.debug & L3_DEB_CHARGE)
- l3_debug(pc->st, "charging info not found");
- dev_kfree_skb(skb);
-
-}
-
-static void
-l3_1tr6_info_s2(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
-
- dev_kfree_skb(skb);
-}
-
-static void
-l3_1tr6_connect(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
-
- L3DelTimer(&pc->timer); /* T310 */
- if (!findie(skb->data, skb->len, WE6_date, 6)) {
- l3_1tr6_error(pc, "missing connect date", skb);
- return;
- }
- newl3state(pc, 10);
- dev_kfree_skb(skb);
- pc->para.chargeinfo = 0;
- pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc);
-}
-
-static void
-l3_1tr6_rel(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- u_char *p;
-
- p = skb->data;
- if ((p = findie(p, skb->len, WE0_cause, 0))) {
- if (p[1] > 0) {
- pc->para.cause = p[2];
- if (p[1] > 1)
- pc->para.loc = p[3];
- else
- pc->para.loc = 0;
- } else {
- pc->para.cause = 0;
- pc->para.loc = 0;
- }
- } else {
- pc->para.cause = NO_CAUSE;
- l3_1tr6_error(pc, "missing REL cause", skb);
- return;
- }
- dev_kfree_skb(skb);
- StopAllL3Timer(pc);
- newl3state(pc, 0);
- l3_1TR6_message(pc, MT_N1_REL_ACK, PROTO_DIS_N1);
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
- release_l3_process(pc);
-}
-
-static void
-l3_1tr6_rel_ack(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
-
- dev_kfree_skb(skb);
- StopAllL3Timer(pc);
- newl3state(pc, 0);
- pc->para.cause = NO_CAUSE;
- pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc);
- release_l3_process(pc);
-}
-
-static void
-l3_1tr6_disc(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- u_char *p;
- int i, tmpcharge = 0;
- char a_charge[8];
-
- StopAllL3Timer(pc);
- p = skb->data;
- if ((p = findie(p, skb->len, WE6_chargingInfo, 6))) {
- iecpy(a_charge, p, 1);
- for (i = 0; i < strlen(a_charge); i++) {
- tmpcharge *= 10;
- tmpcharge += a_charge[i] & 0xf;
- }
- if (tmpcharge > pc->para.chargeinfo) {
- pc->para.chargeinfo = tmpcharge;
- pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc);
- }
- if (pc->st->l3.debug & L3_DEB_CHARGE) {
- l3_debug(pc->st, "charging info %d",
- pc->para.chargeinfo);
- }
- } else if (pc->st->l3.debug & L3_DEB_CHARGE)
- l3_debug(pc->st, "charging info not found");
-
-
- p = skb->data;
- if ((p = findie(p, skb->len, WE0_cause, 0))) {
- if (p[1] > 0) {
- pc->para.cause = p[2];
- if (p[1] > 1)
- pc->para.loc = p[3];
- else
- pc->para.loc = 0;
- } else {
- pc->para.cause = 0;
- pc->para.loc = 0;
- }
- } else {
- if (pc->st->l3.debug & L3_DEB_WARN)
- l3_debug(pc->st, "cause not found");
- pc->para.cause = NO_CAUSE;
- }
- if (!findie(skb->data, skb->len, WE6_date, 6)) {
- l3_1tr6_error(pc, "missing connack date", skb);
- return;
- }
- dev_kfree_skb(skb);
- newl3state(pc, 12);
- pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc);
-}
-
-
-static void
-l3_1tr6_connect_ack(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
-
- if (!findie(skb->data, skb->len, WE6_date, 6)) {
- l3_1tr6_error(pc, "missing connack date", skb);
- return;
- }
- dev_kfree_skb(skb);
- newl3state(pc, 10);
- pc->para.chargeinfo = 0;
- L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
-}
-
-static void
-l3_1tr6_alert_req(struct l3_process *pc, u_char pr, void *arg)
-{
- newl3state(pc, 7);
- l3_1TR6_message(pc, MT_N1_ALERT, PROTO_DIS_N1);
-}
-
-static void
-l3_1tr6_setup_rsp(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb;
- u_char tmp[24];
- u_char *p = tmp;
- int l;
-
- MsgHead(p, pc->callref, MT_N1_CONN, PROTO_DIS_N1);
- if (pc->para.spv) { /* SPV ? */
- /* NSF SPV */
- *p++ = WE0_netSpecFac;
- *p++ = 4; /* Laenge */
- *p++ = 0;
- *p++ = FAC_SPV; /* SPV */
- *p++ = pc->para.setup.si1;
- *p++ = pc->para.setup.si2;
- *p++ = WE0_netSpecFac;
- *p++ = 4; /* Laenge */
- *p++ = 0;
- *p++ = FAC_Activate; /* aktiviere SPV */
- *p++ = pc->para.setup.si1;
- *p++ = pc->para.setup.si2;
- }
- newl3state(pc, 8);
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- skb_put_data(skb, tmp, l);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
- L3DelTimer(&pc->timer);
- L3AddTimer(&pc->timer, T313, CC_T313);
-}
-
-static void
-l3_1tr6_reset(struct l3_process *pc, u_char pr, void *arg)
-{
- release_l3_process(pc);
-}
-
-static void
-l3_1tr6_disconnect_req(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb;
- u_char tmp[16];
- u_char *p = tmp;
- int l;
- u_char cause = 0x10;
- u_char clen = 1;
-
- if (pc->para.cause > 0)
- cause = pc->para.cause;
- /* Map DSS1 causes */
- switch (cause & 0x7f) {
- case 0x10:
- clen = 0;
- break;
- case 0x11:
- cause = CAUSE_UserBusy;
- break;
- case 0x15:
- cause = CAUSE_CallRejected;
- break;
- }
- StopAllL3Timer(pc);
- MsgHead(p, pc->callref, MT_N1_DISC, PROTO_DIS_N1);
- *p++ = WE0_cause;
- *p++ = clen; /* Laenge */
- if (clen)
- *p++ = cause | 0x80;
- newl3state(pc, 11);
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- skb_put_data(skb, tmp, l);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
- L3AddTimer(&pc->timer, T305, CC_T305);
-}
-
-static void
-l3_1tr6_t303(struct l3_process *pc, u_char pr, void *arg)
-{
- if (pc->N303 > 0) {
- pc->N303--;
- L3DelTimer(&pc->timer);
- l3_1tr6_setup_req(pc, pr, arg);
- } else {
- L3DelTimer(&pc->timer);
- pc->para.cause = 0;
- l3_1tr6_disconnect_req(pc, 0, NULL);
- }
-}
-
-static void
-l3_1tr6_t304(struct l3_process *pc, u_char pr, void *arg)
-{
- L3DelTimer(&pc->timer);
- pc->para.cause = 0xE6;
- l3_1tr6_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
-}
-
-static void
-l3_1tr6_t305(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb;
- u_char tmp[16];
- u_char *p = tmp;
- int l;
- u_char cause = 0x90;
- u_char clen = 1;
-
- L3DelTimer(&pc->timer);
- if (pc->para.cause != NO_CAUSE)
- cause = pc->para.cause;
- /* Map DSS1 causes */
- switch (cause & 0x7f) {
- case 0x10:
- clen = 0;
- break;
- case 0x15:
- cause = CAUSE_CallRejected;
- break;
- }
- MsgHead(p, pc->callref, MT_N1_REL, PROTO_DIS_N1);
- *p++ = WE0_cause;
- *p++ = clen; /* Laenge */
- if (clen)
- *p++ = cause;
- newl3state(pc, 19);
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- skb_put_data(skb, tmp, l);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
- L3AddTimer(&pc->timer, T308, CC_T308_1);
-}
-
-static void
-l3_1tr6_t310(struct l3_process *pc, u_char pr, void *arg)
-{
- L3DelTimer(&pc->timer);
- pc->para.cause = 0xE6;
- l3_1tr6_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
-}
-
-static void
-l3_1tr6_t313(struct l3_process *pc, u_char pr, void *arg)
-{
- L3DelTimer(&pc->timer);
- pc->para.cause = 0xE6;
- l3_1tr6_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc);
-}
-
-static void
-l3_1tr6_t308_1(struct l3_process *pc, u_char pr, void *arg)
-{
- L3DelTimer(&pc->timer);
- l3_1TR6_message(pc, MT_N1_REL, PROTO_DIS_N1);
- L3AddTimer(&pc->timer, T308, CC_T308_2);
- newl3state(pc, 19);
-}
-
-static void
-l3_1tr6_t308_2(struct l3_process *pc, u_char pr, void *arg)
-{
- L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc);
- release_l3_process(pc);
-}
-
-static void
-l3_1tr6_dl_reset(struct l3_process *pc, u_char pr, void *arg)
-{
- pc->para.cause = CAUSE_LocalProcErr;
- l3_1tr6_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
-}
-
-static void
-l3_1tr6_dl_release(struct l3_process *pc, u_char pr, void *arg)
-{
- newl3state(pc, 0);
- pc->para.cause = 0x1b; /* Destination out of order */
- pc->para.loc = 0;
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
- release_l3_process(pc);
-}
-
-/* *INDENT-OFF* */
-static struct stateentry downstl[] =
-{
- {SBIT(0),
- CC_SETUP | REQUEST, l3_1tr6_setup_req},
- {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) |
- SBIT(10),
- CC_DISCONNECT | REQUEST, l3_1tr6_disconnect_req},
- {SBIT(12),
- CC_RELEASE | REQUEST, l3_1tr6_release_req},
- {SBIT(6),
- CC_IGNORE | REQUEST, l3_1tr6_reset},
- {SBIT(6),
- CC_REJECT | REQUEST, l3_1tr6_disconnect_req},
- {SBIT(6),
- CC_ALERTING | REQUEST, l3_1tr6_alert_req},
- {SBIT(6) | SBIT(7),
- CC_SETUP | RESPONSE, l3_1tr6_setup_rsp},
- {SBIT(1),
- CC_T303, l3_1tr6_t303},
- {SBIT(2),
- CC_T304, l3_1tr6_t304},
- {SBIT(3),
- CC_T310, l3_1tr6_t310},
- {SBIT(8),
- CC_T313, l3_1tr6_t313},
- {SBIT(11),
- CC_T305, l3_1tr6_t305},
- {SBIT(19),
- CC_T308_1, l3_1tr6_t308_1},
- {SBIT(19),
- CC_T308_2, l3_1tr6_t308_2},
-};
-
-static struct stateentry datastln1[] =
-{
- {SBIT(0),
- MT_N1_INVALID, l3_1tr6_invalid},
- {SBIT(0),
- MT_N1_SETUP, l3_1tr6_setup},
- {SBIT(1),
- MT_N1_SETUP_ACK, l3_1tr6_setup_ack},
- {SBIT(1) | SBIT(2),
- MT_N1_CALL_SENT, l3_1tr6_call_sent},
- {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10),
- MT_N1_DISC, l3_1tr6_disc},
- {SBIT(2) | SBIT(3) | SBIT(4),
- MT_N1_ALERT, l3_1tr6_alert},
- {SBIT(2) | SBIT(3) | SBIT(4),
- MT_N1_CONN, l3_1tr6_connect},
- {SBIT(2),
- MT_N1_INFO, l3_1tr6_info_s2},
- {SBIT(8),
- MT_N1_CONN_ACK, l3_1tr6_connect_ack},
- {SBIT(10),
- MT_N1_INFO, l3_1tr6_info},
- {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) |
- SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17),
- MT_N1_REL, l3_1tr6_rel},
- {SBIT(19),
- MT_N1_REL, l3_1tr6_rel_ack},
- {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) |
- SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17),
- MT_N1_REL_ACK, l3_1tr6_invalid},
- {SBIT(19),
- MT_N1_REL_ACK, l3_1tr6_rel_ack}
-};
-
-static struct stateentry manstatelist[] =
-{
- {SBIT(2),
- DL_ESTABLISH | INDICATION, l3_1tr6_dl_reset},
- {ALL_STATES,
- DL_RELEASE | INDICATION, l3_1tr6_dl_release},
-};
-
-/* *INDENT-ON* */
-
-static void
-up1tr6(struct PStack *st, int pr, void *arg)
-{
- int i, mt, cr;
- struct l3_process *proc;
- struct sk_buff *skb = arg;
-
- switch (pr) {
- case (DL_DATA | INDICATION):
- case (DL_UNIT_DATA | INDICATION):
- break;
- case (DL_ESTABLISH | CONFIRM):
- case (DL_ESTABLISH | INDICATION):
- case (DL_RELEASE | INDICATION):
- case (DL_RELEASE | CONFIRM):
- l3_msg(st, pr, arg);
- return;
- break;
- }
- if (skb->len < 4) {
- if (st->l3.debug & L3_DEB_PROTERR) {
- l3_debug(st, "up1tr6 len only %d", skb->len);
- }
- dev_kfree_skb(skb);
- return;
- }
- if ((skb->data[0] & 0xfe) != PROTO_DIS_N0) {
- if (st->l3.debug & L3_DEB_PROTERR) {
- l3_debug(st, "up1tr6%sunexpected discriminator %x message len %d",
- (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
- skb->data[0], skb->len);
- }
- dev_kfree_skb(skb);
- return;
- }
- if (skb->data[1] != 1) {
- if (st->l3.debug & L3_DEB_PROTERR) {
- l3_debug(st, "up1tr6 CR len not 1");
- }
- dev_kfree_skb(skb);
- return;
- }
- cr = skb->data[2];
- mt = skb->data[3];
- if (skb->data[0] == PROTO_DIS_N0) {
- dev_kfree_skb(skb);
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "up1tr6%s N0 mt %x unhandled",
- (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", mt);
- }
- } else if (skb->data[0] == PROTO_DIS_N1) {
- if (!(proc = getl3proc(st, cr))) {
- if (mt == MT_N1_SETUP) {
- if (cr < 128) {
- if (!(proc = new_l3_process(st, cr))) {
- if (st->l3.debug & L3_DEB_PROTERR) {
- l3_debug(st, "up1tr6 no roc mem");
- }
- dev_kfree_skb(skb);
- return;
- }
- } else {
- dev_kfree_skb(skb);
- return;
- }
- } else if ((mt == MT_N1_REL) || (mt == MT_N1_REL_ACK) ||
- (mt == MT_N1_CANC_ACK) || (mt == MT_N1_CANC_REJ) ||
- (mt == MT_N1_REG_ACK) || (mt == MT_N1_REG_REJ) ||
- (mt == MT_N1_SUSP_ACK) || (mt == MT_N1_RES_REJ) ||
- (mt == MT_N1_INFO)) {
- dev_kfree_skb(skb);
- return;
- } else {
- if (!(proc = new_l3_process(st, cr))) {
- if (st->l3.debug & L3_DEB_PROTERR) {
- l3_debug(st, "up1tr6 no roc mem");
- }
- dev_kfree_skb(skb);
- return;
- }
- mt = MT_N1_INVALID;
- }
- }
- for (i = 0; i < ARRAY_SIZE(datastln1); i++)
- if ((mt == datastln1[i].primitive) &&
- ((1 << proc->state) & datastln1[i].state))
- break;
- if (i == ARRAY_SIZE(datastln1)) {
- dev_kfree_skb(skb);
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "up1tr6%sstate %d mt %x unhandled",
- (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
- proc->state, mt);
- }
- return;
- } else {
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "up1tr6%sstate %d mt %x",
- (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
- proc->state, mt);
- }
- datastln1[i].rout(proc, pr, skb);
- }
- }
-}
-
-static void
-down1tr6(struct PStack *st, int pr, void *arg)
-{
- int i, cr;
- struct l3_process *proc;
- struct Channel *chan;
-
- if ((DL_ESTABLISH | REQUEST) == pr) {
- l3_msg(st, pr, NULL);
- return;
- } else if ((CC_SETUP | REQUEST) == pr) {
- chan = arg;
- cr = newcallref();
- cr |= 0x80;
- if (!(proc = new_l3_process(st, cr))) {
- return;
- } else {
- proc->chan = chan;
- chan->proc = proc;
- memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm));
- proc->callref = cr;
- }
- } else {
- proc = arg;
- }
-
- for (i = 0; i < ARRAY_SIZE(downstl); i++)
- if ((pr == downstl[i].primitive) &&
- ((1 << proc->state) & downstl[i].state))
- break;
- if (i == ARRAY_SIZE(downstl)) {
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "down1tr6 state %d prim %d unhandled",
- proc->state, pr);
- }
- } else {
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "down1tr6 state %d prim %d",
- proc->state, pr);
- }
- downstl[i].rout(proc, pr, arg);
- }
-}
-
-static void
-man1tr6(struct PStack *st, int pr, void *arg)
-{
- int i;
- struct l3_process *proc = arg;
-
- if (!proc) {
- printk(KERN_ERR "HiSax man1tr6 without proc pr=%04x\n", pr);
- return;
- }
- for (i = 0; i < ARRAY_SIZE(manstatelist); i++)
- if ((pr == manstatelist[i].primitive) &&
- ((1 << proc->state) & manstatelist[i].state))
- break;
- if (i == ARRAY_SIZE(manstatelist)) {
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "cr %d man1tr6 state %d prim %d unhandled",
- proc->callref & 0x7f, proc->state, pr);
- }
- } else {
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "cr %d man1tr6 state %d prim %d",
- proc->callref & 0x7f, proc->state, pr);
- }
- manstatelist[i].rout(proc, pr, arg);
- }
-}
-
-void
-setstack_1tr6(struct PStack *st)
-{
- char tmp[64];
-
- st->lli.l4l3 = down1tr6;
- st->l2.l2l3 = up1tr6;
- st->l3.l3ml3 = man1tr6;
- st->l3.N303 = 0;
-
- strcpy(tmp, l3_1tr6_revision);
- printk(KERN_INFO "HiSax: 1TR6 Rev. %s\n", HiSax_getrev(tmp));
-}
diff --git a/drivers/isdn/hisax/l3_1tr6.h b/drivers/isdn/hisax/l3_1tr6.h
deleted file mode 100644
index 43215c00cada..000000000000
--- a/drivers/isdn/hisax/l3_1tr6.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/* $Id: l3_1tr6.h,v 2.2.6.2 2001/09/23 22:24:49 kai Exp $
- *
- * German 1TR6 D-channel protocol defines
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef l3_1tr6
-#define l3_1tr6
-
-#define PROTO_DIS_N0 0x40
-#define PROTO_DIS_N1 0x41
-
-/*
- * MsgType N0
- */
-#define MT_N0_REG_IND 0x61
-#define MT_N0_CANC_IND 0x62
-#define MT_N0_FAC_STA 0x63
-#define MT_N0_STA_ACK 0x64
-#define MT_N0_STA_REJ 0x65
-#define MT_N0_FAC_INF 0x66
-#define MT_N0_INF_ACK 0x67
-#define MT_N0_INF_REJ 0x68
-#define MT_N0_CLOSE 0x75
-#define MT_N0_CLO_ACK 0x77
-
-/*
- * MsgType N1
- */
-
-#define MT_N1_ESC 0x00
-#define MT_N1_ALERT 0x01
-#define MT_N1_CALL_SENT 0x02
-#define MT_N1_CONN 0x07
-#define MT_N1_CONN_ACK 0x0F
-#define MT_N1_SETUP 0x05
-#define MT_N1_SETUP_ACK 0x0D
-#define MT_N1_RES 0x26
-#define MT_N1_RES_ACK 0x2E
-#define MT_N1_RES_REJ 0x22
-#define MT_N1_SUSP 0x25
-#define MT_N1_SUSP_ACK 0x2D
-#define MT_N1_SUSP_REJ 0x21
-#define MT_N1_USER_INFO 0x20
-#define MT_N1_DET 0x40
-#define MT_N1_DISC 0x45
-#define MT_N1_REL 0x4D
-#define MT_N1_REL_ACK 0x5A
-#define MT_N1_CANC_ACK 0x6E
-#define MT_N1_CANC_REJ 0x67
-#define MT_N1_CON_CON 0x69
-#define MT_N1_FAC 0x60
-#define MT_N1_FAC_ACK 0x68
-#define MT_N1_FAC_CAN 0x66
-#define MT_N1_FAC_REG 0x64
-#define MT_N1_FAC_REJ 0x65
-#define MT_N1_INFO 0x6D
-#define MT_N1_REG_ACK 0x6C
-#define MT_N1_REG_REJ 0x6F
-#define MT_N1_STAT 0x63
-#define MT_N1_INVALID 0
-
-/*
- * W Elemente
- */
-
-#define WE_Shift_F0 0x90
-#define WE_Shift_F6 0x96
-#define WE_Shift_OF0 0x98
-#define WE_Shift_OF6 0x9E
-
-#define WE0_cause 0x08
-#define WE0_connAddr 0x0C
-#define WE0_callID 0x10
-#define WE0_chanID 0x18
-#define WE0_netSpecFac 0x20
-#define WE0_display 0x28
-#define WE0_keypad 0x2C
-#define WE0_origAddr 0x6C
-#define WE0_destAddr 0x70
-#define WE0_userInfo 0x7E
-
-#define WE0_moreData 0xA0
-#define WE0_congestLevel 0xB0
-
-#define WE6_serviceInd 0x01
-#define WE6_chargingInfo 0x02
-#define WE6_date 0x03
-#define WE6_facSelect 0x05
-#define WE6_facStatus 0x06
-#define WE6_statusCalled 0x07
-#define WE6_addTransAttr 0x08
-
-/*
- * FacCodes
- */
-#define FAC_Sperre 0x01
-#define FAC_Sperre_All 0x02
-#define FAC_Sperre_Fern 0x03
-#define FAC_Sperre_Intl 0x04
-#define FAC_Sperre_Interk 0x05
-
-#define FAC_Forward1 0x02
-#define FAC_Forward2 0x03
-#define FAC_Konferenz 0x06
-#define FAC_GrabBchan 0x0F
-#define FAC_Reactivate 0x10
-#define FAC_Konferenz3 0x11
-#define FAC_Dienstwechsel1 0x12
-#define FAC_Dienstwechsel2 0x13
-#define FAC_NummernIdent 0x14
-#define FAC_GBG 0x15
-#define FAC_DisplayUebergeben 0x17
-#define FAC_DisplayUmgeleitet 0x1A
-#define FAC_Unterdruecke 0x1B
-#define FAC_Deactivate 0x1E
-#define FAC_Activate 0x1D
-#define FAC_SPV 0x1F
-#define FAC_Rueckwechsel 0x23
-#define FAC_Umleitung 0x24
-
-/*
- * Cause codes
- */
-#define CAUSE_InvCRef 0x01
-#define CAUSE_BearerNotImpl 0x03
-#define CAUSE_CIDunknown 0x07
-#define CAUSE_CIDinUse 0x08
-#define CAUSE_NoChans 0x0A
-#define CAUSE_FacNotImpl 0x10
-#define CAUSE_FacNotSubscr 0x11
-#define CAUSE_OutgoingBarred 0x20
-#define CAUSE_UserAccessBusy 0x21
-#define CAUSE_NegativeGBG 0x22
-#define CAUSE_UnknownGBG 0x23
-#define CAUSE_NoSPVknown 0x25
-#define CAUSE_DestNotObtain 0x35
-#define CAUSE_NumberChanged 0x38
-#define CAUSE_OutOfOrder 0x39
-#define CAUSE_NoUserResponse 0x3A
-#define CAUSE_UserBusy 0x3B
-#define CAUSE_IncomingBarred 0x3D
-#define CAUSE_CallRejected 0x3E
-#define CAUSE_NetworkCongestion 0x59
-#define CAUSE_RemoteUser 0x5A
-#define CAUSE_LocalProcErr 0x70
-#define CAUSE_RemoteProcErr 0x71
-#define CAUSE_RemoteUserSuspend 0x72
-#define CAUSE_RemoteUserResumed 0x73
-#define CAUSE_UserInfoDiscarded 0x7F
-
-#define T303 4000
-#define T304 20000
-#define T305 4000
-#define T308 4000
-#define T310 120000
-#define T313 4000
-#define T318 4000
-#define T319 4000
-
-#endif
diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c
deleted file mode 100644
index 368d152a8f1d..000000000000
--- a/drivers/isdn/hisax/l3dss1.c
+++ /dev/null
@@ -1,3227 +0,0 @@
-/* $Id: l3dss1.c,v 2.32.2.3 2004/01/13 14:31:25 keil Exp $
- *
- * EURO/DSS1 D-channel protocol
- *
- * German 1TR6 D-channel protocol
- *
- * Author Karsten Keil
- * based on the teles driver from Jan den Ouden
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * For changes and modifications please read
- * Documentation/isdn/HiSax.cert
- *
- * Thanks to Jan den Ouden
- * Fritz Elfert
- *
- */
-
-#include "hisax.h"
-#include "isdnl3.h"
-#include "l3dss1.h"
-#include <linux/ctype.h>
-#include <linux/slab.h>
-
-extern char *HiSax_getrev(const char *revision);
-static const char *dss1_revision = "$Revision: 2.32.2.3 $";
-
-#define EXT_BEARER_CAPS 1
-
-#define MsgHead(ptr, cref, mty) \
- *ptr++ = 0x8; \
- if (cref == -1) { \
- *ptr++ = 0x0; \
- } else { \
- *ptr++ = 0x1; \
- *ptr++ = cref^0x80; \
- } \
- *ptr++ = mty
-
-
-/**********************************************/
-/* get a new invoke id for remote operations. */
-/* Only a return value != 0 is valid */
-/**********************************************/
-static unsigned char new_invoke_id(struct PStack *p)
-{
- unsigned char retval;
- int i;
-
- i = 32; /* maximum search depth */
-
- retval = p->prot.dss1.last_invoke_id + 1; /* try new id */
- while ((i) && (p->prot.dss1.invoke_used[retval >> 3] == 0xFF)) {
- p->prot.dss1.last_invoke_id = (retval & 0xF8) + 8;
- i--;
- }
- if (i) {
- while (p->prot.dss1.invoke_used[retval >> 3] & (1 << (retval & 7)))
- retval++;
- } else
- retval = 0;
- p->prot.dss1.last_invoke_id = retval;
- p->prot.dss1.invoke_used[retval >> 3] |= (1 << (retval & 7));
- return (retval);
-} /* new_invoke_id */
-
-/*************************/
-/* free a used invoke id */
-/*************************/
-static void free_invoke_id(struct PStack *p, unsigned char id)
-{
-
- if (!id) return; /* 0 = invalid value */
-
- p->prot.dss1.invoke_used[id >> 3] &= ~(1 << (id & 7));
-} /* free_invoke_id */
-
-
-/**********************************************************/
-/* create a new l3 process and fill in dss1 specific data */
-/**********************************************************/
-static struct l3_process
-*dss1_new_l3_process(struct PStack *st, int cr)
-{ struct l3_process *proc;
-
- if (!(proc = new_l3_process(st, cr)))
- return (NULL);
-
- proc->prot.dss1.invoke_id = 0;
- proc->prot.dss1.remote_operation = 0;
- proc->prot.dss1.uus1_data[0] = '\0';
-
- return (proc);
-} /* dss1_new_l3_process */
-
-/************************************************/
-/* free a l3 process and all dss1 specific data */
-/************************************************/
-static void
-dss1_release_l3_process(struct l3_process *p)
-{
- free_invoke_id(p->st, p->prot.dss1.invoke_id);
- release_l3_process(p);
-} /* dss1_release_l3_process */
-
-/********************************************************/
-/* search a process with invoke id id and dummy callref */
-/********************************************************/
-static struct l3_process *
-l3dss1_search_dummy_proc(struct PStack *st, int id)
-{ struct l3_process *pc = st->l3.proc; /* start of processes */
-
- if (!id) return (NULL);
-
- while (pc)
- { if ((pc->callref == -1) && (pc->prot.dss1.invoke_id == id))
- return (pc);
- pc = pc->next;
- }
- return (NULL);
-} /* l3dss1_search_dummy_proc */
-
-/*******************************************************************/
-/* called when a facility message with a dummy callref is received */
-/* and a return result is delivered. id specifies the invoke id. */
-/*******************************************************************/
-static void
-l3dss1_dummy_return_result(struct PStack *st, int id, u_char *p, u_char nlen)
-{ isdn_ctrl ic;
- struct IsdnCardState *cs;
- struct l3_process *pc = NULL;
-
- if ((pc = l3dss1_search_dummy_proc(st, id)))
- { L3DelTimer(&pc->timer); /* remove timer */
-
- cs = pc->st->l1.hardware;
- ic.driver = cs->myid;
- ic.command = ISDN_STAT_PROT;
- ic.arg = DSS1_STAT_INVOKE_RES;
- ic.parm.dss1_io.hl_id = pc->prot.dss1.invoke_id;
- ic.parm.dss1_io.ll_id = pc->prot.dss1.ll_id;
- ic.parm.dss1_io.proc = pc->prot.dss1.proc;
- ic.parm.dss1_io.timeout = 0;
- ic.parm.dss1_io.datalen = nlen;
- ic.parm.dss1_io.data = p;
- free_invoke_id(pc->st, pc->prot.dss1.invoke_id);
- pc->prot.dss1.invoke_id = 0; /* reset id */
-
- cs->iif.statcallb(&ic);
- dss1_release_l3_process(pc);
- }
- else
- l3_debug(st, "dummy return result id=0x%x result len=%d", id, nlen);
-} /* l3dss1_dummy_return_result */
-
-/*******************************************************************/
-/* called when a facility message with a dummy callref is received */
-/* and a return error is delivered. id specifies the invoke id. */
-/*******************************************************************/
-static void
-l3dss1_dummy_error_return(struct PStack *st, int id, ulong error)
-{ isdn_ctrl ic;
- struct IsdnCardState *cs;
- struct l3_process *pc = NULL;
-
- if ((pc = l3dss1_search_dummy_proc(st, id)))
- { L3DelTimer(&pc->timer); /* remove timer */
-
- cs = pc->st->l1.hardware;
- ic.driver = cs->myid;
- ic.command = ISDN_STAT_PROT;
- ic.arg = DSS1_STAT_INVOKE_ERR;
- ic.parm.dss1_io.hl_id = pc->prot.dss1.invoke_id;
- ic.parm.dss1_io.ll_id = pc->prot.dss1.ll_id;
- ic.parm.dss1_io.proc = pc->prot.dss1.proc;
- ic.parm.dss1_io.timeout = error;
- ic.parm.dss1_io.datalen = 0;
- ic.parm.dss1_io.data = NULL;
- free_invoke_id(pc->st, pc->prot.dss1.invoke_id);
- pc->prot.dss1.invoke_id = 0; /* reset id */
-
- cs->iif.statcallb(&ic);
- dss1_release_l3_process(pc);
- }
- else
- l3_debug(st, "dummy return error id=0x%x error=0x%lx", id, error);
-} /* l3dss1_error_return */
-
-/*******************************************************************/
-/* called when a facility message with a dummy callref is received */
-/* and a invoke is delivered. id specifies the invoke id. */
-/*******************************************************************/
-static void
-l3dss1_dummy_invoke(struct PStack *st, int cr, int id,
- int ident, u_char *p, u_char nlen)
-{ isdn_ctrl ic;
- struct IsdnCardState *cs;
-
- l3_debug(st, "dummy invoke %s id=0x%x ident=0x%x datalen=%d",
- (cr == -1) ? "local" : "broadcast", id, ident, nlen);
- if (cr >= -1) return; /* ignore local data */
-
- cs = st->l1.hardware;
- ic.driver = cs->myid;
- ic.command = ISDN_STAT_PROT;
- ic.arg = DSS1_STAT_INVOKE_BRD;
- ic.parm.dss1_io.hl_id = id;
- ic.parm.dss1_io.ll_id = 0;
- ic.parm.dss1_io.proc = ident;
- ic.parm.dss1_io.timeout = 0;
- ic.parm.dss1_io.datalen = nlen;
- ic.parm.dss1_io.data = p;
-
- cs->iif.statcallb(&ic);
-} /* l3dss1_dummy_invoke */
-
-static void
-l3dss1_parse_facility(struct PStack *st, struct l3_process *pc,
- int cr, u_char *p)
-{
- int qd_len = 0;
- unsigned char nlen = 0, ilen, cp_tag;
- int ident, id;
- ulong err_ret;
-
- if (pc)
- st = pc->st; /* valid Stack */
- else
- if ((!st) || (cr >= 0)) return; /* neither pc nor st specified */
-
- p++;
- qd_len = *p++;
- if (qd_len == 0) {
- l3_debug(st, "qd_len == 0");
- return;
- }
- if ((*p & 0x1F) != 0x11) { /* Service discriminator, supplementary service */
- l3_debug(st, "supplementary service != 0x11");
- return;
- }
- while (qd_len > 0 && !(*p & 0x80)) { /* extension ? */
- p++;
- qd_len--;
- }
- if (qd_len < 2) {
- l3_debug(st, "qd_len < 2");
- return;
- }
- p++;
- qd_len--;
- if ((*p & 0xE0) != 0xA0) { /* class and form */
- l3_debug(st, "class and form != 0xA0");
- return;
- }
-
- cp_tag = *p & 0x1F; /* remember tag value */
-
- p++;
- qd_len--;
- if (qd_len < 1)
- { l3_debug(st, "qd_len < 1");
- return;
- }
- if (*p & 0x80)
- { /* length format indefinite or limited */
- nlen = *p++ & 0x7F; /* number of len bytes or indefinite */
- if ((qd_len-- < ((!nlen) ? 3 : (1 + nlen))) ||
- (nlen > 1))
- { l3_debug(st, "length format error or not implemented");
- return;
- }
- if (nlen == 1)
- { nlen = *p++; /* complete length */
- qd_len--;
- }
- else
- { qd_len -= 2; /* trailing null bytes */
- if ((*(p + qd_len)) || (*(p + qd_len + 1)))
- { l3_debug(st, "length format indefinite error");
- return;
- }
- nlen = qd_len;
- }
- }
- else
- { nlen = *p++;
- qd_len--;
- }
- if (qd_len < nlen)
- { l3_debug(st, "qd_len < nlen");
- return;
- }
- qd_len -= nlen;
-
- if (nlen < 2)
- { l3_debug(st, "nlen < 2");
- return;
- }
- if (*p != 0x02)
- { /* invoke identifier tag */
- l3_debug(st, "invoke identifier tag !=0x02");
- return;
- }
- p++;
- nlen--;
- if (*p & 0x80)
- { /* length format */
- l3_debug(st, "invoke id length format 2");
- return;
- }
- ilen = *p++;
- nlen--;
- if (ilen > nlen || ilen == 0)
- { l3_debug(st, "ilen > nlen || ilen == 0");
- return;
- }
- nlen -= ilen;
- id = 0;
- while (ilen > 0)
- { id = (id << 8) | (*p++ & 0xFF); /* invoke identifier */
- ilen--;
- }
-
- switch (cp_tag) { /* component tag */
- case 1: /* invoke */
- if (nlen < 2) {
- l3_debug(st, "nlen < 2 22");
- return;
- }
- if (*p != 0x02) { /* operation value */
- l3_debug(st, "operation value !=0x02");
- return;
- }
- p++;
- nlen--;
- ilen = *p++;
- nlen--;
- if (ilen > nlen || ilen == 0) {
- l3_debug(st, "ilen > nlen || ilen == 0 22");
- return;
- }
- nlen -= ilen;
- ident = 0;
- while (ilen > 0) {
- ident = (ident << 8) | (*p++ & 0xFF);
- ilen--;
- }
-
- if (!pc)
- { l3dss1_dummy_invoke(st, cr, id, ident, p, nlen);
- return;
- }
-#ifdef CONFIG_DE_AOC
- {
-
-#define FOO1(s, a, b) \
- while (nlen > 1) { \
- int ilen = p[1]; \
- if (nlen < ilen + 2) { \
- l3_debug(st, "FOO1 nlen < ilen+2"); \
- return; \
- } \
- nlen -= ilen + 2; \
- if ((*p & 0xFF) == (a)) { \
- int nlen = ilen; \
- p += 2; \
- b; \
- } else { \
- p += ilen + 2; \
- } \
- }
-
- switch (ident) {
- case 0x22: /* during */
- FOO1("1A", 0x30, FOO1("1C", 0xA1, FOO1("1D", 0x30, FOO1("1E", 0x02, ( {
- ident = 0;
- nlen = (nlen) ? nlen : 0; /* Make gcc happy */
- while (ilen > 0) {
- ident = (ident << 8) | *p++;
- ilen--;
- }
- if (ident > pc->para.chargeinfo) {
- pc->para.chargeinfo = ident;
- st->l3.l3l4(st, CC_CHARGE | INDICATION, pc);
- }
- if (st->l3.debug & L3_DEB_CHARGE) {
- if (*(p + 2) == 0) {
- l3_debug(st, "charging info during %d", pc->para.chargeinfo);
- }
- else {
- l3_debug(st, "charging info final %d", pc->para.chargeinfo);
- }
- }
- }
- )))))
- break;
- case 0x24: /* final */
- FOO1("2A", 0x30, FOO1("2B", 0x30, FOO1("2C", 0xA1, FOO1("2D", 0x30, FOO1("2E", 0x02, ( {
- ident = 0;
- nlen = (nlen) ? nlen : 0; /* Make gcc happy */
- while (ilen > 0) {
- ident = (ident << 8) | *p++;
- ilen--;
- }
- if (ident > pc->para.chargeinfo) {
- pc->para.chargeinfo = ident;
- st->l3.l3l4(st, CC_CHARGE | INDICATION, pc);
- }
- if (st->l3.debug & L3_DEB_CHARGE) {
- l3_debug(st, "charging info final %d", pc->para.chargeinfo);
- }
- }
- ))))))
- break;
- default:
- l3_debug(st, "invoke break invalid ident %02x", ident);
- break;
- }
-#undef FOO1
-
- }
-#else /* not CONFIG_DE_AOC */
- l3_debug(st, "invoke break");
-#endif /* not CONFIG_DE_AOC */
- break;
- case 2: /* return result */
- /* if no process available handle separately */
- if (!pc)
- { if (cr == -1)
- l3dss1_dummy_return_result(st, id, p, nlen);
- return;
- }
- if ((pc->prot.dss1.invoke_id) && (pc->prot.dss1.invoke_id == id))
- { /* Diversion successful */
- free_invoke_id(st, pc->prot.dss1.invoke_id);
- pc->prot.dss1.remote_result = 0; /* success */
- pc->prot.dss1.invoke_id = 0;
- pc->redir_result = pc->prot.dss1.remote_result;
- st->l3.l3l4(st, CC_REDIR | INDICATION, pc); } /* Diversion successful */
- else
- l3_debug(st, "return error unknown identifier");
- break;
- case 3: /* return error */
- err_ret = 0;
- if (nlen < 2)
- { l3_debug(st, "return error nlen < 2");
- return;
- }
- if (*p != 0x02)
- { /* result tag */
- l3_debug(st, "invoke error tag !=0x02");
- return;
- }
- p++;
- nlen--;
- if (*p > 4)
- { /* length format */
- l3_debug(st, "invoke return errlen > 4 ");
- return;
- }
- ilen = *p++;
- nlen--;
- if (ilen > nlen || ilen == 0)
- { l3_debug(st, "error return ilen > nlen || ilen == 0");
- return;
- }
- nlen -= ilen;
- while (ilen > 0)
- { err_ret = (err_ret << 8) | (*p++ & 0xFF); /* error value */
- ilen--;
- }
- /* if no process available handle separately */
- if (!pc)
- { if (cr == -1)
- l3dss1_dummy_error_return(st, id, err_ret);
- return;
- }
- if ((pc->prot.dss1.invoke_id) && (pc->prot.dss1.invoke_id == id))
- { /* Deflection error */
- free_invoke_id(st, pc->prot.dss1.invoke_id);
- pc->prot.dss1.remote_result = err_ret; /* result */
- pc->prot.dss1.invoke_id = 0;
- pc->redir_result = pc->prot.dss1.remote_result;
- st->l3.l3l4(st, CC_REDIR | INDICATION, pc);
- } /* Deflection error */
- else
- l3_debug(st, "return result unknown identifier");
- break;
- default:
- l3_debug(st, "facility default break tag=0x%02x", cp_tag);
- break;
- }
-}
-
-static void
-l3dss1_message(struct l3_process *pc, u_char mt)
-{
- struct sk_buff *skb;
- u_char *p;
-
- if (!(skb = l3_alloc_skb(4)))
- return;
- p = skb_put(skb, 4);
- MsgHead(p, pc->callref, mt);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
-}
-
-static void
-l3dss1_message_cause(struct l3_process *pc, u_char mt, u_char cause)
-{
- struct sk_buff *skb;
- u_char tmp[16];
- u_char *p = tmp;
- int l;
-
- MsgHead(p, pc->callref, mt);
- *p++ = IE_CAUSE;
- *p++ = 0x2;
- *p++ = 0x80;
- *p++ = cause | 0x80;
-
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- skb_put_data(skb, tmp, l);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
-}
-
-static void
-l3dss1_status_send(struct l3_process *pc, u_char pr, void *arg)
-{
- u_char tmp[16];
- u_char *p = tmp;
- int l;
- struct sk_buff *skb;
-
- MsgHead(p, pc->callref, MT_STATUS);
-
- *p++ = IE_CAUSE;
- *p++ = 0x2;
- *p++ = 0x80;
- *p++ = pc->para.cause | 0x80;
-
- *p++ = IE_CALL_STATE;
- *p++ = 0x1;
- *p++ = pc->state & 0x3f;
-
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- skb_put_data(skb, tmp, l);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
-}
-
-static void
-l3dss1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg)
-{
- /* This routine is called if here was no SETUP made (checks in dss1up and in
- * l3dss1_setup) and a RELEASE_COMPLETE have to be sent with an error code
- * MT_STATUS_ENQUIRE in the NULL state is handled too
- */
- u_char tmp[16];
- u_char *p = tmp;
- int l;
- struct sk_buff *skb;
-
- switch (pc->para.cause) {
- case 81: /* invalid callreference */
- case 88: /* incomp destination */
- case 96: /* mandory IE missing */
- case 100: /* invalid IE contents */
- case 101: /* incompatible Callstate */
- MsgHead(p, pc->callref, MT_RELEASE_COMPLETE);
- *p++ = IE_CAUSE;
- *p++ = 0x2;
- *p++ = 0x80;
- *p++ = pc->para.cause | 0x80;
- break;
- default:
- printk(KERN_ERR "HiSax l3dss1_msg_without_setup wrong cause %d\n",
- pc->para.cause);
- return;
- }
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- skb_put_data(skb, tmp, l);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
- dss1_release_l3_process(pc);
-}
-
-static int ie_ALERTING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
- IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_HLC,
- IE_USER_USER, -1};
-static int ie_CALL_PROCEEDING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
- IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_HLC, -1};
-static int ie_CONNECT[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
- IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_DATE, IE_SIGNAL,
- IE_CONNECT_PN, IE_CONNECT_SUB, IE_LLC, IE_HLC, IE_USER_USER, -1};
-static int ie_CONNECT_ACKNOWLEDGE[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_SIGNAL, -1};
-static int ie_DISCONNECT[] = {IE_CAUSE | IE_MANDATORY, IE_FACILITY,
- IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1};
-static int ie_INFORMATION[] = {IE_COMPLETE, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL,
- IE_CALLED_PN, -1};
-static int ie_NOTIFY[] = {IE_BEARER, IE_NOTIFY | IE_MANDATORY, IE_DISPLAY, -1};
-static int ie_PROGRESS[] = {IE_BEARER, IE_CAUSE, IE_FACILITY, IE_PROGRESS |
- IE_MANDATORY, IE_DISPLAY, IE_HLC, IE_USER_USER, -1};
-static int ie_RELEASE[] = {IE_CAUSE | IE_MANDATORY_1, IE_FACILITY, IE_DISPLAY,
- IE_SIGNAL, IE_USER_USER, -1};
-/* a RELEASE_COMPLETE with errors don't require special actions
- static int ie_RELEASE_COMPLETE[] = {IE_CAUSE | IE_MANDATORY_1, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1};
-*/
-static int ie_RESUME_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY,
- IE_DISPLAY, -1};
-static int ie_RESUME_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
-static int ie_SETUP[] = {IE_COMPLETE, IE_BEARER | IE_MANDATORY,
- IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY, IE_PROGRESS,
- IE_NET_FAC, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, IE_CALLING_PN,
- IE_CALLING_SUB, IE_CALLED_PN, IE_CALLED_SUB, IE_REDIR_NR,
- IE_LLC, IE_HLC, IE_USER_USER, -1};
-static int ie_SETUP_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY,
- IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, -1};
-static int ie_STATUS[] = {IE_CAUSE | IE_MANDATORY, IE_CALL_STATE |
- IE_MANDATORY, IE_DISPLAY, -1};
-static int ie_STATUS_ENQUIRY[] = {IE_DISPLAY, -1};
-static int ie_SUSPEND_ACKNOWLEDGE[] = {IE_DISPLAY, IE_FACILITY, -1};
-static int ie_SUSPEND_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
-/* not used
- * static int ie_CONGESTION_CONTROL[] = {IE_CONGESTION | IE_MANDATORY,
- * IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
- * static int ie_USER_INFORMATION[] = {IE_MORE_DATA, IE_USER_USER | IE_MANDATORY, -1};
- * static int ie_RESTART[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_RESTART_IND |
- * IE_MANDATORY, -1};
- */
-static int ie_FACILITY[] = {IE_FACILITY | IE_MANDATORY, IE_DISPLAY, -1};
-static int comp_required[] = {1, 2, 3, 5, 6, 7, 9, 10, 11, 14, 15, -1};
-static int l3_valid_states[] = {0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 15, 17, 19, 25, -1};
-
-struct ie_len {
- int ie;
- int len;
-};
-
-static
-struct ie_len max_ie_len[] = {
- {IE_SEGMENT, 4},
- {IE_BEARER, 12},
- {IE_CAUSE, 32},
- {IE_CALL_ID, 10},
- {IE_CALL_STATE, 3},
- {IE_CHANNEL_ID, 34},
- {IE_FACILITY, 255},
- {IE_PROGRESS, 4},
- {IE_NET_FAC, 255},
- {IE_NOTIFY, 3},
- {IE_DISPLAY, 82},
- {IE_DATE, 8},
- {IE_KEYPAD, 34},
- {IE_SIGNAL, 3},
- {IE_INFORATE, 6},
- {IE_E2E_TDELAY, 11},
- {IE_TDELAY_SEL, 5},
- {IE_PACK_BINPARA, 3},
- {IE_PACK_WINSIZE, 4},
- {IE_PACK_SIZE, 4},
- {IE_CUG, 7},
- {IE_REV_CHARGE, 3},
- {IE_CALLING_PN, 24},
- {IE_CALLING_SUB, 23},
- {IE_CALLED_PN, 24},
- {IE_CALLED_SUB, 23},
- {IE_REDIR_NR, 255},
- {IE_TRANS_SEL, 255},
- {IE_RESTART_IND, 3},
- {IE_LLC, 18},
- {IE_HLC, 5},
- {IE_USER_USER, 131},
- {-1, 0},
-};
-
-static int
-getmax_ie_len(u_char ie) {
- int i = 0;
- while (max_ie_len[i].ie != -1) {
- if (max_ie_len[i].ie == ie)
- return (max_ie_len[i].len);
- i++;
- }
- return (255);
-}
-
-static int
-ie_in_set(struct l3_process *pc, u_char ie, int *checklist) {
- int ret = 1;
-
- while (*checklist != -1) {
- if ((*checklist & 0xff) == ie) {
- if (ie & 0x80)
- return (-ret);
- else
- return (ret);
- }
- ret++;
- checklist++;
- }
- return (0);
-}
-
-static int
-check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist)
-{
- int *cl = checklist;
- u_char mt;
- u_char *p, ie;
- int l, newpos, oldpos;
- int err_seq = 0, err_len = 0, err_compr = 0, err_ureg = 0;
- u_char codeset = 0;
- u_char old_codeset = 0;
- u_char codelock = 1;
-
- p = skb->data;
- /* skip cr */
- p++;
- l = (*p++) & 0xf;
- p += l;
- mt = *p++;
- oldpos = 0;
- while ((p - skb->data) < skb->len) {
- if ((*p & 0xf0) == 0x90) { /* shift codeset */
- old_codeset = codeset;
- codeset = *p & 7;
- if (*p & 0x08)
- codelock = 0;
- else
- codelock = 1;
- if (pc->debug & L3_DEB_CHECK)
- l3_debug(pc->st, "check IE shift%scodeset %d->%d",
- codelock ? " locking " : " ", old_codeset, codeset);
- p++;
- continue;
- }
- if (!codeset) { /* only codeset 0 */
- if ((newpos = ie_in_set(pc, *p, cl))) {
- if (newpos > 0) {
- if (newpos < oldpos)
- err_seq++;
- else
- oldpos = newpos;
- }
- } else {
- if (ie_in_set(pc, *p, comp_required))
- err_compr++;
- else
- err_ureg++;
- }
- }
- ie = *p++;
- if (ie & 0x80) {
- l = 1;
- } else {
- l = *p++;
- p += l;
- l += 2;
- }
- if (!codeset && (l > getmax_ie_len(ie)))
- err_len++;
- if (!codelock) {
- if (pc->debug & L3_DEB_CHECK)
- l3_debug(pc->st, "check IE shift back codeset %d->%d",
- codeset, old_codeset);
- codeset = old_codeset;
- codelock = 1;
- }
- }
- if (err_compr | err_ureg | err_len | err_seq) {
- if (pc->debug & L3_DEB_CHECK)
- l3_debug(pc->st, "check IE MT(%x) %d/%d/%d/%d",
- mt, err_compr, err_ureg, err_len, err_seq);
- if (err_compr)
- return (ERR_IE_COMPREHENSION);
- if (err_ureg)
- return (ERR_IE_UNRECOGNIZED);
- if (err_len)
- return (ERR_IE_LENGTH);
- if (err_seq)
- return (ERR_IE_SEQUENCE);
- }
- return (0);
-}
-
-/* verify if a message type exists and contain no IE error */
-static int
-l3dss1_check_messagetype_validity(struct l3_process *pc, int mt, void *arg)
-{
- switch (mt) {
- case MT_ALERTING:
- case MT_CALL_PROCEEDING:
- case MT_CONNECT:
- case MT_CONNECT_ACKNOWLEDGE:
- case MT_DISCONNECT:
- case MT_INFORMATION:
- case MT_FACILITY:
- case MT_NOTIFY:
- case MT_PROGRESS:
- case MT_RELEASE:
- case MT_RELEASE_COMPLETE:
- case MT_SETUP:
- case MT_SETUP_ACKNOWLEDGE:
- case MT_RESUME_ACKNOWLEDGE:
- case MT_RESUME_REJECT:
- case MT_SUSPEND_ACKNOWLEDGE:
- case MT_SUSPEND_REJECT:
- case MT_USER_INFORMATION:
- case MT_RESTART:
- case MT_RESTART_ACKNOWLEDGE:
- case MT_CONGESTION_CONTROL:
- case MT_STATUS:
- case MT_STATUS_ENQUIRY:
- if (pc->debug & L3_DEB_CHECK)
- l3_debug(pc->st, "l3dss1_check_messagetype_validity mt(%x) OK", mt);
- break;
- case MT_RESUME: /* RESUME only in user->net */
- case MT_SUSPEND: /* SUSPEND only in user->net */
- default:
- if (pc->debug & (L3_DEB_CHECK | L3_DEB_WARN))
- l3_debug(pc->st, "l3dss1_check_messagetype_validity mt(%x) fail", mt);
- pc->para.cause = 97;
- l3dss1_status_send(pc, 0, NULL);
- return (1);
- }
- return (0);
-}
-
-static void
-l3dss1_std_ie_err(struct l3_process *pc, int ret) {
-
- if (pc->debug & L3_DEB_CHECK)
- l3_debug(pc->st, "check_infoelements ret %d", ret);
- switch (ret) {
- case 0:
- break;
- case ERR_IE_COMPREHENSION:
- pc->para.cause = 96;
- l3dss1_status_send(pc, 0, NULL);
- break;
- case ERR_IE_UNRECOGNIZED:
- pc->para.cause = 99;
- l3dss1_status_send(pc, 0, NULL);
- break;
- case ERR_IE_LENGTH:
- pc->para.cause = 100;
- l3dss1_status_send(pc, 0, NULL);
- break;
- case ERR_IE_SEQUENCE:
- default:
- break;
- }
-}
-
-static int
-l3dss1_get_channel_id(struct l3_process *pc, struct sk_buff *skb) {
- u_char *p;
-
- p = skb->data;
- if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) {
- p++;
- if (*p != 1) { /* len for BRI = 1 */
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "wrong chid len %d", *p);
- return (-2);
- }
- p++;
- if (*p & 0x60) { /* only base rate interface */
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "wrong chid %x", *p);
- return (-3);
- }
- return (*p & 0x3);
- } else
- return (-1);
-}
-
-static int
-l3dss1_get_cause(struct l3_process *pc, struct sk_buff *skb) {
- u_char l, i = 0;
- u_char *p;
-
- p = skb->data;
- pc->para.cause = 31;
- pc->para.loc = 0;
- if ((p = findie(p, skb->len, IE_CAUSE, 0))) {
- p++;
- l = *p++;
- if (l > 30)
- return (1);
- if (l) {
- pc->para.loc = *p++;
- l--;
- } else {
- return (2);
- }
- if (l && !(pc->para.loc & 0x80)) {
- l--;
- p++; /* skip recommendation */
- }
- if (l) {
- pc->para.cause = *p++;
- l--;
- if (!(pc->para.cause & 0x80))
- return (3);
- } else
- return (4);
- while (l && (i < 6)) {
- pc->para.diag[i++] = *p++;
- l--;
- }
- } else
- return (-1);
- return (0);
-}
-
-static void
-l3dss1_msg_with_uus(struct l3_process *pc, u_char cmd)
-{
- struct sk_buff *skb;
- u_char tmp[16 + 40];
- u_char *p = tmp;
- int l;
-
- MsgHead(p, pc->callref, cmd);
-
- if (pc->prot.dss1.uus1_data[0])
- { *p++ = IE_USER_USER; /* UUS info element */
- *p++ = strlen(pc->prot.dss1.uus1_data) + 1;
- *p++ = 0x04; /* IA5 chars */
- strcpy(p, pc->prot.dss1.uus1_data);
- p += strlen(pc->prot.dss1.uus1_data);
- pc->prot.dss1.uus1_data[0] = '\0';
- }
-
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- skb_put_data(skb, tmp, l);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
-} /* l3dss1_msg_with_uus */
-
-static void
-l3dss1_release_req(struct l3_process *pc, u_char pr, void *arg)
-{
- StopAllL3Timer(pc);
- newl3state(pc, 19);
- if (!pc->prot.dss1.uus1_data[0])
- l3dss1_message(pc, MT_RELEASE);
- else
- l3dss1_msg_with_uus(pc, MT_RELEASE);
- L3AddTimer(&pc->timer, T308, CC_T308_1);
-}
-
-static void
-l3dss1_release_cmpl(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- int ret;
-
- if ((ret = l3dss1_get_cause(pc, skb)) > 0) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "RELCMPL get_cause ret(%d)", ret);
- } else if (ret < 0)
- pc->para.cause = NO_CAUSE;
- StopAllL3Timer(pc);
- newl3state(pc, 0);
- pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc);
- dss1_release_l3_process(pc);
-}
-
-#ifdef EXT_BEARER_CAPS
-
-static u_char *
-EncodeASyncParams(u_char *p, u_char si2)
-{ // 7c 06 88 90 21 42 00 bb
-
- p[0] = 0;
- p[1] = 0x40; // Intermediate rate: 16 kbit/s jj 2000.02.19
- p[2] = 0x80;
- if (si2 & 32) // 7 data bits
-
- p[2] += 16;
- else // 8 data bits
-
- p[2] += 24;
-
- if (si2 & 16) // 2 stop bits
-
- p[2] += 96;
- else // 1 stop bit
-
- p[2] += 32;
-
- if (si2 & 8) // even parity
-
- p[2] += 2;
- else // no parity
-
- p[2] += 3;
-
- switch (si2 & 0x07) {
- case 0:
- p[0] = 66; // 1200 bit/s
-
- break;
- case 1:
- p[0] = 88; // 1200/75 bit/s
-
- break;
- case 2:
- p[0] = 87; // 75/1200 bit/s
-
- break;
- case 3:
- p[0] = 67; // 2400 bit/s
-
- break;
- case 4:
- p[0] = 69; // 4800 bit/s
-
- break;
- case 5:
- p[0] = 72; // 9600 bit/s
-
- break;
- case 6:
- p[0] = 73; // 14400 bit/s
-
- break;
- case 7:
- p[0] = 75; // 19200 bit/s
-
- break;
- }
- return p + 3;
-}
-
-static u_char
-EncodeSyncParams(u_char si2, u_char ai)
-{
-
- switch (si2) {
- case 0:
- return ai + 2; // 1200 bit/s
-
- case 1:
- return ai + 24; // 1200/75 bit/s
-
- case 2:
- return ai + 23; // 75/1200 bit/s
-
- case 3:
- return ai + 3; // 2400 bit/s
-
- case 4:
- return ai + 5; // 4800 bit/s
-
- case 5:
- return ai + 8; // 9600 bit/s
-
- case 6:
- return ai + 9; // 14400 bit/s
-
- case 7:
- return ai + 11; // 19200 bit/s
-
- case 8:
- return ai + 14; // 48000 bit/s
-
- case 9:
- return ai + 15; // 56000 bit/s
-
- case 15:
- return ai + 40; // negotiate bit/s
-
- default:
- break;
- }
- return ai;
-}
-
-
-static u_char
-DecodeASyncParams(u_char si2, u_char *p)
-{
- u_char info;
-
- switch (p[5]) {
- case 66: // 1200 bit/s
-
- break; // si2 don't change
-
- case 88: // 1200/75 bit/s
-
- si2 += 1;
- break;
- case 87: // 75/1200 bit/s
-
- si2 += 2;
- break;
- case 67: // 2400 bit/s
-
- si2 += 3;
- break;
- case 69: // 4800 bit/s
-
- si2 += 4;
- break;
- case 72: // 9600 bit/s
-
- si2 += 5;
- break;
- case 73: // 14400 bit/s
-
- si2 += 6;
- break;
- case 75: // 19200 bit/s
-
- si2 += 7;
- break;
- }
-
- info = p[7] & 0x7f;
- if ((info & 16) && (!(info & 8))) // 7 data bits
-
- si2 += 32; // else 8 data bits
-
- if ((info & 96) == 96) // 2 stop bits
-
- si2 += 16; // else 1 stop bit
-
- if ((info & 2) && (!(info & 1))) // even parity
-
- si2 += 8; // else no parity
-
- return si2;
-}
-
-
-static u_char
-DecodeSyncParams(u_char si2, u_char info)
-{
- info &= 0x7f;
- switch (info) {
- case 40: // bit/s negotiation failed ai := 165 not 175!
-
- return si2 + 15;
- case 15: // 56000 bit/s failed, ai := 0 not 169 !
-
- return si2 + 9;
- case 14: // 48000 bit/s
-
- return si2 + 8;
- case 11: // 19200 bit/s
-
- return si2 + 7;
- case 9: // 14400 bit/s
-
- return si2 + 6;
- case 8: // 9600 bit/s
-
- return si2 + 5;
- case 5: // 4800 bit/s
-
- return si2 + 4;
- case 3: // 2400 bit/s
-
- return si2 + 3;
- case 23: // 75/1200 bit/s
-
- return si2 + 2;
- case 24: // 1200/75 bit/s
-
- return si2 + 1;
- default: // 1200 bit/s
-
- return si2;
- }
-}
-
-static u_char
-DecodeSI2(struct sk_buff *skb)
-{
- u_char *p; //, *pend=skb->data + skb->len;
-
- if ((p = findie(skb->data, skb->len, 0x7c, 0))) {
- switch (p[4] & 0x0f) {
- case 0x01:
- if (p[1] == 0x04) // sync. Bitratenadaption
-
- return DecodeSyncParams(160, p[5]); // V.110/X.30
-
- else if (p[1] == 0x06) // async. Bitratenadaption
-
- return DecodeASyncParams(192, p); // V.110/X.30
-
- break;
- case 0x08: // if (p[5] == 0x02) // sync. Bitratenadaption
- if (p[1] > 3)
- return DecodeSyncParams(176, p[5]); // V.120
- break;
- }
- }
- return 0;
-}
-
-#endif
-
-
-static void
-l3dss1_setup_req(struct l3_process *pc, u_char pr,
- void *arg)
-{
- struct sk_buff *skb;
- u_char tmp[128];
- u_char *p = tmp;
- u_char channel = 0;
-
- u_char send_keypad;
- u_char screen = 0x80;
- u_char *teln;
- u_char *msn;
- u_char *sub;
- u_char *sp;
- int l;
-
- MsgHead(p, pc->callref, MT_SETUP);
-
- teln = pc->para.setup.phone;
-#ifndef CONFIG_HISAX_NO_KEYPAD
- send_keypad = (strchr(teln, '*') || strchr(teln, '#')) ? 1 : 0;
-#else
- send_keypad = 0;
-#endif
-#ifndef CONFIG_HISAX_NO_SENDCOMPLETE
- if (!send_keypad)
- *p++ = 0xa1; /* complete indicator */
-#endif
- /*
- * Set Bearer Capability, Map info from 1TR6-convention to EDSS1
- */
- switch (pc->para.setup.si1) {
- case 1: /* Telephony */
- *p++ = IE_BEARER;
- *p++ = 0x3; /* Length */
- *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */
- *p++ = 0x90; /* Circuit-Mode 64kbps */
- *p++ = 0xa3; /* A-Law Audio */
- break;
- case 5: /* Datatransmission 64k, BTX */
- case 7: /* Datatransmission 64k */
- default:
- *p++ = IE_BEARER;
- *p++ = 0x2; /* Length */
- *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */
- *p++ = 0x90; /* Circuit-Mode 64kbps */
- break;
- }
-
- if (send_keypad) {
- *p++ = IE_KEYPAD;
- *p++ = strlen(teln);
- while (*teln)
- *p++ = (*teln++) & 0x7F;
- }
-
- /*
- * What about info2? Mapping to High-Layer-Compatibility?
- */
- if ((*teln) && (!send_keypad)) {
- /* parse number for special things */
- if (!isdigit(*teln)) {
- switch (0x5f & *teln) {
- case 'C':
- channel = 0x08;
- /* fall through */
- case 'P':
- channel |= 0x80;
- teln++;
- if (*teln == '1')
- channel |= 0x01;
- else
- channel |= 0x02;
- break;
- case 'R':
- screen = 0xA0;
- break;
- case 'D':
- screen = 0x80;
- break;
-
- default:
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "Wrong MSN Code");
- break;
- }
- teln++;
- }
- }
- if (channel) {
- *p++ = IE_CHANNEL_ID;
- *p++ = 1;
- *p++ = channel;
- }
- msn = pc->para.setup.eazmsn;
- sub = NULL;
- sp = msn;
- while (*sp) {
- if ('.' == *sp) {
- sub = sp;
- *sp = 0;
- } else
- sp++;
- }
- if (*msn) {
- *p++ = IE_CALLING_PN;
- *p++ = strlen(msn) + (screen ? 2 : 1);
- /* Classify as AnyPref. */
- if (screen) {
- *p++ = 0x01; /* Ext = '0'B, Type = '000'B, Plan = '0001'B. */
- *p++ = screen;
- } else
- *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
- while (*msn)
- *p++ = *msn++ & 0x7f;
- }
- if (sub) {
- *sub++ = '.';
- *p++ = IE_CALLING_SUB;
- *p++ = strlen(sub) + 2;
- *p++ = 0x80; /* NSAP coded */
- *p++ = 0x50; /* local IDI format */
- while (*sub)
- *p++ = *sub++ & 0x7f;
- }
- sub = NULL;
- sp = teln;
- while (*sp) {
- if ('.' == *sp) {
- sub = sp;
- *sp = 0;
- } else
- sp++;
- }
-
- if (!send_keypad) {
- *p++ = IE_CALLED_PN;
- *p++ = strlen(teln) + 1;
- /* Classify as AnyPref. */
- *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
- while (*teln)
- *p++ = *teln++ & 0x7f;
-
- if (sub) {
- *sub++ = '.';
- *p++ = IE_CALLED_SUB;
- *p++ = strlen(sub) + 2;
- *p++ = 0x80; /* NSAP coded */
- *p++ = 0x50; /* local IDI format */
- while (*sub)
- *p++ = *sub++ & 0x7f;
- }
- }
-#ifdef EXT_BEARER_CAPS
- if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) { // sync. Bitratenadaption, V.110/X.30
-
- *p++ = IE_LLC;
- *p++ = 0x04;
- *p++ = 0x88;
- *p++ = 0x90;
- *p++ = 0x21;
- *p++ = EncodeSyncParams(pc->para.setup.si2 - 160, 0x80);
- } else if ((pc->para.setup.si2 >= 176) && (pc->para.setup.si2 <= 191)) { // sync. Bitratenadaption, V.120
-
- *p++ = IE_LLC;
- *p++ = 0x05;
- *p++ = 0x88;
- *p++ = 0x90;
- *p++ = 0x28;
- *p++ = EncodeSyncParams(pc->para.setup.si2 - 176, 0);
- *p++ = 0x82;
- } else if (pc->para.setup.si2 >= 192) { // async. Bitratenadaption, V.110/X.30
-
- *p++ = IE_LLC;
- *p++ = 0x06;
- *p++ = 0x88;
- *p++ = 0x90;
- *p++ = 0x21;
- p = EncodeASyncParams(p, pc->para.setup.si2 - 192);
-#ifndef CONFIG_HISAX_NO_LLC
- } else {
- switch (pc->para.setup.si1) {
- case 1: /* Telephony */
- *p++ = IE_LLC;
- *p++ = 0x3; /* Length */
- *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */
- *p++ = 0x90; /* Circuit-Mode 64kbps */
- *p++ = 0xa3; /* A-Law Audio */
- break;
- case 5: /* Datatransmission 64k, BTX */
- case 7: /* Datatransmission 64k */
- default:
- *p++ = IE_LLC;
- *p++ = 0x2; /* Length */
- *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */
- *p++ = 0x90; /* Circuit-Mode 64kbps */
- break;
- }
-#endif
- }
-#endif
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- skb_put_data(skb, tmp, l);
- L3DelTimer(&pc->timer);
- L3AddTimer(&pc->timer, T303, CC_T303);
- newl3state(pc, 1);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
-}
-
-static void
-l3dss1_call_proc(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- int id, ret;
-
- if ((id = l3dss1_get_channel_id(pc, skb)) >= 0) {
- if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "setup answer with wrong chid %x", id);
- pc->para.cause = 100;
- l3dss1_status_send(pc, pr, NULL);
- return;
- }
- pc->para.bchannel = id;
- } else if (1 == pc->state) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "setup answer wrong chid (ret %d)", id);
- if (id == -1)
- pc->para.cause = 96;
- else
- pc->para.cause = 100;
- l3dss1_status_send(pc, pr, NULL);
- return;
- }
- /* Now we are on none mandatory IEs */
- ret = check_infoelements(pc, skb, ie_CALL_PROCEEDING);
- if (ERR_IE_COMPREHENSION == ret) {
- l3dss1_std_ie_err(pc, ret);
- return;
- }
- L3DelTimer(&pc->timer);
- newl3state(pc, 3);
- L3AddTimer(&pc->timer, T310, CC_T310);
- if (ret) /* STATUS for none mandatory IE errors after actions are taken */
- l3dss1_std_ie_err(pc, ret);
- pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc);
-}
-
-static void
-l3dss1_setup_ack(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- int id, ret;
-
- if ((id = l3dss1_get_channel_id(pc, skb)) >= 0) {
- if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "setup answer with wrong chid %x", id);
- pc->para.cause = 100;
- l3dss1_status_send(pc, pr, NULL);
- return;
- }
- pc->para.bchannel = id;
- } else {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "setup answer wrong chid (ret %d)", id);
- if (id == -1)
- pc->para.cause = 96;
- else
- pc->para.cause = 100;
- l3dss1_status_send(pc, pr, NULL);
- return;
- }
- /* Now we are on none mandatory IEs */
- ret = check_infoelements(pc, skb, ie_SETUP_ACKNOWLEDGE);
- if (ERR_IE_COMPREHENSION == ret) {
- l3dss1_std_ie_err(pc, ret);
- return;
- }
- L3DelTimer(&pc->timer);
- newl3state(pc, 2);
- L3AddTimer(&pc->timer, T304, CC_T304);
- if (ret) /* STATUS for none mandatory IE errors after actions are taken */
- l3dss1_std_ie_err(pc, ret);
- pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
-}
-
-static void
-l3dss1_disconnect(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- u_char *p;
- int ret;
- u_char cause = 0;
-
- StopAllL3Timer(pc);
- if ((ret = l3dss1_get_cause(pc, skb))) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "DISC get_cause ret(%d)", ret);
- if (ret < 0)
- cause = 96;
- else if (ret > 0)
- cause = 100;
- }
- if ((p = findie(skb->data, skb->len, IE_FACILITY, 0)))
- l3dss1_parse_facility(pc->st, pc, pc->callref, p);
- ret = check_infoelements(pc, skb, ie_DISCONNECT);
- if (ERR_IE_COMPREHENSION == ret)
- cause = 96;
- else if ((!cause) && (ERR_IE_UNRECOGNIZED == ret))
- cause = 99;
- ret = pc->state;
- newl3state(pc, 12);
- if (cause)
- newl3state(pc, 19);
- if (11 != ret)
- pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc);
- else if (!cause)
- l3dss1_release_req(pc, pr, NULL);
- if (cause) {
- l3dss1_message_cause(pc, MT_RELEASE, cause);
- L3AddTimer(&pc->timer, T308, CC_T308_1);
- }
-}
-
-static void
-l3dss1_connect(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- int ret;
-
- ret = check_infoelements(pc, skb, ie_CONNECT);
- if (ERR_IE_COMPREHENSION == ret) {
- l3dss1_std_ie_err(pc, ret);
- return;
- }
- L3DelTimer(&pc->timer); /* T310 */
- newl3state(pc, 10);
- pc->para.chargeinfo = 0;
- /* here should inserted COLP handling KKe */
- if (ret)
- l3dss1_std_ie_err(pc, ret);
- pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc);
-}
-
-static void
-l3dss1_alerting(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- int ret;
-
- ret = check_infoelements(pc, skb, ie_ALERTING);
- if (ERR_IE_COMPREHENSION == ret) {
- l3dss1_std_ie_err(pc, ret);
- return;
- }
- L3DelTimer(&pc->timer); /* T304 */
- newl3state(pc, 4);
- if (ret)
- l3dss1_std_ie_err(pc, ret);
- pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc);
-}
-
-static void
-l3dss1_setup(struct l3_process *pc, u_char pr, void *arg)
-{
- u_char *p;
- int bcfound = 0;
- char tmp[80];
- struct sk_buff *skb = arg;
- int id;
- int err = 0;
-
- /*
- * Bearer Capabilities
- */
- p = skb->data;
- /* only the first occurrence 'll be detected ! */
- if ((p = findie(p, skb->len, 0x04, 0))) {
- if ((p[1] < 2) || (p[1] > 11))
- err = 1;
- else {
- pc->para.setup.si2 = 0;
- switch (p[2] & 0x7f) {
- case 0x00: /* Speech */
- case 0x10: /* 3.1 Khz audio */
- pc->para.setup.si1 = 1;
- break;
- case 0x08: /* Unrestricted digital information */
- pc->para.setup.si1 = 7;
-/* JIM, 05.11.97 I wanna set service indicator 2 */
-#ifdef EXT_BEARER_CAPS
- pc->para.setup.si2 = DecodeSI2(skb);
-#endif
- break;
- case 0x09: /* Restricted digital information */
- pc->para.setup.si1 = 2;
- break;
- case 0x11:
- /* Unrestr. digital information with
- * tones/announcements ( or 7 kHz audio
- */
- pc->para.setup.si1 = 3;
- break;
- case 0x18: /* Video */
- pc->para.setup.si1 = 4;
- break;
- default:
- err = 2;
- break;
- }
- switch (p[3] & 0x7f) {
- case 0x40: /* packed mode */
- pc->para.setup.si1 = 8;
- break;
- case 0x10: /* 64 kbit */
- case 0x11: /* 2*64 kbit */
- case 0x13: /* 384 kbit */
- case 0x15: /* 1536 kbit */
- case 0x17: /* 1920 kbit */
- pc->para.moderate = p[3] & 0x7f;
- break;
- default:
- err = 3;
- break;
- }
- }
- if (pc->debug & L3_DEB_SI)
- l3_debug(pc->st, "SI=%d, AI=%d",
- pc->para.setup.si1, pc->para.setup.si2);
- if (err) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "setup with wrong bearer(l=%d:%x,%x)",
- p[1], p[2], p[3]);
- pc->para.cause = 100;
- l3dss1_msg_without_setup(pc, pr, NULL);
- return;
- }
- } else {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "setup without bearer capabilities");
- /* ETS 300-104 1.3.3 */
- pc->para.cause = 96;
- l3dss1_msg_without_setup(pc, pr, NULL);
- return;
- }
- /*
- * Channel Identification
- */
- if ((id = l3dss1_get_channel_id(pc, skb)) >= 0) {
- if ((pc->para.bchannel = id)) {
- if ((3 == id) && (0x10 == pc->para.moderate)) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "setup with wrong chid %x",
- id);
- pc->para.cause = 100;
- l3dss1_msg_without_setup(pc, pr, NULL);
- return;
- }
- bcfound++;
- } else
- { if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "setup without bchannel, call waiting");
- bcfound++;
- }
- } else {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "setup with wrong chid ret %d", id);
- if (id == -1)
- pc->para.cause = 96;
- else
- pc->para.cause = 100;
- l3dss1_msg_without_setup(pc, pr, NULL);
- return;
- }
- /* Now we are on none mandatory IEs */
- err = check_infoelements(pc, skb, ie_SETUP);
- if (ERR_IE_COMPREHENSION == err) {
- pc->para.cause = 96;
- l3dss1_msg_without_setup(pc, pr, NULL);
- return;
- }
- p = skb->data;
- if ((p = findie(p, skb->len, 0x70, 0)))
- iecpy(pc->para.setup.eazmsn, p, 1);
- else
- pc->para.setup.eazmsn[0] = 0;
-
- p = skb->data;
- if ((p = findie(p, skb->len, 0x71, 0))) {
- /* Called party subaddress */
- if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) {
- tmp[0] = '.';
- iecpy(&tmp[1], p, 2);
- strcat(pc->para.setup.eazmsn, tmp);
- } else if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "wrong called subaddress");
- }
- p = skb->data;
- if ((p = findie(p, skb->len, 0x6c, 0))) {
- pc->para.setup.plan = p[2];
- if (p[2] & 0x80) {
- iecpy(pc->para.setup.phone, p, 1);
- pc->para.setup.screen = 0;
- } else {
- iecpy(pc->para.setup.phone, p, 2);
- pc->para.setup.screen = p[3];
- }
- } else {
- pc->para.setup.phone[0] = 0;
- pc->para.setup.plan = 0;
- pc->para.setup.screen = 0;
- }
- p = skb->data;
- if ((p = findie(p, skb->len, 0x6d, 0))) {
- /* Calling party subaddress */
- if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) {
- tmp[0] = '.';
- iecpy(&tmp[1], p, 2);
- strcat(pc->para.setup.phone, tmp);
- } else if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "wrong calling subaddress");
- }
- newl3state(pc, 6);
- if (err) /* STATUS for none mandatory IE errors after actions are taken */
- l3dss1_std_ie_err(pc, err);
- pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc);
-}
-
-static void
-l3dss1_reset(struct l3_process *pc, u_char pr, void *arg)
-{
- dss1_release_l3_process(pc);
-}
-
-static void
-l3dss1_disconnect_req(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb;
- u_char tmp[16 + 40];
- u_char *p = tmp;
- int l;
- u_char cause = 16;
-
- if (pc->para.cause != NO_CAUSE)
- cause = pc->para.cause;
-
- StopAllL3Timer(pc);
-
- MsgHead(p, pc->callref, MT_DISCONNECT);
-
- *p++ = IE_CAUSE;
- *p++ = 0x2;
- *p++ = 0x80;
- *p++ = cause | 0x80;
-
- if (pc->prot.dss1.uus1_data[0])
- { *p++ = IE_USER_USER; /* UUS info element */
- *p++ = strlen(pc->prot.dss1.uus1_data) + 1;
- *p++ = 0x04; /* IA5 chars */
- strcpy(p, pc->prot.dss1.uus1_data);
- p += strlen(pc->prot.dss1.uus1_data);
- pc->prot.dss1.uus1_data[0] = '\0';
- }
-
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- skb_put_data(skb, tmp, l);
- newl3state(pc, 11);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
- L3AddTimer(&pc->timer, T305, CC_T305);
-}
-
-static void
-l3dss1_setup_rsp(struct l3_process *pc, u_char pr,
- void *arg)
-{
- if (!pc->para.bchannel)
- { if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "D-chan connect for waiting call");
- l3dss1_disconnect_req(pc, pr, arg);
- return;
- }
- newl3state(pc, 8);
- l3dss1_message(pc, MT_CONNECT);
- L3DelTimer(&pc->timer);
- L3AddTimer(&pc->timer, T313, CC_T313);
-}
-
-static void
-l3dss1_connect_ack(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- int ret;
-
- ret = check_infoelements(pc, skb, ie_CONNECT_ACKNOWLEDGE);
- if (ERR_IE_COMPREHENSION == ret) {
- l3dss1_std_ie_err(pc, ret);
- return;
- }
- newl3state(pc, 10);
- L3DelTimer(&pc->timer);
- if (ret)
- l3dss1_std_ie_err(pc, ret);
- pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
-}
-
-static void
-l3dss1_reject_req(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb;
- u_char tmp[16];
- u_char *p = tmp;
- int l;
- u_char cause = 21;
-
- if (pc->para.cause != NO_CAUSE)
- cause = pc->para.cause;
-
- MsgHead(p, pc->callref, MT_RELEASE_COMPLETE);
-
- *p++ = IE_CAUSE;
- *p++ = 0x2;
- *p++ = 0x80;
- *p++ = cause | 0x80;
-
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- skb_put_data(skb, tmp, l);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
- newl3state(pc, 0);
- dss1_release_l3_process(pc);
-}
-
-static void
-l3dss1_release(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- u_char *p;
- int ret, cause = 0;
-
- StopAllL3Timer(pc);
- if ((ret = l3dss1_get_cause(pc, skb)) > 0) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "REL get_cause ret(%d)", ret);
- } else if (ret < 0)
- pc->para.cause = NO_CAUSE;
- if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) {
- l3dss1_parse_facility(pc->st, pc, pc->callref, p);
- }
- if ((ret < 0) && (pc->state != 11))
- cause = 96;
- else if (ret > 0)
- cause = 100;
- ret = check_infoelements(pc, skb, ie_RELEASE);
- if (ERR_IE_COMPREHENSION == ret)
- cause = 96;
- else if ((ERR_IE_UNRECOGNIZED == ret) && (!cause))
- cause = 99;
- if (cause)
- l3dss1_message_cause(pc, MT_RELEASE_COMPLETE, cause);
- else
- l3dss1_message(pc, MT_RELEASE_COMPLETE);
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
- newl3state(pc, 0);
- dss1_release_l3_process(pc);
-}
-
-static void
-l3dss1_alert_req(struct l3_process *pc, u_char pr,
- void *arg)
-{
- newl3state(pc, 7);
- if (!pc->prot.dss1.uus1_data[0])
- l3dss1_message(pc, MT_ALERTING);
- else
- l3dss1_msg_with_uus(pc, MT_ALERTING);
-}
-
-static void
-l3dss1_proceed_req(struct l3_process *pc, u_char pr,
- void *arg)
-{
- newl3state(pc, 9);
- l3dss1_message(pc, MT_CALL_PROCEEDING);
- pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc);
-}
-
-static void
-l3dss1_setup_ack_req(struct l3_process *pc, u_char pr,
- void *arg)
-{
- newl3state(pc, 25);
- L3DelTimer(&pc->timer);
- L3AddTimer(&pc->timer, T302, CC_T302);
- l3dss1_message(pc, MT_SETUP_ACKNOWLEDGE);
-}
-
-/********************************************/
-/* deliver a incoming display message to HL */
-/********************************************/
-static void
-l3dss1_deliver_display(struct l3_process *pc, int pr, u_char *infp)
-{ u_char len;
- isdn_ctrl ic;
- struct IsdnCardState *cs;
- char *p;
-
- if (*infp++ != IE_DISPLAY) return;
- if ((len = *infp++) > 80) return; /* total length <= 82 */
- if (!pc->chan) return;
-
- p = ic.parm.display;
- while (len--)
- *p++ = *infp++;
- *p = '\0';
- ic.command = ISDN_STAT_DISPLAY;
- cs = pc->st->l1.hardware;
- ic.driver = cs->myid;
- ic.arg = pc->chan->chan;
- cs->iif.statcallb(&ic);
-} /* l3dss1_deliver_display */
-
-
-static void
-l3dss1_progress(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- int err = 0;
- u_char *p;
-
- if ((p = findie(skb->data, skb->len, IE_PROGRESS, 0))) {
- if (p[1] != 2) {
- err = 1;
- pc->para.cause = 100;
- } else if (!(p[2] & 0x70)) {
- switch (p[2]) {
- case 0x80:
- case 0x81:
- case 0x82:
- case 0x84:
- case 0x85:
- case 0x87:
- case 0x8a:
- switch (p[3]) {
- case 0x81:
- case 0x82:
- case 0x83:
- case 0x84:
- case 0x88:
- break;
- default:
- err = 2;
- pc->para.cause = 100;
- break;
- }
- break;
- default:
- err = 3;
- pc->para.cause = 100;
- break;
- }
- }
- } else {
- pc->para.cause = 96;
- err = 4;
- }
- if (err) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "progress error %d", err);
- l3dss1_status_send(pc, pr, NULL);
- return;
- }
- /* Now we are on none mandatory IEs */
- err = check_infoelements(pc, skb, ie_PROGRESS);
- if (err)
- l3dss1_std_ie_err(pc, err);
- if (ERR_IE_COMPREHENSION != err)
- pc->st->l3.l3l4(pc->st, CC_PROGRESS | INDICATION, pc);
-}
-
-static void
-l3dss1_notify(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- int err = 0;
- u_char *p;
-
- if ((p = findie(skb->data, skb->len, IE_NOTIFY, 0))) {
- if (p[1] != 1) {
- err = 1;
- pc->para.cause = 100;
- } else {
- switch (p[2]) {
- case 0x80:
- case 0x81:
- case 0x82:
- break;
- default:
- pc->para.cause = 100;
- err = 2;
- break;
- }
- }
- } else {
- pc->para.cause = 96;
- err = 3;
- }
- if (err) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "notify error %d", err);
- l3dss1_status_send(pc, pr, NULL);
- return;
- }
- /* Now we are on none mandatory IEs */
- err = check_infoelements(pc, skb, ie_NOTIFY);
- if (err)
- l3dss1_std_ie_err(pc, err);
- if (ERR_IE_COMPREHENSION != err)
- pc->st->l3.l3l4(pc->st, CC_NOTIFY | INDICATION, pc);
-}
-
-static void
-l3dss1_status_enq(struct l3_process *pc, u_char pr, void *arg)
-{
- int ret;
- struct sk_buff *skb = arg;
-
- ret = check_infoelements(pc, skb, ie_STATUS_ENQUIRY);
- l3dss1_std_ie_err(pc, ret);
- pc->para.cause = 30; /* response to STATUS_ENQUIRY */
- l3dss1_status_send(pc, pr, NULL);
-}
-
-static void
-l3dss1_information(struct l3_process *pc, u_char pr, void *arg)
-{
- int ret;
- struct sk_buff *skb = arg;
- u_char *p;
- char tmp[32];
-
- ret = check_infoelements(pc, skb, ie_INFORMATION);
- if (ret)
- l3dss1_std_ie_err(pc, ret);
- if (pc->state == 25) { /* overlap receiving */
- L3DelTimer(&pc->timer);
- p = skb->data;
- if ((p = findie(p, skb->len, 0x70, 0))) {
- iecpy(tmp, p, 1);
- strcat(pc->para.setup.eazmsn, tmp);
- pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
- }
- L3AddTimer(&pc->timer, T302, CC_T302);
- }
-}
-
-/******************************/
-/* handle deflection requests */
-/******************************/
-static void l3dss1_redir_req(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb;
- u_char tmp[128];
- u_char *p = tmp;
- u_char *subp;
- u_char len_phone = 0;
- u_char len_sub = 0;
- int l;
-
-
- strcpy(pc->prot.dss1.uus1_data, pc->chan->setup.eazmsn); /* copy uus element if available */
- if (!pc->chan->setup.phone[0])
- { pc->para.cause = -1;
- l3dss1_disconnect_req(pc, pr, arg); /* disconnect immediately */
- return;
- } /* only uus */
-
- if (pc->prot.dss1.invoke_id)
- free_invoke_id(pc->st, pc->prot.dss1.invoke_id);
-
- if (!(pc->prot.dss1.invoke_id = new_invoke_id(pc->st)))
- return;
-
- MsgHead(p, pc->callref, MT_FACILITY);
-
- for (subp = pc->chan->setup.phone; (*subp) && (*subp != '.'); subp++) len_phone++; /* len of phone number */
- if (*subp++ == '.') len_sub = strlen(subp) + 2; /* length including info subaddress element */
-
- *p++ = 0x1c; /* Facility info element */
- *p++ = len_phone + len_sub + 2 + 2 + 8 + 3 + 3; /* length of element */
- *p++ = 0x91; /* remote operations protocol */
- *p++ = 0xa1; /* invoke component */
-
- *p++ = len_phone + len_sub + 2 + 2 + 8 + 3; /* length of data */
- *p++ = 0x02; /* invoke id tag, integer */
- *p++ = 0x01; /* length */
- *p++ = pc->prot.dss1.invoke_id; /* invoke id */
- *p++ = 0x02; /* operation value tag, integer */
- *p++ = 0x01; /* length */
- *p++ = 0x0D; /* Call Deflect */
-
- *p++ = 0x30; /* sequence phone number */
- *p++ = len_phone + 2 + 2 + 3 + len_sub; /* length */
-
- *p++ = 0x30; /* Deflected to UserNumber */
- *p++ = len_phone + 2 + len_sub; /* length */
- *p++ = 0x80; /* NumberDigits */
- *p++ = len_phone; /* length */
- for (l = 0; l < len_phone; l++)
- *p++ = pc->chan->setup.phone[l];
-
- if (len_sub)
- { *p++ = 0x04; /* called party subaddress */
- *p++ = len_sub - 2;
- while (*subp) *p++ = *subp++;
- }
-
- *p++ = 0x01; /* screening identifier */
- *p++ = 0x01;
- *p++ = pc->chan->setup.screen;
-
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l))) return;
- skb_put_data(skb, tmp, l);
-
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
-} /* l3dss1_redir_req */
-
-/********************************************/
-/* handle deflection request in early state */
-/********************************************/
-static void l3dss1_redir_req_early(struct l3_process *pc, u_char pr, void *arg)
-{
- l3dss1_proceed_req(pc, pr, arg);
- l3dss1_redir_req(pc, pr, arg);
-} /* l3dss1_redir_req_early */
-
-/***********************************************/
-/* handle special commands for this protocol. */
-/* Examples are call independent services like */
-/* remote operations with dummy callref. */
-/***********************************************/
-static int l3dss1_cmd_global(struct PStack *st, isdn_ctrl *ic)
-{ u_char id;
- u_char temp[265];
- u_char *p = temp;
- int i, l, proc_len;
- struct sk_buff *skb;
- struct l3_process *pc = NULL;
-
- switch (ic->arg)
- { case DSS1_CMD_INVOKE:
- if (ic->parm.dss1_io.datalen < 0) return (-2); /* invalid parameter */
-
- for (proc_len = 1, i = ic->parm.dss1_io.proc >> 8; i; i++)
- i = i >> 8; /* add one byte */
- l = ic->parm.dss1_io.datalen + proc_len + 8; /* length excluding ie header */
- if (l > 255)
- return (-2); /* too long */
-
- if (!(id = new_invoke_id(st)))
- return (0); /* first get a invoke id -> return if no available */
-
- i = -1;
- MsgHead(p, i, MT_FACILITY); /* build message head */
- *p++ = 0x1C; /* Facility IE */
- *p++ = l; /* length of ie */
- *p++ = 0x91; /* remote operations */
- *p++ = 0xA1; /* invoke */
- *p++ = l - 3; /* length of invoke */
- *p++ = 0x02; /* invoke id tag */
- *p++ = 0x01; /* length is 1 */
- *p++ = id; /* invoke id */
- *p++ = 0x02; /* operation */
- *p++ = proc_len; /* length of operation */
-
- for (i = proc_len; i; i--)
- *p++ = (ic->parm.dss1_io.proc >> (i - 1)) & 0xFF;
- memcpy(p, ic->parm.dss1_io.data, ic->parm.dss1_io.datalen); /* copy data */
- l = (p - temp) + ic->parm.dss1_io.datalen; /* total length */
-
- if (ic->parm.dss1_io.timeout > 0)
- if (!(pc = dss1_new_l3_process(st, -1)))
- { free_invoke_id(st, id);
- return (-2);
- }
- pc->prot.dss1.ll_id = ic->parm.dss1_io.ll_id; /* remember id */
- pc->prot.dss1.proc = ic->parm.dss1_io.proc; /* and procedure */
-
- if (!(skb = l3_alloc_skb(l)))
- { free_invoke_id(st, id);
- if (pc) dss1_release_l3_process(pc);
- return (-2);
- }
- skb_put_data(skb, temp, l);
-
- if (pc)
- { pc->prot.dss1.invoke_id = id; /* remember id */
- L3AddTimer(&pc->timer, ic->parm.dss1_io.timeout, CC_TDSS1_IO | REQUEST);
- }
-
- l3_msg(st, DL_DATA | REQUEST, skb);
- ic->parm.dss1_io.hl_id = id; /* return id */
- return (0);
-
- case DSS1_CMD_INVOKE_ABORT:
- if ((pc = l3dss1_search_dummy_proc(st, ic->parm.dss1_io.hl_id)))
- { L3DelTimer(&pc->timer); /* remove timer */
- dss1_release_l3_process(pc);
- return (0);
- }
- else
- { l3_debug(st, "l3dss1_cmd_global abort unknown id");
- return (-2);
- }
- break;
-
- default:
- l3_debug(st, "l3dss1_cmd_global unknown cmd 0x%lx", ic->arg);
- return (-1);
- } /* switch ic-> arg */
- return (-1);
-} /* l3dss1_cmd_global */
-
-static void
-l3dss1_io_timer(struct l3_process *pc)
-{ isdn_ctrl ic;
- struct IsdnCardState *cs = pc->st->l1.hardware;
-
- L3DelTimer(&pc->timer); /* remove timer */
-
- ic.driver = cs->myid;
- ic.command = ISDN_STAT_PROT;
- ic.arg = DSS1_STAT_INVOKE_ERR;
- ic.parm.dss1_io.hl_id = pc->prot.dss1.invoke_id;
- ic.parm.dss1_io.ll_id = pc->prot.dss1.ll_id;
- ic.parm.dss1_io.proc = pc->prot.dss1.proc;
- ic.parm.dss1_io.timeout = -1;
- ic.parm.dss1_io.datalen = 0;
- ic.parm.dss1_io.data = NULL;
- free_invoke_id(pc->st, pc->prot.dss1.invoke_id);
- pc->prot.dss1.invoke_id = 0; /* reset id */
-
- cs->iif.statcallb(&ic);
-
- dss1_release_l3_process(pc);
-} /* l3dss1_io_timer */
-
-static void
-l3dss1_release_ind(struct l3_process *pc, u_char pr, void *arg)
-{
- u_char *p;
- struct sk_buff *skb = arg;
- int callState = 0;
- p = skb->data;
-
- if ((p = findie(p, skb->len, IE_CALL_STATE, 0))) {
- p++;
- if (1 == *p++)
- callState = *p;
- }
- if (callState == 0) {
- /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... and 16.1
- * set down layer 3 without sending any message
- */
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
- newl3state(pc, 0);
- dss1_release_l3_process(pc);
- } else {
- pc->st->l3.l3l4(pc->st, CC_IGNORE | INDICATION, pc);
- }
-}
-
-static void
-l3dss1_dummy(struct l3_process *pc, u_char pr, void *arg)
-{
-}
-
-static void
-l3dss1_t302(struct l3_process *pc, u_char pr, void *arg)
-{
- L3DelTimer(&pc->timer);
- pc->para.loc = 0;
- pc->para.cause = 28; /* invalid number */
- l3dss1_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
-}
-
-static void
-l3dss1_t303(struct l3_process *pc, u_char pr, void *arg)
-{
- if (pc->N303 > 0) {
- pc->N303--;
- L3DelTimer(&pc->timer);
- l3dss1_setup_req(pc, pr, arg);
- } else {
- L3DelTimer(&pc->timer);
- l3dss1_message_cause(pc, MT_RELEASE_COMPLETE, 102);
- pc->st->l3.l3l4(pc->st, CC_NOSETUP_RSP, pc);
- dss1_release_l3_process(pc);
- }
-}
-
-static void
-l3dss1_t304(struct l3_process *pc, u_char pr, void *arg)
-{
- L3DelTimer(&pc->timer);
- pc->para.loc = 0;
- pc->para.cause = 102;
- l3dss1_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
-
-}
-
-static void
-l3dss1_t305(struct l3_process *pc, u_char pr, void *arg)
-{
- u_char tmp[16];
- u_char *p = tmp;
- int l;
- struct sk_buff *skb;
- u_char cause = 16;
-
- L3DelTimer(&pc->timer);
- if (pc->para.cause != NO_CAUSE)
- cause = pc->para.cause;
-
- MsgHead(p, pc->callref, MT_RELEASE);
-
- *p++ = IE_CAUSE;
- *p++ = 0x2;
- *p++ = 0x80;
- *p++ = cause | 0x80;
-
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- skb_put_data(skb, tmp, l);
- newl3state(pc, 19);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
- L3AddTimer(&pc->timer, T308, CC_T308_1);
-}
-
-static void
-l3dss1_t310(struct l3_process *pc, u_char pr, void *arg)
-{
- L3DelTimer(&pc->timer);
- pc->para.loc = 0;
- pc->para.cause = 102;
- l3dss1_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
-}
-
-static void
-l3dss1_t313(struct l3_process *pc, u_char pr, void *arg)
-{
- L3DelTimer(&pc->timer);
- pc->para.loc = 0;
- pc->para.cause = 102;
- l3dss1_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc);
-}
-
-static void
-l3dss1_t308_1(struct l3_process *pc, u_char pr, void *arg)
-{
- newl3state(pc, 19);
- L3DelTimer(&pc->timer);
- l3dss1_message(pc, MT_RELEASE);
- L3AddTimer(&pc->timer, T308, CC_T308_2);
-}
-
-static void
-l3dss1_t308_2(struct l3_process *pc, u_char pr, void *arg)
-{
- L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc);
- dss1_release_l3_process(pc);
-}
-
-static void
-l3dss1_t318(struct l3_process *pc, u_char pr, void *arg)
-{
- L3DelTimer(&pc->timer);
- pc->para.cause = 102; /* Timer expiry */
- pc->para.loc = 0; /* local */
- pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc);
- newl3state(pc, 19);
- l3dss1_message(pc, MT_RELEASE);
- L3AddTimer(&pc->timer, T308, CC_T308_1);
-}
-
-static void
-l3dss1_t319(struct l3_process *pc, u_char pr, void *arg)
-{
- L3DelTimer(&pc->timer);
- pc->para.cause = 102; /* Timer expiry */
- pc->para.loc = 0; /* local */
- pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc);
- newl3state(pc, 10);
-}
-
-static void
-l3dss1_restart(struct l3_process *pc, u_char pr, void *arg)
-{
- L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
- dss1_release_l3_process(pc);
-}
-
-static void
-l3dss1_status(struct l3_process *pc, u_char pr, void *arg)
-{
- u_char *p;
- struct sk_buff *skb = arg;
- int ret;
- u_char cause = 0, callState = 0;
-
- if ((ret = l3dss1_get_cause(pc, skb))) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "STATUS get_cause ret(%d)", ret);
- if (ret < 0)
- cause = 96;
- else if (ret > 0)
- cause = 100;
- }
- if ((p = findie(skb->data, skb->len, IE_CALL_STATE, 0))) {
- p++;
- if (1 == *p++) {
- callState = *p;
- if (!ie_in_set(pc, *p, l3_valid_states))
- cause = 100;
- } else
- cause = 100;
- } else
- cause = 96;
- if (!cause) { /* no error before */
- ret = check_infoelements(pc, skb, ie_STATUS);
- if (ERR_IE_COMPREHENSION == ret)
- cause = 96;
- else if (ERR_IE_UNRECOGNIZED == ret)
- cause = 99;
- }
- if (cause) {
- u_char tmp;
-
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "STATUS error(%d/%d)", ret, cause);
- tmp = pc->para.cause;
- pc->para.cause = cause;
- l3dss1_status_send(pc, 0, NULL);
- if (cause == 99)
- pc->para.cause = tmp;
- else
- return;
- }
- cause = pc->para.cause;
- if (((cause & 0x7f) == 111) && (callState == 0)) {
- /* ETS 300-104 7.6.1, 8.6.1, 10.6.1...
- * if received MT_STATUS with cause == 111 and call
- * state == 0, then we must set down layer 3
- */
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
- newl3state(pc, 0);
- dss1_release_l3_process(pc);
- }
-}
-
-static void
-l3dss1_facility(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- int ret;
-
- ret = check_infoelements(pc, skb, ie_FACILITY);
- l3dss1_std_ie_err(pc, ret);
- {
- u_char *p;
- if ((p = findie(skb->data, skb->len, IE_FACILITY, 0)))
- l3dss1_parse_facility(pc->st, pc, pc->callref, p);
- }
-}
-
-static void
-l3dss1_suspend_req(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb;
- u_char tmp[32];
- u_char *p = tmp;
- u_char i, l;
- u_char *msg = pc->chan->setup.phone;
-
- MsgHead(p, pc->callref, MT_SUSPEND);
- l = *msg++;
- if (l && (l <= 10)) { /* Max length 10 octets */
- *p++ = IE_CALL_ID;
- *p++ = l;
- for (i = 0; i < l; i++)
- *p++ = *msg++;
- } else if (l) {
- l3_debug(pc->st, "SUS wrong CALL_ID len %d", l);
- return;
- }
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- skb_put_data(skb, tmp, l);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
- newl3state(pc, 15);
- L3AddTimer(&pc->timer, T319, CC_T319);
-}
-
-static void
-l3dss1_suspend_ack(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- int ret;
-
- L3DelTimer(&pc->timer);
- newl3state(pc, 0);
- pc->para.cause = NO_CAUSE;
- pc->st->l3.l3l4(pc->st, CC_SUSPEND | CONFIRM, pc);
- /* We don't handle suspend_ack for IE errors now */
- if ((ret = check_infoelements(pc, skb, ie_SUSPEND_ACKNOWLEDGE)))
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "SUSPACK check ie(%d)", ret);
- dss1_release_l3_process(pc);
-}
-
-static void
-l3dss1_suspend_rej(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- int ret;
-
- if ((ret = l3dss1_get_cause(pc, skb))) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "SUSP_REJ get_cause ret(%d)", ret);
- if (ret < 0)
- pc->para.cause = 96;
- else
- pc->para.cause = 100;
- l3dss1_status_send(pc, pr, NULL);
- return;
- }
- ret = check_infoelements(pc, skb, ie_SUSPEND_REJECT);
- if (ERR_IE_COMPREHENSION == ret) {
- l3dss1_std_ie_err(pc, ret);
- return;
- }
- L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc);
- newl3state(pc, 10);
- if (ret) /* STATUS for none mandatory IE errors after actions are taken */
- l3dss1_std_ie_err(pc, ret);
-}
-
-static void
-l3dss1_resume_req(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb;
- u_char tmp[32];
- u_char *p = tmp;
- u_char i, l;
- u_char *msg = pc->para.setup.phone;
-
- MsgHead(p, pc->callref, MT_RESUME);
-
- l = *msg++;
- if (l && (l <= 10)) { /* Max length 10 octets */
- *p++ = IE_CALL_ID;
- *p++ = l;
- for (i = 0; i < l; i++)
- *p++ = *msg++;
- } else if (l) {
- l3_debug(pc->st, "RES wrong CALL_ID len %d", l);
- return;
- }
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- skb_put_data(skb, tmp, l);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
- newl3state(pc, 17);
- L3AddTimer(&pc->timer, T318, CC_T318);
-}
-
-static void
-l3dss1_resume_ack(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- int id, ret;
-
- if ((id = l3dss1_get_channel_id(pc, skb)) > 0) {
- if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "resume ack with wrong chid %x", id);
- pc->para.cause = 100;
- l3dss1_status_send(pc, pr, NULL);
- return;
- }
- pc->para.bchannel = id;
- } else if (1 == pc->state) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "resume ack without chid (ret %d)", id);
- pc->para.cause = 96;
- l3dss1_status_send(pc, pr, NULL);
- return;
- }
- ret = check_infoelements(pc, skb, ie_RESUME_ACKNOWLEDGE);
- if (ERR_IE_COMPREHENSION == ret) {
- l3dss1_std_ie_err(pc, ret);
- return;
- }
- L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_RESUME | CONFIRM, pc);
- newl3state(pc, 10);
- if (ret) /* STATUS for none mandatory IE errors after actions are taken */
- l3dss1_std_ie_err(pc, ret);
-}
-
-static void
-l3dss1_resume_rej(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- int ret;
-
- if ((ret = l3dss1_get_cause(pc, skb))) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "RES_REJ get_cause ret(%d)", ret);
- if (ret < 0)
- pc->para.cause = 96;
- else
- pc->para.cause = 100;
- l3dss1_status_send(pc, pr, NULL);
- return;
- }
- ret = check_infoelements(pc, skb, ie_RESUME_REJECT);
- if (ERR_IE_COMPREHENSION == ret) {
- l3dss1_std_ie_err(pc, ret);
- return;
- }
- L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc);
- newl3state(pc, 0);
- if (ret) /* STATUS for none mandatory IE errors after actions are taken */
- l3dss1_std_ie_err(pc, ret);
- dss1_release_l3_process(pc);
-}
-
-static void
-l3dss1_global_restart(struct l3_process *pc, u_char pr, void *arg)
-{
- u_char tmp[32];
- u_char *p;
- u_char ri, ch = 0, chan = 0;
- int l;
- struct sk_buff *skb = arg;
- struct l3_process *up;
-
- newl3state(pc, 2);
- L3DelTimer(&pc->timer);
- p = skb->data;
- if ((p = findie(p, skb->len, IE_RESTART_IND, 0))) {
- ri = p[2];
- l3_debug(pc->st, "Restart %x", ri);
- } else {
- l3_debug(pc->st, "Restart without restart IE");
- ri = 0x86;
- }
- p = skb->data;
- if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) {
- chan = p[2] & 3;
- ch = p[2];
- if (pc->st->l3.debug)
- l3_debug(pc->st, "Restart for channel %d", chan);
- }
- newl3state(pc, 2);
- up = pc->st->l3.proc;
- while (up) {
- if ((ri & 7) == 7)
- up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up);
- else if (up->para.bchannel == chan)
- up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up);
- up = up->next;
- }
- p = tmp;
- MsgHead(p, pc->callref, MT_RESTART_ACKNOWLEDGE);
- if (chan) {
- *p++ = IE_CHANNEL_ID;
- *p++ = 1;
- *p++ = ch | 0x80;
- }
- *p++ = 0x79; /* RESTART Ind */
- *p++ = 1;
- *p++ = ri;
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- skb_put_data(skb, tmp, l);
- newl3state(pc, 0);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
-}
-
-static void
-l3dss1_dl_reset(struct l3_process *pc, u_char pr, void *arg)
-{
- pc->para.cause = 0x29; /* Temporary failure */
- pc->para.loc = 0;
- l3dss1_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
-}
-
-static void
-l3dss1_dl_release(struct l3_process *pc, u_char pr, void *arg)
-{
- newl3state(pc, 0);
- pc->para.cause = 0x1b; /* Destination out of order */
- pc->para.loc = 0;
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
- release_l3_process(pc);
-}
-
-static void
-l3dss1_dl_reestablish(struct l3_process *pc, u_char pr, void *arg)
-{
- L3DelTimer(&pc->timer);
- L3AddTimer(&pc->timer, T309, CC_T309);
- l3_msg(pc->st, DL_ESTABLISH | REQUEST, NULL);
-}
-
-static void
-l3dss1_dl_reest_status(struct l3_process *pc, u_char pr, void *arg)
-{
- L3DelTimer(&pc->timer);
-
- pc->para.cause = 0x1F; /* normal, unspecified */
- l3dss1_status_send(pc, 0, NULL);
-}
-
-/* *INDENT-OFF* */
-static struct stateentry downstatelist[] =
-{
- {SBIT(0),
- CC_SETUP | REQUEST, l3dss1_setup_req},
- {SBIT(0),
- CC_RESUME | REQUEST, l3dss1_resume_req},
- {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(25),
- CC_DISCONNECT | REQUEST, l3dss1_disconnect_req},
- {SBIT(12),
- CC_RELEASE | REQUEST, l3dss1_release_req},
- {ALL_STATES,
- CC_RESTART | REQUEST, l3dss1_restart},
- {SBIT(6) | SBIT(25),
- CC_IGNORE | REQUEST, l3dss1_reset},
- {SBIT(6) | SBIT(25),
- CC_REJECT | REQUEST, l3dss1_reject_req},
- {SBIT(6) | SBIT(25),
- CC_PROCEED_SEND | REQUEST, l3dss1_proceed_req},
- {SBIT(6),
- CC_MORE_INFO | REQUEST, l3dss1_setup_ack_req},
- {SBIT(25),
- CC_MORE_INFO | REQUEST, l3dss1_dummy},
- {SBIT(6) | SBIT(9) | SBIT(25),
- CC_ALERTING | REQUEST, l3dss1_alert_req},
- {SBIT(6) | SBIT(7) | SBIT(9) | SBIT(25),
- CC_SETUP | RESPONSE, l3dss1_setup_rsp},
- {SBIT(10),
- CC_SUSPEND | REQUEST, l3dss1_suspend_req},
- {SBIT(7) | SBIT(9) | SBIT(25),
- CC_REDIR | REQUEST, l3dss1_redir_req},
- {SBIT(6),
- CC_REDIR | REQUEST, l3dss1_redir_req_early},
- {SBIT(9) | SBIT(25),
- CC_DISCONNECT | REQUEST, l3dss1_disconnect_req},
- {SBIT(25),
- CC_T302, l3dss1_t302},
- {SBIT(1),
- CC_T303, l3dss1_t303},
- {SBIT(2),
- CC_T304, l3dss1_t304},
- {SBIT(3),
- CC_T310, l3dss1_t310},
- {SBIT(8),
- CC_T313, l3dss1_t313},
- {SBIT(11),
- CC_T305, l3dss1_t305},
- {SBIT(15),
- CC_T319, l3dss1_t319},
- {SBIT(17),
- CC_T318, l3dss1_t318},
- {SBIT(19),
- CC_T308_1, l3dss1_t308_1},
- {SBIT(19),
- CC_T308_2, l3dss1_t308_2},
- {SBIT(10),
- CC_T309, l3dss1_dl_release},
-};
-
-static struct stateentry datastatelist[] =
-{
- {ALL_STATES,
- MT_STATUS_ENQUIRY, l3dss1_status_enq},
- {ALL_STATES,
- MT_FACILITY, l3dss1_facility},
- {SBIT(19),
- MT_STATUS, l3dss1_release_ind},
- {ALL_STATES,
- MT_STATUS, l3dss1_status},
- {SBIT(0),
- MT_SETUP, l3dss1_setup},
- {SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) |
- SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25),
- MT_SETUP, l3dss1_dummy},
- {SBIT(1) | SBIT(2),
- MT_CALL_PROCEEDING, l3dss1_call_proc},
- {SBIT(1),
- MT_SETUP_ACKNOWLEDGE, l3dss1_setup_ack},
- {SBIT(2) | SBIT(3),
- MT_ALERTING, l3dss1_alerting},
- {SBIT(2) | SBIT(3),
- MT_PROGRESS, l3dss1_progress},
- {SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) |
- SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25),
- MT_INFORMATION, l3dss1_information},
- {SBIT(10) | SBIT(11) | SBIT(15),
- MT_NOTIFY, l3dss1_notify},
- {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10) |
- SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25),
- MT_RELEASE_COMPLETE, l3dss1_release_cmpl},
- {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(25),
- MT_RELEASE, l3dss1_release},
- {SBIT(19), MT_RELEASE, l3dss1_release_ind},
- {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(15) | SBIT(17) | SBIT(25),
- MT_DISCONNECT, l3dss1_disconnect},
- {SBIT(19),
- MT_DISCONNECT, l3dss1_dummy},
- {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4),
- MT_CONNECT, l3dss1_connect},
- {SBIT(8),
- MT_CONNECT_ACKNOWLEDGE, l3dss1_connect_ack},
- {SBIT(15),
- MT_SUSPEND_ACKNOWLEDGE, l3dss1_suspend_ack},
- {SBIT(15),
- MT_SUSPEND_REJECT, l3dss1_suspend_rej},
- {SBIT(17),
- MT_RESUME_ACKNOWLEDGE, l3dss1_resume_ack},
- {SBIT(17),
- MT_RESUME_REJECT, l3dss1_resume_rej},
-};
-
-static struct stateentry globalmes_list[] =
-{
- {ALL_STATES,
- MT_STATUS, l3dss1_status},
- {SBIT(0),
- MT_RESTART, l3dss1_global_restart},
-/* {SBIT(1),
- MT_RESTART_ACKNOWLEDGE, l3dss1_restart_ack},
-*/
-};
-
-static struct stateentry manstatelist[] =
-{
- {SBIT(2),
- DL_ESTABLISH | INDICATION, l3dss1_dl_reset},
- {SBIT(10),
- DL_ESTABLISH | CONFIRM, l3dss1_dl_reest_status},
- {SBIT(10),
- DL_RELEASE | INDICATION, l3dss1_dl_reestablish},
- {ALL_STATES,
- DL_RELEASE | INDICATION, l3dss1_dl_release},
-};
-
-/* *INDENT-ON* */
-
-
-static void
-global_handler(struct PStack *st, int mt, struct sk_buff *skb)
-{
- u_char tmp[16];
- u_char *p = tmp;
- int l;
- int i;
- struct l3_process *proc = st->l3.global;
-
- proc->callref = skb->data[2]; /* cr flag */
- for (i = 0; i < ARRAY_SIZE(globalmes_list); i++)
- if ((mt == globalmes_list[i].primitive) &&
- ((1 << proc->state) & globalmes_list[i].state))
- break;
- if (i == ARRAY_SIZE(globalmes_list)) {
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "dss1 global state %d mt %x unhandled",
- proc->state, mt);
- }
- MsgHead(p, proc->callref, MT_STATUS);
- *p++ = IE_CAUSE;
- *p++ = 0x2;
- *p++ = 0x80;
- *p++ = 81 | 0x80; /* invalid cr */
- *p++ = 0x14; /* CallState */
- *p++ = 0x1;
- *p++ = proc->state & 0x3f;
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- skb_put_data(skb, tmp, l);
- l3_msg(proc->st, DL_DATA | REQUEST, skb);
- } else {
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "dss1 global %d mt %x",
- proc->state, mt);
- }
- globalmes_list[i].rout(proc, mt, skb);
- }
-}
-
-static void
-dss1up(struct PStack *st, int pr, void *arg)
-{
- int i, mt, cr, callState;
- char *ptr;
- u_char *p;
- struct sk_buff *skb = arg;
- struct l3_process *proc;
-
- switch (pr) {
- case (DL_DATA | INDICATION):
- case (DL_UNIT_DATA | INDICATION):
- break;
- case (DL_ESTABLISH | CONFIRM):
- case (DL_ESTABLISH | INDICATION):
- case (DL_RELEASE | INDICATION):
- case (DL_RELEASE | CONFIRM):
- l3_msg(st, pr, arg);
- return;
- break;
- default:
- printk(KERN_ERR "HiSax dss1up unknown pr=%04x\n", pr);
- return;
- }
- if (skb->len < 3) {
- l3_debug(st, "dss1up frame too short(%d)", skb->len);
- dev_kfree_skb(skb);
- return;
- }
-
- if (skb->data[0] != PROTO_DIS_EURO) {
- if (st->l3.debug & L3_DEB_PROTERR) {
- l3_debug(st, "dss1up%sunexpected discriminator %x message len %d",
- (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
- skb->data[0], skb->len);
- }
- dev_kfree_skb(skb);
- return;
- }
- cr = getcallref(skb->data);
- if (skb->len < ((skb->data[1] & 0x0f) + 3)) {
- l3_debug(st, "dss1up frame too short(%d)", skb->len);
- dev_kfree_skb(skb);
- return;
- }
- mt = skb->data[skb->data[1] + 2];
- if (st->l3.debug & L3_DEB_STATE)
- l3_debug(st, "dss1up cr %d", cr);
- if (cr == -2) { /* wrong Callref */
- if (st->l3.debug & L3_DEB_WARN)
- l3_debug(st, "dss1up wrong Callref");
- dev_kfree_skb(skb);
- return;
- } else if (cr == -1) { /* Dummy Callref */
- if (mt == MT_FACILITY)
- if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) {
- l3dss1_parse_facility(st, NULL,
- (pr == (DL_DATA | INDICATION)) ? -1 : -2, p);
- dev_kfree_skb(skb);
- return;
- }
- if (st->l3.debug & L3_DEB_WARN)
- l3_debug(st, "dss1up dummy Callref (no facility msg or ie)");
- dev_kfree_skb(skb);
- return;
- } else if ((((skb->data[1] & 0x0f) == 1) && (0 == (cr & 0x7f))) ||
- (((skb->data[1] & 0x0f) == 2) && (0 == (cr & 0x7fff)))) { /* Global CallRef */
- if (st->l3.debug & L3_DEB_STATE)
- l3_debug(st, "dss1up Global CallRef");
- global_handler(st, mt, skb);
- dev_kfree_skb(skb);
- return;
- } else if (!(proc = getl3proc(st, cr))) {
- /* No transaction process exist, that means no call with
- * this callreference is active
- */
- if (mt == MT_SETUP) {
- /* Setup creates a new transaction process */
- if (skb->data[2] & 0x80) {
- /* Setup with wrong CREF flag */
- if (st->l3.debug & L3_DEB_STATE)
- l3_debug(st, "dss1up wrong CRef flag");
- dev_kfree_skb(skb);
- return;
- }
- if (!(proc = dss1_new_l3_process(st, cr))) {
- /* May be to answer with RELEASE_COMPLETE and
- * CAUSE 0x2f "Resource unavailable", but this
- * need a new_l3_process too ... arghh
- */
- dev_kfree_skb(skb);
- return;
- }
- } else if (mt == MT_STATUS) {
- if ((ptr = findie(skb->data, skb->len, IE_CAUSE, 0)) != NULL) {
- ptr++;
- if (*ptr++ == 2)
- ptr++;
- }
- callState = 0;
- if ((ptr = findie(skb->data, skb->len, IE_CALL_STATE, 0)) != NULL) {
- ptr++;
- if (*ptr++ == 2)
- ptr++;
- callState = *ptr;
- }
- /* ETS 300-104 part 2.4.1
- * if setup has not been made and a message type
- * MT_STATUS is received with call state == 0,
- * we must send nothing
- */
- if (callState != 0) {
- /* ETS 300-104 part 2.4.2
- * if setup has not been made and a message type
- * MT_STATUS is received with call state != 0,
- * we must send MT_RELEASE_COMPLETE cause 101
- */
- if ((proc = dss1_new_l3_process(st, cr))) {
- proc->para.cause = 101;
- l3dss1_msg_without_setup(proc, 0, NULL);
- }
- }
- dev_kfree_skb(skb);
- return;
- } else if (mt == MT_RELEASE_COMPLETE) {
- dev_kfree_skb(skb);
- return;
- } else {
- /* ETS 300-104 part 2
- * if setup has not been made and a message type
- * (except MT_SETUP and RELEASE_COMPLETE) is received,
- * we must send MT_RELEASE_COMPLETE cause 81 */
- dev_kfree_skb(skb);
- if ((proc = dss1_new_l3_process(st, cr))) {
- proc->para.cause = 81;
- l3dss1_msg_without_setup(proc, 0, NULL);
- }
- return;
- }
- }
- if (l3dss1_check_messagetype_validity(proc, mt, skb)) {
- dev_kfree_skb(skb);
- return;
- }
- if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL)
- l3dss1_deliver_display(proc, pr, p); /* Display IE included */
- for (i = 0; i < ARRAY_SIZE(datastatelist); i++)
- if ((mt == datastatelist[i].primitive) &&
- ((1 << proc->state) & datastatelist[i].state))
- break;
- if (i == ARRAY_SIZE(datastatelist)) {
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "dss1up%sstate %d mt %#x unhandled",
- (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
- proc->state, mt);
- }
- if ((MT_RELEASE_COMPLETE != mt) && (MT_RELEASE != mt)) {
- proc->para.cause = 101;
- l3dss1_status_send(proc, pr, skb);
- }
- } else {
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "dss1up%sstate %d mt %x",
- (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
- proc->state, mt);
- }
- datastatelist[i].rout(proc, pr, skb);
- }
- dev_kfree_skb(skb);
- return;
-}
-
-static void
-dss1down(struct PStack *st, int pr, void *arg)
-{
- int i, cr;
- struct l3_process *proc;
- struct Channel *chan;
-
- if ((DL_ESTABLISH | REQUEST) == pr) {
- l3_msg(st, pr, NULL);
- return;
- } else if (((CC_SETUP | REQUEST) == pr) || ((CC_RESUME | REQUEST) == pr)) {
- chan = arg;
- cr = newcallref();
- cr |= 0x80;
- if ((proc = dss1_new_l3_process(st, cr))) {
- proc->chan = chan;
- chan->proc = proc;
- memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm));
- proc->callref = cr;
- }
- } else {
- proc = arg;
- }
- if (!proc) {
- printk(KERN_ERR "HiSax dss1down without proc pr=%04x\n", pr);
- return;
- }
-
- if (pr == (CC_TDSS1_IO | REQUEST)) {
- l3dss1_io_timer(proc); /* timer expires */
- return;
- }
-
- for (i = 0; i < ARRAY_SIZE(downstatelist); i++)
- if ((pr == downstatelist[i].primitive) &&
- ((1 << proc->state) & downstatelist[i].state))
- break;
- if (i == ARRAY_SIZE(downstatelist)) {
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "dss1down state %d prim %#x unhandled",
- proc->state, pr);
- }
- } else {
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "dss1down state %d prim %#x",
- proc->state, pr);
- }
- downstatelist[i].rout(proc, pr, arg);
- }
-}
-
-static void
-dss1man(struct PStack *st, int pr, void *arg)
-{
- int i;
- struct l3_process *proc = arg;
-
- if (!proc) {
- printk(KERN_ERR "HiSax dss1man without proc pr=%04x\n", pr);
- return;
- }
- for (i = 0; i < ARRAY_SIZE(manstatelist); i++)
- if ((pr == manstatelist[i].primitive) &&
- ((1 << proc->state) & manstatelist[i].state))
- break;
- if (i == ARRAY_SIZE(manstatelist)) {
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "cr %d dss1man state %d prim %#x unhandled",
- proc->callref & 0x7f, proc->state, pr);
- }
- } else {
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "cr %d dss1man state %d prim %#x",
- proc->callref & 0x7f, proc->state, pr);
- }
- manstatelist[i].rout(proc, pr, arg);
- }
-}
-
-void
-setstack_dss1(struct PStack *st)
-{
- char tmp[64];
- int i;
-
- st->lli.l4l3 = dss1down;
- st->lli.l4l3_proto = l3dss1_cmd_global;
- st->l2.l2l3 = dss1up;
- st->l3.l3ml3 = dss1man;
- st->l3.N303 = 1;
- st->prot.dss1.last_invoke_id = 0;
- st->prot.dss1.invoke_used[0] = 1; /* Bit 0 must always be set to 1 */
- i = 1;
- while (i < 32)
- st->prot.dss1.invoke_used[i++] = 0;
-
- if (!(st->l3.global = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) {
- printk(KERN_ERR "HiSax can't get memory for dss1 global CR\n");
- } else {
- st->l3.global->state = 0;
- st->l3.global->callref = 0;
- st->l3.global->next = NULL;
- st->l3.global->debug = L3_DEB_WARN;
- st->l3.global->st = st;
- st->l3.global->N303 = 1;
- st->l3.global->prot.dss1.invoke_id = 0;
-
- L3InitTimer(st->l3.global, &st->l3.global->timer);
- }
- strcpy(tmp, dss1_revision);
- printk(KERN_INFO "HiSax: DSS1 Rev. %s\n", HiSax_getrev(tmp));
-}
diff --git a/drivers/isdn/hisax/l3dss1.h b/drivers/isdn/hisax/l3dss1.h
deleted file mode 100644
index a7807e8a94f1..000000000000
--- a/drivers/isdn/hisax/l3dss1.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/* $Id: l3dss1.h,v 1.10.6.2 2001/09/23 22:24:50 kai Exp $
- *
- * DSS1 (Euro) D-channel protocol defines
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef l3dss1_process
-
-#define T302 15000
-#define T303 4000
-#define T304 30000
-#define T305 30000
-#define T308 4000
-/* for layer 1 certification T309 < layer1 T3 (e.g. 4000) */
-/* This makes some tests easier and quicker */
-#define T309 40000
-#define T310 30000
-#define T313 4000
-#define T318 4000
-#define T319 4000
-
-/*
- * Message-Types
- */
-
-#define MT_ALERTING 0x01
-#define MT_CALL_PROCEEDING 0x02
-#define MT_CONNECT 0x07
-#define MT_CONNECT_ACKNOWLEDGE 0x0f
-#define MT_PROGRESS 0x03
-#define MT_SETUP 0x05
-#define MT_SETUP_ACKNOWLEDGE 0x0d
-#define MT_RESUME 0x26
-#define MT_RESUME_ACKNOWLEDGE 0x2e
-#define MT_RESUME_REJECT 0x22
-#define MT_SUSPEND 0x25
-#define MT_SUSPEND_ACKNOWLEDGE 0x2d
-#define MT_SUSPEND_REJECT 0x21
-#define MT_USER_INFORMATION 0x20
-#define MT_DISCONNECT 0x45
-#define MT_RELEASE 0x4d
-#define MT_RELEASE_COMPLETE 0x5a
-#define MT_RESTART 0x46
-#define MT_RESTART_ACKNOWLEDGE 0x4e
-#define MT_SEGMENT 0x60
-#define MT_CONGESTION_CONTROL 0x79
-#define MT_INFORMATION 0x7b
-#define MT_FACILITY 0x62
-#define MT_NOTIFY 0x6e
-#define MT_STATUS 0x7d
-#define MT_STATUS_ENQUIRY 0x75
-
-#define IE_SEGMENT 0x00
-#define IE_BEARER 0x04
-#define IE_CAUSE 0x08
-#define IE_CALL_ID 0x10
-#define IE_CALL_STATE 0x14
-#define IE_CHANNEL_ID 0x18
-#define IE_FACILITY 0x1c
-#define IE_PROGRESS 0x1e
-#define IE_NET_FAC 0x20
-#define IE_NOTIFY 0x27
-#define IE_DISPLAY 0x28
-#define IE_DATE 0x29
-#define IE_KEYPAD 0x2c
-#define IE_SIGNAL 0x34
-#define IE_INFORATE 0x40
-#define IE_E2E_TDELAY 0x42
-#define IE_TDELAY_SEL 0x43
-#define IE_PACK_BINPARA 0x44
-#define IE_PACK_WINSIZE 0x45
-#define IE_PACK_SIZE 0x46
-#define IE_CUG 0x47
-#define IE_REV_CHARGE 0x4a
-#define IE_CONNECT_PN 0x4c
-#define IE_CONNECT_SUB 0x4d
-#define IE_CALLING_PN 0x6c
-#define IE_CALLING_SUB 0x6d
-#define IE_CALLED_PN 0x70
-#define IE_CALLED_SUB 0x71
-#define IE_REDIR_NR 0x74
-#define IE_TRANS_SEL 0x78
-#define IE_RESTART_IND 0x79
-#define IE_LLC 0x7c
-#define IE_HLC 0x7d
-#define IE_USER_USER 0x7e
-#define IE_ESCAPE 0x7f
-#define IE_SHIFT 0x90
-#define IE_MORE_DATA 0xa0
-#define IE_COMPLETE 0xa1
-#define IE_CONGESTION 0xb0
-#define IE_REPEAT 0xd0
-
-#define IE_MANDATORY 0x0100
-/* mandatory not in every case */
-#define IE_MANDATORY_1 0x0200
-
-#define ERR_IE_COMPREHENSION 1
-#define ERR_IE_UNRECOGNIZED -1
-#define ERR_IE_LENGTH -2
-#define ERR_IE_SEQUENCE -3
-
-#else /* only l3dss1_process */
-
-/* l3dss1 specific data in l3 process */
-typedef struct
-{ unsigned char invoke_id; /* used invoke id in remote ops, 0 = not active */
- ulong ll_id; /* remebered ll id */
- u8 remote_operation; /* handled remote operation, 0 = not active */
- int proc; /* rememered procedure */
- ulong remote_result; /* result of remote operation for statcallb */
- char uus1_data[35]; /* data send during alerting or disconnect */
-} dss1_proc_priv;
-
-/* l3dss1 specific data in protocol stack */
-typedef struct
-{ unsigned char last_invoke_id; /* last used value for invoking */
- unsigned char invoke_used[32]; /* 256 bits for 256 values */
-} dss1_stk_priv;
-
-#endif /* only l3dss1_process */
diff --git a/drivers/isdn/hisax/l3ni1.c b/drivers/isdn/hisax/l3ni1.c
deleted file mode 100644
index ea311e7df48e..000000000000
--- a/drivers/isdn/hisax/l3ni1.c
+++ /dev/null
@@ -1,3182 +0,0 @@
-/* $Id: l3ni1.c,v 2.8.2.3 2004/01/13 14:31:25 keil Exp $
- *
- * NI1 D-channel protocol
- *
- * Author Matt Henderson & Guy Ellis
- * Copyright by Traverse Technologies Pty Ltd, www.travers.com.au
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * 2000.6.6 Initial implementation of routines for US NI1
- * Layer 3 protocol based on the EURO/DSS1 D-channel protocol
- * driver written by Karsten Keil et al.
- * NI-1 Hall of Fame - Thanks to....
- * Ragnar Paulson - for some handy code fragments
- * Will Scales - beta tester extraordinaire
- * Brett Whittacre - beta tester and remote devel system in Vegas
- *
- */
-
-#include "hisax.h"
-#include "isdnl3.h"
-#include "l3ni1.h"
-#include <linux/ctype.h>
-#include <linux/slab.h>
-
-extern char *HiSax_getrev(const char *revision);
-static const char *ni1_revision = "$Revision: 2.8.2.3 $";
-
-#define EXT_BEARER_CAPS 1
-
-#define MsgHead(ptr, cref, mty) \
- *ptr++ = 0x8; \
- if (cref == -1) { \
- *ptr++ = 0x0; \
- } else { \
- *ptr++ = 0x1; \
- *ptr++ = cref^0x80; \
- } \
- *ptr++ = mty
-
-
-/**********************************************/
-/* get a new invoke id for remote operations. */
-/* Only a return value != 0 is valid */
-/**********************************************/
-static unsigned char new_invoke_id(struct PStack *p)
-{
- unsigned char retval;
- int i;
-
- i = 32; /* maximum search depth */
-
- retval = p->prot.ni1.last_invoke_id + 1; /* try new id */
- while ((i) && (p->prot.ni1.invoke_used[retval >> 3] == 0xFF)) {
- p->prot.ni1.last_invoke_id = (retval & 0xF8) + 8;
- i--;
- }
- if (i) {
- while (p->prot.ni1.invoke_used[retval >> 3] & (1 << (retval & 7)))
- retval++;
- } else
- retval = 0;
- p->prot.ni1.last_invoke_id = retval;
- p->prot.ni1.invoke_used[retval >> 3] |= (1 << (retval & 7));
- return (retval);
-} /* new_invoke_id */
-
-/*************************/
-/* free a used invoke id */
-/*************************/
-static void free_invoke_id(struct PStack *p, unsigned char id)
-{
-
- if (!id) return; /* 0 = invalid value */
-
- p->prot.ni1.invoke_used[id >> 3] &= ~(1 << (id & 7));
-} /* free_invoke_id */
-
-
-/**********************************************************/
-/* create a new l3 process and fill in ni1 specific data */
-/**********************************************************/
-static struct l3_process
-*ni1_new_l3_process(struct PStack *st, int cr)
-{ struct l3_process *proc;
-
- if (!(proc = new_l3_process(st, cr)))
- return (NULL);
-
- proc->prot.ni1.invoke_id = 0;
- proc->prot.ni1.remote_operation = 0;
- proc->prot.ni1.uus1_data[0] = '\0';
-
- return (proc);
-} /* ni1_new_l3_process */
-
-/************************************************/
-/* free a l3 process and all ni1 specific data */
-/************************************************/
-static void
-ni1_release_l3_process(struct l3_process *p)
-{
- free_invoke_id(p->st, p->prot.ni1.invoke_id);
- release_l3_process(p);
-} /* ni1_release_l3_process */
-
-/********************************************************/
-/* search a process with invoke id id and dummy callref */
-/********************************************************/
-static struct l3_process *
-l3ni1_search_dummy_proc(struct PStack *st, int id)
-{ struct l3_process *pc = st->l3.proc; /* start of processes */
-
- if (!id) return (NULL);
-
- while (pc)
- { if ((pc->callref == -1) && (pc->prot.ni1.invoke_id == id))
- return (pc);
- pc = pc->next;
- }
- return (NULL);
-} /* l3ni1_search_dummy_proc */
-
-/*******************************************************************/
-/* called when a facility message with a dummy callref is received */
-/* and a return result is delivered. id specifies the invoke id. */
-/*******************************************************************/
-static void
-l3ni1_dummy_return_result(struct PStack *st, int id, u_char *p, u_char nlen)
-{ isdn_ctrl ic;
- struct IsdnCardState *cs;
- struct l3_process *pc = NULL;
-
- if ((pc = l3ni1_search_dummy_proc(st, id)))
- { L3DelTimer(&pc->timer); /* remove timer */
-
- cs = pc->st->l1.hardware;
- ic.driver = cs->myid;
- ic.command = ISDN_STAT_PROT;
- ic.arg = NI1_STAT_INVOKE_RES;
- ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id;
- ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id;
- ic.parm.ni1_io.proc = pc->prot.ni1.proc;
- ic.parm.ni1_io.timeout = 0;
- ic.parm.ni1_io.datalen = nlen;
- ic.parm.ni1_io.data = p;
- free_invoke_id(pc->st, pc->prot.ni1.invoke_id);
- pc->prot.ni1.invoke_id = 0; /* reset id */
-
- cs->iif.statcallb(&ic);
- ni1_release_l3_process(pc);
- }
- else
- l3_debug(st, "dummy return result id=0x%x result len=%d", id, nlen);
-} /* l3ni1_dummy_return_result */
-
-/*******************************************************************/
-/* called when a facility message with a dummy callref is received */
-/* and a return error is delivered. id specifies the invoke id. */
-/*******************************************************************/
-static void
-l3ni1_dummy_error_return(struct PStack *st, int id, ulong error)
-{ isdn_ctrl ic;
- struct IsdnCardState *cs;
- struct l3_process *pc = NULL;
-
- if ((pc = l3ni1_search_dummy_proc(st, id)))
- { L3DelTimer(&pc->timer); /* remove timer */
-
- cs = pc->st->l1.hardware;
- ic.driver = cs->myid;
- ic.command = ISDN_STAT_PROT;
- ic.arg = NI1_STAT_INVOKE_ERR;
- ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id;
- ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id;
- ic.parm.ni1_io.proc = pc->prot.ni1.proc;
- ic.parm.ni1_io.timeout = error;
- ic.parm.ni1_io.datalen = 0;
- ic.parm.ni1_io.data = NULL;
- free_invoke_id(pc->st, pc->prot.ni1.invoke_id);
- pc->prot.ni1.invoke_id = 0; /* reset id */
-
- cs->iif.statcallb(&ic);
- ni1_release_l3_process(pc);
- }
- else
- l3_debug(st, "dummy return error id=0x%x error=0x%lx", id, error);
-} /* l3ni1_error_return */
-
-/*******************************************************************/
-/* called when a facility message with a dummy callref is received */
-/* and a invoke is delivered. id specifies the invoke id. */
-/*******************************************************************/
-static void
-l3ni1_dummy_invoke(struct PStack *st, int cr, int id,
- int ident, u_char *p, u_char nlen)
-{ isdn_ctrl ic;
- struct IsdnCardState *cs;
-
- l3_debug(st, "dummy invoke %s id=0x%x ident=0x%x datalen=%d",
- (cr == -1) ? "local" : "broadcast", id, ident, nlen);
- if (cr >= -1) return; /* ignore local data */
-
- cs = st->l1.hardware;
- ic.driver = cs->myid;
- ic.command = ISDN_STAT_PROT;
- ic.arg = NI1_STAT_INVOKE_BRD;
- ic.parm.ni1_io.hl_id = id;
- ic.parm.ni1_io.ll_id = 0;
- ic.parm.ni1_io.proc = ident;
- ic.parm.ni1_io.timeout = 0;
- ic.parm.ni1_io.datalen = nlen;
- ic.parm.ni1_io.data = p;
-
- cs->iif.statcallb(&ic);
-} /* l3ni1_dummy_invoke */
-
-static void
-l3ni1_parse_facility(struct PStack *st, struct l3_process *pc,
- int cr, u_char *p)
-{
- int qd_len = 0;
- unsigned char nlen = 0, ilen, cp_tag;
- int ident, id;
- ulong err_ret;
-
- if (pc)
- st = pc->st; /* valid Stack */
- else
- if ((!st) || (cr >= 0)) return; /* neither pc nor st specified */
-
- p++;
- qd_len = *p++;
- if (qd_len == 0) {
- l3_debug(st, "qd_len == 0");
- return;
- }
- if ((*p & 0x1F) != 0x11) { /* Service discriminator, supplementary service */
- l3_debug(st, "supplementary service != 0x11");
- return;
- }
- while (qd_len > 0 && !(*p & 0x80)) { /* extension ? */
- p++;
- qd_len--;
- }
- if (qd_len < 2) {
- l3_debug(st, "qd_len < 2");
- return;
- }
- p++;
- qd_len--;
- if ((*p & 0xE0) != 0xA0) { /* class and form */
- l3_debug(st, "class and form != 0xA0");
- return;
- }
-
- cp_tag = *p & 0x1F; /* remember tag value */
-
- p++;
- qd_len--;
- if (qd_len < 1)
- { l3_debug(st, "qd_len < 1");
- return;
- }
- if (*p & 0x80)
- { /* length format indefinite or limited */
- nlen = *p++ & 0x7F; /* number of len bytes or indefinite */
- if ((qd_len-- < ((!nlen) ? 3 : (1 + nlen))) ||
- (nlen > 1))
- { l3_debug(st, "length format error or not implemented");
- return;
- }
- if (nlen == 1)
- { nlen = *p++; /* complete length */
- qd_len--;
- }
- else
- { qd_len -= 2; /* trailing null bytes */
- if ((*(p + qd_len)) || (*(p + qd_len + 1)))
- { l3_debug(st, "length format indefinite error");
- return;
- }
- nlen = qd_len;
- }
- }
- else
- { nlen = *p++;
- qd_len--;
- }
- if (qd_len < nlen)
- { l3_debug(st, "qd_len < nlen");
- return;
- }
- qd_len -= nlen;
-
- if (nlen < 2)
- { l3_debug(st, "nlen < 2");
- return;
- }
- if (*p != 0x02)
- { /* invoke identifier tag */
- l3_debug(st, "invoke identifier tag !=0x02");
- return;
- }
- p++;
- nlen--;
- if (*p & 0x80)
- { /* length format */
- l3_debug(st, "invoke id length format 2");
- return;
- }
- ilen = *p++;
- nlen--;
- if (ilen > nlen || ilen == 0)
- { l3_debug(st, "ilen > nlen || ilen == 0");
- return;
- }
- nlen -= ilen;
- id = 0;
- while (ilen > 0)
- { id = (id << 8) | (*p++ & 0xFF); /* invoke identifier */
- ilen--;
- }
-
- switch (cp_tag) { /* component tag */
- case 1: /* invoke */
- if (nlen < 2) {
- l3_debug(st, "nlen < 2 22");
- return;
- }
- if (*p != 0x02) { /* operation value */
- l3_debug(st, "operation value !=0x02");
- return;
- }
- p++;
- nlen--;
- ilen = *p++;
- nlen--;
- if (ilen > nlen || ilen == 0) {
- l3_debug(st, "ilen > nlen || ilen == 0 22");
- return;
- }
- nlen -= ilen;
- ident = 0;
- while (ilen > 0) {
- ident = (ident << 8) | (*p++ & 0xFF);
- ilen--;
- }
-
- if (!pc)
- {
- l3ni1_dummy_invoke(st, cr, id, ident, p, nlen);
- return;
- }
- l3_debug(st, "invoke break");
- break;
- case 2: /* return result */
- /* if no process available handle separately */
- if (!pc)
- { if (cr == -1)
- l3ni1_dummy_return_result(st, id, p, nlen);
- return;
- }
- if ((pc->prot.ni1.invoke_id) && (pc->prot.ni1.invoke_id == id))
- { /* Diversion successful */
- free_invoke_id(st, pc->prot.ni1.invoke_id);
- pc->prot.ni1.remote_result = 0; /* success */
- pc->prot.ni1.invoke_id = 0;
- pc->redir_result = pc->prot.ni1.remote_result;
- st->l3.l3l4(st, CC_REDIR | INDICATION, pc); } /* Diversion successful */
- else
- l3_debug(st, "return error unknown identifier");
- break;
- case 3: /* return error */
- err_ret = 0;
- if (nlen < 2)
- { l3_debug(st, "return error nlen < 2");
- return;
- }
- if (*p != 0x02)
- { /* result tag */
- l3_debug(st, "invoke error tag !=0x02");
- return;
- }
- p++;
- nlen--;
- if (*p > 4)
- { /* length format */
- l3_debug(st, "invoke return errlen > 4 ");
- return;
- }
- ilen = *p++;
- nlen--;
- if (ilen > nlen || ilen == 0)
- { l3_debug(st, "error return ilen > nlen || ilen == 0");
- return;
- }
- nlen -= ilen;
- while (ilen > 0)
- { err_ret = (err_ret << 8) | (*p++ & 0xFF); /* error value */
- ilen--;
- }
- /* if no process available handle separately */
- if (!pc)
- { if (cr == -1)
- l3ni1_dummy_error_return(st, id, err_ret);
- return;
- }
- if ((pc->prot.ni1.invoke_id) && (pc->prot.ni1.invoke_id == id))
- { /* Deflection error */
- free_invoke_id(st, pc->prot.ni1.invoke_id);
- pc->prot.ni1.remote_result = err_ret; /* result */
- pc->prot.ni1.invoke_id = 0;
- pc->redir_result = pc->prot.ni1.remote_result;
- st->l3.l3l4(st, CC_REDIR | INDICATION, pc);
- } /* Deflection error */
- else
- l3_debug(st, "return result unknown identifier");
- break;
- default:
- l3_debug(st, "facility default break tag=0x%02x", cp_tag);
- break;
- }
-}
-
-static void
-l3ni1_message(struct l3_process *pc, u_char mt)
-{
- struct sk_buff *skb;
- u_char *p;
-
- if (!(skb = l3_alloc_skb(4)))
- return;
- p = skb_put(skb, 4);
- MsgHead(p, pc->callref, mt);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
-}
-
-static void
-l3ni1_message_plus_chid(struct l3_process *pc, u_char mt)
-/* sends an l3 messages plus channel id - added GE 05/09/00 */
-{
- struct sk_buff *skb;
- u_char tmp[16];
- u_char *p = tmp;
- u_char chid;
-
- chid = (u_char)(pc->para.bchannel & 0x03) | 0x88;
- MsgHead(p, pc->callref, mt);
- *p++ = IE_CHANNEL_ID;
- *p++ = 0x01;
- *p++ = chid;
-
- if (!(skb = l3_alloc_skb(7)))
- return;
- skb_put_data(skb, tmp, 7);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
-}
-
-static void
-l3ni1_message_cause(struct l3_process *pc, u_char mt, u_char cause)
-{
- struct sk_buff *skb;
- u_char tmp[16];
- u_char *p = tmp;
- int l;
-
- MsgHead(p, pc->callref, mt);
- *p++ = IE_CAUSE;
- *p++ = 0x2;
- *p++ = 0x80;
- *p++ = cause | 0x80;
-
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- skb_put_data(skb, tmp, l);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
-}
-
-static void
-l3ni1_status_send(struct l3_process *pc, u_char pr, void *arg)
-{
- u_char tmp[16];
- u_char *p = tmp;
- int l;
- struct sk_buff *skb;
-
- MsgHead(p, pc->callref, MT_STATUS);
-
- *p++ = IE_CAUSE;
- *p++ = 0x2;
- *p++ = 0x80;
- *p++ = pc->para.cause | 0x80;
-
- *p++ = IE_CALL_STATE;
- *p++ = 0x1;
- *p++ = pc->state & 0x3f;
-
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- skb_put_data(skb, tmp, l);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
-}
-
-static void
-l3ni1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg)
-{
- /* This routine is called if here was no SETUP made (checks in ni1up and in
- * l3ni1_setup) and a RELEASE_COMPLETE have to be sent with an error code
- * MT_STATUS_ENQUIRE in the NULL state is handled too
- */
- u_char tmp[16];
- u_char *p = tmp;
- int l;
- struct sk_buff *skb;
-
- switch (pc->para.cause) {
- case 81: /* invalid callreference */
- case 88: /* incomp destination */
- case 96: /* mandory IE missing */
- case 100: /* invalid IE contents */
- case 101: /* incompatible Callstate */
- MsgHead(p, pc->callref, MT_RELEASE_COMPLETE);
- *p++ = IE_CAUSE;
- *p++ = 0x2;
- *p++ = 0x80;
- *p++ = pc->para.cause | 0x80;
- break;
- default:
- printk(KERN_ERR "HiSax l3ni1_msg_without_setup wrong cause %d\n",
- pc->para.cause);
- return;
- }
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- skb_put_data(skb, tmp, l);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
- ni1_release_l3_process(pc);
-}
-
-static int ie_ALERTING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
- IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_HLC,
- IE_USER_USER, -1};
-static int ie_CALL_PROCEEDING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
- IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_HLC, -1};
-static int ie_CONNECT[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
- IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_DATE, IE_SIGNAL,
- IE_CONNECT_PN, IE_CONNECT_SUB, IE_LLC, IE_HLC, IE_USER_USER, -1};
-static int ie_CONNECT_ACKNOWLEDGE[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_SIGNAL, -1};
-static int ie_DISCONNECT[] = {IE_CAUSE | IE_MANDATORY, IE_FACILITY,
- IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1};
-static int ie_INFORMATION[] = {IE_COMPLETE, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL,
- IE_CALLED_PN, -1};
-static int ie_NOTIFY[] = {IE_BEARER, IE_NOTIFY | IE_MANDATORY, IE_DISPLAY, -1};
-static int ie_PROGRESS[] = {IE_BEARER, IE_CAUSE, IE_FACILITY, IE_PROGRESS |
- IE_MANDATORY, IE_DISPLAY, IE_HLC, IE_USER_USER, -1};
-static int ie_RELEASE[] = {IE_CAUSE | IE_MANDATORY_1, IE_FACILITY, IE_DISPLAY,
- IE_SIGNAL, IE_USER_USER, -1};
-/* a RELEASE_COMPLETE with errors don't require special actions
- static int ie_RELEASE_COMPLETE[] = {IE_CAUSE | IE_MANDATORY_1, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1};
-*/
-static int ie_RESUME_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY,
- IE_DISPLAY, -1};
-static int ie_RESUME_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
-static int ie_SETUP[] = {IE_COMPLETE, IE_BEARER | IE_MANDATORY,
- IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY, IE_PROGRESS,
- IE_NET_FAC, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, IE_CALLING_PN,
- IE_CALLING_SUB, IE_CALLED_PN, IE_CALLED_SUB, IE_REDIR_NR,
- IE_LLC, IE_HLC, IE_USER_USER, -1};
-static int ie_SETUP_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY,
- IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, -1};
-static int ie_STATUS[] = {IE_CAUSE | IE_MANDATORY, IE_CALL_STATE |
- IE_MANDATORY, IE_DISPLAY, -1};
-static int ie_STATUS_ENQUIRY[] = {IE_DISPLAY, -1};
-static int ie_SUSPEND_ACKNOWLEDGE[] = {IE_DISPLAY, IE_FACILITY, -1};
-static int ie_SUSPEND_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
-/* not used
- * static int ie_CONGESTION_CONTROL[] = {IE_CONGESTION | IE_MANDATORY,
- * IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
- * static int ie_USER_INFORMATION[] = {IE_MORE_DATA, IE_USER_USER | IE_MANDATORY, -1};
- * static int ie_RESTART[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_RESTART_IND |
- * IE_MANDATORY, -1};
- */
-static int ie_FACILITY[] = {IE_FACILITY | IE_MANDATORY, IE_DISPLAY, -1};
-static int comp_required[] = {1, 2, 3, 5, 6, 7, 9, 10, 11, 14, 15, -1};
-static int l3_valid_states[] = {0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 15, 17, 19, 25, -1};
-
-struct ie_len {
- int ie;
- int len;
-};
-
-static
-struct ie_len max_ie_len[] = {
- {IE_SEGMENT, 4},
- {IE_BEARER, 12},
- {IE_CAUSE, 32},
- {IE_CALL_ID, 10},
- {IE_CALL_STATE, 3},
- {IE_CHANNEL_ID, 34},
- {IE_FACILITY, 255},
- {IE_PROGRESS, 4},
- {IE_NET_FAC, 255},
- {IE_NOTIFY, 3},
- {IE_DISPLAY, 82},
- {IE_DATE, 8},
- {IE_KEYPAD, 34},
- {IE_SIGNAL, 3},
- {IE_INFORATE, 6},
- {IE_E2E_TDELAY, 11},
- {IE_TDELAY_SEL, 5},
- {IE_PACK_BINPARA, 3},
- {IE_PACK_WINSIZE, 4},
- {IE_PACK_SIZE, 4},
- {IE_CUG, 7},
- {IE_REV_CHARGE, 3},
- {IE_CALLING_PN, 24},
- {IE_CALLING_SUB, 23},
- {IE_CALLED_PN, 24},
- {IE_CALLED_SUB, 23},
- {IE_REDIR_NR, 255},
- {IE_TRANS_SEL, 255},
- {IE_RESTART_IND, 3},
- {IE_LLC, 18},
- {IE_HLC, 5},
- {IE_USER_USER, 131},
- {-1, 0},
-};
-
-static int
-getmax_ie_len(u_char ie) {
- int i = 0;
- while (max_ie_len[i].ie != -1) {
- if (max_ie_len[i].ie == ie)
- return (max_ie_len[i].len);
- i++;
- }
- return (255);
-}
-
-static int
-ie_in_set(struct l3_process *pc, u_char ie, int *checklist) {
- int ret = 1;
-
- while (*checklist != -1) {
- if ((*checklist & 0xff) == ie) {
- if (ie & 0x80)
- return (-ret);
- else
- return (ret);
- }
- ret++;
- checklist++;
- }
- return (0);
-}
-
-static int
-check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist)
-{
- int *cl = checklist;
- u_char mt;
- u_char *p, ie;
- int l, newpos, oldpos;
- int err_seq = 0, err_len = 0, err_compr = 0, err_ureg = 0;
- u_char codeset = 0;
- u_char old_codeset = 0;
- u_char codelock = 1;
-
- p = skb->data;
- /* skip cr */
- p++;
- l = (*p++) & 0xf;
- p += l;
- mt = *p++;
- oldpos = 0;
- while ((p - skb->data) < skb->len) {
- if ((*p & 0xf0) == 0x90) { /* shift codeset */
- old_codeset = codeset;
- codeset = *p & 7;
- if (*p & 0x08)
- codelock = 0;
- else
- codelock = 1;
- if (pc->debug & L3_DEB_CHECK)
- l3_debug(pc->st, "check IE shift%scodeset %d->%d",
- codelock ? " locking " : " ", old_codeset, codeset);
- p++;
- continue;
- }
- if (!codeset) { /* only codeset 0 */
- if ((newpos = ie_in_set(pc, *p, cl))) {
- if (newpos > 0) {
- if (newpos < oldpos)
- err_seq++;
- else
- oldpos = newpos;
- }
- } else {
- if (ie_in_set(pc, *p, comp_required))
- err_compr++;
- else
- err_ureg++;
- }
- }
- ie = *p++;
- if (ie & 0x80) {
- l = 1;
- } else {
- l = *p++;
- p += l;
- l += 2;
- }
- if (!codeset && (l > getmax_ie_len(ie)))
- err_len++;
- if (!codelock) {
- if (pc->debug & L3_DEB_CHECK)
- l3_debug(pc->st, "check IE shift back codeset %d->%d",
- codeset, old_codeset);
- codeset = old_codeset;
- codelock = 1;
- }
- }
- if (err_compr | err_ureg | err_len | err_seq) {
- if (pc->debug & L3_DEB_CHECK)
- l3_debug(pc->st, "check IE MT(%x) %d/%d/%d/%d",
- mt, err_compr, err_ureg, err_len, err_seq);
- if (err_compr)
- return (ERR_IE_COMPREHENSION);
- if (err_ureg)
- return (ERR_IE_UNRECOGNIZED);
- if (err_len)
- return (ERR_IE_LENGTH);
- if (err_seq)
- return (ERR_IE_SEQUENCE);
- }
- return (0);
-}
-
-/* verify if a message type exists and contain no IE error */
-static int
-l3ni1_check_messagetype_validity(struct l3_process *pc, int mt, void *arg)
-{
- switch (mt) {
- case MT_ALERTING:
- case MT_CALL_PROCEEDING:
- case MT_CONNECT:
- case MT_CONNECT_ACKNOWLEDGE:
- case MT_DISCONNECT:
- case MT_INFORMATION:
- case MT_FACILITY:
- case MT_NOTIFY:
- case MT_PROGRESS:
- case MT_RELEASE:
- case MT_RELEASE_COMPLETE:
- case MT_SETUP:
- case MT_SETUP_ACKNOWLEDGE:
- case MT_RESUME_ACKNOWLEDGE:
- case MT_RESUME_REJECT:
- case MT_SUSPEND_ACKNOWLEDGE:
- case MT_SUSPEND_REJECT:
- case MT_USER_INFORMATION:
- case MT_RESTART:
- case MT_RESTART_ACKNOWLEDGE:
- case MT_CONGESTION_CONTROL:
- case MT_STATUS:
- case MT_STATUS_ENQUIRY:
- if (pc->debug & L3_DEB_CHECK)
- l3_debug(pc->st, "l3ni1_check_messagetype_validity mt(%x) OK", mt);
- break;
- case MT_RESUME: /* RESUME only in user->net */
- case MT_SUSPEND: /* SUSPEND only in user->net */
- default:
- if (pc->debug & (L3_DEB_CHECK | L3_DEB_WARN))
- l3_debug(pc->st, "l3ni1_check_messagetype_validity mt(%x) fail", mt);
- pc->para.cause = 97;
- l3ni1_status_send(pc, 0, NULL);
- return (1);
- }
- return (0);
-}
-
-static void
-l3ni1_std_ie_err(struct l3_process *pc, int ret) {
-
- if (pc->debug & L3_DEB_CHECK)
- l3_debug(pc->st, "check_infoelements ret %d", ret);
- switch (ret) {
- case 0:
- break;
- case ERR_IE_COMPREHENSION:
- pc->para.cause = 96;
- l3ni1_status_send(pc, 0, NULL);
- break;
- case ERR_IE_UNRECOGNIZED:
- pc->para.cause = 99;
- l3ni1_status_send(pc, 0, NULL);
- break;
- case ERR_IE_LENGTH:
- pc->para.cause = 100;
- l3ni1_status_send(pc, 0, NULL);
- break;
- case ERR_IE_SEQUENCE:
- default:
- break;
- }
-}
-
-static int
-l3ni1_get_channel_id(struct l3_process *pc, struct sk_buff *skb) {
- u_char *p;
-
- p = skb->data;
- if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) {
- p++;
- if (*p != 1) { /* len for BRI = 1 */
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "wrong chid len %d", *p);
- return (-2);
- }
- p++;
- if (*p & 0x60) { /* only base rate interface */
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "wrong chid %x", *p);
- return (-3);
- }
- return (*p & 0x3);
- } else
- return (-1);
-}
-
-static int
-l3ni1_get_cause(struct l3_process *pc, struct sk_buff *skb) {
- u_char l, i = 0;
- u_char *p;
-
- p = skb->data;
- pc->para.cause = 31;
- pc->para.loc = 0;
- if ((p = findie(p, skb->len, IE_CAUSE, 0))) {
- p++;
- l = *p++;
- if (l > 30)
- return (1);
- if (l) {
- pc->para.loc = *p++;
- l--;
- } else {
- return (2);
- }
- if (l && !(pc->para.loc & 0x80)) {
- l--;
- p++; /* skip recommendation */
- }
- if (l) {
- pc->para.cause = *p++;
- l--;
- if (!(pc->para.cause & 0x80))
- return (3);
- } else
- return (4);
- while (l && (i < 6)) {
- pc->para.diag[i++] = *p++;
- l--;
- }
- } else
- return (-1);
- return (0);
-}
-
-static void
-l3ni1_msg_with_uus(struct l3_process *pc, u_char cmd)
-{
- struct sk_buff *skb;
- u_char tmp[16 + 40];
- u_char *p = tmp;
- int l;
-
- MsgHead(p, pc->callref, cmd);
-
- if (pc->prot.ni1.uus1_data[0])
- { *p++ = IE_USER_USER; /* UUS info element */
- *p++ = strlen(pc->prot.ni1.uus1_data) + 1;
- *p++ = 0x04; /* IA5 chars */
- strcpy(p, pc->prot.ni1.uus1_data);
- p += strlen(pc->prot.ni1.uus1_data);
- pc->prot.ni1.uus1_data[0] = '\0';
- }
-
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- skb_put_data(skb, tmp, l);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
-} /* l3ni1_msg_with_uus */
-
-static void
-l3ni1_release_req(struct l3_process *pc, u_char pr, void *arg)
-{
- StopAllL3Timer(pc);
- newl3state(pc, 19);
- if (!pc->prot.ni1.uus1_data[0])
- l3ni1_message(pc, MT_RELEASE);
- else
- l3ni1_msg_with_uus(pc, MT_RELEASE);
- L3AddTimer(&pc->timer, T308, CC_T308_1);
-}
-
-static void
-l3ni1_release_cmpl(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- int ret;
-
- if ((ret = l3ni1_get_cause(pc, skb)) > 0) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "RELCMPL get_cause ret(%d)", ret);
- } else if (ret < 0)
- pc->para.cause = NO_CAUSE;
- StopAllL3Timer(pc);
- newl3state(pc, 0);
- pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc);
- ni1_release_l3_process(pc);
-}
-
-#if EXT_BEARER_CAPS
-
-static u_char *
-EncodeASyncParams(u_char *p, u_char si2)
-{ // 7c 06 88 90 21 42 00 bb
-
- p[0] = 0;
- p[1] = 0x40; // Intermediate rate: 16 kbit/s jj 2000.02.19
- p[2] = 0x80;
- if (si2 & 32) // 7 data bits
-
- p[2] += 16;
- else // 8 data bits
-
- p[2] += 24;
-
- if (si2 & 16) // 2 stop bits
-
- p[2] += 96;
- else // 1 stop bit
-
- p[2] += 32;
-
- if (si2 & 8) // even parity
-
- p[2] += 2;
- else // no parity
-
- p[2] += 3;
-
- switch (si2 & 0x07) {
- case 0:
- p[0] = 66; // 1200 bit/s
-
- break;
- case 1:
- p[0] = 88; // 1200/75 bit/s
-
- break;
- case 2:
- p[0] = 87; // 75/1200 bit/s
-
- break;
- case 3:
- p[0] = 67; // 2400 bit/s
-
- break;
- case 4:
- p[0] = 69; // 4800 bit/s
-
- break;
- case 5:
- p[0] = 72; // 9600 bit/s
-
- break;
- case 6:
- p[0] = 73; // 14400 bit/s
-
- break;
- case 7:
- p[0] = 75; // 19200 bit/s
-
- break;
- }
- return p + 3;
-}
-
-static u_char
-EncodeSyncParams(u_char si2, u_char ai)
-{
-
- switch (si2) {
- case 0:
- return ai + 2; // 1200 bit/s
-
- case 1:
- return ai + 24; // 1200/75 bit/s
-
- case 2:
- return ai + 23; // 75/1200 bit/s
-
- case 3:
- return ai + 3; // 2400 bit/s
-
- case 4:
- return ai + 5; // 4800 bit/s
-
- case 5:
- return ai + 8; // 9600 bit/s
-
- case 6:
- return ai + 9; // 14400 bit/s
-
- case 7:
- return ai + 11; // 19200 bit/s
-
- case 8:
- return ai + 14; // 48000 bit/s
-
- case 9:
- return ai + 15; // 56000 bit/s
-
- case 15:
- return ai + 40; // negotiate bit/s
-
- default:
- break;
- }
- return ai;
-}
-
-
-static u_char
-DecodeASyncParams(u_char si2, u_char *p)
-{
- u_char info;
-
- switch (p[5]) {
- case 66: // 1200 bit/s
-
- break; // si2 don't change
-
- case 88: // 1200/75 bit/s
-
- si2 += 1;
- break;
- case 87: // 75/1200 bit/s
-
- si2 += 2;
- break;
- case 67: // 2400 bit/s
-
- si2 += 3;
- break;
- case 69: // 4800 bit/s
-
- si2 += 4;
- break;
- case 72: // 9600 bit/s
-
- si2 += 5;
- break;
- case 73: // 14400 bit/s
-
- si2 += 6;
- break;
- case 75: // 19200 bit/s
-
- si2 += 7;
- break;
- }
-
- info = p[7] & 0x7f;
- if ((info & 16) && (!(info & 8))) // 7 data bits
-
- si2 += 32; // else 8 data bits
-
- if ((info & 96) == 96) // 2 stop bits
-
- si2 += 16; // else 1 stop bit
-
- if ((info & 2) && (!(info & 1))) // even parity
-
- si2 += 8; // else no parity
-
- return si2;
-}
-
-
-static u_char
-DecodeSyncParams(u_char si2, u_char info)
-{
- info &= 0x7f;
- switch (info) {
- case 40: // bit/s negotiation failed ai := 165 not 175!
-
- return si2 + 15;
- case 15: // 56000 bit/s failed, ai := 0 not 169 !
-
- return si2 + 9;
- case 14: // 48000 bit/s
-
- return si2 + 8;
- case 11: // 19200 bit/s
-
- return si2 + 7;
- case 9: // 14400 bit/s
-
- return si2 + 6;
- case 8: // 9600 bit/s
-
- return si2 + 5;
- case 5: // 4800 bit/s
-
- return si2 + 4;
- case 3: // 2400 bit/s
-
- return si2 + 3;
- case 23: // 75/1200 bit/s
-
- return si2 + 2;
- case 24: // 1200/75 bit/s
-
- return si2 + 1;
- default: // 1200 bit/s
-
- return si2;
- }
-}
-
-static u_char
-DecodeSI2(struct sk_buff *skb)
-{
- u_char *p; //, *pend=skb->data + skb->len;
-
- if ((p = findie(skb->data, skb->len, 0x7c, 0))) {
- switch (p[4] & 0x0f) {
- case 0x01:
- if (p[1] == 0x04) // sync. Bitratenadaption
-
- return DecodeSyncParams(160, p[5]); // V.110/X.30
-
- else if (p[1] == 0x06) // async. Bitratenadaption
-
- return DecodeASyncParams(192, p); // V.110/X.30
-
- break;
- case 0x08: // if (p[5] == 0x02) // sync. Bitratenadaption
- if (p[1] > 3)
- return DecodeSyncParams(176, p[5]); // V.120
- break;
- }
- }
- return 0;
-}
-
-#endif
-
-
-static void
-l3ni1_setup_req(struct l3_process *pc, u_char pr,
- void *arg)
-{
- struct sk_buff *skb;
- u_char tmp[128];
- u_char *p = tmp;
-
- u_char *teln;
- u_char *sub;
- u_char *sp;
- int l;
-
- MsgHead(p, pc->callref, MT_SETUP);
-
- teln = pc->para.setup.phone;
-
- *p++ = 0xa1; /* complete indicator */
- /*
- * Set Bearer Capability, Map info from 1TR6-convention to NI1
- */
- switch (pc->para.setup.si1) {
- case 1: /* Telephony */
- *p++ = IE_BEARER;
- *p++ = 0x3; /* Length */
- *p++ = 0x90; /* 3.1khz Audio */
- *p++ = 0x90; /* Circuit-Mode 64kbps */
- *p++ = 0xa2; /* u-Law Audio */
- break;
- case 5: /* Datatransmission 64k, BTX */
- case 7: /* Datatransmission 64k */
- default:
- *p++ = IE_BEARER;
- *p++ = 0x2; /* Length */
- *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */
- *p++ = 0x90; /* Circuit-Mode 64kbps */
- break;
- }
-
- sub = NULL;
- sp = teln;
- while (*sp) {
- if ('.' == *sp) {
- sub = sp;
- *sp = 0;
- } else
- sp++;
- }
-
- *p++ = IE_KEYPAD;
- *p++ = strlen(teln);
- while (*teln)
- *p++ = (*teln++) & 0x7F;
-
- if (sub)
- *sub++ = '.';
-
-#if EXT_BEARER_CAPS
- if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) { // sync. Bitratenadaption, V.110/X.30
-
- *p++ = IE_LLC;
- *p++ = 0x04;
- *p++ = 0x88;
- *p++ = 0x90;
- *p++ = 0x21;
- *p++ = EncodeSyncParams(pc->para.setup.si2 - 160, 0x80);
- } else if ((pc->para.setup.si2 >= 176) && (pc->para.setup.si2 <= 191)) { // sync. Bitratenadaption, V.120
-
- *p++ = IE_LLC;
- *p++ = 0x05;
- *p++ = 0x88;
- *p++ = 0x90;
- *p++ = 0x28;
- *p++ = EncodeSyncParams(pc->para.setup.si2 - 176, 0);
- *p++ = 0x82;
- } else if (pc->para.setup.si2 >= 192) { // async. Bitratenadaption, V.110/X.30
-
- *p++ = IE_LLC;
- *p++ = 0x06;
- *p++ = 0x88;
- *p++ = 0x90;
- *p++ = 0x21;
- p = EncodeASyncParams(p, pc->para.setup.si2 - 192);
- } else {
- switch (pc->para.setup.si1) {
- case 1: /* Telephony */
- *p++ = IE_LLC;
- *p++ = 0x3; /* Length */
- *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */
- *p++ = 0x90; /* Circuit-Mode 64kbps */
- *p++ = 0xa2; /* u-Law Audio */
- break;
- case 5: /* Datatransmission 64k, BTX */
- case 7: /* Datatransmission 64k */
- default:
- *p++ = IE_LLC;
- *p++ = 0x2; /* Length */
- *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */
- *p++ = 0x90; /* Circuit-Mode 64kbps */
- break;
- }
- }
-#endif
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- {
- return;
- }
- skb_put_data(skb, tmp, l);
- L3DelTimer(&pc->timer);
- L3AddTimer(&pc->timer, T303, CC_T303);
- newl3state(pc, 1);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
-}
-
-static void
-l3ni1_call_proc(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- int id, ret;
-
- if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) {
- if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "setup answer with wrong chid %x", id);
- pc->para.cause = 100;
- l3ni1_status_send(pc, pr, NULL);
- return;
- }
- pc->para.bchannel = id;
- } else if (1 == pc->state) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "setup answer wrong chid (ret %d)", id);
- if (id == -1)
- pc->para.cause = 96;
- else
- pc->para.cause = 100;
- l3ni1_status_send(pc, pr, NULL);
- return;
- }
- /* Now we are on none mandatory IEs */
- ret = check_infoelements(pc, skb, ie_CALL_PROCEEDING);
- if (ERR_IE_COMPREHENSION == ret) {
- l3ni1_std_ie_err(pc, ret);
- return;
- }
- L3DelTimer(&pc->timer);
- newl3state(pc, 3);
- L3AddTimer(&pc->timer, T310, CC_T310);
- if (ret) /* STATUS for none mandatory IE errors after actions are taken */
- l3ni1_std_ie_err(pc, ret);
- pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc);
-}
-
-static void
-l3ni1_setup_ack(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- int id, ret;
-
- if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) {
- if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "setup answer with wrong chid %x", id);
- pc->para.cause = 100;
- l3ni1_status_send(pc, pr, NULL);
- return;
- }
- pc->para.bchannel = id;
- } else {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "setup answer wrong chid (ret %d)", id);
- if (id == -1)
- pc->para.cause = 96;
- else
- pc->para.cause = 100;
- l3ni1_status_send(pc, pr, NULL);
- return;
- }
- /* Now we are on none mandatory IEs */
- ret = check_infoelements(pc, skb, ie_SETUP_ACKNOWLEDGE);
- if (ERR_IE_COMPREHENSION == ret) {
- l3ni1_std_ie_err(pc, ret);
- return;
- }
- L3DelTimer(&pc->timer);
- newl3state(pc, 2);
- L3AddTimer(&pc->timer, T304, CC_T304);
- if (ret) /* STATUS for none mandatory IE errors after actions are taken */
- l3ni1_std_ie_err(pc, ret);
- pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
-}
-
-static void
-l3ni1_disconnect(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- u_char *p;
- int ret;
- u_char cause = 0;
-
- StopAllL3Timer(pc);
- if ((ret = l3ni1_get_cause(pc, skb))) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "DISC get_cause ret(%d)", ret);
- if (ret < 0)
- cause = 96;
- else if (ret > 0)
- cause = 100;
- }
- if ((p = findie(skb->data, skb->len, IE_FACILITY, 0)))
- l3ni1_parse_facility(pc->st, pc, pc->callref, p);
- ret = check_infoelements(pc, skb, ie_DISCONNECT);
- if (ERR_IE_COMPREHENSION == ret)
- cause = 96;
- else if ((!cause) && (ERR_IE_UNRECOGNIZED == ret))
- cause = 99;
- ret = pc->state;
- newl3state(pc, 12);
- if (cause)
- newl3state(pc, 19);
- if (11 != ret)
- pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc);
- else if (!cause)
- l3ni1_release_req(pc, pr, NULL);
- if (cause) {
- l3ni1_message_cause(pc, MT_RELEASE, cause);
- L3AddTimer(&pc->timer, T308, CC_T308_1);
- }
-}
-
-static void
-l3ni1_connect(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- int ret;
-
- ret = check_infoelements(pc, skb, ie_CONNECT);
- if (ERR_IE_COMPREHENSION == ret) {
- l3ni1_std_ie_err(pc, ret);
- return;
- }
- L3DelTimer(&pc->timer); /* T310 */
- newl3state(pc, 10);
- pc->para.chargeinfo = 0;
- /* here should inserted COLP handling KKe */
- if (ret)
- l3ni1_std_ie_err(pc, ret);
- pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc);
-}
-
-static void
-l3ni1_alerting(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- int ret;
-
- ret = check_infoelements(pc, skb, ie_ALERTING);
- if (ERR_IE_COMPREHENSION == ret) {
- l3ni1_std_ie_err(pc, ret);
- return;
- }
- L3DelTimer(&pc->timer); /* T304 */
- newl3state(pc, 4);
- if (ret)
- l3ni1_std_ie_err(pc, ret);
- pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc);
-}
-
-static void
-l3ni1_setup(struct l3_process *pc, u_char pr, void *arg)
-{
- u_char *p;
- int bcfound = 0;
- char tmp[80];
- struct sk_buff *skb = arg;
- int id;
- int err = 0;
-
- /*
- * Bearer Capabilities
- */
- p = skb->data;
- /* only the first occurrence 'll be detected ! */
- if ((p = findie(p, skb->len, 0x04, 0))) {
- if ((p[1] < 2) || (p[1] > 11))
- err = 1;
- else {
- pc->para.setup.si2 = 0;
- switch (p[2] & 0x7f) {
- case 0x00: /* Speech */
- case 0x10: /* 3.1 Khz audio */
- pc->para.setup.si1 = 1;
- break;
- case 0x08: /* Unrestricted digital information */
- pc->para.setup.si1 = 7;
-/* JIM, 05.11.97 I wanna set service indicator 2 */
-#if EXT_BEARER_CAPS
- pc->para.setup.si2 = DecodeSI2(skb);
-#endif
- break;
- case 0x09: /* Restricted digital information */
- pc->para.setup.si1 = 2;
- break;
- case 0x11:
- /* Unrestr. digital information with
- * tones/announcements ( or 7 kHz audio
- */
- pc->para.setup.si1 = 3;
- break;
- case 0x18: /* Video */
- pc->para.setup.si1 = 4;
- break;
- default:
- err = 2;
- break;
- }
- switch (p[3] & 0x7f) {
- case 0x40: /* packed mode */
- pc->para.setup.si1 = 8;
- break;
- case 0x10: /* 64 kbit */
- case 0x11: /* 2*64 kbit */
- case 0x13: /* 384 kbit */
- case 0x15: /* 1536 kbit */
- case 0x17: /* 1920 kbit */
- pc->para.moderate = p[3] & 0x7f;
- break;
- default:
- err = 3;
- break;
- }
- }
- if (pc->debug & L3_DEB_SI)
- l3_debug(pc->st, "SI=%d, AI=%d",
- pc->para.setup.si1, pc->para.setup.si2);
- if (err) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "setup with wrong bearer(l=%d:%x,%x)",
- p[1], p[2], p[3]);
- pc->para.cause = 100;
- l3ni1_msg_without_setup(pc, pr, NULL);
- return;
- }
- } else {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "setup without bearer capabilities");
- /* ETS 300-104 1.3.3 */
- pc->para.cause = 96;
- l3ni1_msg_without_setup(pc, pr, NULL);
- return;
- }
- /*
- * Channel Identification
- */
- if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) {
- if ((pc->para.bchannel = id)) {
- if ((3 == id) && (0x10 == pc->para.moderate)) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "setup with wrong chid %x",
- id);
- pc->para.cause = 100;
- l3ni1_msg_without_setup(pc, pr, NULL);
- return;
- }
- bcfound++;
- } else
- { if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "setup without bchannel, call waiting");
- bcfound++;
- }
- } else {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "setup with wrong chid ret %d", id);
- if (id == -1)
- pc->para.cause = 96;
- else
- pc->para.cause = 100;
- l3ni1_msg_without_setup(pc, pr, NULL);
- return;
- }
- /* Now we are on none mandatory IEs */
- err = check_infoelements(pc, skb, ie_SETUP);
- if (ERR_IE_COMPREHENSION == err) {
- pc->para.cause = 96;
- l3ni1_msg_without_setup(pc, pr, NULL);
- return;
- }
- p = skb->data;
- if ((p = findie(p, skb->len, 0x70, 0)))
- iecpy(pc->para.setup.eazmsn, p, 1);
- else
- pc->para.setup.eazmsn[0] = 0;
-
- p = skb->data;
- if ((p = findie(p, skb->len, 0x71, 0))) {
- /* Called party subaddress */
- if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) {
- tmp[0] = '.';
- iecpy(&tmp[1], p, 2);
- strcat(pc->para.setup.eazmsn, tmp);
- } else if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "wrong called subaddress");
- }
- p = skb->data;
- if ((p = findie(p, skb->len, 0x6c, 0))) {
- pc->para.setup.plan = p[2];
- if (p[2] & 0x80) {
- iecpy(pc->para.setup.phone, p, 1);
- pc->para.setup.screen = 0;
- } else {
- iecpy(pc->para.setup.phone, p, 2);
- pc->para.setup.screen = p[3];
- }
- } else {
- pc->para.setup.phone[0] = 0;
- pc->para.setup.plan = 0;
- pc->para.setup.screen = 0;
- }
- p = skb->data;
- if ((p = findie(p, skb->len, 0x6d, 0))) {
- /* Calling party subaddress */
- if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) {
- tmp[0] = '.';
- iecpy(&tmp[1], p, 2);
- strcat(pc->para.setup.phone, tmp);
- } else if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "wrong calling subaddress");
- }
- newl3state(pc, 6);
- if (err) /* STATUS for none mandatory IE errors after actions are taken */
- l3ni1_std_ie_err(pc, err);
- pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc);
-}
-
-static void
-l3ni1_reset(struct l3_process *pc, u_char pr, void *arg)
-{
- ni1_release_l3_process(pc);
-}
-
-static void
-l3ni1_disconnect_req(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb;
- u_char tmp[16 + 40];
- u_char *p = tmp;
- int l;
- u_char cause = 16;
-
- if (pc->para.cause != NO_CAUSE)
- cause = pc->para.cause;
-
- StopAllL3Timer(pc);
-
- MsgHead(p, pc->callref, MT_DISCONNECT);
-
- *p++ = IE_CAUSE;
- *p++ = 0x2;
- *p++ = 0x80;
- *p++ = cause | 0x80;
-
- if (pc->prot.ni1.uus1_data[0])
- { *p++ = IE_USER_USER; /* UUS info element */
- *p++ = strlen(pc->prot.ni1.uus1_data) + 1;
- *p++ = 0x04; /* IA5 chars */
- strcpy(p, pc->prot.ni1.uus1_data);
- p += strlen(pc->prot.ni1.uus1_data);
- pc->prot.ni1.uus1_data[0] = '\0';
- }
-
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- skb_put_data(skb, tmp, l);
- newl3state(pc, 11);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
- L3AddTimer(&pc->timer, T305, CC_T305);
-}
-
-static void
-l3ni1_setup_rsp(struct l3_process *pc, u_char pr,
- void *arg)
-{
- if (!pc->para.bchannel)
- { if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "D-chan connect for waiting call");
- l3ni1_disconnect_req(pc, pr, arg);
- return;
- }
- newl3state(pc, 8);
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "D-chan connect for waiting call");
- l3ni1_message_plus_chid(pc, MT_CONNECT); /* GE 05/09/00 */
- L3DelTimer(&pc->timer);
- L3AddTimer(&pc->timer, T313, CC_T313);
-}
-
-static void
-l3ni1_connect_ack(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- int ret;
-
- ret = check_infoelements(pc, skb, ie_CONNECT_ACKNOWLEDGE);
- if (ERR_IE_COMPREHENSION == ret) {
- l3ni1_std_ie_err(pc, ret);
- return;
- }
- newl3state(pc, 10);
- L3DelTimer(&pc->timer);
- if (ret)
- l3ni1_std_ie_err(pc, ret);
- pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
-}
-
-static void
-l3ni1_reject_req(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb;
- u_char tmp[16];
- u_char *p = tmp;
- int l;
- u_char cause = 21;
-
- if (pc->para.cause != NO_CAUSE)
- cause = pc->para.cause;
-
- MsgHead(p, pc->callref, MT_RELEASE_COMPLETE);
-
- *p++ = IE_CAUSE;
- *p++ = 0x2;
- *p++ = 0x80;
- *p++ = cause | 0x80;
-
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- skb_put_data(skb, tmp, l);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
- newl3state(pc, 0);
- ni1_release_l3_process(pc);
-}
-
-static void
-l3ni1_release(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- u_char *p;
- int ret, cause = 0;
-
- StopAllL3Timer(pc);
- if ((ret = l3ni1_get_cause(pc, skb)) > 0) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "REL get_cause ret(%d)", ret);
- } else if (ret < 0)
- pc->para.cause = NO_CAUSE;
- if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) {
- l3ni1_parse_facility(pc->st, pc, pc->callref, p);
- }
- if ((ret < 0) && (pc->state != 11))
- cause = 96;
- else if (ret > 0)
- cause = 100;
- ret = check_infoelements(pc, skb, ie_RELEASE);
- if (ERR_IE_COMPREHENSION == ret)
- cause = 96;
- else if ((ERR_IE_UNRECOGNIZED == ret) && (!cause))
- cause = 99;
- if (cause)
- l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, cause);
- else
- l3ni1_message(pc, MT_RELEASE_COMPLETE);
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
- newl3state(pc, 0);
- ni1_release_l3_process(pc);
-}
-
-static void
-l3ni1_alert_req(struct l3_process *pc, u_char pr,
- void *arg)
-{
- newl3state(pc, 7);
- if (!pc->prot.ni1.uus1_data[0])
- l3ni1_message(pc, MT_ALERTING);
- else
- l3ni1_msg_with_uus(pc, MT_ALERTING);
-}
-
-static void
-l3ni1_proceed_req(struct l3_process *pc, u_char pr,
- void *arg)
-{
- newl3state(pc, 9);
- l3ni1_message(pc, MT_CALL_PROCEEDING);
- pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc);
-}
-
-static void
-l3ni1_setup_ack_req(struct l3_process *pc, u_char pr,
- void *arg)
-{
- newl3state(pc, 25);
- L3DelTimer(&pc->timer);
- L3AddTimer(&pc->timer, T302, CC_T302);
- l3ni1_message(pc, MT_SETUP_ACKNOWLEDGE);
-}
-
-/********************************************/
-/* deliver a incoming display message to HL */
-/********************************************/
-static void
-l3ni1_deliver_display(struct l3_process *pc, int pr, u_char *infp)
-{ u_char len;
- isdn_ctrl ic;
- struct IsdnCardState *cs;
- char *p;
-
- if (*infp++ != IE_DISPLAY) return;
- if ((len = *infp++) > 80) return; /* total length <= 82 */
- if (!pc->chan) return;
-
- p = ic.parm.display;
- while (len--)
- *p++ = *infp++;
- *p = '\0';
- ic.command = ISDN_STAT_DISPLAY;
- cs = pc->st->l1.hardware;
- ic.driver = cs->myid;
- ic.arg = pc->chan->chan;
- cs->iif.statcallb(&ic);
-} /* l3ni1_deliver_display */
-
-
-static void
-l3ni1_progress(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- int err = 0;
- u_char *p;
-
- if ((p = findie(skb->data, skb->len, IE_PROGRESS, 0))) {
- if (p[1] != 2) {
- err = 1;
- pc->para.cause = 100;
- } else if (!(p[2] & 0x70)) {
- switch (p[2]) {
- case 0x80:
- case 0x81:
- case 0x82:
- case 0x84:
- case 0x85:
- case 0x87:
- case 0x8a:
- switch (p[3]) {
- case 0x81:
- case 0x82:
- case 0x83:
- case 0x84:
- case 0x88:
- break;
- default:
- err = 2;
- pc->para.cause = 100;
- break;
- }
- break;
- default:
- err = 3;
- pc->para.cause = 100;
- break;
- }
- }
- } else {
- pc->para.cause = 96;
- err = 4;
- }
- if (err) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "progress error %d", err);
- l3ni1_status_send(pc, pr, NULL);
- return;
- }
- /* Now we are on none mandatory IEs */
- err = check_infoelements(pc, skb, ie_PROGRESS);
- if (err)
- l3ni1_std_ie_err(pc, err);
- if (ERR_IE_COMPREHENSION != err)
- pc->st->l3.l3l4(pc->st, CC_PROGRESS | INDICATION, pc);
-}
-
-static void
-l3ni1_notify(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- int err = 0;
- u_char *p;
-
- if ((p = findie(skb->data, skb->len, IE_NOTIFY, 0))) {
- if (p[1] != 1) {
- err = 1;
- pc->para.cause = 100;
- } else {
- switch (p[2]) {
- case 0x80:
- case 0x81:
- case 0x82:
- break;
- default:
- pc->para.cause = 100;
- err = 2;
- break;
- }
- }
- } else {
- pc->para.cause = 96;
- err = 3;
- }
- if (err) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "notify error %d", err);
- l3ni1_status_send(pc, pr, NULL);
- return;
- }
- /* Now we are on none mandatory IEs */
- err = check_infoelements(pc, skb, ie_NOTIFY);
- if (err)
- l3ni1_std_ie_err(pc, err);
- if (ERR_IE_COMPREHENSION != err)
- pc->st->l3.l3l4(pc->st, CC_NOTIFY | INDICATION, pc);
-}
-
-static void
-l3ni1_status_enq(struct l3_process *pc, u_char pr, void *arg)
-{
- int ret;
- struct sk_buff *skb = arg;
-
- ret = check_infoelements(pc, skb, ie_STATUS_ENQUIRY);
- l3ni1_std_ie_err(pc, ret);
- pc->para.cause = 30; /* response to STATUS_ENQUIRY */
- l3ni1_status_send(pc, pr, NULL);
-}
-
-static void
-l3ni1_information(struct l3_process *pc, u_char pr, void *arg)
-{
- int ret;
- struct sk_buff *skb = arg;
- u_char *p;
- char tmp[32];
-
- ret = check_infoelements(pc, skb, ie_INFORMATION);
- if (ret)
- l3ni1_std_ie_err(pc, ret);
- if (pc->state == 25) { /* overlap receiving */
- L3DelTimer(&pc->timer);
- p = skb->data;
- if ((p = findie(p, skb->len, 0x70, 0))) {
- iecpy(tmp, p, 1);
- strcat(pc->para.setup.eazmsn, tmp);
- pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
- }
- L3AddTimer(&pc->timer, T302, CC_T302);
- }
-}
-
-/******************************/
-/* handle deflection requests */
-/******************************/
-static void l3ni1_redir_req(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb;
- u_char tmp[128];
- u_char *p = tmp;
- u_char *subp;
- u_char len_phone = 0;
- u_char len_sub = 0;
- int l;
-
-
- strcpy(pc->prot.ni1.uus1_data, pc->chan->setup.eazmsn); /* copy uus element if available */
- if (!pc->chan->setup.phone[0])
- { pc->para.cause = -1;
- l3ni1_disconnect_req(pc, pr, arg); /* disconnect immediately */
- return;
- } /* only uus */
-
- if (pc->prot.ni1.invoke_id)
- free_invoke_id(pc->st, pc->prot.ni1.invoke_id);
-
- if (!(pc->prot.ni1.invoke_id = new_invoke_id(pc->st)))
- return;
-
- MsgHead(p, pc->callref, MT_FACILITY);
-
- for (subp = pc->chan->setup.phone; (*subp) && (*subp != '.'); subp++) len_phone++; /* len of phone number */
- if (*subp++ == '.') len_sub = strlen(subp) + 2; /* length including info subaddress element */
-
- *p++ = 0x1c; /* Facility info element */
- *p++ = len_phone + len_sub + 2 + 2 + 8 + 3 + 3; /* length of element */
- *p++ = 0x91; /* remote operations protocol */
- *p++ = 0xa1; /* invoke component */
-
- *p++ = len_phone + len_sub + 2 + 2 + 8 + 3; /* length of data */
- *p++ = 0x02; /* invoke id tag, integer */
- *p++ = 0x01; /* length */
- *p++ = pc->prot.ni1.invoke_id; /* invoke id */
- *p++ = 0x02; /* operation value tag, integer */
- *p++ = 0x01; /* length */
- *p++ = 0x0D; /* Call Deflect */
-
- *p++ = 0x30; /* sequence phone number */
- *p++ = len_phone + 2 + 2 + 3 + len_sub; /* length */
-
- *p++ = 0x30; /* Deflected to UserNumber */
- *p++ = len_phone + 2 + len_sub; /* length */
- *p++ = 0x80; /* NumberDigits */
- *p++ = len_phone; /* length */
- for (l = 0; l < len_phone; l++)
- *p++ = pc->chan->setup.phone[l];
-
- if (len_sub)
- { *p++ = 0x04; /* called party subaddress */
- *p++ = len_sub - 2;
- while (*subp) *p++ = *subp++;
- }
-
- *p++ = 0x01; /* screening identifier */
- *p++ = 0x01;
- *p++ = pc->chan->setup.screen;
-
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l))) return;
- skb_put_data(skb, tmp, l);
-
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
-} /* l3ni1_redir_req */
-
-/********************************************/
-/* handle deflection request in early state */
-/********************************************/
-static void l3ni1_redir_req_early(struct l3_process *pc, u_char pr, void *arg)
-{
- l3ni1_proceed_req(pc, pr, arg);
- l3ni1_redir_req(pc, pr, arg);
-} /* l3ni1_redir_req_early */
-
-/***********************************************/
-/* handle special commands for this protocol. */
-/* Examples are call independent services like */
-/* remote operations with dummy callref. */
-/***********************************************/
-static int l3ni1_cmd_global(struct PStack *st, isdn_ctrl *ic)
-{ u_char id;
- u_char temp[265];
- u_char *p = temp;
- int i, l, proc_len;
- struct sk_buff *skb;
- struct l3_process *pc = NULL;
-
- switch (ic->arg)
- { case NI1_CMD_INVOKE:
- if (ic->parm.ni1_io.datalen < 0) return (-2); /* invalid parameter */
-
- for (proc_len = 1, i = ic->parm.ni1_io.proc >> 8; i; i++)
- i = i >> 8; /* add one byte */
- l = ic->parm.ni1_io.datalen + proc_len + 8; /* length excluding ie header */
- if (l > 255)
- return (-2); /* too long */
-
- if (!(id = new_invoke_id(st)))
- return (0); /* first get a invoke id -> return if no available */
-
- i = -1;
- MsgHead(p, i, MT_FACILITY); /* build message head */
- *p++ = 0x1C; /* Facility IE */
- *p++ = l; /* length of ie */
- *p++ = 0x91; /* remote operations */
- *p++ = 0xA1; /* invoke */
- *p++ = l - 3; /* length of invoke */
- *p++ = 0x02; /* invoke id tag */
- *p++ = 0x01; /* length is 1 */
- *p++ = id; /* invoke id */
- *p++ = 0x02; /* operation */
- *p++ = proc_len; /* length of operation */
-
- for (i = proc_len; i; i--)
- *p++ = (ic->parm.ni1_io.proc >> (i - 1)) & 0xFF;
- memcpy(p, ic->parm.ni1_io.data, ic->parm.ni1_io.datalen); /* copy data */
- l = (p - temp) + ic->parm.ni1_io.datalen; /* total length */
-
- if (ic->parm.ni1_io.timeout > 0) {
- pc = ni1_new_l3_process(st, -1);
- if (!pc) {
- free_invoke_id(st, id);
- return (-2);
- }
- /* remember id */
- pc->prot.ni1.ll_id = ic->parm.ni1_io.ll_id;
- /* and procedure */
- pc->prot.ni1.proc = ic->parm.ni1_io.proc;
- }
-
- if (!(skb = l3_alloc_skb(l)))
- { free_invoke_id(st, id);
- if (pc) ni1_release_l3_process(pc);
- return (-2);
- }
- skb_put_data(skb, temp, l);
-
- if (pc)
- { pc->prot.ni1.invoke_id = id; /* remember id */
- L3AddTimer(&pc->timer, ic->parm.ni1_io.timeout, CC_TNI1_IO | REQUEST);
- }
-
- l3_msg(st, DL_DATA | REQUEST, skb);
- ic->parm.ni1_io.hl_id = id; /* return id */
- return (0);
-
- case NI1_CMD_INVOKE_ABORT:
- if ((pc = l3ni1_search_dummy_proc(st, ic->parm.ni1_io.hl_id)))
- { L3DelTimer(&pc->timer); /* remove timer */
- ni1_release_l3_process(pc);
- return (0);
- }
- else
- { l3_debug(st, "l3ni1_cmd_global abort unknown id");
- return (-2);
- }
- break;
-
- default:
- l3_debug(st, "l3ni1_cmd_global unknown cmd 0x%lx", ic->arg);
- return (-1);
- } /* switch ic-> arg */
- return (-1);
-} /* l3ni1_cmd_global */
-
-static void
-l3ni1_io_timer(struct l3_process *pc)
-{ isdn_ctrl ic;
- struct IsdnCardState *cs = pc->st->l1.hardware;
-
- L3DelTimer(&pc->timer); /* remove timer */
-
- ic.driver = cs->myid;
- ic.command = ISDN_STAT_PROT;
- ic.arg = NI1_STAT_INVOKE_ERR;
- ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id;
- ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id;
- ic.parm.ni1_io.proc = pc->prot.ni1.proc;
- ic.parm.ni1_io.timeout = -1;
- ic.parm.ni1_io.datalen = 0;
- ic.parm.ni1_io.data = NULL;
- free_invoke_id(pc->st, pc->prot.ni1.invoke_id);
- pc->prot.ni1.invoke_id = 0; /* reset id */
-
- cs->iif.statcallb(&ic);
-
- ni1_release_l3_process(pc);
-} /* l3ni1_io_timer */
-
-static void
-l3ni1_release_ind(struct l3_process *pc, u_char pr, void *arg)
-{
- u_char *p;
- struct sk_buff *skb = arg;
- int callState = 0;
- p = skb->data;
-
- if ((p = findie(p, skb->len, IE_CALL_STATE, 0))) {
- p++;
- if (1 == *p++)
- callState = *p;
- }
- if (callState == 0) {
- /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... and 16.1
- * set down layer 3 without sending any message
- */
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
- newl3state(pc, 0);
- ni1_release_l3_process(pc);
- } else {
- pc->st->l3.l3l4(pc->st, CC_IGNORE | INDICATION, pc);
- }
-}
-
-static void
-l3ni1_dummy(struct l3_process *pc, u_char pr, void *arg)
-{
-}
-
-static void
-l3ni1_t302(struct l3_process *pc, u_char pr, void *arg)
-{
- L3DelTimer(&pc->timer);
- pc->para.loc = 0;
- pc->para.cause = 28; /* invalid number */
- l3ni1_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
-}
-
-static void
-l3ni1_t303(struct l3_process *pc, u_char pr, void *arg)
-{
- if (pc->N303 > 0) {
- pc->N303--;
- L3DelTimer(&pc->timer);
- l3ni1_setup_req(pc, pr, arg);
- } else {
- L3DelTimer(&pc->timer);
- l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, 102);
- pc->st->l3.l3l4(pc->st, CC_NOSETUP_RSP, pc);
- ni1_release_l3_process(pc);
- }
-}
-
-static void
-l3ni1_t304(struct l3_process *pc, u_char pr, void *arg)
-{
- L3DelTimer(&pc->timer);
- pc->para.loc = 0;
- pc->para.cause = 102;
- l3ni1_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
-
-}
-
-static void
-l3ni1_t305(struct l3_process *pc, u_char pr, void *arg)
-{
- u_char tmp[16];
- u_char *p = tmp;
- int l;
- struct sk_buff *skb;
- u_char cause = 16;
-
- L3DelTimer(&pc->timer);
- if (pc->para.cause != NO_CAUSE)
- cause = pc->para.cause;
-
- MsgHead(p, pc->callref, MT_RELEASE);
-
- *p++ = IE_CAUSE;
- *p++ = 0x2;
- *p++ = 0x80;
- *p++ = cause | 0x80;
-
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- skb_put_data(skb, tmp, l);
- newl3state(pc, 19);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
- L3AddTimer(&pc->timer, T308, CC_T308_1);
-}
-
-static void
-l3ni1_t310(struct l3_process *pc, u_char pr, void *arg)
-{
- L3DelTimer(&pc->timer);
- pc->para.loc = 0;
- pc->para.cause = 102;
- l3ni1_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
-}
-
-static void
-l3ni1_t313(struct l3_process *pc, u_char pr, void *arg)
-{
- L3DelTimer(&pc->timer);
- pc->para.loc = 0;
- pc->para.cause = 102;
- l3ni1_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc);
-}
-
-static void
-l3ni1_t308_1(struct l3_process *pc, u_char pr, void *arg)
-{
- newl3state(pc, 19);
- L3DelTimer(&pc->timer);
- l3ni1_message(pc, MT_RELEASE);
- L3AddTimer(&pc->timer, T308, CC_T308_2);
-}
-
-static void
-l3ni1_t308_2(struct l3_process *pc, u_char pr, void *arg)
-{
- L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc);
- ni1_release_l3_process(pc);
-}
-
-static void
-l3ni1_t318(struct l3_process *pc, u_char pr, void *arg)
-{
- L3DelTimer(&pc->timer);
- pc->para.cause = 102; /* Timer expiry */
- pc->para.loc = 0; /* local */
- pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc);
- newl3state(pc, 19);
- l3ni1_message(pc, MT_RELEASE);
- L3AddTimer(&pc->timer, T308, CC_T308_1);
-}
-
-static void
-l3ni1_t319(struct l3_process *pc, u_char pr, void *arg)
-{
- L3DelTimer(&pc->timer);
- pc->para.cause = 102; /* Timer expiry */
- pc->para.loc = 0; /* local */
- pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc);
- newl3state(pc, 10);
-}
-
-static void
-l3ni1_restart(struct l3_process *pc, u_char pr, void *arg)
-{
- L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
- ni1_release_l3_process(pc);
-}
-
-static void
-l3ni1_status(struct l3_process *pc, u_char pr, void *arg)
-{
- u_char *p;
- struct sk_buff *skb = arg;
- int ret;
- u_char cause = 0, callState = 0;
-
- if ((ret = l3ni1_get_cause(pc, skb))) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "STATUS get_cause ret(%d)", ret);
- if (ret < 0)
- cause = 96;
- else if (ret > 0)
- cause = 100;
- }
- if ((p = findie(skb->data, skb->len, IE_CALL_STATE, 0))) {
- p++;
- if (1 == *p++) {
- callState = *p;
- if (!ie_in_set(pc, *p, l3_valid_states))
- cause = 100;
- } else
- cause = 100;
- } else
- cause = 96;
- if (!cause) { /* no error before */
- ret = check_infoelements(pc, skb, ie_STATUS);
- if (ERR_IE_COMPREHENSION == ret)
- cause = 96;
- else if (ERR_IE_UNRECOGNIZED == ret)
- cause = 99;
- }
- if (cause) {
- u_char tmp;
-
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "STATUS error(%d/%d)", ret, cause);
- tmp = pc->para.cause;
- pc->para.cause = cause;
- l3ni1_status_send(pc, 0, NULL);
- if (cause == 99)
- pc->para.cause = tmp;
- else
- return;
- }
- cause = pc->para.cause;
- if (((cause & 0x7f) == 111) && (callState == 0)) {
- /* ETS 300-104 7.6.1, 8.6.1, 10.6.1...
- * if received MT_STATUS with cause == 111 and call
- * state == 0, then we must set down layer 3
- */
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
- newl3state(pc, 0);
- ni1_release_l3_process(pc);
- }
-}
-
-static void
-l3ni1_facility(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- int ret;
-
- ret = check_infoelements(pc, skb, ie_FACILITY);
- l3ni1_std_ie_err(pc, ret);
- {
- u_char *p;
- if ((p = findie(skb->data, skb->len, IE_FACILITY, 0)))
- l3ni1_parse_facility(pc->st, pc, pc->callref, p);
- }
-}
-
-static void
-l3ni1_suspend_req(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb;
- u_char tmp[32];
- u_char *p = tmp;
- u_char i, l;
- u_char *msg = pc->chan->setup.phone;
-
- MsgHead(p, pc->callref, MT_SUSPEND);
- l = *msg++;
- if (l && (l <= 10)) { /* Max length 10 octets */
- *p++ = IE_CALL_ID;
- *p++ = l;
- for (i = 0; i < l; i++)
- *p++ = *msg++;
- } else if (l) {
- l3_debug(pc->st, "SUS wrong CALL_ID len %d", l);
- return;
- }
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- skb_put_data(skb, tmp, l);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
- newl3state(pc, 15);
- L3AddTimer(&pc->timer, T319, CC_T319);
-}
-
-static void
-l3ni1_suspend_ack(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- int ret;
-
- L3DelTimer(&pc->timer);
- newl3state(pc, 0);
- pc->para.cause = NO_CAUSE;
- pc->st->l3.l3l4(pc->st, CC_SUSPEND | CONFIRM, pc);
- /* We don't handle suspend_ack for IE errors now */
- if ((ret = check_infoelements(pc, skb, ie_SUSPEND_ACKNOWLEDGE)))
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "SUSPACK check ie(%d)", ret);
- ni1_release_l3_process(pc);
-}
-
-static void
-l3ni1_suspend_rej(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- int ret;
-
- if ((ret = l3ni1_get_cause(pc, skb))) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "SUSP_REJ get_cause ret(%d)", ret);
- if (ret < 0)
- pc->para.cause = 96;
- else
- pc->para.cause = 100;
- l3ni1_status_send(pc, pr, NULL);
- return;
- }
- ret = check_infoelements(pc, skb, ie_SUSPEND_REJECT);
- if (ERR_IE_COMPREHENSION == ret) {
- l3ni1_std_ie_err(pc, ret);
- return;
- }
- L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc);
- newl3state(pc, 10);
- if (ret) /* STATUS for none mandatory IE errors after actions are taken */
- l3ni1_std_ie_err(pc, ret);
-}
-
-static void
-l3ni1_resume_req(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb;
- u_char tmp[32];
- u_char *p = tmp;
- u_char i, l;
- u_char *msg = pc->para.setup.phone;
-
- MsgHead(p, pc->callref, MT_RESUME);
-
- l = *msg++;
- if (l && (l <= 10)) { /* Max length 10 octets */
- *p++ = IE_CALL_ID;
- *p++ = l;
- for (i = 0; i < l; i++)
- *p++ = *msg++;
- } else if (l) {
- l3_debug(pc->st, "RES wrong CALL_ID len %d", l);
- return;
- }
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- skb_put_data(skb, tmp, l);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
- newl3state(pc, 17);
- L3AddTimer(&pc->timer, T318, CC_T318);
-}
-
-static void
-l3ni1_resume_ack(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- int id, ret;
-
- if ((id = l3ni1_get_channel_id(pc, skb)) > 0) {
- if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "resume ack with wrong chid %x", id);
- pc->para.cause = 100;
- l3ni1_status_send(pc, pr, NULL);
- return;
- }
- pc->para.bchannel = id;
- } else if (1 == pc->state) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "resume ack without chid (ret %d)", id);
- pc->para.cause = 96;
- l3ni1_status_send(pc, pr, NULL);
- return;
- }
- ret = check_infoelements(pc, skb, ie_RESUME_ACKNOWLEDGE);
- if (ERR_IE_COMPREHENSION == ret) {
- l3ni1_std_ie_err(pc, ret);
- return;
- }
- L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_RESUME | CONFIRM, pc);
- newl3state(pc, 10);
- if (ret) /* STATUS for none mandatory IE errors after actions are taken */
- l3ni1_std_ie_err(pc, ret);
-}
-
-static void
-l3ni1_resume_rej(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
- int ret;
-
- if ((ret = l3ni1_get_cause(pc, skb))) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "RES_REJ get_cause ret(%d)", ret);
- if (ret < 0)
- pc->para.cause = 96;
- else
- pc->para.cause = 100;
- l3ni1_status_send(pc, pr, NULL);
- return;
- }
- ret = check_infoelements(pc, skb, ie_RESUME_REJECT);
- if (ERR_IE_COMPREHENSION == ret) {
- l3ni1_std_ie_err(pc, ret);
- return;
- }
- L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc);
- newl3state(pc, 0);
- if (ret) /* STATUS for none mandatory IE errors after actions are taken */
- l3ni1_std_ie_err(pc, ret);
- ni1_release_l3_process(pc);
-}
-
-static void
-l3ni1_global_restart(struct l3_process *pc, u_char pr, void *arg)
-{
- u_char tmp[32];
- u_char *p;
- u_char ri, ch = 0, chan = 0;
- int l;
- struct sk_buff *skb = arg;
- struct l3_process *up;
-
- newl3state(pc, 2);
- L3DelTimer(&pc->timer);
- p = skb->data;
- if ((p = findie(p, skb->len, IE_RESTART_IND, 0))) {
- ri = p[2];
- l3_debug(pc->st, "Restart %x", ri);
- } else {
- l3_debug(pc->st, "Restart without restart IE");
- ri = 0x86;
- }
- p = skb->data;
- if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) {
- chan = p[2] & 3;
- ch = p[2];
- if (pc->st->l3.debug)
- l3_debug(pc->st, "Restart for channel %d", chan);
- }
- newl3state(pc, 2);
- up = pc->st->l3.proc;
- while (up) {
- if ((ri & 7) == 7)
- up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up);
- else if (up->para.bchannel == chan)
- up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up);
-
- up = up->next;
- }
- p = tmp;
- MsgHead(p, pc->callref, MT_RESTART_ACKNOWLEDGE);
- if (chan) {
- *p++ = IE_CHANNEL_ID;
- *p++ = 1;
- *p++ = ch | 0x80;
- }
- *p++ = 0x79; /* RESTART Ind */
- *p++ = 1;
- *p++ = ri;
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- skb_put_data(skb, tmp, l);
- newl3state(pc, 0);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
-}
-
-static void
-l3ni1_dl_reset(struct l3_process *pc, u_char pr, void *arg)
-{
- pc->para.cause = 0x29; /* Temporary failure */
- pc->para.loc = 0;
- l3ni1_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
-}
-
-static void
-l3ni1_dl_release(struct l3_process *pc, u_char pr, void *arg)
-{
- newl3state(pc, 0);
- pc->para.cause = 0x1b; /* Destination out of order */
- pc->para.loc = 0;
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
- release_l3_process(pc);
-}
-
-static void
-l3ni1_dl_reestablish(struct l3_process *pc, u_char pr, void *arg)
-{
- L3DelTimer(&pc->timer);
- L3AddTimer(&pc->timer, T309, CC_T309);
- l3_msg(pc->st, DL_ESTABLISH | REQUEST, NULL);
-}
-
-static void
-l3ni1_dl_reest_status(struct l3_process *pc, u_char pr, void *arg)
-{
- L3DelTimer(&pc->timer);
-
- pc->para.cause = 0x1F; /* normal, unspecified */
- l3ni1_status_send(pc, 0, NULL);
-}
-
-static void l3ni1_SendSpid(struct l3_process *pc, u_char pr, struct sk_buff *skb, int iNewState)
-{
- u_char *p;
- char *pSPID;
- struct Channel *pChan = pc->st->lli.userdata;
- int l;
-
- if (skb)
- dev_kfree_skb(skb);
-
- if (!(pSPID = strchr(pChan->setup.eazmsn, ':')))
- {
- printk(KERN_ERR "SPID not supplied in EAZMSN %s\n", pChan->setup.eazmsn);
- newl3state(pc, 0);
- pc->st->l3.l3l2(pc->st, DL_RELEASE | REQUEST, NULL);
- return;
- }
-
- l = strlen(++pSPID);
- if (!(skb = l3_alloc_skb(5 + l)))
- {
- printk(KERN_ERR "HiSax can't get memory to send SPID\n");
- return;
- }
-
- p = skb_put(skb, 5);
- *p++ = PROTO_DIS_EURO;
- *p++ = 0;
- *p++ = MT_INFORMATION;
- *p++ = IE_SPID;
- *p++ = l;
-
- skb_put_data(skb, pSPID, l);
-
- newl3state(pc, iNewState);
-
- L3DelTimer(&pc->timer);
- L3AddTimer(&pc->timer, TSPID, CC_TSPID);
-
- pc->st->l3.l3l2(pc->st, DL_DATA | REQUEST, skb);
-}
-
-static void l3ni1_spid_send(struct l3_process *pc, u_char pr, void *arg)
-{
- l3ni1_SendSpid(pc, pr, arg, 20);
-}
-
-static void l3ni1_spid_epid(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
-
- if (skb->data[1] == 0)
- if (skb->data[3] == IE_ENDPOINT_ID)
- {
- L3DelTimer(&pc->timer);
- newl3state(pc, 0);
- l3_msg(pc->st, DL_ESTABLISH | CONFIRM, NULL);
- }
- dev_kfree_skb(skb);
-}
-
-static void l3ni1_spid_tout(struct l3_process *pc, u_char pr, void *arg)
-{
- if (pc->state < 22)
- l3ni1_SendSpid(pc, pr, arg, pc->state + 1);
- else
- {
- L3DelTimer(&pc->timer);
- dev_kfree_skb(arg);
-
- printk(KERN_ERR "SPID not accepted\n");
- newl3state(pc, 0);
- pc->st->l3.l3l2(pc->st, DL_RELEASE | REQUEST, NULL);
- }
-}
-
-/* *INDENT-OFF* */
-static struct stateentry downstatelist[] =
-{
- {SBIT(0),
- CC_SETUP | REQUEST, l3ni1_setup_req},
- {SBIT(0),
- CC_RESUME | REQUEST, l3ni1_resume_req},
- {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(25),
- CC_DISCONNECT | REQUEST, l3ni1_disconnect_req},
- {SBIT(12),
- CC_RELEASE | REQUEST, l3ni1_release_req},
- {ALL_STATES,
- CC_RESTART | REQUEST, l3ni1_restart},
- {SBIT(6) | SBIT(25),
- CC_IGNORE | REQUEST, l3ni1_reset},
- {SBIT(6) | SBIT(25),
- CC_REJECT | REQUEST, l3ni1_reject_req},
- {SBIT(6) | SBIT(25),
- CC_PROCEED_SEND | REQUEST, l3ni1_proceed_req},
- {SBIT(6),
- CC_MORE_INFO | REQUEST, l3ni1_setup_ack_req},
- {SBIT(25),
- CC_MORE_INFO | REQUEST, l3ni1_dummy},
- {SBIT(6) | SBIT(9) | SBIT(25),
- CC_ALERTING | REQUEST, l3ni1_alert_req},
- {SBIT(6) | SBIT(7) | SBIT(9) | SBIT(25),
- CC_SETUP | RESPONSE, l3ni1_setup_rsp},
- {SBIT(10),
- CC_SUSPEND | REQUEST, l3ni1_suspend_req},
- {SBIT(7) | SBIT(9) | SBIT(25),
- CC_REDIR | REQUEST, l3ni1_redir_req},
- {SBIT(6),
- CC_REDIR | REQUEST, l3ni1_redir_req_early},
- {SBIT(9) | SBIT(25),
- CC_DISCONNECT | REQUEST, l3ni1_disconnect_req},
- {SBIT(25),
- CC_T302, l3ni1_t302},
- {SBIT(1),
- CC_T303, l3ni1_t303},
- {SBIT(2),
- CC_T304, l3ni1_t304},
- {SBIT(3),
- CC_T310, l3ni1_t310},
- {SBIT(8),
- CC_T313, l3ni1_t313},
- {SBIT(11),
- CC_T305, l3ni1_t305},
- {SBIT(15),
- CC_T319, l3ni1_t319},
- {SBIT(17),
- CC_T318, l3ni1_t318},
- {SBIT(19),
- CC_T308_1, l3ni1_t308_1},
- {SBIT(19),
- CC_T308_2, l3ni1_t308_2},
- {SBIT(10),
- CC_T309, l3ni1_dl_release},
- { SBIT(20) | SBIT(21) | SBIT(22),
- CC_TSPID, l3ni1_spid_tout },
-};
-
-static struct stateentry datastatelist[] =
-{
- {ALL_STATES,
- MT_STATUS_ENQUIRY, l3ni1_status_enq},
- {ALL_STATES,
- MT_FACILITY, l3ni1_facility},
- {SBIT(19),
- MT_STATUS, l3ni1_release_ind},
- {ALL_STATES,
- MT_STATUS, l3ni1_status},
- {SBIT(0),
- MT_SETUP, l3ni1_setup},
- {SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) |
- SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25),
- MT_SETUP, l3ni1_dummy},
- {SBIT(1) | SBIT(2),
- MT_CALL_PROCEEDING, l3ni1_call_proc},
- {SBIT(1),
- MT_SETUP_ACKNOWLEDGE, l3ni1_setup_ack},
- {SBIT(2) | SBIT(3),
- MT_ALERTING, l3ni1_alerting},
- {SBIT(2) | SBIT(3),
- MT_PROGRESS, l3ni1_progress},
- {SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) |
- SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25),
- MT_INFORMATION, l3ni1_information},
- {SBIT(10) | SBIT(11) | SBIT(15),
- MT_NOTIFY, l3ni1_notify},
- {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10) |
- SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25),
- MT_RELEASE_COMPLETE, l3ni1_release_cmpl},
- {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(25),
- MT_RELEASE, l3ni1_release},
- {SBIT(19), MT_RELEASE, l3ni1_release_ind},
- {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(15) | SBIT(17) | SBIT(25),
- MT_DISCONNECT, l3ni1_disconnect},
- {SBIT(19),
- MT_DISCONNECT, l3ni1_dummy},
- {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4),
- MT_CONNECT, l3ni1_connect},
- {SBIT(8),
- MT_CONNECT_ACKNOWLEDGE, l3ni1_connect_ack},
- {SBIT(15),
- MT_SUSPEND_ACKNOWLEDGE, l3ni1_suspend_ack},
- {SBIT(15),
- MT_SUSPEND_REJECT, l3ni1_suspend_rej},
- {SBIT(17),
- MT_RESUME_ACKNOWLEDGE, l3ni1_resume_ack},
- {SBIT(17),
- MT_RESUME_REJECT, l3ni1_resume_rej},
-};
-
-static struct stateentry globalmes_list[] =
-{
- {ALL_STATES,
- MT_STATUS, l3ni1_status},
- {SBIT(0),
- MT_RESTART, l3ni1_global_restart},
-/* {SBIT(1),
- MT_RESTART_ACKNOWLEDGE, l3ni1_restart_ack},
-*/
- { SBIT(0), MT_DL_ESTABLISHED, l3ni1_spid_send },
- { SBIT(20) | SBIT(21) | SBIT(22), MT_INFORMATION, l3ni1_spid_epid },
-};
-
-static struct stateentry manstatelist[] =
-{
- {SBIT(2),
- DL_ESTABLISH | INDICATION, l3ni1_dl_reset},
- {SBIT(10),
- DL_ESTABLISH | CONFIRM, l3ni1_dl_reest_status},
- {SBIT(10),
- DL_RELEASE | INDICATION, l3ni1_dl_reestablish},
- {ALL_STATES,
- DL_RELEASE | INDICATION, l3ni1_dl_release},
-};
-
-/* *INDENT-ON* */
-
-
-static void
-global_handler(struct PStack *st, int mt, struct sk_buff *skb)
-{
- u_char tmp[16];
- u_char *p = tmp;
- int l;
- int i;
- struct l3_process *proc = st->l3.global;
-
- if (skb)
- proc->callref = skb->data[2]; /* cr flag */
- else
- proc->callref = 0;
- for (i = 0; i < ARRAY_SIZE(globalmes_list); i++)
- if ((mt == globalmes_list[i].primitive) &&
- ((1 << proc->state) & globalmes_list[i].state))
- break;
- if (i == ARRAY_SIZE(globalmes_list)) {
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "ni1 global state %d mt %x unhandled",
- proc->state, mt);
- }
- MsgHead(p, proc->callref, MT_STATUS);
- *p++ = IE_CAUSE;
- *p++ = 0x2;
- *p++ = 0x80;
- *p++ = 81 | 0x80; /* invalid cr */
- *p++ = 0x14; /* CallState */
- *p++ = 0x1;
- *p++ = proc->state & 0x3f;
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- skb_put_data(skb, tmp, l);
- l3_msg(proc->st, DL_DATA | REQUEST, skb);
- } else {
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "ni1 global %d mt %x",
- proc->state, mt);
- }
- globalmes_list[i].rout(proc, mt, skb);
- }
-}
-
-static void
-ni1up(struct PStack *st, int pr, void *arg)
-{
- int i, mt, cr, callState;
- char *ptr;
- u_char *p;
- struct sk_buff *skb = arg;
- struct l3_process *proc;
-
- switch (pr) {
- case (DL_DATA | INDICATION):
- case (DL_UNIT_DATA | INDICATION):
- break;
- case (DL_ESTABLISH | INDICATION):
- case (DL_RELEASE | INDICATION):
- case (DL_RELEASE | CONFIRM):
- l3_msg(st, pr, arg);
- return;
- break;
-
- case (DL_ESTABLISH | CONFIRM):
- global_handler(st, MT_DL_ESTABLISHED, NULL);
- return;
-
- default:
- printk(KERN_ERR "HiSax ni1up unknown pr=%04x\n", pr);
- return;
- }
- if (skb->len < 3) {
- l3_debug(st, "ni1up frame too short(%d)", skb->len);
- dev_kfree_skb(skb);
- return;
- }
-
- if (skb->data[0] != PROTO_DIS_EURO) {
- if (st->l3.debug & L3_DEB_PROTERR) {
- l3_debug(st, "ni1up%sunexpected discriminator %x message len %d",
- (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
- skb->data[0], skb->len);
- }
- dev_kfree_skb(skb);
- return;
- }
- cr = getcallref(skb->data);
- if (skb->len < ((skb->data[1] & 0x0f) + 3)) {
- l3_debug(st, "ni1up frame too short(%d)", skb->len);
- dev_kfree_skb(skb);
- return;
- }
- mt = skb->data[skb->data[1] + 2];
- if (st->l3.debug & L3_DEB_STATE)
- l3_debug(st, "ni1up cr %d", cr);
- if (cr == -2) { /* wrong Callref */
- if (st->l3.debug & L3_DEB_WARN)
- l3_debug(st, "ni1up wrong Callref");
- dev_kfree_skb(skb);
- return;
- } else if (cr == -1) { /* Dummy Callref */
- if (mt == MT_FACILITY)
- {
- if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) {
- l3ni1_parse_facility(st, NULL,
- (pr == (DL_DATA | INDICATION)) ? -1 : -2, p);
- dev_kfree_skb(skb);
- return;
- }
- }
- else
- {
- global_handler(st, mt, skb);
- return;
- }
-
- if (st->l3.debug & L3_DEB_WARN)
- l3_debug(st, "ni1up dummy Callref (no facility msg or ie)");
- dev_kfree_skb(skb);
- return;
- } else if ((((skb->data[1] & 0x0f) == 1) && (0 == (cr & 0x7f))) ||
- (((skb->data[1] & 0x0f) == 2) && (0 == (cr & 0x7fff)))) { /* Global CallRef */
- if (st->l3.debug & L3_DEB_STATE)
- l3_debug(st, "ni1up Global CallRef");
- global_handler(st, mt, skb);
- dev_kfree_skb(skb);
- return;
- } else if (!(proc = getl3proc(st, cr))) {
- /* No transaction process exist, that means no call with
- * this callreference is active
- */
- if (mt == MT_SETUP) {
- /* Setup creates a new transaction process */
- if (skb->data[2] & 0x80) {
- /* Setup with wrong CREF flag */
- if (st->l3.debug & L3_DEB_STATE)
- l3_debug(st, "ni1up wrong CRef flag");
- dev_kfree_skb(skb);
- return;
- }
- if (!(proc = ni1_new_l3_process(st, cr))) {
- /* May be to answer with RELEASE_COMPLETE and
- * CAUSE 0x2f "Resource unavailable", but this
- * need a new_l3_process too ... arghh
- */
- dev_kfree_skb(skb);
- return;
- }
- } else if (mt == MT_STATUS) {
- if ((ptr = findie(skb->data, skb->len, IE_CAUSE, 0)) != NULL) {
- ptr++;
- if (*ptr++ == 2)
- ptr++;
- }
- callState = 0;
- if ((ptr = findie(skb->data, skb->len, IE_CALL_STATE, 0)) != NULL) {
- ptr++;
- if (*ptr++ == 2)
- ptr++;
- callState = *ptr;
- }
- /* ETS 300-104 part 2.4.1
- * if setup has not been made and a message type
- * MT_STATUS is received with call state == 0,
- * we must send nothing
- */
- if (callState != 0) {
- /* ETS 300-104 part 2.4.2
- * if setup has not been made and a message type
- * MT_STATUS is received with call state != 0,
- * we must send MT_RELEASE_COMPLETE cause 101
- */
- if ((proc = ni1_new_l3_process(st, cr))) {
- proc->para.cause = 101;
- l3ni1_msg_without_setup(proc, 0, NULL);
- }
- }
- dev_kfree_skb(skb);
- return;
- } else if (mt == MT_RELEASE_COMPLETE) {
- dev_kfree_skb(skb);
- return;
- } else {
- /* ETS 300-104 part 2
- * if setup has not been made and a message type
- * (except MT_SETUP and RELEASE_COMPLETE) is received,
- * we must send MT_RELEASE_COMPLETE cause 81 */
- dev_kfree_skb(skb);
- if ((proc = ni1_new_l3_process(st, cr))) {
- proc->para.cause = 81;
- l3ni1_msg_without_setup(proc, 0, NULL);
- }
- return;
- }
- }
- if (l3ni1_check_messagetype_validity(proc, mt, skb)) {
- dev_kfree_skb(skb);
- return;
- }
- if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL)
- l3ni1_deliver_display(proc, pr, p); /* Display IE included */
- for (i = 0; i < ARRAY_SIZE(datastatelist); i++)
- if ((mt == datastatelist[i].primitive) &&
- ((1 << proc->state) & datastatelist[i].state))
- break;
- if (i == ARRAY_SIZE(datastatelist)) {
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "ni1up%sstate %d mt %#x unhandled",
- (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
- proc->state, mt);
- }
- if ((MT_RELEASE_COMPLETE != mt) && (MT_RELEASE != mt)) {
- proc->para.cause = 101;
- l3ni1_status_send(proc, pr, skb);
- }
- } else {
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "ni1up%sstate %d mt %x",
- (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
- proc->state, mt);
- }
- datastatelist[i].rout(proc, pr, skb);
- }
- dev_kfree_skb(skb);
- return;
-}
-
-static void
-ni1down(struct PStack *st, int pr, void *arg)
-{
- int i, cr;
- struct l3_process *proc;
- struct Channel *chan;
-
- if ((DL_ESTABLISH | REQUEST) == pr) {
- l3_msg(st, pr, NULL);
- return;
- } else if (((CC_SETUP | REQUEST) == pr) || ((CC_RESUME | REQUEST) == pr)) {
- chan = arg;
- cr = newcallref();
- cr |= 0x80;
- if ((proc = ni1_new_l3_process(st, cr))) {
- proc->chan = chan;
- chan->proc = proc;
- memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm));
- proc->callref = cr;
- }
- } else {
- proc = arg;
- }
- if (!proc) {
- printk(KERN_ERR "HiSax ni1down without proc pr=%04x\n", pr);
- return;
- }
-
- if (pr == (CC_TNI1_IO | REQUEST)) {
- l3ni1_io_timer(proc); /* timer expires */
- return;
- }
-
- for (i = 0; i < ARRAY_SIZE(downstatelist); i++)
- if ((pr == downstatelist[i].primitive) &&
- ((1 << proc->state) & downstatelist[i].state))
- break;
- if (i == ARRAY_SIZE(downstatelist)) {
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "ni1down state %d prim %#x unhandled",
- proc->state, pr);
- }
- } else {
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "ni1down state %d prim %#x",
- proc->state, pr);
- }
- downstatelist[i].rout(proc, pr, arg);
- }
-}
-
-static void
-ni1man(struct PStack *st, int pr, void *arg)
-{
- int i;
- struct l3_process *proc = arg;
-
- if (!proc) {
- printk(KERN_ERR "HiSax ni1man without proc pr=%04x\n", pr);
- return;
- }
- for (i = 0; i < ARRAY_SIZE(manstatelist); i++)
- if ((pr == manstatelist[i].primitive) &&
- ((1 << proc->state) & manstatelist[i].state))
- break;
- if (i == ARRAY_SIZE(manstatelist)) {
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "cr %d ni1man state %d prim %#x unhandled",
- proc->callref & 0x7f, proc->state, pr);
- }
- } else {
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "cr %d ni1man state %d prim %#x",
- proc->callref & 0x7f, proc->state, pr);
- }
- manstatelist[i].rout(proc, pr, arg);
- }
-}
-
-void
-setstack_ni1(struct PStack *st)
-{
- char tmp[64];
- int i;
-
- st->lli.l4l3 = ni1down;
- st->lli.l4l3_proto = l3ni1_cmd_global;
- st->l2.l2l3 = ni1up;
- st->l3.l3ml3 = ni1man;
- st->l3.N303 = 1;
- st->prot.ni1.last_invoke_id = 0;
- st->prot.ni1.invoke_used[0] = 1; /* Bit 0 must always be set to 1 */
- i = 1;
- while (i < 32)
- st->prot.ni1.invoke_used[i++] = 0;
-
- if (!(st->l3.global = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) {
- printk(KERN_ERR "HiSax can't get memory for ni1 global CR\n");
- } else {
- st->l3.global->state = 0;
- st->l3.global->callref = 0;
- st->l3.global->next = NULL;
- st->l3.global->debug = L3_DEB_WARN;
- st->l3.global->st = st;
- st->l3.global->N303 = 1;
- st->l3.global->prot.ni1.invoke_id = 0;
-
- L3InitTimer(st->l3.global, &st->l3.global->timer);
- }
- strcpy(tmp, ni1_revision);
- printk(KERN_INFO "HiSax: National ISDN-1 Rev. %s\n", HiSax_getrev(tmp));
-}
diff --git a/drivers/isdn/hisax/l3ni1.h b/drivers/isdn/hisax/l3ni1.h
deleted file mode 100644
index 99d37d2cea4f..000000000000
--- a/drivers/isdn/hisax/l3ni1.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/* $Id: l3ni1.h,v 2.3.6.2 2001/09/23 22:24:50 kai Exp $
- *
- * NI1 D-channel protocol
- *
- * Author Matt Henderson & Guy Ellis
- * Copyright by Traverse Technologies Pty Ltd, www.travers.com.au
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * 2000.6.6 Initial implementation of routines for US NI1
- * Layer 3 protocol based on the EURO/DSS1 D-channel protocol
- * driver written by Karsten Keil et al. Thanks also for the
- * code provided by Ragnar Paulson.
- *
- */
-
-#ifndef l3ni1_process
-
-#define T302 15000
-#define T303 4000
-#define T304 30000
-#define T305 30000
-#define T308 4000
-/* for layer 1 certification T309 < layer1 T3 (e.g. 4000) */
-/* This makes some tests easier and quicker */
-#define T309 40000
-#define T310 30000
-#define T313 4000
-#define T318 4000
-#define T319 4000
-#define TSPID 5000 /* was 2000 - Guy Ellis */
-
-/*
- * Message-Types
- */
-
-#define MT_ALERTING 0x01
-#define MT_CALL_PROCEEDING 0x02
-#define MT_CONNECT 0x07
-#define MT_CONNECT_ACKNOWLEDGE 0x0f
-#define MT_PROGRESS 0x03
-#define MT_SETUP 0x05
-#define MT_SETUP_ACKNOWLEDGE 0x0d
-#define MT_RESUME 0x26
-#define MT_RESUME_ACKNOWLEDGE 0x2e
-#define MT_RESUME_REJECT 0x22
-#define MT_SUSPEND 0x25
-#define MT_SUSPEND_ACKNOWLEDGE 0x2d
-#define MT_SUSPEND_REJECT 0x21
-#define MT_USER_INFORMATION 0x20
-#define MT_DISCONNECT 0x45
-#define MT_RELEASE 0x4d
-#define MT_RELEASE_COMPLETE 0x5a
-#define MT_RESTART 0x46
-#define MT_RESTART_ACKNOWLEDGE 0x4e
-#define MT_SEGMENT 0x60
-#define MT_CONGESTION_CONTROL 0x79
-#define MT_INFORMATION 0x7b
-#define MT_FACILITY 0x62
-#define MT_NOTIFY 0x6e
-#define MT_STATUS 0x7d
-#define MT_STATUS_ENQUIRY 0x75
-#define MT_DL_ESTABLISHED 0xfe
-
-#define IE_SEGMENT 0x00
-#define IE_BEARER 0x04
-#define IE_CAUSE 0x08
-#define IE_CALL_ID 0x10
-#define IE_CALL_STATE 0x14
-#define IE_CHANNEL_ID 0x18
-#define IE_FACILITY 0x1c
-#define IE_PROGRESS 0x1e
-#define IE_NET_FAC 0x20
-#define IE_NOTIFY 0x27
-#define IE_DISPLAY 0x28
-#define IE_DATE 0x29
-#define IE_KEYPAD 0x2c
-#define IE_SIGNAL 0x34
-#define IE_SPID 0x3a
-#define IE_ENDPOINT_ID 0x3b
-#define IE_INFORATE 0x40
-#define IE_E2E_TDELAY 0x42
-#define IE_TDELAY_SEL 0x43
-#define IE_PACK_BINPARA 0x44
-#define IE_PACK_WINSIZE 0x45
-#define IE_PACK_SIZE 0x46
-#define IE_CUG 0x47
-#define IE_REV_CHARGE 0x4a
-#define IE_CONNECT_PN 0x4c
-#define IE_CONNECT_SUB 0x4d
-#define IE_CALLING_PN 0x6c
-#define IE_CALLING_SUB 0x6d
-#define IE_CALLED_PN 0x70
-#define IE_CALLED_SUB 0x71
-#define IE_REDIR_NR 0x74
-#define IE_TRANS_SEL 0x78
-#define IE_RESTART_IND 0x79
-#define IE_LLC 0x7c
-#define IE_HLC 0x7d
-#define IE_USER_USER 0x7e
-#define IE_ESCAPE 0x7f
-#define IE_SHIFT 0x90
-#define IE_MORE_DATA 0xa0
-#define IE_COMPLETE 0xa1
-#define IE_CONGESTION 0xb0
-#define IE_REPEAT 0xd0
-
-#define IE_MANDATORY 0x0100
-/* mandatory not in every case */
-#define IE_MANDATORY_1 0x0200
-
-#define ERR_IE_COMPREHENSION 1
-#define ERR_IE_UNRECOGNIZED -1
-#define ERR_IE_LENGTH -2
-#define ERR_IE_SEQUENCE -3
-
-#else /* only l3ni1_process */
-
-/* l3ni1 specific data in l3 process */
-typedef struct
-{ unsigned char invoke_id; /* used invoke id in remote ops, 0 = not active */
- ulong ll_id; /* remebered ll id */
- u8 remote_operation; /* handled remote operation, 0 = not active */
- int proc; /* rememered procedure */
- ulong remote_result; /* result of remote operation for statcallb */
- char uus1_data[35]; /* data send during alerting or disconnect */
-} ni1_proc_priv;
-
-/* l3dni1 specific data in protocol stack */
-typedef struct
-{ unsigned char last_invoke_id; /* last used value for invoking */
- unsigned char invoke_used[32]; /* 256 bits for 256 values */
-} ni1_stk_priv;
-
-#endif /* only l3dni1_process */
diff --git a/drivers/isdn/hisax/lmgr.c b/drivers/isdn/hisax/lmgr.c
deleted file mode 100644
index 5b63eb6601aa..000000000000
--- a/drivers/isdn/hisax/lmgr.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/* $Id: lmgr.c,v 1.7.6.2 2001/09/23 22:24:50 kai Exp $
- *
- * Layermanagement module
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include "hisax.h"
-
-static void
-error_handling_dchan(struct PStack *st, int Error)
-{
- switch (Error) {
- case 'C':
- case 'D':
- case 'G':
- case 'H':
- st->l2.l2tei(st, MDL_ERROR | REQUEST, NULL);
- break;
- }
-}
-
-static void
-hisax_manager(struct PStack *st, int pr, void *arg)
-{
- long Code;
-
- switch (pr) {
- case (MDL_ERROR | INDICATION):
- Code = (long) arg;
- HiSax_putstatus(st->l1.hardware, "manager: MDL_ERROR",
- " %c %s", (char)Code,
- test_bit(FLG_LAPD, &st->l2.flag) ?
- "D-channel" : "B-channel");
- if (test_bit(FLG_LAPD, &st->l2.flag))
- error_handling_dchan(st, Code);
- break;
- }
-}
-
-void
-setstack_manager(struct PStack *st)
-{
- st->ma.layer = hisax_manager;
-}
diff --git a/drivers/isdn/hisax/mic.c b/drivers/isdn/hisax/mic.c
deleted file mode 100644
index 93398676f78f..000000000000
--- a/drivers/isdn/hisax/mic.c
+++ /dev/null
@@ -1,235 +0,0 @@
-/* $Id: mic.c,v 1.12.2.4 2004/01/13 23:48:39 keil Exp $
- *
- * low level stuff for mic cards
- *
- * Author Stephan von Krawczynski
- * Copyright by Stephan von Krawczynski <skraw@ithnet.com>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/init.h>
-#include "hisax.h"
-#include "isac.h"
-#include "hscx.h"
-#include "isdnl1.h"
-
-static const char *mic_revision = "$Revision: 1.12.2.4 $";
-
-#define byteout(addr, val) outb(val, addr)
-#define bytein(addr) inb(addr)
-
-#define MIC_ISAC 2
-#define MIC_HSCX 1
-#define MIC_ADR 7
-
-/* CARD_ADR (Write) */
-#define MIC_RESET 0x3 /* same as DOS driver */
-
-static inline u_char
-readreg(unsigned int ale, unsigned int adr, u_char off)
-{
- register u_char ret;
-
- byteout(ale, off);
- ret = bytein(adr);
- return (ret);
-}
-
-static inline void
-readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
-{
- byteout(ale, off);
- insb(adr, data, size);
-}
-
-
-static inline void
-writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
-{
- byteout(ale, off);
- byteout(adr, data);
-}
-
-static inline void
-writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
-{
- byteout(ale, off);
- outsb(adr, data, size);
-}
-
-/* Interface functions */
-
-static u_char
-ReadISAC(struct IsdnCardState *cs, u_char offset)
-{
- return (readreg(cs->hw.mic.adr, cs->hw.mic.isac, offset));
-}
-
-static void
-WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
-{
- writereg(cs->hw.mic.adr, cs->hw.mic.isac, offset, value);
-}
-
-static void
-ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- readfifo(cs->hw.mic.adr, cs->hw.mic.isac, 0, data, size);
-}
-
-static void
-WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- writefifo(cs->hw.mic.adr, cs->hw.mic.isac, 0, data, size);
-}
-
-static u_char
-ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
-{
- return (readreg(cs->hw.mic.adr,
- cs->hw.mic.hscx, offset + (hscx ? 0x40 : 0)));
-}
-
-static void
-WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
-{
- writereg(cs->hw.mic.adr,
- cs->hw.mic.hscx, offset + (hscx ? 0x40 : 0), value);
-}
-
-/*
- * fast interrupt HSCX stuff goes here
- */
-
-#define READHSCX(cs, nr, reg) readreg(cs->hw.mic.adr, \
- cs->hw.mic.hscx, reg + (nr ? 0x40 : 0))
-#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.mic.adr, \
- cs->hw.mic.hscx, reg + (nr ? 0x40 : 0), data)
-
-#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.mic.adr, \
- cs->hw.mic.hscx, (nr ? 0x40 : 0), ptr, cnt)
-
-#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.mic.adr, \
- cs->hw.mic.hscx, (nr ? 0x40 : 0), ptr, cnt)
-
-#include "hscx_irq.c"
-
-static irqreturn_t
-mic_interrupt(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_char val;
- u_long flags;
-
- spin_lock_irqsave(&cs->lock, flags);
- val = readreg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_ISTA + 0x40);
-Start_HSCX:
- if (val)
- hscx_int_main(cs, val);
- val = readreg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_ISTA);
-Start_ISAC:
- if (val)
- isac_interrupt(cs, val);
- val = readreg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_ISTA + 0x40);
- if (val) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "HSCX IntStat after IntRoutine");
- goto Start_HSCX;
- }
- val = readreg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_ISTA);
- if (val) {
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ISAC IntStat after IntRoutine");
- goto Start_ISAC;
- }
- writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK, 0xFF);
- writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK + 0x40, 0xFF);
- writereg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_MASK, 0xFF);
- writereg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_MASK, 0x0);
- writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK, 0x0);
- writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK + 0x40, 0x0);
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static void
-release_io_mic(struct IsdnCardState *cs)
-{
- int bytecnt = 8;
-
- if (cs->hw.mic.cfg_reg)
- release_region(cs->hw.mic.cfg_reg, bytecnt);
-}
-
-static int
-mic_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
- u_long flags;
-
- switch (mt) {
- case CARD_RESET:
- return (0);
- case CARD_RELEASE:
- release_io_mic(cs);
- return (0);
- case CARD_INIT:
- spin_lock_irqsave(&cs->lock, flags);
- inithscx(cs); /* /RTSA := ISAC RST */
- inithscxisac(cs, 3);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_TEST:
- return (0);
- }
- return (0);
-}
-
-int setup_mic(struct IsdnCard *card)
-{
- int bytecnt;
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
-
- strcpy(tmp, mic_revision);
- printk(KERN_INFO "HiSax: mic driver Rev. %s\n", HiSax_getrev(tmp));
- if (cs->typ != ISDN_CTYPE_MIC)
- return (0);
-
- bytecnt = 8;
- cs->hw.mic.cfg_reg = card->para[1];
- cs->irq = card->para[0];
- cs->hw.mic.adr = cs->hw.mic.cfg_reg + MIC_ADR;
- cs->hw.mic.isac = cs->hw.mic.cfg_reg + MIC_ISAC;
- cs->hw.mic.hscx = cs->hw.mic.cfg_reg + MIC_HSCX;
-
- if (!request_region(cs->hw.mic.cfg_reg, bytecnt, "mic isdn")) {
- printk(KERN_WARNING
- "HiSax: ith mic config port %x-%x already in use\n",
- cs->hw.mic.cfg_reg,
- cs->hw.mic.cfg_reg + bytecnt);
- return (0);
- }
- printk(KERN_INFO "mic: defined at 0x%x IRQ %d\n",
- cs->hw.mic.cfg_reg, cs->irq);
- setup_isac(cs);
- cs->readisac = &ReadISAC;
- cs->writeisac = &WriteISAC;
- cs->readisacfifo = &ReadISACfifo;
- cs->writeisacfifo = &WriteISACfifo;
- cs->BC_Read_Reg = &ReadHSCX;
- cs->BC_Write_Reg = &WriteHSCX;
- cs->BC_Send_Data = &hscx_fill_fifo;
- cs->cardmsg = &mic_card_msg;
- cs->irq_func = &mic_interrupt;
- ISACVersion(cs, "mic:");
- if (HscxVersion(cs, "mic:")) {
- printk(KERN_WARNING
- "mic: wrong HSCX versions check IO address\n");
- release_io_mic(cs);
- return (0);
- }
- return (1);
-}
diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c
deleted file mode 100644
index d7b011c8d692..000000000000
--- a/drivers/isdn/hisax/netjet.c
+++ /dev/null
@@ -1,985 +0,0 @@
-/* $Id: netjet.c,v 1.29.2.4 2004/02/11 13:21:34 keil Exp $
- *
- * low level stuff for Traverse Technologie NETJet ISDN cards
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Thanks to Traverse Technologies Australia for documents and information
- *
- * 16-Apr-2002 - led code added - Guy Ellis (guy@traverse.com.au)
- *
- */
-
-#include <linux/init.h>
-#include "hisax.h"
-#include "isac.h"
-#include "hscx.h"
-#include "isdnl1.h"
-#include <linux/interrupt.h>
-#include <linux/ppp_defs.h>
-#include <linux/slab.h>
-#include <asm/io.h>
-#include "netjet.h"
-
-/* Interface functions */
-
-u_char
-NETjet_ReadIC(struct IsdnCardState *cs, u_char offset)
-{
- u_char ret;
-
- cs->hw.njet.auxd &= 0xfc;
- cs->hw.njet.auxd |= (offset >> 4) & 3;
- byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
- ret = bytein(cs->hw.njet.isac + ((offset & 0xf) << 2));
- return (ret);
-}
-
-void
-NETjet_WriteIC(struct IsdnCardState *cs, u_char offset, u_char value)
-{
- cs->hw.njet.auxd &= 0xfc;
- cs->hw.njet.auxd |= (offset >> 4) & 3;
- byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
- byteout(cs->hw.njet.isac + ((offset & 0xf) << 2), value);
-}
-
-void
-NETjet_ReadICfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- cs->hw.njet.auxd &= 0xfc;
- byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
- insb(cs->hw.njet.isac, data, size);
-}
-
-void
-NETjet_WriteICfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- cs->hw.njet.auxd &= 0xfc;
- byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
- outsb(cs->hw.njet.isac, data, size);
-}
-
-static void fill_mem(struct BCState *bcs, u_int *pos, u_int cnt, int chan, u_char fill)
-{
- u_int mask = 0x000000ff, val = 0, *p = pos;
- u_int i;
-
- val |= fill;
- if (chan) {
- val <<= 8;
- mask <<= 8;
- }
- mask ^= 0xffffffff;
- for (i = 0; i < cnt; i++) {
- *p &= mask;
- *p++ |= val;
- if (p > bcs->hw.tiger.s_end)
- p = bcs->hw.tiger.send;
- }
-}
-
-static void
-mode_tiger(struct BCState *bcs, int mode, int bc)
-{
- struct IsdnCardState *cs = bcs->cs;
- u_char led;
-
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "Tiger mode %d bchan %d/%d",
- mode, bc, bcs->channel);
- bcs->mode = mode;
- bcs->channel = bc;
- switch (mode) {
- case (L1_MODE_NULL):
- fill_mem(bcs, bcs->hw.tiger.send,
- NETJET_DMA_TXSIZE, bc, 0xff);
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "Tiger stat rec %d/%d send %d",
- bcs->hw.tiger.r_tot, bcs->hw.tiger.r_err,
- bcs->hw.tiger.s_tot);
- if ((cs->bcs[0].mode == L1_MODE_NULL) &&
- (cs->bcs[1].mode == L1_MODE_NULL)) {
- cs->hw.njet.dmactrl = 0;
- byteout(cs->hw.njet.base + NETJET_DMACTRL,
- cs->hw.njet.dmactrl);
- byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0);
- }
- if (cs->typ == ISDN_CTYPE_NETJET_S)
- {
- // led off
- led = bc & 0x01;
- led = 0x01 << (6 + led); // convert to mask
- led = ~led;
- cs->hw.njet.auxd &= led;
- byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
- }
- break;
- case (L1_MODE_TRANS):
- break;
- case (L1_MODE_HDLC_56K):
- case (L1_MODE_HDLC):
- fill_mem(bcs, bcs->hw.tiger.send,
- NETJET_DMA_TXSIZE, bc, 0xff);
- bcs->hw.tiger.r_state = HDLC_ZERO_SEARCH;
- bcs->hw.tiger.r_tot = 0;
- bcs->hw.tiger.r_bitcnt = 0;
- bcs->hw.tiger.r_one = 0;
- bcs->hw.tiger.r_err = 0;
- bcs->hw.tiger.s_tot = 0;
- if (!cs->hw.njet.dmactrl) {
- fill_mem(bcs, bcs->hw.tiger.send,
- NETJET_DMA_TXSIZE, !bc, 0xff);
- cs->hw.njet.dmactrl = 1;
- byteout(cs->hw.njet.base + NETJET_DMACTRL,
- cs->hw.njet.dmactrl);
- byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0x0f);
- /* was 0x3f now 0x0f for TJ300 and TJ320 GE 13/07/00 */
- }
- bcs->hw.tiger.sendp = bcs->hw.tiger.send;
- bcs->hw.tiger.free = NETJET_DMA_TXSIZE;
- test_and_set_bit(BC_FLG_EMPTY, &bcs->Flag);
- if (cs->typ == ISDN_CTYPE_NETJET_S)
- {
- // led on
- led = bc & 0x01;
- led = 0x01 << (6 + led); // convert to mask
- cs->hw.njet.auxd |= led;
- byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
- }
- break;
- }
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "tiger: set %x %x %x %x/%x pulse=%d",
- bytein(cs->hw.njet.base + NETJET_DMACTRL),
- bytein(cs->hw.njet.base + NETJET_IRQMASK0),
- bytein(cs->hw.njet.base + NETJET_IRQSTAT0),
- inl(cs->hw.njet.base + NETJET_DMA_READ_ADR),
- inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR),
- bytein(cs->hw.njet.base + NETJET_PULSE_CNT));
-}
-
-static void printframe(struct IsdnCardState *cs, u_char *buf, int count, char *s) {
- char tmp[128];
- char *t = tmp;
- int i = count, j;
- u_char *p = buf;
-
- t += sprintf(t, "tiger %s(%4d)", s, count);
- while (i > 0) {
- if (i > 16)
- j = 16;
- else
- j = i;
- QuickHex(t, p, j);
- debugl1(cs, "%s", tmp);
- p += j;
- i -= j;
- t = tmp;
- t += sprintf(t, "tiger %s ", s);
- }
-}
-
-// macro for 64k
-
-#define MAKE_RAW_BYTE for (j = 0; j < 8; j++) { \
- bitcnt++; \
- s_val >>= 1; \
- if (val & 1) { \
- s_one++; \
- s_val |= 0x80; \
- } else { \
- s_one = 0; \
- s_val &= 0x7f; \
- } \
- if (bitcnt == 8) { \
- bcs->hw.tiger.sendbuf[s_cnt++] = s_val; \
- bitcnt = 0; \
- } \
- if (s_one == 5) { \
- s_val >>= 1; \
- s_val &= 0x7f; \
- bitcnt++; \
- s_one = 0; \
- } \
- if (bitcnt == 8) { \
- bcs->hw.tiger.sendbuf[s_cnt++] = s_val; \
- bitcnt = 0; \
- } \
- val >>= 1; \
- }
-
-static int make_raw_data(struct BCState *bcs) {
-// this make_raw is for 64k
- register u_int i, s_cnt = 0;
- register u_char j;
- register u_char val;
- register u_char s_one = 0;
- register u_char s_val = 0;
- register u_char bitcnt = 0;
- u_int fcs;
-
- if (!bcs->tx_skb) {
- debugl1(bcs->cs, "tiger make_raw: NULL skb");
- return (1);
- }
- bcs->hw.tiger.sendbuf[s_cnt++] = HDLC_FLAG_VALUE;
- fcs = PPP_INITFCS;
- for (i = 0; i < bcs->tx_skb->len; i++) {
- val = bcs->tx_skb->data[i];
- fcs = PPP_FCS(fcs, val);
- MAKE_RAW_BYTE;
- }
- fcs ^= 0xffff;
- val = fcs & 0xff;
- MAKE_RAW_BYTE;
- val = (fcs >> 8) & 0xff;
- MAKE_RAW_BYTE;
- val = HDLC_FLAG_VALUE;
- for (j = 0; j < 8; j++) {
- bitcnt++;
- s_val >>= 1;
- if (val & 1)
- s_val |= 0x80;
- else
- s_val &= 0x7f;
- if (bitcnt == 8) {
- bcs->hw.tiger.sendbuf[s_cnt++] = s_val;
- bitcnt = 0;
- }
- val >>= 1;
- }
- if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs, "tiger make_raw: in %u out %d.%d",
- bcs->tx_skb->len, s_cnt, bitcnt);
- if (bitcnt) {
- while (8 > bitcnt++) {
- s_val >>= 1;
- s_val |= 0x80;
- }
- bcs->hw.tiger.sendbuf[s_cnt++] = s_val;
- bcs->hw.tiger.sendbuf[s_cnt++] = 0xff; // NJ<->NJ thoughput bug fix
- }
- bcs->hw.tiger.sendcnt = s_cnt;
- bcs->tx_cnt -= bcs->tx_skb->len;
- bcs->hw.tiger.sp = bcs->hw.tiger.sendbuf;
- return (0);
-}
-
-// macro for 56k
-
-#define MAKE_RAW_BYTE_56K for (j = 0; j < 8; j++) { \
- bitcnt++; \
- s_val >>= 1; \
- if (val & 1) { \
- s_one++; \
- s_val |= 0x80; \
- } else { \
- s_one = 0; \
- s_val &= 0x7f; \
- } \
- if (bitcnt == 7) { \
- s_val >>= 1; \
- s_val |= 0x80; \
- bcs->hw.tiger.sendbuf[s_cnt++] = s_val; \
- bitcnt = 0; \
- } \
- if (s_one == 5) { \
- s_val >>= 1; \
- s_val &= 0x7f; \
- bitcnt++; \
- s_one = 0; \
- } \
- if (bitcnt == 7) { \
- s_val >>= 1; \
- s_val |= 0x80; \
- bcs->hw.tiger.sendbuf[s_cnt++] = s_val; \
- bitcnt = 0; \
- } \
- val >>= 1; \
- }
-
-static int make_raw_data_56k(struct BCState *bcs) {
-// this make_raw is for 56k
- register u_int i, s_cnt = 0;
- register u_char j;
- register u_char val;
- register u_char s_one = 0;
- register u_char s_val = 0;
- register u_char bitcnt = 0;
- u_int fcs;
-
- if (!bcs->tx_skb) {
- debugl1(bcs->cs, "tiger make_raw_56k: NULL skb");
- return (1);
- }
- val = HDLC_FLAG_VALUE;
- for (j = 0; j < 8; j++) {
- bitcnt++;
- s_val >>= 1;
- if (val & 1)
- s_val |= 0x80;
- else
- s_val &= 0x7f;
- if (bitcnt == 7) {
- s_val >>= 1;
- s_val |= 0x80;
- bcs->hw.tiger.sendbuf[s_cnt++] = s_val;
- bitcnt = 0;
- }
- val >>= 1;
- }
- fcs = PPP_INITFCS;
- for (i = 0; i < bcs->tx_skb->len; i++) {
- val = bcs->tx_skb->data[i];
- fcs = PPP_FCS(fcs, val);
- MAKE_RAW_BYTE_56K;
- }
- fcs ^= 0xffff;
- val = fcs & 0xff;
- MAKE_RAW_BYTE_56K;
- val = (fcs >> 8) & 0xff;
- MAKE_RAW_BYTE_56K;
- val = HDLC_FLAG_VALUE;
- for (j = 0; j < 8; j++) {
- bitcnt++;
- s_val >>= 1;
- if (val & 1)
- s_val |= 0x80;
- else
- s_val &= 0x7f;
- if (bitcnt == 7) {
- s_val >>= 1;
- s_val |= 0x80;
- bcs->hw.tiger.sendbuf[s_cnt++] = s_val;
- bitcnt = 0;
- }
- val >>= 1;
- }
- if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs, "tiger make_raw_56k: in %u out %d.%d",
- bcs->tx_skb->len, s_cnt, bitcnt);
- if (bitcnt) {
- while (8 > bitcnt++) {
- s_val >>= 1;
- s_val |= 0x80;
- }
- bcs->hw.tiger.sendbuf[s_cnt++] = s_val;
- bcs->hw.tiger.sendbuf[s_cnt++] = 0xff; // NJ<->NJ thoughput bug fix
- }
- bcs->hw.tiger.sendcnt = s_cnt;
- bcs->tx_cnt -= bcs->tx_skb->len;
- bcs->hw.tiger.sp = bcs->hw.tiger.sendbuf;
- return (0);
-}
-
-static void got_frame(struct BCState *bcs, int count) {
- struct sk_buff *skb;
-
- if (!(skb = dev_alloc_skb(count)))
- printk(KERN_WARNING "TIGER: receive out of memory\n");
- else {
- skb_put_data(skb, bcs->hw.tiger.rcvbuf, count);
- skb_queue_tail(&bcs->rqueue, skb);
- }
- test_and_set_bit(B_RCVBUFREADY, &bcs->event);
- schedule_work(&bcs->tqueue);
-
- if (bcs->cs->debug & L1_DEB_RECEIVE_FRAME)
- printframe(bcs->cs, bcs->hw.tiger.rcvbuf, count, "rec");
-}
-
-
-
-static void read_raw(struct BCState *bcs, u_int *buf, int cnt) {
- int i;
- register u_char j;
- register u_char val;
- u_int *pend = bcs->hw.tiger.rec + NETJET_DMA_RXSIZE - 1;
- register u_char state = bcs->hw.tiger.r_state;
- register u_char r_one = bcs->hw.tiger.r_one;
- register u_char r_val = bcs->hw.tiger.r_val;
- register u_int bitcnt = bcs->hw.tiger.r_bitcnt;
- u_int *p = buf;
- int bits;
- u_char mask;
-
- if (bcs->mode == L1_MODE_HDLC) { // it's 64k
- mask = 0xff;
- bits = 8;
- }
- else { // it's 56K
- mask = 0x7f;
- bits = 7;
- }
- for (i = 0; i < cnt; i++) {
- val = bcs->channel ? ((*p >> 8) & 0xff) : (*p & 0xff);
- p++;
- if (p > pend)
- p = bcs->hw.tiger.rec;
- if ((val & mask) == mask) {
- state = HDLC_ZERO_SEARCH;
- bcs->hw.tiger.r_tot++;
- bitcnt = 0;
- r_one = 0;
- continue;
- }
- for (j = 0; j < bits; j++) {
- if (state == HDLC_ZERO_SEARCH) {
- if (val & 1) {
- r_one++;
- } else {
- r_one = 0;
- state = HDLC_FLAG_SEARCH;
- if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs, "tiger read_raw: zBit(%d,%d,%d) %x",
- bcs->hw.tiger.r_tot, i, j, val);
- }
- } else if (state == HDLC_FLAG_SEARCH) {
- if (val & 1) {
- r_one++;
- if (r_one > 6) {
- state = HDLC_ZERO_SEARCH;
- }
- } else {
- if (r_one == 6) {
- bitcnt = 0;
- r_val = 0;
- state = HDLC_FLAG_FOUND;
- if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs, "tiger read_raw: flag(%d,%d,%d) %x",
- bcs->hw.tiger.r_tot, i, j, val);
- }
- r_one = 0;
- }
- } else if (state == HDLC_FLAG_FOUND) {
- if (val & 1) {
- r_one++;
- if (r_one > 6) {
- state = HDLC_ZERO_SEARCH;
- } else {
- r_val >>= 1;
- r_val |= 0x80;
- bitcnt++;
- }
- } else {
- if (r_one == 6) {
- bitcnt = 0;
- r_val = 0;
- r_one = 0;
- val >>= 1;
- continue;
- } else if (r_one != 5) {
- r_val >>= 1;
- r_val &= 0x7f;
- bitcnt++;
- }
- r_one = 0;
- }
- if ((state != HDLC_ZERO_SEARCH) &&
- !(bitcnt & 7)) {
- state = HDLC_FRAME_FOUND;
- bcs->hw.tiger.r_fcs = PPP_INITFCS;
- bcs->hw.tiger.rcvbuf[0] = r_val;
- bcs->hw.tiger.r_fcs = PPP_FCS(bcs->hw.tiger.r_fcs, r_val);
- if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs, "tiger read_raw: byte1(%d,%d,%d) rval %x val %x i %x",
- bcs->hw.tiger.r_tot, i, j, r_val, val,
- bcs->cs->hw.njet.irqstat0);
- }
- } else if (state == HDLC_FRAME_FOUND) {
- if (val & 1) {
- r_one++;
- if (r_one > 6) {
- state = HDLC_ZERO_SEARCH;
- bitcnt = 0;
- } else {
- r_val >>= 1;
- r_val |= 0x80;
- bitcnt++;
- }
- } else {
- if (r_one == 6) {
- r_val = 0;
- r_one = 0;
- bitcnt++;
- if (bitcnt & 7) {
- debugl1(bcs->cs, "tiger: frame not byte aligned");
- state = HDLC_FLAG_SEARCH;
- bcs->hw.tiger.r_err++;
-#ifdef ERROR_STATISTIC
- bcs->err_inv++;
-#endif
- } else {
- if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs, "tiger frame end(%d,%d): fcs(%x) i %x",
- i, j, bcs->hw.tiger.r_fcs, bcs->cs->hw.njet.irqstat0);
- if (bcs->hw.tiger.r_fcs == PPP_GOODFCS) {
- got_frame(bcs, (bitcnt >> 3) - 3);
- } else {
- if (bcs->cs->debug) {
- debugl1(bcs->cs, "tiger FCS error");
- printframe(bcs->cs, bcs->hw.tiger.rcvbuf,
- (bitcnt >> 3) - 1, "rec");
- bcs->hw.tiger.r_err++;
- }
-#ifdef ERROR_STATISTIC
- bcs->err_crc++;
-#endif
- }
- state = HDLC_FLAG_FOUND;
- }
- bitcnt = 0;
- } else if (r_one == 5) {
- val >>= 1;
- r_one = 0;
- continue;
- } else {
- r_val >>= 1;
- r_val &= 0x7f;
- bitcnt++;
- }
- r_one = 0;
- }
- if ((state == HDLC_FRAME_FOUND) &&
- !(bitcnt & 7)) {
- if ((bitcnt >> 3) >= HSCX_BUFMAX) {
- debugl1(bcs->cs, "tiger: frame too big");
- r_val = 0;
- state = HDLC_FLAG_SEARCH;
- bcs->hw.tiger.r_err++;
-#ifdef ERROR_STATISTIC
- bcs->err_inv++;
-#endif
- } else {
- bcs->hw.tiger.rcvbuf[(bitcnt >> 3) - 1] = r_val;
- bcs->hw.tiger.r_fcs =
- PPP_FCS(bcs->hw.tiger.r_fcs, r_val);
- }
- }
- }
- val >>= 1;
- }
- bcs->hw.tiger.r_tot++;
- }
- bcs->hw.tiger.r_state = state;
- bcs->hw.tiger.r_one = r_one;
- bcs->hw.tiger.r_val = r_val;
- bcs->hw.tiger.r_bitcnt = bitcnt;
-}
-
-void read_tiger(struct IsdnCardState *cs) {
- u_int *p;
- int cnt = NETJET_DMA_RXSIZE / 2;
-
- if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_READ) {
- debugl1(cs, "tiger warn read double dma %x/%x",
- cs->hw.njet.irqstat0, cs->hw.njet.last_is0);
-#ifdef ERROR_STATISTIC
- if (cs->bcs[0].mode)
- cs->bcs[0].err_rdo++;
- if (cs->bcs[1].mode)
- cs->bcs[1].err_rdo++;
-#endif
- return;
- } else {
- cs->hw.njet.last_is0 &= ~NETJET_IRQM0_READ;
- cs->hw.njet.last_is0 |= (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ);
- }
- if (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ_1)
- p = cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE - 1;
- else
- p = cs->bcs[0].hw.tiger.rec + cnt - 1;
- if ((cs->bcs[0].mode == L1_MODE_HDLC) || (cs->bcs[0].mode == L1_MODE_HDLC_56K))
- read_raw(cs->bcs, p, cnt);
-
- if ((cs->bcs[1].mode == L1_MODE_HDLC) || (cs->bcs[1].mode == L1_MODE_HDLC_56K))
- read_raw(cs->bcs + 1, p, cnt);
- cs->hw.njet.irqstat0 &= ~NETJET_IRQM0_READ;
-}
-
-static void write_raw(struct BCState *bcs, u_int *buf, int cnt);
-
-void netjet_fill_dma(struct BCState *bcs)
-{
- register u_int *p, *sp;
- register int cnt;
-
- if (!bcs->tx_skb)
- return;
- if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs, "tiger fill_dma1: c%d %4lx", bcs->channel,
- bcs->Flag);
- if (test_and_set_bit(BC_FLG_BUSY, &bcs->Flag))
- return;
- if (bcs->mode == L1_MODE_HDLC) { // it's 64k
- if (make_raw_data(bcs))
- return;
- }
- else { // it's 56k
- if (make_raw_data_56k(bcs))
- return;
- }
- if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs, "tiger fill_dma2: c%d %4lx", bcs->channel,
- bcs->Flag);
- if (test_and_clear_bit(BC_FLG_NOFRAME, &bcs->Flag)) {
- write_raw(bcs, bcs->hw.tiger.sendp, bcs->hw.tiger.free);
- } else if (test_and_clear_bit(BC_FLG_HALF, &bcs->Flag)) {
- p = bus_to_virt(inl(bcs->cs->hw.njet.base + NETJET_DMA_READ_ADR));
- sp = bcs->hw.tiger.sendp;
- if (p == bcs->hw.tiger.s_end)
- p = bcs->hw.tiger.send - 1;
- if (sp == bcs->hw.tiger.s_end)
- sp = bcs->hw.tiger.send - 1;
- cnt = p - sp;
- if (cnt < 0) {
- write_raw(bcs, bcs->hw.tiger.sendp, bcs->hw.tiger.free);
- } else {
- p++;
- cnt++;
- if (p > bcs->hw.tiger.s_end)
- p = bcs->hw.tiger.send;
- p++;
- cnt++;
- if (p > bcs->hw.tiger.s_end)
- p = bcs->hw.tiger.send;
- write_raw(bcs, p, bcs->hw.tiger.free - cnt);
- }
- } else if (test_and_clear_bit(BC_FLG_EMPTY, &bcs->Flag)) {
- p = bus_to_virt(inl(bcs->cs->hw.njet.base + NETJET_DMA_READ_ADR));
- cnt = bcs->hw.tiger.s_end - p;
- if (cnt < 2) {
- p = bcs->hw.tiger.send + 1;
- cnt = NETJET_DMA_TXSIZE / 2 - 2;
- } else {
- p++;
- p++;
- if (cnt <= (NETJET_DMA_TXSIZE / 2))
- cnt += NETJET_DMA_TXSIZE / 2;
- cnt--;
- cnt--;
- }
- write_raw(bcs, p, cnt);
- }
- if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs, "tiger fill_dma3: c%d %4lx", bcs->channel,
- bcs->Flag);
-}
-
-static void write_raw(struct BCState *bcs, u_int *buf, int cnt) {
- u_int mask, val, *p = buf;
- u_int i, s_cnt;
-
- if (cnt <= 0)
- return;
- if (test_bit(BC_FLG_BUSY, &bcs->Flag)) {
- if (bcs->hw.tiger.sendcnt > cnt) {
- s_cnt = cnt;
- bcs->hw.tiger.sendcnt -= cnt;
- } else {
- s_cnt = bcs->hw.tiger.sendcnt;
- bcs->hw.tiger.sendcnt = 0;
- }
- if (bcs->channel)
- mask = 0xffff00ff;
- else
- mask = 0xffffff00;
- for (i = 0; i < s_cnt; i++) {
- val = bcs->channel ? ((bcs->hw.tiger.sp[i] << 8) & 0xff00) :
- (bcs->hw.tiger.sp[i]);
- *p &= mask;
- *p++ |= val;
- if (p > bcs->hw.tiger.s_end)
- p = bcs->hw.tiger.send;
- }
- bcs->hw.tiger.s_tot += s_cnt;
- if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs, "tiger write_raw: c%d %p-%p %d/%d %d %x", bcs->channel,
- buf, p, s_cnt, cnt,
- bcs->hw.tiger.sendcnt, bcs->cs->hw.njet.irqstat0);
- if (bcs->cs->debug & L1_DEB_HSCX_FIFO)
- printframe(bcs->cs, bcs->hw.tiger.sp, s_cnt, "snd");
- bcs->hw.tiger.sp += s_cnt;
- bcs->hw.tiger.sendp = p;
- if (!bcs->hw.tiger.sendcnt) {
- if (!bcs->tx_skb) {
- debugl1(bcs->cs, "tiger write_raw: NULL skb s_cnt %d", s_cnt);
- } else {
- if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
- (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
- u_long flags;
- spin_lock_irqsave(&bcs->aclock, flags);
- bcs->ackcnt += bcs->tx_skb->len;
- spin_unlock_irqrestore(&bcs->aclock, flags);
- schedule_event(bcs, B_ACKPENDING);
- }
- dev_kfree_skb_any(bcs->tx_skb);
- bcs->tx_skb = NULL;
- }
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->hw.tiger.free = cnt - s_cnt;
- if (bcs->hw.tiger.free > (NETJET_DMA_TXSIZE / 2))
- test_and_set_bit(BC_FLG_HALF, &bcs->Flag);
- else {
- test_and_clear_bit(BC_FLG_HALF, &bcs->Flag);
- test_and_set_bit(BC_FLG_NOFRAME, &bcs->Flag);
- }
- if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
- netjet_fill_dma(bcs);
- } else {
- mask ^= 0xffffffff;
- if (s_cnt < cnt) {
- for (i = s_cnt; i < cnt; i++) {
- *p++ |= mask;
- if (p > bcs->hw.tiger.s_end)
- p = bcs->hw.tiger.send;
- }
- if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs, "tiger write_raw: fill rest %d",
- cnt - s_cnt);
- }
- test_and_set_bit(B_XMTBUFREADY, &bcs->event);
- schedule_work(&bcs->tqueue);
- }
- }
- } else if (test_and_clear_bit(BC_FLG_NOFRAME, &bcs->Flag)) {
- test_and_set_bit(BC_FLG_HALF, &bcs->Flag);
- fill_mem(bcs, buf, cnt, bcs->channel, 0xff);
- bcs->hw.tiger.free += cnt;
- if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs, "tiger write_raw: fill half");
- } else if (test_and_clear_bit(BC_FLG_HALF, &bcs->Flag)) {
- test_and_set_bit(BC_FLG_EMPTY, &bcs->Flag);
- fill_mem(bcs, buf, cnt, bcs->channel, 0xff);
- if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs, "tiger write_raw: fill full");
- }
-}
-
-void write_tiger(struct IsdnCardState *cs) {
- u_int *p, cnt = NETJET_DMA_TXSIZE / 2;
-
- if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_WRITE) {
- debugl1(cs, "tiger warn write double dma %x/%x",
- cs->hw.njet.irqstat0, cs->hw.njet.last_is0);
-#ifdef ERROR_STATISTIC
- if (cs->bcs[0].mode)
- cs->bcs[0].err_tx++;
- if (cs->bcs[1].mode)
- cs->bcs[1].err_tx++;
-#endif
- return;
- } else {
- cs->hw.njet.last_is0 &= ~NETJET_IRQM0_WRITE;
- cs->hw.njet.last_is0 |= (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE);
- }
- if (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE_1)
- p = cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE - 1;
- else
- p = cs->bcs[0].hw.tiger.send + cnt - 1;
- if ((cs->bcs[0].mode == L1_MODE_HDLC) || (cs->bcs[0].mode == L1_MODE_HDLC_56K))
- write_raw(cs->bcs, p, cnt);
- if ((cs->bcs[1].mode == L1_MODE_HDLC) || (cs->bcs[1].mode == L1_MODE_HDLC_56K))
- write_raw(cs->bcs + 1, p, cnt);
- cs->hw.njet.irqstat0 &= ~NETJET_IRQM0_WRITE;
-}
-
-static void
-tiger_l2l1(struct PStack *st, int pr, void *arg)
-{
- struct BCState *bcs = st->l1.bcs;
- struct sk_buff *skb = arg;
- u_long flags;
-
- switch (pr) {
- case (PH_DATA | REQUEST):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- if (bcs->tx_skb) {
- skb_queue_tail(&bcs->squeue, skb);
- } else {
- bcs->tx_skb = skb;
- bcs->cs->BC_Send_Data(bcs);
- }
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- break;
- case (PH_PULL | INDICATION):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- if (bcs->tx_skb) {
- printk(KERN_WARNING "tiger_l2l1: this shouldn't happen\n");
- } else {
- bcs->tx_skb = skb;
- bcs->cs->BC_Send_Data(bcs);
- }
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- break;
- case (PH_PULL | REQUEST):
- if (!bcs->tx_skb) {
- test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
- } else
- test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- break;
- case (PH_ACTIVATE | REQUEST):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
- mode_tiger(bcs, st->l1.mode, st->l1.bc);
- /* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG */
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- bcs->cs->cardmsg(bcs->cs, MDL_BC_ASSIGN, (void *)(&st->l1.bc));
- l1_msg_b(st, pr, arg);
- break;
- case (PH_DEACTIVATE | REQUEST):
- /* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG */
- bcs->cs->cardmsg(bcs->cs, MDL_BC_RELEASE, (void *)(&st->l1.bc));
- l1_msg_b(st, pr, arg);
- break;
- case (PH_DEACTIVATE | CONFIRM):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- mode_tiger(bcs, 0, st->l1.bc);
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
- break;
- }
-}
-
-
-static void
-close_tigerstate(struct BCState *bcs)
-{
- mode_tiger(bcs, 0, bcs->channel);
- if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
- kfree(bcs->hw.tiger.rcvbuf);
- bcs->hw.tiger.rcvbuf = NULL;
- kfree(bcs->hw.tiger.sendbuf);
- bcs->hw.tiger.sendbuf = NULL;
- skb_queue_purge(&bcs->rqueue);
- skb_queue_purge(&bcs->squeue);
- if (bcs->tx_skb) {
- dev_kfree_skb_any(bcs->tx_skb);
- bcs->tx_skb = NULL;
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- }
- }
-}
-
-static int
-open_tigerstate(struct IsdnCardState *cs, struct BCState *bcs)
-{
- if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
- if (!(bcs->hw.tiger.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
- printk(KERN_WARNING
- "HiSax: No memory for tiger.rcvbuf\n");
- return (1);
- }
- if (!(bcs->hw.tiger.sendbuf = kmalloc(RAW_BUFMAX, GFP_ATOMIC))) {
- printk(KERN_WARNING
- "HiSax: No memory for tiger.sendbuf\n");
- return (1);
- }
- skb_queue_head_init(&bcs->rqueue);
- skb_queue_head_init(&bcs->squeue);
- }
- bcs->tx_skb = NULL;
- bcs->hw.tiger.sendcnt = 0;
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->event = 0;
- bcs->tx_cnt = 0;
- return (0);
-}
-
-static int
-setstack_tiger(struct PStack *st, struct BCState *bcs)
-{
- bcs->channel = st->l1.bc;
- if (open_tigerstate(st->l1.hardware, bcs))
- return (-1);
- st->l1.bcs = bcs;
- st->l2.l2l1 = tiger_l2l1;
- setstack_manager(st);
- bcs->st = st;
- setstack_l1_B(st);
- return (0);
-}
-
-
-void
-inittiger(struct IsdnCardState *cs)
-{
- cs->bcs[0].hw.tiger.send = kmalloc_array(NETJET_DMA_TXSIZE,
- sizeof(unsigned int),
- GFP_KERNEL | GFP_DMA);
- if (!cs->bcs[0].hw.tiger.send) {
- printk(KERN_WARNING
- "HiSax: No memory for tiger.send\n");
- return;
- }
- cs->bcs[0].hw.tiger.s_irq = cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE / 2 - 1;
- cs->bcs[0].hw.tiger.s_end = cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE - 1;
- cs->bcs[1].hw.tiger.send = cs->bcs[0].hw.tiger.send;
- cs->bcs[1].hw.tiger.s_irq = cs->bcs[0].hw.tiger.s_irq;
- cs->bcs[1].hw.tiger.s_end = cs->bcs[0].hw.tiger.s_end;
-
- memset(cs->bcs[0].hw.tiger.send, 0xff, NETJET_DMA_TXSIZE * sizeof(unsigned int));
- debugl1(cs, "tiger: send buf %p - %p", cs->bcs[0].hw.tiger.send,
- cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE - 1);
- outl(virt_to_bus(cs->bcs[0].hw.tiger.send),
- cs->hw.njet.base + NETJET_DMA_READ_START);
- outl(virt_to_bus(cs->bcs[0].hw.tiger.s_irq),
- cs->hw.njet.base + NETJET_DMA_READ_IRQ);
- outl(virt_to_bus(cs->bcs[0].hw.tiger.s_end),
- cs->hw.njet.base + NETJET_DMA_READ_END);
- cs->bcs[0].hw.tiger.rec = kmalloc_array(NETJET_DMA_RXSIZE,
- sizeof(unsigned int),
- GFP_KERNEL | GFP_DMA);
- if (!cs->bcs[0].hw.tiger.rec) {
- printk(KERN_WARNING
- "HiSax: No memory for tiger.rec\n");
- return;
- }
- debugl1(cs, "tiger: rec buf %p - %p", cs->bcs[0].hw.tiger.rec,
- cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE - 1);
- cs->bcs[1].hw.tiger.rec = cs->bcs[0].hw.tiger.rec;
- memset(cs->bcs[0].hw.tiger.rec, 0xff, NETJET_DMA_RXSIZE * sizeof(unsigned int));
- outl(virt_to_bus(cs->bcs[0].hw.tiger.rec),
- cs->hw.njet.base + NETJET_DMA_WRITE_START);
- outl(virt_to_bus(cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE / 2 - 1),
- cs->hw.njet.base + NETJET_DMA_WRITE_IRQ);
- outl(virt_to_bus(cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE - 1),
- cs->hw.njet.base + NETJET_DMA_WRITE_END);
- debugl1(cs, "tiger: dmacfg %x/%x pulse=%d",
- inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR),
- inl(cs->hw.njet.base + NETJET_DMA_READ_ADR),
- bytein(cs->hw.njet.base + NETJET_PULSE_CNT));
- cs->hw.njet.last_is0 = 0;
- cs->bcs[0].BC_SetStack = setstack_tiger;
- cs->bcs[1].BC_SetStack = setstack_tiger;
- cs->bcs[0].BC_Close = close_tigerstate;
- cs->bcs[1].BC_Close = close_tigerstate;
-}
-
-static void
-releasetiger(struct IsdnCardState *cs)
-{
- kfree(cs->bcs[0].hw.tiger.send);
- cs->bcs[0].hw.tiger.send = NULL;
- cs->bcs[1].hw.tiger.send = NULL;
- kfree(cs->bcs[0].hw.tiger.rec);
- cs->bcs[0].hw.tiger.rec = NULL;
- cs->bcs[1].hw.tiger.rec = NULL;
-}
-
-void
-release_io_netjet(struct IsdnCardState *cs)
-{
- byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0);
- byteout(cs->hw.njet.base + NETJET_IRQMASK1, 0);
- releasetiger(cs);
- release_region(cs->hw.njet.base, 256);
-}
diff --git a/drivers/isdn/hisax/netjet.h b/drivers/isdn/hisax/netjet.h
deleted file mode 100644
index 70590d5d5e64..000000000000
--- a/drivers/isdn/hisax/netjet.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/* $Id: netjet.h,v 2.8.2.2 2004/01/12 22:52:28 keil Exp $
- *
- * NETjet common header file
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- * by Matt Henderson,
- * Traverse Technologies P/L www.traverse.com.au
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#define byteout(addr, val) outb(val, addr)
-#define bytein(addr) inb(addr)
-
-#define NETJET_CTRL 0x00
-#define NETJET_DMACTRL 0x01
-#define NETJET_AUXCTRL 0x02
-#define NETJET_AUXDATA 0x03
-#define NETJET_IRQMASK0 0x04
-#define NETJET_IRQMASK1 0x05
-#define NETJET_IRQSTAT0 0x06
-#define NETJET_IRQSTAT1 0x07
-#define NETJET_DMA_READ_START 0x08
-#define NETJET_DMA_READ_IRQ 0x0c
-#define NETJET_DMA_READ_END 0x10
-#define NETJET_DMA_READ_ADR 0x14
-#define NETJET_DMA_WRITE_START 0x18
-#define NETJET_DMA_WRITE_IRQ 0x1c
-#define NETJET_DMA_WRITE_END 0x20
-#define NETJET_DMA_WRITE_ADR 0x24
-#define NETJET_PULSE_CNT 0x28
-
-#define NETJET_ISAC_OFF 0xc0
-#define NETJET_ISACIRQ 0x10
-#define NETJET_IRQM0_READ 0x0c
-#define NETJET_IRQM0_READ_1 0x04
-#define NETJET_IRQM0_READ_2 0x08
-#define NETJET_IRQM0_WRITE 0x03
-#define NETJET_IRQM0_WRITE_1 0x01
-#define NETJET_IRQM0_WRITE_2 0x02
-
-#define NETJET_DMA_TXSIZE 512
-#define NETJET_DMA_RXSIZE 128
-
-#define HDLC_ZERO_SEARCH 0
-#define HDLC_FLAG_SEARCH 1
-#define HDLC_FLAG_FOUND 2
-#define HDLC_FRAME_FOUND 3
-#define HDLC_NULL 4
-#define HDLC_PART 5
-#define HDLC_FULL 6
-
-#define HDLC_FLAG_VALUE 0x7e
-
-u_char NETjet_ReadIC(struct IsdnCardState *cs, u_char offset);
-void NETjet_WriteIC(struct IsdnCardState *cs, u_char offset, u_char value);
-void NETjet_ReadICfifo(struct IsdnCardState *cs, u_char *data, int size);
-void NETjet_WriteICfifo(struct IsdnCardState *cs, u_char *data, int size);
-
-void read_tiger(struct IsdnCardState *cs);
-void write_tiger(struct IsdnCardState *cs);
-
-void netjet_fill_dma(struct BCState *bcs);
-void netjet_interrupt(int intno, void *dev_id);
-void inittiger(struct IsdnCardState *cs);
-void release_io_netjet(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c
deleted file mode 100644
index dfbcd2eaa81a..000000000000
--- a/drivers/isdn/hisax/niccy.c
+++ /dev/null
@@ -1,380 +0,0 @@
-/* $Id: niccy.c,v 1.21.2.4 2004/01/13 23:48:39 keil Exp $
- *
- * low level stuff for Dr. Neuhaus NICCY PnP and NICCY PCI and
- * compatible (SAGEM cybermodem)
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Thanks to Dr. Neuhaus and SAGEM for information
- *
- */
-
-#include <linux/init.h>
-#include "hisax.h"
-#include "isac.h"
-#include "hscx.h"
-#include "isdnl1.h"
-#include <linux/pci.h>
-#include <linux/isapnp.h>
-
-static const char *niccy_revision = "$Revision: 1.21.2.4 $";
-
-#define byteout(addr, val) outb(val, addr)
-#define bytein(addr) inb(addr)
-
-#define ISAC_PCI_DATA 0
-#define HSCX_PCI_DATA 1
-#define ISAC_PCI_ADDR 2
-#define HSCX_PCI_ADDR 3
-#define ISAC_PNP 0
-#define HSCX_PNP 1
-
-/* SUB Types */
-#define NICCY_PNP 1
-#define NICCY_PCI 2
-
-/* PCI stuff */
-#define PCI_IRQ_CTRL_REG 0x38
-#define PCI_IRQ_ENABLE 0x1f00
-#define PCI_IRQ_DISABLE 0xff0000
-#define PCI_IRQ_ASSERT 0x800000
-
-static inline u_char readreg(unsigned int ale, unsigned int adr, u_char off)
-{
- register u_char ret;
-
- byteout(ale, off);
- ret = bytein(adr);
- return ret;
-}
-
-static inline void readfifo(unsigned int ale, unsigned int adr, u_char off,
- u_char *data, int size)
-{
- byteout(ale, off);
- insb(adr, data, size);
-}
-
-static inline void writereg(unsigned int ale, unsigned int adr, u_char off,
- u_char data)
-{
- byteout(ale, off);
- byteout(adr, data);
-}
-
-static inline void writefifo(unsigned int ale, unsigned int adr, u_char off,
- u_char *data, int size)
-{
- byteout(ale, off);
- outsb(adr, data, size);
-}
-
-/* Interface functions */
-
-static u_char ReadISAC(struct IsdnCardState *cs, u_char offset)
-{
- return readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset);
-}
-
-static void WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
-{
- writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset, value);
-}
-
-static void ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- readfifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size);
-}
-
-static void WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- writefifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size);
-}
-
-static u_char ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
-{
- return readreg(cs->hw.niccy.hscx_ale,
- cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0));
-}
-
-static void WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset,
- u_char value)
-{
- writereg(cs->hw.niccy.hscx_ale,
- cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0), value);
-}
-
-#define READHSCX(cs, nr, reg) readreg(cs->hw.niccy.hscx_ale, \
- cs->hw.niccy.hscx, reg + (nr ? 0x40 : 0))
-#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.niccy.hscx_ale, \
- cs->hw.niccy.hscx, reg + (nr ? 0x40 : 0), data)
-
-#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.niccy.hscx_ale, \
- cs->hw.niccy.hscx, (nr ? 0x40 : 0), ptr, cnt)
-
-#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.niccy.hscx_ale, \
- cs->hw.niccy.hscx, (nr ? 0x40 : 0), ptr, cnt)
-
-#include "hscx_irq.c"
-
-static irqreturn_t niccy_interrupt(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_char val;
- u_long flags;
-
- spin_lock_irqsave(&cs->lock, flags);
- if (cs->subtyp == NICCY_PCI) {
- int ival;
- ival = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
- if (!(ival & PCI_IRQ_ASSERT)) { /* IRQ not for us (shared) */
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_NONE;
- }
- outl(ival, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
- }
- val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx,
- HSCX_ISTA + 0x40);
-Start_HSCX:
- if (val)
- hscx_int_main(cs, val);
- val = readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_ISTA);
-Start_ISAC:
- if (val)
- isac_interrupt(cs, val);
- val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx,
- HSCX_ISTA + 0x40);
- if (val) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "HSCX IntStat after IntRoutine");
- goto Start_HSCX;
- }
- val = readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_ISTA);
- if (val) {
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ISAC IntStat after IntRoutine");
- goto Start_ISAC;
- }
- writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0xFF);
- writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40,
- 0xFF);
- writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0xFF);
- writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0);
- writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0);
- writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0);
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static void release_io_niccy(struct IsdnCardState *cs)
-{
- if (cs->subtyp == NICCY_PCI) {
- int val;
-
- val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
- val &= PCI_IRQ_DISABLE;
- outl(val, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
- release_region(cs->hw.niccy.cfg_reg, 0x40);
- release_region(cs->hw.niccy.isac, 4);
- } else {
- release_region(cs->hw.niccy.isac, 2);
- release_region(cs->hw.niccy.isac_ale, 2);
- }
-}
-
-static void niccy_reset(struct IsdnCardState *cs)
-{
- if (cs->subtyp == NICCY_PCI) {
- int val;
-
- val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
- val |= PCI_IRQ_ENABLE;
- outl(val, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
- }
- inithscxisac(cs, 3);
-}
-
-static int niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
- u_long flags;
-
- switch (mt) {
- case CARD_RESET:
- spin_lock_irqsave(&cs->lock, flags);
- niccy_reset(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- return 0;
- case CARD_RELEASE:
- release_io_niccy(cs);
- return 0;
- case CARD_INIT:
- spin_lock_irqsave(&cs->lock, flags);
- niccy_reset(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- return 0;
- case CARD_TEST:
- return 0;
- }
- return 0;
-}
-
-#ifdef __ISAPNP__
-static struct pnp_card *pnp_c = NULL;
-#endif
-
-int setup_niccy(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
-
- strcpy(tmp, niccy_revision);
- printk(KERN_INFO "HiSax: Niccy driver Rev. %s\n", HiSax_getrev(tmp));
- if (cs->typ != ISDN_CTYPE_NICCY)
- return 0;
-#ifdef __ISAPNP__
- if (!card->para[1] && isapnp_present()) {
- struct pnp_dev *pnp_d = NULL;
- int err;
-
- pnp_c = pnp_find_card(ISAPNP_VENDOR('S', 'D', 'A'),
- ISAPNP_FUNCTION(0x0150), pnp_c);
- if (pnp_c) {
- pnp_d = pnp_find_dev(pnp_c,
- ISAPNP_VENDOR('S', 'D', 'A'),
- ISAPNP_FUNCTION(0x0150), pnp_d);
- if (!pnp_d) {
- printk(KERN_ERR "NiccyPnP: PnP error card "
- "found, no device\n");
- return 0;
- }
- pnp_disable_dev(pnp_d);
- err = pnp_activate_dev(pnp_d);
- if (err < 0) {
- printk(KERN_WARNING "%s: pnp_activate_dev "
- "ret(%d)\n", __func__, err);
- return 0;
- }
- card->para[1] = pnp_port_start(pnp_d, 0);
- card->para[2] = pnp_port_start(pnp_d, 1);
- card->para[0] = pnp_irq(pnp_d, 0);
- if (card->para[0] == -1 || !card->para[1] ||
- !card->para[2]) {
- printk(KERN_ERR "NiccyPnP:some resources are "
- "missing %ld/%lx/%lx\n",
- card->para[0], card->para[1],
- card->para[2]);
- pnp_disable_dev(pnp_d);
- return 0;
- }
- } else
- printk(KERN_INFO "NiccyPnP: no ISAPnP card found\n");
- }
-#endif
- if (card->para[1]) {
- cs->hw.niccy.isac = card->para[1] + ISAC_PNP;
- cs->hw.niccy.hscx = card->para[1] + HSCX_PNP;
- cs->hw.niccy.isac_ale = card->para[2] + ISAC_PNP;
- cs->hw.niccy.hscx_ale = card->para[2] + HSCX_PNP;
- cs->hw.niccy.cfg_reg = 0;
- cs->subtyp = NICCY_PNP;
- cs->irq = card->para[0];
- if (!request_region(cs->hw.niccy.isac, 2, "niccy data")) {
- printk(KERN_WARNING "HiSax: NICCY data port %x-%x "
- "already in use\n",
- cs->hw.niccy.isac, cs->hw.niccy.isac + 1);
- return 0;
- }
- if (!request_region(cs->hw.niccy.isac_ale, 2, "niccy addr")) {
- printk(KERN_WARNING "HiSax: NICCY address port %x-%x "
- "already in use\n",
- cs->hw.niccy.isac_ale,
- cs->hw.niccy.isac_ale + 1);
- release_region(cs->hw.niccy.isac, 2);
- return 0;
- }
- } else {
-#ifdef CONFIG_PCI
- static struct pci_dev *niccy_dev;
-
- u_int pci_ioaddr;
- cs->subtyp = 0;
- if ((niccy_dev = hisax_find_pci_device(PCI_VENDOR_ID_SATSAGEM,
- PCI_DEVICE_ID_SATSAGEM_NICCY,
- niccy_dev))) {
- if (pci_enable_device(niccy_dev))
- return 0;
- /* get IRQ */
- if (!niccy_dev->irq) {
- printk(KERN_WARNING
- "Niccy: No IRQ for PCI card found\n");
- return 0;
- }
- cs->irq = niccy_dev->irq;
- cs->hw.niccy.cfg_reg = pci_resource_start(niccy_dev, 0);
- if (!cs->hw.niccy.cfg_reg) {
- printk(KERN_WARNING
- "Niccy: No IO-Adr for PCI cfg found\n");
- return 0;
- }
- pci_ioaddr = pci_resource_start(niccy_dev, 1);
- if (!pci_ioaddr) {
- printk(KERN_WARNING
- "Niccy: No IO-Adr for PCI card found\n");
- return 0;
- }
- cs->subtyp = NICCY_PCI;
- } else {
- printk(KERN_WARNING "Niccy: No PCI card found\n");
- return 0;
- }
- cs->irq_flags |= IRQF_SHARED;
- cs->hw.niccy.isac = pci_ioaddr + ISAC_PCI_DATA;
- cs->hw.niccy.isac_ale = pci_ioaddr + ISAC_PCI_ADDR;
- cs->hw.niccy.hscx = pci_ioaddr + HSCX_PCI_DATA;
- cs->hw.niccy.hscx_ale = pci_ioaddr + HSCX_PCI_ADDR;
- if (!request_region(cs->hw.niccy.isac, 4, "niccy")) {
- printk(KERN_WARNING
- "HiSax: NICCY data port %x-%x already in use\n",
- cs->hw.niccy.isac, cs->hw.niccy.isac + 4);
- return 0;
- }
- if (!request_region(cs->hw.niccy.cfg_reg, 0x40, "niccy pci")) {
- printk(KERN_WARNING
- "HiSax: NICCY pci port %x-%x already in use\n",
- cs->hw.niccy.cfg_reg,
- cs->hw.niccy.cfg_reg + 0x40);
- release_region(cs->hw.niccy.isac, 4);
- return 0;
- }
-#else
- printk(KERN_WARNING "Niccy: io0 0 and NO_PCI_BIOS\n");
- printk(KERN_WARNING "Niccy: unable to config NICCY PCI\n");
- return 0;
-#endif /* CONFIG_PCI */
- }
- printk(KERN_INFO "HiSax: NICCY %s config irq:%d data:0x%X ale:0x%X\n",
- (cs->subtyp == 1) ? "PnP" : "PCI",
- cs->irq, cs->hw.niccy.isac, cs->hw.niccy.isac_ale);
- setup_isac(cs);
- cs->readisac = &ReadISAC;
- cs->writeisac = &WriteISAC;
- cs->readisacfifo = &ReadISACfifo;
- cs->writeisacfifo = &WriteISACfifo;
- cs->BC_Read_Reg = &ReadHSCX;
- cs->BC_Write_Reg = &WriteHSCX;
- cs->BC_Send_Data = &hscx_fill_fifo;
- cs->cardmsg = &niccy_card_msg;
- cs->irq_func = &niccy_interrupt;
- ISACVersion(cs, "Niccy:");
- if (HscxVersion(cs, "Niccy:")) {
- printk(KERN_WARNING "Niccy: wrong HSCX versions check IO "
- "address\n");
- release_io_niccy(cs);
- return 0;
- }
- return 1;
-}
diff --git a/drivers/isdn/hisax/nj_s.c b/drivers/isdn/hisax/nj_s.c
deleted file mode 100644
index 32b4bbd18eb9..000000000000
--- a/drivers/isdn/hisax/nj_s.c
+++ /dev/null
@@ -1,294 +0,0 @@
-/* $Id: nj_s.c,v 2.13.2.4 2004/01/16 01:53:48 keil Exp $
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/init.h>
-#include "hisax.h"
-#include "isac.h"
-#include "isdnl1.h"
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/ppp_defs.h>
-#include "netjet.h"
-
-static const char *NETjet_S_revision = "$Revision: 2.13.2.4 $";
-
-static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off)
-{
- return (5);
-}
-
-static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value)
-{
-}
-
-static irqreturn_t
-netjet_s_interrupt(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_char val, s1val, s0val;
- u_long flags;
-
- spin_lock_irqsave(&cs->lock, flags);
- s1val = bytein(cs->hw.njet.base + NETJET_IRQSTAT1);
- if (!(s1val & NETJET_ISACIRQ)) {
- val = NETjet_ReadIC(cs, ISAC_ISTA);
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "tiger: i1 %x %x", s1val, val);
- if (val) {
- isac_interrupt(cs, val);
- NETjet_WriteIC(cs, ISAC_MASK, 0xFF);
- NETjet_WriteIC(cs, ISAC_MASK, 0x0);
- }
- s1val = 1;
- } else
- s1val = 0;
- /*
- * read/write stat0 is better, because lower IRQ rate
- * Note the IRQ is on for 125 us if a condition match
- * thats long on modern CPU and so the IRQ is reentered
- * all the time.
- */
- s0val = bytein(cs->hw.njet.base + NETJET_IRQSTAT0);
- if ((s0val | s1val) == 0) { // shared IRQ
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_NONE;
- }
- if (s0val)
- byteout(cs->hw.njet.base + NETJET_IRQSTAT0, s0val);
- /* start new code 13/07/00 GE */
- /* set bits in sval to indicate which page is free */
- if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) <
- inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ))
- /* the 2nd write page is free */
- s0val = 0x08;
- else /* the 1st write page is free */
- s0val = 0x04;
- if (inl(cs->hw.njet.base + NETJET_DMA_READ_ADR) <
- inl(cs->hw.njet.base + NETJET_DMA_READ_IRQ))
- /* the 2nd read page is free */
- s0val |= 0x02;
- else /* the 1st read page is free */
- s0val |= 0x01;
- if (s0val != cs->hw.njet.last_is0) /* we have a DMA interrupt */
- {
- if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- printk(KERN_WARNING "nj LOCK_ATOMIC s0val %x->%x\n",
- cs->hw.njet.last_is0, s0val);
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
- }
- cs->hw.njet.irqstat0 = s0val;
- if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) !=
- (cs->hw.njet.last_is0 & NETJET_IRQM0_READ))
- /* we have a read dma int */
- read_tiger(cs);
- if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) !=
- (cs->hw.njet.last_is0 & NETJET_IRQM0_WRITE))
- /* we have a write dma int */
- write_tiger(cs);
- /* end new code 13/07/00 GE */
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- }
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static void
-reset_netjet_s(struct IsdnCardState *cs)
-{
- cs->hw.njet.ctrl_reg = 0xff; /* Reset On */
- byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
- mdelay(10);
- /* now edge triggered for TJ320 GE 13/07/00 */
- /* see comment in IRQ function */
- if (cs->subtyp) /* TJ320 */
- cs->hw.njet.ctrl_reg = 0x40; /* Reset Off and status read clear */
- else
- cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */
- byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
- mdelay(10);
- cs->hw.njet.auxd = 0;
- cs->hw.njet.dmactrl = 0;
- byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
- byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
- byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
-}
-
-static int
-NETjet_S_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
- u_long flags;
-
- switch (mt) {
- case CARD_RESET:
- spin_lock_irqsave(&cs->lock, flags);
- reset_netjet_s(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_RELEASE:
- release_io_netjet(cs);
- return (0);
- case CARD_INIT:
- reset_netjet_s(cs);
- inittiger(cs);
- spin_lock_irqsave(&cs->lock, flags);
- clear_pending_isac_ints(cs);
- initisac(cs);
- /* Reenable all IRQ */
- cs->writeisac(cs, ISAC_MASK, 0);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_TEST:
- return (0);
- }
- return (0);
-}
-
-static int njs_pci_probe(struct pci_dev *dev_netjet, struct IsdnCardState *cs)
-{
- u32 cfg;
-
- if (pci_enable_device(dev_netjet))
- return (0);
- pci_set_master(dev_netjet);
- cs->irq = dev_netjet->irq;
- if (!cs->irq) {
- printk(KERN_WARNING "NETjet-S: No IRQ for PCI card found\n");
- return (0);
- }
- cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
- if (!cs->hw.njet.base) {
- printk(KERN_WARNING "NETjet-S: No IO-Adr for PCI card found\n");
- return (0);
- }
- /* the TJ300 and TJ320 must be detected, the IRQ handling is different
- * unfortunately the chips use the same device ID, but the TJ320 has
- * the bit20 in status PCI cfg register set
- */
- pci_read_config_dword(dev_netjet, 0x04, &cfg);
- if (cfg & 0x00100000)
- cs->subtyp = 1; /* TJ320 */
- else
- cs->subtyp = 0; /* TJ300 */
- /* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG www.formula-n.com */
- if ((dev_netjet->subsystem_vendor == 0x55) &&
- (dev_netjet->subsystem_device == 0x02)) {
- printk(KERN_WARNING "Netjet: You tried to load this driver with an incompatible TigerJet-card\n");
- printk(KERN_WARNING "Use type=41 for Formula-n enter:now ISDN PCI and compatible\n");
- return (0);
- }
- /* end new code */
-
- return (1);
-}
-
-static int njs_cs_init(struct IsdnCard *card, struct IsdnCardState *cs)
-{
-
- cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
- cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF;
-
- cs->hw.njet.ctrl_reg = 0xff; /* Reset On */
- byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
- mdelay(10);
-
- cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */
- byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
- mdelay(10);
-
- cs->hw.njet.auxd = 0xC0;
- cs->hw.njet.dmactrl = 0;
-
- byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
- byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
- byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
-
- switch (((NETjet_ReadIC(cs, ISAC_RBCH) >> 5) & 3))
- {
- case 0:
- return 1; /* end loop */
-
- case 3:
- printk(KERN_WARNING "NETjet-S: NETspider-U PCI card found\n");
- return -1; /* continue looping */
-
- default:
- printk(KERN_WARNING "NETjet-S: No PCI card found\n");
- return 0; /* end loop & function */
- }
- return 1; /* end loop */
-}
-
-static int njs_cs_init_rest(struct IsdnCard *card, struct IsdnCardState *cs)
-{
- const int bytecnt = 256;
-
- printk(KERN_INFO
- "NETjet-S: %s card configured at %#lx IRQ %d\n",
- cs->subtyp ? "TJ320" : "TJ300", cs->hw.njet.base, cs->irq);
- if (!request_region(cs->hw.njet.base, bytecnt, "netjet-s isdn")) {
- printk(KERN_WARNING
- "HiSax: NETjet-S config port %#lx-%#lx already in use\n",
- cs->hw.njet.base,
- cs->hw.njet.base + bytecnt);
- return (0);
- }
- cs->readisac = &NETjet_ReadIC;
- cs->writeisac = &NETjet_WriteIC;
- cs->readisacfifo = &NETjet_ReadICfifo;
- cs->writeisacfifo = &NETjet_WriteICfifo;
- cs->BC_Read_Reg = &dummyrr;
- cs->BC_Write_Reg = &dummywr;
- cs->BC_Send_Data = &netjet_fill_dma;
- setup_isac(cs);
- cs->cardmsg = &NETjet_S_card_msg;
- cs->irq_func = &netjet_s_interrupt;
- cs->irq_flags |= IRQF_SHARED;
- ISACVersion(cs, "NETjet-S:");
-
- return (1);
-}
-
-static struct pci_dev *dev_netjet = NULL;
-
-int setup_netjet_s(struct IsdnCard *card)
-{
- int ret;
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
-
-#ifdef __BIG_ENDIAN
-#error "not running on big endian machines now"
-#endif
- strcpy(tmp, NETjet_S_revision);
- printk(KERN_INFO "HiSax: Traverse Tech. NETjet-S driver Rev. %s\n", HiSax_getrev(tmp));
- if (cs->typ != ISDN_CTYPE_NETJET_S)
- return (0);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
-
- for (;;)
- {
- if ((dev_netjet = hisax_find_pci_device(PCI_VENDOR_ID_TIGERJET,
- PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) {
- ret = njs_pci_probe(dev_netjet, cs);
- if (!ret)
- return (0);
- } else {
- printk(KERN_WARNING "NETjet-S: No PCI card found\n");
- return (0);
- }
-
- ret = njs_cs_init(card, cs);
- if (!ret)
- return (0);
- if (ret > 0)
- break;
- /* otherwise, ret < 0, continue looping */
- }
-
- return njs_cs_init_rest(card, cs);
-}
diff --git a/drivers/isdn/hisax/nj_u.c b/drivers/isdn/hisax/nj_u.c
deleted file mode 100644
index 4e8adbede361..000000000000
--- a/drivers/isdn/hisax/nj_u.c
+++ /dev/null
@@ -1,258 +0,0 @@
-/* $Id: nj_u.c,v 2.14.2.3 2004/01/13 14:31:26 keil Exp $
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/init.h>
-#include "hisax.h"
-#include "icc.h"
-#include "isdnl1.h"
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/ppp_defs.h>
-#include "netjet.h"
-
-static const char *NETjet_U_revision = "$Revision: 2.14.2.3 $";
-
-static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off)
-{
- return (5);
-}
-
-static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value)
-{
-}
-
-static irqreturn_t
-netjet_u_interrupt(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_char val, sval;
- u_long flags;
-
- spin_lock_irqsave(&cs->lock, flags);
- if (!((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT1)) &
- NETJET_ISACIRQ)) {
- val = NETjet_ReadIC(cs, ICC_ISTA);
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "tiger: i1 %x %x", sval, val);
- if (val) {
- icc_interrupt(cs, val);
- NETjet_WriteIC(cs, ICC_MASK, 0xFF);
- NETjet_WriteIC(cs, ICC_MASK, 0x0);
- }
- }
- /* start new code 13/07/00 GE */
- /* set bits in sval to indicate which page is free */
- if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) <
- inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ))
- /* the 2nd write page is free */
- sval = 0x08;
- else /* the 1st write page is free */
- sval = 0x04;
- if (inl(cs->hw.njet.base + NETJET_DMA_READ_ADR) <
- inl(cs->hw.njet.base + NETJET_DMA_READ_IRQ))
- /* the 2nd read page is free */
- sval = sval | 0x02;
- else /* the 1st read page is free */
- sval = sval | 0x01;
- if (sval != cs->hw.njet.last_is0) /* we have a DMA interrupt */
- {
- if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
- }
- cs->hw.njet.irqstat0 = sval;
- if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) !=
- (cs->hw.njet.last_is0 & NETJET_IRQM0_READ))
- /* we have a read dma int */
- read_tiger(cs);
- if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) !=
- (cs->hw.njet.last_is0 & NETJET_IRQM0_WRITE))
- /* we have a write dma int */
- write_tiger(cs);
- /* end new code 13/07/00 GE */
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- }
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static void
-reset_netjet_u(struct IsdnCardState *cs)
-{
- cs->hw.njet.ctrl_reg = 0xff; /* Reset On */
- byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
- mdelay(10);
- cs->hw.njet.ctrl_reg = 0x40; /* Reset Off and status read clear */
- /* now edge triggered for TJ320 GE 13/07/00 */
- byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
- mdelay(10);
- cs->hw.njet.auxd = 0xC0;
- cs->hw.njet.dmactrl = 0;
- byteout(cs->hw.njet.auxa, 0);
- byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
- byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
- byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
-}
-
-static int
-NETjet_U_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
- u_long flags;
-
- switch (mt) {
- case CARD_RESET:
- spin_lock_irqsave(&cs->lock, flags);
- reset_netjet_u(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_RELEASE:
- release_io_netjet(cs);
- return (0);
- case CARD_INIT:
- spin_lock_irqsave(&cs->lock, flags);
- inittiger(cs);
- reset_netjet_u(cs);
- clear_pending_icc_ints(cs);
- initicc(cs);
- /* Reenable all IRQ */
- cs->writeisac(cs, ICC_MASK, 0);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_TEST:
- return (0);
- }
- return (0);
-}
-
-static int nju_pci_probe(struct pci_dev *dev_netjet, struct IsdnCardState *cs)
-{
- if (pci_enable_device(dev_netjet))
- return (0);
- pci_set_master(dev_netjet);
- cs->irq = dev_netjet->irq;
- if (!cs->irq) {
- printk(KERN_WARNING "NETspider-U: No IRQ for PCI card found\n");
- return (0);
- }
- cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
- if (!cs->hw.njet.base) {
- printk(KERN_WARNING "NETspider-U: No IO-Adr for PCI card found\n");
- return (0);
- }
-
- return (1);
-}
-
-static int nju_cs_init(struct IsdnCard *card, struct IsdnCardState *cs)
-{
- cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
- cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF;
- mdelay(10);
-
- cs->hw.njet.ctrl_reg = 0xff; /* Reset On */
- byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
- mdelay(10);
-
- cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */
- byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
- mdelay(10);
-
- cs->hw.njet.auxd = 0xC0;
- cs->hw.njet.dmactrl = 0;
-
- byteout(cs->hw.njet.auxa, 0);
- byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
- byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
- byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
-
- switch (((NETjet_ReadIC(cs, ICC_RBCH) >> 5) & 3))
- {
- case 3:
- return 1; /* end loop */
-
- case 0:
- printk(KERN_WARNING "NETspider-U: NETjet-S PCI card found\n");
- return -1; /* continue looping */
-
- default:
- printk(KERN_WARNING "NETspider-U: No PCI card found\n");
- return 0; /* end loop & function */
- }
- return 1; /* end loop */
-}
-
-static int nju_cs_init_rest(struct IsdnCard *card, struct IsdnCardState *cs)
-{
- const int bytecnt = 256;
-
- printk(KERN_INFO
- "NETspider-U: PCI card configured at %#lx IRQ %d\n",
- cs->hw.njet.base, cs->irq);
- if (!request_region(cs->hw.njet.base, bytecnt, "netspider-u isdn")) {
- printk(KERN_WARNING
- "HiSax: NETspider-U config port %#lx-%#lx "
- "already in use\n",
- cs->hw.njet.base,
- cs->hw.njet.base + bytecnt);
- return (0);
- }
- setup_icc(cs);
- cs->readisac = &NETjet_ReadIC;
- cs->writeisac = &NETjet_WriteIC;
- cs->readisacfifo = &NETjet_ReadICfifo;
- cs->writeisacfifo = &NETjet_WriteICfifo;
- cs->BC_Read_Reg = &dummyrr;
- cs->BC_Write_Reg = &dummywr;
- cs->BC_Send_Data = &netjet_fill_dma;
- cs->cardmsg = &NETjet_U_card_msg;
- cs->irq_func = &netjet_u_interrupt;
- cs->irq_flags |= IRQF_SHARED;
- ICCVersion(cs, "NETspider-U:");
-
- return (1);
-}
-
-static struct pci_dev *dev_netjet = NULL;
-
-int setup_netjet_u(struct IsdnCard *card)
-{
- int ret;
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
-
-#ifdef __BIG_ENDIAN
-#error "not running on big endian machines now"
-#endif
-
- strcpy(tmp, NETjet_U_revision);
- printk(KERN_INFO "HiSax: Traverse Tech. NETspider-U driver Rev. %s\n", HiSax_getrev(tmp));
- if (cs->typ != ISDN_CTYPE_NETJET_U)
- return (0);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
-
- for (;;)
- {
- if ((dev_netjet = hisax_find_pci_device(PCI_VENDOR_ID_TIGERJET,
- PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) {
- ret = nju_pci_probe(dev_netjet, cs);
- if (!ret)
- return (0);
- } else {
- printk(KERN_WARNING "NETspider-U: No PCI card found\n");
- return (0);
- }
-
- ret = nju_cs_init(card, cs);
- if (!ret)
- return (0);
- if (ret > 0)
- break;
- /* ret < 0 == continue looping */
- }
-
- return nju_cs_init_rest(card, cs);
-}
diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c
deleted file mode 100644
index 6b8c3fbe3965..000000000000
--- a/drivers/isdn/hisax/q931.c
+++ /dev/null
@@ -1,1513 +0,0 @@
-/* $Id: q931.c,v 1.12.2.3 2004/01/13 14:31:26 keil Exp $
- *
- * code to decode ITU Q.931 call control messages
- *
- * Author Jan den Ouden
- * Copyright by Jan den Ouden
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Changelog:
- *
- * Pauline Middelink general improvements
- * Beat Doebeli cause texts, display information element
- * Karsten Keil cause texts, display information element for 1TR6
- *
- */
-
-
-#include "hisax.h"
-#include "l3_1tr6.h"
-
-void
-iecpy(u_char *dest, u_char *iestart, int ieoffset)
-{
- u_char *p;
- int l;
-
- p = iestart + ieoffset + 2;
- l = iestart[1] - ieoffset;
- while (l--)
- *dest++ = *p++;
- *dest++ = '\0';
-}
-
-/*
- * According to Table 4-2/Q.931
- */
-static
-struct MessageType {
- u_char nr;
- char *descr;
-} mtlist[] = {
-
- {
- 0x1, "ALERTING"
- },
- {
- 0x2, "CALL PROCEEDING"
- },
- {
- 0x7, "CONNECT"
- },
- {
- 0xf, "CONNECT ACKNOWLEDGE"
- },
- {
- 0x3, "PROGRESS"
- },
- {
- 0x5, "SETUP"
- },
- {
- 0xd, "SETUP ACKNOWLEDGE"
- },
- {
- 0x24, "HOLD"
- },
- {
- 0x28, "HOLD ACKNOWLEDGE"
- },
- {
- 0x30, "HOLD REJECT"
- },
- {
- 0x31, "RETRIEVE"
- },
- {
- 0x33, "RETRIEVE ACKNOWLEDGE"
- },
- {
- 0x37, "RETRIEVE REJECT"
- },
- {
- 0x26, "RESUME"
- },
- {
- 0x2e, "RESUME ACKNOWLEDGE"
- },
- {
- 0x22, "RESUME REJECT"
- },
- {
- 0x25, "SUSPEND"
- },
- {
- 0x2d, "SUSPEND ACKNOWLEDGE"
- },
- {
- 0x21, "SUSPEND REJECT"
- },
- {
- 0x20, "USER INFORMATION"
- },
- {
- 0x45, "DISCONNECT"
- },
- {
- 0x4d, "RELEASE"
- },
- {
- 0x5a, "RELEASE COMPLETE"
- },
- {
- 0x46, "RESTART"
- },
- {
- 0x4e, "RESTART ACKNOWLEDGE"
- },
- {
- 0x60, "SEGMENT"
- },
- {
- 0x79, "CONGESTION CONTROL"
- },
- {
- 0x7b, "INFORMATION"
- },
- {
- 0x62, "FACILITY"
- },
- {
- 0x6e, "NOTIFY"
- },
- {
- 0x7d, "STATUS"
- },
- {
- 0x75, "STATUS ENQUIRY"
- }
-};
-
-#define MTSIZE ARRAY_SIZE(mtlist)
-
-static
-struct MessageType mt_n0[] =
-{
- {MT_N0_REG_IND, "REGister INDication"},
- {MT_N0_CANC_IND, "CANCel INDication"},
- {MT_N0_FAC_STA, "FACility STAtus"},
- {MT_N0_STA_ACK, "STAtus ACKnowledge"},
- {MT_N0_STA_REJ, "STAtus REJect"},
- {MT_N0_FAC_INF, "FACility INFormation"},
- {MT_N0_INF_ACK, "INFormation ACKnowledge"},
- {MT_N0_INF_REJ, "INFormation REJect"},
- {MT_N0_CLOSE, "CLOSE"},
- {MT_N0_CLO_ACK, "CLOse ACKnowledge"}
-};
-
-#define MT_N0_LEN ARRAY_SIZE(mt_n0)
-
-static
-struct MessageType mt_n1[] =
-{
- {MT_N1_ESC, "ESCape"},
- {MT_N1_ALERT, "ALERT"},
- {MT_N1_CALL_SENT, "CALL SENT"},
- {MT_N1_CONN, "CONNect"},
- {MT_N1_CONN_ACK, "CONNect ACKnowledge"},
- {MT_N1_SETUP, "SETUP"},
- {MT_N1_SETUP_ACK, "SETUP ACKnowledge"},
- {MT_N1_RES, "RESume"},
- {MT_N1_RES_ACK, "RESume ACKnowledge"},
- {MT_N1_RES_REJ, "RESume REJect"},
- {MT_N1_SUSP, "SUSPend"},
- {MT_N1_SUSP_ACK, "SUSPend ACKnowledge"},
- {MT_N1_SUSP_REJ, "SUSPend REJect"},
- {MT_N1_USER_INFO, "USER INFO"},
- {MT_N1_DET, "DETach"},
- {MT_N1_DISC, "DISConnect"},
- {MT_N1_REL, "RELease"},
- {MT_N1_REL_ACK, "RELease ACKnowledge"},
- {MT_N1_CANC_ACK, "CANCel ACKnowledge"},
- {MT_N1_CANC_REJ, "CANCel REJect"},
- {MT_N1_CON_CON, "CONgestion CONtrol"},
- {MT_N1_FAC, "FACility"},
- {MT_N1_FAC_ACK, "FACility ACKnowledge"},
- {MT_N1_FAC_CAN, "FACility CANcel"},
- {MT_N1_FAC_REG, "FACility REGister"},
- {MT_N1_FAC_REJ, "FACility REJect"},
- {MT_N1_INFO, "INFOrmation"},
- {MT_N1_REG_ACK, "REGister ACKnowledge"},
- {MT_N1_REG_REJ, "REGister REJect"},
- {MT_N1_STAT, "STATus"}
-};
-
-#define MT_N1_LEN ARRAY_SIZE(mt_n1)
-
-
-static int
-prbits(char *dest, u_char b, int start, int len)
-{
- char *dp = dest;
-
- b = b << (8 - start);
- while (len--) {
- if (b & 0x80)
- *dp++ = '1';
- else
- *dp++ = '0';
- b = b << 1;
- }
- return (dp - dest);
-}
-
-static
-u_char *
-skipext(u_char *p)
-{
- while (!(*p++ & 0x80));
- return (p);
-}
-
-/*
- * Cause Values According to Q.850
- * edescr: English description
- * ddescr: German description used by Swissnet II (Swiss Telecom
- * not yet written...
- */
-
-static
-struct CauseValue {
- u_char nr;
- char *edescr;
- char *ddescr;
-} cvlist[] = {
-
- {
- 0x01, "Unallocated (unassigned) number", "Nummer nicht zugeteilt"
- },
- {
- 0x02, "No route to specified transit network", ""
- },
- {
- 0x03, "No route to destination", ""
- },
- {
- 0x04, "Send special information tone", ""
- },
- {
- 0x05, "Misdialled trunk prefix", ""
- },
- {
- 0x06, "Channel unacceptable", "Kanal nicht akzeptierbar"
- },
- {
- 0x07, "Channel awarded and being delivered in an established channel", ""
- },
- {
- 0x08, "Preemption", ""
- },
- {
- 0x09, "Preemption - circuit reserved for reuse", ""
- },
- {
- 0x10, "Normal call clearing", "Normale Ausloesung"
- },
- {
- 0x11, "User busy", "TNB besetzt"
- },
- {
- 0x12, "No user responding", ""
- },
- {
- 0x13, "No answer from user (user alerted)", ""
- },
- {
- 0x14, "Subscriber absent", ""
- },
- {
- 0x15, "Call rejected", ""
- },
- {
- 0x16, "Number changed", ""
- },
- {
- 0x1a, "non-selected user clearing", ""
- },
- {
- 0x1b, "Destination out of order", ""
- },
- {
- 0x1c, "Invalid number format (address incomplete)", ""
- },
- {
- 0x1d, "Facility rejected", ""
- },
- {
- 0x1e, "Response to Status enquiry", ""
- },
- {
- 0x1f, "Normal, unspecified", ""
- },
- {
- 0x22, "No circuit/channel available", ""
- },
- {
- 0x26, "Network out of order", ""
- },
- {
- 0x27, "Permanent frame mode connection out-of-service", ""
- },
- {
- 0x28, "Permanent frame mode connection operational", ""
- },
- {
- 0x29, "Temporary failure", ""
- },
- {
- 0x2a, "Switching equipment congestion", ""
- },
- {
- 0x2b, "Access information discarded", ""
- },
- {
- 0x2c, "Requested circuit/channel not available", ""
- },
- {
- 0x2e, "Precedence call blocked", ""
- },
- {
- 0x2f, "Resource unavailable, unspecified", ""
- },
- {
- 0x31, "Quality of service unavailable", ""
- },
- {
- 0x32, "Requested facility not subscribed", ""
- },
- {
- 0x35, "Outgoing calls barred within CUG", ""
- },
- {
- 0x37, "Incoming calls barred within CUG", ""
- },
- {
- 0x39, "Bearer capability not authorized", ""
- },
- {
- 0x3a, "Bearer capability not presently available", ""
- },
- {
- 0x3e, "Inconsistency in designated outgoing access information and subscriber class ", " "
- },
- {
- 0x3f, "Service or option not available, unspecified", ""
- },
- {
- 0x41, "Bearer capability not implemented", ""
- },
- {
- 0x42, "Channel type not implemented", ""
- },
- {
- 0x43, "Requested facility not implemented", ""
- },
- {
- 0x44, "Only restricted digital information bearer capability is available", ""
- },
- {
- 0x4f, "Service or option not implemented", ""
- },
- {
- 0x51, "Invalid call reference value", ""
- },
- {
- 0x52, "Identified channel does not exist", ""
- },
- {
- 0x53, "A suspended call exists, but this call identity does not", ""
- },
- {
- 0x54, "Call identity in use", ""
- },
- {
- 0x55, "No call suspended", ""
- },
- {
- 0x56, "Call having the requested call identity has been cleared", ""
- },
- {
- 0x57, "User not member of CUG", ""
- },
- {
- 0x58, "Incompatible destination", ""
- },
- {
- 0x5a, "Non-existent CUG", ""
- },
- {
- 0x5b, "Invalid transit network selection", ""
- },
- {
- 0x5f, "Invalid message, unspecified", ""
- },
- {
- 0x60, "Mandatory information element is missing", ""
- },
- {
- 0x61, "Message type non-existent or not implemented", ""
- },
- {
- 0x62, "Message not compatible with call state or message type non-existent or not implemented ", " "
- },
- {
- 0x63, "Information element/parameter non-existent or not implemented", ""
- },
- {
- 0x64, "Invalid information element contents", ""
- },
- {
- 0x65, "Message not compatible with call state", ""
- },
- {
- 0x66, "Recovery on timer expiry", ""
- },
- {
- 0x67, "Parameter non-existent or not implemented - passed on", ""
- },
- {
- 0x6e, "Message with unrecognized parameter discarded", ""
- },
- {
- 0x6f, "Protocol error, unspecified", ""
- },
- {
- 0x7f, "Interworking, unspecified", ""
- },
-};
-
-#define CVSIZE ARRAY_SIZE(cvlist)
-
-static
-int
-prcause(char *dest, u_char *p)
-{
- u_char *end;
- char *dp = dest;
- int i, cause;
-
- end = p + p[1] + 1;
- p += 2;
- dp += sprintf(dp, " coding ");
- dp += prbits(dp, *p, 7, 2);
- dp += sprintf(dp, " location ");
- dp += prbits(dp, *p, 4, 4);
- *dp++ = '\n';
- p = skipext(p);
-
- cause = 0x7f & *p++;
-
- /* locate cause value */
- for (i = 0; i < CVSIZE; i++)
- if (cvlist[i].nr == cause)
- break;
-
- /* display cause value if it exists */
- if (i == CVSIZE)
- dp += sprintf(dp, "Unknown cause type %x!\n", cause);
- else
- dp += sprintf(dp, " cause value %x : %s \n", cause, cvlist[i].edescr);
-
- while (!0) {
- if (p > end)
- break;
- dp += sprintf(dp, " diag attribute %d ", *p++ & 0x7f);
- dp += sprintf(dp, " rej %d ", *p & 0x7f);
- if (*p & 0x80) {
- *dp++ = '\n';
- break;
- } else
- dp += sprintf(dp, " av %d\n", (*++p) & 0x7f);
- }
- return (dp - dest);
-
-}
-
-static
-struct MessageType cause_1tr6[] =
-{
- {CAUSE_InvCRef, "Invalid Call Reference"},
- {CAUSE_BearerNotImpl, "Bearer Service Not Implemented"},
- {CAUSE_CIDunknown, "Caller Identity unknown"},
- {CAUSE_CIDinUse, "Caller Identity in Use"},
- {CAUSE_NoChans, "No Channels available"},
- {CAUSE_FacNotImpl, "Facility Not Implemented"},
- {CAUSE_FacNotSubscr, "Facility Not Subscribed"},
- {CAUSE_OutgoingBarred, "Outgoing calls barred"},
- {CAUSE_UserAccessBusy, "User Access Busy"},
- {CAUSE_NegativeGBG, "Negative GBG"},
- {CAUSE_UnknownGBG, "Unknown GBG"},
- {CAUSE_NoSPVknown, "No SPV known"},
- {CAUSE_DestNotObtain, "Destination not obtainable"},
- {CAUSE_NumberChanged, "Number changed"},
- {CAUSE_OutOfOrder, "Out Of Order"},
- {CAUSE_NoUserResponse, "No User Response"},
- {CAUSE_UserBusy, "User Busy"},
- {CAUSE_IncomingBarred, "Incoming Barred"},
- {CAUSE_CallRejected, "Call Rejected"},
- {CAUSE_NetworkCongestion, "Network Congestion"},
- {CAUSE_RemoteUser, "Remote User initiated"},
- {CAUSE_LocalProcErr, "Local Procedure Error"},
- {CAUSE_RemoteProcErr, "Remote Procedure Error"},
- {CAUSE_RemoteUserSuspend, "Remote User Suspend"},
- {CAUSE_RemoteUserResumed, "Remote User Resumed"},
- {CAUSE_UserInfoDiscarded, "User Info Discarded"}
-};
-
-static int cause_1tr6_len = ARRAY_SIZE(cause_1tr6);
-
-static int
-prcause_1tr6(char *dest, u_char *p)
-{
- char *dp = dest;
- int i, cause;
-
- p++;
- if (0 == *p) {
- dp += sprintf(dp, " OK (cause length=0)\n");
- return (dp - dest);
- } else if (*p > 1) {
- dp += sprintf(dp, " coding ");
- dp += prbits(dp, p[2], 7, 2);
- dp += sprintf(dp, " location ");
- dp += prbits(dp, p[2], 4, 4);
- *dp++ = '\n';
- }
- p++;
- cause = 0x7f & *p;
-
- /* locate cause value */
- for (i = 0; i < cause_1tr6_len; i++)
- if (cause_1tr6[i].nr == cause)
- break;
-
- /* display cause value if it exists */
- if (i == cause_1tr6_len)
- dp += sprintf(dp, "Unknown cause type %x!\n", cause);
- else
- dp += sprintf(dp, " cause value %x : %s \n", cause, cause_1tr6[i].descr);
-
- return (dp - dest);
-
-}
-
-static int
-prchident(char *dest, u_char *p)
-{
- char *dp = dest;
-
- p += 2;
- dp += sprintf(dp, " octet 3 ");
- dp += prbits(dp, *p, 8, 8);
- *dp++ = '\n';
- return (dp - dest);
-}
-
-static int
-prcalled(char *dest, u_char *p)
-{
- int l;
- char *dp = dest;
-
- p++;
- l = *p++ - 1;
- dp += sprintf(dp, " octet 3 ");
- dp += prbits(dp, *p++, 8, 8);
- *dp++ = '\n';
- dp += sprintf(dp, " number digits ");
- while (l--)
- *dp++ = *p++;
- *dp++ = '\n';
- return (dp - dest);
-}
-static int
-prcalling(char *dest, u_char *p)
-{
- int l;
- char *dp = dest;
-
- p++;
- l = *p++ - 1;
- dp += sprintf(dp, " octet 3 ");
- dp += prbits(dp, *p, 8, 8);
- *dp++ = '\n';
- if (!(*p & 0x80)) {
- dp += sprintf(dp, " octet 3a ");
- dp += prbits(dp, *++p, 8, 8);
- *dp++ = '\n';
- l--;
- }
- p++;
-
- dp += sprintf(dp, " number digits ");
- while (l--)
- *dp++ = *p++;
- *dp++ = '\n';
- return (dp - dest);
-}
-
-static
-int
-prbearer(char *dest, u_char *p)
-{
- char *dp = dest, ch;
-
- p += 2;
- dp += sprintf(dp, " octet 3 ");
- dp += prbits(dp, *p++, 8, 8);
- *dp++ = '\n';
- dp += sprintf(dp, " octet 4 ");
- dp += prbits(dp, *p, 8, 8);
- *dp++ = '\n';
- if ((*p++ & 0x1f) == 0x18) {
- dp += sprintf(dp, " octet 4.1 ");
- dp += prbits(dp, *p++, 8, 8);
- *dp++ = '\n';
- }
- /* check for user information layer 1 */
- if ((*p & 0x60) == 0x20) {
- ch = ' ';
- do {
- dp += sprintf(dp, " octet 5%c ", ch);
- dp += prbits(dp, *p, 8, 8);
- *dp++ = '\n';
- if (ch == ' ')
- ch = 'a';
- else
- ch++;
- }
- while (!(*p++ & 0x80));
- }
- /* check for user information layer 2 */
- if ((*p & 0x60) == 0x40) {
- dp += sprintf(dp, " octet 6 ");
- dp += prbits(dp, *p++, 8, 8);
- *dp++ = '\n';
- }
- /* check for user information layer 3 */
- if ((*p & 0x60) == 0x60) {
- dp += sprintf(dp, " octet 7 ");
- dp += prbits(dp, *p++, 8, 8);
- *dp++ = '\n';
- }
- return (dp - dest);
-}
-
-
-static
-int
-prbearer_ni1(char *dest, u_char *p)
-{
- char *dp = dest;
- u_char len;
-
- p++;
- len = *p++;
- dp += sprintf(dp, " octet 3 ");
- dp += prbits(dp, *p, 8, 8);
- switch (*p++) {
- case 0x80:
- dp += sprintf(dp, " Speech");
- break;
- case 0x88:
- dp += sprintf(dp, " Unrestricted digital information");
- break;
- case 0x90:
- dp += sprintf(dp, " 3.1 kHz audio");
- break;
- default:
- dp += sprintf(dp, " Unknown information-transfer capability");
- }
- *dp++ = '\n';
- dp += sprintf(dp, " octet 4 ");
- dp += prbits(dp, *p, 8, 8);
- switch (*p++) {
- case 0x90:
- dp += sprintf(dp, " 64 kbps, circuit mode");
- break;
- case 0xc0:
- dp += sprintf(dp, " Packet mode");
- break;
- default:
- dp += sprintf(dp, " Unknown transfer mode");
- }
- *dp++ = '\n';
- if (len > 2) {
- dp += sprintf(dp, " octet 5 ");
- dp += prbits(dp, *p, 8, 8);
- switch (*p++) {
- case 0x21:
- dp += sprintf(dp, " Rate adaption\n");
- dp += sprintf(dp, " octet 5a ");
- dp += prbits(dp, *p, 8, 8);
- break;
- case 0xa2:
- dp += sprintf(dp, " u-law");
- break;
- default:
- dp += sprintf(dp, " Unknown UI layer 1 protocol");
- }
- *dp++ = '\n';
- }
- return (dp - dest);
-}
-
-static int
-general(char *dest, u_char *p)
-{
- char *dp = dest;
- char ch = ' ';
- int l, octet = 3;
-
- p++;
- l = *p++;
- /* Iterate over all octets in the information element */
- while (l--) {
- dp += sprintf(dp, " octet %d%c ", octet, ch);
- dp += prbits(dp, *p++, 8, 8);
- *dp++ = '\n';
-
- /* last octet in group? */
- if (*p & 0x80) {
- octet++;
- ch = ' ';
- } else if (ch == ' ')
- ch = 'a';
- else
- ch++;
- }
- return (dp - dest);
-}
-
-static int
-general_ni1(char *dest, u_char *p)
-{
- char *dp = dest;
- char ch = ' ';
- int l, octet = 3;
-
- p++;
- l = *p++;
- /* Iterate over all octets in the information element */
- while (l--) {
- dp += sprintf(dp, " octet %d%c ", octet, ch);
- dp += prbits(dp, *p, 8, 8);
- *dp++ = '\n';
-
- /* last octet in group? */
- if (*p++ & 0x80) {
- octet++;
- ch = ' ';
- } else if (ch == ' ')
- ch = 'a';
- else
- ch++;
- }
- return (dp - dest);
-}
-
-static int
-prcharge(char *dest, u_char *p)
-{
- char *dp = dest;
- int l;
-
- p++;
- l = *p++ - 1;
- dp += sprintf(dp, " GEA ");
- dp += prbits(dp, *p++, 8, 8);
- dp += sprintf(dp, " Anzahl: ");
- /* Iterate over all octets in the * information element */
- while (l--)
- *dp++ = *p++;
- *dp++ = '\n';
- return (dp - dest);
-}
-static int
-prtext(char *dest, u_char *p)
-{
- char *dp = dest;
- int l;
-
- p++;
- l = *p++;
- dp += sprintf(dp, " ");
- /* Iterate over all octets in the * information element */
- while (l--)
- *dp++ = *p++;
- *dp++ = '\n';
- return (dp - dest);
-}
-
-static int
-prfeatureind(char *dest, u_char *p)
-{
- char *dp = dest;
-
- p += 2; /* skip id, len */
- dp += sprintf(dp, " octet 3 ");
- dp += prbits(dp, *p, 8, 8);
- *dp++ = '\n';
- if (!(*p++ & 0x80)) {
- dp += sprintf(dp, " octet 4 ");
- dp += prbits(dp, *p++, 8, 8);
- *dp++ = '\n';
- }
- dp += sprintf(dp, " Status: ");
- switch (*p) {
- case 0:
- dp += sprintf(dp, "Idle");
- break;
- case 1:
- dp += sprintf(dp, "Active");
- break;
- case 2:
- dp += sprintf(dp, "Prompt");
- break;
- case 3:
- dp += sprintf(dp, "Pending");
- break;
- default:
- dp += sprintf(dp, "(Reserved)");
- break;
- }
- *dp++ = '\n';
- return (dp - dest);
-}
-
-static
-struct DTag { /* Display tags */
- u_char nr;
- char *descr;
-} dtaglist[] = {
- { 0x82, "Continuation" },
- { 0x83, "Called address" },
- { 0x84, "Cause" },
- { 0x85, "Progress indicator" },
- { 0x86, "Notification indicator" },
- { 0x87, "Prompt" },
- { 0x88, "Accumlated digits" },
- { 0x89, "Status" },
- { 0x8a, "Inband" },
- { 0x8b, "Calling address" },
- { 0x8c, "Reason" },
- { 0x8d, "Calling party name" },
- { 0x8e, "Called party name" },
- { 0x8f, "Original called name" },
- { 0x90, "Redirecting name" },
- { 0x91, "Connected name" },
- { 0x92, "Originating restrictions" },
- { 0x93, "Date & time of day" },
- { 0x94, "Call Appearance ID" },
- { 0x95, "Feature address" },
- { 0x96, "Redirection name" },
- { 0x9e, "Text" },
-};
-#define DTAGSIZE ARRAY_SIZE(dtaglist)
-
-static int
-disptext_ni1(char *dest, u_char *p)
-{
- char *dp = dest;
- int l, tag, len, i;
-
- p++;
- l = *p++ - 1;
- if (*p++ != 0x80) {
- dp += sprintf(dp, " Unknown display type\n");
- return (dp - dest);
- }
- /* Iterate over all tag,length,text fields */
- while (l > 0) {
- tag = *p++;
- len = *p++;
- l -= len + 2;
- /* Don't space or skip */
- if ((tag == 0x80) || (tag == 0x81)) p++;
- else {
- for (i = 0; i < DTAGSIZE; i++)
- if (tag == dtaglist[i].nr)
- break;
-
- /* When not found, give appropriate msg */
- if (i != DTAGSIZE) {
- dp += sprintf(dp, " %s: ", dtaglist[i].descr);
- while (len--)
- *dp++ = *p++;
- } else {
- dp += sprintf(dp, " (unknown display tag %2x): ", tag);
- while (len--)
- *dp++ = *p++;
- }
- dp += sprintf(dp, "\n");
- }
- }
- return (dp - dest);
-}
-static int
-display(char *dest, u_char *p)
-{
- char *dp = dest;
- char ch = ' ';
- int l, octet = 3;
-
- p++;
- l = *p++;
- /* Iterate over all octets in the * display-information element */
- dp += sprintf(dp, " \"");
- while (l--) {
- dp += sprintf(dp, "%c", *p++);
-
- /* last octet in group? */
- if (*p & 0x80) {
- octet++;
- ch = ' ';
- } else if (ch == ' ')
- ch = 'a';
-
- else
- ch++;
- }
- *dp++ = '\"';
- *dp++ = '\n';
- return (dp - dest);
-}
-
-static int
-prfacility(char *dest, u_char *p)
-{
- char *dp = dest;
- int l, l2;
-
- p++;
- l = *p++;
- dp += sprintf(dp, " octet 3 ");
- dp += prbits(dp, *p++, 8, 8);
- dp += sprintf(dp, "\n");
- l -= 1;
-
- while (l > 0) {
- dp += sprintf(dp, " octet 4 ");
- dp += prbits(dp, *p++, 8, 8);
- dp += sprintf(dp, "\n");
- dp += sprintf(dp, " octet 5 %d\n", l2 = *p++ & 0x7f);
- l -= 2;
- dp += sprintf(dp, " contents ");
- while (l2--) {
- dp += sprintf(dp, "%2x ", *p++);
- l--;
- }
- dp += sprintf(dp, "\n");
- }
-
- return (dp - dest);
-}
-
-static
-struct InformationElement {
- u_char nr;
- char *descr;
- int (*f) (char *, u_char *);
-} ielist[] = {
-
- {
- 0x00, "Segmented message", general
- },
- {
- 0x04, "Bearer capability", prbearer
- },
- {
- 0x08, "Cause", prcause
- },
- {
- 0x10, "Call identity", general
- },
- {
- 0x14, "Call state", general
- },
- {
- 0x18, "Channel identification", prchident
- },
- {
- 0x1c, "Facility", prfacility
- },
- {
- 0x1e, "Progress indicator", general
- },
- {
- 0x20, "Network-specific facilities", general
- },
- {
- 0x27, "Notification indicator", general
- },
- {
- 0x28, "Display", display
- },
- {
- 0x29, "Date/Time", general
- },
- {
- 0x2c, "Keypad facility", general
- },
- {
- 0x34, "Signal", general
- },
- {
- 0x40, "Information rate", general
- },
- {
- 0x42, "End-to-end delay", general
- },
- {
- 0x43, "Transit delay selection and indication", general
- },
- {
- 0x44, "Packet layer binary parameters", general
- },
- {
- 0x45, "Packet layer window size", general
- },
- {
- 0x46, "Packet size", general
- },
- {
- 0x47, "Closed user group", general
- },
- {
- 0x4a, "Reverse charge indication", general
- },
- {
- 0x6c, "Calling party number", prcalling
- },
- {
- 0x6d, "Calling party subaddress", general
- },
- {
- 0x70, "Called party number", prcalled
- },
- {
- 0x71, "Called party subaddress", general
- },
- {
- 0x74, "Redirecting number", general
- },
- {
- 0x78, "Transit network selection", general
- },
- {
- 0x79, "Restart indicator", general
- },
- {
- 0x7c, "Low layer compatibility", general
- },
- {
- 0x7d, "High layer compatibility", general
- },
- {
- 0x7e, "User-user", general
- },
- {
- 0x7f, "Escape for extension", general
- },
-};
-
-
-#define IESIZE ARRAY_SIZE(ielist)
-
-static
-struct InformationElement ielist_ni1[] = {
- { 0x04, "Bearer Capability", prbearer_ni1 },
- { 0x08, "Cause", prcause },
- { 0x14, "Call State", general_ni1 },
- { 0x18, "Channel Identification", prchident },
- { 0x1e, "Progress Indicator", general_ni1 },
- { 0x27, "Notification Indicator", general_ni1 },
- { 0x2c, "Keypad Facility", prtext },
- { 0x32, "Information Request", general_ni1 },
- { 0x34, "Signal", general_ni1 },
- { 0x38, "Feature Activation", general_ni1 },
- { 0x39, "Feature Indication", prfeatureind },
- { 0x3a, "Service Profile Identification (SPID)", prtext },
- { 0x3b, "Endpoint Identifier", general_ni1 },
- { 0x6c, "Calling Party Number", prcalling },
- { 0x6d, "Calling Party Subaddress", general_ni1 },
- { 0x70, "Called Party Number", prcalled },
- { 0x71, "Called Party Subaddress", general_ni1 },
- { 0x74, "Redirecting Number", general_ni1 },
- { 0x78, "Transit Network Selection", general_ni1 },
- { 0x7c, "Low Layer Compatibility", general_ni1 },
- { 0x7d, "High Layer Compatibility", general_ni1 },
-};
-
-
-#define IESIZE_NI1 ARRAY_SIZE(ielist_ni1)
-
-static
-struct InformationElement ielist_ni1_cs5[] = {
- { 0x1d, "Operator system access", general_ni1 },
- { 0x2a, "Display text", disptext_ni1 },
-};
-
-#define IESIZE_NI1_CS5 ARRAY_SIZE(ielist_ni1_cs5)
-
-static
-struct InformationElement ielist_ni1_cs6[] = {
- { 0x7b, "Call appearance", general_ni1 },
-};
-
-#define IESIZE_NI1_CS6 ARRAY_SIZE(ielist_ni1_cs6)
-
-static struct InformationElement we_0[] =
-{
- {WE0_cause, "Cause", prcause_1tr6},
- {WE0_connAddr, "Connecting Address", prcalled},
- {WE0_callID, "Call IDentity", general},
- {WE0_chanID, "Channel IDentity", general},
- {WE0_netSpecFac, "Network Specific Facility", general},
- {WE0_display, "Display", general},
- {WE0_keypad, "Keypad", general},
- {WE0_origAddr, "Origination Address", prcalled},
- {WE0_destAddr, "Destination Address", prcalled},
- {WE0_userInfo, "User Info", general}
-};
-
-#define WE_0_LEN ARRAY_SIZE(we_0)
-
-static struct InformationElement we_6[] =
-{
- {WE6_serviceInd, "Service Indicator", general},
- {WE6_chargingInfo, "Charging Information", prcharge},
- {WE6_date, "Date", prtext},
- {WE6_facSelect, "Facility Select", general},
- {WE6_facStatus, "Facility Status", general},
- {WE6_statusCalled, "Status Called", general},
- {WE6_addTransAttr, "Additional Transmission Attributes", general}
-};
-#define WE_6_LEN ARRAY_SIZE(we_6)
-
-int
-QuickHex(char *txt, u_char *p, int cnt)
-{
- register int i;
- register char *t = txt;
-
- for (i = 0; i < cnt; i++) {
- *t++ = ' ';
- *t++ = hex_asc_hi(p[i]);
- *t++ = hex_asc_lo(p[i]);
- }
- *t++ = 0;
- return (t - txt);
-}
-
-void
-LogFrame(struct IsdnCardState *cs, u_char *buf, int size)
-{
- char *dp;
-
- if (size < 1)
- return;
- dp = cs->dlog;
- if (size < MAX_DLOG_SPACE / 3 - 10) {
- *dp++ = 'H';
- *dp++ = 'E';
- *dp++ = 'X';
- *dp++ = ':';
- dp += QuickHex(dp, buf, size);
- dp--;
- *dp++ = '\n';
- *dp = 0;
- HiSax_putstatus(cs, NULL, cs->dlog);
- } else
- HiSax_putstatus(cs, "LogFrame: ", "warning Frame too big (%d)", size);
-}
-
-void
-dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir)
-{
- u_char *bend, *buf;
- char *dp;
- unsigned char pd, cr_l, cr, mt;
- unsigned char sapi, tei, ftyp;
- int i, cset = 0, cs_old = 0, cs_fest = 0;
- int size, finish = 0;
-
- if (skb->len < 3)
- return;
- /* display header */
- dp = cs->dlog;
- dp += jiftime(dp, jiffies);
- *dp++ = ' ';
- sapi = skb->data[0] >> 2;
- tei = skb->data[1] >> 1;
- ftyp = skb->data[2];
- buf = skb->data;
- dp += sprintf(dp, "frame %s ", dir ? "network->user" : "user->network");
- size = skb->len;
-
- if (tei == GROUP_TEI) {
- if (sapi == CTRL_SAPI) { /* sapi 0 */
- if (ftyp == 3) {
- dp += sprintf(dp, "broadcast\n");
- buf += 3;
- size -= 3;
- } else {
- dp += sprintf(dp, "no UI broadcast\n");
- finish = 1;
- }
- } else if (sapi == TEI_SAPI) {
- dp += sprintf(dp, "tei management\n");
- finish = 1;
- } else {
- dp += sprintf(dp, "unknown sapi %d broadcast\n", sapi);
- finish = 1;
- }
- } else {
- if (sapi == CTRL_SAPI) {
- if (!(ftyp & 1)) { /* IFrame */
- dp += sprintf(dp, "with tei %d\n", tei);
- buf += 4;
- size -= 4;
- } else {
- dp += sprintf(dp, "SFrame with tei %d\n", tei);
- finish = 1;
- }
- } else {
- dp += sprintf(dp, "unknown sapi %d tei %d\n", sapi, tei);
- finish = 1;
- }
- }
- bend = skb->data + skb->len;
- if (buf >= bend) {
- dp += sprintf(dp, "frame too short\n");
- finish = 1;
- }
- if (finish) {
- *dp = 0;
- HiSax_putstatus(cs, NULL, cs->dlog);
- return;
- }
- if ((0xfe & buf[0]) == PROTO_DIS_N0) { /* 1TR6 */
- /* locate message type */
- pd = *buf++;
- cr_l = *buf++;
- if (cr_l)
- cr = *buf++;
- else
- cr = 0;
- mt = *buf++;
- if (pd == PROTO_DIS_N0) { /* N0 */
- for (i = 0; i < MT_N0_LEN; i++)
- if (mt_n0[i].nr == mt)
- break;
- /* display message type if it exists */
- if (i == MT_N0_LEN)
- dp += sprintf(dp, "callref %d %s size %d unknown message type N0 %x!\n",
- cr & 0x7f, (cr & 0x80) ? "called" : "caller",
- size, mt);
- else
- dp += sprintf(dp, "callref %d %s size %d message type %s\n",
- cr & 0x7f, (cr & 0x80) ? "called" : "caller",
- size, mt_n0[i].descr);
- } else { /* N1 */
- for (i = 0; i < MT_N1_LEN; i++)
- if (mt_n1[i].nr == mt)
- break;
- /* display message type if it exists */
- if (i == MT_N1_LEN)
- dp += sprintf(dp, "callref %d %s size %d unknown message type N1 %x!\n",
- cr & 0x7f, (cr & 0x80) ? "called" : "caller",
- size, mt);
- else
- dp += sprintf(dp, "callref %d %s size %d message type %s\n",
- cr & 0x7f, (cr & 0x80) ? "called" : "caller",
- size, mt_n1[i].descr);
- }
-
- /* display each information element */
- while (buf < bend) {
- /* Is it a single octet information element? */
- if (*buf & 0x80) {
- switch ((*buf >> 4) & 7) {
- case 1:
- dp += sprintf(dp, " Shift %x\n", *buf & 0xf);
- cs_old = cset;
- cset = *buf & 7;
- cs_fest = *buf & 8;
- break;
- case 3:
- dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf);
- break;
- case 2:
- if (*buf == 0xa0) {
- dp += sprintf(dp, " More data\n");
- break;
- }
- if (*buf == 0xa1) {
- dp += sprintf(dp, " Sending complete\n");
- }
- break;
- /* fall through */
- default:
- dp += sprintf(dp, " Reserved %x\n", *buf);
- break;
- }
- buf++;
- continue;
- }
- /* No, locate it in the table */
- if (cset == 0) {
- for (i = 0; i < WE_0_LEN; i++)
- if (*buf == we_0[i].nr)
- break;
-
- /* When found, give appropriate msg */
- if (i != WE_0_LEN) {
- dp += sprintf(dp, " %s\n", we_0[i].descr);
- dp += we_0[i].f(dp, buf);
- } else
- dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
- } else if (cset == 6) {
- for (i = 0; i < WE_6_LEN; i++)
- if (*buf == we_6[i].nr)
- break;
-
- /* When found, give appropriate msg */
- if (i != WE_6_LEN) {
- dp += sprintf(dp, " %s\n", we_6[i].descr);
- dp += we_6[i].f(dp, buf);
- } else
- dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
- } else
- dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
- /* Skip to next element */
- if (cs_fest == 8) {
- cset = cs_old;
- cs_old = 0;
- cs_fest = 0;
- }
- buf += buf[1] + 2;
- }
- } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_NI1)) { /* NI-1 */
- /* locate message type */
- buf++;
- cr_l = *buf++;
- if (cr_l)
- cr = *buf++;
- else
- cr = 0;
- mt = *buf++;
- for (i = 0; i < MTSIZE; i++)
- if (mtlist[i].nr == mt)
- break;
-
- /* display message type if it exists */
- if (i == MTSIZE)
- dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n",
- cr & 0x7f, (cr & 0x80) ? "called" : "caller",
- size, mt);
- else
- dp += sprintf(dp, "callref %d %s size %d message type %s\n",
- cr & 0x7f, (cr & 0x80) ? "called" : "caller",
- size, mtlist[i].descr);
-
- /* display each information element */
- while (buf < bend) {
- /* Is it a single octet information element? */
- if (*buf & 0x80) {
- switch ((*buf >> 4) & 7) {
- case 1:
- dp += sprintf(dp, " Shift %x\n", *buf & 0xf);
- cs_old = cset;
- cset = *buf & 7;
- cs_fest = *buf & 8;
- break;
- default:
- dp += sprintf(dp, " Unknown single-octet IE %x\n", *buf);
- break;
- }
- buf++;
- continue;
- }
- /* No, locate it in the table */
- if (cset == 0) {
- for (i = 0; i < IESIZE_NI1; i++)
- if (*buf == ielist_ni1[i].nr)
- break;
-
- /* When not found, give appropriate msg */
- if (i != IESIZE_NI1) {
- dp += sprintf(dp, " %s\n", ielist_ni1[i].descr);
- dp += ielist_ni1[i].f(dp, buf);
- } else
- dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]);
- } else if (cset == 5) {
- for (i = 0; i < IESIZE_NI1_CS5; i++)
- if (*buf == ielist_ni1_cs5[i].nr)
- break;
-
- /* When not found, give appropriate msg */
- if (i != IESIZE_NI1_CS5) {
- dp += sprintf(dp, " %s\n", ielist_ni1_cs5[i].descr);
- dp += ielist_ni1_cs5[i].f(dp, buf);
- } else
- dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]);
- } else if (cset == 6) {
- for (i = 0; i < IESIZE_NI1_CS6; i++)
- if (*buf == ielist_ni1_cs6[i].nr)
- break;
-
- /* When not found, give appropriate msg */
- if (i != IESIZE_NI1_CS6) {
- dp += sprintf(dp, " %s\n", ielist_ni1_cs6[i].descr);
- dp += ielist_ni1_cs6[i].f(dp, buf);
- } else
- dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]);
- } else
- dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
-
- /* Skip to next element */
- if (cs_fest == 8) {
- cset = cs_old;
- cs_old = 0;
- cs_fest = 0;
- }
- buf += buf[1] + 2;
- }
- } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_EURO)) { /* EURO */
- /* locate message type */
- buf++;
- cr_l = *buf++;
- if (cr_l)
- cr = *buf++;
- else
- cr = 0;
- mt = *buf++;
- for (i = 0; i < MTSIZE; i++)
- if (mtlist[i].nr == mt)
- break;
-
- /* display message type if it exists */
- if (i == MTSIZE)
- dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n",
- cr & 0x7f, (cr & 0x80) ? "called" : "caller",
- size, mt);
- else
- dp += sprintf(dp, "callref %d %s size %d message type %s\n",
- cr & 0x7f, (cr & 0x80) ? "called" : "caller",
- size, mtlist[i].descr);
-
- /* display each information element */
- while (buf < bend) {
- /* Is it a single octet information element? */
- if (*buf & 0x80) {
- switch ((*buf >> 4) & 7) {
- case 1:
- dp += sprintf(dp, " Shift %x\n", *buf & 0xf);
- break;
- case 3:
- dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf);
- break;
- case 5:
- dp += sprintf(dp, " Repeat indicator %x\n", *buf & 0xf);
- break;
- case 2:
- if (*buf == 0xa0) {
- dp += sprintf(dp, " More data\n");
- break;
- }
- if (*buf == 0xa1) {
- dp += sprintf(dp, " Sending complete\n");
- }
- break;
- /* fall through */
- default:
- dp += sprintf(dp, " Reserved %x\n", *buf);
- break;
- }
- buf++;
- continue;
- }
- /* No, locate it in the table */
- for (i = 0; i < IESIZE; i++)
- if (*buf == ielist[i].nr)
- break;
-
- /* When not found, give appropriate msg */
- if (i != IESIZE) {
- dp += sprintf(dp, " %s\n", ielist[i].descr);
- dp += ielist[i].f(dp, buf);
- } else
- dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]);
-
- /* Skip to next element */
- buf += buf[1] + 2;
- }
- } else {
- dp += sprintf(dp, "Unknown protocol %x!", buf[0]);
- }
- *dp = 0;
- HiSax_putstatus(cs, NULL, cs->dlog);
-}
diff --git a/drivers/isdn/hisax/s0box.c b/drivers/isdn/hisax/s0box.c
deleted file mode 100644
index 4e7d0aa227ad..000000000000
--- a/drivers/isdn/hisax/s0box.c
+++ /dev/null
@@ -1,260 +0,0 @@
-/* $Id: s0box.c,v 2.6.2.4 2004/01/13 23:48:39 keil Exp $
- *
- * low level stuff for Creatix S0BOX
- *
- * Author Enrik Berkhan
- * Copyright by Enrik Berkhan <enrik@starfleet.inka.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/init.h>
-#include "hisax.h"
-#include "isac.h"
-#include "hscx.h"
-#include "isdnl1.h"
-
-static const char *s0box_revision = "$Revision: 2.6.2.4 $";
-
-static inline void
-writereg(unsigned int padr, signed int addr, u_char off, u_char val) {
- outb_p(0x1c, padr + 2);
- outb_p(0x14, padr + 2);
- outb_p((addr + off) & 0x7f, padr);
- outb_p(0x16, padr + 2);
- outb_p(val, padr);
- outb_p(0x17, padr + 2);
- outb_p(0x14, padr + 2);
- outb_p(0x1c, padr + 2);
-}
-
-static u_char nibtab[] = { 1, 9, 5, 0xd, 3, 0xb, 7, 0xf,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 8, 4, 0xc, 2, 0xa, 6, 0xe };
-
-static inline u_char
-readreg(unsigned int padr, signed int addr, u_char off) {
- register u_char n1, n2;
-
- outb_p(0x1c, padr + 2);
- outb_p(0x14, padr + 2);
- outb_p((addr + off) | 0x80, padr);
- outb_p(0x16, padr + 2);
- outb_p(0x17, padr + 2);
- n1 = (inb_p(padr + 1) >> 3) & 0x17;
- outb_p(0x16, padr + 2);
- n2 = (inb_p(padr + 1) >> 3) & 0x17;
- outb_p(0x14, padr + 2);
- outb_p(0x1c, padr + 2);
- return nibtab[n1] | (nibtab[n2] << 4);
-}
-
-static inline void
-read_fifo(unsigned int padr, signed int adr, u_char *data, int size)
-{
- int i;
- register u_char n1, n2;
-
- outb_p(0x1c, padr + 2);
- outb_p(0x14, padr + 2);
- outb_p(adr | 0x80, padr);
- outb_p(0x16, padr + 2);
- for (i = 0; i < size; i++) {
- outb_p(0x17, padr + 2);
- n1 = (inb_p(padr + 1) >> 3) & 0x17;
- outb_p(0x16, padr + 2);
- n2 = (inb_p(padr + 1) >> 3) & 0x17;
- *(data++) = nibtab[n1] | (nibtab[n2] << 4);
- }
- outb_p(0x14, padr + 2);
- outb_p(0x1c, padr + 2);
- return;
-}
-
-static inline void
-write_fifo(unsigned int padr, signed int adr, u_char *data, int size)
-{
- int i;
- outb_p(0x1c, padr + 2);
- outb_p(0x14, padr + 2);
- outb_p(adr & 0x7f, padr);
- for (i = 0; i < size; i++) {
- outb_p(0x16, padr + 2);
- outb_p(*(data++), padr);
- outb_p(0x17, padr + 2);
- }
- outb_p(0x14, padr + 2);
- outb_p(0x1c, padr + 2);
- return;
-}
-
-/* Interface functions */
-
-static u_char
-ReadISAC(struct IsdnCardState *cs, u_char offset)
-{
- return (readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, offset));
-}
-
-static void
-WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
-{
- writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, offset, value);
-}
-
-static void
-ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- read_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.isacfifo, data, size);
-}
-
-static void
-WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- write_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.isacfifo, data, size);
-}
-
-static u_char
-ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
-{
- return (readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[hscx], offset));
-}
-
-static void
-WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
-{
- writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[hscx], offset, value);
-}
-
-/*
- * fast interrupt HSCX stuff goes here
- */
-
-#define READHSCX(cs, nr, reg) readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[nr], reg)
-#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[nr], reg, data)
-#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscxfifo[nr], ptr, cnt)
-#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscxfifo[nr], ptr, cnt)
-
-#include "hscx_irq.c"
-
-static irqreturn_t
-s0box_interrupt(int intno, void *dev_id)
-{
-#define MAXCOUNT 5
- struct IsdnCardState *cs = dev_id;
- u_char val;
- u_long flags;
- int count = 0;
-
- spin_lock_irqsave(&cs->lock, flags);
- val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_ISTA);
-Start_HSCX:
- if (val)
- hscx_int_main(cs, val);
- val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_ISTA);
-Start_ISAC:
- if (val)
- isac_interrupt(cs, val);
- count++;
- val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_ISTA);
- if (val && count < MAXCOUNT) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "HSCX IntStat after IntRoutine");
- goto Start_HSCX;
- }
- val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_ISTA);
- if (val && count < MAXCOUNT) {
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ISAC IntStat after IntRoutine");
- goto Start_ISAC;
- }
- if (count >= MAXCOUNT)
- printk(KERN_WARNING "S0Box: more than %d loops in s0box_interrupt\n", count);
- writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[0], HSCX_MASK, 0xFF);
- writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_MASK, 0xFF);
- writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_MASK, 0xFF);
- writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_MASK, 0x0);
- writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[0], HSCX_MASK, 0x0);
- writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_MASK, 0x0);
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static void
-release_io_s0box(struct IsdnCardState *cs)
-{
- release_region(cs->hw.teles3.cfg_reg, 8);
-}
-
-static int
-S0Box_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
- u_long flags;
-
- switch (mt) {
- case CARD_RESET:
- break;
- case CARD_RELEASE:
- release_io_s0box(cs);
- break;
- case CARD_INIT:
- spin_lock_irqsave(&cs->lock, flags);
- inithscxisac(cs, 3);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case CARD_TEST:
- break;
- }
- return (0);
-}
-
-int setup_s0box(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
-
- strcpy(tmp, s0box_revision);
- printk(KERN_INFO "HiSax: S0Box IO driver Rev. %s\n", HiSax_getrev(tmp));
- if (cs->typ != ISDN_CTYPE_S0BOX)
- return (0);
-
- cs->hw.teles3.cfg_reg = card->para[1];
- cs->hw.teles3.hscx[0] = -0x20;
- cs->hw.teles3.hscx[1] = 0x0;
- cs->hw.teles3.isac = 0x20;
- cs->hw.teles3.isacfifo = cs->hw.teles3.isac + 0x3e;
- cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e;
- cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e;
- cs->irq = card->para[0];
- if (!request_region(cs->hw.teles3.cfg_reg, 8, "S0Box parallel I/O")) {
- printk(KERN_WARNING "HiSax: S0Box ports %x-%x already in use\n",
- cs->hw.teles3.cfg_reg,
- cs->hw.teles3.cfg_reg + 7);
- return 0;
- }
- printk(KERN_INFO "HiSax: S0Box config irq:%d isac:0x%x cfg:0x%x\n",
- cs->irq,
- cs->hw.teles3.isac, cs->hw.teles3.cfg_reg);
- printk(KERN_INFO "HiSax: hscx A:0x%x hscx B:0x%x\n",
- cs->hw.teles3.hscx[0], cs->hw.teles3.hscx[1]);
- setup_isac(cs);
- cs->readisac = &ReadISAC;
- cs->writeisac = &WriteISAC;
- cs->readisacfifo = &ReadISACfifo;
- cs->writeisacfifo = &WriteISACfifo;
- cs->BC_Read_Reg = &ReadHSCX;
- cs->BC_Write_Reg = &WriteHSCX;
- cs->BC_Send_Data = &hscx_fill_fifo;
- cs->cardmsg = &S0Box_card_msg;
- cs->irq_func = &s0box_interrupt;
- ISACVersion(cs, "S0Box:");
- if (HscxVersion(cs, "S0Box:")) {
- printk(KERN_WARNING
- "S0Box: wrong HSCX versions check IO address\n");
- release_io_s0box(cs);
- return (0);
- }
- return (1);
-}
diff --git a/drivers/isdn/hisax/saphir.c b/drivers/isdn/hisax/saphir.c
deleted file mode 100644
index db906cb37a3f..000000000000
--- a/drivers/isdn/hisax/saphir.c
+++ /dev/null
@@ -1,296 +0,0 @@
-/* $Id: saphir.c,v 1.10.2.4 2004/01/13 23:48:39 keil Exp $
- *
- * low level stuff for HST Saphir 1
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Thanks to HST High Soft Tech GmbH
- *
- */
-
-#include <linux/init.h>
-#include "hisax.h"
-#include "isac.h"
-#include "hscx.h"
-#include "isdnl1.h"
-
-static char *saphir_rev = "$Revision: 1.10.2.4 $";
-
-#define byteout(addr, val) outb(val, addr)
-#define bytein(addr) inb(addr)
-
-#define ISAC_DATA 0
-#define HSCX_DATA 1
-#define ADDRESS_REG 2
-#define IRQ_REG 3
-#define SPARE_REG 4
-#define RESET_REG 5
-
-static inline u_char
-readreg(unsigned int ale, unsigned int adr, u_char off)
-{
- register u_char ret;
-
- byteout(ale, off);
- ret = bytein(adr);
- return (ret);
-}
-
-static inline void
-readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
-{
- byteout(ale, off);
- insb(adr, data, size);
-}
-
-
-static inline void
-writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
-{
- byteout(ale, off);
- byteout(adr, data);
-}
-
-static inline void
-writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
-{
- byteout(ale, off);
- outsb(adr, data, size);
-}
-
-/* Interface functions */
-
-static u_char
-ReadISAC(struct IsdnCardState *cs, u_char offset)
-{
- return (readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, offset));
-}
-
-static void
-WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
-{
- writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, offset, value);
-}
-
-static void
-ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- readfifo(cs->hw.saphir.ale, cs->hw.saphir.isac, 0, data, size);
-}
-
-static void
-WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- writefifo(cs->hw.saphir.ale, cs->hw.saphir.isac, 0, data, size);
-}
-
-static u_char
-ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
-{
- return (readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx,
- offset + (hscx ? 0x40 : 0)));
-}
-
-static void
-WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
-{
- writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx,
- offset + (hscx ? 0x40 : 0), value);
-}
-
-#define READHSCX(cs, nr, reg) readreg(cs->hw.saphir.ale, \
- cs->hw.saphir.hscx, reg + (nr ? 0x40 : 0))
-#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.saphir.ale, \
- cs->hw.saphir.hscx, reg + (nr ? 0x40 : 0), data)
-
-#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.saphir.ale, \
- cs->hw.saphir.hscx, (nr ? 0x40 : 0), ptr, cnt)
-
-#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.saphir.ale, \
- cs->hw.saphir.hscx, (nr ? 0x40 : 0), ptr, cnt)
-
-#include "hscx_irq.c"
-
-static irqreturn_t
-saphir_interrupt(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_char val;
- u_long flags;
-
- spin_lock_irqsave(&cs->lock, flags);
- val = readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_ISTA + 0x40);
-Start_HSCX:
- if (val)
- hscx_int_main(cs, val);
- val = readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_ISTA);
-Start_ISAC:
- if (val)
- isac_interrupt(cs, val);
- val = readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_ISTA + 0x40);
- if (val) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "HSCX IntStat after IntRoutine");
- goto Start_HSCX;
- }
- val = readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_ISTA);
- if (val) {
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ISAC IntStat after IntRoutine");
- goto Start_ISAC;
- }
- /* Watchdog */
- if (cs->hw.saphir.timer.function)
- mod_timer(&cs->hw.saphir.timer, jiffies + 1 * HZ);
- else
- printk(KERN_WARNING "saphir: Spurious timer!\n");
- writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK, 0xFF);
- writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK + 0x40, 0xFF);
- writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_MASK, 0xFF);
- writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_MASK, 0);
- writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK, 0);
- writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK + 0x40, 0);
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static void
-SaphirWatchDog(struct timer_list *t)
-{
- struct IsdnCardState *cs = from_timer(cs, t, hw.saphir.timer);
- u_long flags;
-
- spin_lock_irqsave(&cs->lock, flags);
- /* 5 sec WatchDog, so read at least every 4 sec */
- cs->readisac(cs, ISAC_RBCH);
- spin_unlock_irqrestore(&cs->lock, flags);
- mod_timer(&cs->hw.saphir.timer, jiffies + 1 * HZ);
-}
-
-static void
-release_io_saphir(struct IsdnCardState *cs)
-{
- byteout(cs->hw.saphir.cfg_reg + IRQ_REG, 0xff);
- del_timer(&cs->hw.saphir.timer);
- cs->hw.saphir.timer.function = NULL;
- if (cs->hw.saphir.cfg_reg)
- release_region(cs->hw.saphir.cfg_reg, 6);
-}
-
-static int
-saphir_reset(struct IsdnCardState *cs)
-{
- u_char irq_val;
-
- switch (cs->irq) {
- case 5: irq_val = 0;
- break;
- case 3: irq_val = 1;
- break;
- case 11:
- irq_val = 2;
- break;
- case 12:
- irq_val = 3;
- break;
- case 15:
- irq_val = 4;
- break;
- default:
- printk(KERN_WARNING "HiSax: saphir wrong IRQ %d\n",
- cs->irq);
- return (1);
- }
- byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val);
- byteout(cs->hw.saphir.cfg_reg + RESET_REG, 1);
- mdelay(10);
- byteout(cs->hw.saphir.cfg_reg + RESET_REG, 0);
- mdelay(10);
- byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val);
- byteout(cs->hw.saphir.cfg_reg + SPARE_REG, 0x02);
- return (0);
-}
-
-static int
-saphir_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
- u_long flags;
-
- switch (mt) {
- case CARD_RESET:
- spin_lock_irqsave(&cs->lock, flags);
- saphir_reset(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_RELEASE:
- release_io_saphir(cs);
- return (0);
- case CARD_INIT:
- spin_lock_irqsave(&cs->lock, flags);
- inithscxisac(cs, 3);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_TEST:
- return (0);
- }
- return (0);
-}
-
-
-int setup_saphir(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
-
- strcpy(tmp, saphir_rev);
- printk(KERN_INFO "HiSax: HST Saphir driver Rev. %s\n", HiSax_getrev(tmp));
- if (cs->typ != ISDN_CTYPE_HSTSAPHIR)
- return (0);
-
- /* IO-Ports */
- cs->hw.saphir.cfg_reg = card->para[1];
- cs->hw.saphir.isac = card->para[1] + ISAC_DATA;
- cs->hw.saphir.hscx = card->para[1] + HSCX_DATA;
- cs->hw.saphir.ale = card->para[1] + ADDRESS_REG;
- cs->irq = card->para[0];
- if (!request_region(cs->hw.saphir.cfg_reg, 6, "saphir")) {
- printk(KERN_WARNING
- "HiSax: HST Saphir config port %x-%x already in use\n",
- cs->hw.saphir.cfg_reg,
- cs->hw.saphir.cfg_reg + 5);
- return (0);
- }
-
- printk(KERN_INFO "HiSax: HST Saphir config irq:%d io:0x%X\n",
- cs->irq, cs->hw.saphir.cfg_reg);
-
- setup_isac(cs);
- timer_setup(&cs->hw.saphir.timer, SaphirWatchDog, 0);
- cs->hw.saphir.timer.expires = jiffies + 4 * HZ;
- add_timer(&cs->hw.saphir.timer);
- if (saphir_reset(cs)) {
- release_io_saphir(cs);
- return (0);
- }
- cs->readisac = &ReadISAC;
- cs->writeisac = &WriteISAC;
- cs->readisacfifo = &ReadISACfifo;
- cs->writeisacfifo = &WriteISACfifo;
- cs->BC_Read_Reg = &ReadHSCX;
- cs->BC_Write_Reg = &WriteHSCX;
- cs->BC_Send_Data = &hscx_fill_fifo;
- cs->cardmsg = &saphir_card_msg;
- cs->irq_func = &saphir_interrupt;
- ISACVersion(cs, "saphir:");
- if (HscxVersion(cs, "saphir:")) {
- printk(KERN_WARNING
- "saphir: wrong HSCX versions check IO address\n");
- release_io_saphir(cs);
- return (0);
- }
- return (1);
-}
diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c
deleted file mode 100644
index c0b97b893495..000000000000
--- a/drivers/isdn/hisax/sedlbauer.c
+++ /dev/null
@@ -1,873 +0,0 @@
-/* $Id: sedlbauer.c,v 1.34.2.6 2004/01/24 20:47:24 keil Exp $
- *
- * low level stuff for Sedlbauer cards
- * includes support for the Sedlbauer speed star (speed star II),
- * support for the Sedlbauer speed fax+,
- * support for the Sedlbauer ISDN-Controller PC/104 and
- * support for the Sedlbauer speed pci
- * derived from the original file asuscom.c from Karsten Keil
- *
- * Author Marcus Niemann
- * Copyright by Marcus Niemann <niemann@www-bib.fh-bielefeld.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Thanks to Karsten Keil
- * Sedlbauer AG for informations
- * Edgar Toernig
- *
- */
-
-/* Supported cards:
- * Card: Chip: Configuration: Comment:
- * ---------------------------------------------------------------------
- * Speed Card ISAC_HSCX DIP-SWITCH
- * Speed Win ISAC_HSCX ISAPNP
- * Speed Fax+ ISAC_ISAR ISAPNP Full analog support
- * Speed Star ISAC_HSCX CARDMGR
- * Speed Win2 IPAC ISAPNP
- * ISDN PC/104 IPAC DIP-SWITCH
- * Speed Star2 IPAC CARDMGR
- * Speed PCI IPAC PCI PNP
- * Speed Fax+ ISAC_ISAR PCI PNP Full analog support
- *
- * Important:
- * For the sedlbauer speed fax+ to work properly you have to download
- * the firmware onto the card.
- * For example: hisaxctrl <DriverID> 9 ISAR.BIN
- */
-
-#include <linux/init.h>
-#include "hisax.h"
-#include "isac.h"
-#include "ipac.h"
-#include "hscx.h"
-#include "isar.h"
-#include "isdnl1.h"
-#include <linux/pci.h>
-#include <linux/isapnp.h>
-
-static const char *Sedlbauer_revision = "$Revision: 1.34.2.6 $";
-
-static const char *Sedlbauer_Types[] =
-{"None", "speed card/win", "speed star", "speed fax+",
- "speed win II / ISDN PC/104", "speed star II", "speed pci",
- "speed fax+ pyramid", "speed fax+ pci", "HST Saphir III"};
-
-#define PCI_SUBVENDOR_SPEEDFAX_PYRAMID 0x51
-#define PCI_SUBVENDOR_HST_SAPHIR3 0x52
-#define PCI_SUBVENDOR_SEDLBAUER_PCI 0x53
-#define PCI_SUBVENDOR_SPEEDFAX_PCI 0x54
-#define PCI_SUB_ID_SEDLBAUER 0x01
-
-#define SEDL_SPEED_CARD_WIN 1
-#define SEDL_SPEED_STAR 2
-#define SEDL_SPEED_FAX 3
-#define SEDL_SPEED_WIN2_PC104 4
-#define SEDL_SPEED_STAR2 5
-#define SEDL_SPEED_PCI 6
-#define SEDL_SPEEDFAX_PYRAMID 7
-#define SEDL_SPEEDFAX_PCI 8
-#define HST_SAPHIR3 9
-
-#define SEDL_CHIP_TEST 0
-#define SEDL_CHIP_ISAC_HSCX 1
-#define SEDL_CHIP_ISAC_ISAR 2
-#define SEDL_CHIP_IPAC 3
-
-#define SEDL_BUS_ISA 1
-#define SEDL_BUS_PCI 2
-#define SEDL_BUS_PCMCIA 3
-
-#define byteout(addr, val) outb(val, addr)
-#define bytein(addr) inb(addr)
-
-#define SEDL_HSCX_ISA_RESET_ON 0
-#define SEDL_HSCX_ISA_RESET_OFF 1
-#define SEDL_HSCX_ISA_ISAC 2
-#define SEDL_HSCX_ISA_HSCX 3
-#define SEDL_HSCX_ISA_ADR 4
-
-#define SEDL_HSCX_PCMCIA_RESET 0
-#define SEDL_HSCX_PCMCIA_ISAC 1
-#define SEDL_HSCX_PCMCIA_HSCX 2
-#define SEDL_HSCX_PCMCIA_ADR 4
-
-#define SEDL_ISAR_ISA_ISAC 4
-#define SEDL_ISAR_ISA_ISAR 6
-#define SEDL_ISAR_ISA_ADR 8
-#define SEDL_ISAR_ISA_ISAR_RESET_ON 10
-#define SEDL_ISAR_ISA_ISAR_RESET_OFF 12
-
-#define SEDL_IPAC_ANY_ADR 0
-#define SEDL_IPAC_ANY_IPAC 2
-
-#define SEDL_IPAC_PCI_BASE 0
-#define SEDL_IPAC_PCI_ADR 0xc0
-#define SEDL_IPAC_PCI_IPAC 0xc8
-#define SEDL_ISAR_PCI_ADR 0xc8
-#define SEDL_ISAR_PCI_ISAC 0xd0
-#define SEDL_ISAR_PCI_ISAR 0xe0
-#define SEDL_ISAR_PCI_ISAR_RESET_ON 0x01
-#define SEDL_ISAR_PCI_ISAR_RESET_OFF 0x18
-#define SEDL_ISAR_PCI_LED1 0x08
-#define SEDL_ISAR_PCI_LED2 0x10
-
-#define SEDL_RESET 0x3 /* same as DOS driver */
-
-static inline u_char
-readreg(unsigned int ale, unsigned int adr, u_char off)
-{
- register u_char ret;
-
- byteout(ale, off);
- ret = bytein(adr);
- return (ret);
-}
-
-static inline void
-readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
-{
- byteout(ale, off);
- insb(adr, data, size);
-}
-
-
-static inline void
-writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
-{
- byteout(ale, off);
- byteout(adr, data);
-}
-
-static inline void
-writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
-{
- byteout(ale, off);
- outsb(adr, data, size);
-}
-
-/* Interface functions */
-
-static u_char
-ReadISAC(struct IsdnCardState *cs, u_char offset)
-{
- return (readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset));
-}
-
-static void
-WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
-{
- writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset, value);
-}
-
-static void
-ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- readfifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0, data, size);
-}
-
-static void
-WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- writefifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0, data, size);
-}
-
-static u_char
-ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset)
-{
- return (readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset | 0x80));
-}
-
-static void
-WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value)
-{
- writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset | 0x80, value);
-}
-
-static void
-ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size)
-{
- readfifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size);
-}
-
-static void
-WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size)
-{
- writefifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size);
-}
-
-static u_char
-ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
-{
- return (readreg(cs->hw.sedl.adr,
- cs->hw.sedl.hscx, offset + (hscx ? 0x40 : 0)));
-}
-
-static void
-WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
-{
- writereg(cs->hw.sedl.adr,
- cs->hw.sedl.hscx, offset + (hscx ? 0x40 : 0), value);
-}
-
-/* ISAR access routines
- * mode = 0 access with IRQ on
- * mode = 1 access with IRQ off
- * mode = 2 access with IRQ off and using last offset
- */
-
-static u_char
-ReadISAR(struct IsdnCardState *cs, int mode, u_char offset)
-{
- if (mode == 0)
- return (readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, offset));
- else if (mode == 1)
- byteout(cs->hw.sedl.adr, offset);
- return (bytein(cs->hw.sedl.hscx));
-}
-
-static void
-WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value)
-{
- if (mode == 0)
- writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, offset, value);
- else {
- if (mode == 1)
- byteout(cs->hw.sedl.adr, offset);
- byteout(cs->hw.sedl.hscx, value);
- }
-}
-
-/*
- * fast interrupt HSCX stuff goes here
- */
-
-#define READHSCX(cs, nr, reg) readreg(cs->hw.sedl.adr, \
- cs->hw.sedl.hscx, reg + (nr ? 0x40 : 0))
-#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.sedl.adr, \
- cs->hw.sedl.hscx, reg + (nr ? 0x40 : 0), data)
-
-#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.sedl.adr, \
- cs->hw.sedl.hscx, (nr ? 0x40 : 0), ptr, cnt)
-
-#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.sedl.adr, \
- cs->hw.sedl.hscx, (nr ? 0x40 : 0), ptr, cnt)
-
-#include "hscx_irq.c"
-
-static irqreturn_t
-sedlbauer_interrupt(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_char val;
- u_long flags;
-
- spin_lock_irqsave(&cs->lock, flags);
- if ((cs->hw.sedl.bus == SEDL_BUS_PCMCIA) && (*cs->busy_flag == 1)) {
- /* The card tends to generate interrupts while being removed
- causing us to just crash the kernel. bad. */
- spin_unlock_irqrestore(&cs->lock, flags);
- printk(KERN_WARNING "Sedlbauer: card not available!\n");
- return IRQ_NONE;
- }
-
- val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40);
-Start_HSCX:
- if (val)
- hscx_int_main(cs, val);
- val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA);
-Start_ISAC:
- if (val)
- isac_interrupt(cs, val);
- val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40);
- if (val) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "HSCX IntStat after IntRoutine");
- goto Start_HSCX;
- }
- val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA);
- if (val) {
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ISAC IntStat after IntRoutine");
- goto Start_ISAC;
- }
- writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK, 0xFF);
- writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK + 0x40, 0xFF);
- writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0xFF);
- writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0x0);
- writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK, 0x0);
- writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK + 0x40, 0x0);
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static irqreturn_t
-sedlbauer_interrupt_ipac(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_char ista, val, icnt = 5;
- u_long flags;
-
- spin_lock_irqsave(&cs->lock, flags);
- ista = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ISTA);
-Start_IPAC:
- if (cs->debug & L1_DEB_IPAC)
- debugl1(cs, "IPAC ISTA %02X", ista);
- if (ista & 0x0f) {
- val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40);
- if (ista & 0x01)
- val |= 0x01;
- if (ista & 0x04)
- val |= 0x02;
- if (ista & 0x08)
- val |= 0x04;
- if (val)
- hscx_int_main(cs, val);
- }
- if (ista & 0x20) {
- val = 0xfe & readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA | 0x80);
- if (val) {
- isac_interrupt(cs, val);
- }
- }
- if (ista & 0x10) {
- val = 0x01;
- isac_interrupt(cs, val);
- }
- ista = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ISTA);
- if ((ista & 0x3f) && icnt) {
- icnt--;
- goto Start_IPAC;
- }
- if (!icnt)
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "Sedlbauer IRQ LOOP");
- writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xFF);
- writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xC0);
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static irqreturn_t
-sedlbauer_interrupt_isar(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_char val;
- int cnt = 5;
- u_long flags;
-
- spin_lock_irqsave(&cs->lock, flags);
- val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT);
-Start_ISAR:
- if (val & ISAR_IRQSTA)
- isar_int_main(cs);
- val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA);
-Start_ISAC:
- if (val)
- isac_interrupt(cs, val);
- val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT);
- if ((val & ISAR_IRQSTA) && --cnt) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "ISAR IntStat after IntRoutine");
- goto Start_ISAR;
- }
- val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA);
- if (val && --cnt) {
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ISAC IntStat after IntRoutine");
- goto Start_ISAC;
- }
- if (!cnt)
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "Sedlbauer IRQ LOOP");
-
- writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT, 0);
- writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0xFF);
- writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0x0);
- writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT, ISAR_IRQMSK);
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static void
-release_io_sedlbauer(struct IsdnCardState *cs)
-{
- int bytecnt = 8;
-
- if (cs->subtyp == SEDL_SPEED_FAX) {
- bytecnt = 16;
- } else if (cs->hw.sedl.bus == SEDL_BUS_PCI) {
- bytecnt = 256;
- }
- if (cs->hw.sedl.cfg_reg)
- release_region(cs->hw.sedl.cfg_reg, bytecnt);
-}
-
-static void
-reset_sedlbauer(struct IsdnCardState *cs)
-{
- printk(KERN_INFO "Sedlbauer: resetting card\n");
-
- if (!((cs->hw.sedl.bus == SEDL_BUS_PCMCIA) &&
- (cs->hw.sedl.chip == SEDL_CHIP_ISAC_HSCX))) {
- if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) {
- writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x20);
- mdelay(2);
- writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x0);
- mdelay(10);
- writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_CONF, 0x0);
- writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ACFG, 0xff);
- writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_AOE, 0x0);
- writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xc0);
- writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_PCFG, 0x12);
- } else if ((cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) &&
- (cs->hw.sedl.bus == SEDL_BUS_PCI)) {
- byteout(cs->hw.sedl.cfg_reg + 3, cs->hw.sedl.reset_on);
- mdelay(2);
- byteout(cs->hw.sedl.cfg_reg + 3, cs->hw.sedl.reset_off);
- mdelay(10);
- } else {
- byteout(cs->hw.sedl.reset_on, SEDL_RESET); /* Reset On */
- mdelay(2);
- byteout(cs->hw.sedl.reset_off, 0); /* Reset Off */
- mdelay(10);
- }
- }
-}
-
-static int
-Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
- u_long flags;
-
- switch (mt) {
- case CARD_RESET:
- spin_lock_irqsave(&cs->lock, flags);
- reset_sedlbauer(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_RELEASE:
- if (cs->hw.sedl.bus == SEDL_BUS_PCI)
- /* disable all IRQ */
- byteout(cs->hw.sedl.cfg_reg + 5, 0);
- if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) {
- spin_lock_irqsave(&cs->lock, flags);
- writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx,
- ISAR_IRQBIT, 0);
- writereg(cs->hw.sedl.adr, cs->hw.sedl.isac,
- ISAC_MASK, 0xFF);
- reset_sedlbauer(cs);
- writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx,
- ISAR_IRQBIT, 0);
- writereg(cs->hw.sedl.adr, cs->hw.sedl.isac,
- ISAC_MASK, 0xFF);
- spin_unlock_irqrestore(&cs->lock, flags);
- }
- release_io_sedlbauer(cs);
- return (0);
- case CARD_INIT:
- spin_lock_irqsave(&cs->lock, flags);
- if (cs->hw.sedl.bus == SEDL_BUS_PCI)
- /* enable all IRQ */
- byteout(cs->hw.sedl.cfg_reg + 5, 0x02);
- reset_sedlbauer(cs);
- if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) {
- clear_pending_isac_ints(cs);
- writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx,
- ISAR_IRQBIT, 0);
- initisac(cs);
- initisar(cs);
- /* Reenable all IRQ */
- cs->writeisac(cs, ISAC_MASK, 0);
- /* RESET Receiver and Transmitter */
- cs->writeisac(cs, ISAC_CMDR, 0x41);
- } else {
- inithscxisac(cs, 3);
- }
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_TEST:
- return (0);
- case MDL_INFO_CONN:
- if (cs->subtyp != SEDL_SPEEDFAX_PYRAMID)
- return (0);
- spin_lock_irqsave(&cs->lock, flags);
- if ((long) arg)
- cs->hw.sedl.reset_off &= ~SEDL_ISAR_PCI_LED2;
- else
- cs->hw.sedl.reset_off &= ~SEDL_ISAR_PCI_LED1;
- byteout(cs->hw.sedl.cfg_reg + 3, cs->hw.sedl.reset_off);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case MDL_INFO_REL:
- if (cs->subtyp != SEDL_SPEEDFAX_PYRAMID)
- return (0);
- spin_lock_irqsave(&cs->lock, flags);
- if ((long) arg)
- cs->hw.sedl.reset_off |= SEDL_ISAR_PCI_LED2;
- else
- cs->hw.sedl.reset_off |= SEDL_ISAR_PCI_LED1;
- byteout(cs->hw.sedl.cfg_reg + 3, cs->hw.sedl.reset_off);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- }
- return (0);
-}
-
-#ifdef __ISAPNP__
-static struct isapnp_device_id sedl_ids[] = {
- { ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01),
- ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01),
- (unsigned long) "Speed win" },
- { ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x02),
- ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x02),
- (unsigned long) "Speed Fax+" },
- { 0, }
-};
-
-static struct isapnp_device_id *ipid = &sedl_ids[0];
-static struct pnp_card *pnp_c = NULL;
-
-static int setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt)
-{
- struct IsdnCardState *cs = card->cs;
- struct pnp_dev *pnp_d;
-
- if (!isapnp_present())
- return -1;
-
- while (ipid->card_vendor) {
- if ((pnp_c = pnp_find_card(ipid->card_vendor,
- ipid->card_device, pnp_c))) {
- pnp_d = NULL;
- if ((pnp_d = pnp_find_dev(pnp_c,
- ipid->vendor, ipid->function, pnp_d))) {
- int err;
-
- printk(KERN_INFO "HiSax: %s detected\n",
- (char *)ipid->driver_data);
- pnp_disable_dev(pnp_d);
- err = pnp_activate_dev(pnp_d);
- if (err < 0) {
- printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __func__, err);
- return (0);
- }
- card->para[1] = pnp_port_start(pnp_d, 0);
- card->para[0] = pnp_irq(pnp_d, 0);
-
- if (card->para[0] == -1 || !card->para[1]) {
- printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n",
- card->para[0], card->para[1]);
- pnp_disable_dev(pnp_d);
- return (0);
- }
- cs->hw.sedl.cfg_reg = card->para[1];
- cs->irq = card->para[0];
- if (ipid->function == ISAPNP_FUNCTION(0x2)) {
- cs->subtyp = SEDL_SPEED_FAX;
- cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
- *bytecnt = 16;
- } else {
- cs->subtyp = SEDL_SPEED_CARD_WIN;
- cs->hw.sedl.chip = SEDL_CHIP_TEST;
- }
-
- return (1);
- } else {
- printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n");
- return (0);
- }
- }
- ipid++;
- pnp_c = NULL;
- }
-
- printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n");
- return -1;
-}
-#else
-
-static int setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt)
-{
- return -1;
-}
-#endif /* __ISAPNP__ */
-
-#ifdef CONFIG_PCI
-static struct pci_dev *dev_sedl = NULL;
-
-static int setup_sedlbauer_pci(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
- u16 sub_vendor_id, sub_id;
-
- if ((dev_sedl = hisax_find_pci_device(PCI_VENDOR_ID_TIGERJET,
- PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) {
- if (pci_enable_device(dev_sedl))
- return (0);
- cs->irq = dev_sedl->irq;
- if (!cs->irq) {
- printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n");
- return (0);
- }
- cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0);
- } else {
- printk(KERN_WARNING "Sedlbauer: No PCI card found\n");
- return (0);
- }
- cs->irq_flags |= IRQF_SHARED;
- cs->hw.sedl.bus = SEDL_BUS_PCI;
- sub_vendor_id = dev_sedl->subsystem_vendor;
- sub_id = dev_sedl->subsystem_device;
- printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n",
- sub_vendor_id, sub_id);
- printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n",
- cs->hw.sedl.cfg_reg);
- if (sub_id != PCI_SUB_ID_SEDLBAUER) {
- printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id);
- return (0);
- }
- if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) {
- cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
- cs->subtyp = SEDL_SPEEDFAX_PYRAMID;
- } else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) {
- cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
- cs->subtyp = SEDL_SPEEDFAX_PCI;
- } else if (sub_vendor_id == PCI_SUBVENDOR_HST_SAPHIR3) {
- cs->hw.sedl.chip = SEDL_CHIP_IPAC;
- cs->subtyp = HST_SAPHIR3;
- } else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) {
- cs->hw.sedl.chip = SEDL_CHIP_IPAC;
- cs->subtyp = SEDL_SPEED_PCI;
- } else {
- printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n",
- sub_vendor_id);
- return (0);
- }
-
- cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON;
- cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF;
- byteout(cs->hw.sedl.cfg_reg, 0xff);
- byteout(cs->hw.sedl.cfg_reg, 0x00);
- byteout(cs->hw.sedl.cfg_reg + 2, 0xdd);
- byteout(cs->hw.sedl.cfg_reg + 5, 0); /* disable all IRQ */
- byteout(cs->hw.sedl.cfg_reg + 3, cs->hw.sedl.reset_on);
- mdelay(2);
- byteout(cs->hw.sedl.cfg_reg + 3, cs->hw.sedl.reset_off);
- mdelay(10);
-
- return (1);
-}
-
-#else
-
-static int setup_sedlbauer_pci(struct IsdnCard *card)
-{
- return (1);
-}
-
-#endif /* CONFIG_PCI */
-
-int setup_sedlbauer(struct IsdnCard *card)
-{
- int bytecnt = 8, ver, val, rc;
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
-
- strcpy(tmp, Sedlbauer_revision);
- printk(KERN_INFO "HiSax: Sedlbauer driver Rev. %s\n", HiSax_getrev(tmp));
-
- if (cs->typ == ISDN_CTYPE_SEDLBAUER) {
- cs->subtyp = SEDL_SPEED_CARD_WIN;
- cs->hw.sedl.bus = SEDL_BUS_ISA;
- cs->hw.sedl.chip = SEDL_CHIP_TEST;
- } else if (cs->typ == ISDN_CTYPE_SEDLBAUER_PCMCIA) {
- cs->subtyp = SEDL_SPEED_STAR;
- cs->hw.sedl.bus = SEDL_BUS_PCMCIA;
- cs->hw.sedl.chip = SEDL_CHIP_TEST;
- } else if (cs->typ == ISDN_CTYPE_SEDLBAUER_FAX) {
- cs->subtyp = SEDL_SPEED_FAX;
- cs->hw.sedl.bus = SEDL_BUS_ISA;
- cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
- } else
- return (0);
-
- bytecnt = 8;
- if (card->para[1]) {
- cs->hw.sedl.cfg_reg = card->para[1];
- cs->irq = card->para[0];
- if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) {
- bytecnt = 16;
- }
- } else {
- rc = setup_sedlbauer_isapnp(card, &bytecnt);
- if (!rc)
- return (0);
- if (rc > 0)
- goto ready;
-
- /* Probe for Sedlbauer speed pci */
- rc = setup_sedlbauer_pci(card);
- if (!rc)
- return (0);
-
- bytecnt = 256;
- }
-
-ready:
-
- /* In case of the sedlbauer pcmcia card, this region is in use,
- * reserved for us by the card manager. So we do not check it
- * here, it would fail.
- */
- if (cs->hw.sedl.bus != SEDL_BUS_PCMCIA &&
- !request_region(cs->hw.sedl.cfg_reg, bytecnt, "sedlbauer isdn")) {
- printk(KERN_WARNING
- "HiSax: %s config port %x-%x already in use\n",
- CardType[card->typ],
- cs->hw.sedl.cfg_reg,
- cs->hw.sedl.cfg_reg + bytecnt);
- return (0);
- }
-
- printk(KERN_INFO
- "Sedlbauer: defined at 0x%x-0x%x IRQ %d\n",
- cs->hw.sedl.cfg_reg,
- cs->hw.sedl.cfg_reg + bytecnt,
- cs->irq);
-
- cs->BC_Read_Reg = &ReadHSCX;
- cs->BC_Write_Reg = &WriteHSCX;
- cs->BC_Send_Data = &hscx_fill_fifo;
- cs->cardmsg = &Sedl_card_msg;
-
-/*
- * testing ISA and PCMCIA Cards for IPAC, default is ISAC
- * do not test for PCI card, because ports are different
- * and PCI card uses only IPAC (for the moment)
- */
- if (cs->hw.sedl.bus != SEDL_BUS_PCI) {
- val = readreg(cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_ADR,
- cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC, IPAC_ID);
- printk(KERN_DEBUG "Sedlbauer: testing IPAC version %x\n", val);
- if ((val == 1) || (val == 2)) {
- /* IPAC */
- cs->subtyp = SEDL_SPEED_WIN2_PC104;
- if (cs->hw.sedl.bus == SEDL_BUS_PCMCIA) {
- cs->subtyp = SEDL_SPEED_STAR2;
- }
- cs->hw.sedl.chip = SEDL_CHIP_IPAC;
- } else {
- /* ISAC_HSCX oder ISAC_ISAR */
- if (cs->hw.sedl.chip == SEDL_CHIP_TEST) {
- cs->hw.sedl.chip = SEDL_CHIP_ISAC_HSCX;
- }
- }
- }
-
-/*
- * hw.sedl.chip is now properly set
- */
- printk(KERN_INFO "Sedlbauer: %s detected\n",
- Sedlbauer_Types[cs->subtyp]);
-
- setup_isac(cs);
- if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) {
- if (cs->hw.sedl.bus == SEDL_BUS_PCI) {
- cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_ADR;
- cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC;
- cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC;
- } else {
- cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_ADR;
- cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC;
- cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC;
- }
- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
- cs->readisac = &ReadISAC_IPAC;
- cs->writeisac = &WriteISAC_IPAC;
- cs->readisacfifo = &ReadISACfifo_IPAC;
- cs->writeisacfifo = &WriteISACfifo_IPAC;
- cs->irq_func = &sedlbauer_interrupt_ipac;
- val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ID);
- printk(KERN_INFO "Sedlbauer: IPAC version %x\n", val);
- } else {
- /* ISAC_HSCX oder ISAC_ISAR */
- cs->readisac = &ReadISAC;
- cs->writeisac = &WriteISAC;
- cs->readisacfifo = &ReadISACfifo;
- cs->writeisacfifo = &WriteISACfifo;
- if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) {
- if (cs->hw.sedl.bus == SEDL_BUS_PCI) {
- cs->hw.sedl.adr = cs->hw.sedl.cfg_reg +
- SEDL_ISAR_PCI_ADR;
- cs->hw.sedl.isac = cs->hw.sedl.cfg_reg +
- SEDL_ISAR_PCI_ISAC;
- cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg +
- SEDL_ISAR_PCI_ISAR;
- } else {
- cs->hw.sedl.adr = cs->hw.sedl.cfg_reg +
- SEDL_ISAR_ISA_ADR;
- cs->hw.sedl.isac = cs->hw.sedl.cfg_reg +
- SEDL_ISAR_ISA_ISAC;
- cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg +
- SEDL_ISAR_ISA_ISAR;
- cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg +
- SEDL_ISAR_ISA_ISAR_RESET_ON;
- cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg +
- SEDL_ISAR_ISA_ISAR_RESET_OFF;
- }
- cs->bcs[0].hw.isar.reg = &cs->hw.sedl.isar;
- cs->bcs[1].hw.isar.reg = &cs->hw.sedl.isar;
- test_and_set_bit(HW_ISAR, &cs->HW_Flags);
- cs->irq_func = &sedlbauer_interrupt_isar;
- cs->auxcmd = &isar_auxcmd;
- ISACVersion(cs, "Sedlbauer:");
- cs->BC_Read_Reg = &ReadISAR;
- cs->BC_Write_Reg = &WriteISAR;
- cs->BC_Send_Data = &isar_fill_fifo;
- bytecnt = 3;
- while (bytecnt) {
- ver = ISARVersion(cs, "Sedlbauer:");
- if (ver < 0)
- printk(KERN_WARNING
- "Sedlbauer: wrong ISAR version (ret = %d)\n", ver);
- else
- break;
- reset_sedlbauer(cs);
- bytecnt--;
- }
- if (!bytecnt) {
- release_io_sedlbauer(cs);
- return (0);
- }
- } else {
- if (cs->hw.sedl.bus == SEDL_BUS_PCMCIA) {
- cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_ADR;
- cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_ISAC;
- cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_HSCX;
- cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_RESET;
- cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_RESET;
- cs->irq_flags |= IRQF_SHARED;
- } else {
- cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_ADR;
- cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_ISAC;
- cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_HSCX;
- cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_RESET_ON;
- cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_RESET_OFF;
- }
- cs->irq_func = &sedlbauer_interrupt;
- ISACVersion(cs, "Sedlbauer:");
-
- if (HscxVersion(cs, "Sedlbauer:")) {
- printk(KERN_WARNING
- "Sedlbauer: wrong HSCX versions check IO address\n");
- release_io_sedlbauer(cs);
- return (0);
- }
- }
- }
- return (1);
-}
diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c
deleted file mode 100644
index 92ef62d4caf4..000000000000
--- a/drivers/isdn/hisax/sedlbauer_cs.c
+++ /dev/null
@@ -1,209 +0,0 @@
-/*======================================================================
-
- A Sedlbauer PCMCIA client driver
-
- This driver is for the Sedlbauer Speed Star and Speed Star II,
- which are ISDN PCMCIA Cards.
-
- The contents of this file are subject to the Mozilla Public
- License Version 1.1 (the "License"); you may not use this file
- except in compliance with the License. You may obtain a copy of
- the License at http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS
- IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- implied. See the License for the specific language governing
- rights and limitations under the License.
-
- The initial developer of the original code is David A. Hinds
- <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
- are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
-
- Modifications from dummy_cs.c are Copyright (C) 1999-2001 Marcus Niemann
- <maniemann@users.sourceforge.net>. All Rights Reserved.
-
- Alternatively, the contents of this file may be used under the
- terms of the GNU General Public License version 2 (the "GPL"), in
- which case the provisions of the GPL are applicable instead of the
- above. If you wish to allow the use of your version of this file
- only under the terms of the GPL and not to allow others to use
- your version of this file under the MPL, indicate your decision
- by deleting the provisions above and replace them with the notice
- and other provisions required by the GPL. If you do not delete
- the provisions above, a recipient may use your version of this
- file under either the MPL or the GPL.
-
- ======================================================================*/
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/ioport.h>
-#include <asm/io.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ds.h>
-#include "hisax_cfg.h"
-
-MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Sedlbauer cards");
-MODULE_AUTHOR("Marcus Niemann");
-MODULE_LICENSE("Dual MPL/GPL");
-
-
-/*====================================================================*/
-
-/* Parameters that can be set with 'insmod' */
-
-static int protocol = 2; /* EURO-ISDN Default */
-module_param(protocol, int, 0);
-
-static int sedlbauer_config(struct pcmcia_device *link);
-static void sedlbauer_release(struct pcmcia_device *link);
-
-static void sedlbauer_detach(struct pcmcia_device *p_dev);
-
-typedef struct local_info_t {
- struct pcmcia_device *p_dev;
- int stop;
- int cardnr;
-} local_info_t;
-
-static int sedlbauer_probe(struct pcmcia_device *link)
-{
- local_info_t *local;
-
- dev_dbg(&link->dev, "sedlbauer_attach()\n");
-
- /* Allocate space for private device-specific data */
- local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
- if (!local) return -ENOMEM;
- local->cardnr = -1;
-
- local->p_dev = link;
- link->priv = local;
-
- return sedlbauer_config(link);
-} /* sedlbauer_attach */
-
-static void sedlbauer_detach(struct pcmcia_device *link)
-{
- dev_dbg(&link->dev, "sedlbauer_detach(0x%p)\n", link);
-
- ((local_info_t *)link->priv)->stop = 1;
- sedlbauer_release(link);
-
- /* This points to the parent local_info_t struct */
- kfree(link->priv);
-} /* sedlbauer_detach */
-
-static int sedlbauer_config_check(struct pcmcia_device *p_dev, void *priv_data)
-{
- if (p_dev->config_index == 0)
- return -EINVAL;
-
- p_dev->io_lines = 3;
- return pcmcia_request_io(p_dev);
-}
-
-static int sedlbauer_config(struct pcmcia_device *link)
-{
- int ret;
- IsdnCard_t icard;
-
- dev_dbg(&link->dev, "sedlbauer_config(0x%p)\n", link);
-
- link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_CHECK_VCC |
- CONF_AUTO_SET_VPP | CONF_AUTO_AUDIO | CONF_AUTO_SET_IO;
-
- ret = pcmcia_loop_config(link, sedlbauer_config_check, NULL);
- if (ret)
- goto failed;
-
- ret = pcmcia_enable_device(link);
- if (ret)
- goto failed;
-
- icard.para[0] = link->irq;
- icard.para[1] = link->resource[0]->start;
- icard.protocol = protocol;
- icard.typ = ISDN_CTYPE_SEDLBAUER_PCMCIA;
-
- ret = hisax_init_pcmcia(link,
- &(((local_info_t *)link->priv)->stop), &icard);
- if (ret < 0) {
- printk(KERN_ERR "sedlbauer_cs: failed to initialize SEDLBAUER PCMCIA %d with %pR\n",
- ret, link->resource[0]);
- sedlbauer_release(link);
- return -ENODEV;
- } else
- ((local_info_t *)link->priv)->cardnr = ret;
-
- return 0;
-
-failed:
- sedlbauer_release(link);
- return -ENODEV;
-
-} /* sedlbauer_config */
-
-static void sedlbauer_release(struct pcmcia_device *link)
-{
- local_info_t *local = link->priv;
- dev_dbg(&link->dev, "sedlbauer_release(0x%p)\n", link);
-
- if (local) {
- if (local->cardnr >= 0) {
- /* no unregister function with hisax */
- HiSax_closecard(local->cardnr);
- }
- }
-
- pcmcia_disable_device(link);
-} /* sedlbauer_release */
-
-static int sedlbauer_suspend(struct pcmcia_device *link)
-{
- local_info_t *dev = link->priv;
-
- dev->stop = 1;
-
- return 0;
-}
-
-static int sedlbauer_resume(struct pcmcia_device *link)
-{
- local_info_t *dev = link->priv;
-
- dev->stop = 0;
-
- return 0;
-}
-
-
-static const struct pcmcia_device_id sedlbauer_ids[] = {
- PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "speed star II", "V 3.1", 0x81fb79f5, 0xf3612e1d, 0x6b95c78a),
- PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D67", 0x81fb79f5, 0xe4e9bc12, 0x397b7e90),
- PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D98", 0x81fb79f5, 0xe4e9bc12, 0x2e5c7fce),
- PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", " (C) 93-94 VK", 0x81fb79f5, 0xe4e9bc12, 0x8db143fe),
- PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", " (c) 93-95 VK", 0x81fb79f5, 0xe4e9bc12, 0xb391ab4c),
- PCMCIA_DEVICE_PROD_ID12("HST High Soft Tech GmbH", "Saphir II B", 0xd79e0b84, 0x21d083ae),
-/* PCMCIA_DEVICE_PROD_ID1234("SEDLBAUER", 0x81fb79f5), */ /* too generic*/
- PCMCIA_DEVICE_NULL
-};
-MODULE_DEVICE_TABLE(pcmcia, sedlbauer_ids);
-
-static struct pcmcia_driver sedlbauer_driver = {
- .owner = THIS_MODULE,
- .name = "sedlbauer_cs",
- .probe = sedlbauer_probe,
- .remove = sedlbauer_detach,
- .id_table = sedlbauer_ids,
- .suspend = sedlbauer_suspend,
- .resume = sedlbauer_resume,
-};
-module_pcmcia_driver(sedlbauer_driver);
diff --git a/drivers/isdn/hisax/sportster.c b/drivers/isdn/hisax/sportster.c
deleted file mode 100644
index 18cee6360d0a..000000000000
--- a/drivers/isdn/hisax/sportster.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/* $Id: sportster.c,v 1.16.2.4 2004/01/13 23:48:39 keil Exp $
- *
- * low level stuff for USR Sportster internal TA
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Thanks to Christian "naddy" Weisgerber (3Com, US Robotics) for documentation
- *
- *
- */
-#include <linux/init.h>
-#include "hisax.h"
-#include "isac.h"
-#include "hscx.h"
-#include "isdnl1.h"
-
-static const char *sportster_revision = "$Revision: 1.16.2.4 $";
-
-#define byteout(addr, val) outb(val, addr)
-#define bytein(addr) inb(addr)
-
-#define SPORTSTER_ISAC 0xC000
-#define SPORTSTER_HSCXA 0x0000
-#define SPORTSTER_HSCXB 0x4000
-#define SPORTSTER_RES_IRQ 0x8000
-#define SPORTSTER_RESET 0x80
-#define SPORTSTER_INTE 0x40
-
-static inline int
-calc_off(unsigned int base, unsigned int off)
-{
- return (base + ((off & 0xfc) << 8) + ((off & 3) << 1));
-}
-
-static inline void
-read_fifo(unsigned int adr, u_char *data, int size)
-{
- insb(adr, data, size);
-}
-
-static void
-write_fifo(unsigned int adr, u_char *data, int size)
-{
- outsb(adr, data, size);
-}
-
-/* Interface functions */
-
-static u_char
-ReadISAC(struct IsdnCardState *cs, u_char offset)
-{
- return (bytein(calc_off(cs->hw.spt.isac, offset)));
-}
-
-static void
-WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
-{
- byteout(calc_off(cs->hw.spt.isac, offset), value);
-}
-
-static void
-ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- read_fifo(cs->hw.spt.isac, data, size);
-}
-
-static void
-WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- write_fifo(cs->hw.spt.isac, data, size);
-}
-
-static u_char
-ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
-{
- return (bytein(calc_off(cs->hw.spt.hscx[hscx], offset)));
-}
-
-static void
-WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
-{
- byteout(calc_off(cs->hw.spt.hscx[hscx], offset), value);
-}
-
-/*
- * fast interrupt HSCX stuff goes here
- */
-
-#define READHSCX(cs, nr, reg) bytein(calc_off(cs->hw.spt.hscx[nr], reg))
-#define WRITEHSCX(cs, nr, reg, data) byteout(calc_off(cs->hw.spt.hscx[nr], reg), data)
-#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.spt.hscx[nr], ptr, cnt)
-#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.spt.hscx[nr], ptr, cnt)
-
-#include "hscx_irq.c"
-
-static irqreturn_t
-sportster_interrupt(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_char val;
- u_long flags;
-
- spin_lock_irqsave(&cs->lock, flags);
- val = READHSCX(cs, 1, HSCX_ISTA);
-Start_HSCX:
- if (val)
- hscx_int_main(cs, val);
- val = ReadISAC(cs, ISAC_ISTA);
-Start_ISAC:
- if (val)
- isac_interrupt(cs, val);
- val = READHSCX(cs, 1, HSCX_ISTA);
- if (val) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "HSCX IntStat after IntRoutine");
- goto Start_HSCX;
- }
- val = ReadISAC(cs, ISAC_ISTA);
- if (val) {
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ISAC IntStat after IntRoutine");
- goto Start_ISAC;
- }
- /* get a new irq impulse if there any pending */
- bytein(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ + 1);
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static void
-release_io_sportster(struct IsdnCardState *cs)
-{
- int i, adr;
-
- byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, 0);
- for (i = 0; i < 64; i++) {
- adr = cs->hw.spt.cfg_reg + i * 1024;
- release_region(adr, 8);
- }
-}
-
-static void
-reset_sportster(struct IsdnCardState *cs)
-{
- cs->hw.spt.res_irq |= SPORTSTER_RESET; /* Reset On */
- byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
- mdelay(10);
- cs->hw.spt.res_irq &= ~SPORTSTER_RESET; /* Reset Off */
- byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
- mdelay(10);
-}
-
-static int
-Sportster_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
- u_long flags;
-
- switch (mt) {
- case CARD_RESET:
- spin_lock_irqsave(&cs->lock, flags);
- reset_sportster(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_RELEASE:
- release_io_sportster(cs);
- return (0);
- case CARD_INIT:
- spin_lock_irqsave(&cs->lock, flags);
- reset_sportster(cs);
- inithscxisac(cs, 1);
- cs->hw.spt.res_irq |= SPORTSTER_INTE; /* IRQ On */
- byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
- inithscxisac(cs, 2);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_TEST:
- return (0);
- }
- return (0);
-}
-
-static int get_io_range(struct IsdnCardState *cs)
-{
- int i, j, adr;
-
- for (i = 0; i < 64; i++) {
- adr = cs->hw.spt.cfg_reg + i * 1024;
- if (!request_region(adr, 8, "sportster")) {
- printk(KERN_WARNING "HiSax: USR Sportster config port "
- "%x-%x already in use\n",
- adr, adr + 8);
- break;
- }
- }
- if (i == 64)
- return (1);
- else {
- for (j = 0; j < i; j++) {
- adr = cs->hw.spt.cfg_reg + j * 1024;
- release_region(adr, 8);
- }
- return (0);
- }
-}
-
-int setup_sportster(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
-
- strcpy(tmp, sportster_revision);
- printk(KERN_INFO "HiSax: USR Sportster driver Rev. %s\n", HiSax_getrev(tmp));
- if (cs->typ != ISDN_CTYPE_SPORTSTER)
- return (0);
-
- cs->hw.spt.cfg_reg = card->para[1];
- cs->irq = card->para[0];
- if (!get_io_range(cs))
- return (0);
- cs->hw.spt.isac = cs->hw.spt.cfg_reg + SPORTSTER_ISAC;
- cs->hw.spt.hscx[0] = cs->hw.spt.cfg_reg + SPORTSTER_HSCXA;
- cs->hw.spt.hscx[1] = cs->hw.spt.cfg_reg + SPORTSTER_HSCXB;
-
- switch (cs->irq) {
- case 5: cs->hw.spt.res_irq = 1;
- break;
- case 7: cs->hw.spt.res_irq = 2;
- break;
- case 10:cs->hw.spt.res_irq = 3;
- break;
- case 11:cs->hw.spt.res_irq = 4;
- break;
- case 12:cs->hw.spt.res_irq = 5;
- break;
- case 14:cs->hw.spt.res_irq = 6;
- break;
- case 15:cs->hw.spt.res_irq = 7;
- break;
- default:release_io_sportster(cs);
- printk(KERN_WARNING "Sportster: wrong IRQ\n");
- return (0);
- }
- printk(KERN_INFO "HiSax: USR Sportster config irq:%d cfg:0x%X\n",
- cs->irq, cs->hw.spt.cfg_reg);
- setup_isac(cs);
- cs->readisac = &ReadISAC;
- cs->writeisac = &WriteISAC;
- cs->readisacfifo = &ReadISACfifo;
- cs->writeisacfifo = &WriteISACfifo;
- cs->BC_Read_Reg = &ReadHSCX;
- cs->BC_Write_Reg = &WriteHSCX;
- cs->BC_Send_Data = &hscx_fill_fifo;
- cs->cardmsg = &Sportster_card_msg;
- cs->irq_func = &sportster_interrupt;
- ISACVersion(cs, "Sportster:");
- if (HscxVersion(cs, "Sportster:")) {
- printk(KERN_WARNING
- "Sportster: wrong HSCX versions check IO address\n");
- release_io_sportster(cs);
- return (0);
- }
- return (1);
-}
diff --git a/drivers/isdn/hisax/st5481.h b/drivers/isdn/hisax/st5481.h
deleted file mode 100644
index b421b86ca7da..000000000000
--- a/drivers/isdn/hisax/st5481.h
+++ /dev/null
@@ -1,529 +0,0 @@
-/*
- * Driver for ST5481 USB ISDN modem
- *
- * Author Frode Isaksen
- * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
- * 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef _ST5481_H_
-#define _ST5481_H_
-
-
-// USB IDs, the Product Id is in the range 0x4810-0x481F
-
-#define ST_VENDOR_ID 0x0483
-#define ST5481_PRODUCT_ID 0x4810
-#define ST5481_PRODUCT_ID_MASK 0xFFF0
-
-// ST5481 endpoints when using alternative setting 3 (2B+D).
-// To get the endpoint address, OR with 0x80 for IN endpoints.
-
-#define EP_CTRL 0x00U /* Control endpoint */
-#define EP_INT 0x01U /* Interrupt endpoint */
-#define EP_B1_OUT 0x02U /* B1 channel out */
-#define EP_B1_IN 0x03U /* B1 channel in */
-#define EP_B2_OUT 0x04U /* B2 channel out */
-#define EP_B2_IN 0x05U /* B2 channel in */
-#define EP_D_OUT 0x06U /* D channel out */
-#define EP_D_IN 0x07U /* D channel in */
-
-// Number of isochronous packets. With 20 packets we get
-// 50 interrupts/sec for each endpoint.
-
-#define NUM_ISO_PACKETS_D 20
-#define NUM_ISO_PACKETS_B 20
-
-// Size of each isochronous packet.
-// In outgoing direction we need to match ISDN data rates:
-// D: 2 bytes / msec -> 16 kbit / s
-// B: 16 bytes / msec -> 64 kbit / s
-#define SIZE_ISO_PACKETS_D_IN 16
-#define SIZE_ISO_PACKETS_D_OUT 2
-#define SIZE_ISO_PACKETS_B_IN 32
-#define SIZE_ISO_PACKETS_B_OUT 8
-
-// If we overrun/underrun, we send one packet with +/- 2 bytes
-#define B_FLOW_ADJUST 2
-
-// Registers that are written using vendor specific device request
-// on endpoint 0.
-
-#define LBA 0x02 /* S loopback */
-#define SET_DEFAULT 0x06 /* Soft reset */
-#define LBB 0x1D /* S maintenance loopback */
-#define STT 0x1e /* S force transmission signals */
-#define SDA_MIN 0x20 /* SDA-sin minimal value */
-#define SDA_MAX 0x21 /* SDA-sin maximal value */
-#define SDELAY_VALUE 0x22 /* Delay between Tx and Rx clock */
-#define IN_D_COUNTER 0x36 /* D receive channel fifo counter */
-#define OUT_D_COUNTER 0x37 /* D transmit channel fifo counter */
-#define IN_B1_COUNTER 0x38 /* B1 receive channel fifo counter */
-#define OUT_B1_COUNTER 0x39 /* B1 transmit channel fifo counter */
-#define IN_B2_COUNTER 0x3a /* B2 receive channel fifo counter */
-#define OUT_B2_COUNTER 0x3b /* B2 transmit channel fifo counter */
-#define FFCTRL_IN_D 0x3C /* D receive channel fifo threshold low */
-#define FFCTRH_IN_D 0x3D /* D receive channel fifo threshold high */
-#define FFCTRL_OUT_D 0x3E /* D transmit channel fifo threshold low */
-#define FFCTRH_OUT_D 0x3F /* D transmit channel fifo threshold high */
-#define FFCTRL_IN_B1 0x40 /* B1 receive channel fifo threshold low */
-#define FFCTRH_IN_B1 0x41 /* B1 receive channel fifo threshold high */
-#define FFCTRL_OUT_B1 0x42 /* B1 transmit channel fifo threshold low */
-#define FFCTRH_OUT_B1 0x43 /* B1 transmit channel fifo threshold high */
-#define FFCTRL_IN_B2 0x44 /* B2 receive channel fifo threshold low */
-#define FFCTRH_IN_B2 0x45 /* B2 receive channel fifo threshold high */
-#define FFCTRL_OUT_B2 0x46 /* B2 transmit channel fifo threshold low */
-#define FFCTRH_OUT_B2 0x47 /* B2 transmit channel fifo threshold high */
-#define MPMSK 0x4A /* Multi purpose interrupt MASK register */
-#define FFMSK_D 0x4c /* D fifo interrupt MASK register */
-#define FFMSK_B1 0x4e /* B1 fifo interrupt MASK register */
-#define FFMSK_B2 0x50 /* B2 fifo interrupt MASK register */
-#define GPIO_DIR 0x52 /* GPIO pins direction registers */
-#define GPIO_OUT 0x53 /* GPIO pins output register */
-#define GPIO_IN 0x54 /* GPIO pins input register */
-#define TXCI 0x56 /* CI command to be transmitted */
-
-
-// Format of the interrupt packet received on endpoint 1:
-//
-// +--------+--------+--------+--------+--------+--------+
-// !MPINT !FFINT_D !FFINT_B1!FFINT_B2!CCIST !GPIO_INT!
-// +--------+--------+--------+--------+--------+--------+
-
-// Offsets in the interrupt packet
-
-#define MPINT 0
-#define FFINT_D 1
-#define FFINT_B1 2
-#define FFINT_B2 3
-#define CCIST 4
-#define GPIO_INT 5
-#define INT_PKT_SIZE 6
-
-// MPINT
-#define LSD_INT 0x80 /* S line activity detected */
-#define RXCI_INT 0x40 /* Indicate primitive arrived */
-#define DEN_INT 0x20 /* Signal enabling data out of D Tx fifo */
-#define DCOLL_INT 0x10 /* D channel collision */
-#define AMIVN_INT 0x04 /* AMI violation number reached 2 */
-#define INFOI_INT 0x04 /* INFOi changed */
-#define DRXON_INT 0x02 /* Reception channel active */
-#define GPCHG_INT 0x01 /* GPIO pin value changed */
-
-// FFINT_x
-#define IN_OVERRUN 0x80 /* In fifo overrun */
-#define OUT_UNDERRUN 0x40 /* Out fifo underrun */
-#define IN_UP 0x20 /* In fifo thresholdh up-crossed */
-#define IN_DOWN 0x10 /* In fifo thresholdl down-crossed */
-#define OUT_UP 0x08 /* Out fifo thresholdh up-crossed */
-#define OUT_DOWN 0x04 /* Out fifo thresholdl down-crossed */
-#define IN_COUNTER_ZEROED 0x02 /* In down-counter reached 0 */
-#define OUT_COUNTER_ZEROED 0x01 /* Out down-counter reached 0 */
-
-#define ANY_REC_INT (IN_OVERRUN + IN_UP + IN_DOWN + IN_COUNTER_ZEROED)
-#define ANY_XMIT_INT (OUT_UNDERRUN + OUT_UP + OUT_DOWN + OUT_COUNTER_ZEROED)
-
-
-// Level 1 commands that are sent using the TXCI device request
-#define ST5481_CMD_DR 0x0 /* Deactivation Request */
-#define ST5481_CMD_RES 0x1 /* state machine RESet */
-#define ST5481_CMD_TM1 0x2 /* Test Mode 1 */
-#define ST5481_CMD_TM2 0x3 /* Test Mode 2 */
-#define ST5481_CMD_PUP 0x7 /* Power UP */
-#define ST5481_CMD_AR8 0x8 /* Activation Request class 1 */
-#define ST5481_CMD_AR10 0x9 /* Activation Request class 2 */
-#define ST5481_CMD_ARL 0xA /* Activation Request Loopback */
-#define ST5481_CMD_PDN 0xF /* Power DoWn */
-
-// Turn on/off the LEDs using the GPIO device request.
-// To use the B LEDs, number_of_leds must be set to 4
-#define B1_LED 0x10U
-#define B2_LED 0x20U
-#define GREEN_LED 0x40U
-#define RED_LED 0x80U
-
-// D channel out states
-enum {
- ST_DOUT_NONE,
-
- ST_DOUT_SHORT_INIT,
- ST_DOUT_SHORT_WAIT_DEN,
-
- ST_DOUT_LONG_INIT,
- ST_DOUT_LONG_WAIT_DEN,
- ST_DOUT_NORMAL,
-
- ST_DOUT_WAIT_FOR_UNDERRUN,
- ST_DOUT_WAIT_FOR_NOT_BUSY,
- ST_DOUT_WAIT_FOR_STOP,
- ST_DOUT_WAIT_FOR_RESET,
-};
-
-#define DOUT_STATE_COUNT (ST_DOUT_WAIT_FOR_RESET + 1)
-
-// D channel out events
-enum {
- EV_DOUT_START_XMIT,
- EV_DOUT_COMPLETE,
- EV_DOUT_DEN,
- EV_DOUT_RESETED,
- EV_DOUT_STOPPED,
- EV_DOUT_COLL,
- EV_DOUT_UNDERRUN,
-};
-
-#define DOUT_EVENT_COUNT (EV_DOUT_UNDERRUN + 1)
-
-// ----------------------------------------------------------------------
-
-enum {
- ST_L1_F3,
- ST_L1_F4,
- ST_L1_F6,
- ST_L1_F7,
- ST_L1_F8,
-};
-
-#define L1_STATE_COUNT (ST_L1_F8 + 1)
-
-// The first 16 entries match the Level 1 indications that
-// are found at offset 4 (CCIST) in the interrupt packet
-
-enum {
- EV_IND_DP, // 0000 Deactivation Pending
- EV_IND_1, // 0001
- EV_IND_2, // 0010
- EV_IND_3, // 0011
- EV_IND_RSY, // 0100 ReSYnchronizing
- EV_IND_5, // 0101
- EV_IND_6, // 0110
- EV_IND_7, // 0111
- EV_IND_AP, // 1000 Activation Pending
- EV_IND_9, // 1001
- EV_IND_10, // 1010
- EV_IND_11, // 1011
- EV_IND_AI8, // 1100 Activation Indication class 8
- EV_IND_AI10,// 1101 Activation Indication class 10
- EV_IND_AIL, // 1110 Activation Indication Loopback
- EV_IND_DI, // 1111 Deactivation Indication
- EV_PH_ACTIVATE_REQ,
- EV_PH_DEACTIVATE_REQ,
- EV_TIMER3,
-};
-
-#define L1_EVENT_COUNT (EV_TIMER3 + 1)
-
-#define ERR(format, arg...) \
- printk(KERN_ERR "%s:%s: " format "\n" , __FILE__, __func__ , ## arg)
-
-#define WARNING(format, arg...) \
- printk(KERN_WARNING "%s:%s: " format "\n" , __FILE__, __func__ , ## arg)
-
-#define INFO(format, arg...) \
- printk(KERN_INFO "%s:%s: " format "\n" , __FILE__, __func__ , ## arg)
-
-#include <linux/isdn/hdlc.h>
-#include "fsm.h"
-#include "hisax_if.h"
-#include <linux/skbuff.h>
-
-/* ======================================================================
- * FIFO handling
- */
-
-/* Generic FIFO structure */
-struct fifo {
- u_char r, w, count, size;
- spinlock_t lock;
-};
-
-/*
- * Init an FIFO
- */
-static inline void fifo_init(struct fifo *fifo, int size)
-{
- fifo->r = fifo->w = fifo->count = 0;
- fifo->size = size;
- spin_lock_init(&fifo->lock);
-}
-
-/*
- * Add an entry to the FIFO
- */
-static inline int fifo_add(struct fifo *fifo)
-{
- unsigned long flags;
- int index;
-
- if (!fifo) {
- return -1;
- }
-
- spin_lock_irqsave(&fifo->lock, flags);
- if (fifo->count == fifo->size) {
- // FIFO full
- index = -1;
- } else {
- // Return index where to get the next data to add to the FIFO
- index = fifo->w++ & (fifo->size - 1);
- fifo->count++;
- }
- spin_unlock_irqrestore(&fifo->lock, flags);
- return index;
-}
-
-/*
- * Remove an entry from the FIFO with the index returned.
- */
-static inline int fifo_remove(struct fifo *fifo)
-{
- unsigned long flags;
- int index;
-
- if (!fifo) {
- return -1;
- }
-
- spin_lock_irqsave(&fifo->lock, flags);
- if (!fifo->count) {
- // FIFO empty
- index = -1;
- } else {
- // Return index where to get the next data from the FIFO
- index = fifo->r++ & (fifo->size - 1);
- fifo->count--;
- }
- spin_unlock_irqrestore(&fifo->lock, flags);
-
- return index;
-}
-
-/* ======================================================================
- * control pipe
- */
-typedef void (*ctrl_complete_t)(void *);
-
-typedef struct ctrl_msg {
- struct usb_ctrlrequest dr;
- ctrl_complete_t complete;
- void *context;
-} ctrl_msg;
-
-/* FIFO of ctrl messages waiting to be sent */
-#define MAX_EP0_MSG 16
-struct ctrl_msg_fifo {
- struct fifo f;
- struct ctrl_msg data[MAX_EP0_MSG];
-};
-
-#define MAX_DFRAME_LEN_L1 300
-#define HSCX_BUFMAX 4096
-
-struct st5481_ctrl {
- struct ctrl_msg_fifo msg_fifo;
- unsigned long busy;
- struct urb *urb;
-};
-
-struct st5481_intr {
- // struct evt_fifo evt_fifo;
- struct urb *urb;
-};
-
-struct st5481_d_out {
- struct isdnhdlc_vars hdlc_state;
- struct urb *urb[2]; /* double buffering */
- unsigned long busy;
- struct sk_buff *tx_skb;
- struct FsmInst fsm;
-};
-
-struct st5481_b_out {
- struct isdnhdlc_vars hdlc_state;
- struct urb *urb[2]; /* double buffering */
- u_char flow_event;
- u_long busy;
- struct sk_buff *tx_skb;
-};
-
-struct st5481_in {
- struct isdnhdlc_vars hdlc_state;
- struct urb *urb[2]; /* double buffering */
- int mode;
- int bufsize;
- unsigned int num_packets;
- unsigned int packet_size;
- unsigned char ep, counter;
- unsigned char *rcvbuf;
- struct st5481_adapter *adapter;
- struct hisax_if *hisax_if;
-};
-
-int st5481_setup_in(struct st5481_in *in);
-void st5481_release_in(struct st5481_in *in);
-void st5481_in_mode(struct st5481_in *in, int mode);
-
-struct st5481_bcs {
- struct hisax_b_if b_if;
- struct st5481_adapter *adapter;
- struct st5481_in b_in;
- struct st5481_b_out b_out;
- int channel;
- int mode;
-};
-
-struct st5481_adapter {
- int number_of_leds;
- struct usb_device *usb_dev;
- struct hisax_d_if hisax_d_if;
-
- struct st5481_ctrl ctrl;
- struct st5481_intr intr;
- struct st5481_in d_in;
- struct st5481_d_out d_out;
-
- unsigned char leds;
- unsigned int led_counter;
-
- unsigned long event;
-
- struct FsmInst l1m;
- struct FsmTimer timer;
-
- struct st5481_bcs bcs[2];
-};
-
-#define TIMER3_VALUE 7000
-
-/* ======================================================================
- *
- */
-
-/*
- * Submit an URB with error reporting. This is a macro so
- * the __func__ returns the caller function name.
- */
-#define SUBMIT_URB(urb, mem_flags) \
- ({ \
- int status; \
- if ((status = usb_submit_urb(urb, mem_flags)) < 0) { \
- WARNING("usb_submit_urb failed,status=%d", status); \
- } \
- status; \
- })
-
-/*
- * USB double buffering, return the URB index (0 or 1).
- */
-static inline int get_buf_nr(struct urb *urbs[], struct urb *urb)
-{
- return (urbs[0] == urb ? 0 : 1);
-}
-
-/* ---------------------------------------------------------------------- */
-
-/* B Channel */
-
-int st5481_setup_b(struct st5481_bcs *bcs);
-void st5481_release_b(struct st5481_bcs *bcs);
-void st5481_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg);
-
-/* D Channel */
-
-int st5481_setup_d(struct st5481_adapter *adapter);
-void st5481_release_d(struct st5481_adapter *adapter);
-void st5481_b_l2l1(struct hisax_if *b_if, int pr, void *arg);
-int st5481_d_init(void);
-void st5481_d_exit(void);
-
-/* USB */
-void st5481_ph_command(struct st5481_adapter *adapter, unsigned int command);
-int st5481_setup_isocpipes(struct urb *urb[2], struct usb_device *dev,
- unsigned int pipe, int num_packets,
- int packet_size, int buf_size,
- usb_complete_t complete, void *context);
-void st5481_release_isocpipes(struct urb *urb[2]);
-
-void st5481_usb_pipe_reset(struct st5481_adapter *adapter,
- u_char pipe, ctrl_complete_t complete, void *context);
-void st5481_usb_device_ctrl_msg(struct st5481_adapter *adapter,
- u8 request, u16 value,
- ctrl_complete_t complete, void *context);
-int st5481_setup_usb(struct st5481_adapter *adapter);
-void st5481_release_usb(struct st5481_adapter *adapter);
-void st5481_start(struct st5481_adapter *adapter);
-void st5481_stop(struct st5481_adapter *adapter);
-
-// ----------------------------------------------------------------------
-// debugging macros
-
-#define __debug_variable st5481_debug
-#include "hisax_debug.h"
-
-extern int st5481_debug;
-
-#ifdef CONFIG_HISAX_DEBUG
-
-#define DBG_ISO_PACKET(level, urb) \
- if (level & __debug_variable) dump_iso_packet(__func__, urb)
-
-static void __attribute__((unused))
-dump_iso_packet(const char *name, struct urb *urb)
-{
- int i, j;
- int len, ofs;
- u_char *data;
-
- printk(KERN_DEBUG "%s: packets=%d,errors=%d\n",
- name, urb->number_of_packets, urb->error_count);
- for (i = 0; i < urb->number_of_packets; ++i) {
- if (urb->pipe & USB_DIR_IN) {
- len = urb->iso_frame_desc[i].actual_length;
- } else {
- len = urb->iso_frame_desc[i].length;
- }
- ofs = urb->iso_frame_desc[i].offset;
- printk(KERN_DEBUG "len=%.2d,ofs=%.3d ", len, ofs);
- if (len) {
- data = urb->transfer_buffer + ofs;
- for (j = 0; j < len; j++) {
- printk("%.2x", data[j]);
- }
- }
- printk("\n");
- }
-}
-
-static inline const char *ST5481_CMD_string(int evt)
-{
- static char s[16];
-
- switch (evt) {
- case ST5481_CMD_DR: return "DR";
- case ST5481_CMD_RES: return "RES";
- case ST5481_CMD_TM1: return "TM1";
- case ST5481_CMD_TM2: return "TM2";
- case ST5481_CMD_PUP: return "PUP";
- case ST5481_CMD_AR8: return "AR8";
- case ST5481_CMD_AR10: return "AR10";
- case ST5481_CMD_ARL: return "ARL";
- case ST5481_CMD_PDN: return "PDN";
- }
-
- sprintf(s, "0x%x", evt);
- return s;
-}
-
-#else
-
-#define DBG_ISO_PACKET(level, urb) do {} while (0)
-
-#endif
-
-
-
-#endif
diff --git a/drivers/isdn/hisax/st5481_b.c b/drivers/isdn/hisax/st5481_b.c
deleted file mode 100644
index f64a36007800..000000000000
--- a/drivers/isdn/hisax/st5481_b.c
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * Driver for ST5481 USB ISDN modem
- *
- * Author Frode Isaksen
- * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
- * 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/init.h>
-#include <linux/gfp.h>
-#include <linux/usb.h>
-#include <linux/netdevice.h>
-#include <linux/bitrev.h>
-#include "st5481.h"
-
-static inline void B_L1L2(struct st5481_bcs *bcs, int pr, void *arg)
-{
- struct hisax_if *ifc = (struct hisax_if *) &bcs->b_if;
-
- ifc->l1l2(ifc, pr, arg);
-}
-
-/*
- * Encode and transmit next frame.
- */
-static void usb_b_out(struct st5481_bcs *bcs, int buf_nr)
-{
- struct st5481_b_out *b_out = &bcs->b_out;
- struct st5481_adapter *adapter = bcs->adapter;
- struct urb *urb;
- unsigned int packet_size, offset;
- int len, buf_size, bytes_sent;
- int i;
- struct sk_buff *skb;
-
- if (test_and_set_bit(buf_nr, &b_out->busy)) {
- DBG(4, "ep %d urb %d busy", (bcs->channel + 1) * 2, buf_nr);
- return;
- }
- urb = b_out->urb[buf_nr];
-
- // Adjust isoc buffer size according to flow state
- if (b_out->flow_event & (OUT_DOWN | OUT_UNDERRUN)) {
- buf_size = NUM_ISO_PACKETS_B * SIZE_ISO_PACKETS_B_OUT + B_FLOW_ADJUST;
- packet_size = SIZE_ISO_PACKETS_B_OUT + B_FLOW_ADJUST;
- DBG(4, "B%d,adjust flow,add %d bytes", bcs->channel + 1, B_FLOW_ADJUST);
- } else if (b_out->flow_event & OUT_UP) {
- buf_size = NUM_ISO_PACKETS_B * SIZE_ISO_PACKETS_B_OUT - B_FLOW_ADJUST;
- packet_size = SIZE_ISO_PACKETS_B_OUT - B_FLOW_ADJUST;
- DBG(4, "B%d,adjust flow,remove %d bytes", bcs->channel + 1, B_FLOW_ADJUST);
- } else {
- buf_size = NUM_ISO_PACKETS_B * SIZE_ISO_PACKETS_B_OUT;
- packet_size = 8;
- }
- b_out->flow_event = 0;
-
- len = 0;
- while (len < buf_size) {
- if ((skb = b_out->tx_skb)) {
- DBG_SKB(0x100, skb);
- DBG(4, "B%d,len=%d", bcs->channel + 1, skb->len);
-
- if (bcs->mode == L1_MODE_TRANS) {
- bytes_sent = buf_size - len;
- if (skb->len < bytes_sent)
- bytes_sent = skb->len;
- { /* swap tx bytes to get hearable audio data */
- register unsigned char *src = skb->data;
- register unsigned char *dest = urb->transfer_buffer + len;
- register unsigned int count;
- for (count = 0; count < bytes_sent; count++)
- *dest++ = bitrev8(*src++);
- }
- len += bytes_sent;
- } else {
- len += isdnhdlc_encode(&b_out->hdlc_state,
- skb->data, skb->len, &bytes_sent,
- urb->transfer_buffer + len, buf_size-len);
- }
-
- skb_pull(skb, bytes_sent);
-
- if (!skb->len) {
- // Frame sent
- b_out->tx_skb = NULL;
- B_L1L2(bcs, PH_DATA | CONFIRM, (void *)(unsigned long) skb->truesize);
- dev_kfree_skb_any(skb);
-
-/* if (!(bcs->tx_skb = skb_dequeue(&bcs->sq))) { */
-/* st5481B_sched_event(bcs, B_XMTBUFREADY); */
-/* } */
- }
- } else {
- if (bcs->mode == L1_MODE_TRANS) {
- memset(urb->transfer_buffer + len, 0xff, buf_size-len);
- len = buf_size;
- } else {
- // Send flags
- len += isdnhdlc_encode(&b_out->hdlc_state,
- NULL, 0, &bytes_sent,
- urb->transfer_buffer + len, buf_size-len);
- }
- }
- }
-
- // Prepare the URB
- for (i = 0, offset = 0; offset < len; i++) {
- urb->iso_frame_desc[i].offset = offset;
- urb->iso_frame_desc[i].length = packet_size;
- offset += packet_size;
- packet_size = SIZE_ISO_PACKETS_B_OUT;
- }
- urb->transfer_buffer_length = len;
- urb->number_of_packets = i;
- urb->dev = adapter->usb_dev;
-
- DBG_ISO_PACKET(0x200, urb);
-
- SUBMIT_URB(urb, GFP_NOIO);
-}
-
-/*
- * Start transferring (flags or data) on the B channel, since
- * FIFO counters has been set to a non-zero value.
- */
-static void st5481B_start_xfer(void *context)
-{
- struct st5481_bcs *bcs = context;
-
- DBG(4, "B%d", bcs->channel + 1);
-
- // Start transmitting (flags or data) on B channel
-
- usb_b_out(bcs, 0);
- usb_b_out(bcs, 1);
-}
-
-/*
- * If the adapter has only 2 LEDs, the green
- * LED will blink with a rate depending
- * on the number of channels opened.
- */
-static void led_blink(struct st5481_adapter *adapter)
-{
- u_char leds = adapter->leds;
-
- // 50 frames/sec for each channel
- if (++adapter->led_counter % 50) {
- return;
- }
-
- if (adapter->led_counter % 100) {
- leds |= GREEN_LED;
- } else {
- leds &= ~GREEN_LED;
- }
-
- st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, leds, NULL, NULL);
-}
-
-static void usb_b_out_complete(struct urb *urb)
-{
- struct st5481_bcs *bcs = urb->context;
- struct st5481_b_out *b_out = &bcs->b_out;
- struct st5481_adapter *adapter = bcs->adapter;
- int buf_nr;
-
- buf_nr = get_buf_nr(b_out->urb, urb);
- test_and_clear_bit(buf_nr, &b_out->busy);
-
- if (unlikely(urb->status < 0)) {
- switch (urb->status) {
- case -ENOENT:
- case -ESHUTDOWN:
- case -ECONNRESET:
- DBG(4, "urb killed status %d", urb->status);
- return; // Give up
- default:
- WARNING("urb status %d", urb->status);
- if (b_out->busy == 0) {
- st5481_usb_pipe_reset(adapter, (bcs->channel + 1) * 2 | USB_DIR_OUT, NULL, NULL);
- }
- break;
- }
- }
-
- usb_b_out(bcs, buf_nr);
-
- if (adapter->number_of_leds == 2)
- led_blink(adapter);
-}
-
-/*
- * Start or stop the transfer on the B channel.
- */
-static void st5481B_mode(struct st5481_bcs *bcs, int mode)
-{
- struct st5481_b_out *b_out = &bcs->b_out;
- struct st5481_adapter *adapter = bcs->adapter;
-
- DBG(4, "B%d,mode=%d", bcs->channel + 1, mode);
-
- if (bcs->mode == mode)
- return;
-
- bcs->mode = mode;
-
- // Cancel all USB transfers on this B channel
- usb_unlink_urb(b_out->urb[0]);
- usb_unlink_urb(b_out->urb[1]);
- b_out->busy = 0;
-
- st5481_in_mode(&bcs->b_in, mode);
- if (bcs->mode != L1_MODE_NULL) {
- // Open the B channel
- if (bcs->mode != L1_MODE_TRANS) {
- u32 features = HDLC_BITREVERSE;
- if (bcs->mode == L1_MODE_HDLC_56K)
- features |= HDLC_56KBIT;
- isdnhdlc_out_init(&b_out->hdlc_state, features);
- }
- st5481_usb_pipe_reset(adapter, (bcs->channel + 1) * 2, NULL, NULL);
-
- // Enable B channel interrupts
- st5481_usb_device_ctrl_msg(adapter, FFMSK_B1 + (bcs->channel * 2),
- OUT_UP + OUT_DOWN + OUT_UNDERRUN, NULL, NULL);
-
- // Enable B channel FIFOs
- st5481_usb_device_ctrl_msg(adapter, OUT_B1_COUNTER+(bcs->channel * 2), 32, st5481B_start_xfer, bcs);
- if (adapter->number_of_leds == 4) {
- if (bcs->channel == 0) {
- adapter->leds |= B1_LED;
- } else {
- adapter->leds |= B2_LED;
- }
- }
- } else {
- // Disable B channel interrupts
- st5481_usb_device_ctrl_msg(adapter, FFMSK_B1+(bcs->channel * 2), 0, NULL, NULL);
-
- // Disable B channel FIFOs
- st5481_usb_device_ctrl_msg(adapter, OUT_B1_COUNTER+(bcs->channel * 2), 0, NULL, NULL);
-
- if (adapter->number_of_leds == 4) {
- if (bcs->channel == 0) {
- adapter->leds &= ~B1_LED;
- } else {
- adapter->leds &= ~B2_LED;
- }
- } else {
- st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, adapter->leds, NULL, NULL);
- }
- if (b_out->tx_skb) {
- dev_kfree_skb_any(b_out->tx_skb);
- b_out->tx_skb = NULL;
- }
-
- }
-}
-
-static int st5481_setup_b_out(struct st5481_bcs *bcs)
-{
- struct usb_device *dev = bcs->adapter->usb_dev;
- struct usb_interface *intf;
- struct usb_host_interface *altsetting = NULL;
- struct usb_host_endpoint *endpoint;
- struct st5481_b_out *b_out = &bcs->b_out;
-
- DBG(4, "");
-
- intf = usb_ifnum_to_if(dev, 0);
- if (intf)
- altsetting = usb_altnum_to_altsetting(intf, 3);
- if (!altsetting)
- return -ENXIO;
-
- // Allocate URBs and buffers for the B channel out
- endpoint = &altsetting->endpoint[EP_B1_OUT - 1 + bcs->channel * 2];
-
- DBG(4, "endpoint address=%02x,packet size=%d",
- endpoint->desc.bEndpointAddress, le16_to_cpu(endpoint->desc.wMaxPacketSize));
-
- // Allocate memory for 8000bytes/sec + extra bytes if underrun
- return st5481_setup_isocpipes(b_out->urb, dev,
- usb_sndisocpipe(dev, endpoint->desc.bEndpointAddress),
- NUM_ISO_PACKETS_B, SIZE_ISO_PACKETS_B_OUT,
- NUM_ISO_PACKETS_B * SIZE_ISO_PACKETS_B_OUT + B_FLOW_ADJUST,
- usb_b_out_complete, bcs);
-}
-
-static void st5481_release_b_out(struct st5481_bcs *bcs)
-{
- struct st5481_b_out *b_out = &bcs->b_out;
-
- DBG(4, "");
-
- st5481_release_isocpipes(b_out->urb);
-}
-
-int st5481_setup_b(struct st5481_bcs *bcs)
-{
- int retval;
-
- DBG(4, "");
-
- retval = st5481_setup_b_out(bcs);
- if (retval)
- goto err;
- bcs->b_in.bufsize = HSCX_BUFMAX;
- bcs->b_in.num_packets = NUM_ISO_PACKETS_B;
- bcs->b_in.packet_size = SIZE_ISO_PACKETS_B_IN;
- bcs->b_in.ep = (bcs->channel ? EP_B2_IN : EP_B1_IN) | USB_DIR_IN;
- bcs->b_in.counter = bcs->channel ? IN_B2_COUNTER : IN_B1_COUNTER;
- bcs->b_in.adapter = bcs->adapter;
- bcs->b_in.hisax_if = &bcs->b_if.ifc;
- retval = st5481_setup_in(&bcs->b_in);
- if (retval)
- goto err_b_out;
-
-
- return 0;
-
-err_b_out:
- st5481_release_b_out(bcs);
-err:
- return retval;
-}
-
-/*
- * Release buffers and URBs for the B channels
- */
-void st5481_release_b(struct st5481_bcs *bcs)
-{
- DBG(4, "");
-
- st5481_release_in(&bcs->b_in);
- st5481_release_b_out(bcs);
-}
-
-/*
- * st5481_b_l2l1 is the entry point for upper layer routines that want to
- * transmit on the B channel. PH_DATA | REQUEST is a normal packet that
- * we either start transmitting (if idle) or queue (if busy).
- * PH_PULL | REQUEST can be called to request a callback message
- * (PH_PULL | CONFIRM)
- * once the link is idle. After a "pull" callback, the upper layer
- * routines can use PH_PULL | INDICATION to send data.
- */
-void st5481_b_l2l1(struct hisax_if *ifc, int pr, void *arg)
-{
- struct st5481_bcs *bcs = ifc->priv;
- struct sk_buff *skb = arg;
- long mode;
-
- DBG(4, "");
-
- switch (pr) {
- case PH_DATA | REQUEST:
- BUG_ON(bcs->b_out.tx_skb);
- bcs->b_out.tx_skb = skb;
- break;
- case PH_ACTIVATE | REQUEST:
- mode = (long) arg;
- DBG(4, "B%d,PH_ACTIVATE_REQUEST %ld", bcs->channel + 1, mode);
- st5481B_mode(bcs, mode);
- B_L1L2(bcs, PH_ACTIVATE | INDICATION, NULL);
- break;
- case PH_DEACTIVATE | REQUEST:
- DBG(4, "B%d,PH_DEACTIVATE_REQUEST", bcs->channel + 1);
- st5481B_mode(bcs, L1_MODE_NULL);
- B_L1L2(bcs, PH_DEACTIVATE | INDICATION, NULL);
- break;
- default:
- WARNING("pr %#x\n", pr);
- }
-}
diff --git a/drivers/isdn/hisax/st5481_d.c b/drivers/isdn/hisax/st5481_d.c
deleted file mode 100644
index e88c5c71fca7..000000000000
--- a/drivers/isdn/hisax/st5481_d.c
+++ /dev/null
@@ -1,780 +0,0 @@
-/*
- * Driver for ST5481 USB ISDN modem
- *
- * Author Frode Isaksen
- * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
- * 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/init.h>
-#include <linux/gfp.h>
-#include <linux/usb.h>
-#include <linux/netdevice.h>
-#include "st5481.h"
-
-static void ph_connect(struct st5481_adapter *adapter);
-static void ph_disconnect(struct st5481_adapter *adapter);
-
-static struct Fsm l1fsm;
-
-static char *strL1State[] =
-{
- "ST_L1_F3",
- "ST_L1_F4",
- "ST_L1_F6",
- "ST_L1_F7",
- "ST_L1_F8",
-};
-
-static char *strL1Event[] =
-{
- "EV_IND_DP",
- "EV_IND_1",
- "EV_IND_2",
- "EV_IND_3",
- "EV_IND_RSY",
- "EV_IND_5",
- "EV_IND_6",
- "EV_IND_7",
- "EV_IND_AP",
- "EV_IND_9",
- "EV_IND_10",
- "EV_IND_11",
- "EV_IND_AI8",
- "EV_IND_AI10",
- "EV_IND_AIL",
- "EV_IND_DI",
- "EV_PH_ACTIVATE_REQ",
- "EV_PH_DEACTIVATE_REQ",
- "EV_TIMER3",
-};
-
-static inline void D_L1L2(struct st5481_adapter *adapter, int pr, void *arg)
-{
- struct hisax_if *ifc = (struct hisax_if *) &adapter->hisax_d_if;
-
- ifc->l1l2(ifc, pr, arg);
-}
-
-static void
-l1_go_f3(struct FsmInst *fi, int event, void *arg)
-{
- struct st5481_adapter *adapter = fi->userdata;
-
- if (fi->state == ST_L1_F7)
- ph_disconnect(adapter);
-
- FsmChangeState(fi, ST_L1_F3);
- D_L1L2(adapter, PH_DEACTIVATE | INDICATION, NULL);
-}
-
-static void
-l1_go_f6(struct FsmInst *fi, int event, void *arg)
-{
- struct st5481_adapter *adapter = fi->userdata;
-
- if (fi->state == ST_L1_F7)
- ph_disconnect(adapter);
-
- FsmChangeState(fi, ST_L1_F6);
-}
-
-static void
-l1_go_f7(struct FsmInst *fi, int event, void *arg)
-{
- struct st5481_adapter *adapter = fi->userdata;
-
- FsmDelTimer(&adapter->timer, 0);
- ph_connect(adapter);
- FsmChangeState(fi, ST_L1_F7);
- D_L1L2(adapter, PH_ACTIVATE | INDICATION, NULL);
-}
-
-static void
-l1_go_f8(struct FsmInst *fi, int event, void *arg)
-{
- struct st5481_adapter *adapter = fi->userdata;
-
- if (fi->state == ST_L1_F7)
- ph_disconnect(adapter);
-
- FsmChangeState(fi, ST_L1_F8);
-}
-
-static void
-l1_timer3(struct FsmInst *fi, int event, void *arg)
-{
- struct st5481_adapter *adapter = fi->userdata;
-
- st5481_ph_command(adapter, ST5481_CMD_DR);
- FsmChangeState(fi, ST_L1_F3);
- D_L1L2(adapter, PH_DEACTIVATE | INDICATION, NULL);
-}
-
-static void
-l1_ignore(struct FsmInst *fi, int event, void *arg)
-{
-}
-
-static void
-l1_activate(struct FsmInst *fi, int event, void *arg)
-{
- struct st5481_adapter *adapter = fi->userdata;
-
- st5481_ph_command(adapter, ST5481_CMD_DR);
- st5481_ph_command(adapter, ST5481_CMD_PUP);
- FsmRestartTimer(&adapter->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
- st5481_ph_command(adapter, ST5481_CMD_AR8);
- FsmChangeState(fi, ST_L1_F4);
-}
-
-static struct FsmNode L1FnList[] __initdata =
-{
- {ST_L1_F3, EV_IND_DP, l1_ignore},
- {ST_L1_F3, EV_IND_AP, l1_go_f6},
- {ST_L1_F3, EV_IND_AI8, l1_go_f7},
- {ST_L1_F3, EV_IND_AI10, l1_go_f7},
- {ST_L1_F3, EV_PH_ACTIVATE_REQ, l1_activate},
-
- {ST_L1_F4, EV_TIMER3, l1_timer3},
- {ST_L1_F4, EV_IND_DP, l1_go_f3},
- {ST_L1_F4, EV_IND_AP, l1_go_f6},
- {ST_L1_F4, EV_IND_AI8, l1_go_f7},
- {ST_L1_F4, EV_IND_AI10, l1_go_f7},
-
- {ST_L1_F6, EV_TIMER3, l1_timer3},
- {ST_L1_F6, EV_IND_DP, l1_go_f3},
- {ST_L1_F6, EV_IND_AP, l1_ignore},
- {ST_L1_F6, EV_IND_AI8, l1_go_f7},
- {ST_L1_F6, EV_IND_AI10, l1_go_f7},
- {ST_L1_F7, EV_IND_RSY, l1_go_f8},
-
- {ST_L1_F7, EV_IND_DP, l1_go_f3},
- {ST_L1_F7, EV_IND_AP, l1_go_f6},
- {ST_L1_F7, EV_IND_AI8, l1_ignore},
- {ST_L1_F7, EV_IND_AI10, l1_ignore},
- {ST_L1_F7, EV_IND_RSY, l1_go_f8},
-
- {ST_L1_F8, EV_TIMER3, l1_timer3},
- {ST_L1_F8, EV_IND_DP, l1_go_f3},
- {ST_L1_F8, EV_IND_AP, l1_go_f6},
- {ST_L1_F8, EV_IND_AI8, l1_go_f8},
- {ST_L1_F8, EV_IND_AI10, l1_go_f8},
- {ST_L1_F8, EV_IND_RSY, l1_ignore},
-};
-
-static __printf(2, 3)
- void l1m_debug(struct FsmInst *fi, char *fmt, ...)
-{
- va_list args;
- char buf[256];
-
- va_start(args, fmt);
- vsnprintf(buf, sizeof(buf), fmt, args);
- DBG(8, "%s", buf);
- va_end(args);
-}
-
-/* ======================================================================
- * D-Channel out
- */
-
-/*
- D OUT state machine:
- ====================
-
- Transmit short frame (< 16 bytes of encoded data):
-
- L1 FRAME D_OUT_STATE USB D CHANNEL
- -------- ----------- --- ---------
-
- FIXME
-
- -> [xx..xx] SHORT_INIT -> [7Exx..xxC1C27EFF]
- SHORT_WAIT_DEN <> OUT_D_COUNTER=16
-
- END_OF_SHORT <- DEN_EVENT -> 7Exx
- xxxx
- xxxx
- xxxx
- xxxx
- xxxx
- C1C1
- 7EFF
- WAIT_FOR_RESET_IDLE <- D_UNDERRUN <- (8ms)
- IDLE <> Reset pipe
-
-
-
- Transmit long frame (>= 16 bytes of encoded data):
-
- L1 FRAME D_OUT_STATE USB D CHANNEL
- -------- ----------- --- ---------
-
- -> [xx...xx] IDLE
- WAIT_FOR_STOP <> OUT_D_COUNTER=0
- WAIT_FOR_RESET <> Reset pipe
- STOP
- INIT_LONG_FRAME -> [7Exx..xx]
- WAIT_DEN <> OUT_D_COUNTER=16
- OUT_NORMAL <- DEN_EVENT -> 7Exx
- END_OF_FRAME_BUSY -> [xxxx] xxxx
- END_OF_FRAME_NOT_BUSY -> [xxxx] xxxx
- -> [xxxx] xxxx
- -> [C1C2] xxxx
- -> [7EFF] xxxx
- xxxx
- xxxx
- ....
- xxxx
- C1C2
- 7EFF
- <- D_UNDERRUN <- (> 8ms)
- WAIT_FOR_STOP <> OUT_D_COUNTER=0
- WAIT_FOR_RESET <> Reset pipe
- STOP
-
-*/
-
-static struct Fsm dout_fsm;
-
-static char *strDoutState[] =
-{
- "ST_DOUT_NONE",
-
- "ST_DOUT_SHORT_INIT",
- "ST_DOUT_SHORT_WAIT_DEN",
-
- "ST_DOUT_LONG_INIT",
- "ST_DOUT_LONG_WAIT_DEN",
- "ST_DOUT_NORMAL",
-
- "ST_DOUT_WAIT_FOR_UNDERRUN",
- "ST_DOUT_WAIT_FOR_NOT_BUSY",
- "ST_DOUT_WAIT_FOR_STOP",
- "ST_DOUT_WAIT_FOR_RESET",
-};
-
-static char *strDoutEvent[] =
-{
- "EV_DOUT_START_XMIT",
- "EV_DOUT_COMPLETE",
- "EV_DOUT_DEN",
- "EV_DOUT_RESETED",
- "EV_DOUT_STOPPED",
- "EV_DOUT_COLL",
- "EV_DOUT_UNDERRUN",
-};
-
-static __printf(2, 3)
- void dout_debug(struct FsmInst *fi, char *fmt, ...)
-{
- va_list args;
- char buf[256];
-
- va_start(args, fmt);
- vsnprintf(buf, sizeof(buf), fmt, args);
- DBG(0x2, "%s", buf);
- va_end(args);
-}
-
-static void dout_stop_event(void *context)
-{
- struct st5481_adapter *adapter = context;
-
- FsmEvent(&adapter->d_out.fsm, EV_DOUT_STOPPED, NULL);
-}
-
-/*
- * Start the transfer of a D channel frame.
- */
-static void usb_d_out(struct st5481_adapter *adapter, int buf_nr)
-{
- struct st5481_d_out *d_out = &adapter->d_out;
- struct urb *urb;
- unsigned int num_packets, packet_offset;
- int len, buf_size, bytes_sent;
- struct sk_buff *skb;
- struct usb_iso_packet_descriptor *desc;
-
- if (d_out->fsm.state != ST_DOUT_NORMAL)
- return;
-
- if (test_and_set_bit(buf_nr, &d_out->busy)) {
- DBG(2, "ep %d urb %d busy %#lx", EP_D_OUT, buf_nr, d_out->busy);
- return;
- }
- urb = d_out->urb[buf_nr];
-
- skb = d_out->tx_skb;
-
- buf_size = NUM_ISO_PACKETS_D * SIZE_ISO_PACKETS_D_OUT;
-
- if (skb) {
- len = isdnhdlc_encode(&d_out->hdlc_state,
- skb->data, skb->len, &bytes_sent,
- urb->transfer_buffer, buf_size);
- skb_pull(skb, bytes_sent);
- } else {
- // Send flags or idle
- len = isdnhdlc_encode(&d_out->hdlc_state,
- NULL, 0, &bytes_sent,
- urb->transfer_buffer, buf_size);
- }
-
- if (len < buf_size) {
- FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_UNDERRUN);
- }
- if (skb && !skb->len) {
- d_out->tx_skb = NULL;
- D_L1L2(adapter, PH_DATA | CONFIRM, NULL);
- dev_kfree_skb_any(skb);
- }
-
- // Prepare the URB
- urb->transfer_buffer_length = len;
- num_packets = 0;
- packet_offset = 0;
- while (packet_offset < len) {
- desc = &urb->iso_frame_desc[num_packets];
- desc->offset = packet_offset;
- desc->length = SIZE_ISO_PACKETS_D_OUT;
- if (len - packet_offset < desc->length)
- desc->length = len - packet_offset;
- num_packets++;
- packet_offset += desc->length;
- }
- urb->number_of_packets = num_packets;
-
- // Prepare the URB
- urb->dev = adapter->usb_dev;
- // Need to transmit the next buffer 2ms after the DEN_EVENT
- urb->transfer_flags = 0;
- urb->start_frame = usb_get_current_frame_number(adapter->usb_dev) + 2;
-
- DBG_ISO_PACKET(0x20, urb);
-
- if (usb_submit_urb(urb, GFP_KERNEL) < 0) {
- // There is another URB queued up
- urb->transfer_flags = URB_ISO_ASAP;
- SUBMIT_URB(urb, GFP_KERNEL);
- }
-}
-
-static void fifo_reseted(void *context)
-{
- struct st5481_adapter *adapter = context;
-
- FsmEvent(&adapter->d_out.fsm, EV_DOUT_RESETED, NULL);
-}
-
-static void usb_d_out_complete(struct urb *urb)
-{
- struct st5481_adapter *adapter = urb->context;
- struct st5481_d_out *d_out = &adapter->d_out;
- long buf_nr;
-
- DBG(2, "");
-
- buf_nr = get_buf_nr(d_out->urb, urb);
- test_and_clear_bit(buf_nr, &d_out->busy);
-
- if (unlikely(urb->status < 0)) {
- switch (urb->status) {
- case -ENOENT:
- case -ESHUTDOWN:
- case -ECONNRESET:
- DBG(1, "urb killed status %d", urb->status);
- break;
- default:
- WARNING("urb status %d", urb->status);
- if (d_out->busy == 0) {
- st5481_usb_pipe_reset(adapter, EP_D_OUT | USB_DIR_OUT, fifo_reseted, adapter);
- }
- break;
- }
- return; // Give up
- }
-
- FsmEvent(&adapter->d_out.fsm, EV_DOUT_COMPLETE, (void *) buf_nr);
-}
-
-/* ====================================================================== */
-
-static void dout_start_xmit(struct FsmInst *fsm, int event, void *arg)
-{
- // FIXME unify?
- struct st5481_adapter *adapter = fsm->userdata;
- struct st5481_d_out *d_out = &adapter->d_out;
- struct urb *urb;
- int len, bytes_sent;
- struct sk_buff *skb;
- int buf_nr = 0;
-
- skb = d_out->tx_skb;
-
- DBG(2, "len=%d", skb->len);
-
- isdnhdlc_out_init(&d_out->hdlc_state, HDLC_DCHANNEL | HDLC_BITREVERSE);
-
- if (test_and_set_bit(buf_nr, &d_out->busy)) {
- WARNING("ep %d urb %d busy %#lx", EP_D_OUT, buf_nr, d_out->busy);
- return;
- }
- urb = d_out->urb[buf_nr];
-
- DBG_SKB(0x10, skb);
- len = isdnhdlc_encode(&d_out->hdlc_state,
- skb->data, skb->len, &bytes_sent,
- urb->transfer_buffer, 16);
- skb_pull(skb, bytes_sent);
-
- if (len < 16)
- FsmChangeState(&d_out->fsm, ST_DOUT_SHORT_INIT);
- else
- FsmChangeState(&d_out->fsm, ST_DOUT_LONG_INIT);
-
- if (skb->len == 0) {
- d_out->tx_skb = NULL;
- D_L1L2(adapter, PH_DATA | CONFIRM, NULL);
- dev_kfree_skb_any(skb);
- }
-
-// Prepare the URB
- urb->transfer_buffer_length = len;
-
- urb->iso_frame_desc[0].offset = 0;
- urb->iso_frame_desc[0].length = len;
- urb->number_of_packets = 1;
-
- // Prepare the URB
- urb->dev = adapter->usb_dev;
- urb->transfer_flags = URB_ISO_ASAP;
-
- DBG_ISO_PACKET(0x20, urb);
- SUBMIT_URB(urb, GFP_KERNEL);
-}
-
-static void dout_short_fifo(struct FsmInst *fsm, int event, void *arg)
-{
- struct st5481_adapter *adapter = fsm->userdata;
- struct st5481_d_out *d_out = &adapter->d_out;
-
- FsmChangeState(&d_out->fsm, ST_DOUT_SHORT_WAIT_DEN);
- st5481_usb_device_ctrl_msg(adapter, OUT_D_COUNTER, 16, NULL, NULL);
-}
-
-static void dout_end_short_frame(struct FsmInst *fsm, int event, void *arg)
-{
- struct st5481_adapter *adapter = fsm->userdata;
- struct st5481_d_out *d_out = &adapter->d_out;
-
- FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_UNDERRUN);
-}
-
-static void dout_long_enable_fifo(struct FsmInst *fsm, int event, void *arg)
-{
- struct st5481_adapter *adapter = fsm->userdata;
- struct st5481_d_out *d_out = &adapter->d_out;
-
- st5481_usb_device_ctrl_msg(adapter, OUT_D_COUNTER, 16, NULL, NULL);
- FsmChangeState(&d_out->fsm, ST_DOUT_LONG_WAIT_DEN);
-}
-
-static void dout_long_den(struct FsmInst *fsm, int event, void *arg)
-{
- struct st5481_adapter *adapter = fsm->userdata;
- struct st5481_d_out *d_out = &adapter->d_out;
-
- FsmChangeState(&d_out->fsm, ST_DOUT_NORMAL);
- usb_d_out(adapter, 0);
- usb_d_out(adapter, 1);
-}
-
-static void dout_reset(struct FsmInst *fsm, int event, void *arg)
-{
- struct st5481_adapter *adapter = fsm->userdata;
- struct st5481_d_out *d_out = &adapter->d_out;
-
- FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_RESET);
- st5481_usb_pipe_reset(adapter, EP_D_OUT | USB_DIR_OUT, fifo_reseted, adapter);
-}
-
-static void dout_stop(struct FsmInst *fsm, int event, void *arg)
-{
- struct st5481_adapter *adapter = fsm->userdata;
- struct st5481_d_out *d_out = &adapter->d_out;
-
- FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_STOP);
- st5481_usb_device_ctrl_msg(adapter, OUT_D_COUNTER, 0, dout_stop_event, adapter);
-}
-
-static void dout_underrun(struct FsmInst *fsm, int event, void *arg)
-{
- struct st5481_adapter *adapter = fsm->userdata;
- struct st5481_d_out *d_out = &adapter->d_out;
-
- if (test_bit(0, &d_out->busy) || test_bit(1, &d_out->busy)) {
- FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_NOT_BUSY);
- } else {
- dout_stop(fsm, event, arg);
- }
-}
-
-static void dout_check_busy(struct FsmInst *fsm, int event, void *arg)
-{
- struct st5481_adapter *adapter = fsm->userdata;
- struct st5481_d_out *d_out = &adapter->d_out;
-
- if (!test_bit(0, &d_out->busy) && !test_bit(1, &d_out->busy))
- dout_stop(fsm, event, arg);
-}
-
-static void dout_reseted(struct FsmInst *fsm, int event, void *arg)
-{
- struct st5481_adapter *adapter = fsm->userdata;
- struct st5481_d_out *d_out = &adapter->d_out;
-
- FsmChangeState(&d_out->fsm, ST_DOUT_NONE);
- // FIXME locking
- if (d_out->tx_skb)
- FsmEvent(&d_out->fsm, EV_DOUT_START_XMIT, NULL);
-}
-
-static void dout_complete(struct FsmInst *fsm, int event, void *arg)
-{
- struct st5481_adapter *adapter = fsm->userdata;
- long buf_nr = (long) arg;
-
- usb_d_out(adapter, buf_nr);
-}
-
-static void dout_ignore(struct FsmInst *fsm, int event, void *arg)
-{
-}
-
-static struct FsmNode DoutFnList[] __initdata =
-{
- {ST_DOUT_NONE, EV_DOUT_START_XMIT, dout_start_xmit},
-
- {ST_DOUT_SHORT_INIT, EV_DOUT_COMPLETE, dout_short_fifo},
-
- {ST_DOUT_SHORT_WAIT_DEN, EV_DOUT_DEN, dout_end_short_frame},
- {ST_DOUT_SHORT_WAIT_DEN, EV_DOUT_UNDERRUN, dout_underrun},
-
- {ST_DOUT_LONG_INIT, EV_DOUT_COMPLETE, dout_long_enable_fifo},
-
- {ST_DOUT_LONG_WAIT_DEN, EV_DOUT_DEN, dout_long_den},
- {ST_DOUT_LONG_WAIT_DEN, EV_DOUT_UNDERRUN, dout_underrun},
-
- {ST_DOUT_NORMAL, EV_DOUT_UNDERRUN, dout_underrun},
- {ST_DOUT_NORMAL, EV_DOUT_COMPLETE, dout_complete},
-
- {ST_DOUT_WAIT_FOR_UNDERRUN, EV_DOUT_UNDERRUN, dout_underrun},
- {ST_DOUT_WAIT_FOR_UNDERRUN, EV_DOUT_COMPLETE, dout_ignore},
-
- {ST_DOUT_WAIT_FOR_NOT_BUSY, EV_DOUT_COMPLETE, dout_check_busy},
-
- {ST_DOUT_WAIT_FOR_STOP, EV_DOUT_STOPPED, dout_reset},
-
- {ST_DOUT_WAIT_FOR_RESET, EV_DOUT_RESETED, dout_reseted},
-};
-
-void st5481_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg)
-{
- struct st5481_adapter *adapter = hisax_d_if->priv;
- struct sk_buff *skb = arg;
-
- switch (pr) {
- case PH_ACTIVATE | REQUEST:
- FsmEvent(&adapter->l1m, EV_PH_ACTIVATE_REQ, NULL);
- break;
- case PH_DEACTIVATE | REQUEST:
- FsmEvent(&adapter->l1m, EV_PH_DEACTIVATE_REQ, NULL);
- break;
- case PH_DATA | REQUEST:
- DBG(2, "PH_DATA REQUEST len %d", skb->len);
- BUG_ON(adapter->d_out.tx_skb);
- adapter->d_out.tx_skb = skb;
- FsmEvent(&adapter->d_out.fsm, EV_DOUT_START_XMIT, NULL);
- break;
- default:
- WARNING("pr %#x\n", pr);
- break;
- }
-}
-
-/* ======================================================================
- */
-
-/*
- * Start receiving on the D channel since entered state F7.
- */
-static void ph_connect(struct st5481_adapter *adapter)
-{
- struct st5481_d_out *d_out = &adapter->d_out;
- struct st5481_in *d_in = &adapter->d_in;
-
- DBG(8, "");
-
- FsmChangeState(&d_out->fsm, ST_DOUT_NONE);
-
- // st5481_usb_device_ctrl_msg(adapter, FFMSK_D, OUT_UNDERRUN, NULL, NULL);
- st5481_usb_device_ctrl_msg(adapter, FFMSK_D, 0xfc, NULL, NULL);
- st5481_in_mode(d_in, L1_MODE_HDLC);
-
-#ifdef LOOPBACK
- // Turn loopback on (data sent on B and D looped back)
- st5481_usb_device_ctrl_msg(cs, LBB, 0x04, NULL, NULL);
-#endif
-
- st5481_usb_pipe_reset(adapter, EP_D_OUT | USB_DIR_OUT, NULL, NULL);
-
- // Turn on the green LED to tell that we are in state F7
- adapter->leds |= GREEN_LED;
- st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, adapter->leds, NULL, NULL);
-}
-
-/*
- * Stop receiving on the D channel since not in state F7.
- */
-static void ph_disconnect(struct st5481_adapter *adapter)
-{
- DBG(8, "");
-
- st5481_in_mode(&adapter->d_in, L1_MODE_NULL);
-
- // Turn off the green LED to tell that we left state F7
- adapter->leds &= ~GREEN_LED;
- st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, adapter->leds, NULL, NULL);
-}
-
-static int st5481_setup_d_out(struct st5481_adapter *adapter)
-{
- struct usb_device *dev = adapter->usb_dev;
- struct usb_interface *intf;
- struct usb_host_interface *altsetting = NULL;
- struct usb_host_endpoint *endpoint;
- struct st5481_d_out *d_out = &adapter->d_out;
-
- DBG(2, "");
-
- intf = usb_ifnum_to_if(dev, 0);
- if (intf)
- altsetting = usb_altnum_to_altsetting(intf, 3);
- if (!altsetting)
- return -ENXIO;
-
- // Allocate URBs and buffers for the D channel out
- endpoint = &altsetting->endpoint[EP_D_OUT-1];
-
- DBG(2, "endpoint address=%02x,packet size=%d",
- endpoint->desc.bEndpointAddress, le16_to_cpu(endpoint->desc.wMaxPacketSize));
-
- return st5481_setup_isocpipes(d_out->urb, dev,
- usb_sndisocpipe(dev, endpoint->desc.bEndpointAddress),
- NUM_ISO_PACKETS_D, SIZE_ISO_PACKETS_D_OUT,
- NUM_ISO_PACKETS_D * SIZE_ISO_PACKETS_D_OUT,
- usb_d_out_complete, adapter);
-}
-
-static void st5481_release_d_out(struct st5481_adapter *adapter)
-{
- struct st5481_d_out *d_out = &adapter->d_out;
-
- DBG(2, "");
-
- st5481_release_isocpipes(d_out->urb);
-}
-
-int st5481_setup_d(struct st5481_adapter *adapter)
-{
- int retval;
-
- DBG(2, "");
-
- retval = st5481_setup_d_out(adapter);
- if (retval)
- goto err;
- adapter->d_in.bufsize = MAX_DFRAME_LEN_L1;
- adapter->d_in.num_packets = NUM_ISO_PACKETS_D;
- adapter->d_in.packet_size = SIZE_ISO_PACKETS_D_IN;
- adapter->d_in.ep = EP_D_IN | USB_DIR_IN;
- adapter->d_in.counter = IN_D_COUNTER;
- adapter->d_in.adapter = adapter;
- adapter->d_in.hisax_if = &adapter->hisax_d_if.ifc;
- retval = st5481_setup_in(&adapter->d_in);
- if (retval)
- goto err_d_out;
-
- adapter->l1m.fsm = &l1fsm;
- adapter->l1m.state = ST_L1_F3;
- adapter->l1m.debug = st5481_debug & 0x100;
- adapter->l1m.userdata = adapter;
- adapter->l1m.printdebug = l1m_debug;
- FsmInitTimer(&adapter->l1m, &adapter->timer);
-
- adapter->d_out.fsm.fsm = &dout_fsm;
- adapter->d_out.fsm.state = ST_DOUT_NONE;
- adapter->d_out.fsm.debug = st5481_debug & 0x100;
- adapter->d_out.fsm.userdata = adapter;
- adapter->d_out.fsm.printdebug = dout_debug;
-
- return 0;
-
-err_d_out:
- st5481_release_d_out(adapter);
-err:
- return retval;
-}
-
-void st5481_release_d(struct st5481_adapter *adapter)
-{
- DBG(2, "");
-
- st5481_release_in(&adapter->d_in);
- st5481_release_d_out(adapter);
-}
-
-/* ======================================================================
- * init / exit
- */
-
-int __init st5481_d_init(void)
-{
- int retval;
-
- l1fsm.state_count = L1_STATE_COUNT;
- l1fsm.event_count = L1_EVENT_COUNT;
- l1fsm.strEvent = strL1Event;
- l1fsm.strState = strL1State;
- retval = FsmNew(&l1fsm, L1FnList, ARRAY_SIZE(L1FnList));
- if (retval)
- goto err;
-
- dout_fsm.state_count = DOUT_STATE_COUNT;
- dout_fsm.event_count = DOUT_EVENT_COUNT;
- dout_fsm.strEvent = strDoutEvent;
- dout_fsm.strState = strDoutState;
- retval = FsmNew(&dout_fsm, DoutFnList, ARRAY_SIZE(DoutFnList));
- if (retval)
- goto err_l1;
-
- return 0;
-
-err_l1:
- FsmFree(&l1fsm);
-err:
- return retval;
-}
-
-// can't be __exit
-void st5481_d_exit(void)
-{
- FsmFree(&l1fsm);
- FsmFree(&dout_fsm);
-}
diff --git a/drivers/isdn/hisax/st5481_init.c b/drivers/isdn/hisax/st5481_init.c
deleted file mode 100644
index 54ef9e4f8cbc..000000000000
--- a/drivers/isdn/hisax/st5481_init.c
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Driver for ST5481 USB ISDN modem
- *
- * Author Frode Isaksen
- * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
- * 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-/*
- * TODO:
- *
- * b layer1 delay?
- * hotplug / unregister issues
- * mod_inc/dec_use_count
- * unify parts of d/b channel usb handling
- * file header
- * avoid copy to isoc buffer?
- * improve usb delay?
- * merge l1 state machines?
- * clean up debug
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/usb.h>
-#include <linux/slab.h>
-#include "st5481.h"
-
-MODULE_DESCRIPTION("ISDN4Linux: driver for ST5481 USB ISDN adapter");
-MODULE_AUTHOR("Frode Isaksen");
-MODULE_LICENSE("GPL");
-
-static int protocol = 2; /* EURO-ISDN Default */
-module_param(protocol, int, 0);
-
-static int number_of_leds = 2; /* 2 LEDs on the adpater default */
-module_param(number_of_leds, int, 0);
-
-#ifdef CONFIG_HISAX_DEBUG
-static int debug = 0;
-module_param(debug, int, 0);
-#endif
-int st5481_debug;
-
-/* ======================================================================
- * registration/deregistration with the USB layer
- */
-
-/*
- * This function will be called when the adapter is plugged
- * into the USB bus.
- */
-static int probe_st5481(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct usb_device *dev = interface_to_usbdev(intf);
- struct st5481_adapter *adapter;
- struct hisax_b_if *b_if[2];
- int retval, i;
-
- printk(KERN_INFO "st541: found adapter VendorId %04x, ProductId %04x, LEDs %d\n",
- le16_to_cpu(dev->descriptor.idVendor),
- le16_to_cpu(dev->descriptor.idProduct),
- number_of_leds);
-
- adapter = kzalloc(sizeof(struct st5481_adapter), GFP_KERNEL);
- if (!adapter)
- return -ENOMEM;
-
- adapter->number_of_leds = number_of_leds;
- adapter->usb_dev = dev;
-
- adapter->hisax_d_if.owner = THIS_MODULE;
- adapter->hisax_d_if.ifc.priv = adapter;
- adapter->hisax_d_if.ifc.l2l1 = st5481_d_l2l1;
-
- for (i = 0; i < 2; i++) {
- adapter->bcs[i].adapter = adapter;
- adapter->bcs[i].channel = i;
- adapter->bcs[i].b_if.ifc.priv = &adapter->bcs[i];
- adapter->bcs[i].b_if.ifc.l2l1 = st5481_b_l2l1;
- }
-
- retval = st5481_setup_usb(adapter);
- if (retval < 0)
- goto err;
-
- retval = st5481_setup_d(adapter);
- if (retval < 0)
- goto err_usb;
-
- retval = st5481_setup_b(&adapter->bcs[0]);
- if (retval < 0)
- goto err_d;
-
- retval = st5481_setup_b(&adapter->bcs[1]);
- if (retval < 0)
- goto err_b;
-
- for (i = 0; i < 2; i++)
- b_if[i] = &adapter->bcs[i].b_if;
-
- if (hisax_register(&adapter->hisax_d_if, b_if, "st5481_usb",
- protocol) != 0)
- goto err_b1;
-
- st5481_start(adapter);
-
- usb_set_intfdata(intf, adapter);
- return 0;
-
-err_b1:
- st5481_release_b(&adapter->bcs[1]);
-err_b:
- st5481_release_b(&adapter->bcs[0]);
-err_d:
- st5481_release_d(adapter);
-err_usb:
- st5481_release_usb(adapter);
-err:
- kfree(adapter);
- return -EIO;
-}
-
-/*
- * This function will be called when the adapter is removed
- * from the USB bus.
- */
-static void disconnect_st5481(struct usb_interface *intf)
-{
- struct st5481_adapter *adapter = usb_get_intfdata(intf);
-
- DBG(1, "");
-
- usb_set_intfdata(intf, NULL);
- if (!adapter)
- return;
-
- st5481_stop(adapter);
- st5481_release_b(&adapter->bcs[1]);
- st5481_release_b(&adapter->bcs[0]);
- st5481_release_d(adapter);
- // we would actually better wait for completion of outstanding urbs
- mdelay(2);
- st5481_release_usb(adapter);
-
- hisax_unregister(&adapter->hisax_d_if);
-
- kfree(adapter);
-}
-
-/*
- * The last 4 bits in the Product Id is set with 4 pins on the chip.
- */
-static struct usb_device_id st5481_ids[] = {
- { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x0) },
- { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x1) },
- { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x2) },
- { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x3) },
- { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x4) },
- { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x5) },
- { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x6) },
- { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x7) },
- { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x8) },
- { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x9) },
- { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0xA) },
- { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0xB) },
- { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0xC) },
- { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0xD) },
- { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0xE) },
- { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0xF) },
- { }
-};
-MODULE_DEVICE_TABLE(usb, st5481_ids);
-
-static struct usb_driver st5481_usb_driver = {
- .name = "st5481_usb",
- .probe = probe_st5481,
- .disconnect = disconnect_st5481,
- .id_table = st5481_ids,
- .disable_hub_initiated_lpm = 1,
-};
-
-static int __init st5481_usb_init(void)
-{
- int retval;
-
-#ifdef CONFIG_HISAX_DEBUG
- st5481_debug = debug;
-#endif
-
- printk(KERN_INFO "hisax_st5481: ST5481 USB ISDN driver $Revision: 2.4.2.3 $\n");
-
- retval = st5481_d_init();
- if (retval < 0)
- goto out;
-
- retval = usb_register(&st5481_usb_driver);
- if (retval < 0)
- goto out_d_exit;
-
- return 0;
-
-out_d_exit:
- st5481_d_exit();
-out:
- return retval;
-}
-
-static void __exit st5481_usb_exit(void)
-{
- usb_deregister(&st5481_usb_driver);
- st5481_d_exit();
-}
-
-module_init(st5481_usb_init);
-module_exit(st5481_usb_exit);
diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c
deleted file mode 100644
index f207fda691c7..000000000000
--- a/drivers/isdn/hisax/st5481_usb.c
+++ /dev/null
@@ -1,659 +0,0 @@
-/*
- * Driver for ST5481 USB ISDN modem
- *
- * Author Frode Isaksen
- * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
- * 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/init.h>
-#include <linux/usb.h>
-#include <linux/slab.h>
-#include "st5481.h"
-
-static int st5481_isoc_flatten(struct urb *urb);
-
-/* ======================================================================
- * control pipe
- */
-
-/*
- * Send the next endpoint 0 request stored in the FIFO.
- * Called either by the completion or by usb_ctrl_msg.
- */
-static void usb_next_ctrl_msg(struct urb *urb,
- struct st5481_adapter *adapter)
-{
- struct st5481_ctrl *ctrl = &adapter->ctrl;
- int r_index;
-
- if (test_and_set_bit(0, &ctrl->busy)) {
- return;
- }
-
- if ((r_index = fifo_remove(&ctrl->msg_fifo.f)) < 0) {
- test_and_clear_bit(0, &ctrl->busy);
- return;
- }
- urb->setup_packet =
- (unsigned char *)&ctrl->msg_fifo.data[r_index];
-
- DBG(1, "request=0x%02x,value=0x%04x,index=%x",
- ((struct ctrl_msg *)urb->setup_packet)->dr.bRequest,
- ((struct ctrl_msg *)urb->setup_packet)->dr.wValue,
- ((struct ctrl_msg *)urb->setup_packet)->dr.wIndex);
-
- // Prepare the URB
- urb->dev = adapter->usb_dev;
-
- SUBMIT_URB(urb, GFP_ATOMIC);
-}
-
-/*
- * Asynchronous endpoint 0 request (async version of usb_control_msg).
- * The request will be queued up in a FIFO if the endpoint is busy.
- */
-static void usb_ctrl_msg(struct st5481_adapter *adapter,
- u8 request, u8 requesttype, u16 value, u16 index,
- ctrl_complete_t complete, void *context)
-{
- struct st5481_ctrl *ctrl = &adapter->ctrl;
- int w_index;
- struct ctrl_msg *ctrl_msg;
-
- if ((w_index = fifo_add(&ctrl->msg_fifo.f)) < 0) {
- WARNING("control msg FIFO full");
- return;
- }
- ctrl_msg = &ctrl->msg_fifo.data[w_index];
-
- ctrl_msg->dr.bRequestType = requesttype;
- ctrl_msg->dr.bRequest = request;
- ctrl_msg->dr.wValue = cpu_to_le16p(&value);
- ctrl_msg->dr.wIndex = cpu_to_le16p(&index);
- ctrl_msg->dr.wLength = 0;
- ctrl_msg->complete = complete;
- ctrl_msg->context = context;
-
- usb_next_ctrl_msg(ctrl->urb, adapter);
-}
-
-/*
- * Asynchronous endpoint 0 device request.
- */
-void st5481_usb_device_ctrl_msg(struct st5481_adapter *adapter,
- u8 request, u16 value,
- ctrl_complete_t complete, void *context)
-{
- usb_ctrl_msg(adapter, request,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- value, 0, complete, context);
-}
-
-/*
- * Asynchronous pipe reset (async version of usb_clear_halt).
- */
-void st5481_usb_pipe_reset(struct st5481_adapter *adapter,
- u_char pipe,
- ctrl_complete_t complete, void *context)
-{
- DBG(1, "pipe=%02x", pipe);
-
- usb_ctrl_msg(adapter,
- USB_REQ_CLEAR_FEATURE, USB_DIR_OUT | USB_RECIP_ENDPOINT,
- 0, pipe, complete, context);
-}
-
-
-/*
- Physical level functions
-*/
-
-void st5481_ph_command(struct st5481_adapter *adapter, unsigned int command)
-{
- DBG(8, "command=%s", ST5481_CMD_string(command));
-
- st5481_usb_device_ctrl_msg(adapter, TXCI, command, NULL, NULL);
-}
-
-/*
- * The request on endpoint 0 has completed.
- * Call the user provided completion routine and try
- * to send the next request.
- */
-static void usb_ctrl_complete(struct urb *urb)
-{
- struct st5481_adapter *adapter = urb->context;
- struct st5481_ctrl *ctrl = &adapter->ctrl;
- struct ctrl_msg *ctrl_msg;
-
- if (unlikely(urb->status < 0)) {
- switch (urb->status) {
- case -ENOENT:
- case -ESHUTDOWN:
- case -ECONNRESET:
- DBG(1, "urb killed status %d", urb->status);
- return; // Give up
- default:
- WARNING("urb status %d", urb->status);
- break;
- }
- }
-
- ctrl_msg = (struct ctrl_msg *)urb->setup_packet;
-
- if (ctrl_msg->dr.bRequest == USB_REQ_CLEAR_FEATURE) {
- /* Special case handling for pipe reset */
- le16_to_cpus(&ctrl_msg->dr.wIndex);
- usb_reset_endpoint(adapter->usb_dev, ctrl_msg->dr.wIndex);
- }
-
- if (ctrl_msg->complete)
- ctrl_msg->complete(ctrl_msg->context);
-
- clear_bit(0, &ctrl->busy);
-
- // Try to send next control message
- usb_next_ctrl_msg(urb, adapter);
- return;
-}
-
-/* ======================================================================
- * interrupt pipe
- */
-
-/*
- * The interrupt endpoint will be called when any
- * of the 6 registers changes state (depending on masks).
- * Decode the register values and schedule a private event.
- * Called at interrupt.
- */
-static void usb_int_complete(struct urb *urb)
-{
- u8 *data = urb->transfer_buffer;
- u8 irqbyte;
- struct st5481_adapter *adapter = urb->context;
- int j;
- int status;
-
- switch (urb->status) {
- case 0:
- /* success */
- break;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- /* this urb is terminated, clean up */
- DBG(2, "urb shutting down with status: %d", urb->status);
- return;
- default:
- WARNING("nonzero urb status received: %d", urb->status);
- goto exit;
- }
-
-
- DBG_PACKET(2, data, INT_PKT_SIZE);
-
- if (urb->actual_length == 0) {
- goto exit;
- }
-
- irqbyte = data[MPINT];
- if (irqbyte & DEN_INT)
- FsmEvent(&adapter->d_out.fsm, EV_DOUT_DEN, NULL);
-
- if (irqbyte & DCOLL_INT)
- FsmEvent(&adapter->d_out.fsm, EV_DOUT_COLL, NULL);
-
- irqbyte = data[FFINT_D];
- if (irqbyte & OUT_UNDERRUN)
- FsmEvent(&adapter->d_out.fsm, EV_DOUT_UNDERRUN, NULL);
-
- if (irqbyte & OUT_DOWN)
- ;// printk("OUT_DOWN\n");
-
- irqbyte = data[MPINT];
- if (irqbyte & RXCI_INT)
- FsmEvent(&adapter->l1m, data[CCIST] & 0x0f, NULL);
-
- for (j = 0; j < 2; j++)
- adapter->bcs[j].b_out.flow_event |= data[FFINT_B1 + j];
-
- urb->actual_length = 0;
-
-exit:
- status = usb_submit_urb(urb, GFP_ATOMIC);
- if (status)
- WARNING("usb_submit_urb failed with result %d", status);
-}
-
-/* ======================================================================
- * initialization
- */
-
-int st5481_setup_usb(struct st5481_adapter *adapter)
-{
- struct usb_device *dev = adapter->usb_dev;
- struct st5481_ctrl *ctrl = &adapter->ctrl;
- struct st5481_intr *intr = &adapter->intr;
- struct usb_interface *intf;
- struct usb_host_interface *altsetting = NULL;
- struct usb_host_endpoint *endpoint;
- int status;
- struct urb *urb;
- u8 *buf;
-
- DBG(2, "");
-
- if ((status = usb_reset_configuration(dev)) < 0) {
- WARNING("reset_configuration failed,status=%d", status);
- return status;
- }
-
- intf = usb_ifnum_to_if(dev, 0);
- if (intf)
- altsetting = usb_altnum_to_altsetting(intf, 3);
- if (!altsetting)
- return -ENXIO;
-
- // Check if the config is sane
- if (altsetting->desc.bNumEndpoints != 7) {
- WARNING("expecting 7 got %d endpoints!", altsetting->desc.bNumEndpoints);
- return -EINVAL;
- }
-
- // The descriptor is wrong for some early samples of the ST5481 chip
- altsetting->endpoint[3].desc.wMaxPacketSize = cpu_to_le16(32);
- altsetting->endpoint[4].desc.wMaxPacketSize = cpu_to_le16(32);
-
- // Use alternative setting 3 on interface 0 to have 2B+D
- if ((status = usb_set_interface(dev, 0, 3)) < 0) {
- WARNING("usb_set_interface failed,status=%d", status);
- return status;
- }
-
- // Allocate URB for control endpoint
- urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb) {
- return -ENOMEM;
- }
- ctrl->urb = urb;
-
- // Fill the control URB
- usb_fill_control_urb(urb, dev,
- usb_sndctrlpipe(dev, 0),
- NULL, NULL, 0, usb_ctrl_complete, adapter);
-
-
- fifo_init(&ctrl->msg_fifo.f, ARRAY_SIZE(ctrl->msg_fifo.data));
-
- // Allocate URBs and buffers for interrupt endpoint
- urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb) {
- goto err1;
- }
- intr->urb = urb;
-
- buf = kmalloc(INT_PKT_SIZE, GFP_KERNEL);
- if (!buf) {
- goto err2;
- }
-
- endpoint = &altsetting->endpoint[EP_INT-1];
-
- // Fill the interrupt URB
- usb_fill_int_urb(urb, dev,
- usb_rcvintpipe(dev, endpoint->desc.bEndpointAddress),
- buf, INT_PKT_SIZE,
- usb_int_complete, adapter,
- endpoint->desc.bInterval);
-
- return 0;
-err2:
- usb_free_urb(intr->urb);
- intr->urb = NULL;
-err1:
- usb_free_urb(ctrl->urb);
- ctrl->urb = NULL;
-
- return -ENOMEM;
-}
-
-/*
- * Release buffers and URBs for the interrupt and control
- * endpoint.
- */
-void st5481_release_usb(struct st5481_adapter *adapter)
-{
- struct st5481_intr *intr = &adapter->intr;
- struct st5481_ctrl *ctrl = &adapter->ctrl;
-
- DBG(1, "");
-
- // Stop and free Control and Interrupt URBs
- usb_kill_urb(ctrl->urb);
- kfree(ctrl->urb->transfer_buffer);
- usb_free_urb(ctrl->urb);
- ctrl->urb = NULL;
-
- usb_kill_urb(intr->urb);
- kfree(intr->urb->transfer_buffer);
- usb_free_urb(intr->urb);
- intr->urb = NULL;
-}
-
-/*
- * Initialize the adapter.
- */
-void st5481_start(struct st5481_adapter *adapter)
-{
- static const u8 init_cmd_table[] = {
- SET_DEFAULT, 0,
- STT, 0,
- SDA_MIN, 0x0d,
- SDA_MAX, 0x29,
- SDELAY_VALUE, 0x14,
- GPIO_DIR, 0x01,
- GPIO_OUT, RED_LED,
-// FFCTRL_OUT_D,4,
-// FFCTRH_OUT_D,12,
- FFCTRL_OUT_B1, 6,
- FFCTRH_OUT_B1, 20,
- FFCTRL_OUT_B2, 6,
- FFCTRH_OUT_B2, 20,
- MPMSK, RXCI_INT + DEN_INT + DCOLL_INT,
- 0
- };
- struct st5481_intr *intr = &adapter->intr;
- int i = 0;
- u8 request, value;
-
- DBG(8, "");
-
- adapter->leds = RED_LED;
-
- // Start receiving on the interrupt endpoint
- SUBMIT_URB(intr->urb, GFP_KERNEL);
-
- while ((request = init_cmd_table[i++])) {
- value = init_cmd_table[i++];
- st5481_usb_device_ctrl_msg(adapter, request, value, NULL, NULL);
- }
- st5481_ph_command(adapter, ST5481_CMD_PUP);
-}
-
-/*
- * Reset the adapter to default values.
- */
-void st5481_stop(struct st5481_adapter *adapter)
-{
- DBG(8, "");
-
- st5481_usb_device_ctrl_msg(adapter, SET_DEFAULT, 0, NULL, NULL);
-}
-
-/* ======================================================================
- * isochronous USB helpers
- */
-
-static void
-fill_isoc_urb(struct urb *urb, struct usb_device *dev,
- unsigned int pipe, void *buf, int num_packets,
- int packet_size, usb_complete_t complete,
- void *context)
-{
- int k;
-
- usb_fill_int_urb(urb, dev, pipe, buf, num_packets * packet_size,
- complete, context, 1);
-
- urb->number_of_packets = num_packets;
- urb->transfer_flags = URB_ISO_ASAP;
- for (k = 0; k < num_packets; k++) {
- urb->iso_frame_desc[k].offset = packet_size * k;
- urb->iso_frame_desc[k].length = packet_size;
- urb->iso_frame_desc[k].actual_length = 0;
- }
-}
-
-int
-st5481_setup_isocpipes(struct urb *urb[2], struct usb_device *dev,
- unsigned int pipe, int num_packets,
- int packet_size, int buf_size,
- usb_complete_t complete, void *context)
-{
- int j, retval;
- unsigned char *buf;
-
- for (j = 0; j < 2; j++) {
- retval = -ENOMEM;
- urb[j] = usb_alloc_urb(num_packets, GFP_KERNEL);
- if (!urb[j])
- goto err;
-
- // Allocate memory for 2000bytes/sec (16Kb/s)
- buf = kmalloc(buf_size, GFP_KERNEL);
- if (!buf)
- goto err;
-
- // Fill the isochronous URB
- fill_isoc_urb(urb[j], dev, pipe, buf,
- num_packets, packet_size, complete,
- context);
- }
- return 0;
-
-err:
- for (j = 0; j < 2; j++) {
- if (urb[j]) {
- kfree(urb[j]->transfer_buffer);
- urb[j]->transfer_buffer = NULL;
- usb_free_urb(urb[j]);
- urb[j] = NULL;
- }
- }
- return retval;
-}
-
-void st5481_release_isocpipes(struct urb *urb[2])
-{
- int j;
-
- for (j = 0; j < 2; j++) {
- usb_kill_urb(urb[j]);
- kfree(urb[j]->transfer_buffer);
- usb_free_urb(urb[j]);
- urb[j] = NULL;
- }
-}
-
-/*
- * Decode frames received on the B/D channel.
- * Note that this function will be called continuously
- * with 64Kbit/s / 16Kbit/s of data and hence it will be
- * called 50 times per second with 20 ISOC descriptors.
- * Called at interrupt.
- */
-static void usb_in_complete(struct urb *urb)
-{
- struct st5481_in *in = urb->context;
- unsigned char *ptr;
- struct sk_buff *skb;
- int len, count, status;
-
- if (unlikely(urb->status < 0)) {
- switch (urb->status) {
- case -ENOENT:
- case -ESHUTDOWN:
- case -ECONNRESET:
- DBG(1, "urb killed status %d", urb->status);
- return; // Give up
- default:
- WARNING("urb status %d", urb->status);
- break;
- }
- }
-
- DBG_ISO_PACKET(0x80, urb);
-
- len = st5481_isoc_flatten(urb);
- ptr = urb->transfer_buffer;
- while (len > 0) {
- if (in->mode == L1_MODE_TRANS) {
- memcpy(in->rcvbuf, ptr, len);
- status = len;
- len = 0;
- } else {
- status = isdnhdlc_decode(&in->hdlc_state, ptr, len, &count,
- in->rcvbuf, in->bufsize);
- ptr += count;
- len -= count;
- }
-
- if (status > 0) {
- // Good frame received
- DBG(4, "count=%d", status);
- DBG_PACKET(0x400, in->rcvbuf, status);
- if (!(skb = dev_alloc_skb(status))) {
- WARNING("receive out of memory\n");
- break;
- }
- skb_put_data(skb, in->rcvbuf, status);
- in->hisax_if->l1l2(in->hisax_if, PH_DATA | INDICATION, skb);
- } else if (status == -HDLC_CRC_ERROR) {
- INFO("CRC error");
- } else if (status == -HDLC_FRAMING_ERROR) {
- INFO("framing error");
- } else if (status == -HDLC_LENGTH_ERROR) {
- INFO("length error");
- }
- }
-
- // Prepare URB for next transfer
- urb->dev = in->adapter->usb_dev;
- urb->actual_length = 0;
-
- SUBMIT_URB(urb, GFP_ATOMIC);
-}
-
-int st5481_setup_in(struct st5481_in *in)
-{
- struct usb_device *dev = in->adapter->usb_dev;
- int retval;
-
- DBG(4, "");
-
- in->rcvbuf = kmalloc(in->bufsize, GFP_KERNEL);
- retval = -ENOMEM;
- if (!in->rcvbuf)
- goto err;
-
- retval = st5481_setup_isocpipes(in->urb, dev,
- usb_rcvisocpipe(dev, in->ep),
- in->num_packets, in->packet_size,
- in->num_packets * in->packet_size,
- usb_in_complete, in);
- if (retval)
- goto err_free;
- return 0;
-
-err_free:
- kfree(in->rcvbuf);
-err:
- return retval;
-}
-
-void st5481_release_in(struct st5481_in *in)
-{
- DBG(2, "");
-
- st5481_release_isocpipes(in->urb);
-}
-
-/*
- * Make the transfer_buffer contiguous by
- * copying from the iso descriptors if necessary.
- */
-static int st5481_isoc_flatten(struct urb *urb)
-{
- struct usb_iso_packet_descriptor *pipd, *pend;
- unsigned char *src, *dst;
- unsigned int len;
-
- if (urb->status < 0) {
- return urb->status;
- }
- for (pipd = &urb->iso_frame_desc[0],
- pend = &urb->iso_frame_desc[urb->number_of_packets],
- dst = urb->transfer_buffer;
- pipd < pend;
- pipd++) {
-
- if (pipd->status < 0) {
- return (pipd->status);
- }
-
- len = pipd->actual_length;
- pipd->actual_length = 0;
- src = urb->transfer_buffer + pipd->offset;
-
- if (src != dst) {
- // Need to copy since isoc buffers not full
- while (len--) {
- *dst++ = *src++;
- }
- } else {
- // No need to copy, just update destination buffer
- dst += len;
- }
- }
- // Return size of flattened buffer
- return (dst - (unsigned char *)urb->transfer_buffer);
-}
-
-static void st5481_start_rcv(void *context)
-{
- struct st5481_in *in = context;
- struct st5481_adapter *adapter = in->adapter;
-
- DBG(4, "");
-
- in->urb[0]->dev = adapter->usb_dev;
- SUBMIT_URB(in->urb[0], GFP_KERNEL);
-
- in->urb[1]->dev = adapter->usb_dev;
- SUBMIT_URB(in->urb[1], GFP_KERNEL);
-}
-
-void st5481_in_mode(struct st5481_in *in, int mode)
-{
- if (in->mode == mode)
- return;
-
- in->mode = mode;
-
- usb_unlink_urb(in->urb[0]);
- usb_unlink_urb(in->urb[1]);
-
- if (in->mode != L1_MODE_NULL) {
- if (in->mode != L1_MODE_TRANS) {
- u32 features = HDLC_BITREVERSE;
-
- if (in->mode == L1_MODE_HDLC_56K)
- features |= HDLC_56KBIT;
- isdnhdlc_rcv_init(&in->hdlc_state, features);
- }
- st5481_usb_pipe_reset(in->adapter, in->ep, NULL, NULL);
- st5481_usb_device_ctrl_msg(in->adapter, in->counter,
- in->packet_size,
- NULL, NULL);
- st5481_start_rcv(in);
- } else {
- st5481_usb_device_ctrl_msg(in->adapter, in->counter,
- 0, NULL, NULL);
- }
-}
diff --git a/drivers/isdn/hisax/tei.c b/drivers/isdn/hisax/tei.c
deleted file mode 100644
index 9195f9fd628f..000000000000
--- a/drivers/isdn/hisax/tei.c
+++ /dev/null
@@ -1,465 +0,0 @@
-/* $Id: tei.c,v 2.20.2.3 2004/01/13 14:31:26 keil Exp $
- *
- * Author Karsten Keil
- * based on the teles driver from Jan den Ouden
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * For changes and modifications please read
- * Documentation/isdn/HiSax.cert
- *
- * Thanks to Jan den Ouden
- * Fritz Elfert
- *
- */
-
-#include "hisax.h"
-#include "isdnl2.h"
-#include <linux/gfp.h>
-#include <linux/init.h>
-#include <linux/random.h>
-
-const char *tei_revision = "$Revision: 2.20.2.3 $";
-
-#define ID_REQUEST 1
-#define ID_ASSIGNED 2
-#define ID_DENIED 3
-#define ID_CHK_REQ 4
-#define ID_CHK_RES 5
-#define ID_REMOVE 6
-#define ID_VERIFY 7
-
-#define TEI_ENTITY_ID 0xf
-
-static struct Fsm teifsm;
-
-void tei_handler(struct PStack *st, u_char pr, struct sk_buff *skb);
-
-enum {
- ST_TEI_NOP,
- ST_TEI_IDREQ,
- ST_TEI_IDVERIFY,
-};
-
-#define TEI_STATE_COUNT (ST_TEI_IDVERIFY + 1)
-
-static char *strTeiState[] =
-{
- "ST_TEI_NOP",
- "ST_TEI_IDREQ",
- "ST_TEI_IDVERIFY",
-};
-
-enum {
- EV_IDREQ,
- EV_ASSIGN,
- EV_DENIED,
- EV_CHKREQ,
- EV_REMOVE,
- EV_VERIFY,
- EV_T202,
-};
-
-#define TEI_EVENT_COUNT (EV_T202 + 1)
-
-static char *strTeiEvent[] =
-{
- "EV_IDREQ",
- "EV_ASSIGN",
- "EV_DENIED",
- "EV_CHKREQ",
- "EV_REMOVE",
- "EV_VERIFY",
- "EV_T202",
-};
-
-static unsigned int
-random_ri(void)
-{
- unsigned int x;
-
- get_random_bytes(&x, sizeof(x));
- return (x & 0xffff);
-}
-
-static struct PStack *
-findtei(struct PStack *st, int tei)
-{
- struct PStack *ptr = *(st->l1.stlistp);
-
- if (tei == 127)
- return (NULL);
-
- while (ptr)
- if (ptr->l2.tei == tei)
- return (ptr);
- else
- ptr = ptr->next;
- return (NULL);
-}
-
-static void
-put_tei_msg(struct PStack *st, u_char m_id, unsigned int ri, u_char tei)
-{
- struct sk_buff *skb;
- u_char *bp;
-
- if (!(skb = alloc_skb(8, GFP_ATOMIC))) {
- printk(KERN_WARNING "HiSax: No skb for TEI manager\n");
- return;
- }
- bp = skb_put(skb, 3);
- bp[0] = (TEI_SAPI << 2);
- bp[1] = (GROUP_TEI << 1) | 0x1;
- bp[2] = UI;
- bp = skb_put(skb, 5);
- bp[0] = TEI_ENTITY_ID;
- bp[1] = ri >> 8;
- bp[2] = ri & 0xff;
- bp[3] = m_id;
- bp[4] = (tei << 1) | 1;
- st->l2.l2l1(st, PH_DATA | REQUEST, skb);
-}
-
-static void
-tei_id_request(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- if (st->l2.tei != -1) {
- st->ma.tei_m.printdebug(&st->ma.tei_m,
- "assign request for already assigned tei %d",
- st->l2.tei);
- return;
- }
- st->ma.ri = random_ri();
- if (st->ma.debug)
- st->ma.tei_m.printdebug(&st->ma.tei_m,
- "assign request ri %d", st->ma.ri);
- put_tei_msg(st, ID_REQUEST, st->ma.ri, 127);
- FsmChangeState(&st->ma.tei_m, ST_TEI_IDREQ);
- FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 1);
- st->ma.N202 = 3;
-}
-
-static void
-tei_id_assign(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *ost, *st = fi->userdata;
- struct sk_buff *skb = arg;
- struct IsdnCardState *cs;
- int ri, tei;
-
- ri = ((unsigned int) skb->data[1] << 8) + skb->data[2];
- tei = skb->data[4] >> 1;
- if (st->ma.debug)
- st->ma.tei_m.printdebug(&st->ma.tei_m,
- "identity assign ri %d tei %d", ri, tei);
- if ((ost = findtei(st, tei))) { /* same tei is in use */
- if (ri != ost->ma.ri) {
- st->ma.tei_m.printdebug(&st->ma.tei_m,
- "possible duplicate assignment tei %d", tei);
- ost->l2.l2tei(ost, MDL_ERROR | RESPONSE, NULL);
- }
- } else if (ri == st->ma.ri) {
- FsmDelTimer(&st->ma.t202, 1);
- FsmChangeState(&st->ma.tei_m, ST_TEI_NOP);
- st->l3.l3l2(st, MDL_ASSIGN | REQUEST, (void *) (long) tei);
- cs = (struct IsdnCardState *) st->l1.hardware;
- cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL);
- }
-}
-
-static void
-tei_id_test_dup(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *ost, *st = fi->userdata;
- struct sk_buff *skb = arg;
- int tei, ri;
-
- ri = ((unsigned int) skb->data[1] << 8) + skb->data[2];
- tei = skb->data[4] >> 1;
- if (st->ma.debug)
- st->ma.tei_m.printdebug(&st->ma.tei_m,
- "foreign identity assign ri %d tei %d", ri, tei);
- if ((ost = findtei(st, tei))) { /* same tei is in use */
- if (ri != ost->ma.ri) { /* and it wasn't our request */
- st->ma.tei_m.printdebug(&st->ma.tei_m,
- "possible duplicate assignment tei %d", tei);
- FsmEvent(&ost->ma.tei_m, EV_VERIFY, NULL);
- }
- }
-}
-
-static void
-tei_id_denied(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
- int ri, tei;
-
- ri = ((unsigned int) skb->data[1] << 8) + skb->data[2];
- tei = skb->data[4] >> 1;
- if (st->ma.debug)
- st->ma.tei_m.printdebug(&st->ma.tei_m,
- "identity denied ri %d tei %d", ri, tei);
-}
-
-static void
-tei_id_chk_req(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
- int tei;
-
- tei = skb->data[4] >> 1;
- if (st->ma.debug)
- st->ma.tei_m.printdebug(&st->ma.tei_m,
- "identity check req tei %d", tei);
- if ((st->l2.tei != -1) && ((tei == GROUP_TEI) || (tei == st->l2.tei))) {
- FsmDelTimer(&st->ma.t202, 4);
- FsmChangeState(&st->ma.tei_m, ST_TEI_NOP);
- put_tei_msg(st, ID_CHK_RES, random_ri(), st->l2.tei);
- }
-}
-
-static void
-tei_id_remove(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct sk_buff *skb = arg;
- struct IsdnCardState *cs;
- int tei;
-
- tei = skb->data[4] >> 1;
- if (st->ma.debug)
- st->ma.tei_m.printdebug(&st->ma.tei_m,
- "identity remove tei %d", tei);
- if ((st->l2.tei != -1) && ((tei == GROUP_TEI) || (tei == st->l2.tei))) {
- FsmDelTimer(&st->ma.t202, 5);
- FsmChangeState(&st->ma.tei_m, ST_TEI_NOP);
- st->l3.l3l2(st, MDL_REMOVE | REQUEST, NULL);
- cs = (struct IsdnCardState *) st->l1.hardware;
- cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL);
- }
-}
-
-static void
-tei_id_verify(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- if (st->ma.debug)
- st->ma.tei_m.printdebug(&st->ma.tei_m,
- "id verify request for tei %d", st->l2.tei);
- put_tei_msg(st, ID_VERIFY, 0, st->l2.tei);
- FsmChangeState(&st->ma.tei_m, ST_TEI_IDVERIFY);
- FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 2);
- st->ma.N202 = 2;
-}
-
-static void
-tei_id_req_tout(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct IsdnCardState *cs;
-
- if (--st->ma.N202) {
- st->ma.ri = random_ri();
- if (st->ma.debug)
- st->ma.tei_m.printdebug(&st->ma.tei_m,
- "assign req(%d) ri %d", 4 - st->ma.N202,
- st->ma.ri);
- put_tei_msg(st, ID_REQUEST, st->ma.ri, 127);
- FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 3);
- } else {
- st->ma.tei_m.printdebug(&st->ma.tei_m, "assign req failed");
- st->l3.l3l2(st, MDL_ERROR | RESPONSE, NULL);
- cs = (struct IsdnCardState *) st->l1.hardware;
- cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL);
- FsmChangeState(fi, ST_TEI_NOP);
- }
-}
-
-static void
-tei_id_ver_tout(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct IsdnCardState *cs;
-
- if (--st->ma.N202) {
- if (st->ma.debug)
- st->ma.tei_m.printdebug(&st->ma.tei_m,
- "id verify req(%d) for tei %d",
- 3 - st->ma.N202, st->l2.tei);
- put_tei_msg(st, ID_VERIFY, 0, st->l2.tei);
- FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 4);
- } else {
- st->ma.tei_m.printdebug(&st->ma.tei_m,
- "verify req for tei %d failed", st->l2.tei);
- st->l3.l3l2(st, MDL_REMOVE | REQUEST, NULL);
- cs = (struct IsdnCardState *) st->l1.hardware;
- cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL);
- FsmChangeState(fi, ST_TEI_NOP);
- }
-}
-
-static void
-tei_l1l2(struct PStack *st, int pr, void *arg)
-{
- struct sk_buff *skb = arg;
- int mt;
-
- if (test_bit(FLG_FIXED_TEI, &st->l2.flag)) {
- dev_kfree_skb(skb);
- return;
- }
-
- if (pr == (PH_DATA | INDICATION)) {
- if (skb->len < 3) {
- st->ma.tei_m.printdebug(&st->ma.tei_m,
- "short mgr frame %ld/3", skb->len);
- } else if ((skb->data[0] != ((TEI_SAPI << 2) | 2)) ||
- (skb->data[1] != ((GROUP_TEI << 1) | 1))) {
- st->ma.tei_m.printdebug(&st->ma.tei_m,
- "wrong mgr sapi/tei %x/%x",
- skb->data[0], skb->data[1]);
- } else if ((skb->data[2] & 0xef) != UI) {
- st->ma.tei_m.printdebug(&st->ma.tei_m,
- "mgr frame is not ui %x", skb->data[2]);
- } else {
- skb_pull(skb, 3);
- if (skb->len < 5) {
- st->ma.tei_m.printdebug(&st->ma.tei_m,
- "short mgr frame %ld/5", skb->len);
- } else if (skb->data[0] != TEI_ENTITY_ID) {
- /* wrong management entity identifier, ignore */
- st->ma.tei_m.printdebug(&st->ma.tei_m,
- "tei handler wrong entity id %x",
- skb->data[0]);
- } else {
- mt = skb->data[3];
- if (mt == ID_ASSIGNED)
- FsmEvent(&st->ma.tei_m, EV_ASSIGN, skb);
- else if (mt == ID_DENIED)
- FsmEvent(&st->ma.tei_m, EV_DENIED, skb);
- else if (mt == ID_CHK_REQ)
- FsmEvent(&st->ma.tei_m, EV_CHKREQ, skb);
- else if (mt == ID_REMOVE)
- FsmEvent(&st->ma.tei_m, EV_REMOVE, skb);
- else {
- st->ma.tei_m.printdebug(&st->ma.tei_m,
- "tei handler wrong mt %x\n", mt);
- }
- }
- }
- } else {
- st->ma.tei_m.printdebug(&st->ma.tei_m,
- "tei handler wrong pr %x\n", pr);
- }
- dev_kfree_skb(skb);
-}
-
-static void
-tei_l2tei(struct PStack *st, int pr, void *arg)
-{
- struct IsdnCardState *cs;
-
- if (test_bit(FLG_FIXED_TEI, &st->l2.flag)) {
- if (pr == (MDL_ASSIGN | INDICATION)) {
- if (st->ma.debug)
- st->ma.tei_m.printdebug(&st->ma.tei_m,
- "fixed assign tei %d", st->l2.tei);
- st->l3.l3l2(st, MDL_ASSIGN | REQUEST, (void *) (long) st->l2.tei);
- cs = (struct IsdnCardState *) st->l1.hardware;
- cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL);
- }
- return;
- }
- switch (pr) {
- case (MDL_ASSIGN | INDICATION):
- FsmEvent(&st->ma.tei_m, EV_IDREQ, arg);
- break;
- case (MDL_ERROR | REQUEST):
- FsmEvent(&st->ma.tei_m, EV_VERIFY, arg);
- break;
- default:
- break;
- }
-}
-
-static void
-tei_debug(struct FsmInst *fi, char *fmt, ...)
-{
- va_list args;
- struct PStack *st = fi->userdata;
-
- va_start(args, fmt);
- VHiSax_putstatus(st->l1.hardware, "tei ", fmt, args);
- va_end(args);
-}
-
-void
-setstack_tei(struct PStack *st)
-{
- st->l2.l2tei = tei_l2tei;
- st->ma.T202 = 2000; /* T202 2000 milliseconds */
- st->l1.l1tei = tei_l1l2;
- st->ma.debug = 1;
- st->ma.tei_m.fsm = &teifsm;
- st->ma.tei_m.state = ST_TEI_NOP;
- st->ma.tei_m.debug = 1;
- st->ma.tei_m.userdata = st;
- st->ma.tei_m.userint = 0;
- st->ma.tei_m.printdebug = tei_debug;
- FsmInitTimer(&st->ma.tei_m, &st->ma.t202);
-}
-
-void
-init_tei(struct IsdnCardState *cs, int protocol)
-{
-}
-
-void
-release_tei(struct IsdnCardState *cs)
-{
- struct PStack *st = cs->stlist;
-
- while (st) {
- FsmDelTimer(&st->ma.t202, 1);
- st = st->next;
- }
-}
-
-static struct FsmNode TeiFnList[] __initdata =
-{
- {ST_TEI_NOP, EV_IDREQ, tei_id_request},
- {ST_TEI_NOP, EV_ASSIGN, tei_id_test_dup},
- {ST_TEI_NOP, EV_VERIFY, tei_id_verify},
- {ST_TEI_NOP, EV_REMOVE, tei_id_remove},
- {ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req},
- {ST_TEI_IDREQ, EV_T202, tei_id_req_tout},
- {ST_TEI_IDREQ, EV_ASSIGN, tei_id_assign},
- {ST_TEI_IDREQ, EV_DENIED, tei_id_denied},
- {ST_TEI_IDVERIFY, EV_T202, tei_id_ver_tout},
- {ST_TEI_IDVERIFY, EV_REMOVE, tei_id_remove},
- {ST_TEI_IDVERIFY, EV_CHKREQ, tei_id_chk_req},
-};
-
-int __init
-TeiNew(void)
-{
- teifsm.state_count = TEI_STATE_COUNT;
- teifsm.event_count = TEI_EVENT_COUNT;
- teifsm.strEvent = strTeiEvent;
- teifsm.strState = strTeiState;
- return FsmNew(&teifsm, TeiFnList, ARRAY_SIZE(TeiFnList));
-}
-
-void
-TeiFree(void)
-{
- FsmFree(&teifsm);
-}
diff --git a/drivers/isdn/hisax/teleint.c b/drivers/isdn/hisax/teleint.c
deleted file mode 100644
index 247aa33076b1..000000000000
--- a/drivers/isdn/hisax/teleint.c
+++ /dev/null
@@ -1,334 +0,0 @@
-/* $Id: teleint.c,v 1.16.2.5 2004/01/19 15:31:50 keil Exp $
- *
- * low level stuff for TeleInt isdn cards
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/init.h>
-#include "hisax.h"
-#include "isac.h"
-#include "hfc_2bs0.h"
-#include "isdnl1.h"
-
-static const char *TeleInt_revision = "$Revision: 1.16.2.5 $";
-
-#define byteout(addr, val) outb(val, addr)
-#define bytein(addr) inb(addr)
-
-static inline u_char
-readreg(unsigned int ale, unsigned int adr, u_char off)
-{
- register u_char ret;
- int max_delay = 2000;
-
- byteout(ale, off);
- ret = HFC_BUSY & bytein(ale);
- while (ret && --max_delay)
- ret = HFC_BUSY & bytein(ale);
- if (!max_delay) {
- printk(KERN_WARNING "TeleInt Busy not inactive\n");
- return (0);
- }
- ret = bytein(adr);
- return (ret);
-}
-
-static inline void
-readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
-{
- register u_char ret;
- register int max_delay = 20000;
- register int i;
-
- byteout(ale, off);
- for (i = 0; i < size; i++) {
- ret = HFC_BUSY & bytein(ale);
- while (ret && --max_delay)
- ret = HFC_BUSY & bytein(ale);
- if (!max_delay) {
- printk(KERN_WARNING "TeleInt Busy not inactive\n");
- return;
- }
- data[i] = bytein(adr);
- }
-}
-
-
-static inline void
-writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
-{
- register u_char ret;
- int max_delay = 2000;
-
- byteout(ale, off);
- ret = HFC_BUSY & bytein(ale);
- while (ret && --max_delay)
- ret = HFC_BUSY & bytein(ale);
- if (!max_delay) {
- printk(KERN_WARNING "TeleInt Busy not inactive\n");
- return;
- }
- byteout(adr, data);
-}
-
-static inline void
-writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
-{
- register u_char ret;
- register int max_delay = 20000;
- register int i;
-
- byteout(ale, off);
- for (i = 0; i < size; i++) {
- ret = HFC_BUSY & bytein(ale);
- while (ret && --max_delay)
- ret = HFC_BUSY & bytein(ale);
- if (!max_delay) {
- printk(KERN_WARNING "TeleInt Busy not inactive\n");
- return;
- }
- byteout(adr, data[i]);
- }
-}
-
-/* Interface functions */
-
-static u_char
-ReadISAC(struct IsdnCardState *cs, u_char offset)
-{
- cs->hw.hfc.cip = offset;
- return (readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, offset));
-}
-
-static void
-WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
-{
- cs->hw.hfc.cip = offset;
- writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, offset, value);
-}
-
-static void
-ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- cs->hw.hfc.cip = 0;
- readfifo(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, 0, data, size);
-}
-
-static void
-WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- cs->hw.hfc.cip = 0;
- writefifo(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, 0, data, size);
-}
-
-static u_char
-ReadHFC(struct IsdnCardState *cs, int data, u_char reg)
-{
- register u_char ret;
-
- if (data) {
- cs->hw.hfc.cip = reg;
- byteout(cs->hw.hfc.addr | 1, reg);
- ret = bytein(cs->hw.hfc.addr);
- if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2))
- debugl1(cs, "hfc RD %02x %02x", reg, ret);
- } else
- ret = bytein(cs->hw.hfc.addr | 1);
- return (ret);
-}
-
-static void
-WriteHFC(struct IsdnCardState *cs, int data, u_char reg, u_char value)
-{
- byteout(cs->hw.hfc.addr | 1, reg);
- cs->hw.hfc.cip = reg;
- if (data)
- byteout(cs->hw.hfc.addr, value);
- if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2))
- debugl1(cs, "hfc W%c %02x %02x", data ? 'D' : 'C', reg, value);
-}
-
-static irqreturn_t
-TeleInt_interrupt(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_char val;
- u_long flags;
-
- spin_lock_irqsave(&cs->lock, flags);
- val = readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_ISTA);
-Start_ISAC:
- if (val)
- isac_interrupt(cs, val);
- val = readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_ISTA);
- if (val) {
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ISAC IntStat after IntRoutine");
- goto Start_ISAC;
- }
- writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_MASK, 0xFF);
- writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_MASK, 0x0);
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static void
-TeleInt_Timer(struct timer_list *t)
-{
- struct IsdnCardState *cs = from_timer(cs, t, hw.hfc.timer);
- int stat = 0;
- u_long flags;
-
- spin_lock_irqsave(&cs->lock, flags);
- if (cs->bcs[0].mode) {
- stat |= 1;
- main_irq_hfc(&cs->bcs[0]);
- }
- if (cs->bcs[1].mode) {
- stat |= 2;
- main_irq_hfc(&cs->bcs[1]);
- }
- spin_unlock_irqrestore(&cs->lock, flags);
- stat = HZ / 100;
- if (!stat)
- stat = 1;
- cs->hw.hfc.timer.expires = jiffies + stat;
- add_timer(&cs->hw.hfc.timer);
-}
-
-static void
-release_io_TeleInt(struct IsdnCardState *cs)
-{
- del_timer(&cs->hw.hfc.timer);
- releasehfc(cs);
- if (cs->hw.hfc.addr)
- release_region(cs->hw.hfc.addr, 2);
-}
-
-static void
-reset_TeleInt(struct IsdnCardState *cs)
-{
- printk(KERN_INFO "TeleInt: resetting card\n");
- cs->hw.hfc.cirm |= HFC_RESET;
- byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); /* Reset On */
- mdelay(10);
- cs->hw.hfc.cirm &= ~HFC_RESET;
- byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); /* Reset Off */
- mdelay(10);
-}
-
-static int
-TeleInt_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
- u_long flags;
- int delay;
-
- switch (mt) {
- case CARD_RESET:
- spin_lock_irqsave(&cs->lock, flags);
- reset_TeleInt(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_RELEASE:
- release_io_TeleInt(cs);
- return (0);
- case CARD_INIT:
- spin_lock_irqsave(&cs->lock, flags);
- reset_TeleInt(cs);
- inithfc(cs);
- clear_pending_isac_ints(cs);
- initisac(cs);
- /* Reenable all IRQ */
- cs->writeisac(cs, ISAC_MASK, 0);
- cs->writeisac(cs, ISAC_CMDR, 0x41);
- spin_unlock_irqrestore(&cs->lock, flags);
- delay = HZ / 100;
- if (!delay)
- delay = 1;
- cs->hw.hfc.timer.expires = jiffies + delay;
- add_timer(&cs->hw.hfc.timer);
- return (0);
- case CARD_TEST:
- return (0);
- }
- return (0);
-}
-
-int setup_TeleInt(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
-
- strcpy(tmp, TeleInt_revision);
- printk(KERN_INFO "HiSax: TeleInt driver Rev. %s\n", HiSax_getrev(tmp));
- if (cs->typ != ISDN_CTYPE_TELEINT)
- return (0);
-
- cs->hw.hfc.addr = card->para[1] & 0x3fe;
- cs->irq = card->para[0];
- cs->hw.hfc.cirm = HFC_CIRM;
- cs->hw.hfc.isac_spcr = 0x00;
- cs->hw.hfc.cip = 0;
- cs->hw.hfc.ctmt = HFC_CTMT | HFC_CLTIMER;
- cs->bcs[0].hw.hfc.send = NULL;
- cs->bcs[1].hw.hfc.send = NULL;
- cs->hw.hfc.fifosize = 7 * 1024 + 512;
- timer_setup(&cs->hw.hfc.timer, TeleInt_Timer, 0);
- if (!request_region(cs->hw.hfc.addr, 2, "TeleInt isdn")) {
- printk(KERN_WARNING
- "HiSax: TeleInt config port %x-%x already in use\n",
- cs->hw.hfc.addr,
- cs->hw.hfc.addr + 2);
- return (0);
- }
- /* HW IO = IO */
- byteout(cs->hw.hfc.addr, cs->hw.hfc.addr & 0xff);
- byteout(cs->hw.hfc.addr | 1, ((cs->hw.hfc.addr & 0x300) >> 8) | 0x54);
- switch (cs->irq) {
- case 3:
- cs->hw.hfc.cirm |= HFC_INTA;
- break;
- case 4:
- cs->hw.hfc.cirm |= HFC_INTB;
- break;
- case 5:
- cs->hw.hfc.cirm |= HFC_INTC;
- break;
- case 7:
- cs->hw.hfc.cirm |= HFC_INTD;
- break;
- case 10:
- cs->hw.hfc.cirm |= HFC_INTE;
- break;
- case 11:
- cs->hw.hfc.cirm |= HFC_INTF;
- break;
- default:
- printk(KERN_WARNING "TeleInt: wrong IRQ\n");
- release_io_TeleInt(cs);
- return (0);
- }
- byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm);
- byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.ctmt);
-
- printk(KERN_INFO "TeleInt: defined at 0x%x IRQ %d\n",
- cs->hw.hfc.addr, cs->irq);
-
- setup_isac(cs);
- cs->readisac = &ReadISAC;
- cs->writeisac = &WriteISAC;
- cs->readisacfifo = &ReadISACfifo;
- cs->writeisacfifo = &WriteISACfifo;
- cs->BC_Read_Reg = &ReadHFC;
- cs->BC_Write_Reg = &WriteHFC;
- cs->cardmsg = &TeleInt_card_msg;
- cs->irq_func = &TeleInt_interrupt;
- ISACVersion(cs, "TeleInt:");
- return (1);
-}
diff --git a/drivers/isdn/hisax/teles0.c b/drivers/isdn/hisax/teles0.c
deleted file mode 100644
index ce9eabdd2f6e..000000000000
--- a/drivers/isdn/hisax/teles0.c
+++ /dev/null
@@ -1,364 +0,0 @@
-/* $Id: teles0.c,v 2.15.2.4 2004/01/13 23:48:39 keil Exp $
- *
- * low level stuff for Teles Memory IO isdn cards
- *
- * Author Karsten Keil
- * based on the teles driver from Jan den Ouden
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Thanks to Jan den Ouden
- * Fritz Elfert
- * Beat Doebeli
- *
- */
-
-#include <linux/init.h>
-#include "hisax.h"
-#include "isdnl1.h"
-#include "isac.h"
-#include "hscx.h"
-
-static const char *teles0_revision = "$Revision: 2.15.2.4 $";
-
-#define TELES_IOMEM_SIZE 0x400
-#define byteout(addr, val) outb(val, addr)
-#define bytein(addr) inb(addr)
-
-static inline u_char
-readisac(void __iomem *adr, u_char off)
-{
- return readb(adr + ((off & 1) ? 0x2ff : 0x100) + off);
-}
-
-static inline void
-writeisac(void __iomem *adr, u_char off, u_char data)
-{
- writeb(data, adr + ((off & 1) ? 0x2ff : 0x100) + off); mb();
-}
-
-
-static inline u_char
-readhscx(void __iomem *adr, int hscx, u_char off)
-{
- return readb(adr + (hscx ? 0x1c0 : 0x180) +
- ((off & 1) ? 0x1ff : 0) + off);
-}
-
-static inline void
-writehscx(void __iomem *adr, int hscx, u_char off, u_char data)
-{
- writeb(data, adr + (hscx ? 0x1c0 : 0x180) +
- ((off & 1) ? 0x1ff : 0) + off); mb();
-}
-
-static inline void
-read_fifo_isac(void __iomem *adr, u_char *data, int size)
-{
- register int i;
- register u_char __iomem *ad = adr + 0x100;
- for (i = 0; i < size; i++)
- data[i] = readb(ad);
-}
-
-static inline void
-write_fifo_isac(void __iomem *adr, u_char *data, int size)
-{
- register int i;
- register u_char __iomem *ad = adr + 0x100;
- for (i = 0; i < size; i++) {
- writeb(data[i], ad); mb();
- }
-}
-
-static inline void
-read_fifo_hscx(void __iomem *adr, int hscx, u_char *data, int size)
-{
- register int i;
- register u_char __iomem *ad = adr + (hscx ? 0x1c0 : 0x180);
- for (i = 0; i < size; i++)
- data[i] = readb(ad);
-}
-
-static inline void
-write_fifo_hscx(void __iomem *adr, int hscx, u_char *data, int size)
-{
- int i;
- register u_char __iomem *ad = adr + (hscx ? 0x1c0 : 0x180);
- for (i = 0; i < size; i++) {
- writeb(data[i], ad); mb();
- }
-}
-
-/* Interface functions */
-
-static u_char
-ReadISAC(struct IsdnCardState *cs, u_char offset)
-{
- return (readisac(cs->hw.teles0.membase, offset));
-}
-
-static void
-WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
-{
- writeisac(cs->hw.teles0.membase, offset, value);
-}
-
-static void
-ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- read_fifo_isac(cs->hw.teles0.membase, data, size);
-}
-
-static void
-WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- write_fifo_isac(cs->hw.teles0.membase, data, size);
-}
-
-static u_char
-ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
-{
- return (readhscx(cs->hw.teles0.membase, hscx, offset));
-}
-
-static void
-WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
-{
- writehscx(cs->hw.teles0.membase, hscx, offset, value);
-}
-
-/*
- * fast interrupt HSCX stuff goes here
- */
-
-#define READHSCX(cs, nr, reg) readhscx(cs->hw.teles0.membase, nr, reg)
-#define WRITEHSCX(cs, nr, reg, data) writehscx(cs->hw.teles0.membase, nr, reg, data)
-#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt)
-#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt)
-
-#include "hscx_irq.c"
-
-static irqreturn_t
-teles0_interrupt(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_char val;
- u_long flags;
- int count = 0;
-
- spin_lock_irqsave(&cs->lock, flags);
- val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA);
-Start_HSCX:
- if (val)
- hscx_int_main(cs, val);
- val = readisac(cs->hw.teles0.membase, ISAC_ISTA);
-Start_ISAC:
- if (val)
- isac_interrupt(cs, val);
- count++;
- val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA);
- if (val && count < 5) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "HSCX IntStat after IntRoutine");
- goto Start_HSCX;
- }
- val = readisac(cs->hw.teles0.membase, ISAC_ISTA);
- if (val && count < 5) {
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ISAC IntStat after IntRoutine");
- goto Start_ISAC;
- }
- writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0xFF);
- writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0xFF);
- writeisac(cs->hw.teles0.membase, ISAC_MASK, 0xFF);
- writeisac(cs->hw.teles0.membase, ISAC_MASK, 0x0);
- writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0x0);
- writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0x0);
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static void
-release_io_teles0(struct IsdnCardState *cs)
-{
- if (cs->hw.teles0.cfg_reg)
- release_region(cs->hw.teles0.cfg_reg, 8);
- iounmap(cs->hw.teles0.membase);
- release_mem_region(cs->hw.teles0.phymem, TELES_IOMEM_SIZE);
-}
-
-static int
-reset_teles0(struct IsdnCardState *cs)
-{
- u_char cfval;
-
- if (cs->hw.teles0.cfg_reg) {
- switch (cs->irq) {
- case 2:
- case 9:
- cfval = 0x00;
- break;
- case 3:
- cfval = 0x02;
- break;
- case 4:
- cfval = 0x04;
- break;
- case 5:
- cfval = 0x06;
- break;
- case 10:
- cfval = 0x08;
- break;
- case 11:
- cfval = 0x0A;
- break;
- case 12:
- cfval = 0x0C;
- break;
- case 15:
- cfval = 0x0E;
- break;
- default:
- return (1);
- }
- cfval |= ((cs->hw.teles0.phymem >> 9) & 0xF0);
- byteout(cs->hw.teles0.cfg_reg + 4, cfval);
- HZDELAY(HZ / 10 + 1);
- byteout(cs->hw.teles0.cfg_reg + 4, cfval | 1);
- HZDELAY(HZ / 10 + 1);
- }
- writeb(0, cs->hw.teles0.membase + 0x80); mb();
- HZDELAY(HZ / 5 + 1);
- writeb(1, cs->hw.teles0.membase + 0x80); mb();
- HZDELAY(HZ / 5 + 1);
- return (0);
-}
-
-static int
-Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
- u_long flags;
-
- switch (mt) {
- case CARD_RESET:
- spin_lock_irqsave(&cs->lock, flags);
- reset_teles0(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_RELEASE:
- release_io_teles0(cs);
- return (0);
- case CARD_INIT:
- spin_lock_irqsave(&cs->lock, flags);
- inithscxisac(cs, 3);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_TEST:
- return (0);
- }
- return (0);
-}
-
-int setup_teles0(struct IsdnCard *card)
-{
- u_char val;
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
-
- strcpy(tmp, teles0_revision);
- printk(KERN_INFO "HiSax: Teles 8.0/16.0 driver Rev. %s\n", HiSax_getrev(tmp));
- if ((cs->typ != ISDN_CTYPE_16_0) && (cs->typ != ISDN_CTYPE_8_0))
- return (0);
-
- if (cs->typ == ISDN_CTYPE_16_0)
- cs->hw.teles0.cfg_reg = card->para[2];
- else /* 8.0 */
- cs->hw.teles0.cfg_reg = 0;
-
- if (card->para[1] < 0x10000) {
- card->para[1] <<= 4;
- printk(KERN_INFO
- "Teles0: membase configured DOSish, assuming 0x%lx\n",
- (unsigned long) card->para[1]);
- }
- cs->irq = card->para[0];
- if (cs->hw.teles0.cfg_reg) {
- if (!request_region(cs->hw.teles0.cfg_reg, 8, "teles cfg")) {
- printk(KERN_WARNING
- "HiSax: %s config port %x-%x already in use\n",
- CardType[card->typ],
- cs->hw.teles0.cfg_reg,
- cs->hw.teles0.cfg_reg + 8);
- return (0);
- }
- }
- if (cs->hw.teles0.cfg_reg) {
- if ((val = bytein(cs->hw.teles0.cfg_reg + 0)) != 0x51) {
- printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
- cs->hw.teles0.cfg_reg + 0, val);
- release_region(cs->hw.teles0.cfg_reg, 8);
- return (0);
- }
- if ((val = bytein(cs->hw.teles0.cfg_reg + 1)) != 0x93) {
- printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
- cs->hw.teles0.cfg_reg + 1, val);
- release_region(cs->hw.teles0.cfg_reg, 8);
- return (0);
- }
- val = bytein(cs->hw.teles0.cfg_reg + 2); /* 0x1e=without AB
- * 0x1f=with AB
- * 0x1c 16.3 ???
- */
- if (val != 0x1e && val != 0x1f) {
- printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
- cs->hw.teles0.cfg_reg + 2, val);
- release_region(cs->hw.teles0.cfg_reg, 8);
- return (0);
- }
- }
- /* 16.0 and 8.0 designed for IOM1 */
- test_and_set_bit(HW_IOM1, &cs->HW_Flags);
- cs->hw.teles0.phymem = card->para[1];
- if (!request_mem_region(cs->hw.teles0.phymem, TELES_IOMEM_SIZE, "teles iomem")) {
- printk(KERN_WARNING
- "HiSax: %s memory region %lx-%lx already in use\n",
- CardType[card->typ],
- cs->hw.teles0.phymem,
- cs->hw.teles0.phymem + TELES_IOMEM_SIZE);
- if (cs->hw.teles0.cfg_reg)
- release_region(cs->hw.teles0.cfg_reg, 8);
- return (0);
- }
- cs->hw.teles0.membase = ioremap(cs->hw.teles0.phymem, TELES_IOMEM_SIZE);
- printk(KERN_INFO
- "HiSax: %s config irq:%d mem:%p cfg:0x%X\n",
- CardType[cs->typ], cs->irq,
- cs->hw.teles0.membase, cs->hw.teles0.cfg_reg);
- if (reset_teles0(cs)) {
- printk(KERN_WARNING "Teles0: wrong IRQ\n");
- release_io_teles0(cs);
- return (0);
- }
- setup_isac(cs);
- cs->readisac = &ReadISAC;
- cs->writeisac = &WriteISAC;
- cs->readisacfifo = &ReadISACfifo;
- cs->writeisacfifo = &WriteISACfifo;
- cs->BC_Read_Reg = &ReadHSCX;
- cs->BC_Write_Reg = &WriteHSCX;
- cs->BC_Send_Data = &hscx_fill_fifo;
- cs->cardmsg = &Teles_card_msg;
- cs->irq_func = &teles0_interrupt;
- ISACVersion(cs, "Teles0:");
- if (HscxVersion(cs, "Teles0:")) {
- printk(KERN_WARNING
- "Teles0: wrong HSCX versions check IO/MEM addresses\n");
- release_io_teles0(cs);
- return (0);
- }
- return (1);
-}
diff --git a/drivers/isdn/hisax/teles3.c b/drivers/isdn/hisax/teles3.c
deleted file mode 100644
index 1eef693f04f0..000000000000
--- a/drivers/isdn/hisax/teles3.c
+++ /dev/null
@@ -1,498 +0,0 @@
-/* $Id: teles3.c,v 2.19.2.4 2004/01/13 23:48:39 keil Exp $
- *
- * low level stuff for Teles 16.3 & PNP isdn cards
- *
- * Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Thanks to Jan den Ouden
- * Fritz Elfert
- * Beat Doebeli
- *
- */
-#include <linux/init.h>
-#include <linux/isapnp.h>
-#include "hisax.h"
-#include "isac.h"
-#include "hscx.h"
-#include "isdnl1.h"
-
-static const char *teles3_revision = "$Revision: 2.19.2.4 $";
-
-#define byteout(addr, val) outb(val, addr)
-#define bytein(addr) inb(addr)
-
-static inline u_char
-readreg(unsigned int adr, u_char off)
-{
- return (bytein(adr + off));
-}
-
-static inline void
-writereg(unsigned int adr, u_char off, u_char data)
-{
- byteout(adr + off, data);
-}
-
-
-static inline void
-read_fifo(unsigned int adr, u_char *data, int size)
-{
- insb(adr, data, size);
-}
-
-static void
-write_fifo(unsigned int adr, u_char *data, int size)
-{
- outsb(adr, data, size);
-}
-
-/* Interface functions */
-
-static u_char
-ReadISAC(struct IsdnCardState *cs, u_char offset)
-{
- return (readreg(cs->hw.teles3.isac, offset));
-}
-
-static void
-WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
-{
- writereg(cs->hw.teles3.isac, offset, value);
-}
-
-static void
-ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- read_fifo(cs->hw.teles3.isacfifo, data, size);
-}
-
-static void
-WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- write_fifo(cs->hw.teles3.isacfifo, data, size);
-}
-
-static u_char
-ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
-{
- return (readreg(cs->hw.teles3.hscx[hscx], offset));
-}
-
-static void
-WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
-{
- writereg(cs->hw.teles3.hscx[hscx], offset, value);
-}
-
-/*
- * fast interrupt HSCX stuff goes here
- */
-
-#define READHSCX(cs, nr, reg) readreg(cs->hw.teles3.hscx[nr], reg)
-#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.teles3.hscx[nr], reg, data)
-#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.teles3.hscxfifo[nr], ptr, cnt)
-#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.teles3.hscxfifo[nr], ptr, cnt)
-
-#include "hscx_irq.c"
-
-static irqreturn_t
-teles3_interrupt(int intno, void *dev_id)
-{
-#define MAXCOUNT 5
- struct IsdnCardState *cs = dev_id;
- u_char val;
- u_long flags;
- int count = 0;
-
- spin_lock_irqsave(&cs->lock, flags);
- val = readreg(cs->hw.teles3.hscx[1], HSCX_ISTA);
-Start_HSCX:
- if (val)
- hscx_int_main(cs, val);
- val = readreg(cs->hw.teles3.isac, ISAC_ISTA);
-Start_ISAC:
- if (val)
- isac_interrupt(cs, val);
- count++;
- val = readreg(cs->hw.teles3.hscx[1], HSCX_ISTA);
- if (val && count < MAXCOUNT) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "HSCX IntStat after IntRoutine");
- goto Start_HSCX;
- }
- val = readreg(cs->hw.teles3.isac, ISAC_ISTA);
- if (val && count < MAXCOUNT) {
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ISAC IntStat after IntRoutine");
- goto Start_ISAC;
- }
- if (count >= MAXCOUNT)
- printk(KERN_WARNING "Teles3: more than %d loops in teles3_interrupt\n", count);
- writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0xFF);
- writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0xFF);
- writereg(cs->hw.teles3.isac, ISAC_MASK, 0xFF);
- writereg(cs->hw.teles3.isac, ISAC_MASK, 0x0);
- writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0x0);
- writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0x0);
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static inline void
-release_ioregs(struct IsdnCardState *cs, int mask)
-{
- if (mask & 1)
- release_region(cs->hw.teles3.isac + 32, 32);
- if (mask & 2)
- release_region(cs->hw.teles3.hscx[0] + 32, 32);
- if (mask & 4)
- release_region(cs->hw.teles3.hscx[1] + 32, 32);
-}
-
-static void
-release_io_teles3(struct IsdnCardState *cs)
-{
- if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
- release_region(cs->hw.teles3.hscx[1], 96);
- } else {
- if (cs->hw.teles3.cfg_reg) {
- if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
- release_region(cs->hw.teles3.cfg_reg, 1);
- } else {
- release_region(cs->hw.teles3.cfg_reg, 8);
- }
- }
- release_ioregs(cs, 0x7);
- }
-}
-
-static int
-reset_teles3(struct IsdnCardState *cs)
-{
- u_char irqcfg;
-
- if (cs->typ != ISDN_CTYPE_TELESPCMCIA) {
- if ((cs->hw.teles3.cfg_reg) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) {
- switch (cs->irq) {
- case 2:
- case 9:
- irqcfg = 0x00;
- break;
- case 3:
- irqcfg = 0x02;
- break;
- case 4:
- irqcfg = 0x04;
- break;
- case 5:
- irqcfg = 0x06;
- break;
- case 10:
- irqcfg = 0x08;
- break;
- case 11:
- irqcfg = 0x0A;
- break;
- case 12:
- irqcfg = 0x0C;
- break;
- case 15:
- irqcfg = 0x0E;
- break;
- default:
- return (1);
- }
- byteout(cs->hw.teles3.cfg_reg + 4, irqcfg);
- HZDELAY(HZ / 10 + 1);
- byteout(cs->hw.teles3.cfg_reg + 4, irqcfg | 1);
- HZDELAY(HZ / 10 + 1);
- } else if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
- byteout(cs->hw.teles3.cfg_reg, 0xff);
- HZDELAY(2);
- byteout(cs->hw.teles3.cfg_reg, 0x00);
- HZDELAY(2);
- } else {
- /* Reset off for 16.3 PnP , thanks to Georg Acher */
- byteout(cs->hw.teles3.isac + 0x3c, 0);
- HZDELAY(2);
- byteout(cs->hw.teles3.isac + 0x3c, 1);
- HZDELAY(2);
- }
- }
- return (0);
-}
-
-static int
-Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
- u_long flags;
-
- switch (mt) {
- case CARD_RESET:
- spin_lock_irqsave(&cs->lock, flags);
- reset_teles3(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_RELEASE:
- release_io_teles3(cs);
- return (0);
- case CARD_INIT:
- spin_lock_irqsave(&cs->lock, flags);
- inithscxisac(cs, 3);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_TEST:
- return (0);
- }
- return (0);
-}
-
-#ifdef __ISAPNP__
-
-static struct isapnp_device_id teles_ids[] = {
- { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110),
- ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110),
- (unsigned long) "Teles 16.3 PnP" },
- { ISAPNP_VENDOR('C', 'T', 'X'), ISAPNP_FUNCTION(0x0),
- ISAPNP_VENDOR('C', 'T', 'X'), ISAPNP_FUNCTION(0x0),
- (unsigned long) "Creatix 16.3 PnP" },
- { ISAPNP_VENDOR('C', 'P', 'Q'), ISAPNP_FUNCTION(0x1002),
- ISAPNP_VENDOR('C', 'P', 'Q'), ISAPNP_FUNCTION(0x1002),
- (unsigned long) "Compaq ISDN S0" },
- { 0, }
-};
-
-static struct isapnp_device_id *ipid = &teles_ids[0];
-static struct pnp_card *pnp_c = NULL;
-#endif
-
-int setup_teles3(struct IsdnCard *card)
-{
- u_char val;
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
-
- strcpy(tmp, teles3_revision);
- printk(KERN_INFO "HiSax: Teles IO driver Rev. %s\n", HiSax_getrev(tmp));
- if ((cs->typ != ISDN_CTYPE_16_3) && (cs->typ != ISDN_CTYPE_PNP)
- && (cs->typ != ISDN_CTYPE_TELESPCMCIA) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA))
- return (0);
-
-#ifdef __ISAPNP__
- if (!card->para[1] && isapnp_present()) {
- struct pnp_dev *pnp_d;
- while (ipid->card_vendor) {
- if ((pnp_c = pnp_find_card(ipid->card_vendor,
- ipid->card_device, pnp_c))) {
- pnp_d = NULL;
- if ((pnp_d = pnp_find_dev(pnp_c,
- ipid->vendor, ipid->function, pnp_d))) {
- int err;
-
- printk(KERN_INFO "HiSax: %s detected\n",
- (char *)ipid->driver_data);
- pnp_disable_dev(pnp_d);
- err = pnp_activate_dev(pnp_d);
- if (err < 0) {
- printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __func__, err);
- return (0);
- }
- card->para[3] = pnp_port_start(pnp_d, 2);
- card->para[2] = pnp_port_start(pnp_d, 1);
- card->para[1] = pnp_port_start(pnp_d, 0);
- card->para[0] = pnp_irq(pnp_d, 0);
- if (card->para[0] == -1 || !card->para[1] || !card->para[2]) {
- printk(KERN_ERR "Teles PnP:some resources are missing %ld/%lx/%lx\n",
- card->para[0], card->para[1], card->para[2]);
- pnp_disable_dev(pnp_d);
- return (0);
- }
- break;
- } else {
- printk(KERN_ERR "Teles PnP: PnP error card found, no device\n");
- }
- }
- ipid++;
- pnp_c = NULL;
- }
- if (!ipid->card_vendor) {
- printk(KERN_INFO "Teles PnP: no ISAPnP card found\n");
- return (0);
- }
- }
-#endif
- if (cs->typ == ISDN_CTYPE_16_3) {
- cs->hw.teles3.cfg_reg = card->para[1];
- switch (cs->hw.teles3.cfg_reg) {
- case 0x180:
- case 0x280:
- case 0x380:
- cs->hw.teles3.cfg_reg |= 0xc00;
- break;
- }
- cs->hw.teles3.isac = cs->hw.teles3.cfg_reg - 0x420;
- cs->hw.teles3.hscx[0] = cs->hw.teles3.cfg_reg - 0xc20;
- cs->hw.teles3.hscx[1] = cs->hw.teles3.cfg_reg - 0x820;
- } else if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
- cs->hw.teles3.cfg_reg = 0;
- cs->hw.teles3.hscx[0] = card->para[1] - 0x20;
- cs->hw.teles3.hscx[1] = card->para[1];
- cs->hw.teles3.isac = card->para[1] + 0x20;
- } else if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
- cs->hw.teles3.cfg_reg = card->para[3];
- cs->hw.teles3.isac = card->para[2] - 32;
- cs->hw.teles3.hscx[0] = card->para[1] - 32;
- cs->hw.teles3.hscx[1] = card->para[1];
- } else { /* PNP */
- cs->hw.teles3.cfg_reg = 0;
- cs->hw.teles3.isac = card->para[1] - 32;
- cs->hw.teles3.hscx[0] = card->para[2] - 32;
- cs->hw.teles3.hscx[1] = card->para[2];
- }
- cs->irq = card->para[0];
- cs->hw.teles3.isacfifo = cs->hw.teles3.isac + 0x3e;
- cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e;
- cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e;
- if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
- if (!request_region(cs->hw.teles3.hscx[1], 96, "HiSax Teles PCMCIA")) {
- printk(KERN_WARNING
- "HiSax: %s ports %x-%x already in use\n",
- CardType[cs->typ],
- cs->hw.teles3.hscx[1],
- cs->hw.teles3.hscx[1] + 96);
- return (0);
- }
- cs->irq_flags |= IRQF_SHARED; /* cardbus can share */
- } else {
- if (cs->hw.teles3.cfg_reg) {
- if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
- if (!request_region(cs->hw.teles3.cfg_reg, 1, "teles3 cfg")) {
- printk(KERN_WARNING
- "HiSax: %s config port %x already in use\n",
- CardType[card->typ],
- cs->hw.teles3.cfg_reg);
- return (0);
- }
- } else {
- if (!request_region(cs->hw.teles3.cfg_reg, 8, "teles3 cfg")) {
- printk(KERN_WARNING
- "HiSax: %s config port %x-%x already in use\n",
- CardType[card->typ],
- cs->hw.teles3.cfg_reg,
- cs->hw.teles3.cfg_reg + 8);
- return (0);
- }
- }
- }
- if (!request_region(cs->hw.teles3.isac + 32, 32, "HiSax isac")) {
- printk(KERN_WARNING
- "HiSax: %s isac ports %x-%x already in use\n",
- CardType[cs->typ],
- cs->hw.teles3.isac + 32,
- cs->hw.teles3.isac + 64);
- if (cs->hw.teles3.cfg_reg) {
- if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
- release_region(cs->hw.teles3.cfg_reg, 1);
- } else {
- release_region(cs->hw.teles3.cfg_reg, 8);
- }
- }
- return (0);
- }
- if (!request_region(cs->hw.teles3.hscx[0] + 32, 32, "HiSax hscx A")) {
- printk(KERN_WARNING
- "HiSax: %s hscx A ports %x-%x already in use\n",
- CardType[cs->typ],
- cs->hw.teles3.hscx[0] + 32,
- cs->hw.teles3.hscx[0] + 64);
- if (cs->hw.teles3.cfg_reg) {
- if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
- release_region(cs->hw.teles3.cfg_reg, 1);
- } else {
- release_region(cs->hw.teles3.cfg_reg, 8);
- }
- }
- release_ioregs(cs, 1);
- return (0);
- }
- if (!request_region(cs->hw.teles3.hscx[1] + 32, 32, "HiSax hscx B")) {
- printk(KERN_WARNING
- "HiSax: %s hscx B ports %x-%x already in use\n",
- CardType[cs->typ],
- cs->hw.teles3.hscx[1] + 32,
- cs->hw.teles3.hscx[1] + 64);
- if (cs->hw.teles3.cfg_reg) {
- if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
- release_region(cs->hw.teles3.cfg_reg, 1);
- } else {
- release_region(cs->hw.teles3.cfg_reg, 8);
- }
- }
- release_ioregs(cs, 3);
- return (0);
- }
- }
- if ((cs->hw.teles3.cfg_reg) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) {
- if ((val = bytein(cs->hw.teles3.cfg_reg + 0)) != 0x51) {
- printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
- cs->hw.teles3.cfg_reg + 0, val);
- release_io_teles3(cs);
- return (0);
- }
- if ((val = bytein(cs->hw.teles3.cfg_reg + 1)) != 0x93) {
- printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
- cs->hw.teles3.cfg_reg + 1, val);
- release_io_teles3(cs);
- return (0);
- }
- val = bytein(cs->hw.teles3.cfg_reg + 2);/* 0x1e=without AB
- * 0x1f=with AB
- * 0x1c 16.3 ???
- * 0x39 16.3 1.1
- * 0x38 16.3 1.3
- * 0x46 16.3 with AB + Video (Teles-Vision)
- */
- if (val != 0x46 && val != 0x39 && val != 0x38 && val != 0x1c && val != 0x1e && val != 0x1f) {
- printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
- cs->hw.teles3.cfg_reg + 2, val);
- release_io_teles3(cs);
- return (0);
- }
- }
- printk(KERN_INFO
- "HiSax: %s config irq:%d isac:0x%X cfg:0x%X\n",
- CardType[cs->typ], cs->irq,
- cs->hw.teles3.isac + 32, cs->hw.teles3.cfg_reg);
- printk(KERN_INFO
- "HiSax: hscx A:0x%X hscx B:0x%X\n",
- cs->hw.teles3.hscx[0] + 32, cs->hw.teles3.hscx[1] + 32);
-
- setup_isac(cs);
- if (reset_teles3(cs)) {
- printk(KERN_WARNING "Teles3: wrong IRQ\n");
- release_io_teles3(cs);
- return (0);
- }
- cs->readisac = &ReadISAC;
- cs->writeisac = &WriteISAC;
- cs->readisacfifo = &ReadISACfifo;
- cs->writeisacfifo = &WriteISACfifo;
- cs->BC_Read_Reg = &ReadHSCX;
- cs->BC_Write_Reg = &WriteHSCX;
- cs->BC_Send_Data = &hscx_fill_fifo;
- cs->cardmsg = &Teles_card_msg;
- cs->irq_func = &teles3_interrupt;
- ISACVersion(cs, "Teles3:");
- if (HscxVersion(cs, "Teles3:")) {
- printk(KERN_WARNING
- "Teles3: wrong HSCX versions check IO address\n");
- release_io_teles3(cs);
- return (0);
- }
- return (1);
-}
diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c
deleted file mode 100644
index bcc37e955622..000000000000
--- a/drivers/isdn/hisax/teles_cs.c
+++ /dev/null
@@ -1,201 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/* $Id: teles_cs.c,v 1.1.2.2 2004/01/25 15:07:06 keil Exp $ */
-/*======================================================================
-
- A teles S0 PCMCIA client driver
-
- Based on skeleton by David Hinds, dhinds@allegro.stanford.edu
- Written by Christof Petig, christof.petig@wtal.de
-
- Also inspired by ELSA PCMCIA driver
- by Klaus Lichtenwalder <Lichtenwalder@ACM.org>
-
- Extensions to new hisax_pcmcia by Karsten Keil
-
- minor changes to be compatible with kernel 2.4.x
- by Jan.Schubert@GMX.li
-
- ======================================================================*/
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/ioport.h>
-#include <asm/io.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ds.h>
-#include "hisax_cfg.h"
-
-MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Teles PCMCIA cards");
-MODULE_AUTHOR("Christof Petig, christof.petig@wtal.de, Karsten Keil, kkeil@suse.de");
-MODULE_LICENSE("GPL");
-
-
-/*====================================================================*/
-
-/* Parameters that can be set with 'insmod' */
-
-static int protocol = 2; /* EURO-ISDN Default */
-module_param(protocol, int, 0);
-
-static int teles_cs_config(struct pcmcia_device *link);
-static void teles_cs_release(struct pcmcia_device *link);
-static void teles_detach(struct pcmcia_device *p_dev);
-
-typedef struct local_info_t {
- struct pcmcia_device *p_dev;
- int busy;
- int cardnr;
-} local_info_t;
-
-static int teles_probe(struct pcmcia_device *link)
-{
- local_info_t *local;
-
- dev_dbg(&link->dev, "teles_attach()\n");
-
- /* Allocate space for private device-specific data */
- local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
- if (!local) return -ENOMEM;
- local->cardnr = -1;
-
- local->p_dev = link;
- link->priv = local;
-
- link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
-
- return teles_cs_config(link);
-} /* teles_attach */
-
-static void teles_detach(struct pcmcia_device *link)
-{
- local_info_t *info = link->priv;
-
- dev_dbg(&link->dev, "teles_detach(0x%p)\n", link);
-
- info->busy = 1;
- teles_cs_release(link);
-
- kfree(info);
-} /* teles_detach */
-
-static int teles_cs_configcheck(struct pcmcia_device *p_dev, void *priv_data)
-{
- int j;
-
- p_dev->io_lines = 5;
- p_dev->resource[0]->end = 96;
- p_dev->resource[0]->flags &= IO_DATA_PATH_WIDTH;
- p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-
- if ((p_dev->resource[0]->end) && p_dev->resource[0]->start) {
- printk(KERN_INFO "(teles_cs: looks like the 96 model)\n");
- if (!pcmcia_request_io(p_dev))
- return 0;
- } else {
- printk(KERN_INFO "(teles_cs: looks like the 97 model)\n");
- for (j = 0x2f0; j > 0x100; j -= 0x10) {
- p_dev->resource[0]->start = j;
- if (!pcmcia_request_io(p_dev))
- return 0;
- }
- }
- return -ENODEV;
-}
-
-static int teles_cs_config(struct pcmcia_device *link)
-{
- int i;
- IsdnCard_t icard;
-
- dev_dbg(&link->dev, "teles_config(0x%p)\n", link);
-
- i = pcmcia_loop_config(link, teles_cs_configcheck, NULL);
- if (i != 0)
- goto cs_failed;
-
- if (!link->irq)
- goto cs_failed;
-
- i = pcmcia_enable_device(link);
- if (i != 0)
- goto cs_failed;
-
- icard.para[0] = link->irq;
- icard.para[1] = link->resource[0]->start;
- icard.protocol = protocol;
- icard.typ = ISDN_CTYPE_TELESPCMCIA;
-
- i = hisax_init_pcmcia(link, &(((local_info_t *)link->priv)->busy), &icard);
- if (i < 0) {
- printk(KERN_ERR "teles_cs: failed to initialize Teles PCMCIA %d at i/o %#x\n",
- i, (unsigned int) link->resource[0]->start);
- teles_cs_release(link);
- return -ENODEV;
- }
-
- ((local_info_t *)link->priv)->cardnr = i;
- return 0;
-
-cs_failed:
- teles_cs_release(link);
- return -ENODEV;
-} /* teles_cs_config */
-
-static void teles_cs_release(struct pcmcia_device *link)
-{
- local_info_t *local = link->priv;
-
- dev_dbg(&link->dev, "teles_cs_release(0x%p)\n", link);
-
- if (local) {
- if (local->cardnr >= 0) {
- /* no unregister function with hisax */
- HiSax_closecard(local->cardnr);
- }
- }
-
- pcmcia_disable_device(link);
-} /* teles_cs_release */
-
-static int teles_suspend(struct pcmcia_device *link)
-{
- local_info_t *dev = link->priv;
-
- dev->busy = 1;
-
- return 0;
-}
-
-static int teles_resume(struct pcmcia_device *link)
-{
- local_info_t *dev = link->priv;
-
- dev->busy = 0;
-
- return 0;
-}
-
-
-static const struct pcmcia_device_id teles_ids[] = {
- PCMCIA_DEVICE_PROD_ID12("TELES", "S0/PC", 0x67b50eae, 0xe9e70119),
- PCMCIA_DEVICE_NULL,
-};
-MODULE_DEVICE_TABLE(pcmcia, teles_ids);
-
-static struct pcmcia_driver teles_cs_driver = {
- .owner = THIS_MODULE,
- .name = "teles_cs",
- .probe = teles_probe,
- .remove = teles_detach,
- .id_table = teles_ids,
- .suspend = teles_suspend,
- .resume = teles_resume,
-};
-module_pcmcia_driver(teles_cs_driver);
diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c
deleted file mode 100644
index 33eeb4602c7e..000000000000
--- a/drivers/isdn/hisax/telespci.c
+++ /dev/null
@@ -1,349 +0,0 @@
-/* $Id: telespci.c,v 2.23.2.3 2004/01/13 14:31:26 keil Exp $
- *
- * low level stuff for Teles PCI isdn cards
- *
- * Author Ton van Rosmalen
- * Karsten Keil
- * Copyright by Ton van Rosmalen
- * by Karsten Keil <keil@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/init.h>
-#include "hisax.h"
-#include "isac.h"
-#include "hscx.h"
-#include "isdnl1.h"
-#include <linux/pci.h>
-
-static const char *telespci_revision = "$Revision: 2.23.2.3 $";
-
-#define ZORAN_PO_RQ_PEN 0x02000000
-#define ZORAN_PO_WR 0x00800000
-#define ZORAN_PO_GID0 0x00000000
-#define ZORAN_PO_GID1 0x00100000
-#define ZORAN_PO_GREG0 0x00000000
-#define ZORAN_PO_GREG1 0x00010000
-#define ZORAN_PO_DMASK 0xFF
-
-#define WRITE_ADDR_ISAC (ZORAN_PO_WR | ZORAN_PO_GID0 | ZORAN_PO_GREG0)
-#define READ_DATA_ISAC (ZORAN_PO_GID0 | ZORAN_PO_GREG1)
-#define WRITE_DATA_ISAC (ZORAN_PO_WR | ZORAN_PO_GID0 | ZORAN_PO_GREG1)
-#define WRITE_ADDR_HSCX (ZORAN_PO_WR | ZORAN_PO_GID1 | ZORAN_PO_GREG0)
-#define READ_DATA_HSCX (ZORAN_PO_GID1 | ZORAN_PO_GREG1)
-#define WRITE_DATA_HSCX (ZORAN_PO_WR | ZORAN_PO_GID1 | ZORAN_PO_GREG1)
-
-#define ZORAN_WAIT_NOBUSY do { \
- portdata = readl(adr + 0x200); \
- } while (portdata & ZORAN_PO_RQ_PEN)
-
-static inline u_char
-readisac(void __iomem *adr, u_char off)
-{
- register unsigned int portdata;
-
- ZORAN_WAIT_NOBUSY;
-
- /* set address for ISAC */
- writel(WRITE_ADDR_ISAC | off, adr + 0x200);
- ZORAN_WAIT_NOBUSY;
-
- /* read data from ISAC */
- writel(READ_DATA_ISAC, adr + 0x200);
- ZORAN_WAIT_NOBUSY;
- return ((u_char)(portdata & ZORAN_PO_DMASK));
-}
-
-static inline void
-writeisac(void __iomem *adr, u_char off, u_char data)
-{
- register unsigned int portdata;
-
- ZORAN_WAIT_NOBUSY;
-
- /* set address for ISAC */
- writel(WRITE_ADDR_ISAC | off, adr + 0x200);
- ZORAN_WAIT_NOBUSY;
-
- /* write data to ISAC */
- writel(WRITE_DATA_ISAC | data, adr + 0x200);
- ZORAN_WAIT_NOBUSY;
-}
-
-static inline u_char
-readhscx(void __iomem *adr, int hscx, u_char off)
-{
- register unsigned int portdata;
-
- ZORAN_WAIT_NOBUSY;
- /* set address for HSCX */
- writel(WRITE_ADDR_HSCX | ((hscx ? 0x40 : 0) + off), adr + 0x200);
- ZORAN_WAIT_NOBUSY;
-
- /* read data from HSCX */
- writel(READ_DATA_HSCX, adr + 0x200);
- ZORAN_WAIT_NOBUSY;
- return ((u_char)(portdata & ZORAN_PO_DMASK));
-}
-
-static inline void
-writehscx(void __iomem *adr, int hscx, u_char off, u_char data)
-{
- register unsigned int portdata;
-
- ZORAN_WAIT_NOBUSY;
- /* set address for HSCX */
- writel(WRITE_ADDR_HSCX | ((hscx ? 0x40 : 0) + off), adr + 0x200);
- ZORAN_WAIT_NOBUSY;
-
- /* write data to HSCX */
- writel(WRITE_DATA_HSCX | data, adr + 0x200);
- ZORAN_WAIT_NOBUSY;
-}
-
-static inline void
-read_fifo_isac(void __iomem *adr, u_char *data, int size)
-{
- register unsigned int portdata;
- register int i;
-
- ZORAN_WAIT_NOBUSY;
- /* read data from ISAC */
- for (i = 0; i < size; i++) {
- /* set address for ISAC fifo */
- writel(WRITE_ADDR_ISAC | 0x1E, adr + 0x200);
- ZORAN_WAIT_NOBUSY;
- writel(READ_DATA_ISAC, adr + 0x200);
- ZORAN_WAIT_NOBUSY;
- data[i] = (u_char)(portdata & ZORAN_PO_DMASK);
- }
-}
-
-static void
-write_fifo_isac(void __iomem *adr, u_char *data, int size)
-{
- register unsigned int portdata;
- register int i;
-
- ZORAN_WAIT_NOBUSY;
- /* write data to ISAC */
- for (i = 0; i < size; i++) {
- /* set address for ISAC fifo */
- writel(WRITE_ADDR_ISAC | 0x1E, adr + 0x200);
- ZORAN_WAIT_NOBUSY;
- writel(WRITE_DATA_ISAC | data[i], adr + 0x200);
- ZORAN_WAIT_NOBUSY;
- }
-}
-
-static inline void
-read_fifo_hscx(void __iomem *adr, int hscx, u_char *data, int size)
-{
- register unsigned int portdata;
- register int i;
-
- ZORAN_WAIT_NOBUSY;
- /* read data from HSCX */
- for (i = 0; i < size; i++) {
- /* set address for HSCX fifo */
- writel(WRITE_ADDR_HSCX | (hscx ? 0x5F : 0x1F), adr + 0x200);
- ZORAN_WAIT_NOBUSY;
- writel(READ_DATA_HSCX, adr + 0x200);
- ZORAN_WAIT_NOBUSY;
- data[i] = (u_char) (portdata & ZORAN_PO_DMASK);
- }
-}
-
-static inline void
-write_fifo_hscx(void __iomem *adr, int hscx, u_char *data, int size)
-{
- unsigned int portdata;
- register int i;
-
- ZORAN_WAIT_NOBUSY;
- /* write data to HSCX */
- for (i = 0; i < size; i++) {
- /* set address for HSCX fifo */
- writel(WRITE_ADDR_HSCX | (hscx ? 0x5F : 0x1F), adr + 0x200);
- ZORAN_WAIT_NOBUSY;
- writel(WRITE_DATA_HSCX | data[i], adr + 0x200);
- ZORAN_WAIT_NOBUSY;
- udelay(10);
- }
-}
-
-/* Interface functions */
-
-static u_char
-ReadISAC(struct IsdnCardState *cs, u_char offset)
-{
- return (readisac(cs->hw.teles0.membase, offset));
-}
-
-static void
-WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
-{
- writeisac(cs->hw.teles0.membase, offset, value);
-}
-
-static void
-ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- read_fifo_isac(cs->hw.teles0.membase, data, size);
-}
-
-static void
-WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- write_fifo_isac(cs->hw.teles0.membase, data, size);
-}
-
-static u_char
-ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
-{
- return (readhscx(cs->hw.teles0.membase, hscx, offset));
-}
-
-static void
-WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
-{
- writehscx(cs->hw.teles0.membase, hscx, offset, value);
-}
-
-/*
- * fast interrupt HSCX stuff goes here
- */
-
-#define READHSCX(cs, nr, reg) readhscx(cs->hw.teles0.membase, nr, reg)
-#define WRITEHSCX(cs, nr, reg, data) writehscx(cs->hw.teles0.membase, nr, reg, data)
-#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt)
-#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt)
-
-#include "hscx_irq.c"
-
-static irqreturn_t
-telespci_interrupt(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_char hval, ival;
- u_long flags;
-
- spin_lock_irqsave(&cs->lock, flags);
- hval = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA);
- if (hval)
- hscx_int_main(cs, hval);
- ival = readisac(cs->hw.teles0.membase, ISAC_ISTA);
- if ((hval | ival) == 0) {
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_NONE;
- }
- if (ival)
- isac_interrupt(cs, ival);
- /* Clear interrupt register for Zoran PCI controller */
- writel(0x70000000, cs->hw.teles0.membase + 0x3C);
-
- writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0xFF);
- writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0xFF);
- writeisac(cs->hw.teles0.membase, ISAC_MASK, 0xFF);
- writeisac(cs->hw.teles0.membase, ISAC_MASK, 0x0);
- writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0x0);
- writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0x0);
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static void
-release_io_telespci(struct IsdnCardState *cs)
-{
- iounmap(cs->hw.teles0.membase);
-}
-
-static int
-TelesPCI_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
- u_long flags;
-
- switch (mt) {
- case CARD_RESET:
- return (0);
- case CARD_RELEASE:
- release_io_telespci(cs);
- return (0);
- case CARD_INIT:
- spin_lock_irqsave(&cs->lock, flags);
- inithscxisac(cs, 3);
- spin_unlock_irqrestore(&cs->lock, flags);
- return (0);
- case CARD_TEST:
- return (0);
- }
- return (0);
-}
-
-static struct pci_dev *dev_tel = NULL;
-
-int setup_telespci(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
-
- strcpy(tmp, telespci_revision);
- printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp));
- if (cs->typ != ISDN_CTYPE_TELESPCI)
- return (0);
-
- if ((dev_tel = hisax_find_pci_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) {
- if (pci_enable_device(dev_tel))
- return (0);
- cs->irq = dev_tel->irq;
- if (!cs->irq) {
- printk(KERN_WARNING "Teles: No IRQ for PCI card found\n");
- return (0);
- }
- cs->hw.teles0.membase = ioremap(pci_resource_start(dev_tel, 0),
- PAGE_SIZE);
- printk(KERN_INFO "Found: Zoran, base-address: 0x%llx, irq: 0x%x\n",
- (unsigned long long)pci_resource_start(dev_tel, 0),
- dev_tel->irq);
- } else {
- printk(KERN_WARNING "TelesPCI: No PCI card found\n");
- return (0);
- }
-
- /* Initialize Zoran PCI controller */
- writel(0x00000000, cs->hw.teles0.membase + 0x28);
- writel(0x01000000, cs->hw.teles0.membase + 0x28);
- writel(0x01000000, cs->hw.teles0.membase + 0x28);
- writel(0x7BFFFFFF, cs->hw.teles0.membase + 0x2C);
- writel(0x70000000, cs->hw.teles0.membase + 0x3C);
- writel(0x61000000, cs->hw.teles0.membase + 0x40);
- /* writel(0x00800000, cs->hw.teles0.membase + 0x200); */
-
- printk(KERN_INFO
- "HiSax: Teles PCI config irq:%d mem:%p\n",
- cs->irq,
- cs->hw.teles0.membase);
-
- setup_isac(cs);
- cs->readisac = &ReadISAC;
- cs->writeisac = &WriteISAC;
- cs->readisacfifo = &ReadISACfifo;
- cs->writeisacfifo = &WriteISACfifo;
- cs->BC_Read_Reg = &ReadHSCX;
- cs->BC_Write_Reg = &WriteHSCX;
- cs->BC_Send_Data = &hscx_fill_fifo;
- cs->cardmsg = &TelesPCI_card_msg;
- cs->irq_func = &telespci_interrupt;
- cs->irq_flags |= IRQF_SHARED;
- ISACVersion(cs, "TelesPCI:");
- if (HscxVersion(cs, "TelesPCI:")) {
- printk(KERN_WARNING
- "TelesPCI: wrong HSCX versions check IO/MEM addresses\n");
- release_io_telespci(cs);
- return (0);
- }
- return (1);
-}
diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c
deleted file mode 100644
index 36eefaa3a7d9..000000000000
--- a/drivers/isdn/hisax/w6692.c
+++ /dev/null
@@ -1,1085 +0,0 @@
-/* $Id: w6692.c,v 1.18.2.4 2004/02/11 13:21:34 keil Exp $
- *
- * Winbond W6692 specific routines
- *
- * Author Petr Novak
- * Copyright by Petr Novak <petr.novak@i.cz>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/init.h>
-#include "hisax.h"
-#include "w6692.h"
-#include "isdnl1.h"
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-
-/* table entry in the PCI devices list */
-typedef struct {
- int vendor_id;
- int device_id;
- char *vendor_name;
- char *card_name;
-} PCI_ENTRY;
-
-static const PCI_ENTRY id_list[] =
-{
- {PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692, "Winbond", "W6692"},
- {PCI_VENDOR_ID_DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH, "Dynalink/AsusCom", "IS64PH"},
- {0, 0, "U.S.Robotics", "ISDN PCI Card TA"}
-};
-
-#define W6692_SV_USR 0x16ec
-#define W6692_SD_USR 0x3409
-#define W6692_WINBOND 0
-#define W6692_DYNALINK 1
-#define W6692_USR 2
-
-static const char *w6692_revision = "$Revision: 1.18.2.4 $";
-
-#define DBUSY_TIMER_VALUE 80
-
-static char *W6692Ver[] =
-{"W6692 V00", "W6692 V01", "W6692 V10",
- "W6692 V11"};
-
-static void
-W6692Version(struct IsdnCardState *cs, char *s)
-{
- int val;
-
- val = cs->readW6692(cs, W_D_RBCH);
- printk(KERN_INFO "%s Winbond W6692 version (%x): %s\n", s, val, W6692Ver[(val >> 6) & 3]);
-}
-
-static void
-ph_command(struct IsdnCardState *cs, unsigned int command)
-{
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ph_command %x", command);
- cs->writeisac(cs, W_CIX, command);
-}
-
-
-static void
-W6692_new_ph(struct IsdnCardState *cs)
-{
- switch (cs->dc.w6692.ph_state) {
- case (W_L1CMD_RST):
- ph_command(cs, W_L1CMD_DRC);
- l1_msg(cs, HW_RESET | INDICATION, NULL);
- /* fall through */
- case (W_L1IND_CD):
- l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
- break;
- case (W_L1IND_DRD):
- l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
- break;
- case (W_L1IND_CE):
- l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
- break;
- case (W_L1IND_LD):
- l1_msg(cs, HW_RSYNC | INDICATION, NULL);
- break;
- case (W_L1IND_ARD):
- l1_msg(cs, HW_INFO2 | INDICATION, NULL);
- break;
- case (W_L1IND_AI8):
- l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
- break;
- case (W_L1IND_AI10):
- l1_msg(cs, HW_INFO4_P10 | INDICATION, NULL);
- break;
- default:
- break;
- }
-}
-
-static void
-W6692_bh(struct work_struct *work)
-{
- struct IsdnCardState *cs =
- container_of(work, struct IsdnCardState, tqueue);
- struct PStack *stptr;
-
- if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
- if (cs->debug)
- debugl1(cs, "D-Channel Busy cleared");
- stptr = cs->stlist;
- while (stptr != NULL) {
- stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
- stptr = stptr->next;
- }
- }
- if (test_and_clear_bit(D_L1STATECHANGE, &cs->event))
- W6692_new_ph(cs);
- if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
- DChannel_proc_rcv(cs);
- if (test_and_clear_bit(D_XMTBUFREADY, &cs->event))
- DChannel_proc_xmt(cs);
-/*
- if (test_and_clear_bit(D_RX_MON1, &cs->event))
- arcofi_fsm(cs, ARCOFI_RX_END, NULL);
- if (test_and_clear_bit(D_TX_MON1, &cs->event))
- arcofi_fsm(cs, ARCOFI_TX_END, NULL);
-*/
-}
-
-static void
-W6692_empty_fifo(struct IsdnCardState *cs, int count)
-{
- u_char *ptr;
-
- if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
- debugl1(cs, "W6692_empty_fifo");
-
- if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "W6692_empty_fifo overrun %d",
- cs->rcvidx + count);
- cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RACK);
- cs->rcvidx = 0;
- return;
- }
- ptr = cs->rcvbuf + cs->rcvidx;
- cs->rcvidx += count;
- cs->readW6692fifo(cs, ptr, count);
- cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RACK);
- if (cs->debug & L1_DEB_ISAC_FIFO) {
- char *t = cs->dlog;
-
- t += sprintf(t, "W6692_empty_fifo cnt %d", count);
- QuickHex(t, ptr, count);
- debugl1(cs, "%s", cs->dlog);
- }
-}
-
-static void
-W6692_fill_fifo(struct IsdnCardState *cs)
-{
- int count, more;
- u_char *ptr;
-
- if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
- debugl1(cs, "W6692_fill_fifo");
-
- if (!cs->tx_skb)
- return;
-
- count = cs->tx_skb->len;
- if (count <= 0)
- return;
-
- more = 0;
- if (count > W_D_FIFO_THRESH) {
- more = !0;
- count = W_D_FIFO_THRESH;
- }
- ptr = cs->tx_skb->data;
- skb_pull(cs->tx_skb, count);
- cs->tx_cnt += count;
- cs->writeW6692fifo(cs, ptr, count);
- cs->writeW6692(cs, W_D_CMDR, more ? W_D_CMDR_XMS : (W_D_CMDR_XMS | W_D_CMDR_XME));
- if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
- debugl1(cs, "W6692_fill_fifo dbusytimer running");
- del_timer(&cs->dbusytimer);
- }
- cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ) / 1000);
- add_timer(&cs->dbusytimer);
- if (cs->debug & L1_DEB_ISAC_FIFO) {
- char *t = cs->dlog;
-
- t += sprintf(t, "W6692_fill_fifo cnt %d", count);
- QuickHex(t, ptr, count);
- debugl1(cs, "%s", cs->dlog);
- }
-}
-
-static void
-W6692B_empty_fifo(struct BCState *bcs, int count)
-{
- u_char *ptr;
- struct IsdnCardState *cs = bcs->cs;
-
- if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
- debugl1(cs, "W6692B_empty_fifo");
-
- if (bcs->hw.w6692.rcvidx + count > HSCX_BUFMAX) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "W6692B_empty_fifo: incoming packet too large");
- cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
- bcs->hw.w6692.rcvidx = 0;
- return;
- }
- ptr = bcs->hw.w6692.rcvbuf + bcs->hw.w6692.rcvidx;
- bcs->hw.w6692.rcvidx += count;
- READW6692BFIFO(cs, bcs->channel, ptr, count);
- cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
- if (cs->debug & L1_DEB_HSCX_FIFO) {
- char *t = bcs->blog;
-
- t += sprintf(t, "W6692B_empty_fifo %c cnt %d",
- bcs->channel + '1', count);
- QuickHex(t, ptr, count);
- debugl1(cs, "%s", bcs->blog);
- }
-}
-
-static void
-W6692B_fill_fifo(struct BCState *bcs)
-{
- struct IsdnCardState *cs = bcs->cs;
- int more, count;
- u_char *ptr;
-
- if (!bcs->tx_skb)
- return;
- if (bcs->tx_skb->len <= 0)
- return;
-
- more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
- if (bcs->tx_skb->len > W_B_FIFO_THRESH) {
- more = 1;
- count = W_B_FIFO_THRESH;
- } else
- count = bcs->tx_skb->len;
-
- if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
- debugl1(cs, "W6692B_fill_fifo%s%d", (more ? " " : " last "), count);
-
- ptr = bcs->tx_skb->data;
- skb_pull(bcs->tx_skb, count);
- bcs->tx_cnt -= count;
- bcs->hw.w6692.count += count;
- WRITEW6692BFIFO(cs, bcs->channel, ptr, count);
- cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACT | W_B_CMDR_XMS | (more ? 0 : W_B_CMDR_XME));
- if (cs->debug & L1_DEB_HSCX_FIFO) {
- char *t = bcs->blog;
-
- t += sprintf(t, "W6692B_fill_fifo %c cnt %d",
- bcs->channel + '1', count);
- QuickHex(t, ptr, count);
- debugl1(cs, "%s", bcs->blog);
- }
-}
-
-static void
-W6692B_interrupt(struct IsdnCardState *cs, u_char bchan)
-{
- u_char val;
- u_char r;
- struct BCState *bcs;
- struct sk_buff *skb;
- int count;
-
- bcs = (cs->bcs->channel == bchan) ? cs->bcs : (cs->bcs + 1);
- val = cs->BC_Read_Reg(cs, bchan, W_B_EXIR);
- debugl1(cs, "W6692B chan %d B_EXIR 0x%02X", bchan, val);
-
- if (!test_bit(BC_FLG_INIT, &bcs->Flag)) {
- debugl1(cs, "W6692B not INIT yet");
- return;
- }
- if (val & W_B_EXI_RME) { /* RME */
- r = cs->BC_Read_Reg(cs, bchan, W_B_STAR);
- if (r & (W_B_STAR_RDOV | W_B_STAR_CRCE | W_B_STAR_RMB)) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "W6692 B STAR %x", r);
- if ((r & W_B_STAR_RDOV) && bcs->mode)
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "W6692 B RDOV mode=%d",
- bcs->mode);
- if (r & W_B_STAR_CRCE)
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "W6692 B CRC error");
- cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RRST | W_B_CMDR_RACT);
- } else {
- count = cs->BC_Read_Reg(cs, bchan, W_B_RBCL) & (W_B_FIFO_THRESH - 1);
- if (count == 0)
- count = W_B_FIFO_THRESH;
- W6692B_empty_fifo(bcs, count);
- if ((count = bcs->hw.w6692.rcvidx) > 0) {
- if (cs->debug & L1_DEB_HSCX_FIFO)
- debugl1(cs, "W6692 Bchan Frame %d", count);
- if (!(skb = dev_alloc_skb(count)))
- printk(KERN_WARNING "W6692: Bchan receive out of memory\n");
- else {
- skb_put_data(skb,
- bcs->hw.w6692.rcvbuf,
- count);
- skb_queue_tail(&bcs->rqueue, skb);
- }
- }
- }
- bcs->hw.w6692.rcvidx = 0;
- schedule_event(bcs, B_RCVBUFREADY);
- }
- if (val & W_B_EXI_RMR) { /* RMR */
- W6692B_empty_fifo(bcs, W_B_FIFO_THRESH);
- r = cs->BC_Read_Reg(cs, bchan, W_B_STAR);
- if (r & W_B_STAR_RDOV) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "W6692 B RDOV(RMR) mode=%d", bcs->mode);
- cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RRST | W_B_CMDR_RACT);
- if (bcs->mode != L1_MODE_TRANS)
- bcs->hw.w6692.rcvidx = 0;
- }
- if (bcs->mode == L1_MODE_TRANS) {
- /* receive audio data */
- if (!(skb = dev_alloc_skb(W_B_FIFO_THRESH)))
- printk(KERN_WARNING "HiSax: receive out of memory\n");
- else {
- skb_put_data(skb, bcs->hw.w6692.rcvbuf,
- W_B_FIFO_THRESH);
- skb_queue_tail(&bcs->rqueue, skb);
- }
- bcs->hw.w6692.rcvidx = 0;
- schedule_event(bcs, B_RCVBUFREADY);
- }
- }
- if (val & W_B_EXI_XDUN) { /* XDUN */
- cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT);
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "W6692 B EXIR %x Lost TX", val);
- if (bcs->mode == 1)
- W6692B_fill_fifo(bcs);
- else {
- /* Here we lost an TX interrupt, so
- * restart transmitting the whole frame.
- */
- if (bcs->tx_skb) {
- skb_push(bcs->tx_skb, bcs->hw.w6692.count);
- bcs->tx_cnt += bcs->hw.w6692.count;
- bcs->hw.w6692.count = 0;
- }
- }
- return;
- }
- if (val & W_B_EXI_XFR) { /* XFR */
- r = cs->BC_Read_Reg(cs, bchan, W_B_STAR);
- if (r & W_B_STAR_XDOW) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "W6692 B STAR %x XDOW", r);
- cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT);
- if (bcs->tx_skb && (bcs->mode != 1)) {
- skb_push(bcs->tx_skb, bcs->hw.w6692.count);
- bcs->tx_cnt += bcs->hw.w6692.count;
- bcs->hw.w6692.count = 0;
- }
- }
- if (bcs->tx_skb) {
- if (bcs->tx_skb->len) {
- W6692B_fill_fifo(bcs);
- return;
- } else {
- if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
- (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
- u_long flags;
- spin_lock_irqsave(&bcs->aclock, flags);
- bcs->ackcnt += bcs->hw.w6692.count;
- spin_unlock_irqrestore(&bcs->aclock, flags);
- schedule_event(bcs, B_ACKPENDING);
- }
- dev_kfree_skb_irq(bcs->tx_skb);
- bcs->hw.w6692.count = 0;
- bcs->tx_skb = NULL;
- }
- }
- if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
- bcs->hw.w6692.count = 0;
- test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
- W6692B_fill_fifo(bcs);
- } else {
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- schedule_event(bcs, B_XMTBUFREADY);
- }
- }
-}
-
-static irqreturn_t
-W6692_interrupt(int intno, void *dev_id)
-{
- struct IsdnCardState *cs = dev_id;
- u_char val, exval, v1;
- struct sk_buff *skb;
- u_int count;
- u_long flags;
- int icnt = 5;
-
- spin_lock_irqsave(&cs->lock, flags);
- val = cs->readW6692(cs, W_ISTA);
- if (!val) {
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_NONE;
- }
-StartW6692:
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "W6692 ISTA %x", val);
-
- if (val & W_INT_D_RME) { /* RME */
- exval = cs->readW6692(cs, W_D_RSTA);
- if (exval & (W_D_RSTA_RDOV | W_D_RSTA_CRCE | W_D_RSTA_RMB)) {
- if (exval & W_D_RSTA_RDOV)
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "W6692 RDOV");
- if (exval & W_D_RSTA_CRCE)
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "W6692 D-channel CRC error");
- if (exval & W_D_RSTA_RMB)
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "W6692 D-channel ABORT");
- cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RACK | W_D_CMDR_RRST);
- } else {
- count = cs->readW6692(cs, W_D_RBCL) & (W_D_FIFO_THRESH - 1);
- if (count == 0)
- count = W_D_FIFO_THRESH;
- W6692_empty_fifo(cs, count);
- if ((count = cs->rcvidx) > 0) {
- cs->rcvidx = 0;
- if (!(skb = alloc_skb(count, GFP_ATOMIC)))
- printk(KERN_WARNING "HiSax: D receive out of memory\n");
- else {
- skb_put_data(skb, cs->rcvbuf, count);
- skb_queue_tail(&cs->rq, skb);
- }
- }
- }
- cs->rcvidx = 0;
- schedule_event(cs, D_RCVBUFREADY);
- }
- if (val & W_INT_D_RMR) { /* RMR */
- W6692_empty_fifo(cs, W_D_FIFO_THRESH);
- }
- if (val & W_INT_D_XFR) { /* XFR */
- if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
- del_timer(&cs->dbusytimer);
- if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
- schedule_event(cs, D_CLEARBUSY);
- if (cs->tx_skb) {
- if (cs->tx_skb->len) {
- W6692_fill_fifo(cs);
- goto afterXFR;
- } else {
- dev_kfree_skb_irq(cs->tx_skb);
- cs->tx_cnt = 0;
- cs->tx_skb = NULL;
- }
- }
- if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
- cs->tx_cnt = 0;
- W6692_fill_fifo(cs);
- } else
- schedule_event(cs, D_XMTBUFREADY);
- }
-afterXFR:
- if (val & (W_INT_XINT0 | W_INT_XINT1)) { /* XINT0/1 - never */
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "W6692 spurious XINT!");
- }
- if (val & W_INT_D_EXI) { /* EXI */
- exval = cs->readW6692(cs, W_D_EXIR);
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "W6692 D_EXIR %02x", exval);
- if (exval & (W_D_EXI_XDUN | W_D_EXI_XCOL)) { /* Transmit underrun/collision */
- debugl1(cs, "W6692 D-chan underrun/collision");
- printk(KERN_WARNING "HiSax: W6692 XDUN/XCOL\n");
- if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
- del_timer(&cs->dbusytimer);
- if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
- schedule_event(cs, D_CLEARBUSY);
- if (cs->tx_skb) { /* Restart frame */
- skb_push(cs->tx_skb, cs->tx_cnt);
- cs->tx_cnt = 0;
- W6692_fill_fifo(cs);
- } else {
- printk(KERN_WARNING "HiSax: W6692 XDUN/XCOL no skb\n");
- debugl1(cs, "W6692 XDUN/XCOL no skb");
- cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_XRST);
- }
- }
- if (exval & W_D_EXI_RDOV) { /* RDOV */
- debugl1(cs, "W6692 D-channel RDOV");
- printk(KERN_WARNING "HiSax: W6692 D-RDOV\n");
- cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RRST);
- }
- if (exval & W_D_EXI_TIN2) { /* TIN2 - never */
- debugl1(cs, "W6692 spurious TIN2 interrupt");
- }
- if (exval & W_D_EXI_MOC) { /* MOC - not supported */
- debugl1(cs, "W6692 spurious MOC interrupt");
- v1 = cs->readW6692(cs, W_MOSR);
- debugl1(cs, "W6692 MOSR %02x", v1);
- }
- if (exval & W_D_EXI_ISC) { /* ISC - Level1 change */
- v1 = cs->readW6692(cs, W_CIR);
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "W6692 ISC CIR=0x%02X", v1);
- if (v1 & W_CIR_ICC) {
- cs->dc.w6692.ph_state = v1 & W_CIR_COD_MASK;
- if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ph_state_change %x", cs->dc.w6692.ph_state);
- schedule_event(cs, D_L1STATECHANGE);
- }
- if (v1 & W_CIR_SCC) {
- v1 = cs->readW6692(cs, W_SQR);
- debugl1(cs, "W6692 SCC SQR=0x%02X", v1);
- }
- }
- if (exval & W_D_EXI_WEXP) {
- debugl1(cs, "W6692 spurious WEXP interrupt!");
- }
- if (exval & W_D_EXI_TEXP) {
- debugl1(cs, "W6692 spurious TEXP interrupt!");
- }
- }
- if (val & W_INT_B1_EXI) {
- debugl1(cs, "W6692 B channel 1 interrupt");
- W6692B_interrupt(cs, 0);
- }
- if (val & W_INT_B2_EXI) {
- debugl1(cs, "W6692 B channel 2 interrupt");
- W6692B_interrupt(cs, 1);
- }
- val = cs->readW6692(cs, W_ISTA);
- if (val && icnt) {
- icnt--;
- goto StartW6692;
- }
- if (!icnt) {
- printk(KERN_WARNING "W6692 IRQ LOOP\n");
- cs->writeW6692(cs, W_IMASK, 0xff);
- }
- spin_unlock_irqrestore(&cs->lock, flags);
- return IRQ_HANDLED;
-}
-
-static void
-W6692_l1hw(struct PStack *st, int pr, void *arg)
-{
- struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
- struct sk_buff *skb = arg;
- u_long flags;
- int val;
-
- switch (pr) {
- case (PH_DATA | REQUEST):
- if (cs->debug & DEB_DLOG_HEX)
- LogFrame(cs, skb->data, skb->len);
- if (cs->debug & DEB_DLOG_VERBOSE)
- dlogframe(cs, skb, 0);
- spin_lock_irqsave(&cs->lock, flags);
- if (cs->tx_skb) {
- skb_queue_tail(&cs->sq, skb);
-#ifdef L2FRAME_DEBUG /* psa */
- if (cs->debug & L1_DEB_LAPD)
- Logl2Frame(cs, skb, "PH_DATA Queued", 0);
-#endif
- } else {
- cs->tx_skb = skb;
- cs->tx_cnt = 0;
-#ifdef L2FRAME_DEBUG /* psa */
- if (cs->debug & L1_DEB_LAPD)
- Logl2Frame(cs, skb, "PH_DATA", 0);
-#endif
- W6692_fill_fifo(cs);
- }
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (PH_PULL | INDICATION):
- spin_lock_irqsave(&cs->lock, flags);
- if (cs->tx_skb) {
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
- skb_queue_tail(&cs->sq, skb);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- }
- if (cs->debug & DEB_DLOG_HEX)
- LogFrame(cs, skb->data, skb->len);
- if (cs->debug & DEB_DLOG_VERBOSE)
- dlogframe(cs, skb, 0);
- cs->tx_skb = skb;
- cs->tx_cnt = 0;
-#ifdef L2FRAME_DEBUG /* psa */
- if (cs->debug & L1_DEB_LAPD)
- Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
-#endif
- W6692_fill_fifo(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (PH_PULL | REQUEST):
-#ifdef L2FRAME_DEBUG /* psa */
- if (cs->debug & L1_DEB_LAPD)
- debugl1(cs, "-> PH_REQUEST_PULL");
-#endif
- if (!cs->tx_skb) {
- test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
- } else
- test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- break;
- case (HW_RESET | REQUEST):
- spin_lock_irqsave(&cs->lock, flags);
- if (cs->dc.w6692.ph_state == W_L1IND_DRD) {
- ph_command(cs, W_L1CMD_ECK);
- spin_unlock_irqrestore(&cs->lock, flags);
- } else {
- ph_command(cs, W_L1CMD_RST);
- cs->dc.w6692.ph_state = W_L1CMD_RST;
- spin_unlock_irqrestore(&cs->lock, flags);
- W6692_new_ph(cs);
- }
- break;
- case (HW_ENABLE | REQUEST):
- spin_lock_irqsave(&cs->lock, flags);
- ph_command(cs, W_L1CMD_ECK);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (HW_INFO3 | REQUEST):
- spin_lock_irqsave(&cs->lock, flags);
- ph_command(cs, W_L1CMD_AR8);
- spin_unlock_irqrestore(&cs->lock, flags);
- break;
- case (HW_TESTLOOP | REQUEST):
- val = 0;
- if (1 & (long) arg)
- val |= 0x0c;
- if (2 & (long) arg)
- val |= 0x3;
- /* !!! not implemented yet */
- break;
- case (HW_DEACTIVATE | RESPONSE):
- skb_queue_purge(&cs->rq);
- skb_queue_purge(&cs->sq);
- if (cs->tx_skb) {
- dev_kfree_skb_any(cs->tx_skb);
- cs->tx_skb = NULL;
- }
- if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
- del_timer(&cs->dbusytimer);
- if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
- schedule_event(cs, D_CLEARBUSY);
- break;
- default:
- if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "W6692_l1hw unknown %04x", pr);
- break;
- }
-}
-
-static void
-setstack_W6692(struct PStack *st, struct IsdnCardState *cs)
-{
- st->l1.l1hw = W6692_l1hw;
-}
-
-static void
-DC_Close_W6692(struct IsdnCardState *cs)
-{
-}
-
-static void
-dbusy_timer_handler(struct timer_list *t)
-{
- struct IsdnCardState *cs = from_timer(cs, t, dbusytimer);
- struct PStack *stptr;
- int rbch, star;
- u_long flags;
-
- spin_lock_irqsave(&cs->lock, flags);
- if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
- rbch = cs->readW6692(cs, W_D_RBCH);
- star = cs->readW6692(cs, W_D_STAR);
- if (cs->debug)
- debugl1(cs, "D-Channel Busy D_RBCH %02x D_STAR %02x",
- rbch, star);
- if (star & W_D_STAR_XBZ) { /* D-Channel Busy */
- test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
- stptr = cs->stlist;
- while (stptr != NULL) {
- stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
- stptr = stptr->next;
- }
- } else {
- /* discard frame; reset transceiver */
- test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
- if (cs->tx_skb) {
- dev_kfree_skb_any(cs->tx_skb);
- cs->tx_cnt = 0;
- cs->tx_skb = NULL;
- } else {
- printk(KERN_WARNING "HiSax: W6692 D-Channel Busy no skb\n");
- debugl1(cs, "D-Channel Busy no skb");
- }
- cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_XRST); /* Transmitter reset */
- spin_unlock_irqrestore(&cs->lock, flags);
- cs->irq_func(cs->irq, cs);
- return;
- }
- }
- spin_unlock_irqrestore(&cs->lock, flags);
-}
-
-static void
-W6692Bmode(struct BCState *bcs, int mode, int bchan)
-{
- struct IsdnCardState *cs = bcs->cs;
-
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "w6692 %c mode %d ichan %d",
- '1' + bchan, mode, bchan);
- bcs->mode = mode;
- bcs->channel = bchan;
- bcs->hw.w6692.bchan = bchan;
-
- switch (mode) {
- case (L1_MODE_NULL):
- cs->BC_Write_Reg(cs, bchan, W_B_MODE, 0);
- break;
- case (L1_MODE_TRANS):
- cs->BC_Write_Reg(cs, bchan, W_B_MODE, W_B_MODE_MMS);
- break;
- case (L1_MODE_HDLC):
- cs->BC_Write_Reg(cs, bchan, W_B_MODE, W_B_MODE_ITF);
- cs->BC_Write_Reg(cs, bchan, W_B_ADM1, 0xff);
- cs->BC_Write_Reg(cs, bchan, W_B_ADM2, 0xff);
- break;
- }
- if (mode)
- cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_RRST |
- W_B_CMDR_RACT | W_B_CMDR_XRST);
- cs->BC_Write_Reg(cs, bchan, W_B_EXIM, 0x00);
-}
-
-static void
-W6692_l2l1(struct PStack *st, int pr, void *arg)
-{
- struct sk_buff *skb = arg;
- struct BCState *bcs = st->l1.bcs;
- u_long flags;
-
- switch (pr) {
- case (PH_DATA | REQUEST):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- if (bcs->tx_skb) {
- skb_queue_tail(&bcs->squeue, skb);
- } else {
- bcs->tx_skb = skb;
- test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->hw.w6692.count = 0;
- bcs->cs->BC_Send_Data(bcs);
- }
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- break;
- case (PH_PULL | INDICATION):
- if (bcs->tx_skb) {
- printk(KERN_WARNING "W6692_l2l1: this shouldn't happen\n");
- break;
- }
- spin_lock_irqsave(&bcs->cs->lock, flags);
- test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->tx_skb = skb;
- bcs->hw.w6692.count = 0;
- bcs->cs->BC_Send_Data(bcs);
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- break;
- case (PH_PULL | REQUEST):
- if (!bcs->tx_skb) {
- test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
- } else
- test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
- break;
- case (PH_ACTIVATE | REQUEST):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
- W6692Bmode(bcs, st->l1.mode, st->l1.bc);
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- l1_msg_b(st, pr, arg);
- break;
- case (PH_DEACTIVATE | REQUEST):
- l1_msg_b(st, pr, arg);
- break;
- case (PH_DEACTIVATE | CONFIRM):
- spin_lock_irqsave(&bcs->cs->lock, flags);
- test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- W6692Bmode(bcs, 0, st->l1.bc);
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
- st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
- break;
- }
-}
-
-static void
-close_w6692state(struct BCState *bcs)
-{
- W6692Bmode(bcs, 0, bcs->channel);
- if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
- kfree(bcs->hw.w6692.rcvbuf);
- bcs->hw.w6692.rcvbuf = NULL;
- kfree(bcs->blog);
- bcs->blog = NULL;
- skb_queue_purge(&bcs->rqueue);
- skb_queue_purge(&bcs->squeue);
- if (bcs->tx_skb) {
- dev_kfree_skb_any(bcs->tx_skb);
- bcs->tx_skb = NULL;
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- }
- }
-}
-
-static int
-open_w6692state(struct IsdnCardState *cs, struct BCState *bcs)
-{
- if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
- if (!(bcs->hw.w6692.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
- printk(KERN_WARNING
- "HiSax: No memory for w6692.rcvbuf\n");
- test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
- return (1);
- }
- if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
- printk(KERN_WARNING
- "HiSax: No memory for bcs->blog\n");
- test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
- kfree(bcs->hw.w6692.rcvbuf);
- bcs->hw.w6692.rcvbuf = NULL;
- return (2);
- }
- skb_queue_head_init(&bcs->rqueue);
- skb_queue_head_init(&bcs->squeue);
- }
- bcs->tx_skb = NULL;
- test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- bcs->event = 0;
- bcs->hw.w6692.rcvidx = 0;
- bcs->tx_cnt = 0;
- return (0);
-}
-
-static int
-setstack_w6692(struct PStack *st, struct BCState *bcs)
-{
- bcs->channel = st->l1.bc;
- if (open_w6692state(st->l1.hardware, bcs))
- return (-1);
- st->l1.bcs = bcs;
- st->l2.l2l1 = W6692_l2l1;
- setstack_manager(st);
- bcs->st = st;
- setstack_l1_B(st);
- return (0);
-}
-
-static void resetW6692(struct IsdnCardState *cs)
-{
- cs->writeW6692(cs, W_D_CTL, W_D_CTL_SRST);
- mdelay(10);
- cs->writeW6692(cs, W_D_CTL, 0x00);
- mdelay(10);
- cs->writeW6692(cs, W_IMASK, 0xff);
- cs->writeW6692(cs, W_D_SAM, 0xff);
- cs->writeW6692(cs, W_D_TAM, 0xff);
- cs->writeW6692(cs, W_D_EXIM, 0x00);
- cs->writeW6692(cs, W_D_MODE, W_D_MODE_RACT);
- cs->writeW6692(cs, W_IMASK, 0x18);
- if (cs->subtyp == W6692_USR) {
- /* seems that USR implemented some power control features
- * Pin 79 is connected to the oscilator circuit so we
- * have to handle it here
- */
- cs->writeW6692(cs, W_PCTL, 0x80);
- cs->writeW6692(cs, W_XDATA, 0x00);
- }
-}
-
-static void initW6692(struct IsdnCardState *cs, int part)
-{
- if (part & 1) {
- cs->setstack_d = setstack_W6692;
- cs->DC_Close = DC_Close_W6692;
- timer_setup(&cs->dbusytimer, dbusy_timer_handler, 0);
- resetW6692(cs);
- ph_command(cs, W_L1CMD_RST);
- cs->dc.w6692.ph_state = W_L1CMD_RST;
- W6692_new_ph(cs);
- ph_command(cs, W_L1CMD_ECK);
-
- cs->bcs[0].BC_SetStack = setstack_w6692;
- cs->bcs[1].BC_SetStack = setstack_w6692;
- cs->bcs[0].BC_Close = close_w6692state;
- cs->bcs[1].BC_Close = close_w6692state;
- W6692Bmode(cs->bcs, 0, 0);
- W6692Bmode(cs->bcs + 1, 0, 0);
- }
- if (part & 2) {
- /* Reenable all IRQ */
- cs->writeW6692(cs, W_IMASK, 0x18);
- cs->writeW6692(cs, W_D_EXIM, 0x00);
- cs->BC_Write_Reg(cs, 0, W_B_EXIM, 0x00);
- cs->BC_Write_Reg(cs, 1, W_B_EXIM, 0x00);
- /* Reset D-chan receiver and transmitter */
- cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RRST | W_D_CMDR_XRST);
- }
-}
-
-/* Interface functions */
-
-static u_char
-ReadW6692(struct IsdnCardState *cs, u_char offset)
-{
- return (inb(cs->hw.w6692.iobase + offset));
-}
-
-static void
-WriteW6692(struct IsdnCardState *cs, u_char offset, u_char value)
-{
- outb(value, cs->hw.w6692.iobase + offset);
-}
-
-static void
-ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- insb(cs->hw.w6692.iobase + W_D_RFIFO, data, size);
-}
-
-static void
-WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
-{
- outsb(cs->hw.w6692.iobase + W_D_XFIFO, data, size);
-}
-
-static u_char
-ReadW6692B(struct IsdnCardState *cs, int bchan, u_char offset)
-{
- return (inb(cs->hw.w6692.iobase + (bchan ? 0x40 : 0) + offset));
-}
-
-static void
-WriteW6692B(struct IsdnCardState *cs, int bchan, u_char offset, u_char value)
-{
- outb(value, cs->hw.w6692.iobase + (bchan ? 0x40 : 0) + offset);
-}
-
-static int
-w6692_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
- switch (mt) {
- case CARD_RESET:
- resetW6692(cs);
- return (0);
- case CARD_RELEASE:
- cs->writeW6692(cs, W_IMASK, 0xff);
- release_region(cs->hw.w6692.iobase, 256);
- if (cs->subtyp == W6692_USR) {
- cs->writeW6692(cs, W_XDATA, 0x04);
- }
- return (0);
- case CARD_INIT:
- initW6692(cs, 3);
- return (0);
- case CARD_TEST:
- return (0);
- }
- return (0);
-}
-
-static int id_idx;
-
-static struct pci_dev *dev_w6692 = NULL;
-
-int setup_w6692(struct IsdnCard *card)
-{
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
- u_char found = 0;
- u_char pci_irq = 0;
- u_int pci_ioaddr = 0;
-
- strcpy(tmp, w6692_revision);
- printk(KERN_INFO "HiSax: W6692 driver Rev. %s\n", HiSax_getrev(tmp));
- if (cs->typ != ISDN_CTYPE_W6692)
- return (0);
-
- while (id_list[id_idx].vendor_id) {
- dev_w6692 = hisax_find_pci_device(id_list[id_idx].vendor_id,
- id_list[id_idx].device_id,
- dev_w6692);
- if (dev_w6692) {
- if (pci_enable_device(dev_w6692))
- continue;
- cs->subtyp = id_idx;
- break;
- }
- id_idx++;
- }
- if (dev_w6692) {
- found = 1;
- pci_irq = dev_w6692->irq;
- /* I think address 0 is allways the configuration area */
- /* and address 1 is the real IO space KKe 03.09.99 */
- pci_ioaddr = pci_resource_start(dev_w6692, 1);
- /* USR ISDN PCI card TA need some special handling */
- if (cs->subtyp == W6692_WINBOND) {
- if ((W6692_SV_USR == dev_w6692->subsystem_vendor) &&
- (W6692_SD_USR == dev_w6692->subsystem_device)) {
- cs->subtyp = W6692_USR;
- }
- }
- }
- if (!found) {
- printk(KERN_WARNING "W6692: No PCI card found\n");
- return (0);
- }
- cs->irq = pci_irq;
- if (!cs->irq) {
- printk(KERN_WARNING "W6692: No IRQ for PCI card found\n");
- return (0);
- }
- if (!pci_ioaddr) {
- printk(KERN_WARNING "W6692: NO I/O Base Address found\n");
- return (0);
- }
- cs->hw.w6692.iobase = pci_ioaddr;
- printk(KERN_INFO "Found: %s %s, I/O base: 0x%x, irq: %d\n",
- id_list[cs->subtyp].vendor_name, id_list[cs->subtyp].card_name,
- pci_ioaddr, pci_irq);
- if (!request_region(cs->hw.w6692.iobase, 256, id_list[cs->subtyp].card_name)) {
- printk(KERN_WARNING
- "HiSax: %s I/O ports %x-%x already in use\n",
- id_list[cs->subtyp].card_name,
- cs->hw.w6692.iobase,
- cs->hw.w6692.iobase + 255);
- return (0);
- }
-
- printk(KERN_INFO
- "HiSax: %s config irq:%d I/O:%x\n",
- id_list[cs->subtyp].card_name, cs->irq,
- cs->hw.w6692.iobase);
-
- INIT_WORK(&cs->tqueue, W6692_bh);
- cs->readW6692 = &ReadW6692;
- cs->writeW6692 = &WriteW6692;
- cs->readisacfifo = &ReadISACfifo;
- cs->writeisacfifo = &WriteISACfifo;
- cs->BC_Read_Reg = &ReadW6692B;
- cs->BC_Write_Reg = &WriteW6692B;
- cs->BC_Send_Data = &W6692B_fill_fifo;
- cs->cardmsg = &w6692_card_msg;
- cs->irq_func = &W6692_interrupt;
- cs->irq_flags |= IRQF_SHARED;
- W6692Version(cs, "W6692:");
- printk(KERN_INFO "W6692 ISTA=0x%X\n", ReadW6692(cs, W_ISTA));
- printk(KERN_INFO "W6692 IMASK=0x%X\n", ReadW6692(cs, W_IMASK));
- printk(KERN_INFO "W6692 D_EXIR=0x%X\n", ReadW6692(cs, W_D_EXIR));
- printk(KERN_INFO "W6692 D_EXIM=0x%X\n", ReadW6692(cs, W_D_EXIM));
- printk(KERN_INFO "W6692 D_RSTA=0x%X\n", ReadW6692(cs, W_D_RSTA));
- return (1);
-}
diff --git a/drivers/isdn/hisax/w6692.h b/drivers/isdn/hisax/w6692.h
deleted file mode 100644
index 024b04d33e43..000000000000
--- a/drivers/isdn/hisax/w6692.h
+++ /dev/null
@@ -1,184 +0,0 @@
-/* $Id: w6692.h,v 1.4.2.2 2004/01/12 22:52:29 keil Exp $
- *
- * Winbond W6692 specific defines
- *
- * Author Petr Novak
- * Copyright by Petr Novak <petr.novak@i.cz>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-/* map W6692 functions to ISAC functions */
-#define readW6692 readisac
-#define writeW6692 writeisac
-#define readW6692fifo readisacfifo
-#define writeW6692fifo writeisacfifo
-
-/* B-channel FIFO read/write routines */
-
-#define READW6692BFIFO(cs, bchan, ptr, count) \
- insb(cs->hw.w6692.iobase + W_B_RFIFO + (bchan ? 0x40 : 0), ptr, count)
-
-#define WRITEW6692BFIFO(cs, bchan, ptr, count) \
- outsb(cs->hw.w6692.iobase + W_B_XFIFO + (bchan ? 0x40 : 0), ptr, count)
-
-/* Specifications of W6692 registers */
-
-#define W_D_RFIFO 0x00 /* R */
-#define W_D_XFIFO 0x04 /* W */
-#define W_D_CMDR 0x08 /* W */
-#define W_D_MODE 0x0c /* R/W */
-#define W_D_TIMR 0x10 /* R/W */
-#define W_ISTA 0x14 /* R_clr */
-#define W_IMASK 0x18 /* R/W */
-#define W_D_EXIR 0x1c /* R_clr */
-#define W_D_EXIM 0x20 /* R/W */
-#define W_D_STAR 0x24 /* R */
-#define W_D_RSTA 0x28 /* R */
-#define W_D_SAM 0x2c /* R/W */
-#define W_D_SAP1 0x30 /* R/W */
-#define W_D_SAP2 0x34 /* R/W */
-#define W_D_TAM 0x38 /* R/W */
-#define W_D_TEI1 0x3c /* R/W */
-#define W_D_TEI2 0x40 /* R/W */
-#define W_D_RBCH 0x44 /* R */
-#define W_D_RBCL 0x48 /* R */
-#define W_TIMR2 0x4c /* W */
-#define W_L1_RC 0x50 /* R/W */
-#define W_D_CTL 0x54 /* R/W */
-#define W_CIR 0x58 /* R */
-#define W_CIX 0x5c /* W */
-#define W_SQR 0x60 /* R */
-#define W_SQX 0x64 /* W */
-#define W_PCTL 0x68 /* R/W */
-#define W_MOR 0x6c /* R */
-#define W_MOX 0x70 /* R/W */
-#define W_MOSR 0x74 /* R_clr */
-#define W_MOCR 0x78 /* R/W */
-#define W_GCR 0x7c /* R/W */
-
-#define W_B_RFIFO 0x80 /* R */
-#define W_B_XFIFO 0x84 /* W */
-#define W_B_CMDR 0x88 /* W */
-#define W_B_MODE 0x8c /* R/W */
-#define W_B_EXIR 0x90 /* R_clr */
-#define W_B_EXIM 0x94 /* R/W */
-#define W_B_STAR 0x98 /* R */
-#define W_B_ADM1 0x9c /* R/W */
-#define W_B_ADM2 0xa0 /* R/W */
-#define W_B_ADR1 0xa4 /* R/W */
-#define W_B_ADR2 0xa8 /* R/W */
-#define W_B_RBCL 0xac /* R */
-#define W_B_RBCH 0xb0 /* R */
-
-#define W_XADDR 0xf4 /* R/W */
-#define W_XDATA 0xf8 /* R/W */
-#define W_EPCTL 0xfc /* W */
-
-/* W6692 register bits */
-
-#define W_D_CMDR_XRST 0x01
-#define W_D_CMDR_XME 0x02
-#define W_D_CMDR_XMS 0x08
-#define W_D_CMDR_STT 0x10
-#define W_D_CMDR_RRST 0x40
-#define W_D_CMDR_RACK 0x80
-
-#define W_D_MODE_RLP 0x01
-#define W_D_MODE_DLP 0x02
-#define W_D_MODE_MFD 0x04
-#define W_D_MODE_TEE 0x08
-#define W_D_MODE_TMS 0x10
-#define W_D_MODE_RACT 0x40
-#define W_D_MODE_MMS 0x80
-
-#define W_INT_B2_EXI 0x01
-#define W_INT_B1_EXI 0x02
-#define W_INT_D_EXI 0x04
-#define W_INT_XINT0 0x08
-#define W_INT_XINT1 0x10
-#define W_INT_D_XFR 0x20
-#define W_INT_D_RME 0x40
-#define W_INT_D_RMR 0x80
-
-#define W_D_EXI_WEXP 0x01
-#define W_D_EXI_TEXP 0x02
-#define W_D_EXI_ISC 0x04
-#define W_D_EXI_MOC 0x08
-#define W_D_EXI_TIN2 0x10
-#define W_D_EXI_XCOL 0x20
-#define W_D_EXI_XDUN 0x40
-#define W_D_EXI_RDOV 0x80
-
-#define W_D_STAR_DRDY 0x10
-#define W_D_STAR_XBZ 0x20
-#define W_D_STAR_XDOW 0x80
-
-#define W_D_RSTA_RMB 0x10
-#define W_D_RSTA_CRCE 0x20
-#define W_D_RSTA_RDOV 0x40
-
-#define W_D_CTL_SRST 0x20
-
-#define W_CIR_SCC 0x80
-#define W_CIR_ICC 0x40
-#define W_CIR_COD_MASK 0x0f
-
-#define W_B_CMDR_XRST 0x01
-#define W_B_CMDR_XME 0x02
-#define W_B_CMDR_XMS 0x04
-#define W_B_CMDR_RACT 0x20
-#define W_B_CMDR_RRST 0x40
-#define W_B_CMDR_RACK 0x80
-
-#define W_B_MODE_FTS0 0x01
-#define W_B_MODE_FTS1 0x02
-#define W_B_MODE_SW56 0x04
-#define W_B_MODE_BSW0 0x08
-#define W_B_MODE_BSW1 0x10
-#define W_B_MODE_EPCM 0x20
-#define W_B_MODE_ITF 0x40
-#define W_B_MODE_MMS 0x80
-
-#define W_B_EXI_XDUN 0x01
-#define W_B_EXI_XFR 0x02
-#define W_B_EXI_RDOV 0x10
-#define W_B_EXI_RME 0x20
-#define W_B_EXI_RMR 0x40
-
-#define W_B_STAR_XBZ 0x01
-#define W_B_STAR_XDOW 0x04
-#define W_B_STAR_RMB 0x10
-#define W_B_STAR_CRCE 0x20
-#define W_B_STAR_RDOV 0x40
-
-#define W_B_RBCH_LOV 0x20
-
-/* W6692 Layer1 commands */
-
-#define W_L1CMD_ECK 0x00
-#define W_L1CMD_RST 0x01
-#define W_L1CMD_SCP 0x04
-#define W_L1CMD_SSP 0x02
-#define W_L1CMD_AR8 0x08
-#define W_L1CMD_AR10 0x09
-#define W_L1CMD_EAL 0x0a
-#define W_L1CMD_DRC 0x0f
-
-/* W6692 Layer1 indications */
-
-#define W_L1IND_CE 0x07
-#define W_L1IND_DRD 0x00
-#define W_L1IND_LD 0x04
-#define W_L1IND_ARD 0x08
-#define W_L1IND_TI 0x0a
-#define W_L1IND_ATI 0x0b
-#define W_L1IND_AI8 0x0c
-#define W_L1IND_AI10 0x0d
-#define W_L1IND_CD 0x0f
-
-/* FIFO thresholds */
-#define W_D_FIFO_THRESH 64
-#define W_B_FIFO_THRESH 64
diff --git a/drivers/isdn/i4l/Kconfig b/drivers/isdn/i4l/Kconfig
deleted file mode 100644
index caa1b52f06f7..000000000000
--- a/drivers/isdn/i4l/Kconfig
+++ /dev/null
@@ -1,129 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Old ISDN4Linux config
-#
-
-if ISDN_I4L
-
-config ISDN_PPP
- bool "Support synchronous PPP"
- depends on INET
- select SLHC
- help
- Over digital connections such as ISDN, there is no need to
- synchronize sender and recipient's clocks with start and stop bits
- as is done over analog telephone lines. Instead, one can use
- "synchronous PPP". Saying Y here will include this protocol. This
- protocol is used by Cisco and Sun for example. So you want to say Y
- here if the other end of your ISDN connection supports it. You will
- need a special version of pppd (called ipppd) for using this
- feature. See <file:Documentation/isdn/README.syncppp> and
- <file:Documentation/isdn/syncPPP.FAQ> for more information.
-
-config ISDN_PPP_VJ
- bool "Use VJ-compression with synchronous PPP"
- depends on ISDN_PPP
- help
- This enables Van Jacobson header compression for synchronous PPP.
- Say Y if the other end of the connection supports it.
-
-config ISDN_MPP
- bool "Support generic MP (RFC 1717)"
- depends on ISDN_PPP
- help
- With synchronous PPP enabled, it is possible to increase throughput
- by bundling several ISDN-connections, using this protocol. See
- <file:Documentation/isdn/README.syncppp> for more information.
-
-config IPPP_FILTER
- bool "Filtering for synchronous PPP"
- depends on ISDN_PPP
- help
- Say Y here if you want to be able to filter the packets passing over
- IPPP interfaces. This allows you to control which packets count as
- activity (i.e. which packets will reset the idle timer or bring up
- a demand-dialled link) and which packets are to be dropped entirely.
- You need to say Y here if you wish to use the pass-filter and
- active-filter options to ipppd.
-
-config ISDN_PPP_BSDCOMP
- tristate "Support BSD compression"
- depends on ISDN_PPP
- help
- Support for the BSD-Compress compression method for PPP, which uses
- the LZW compression method to compress each PPP packet before it is
- sent over the wire. The machine at the other end of the PPP link
- (usually your ISP) has to support the BSD-Compress compression
- method as well for this to be useful. Even if they don't support it,
- it is safe to say Y here.
-
-config ISDN_AUDIO
- bool "Support audio via ISDN"
- help
- If you say Y here, the modem-emulator will support a subset of the
- EIA Class 8 Voice commands. Using a getty with voice-support
- (mgetty+sendfax by <gert@greenie.muc.de> with an extension, available
- with the ISDN utility package for example), you will be able to use
- your Linux box as an ISDN-answering machine. Of course, this must be
- supported by the lowlevel driver also. Currently, the HiSax driver
- is the only voice-supporting driver. See
- <file:Documentation/isdn/README.audio> for more information.
-
-config ISDN_TTY_FAX
- bool "Support AT-Fax Class 1 and 2 commands"
- depends on ISDN_AUDIO
- help
- If you say Y here, the modem-emulator will support a subset of the
- Fax Class 1 and 2 commands. Using a getty with fax-support
- (mgetty+sendfax, hylafax), you will be able to use your Linux box as
- an ISDN-fax-machine. This must be supported by the lowlevel driver
- also. See <file:Documentation/isdn/README.fax> for more information.
-
-config ISDN_X25
- bool "X.25 PLP on top of ISDN"
- depends on X25
- help
- This feature provides the X.25 protocol over ISDN connections.
- See <file:Documentation/isdn/README.x25> for more information
- if you are thinking about using this.
-
-
-menu "ISDN feature submodules"
-
-config ISDN_DRV_LOOP
- tristate "isdnloop support"
- depends on BROKEN_ON_SMP
- help
- This driver provides a virtual ISDN card. Its primary purpose is
- testing of linklevel features or configuration without getting
- charged by your service-provider for lots of phone calls.
- You need will need the loopctrl utility from the latest isdn4k-utils
- package to set up this driver.
-
-config ISDN_DIVERSION
- tristate "Support isdn diversion services"
- help
- This option allows you to use some supplementary diversion
- services in conjunction with the HiSax driver on an EURO/DSS1
- line.
-
- Supported options are CD (call deflection), CFU (Call forward
- unconditional), CFB (Call forward when busy) and CFNR (call forward
- not reachable). Additionally the actual CFU, CFB and CFNR state may
- be interrogated.
-
- The use of CFU, CFB, CFNR and interrogation may be limited to some
- countries. The keypad protocol is still not implemented. CD should
- work in all countries if the service has been subscribed to.
-
- Please read the file <file:Documentation/isdn/README.diversion>.
-
-endmenu
-
-comment "ISDN4Linux hardware drivers"
-
-source "drivers/isdn/hisax/Kconfig"
-
-# end ISDN_I4L
-endif
-
diff --git a/drivers/isdn/i4l/Makefile b/drivers/isdn/i4l/Makefile
deleted file mode 100644
index be77500c9e86..000000000000
--- a/drivers/isdn/i4l/Makefile
+++ /dev/null
@@ -1,20 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-# Makefile for the kernel ISDN subsystem and device drivers.
-
-# Each configuration option enables a list of files.
-
-obj-$(CONFIG_ISDN_I4L) += isdn.o
-obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
-obj-$(CONFIG_ISDN_HDLC) += isdnhdlc.o
-
-# Multipart objects.
-
-isdn-y := isdn_net.o isdn_tty.o isdn_v110.o isdn_common.o
-
-# Optional parts of multipart objects.
-
-isdn-$(CONFIG_ISDN_PPP) += isdn_ppp.o
-isdn-$(CONFIG_ISDN_X25) += isdn_concap.o isdn_x25iface.o
-isdn-$(CONFIG_ISDN_AUDIO) += isdn_audio.o
-isdn-$(CONFIG_ISDN_TTY_FAX) += isdn_ttyfax.o
-
diff --git a/drivers/isdn/i4l/isdn_audio.c b/drivers/isdn/i4l/isdn_audio.c
deleted file mode 100644
index b6bcd1eca128..000000000000
--- a/drivers/isdn/i4l/isdn_audio.c
+++ /dev/null
@@ -1,711 +0,0 @@
-/* $Id: isdn_audio.c,v 1.1.2.2 2004/01/12 22:37:18 keil Exp $
- *
- * Linux ISDN subsystem, audio conversion and compression (linklevel).
- *
- * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
- * DTMF code (c) 1996 by Christian Mock (cm@kukuruz.ping.at)
- * Silence detection (c) 1998 by Armin Schindler (mac@gismo.telekom.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/isdn.h>
-#include <linux/slab.h>
-#include "isdn_audio.h"
-#include "isdn_common.h"
-
-char *isdn_audio_revision = "$Revision: 1.1.2.2 $";
-
-/*
- * Misc. lookup-tables.
- */
-
-/* ulaw -> signed 16-bit */
-static short isdn_audio_ulaw_to_s16[] =
-{
- 0x8284, 0x8684, 0x8a84, 0x8e84, 0x9284, 0x9684, 0x9a84, 0x9e84,
- 0xa284, 0xa684, 0xaa84, 0xae84, 0xb284, 0xb684, 0xba84, 0xbe84,
- 0xc184, 0xc384, 0xc584, 0xc784, 0xc984, 0xcb84, 0xcd84, 0xcf84,
- 0xd184, 0xd384, 0xd584, 0xd784, 0xd984, 0xdb84, 0xdd84, 0xdf84,
- 0xe104, 0xe204, 0xe304, 0xe404, 0xe504, 0xe604, 0xe704, 0xe804,
- 0xe904, 0xea04, 0xeb04, 0xec04, 0xed04, 0xee04, 0xef04, 0xf004,
- 0xf0c4, 0xf144, 0xf1c4, 0xf244, 0xf2c4, 0xf344, 0xf3c4, 0xf444,
- 0xf4c4, 0xf544, 0xf5c4, 0xf644, 0xf6c4, 0xf744, 0xf7c4, 0xf844,
- 0xf8a4, 0xf8e4, 0xf924, 0xf964, 0xf9a4, 0xf9e4, 0xfa24, 0xfa64,
- 0xfaa4, 0xfae4, 0xfb24, 0xfb64, 0xfba4, 0xfbe4, 0xfc24, 0xfc64,
- 0xfc94, 0xfcb4, 0xfcd4, 0xfcf4, 0xfd14, 0xfd34, 0xfd54, 0xfd74,
- 0xfd94, 0xfdb4, 0xfdd4, 0xfdf4, 0xfe14, 0xfe34, 0xfe54, 0xfe74,
- 0xfe8c, 0xfe9c, 0xfeac, 0xfebc, 0xfecc, 0xfedc, 0xfeec, 0xfefc,
- 0xff0c, 0xff1c, 0xff2c, 0xff3c, 0xff4c, 0xff5c, 0xff6c, 0xff7c,
- 0xff88, 0xff90, 0xff98, 0xffa0, 0xffa8, 0xffb0, 0xffb8, 0xffc0,
- 0xffc8, 0xffd0, 0xffd8, 0xffe0, 0xffe8, 0xfff0, 0xfff8, 0x0000,
- 0x7d7c, 0x797c, 0x757c, 0x717c, 0x6d7c, 0x697c, 0x657c, 0x617c,
- 0x5d7c, 0x597c, 0x557c, 0x517c, 0x4d7c, 0x497c, 0x457c, 0x417c,
- 0x3e7c, 0x3c7c, 0x3a7c, 0x387c, 0x367c, 0x347c, 0x327c, 0x307c,
- 0x2e7c, 0x2c7c, 0x2a7c, 0x287c, 0x267c, 0x247c, 0x227c, 0x207c,
- 0x1efc, 0x1dfc, 0x1cfc, 0x1bfc, 0x1afc, 0x19fc, 0x18fc, 0x17fc,
- 0x16fc, 0x15fc, 0x14fc, 0x13fc, 0x12fc, 0x11fc, 0x10fc, 0x0ffc,
- 0x0f3c, 0x0ebc, 0x0e3c, 0x0dbc, 0x0d3c, 0x0cbc, 0x0c3c, 0x0bbc,
- 0x0b3c, 0x0abc, 0x0a3c, 0x09bc, 0x093c, 0x08bc, 0x083c, 0x07bc,
- 0x075c, 0x071c, 0x06dc, 0x069c, 0x065c, 0x061c, 0x05dc, 0x059c,
- 0x055c, 0x051c, 0x04dc, 0x049c, 0x045c, 0x041c, 0x03dc, 0x039c,
- 0x036c, 0x034c, 0x032c, 0x030c, 0x02ec, 0x02cc, 0x02ac, 0x028c,
- 0x026c, 0x024c, 0x022c, 0x020c, 0x01ec, 0x01cc, 0x01ac, 0x018c,
- 0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104,
- 0x00f4, 0x00e4, 0x00d4, 0x00c4, 0x00b4, 0x00a4, 0x0094, 0x0084,
- 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040,
- 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000
-};
-
-/* alaw -> signed 16-bit */
-static short isdn_audio_alaw_to_s16[] =
-{
- 0x13fc, 0xec04, 0x0144, 0xfebc, 0x517c, 0xae84, 0x051c, 0xfae4,
- 0x0a3c, 0xf5c4, 0x0048, 0xffb8, 0x287c, 0xd784, 0x028c, 0xfd74,
- 0x1bfc, 0xe404, 0x01cc, 0xfe34, 0x717c, 0x8e84, 0x071c, 0xf8e4,
- 0x0e3c, 0xf1c4, 0x00c4, 0xff3c, 0x387c, 0xc784, 0x039c, 0xfc64,
- 0x0ffc, 0xf004, 0x0104, 0xfefc, 0x417c, 0xbe84, 0x041c, 0xfbe4,
- 0x083c, 0xf7c4, 0x0008, 0xfff8, 0x207c, 0xdf84, 0x020c, 0xfdf4,
- 0x17fc, 0xe804, 0x018c, 0xfe74, 0x617c, 0x9e84, 0x061c, 0xf9e4,
- 0x0c3c, 0xf3c4, 0x0084, 0xff7c, 0x307c, 0xcf84, 0x030c, 0xfcf4,
- 0x15fc, 0xea04, 0x0164, 0xfe9c, 0x597c, 0xa684, 0x059c, 0xfa64,
- 0x0b3c, 0xf4c4, 0x0068, 0xff98, 0x2c7c, 0xd384, 0x02cc, 0xfd34,
- 0x1dfc, 0xe204, 0x01ec, 0xfe14, 0x797c, 0x8684, 0x07bc, 0xf844,
- 0x0f3c, 0xf0c4, 0x00e4, 0xff1c, 0x3c7c, 0xc384, 0x03dc, 0xfc24,
- 0x11fc, 0xee04, 0x0124, 0xfedc, 0x497c, 0xb684, 0x049c, 0xfb64,
- 0x093c, 0xf6c4, 0x0028, 0xffd8, 0x247c, 0xdb84, 0x024c, 0xfdb4,
- 0x19fc, 0xe604, 0x01ac, 0xfe54, 0x697c, 0x9684, 0x069c, 0xf964,
- 0x0d3c, 0xf2c4, 0x00a4, 0xff5c, 0x347c, 0xcb84, 0x034c, 0xfcb4,
- 0x12fc, 0xed04, 0x0134, 0xfecc, 0x4d7c, 0xb284, 0x04dc, 0xfb24,
- 0x09bc, 0xf644, 0x0038, 0xffc8, 0x267c, 0xd984, 0x026c, 0xfd94,
- 0x1afc, 0xe504, 0x01ac, 0xfe54, 0x6d7c, 0x9284, 0x06dc, 0xf924,
- 0x0dbc, 0xf244, 0x00b4, 0xff4c, 0x367c, 0xc984, 0x036c, 0xfc94,
- 0x0f3c, 0xf0c4, 0x00f4, 0xff0c, 0x3e7c, 0xc184, 0x03dc, 0xfc24,
- 0x07bc, 0xf844, 0x0008, 0xfff8, 0x1efc, 0xe104, 0x01ec, 0xfe14,
- 0x16fc, 0xe904, 0x0174, 0xfe8c, 0x5d7c, 0xa284, 0x05dc, 0xfa24,
- 0x0bbc, 0xf444, 0x0078, 0xff88, 0x2e7c, 0xd184, 0x02ec, 0xfd14,
- 0x14fc, 0xeb04, 0x0154, 0xfeac, 0x557c, 0xaa84, 0x055c, 0xfaa4,
- 0x0abc, 0xf544, 0x0058, 0xffa8, 0x2a7c, 0xd584, 0x02ac, 0xfd54,
- 0x1cfc, 0xe304, 0x01cc, 0xfe34, 0x757c, 0x8a84, 0x075c, 0xf8a4,
- 0x0ebc, 0xf144, 0x00d4, 0xff2c, 0x3a7c, 0xc584, 0x039c, 0xfc64,
- 0x10fc, 0xef04, 0x0114, 0xfeec, 0x457c, 0xba84, 0x045c, 0xfba4,
- 0x08bc, 0xf744, 0x0018, 0xffe8, 0x227c, 0xdd84, 0x022c, 0xfdd4,
- 0x18fc, 0xe704, 0x018c, 0xfe74, 0x657c, 0x9a84, 0x065c, 0xf9a4,
- 0x0cbc, 0xf344, 0x0094, 0xff6c, 0x327c, 0xcd84, 0x032c, 0xfcd4
-};
-
-/* alaw -> ulaw */
-static char isdn_audio_alaw_to_ulaw[] =
-{
- 0xab, 0x2b, 0xe3, 0x63, 0x8b, 0x0b, 0xc9, 0x49,
- 0xba, 0x3a, 0xf6, 0x76, 0x9b, 0x1b, 0xd7, 0x57,
- 0xa3, 0x23, 0xdd, 0x5d, 0x83, 0x03, 0xc1, 0x41,
- 0xb2, 0x32, 0xeb, 0x6b, 0x93, 0x13, 0xcf, 0x4f,
- 0xaf, 0x2f, 0xe7, 0x67, 0x8f, 0x0f, 0xcd, 0x4d,
- 0xbe, 0x3e, 0xfe, 0x7e, 0x9f, 0x1f, 0xdb, 0x5b,
- 0xa7, 0x27, 0xdf, 0x5f, 0x87, 0x07, 0xc5, 0x45,
- 0xb6, 0x36, 0xef, 0x6f, 0x97, 0x17, 0xd3, 0x53,
- 0xa9, 0x29, 0xe1, 0x61, 0x89, 0x09, 0xc7, 0x47,
- 0xb8, 0x38, 0xf2, 0x72, 0x99, 0x19, 0xd5, 0x55,
- 0xa1, 0x21, 0xdc, 0x5c, 0x81, 0x01, 0xbf, 0x3f,
- 0xb0, 0x30, 0xe9, 0x69, 0x91, 0x11, 0xce, 0x4e,
- 0xad, 0x2d, 0xe5, 0x65, 0x8d, 0x0d, 0xcb, 0x4b,
- 0xbc, 0x3c, 0xfa, 0x7a, 0x9d, 0x1d, 0xd9, 0x59,
- 0xa5, 0x25, 0xde, 0x5e, 0x85, 0x05, 0xc3, 0x43,
- 0xb4, 0x34, 0xed, 0x6d, 0x95, 0x15, 0xd1, 0x51,
- 0xac, 0x2c, 0xe4, 0x64, 0x8c, 0x0c, 0xca, 0x4a,
- 0xbb, 0x3b, 0xf8, 0x78, 0x9c, 0x1c, 0xd8, 0x58,
- 0xa4, 0x24, 0xde, 0x5e, 0x84, 0x04, 0xc2, 0x42,
- 0xb3, 0x33, 0xec, 0x6c, 0x94, 0x14, 0xd0, 0x50,
- 0xb0, 0x30, 0xe8, 0x68, 0x90, 0x10, 0xce, 0x4e,
- 0xbf, 0x3f, 0xfe, 0x7e, 0xa0, 0x20, 0xdc, 0x5c,
- 0xa8, 0x28, 0xe0, 0x60, 0x88, 0x08, 0xc6, 0x46,
- 0xb7, 0x37, 0xf0, 0x70, 0x98, 0x18, 0xd4, 0x54,
- 0xaa, 0x2a, 0xe2, 0x62, 0x8a, 0x0a, 0xc8, 0x48,
- 0xb9, 0x39, 0xf4, 0x74, 0x9a, 0x1a, 0xd6, 0x56,
- 0xa2, 0x22, 0xdd, 0x5d, 0x82, 0x02, 0xc0, 0x40,
- 0xb1, 0x31, 0xea, 0x6a, 0x92, 0x12, 0xcf, 0x4f,
- 0xae, 0x2e, 0xe6, 0x66, 0x8e, 0x0e, 0xcc, 0x4c,
- 0xbd, 0x3d, 0xfc, 0x7c, 0x9e, 0x1e, 0xda, 0x5a,
- 0xa6, 0x26, 0xdf, 0x5f, 0x86, 0x06, 0xc4, 0x44,
- 0xb5, 0x35, 0xee, 0x6e, 0x96, 0x16, 0xd2, 0x52
-};
-
-/* ulaw -> alaw */
-static char isdn_audio_ulaw_to_alaw[] =
-{
- 0xab, 0x55, 0xd5, 0x15, 0x95, 0x75, 0xf5, 0x35,
- 0xb5, 0x45, 0xc5, 0x05, 0x85, 0x65, 0xe5, 0x25,
- 0xa5, 0x5d, 0xdd, 0x1d, 0x9d, 0x7d, 0xfd, 0x3d,
- 0xbd, 0x4d, 0xcd, 0x0d, 0x8d, 0x6d, 0xed, 0x2d,
- 0xad, 0x51, 0xd1, 0x11, 0x91, 0x71, 0xf1, 0x31,
- 0xb1, 0x41, 0xc1, 0x01, 0x81, 0x61, 0xe1, 0x21,
- 0x59, 0xd9, 0x19, 0x99, 0x79, 0xf9, 0x39, 0xb9,
- 0x49, 0xc9, 0x09, 0x89, 0x69, 0xe9, 0x29, 0xa9,
- 0xd7, 0x17, 0x97, 0x77, 0xf7, 0x37, 0xb7, 0x47,
- 0xc7, 0x07, 0x87, 0x67, 0xe7, 0x27, 0xa7, 0xdf,
- 0x9f, 0x7f, 0xff, 0x3f, 0xbf, 0x4f, 0xcf, 0x0f,
- 0x8f, 0x6f, 0xef, 0x2f, 0x53, 0x13, 0x73, 0x33,
- 0xb3, 0x43, 0xc3, 0x03, 0x83, 0x63, 0xe3, 0x23,
- 0xa3, 0x5b, 0xdb, 0x1b, 0x9b, 0x7b, 0xfb, 0x3b,
- 0xbb, 0xbb, 0x4b, 0x4b, 0xcb, 0xcb, 0x0b, 0x0b,
- 0x8b, 0x8b, 0x6b, 0x6b, 0xeb, 0xeb, 0x2b, 0x2b,
- 0xab, 0x54, 0xd4, 0x14, 0x94, 0x74, 0xf4, 0x34,
- 0xb4, 0x44, 0xc4, 0x04, 0x84, 0x64, 0xe4, 0x24,
- 0xa4, 0x5c, 0xdc, 0x1c, 0x9c, 0x7c, 0xfc, 0x3c,
- 0xbc, 0x4c, 0xcc, 0x0c, 0x8c, 0x6c, 0xec, 0x2c,
- 0xac, 0x50, 0xd0, 0x10, 0x90, 0x70, 0xf0, 0x30,
- 0xb0, 0x40, 0xc0, 0x00, 0x80, 0x60, 0xe0, 0x20,
- 0x58, 0xd8, 0x18, 0x98, 0x78, 0xf8, 0x38, 0xb8,
- 0x48, 0xc8, 0x08, 0x88, 0x68, 0xe8, 0x28, 0xa8,
- 0xd6, 0x16, 0x96, 0x76, 0xf6, 0x36, 0xb6, 0x46,
- 0xc6, 0x06, 0x86, 0x66, 0xe6, 0x26, 0xa6, 0xde,
- 0x9e, 0x7e, 0xfe, 0x3e, 0xbe, 0x4e, 0xce, 0x0e,
- 0x8e, 0x6e, 0xee, 0x2e, 0x52, 0x12, 0x72, 0x32,
- 0xb2, 0x42, 0xc2, 0x02, 0x82, 0x62, 0xe2, 0x22,
- 0xa2, 0x5a, 0xda, 0x1a, 0x9a, 0x7a, 0xfa, 0x3a,
- 0xba, 0xba, 0x4a, 0x4a, 0xca, 0xca, 0x0a, 0x0a,
- 0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a
-};
-
-#define NCOEFF 8 /* number of frequencies to be analyzed */
-#define DTMF_TRESH 4000 /* above this is dtmf */
-#define SILENCE_TRESH 200 /* below this is silence */
-#define AMP_BITS 9 /* bits per sample, reduced to avoid overflow */
-#define LOGRP 0
-#define HIGRP 1
-
-/* For DTMF recognition:
- * 2 * cos(2 * PI * k / N) precalculated for all k
- */
-static int cos2pik[NCOEFF] =
-{
- 55813, 53604, 51193, 48591, 38114, 33057, 25889, 18332
-};
-
-static char dtmf_matrix[4][4] =
-{
- {'1', '2', '3', 'A'},
- {'4', '5', '6', 'B'},
- {'7', '8', '9', 'C'},
- {'*', '0', '#', 'D'}
-};
-
-static inline void
-isdn_audio_tlookup(const u_char *table, u_char *buff, unsigned long n)
-{
-#ifdef __i386__
- unsigned long d0, d1, d2, d3;
- __asm__ __volatile__(
- "cld\n"
- "1:\tlodsb\n\t"
- "xlatb\n\t"
- "stosb\n\t"
- "loop 1b\n\t"
- : "=&b"(d0), "=&c"(d1), "=&D"(d2), "=&S"(d3)
- : "0"((long) table), "1"(n), "2"((long) buff), "3"((long) buff)
- : "memory", "ax");
-#else
- while (n--)
- *buff = table[*(unsigned char *)buff], buff++;
-#endif
-}
-
-void
-isdn_audio_ulaw2alaw(unsigned char *buff, unsigned long len)
-{
- isdn_audio_tlookup(isdn_audio_ulaw_to_alaw, buff, len);
-}
-
-void
-isdn_audio_alaw2ulaw(unsigned char *buff, unsigned long len)
-{
- isdn_audio_tlookup(isdn_audio_alaw_to_ulaw, buff, len);
-}
-
-/*
- * linear <-> adpcm conversion stuff
- * Most parts from the mgetty-package.
- * (C) by Gert Doering and Klaus Weidner
- * Used by permission of Gert Doering
- */
-
-
-#define ZEROTRAP /* turn on the trap as per the MIL-STD */
-#undef ZEROTRAP
-#define BIAS 0x84 /* define the add-in bias for 16 bit samples */
-#define CLIP 32635
-
-static unsigned char
-isdn_audio_linear2ulaw(int sample)
-{
- static int exp_lut[256] =
- {
- 0, 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, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
- };
- int sign,
- exponent,
- mantissa;
- unsigned char ulawbyte;
-
- /* Get the sample into sign-magnitude. */
- sign = (sample >> 8) & 0x80; /* set aside the sign */
- if (sign != 0)
- sample = -sample; /* get magnitude */
- if (sample > CLIP)
- sample = CLIP; /* clip the magnitude */
-
- /* Convert from 16 bit linear to ulaw. */
- sample = sample + BIAS;
- exponent = exp_lut[(sample >> 7) & 0xFF];
- mantissa = (sample >> (exponent + 3)) & 0x0F;
- ulawbyte = ~(sign | (exponent << 4) | mantissa);
-#ifdef ZEROTRAP
- /* optional CCITT trap */
- if (ulawbyte == 0)
- ulawbyte = 0x02;
-#endif
- return (ulawbyte);
-}
-
-
-static int Mx[3][8] =
-{
- {0x3800, 0x5600, 0, 0, 0, 0, 0, 0},
- {0x399a, 0x3a9f, 0x4d14, 0x6607, 0, 0, 0, 0},
- {0x3556, 0x3556, 0x399A, 0x3A9F, 0x4200, 0x4D14, 0x6607, 0x6607},
-};
-
-static int bitmask[9] =
-{
- 0, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
-};
-
-static int
-isdn_audio_get_bits(adpcm_state *s, unsigned char **in, int *len)
-{
- while (s->nleft < s->nbits) {
- int d = *((*in)++);
- (*len)--;
- s->word = (s->word << 8) | d;
- s->nleft += 8;
- }
- s->nleft -= s->nbits;
- return (s->word >> s->nleft) & bitmask[s->nbits];
-}
-
-static void
-isdn_audio_put_bits(int data, int nbits, adpcm_state *s,
- unsigned char **out, int *len)
-{
- s->word = (s->word << nbits) | (data & bitmask[nbits]);
- s->nleft += nbits;
- while (s->nleft >= 8) {
- int d = (s->word >> (s->nleft - 8));
- *(out[0]++) = d & 255;
- (*len)++;
- s->nleft -= 8;
- }
-}
-
-adpcm_state *
-isdn_audio_adpcm_init(adpcm_state *s, int nbits)
-{
- if (!s)
- s = kmalloc(sizeof(adpcm_state), GFP_ATOMIC);
- if (s) {
- s->a = 0;
- s->d = 5;
- s->word = 0;
- s->nleft = 0;
- s->nbits = nbits;
- }
- return s;
-}
-
-dtmf_state *
-isdn_audio_dtmf_init(dtmf_state *s)
-{
- if (!s)
- s = kmalloc(sizeof(dtmf_state), GFP_ATOMIC);
- if (s) {
- s->idx = 0;
- s->last = ' ';
- }
- return s;
-}
-
-/*
- * Decompression of adpcm data to a/u-law
- *
- */
-
-int
-isdn_audio_adpcm2xlaw(adpcm_state *s, int fmt, unsigned char *in,
- unsigned char *out, int len)
-{
- int a = s->a;
- int d = s->d;
- int nbits = s->nbits;
- int olen = 0;
-
- while (len) {
- int e = isdn_audio_get_bits(s, &in, &len);
- int sign;
-
- if (nbits == 4 && e == 0)
- d = 4;
- sign = (e >> (nbits - 1)) ? -1 : 1;
- e &= bitmask[nbits - 1];
- a += sign * ((e << 1) + 1) * d >> 1;
- if (d & 1)
- a++;
- if (fmt)
- *out++ = isdn_audio_ulaw_to_alaw[
- isdn_audio_linear2ulaw(a << 2)];
- else
- *out++ = isdn_audio_linear2ulaw(a << 2);
- olen++;
- d = (d * Mx[nbits - 2][e] + 0x2000) >> 14;
- if (d < 5)
- d = 5;
- }
- s->a = a;
- s->d = d;
- return olen;
-}
-
-int
-isdn_audio_xlaw2adpcm(adpcm_state *s, int fmt, unsigned char *in,
- unsigned char *out, int len)
-{
- int a = s->a;
- int d = s->d;
- int nbits = s->nbits;
- int olen = 0;
-
- while (len--) {
- int e = 0,
- nmax = 1 << (nbits - 1);
- int sign,
- delta;
-
- if (fmt)
- delta = (isdn_audio_alaw_to_s16[*in++] >> 2) - a;
- else
- delta = (isdn_audio_ulaw_to_s16[*in++] >> 2) - a;
- if (delta < 0) {
- e = nmax;
- delta = -delta;
- }
- while (--nmax && delta > d) {
- delta -= d;
- e++;
- }
- if (nbits == 4 && ((e & 0x0f) == 0))
- e = 8;
- isdn_audio_put_bits(e, nbits, s, &out, &olen);
- sign = (e >> (nbits - 1)) ? -1 : 1;
- e &= bitmask[nbits - 1];
-
- a += sign * ((e << 1) + 1) * d >> 1;
- if (d & 1)
- a++;
- d = (d * Mx[nbits - 2][e] + 0x2000) >> 14;
- if (d < 5)
- d = 5;
- }
- s->a = a;
- s->d = d;
- return olen;
-}
-
-/*
- * Goertzel algorithm.
- * See http://ptolemy.eecs.berkeley.edu/papers/96/dtmf_ict/
- * for more info.
- * Result is stored into an sk_buff and queued up for later
- * evaluation.
- */
-static void
-isdn_audio_goertzel(int *sample, modem_info *info)
-{
- int sk,
- sk1,
- sk2;
- int k,
- n;
- struct sk_buff *skb;
- int *result;
-
- skb = dev_alloc_skb(sizeof(int) * NCOEFF);
- if (!skb) {
- printk(KERN_WARNING
- "isdn_audio: Could not alloc DTMF result for ttyI%d\n",
- info->line);
- return;
- }
- result = skb_put(skb, sizeof(int) * NCOEFF);
- for (k = 0; k < NCOEFF; k++) {
- sk = sk1 = sk2 = 0;
- for (n = 0; n < DTMF_NPOINTS; n++) {
- sk = sample[n] + ((cos2pik[k] * sk1) >> 15) - sk2;
- sk2 = sk1;
- sk1 = sk;
- }
- /* Avoid overflows */
- sk >>= 1;
- sk2 >>= 1;
- /* compute |X(k)|**2 */
- /* report overflows. This should not happen. */
- /* Comment this out if desired */
- if (sk < -32768 || sk > 32767)
- printk(KERN_DEBUG
- "isdn_audio: dtmf goertzel overflow, sk=%d\n", sk);
- if (sk2 < -32768 || sk2 > 32767)
- printk(KERN_DEBUG
- "isdn_audio: dtmf goertzel overflow, sk2=%d\n", sk2);
- result[k] =
- ((sk * sk) >> AMP_BITS) -
- ((((cos2pik[k] * sk) >> 15) * sk2) >> AMP_BITS) +
- ((sk2 * sk2) >> AMP_BITS);
- }
- skb_queue_tail(&info->dtmf_queue, skb);
- isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
-}
-
-void
-isdn_audio_eval_dtmf(modem_info *info)
-{
- struct sk_buff *skb;
- int *result;
- dtmf_state *s;
- int silence;
- int i;
- int di;
- int ch;
- int grp[2];
- char what;
- char *p;
- int thresh;
-
- while ((skb = skb_dequeue(&info->dtmf_queue))) {
- result = (int *) skb->data;
- s = info->dtmf_state;
- grp[LOGRP] = grp[HIGRP] = -1;
- silence = 0;
- thresh = 0;
- for (i = 0; i < NCOEFF; i++) {
- if (result[i] > DTMF_TRESH) {
- if (result[i] > thresh)
- thresh = result[i];
- }
- else if (result[i] < SILENCE_TRESH)
- silence++;
- }
- if (silence == NCOEFF)
- what = ' ';
- else {
- if (thresh > 0) {
- thresh = thresh >> 4; /* touchtones must match within 12 dB */
- for (i = 0; i < NCOEFF; i++) {
- if (result[i] < thresh)
- continue; /* ignore */
- /* good level found. This is allowed only one time per group */
- if (i < NCOEFF / 2) {
- /* lowgroup*/
- if (grp[LOGRP] >= 0) {
- // Bad. Another tone found. */
- grp[LOGRP] = -1;
- break;
- }
- else
- grp[LOGRP] = i;
- }
- else { /* higroup */
- if (grp[HIGRP] >= 0) { // Bad. Another tone found. */
- grp[HIGRP] = -1;
- break;
- }
- else
- grp[HIGRP] = i - NCOEFF/2;
- }
- }
- if ((grp[LOGRP] >= 0) && (grp[HIGRP] >= 0)) {
- what = dtmf_matrix[grp[LOGRP]][grp[HIGRP]];
- if (s->last != ' ' && s->last != '.')
- s->last = what; /* min. 1 non-DTMF between DTMF */
- } else
- what = '.';
- }
- else
- what = '.';
- }
- if ((what != s->last) && (what != ' ') && (what != '.')) {
- printk(KERN_DEBUG "dtmf: tt='%c'\n", what);
- p = skb->data;
- *p++ = 0x10;
- *p = what;
- skb_trim(skb, 2);
- ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
- ISDN_AUDIO_SKB_LOCK(skb) = 0;
- di = info->isdn_driver;
- ch = info->isdn_channel;
- __skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
- dev->drv[di]->rcvcount[ch] += 2;
- /* Schedule dequeuing */
- if ((dev->modempoll) && (info->rcvsched))
- isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
- wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]);
- } else
- kfree_skb(skb);
- s->last = what;
- }
-}
-
-/*
- * Decode DTMF tones, queue result in separate sk_buf for
- * later examination.
- * Parameters:
- * s = pointer to state-struct.
- * buf = input audio data
- * len = size of audio data.
- * fmt = audio data format (0 = ulaw, 1 = alaw)
- */
-void
-isdn_audio_calc_dtmf(modem_info *info, unsigned char *buf, int len, int fmt)
-{
- dtmf_state *s = info->dtmf_state;
- int i;
- int c;
-
- while (len) {
- c = DTMF_NPOINTS - s->idx;
- if (c > len)
- c = len;
- if (c <= 0)
- break;
- for (i = 0; i < c; i++) {
- if (fmt)
- s->buf[s->idx++] =
- isdn_audio_alaw_to_s16[*buf++] >> (15 - AMP_BITS);
- else
- s->buf[s->idx++] =
- isdn_audio_ulaw_to_s16[*buf++] >> (15 - AMP_BITS);
- }
- if (s->idx == DTMF_NPOINTS) {
- isdn_audio_goertzel(s->buf, info);
- s->idx = 0;
- }
- len -= c;
- }
-}
-
-silence_state *
-isdn_audio_silence_init(silence_state *s)
-{
- if (!s)
- s = kmalloc(sizeof(silence_state), GFP_ATOMIC);
- if (s) {
- s->idx = 0;
- s->state = 0;
- }
- return s;
-}
-
-void
-isdn_audio_calc_silence(modem_info *info, unsigned char *buf, int len, int fmt)
-{
- silence_state *s = info->silence_state;
- int i;
- signed char c;
-
- if (!info->emu.vpar[1]) return;
-
- for (i = 0; i < len; i++) {
- if (fmt)
- c = isdn_audio_alaw_to_ulaw[*buf++];
- else
- c = *buf++;
-
- if (c > 0) c -= 128;
- c = abs(c);
-
- if (c > (info->emu.vpar[1] * 4)) {
- s->idx = 0;
- s->state = 1;
- } else {
- if (s->idx < 210000) s->idx++;
- }
- }
-}
-
-void
-isdn_audio_put_dle_code(modem_info *info, u_char code)
-{
- struct sk_buff *skb;
- int di;
- int ch;
- char *p;
-
- skb = dev_alloc_skb(2);
- if (!skb) {
- printk(KERN_WARNING
- "isdn_audio: Could not alloc skb for ttyI%d\n",
- info->line);
- return;
- }
- p = skb_put(skb, 2);
- p[0] = 0x10;
- p[1] = code;
- ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
- ISDN_AUDIO_SKB_LOCK(skb) = 0;
- di = info->isdn_driver;
- ch = info->isdn_channel;
- __skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
- dev->drv[di]->rcvcount[ch] += 2;
- /* Schedule dequeuing */
- if ((dev->modempoll) && (info->rcvsched))
- isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
- wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]);
-}
-
-void
-isdn_audio_eval_silence(modem_info *info)
-{
- silence_state *s = info->silence_state;
- char what;
-
- what = ' ';
-
- if (s->idx > (info->emu.vpar[2] * 800)) {
- s->idx = 0;
- if (!s->state) { /* silence from beginning of rec */
- what = 's';
- } else {
- what = 'q';
- }
- }
- if ((what == 's') || (what == 'q')) {
- printk(KERN_DEBUG "ttyI%d: %s\n", info->line,
- (what == 's') ? "silence" : "quiet");
- isdn_audio_put_dle_code(info, what);
- }
-}
diff --git a/drivers/isdn/i4l/isdn_audio.h b/drivers/isdn/i4l/isdn_audio.h
deleted file mode 100644
index 013c3582e0d1..000000000000
--- a/drivers/isdn/i4l/isdn_audio.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* $Id: isdn_audio.h,v 1.1.2.2 2004/01/12 22:37:18 keil Exp $
- *
- * Linux ISDN subsystem, audio conversion and compression (linklevel).
- *
- * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#define DTMF_NPOINTS 205 /* Number of samples for DTMF recognition */
-typedef struct adpcm_state {
- int a;
- int d;
- int word;
- int nleft;
- int nbits;
-} adpcm_state;
-
-typedef struct dtmf_state {
- char last;
- char llast;
- int idx;
- int buf[DTMF_NPOINTS];
-} dtmf_state;
-
-typedef struct silence_state {
- int state;
- unsigned int idx;
-} silence_state;
-
-extern void isdn_audio_ulaw2alaw(unsigned char *, unsigned long);
-extern void isdn_audio_alaw2ulaw(unsigned char *, unsigned long);
-extern adpcm_state *isdn_audio_adpcm_init(adpcm_state *, int);
-extern int isdn_audio_adpcm2xlaw(adpcm_state *, int, unsigned char *, unsigned char *, int);
-extern int isdn_audio_xlaw2adpcm(adpcm_state *, int, unsigned char *, unsigned char *, int);
-extern void isdn_audio_calc_dtmf(modem_info *, unsigned char *, int, int);
-extern void isdn_audio_eval_dtmf(modem_info *);
-dtmf_state *isdn_audio_dtmf_init(dtmf_state *);
-extern void isdn_audio_calc_silence(modem_info *, unsigned char *, int, int);
-extern void isdn_audio_eval_silence(modem_info *);
-silence_state *isdn_audio_silence_init(silence_state *);
-extern void isdn_audio_put_dle_code(modem_info *, u_char);
diff --git a/drivers/isdn/i4l/isdn_bsdcomp.c b/drivers/isdn/i4l/isdn_bsdcomp.c
deleted file mode 100644
index 7f28b967ed19..000000000000
--- a/drivers/isdn/i4l/isdn_bsdcomp.c
+++ /dev/null
@@ -1,930 +0,0 @@
-/*
- * BSD compression module
- *
- * Patched version for ISDN syncPPP written 1997/1998 by Michael Hipp
- * The whole module is now SKB based.
- *
- */
-
-/*
- * Update: The Berkeley copyright was changed, and the change
- * is retroactive to all "true" BSD software (ie everything
- * from UCB as opposed to other peoples code that just carried
- * the same license). The new copyright doesn't clash with the
- * GPL, so the module-only restriction has been removed..
- */
-
-/*
- * Original copyright notice:
- *
- * Copyright (c) 1985, 1986 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * James A. Woods, derived from original work by Spencer Thomas
- * and Joseph Orost.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/slab.h>
-#include <linux/tty.h>
-#include <linux/errno.h>
-#include <linux/string.h> /* used in new tty drivers */
-#include <linux/signal.h> /* used in new tty drivers */
-#include <linux/bitops.h>
-
-#include <asm/byteorder.h>
-#include <asm/types.h>
-
-#include <linux/if.h>
-
-#include <linux/if_ether.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <linux/inet.h>
-#include <linux/ioctl.h>
-#include <linux/vmalloc.h>
-
-#include <linux/ppp_defs.h>
-
-#include <linux/isdn.h>
-#include <linux/isdn_ppp.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>
-#include <linux/if_arp.h>
-#include <linux/ppp-comp.h>
-
-#include "isdn_ppp.h"
-
-MODULE_DESCRIPTION("ISDN4Linux: BSD Compression for PPP over ISDN");
-MODULE_LICENSE("Dual BSD/GPL");
-
-#define BSD_VERSION(x) ((x) >> 5)
-#define BSD_NBITS(x) ((x) & 0x1F)
-
-#define BSD_CURRENT_VERSION 1
-
-#define DEBUG 1
-
-/*
- * A dictionary for doing BSD compress.
- */
-
-struct bsd_dict {
- u32 fcode;
- u16 codem1; /* output of hash table -1 */
- u16 cptr; /* map code to hash table entry */
-};
-
-struct bsd_db {
- int totlen; /* length of this structure */
- unsigned int hsize; /* size of the hash table */
- unsigned char hshift; /* used in hash function */
- unsigned char n_bits; /* current bits/code */
- unsigned char maxbits; /* maximum bits/code */
- unsigned char debug; /* non-zero if debug desired */
- unsigned char unit; /* ppp unit number */
- u16 seqno; /* sequence # of next packet */
- unsigned int mru; /* size of receive (decompress) bufr */
- unsigned int maxmaxcode; /* largest valid code */
- unsigned int max_ent; /* largest code in use */
- unsigned int in_count; /* uncompressed bytes, aged */
- unsigned int bytes_out; /* compressed bytes, aged */
- unsigned int ratio; /* recent compression ratio */
- unsigned int checkpoint; /* when to next check the ratio */
- unsigned int clear_count; /* times dictionary cleared */
- unsigned int incomp_count; /* incompressible packets */
- unsigned int incomp_bytes; /* incompressible bytes */
- unsigned int uncomp_count; /* uncompressed packets */
- unsigned int uncomp_bytes; /* uncompressed bytes */
- unsigned int comp_count; /* compressed packets */
- unsigned int comp_bytes; /* compressed bytes */
- unsigned short *lens; /* array of lengths of codes */
- struct bsd_dict *dict; /* dictionary */
- int xmit;
-};
-
-#define BSD_OVHD 2 /* BSD compress overhead/packet */
-#define MIN_BSD_BITS 9
-#define BSD_INIT_BITS MIN_BSD_BITS
-#define MAX_BSD_BITS 15
-
-/*
- * the next two codes should not be changed lightly, as they must not
- * lie within the contiguous general code space.
- */
-#define CLEAR 256 /* table clear output code */
-#define FIRST 257 /* first free entry */
-#define LAST 255
-
-#define MAXCODE(b) ((1 << (b)) - 1)
-#define BADCODEM1 MAXCODE(MAX_BSD_BITS)
-
-#define BSD_HASH(prefix, suffix, hshift) ((((unsigned long)(suffix)) << (hshift)) \
- ^ (unsigned long)(prefix))
-#define BSD_KEY(prefix, suffix) ((((unsigned long)(suffix)) << 16) \
- + (unsigned long)(prefix))
-
-#define CHECK_GAP 10000 /* Ratio check interval */
-
-#define RATIO_SCALE_LOG 8
-#define RATIO_SCALE (1 << RATIO_SCALE_LOG)
-#define RATIO_MAX (0x7fffffff >> RATIO_SCALE_LOG)
-
-/*
- * clear the dictionary
- */
-
-static void bsd_clear(struct bsd_db *db)
-{
- db->clear_count++;
- db->max_ent = FIRST - 1;
- db->n_bits = BSD_INIT_BITS;
- db->bytes_out = 0;
- db->in_count = 0;
- db->incomp_count = 0;
- db->ratio = 0;
- db->checkpoint = CHECK_GAP;
-}
-
-/*
- * If the dictionary is full, then see if it is time to reset it.
- *
- * Compute the compression ratio using fixed-point arithmetic
- * with 8 fractional bits.
- *
- * Since we have an infinite stream instead of a single file,
- * watch only the local compression ratio.
- *
- * Since both peers must reset the dictionary at the same time even in
- * the absence of CLEAR codes (while packets are incompressible), they
- * must compute the same ratio.
- */
-static int bsd_check(struct bsd_db *db) /* 1=output CLEAR */
-{
- unsigned int new_ratio;
-
- if (db->in_count >= db->checkpoint)
- {
- /* age the ratio by limiting the size of the counts */
- if (db->in_count >= RATIO_MAX || db->bytes_out >= RATIO_MAX)
- {
- db->in_count -= (db->in_count >> 2);
- db->bytes_out -= (db->bytes_out >> 2);
- }
-
- db->checkpoint = db->in_count + CHECK_GAP;
-
- if (db->max_ent >= db->maxmaxcode)
- {
- /* Reset the dictionary only if the ratio is worse,
- * or if it looks as if it has been poisoned
- * by incompressible data.
- *
- * This does not overflow, because
- * db->in_count <= RATIO_MAX.
- */
-
- new_ratio = db->in_count << RATIO_SCALE_LOG;
- if (db->bytes_out != 0)
- {
- new_ratio /= db->bytes_out;
- }
-
- if (new_ratio < db->ratio || new_ratio < 1 * RATIO_SCALE)
- {
- bsd_clear(db);
- return 1;
- }
- db->ratio = new_ratio;
- }
- }
- return 0;
-}
-
-/*
- * Return statistics.
- */
-
-static void bsd_stats(void *state, struct compstat *stats)
-{
- struct bsd_db *db = (struct bsd_db *) state;
-
- stats->unc_bytes = db->uncomp_bytes;
- stats->unc_packets = db->uncomp_count;
- stats->comp_bytes = db->comp_bytes;
- stats->comp_packets = db->comp_count;
- stats->inc_bytes = db->incomp_bytes;
- stats->inc_packets = db->incomp_count;
- stats->in_count = db->in_count;
- stats->bytes_out = db->bytes_out;
-}
-
-/*
- * Reset state, as on a CCP ResetReq.
- */
-static void bsd_reset(void *state, unsigned char code, unsigned char id,
- unsigned char *data, unsigned len,
- struct isdn_ppp_resetparams *rsparm)
-{
- struct bsd_db *db = (struct bsd_db *) state;
-
- bsd_clear(db);
- db->seqno = 0;
- db->clear_count = 0;
-}
-
-/*
- * Release the compression structure
- */
-static void bsd_free(void *state)
-{
- struct bsd_db *db = (struct bsd_db *) state;
-
- if (db) {
- /*
- * Release the dictionary
- */
- vfree(db->dict);
- db->dict = NULL;
-
- /*
- * Release the string buffer
- */
- vfree(db->lens);
- db->lens = NULL;
-
- /*
- * Finally release the structure itself.
- */
- kfree(db);
- }
-}
-
-
-/*
- * Allocate space for a (de) compressor.
- */
-static void *bsd_alloc(struct isdn_ppp_comp_data *data)
-{
- int bits;
- unsigned int hsize, hshift, maxmaxcode;
- struct bsd_db *db;
- int decomp;
-
- static unsigned int htab[][2] = {
- { 5003 , 4 } , { 5003 , 4 } , { 5003 , 4 } , { 5003 , 4 } ,
- { 9001 , 5 } , { 18013 , 6 } , { 35023 , 7 } , { 69001 , 8 }
- };
-
- if (data->optlen != 1 || data->num != CI_BSD_COMPRESS
- || BSD_VERSION(data->options[0]) != BSD_CURRENT_VERSION)
- return NULL;
-
- bits = BSD_NBITS(data->options[0]);
-
- if (bits < 9 || bits > 15)
- return NULL;
-
- hsize = htab[bits - 9][0];
- hshift = htab[bits - 9][1];
-
- /*
- * Allocate the main control structure for this instance.
- */
- maxmaxcode = MAXCODE(bits);
- db = kzalloc(sizeof(struct bsd_db), GFP_KERNEL);
- if (!db)
- return NULL;
-
- db->xmit = data->flags & IPPP_COMP_FLAG_XMIT;
- decomp = db->xmit ? 0 : 1;
-
- /*
- * Allocate space for the dictionary. This may be more than one page in
- * length.
- */
- db->dict = vmalloc(array_size(hsize, sizeof(struct bsd_dict)));
- if (!db->dict) {
- bsd_free(db);
- return NULL;
- }
-
- /*
- * If this is the compression buffer then there is no length data.
- * For decompression, the length information is needed as well.
- */
- if (!decomp)
- db->lens = NULL;
- else {
- db->lens = vmalloc(array_size(sizeof(db->lens[0]),
- maxmaxcode + 1));
- if (!db->lens) {
- bsd_free(db);
- return (NULL);
- }
- }
-
- /*
- * Initialize the data information for the compression code
- */
- db->totlen = sizeof(struct bsd_db) + (sizeof(struct bsd_dict) * hsize);
- db->hsize = hsize;
- db->hshift = hshift;
- db->maxmaxcode = maxmaxcode;
- db->maxbits = bits;
-
- return (void *)db;
-}
-
-/*
- * Initialize the database.
- */
-static int bsd_init(void *state, struct isdn_ppp_comp_data *data, int unit, int debug)
-{
- struct bsd_db *db = state;
- int indx;
- int decomp;
-
- if (!state || !data) {
- printk(KERN_ERR "isdn_bsd_init: [%d] ERR, state %lx data %lx\n", unit, (long)state, (long)data);
- return 0;
- }
-
- decomp = db->xmit ? 0 : 1;
-
- if (data->optlen != 1 || data->num != CI_BSD_COMPRESS
- || (BSD_VERSION(data->options[0]) != BSD_CURRENT_VERSION)
- || (BSD_NBITS(data->options[0]) != db->maxbits)
- || (decomp && db->lens == NULL)) {
- printk(KERN_ERR "isdn_bsd: %d %d %d %d %lx\n", data->optlen, data->num, data->options[0], decomp, (unsigned long)db->lens);
- return 0;
- }
-
- if (decomp)
- for (indx = LAST; indx >= 0; indx--)
- db->lens[indx] = 1;
-
- indx = db->hsize;
- while (indx-- != 0) {
- db->dict[indx].codem1 = BADCODEM1;
- db->dict[indx].cptr = 0;
- }
-
- db->unit = unit;
- db->mru = 0;
-
- db->debug = 1;
-
- bsd_reset(db, 0, 0, NULL, 0, NULL);
-
- return 1;
-}
-
-/*
- * Obtain pointers to the various structures in the compression tables
- */
-
-#define dict_ptrx(p, idx) &(p->dict[idx])
-#define lens_ptrx(p, idx) &(p->lens[idx])
-
-#ifdef DEBUG
-static unsigned short *lens_ptr(struct bsd_db *db, int idx)
-{
- if ((unsigned int) idx > (unsigned int) db->maxmaxcode) {
- printk(KERN_DEBUG "<9>ppp: lens_ptr(%d) > max\n", idx);
- idx = 0;
- }
- return lens_ptrx(db, idx);
-}
-
-static struct bsd_dict *dict_ptr(struct bsd_db *db, int idx)
-{
- if ((unsigned int) idx >= (unsigned int) db->hsize) {
- printk(KERN_DEBUG "<9>ppp: dict_ptr(%d) > max\n", idx);
- idx = 0;
- }
- return dict_ptrx(db, idx);
-}
-
-#else
-#define lens_ptr(db, idx) lens_ptrx(db, idx)
-#define dict_ptr(db, idx) dict_ptrx(db, idx)
-#endif
-
-/*
- * compress a packet
- */
-static int bsd_compress(void *state, struct sk_buff *skb_in, struct sk_buff *skb_out, int proto)
-{
- struct bsd_db *db;
- int hshift;
- unsigned int max_ent;
- unsigned int n_bits;
- unsigned int bitno;
- unsigned long accm;
- int ent;
- unsigned long fcode;
- struct bsd_dict *dictp;
- unsigned char c;
- int hval, disp, ilen, mxcode;
- unsigned char *rptr = skb_in->data;
- int isize = skb_in->len;
-
-#define OUTPUT(ent) \
- { \
- bitno -= n_bits; \
- accm |= ((ent) << bitno); \
- do { \
- if (skb_out && skb_tailroom(skb_out) > 0) \
- skb_put_u8(skb_out, (u8)(accm >> 24)); \
- accm <<= 8; \
- bitno += 8; \
- } while (bitno <= 24); \
- }
-
- /*
- * If the protocol is not in the range we're interested in,
- * just return without compressing the packet. If it is,
- * the protocol becomes the first byte to compress.
- */
- printk(KERN_DEBUG "bsd_compress called with %x\n", proto);
-
- ent = proto;
- if (proto < 0x21 || proto > 0xf9 || !(proto & 0x1))
- return 0;
-
- db = (struct bsd_db *) state;
- hshift = db->hshift;
- max_ent = db->max_ent;
- n_bits = db->n_bits;
- bitno = 32;
- accm = 0;
- mxcode = MAXCODE(n_bits);
-
- /* This is the PPP header information */
- if (skb_out && skb_tailroom(skb_out) >= 2) {
- char *v = skb_put(skb_out, 2);
- /* we only push our own data on the header,
- AC,PC and protos is pushed by caller */
- v[0] = db->seqno >> 8;
- v[1] = db->seqno;
- }
-
- ilen = ++isize; /* This is off by one, but that is what is in draft! */
-
- while (--ilen > 0) {
- c = *rptr++;
- fcode = BSD_KEY(ent, c);
- hval = BSD_HASH(ent, c, hshift);
- dictp = dict_ptr(db, hval);
-
- /* Validate and then check the entry. */
- if (dictp->codem1 >= max_ent)
- goto nomatch;
-
- if (dictp->fcode == fcode) {
- ent = dictp->codem1 + 1;
- continue; /* found (prefix,suffix) */
- }
-
- /* continue probing until a match or invalid entry */
- disp = (hval == 0) ? 1 : hval;
-
- do {
- hval += disp;
- if (hval >= db->hsize)
- hval -= db->hsize;
- dictp = dict_ptr(db, hval);
- if (dictp->codem1 >= max_ent)
- goto nomatch;
- } while (dictp->fcode != fcode);
-
- ent = dictp->codem1 + 1; /* finally found (prefix,suffix) */
- continue;
-
- nomatch:
- OUTPUT(ent); /* output the prefix */
-
- /* code -> hashtable */
- if (max_ent < db->maxmaxcode) {
- struct bsd_dict *dictp2;
- struct bsd_dict *dictp3;
- int indx;
-
- /* expand code size if needed */
- if (max_ent >= mxcode) {
- db->n_bits = ++n_bits;
- mxcode = MAXCODE(n_bits);
- }
-
- /*
- * Invalidate old hash table entry using
- * this code, and then take it over.
- */
- dictp2 = dict_ptr(db, max_ent + 1);
- indx = dictp2->cptr;
- dictp3 = dict_ptr(db, indx);
-
- if (dictp3->codem1 == max_ent)
- dictp3->codem1 = BADCODEM1;
-
- dictp2->cptr = hval;
- dictp->codem1 = max_ent;
- dictp->fcode = fcode;
- db->max_ent = ++max_ent;
-
- if (db->lens) {
- unsigned short *len1 = lens_ptr(db, max_ent);
- unsigned short *len2 = lens_ptr(db, ent);
- *len1 = *len2 + 1;
- }
- }
- ent = c;
- }
-
- OUTPUT(ent); /* output the last code */
-
- if (skb_out)
- db->bytes_out += skb_out->len; /* Do not count bytes from here */
- db->uncomp_bytes += isize;
- db->in_count += isize;
- ++db->uncomp_count;
- ++db->seqno;
-
- if (bitno < 32)
- ++db->bytes_out; /* must be set before calling bsd_check */
-
- /*
- * Generate the clear command if needed
- */
-
- if (bsd_check(db))
- OUTPUT(CLEAR);
-
- /*
- * Pad dribble bits of last code with ones.
- * Do not emit a completely useless byte of ones.
- */
- if (bitno < 32 && skb_out && skb_tailroom(skb_out) > 0)
- skb_put_u8(skb_out,
- (unsigned char)((accm | (0xff << (bitno - 8))) >> 24));
-
- /*
- * Increase code size if we would have without the packet
- * boundary because the decompressor will do so.
- */
- if (max_ent >= mxcode && max_ent < db->maxmaxcode)
- db->n_bits++;
-
- /* If output length is too large then this is an incompressible frame. */
- if (!skb_out || skb_out->len >= skb_in->len) {
- ++db->incomp_count;
- db->incomp_bytes += isize;
- return 0;
- }
-
- /* Count the number of compressed frames */
- ++db->comp_count;
- db->comp_bytes += skb_out->len;
- return skb_out->len;
-
-#undef OUTPUT
-}
-
-/*
- * Update the "BSD Compress" dictionary on the receiver for
- * incompressible data by pretending to compress the incoming data.
- */
-static void bsd_incomp(void *state, struct sk_buff *skb_in, int proto)
-{
- bsd_compress(state, skb_in, NULL, proto);
-}
-
-/*
- * Decompress "BSD Compress".
- */
-static int bsd_decompress(void *state, struct sk_buff *skb_in, struct sk_buff *skb_out,
- struct isdn_ppp_resetparams *rsparm)
-{
- struct bsd_db *db;
- unsigned int max_ent;
- unsigned long accm;
- unsigned int bitno; /* 1st valid bit in accm */
- unsigned int n_bits;
- unsigned int tgtbitno; /* bitno when we have a code */
- struct bsd_dict *dictp;
- int seq;
- unsigned int incode;
- unsigned int oldcode;
- unsigned int finchar;
- unsigned char *p, *ibuf;
- int ilen;
- int codelen;
- int extra;
-
- db = (struct bsd_db *) state;
- max_ent = db->max_ent;
- accm = 0;
- bitno = 32; /* 1st valid bit in accm */
- n_bits = db->n_bits;
- tgtbitno = 32 - n_bits; /* bitno when we have a code */
-
- printk(KERN_DEBUG "bsd_decompress called\n");
-
- if (!skb_in || !skb_out) {
- printk(KERN_ERR "bsd_decompress called with NULL parameter\n");
- return DECOMP_ERROR;
- }
-
- /*
- * Get the sequence number.
- */
- if ((p = skb_pull(skb_in, 2)) == NULL) {
- return DECOMP_ERROR;
- }
- p -= 2;
- seq = (p[0] << 8) + p[1];
- ilen = skb_in->len;
- ibuf = skb_in->data;
-
- /*
- * Check the sequence number and give up if it differs from
- * the value we're expecting.
- */
- if (seq != db->seqno) {
- if (db->debug) {
- printk(KERN_DEBUG "bsd_decomp%d: bad sequence # %d, expected %d\n",
- db->unit, seq, db->seqno - 1);
- }
- return DECOMP_ERROR;
- }
-
- ++db->seqno;
- db->bytes_out += ilen;
-
- if (skb_tailroom(skb_out) > 0)
- skb_put_u8(skb_out, 0);
- else
- return DECOMP_ERR_NOMEM;
-
- oldcode = CLEAR;
-
- /*
- * Keep the checkpoint correctly so that incompressible packets
- * clear the dictionary at the proper times.
- */
-
- for (;;) {
- if (ilen-- <= 0) {
- db->in_count += (skb_out->len - 1); /* don't count the header */
- break;
- }
-
- /*
- * Accumulate bytes until we have a complete code.
- * Then get the next code, relying on the 32-bit,
- * unsigned accm to mask the result.
- */
-
- bitno -= 8;
- accm |= *ibuf++ << bitno;
- if (tgtbitno < bitno)
- continue;
-
- incode = accm >> tgtbitno;
- accm <<= n_bits;
- bitno += n_bits;
-
- /*
- * The dictionary must only be cleared at the end of a packet.
- */
-
- if (incode == CLEAR) {
- if (ilen > 0) {
- if (db->debug)
- printk(KERN_DEBUG "bsd_decomp%d: bad CLEAR\n", db->unit);
- return DECOMP_FATALERROR; /* probably a bug */
- }
- bsd_clear(db);
- break;
- }
-
- if ((incode > max_ent + 2) || (incode > db->maxmaxcode)
- || (incode > max_ent && oldcode == CLEAR)) {
- if (db->debug) {
- printk(KERN_DEBUG "bsd_decomp%d: bad code 0x%x oldcode=0x%x ",
- db->unit, incode, oldcode);
- printk(KERN_DEBUG "max_ent=0x%x skb->Len=%d seqno=%d\n",
- max_ent, skb_out->len, db->seqno);
- }
- return DECOMP_FATALERROR; /* probably a bug */
- }
-
- /* Special case for KwKwK string. */
- if (incode > max_ent) {
- finchar = oldcode;
- extra = 1;
- } else {
- finchar = incode;
- extra = 0;
- }
-
- codelen = *(lens_ptr(db, finchar));
- if (skb_tailroom(skb_out) < codelen + extra) {
- if (db->debug) {
- printk(KERN_DEBUG "bsd_decomp%d: ran out of mru\n", db->unit);
-#ifdef DEBUG
- printk(KERN_DEBUG " len=%d, finchar=0x%x, codelen=%d,skblen=%d\n",
- ilen, finchar, codelen, skb_out->len);
-#endif
- }
- return DECOMP_FATALERROR;
- }
-
- /*
- * Decode this code and install it in the decompressed buffer.
- */
-
- p = skb_put(skb_out, codelen);
- p += codelen;
- while (finchar > LAST) {
- struct bsd_dict *dictp2 = dict_ptr(db, finchar);
-
- dictp = dict_ptr(db, dictp2->cptr);
-
-#ifdef DEBUG
- if (--codelen <= 0 || dictp->codem1 != finchar - 1) {
- if (codelen <= 0) {
- printk(KERN_ERR "bsd_decomp%d: fell off end of chain ", db->unit);
- printk(KERN_ERR "0x%x at 0x%x by 0x%x, max_ent=0x%x\n", incode, finchar, dictp2->cptr, max_ent);
- } else {
- if (dictp->codem1 != finchar - 1) {
- printk(KERN_ERR "bsd_decomp%d: bad code chain 0x%x finchar=0x%x ", db->unit, incode, finchar);
- printk(KERN_ERR "oldcode=0x%x cptr=0x%x codem1=0x%x\n", oldcode, dictp2->cptr, dictp->codem1);
- }
- }
- return DECOMP_FATALERROR;
- }
-#endif
-
- {
- u32 fcode = dictp->fcode;
- *--p = (fcode >> 16) & 0xff;
- finchar = fcode & 0xffff;
- }
- }
- *--p = finchar;
-
-#ifdef DEBUG
- if (--codelen != 0)
- printk(KERN_ERR "bsd_decomp%d: short by %d after code 0x%x, max_ent=0x%x\n", db->unit, codelen, incode, max_ent);
-#endif
-
- if (extra) /* the KwKwK case again */
- skb_put_u8(skb_out, finchar);
-
- /*
- * If not first code in a packet, and
- * if not out of code space, then allocate a new code.
- *
- * Keep the hash table correct so it can be used
- * with uncompressed packets.
- */
- if (oldcode != CLEAR && max_ent < db->maxmaxcode) {
- struct bsd_dict *dictp2, *dictp3;
- u16 *lens1, *lens2;
- unsigned long fcode;
- int hval, disp, indx;
-
- fcode = BSD_KEY(oldcode, finchar);
- hval = BSD_HASH(oldcode, finchar, db->hshift);
- dictp = dict_ptr(db, hval);
-
- /* look for a free hash table entry */
- if (dictp->codem1 < max_ent) {
- disp = (hval == 0) ? 1 : hval;
- do {
- hval += disp;
- if (hval >= db->hsize)
- hval -= db->hsize;
- dictp = dict_ptr(db, hval);
- } while (dictp->codem1 < max_ent);
- }
-
- /*
- * Invalidate previous hash table entry
- * assigned this code, and then take it over
- */
-
- dictp2 = dict_ptr(db, max_ent + 1);
- indx = dictp2->cptr;
- dictp3 = dict_ptr(db, indx);
-
- if (dictp3->codem1 == max_ent)
- dictp3->codem1 = BADCODEM1;
-
- dictp2->cptr = hval;
- dictp->codem1 = max_ent;
- dictp->fcode = fcode;
- db->max_ent = ++max_ent;
-
- /* Update the length of this string. */
- lens1 = lens_ptr(db, max_ent);
- lens2 = lens_ptr(db, oldcode);
- *lens1 = *lens2 + 1;
-
- /* Expand code size if needed. */
- if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) {
- db->n_bits = ++n_bits;
- tgtbitno = 32-n_bits;
- }
- }
- oldcode = incode;
- }
-
- ++db->comp_count;
- ++db->uncomp_count;
- db->comp_bytes += skb_in->len - BSD_OVHD;
- db->uncomp_bytes += skb_out->len;
-
- if (bsd_check(db)) {
- if (db->debug)
- printk(KERN_DEBUG "bsd_decomp%d: peer should have cleared dictionary on %d\n",
- db->unit, db->seqno - 1);
- }
- return skb_out->len;
-}
-
-/*************************************************************
- * Table of addresses for the BSD compression module
- *************************************************************/
-
-static struct isdn_ppp_compressor ippp_bsd_compress = {
- .owner = THIS_MODULE,
- .num = CI_BSD_COMPRESS,
- .alloc = bsd_alloc,
- .free = bsd_free,
- .init = bsd_init,
- .reset = bsd_reset,
- .compress = bsd_compress,
- .decompress = bsd_decompress,
- .incomp = bsd_incomp,
- .stat = bsd_stats,
-};
-
-/*************************************************************
- * Module support routines
- *************************************************************/
-
-static int __init isdn_bsdcomp_init(void)
-{
- int answer = isdn_ppp_register_compressor(&ippp_bsd_compress);
- if (answer == 0)
- printk(KERN_INFO "PPP BSD Compression module registered\n");
- return answer;
-}
-
-static void __exit isdn_bsdcomp_exit(void)
-{
- isdn_ppp_unregister_compressor(&ippp_bsd_compress);
-}
-
-module_init(isdn_bsdcomp_init);
-module_exit(isdn_bsdcomp_exit);
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
deleted file mode 100644
index 74ee00f5b310..000000000000
--- a/drivers/isdn/i4l/isdn_common.c
+++ /dev/null
@@ -1,2368 +0,0 @@
-/* $Id: isdn_common.c,v 1.1.2.3 2004/02/10 01:07:13 keil Exp $
- *
- * Linux ISDN subsystem, common used functions (linklevel).
- *
- * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1995,96 Thinking Objects Software GmbH Wuerzburg
- * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/isdn.h>
-#include <linux/mutex.h>
-#include "isdn_common.h"
-#include "isdn_tty.h"
-#include "isdn_net.h"
-#include "isdn_ppp.h"
-#ifdef CONFIG_ISDN_AUDIO
-#include "isdn_audio.h"
-#endif
-#ifdef CONFIG_ISDN_DIVERSION_MODULE
-#define CONFIG_ISDN_DIVERSION
-#endif
-#ifdef CONFIG_ISDN_DIVERSION
-#include <linux/isdn_divertif.h>
-#endif /* CONFIG_ISDN_DIVERSION */
-#include "isdn_v110.h"
-
-/* Debugflags */
-#undef ISDN_DEBUG_STATCALLB
-
-MODULE_DESCRIPTION("ISDN4Linux: link layer");
-MODULE_AUTHOR("Fritz Elfert");
-MODULE_LICENSE("GPL");
-
-isdn_dev *dev;
-
-static DEFINE_MUTEX(isdn_mutex);
-static char *isdn_revision = "$Revision: 1.1.2.3 $";
-
-extern char *isdn_net_revision;
-#ifdef CONFIG_ISDN_PPP
-extern char *isdn_ppp_revision;
-#else
-static char *isdn_ppp_revision = ": none $";
-#endif
-#ifdef CONFIG_ISDN_AUDIO
-extern char *isdn_audio_revision;
-#else
-static char *isdn_audio_revision = ": none $";
-#endif
-extern char *isdn_v110_revision;
-
-#ifdef CONFIG_ISDN_DIVERSION
-static isdn_divert_if *divert_if; /* = NULL */
-#endif /* CONFIG_ISDN_DIVERSION */
-
-
-static int isdn_writebuf_stub(int, int, const u_char __user *, int);
-static void set_global_features(void);
-static int isdn_wildmat(char *s, char *p);
-static int isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding);
-
-static inline void
-isdn_lock_driver(isdn_driver_t *drv)
-{
- try_module_get(drv->interface->owner);
- drv->locks++;
-}
-
-void
-isdn_lock_drivers(void)
-{
- int i;
-
- for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
- if (!dev->drv[i])
- continue;
- isdn_lock_driver(dev->drv[i]);
- }
-}
-
-static inline void
-isdn_unlock_driver(isdn_driver_t *drv)
-{
- if (drv->locks > 0) {
- drv->locks--;
- module_put(drv->interface->owner);
- }
-}
-
-void
-isdn_unlock_drivers(void)
-{
- int i;
-
- for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
- if (!dev->drv[i])
- continue;
- isdn_unlock_driver(dev->drv[i]);
- }
-}
-
-#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
-void
-isdn_dumppkt(char *s, u_char *p, int len, int dumplen)
-{
- int dumpc;
-
- printk(KERN_DEBUG "%s(%d) ", s, len);
- for (dumpc = 0; (dumpc < dumplen) && (len); len--, dumpc++)
- printk(" %02x", *p++);
- printk("\n");
-}
-#endif
-
-/*
- * I picked the pattern-matching-functions from an old GNU-tar version (1.10)
- * It was originally written and put to PD by rs@mirror.TMC.COM (Rich Salz)
- */
-static int
-isdn_star(char *s, char *p)
-{
- while (isdn_wildmat(s, p)) {
- if (*++s == '\0')
- return (2);
- }
- return (0);
-}
-
-/*
- * Shell-type Pattern-matching for incoming caller-Ids
- * This function gets a string in s and checks, if it matches the pattern
- * given in p.
- *
- * Return:
- * 0 = match.
- * 1 = no match.
- * 2 = no match. Would eventually match, if s would be longer.
- *
- * Possible Patterns:
- *
- * '?' matches one character
- * '*' matches zero or more characters
- * [xyz] matches the set of characters in brackets.
- * [^xyz] matches any single character not in the set of characters
- */
-
-static int
-isdn_wildmat(char *s, char *p)
-{
- register int last;
- register int matched;
- register int reverse;
- register int nostar = 1;
-
- if (!(*s) && !(*p))
- return (1);
- for (; *p; s++, p++)
- switch (*p) {
- case '\\':
- /* Literal match with following character. */
- p++;
- /* fall through */
- default:
- if (*s != *p)
- return (*s == '\0') ? 2 : 1;
- continue;
- case '?':
- /* Match anything. */
- if (*s == '\0')
- return (2);
- continue;
- case '*':
- nostar = 0;
- /* Trailing star matches everything. */
- return (*++p ? isdn_star(s, p) : 0);
- case '[':
- /* [^....] means inverse character class. */
- if ((reverse = (p[1] == '^')))
- p++;
- for (last = 0, matched = 0; *++p && (*p != ']'); last = *p)
- /* This next line requires a good C compiler. */
- if (*p == '-' ? *s <= *++p && *s >= last : *s == *p)
- matched = 1;
- if (matched == reverse)
- return (1);
- continue;
- }
- return (*s == '\0') ? 0 : nostar;
-}
-
-int isdn_msncmp(const char *msn1, const char *msn2)
-{
- char TmpMsn1[ISDN_MSNLEN];
- char TmpMsn2[ISDN_MSNLEN];
- char *p;
-
- for (p = TmpMsn1; *msn1 && *msn1 != ':';) // Strip off a SPID
- *p++ = *msn1++;
- *p = '\0';
-
- for (p = TmpMsn2; *msn2 && *msn2 != ':';) // Strip off a SPID
- *p++ = *msn2++;
- *p = '\0';
-
- return isdn_wildmat(TmpMsn1, TmpMsn2);
-}
-
-int
-isdn_dc2minor(int di, int ch)
-{
- int i;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (dev->chanmap[i] == ch && dev->drvmap[i] == di)
- return i;
- return -1;
-}
-
-static int isdn_timer_cnt1 = 0;
-static int isdn_timer_cnt2 = 0;
-static int isdn_timer_cnt3 = 0;
-
-static void
-isdn_timer_funct(struct timer_list *unused)
-{
- int tf = dev->tflags;
- if (tf & ISDN_TIMER_FAST) {
- if (tf & ISDN_TIMER_MODEMREAD)
- isdn_tty_readmodem();
- if (tf & ISDN_TIMER_MODEMPLUS)
- isdn_tty_modem_escape();
- if (tf & ISDN_TIMER_MODEMXMIT)
- isdn_tty_modem_xmit();
- }
- if (tf & ISDN_TIMER_SLOW) {
- if (++isdn_timer_cnt1 >= ISDN_TIMER_02SEC) {
- isdn_timer_cnt1 = 0;
- if (tf & ISDN_TIMER_NETDIAL)
- isdn_net_dial();
- }
- if (++isdn_timer_cnt2 >= ISDN_TIMER_1SEC) {
- isdn_timer_cnt2 = 0;
- if (tf & ISDN_TIMER_NETHANGUP)
- isdn_net_autohup();
- if (++isdn_timer_cnt3 >= ISDN_TIMER_RINGING) {
- isdn_timer_cnt3 = 0;
- if (tf & ISDN_TIMER_MODEMRING)
- isdn_tty_modem_ring();
- }
- if (tf & ISDN_TIMER_CARRIER)
- isdn_tty_carrier_timeout();
- }
- }
- if (tf)
- mod_timer(&dev->timer, jiffies + ISDN_TIMER_RES);
-}
-
-void
-isdn_timer_ctrl(int tf, int onoff)
-{
- unsigned long flags;
- int old_tflags;
-
- spin_lock_irqsave(&dev->timerlock, flags);
- if ((tf & ISDN_TIMER_SLOW) && (!(dev->tflags & ISDN_TIMER_SLOW))) {
- /* If the slow-timer wasn't activated until now */
- isdn_timer_cnt1 = 0;
- isdn_timer_cnt2 = 0;
- }
- old_tflags = dev->tflags;
- if (onoff)
- dev->tflags |= tf;
- else
- dev->tflags &= ~tf;
- if (dev->tflags && !old_tflags)
- mod_timer(&dev->timer, jiffies + ISDN_TIMER_RES);
- spin_unlock_irqrestore(&dev->timerlock, flags);
-}
-
-/*
- * Receive a packet from B-Channel. (Called from low-level-module)
- */
-static void
-isdn_receive_skb_callback(int di, int channel, struct sk_buff *skb)
-{
- int i;
-
- if ((i = isdn_dc2minor(di, channel)) == -1) {
- dev_kfree_skb(skb);
- return;
- }
- /* Update statistics */
- dev->ibytes[i] += skb->len;
-
- /* First, try to deliver data to network-device */
- if (isdn_net_rcv_skb(i, skb))
- return;
-
- /* V.110 handling
- * makes sense for async streams only, so it is
- * called after possible net-device delivery.
- */
- if (dev->v110[i]) {
- atomic_inc(&dev->v110use[i]);
- skb = isdn_v110_decode(dev->v110[i], skb);
- atomic_dec(&dev->v110use[i]);
- if (!skb)
- return;
- }
-
- /* No network-device found, deliver to tty or raw-channel */
- if (skb->len) {
- if (isdn_tty_rcv_skb(i, di, channel, skb))
- return;
- wake_up_interruptible(&dev->drv[di]->rcv_waitq[channel]);
- } else
- dev_kfree_skb(skb);
-}
-
-/*
- * Intercept command from Linklevel to Lowlevel.
- * If layer 2 protocol is V.110 and this is not supported by current
- * lowlevel-driver, use driver's transparent mode and handle V.110 in
- * linklevel instead.
- */
-int
-isdn_command(isdn_ctrl *cmd)
-{
- if (cmd->driver == -1) {
- printk(KERN_WARNING "isdn_command command(%x) driver -1\n", cmd->command);
- return (1);
- }
- if (!dev->drv[cmd->driver]) {
- printk(KERN_WARNING "isdn_command command(%x) dev->drv[%d] NULL\n",
- cmd->command, cmd->driver);
- return (1);
- }
- if (!dev->drv[cmd->driver]->interface) {
- printk(KERN_WARNING "isdn_command command(%x) dev->drv[%d]->interface NULL\n",
- cmd->command, cmd->driver);
- return (1);
- }
- if (cmd->command == ISDN_CMD_SETL2) {
- int idx = isdn_dc2minor(cmd->driver, cmd->arg & 255);
- unsigned long l2prot = (cmd->arg >> 8) & 255;
- unsigned long features = (dev->drv[cmd->driver]->interface->features
- >> ISDN_FEATURE_L2_SHIFT) &
- ISDN_FEATURE_L2_MASK;
- unsigned long l2_feature = (1 << l2prot);
-
- switch (l2prot) {
- case ISDN_PROTO_L2_V11096:
- case ISDN_PROTO_L2_V11019:
- case ISDN_PROTO_L2_V11038:
- /* If V.110 requested, but not supported by
- * HL-driver, set emulator-flag and change
- * Layer-2 to transparent
- */
- if (!(features & l2_feature)) {
- dev->v110emu[idx] = l2prot;
- cmd->arg = (cmd->arg & 255) |
- (ISDN_PROTO_L2_TRANS << 8);
- } else
- dev->v110emu[idx] = 0;
- }
- }
- return dev->drv[cmd->driver]->interface->command(cmd);
-}
-
-void
-isdn_all_eaz(int di, int ch)
-{
- isdn_ctrl cmd;
-
- if (di < 0)
- return;
- cmd.driver = di;
- cmd.arg = ch;
- cmd.command = ISDN_CMD_SETEAZ;
- cmd.parm.num[0] = '\0';
- isdn_command(&cmd);
-}
-
-/*
- * Begin of a CAPI like LL<->HL interface, currently used only for
- * supplementary service (CAPI 2.0 part III)
- */
-#include <linux/isdn/capicmd.h>
-
-static int
-isdn_capi_rec_hl_msg(capi_msg *cm)
-{
- switch (cm->Command) {
- case CAPI_FACILITY:
- /* in the moment only handled in tty */
- return (isdn_tty_capi_facility(cm));
- default:
- return (-1);
- }
-}
-
-static int
-isdn_status_callback(isdn_ctrl *c)
-{
- int di;
- u_long flags;
- int i;
- int r;
- int retval = 0;
- isdn_ctrl cmd;
- isdn_net_dev *p;
-
- di = c->driver;
- i = isdn_dc2minor(di, c->arg);
- switch (c->command) {
- case ISDN_STAT_BSENT:
- if (i < 0)
- return -1;
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- if (isdn_net_stat_callback(i, c))
- return 0;
- if (isdn_v110_stat_callback(i, c))
- return 0;
- if (isdn_tty_stat_callback(i, c))
- return 0;
- wake_up_interruptible(&dev->drv[di]->snd_waitq[c->arg]);
- break;
- case ISDN_STAT_STAVAIL:
- dev->drv[di]->stavail += c->arg;
- wake_up_interruptible(&dev->drv[di]->st_waitq);
- break;
- case ISDN_STAT_RUN:
- dev->drv[di]->flags |= DRV_FLAG_RUNNING;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (dev->drvmap[i] == di)
- isdn_all_eaz(di, dev->chanmap[i]);
- set_global_features();
- break;
- case ISDN_STAT_STOP:
- dev->drv[di]->flags &= ~DRV_FLAG_RUNNING;
- break;
- case ISDN_STAT_ICALL:
- if (i < 0)
- return -1;
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "ICALL (net): %d %ld %s\n", di, c->arg, c->parm.num);
-#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED) {
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_HANGUP;
- isdn_command(&cmd);
- return 0;
- }
- /* Try to find a network-interface which will accept incoming call */
- r = ((c->command == ISDN_STAT_ICALLW) ? 0 : isdn_net_find_icall(di, c->arg, i, &c->parm.setup));
- switch (r) {
- case 0:
- /* No network-device replies.
- * Try ttyI's.
- * These return 0 on no match, 1 on match and
- * 3 on eventually match, if CID is longer.
- */
- if (c->command == ISDN_STAT_ICALL)
- if ((retval = isdn_tty_find_icall(di, c->arg, &c->parm.setup))) return (retval);
-#ifdef CONFIG_ISDN_DIVERSION
- if (divert_if)
- if ((retval = divert_if->stat_callback(c)))
- return (retval); /* processed */
-#endif /* CONFIG_ISDN_DIVERSION */
- if ((!retval) && (dev->drv[di]->flags & DRV_FLAG_REJBUS)) {
- /* No tty responding */
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_HANGUP;
- isdn_command(&cmd);
- retval = 2;
- }
- break;
- case 1:
- /* Schedule connection-setup */
- isdn_net_dial();
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_ACCEPTD;
- for (p = dev->netdev; p; p = p->next)
- if (p->local->isdn_channel == cmd.arg)
- {
- strcpy(cmd.parm.setup.eazmsn, p->local->msn);
- isdn_command(&cmd);
- retval = 1;
- break;
- }
- break;
-
- case 2: /* For calling back, first reject incoming call ... */
- case 3: /* Interface found, but down, reject call actively */
- retval = 2;
- printk(KERN_INFO "isdn: Rejecting Call\n");
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_HANGUP;
- isdn_command(&cmd);
- if (r == 3)
- break;
- /* Fall through */
- case 4:
- /* ... then start callback. */
- isdn_net_dial();
- break;
- case 5:
- /* Number would eventually match, if longer */
- retval = 3;
- break;
- }
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "ICALL: ret=%d\n", retval);
-#endif
- return retval;
- break;
- case ISDN_STAT_CINF:
- if (i < 0)
- return -1;
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "CINF: %ld %s\n", c->arg, c->parm.num);
-#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- if (strcmp(c->parm.num, "0"))
- isdn_net_stat_callback(i, c);
- isdn_tty_stat_callback(i, c);
- break;
- case ISDN_STAT_CAUSE:
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "CAUSE: %ld %s\n", c->arg, c->parm.num);
-#endif
- printk(KERN_INFO "isdn: %s,ch%ld cause: %s\n",
- dev->drvid[di], c->arg, c->parm.num);
- isdn_tty_stat_callback(i, c);
-#ifdef CONFIG_ISDN_DIVERSION
- if (divert_if)
- divert_if->stat_callback(c);
-#endif /* CONFIG_ISDN_DIVERSION */
- break;
- case ISDN_STAT_DISPLAY:
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "DISPLAY: %ld %s\n", c->arg, c->parm.display);
-#endif
- isdn_tty_stat_callback(i, c);
-#ifdef CONFIG_ISDN_DIVERSION
- if (divert_if)
- divert_if->stat_callback(c);
-#endif /* CONFIG_ISDN_DIVERSION */
- break;
- case ISDN_STAT_DCONN:
- if (i < 0)
- return -1;
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "DCONN: %ld\n", c->arg);
-#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- /* Find any net-device, waiting for D-channel setup */
- if (isdn_net_stat_callback(i, c))
- break;
- isdn_v110_stat_callback(i, c);
- /* Find any ttyI, waiting for D-channel setup */
- if (isdn_tty_stat_callback(i, c)) {
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_ACCEPTB;
- isdn_command(&cmd);
- break;
- }
- break;
- case ISDN_STAT_DHUP:
- if (i < 0)
- return -1;
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "DHUP: %ld\n", c->arg);
-#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- dev->drv[di]->online &= ~(1 << (c->arg));
- isdn_info_update();
- /* Signal hangup to network-devices */
- if (isdn_net_stat_callback(i, c))
- break;
- isdn_v110_stat_callback(i, c);
- if (isdn_tty_stat_callback(i, c))
- break;
-#ifdef CONFIG_ISDN_DIVERSION
- if (divert_if)
- divert_if->stat_callback(c);
-#endif /* CONFIG_ISDN_DIVERSION */
- break;
- break;
- case ISDN_STAT_BCONN:
- if (i < 0)
- return -1;
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "BCONN: %ld\n", c->arg);
-#endif
- /* Signal B-channel-connect to network-devices */
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- dev->drv[di]->online |= (1 << (c->arg));
- isdn_info_update();
- if (isdn_net_stat_callback(i, c))
- break;
- isdn_v110_stat_callback(i, c);
- if (isdn_tty_stat_callback(i, c))
- break;
- break;
- case ISDN_STAT_BHUP:
- if (i < 0)
- return -1;
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "BHUP: %ld\n", c->arg);
-#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- dev->drv[di]->online &= ~(1 << (c->arg));
- isdn_info_update();
-#ifdef CONFIG_ISDN_X25
- /* Signal hangup to network-devices */
- if (isdn_net_stat_callback(i, c))
- break;
-#endif
- isdn_v110_stat_callback(i, c);
- if (isdn_tty_stat_callback(i, c))
- break;
- break;
- case ISDN_STAT_NODCH:
- if (i < 0)
- return -1;
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "NODCH: %ld\n", c->arg);
-#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- if (isdn_net_stat_callback(i, c))
- break;
- if (isdn_tty_stat_callback(i, c))
- break;
- break;
- case ISDN_STAT_ADDCH:
- spin_lock_irqsave(&dev->lock, flags);
- if (isdn_add_channels(dev->drv[di], di, c->arg, 1)) {
- spin_unlock_irqrestore(&dev->lock, flags);
- return -1;
- }
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_info_update();
- break;
- case ISDN_STAT_DISCH:
- spin_lock_irqsave(&dev->lock, flags);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if ((dev->drvmap[i] == di) &&
- (dev->chanmap[i] == c->arg)) {
- if (c->parm.num[0])
- dev->usage[i] &= ~ISDN_USAGE_DISABLED;
- else
- if (USG_NONE(dev->usage[i])) {
- dev->usage[i] |= ISDN_USAGE_DISABLED;
- }
- else
- retval = -1;
- break;
- }
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_info_update();
- break;
- case ISDN_STAT_UNLOAD:
- while (dev->drv[di]->locks > 0) {
- isdn_unlock_driver(dev->drv[di]);
- }
- spin_lock_irqsave(&dev->lock, flags);
- isdn_tty_stat_callback(i, c);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (dev->drvmap[i] == di) {
- dev->drvmap[i] = -1;
- dev->chanmap[i] = -1;
- dev->usage[i] &= ~ISDN_USAGE_DISABLED;
- }
- dev->drivers--;
- dev->channels -= dev->drv[di]->channels;
- kfree(dev->drv[di]->rcverr);
- kfree(dev->drv[di]->rcvcount);
- for (i = 0; i < dev->drv[di]->channels; i++)
- skb_queue_purge(&dev->drv[di]->rpqueue[i]);
- kfree(dev->drv[di]->rpqueue);
- kfree(dev->drv[di]->rcv_waitq);
- kfree(dev->drv[di]);
- dev->drv[di] = NULL;
- dev->drvid[di][0] = '\0';
- isdn_info_update();
- set_global_features();
- spin_unlock_irqrestore(&dev->lock, flags);
- return 0;
- case ISDN_STAT_L1ERR:
- break;
- case CAPI_PUT_MESSAGE:
- return (isdn_capi_rec_hl_msg(&c->parm.cmsg));
-#ifdef CONFIG_ISDN_TTY_FAX
- case ISDN_STAT_FAXIND:
- isdn_tty_stat_callback(i, c);
- break;
-#endif
-#ifdef CONFIG_ISDN_AUDIO
- case ISDN_STAT_AUDIO:
- isdn_tty_stat_callback(i, c);
- break;
-#endif
-#ifdef CONFIG_ISDN_DIVERSION
- case ISDN_STAT_PROT:
- case ISDN_STAT_REDIR:
- if (divert_if)
- return (divert_if->stat_callback(c));
-#endif /* CONFIG_ISDN_DIVERSION */
- /* fall through */
- default:
- return -1;
- }
- return 0;
-}
-
-/*
- * Get integer from char-pointer, set pointer to end of number
- */
-int
-isdn_getnum(char **p)
-{
- int v = -1;
-
- while (*p[0] >= '0' && *p[0] <= '9')
- v = ((v < 0) ? 0 : (v * 10)) + (int) ((*p[0]++) - '0');
- return v;
-}
-
-#define DLE 0x10
-
-/*
- * isdn_readbchan() tries to get data from the read-queue.
- * It MUST be called with interrupts off.
- *
- * Be aware that this is not an atomic operation when sleep != 0, even though
- * interrupts are turned off! Well, like that we are currently only called
- * on behalf of a read system call on raw device files (which are documented
- * to be dangerous and for debugging purpose only). The inode semaphore
- * takes care that this is not called for the same minor device number while
- * we are sleeping, but access is not serialized against simultaneous read()
- * from the corresponding ttyI device. Can other ugly events, like changes
- * of the mapping (di,ch)<->minor, happen during the sleep? --he
- */
-int
-isdn_readbchan(int di, int channel, u_char *buf, u_char *fp, int len, wait_queue_head_t *sleep)
-{
- int count;
- int count_pull;
- int count_put;
- int dflag;
- struct sk_buff *skb;
- u_char *cp;
-
- if (!dev->drv[di])
- return 0;
- if (skb_queue_empty(&dev->drv[di]->rpqueue[channel])) {
- if (sleep)
- wait_event_interruptible(*sleep,
- !skb_queue_empty(&dev->drv[di]->rpqueue[channel]));
- else
- return 0;
- }
- if (len > dev->drv[di]->rcvcount[channel])
- len = dev->drv[di]->rcvcount[channel];
- cp = buf;
- count = 0;
- while (len) {
- if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel])))
- break;
-#ifdef CONFIG_ISDN_AUDIO
- if (ISDN_AUDIO_SKB_LOCK(skb))
- break;
- ISDN_AUDIO_SKB_LOCK(skb) = 1;
- if ((ISDN_AUDIO_SKB_DLECOUNT(skb)) || (dev->drv[di]->DLEflag & (1 << channel))) {
- char *p = skb->data;
- unsigned long DLEmask = (1 << channel);
-
- dflag = 0;
- count_pull = count_put = 0;
- while ((count_pull < skb->len) && (len > 0)) {
- len--;
- if (dev->drv[di]->DLEflag & DLEmask) {
- *cp++ = DLE;
- dev->drv[di]->DLEflag &= ~DLEmask;
- } else {
- *cp++ = *p;
- if (*p == DLE) {
- dev->drv[di]->DLEflag |= DLEmask;
- (ISDN_AUDIO_SKB_DLECOUNT(skb))--;
- }
- p++;
- count_pull++;
- }
- count_put++;
- }
- if (count_pull >= skb->len)
- dflag = 1;
- } else {
-#endif
- /* No DLE's in buff, so simply copy it */
- dflag = 1;
- if ((count_pull = skb->len) > len) {
- count_pull = len;
- dflag = 0;
- }
- count_put = count_pull;
- skb_copy_from_linear_data(skb, cp, count_put);
- cp += count_put;
- len -= count_put;
-#ifdef CONFIG_ISDN_AUDIO
- }
-#endif
- count += count_put;
- if (fp) {
- memset(fp, 0, count_put);
- fp += count_put;
- }
- if (dflag) {
- /* We got all the data in this buff.
- * Now we can dequeue it.
- */
- if (fp)
- *(fp - 1) = 0xff;
-#ifdef CONFIG_ISDN_AUDIO
- ISDN_AUDIO_SKB_LOCK(skb) = 0;
-#endif
- skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]);
- dev_kfree_skb(skb);
- } else {
- /* Not yet emptied this buff, so it
- * must stay in the queue, for further calls
- * but we pull off the data we got until now.
- */
- skb_pull(skb, count_pull);
-#ifdef CONFIG_ISDN_AUDIO
- ISDN_AUDIO_SKB_LOCK(skb) = 0;
-#endif
- }
- dev->drv[di]->rcvcount[channel] -= count_put;
- }
- return count;
-}
-
-/*
- * isdn_readbchan_tty() tries to get data from the read-queue.
- * It MUST be called with interrupts off.
- *
- * Be aware that this is not an atomic operation when sleep != 0, even though
- * interrupts are turned off! Well, like that we are currently only called
- * on behalf of a read system call on raw device files (which are documented
- * to be dangerous and for debugging purpose only). The inode semaphore
- * takes care that this is not called for the same minor device number while
- * we are sleeping, but access is not serialized against simultaneous read()
- * from the corresponding ttyI device. Can other ugly events, like changes
- * of the mapping (di,ch)<->minor, happen during the sleep? --he
- */
-int
-isdn_readbchan_tty(int di, int channel, struct tty_port *port, int cisco_hack)
-{
- int count;
- int count_pull;
- int count_put;
- int dflag;
- struct sk_buff *skb;
- char last = 0;
- int len;
-
- if (!dev->drv[di])
- return 0;
- if (skb_queue_empty(&dev->drv[di]->rpqueue[channel]))
- return 0;
-
- len = tty_buffer_request_room(port, dev->drv[di]->rcvcount[channel]);
- if (len == 0)
- return len;
-
- count = 0;
- while (len) {
- if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel])))
- break;
-#ifdef CONFIG_ISDN_AUDIO
- if (ISDN_AUDIO_SKB_LOCK(skb))
- break;
- ISDN_AUDIO_SKB_LOCK(skb) = 1;
- if ((ISDN_AUDIO_SKB_DLECOUNT(skb)) || (dev->drv[di]->DLEflag & (1 << channel))) {
- char *p = skb->data;
- unsigned long DLEmask = (1 << channel);
-
- dflag = 0;
- count_pull = count_put = 0;
- while ((count_pull < skb->len) && (len > 0)) {
- /* push every character but the last to the tty buffer directly */
- if (count_put)
- tty_insert_flip_char(port, last, TTY_NORMAL);
- len--;
- if (dev->drv[di]->DLEflag & DLEmask) {
- last = DLE;
- dev->drv[di]->DLEflag &= ~DLEmask;
- } else {
- last = *p;
- if (last == DLE) {
- dev->drv[di]->DLEflag |= DLEmask;
- (ISDN_AUDIO_SKB_DLECOUNT(skb))--;
- }
- p++;
- count_pull++;
- }
- count_put++;
- }
- if (count_pull >= skb->len)
- dflag = 1;
- } else {
-#endif
- /* No DLE's in buff, so simply copy it */
- dflag = 1;
- if ((count_pull = skb->len) > len) {
- count_pull = len;
- dflag = 0;
- }
- count_put = count_pull;
- if (count_put > 1)
- tty_insert_flip_string(port, skb->data, count_put - 1);
- last = skb->data[count_put - 1];
- len -= count_put;
-#ifdef CONFIG_ISDN_AUDIO
- }
-#endif
- count += count_put;
- if (dflag) {
- /* We got all the data in this buff.
- * Now we can dequeue it.
- */
- if (cisco_hack)
- tty_insert_flip_char(port, last, 0xFF);
- else
- tty_insert_flip_char(port, last, TTY_NORMAL);
-#ifdef CONFIG_ISDN_AUDIO
- ISDN_AUDIO_SKB_LOCK(skb) = 0;
-#endif
- skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]);
- dev_kfree_skb(skb);
- } else {
- tty_insert_flip_char(port, last, TTY_NORMAL);
- /* Not yet emptied this buff, so it
- * must stay in the queue, for further calls
- * but we pull off the data we got until now.
- */
- skb_pull(skb, count_pull);
-#ifdef CONFIG_ISDN_AUDIO
- ISDN_AUDIO_SKB_LOCK(skb) = 0;
-#endif
- }
- dev->drv[di]->rcvcount[channel] -= count_put;
- }
- return count;
-}
-
-
-static inline int
-isdn_minor2drv(int minor)
-{
- return (dev->drvmap[minor]);
-}
-
-static inline int
-isdn_minor2chan(int minor)
-{
- return (dev->chanmap[minor]);
-}
-
-static char *
-isdn_statstr(void)
-{
- static char istatbuf[2048];
- char *p;
- int i;
-
- sprintf(istatbuf, "idmap:\t");
- p = istatbuf + strlen(istatbuf);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- sprintf(p, "%s ", (dev->drvmap[i] < 0) ? "-" : dev->drvid[dev->drvmap[i]]);
- p = istatbuf + strlen(istatbuf);
- }
- sprintf(p, "\nchmap:\t");
- p = istatbuf + strlen(istatbuf);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- sprintf(p, "%d ", dev->chanmap[i]);
- p = istatbuf + strlen(istatbuf);
- }
- sprintf(p, "\ndrmap:\t");
- p = istatbuf + strlen(istatbuf);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- sprintf(p, "%d ", dev->drvmap[i]);
- p = istatbuf + strlen(istatbuf);
- }
- sprintf(p, "\nusage:\t");
- p = istatbuf + strlen(istatbuf);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- sprintf(p, "%d ", dev->usage[i]);
- p = istatbuf + strlen(istatbuf);
- }
- sprintf(p, "\nflags:\t");
- p = istatbuf + strlen(istatbuf);
- for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
- if (dev->drv[i]) {
- sprintf(p, "%ld ", dev->drv[i]->online);
- p = istatbuf + strlen(istatbuf);
- } else {
- sprintf(p, "? ");
- p = istatbuf + strlen(istatbuf);
- }
- }
- sprintf(p, "\nphone:\t");
- p = istatbuf + strlen(istatbuf);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- sprintf(p, "%s ", dev->num[i]);
- p = istatbuf + strlen(istatbuf);
- }
- sprintf(p, "\n");
- return istatbuf;
-}
-
-/* Module interface-code */
-
-void
-isdn_info_update(void)
-{
- infostruct *p = dev->infochain;
-
- while (p) {
- *(p->private) = 1;
- p = (infostruct *) p->next;
- }
- wake_up_interruptible(&(dev->info_waitq));
-}
-
-static ssize_t
-isdn_read(struct file *file, char __user *buf, size_t count, loff_t *off)
-{
- uint minor = iminor(file_inode(file));
- int len = 0;
- int drvidx;
- int chidx;
- int retval;
- char *p;
-
- mutex_lock(&isdn_mutex);
- if (minor == ISDN_MINOR_STATUS) {
- if (!file->private_data) {
- if (file->f_flags & O_NONBLOCK) {
- retval = -EAGAIN;
- goto out;
- }
- wait_event_interruptible(dev->info_waitq,
- file->private_data);
- }
- p = isdn_statstr();
- file->private_data = NULL;
- if ((len = strlen(p)) <= count) {
- if (copy_to_user(buf, p, len)) {
- retval = -EFAULT;
- goto out;
- }
- *off += len;
- retval = len;
- goto out;
- }
- retval = 0;
- goto out;
- }
- if (!dev->drivers) {
- retval = -ENODEV;
- goto out;
- }
- if (minor <= ISDN_MINOR_BMAX) {
- printk(KERN_WARNING "isdn_read minor %d obsolete!\n", minor);
- drvidx = isdn_minor2drv(minor);
- if (drvidx < 0) {
- retval = -ENODEV;
- goto out;
- }
- if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) {
- retval = -ENODEV;
- goto out;
- }
- chidx = isdn_minor2chan(minor);
- if (!(p = kmalloc(count, GFP_KERNEL))) {
- retval = -ENOMEM;
- goto out;
- }
- len = isdn_readbchan(drvidx, chidx, p, NULL, count,
- &dev->drv[drvidx]->rcv_waitq[chidx]);
- *off += len;
- if (copy_to_user(buf, p, len))
- len = -EFAULT;
- kfree(p);
- retval = len;
- goto out;
- }
- if (minor <= ISDN_MINOR_CTRLMAX) {
- drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
- if (drvidx < 0) {
- retval = -ENODEV;
- goto out;
- }
- if (!dev->drv[drvidx]->stavail) {
- if (file->f_flags & O_NONBLOCK) {
- retval = -EAGAIN;
- goto out;
- }
- wait_event_interruptible(dev->drv[drvidx]->st_waitq,
- dev->drv[drvidx]->stavail);
- }
- if (dev->drv[drvidx]->interface->readstat) {
- if (count > dev->drv[drvidx]->stavail)
- count = dev->drv[drvidx]->stavail;
- len = dev->drv[drvidx]->interface->readstat(buf, count,
- drvidx, isdn_minor2chan(minor - ISDN_MINOR_CTRL));
- if (len < 0) {
- retval = len;
- goto out;
- }
- } else {
- len = 0;
- }
- if (len)
- dev->drv[drvidx]->stavail -= len;
- else
- dev->drv[drvidx]->stavail = 0;
- *off += len;
- retval = len;
- goto out;
- }
-#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX) {
- retval = isdn_ppp_read(minor - ISDN_MINOR_PPP, file, buf, count);
- goto out;
- }
-#endif
- retval = -ENODEV;
-out:
- mutex_unlock(&isdn_mutex);
- return retval;
-}
-
-static ssize_t
-isdn_write(struct file *file, const char __user *buf, size_t count, loff_t *off)
-{
- uint minor = iminor(file_inode(file));
- int drvidx;
- int chidx;
- int retval;
-
- if (minor == ISDN_MINOR_STATUS)
- return -EPERM;
- if (!dev->drivers)
- return -ENODEV;
-
- mutex_lock(&isdn_mutex);
- if (minor <= ISDN_MINOR_BMAX) {
- printk(KERN_WARNING "isdn_write minor %d obsolete!\n", minor);
- drvidx = isdn_minor2drv(minor);
- if (drvidx < 0) {
- retval = -ENODEV;
- goto out;
- }
- if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) {
- retval = -ENODEV;
- goto out;
- }
- chidx = isdn_minor2chan(minor);
- wait_event_interruptible(dev->drv[drvidx]->snd_waitq[chidx],
- (retval = isdn_writebuf_stub(drvidx, chidx, buf, count)));
- goto out;
- }
- if (minor <= ISDN_MINOR_CTRLMAX) {
- drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
- if (drvidx < 0) {
- retval = -ENODEV;
- goto out;
- }
- /*
- * We want to use the isdnctrl device to load the firmware
- *
- if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
- return -ENODEV;
- */
- if (dev->drv[drvidx]->interface->writecmd)
- retval = dev->drv[drvidx]->interface->
- writecmd(buf, count, drvidx,
- isdn_minor2chan(minor - ISDN_MINOR_CTRL));
- else
- retval = count;
- goto out;
- }
-#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX) {
- retval = isdn_ppp_write(minor - ISDN_MINOR_PPP, file, buf, count);
- goto out;
- }
-#endif
- retval = -ENODEV;
-out:
- mutex_unlock(&isdn_mutex);
- return retval;
-}
-
-static __poll_t
-isdn_poll(struct file *file, poll_table *wait)
-{
- __poll_t mask = 0;
- unsigned int minor = iminor(file_inode(file));
- int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
-
- mutex_lock(&isdn_mutex);
- if (minor == ISDN_MINOR_STATUS) {
- poll_wait(file, &(dev->info_waitq), wait);
- /* mask = EPOLLOUT | EPOLLWRNORM; */
- if (file->private_data) {
- mask |= EPOLLIN | EPOLLRDNORM;
- }
- goto out;
- }
- if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) {
- if (drvidx < 0) {
- /* driver deregistered while file open */
- mask = EPOLLHUP;
- goto out;
- }
- poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait);
- mask = EPOLLOUT | EPOLLWRNORM;
- if (dev->drv[drvidx]->stavail) {
- mask |= EPOLLIN | EPOLLRDNORM;
- }
- goto out;
- }
-#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX) {
- mask = isdn_ppp_poll(file, wait);
- goto out;
- }
-#endif
- mask = EPOLLERR;
-out:
- mutex_unlock(&isdn_mutex);
- return mask;
-}
-
-
-static int
-isdn_ioctl(struct file *file, uint cmd, ulong arg)
-{
- uint minor = iminor(file_inode(file));
- isdn_ctrl c;
- int drvidx;
- int ret;
- int i;
- char __user *p;
- char *s;
- union iocpar {
- char name[10];
- char bname[22];
- isdn_ioctl_struct iocts;
- isdn_net_ioctl_phone phone;
- isdn_net_ioctl_cfg cfg;
- } iocpar;
- void __user *argp = (void __user *)arg;
-
-#define name iocpar.name
-#define bname iocpar.bname
-#define iocts iocpar.iocts
-#define phone iocpar.phone
-#define cfg iocpar.cfg
-
- if (minor == ISDN_MINOR_STATUS) {
- switch (cmd) {
- case IIOCGETDVR:
- return (TTY_DV +
- (NET_DV << 8) +
- (INF_DV << 16));
- case IIOCGETCPS:
- if (arg) {
- ulong __user *p = argp;
- int i;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- put_user(dev->ibytes[i], p++);
- put_user(dev->obytes[i], p++);
- }
- return 0;
- } else
- return -EINVAL;
- break;
- case IIOCNETGPN:
- /* Get peer phone number of a connected
- * isdn network interface */
- if (arg) {
- if (copy_from_user(&phone, argp, sizeof(phone)))
- return -EFAULT;
- return isdn_net_getpeer(&phone, argp);
- } else
- return -EINVAL;
- default:
- return -EINVAL;
- }
- }
- if (!dev->drivers)
- return -ENODEV;
- if (minor <= ISDN_MINOR_BMAX) {
- drvidx = isdn_minor2drv(minor);
- if (drvidx < 0)
- return -ENODEV;
- if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
- return -ENODEV;
- return 0;
- }
- if (minor <= ISDN_MINOR_CTRLMAX) {
-/*
- * isdn net devices manage lots of configuration variables as linked lists.
- * Those lists must only be manipulated from user space. Some of the ioctl's
- * service routines access user space and are not atomic. Therefore, ioctl's
- * manipulating the lists and ioctl's sleeping while accessing the lists
- * are serialized by means of a semaphore.
- */
- switch (cmd) {
- case IIOCNETDWRSET:
- printk(KERN_INFO "INFO: ISDN_DW_ABC_EXTENSION not enabled\n");
- return (-EINVAL);
- case IIOCNETLCR:
- printk(KERN_INFO "INFO: ISDN_ABC_LCR_SUPPORT not enabled\n");
- return -ENODEV;
- case IIOCNETAIF:
- /* Add a network-interface */
- if (arg) {
- if (copy_from_user(name, argp, sizeof(name)))
- return -EFAULT;
- s = name;
- } else {
- s = NULL;
- }
- ret = mutex_lock_interruptible(&dev->mtx);
- if (ret) return ret;
- if ((s = isdn_net_new(s, NULL))) {
- if (copy_to_user(argp, s, strlen(s) + 1)) {
- ret = -EFAULT;
- } else {
- ret = 0;
- }
- } else
- ret = -ENODEV;
- mutex_unlock(&dev->mtx);
- return ret;
- case IIOCNETASL:
- /* Add a slave to a network-interface */
- if (arg) {
- if (copy_from_user(bname, argp, sizeof(bname) - 1))
- return -EFAULT;
- bname[sizeof(bname)-1] = 0;
- } else
- return -EINVAL;
- ret = mutex_lock_interruptible(&dev->mtx);
- if (ret) return ret;
- if ((s = isdn_net_newslave(bname))) {
- if (copy_to_user(argp, s, strlen(s) + 1)) {
- ret = -EFAULT;
- } else {
- ret = 0;
- }
- } else
- ret = -ENODEV;
- mutex_unlock(&dev->mtx);
- return ret;
- case IIOCNETDIF:
- /* Delete a network-interface */
- if (arg) {
- if (copy_from_user(name, argp, sizeof(name)))
- return -EFAULT;
- ret = mutex_lock_interruptible(&dev->mtx);
- if (ret) return ret;
- ret = isdn_net_rm(name);
- mutex_unlock(&dev->mtx);
- return ret;
- } else
- return -EINVAL;
- case IIOCNETSCF:
- /* Set configurable parameters of a network-interface */
- if (arg) {
- if (copy_from_user(&cfg, argp, sizeof(cfg)))
- return -EFAULT;
- return isdn_net_setcfg(&cfg);
- } else
- return -EINVAL;
- case IIOCNETGCF:
- /* Get configurable parameters of a network-interface */
- if (arg) {
- if (copy_from_user(&cfg, argp, sizeof(cfg)))
- return -EFAULT;
- if (!(ret = isdn_net_getcfg(&cfg))) {
- if (copy_to_user(argp, &cfg, sizeof(cfg)))
- return -EFAULT;
- }
- return ret;
- } else
- return -EINVAL;
- case IIOCNETANM:
- /* Add a phone-number to a network-interface */
- if (arg) {
- if (copy_from_user(&phone, argp, sizeof(phone)))
- return -EFAULT;
- ret = mutex_lock_interruptible(&dev->mtx);
- if (ret) return ret;
- ret = isdn_net_addphone(&phone);
- mutex_unlock(&dev->mtx);
- return ret;
- } else
- return -EINVAL;
- case IIOCNETGNM:
- /* Get list of phone-numbers of a network-interface */
- if (arg) {
- if (copy_from_user(&phone, argp, sizeof(phone)))
- return -EFAULT;
- ret = mutex_lock_interruptible(&dev->mtx);
- if (ret) return ret;
- ret = isdn_net_getphones(&phone, argp);
- mutex_unlock(&dev->mtx);
- return ret;
- } else
- return -EINVAL;
- case IIOCNETDNM:
- /* Delete a phone-number of a network-interface */
- if (arg) {
- if (copy_from_user(&phone, argp, sizeof(phone)))
- return -EFAULT;
- ret = mutex_lock_interruptible(&dev->mtx);
- if (ret) return ret;
- ret = isdn_net_delphone(&phone);
- mutex_unlock(&dev->mtx);
- return ret;
- } else
- return -EINVAL;
- case IIOCNETDIL:
- /* Force dialing of a network-interface */
- if (arg) {
- if (copy_from_user(name, argp, sizeof(name)))
- return -EFAULT;
- return isdn_net_force_dial(name);
- } else
- return -EINVAL;
-#ifdef CONFIG_ISDN_PPP
- case IIOCNETALN:
- if (!arg)
- return -EINVAL;
- if (copy_from_user(name, argp, sizeof(name)))
- return -EFAULT;
- return isdn_ppp_dial_slave(name);
- case IIOCNETDLN:
- if (!arg)
- return -EINVAL;
- if (copy_from_user(name, argp, sizeof(name)))
- return -EFAULT;
- return isdn_ppp_hangup_slave(name);
-#endif
- case IIOCNETHUP:
- /* Force hangup of a network-interface */
- if (!arg)
- return -EINVAL;
- if (copy_from_user(name, argp, sizeof(name)))
- return -EFAULT;
- return isdn_net_force_hangup(name);
- break;
- case IIOCSETVER:
- dev->net_verbose = arg;
- printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose);
- return 0;
- case IIOCSETGST:
- if (arg)
- dev->global_flags |= ISDN_GLOBAL_STOPPED;
- else
- dev->global_flags &= ~ISDN_GLOBAL_STOPPED;
- printk(KERN_INFO "isdn: Global Mode %s\n",
- (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running");
- return 0;
- case IIOCSETBRJ:
- drvidx = -1;
- if (arg) {
- int i;
- char *p;
- if (copy_from_user(&iocts, argp,
- sizeof(isdn_ioctl_struct)))
- return -EFAULT;
- iocts.drvid[sizeof(iocts.drvid) - 1] = 0;
- if (strlen(iocts.drvid)) {
- if ((p = strchr(iocts.drvid, ',')))
- *p = 0;
- drvidx = -1;
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- if (!(strcmp(dev->drvid[i], iocts.drvid))) {
- drvidx = i;
- break;
- }
- }
- }
- if (drvidx == -1)
- return -ENODEV;
- if (iocts.arg)
- dev->drv[drvidx]->flags |= DRV_FLAG_REJBUS;
- else
- dev->drv[drvidx]->flags &= ~DRV_FLAG_REJBUS;
- return 0;
- case IIOCSIGPRF:
- dev->profd = current;
- return 0;
- break;
- case IIOCGETPRF:
- /* Get all Modem-Profiles */
- if (arg) {
- char __user *p = argp;
- int i;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if (copy_to_user(p, dev->mdm.info[i].emu.profile,
- ISDN_MODEM_NUMREG))
- return -EFAULT;
- p += ISDN_MODEM_NUMREG;
- if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN))
- return -EFAULT;
- p += ISDN_MSNLEN;
- if (copy_to_user(p, dev->mdm.info[i].emu.plmsn, ISDN_LMSNLEN))
- return -EFAULT;
- p += ISDN_LMSNLEN;
- }
- return (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS;
- } else
- return -EINVAL;
- break;
- case IIOCSETPRF:
- /* Set all Modem-Profiles */
- if (arg) {
- char __user *p = argp;
- int i;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if (copy_from_user(dev->mdm.info[i].emu.profile, p,
- ISDN_MODEM_NUMREG))
- return -EFAULT;
- p += ISDN_MODEM_NUMREG;
- if (copy_from_user(dev->mdm.info[i].emu.plmsn, p, ISDN_LMSNLEN))
- return -EFAULT;
- p += ISDN_LMSNLEN;
- if (copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN))
- return -EFAULT;
- p += ISDN_MSNLEN;
- }
- return 0;
- } else
- return -EINVAL;
- break;
- case IIOCSETMAP:
- case IIOCGETMAP:
- /* Set/Get MSN->EAZ-Mapping for a driver */
- if (arg) {
-
- if (copy_from_user(&iocts, argp,
- sizeof(isdn_ioctl_struct)))
- return -EFAULT;
- iocts.drvid[sizeof(iocts.drvid) - 1] = 0;
- if (strlen(iocts.drvid)) {
- drvidx = -1;
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- if (!(strcmp(dev->drvid[i], iocts.drvid))) {
- drvidx = i;
- break;
- }
- } else
- drvidx = 0;
- if (drvidx == -1)
- return -ENODEV;
- if (cmd == IIOCSETMAP) {
- int loop = 1;
-
- p = (char __user *) iocts.arg;
- i = 0;
- while (loop) {
- int j = 0;
-
- while (1) {
- get_user(bname[j], p++);
- switch (bname[j]) {
- case '\0':
- loop = 0;
- /* Fall through */
- case ',':
- bname[j] = '\0';
- strcpy(dev->drv[drvidx]->msn2eaz[i], bname);
- j = ISDN_MSNLEN;
- break;
- default:
- j++;
- }
- if (j >= ISDN_MSNLEN)
- break;
- }
- if (++i > 9)
- break;
- }
- } else {
- p = (char __user *) iocts.arg;
- for (i = 0; i < 10; i++) {
- snprintf(bname, sizeof(bname), "%s%s",
- strlen(dev->drv[drvidx]->msn2eaz[i]) ?
- dev->drv[drvidx]->msn2eaz[i] : "_",
- (i < 9) ? "," : "\0");
- if (copy_to_user(p, bname, strlen(bname) + 1))
- return -EFAULT;
- p += strlen(bname);
- }
- }
- return 0;
- } else
- return -EINVAL;
- case IIOCDBGVAR:
- return -EINVAL;
- default:
- if ((cmd & IIOCDRVCTL) == IIOCDRVCTL)
- cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK;
- else
- return -EINVAL;
- if (arg) {
- int i;
- char *p;
- if (copy_from_user(&iocts, argp, sizeof(isdn_ioctl_struct)))
- return -EFAULT;
- iocts.drvid[sizeof(iocts.drvid) - 1] = 0;
- if (strlen(iocts.drvid)) {
- if ((p = strchr(iocts.drvid, ',')))
- *p = 0;
- drvidx = -1;
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- if (!(strcmp(dev->drvid[i], iocts.drvid))) {
- drvidx = i;
- break;
- }
- } else
- drvidx = 0;
- if (drvidx == -1)
- return -ENODEV;
- c.driver = drvidx;
- c.command = ISDN_CMD_IOCTL;
- c.arg = cmd;
- memcpy(c.parm.num, &iocts.arg, sizeof(ulong));
- ret = isdn_command(&c);
- memcpy(&iocts.arg, c.parm.num, sizeof(ulong));
- if (copy_to_user(argp, &iocts, sizeof(isdn_ioctl_struct)))
- return -EFAULT;
- return ret;
- } else
- return -EINVAL;
- }
- }
-#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX)
- return (isdn_ppp_ioctl(minor - ISDN_MINOR_PPP, file, cmd, arg));
-#endif
- return -ENODEV;
-
-#undef name
-#undef bname
-#undef iocts
-#undef phone
-#undef cfg
-}
-
-static long
-isdn_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- int ret;
-
- mutex_lock(&isdn_mutex);
- ret = isdn_ioctl(file, cmd, arg);
- mutex_unlock(&isdn_mutex);
-
- return ret;
-}
-
-/*
- * Open the device code.
- */
-static int
-isdn_open(struct inode *ino, struct file *filep)
-{
- uint minor = iminor(ino);
- int drvidx;
- int chidx;
- int retval = -ENODEV;
-
- mutex_lock(&isdn_mutex);
- if (minor == ISDN_MINOR_STATUS) {
- infostruct *p;
-
- if ((p = kmalloc(sizeof(infostruct), GFP_KERNEL))) {
- p->next = (char *) dev->infochain;
- p->private = (char *) &(filep->private_data);
- dev->infochain = p;
- /* At opening we allow a single update */
- filep->private_data = (char *) 1;
- retval = 0;
- goto out;
- } else {
- retval = -ENOMEM;
- goto out;
- }
- }
- if (!dev->channels)
- goto out;
- if (minor <= ISDN_MINOR_BMAX) {
- printk(KERN_WARNING "isdn_open minor %d obsolete!\n", minor);
- drvidx = isdn_minor2drv(minor);
- if (drvidx < 0)
- goto out;
- chidx = isdn_minor2chan(minor);
- if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
- goto out;
- if (!(dev->drv[drvidx]->online & (1 << chidx)))
- goto out;
- isdn_lock_drivers();
- retval = 0;
- goto out;
- }
- if (minor <= ISDN_MINOR_CTRLMAX) {
- drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
- if (drvidx < 0)
- goto out;
- isdn_lock_drivers();
- retval = 0;
- goto out;
- }
-#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX) {
- retval = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep);
- if (retval == 0)
- isdn_lock_drivers();
- goto out;
- }
-#endif
-out:
- nonseekable_open(ino, filep);
- mutex_unlock(&isdn_mutex);
- return retval;
-}
-
-static int
-isdn_close(struct inode *ino, struct file *filep)
-{
- uint minor = iminor(ino);
-
- mutex_lock(&isdn_mutex);
- if (minor == ISDN_MINOR_STATUS) {
- infostruct *p = dev->infochain;
- infostruct *q = NULL;
-
- while (p) {
- if (p->private == (char *) &(filep->private_data)) {
- if (q)
- q->next = p->next;
- else
- dev->infochain = (infostruct *) (p->next);
- kfree(p);
- goto out;
- }
- q = p;
- p = (infostruct *) (p->next);
- }
- printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
- goto out;
- }
- isdn_unlock_drivers();
- if (minor <= ISDN_MINOR_BMAX)
- goto out;
- if (minor <= ISDN_MINOR_CTRLMAX) {
- if (dev->profd == current)
- dev->profd = NULL;
- goto out;
- }
-#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX)
- isdn_ppp_release(minor - ISDN_MINOR_PPP, filep);
-#endif
-
-out:
- mutex_unlock(&isdn_mutex);
- return 0;
-}
-
-static const struct file_operations isdn_fops =
-{
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = isdn_read,
- .write = isdn_write,
- .poll = isdn_poll,
- .unlocked_ioctl = isdn_unlocked_ioctl,
- .open = isdn_open,
- .release = isdn_close,
-};
-
-char *
-isdn_map_eaz2msn(char *msn, int di)
-{
- isdn_driver_t *this = dev->drv[di];
- int i;
-
- if (strlen(msn) == 1) {
- i = msn[0] - '0';
- if ((i >= 0) && (i <= 9))
- if (strlen(this->msn2eaz[i]))
- return (this->msn2eaz[i]);
- }
- return (msn);
-}
-
-/*
- * Find an unused ISDN-channel, whose feature-flags match the
- * given L2- and L3-protocols.
- */
-#define L2V (~(ISDN_FEATURE_L2_V11096 | ISDN_FEATURE_L2_V11019 | ISDN_FEATURE_L2_V11038))
-
-/*
- * This function must be called with holding the dev->lock.
- */
-int
-isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
- , int pre_chan, char *msn)
-{
- int i;
- ulong features;
- ulong vfeatures;
-
- features = ((1 << l2_proto) | (0x10000 << l3_proto));
- vfeatures = (((1 << l2_proto) | (0x10000 << l3_proto)) &
- ~(ISDN_FEATURE_L2_V11096 | ISDN_FEATURE_L2_V11019 | ISDN_FEATURE_L2_V11038));
- /* If Layer-2 protocol is V.110, accept drivers with
- * transparent feature even if these don't support V.110
- * because we can emulate this in linklevel.
- */
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (USG_NONE(dev->usage[i]) &&
- (dev->drvmap[i] != -1)) {
- int d = dev->drvmap[i];
- if ((dev->usage[i] & ISDN_USAGE_EXCLUSIVE) &&
- ((pre_dev != d) || (pre_chan != dev->chanmap[i])))
- continue;
- if (!strcmp(isdn_map_eaz2msn(msn, d), "-"))
- continue;
- if (dev->usage[i] & ISDN_USAGE_DISABLED)
- continue; /* usage not allowed */
- if (dev->drv[d]->flags & DRV_FLAG_RUNNING) {
- if (((dev->drv[d]->interface->features & features) == features) ||
- (((dev->drv[d]->interface->features & vfeatures) == vfeatures) &&
- (dev->drv[d]->interface->features & ISDN_FEATURE_L2_TRANS))) {
- if ((pre_dev < 0) || (pre_chan < 0)) {
- dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
- dev->usage[i] |= usage;
- isdn_info_update();
- return i;
- } else {
- if ((pre_dev == d) && (pre_chan == dev->chanmap[i])) {
- dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
- dev->usage[i] |= usage;
- isdn_info_update();
- return i;
- }
- }
- }
- }
- }
- return -1;
-}
-
-/*
- * Set state of ISDN-channel to 'unused'
- */
-void
-isdn_free_channel(int di, int ch, int usage)
-{
- int i;
-
- if ((di < 0) || (ch < 0)) {
- printk(KERN_WARNING "%s: called with invalid drv(%d) or channel(%d)\n",
- __func__, di, ch);
- return;
- }
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (((!usage) || ((dev->usage[i] & ISDN_USAGE_MASK) == usage)) &&
- (dev->drvmap[i] == di) &&
- (dev->chanmap[i] == ch)) {
- dev->usage[i] &= (ISDN_USAGE_NONE | ISDN_USAGE_EXCLUSIVE);
- strcpy(dev->num[i], "???");
- dev->ibytes[i] = 0;
- dev->obytes[i] = 0;
-// 20.10.99 JIM, try to reinitialize v110 !
- dev->v110emu[i] = 0;
- atomic_set(&(dev->v110use[i]), 0);
- isdn_v110_close(dev->v110[i]);
- dev->v110[i] = NULL;
-// 20.10.99 JIM, try to reinitialize v110 !
- isdn_info_update();
- if (dev->drv[di])
- skb_queue_purge(&dev->drv[di]->rpqueue[ch]);
- }
-}
-
-/*
- * Cancel Exclusive-Flag for ISDN-channel
- */
-void
-isdn_unexclusive_channel(int di, int ch)
-{
- int i;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if ((dev->drvmap[i] == di) &&
- (dev->chanmap[i] == ch)) {
- dev->usage[i] &= ~ISDN_USAGE_EXCLUSIVE;
- isdn_info_update();
- return;
- }
-}
-
-/*
- * writebuf replacement for SKB_ABLE drivers
- */
-static int
-isdn_writebuf_stub(int drvidx, int chan, const u_char __user *buf, int len)
-{
- int ret;
- int hl = dev->drv[drvidx]->interface->hl_hdrlen;
- struct sk_buff *skb = alloc_skb(hl + len, GFP_ATOMIC);
-
- if (!skb)
- return -ENOMEM;
- skb_reserve(skb, hl);
- if (copy_from_user(skb_put(skb, len), buf, len)) {
- dev_kfree_skb(skb);
- return -EFAULT;
- }
- ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, 1, skb);
- if (ret <= 0)
- dev_kfree_skb(skb);
- if (ret > 0)
- dev->obytes[isdn_dc2minor(drvidx, chan)] += ret;
- return ret;
-}
-
-/*
- * Return: length of data on success, -ERRcode on failure.
- */
-int
-isdn_writebuf_skb_stub(int drvidx, int chan, int ack, struct sk_buff *skb)
-{
- int ret;
- struct sk_buff *nskb = NULL;
- int v110_ret = skb->len;
- int idx = isdn_dc2minor(drvidx, chan);
-
- if (dev->v110[idx]) {
- atomic_inc(&dev->v110use[idx]);
- nskb = isdn_v110_encode(dev->v110[idx], skb);
- atomic_dec(&dev->v110use[idx]);
- if (!nskb)
- return 0;
- v110_ret = *((int *)nskb->data);
- skb_pull(nskb, sizeof(int));
- if (!nskb->len) {
- dev_kfree_skb(nskb);
- return v110_ret;
- }
- /* V.110 must always be acknowledged */
- ack = 1;
- ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, nskb);
- } else {
- int hl = dev->drv[drvidx]->interface->hl_hdrlen;
-
- if (skb_headroom(skb) < hl) {
- /*
- * This should only occur when new HL driver with
- * increased hl_hdrlen was loaded after netdevice
- * was created and connected to the new driver.
- *
- * The V.110 branch (re-allocates on its own) does
- * not need this
- */
- struct sk_buff *skb_tmp;
-
- skb_tmp = skb_realloc_headroom(skb, hl);
- printk(KERN_DEBUG "isdn_writebuf_skb_stub: reallocating headroom%s\n", skb_tmp ? "" : " failed");
- if (!skb_tmp) return -ENOMEM; /* 0 better? */
- ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, skb_tmp);
- if (ret > 0) {
- dev_kfree_skb(skb);
- } else {
- dev_kfree_skb(skb_tmp);
- }
- } else {
- ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, skb);
- }
- }
- if (ret > 0) {
- dev->obytes[idx] += ret;
- if (dev->v110[idx]) {
- atomic_inc(&dev->v110use[idx]);
- dev->v110[idx]->skbuser++;
- atomic_dec(&dev->v110use[idx]);
- /* For V.110 return unencoded data length */
- ret = v110_ret;
- /* if the complete frame was send we free the skb;
- if not upper function will requeue the skb */
- if (ret == skb->len)
- dev_kfree_skb(skb);
- }
- } else
- if (dev->v110[idx])
- dev_kfree_skb(nskb);
- return ret;
-}
-
-static int
-isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding)
-{
- int j, k, m;
-
- init_waitqueue_head(&d->st_waitq);
- if (d->flags & DRV_FLAG_RUNNING)
- return -1;
- if (n < 1) return 0;
-
- m = (adding) ? d->channels + n : n;
-
- if (dev->channels + n > ISDN_MAX_CHANNELS) {
- printk(KERN_WARNING "register_isdn: Max. %d channels supported\n",
- ISDN_MAX_CHANNELS);
- return -1;
- }
-
- if ((adding) && (d->rcverr))
- kfree(d->rcverr);
- if (!(d->rcverr = kcalloc(m, sizeof(int), GFP_ATOMIC))) {
- printk(KERN_WARNING "register_isdn: Could not alloc rcverr\n");
- return -1;
- }
-
- if ((adding) && (d->rcvcount))
- kfree(d->rcvcount);
- if (!(d->rcvcount = kcalloc(m, sizeof(int), GFP_ATOMIC))) {
- printk(KERN_WARNING "register_isdn: Could not alloc rcvcount\n");
- if (!adding)
- kfree(d->rcverr);
- return -1;
- }
-
- if ((adding) && (d->rpqueue)) {
- for (j = 0; j < d->channels; j++)
- skb_queue_purge(&d->rpqueue[j]);
- kfree(d->rpqueue);
- }
- d->rpqueue = kmalloc_array(m, sizeof(struct sk_buff_head), GFP_ATOMIC);
- if (!d->rpqueue) {
- printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n");
- if (!adding) {
- kfree(d->rcvcount);
- kfree(d->rcverr);
- }
- return -1;
- }
- for (j = 0; j < m; j++) {
- skb_queue_head_init(&d->rpqueue[j]);
- }
-
- if ((adding) && (d->rcv_waitq))
- kfree(d->rcv_waitq);
- d->rcv_waitq = kmalloc(array3_size(sizeof(wait_queue_head_t), 2, m),
- GFP_ATOMIC);
- if (!d->rcv_waitq) {
- printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n");
- if (!adding) {
- kfree(d->rpqueue);
- kfree(d->rcvcount);
- kfree(d->rcverr);
- }
- return -1;
- }
- d->snd_waitq = d->rcv_waitq + m;
- for (j = 0; j < m; j++) {
- init_waitqueue_head(&d->rcv_waitq[j]);
- init_waitqueue_head(&d->snd_waitq[j]);
- }
-
- dev->channels += n;
- for (j = d->channels; j < m; j++)
- for (k = 0; k < ISDN_MAX_CHANNELS; k++)
- if (dev->chanmap[k] < 0) {
- dev->chanmap[k] = j;
- dev->drvmap[k] = drvidx;
- break;
- }
- d->channels = m;
- return 0;
-}
-
-/*
- * Low-level-driver registration
- */
-
-static void
-set_global_features(void)
-{
- int drvidx;
-
- dev->global_features = 0;
- for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) {
- if (!dev->drv[drvidx])
- continue;
- if (dev->drv[drvidx]->interface)
- dev->global_features |= dev->drv[drvidx]->interface->features;
- }
-}
-
-#ifdef CONFIG_ISDN_DIVERSION
-
-static char *map_drvname(int di)
-{
- if ((di < 0) || (di >= ISDN_MAX_DRIVERS))
- return (NULL);
- return (dev->drvid[di]); /* driver name */
-} /* map_drvname */
-
-static int map_namedrv(char *id)
-{ int i;
-
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- { if (!strcmp(dev->drvid[i], id))
- return (i);
- }
- return (-1);
-} /* map_namedrv */
-
-int DIVERT_REG_NAME(isdn_divert_if *i_div)
-{
- if (i_div->if_magic != DIVERT_IF_MAGIC)
- return (DIVERT_VER_ERR);
- switch (i_div->cmd)
- {
- case DIVERT_CMD_REL:
- if (divert_if != i_div)
- return (DIVERT_REL_ERR);
- divert_if = NULL; /* free interface */
- return (DIVERT_NO_ERR);
-
- case DIVERT_CMD_REG:
- if (divert_if)
- return (DIVERT_REG_ERR);
- i_div->ll_cmd = isdn_command; /* set command function */
- i_div->drv_to_name = map_drvname;
- i_div->name_to_drv = map_namedrv;
- divert_if = i_div; /* remember interface */
- return (DIVERT_NO_ERR);
-
- default:
- return (DIVERT_CMD_ERR);
- }
-} /* DIVERT_REG_NAME */
-
-EXPORT_SYMBOL(DIVERT_REG_NAME);
-
-#endif /* CONFIG_ISDN_DIVERSION */
-
-
-EXPORT_SYMBOL(register_isdn);
-#ifdef CONFIG_ISDN_PPP
-EXPORT_SYMBOL(isdn_ppp_register_compressor);
-EXPORT_SYMBOL(isdn_ppp_unregister_compressor);
-#endif
-
-int
-register_isdn(isdn_if *i)
-{
- isdn_driver_t *d;
- int j;
- ulong flags;
- int drvidx;
-
- if (dev->drivers >= ISDN_MAX_DRIVERS) {
- printk(KERN_WARNING "register_isdn: Max. %d drivers supported\n",
- ISDN_MAX_DRIVERS);
- return 0;
- }
- if (!i->writebuf_skb) {
- printk(KERN_WARNING "register_isdn: No write routine given.\n");
- return 0;
- }
- if (!(d = kzalloc(sizeof(isdn_driver_t), GFP_KERNEL))) {
- printk(KERN_WARNING "register_isdn: Could not alloc driver-struct\n");
- return 0;
- }
-
- d->maxbufsize = i->maxbufsize;
- d->pktcount = 0;
- d->stavail = 0;
- d->flags = DRV_FLAG_LOADED;
- d->online = 0;
- d->interface = i;
- d->channels = 0;
- spin_lock_irqsave(&dev->lock, flags);
- for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++)
- if (!dev->drv[drvidx])
- break;
- if (isdn_add_channels(d, drvidx, i->channels, 0)) {
- spin_unlock_irqrestore(&dev->lock, flags);
- kfree(d);
- return 0;
- }
- i->channels = drvidx;
- i->rcvcallb_skb = isdn_receive_skb_callback;
- i->statcallb = isdn_status_callback;
- if (!strlen(i->id))
- sprintf(i->id, "line%d", drvidx);
- for (j = 0; j < drvidx; j++)
- if (!strcmp(i->id, dev->drvid[j]))
- sprintf(i->id, "line%d", drvidx);
- dev->drv[drvidx] = d;
- strcpy(dev->drvid[drvidx], i->id);
- isdn_info_update();
- dev->drivers++;
- set_global_features();
- spin_unlock_irqrestore(&dev->lock, flags);
- return 1;
-}
-
-/*
-*****************************************************************************
-* And now the modules code.
-*****************************************************************************
-*/
-
-static char *
-isdn_getrev(const char *revision)
-{
- char *rev;
- char *p;
-
- if ((p = strchr(revision, ':'))) {
- rev = p + 2;
- p = strchr(rev, '$');
- *--p = 0;
- } else
- rev = "???";
- return rev;
-}
-
-/*
- * Allocate and initialize all data, register modem-devices
- */
-static int __init isdn_init(void)
-{
- int i;
- char tmprev[50];
-
- dev = vzalloc(sizeof(isdn_dev));
- if (!dev) {
- printk(KERN_WARNING "isdn: Could not allocate device-struct.\n");
- return -EIO;
- }
- timer_setup(&dev->timer, isdn_timer_funct, 0);
- spin_lock_init(&dev->lock);
- spin_lock_init(&dev->timerlock);
-#ifdef MODULE
- dev->owner = THIS_MODULE;
-#endif
- mutex_init(&dev->mtx);
- init_waitqueue_head(&dev->info_waitq);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- dev->drvmap[i] = -1;
- dev->chanmap[i] = -1;
- dev->m_idx[i] = -1;
- strcpy(dev->num[i], "???");
- }
- if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) {
- printk(KERN_WARNING "isdn: Could not register control devices\n");
- vfree(dev);
- return -EIO;
- }
- if ((isdn_tty_modem_init()) < 0) {
- printk(KERN_WARNING "isdn: Could not register tty devices\n");
- vfree(dev);
- unregister_chrdev(ISDN_MAJOR, "isdn");
- return -EIO;
- }
-#ifdef CONFIG_ISDN_PPP
- if (isdn_ppp_init() < 0) {
- printk(KERN_WARNING "isdn: Could not create PPP-device-structs\n");
- isdn_tty_exit();
- unregister_chrdev(ISDN_MAJOR, "isdn");
- vfree(dev);
- return -EIO;
- }
-#endif /* CONFIG_ISDN_PPP */
-
- strcpy(tmprev, isdn_revision);
- printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(tmprev));
- strcpy(tmprev, isdn_net_revision);
- printk("%s/", isdn_getrev(tmprev));
- strcpy(tmprev, isdn_ppp_revision);
- printk("%s/", isdn_getrev(tmprev));
- strcpy(tmprev, isdn_audio_revision);
- printk("%s/", isdn_getrev(tmprev));
- strcpy(tmprev, isdn_v110_revision);
- printk("%s", isdn_getrev(tmprev));
-
-#ifdef MODULE
- printk(" loaded\n");
-#else
- printk("\n");
-#endif
- isdn_info_update();
- return 0;
-}
-
-/*
- * Unload module
- */
-static void __exit isdn_exit(void)
-{
-#ifdef CONFIG_ISDN_PPP
- isdn_ppp_cleanup();
-#endif
- if (isdn_net_rmall() < 0) {
- printk(KERN_WARNING "isdn: net-device busy, remove cancelled\n");
- return;
- }
- isdn_tty_exit();
- unregister_chrdev(ISDN_MAJOR, "isdn");
- del_timer_sync(&dev->timer);
- /* call vfree with interrupts enabled, else it will hang */
- vfree(dev);
- printk(KERN_NOTICE "ISDN-subsystem unloaded\n");
-}
-
-module_init(isdn_init);
-module_exit(isdn_exit);
diff --git a/drivers/isdn/i4l/isdn_common.h b/drivers/isdn/i4l/isdn_common.h
deleted file mode 100644
index 2260ef07ab9c..000000000000
--- a/drivers/isdn/i4l/isdn_common.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* $Id: isdn_common.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * header for Linux ISDN subsystem
- * common used functions and debugging-switches (linklevel).
- *
- * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
- * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#undef ISDN_DEBUG_MODEM_OPEN
-#undef ISDN_DEBUG_MODEM_IOCTL
-#undef ISDN_DEBUG_MODEM_WAITSENT
-#undef ISDN_DEBUG_MODEM_HUP
-#undef ISDN_DEBUG_MODEM_ICALL
-#undef ISDN_DEBUG_MODEM_DUMP
-#undef ISDN_DEBUG_MODEM_VOICE
-#undef ISDN_DEBUG_AT
-#undef ISDN_DEBUG_NET_DUMP
-#undef ISDN_DEBUG_NET_DIAL
-#undef ISDN_DEBUG_NET_ICALL
-
-/* Prototypes */
-extern void isdn_lock_drivers(void);
-extern void isdn_unlock_drivers(void);
-extern void isdn_free_channel(int di, int ch, int usage);
-extern void isdn_all_eaz(int di, int ch);
-extern int isdn_command(isdn_ctrl *);
-extern int isdn_dc2minor(int di, int ch);
-extern void isdn_info_update(void);
-extern char *isdn_map_eaz2msn(char *msn, int di);
-extern void isdn_timer_ctrl(int tf, int onoff);
-extern void isdn_unexclusive_channel(int di, int ch);
-extern int isdn_getnum(char **);
-extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *);
-extern int isdn_readbchan_tty(int, int, struct tty_port *, int);
-extern int isdn_get_free_channel(int, int, int, int, int, char *);
-extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *);
-extern int register_isdn(isdn_if *i);
-extern int isdn_msncmp(const char *, const char *);
-#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
-extern void isdn_dumppkt(char *, u_char *, int, int);
-#endif
diff --git a/drivers/isdn/i4l/isdn_concap.c b/drivers/isdn/i4l/isdn_concap.c
deleted file mode 100644
index 336523ec077c..000000000000
--- a/drivers/isdn/i4l/isdn_concap.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/* $Id: isdn_concap.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * Linux ISDN subsystem, protocol encapsulation
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-/* Stuff to support the concap_proto by isdn4linux. isdn4linux - specific
- * stuff goes here. Stuff that depends only on the concap protocol goes to
- * another -- protocol specific -- source file.
- *
- */
-
-
-#include <linux/isdn.h>
-#include "isdn_x25iface.h"
-#include "isdn_net.h"
-#include <linux/concap.h>
-#include "isdn_concap.h"
-
-
-/* The following set of device service operations are for encapsulation
- protocols that require for reliable datalink semantics. That means:
-
- - before any data is to be submitted the connection must explicitly
- be set up.
- - after the successful set up of the connection is signalled the
- connection is considered to be reliably up.
-
- Auto-dialing ist not compatible with this requirements. Thus, auto-dialing
- is completely bypassed.
-
- It might be possible to implement a (non standardized) datalink protocol
- that provides a reliable data link service while using some auto dialing
- mechanism. Such a protocol would need an auxiliary channel (i.e. user-user-
- signaling on the D-channel) while the B-channel is down.
-*/
-
-
-static int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb)
-{
- struct net_device *ndev = concap->net_dev;
- isdn_net_dev *nd = ((isdn_net_local *) netdev_priv(ndev))->netdev;
- isdn_net_local *lp = isdn_net_get_locked_lp(nd);
-
- IX25DEBUG("isdn_concap_dl_data_req: %s \n", concap->net_dev->name);
- if (!lp) {
- IX25DEBUG("isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap->net_dev->name, 1);
- return 1;
- }
- lp->huptimer = 0;
- isdn_net_writebuf_skb(lp, skb);
- spin_unlock_bh(&lp->xmit_lock);
- IX25DEBUG("isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap->net_dev->name, 0);
- return 0;
-}
-
-
-static int isdn_concap_dl_connect_req(struct concap_proto *concap)
-{
- struct net_device *ndev = concap->net_dev;
- isdn_net_local *lp = netdev_priv(ndev);
- int ret;
- IX25DEBUG("isdn_concap_dl_connect_req: %s \n", ndev->name);
-
- /* dial ... */
- ret = isdn_net_dial_req(lp);
- if (ret) IX25DEBUG("dialing failed\n");
- return ret;
-}
-
-static int isdn_concap_dl_disconn_req(struct concap_proto *concap)
-{
- IX25DEBUG("isdn_concap_dl_disconn_req: %s \n", concap->net_dev->name);
-
- isdn_net_hangup(concap->net_dev);
- return 0;
-}
-
-struct concap_device_ops isdn_concap_reliable_dl_dops = {
- .data_req = &isdn_concap_dl_data_req,
- .connect_req = &isdn_concap_dl_connect_req,
- .disconn_req = &isdn_concap_dl_disconn_req
-};
-
-/* The following should better go into a dedicated source file such that
- this sourcefile does not need to include any protocol specific header
- files. For now:
-*/
-struct concap_proto *isdn_concap_new(int encap)
-{
- switch (encap) {
- case ISDN_NET_ENCAP_X25IFACE:
- return isdn_x25iface_proto_new();
- }
- return NULL;
-}
diff --git a/drivers/isdn/i4l/isdn_concap.h b/drivers/isdn/i4l/isdn_concap.h
deleted file mode 100644
index cd7e3ba74e25..000000000000
--- a/drivers/isdn/i4l/isdn_concap.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/* $Id: isdn_concap.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * Linux ISDN subsystem, protocol encapsulation
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-extern struct concap_device_ops isdn_concap_reliable_dl_dops;
-extern struct concap_proto *isdn_concap_new(int);
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
deleted file mode 100644
index c138f66f2659..000000000000
--- a/drivers/isdn/i4l/isdn_net.c
+++ /dev/null
@@ -1,3198 +0,0 @@
-/* $Id: isdn_net.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * Linux ISDN subsystem, network interfaces and related functions (linklevel).
- *
- * Copyright 1994-1998 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
- * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Data Over Voice (DOV) support added - Guy Ellis 23-Mar-02
- * guy@traverse.com.au
- * Outgoing calls - looks for a 'V' in first char of dialed number
- * Incoming calls - checks first character of eaz as follows:
- * Numeric - accept DATA only - original functionality
- * 'V' - accept VOICE (DOV) only
- * 'B' - accept BOTH DATA and DOV types
- *
- * Jan 2001: fix CISCO HDLC Bjoern A. Zeeb <i4l@zabbadoz.net>
- * for info on the protocol, see
- * http://i4l.zabbadoz.net/i4l/cisco-hdlc.txt
- */
-
-#include <linux/isdn.h>
-#include <linux/slab.h>
-#include <net/arp.h>
-#include <net/dst.h>
-#include <net/pkt_sched.h>
-#include <linux/inetdevice.h>
-#include "isdn_common.h"
-#include "isdn_net.h"
-#ifdef CONFIG_ISDN_PPP
-#include "isdn_ppp.h"
-#endif
-#ifdef CONFIG_ISDN_X25
-#include <linux/concap.h>
-#include "isdn_concap.h"
-#endif
-
-
-/*
- * Outline of new tbusy handling:
- *
- * Old method, roughly spoken, consisted of setting tbusy when entering
- * isdn_net_start_xmit() and at several other locations and clearing
- * it from isdn_net_start_xmit() thread when sending was successful.
- *
- * With 2.3.x multithreaded network core, to prevent problems, tbusy should
- * only be set by the isdn_net_start_xmit() thread and only when a tx-busy
- * condition is detected. Other threads (in particular isdn_net_stat_callb())
- * are only allowed to clear tbusy.
- *
- * -HE
- */
-
-/*
- * About SOFTNET:
- * Most of the changes were pretty obvious and basically done by HE already.
- *
- * One problem of the isdn net device code is that it uses struct net_device
- * for masters and slaves. However, only master interface are registered to
- * the network layer, and therefore, it only makes sense to call netif_*
- * functions on them.
- *
- * --KG
- */
-
-/*
- * Find out if the netdevice has been ifup-ed yet.
- * For slaves, look at the corresponding master.
- */
-static __inline__ int isdn_net_device_started(isdn_net_dev *n)
-{
- isdn_net_local *lp = n->local;
- struct net_device *dev;
-
- if (lp->master)
- dev = lp->master;
- else
- dev = n->dev;
- return netif_running(dev);
-}
-
-/*
- * wake up the network -> net_device queue.
- * For slaves, wake the corresponding master interface.
- */
-static __inline__ void isdn_net_device_wake_queue(isdn_net_local *lp)
-{
- if (lp->master)
- netif_wake_queue(lp->master);
- else
- netif_wake_queue(lp->netdev->dev);
-}
-
-/*
- * stop the network -> net_device queue.
- * For slaves, stop the corresponding master interface.
- */
-static __inline__ void isdn_net_device_stop_queue(isdn_net_local *lp)
-{
- if (lp->master)
- netif_stop_queue(lp->master);
- else
- netif_stop_queue(lp->netdev->dev);
-}
-
-/*
- * find out if the net_device which this lp belongs to (lp can be
- * master or slave) is busy. It's busy iff all (master and slave)
- * queues are busy
- */
-static __inline__ int isdn_net_device_busy(isdn_net_local *lp)
-{
- isdn_net_local *nlp;
- isdn_net_dev *nd;
- unsigned long flags;
-
- if (!isdn_net_lp_busy(lp))
- return 0;
-
- if (lp->master)
- nd = ISDN_MASTER_PRIV(lp)->netdev;
- else
- nd = lp->netdev;
-
- spin_lock_irqsave(&nd->queue_lock, flags);
- nlp = lp->next;
- while (nlp != lp) {
- if (!isdn_net_lp_busy(nlp)) {
- spin_unlock_irqrestore(&nd->queue_lock, flags);
- return 0;
- }
- nlp = nlp->next;
- }
- spin_unlock_irqrestore(&nd->queue_lock, flags);
- return 1;
-}
-
-static __inline__ void isdn_net_inc_frame_cnt(isdn_net_local *lp)
-{
- atomic_inc(&lp->frame_cnt);
- if (isdn_net_device_busy(lp))
- isdn_net_device_stop_queue(lp);
-}
-
-static __inline__ void isdn_net_dec_frame_cnt(isdn_net_local *lp)
-{
- atomic_dec(&lp->frame_cnt);
-
- if (!(isdn_net_device_busy(lp))) {
- if (!skb_queue_empty(&lp->super_tx_queue)) {
- schedule_work(&lp->tqueue);
- } else {
- isdn_net_device_wake_queue(lp);
- }
- }
-}
-
-static __inline__ void isdn_net_zero_frame_cnt(isdn_net_local *lp)
-{
- atomic_set(&lp->frame_cnt, 0);
-}
-
-/* For 2.2.x we leave the transmitter busy timeout at 2 secs, just
- * to be safe.
- * For 2.3.x we push it up to 20 secs, because call establishment
- * (in particular callback) may take such a long time, and we
- * don't want confusing messages in the log. However, there is a slight
- * possibility that this large timeout will break other things like MPPP,
- * which might rely on the tx timeout. If so, we'll find out this way...
- */
-
-#define ISDN_NET_TX_TIMEOUT (20 * HZ)
-
-/* Prototypes */
-
-static int isdn_net_force_dial_lp(isdn_net_local *);
-static netdev_tx_t isdn_net_start_xmit(struct sk_buff *,
- struct net_device *);
-
-static void isdn_net_ciscohdlck_connected(isdn_net_local *lp);
-static void isdn_net_ciscohdlck_disconnected(isdn_net_local *lp);
-
-char *isdn_net_revision = "$Revision: 1.1.2.2 $";
-
-/*
- * Code for raw-networking over ISDN
- */
-
-static void
-isdn_net_unreachable(struct net_device *dev, struct sk_buff *skb, char *reason)
-{
- if (skb) {
-
- u_short proto = ntohs(skb->protocol);
-
- printk(KERN_DEBUG "isdn_net: %s: %s, signalling dst_link_failure %s\n",
- dev->name,
- (reason != NULL) ? reason : "unknown",
- (proto != ETH_P_IP) ? "Protocol != ETH_P_IP" : "");
-
- dst_link_failure(skb);
- }
- else { /* dial not triggered by rawIP packet */
- printk(KERN_DEBUG "isdn_net: %s: %s\n",
- dev->name,
- (reason != NULL) ? reason : "reason unknown");
- }
-}
-
-static void
-isdn_net_reset(struct net_device *dev)
-{
-#ifdef CONFIG_ISDN_X25
- struct concap_device_ops *dops =
- ((isdn_net_local *)netdev_priv(dev))->dops;
- struct concap_proto *cprot =
- ((isdn_net_local *)netdev_priv(dev))->netdev->cprot;
-#endif
-#ifdef CONFIG_ISDN_X25
- if (cprot && cprot->pops && dops)
- cprot->pops->restart(cprot, dev, dops);
-#endif
-}
-
-/* Open/initialize the board. */
-static int
-isdn_net_open(struct net_device *dev)
-{
- int i;
- struct net_device *p;
- struct in_device *in_dev;
-
- /* moved here from isdn_net_reset, because only the master has an
- interface associated which is supposed to be started. BTW:
- we need to call netif_start_queue, not netif_wake_queue here */
- netif_start_queue(dev);
-
- isdn_net_reset(dev);
- /* Fill in the MAC-level header (not needed, but for compatibility... */
- for (i = 0; i < ETH_ALEN - sizeof(u32); i++)
- dev->dev_addr[i] = 0xfc;
- if ((in_dev = dev->ip_ptr) != NULL) {
- /*
- * Any address will do - we take the first
- */
- struct in_ifaddr *ifa = in_dev->ifa_list;
- if (ifa != NULL)
- memcpy(dev->dev_addr + 2, &ifa->ifa_local, 4);
- }
-
- /* If this interface has slaves, start them also */
- p = MASTER_TO_SLAVE(dev);
- if (p) {
- while (p) {
- isdn_net_reset(p);
- p = MASTER_TO_SLAVE(p);
- }
- }
- isdn_lock_drivers();
- return 0;
-}
-
-/*
- * Assign an ISDN-channel to a net-interface
- */
-static void
-isdn_net_bind_channel(isdn_net_local *lp, int idx)
-{
- lp->flags |= ISDN_NET_CONNECTED;
- lp->isdn_device = dev->drvmap[idx];
- lp->isdn_channel = dev->chanmap[idx];
- dev->rx_netdev[idx] = lp->netdev;
- dev->st_netdev[idx] = lp->netdev;
-}
-
-/*
- * unbind a net-interface (resets interface after an error)
- */
-static void
-isdn_net_unbind_channel(isdn_net_local *lp)
-{
- skb_queue_purge(&lp->super_tx_queue);
-
- if (!lp->master) { /* reset only master device */
- /* Moral equivalent of dev_purge_queues():
- BEWARE! This chunk of code cannot be called from hardware
- interrupt handler. I hope it is true. --ANK
- */
- qdisc_reset_all_tx(lp->netdev->dev);
- }
- lp->dialstate = 0;
- dev->rx_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL;
- dev->st_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL;
- if (lp->isdn_device != -1 && lp->isdn_channel != -1)
- isdn_free_channel(lp->isdn_device, lp->isdn_channel,
- ISDN_USAGE_NET);
- lp->flags &= ~ISDN_NET_CONNECTED;
- lp->isdn_device = -1;
- lp->isdn_channel = -1;
-}
-
-/*
- * Perform auto-hangup and cps-calculation for net-interfaces.
- *
- * auto-hangup:
- * Increment idle-counter (this counter is reset on any incoming or
- * outgoing packet), if counter exceeds configured limit either do a
- * hangup immediately or - if configured - wait until just before the next
- * charge-info.
- *
- * cps-calculation (needed for dynamic channel-bundling):
- * Since this function is called every second, simply reset the
- * byte-counter of the interface after copying it to the cps-variable.
- */
-static unsigned long last_jiffies = -HZ;
-
-void
-isdn_net_autohup(void)
-{
- isdn_net_dev *p = dev->netdev;
- int anymore;
-
- anymore = 0;
- while (p) {
- isdn_net_local *l = p->local;
- if (jiffies == last_jiffies)
- l->cps = l->transcount;
- else
- l->cps = (l->transcount * HZ) / (jiffies - last_jiffies);
- l->transcount = 0;
- if (dev->net_verbose > 3)
- printk(KERN_DEBUG "%s: %d bogocps\n", p->dev->name, l->cps);
- if ((l->flags & ISDN_NET_CONNECTED) && (!l->dialstate)) {
- anymore = 1;
- l->huptimer++;
- /*
- * if there is some dialmode where timeout-hangup
- * should _not_ be done, check for that here
- */
- if ((l->onhtime) &&
- (l->huptimer > l->onhtime))
- {
- if (l->hupflags & ISDN_MANCHARGE &&
- l->hupflags & ISDN_CHARGEHUP) {
- while (time_after(jiffies, l->chargetime + l->chargeint))
- l->chargetime += l->chargeint;
- if (time_after(jiffies, l->chargetime + l->chargeint - 2 * HZ))
- if (l->outgoing || l->hupflags & ISDN_INHUP)
- isdn_net_hangup(p->dev);
- } else if (l->outgoing) {
- if (l->hupflags & ISDN_CHARGEHUP) {
- if (l->hupflags & ISDN_WAITCHARGE) {
- printk(KERN_DEBUG "isdn_net: Hupflags of %s are %X\n",
- p->dev->name, l->hupflags);
- isdn_net_hangup(p->dev);
- } else if (time_after(jiffies, l->chargetime + l->chargeint)) {
- printk(KERN_DEBUG
- "isdn_net: %s: chtime = %lu, chint = %d\n",
- p->dev->name, l->chargetime, l->chargeint);
- isdn_net_hangup(p->dev);
- }
- } else
- isdn_net_hangup(p->dev);
- } else if (l->hupflags & ISDN_INHUP)
- isdn_net_hangup(p->dev);
- }
-
- if (dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*l) == ISDN_NET_DM_OFF)) {
- isdn_net_hangup(p->dev);
- break;
- }
- }
- p = (isdn_net_dev *) p->next;
- }
- last_jiffies = jiffies;
- isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, anymore);
-}
-
-static void isdn_net_lp_disconnected(isdn_net_local *lp)
-{
- isdn_net_rm_from_bundle(lp);
-}
-
-/*
- * Handle status-messages from ISDN-interfacecard.
- * This function is called from within the main-status-dispatcher
- * isdn_status_callback, which itself is called from the low-level driver.
- * Return: 1 = Event handled, 0 = not for us or unknown Event.
- */
-int
-isdn_net_stat_callback(int idx, isdn_ctrl *c)
-{
- isdn_net_dev *p = dev->st_netdev[idx];
- int cmd = c->command;
-
- if (p) {
- isdn_net_local *lp = p->local;
-#ifdef CONFIG_ISDN_X25
- struct concap_proto *cprot = lp->netdev->cprot;
- struct concap_proto_ops *pops = cprot ? cprot->pops : NULL;
-#endif
- switch (cmd) {
- case ISDN_STAT_BSENT:
- /* A packet has successfully been sent out */
- if ((lp->flags & ISDN_NET_CONNECTED) &&
- (!lp->dialstate)) {
- isdn_net_dec_frame_cnt(lp);
- lp->stats.tx_packets++;
- lp->stats.tx_bytes += c->parm.length;
- }
- return 1;
- case ISDN_STAT_DCONN:
- /* D-Channel is up */
- switch (lp->dialstate) {
- case 4:
- case 7:
- case 8:
- lp->dialstate++;
- return 1;
- case 12:
- lp->dialstate = 5;
- return 1;
- }
- break;
- case ISDN_STAT_DHUP:
- /* Either D-Channel-hangup or error during dialout */
-#ifdef CONFIG_ISDN_X25
- /* If we are not connencted then dialing had
- failed. If there are generic encap protocol
- receiver routines signal the closure of
- the link*/
-
- if (!(lp->flags & ISDN_NET_CONNECTED)
- && pops && pops->disconn_ind)
- pops->disconn_ind(cprot);
-#endif /* CONFIG_ISDN_X25 */
- if ((!lp->dialstate) && (lp->flags & ISDN_NET_CONNECTED)) {
- if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK)
- isdn_net_ciscohdlck_disconnected(lp);
-#ifdef CONFIG_ISDN_PPP
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
- isdn_ppp_free(lp);
-#endif
- isdn_net_lp_disconnected(lp);
- isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
- printk(KERN_INFO "%s: remote hangup\n", p->dev->name);
- printk(KERN_INFO "%s: Chargesum is %d\n", p->dev->name,
- lp->charge);
- isdn_net_unbind_channel(lp);
- return 1;
- }
- break;
-#ifdef CONFIG_ISDN_X25
- case ISDN_STAT_BHUP:
- /* B-Channel-hangup */
- /* try if there are generic encap protocol
- receiver routines and signal the closure of
- the link */
- if (pops && pops->disconn_ind) {
- pops->disconn_ind(cprot);
- return 1;
- }
- break;
-#endif /* CONFIG_ISDN_X25 */
- case ISDN_STAT_BCONN:
- /* B-Channel is up */
- isdn_net_zero_frame_cnt(lp);
- switch (lp->dialstate) {
- case 5:
- case 6:
- case 7:
- case 8:
- case 9:
- case 10:
- case 12:
- if (lp->dialstate <= 6) {
- dev->usage[idx] |= ISDN_USAGE_OUTGOING;
- isdn_info_update();
- } else
- dev->rx_netdev[idx] = p;
- lp->dialstate = 0;
- isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 1);
- if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK)
- isdn_net_ciscohdlck_connected(lp);
- if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) {
- if (lp->master) { /* is lp a slave? */
- isdn_net_dev *nd = ISDN_MASTER_PRIV(lp)->netdev;
- isdn_net_add_to_bundle(nd, lp);
- }
- }
- printk(KERN_INFO "isdn_net: %s connected\n", p->dev->name);
- /* If first Chargeinfo comes before B-Channel connect,
- * we correct the timestamp here.
- */
- lp->chargetime = jiffies;
-
- /* reset dial-timeout */
- lp->dialstarted = 0;
- lp->dialwait_timer = 0;
-
-#ifdef CONFIG_ISDN_PPP
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
- isdn_ppp_wakeup_daemon(lp);
-#endif
-#ifdef CONFIG_ISDN_X25
- /* try if there are generic concap receiver routines */
- if (pops)
- if (pops->connect_ind)
- pops->connect_ind(cprot);
-#endif /* CONFIG_ISDN_X25 */
- /* ppp needs to do negotiations first */
- if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
- isdn_net_device_wake_queue(lp);
- return 1;
- }
- break;
- case ISDN_STAT_NODCH:
- /* No D-Channel avail. */
- if (lp->dialstate == 4) {
- lp->dialstate--;
- return 1;
- }
- break;
- case ISDN_STAT_CINF:
- /* Charge-info from TelCo. Calculate interval between
- * charge-infos and set timestamp for last info for
- * usage by isdn_net_autohup()
- */
- lp->charge++;
- if (lp->hupflags & ISDN_HAVECHARGE) {
- lp->hupflags &= ~ISDN_WAITCHARGE;
- lp->chargeint = jiffies - lp->chargetime - (2 * HZ);
- }
- if (lp->hupflags & ISDN_WAITCHARGE)
- lp->hupflags |= ISDN_HAVECHARGE;
- lp->chargetime = jiffies;
- printk(KERN_DEBUG "isdn_net: Got CINF chargetime of %s now %lu\n",
- p->dev->name, lp->chargetime);
- return 1;
- }
- }
- return 0;
-}
-
-/*
- * Perform dialout for net-interfaces and timeout-handling for
- * D-Channel-up and B-Channel-up Messages.
- * This function is initially called from within isdn_net_start_xmit() or
- * or isdn_net_find_icall() after initializing the dialstate for an
- * interface. If further calls are needed, the function schedules itself
- * for a timer-callback via isdn_timer_function().
- * The dialstate is also affected by incoming status-messages from
- * the ISDN-Channel which are handled in isdn_net_stat_callback() above.
- */
-void
-isdn_net_dial(void)
-{
- isdn_net_dev *p = dev->netdev;
- int anymore = 0;
- int i;
- isdn_ctrl cmd;
- u_char *phone_number;
-
- while (p) {
- isdn_net_local *lp = p->local;
-
-#ifdef ISDN_DEBUG_NET_DIAL
- if (lp->dialstate)
- printk(KERN_DEBUG "%s: dialstate=%d\n", p->dev->name, lp->dialstate);
-#endif
- switch (lp->dialstate) {
- case 0:
- /* Nothing to do for this interface */
- break;
- case 1:
- /* Initiate dialout. Set phone-number-pointer to first number
- * of interface.
- */
- lp->dial = lp->phone[1];
- if (!lp->dial) {
- printk(KERN_WARNING "%s: phone number deleted?\n",
- p->dev->name);
- isdn_net_hangup(p->dev);
- break;
- }
- anymore = 1;
-
- if (lp->dialtimeout > 0)
- if (lp->dialstarted == 0 || time_after(jiffies, lp->dialstarted + lp->dialtimeout + lp->dialwait)) {
- lp->dialstarted = jiffies;
- lp->dialwait_timer = 0;
- }
-
- lp->dialstate++;
- /* Fall through */
- case 2:
- /* Prepare dialing. Clear EAZ, then set EAZ. */
- cmd.driver = lp->isdn_device;
- cmd.arg = lp->isdn_channel;
- cmd.command = ISDN_CMD_CLREAZ;
- isdn_command(&cmd);
- sprintf(cmd.parm.num, "%s", isdn_map_eaz2msn(lp->msn, cmd.driver));
- cmd.command = ISDN_CMD_SETEAZ;
- isdn_command(&cmd);
- lp->dialretry = 0;
- anymore = 1;
- lp->dialstate++;
- /* Fall through */
- case 3:
- /* Setup interface, dial current phone-number, switch to next number.
- * If list of phone-numbers is exhausted, increment
- * retry-counter.
- */
- if (dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF)) {
- char *s;
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- s = "dial suppressed: isdn system stopped";
- else
- s = "dial suppressed: dialmode `off'";
- isdn_net_unreachable(p->dev, NULL, s);
- isdn_net_hangup(p->dev);
- break;
- }
- cmd.driver = lp->isdn_device;
- cmd.command = ISDN_CMD_SETL2;
- cmd.arg = lp->isdn_channel + (lp->l2_proto << 8);
- isdn_command(&cmd);
- cmd.driver = lp->isdn_device;
- cmd.command = ISDN_CMD_SETL3;
- cmd.arg = lp->isdn_channel + (lp->l3_proto << 8);
- isdn_command(&cmd);
- cmd.driver = lp->isdn_device;
- cmd.arg = lp->isdn_channel;
- if (!lp->dial) {
- printk(KERN_WARNING "%s: phone number deleted?\n",
- p->dev->name);
- isdn_net_hangup(p->dev);
- break;
- }
- if (!strncmp(lp->dial->num, "LEASED", strlen("LEASED"))) {
- lp->dialstate = 4;
- printk(KERN_INFO "%s: Open leased line ...\n", p->dev->name);
- } else {
- if (lp->dialtimeout > 0)
- if (time_after(jiffies, lp->dialstarted + lp->dialtimeout)) {
- lp->dialwait_timer = jiffies + lp->dialwait;
- lp->dialstarted = 0;
- isdn_net_unreachable(p->dev, NULL, "dial: timed out");
- isdn_net_hangup(p->dev);
- break;
- }
-
- cmd.driver = lp->isdn_device;
- cmd.command = ISDN_CMD_DIAL;
- cmd.parm.setup.si2 = 0;
-
- /* check for DOV */
- phone_number = lp->dial->num;
- if ((*phone_number == 'v') ||
- (*phone_number == 'V')) { /* DOV call */
- cmd.parm.setup.si1 = 1;
- } else { /* DATA call */
- cmd.parm.setup.si1 = 7;
- }
-
- strcpy(cmd.parm.setup.phone, phone_number);
- /*
- * Switch to next number or back to start if at end of list.
- */
- if (!(lp->dial = (isdn_net_phone *) lp->dial->next)) {
- lp->dial = lp->phone[1];
- lp->dialretry++;
-
- if (lp->dialretry > lp->dialmax) {
- if (lp->dialtimeout == 0) {
- lp->dialwait_timer = jiffies + lp->dialwait;
- lp->dialstarted = 0;
- isdn_net_unreachable(p->dev, NULL, "dial: tried all numbers dialmax times");
- }
- isdn_net_hangup(p->dev);
- break;
- }
- }
- sprintf(cmd.parm.setup.eazmsn, "%s",
- isdn_map_eaz2msn(lp->msn, cmd.driver));
- i = isdn_dc2minor(lp->isdn_device, lp->isdn_channel);
- if (i >= 0) {
- strcpy(dev->num[i], cmd.parm.setup.phone);
- dev->usage[i] |= ISDN_USAGE_OUTGOING;
- isdn_info_update();
- }
- printk(KERN_INFO "%s: dialing %d %s... %s\n", p->dev->name,
- lp->dialretry, cmd.parm.setup.phone,
- (cmd.parm.setup.si1 == 1) ? "DOV" : "");
- lp->dtimer = 0;
-#ifdef ISDN_DEBUG_NET_DIAL
- printk(KERN_DEBUG "dial: d=%d c=%d\n", lp->isdn_device,
- lp->isdn_channel);
-#endif
- isdn_command(&cmd);
- }
- lp->huptimer = 0;
- lp->outgoing = 1;
- if (lp->chargeint) {
- lp->hupflags |= ISDN_HAVECHARGE;
- lp->hupflags &= ~ISDN_WAITCHARGE;
- } else {
- lp->hupflags |= ISDN_WAITCHARGE;
- lp->hupflags &= ~ISDN_HAVECHARGE;
- }
- anymore = 1;
- lp->dialstate =
- (lp->cbdelay &&
- (lp->flags & ISDN_NET_CBOUT)) ? 12 : 4;
- break;
- case 4:
- /* Wait for D-Channel-connect.
- * If timeout, switch back to state 3.
- * Dialmax-handling moved to state 3.
- */
- if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10)
- lp->dialstate = 3;
- anymore = 1;
- break;
- case 5:
- /* Got D-Channel-Connect, send B-Channel-request */
- cmd.driver = lp->isdn_device;
- cmd.arg = lp->isdn_channel;
- cmd.command = ISDN_CMD_ACCEPTB;
- anymore = 1;
- lp->dtimer = 0;
- lp->dialstate++;
- isdn_command(&cmd);
- break;
- case 6:
- /* Wait for B- or D-Channel-connect. If timeout,
- * switch back to state 3.
- */
-#ifdef ISDN_DEBUG_NET_DIAL
- printk(KERN_DEBUG "dialtimer2: %d\n", lp->dtimer);
-#endif
- if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10)
- lp->dialstate = 3;
- anymore = 1;
- break;
- case 7:
- /* Got incoming Call, setup L2 and L3 protocols,
- * then wait for D-Channel-connect
- */
-#ifdef ISDN_DEBUG_NET_DIAL
- printk(KERN_DEBUG "dialtimer4: %d\n", lp->dtimer);
-#endif
- cmd.driver = lp->isdn_device;
- cmd.command = ISDN_CMD_SETL2;
- cmd.arg = lp->isdn_channel + (lp->l2_proto << 8);
- isdn_command(&cmd);
- cmd.driver = lp->isdn_device;
- cmd.command = ISDN_CMD_SETL3;
- cmd.arg = lp->isdn_channel + (lp->l3_proto << 8);
- isdn_command(&cmd);
- if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT15)
- isdn_net_hangup(p->dev);
- else {
- anymore = 1;
- lp->dialstate++;
- }
- break;
- case 9:
- /* Got incoming D-Channel-Connect, send B-Channel-request */
- cmd.driver = lp->isdn_device;
- cmd.arg = lp->isdn_channel;
- cmd.command = ISDN_CMD_ACCEPTB;
- isdn_command(&cmd);
- anymore = 1;
- lp->dtimer = 0;
- lp->dialstate++;
- break;
- case 8:
- case 10:
- /* Wait for B- or D-channel-connect */
-#ifdef ISDN_DEBUG_NET_DIAL
- printk(KERN_DEBUG "dialtimer4: %d\n", lp->dtimer);
-#endif
- if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10)
- isdn_net_hangup(p->dev);
- else
- anymore = 1;
- break;
- case 11:
- /* Callback Delay */
- if (lp->dtimer++ > lp->cbdelay)
- lp->dialstate = 1;
- anymore = 1;
- break;
- case 12:
- /* Remote does callback. Hangup after cbdelay, then wait for incoming
- * call (in state 4).
- */
- if (lp->dtimer++ > lp->cbdelay)
- {
- printk(KERN_INFO "%s: hangup waiting for callback ...\n", p->dev->name);
- lp->dtimer = 0;
- lp->dialstate = 4;
- cmd.driver = lp->isdn_device;
- cmd.command = ISDN_CMD_HANGUP;
- cmd.arg = lp->isdn_channel;
- isdn_command(&cmd);
- isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
- }
- anymore = 1;
- break;
- default:
- printk(KERN_WARNING "isdn_net: Illegal dialstate %d for device %s\n",
- lp->dialstate, p->dev->name);
- }
- p = (isdn_net_dev *) p->next;
- }
- isdn_timer_ctrl(ISDN_TIMER_NETDIAL, anymore);
-}
-
-/*
- * Perform hangup for a net-interface.
- */
-void
-isdn_net_hangup(struct net_device *d)
-{
- isdn_net_local *lp = netdev_priv(d);
- isdn_ctrl cmd;
-#ifdef CONFIG_ISDN_X25
- struct concap_proto *cprot = lp->netdev->cprot;
- struct concap_proto_ops *pops = cprot ? cprot->pops : NULL;
-#endif
-
- if (lp->flags & ISDN_NET_CONNECTED) {
- if (lp->slave != NULL) {
- isdn_net_local *slp = ISDN_SLAVE_PRIV(lp);
- if (slp->flags & ISDN_NET_CONNECTED) {
- printk(KERN_INFO
- "isdn_net: hang up slave %s before %s\n",
- lp->slave->name, d->name);
- isdn_net_hangup(lp->slave);
- }
- }
- printk(KERN_INFO "isdn_net: local hangup %s\n", d->name);
-#ifdef CONFIG_ISDN_PPP
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
- isdn_ppp_free(lp);
-#endif
- isdn_net_lp_disconnected(lp);
-#ifdef CONFIG_ISDN_X25
- /* try if there are generic encap protocol
- receiver routines and signal the closure of
- the link */
- if (pops && pops->disconn_ind)
- pops->disconn_ind(cprot);
-#endif /* CONFIG_ISDN_X25 */
-
- cmd.driver = lp->isdn_device;
- cmd.command = ISDN_CMD_HANGUP;
- cmd.arg = lp->isdn_channel;
- isdn_command(&cmd);
- printk(KERN_INFO "%s: Chargesum is %d\n", d->name, lp->charge);
- isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
- }
- isdn_net_unbind_channel(lp);
-}
-
-typedef struct {
- __be16 source;
- __be16 dest;
-} ip_ports;
-
-static void
-isdn_net_log_skb(struct sk_buff *skb, isdn_net_local *lp)
-{
- /* hopefully, this was set correctly */
- const u_char *p = skb_network_header(skb);
- unsigned short proto = ntohs(skb->protocol);
- int data_ofs;
- ip_ports *ipp;
- char addinfo[100];
-
- addinfo[0] = '\0';
- /* This check stolen from 2.1.72 dev_queue_xmit_nit() */
- if (p < skb->data || skb_network_header(skb) >= skb_tail_pointer(skb)) {
- /* fall back to old isdn_net_log_packet method() */
- char *buf = skb->data;
-
- printk(KERN_DEBUG "isdn_net: protocol %04x is buggy, dev %s\n", skb->protocol, lp->netdev->dev->name);
- p = buf;
- proto = ETH_P_IP;
- switch (lp->p_encap) {
- case ISDN_NET_ENCAP_IPTYP:
- proto = ntohs(*(__be16 *)&buf[0]);
- p = &buf[2];
- break;
- case ISDN_NET_ENCAP_ETHER:
- proto = ntohs(*(__be16 *)&buf[12]);
- p = &buf[14];
- break;
- case ISDN_NET_ENCAP_CISCOHDLC:
- proto = ntohs(*(__be16 *)&buf[2]);
- p = &buf[4];
- break;
-#ifdef CONFIG_ISDN_PPP
- case ISDN_NET_ENCAP_SYNCPPP:
- proto = ntohs(skb->protocol);
- p = &buf[IPPP_MAX_HEADER];
- break;
-#endif
- }
- }
- data_ofs = ((p[0] & 15) * 4);
- switch (proto) {
- case ETH_P_IP:
- switch (p[9]) {
- case 1:
- strcpy(addinfo, " ICMP");
- break;
- case 2:
- strcpy(addinfo, " IGMP");
- break;
- case 4:
- strcpy(addinfo, " IPIP");
- break;
- case 6:
- ipp = (ip_ports *) (&p[data_ofs]);
- sprintf(addinfo, " TCP, port: %d -> %d", ntohs(ipp->source),
- ntohs(ipp->dest));
- break;
- case 8:
- strcpy(addinfo, " EGP");
- break;
- case 12:
- strcpy(addinfo, " PUP");
- break;
- case 17:
- ipp = (ip_ports *) (&p[data_ofs]);
- sprintf(addinfo, " UDP, port: %d -> %d", ntohs(ipp->source),
- ntohs(ipp->dest));
- break;
- case 22:
- strcpy(addinfo, " IDP");
- break;
- }
- printk(KERN_INFO "OPEN: %pI4 -> %pI4%s\n",
- p + 12, p + 16, addinfo);
- break;
- case ETH_P_ARP:
- printk(KERN_INFO "OPEN: ARP %pI4 -> *.*.*.* ?%pI4\n",
- p + 14, p + 24);
- break;
- }
-}
-
-/*
- * this function is used to send supervisory data, i.e. data which was
- * not received from the network layer, but e.g. frames from ipppd, CCP
- * reset frames etc.
- */
-void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb)
-{
- if (in_irq()) {
- // we can't grab the lock from irq context,
- // so we just queue the packet
- skb_queue_tail(&lp->super_tx_queue, skb);
- schedule_work(&lp->tqueue);
- return;
- }
-
- spin_lock_bh(&lp->xmit_lock);
- if (!isdn_net_lp_busy(lp)) {
- isdn_net_writebuf_skb(lp, skb);
- } else {
- skb_queue_tail(&lp->super_tx_queue, skb);
- }
- spin_unlock_bh(&lp->xmit_lock);
-}
-
-/*
- * called from tq_immediate
- */
-static void isdn_net_softint(struct work_struct *work)
-{
- isdn_net_local *lp = container_of(work, isdn_net_local, tqueue);
- struct sk_buff *skb;
-
- spin_lock_bh(&lp->xmit_lock);
- while (!isdn_net_lp_busy(lp)) {
- skb = skb_dequeue(&lp->super_tx_queue);
- if (!skb)
- break;
- isdn_net_writebuf_skb(lp, skb);
- }
- spin_unlock_bh(&lp->xmit_lock);
-}
-
-/*
- * all frames sent from the (net) LL to a HL driver should go via this function
- * it's serialized by the caller holding the lp->xmit_lock spinlock
- */
-void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb)
-{
- int ret;
- int len = skb->len; /* save len */
-
- /* before obtaining the lock the caller should have checked that
- the lp isn't busy */
- if (isdn_net_lp_busy(lp)) {
- printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
- goto error;
- }
-
- if (!(lp->flags & ISDN_NET_CONNECTED)) {
- printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
- goto error;
- }
- ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb);
- if (ret != len) {
- /* we should never get here */
- printk(KERN_WARNING "%s: HL driver queue full\n", lp->netdev->dev->name);
- goto error;
- }
-
- lp->transcount += len;
- isdn_net_inc_frame_cnt(lp);
- return;
-
-error:
- dev_kfree_skb(skb);
- lp->stats.tx_errors++;
-
-}
-
-
-/*
- * Helper function for isdn_net_start_xmit.
- * When called, the connection is already established.
- * Based on cps-calculation, check if device is overloaded.
- * If so, and if a slave exists, trigger dialing for it.
- * If any slave is online, deliver packets using a simple round robin
- * scheme.
- *
- * Return: 0 on success, !0 on failure.
- */
-
-static int
-isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb)
-{
- isdn_net_dev *nd;
- isdn_net_local *slp;
- isdn_net_local *lp = netdev_priv(ndev);
- int retv = NETDEV_TX_OK;
-
- if (((isdn_net_local *) netdev_priv(ndev))->master) {
- printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-
- /* For the other encaps the header has already been built */
-#ifdef CONFIG_ISDN_PPP
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
- return isdn_ppp_xmit(skb, ndev);
- }
-#endif
- nd = ((isdn_net_local *) netdev_priv(ndev))->netdev;
- lp = isdn_net_get_locked_lp(nd);
- if (!lp) {
- printk(KERN_WARNING "%s: all channels busy - requeuing!\n", ndev->name);
- return NETDEV_TX_BUSY;
- }
- /* we have our lp locked from now on */
-
- /* Reset hangup-timeout */
- lp->huptimer = 0; // FIXME?
- isdn_net_writebuf_skb(lp, skb);
- spin_unlock_bh(&lp->xmit_lock);
-
- /* the following stuff is here for backwards compatibility.
- * in future, start-up and hangup of slaves (based on current load)
- * should move to userspace and get based on an overall cps
- * calculation
- */
- if (lp->cps > lp->triggercps) {
- if (lp->slave) {
- if (!lp->sqfull) {
- /* First time overload: set timestamp only */
- lp->sqfull = 1;
- lp->sqfull_stamp = jiffies;
- } else {
- /* subsequent overload: if slavedelay exceeded, start dialing */
- if (time_after(jiffies, lp->sqfull_stamp + lp->slavedelay)) {
- slp = ISDN_SLAVE_PRIV(lp);
- if (!(slp->flags & ISDN_NET_CONNECTED)) {
- isdn_net_force_dial_lp(ISDN_SLAVE_PRIV(lp));
- }
- }
- }
- }
- } else {
- if (lp->sqfull && time_after(jiffies, lp->sqfull_stamp + lp->slavedelay + (10 * HZ))) {
- lp->sqfull = 0;
- }
- /* this is a hack to allow auto-hangup for slaves on moderate loads */
- nd->queue = nd->local;
- }
-
- return retv;
-
-}
-
-static void
-isdn_net_adjust_hdr(struct sk_buff *skb, struct net_device *dev)
-{
- isdn_net_local *lp = netdev_priv(dev);
- if (!skb)
- return;
- if (lp->p_encap == ISDN_NET_ENCAP_ETHER) {
- const int pullsize = skb_network_offset(skb) - ETH_HLEN;
- if (pullsize > 0) {
- printk(KERN_DEBUG "isdn_net: Pull junk %d\n", pullsize);
- skb_pull(skb, pullsize);
- }
- }
-}
-
-
-static void isdn_net_tx_timeout(struct net_device *ndev)
-{
- isdn_net_local *lp = netdev_priv(ndev);
-
- printk(KERN_WARNING "isdn_tx_timeout dev %s dialstate %d\n", ndev->name, lp->dialstate);
- if (!lp->dialstate) {
- lp->stats.tx_errors++;
- /*
- * There is a certain probability that this currently
- * works at all because if we always wake up the interface,
- * then upper layer will try to send the next packet
- * immediately. And then, the old clean_up logic in the
- * driver will hopefully continue to work as it used to do.
- *
- * This is rather primitive right know, we better should
- * clean internal queues here, in particular for multilink and
- * ppp, and reset HL driver's channel, too. --HE
- *
- * actually, this may not matter at all, because ISDN hardware
- * should not see transmitter hangs at all IMO
- * changed KERN_DEBUG to KERN_WARNING to find out if this is
- * ever called --KG
- */
- }
- netif_trans_update(ndev);
- netif_wake_queue(ndev);
-}
-
-/*
- * Try sending a packet.
- * If this interface isn't connected to a ISDN-Channel, find a free channel,
- * and start dialing.
- */
-static netdev_tx_t
-isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
-{
- isdn_net_local *lp = netdev_priv(ndev);
-#ifdef CONFIG_ISDN_X25
- struct concap_proto *cprot = lp->netdev->cprot;
-/* At this point hard_start_xmit() passes control to the encapsulation
- protocol (if present).
- For X.25 auto-dialing is completly bypassed because:
- - It does not conform with the semantics of a reliable datalink
- service as needed by X.25 PLP.
- - I don't want that the interface starts dialing when the network layer
- sends a message which requests to disconnect the lapb link (or if it
- sends any other message not resulting in data transmission).
- Instead, dialing will be initiated by the encapsulation protocol entity
- when a dl_establish request is received from the upper layer.
-*/
- if (cprot && cprot->pops) {
- int ret = cprot->pops->encap_and_xmit(cprot, skb);
-
- if (ret)
- netif_stop_queue(ndev);
- return ret;
- } else
-#endif
- /* auto-dialing xmit function */
- {
-#ifdef ISDN_DEBUG_NET_DUMP
- u_char *buf;
-#endif
- isdn_net_adjust_hdr(skb, ndev);
-#ifdef ISDN_DEBUG_NET_DUMP
- buf = skb->data;
- isdn_dumppkt("S:", buf, skb->len, 40);
-#endif
-
- if (!(lp->flags & ISDN_NET_CONNECTED)) {
- int chi;
- /* only do autodial if allowed by config */
- if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) {
- isdn_net_unreachable(ndev, skb, "dial rejected: interface not in dialmode `auto'");
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
- if (lp->phone[1]) {
- ulong flags;
-
- if (lp->dialwait_timer <= 0)
- if (lp->dialstarted > 0 && lp->dialtimeout > 0 && time_before(jiffies, lp->dialstarted + lp->dialtimeout + lp->dialwait))
- lp->dialwait_timer = lp->dialstarted + lp->dialtimeout + lp->dialwait;
-
- if (lp->dialwait_timer > 0) {
- if (time_before(jiffies, lp->dialwait_timer)) {
- isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached");
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- } else
- lp->dialwait_timer = 0;
- }
- /* Grab a free ISDN-Channel */
- spin_lock_irqsave(&dev->lock, flags);
- if (((chi =
- isdn_get_free_channel(
- ISDN_USAGE_NET,
- lp->l2_proto,
- lp->l3_proto,
- lp->pre_device,
- lp->pre_channel,
- lp->msn)
- ) < 0) &&
- ((chi =
- isdn_get_free_channel(
- ISDN_USAGE_NET,
- lp->l2_proto,
- lp->l3_proto,
- lp->pre_device,
- lp->pre_channel^1,
- lp->msn)
- ) < 0)) {
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_net_unreachable(ndev, skb,
- "No channel");
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
- /* Log packet, which triggered dialing */
- if (dev->net_verbose)
- isdn_net_log_skb(skb, lp);
- lp->dialstate = 1;
- /* Connect interface with channel */
- isdn_net_bind_channel(lp, chi);
-#ifdef CONFIG_ISDN_PPP
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
- /* no 'first_skb' handling for syncPPP */
- if (isdn_ppp_bind(lp) < 0) {
- dev_kfree_skb(skb);
- isdn_net_unbind_channel(lp);
- spin_unlock_irqrestore(&dev->lock, flags);
- return NETDEV_TX_OK; /* STN (skb to nirvana) ;) */
- }
-#ifdef CONFIG_IPPP_FILTER
- if (isdn_ppp_autodial_filter(skb, lp)) {
- isdn_ppp_free(lp);
- isdn_net_unbind_channel(lp);
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_net_unreachable(ndev, skb, "dial rejected: packet filtered");
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-#endif
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_net_dial(); /* Initiate dialing */
- netif_stop_queue(ndev);
- return NETDEV_TX_BUSY; /* let upper layer requeue skb packet */
- }
-#endif
- /* Initiate dialing */
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_net_dial();
- isdn_net_device_stop_queue(lp);
- return NETDEV_TX_BUSY;
- } else {
- isdn_net_unreachable(ndev, skb,
- "No phone number");
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
- } else {
- /* Device is connected to an ISDN channel */
- netif_trans_update(ndev);
- if (!lp->dialstate) {
- /* ISDN connection is established, try sending */
- int ret;
- ret = (isdn_net_xmit(ndev, skb));
- if (ret) netif_stop_queue(ndev);
- return ret;
- } else
- netif_stop_queue(ndev);
- }
- }
- return NETDEV_TX_BUSY;
-}
-
-/*
- * Shutdown a net-interface.
- */
-static int
-isdn_net_close(struct net_device *dev)
-{
- struct net_device *p;
-#ifdef CONFIG_ISDN_X25
- struct concap_proto *cprot =
- ((isdn_net_local *)netdev_priv(dev))->netdev->cprot;
- /* printk(KERN_DEBUG "isdn_net_close %s\n" , dev-> name); */
-#endif
-
-#ifdef CONFIG_ISDN_X25
- if (cprot && cprot->pops) cprot->pops->close(cprot);
-#endif
- netif_stop_queue(dev);
- p = MASTER_TO_SLAVE(dev);
- if (p) {
- /* If this interface has slaves, stop them also */
- while (p) {
-#ifdef CONFIG_ISDN_X25
- cprot = ((isdn_net_local *)netdev_priv(p))
- ->netdev->cprot;
- if (cprot && cprot->pops)
- cprot->pops->close(cprot);
-#endif
- isdn_net_hangup(p);
- p = MASTER_TO_SLAVE(p);
- }
- }
- isdn_net_hangup(dev);
- isdn_unlock_drivers();
- return 0;
-}
-
-/*
- * Get statistics
- */
-static struct net_device_stats *
-isdn_net_get_stats(struct net_device *dev)
-{
- isdn_net_local *lp = netdev_priv(dev);
- return &lp->stats;
-}
-
-/* This is simply a copy from std. eth.c EXCEPT we pull ETH_HLEN
- * instead of dev->hard_header_len off. This is done because the
- * lowlevel-driver has already pulled off its stuff when we get
- * here and this routine only gets called with p_encap == ETHER.
- * Determine the packet's protocol ID. The rule here is that we
- * assume 802.3 if the type field is short enough to be a length.
- * This is normal practice and works for any 'now in use' protocol.
- */
-
-static __be16
-isdn_net_type_trans(struct sk_buff *skb, struct net_device *dev)
-{
- struct ethhdr *eth;
- unsigned char *rawp;
-
- skb_reset_mac_header(skb);
- skb_pull(skb, ETH_HLEN);
- eth = eth_hdr(skb);
-
- if (*eth->h_dest & 1) {
- if (ether_addr_equal(eth->h_dest, dev->broadcast))
- skb->pkt_type = PACKET_BROADCAST;
- else
- skb->pkt_type = PACKET_MULTICAST;
- }
- /*
- * This ALLMULTI check should be redundant by 1.4
- * so don't forget to remove it.
- */
-
- else if (dev->flags & (IFF_PROMISC /*| IFF_ALLMULTI*/)) {
- if (!ether_addr_equal(eth->h_dest, dev->dev_addr))
- skb->pkt_type = PACKET_OTHERHOST;
- }
- if (ntohs(eth->h_proto) >= ETH_P_802_3_MIN)
- return eth->h_proto;
-
- rawp = skb->data;
-
- /*
- * This is a magic hack to spot IPX packets. Older Novell breaks
- * the protocol design and runs IPX over 802.3 without an 802.2 LLC
- * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
- * won't work for fault tolerant netware but does for the rest.
- */
- if (*(unsigned short *) rawp == 0xFFFF)
- return htons(ETH_P_802_3);
- /*
- * Real 802.2 LLC
- */
- return htons(ETH_P_802_2);
-}
-
-
-/*
- * CISCO HDLC keepalive specific stuff
- */
-static struct sk_buff*
-isdn_net_ciscohdlck_alloc_skb(isdn_net_local *lp, int len)
-{
- unsigned short hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
- struct sk_buff *skb;
-
- skb = alloc_skb(hl + len, GFP_ATOMIC);
- if (skb)
- skb_reserve(skb, hl);
- else
- printk("isdn out of mem at %s:%d!\n", __FILE__, __LINE__);
- return skb;
-}
-
-/* cisco hdlck device private ioctls */
-static int
-isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
- isdn_net_local *lp = netdev_priv(dev);
- unsigned long len = 0;
- unsigned long expires = 0;
- int tmp = 0;
- int period = lp->cisco_keepalive_period;
- s8 debserint = lp->cisco_debserint;
- int rc = 0;
-
- if (lp->p_encap != ISDN_NET_ENCAP_CISCOHDLCK)
- return -EINVAL;
-
- switch (cmd) {
- /* get/set keepalive period */
- case SIOCGKEEPPERIOD:
- len = (unsigned long)sizeof(lp->cisco_keepalive_period);
- if (copy_to_user(ifr->ifr_data,
- &lp->cisco_keepalive_period, len))
- rc = -EFAULT;
- break;
- case SIOCSKEEPPERIOD:
- tmp = lp->cisco_keepalive_period;
- len = (unsigned long)sizeof(lp->cisco_keepalive_period);
- if (copy_from_user(&period, ifr->ifr_data, len))
- rc = -EFAULT;
- if ((period > 0) && (period <= 32767))
- lp->cisco_keepalive_period = period;
- else
- rc = -EINVAL;
- if (!rc && (tmp != lp->cisco_keepalive_period)) {
- expires = (unsigned long)(jiffies +
- lp->cisco_keepalive_period * HZ);
- mod_timer(&lp->cisco_timer, expires);
- printk(KERN_INFO "%s: Keepalive period set "
- "to %d seconds.\n",
- dev->name, lp->cisco_keepalive_period);
- }
- break;
-
- /* get/set debugging */
- case SIOCGDEBSERINT:
- len = (unsigned long)sizeof(lp->cisco_debserint);
- if (copy_to_user(ifr->ifr_data,
- &lp->cisco_debserint, len))
- rc = -EFAULT;
- break;
- case SIOCSDEBSERINT:
- len = (unsigned long)sizeof(lp->cisco_debserint);
- if (copy_from_user(&debserint,
- ifr->ifr_data, len))
- rc = -EFAULT;
- if ((debserint >= 0) && (debserint <= 64))
- lp->cisco_debserint = debserint;
- else
- rc = -EINVAL;
- break;
-
- default:
- rc = -EINVAL;
- break;
- }
- return (rc);
-}
-
-
-static int isdn_net_ioctl(struct net_device *dev,
- struct ifreq *ifr, int cmd)
-{
- isdn_net_local *lp = netdev_priv(dev);
-
- switch (lp->p_encap) {
-#ifdef CONFIG_ISDN_PPP
- case ISDN_NET_ENCAP_SYNCPPP:
- return isdn_ppp_dev_ioctl(dev, ifr, cmd);
-#endif
- case ISDN_NET_ENCAP_CISCOHDLCK:
- return isdn_ciscohdlck_dev_ioctl(dev, ifr, cmd);
- default:
- return -EINVAL;
- }
-}
-
-/* called via cisco_timer.function */
-static void
-isdn_net_ciscohdlck_slarp_send_keepalive(struct timer_list *t)
-{
- isdn_net_local *lp = from_timer(lp, t, cisco_timer);
- struct sk_buff *skb;
- unsigned char *p;
- unsigned long last_cisco_myseq = lp->cisco_myseq;
- int myseq_diff = 0;
-
- if (!(lp->flags & ISDN_NET_CONNECTED) || lp->dialstate) {
- printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
- return;
- }
- lp->cisco_myseq++;
-
- myseq_diff = (lp->cisco_myseq - lp->cisco_mineseen);
- if ((lp->cisco_line_state) && ((myseq_diff >= 3) || (myseq_diff <= -3))) {
- /* line up -> down */
- lp->cisco_line_state = 0;
- printk(KERN_WARNING
- "UPDOWN: Line protocol on Interface %s,"
- " changed state to down\n", lp->netdev->dev->name);
- /* should stop routing higher-level data across */
- } else if ((!lp->cisco_line_state) &&
- (myseq_diff >= 0) && (myseq_diff <= 2)) {
- /* line down -> up */
- lp->cisco_line_state = 1;
- printk(KERN_WARNING
- "UPDOWN: Line protocol on Interface %s,"
- " changed state to up\n", lp->netdev->dev->name);
- /* restart routing higher-level data across */
- }
-
- if (lp->cisco_debserint)
- printk(KERN_DEBUG "%s: HDLC "
- "myseq %lu, mineseen %lu%c, yourseen %lu, %s\n",
- lp->netdev->dev->name, last_cisco_myseq, lp->cisco_mineseen,
- ((last_cisco_myseq == lp->cisco_mineseen) ? '*' : 040),
- lp->cisco_yourseq,
- ((lp->cisco_line_state) ? "line up" : "line down"));
-
- skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
- if (!skb)
- return;
-
- p = skb_put(skb, 4 + 14);
-
- /* cisco header */
- *(u8 *)(p + 0) = CISCO_ADDR_UNICAST;
- *(u8 *)(p + 1) = CISCO_CTRL;
- *(__be16 *)(p + 2) = cpu_to_be16(CISCO_TYPE_SLARP);
-
- /* slarp keepalive */
- *(__be32 *)(p + 4) = cpu_to_be32(CISCO_SLARP_KEEPALIVE);
- *(__be32 *)(p + 8) = cpu_to_be32(lp->cisco_myseq);
- *(__be32 *)(p + 12) = cpu_to_be32(lp->cisco_yourseq);
- *(__be16 *)(p + 16) = cpu_to_be16(0xffff); // reliability, always 0xffff
- p += 18;
-
- isdn_net_write_super(lp, skb);
-
- lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ;
-
- add_timer(&lp->cisco_timer);
-}
-
-static void
-isdn_net_ciscohdlck_slarp_send_request(isdn_net_local *lp)
-{
- struct sk_buff *skb;
- unsigned char *p;
-
- skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
- if (!skb)
- return;
-
- p = skb_put(skb, 4 + 14);
-
- /* cisco header */
- *(u8 *)(p + 0) = CISCO_ADDR_UNICAST;
- *(u8 *)(p + 1) = CISCO_CTRL;
- *(__be16 *)(p + 2) = cpu_to_be16(CISCO_TYPE_SLARP);
-
- /* slarp request */
- *(__be32 *)(p + 4) = cpu_to_be32(CISCO_SLARP_REQUEST);
- *(__be32 *)(p + 8) = cpu_to_be32(0); // address
- *(__be32 *)(p + 12) = cpu_to_be32(0); // netmask
- *(__be16 *)(p + 16) = cpu_to_be16(0); // unused
- p += 18;
-
- isdn_net_write_super(lp, skb);
-}
-
-static void
-isdn_net_ciscohdlck_connected(isdn_net_local *lp)
-{
- lp->cisco_myseq = 0;
- lp->cisco_mineseen = 0;
- lp->cisco_yourseq = 0;
- lp->cisco_keepalive_period = ISDN_TIMER_KEEPINT;
- lp->cisco_last_slarp_in = 0;
- lp->cisco_line_state = 0;
- lp->cisco_debserint = 0;
-
- /* send slarp request because interface/seq.no.s reset */
- isdn_net_ciscohdlck_slarp_send_request(lp);
-
- timer_setup(&lp->cisco_timer,
- isdn_net_ciscohdlck_slarp_send_keepalive, 0);
- lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ;
- add_timer(&lp->cisco_timer);
-}
-
-static void
-isdn_net_ciscohdlck_disconnected(isdn_net_local *lp)
-{
- del_timer(&lp->cisco_timer);
-}
-
-static void
-isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp)
-{
- struct sk_buff *skb;
- unsigned char *p;
- struct in_device *in_dev = NULL;
- __be32 addr = 0; /* local ipv4 address */
- __be32 mask = 0; /* local netmask */
-
- if ((in_dev = lp->netdev->dev->ip_ptr) != NULL) {
- /* take primary(first) address of interface */
- struct in_ifaddr *ifa = in_dev->ifa_list;
- if (ifa != NULL) {
- addr = ifa->ifa_local;
- mask = ifa->ifa_mask;
- }
- }
-
- skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
- if (!skb)
- return;
-
- p = skb_put(skb, 4 + 14);
-
- /* cisco header */
- *(u8 *)(p + 0) = CISCO_ADDR_UNICAST;
- *(u8 *)(p + 1) = CISCO_CTRL;
- *(__be16 *)(p + 2) = cpu_to_be16(CISCO_TYPE_SLARP);
-
- /* slarp reply, send own ip/netmask; if values are nonsense remote
- * should think we are unable to provide it with an address via SLARP */
- *(__be32 *)(p + 4) = cpu_to_be32(CISCO_SLARP_REPLY);
- *(__be32 *)(p + 8) = addr; // address
- *(__be32 *)(p + 12) = mask; // netmask
- *(__be16 *)(p + 16) = cpu_to_be16(0); // unused
- p += 18;
-
- isdn_net_write_super(lp, skb);
-}
-
-static void
-isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb)
-{
- unsigned char *p;
- int period;
- u32 code;
- u32 my_seq;
- u32 your_seq;
- __be32 local;
- __be32 *addr, *mask;
-
- if (skb->len < 14)
- return;
-
- p = skb->data;
- code = be32_to_cpup((__be32 *)p);
- p += 4;
-
- switch (code) {
- case CISCO_SLARP_REQUEST:
- lp->cisco_yourseq = 0;
- isdn_net_ciscohdlck_slarp_send_reply(lp);
- break;
- case CISCO_SLARP_REPLY:
- addr = (__be32 *)p;
- mask = (__be32 *)(p + 4);
- if (*mask != cpu_to_be32(0xfffffffc))
- goto slarp_reply_out;
- if ((*addr & cpu_to_be32(3)) == cpu_to_be32(0) ||
- (*addr & cpu_to_be32(3)) == cpu_to_be32(3))
- goto slarp_reply_out;
- local = *addr ^ cpu_to_be32(3);
- printk(KERN_INFO "%s: got slarp reply: remote ip: %pI4, local ip: %pI4 mask: %pI4\n",
- lp->netdev->dev->name, addr, &local, mask);
- break;
- slarp_reply_out:
- printk(KERN_INFO "%s: got invalid slarp reply (%pI4/%pI4) - ignored\n",
- lp->netdev->dev->name, addr, mask);
- break;
- case CISCO_SLARP_KEEPALIVE:
- period = (int)((jiffies - lp->cisco_last_slarp_in
- + HZ / 2 - 1) / HZ);
- if (lp->cisco_debserint &&
- (period != lp->cisco_keepalive_period) &&
- lp->cisco_last_slarp_in) {
- printk(KERN_DEBUG "%s: Keepalive period mismatch - "
- "is %d but should be %d.\n",
- lp->netdev->dev->name, period,
- lp->cisco_keepalive_period);
- }
- lp->cisco_last_slarp_in = jiffies;
- my_seq = be32_to_cpup((__be32 *)(p + 0));
- your_seq = be32_to_cpup((__be32 *)(p + 4));
- p += 10;
- lp->cisco_yourseq = my_seq;
- lp->cisco_mineseen = your_seq;
- break;
- }
-}
-
-static void
-isdn_net_ciscohdlck_receive(isdn_net_local *lp, struct sk_buff *skb)
-{
- unsigned char *p;
- u8 addr;
- u8 ctrl;
- u16 type;
-
- if (skb->len < 4)
- goto out_free;
-
- p = skb->data;
- addr = *(u8 *)(p + 0);
- ctrl = *(u8 *)(p + 1);
- type = be16_to_cpup((__be16 *)(p + 2));
- p += 4;
- skb_pull(skb, 4);
-
- if (addr != CISCO_ADDR_UNICAST && addr != CISCO_ADDR_BROADCAST) {
- printk(KERN_WARNING "%s: Unknown Cisco addr 0x%02x\n",
- lp->netdev->dev->name, addr);
- goto out_free;
- }
- if (ctrl != CISCO_CTRL) {
- printk(KERN_WARNING "%s: Unknown Cisco ctrl 0x%02x\n",
- lp->netdev->dev->name, ctrl);
- goto out_free;
- }
-
- switch (type) {
- case CISCO_TYPE_SLARP:
- isdn_net_ciscohdlck_slarp_in(lp, skb);
- goto out_free;
- case CISCO_TYPE_CDP:
- if (lp->cisco_debserint)
- printk(KERN_DEBUG "%s: Received CDP packet. use "
- "\"no cdp enable\" on cisco.\n",
- lp->netdev->dev->name);
- goto out_free;
- default:
- /* no special cisco protocol */
- skb->protocol = htons(type);
- netif_rx(skb);
- return;
- }
-
-out_free:
- kfree_skb(skb);
-}
-
-/*
- * Got a packet from ISDN-Channel.
- */
-static void
-isdn_net_receive(struct net_device *ndev, struct sk_buff *skb)
-{
- isdn_net_local *lp = netdev_priv(ndev);
- isdn_net_local *olp = lp; /* original 'lp' */
-#ifdef CONFIG_ISDN_X25
- struct concap_proto *cprot = lp->netdev->cprot;
-#endif
- lp->transcount += skb->len;
-
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += skb->len;
- if (lp->master) {
- /* Bundling: If device is a slave-device, deliver to master, also
- * handle master's statistics and hangup-timeout
- */
- ndev = lp->master;
- lp = netdev_priv(ndev);
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += skb->len;
- }
- skb->dev = ndev;
- skb->pkt_type = PACKET_HOST;
- skb_reset_mac_header(skb);
-#ifdef ISDN_DEBUG_NET_DUMP
- isdn_dumppkt("R:", skb->data, skb->len, 40);
-#endif
- switch (lp->p_encap) {
- case ISDN_NET_ENCAP_ETHER:
- /* Ethernet over ISDN */
- olp->huptimer = 0;
- lp->huptimer = 0;
- skb->protocol = isdn_net_type_trans(skb, ndev);
- break;
- case ISDN_NET_ENCAP_UIHDLC:
- /* HDLC with UI-frame (for ispa with -h1 option) */
- olp->huptimer = 0;
- lp->huptimer = 0;
- skb_pull(skb, 2);
- /* Fall through */
- case ISDN_NET_ENCAP_RAWIP:
- /* RAW-IP without MAC-Header */
- olp->huptimer = 0;
- lp->huptimer = 0;
- skb->protocol = htons(ETH_P_IP);
- break;
- case ISDN_NET_ENCAP_CISCOHDLCK:
- isdn_net_ciscohdlck_receive(lp, skb);
- return;
- case ISDN_NET_ENCAP_CISCOHDLC:
- /* CISCO-HDLC IP with type field and fake I-frame-header */
- skb_pull(skb, 2);
- /* Fall through */
- case ISDN_NET_ENCAP_IPTYP:
- /* IP with type field */
- olp->huptimer = 0;
- lp->huptimer = 0;
- skb->protocol = *(__be16 *)&(skb->data[0]);
- skb_pull(skb, 2);
- if (*(unsigned short *) skb->data == 0xFFFF)
- skb->protocol = htons(ETH_P_802_3);
- break;
-#ifdef CONFIG_ISDN_PPP
- case ISDN_NET_ENCAP_SYNCPPP:
- /* huptimer is done in isdn_ppp_push_higher */
- isdn_ppp_receive(lp->netdev, olp, skb);
- return;
-#endif
-
- default:
-#ifdef CONFIG_ISDN_X25
- /* try if there are generic sync_device receiver routines */
- if (cprot) if (cprot->pops)
- if (cprot->pops->data_ind) {
- cprot->pops->data_ind(cprot, skb);
- return;
- };
-#endif /* CONFIG_ISDN_X25 */
- printk(KERN_WARNING "%s: unknown encapsulation, dropping\n",
- lp->netdev->dev->name);
- kfree_skb(skb);
- return;
- }
-
- netif_rx(skb);
- return;
-}
-
-/*
- * A packet arrived via ISDN. Search interface-chain for a corresponding
- * interface. If found, deliver packet to receiver-function and return 1,
- * else return 0.
- */
-int
-isdn_net_rcv_skb(int idx, struct sk_buff *skb)
-{
- isdn_net_dev *p = dev->rx_netdev[idx];
-
- if (p) {
- isdn_net_local *lp = p->local;
- if ((lp->flags & ISDN_NET_CONNECTED) &&
- (!lp->dialstate)) {
- isdn_net_receive(p->dev, skb);
- return 1;
- }
- }
- return 0;
-}
-
-/*
- * build an header
- * depends on encaps that is being used.
- */
-
-static int isdn_net_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type,
- const void *daddr, const void *saddr, unsigned plen)
-{
- isdn_net_local *lp = netdev_priv(dev);
- unsigned char *p;
- int len = 0;
-
- switch (lp->p_encap) {
- case ISDN_NET_ENCAP_ETHER:
- len = eth_header(skb, dev, type, daddr, saddr, plen);
- break;
-#ifdef CONFIG_ISDN_PPP
- case ISDN_NET_ENCAP_SYNCPPP:
- /* stick on a fake header to keep fragmentation code happy. */
- len = IPPP_MAX_HEADER;
- skb_push(skb, len);
- break;
-#endif
- case ISDN_NET_ENCAP_RAWIP:
- printk(KERN_WARNING "isdn_net_header called with RAW_IP!\n");
- len = 0;
- break;
- case ISDN_NET_ENCAP_IPTYP:
- /* ethernet type field */
- *((__be16 *)skb_push(skb, 2)) = htons(type);
- len = 2;
- break;
- case ISDN_NET_ENCAP_UIHDLC:
- /* HDLC with UI-Frames (for ispa with -h1 option) */
- *((__be16 *)skb_push(skb, 2)) = htons(0x0103);
- len = 2;
- break;
- case ISDN_NET_ENCAP_CISCOHDLC:
- case ISDN_NET_ENCAP_CISCOHDLCK:
- p = skb_push(skb, 4);
- *(u8 *)(p + 0) = CISCO_ADDR_UNICAST;
- *(u8 *)(p + 1) = CISCO_CTRL;
- *(__be16 *)(p + 2) = cpu_to_be16(type);
- p += 4;
- len = 4;
- break;
-#ifdef CONFIG_ISDN_X25
- default:
- /* try if there are generic concap protocol routines */
- if (lp->netdev->cprot) {
- printk(KERN_WARNING "isdn_net_header called with concap_proto!\n");
- len = 0;
- break;
- }
- break;
-#endif /* CONFIG_ISDN_X25 */
- }
- return len;
-}
-
-static int isdn_header_cache(const struct neighbour *neigh, struct hh_cache *hh,
- __be16 type)
-{
- const struct net_device *dev = neigh->dev;
- isdn_net_local *lp = netdev_priv(dev);
-
- if (lp->p_encap == ISDN_NET_ENCAP_ETHER)
- return eth_header_cache(neigh, hh, type);
- return -1;
-}
-
-static void isdn_header_cache_update(struct hh_cache *hh,
- const struct net_device *dev,
- const unsigned char *haddr)
-{
- isdn_net_local *lp = netdev_priv(dev);
- if (lp->p_encap == ISDN_NET_ENCAP_ETHER)
- eth_header_cache_update(hh, dev, haddr);
-}
-
-static const struct header_ops isdn_header_ops = {
- .create = isdn_net_header,
- .cache = isdn_header_cache,
- .cache_update = isdn_header_cache_update,
-};
-
-/*
- * Interface-setup. (just after registering a new interface)
- */
-static int
-isdn_net_init(struct net_device *ndev)
-{
- ushort max_hlhdr_len = 0;
- int drvidx;
-
- /*
- * up till binding we ask the protocol layer to reserve as much
- * as we might need for HL layer
- */
-
- for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++)
- if (dev->drv[drvidx])
- if (max_hlhdr_len < dev->drv[drvidx]->interface->hl_hdrlen)
- max_hlhdr_len = dev->drv[drvidx]->interface->hl_hdrlen;
-
- ndev->hard_header_len = ETH_HLEN + max_hlhdr_len;
- return 0;
-}
-
-static void
-isdn_net_swapbind(int drvidx)
-{
- isdn_net_dev *p;
-
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: swapping ch of %d\n", drvidx);
-#endif
- p = dev->netdev;
- while (p) {
- if (p->local->pre_device == drvidx)
- switch (p->local->pre_channel) {
- case 0:
- p->local->pre_channel = 1;
- break;
- case 1:
- p->local->pre_channel = 0;
- break;
- }
- p = (isdn_net_dev *) p->next;
- }
-}
-
-static void
-isdn_net_swap_usage(int i1, int i2)
-{
- int u1 = dev->usage[i1] & ISDN_USAGE_EXCLUSIVE;
- int u2 = dev->usage[i2] & ISDN_USAGE_EXCLUSIVE;
-
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: usage of %d and %d\n", i1, i2);
-#endif
- dev->usage[i1] &= ~ISDN_USAGE_EXCLUSIVE;
- dev->usage[i1] |= u2;
- dev->usage[i2] &= ~ISDN_USAGE_EXCLUSIVE;
- dev->usage[i2] |= u1;
- isdn_info_update();
-}
-
-/*
- * An incoming call-request has arrived.
- * Search the interface-chain for an appropriate interface.
- * If found, connect the interface to the ISDN-channel and initiate
- * D- and B-Channel-setup. If secure-flag is set, accept only
- * configured phone-numbers. If callback-flag is set, initiate
- * callback-dialing.
- *
- * Return-Value: 0 = No appropriate interface for this call.
- * 1 = Call accepted
- * 2 = Reject call, wait cbdelay, then call back
- * 3 = Reject call
- * 4 = Wait cbdelay, then call back
- * 5 = No appropriate interface for this call,
- * would eventually match if CID was longer.
- */
-
-int
-isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
-{
- char *eaz;
- int si1;
- int si2;
- int ematch;
- int wret;
- int swapped;
- int sidx = 0;
- u_long flags;
- isdn_net_dev *p;
- isdn_net_phone *n;
- char nr[ISDN_MSNLEN];
- char *my_eaz;
-
- /* Search name in netdev-chain */
- if (!setup->phone[0]) {
- nr[0] = '0';
- nr[1] = '\0';
- printk(KERN_INFO "isdn_net: Incoming call without OAD, assuming '0'\n");
- } else
- strlcpy(nr, setup->phone, ISDN_MSNLEN);
- si1 = (int) setup->si1;
- si2 = (int) setup->si2;
- if (!setup->eazmsn[0]) {
- printk(KERN_WARNING "isdn_net: Incoming call without CPN, assuming '0'\n");
- eaz = "0";
- } else
- eaz = setup->eazmsn;
- if (dev->net_verbose > 1)
- printk(KERN_INFO "isdn_net: call from %s,%d,%d -> %s\n", nr, si1, si2, eaz);
- /* Accept DATA and VOICE calls at this stage
- * local eaz is checked later for allowed call types
- */
- if ((si1 != 7) && (si1 != 1)) {
- if (dev->net_verbose > 1)
- printk(KERN_INFO "isdn_net: Service-Indicator not 1 or 7, ignored\n");
- return 0;
- }
- n = (isdn_net_phone *) 0;
- p = dev->netdev;
- ematch = wret = swapped = 0;
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: di=%d ch=%d idx=%d usg=%d\n", di, ch, idx,
- dev->usage[idx]);
-#endif
- while (p) {
- int matchret;
- isdn_net_local *lp = p->local;
-
- /* If last check has triggered as binding-swap, revert it */
- switch (swapped) {
- case 2:
- isdn_net_swap_usage(idx, sidx);
- /* fall through */
- case 1:
- isdn_net_swapbind(di);
- break;
- }
- swapped = 0;
- /* check acceptable call types for DOV */
- my_eaz = isdn_map_eaz2msn(lp->msn, di);
- if (si1 == 1) { /* it's a DOV call, check if we allow it */
- if (*my_eaz == 'v' || *my_eaz == 'V' ||
- *my_eaz == 'b' || *my_eaz == 'B')
- my_eaz++; /* skip to allow a match */
- else
- my_eaz = NULL; /* force non match */
- } else { /* it's a DATA call, check if we allow it */
- if (*my_eaz == 'b' || *my_eaz == 'B')
- my_eaz++; /* skip to allow a match */
- }
- if (my_eaz)
- matchret = isdn_msncmp(eaz, my_eaz);
- else
- matchret = 1;
- if (!matchret)
- ematch = 1;
-
- /* Remember if more numbers eventually can match */
- if (matchret > wret)
- wret = matchret;
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: if='%s', l.msn=%s, l.flags=%d, l.dstate=%d\n",
- p->dev->name, lp->msn, lp->flags, lp->dialstate);
-#endif
- if ((!matchret) && /* EAZ is matching */
- (((!(lp->flags & ISDN_NET_CONNECTED)) && /* but not connected */
- (USG_NONE(dev->usage[idx]))) || /* and ch. unused or */
- ((((lp->dialstate == 4) || (lp->dialstate == 12)) && /* if dialing */
- (!(lp->flags & ISDN_NET_CALLBACK))) /* but no callback */
- )))
- {
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: match1, pdev=%d pch=%d\n",
- lp->pre_device, lp->pre_channel);
-#endif
- if (dev->usage[idx] & ISDN_USAGE_EXCLUSIVE) {
- if ((lp->pre_channel != ch) ||
- (lp->pre_device != di)) {
- /* Here we got a problem:
- * If using an ICN-Card, an incoming call is always signaled on
- * on the first channel of the card, if both channels are
- * down. However this channel may be bound exclusive. If the
- * second channel is free, this call should be accepted.
- * The solution is horribly but it runs, so what:
- * We exchange the exclusive bindings of the two channels, the
- * corresponding variables in the interface-structs.
- */
- if (ch == 0) {
- sidx = isdn_dc2minor(di, 1);
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: ch is 0\n");
-#endif
- if (USG_NONE(dev->usage[sidx])) {
- /* Second Channel is free, now see if it is bound
- * exclusive too. */
- if (dev->usage[sidx] & ISDN_USAGE_EXCLUSIVE) {
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: 2nd channel is down and bound\n");
-#endif
- /* Yes, swap bindings only, if the original
- * binding is bound to channel 1 of this driver */
- if ((lp->pre_device == di) &&
- (lp->pre_channel == 1)) {
- isdn_net_swapbind(di);
- swapped = 1;
- } else {
- /* ... else iterate next device */
- p = (isdn_net_dev *) p->next;
- continue;
- }
- } else {
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: 2nd channel is down and unbound\n");
-#endif
- /* No, swap always and swap excl-usage also */
- isdn_net_swap_usage(idx, sidx);
- isdn_net_swapbind(di);
- swapped = 2;
- }
- /* Now check for exclusive binding again */
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: final check\n");
-#endif
- if ((dev->usage[idx] & ISDN_USAGE_EXCLUSIVE) &&
- ((lp->pre_channel != ch) ||
- (lp->pre_device != di))) {
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: final check failed\n");
-#endif
- p = (isdn_net_dev *) p->next;
- continue;
- }
- }
- } else {
- /* We are already on the second channel, so nothing to do */
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: already on 2nd channel\n");
-#endif
- }
- }
- }
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: match2\n");
-#endif
- n = lp->phone[0];
- if (lp->flags & ISDN_NET_SECURE) {
- while (n) {
- if (!isdn_msncmp(nr, n->num))
- break;
- n = (isdn_net_phone *) n->next;
- }
- }
- if (n || (!(lp->flags & ISDN_NET_SECURE))) {
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: match3\n");
-#endif
- /* matching interface found */
-
- /*
- * Is the state STOPPED?
- * If so, no dialin is allowed,
- * so reject actively.
- * */
- if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) {
- printk(KERN_INFO "incoming call, interface %s `stopped' -> rejected\n",
- p->dev->name);
- return 3;
- }
- /*
- * Is the interface up?
- * If not, reject the call actively.
- */
- if (!isdn_net_device_started(p)) {
- printk(KERN_INFO "%s: incoming call, interface down -> rejected\n",
- p->dev->name);
- return 3;
- }
- /* Interface is up, now see if it's a slave. If so, see if
- * it's master and parent slave is online. If not, reject the call.
- */
- if (lp->master) {
- isdn_net_local *mlp = ISDN_MASTER_PRIV(lp);
- printk(KERN_DEBUG "ICALLslv: %s\n", p->dev->name);
- printk(KERN_DEBUG "master=%s\n", lp->master->name);
- if (mlp->flags & ISDN_NET_CONNECTED) {
- printk(KERN_DEBUG "master online\n");
- /* Master is online, find parent-slave (master if first slave) */
- while (mlp->slave) {
- if (ISDN_SLAVE_PRIV(mlp) == lp)
- break;
- mlp = ISDN_SLAVE_PRIV(mlp);
- }
- } else
- printk(KERN_DEBUG "master offline\n");
- /* Found parent, if it's offline iterate next device */
- printk(KERN_DEBUG "mlpf: %d\n", mlp->flags & ISDN_NET_CONNECTED);
- if (!(mlp->flags & ISDN_NET_CONNECTED)) {
- p = (isdn_net_dev *) p->next;
- continue;
- }
- }
- if (lp->flags & ISDN_NET_CALLBACK) {
- int chi;
- /*
- * Is the state MANUAL?
- * If so, no callback can be made,
- * so reject actively.
- * */
- if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) {
- printk(KERN_INFO "incoming call for callback, interface %s `off' -> rejected\n",
- p->dev->name);
- return 3;
- }
- printk(KERN_DEBUG "%s: call from %s -> %s, start callback\n",
- p->dev->name, nr, eaz);
- if (lp->phone[1]) {
- /* Grab a free ISDN-Channel */
- spin_lock_irqsave(&dev->lock, flags);
- if ((chi =
- isdn_get_free_channel(
- ISDN_USAGE_NET,
- lp->l2_proto,
- lp->l3_proto,
- lp->pre_device,
- lp->pre_channel,
- lp->msn)
- ) < 0) {
-
- printk(KERN_WARNING "isdn_net_find_icall: No channel for %s\n",
- p->dev->name);
- spin_unlock_irqrestore(&dev->lock, flags);
- return 0;
- }
- /* Setup dialstate. */
- lp->dtimer = 0;
- lp->dialstate = 11;
- /* Connect interface with channel */
- isdn_net_bind_channel(lp, chi);
-#ifdef CONFIG_ISDN_PPP
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
- if (isdn_ppp_bind(lp) < 0) {
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_net_unbind_channel(lp);
- return 0;
- }
-#endif
- spin_unlock_irqrestore(&dev->lock, flags);
- /* Initiate dialing by returning 2 or 4 */
- return (lp->flags & ISDN_NET_CBHUP) ? 2 : 4;
- } else
- printk(KERN_WARNING "isdn_net: %s: No phone number\n",
- p->dev->name);
- return 0;
- } else {
- printk(KERN_DEBUG "%s: call from %s -> %s accepted\n",
- p->dev->name, nr, eaz);
- /* if this interface is dialing, it does it probably on a different
- device, so free this device */
- if ((lp->dialstate == 4) || (lp->dialstate == 12)) {
-#ifdef CONFIG_ISDN_PPP
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
- isdn_ppp_free(lp);
-#endif
- isdn_net_lp_disconnected(lp);
- isdn_free_channel(lp->isdn_device, lp->isdn_channel,
- ISDN_USAGE_NET);
- }
- spin_lock_irqsave(&dev->lock, flags);
- dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
- dev->usage[idx] |= ISDN_USAGE_NET;
- strcpy(dev->num[idx], nr);
- isdn_info_update();
- dev->st_netdev[idx] = lp->netdev;
- lp->isdn_device = di;
- lp->isdn_channel = ch;
- lp->ppp_slot = -1;
- lp->flags |= ISDN_NET_CONNECTED;
- lp->dialstate = 7;
- lp->dtimer = 0;
- lp->outgoing = 0;
- lp->huptimer = 0;
- lp->hupflags |= ISDN_WAITCHARGE;
- lp->hupflags &= ~ISDN_HAVECHARGE;
-#ifdef CONFIG_ISDN_PPP
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
- if (isdn_ppp_bind(lp) < 0) {
- isdn_net_unbind_channel(lp);
- spin_unlock_irqrestore(&dev->lock, flags);
- return 0;
- }
- }
-#endif
- spin_unlock_irqrestore(&dev->lock, flags);
- return 1;
- }
- }
- }
- p = (isdn_net_dev *) p->next;
- }
- /* If none of configured EAZ/MSN matched and not verbose, be silent */
- if (!ematch || dev->net_verbose)
- printk(KERN_INFO "isdn_net: call from %s -> %d %s ignored\n", nr, di, eaz);
- return (wret == 2) ? 5 : 0;
-}
-
-/*
- * Search list of net-interfaces for an interface with given name.
- */
-isdn_net_dev *
-isdn_net_findif(char *name)
-{
- isdn_net_dev *p = dev->netdev;
-
- while (p) {
- if (!strcmp(p->dev->name, name))
- return p;
- p = (isdn_net_dev *) p->next;
- }
- return (isdn_net_dev *) NULL;
-}
-
-/*
- * Force a net-interface to dial out.
- * This is called from the userlevel-routine below or
- * from isdn_net_start_xmit().
- */
-static int
-isdn_net_force_dial_lp(isdn_net_local *lp)
-{
- if ((!(lp->flags & ISDN_NET_CONNECTED)) && !lp->dialstate) {
- int chi;
- if (lp->phone[1]) {
- ulong flags;
-
- /* Grab a free ISDN-Channel */
- spin_lock_irqsave(&dev->lock, flags);
- if ((chi = isdn_get_free_channel(
- ISDN_USAGE_NET,
- lp->l2_proto,
- lp->l3_proto,
- lp->pre_device,
- lp->pre_channel,
- lp->msn)) < 0) {
- printk(KERN_WARNING "isdn_net_force_dial: No channel for %s\n",
- lp->netdev->dev->name);
- spin_unlock_irqrestore(&dev->lock, flags);
- return -EAGAIN;
- }
- lp->dialstate = 1;
- /* Connect interface with channel */
- isdn_net_bind_channel(lp, chi);
-#ifdef CONFIG_ISDN_PPP
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
- if (isdn_ppp_bind(lp) < 0) {
- isdn_net_unbind_channel(lp);
- spin_unlock_irqrestore(&dev->lock, flags);
- return -EAGAIN;
- }
-#endif
- /* Initiate dialing */
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_net_dial();
- return 0;
- } else
- return -EINVAL;
- } else
- return -EBUSY;
-}
-
-/*
- * This is called from certain upper protocol layers (multilink ppp
- * and x25iface encapsulation module) that want to initiate dialing
- * themselves.
- */
-int
-isdn_net_dial_req(isdn_net_local *lp)
-{
- /* is there a better error code? */
- if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) return -EBUSY;
-
- return isdn_net_force_dial_lp(lp);
-}
-
-/*
- * Force a net-interface to dial out.
- * This is always called from within userspace (ISDN_IOCTL_NET_DIAL).
- */
-int
-isdn_net_force_dial(char *name)
-{
- isdn_net_dev *p = isdn_net_findif(name);
-
- if (!p)
- return -ENODEV;
- return (isdn_net_force_dial_lp(p->local));
-}
-
-/* The ISDN-specific entries in the device structure. */
-static const struct net_device_ops isdn_netdev_ops = {
- .ndo_init = isdn_net_init,
- .ndo_open = isdn_net_open,
- .ndo_stop = isdn_net_close,
- .ndo_do_ioctl = isdn_net_ioctl,
-
- .ndo_start_xmit = isdn_net_start_xmit,
- .ndo_get_stats = isdn_net_get_stats,
- .ndo_tx_timeout = isdn_net_tx_timeout,
-};
-
-/*
- * Helper for alloc_netdev()
- */
-static void _isdn_setup(struct net_device *dev)
-{
- isdn_net_local *lp = netdev_priv(dev);
-
- ether_setup(dev);
-
- /* Setup the generic properties */
- dev->flags = IFF_NOARP | IFF_POINTOPOINT;
-
- /* isdn prepends a header in the tx path, can't share skbs */
- dev->priv_flags &= ~IFF_TX_SKB_SHARING;
- dev->header_ops = NULL;
- dev->netdev_ops = &isdn_netdev_ops;
-
- /* for clients with MPPP maybe higher values better */
- dev->tx_queue_len = 30;
-
- lp->p_encap = ISDN_NET_ENCAP_RAWIP;
- lp->magic = ISDN_NET_MAGIC;
- lp->last = lp;
- lp->next = lp;
- lp->isdn_device = -1;
- lp->isdn_channel = -1;
- lp->pre_device = -1;
- lp->pre_channel = -1;
- lp->exclusive = -1;
- lp->ppp_slot = -1;
- lp->pppbind = -1;
- skb_queue_head_init(&lp->super_tx_queue);
- lp->l2_proto = ISDN_PROTO_L2_X75I;
- lp->l3_proto = ISDN_PROTO_L3_TRANS;
- lp->triggercps = 6000;
- lp->slavedelay = 10 * HZ;
- lp->hupflags = ISDN_INHUP; /* Do hangup even on incoming calls */
- lp->onhtime = 10; /* Default hangup-time for saving costs */
- lp->dialmax = 1;
- /* Hangup before Callback, manual dial */
- lp->flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL;
- lp->cbdelay = 25; /* Wait 5 secs before Callback */
- lp->dialtimeout = -1; /* Infinite Dial-Timeout */
- lp->dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */
- lp->dialstarted = 0; /* Jiffies of last dial-start */
- lp->dialwait_timer = 0; /* Jiffies of earliest next dial-start */
-}
-
-/*
- * Allocate a new network-interface and initialize its data structures.
- */
-char *
-isdn_net_new(char *name, struct net_device *master)
-{
- isdn_net_dev *netdev;
-
- /* Avoid creating an existing interface */
- if (isdn_net_findif(name)) {
- printk(KERN_WARNING "isdn_net: interface %s already exists\n", name);
- return NULL;
- }
- if (name == NULL)
- return NULL;
- if (!(netdev = kzalloc(sizeof(isdn_net_dev), GFP_KERNEL))) {
- printk(KERN_WARNING "isdn_net: Could not allocate net-device\n");
- return NULL;
- }
- netdev->dev = alloc_netdev(sizeof(isdn_net_local), name,
- NET_NAME_UNKNOWN, _isdn_setup);
- if (!netdev->dev) {
- printk(KERN_WARNING "isdn_net: Could not allocate network device\n");
- kfree(netdev);
- return NULL;
- }
- netdev->local = netdev_priv(netdev->dev);
-
- if (master) {
- /* Device shall be a slave */
- struct net_device *p = MASTER_TO_SLAVE(master);
- struct net_device *q = master;
-
- netdev->local->master = master;
- /* Put device at end of slave-chain */
- while (p) {
- q = p;
- p = MASTER_TO_SLAVE(p);
- }
- MASTER_TO_SLAVE(q) = netdev->dev;
- } else {
- /* Device shall be a master */
- /*
- * Watchdog timer (currently) for master only.
- */
- netdev->dev->watchdog_timeo = ISDN_NET_TX_TIMEOUT;
- if (register_netdev(netdev->dev) != 0) {
- printk(KERN_WARNING "isdn_net: Could not register net-device\n");
- free_netdev(netdev->dev);
- kfree(netdev);
- return NULL;
- }
- }
- netdev->queue = netdev->local;
- spin_lock_init(&netdev->queue_lock);
-
- netdev->local->netdev = netdev;
-
- INIT_WORK(&netdev->local->tqueue, isdn_net_softint);
- spin_lock_init(&netdev->local->xmit_lock);
-
- /* Put into to netdev-chain */
- netdev->next = (void *) dev->netdev;
- dev->netdev = netdev;
- return netdev->dev->name;
-}
-
-char *
-isdn_net_newslave(char *parm)
-{
- char *p = strchr(parm, ',');
- isdn_net_dev *n;
- char newname[10];
-
- if (p) {
- /* Slave-Name MUST not be empty or overflow 'newname' */
- if (strscpy(newname, p + 1, sizeof(newname)) <= 0)
- return NULL;
- *p = 0;
- /* Master must already exist */
- if (!(n = isdn_net_findif(parm)))
- return NULL;
- /* Master must be a real interface, not a slave */
- if (n->local->master)
- return NULL;
- /* Master must not be started yet */
- if (isdn_net_device_started(n))
- return NULL;
- return (isdn_net_new(newname, n->dev));
- }
- return NULL;
-}
-
-/*
- * Set interface-parameters.
- * Always set all parameters, so the user-level application is responsible
- * for not overwriting existing setups. It has to get the current
- * setup first, if only selected parameters are to be changed.
- */
-int
-isdn_net_setcfg(isdn_net_ioctl_cfg *cfg)
-{
- isdn_net_dev *p = isdn_net_findif(cfg->name);
- ulong features;
- int i;
- int drvidx;
- int chidx;
- char drvid[25];
-
- if (p) {
- isdn_net_local *lp = p->local;
-
- /* See if any registered driver supports the features we want */
- features = ((1 << cfg->l2_proto) << ISDN_FEATURE_L2_SHIFT) |
- ((1 << cfg->l3_proto) << ISDN_FEATURE_L3_SHIFT);
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- if (dev->drv[i])
- if ((dev->drv[i]->interface->features & features) == features)
- break;
- if (i == ISDN_MAX_DRIVERS) {
- printk(KERN_WARNING "isdn_net: No driver with selected features\n");
- return -ENODEV;
- }
- if (lp->p_encap != cfg->p_encap) {
-#ifdef CONFIG_ISDN_X25
- struct concap_proto *cprot = p->cprot;
-#endif
- if (isdn_net_device_started(p)) {
- printk(KERN_WARNING "%s: cannot change encap when if is up\n",
- p->dev->name);
- return -EBUSY;
- }
-#ifdef CONFIG_ISDN_X25
- if (cprot && cprot->pops)
- cprot->pops->proto_del(cprot);
- p->cprot = NULL;
- lp->dops = NULL;
- /* ... , prepare for configuration of new one ... */
- switch (cfg->p_encap) {
- case ISDN_NET_ENCAP_X25IFACE:
- lp->dops = &isdn_concap_reliable_dl_dops;
- }
- /* ... and allocate new one ... */
- p->cprot = isdn_concap_new(cfg->p_encap);
- /* p -> cprot == NULL now if p_encap is not supported
- by means of the concap_proto mechanism */
- /* the protocol is not configured yet; this will
- happen later when isdn_net_reset() is called */
-#endif
- }
- switch (cfg->p_encap) {
- case ISDN_NET_ENCAP_SYNCPPP:
-#ifndef CONFIG_ISDN_PPP
- printk(KERN_WARNING "%s: SyncPPP support not configured\n",
- p->dev->name);
- return -EINVAL;
-#else
- p->dev->type = ARPHRD_PPP; /* change ARP type */
- p->dev->addr_len = 0;
-#endif
- break;
- case ISDN_NET_ENCAP_X25IFACE:
-#ifndef CONFIG_ISDN_X25
- printk(KERN_WARNING "%s: isdn-x25 support not configured\n",
- p->dev->name);
- return -EINVAL;
-#else
- p->dev->type = ARPHRD_X25; /* change ARP type */
- p->dev->addr_len = 0;
-#endif
- break;
- case ISDN_NET_ENCAP_CISCOHDLCK:
- break;
- default:
- if (cfg->p_encap >= 0 &&
- cfg->p_encap <= ISDN_NET_ENCAP_MAX_ENCAP)
- break;
- printk(KERN_WARNING
- "%s: encapsulation protocol %d not supported\n",
- p->dev->name, cfg->p_encap);
- return -EINVAL;
- }
- if (strlen(cfg->drvid)) {
- /* A bind has been requested ... */
- char *c,
- *e;
-
- if (strnlen(cfg->drvid, sizeof(cfg->drvid)) ==
- sizeof(cfg->drvid))
- return -EINVAL;
- drvidx = -1;
- chidx = -1;
- strcpy(drvid, cfg->drvid);
- if ((c = strchr(drvid, ','))) {
- /* The channel-number is appended to the driver-Id with a comma */
- chidx = (int) simple_strtoul(c + 1, &e, 10);
- if (e == c)
- chidx = -1;
- *c = '\0';
- }
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- /* Lookup driver-Id in array */
- if (!(strcmp(dev->drvid[i], drvid))) {
- drvidx = i;
- break;
- }
- if ((drvidx == -1) || (chidx == -1))
- /* Either driver-Id or channel-number invalid */
- return -ENODEV;
- } else {
- /* Parameters are valid, so get them */
- drvidx = lp->pre_device;
- chidx = lp->pre_channel;
- }
- if (cfg->exclusive > 0) {
- unsigned long flags;
-
- /* If binding is exclusive, try to grab the channel */
- spin_lock_irqsave(&dev->lock, flags);
- if ((i = isdn_get_free_channel(ISDN_USAGE_NET,
- lp->l2_proto, lp->l3_proto, drvidx,
- chidx, lp->msn)) < 0) {
- /* Grab failed, because desired channel is in use */
- lp->exclusive = -1;
- spin_unlock_irqrestore(&dev->lock, flags);
- return -EBUSY;
- }
- /* All went ok, so update isdninfo */
- dev->usage[i] = ISDN_USAGE_EXCLUSIVE;
- isdn_info_update();
- spin_unlock_irqrestore(&dev->lock, flags);
- lp->exclusive = i;
- } else {
- /* Non-exclusive binding or unbind. */
- lp->exclusive = -1;
- if ((lp->pre_device != -1) && (cfg->exclusive == -1)) {
- isdn_unexclusive_channel(lp->pre_device, lp->pre_channel);
- isdn_free_channel(lp->pre_device, lp->pre_channel, ISDN_USAGE_NET);
- drvidx = -1;
- chidx = -1;
- }
- }
- strlcpy(lp->msn, cfg->eaz, sizeof(lp->msn));
- lp->pre_device = drvidx;
- lp->pre_channel = chidx;
- lp->onhtime = cfg->onhtime;
- lp->charge = cfg->charge;
- lp->l2_proto = cfg->l2_proto;
- lp->l3_proto = cfg->l3_proto;
- lp->cbdelay = cfg->cbdelay;
- lp->dialmax = cfg->dialmax;
- lp->triggercps = cfg->triggercps;
- lp->slavedelay = cfg->slavedelay * HZ;
- lp->pppbind = cfg->pppbind;
- lp->dialtimeout = cfg->dialtimeout >= 0 ? cfg->dialtimeout * HZ : -1;
- lp->dialwait = cfg->dialwait * HZ;
- if (cfg->secure)
- lp->flags |= ISDN_NET_SECURE;
- else
- lp->flags &= ~ISDN_NET_SECURE;
- if (cfg->cbhup)
- lp->flags |= ISDN_NET_CBHUP;
- else
- lp->flags &= ~ISDN_NET_CBHUP;
- switch (cfg->callback) {
- case 0:
- lp->flags &= ~(ISDN_NET_CALLBACK | ISDN_NET_CBOUT);
- break;
- case 1:
- lp->flags |= ISDN_NET_CALLBACK;
- lp->flags &= ~ISDN_NET_CBOUT;
- break;
- case 2:
- lp->flags |= ISDN_NET_CBOUT;
- lp->flags &= ~ISDN_NET_CALLBACK;
- break;
- }
- lp->flags &= ~ISDN_NET_DIALMODE_MASK; /* first all bits off */
- if (cfg->dialmode && !(cfg->dialmode & ISDN_NET_DIALMODE_MASK)) {
- /* old isdnctrl version, where only 0 or 1 is given */
- printk(KERN_WARNING
- "Old isdnctrl version detected! Please update.\n");
- lp->flags |= ISDN_NET_DM_OFF; /* turn on `off' bit */
- }
- else {
- lp->flags |= cfg->dialmode; /* turn on selected bits */
- }
- if (cfg->chargehup)
- lp->hupflags |= ISDN_CHARGEHUP;
- else
- lp->hupflags &= ~ISDN_CHARGEHUP;
- if (cfg->ihup)
- lp->hupflags |= ISDN_INHUP;
- else
- lp->hupflags &= ~ISDN_INHUP;
- if (cfg->chargeint > 10) {
- lp->hupflags |= ISDN_CHARGEHUP | ISDN_HAVECHARGE | ISDN_MANCHARGE;
- lp->chargeint = cfg->chargeint * HZ;
- }
- if (cfg->p_encap != lp->p_encap) {
- if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) {
- p->dev->header_ops = NULL;
- p->dev->flags = IFF_NOARP | IFF_POINTOPOINT;
- } else {
- p->dev->header_ops = &isdn_header_ops;
- if (cfg->p_encap == ISDN_NET_ENCAP_ETHER)
- p->dev->flags = IFF_BROADCAST | IFF_MULTICAST;
- else
- p->dev->flags = IFF_NOARP | IFF_POINTOPOINT;
- }
- }
- lp->p_encap = cfg->p_encap;
- return 0;
- }
- return -ENODEV;
-}
-
-/*
- * Perform get-interface-parameters.ioctl
- */
-int
-isdn_net_getcfg(isdn_net_ioctl_cfg *cfg)
-{
- isdn_net_dev *p = isdn_net_findif(cfg->name);
-
- if (p) {
- isdn_net_local *lp = p->local;
-
- strcpy(cfg->eaz, lp->msn);
- cfg->exclusive = lp->exclusive;
- if (lp->pre_device >= 0) {
- sprintf(cfg->drvid, "%s,%d", dev->drvid[lp->pre_device],
- lp->pre_channel);
- } else
- cfg->drvid[0] = '\0';
- cfg->onhtime = lp->onhtime;
- cfg->charge = lp->charge;
- cfg->l2_proto = lp->l2_proto;
- cfg->l3_proto = lp->l3_proto;
- cfg->p_encap = lp->p_encap;
- cfg->secure = (lp->flags & ISDN_NET_SECURE) ? 1 : 0;
- cfg->callback = 0;
- if (lp->flags & ISDN_NET_CALLBACK)
- cfg->callback = 1;
- if (lp->flags & ISDN_NET_CBOUT)
- cfg->callback = 2;
- cfg->cbhup = (lp->flags & ISDN_NET_CBHUP) ? 1 : 0;
- cfg->dialmode = lp->flags & ISDN_NET_DIALMODE_MASK;
- cfg->chargehup = (lp->hupflags & ISDN_CHARGEHUP) ? 1 : 0;
- cfg->ihup = (lp->hupflags & ISDN_INHUP) ? 1 : 0;
- cfg->cbdelay = lp->cbdelay;
- cfg->dialmax = lp->dialmax;
- cfg->triggercps = lp->triggercps;
- cfg->slavedelay = lp->slavedelay / HZ;
- cfg->chargeint = (lp->hupflags & ISDN_CHARGEHUP) ?
- (lp->chargeint / HZ) : 0;
- cfg->pppbind = lp->pppbind;
- cfg->dialtimeout = lp->dialtimeout >= 0 ? lp->dialtimeout / HZ : -1;
- cfg->dialwait = lp->dialwait / HZ;
- if (lp->slave) {
- if (strlen(lp->slave->name) >= 10)
- strcpy(cfg->slave, "too-long");
- else
- strcpy(cfg->slave, lp->slave->name);
- } else
- cfg->slave[0] = '\0';
- if (lp->master) {
- if (strlen(lp->master->name) >= 10)
- strcpy(cfg->master, "too-long");
- else
- strcpy(cfg->master, lp->master->name);
- } else
- cfg->master[0] = '\0';
- return 0;
- }
- return -ENODEV;
-}
-
-/*
- * Add a phone-number to an interface.
- */
-int
-isdn_net_addphone(isdn_net_ioctl_phone *phone)
-{
- isdn_net_dev *p = isdn_net_findif(phone->name);
- isdn_net_phone *n;
-
- if (p) {
- if (!(n = kmalloc(sizeof(isdn_net_phone), GFP_KERNEL)))
- return -ENOMEM;
- strlcpy(n->num, phone->phone, sizeof(n->num));
- n->next = p->local->phone[phone->outgoing & 1];
- p->local->phone[phone->outgoing & 1] = n;
- return 0;
- }
- return -ENODEV;
-}
-
-/*
- * Copy a string of all phone-numbers of an interface to user space.
- * This might sleep and must be called with the isdn semaphore down.
- */
-int
-isdn_net_getphones(isdn_net_ioctl_phone *phone, char __user *phones)
-{
- isdn_net_dev *p = isdn_net_findif(phone->name);
- int inout = phone->outgoing & 1;
- int more = 0;
- int count = 0;
- isdn_net_phone *n;
-
- if (!p)
- return -ENODEV;
- inout &= 1;
- for (n = p->local->phone[inout]; n; n = n->next) {
- if (more) {
- put_user(' ', phones++);
- count++;
- }
- if (copy_to_user(phones, n->num, strlen(n->num) + 1)) {
- return -EFAULT;
- }
- phones += strlen(n->num);
- count += strlen(n->num);
- more = 1;
- }
- put_user(0, phones);
- count++;
- return count;
-}
-
-/*
- * Copy a string containing the peer's phone number of a connected interface
- * to user space.
- */
-int
-isdn_net_getpeer(isdn_net_ioctl_phone *phone, isdn_net_ioctl_phone __user *peer)
-{
- isdn_net_dev *p = isdn_net_findif(phone->name);
- int ch, dv, idx;
-
- if (!p)
- return -ENODEV;
- /*
- * Theoretical race: while this executes, the remote number might
- * become invalid (hang up) or change (new connection), resulting
- * in (partially) wrong number copied to user. This race
- * currently ignored.
- */
- ch = p->local->isdn_channel;
- dv = p->local->isdn_device;
- if (ch < 0 && dv < 0)
- return -ENOTCONN;
- idx = isdn_dc2minor(dv, ch);
- if (idx < 0)
- return -ENODEV;
- /* for pre-bound channels, we need this extra check */
- if (strncmp(dev->num[idx], "???", 3) == 0)
- return -ENOTCONN;
- strncpy(phone->phone, dev->num[idx], ISDN_MSNLEN);
- phone->outgoing = USG_OUTGOING(dev->usage[idx]);
- if (copy_to_user(peer, phone, sizeof(*peer)))
- return -EFAULT;
- return 0;
-}
-/*
- * Delete a phone-number from an interface.
- */
-int
-isdn_net_delphone(isdn_net_ioctl_phone *phone)
-{
- isdn_net_dev *p = isdn_net_findif(phone->name);
- int inout = phone->outgoing & 1;
- isdn_net_phone *n;
- isdn_net_phone *m;
-
- if (p) {
- n = p->local->phone[inout];
- m = NULL;
- while (n) {
- if (!strcmp(n->num, phone->phone)) {
- if (p->local->dial == n)
- p->local->dial = n->next;
- if (m)
- m->next = n->next;
- else
- p->local->phone[inout] = n->next;
- kfree(n);
- return 0;
- }
- m = n;
- n = (isdn_net_phone *) n->next;
- }
- return -EINVAL;
- }
- return -ENODEV;
-}
-
-/*
- * Delete all phone-numbers of an interface.
- */
-static int
-isdn_net_rmallphone(isdn_net_dev *p)
-{
- isdn_net_phone *n;
- isdn_net_phone *m;
- int i;
-
- for (i = 0; i < 2; i++) {
- n = p->local->phone[i];
- while (n) {
- m = n->next;
- kfree(n);
- n = m;
- }
- p->local->phone[i] = NULL;
- }
- p->local->dial = NULL;
- return 0;
-}
-
-/*
- * Force a hangup of a network-interface.
- */
-int
-isdn_net_force_hangup(char *name)
-{
- isdn_net_dev *p = isdn_net_findif(name);
- struct net_device *q;
-
- if (p) {
- if (p->local->isdn_device < 0)
- return 1;
- q = p->local->slave;
- /* If this interface has slaves, do a hangup for them also. */
- while (q) {
- isdn_net_hangup(q);
- q = MASTER_TO_SLAVE(q);
- }
- isdn_net_hangup(p->dev);
- return 0;
- }
- return -ENODEV;
-}
-
-/*
- * Helper-function for isdn_net_rm: Do the real work.
- */
-static int
-isdn_net_realrm(isdn_net_dev *p, isdn_net_dev *q)
-{
- u_long flags;
-
- if (isdn_net_device_started(p)) {
- return -EBUSY;
- }
-#ifdef CONFIG_ISDN_X25
- if (p->cprot && p->cprot->pops)
- p->cprot->pops->proto_del(p->cprot);
-#endif
- /* Free all phone-entries */
- isdn_net_rmallphone(p);
- /* If interface is bound exclusive, free channel-usage */
- if (p->local->exclusive != -1)
- isdn_unexclusive_channel(p->local->pre_device, p->local->pre_channel);
- if (p->local->master) {
- /* It's a slave-device, so update master's slave-pointer if necessary */
- if (((isdn_net_local *) ISDN_MASTER_PRIV(p->local))->slave ==
- p->dev)
- ((isdn_net_local *)ISDN_MASTER_PRIV(p->local))->slave =
- p->local->slave;
- } else {
- /* Unregister only if it's a master-device */
- unregister_netdev(p->dev);
- }
- /* Unlink device from chain */
- spin_lock_irqsave(&dev->lock, flags);
- if (q)
- q->next = p->next;
- else
- dev->netdev = p->next;
- if (p->local->slave) {
- /* If this interface has a slave, remove it also */
- char *slavename = p->local->slave->name;
- isdn_net_dev *n = dev->netdev;
- q = NULL;
- while (n) {
- if (!strcmp(n->dev->name, slavename)) {
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_net_realrm(n, q);
- spin_lock_irqsave(&dev->lock, flags);
- break;
- }
- q = n;
- n = (isdn_net_dev *)n->next;
- }
- }
- spin_unlock_irqrestore(&dev->lock, flags);
- /* If no more net-devices remain, disable auto-hangup timer */
- if (dev->netdev == NULL)
- isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0);
- free_netdev(p->dev);
- kfree(p);
-
- return 0;
-}
-
-/*
- * Remove a single network-interface.
- */
-int
-isdn_net_rm(char *name)
-{
- u_long flags;
- isdn_net_dev *p;
- isdn_net_dev *q;
-
- /* Search name in netdev-chain */
- spin_lock_irqsave(&dev->lock, flags);
- p = dev->netdev;
- q = NULL;
- while (p) {
- if (!strcmp(p->dev->name, name)) {
- spin_unlock_irqrestore(&dev->lock, flags);
- return (isdn_net_realrm(p, q));
- }
- q = p;
- p = (isdn_net_dev *) p->next;
- }
- spin_unlock_irqrestore(&dev->lock, flags);
- /* If no more net-devices remain, disable auto-hangup timer */
- if (dev->netdev == NULL)
- isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0);
- return -ENODEV;
-}
-
-/*
- * Remove all network-interfaces
- */
-int
-isdn_net_rmall(void)
-{
- u_long flags;
- int ret;
-
- /* Walk through netdev-chain */
- spin_lock_irqsave(&dev->lock, flags);
- while (dev->netdev) {
- if (!dev->netdev->local->master) {
- /* Remove master-devices only, slaves get removed with their master */
- spin_unlock_irqrestore(&dev->lock, flags);
- if ((ret = isdn_net_realrm(dev->netdev, NULL))) {
- return ret;
- }
- spin_lock_irqsave(&dev->lock, flags);
- }
- }
- dev->netdev = NULL;
- spin_unlock_irqrestore(&dev->lock, flags);
- return 0;
-}
diff --git a/drivers/isdn/i4l/isdn_net.h b/drivers/isdn/i4l/isdn_net.h
deleted file mode 100644
index cca6d68da171..000000000000
--- a/drivers/isdn/i4l/isdn_net.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/* $Id: isdn_net.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * header for Linux ISDN subsystem, network related functions (linklevel).
- *
- * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
- * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-/* Definitions for hupflags: */
-#define ISDN_WAITCHARGE 1 /* did not get a charge info yet */
-#define ISDN_HAVECHARGE 2 /* We know a charge info */
-#define ISDN_CHARGEHUP 4 /* We want to use the charge mechanism */
-#define ISDN_INHUP 8 /* Even if incoming, close after huptimeout */
-#define ISDN_MANCHARGE 16 /* Charge Interval manually set */
-
-/*
- * Definitions for Cisco-HDLC header.
- */
-
-#define CISCO_ADDR_UNICAST 0x0f
-#define CISCO_ADDR_BROADCAST 0x8f
-#define CISCO_CTRL 0x00
-#define CISCO_TYPE_CDP 0x2000
-#define CISCO_TYPE_SLARP 0x8035
-#define CISCO_SLARP_REQUEST 0
-#define CISCO_SLARP_REPLY 1
-#define CISCO_SLARP_KEEPALIVE 2
-
-extern char *isdn_net_new(char *, struct net_device *);
-extern char *isdn_net_newslave(char *);
-extern int isdn_net_rm(char *);
-extern int isdn_net_rmall(void);
-extern int isdn_net_stat_callback(int, isdn_ctrl *);
-extern int isdn_net_setcfg(isdn_net_ioctl_cfg *);
-extern int isdn_net_getcfg(isdn_net_ioctl_cfg *);
-extern int isdn_net_addphone(isdn_net_ioctl_phone *);
-extern int isdn_net_getphones(isdn_net_ioctl_phone *, char __user *);
-extern int isdn_net_getpeer(isdn_net_ioctl_phone *, isdn_net_ioctl_phone __user *);
-extern int isdn_net_delphone(isdn_net_ioctl_phone *);
-extern int isdn_net_find_icall(int, int, int, setup_parm *);
-extern void isdn_net_hangup(struct net_device *);
-extern void isdn_net_dial(void);
-extern void isdn_net_autohup(void);
-extern int isdn_net_force_hangup(char *);
-extern int isdn_net_force_dial(char *);
-extern isdn_net_dev *isdn_net_findif(char *);
-extern int isdn_net_rcv_skb(int, struct sk_buff *);
-extern int isdn_net_dial_req(isdn_net_local *);
-extern void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb);
-extern void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb);
-
-#define ISDN_NET_MAX_QUEUE_LENGTH 2
-
-#define ISDN_MASTER_PRIV(lp) ((isdn_net_local *) netdev_priv(lp->master))
-#define ISDN_SLAVE_PRIV(lp) ((isdn_net_local *) netdev_priv(lp->slave))
-#define MASTER_TO_SLAVE(master) \
- (((isdn_net_local *) netdev_priv(master))->slave)
-
-/*
- * is this particular channel busy?
- */
-static __inline__ int isdn_net_lp_busy(isdn_net_local *lp)
-{
- if (atomic_read(&lp->frame_cnt) < ISDN_NET_MAX_QUEUE_LENGTH)
- return 0;
- else
- return 1;
-}
-
-/*
- * For the given net device, this will get a non-busy channel out of the
- * corresponding bundle. The returned channel is locked.
- */
-static __inline__ isdn_net_local *isdn_net_get_locked_lp(isdn_net_dev *nd)
-{
- unsigned long flags;
- isdn_net_local *lp;
-
- spin_lock_irqsave(&nd->queue_lock, flags);
- lp = nd->queue; /* get lp on top of queue */
- while (isdn_net_lp_busy(nd->queue)) {
- nd->queue = nd->queue->next;
- if (nd->queue == lp) { /* not found -- should never happen */
- lp = NULL;
- goto errout;
- }
- }
- lp = nd->queue;
- nd->queue = nd->queue->next;
- spin_unlock_irqrestore(&nd->queue_lock, flags);
- spin_lock(&lp->xmit_lock);
- local_bh_disable();
- return lp;
-errout:
- spin_unlock_irqrestore(&nd->queue_lock, flags);
- return lp;
-}
-
-/*
- * add a channel to a bundle
- */
-static __inline__ void isdn_net_add_to_bundle(isdn_net_dev *nd, isdn_net_local *nlp)
-{
- isdn_net_local *lp;
- unsigned long flags;
-
- spin_lock_irqsave(&nd->queue_lock, flags);
-
- lp = nd->queue;
-// printk(KERN_DEBUG "%s: lp:%s(%p) nlp:%s(%p) last(%p)\n",
-// __func__, lp->name, lp, nlp->name, nlp, lp->last);
- nlp->last = lp->last;
- lp->last->next = nlp;
- lp->last = nlp;
- nlp->next = lp;
- nd->queue = nlp;
-
- spin_unlock_irqrestore(&nd->queue_lock, flags);
-}
-/*
- * remove a channel from the bundle it belongs to
- */
-static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp)
-{
- isdn_net_local *master_lp = lp;
- unsigned long flags;
-
- if (lp->master)
- master_lp = ISDN_MASTER_PRIV(lp);
-
-// printk(KERN_DEBUG "%s: lp:%s(%p) mlp:%s(%p) last(%p) next(%p) mndq(%p)\n",
-// __func__, lp->name, lp, master_lp->name, master_lp, lp->last, lp->next, master_lp->netdev->queue);
- spin_lock_irqsave(&master_lp->netdev->queue_lock, flags);
- lp->last->next = lp->next;
- lp->next->last = lp->last;
- if (master_lp->netdev->queue == lp) {
- master_lp->netdev->queue = lp->next;
- if (lp->next == lp) { /* last in queue */
- master_lp->netdev->queue = master_lp->netdev->local;
- }
- }
- lp->next = lp->last = lp; /* (re)set own pointers */
-// printk(KERN_DEBUG "%s: mndq(%p)\n",
-// __func__, master_lp->netdev->queue);
- spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags);
-}
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
deleted file mode 100644
index 7e0f419c14f8..000000000000
--- a/drivers/isdn/i4l/isdn_ppp.c
+++ /dev/null
@@ -1,3046 +0,0 @@
-/* $Id: isdn_ppp.c,v 1.1.2.3 2004/02/10 01:07:13 keil Exp $
- *
- * Linux ISDN subsystem, functions for synchronous PPP (linklevel).
- *
- * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/isdn.h>
-#include <linux/poll.h>
-#include <linux/ppp-comp.h>
-#include <linux/slab.h>
-#ifdef CONFIG_IPPP_FILTER
-#include <linux/filter.h>
-#endif
-
-#include "isdn_common.h"
-#include "isdn_ppp.h"
-#include "isdn_net.h"
-
-#ifndef PPP_IPX
-#define PPP_IPX 0x002b
-#endif
-
-/* Prototypes */
-static int isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot);
-static int isdn_ppp_closewait(int slot);
-static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp,
- struct sk_buff *skb, int proto);
-static int isdn_ppp_if_get_unit(char *namebuf);
-static int isdn_ppp_set_compressor(struct ippp_struct *is, struct isdn_ppp_comp_data *);
-static struct sk_buff *isdn_ppp_decompress(struct sk_buff *,
- struct ippp_struct *, struct ippp_struct *, int *proto);
-static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
- struct sk_buff *skb, int proto);
-static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in, int *proto,
- struct ippp_struct *is, struct ippp_struct *master, int type);
-static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
- struct sk_buff *skb);
-
-/* New CCP stuff */
-static void isdn_ppp_ccp_kickup(struct ippp_struct *is);
-static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
- unsigned char code, unsigned char id,
- unsigned char *data, int len);
-static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is);
-static void isdn_ppp_ccp_reset_free(struct ippp_struct *is);
-static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is,
- unsigned char id);
-static void isdn_ppp_ccp_timer_callback(struct timer_list *t);
-static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is,
- unsigned char id);
-static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is,
- struct isdn_ppp_resetparams *rp);
-static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is,
- unsigned char id);
-
-
-
-#ifdef CONFIG_ISDN_MPP
-static ippp_bundle *isdn_ppp_bundle_arr = NULL;
-
-static int isdn_ppp_mp_bundle_array_init(void);
-static int isdn_ppp_mp_init(isdn_net_local *lp, ippp_bundle *add_to);
-static void isdn_ppp_mp_receive(isdn_net_dev *net_dev, isdn_net_local *lp,
- struct sk_buff *skb);
-static void isdn_ppp_mp_cleanup(isdn_net_local *lp);
-
-static int isdn_ppp_bundle(struct ippp_struct *, int unit);
-#endif /* CONFIG_ISDN_MPP */
-
-char *isdn_ppp_revision = "$Revision: 1.1.2.3 $";
-
-static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
-
-static struct isdn_ppp_compressor *ipc_head = NULL;
-
-/*
- * frame log (debug)
- */
-static void
-isdn_ppp_frame_log(char *info, char *data, int len, int maxlen, int unit, int slot)
-{
- int cnt,
- j,
- i;
- char buf[80];
-
- if (len < maxlen)
- maxlen = len;
-
- for (i = 0, cnt = 0; cnt < maxlen; i++) {
- for (j = 0; j < 16 && cnt < maxlen; j++, cnt++)
- sprintf(buf + j * 3, "%02x ", (unsigned char)data[cnt]);
- printk(KERN_DEBUG "[%d/%d].%s[%d]: %s\n", unit, slot, info, i, buf);
- }
-}
-
-/*
- * unbind isdn_net_local <=> ippp-device
- * note: it can happen, that we hangup/free the master before the slaves
- * in this case we bind another lp to the master device
- */
-int
-isdn_ppp_free(isdn_net_local *lp)
-{
- struct ippp_struct *is;
-
- if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",
- __func__, lp->ppp_slot);
- return 0;
- }
-
-#ifdef CONFIG_ISDN_MPP
- spin_lock(&lp->netdev->pb->lock);
-#endif
- isdn_net_rm_from_bundle(lp);
-#ifdef CONFIG_ISDN_MPP
- if (lp->netdev->pb->ref_ct == 1) /* last link in queue? */
- isdn_ppp_mp_cleanup(lp);
-
- lp->netdev->pb->ref_ct--;
- spin_unlock(&lp->netdev->pb->lock);
-#endif /* CONFIG_ISDN_MPP */
- if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: ppp_slot(%d) now invalid\n",
- __func__, lp->ppp_slot);
- return 0;
- }
- is = ippp_table[lp->ppp_slot];
- if ((is->state & IPPP_CONNECT))
- isdn_ppp_closewait(lp->ppp_slot); /* force wakeup on ippp device */
- else if (is->state & IPPP_ASSIGNED)
- is->state = IPPP_OPEN; /* fallback to 'OPEN but not ASSIGNED' state */
-
- if (is->debug & 0x1)
- printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_slot, (long) lp, (long) is->lp);
-
- is->lp = NULL; /* link is down .. set lp to NULL */
- lp->ppp_slot = -1; /* is this OK ?? */
-
- return 0;
-}
-
-/*
- * bind isdn_net_local <=> ippp-device
- *
- * This function is allways called with holding dev->lock so
- * no additional lock is needed
- */
-int
-isdn_ppp_bind(isdn_net_local *lp)
-{
- int i;
- int unit = 0;
- struct ippp_struct *is;
- int retval;
-
- if (lp->pppbind < 0) { /* device bounded to ippp device ? */
- isdn_net_dev *net_dev = dev->netdev;
- char exclusive[ISDN_MAX_CHANNELS]; /* exclusive flags */
- memset(exclusive, 0, ISDN_MAX_CHANNELS);
- while (net_dev) { /* step through net devices to find exclusive minors */
- isdn_net_local *lp = net_dev->local;
- if (lp->pppbind >= 0)
- exclusive[lp->pppbind] = 1;
- net_dev = net_dev->next;
- }
- /*
- * search a free device / slot
- */
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if (ippp_table[i]->state == IPPP_OPEN && !exclusive[ippp_table[i]->minor]) { /* OPEN, but not connected! */
- break;
- }
- }
- } else {
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if (ippp_table[i]->minor == lp->pppbind &&
- (ippp_table[i]->state & IPPP_OPEN) == IPPP_OPEN)
- break;
- }
- }
-
- if (i >= ISDN_MAX_CHANNELS) {
- printk(KERN_WARNING "isdn_ppp_bind: Can't find a (free) connection to the ipppd daemon.\n");
- retval = -1;
- goto out;
- }
- /* get unit number from interface name .. ugly! */
- unit = isdn_ppp_if_get_unit(lp->netdev->dev->name);
- if (unit < 0) {
- printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n",
- lp->netdev->dev->name);
- retval = -1;
- goto out;
- }
-
- lp->ppp_slot = i;
- is = ippp_table[i];
- is->lp = lp;
- is->unit = unit;
- is->state = IPPP_OPEN | IPPP_ASSIGNED; /* assigned to a netdevice but not connected */
-#ifdef CONFIG_ISDN_MPP
- retval = isdn_ppp_mp_init(lp, NULL);
- if (retval < 0)
- goto out;
-#endif /* CONFIG_ISDN_MPP */
-
- retval = lp->ppp_slot;
-
-out:
- return retval;
-}
-
-/*
- * kick the ipppd on the device
- * (wakes up daemon after B-channel connect)
- */
-
-void
-isdn_ppp_wakeup_daemon(isdn_net_local *lp)
-{
- if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",
- __func__, lp->ppp_slot);
- return;
- }
- ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK;
- wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq);
-}
-
-/*
- * there was a hangup on the netdevice
- * force wakeup of the ippp device
- * go into 'device waits for release' state
- */
-static int
-isdn_ppp_closewait(int slot)
-{
- struct ippp_struct *is;
-
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: slot(%d) out of range\n",
- __func__, slot);
- return 0;
- }
- is = ippp_table[slot];
- if (is->state)
- wake_up_interruptible(&is->wq);
- is->state = IPPP_CLOSEWAIT;
- return 1;
-}
-
-/*
- * isdn_ppp_find_slot / isdn_ppp_free_slot
- */
-
-static int
-isdn_ppp_get_slot(void)
-{
- int i;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if (!ippp_table[i]->state)
- return i;
- }
- return -1;
-}
-
-/*
- * isdn_ppp_open
- */
-
-int
-isdn_ppp_open(int min, struct file *file)
-{
- int slot;
- struct ippp_struct *is;
-
- if (min < 0 || min >= ISDN_MAX_CHANNELS)
- return -ENODEV;
-
- slot = isdn_ppp_get_slot();
- if (slot < 0) {
- return -EBUSY;
- }
- is = file->private_data = ippp_table[slot];
-
- printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n",
- slot, min, is->state);
-
- /* compression stuff */
- is->link_compressor = is->compressor = NULL;
- is->link_decompressor = is->decompressor = NULL;
- is->link_comp_stat = is->comp_stat = NULL;
- is->link_decomp_stat = is->decomp_stat = NULL;
- is->compflags = 0;
-
- is->reset = isdn_ppp_ccp_reset_alloc(is);
- if (!is->reset)
- return -ENOMEM;
-
- is->lp = NULL;
- is->mp_seqno = 0; /* MP sequence number */
- is->pppcfg = 0; /* ppp configuration */
- is->mpppcfg = 0; /* mppp configuration */
- is->last_link_seqno = -1; /* MP: maybe set to Bundle-MIN, when joining a bundle ?? */
- is->unit = -1; /* set, when we have our interface */
- is->mru = 1524; /* MRU, default 1524 */
- is->maxcid = 16; /* VJ: maxcid */
- is->tk = current;
- init_waitqueue_head(&is->wq);
- is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
- is->last = is->rq;
- is->minor = min;
-#ifdef CONFIG_ISDN_PPP_VJ
- /*
- * VJ header compression init
- */
- is->slcomp = slhc_init(16, 16); /* not necessary for 2. link in bundle */
- if (IS_ERR(is->slcomp)) {
- isdn_ppp_ccp_reset_free(is);
- return PTR_ERR(is->slcomp);
- }
-#endif
-#ifdef CONFIG_IPPP_FILTER
- is->pass_filter = NULL;
- is->active_filter = NULL;
-#endif
- is->state = IPPP_OPEN;
-
- return 0;
-}
-
-/*
- * release ippp device
- */
-void
-isdn_ppp_release(int min, struct file *file)
-{
- int i;
- struct ippp_struct *is;
-
- if (min < 0 || min >= ISDN_MAX_CHANNELS)
- return;
- is = file->private_data;
-
- if (!is) {
- printk(KERN_ERR "%s: no file->private_data\n", __func__);
- return;
- }
- if (is->debug & 0x1)
- printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", min, (long) is->lp);
-
- if (is->lp) { /* a lp address says: this link is still up */
- isdn_net_dev *p = is->lp->netdev;
-
- if (!p) {
- printk(KERN_ERR "%s: no lp->netdev\n", __func__);
- return;
- }
- is->state &= ~IPPP_CONNECT; /* -> effect: no call of wakeup */
- /*
- * isdn_net_hangup() calls isdn_ppp_free()
- * isdn_ppp_free() sets is->lp to NULL and lp->ppp_slot to -1
- * removing the IPPP_CONNECT flag omits calling of isdn_ppp_wakeup_daemon()
- */
- isdn_net_hangup(p->dev);
- }
- for (i = 0; i < NUM_RCV_BUFFS; i++) {
- kfree(is->rq[i].buf);
- is->rq[i].buf = NULL;
- }
- is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
- is->last = is->rq;
-
-#ifdef CONFIG_ISDN_PPP_VJ
-/* TODO: if this was the previous master: link the slcomp to the new master */
- slhc_free(is->slcomp);
- is->slcomp = NULL;
-#endif
-#ifdef CONFIG_IPPP_FILTER
- if (is->pass_filter) {
- bpf_prog_destroy(is->pass_filter);
- is->pass_filter = NULL;
- }
-
- if (is->active_filter) {
- bpf_prog_destroy(is->active_filter);
- is->active_filter = NULL;
- }
-#endif
-
-/* TODO: if this was the previous master: link the stuff to the new master */
- if (is->comp_stat)
- is->compressor->free(is->comp_stat);
- if (is->link_comp_stat)
- is->link_compressor->free(is->link_comp_stat);
- if (is->link_decomp_stat)
- is->link_decompressor->free(is->link_decomp_stat);
- if (is->decomp_stat)
- is->decompressor->free(is->decomp_stat);
- is->compressor = is->link_compressor = NULL;
- is->decompressor = is->link_decompressor = NULL;
- is->comp_stat = is->link_comp_stat = NULL;
- is->decomp_stat = is->link_decomp_stat = NULL;
-
- /* Clean up if necessary */
- if (is->reset)
- isdn_ppp_ccp_reset_free(is);
-
- /* this slot is ready for new connections */
- is->state = 0;
-}
-
-/*
- * get_arg .. ioctl helper
- */
-static int
-get_arg(void __user *b, void *val, int len)
-{
- if (len <= 0)
- len = sizeof(void *);
- if (copy_from_user(val, b, len))
- return -EFAULT;
- return 0;
-}
-
-/*
- * set arg .. ioctl helper
- */
-static int
-set_arg(void __user *b, void *val, int len)
-{
- if (len <= 0)
- len = sizeof(void *);
- if (copy_to_user(b, val, len))
- return -EFAULT;
- return 0;
-}
-
-#ifdef CONFIG_IPPP_FILTER
-static int get_filter(void __user *arg, struct sock_filter **p)
-{
- struct sock_fprog uprog;
- struct sock_filter *code = NULL;
- int len;
-
- if (copy_from_user(&uprog, arg, sizeof(uprog)))
- return -EFAULT;
-
- if (!uprog.len) {
- *p = NULL;
- return 0;
- }
-
- /* uprog.len is unsigned short, so no overflow here */
- len = uprog.len * sizeof(struct sock_filter);
- code = memdup_user(uprog.filter, len);
- if (IS_ERR(code))
- return PTR_ERR(code);
-
- *p = code;
- return uprog.len;
-}
-#endif /* CONFIG_IPPP_FILTER */
-
-/*
- * ippp device ioctl
- */
-int
-isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
-{
- unsigned long val;
- int r, i, j;
- struct ippp_struct *is;
- isdn_net_local *lp;
- struct isdn_ppp_comp_data data;
- void __user *argp = (void __user *)arg;
-
- is = file->private_data;
- lp = is->lp;
-
- if (is->debug & 0x1)
- printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", min, cmd, is->state);
-
- if (!(is->state & IPPP_OPEN))
- return -EINVAL;
-
- switch (cmd) {
- case PPPIOCBUNDLE:
-#ifdef CONFIG_ISDN_MPP
- if (!(is->state & IPPP_CONNECT))
- return -EINVAL;
- if ((r = get_arg(argp, &val, sizeof(val))))
- return r;
- printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n",
- (int) min, (int) is->unit, (int) val);
- return isdn_ppp_bundle(is, val);
-#else
- return -1;
-#endif
- break;
- case PPPIOCGUNIT: /* get ppp/isdn unit number */
- if ((r = set_arg(argp, &is->unit, sizeof(is->unit))))
- return r;
- break;
- case PPPIOCGIFNAME:
- if (!lp)
- return -EINVAL;
- if ((r = set_arg(argp, lp->netdev->dev->name,
- strlen(lp->netdev->dev->name))))
- return r;
- break;
- case PPPIOCGMPFLAGS: /* get configuration flags */
- if ((r = set_arg(argp, &is->mpppcfg, sizeof(is->mpppcfg))))
- return r;
- break;
- case PPPIOCSMPFLAGS: /* set configuration flags */
- if ((r = get_arg(argp, &val, sizeof(val))))
- return r;
- is->mpppcfg = val;
- break;
- case PPPIOCGFLAGS: /* get configuration flags */
- if ((r = set_arg(argp, &is->pppcfg, sizeof(is->pppcfg))))
- return r;
- break;
- case PPPIOCSFLAGS: /* set configuration flags */
- if ((r = get_arg(argp, &val, sizeof(val)))) {
- return r;
- }
- if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) {
- if (lp) {
- /* OK .. we are ready to send buffers */
- is->pppcfg = val; /* isdn_ppp_xmit test for SC_ENABLE_IP !!! */
- netif_wake_queue(lp->netdev->dev);
- break;
- }
- }
- is->pppcfg = val;
- break;
- case PPPIOCGIDLE: /* get idle time information */
- if (lp) {
- struct ppp_idle pidle;
- pidle.xmit_idle = pidle.recv_idle = lp->huptimer;
- if ((r = set_arg(argp, &pidle, sizeof(struct ppp_idle))))
- return r;
- }
- break;
- case PPPIOCSMRU: /* set receive unit size for PPP */
- if ((r = get_arg(argp, &val, sizeof(val))))
- return r;
- is->mru = val;
- break;
- case PPPIOCSMPMRU:
- break;
- case PPPIOCSMPMTU:
- break;
- case PPPIOCSMAXCID: /* set the maximum compression slot id */
- if ((r = get_arg(argp, &val, sizeof(val))))
- return r;
- val++;
- if (is->maxcid != val) {
-#ifdef CONFIG_ISDN_PPP_VJ
- struct slcompress *sltmp;
-#endif
- if (is->debug & 0x1)
- printk(KERN_DEBUG "ippp, ioctl: changed MAXCID to %ld\n", val);
- is->maxcid = val;
-#ifdef CONFIG_ISDN_PPP_VJ
- sltmp = slhc_init(16, val);
- if (IS_ERR(sltmp))
- return PTR_ERR(sltmp);
- if (is->slcomp)
- slhc_free(is->slcomp);
- is->slcomp = sltmp;
-#endif
- }
- break;
- case PPPIOCGDEBUG:
- if ((r = set_arg(argp, &is->debug, sizeof(is->debug))))
- return r;
- break;
- case PPPIOCSDEBUG:
- if ((r = get_arg(argp, &val, sizeof(val))))
- return r;
- is->debug = val;
- break;
- case PPPIOCGCOMPRESSORS:
- {
- unsigned long protos[8] = {0,};
- struct isdn_ppp_compressor *ipc = ipc_head;
- while (ipc) {
- j = ipc->num / (sizeof(long) * 8);
- i = ipc->num % (sizeof(long) * 8);
- if (j < 8)
- protos[j] |= (1UL << i);
- ipc = ipc->next;
- }
- if ((r = set_arg(argp, protos, 8 * sizeof(long))))
- return r;
- }
- break;
- case PPPIOCSCOMPRESSOR:
- if ((r = get_arg(argp, &data, sizeof(struct isdn_ppp_comp_data))))
- return r;
- return isdn_ppp_set_compressor(is, &data);
- case PPPIOCGCALLINFO:
- {
- struct pppcallinfo pci;
- memset((char *)&pci, 0, sizeof(struct pppcallinfo));
- if (lp)
- {
- strncpy(pci.local_num, lp->msn, 63);
- if (lp->dial) {
- strncpy(pci.remote_num, lp->dial->num, 63);
- }
- pci.charge_units = lp->charge;
- if (lp->outgoing)
- pci.calltype = CALLTYPE_OUTGOING;
- else
- pci.calltype = CALLTYPE_INCOMING;
- if (lp->flags & ISDN_NET_CALLBACK)
- pci.calltype |= CALLTYPE_CALLBACK;
- }
- return set_arg(argp, &pci, sizeof(struct pppcallinfo));
- }
-#ifdef CONFIG_IPPP_FILTER
- case PPPIOCSPASS:
- {
- struct sock_fprog_kern fprog;
- struct sock_filter *code;
- int err, len = get_filter(argp, &code);
-
- if (len < 0)
- return len;
-
- fprog.len = len;
- fprog.filter = code;
-
- if (is->pass_filter) {
- bpf_prog_destroy(is->pass_filter);
- is->pass_filter = NULL;
- }
- if (fprog.filter != NULL)
- err = bpf_prog_create(&is->pass_filter, &fprog);
- else
- err = 0;
- kfree(code);
-
- return err;
- }
- case PPPIOCSACTIVE:
- {
- struct sock_fprog_kern fprog;
- struct sock_filter *code;
- int err, len = get_filter(argp, &code);
-
- if (len < 0)
- return len;
-
- fprog.len = len;
- fprog.filter = code;
-
- if (is->active_filter) {
- bpf_prog_destroy(is->active_filter);
- is->active_filter = NULL;
- }
- if (fprog.filter != NULL)
- err = bpf_prog_create(&is->active_filter, &fprog);
- else
- err = 0;
- kfree(code);
-
- return err;
- }
-#endif /* CONFIG_IPPP_FILTER */
- default:
- break;
- }
- return 0;
-}
-
-__poll_t
-isdn_ppp_poll(struct file *file, poll_table *wait)
-{
- __poll_t mask;
- struct ippp_buf_queue *bf, *bl;
- u_long flags;
- struct ippp_struct *is;
-
- is = file->private_data;
-
- if (is->debug & 0x2)
- printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n",
- iminor(file_inode(file)));
-
- /* just registers wait_queue hook. This doesn't really wait. */
- poll_wait(file, &is->wq, wait);
-
- if (!(is->state & IPPP_OPEN)) {
- if (is->state == IPPP_CLOSEWAIT)
- return EPOLLHUP;
- printk(KERN_DEBUG "isdn_ppp: device not open\n");
- return EPOLLERR;
- }
- /* we're always ready to send .. */
- mask = EPOLLOUT | EPOLLWRNORM;
-
- spin_lock_irqsave(&is->buflock, flags);
- bl = is->last;
- bf = is->first;
- /*
- * if IPPP_NOBLOCK is set we return even if we have nothing to read
- */
- if (bf->next != bl || (is->state & IPPP_NOBLOCK)) {
- is->state &= ~IPPP_NOBLOCK;
- mask |= EPOLLIN | EPOLLRDNORM;
- }
- spin_unlock_irqrestore(&is->buflock, flags);
- return mask;
-}
-
-/*
- * fill up isdn_ppp_read() queue ..
- */
-
-static int
-isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
-{
- struct ippp_buf_queue *bf, *bl;
- u_long flags;
- u_char *nbuf;
- struct ippp_struct *is;
-
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_WARNING "ippp: illegal slot(%d).\n", slot);
- return 0;
- }
- is = ippp_table[slot];
-
- if (!(is->state & IPPP_CONNECT)) {
- printk(KERN_DEBUG "ippp: device not activated.\n");
- return 0;
- }
- nbuf = kmalloc(len + 4, GFP_ATOMIC);
- if (!nbuf) {
- printk(KERN_WARNING "ippp: Can't alloc buf\n");
- return 0;
- }
- nbuf[0] = PPP_ALLSTATIONS;
- nbuf[1] = PPP_UI;
- nbuf[2] = proto >> 8;
- nbuf[3] = proto & 0xff;
- memcpy(nbuf + 4, buf, len);
-
- spin_lock_irqsave(&is->buflock, flags);
- bf = is->first;
- bl = is->last;
-
- if (bf == bl) {
- printk(KERN_WARNING "ippp: Queue is full; discarding first buffer\n");
- bf = bf->next;
- kfree(bf->buf);
- is->first = bf;
- }
- bl->buf = (char *) nbuf;
- bl->len = len + 4;
-
- is->last = bl->next;
- spin_unlock_irqrestore(&is->buflock, flags);
- wake_up_interruptible(&is->wq);
- return len;
-}
-
-/*
- * read() .. non-blocking: ipppd calls it only after select()
- * reports, that there is data
- */
-
-int
-isdn_ppp_read(int min, struct file *file, char __user *buf, int count)
-{
- struct ippp_struct *is;
- struct ippp_buf_queue *b;
- u_long flags;
- u_char *save_buf;
-
- is = file->private_data;
-
- if (!(is->state & IPPP_OPEN))
- return 0;
-
- spin_lock_irqsave(&is->buflock, flags);
- b = is->first->next;
- save_buf = b->buf;
- if (!save_buf) {
- spin_unlock_irqrestore(&is->buflock, flags);
- return -EAGAIN;
- }
- if (b->len < count)
- count = b->len;
- b->buf = NULL;
- is->first = b;
-
- spin_unlock_irqrestore(&is->buflock, flags);
- if (copy_to_user(buf, save_buf, count))
- count = -EFAULT;
- kfree(save_buf);
-
- return count;
-}
-
-/*
- * ipppd wanna write a packet to the card .. non-blocking
- */
-
-int
-isdn_ppp_write(int min, struct file *file, const char __user *buf, int count)
-{
- isdn_net_local *lp;
- struct ippp_struct *is;
- int proto;
-
- is = file->private_data;
-
- if (!(is->state & IPPP_CONNECT))
- return 0;
-
- lp = is->lp;
-
- /* -> push it directly to the lowlevel interface */
-
- if (!lp)
- printk(KERN_DEBUG "isdn_ppp_write: lp == NULL\n");
- else {
- if (lp->isdn_device < 0 || lp->isdn_channel < 0) {
- unsigned char protobuf[4];
- /*
- * Don't reset huptimer for
- * LCP packets. (Echo requests).
- */
- if (copy_from_user(protobuf, buf, 4))
- return -EFAULT;
-
- proto = PPP_PROTOCOL(protobuf);
- if (proto != PPP_LCP)
- lp->huptimer = 0;
-
- return 0;
- }
-
- if ((dev->drv[lp->isdn_device]->flags & DRV_FLAG_RUNNING) &&
- lp->dialstate == 0 &&
- (lp->flags & ISDN_NET_CONNECTED)) {
- unsigned short hl;
- struct sk_buff *skb;
- unsigned char *cpy_buf;
- /*
- * we need to reserve enough space in front of
- * sk_buff. old call to dev_alloc_skb only reserved
- * 16 bytes, now we are looking what the driver want
- */
- hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
- skb = alloc_skb(hl + count, GFP_ATOMIC);
- if (!skb) {
- printk(KERN_WARNING "isdn_ppp_write: out of memory!\n");
- return count;
- }
- skb_reserve(skb, hl);
- cpy_buf = skb_put(skb, count);
- if (copy_from_user(cpy_buf, buf, count))
- {
- kfree_skb(skb);
- return -EFAULT;
- }
-
- /*
- * Don't reset huptimer for
- * LCP packets. (Echo requests).
- */
- proto = PPP_PROTOCOL(cpy_buf);
- if (proto != PPP_LCP)
- lp->huptimer = 0;
-
- if (is->debug & 0x40) {
- printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len);
- isdn_ppp_frame_log("xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
- }
-
- isdn_ppp_send_ccp(lp->netdev, lp, skb); /* keeps CCP/compression states in sync */
-
- isdn_net_write_super(lp, skb);
- }
- }
- return count;
-}
-
-/*
- * init memory, structures etc.
- */
-
-int
-isdn_ppp_init(void)
-{
- int i,
- j;
-
-#ifdef CONFIG_ISDN_MPP
- if (isdn_ppp_mp_bundle_array_init() < 0)
- return -ENOMEM;
-#endif /* CONFIG_ISDN_MPP */
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if (!(ippp_table[i] = kzalloc(sizeof(struct ippp_struct), GFP_KERNEL))) {
- printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n");
- for (j = 0; j < i; j++)
- kfree(ippp_table[j]);
- return -1;
- }
- spin_lock_init(&ippp_table[i]->buflock);
- ippp_table[i]->state = 0;
- ippp_table[i]->first = ippp_table[i]->rq + NUM_RCV_BUFFS - 1;
- ippp_table[i]->last = ippp_table[i]->rq;
-
- for (j = 0; j < NUM_RCV_BUFFS; j++) {
- ippp_table[i]->rq[j].buf = NULL;
- ippp_table[i]->rq[j].last = ippp_table[i]->rq +
- (NUM_RCV_BUFFS + j - 1) % NUM_RCV_BUFFS;
- ippp_table[i]->rq[j].next = ippp_table[i]->rq + (j + 1) % NUM_RCV_BUFFS;
- }
- }
- return 0;
-}
-
-void
-isdn_ppp_cleanup(void)
-{
- int i;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- kfree(ippp_table[i]);
-
-#ifdef CONFIG_ISDN_MPP
- kfree(isdn_ppp_bundle_arr);
-#endif /* CONFIG_ISDN_MPP */
-
-}
-
-/*
- * check for address/control field and skip if allowed
- * retval != 0 -> discard packet silently
- */
-static int isdn_ppp_skip_ac(struct ippp_struct *is, struct sk_buff *skb)
-{
- if (skb->len < 1)
- return -1;
-
- if (skb->data[0] == 0xff) {
- if (skb->len < 2)
- return -1;
-
- if (skb->data[1] != 0x03)
- return -1;
-
- // skip address/control (AC) field
- skb_pull(skb, 2);
- } else {
- if (is->pppcfg & SC_REJ_COMP_AC)
- // if AC compression was not negotiated, but used, discard packet
- return -1;
- }
- return 0;
-}
-
-/*
- * get the PPP protocol header and pull skb
- * retval < 0 -> discard packet silently
- */
-static int isdn_ppp_strip_proto(struct sk_buff *skb)
-{
- int proto;
-
- if (skb->len < 1)
- return -1;
-
- if (skb->data[0] & 0x1) {
- // protocol field is compressed
- proto = skb->data[0];
- skb_pull(skb, 1);
- } else {
- if (skb->len < 2)
- return -1;
- proto = ((int) skb->data[0] << 8) + skb->data[1];
- skb_pull(skb, 2);
- }
- return proto;
-}
-
-
-/*
- * handler for incoming packets on a syncPPP interface
- */
-void isdn_ppp_receive(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb)
-{
- struct ippp_struct *is;
- int slot;
- int proto;
-
- BUG_ON(net_dev->local->master); // we're called with the master device always
-
- slot = lp->ppp_slot;
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot(%d)\n",
- lp->ppp_slot);
- kfree_skb(skb);
- return;
- }
- is = ippp_table[slot];
-
- if (is->debug & 0x4) {
- printk(KERN_DEBUG "ippp_receive: is:%08lx lp:%08lx slot:%d unit:%d len:%d\n",
- (long)is, (long)lp, lp->ppp_slot, is->unit, (int)skb->len);
- isdn_ppp_frame_log("receive", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
- }
-
- if (isdn_ppp_skip_ac(is, skb) < 0) {
- kfree_skb(skb);
- return;
- }
- proto = isdn_ppp_strip_proto(skb);
- if (proto < 0) {
- kfree_skb(skb);
- return;
- }
-
-#ifdef CONFIG_ISDN_MPP
- if (is->compflags & SC_LINK_DECOMP_ON) {
- skb = isdn_ppp_decompress(skb, is, NULL, &proto);
- if (!skb) // decompression error
- return;
- }
-
- if (!(is->mpppcfg & SC_REJ_MP_PROT)) { // we agreed to receive MPPP
- if (proto == PPP_MP) {
- isdn_ppp_mp_receive(net_dev, lp, skb);
- return;
- }
- }
-#endif
- isdn_ppp_push_higher(net_dev, lp, skb, proto);
-}
-
-/*
- * we receive a reassembled frame, MPPP has been taken care of before.
- * address/control and protocol have been stripped from the skb
- * note: net_dev has to be master net_dev
- */
-static void
-isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb, int proto)
-{
- struct net_device *dev = net_dev->dev;
- struct ippp_struct *is, *mis;
- isdn_net_local *mlp = NULL;
- int slot;
-
- slot = lp->ppp_slot;
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot(%d)\n",
- lp->ppp_slot);
- goto drop_packet;
- }
- is = ippp_table[slot];
-
- if (lp->master) { // FIXME?
- mlp = ISDN_MASTER_PRIV(lp);
- slot = mlp->ppp_slot;
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot(%d)\n",
- lp->ppp_slot);
- goto drop_packet;
- }
- }
- mis = ippp_table[slot];
-
- if (is->debug & 0x10) {
- printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto);
- isdn_ppp_frame_log("rpush", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
- }
- if (mis->compflags & SC_DECOMP_ON) {
- skb = isdn_ppp_decompress(skb, is, mis, &proto);
- if (!skb) // decompression error
- return;
- }
- switch (proto) {
- case PPP_IPX: /* untested */
- if (is->debug & 0x20)
- printk(KERN_DEBUG "isdn_ppp: IPX\n");
- skb->protocol = htons(ETH_P_IPX);
- break;
- case PPP_IP:
- if (is->debug & 0x20)
- printk(KERN_DEBUG "isdn_ppp: IP\n");
- skb->protocol = htons(ETH_P_IP);
- break;
- case PPP_COMP:
- case PPP_COMPFRAG:
- printk(KERN_INFO "isdn_ppp: unexpected compressed frame dropped\n");
- goto drop_packet;
-#ifdef CONFIG_ISDN_PPP_VJ
- case PPP_VJC_UNCOMP:
- if (is->debug & 0x20)
- printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
- if (net_dev->local->ppp_slot < 0) {
- printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n",
- __func__, net_dev->local->ppp_slot);
- goto drop_packet;
- }
- if (slhc_remember(ippp_table[net_dev->local->ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
- printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
- goto drop_packet;
- }
- skb->protocol = htons(ETH_P_IP);
- break;
- case PPP_VJC_COMP:
- if (is->debug & 0x20)
- printk(KERN_DEBUG "isdn_ppp: VJC_COMP\n");
- {
- struct sk_buff *skb_old = skb;
- int pkt_len;
- skb = dev_alloc_skb(skb_old->len + 128);
-
- if (!skb) {
- printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
- skb = skb_old;
- goto drop_packet;
- }
- skb_put(skb, skb_old->len + 128);
- skb_copy_from_linear_data(skb_old, skb->data,
- skb_old->len);
- if (net_dev->local->ppp_slot < 0) {
- printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n",
- __func__, net_dev->local->ppp_slot);
- goto drop_packet;
- }
- pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp,
- skb->data, skb_old->len);
- kfree_skb(skb_old);
- if (pkt_len < 0)
- goto drop_packet;
-
- skb_trim(skb, pkt_len);
- skb->protocol = htons(ETH_P_IP);
- }
- break;
-#endif
- case PPP_CCP:
- case PPP_CCPFRAG:
- isdn_ppp_receive_ccp(net_dev, lp, skb, proto);
- /* Dont pop up ResetReq/Ack stuff to the daemon any
- longer - the job is done already */
- if (skb->data[0] == CCP_RESETREQ ||
- skb->data[0] == CCP_RESETACK)
- break;
- /* fall through */
- default:
- isdn_ppp_fill_rq(skb->data, skb->len, proto, lp->ppp_slot); /* push data to pppd device */
- kfree_skb(skb);
- return;
- }
-
-#ifdef CONFIG_IPPP_FILTER
- /* check if the packet passes the pass and active filters
- * the filter instructions are constructed assuming
- * a four-byte PPP header on each packet (which is still present) */
- skb_push(skb, 4);
-
- {
- u_int16_t *p = (u_int16_t *) skb->data;
-
- *p = 0; /* indicate inbound */
- }
-
- if (is->pass_filter
- && BPF_PROG_RUN(is->pass_filter, skb) == 0) {
- if (is->debug & 0x2)
- printk(KERN_DEBUG "IPPP: inbound frame filtered.\n");
- kfree_skb(skb);
- return;
- }
- if (!(is->active_filter
- && BPF_PROG_RUN(is->active_filter, skb) == 0)) {
- if (is->debug & 0x2)
- printk(KERN_DEBUG "IPPP: link-active filter: resetting huptimer.\n");
- lp->huptimer = 0;
- if (mlp)
- mlp->huptimer = 0;
- }
- skb_pull(skb, 4);
-#else /* CONFIG_IPPP_FILTER */
- lp->huptimer = 0;
- if (mlp)
- mlp->huptimer = 0;
-#endif /* CONFIG_IPPP_FILTER */
- skb->dev = dev;
- skb_reset_mac_header(skb);
- netif_rx(skb);
- /* net_dev->local->stats.rx_packets++; done in isdn_net.c */
- return;
-
-drop_packet:
- net_dev->local->stats.rx_dropped++;
- kfree_skb(skb);
-}
-
-/*
- * isdn_ppp_skb_push ..
- * checks whether we have enough space at the beginning of the skb
- * and allocs a new SKB if necessary
- */
-static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p, int len)
-{
- struct sk_buff *skb = *skb_p;
-
- if (skb_headroom(skb) < len) {
- struct sk_buff *nskb = skb_realloc_headroom(skb, len);
-
- if (!nskb) {
- printk(KERN_ERR "isdn_ppp_skb_push: can't realloc headroom!\n");
- dev_kfree_skb(skb);
- return NULL;
- }
- printk(KERN_DEBUG "isdn_ppp_skb_push:under %d %d\n", skb_headroom(skb), len);
- dev_kfree_skb(skb);
- *skb_p = nskb;
- return skb_push(nskb, len);
- }
- return skb_push(skb, len);
-}
-
-/*
- * send ppp frame .. we expect a PIDCOMPressable proto --
- * (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP)
- *
- * VJ compression may change skb pointer!!! .. requeue with old
- * skb isn't allowed!!
- */
-
-int
-isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
-{
- isdn_net_local *lp, *mlp;
- isdn_net_dev *nd;
- unsigned int proto = PPP_IP; /* 0x21 */
- struct ippp_struct *ipt, *ipts;
- int slot, retval = NETDEV_TX_OK;
-
- mlp = netdev_priv(netdev);
- nd = mlp->netdev; /* get master lp */
-
- slot = mlp->ppp_slot;
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
- mlp->ppp_slot);
- kfree_skb(skb);
- goto out;
- }
- ipts = ippp_table[slot];
-
- if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */
- if (ipts->debug & 0x1)
- printk(KERN_INFO "%s: IP frame delayed.\n", netdev->name);
- retval = NETDEV_TX_BUSY;
- goto out;
- }
-
- switch (ntohs(skb->protocol)) {
- case ETH_P_IP:
- proto = PPP_IP;
- break;
- case ETH_P_IPX:
- proto = PPP_IPX; /* untested */
- break;
- default:
- printk(KERN_ERR "isdn_ppp: skipped unsupported protocol: %#x.\n",
- skb->protocol);
- dev_kfree_skb(skb);
- goto out;
- }
-
- lp = isdn_net_get_locked_lp(nd);
- if (!lp) {
- printk(KERN_WARNING "%s: all channels busy - requeuing!\n", netdev->name);
- retval = NETDEV_TX_BUSY;
- goto out;
- }
- /* we have our lp locked from now on */
-
- slot = lp->ppp_slot;
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
- lp->ppp_slot);
- kfree_skb(skb);
- goto unlock;
- }
- ipt = ippp_table[slot];
-
- /*
- * after this line .. requeueing in the device queue is no longer allowed!!!
- */
-
- /* Pull off the fake header we stuck on earlier to keep
- * the fragmentation code happy.
- */
- skb_pull(skb, IPPP_MAX_HEADER);
-
-#ifdef CONFIG_IPPP_FILTER
- /* check if we should pass this packet
- * the filter instructions are constructed assuming
- * a four-byte PPP header on each packet */
- *(u8 *)skb_push(skb, 4) = 1; /* indicate outbound */
-
- {
- __be16 *p = (__be16 *)skb->data;
-
- p++;
- *p = htons(proto);
- }
-
- if (ipt->pass_filter
- && BPF_PROG_RUN(ipt->pass_filter, skb) == 0) {
- if (ipt->debug & 0x4)
- printk(KERN_DEBUG "IPPP: outbound frame filtered.\n");
- kfree_skb(skb);
- goto unlock;
- }
- if (!(ipt->active_filter
- && BPF_PROG_RUN(ipt->active_filter, skb) == 0)) {
- if (ipt->debug & 0x4)
- printk(KERN_DEBUG "IPPP: link-active filter: resetting huptimer.\n");
- lp->huptimer = 0;
- }
- skb_pull(skb, 4);
-#else /* CONFIG_IPPP_FILTER */
- lp->huptimer = 0;
-#endif /* CONFIG_IPPP_FILTER */
-
- if (ipt->debug & 0x4)
- printk(KERN_DEBUG "xmit skb, len %d\n", (int) skb->len);
- if (ipts->debug & 0x40)
- isdn_ppp_frame_log("xmit0", skb->data, skb->len, 32, ipts->unit, lp->ppp_slot);
-
-#ifdef CONFIG_ISDN_PPP_VJ
- if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes, but check this again */
- struct sk_buff *new_skb;
- unsigned short hl;
- /*
- * we need to reserve enough space in front of
- * sk_buff. old call to dev_alloc_skb only reserved
- * 16 bytes, now we are looking what the driver want.
- */
- hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen + IPPP_MAX_HEADER;
- /*
- * Note: hl might still be insufficient because the method
- * above does not account for a possibible MPPP slave channel
- * which had larger HL header space requirements than the
- * master.
- */
- new_skb = alloc_skb(hl + skb->len, GFP_ATOMIC);
- if (new_skb) {
- u_char *buf;
- int pktlen;
-
- skb_reserve(new_skb, hl);
- new_skb->dev = skb->dev;
- skb_put(new_skb, skb->len);
- buf = skb->data;
-
- pktlen = slhc_compress(ipts->slcomp, skb->data, skb->len, new_skb->data,
- &buf, !(ipts->pppcfg & SC_NO_TCP_CCID));
-
- if (buf != skb->data) {
- if (new_skb->data != buf)
- printk(KERN_ERR "isdn_ppp: FATAL error after slhc_compress!!\n");
- dev_kfree_skb(skb);
- skb = new_skb;
- } else {
- dev_kfree_skb(new_skb);
- }
-
- skb_trim(skb, pktlen);
- if (skb->data[0] & SL_TYPE_COMPRESSED_TCP) { /* cslip? style -> PPP */
- proto = PPP_VJC_COMP;
- skb->data[0] ^= SL_TYPE_COMPRESSED_TCP;
- } else {
- if (skb->data[0] >= SL_TYPE_UNCOMPRESSED_TCP)
- proto = PPP_VJC_UNCOMP;
- skb->data[0] = (skb->data[0] & 0x0f) | 0x40;
- }
- }
- }
-#endif
-
- /*
- * normal (single link) or bundle compression
- */
- if (ipts->compflags & SC_COMP_ON) {
- /* We send compressed only if both down- und upstream
- compression is negotiated, that means, CCP is up */
- if (ipts->compflags & SC_DECOMP_ON) {
- skb = isdn_ppp_compress(skb, &proto, ipt, ipts, 0);
- } else {
- printk(KERN_DEBUG "isdn_ppp: CCP not yet up - sending as-is\n");
- }
- }
-
- if (ipt->debug & 0x24)
- printk(KERN_DEBUG "xmit2 skb, len %d, proto %04x\n", (int) skb->len, proto);
-
-#ifdef CONFIG_ISDN_MPP
- if (ipt->mpppcfg & SC_MP_PROT) {
- /* we get mp_seqno from static isdn_net_local */
- long mp_seqno = ipts->mp_seqno;
- ipts->mp_seqno++;
- if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) {
- unsigned char *data = isdn_ppp_skb_push(&skb, 3);
- if (!data)
- goto unlock;
- mp_seqno &= 0xfff;
- data[0] = MP_BEGIN_FRAG | MP_END_FRAG | ((mp_seqno >> 8) & 0xf); /* (B)egin & (E)ndbit .. */
- data[1] = mp_seqno & 0xff;
- data[2] = proto; /* PID compression */
- } else {
- unsigned char *data = isdn_ppp_skb_push(&skb, 5);
- if (!data)
- goto unlock;
- data[0] = MP_BEGIN_FRAG | MP_END_FRAG; /* (B)egin & (E)ndbit .. */
- data[1] = (mp_seqno >> 16) & 0xff; /* sequence number: 24bit */
- data[2] = (mp_seqno >> 8) & 0xff;
- data[3] = (mp_seqno >> 0) & 0xff;
- data[4] = proto; /* PID compression */
- }
- proto = PPP_MP; /* MP Protocol, 0x003d */
- }
-#endif
-
- /*
- * 'link in bundle' compression ...
- */
- if (ipt->compflags & SC_LINK_COMP_ON)
- skb = isdn_ppp_compress(skb, &proto, ipt, ipts, 1);
-
- if ((ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff)) {
- unsigned char *data = isdn_ppp_skb_push(&skb, 1);
- if (!data)
- goto unlock;
- data[0] = proto & 0xff;
- }
- else {
- unsigned char *data = isdn_ppp_skb_push(&skb, 2);
- if (!data)
- goto unlock;
- data[0] = (proto >> 8) & 0xff;
- data[1] = proto & 0xff;
- }
- if (!(ipt->pppcfg & SC_COMP_AC)) {
- unsigned char *data = isdn_ppp_skb_push(&skb, 2);
- if (!data)
- goto unlock;
- data[0] = 0xff; /* All Stations */
- data[1] = 0x03; /* Unnumbered information */
- }
-
- /* tx-stats are now updated via BSENT-callback */
-
- if (ipts->debug & 0x40) {
- printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len);
- isdn_ppp_frame_log("xmit", skb->data, skb->len, 32, ipt->unit, lp->ppp_slot);
- }
-
- isdn_net_writebuf_skb(lp, skb);
-
-unlock:
- spin_unlock_bh(&lp->xmit_lock);
-out:
- return retval;
-}
-
-#ifdef CONFIG_IPPP_FILTER
-/*
- * check if this packet may trigger auto-dial.
- */
-
-int isdn_ppp_autodial_filter(struct sk_buff *skb, isdn_net_local *lp)
-{
- struct ippp_struct *is = ippp_table[lp->ppp_slot];
- u_int16_t proto;
- int drop = 0;
-
- switch (ntohs(skb->protocol)) {
- case ETH_P_IP:
- proto = PPP_IP;
- break;
- case ETH_P_IPX:
- proto = PPP_IPX;
- break;
- default:
- printk(KERN_ERR "isdn_ppp_autodial_filter: unsupported protocol 0x%x.\n",
- skb->protocol);
- return 1;
- }
-
- /* the filter instructions are constructed assuming
- * a four-byte PPP header on each packet. we have to
- * temporarily remove part of the fake header stuck on
- * earlier.
- */
- *(u8 *)skb_pull(skb, IPPP_MAX_HEADER - 4) = 1; /* indicate outbound */
-
- {
- __be16 *p = (__be16 *)skb->data;
-
- p++;
- *p = htons(proto);
- }
-
- drop |= is->pass_filter
- && BPF_PROG_RUN(is->pass_filter, skb) == 0;
- drop |= is->active_filter
- && BPF_PROG_RUN(is->active_filter, skb) == 0;
-
- skb_push(skb, IPPP_MAX_HEADER - 4);
- return drop;
-}
-#endif
-#ifdef CONFIG_ISDN_MPP
-
-/* this is _not_ rfc1990 header, but something we convert both short and long
- * headers to for convinience's sake:
- * byte 0 is flags as in rfc1990
- * bytes 1...4 is 24-bit seqence number converted to host byte order
- */
-#define MP_HEADER_LEN 5
-
-#define MP_LONGSEQ_MASK 0x00ffffff
-#define MP_SHORTSEQ_MASK 0x00000fff
-#define MP_LONGSEQ_MAX MP_LONGSEQ_MASK
-#define MP_SHORTSEQ_MAX MP_SHORTSEQ_MASK
-#define MP_LONGSEQ_MAXBIT ((MP_LONGSEQ_MASK + 1) >> 1)
-#define MP_SHORTSEQ_MAXBIT ((MP_SHORTSEQ_MASK + 1) >> 1)
-
-/* sequence-wrap safe comparisons (for long sequence)*/
-#define MP_LT(a, b) ((a - b) & MP_LONGSEQ_MAXBIT)
-#define MP_LE(a, b) !((b - a) & MP_LONGSEQ_MAXBIT)
-#define MP_GT(a, b) ((b - a) & MP_LONGSEQ_MAXBIT)
-#define MP_GE(a, b) !((a - b) & MP_LONGSEQ_MAXBIT)
-
-#define MP_SEQ(f) ((*(u32 *)(f->data + 1)))
-#define MP_FLAGS(f) (f->data[0])
-
-static int isdn_ppp_mp_bundle_array_init(void)
-{
- int i;
- int sz = ISDN_MAX_CHANNELS * sizeof(ippp_bundle);
- if ((isdn_ppp_bundle_arr = kzalloc(sz, GFP_KERNEL)) == NULL)
- return -ENOMEM;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- spin_lock_init(&isdn_ppp_bundle_arr[i].lock);
- return 0;
-}
-
-static ippp_bundle *isdn_ppp_mp_bundle_alloc(void)
-{
- int i;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (isdn_ppp_bundle_arr[i].ref_ct <= 0)
- return (isdn_ppp_bundle_arr + i);
- return NULL;
-}
-
-static int isdn_ppp_mp_init(isdn_net_local *lp, ippp_bundle *add_to)
-{
- struct ippp_struct *is;
-
- if (lp->ppp_slot < 0) {
- printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
- __func__, lp->ppp_slot);
- return (-EINVAL);
- }
-
- is = ippp_table[lp->ppp_slot];
- if (add_to) {
- if (lp->netdev->pb)
- lp->netdev->pb->ref_ct--;
- lp->netdev->pb = add_to;
- } else { /* first link in a bundle */
- is->mp_seqno = 0;
- if ((lp->netdev->pb = isdn_ppp_mp_bundle_alloc()) == NULL)
- return -ENOMEM;
- lp->next = lp->last = lp; /* nobody else in a queue */
- lp->netdev->pb->frags = NULL;
- lp->netdev->pb->frames = 0;
- lp->netdev->pb->seq = UINT_MAX;
- }
- lp->netdev->pb->ref_ct++;
-
- is->last_link_seqno = 0;
- return 0;
-}
-
-static u32 isdn_ppp_mp_get_seq(int short_seq,
- struct sk_buff *skb, u32 last_seq);
-static struct sk_buff *isdn_ppp_mp_discard(ippp_bundle *mp,
- struct sk_buff *from, struct sk_buff *to);
-static void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp,
- struct sk_buff *from, struct sk_buff *to);
-static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb);
-static void isdn_ppp_mp_print_recv_pkt(int slot, struct sk_buff *skb);
-
-static void isdn_ppp_mp_receive(isdn_net_dev *net_dev, isdn_net_local *lp,
- struct sk_buff *skb)
-{
- struct ippp_struct *is;
- isdn_net_local *lpq;
- ippp_bundle *mp;
- isdn_mppp_stats *stats;
- struct sk_buff *newfrag, *frag, *start, *nextf;
- u32 newseq, minseq, thisseq;
- unsigned long flags;
- int slot;
-
- spin_lock_irqsave(&net_dev->pb->lock, flags);
- mp = net_dev->pb;
- stats = &mp->stats;
- slot = lp->ppp_slot;
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: lp->ppp_slot(%d)\n",
- __func__, lp->ppp_slot);
- stats->frame_drops++;
- dev_kfree_skb(skb);
- spin_unlock_irqrestore(&mp->lock, flags);
- return;
- }
- is = ippp_table[slot];
- if (++mp->frames > stats->max_queue_len)
- stats->max_queue_len = mp->frames;
-
- if (is->debug & 0x8)
- isdn_ppp_mp_print_recv_pkt(lp->ppp_slot, skb);
-
- newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ,
- skb, is->last_link_seqno);
-
-
- /* if this packet seq # is less than last already processed one,
- * toss it right away, but check for sequence start case first
- */
- if (mp->seq > MP_LONGSEQ_MAX && (newseq & MP_LONGSEQ_MAXBIT)) {
- mp->seq = newseq; /* the first packet: required for
- * rfc1990 non-compliant clients --
- * prevents constant packet toss */
- } else if (MP_LT(newseq, mp->seq)) {
- stats->frame_drops++;
- isdn_ppp_mp_free_skb(mp, skb);
- spin_unlock_irqrestore(&mp->lock, flags);
- return;
- }
-
- /* find the minimum received sequence number over all links */
- is->last_link_seqno = minseq = newseq;
- for (lpq = net_dev->queue;;) {
- slot = lpq->ppp_slot;
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: lpq->ppp_slot(%d)\n",
- __func__, lpq->ppp_slot);
- } else {
- u32 lls = ippp_table[slot]->last_link_seqno;
- if (MP_LT(lls, minseq))
- minseq = lls;
- }
- if ((lpq = lpq->next) == net_dev->queue)
- break;
- }
- if (MP_LT(minseq, mp->seq))
- minseq = mp->seq; /* can't go beyond already processed
- * packets */
- newfrag = skb;
-
- /* if this new fragment is before the first one, then enqueue it now. */
- if ((frag = mp->frags) == NULL || MP_LT(newseq, MP_SEQ(frag))) {
- newfrag->next = frag;
- mp->frags = frag = newfrag;
- newfrag = NULL;
- }
-
- start = MP_FLAGS(frag) & MP_BEGIN_FRAG &&
- MP_SEQ(frag) == mp->seq ? frag : NULL;
-
- /*
- * main fragment traversing loop
- *
- * try to accomplish several tasks:
- * - insert new fragment into the proper sequence slot (once that's done
- * newfrag will be set to NULL)
- * - reassemble any complete fragment sequence (non-null 'start'
- * indicates there is a contiguous sequence present)
- * - discard any incomplete sequences that are below minseq -- due
- * to the fact that sender always increment sequence number, if there
- * is an incomplete sequence below minseq, no new fragments would
- * come to complete such sequence and it should be discarded
- *
- * loop completes when we accomplished the following tasks:
- * - new fragment is inserted in the proper sequence ('newfrag' is
- * set to NULL)
- * - we hit a gap in the sequence, so no reassembly/processing is
- * possible ('start' would be set to NULL)
- *
- * algorithm for this code is derived from code in the book
- * 'PPP Design And Debugging' by James Carlson (Addison-Wesley)
- */
- while (start != NULL || newfrag != NULL) {
-
- thisseq = MP_SEQ(frag);
- nextf = frag->next;
-
- /* drop any duplicate fragments */
- if (newfrag != NULL && thisseq == newseq) {
- isdn_ppp_mp_free_skb(mp, newfrag);
- newfrag = NULL;
- }
-
- /* insert new fragment before next element if possible. */
- if (newfrag != NULL && (nextf == NULL ||
- MP_LT(newseq, MP_SEQ(nextf)))) {
- newfrag->next = nextf;
- frag->next = nextf = newfrag;
- newfrag = NULL;
- }
-
- if (start != NULL) {
- /* check for misplaced start */
- if (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) {
- printk(KERN_WARNING"isdn_mppp(seq %d): new "
- "BEGIN flag with no prior END", thisseq);
- stats->seqerrs++;
- stats->frame_drops++;
- start = isdn_ppp_mp_discard(mp, start, frag);
- nextf = frag->next;
- }
- } else if (MP_LE(thisseq, minseq)) {
- if (MP_FLAGS(frag) & MP_BEGIN_FRAG)
- start = frag;
- else {
- if (MP_FLAGS(frag) & MP_END_FRAG)
- stats->frame_drops++;
- if (mp->frags == frag)
- mp->frags = nextf;
- isdn_ppp_mp_free_skb(mp, frag);
- frag = nextf;
- continue;
- }
- }
-
- /* if start is non-null and we have end fragment, then
- * we have full reassembly sequence -- reassemble
- * and process packet now
- */
- if (start != NULL && (MP_FLAGS(frag) & MP_END_FRAG)) {
- minseq = mp->seq = (thisseq + 1) & MP_LONGSEQ_MASK;
- /* Reassemble the packet then dispatch it */
- isdn_ppp_mp_reassembly(net_dev, lp, start, nextf);
-
- start = NULL;
- frag = NULL;
-
- mp->frags = nextf;
- }
-
- /* check if need to update start pointer: if we just
- * reassembled the packet and sequence is contiguous
- * then next fragment should be the start of new reassembly
- * if sequence is contiguous, but we haven't reassembled yet,
- * keep going.
- * if sequence is not contiguous, either clear everything
- * below low watermark and set start to the next frag or
- * clear start ptr.
- */
- if (nextf != NULL &&
- ((thisseq + 1) & MP_LONGSEQ_MASK) == MP_SEQ(nextf)) {
- /* if we just reassembled and the next one is here,
- * then start another reassembly. */
-
- if (frag == NULL) {
- if (MP_FLAGS(nextf) & MP_BEGIN_FRAG)
- start = nextf;
- else
- {
- printk(KERN_WARNING"isdn_mppp(seq %d):"
- " END flag with no following "
- "BEGIN", thisseq);
- stats->seqerrs++;
- }
- }
-
- } else {
- if (nextf != NULL && frag != NULL &&
- MP_LT(thisseq, minseq)) {
- /* we've got a break in the sequence
- * and we not at the end yet
- * and we did not just reassembled
- *(if we did, there wouldn't be anything before)
- * and we below the low watermark
- * discard all the frames below low watermark
- * and start over */
- stats->frame_drops++;
- mp->frags = isdn_ppp_mp_discard(mp, start, nextf);
- }
- /* break in the sequence, no reassembly */
- start = NULL;
- }
-
- frag = nextf;
- } /* while -- main loop */
-
- if (mp->frags == NULL)
- mp->frags = frag;
-
- /* rather straighforward way to deal with (not very) possible
- * queue overflow */
- if (mp->frames > MP_MAX_QUEUE_LEN) {
- stats->overflows++;
- while (mp->frames > MP_MAX_QUEUE_LEN) {
- frag = mp->frags->next;
- isdn_ppp_mp_free_skb(mp, mp->frags);
- mp->frags = frag;
- }
- }
- spin_unlock_irqrestore(&mp->lock, flags);
-}
-
-static void isdn_ppp_mp_cleanup(isdn_net_local *lp)
-{
- struct sk_buff *frag = lp->netdev->pb->frags;
- struct sk_buff *nextfrag;
- while (frag) {
- nextfrag = frag->next;
- isdn_ppp_mp_free_skb(lp->netdev->pb, frag);
- frag = nextfrag;
- }
- lp->netdev->pb->frags = NULL;
-}
-
-static u32 isdn_ppp_mp_get_seq(int short_seq,
- struct sk_buff *skb, u32 last_seq)
-{
- u32 seq;
- int flags = skb->data[0] & (MP_BEGIN_FRAG | MP_END_FRAG);
-
- if (!short_seq)
- {
- seq = ntohl(*(__be32 *)skb->data) & MP_LONGSEQ_MASK;
- skb_push(skb, 1);
- }
- else
- {
- /* convert 12-bit short seq number to 24-bit long one
- */
- seq = ntohs(*(__be16 *)skb->data) & MP_SHORTSEQ_MASK;
-
- /* check for seqence wrap */
- if (!(seq & MP_SHORTSEQ_MAXBIT) &&
- (last_seq & MP_SHORTSEQ_MAXBIT) &&
- (unsigned long)last_seq <= MP_LONGSEQ_MAX)
- seq |= (last_seq + MP_SHORTSEQ_MAX + 1) &
- (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK);
- else
- seq |= last_seq & (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK);
-
- skb_push(skb, 3); /* put converted seqence back in skb */
- }
- *(u32 *)(skb->data + 1) = seq; /* put seqence back in _host_ byte
- * order */
- skb->data[0] = flags; /* restore flags */
- return seq;
-}
-
-static struct sk_buff *isdn_ppp_mp_discard(ippp_bundle *mp,
- struct sk_buff *from,
- struct sk_buff *to)
-{
- if (from)
- while (from != to) {
- struct sk_buff *next = from->next;
- isdn_ppp_mp_free_skb(mp, from);
- from = next;
- }
- return from;
-}
-
-static void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp,
- struct sk_buff *from, struct sk_buff *to)
-{
- ippp_bundle *mp = net_dev->pb;
- int proto;
- struct sk_buff *skb;
- unsigned int tot_len;
-
- if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
- __func__, lp->ppp_slot);
- return;
- }
- if (MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG)) {
- if (ippp_table[lp->ppp_slot]->debug & 0x40)
- printk(KERN_DEBUG "isdn_mppp: reassembly: frame %d, "
- "len %d\n", MP_SEQ(from), from->len);
- skb = from;
- skb_pull(skb, MP_HEADER_LEN);
- mp->frames--;
- } else {
- struct sk_buff *frag;
- int n;
-
- for (tot_len = n = 0, frag = from; frag != to; frag = frag->next, n++)
- tot_len += frag->len - MP_HEADER_LEN;
-
- if (ippp_table[lp->ppp_slot]->debug & 0x40)
- printk(KERN_DEBUG"isdn_mppp: reassembling frames %d "
- "to %d, len %d\n", MP_SEQ(from),
- (MP_SEQ(from) + n - 1) & MP_LONGSEQ_MASK, tot_len);
- if ((skb = dev_alloc_skb(tot_len)) == NULL) {
- printk(KERN_ERR "isdn_mppp: cannot allocate sk buff "
- "of size %d\n", tot_len);
- isdn_ppp_mp_discard(mp, from, to);
- return;
- }
-
- while (from != to) {
- unsigned int len = from->len - MP_HEADER_LEN;
-
- skb_copy_from_linear_data_offset(from, MP_HEADER_LEN,
- skb_put(skb, len),
- len);
- frag = from->next;
- isdn_ppp_mp_free_skb(mp, from);
- from = frag;
- }
- }
- proto = isdn_ppp_strip_proto(skb);
- isdn_ppp_push_higher(net_dev, lp, skb, proto);
-}
-
-static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb)
-{
- dev_kfree_skb(skb);
- mp->frames--;
-}
-
-static void isdn_ppp_mp_print_recv_pkt(int slot, struct sk_buff *skb)
-{
- printk(KERN_DEBUG "mp_recv: %d/%d -> %02x %02x %02x %02x %02x %02x\n",
- slot, (int) skb->len,
- (int) skb->data[0], (int) skb->data[1], (int) skb->data[2],
- (int) skb->data[3], (int) skb->data[4], (int) skb->data[5]);
-}
-
-static int
-isdn_ppp_bundle(struct ippp_struct *is, int unit)
-{
- char ifn[IFNAMSIZ + 1];
- isdn_net_dev *p;
- isdn_net_local *lp, *nlp;
- int rc;
- unsigned long flags;
-
- sprintf(ifn, "ippp%d", unit);
- p = isdn_net_findif(ifn);
- if (!p) {
- printk(KERN_ERR "ippp_bundle: cannot find %s\n", ifn);
- return -EINVAL;
- }
-
- spin_lock_irqsave(&p->pb->lock, flags);
-
- nlp = is->lp;
- lp = p->queue;
- if (nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ||
- lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "ippp_bundle: binding to invalid slot %d\n",
- nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ?
- nlp->ppp_slot : lp->ppp_slot);
- rc = -EINVAL;
- goto out;
- }
-
- isdn_net_add_to_bundle(p, nlp);
-
- ippp_table[nlp->ppp_slot]->unit = ippp_table[lp->ppp_slot]->unit;
-
- /* maybe also SC_CCP stuff */
- ippp_table[nlp->ppp_slot]->pppcfg |= ippp_table[lp->ppp_slot]->pppcfg &
- (SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP);
- ippp_table[nlp->ppp_slot]->mpppcfg |= ippp_table[lp->ppp_slot]->mpppcfg &
- (SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ);
- rc = isdn_ppp_mp_init(nlp, p->pb);
-out:
- spin_unlock_irqrestore(&p->pb->lock, flags);
- return rc;
-}
-
-#endif /* CONFIG_ISDN_MPP */
-
-/*
- * network device ioctl handlers
- */
-
-static int
-isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev)
-{
- struct ppp_stats __user *res = ifr->ifr_data;
- struct ppp_stats t;
- isdn_net_local *lp = netdev_priv(dev);
-
- /* build a temporary stat struct and copy it to user space */
-
- memset(&t, 0, sizeof(struct ppp_stats));
- if (dev->flags & IFF_UP) {
- t.p.ppp_ipackets = lp->stats.rx_packets;
- t.p.ppp_ibytes = lp->stats.rx_bytes;
- t.p.ppp_ierrors = lp->stats.rx_errors;
- t.p.ppp_opackets = lp->stats.tx_packets;
- t.p.ppp_obytes = lp->stats.tx_bytes;
- t.p.ppp_oerrors = lp->stats.tx_errors;
-#ifdef CONFIG_ISDN_PPP_VJ
- if (slot >= 0 && ippp_table[slot]->slcomp) {
- struct slcompress *slcomp = ippp_table[slot]->slcomp;
- t.vj.vjs_packets = slcomp->sls_o_compressed + slcomp->sls_o_uncompressed;
- t.vj.vjs_compressed = slcomp->sls_o_compressed;
- t.vj.vjs_searches = slcomp->sls_o_searches;
- t.vj.vjs_misses = slcomp->sls_o_misses;
- t.vj.vjs_errorin = slcomp->sls_i_error;
- t.vj.vjs_tossed = slcomp->sls_i_tossed;
- t.vj.vjs_uncompressedin = slcomp->sls_i_uncompressed;
- t.vj.vjs_compressedin = slcomp->sls_i_compressed;
- }
-#endif
- }
- if (copy_to_user(res, &t, sizeof(struct ppp_stats)))
- return -EFAULT;
- return 0;
-}
-
-int
-isdn_ppp_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
- int error = 0;
- int len;
- isdn_net_local *lp = netdev_priv(dev);
-
-
- if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
- return -EINVAL;
-
- switch (cmd) {
-#define PPP_VERSION "2.3.7"
- case SIOCGPPPVER:
- len = strlen(PPP_VERSION) + 1;
- if (copy_to_user(ifr->ifr_data, PPP_VERSION, len))
- error = -EFAULT;
- break;
-
- case SIOCGPPPSTATS:
- error = isdn_ppp_dev_ioctl_stats(lp->ppp_slot, ifr, dev);
- break;
- default:
- error = -EINVAL;
- break;
- }
- return error;
-}
-
-static int
-isdn_ppp_if_get_unit(char *name)
-{
- int len,
- i,
- unit = 0,
- deci;
-
- len = strlen(name);
-
- if (strncmp("ippp", name, 4) || len > 8)
- return -1;
-
- for (i = 0, deci = 1; i < len; i++, deci *= 10) {
- char a = name[len - i - 1];
- if (a >= '0' && a <= '9')
- unit += (a - '0') * deci;
- else
- break;
- }
- if (!i || len - i != 4)
- unit = -1;
-
- return unit;
-}
-
-
-int
-isdn_ppp_dial_slave(char *name)
-{
-#ifdef CONFIG_ISDN_MPP
- isdn_net_dev *ndev;
- isdn_net_local *lp;
- struct net_device *sdev;
-
- if (!(ndev = isdn_net_findif(name)))
- return 1;
- lp = ndev->local;
- if (!(lp->flags & ISDN_NET_CONNECTED))
- return 5;
-
- sdev = lp->slave;
- while (sdev) {
- isdn_net_local *mlp = netdev_priv(sdev);
- if (!(mlp->flags & ISDN_NET_CONNECTED))
- break;
- sdev = mlp->slave;
- }
- if (!sdev)
- return 2;
-
- isdn_net_dial_req(netdev_priv(sdev));
- return 0;
-#else
- return -1;
-#endif
-}
-
-int
-isdn_ppp_hangup_slave(char *name)
-{
-#ifdef CONFIG_ISDN_MPP
- isdn_net_dev *ndev;
- isdn_net_local *lp;
- struct net_device *sdev;
-
- if (!(ndev = isdn_net_findif(name)))
- return 1;
- lp = ndev->local;
- if (!(lp->flags & ISDN_NET_CONNECTED))
- return 5;
-
- sdev = lp->slave;
- while (sdev) {
- isdn_net_local *mlp = netdev_priv(sdev);
-
- if (mlp->slave) { /* find last connected link in chain */
- isdn_net_local *nlp = ISDN_SLAVE_PRIV(mlp);
-
- if (!(nlp->flags & ISDN_NET_CONNECTED))
- break;
- } else if (mlp->flags & ISDN_NET_CONNECTED)
- break;
-
- sdev = mlp->slave;
- }
- if (!sdev)
- return 2;
-
- isdn_net_hangup(sdev);
- return 0;
-#else
- return -1;
-#endif
-}
-
-/*
- * PPP compression stuff
- */
-
-
-/* Push an empty CCP Data Frame up to the daemon to wake it up and let it
- generate a CCP Reset-Request or tear down CCP altogether */
-
-static void isdn_ppp_ccp_kickup(struct ippp_struct *is)
-{
- isdn_ppp_fill_rq(NULL, 0, PPP_COMP, is->lp->ppp_slot);
-}
-
-/* In-kernel handling of CCP Reset-Request and Reset-Ack is necessary,
- but absolutely nontrivial. The most abstruse problem we are facing is
- that the generation, reception and all the handling of timeouts and
- resends including proper request id management should be entirely left
- to the (de)compressor, but indeed is not covered by the current API to
- the (de)compressor. The API is a prototype version from PPP where only
- some (de)compressors have yet been implemented and all of them are
- rather simple in their reset handling. Especially, their is only one
- outstanding ResetAck at a time with all of them and ResetReq/-Acks do
- not have parameters. For this very special case it was sufficient to
- just return an error code from the decompressor and have a single
- reset() entry to communicate all the necessary information between
- the framework and the (de)compressor. Bad enough, LZS is different
- (and any other compressor may be different, too). It has multiple
- histories (eventually) and needs to Reset each of them independently
- and thus uses multiple outstanding Acks and history numbers as an
- additional parameter to Reqs/Acks.
- All that makes it harder to port the reset state engine into the
- kernel because it is not just the same simple one as in (i)pppd but
- it must be able to pass additional parameters and have multiple out-
- standing Acks. We are trying to achieve the impossible by handling
- reset transactions independent by their id. The id MUST change when
- the data portion changes, thus any (de)compressor who uses more than
- one resettable state must provide and recognize individual ids for
- each individual reset transaction. The framework itself does _only_
- differentiate them by id, because it has no other semantics like the
- (de)compressor might.
- This looks like a major redesign of the interface would be nice,
- but I don't have an idea how to do it better. */
-
-/* Send a CCP Reset-Request or Reset-Ack directly from the kernel. This is
- getting that lengthy because there is no simple "send-this-frame-out"
- function above but every wrapper does a bit different. Hope I guess
- correct in this hack... */
-
-static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
- unsigned char code, unsigned char id,
- unsigned char *data, int len)
-{
- struct sk_buff *skb;
- unsigned char *p;
- int hl;
- int cnt = 0;
- isdn_net_local *lp = is->lp;
-
- /* Alloc large enough skb */
- hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
- skb = alloc_skb(len + hl + 16, GFP_ATOMIC);
- if (!skb) {
- printk(KERN_WARNING
- "ippp: CCP cannot send reset - out of memory\n");
- return;
- }
- skb_reserve(skb, hl);
-
- /* We may need to stuff an address and control field first */
- if (!(is->pppcfg & SC_COMP_AC)) {
- p = skb_put(skb, 2);
- *p++ = 0xff;
- *p++ = 0x03;
- }
-
- /* Stuff proto, code, id and length */
- p = skb_put(skb, 6);
- *p++ = (proto >> 8);
- *p++ = (proto & 0xff);
- *p++ = code;
- *p++ = id;
- cnt = 4 + len;
- *p++ = (cnt >> 8);
- *p++ = (cnt & 0xff);
-
- /* Now stuff remaining bytes */
- if (len) {
- skb_put_data(skb, data, len);
- }
-
- /* skb is now ready for xmit */
- printk(KERN_DEBUG "Sending CCP Frame:\n");
- isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
-
- isdn_net_write_super(lp, skb);
-}
-
-/* Allocate the reset state vector */
-static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is)
-{
- struct ippp_ccp_reset *r;
- r = kzalloc(sizeof(struct ippp_ccp_reset), GFP_KERNEL);
- if (!r) {
- printk(KERN_ERR "ippp_ccp: failed to allocate reset data"
- " structure - no mem\n");
- return NULL;
- }
- printk(KERN_DEBUG "ippp_ccp: allocated reset data structure %p\n", r);
- is->reset = r;
- return r;
-}
-
-/* Destroy the reset state vector. Kill all pending timers first. */
-static void isdn_ppp_ccp_reset_free(struct ippp_struct *is)
-{
- unsigned int id;
-
- printk(KERN_DEBUG "ippp_ccp: freeing reset data structure %p\n",
- is->reset);
- for (id = 0; id < 256; id++) {
- if (is->reset->rs[id]) {
- isdn_ppp_ccp_reset_free_state(is, (unsigned char)id);
- }
- }
- kfree(is->reset);
- is->reset = NULL;
-}
-
-/* Free a given state and clear everything up for later reallocation */
-static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is,
- unsigned char id)
-{
- struct ippp_ccp_reset_state *rs;
-
- if (is->reset->rs[id]) {
- printk(KERN_DEBUG "ippp_ccp: freeing state for id %d\n", id);
- rs = is->reset->rs[id];
- /* Make sure the kernel will not call back later */
- if (rs->ta)
- del_timer(&rs->timer);
- is->reset->rs[id] = NULL;
- kfree(rs);
- } else {
- printk(KERN_WARNING "ippp_ccp: id %d is not allocated\n", id);
- }
-}
-
-/* The timer callback function which is called when a ResetReq has timed out,
- aka has never been answered by a ResetAck */
-static void isdn_ppp_ccp_timer_callback(struct timer_list *t)
-{
- struct ippp_ccp_reset_state *rs =
- from_timer(rs, t, timer);
-
- if (!rs) {
- printk(KERN_ERR "ippp_ccp: timer cb with zero closure.\n");
- return;
- }
- if (rs->ta && rs->state == CCPResetSentReq) {
- /* We are correct here */
- if (!rs->expra) {
- /* Hmm, there is no Ack really expected. We can clean
- up the state now, it will be reallocated if the
- decompressor insists on another reset */
- rs->ta = 0;
- isdn_ppp_ccp_reset_free_state(rs->is, rs->id);
- return;
- }
- printk(KERN_DEBUG "ippp_ccp: CCP Reset timed out for id %d\n",
- rs->id);
- /* Push it again */
- isdn_ppp_ccp_xmit_reset(rs->is, PPP_CCP, CCP_RESETREQ, rs->id,
- rs->data, rs->dlen);
- /* Restart timer */
- rs->timer.expires = jiffies + HZ * 5;
- add_timer(&rs->timer);
- } else {
- printk(KERN_WARNING "ippp_ccp: timer cb in wrong state %d\n",
- rs->state);
- }
-}
-
-/* Allocate a new reset transaction state */
-static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is,
- unsigned char id)
-{
- struct ippp_ccp_reset_state *rs;
- if (is->reset->rs[id]) {
- printk(KERN_WARNING "ippp_ccp: old state exists for id %d\n",
- id);
- return NULL;
- } else {
- rs = kzalloc(sizeof(struct ippp_ccp_reset_state), GFP_ATOMIC);
- if (!rs)
- return NULL;
- rs->state = CCPResetIdle;
- rs->is = is;
- rs->id = id;
- timer_setup(&rs->timer, isdn_ppp_ccp_timer_callback, 0);
- is->reset->rs[id] = rs;
- }
- return rs;
-}
-
-
-/* A decompressor wants a reset with a set of parameters - do what is
- necessary to fulfill it */
-static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is,
- struct isdn_ppp_resetparams *rp)
-{
- struct ippp_ccp_reset_state *rs;
-
- if (rp->valid) {
- /* The decompressor defines parameters by itself */
- if (rp->rsend) {
- /* And he wants us to send a request */
- if (!(rp->idval)) {
- printk(KERN_ERR "ippp_ccp: decompressor must"
- " specify reset id\n");
- return;
- }
- if (is->reset->rs[rp->id]) {
- /* There is already a transaction in existence
- for this id. May be still waiting for a
- Ack or may be wrong. */
- rs = is->reset->rs[rp->id];
- if (rs->state == CCPResetSentReq && rs->ta) {
- printk(KERN_DEBUG "ippp_ccp: reset"
- " trans still in progress"
- " for id %d\n", rp->id);
- } else {
- printk(KERN_WARNING "ippp_ccp: reset"
- " trans in wrong state %d for"
- " id %d\n", rs->state, rp->id);
- }
- } else {
- /* Ok, this is a new transaction */
- printk(KERN_DEBUG "ippp_ccp: new trans for id"
- " %d to be started\n", rp->id);
- rs = isdn_ppp_ccp_reset_alloc_state(is, rp->id);
- if (!rs) {
- printk(KERN_ERR "ippp_ccp: out of mem"
- " allocing ccp trans\n");
- return;
- }
- rs->state = CCPResetSentReq;
- rs->expra = rp->expra;
- if (rp->dtval) {
- rs->dlen = rp->dlen;
- memcpy(rs->data, rp->data, rp->dlen);
- }
- /* HACK TODO - add link comp here */
- isdn_ppp_ccp_xmit_reset(is, PPP_CCP,
- CCP_RESETREQ, rs->id,
- rs->data, rs->dlen);
- /* Start the timer */
- rs->timer.expires = jiffies + 5 * HZ;
- add_timer(&rs->timer);
- rs->ta = 1;
- }
- } else {
- printk(KERN_DEBUG "ippp_ccp: no reset sent\n");
- }
- } else {
- /* The reset params are invalid. The decompressor does not
- care about them, so we just send the minimal requests
- and increase ids only when an Ack is received for a
- given id */
- if (is->reset->rs[is->reset->lastid]) {
- /* There is already a transaction in existence
- for this id. May be still waiting for a
- Ack or may be wrong. */
- rs = is->reset->rs[is->reset->lastid];
- if (rs->state == CCPResetSentReq && rs->ta) {
- printk(KERN_DEBUG "ippp_ccp: reset"
- " trans still in progress"
- " for id %d\n", rp->id);
- } else {
- printk(KERN_WARNING "ippp_ccp: reset"
- " trans in wrong state %d for"
- " id %d\n", rs->state, rp->id);
- }
- } else {
- printk(KERN_DEBUG "ippp_ccp: new trans for id"
- " %d to be started\n", is->reset->lastid);
- rs = isdn_ppp_ccp_reset_alloc_state(is,
- is->reset->lastid);
- if (!rs) {
- printk(KERN_ERR "ippp_ccp: out of mem"
- " allocing ccp trans\n");
- return;
- }
- rs->state = CCPResetSentReq;
- /* We always expect an Ack if the decompressor doesn't
- know better */
- rs->expra = 1;
- rs->dlen = 0;
- /* HACK TODO - add link comp here */
- isdn_ppp_ccp_xmit_reset(is, PPP_CCP, CCP_RESETREQ,
- rs->id, NULL, 0);
- /* Start the timer */
- rs->timer.expires = jiffies + 5 * HZ;
- add_timer(&rs->timer);
- rs->ta = 1;
- }
- }
-}
-
-/* An Ack was received for this id. This means we stop the timer and clean
- up the state prior to calling the decompressors reset routine. */
-static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is,
- unsigned char id)
-{
- struct ippp_ccp_reset_state *rs = is->reset->rs[id];
-
- if (rs) {
- if (rs->ta && rs->state == CCPResetSentReq) {
- /* Great, we are correct */
- if (!rs->expra)
- printk(KERN_DEBUG "ippp_ccp: ResetAck received"
- " for id %d but not expected\n", id);
- } else {
- printk(KERN_INFO "ippp_ccp: ResetAck received out of"
- "sync for id %d\n", id);
- }
- if (rs->ta) {
- rs->ta = 0;
- del_timer(&rs->timer);
- }
- isdn_ppp_ccp_reset_free_state(is, id);
- } else {
- printk(KERN_INFO "ippp_ccp: ResetAck received for unknown id"
- " %d\n", id);
- }
- /* Make sure the simple reset stuff uses a new id next time */
- is->reset->lastid++;
-}
-
-/*
- * decompress packet
- *
- * if master = 0, we're trying to uncompress an per-link compressed packet,
- * as opposed to an compressed reconstructed-from-MPPP packet.
- * proto is updated to protocol field of uncompressed packet.
- *
- * retval: decompressed packet,
- * same packet if uncompressed,
- * NULL if decompression error
- */
-
-static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb, struct ippp_struct *is, struct ippp_struct *master,
- int *proto)
-{
- void *stat = NULL;
- struct isdn_ppp_compressor *ipc = NULL;
- struct sk_buff *skb_out;
- int len;
- struct ippp_struct *ri;
- struct isdn_ppp_resetparams rsparm;
- unsigned char rsdata[IPPP_RESET_MAXDATABYTES];
-
- if (!master) {
- // per-link decompression
- stat = is->link_decomp_stat;
- ipc = is->link_decompressor;
- ri = is;
- } else {
- stat = master->decomp_stat;
- ipc = master->decompressor;
- ri = master;
- }
-
- if (!ipc) {
- // no decompressor -> we can't decompress.
- printk(KERN_DEBUG "ippp: no decompressor defined!\n");
- return skb;
- }
- BUG_ON(!stat); // if we have a compressor, stat has been set as well
-
- if ((master && *proto == PPP_COMP) || (!master && *proto == PPP_COMPFRAG)) {
- // compressed packets are compressed by their protocol type
-
- // Set up reset params for the decompressor
- memset(&rsparm, 0, sizeof(rsparm));
- rsparm.data = rsdata;
- rsparm.maxdlen = IPPP_RESET_MAXDATABYTES;
-
- skb_out = dev_alloc_skb(is->mru + PPP_HDRLEN);
- if (!skb_out) {
- kfree_skb(skb);
- printk(KERN_ERR "ippp: decomp memory allocation failure\n");
- return NULL;
- }
- len = ipc->decompress(stat, skb, skb_out, &rsparm);
- kfree_skb(skb);
- if (len <= 0) {
- switch (len) {
- case DECOMP_ERROR:
- printk(KERN_INFO "ippp: decomp wants reset %s params\n",
- rsparm.valid ? "with" : "without");
-
- isdn_ppp_ccp_reset_trans(ri, &rsparm);
- break;
- case DECOMP_FATALERROR:
- ri->pppcfg |= SC_DC_FERROR;
- /* Kick ipppd to recognize the error */
- isdn_ppp_ccp_kickup(ri);
- break;
- }
- kfree_skb(skb_out);
- return NULL;
- }
- *proto = isdn_ppp_strip_proto(skb_out);
- if (*proto < 0) {
- kfree_skb(skb_out);
- return NULL;
- }
- return skb_out;
- } else {
- // uncompressed packets are fed through the decompressor to
- // update the decompressor state
- ipc->incomp(stat, skb, *proto);
- return skb;
- }
-}
-
-/*
- * compress a frame
- * type=0: normal/bundle compression
- * =1: link compression
- * returns original skb if we haven't compressed the frame
- * and a new skb pointer if we've done it
- */
-static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in, int *proto,
- struct ippp_struct *is, struct ippp_struct *master, int type)
-{
- int ret;
- int new_proto;
- struct isdn_ppp_compressor *compressor;
- void *stat;
- struct sk_buff *skb_out;
-
- /* we do not compress control protocols */
- if (*proto < 0 || *proto > 0x3fff) {
- return skb_in;
- }
-
- if (type) { /* type=1 => Link compression */
- return skb_in;
- }
- else {
- if (!master) {
- compressor = is->compressor;
- stat = is->comp_stat;
- }
- else {
- compressor = master->compressor;
- stat = master->comp_stat;
- }
- new_proto = PPP_COMP;
- }
-
- if (!compressor) {
- printk(KERN_ERR "isdn_ppp: No compressor set!\n");
- return skb_in;
- }
- if (!stat) {
- printk(KERN_ERR "isdn_ppp: Compressor not initialized?\n");
- return skb_in;
- }
-
- /* Allow for at least 150 % expansion (for now) */
- skb_out = alloc_skb(skb_in->len + skb_in->len / 2 + 32 +
- skb_headroom(skb_in), GFP_ATOMIC);
- if (!skb_out)
- return skb_in;
- skb_reserve(skb_out, skb_headroom(skb_in));
-
- ret = (compressor->compress)(stat, skb_in, skb_out, *proto);
- if (!ret) {
- dev_kfree_skb(skb_out);
- return skb_in;
- }
-
- dev_kfree_skb(skb_in);
- *proto = new_proto;
- return skb_out;
-}
-
-/*
- * we received a CCP frame ..
- * not a clean solution, but we MUST handle a few cases in the kernel
- */
-static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
- struct sk_buff *skb, int proto)
-{
- struct ippp_struct *is;
- struct ippp_struct *mis;
- int len;
- struct isdn_ppp_resetparams rsparm;
- unsigned char rsdata[IPPP_RESET_MAXDATABYTES];
-
- printk(KERN_DEBUG "Received CCP frame from peer slot(%d)\n",
- lp->ppp_slot);
- if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
- __func__, lp->ppp_slot);
- return;
- }
- is = ippp_table[lp->ppp_slot];
- isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
-
- if (lp->master) {
- int slot = ISDN_MASTER_PRIV(lp)->ppp_slot;
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: slot(%d) out of range\n",
- __func__, slot);
- return;
- }
- mis = ippp_table[slot];
- } else
- mis = is;
-
- switch (skb->data[0]) {
- case CCP_CONFREQ:
- if (is->debug & 0x10)
- printk(KERN_DEBUG "Disable compression here!\n");
- if (proto == PPP_CCP)
- mis->compflags &= ~SC_COMP_ON;
- else
- is->compflags &= ~SC_LINK_COMP_ON;
- break;
- case CCP_TERMREQ:
- case CCP_TERMACK:
- if (is->debug & 0x10)
- printk(KERN_DEBUG "Disable (de)compression here!\n");
- if (proto == PPP_CCP)
- mis->compflags &= ~(SC_DECOMP_ON | SC_COMP_ON);
- else
- is->compflags &= ~(SC_LINK_DECOMP_ON | SC_LINK_COMP_ON);
- break;
- case CCP_CONFACK:
- /* if we RECEIVE an ackowledge we enable the decompressor */
- if (is->debug & 0x10)
- printk(KERN_DEBUG "Enable decompression here!\n");
- if (proto == PPP_CCP) {
- if (!mis->decompressor)
- break;
- mis->compflags |= SC_DECOMP_ON;
- } else {
- if (!is->decompressor)
- break;
- is->compflags |= SC_LINK_DECOMP_ON;
- }
- break;
-
- case CCP_RESETACK:
- printk(KERN_DEBUG "Received ResetAck from peer\n");
- len = (skb->data[2] << 8) | skb->data[3];
- len -= 4;
-
- if (proto == PPP_CCP) {
- /* If a reset Ack was outstanding for this id, then
- clean up the state engine */
- isdn_ppp_ccp_reset_ack_rcvd(mis, skb->data[1]);
- if (mis->decompressor && mis->decomp_stat)
- mis->decompressor->
- reset(mis->decomp_stat,
- skb->data[0],
- skb->data[1],
- len ? &skb->data[4] : NULL,
- len, NULL);
- /* TODO: This is not easy to decide here */
- mis->compflags &= ~SC_DECOMP_DISCARD;
- }
- else {
- isdn_ppp_ccp_reset_ack_rcvd(is, skb->data[1]);
- if (is->link_decompressor && is->link_decomp_stat)
- is->link_decompressor->
- reset(is->link_decomp_stat,
- skb->data[0],
- skb->data[1],
- len ? &skb->data[4] : NULL,
- len, NULL);
- /* TODO: neither here */
- is->compflags &= ~SC_LINK_DECOMP_DISCARD;
- }
- break;
-
- case CCP_RESETREQ:
- printk(KERN_DEBUG "Received ResetReq from peer\n");
- /* Receiving a ResetReq means we must reset our compressor */
- /* Set up reset params for the reset entry */
- memset(&rsparm, 0, sizeof(rsparm));
- rsparm.data = rsdata;
- rsparm.maxdlen = IPPP_RESET_MAXDATABYTES;
- /* Isolate data length */
- len = (skb->data[2] << 8) | skb->data[3];
- len -= 4;
- if (proto == PPP_CCP) {
- if (mis->compressor && mis->comp_stat)
- mis->compressor->
- reset(mis->comp_stat,
- skb->data[0],
- skb->data[1],
- len ? &skb->data[4] : NULL,
- len, &rsparm);
- }
- else {
- if (is->link_compressor && is->link_comp_stat)
- is->link_compressor->
- reset(is->link_comp_stat,
- skb->data[0],
- skb->data[1],
- len ? &skb->data[4] : NULL,
- len, &rsparm);
- }
- /* Ack the Req as specified by rsparm */
- if (rsparm.valid) {
- /* Compressor reset handler decided how to answer */
- if (rsparm.rsend) {
- /* We should send a Frame */
- isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK,
- rsparm.idval ? rsparm.id
- : skb->data[1],
- rsparm.dtval ?
- rsparm.data : NULL,
- rsparm.dtval ?
- rsparm.dlen : 0);
- } else {
- printk(KERN_DEBUG "ResetAck suppressed\n");
- }
- } else {
- /* We answer with a straight reflected Ack */
- isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK,
- skb->data[1],
- len ? &skb->data[4] : NULL,
- len);
- }
- break;
- }
-}
-
-
-/*
- * Daemon sends a CCP frame ...
- */
-
-/* TODO: Clean this up with new Reset semantics */
-
-/* I believe the CCP handling as-is is done wrong. Compressed frames
- * should only be sent/received after CCP reaches UP state, which means
- * both sides have sent CONF_ACK. Currently, we handle both directions
- * independently, which means we may accept compressed frames too early
- * (supposedly not a problem), but may also mean we send compressed frames
- * too early, which may turn out to be a problem.
- * This part of state machine should actually be handled by (i)pppd, but
- * that's too big of a change now. --kai
- */
-
-/* Actually, we might turn this into an advantage: deal with the RFC in
- * the old tradition of beeing generous on what we accept, but beeing
- * strict on what we send. Thus we should just
- * - accept compressed frames as soon as decompression is negotiated
- * - send compressed frames only when decomp *and* comp are negotiated
- * - drop rx compressed frames if we cannot decomp (instead of pushing them
- * up to ipppd)
- * and I tried to modify this file according to that. --abp
- */
-
-static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb)
-{
- struct ippp_struct *mis, *is;
- int proto, slot = lp->ppp_slot;
- unsigned char *data;
-
- if (!skb || skb->len < 3)
- return;
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
- __func__, slot);
- return;
- }
- is = ippp_table[slot];
- /* Daemon may send with or without address and control field comp */
- data = skb->data;
- if (!(is->pppcfg & SC_COMP_AC) && data[0] == 0xff && data[1] == 0x03) {
- data += 2;
- if (skb->len < 5)
- return;
- }
-
- proto = ((int)data[0]<<8) + data[1];
- if (proto != PPP_CCP && proto != PPP_CCPFRAG)
- return;
-
- printk(KERN_DEBUG "Received CCP frame from daemon:\n");
- isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
-
- if (lp->master) {
- slot = ISDN_MASTER_PRIV(lp)->ppp_slot;
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: slot(%d) out of range\n",
- __func__, slot);
- return;
- }
- mis = ippp_table[slot];
- } else
- mis = is;
- if (mis != is)
- printk(KERN_DEBUG "isdn_ppp: Ouch! Master CCP sends on slave slot!\n");
-
- switch (data[2]) {
- case CCP_CONFREQ:
- if (is->debug & 0x10)
- printk(KERN_DEBUG "Disable decompression here!\n");
- if (proto == PPP_CCP)
- is->compflags &= ~SC_DECOMP_ON;
- else
- is->compflags &= ~SC_LINK_DECOMP_ON;
- break;
- case CCP_TERMREQ:
- case CCP_TERMACK:
- if (is->debug & 0x10)
- printk(KERN_DEBUG "Disable (de)compression here!\n");
- if (proto == PPP_CCP)
- is->compflags &= ~(SC_DECOMP_ON | SC_COMP_ON);
- else
- is->compflags &= ~(SC_LINK_DECOMP_ON | SC_LINK_COMP_ON);
- break;
- case CCP_CONFACK:
- /* if we SEND an ackowledge we can/must enable the compressor */
- if (is->debug & 0x10)
- printk(KERN_DEBUG "Enable compression here!\n");
- if (proto == PPP_CCP) {
- if (!is->compressor)
- break;
- is->compflags |= SC_COMP_ON;
- } else {
- if (!is->compressor)
- break;
- is->compflags |= SC_LINK_COMP_ON;
- }
- break;
- case CCP_RESETACK:
- /* If we send a ACK we should reset our compressor */
- if (is->debug & 0x10)
- printk(KERN_DEBUG "Reset decompression state here!\n");
- printk(KERN_DEBUG "ResetAck from daemon passed by\n");
- if (proto == PPP_CCP) {
- /* link to master? */
- if (is->compressor && is->comp_stat)
- is->compressor->reset(is->comp_stat, 0, 0,
- NULL, 0, NULL);
- is->compflags &= ~SC_COMP_DISCARD;
- }
- else {
- if (is->link_compressor && is->link_comp_stat)
- is->link_compressor->reset(is->link_comp_stat,
- 0, 0, NULL, 0, NULL);
- is->compflags &= ~SC_LINK_COMP_DISCARD;
- }
- break;
- case CCP_RESETREQ:
- /* Just let it pass by */
- printk(KERN_DEBUG "ResetReq from daemon passed by\n");
- break;
- }
-}
-
-int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc)
-{
- ipc->next = ipc_head;
- ipc->prev = NULL;
- if (ipc_head) {
- ipc_head->prev = ipc;
- }
- ipc_head = ipc;
- return 0;
-}
-
-int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc)
-{
- if (ipc->prev)
- ipc->prev->next = ipc->next;
- else
- ipc_head = ipc->next;
- if (ipc->next)
- ipc->next->prev = ipc->prev;
- ipc->prev = ipc->next = NULL;
- return 0;
-}
-
-static int isdn_ppp_set_compressor(struct ippp_struct *is, struct isdn_ppp_comp_data *data)
-{
- struct isdn_ppp_compressor *ipc = ipc_head;
- int ret;
- void *stat;
- int num = data->num;
-
- if (is->debug & 0x10)
- printk(KERN_DEBUG "[%d] Set %s type %d\n", is->unit,
- (data->flags & IPPP_COMP_FLAG_XMIT) ? "compressor" : "decompressor", num);
-
- /* If is has no valid reset state vector, we cannot allocate a
- decompressor. The decompressor would cause reset transactions
- sooner or later, and they need that vector. */
-
- if (!(data->flags & IPPP_COMP_FLAG_XMIT) && !is->reset) {
- printk(KERN_ERR "ippp_ccp: no reset data structure - can't"
- " allow decompression.\n");
- return -ENOMEM;
- }
-
- while (ipc) {
- if (ipc->num == num) {
- stat = ipc->alloc(data);
- if (stat) {
- ret = ipc->init(stat, data, is->unit, 0);
- if (!ret) {
- printk(KERN_ERR "Can't init (de)compression!\n");
- ipc->free(stat);
- stat = NULL;
- break;
- }
- }
- else {
- printk(KERN_ERR "Can't alloc (de)compression!\n");
- break;
- }
-
- if (data->flags & IPPP_COMP_FLAG_XMIT) {
- if (data->flags & IPPP_COMP_FLAG_LINK) {
- if (is->link_comp_stat)
- is->link_compressor->free(is->link_comp_stat);
- is->link_comp_stat = stat;
- is->link_compressor = ipc;
- }
- else {
- if (is->comp_stat)
- is->compressor->free(is->comp_stat);
- is->comp_stat = stat;
- is->compressor = ipc;
- }
- }
- else {
- if (data->flags & IPPP_COMP_FLAG_LINK) {
- if (is->link_decomp_stat)
- is->link_decompressor->free(is->link_decomp_stat);
- is->link_decomp_stat = stat;
- is->link_decompressor = ipc;
- }
- else {
- if (is->decomp_stat)
- is->decompressor->free(is->decomp_stat);
- is->decomp_stat = stat;
- is->decompressor = ipc;
- }
- }
- return 0;
- }
- ipc = ipc->next;
- }
- return -EINVAL;
-}
diff --git a/drivers/isdn/i4l/isdn_ppp.h b/drivers/isdn/i4l/isdn_ppp.h
deleted file mode 100644
index 34b8a2ce84f3..000000000000
--- a/drivers/isdn/i4l/isdn_ppp.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* $Id: isdn_ppp.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * header for Linux ISDN subsystem, functions for synchronous PPP (linklevel).
- *
- * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/ppp_defs.h> /* for PPP_PROTOCOL */
-#include <linux/isdn_ppp.h> /* for isdn_ppp info */
-
-extern int isdn_ppp_read(int, struct file *, char __user *, int);
-extern int isdn_ppp_write(int, struct file *, const char __user *, int);
-extern int isdn_ppp_open(int, struct file *);
-extern int isdn_ppp_init(void);
-extern void isdn_ppp_cleanup(void);
-extern int isdn_ppp_free(isdn_net_local *);
-extern int isdn_ppp_bind(isdn_net_local *);
-extern int isdn_ppp_autodial_filter(struct sk_buff *, isdn_net_local *);
-extern int isdn_ppp_xmit(struct sk_buff *, struct net_device *);
-extern void isdn_ppp_receive(isdn_net_dev *, isdn_net_local *, struct sk_buff *);
-extern int isdn_ppp_dev_ioctl(struct net_device *, struct ifreq *, int);
-extern __poll_t isdn_ppp_poll(struct file *, struct poll_table_struct *);
-extern int isdn_ppp_ioctl(int, struct file *, unsigned int, unsigned long);
-extern void isdn_ppp_release(int, struct file *);
-extern int isdn_ppp_dial_slave(char *);
-extern void isdn_ppp_wakeup_daemon(isdn_net_local *);
-
-extern int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc);
-extern int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc);
-
-#define IPPP_OPEN 0x01
-#define IPPP_CONNECT 0x02
-#define IPPP_CLOSEWAIT 0x04
-#define IPPP_NOBLOCK 0x08
-#define IPPP_ASSIGNED 0x10
-
-#define IPPP_MAX_HEADER 10
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
deleted file mode 100644
index 43700fc19a31..000000000000
--- a/drivers/isdn/i4l/isdn_tty.c
+++ /dev/null
@@ -1,3756 +0,0 @@
-/*
- * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
- *
- * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-#undef ISDN_TTY_STAT_DEBUG
-
-#include <linux/isdn.h>
-#include <linux/serial.h> /* ASYNC_* flags */
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
-#include <linux/sched/signal.h>
-#include "isdn_common.h"
-#include "isdn_tty.h"
-#ifdef CONFIG_ISDN_AUDIO
-#include "isdn_audio.h"
-#define VBUF 0x3e0
-#define VBUFX (VBUF/16)
-#endif
-
-#define FIX_FILE_TRANSFER
-#define DUMMY_HAYES_AT
-
-/* Prototypes */
-
-static DEFINE_MUTEX(modem_info_mutex);
-static int isdn_tty_edit_at(const char *, int, modem_info *);
-static void isdn_tty_check_esc(const u_char *, u_char, int, int *, u_long *);
-static void isdn_tty_modem_reset_regs(modem_info *, int);
-static void isdn_tty_cmd_ATA(modem_info *);
-static void isdn_tty_flush_buffer(struct tty_struct *);
-static void isdn_tty_modem_result(int, modem_info *);
-#ifdef CONFIG_ISDN_AUDIO
-static int isdn_tty_countDLE(unsigned char *, int);
-#endif
-
-/* Leave this unchanged unless you know what you do! */
-#define MODEM_PARANOIA_CHECK
-#define MODEM_DO_RESTART
-
-static int bit2si[8] =
-{1, 5, 7, 7, 7, 7, 7, 7};
-static int si2bit[8] =
-{4, 1, 4, 4, 4, 4, 4, 4};
-
-/* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
- * to stuff incoming data directly into a tty's flip-buffer. This
- * is done to speed up tty-receiving if the receive-queue is empty.
- * This routine MUST be called with interrupts off.
- * Return:
- * 1 = Success
- * 0 = Failure, data has to be buffered and later processed by
- * isdn_tty_readmodem().
- */
-static int
-isdn_tty_try_read(modem_info *info, struct sk_buff *skb)
-{
- struct tty_port *port = &info->port;
- int c;
- int len;
- char last;
-
- if (!info->online)
- return 0;
-
- if (!(info->mcr & UART_MCR_RTS))
- return 0;
-
- len = skb->len
-#ifdef CONFIG_ISDN_AUDIO
- + ISDN_AUDIO_SKB_DLECOUNT(skb)
-#endif
- ;
-
- c = tty_buffer_request_room(port, len);
- if (c < len)
- return 0;
-
-#ifdef CONFIG_ISDN_AUDIO
- if (ISDN_AUDIO_SKB_DLECOUNT(skb)) {
- int l = skb->len;
- unsigned char *dp = skb->data;
- while (--l) {
- if (*dp == DLE)
- tty_insert_flip_char(port, DLE, 0);
- tty_insert_flip_char(port, *dp++, 0);
- }
- if (*dp == DLE)
- tty_insert_flip_char(port, DLE, 0);
- last = *dp;
- } else {
-#endif
- if (len > 1)
- tty_insert_flip_string(port, skb->data, len - 1);
- last = skb->data[len - 1];
-#ifdef CONFIG_ISDN_AUDIO
- }
-#endif
- if (info->emu.mdmreg[REG_CPPP] & BIT_CPPP)
- tty_insert_flip_char(port, last, 0xFF);
- else
- tty_insert_flip_char(port, last, TTY_NORMAL);
- tty_flip_buffer_push(port);
- kfree_skb(skb);
-
- return 1;
-}
-
-/* isdn_tty_readmodem() is called periodically from within timer-interrupt.
- * It tries getting received data from the receive queue an stuff it into
- * the tty's flip-buffer.
- */
-void
-isdn_tty_readmodem(void)
-{
- int resched = 0;
- int midx;
- int i;
- int r;
- modem_info *info;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- midx = dev->m_idx[i];
- if (midx < 0)
- continue;
-
- info = &dev->mdm.info[midx];
- if (!info->online)
- continue;
-
- r = 0;
-#ifdef CONFIG_ISDN_AUDIO
- isdn_audio_eval_dtmf(info);
- if ((info->vonline & 1) && (info->emu.vpar[1]))
- isdn_audio_eval_silence(info);
-#endif
- if (info->mcr & UART_MCR_RTS) {
- /* CISCO AsyncPPP Hack */
- if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
- r = isdn_readbchan_tty(info->isdn_driver,
- info->isdn_channel,
- &info->port, 0);
- else
- r = isdn_readbchan_tty(info->isdn_driver,
- info->isdn_channel,
- &info->port, 1);
- if (r)
- tty_flip_buffer_push(&info->port);
- } else
- r = 1;
-
- if (r) {
- info->rcvsched = 0;
- resched = 1;
- } else
- info->rcvsched = 1;
- }
- if (!resched)
- isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 0);
-}
-
-int
-isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb)
-{
- ulong flags;
- int midx;
-#ifdef CONFIG_ISDN_AUDIO
- int ifmt;
-#endif
- modem_info *info;
-
- if ((midx = dev->m_idx[i]) < 0) {
- /* if midx is invalid, packet is not for tty */
- return 0;
- }
- info = &dev->mdm.info[midx];
-#ifdef CONFIG_ISDN_AUDIO
- ifmt = 1;
-
- if ((info->vonline) && (!info->emu.vpar[4]))
- isdn_audio_calc_dtmf(info, skb->data, skb->len, ifmt);
- if ((info->vonline & 1) && (info->emu.vpar[1]))
- isdn_audio_calc_silence(info, skb->data, skb->len, ifmt);
-#endif
- if ((info->online < 2)
-#ifdef CONFIG_ISDN_AUDIO
- && (!(info->vonline & 1))
-#endif
- ) {
- /* If Modem not listening, drop data */
- kfree_skb(skb);
- return 1;
- }
- if (info->emu.mdmreg[REG_T70] & BIT_T70) {
- if (info->emu.mdmreg[REG_T70] & BIT_T70_EXT) {
- /* T.70 decoding: throw away the T.70 header (2 or 4 bytes) */
- if (skb->data[0] == 3) /* pure data packet -> 4 byte headers */
- skb_pull(skb, 4);
- else
- if (skb->data[0] == 1) /* keepalive packet -> 2 byte hdr */
- skb_pull(skb, 2);
- } else
- /* T.70 decoding: Simply throw away the T.70 header (4 bytes) */
- if ((skb->data[0] == 1) && ((skb->data[1] == 0) || (skb->data[1] == 1)))
- skb_pull(skb, 4);
- }
-#ifdef CONFIG_ISDN_AUDIO
- ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
- ISDN_AUDIO_SKB_LOCK(skb) = 0;
- if (info->vonline & 1) {
- /* voice conversion/compression */
- switch (info->emu.vpar[3]) {
- case 2:
- case 3:
- case 4:
- /* adpcm
- * Since compressed data takes less
- * space, we can overwrite the buffer.
- */
- skb_trim(skb, isdn_audio_xlaw2adpcm(info->adpcmr,
- ifmt,
- skb->data,
- skb->data,
- skb->len));
- break;
- case 5:
- /* a-law */
- if (!ifmt)
- isdn_audio_ulaw2alaw(skb->data, skb->len);
- break;
- case 6:
- /* u-law */
- if (ifmt)
- isdn_audio_alaw2ulaw(skb->data, skb->len);
- break;
- }
- ISDN_AUDIO_SKB_DLECOUNT(skb) =
- isdn_tty_countDLE(skb->data, skb->len);
- }
-#ifdef CONFIG_ISDN_TTY_FAX
- else {
- if (info->faxonline & 2) {
- isdn_tty_fax_bitorder(info, skb);
- ISDN_AUDIO_SKB_DLECOUNT(skb) =
- isdn_tty_countDLE(skb->data, skb->len);
- }
- }
-#endif
-#endif
- /* Try to deliver directly via tty-buf if queue is empty */
- spin_lock_irqsave(&info->readlock, flags);
- if (skb_queue_empty(&dev->drv[di]->rpqueue[channel]))
- if (isdn_tty_try_read(info, skb)) {
- spin_unlock_irqrestore(&info->readlock, flags);
- return 1;
- }
- /* Direct deliver failed or queue wasn't empty.
- * Queue up for later dequeueing via timer-irq.
- */
- __skb_queue_tail(&dev->drv[di]->rpqueue[channel], skb);
- dev->drv[di]->rcvcount[channel] +=
- (skb->len
-#ifdef CONFIG_ISDN_AUDIO
- + ISDN_AUDIO_SKB_DLECOUNT(skb)
-#endif
- );
- spin_unlock_irqrestore(&info->readlock, flags);
- /* Schedule dequeuing */
- if ((dev->modempoll) && (info->rcvsched))
- isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
- return 1;
-}
-
-static void
-isdn_tty_cleanup_xmit(modem_info *info)
-{
- skb_queue_purge(&info->xmit_queue);
-#ifdef CONFIG_ISDN_AUDIO
- skb_queue_purge(&info->dtmf_queue);
-#endif
-}
-
-static void
-isdn_tty_tint(modem_info *info)
-{
- struct sk_buff *skb = skb_dequeue(&info->xmit_queue);
- int len, slen;
-
- if (!skb)
- return;
- len = skb->len;
- if ((slen = isdn_writebuf_skb_stub(info->isdn_driver,
- info->isdn_channel, 1, skb)) == len) {
- struct tty_struct *tty = info->port.tty;
- info->send_outstanding++;
- info->msr &= ~UART_MSR_CTS;
- info->lsr &= ~UART_LSR_TEMT;
- tty_wakeup(tty);
- return;
- }
- if (slen < 0) {
- /* Error: no channel, already shutdown, or wrong parameter */
- dev_kfree_skb(skb);
- return;
- }
- skb_queue_head(&info->xmit_queue, skb);
-}
-
-#ifdef CONFIG_ISDN_AUDIO
-static int
-isdn_tty_countDLE(unsigned char *buf, int len)
-{
- int count = 0;
-
- while (len--)
- if (*buf++ == DLE)
- count++;
- return count;
-}
-
-/* This routine is called from within isdn_tty_write() to perform
- * DLE-decoding when sending audio-data.
- */
-static int
-isdn_tty_handleDLEdown(modem_info *info, atemu *m, int len)
-{
- unsigned char *p = &info->port.xmit_buf[info->xmit_count];
- int count = 0;
-
- while (len > 0) {
- if (m->lastDLE) {
- m->lastDLE = 0;
- switch (*p) {
- case DLE:
- /* Escape code */
- if (len > 1)
- memmove(p, p + 1, len - 1);
- p--;
- count++;
- break;
- case ETX:
- /* End of data */
- info->vonline |= 4;
- return count;
- case DC4:
- /* Abort RX */
- info->vonline &= ~1;
-#ifdef ISDN_DEBUG_MODEM_VOICE
- printk(KERN_DEBUG
- "DLEdown: got DLE-DC4, send DLE-ETX on ttyI%d\n",
- info->line);
-#endif
- isdn_tty_at_cout("\020\003", info);
- if (!info->vonline) {
-#ifdef ISDN_DEBUG_MODEM_VOICE
- printk(KERN_DEBUG
- "DLEdown: send VCON on ttyI%d\n",
- info->line);
-#endif
- isdn_tty_at_cout("\r\nVCON\r\n", info);
- }
- /* Fall through */
- case 'q':
- case 's':
- /* Silence */
- if (len > 1)
- memmove(p, p + 1, len - 1);
- p--;
- break;
- }
- } else {
- if (*p == DLE)
- m->lastDLE = 1;
- else
- count++;
- }
- p++;
- len--;
- }
- if (len < 0) {
- printk(KERN_WARNING "isdn_tty: len<0 in DLEdown\n");
- return 0;
- }
- return count;
-}
-
-/* This routine is called from within isdn_tty_write() when receiving
- * audio-data. It interrupts receiving, if an character other than
- * ^S or ^Q is sent.
- */
-static int
-isdn_tty_end_vrx(const char *buf, int c)
-{
- char ch;
-
- while (c--) {
- ch = *buf;
- if ((ch != 0x11) && (ch != 0x13))
- return 1;
- buf++;
- }
- return 0;
-}
-
-static int voice_cf[7] =
-{0, 0, 4, 3, 2, 0, 0};
-
-#endif /* CONFIG_ISDN_AUDIO */
-
-/* isdn_tty_senddown() is called either directly from within isdn_tty_write()
- * or via timer-interrupt from within isdn_tty_modem_xmit(). It pulls
- * outgoing data from the tty's xmit-buffer, handles voice-decompression or
- * T.70 if necessary, and finally queues it up for sending via isdn_tty_tint.
- */
-static void
-isdn_tty_senddown(modem_info *info)
-{
- int buflen;
- int skb_res;
-#ifdef CONFIG_ISDN_AUDIO
- int audio_len;
-#endif
- struct sk_buff *skb;
-
-#ifdef CONFIG_ISDN_AUDIO
- if (info->vonline & 4) {
- info->vonline &= ~6;
- if (!info->vonline) {
-#ifdef ISDN_DEBUG_MODEM_VOICE
- printk(KERN_DEBUG
- "senddown: send VCON on ttyI%d\n",
- info->line);
-#endif
- isdn_tty_at_cout("\r\nVCON\r\n", info);
- }
- }
-#endif
- if (!(buflen = info->xmit_count))
- return;
- if ((info->emu.mdmreg[REG_CTS] & BIT_CTS) != 0)
- info->msr &= ~UART_MSR_CTS;
- info->lsr &= ~UART_LSR_TEMT;
- /* info->xmit_count is modified here and in isdn_tty_write().
- * So we return here if isdn_tty_write() is in the
- * critical section.
- */
- atomic_inc(&info->xmit_lock);
- if (!(atomic_dec_and_test(&info->xmit_lock)))
- return;
- if (info->isdn_driver < 0) {
- info->xmit_count = 0;
- return;
- }
- skb_res = dev->drv[info->isdn_driver]->interface->hl_hdrlen + 4;
-#ifdef CONFIG_ISDN_AUDIO
- if (info->vonline & 2)
- audio_len = buflen * voice_cf[info->emu.vpar[3]];
- else
- audio_len = 0;
- skb = dev_alloc_skb(skb_res + buflen + audio_len);
-#else
- skb = dev_alloc_skb(skb_res + buflen);
-#endif
- if (!skb) {
- printk(KERN_WARNING
- "isdn_tty: Out of memory in ttyI%d senddown\n",
- info->line);
- return;
- }
- skb_reserve(skb, skb_res);
- skb_put_data(skb, info->port.xmit_buf, buflen);
- info->xmit_count = 0;
-#ifdef CONFIG_ISDN_AUDIO
- if (info->vonline & 2) {
- /* For now, ifmt is fixed to 1 (alaw), since this
- * is used with ISDN everywhere in the world, except
- * US, Canada and Japan.
- * Later, when US-ISDN protocols are implemented,
- * this setting will depend on the D-channel protocol.
- */
- int ifmt = 1;
-
- /* voice conversion/decompression */
- switch (info->emu.vpar[3]) {
- case 2:
- case 3:
- case 4:
- /* adpcm, compatible to ZyXel 1496 modem
- * with ROM revision 6.01
- */
- audio_len = isdn_audio_adpcm2xlaw(info->adpcms,
- ifmt,
- skb->data,
- skb_put(skb, audio_len),
- buflen);
- skb_pull(skb, buflen);
- skb_trim(skb, audio_len);
- break;
- case 5:
- /* a-law */
- if (!ifmt)
- isdn_audio_alaw2ulaw(skb->data,
- buflen);
- break;
- case 6:
- /* u-law */
- if (ifmt)
- isdn_audio_ulaw2alaw(skb->data,
- buflen);
- break;
- }
- }
-#endif /* CONFIG_ISDN_AUDIO */
- if (info->emu.mdmreg[REG_T70] & BIT_T70) {
- /* Add T.70 simplified header */
- if (info->emu.mdmreg[REG_T70] & BIT_T70_EXT)
- memcpy(skb_push(skb, 2), "\1\0", 2);
- else
- memcpy(skb_push(skb, 4), "\1\0\1\0", 4);
- }
- skb_queue_tail(&info->xmit_queue, skb);
-}
-
-/************************************************************
- *
- * Modem-functions
- *
- * mostly "stolen" from original Linux-serial.c and friends.
- *
- ************************************************************/
-
-/* The next routine is called once from within timer-interrupt
- * triggered within isdn_tty_modem_ncarrier(). It calls
- * isdn_tty_modem_result() to stuff a "NO CARRIER" Message
- * into the tty's buffer.
- */
-static void
-isdn_tty_modem_do_ncarrier(struct timer_list *t)
-{
- modem_info *info = from_timer(info, t, nc_timer);
- isdn_tty_modem_result(RESULT_NO_CARRIER, info);
-}
-
-/* Next routine is called, whenever the DTR-signal is raised.
- * It checks the ncarrier-flag, and triggers the above routine
- * when necessary. The ncarrier-flag is set, whenever DTR goes
- * low.
- */
-static void
-isdn_tty_modem_ncarrier(modem_info *info)
-{
- if (info->ncarrier) {
- info->nc_timer.expires = jiffies + HZ;
- add_timer(&info->nc_timer);
- }
-}
-
-/*
- * return the usage calculated by si and layer 2 protocol
- */
-static int
-isdn_calc_usage(int si, int l2)
-{
- int usg = ISDN_USAGE_MODEM;
-
-#ifdef CONFIG_ISDN_AUDIO
- if (si == 1) {
- switch (l2) {
- case ISDN_PROTO_L2_MODEM:
- usg = ISDN_USAGE_MODEM;
- break;
-#ifdef CONFIG_ISDN_TTY_FAX
- case ISDN_PROTO_L2_FAX:
- usg = ISDN_USAGE_FAX;
- break;
-#endif
- case ISDN_PROTO_L2_TRANS:
- default:
- usg = ISDN_USAGE_VOICE;
- break;
- }
- }
-#endif
- return (usg);
-}
-
-/* isdn_tty_dial() performs dialing of a tty an the necessary
- * setup of the lower levels before that.
- */
-static void
-isdn_tty_dial(char *n, modem_info *info, atemu *m)
-{
- int usg = ISDN_USAGE_MODEM;
- int si = 7;
- int l2 = m->mdmreg[REG_L2PROT];
- u_long flags;
- isdn_ctrl cmd;
- int i;
- int j;
-
- for (j = 7; j >= 0; j--)
- if (m->mdmreg[REG_SI1] & (1 << j)) {
- si = bit2si[j];
- break;
- }
- usg = isdn_calc_usage(si, l2);
-#ifdef CONFIG_ISDN_AUDIO
- if ((si == 1) &&
- (l2 != ISDN_PROTO_L2_MODEM)
-#ifdef CONFIG_ISDN_TTY_FAX
- && (l2 != ISDN_PROTO_L2_FAX)
-#endif
- ) {
- l2 = ISDN_PROTO_L2_TRANS;
- usg = ISDN_USAGE_VOICE;
- }
-#endif
- m->mdmreg[REG_SI1I] = si2bit[si];
- spin_lock_irqsave(&dev->lock, flags);
- i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
- if (i < 0) {
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
- } else {
- info->isdn_driver = dev->drvmap[i];
- info->isdn_channel = dev->chanmap[i];
- info->drv_index = i;
- dev->m_idx[i] = info->line;
- dev->usage[i] |= ISDN_USAGE_OUTGOING;
- info->last_dir = 1;
- strcpy(info->last_num, n);
- isdn_info_update();
- spin_unlock_irqrestore(&dev->lock, flags);
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- cmd.command = ISDN_CMD_CLREAZ;
- isdn_command(&cmd);
- strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETEAZ;
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETL2;
- info->last_l2 = l2;
- cmd.arg = info->isdn_channel + (l2 << 8);
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETL3;
- cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
-#ifdef CONFIG_ISDN_TTY_FAX
- if (l2 == ISDN_PROTO_L2_FAX) {
- cmd.parm.fax = info->fax;
- info->fax->direction = ISDN_TTY_FAX_CONN_OUT;
- }
-#endif
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- sprintf(cmd.parm.setup.phone, "%s", n);
- sprintf(cmd.parm.setup.eazmsn, "%s",
- isdn_map_eaz2msn(m->msn, info->isdn_driver));
- cmd.parm.setup.si1 = si;
- cmd.parm.setup.si2 = m->mdmreg[REG_SI2];
- cmd.command = ISDN_CMD_DIAL;
- info->dialing = 1;
- info->emu.carrierwait = 0;
- strcpy(dev->num[i], n);
- isdn_info_update();
- isdn_command(&cmd);
- isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
- }
-}
-
-/* isdn_tty_hangup() disassociates a tty from the real
- * ISDN-line (hangup). The usage-status is cleared
- * and some cleanup is done also.
- */
-void
-isdn_tty_modem_hup(modem_info *info, int local)
-{
- isdn_ctrl cmd;
- int di, ch;
-
- if (!info)
- return;
-
- di = info->isdn_driver;
- ch = info->isdn_channel;
- if (di < 0 || ch < 0)
- return;
-
- info->isdn_driver = -1;
- info->isdn_channel = -1;
-
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup ttyI%d\n", info->line);
-#endif
- info->rcvsched = 0;
- isdn_tty_flush_buffer(info->port.tty);
- if (info->online) {
- info->last_lhup = local;
- info->online = 0;
- isdn_tty_modem_result(RESULT_NO_CARRIER, info);
- }
-#ifdef CONFIG_ISDN_AUDIO
- info->vonline = 0;
-#ifdef CONFIG_ISDN_TTY_FAX
- info->faxonline = 0;
- info->fax->phase = ISDN_FAX_PHASE_IDLE;
-#endif
- info->emu.vpar[4] = 0;
- info->emu.vpar[5] = 8;
- kfree(info->dtmf_state);
- info->dtmf_state = NULL;
- kfree(info->silence_state);
- info->silence_state = NULL;
- kfree(info->adpcms);
- info->adpcms = NULL;
- kfree(info->adpcmr);
- info->adpcmr = NULL;
-#endif
- if ((info->msr & UART_MSR_RI) &&
- (info->emu.mdmreg[REG_RUNG] & BIT_RUNG))
- isdn_tty_modem_result(RESULT_RUNG, info);
- info->msr &= ~(UART_MSR_DCD | UART_MSR_RI);
- info->lsr |= UART_LSR_TEMT;
-
- if (local) {
- cmd.driver = di;
- cmd.command = ISDN_CMD_HANGUP;
- cmd.arg = ch;
- isdn_command(&cmd);
- }
-
- isdn_all_eaz(di, ch);
- info->emu.mdmreg[REG_RINGCNT] = 0;
- isdn_free_channel(di, ch, 0);
-
- if (info->drv_index >= 0) {
- dev->m_idx[info->drv_index] = -1;
- info->drv_index = -1;
- }
-}
-
-/*
- * Begin of a CAPI like interface, currently used only for
- * supplementary service (CAPI 2.0 part III)
- */
-#include <linux/isdn/capicmd.h>
-#include <linux/module.h>
-
-int
-isdn_tty_capi_facility(capi_msg *cm) {
- return (-1); /* dummy */
-}
-
-/* isdn_tty_suspend() tries to suspend the current tty connection
- */
-static void
-isdn_tty_suspend(char *id, modem_info *info, atemu *m)
-{
- isdn_ctrl cmd;
-
- int l;
-
- if (!info)
- return;
-
-#ifdef ISDN_DEBUG_MODEM_SERVICES
- printk(KERN_DEBUG "Msusp ttyI%d\n", info->line);
-#endif
- l = strlen(id);
- if ((info->isdn_driver >= 0)) {
- cmd.parm.cmsg.Length = l + 18;
- cmd.parm.cmsg.Command = CAPI_FACILITY;
- cmd.parm.cmsg.Subcommand = CAPI_REQ;
- cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
- cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */
- cmd.parm.cmsg.para[1] = 0;
- cmd.parm.cmsg.para[2] = l + 3;
- cmd.parm.cmsg.para[3] = 4; /* 16 bit 0x0004 Suspend */
- cmd.parm.cmsg.para[4] = 0;
- cmd.parm.cmsg.para[5] = l;
- memcpy(&cmd.parm.cmsg.para[6], id, l);
- cmd.command = CAPI_PUT_MESSAGE;
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- isdn_command(&cmd);
- }
-}
-
-/* isdn_tty_resume() tries to resume a suspended call
- * setup of the lower levels before that. unfortunately here is no
- * checking for compatibility of used protocols implemented by Q931
- * It does the same things like isdn_tty_dial, the last command
- * is different, may be we can merge it.
- */
-
-static void
-isdn_tty_resume(char *id, modem_info *info, atemu *m)
-{
- int usg = ISDN_USAGE_MODEM;
- int si = 7;
- int l2 = m->mdmreg[REG_L2PROT];
- isdn_ctrl cmd;
- ulong flags;
- int i;
- int j;
- int l;
-
- l = strlen(id);
- for (j = 7; j >= 0; j--)
- if (m->mdmreg[REG_SI1] & (1 << j)) {
- si = bit2si[j];
- break;
- }
- usg = isdn_calc_usage(si, l2);
-#ifdef CONFIG_ISDN_AUDIO
- if ((si == 1) &&
- (l2 != ISDN_PROTO_L2_MODEM)
-#ifdef CONFIG_ISDN_TTY_FAX
- && (l2 != ISDN_PROTO_L2_FAX)
-#endif
- ) {
- l2 = ISDN_PROTO_L2_TRANS;
- usg = ISDN_USAGE_VOICE;
- }
-#endif
- m->mdmreg[REG_SI1I] = si2bit[si];
- spin_lock_irqsave(&dev->lock, flags);
- i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
- if (i < 0) {
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
- } else {
- info->isdn_driver = dev->drvmap[i];
- info->isdn_channel = dev->chanmap[i];
- info->drv_index = i;
- dev->m_idx[i] = info->line;
- dev->usage[i] |= ISDN_USAGE_OUTGOING;
- info->last_dir = 1;
-// strcpy(info->last_num, n);
- isdn_info_update();
- spin_unlock_irqrestore(&dev->lock, flags);
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- cmd.command = ISDN_CMD_CLREAZ;
- isdn_command(&cmd);
- strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETEAZ;
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETL2;
- info->last_l2 = l2;
- cmd.arg = info->isdn_channel + (l2 << 8);
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETL3;
- cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- cmd.parm.cmsg.Length = l + 18;
- cmd.parm.cmsg.Command = CAPI_FACILITY;
- cmd.parm.cmsg.Subcommand = CAPI_REQ;
- cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
- cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */
- cmd.parm.cmsg.para[1] = 0;
- cmd.parm.cmsg.para[2] = l + 3;
- cmd.parm.cmsg.para[3] = 5; /* 16 bit 0x0005 Resume */
- cmd.parm.cmsg.para[4] = 0;
- cmd.parm.cmsg.para[5] = l;
- memcpy(&cmd.parm.cmsg.para[6], id, l);
- cmd.command = CAPI_PUT_MESSAGE;
- info->dialing = 1;
-// strcpy(dev->num[i], n);
- isdn_info_update();
- isdn_command(&cmd);
- isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
- }
-}
-
-/* isdn_tty_send_msg() sends a message to a HL driver
- * This is used for hybrid modem cards to send AT commands to it
- */
-
-static void
-isdn_tty_send_msg(modem_info *info, atemu *m, char *msg)
-{
- int usg = ISDN_USAGE_MODEM;
- int si = 7;
- int l2 = m->mdmreg[REG_L2PROT];
- isdn_ctrl cmd;
- ulong flags;
- int i;
- int j;
- int l;
-
- l = min(strlen(msg), sizeof(cmd.parm) - sizeof(cmd.parm.cmsg)
- + sizeof(cmd.parm.cmsg.para) - 2);
-
- if (!l) {
- isdn_tty_modem_result(RESULT_ERROR, info);
- return;
- }
- for (j = 7; j >= 0; j--)
- if (m->mdmreg[REG_SI1] & (1 << j)) {
- si = bit2si[j];
- break;
- }
- usg = isdn_calc_usage(si, l2);
-#ifdef CONFIG_ISDN_AUDIO
- if ((si == 1) &&
- (l2 != ISDN_PROTO_L2_MODEM)
-#ifdef CONFIG_ISDN_TTY_FAX
- && (l2 != ISDN_PROTO_L2_FAX)
-#endif
- ) {
- l2 = ISDN_PROTO_L2_TRANS;
- usg = ISDN_USAGE_VOICE;
- }
-#endif
- m->mdmreg[REG_SI1I] = si2bit[si];
- spin_lock_irqsave(&dev->lock, flags);
- i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
- if (i < 0) {
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
- } else {
- info->isdn_driver = dev->drvmap[i];
- info->isdn_channel = dev->chanmap[i];
- info->drv_index = i;
- dev->m_idx[i] = info->line;
- dev->usage[i] |= ISDN_USAGE_OUTGOING;
- info->last_dir = 1;
- isdn_info_update();
- spin_unlock_irqrestore(&dev->lock, flags);
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- cmd.command = ISDN_CMD_CLREAZ;
- isdn_command(&cmd);
- strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETEAZ;
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETL2;
- info->last_l2 = l2;
- cmd.arg = info->isdn_channel + (l2 << 8);
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETL3;
- cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- cmd.parm.cmsg.Length = l + 14;
- cmd.parm.cmsg.Command = CAPI_MANUFACTURER;
- cmd.parm.cmsg.Subcommand = CAPI_REQ;
- cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
- cmd.parm.cmsg.para[0] = l + 1;
- strncpy(&cmd.parm.cmsg.para[1], msg, l);
- cmd.parm.cmsg.para[l + 1] = 0xd;
- cmd.command = CAPI_PUT_MESSAGE;
-/* info->dialing = 1;
- strcpy(dev->num[i], n);
- isdn_info_update();
-*/
- isdn_command(&cmd);
- }
-}
-
-static inline int
-isdn_tty_paranoia_check(modem_info *info, char *name, const char *routine)
-{
-#ifdef MODEM_PARANOIA_CHECK
- if (!info) {
- printk(KERN_WARNING "isdn_tty: null info_struct for %s in %s\n",
- name, routine);
- return 1;
- }
- if (info->magic != ISDN_ASYNC_MAGIC) {
- printk(KERN_WARNING "isdn_tty: bad magic for modem struct %s in %s\n",
- name, routine);
- return 1;
- }
-#endif
- return 0;
-}
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static void
-isdn_tty_change_speed(modem_info *info)
-{
- struct tty_port *port = &info->port;
- uint cflag,
- cval,
- quot;
- int i;
-
- if (!port->tty)
- return;
- cflag = port->tty->termios.c_cflag;
-
- quot = i = cflag & CBAUD;
- if (i & CBAUDEX) {
- i &= ~CBAUDEX;
- if (i < 1 || i > 2)
- port->tty->termios.c_cflag &= ~CBAUDEX;
- else
- i += 15;
- }
- if (quot) {
- info->mcr |= UART_MCR_DTR;
- isdn_tty_modem_ncarrier(info);
- } else {
- info->mcr &= ~UART_MCR_DTR;
- if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup in changespeed\n");
-#endif
- if (info->online)
- info->ncarrier = 1;
- isdn_tty_modem_reset_regs(info, 0);
- isdn_tty_modem_hup(info, 1);
- }
- return;
- }
- /* byte size and parity */
- cval = cflag & (CSIZE | CSTOPB);
- cval >>= 4;
- if (cflag & PARENB)
- cval |= UART_LCR_PARITY;
- if (!(cflag & PARODD))
- cval |= UART_LCR_EPAR;
-
- tty_port_set_check_carrier(port, ~cflag & CLOCAL);
-}
-
-static int
-isdn_tty_startup(modem_info *info)
-{
- if (tty_port_initialized(&info->port))
- return 0;
- isdn_lock_drivers();
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "starting up ttyi%d ...\n", info->line);
-#endif
- /*
- * Now, initialize the UART
- */
- info->mcr = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
- if (info->port.tty)
- clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
- /*
- * and set the speed of the serial port
- */
- isdn_tty_change_speed(info);
-
- tty_port_set_initialized(&info->port, 1);
- info->msr |= (UART_MSR_DSR | UART_MSR_CTS);
- info->send_outstanding = 0;
- return 0;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void
-isdn_tty_shutdown(modem_info *info)
-{
- if (!tty_port_initialized(&info->port))
- return;
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "Shutting down isdnmodem port %d ....\n", info->line);
-#endif
- isdn_unlock_drivers();
- info->msr &= ~UART_MSR_RI;
- if (!info->port.tty || (info->port.tty->termios.c_cflag & HUPCL)) {
- info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
- if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
- isdn_tty_modem_reset_regs(info, 0);
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup in isdn_tty_shutdown\n");
-#endif
- isdn_tty_modem_hup(info, 1);
- }
- }
- if (info->port.tty)
- set_bit(TTY_IO_ERROR, &info->port.tty->flags);
-
- tty_port_set_initialized(&info->port, 0);
-}
-
-/* isdn_tty_write() is the main send-routine. It is called from the upper
- * levels within the kernel to perform sending data. Depending on the
- * online-flag it either directs output to the at-command-interpreter or
- * to the lower level. Additional tasks done here:
- * - If online, check for escape-sequence (+++)
- * - If sending audio-data, call isdn_tty_DLEdown() to parse DLE-codes.
- * - If receiving audio-data, call isdn_tty_end_vrx() to abort if needed.
- * - If dialing, abort dial.
- */
-static int
-isdn_tty_write(struct tty_struct *tty, const u_char *buf, int count)
-{
- int c;
- int total = 0;
- modem_info *info = (modem_info *) tty->driver_data;
- atemu *m = &info->emu;
-
- if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_write"))
- return 0;
- /* See isdn_tty_senddown() */
- atomic_inc(&info->xmit_lock);
- while (1) {
- c = count;
- if (c > info->xmit_size - info->xmit_count)
- c = info->xmit_size - info->xmit_count;
- if (info->isdn_driver >= 0 && c > dev->drv[info->isdn_driver]->maxbufsize)
- c = dev->drv[info->isdn_driver]->maxbufsize;
- if (c <= 0)
- break;
- if ((info->online > 1)
-#ifdef CONFIG_ISDN_AUDIO
- || (info->vonline & 3)
-#endif
- ) {
-#ifdef CONFIG_ISDN_AUDIO
- if (!info->vonline)
-#endif
- isdn_tty_check_esc(buf, m->mdmreg[REG_ESC], c,
- &(m->pluscount),
- &(m->lastplus));
- memcpy(&info->port.xmit_buf[info->xmit_count], buf, c);
-#ifdef CONFIG_ISDN_AUDIO
- if (info->vonline) {
- int cc = isdn_tty_handleDLEdown(info, m, c);
- if (info->vonline & 2) {
- if (!cc) {
- /* If DLE decoding results in zero-transmit, but
- * c originally was non-zero, do a wakeup.
- */
- tty_wakeup(tty);
- info->msr |= UART_MSR_CTS;
- info->lsr |= UART_LSR_TEMT;
- }
- info->xmit_count += cc;
- }
- if ((info->vonline & 3) == 1) {
- /* Do NOT handle Ctrl-Q or Ctrl-S
- * when in full-duplex audio mode.
- */
- if (isdn_tty_end_vrx(buf, c)) {
- info->vonline &= ~1;
-#ifdef ISDN_DEBUG_MODEM_VOICE
- printk(KERN_DEBUG
- "got !^Q/^S, send DLE-ETX,VCON on ttyI%d\n",
- info->line);
-#endif
- isdn_tty_at_cout("\020\003\r\nVCON\r\n", info);
- }
- }
- } else
- if (TTY_IS_FCLASS1(info)) {
- int cc = isdn_tty_handleDLEdown(info, m, c);
-
- if (info->vonline & 4) { /* ETX seen */
- isdn_ctrl c;
-
- c.command = ISDN_CMD_FAXCMD;
- c.driver = info->isdn_driver;
- c.arg = info->isdn_channel;
- c.parm.aux.cmd = ISDN_FAX_CLASS1_CTRL;
- c.parm.aux.subcmd = ETX;
- isdn_command(&c);
- }
- info->vonline = 0;
-#ifdef ISDN_DEBUG_MODEM_VOICE
- printk(KERN_DEBUG "fax dle cc/c %d/%d\n", cc, c);
-#endif
- info->xmit_count += cc;
- } else
-#endif
- info->xmit_count += c;
- } else {
- info->msr |= UART_MSR_CTS;
- info->lsr |= UART_LSR_TEMT;
- if (info->dialing) {
- info->dialing = 0;
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup in isdn_tty_write\n");
-#endif
- isdn_tty_modem_result(RESULT_NO_CARRIER, info);
- isdn_tty_modem_hup(info, 1);
- } else
- c = isdn_tty_edit_at(buf, c, info);
- }
- buf += c;
- count -= c;
- total += c;
- }
- atomic_dec(&info->xmit_lock);
- if ((info->xmit_count) || !skb_queue_empty(&info->xmit_queue)) {
- if (m->mdmreg[REG_DXMT] & BIT_DXMT) {
- isdn_tty_senddown(info);
- isdn_tty_tint(info);
- }
- isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
- }
- return total;
-}
-
-static int
-isdn_tty_write_room(struct tty_struct *tty)
-{
- modem_info *info = (modem_info *) tty->driver_data;
- int ret;
-
- if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_write_room"))
- return 0;
- if (!info->online)
- return info->xmit_size;
- ret = info->xmit_size - info->xmit_count;
- return (ret < 0) ? 0 : ret;
-}
-
-static int
-isdn_tty_chars_in_buffer(struct tty_struct *tty)
-{
- modem_info *info = (modem_info *) tty->driver_data;
-
- if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_chars_in_buffer"))
- return 0;
- if (!info->online)
- return 0;
- return (info->xmit_count);
-}
-
-static void
-isdn_tty_flush_buffer(struct tty_struct *tty)
-{
- modem_info *info;
-
- if (!tty) {
- return;
- }
- info = (modem_info *) tty->driver_data;
- if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_flush_buffer")) {
- return;
- }
- isdn_tty_cleanup_xmit(info);
- info->xmit_count = 0;
- tty_wakeup(tty);
-}
-
-static void
-isdn_tty_flush_chars(struct tty_struct *tty)
-{
- modem_info *info = (modem_info *) tty->driver_data;
-
- if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_flush_chars"))
- return;
- if ((info->xmit_count) || !skb_queue_empty(&info->xmit_queue))
- isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
-}
-
-/*
- * ------------------------------------------------------------
- * isdn_tty_throttle()
- *
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void
-isdn_tty_throttle(struct tty_struct *tty)
-{
- modem_info *info = (modem_info *) tty->driver_data;
-
- if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_throttle"))
- return;
- if (I_IXOFF(tty))
- info->x_char = STOP_CHAR(tty);
- info->mcr &= ~UART_MCR_RTS;
-}
-
-static void
-isdn_tty_unthrottle(struct tty_struct *tty)
-{
- modem_info *info = (modem_info *) tty->driver_data;
-
- if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_unthrottle"))
- return;
- if (I_IXOFF(tty)) {
- if (info->x_char)
- info->x_char = 0;
- else
- info->x_char = START_CHAR(tty);
- }
- info->mcr |= UART_MCR_RTS;
-}
-
-/*
- * ------------------------------------------------------------
- * isdn_tty_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-/*
- * isdn_tty_get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- * is emptied. On bus types like RS485, the transmitter must
- * release the bus after transmitting. This must be done when
- * the transmit shift register is empty, not be done when the
- * transmit holding register is empty. This functionality
- * allows RS485 driver to be written in user space.
- */
-static int
-isdn_tty_get_lsr_info(modem_info *info, uint __user *value)
-{
- u_char status;
- uint result;
-
- status = info->lsr;
- result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
- return put_user(result, value);
-}
-
-
-static int
-isdn_tty_tiocmget(struct tty_struct *tty)
-{
- modem_info *info = (modem_info *) tty->driver_data;
- u_char control, status;
-
- if (isdn_tty_paranoia_check(info, tty->name, __func__))
- return -ENODEV;
- if (tty_io_error(tty))
- return -EIO;
-
- mutex_lock(&modem_info_mutex);
-#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line);
-#endif
-
- control = info->mcr;
- status = info->msr;
- mutex_unlock(&modem_info_mutex);
- return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
- | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
- | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0)
- | ((status & UART_MSR_RI) ? TIOCM_RNG : 0)
- | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0)
- | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
-}
-
-static int
-isdn_tty_tiocmset(struct tty_struct *tty,
- unsigned int set, unsigned int clear)
-{
- modem_info *info = (modem_info *) tty->driver_data;
-
- if (isdn_tty_paranoia_check(info, tty->name, __func__))
- return -ENODEV;
- if (tty_io_error(tty))
- return -EIO;
-
-#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "ttyI%d ioctl TIOCMxxx: %x %x\n", info->line, set, clear);
-#endif
-
- mutex_lock(&modem_info_mutex);
- if (set & TIOCM_RTS)
- info->mcr |= UART_MCR_RTS;
- if (set & TIOCM_DTR) {
- info->mcr |= UART_MCR_DTR;
- isdn_tty_modem_ncarrier(info);
- }
-
- if (clear & TIOCM_RTS)
- info->mcr &= ~UART_MCR_RTS;
- if (clear & TIOCM_DTR) {
- info->mcr &= ~UART_MCR_DTR;
- if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
- isdn_tty_modem_reset_regs(info, 0);
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup in TIOCMSET\n");
-#endif
- if (info->online)
- info->ncarrier = 1;
- isdn_tty_modem_hup(info, 1);
- }
- }
- mutex_unlock(&modem_info_mutex);
- return 0;
-}
-
-static int
-isdn_tty_ioctl(struct tty_struct *tty, uint cmd, ulong arg)
-{
- modem_info *info = (modem_info *) tty->driver_data;
-
- if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_ioctl"))
- return -ENODEV;
- if (tty_io_error(tty))
- return -EIO;
- switch (cmd) {
- case TIOCSERGETLSR: /* Get line status register */
-#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line);
-#endif
- return isdn_tty_get_lsr_info(info, (uint __user *) arg);
- default:
-#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on ttyi%d\n", cmd, info->line);
-#endif
- return -ENOIOCTLCMD;
- }
- return 0;
-}
-
-static void
-isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
-{
- modem_info *info = (modem_info *) tty->driver_data;
-
- mutex_lock(&modem_info_mutex);
- if (!old_termios)
- isdn_tty_change_speed(info);
- else {
- if (tty->termios.c_cflag == old_termios->c_cflag &&
- tty->termios.c_ispeed == old_termios->c_ispeed &&
- tty->termios.c_ospeed == old_termios->c_ospeed) {
- mutex_unlock(&modem_info_mutex);
- return;
- }
- isdn_tty_change_speed(info);
- }
- mutex_unlock(&modem_info_mutex);
-}
-
-/*
- * ------------------------------------------------------------
- * isdn_tty_open() and friends
- * ------------------------------------------------------------
- */
-
-static int isdn_tty_install(struct tty_driver *driver, struct tty_struct *tty)
-{
- modem_info *info = &dev->mdm.info[tty->index];
-
- if (isdn_tty_paranoia_check(info, tty->name, __func__))
- return -ENODEV;
-
- tty->driver_data = info;
-
- return tty_port_install(&info->port, driver, tty);
-}
-
-/*
- * This routine is called whenever a serial port is opened. It
- * enables interrupts for a serial port, linking in its async structure into
- * the IRQ chain. It also performs the serial-specific
- * initialization for the tty structure.
- */
-static int
-isdn_tty_open(struct tty_struct *tty, struct file *filp)
-{
- modem_info *info = tty->driver_data;
- struct tty_port *port = &info->port;
- int retval;
-
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "isdn_tty_open %s, count = %d\n", tty->name,
- port->count);
-#endif
- port->count++;
- port->tty = tty;
- /*
- * Start up serial port
- */
- retval = isdn_tty_startup(info);
- if (retval) {
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "isdn_tty_open return after startup\n");
-#endif
- return retval;
- }
- retval = tty_port_block_til_ready(port, tty, filp);
- if (retval) {
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "isdn_tty_open return after isdn_tty_block_til_ready \n");
-#endif
- return retval;
- }
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "isdn_tty_open ttyi%d successful...\n", info->line);
-#endif
- dev->modempoll++;
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "isdn_tty_open normal exit\n");
-#endif
- return 0;
-}
-
-static void
-isdn_tty_close(struct tty_struct *tty, struct file *filp)
-{
- modem_info *info = (modem_info *) tty->driver_data;
- struct tty_port *port = &info->port;
- ulong timeout;
-
- if (!info || isdn_tty_paranoia_check(info, tty->name, "isdn_tty_close"))
- return;
- if (tty_hung_up_p(filp)) {
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "isdn_tty_close return after tty_hung_up_p\n");
-#endif
- return;
- }
- if ((tty->count == 1) && (port->count != 1)) {
- /*
- * Uh, oh. tty->count is 1, which means that the tty
- * structure will be freed. Info->count should always
- * be one in these conditions. If it's greater than
- * one, we've got real problems, since it means the
- * serial port won't be shutdown.
- */
- printk(KERN_ERR "isdn_tty_close: bad port count; tty->count is 1, "
- "info->count is %d\n", port->count);
- port->count = 1;
- }
- if (--port->count < 0) {
- printk(KERN_ERR "isdn_tty_close: bad port count for ttyi%d: %d\n",
- info->line, port->count);
- port->count = 0;
- }
- if (port->count) {
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "isdn_tty_close after info->count != 0\n");
-#endif
- return;
- }
- info->closing = 1;
-
- tty->closing = 1;
- /*
- * At this point we stop accepting input. To do this, we
- * disable the receive line status interrupts, and tell the
- * interrupt driver to stop checking the data ready bit in the
- * line status register.
- */
- if (tty_port_initialized(port)) {
- tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
- /*
- * Before we drop DTR, make sure the UART transmitter
- * has completely drained; this is especially
- * important if there is a transmit FIFO!
- */
- timeout = jiffies + HZ;
- while (!(info->lsr & UART_LSR_TEMT)) {
- schedule_timeout_interruptible(20);
- if (time_after(jiffies, timeout))
- break;
- }
- }
- dev->modempoll--;
- isdn_tty_shutdown(info);
- isdn_tty_flush_buffer(tty);
- tty_ldisc_flush(tty);
- port->tty = NULL;
- info->ncarrier = 0;
-
- tty_port_close_end(port, tty);
- info->closing = 0;
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "isdn_tty_close normal exit\n");
-#endif
-}
-
-/*
- * isdn_tty_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-static void
-isdn_tty_hangup(struct tty_struct *tty)
-{
- modem_info *info = (modem_info *) tty->driver_data;
- struct tty_port *port = &info->port;
-
- if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_hangup"))
- return;
- isdn_tty_shutdown(info);
- port->count = 0;
- tty_port_set_active(port, 0);
- port->tty = NULL;
- wake_up_interruptible(&port->open_wait);
-}
-
-/* This routine initializes all emulator-data.
- */
-static void
-isdn_tty_reset_profile(atemu *m)
-{
- m->profile[0] = 0;
- m->profile[1] = 0;
- m->profile[2] = 43;
- m->profile[3] = 13;
- m->profile[4] = 10;
- m->profile[5] = 8;
- m->profile[6] = 3;
- m->profile[7] = 60;
- m->profile[8] = 2;
- m->profile[9] = 6;
- m->profile[10] = 7;
- m->profile[11] = 70;
- m->profile[12] = 0x45;
- m->profile[13] = 4;
- m->profile[14] = ISDN_PROTO_L2_X75I;
- m->profile[15] = ISDN_PROTO_L3_TRANS;
- m->profile[16] = ISDN_SERIAL_XMIT_SIZE / 16;
- m->profile[17] = ISDN_MODEM_WINSIZE;
- m->profile[18] = 4;
- m->profile[19] = 0;
- m->profile[20] = 0;
- m->profile[23] = 0;
- m->pmsn[0] = '\0';
- m->plmsn[0] = '\0';
-}
-
-#ifdef CONFIG_ISDN_AUDIO
-static void
-isdn_tty_modem_reset_vpar(atemu *m)
-{
- m->vpar[0] = 2; /* Voice-device (2 = phone line) */
- m->vpar[1] = 0; /* Silence detection level (0 = none ) */
- m->vpar[2] = 70; /* Silence interval (7 sec. ) */
- m->vpar[3] = 2; /* Compression type (1 = ADPCM-2 ) */
- m->vpar[4] = 0; /* DTMF detection level (0 = softcode ) */
- m->vpar[5] = 8; /* DTMF interval (8 * 5 ms. ) */
-}
-#endif
-
-#ifdef CONFIG_ISDN_TTY_FAX
-static void
-isdn_tty_modem_reset_faxpar(modem_info *info)
-{
- T30_s *f = info->fax;
-
- f->code = 0;
- f->phase = ISDN_FAX_PHASE_IDLE;
- f->direction = 0;
- f->resolution = 1; /* fine */
- f->rate = 5; /* 14400 bit/s */
- f->width = 0;
- f->length = 0;
- f->compression = 0;
- f->ecm = 0;
- f->binary = 0;
- f->scantime = 0;
- memset(&f->id[0], 32, FAXIDLEN - 1);
- f->id[FAXIDLEN - 1] = 0;
- f->badlin = 0;
- f->badmul = 0;
- f->bor = 0;
- f->nbc = 0;
- f->cq = 0;
- f->cr = 0;
- f->ctcrty = 0;
- f->minsp = 0;
- f->phcto = 30;
- f->rel = 0;
- memset(&f->pollid[0], 32, FAXIDLEN - 1);
- f->pollid[FAXIDLEN - 1] = 0;
-}
-#endif
-
-static void
-isdn_tty_modem_reset_regs(modem_info *info, int force)
-{
- atemu *m = &info->emu;
- if ((m->mdmreg[REG_DTRR] & BIT_DTRR) || force) {
- memcpy(m->mdmreg, m->profile, ISDN_MODEM_NUMREG);
- memcpy(m->msn, m->pmsn, ISDN_MSNLEN);
- memcpy(m->lmsn, m->plmsn, ISDN_LMSNLEN);
- info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
- }
-#ifdef CONFIG_ISDN_AUDIO
- isdn_tty_modem_reset_vpar(m);
-#endif
-#ifdef CONFIG_ISDN_TTY_FAX
- isdn_tty_modem_reset_faxpar(info);
-#endif
- m->mdmcmdl = 0;
-}
-
-static void
-modem_write_profile(atemu *m)
-{
- memcpy(m->profile, m->mdmreg, ISDN_MODEM_NUMREG);
- memcpy(m->pmsn, m->msn, ISDN_MSNLEN);
- memcpy(m->plmsn, m->lmsn, ISDN_LMSNLEN);
- if (dev->profd)
- send_sig(SIGIO, dev->profd, 1);
-}
-
-static const struct tty_operations modem_ops = {
- .install = isdn_tty_install,
- .open = isdn_tty_open,
- .close = isdn_tty_close,
- .write = isdn_tty_write,
- .flush_chars = isdn_tty_flush_chars,
- .write_room = isdn_tty_write_room,
- .chars_in_buffer = isdn_tty_chars_in_buffer,
- .flush_buffer = isdn_tty_flush_buffer,
- .ioctl = isdn_tty_ioctl,
- .throttle = isdn_tty_throttle,
- .unthrottle = isdn_tty_unthrottle,
- .set_termios = isdn_tty_set_termios,
- .hangup = isdn_tty_hangup,
- .tiocmget = isdn_tty_tiocmget,
- .tiocmset = isdn_tty_tiocmset,
-};
-
-static int isdn_tty_carrier_raised(struct tty_port *port)
-{
- modem_info *info = container_of(port, modem_info, port);
- return info->msr & UART_MSR_DCD;
-}
-
-static const struct tty_port_operations isdn_tty_port_ops = {
- .carrier_raised = isdn_tty_carrier_raised,
-};
-
-int
-isdn_tty_modem_init(void)
-{
- isdn_modem_t *m;
- int i, retval;
- modem_info *info;
-
- m = &dev->mdm;
- m->tty_modem = alloc_tty_driver(ISDN_MAX_CHANNELS);
- if (!m->tty_modem)
- return -ENOMEM;
- m->tty_modem->name = "ttyI";
- m->tty_modem->major = ISDN_TTY_MAJOR;
- m->tty_modem->minor_start = 0;
- m->tty_modem->type = TTY_DRIVER_TYPE_SERIAL;
- m->tty_modem->subtype = SERIAL_TYPE_NORMAL;
- m->tty_modem->init_termios = tty_std_termios;
- m->tty_modem->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- m->tty_modem->flags = TTY_DRIVER_REAL_RAW;
- m->tty_modem->driver_name = "isdn_tty";
- tty_set_operations(m->tty_modem, &modem_ops);
- retval = tty_register_driver(m->tty_modem);
- if (retval) {
- printk(KERN_WARNING "isdn_tty: Couldn't register modem-device\n");
- goto err;
- }
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- info = &m->info[i];
-#ifdef CONFIG_ISDN_TTY_FAX
- if (!(info->fax = kmalloc(sizeof(T30_s), GFP_KERNEL))) {
- printk(KERN_ERR "Could not allocate fax t30-buffer\n");
- retval = -ENOMEM;
- goto err_unregister;
- }
-#endif
- tty_port_init(&info->port);
- info->port.ops = &isdn_tty_port_ops;
- spin_lock_init(&info->readlock);
- sprintf(info->last_cause, "0000");
- sprintf(info->last_num, "none");
- info->last_dir = 0;
- info->last_lhup = 1;
- info->last_l2 = -1;
- info->last_si = 0;
- isdn_tty_reset_profile(&info->emu);
- isdn_tty_modem_reset_regs(info, 1);
- info->magic = ISDN_ASYNC_MAGIC;
- info->line = i;
- info->x_char = 0;
- info->isdn_driver = -1;
- info->isdn_channel = -1;
- info->drv_index = -1;
- info->xmit_size = ISDN_SERIAL_XMIT_SIZE;
- timer_setup(&info->nc_timer, isdn_tty_modem_do_ncarrier, 0);
- skb_queue_head_init(&info->xmit_queue);
-#ifdef CONFIG_ISDN_AUDIO
- skb_queue_head_init(&info->dtmf_queue);
-#endif
- info->port.xmit_buf = kmalloc(ISDN_SERIAL_XMIT_MAX + 5,
- GFP_KERNEL);
- if (!info->port.xmit_buf) {
- printk(KERN_ERR "Could not allocate modem xmit-buffer\n");
- retval = -ENOMEM;
- goto err_unregister;
- }
- /* Make room for T.70 header */
- info->port.xmit_buf += 4;
- }
- return 0;
-err_unregister:
- for (i--; i >= 0; i--) {
- info = &m->info[i];
-#ifdef CONFIG_ISDN_TTY_FAX
- kfree(info->fax);
-#endif
- kfree(info->port.xmit_buf - 4);
- info->port.xmit_buf = NULL;
- tty_port_destroy(&info->port);
- }
- tty_unregister_driver(m->tty_modem);
-err:
- put_tty_driver(m->tty_modem);
- m->tty_modem = NULL;
- return retval;
-}
-
-void
-isdn_tty_exit(void)
-{
- modem_info *info;
- int i;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- info = &dev->mdm.info[i];
- isdn_tty_cleanup_xmit(info);
-#ifdef CONFIG_ISDN_TTY_FAX
- kfree(info->fax);
-#endif
- kfree(info->port.xmit_buf - 4);
- info->port.xmit_buf = NULL;
- tty_port_destroy(&info->port);
- }
- tty_unregister_driver(dev->mdm.tty_modem);
- put_tty_driver(dev->mdm.tty_modem);
- dev->mdm.tty_modem = NULL;
-}
-
-
-/*
- * isdn_tty_match_icall(char *MSN, atemu *tty_emulator, int dev_idx)
- * match the MSN against the MSNs (glob patterns) defined for tty_emulator,
- * and return 0 for match, 1 for no match, 2 if MSN could match if longer.
- */
-
-static int
-isdn_tty_match_icall(char *cid, atemu *emu, int di)
-{
-#ifdef ISDN_DEBUG_MODEM_ICALL
- printk(KERN_DEBUG "m_fi: msn=%s lmsn=%s mmsn=%s mreg[SI1]=%d mreg[SI2]=%d\n",
- emu->msn, emu->lmsn, isdn_map_eaz2msn(emu->msn, di),
- emu->mdmreg[REG_SI1], emu->mdmreg[REG_SI2]);
-#endif
- if (strlen(emu->lmsn)) {
- char *p = emu->lmsn;
- char *q;
- int tmp;
- int ret = 0;
-
- while (1) {
- if ((q = strchr(p, ';')))
- *q = '\0';
- if ((tmp = isdn_msncmp(cid, isdn_map_eaz2msn(p, di))) > ret)
- ret = tmp;
-#ifdef ISDN_DEBUG_MODEM_ICALL
- printk(KERN_DEBUG "m_fi: lmsnX=%s mmsn=%s -> tmp=%d\n",
- p, isdn_map_eaz2msn(emu->msn, di), tmp);
-#endif
- if (q) {
- *q = ';';
- p = q;
- p++;
- }
- if (!tmp)
- return 0;
- if (!q)
- break;
- }
- return ret;
- } else {
- int tmp;
- tmp = isdn_msncmp(cid, isdn_map_eaz2msn(emu->msn, di));
-#ifdef ISDN_DEBUG_MODEM_ICALL
- printk(KERN_DEBUG "m_fi: mmsn=%s -> tmp=%d\n",
- isdn_map_eaz2msn(emu->msn, di), tmp);
-#endif
- return tmp;
- }
-}
-
-/*
- * An incoming call-request has arrived.
- * Search the tty-devices for an appropriate device and bind
- * it to the ISDN-Channel.
- * Return:
- *
- * 0 = No matching device found.
- * 1 = A matching device found.
- * 3 = No match found, but eventually would match, if
- * CID is longer.
- */
-int
-isdn_tty_find_icall(int di, int ch, setup_parm *setup)
-{
- char *eaz;
- int i;
- int wret;
- int idx;
- int si1;
- int si2;
- char *nr;
- ulong flags;
-
- if (!setup->phone[0]) {
- nr = "0";
- printk(KERN_INFO "isdn_tty: Incoming call without OAD, assuming '0'\n");
- } else
- nr = setup->phone;
- si1 = (int) setup->si1;
- si2 = (int) setup->si2;
- if (!setup->eazmsn[0]) {
- printk(KERN_WARNING "isdn_tty: Incoming call without CPN, assuming '0'\n");
- eaz = "0";
- } else
- eaz = setup->eazmsn;
-#ifdef ISDN_DEBUG_MODEM_ICALL
- printk(KERN_DEBUG "m_fi: eaz=%s si1=%d si2=%d\n", eaz, si1, si2);
-#endif
- wret = 0;
- spin_lock_irqsave(&dev->lock, flags);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- modem_info *info = &dev->mdm.info[i];
-
- if (info->port.count == 0)
- continue;
- if ((info->emu.mdmreg[REG_SI1] & si2bit[si1]) && /* SI1 is matching */
- (info->emu.mdmreg[REG_SI2] == si2)) { /* SI2 is matching */
- idx = isdn_dc2minor(di, ch);
-#ifdef ISDN_DEBUG_MODEM_ICALL
- printk(KERN_DEBUG "m_fi: match1 wret=%d\n", wret);
- printk(KERN_DEBUG "m_fi: idx=%d flags=%08lx drv=%d ch=%d usg=%d\n", idx,
- info->port.flags, info->isdn_driver,
- info->isdn_channel, dev->usage[idx]);
-#endif
- if (
-#ifndef FIX_FILE_TRANSFER
- tty_port_active(&info->port) &&
-#endif
- (info->isdn_driver == -1) &&
- (info->isdn_channel == -1) &&
- (USG_NONE(dev->usage[idx]))) {
- int matchret;
-
- if ((matchret = isdn_tty_match_icall(eaz, &info->emu, di)) > wret)
- wret = matchret;
- if (!matchret) { /* EAZ is matching */
- info->isdn_driver = di;
- info->isdn_channel = ch;
- info->drv_index = idx;
- dev->m_idx[idx] = info->line;
- dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
- dev->usage[idx] |= isdn_calc_usage(si1, info->emu.mdmreg[REG_L2PROT]);
- strcpy(dev->num[idx], nr);
- strcpy(info->emu.cpn, eaz);
- info->emu.mdmreg[REG_SI1I] = si2bit[si1];
- info->emu.mdmreg[REG_PLAN] = setup->plan;
- info->emu.mdmreg[REG_SCREEN] = setup->screen;
- isdn_info_update();
- spin_unlock_irqrestore(&dev->lock, flags);
- printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr,
- info->line);
- info->msr |= UART_MSR_RI;
- isdn_tty_modem_result(RESULT_RING, info);
- isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1);
- return 1;
- }
- }
- }
- }
- spin_unlock_irqrestore(&dev->lock, flags);
- printk(KERN_INFO "isdn_tty: call from %s -> %s %s\n", nr, eaz,
- ((dev->drv[di]->flags & DRV_FLAG_REJBUS) && (wret != 2)) ? "rejected" : "ignored");
- return (wret == 2) ? 3 : 0;
-}
-
-int
-isdn_tty_stat_callback(int i, isdn_ctrl *c)
-{
- int mi;
- modem_info *info;
- char *e;
-
- if (i < 0)
- return 0;
- if ((mi = dev->m_idx[i]) >= 0) {
- info = &dev->mdm.info[mi];
- switch (c->command) {
- case ISDN_STAT_CINF:
- printk(KERN_DEBUG "CHARGEINFO on ttyI%d: %ld %s\n", info->line, c->arg, c->parm.num);
- info->emu.charge = (unsigned) simple_strtoul(c->parm.num, &e, 10);
- if (e == (char *)c->parm.num)
- info->emu.charge = 0;
-
- break;
- case ISDN_STAT_BSENT:
-#ifdef ISDN_TTY_STAT_DEBUG
- printk(KERN_DEBUG "tty_STAT_BSENT ttyI%d\n", info->line);
-#endif
- if ((info->isdn_driver == c->driver) &&
- (info->isdn_channel == c->arg)) {
- info->msr |= UART_MSR_CTS;
- if (info->send_outstanding)
- if (!(--info->send_outstanding))
- info->lsr |= UART_LSR_TEMT;
- isdn_tty_tint(info);
- return 1;
- }
- break;
- case ISDN_STAT_CAUSE:
-#ifdef ISDN_TTY_STAT_DEBUG
- printk(KERN_DEBUG "tty_STAT_CAUSE ttyI%d\n", info->line);
-#endif
- /* Signal cause to tty-device */
- strncpy(info->last_cause, c->parm.num, 5);
- return 1;
- case ISDN_STAT_DISPLAY:
-#ifdef ISDN_TTY_STAT_DEBUG
- printk(KERN_DEBUG "tty_STAT_DISPLAY ttyI%d\n", info->line);
-#endif
- /* Signal display to tty-device */
- if ((info->emu.mdmreg[REG_DISPLAY] & BIT_DISPLAY) &&
- !(info->emu.mdmreg[REG_RESPNUM] & BIT_RESPNUM)) {
- isdn_tty_at_cout("\r\n", info);
- isdn_tty_at_cout("DISPLAY: ", info);
- isdn_tty_at_cout(c->parm.display, info);
- isdn_tty_at_cout("\r\n", info);
- }
- return 1;
- case ISDN_STAT_DCONN:
-#ifdef ISDN_TTY_STAT_DEBUG
- printk(KERN_DEBUG "tty_STAT_DCONN ttyI%d\n", info->line);
-#endif
- if (tty_port_active(&info->port)) {
- if (info->dialing == 1) {
- info->dialing = 2;
- return 1;
- }
- }
- break;
- case ISDN_STAT_DHUP:
-#ifdef ISDN_TTY_STAT_DEBUG
- printk(KERN_DEBUG "tty_STAT_DHUP ttyI%d\n", info->line);
-#endif
- if (tty_port_active(&info->port)) {
- if (info->dialing == 1)
- isdn_tty_modem_result(RESULT_BUSY, info);
- if (info->dialing > 1)
- isdn_tty_modem_result(RESULT_NO_CARRIER, info);
- info->dialing = 0;
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup in ISDN_STAT_DHUP\n");
-#endif
- isdn_tty_modem_hup(info, 0);
- return 1;
- }
- break;
- case ISDN_STAT_BCONN:
-#ifdef ISDN_TTY_STAT_DEBUG
- printk(KERN_DEBUG "tty_STAT_BCONN ttyI%d\n", info->line);
-#endif
- /* Wake up any processes waiting
- * for incoming call of this device when
- * DCD follow the state of incoming carrier
- */
- if (info->port.blocked_open &&
- (info->emu.mdmreg[REG_DCD] & BIT_DCD)) {
- wake_up_interruptible(&info->port.open_wait);
- }
-
- /* Schedule CONNECT-Message to any tty
- * waiting for it and
- * set DCD-bit of its modem-status.
- */
- if (tty_port_active(&info->port) ||
- (info->port.blocked_open &&
- (info->emu.mdmreg[REG_DCD] & BIT_DCD))) {
- info->msr |= UART_MSR_DCD;
- info->emu.charge = 0;
- if (info->dialing & 0xf)
- info->last_dir = 1;
- else
- info->last_dir = 0;
- info->dialing = 0;
- info->rcvsched = 1;
- if (USG_MODEM(dev->usage[i])) {
- if (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) {
- strcpy(info->emu.connmsg, c->parm.num);
- isdn_tty_modem_result(RESULT_CONNECT, info);
- } else
- isdn_tty_modem_result(RESULT_CONNECT64000, info);
- }
- if (USG_VOICE(dev->usage[i]))
- isdn_tty_modem_result(RESULT_VCON, info);
- return 1;
- }
- break;
- case ISDN_STAT_BHUP:
-#ifdef ISDN_TTY_STAT_DEBUG
- printk(KERN_DEBUG "tty_STAT_BHUP ttyI%d\n", info->line);
-#endif
- if (tty_port_active(&info->port)) {
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup in ISDN_STAT_BHUP\n");
-#endif
- isdn_tty_modem_hup(info, 0);
- return 1;
- }
- break;
- case ISDN_STAT_NODCH:
-#ifdef ISDN_TTY_STAT_DEBUG
- printk(KERN_DEBUG "tty_STAT_NODCH ttyI%d\n", info->line);
-#endif
- if (tty_port_active(&info->port)) {
- if (info->dialing) {
- info->dialing = 0;
- info->last_l2 = -1;
- info->last_si = 0;
- sprintf(info->last_cause, "0000");
- isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
- }
- isdn_tty_modem_hup(info, 0);
- return 1;
- }
- break;
- case ISDN_STAT_UNLOAD:
-#ifdef ISDN_TTY_STAT_DEBUG
- printk(KERN_DEBUG "tty_STAT_UNLOAD ttyI%d\n", info->line);
-#endif
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- info = &dev->mdm.info[i];
- if (info->isdn_driver == c->driver) {
- if (info->online)
- isdn_tty_modem_hup(info, 1);
- }
- }
- return 1;
-#ifdef CONFIG_ISDN_TTY_FAX
- case ISDN_STAT_FAXIND:
- if (tty_port_active(&info->port)) {
- isdn_tty_fax_command(info, c);
- }
- break;
-#endif
-#ifdef CONFIG_ISDN_AUDIO
- case ISDN_STAT_AUDIO:
- if (tty_port_active(&info->port)) {
- switch (c->parm.num[0]) {
- case ISDN_AUDIO_DTMF:
- if (info->vonline) {
- isdn_audio_put_dle_code(info,
- c->parm.num[1]);
- }
- break;
- }
- }
- break;
-#endif
- }
- }
- return 0;
-}
-
-/*********************************************************************
- Modem-Emulator-Routines
-*********************************************************************/
-
-#define cmdchar(c) ((c >= ' ') && (c <= 0x7f))
-
-/*
- * Put a message from the AT-emulator into receive-buffer of tty,
- * convert CR, LF, and BS to values in modem-registers 3, 4 and 5.
- */
-void
-isdn_tty_at_cout(char *msg, modem_info *info)
-{
- struct tty_port *port = &info->port;
- atemu *m = &info->emu;
- char *p;
- char c;
- u_long flags;
- struct sk_buff *skb = NULL;
- char *sp = NULL;
- int l;
-
- if (!msg) {
- printk(KERN_WARNING "isdn_tty: Null-Message in isdn_tty_at_cout\n");
- return;
- }
-
- l = strlen(msg);
-
- spin_lock_irqsave(&info->readlock, flags);
- if (info->closing) {
- spin_unlock_irqrestore(&info->readlock, flags);
- return;
- }
-
- /* use queue instead of direct, if online and */
- /* data is in queue or buffer is full */
- if (info->online && ((tty_buffer_request_room(port, l) < l) ||
- !skb_queue_empty(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel]))) {
- skb = alloc_skb(l, GFP_ATOMIC);
- if (!skb) {
- spin_unlock_irqrestore(&info->readlock, flags);
- return;
- }
- sp = skb_put(skb, l);
-#ifdef CONFIG_ISDN_AUDIO
- ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
- ISDN_AUDIO_SKB_LOCK(skb) = 0;
-#endif
- }
-
- for (p = msg; *p; p++) {
- switch (*p) {
- case '\r':
- c = m->mdmreg[REG_CR];
- break;
- case '\n':
- c = m->mdmreg[REG_LF];
- break;
- case '\b':
- c = m->mdmreg[REG_BS];
- break;
- default:
- c = *p;
- }
- if (skb) {
- *sp++ = c;
- } else {
- if (tty_insert_flip_char(port, c, TTY_NORMAL) == 0)
- break;
- }
- }
- if (skb) {
- __skb_queue_tail(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel], skb);
- dev->drv[info->isdn_driver]->rcvcount[info->isdn_channel] += skb->len;
- spin_unlock_irqrestore(&info->readlock, flags);
- /* Schedule dequeuing */
- if (dev->modempoll && info->rcvsched)
- isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
-
- } else {
- spin_unlock_irqrestore(&info->readlock, flags);
- tty_flip_buffer_push(port);
- }
-}
-
-/*
- * Perform ATH Hangup
- */
-static void
-isdn_tty_on_hook(modem_info *info)
-{
- if (info->isdn_channel >= 0) {
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup in isdn_tty_on_hook\n");
-#endif
- isdn_tty_modem_hup(info, 1);
- }
-}
-
-static void
-isdn_tty_off_hook(void)
-{
- printk(KERN_DEBUG "isdn_tty_off_hook\n");
-}
-
-#define PLUSWAIT1 (HZ / 2) /* 0.5 sec. */
-#define PLUSWAIT2 (HZ * 3 / 2) /* 1.5 sec */
-
-/*
- * Check Buffer for Modem-escape-sequence, activate timer-callback to
- * isdn_tty_modem_escape() if sequence found.
- *
- * Parameters:
- * p pointer to databuffer
- * plus escape-character
- * count length of buffer
- * pluscount count of valid escape-characters so far
- * lastplus timestamp of last character
- */
-static void
-isdn_tty_check_esc(const u_char *p, u_char plus, int count, int *pluscount,
- u_long *lastplus)
-{
- if (plus > 127)
- return;
- if (count > 3) {
- p += count - 3;
- count = 3;
- *pluscount = 0;
- }
- while (count > 0) {
- if (*(p++) == plus) {
- if ((*pluscount)++) {
- /* Time since last '+' > 0.5 sec. ? */
- if (time_after(jiffies, *lastplus + PLUSWAIT1))
- *pluscount = 1;
- } else {
- /* Time since last non-'+' < 1.5 sec. ? */
- if (time_before(jiffies, *lastplus + PLUSWAIT2))
- *pluscount = 0;
- }
- if ((*pluscount == 3) && (count == 1))
- isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, 1);
- if (*pluscount > 3)
- *pluscount = 1;
- } else
- *pluscount = 0;
- *lastplus = jiffies;
- count--;
- }
-}
-
-/*
- * Return result of AT-emulator to tty-receive-buffer, depending on
- * modem-register 12, bit 0 and 1.
- * For CONNECT-messages also switch to online-mode.
- * For RING-message handle auto-ATA if register 0 != 0
- */
-
-static void
-isdn_tty_modem_result(int code, modem_info *info)
-{
- atemu *m = &info->emu;
- static char *msg[] =
- {"OK", "CONNECT", "RING", "NO CARRIER", "ERROR",
- "CONNECT 64000", "NO DIALTONE", "BUSY", "NO ANSWER",
- "RINGING", "NO MSN/EAZ", "VCON", "RUNG"};
- char s[ISDN_MSNLEN + 10];
-
- switch (code) {
- case RESULT_RING:
- m->mdmreg[REG_RINGCNT]++;
- if (m->mdmreg[REG_RINGCNT] == m->mdmreg[REG_RINGATA])
- /* Automatically accept incoming call */
- isdn_tty_cmd_ATA(info);
- break;
- case RESULT_NO_CARRIER:
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n",
- info->closing, !info->port.tty);
-#endif
- m->mdmreg[REG_RINGCNT] = 0;
- del_timer(&info->nc_timer);
- info->ncarrier = 0;
- if (info->closing || !info->port.tty)
- return;
-
-#ifdef CONFIG_ISDN_AUDIO
- if (info->vonline & 1) {
-#ifdef ISDN_DEBUG_MODEM_VOICE
- printk(KERN_DEBUG "res3: send DLE-ETX on ttyI%d\n",
- info->line);
-#endif
- /* voice-recording, add DLE-ETX */
- isdn_tty_at_cout("\020\003", info);
- }
- if (info->vonline & 2) {
-#ifdef ISDN_DEBUG_MODEM_VOICE
- printk(KERN_DEBUG "res3: send DLE-DC4 on ttyI%d\n",
- info->line);
-#endif
- /* voice-playing, add DLE-DC4 */
- isdn_tty_at_cout("\020\024", info);
- }
-#endif
- break;
- case RESULT_CONNECT:
- case RESULT_CONNECT64000:
- sprintf(info->last_cause, "0000");
- if (!info->online)
- info->online = 2;
- break;
- case RESULT_VCON:
-#ifdef ISDN_DEBUG_MODEM_VOICE
- printk(KERN_DEBUG "res3: send VCON on ttyI%d\n",
- info->line);
-#endif
- sprintf(info->last_cause, "0000");
- if (!info->online)
- info->online = 1;
- break;
- } /* switch (code) */
-
- if (m->mdmreg[REG_RESP] & BIT_RESP) {
- /* Show results */
- if (m->mdmreg[REG_RESPNUM] & BIT_RESPNUM) {
- /* Show numeric results only */
- sprintf(s, "\r\n%d\r\n", code);
- isdn_tty_at_cout(s, info);
- } else {
- if (code == RESULT_RING) {
- /* return if "show RUNG" and ringcounter>1 */
- if ((m->mdmreg[REG_RUNG] & BIT_RUNG) &&
- (m->mdmreg[REG_RINGCNT] > 1))
- return;
- /* print CID, _before_ _every_ ring */
- if (!(m->mdmreg[REG_CIDONCE] & BIT_CIDONCE)) {
- isdn_tty_at_cout("\r\nCALLER NUMBER: ", info);
- isdn_tty_at_cout(dev->num[info->drv_index], info);
- if (m->mdmreg[REG_CDN] & BIT_CDN) {
- isdn_tty_at_cout("\r\nCALLED NUMBER: ", info);
- isdn_tty_at_cout(info->emu.cpn, info);
- }
- }
- }
- isdn_tty_at_cout("\r\n", info);
- isdn_tty_at_cout(msg[code], info);
- switch (code) {
- case RESULT_CONNECT:
- switch (m->mdmreg[REG_L2PROT]) {
- case ISDN_PROTO_L2_MODEM:
- isdn_tty_at_cout(" ", info);
- isdn_tty_at_cout(m->connmsg, info);
- break;
- }
- break;
- case RESULT_RING:
- /* Append CPN, if enabled */
- if ((m->mdmreg[REG_CPN] & BIT_CPN)) {
- sprintf(s, "/%s", m->cpn);
- isdn_tty_at_cout(s, info);
- }
- /* Print CID only once, _after_ 1st RING */
- if ((m->mdmreg[REG_CIDONCE] & BIT_CIDONCE) &&
- (m->mdmreg[REG_RINGCNT] == 1)) {
- isdn_tty_at_cout("\r\n", info);
- isdn_tty_at_cout("CALLER NUMBER: ", info);
- isdn_tty_at_cout(dev->num[info->drv_index], info);
- if (m->mdmreg[REG_CDN] & BIT_CDN) {
- isdn_tty_at_cout("\r\nCALLED NUMBER: ", info);
- isdn_tty_at_cout(info->emu.cpn, info);
- }
- }
- break;
- case RESULT_NO_CARRIER:
- case RESULT_NO_DIALTONE:
- case RESULT_BUSY:
- case RESULT_NO_ANSWER:
- m->mdmreg[REG_RINGCNT] = 0;
- /* Append Cause-Message if enabled */
- if (m->mdmreg[REG_RESPXT] & BIT_RESPXT) {
- sprintf(s, "/%s", info->last_cause);
- isdn_tty_at_cout(s, info);
- }
- break;
- case RESULT_CONNECT64000:
- /* Append Protocol to CONNECT message */
- switch (m->mdmreg[REG_L2PROT]) {
- case ISDN_PROTO_L2_X75I:
- case ISDN_PROTO_L2_X75UI:
- case ISDN_PROTO_L2_X75BUI:
- isdn_tty_at_cout("/X.75", info);
- break;
- case ISDN_PROTO_L2_HDLC:
- isdn_tty_at_cout("/HDLC", info);
- break;
- case ISDN_PROTO_L2_V11096:
- isdn_tty_at_cout("/V110/9600", info);
- break;
- case ISDN_PROTO_L2_V11019:
- isdn_tty_at_cout("/V110/19200", info);
- break;
- case ISDN_PROTO_L2_V11038:
- isdn_tty_at_cout("/V110/38400", info);
- break;
- }
- if (m->mdmreg[REG_T70] & BIT_T70) {
- isdn_tty_at_cout("/T.70", info);
- if (m->mdmreg[REG_T70] & BIT_T70_EXT)
- isdn_tty_at_cout("+", info);
- }
- break;
- }
- isdn_tty_at_cout("\r\n", info);
- }
- }
- if (code == RESULT_NO_CARRIER) {
- if (info->closing || (!info->port.tty))
- return;
-
- if (tty_port_check_carrier(&info->port))
- tty_hangup(info->port.tty);
- }
-}
-
-
-/*
- * Display a modem-register-value.
- */
-static void
-isdn_tty_show_profile(int ridx, modem_info *info)
-{
- char v[6];
-
- sprintf(v, "\r\n%d", info->emu.mdmreg[ridx]);
- isdn_tty_at_cout(v, info);
-}
-
-/*
- * Get MSN-string from char-pointer, set pointer to end of number
- */
-static void
-isdn_tty_get_msnstr(char *n, char **p)
-{
- int limit = ISDN_MSNLEN - 1;
-
- while (((*p[0] >= '0' && *p[0] <= '9') ||
- /* Why a comma ??? */
- (*p[0] == ',') || (*p[0] == ':')) &&
- (limit--))
- *n++ = *p[0]++;
- *n = '\0';
-}
-
-/*
- * Get phone-number from modem-commandbuffer
- */
-static void
-isdn_tty_getdial(char *p, char *q, int cnt)
-{
- int first = 1;
- int limit = ISDN_MSNLEN - 1; /* MUST match the size of interface var to avoid
- buffer overflow */
-
- while (strchr(" 0123456789,#.*WPTSR-", *p) && *p && --cnt > 0) {
- if ((*p >= '0' && *p <= '9') || ((*p == 'S') && first) ||
- ((*p == 'R') && first) ||
- (*p == '*') || (*p == '#')) {
- *q++ = *p;
- limit--;
- }
- if (!limit)
- break;
- p++;
- first = 0;
- }
- *q = 0;
-}
-
-#define PARSE_ERROR { isdn_tty_modem_result(RESULT_ERROR, info); return; }
-#define PARSE_ERROR1 { isdn_tty_modem_result(RESULT_ERROR, info); return 1; }
-
-static void
-isdn_tty_report(modem_info *info)
-{
- atemu *m = &info->emu;
- char s[80];
-
- isdn_tty_at_cout("\r\nStatistics of last connection:\r\n\r\n", info);
- sprintf(s, " Remote Number: %s\r\n", info->last_num);
- isdn_tty_at_cout(s, info);
- sprintf(s, " Direction: %s\r\n", info->last_dir ? "outgoing" : "incoming");
- isdn_tty_at_cout(s, info);
- isdn_tty_at_cout(" Layer-2 Protocol: ", info);
- switch (info->last_l2) {
- case ISDN_PROTO_L2_X75I:
- isdn_tty_at_cout("X.75i", info);
- break;
- case ISDN_PROTO_L2_X75UI:
- isdn_tty_at_cout("X.75ui", info);
- break;
- case ISDN_PROTO_L2_X75BUI:
- isdn_tty_at_cout("X.75bui", info);
- break;
- case ISDN_PROTO_L2_HDLC:
- isdn_tty_at_cout("HDLC", info);
- break;
- case ISDN_PROTO_L2_V11096:
- isdn_tty_at_cout("V.110 9600 Baud", info);
- break;
- case ISDN_PROTO_L2_V11019:
- isdn_tty_at_cout("V.110 19200 Baud", info);
- break;
- case ISDN_PROTO_L2_V11038:
- isdn_tty_at_cout("V.110 38400 Baud", info);
- break;
- case ISDN_PROTO_L2_TRANS:
- isdn_tty_at_cout("transparent", info);
- break;
- case ISDN_PROTO_L2_MODEM:
- isdn_tty_at_cout("modem", info);
- break;
- case ISDN_PROTO_L2_FAX:
- isdn_tty_at_cout("fax", info);
- break;
- default:
- isdn_tty_at_cout("unknown", info);
- break;
- }
- if (m->mdmreg[REG_T70] & BIT_T70) {
- isdn_tty_at_cout("/T.70", info);
- if (m->mdmreg[REG_T70] & BIT_T70_EXT)
- isdn_tty_at_cout("+", info);
- }
- isdn_tty_at_cout("\r\n", info);
- isdn_tty_at_cout(" Service: ", info);
- switch (info->last_si) {
- case 1:
- isdn_tty_at_cout("audio\r\n", info);
- break;
- case 5:
- isdn_tty_at_cout("btx\r\n", info);
- break;
- case 7:
- isdn_tty_at_cout("data\r\n", info);
- break;
- default:
- sprintf(s, "%d\r\n", info->last_si);
- isdn_tty_at_cout(s, info);
- break;
- }
- sprintf(s, " Hangup location: %s\r\n", info->last_lhup ? "local" : "remote");
- isdn_tty_at_cout(s, info);
- sprintf(s, " Last cause: %s\r\n", info->last_cause);
- isdn_tty_at_cout(s, info);
-}
-
-/*
- * Parse AT&.. commands.
- */
-static int
-isdn_tty_cmd_ATand(char **p, modem_info *info)
-{
- atemu *m = &info->emu;
- int i;
- char rb[100];
-
-#define MAXRB (sizeof(rb) - 1)
-
- switch (*p[0]) {
- case 'B':
- /* &B - Set Buffersize */
- p[0]++;
- i = isdn_getnum(p);
- if ((i < 0) || (i > ISDN_SERIAL_XMIT_MAX))
- PARSE_ERROR1;
-#ifdef CONFIG_ISDN_AUDIO
- if ((m->mdmreg[REG_SI1] & 1) && (i > VBUF))
- PARSE_ERROR1;
-#endif
- m->mdmreg[REG_PSIZE] = i / 16;
- info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
- switch (m->mdmreg[REG_L2PROT]) {
- case ISDN_PROTO_L2_V11096:
- case ISDN_PROTO_L2_V11019:
- case ISDN_PROTO_L2_V11038:
- info->xmit_size /= 10;
- }
- break;
- case 'C':
- /* &C - DCD Status */
- p[0]++;
- switch (isdn_getnum(p)) {
- case 0:
- m->mdmreg[REG_DCD] &= ~BIT_DCD;
- break;
- case 1:
- m->mdmreg[REG_DCD] |= BIT_DCD;
- break;
- default:
- PARSE_ERROR1
- }
- break;
- case 'D':
- /* &D - Set DTR-Low-behavior */
- p[0]++;
- switch (isdn_getnum(p)) {
- case 0:
- m->mdmreg[REG_DTRHUP] &= ~BIT_DTRHUP;
- m->mdmreg[REG_DTRR] &= ~BIT_DTRR;
- break;
- case 2:
- m->mdmreg[REG_DTRHUP] |= BIT_DTRHUP;
- m->mdmreg[REG_DTRR] &= ~BIT_DTRR;
- break;
- case 3:
- m->mdmreg[REG_DTRHUP] |= BIT_DTRHUP;
- m->mdmreg[REG_DTRR] |= BIT_DTRR;
- break;
- default:
- PARSE_ERROR1
- }
- break;
- case 'E':
- /* &E -Set EAZ/MSN */
- p[0]++;
- isdn_tty_get_msnstr(m->msn, p);
- break;
- case 'F':
- /* &F -Set Factory-Defaults */
- p[0]++;
- if (info->msr & UART_MSR_DCD)
- PARSE_ERROR1;
- isdn_tty_reset_profile(m);
- isdn_tty_modem_reset_regs(info, 1);
- break;
-#ifdef DUMMY_HAYES_AT
- case 'K':
- /* only for be compilant with common scripts */
- /* &K Flowcontrol - no function */
- p[0]++;
- isdn_getnum(p);
- break;
-#endif
- case 'L':
- /* &L -Set Numbers to listen on */
- p[0]++;
- i = 0;
- while (*p[0] && (strchr("0123456789,-*[]?;", *p[0])) &&
- (i < ISDN_LMSNLEN - 1))
- m->lmsn[i++] = *p[0]++;
- m->lmsn[i] = '\0';
- break;
- case 'R':
- /* &R - Set V.110 bitrate adaption */
- p[0]++;
- i = isdn_getnum(p);
- switch (i) {
- case 0:
- /* Switch off V.110, back to X.75 */
- m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
- m->mdmreg[REG_SI2] = 0;
- info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
- break;
- case 9600:
- m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11096;
- m->mdmreg[REG_SI2] = 197;
- info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10;
- break;
- case 19200:
- m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11019;
- m->mdmreg[REG_SI2] = 199;
- info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10;
- break;
- case 38400:
- m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11038;
- m->mdmreg[REG_SI2] = 198; /* no existing standard for this */
- info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10;
- break;
- default:
- PARSE_ERROR1;
- }
- /* Switch off T.70 */
- m->mdmreg[REG_T70] &= ~(BIT_T70 | BIT_T70_EXT);
- /* Set Service 7 */
- m->mdmreg[REG_SI1] |= 4;
- break;
- case 'S':
- /* &S - Set Windowsize */
- p[0]++;
- i = isdn_getnum(p);
- if ((i > 0) && (i < 9))
- m->mdmreg[REG_WSIZE] = i;
- else
- PARSE_ERROR1;
- break;
- case 'V':
- /* &V - Show registers */
- p[0]++;
- isdn_tty_at_cout("\r\n", info);
- for (i = 0; i < ISDN_MODEM_NUMREG; i++) {
- sprintf(rb, "S%02d=%03d%s", i,
- m->mdmreg[i], ((i + 1) % 10) ? " " : "\r\n");
- isdn_tty_at_cout(rb, info);
- }
- sprintf(rb, "\r\nEAZ/MSN: %.50s\r\n",
- strlen(m->msn) ? m->msn : "None");
- isdn_tty_at_cout(rb, info);
- if (strlen(m->lmsn)) {
- isdn_tty_at_cout("\r\nListen: ", info);
- isdn_tty_at_cout(m->lmsn, info);
- isdn_tty_at_cout("\r\n", info);
- }
- break;
- case 'W':
- /* &W - Write Profile */
- p[0]++;
- switch (*p[0]) {
- case '0':
- p[0]++;
- modem_write_profile(m);
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- case 'X':
- /* &X - Switch to BTX-Mode and T.70 */
- p[0]++;
- switch (isdn_getnum(p)) {
- case 0:
- m->mdmreg[REG_T70] &= ~(BIT_T70 | BIT_T70_EXT);
- info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
- break;
- case 1:
- m->mdmreg[REG_T70] |= BIT_T70;
- m->mdmreg[REG_T70] &= ~BIT_T70_EXT;
- m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
- info->xmit_size = 112;
- m->mdmreg[REG_SI1] = 4;
- m->mdmreg[REG_SI2] = 0;
- break;
- case 2:
- m->mdmreg[REG_T70] |= (BIT_T70 | BIT_T70_EXT);
- m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
- info->xmit_size = 112;
- m->mdmreg[REG_SI1] = 4;
- m->mdmreg[REG_SI2] = 0;
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
-}
-
-static int
-isdn_tty_check_ats(int mreg, int mval, modem_info *info, atemu *m)
-{
- /* Some plausibility checks */
- switch (mreg) {
- case REG_L2PROT:
- if (mval > ISDN_PROTO_L2_MAX)
- return 1;
- break;
- case REG_PSIZE:
- if ((mval * 16) > ISDN_SERIAL_XMIT_MAX)
- return 1;
-#ifdef CONFIG_ISDN_AUDIO
- if ((m->mdmreg[REG_SI1] & 1) && (mval > VBUFX))
- return 1;
-#endif
- info->xmit_size = mval * 16;
- switch (m->mdmreg[REG_L2PROT]) {
- case ISDN_PROTO_L2_V11096:
- case ISDN_PROTO_L2_V11019:
- case ISDN_PROTO_L2_V11038:
- info->xmit_size /= 10;
- }
- break;
- case REG_SI1I:
- case REG_PLAN:
- case REG_SCREEN:
- /* readonly registers */
- return 1;
- }
- return 0;
-}
-
-/*
- * Perform ATS command
- */
-static int
-isdn_tty_cmd_ATS(char **p, modem_info *info)
-{
- atemu *m = &info->emu;
- int bitpos;
- int mreg;
- int mval;
- int bval;
-
- mreg = isdn_getnum(p);
- if (mreg < 0 || mreg >= ISDN_MODEM_NUMREG)
- PARSE_ERROR1;
- switch (*p[0]) {
- case '=':
- p[0]++;
- mval = isdn_getnum(p);
- if (mval < 0 || mval > 255)
- PARSE_ERROR1;
- if (isdn_tty_check_ats(mreg, mval, info, m))
- PARSE_ERROR1;
- m->mdmreg[mreg] = mval;
- break;
- case '.':
- /* Set/Clear a single bit */
- p[0]++;
- bitpos = isdn_getnum(p);
- if ((bitpos < 0) || (bitpos > 7))
- PARSE_ERROR1;
- switch (*p[0]) {
- case '=':
- p[0]++;
- bval = isdn_getnum(p);
- if (bval < 0 || bval > 1)
- PARSE_ERROR1;
- if (bval)
- mval = m->mdmreg[mreg] | (1 << bitpos);
- else
- mval = m->mdmreg[mreg] & ~(1 << bitpos);
- if (isdn_tty_check_ats(mreg, mval, info, m))
- PARSE_ERROR1;
- m->mdmreg[mreg] = mval;
- break;
- case '?':
- p[0]++;
- isdn_tty_at_cout("\r\n", info);
- isdn_tty_at_cout((m->mdmreg[mreg] & (1 << bitpos)) ? "1" : "0",
- info);
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- case '?':
- p[0]++;
- isdn_tty_show_profile(mreg, info);
- break;
- default:
- PARSE_ERROR1;
- break;
- }
- return 0;
-}
-
-/*
- * Perform ATA command
- */
-static void
-isdn_tty_cmd_ATA(modem_info *info)
-{
- atemu *m = &info->emu;
- isdn_ctrl cmd;
- int l2;
-
- if (info->msr & UART_MSR_RI) {
- /* Accept incoming call */
- info->last_dir = 0;
- strcpy(info->last_num, dev->num[info->drv_index]);
- m->mdmreg[REG_RINGCNT] = 0;
- info->msr &= ~UART_MSR_RI;
- l2 = m->mdmreg[REG_L2PROT];
-#ifdef CONFIG_ISDN_AUDIO
- /* If more than one bit set in reg18, autoselect Layer2 */
- if ((m->mdmreg[REG_SI1] & m->mdmreg[REG_SI1I]) != m->mdmreg[REG_SI1]) {
- if (m->mdmreg[REG_SI1I] == 1) {
- if ((l2 != ISDN_PROTO_L2_MODEM) && (l2 != ISDN_PROTO_L2_FAX))
- l2 = ISDN_PROTO_L2_TRANS;
- } else
- l2 = ISDN_PROTO_L2_X75I;
- }
-#endif
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETL2;
- cmd.arg = info->isdn_channel + (l2 << 8);
- info->last_l2 = l2;
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETL3;
- cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
-#ifdef CONFIG_ISDN_TTY_FAX
- if (l2 == ISDN_PROTO_L2_FAX) {
- cmd.parm.fax = info->fax;
- info->fax->direction = ISDN_TTY_FAX_CONN_IN;
- }
-#endif
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- cmd.command = ISDN_CMD_ACCEPTD;
- info->dialing = 16;
- info->emu.carrierwait = 0;
- isdn_command(&cmd);
- isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
- } else
- isdn_tty_modem_result(RESULT_NO_ANSWER, info);
-}
-
-#ifdef CONFIG_ISDN_AUDIO
-/*
- * Parse AT+F.. commands
- */
-static int
-isdn_tty_cmd_PLUSF(char **p, modem_info *info)
-{
- atemu *m = &info->emu;
- char rs[20];
-
- if (!strncmp(p[0], "CLASS", 5)) {
- p[0] += 5;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d",
- (m->mdmreg[REG_SI1] & 1) ? 8 : 0);
-#ifdef CONFIG_ISDN_TTY_FAX
- if (TTY_IS_FCLASS2(info))
- sprintf(rs, "\r\n2");
- else if (TTY_IS_FCLASS1(info))
- sprintf(rs, "\r\n1");
-#endif
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- switch (*p[0]) {
- case '0':
- p[0]++;
- m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
- m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_TRANS;
- m->mdmreg[REG_SI1] = 4;
- info->xmit_size =
- m->mdmreg[REG_PSIZE] * 16;
- break;
-#ifdef CONFIG_ISDN_TTY_FAX
- case '1':
- p[0]++;
- if (!(dev->global_features &
- ISDN_FEATURE_L3_FCLASS1))
- PARSE_ERROR1;
- m->mdmreg[REG_SI1] = 1;
- m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_FAX;
- m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_FCLASS1;
- info->xmit_size =
- m->mdmreg[REG_PSIZE] * 16;
- break;
- case '2':
- p[0]++;
- if (!(dev->global_features &
- ISDN_FEATURE_L3_FCLASS2))
- PARSE_ERROR1;
- m->mdmreg[REG_SI1] = 1;
- m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_FAX;
- m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_FCLASS2;
- info->xmit_size =
- m->mdmreg[REG_PSIZE] * 16;
- break;
-#endif
- case '8':
- p[0]++;
- /* L2 will change on dialout with si=1 */
- m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
- m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_TRANS;
- m->mdmreg[REG_SI1] = 5;
- info->xmit_size = VBUF;
- break;
- case '?':
- p[0]++;
- strcpy(rs, "\r\n0,");
-#ifdef CONFIG_ISDN_TTY_FAX
- if (dev->global_features &
- ISDN_FEATURE_L3_FCLASS1)
- strcat(rs, "1,");
- if (dev->global_features &
- ISDN_FEATURE_L3_FCLASS2)
- strcat(rs, "2,");
-#endif
- strcat(rs, "8");
- isdn_tty_at_cout(rs, info);
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
-#ifdef CONFIG_ISDN_TTY_FAX
- return (isdn_tty_cmd_PLUSF_FAX(p, info));
-#else
- PARSE_ERROR1;
-#endif
-}
-
-/*
- * Parse AT+V.. commands
- */
-static int
-isdn_tty_cmd_PLUSV(char **p, modem_info *info)
-{
- atemu *m = &info->emu;
- isdn_ctrl cmd;
- static char *vcmd[] =
- {"NH", "IP", "LS", "RX", "SD", "SM", "TX", "DD", NULL};
- int i;
- int par1;
- int par2;
- char rs[20];
-
- i = 0;
- while (vcmd[i]) {
- if (!strncmp(vcmd[i], p[0], 2)) {
- p[0] += 2;
- break;
- }
- i++;
- }
- switch (i) {
- case 0:
- /* AT+VNH - Auto hangup feature */
- switch (*p[0]) {
- case '?':
- p[0]++;
- isdn_tty_at_cout("\r\n1", info);
- break;
- case '=':
- p[0]++;
- switch (*p[0]) {
- case '1':
- p[0]++;
- break;
- case '?':
- p[0]++;
- isdn_tty_at_cout("\r\n1", info);
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- case 1:
- /* AT+VIP - Reset all voice parameters */
- isdn_tty_modem_reset_vpar(m);
- break;
- case 2:
- /* AT+VLS - Select device, accept incoming call */
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", m->vpar[0]);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- switch (*p[0]) {
- case '0':
- p[0]++;
- m->vpar[0] = 0;
- break;
- case '2':
- p[0]++;
- m->vpar[0] = 2;
- break;
- case '?':
- p[0]++;
- isdn_tty_at_cout("\r\n0,2", info);
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- case 3:
- /* AT+VRX - Start recording */
- if (!m->vpar[0])
- PARSE_ERROR1;
- if (info->online != 1) {
- isdn_tty_modem_result(RESULT_NO_ANSWER, info);
- return 1;
- }
- info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state);
- if (!info->dtmf_state) {
- printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n");
- PARSE_ERROR1;
- }
- info->silence_state = isdn_audio_silence_init(info->silence_state);
- if (!info->silence_state) {
- printk(KERN_WARNING "isdn_tty: Couldn't malloc silence state\n");
- PARSE_ERROR1;
- }
- if (m->vpar[3] < 5) {
- info->adpcmr = isdn_audio_adpcm_init(info->adpcmr, m->vpar[3]);
- if (!info->adpcmr) {
- printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n");
- PARSE_ERROR1;
- }
- }
-#ifdef ISDN_DEBUG_AT
- printk(KERN_DEBUG "AT: +VRX\n");
-#endif
- info->vonline |= 1;
- isdn_tty_modem_result(RESULT_CONNECT, info);
- return 0;
- break;
- case 4:
- /* AT+VSD - Silence detection */
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n<%d>,<%d>",
- m->vpar[1],
- m->vpar[2]);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if ((*p[0] >= '0') && (*p[0] <= '9')) {
- par1 = isdn_getnum(p);
- if ((par1 < 0) || (par1 > 31))
- PARSE_ERROR1;
- if (*p[0] != ',')
- PARSE_ERROR1;
- p[0]++;
- par2 = isdn_getnum(p);
- if ((par2 < 0) || (par2 > 255))
- PARSE_ERROR1;
- m->vpar[1] = par1;
- m->vpar[2] = par2;
- break;
- } else
- if (*p[0] == '?') {
- p[0]++;
- isdn_tty_at_cout("\r\n<0-31>,<0-255>",
- info);
- break;
- } else
- PARSE_ERROR1;
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- case 5:
- /* AT+VSM - Select compression */
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n<%d>,<%d><8000>",
- m->vpar[3],
- m->vpar[1]);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- switch (*p[0]) {
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- par1 = isdn_getnum(p);
- if ((par1 < 2) || (par1 > 6))
- PARSE_ERROR1;
- m->vpar[3] = par1;
- break;
- case '?':
- p[0]++;
- isdn_tty_at_cout("\r\n2;ADPCM;2;0;(8000)\r\n",
- info);
- isdn_tty_at_cout("3;ADPCM;3;0;(8000)\r\n",
- info);
- isdn_tty_at_cout("4;ADPCM;4;0;(8000)\r\n",
- info);
- isdn_tty_at_cout("5;ALAW;8;0;(8000)\r\n",
- info);
- isdn_tty_at_cout("6;ULAW;8;0;(8000)\r\n",
- info);
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- case 6:
- /* AT+VTX - Start sending */
- if (!m->vpar[0])
- PARSE_ERROR1;
- if (info->online != 1) {
- isdn_tty_modem_result(RESULT_NO_ANSWER, info);
- return 1;
- }
- info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state);
- if (!info->dtmf_state) {
- printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n");
- PARSE_ERROR1;
- }
- if (m->vpar[3] < 5) {
- info->adpcms = isdn_audio_adpcm_init(info->adpcms, m->vpar[3]);
- if (!info->adpcms) {
- printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n");
- PARSE_ERROR1;
- }
- }
-#ifdef ISDN_DEBUG_AT
- printk(KERN_DEBUG "AT: +VTX\n");
-#endif
- m->lastDLE = 0;
- info->vonline |= 2;
- isdn_tty_modem_result(RESULT_CONNECT, info);
- return 0;
- break;
- case 7:
- /* AT+VDD - DTMF detection */
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n<%d>,<%d>",
- m->vpar[4],
- m->vpar[5]);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if ((*p[0] >= '0') && (*p[0] <= '9')) {
- if (info->online != 1)
- PARSE_ERROR1;
- par1 = isdn_getnum(p);
- if ((par1 < 0) || (par1 > 15))
- PARSE_ERROR1;
- if (*p[0] != ',')
- PARSE_ERROR1;
- p[0]++;
- par2 = isdn_getnum(p);
- if ((par2 < 0) || (par2 > 255))
- PARSE_ERROR1;
- m->vpar[4] = par1;
- m->vpar[5] = par2;
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_AUDIO;
- cmd.arg = info->isdn_channel + (ISDN_AUDIO_SETDD << 8);
- cmd.parm.num[0] = par1;
- cmd.parm.num[1] = par2;
- isdn_command(&cmd);
- break;
- } else
- if (*p[0] == '?') {
- p[0]++;
- isdn_tty_at_cout("\r\n<0-15>,<0-255>",
- info);
- break;
- } else
- PARSE_ERROR1;
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
-}
-#endif /* CONFIG_ISDN_AUDIO */
-
-/*
- * Parse and perform an AT-command-line.
- */
-static void
-isdn_tty_parse_at(modem_info *info)
-{
- atemu *m = &info->emu;
- char *p;
- char ds[ISDN_MSNLEN];
-
-#ifdef ISDN_DEBUG_AT
- printk(KERN_DEBUG "AT: '%s'\n", m->mdmcmd);
-#endif
- for (p = &m->mdmcmd[2]; *p;) {
- switch (*p) {
- case ' ':
- p++;
- break;
- case 'A':
- /* A - Accept incoming call */
- p++;
- isdn_tty_cmd_ATA(info);
- return;
- case 'D':
- /* D - Dial */
- if (info->msr & UART_MSR_DCD)
- PARSE_ERROR;
- if (info->msr & UART_MSR_RI) {
- isdn_tty_modem_result(RESULT_NO_CARRIER, info);
- return;
- }
- isdn_tty_getdial(++p, ds, sizeof ds);
- p += strlen(p);
- if (!strlen(m->msn))
- isdn_tty_modem_result(RESULT_NO_MSN_EAZ, info);
- else if (strlen(ds))
- isdn_tty_dial(ds, info, m);
- else
- PARSE_ERROR;
- return;
- case 'E':
- /* E - Turn Echo on/off */
- p++;
- switch (isdn_getnum(&p)) {
- case 0:
- m->mdmreg[REG_ECHO] &= ~BIT_ECHO;
- break;
- case 1:
- m->mdmreg[REG_ECHO] |= BIT_ECHO;
- break;
- default:
- PARSE_ERROR;
- }
- break;
- case 'H':
- /* H - On/Off-hook */
- p++;
- switch (*p) {
- case '0':
- p++;
- isdn_tty_on_hook(info);
- break;
- case '1':
- p++;
- isdn_tty_off_hook();
- break;
- default:
- isdn_tty_on_hook(info);
- break;
- }
- break;
- case 'I':
- /* I - Information */
- p++;
- isdn_tty_at_cout("\r\nLinux ISDN", info);
- switch (*p) {
- case '0':
- case '1':
- p++;
- break;
- case '2':
- p++;
- isdn_tty_report(info);
- break;
- case '3':
- p++;
- snprintf(ds, sizeof(ds), "\r\n%d", info->emu.charge);
- isdn_tty_at_cout(ds, info);
- break;
- default:;
- }
- break;
-#ifdef DUMMY_HAYES_AT
- case 'L':
- case 'M':
- /* only for be compilant with common scripts */
- /* no function */
- p++;
- isdn_getnum(&p);
- break;
-#endif
- case 'O':
- /* O - Go online */
- p++;
- if (info->msr & UART_MSR_DCD)
- /* if B-Channel is up */
- isdn_tty_modem_result((m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) ? RESULT_CONNECT : RESULT_CONNECT64000, info);
- else
- isdn_tty_modem_result(RESULT_NO_CARRIER, info);
- return;
- case 'Q':
- /* Q - Turn Emulator messages on/off */
- p++;
- switch (isdn_getnum(&p)) {
- case 0:
- m->mdmreg[REG_RESP] |= BIT_RESP;
- break;
- case 1:
- m->mdmreg[REG_RESP] &= ~BIT_RESP;
- break;
- default:
- PARSE_ERROR;
- }
- break;
- case 'S':
- /* S - Set/Get Register */
- p++;
- if (isdn_tty_cmd_ATS(&p, info))
- return;
- break;
- case 'V':
- /* V - Numeric or ASCII Emulator-messages */
- p++;
- switch (isdn_getnum(&p)) {
- case 0:
- m->mdmreg[REG_RESP] |= BIT_RESPNUM;
- break;
- case 1:
- m->mdmreg[REG_RESP] &= ~BIT_RESPNUM;
- break;
- default:
- PARSE_ERROR;
- }
- break;
- case 'Z':
- /* Z - Load Registers from Profile */
- p++;
- if (info->msr & UART_MSR_DCD) {
- info->online = 0;
- isdn_tty_on_hook(info);
- }
- isdn_tty_modem_reset_regs(info, 1);
- break;
- case '+':
- p++;
- switch (*p) {
-#ifdef CONFIG_ISDN_AUDIO
- case 'F':
- p++;
- if (isdn_tty_cmd_PLUSF(&p, info))
- return;
- break;
- case 'V':
- if ((!(m->mdmreg[REG_SI1] & 1)) ||
- (m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM))
- PARSE_ERROR;
- p++;
- if (isdn_tty_cmd_PLUSV(&p, info))
- return;
- break;
-#endif /* CONFIG_ISDN_AUDIO */
- case 'S': /* SUSPEND */
- p++;
- isdn_tty_get_msnstr(ds, &p);
- isdn_tty_suspend(ds, info, m);
- break;
- case 'R': /* RESUME */
- p++;
- isdn_tty_get_msnstr(ds, &p);
- isdn_tty_resume(ds, info, m);
- break;
- case 'M': /* MESSAGE */
- p++;
- isdn_tty_send_msg(info, m, p);
- break;
- default:
- PARSE_ERROR;
- }
- break;
- case '&':
- p++;
- if (isdn_tty_cmd_ATand(&p, info))
- return;
- break;
- default:
- PARSE_ERROR;
- }
- }
-#ifdef CONFIG_ISDN_AUDIO
- if (!info->vonline)
-#endif
- isdn_tty_modem_result(RESULT_OK, info);
-}
-
-/* Need own toupper() because standard-toupper is not available
- * within modules.
- */
-#define my_toupper(c) (((c >= 'a') && (c <= 'z')) ? (c & 0xdf) : c)
-
-/*
- * Perform line-editing of AT-commands
- *
- * Parameters:
- * p inputbuffer
- * count length of buffer
- * channel index to line (minor-device)
- */
-static int
-isdn_tty_edit_at(const char *p, int count, modem_info *info)
-{
- atemu *m = &info->emu;
- int total = 0;
- u_char c;
- char eb[2];
- int cnt;
-
- for (cnt = count; cnt > 0; p++, cnt--) {
- c = *p;
- total++;
- if (c == m->mdmreg[REG_CR] || c == m->mdmreg[REG_LF]) {
- /* Separator (CR or LF) */
- m->mdmcmd[m->mdmcmdl] = 0;
- if (m->mdmreg[REG_ECHO] & BIT_ECHO) {
- eb[0] = c;
- eb[1] = 0;
- isdn_tty_at_cout(eb, info);
- }
- if ((m->mdmcmdl >= 2) && (!(strncmp(m->mdmcmd, "AT", 2))))
- isdn_tty_parse_at(info);
- m->mdmcmdl = 0;
- continue;
- }
- if (c == m->mdmreg[REG_BS] && m->mdmreg[REG_BS] < 128) {
- /* Backspace-Function */
- if ((m->mdmcmdl > 2) || (!m->mdmcmdl)) {
- if (m->mdmcmdl)
- m->mdmcmdl--;
- if (m->mdmreg[REG_ECHO] & BIT_ECHO)
- isdn_tty_at_cout("\b", info);
- }
- continue;
- }
- if (cmdchar(c)) {
- if (m->mdmreg[REG_ECHO] & BIT_ECHO) {
- eb[0] = c;
- eb[1] = 0;
- isdn_tty_at_cout(eb, info);
- }
- if (m->mdmcmdl < 255) {
- c = my_toupper(c);
- switch (m->mdmcmdl) {
- case 1:
- if (c == 'T') {
- m->mdmcmd[m->mdmcmdl] = c;
- m->mdmcmd[++m->mdmcmdl] = 0;
- break;
- } else
- m->mdmcmdl = 0;
- /* Fall through - check for 'A' */
- case 0:
- if (c == 'A') {
- m->mdmcmd[m->mdmcmdl] = c;
- m->mdmcmd[++m->mdmcmdl] = 0;
- }
- break;
- default:
- m->mdmcmd[m->mdmcmdl] = c;
- m->mdmcmd[++m->mdmcmdl] = 0;
- }
- }
- }
- }
- return total;
-}
-
-/*
- * Switch all modem-channels who are online and got a valid
- * escape-sequence 1.5 seconds ago, to command-mode.
- * This function is called every second via timer-interrupt from within
- * timer-dispatcher isdn_timer_function()
- */
-void
-isdn_tty_modem_escape(void)
-{
- int ton = 0;
- int i;
- int midx;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (USG_MODEM(dev->usage[i]) && (midx = dev->m_idx[i]) >= 0) {
- modem_info *info = &dev->mdm.info[midx];
- if (info->online) {
- ton = 1;
- if ((info->emu.pluscount == 3) &&
- time_after(jiffies,
- info->emu.lastplus + PLUSWAIT2)) {
- info->emu.pluscount = 0;
- info->online = 0;
- isdn_tty_modem_result(RESULT_OK, info);
- }
- }
- }
- isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, ton);
-}
-
-/*
- * Put a RING-message to all modem-channels who have the RI-bit set.
- * This function is called every second via timer-interrupt from within
- * timer-dispatcher isdn_timer_function()
- */
-void
-isdn_tty_modem_ring(void)
-{
- int ton = 0;
- int i;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- modem_info *info = &dev->mdm.info[i];
- if (info->msr & UART_MSR_RI) {
- ton = 1;
- isdn_tty_modem_result(RESULT_RING, info);
- }
- }
- isdn_timer_ctrl(ISDN_TIMER_MODEMRING, ton);
-}
-
-/*
- * For all online tty's, try sending data to
- * the lower levels.
- */
-void
-isdn_tty_modem_xmit(void)
-{
- int ton = 1;
- int i;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- modem_info *info = &dev->mdm.info[i];
- if (info->online) {
- ton = 1;
- isdn_tty_senddown(info);
- isdn_tty_tint(info);
- }
- }
- isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, ton);
-}
-
-/*
- * Check all channels if we have a 'no carrier' timeout.
- * Timeout value is set by Register S7.
- */
-void
-isdn_tty_carrier_timeout(void)
-{
- int ton = 0;
- int i;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- modem_info *info = &dev->mdm.info[i];
- if (!info->dialing)
- continue;
- if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) {
- info->dialing = 0;
- isdn_tty_modem_result(RESULT_NO_CARRIER, info);
- isdn_tty_modem_hup(info, 1);
- } else
- ton = 1;
- }
- isdn_timer_ctrl(ISDN_TIMER_CARRIER, ton);
-}
diff --git a/drivers/isdn/i4l/isdn_tty.h b/drivers/isdn/i4l/isdn_tty.h
deleted file mode 100644
index a6f801d2263b..000000000000
--- a/drivers/isdn/i4l/isdn_tty.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/* $Id: isdn_tty.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * header for Linux ISDN subsystem, tty related functions (linklevel).
- *
- * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-
-#define DLE 0x10
-#define ETX 0x03
-#define DC4 0x14
-
-
-/*
- * Definition of some special Registers of AT-Emulator
- */
-#define REG_RINGATA 0
-#define REG_RINGCNT 1 /* ring counter register */
-#define REG_ESC 2
-#define REG_CR 3
-#define REG_LF 4
-#define REG_BS 5
-
-#define REG_WAITC 7
-
-#define REG_RESP 12 /* show response messages register */
-#define BIT_RESP 1 /* show response messages bit */
-#define REG_RESPNUM 12 /* show numeric responses register */
-#define BIT_RESPNUM 2 /* show numeric responses bit */
-#define REG_ECHO 12
-#define BIT_ECHO 4
-#define REG_DCD 12
-#define BIT_DCD 8
-#define REG_CTS 12
-#define BIT_CTS 16
-#define REG_DTRR 12
-#define BIT_DTRR 32
-#define REG_DSR 12
-#define BIT_DSR 64
-#define REG_CPPP 12
-#define BIT_CPPP 128
-
-#define REG_DXMT 13
-#define BIT_DXMT 1
-#define REG_T70 13
-#define BIT_T70 2
-#define BIT_T70_EXT 32
-#define REG_DTRHUP 13
-#define BIT_DTRHUP 4
-#define REG_RESPXT 13
-#define BIT_RESPXT 8
-#define REG_CIDONCE 13
-#define BIT_CIDONCE 16
-#define REG_RUNG 13 /* show RUNG message register */
-#define BIT_RUNG 64 /* show RUNG message bit */
-#define REG_DISPLAY 13
-#define BIT_DISPLAY 128
-
-#define REG_L2PROT 14
-#define REG_L3PROT 15
-#define REG_PSIZE 16
-#define REG_WSIZE 17
-#define REG_SI1 18
-#define REG_SI2 19
-#define REG_SI1I 20
-#define REG_PLAN 21
-#define REG_SCREEN 22
-
-#define REG_CPN 23
-#define BIT_CPN 1
-#define REG_CPNFCON 23
-#define BIT_CPNFCON 2
-#define REG_CDN 23
-#define BIT_CDN 4
-
-/* defines for result codes */
-#define RESULT_OK 0
-#define RESULT_CONNECT 1
-#define RESULT_RING 2
-#define RESULT_NO_CARRIER 3
-#define RESULT_ERROR 4
-#define RESULT_CONNECT64000 5
-#define RESULT_NO_DIALTONE 6
-#define RESULT_BUSY 7
-#define RESULT_NO_ANSWER 8
-#define RESULT_RINGING 9
-#define RESULT_NO_MSN_EAZ 10
-#define RESULT_VCON 11
-#define RESULT_RUNG 12
-
-#define TTY_IS_FCLASS1(info) \
- ((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \
- (info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS1))
-#define TTY_IS_FCLASS2(info) \
- ((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \
- (info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS2))
-
-extern void isdn_tty_modem_escape(void);
-extern void isdn_tty_modem_ring(void);
-extern void isdn_tty_carrier_timeout(void);
-extern void isdn_tty_modem_xmit(void);
-extern int isdn_tty_modem_init(void);
-extern void isdn_tty_exit(void);
-extern void isdn_tty_readmodem(void);
-extern int isdn_tty_find_icall(int, int, setup_parm *);
-extern int isdn_tty_stat_callback(int, isdn_ctrl *);
-extern int isdn_tty_rcv_skb(int, int, int, struct sk_buff *);
-extern int isdn_tty_capi_facility(capi_msg *cm);
-extern void isdn_tty_at_cout(char *, modem_info *);
-extern void isdn_tty_modem_hup(modem_info *, int);
-#ifdef CONFIG_ISDN_TTY_FAX
-extern int isdn_tty_cmd_PLUSF_FAX(char **, modem_info *);
-extern int isdn_tty_fax_command(modem_info *, isdn_ctrl *);
-extern void isdn_tty_fax_bitorder(modem_info *, struct sk_buff *);
-#endif
diff --git a/drivers/isdn/i4l/isdn_ttyfax.c b/drivers/isdn/i4l/isdn_ttyfax.c
deleted file mode 100644
index 47aae4916730..000000000000
--- a/drivers/isdn/i4l/isdn_ttyfax.c
+++ /dev/null
@@ -1,1123 +0,0 @@
-/* $Id: isdn_ttyfax.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * Linux ISDN subsystem, tty_fax AT-command emulator (linklevel).
- *
- * Copyright 1999 by Armin Schindler (mac@melware.de)
- * Copyright 1999 by Ralf Spachmann (mel@melware.de)
- * Copyright 1999 by Cytronics & Melware
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#undef ISDN_TTY_FAX_STAT_DEBUG
-#undef ISDN_TTY_FAX_CMD_DEBUG
-
-#include <linux/isdn.h>
-#include "isdn_common.h"
-#include "isdn_tty.h"
-#include "isdn_ttyfax.h"
-
-
-static char *isdn_tty_fax_revision = "$Revision: 1.1.2.2 $";
-
-#define PARSE_ERROR1 { isdn_tty_fax_modem_result(1, info); return 1; }
-
-static char *
-isdn_getrev(const char *revision)
-{
- char *rev;
- char *p;
-
- if ((p = strchr(revision, ':'))) {
- rev = p + 2;
- p = strchr(rev, '$');
- *--p = 0;
- } else
- rev = "???";
- return rev;
-}
-
-/*
- * Fax Class 2 Modem results
- *
- */
-
-static void
-isdn_tty_fax_modem_result(int code, modem_info *info)
-{
- atemu *m = &info->emu;
- T30_s *f = info->fax;
- char rs[50];
- char rss[50];
- char *rp;
- int i;
- static char *msg[] =
- {"OK", "ERROR", "+FCON", "+FCSI:", "+FDIS:",
- "+FHNG:", "+FDCS:", "CONNECT", "+FTSI:",
- "+FCFR", "+FPTS:", "+FET:"};
-
-
- isdn_tty_at_cout("\r\n", info);
- isdn_tty_at_cout(msg[code], info);
-
-#ifdef ISDN_TTY_FAX_CMD_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax send %s on ttyI%d\n",
- msg[code], info->line);
-#endif
- switch (code) {
- case 0: /* OK */
- break;
- case 1: /* ERROR */
- break;
- case 2: /* +FCON */
- /* Append CPN, if enabled */
- if ((m->mdmreg[REG_CPNFCON] & BIT_CPNFCON) &&
- (!(dev->usage[info->isdn_channel] & ISDN_USAGE_OUTGOING))) {
- sprintf(rs, "/%s", m->cpn);
- isdn_tty_at_cout(rs, info);
- }
- info->online = 1;
- f->fet = 0;
- if (f->phase == ISDN_FAX_PHASE_A)
- f->phase = ISDN_FAX_PHASE_B;
- break;
- case 3: /* +FCSI */
- case 8: /* +FTSI */
- sprintf(rs, "\"%s\"", f->r_id);
- isdn_tty_at_cout(rs, info);
- break;
- case 4: /* +FDIS */
- rs[0] = 0;
- rp = &f->r_resolution;
- for (i = 0; i < 8; i++) {
- sprintf(rss, "%c%s", rp[i] + 48,
- (i < 7) ? "," : "");
- strcat(rs, rss);
- }
- isdn_tty_at_cout(rs, info);
-#ifdef ISDN_TTY_FAX_CMD_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax DIS=%s on ttyI%d\n",
- rs, info->line);
-#endif
- break;
- case 5: /* +FHNG */
- sprintf(rs, "%d", f->code);
- isdn_tty_at_cout(rs, info);
- info->faxonline = 0;
- break;
- case 6: /* +FDCS */
- rs[0] = 0;
- rp = &f->r_resolution;
- for (i = 0; i < 8; i++) {
- sprintf(rss, "%c%s", rp[i] + 48,
- (i < 7) ? "," : "");
- strcat(rs, rss);
- }
- isdn_tty_at_cout(rs, info);
-#ifdef ISDN_TTY_FAX_CMD_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax DCS=%s on ttyI%d\n",
- rs, info->line);
-#endif
- break;
- case 7: /* CONNECT */
- info->faxonline |= 2;
- break;
- case 9: /* FCFR */
- break;
- case 10: /* FPTS */
- isdn_tty_at_cout("1", info);
- break;
- case 11: /* FET */
- sprintf(rs, "%d", f->fet);
- isdn_tty_at_cout(rs, info);
- break;
- }
-
- isdn_tty_at_cout("\r\n", info);
-
- switch (code) {
- case 7: /* CONNECT */
- info->online = 2;
- if (info->faxonline & 1) {
- sprintf(rs, "%c", XON);
- isdn_tty_at_cout(rs, info);
- }
- break;
- }
-}
-
-static int
-isdn_tty_fax_command1(modem_info *info, isdn_ctrl *c)
-{
- static char *msg[] =
- {"OK", "CONNECT", "NO CARRIER", "ERROR", "FCERROR"};
-
-#ifdef ISDN_TTY_FAX_CMD_DEBUG
- printk(KERN_DEBUG "isdn_tty: FCLASS1 cmd(%d)\n", c->parm.aux.cmd);
-#endif
- if (c->parm.aux.cmd < ISDN_FAX_CLASS1_QUERY) {
- if (info->online)
- info->online = 1;
- isdn_tty_at_cout("\r\n", info);
- isdn_tty_at_cout(msg[c->parm.aux.cmd], info);
- isdn_tty_at_cout("\r\n", info);
- }
- switch (c->parm.aux.cmd) {
- case ISDN_FAX_CLASS1_CONNECT:
- info->online = 2;
- break;
- case ISDN_FAX_CLASS1_OK:
- case ISDN_FAX_CLASS1_FCERROR:
- case ISDN_FAX_CLASS1_ERROR:
- case ISDN_FAX_CLASS1_NOCARR:
- break;
- case ISDN_FAX_CLASS1_QUERY:
- isdn_tty_at_cout("\r\n", info);
- if (!c->parm.aux.para[0]) {
- isdn_tty_at_cout(msg[ISDN_FAX_CLASS1_ERROR], info);
- isdn_tty_at_cout("\r\n", info);
- } else {
- isdn_tty_at_cout(c->parm.aux.para, info);
- isdn_tty_at_cout("\r\nOK\r\n", info);
- }
- break;
- }
- return (0);
-}
-
-int
-isdn_tty_fax_command(modem_info *info, isdn_ctrl *c)
-{
- T30_s *f = info->fax;
- char rs[10];
-
- if (TTY_IS_FCLASS1(info))
- return (isdn_tty_fax_command1(info, c));
-
-#ifdef ISDN_TTY_FAX_CMD_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax cmd %d on ttyI%d\n",
- f->r_code, info->line);
-#endif
- switch (f->r_code) {
- case ISDN_TTY_FAX_FCON:
- info->faxonline = 1;
- isdn_tty_fax_modem_result(2, info); /* +FCON */
- return (0);
- case ISDN_TTY_FAX_FCON_I:
- info->faxonline = 16;
- isdn_tty_fax_modem_result(2, info); /* +FCON */
- return (0);
- case ISDN_TTY_FAX_RID:
- if (info->faxonline & 1)
- isdn_tty_fax_modem_result(3, info); /* +FCSI */
- if (info->faxonline & 16)
- isdn_tty_fax_modem_result(8, info); /* +FTSI */
- return (0);
- case ISDN_TTY_FAX_DIS:
- isdn_tty_fax_modem_result(4, info); /* +FDIS */
- return (0);
- case ISDN_TTY_FAX_HNG:
- if (f->phase == ISDN_FAX_PHASE_C) {
- if (f->direction == ISDN_TTY_FAX_CONN_IN) {
- sprintf(rs, "%c%c", DLE, ETX);
- isdn_tty_at_cout(rs, info);
- } else {
- sprintf(rs, "%c", 0x18);
- isdn_tty_at_cout(rs, info);
- }
- info->faxonline &= ~2; /* leave data mode */
- info->online = 1;
- }
- f->phase = ISDN_FAX_PHASE_E;
- isdn_tty_fax_modem_result(5, info); /* +FHNG */
- isdn_tty_fax_modem_result(0, info); /* OK */
- return (0);
- case ISDN_TTY_FAX_DCS:
- isdn_tty_fax_modem_result(6, info); /* +FDCS */
- isdn_tty_fax_modem_result(7, info); /* CONNECT */
- f->phase = ISDN_FAX_PHASE_C;
- return (0);
- case ISDN_TTY_FAX_TRAIN_OK:
- isdn_tty_fax_modem_result(6, info); /* +FDCS */
- isdn_tty_fax_modem_result(0, info); /* OK */
- return (0);
- case ISDN_TTY_FAX_SENT:
- isdn_tty_fax_modem_result(0, info); /* OK */
- return (0);
- case ISDN_TTY_FAX_CFR:
- isdn_tty_fax_modem_result(9, info); /* +FCFR */
- return (0);
- case ISDN_TTY_FAX_ET:
- sprintf(rs, "%c%c", DLE, ETX);
- isdn_tty_at_cout(rs, info);
- isdn_tty_fax_modem_result(10, info); /* +FPTS */
- isdn_tty_fax_modem_result(11, info); /* +FET */
- isdn_tty_fax_modem_result(0, info); /* OK */
- info->faxonline &= ~2; /* leave data mode */
- info->online = 1;
- f->phase = ISDN_FAX_PHASE_D;
- return (0);
- case ISDN_TTY_FAX_PTS:
- isdn_tty_fax_modem_result(10, info); /* +FPTS */
- if (f->direction == ISDN_TTY_FAX_CONN_OUT) {
- if (f->fet == 1)
- f->phase = ISDN_FAX_PHASE_B;
- if (f->fet == 0)
- isdn_tty_fax_modem_result(0, info); /* OK */
- }
- return (0);
- case ISDN_TTY_FAX_EOP:
- info->faxonline &= ~2; /* leave data mode */
- info->online = 1;
- f->phase = ISDN_FAX_PHASE_D;
- return (0);
-
- }
- return (-1);
-}
-
-
-void
-isdn_tty_fax_bitorder(modem_info *info, struct sk_buff *skb)
-{
- __u8 LeftMask;
- __u8 RightMask;
- __u8 fBit;
- __u8 Data;
- int i;
-
- if (!info->fax->bor) {
- for (i = 0; i < skb->len; i++) {
- Data = skb->data[i];
- for (
- LeftMask = 0x80, RightMask = 0x01;
- LeftMask > RightMask;
- LeftMask >>= 1, RightMask <<= 1
- ) {
- fBit = (Data & LeftMask);
- if (Data & RightMask)
- Data |= LeftMask;
- else
- Data &= ~LeftMask;
- if (fBit)
- Data |= RightMask;
- else
- Data &= ~RightMask;
-
- }
- skb->data[i] = Data;
- }
- }
-}
-
-/*
- * Parse AT+F.. FAX class 1 commands
- */
-
-static int
-isdn_tty_cmd_FCLASS1(char **p, modem_info *info)
-{
- static char *cmd[] =
- {"AE", "TS", "RS", "TM", "RM", "TH", "RH"};
- isdn_ctrl c;
- int par, i;
- u_long flags;
-
- for (c.parm.aux.cmd = 0; c.parm.aux.cmd < 7; c.parm.aux.cmd++)
- if (!strncmp(p[0], cmd[c.parm.aux.cmd], 2))
- break;
-
-#ifdef ISDN_TTY_FAX_CMD_DEBUG
- printk(KERN_DEBUG "isdn_tty_cmd_FCLASS1 (%s,%d)\n", p[0], c.parm.aux.cmd);
-#endif
- if (c.parm.aux.cmd == 7)
- PARSE_ERROR1;
-
- p[0] += 2;
- switch (*p[0]) {
- case '?':
- p[0]++;
- c.parm.aux.subcmd = AT_QUERY;
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- c.parm.aux.subcmd = AT_EQ_QUERY;
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 255))
- PARSE_ERROR1;
- c.parm.aux.subcmd = AT_EQ_VALUE;
- c.parm.aux.para[0] = par;
- }
- break;
- case 0:
- c.parm.aux.subcmd = AT_COMMAND;
- break;
- default:
- PARSE_ERROR1;
- }
- c.command = ISDN_CMD_FAXCMD;
-#ifdef ISDN_TTY_FAX_CMD_DEBUG
- printk(KERN_DEBUG "isdn_tty_cmd_FCLASS1 %d/%d/%d)\n",
- c.parm.aux.cmd, c.parm.aux.subcmd, c.parm.aux.para[0]);
-#endif
- if (info->isdn_driver < 0) {
- if ((c.parm.aux.subcmd == AT_EQ_VALUE) ||
- (c.parm.aux.subcmd == AT_COMMAND)) {
- PARSE_ERROR1;
- }
- spin_lock_irqsave(&dev->lock, flags);
- /* get a temporary connection to the first free fax driver */
- i = isdn_get_free_channel(ISDN_USAGE_FAX, ISDN_PROTO_L2_FAX,
- ISDN_PROTO_L3_FCLASS1, -1, -1, "00");
- if (i < 0) {
- spin_unlock_irqrestore(&dev->lock, flags);
- PARSE_ERROR1;
- }
- info->isdn_driver = dev->drvmap[i];
- info->isdn_channel = dev->chanmap[i];
- info->drv_index = i;
- dev->m_idx[i] = info->line;
- spin_unlock_irqrestore(&dev->lock, flags);
- c.driver = info->isdn_driver;
- c.arg = info->isdn_channel;
- isdn_command(&c);
- spin_lock_irqsave(&dev->lock, flags);
- isdn_free_channel(info->isdn_driver, info->isdn_channel,
- ISDN_USAGE_FAX);
- info->isdn_driver = -1;
- info->isdn_channel = -1;
- if (info->drv_index >= 0) {
- dev->m_idx[info->drv_index] = -1;
- info->drv_index = -1;
- }
- spin_unlock_irqrestore(&dev->lock, flags);
- } else {
- c.driver = info->isdn_driver;
- c.arg = info->isdn_channel;
- isdn_command(&c);
- }
- return 1;
-}
-
-/*
- * Parse AT+F.. FAX class 2 commands
- */
-
-static int
-isdn_tty_cmd_FCLASS2(char **p, modem_info *info)
-{
- atemu *m = &info->emu;
- T30_s *f = info->fax;
- isdn_ctrl cmd;
- int par;
- char rs[50];
- char rss[50];
- int maxdccval[] =
- {1, 5, 2, 2, 3, 2, 0, 7};
-
- /* FAA still unchanged */
- if (!strncmp(p[0], "AA", 2)) { /* TODO */
- p[0] += 2;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", 0);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- par = isdn_getnum(p);
- if ((par < 0) || (par > 255))
- PARSE_ERROR1;
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* BADLIN=value - dummy 0=disable errorchk disabled, 1-255 nr. of lines for making page bad */
- if (!strncmp(p[0], "BADLIN", 6)) {
- p[0] += 6;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->badlin);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0-255");
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 255))
- PARSE_ERROR1;
- f->badlin = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FBADLIN=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* BADMUL=value - dummy 0=disable errorchk disabled (threshold multiplier) */
- if (!strncmp(p[0], "BADMUL", 6)) {
- p[0] += 6;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->badmul);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0-255");
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 255))
- PARSE_ERROR1;
- f->badmul = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FBADMUL=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* BOR=n - Phase C bit order, 0=direct, 1=reverse */
- if (!strncmp(p[0], "BOR", 3)) {
- p[0] += 3;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->bor);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0,1");
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 1))
- PARSE_ERROR1;
- f->bor = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FBOR=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* NBC=n - No Best Capabilities */
- if (!strncmp(p[0], "NBC", 3)) {
- p[0] += 3;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->nbc);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0,1");
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 1))
- PARSE_ERROR1;
- f->nbc = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FNBC=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* BUF? - Readonly buffersize readout */
- if (!strncmp(p[0], "BUF?", 4)) {
- p[0] += 4;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FBUF? (%d) \n", (16 * m->mdmreg[REG_PSIZE]));
-#endif
- p[0]++;
- sprintf(rs, "\r\n %d ", (16 * m->mdmreg[REG_PSIZE]));
- isdn_tty_at_cout(rs, info);
- return 0;
- }
- /* CIG=string - local fax station id string for polling rx */
- if (!strncmp(p[0], "CIG", 3)) {
- int i, r;
- p[0] += 3;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n\"%s\"", f->pollid);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n\"STRING\"");
- isdn_tty_at_cout(rs, info);
- } else {
- if (*p[0] == '"')
- p[0]++;
- for (i = 0; (*p[0]) && i < (FAXIDLEN - 1) && (*p[0] != '"'); i++) {
- f->pollid[i] = *p[0]++;
- }
- if (*p[0] == '"')
- p[0]++;
- for (r = i; r < FAXIDLEN; r++) {
- f->pollid[r] = 32;
- }
- f->pollid[FAXIDLEN - 1] = 0;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax local poll ID rx \"%s\"\n", f->pollid);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* CQ=n - copy qlty chk, 0= no chk, 1=only 1D chk, 2=1D+2D chk */
- if (!strncmp(p[0], "CQ", 2)) {
- p[0] += 2;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->cq);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0,1,2");
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 2))
- PARSE_ERROR1;
- f->cq = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FCQ=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* CR=n - can receive? 0= no data rx or poll remote dev, 1=do receive data or poll remote dev */
- if (!strncmp(p[0], "CR", 2)) {
- p[0] += 2;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->cr); /* read actual value from struct and print */
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0,1"); /* display online help */
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 1))
- PARSE_ERROR1;
- f->cr = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FCR=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* CTCRTY=value - ECM retry count */
- if (!strncmp(p[0], "CTCRTY", 6)) {
- p[0] += 6;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->ctcrty);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0-255");
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 255))
- PARSE_ERROR1;
- f->ctcrty = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FCTCRTY=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* DCC=vr,br,wd,ln,df,ec,bf,st - DCE capabilities parms */
- if (!strncmp(p[0], "DCC", 3)) {
- char *rp = &f->resolution;
- int i;
-
- p[0] += 3;
- switch (*p[0]) {
- case '?':
- p[0]++;
- strcpy(rs, "\r\n");
- for (i = 0; i < 8; i++) {
- sprintf(rss, "%c%s", rp[i] + 48,
- (i < 7) ? "," : "");
- strcat(rs, rss);
- }
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0-3),(0-2),(0),(0-7)", info);
- p[0]++;
- } else {
- for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 8); i++) {
- if (*p[0] != ',') {
- if ((*p[0] - 48) > maxdccval[i]) {
- PARSE_ERROR1;
- }
- rp[i] = *p[0] - 48;
- p[0]++;
- if (*p[0] == ',')
- p[0]++;
- } else
- p[0]++;
- }
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FDCC capabilities DCE=%d,%d,%d,%d,%d,%d,%d,%d\n",
- rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7]);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* DIS=vr,br,wd,ln,df,ec,bf,st - current session parms */
- if (!strncmp(p[0], "DIS", 3)) {
- char *rp = &f->resolution;
- int i;
-
- p[0] += 3;
- switch (*p[0]) {
- case '?':
- p[0]++;
- strcpy(rs, "\r\n");
- for (i = 0; i < 8; i++) {
- sprintf(rss, "%c%s", rp[i] + 48,
- (i < 7) ? "," : "");
- strcat(rs, rss);
- }
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0-3),(0-2),(0),(0-7)", info);
- p[0]++;
- } else {
- for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 8); i++) {
- if (*p[0] != ',') {
- if ((*p[0] - 48) > maxdccval[i]) {
- PARSE_ERROR1;
- }
- rp[i] = *p[0] - 48;
- p[0]++;
- if (*p[0] == ',')
- p[0]++;
- } else
- p[0]++;
- }
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FDIS session parms=%d,%d,%d,%d,%d,%d,%d,%d\n",
- rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7]);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* DR - Receive Phase C data command, initiates document reception */
- if (!strncmp(p[0], "DR", 2)) {
- p[0] += 2;
- if ((info->faxonline & 16) && /* incoming connection */
- ((f->phase == ISDN_FAX_PHASE_B) || (f->phase == ISDN_FAX_PHASE_D))) {
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FDR\n");
-#endif
- f->code = ISDN_TTY_FAX_DR;
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- cmd.command = ISDN_CMD_FAXCMD;
- isdn_command(&cmd);
- if (f->phase == ISDN_FAX_PHASE_B) {
- f->phase = ISDN_FAX_PHASE_C;
- } else if (f->phase == ISDN_FAX_PHASE_D) {
- switch (f->fet) {
- case 0: /* next page will be received */
- f->phase = ISDN_FAX_PHASE_C;
- isdn_tty_fax_modem_result(7, info); /* CONNECT */
- break;
- case 1: /* next doc will be received */
- f->phase = ISDN_FAX_PHASE_B;
- break;
- case 2: /* fax session is terminating */
- f->phase = ISDN_FAX_PHASE_E;
- break;
- default:
- PARSE_ERROR1;
- }
- }
- } else {
- PARSE_ERROR1;
- }
- return 1;
- }
- /* DT=df,vr,wd,ln - TX phase C data command (release DCE to proceed with negotiation) */
- if (!strncmp(p[0], "DT", 2)) {
- int i, val[] =
- {4, 0, 2, 3};
- char *rp = &f->resolution;
-
- p[0] += 2;
- if (!(info->faxonline & 1)) /* not outgoing connection */
- PARSE_ERROR1;
-
- for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 4); i++) {
- if (*p[0] != ',') {
- if ((*p[0] - 48) > maxdccval[val[i]]) {
- PARSE_ERROR1;
- }
- rp[val[i]] = *p[0] - 48;
- p[0]++;
- if (*p[0] == ',')
- p[0]++;
- } else
- p[0]++;
- }
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FDT tx data command parms=%d,%d,%d,%d\n",
- rp[4], rp[0], rp[2], rp[3]);
-#endif
- if ((f->phase == ISDN_FAX_PHASE_B) || (f->phase == ISDN_FAX_PHASE_D)) {
- f->code = ISDN_TTY_FAX_DT;
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- cmd.command = ISDN_CMD_FAXCMD;
- isdn_command(&cmd);
- if (f->phase == ISDN_FAX_PHASE_D) {
- f->phase = ISDN_FAX_PHASE_C;
- isdn_tty_fax_modem_result(7, info); /* CONNECT */
- }
- } else {
- PARSE_ERROR1;
- }
- return 1;
- }
- /* ECM=n - Error mode control 0=disabled, 2=enabled, handled by DCE alone incl. buff of partial pages */
- if (!strncmp(p[0], "ECM", 3)) {
- p[0] += 3;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->ecm);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0,2");
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par != 0) && (par != 2))
- PARSE_ERROR1;
- f->ecm = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FECM=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* ET=n - End of page or document */
- if (!strncmp(p[0], "ET=", 3)) {
- p[0] += 3;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0-2");
- isdn_tty_at_cout(rs, info);
- } else {
- if ((f->phase != ISDN_FAX_PHASE_D) ||
- (!(info->faxonline & 1)))
- PARSE_ERROR1;
- par = isdn_getnum(p);
- if ((par < 0) || (par > 2))
- PARSE_ERROR1;
- f->fet = par;
- f->code = ISDN_TTY_FAX_ET;
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- cmd.command = ISDN_CMD_FAXCMD;
- isdn_command(&cmd);
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FET=%d\n", par);
-#endif
- return 1;
- }
- return 0;
- }
- /* K - terminate */
- if (!strncmp(p[0], "K", 1)) {
- p[0] += 1;
- if ((f->phase == ISDN_FAX_PHASE_IDLE) || (f->phase == ISDN_FAX_PHASE_E))
- PARSE_ERROR1;
- isdn_tty_modem_hup(info, 1);
- return 1;
- }
- /* LID=string - local fax ID */
- if (!strncmp(p[0], "LID", 3)) {
- int i, r;
- p[0] += 3;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n\"%s\"", f->id);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n\"STRING\"");
- isdn_tty_at_cout(rs, info);
- } else {
- if (*p[0] == '"')
- p[0]++;
- for (i = 0; (*p[0]) && i < (FAXIDLEN - 1) && (*p[0] != '"'); i++) {
- f->id[i] = *p[0]++;
- }
- if (*p[0] == '"')
- p[0]++;
- for (r = i; r < FAXIDLEN; r++) {
- f->id[r] = 32;
- }
- f->id[FAXIDLEN - 1] = 0;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax local ID \"%s\"\n", f->id);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
-
- /* MDL? - DCE Model */
- if (!strncmp(p[0], "MDL?", 4)) {
- p[0] += 4;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: FMDL?\n");
-#endif
- isdn_tty_at_cout("\r\nisdn4linux", info);
- return 0;
- }
- /* MFR? - DCE Manufacturer */
- if (!strncmp(p[0], "MFR?", 4)) {
- p[0] += 4;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: FMFR?\n");
-#endif
- isdn_tty_at_cout("\r\nisdn4linux", info);
- return 0;
- }
- /* MINSP=n - Minimum Speed for Phase C */
- if (!strncmp(p[0], "MINSP", 5)) {
- p[0] += 5;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->minsp);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0-5");
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 5))
- PARSE_ERROR1;
- f->minsp = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FMINSP=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* PHCTO=value - DTE phase C timeout */
- if (!strncmp(p[0], "PHCTO", 5)) {
- p[0] += 5;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->phcto);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0-255");
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 255))
- PARSE_ERROR1;
- f->phcto = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FPHCTO=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
-
- /* REL=n - Phase C received EOL alignment */
- if (!strncmp(p[0], "REL", 3)) {
- p[0] += 3;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->rel);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0,1");
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 1))
- PARSE_ERROR1;
- f->rel = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FREL=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* REV? - DCE Revision */
- if (!strncmp(p[0], "REV?", 4)) {
- p[0] += 4;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: FREV?\n");
-#endif
- strcpy(rss, isdn_tty_fax_revision);
- sprintf(rs, "\r\nRev: %s", isdn_getrev(rss));
- isdn_tty_at_cout(rs, info);
- return 0;
- }
-
- /* Phase C Transmit Data Block Size */
- if (!strncmp(p[0], "TBC=", 4)) { /* dummy, not used */
- p[0] += 4;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FTBC=%c\n", *p[0]);
-#endif
- switch (*p[0]) {
- case '0':
- p[0]++;
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- printk(KERN_DEBUG "isdn_tty: unknown token=>AT+F%s<\n", p[0]);
- PARSE_ERROR1;
-}
-
-int
-isdn_tty_cmd_PLUSF_FAX(char **p, modem_info *info)
-{
- if (TTY_IS_FCLASS2(info))
- return (isdn_tty_cmd_FCLASS2(p, info));
- else if (TTY_IS_FCLASS1(info))
- return (isdn_tty_cmd_FCLASS1(p, info));
- PARSE_ERROR1;
-}
diff --git a/drivers/isdn/i4l/isdn_ttyfax.h b/drivers/isdn/i4l/isdn_ttyfax.h
deleted file mode 100644
index ccda4fcf8f7b..000000000000
--- a/drivers/isdn/i4l/isdn_ttyfax.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/* $Id: isdn_ttyfax.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * header for Linux ISDN subsystem, tty_fax related functions (linklevel).
- *
- * Copyright 1999 by Armin Schindler (mac@melware.de)
- * Copyright 1999 by Ralf Spachmann (mel@melware.de)
- * Copyright 1999 by Cytronics & Melware
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-
-#define XON 0x11
-#define XOFF 0x13
-#define DC2 0x12
diff --git a/drivers/isdn/i4l/isdn_v110.c b/drivers/isdn/i4l/isdn_v110.c
deleted file mode 100644
index d11fe76f138f..000000000000
--- a/drivers/isdn/i4l/isdn_v110.c
+++ /dev/null
@@ -1,625 +0,0 @@
-/* $Id: isdn_v110.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * Linux ISDN subsystem, V.110 related functions (linklevel).
- *
- * Copyright by Thomas Pfeiffer (pfeiffer@pds.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/delay.h>
-
-#include <linux/isdn.h>
-#include "isdn_v110.h"
-
-#undef ISDN_V110_DEBUG
-
-char *isdn_v110_revision = "$Revision: 1.1.2.2 $";
-
-#define V110_38400 255
-#define V110_19200 15
-#define V110_9600 3
-
-/*
- * The following data are precoded matrices, online and offline matrix
- * for 9600, 19200 und 38400, respectively
- */
-static unsigned char V110_OnMatrix_9600[] =
-{0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff,
- 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd,
- 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff,
- 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd};
-
-static unsigned char V110_OffMatrix_9600[] =
-{0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-
-static unsigned char V110_OnMatrix_19200[] =
-{0xf0, 0xf0, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7,
- 0xfd, 0xff, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7};
-
-static unsigned char V110_OffMatrix_19200[] =
-{0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-
-static unsigned char V110_OnMatrix_38400[] =
-{0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0xfd, 0x7f, 0x7f, 0x7f, 0x7f};
-
-static unsigned char V110_OffMatrix_38400[] =
-{0x00, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff};
-
-/*
- * FlipBits reorders sequences of keylen bits in one byte.
- * E.g. source order 7654321 will be converted to 45670123 when keylen = 4,
- * and to 67452301 when keylen = 2. This is necessary because ordering on
- * the isdn line is the other way.
- */
-static inline unsigned char
-FlipBits(unsigned char c, int keylen)
-{
- unsigned char b = c;
- unsigned char bit = 128;
- int i;
- int j;
- int hunks = (8 / keylen);
-
- c = 0;
- for (i = 0; i < hunks; i++) {
- for (j = 0; j < keylen; j++) {
- if (b & (bit >> j))
- c |= bit >> (keylen - j - 1);
- }
- bit >>= keylen;
- }
- return c;
-}
-
-
-/* isdn_v110_open allocates and initializes private V.110 data
- * structures and returns a pointer to these.
- */
-static isdn_v110_stream *
-isdn_v110_open(unsigned char key, int hdrlen, int maxsize)
-{
- int i;
- isdn_v110_stream *v;
-
- if ((v = kzalloc(sizeof(isdn_v110_stream), GFP_ATOMIC)) == NULL)
- return NULL;
- v->key = key;
- v->nbits = 0;
- for (i = 0; key & (1 << i); i++)
- v->nbits++;
-
- v->nbytes = 8 / v->nbits;
- v->decodelen = 0;
-
- switch (key) {
- case V110_38400:
- v->OnlineFrame = V110_OnMatrix_38400;
- v->OfflineFrame = V110_OffMatrix_38400;
- break;
- case V110_19200:
- v->OnlineFrame = V110_OnMatrix_19200;
- v->OfflineFrame = V110_OffMatrix_19200;
- break;
- default:
- v->OnlineFrame = V110_OnMatrix_9600;
- v->OfflineFrame = V110_OffMatrix_9600;
- break;
- }
- v->framelen = v->nbytes * 10;
- v->SyncInit = 5;
- v->introducer = 0;
- v->dbit = 1;
- v->b = 0;
- v->skbres = hdrlen;
- v->maxsize = maxsize - hdrlen;
- if ((v->encodebuf = kmalloc(maxsize, GFP_ATOMIC)) == NULL) {
- kfree(v);
- return NULL;
- }
- return v;
-}
-
-/* isdn_v110_close frees private V.110 data structures */
-void
-isdn_v110_close(isdn_v110_stream *v)
-{
- if (v == NULL)
- return;
-#ifdef ISDN_V110_DEBUG
- printk(KERN_DEBUG "v110 close\n");
-#endif
- kfree(v->encodebuf);
- kfree(v);
-}
-
-
-/*
- * ValidHeaderBytes return the number of valid bytes in v->decodebuf
- */
-static int
-ValidHeaderBytes(isdn_v110_stream *v)
-{
- int i;
- for (i = 0; (i < v->decodelen) && (i < v->nbytes); i++)
- if ((v->decodebuf[i] & v->key) != 0)
- break;
- return i;
-}
-
-/*
- * SyncHeader moves the decodebuf ptr to the next valid header
- */
-static void
-SyncHeader(isdn_v110_stream *v)
-{
- unsigned char *rbuf = v->decodebuf;
- int len = v->decodelen;
-
- if (len == 0)
- return;
- for (rbuf++, len--; len > 0; len--, rbuf++) /* such den SyncHeader in buf ! */
- if ((*rbuf & v->key) == 0) /* erstes byte gefunden ? */
- break; /* jupp! */
- if (len)
- memcpy(v->decodebuf, rbuf, len);
-
- v->decodelen = len;
-#ifdef ISDN_V110_DEBUG
- printk(KERN_DEBUG "isdn_v110: Header resync\n");
-#endif
-}
-
-/* DecodeMatrix takes n (n>=1) matrices (v110 frames, 10 bytes) where
- len is the number of matrix-lines. len must be a multiple of 10, i.e.
- only complete matices must be given.
- From these, netto data is extracted and returned in buf. The return-value
- is the bytecount of the decoded data.
-*/
-static int
-DecodeMatrix(isdn_v110_stream *v, unsigned char *m, int len, unsigned char *buf)
-{
- int line = 0;
- int buflen = 0;
- int mbit = 64;
- int introducer = v->introducer;
- int dbit = v->dbit;
- unsigned char b = v->b;
-
- while (line < len) { /* Are we done with all lines of the matrix? */
- if ((line % 10) == 0) { /* the 0. line of the matrix is always 0 ! */
- if (m[line] != 0x00) { /* not 0 ? -> error! */
-#ifdef ISDN_V110_DEBUG
- printk(KERN_DEBUG "isdn_v110: DecodeMatrix, V110 Bad Header\n");
- /* returning now is not the right thing, though :-( */
-#endif
- }
- line++; /* next line of matrix */
- continue;
- } else if ((line % 10) == 5) { /* in line 5 there's only e-bits ! */
- if ((m[line] & 0x70) != 0x30) { /* 011 has to be at the beginning! */
-#ifdef ISDN_V110_DEBUG
- printk(KERN_DEBUG "isdn_v110: DecodeMatrix, V110 Bad 5th line\n");
- /* returning now is not the right thing, though :-( */
-#endif
- }
- line++; /* next line */
- continue;
- } else if (!introducer) { /* every byte starts with 10 (stopbit, startbit) */
- introducer = (m[line] & mbit) ? 0 : 1; /* current bit of the matrix */
- next_byte:
- if (mbit > 2) { /* was it the last bit in this line ? */
- mbit >>= 1; /* no -> take next */
- continue;
- } /* otherwise start with leftmost bit in the next line */
- mbit = 64;
- line++;
- continue;
- } else { /* otherwise we need to set a data bit */
- if (m[line] & mbit) /* was that bit set in the matrix ? */
- b |= dbit; /* yes -> set it in the data byte */
- else
- b &= dbit - 1; /* no -> clear it in the data byte */
- if (dbit < 128) /* is that data byte done ? */
- dbit <<= 1; /* no, got the next bit */
- else { /* data byte is done */
- buf[buflen++] = b; /* copy byte into the output buffer */
- introducer = b = 0; /* init of the intro sequence and of the data byte */
- dbit = 1; /* next we look for the 0th bit */
- }
- goto next_byte; /* look for next bit in the matrix */
- }
- }
- v->introducer = introducer;
- v->dbit = dbit;
- v->b = b;
- return buflen; /* return number of bytes in the output buffer */
-}
-
-/*
- * DecodeStream receives V.110 coded data from the input stream. It recovers the
- * original frames.
- * The input stream doesn't need to be framed
- */
-struct sk_buff *
-isdn_v110_decode(isdn_v110_stream *v, struct sk_buff *skb)
-{
- int i;
- int j;
- int len;
- unsigned char *v110_buf;
- unsigned char *rbuf;
-
- if (!skb) {
- printk(KERN_WARNING "isdn_v110_decode called with NULL skb!\n");
- return NULL;
- }
- rbuf = skb->data;
- len = skb->len;
- if (v == NULL) {
- /* invalid handle, no chance to proceed */
- printk(KERN_WARNING "isdn_v110_decode called with NULL stream!\n");
- dev_kfree_skb(skb);
- return NULL;
- }
- if (v->decodelen == 0) /* cache empty? */
- for (; len > 0; len--, rbuf++) /* scan for SyncHeader in buf */
- if ((*rbuf & v->key) == 0)
- break; /* found first byte */
- if (len == 0) {
- dev_kfree_skb(skb);
- return NULL;
- }
- /* copy new data to decode-buffer */
- memcpy(&(v->decodebuf[v->decodelen]), rbuf, len);
- v->decodelen += len;
-ReSync:
- if (v->decodelen < v->nbytes) { /* got a new header ? */
- dev_kfree_skb(skb);
- return NULL; /* no, try later */
- }
- if (ValidHeaderBytes(v) != v->nbytes) { /* is that a valid header? */
- SyncHeader(v); /* no -> look for header */
- goto ReSync;
- }
- len = (v->decodelen - (v->decodelen % (10 * v->nbytes))) / v->nbytes;
- if ((v110_buf = kmalloc(len, GFP_ATOMIC)) == NULL) {
- printk(KERN_WARNING "isdn_v110_decode: Couldn't allocate v110_buf\n");
- dev_kfree_skb(skb);
- return NULL;
- }
- for (i = 0; i < len; i++) {
- v110_buf[i] = 0;
- for (j = 0; j < v->nbytes; j++)
- v110_buf[i] |= (v->decodebuf[(i * v->nbytes) + j] & v->key) << (8 - ((j + 1) * v->nbits));
- v110_buf[i] = FlipBits(v110_buf[i], v->nbits);
- }
- v->decodelen = (v->decodelen % (10 * v->nbytes));
- memcpy(v->decodebuf, &(v->decodebuf[len * v->nbytes]), v->decodelen);
-
- skb_trim(skb, DecodeMatrix(v, v110_buf, len, skb->data));
- kfree(v110_buf);
- if (skb->len)
- return skb;
- else {
- kfree_skb(skb);
- return NULL;
- }
-}
-
-/* EncodeMatrix takes input data in buf, len is the bytecount.
- Data is encoded into v110 frames in m. Return value is the number of
- matrix-lines generated.
-*/
-static int
-EncodeMatrix(unsigned char *buf, int len, unsigned char *m, int mlen)
-{
- int line = 0;
- int i = 0;
- int mbit = 128;
- int dbit = 1;
- int introducer = 3;
- int ibit[] = {0, 1, 1};
-
- while ((i < len) && (line < mlen)) { /* while we still have input data */
- switch (line % 10) { /* in which line of the matrix are we? */
- case 0:
- m[line++] = 0x00; /* line 0 is always 0 */
- mbit = 128; /* go on with the 7th bit */
- break;
- case 5:
- m[line++] = 0xbf; /* line 5 is always 10111111 */
- mbit = 128; /* go on with the 7th bit */
- break;
- }
- if (line >= mlen) {
- printk(KERN_WARNING "isdn_v110 (EncodeMatrix): buffer full!\n");
- return line;
- }
- next_bit:
- switch (mbit) { /* leftmost or rightmost bit ? */
- case 1:
- line++; /* rightmost -> go to next line */
- if (line >= mlen) {
- printk(KERN_WARNING "isdn_v110 (EncodeMatrix): buffer full!\n");
- return line;
- }
- /* fall through */
- case 128:
- m[line] = 128; /* leftmost -> set byte to 1000000 */
- mbit = 64; /* current bit in the matrix line */
- continue;
- }
- if (introducer) { /* set 110 sequence ? */
- introducer--; /* set on digit less */
- m[line] |= ibit[introducer] ? mbit : 0; /* set corresponding bit */
- mbit >>= 1; /* bit of matrix line >> 1 */
- goto next_bit; /* and go on there */
- } /* else push data bits into the matrix! */
- m[line] |= (buf[i] & dbit) ? mbit : 0; /* set data bit in matrix */
- if (dbit == 128) { /* was it the last one? */
- dbit = 1; /* then go on with first bit of */
- i++; /* next byte in input buffer */
- if (i < len) /* input buffer done ? */
- introducer = 3; /* no, write introducer 110 */
- else { /* input buffer done ! */
- m[line] |= (mbit - 1) & 0xfe; /* set remaining bits in line to 1 */
- break;
- }
- } else /* not the last data bit */
- dbit <<= 1; /* then go to next data bit */
- mbit >>= 1; /* go to next bit of matrix */
- goto next_bit;
-
- }
- /* if necessary, generate remaining lines of the matrix... */
- if ((line) && ((line + 10) < mlen))
- switch (++line % 10) {
- case 1:
- m[line++] = 0xfe;
- /* fall through */
- case 2:
- m[line++] = 0xfe;
- /* fall through */
- case 3:
- m[line++] = 0xfe;
- /* fall through */
- case 4:
- m[line++] = 0xfe;
- /* fall through */
- case 5:
- m[line++] = 0xbf;
- /* fall through */
- case 6:
- m[line++] = 0xfe;
- /* fall through */
- case 7:
- m[line++] = 0xfe;
- /* fall through */
- case 8:
- m[line++] = 0xfe;
- /* fall through */
- case 9:
- m[line++] = 0xfe;
- }
- return line; /* that's how many lines we have */
-}
-
-/*
- * Build a sync frame.
- */
-static struct sk_buff *
-isdn_v110_sync(isdn_v110_stream *v)
-{
- struct sk_buff *skb;
-
- if (v == NULL) {
- /* invalid handle, no chance to proceed */
- printk(KERN_WARNING "isdn_v110_sync called with NULL stream!\n");
- return NULL;
- }
- if ((skb = dev_alloc_skb(v->framelen + v->skbres))) {
- skb_reserve(skb, v->skbres);
- skb_put_data(skb, v->OfflineFrame, v->framelen);
- }
- return skb;
-}
-
-/*
- * Build an idle frame.
- */
-static struct sk_buff *
-isdn_v110_idle(isdn_v110_stream *v)
-{
- struct sk_buff *skb;
-
- if (v == NULL) {
- /* invalid handle, no chance to proceed */
- printk(KERN_WARNING "isdn_v110_sync called with NULL stream!\n");
- return NULL;
- }
- if ((skb = dev_alloc_skb(v->framelen + v->skbres))) {
- skb_reserve(skb, v->skbres);
- skb_put_data(skb, v->OnlineFrame, v->framelen);
- }
- return skb;
-}
-
-struct sk_buff *
-isdn_v110_encode(isdn_v110_stream *v, struct sk_buff *skb)
-{
- int i;
- int j;
- int rlen;
- int mlen;
- int olen;
- int size;
- int sval1;
- int sval2;
- int nframes;
- unsigned char *v110buf;
- unsigned char *rbuf;
- struct sk_buff *nskb;
-
- if (v == NULL) {
- /* invalid handle, no chance to proceed */
- printk(KERN_WARNING "isdn_v110_encode called with NULL stream!\n");
- return NULL;
- }
- if (!skb) {
- /* invalid skb, no chance to proceed */
- printk(KERN_WARNING "isdn_v110_encode called with NULL skb!\n");
- return NULL;
- }
- rlen = skb->len;
- nframes = (rlen + 3) / 4;
- v110buf = v->encodebuf;
- if ((nframes * 40) > v->maxsize) {
- size = v->maxsize;
- rlen = v->maxsize / 40;
- } else
- size = nframes * 40;
- if (!(nskb = dev_alloc_skb(size + v->skbres + sizeof(int)))) {
- printk(KERN_WARNING "isdn_v110_encode: Couldn't alloc skb\n");
- return NULL;
- }
- skb_reserve(nskb, v->skbres + sizeof(int));
- if (skb->len == 0) {
- skb_put_data(nskb, v->OnlineFrame, v->framelen);
- *((int *)skb_push(nskb, sizeof(int))) = 0;
- return nskb;
- }
- mlen = EncodeMatrix(skb->data, rlen, v110buf, size);
- /* now distribute 2 or 4 bits each to the output stream! */
- rbuf = skb_put(nskb, size);
- olen = 0;
- sval1 = 8 - v->nbits;
- sval2 = v->key << sval1;
- for (i = 0; i < mlen; i++) {
- v110buf[i] = FlipBits(v110buf[i], v->nbits);
- for (j = 0; j < v->nbytes; j++) {
- if (size--)
- *rbuf++ = ~v->key | (((v110buf[i] << (j * v->nbits)) & sval2) >> sval1);
- else {
- printk(KERN_WARNING "isdn_v110_encode: buffers full!\n");
- goto buffer_full;
- }
- olen++;
- }
- }
-buffer_full:
- skb_trim(nskb, olen);
- *((int *)skb_push(nskb, sizeof(int))) = rlen;
- return nskb;
-}
-
-int
-isdn_v110_stat_callback(int idx, isdn_ctrl *c)
-{
- isdn_v110_stream *v = NULL;
- int i;
- int ret = 0;
-
- if (idx < 0)
- return 0;
- switch (c->command) {
- case ISDN_STAT_BSENT:
- /* Keep the send-queue of the driver filled
- * with frames:
- * If number of outstanding frames < 3,
- * send down an Idle-Frame (or an Sync-Frame, if
- * v->SyncInit != 0).
- */
- if (!(v = dev->v110[idx]))
- return 0;
- atomic_inc(&dev->v110use[idx]);
- for (i = 0; i * v->framelen < c->parm.length; i++) {
- if (v->skbidle > 0) {
- v->skbidle--;
- ret = 1;
- } else {
- if (v->skbuser > 0)
- v->skbuser--;
- ret = 0;
- }
- }
- for (i = v->skbuser + v->skbidle; i < 2; i++) {
- struct sk_buff *skb;
- if (v->SyncInit > 0)
- skb = isdn_v110_sync(v);
- else
- skb = isdn_v110_idle(v);
- if (skb) {
- if (dev->drv[c->driver]->interface->writebuf_skb(c->driver, c->arg, 1, skb) <= 0) {
- dev_kfree_skb(skb);
- break;
- } else {
- if (v->SyncInit)
- v->SyncInit--;
- v->skbidle++;
- }
- } else
- break;
- }
- atomic_dec(&dev->v110use[idx]);
- return ret;
- case ISDN_STAT_DHUP:
- case ISDN_STAT_BHUP:
- while (1) {
- atomic_inc(&dev->v110use[idx]);
- if (atomic_dec_and_test(&dev->v110use[idx])) {
- isdn_v110_close(dev->v110[idx]);
- dev->v110[idx] = NULL;
- break;
- }
- mdelay(1);
- }
- break;
- case ISDN_STAT_BCONN:
- if (dev->v110emu[idx] && (dev->v110[idx] == NULL)) {
- int hdrlen = dev->drv[c->driver]->interface->hl_hdrlen;
- int maxsize = dev->drv[c->driver]->interface->maxbufsize;
- atomic_inc(&dev->v110use[idx]);
- switch (dev->v110emu[idx]) {
- case ISDN_PROTO_L2_V11096:
- dev->v110[idx] = isdn_v110_open(V110_9600, hdrlen, maxsize);
- break;
- case ISDN_PROTO_L2_V11019:
- dev->v110[idx] = isdn_v110_open(V110_19200, hdrlen, maxsize);
- break;
- case ISDN_PROTO_L2_V11038:
- dev->v110[idx] = isdn_v110_open(V110_38400, hdrlen, maxsize);
- break;
- default:;
- }
- if ((v = dev->v110[idx])) {
- while (v->SyncInit) {
- struct sk_buff *skb = isdn_v110_sync(v);
- if (dev->drv[c->driver]->interface->writebuf_skb(c->driver, c->arg, 1, skb) <= 0) {
- dev_kfree_skb(skb);
- /* Unable to send, try later */
- break;
- }
- v->SyncInit--;
- v->skbidle++;
- }
- } else
- printk(KERN_WARNING "isdn_v110: Couldn't open stream for chan %d\n", idx);
- atomic_dec(&dev->v110use[idx]);
- }
- break;
- default:
- return 0;
- }
- return 0;
-}
diff --git a/drivers/isdn/i4l/isdn_v110.h b/drivers/isdn/i4l/isdn_v110.h
deleted file mode 100644
index de774ab598c9..000000000000
--- a/drivers/isdn/i4l/isdn_v110.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* $Id: isdn_v110.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * Linux ISDN subsystem, V.110 related functions (linklevel).
- *
- * Copyright by Thomas Pfeiffer (pfeiffer@pds.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef _isdn_v110_h_
-#define _isdn_v110_h_
-
-/*
- * isdn_v110_encode will take raw data and encode it using V.110
- */
-extern struct sk_buff *isdn_v110_encode(isdn_v110_stream *, struct sk_buff *);
-
-/*
- * isdn_v110_decode receives V.110 coded data from the stream and rebuilds
- * frames from them. The source stream doesn't need to be framed.
- */
-extern struct sk_buff *isdn_v110_decode(isdn_v110_stream *, struct sk_buff *);
-
-extern int isdn_v110_stat_callback(int, isdn_ctrl *);
-extern void isdn_v110_close(isdn_v110_stream *v);
-
-#endif
diff --git a/drivers/isdn/i4l/isdn_x25iface.c b/drivers/isdn/i4l/isdn_x25iface.c
deleted file mode 100644
index 48bfbcb4a09d..000000000000
--- a/drivers/isdn/i4l/isdn_x25iface.c
+++ /dev/null
@@ -1,332 +0,0 @@
-/* $Id: isdn_x25iface.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * Linux ISDN subsystem, X.25 related functions
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * stuff needed to support the Linux X.25 PLP code on top of devices that
- * can provide a lab_b service using the concap_proto mechanism.
- * This module supports a network interface which provides lapb_sematics
- * -- as defined in Documentation/networking/x25-iface.txt -- to
- * the upper layer and assumes that the lower layer provides a reliable
- * data link service by means of the concap_device_ops callbacks.
- *
- * Only protocol specific stuff goes here. Device specific stuff
- * goes to another -- device related -- concap_proto support source file.
- *
- */
-
-/* #include <linux/isdn.h> */
-#include <linux/netdevice.h>
-#include <linux/concap.h>
-#include <linux/slab.h>
-#include <linux/wanrouter.h>
-#include <net/x25device.h>
-#include "isdn_x25iface.h"
-
-/* for debugging messages not to cause an oops when device pointer is NULL*/
-#define MY_DEVNAME(dev) ((dev) ? (dev)->name : "DEVICE UNSPECIFIED")
-
-
-typedef struct isdn_x25iface_proto_data {
- int magic;
- enum wan_states state;
- /* Private stuff, not to be accessed via proto_data. We provide the
- other storage for the concap_proto instance here as well,
- enabling us to allocate both with just one kmalloc(): */
- struct concap_proto priv;
-} ix25_pdata_t;
-
-
-
-/* is now in header file (extern): struct concap_proto * isdn_x25iface_proto_new(void); */
-static void isdn_x25iface_proto_del(struct concap_proto *);
-static int isdn_x25iface_proto_close(struct concap_proto *);
-static int isdn_x25iface_proto_restart(struct concap_proto *,
- struct net_device *,
- struct concap_device_ops *);
-static int isdn_x25iface_xmit(struct concap_proto *, struct sk_buff *);
-static int isdn_x25iface_receive(struct concap_proto *, struct sk_buff *);
-static int isdn_x25iface_connect_ind(struct concap_proto *);
-static int isdn_x25iface_disconn_ind(struct concap_proto *);
-
-
-static struct concap_proto_ops ix25_pops = {
- .proto_new = &isdn_x25iface_proto_new,
- .proto_del = &isdn_x25iface_proto_del,
- .restart = &isdn_x25iface_proto_restart,
- .close = &isdn_x25iface_proto_close,
- .encap_and_xmit = &isdn_x25iface_xmit,
- .data_ind = &isdn_x25iface_receive,
- .connect_ind = &isdn_x25iface_connect_ind,
- .disconn_ind = &isdn_x25iface_disconn_ind
-};
-
-/* error message helper function */
-static void illegal_state_warn(unsigned state, unsigned char firstbyte)
-{
- printk(KERN_WARNING "isdn_x25iface: firstbyte %x illegal in"
- "current state %d\n", firstbyte, state);
-}
-
-/* check protocol data field for consistency */
-static int pdata_is_bad(ix25_pdata_t *pda) {
-
- if (pda && pda->magic == ISDN_X25IFACE_MAGIC) return 0;
- printk(KERN_WARNING
- "isdn_x25iface_xxx: illegal pointer to proto data\n");
- return 1;
-}
-
-/* create a new x25 interface protocol instance
- */
-struct concap_proto *isdn_x25iface_proto_new(void)
-{
- ix25_pdata_t *tmp = kmalloc(sizeof(ix25_pdata_t), GFP_KERNEL);
- IX25DEBUG("isdn_x25iface_proto_new\n");
- if (tmp) {
- tmp->magic = ISDN_X25IFACE_MAGIC;
- tmp->state = WAN_UNCONFIGURED;
- /* private data space used to hold the concap_proto data.
- Only to be accessed via the returned pointer */
- spin_lock_init(&tmp->priv.lock);
- tmp->priv.dops = NULL;
- tmp->priv.net_dev = NULL;
- tmp->priv.pops = &ix25_pops;
- tmp->priv.flags = 0;
- tmp->priv.proto_data = tmp;
- return (&(tmp->priv));
- }
- return NULL;
-};
-
-/* close the x25iface encapsulation protocol
- */
-static int isdn_x25iface_proto_close(struct concap_proto *cprot) {
-
- ix25_pdata_t *tmp;
- int ret = 0;
- ulong flags;
-
- if (!cprot) {
- printk(KERN_ERR "isdn_x25iface_proto_close: "
- "invalid concap_proto pointer\n");
- return -1;
- }
- IX25DEBUG("isdn_x25iface_proto_close %s \n", MY_DEVNAME(cprot->net_dev));
- spin_lock_irqsave(&cprot->lock, flags);
- cprot->dops = NULL;
- cprot->net_dev = NULL;
- tmp = cprot->proto_data;
- if (pdata_is_bad(tmp)) {
- ret = -1;
- } else {
- tmp->state = WAN_UNCONFIGURED;
- }
- spin_unlock_irqrestore(&cprot->lock, flags);
- return ret;
-}
-
-/* Delete the x25iface encapsulation protocol instance
- */
-static void isdn_x25iface_proto_del(struct concap_proto *cprot) {
-
- ix25_pdata_t *tmp;
-
- IX25DEBUG("isdn_x25iface_proto_del \n");
- if (!cprot) {
- printk(KERN_ERR "isdn_x25iface_proto_del: "
- "concap_proto pointer is NULL\n");
- return;
- }
- tmp = cprot->proto_data;
- if (tmp == NULL) {
- printk(KERN_ERR "isdn_x25iface_proto_del: inconsistent "
- "proto_data pointer (maybe already deleted?)\n");
- return;
- }
- /* close if the protocol is still open */
- if (cprot->dops) isdn_x25iface_proto_close(cprot);
- /* freeing the storage should be sufficient now. But some additional
- settings might help to catch wild pointer bugs */
- tmp->magic = 0;
- cprot->proto_data = NULL;
-
- kfree(tmp);
- return;
-}
-
-/* (re-)initialize the data structures for x25iface encapsulation
- */
-static int isdn_x25iface_proto_restart(struct concap_proto *cprot,
- struct net_device *ndev,
- struct concap_device_ops *dops)
-{
- ix25_pdata_t *pda = cprot->proto_data;
- ulong flags;
-
- IX25DEBUG("isdn_x25iface_proto_restart %s \n", MY_DEVNAME(ndev));
-
- if (pdata_is_bad(pda)) return -1;
-
- if (!(dops && dops->data_req && dops->connect_req
- && dops->disconn_req)) {
- printk(KERN_WARNING "isdn_x25iface_restart: required dops"
- " missing\n");
- isdn_x25iface_proto_close(cprot);
- return -1;
- }
- spin_lock_irqsave(&cprot->lock, flags);
- cprot->net_dev = ndev;
- cprot->pops = &ix25_pops;
- cprot->dops = dops;
- pda->state = WAN_DISCONNECTED;
- spin_unlock_irqrestore(&cprot->lock, flags);
- return 0;
-}
-
-/* deliver a dl_data frame received from i4l HL driver to the network layer
- */
-static int isdn_x25iface_receive(struct concap_proto *cprot, struct sk_buff *skb)
-{
- IX25DEBUG("isdn_x25iface_receive %s \n", MY_DEVNAME(cprot->net_dev));
- if (((ix25_pdata_t *)(cprot->proto_data))
- ->state == WAN_CONNECTED) {
- if (skb_push(skb, 1)) {
- skb->data[0] = X25_IFACE_DATA;
- skb->protocol = x25_type_trans(skb, cprot->net_dev);
- netif_rx(skb);
- return 0;
- }
- }
- printk(KERN_WARNING "isdn_x25iface_receive %s: not connected, skb dropped\n", MY_DEVNAME(cprot->net_dev));
- dev_kfree_skb(skb);
- return -1;
-}
-
-/* a connection set up is indicated by lower layer
- */
-static int isdn_x25iface_connect_ind(struct concap_proto *cprot)
-{
- struct sk_buff *skb;
- enum wan_states *state_p
- = &(((ix25_pdata_t *)(cprot->proto_data))->state);
- IX25DEBUG("isdn_x25iface_connect_ind %s \n"
- , MY_DEVNAME(cprot->net_dev));
- if (*state_p == WAN_UNCONFIGURED) {
- printk(KERN_WARNING
- "isdn_x25iface_connect_ind while unconfigured %s\n"
- , MY_DEVNAME(cprot->net_dev));
- return -1;
- }
- *state_p = WAN_CONNECTED;
-
- skb = dev_alloc_skb(1);
- if (skb) {
- skb_put_u8(skb, X25_IFACE_CONNECT);
- skb->protocol = x25_type_trans(skb, cprot->net_dev);
- netif_rx(skb);
- return 0;
- } else {
- printk(KERN_WARNING "isdn_x25iface_connect_ind: "
- " out of memory -- disconnecting\n");
- cprot->dops->disconn_req(cprot);
- return -1;
- }
-}
-
-/* a disconnect is indicated by lower layer
- */
-static int isdn_x25iface_disconn_ind(struct concap_proto *cprot)
-{
- struct sk_buff *skb;
- enum wan_states *state_p
- = &(((ix25_pdata_t *)(cprot->proto_data))->state);
- IX25DEBUG("isdn_x25iface_disconn_ind %s \n", MY_DEVNAME(cprot->net_dev));
- if (*state_p == WAN_UNCONFIGURED) {
- printk(KERN_WARNING
- "isdn_x25iface_disconn_ind while unconfigured\n");
- return -1;
- }
- if (!cprot->net_dev) return -1;
- *state_p = WAN_DISCONNECTED;
- skb = dev_alloc_skb(1);
- if (skb) {
- skb_put_u8(skb, X25_IFACE_DISCONNECT);
- skb->protocol = x25_type_trans(skb, cprot->net_dev);
- netif_rx(skb);
- return 0;
- } else {
- printk(KERN_WARNING "isdn_x25iface_disconn_ind:"
- " out of memory\n");
- return -1;
- }
-}
-
-/* process a frame handed over to us from linux network layer. First byte
- semantics as defined in Documentation/networking/x25-iface.txt
-*/
-static int isdn_x25iface_xmit(struct concap_proto *cprot, struct sk_buff *skb)
-{
- unsigned char firstbyte = skb->data[0];
- enum wan_states *state = &((ix25_pdata_t *)cprot->proto_data)->state;
- int ret = 0;
- IX25DEBUG("isdn_x25iface_xmit: %s first=%x state=%d\n",
- MY_DEVNAME(cprot->net_dev), firstbyte, *state);
- switch (firstbyte) {
- case X25_IFACE_DATA:
- if (*state == WAN_CONNECTED) {
- skb_pull(skb, 1);
- netif_trans_update(cprot->net_dev);
- ret = (cprot->dops->data_req(cprot, skb));
- /* prepare for future retransmissions */
- if (ret) skb_push(skb, 1);
- return ret;
- }
- illegal_state_warn(*state, firstbyte);
- break;
- case X25_IFACE_CONNECT:
- if (*state == WAN_DISCONNECTED) {
- *state = WAN_CONNECTING;
- ret = cprot->dops->connect_req(cprot);
- if (ret) {
- /* reset state and notify upper layer about
- * immidiatly failed attempts */
- isdn_x25iface_disconn_ind(cprot);
- }
- } else {
- illegal_state_warn(*state, firstbyte);
- }
- break;
- case X25_IFACE_DISCONNECT:
- switch (*state) {
- case WAN_DISCONNECTED:
- /* Should not happen. However, give upper layer a
- chance to recover from inconstistency but don't
- trust the lower layer sending the disconn_confirm
- when already disconnected */
- printk(KERN_WARNING "isdn_x25iface_xmit: disconnect "
- " requested while disconnected\n");
- isdn_x25iface_disconn_ind(cprot);
- break; /* prevent infinite loops */
- case WAN_CONNECTING:
- case WAN_CONNECTED:
- *state = WAN_DISCONNECTED;
- cprot->dops->disconn_req(cprot);
- break;
- default:
- illegal_state_warn(*state, firstbyte);
- }
- break;
- case X25_IFACE_PARAMS:
- printk(KERN_WARNING "isdn_x25iface_xmit: setting of lapb"
- " options not yet supported\n");
- break;
- default:
- printk(KERN_WARNING "isdn_x25iface_xmit: frame with illegal"
- " first byte %x ignored:\n", firstbyte);
- }
- dev_kfree_skb(skb);
- return 0;
-}
diff --git a/drivers/isdn/i4l/isdn_x25iface.h b/drivers/isdn/i4l/isdn_x25iface.h
deleted file mode 100644
index ca08e082cf7c..000000000000
--- a/drivers/isdn/i4l/isdn_x25iface.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* $Id: isdn_x25iface.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * header for Linux ISDN subsystem, x.25 related functions
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef _LINUX_ISDN_X25IFACE_H
-#define _LINUX_ISDN_X25IFACE_H
-
-#define ISDN_X25IFACE_MAGIC 0x1e75a2b9
-/* #define DEBUG_ISDN_X25 if you want isdn_x25 debugging messages */
-#ifdef DEBUG_ISDN_X25
-# define IX25DEBUG(fmt, args...) printk(KERN_DEBUG fmt, ##args)
-#else
-# define IX25DEBUG(fmt, args...)
-#endif
-
-#include <linux/skbuff.h>
-#include <linux/isdn.h>
-#include <linux/concap.h>
-
-extern struct concap_proto_ops *isdn_x25iface_concap_proto_ops_pt;
-extern struct concap_proto *isdn_x25iface_proto_new(void);
-
-
-
-#endif
diff --git a/drivers/isdn/isdnloop/Makefile b/drivers/isdn/isdnloop/Makefile
deleted file mode 100644
index 5ff4c0e09768..000000000000
--- a/drivers/isdn/isdnloop/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-# Makefile for the isdnloop ISDN device driver
-
-# Each configuration option enables a list of files.
-
-obj-$(CONFIG_ISDN_DRV_LOOP) += isdnloop.o
diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c
deleted file mode 100644
index 755c6bbc9553..000000000000
--- a/drivers/isdn/isdnloop/isdnloop.c
+++ /dev/null
@@ -1,1528 +0,0 @@
-/* $Id: isdnloop.c,v 1.11.6.7 2001/11/11 19:54:31 kai Exp $
- *
- * ISDN low-level module implementing a dummy loop driver.
- *
- * Copyright 1997 by Fritz Elfert (fritz@isdn4linux.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include "isdnloop.h"
-
-static char *isdnloop_id = "loop0";
-
-MODULE_DESCRIPTION("ISDN4Linux: Pseudo Driver that simulates an ISDN card");
-MODULE_AUTHOR("Fritz Elfert");
-MODULE_LICENSE("GPL");
-module_param(isdnloop_id, charp, 0);
-MODULE_PARM_DESC(isdnloop_id, "ID-String of first card");
-
-static int isdnloop_addcard(char *);
-
-/*
- * Free queue completely.
- *
- * Parameter:
- * card = pointer to card struct
- * channel = channel number
- */
-static void
-isdnloop_free_queue(isdnloop_card *card, int channel)
-{
- struct sk_buff_head *queue = &card->bqueue[channel];
-
- skb_queue_purge(queue);
- card->sndcount[channel] = 0;
-}
-
-/*
- * Send B-Channel data to another virtual card.
- * This routine is called via timer-callback from isdnloop_pollbchan().
- *
- * Parameter:
- * card = pointer to card struct.
- * ch = channel number (0-based)
- */
-static void
-isdnloop_bchan_send(isdnloop_card *card, int ch)
-{
- isdnloop_card *rcard = card->rcard[ch];
- int rch = card->rch[ch], len, ack;
- struct sk_buff *skb;
- isdn_ctrl cmd;
-
- while (card->sndcount[ch]) {
- skb = skb_dequeue(&card->bqueue[ch]);
- if (skb) {
- len = skb->len;
- card->sndcount[ch] -= len;
- ack = *(skb->head); /* used as scratch area */
- cmd.driver = card->myid;
- cmd.arg = ch;
- if (rcard) {
- rcard->interface.rcvcallb_skb(rcard->myid, rch, skb);
- } else {
- printk(KERN_WARNING "isdnloop: no rcard, skb dropped\n");
- dev_kfree_skb(skb);
-
- }
- cmd.command = ISDN_STAT_BSENT;
- cmd.parm.length = len;
- card->interface.statcallb(&cmd);
- } else
- card->sndcount[ch] = 0;
- }
-}
-
-/*
- * Send/Receive Data to/from the B-Channel.
- * This routine is called via timer-callback.
- * It schedules itself while any B-Channel is open.
- *
- * Parameter:
- * data = pointer to card struct, set by kernel timer.data
- */
-static void
-isdnloop_pollbchan(struct timer_list *t)
-{
- isdnloop_card *card = from_timer(card, t, rb_timer);
- unsigned long flags;
-
- if (card->flags & ISDNLOOP_FLAGS_B1ACTIVE)
- isdnloop_bchan_send(card, 0);
- if (card->flags & ISDNLOOP_FLAGS_B2ACTIVE)
- isdnloop_bchan_send(card, 1);
- if (card->flags & (ISDNLOOP_FLAGS_B1ACTIVE | ISDNLOOP_FLAGS_B2ACTIVE)) {
- /* schedule b-channel polling again */
- spin_lock_irqsave(&card->isdnloop_lock, flags);
- card->rb_timer.expires = jiffies + ISDNLOOP_TIMER_BCREAD;
- add_timer(&card->rb_timer);
- card->flags |= ISDNLOOP_FLAGS_RBTIMER;
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
- } else
- card->flags &= ~ISDNLOOP_FLAGS_RBTIMER;
-}
-
-/*
- * Parse ICN-type setup string and fill fields of setup-struct
- * with parsed data.
- *
- * Parameter:
- * setup = setup string, format: [caller-id],si1,si2,[called-id]
- * cmd = pointer to struct to be filled.
- */
-static void
-isdnloop_parse_setup(char *setup, isdn_ctrl *cmd)
-{
- char *t = setup;
- char *s = strchr(t, ',');
-
- *s++ = '\0';
- strlcpy(cmd->parm.setup.phone, t, sizeof(cmd->parm.setup.phone));
- s = strchr(t = s, ',');
- *s++ = '\0';
- if (!strlen(t))
- cmd->parm.setup.si1 = 0;
- else
- cmd->parm.setup.si1 = simple_strtoul(t, NULL, 10);
- s = strchr(t = s, ',');
- *s++ = '\0';
- if (!strlen(t))
- cmd->parm.setup.si2 = 0;
- else
- cmd->parm.setup.si2 =
- simple_strtoul(t, NULL, 10);
- strlcpy(cmd->parm.setup.eazmsn, s, sizeof(cmd->parm.setup.eazmsn));
- cmd->parm.setup.plan = 0;
- cmd->parm.setup.screen = 0;
-}
-
-typedef struct isdnloop_stat {
- char *statstr;
- int command;
- int action;
-} isdnloop_stat;
-/* *INDENT-OFF* */
-static isdnloop_stat isdnloop_stat_table[] = {
- {"BCON_", ISDN_STAT_BCONN, 1}, /* B-Channel connected */
- {"BDIS_", ISDN_STAT_BHUP, 2}, /* B-Channel disconnected */
- {"DCON_", ISDN_STAT_DCONN, 0}, /* D-Channel connected */
- {"DDIS_", ISDN_STAT_DHUP, 0}, /* D-Channel disconnected */
- {"DCAL_I", ISDN_STAT_ICALL, 3}, /* Incoming call dialup-line */
- {"DSCA_I", ISDN_STAT_ICALL, 3}, /* Incoming call 1TR6-SPV */
- {"FCALL", ISDN_STAT_ICALL, 4}, /* Leased line connection up */
- {"CIF", ISDN_STAT_CINF, 5}, /* Charge-info, 1TR6-type */
- {"AOC", ISDN_STAT_CINF, 6}, /* Charge-info, DSS1-type */
- {"CAU", ISDN_STAT_CAUSE, 7}, /* Cause code */
- {"TEI OK", ISDN_STAT_RUN, 0}, /* Card connected to wallplug */
- {"E_L1: ACT FAIL", ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */
- {"E_L2: DATA LIN", ISDN_STAT_BHUP, 8}, /* Layer-2 data link lost */
- {"E_L1: ACTIVATION FAILED",
- ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */
- {NULL, 0, -1}
-};
-/* *INDENT-ON* */
-
-
-/*
- * Parse Status message-strings from virtual card.
- * Depending on status, call statcallb for sending messages to upper
- * levels. Also set/reset B-Channel active-flags.
- *
- * Parameter:
- * status = status string to parse.
- * channel = channel where message comes from.
- * card = card where message comes from.
- */
-static void
-isdnloop_parse_status(u_char *status, int channel, isdnloop_card *card)
-{
- isdnloop_stat *s = isdnloop_stat_table;
- int action = -1;
- isdn_ctrl cmd;
-
- while (s->statstr) {
- if (!strncmp(status, s->statstr, strlen(s->statstr))) {
- cmd.command = s->command;
- action = s->action;
- break;
- }
- s++;
- }
- if (action == -1)
- return;
- cmd.driver = card->myid;
- cmd.arg = channel;
- switch (action) {
- case 1:
- /* BCON_x */
- card->flags |= (channel) ?
- ISDNLOOP_FLAGS_B2ACTIVE : ISDNLOOP_FLAGS_B1ACTIVE;
- break;
- case 2:
- /* BDIS_x */
- card->flags &= ~((channel) ?
- ISDNLOOP_FLAGS_B2ACTIVE : ISDNLOOP_FLAGS_B1ACTIVE);
- isdnloop_free_queue(card, channel);
- break;
- case 3:
- /* DCAL_I and DSCA_I */
- isdnloop_parse_setup(status + 6, &cmd);
- break;
- case 4:
- /* FCALL */
- sprintf(cmd.parm.setup.phone, "LEASED%d", card->myid);
- sprintf(cmd.parm.setup.eazmsn, "%d", channel + 1);
- cmd.parm.setup.si1 = 7;
- cmd.parm.setup.si2 = 0;
- cmd.parm.setup.plan = 0;
- cmd.parm.setup.screen = 0;
- break;
- case 5:
- /* CIF */
- strlcpy(cmd.parm.num, status + 3, sizeof(cmd.parm.num));
- break;
- case 6:
- /* AOC */
- snprintf(cmd.parm.num, sizeof(cmd.parm.num), "%d",
- (int) simple_strtoul(status + 7, NULL, 16));
- break;
- case 7:
- /* CAU */
- status += 3;
- if (strlen(status) == 4)
- snprintf(cmd.parm.num, sizeof(cmd.parm.num), "%s%c%c",
- status + 2, *status, *(status + 1));
- else
- strlcpy(cmd.parm.num, status + 1, sizeof(cmd.parm.num));
- break;
- case 8:
- /* Misc Errors on L1 and L2 */
- card->flags &= ~ISDNLOOP_FLAGS_B1ACTIVE;
- isdnloop_free_queue(card, 0);
- cmd.arg = 0;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
- cmd.command = ISDN_STAT_DHUP;
- cmd.arg = 0;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
- cmd.command = ISDN_STAT_BHUP;
- card->flags &= ~ISDNLOOP_FLAGS_B2ACTIVE;
- isdnloop_free_queue(card, 1);
- cmd.arg = 1;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
- cmd.command = ISDN_STAT_DHUP;
- cmd.arg = 1;
- cmd.driver = card->myid;
- break;
- }
- card->interface.statcallb(&cmd);
-}
-
-/*
- * Store a cwcharacter into ringbuffer for reading from /dev/isdnctrl
- *
- * Parameter:
- * card = pointer to card struct.
- * c = char to store.
- */
-static void
-isdnloop_putmsg(isdnloop_card *card, unsigned char c)
-{
- ulong flags;
-
- spin_lock_irqsave(&card->isdnloop_lock, flags);
- *card->msg_buf_write++ = (c == 0xff) ? '\n' : c;
- if (card->msg_buf_write == card->msg_buf_read) {
- if (++card->msg_buf_read > card->msg_buf_end)
- card->msg_buf_read = card->msg_buf;
- }
- if (card->msg_buf_write > card->msg_buf_end)
- card->msg_buf_write = card->msg_buf;
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
-}
-
-/*
- * Poll a virtual cards message queue.
- * If there are new status-replies from the card, copy them to
- * ringbuffer for reading on /dev/isdnctrl and call
- * isdnloop_parse_status() for processing them. Watch for special
- * Firmware bootmessage and parse it, to get the D-Channel protocol.
- * If there are B-Channels open, initiate a timer-callback to
- * isdnloop_pollbchan().
- * This routine is called periodically via timer interrupt.
- *
- * Parameter:
- * data = pointer to card struct
- */
-static void
-isdnloop_polldchan(struct timer_list *t)
-{
- isdnloop_card *card = from_timer(card, t, st_timer);
- struct sk_buff *skb;
- int avail;
- int left;
- u_char c;
- int ch;
- unsigned long flags;
- u_char *p;
- isdn_ctrl cmd;
-
- skb = skb_dequeue(&card->dqueue);
- if (skb)
- avail = skb->len;
- else
- avail = 0;
- for (left = avail; left > 0; left--) {
- c = *skb->data;
- skb_pull(skb, 1);
- isdnloop_putmsg(card, c);
- card->imsg[card->iptr] = c;
- if (card->iptr < 59)
- card->iptr++;
- if (!skb->len) {
- avail++;
- isdnloop_putmsg(card, '\n');
- card->imsg[card->iptr] = 0;
- card->iptr = 0;
- if (card->imsg[0] == '0' && card->imsg[1] >= '0' &&
- card->imsg[1] <= '2' && card->imsg[2] == ';') {
- ch = (card->imsg[1] - '0') - 1;
- p = &card->imsg[3];
- isdnloop_parse_status(p, ch, card);
- } else {
- p = card->imsg;
- if (!strncmp(p, "DRV1.", 5)) {
- printk(KERN_INFO "isdnloop: (%s) %s\n", CID, p);
- if (!strncmp(p + 7, "TC", 2)) {
- card->ptype = ISDN_PTYPE_1TR6;
- card->interface.features |= ISDN_FEATURE_P_1TR6;
- printk(KERN_INFO
- "isdnloop: (%s) 1TR6-Protocol loaded and running\n", CID);
- }
- if (!strncmp(p + 7, "EC", 2)) {
- card->ptype = ISDN_PTYPE_EURO;
- card->interface.features |= ISDN_FEATURE_P_EURO;
- printk(KERN_INFO
- "isdnloop: (%s) Euro-Protocol loaded and running\n", CID);
- }
- continue;
-
- }
- }
- }
- }
- if (avail) {
- cmd.command = ISDN_STAT_STAVAIL;
- cmd.driver = card->myid;
- cmd.arg = avail;
- card->interface.statcallb(&cmd);
- }
- if (card->flags & (ISDNLOOP_FLAGS_B1ACTIVE | ISDNLOOP_FLAGS_B2ACTIVE))
- if (!(card->flags & ISDNLOOP_FLAGS_RBTIMER)) {
- /* schedule b-channel polling */
- card->flags |= ISDNLOOP_FLAGS_RBTIMER;
- spin_lock_irqsave(&card->isdnloop_lock, flags);
- del_timer(&card->rb_timer);
- card->rb_timer.expires = jiffies + ISDNLOOP_TIMER_BCREAD;
- add_timer(&card->rb_timer);
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
- }
- /* schedule again */
- spin_lock_irqsave(&card->isdnloop_lock, flags);
- card->st_timer.expires = jiffies + ISDNLOOP_TIMER_DCREAD;
- add_timer(&card->st_timer);
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
-}
-
-/*
- * Append a packet to the transmit buffer-queue.
- *
- * Parameter:
- * channel = Number of B-channel
- * skb = packet to send.
- * card = pointer to card-struct
- * Return:
- * Number of bytes transferred, -E??? on error
- */
-static int
-isdnloop_sendbuf(int channel, struct sk_buff *skb, isdnloop_card *card)
-{
- int len = skb->len;
- unsigned long flags;
- struct sk_buff *nskb;
-
- if (len > 4000) {
- printk(KERN_WARNING
- "isdnloop: Send packet too large\n");
- return -EINVAL;
- }
- if (len) {
- if (!(card->flags & (channel ? ISDNLOOP_FLAGS_B2ACTIVE : ISDNLOOP_FLAGS_B1ACTIVE)))
- return 0;
- if (card->sndcount[channel] > ISDNLOOP_MAX_SQUEUE)
- return 0;
- spin_lock_irqsave(&card->isdnloop_lock, flags);
- nskb = dev_alloc_skb(skb->len);
- if (nskb) {
- skb_copy_from_linear_data(skb,
- skb_put(nskb, len), len);
- skb_queue_tail(&card->bqueue[channel], nskb);
- dev_kfree_skb(skb);
- } else
- len = 0;
- card->sndcount[channel] += len;
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
- }
- return len;
-}
-
-/*
- * Read the messages from the card's ringbuffer
- *
- * Parameter:
- * buf = pointer to buffer.
- * len = number of bytes to read.
- * user = flag, 1: called from userlevel 0: called from kernel.
- * card = pointer to card struct.
- * Return:
- * number of bytes actually transferred.
- */
-static int
-isdnloop_readstatus(u_char __user *buf, int len, isdnloop_card *card)
-{
- int count;
- u_char __user *p;
-
- for (p = buf, count = 0; count < len; p++, count++) {
- if (card->msg_buf_read == card->msg_buf_write)
- return count;
- if (put_user(*card->msg_buf_read++, p))
- return -EFAULT;
- if (card->msg_buf_read > card->msg_buf_end)
- card->msg_buf_read = card->msg_buf;
- }
- return count;
-}
-
-/*
- * Simulate a card's response by appending it to the cards
- * message queue.
- *
- * Parameter:
- * card = pointer to card struct.
- * s = pointer to message-string.
- * ch = channel: 0 = generic messages, 1 and 2 = D-channel messages.
- * Return:
- * 0 on success, 1 on memory squeeze.
- */
-static int
-isdnloop_fake(isdnloop_card *card, char *s, int ch)
-{
- struct sk_buff *skb;
- int len = strlen(s) + ((ch >= 0) ? 3 : 0);
- skb = dev_alloc_skb(len);
- if (!skb) {
- printk(KERN_WARNING "isdnloop: Out of memory in isdnloop_fake\n");
- return 1;
- }
- if (ch >= 0)
- sprintf(skb_put(skb, 3), "%02d;", ch);
- skb_put_data(skb, s, strlen(s));
- skb_queue_tail(&card->dqueue, skb);
- return 0;
-}
-/* *INDENT-OFF* */
-static isdnloop_stat isdnloop_cmd_table[] = {
- {"BCON_R", 0, 1}, /* B-Channel connect */
- {"BCON_I", 0, 17}, /* B-Channel connect ind */
- {"BDIS_R", 0, 2}, /* B-Channel disconnect */
- {"DDIS_R", 0, 3}, /* D-Channel disconnect */
- {"DCON_R", 0, 16}, /* D-Channel connect */
- {"DSCA_R", 0, 4}, /* Dial 1TR6-SPV */
- {"DCAL_R", 0, 5}, /* Dial */
- {"EAZC", 0, 6}, /* Clear EAZ listener */
- {"EAZ", 0, 7}, /* Set EAZ listener */
- {"SEEAZ", 0, 8}, /* Get EAZ listener */
- {"MSN", 0, 9}, /* Set/Clear MSN listener */
- {"MSALL", 0, 10}, /* Set multi MSN listeners */
- {"SETSIL", 0, 11}, /* Set SI list */
- {"SEESIL", 0, 12}, /* Get SI list */
- {"SILC", 0, 13}, /* Clear SI list */
- {"LOCK", 0, -1}, /* LOCK channel */
- {"UNLOCK", 0, -1}, /* UNLOCK channel */
- {"FV2ON", 1, 14}, /* Leased mode on */
- {"FV2OFF", 1, 15}, /* Leased mode off */
- {NULL, 0, -1}
-};
-/* *INDENT-ON* */
-
-
-/*
- * Simulate an error-response from a card.
- *
- * Parameter:
- * card = pointer to card struct.
- */
-static void
-isdnloop_fake_err(isdnloop_card *card)
-{
- char buf[64];
-
- snprintf(buf, sizeof(buf), "E%s", card->omsg);
- isdnloop_fake(card, buf, -1);
- isdnloop_fake(card, "NAK", -1);
-}
-
-static u_char ctable_eu[] = {0x00, 0x11, 0x01, 0x12};
-static u_char ctable_1t[] = {0x00, 0x3b, 0x01, 0x3a};
-
-/*
- * Assemble a simplified cause message depending on the
- * D-channel protocol used.
- *
- * Parameter:
- * card = pointer to card struct.
- * loc = location: 0 = local, 1 = remote.
- * cau = cause: 1 = busy, 2 = nonexistent callerid, 3 = no user responding.
- * Return:
- * Pointer to buffer containing the assembled message.
- */
-static char *
-isdnloop_unicause(isdnloop_card *card, int loc, int cau)
-{
- static char buf[6];
-
- switch (card->ptype) {
- case ISDN_PTYPE_EURO:
- sprintf(buf, "E%02X%02X", (loc) ? 4 : 2, ctable_eu[cau]);
- break;
- case ISDN_PTYPE_1TR6:
- sprintf(buf, "%02X44", ctable_1t[cau]);
- break;
- default:
- return "0000";
- }
- return buf;
-}
-
-/*
- * Release a virtual connection. Called from timer interrupt, when
- * called party did not respond.
- *
- * Parameter:
- * card = pointer to card struct.
- * ch = channel (0-based)
- */
-static void
-isdnloop_atimeout(isdnloop_card *card, int ch)
-{
- unsigned long flags;
- char buf[60];
-
- spin_lock_irqsave(&card->isdnloop_lock, flags);
- if (card->rcard[ch]) {
- isdnloop_fake(card->rcard[ch], "DDIS_I", card->rch[ch] + 1);
- card->rcard[ch]->rcard[card->rch[ch]] = NULL;
- card->rcard[ch] = NULL;
- }
- isdnloop_fake(card, "DDIS_I", ch + 1);
- /* No user responding */
- sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 3));
- isdnloop_fake(card, buf, ch + 1);
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
-}
-
-/*
- * Wrapper for isdnloop_atimeout().
- */
-static void
-isdnloop_atimeout0(struct timer_list *t)
-{
- isdnloop_card *card = from_timer(card, t, c_timer[0]);
-
- isdnloop_atimeout(card, 0);
-}
-
-/*
- * Wrapper for isdnloop_atimeout().
- */
-static void
-isdnloop_atimeout1(struct timer_list *t)
-{
- isdnloop_card *card = from_timer(card, t, c_timer[1]);
-
- isdnloop_atimeout(card, 1);
-}
-
-/*
- * Install a watchdog for a user, not responding.
- *
- * Parameter:
- * card = pointer to card struct.
- * ch = channel to watch for.
- */
-static void
-isdnloop_start_ctimer(isdnloop_card *card, int ch)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&card->isdnloop_lock, flags);
- timer_setup(&card->c_timer[ch], ch ? isdnloop_atimeout1
- : isdnloop_atimeout0, 0);
- card->c_timer[ch].expires = jiffies + ISDNLOOP_TIMER_ALERTWAIT;
- add_timer(&card->c_timer[ch]);
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
-}
-
-/*
- * Kill a pending channel watchdog.
- *
- * Parameter:
- * card = pointer to card struct.
- * ch = channel (0-based).
- */
-static void
-isdnloop_kill_ctimer(isdnloop_card *card, int ch)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&card->isdnloop_lock, flags);
- del_timer(&card->c_timer[ch]);
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
-}
-
-static u_char si2bit[] = {0, 1, 0, 0, 0, 2, 0, 4, 0, 0};
-static u_char bit2si[] = {1, 5, 7};
-
-/*
- * Try finding a listener for an outgoing call.
- *
- * Parameter:
- * card = pointer to calling card.
- * p = pointer to ICN-type setup-string.
- * lch = channel of calling card.
- * cmd = pointer to struct to be filled when parsing setup.
- * Return:
- * 0 = found match, alerting should happen.
- * 1 = found matching number but it is busy.
- * 2 = no matching listener.
- * 3 = found matching number but SI does not match.
- */
-static int
-isdnloop_try_call(isdnloop_card *card, char *p, int lch, isdn_ctrl *cmd)
-{
- isdnloop_card *cc = cards;
- unsigned long flags;
- int ch;
- int num_match;
- int i;
- char *e;
- char nbuf[32];
-
- isdnloop_parse_setup(p, cmd);
- while (cc) {
- for (ch = 0; ch < 2; ch++) {
- /* Exclude ourself */
- if ((cc == card) && (ch == lch))
- continue;
- num_match = 0;
- switch (cc->ptype) {
- case ISDN_PTYPE_EURO:
- for (i = 0; i < 3; i++)
- if (!(strcmp(cc->s0num[i], cmd->parm.setup.phone)))
- num_match = 1;
- break;
- case ISDN_PTYPE_1TR6:
- e = cc->eazlist[ch];
- while (*e) {
- sprintf(nbuf, "%s%c", cc->s0num[0], *e);
- if (!(strcmp(nbuf, cmd->parm.setup.phone)))
- num_match = 1;
- e++;
- }
- }
- if (num_match) {
- spin_lock_irqsave(&card->isdnloop_lock, flags);
- /* channel idle? */
- if (!(cc->rcard[ch])) {
- /* Check SI */
- if (!(si2bit[cmd->parm.setup.si1] & cc->sil[ch])) {
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
- return 3;
- }
- /* ch is idle, si and number matches */
- cc->rcard[ch] = card;
- cc->rch[ch] = lch;
- card->rcard[lch] = cc;
- card->rch[lch] = ch;
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
- return 0;
- } else {
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
- /* num matches, but busy */
- if (ch == 1)
- return 1;
- }
- }
- }
- cc = cc->next;
- }
- return 2;
-}
-
-/*
- * Depending on D-channel protocol and caller/called, modify
- * phone number.
- *
- * Parameter:
- * card = pointer to card struct.
- * phone = pointer phone number.
- * caller = flag: 1 = caller, 0 = called.
- * Return:
- * pointer to new phone number.
- */
-static char *
-isdnloop_vstphone(isdnloop_card *card, char *phone, int caller)
-{
- int i;
- static char nphone[30];
-
- if (!card) {
- printk("BUG!!!\n");
- return "";
- }
- switch (card->ptype) {
- case ISDN_PTYPE_EURO:
- if (caller) {
- for (i = 0; i < 2; i++)
- if (!(strcmp(card->s0num[i], phone)))
- return phone;
- return card->s0num[0];
- }
- return phone;
- break;
- case ISDN_PTYPE_1TR6:
- if (caller) {
- sprintf(nphone, "%s%c", card->s0num[0], phone[0]);
- return nphone;
- } else
- return &phone[strlen(phone) - 1];
- break;
- }
- return "";
-}
-
-/*
- * Parse an ICN-type command string sent to the 'card'.
- * Perform misc. actions depending on the command.
- *
- * Parameter:
- * card = pointer to card struct.
- */
-static void
-isdnloop_parse_cmd(isdnloop_card *card)
-{
- char *p = card->omsg;
- isdn_ctrl cmd;
- char buf[60];
- isdnloop_stat *s = isdnloop_cmd_table;
- int action = -1;
- int i;
- int ch;
-
- if ((card->omsg[0] != '0') && (card->omsg[2] != ';')) {
- isdnloop_fake_err(card);
- return;
- }
- ch = card->omsg[1] - '0';
- if ((ch < 0) || (ch > 2)) {
- isdnloop_fake_err(card);
- return;
- }
- p += 3;
- while (s->statstr) {
- if (!strncmp(p, s->statstr, strlen(s->statstr))) {
- action = s->action;
- if (s->command && (ch != 0)) {
- isdnloop_fake_err(card);
- return;
- }
- break;
- }
- s++;
- }
- if (action == -1)
- return;
- switch (action) {
- case 1:
- /* 0x;BCON_R */
- if (card->rcard[ch - 1]) {
- isdnloop_fake(card->rcard[ch - 1], "BCON_I",
- card->rch[ch - 1] + 1);
- isdnloop_fake(card, "BCON_C", ch);
- }
- break;
- case 17:
- /* 0x;BCON_I */
- if (card->rcard[ch - 1]) {
- isdnloop_fake(card->rcard[ch - 1], "BCON_C",
- card->rch[ch - 1] + 1);
- }
- break;
- case 2:
- /* 0x;BDIS_R */
- isdnloop_fake(card, "BDIS_C", ch);
- if (card->rcard[ch - 1]) {
- isdnloop_fake(card->rcard[ch - 1], "BDIS_I",
- card->rch[ch - 1] + 1);
- }
- break;
- case 16:
- /* 0x;DCON_R */
- isdnloop_kill_ctimer(card, ch - 1);
- if (card->rcard[ch - 1]) {
- isdnloop_kill_ctimer(card->rcard[ch - 1], card->rch[ch - 1]);
- isdnloop_fake(card->rcard[ch - 1], "DCON_C",
- card->rch[ch - 1] + 1);
- isdnloop_fake(card, "DCON_C", ch);
- }
- break;
- case 3:
- /* 0x;DDIS_R */
- isdnloop_kill_ctimer(card, ch - 1);
- if (card->rcard[ch - 1]) {
- isdnloop_kill_ctimer(card->rcard[ch - 1], card->rch[ch - 1]);
- isdnloop_fake(card->rcard[ch - 1], "DDIS_I",
- card->rch[ch - 1] + 1);
- card->rcard[ch - 1] = NULL;
- }
- isdnloop_fake(card, "DDIS_C", ch);
- break;
- case 4:
- /* 0x;DSCA_Rdd,yy,zz,oo */
- if (card->ptype != ISDN_PTYPE_1TR6) {
- isdnloop_fake_err(card);
- return;
- }
- /* Fall through */
- case 5:
- /* 0x;DCAL_Rdd,yy,zz,oo */
- p += 6;
- switch (isdnloop_try_call(card, p, ch - 1, &cmd)) {
- case 0:
- /* Alerting */
- sprintf(buf, "D%s_I%s,%02d,%02d,%s",
- (action == 4) ? "SCA" : "CAL",
- isdnloop_vstphone(card, cmd.parm.setup.eazmsn, 1),
- cmd.parm.setup.si1,
- cmd.parm.setup.si2,
- isdnloop_vstphone(card->rcard[ch - 1],
- cmd.parm.setup.phone, 0));
- isdnloop_fake(card->rcard[ch - 1], buf, card->rch[ch - 1] + 1);
- /* Fall through */
- case 3:
- /* si1 does not match, don't alert but start timer */
- isdnloop_start_ctimer(card, ch - 1);
- break;
- case 1:
- /* Remote busy */
- isdnloop_fake(card, "DDIS_I", ch);
- sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 1));
- isdnloop_fake(card, buf, ch);
- break;
- case 2:
- /* No such user */
- isdnloop_fake(card, "DDIS_I", ch);
- sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 2));
- isdnloop_fake(card, buf, ch);
- break;
- }
- break;
- case 6:
- /* 0x;EAZC */
- card->eazlist[ch - 1][0] = '\0';
- break;
- case 7:
- /* 0x;EAZ */
- p += 3;
- if (strlen(p) >= sizeof(card->eazlist[0]))
- break;
- strcpy(card->eazlist[ch - 1], p);
- break;
- case 8:
- /* 0x;SEEAZ */
- sprintf(buf, "EAZ-LIST: %s", card->eazlist[ch - 1]);
- isdnloop_fake(card, buf, ch + 1);
- break;
- case 9:
- /* 0x;MSN */
- break;
- case 10:
- /* 0x;MSNALL */
- break;
- case 11:
- /* 0x;SETSIL */
- p += 6;
- i = 0;
- while (strchr("0157", *p)) {
- if (i)
- card->sil[ch - 1] |= si2bit[*p - '0'];
- i = (*p++ == '0');
- }
- if (*p)
- isdnloop_fake_err(card);
- break;
- case 12:
- /* 0x;SEESIL */
- sprintf(buf, "SIN-LIST: ");
- p = buf + 10;
- for (i = 0; i < 3; i++)
- if (card->sil[ch - 1] & (1 << i))
- p += sprintf(p, "%02d", bit2si[i]);
- isdnloop_fake(card, buf, ch + 1);
- break;
- case 13:
- /* 0x;SILC */
- card->sil[ch - 1] = 0;
- break;
- case 14:
- /* 00;FV2ON */
- break;
- case 15:
- /* 00;FV2OFF */
- break;
- }
-}
-
-/*
- * Put command-strings into the of the 'card'. In reality, execute them
- * right in place by calling isdnloop_parse_cmd(). Also copy every
- * command to the read message ringbuffer, preceding it with a '>'.
- * These mesagges can be read at /dev/isdnctrl.
- *
- * Parameter:
- * buf = pointer to command buffer.
- * len = length of buffer data.
- * user = flag: 1 = called form userlevel, 0 called from kernel.
- * card = pointer to card struct.
- * Return:
- * number of bytes transferred (currently always equals len).
- */
-static int
-isdnloop_writecmd(const u_char *buf, int len, int user, isdnloop_card *card)
-{
- int xcount = 0;
- int ocount = 1;
- isdn_ctrl cmd;
-
- while (len) {
- int count = len;
- u_char *p;
- u_char msg[0x100];
-
- if (count > 255)
- count = 255;
- if (user) {
- if (copy_from_user(msg, buf, count))
- return -EFAULT;
- } else
- memcpy(msg, buf, count);
- isdnloop_putmsg(card, '>');
- for (p = msg; count > 0; count--, p++) {
- len--;
- xcount++;
- isdnloop_putmsg(card, *p);
- card->omsg[card->optr] = *p;
- if (*p == '\n') {
- card->omsg[card->optr] = '\0';
- card->optr = 0;
- isdnloop_parse_cmd(card);
- if (len) {
- isdnloop_putmsg(card, '>');
- ocount++;
- }
- } else {
- if (card->optr < 59)
- card->optr++;
- }
- ocount++;
- }
- }
- cmd.command = ISDN_STAT_STAVAIL;
- cmd.driver = card->myid;
- cmd.arg = ocount;
- card->interface.statcallb(&cmd);
- return xcount;
-}
-
-/*
- * Delete card's pending timers, send STOP to linklevel
- */
-static void
-isdnloop_stopcard(isdnloop_card *card)
-{
- unsigned long flags;
- isdn_ctrl cmd;
-
- spin_lock_irqsave(&card->isdnloop_lock, flags);
- if (card->flags & ISDNLOOP_FLAGS_RUNNING) {
- card->flags &= ~ISDNLOOP_FLAGS_RUNNING;
- del_timer(&card->st_timer);
- del_timer(&card->rb_timer);
- del_timer(&card->c_timer[0]);
- del_timer(&card->c_timer[1]);
- cmd.command = ISDN_STAT_STOP;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
- }
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
-}
-
-/*
- * Stop all cards before unload.
- */
-static void
-isdnloop_stopallcards(void)
-{
- isdnloop_card *p = cards;
-
- while (p) {
- isdnloop_stopcard(p);
- p = p->next;
- }
-}
-
-/*
- * Start a 'card'. Simulate card's boot message and set the phone
- * number(s) of the virtual 'S0-Interface'. Install D-channel
- * poll timer.
- *
- * Parameter:
- * card = pointer to card struct.
- * sdefp = pointer to struct holding ioctl parameters.
- * Return:
- * 0 on success, -E??? otherwise.
- */
-static int
-isdnloop_start(isdnloop_card *card, isdnloop_sdef *sdefp)
-{
- unsigned long flags;
- isdnloop_sdef sdef;
- int i;
-
- if (card->flags & ISDNLOOP_FLAGS_RUNNING)
- return -EBUSY;
- if (copy_from_user((char *) &sdef, (char *) sdefp, sizeof(sdef)))
- return -EFAULT;
-
- for (i = 0; i < 3; i++) {
- if (!memchr(sdef.num[i], 0, sizeof(sdef.num[i])))
- return -EINVAL;
- }
-
- spin_lock_irqsave(&card->isdnloop_lock, flags);
- switch (sdef.ptype) {
- case ISDN_PTYPE_EURO:
- if (isdnloop_fake(card, "DRV1.23EC-Q.931-CAPI-CNS-BASIS-20.02.96",
- -1)) {
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
- return -ENOMEM;
- }
- card->sil[0] = card->sil[1] = 4;
- if (isdnloop_fake(card, "TEI OK", 0)) {
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
- return -ENOMEM;
- }
- for (i = 0; i < 3; i++) {
- strlcpy(card->s0num[i], sdef.num[i],
- sizeof(card->s0num[0]));
- }
- break;
- case ISDN_PTYPE_1TR6:
- if (isdnloop_fake(card, "DRV1.04TC-1TR6-CAPI-CNS-BASIS-29.11.95",
- -1)) {
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
- return -ENOMEM;
- }
- card->sil[0] = card->sil[1] = 4;
- if (isdnloop_fake(card, "TEI OK", 0)) {
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
- return -ENOMEM;
- }
- strlcpy(card->s0num[0], sdef.num[0], sizeof(card->s0num[0]));
- card->s0num[1][0] = '\0';
- card->s0num[2][0] = '\0';
- break;
- default:
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
- printk(KERN_WARNING "isdnloop: Illegal D-channel protocol %d\n",
- sdef.ptype);
- return -EINVAL;
- }
- timer_setup(&card->rb_timer, isdnloop_pollbchan, 0);
- timer_setup(&card->st_timer, isdnloop_polldchan, 0);
- card->st_timer.expires = jiffies + ISDNLOOP_TIMER_DCREAD;
- add_timer(&card->st_timer);
- card->flags |= ISDNLOOP_FLAGS_RUNNING;
- spin_unlock_irqrestore(&card->isdnloop_lock, flags);
- return 0;
-}
-
-/*
- * Main handler for commands sent by linklevel.
- */
-static int
-isdnloop_command(isdn_ctrl *c, isdnloop_card *card)
-{
- ulong a;
- int i;
- char cbuf[80];
- isdn_ctrl cmd;
- isdnloop_cdef cdef;
-
- switch (c->command) {
- case ISDN_CMD_IOCTL:
- memcpy(&a, c->parm.num, sizeof(ulong));
- switch (c->arg) {
- case ISDNLOOP_IOCTL_DEBUGVAR:
- return (ulong) card;
- case ISDNLOOP_IOCTL_STARTUP:
- return isdnloop_start(card, (isdnloop_sdef *) a);
- break;
- case ISDNLOOP_IOCTL_ADDCARD:
- if (copy_from_user((char *)&cdef,
- (char *)a,
- sizeof(cdef)))
- return -EFAULT;
- return isdnloop_addcard(cdef.id1);
- break;
- case ISDNLOOP_IOCTL_LEASEDCFG:
- if (a) {
- if (!card->leased) {
- card->leased = 1;
- while (card->ptype == ISDN_PTYPE_UNKNOWN)
- schedule_timeout_interruptible(10);
- schedule_timeout_interruptible(10);
- sprintf(cbuf, "00;FV2ON\n01;EAZ1\n02;EAZ2\n");
- i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
- printk(KERN_INFO
- "isdnloop: (%s) Leased-line mode enabled\n",
- CID);
- cmd.command = ISDN_STAT_RUN;
- cmd.driver = card->myid;
- cmd.arg = 0;
- card->interface.statcallb(&cmd);
- }
- } else {
- if (card->leased) {
- card->leased = 0;
- sprintf(cbuf, "00;FV2OFF\n");
- i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
- printk(KERN_INFO
- "isdnloop: (%s) Leased-line mode disabled\n",
- CID);
- cmd.command = ISDN_STAT_RUN;
- cmd.driver = card->myid;
- cmd.arg = 0;
- card->interface.statcallb(&cmd);
- }
- }
- return 0;
- default:
- return -EINVAL;
- }
- break;
- case ISDN_CMD_DIAL:
- if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
- return -ENODEV;
- if (card->leased)
- break;
- if ((c->arg & 255) < ISDNLOOP_BCH) {
- char *p;
- char dcode[4];
-
- a = c->arg;
- p = c->parm.setup.phone;
- if (*p == 's' || *p == 'S') {
- /* Dial for SPV */
- p++;
- strcpy(dcode, "SCA");
- } else
- /* Normal Dial */
- strcpy(dcode, "CAL");
- snprintf(cbuf, sizeof(cbuf),
- "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1),
- dcode, p, c->parm.setup.si1,
- c->parm.setup.si2, c->parm.setup.eazmsn);
- i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
- }
- break;
- case ISDN_CMD_ACCEPTD:
- if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
- return -ENODEV;
- if (c->arg < ISDNLOOP_BCH) {
- a = c->arg + 1;
- cbuf[0] = 0;
- switch (card->l2_proto[a - 1]) {
- case ISDN_PROTO_L2_X75I:
- sprintf(cbuf, "%02d;BX75\n", (int) a);
- break;
-#ifdef CONFIG_ISDN_X25
- case ISDN_PROTO_L2_X25DTE:
- sprintf(cbuf, "%02d;BX2T\n", (int) a);
- break;
- case ISDN_PROTO_L2_X25DCE:
- sprintf(cbuf, "%02d;BX2C\n", (int) a);
- break;
-#endif
- case ISDN_PROTO_L2_HDLC:
- sprintf(cbuf, "%02d;BTRA\n", (int) a);
- break;
- }
- if (strlen(cbuf))
- i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
- sprintf(cbuf, "%02d;DCON_R\n", (int) a);
- i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
- }
- break;
- case ISDN_CMD_ACCEPTB:
- if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
- return -ENODEV;
- if (c->arg < ISDNLOOP_BCH) {
- a = c->arg + 1;
- switch (card->l2_proto[a - 1]) {
- case ISDN_PROTO_L2_X75I:
- sprintf(cbuf, "%02d;BCON_R,BX75\n", (int) a);
- break;
-#ifdef CONFIG_ISDN_X25
- case ISDN_PROTO_L2_X25DTE:
- sprintf(cbuf, "%02d;BCON_R,BX2T\n", (int) a);
- break;
- case ISDN_PROTO_L2_X25DCE:
- sprintf(cbuf, "%02d;BCON_R,BX2C\n", (int) a);
- break;
-#endif
- case ISDN_PROTO_L2_HDLC:
- sprintf(cbuf, "%02d;BCON_R,BTRA\n", (int) a);
- break;
- default:
- sprintf(cbuf, "%02d;BCON_R\n", (int) a);
- }
- printk(KERN_DEBUG "isdnloop writecmd '%s'\n", cbuf);
- i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
- break;
- case ISDN_CMD_HANGUP:
- if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
- return -ENODEV;
- if (c->arg < ISDNLOOP_BCH) {
- a = c->arg + 1;
- sprintf(cbuf, "%02d;BDIS_R\n%02d;DDIS_R\n", (int) a, (int) a);
- i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
- }
- break;
- case ISDN_CMD_SETEAZ:
- if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
- return -ENODEV;
- if (card->leased)
- break;
- if (c->arg < ISDNLOOP_BCH) {
- a = c->arg + 1;
- if (card->ptype == ISDN_PTYPE_EURO) {
- sprintf(cbuf, "%02d;MS%s%s\n", (int) a,
- c->parm.num[0] ? "N" : "ALL", c->parm.num);
- } else
- sprintf(cbuf, "%02d;EAZ%s\n", (int) a,
- c->parm.num[0] ? c->parm.num : (u_char *) "0123456789");
- i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
- }
- break;
- case ISDN_CMD_CLREAZ:
- if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
- return -ENODEV;
- if (card->leased)
- break;
- if (c->arg < ISDNLOOP_BCH) {
- a = c->arg + 1;
- if (card->ptype == ISDN_PTYPE_EURO)
- sprintf(cbuf, "%02d;MSNC\n", (int) a);
- else
- sprintf(cbuf, "%02d;EAZC\n", (int) a);
- i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
- }
- break;
- case ISDN_CMD_SETL2:
- if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
- return -ENODEV;
- if ((c->arg & 255) < ISDNLOOP_BCH) {
- a = c->arg;
- switch (a >> 8) {
- case ISDN_PROTO_L2_X75I:
- sprintf(cbuf, "%02d;BX75\n", (int) (a & 255) + 1);
- break;
-#ifdef CONFIG_ISDN_X25
- case ISDN_PROTO_L2_X25DTE:
- sprintf(cbuf, "%02d;BX2T\n", (int) (a & 255) + 1);
- break;
- case ISDN_PROTO_L2_X25DCE:
- sprintf(cbuf, "%02d;BX2C\n", (int) (a & 255) + 1);
- break;
-#endif
- case ISDN_PROTO_L2_HDLC:
- sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1);
- break;
- case ISDN_PROTO_L2_TRANS:
- sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1);
- break;
- default:
- return -EINVAL;
- }
- i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
- card->l2_proto[a & 255] = (a >> 8);
- }
- break;
- case ISDN_CMD_SETL3:
- if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
- return -ENODEV;
- return 0;
- default:
- return -EINVAL;
- }
- }
- return 0;
-}
-
-/*
- * Find card with given driverId
- */
-static inline isdnloop_card *
-isdnloop_findcard(int driverid)
-{
- isdnloop_card *p = cards;
-
- while (p) {
- if (p->myid == driverid)
- return p;
- p = p->next;
- }
- return (isdnloop_card *) 0;
-}
-
-/*
- * Wrapper functions for interface to linklevel
- */
-static int
-if_command(isdn_ctrl *c)
-{
- isdnloop_card *card = isdnloop_findcard(c->driver);
-
- if (card)
- return isdnloop_command(c, card);
- printk(KERN_ERR
- "isdnloop: if_command called with invalid driverId!\n");
- return -ENODEV;
-}
-
-static int
-if_writecmd(const u_char __user *buf, int len, int id, int channel)
-{
- isdnloop_card *card = isdnloop_findcard(id);
-
- if (card) {
- if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
- return -ENODEV;
- return isdnloop_writecmd(buf, len, 1, card);
- }
- printk(KERN_ERR
- "isdnloop: if_writecmd called with invalid driverId!\n");
- return -ENODEV;
-}
-
-static int
-if_readstatus(u_char __user *buf, int len, int id, int channel)
-{
- isdnloop_card *card = isdnloop_findcard(id);
-
- if (card) {
- if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
- return -ENODEV;
- return isdnloop_readstatus(buf, len, card);
- }
- printk(KERN_ERR
- "isdnloop: if_readstatus called with invalid driverId!\n");
- return -ENODEV;
-}
-
-static int
-if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
-{
- isdnloop_card *card = isdnloop_findcard(id);
-
- if (card) {
- if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
- return -ENODEV;
- /* ack request stored in skb scratch area */
- *(skb->head) = ack;
- return isdnloop_sendbuf(channel, skb, card);
- }
- printk(KERN_ERR
- "isdnloop: if_sendbuf called with invalid driverId!\n");
- return -ENODEV;
-}
-
-/*
- * Allocate a new card-struct, initialize it
- * link it into cards-list and register it at linklevel.
- */
-static isdnloop_card *
-isdnloop_initcard(char *id)
-{
- isdnloop_card *card;
- int i;
- card = kzalloc(sizeof(isdnloop_card), GFP_KERNEL);
- if (!card) {
- printk(KERN_WARNING
- "isdnloop: (%s) Could not allocate card-struct.\n", id);
- return (isdnloop_card *) 0;
- }
- card->interface.owner = THIS_MODULE;
- card->interface.channels = ISDNLOOP_BCH;
- card->interface.hl_hdrlen = 1; /* scratch area for storing ack flag*/
- card->interface.maxbufsize = 4000;
- card->interface.command = if_command;
- card->interface.writebuf_skb = if_sendbuf;
- card->interface.writecmd = if_writecmd;
- card->interface.readstat = if_readstatus;
- card->interface.features = ISDN_FEATURE_L2_X75I |
-#ifdef CONFIG_ISDN_X25
- ISDN_FEATURE_L2_X25DTE |
- ISDN_FEATURE_L2_X25DCE |
-#endif
- ISDN_FEATURE_L2_HDLC |
- ISDN_FEATURE_L3_TRANS |
- ISDN_FEATURE_P_UNKNOWN;
- card->ptype = ISDN_PTYPE_UNKNOWN;
- strlcpy(card->interface.id, id, sizeof(card->interface.id));
- card->msg_buf_write = card->msg_buf;
- card->msg_buf_read = card->msg_buf;
- card->msg_buf_end = &card->msg_buf[sizeof(card->msg_buf) - 1];
- for (i = 0; i < ISDNLOOP_BCH; i++) {
- card->l2_proto[i] = ISDN_PROTO_L2_X75I;
- skb_queue_head_init(&card->bqueue[i]);
- }
- skb_queue_head_init(&card->dqueue);
- spin_lock_init(&card->isdnloop_lock);
- card->next = cards;
- cards = card;
- if (!register_isdn(&card->interface)) {
- cards = cards->next;
- printk(KERN_WARNING
- "isdnloop: Unable to register %s\n", id);
- kfree(card);
- return (isdnloop_card *) 0;
- }
- card->myid = card->interface.channels;
- return card;
-}
-
-static int
-isdnloop_addcard(char *id1)
-{
- isdnloop_card *card;
- card = isdnloop_initcard(id1);
- if (!card) {
- return -EIO;
- }
- printk(KERN_INFO
- "isdnloop: (%s) virtual card added\n",
- card->interface.id);
- return 0;
-}
-
-static int __init
-isdnloop_init(void)
-{
- if (isdnloop_id)
- return isdnloop_addcard(isdnloop_id);
-
- return 0;
-}
-
-static void __exit
-isdnloop_exit(void)
-{
- isdn_ctrl cmd;
- isdnloop_card *card = cards;
- isdnloop_card *last;
- int i;
-
- isdnloop_stopallcards();
- while (card) {
- cmd.command = ISDN_STAT_UNLOAD;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
- for (i = 0; i < ISDNLOOP_BCH; i++)
- isdnloop_free_queue(card, i);
- card = card->next;
- }
- card = cards;
- while (card) {
- last = card;
- skb_queue_purge(&card->dqueue);
- card = card->next;
- kfree(last);
- }
- printk(KERN_NOTICE "isdnloop-ISDN-driver unloaded\n");
-}
-
-module_init(isdnloop_init);
-module_exit(isdnloop_exit);
diff --git a/drivers/isdn/isdnloop/isdnloop.h b/drivers/isdn/isdnloop/isdnloop.h
deleted file mode 100644
index e9e035552bb4..000000000000
--- a/drivers/isdn/isdnloop/isdnloop.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/* $Id: isdnloop.h,v 1.5.6.3 2001/09/23 22:24:56 kai Exp $
- *
- * Loopback lowlevel module for testing of linklevel.
- *
- * Copyright 1997 by Fritz Elfert (fritz@isdn4linux.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef isdnloop_h
-#define isdnloop_h
-
-#define ISDNLOOP_IOCTL_DEBUGVAR 0
-#define ISDNLOOP_IOCTL_ADDCARD 1
-#define ISDNLOOP_IOCTL_LEASEDCFG 2
-#define ISDNLOOP_IOCTL_STARTUP 3
-
-/* Struct for adding new cards */
-typedef struct isdnloop_cdef {
- char id1[10];
-} isdnloop_cdef;
-
-/* Struct for configuring cards */
-typedef struct isdnloop_sdef {
- int ptype;
- char num[3][20];
-} isdnloop_sdef;
-
-#if defined(__KERNEL__) || defined(__DEBUGVAR__)
-
-#ifdef __KERNEL__
-/* Kernel includes */
-
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/major.h>
-#include <asm/io.h>
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/ioport.h>
-#include <linux/timer.h>
-#include <linux/wait.h>
-#include <linux/isdnif.h>
-
-#endif /* __KERNEL__ */
-
-#define ISDNLOOP_FLAGS_B1ACTIVE 1 /* B-Channel-1 is open */
-#define ISDNLOOP_FLAGS_B2ACTIVE 2 /* B-Channel-2 is open */
-#define ISDNLOOP_FLAGS_RUNNING 4 /* Cards driver activated */
-#define ISDNLOOP_FLAGS_RBTIMER 8 /* scheduling of B-Channel-poll */
-#define ISDNLOOP_TIMER_BCREAD 1 /* B-Channel poll-cycle */
-#define ISDNLOOP_TIMER_DCREAD (HZ/2) /* D-Channel poll-cycle */
-#define ISDNLOOP_TIMER_ALERTWAIT (10 * HZ) /* Alert timeout */
-#define ISDNLOOP_MAX_SQUEUE 65536 /* Max. outstanding send-data */
-#define ISDNLOOP_BCH 2 /* channels per card */
-
-/*
- * Per card driver data
- */
-typedef struct isdnloop_card {
- struct isdnloop_card *next; /* Pointer to next device struct */
- struct isdnloop_card
- *rcard[ISDNLOOP_BCH]; /* Pointer to 'remote' card */
- int rch[ISDNLOOP_BCH]; /* 'remote' channel */
- int myid; /* Driver-Nr. assigned by linklevel */
- int leased; /* Flag: This Adapter is connected */
- /* to a leased line */
- int sil[ISDNLOOP_BCH]; /* SI's to listen for */
- char eazlist[ISDNLOOP_BCH][11];
- /* EAZ's to listen for */
- char s0num[3][20]; /* 1TR6 base-number or MSN's */
- unsigned short flags; /* Statusflags */
- int ptype; /* Protocol type (1TR6 or Euro) */
- struct timer_list st_timer; /* Timer for Status-Polls */
- struct timer_list rb_timer; /* Timer for B-Channel-Polls */
- struct timer_list
- c_timer[ISDNLOOP_BCH]; /* Timer for Alerting */
- int l2_proto[ISDNLOOP_BCH]; /* Current layer-2-protocol */
- isdn_if interface; /* Interface to upper layer */
- int iptr; /* Index to imsg-buffer */
- char imsg[60]; /* Internal buf for status-parsing */
- int optr; /* Index to omsg-buffer */
- char omsg[60]; /* Internal buf for cmd-parsing */
- char msg_buf[2048]; /* Buffer for status-messages */
- char *msg_buf_write; /* Writepointer for statusbuffer */
- char *msg_buf_read; /* Readpointer for statusbuffer */
- char *msg_buf_end; /* Pointer to end of statusbuffer */
- int sndcount[ISDNLOOP_BCH]; /* Byte-counters for B-Ch.-send */
- struct sk_buff_head
- bqueue[ISDNLOOP_BCH]; /* B-Channel queues */
- struct sk_buff_head dqueue; /* D-Channel queue */
- spinlock_t isdnloop_lock;
-} isdnloop_card;
-
-/*
- * Main driver data
- */
-#ifdef __KERNEL__
-static isdnloop_card *cards = (isdnloop_card *) 0;
-#endif /* __KERNEL__ */
-
-/* Utility-Macros */
-
-#define CID (card->interface.id)
-
-#endif /* defined(__KERNEL__) || defined(__DEBUGVAR__) */
-#endif /* isdnloop_h */
diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c
index cd036e87335a..038e72a84b33 100644
--- a/drivers/isdn/mISDN/dsp_core.c
+++ b/drivers/isdn/mISDN/dsp_core.c
@@ -4,8 +4,6 @@
* Karsten Keil (keil@isdn4linux.de)
*
* This file is (c) under GNU PUBLIC LICENSE
- * For changes and modifications please read
- * ../../../Documentation/isdn/mISDN.cert
*
* Thanks to Karsten Keil (great drivers)
* Cologne Chip (great chips)
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 760f73a49c9f..b0fdeef10bd9 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -784,6 +784,41 @@ config LEDS_NIC78BX
To compile this driver as a module, choose M here: the module
will be called leds-nic78bx.
+config LEDS_SPI_BYTE
+ tristate "LED support for SPI LED controller with a single byte"
+ depends on LEDS_CLASS
+ depends on SPI
+ depends on OF
+ help
+ This option enables support for LED controller which use a single byte
+ for controlling the brightness. Currently the following controller is
+ supported: Ubiquiti airCube ISP microcontroller based LED controller.
+
+config LEDS_TI_LMU_COMMON
+ tristate "LED driver for TI LMU"
+ depends on LEDS_CLASS
+ depends on REGMAP
+ help
+ Say Y to enable the LED driver for TI LMU devices.
+ This supports common features between the TI LM3532, LM3631, LM3632,
+ LM3633, LM3695 and LM3697.
+
+config LEDS_LM3697
+ tristate "LED driver for LM3697"
+ depends on LEDS_TI_LMU_COMMON
+ depends on I2C && OF
+ help
+ Say Y to enable the LM3697 LED driver for TI LMU devices.
+ This supports the LED device LM3697.
+
+config LEDS_LM36274
+ tristate "LED driver for LM36274"
+ depends on LEDS_TI_LMU_COMMON
+ depends on MFD_TI_LMU
+ help
+ Say Y to enable the LM36274 LED driver for TI LMU devices.
+ This supports the LED device LM36274.
+
comment "LED Triggers"
source "drivers/leds/trigger/Kconfig"
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 1e9702ebffee..41fb073a39c1 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -77,10 +77,14 @@ obj-$(CONFIG_LEDS_PM8058) += leds-pm8058.o
obj-$(CONFIG_LEDS_MLXCPLD) += leds-mlxcpld.o
obj-$(CONFIG_LEDS_MLXREG) += leds-mlxreg.o
obj-$(CONFIG_LEDS_NIC78BX) += leds-nic78bx.o
+obj-$(CONFIG_LEDS_SPI_BYTE) += leds-spi-byte.o
obj-$(CONFIG_LEDS_MT6323) += leds-mt6323.o
obj-$(CONFIG_LEDS_LM3692X) += leds-lm3692x.o
obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o
obj-$(CONFIG_LEDS_LM3601X) += leds-lm3601x.o
+obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o
+obj-$(CONFIG_LEDS_LM3697) += leds-lm3697.o
+obj-$(CONFIG_LEDS_LM36274) += leds-lm36274.o
# LED SPI Drivers
obj-$(CONFIG_LEDS_CR0014114) += leds-cr0014114.o
diff --git a/drivers/leds/led-class-flash.c b/drivers/leds/led-class-flash.c
index cf398275a53c..94980c654d89 100644
--- a/drivers/leds/led-class-flash.c
+++ b/drivers/leds/led-class-flash.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LED Flash class interface
*
* Copyright (C) 2015 Samsung Electronics Co., Ltd.
* Author: Jacek Anaszewski <j.anaszewski@samsung.com>
- *
- * 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.
*/
#include <linux/device.h>
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 85848c5da705..4793e77808e2 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LED Class Core
*
* Copyright (C) 2005 John Lenz <lenz@cs.wisc.edu>
* Copyright (C) 2005-2007 Richard Purdie <rpurdie@openedhand.com>
- *
- * 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.
*/
#include <linux/ctype.h>
diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c
index e3da7c03da1b..7107cd7e87cf 100644
--- a/drivers/leds/led-core.c
+++ b/drivers/leds/led-core.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LED Class Core
*
* Copyright 2005-2006 Openedhand Ltd.
*
* Author: Richard Purdie <rpurdie@openedhand.com>
- *
- * 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.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index 2d451b6c24af..8d11a5e23227 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LED Triggers Core
*
* Copyright 2005-2007 Openedhand Ltd.
*
* Author: Richard Purdie <rpurdie@openedhand.com>
- *
- * 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.
- *
*/
#include <linux/export.h>
diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c
index 036d4a536697..b3044c9a8120 100644
--- a/drivers/leds/leds-88pm860x.c
+++ b/drivers/leds/leds-88pm860x.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LED driver for Marvell 88PM860x
*
* Copyright (C) 2009 Marvell International Ltd.
* Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- * 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.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/leds/leds-aat1290.c b/drivers/leds/leds-aat1290.c
index 43bd8a43f36c..bf26f5bed1f0 100644
--- a/drivers/leds/leds-aat1290.c
+++ b/drivers/leds/leds-aat1290.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LED Flash class driver for the AAT1290
* 1.5A Step-Up Current Regulator for Flash LEDs
*
* Copyright (C) 2015, Samsung Electronics Co., Ltd.
* Author: Jacek Anaszewski <j.anaszewski@samsung.com>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/leds/leds-asic3.c b/drivers/leds/leds-asic3.c
index 1b71eac639f0..8cbc1b8bafa5 100644
--- a/drivers/leds/leds-asic3.c
+++ b/drivers/leds/leds-asic3.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Paul Parsons <lost.distance@yahoo.com>
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/leds/leds-bd2802.c b/drivers/leds/leds-bd2802.c
index 6b4de762a760..e7ec6bff2b5f 100644
--- a/drivers/leds/leds-bd2802.c
+++ b/drivers/leds/leds-bd2802.c
@@ -1,15 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* leds-bd2802.c - RGB LED Driver
*
* Copyright (C) 2009 Samsung Electronics
* Kim Kyuwon <q1.kim@samsung.com>
*
- * 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.
- *
* Datasheet: http://www.rohm.com/products/databook/driver/pdf/bd2802gu-e.pdf
- *
*/
#include <linux/module.h>
diff --git a/drivers/leds/leds-da903x.c b/drivers/leds/leds-da903x.c
index 5ff7d72f73aa..ed1b303f699f 100644
--- a/drivers/leds/leds-da903x.c
+++ b/drivers/leds/leds-da903x.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LEDs driver for Dialog Semiconductor DA9030/DA9034
*
@@ -6,10 +7,6 @@
*
* Copyright (C) 2006-2008 Marvell International Ltd.
* Eric Miao <eric.miao@marvell.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/leds/leds-fsg.c b/drivers/leds/leds-fsg.c
index 257a813c73f3..bc6b420637d6 100644
--- a/drivers/leds/leds-fsg.c
+++ b/drivers/leds/leds-fsg.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LED Driver for the Freecom FSG-3
*
@@ -8,11 +9,6 @@
* Based on leds-spitz.c
* Copyright 2005-2006 Openedhand Ltd.
* Author: Richard Purdie <rpurdie@openedhand.com>
- *
- * 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.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/leds/leds-gpio-register.c b/drivers/leds/leds-gpio-register.c
index 75717ba68ae0..b9187e71e0cf 100644
--- a/drivers/leds/leds-gpio-register.c
+++ b/drivers/leds/leds-gpio-register.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Pengutronix
* Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
- *
- * 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.
*/
#include <linux/err.h>
#include <linux/leds.h>
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index 998f2ff6914d..bdc98ddca1dc 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LEDs driver for GPIOs
*
* Copyright (C) 2007 8D Technologies inc.
* Raphael Assenat <raph@8d.com>
* Copyright (C) 2008 Freescale Semiconductor, 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.
- *
*/
#include <linux/err.h>
#include <linux/gpio.h>
diff --git a/drivers/leds/leds-hp6xx.c b/drivers/leds/leds-hp6xx.c
index 137969fcecbb..54af9e63c09c 100644
--- a/drivers/leds/leds-hp6xx.c
+++ b/drivers/leds/leds-hp6xx.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LED Triggers Core
* For the HP Jornada 620/660/680/690 handhelds
*
* Copyright 2008 Kristoffer Ericson <kristoffer.ericson@gmail.com>
* this driver is based on leds-spitz.c by Richard Purdie.
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/leds/leds-ipaq-micro.c b/drivers/leds/leds-ipaq-micro.c
index 02f17331379d..504a95b6ef45 100644
--- a/drivers/leds/leds-ipaq-micro.c
+++ b/drivers/leds/leds-ipaq-micro.c
@@ -1,7 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
- * 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.
*
* h3xxx atmel micro companion support, notification LED subdevice
*
diff --git a/drivers/leds/leds-is31fl32xx.c b/drivers/leds/leds-is31fl32xx.c
index 31a9d749c8be..6fbab70dfb04 100644
--- a/drivers/leds/leds-is31fl32xx.c
+++ b/drivers/leds/leds-is31fl32xx.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for ISSI IS31FL32xx family of I2C LED controllers
*
* Copyright 2015 Allworx Corp.
*
- *
- * 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.
- *
* Datasheets:
* http://www.issi.com/US/product-analog-fxled-driver.shtml
* http://www.si-en.com/product.asp?parentid=890
diff --git a/drivers/leds/leds-ktd2692.c b/drivers/leds/leds-ktd2692.c
index 45296aaca9da..f63918206bfb 100644
--- a/drivers/leds/leds-ktd2692.c
+++ b/drivers/leds/leds-ktd2692.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LED driver : leds-ktd2692.c
*
* Copyright (C) 2015 Samsung Electronics
* Ingi Kim <ingi2.kim@samsung.com>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/leds/leds-lm355x.c b/drivers/leds/leds-lm355x.c
index 6cb94f9a2f3f..a5abb499574b 100644
--- a/drivers/leds/leds-lm355x.c
+++ b/drivers/leds/leds-lm355x.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Simple driver for Texas Instruments LM355x LED Flash driver chip
* Copyright (C) 2012 Texas Instruments
-*
-* 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.
*/
#include <linux/module.h>
diff --git a/drivers/leds/leds-lm36274.c b/drivers/leds/leds-lm36274.c
new file mode 100644
index 000000000000..ed9dc857ec8f
--- /dev/null
+++ b/drivers/leds/leds-lm36274.c
@@ -0,0 +1,172 @@
+// SPDX-License-Identifier: GPL-2.0
+// TI LM36274 LED chip family driver
+// Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/leds.h>
+#include <linux/leds-ti-lmu-common.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include <linux/mfd/ti-lmu.h>
+#include <linux/mfd/ti-lmu-register.h>
+
+#include <uapi/linux/uleds.h>
+
+#define LM36274_MAX_STRINGS 4
+#define LM36274_BL_EN BIT(4)
+
+/**
+ * struct lm36274
+ * @pdev: platform device
+ * @led_dev: led class device
+ * @lmu_data: Register and setting values for common code
+ * @regmap: Devices register map
+ * @dev: Pointer to the devices device struct
+ * @led_sources - The LED strings supported in this array
+ * @num_leds - Number of LED strings are supported in this array
+ */
+struct lm36274 {
+ struct platform_device *pdev;
+ struct led_classdev led_dev;
+ struct ti_lmu_bank lmu_data;
+ struct regmap *regmap;
+ struct device *dev;
+
+ u32 led_sources[LM36274_MAX_STRINGS];
+ int num_leds;
+};
+
+static int lm36274_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness brt_val)
+{
+ struct lm36274 *led = container_of(led_cdev, struct lm36274, led_dev);
+
+ return ti_lmu_common_set_brightness(&led->lmu_data, brt_val);
+}
+
+static int lm36274_init(struct lm36274 *lm36274_data)
+{
+ int enable_val = 0;
+ int i;
+
+ for (i = 0; i < lm36274_data->num_leds; i++)
+ enable_val |= (1 << lm36274_data->led_sources[i]);
+
+ if (!enable_val) {
+ dev_err(lm36274_data->dev, "No LEDs were enabled\n");
+ return -EINVAL;
+ }
+
+ enable_val |= LM36274_BL_EN;
+
+ return regmap_write(lm36274_data->regmap, LM36274_REG_BL_EN,
+ enable_val);
+}
+
+static int lm36274_parse_dt(struct lm36274 *lm36274_data)
+{
+ struct fwnode_handle *child = NULL;
+ char label[LED_MAX_NAME_SIZE];
+ struct device *dev = &lm36274_data->pdev->dev;
+ const char *name;
+ int child_cnt;
+ int ret = -EINVAL;
+
+ /* There should only be 1 node */
+ child_cnt = device_get_child_node_count(dev);
+ if (child_cnt != 1)
+ return -EINVAL;
+
+ device_for_each_child_node(dev, child) {
+ ret = fwnode_property_read_string(child, "label", &name);
+ if (ret)
+ snprintf(label, sizeof(label),
+ "%s::", lm36274_data->pdev->name);
+ else
+ snprintf(label, sizeof(label),
+ "%s:%s", lm36274_data->pdev->name, name);
+
+ lm36274_data->num_leds = fwnode_property_read_u32_array(child,
+ "led-sources",
+ NULL, 0);
+ if (lm36274_data->num_leds <= 0)
+ return -ENODEV;
+
+ ret = fwnode_property_read_u32_array(child, "led-sources",
+ lm36274_data->led_sources,
+ lm36274_data->num_leds);
+ if (ret) {
+ dev_err(dev, "led-sources property missing\n");
+ return ret;
+ }
+
+ fwnode_property_read_string(child, "linux,default-trigger",
+ &lm36274_data->led_dev.default_trigger);
+
+ }
+
+ lm36274_data->lmu_data.regmap = lm36274_data->regmap;
+ lm36274_data->lmu_data.max_brightness = MAX_BRIGHTNESS_11BIT;
+ lm36274_data->lmu_data.msb_brightness_reg = LM36274_REG_BRT_MSB;
+ lm36274_data->lmu_data.lsb_brightness_reg = LM36274_REG_BRT_LSB;
+
+ lm36274_data->led_dev.name = label;
+ lm36274_data->led_dev.max_brightness = MAX_BRIGHTNESS_11BIT;
+ lm36274_data->led_dev.brightness_set_blocking = lm36274_brightness_set;
+
+ return 0;
+}
+
+static int lm36274_probe(struct platform_device *pdev)
+{
+ struct ti_lmu *lmu = dev_get_drvdata(pdev->dev.parent);
+ struct lm36274 *lm36274_data;
+ int ret;
+
+ lm36274_data = devm_kzalloc(&pdev->dev, sizeof(*lm36274_data),
+ GFP_KERNEL);
+ if (!lm36274_data)
+ return -ENOMEM;
+
+ lm36274_data->pdev = pdev;
+ lm36274_data->dev = lmu->dev;
+ lm36274_data->regmap = lmu->regmap;
+ dev_set_drvdata(&pdev->dev, lm36274_data);
+
+ ret = lm36274_parse_dt(lm36274_data);
+ if (ret) {
+ dev_err(lm36274_data->dev, "Failed to parse DT node\n");
+ return ret;
+ }
+
+ ret = lm36274_init(lm36274_data);
+ if (ret) {
+ dev_err(lm36274_data->dev, "Failed to init the device\n");
+ return ret;
+ }
+
+ return devm_led_classdev_register(lm36274_data->dev,
+ &lm36274_data->led_dev);
+}
+
+static const struct of_device_id of_lm36274_leds_match[] = {
+ { .compatible = "ti,lm36274-backlight", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, of_lm36274_leds_match);
+
+static struct platform_driver lm36274_driver = {
+ .probe = lm36274_probe,
+ .driver = {
+ .name = "lm36274-leds",
+ },
+};
+module_platform_driver(lm36274_driver)
+
+MODULE_DESCRIPTION("Texas Instruments LM36274 LED driver");
+MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/leds-lm3642.c b/drivers/leds/leds-lm3642.c
index cada0848db7b..480575442ed8 100644
--- a/drivers/leds/leds-lm3642.c
+++ b/drivers/leds/leds-lm3642.c
@@ -1,11 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Simple driver for Texas Instruments LM3642 LED Flash driver chip
* Copyright (C) 2012 Texas Instruments
-*
-* 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.
-*
*/
#include <linux/module.h>
#include <linux/delay.h>
diff --git a/drivers/leds/leds-lm3697.c b/drivers/leds/leds-lm3697.c
new file mode 100644
index 000000000000..54e0e35df824
--- /dev/null
+++ b/drivers/leds/leds-lm3697.c
@@ -0,0 +1,395 @@
+// SPDX-License-Identifier: GPL-2.0
+// TI LM3697 LED chip family driver
+// Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/leds-ti-lmu-common.h>
+
+#define LM3697_REV 0x0
+#define LM3697_RESET 0x1
+#define LM3697_OUTPUT_CONFIG 0x10
+#define LM3697_CTRL_A_RAMP 0x11
+#define LM3697_CTRL_B_RAMP 0x12
+#define LM3697_CTRL_A_B_RT_RAMP 0x13
+#define LM3697_CTRL_A_B_RAMP_CFG 0x14
+#define LM3697_CTRL_A_B_BRT_CFG 0x16
+#define LM3697_CTRL_A_FS_CURR_CFG 0x17
+#define LM3697_CTRL_B_FS_CURR_CFG 0x18
+#define LM3697_PWM_CFG 0x1c
+#define LM3697_CTRL_A_BRT_LSB 0x20
+#define LM3697_CTRL_A_BRT_MSB 0x21
+#define LM3697_CTRL_B_BRT_LSB 0x22
+#define LM3697_CTRL_B_BRT_MSB 0x23
+#define LM3697_CTRL_ENABLE 0x24
+
+#define LM3697_SW_RESET BIT(0)
+
+#define LM3697_CTRL_A_EN BIT(0)
+#define LM3697_CTRL_B_EN BIT(1)
+#define LM3697_CTRL_A_B_EN (LM3697_CTRL_A_EN | LM3697_CTRL_B_EN)
+
+#define LM3697_MAX_LED_STRINGS 3
+
+#define LM3697_CONTROL_A 0
+#define LM3697_CONTROL_B 1
+#define LM3697_MAX_CONTROL_BANKS 2
+
+/**
+ * struct lm3697_led -
+ * @hvled_strings: Array of LED strings associated with a control bank
+ * @label: LED label
+ * @led_dev: LED class device
+ * @priv: Pointer to the device struct
+ * @lmu_data: Register and setting values for common code
+ * @control_bank: Control bank the LED is associated to. 0 is control bank A
+ * 1 is control bank B
+ */
+struct lm3697_led {
+ u32 hvled_strings[LM3697_MAX_LED_STRINGS];
+ char label[LED_MAX_NAME_SIZE];
+ struct led_classdev led_dev;
+ struct lm3697 *priv;
+ struct ti_lmu_bank lmu_data;
+ int control_bank;
+ int enabled;
+ int num_leds;
+};
+
+/**
+ * struct lm3697 -
+ * @enable_gpio: Hardware enable gpio
+ * @regulator: LED supply regulator pointer
+ * @client: Pointer to the I2C client
+ * @regmap: Devices register map
+ * @dev: Pointer to the devices device struct
+ * @lock: Lock for reading/writing the device
+ * @leds: Array of LED strings
+ */
+struct lm3697 {
+ struct gpio_desc *enable_gpio;
+ struct regulator *regulator;
+ struct i2c_client *client;
+ struct regmap *regmap;
+ struct device *dev;
+ struct mutex lock;
+
+ int bank_cfg;
+
+ struct lm3697_led leds[];
+};
+
+static const struct reg_default lm3697_reg_defs[] = {
+ {LM3697_OUTPUT_CONFIG, 0x6},
+ {LM3697_CTRL_A_RAMP, 0x0},
+ {LM3697_CTRL_B_RAMP, 0x0},
+ {LM3697_CTRL_A_B_RT_RAMP, 0x0},
+ {LM3697_CTRL_A_B_RAMP_CFG, 0x0},
+ {LM3697_CTRL_A_B_BRT_CFG, 0x0},
+ {LM3697_CTRL_A_FS_CURR_CFG, 0x13},
+ {LM3697_CTRL_B_FS_CURR_CFG, 0x13},
+ {LM3697_PWM_CFG, 0xc},
+ {LM3697_CTRL_A_BRT_LSB, 0x0},
+ {LM3697_CTRL_A_BRT_MSB, 0x0},
+ {LM3697_CTRL_B_BRT_LSB, 0x0},
+ {LM3697_CTRL_B_BRT_MSB, 0x0},
+ {LM3697_CTRL_ENABLE, 0x0},
+};
+
+static const struct regmap_config lm3697_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = LM3697_CTRL_ENABLE,
+ .reg_defaults = lm3697_reg_defs,
+ .num_reg_defaults = ARRAY_SIZE(lm3697_reg_defs),
+ .cache_type = REGCACHE_FLAT,
+};
+
+static int lm3697_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness brt_val)
+{
+ struct lm3697_led *led = container_of(led_cdev, struct lm3697_led,
+ led_dev);
+ int ctrl_en_val = (1 << led->control_bank);
+ int ret;
+
+ mutex_lock(&led->priv->lock);
+
+ if (brt_val == LED_OFF) {
+ ret = regmap_update_bits(led->priv->regmap, LM3697_CTRL_ENABLE,
+ ctrl_en_val, ~ctrl_en_val);
+ if (ret) {
+ dev_err(&led->priv->client->dev, "Cannot write ctrl register\n");
+ goto brightness_out;
+ }
+
+ led->enabled = LED_OFF;
+ } else {
+ ret = ti_lmu_common_set_brightness(&led->lmu_data, brt_val);
+ if (ret) {
+ dev_err(&led->priv->client->dev,
+ "Cannot write brightness\n");
+ goto brightness_out;
+ }
+
+ if (!led->enabled) {
+ ret = regmap_update_bits(led->priv->regmap,
+ LM3697_CTRL_ENABLE,
+ ctrl_en_val, ctrl_en_val);
+ if (ret) {
+ dev_err(&led->priv->client->dev,
+ "Cannot enable the device\n");
+ goto brightness_out;
+ }
+
+ led->enabled = brt_val;
+ }
+ }
+
+brightness_out:
+ mutex_unlock(&led->priv->lock);
+ return ret;
+}
+
+static int lm3697_init(struct lm3697 *priv)
+{
+ struct lm3697_led *led;
+ int i, ret;
+
+ if (priv->enable_gpio) {
+ gpiod_direction_output(priv->enable_gpio, 1);
+ } else {
+ ret = regmap_write(priv->regmap, LM3697_RESET, LM3697_SW_RESET);
+ if (ret) {
+ dev_err(&priv->client->dev, "Cannot reset the device\n");
+ goto out;
+ }
+ }
+
+ ret = regmap_write(priv->regmap, LM3697_CTRL_ENABLE, 0x0);
+ if (ret) {
+ dev_err(&priv->client->dev, "Cannot write ctrl enable\n");
+ goto out;
+ }
+
+ ret = regmap_write(priv->regmap, LM3697_OUTPUT_CONFIG, priv->bank_cfg);
+ if (ret)
+ dev_err(&priv->client->dev, "Cannot write OUTPUT config\n");
+
+ for (i = 0; i < LM3697_MAX_CONTROL_BANKS; i++) {
+ led = &priv->leds[i];
+ ret = ti_lmu_common_set_ramp(&led->lmu_data);
+ if (ret)
+ dev_err(&priv->client->dev, "Setting the ramp rate failed\n");
+ }
+out:
+ return ret;
+}
+
+static int lm3697_probe_dt(struct lm3697 *priv)
+{
+ struct fwnode_handle *child = NULL;
+ struct lm3697_led *led;
+ const char *name;
+ int control_bank;
+ size_t i = 0;
+ int ret = -EINVAL;
+ int j;
+
+ priv->enable_gpio = devm_gpiod_get_optional(&priv->client->dev,
+ "enable", GPIOD_OUT_LOW);
+ if (IS_ERR(priv->enable_gpio)) {
+ ret = PTR_ERR(priv->enable_gpio);
+ dev_err(&priv->client->dev, "Failed to get enable gpio: %d\n",
+ ret);
+ return ret;
+ }
+
+ priv->regulator = devm_regulator_get(&priv->client->dev, "vled");
+ if (IS_ERR(priv->regulator))
+ priv->regulator = NULL;
+
+ device_for_each_child_node(priv->dev, child) {
+ ret = fwnode_property_read_u32(child, "reg", &control_bank);
+ if (ret) {
+ dev_err(&priv->client->dev, "reg property missing\n");
+ fwnode_handle_put(child);
+ goto child_out;
+ }
+
+ if (control_bank > LM3697_CONTROL_B) {
+ dev_err(&priv->client->dev, "reg property is invalid\n");
+ ret = -EINVAL;
+ fwnode_handle_put(child);
+ goto child_out;
+ }
+
+ led = &priv->leds[i];
+
+ ret = ti_lmu_common_get_brt_res(&priv->client->dev,
+ child, &led->lmu_data);
+ if (ret)
+ dev_warn(&priv->client->dev, "brightness resolution property missing\n");
+
+ led->control_bank = control_bank;
+ led->lmu_data.regmap = priv->regmap;
+ led->lmu_data.runtime_ramp_reg = LM3697_CTRL_A_RAMP +
+ control_bank;
+ led->lmu_data.msb_brightness_reg = LM3697_CTRL_A_BRT_MSB +
+ led->control_bank * 2;
+ led->lmu_data.lsb_brightness_reg = LM3697_CTRL_A_BRT_LSB +
+ led->control_bank * 2;
+
+ led->num_leds = fwnode_property_read_u32_array(child,
+ "led-sources",
+ NULL, 0);
+
+ if (led->num_leds > LM3697_MAX_LED_STRINGS) {
+ dev_err(&priv->client->dev, "To many LED strings defined\n");
+ continue;
+ }
+
+ ret = fwnode_property_read_u32_array(child, "led-sources",
+ led->hvled_strings,
+ led->num_leds);
+ if (ret) {
+ dev_err(&priv->client->dev, "led-sources property missing\n");
+ fwnode_handle_put(child);
+ goto child_out;
+ }
+
+ for (j = 0; j < led->num_leds; j++)
+ priv->bank_cfg |=
+ (led->control_bank << led->hvled_strings[j]);
+
+ ret = ti_lmu_common_get_ramp_params(&priv->client->dev,
+ child, &led->lmu_data);
+ if (ret)
+ dev_warn(&priv->client->dev, "runtime-ramp properties missing\n");
+
+ fwnode_property_read_string(child, "linux,default-trigger",
+ &led->led_dev.default_trigger);
+
+ ret = fwnode_property_read_string(child, "label", &name);
+ if (ret)
+ snprintf(led->label, sizeof(led->label),
+ "%s::", priv->client->name);
+ else
+ snprintf(led->label, sizeof(led->label),
+ "%s:%s", priv->client->name, name);
+
+ led->priv = priv;
+ led->led_dev.name = led->label;
+ led->led_dev.max_brightness = led->lmu_data.max_brightness;
+ led->led_dev.brightness_set_blocking = lm3697_brightness_set;
+
+ ret = devm_led_classdev_register(priv->dev, &led->led_dev);
+ if (ret) {
+ dev_err(&priv->client->dev, "led register err: %d\n",
+ ret);
+ fwnode_handle_put(child);
+ goto child_out;
+ }
+
+ i++;
+ }
+
+child_out:
+ return ret;
+}
+
+static int lm3697_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct lm3697 *led;
+ int count;
+ int ret;
+
+ count = device_get_child_node_count(&client->dev);
+ if (!count) {
+ dev_err(&client->dev, "LEDs are not defined in device tree!");
+ return -ENODEV;
+ }
+
+ led = devm_kzalloc(&client->dev, struct_size(led, leds, count),
+ GFP_KERNEL);
+ if (!led)
+ return -ENOMEM;
+
+ mutex_init(&led->lock);
+ i2c_set_clientdata(client, led);
+
+ led->client = client;
+ led->dev = &client->dev;
+ led->regmap = devm_regmap_init_i2c(client, &lm3697_regmap_config);
+ if (IS_ERR(led->regmap)) {
+ ret = PTR_ERR(led->regmap);
+ dev_err(&client->dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = lm3697_probe_dt(led);
+ if (ret)
+ return ret;
+
+ return lm3697_init(led);
+}
+
+static int lm3697_remove(struct i2c_client *client)
+{
+ struct lm3697 *led = i2c_get_clientdata(client);
+ int ret;
+
+ ret = regmap_update_bits(led->regmap, LM3697_CTRL_ENABLE,
+ LM3697_CTRL_A_B_EN, 0);
+ if (ret) {
+ dev_err(&led->client->dev, "Failed to disable the device\n");
+ return ret;
+ }
+
+ if (led->enable_gpio)
+ gpiod_direction_output(led->enable_gpio, 0);
+
+ if (led->regulator) {
+ ret = regulator_disable(led->regulator);
+ if (ret)
+ dev_err(&led->client->dev,
+ "Failed to disable regulator\n");
+ }
+
+ mutex_destroy(&led->lock);
+
+ return 0;
+}
+
+static const struct i2c_device_id lm3697_id[] = {
+ { "lm3697", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, lm3697_id);
+
+static const struct of_device_id of_lm3697_leds_match[] = {
+ { .compatible = "ti,lm3697", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, of_lm3697_leds_match);
+
+static struct i2c_driver lm3697_driver = {
+ .driver = {
+ .name = "lm3697",
+ .of_match_table = of_lm3697_leds_match,
+ },
+ .probe = lm3697_probe,
+ .remove = lm3697_remove,
+ .id_table = lm3697_id,
+};
+module_i2c_driver(lm3697_driver);
+
+MODULE_DESCRIPTION("Texas Instruments LM3697 LED driver");
+MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/leds-locomo.c b/drivers/leds/leds-locomo.c
index 24c4b53a6b93..42dc46e3f00f 100644
--- a/drivers/leds/leds-locomo.c
+++ b/drivers/leds/leds-locomo.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/leds/leds-locomo.c
*
* Copyright (C) 2005 John Lenz <lenz@cs.wisc.edu>
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/leds/leds-lp3944.c b/drivers/leds/leds-lp3944.c
index be60c181222a..838e6f19d37e 100644
--- a/drivers/leds/leds-lp3944.c
+++ b/drivers/leds/leds-lp3944.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* leds-lp3944.c - driver for National Semiconductor LP3944 Funlight Chip
*
* Copyright (C) 2009 Antonio Ospite <ospite@studenti.unina.it>
- *
- * 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.
- *
*/
/*
diff --git a/drivers/leds/leds-lp3952.c b/drivers/leds/leds-lp3952.c
index 847f7f282126..4e4e542774cb 100644
--- a/drivers/leds/leds-lp3952.c
+++ b/drivers/leds/leds-lp3952.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LED driver for TI lp3952 controller
*
* Copyright (C) 2016, DAQRI, LLC.
* Author: Tony Makkiel <tony.makkiel@daqri.com>
- *
- * 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.
- *
*/
#include <linux/delay.h>
diff --git a/drivers/leds/leds-lp5562.c b/drivers/leds/leds-lp5562.c
index 2a9009fe5545..37632fc63741 100644
--- a/drivers/leds/leds-lp5562.c
+++ b/drivers/leds/leds-lp5562.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LP5562 LED driver
*
* Copyright (C) 2013 Texas Instruments
*
* Author: Milo(Woogyom) Kim <milo.kim@ti.com>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/leds/leds-lp55xx-common.c b/drivers/leds/leds-lp55xx-common.c
index 723f2f17497a..44ced02b49f9 100644
--- a/drivers/leds/leds-lp55xx-common.c
+++ b/drivers/leds/leds-lp55xx-common.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LP5521/LP5523/LP55231/LP5562 Common Driver
*
@@ -5,10 +6,6 @@
*
* Author: Milo(Woogyom) Kim <milo.kim@ti.com>
*
- * 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.
- *
* Derived from leds-lp5521.c, leds-lp5523.c
*/
diff --git a/drivers/leds/leds-lp55xx-common.h b/drivers/leds/leds-lp55xx-common.h
index abf1fb5da37d..783ed5103ce5 100644
--- a/drivers/leds/leds-lp55xx-common.h
+++ b/drivers/leds/leds-lp55xx-common.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* LP55XX Common Driver Header
*
@@ -5,10 +6,6 @@
*
* Author: Milo(Woogyom) Kim <milo.kim@ti.com>
*
- * 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.
- *
* Derived from leds-lp5521.c, leds-lp5523.c
*/
diff --git a/drivers/leds/leds-lp8501.c b/drivers/leds/leds-lp8501.c
index 4c800b5989a9..2638dbf0e8ac 100644
--- a/drivers/leds/leds-lp8501.c
+++ b/drivers/leds/leds-lp8501.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TI LP8501 9 channel LED Driver
*
* Copyright (C) 2013 Texas Instruments
*
* Author: Milo(Woogyom) Kim <milo.kim@ti.com>
- *
- * 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.
- *
*/
#include <linux/delay.h>
diff --git a/drivers/leds/leds-lp8788.c b/drivers/leds/leds-lp8788.c
index 38c253a43700..9b9525ccca15 100644
--- a/drivers/leds/leds-lp8788.c
+++ b/drivers/leds/leds-lp8788.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TI LP8788 MFD - keyled driver
*
* Copyright 2012 Texas Instruments
*
* Author: Milo(Woogyom) Kim <milo.kim@ti.com>
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/leds/leds-lp8860.c b/drivers/leds/leds-lp8860.c
index 39c72a908f3b..ed680d0c15b0 100644
--- a/drivers/leds/leds-lp8860.c
+++ b/drivers/leds/leds-lp8860.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TI LP8860 4-Channel LED Driver
*
* Copyright (C) 2014 Texas Instruments
*
* Author: Dan Murphy <dmurphy@ti.com>
- *
- * 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.
- *
*/
#include <linux/i2c.h>
diff --git a/drivers/leds/leds-max77650.c b/drivers/leds/leds-max77650.c
index 6b74ce9cac12..8a8e5c65b157 100644
--- a/drivers/leds/leds-max77650.c
+++ b/drivers/leds/leds-max77650.c
@@ -64,7 +64,6 @@ static int max77650_led_probe(struct platform_device *pdev)
{
struct device_node *of_node, *child;
struct max77650_led *leds, *led;
- struct device *parent;
struct device *dev;
struct regmap *map;
const char *label;
@@ -72,7 +71,6 @@ static int max77650_led_probe(struct platform_device *pdev)
u32 reg;
dev = &pdev->dev;
- parent = dev->parent;
of_node = dev->of_node;
if (!of_node)
diff --git a/drivers/leds/leds-max77693.c b/drivers/leds/leds-max77693.c
index adf0f191f794..fec56090c2ba 100644
--- a/drivers/leds/leds-max77693.c
+++ b/drivers/leds/leds-max77693.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LED Flash class driver for the flash cell of max77693 mfd.
*
@@ -5,10 +6,6 @@
*
* Authors: Jacek Anaszewski <j.anaszewski@samsung.com>
* Andrzej Hajda <a.hajda@samsung.com>
- *
- * 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.
*/
#include <linux/led-class-flash.h>
diff --git a/drivers/leds/leds-max8997.c b/drivers/leds/leds-max8997.c
index 8c019c28f9f5..512a11d142d0 100644
--- a/drivers/leds/leds-max8997.c
+++ b/drivers/leds/leds-max8997.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* leds-max8997.c - LED class driver for MAX8997 LEDs.
*
* Copyright (C) 2011 Samsung Electronics
* Donggeun Kim <dg77.kim@samsung.com>
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/leds/leds-mc13783.c b/drivers/leds/leds-mc13783.c
index 47ad7de9553c..5cd810c545f3 100644
--- a/drivers/leds/leds-mc13783.c
+++ b/drivers/leds/leds-mc13783.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LEDs driver for Freescale MC13783/MC13892/MC34708
*
@@ -9,10 +10,6 @@
*
* Copyright (C) 2006-2008 Marvell International Ltd.
* Eric Miao <eric.miao@marvell.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/leds/leds-net48xx.c b/drivers/leds/leds-net48xx.c
index 0d214c2e403c..a93468c13772 100644
--- a/drivers/leds/leds-net48xx.c
+++ b/drivers/leds/leds-net48xx.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LEDs driver for Soekris net48xx
*
* Copyright (C) 2006 Chris Boot <bootc@bootc.net>
*
* Based on leds-ams-delta.c
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c
index c2bc8f569760..4037c504589c 100644
--- a/drivers/leds/leds-pca955x.c
+++ b/drivers/leds/leds-pca955x.c
@@ -429,7 +429,7 @@ static int pca955x_probe(struct i2c_client *client,
int ngpios = 0;
chip = &pca955x_chipdefs[id->driver_data];
- adapter = to_i2c_adapter(client->dev.parent);
+ adapter = client->adapter;
pdata = dev_get_platdata(&client->dev);
if (!pdata) {
pdata = pca955x_get_pdata(client, chip);
diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c
index af08bcdc4fd8..48d068f80f11 100644
--- a/drivers/leds/leds-pwm.c
+++ b/drivers/leds/leds-pwm.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/leds-pwm.c
*
@@ -6,10 +7,6 @@
* Copyright 2009 Luotao Fu @ Pengutronix (l.fu@pengutronix.de)
*
* based on leds-gpio.c by Raphael Assenat <raph@8d.com>
- *
- * 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.
*/
#include <linux/module.h>
@@ -75,7 +72,7 @@ static inline size_t sizeof_pwm_leds_priv(int num_leds)
}
static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
- struct led_pwm *led, struct device_node *child)
+ struct led_pwm *led, struct fwnode_handle *fwnode)
{
struct led_pwm_data *led_data = &priv->leds[priv->num_leds];
struct pwm_args pargs;
@@ -88,8 +85,8 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
led_data->cdev.max_brightness = led->max_brightness;
led_data->cdev.flags = LED_CORE_SUSPENDRESUME;
- if (child)
- led_data->pwm = devm_of_pwm_get(dev, child, NULL);
+ if (fwnode)
+ led_data->pwm = devm_fwnode_pwm_get(dev, fwnode, NULL);
else
led_data->pwm = devm_pwm_get(dev, led->name);
if (IS_ERR(led_data->pwm)) {
@@ -114,7 +111,8 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
if (!led_data->period && (led->pwm_period_ns > 0))
led_data->period = led->pwm_period_ns;
- ret = devm_of_led_classdev_register(dev, child, &led_data->cdev);
+ ret = devm_of_led_classdev_register(dev, to_of_node(fwnode),
+ &led_data->cdev);
if (ret == 0) {
priv->num_leds++;
led_pwm_set(&led_data->cdev, led_data->cdev.brightness);
@@ -126,27 +124,35 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
return ret;
}
-static int led_pwm_create_of(struct device *dev, struct led_pwm_priv *priv)
+static int led_pwm_create_fwnode(struct device *dev, struct led_pwm_priv *priv)
{
- struct device_node *child;
+ struct fwnode_handle *fwnode;
struct led_pwm led;
int ret = 0;
memset(&led, 0, sizeof(led));
- for_each_child_of_node(dev->of_node, child) {
- led.name = of_get_property(child, "label", NULL) ? :
- child->name;
+ device_for_each_child_node(dev, fwnode) {
+ ret = fwnode_property_read_string(fwnode, "label", &led.name);
+ if (ret && is_of_node(fwnode))
+ led.name = to_of_node(fwnode)->name;
+
+ if (!led.name) {
+ fwnode_handle_put(fwnode);
+ return -EINVAL;
+ }
+
+ fwnode_property_read_string(fwnode, "linux,default-trigger",
+ &led.default_trigger);
- led.default_trigger = of_get_property(child,
- "linux,default-trigger", NULL);
- led.active_low = of_property_read_bool(child, "active-low");
- of_property_read_u32(child, "max-brightness",
- &led.max_brightness);
+ led.active_low = fwnode_property_read_bool(fwnode,
+ "active-low");
+ fwnode_property_read_u32(fwnode, "max-brightness",
+ &led.max_brightness);
- ret = led_pwm_add(dev, priv, &led, child);
+ ret = led_pwm_add(dev, priv, &led, fwnode);
if (ret) {
- of_node_put(child);
+ fwnode_handle_put(fwnode);
break;
}
}
@@ -164,7 +170,7 @@ static int led_pwm_probe(struct platform_device *pdev)
if (pdata)
count = pdata->num_leds;
else
- count = of_get_child_count(pdev->dev.of_node);
+ count = device_get_child_node_count(&pdev->dev);
if (!count)
return -EINVAL;
@@ -182,7 +188,7 @@ static int led_pwm_probe(struct platform_device *pdev)
break;
}
} else {
- ret = led_pwm_create_of(&pdev->dev, priv);
+ ret = led_pwm_create_fwnode(&pdev->dev, priv);
}
if (ret)
diff --git a/drivers/leds/leds-regulator.c b/drivers/leds/leds-regulator.c
index acf77ca47558..208c98918433 100644
--- a/drivers/leds/leds-regulator.c
+++ b/drivers/leds/leds-regulator.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* leds-regulator.c - LED class driver for regulator driven LEDs.
*
* Copyright (C) 2009 Antonio Ospite <ospite@studenti.unina.it>
*
* Inspired by leds-wm8350 driver.
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/leds/leds-s3c24xx.c b/drivers/leds/leds-s3c24xx.c
index 404da451cb88..f8b8d6e313ee 100644
--- a/drivers/leds/leds-s3c24xx.c
+++ b/drivers/leds/leds-s3c24xx.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* drivers/leds/leds-s3c24xx.c
*
* (c) 2006 Simtec Electronics
@@ -5,10 +6,6 @@
* Ben Dooks <ben@simtec.co.uk>
*
* S3C24XX - LEDs GPIO driver
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/leds/leds-spi-byte.c b/drivers/leds/leds-spi-byte.c
new file mode 100644
index 000000000000..b231b563b7bb
--- /dev/null
+++ b/drivers/leds/leds-spi-byte.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2019 Christian Mauderer <oss@c-mauderer.de>
+
+/*
+ * The driver supports controllers with a very simple SPI protocol:
+ * - one LED is controlled by a single byte on MOSI
+ * - the value of the byte gives the brightness between two values (lowest to
+ * highest)
+ * - no return value is necessary (no MISO signal)
+ *
+ * The value for minimum and maximum brightness depends on the device
+ * (compatible string).
+ *
+ * Supported devices:
+ * - "ubnt,acb-spi-led": Microcontroller (SONiX 8F26E611LA) based device used
+ * for example in Ubiquiti airCube ISP. Reverse engineered protocol for this
+ * controller:
+ * * Higher two bits set a mode. Lower six bits are a parameter.
+ * * Mode: 00 -> set brightness between 0x00 (min) and 0x3F (max)
+ * * Mode: 01 -> pulsing pattern (min -> max -> min) with an interval. From
+ * some tests, the period is about (50ms + 102ms * parameter). There is a
+ * slightly different pattern starting from 0x10 (longer gap between the
+ * pulses) but the time still follows that calculation.
+ * * Mode: 10 -> same as 01 but with only a ramp from min to max. Again a
+ * slight jump in the pattern at 0x10.
+ * * Mode: 11 -> blinking (off -> 25% -> off -> 25% -> ...) with a period of
+ * (105ms * parameter)
+ * NOTE: This driver currently only supports mode 00.
+ */
+
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/spi/spi.h>
+#include <linux/mutex.h>
+#include <uapi/linux/uleds.h>
+
+struct spi_byte_chipdef {
+ /* SPI byte that will be send to switch the LED off */
+ u8 off_value;
+ /* SPI byte that will be send to switch the LED to maximum brightness */
+ u8 max_value;
+};
+
+struct spi_byte_led {
+ struct led_classdev ldev;
+ struct spi_device *spi;
+ char name[LED_MAX_NAME_SIZE];
+ struct mutex mutex;
+ const struct spi_byte_chipdef *cdef;
+};
+
+static const struct spi_byte_chipdef ubnt_acb_spi_led_cdef = {
+ .off_value = 0x0,
+ .max_value = 0x3F,
+};
+
+static const struct of_device_id spi_byte_dt_ids[] = {
+ { .compatible = "ubnt,acb-spi-led", .data = &ubnt_acb_spi_led_cdef },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, spi_byte_dt_ids);
+
+static int spi_byte_brightness_set_blocking(struct led_classdev *dev,
+ enum led_brightness brightness)
+{
+ struct spi_byte_led *led = container_of(dev, struct spi_byte_led, ldev);
+ u8 value;
+ int ret;
+
+ value = (u8) brightness + led->cdef->off_value;
+
+ mutex_lock(&led->mutex);
+ ret = spi_write(led->spi, &value, sizeof(value));
+ mutex_unlock(&led->mutex);
+
+ return ret;
+}
+
+static int spi_byte_probe(struct spi_device *spi)
+{
+ const struct of_device_id *of_dev_id;
+ struct device_node *child;
+ struct device *dev = &spi->dev;
+ struct spi_byte_led *led;
+ const char *name = "leds-spi-byte::";
+ const char *state;
+ int ret;
+
+ of_dev_id = of_match_device(spi_byte_dt_ids, dev);
+ if (!of_dev_id)
+ return -EINVAL;
+
+ if (of_get_child_count(dev->of_node) != 1) {
+ dev_err(dev, "Device must have exactly one LED sub-node.");
+ return -EINVAL;
+ }
+ child = of_get_next_child(dev->of_node, NULL);
+
+ led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
+ if (!led)
+ return -ENOMEM;
+
+ of_property_read_string(child, "label", &name);
+ strlcpy(led->name, name, sizeof(led->name));
+ led->spi = spi;
+ mutex_init(&led->mutex);
+ led->cdef = of_dev_id->data;
+ led->ldev.name = led->name;
+ led->ldev.brightness = LED_OFF;
+ led->ldev.max_brightness = led->cdef->max_value - led->cdef->off_value;
+ led->ldev.brightness_set_blocking = spi_byte_brightness_set_blocking;
+
+ state = of_get_property(child, "default-state", NULL);
+ if (state) {
+ if (!strcmp(state, "on")) {
+ led->ldev.brightness = led->ldev.max_brightness;
+ } else if (strcmp(state, "off")) {
+ /* all other cases except "off" */
+ dev_err(dev, "default-state can only be 'on' or 'off'");
+ return -EINVAL;
+ }
+ }
+ spi_byte_brightness_set_blocking(&led->ldev,
+ led->ldev.brightness);
+
+ ret = devm_led_classdev_register(&spi->dev, &led->ldev);
+ if (ret) {
+ mutex_destroy(&led->mutex);
+ return ret;
+ }
+ spi_set_drvdata(spi, led);
+
+ return 0;
+}
+
+static int spi_byte_remove(struct spi_device *spi)
+{
+ struct spi_byte_led *led = spi_get_drvdata(spi);
+
+ mutex_destroy(&led->mutex);
+
+ return 0;
+}
+
+static struct spi_driver spi_byte_driver = {
+ .probe = spi_byte_probe,
+ .remove = spi_byte_remove,
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .of_match_table = spi_byte_dt_ids,
+ },
+};
+
+module_spi_driver(spi_byte_driver);
+
+MODULE_AUTHOR("Christian Mauderer <oss@c-mauderer.de>");
+MODULE_DESCRIPTION("single byte SPI LED driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("spi:leds-spi-byte");
diff --git a/drivers/leds/leds-tca6507.c b/drivers/leds/leds-tca6507.c
index c59035e157d1..58be20cae183 100644
--- a/drivers/leds/leds-tca6507.c
+++ b/drivers/leds/leds-tca6507.c
@@ -758,7 +758,7 @@ static int tca6507_probe(struct i2c_client *client,
int err;
int i = 0;
- adapter = to_i2c_adapter(client->dev.parent);
+ adapter = client->adapter;
pdata = dev_get_platdata(&client->dev);
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
diff --git a/drivers/leds/leds-ti-lmu-common.c b/drivers/leds/leds-ti-lmu-common.c
new file mode 100644
index 000000000000..adc7293004f1
--- /dev/null
+++ b/drivers/leds/leds-ti-lmu-common.c
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright 2015 Texas Instruments
+// Copyright 2018 Sebastian Reichel
+// Copyright 2018 Pavel Machek <pavel@ucw.cz>
+// TI LMU LED common framework, based on previous work from
+// Milo Kim <milo.kim@ti.com>
+
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/of_device.h>
+
+#include <linux/leds-ti-lmu-common.h>
+
+const static int ramp_table[16] = {2048, 262000, 524000, 1049000, 2090000,
+ 4194000, 8389000, 16780000, 33550000, 41940000,
+ 50330000, 58720000, 67110000, 83880000,
+ 100660000, 117440000};
+
+static int ti_lmu_common_update_brightness(struct ti_lmu_bank *lmu_bank,
+ int brightness)
+{
+ struct regmap *regmap = lmu_bank->regmap;
+ u8 reg, val;
+ int ret;
+
+ /*
+ * Brightness register update
+ *
+ * 11 bit dimming: update LSB bits and write MSB byte.
+ * MSB brightness should be shifted.
+ * 8 bit dimming: write MSB byte.
+ */
+ if (lmu_bank->max_brightness == MAX_BRIGHTNESS_11BIT) {
+ reg = lmu_bank->lsb_brightness_reg;
+ ret = regmap_update_bits(regmap, reg,
+ LMU_11BIT_LSB_MASK,
+ brightness);
+ if (ret)
+ return ret;
+
+ val = brightness >> LMU_11BIT_MSB_SHIFT;
+ } else {
+ val = brightness;
+ }
+
+ reg = lmu_bank->msb_brightness_reg;
+
+ return regmap_write(regmap, reg, val);
+}
+
+int ti_lmu_common_set_brightness(struct ti_lmu_bank *lmu_bank, int brightness)
+{
+ return ti_lmu_common_update_brightness(lmu_bank, brightness);
+}
+EXPORT_SYMBOL(ti_lmu_common_set_brightness);
+
+static int ti_lmu_common_convert_ramp_to_index(unsigned int usec)
+{
+ int size = ARRAY_SIZE(ramp_table);
+ int i;
+
+ if (usec <= ramp_table[0])
+ return 0;
+
+ if (usec > ramp_table[size - 1])
+ return size - 1;
+
+ for (i = 1; i < size; i++) {
+ if (usec == ramp_table[i])
+ return i;
+
+ /* Find an approximate index by looking up the table */
+ if (usec > ramp_table[i - 1] && usec < ramp_table[i]) {
+ if (usec - ramp_table[i - 1] < ramp_table[i] - usec)
+ return i - 1;
+ else
+ return i;
+ }
+ }
+
+ return -EINVAL;
+}
+
+int ti_lmu_common_set_ramp(struct ti_lmu_bank *lmu_bank)
+{
+ struct regmap *regmap = lmu_bank->regmap;
+ u8 ramp, ramp_up, ramp_down;
+
+ if (lmu_bank->ramp_up_usec == 0 && lmu_bank->ramp_down_usec == 0) {
+ ramp_up = 0;
+ ramp_down = 0;
+ } else {
+ ramp_up = ti_lmu_common_convert_ramp_to_index(lmu_bank->ramp_up_usec);
+ ramp_down = ti_lmu_common_convert_ramp_to_index(lmu_bank->ramp_down_usec);
+ }
+
+ if (ramp_up < 0 || ramp_down < 0)
+ return -EINVAL;
+
+ ramp = (ramp_up << 4) | ramp_down;
+
+ return regmap_write(regmap, lmu_bank->runtime_ramp_reg, ramp);
+
+}
+EXPORT_SYMBOL(ti_lmu_common_set_ramp);
+
+int ti_lmu_common_get_ramp_params(struct device *dev,
+ struct fwnode_handle *child,
+ struct ti_lmu_bank *lmu_data)
+{
+ int ret;
+
+ ret = fwnode_property_read_u32(child, "ramp-up-us",
+ &lmu_data->ramp_up_usec);
+ if (ret)
+ dev_warn(dev, "ramp-up-us property missing\n");
+
+
+ ret = fwnode_property_read_u32(child, "ramp-down-us",
+ &lmu_data->ramp_down_usec);
+ if (ret)
+ dev_warn(dev, "ramp-down-us property missing\n");
+
+ return 0;
+}
+EXPORT_SYMBOL(ti_lmu_common_get_ramp_params);
+
+int ti_lmu_common_get_brt_res(struct device *dev, struct fwnode_handle *child,
+ struct ti_lmu_bank *lmu_data)
+{
+ int ret;
+
+ ret = device_property_read_u32(dev, "ti,brightness-resolution",
+ &lmu_data->max_brightness);
+ if (ret)
+ ret = fwnode_property_read_u32(child,
+ "ti,brightness-resolution",
+ &lmu_data->max_brightness);
+ if (lmu_data->max_brightness <= 0) {
+ lmu_data->max_brightness = MAX_BRIGHTNESS_8BIT;
+ return ret;
+ }
+
+ if (lmu_data->max_brightness > MAX_BRIGHTNESS_11BIT)
+ lmu_data->max_brightness = MAX_BRIGHTNESS_11BIT;
+
+
+ return 0;
+}
+EXPORT_SYMBOL(ti_lmu_common_get_brt_res);
+
+MODULE_DESCRIPTION("TI LMU common LED framework");
+MODULE_AUTHOR("Sebastian Reichel");
+MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("ti-lmu-led-common");
diff --git a/drivers/leds/leds-wm831x-status.c b/drivers/leds/leds-wm831x-status.c
index c5798b92e4d3..082df7f1dd90 100644
--- a/drivers/leds/leds-wm831x-status.c
+++ b/drivers/leds/leds-wm831x-status.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LED driver for WM831x status LEDs
*
* Copyright(C) 2009 Wolfson Microelectronics PLC.
- *
- * 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.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/leds/leds-wm8350.c b/drivers/leds/leds-wm8350.c
index e1e4e9d0b8b1..8f243c413723 100644
--- a/drivers/leds/leds-wm8350.c
+++ b/drivers/leds/leds-wm8350.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LED driver for WM8350 driven LEDS.
*
* Copyright(C) 2007, 2008 Wolfson Microelectronics PLC.
- *
- * 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.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/leds/leds-wrap.c b/drivers/leds/leds-wrap.c
index 473fb6b97ed4..794697e16068 100644
--- a/drivers/leds/leds-wrap.c
+++ b/drivers/leds/leds-wrap.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LEDs driver for PCEngines WRAP
*
* Copyright (C) 2006 Kristian Kielhofner <kris@krisk.org>
*
* Based on leds-net48xx.c
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h
index 7d38e6b9a740..47b229469069 100644
--- a/drivers/leds/leds.h
+++ b/drivers/leds/leds.h
@@ -1,14 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* LED Core
*
* Copyright 2005 Openedhand Ltd.
*
* Author: Richard Purdie <rpurdie@openedhand.com>
- *
- * 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.
- *
*/
#ifndef __LEDS_H_INCLUDED
#define __LEDS_H_INCLUDED
diff --git a/drivers/leds/trigger/Kconfig b/drivers/leds/trigger/Kconfig
index 7fa9d174a40c..ce9429ca6dde 100644
--- a/drivers/leds/trigger/Kconfig
+++ b/drivers/leds/trigger/Kconfig
@@ -15,7 +15,7 @@ config LEDS_TRIGGER_TIMER
This allows LEDs to be controlled by a programmable timer
via sysfs. Some LED hardware can be programmed to start
blinking the LED without any further software interaction.
- For more details read Documentation/leds/leds-class.txt.
+ For more details read Documentation/leds/leds-class.rst.
If unsure, say Y.
diff --git a/drivers/leds/trigger/ledtrig-activity.c b/drivers/leds/trigger/ledtrig-activity.c
index bcbf41c90c30..6a72b7e13719 100644
--- a/drivers/leds/trigger/ledtrig-activity.c
+++ b/drivers/leds/trigger/ledtrig-activity.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Activity LED trigger
*
* Copyright (C) 2017 Willy Tarreau <w@1wt.eu>
* Partially based on Atsushi Nemoto's ledtrig-heartbeat.c.
- *
- * 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.
*/
#include <linux/init.h>
@@ -73,7 +70,7 @@ static void led_activity_function(struct timer_list *t)
* down to 16us, ensuring we won't overflow 32-bit computations below
* even up to 3k CPUs, while keeping divides cheap on smaller systems.
*/
- curr_boot = ktime_get_boot_ns() * cpus;
+ curr_boot = ktime_get_boottime_ns() * cpus;
diff_boot = (curr_boot - activity_data->last_boot) >> 16;
diff_used = (curr_used - activity_data->last_used) >> 16;
activity_data->last_boot = curr_boot;
diff --git a/drivers/leds/trigger/ledtrig-backlight.c b/drivers/leds/trigger/ledtrig-backlight.c
index c2b57beef718..487577d22cfc 100644
--- a/drivers/leds/trigger/ledtrig-backlight.c
+++ b/drivers/leds/trigger/ledtrig-backlight.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Backlight emulation LED trigger
*
* Copyright 2008 (C) Rodolfo Giometti <giometti@linux.it>
* Copyright 2008 (C) Eurotech S.p.A. <info@eurotech.it>
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/leds/trigger/ledtrig-camera.c b/drivers/leds/trigger/ledtrig-camera.c
index 091a09a20c58..ab1c410872ff 100644
--- a/drivers/leds/trigger/ledtrig-camera.c
+++ b/drivers/leds/trigger/ledtrig-camera.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Camera Flash and Torch On/Off Trigger
*
@@ -6,10 +7,6 @@
* Copyright 2013 Texas Instruments
*
* Author: Milo(Woogyom) Kim <milo.kim@ti.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/leds/trigger/ledtrig-cpu.c b/drivers/leds/trigger/ledtrig-cpu.c
index 66a626091936..869976d1b734 100644
--- a/drivers/leds/trigger/ledtrig-cpu.c
+++ b/drivers/leds/trigger/ledtrig-cpu.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ledtrig-cpu.c - LED trigger based on CPU activity
*
@@ -12,11 +13,6 @@
*
* Copyright 2011 Linus Walleij <linus.walleij@linaro.org>
* Copyright 2011 - 2012 Bryan Wu <bryan.wu@canonical.com>
- *
- * 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.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/leds/trigger/ledtrig-default-on.c b/drivers/leds/trigger/ledtrig-default-on.c
index 7f6d9219711e..8207f85eceb1 100644
--- a/drivers/leds/trigger/ledtrig-default-on.c
+++ b/drivers/leds/trigger/ledtrig-default-on.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LED Kernel Default ON Trigger
*
* Copyright 2008 Nick Forbes <nick.forbes@incepta.com>
*
* Based on Richard Purdie's ledtrig-timer.c.
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/leds/trigger/ledtrig-disk.c b/drivers/leds/trigger/ledtrig-disk.c
index 9816b0d60270..0741910785bb 100644
--- a/drivers/leds/trigger/ledtrig-disk.c
+++ b/drivers/leds/trigger/ledtrig-disk.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LED Disk Activity Trigger
*
* Copyright 2006 Openedhand Ltd.
*
* Author: Richard Purdie <rpurdie@openedhand.com>
- *
- * 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.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/leds/trigger/ledtrig-gpio.c b/drivers/leds/trigger/ledtrig-gpio.c
index ed0db8ed825f..33cc99a1a16a 100644
--- a/drivers/leds/trigger/ledtrig-gpio.c
+++ b/drivers/leds/trigger/ledtrig-gpio.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ledtrig-gio.c - LED Trigger Based on GPIO events
*
* Copyright 2009 Felipe Balbi <me@felipebalbi.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/leds/trigger/ledtrig-heartbeat.c b/drivers/leds/trigger/ledtrig-heartbeat.c
index 7a2b12e19329..36b6709afe9f 100644
--- a/drivers/leds/trigger/ledtrig-heartbeat.c
+++ b/drivers/leds/trigger/ledtrig-heartbeat.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LED Heartbeat Trigger
*
@@ -5,10 +6,6 @@
*
* Based on Richard Purdie's ledtrig-timer.c and some arch's
* CONFIG_HEARTBEAT code.
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/leds/trigger/ledtrig-mtd.c b/drivers/leds/trigger/ledtrig-mtd.c
index 99b5b0a4d826..8fa763c2269b 100644
--- a/drivers/leds/trigger/ledtrig-mtd.c
+++ b/drivers/leds/trigger/ledtrig-mtd.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LED MTD trigger
*
@@ -8,11 +9,6 @@
* Copyright 2006 Openedhand Ltd.
*
* Author: Richard Purdie <rpurdie@openedhand.com>
- *
- * 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.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/leds/trigger/ledtrig-oneshot.c b/drivers/leds/trigger/ledtrig-oneshot.c
index 8808f0ad7339..bee3bd452abf 100644
--- a/drivers/leds/trigger/ledtrig-oneshot.c
+++ b/drivers/leds/trigger/ledtrig-oneshot.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* One-shot LED Trigger
*
* Copyright 2012, Fabio Baltieri <fabio.baltieri@gmail.com>
*
* Based on ledtrig-timer.c by Richard Purdie <rpurdie@openedhand.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/leds/trigger/ledtrig-panic.c b/drivers/leds/trigger/ledtrig-panic.c
index d735526b9db4..5751cd032f9d 100644
--- a/drivers/leds/trigger/ledtrig-panic.c
+++ b/drivers/leds/trigger/ledtrig-panic.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Kernel Panic LED Trigger
*
* Copyright 2016 Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
- *
- * 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.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/leds/trigger/ledtrig-timer.c b/drivers/leds/trigger/ledtrig-timer.c
index 427fc3c303d5..34a68604c46c 100644
--- a/drivers/leds/trigger/ledtrig-timer.c
+++ b/drivers/leds/trigger/ledtrig-timer.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LED Kernel Timer Trigger
*
* Copyright 2005-2006 Openedhand Ltd.
*
* Author: Richard Purdie <rpurdie@openedhand.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/leds/trigger/ledtrig-transient.c b/drivers/leds/trigger/ledtrig-transient.c
index a80bb82aacc2..80635183fac8 100644
--- a/drivers/leds/trigger/ledtrig-transient.c
+++ b/drivers/leds/trigger/ledtrig-transient.c
@@ -3,7 +3,7 @@
// LED Kernel Transient Trigger
//
// Transient trigger allows one shot timer activation. Please refer to
-// Documentation/leds/ledtrig-transient.txt for details
+// Documentation/leds/ledtrig-transient.rst for details
// Copyright (C) 2012 Shuah Khan <shuahkhan@gmail.com>
//
// Based on Richard Purdie's ledtrig-timer.c and Atsushi Nemoto's
diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
index 7d555b110ecd..a600934fdd9c 100644
--- a/drivers/lightnvm/core.c
+++ b/drivers/lightnvm/core.c
@@ -478,7 +478,7 @@ static void __nvm_remove_target(struct nvm_target *t, bool graceful)
*/
static int nvm_remove_tgt(struct nvm_ioctl_remove *remove)
{
- struct nvm_target *t;
+ struct nvm_target *t = NULL;
struct nvm_dev *dev;
down_read(&nvm_lock);
diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c
index 773537804319..f546e6f28b8a 100644
--- a/drivers/lightnvm/pblk-core.c
+++ b/drivers/lightnvm/pblk-core.c
@@ -323,14 +323,16 @@ void pblk_free_rqd(struct pblk *pblk, struct nvm_rq *rqd, int type)
void pblk_bio_free_pages(struct pblk *pblk, struct bio *bio, int off,
int nr_pages)
{
- struct bio_vec bv;
- int i;
-
- WARN_ON(off + nr_pages != bio->bi_vcnt);
-
- for (i = off; i < nr_pages + off; i++) {
- bv = bio->bi_io_vec[i];
- mempool_free(bv.bv_page, &pblk->page_bio_pool);
+ struct bio_vec *bv;
+ struct page *page;
+ int i, e, nbv = 0;
+
+ for (i = 0; i < bio->bi_vcnt; i++) {
+ bv = &bio->bi_io_vec[i];
+ page = bv->bv_page;
+ for (e = 0; e < bv->bv_len; e += PBLK_EXPOSED_PAGE_SIZE, nbv++)
+ if (nbv >= off)
+ mempool_free(page++, &pblk->page_bio_pool);
}
}
diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c
index 3940e2a032f7..4134e580f786 100644
--- a/drivers/macintosh/rack-meter.c
+++ b/drivers/macintosh/rack-meter.c
@@ -1,18 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* RackMac vu-meter driver
*
* (c) Copyright 2006 Benjamin Herrenschmidt, IBM Corp.
* <benh@kernel.crashing.org>
*
- * Released under the term of the GNU GPL v2.
- *
* Support the CPU-meter LEDs of the Xserve G5
*
* TODO: Implement PWM to do variable intensity and provide userland
* interface for fun. Also, the CPU-meter could be made nicer by being
* a bit less "immediate" but giving instead a more average load over
* time. Patches welcome :-)
- *
*/
#undef DEBUG
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
index 6a844125cf2d..276065c888bc 100644
--- a/drivers/macintosh/smu.c
+++ b/drivers/macintosh/smu.c
@@ -1,10 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* PowerMac G5 SMU driver
*
* Copyright 2004 J. Mayer <l_indien@magic.fr>
* Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
- *
- * Released under the term of the GNU GPL v2.
*/
/*
@@ -133,7 +132,7 @@ static void smu_start_cmd(void)
/* Flush command and data to RAM */
faddr = (unsigned long)smu->cmd_buf;
fend = faddr + smu->cmd_buf->length + 2;
- flush_inval_dcache_range(faddr, fend);
+ flush_dcache_range(faddr, fend);
/* We also disable NAP mode for the duration of the command
@@ -195,7 +194,7 @@ static irqreturn_t smu_db_intr(int irq, void *arg)
* reply length (it's only 2 cache lines anyway)
*/
faddr = (unsigned long)smu->cmd_buf;
- flush_inval_dcache_range(faddr, faddr + 256);
+ flush_dcache_range(faddr, faddr + 256);
/* Now check ack */
ack = (~cmd->cmd) & 0xff;
diff --git a/drivers/macintosh/windfarm.h b/drivers/macintosh/windfarm.h
index 901c42f71b5a..5eb480d84e9a 100644
--- a/drivers/macintosh/windfarm.h
+++ b/drivers/macintosh/windfarm.h
@@ -1,10 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Windfarm PowerMac thermal control.
*
* (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
* <benh@kernel.crashing.org>
- *
- * Released under the term of the GNU GPL v2.
*/
#ifndef __WINDFARM_H__
diff --git a/drivers/macintosh/windfarm_ad7417_sensor.c b/drivers/macintosh/windfarm_ad7417_sensor.c
index 7c28b71246c9..125605987b44 100644
--- a/drivers/macintosh/windfarm_ad7417_sensor.c
+++ b/drivers/macintosh/windfarm_ad7417_sensor.c
@@ -1,9 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Windfarm PowerMac thermal control. AD7417 sensors
*
* Copyright 2012 Benjamin Herrenschmidt, IBM Corp.
- *
- * Released under the term of the GNU GPL v2.
*/
#include <linux/types.h>
diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c
index 5e013d781a74..77612303841e 100644
--- a/drivers/macintosh/windfarm_core.c
+++ b/drivers/macintosh/windfarm_core.c
@@ -1,11 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Windfarm PowerMac thermal control. Core
*
* (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
* <benh@kernel.crashing.org>
*
- * Released under the term of the GNU GPL v2.
- *
* This core code tracks the list of sensors & controls, register
* clients, and holds the kernel thread used for control.
*
diff --git a/drivers/macintosh/windfarm_fcu_controls.c b/drivers/macintosh/windfarm_fcu_controls.c
index 629f19875d7f..3c971297b6dc 100644
--- a/drivers/macintosh/windfarm_fcu_controls.c
+++ b/drivers/macintosh/windfarm_fcu_controls.c
@@ -1,9 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Windfarm PowerMac thermal control. FCU fan control
*
* Copyright 2012 Benjamin Herrenschmidt, IBM Corp.
- *
- * Released under the term of the GNU GPL v2.
*/
#undef DEBUG
diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c
index 6cdfe714901d..282c28a17ea1 100644
--- a/drivers/macintosh/windfarm_lm75_sensor.c
+++ b/drivers/macintosh/windfarm_lm75_sensor.c
@@ -1,10 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Windfarm PowerMac thermal control. LM75 sensor
*
* (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
* <benh@kernel.crashing.org>
- *
- * Released under the term of the GNU GPL v2.
*/
#include <linux/types.h>
diff --git a/drivers/macintosh/windfarm_lm87_sensor.c b/drivers/macintosh/windfarm_lm87_sensor.c
index 09724acd70b6..e44525b19071 100644
--- a/drivers/macintosh/windfarm_lm87_sensor.c
+++ b/drivers/macintosh/windfarm_lm87_sensor.c
@@ -1,10 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Windfarm PowerMac thermal control. LM87 sensor
*
* Copyright 2012 Benjamin Herrenschmidt, IBM Corp.
- *
- * Released under the term of the GNU GPL v2.
- *
*/
#include <linux/types.h>
diff --git a/drivers/macintosh/windfarm_max6690_sensor.c b/drivers/macintosh/windfarm_max6690_sensor.c
index 6ad035e13c08..e666cc020683 100644
--- a/drivers/macintosh/windfarm_max6690_sensor.c
+++ b/drivers/macintosh/windfarm_max6690_sensor.c
@@ -1,9 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Windfarm PowerMac thermal control. MAX6690 sensor.
*
* Copyright (C) 2005 Paul Mackerras, IBM Corp. <paulus@samba.org>
- *
- * Use and redistribute under the terms of the GNU GPL v2.
*/
#include <linux/types.h>
#include <linux/errno.h>
diff --git a/drivers/macintosh/windfarm_mpu.h b/drivers/macintosh/windfarm_mpu.h
index 046edc8c2ec5..157ce6e3f32e 100644
--- a/drivers/macintosh/windfarm_mpu.h
+++ b/drivers/macintosh/windfarm_mpu.h
@@ -1,9 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Windfarm PowerMac thermal control
*
* Copyright 2012 Benjamin Herrenschmidt, IBM Corp.
- *
- * Released under the term of the GNU GPL v2.
*/
#ifndef __WINDFARM_MPU_H
diff --git a/drivers/macintosh/windfarm_pid.c b/drivers/macintosh/windfarm_pid.c
index f10efb28cae4..bb31b0e93fad 100644
--- a/drivers/macintosh/windfarm_pid.c
+++ b/drivers/macintosh/windfarm_pid.c
@@ -1,10 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Windfarm PowerMac thermal control. Generic PID helpers
*
* (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
* <benh@kernel.crashing.org>
- *
- * Released under the term of the GNU GPL v2.
*/
#include <linux/types.h>
diff --git a/drivers/macintosh/windfarm_pid.h b/drivers/macintosh/windfarm_pid.h
index bbccc22d42b8..83f747dbeafc 100644
--- a/drivers/macintosh/windfarm_pid.h
+++ b/drivers/macintosh/windfarm_pid.h
@@ -1,11 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Windfarm PowerMac thermal control. Generic PID helpers
*
* (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
* <benh@kernel.crashing.org>
*
- * Released under the term of the GNU GPL v2.
- *
* This is a pair of generic PID helpers that can be used by
* control loops. One is the basic PID implementation, the
* other one is more specifically tailored to the loops used
diff --git a/drivers/macintosh/windfarm_pm112.c b/drivers/macintosh/windfarm_pm112.c
index fec91db1142e..4150301a89a5 100644
--- a/drivers/macintosh/windfarm_pm112.c
+++ b/drivers/macintosh/windfarm_pm112.c
@@ -1,11 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Windfarm PowerMac thermal control.
* Control loops for machines with SMU and PPC970MP processors.
*
* Copyright (C) 2005 Paul Mackerras, IBM Corp. <paulus@samba.org>
* Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
- *
- * Use and redistribute under the terms of the GNU GPL v2.
*/
#include <linux/types.h>
#include <linux/errno.h>
diff --git a/drivers/macintosh/windfarm_pm121.c b/drivers/macintosh/windfarm_pm121.c
index 97634e030991..ab467b9c31be 100644
--- a/drivers/macintosh/windfarm_pm121.c
+++ b/drivers/macintosh/windfarm_pm121.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Windfarm PowerMac thermal control. iMac G5 iSight
*
@@ -6,14 +7,9 @@
* Bits & pieces from windfarm_pm81.c by (c) Copyright 2005 Benjamin
* Herrenschmidt, IBM Corp. <benh@kernel.crashing.org>
*
- * Released under the term of the GNU GPL v2.
- *
- *
- *
* PowerMac12,1
* ============
*
- *
* The algorithm used is the PID control algorithm, used the same way
* the published Darwin code does, using the same values that are
* present in the Darwin 8.10 snapshot property lists (note however
@@ -25,7 +21,6 @@
* controls with a tiny difference. The control-ids of hard-drive-fan
* and cpu-fan is swapped.
*
- *
* Target Correction :
*
* controls have a target correction calculated as :
@@ -63,7 +58,6 @@
* offset : -15650652
* slope : 1565065
*
- *
* Target rubber-banding :
*
* Some controls have a target correction which depends on another
@@ -76,7 +70,6 @@
*
* new_target = max (new_target, new_min >> 16)
*
- *
* # model_id : 2
* control : cpu-fan
* ref : optical-drive-fan
@@ -89,12 +82,10 @@
* offset : -32768000
* slope : 65536
*
- *
* In order to have the moste efficient correction with those
* dependencies, we must trigger HD loop before OD loop before CPU
* loop.
*
- *
* The various control loops found in Darwin config file are:
*
* HD Fan control loop.
@@ -191,12 +182,10 @@
* sensors : cpu-temp, cpu-power
* PID params : from SDB partition
*
- *
* CPU Slew control loop.
*
* control : cpufreq-clamp
* sensor : cpu-temp
- *
*/
#undef DEBUG
diff --git a/drivers/macintosh/windfarm_pm72.c b/drivers/macintosh/windfarm_pm72.c
index 833021508c05..c5da0fc24884 100644
--- a/drivers/macintosh/windfarm_pm72.c
+++ b/drivers/macintosh/windfarm_pm72.c
@@ -1,10 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Windfarm PowerMac thermal control.
* Control loops for PowerMac7,2 and 7,3
*
* Copyright (C) 2012 Benjamin Herrenschmidt, IBM Corp.
- *
- * Use and redistribute under the terms of the GNU GPL v2.
*/
#include <linux/types.h>
#include <linux/errno.h>
diff --git a/drivers/macintosh/windfarm_pm81.c b/drivers/macintosh/windfarm_pm81.c
index 346c91744442..82c67a4ee5f7 100644
--- a/drivers/macintosh/windfarm_pm81.c
+++ b/drivers/macintosh/windfarm_pm81.c
@@ -1,11 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Windfarm PowerMac thermal control. iMac G5
*
* (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
* <benh@kernel.crashing.org>
*
- * Released under the term of the GNU GPL v2.
- *
* The algorithm used is the PID control algorithm, used the same
* way the published Darwin code does, using the same values that
* are present in the Darwin 8.2 snapshot property lists (note however
@@ -90,7 +89,6 @@
* from the SDB partition. If we ever end up with actually slewing the system
* clock and thus changing operating points, we'll have to find a way to
* communicate with the CPU freq driver;
- *
*/
#include <linux/types.h>
diff --git a/drivers/macintosh/windfarm_pm91.c b/drivers/macintosh/windfarm_pm91.c
index a8a47c62a74b..3f346af9e3f7 100644
--- a/drivers/macintosh/windfarm_pm91.c
+++ b/drivers/macintosh/windfarm_pm91.c
@@ -1,11 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Windfarm PowerMac thermal control. SMU based 1 CPU desktop control loops
*
* (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
* <benh@kernel.crashing.org>
*
- * Released under the term of the GNU GPL v2.
- *
* The algorithm used is the PID control algorithm, used the same
* way the published Darwin code does, using the same values that
* are present in the Darwin 8.2 snapshot property lists (note however
diff --git a/drivers/macintosh/windfarm_rm31.c b/drivers/macintosh/windfarm_rm31.c
index 9ce87cc0597f..8456eb67184b 100644
--- a/drivers/macintosh/windfarm_rm31.c
+++ b/drivers/macintosh/windfarm_rm31.c
@@ -1,10 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Windfarm PowerMac thermal control.
* Control loops for RackMack3,1 (Xserve G5)
*
* Copyright (C) 2012 Benjamin Herrenschmidt, IBM Corp.
- *
- * Use and redistribute under the terms of the GNU GPL v2.
*/
#include <linux/types.h>
#include <linux/errno.h>
diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c
index 2cb9652a9998..79cb1ad09bfd 100644
--- a/drivers/macintosh/windfarm_smu_controls.c
+++ b/drivers/macintosh/windfarm_smu_controls.c
@@ -1,10 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Windfarm PowerMac thermal control. SMU based controls
*
* (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
* <benh@kernel.crashing.org>
- *
- * Released under the term of the GNU GPL v2.
*/
#include <linux/types.h>
diff --git a/drivers/macintosh/windfarm_smu_sensors.c b/drivers/macintosh/windfarm_smu_sensors.c
index a58f6733381a..3e6059eaa138 100644
--- a/drivers/macintosh/windfarm_smu_sensors.c
+++ b/drivers/macintosh/windfarm_smu_sensors.c
@@ -1,10 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Windfarm PowerMac thermal control. SMU based sensors
*
* (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
* <benh@kernel.crashing.org>
- *
- * Released under the term of the GNU GPL v2.
*/
#include <linux/types.h>
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index b709481a8de6..ab4eb750bbdd 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -54,7 +54,7 @@ config ARMADA_37XX_RWTM_MBOX
config OMAP2PLUS_MBOX
tristate "OMAP2+ Mailbox framework support"
- depends on ARCH_OMAP2PLUS
+ depends on ARCH_OMAP2PLUS || ARCH_K3
help
Mailbox implementation for OMAP family chips with hardware for
interprocessor communication involving DSP, IVA1.0 and IVA2 in
diff --git a/drivers/mailbox/arm_mhu.c b/drivers/mailbox/arm_mhu.c
index b47851856086..9da236552bd7 100644
--- a/drivers/mailbox/arm_mhu.c
+++ b/drivers/mailbox/arm_mhu.c
@@ -5,16 +5,13 @@
* Author: Jassi Brar <jaswinder.singh@linaro.org>
*/
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
+#include <linux/amba/bus.h>
+#include <linux/device.h>
#include <linux/err.h>
+#include <linux/interrupt.h>
#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/amba/bus.h>
#include <linux/mailbox_controller.h>
+#include <linux/module.h>
#define INTR_STAT_OFS 0x0
#define INTR_SET_OFS 0x8
diff --git a/drivers/mailbox/bcm-flexrm-mailbox.c b/drivers/mailbox/bcm-flexrm-mailbox.c
index a64116586b4c..8ee9db274802 100644
--- a/drivers/mailbox/bcm-flexrm-mailbox.c
+++ b/drivers/mailbox/bcm-flexrm-mailbox.c
@@ -296,8 +296,6 @@ struct flexrm_mbox {
struct dma_pool *bd_pool;
struct dma_pool *cmpl_pool;
struct dentry *root;
- struct dentry *config;
- struct dentry *stats;
struct mbox_controller controller;
};
@@ -1165,8 +1163,7 @@ static int flexrm_process_completions(struct flexrm_ring *ring)
static int flexrm_debugfs_conf_show(struct seq_file *file, void *offset)
{
- struct platform_device *pdev = to_platform_device(file->private);
- struct flexrm_mbox *mbox = platform_get_drvdata(pdev);
+ struct flexrm_mbox *mbox = dev_get_drvdata(file->private);
/* Write config in file */
flexrm_write_config_in_seqfile(mbox, file);
@@ -1176,8 +1173,7 @@ static int flexrm_debugfs_conf_show(struct seq_file *file, void *offset)
static int flexrm_debugfs_stats_show(struct seq_file *file, void *offset)
{
- struct platform_device *pdev = to_platform_device(file->private);
- struct flexrm_mbox *mbox = platform_get_drvdata(pdev);
+ struct flexrm_mbox *mbox = dev_get_drvdata(file->private);
/* Write stats in file */
flexrm_write_stats_in_seqfile(mbox, file);
@@ -1603,7 +1599,6 @@ static int flexrm_mbox_probe(struct platform_device *pdev)
1 << RING_CMPL_ALIGN_ORDER, 0);
if (!mbox->cmpl_pool) {
ret = -ENOMEM;
- goto fail_destroy_bd_pool;
}
/* Allocate platform MSIs for each ring */
@@ -1624,28 +1619,15 @@ static int flexrm_mbox_probe(struct platform_device *pdev)
/* Create debugfs root entry */
mbox->root = debugfs_create_dir(dev_name(mbox->dev), NULL);
- if (IS_ERR_OR_NULL(mbox->root)) {
- ret = PTR_ERR_OR_ZERO(mbox->root);
- goto fail_free_msis;
- }
/* Create debugfs config entry */
- mbox->config = debugfs_create_devm_seqfile(mbox->dev,
- "config", mbox->root,
- flexrm_debugfs_conf_show);
- if (IS_ERR_OR_NULL(mbox->config)) {
- ret = PTR_ERR_OR_ZERO(mbox->config);
- goto fail_free_debugfs_root;
- }
+ debugfs_create_devm_seqfile(mbox->dev, "config", mbox->root,
+ flexrm_debugfs_conf_show);
/* Create debugfs stats entry */
- mbox->stats = debugfs_create_devm_seqfile(mbox->dev,
- "stats", mbox->root,
- flexrm_debugfs_stats_show);
- if (IS_ERR_OR_NULL(mbox->stats)) {
- ret = PTR_ERR_OR_ZERO(mbox->stats);
- goto fail_free_debugfs_root;
- }
+ debugfs_create_devm_seqfile(mbox->dev, "stats", mbox->root,
+ flexrm_debugfs_stats_show);
+
skip_debugfs:
/* Initialize mailbox controller */
@@ -1676,11 +1658,9 @@ skip_debugfs:
fail_free_debugfs_root:
debugfs_remove_recursive(mbox->root);
-fail_free_msis:
platform_msi_domain_free_irqs(dev);
fail_destroy_cmpl_pool:
dma_pool_destroy(mbox->cmpl_pool);
-fail_destroy_bd_pool:
dma_pool_destroy(mbox->bd_pool);
fail:
return ret;
diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c
index ccf3d62af7e7..fcb3b18a0678 100644
--- a/drivers/mailbox/bcm-pdc-mailbox.c
+++ b/drivers/mailbox/bcm-pdc-mailbox.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2016 Broadcom
- *
- * 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 (the "GPL").
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License version 2 (GPLv2) for more details.
- *
- * You should have received a copy of the GNU General Public License
- * version 2 (GPLv2) along with this source code.
*/
/*
@@ -406,8 +395,6 @@ struct pdc_state {
*/
struct scatterlist *src_sg[PDC_RING_ENTRIES];
- struct dentry *debugfs_stats; /* debug FS stats file for this PDC */
-
/* counters */
u32 pdc_requests; /* number of request messages submitted */
u32 pdc_replies; /* number of reply messages received */
@@ -512,9 +499,8 @@ static void pdc_setup_debugfs(struct pdc_state *pdcs)
debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
/* S_IRUSR == 0400 */
- pdcs->debugfs_stats = debugfs_create_file(spu_stats_name, 0400,
- debugfs_dir, pdcs,
- &pdc_debugfs_stats);
+ debugfs_create_file(spu_stats_name, 0400, debugfs_dir, pdcs,
+ &pdc_debugfs_stats);
}
static void pdc_free_debugfs(void)
@@ -1614,7 +1600,6 @@ static int pdc_probe(struct platform_device *pdev)
if (err)
goto cleanup_buf_pool;
- pdcs->debugfs_stats = NULL;
pdc_setup_debugfs(pdcs);
dev_dbg(dev, "pdc_probe() successful");
diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c
index 25be8bb5e371..9f74dee1a58c 100644
--- a/drivers/mailbox/imx-mailbox.c
+++ b/drivers/mailbox/imx-mailbox.c
@@ -217,8 +217,8 @@ static void imx_mu_shutdown(struct mbox_chan *chan)
if (cp->type == IMX_MU_TYPE_TXDB)
tasklet_kill(&cp->txdb_tasklet);
- imx_mu_xcr_rmw(priv, 0,
- IMX_MU_xCR_TIEn(cp->idx) | IMX_MU_xCR_RIEn(cp->idx));
+ imx_mu_xcr_rmw(priv, 0, IMX_MU_xCR_TIEn(cp->idx) |
+ IMX_MU_xCR_RIEn(cp->idx) | IMX_MU_xCR_GIEn(cp->idx));
free_irq(priv->irq, chan);
}
diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
index 38d9df3fb199..0b821a5b2db8 100644
--- a/drivers/mailbox/mailbox.c
+++ b/drivers/mailbox/mailbox.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Mailbox: Common code for Mailbox controllers and users
*
* Copyright (C) 2013-2014 Linaro Ltd.
* Author: Jassi Brar <jassisinghbrar@gmail.com>
- *
- * 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.
*/
#include <linux/interrupt.h>
@@ -421,11 +418,13 @@ struct mbox_chan *mbox_request_channel_byname(struct mbox_client *cl,
of_property_for_each_string(np, "mbox-names", prop, mbox_name) {
if (!strncmp(name, mbox_name, strlen(name)))
- break;
+ return mbox_request_channel(cl, index);
index++;
}
- return mbox_request_channel(cl, index);
+ dev_err(cl->dev, "%s() could not locate channel named \"%s\"\n",
+ __func__, name);
+ return ERR_PTR(-EINVAL);
}
EXPORT_SYMBOL_GPL(mbox_request_channel_byname);
diff --git a/drivers/mailbox/mailbox.h b/drivers/mailbox/mailbox.h
index 456ba68513bb..4e3cc4426513 100644
--- a/drivers/mailbox/mailbox.h
+++ b/drivers/mailbox/mailbox.h
@@ -1,8 +1,4 @@
-/*
- * 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.
- */
+/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __MAILBOX_H
#define __MAILBOX_H
diff --git a/drivers/mailbox/omap-mailbox.c b/drivers/mailbox/omap-mailbox.c
index ca50177a33f2..a3cd63583cf7 100644
--- a/drivers/mailbox/omap-mailbox.c
+++ b/drivers/mailbox/omap-mailbox.c
@@ -3,7 +3,7 @@
* OMAP mailbox driver
*
* Copyright (C) 2006-2009 Nokia Corporation. All rights reserved.
- * Copyright (C) 2013-2016 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (C) 2013-2019 Texas Instruments Incorporated - http://www.ti.com
*
* Contact: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
* Suman Anna <s-anna@ti.com>
@@ -141,14 +141,14 @@ void mbox_write_reg(struct omap_mbox_device *mdev, u32 val, size_t ofs)
}
/* Mailbox FIFO handle functions */
-static mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox)
+static u32 mbox_fifo_read(struct omap_mbox *mbox)
{
struct omap_mbox_fifo *fifo = &mbox->rx_fifo;
- return (mbox_msg_t)mbox_read_reg(mbox->parent, fifo->msg);
+ return mbox_read_reg(mbox->parent, fifo->msg);
}
-static void mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg)
+static void mbox_fifo_write(struct omap_mbox *mbox, u32 msg)
{
struct omap_mbox_fifo *fifo = &mbox->tx_fifo;
@@ -256,14 +256,16 @@ static void mbox_rx_work(struct work_struct *work)
{
struct omap_mbox_queue *mq =
container_of(work, struct omap_mbox_queue, work);
- mbox_msg_t msg;
+ mbox_msg_t data;
+ u32 msg;
int len;
while (kfifo_len(&mq->fifo) >= sizeof(msg)) {
len = kfifo_out(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
WARN_ON(len != sizeof(msg));
+ data = msg;
- mbox_chan_received_data(mq->mbox->chan, (void *)msg);
+ mbox_chan_received_data(mq->mbox->chan, (void *)data);
spin_lock_irq(&mq->lock);
if (mq->full) {
mq->full = false;
@@ -286,7 +288,7 @@ static void __mbox_tx_interrupt(struct omap_mbox *mbox)
static void __mbox_rx_interrupt(struct omap_mbox *mbox)
{
struct omap_mbox_queue *mq = mbox->rxq;
- mbox_msg_t msg;
+ u32 msg;
int len;
while (!mbox_fifo_empty(mbox)) {
@@ -540,13 +542,13 @@ static void omap_mbox_chan_shutdown(struct mbox_chan *chan)
mutex_unlock(&mdev->cfg_lock);
}
-static int omap_mbox_chan_send_noirq(struct omap_mbox *mbox, void *data)
+static int omap_mbox_chan_send_noirq(struct omap_mbox *mbox, u32 msg)
{
int ret = -EBUSY;
if (!mbox_fifo_full(mbox)) {
_omap_mbox_enable_irq(mbox, IRQ_RX);
- mbox_fifo_write(mbox, (mbox_msg_t)data);
+ mbox_fifo_write(mbox, msg);
ret = 0;
_omap_mbox_disable_irq(mbox, IRQ_RX);
@@ -558,12 +560,12 @@ static int omap_mbox_chan_send_noirq(struct omap_mbox *mbox, void *data)
return ret;
}
-static int omap_mbox_chan_send(struct omap_mbox *mbox, void *data)
+static int omap_mbox_chan_send(struct omap_mbox *mbox, u32 msg)
{
int ret = -EBUSY;
if (!mbox_fifo_full(mbox)) {
- mbox_fifo_write(mbox, (mbox_msg_t)data);
+ mbox_fifo_write(mbox, msg);
ret = 0;
}
@@ -576,14 +578,15 @@ static int omap_mbox_chan_send_data(struct mbox_chan *chan, void *data)
{
struct omap_mbox *mbox = mbox_chan_to_omap_mbox(chan);
int ret;
+ u32 msg = omap_mbox_message(data);
if (!mbox)
return -EINVAL;
if (mbox->send_no_irq)
- ret = omap_mbox_chan_send_noirq(mbox, data);
+ ret = omap_mbox_chan_send_noirq(mbox, msg);
else
- ret = omap_mbox_chan_send(mbox, data);
+ ret = omap_mbox_chan_send(mbox, msg);
return ret;
}
@@ -657,6 +660,10 @@ static const struct of_device_id omap_mailbox_of_match[] = {
.data = &omap4_data,
},
{
+ .compatible = "ti,am654-mailbox",
+ .data = &omap4_data,
+ },
+ {
/* end */
},
};
@@ -830,7 +837,10 @@ static int omap_mbox_probe(struct platform_device *pdev)
mdev->intr_type = intr_type;
mdev->mboxes = list;
- /* OMAP does not have a Tx-Done IRQ, but rather a Tx-Ready IRQ */
+ /*
+ * OMAP/K3 Mailbox IP does not have a Tx-Done IRQ, but rather a Tx-Ready
+ * IRQ and is needed to run the Tx state machine
+ */
mdev->controller.txdone_irq = true;
mdev->controller.dev = mdev->dev;
mdev->controller.ops = &omap_mbox_chan_ops;
@@ -899,9 +909,8 @@ static int __init omap_mbox_init(void)
return err;
/* kfifo size sanity check: alignment and minimal size */
- mbox_kfifo_size = ALIGN(mbox_kfifo_size, sizeof(mbox_msg_t));
- mbox_kfifo_size = max_t(unsigned int, mbox_kfifo_size,
- sizeof(mbox_msg_t));
+ mbox_kfifo_size = ALIGN(mbox_kfifo_size, sizeof(u32));
+ mbox_kfifo_size = max_t(unsigned int, mbox_kfifo_size, sizeof(u32));
err = platform_driver_register(&omap_mbox_driver);
if (err)
diff --git a/drivers/mailbox/stm32-ipcc.c b/drivers/mailbox/stm32-ipcc.c
index f91dfb1327c7..5c2d1e1f988b 100644
--- a/drivers/mailbox/stm32-ipcc.c
+++ b/drivers/mailbox/stm32-ipcc.c
@@ -50,6 +50,7 @@ struct stm32_ipcc {
void __iomem *reg_base;
void __iomem *reg_proc;
struct clk *clk;
+ spinlock_t lock; /* protect access to IPCC registers */
int irqs[IPCC_IRQ_NUM];
int wkp;
u32 proc_id;
@@ -58,14 +59,24 @@ struct stm32_ipcc {
u32 xmr;
};
-static inline void stm32_ipcc_set_bits(void __iomem *reg, u32 mask)
+static inline void stm32_ipcc_set_bits(spinlock_t *lock, void __iomem *reg,
+ u32 mask)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(lock, flags);
writel_relaxed(readl_relaxed(reg) | mask, reg);
+ spin_unlock_irqrestore(lock, flags);
}
-static inline void stm32_ipcc_clr_bits(void __iomem *reg, u32 mask)
+static inline void stm32_ipcc_clr_bits(spinlock_t *lock, void __iomem *reg,
+ u32 mask)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(lock, flags);
writel_relaxed(readl_relaxed(reg) & ~mask, reg);
+ spin_unlock_irqrestore(lock, flags);
}
static irqreturn_t stm32_ipcc_rx_irq(int irq, void *data)
@@ -92,7 +103,7 @@ static irqreturn_t stm32_ipcc_rx_irq(int irq, void *data)
mbox_chan_received_data(&ipcc->controller.chans[chan], NULL);
- stm32_ipcc_set_bits(ipcc->reg_proc + IPCC_XSCR,
+ stm32_ipcc_set_bits(&ipcc->lock, ipcc->reg_proc + IPCC_XSCR,
RX_BIT_CHAN(chan));
ret = IRQ_HANDLED;
@@ -121,7 +132,7 @@ static irqreturn_t stm32_ipcc_tx_irq(int irq, void *data)
dev_dbg(dev, "%s: chan:%d tx\n", __func__, chan);
/* mask 'tx channel free' interrupt */
- stm32_ipcc_set_bits(ipcc->reg_proc + IPCC_XMR,
+ stm32_ipcc_set_bits(&ipcc->lock, ipcc->reg_proc + IPCC_XMR,
TX_BIT_CHAN(chan));
mbox_chan_txdone(&ipcc->controller.chans[chan], 0);
@@ -141,10 +152,12 @@ static int stm32_ipcc_send_data(struct mbox_chan *link, void *data)
dev_dbg(ipcc->controller.dev, "%s: chan:%d\n", __func__, chan);
/* set channel n occupied */
- stm32_ipcc_set_bits(ipcc->reg_proc + IPCC_XSCR, TX_BIT_CHAN(chan));
+ stm32_ipcc_set_bits(&ipcc->lock, ipcc->reg_proc + IPCC_XSCR,
+ TX_BIT_CHAN(chan));
/* unmask 'tx channel free' interrupt */
- stm32_ipcc_clr_bits(ipcc->reg_proc + IPCC_XMR, TX_BIT_CHAN(chan));
+ stm32_ipcc_clr_bits(&ipcc->lock, ipcc->reg_proc + IPCC_XMR,
+ TX_BIT_CHAN(chan));
return 0;
}
@@ -163,7 +176,8 @@ static int stm32_ipcc_startup(struct mbox_chan *link)
}
/* unmask 'rx channel occupied' interrupt */
- stm32_ipcc_clr_bits(ipcc->reg_proc + IPCC_XMR, RX_BIT_CHAN(chan));
+ stm32_ipcc_clr_bits(&ipcc->lock, ipcc->reg_proc + IPCC_XMR,
+ RX_BIT_CHAN(chan));
return 0;
}
@@ -175,7 +189,7 @@ static void stm32_ipcc_shutdown(struct mbox_chan *link)
controller);
/* mask rx/tx interrupt */
- stm32_ipcc_set_bits(ipcc->reg_proc + IPCC_XMR,
+ stm32_ipcc_set_bits(&ipcc->lock, ipcc->reg_proc + IPCC_XMR,
RX_BIT_CHAN(chan) | TX_BIT_CHAN(chan));
clk_disable_unprepare(ipcc->clk);
@@ -208,6 +222,8 @@ static int stm32_ipcc_probe(struct platform_device *pdev)
if (!ipcc)
return -ENOMEM;
+ spin_lock_init(&ipcc->lock);
+
/* proc_id */
if (of_property_read_u32(np, "st,proc-id", &ipcc->proc_id)) {
dev_err(dev, "Missing st,proc-id\n");
@@ -259,9 +275,10 @@ static int stm32_ipcc_probe(struct platform_device *pdev)
}
/* mask and enable rx/tx irq */
- stm32_ipcc_set_bits(ipcc->reg_proc + IPCC_XMR,
+ stm32_ipcc_set_bits(&ipcc->lock, ipcc->reg_proc + IPCC_XMR,
RX_BIT_MASK | TX_BIT_MASK);
- stm32_ipcc_set_bits(ipcc->reg_proc + IPCC_XCR, XCR_RXOIE | XCR_TXOIE);
+ stm32_ipcc_set_bits(&ipcc->lock, ipcc->reg_proc + IPCC_XCR,
+ XCR_RXOIE | XCR_TXOIE);
/* wakeup */
if (of_property_read_bool(np, "wakeup-source")) {
diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c
index 91f1a0c62779..4c5ba35d48d4 100644
--- a/drivers/mailbox/tegra-hsp.c
+++ b/drivers/mailbox/tegra-hsp.c
@@ -775,18 +775,28 @@ static int __maybe_unused tegra_hsp_resume(struct device *dev)
{
struct tegra_hsp *hsp = dev_get_drvdata(dev);
unsigned int i;
+ struct tegra_hsp_doorbell *db;
- for (i = 0; i < hsp->num_sm; i++) {
- struct tegra_hsp_mailbox *mb = &hsp->mailboxes[i];
+ list_for_each_entry(db, &hsp->doorbells, list) {
+ if (db && db->channel.chan)
+ tegra_hsp_doorbell_startup(db->channel.chan);
+ }
+
+ if (hsp->mailboxes) {
+ for (i = 0; i < hsp->num_sm; i++) {
+ struct tegra_hsp_mailbox *mb = &hsp->mailboxes[i];
- if (mb->channel.chan->cl)
- tegra_hsp_mailbox_startup(mb->channel.chan);
+ if (mb->channel.chan->cl)
+ tegra_hsp_mailbox_startup(mb->channel.chan);
+ }
}
return 0;
}
-static SIMPLE_DEV_PM_OPS(tegra_hsp_pm_ops, NULL, tegra_hsp_resume);
+static const struct dev_pm_ops tegra_hsp_pm_ops = {
+ .resume_noirq = tegra_hsp_resume,
+};
static const struct tegra_hsp_db_map tegra186_hsp_db_map[] = {
{ "ccplex", TEGRA_HSP_DB_MASTER_CCPLEX, HSP_DB_CCPLEX, },
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 45254b3ef715..3834332f4963 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -453,7 +453,7 @@ config DM_INIT
Enable "dm-mod.create=" parameter to create mapped devices at init time.
This option is useful to allow mounting rootfs without requiring an
initramfs.
- See Documentation/device-mapper/dm-init.txt for dm-mod.create="..."
+ See Documentation/admin-guide/device-mapper/dm-init.rst for dm-mod.create="..."
format.
If unsure, say N.
diff --git a/drivers/md/bcache/alloc.c b/drivers/md/bcache/alloc.c
index f8986effcb50..6f776823b9ba 100644
--- a/drivers/md/bcache/alloc.c
+++ b/drivers/md/bcache/alloc.c
@@ -393,6 +393,11 @@ long bch_bucket_alloc(struct cache *ca, unsigned int reserve, bool wait)
struct bucket *b;
long r;
+
+ /* No allocation if CACHE_SET_IO_DISABLE bit is set */
+ if (unlikely(test_bit(CACHE_SET_IO_DISABLE, &ca->set->flags)))
+ return -1;
+
/* fastpath */
if (fifo_pop(&ca->free[RESERVE_NONE], r) ||
fifo_pop(&ca->free[reserve], r))
@@ -484,6 +489,10 @@ int __bch_bucket_alloc_set(struct cache_set *c, unsigned int reserve,
{
int i;
+ /* No allocation if CACHE_SET_IO_DISABLE bit is set */
+ if (unlikely(test_bit(CACHE_SET_IO_DISABLE, &c->flags)))
+ return -1;
+
lockdep_assert_held(&c->bucket_lock);
BUG_ON(!n || n > c->caches_loaded || n > MAX_CACHES_PER_SET);
diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h
index fdf75352e16a..013e35a9e317 100644
--- a/drivers/md/bcache/bcache.h
+++ b/drivers/md/bcache/bcache.h
@@ -705,8 +705,8 @@ struct cache_set {
atomic_long_t writeback_keys_failed;
atomic_long_t reclaim;
+ atomic_long_t reclaimed_journal_buckets;
atomic_long_t flush_write;
- atomic_long_t retry_flush_write;
enum {
ON_ERROR_UNREGISTER,
@@ -726,8 +726,6 @@ struct cache_set {
#define BUCKET_HASH_BITS 12
struct hlist_head bucket_hash[1 << BUCKET_HASH_BITS];
-
- DECLARE_HEAP(struct btree *, flush_btree);
};
struct bbio {
@@ -1006,7 +1004,7 @@ int bch_flash_dev_create(struct cache_set *c, uint64_t size);
int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c,
uint8_t *set_uuid);
void bch_cached_dev_detach(struct cached_dev *dc);
-void bch_cached_dev_run(struct cached_dev *dc);
+int bch_cached_dev_run(struct cached_dev *dc);
void bcache_device_stop(struct bcache_device *d);
void bch_cache_set_unregister(struct cache_set *c);
diff --git a/drivers/md/bcache/bset.c b/drivers/md/bcache/bset.c
index 268f1b685084..08768796b543 100644
--- a/drivers/md/bcache/bset.c
+++ b/drivers/md/bcache/bset.c
@@ -347,22 +347,19 @@ EXPORT_SYMBOL(bch_btree_keys_alloc);
void bch_btree_keys_init(struct btree_keys *b, const struct btree_keys_ops *ops,
bool *expensive_debug_checks)
{
- unsigned int i;
-
b->ops = ops;
b->expensive_debug_checks = expensive_debug_checks;
b->nsets = 0;
b->last_set_unwritten = 0;
- /* XXX: shouldn't be needed */
- for (i = 0; i < MAX_BSETS; i++)
- b->set[i].size = 0;
/*
- * Second loop starts at 1 because b->keys[0]->data is the memory we
- * allocated
+ * struct btree_keys in embedded in struct btree, and struct
+ * bset_tree is embedded into struct btree_keys. They are all
+ * initialized as 0 by kzalloc() in mca_bucket_alloc(), and
+ * b->set[0].data is allocated in bch_btree_keys_alloc(), so we
+ * don't have to initiate b->set[].size and b->set[].data here
+ * any more.
*/
- for (i = 1; i < MAX_BSETS; i++)
- b->set[i].data = NULL;
}
EXPORT_SYMBOL(bch_btree_keys_init);
@@ -970,45 +967,25 @@ static struct bset_search_iter bset_search_tree(struct bset_tree *t,
unsigned int inorder, j, n = 1;
do {
- /*
- * A bit trick here.
- * If p < t->size, (int)(p - t->size) is a minus value and
- * the most significant bit is set, right shifting 31 bits
- * gets 1. If p >= t->size, the most significant bit is
- * not set, right shifting 31 bits gets 0.
- * So the following 2 lines equals to
- * if (p >= t->size)
- * p = 0;
- * but a branch instruction is avoided.
- */
unsigned int p = n << 4;
- p &= ((int) (p - t->size)) >> 31;
-
- prefetch(&t->tree[p]);
+ if (p < t->size)
+ prefetch(&t->tree[p]);
j = n;
f = &t->tree[j];
- /*
- * Similar bit trick, use subtract operation to avoid a branch
- * instruction.
- *
- * n = (f->mantissa > bfloat_mantissa())
- * ? j * 2
- * : j * 2 + 1;
- *
- * We need to subtract 1 from f->mantissa for the sign bit trick
- * to work - that's done in make_bfloat()
- */
- if (likely(f->exponent != 127))
- n = j * 2 + (((unsigned int)
- (f->mantissa -
- bfloat_mantissa(search, f))) >> 31);
- else
- n = (bkey_cmp(tree_to_bkey(t, j), search) > 0)
- ? j * 2
- : j * 2 + 1;
+ if (likely(f->exponent != 127)) {
+ if (f->mantissa >= bfloat_mantissa(search, f))
+ n = j * 2;
+ else
+ n = j * 2 + 1;
+ } else {
+ if (bkey_cmp(tree_to_bkey(t, j), search) > 0)
+ n = j * 2;
+ else
+ n = j * 2 + 1;
+ }
} while (n < t->size);
inorder = to_inorder(j, t);
diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c
index 773f5fdad25f..ba434d9ac720 100644
--- a/drivers/md/bcache/btree.c
+++ b/drivers/md/bcache/btree.c
@@ -35,7 +35,7 @@
#include <linux/rcupdate.h>
#include <linux/sched/clock.h>
#include <linux/rculist.h>
-
+#include <linux/delay.h>
#include <trace/events/bcache.h>
/*
@@ -613,6 +613,10 @@ static void mca_data_alloc(struct btree *b, struct bkey *k, gfp_t gfp)
static struct btree *mca_bucket_alloc(struct cache_set *c,
struct bkey *k, gfp_t gfp)
{
+ /*
+ * kzalloc() is necessary here for initialization,
+ * see code comments in bch_btree_keys_init().
+ */
struct btree *b = kzalloc(sizeof(struct btree), gfp);
if (!b)
@@ -655,7 +659,25 @@ static int mca_reap(struct btree *b, unsigned int min_order, bool flush)
up(&b->io_mutex);
}
+retry:
+ /*
+ * BTREE_NODE_dirty might be cleared in btree_flush_btree() by
+ * __bch_btree_node_write(). To avoid an extra flush, acquire
+ * b->write_lock before checking BTREE_NODE_dirty bit.
+ */
mutex_lock(&b->write_lock);
+ /*
+ * If this btree node is selected in btree_flush_write() by journal
+ * code, delay and retry until the node is flushed by journal code
+ * and BTREE_NODE_journal_flush bit cleared by btree_flush_write().
+ */
+ if (btree_node_journal_flush(b)) {
+ pr_debug("bnode %p is flushing by journal, retry", b);
+ mutex_unlock(&b->write_lock);
+ udelay(1);
+ goto retry;
+ }
+
if (btree_node_dirty(b))
__bch_btree_node_write(b, &cl);
mutex_unlock(&b->write_lock);
@@ -778,10 +800,15 @@ void bch_btree_cache_free(struct cache_set *c)
while (!list_empty(&c->btree_cache)) {
b = list_first_entry(&c->btree_cache, struct btree, list);
- if (btree_node_dirty(b))
+ /*
+ * This function is called by cache_set_free(), no I/O
+ * request on cache now, it is unnecessary to acquire
+ * b->write_lock before clearing BTREE_NODE_dirty anymore.
+ */
+ if (btree_node_dirty(b)) {
btree_complete_write(b, btree_current_write(b));
- clear_bit(BTREE_NODE_dirty, &b->flags);
-
+ clear_bit(BTREE_NODE_dirty, &b->flags);
+ }
mca_data_free(b);
}
@@ -1067,11 +1094,25 @@ static void btree_node_free(struct btree *b)
BUG_ON(b == b->c->root);
+retry:
mutex_lock(&b->write_lock);
+ /*
+ * If the btree node is selected and flushing in btree_flush_write(),
+ * delay and retry until the BTREE_NODE_journal_flush bit cleared,
+ * then it is safe to free the btree node here. Otherwise this btree
+ * node will be in race condition.
+ */
+ if (btree_node_journal_flush(b)) {
+ mutex_unlock(&b->write_lock);
+ pr_debug("bnode %p journal_flush set, retry", b);
+ udelay(1);
+ goto retry;
+ }
- if (btree_node_dirty(b))
+ if (btree_node_dirty(b)) {
btree_complete_write(b, btree_current_write(b));
- clear_bit(BTREE_NODE_dirty, &b->flags);
+ clear_bit(BTREE_NODE_dirty, &b->flags);
+ }
mutex_unlock(&b->write_lock);
diff --git a/drivers/md/bcache/btree.h b/drivers/md/bcache/btree.h
index d1c72ef64edf..76cfd121a486 100644
--- a/drivers/md/bcache/btree.h
+++ b/drivers/md/bcache/btree.h
@@ -158,11 +158,13 @@ enum btree_flags {
BTREE_NODE_io_error,
BTREE_NODE_dirty,
BTREE_NODE_write_idx,
+ BTREE_NODE_journal_flush,
};
BTREE_FLAG(io_error);
BTREE_FLAG(dirty);
BTREE_FLAG(write_idx);
+BTREE_FLAG(journal_flush);
static inline struct btree_write *btree_current_write(struct btree *b)
{
diff --git a/drivers/md/bcache/io.c b/drivers/md/bcache/io.c
index c25097968319..4d93f07f63e5 100644
--- a/drivers/md/bcache/io.c
+++ b/drivers/md/bcache/io.c
@@ -58,6 +58,18 @@ void bch_count_backing_io_errors(struct cached_dev *dc, struct bio *bio)
WARN_ONCE(!dc, "NULL pointer of struct cached_dev");
+ /*
+ * Read-ahead requests on a degrading and recovering md raid
+ * (e.g. raid6) device might be failured immediately by md
+ * raid code, which is not a real hardware media failure. So
+ * we shouldn't count failed REQ_RAHEAD bio to dc->io_errors.
+ */
+ if (bio->bi_opf & REQ_RAHEAD) {
+ pr_warn_ratelimited("%s: Read-ahead I/O failed on backing device, ignore",
+ dc->backing_dev_name);
+ return;
+ }
+
errors = atomic_add_return(1, &dc->io_errors);
if (errors < dc->error_limit)
pr_err("%s: IO error on backing device, unrecoverable",
diff --git a/drivers/md/bcache/journal.c b/drivers/md/bcache/journal.c
index 12dae9348147..be2a2a201603 100644
--- a/drivers/md/bcache/journal.c
+++ b/drivers/md/bcache/journal.c
@@ -100,6 +100,20 @@ reread: left = ca->sb.bucket_size - offset;
blocks = set_blocks(j, block_bytes(ca->set));
+ /*
+ * Nodes in 'list' are in linear increasing order of
+ * i->j.seq, the node on head has the smallest (oldest)
+ * journal seq, the node on tail has the biggest
+ * (latest) journal seq.
+ */
+
+ /*
+ * Check from the oldest jset for last_seq. If
+ * i->j.seq < j->last_seq, it means the oldest jset
+ * in list is expired and useless, remove it from
+ * this list. Otherwise, j is a condidate jset for
+ * further following checks.
+ */
while (!list_empty(list)) {
i = list_first_entry(list,
struct journal_replay, list);
@@ -109,13 +123,22 @@ reread: left = ca->sb.bucket_size - offset;
kfree(i);
}
+ /* iterate list in reverse order (from latest jset) */
list_for_each_entry_reverse(i, list, list) {
if (j->seq == i->j.seq)
goto next_set;
+ /*
+ * if j->seq is less than any i->j.last_seq
+ * in list, j is an expired and useless jset.
+ */
if (j->seq < i->j.last_seq)
goto next_set;
+ /*
+ * 'where' points to first jset in list which
+ * is elder then j.
+ */
if (j->seq > i->j.seq) {
where = &i->list;
goto add;
@@ -129,10 +152,12 @@ add:
if (!i)
return -ENOMEM;
memcpy(&i->j, j, bytes);
+ /* Add to the location after 'where' points to */
list_add(&i->list, where);
ret = 1;
- ja->seq[bucket_index] = j->seq;
+ if (j->seq > ja->seq[bucket_index])
+ ja->seq[bucket_index] = j->seq;
next_set:
offset += blocks * ca->sb.block_size;
len -= blocks * ca->sb.block_size;
@@ -268,7 +293,7 @@ bsearch:
struct journal_replay,
list)->j.seq;
- return ret;
+ return 0;
#undef read_bucket
}
@@ -391,60 +416,90 @@ err:
}
/* Journalling */
-#define journal_max_cmp(l, r) \
- (fifo_idx(&c->journal.pin, btree_current_write(l)->journal) < \
- fifo_idx(&(c)->journal.pin, btree_current_write(r)->journal))
-#define journal_min_cmp(l, r) \
- (fifo_idx(&c->journal.pin, btree_current_write(l)->journal) > \
- fifo_idx(&(c)->journal.pin, btree_current_write(r)->journal))
static void btree_flush_write(struct cache_set *c)
{
- /*
- * Try to find the btree node with that references the oldest journal
- * entry, best is our current candidate and is locked if non NULL:
- */
- struct btree *b;
- int i;
+ struct btree *b, *t, *btree_nodes[BTREE_FLUSH_NR];
+ unsigned int i, n;
+
+ if (c->journal.btree_flushing)
+ return;
+
+ spin_lock(&c->journal.flush_write_lock);
+ if (c->journal.btree_flushing) {
+ spin_unlock(&c->journal.flush_write_lock);
+ return;
+ }
+ c->journal.btree_flushing = true;
+ spin_unlock(&c->journal.flush_write_lock);
atomic_long_inc(&c->flush_write);
+ memset(btree_nodes, 0, sizeof(btree_nodes));
+ n = 0;
-retry:
- spin_lock(&c->journal.lock);
- if (heap_empty(&c->flush_btree)) {
- for_each_cached_btree(b, c, i)
- if (btree_current_write(b)->journal) {
- if (!heap_full(&c->flush_btree))
- heap_add(&c->flush_btree, b,
- journal_max_cmp);
- else if (journal_max_cmp(b,
- heap_peek(&c->flush_btree))) {
- c->flush_btree.data[0] = b;
- heap_sift(&c->flush_btree, 0,
- journal_max_cmp);
- }
- }
+ mutex_lock(&c->bucket_lock);
+ list_for_each_entry_safe_reverse(b, t, &c->btree_cache, list) {
+ if (btree_node_journal_flush(b))
+ pr_err("BUG: flush_write bit should not be set here!");
+
+ mutex_lock(&b->write_lock);
- for (i = c->flush_btree.used / 2 - 1; i >= 0; --i)
- heap_sift(&c->flush_btree, i, journal_min_cmp);
+ if (!btree_node_dirty(b)) {
+ mutex_unlock(&b->write_lock);
+ continue;
+ }
+
+ if (!btree_current_write(b)->journal) {
+ mutex_unlock(&b->write_lock);
+ continue;
+ }
+
+ set_btree_node_journal_flush(b);
+
+ mutex_unlock(&b->write_lock);
+
+ btree_nodes[n++] = b;
+ if (n == BTREE_FLUSH_NR)
+ break;
}
+ mutex_unlock(&c->bucket_lock);
- b = NULL;
- heap_pop(&c->flush_btree, b, journal_min_cmp);
- spin_unlock(&c->journal.lock);
+ for (i = 0; i < n; i++) {
+ b = btree_nodes[i];
+ if (!b) {
+ pr_err("BUG: btree_nodes[%d] is NULL", i);
+ continue;
+ }
+
+ /* safe to check without holding b->write_lock */
+ if (!btree_node_journal_flush(b)) {
+ pr_err("BUG: bnode %p: journal_flush bit cleaned", b);
+ continue;
+ }
- if (b) {
mutex_lock(&b->write_lock);
if (!btree_current_write(b)->journal) {
+ clear_bit(BTREE_NODE_journal_flush, &b->flags);
+ mutex_unlock(&b->write_lock);
+ pr_debug("bnode %p: written by others", b);
+ continue;
+ }
+
+ if (!btree_node_dirty(b)) {
+ clear_bit(BTREE_NODE_journal_flush, &b->flags);
mutex_unlock(&b->write_lock);
- /* We raced */
- atomic_long_inc(&c->retry_flush_write);
- goto retry;
+ pr_debug("bnode %p: dirty bit cleaned by others", b);
+ continue;
}
__bch_btree_node_write(b, NULL);
+ clear_bit(BTREE_NODE_journal_flush, &b->flags);
mutex_unlock(&b->write_lock);
}
+
+ spin_lock(&c->journal.flush_write_lock);
+ c->journal.btree_flushing = false;
+ spin_unlock(&c->journal.flush_write_lock);
}
#define last_seq(j) ((j)->seq - fifo_used(&(j)->pin) + 1)
@@ -559,6 +614,7 @@ static void journal_reclaim(struct cache_set *c)
k->ptr[n++] = MAKE_PTR(0,
bucket_to_sector(c, ca->sb.d[ja->cur_idx]),
ca->sb.nr_this_dev);
+ atomic_long_inc(&c->reclaimed_journal_buckets);
}
if (n) {
@@ -811,6 +867,10 @@ atomic_t *bch_journal(struct cache_set *c,
struct journal_write *w;
atomic_t *ret;
+ /* No journaling if CACHE_SET_IO_DISABLE set already */
+ if (unlikely(test_bit(CACHE_SET_IO_DISABLE, &c->flags)))
+ return NULL;
+
if (!CACHE_SYNC(&c->sb))
return NULL;
@@ -855,7 +915,6 @@ void bch_journal_free(struct cache_set *c)
free_pages((unsigned long) c->journal.w[1].data, JSET_BITS);
free_pages((unsigned long) c->journal.w[0].data, JSET_BITS);
free_fifo(&c->journal.pin);
- free_heap(&c->flush_btree);
}
int bch_journal_alloc(struct cache_set *c)
@@ -863,6 +922,7 @@ int bch_journal_alloc(struct cache_set *c)
struct journal *j = &c->journal;
spin_lock_init(&j->lock);
+ spin_lock_init(&j->flush_write_lock);
INIT_DELAYED_WORK(&j->work, journal_write_work);
c->journal_delay_ms = 100;
@@ -870,8 +930,7 @@ int bch_journal_alloc(struct cache_set *c)
j->w[0].c = c;
j->w[1].c = c;
- if (!(init_heap(&c->flush_btree, 128, GFP_KERNEL)) ||
- !(init_fifo(&j->pin, JOURNAL_PIN, GFP_KERNEL)) ||
+ if (!(init_fifo(&j->pin, JOURNAL_PIN, GFP_KERNEL)) ||
!(j->w[0].data = (void *) __get_free_pages(GFP_KERNEL, JSET_BITS)) ||
!(j->w[1].data = (void *) __get_free_pages(GFP_KERNEL, JSET_BITS)))
return -ENOMEM;
diff --git a/drivers/md/bcache/journal.h b/drivers/md/bcache/journal.h
index 66f0facff84b..f2ea34d5f431 100644
--- a/drivers/md/bcache/journal.h
+++ b/drivers/md/bcache/journal.h
@@ -103,6 +103,8 @@ struct journal_write {
/* Embedded in struct cache_set */
struct journal {
spinlock_t lock;
+ spinlock_t flush_write_lock;
+ bool btree_flushing;
/* used when waiting because the journal was full */
struct closure_waitlist wait;
struct closure io;
@@ -154,6 +156,8 @@ struct journal_device {
struct bio_vec bv[8];
};
+#define BTREE_FLUSH_NR 8
+
#define journal_pin_cmp(c, l, r) \
(fifo_idx(&(c)->journal.pin, (l)) > fifo_idx(&(c)->journal.pin, (r)))
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index 1b63ac876169..26e374fbf57c 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -40,6 +40,7 @@ static const char invalid_uuid[] = {
static struct kobject *bcache_kobj;
struct mutex bch_register_lock;
+bool bcache_is_reboot;
LIST_HEAD(bch_cache_sets);
static LIST_HEAD(uncached_devices);
@@ -49,6 +50,7 @@ static wait_queue_head_t unregister_wait;
struct workqueue_struct *bcache_wq;
struct workqueue_struct *bch_journal_wq;
+
#define BTREE_MAX_PAGES (256 * 1024 / PAGE_SIZE)
/* limitation of partitions number on single bcache device */
#define BCACHE_MINORS 128
@@ -197,7 +199,9 @@ err:
static void write_bdev_super_endio(struct bio *bio)
{
struct cached_dev *dc = bio->bi_private;
- /* XXX: error checking */
+
+ if (bio->bi_status)
+ bch_count_backing_io_errors(dc, bio);
closure_put(&dc->sb_write);
}
@@ -691,6 +695,7 @@ static void bcache_device_link(struct bcache_device *d, struct cache_set *c,
{
unsigned int i;
struct cache *ca;
+ int ret;
for_each_cache(ca, d->c, i)
bd_link_disk_holder(ca->bdev, d->disk);
@@ -698,9 +703,13 @@ static void bcache_device_link(struct bcache_device *d, struct cache_set *c,
snprintf(d->name, BCACHEDEVNAME_SIZE,
"%s%u", name, d->id);
- WARN(sysfs_create_link(&d->kobj, &c->kobj, "cache") ||
- sysfs_create_link(&c->kobj, &d->kobj, d->name),
- "Couldn't create device <-> cache set symlinks");
+ ret = sysfs_create_link(&d->kobj, &c->kobj, "cache");
+ if (ret < 0)
+ pr_err("Couldn't create device -> cache set symlink");
+
+ ret = sysfs_create_link(&c->kobj, &d->kobj, d->name);
+ if (ret < 0)
+ pr_err("Couldn't create cache set -> device symlink");
clear_bit(BCACHE_DEV_UNLINK_DONE, &d->flags);
}
@@ -908,7 +917,7 @@ static int cached_dev_status_update(void *arg)
}
-void bch_cached_dev_run(struct cached_dev *dc)
+int bch_cached_dev_run(struct cached_dev *dc)
{
struct bcache_device *d = &dc->disk;
char *buf = kmemdup_nul(dc->sb.label, SB_LABEL_SIZE, GFP_KERNEL);
@@ -919,11 +928,19 @@ void bch_cached_dev_run(struct cached_dev *dc)
NULL,
};
+ if (dc->io_disable) {
+ pr_err("I/O disabled on cached dev %s",
+ dc->backing_dev_name);
+ return -EIO;
+ }
+
if (atomic_xchg(&dc->running, 1)) {
kfree(env[1]);
kfree(env[2]);
kfree(buf);
- return;
+ pr_info("cached dev %s is running already",
+ dc->backing_dev_name);
+ return -EBUSY;
}
if (!d->c &&
@@ -949,8 +966,11 @@ void bch_cached_dev_run(struct cached_dev *dc)
kfree(buf);
if (sysfs_create_link(&d->kobj, &disk_to_dev(d->disk)->kobj, "dev") ||
- sysfs_create_link(&disk_to_dev(d->disk)->kobj, &d->kobj, "bcache"))
- pr_debug("error creating sysfs link");
+ sysfs_create_link(&disk_to_dev(d->disk)->kobj,
+ &d->kobj, "bcache")) {
+ pr_err("Couldn't create bcache dev <-> disk sysfs symlinks");
+ return -ENOMEM;
+ }
dc->status_update_thread = kthread_run(cached_dev_status_update,
dc, "bcache_status_update");
@@ -959,6 +979,8 @@ void bch_cached_dev_run(struct cached_dev *dc)
"continue to run without monitoring backing "
"device status");
}
+
+ return 0;
}
/*
@@ -996,7 +1018,6 @@ static void cached_dev_detach_finish(struct work_struct *w)
BUG_ON(!test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags));
BUG_ON(refcount_read(&dc->count));
- mutex_lock(&bch_register_lock);
if (test_and_clear_bit(BCACHE_DEV_WB_RUNNING, &dc->disk.flags))
cancel_writeback_rate_update_dwork(dc);
@@ -1012,6 +1033,8 @@ static void cached_dev_detach_finish(struct work_struct *w)
bch_write_bdev_super(dc, &cl);
closure_sync(&cl);
+ mutex_lock(&bch_register_lock);
+
calc_cached_dev_sectors(dc->disk.c);
bcache_device_detach(&dc->disk);
list_move(&dc->list, &uncached_devices);
@@ -1054,6 +1077,7 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c,
uint32_t rtime = cpu_to_le32((u32)ktime_get_real_seconds());
struct uuid_entry *u;
struct cached_dev *exist_dc, *t;
+ int ret = 0;
if ((set_uuid && memcmp(set_uuid, c->sb.set_uuid, 16)) ||
(!set_uuid && memcmp(dc->sb.set_uuid, c->sb.set_uuid, 16)))
@@ -1153,6 +1177,8 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c,
down_write(&dc->writeback_lock);
if (bch_cached_dev_writeback_start(dc)) {
up_write(&dc->writeback_lock);
+ pr_err("Couldn't start writeback facilities for %s",
+ dc->disk.disk->disk_name);
return -ENOMEM;
}
@@ -1163,7 +1189,22 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c,
bch_sectors_dirty_init(&dc->disk);
- bch_cached_dev_run(dc);
+ ret = bch_cached_dev_run(dc);
+ if (ret && (ret != -EBUSY)) {
+ up_write(&dc->writeback_lock);
+ /*
+ * bch_register_lock is held, bcache_device_stop() is not
+ * able to be directly called. The kthread and kworker
+ * created previously in bch_cached_dev_writeback_start()
+ * have to be stopped manually here.
+ */
+ kthread_stop(dc->writeback_thread);
+ cancel_writeback_rate_update_dwork(dc);
+ pr_err("Couldn't run cached device %s",
+ dc->backing_dev_name);
+ return ret;
+ }
+
bcache_device_link(&dc->disk, c, "bdev");
atomic_inc(&c->attached_dev_nr);
@@ -1190,18 +1231,16 @@ static void cached_dev_free(struct closure *cl)
{
struct cached_dev *dc = container_of(cl, struct cached_dev, disk.cl);
- mutex_lock(&bch_register_lock);
-
if (test_and_clear_bit(BCACHE_DEV_WB_RUNNING, &dc->disk.flags))
cancel_writeback_rate_update_dwork(dc);
if (!IS_ERR_OR_NULL(dc->writeback_thread))
kthread_stop(dc->writeback_thread);
- if (dc->writeback_write_wq)
- destroy_workqueue(dc->writeback_write_wq);
if (!IS_ERR_OR_NULL(dc->status_update_thread))
kthread_stop(dc->status_update_thread);
+ mutex_lock(&bch_register_lock);
+
if (atomic_read(&dc->running))
bd_unlink_disk_holder(dc->bdev, dc->disk.disk);
bcache_device_free(&dc->disk);
@@ -1290,6 +1329,7 @@ static int register_bdev(struct cache_sb *sb, struct page *sb_page,
{
const char *err = "cannot allocate memory";
struct cache_set *c;
+ int ret = -ENOMEM;
bdevname(bdev, dc->backing_dev_name);
memcpy(&dc->sb, sb, sizeof(struct cache_sb));
@@ -1319,14 +1359,18 @@ static int register_bdev(struct cache_sb *sb, struct page *sb_page,
bch_cached_dev_attach(dc, c, NULL);
if (BDEV_STATE(&dc->sb) == BDEV_STATE_NONE ||
- BDEV_STATE(&dc->sb) == BDEV_STATE_STALE)
- bch_cached_dev_run(dc);
+ BDEV_STATE(&dc->sb) == BDEV_STATE_STALE) {
+ err = "failed to run cached device";
+ ret = bch_cached_dev_run(dc);
+ if (ret)
+ goto err;
+ }
return 0;
err:
pr_notice("error %s: %s", dc->backing_dev_name, err);
bcache_device_stop(&dc->disk);
- return -EIO;
+ return ret;
}
/* Flash only volumes */
@@ -1437,8 +1481,6 @@ int bch_flash_dev_create(struct cache_set *c, uint64_t size)
bool bch_cached_dev_error(struct cached_dev *dc)
{
- struct cache_set *c;
-
if (!dc || test_bit(BCACHE_DEV_CLOSING, &dc->disk.flags))
return false;
@@ -1449,21 +1491,6 @@ bool bch_cached_dev_error(struct cached_dev *dc)
pr_err("stop %s: too many IO errors on backing device %s\n",
dc->disk.disk->disk_name, dc->backing_dev_name);
- /*
- * If the cached device is still attached to a cache set,
- * even dc->io_disable is true and no more I/O requests
- * accepted, cache device internal I/O (writeback scan or
- * garbage collection) may still prevent bcache device from
- * being stopped. So here CACHE_SET_IO_DISABLE should be
- * set to c->flags too, to make the internal I/O to cache
- * device rejected and stopped immediately.
- * If c is NULL, that means the bcache device is not attached
- * to any cache set, then no CACHE_SET_IO_DISABLE bit to set.
- */
- c = dc->disk.c;
- if (c && test_and_set_bit(CACHE_SET_IO_DISABLE, &c->flags))
- pr_info("CACHE_SET_IO_DISABLE already set");
-
bcache_device_stop(&dc->disk);
return true;
}
@@ -1564,19 +1591,23 @@ static void cache_set_flush(struct closure *cl)
kobject_put(&c->internal);
kobject_del(&c->kobj);
- if (c->gc_thread)
+ if (!IS_ERR_OR_NULL(c->gc_thread))
kthread_stop(c->gc_thread);
if (!IS_ERR_OR_NULL(c->root))
list_add(&c->root->list, &c->btree_cache);
- /* Should skip this if we're unregistering because of an error */
- list_for_each_entry(b, &c->btree_cache, list) {
- mutex_lock(&b->write_lock);
- if (btree_node_dirty(b))
- __bch_btree_node_write(b, NULL);
- mutex_unlock(&b->write_lock);
- }
+ /*
+ * Avoid flushing cached nodes if cache set is retiring
+ * due to too many I/O errors detected.
+ */
+ if (!test_bit(CACHE_SET_IO_DISABLE, &c->flags))
+ list_for_each_entry(b, &c->btree_cache, list) {
+ mutex_lock(&b->write_lock);
+ if (btree_node_dirty(b))
+ __bch_btree_node_write(b, NULL);
+ mutex_unlock(&b->write_lock);
+ }
for_each_cache(ca, c, i)
if (ca->alloc_thread)
@@ -1849,6 +1880,23 @@ static int run_cache_set(struct cache_set *c)
if (bch_btree_check(c))
goto err;
+ /*
+ * bch_btree_check() may occupy too much system memory which
+ * has negative effects to user space application (e.g. data
+ * base) performance. Shrink the mca cache memory proactively
+ * here to avoid competing memory with user space workloads..
+ */
+ if (!c->shrinker_disabled) {
+ struct shrink_control sc;
+
+ sc.gfp_mask = GFP_KERNEL;
+ sc.nr_to_scan = c->btree_cache_used * c->btree_pages;
+ /* first run to clear b->accessed tag */
+ c->shrink.scan_objects(&c->shrink, &sc);
+ /* second run to reap non-accessed nodes */
+ c->shrink.scan_objects(&c->shrink, &sc);
+ }
+
bch_journal_mark(c, &journal);
bch_initial_gc_finish(c);
pr_debug("btree_check() done");
@@ -1957,7 +2005,7 @@ err:
}
closure_sync(&cl);
- /* XXX: test this, it's broken */
+
bch_cache_set_error(c, "%s", err);
return -EIO;
@@ -2251,9 +2299,13 @@ err:
static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
const char *buffer, size_t size);
+static ssize_t bch_pending_bdevs_cleanup(struct kobject *k,
+ struct kobj_attribute *attr,
+ const char *buffer, size_t size);
kobj_attribute_write(register, register_bcache);
kobj_attribute_write(register_quiet, register_bcache);
+kobj_attribute_write(pendings_cleanup, bch_pending_bdevs_cleanup);
static bool bch_is_open_backing(struct block_device *bdev)
{
@@ -2301,6 +2353,11 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
if (!try_module_get(THIS_MODULE))
return -EBUSY;
+ /* For latest state of bcache_is_reboot */
+ smp_mb();
+ if (bcache_is_reboot)
+ return -EBUSY;
+
path = kstrndup(buffer, size, GFP_KERNEL);
if (!path)
goto err;
@@ -2378,8 +2435,61 @@ err:
goto out;
}
+
+struct pdev {
+ struct list_head list;
+ struct cached_dev *dc;
+};
+
+static ssize_t bch_pending_bdevs_cleanup(struct kobject *k,
+ struct kobj_attribute *attr,
+ const char *buffer,
+ size_t size)
+{
+ LIST_HEAD(pending_devs);
+ ssize_t ret = size;
+ struct cached_dev *dc, *tdc;
+ struct pdev *pdev, *tpdev;
+ struct cache_set *c, *tc;
+
+ mutex_lock(&bch_register_lock);
+ list_for_each_entry_safe(dc, tdc, &uncached_devices, list) {
+ pdev = kmalloc(sizeof(struct pdev), GFP_KERNEL);
+ if (!pdev)
+ break;
+ pdev->dc = dc;
+ list_add(&pdev->list, &pending_devs);
+ }
+
+ list_for_each_entry_safe(pdev, tpdev, &pending_devs, list) {
+ list_for_each_entry_safe(c, tc, &bch_cache_sets, list) {
+ char *pdev_set_uuid = pdev->dc->sb.set_uuid;
+ char *set_uuid = c->sb.uuid;
+
+ if (!memcmp(pdev_set_uuid, set_uuid, 16)) {
+ list_del(&pdev->list);
+ kfree(pdev);
+ break;
+ }
+ }
+ }
+ mutex_unlock(&bch_register_lock);
+
+ list_for_each_entry_safe(pdev, tpdev, &pending_devs, list) {
+ pr_info("delete pdev %p", pdev);
+ list_del(&pdev->list);
+ bcache_device_stop(&pdev->dc->disk);
+ kfree(pdev);
+ }
+
+ return ret;
+}
+
static int bcache_reboot(struct notifier_block *n, unsigned long code, void *x)
{
+ if (bcache_is_reboot)
+ return NOTIFY_DONE;
+
if (code == SYS_DOWN ||
code == SYS_HALT ||
code == SYS_POWER_OFF) {
@@ -2392,19 +2502,45 @@ static int bcache_reboot(struct notifier_block *n, unsigned long code, void *x)
mutex_lock(&bch_register_lock);
+ if (bcache_is_reboot)
+ goto out;
+
+ /* New registration is rejected since now */
+ bcache_is_reboot = true;
+ /*
+ * Make registering caller (if there is) on other CPU
+ * core know bcache_is_reboot set to true earlier
+ */
+ smp_mb();
+
if (list_empty(&bch_cache_sets) &&
list_empty(&uncached_devices))
goto out;
+ mutex_unlock(&bch_register_lock);
+
pr_info("Stopping all devices:");
+ /*
+ * The reason bch_register_lock is not held to call
+ * bch_cache_set_stop() and bcache_device_stop() is to
+ * avoid potential deadlock during reboot, because cache
+ * set or bcache device stopping process will acqurie
+ * bch_register_lock too.
+ *
+ * We are safe here because bcache_is_reboot sets to
+ * true already, register_bcache() will reject new
+ * registration now. bcache_is_reboot also makes sure
+ * bcache_reboot() won't be re-entered on by other thread,
+ * so there is no race in following list iteration by
+ * list_for_each_entry_safe().
+ */
list_for_each_entry_safe(c, tc, &bch_cache_sets, list)
bch_cache_set_stop(c);
list_for_each_entry_safe(dc, tdc, &uncached_devices, list)
bcache_device_stop(&dc->disk);
- mutex_unlock(&bch_register_lock);
/*
* Give an early chance for other kthreads and
@@ -2496,6 +2632,7 @@ static int __init bcache_init(void)
static const struct attribute *files[] = {
&ksysfs_register.attr,
&ksysfs_register_quiet.attr,
+ &ksysfs_pendings_cleanup.attr,
NULL
};
@@ -2531,6 +2668,8 @@ static int __init bcache_init(void)
bch_debug_init();
closure_debug_init();
+ bcache_is_reboot = false;
+
return 0;
err:
bcache_exit();
diff --git a/drivers/md/bcache/sysfs.c b/drivers/md/bcache/sysfs.c
index bfb437ffb13c..9f0826712845 100644
--- a/drivers/md/bcache/sysfs.c
+++ b/drivers/md/bcache/sysfs.c
@@ -16,33 +16,31 @@
#include <linux/sort.h>
#include <linux/sched/clock.h>
+extern bool bcache_is_reboot;
+
/* Default is 0 ("writethrough") */
static const char * const bch_cache_modes[] = {
"writethrough",
"writeback",
"writearound",
- "none",
- NULL
+ "none"
};
/* Default is 0 ("auto") */
static const char * const bch_stop_on_failure_modes[] = {
"auto",
- "always",
- NULL
+ "always"
};
static const char * const cache_replacement_policies[] = {
"lru",
"fifo",
- "random",
- NULL
+ "random"
};
static const char * const error_actions[] = {
"unregister",
- "panic",
- NULL
+ "panic"
};
write_attribute(attach);
@@ -84,8 +82,8 @@ read_attribute(bset_tree_stats);
read_attribute(state);
read_attribute(cache_read_races);
read_attribute(reclaim);
+read_attribute(reclaimed_journal_buckets);
read_attribute(flush_write);
-read_attribute(retry_flush_write);
read_attribute(writeback_keys_done);
read_attribute(writeback_keys_failed);
read_attribute(io_errors);
@@ -180,7 +178,7 @@ SHOW(__bch_cached_dev)
var_print(writeback_percent);
sysfs_hprint(writeback_rate,
wb ? atomic_long_read(&dc->writeback_rate.rate) << 9 : 0);
- sysfs_hprint(io_errors, atomic_read(&dc->io_errors));
+ sysfs_printf(io_errors, "%i", atomic_read(&dc->io_errors));
sysfs_printf(io_error_limit, "%i", dc->error_limit);
sysfs_printf(io_disable, "%i", dc->io_disable);
var_print(writeback_rate_update_seconds);
@@ -271,6 +269,10 @@ STORE(__cached_dev)
struct cache_set *c;
struct kobj_uevent_env *env;
+ /* no user space access if system is rebooting */
+ if (bcache_is_reboot)
+ return -EBUSY;
+
#define d_strtoul(var) sysfs_strtoul(var, dc->var)
#define d_strtoul_nonzero(var) sysfs_strtoul_clamp(var, dc->var, 1, INT_MAX)
#define d_strtoi_h(var) sysfs_hatoi(var, dc->var)
@@ -329,11 +331,14 @@ STORE(__cached_dev)
bch_cache_accounting_clear(&dc->accounting);
if (attr == &sysfs_running &&
- strtoul_or_return(buf))
- bch_cached_dev_run(dc);
+ strtoul_or_return(buf)) {
+ v = bch_cached_dev_run(dc);
+ if (v)
+ return v;
+ }
if (attr == &sysfs_cache_mode) {
- v = __sysfs_match_string(bch_cache_modes, -1, buf);
+ v = sysfs_match_string(bch_cache_modes, buf);
if (v < 0)
return v;
@@ -344,7 +349,7 @@ STORE(__cached_dev)
}
if (attr == &sysfs_stop_when_cache_set_failed) {
- v = __sysfs_match_string(bch_stop_on_failure_modes, -1, buf);
+ v = sysfs_match_string(bch_stop_on_failure_modes, buf);
if (v < 0)
return v;
@@ -408,6 +413,10 @@ STORE(bch_cached_dev)
struct cached_dev *dc = container_of(kobj, struct cached_dev,
disk.kobj);
+ /* no user space access if system is rebooting */
+ if (bcache_is_reboot)
+ return -EBUSY;
+
mutex_lock(&bch_register_lock);
size = __cached_dev_store(kobj, attr, buf, size);
@@ -464,7 +473,7 @@ static struct attribute *bch_cached_dev_files[] = {
&sysfs_writeback_rate_p_term_inverse,
&sysfs_writeback_rate_minimum,
&sysfs_writeback_rate_debug,
- &sysfs_errors,
+ &sysfs_io_errors,
&sysfs_io_error_limit,
&sysfs_io_disable,
&sysfs_dirty_data,
@@ -511,6 +520,10 @@ STORE(__bch_flash_dev)
kobj);
struct uuid_entry *u = &d->c->uuids[d->id];
+ /* no user space access if system is rebooting */
+ if (bcache_is_reboot)
+ return -EBUSY;
+
sysfs_strtoul(data_csum, d->data_csum);
if (attr == &sysfs_size) {
@@ -693,12 +706,12 @@ SHOW(__bch_cache_set)
sysfs_print(reclaim,
atomic_long_read(&c->reclaim));
+ sysfs_print(reclaimed_journal_buckets,
+ atomic_long_read(&c->reclaimed_journal_buckets));
+
sysfs_print(flush_write,
atomic_long_read(&c->flush_write));
- sysfs_print(retry_flush_write,
- atomic_long_read(&c->retry_flush_write));
-
sysfs_print(writeback_keys_done,
atomic_long_read(&c->writeback_keys_done));
sysfs_print(writeback_keys_failed,
@@ -746,6 +759,10 @@ STORE(__bch_cache_set)
struct cache_set *c = container_of(kobj, struct cache_set, kobj);
ssize_t v;
+ /* no user space access if system is rebooting */
+ if (bcache_is_reboot)
+ return -EBUSY;
+
if (attr == &sysfs_unregister)
bch_cache_set_unregister(c);
@@ -799,7 +816,7 @@ STORE(__bch_cache_set)
0, UINT_MAX);
if (attr == &sysfs_errors) {
- v = __sysfs_match_string(error_actions, -1, buf);
+ v = sysfs_match_string(error_actions, buf);
if (v < 0)
return v;
@@ -865,6 +882,10 @@ STORE(bch_cache_set_internal)
{
struct cache_set *c = container_of(kobj, struct cache_set, internal);
+ /* no user space access if system is rebooting */
+ if (bcache_is_reboot)
+ return -EBUSY;
+
return bch_cache_set_store(&c->kobj, attr, buf, size);
}
@@ -914,8 +935,8 @@ static struct attribute *bch_cache_set_internal_files[] = {
&sysfs_bset_tree_stats,
&sysfs_cache_read_races,
&sysfs_reclaim,
+ &sysfs_reclaimed_journal_buckets,
&sysfs_flush_write,
- &sysfs_retry_flush_write,
&sysfs_writeback_keys_done,
&sysfs_writeback_keys_failed,
@@ -1050,6 +1071,10 @@ STORE(__bch_cache)
struct cache *ca = container_of(kobj, struct cache, kobj);
ssize_t v;
+ /* no user space access if system is rebooting */
+ if (bcache_is_reboot)
+ return -EBUSY;
+
if (attr == &sysfs_discard) {
bool v = strtoul_or_return(buf);
@@ -1063,7 +1088,7 @@ STORE(__bch_cache)
}
if (attr == &sysfs_cache_replacement_policy) {
- v = __sysfs_match_string(cache_replacement_policies, -1, buf);
+ v = sysfs_match_string(cache_replacement_policies, buf);
if (v < 0)
return v;
diff --git a/drivers/md/bcache/util.h b/drivers/md/bcache/util.h
index 1fbced94e4cc..c029f7443190 100644
--- a/drivers/md/bcache/util.h
+++ b/drivers/md/bcache/util.h
@@ -113,8 +113,6 @@ do { \
#define heap_full(h) ((h)->used == (h)->size)
-#define heap_empty(h) ((h)->used == 0)
-
#define DECLARE_FIFO(type, name) \
struct { \
size_t front, back, size, mask; \
diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c
index 73f0efac2b9f..d60268fe49e1 100644
--- a/drivers/md/bcache/writeback.c
+++ b/drivers/md/bcache/writeback.c
@@ -122,6 +122,9 @@ static void __update_writeback_rate(struct cached_dev *dc)
static bool set_at_max_writeback_rate(struct cache_set *c,
struct cached_dev *dc)
{
+ /* Don't set max writeback rate if gc is running */
+ if (!c->gc_mark_valid)
+ return false;
/*
* Idle_counter is increased everytime when update_writeback_rate() is
* called. If all backing devices attached to the same cache set have
@@ -735,6 +738,10 @@ static int bch_writeback_thread(void *arg)
}
}
+ if (dc->writeback_write_wq) {
+ flush_workqueue(dc->writeback_write_wq);
+ destroy_workqueue(dc->writeback_write_wq);
+ }
cached_dev_put(dc);
wait_for_kthread_stop();
@@ -830,6 +837,7 @@ int bch_cached_dev_writeback_start(struct cached_dev *dc)
"bcache_writeback");
if (IS_ERR(dc->writeback_thread)) {
cached_dev_put(dc);
+ destroy_workqueue(dc->writeback_write_wq);
return PTR_ERR(dc->writeback_thread);
}
dc->writeback_running = true;
diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c
index 2a48ea3f1b30..b6b5acc92ca2 100644
--- a/drivers/md/dm-bufio.c
+++ b/drivers/md/dm-bufio.c
@@ -1599,9 +1599,7 @@ dm_bufio_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
unsigned long freed;
c = container_of(shrink, struct dm_bufio_client, shrinker);
- if (sc->gfp_mask & __GFP_FS)
- dm_bufio_lock(c);
- else if (!dm_bufio_trylock(c))
+ if (!dm_bufio_trylock(c))
return SHRINK_STOP;
freed = __scan(c, sc->nr_to_scan, sc->gfp_mask);
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 1b16d34bb785..d5216bcc4649 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -120,6 +120,10 @@ struct iv_tcw_private {
u8 *whitening;
};
+struct iv_eboiv_private {
+ struct crypto_cipher *tfm;
+};
+
/*
* Crypt: maps a linear range of a block device
* and encrypts / decrypts at the same time.
@@ -159,6 +163,7 @@ struct crypt_config {
struct iv_benbi_private benbi;
struct iv_lmk_private lmk;
struct iv_tcw_private tcw;
+ struct iv_eboiv_private eboiv;
} iv_gen_private;
u64 iv_offset;
unsigned int iv_size;
@@ -291,8 +296,9 @@ static struct crypto_aead *any_tfm_aead(struct crypt_config *cc)
* Note that this encryption scheme is vulnerable to watermarking attacks
* and should be used for old compatible containers access only.
*
- * plumb: unimplemented, see:
- * http://article.gmane.org/gmane.linux.kernel.device-mapper.dm-crypt/454
+ * eboiv: Encrypted byte-offset IV (used in Bitlocker in CBC mode)
+ * The IV is encrypted little-endian byte-offset (with the same key
+ * and cipher as the volume).
*/
static int crypt_iv_plain_gen(struct crypt_config *cc, u8 *iv,
@@ -841,6 +847,67 @@ static int crypt_iv_random_gen(struct crypt_config *cc, u8 *iv,
return 0;
}
+static void crypt_iv_eboiv_dtr(struct crypt_config *cc)
+{
+ struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
+
+ crypto_free_cipher(eboiv->tfm);
+ eboiv->tfm = NULL;
+}
+
+static int crypt_iv_eboiv_ctr(struct crypt_config *cc, struct dm_target *ti,
+ const char *opts)
+{
+ struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
+ struct crypto_cipher *tfm;
+
+ tfm = crypto_alloc_cipher(cc->cipher, 0, 0);
+ if (IS_ERR(tfm)) {
+ ti->error = "Error allocating crypto tfm for EBOIV";
+ return PTR_ERR(tfm);
+ }
+
+ if (crypto_cipher_blocksize(tfm) != cc->iv_size) {
+ ti->error = "Block size of EBOIV cipher does "
+ "not match IV size of block cipher";
+ crypto_free_cipher(tfm);
+ return -EINVAL;
+ }
+
+ eboiv->tfm = tfm;
+ return 0;
+}
+
+static int crypt_iv_eboiv_init(struct crypt_config *cc)
+{
+ struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
+ int err;
+
+ err = crypto_cipher_setkey(eboiv->tfm, cc->key, cc->key_size);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int crypt_iv_eboiv_wipe(struct crypt_config *cc)
+{
+ /* Called after cc->key is set to random key in crypt_wipe() */
+ return crypt_iv_eboiv_init(cc);
+}
+
+static int crypt_iv_eboiv_gen(struct crypt_config *cc, u8 *iv,
+ struct dm_crypt_request *dmreq)
+{
+ struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
+
+ memset(iv, 0, cc->iv_size);
+ *(__le64 *)iv = cpu_to_le64(dmreq->iv_sector * cc->sector_size);
+ crypto_cipher_encrypt_one(eboiv->tfm, iv, iv);
+
+ return 0;
+}
+
static const struct crypt_iv_operations crypt_iv_plain_ops = {
.generator = crypt_iv_plain_gen
};
@@ -893,6 +960,14 @@ static struct crypt_iv_operations crypt_iv_random_ops = {
.generator = crypt_iv_random_gen
};
+static struct crypt_iv_operations crypt_iv_eboiv_ops = {
+ .ctr = crypt_iv_eboiv_ctr,
+ .dtr = crypt_iv_eboiv_dtr,
+ .init = crypt_iv_eboiv_init,
+ .wipe = crypt_iv_eboiv_wipe,
+ .generator = crypt_iv_eboiv_gen
+};
+
/*
* Integrity extensions
*/
@@ -2158,6 +2233,14 @@ static int crypt_wipe_key(struct crypt_config *cc)
clear_bit(DM_CRYPT_KEY_VALID, &cc->flags);
get_random_bytes(&cc->key, cc->key_size);
+
+ /* Wipe IV private keys */
+ if (cc->iv_gen_ops && cc->iv_gen_ops->wipe) {
+ r = cc->iv_gen_ops->wipe(cc);
+ if (r)
+ return r;
+ }
+
kzfree(cc->key_string);
cc->key_string = NULL;
r = crypt_setkey(cc);
@@ -2288,6 +2371,8 @@ static int crypt_ctr_ivmode(struct dm_target *ti, const char *ivmode)
cc->iv_gen_ops = &crypt_iv_benbi_ops;
else if (strcmp(ivmode, "null") == 0)
cc->iv_gen_ops = &crypt_iv_null_ops;
+ else if (strcmp(ivmode, "eboiv") == 0)
+ cc->iv_gen_ops = &crypt_iv_eboiv_ops;
else if (strcmp(ivmode, "lmk") == 0) {
cc->iv_gen_ops = &crypt_iv_lmk_ops;
/*
@@ -2699,7 +2784,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
return -EINVAL;
}
- cc = kzalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL);
+ cc = kzalloc(struct_size(cc, key, key_size), GFP_KERNEL);
if (!cc) {
ti->error = "Cannot allocate encryption context";
return -ENOMEM;
@@ -3050,14 +3135,8 @@ static int crypt_message(struct dm_target *ti, unsigned argc, char **argv,
memset(cc->key, 0, cc->key_size * sizeof(u8));
return ret;
}
- if (argc == 2 && !strcasecmp(argv[1], "wipe")) {
- if (cc->iv_gen_ops && cc->iv_gen_ops->wipe) {
- ret = cc->iv_gen_ops->wipe(cc);
- if (ret)
- return ret;
- }
+ if (argc == 2 && !strcasecmp(argv[1], "wipe"))
return crypt_wipe_key(cc);
- }
}
error:
@@ -3094,7 +3173,7 @@ static void crypt_io_hints(struct dm_target *ti, struct queue_limits *limits)
static struct target_type crypt_target = {
.name = "crypt",
- .version = {1, 18, 1},
+ .version = {1, 19, 0},
.module = THIS_MODULE,
.ctr = crypt_ctr,
.dtr = crypt_dtr,
diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c
index a9bc518156f2..2900fbde89b3 100644
--- a/drivers/md/dm-flakey.c
+++ b/drivers/md/dm-flakey.c
@@ -461,15 +461,14 @@ static int flakey_prepare_ioctl(struct dm_target *ti, struct block_device **bdev
#ifdef CONFIG_BLK_DEV_ZONED
static int flakey_report_zones(struct dm_target *ti, sector_t sector,
- struct blk_zone *zones, unsigned int *nr_zones,
- gfp_t gfp_mask)
+ struct blk_zone *zones, unsigned int *nr_zones)
{
struct flakey_c *fc = ti->private;
int ret;
/* Do report and remap it */
ret = blkdev_report_zones(fc->dev->bdev, flakey_map_sector(ti, sector),
- zones, nr_zones, gfp_mask);
+ zones, nr_zones);
if (ret != 0)
return ret;
diff --git a/drivers/md/dm-init.c b/drivers/md/dm-init.c
index 352e803f566e..b869316d3722 100644
--- a/drivers/md/dm-init.c
+++ b/drivers/md/dm-init.c
@@ -25,7 +25,7 @@ static char *create;
* Format: dm-mod.create=<name>,<uuid>,<minor>,<flags>,<table>[,<table>+][;<name>,<uuid>,<minor>,<flags>,<table>[,<table>+]+]
* Table format: <start_sector> <num_sectors> <target_type> <target_args>
*
- * See Documentation/device-mapper/dm-init.txt for dm-mod.create="..." format
+ * See Documentation/admin-guide/device-mapper/dm-init.rst for dm-mod.create="..." format
* details.
*/
@@ -140,8 +140,8 @@ static char __init *dm_parse_table_entry(struct dm_device *dev, char *str)
return ERR_PTR(-EINVAL);
}
/* target_args */
- dev->target_args_array[n] = kstrndup(field[3], GFP_KERNEL,
- DM_MAX_STR_SIZE);
+ dev->target_args_array[n] = kstrndup(field[3], DM_MAX_STR_SIZE,
+ GFP_KERNEL);
if (!dev->target_args_array[n])
return ERR_PTR(-ENOMEM);
@@ -272,10 +272,10 @@ static int __init dm_init_init(void)
return 0;
if (strlen(create) >= DM_MAX_STR_SIZE) {
- DMERR("Argument is too big. Limit is %d\n", DM_MAX_STR_SIZE);
+ DMERR("Argument is too big. Limit is %d", DM_MAX_STR_SIZE);
return -EINVAL;
}
- str = kstrndup(create, GFP_KERNEL, DM_MAX_STR_SIZE);
+ str = kstrndup(create, DM_MAX_STR_SIZE, GFP_KERNEL);
if (!str)
return -ENOMEM;
@@ -283,7 +283,7 @@ static int __init dm_init_init(void)
if (r)
goto out;
- DMINFO("waiting for all devices to be available before creating mapped devices\n");
+ DMINFO("waiting for all devices to be available before creating mapped devices");
wait_for_device_probe();
list_for_each_entry(dev, &devices, list) {
diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c
index 44e76cda087a..b1b0de402dfc 100644
--- a/drivers/md/dm-integrity.c
+++ b/drivers/md/dm-integrity.c
@@ -476,6 +476,9 @@ static int sync_rw_sb(struct dm_integrity_c *ic, int op, int op_flags)
io_loc.sector = ic->start;
io_loc.count = SB_SECTORS;
+ if (op == REQ_OP_WRITE)
+ sb_set_version(ic);
+
return dm_io(&io_req, 1, &io_loc, NULL);
}
@@ -2317,7 +2320,6 @@ static void recalc_write_super(struct dm_integrity_c *ic)
if (dm_integrity_failed(ic))
return;
- sb_set_version(ic);
r = sync_rw_sb(ic, REQ_OP_WRITE, 0);
if (unlikely(r))
dm_integrity_io_error(ic, "writing superblock", r);
@@ -3358,7 +3360,7 @@ static int create_journal(struct dm_integrity_c *ic, char **error)
goto bad;
}
- crypt_iv = kmalloc(ivsize, GFP_KERNEL);
+ crypt_iv = kzalloc(ivsize, GFP_KERNEL);
if (!crypt_iv) {
*error = "Could not allocate iv";
r = -ENOMEM;
@@ -3387,7 +3389,6 @@ static int create_journal(struct dm_integrity_c *ic, char **error)
sg_set_buf(&sg[i], va, PAGE_SIZE);
}
sg_set_buf(&sg[i], &ic->commit_ids, sizeof ic->commit_ids);
- memset(crypt_iv, 0x00, ivsize);
skcipher_request_set_crypt(req, sg, sg,
PAGE_SIZE * ic->journal_pages + sizeof ic->commit_ids, crypt_iv);
diff --git a/drivers/md/dm-kcopyd.c b/drivers/md/dm-kcopyd.c
index 671c24332802..df2011de7be2 100644
--- a/drivers/md/dm-kcopyd.c
+++ b/drivers/md/dm-kcopyd.c
@@ -28,10 +28,27 @@
#include "dm-core.h"
-#define SUB_JOB_SIZE 128
#define SPLIT_COUNT 8
#define MIN_JOBS 8
-#define RESERVE_PAGES (DIV_ROUND_UP(SUB_JOB_SIZE << SECTOR_SHIFT, PAGE_SIZE))
+
+#define DEFAULT_SUB_JOB_SIZE_KB 512
+#define MAX_SUB_JOB_SIZE_KB 1024
+
+static unsigned kcopyd_subjob_size_kb = DEFAULT_SUB_JOB_SIZE_KB;
+
+module_param(kcopyd_subjob_size_kb, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(kcopyd_subjob_size_kb, "Sub-job size for dm-kcopyd clients");
+
+static unsigned dm_get_kcopyd_subjob_size(void)
+{
+ unsigned sub_job_size_kb;
+
+ sub_job_size_kb = __dm_get_module_param(&kcopyd_subjob_size_kb,
+ DEFAULT_SUB_JOB_SIZE_KB,
+ MAX_SUB_JOB_SIZE_KB);
+
+ return sub_job_size_kb << 1;
+}
/*-----------------------------------------------------------------
* Each kcopyd client has its own little pool of preallocated
@@ -41,6 +58,7 @@ struct dm_kcopyd_client {
struct page_list *pages;
unsigned nr_reserved_pages;
unsigned nr_free_pages;
+ unsigned sub_job_size;
struct dm_io_client *io_client;
@@ -693,8 +711,8 @@ static void segment_complete(int read_err, unsigned long write_err,
progress = job->progress;
count = job->source.count - progress;
if (count) {
- if (count > SUB_JOB_SIZE)
- count = SUB_JOB_SIZE;
+ if (count > kc->sub_job_size)
+ count = kc->sub_job_size;
job->progress += count;
}
@@ -821,7 +839,7 @@ void dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from,
job->master_job = job;
job->write_offset = 0;
- if (job->source.count <= SUB_JOB_SIZE)
+ if (job->source.count <= kc->sub_job_size)
dispatch_job(job);
else {
job->progress = 0;
@@ -888,6 +906,7 @@ int kcopyd_cancel(struct kcopyd_job *job, int block)
struct dm_kcopyd_client *dm_kcopyd_client_create(struct dm_kcopyd_throttle *throttle)
{
int r;
+ unsigned reserve_pages;
struct dm_kcopyd_client *kc;
kc = kzalloc(sizeof(*kc), GFP_KERNEL);
@@ -912,9 +931,12 @@ struct dm_kcopyd_client *dm_kcopyd_client_create(struct dm_kcopyd_throttle *thro
goto bad_workqueue;
}
+ kc->sub_job_size = dm_get_kcopyd_subjob_size();
+ reserve_pages = DIV_ROUND_UP(kc->sub_job_size << SECTOR_SHIFT, PAGE_SIZE);
+
kc->pages = NULL;
kc->nr_reserved_pages = kc->nr_free_pages = 0;
- r = client_reserve_pages(kc, RESERVE_PAGES);
+ r = client_reserve_pages(kc, reserve_pages);
if (r)
goto bad_client_pages;
diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c
index ad980a38fb1e..ecefe6703736 100644
--- a/drivers/md/dm-linear.c
+++ b/drivers/md/dm-linear.c
@@ -137,15 +137,14 @@ static int linear_prepare_ioctl(struct dm_target *ti, struct block_device **bdev
#ifdef CONFIG_BLK_DEV_ZONED
static int linear_report_zones(struct dm_target *ti, sector_t sector,
- struct blk_zone *zones, unsigned int *nr_zones,
- gfp_t gfp_mask)
+ struct blk_zone *zones, unsigned int *nr_zones)
{
struct linear_c *lc = (struct linear_c *) ti->private;
int ret;
/* Do report and remap it */
ret = blkdev_report_zones(lc->dev->bdev, linear_map_sector(ti, sector),
- zones, nr_zones, gfp_mask);
+ zones, nr_zones);
if (ret != 0)
return ret;
diff --git a/drivers/md/dm-log-writes.c b/drivers/md/dm-log-writes.c
index 9ea2b0291f20..99721c76225d 100644
--- a/drivers/md/dm-log-writes.c
+++ b/drivers/md/dm-log-writes.c
@@ -40,7 +40,7 @@
*
* Would result in the log looking like this:
*
- * c,a,flush,fuad,b,<other writes>,<next flush>
+ * c,a,b,flush,fuad,<other writes>,<next flush>
*
* This is meant to help expose problems where file systems do not properly wait
* on data being written before invoking a FLUSH. FUA bypasses cache so once it
@@ -60,6 +60,7 @@
#define WRITE_LOG_VERSION 1ULL
#define WRITE_LOG_MAGIC 0x6a736677736872ULL
+#define WRITE_LOG_SUPER_SECTOR 0
/*
* The disk format for this is braindead simple.
@@ -115,6 +116,7 @@ struct log_writes_c {
struct list_head logging_blocks;
wait_queue_head_t wait;
struct task_struct *log_kthread;
+ struct completion super_done;
};
struct pending_block {
@@ -180,6 +182,14 @@ static void log_end_io(struct bio *bio)
bio_put(bio);
}
+static void log_end_super(struct bio *bio)
+{
+ struct log_writes_c *lc = bio->bi_private;
+
+ complete(&lc->super_done);
+ log_end_io(bio);
+}
+
/*
* Meant to be called if there is an error, it will free all the pages
* associated with the block.
@@ -215,7 +225,8 @@ static int write_metadata(struct log_writes_c *lc, void *entry,
bio->bi_iter.bi_size = 0;
bio->bi_iter.bi_sector = sector;
bio_set_dev(bio, lc->logdev->bdev);
- bio->bi_end_io = log_end_io;
+ bio->bi_end_io = (sector == WRITE_LOG_SUPER_SECTOR) ?
+ log_end_super : log_end_io;
bio->bi_private = lc;
bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
@@ -418,11 +429,18 @@ static int log_super(struct log_writes_c *lc)
super.nr_entries = cpu_to_le64(lc->logged_entries);
super.sectorsize = cpu_to_le32(lc->sectorsize);
- if (write_metadata(lc, &super, sizeof(super), NULL, 0, 0)) {
+ if (write_metadata(lc, &super, sizeof(super), NULL, 0,
+ WRITE_LOG_SUPER_SECTOR)) {
DMERR("Couldn't write super");
return -1;
}
+ /*
+ * Super sector should be writen in-order, otherwise the
+ * nr_entries could be rewritten incorrectly by an old bio.
+ */
+ wait_for_completion_io(&lc->super_done);
+
return 0;
}
@@ -531,6 +549,7 @@ static int log_writes_ctr(struct dm_target *ti, unsigned int argc, char **argv)
INIT_LIST_HEAD(&lc->unflushed_blocks);
INIT_LIST_HEAD(&lc->logging_blocks);
init_waitqueue_head(&lc->wait);
+ init_completion(&lc->super_done);
atomic_set(&lc->io_blocks, 0);
atomic_set(&lc->pending_blocks, 0);
@@ -680,7 +699,7 @@ static int log_writes_map(struct dm_target *ti, struct bio *bio)
if (discard_bio)
alloc_size = sizeof(struct pending_block);
else
- alloc_size = sizeof(struct pending_block) + sizeof(struct bio_vec) * bio_segments(bio);
+ alloc_size = struct_size(block, vecs, bio_segments(bio));
block = kzalloc(alloc_size, GFP_NOIO);
if (!block) {
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c
index 9fdef6897316..8a60a4a070ac 100644
--- a/drivers/md/dm-raid.c
+++ b/drivers/md/dm-raid.c
@@ -3558,7 +3558,7 @@ static void raid_status(struct dm_target *ti, status_type_t type,
* v1.5.0+:
*
* Sync action:
- * See Documentation/device-mapper/dm-raid.txt for
+ * See Documentation/admin-guide/device-mapper/dm-raid.rst for
* information on each of these states.
*/
DMEMIT(" %s", sync_action);
diff --git a/drivers/md/dm-rq.c b/drivers/md/dm-rq.c
index 5f7063f05ae0..c9e44ac1f9a6 100644
--- a/drivers/md/dm-rq.c
+++ b/drivers/md/dm-rq.c
@@ -115,7 +115,7 @@ static void end_clone_bio(struct bio *clone)
/*
* Update the original request.
- * Do not use blk_end_request() here, because it may complete
+ * Do not use blk_mq_end_request() here, because it may complete
* the original request before the clone, and break the ordering.
*/
if (is_last)
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 3107f2b1988b..f150f5c5492b 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -1,6 +1,4 @@
/*
- * dm-snapshot.c
- *
* Copyright (C) 2001-2002 Sistina Software (UK) Limited.
*
* This file is released under the GPL.
@@ -134,7 +132,10 @@ struct dm_snapshot {
* - I/O error while merging
* => stop merging; set merge_failed; process I/O normally.
*/
- int merge_failed;
+ bool merge_failed:1;
+
+ bool discard_zeroes_cow:1;
+ bool discard_passdown_origin:1;
/*
* Incoming bios that overlap with chunks being merged must wait
@@ -1173,12 +1174,64 @@ static void stop_merge(struct dm_snapshot *s)
clear_bit(SHUTDOWN_MERGE, &s->state_bits);
}
+static int parse_snapshot_features(struct dm_arg_set *as, struct dm_snapshot *s,
+ struct dm_target *ti)
+{
+ int r;
+ unsigned argc;
+ const char *arg_name;
+
+ static const struct dm_arg _args[] = {
+ {0, 2, "Invalid number of feature arguments"},
+ };
+
+ /*
+ * No feature arguments supplied.
+ */
+ if (!as->argc)
+ return 0;
+
+ r = dm_read_arg_group(_args, as, &argc, &ti->error);
+ if (r)
+ return -EINVAL;
+
+ while (argc && !r) {
+ arg_name = dm_shift_arg(as);
+ argc--;
+
+ if (!strcasecmp(arg_name, "discard_zeroes_cow"))
+ s->discard_zeroes_cow = true;
+
+ else if (!strcasecmp(arg_name, "discard_passdown_origin"))
+ s->discard_passdown_origin = true;
+
+ else {
+ ti->error = "Unrecognised feature requested";
+ r = -EINVAL;
+ break;
+ }
+ }
+
+ if (!s->discard_zeroes_cow && s->discard_passdown_origin) {
+ /*
+ * TODO: really these are disjoint.. but ti->num_discard_bios
+ * and dm_bio_get_target_bio_nr() require rigid constraints.
+ */
+ ti->error = "discard_passdown_origin feature depends on discard_zeroes_cow";
+ r = -EINVAL;
+ }
+
+ return r;
+}
+
/*
- * Construct a snapshot mapping: <origin_dev> <COW-dev> <p|po|n> <chunk-size>
+ * Construct a snapshot mapping:
+ * <origin_dev> <COW-dev> <p|po|n> <chunk-size> [<# feature args> [<arg>]*]
*/
static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{
struct dm_snapshot *s;
+ struct dm_arg_set as;
int i;
int r = -EINVAL;
char *origin_path, *cow_path;
@@ -1186,8 +1239,8 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
unsigned args_used, num_flush_bios = 1;
fmode_t origin_mode = FMODE_READ;
- if (argc != 4) {
- ti->error = "requires exactly 4 arguments";
+ if (argc < 4) {
+ ti->error = "requires 4 or more arguments";
r = -EINVAL;
goto bad;
}
@@ -1204,6 +1257,13 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
goto bad;
}
+ as.argc = argc;
+ as.argv = argv;
+ dm_consume_args(&as, 4);
+ r = parse_snapshot_features(&as, s, ti);
+ if (r)
+ goto bad_features;
+
origin_path = argv[0];
argv++;
argc--;
@@ -1289,6 +1349,8 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
ti->private = s;
ti->num_flush_bios = num_flush_bios;
+ if (s->discard_zeroes_cow)
+ ti->num_discard_bios = (s->discard_passdown_origin ? 2 : 1);
ti->per_io_data_size = sizeof(struct dm_snap_tracked_chunk);
/* Add snapshot to the list of snapshots for this origin */
@@ -1336,29 +1398,22 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
bad_read_metadata:
unregister_snapshot(s);
-
bad_load_and_register:
mempool_exit(&s->pending_pool);
-
bad_pending_pool:
dm_kcopyd_client_destroy(s->kcopyd_client);
-
bad_kcopyd:
dm_exception_table_exit(&s->pending, pending_cache);
dm_exception_table_exit(&s->complete, exception_cache);
-
bad_hash_tables:
dm_exception_store_destroy(s->store);
-
bad_store:
dm_put_device(ti, s->cow);
-
bad_cow:
dm_put_device(ti, s->origin);
-
bad_origin:
+bad_features:
kfree(s);
-
bad:
return r;
}
@@ -1806,6 +1861,37 @@ static void remap_exception(struct dm_snapshot *s, struct dm_exception *e,
(bio->bi_iter.bi_sector & s->store->chunk_mask);
}
+static void zero_callback(int read_err, unsigned long write_err, void *context)
+{
+ struct bio *bio = context;
+ struct dm_snapshot *s = bio->bi_private;
+
+ up(&s->cow_count);
+ bio->bi_status = write_err ? BLK_STS_IOERR : 0;
+ bio_endio(bio);
+}
+
+static void zero_exception(struct dm_snapshot *s, struct dm_exception *e,
+ struct bio *bio, chunk_t chunk)
+{
+ struct dm_io_region dest;
+
+ dest.bdev = s->cow->bdev;
+ dest.sector = bio->bi_iter.bi_sector;
+ dest.count = s->store->chunk_size;
+
+ down(&s->cow_count);
+ WARN_ON_ONCE(bio->bi_private);
+ bio->bi_private = s;
+ dm_kcopyd_zero(s->kcopyd_client, 1, &dest, 0, zero_callback, bio);
+}
+
+static bool io_overlaps_chunk(struct dm_snapshot *s, struct bio *bio)
+{
+ return bio->bi_iter.bi_size ==
+ (s->store->chunk_size << SECTOR_SHIFT);
+}
+
static int snapshot_map(struct dm_target *ti, struct bio *bio)
{
struct dm_exception *e;
@@ -1839,10 +1925,43 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio)
goto out_unlock;
}
+ if (unlikely(bio_op(bio) == REQ_OP_DISCARD)) {
+ if (s->discard_passdown_origin && dm_bio_get_target_bio_nr(bio)) {
+ /*
+ * passdown discard to origin (without triggering
+ * snapshot exceptions via do_origin; doing so would
+ * defeat the goal of freeing space in origin that is
+ * implied by the "discard_passdown_origin" feature)
+ */
+ bio_set_dev(bio, s->origin->bdev);
+ track_chunk(s, bio, chunk);
+ goto out_unlock;
+ }
+ /* discard to snapshot (target_bio_nr == 0) zeroes exceptions */
+ }
+
/* If the block is already remapped - use that, else remap it */
e = dm_lookup_exception(&s->complete, chunk);
if (e) {
remap_exception(s, e, bio, chunk);
+ if (unlikely(bio_op(bio) == REQ_OP_DISCARD) &&
+ io_overlaps_chunk(s, bio)) {
+ dm_exception_table_unlock(&lock);
+ up_read(&s->lock);
+ zero_exception(s, e, bio, chunk);
+ r = DM_MAPIO_SUBMITTED; /* discard is not issued */
+ goto out;
+ }
+ goto out_unlock;
+ }
+
+ if (unlikely(bio_op(bio) == REQ_OP_DISCARD)) {
+ /*
+ * If no exception exists, complete discard immediately
+ * otherwise it'll trigger copy-out.
+ */
+ bio_endio(bio);
+ r = DM_MAPIO_SUBMITTED;
goto out_unlock;
}
@@ -1890,9 +2009,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio)
r = DM_MAPIO_SUBMITTED;
- if (!pe->started &&
- bio->bi_iter.bi_size ==
- (s->store->chunk_size << SECTOR_SHIFT)) {
+ if (!pe->started && io_overlaps_chunk(s, bio)) {
pe->started = 1;
dm_exception_table_unlock(&lock);
@@ -1955,6 +2072,12 @@ static int snapshot_merge_map(struct dm_target *ti, struct bio *bio)
return DM_MAPIO_REMAPPED;
}
+ if (unlikely(bio_op(bio) == REQ_OP_DISCARD)) {
+ /* Once merging, discards no longer effect change */
+ bio_endio(bio);
+ return DM_MAPIO_SUBMITTED;
+ }
+
chunk = sector_to_chunk(s->store, bio->bi_iter.bi_sector);
down_write(&s->lock);
@@ -2138,6 +2261,7 @@ static void snapshot_status(struct dm_target *ti, status_type_t type,
{
unsigned sz = 0;
struct dm_snapshot *snap = ti->private;
+ unsigned num_features;
switch (type) {
case STATUSTYPE_INFO:
@@ -2178,8 +2302,16 @@ static void snapshot_status(struct dm_target *ti, status_type_t type,
* make sense.
*/
DMEMIT("%s %s", snap->origin->name, snap->cow->name);
- snap->store->type->status(snap->store, type, result + sz,
- maxlen - sz);
+ sz += snap->store->type->status(snap->store, type, result + sz,
+ maxlen - sz);
+ num_features = snap->discard_zeroes_cow + snap->discard_passdown_origin;
+ if (num_features) {
+ DMEMIT(" %u", num_features);
+ if (snap->discard_zeroes_cow)
+ DMEMIT(" discard_zeroes_cow");
+ if (snap->discard_passdown_origin)
+ DMEMIT(" discard_passdown_origin");
+ }
break;
}
}
@@ -2198,6 +2330,26 @@ static int snapshot_iterate_devices(struct dm_target *ti,
return r;
}
+static void snapshot_io_hints(struct dm_target *ti, struct queue_limits *limits)
+{
+ struct dm_snapshot *snap = ti->private;
+
+ if (snap->discard_zeroes_cow) {
+ struct dm_snapshot *snap_src = NULL, *snap_dest = NULL;
+
+ down_read(&_origins_lock);
+
+ (void) __find_snapshots_sharing_cow(snap, &snap_src, &snap_dest, NULL);
+ if (snap_src && snap_dest)
+ snap = snap_src;
+
+ /* All discards are split on chunk_size boundary */
+ limits->discard_granularity = snap->store->chunk_size;
+ limits->max_discard_sectors = snap->store->chunk_size;
+
+ up_read(&_origins_lock);
+ }
+}
/*-----------------------------------------------------------------
* Origin methods
@@ -2522,7 +2674,7 @@ static struct target_type origin_target = {
static struct target_type snapshot_target = {
.name = "snapshot",
- .version = {1, 15, 0},
+ .version = {1, 16, 0},
.module = THIS_MODULE,
.ctr = snapshot_ctr,
.dtr = snapshot_dtr,
@@ -2532,11 +2684,12 @@ static struct target_type snapshot_target = {
.resume = snapshot_resume,
.status = snapshot_status,
.iterate_devices = snapshot_iterate_devices,
+ .io_hints = snapshot_io_hints,
};
static struct target_type merge_target = {
.name = dm_snapshot_merge_target_name,
- .version = {1, 4, 0},
+ .version = {1, 5, 0},
.module = THIS_MODULE,
.ctr = snapshot_ctr,
.dtr = snapshot_dtr,
@@ -2547,6 +2700,7 @@ static struct target_type merge_target = {
.resume = snapshot_merge_resume,
.status = snapshot_status,
.iterate_devices = snapshot_iterate_devices,
+ .io_hints = snapshot_io_hints,
};
static int __init dm_snapshot_init(void)
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 350cf0451456..caaee8032afe 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -561,7 +561,7 @@ static char **realloc_argv(unsigned *size, char **old_argv)
gfp = GFP_NOIO;
}
argv = kmalloc_array(new_size, sizeof(*argv), gfp);
- if (argv) {
+ if (argv && old_argv) {
memcpy(argv, old_argv, *size * sizeof(*argv));
*size = new_size;
}
@@ -881,7 +881,7 @@ void dm_table_set_type(struct dm_table *t, enum dm_queue_mode type)
EXPORT_SYMBOL_GPL(dm_table_set_type);
/* validate the dax capability of the target device span */
-static int device_supports_dax(struct dm_target *ti, struct dm_dev *dev,
+int device_supports_dax(struct dm_target *ti, struct dm_dev *dev,
sector_t start, sector_t len, void *data)
{
int blocksize = *(int *) data;
@@ -890,7 +890,15 @@ static int device_supports_dax(struct dm_target *ti, struct dm_dev *dev,
start, len);
}
-bool dm_table_supports_dax(struct dm_table *t, int blocksize)
+/* Check devices support synchronous DAX */
+static int device_synchronous(struct dm_target *ti, struct dm_dev *dev,
+ sector_t start, sector_t len, void *data)
+{
+ return dax_synchronous(dev->dax_dev);
+}
+
+bool dm_table_supports_dax(struct dm_table *t,
+ iterate_devices_callout_fn iterate_fn, int *blocksize)
{
struct dm_target *ti;
unsigned i;
@@ -903,8 +911,7 @@ bool dm_table_supports_dax(struct dm_table *t, int blocksize)
return false;
if (!ti->type->iterate_devices ||
- !ti->type->iterate_devices(ti, device_supports_dax,
- &blocksize))
+ !ti->type->iterate_devices(ti, iterate_fn, blocksize))
return false;
}
@@ -940,6 +947,7 @@ static int dm_table_determine_type(struct dm_table *t)
struct dm_target *tgt;
struct list_head *devices = dm_table_get_devices(t);
enum dm_queue_mode live_md_type = dm_get_md_type(t->md);
+ int page_size = PAGE_SIZE;
if (t->type != DM_TYPE_NONE) {
/* target already set the table's type */
@@ -984,7 +992,7 @@ static int dm_table_determine_type(struct dm_table *t)
verify_bio_based:
/* We must use this table as bio-based */
t->type = DM_TYPE_BIO_BASED;
- if (dm_table_supports_dax(t, PAGE_SIZE) ||
+ if (dm_table_supports_dax(t, device_supports_dax, &page_size) ||
(list_empty(devices) && live_md_type == DM_TYPE_DAX_BIO_BASED)) {
t->type = DM_TYPE_DAX_BIO_BASED;
} else {
@@ -1883,6 +1891,7 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
struct queue_limits *limits)
{
bool wc = false, fua = false;
+ int page_size = PAGE_SIZE;
/*
* Copy table's limits to the DM device's request_queue
@@ -1910,8 +1919,11 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
}
blk_queue_write_cache(q, wc, fua);
- if (dm_table_supports_dax(t, PAGE_SIZE))
+ if (dm_table_supports_dax(t, device_supports_dax, &page_size)) {
blk_queue_flag_set(QUEUE_FLAG_DAX, q);
+ if (dm_table_supports_dax(t, device_synchronous, NULL))
+ set_dax_synchronous(t->md->dax_dev);
+ }
else
blk_queue_flag_clear(QUEUE_FLAG_DAX, q);
diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c
index 7f0840601737..4c68a7b93d5e 100644
--- a/drivers/md/dm-thin-metadata.c
+++ b/drivers/md/dm-thin-metadata.c
@@ -2046,16 +2046,19 @@ int dm_pool_register_metadata_threshold(struct dm_pool_metadata *pmd,
int dm_pool_metadata_set_needs_check(struct dm_pool_metadata *pmd)
{
- int r;
+ int r = -EINVAL;
struct dm_block *sblock;
struct thin_disk_superblock *disk_super;
pmd_write_lock(pmd);
+ if (pmd->fail_io)
+ goto out;
+
pmd->flags |= THIN_METADATA_NEEDS_CHECK_FLAG;
r = superblock_lock(pmd, &sblock);
if (r) {
- DMERR("couldn't read superblock");
+ DMERR("couldn't lock superblock");
goto out;
}
diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c
index 720d06531aa3..ea24ff0612e3 100644
--- a/drivers/md/dm-verity-target.c
+++ b/drivers/md/dm-verity-target.c
@@ -235,8 +235,8 @@ static int verity_handle_err(struct dm_verity *v, enum verity_block_type type,
BUG();
}
- DMERR("%s: %s block %llu is corrupted", v->data_dev->name, type_str,
- block);
+ DMERR_LIMIT("%s: %s block %llu is corrupted", v->data_dev->name,
+ type_str, block);
if (v->corrupted_errs == DM_VERITY_MAX_CORRUPTED_ERRS)
DMERR("%s: reached maximum errors", v->data_dev->name);
diff --git a/drivers/md/dm-zoned-metadata.c b/drivers/md/dm-zoned-metadata.c
index d8334cd45d7c..8545dcee9fd0 100644
--- a/drivers/md/dm-zoned-metadata.c
+++ b/drivers/md/dm-zoned-metadata.c
@@ -8,6 +8,7 @@
#include <linux/module.h>
#include <linux/crc32.h>
+#include <linux/sched/mm.h>
#define DM_MSG_PREFIX "zoned metadata"
@@ -1162,8 +1163,7 @@ static int dmz_init_zones(struct dmz_metadata *zmd)
while (sector < dev->capacity) {
/* Get zone information */
nr_blkz = DMZ_REPORT_NR_ZONES;
- ret = blkdev_report_zones(dev->bdev, sector, blkz,
- &nr_blkz, GFP_KERNEL);
+ ret = blkdev_report_zones(dev->bdev, sector, blkz, &nr_blkz);
if (ret) {
dmz_dev_err(dev, "Report zones failed %d", ret);
goto out;
@@ -1201,12 +1201,20 @@ out:
static int dmz_update_zone(struct dmz_metadata *zmd, struct dm_zone *zone)
{
unsigned int nr_blkz = 1;
+ unsigned int noio_flag;
struct blk_zone blkz;
int ret;
- /* Get zone information from disk */
+ /*
+ * Get zone information from disk. Since blkdev_report_zones() uses
+ * GFP_KERNEL by default for memory allocations, set the per-task
+ * PF_MEMALLOC_NOIO flag so that all allocations are done as if
+ * GFP_NOIO was specified.
+ */
+ noio_flag = memalloc_noio_save();
ret = blkdev_report_zones(zmd->dev->bdev, dmz_start_sect(zmd, zone),
- &blkz, &nr_blkz, GFP_NOIO);
+ &blkz, &nr_blkz);
+ memalloc_noio_restore(noio_flag);
if (!nr_blkz)
ret = -EIO;
if (ret) {
@@ -1594,30 +1602,6 @@ struct dm_zone *dmz_get_zone_for_reclaim(struct dmz_metadata *zmd)
}
/*
- * Activate a zone (increment its reference count).
- */
-void dmz_activate_zone(struct dm_zone *zone)
-{
- set_bit(DMZ_ACTIVE, &zone->flags);
- atomic_inc(&zone->refcount);
-}
-
-/*
- * Deactivate a zone. This decrement the zone reference counter
- * and clears the active state of the zone once the count reaches 0,
- * indicating that all BIOs to the zone have completed. Returns
- * true if the zone was deactivated.
- */
-void dmz_deactivate_zone(struct dm_zone *zone)
-{
- if (atomic_dec_and_test(&zone->refcount)) {
- WARN_ON(!test_bit(DMZ_ACTIVE, &zone->flags));
- clear_bit_unlock(DMZ_ACTIVE, &zone->flags);
- smp_mb__after_atomic();
- }
-}
-
-/*
* Get the zone mapping a chunk, if the chunk is mapped already.
* If no mapping exist and the operation is WRITE, a zone is
* allocated and used to map the chunk.
diff --git a/drivers/md/dm-zoned.h b/drivers/md/dm-zoned.h
index 12419f0bfe78..ed8de49c9a08 100644
--- a/drivers/md/dm-zoned.h
+++ b/drivers/md/dm-zoned.h
@@ -115,7 +115,6 @@ enum {
DMZ_BUF,
/* Zone internal state */
- DMZ_ACTIVE,
DMZ_RECLAIM,
DMZ_SEQ_WRITE_ERR,
};
@@ -128,7 +127,6 @@ enum {
#define dmz_is_empty(z) ((z)->wp_block == 0)
#define dmz_is_offline(z) test_bit(DMZ_OFFLINE, &(z)->flags)
#define dmz_is_readonly(z) test_bit(DMZ_READ_ONLY, &(z)->flags)
-#define dmz_is_active(z) test_bit(DMZ_ACTIVE, &(z)->flags)
#define dmz_in_reclaim(z) test_bit(DMZ_RECLAIM, &(z)->flags)
#define dmz_seq_write_err(z) test_bit(DMZ_SEQ_WRITE_ERR, &(z)->flags)
@@ -188,8 +186,30 @@ void dmz_unmap_zone(struct dmz_metadata *zmd, struct dm_zone *zone);
unsigned int dmz_nr_rnd_zones(struct dmz_metadata *zmd);
unsigned int dmz_nr_unmap_rnd_zones(struct dmz_metadata *zmd);
-void dmz_activate_zone(struct dm_zone *zone);
-void dmz_deactivate_zone(struct dm_zone *zone);
+/*
+ * Activate a zone (increment its reference count).
+ */
+static inline void dmz_activate_zone(struct dm_zone *zone)
+{
+ atomic_inc(&zone->refcount);
+}
+
+/*
+ * Deactivate a zone. This decrement the zone reference counter
+ * indicating that all BIOs to the zone have completed when the count is 0.
+ */
+static inline void dmz_deactivate_zone(struct dm_zone *zone)
+{
+ atomic_dec(&zone->refcount);
+}
+
+/*
+ * Test if a zone is active, that is, has a refcount > 0.
+ */
+static inline bool dmz_is_active(struct dm_zone *zone)
+{
+ return atomic_read(&zone->refcount);
+}
int dmz_lock_zone_reclaim(struct dm_zone *zone);
void dmz_unlock_zone_reclaim(struct dm_zone *zone);
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 5475081dcbd6..d0beef033e2f 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -441,8 +441,7 @@ static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
}
static int dm_blk_report_zones(struct gendisk *disk, sector_t sector,
- struct blk_zone *zones, unsigned int *nr_zones,
- gfp_t gfp_mask)
+ struct blk_zone *zones, unsigned int *nr_zones)
{
#ifdef CONFIG_BLK_DEV_ZONED
struct mapped_device *md = disk->private_data;
@@ -480,8 +479,7 @@ static int dm_blk_report_zones(struct gendisk *disk, sector_t sector,
* So there is no need to loop here trying to fill the entire array
* of zones.
*/
- ret = tgt->type->report_zones(tgt, sector, zones,
- nr_zones, gfp_mask);
+ ret = tgt->type->report_zones(tgt, sector, zones, nr_zones);
out:
dm_put_live_table(md, srcu_idx);
@@ -1119,7 +1117,7 @@ static bool dm_dax_supported(struct dax_device *dax_dev, struct block_device *bd
if (!map)
return false;
- ret = dm_table_supports_dax(map, blocksize);
+ ret = dm_table_supports_dax(map, device_supports_dax, &blocksize);
dm_put_live_table(md, srcu_idx);
@@ -1991,7 +1989,8 @@ static struct mapped_device *alloc_dev(int minor)
sprintf(md->disk->disk_name, "dm-%d", minor);
if (IS_ENABLED(CONFIG_DAX_DRIVER)) {
- md->dax_dev = alloc_dax(md, md->disk->disk_name, &dm_dax_ops);
+ md->dax_dev = alloc_dax(md, md->disk->disk_name,
+ &dm_dax_ops, 0);
if (!md->dax_dev)
goto bad;
}
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
index 17e3db54404c..0475673337f3 100644
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -72,7 +72,10 @@ bool dm_table_bio_based(struct dm_table *t);
bool dm_table_request_based(struct dm_table *t);
void dm_table_free_md_mempools(struct dm_table *t);
struct dm_md_mempools *dm_table_get_md_mempools(struct dm_table *t);
-bool dm_table_supports_dax(struct dm_table *t, int blocksize);
+bool dm_table_supports_dax(struct dm_table *t, iterate_devices_callout_fn fn,
+ int *blocksize);
+int device_supports_dax(struct dm_target *ti, struct dm_dev *dev,
+ sector_t start, sector_t len, void *data);
void dm_lock_md_type(struct mapped_device *md);
void dm_unlock_md_type(struct mapped_device *md);
diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c
index c01d41198f5e..b092c7b5282f 100644
--- a/drivers/md/md-bitmap.c
+++ b/drivers/md/md-bitmap.c
@@ -1790,6 +1790,8 @@ void md_bitmap_destroy(struct mddev *mddev)
return;
md_bitmap_wait_behind_writes(mddev);
+ mempool_destroy(mddev->wb_info_pool);
+ mddev->wb_info_pool = NULL;
mutex_lock(&mddev->bitmap_info.mutex);
spin_lock(&mddev->lock);
@@ -1900,10 +1902,14 @@ int md_bitmap_load(struct mddev *mddev)
sector_t start = 0;
sector_t sector = 0;
struct bitmap *bitmap = mddev->bitmap;
+ struct md_rdev *rdev;
if (!bitmap)
goto out;
+ rdev_for_each(rdev, mddev)
+ mddev_create_wb_pool(mddev, rdev, true);
+
if (mddev_is_clustered(mddev))
md_cluster_ops->load_bitmaps(mddev, mddev->bitmap_info.nodes);
@@ -2462,12 +2468,26 @@ static ssize_t
backlog_store(struct mddev *mddev, const char *buf, size_t len)
{
unsigned long backlog;
+ unsigned long old_mwb = mddev->bitmap_info.max_write_behind;
int rv = kstrtoul(buf, 10, &backlog);
if (rv)
return rv;
if (backlog > COUNTER_MAX)
return -EINVAL;
mddev->bitmap_info.max_write_behind = backlog;
+ if (!backlog && mddev->wb_info_pool) {
+ /* wb_info_pool is not needed if backlog is zero */
+ mempool_destroy(mddev->wb_info_pool);
+ mddev->wb_info_pool = NULL;
+ } else if (backlog && !mddev->wb_info_pool) {
+ /* wb_info_pool is needed since backlog is not zero */
+ struct md_rdev *rdev;
+
+ rdev_for_each(rdev, mddev)
+ mddev_create_wb_pool(mddev, rdev, false);
+ }
+ if (old_mwb != backlog)
+ md_bitmap_update_sb(mddev->bitmap);
return len;
}
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 04f4f131f9d6..24638ccedce4 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -37,6 +37,7 @@
*/
+#include <linux/sched/mm.h>
#include <linux/sched/signal.h>
#include <linux/kthread.h>
#include <linux/blkdev.h>
@@ -124,6 +125,77 @@ static inline int speed_max(struct mddev *mddev)
mddev->sync_speed_max : sysctl_speed_limit_max;
}
+static int rdev_init_wb(struct md_rdev *rdev)
+{
+ if (rdev->bdev->bd_queue->nr_hw_queues == 1)
+ return 0;
+
+ spin_lock_init(&rdev->wb_list_lock);
+ INIT_LIST_HEAD(&rdev->wb_list);
+ init_waitqueue_head(&rdev->wb_io_wait);
+ set_bit(WBCollisionCheck, &rdev->flags);
+
+ return 1;
+}
+
+/*
+ * Create wb_info_pool if rdev is the first multi-queue device flaged
+ * with writemostly, also write-behind mode is enabled.
+ */
+void mddev_create_wb_pool(struct mddev *mddev, struct md_rdev *rdev,
+ bool is_suspend)
+{
+ if (mddev->bitmap_info.max_write_behind == 0)
+ return;
+
+ if (!test_bit(WriteMostly, &rdev->flags) || !rdev_init_wb(rdev))
+ return;
+
+ if (mddev->wb_info_pool == NULL) {
+ unsigned int noio_flag;
+
+ if (!is_suspend)
+ mddev_suspend(mddev);
+ noio_flag = memalloc_noio_save();
+ mddev->wb_info_pool = mempool_create_kmalloc_pool(NR_WB_INFOS,
+ sizeof(struct wb_info));
+ memalloc_noio_restore(noio_flag);
+ if (!mddev->wb_info_pool)
+ pr_err("can't alloc memory pool for writemostly\n");
+ if (!is_suspend)
+ mddev_resume(mddev);
+ }
+}
+EXPORT_SYMBOL_GPL(mddev_create_wb_pool);
+
+/*
+ * destroy wb_info_pool if rdev is the last device flaged with WBCollisionCheck.
+ */
+static void mddev_destroy_wb_pool(struct mddev *mddev, struct md_rdev *rdev)
+{
+ if (!test_and_clear_bit(WBCollisionCheck, &rdev->flags))
+ return;
+
+ if (mddev->wb_info_pool) {
+ struct md_rdev *temp;
+ int num = 0;
+
+ /*
+ * Check if other rdevs need wb_info_pool.
+ */
+ rdev_for_each(temp, mddev)
+ if (temp != rdev &&
+ test_bit(WBCollisionCheck, &temp->flags))
+ num++;
+ if (!num) {
+ mddev_suspend(rdev->mddev);
+ mempool_destroy(mddev->wb_info_pool);
+ mddev->wb_info_pool = NULL;
+ mddev_resume(rdev->mddev);
+ }
+ }
+}
+
static struct ctl_table_header *raid_table_header;
static struct ctl_table raid_table[] = {
@@ -2210,6 +2282,9 @@ static int bind_rdev_to_array(struct md_rdev *rdev, struct mddev *mddev)
rdev->mddev = mddev;
pr_debug("md: bind<%s>\n", b);
+ if (mddev->raid_disks)
+ mddev_create_wb_pool(mddev, rdev, false);
+
if ((err = kobject_add(&rdev->kobj, &mddev->kobj, "dev-%s", b)))
goto fail;
@@ -2246,6 +2321,7 @@ static void unbind_rdev_from_array(struct md_rdev *rdev)
bd_unlink_disk_holder(rdev->bdev, rdev->mddev->gendisk);
list_del_rcu(&rdev->same_set);
pr_debug("md: unbind<%s>\n", bdevname(rdev->bdev,b));
+ mddev_destroy_wb_pool(rdev->mddev, rdev);
rdev->mddev = NULL;
sysfs_remove_link(&rdev->kobj, "block");
sysfs_put(rdev->sysfs_state);
@@ -2758,8 +2834,10 @@ state_store(struct md_rdev *rdev, const char *buf, size_t len)
}
} else if (cmd_match(buf, "writemostly")) {
set_bit(WriteMostly, &rdev->flags);
+ mddev_create_wb_pool(rdev->mddev, rdev, false);
err = 0;
} else if (cmd_match(buf, "-writemostly")) {
+ mddev_destroy_wb_pool(rdev->mddev, rdev);
clear_bit(WriteMostly, &rdev->flags);
err = 0;
} else if (cmd_match(buf, "blocked")) {
@@ -3356,7 +3434,7 @@ rdev_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
if (!entry->show)
return -EIO;
if (!rdev->mddev)
- return -EBUSY;
+ return -ENODEV;
return entry->show(rdev, page);
}
@@ -5238,7 +5316,8 @@ int mddev_init_writes_pending(struct mddev *mddev)
{
if (mddev->writes_pending.percpu_count_ptr)
return 0;
- if (percpu_ref_init(&mddev->writes_pending, no_op, 0, GFP_KERNEL) < 0)
+ if (percpu_ref_init(&mddev->writes_pending, no_op,
+ PERCPU_REF_ALLOW_REINIT, GFP_KERNEL) < 0)
return -ENOMEM;
/* We want to start with the refcount at zero */
percpu_ref_put(&mddev->writes_pending);
@@ -5588,15 +5667,28 @@ int md_run(struct mddev *mddev)
mddev->bitmap = bitmap;
}
- if (err) {
- mddev_detach(mddev);
- if (mddev->private)
- pers->free(mddev, mddev->private);
- mddev->private = NULL;
- module_put(pers->owner);
- md_bitmap_destroy(mddev);
- goto abort;
+ if (err)
+ goto bitmap_abort;
+
+ if (mddev->bitmap_info.max_write_behind > 0) {
+ bool creat_pool = false;
+
+ rdev_for_each(rdev, mddev) {
+ if (test_bit(WriteMostly, &rdev->flags) &&
+ rdev_init_wb(rdev))
+ creat_pool = true;
+ }
+ if (creat_pool && mddev->wb_info_pool == NULL) {
+ mddev->wb_info_pool =
+ mempool_create_kmalloc_pool(NR_WB_INFOS,
+ sizeof(struct wb_info));
+ if (!mddev->wb_info_pool) {
+ err = -ENOMEM;
+ goto bitmap_abort;
+ }
+ }
}
+
if (mddev->queue) {
bool nonrot = true;
@@ -5639,8 +5731,7 @@ int md_run(struct mddev *mddev)
spin_unlock(&mddev->lock);
rdev_for_each(rdev, mddev)
if (rdev->raid_disk >= 0)
- if (sysfs_link_rdev(mddev, rdev))
- /* failure here is OK */;
+ sysfs_link_rdev(mddev, rdev); /* failure here is OK */
if (mddev->degraded && !mddev->ro)
/* This ensures that recovering status is reported immediately
@@ -5658,6 +5749,13 @@ int md_run(struct mddev *mddev)
sysfs_notify(&mddev->kobj, NULL, "degraded");
return 0;
+bitmap_abort:
+ mddev_detach(mddev);
+ if (mddev->private)
+ pers->free(mddev, mddev->private);
+ mddev->private = NULL;
+ module_put(pers->owner);
+ md_bitmap_destroy(mddev);
abort:
bioset_exit(&mddev->bio_set);
bioset_exit(&mddev->sync_set);
@@ -5826,6 +5924,8 @@ static void __md_stop_writes(struct mddev *mddev)
mddev->in_sync = 1;
md_update_sb(mddev, 1);
}
+ mempool_destroy(mddev->wb_info_pool);
+ mddev->wb_info_pool = NULL;
}
void md_stop_writes(struct mddev *mddev)
@@ -7607,9 +7707,9 @@ static void status_unused(struct seq_file *seq)
static int status_resync(struct seq_file *seq, struct mddev *mddev)
{
sector_t max_sectors, resync, res;
- unsigned long dt, db;
- sector_t rt;
- int scale;
+ unsigned long dt, db = 0;
+ sector_t rt, curr_mark_cnt, resync_mark_cnt;
+ int scale, recovery_active;
unsigned int per_milli;
if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ||
@@ -7698,22 +7798,30 @@ static int status_resync(struct seq_file *seq, struct mddev *mddev)
* db: blocks written from mark until now
* rt: remaining time
*
- * rt is a sector_t, so could be 32bit or 64bit.
- * So we divide before multiply in case it is 32bit and close
- * to the limit.
- * We scale the divisor (db) by 32 to avoid losing precision
- * near the end of resync when the number of remaining sectors
- * is close to 'db'.
- * We then divide rt by 32 after multiplying by db to compensate.
- * The '+1' avoids division by zero if db is very small.
+ * rt is a sector_t, which is always 64bit now. We are keeping
+ * the original algorithm, but it is not really necessary.
+ *
+ * Original algorithm:
+ * So we divide before multiply in case it is 32bit and close
+ * to the limit.
+ * We scale the divisor (db) by 32 to avoid losing precision
+ * near the end of resync when the number of remaining sectors
+ * is close to 'db'.
+ * We then divide rt by 32 after multiplying by db to compensate.
+ * The '+1' avoids division by zero if db is very small.
*/
dt = ((jiffies - mddev->resync_mark) / HZ);
if (!dt) dt++;
- db = (mddev->curr_mark_cnt - atomic_read(&mddev->recovery_active))
- - mddev->resync_mark_cnt;
+
+ curr_mark_cnt = mddev->curr_mark_cnt;
+ recovery_active = atomic_read(&mddev->recovery_active);
+ resync_mark_cnt = mddev->resync_mark_cnt;
+
+ if (curr_mark_cnt >= (recovery_active + resync_mark_cnt))
+ db = curr_mark_cnt - (recovery_active + resync_mark_cnt);
rt = max_sectors - resync; /* number of remaining sectors */
- sector_div(rt, db/32+1);
+ rt = div64_u64(rt, db/32+1);
rt *= dt;
rt >>= 5;
@@ -8190,8 +8298,7 @@ void md_do_sync(struct md_thread *thread)
{
struct mddev *mddev = thread->mddev;
struct mddev *mddev2;
- unsigned int currspeed = 0,
- window;
+ unsigned int currspeed = 0, window;
sector_t max_sectors,j, io_sectors, recovery_done;
unsigned long mark[SYNC_MARKS];
unsigned long update_time;
@@ -8248,7 +8355,7 @@ void md_do_sync(struct md_thread *thread)
* 0 == not engaged in resync at all
* 2 == checking that there is no conflict with another sync
* 1 == like 2, but have yielded to allow conflicting resync to
- * commense
+ * commence
* other == active in resync - this many blocks
*
* Before starting a resync we must have set curr_resync to
@@ -8379,7 +8486,7 @@ void md_do_sync(struct md_thread *thread)
/*
* Tune reconstruction:
*/
- window = 32*(PAGE_SIZE/512);
+ window = 32 * (PAGE_SIZE / 512);
pr_debug("md: using %dk window, over a total of %lluk.\n",
window/2, (unsigned long long)max_sectors/2);
@@ -9192,7 +9299,6 @@ static void check_sb_changes(struct mddev *mddev, struct md_rdev *rdev)
* perform resync with the new activated disk */
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
md_wakeup_thread(mddev->thread);
-
}
/* device faulty
* We just want to do the minimum to mark the disk
diff --git a/drivers/md/md.h b/drivers/md/md.h
index 7c930c091193..10f98200e2f8 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -109,6 +109,14 @@ struct md_rdev {
* for reporting to userspace and storing
* in superblock.
*/
+
+ /*
+ * The members for check collision of write behind IOs.
+ */
+ struct list_head wb_list;
+ spinlock_t wb_list_lock;
+ wait_queue_head_t wb_io_wait;
+
struct work_struct del_work; /* used for delayed sysfs removal */
struct kernfs_node *sysfs_state; /* handle for 'state'
@@ -193,6 +201,10 @@ enum flag_bits {
* it didn't fail, so don't use FailFast
* any more for metadata
*/
+ WBCollisionCheck, /*
+ * multiqueue device should check if there
+ * is collision between write behind bios.
+ */
};
static inline int is_badblock(struct md_rdev *rdev, sector_t s, int sectors,
@@ -245,6 +257,14 @@ enum mddev_sb_flags {
MD_SB_NEED_REWRITE, /* metadata write needs to be repeated */
};
+#define NR_WB_INFOS 8
+/* record current range of write behind IOs */
+struct wb_info {
+ sector_t lo;
+ sector_t hi;
+ struct list_head list;
+};
+
struct mddev {
void *private;
struct md_personality *pers;
@@ -461,6 +481,7 @@ struct mddev {
*/
struct work_struct flush_work;
struct work_struct event_work; /* used by dm to report failure event */
+ mempool_t *wb_info_pool;
void (*sync_super)(struct mddev *mddev, struct md_rdev *rdev);
struct md_cluster_info *cluster_info;
unsigned int good_device_nr; /* good device num within cluster raid */
@@ -709,6 +730,8 @@ extern struct bio *bio_alloc_mddev(gfp_t gfp_mask, int nr_iovecs,
extern void md_reload_sb(struct mddev *mddev, int raid_disk);
extern void md_update_sb(struct mddev *mddev, int force);
extern void md_kick_rdev_from_array(struct md_rdev * rdev);
+extern void mddev_create_wb_pool(struct mddev *mddev, struct md_rdev *rdev,
+ bool is_suspend);
struct md_rdev *md_find_rdev_nr_rcu(struct mddev *mddev, int nr);
struct md_rdev *md_find_rdev_rcu(struct mddev *mddev, dev_t dev);
diff --git a/drivers/md/raid1-10.c b/drivers/md/raid1-10.c
index 400001b815db..54db34163968 100644
--- a/drivers/md/raid1-10.c
+++ b/drivers/md/raid1-10.c
@@ -3,12 +3,42 @@
#define RESYNC_BLOCK_SIZE (64*1024)
#define RESYNC_PAGES ((RESYNC_BLOCK_SIZE + PAGE_SIZE-1) / PAGE_SIZE)
+/*
+ * Number of guaranteed raid bios in case of extreme VM load:
+ */
+#define NR_RAID_BIOS 256
+
+/* when we get a read error on a read-only array, we redirect to another
+ * device without failing the first device, or trying to over-write to
+ * correct the read error. To keep track of bad blocks on a per-bio
+ * level, we store IO_BLOCKED in the appropriate 'bios' pointer
+ */
+#define IO_BLOCKED ((struct bio *)1)
+/* When we successfully write to a known bad-block, we need to remove the
+ * bad-block marking which must be done from process context. So we record
+ * the success by setting devs[n].bio to IO_MADE_GOOD
+ */
+#define IO_MADE_GOOD ((struct bio *)2)
+
+#define BIO_SPECIAL(bio) ((unsigned long)bio <= 2)
+
+/* When there are this many requests queue to be written by
+ * the raid thread, we become 'congested' to provide back-pressure
+ * for writeback.
+ */
+static int max_queued_requests = 1024;
+
/* for managing resync I/O pages */
struct resync_pages {
void *raid_bio;
struct page *pages[RESYNC_PAGES];
};
+static void rbio_pool_free(void *rbio, void *data)
+{
+ kfree(rbio);
+}
+
static inline int resync_alloc_pages(struct resync_pages *rp,
gfp_t gfp_flags)
{
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 2aa36e570e04..34e26834ad28 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -42,31 +42,6 @@
(1L << MD_HAS_PPL) | \
(1L << MD_HAS_MULTIPLE_PPLS))
-/*
- * Number of guaranteed r1bios in case of extreme VM load:
- */
-#define NR_RAID1_BIOS 256
-
-/* when we get a read error on a read-only array, we redirect to another
- * device without failing the first device, or trying to over-write to
- * correct the read error. To keep track of bad blocks on a per-bio
- * level, we store IO_BLOCKED in the appropriate 'bios' pointer
- */
-#define IO_BLOCKED ((struct bio *)1)
-/* When we successfully write to a known bad-block, we need to remove the
- * bad-block marking which must be done from process context. So we record
- * the success by setting devs[n].bio to IO_MADE_GOOD
- */
-#define IO_MADE_GOOD ((struct bio *)2)
-
-#define BIO_SPECIAL(bio) ((unsigned long)bio <= 2)
-
-/* When there are this many requests queue to be written by
- * the raid1 thread, we become 'congested' to provide back-pressure
- * for writeback.
- */
-static int max_queued_requests = 1024;
-
static void allow_barrier(struct r1conf *conf, sector_t sector_nr);
static void lower_barrier(struct r1conf *conf, sector_t sector_nr);
@@ -75,6 +50,57 @@ static void lower_barrier(struct r1conf *conf, sector_t sector_nr);
#include "raid1-10.c"
+static int check_and_add_wb(struct md_rdev *rdev, sector_t lo, sector_t hi)
+{
+ struct wb_info *wi, *temp_wi;
+ unsigned long flags;
+ int ret = 0;
+ struct mddev *mddev = rdev->mddev;
+
+ wi = mempool_alloc(mddev->wb_info_pool, GFP_NOIO);
+
+ spin_lock_irqsave(&rdev->wb_list_lock, flags);
+ list_for_each_entry(temp_wi, &rdev->wb_list, list) {
+ /* collision happened */
+ if (hi > temp_wi->lo && lo < temp_wi->hi) {
+ ret = -EBUSY;
+ break;
+ }
+ }
+
+ if (!ret) {
+ wi->lo = lo;
+ wi->hi = hi;
+ list_add(&wi->list, &rdev->wb_list);
+ } else
+ mempool_free(wi, mddev->wb_info_pool);
+ spin_unlock_irqrestore(&rdev->wb_list_lock, flags);
+
+ return ret;
+}
+
+static void remove_wb(struct md_rdev *rdev, sector_t lo, sector_t hi)
+{
+ struct wb_info *wi;
+ unsigned long flags;
+ int found = 0;
+ struct mddev *mddev = rdev->mddev;
+
+ spin_lock_irqsave(&rdev->wb_list_lock, flags);
+ list_for_each_entry(wi, &rdev->wb_list, list)
+ if (hi == wi->hi && lo == wi->lo) {
+ list_del(&wi->list);
+ mempool_free(wi, mddev->wb_info_pool);
+ found = 1;
+ break;
+ }
+
+ if (!found)
+ WARN(1, "The write behind IO is not recorded\n");
+ spin_unlock_irqrestore(&rdev->wb_list_lock, flags);
+ wake_up(&rdev->wb_io_wait);
+}
+
/*
* for resync bio, r1bio pointer can be retrieved from the per-bio
* 'struct resync_pages'.
@@ -93,11 +119,6 @@ static void * r1bio_pool_alloc(gfp_t gfp_flags, void *data)
return kzalloc(size, gfp_flags);
}
-static void r1bio_pool_free(void *r1_bio, void *data)
-{
- kfree(r1_bio);
-}
-
#define RESYNC_DEPTH 32
#define RESYNC_SECTORS (RESYNC_BLOCK_SIZE >> 9)
#define RESYNC_WINDOW (RESYNC_BLOCK_SIZE * RESYNC_DEPTH)
@@ -173,7 +194,7 @@ out_free_bio:
kfree(rps);
out_free_r1bio:
- r1bio_pool_free(r1_bio, data);
+ rbio_pool_free(r1_bio, data);
return NULL;
}
@@ -193,7 +214,7 @@ static void r1buf_pool_free(void *__r1_bio, void *data)
/* resync pages array stored in the 1st bio's .bi_private */
kfree(rp);
- r1bio_pool_free(r1bio, data);
+ rbio_pool_free(r1bio, data);
}
static void put_all_bios(struct r1conf *conf, struct r1bio *r1_bio)
@@ -476,6 +497,12 @@ static void raid1_end_write_request(struct bio *bio)
}
if (behind) {
+ if (test_bit(WBCollisionCheck, &rdev->flags)) {
+ sector_t lo = r1_bio->sector;
+ sector_t hi = r1_bio->sector + r1_bio->sectors;
+
+ remove_wb(rdev, lo, hi);
+ }
if (test_bit(WriteMostly, &rdev->flags))
atomic_dec(&r1_bio->behind_remaining);
@@ -1449,7 +1476,6 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
if (!r1_bio->bios[i])
continue;
-
if (first_clone) {
/* do behind I/O ?
* Not if there are too many, or cannot
@@ -1474,7 +1500,16 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
mbio = bio_clone_fast(bio, GFP_NOIO, &mddev->bio_set);
if (r1_bio->behind_master_bio) {
- if (test_bit(WriteMostly, &conf->mirrors[i].rdev->flags))
+ struct md_rdev *rdev = conf->mirrors[i].rdev;
+
+ if (test_bit(WBCollisionCheck, &rdev->flags)) {
+ sector_t lo = r1_bio->sector;
+ sector_t hi = r1_bio->sector + r1_bio->sectors;
+
+ wait_event(rdev->wb_io_wait,
+ check_and_add_wb(rdev, lo, hi) == 0);
+ }
+ if (test_bit(WriteMostly, &rdev->flags))
atomic_inc(&r1_bio->behind_remaining);
}
@@ -1729,9 +1764,8 @@ static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev)
first = last = rdev->saved_raid_disk;
for (mirror = first; mirror <= last; mirror++) {
- p = conf->mirrors+mirror;
+ p = conf->mirrors + mirror;
if (!p->rdev) {
-
if (mddev->gendisk)
disk_stack_limits(mddev->gendisk, rdev->bdev,
rdev->data_offset << 9);
@@ -2888,7 +2922,6 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
if (read_targets == 1)
bio->bi_opf &= ~MD_FAILFAST;
generic_make_request(bio);
-
}
return nr_sectors;
}
@@ -2947,8 +2980,8 @@ static struct r1conf *setup_conf(struct mddev *mddev)
if (!conf->poolinfo)
goto abort;
conf->poolinfo->raid_disks = mddev->raid_disks * 2;
- err = mempool_init(&conf->r1bio_pool, NR_RAID1_BIOS, r1bio_pool_alloc,
- r1bio_pool_free, conf->poolinfo);
+ err = mempool_init(&conf->r1bio_pool, NR_RAID_BIOS, r1bio_pool_alloc,
+ rbio_pool_free, conf->poolinfo);
if (err)
goto abort;
@@ -3089,7 +3122,7 @@ static int raid1_run(struct mddev *mddev)
}
mddev->degraded = 0;
- for (i=0; i < conf->raid_disks; i++)
+ for (i = 0; i < conf->raid_disks; i++)
if (conf->mirrors[i].rdev == NULL ||
!test_bit(In_sync, &conf->mirrors[i].rdev->flags) ||
test_bit(Faulty, &conf->mirrors[i].rdev->flags))
@@ -3124,7 +3157,7 @@ static int raid1_run(struct mddev *mddev)
mddev->queue);
}
- ret = md_integrity_register(mddev);
+ ret = md_integrity_register(mddev);
if (ret) {
md_unregister_thread(&mddev->thread);
raid1_free(mddev, conf);
@@ -3232,8 +3265,8 @@ static int raid1_reshape(struct mddev *mddev)
newpoolinfo->mddev = mddev;
newpoolinfo->raid_disks = raid_disks * 2;
- ret = mempool_init(&newpool, NR_RAID1_BIOS, r1bio_pool_alloc,
- r1bio_pool_free, newpoolinfo);
+ ret = mempool_init(&newpool, NR_RAID_BIOS, r1bio_pool_alloc,
+ rbio_pool_free, newpoolinfo);
if (ret) {
kfree(newpoolinfo);
return ret;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index aea11476fee6..8a1354a08a1a 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -64,31 +64,6 @@
* [B A] [D C] [B A] [E C D]
*/
-/*
- * Number of guaranteed r10bios in case of extreme VM load:
- */
-#define NR_RAID10_BIOS 256
-
-/* when we get a read error on a read-only array, we redirect to another
- * device without failing the first device, or trying to over-write to
- * correct the read error. To keep track of bad blocks on a per-bio
- * level, we store IO_BLOCKED in the appropriate 'bios' pointer
- */
-#define IO_BLOCKED ((struct bio *)1)
-/* When we successfully write to a known bad-block, we need to remove the
- * bad-block marking which must be done from process context. So we record
- * the success by setting devs[n].bio to IO_MADE_GOOD
- */
-#define IO_MADE_GOOD ((struct bio *)2)
-
-#define BIO_SPECIAL(bio) ((unsigned long)bio <= 2)
-
-/* When there are this many requests queued to be written by
- * the raid10 thread, we become 'congested' to provide back-pressure
- * for writeback.
- */
-static int max_queued_requests = 1024;
-
static void allow_barrier(struct r10conf *conf);
static void lower_barrier(struct r10conf *conf);
static int _enough(struct r10conf *conf, int previous, int ignore);
@@ -123,11 +98,6 @@ static void * r10bio_pool_alloc(gfp_t gfp_flags, void *data)
return kzalloc(size, gfp_flags);
}
-static void r10bio_pool_free(void *r10_bio, void *data)
-{
- kfree(r10_bio);
-}
-
#define RESYNC_SECTORS (RESYNC_BLOCK_SIZE >> 9)
/* amount of memory to reserve for resync requests */
#define RESYNC_WINDOW (1024*1024)
@@ -233,7 +203,7 @@ out_free_bio:
}
kfree(rps);
out_free_r10bio:
- r10bio_pool_free(r10_bio, conf);
+ rbio_pool_free(r10_bio, conf);
return NULL;
}
@@ -261,7 +231,7 @@ static void r10buf_pool_free(void *__r10_bio, void *data)
/* resync pages array stored in the 1st bio's .bi_private */
kfree(rp);
- r10bio_pool_free(r10bio, conf);
+ rbio_pool_free(r10bio, conf);
}
static void put_all_bios(struct r10conf *conf, struct r10bio *r10_bio)
@@ -737,15 +707,19 @@ static struct md_rdev *read_balance(struct r10conf *conf,
int sectors = r10_bio->sectors;
int best_good_sectors;
sector_t new_distance, best_dist;
- struct md_rdev *best_rdev, *rdev = NULL;
+ struct md_rdev *best_dist_rdev, *best_pending_rdev, *rdev = NULL;
int do_balance;
- int best_slot;
+ int best_dist_slot, best_pending_slot;
+ bool has_nonrot_disk = false;
+ unsigned int min_pending;
struct geom *geo = &conf->geo;
raid10_find_phys(conf, r10_bio);
rcu_read_lock();
- best_slot = -1;
- best_rdev = NULL;
+ best_dist_slot = -1;
+ min_pending = UINT_MAX;
+ best_dist_rdev = NULL;
+ best_pending_rdev = NULL;
best_dist = MaxSector;
best_good_sectors = 0;
do_balance = 1;
@@ -767,6 +741,8 @@ static struct md_rdev *read_balance(struct r10conf *conf,
sector_t first_bad;
int bad_sectors;
sector_t dev_sector;
+ unsigned int pending;
+ bool nonrot;
if (r10_bio->devs[slot].bio == IO_BLOCKED)
continue;
@@ -803,8 +779,8 @@ static struct md_rdev *read_balance(struct r10conf *conf,
first_bad - dev_sector;
if (good_sectors > best_good_sectors) {
best_good_sectors = good_sectors;
- best_slot = slot;
- best_rdev = rdev;
+ best_dist_slot = slot;
+ best_dist_rdev = rdev;
}
if (!do_balance)
/* Must read from here */
@@ -817,14 +793,23 @@ static struct md_rdev *read_balance(struct r10conf *conf,
if (!do_balance)
break;
- if (best_slot >= 0)
+ nonrot = blk_queue_nonrot(bdev_get_queue(rdev->bdev));
+ has_nonrot_disk |= nonrot;
+ pending = atomic_read(&rdev->nr_pending);
+ if (min_pending > pending && nonrot) {
+ min_pending = pending;
+ best_pending_slot = slot;
+ best_pending_rdev = rdev;
+ }
+
+ if (best_dist_slot >= 0)
/* At least 2 disks to choose from so failfast is OK */
set_bit(R10BIO_FailFast, &r10_bio->state);
/* This optimisation is debatable, and completely destroys
* sequential read speed for 'far copies' arrays. So only
* keep it for 'near' arrays, and review those later.
*/
- if (geo->near_copies > 1 && !atomic_read(&rdev->nr_pending))
+ if (geo->near_copies > 1 && !pending)
new_distance = 0;
/* for far > 1 always use the lowest address */
@@ -833,15 +818,21 @@ static struct md_rdev *read_balance(struct r10conf *conf,
else
new_distance = abs(r10_bio->devs[slot].addr -
conf->mirrors[disk].head_position);
+
if (new_distance < best_dist) {
best_dist = new_distance;
- best_slot = slot;
- best_rdev = rdev;
+ best_dist_slot = slot;
+ best_dist_rdev = rdev;
}
}
if (slot >= conf->copies) {
- slot = best_slot;
- rdev = best_rdev;
+ if (has_nonrot_disk) {
+ slot = best_pending_slot;
+ rdev = best_pending_rdev;
+ } else {
+ slot = best_dist_slot;
+ rdev = best_dist_rdev;
+ }
}
if (slot >= 0) {
@@ -3675,8 +3666,8 @@ static struct r10conf *setup_conf(struct mddev *mddev)
conf->geo = geo;
conf->copies = copies;
- err = mempool_init(&conf->r10bio_pool, NR_RAID10_BIOS, r10bio_pool_alloc,
- r10bio_pool_free, conf);
+ err = mempool_init(&conf->r10bio_pool, NR_RAID_BIOS, r10bio_pool_alloc,
+ rbio_pool_free, conf);
if (err)
goto out;
@@ -4780,8 +4771,7 @@ static int handle_reshape_read_error(struct mddev *mddev,
int idx = 0;
struct page **pages;
- r10b = kmalloc(sizeof(*r10b) +
- sizeof(struct r10dev) * conf->copies, GFP_NOIO);
+ r10b = kmalloc(struct_size(r10b, devs, conf->copies), GFP_NOIO);
if (!r10b) {
set_bit(MD_RECOVERY_INTR, &mddev->recovery);
return -ENOMEM;
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index b83bce2beb66..3de4e13bde98 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -5251,7 +5251,6 @@ static int raid5_read_one_chunk(struct mddev *mddev, struct bio *raid_bio)
rcu_read_unlock();
raid_bio->bi_next = (void*)rdev;
bio_set_dev(align_bi, rdev->bdev);
- bio_clear_flag(align_bi, BIO_SEG_VALID);
if (is_badblock(rdev, align_bi->bi_iter.bi_sector,
bio_sectors(align_bi),
@@ -7672,7 +7671,7 @@ abort:
static int raid5_add_disk(struct mddev *mddev, struct md_rdev *rdev)
{
struct r5conf *conf = mddev->private;
- int err = -EEXIST;
+ int ret, err = -EEXIST;
int disk;
struct disk_info *p;
int first = 0;
@@ -7687,7 +7686,14 @@ static int raid5_add_disk(struct mddev *mddev, struct md_rdev *rdev)
* The array is in readonly mode if journal is missing, so no
* write requests running. We should be safe
*/
- log_init(conf, rdev, false);
+ ret = log_init(conf, rdev, false);
+ if (ret)
+ return ret;
+
+ ret = r5l_start(conf->log);
+ if (ret)
+ return ret;
+
return 0;
}
if (mddev->recovery_disabled == conf->recovery_disabled)
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 092e7509af9b..21cd9c02960b 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -89,40 +89,7 @@ config MEDIA_CEC_SUPPORT
source "drivers/media/cec/Kconfig"
-#
-# Media controller
-# Selectable only for webcam/grabbers, as other drivers don't use it
-#
-
-config MEDIA_CONTROLLER
- bool "Media Controller API"
- depends on MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT
- help
- Enable the media controller API used to query media devices internal
- topology and configure it dynamically.
-
- This API is mostly used by camera interfaces in embedded platforms.
-
-config MEDIA_CONTROLLER_DVB
- bool "Enable Media controller for DVB (EXPERIMENTAL)"
- depends on MEDIA_CONTROLLER && DVB_CORE
- help
- Enable the media controller API support for DVB.
-
- This is currently experimental.
-
-config MEDIA_CONTROLLER_REQUEST_API
- bool "Enable Media controller Request API (EXPERIMENTAL)"
- depends on MEDIA_CONTROLLER && STAGING_MEDIA
- default n
- help
- DO NOT ENABLE THIS OPTION UNLESS YOU KNOW WHAT YOU'RE DOING.
-
- This option enables the Request API for the Media controller and V4L2
- interfaces. It is currently needed by a few stateless codec drivers.
-
- There is currently no intention to provide API or ABI stability for
- this new API as of yet.
+source "drivers/media/mc/Kconfig"
#
# Video4Linux support
@@ -164,7 +131,6 @@ config DVB_MMAP
depends on DVB_CORE
depends on VIDEO_V4L2=y || VIDEO_V4L2=DVB_CORE
select VIDEOBUF2_VMALLOC
- default n
help
This option enables DVB experimental memory-mapped API, which
reduces the number of context switches to read DVB buffers, as
@@ -190,7 +156,6 @@ config DVB_NET
config TTPCI_EEPROM
tristate
depends on I2C
- default n
source "drivers/media/dvb-core/Kconfig"
diff --git a/drivers/media/Makefile b/drivers/media/Makefile
index 4a330d0e5e40..f215f0a89f9e 100644
--- a/drivers/media/Makefile
+++ b/drivers/media/Makefile
@@ -3,15 +3,6 @@
# Makefile for the kernel multimedia device drivers.
#
-media-objs := media-device.o media-devnode.o media-entity.o \
- media-request.o
-
-ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
- ifeq ($(CONFIG_USB),y)
- media-objs += media-dev-allocator.o
- endif
-endif
-
#
# I2C drivers should come before other drivers, otherwise they'll fail
# when compiled as builtin drivers
@@ -20,10 +11,10 @@ obj-y += i2c/ tuners/
obj-$(CONFIG_DVB_CORE) += dvb-frontends/
#
-# Now, let's link-in the media core
+# Now, let's link-in the media controller core
#
ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
- obj-$(CONFIG_MEDIA_SUPPORT) += media.o
+ obj-$(CONFIG_MEDIA_SUPPORT) += mc/
endif
obj-$(CONFIG_VIDEO_DEV) += v4l2-core/
diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c
index f1261cc2b6fa..451c61bde4d4 100644
--- a/drivers/media/cec/cec-adap.c
+++ b/drivers/media/cec/cec-adap.c
@@ -16,7 +16,10 @@
#include <linux/string.h>
#include <linux/types.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_device.h>
#include <drm/drm_edid.h>
+#include <drm/drm_file.h>
#include "cec-priv.h"
@@ -75,6 +78,16 @@ u16 cec_get_edid_phys_addr(const u8 *edid, unsigned int size,
}
EXPORT_SYMBOL_GPL(cec_get_edid_phys_addr);
+void cec_fill_conn_info_from_drm(struct cec_connector_info *conn_info,
+ const struct drm_connector *connector)
+{
+ memset(conn_info, 0, sizeof(*conn_info));
+ conn_info->type = CEC_CONNECTOR_TYPE_DRM;
+ conn_info->drm.card_no = connector->dev->primary->index;
+ conn_info->drm.connector_id = connector->base.id;
+}
+EXPORT_SYMBOL_GPL(cec_fill_conn_info_from_drm);
+
/*
* Queue a new event for this filehandle. If ts == 0, then set it
* to the current time.
@@ -720,6 +733,7 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg,
struct cec_fh *fh, bool block)
{
struct cec_data *data;
+ bool is_raw = msg_is_raw(msg);
msg->rx_ts = 0;
msg->tx_ts = 0;
@@ -735,15 +749,10 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg,
/* Make sure the timeout isn't 0. */
msg->timeout = 1000;
}
- if (msg->timeout)
- msg->flags &= CEC_MSG_FL_REPLY_TO_FOLLOWERS;
- else
- msg->flags = 0;
+ msg->flags &= CEC_MSG_FL_REPLY_TO_FOLLOWERS | CEC_MSG_FL_RAW;
- if (msg->len > 1 && msg->msg[1] == CEC_MSG_CDC_MESSAGE) {
- msg->msg[2] = adap->phys_addr >> 8;
- msg->msg[3] = adap->phys_addr & 0xff;
- }
+ if (!msg->timeout)
+ msg->flags &= ~CEC_MSG_FL_REPLY_TO_FOLLOWERS;
/* Sanity checks */
if (msg->len == 0 || msg->len > CEC_MAX_MSG_SIZE) {
@@ -765,44 +774,80 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg,
dprintk(1, "%s: can't reply to poll msg\n", __func__);
return -EINVAL;
}
- if (msg->len == 1) {
- if (cec_msg_destination(msg) == 0xf) {
- dprintk(1, "%s: invalid poll message\n", __func__);
+
+ if (is_raw) {
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+ } else {
+ /* A CDC-Only device can only send CDC messages */
+ if ((adap->log_addrs.flags & CEC_LOG_ADDRS_FL_CDC_ONLY) &&
+ (msg->len == 1 || msg->msg[1] != CEC_MSG_CDC_MESSAGE)) {
+ dprintk(1, "%s: not a CDC message\n", __func__);
return -EINVAL;
}
- if (cec_has_log_addr(adap, cec_msg_destination(msg))) {
- /*
- * If the destination is a logical address our adapter
- * has already claimed, then just NACK this.
- * It depends on the hardware what it will do with a
- * POLL to itself (some OK this), so it is just as
- * easy to handle it here so the behavior will be
- * consistent.
- */
- msg->tx_ts = ktime_get_ns();
- msg->tx_status = CEC_TX_STATUS_NACK |
- CEC_TX_STATUS_MAX_RETRIES;
- msg->tx_nack_cnt = 1;
- msg->sequence = ++adap->sequence;
- if (!msg->sequence)
+
+ if (msg->len >= 4 && msg->msg[1] == CEC_MSG_CDC_MESSAGE) {
+ msg->msg[2] = adap->phys_addr >> 8;
+ msg->msg[3] = adap->phys_addr & 0xff;
+ }
+
+ if (msg->len == 1) {
+ if (cec_msg_destination(msg) == 0xf) {
+ dprintk(1, "%s: invalid poll message\n",
+ __func__);
+ return -EINVAL;
+ }
+ if (cec_has_log_addr(adap, cec_msg_destination(msg))) {
+ /*
+ * If the destination is a logical address our
+ * adapter has already claimed, then just NACK
+ * this. It depends on the hardware what it will
+ * do with a POLL to itself (some OK this), so
+ * it is just as easy to handle it here so the
+ * behavior will be consistent.
+ */
+ msg->tx_ts = ktime_get_ns();
+ msg->tx_status = CEC_TX_STATUS_NACK |
+ CEC_TX_STATUS_MAX_RETRIES;
+ msg->tx_nack_cnt = 1;
msg->sequence = ++adap->sequence;
- return 0;
+ if (!msg->sequence)
+ msg->sequence = ++adap->sequence;
+ return 0;
+ }
+ }
+ if (msg->len > 1 && !cec_msg_is_broadcast(msg) &&
+ cec_has_log_addr(adap, cec_msg_destination(msg))) {
+ dprintk(1, "%s: destination is the adapter itself\n",
+ __func__);
+ return -EINVAL;
+ }
+ if (msg->len > 1 && adap->is_configured &&
+ !cec_has_log_addr(adap, cec_msg_initiator(msg))) {
+ dprintk(1, "%s: initiator has unknown logical address %d\n",
+ __func__, cec_msg_initiator(msg));
+ return -EINVAL;
+ }
+ /*
+ * Special case: allow Ping and IMAGE/TEXT_VIEW_ON to be
+ * transmitted to a TV, even if the adapter is unconfigured.
+ * This makes it possible to detect or wake up displays that
+ * pull down the HPD when in standby.
+ */
+ if (!adap->is_configured && !adap->is_configuring &&
+ (msg->len > 2 ||
+ cec_msg_destination(msg) != CEC_LOG_ADDR_TV ||
+ (msg->len == 2 && msg->msg[1] != CEC_MSG_IMAGE_VIEW_ON &&
+ msg->msg[1] != CEC_MSG_TEXT_VIEW_ON))) {
+ dprintk(1, "%s: adapter is unconfigured\n", __func__);
+ return -ENONET;
}
}
- if (msg->len > 1 && !cec_msg_is_broadcast(msg) &&
- cec_has_log_addr(adap, cec_msg_destination(msg))) {
- dprintk(1, "%s: destination is the adapter itself\n", __func__);
- return -EINVAL;
- }
- if (msg->len > 1 && adap->is_configured &&
- !cec_has_log_addr(adap, cec_msg_initiator(msg))) {
- dprintk(1, "%s: initiator has unknown logical address %d\n",
- __func__, cec_msg_initiator(msg));
- return -EINVAL;
- }
+
if (!adap->is_configured && !adap->is_configuring) {
- if (adap->needs_hpd || msg->msg[0] != 0xf0) {
- dprintk(1, "%s: adapter is unconfigured\n", __func__);
+ if (adap->needs_hpd) {
+ dprintk(1, "%s: adapter is unconfigured and needs HPD\n",
+ __func__);
return -ENONET;
}
if (msg->reply) {
@@ -1566,6 +1611,22 @@ void cec_s_phys_addr_from_edid(struct cec_adapter *adap,
}
EXPORT_SYMBOL_GPL(cec_s_phys_addr_from_edid);
+void cec_s_conn_info(struct cec_adapter *adap,
+ const struct cec_connector_info *conn_info)
+{
+ if (!(adap->capabilities & CEC_CAP_CONNECTOR_INFO))
+ return;
+
+ mutex_lock(&adap->lock);
+ if (conn_info)
+ adap->conn_info = *conn_info;
+ else
+ memset(&adap->conn_info, 0, sizeof(adap->conn_info));
+ cec_post_state_event(adap);
+ mutex_unlock(&adap->lock);
+}
+EXPORT_SYMBOL_GPL(cec_s_conn_info);
+
/*
* Called from either the ioctl or a driver to set the logical addresses.
*
diff --git a/drivers/media/cec/cec-api.c b/drivers/media/cec/cec-api.c
index 156a0d76ab2a..12d676484472 100644
--- a/drivers/media/cec/cec-api.c
+++ b/drivers/media/cec/cec-api.c
@@ -198,19 +198,11 @@ static long cec_transmit(struct cec_adapter *adap, struct cec_fh *fh,
if (copy_from_user(&msg, parg, sizeof(msg)))
return -EFAULT;
- /* A CDC-Only device can only send CDC messages */
- if ((adap->log_addrs.flags & CEC_LOG_ADDRS_FL_CDC_ONLY) &&
- (msg.len == 1 || msg.msg[1] != CEC_MSG_CDC_MESSAGE))
- return -EINVAL;
-
mutex_lock(&adap->lock);
if (adap->log_addrs.num_log_addrs == 0)
err = -EPERM;
else if (adap->is_configuring)
err = -ENONET;
- else if (!adap->is_configured &&
- (adap->needs_hpd || msg.msg[0] != 0xf0))
- err = -ENONET;
else if (cec_is_busy(adap, fh))
err = -EBUSY;
else
diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c
index f5d1578e256a..9c610e1e99b8 100644
--- a/drivers/media/cec/cec-core.c
+++ b/drivers/media/cec/cec-core.c
@@ -128,13 +128,14 @@ static int __must_check cec_devnode_register(struct cec_devnode *devnode,
devnode->cdev.owner = owner;
kobject_set_name(&devnode->cdev.kobj, "cec%d", devnode->minor);
+ devnode->registered = true;
ret = cdev_device_add(&devnode->cdev, &devnode->dev);
if (ret) {
+ devnode->registered = false;
pr_err("%s: cdev_device_add failed\n", __func__);
goto clr_bit;
}
- devnode->registered = true;
return 0;
clr_bit:
@@ -256,6 +257,11 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
struct cec_adapter *adap;
int res;
+ /*
+ * Disable this capability until the connector info public API
+ * is ready.
+ */
+ caps &= ~CEC_CAP_CONNECTOR_INFO;
#ifndef CONFIG_MEDIA_CEC_RC
caps &= ~CEC_CAP_RC;
#endif
diff --git a/drivers/media/cec/cec-notifier.c b/drivers/media/cec/cec-notifier.c
index 9598c7778871..52a867bde15f 100644
--- a/drivers/media/cec/cec-notifier.c
+++ b/drivers/media/cec/cec-notifier.c
@@ -21,8 +21,9 @@ struct cec_notifier {
struct mutex lock;
struct list_head head;
struct kref kref;
- struct device *dev;
- const char *conn;
+ struct device *hdmi_dev;
+ struct cec_connector_info conn_info;
+ const char *conn_name;
struct cec_adapter *cec_adap;
void (*callback)(struct cec_adapter *adap, u16 pa);
@@ -32,14 +33,16 @@ struct cec_notifier {
static LIST_HEAD(cec_notifiers);
static DEFINE_MUTEX(cec_notifiers_lock);
-struct cec_notifier *cec_notifier_get_conn(struct device *dev, const char *conn)
+struct cec_notifier *
+cec_notifier_get_conn(struct device *hdmi_dev, const char *conn_name)
{
struct cec_notifier *n;
mutex_lock(&cec_notifiers_lock);
list_for_each_entry(n, &cec_notifiers, head) {
- if (n->dev == dev &&
- (!conn || !strcmp(n->conn, conn))) {
+ if (n->hdmi_dev == hdmi_dev &&
+ (!conn_name ||
+ (n->conn_name && !strcmp(n->conn_name, conn_name)))) {
kref_get(&n->kref);
mutex_unlock(&cec_notifiers_lock);
return n;
@@ -48,10 +51,17 @@ struct cec_notifier *cec_notifier_get_conn(struct device *dev, const char *conn)
n = kzalloc(sizeof(*n), GFP_KERNEL);
if (!n)
goto unlock;
- n->dev = dev;
- if (conn)
- n->conn = kstrdup(conn, GFP_KERNEL);
+ n->hdmi_dev = hdmi_dev;
+ if (conn_name) {
+ n->conn_name = kstrdup(conn_name, GFP_KERNEL);
+ if (!n->conn_name) {
+ kfree(n);
+ n = NULL;
+ goto unlock;
+ }
+ }
n->phys_addr = CEC_PHYS_ADDR_INVALID;
+
mutex_init(&n->lock);
kref_init(&n->kref);
list_add_tail(&n->head, &cec_notifiers);
@@ -67,7 +77,7 @@ static void cec_notifier_release(struct kref *kref)
container_of(kref, struct cec_notifier, kref);
list_del(&n->head);
- kfree(n->conn);
+ kfree(n->conn_name);
kfree(n);
}
@@ -79,6 +89,84 @@ void cec_notifier_put(struct cec_notifier *n)
}
EXPORT_SYMBOL_GPL(cec_notifier_put);
+struct cec_notifier *
+cec_notifier_conn_register(struct device *hdmi_dev, const char *conn_name,
+ const struct cec_connector_info *conn_info)
+{
+ struct cec_notifier *n = cec_notifier_get_conn(hdmi_dev, conn_name);
+
+ if (!n)
+ return n;
+
+ mutex_lock(&n->lock);
+ n->phys_addr = CEC_PHYS_ADDR_INVALID;
+ if (conn_info)
+ n->conn_info = *conn_info;
+ else
+ memset(&n->conn_info, 0, sizeof(n->conn_info));
+ if (n->cec_adap) {
+ cec_phys_addr_invalidate(n->cec_adap);
+ cec_s_conn_info(n->cec_adap, conn_info);
+ }
+ mutex_unlock(&n->lock);
+ return n;
+}
+EXPORT_SYMBOL_GPL(cec_notifier_conn_register);
+
+void cec_notifier_conn_unregister(struct cec_notifier *n)
+{
+ if (!n)
+ return;
+
+ mutex_lock(&n->lock);
+ memset(&n->conn_info, 0, sizeof(n->conn_info));
+ n->phys_addr = CEC_PHYS_ADDR_INVALID;
+ if (n->cec_adap) {
+ cec_phys_addr_invalidate(n->cec_adap);
+ cec_s_conn_info(n->cec_adap, NULL);
+ }
+ mutex_unlock(&n->lock);
+ cec_notifier_put(n);
+}
+EXPORT_SYMBOL_GPL(cec_notifier_conn_unregister);
+
+struct cec_notifier *
+cec_notifier_cec_adap_register(struct device *hdmi_dev, const char *conn_name,
+ struct cec_adapter *adap)
+{
+ struct cec_notifier *n;
+
+ if (WARN_ON(!adap))
+ return NULL;
+
+ n = cec_notifier_get_conn(hdmi_dev, conn_name);
+ if (!n)
+ return n;
+
+ mutex_lock(&n->lock);
+ n->cec_adap = adap;
+ adap->conn_info = n->conn_info;
+ adap->notifier = n;
+ cec_s_phys_addr(adap, n->phys_addr, false);
+ mutex_unlock(&n->lock);
+ return n;
+}
+EXPORT_SYMBOL_GPL(cec_notifier_cec_adap_register);
+
+void cec_notifier_cec_adap_unregister(struct cec_notifier *n)
+{
+ if (!n)
+ return;
+
+ mutex_lock(&n->lock);
+ n->cec_adap->notifier = NULL;
+ n->cec_adap = NULL;
+ n->callback = NULL;
+ mutex_unlock(&n->lock);
+ cec_notifier_put(n);
+}
+EXPORT_SYMBOL_GPL(cec_notifier_cec_adap_unregister);
+
void cec_notifier_set_phys_addr(struct cec_notifier *n, u16 pa)
{
if (n == NULL)
@@ -88,6 +176,8 @@ void cec_notifier_set_phys_addr(struct cec_notifier *n, u16 pa)
n->phys_addr = pa;
if (n->callback)
n->callback(n->cec_adap, n->phys_addr);
+ else if (n->cec_adap)
+ cec_s_phys_addr(n->cec_adap, n->phys_addr, false);
mutex_unlock(&n->lock);
}
EXPORT_SYMBOL_GPL(cec_notifier_set_phys_addr);
@@ -122,6 +212,10 @@ EXPORT_SYMBOL_GPL(cec_notifier_register);
void cec_notifier_unregister(struct cec_notifier *n)
{
+ /* Do nothing unless cec_notifier_register was called first */
+ if (!n->callback)
+ return;
+
mutex_lock(&n->lock);
n->callback = NULL;
mutex_unlock(&n->lock);
diff --git a/drivers/media/cec/cec-priv.h b/drivers/media/cec/cec-priv.h
index 804e38f849c7..7bdf855aaecd 100644
--- a/drivers/media/cec/cec-priv.h
+++ b/drivers/media/cec/cec-priv.h
@@ -20,6 +20,11 @@
/* devnode to cec_adapter */
#define to_cec_adapter(node) container_of(node, struct cec_adapter, devnode)
+static inline bool msg_is_raw(const struct cec_msg *msg)
+{
+ return msg->flags & CEC_MSG_FL_RAW;
+}
+
/* cec-core.c */
extern int cec_debug;
int cec_get_device(struct cec_devnode *devnode);
diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c
index be4f80a40214..aabb830e7468 100644
--- a/drivers/media/common/saa7146/saa7146_fops.c
+++ b/drivers/media/common/saa7146/saa7146_fops.c
@@ -608,6 +608,15 @@ int saa7146_register_device(struct video_device *vfd, struct saa7146_dev *dev,
for (i = 0; i < dev->ext_vv_data->num_stds; i++)
vfd->tvnorms |= dev->ext_vv_data->stds[i].id;
strscpy(vfd->name, name, sizeof(vfd->name));
+ vfd->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY |
+ V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+ vfd->device_caps |= dev->ext_vv_data->capabilities;
+ if (type == VFL_TYPE_GRABBER)
+ vfd->device_caps &=
+ ~(V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT);
+ else
+ vfd->device_caps &=
+ ~(V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_AUDIO);
video_set_drvdata(vfd, dev);
err = video_register_device(vfd, type, -1);
diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c
index a0f0b5eef0bd..4c399a42e874 100644
--- a/drivers/media/common/saa7146/saa7146_video.c
+++ b/drivers/media/common/saa7146/saa7146_video.c
@@ -448,25 +448,15 @@ static int video_end(struct saa7146_fh *fh, struct file *file)
static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
{
- struct video_device *vdev = video_devdata(file);
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
strscpy((char *)cap->driver, "saa7146 v4l2", sizeof(cap->driver));
strscpy((char *)cap->card, dev->ext->name, sizeof(cap->card));
sprintf((char *)cap->bus_info, "PCI:%s", pci_name(dev->pci));
- cap->device_caps =
- V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_VIDEO_OVERLAY |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
- cap->device_caps |= dev->ext_vv_data->capabilities;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
- if (vdev->vfl_type == VFL_TYPE_GRABBER)
- cap->device_caps &=
- ~(V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT);
- else
- cap->device_caps &=
- ~(V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_AUDIO);
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY |
+ V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
+ V4L2_CAP_DEVICE_CAPS;
+ cap->capabilities |= dev->ext_vv_data->capabilities;
return 0;
}
diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
index 3cf25abf5807..4489744fbbd9 100644
--- a/drivers/media/common/videobuf2/videobuf2-core.c
+++ b/drivers/media/common/videobuf2/videobuf2-core.c
@@ -205,8 +205,13 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb)
* NOTE: mmapped areas should be page aligned
*/
for (plane = 0; plane < vb->num_planes; ++plane) {
+ /* Memops alloc requires size to be page aligned. */
unsigned long size = PAGE_ALIGN(vb->planes[plane].length);
+ /* Did it wrap around? */
+ if (size < vb->planes[plane].length)
+ goto free;
+
mem_priv = call_ptr_memop(vb, alloc,
q->alloc_devs[plane] ? : q->dev,
q->dma_attrs, size, q->dma_dir, q->gfp_flags);
diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c b/drivers/media/common/videobuf2/videobuf2-dma-contig.c
index ecbef266130b..7d77e4d30c8a 100644
--- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c
+++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c
@@ -475,8 +475,7 @@ static void *vb2_dc_get_userptr(struct device *dev, unsigned long vaddr,
buf->dma_dir = dma_dir;
offset = lower_32_bits(offset_in_page(vaddr));
- vec = vb2_create_framevec(vaddr, size, dma_dir == DMA_FROM_DEVICE ||
- dma_dir == DMA_BIDIRECTIONAL);
+ vec = vb2_create_framevec(vaddr, size);
if (IS_ERR(vec)) {
ret = PTR_ERR(vec);
goto fail_buf;
diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c b/drivers/media/common/videobuf2/videobuf2-dma-sg.c
index 4a4c49d6085c..ed706b2a263c 100644
--- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c
+++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c
@@ -59,7 +59,7 @@ static int vb2_dma_sg_alloc_compacted(struct vb2_dma_sg_buf *buf,
gfp_t gfp_flags)
{
unsigned int last_page = 0;
- int size = buf->size;
+ unsigned long size = buf->size;
while (size > 0) {
struct page *pages;
@@ -239,8 +239,7 @@ static void *vb2_dma_sg_get_userptr(struct device *dev, unsigned long vaddr,
buf->offset = vaddr & ~PAGE_MASK;
buf->size = size;
buf->dma_sgt = &buf->sg_table;
- vec = vb2_create_framevec(vaddr, size, dma_dir == DMA_FROM_DEVICE ||
- dma_dir == DMA_BIDIRECTIONAL);
+ vec = vb2_create_framevec(vaddr, size);
if (IS_ERR(vec))
goto userptr_fail_pfnvec;
buf->vec = vec;
diff --git a/drivers/media/common/videobuf2/videobuf2-memops.c b/drivers/media/common/videobuf2/videobuf2-memops.c
index c4a85be48ac2..6e9e05153f4e 100644
--- a/drivers/media/common/videobuf2/videobuf2-memops.c
+++ b/drivers/media/common/videobuf2/videobuf2-memops.c
@@ -26,7 +26,6 @@
* vb2_create_framevec() - map virtual addresses to pfns
* @start: Virtual user address where we start mapping
* @length: Length of a range to map
- * @write: Should we map for writing into the area
*
* This function allocates and fills in a vector with pfns corresponding to
* virtual address range passed in arguments. If pfns have corresponding pages,
@@ -35,17 +34,13 @@
* failure. Returned vector needs to be freed via vb2_destroy_pfnvec().
*/
struct frame_vector *vb2_create_framevec(unsigned long start,
- unsigned long length,
- bool write)
+ unsigned long length)
{
int ret;
unsigned long first, last;
unsigned long nr;
struct frame_vector *vec;
- unsigned int flags = FOLL_FORCE;
-
- if (write)
- flags |= FOLL_WRITE;
+ unsigned int flags = FOLL_FORCE | FOLL_WRITE;
first = start >> PAGE_SHIFT;
last = (start + length - 1) >> PAGE_SHIFT;
diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c
index fb9ac7696fc6..40d76eb4c2fe 100644
--- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
+++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
@@ -563,11 +563,6 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
b->flags |= V4L2_BUF_FLAG_REQUEST_FD;
b->request_fd = vbuf->request_fd;
}
-
- if (!q->is_output &&
- b->flags & V4L2_BUF_FLAG_DONE &&
- b->flags & V4L2_BUF_FLAG_LAST)
- q->last_buffer_dequeued = true;
}
/*
@@ -786,6 +781,11 @@ int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking)
ret = vb2_core_dqbuf(q, NULL, b, nonblocking);
+ if (!q->is_output &&
+ b->flags & V4L2_BUF_FLAG_DONE &&
+ b->flags & V4L2_BUF_FLAG_LAST)
+ q->last_buffer_dequeued = true;
+
/*
* After calling the VIDIOC_DQBUF V4L2_BUF_FLAG_DONE must be
* cleared.
diff --git a/drivers/media/common/videobuf2/videobuf2-vmalloc.c b/drivers/media/common/videobuf2/videobuf2-vmalloc.c
index 1c6659f7c394..04d51ca63223 100644
--- a/drivers/media/common/videobuf2/videobuf2-vmalloc.c
+++ b/drivers/media/common/videobuf2/videobuf2-vmalloc.c
@@ -87,8 +87,7 @@ static void *vb2_vmalloc_get_userptr(struct device *dev, unsigned long vaddr,
buf->dma_dir = dma_dir;
offset = vaddr & ~PAGE_MASK;
buf->size = size;
- vec = vb2_create_framevec(vaddr, size, dma_dir == DMA_FROM_DEVICE ||
- dma_dir == DMA_BIDIRECTIONAL);
+ vec = vb2_create_framevec(vaddr, size);
if (IS_ERR(vec)) {
ret = PTR_ERR(vec);
goto fail_pfnvec_create;
diff --git a/drivers/media/dvb-core/Kconfig b/drivers/media/dvb-core/Kconfig
index aac4bebb35f7..90e038d5ffd9 100644
--- a/drivers/media/dvb-core/Kconfig
+++ b/drivers/media/dvb-core/Kconfig
@@ -19,7 +19,6 @@ config DVB_MAX_ADAPTERS
config DVB_DYNAMIC_MINORS
bool "Dynamic DVB minor allocation"
depends on DVB_CORE
- default n
help
If you say Y here, the DVB subsystem will use dynamic minor
allocation for any device that uses the DVB major number.
@@ -32,7 +31,6 @@ config DVB_DYNAMIC_MINORS
config DVB_DEMUX_SECTION_LOSS_LOG
bool "Enable DVB demux section packet loss log"
depends on DVB_CORE
- default n
help
Enable extra log messages meant to detect packet loss
inside the Kernel.
@@ -45,7 +43,6 @@ config DVB_DEMUX_SECTION_LOSS_LOG
config DVB_ULE_DEBUG
bool "Enable DVB net ULE packet debug messages"
depends on DVB_CORE
- default n
help
Enable extra log messages meant to detect problems while
handling DVB network ULE packet loss inside the Kernel.
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
index 6351a97f3d18..209186c5cd9b 100644
--- a/drivers/media/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -2311,6 +2311,78 @@ static int dtv_set_frontend(struct dvb_frontend *fe)
return 0;
}
+static int dvb_get_property(struct dvb_frontend *fe, struct file *file,
+ struct dtv_properties *tvps)
+{
+ struct dvb_frontend_private *fepriv = fe->frontend_priv;
+ struct dtv_property *tvp = NULL;
+ struct dtv_frontend_properties getp;
+ int i, err;
+
+ memcpy(&getp, &fe->dtv_property_cache, sizeof(getp));
+
+ dev_dbg(fe->dvb->device, "%s: properties.num = %d\n",
+ __func__, tvps->num);
+ dev_dbg(fe->dvb->device, "%s: properties.props = %p\n",
+ __func__, tvps->props);
+
+ /*
+ * Put an arbitrary limit on the number of messages that can
+ * be sent at once
+ */
+ if (!tvps->num || tvps->num > DTV_IOCTL_MAX_MSGS)
+ return -EINVAL;
+
+ tvp = memdup_user((void __user *)tvps->props, tvps->num * sizeof(*tvp));
+ if (IS_ERR(tvp))
+ return PTR_ERR(tvp);
+
+ /*
+ * Let's use our own copy of property cache, in order to
+ * avoid mangling with DTV zigzag logic, as drivers might
+ * return crap, if they don't check if the data is available
+ * before updating the properties cache.
+ */
+ if (fepriv->state != FESTATE_IDLE) {
+ err = dtv_get_frontend(fe, &getp, NULL);
+ if (err < 0)
+ goto out;
+ }
+ for (i = 0; i < tvps->num; i++) {
+ err = dtv_property_process_get(fe, &getp,
+ tvp + i, file);
+ if (err < 0)
+ goto out;
+ }
+
+ if (copy_to_user((void __user *)tvps->props, tvp,
+ tvps->num * sizeof(struct dtv_property))) {
+ err = -EFAULT;
+ goto out;
+ }
+
+ err = 0;
+out:
+ kfree(tvp);
+ return err;
+}
+
+static int dvb_get_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p_out)
+{
+ struct dtv_frontend_properties getp;
+
+ /*
+ * Let's use our own copy of property cache, in order to
+ * avoid mangling with DTV zigzag logic, as drivers might
+ * return crap, if they don't check if the data is available
+ * before updating the properties cache.
+ */
+ memcpy(&getp, &fe->dtv_property_cache, sizeof(getp));
+
+ return dtv_get_frontend(fe, &getp, p_out);
+}
+
static int dvb_frontend_handle_ioctl(struct file *file,
unsigned int cmd, void *parg)
{
@@ -2356,58 +2428,9 @@ static int dvb_frontend_handle_ioctl(struct file *file,
err = 0;
break;
}
- case FE_GET_PROPERTY: {
- struct dtv_properties *tvps = parg;
- struct dtv_property *tvp = NULL;
- struct dtv_frontend_properties getp = fe->dtv_property_cache;
-
- dev_dbg(fe->dvb->device, "%s: properties.num = %d\n",
- __func__, tvps->num);
- dev_dbg(fe->dvb->device, "%s: properties.props = %p\n",
- __func__, tvps->props);
-
- /*
- * Put an arbitrary limit on the number of messages that can
- * be sent at once
- */
- if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS))
- return -EINVAL;
-
- tvp = memdup_user((void __user *)tvps->props, tvps->num * sizeof(*tvp));
- if (IS_ERR(tvp))
- return PTR_ERR(tvp);
-
- /*
- * Let's use our own copy of property cache, in order to
- * avoid mangling with DTV zigzag logic, as drivers might
- * return crap, if they don't check if the data is available
- * before updating the properties cache.
- */
- if (fepriv->state != FESTATE_IDLE) {
- err = dtv_get_frontend(fe, &getp, NULL);
- if (err < 0) {
- kfree(tvp);
- return err;
- }
- }
- for (i = 0; i < tvps->num; i++) {
- err = dtv_property_process_get(fe, &getp,
- tvp + i, file);
- if (err < 0) {
- kfree(tvp);
- return err;
- }
- }
-
- if (copy_to_user((void __user *)tvps->props, tvp,
- tvps->num * sizeof(struct dtv_property))) {
- kfree(tvp);
- return -EFAULT;
- }
- kfree(tvp);
- err = 0;
+ case FE_GET_PROPERTY:
+ err = dvb_get_property(fe, file, parg);
break;
- }
case FE_GET_INFO: {
struct dvb_frontend_info *info = parg;
@@ -2545,7 +2568,6 @@ static int dvb_frontend_handle_ioctl(struct file *file,
fepriv->tune_mode_flags = (unsigned long)parg;
err = 0;
break;
-
/* DEPRECATED dish control ioctls */
case FE_DISHNETWORK_SEND_LEGACY_CMD:
@@ -2664,22 +2686,14 @@ static int dvb_frontend_handle_ioctl(struct file *file,
break;
err = dtv_set_frontend(fe);
break;
+
case FE_GET_EVENT:
err = dvb_frontend_get_event(fe, parg, file->f_flags);
break;
- case FE_GET_FRONTEND: {
- struct dtv_frontend_properties getp = fe->dtv_property_cache;
-
- /*
- * Let's use our own copy of property cache, in order to
- * avoid mangling with DTV zigzag logic, as drivers might
- * return crap, if they don't check if the data is available
- * before updating the properties cache.
- */
- err = dtv_get_frontend(fe, &getp, parg);
+ case FE_GET_FRONTEND:
+ err = dvb_get_frontend(fe, parg);
break;
- }
default:
return -ENOTSUPP;
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig
index 847da72d1256..dc43749177df 100644
--- a/drivers/media/dvb-frontends/Kconfig
+++ b/drivers/media/dvb-frontends/Kconfig
@@ -1,5 +1,5 @@
menu "Customise DVB Frontends"
- visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST
+ visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST || EXPERT
comment "Multistandard (satellite) frontends"
depends on DVB_CORE
@@ -945,5 +945,4 @@ comment "Tools to develop new frontends"
config DVB_DUMMY_FE
tristate "Dummy frontend driver"
depends on DVB_CORE
- default n
endmenu
diff --git a/drivers/media/dvb-frontends/dib3000.h b/drivers/media/dvb-frontends/dib3000.h
index d2b7523a22b5..9118a7a48ef2 100644
--- a/drivers/media/dvb-frontends/dib3000.h
+++ b/drivers/media/dvb-frontends/dib3000.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* public header file of the frontend drivers for mobile DVB-T demodulators
* DiBcom 3000M-B and DiBcom 3000P/M-C (http://www.dibcom.fr/)
@@ -8,17 +9,12 @@
*
* Copyright (C) 2004 Amaury Demol for DiBcom
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, version 2.
- *
* Acknowledgements
*
* Amaury Demol from DiBcom for providing specs and driver
* sources, on which this driver (and the dvb-dibusb) are based.
*
* see Documentation/media/dvb-drivers/dvb-usb.rst for more information
- *
*/
#ifndef DIB3000_H
diff --git a/drivers/media/dvb-frontends/dib3000mb.c b/drivers/media/dvb-frontends/dib3000mb.c
index bbbd53280477..46ed0e20c8fa 100644
--- a/drivers/media/dvb-frontends/dib3000mb.c
+++ b/drivers/media/dvb-frontends/dib3000mb.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Frontend driver for mobile DVB-T demodulator DiBcom 3000M-B
* DiBcom (http://www.dibcom.fr/)
@@ -8,17 +9,12 @@
*
* Copyright (C) 2004 Amaury Demol for DiBcom
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, version 2.
- *
* Acknowledgements
*
* Amaury Demol from DiBcom for providing specs and driver
* sources, on which this driver (and the dvb-dibusb) are based.
*
* see Documentation/media/dvb-drivers/dvb-usb.rst for more information
- *
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/media/dvb-frontends/drxd.h b/drivers/media/dvb-frontends/drxd.h
index 1d4b89488ac4..ba54fd9adab9 100644
--- a/drivers/media/dvb-frontends/drxd.h
+++ b/drivers/media/dvb-frontends/drxd.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* drxd.h: DRXD DVB-T demodulator driver
*
* Copyright (C) 2005-2007 Micronas
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * To obtain the license, point your browser to
- * http://www.gnu.org/copyleft/gpl.html
*/
#ifndef _DRXD_H_
diff --git a/drivers/media/dvb-frontends/drxd_firm.c b/drivers/media/dvb-frontends/drxd_firm.c
index 412871d6636b..8aae3e0350d3 100644
--- a/drivers/media/dvb-frontends/drxd_firm.c
+++ b/drivers/media/dvb-frontends/drxd_firm.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drxd_firm.c : DRXD firmware tables
*
* Copyright (C) 2006-2007 Micronas
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * To obtain the license, point your browser to
- * http://www.gnu.org/copyleft/gpl.html
*/
/* TODO: generate this file with a script from a settings file */
diff --git a/drivers/media/dvb-frontends/drxd_firm.h b/drivers/media/dvb-frontends/drxd_firm.h
index 7d9f9fa7ab3c..b3f04dfe248c 100644
--- a/drivers/media/dvb-frontends/drxd_firm.h
+++ b/drivers/media/dvb-frontends/drxd_firm.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* drxd_firm.h
*
* Copyright (C) 2006-2007 Micronas
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * To obtain the license, point your browser to
- * http://www.gnu.org/copyleft/gpl.html
*/
#ifndef _DRXD_FIRM_H_
diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c
index c597d6fc3046..fae6f3763364 100644
--- a/drivers/media/dvb-frontends/drxd_hard.c
+++ b/drivers/media/dvb-frontends/drxd_hard.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drxd_hard.c: DVB-T Demodulator Micronas DRX3975D-A2,DRX397xD-B1
*
* Copyright (C) 2003-2007 Micronas
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * To obtain the license, point your browser to
- * http://www.gnu.org/copyleft/gpl.html
*/
#include <linux/kernel.h>
diff --git a/drivers/media/dvb-frontends/drxd_map_firm.h b/drivers/media/dvb-frontends/drxd_map_firm.h
index 8e5bd2e8de40..bdcc63576df1 100644
--- a/drivers/media/dvb-frontends/drxd_map_firm.h
+++ b/drivers/media/dvb-frontends/drxd_map_firm.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* drx3973d_map_firm.h
*
* Copyright (C) 2006-2007 Micronas
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * To obtain the license, point your browser to
- * http://www.gnu.org/copyleft/gpl.html
*/
#ifndef __DRX3973D_MAP__H__
diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c
index 86652a4ef9ce..0a4875b391d9 100644
--- a/drivers/media/dvb-frontends/drxk_hard.c
+++ b/drivers/media/dvb-frontends/drxk_hard.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drxk_hard: DRX-K DVB-C/T demodulator driver
*
* Copyright (C) 2010-2011 Digital Devices GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * To obtain the license, point your browser to
- * http://www.gnu.org/copyleft/gpl.html
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c
index cf1a8f77ee02..e05c21d35dc8 100644
--- a/drivers/media/dvb-frontends/rtl2832_sdr.c
+++ b/drivers/media/dvb-frontends/rtl2832_sdr.c
@@ -428,9 +428,6 @@ static int rtl2832_sdr_querycap(struct file *file, void *fh,
strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
strscpy(cap->card, dev->vdev.name, sizeof(cap->card));
usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
- cap->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING |
- V4L2_CAP_READWRITE | V4L2_CAP_TUNER;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -1242,6 +1239,8 @@ static struct video_device rtl2832_sdr_template = {
.release = video_device_release_empty,
.fops = &rtl2832_sdr_fops,
.ioctl_ops = &rtl2832_sdr_ioctl_ops,
+ .device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE | V4L2_CAP_TUNER,
};
static int rtl2832_sdr_s_ctrl(struct v4l2_ctrl *ctrl)
diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c
index 5dae571e2f62..168c503e9154 100644
--- a/drivers/media/dvb-frontends/si2168.c
+++ b/drivers/media/dvb-frontends/si2168.c
@@ -674,8 +674,11 @@ static const struct dvb_frontend_ops si2168_ops = {
.delsys = {SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A},
.info = {
.name = "Silicon Labs Si2168",
- .symbol_rate_min = 1000000,
- .symbol_rate_max = 7200000,
+ .frequency_min_hz = 48 * MHz,
+ .frequency_max_hz = 870 * MHz,
+ .frequency_stepsize_hz = 62500,
+ .symbol_rate_min = 1000000,
+ .symbol_rate_max = 7200000,
.caps = FE_CAN_FEC_1_2 |
FE_CAN_FEC_2_3 |
FE_CAN_FEC_3_4 |
diff --git a/drivers/media/dvb-frontends/stv0297.c b/drivers/media/dvb-frontends/stv0297.c
index dac396c95a59..6d5962d5697a 100644
--- a/drivers/media/dvb-frontends/stv0297.c
+++ b/drivers/media/dvb-frontends/stv0297.c
@@ -682,7 +682,7 @@ static const struct dvb_frontend_ops stv0297_ops = {
.delsys = { SYS_DVBC_ANNEX_A },
.info = {
.name = "ST STV0297 DVB-C",
- .frequency_min_hz = 470 * MHz,
+ .frequency_min_hz = 47 * MHz,
.frequency_max_hz = 862 * MHz,
.frequency_stepsize_hz = 62500,
.symbol_rate_min = 870000,
diff --git a/drivers/media/dvb-frontends/stv090x.c b/drivers/media/dvb-frontends/stv090x.c
index d1261571dbe4..90d24131d335 100644
--- a/drivers/media/dvb-frontends/stv090x.c
+++ b/drivers/media/dvb-frontends/stv090x.c
@@ -4889,6 +4889,66 @@ static int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, u8 dir,
return stv090x_write_reg(state, STV090x_GPIOxCFG(gpio), reg);
}
+static int stv090x_setup_compound(struct stv090x_state *state)
+{
+ struct stv090x_dev *temp_int;
+
+ temp_int = find_dev(state->i2c,
+ state->config->address);
+
+ if (temp_int && state->demod_mode == STV090x_DUAL) {
+ state->internal = temp_int->internal;
+ state->internal->num_used++;
+ dprintk(FE_INFO, 1, "Found Internal Structure!");
+ } else {
+ state->internal = kmalloc(sizeof(*state->internal), GFP_KERNEL);
+ if (!state->internal)
+ goto error;
+ temp_int = append_internal(state->internal);
+ if (!temp_int) {
+ kfree(state->internal);
+ goto error;
+ }
+ state->internal->num_used = 1;
+ state->internal->mclk = 0;
+ state->internal->dev_ver = 0;
+ state->internal->i2c_adap = state->i2c;
+ state->internal->i2c_addr = state->config->address;
+ dprintk(FE_INFO, 1, "Create New Internal Structure!");
+
+ mutex_init(&state->internal->demod_lock);
+ mutex_init(&state->internal->tuner_lock);
+
+ if (stv090x_setup(&state->frontend) < 0) {
+ dprintk(FE_ERROR, 1, "Error setting up device");
+ goto err_remove;
+ }
+ }
+
+ if (state->internal->dev_ver >= 0x30)
+ state->frontend.ops.info.caps |= FE_CAN_MULTISTREAM;
+
+ /* workaround for stuck DiSEqC output */
+ if (state->config->diseqc_envelope_mode)
+ stv090x_send_diseqc_burst(&state->frontend, SEC_MINI_A);
+
+ state->config->set_gpio = stv090x_set_gpio;
+
+ dprintk(FE_ERROR, 1, "Probing %s demodulator(%d) Cut=0x%02x",
+ state->device == STV0900 ? "STV0900" : "STV0903",
+ state->config->demod,
+ state->internal->dev_ver);
+
+ return 0;
+
+error:
+ return -ENOMEM;
+err_remove:
+ remove_dev(state->internal);
+ kfree(state->internal);
+ return -ENODEV;
+}
+
static const struct dvb_frontend_ops stv090x_ops = {
.delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS },
.info = {
@@ -4921,85 +4981,118 @@ static const struct dvb_frontend_ops stv090x_ops = {
.read_snr = stv090x_read_cnr,
};
+static struct dvb_frontend *stv090x_get_dvb_frontend(struct i2c_client *client)
+{
+ struct stv090x_state *state = i2c_get_clientdata(client);
-struct dvb_frontend *stv090x_attach(struct stv090x_config *config,
- struct i2c_adapter *i2c,
- enum stv090x_demodulator demod)
+ dev_dbg(&client->dev, "\n");
+
+ return &state->frontend;
+}
+
+static int stv090x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
+ int ret = 0;
+ struct stv090x_config *config = client->dev.platform_data;
+
struct stv090x_state *state = NULL;
- struct stv090x_dev *temp_int;
- state = kzalloc(sizeof (struct stv090x_state), GFP_KERNEL);
- if (state == NULL)
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state) {
+ ret = -ENOMEM;
goto error;
+ }
state->verbose = &verbose;
state->config = config;
- state->i2c = i2c;
+ state->i2c = client->adapter;
state->frontend.ops = stv090x_ops;
state->frontend.demodulator_priv = state;
- state->demod = demod;
- state->demod_mode = config->demod_mode; /* Single or Dual mode */
+ state->demod = config->demod;
+ /* Single or Dual mode */
+ state->demod_mode = config->demod_mode;
state->device = config->device;
- state->rolloff = STV090x_RO_35; /* default */
+ /* default */
+ state->rolloff = STV090x_RO_35;
- temp_int = find_dev(state->i2c,
- state->config->address);
+ ret = stv090x_setup_compound(state);
+ if (ret)
+ goto error;
- if ((temp_int != NULL) && (state->demod_mode == STV090x_DUAL)) {
- state->internal = temp_int->internal;
- state->internal->num_used++;
- dprintk(FE_INFO, 1, "Found Internal Structure!");
- } else {
- state->internal = kmalloc(sizeof(struct stv090x_internal),
- GFP_KERNEL);
- if (!state->internal)
- goto error;
- temp_int = append_internal(state->internal);
- if (!temp_int) {
- kfree(state->internal);
- goto error;
- }
- state->internal->num_used = 1;
- state->internal->mclk = 0;
- state->internal->dev_ver = 0;
- state->internal->i2c_adap = state->i2c;
- state->internal->i2c_addr = state->config->address;
- dprintk(FE_INFO, 1, "Create New Internal Structure!");
+ i2c_set_clientdata(client, state);
- mutex_init(&state->internal->demod_lock);
- mutex_init(&state->internal->tuner_lock);
+ /* setup callbacks */
+ config->get_dvb_frontend = stv090x_get_dvb_frontend;
- if (stv090x_setup(&state->frontend) < 0) {
- dprintk(FE_ERROR, 1, "Error setting up device");
- goto err_remove;
- }
- }
+ return 0;
- if (state->internal->dev_ver >= 0x30)
- state->frontend.ops.info.caps |= FE_CAN_MULTISTREAM;
+error:
+ kfree(state);
+ return ret;
+}
- /* workaround for stuck DiSEqC output */
- if (config->diseqc_envelope_mode)
- stv090x_send_diseqc_burst(&state->frontend, SEC_MINI_A);
+static int stv090x_remove(struct i2c_client *client)
+{
+ struct stv090x_state *state = i2c_get_clientdata(client);
+
+ stv090x_release(&state->frontend);
+ return 0;
+}
- config->set_gpio = stv090x_set_gpio;
+struct dvb_frontend *stv090x_attach(struct stv090x_config *config,
+ struct i2c_adapter *i2c,
+ enum stv090x_demodulator demod)
+{
+ int ret = 0;
+ struct stv090x_state *state = NULL;
- dprintk(FE_ERROR, 1, "Attaching %s demodulator(%d) Cut=0x%02x",
- state->device == STV0900 ? "STV0900" : "STV0903",
- demod,
- state->internal->dev_ver);
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ goto error;
+
+ state->verbose = &verbose;
+ state->config = config;
+ state->i2c = i2c;
+ state->frontend.ops = stv090x_ops;
+ state->frontend.demodulator_priv = state;
+ state->demod = demod;
+ /* Single or Dual mode */
+ state->demod_mode = config->demod_mode;
+ state->device = config->device;
+ /* default */
+ state->rolloff = STV090x_RO_35;
+
+ ret = stv090x_setup_compound(state);
+ if (ret)
+ goto error;
return &state->frontend;
-err_remove:
- remove_dev(state->internal);
- kfree(state->internal);
error:
kfree(state);
return NULL;
}
EXPORT_SYMBOL(stv090x_attach);
+
+static const struct i2c_device_id stv090x_id_table[] = {
+ {"stv090x", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, stv090x_id_table);
+
+static struct i2c_driver stv090x_driver = {
+ .driver = {
+ .name = "stv090x",
+ .suppress_bind_attrs = true,
+ },
+ .probe = stv090x_probe,
+ .remove = stv090x_remove,
+ .id_table = stv090x_id_table,
+};
+
+module_i2c_driver(stv090x_driver);
+
MODULE_PARM_DESC(verbose, "Set Verbosity level");
MODULE_AUTHOR("Manu Abraham");
MODULE_DESCRIPTION("STV090x Multi-Std Broadcast frontend");
diff --git a/drivers/media/dvb-frontends/stv090x.h b/drivers/media/dvb-frontends/stv090x.h
index 13f251a08abd..89f45d9fa427 100644
--- a/drivers/media/dvb-frontends/stv090x.h
+++ b/drivers/media/dvb-frontends/stv090x.h
@@ -57,6 +57,7 @@ struct stv090x_config {
enum stv090x_device device;
enum stv090x_mode demod_mode;
enum stv090x_clkmode clk_mode;
+ enum stv090x_demodulator demod;
u32 xtal; /* default: 8000000 */
u8 address; /* default: 0x68 */
@@ -93,6 +94,8 @@ struct stv090x_config {
/* dir = 0 -> output, dir = 1 -> input/open-drain */
int (*set_gpio)(struct dvb_frontend *fe, u8 gpio, u8 dir, u8 value,
u8 xor_value);
+
+ struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *i2c);
};
#if IS_REACHABLE(CONFIG_DVB_STV090x)
diff --git a/drivers/media/dvb-frontends/stv090x_priv.h b/drivers/media/dvb-frontends/stv090x_priv.h
index b22c58968c93..f8ece898c153 100644
--- a/drivers/media/dvb-frontends/stv090x_priv.h
+++ b/drivers/media/dvb-frontends/stv090x_priv.h
@@ -237,7 +237,7 @@ struct stv090x_state {
struct stv090x_internal *internal;
struct i2c_adapter *i2c;
- const struct stv090x_config *config;
+ struct stv090x_config *config;
struct dvb_frontend frontend;
u32 *verbose; /* Cached module verbosity */
diff --git a/drivers/media/dvb-frontends/stv6110x.c b/drivers/media/dvb-frontends/stv6110x.c
index 0126cfae2e03..5012d0231652 100644
--- a/drivers/media/dvb-frontends/stv6110x.c
+++ b/drivers/media/dvb-frontends/stv6110x.c
@@ -333,6 +333,41 @@ static void stv6110x_release(struct dvb_frontend *fe)
kfree(stv6110x);
}
+static void st6110x_init_regs(struct stv6110x_state *stv6110x)
+{
+ u8 default_regs[] = {0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e};
+
+ memcpy(stv6110x->regs, default_regs, 8);
+}
+
+static void stv6110x_setup_divider(struct stv6110x_state *stv6110x)
+{
+ switch (stv6110x->config->clk_div) {
+ default:
+ case 1:
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2],
+ CTRL2_CO_DIV,
+ 0);
+ break;
+ case 2:
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2],
+ CTRL2_CO_DIV,
+ 1);
+ break;
+ case 4:
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2],
+ CTRL2_CO_DIV,
+ 2);
+ break;
+ case 8:
+ case 0:
+ STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2],
+ CTRL2_CO_DIV,
+ 3);
+ break;
+ }
+}
+
static const struct dvb_tuner_ops stv6110x_ops = {
.info = {
.name = "STV6110(A) Silicon Tuner",
@@ -342,7 +377,7 @@ static const struct dvb_tuner_ops stv6110x_ops = {
.release = stv6110x_release
};
-static const struct stv6110x_devctl stv6110x_ctl = {
+static struct stv6110x_devctl stv6110x_ctl = {
.tuner_init = stv6110x_init,
.tuner_sleep = stv6110x_sleep,
.tuner_set_mode = stv6110x_set_mode,
@@ -356,48 +391,104 @@ static const struct stv6110x_devctl stv6110x_ctl = {
.tuner_get_status = stv6110x_get_status,
};
+static void stv6110x_set_frontend_opts(struct stv6110x_state *stv6110x)
+{
+ stv6110x->frontend->tuner_priv = stv6110x;
+ stv6110x->frontend->ops.tuner_ops = stv6110x_ops;
+}
+
+static struct stv6110x_devctl *stv6110x_get_devctl(struct i2c_client *client)
+{
+ struct stv6110x_state *stv6110x = i2c_get_clientdata(client);
+
+ dev_dbg(&client->dev, "\n");
+
+ return stv6110x->devctl;
+}
+
+static int stv6110x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct stv6110x_config *config = client->dev.platform_data;
+
+ struct stv6110x_state *stv6110x;
+
+ stv6110x = kzalloc(sizeof(*stv6110x), GFP_KERNEL);
+ if (!stv6110x)
+ return -ENOMEM;
+
+ stv6110x->frontend = config->frontend;
+ stv6110x->i2c = client->adapter;
+ stv6110x->config = config;
+ stv6110x->devctl = &stv6110x_ctl;
+
+ st6110x_init_regs(stv6110x);
+ stv6110x_setup_divider(stv6110x);
+ stv6110x_set_frontend_opts(stv6110x);
+
+ dev_info(&stv6110x->i2c->dev, "Probed STV6110x\n");
+
+ i2c_set_clientdata(client, stv6110x);
+
+ /* setup callbacks */
+ config->get_devctl = stv6110x_get_devctl;
+
+ return 0;
+}
+
+static int stv6110x_remove(struct i2c_client *client)
+{
+ struct stv6110x_state *stv6110x = i2c_get_clientdata(client);
+
+ stv6110x_release(stv6110x->frontend);
+ return 0;
+}
+
const struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
const struct stv6110x_config *config,
struct i2c_adapter *i2c)
{
struct stv6110x_state *stv6110x;
- u8 default_regs[] = {0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e};
- stv6110x = kzalloc(sizeof (struct stv6110x_state), GFP_KERNEL);
+ stv6110x = kzalloc(sizeof(*stv6110x), GFP_KERNEL);
if (!stv6110x)
return NULL;
+ stv6110x->frontend = fe;
stv6110x->i2c = i2c;
stv6110x->config = config;
stv6110x->devctl = &stv6110x_ctl;
- memcpy(stv6110x->regs, default_regs, 8);
- /* setup divider */
- switch (stv6110x->config->clk_div) {
- default:
- case 1:
- STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 0);
- break;
- case 2:
- STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 1);
- break;
- case 4:
- STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 2);
- break;
- case 8:
- case 0:
- STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 3);
- break;
- }
+ st6110x_init_regs(stv6110x);
+ stv6110x_setup_divider(stv6110x);
+ stv6110x_set_frontend_opts(stv6110x);
fe->tuner_priv = stv6110x;
fe->ops.tuner_ops = stv6110x_ops;
- printk(KERN_INFO "%s: Attaching STV6110x\n", __func__);
+ dev_info(&stv6110x->i2c->dev, "Attaching STV6110x\n");
return stv6110x->devctl;
}
EXPORT_SYMBOL(stv6110x_attach);
+static const struct i2c_device_id stv6110x_id_table[] = {
+ {"stv6110x", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, stv6110x_id_table);
+
+static struct i2c_driver stv6110x_driver = {
+ .driver = {
+ .name = "stv6110x",
+ .suppress_bind_attrs = true,
+ },
+ .probe = stv6110x_probe,
+ .remove = stv6110x_remove,
+ .id_table = stv6110x_id_table,
+};
+
+module_i2c_driver(stv6110x_driver);
+
MODULE_AUTHOR("Manu Abraham");
MODULE_DESCRIPTION("STV6110x Silicon tuner");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/stv6110x.h b/drivers/media/dvb-frontends/stv6110x.h
index 1630e55255fd..1feade3158c2 100644
--- a/drivers/media/dvb-frontends/stv6110x.h
+++ b/drivers/media/dvb-frontends/stv6110x.h
@@ -15,6 +15,9 @@ struct stv6110x_config {
u8 addr;
u32 refclk;
u8 clk_div; /* divisor value for the output clock */
+ struct dvb_frontend *frontend;
+
+ struct stv6110x_devctl* (*get_devctl)(struct i2c_client *i2c);
};
enum tuner_mode {
diff --git a/drivers/media/dvb-frontends/stv6110x_priv.h b/drivers/media/dvb-frontends/stv6110x_priv.h
index 909094df28df..b27769558f78 100644
--- a/drivers/media/dvb-frontends/stv6110x_priv.h
+++ b/drivers/media/dvb-frontends/stv6110x_priv.h
@@ -54,11 +54,12 @@
#define REFCLOCK_MHz (stv6110x->config->refclk / 1000000)
struct stv6110x_state {
+ struct dvb_frontend *frontend;
struct i2c_adapter *i2c;
const struct stv6110x_config *config;
u8 regs[8];
- const struct stv6110x_devctl *devctl;
+ struct stv6110x_devctl *devctl;
};
#endif /* __STV6110x_PRIV_H */
diff --git a/drivers/media/dvb-frontends/tda18271c2dd.c b/drivers/media/dvb-frontends/tda18271c2dd.c
index e064e2b22d9d..43312bba1aec 100644
--- a/drivers/media/dvb-frontends/tda18271c2dd.c
+++ b/drivers/media/dvb-frontends/tda18271c2dd.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* tda18271c2dd: Driver for the TDA18271C2 tuner
*
* Copyright (C) 2010 Digital Devices GmbH
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * To obtain the license, point your browser to
- * http://www.gnu.org/copyleft/gpl.html
*/
#include <linux/kernel.h>
diff --git a/drivers/media/dvb-frontends/tua6100.c b/drivers/media/dvb-frontends/tua6100.c
index f7c3e6be8e4d..2483f614d0e7 100644
--- a/drivers/media/dvb-frontends/tua6100.c
+++ b/drivers/media/dvb-frontends/tua6100.c
@@ -67,8 +67,8 @@ static int tua6100_set_params(struct dvb_frontend *fe)
struct i2c_msg msg1 = { .addr = priv->i2c_address, .flags = 0, .buf = reg1, .len = 4 };
struct i2c_msg msg2 = { .addr = priv->i2c_address, .flags = 0, .buf = reg2, .len = 3 };
-#define _R 4
-#define _P 32
+#define _R_VAL 4
+#define _P_VAL 32
#define _ri 4000000
// setup register 0
@@ -83,14 +83,14 @@ static int tua6100_set_params(struct dvb_frontend *fe)
else
reg1[1] = 0x0c;
- if (_P == 64)
+ if (_P_VAL == 64)
reg1[1] |= 0x40;
if (c->frequency >= 1525000)
reg1[1] |= 0x80;
// register 2
- reg2[1] = (_R >> 8) & 0x03;
- reg2[2] = _R;
+ reg2[1] = (_R_VAL >> 8) & 0x03;
+ reg2[2] = _R_VAL;
if (c->frequency < 1455000)
reg2[1] |= 0x1c;
else if (c->frequency < 1630000)
@@ -102,18 +102,18 @@ static int tua6100_set_params(struct dvb_frontend *fe)
* The N divisor ratio (note: c->frequency is in kHz, but we
* need it in Hz)
*/
- prediv = (c->frequency * _R) / (_ri / 1000);
- div = prediv / _P;
+ prediv = (c->frequency * _R_VAL) / (_ri / 1000);
+ div = prediv / _P_VAL;
reg1[1] |= (div >> 9) & 0x03;
reg1[2] = div >> 1;
reg1[3] = (div << 7);
- priv->frequency = ((div * _P) * (_ri / 1000)) / _R;
+ priv->frequency = ((div * _P_VAL) * (_ri / 1000)) / _R_VAL;
// Finally, calculate and store the value for A
- reg1[3] |= (prediv - (div*_P)) & 0x7f;
+ reg1[3] |= (prediv - (div*_P_VAL)) & 0x7f;
-#undef _R
-#undef _P
+#undef _R_VAL
+#undef _P_VAL
#undef _ri
if (fe->ops.i2c_gate_ctrl)
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index cb8db944aa41..79ce9ec6fc1b 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -6,7 +6,7 @@
if VIDEO_V4L2
config VIDEO_IR_I2C
- tristate "I2C module for IR" if !MEDIA_SUBDRV_AUTOSELECT
+ tristate "I2C module for IR" if !MEDIA_SUBDRV_AUTOSELECT || EXPERT
depends on I2C && RC_CORE
default y
help
@@ -23,7 +23,7 @@ config VIDEO_IR_I2C
#
menu "I2C Encoders, decoders, sensors and other helper chips"
- visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST
+ visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST || EXPERT
comment "Audio decoders, processors and mixers"
@@ -511,6 +511,7 @@ config VIDEO_ADV7393
config VIDEO_ADV7511
tristate "Analog Devices ADV7511 encoder"
depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
+ depends on DRM_I2C_ADV7511=n || COMPILE_TEST
select HDMI
help
Support for the Analog Devices ADV7511 video encoder.
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index d8ad9dad495d..fd4ea86dedd5 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -35,7 +35,7 @@ obj-$(CONFIG_VIDEO_ADV748X) += adv748x/
obj-$(CONFIG_VIDEO_ADV7604) += adv7604.o
obj-$(CONFIG_VIDEO_ADV7842) += adv7842.o
obj-$(CONFIG_VIDEO_AD9389B) += ad9389b.o
-obj-$(CONFIG_VIDEO_ADV7511) += adv7511.o
+obj-$(CONFIG_VIDEO_ADV7511) += adv7511-v4l2.o
obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o
obj-$(CONFIG_VIDEO_VS6624) += vs6624.o
obj-$(CONFIG_VIDEO_BT819) += bt819.o
diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511-v4l2.c
index cec5ebb1c9e6..2ad6bdf1a9fc 100644
--- a/drivers/media/i2c/adv7511.c
+++ b/drivers/media/i2c/adv7511-v4l2.c
@@ -5,6 +5,11 @@
* Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
*/
+/*
+ * This file is named adv7511-v4l2.c so it doesn't conflict with the Analog
+ * Device ADV7511 (config fragment CONFIG_DRM_I2C_ADV7511).
+ */
+
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/media/i2c/ak881x.c b/drivers/media/i2c/ak881x.c
index 30f9db1351b9..1adaf470c75a 100644
--- a/drivers/media/i2c/ak881x.c
+++ b/drivers/media/i2c/ak881x.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for AK8813 / AK8814 TV-ecoders from Asahi Kasei Microsystems Co., Ltd. (AKM)
*
* Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- *
- * 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.
*/
#include <linux/i2c.h>
@@ -232,7 +229,7 @@ static const struct v4l2_subdev_ops ak881x_subdev_ops = {
static int ak881x_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adapter = client->adapter;
struct ak881x *ak881x;
u8 ifmode, data;
diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c
index 3ecf79d242f2..0de946fe2109 100644
--- a/drivers/media/i2c/cx25840/cx25840-core.c
+++ b/drivers/media/i2c/cx25840/cx25840-core.c
@@ -21,9 +21,11 @@
*
* CX23888 DIF support for the HVR1850
* Copyright (C) 2011 Steven Toth <stoth@kernellabs.com>
+ *
+ * CX2584x pin to pad mapping and output format configuration support are
+ * Copyright (C) 2011 Maciej S. Szmigiero <mail@maciej.szmigiero.name>
*/
-
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -64,17 +66,17 @@ MODULE_LICENSE("GPL");
static int cx25840_debug;
-module_param_named(debug,cx25840_debug, int, 0644);
+module_param_named(debug, cx25840_debug, int, 0644);
MODULE_PARM_DESC(debug, "Debugging messages [0=Off (default) 1=On]");
-
/* ----------------------------------------------------------------------- */
static void cx23888_std_setup(struct i2c_client *client);
int cx25840_write(struct i2c_client *client, u16 addr, u8 value)
{
u8 buffer[3];
+
buffer[0] = addr >> 8;
buffer[1] = addr & 0xff;
buffer[2] = value;
@@ -84,6 +86,7 @@ int cx25840_write(struct i2c_client *client, u16 addr, u8 value)
int cx25840_write4(struct i2c_client *client, u16 addr, u32 value)
{
u8 buffer[6];
+
buffer[0] = addr >> 8;
buffer[1] = addr & 0xff;
buffer[2] = value & 0xff;
@@ -93,7 +96,7 @@ int cx25840_write4(struct i2c_client *client, u16 addr, u32 value)
return i2c_master_send(client, buffer, 6);
}
-u8 cx25840_read(struct i2c_client * client, u16 addr)
+u8 cx25840_read(struct i2c_client *client, u16 addr)
{
struct i2c_msg msgs[2];
u8 tx_buf[2], rx_buf[1];
@@ -104,13 +107,13 @@ u8 cx25840_read(struct i2c_client * client, u16 addr)
msgs[0].addr = client->addr;
msgs[0].flags = 0;
msgs[0].len = 2;
- msgs[0].buf = (char *) tx_buf;
+ msgs[0].buf = (char *)tx_buf;
/* Read data from register */
msgs[1].addr = client->addr;
msgs[1].flags = I2C_M_RD;
msgs[1].len = 1;
- msgs[1].buf = (char *) rx_buf;
+ msgs[1].buf = (char *)rx_buf;
if (i2c_transfer(client->adapter, msgs, 2) < 2)
return 0;
@@ -118,7 +121,7 @@ u8 cx25840_read(struct i2c_client * client, u16 addr)
return rx_buf[0];
}
-u32 cx25840_read4(struct i2c_client * client, u16 addr)
+u32 cx25840_read4(struct i2c_client *client, u16 addr)
{
struct i2c_msg msgs[2];
u8 tx_buf[2], rx_buf[4];
@@ -129,13 +132,13 @@ u32 cx25840_read4(struct i2c_client * client, u16 addr)
msgs[0].addr = client->addr;
msgs[0].flags = 0;
msgs[0].len = 2;
- msgs[0].buf = (char *) tx_buf;
+ msgs[0].buf = (char *)tx_buf;
/* Read data from registers */
msgs[1].addr = client->addr;
msgs[1].flags = I2C_M_RD;
msgs[1].len = 4;
- msgs[1].buf = (char *) rx_buf;
+ msgs[1].buf = (char *)rx_buf;
if (i2c_transfer(client->adapter, msgs, 2) < 2)
return 0;
@@ -144,7 +147,7 @@ u32 cx25840_read4(struct i2c_client * client, u16 addr)
rx_buf[0];
}
-int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask,
+int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned int and_mask,
u8 or_value)
{
return cx25840_write(client, addr,
@@ -162,13 +165,14 @@ int cx25840_and_or4(struct i2c_client *client, u16 addr, u32 and_mask,
/* ----------------------------------------------------------------------- */
-static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input,
- enum cx25840_audio_input aud_input);
+static int set_input(struct i2c_client *client,
+ enum cx25840_video_input vid_input,
+ enum cx25840_audio_input aud_input);
/* ----------------------------------------------------------------------- */
static int cx23885_s_io_pin_config(struct v4l2_subdev *sd, size_t n,
- struct v4l2_subdev_io_pin_config *p)
+ struct v4l2_subdev_io_pin_config *p)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
int i;
@@ -307,13 +311,225 @@ static int cx23885_s_io_pin_config(struct v4l2_subdev *sd, size_t n,
return 0;
}
+static u8 cx25840_function_to_pad(struct i2c_client *client, u8 function)
+{
+ if (function > CX25840_PAD_VRESET) {
+ v4l_err(client, "invalid function %u, assuming default\n",
+ (unsigned int)function);
+ return 0;
+ }
+
+ return function;
+}
+
+static void cx25840_set_invert(u8 *pinctrl3, u8 *voutctrl4, u8 function,
+ u8 pin, bool invert)
+{
+ switch (function) {
+ case CX25840_PAD_IRQ_N:
+ if (invert)
+ *pinctrl3 &= ~2;
+ else
+ *pinctrl3 |= 2;
+ break;
+
+ case CX25840_PAD_ACTIVE:
+ if (invert)
+ *voutctrl4 |= BIT(2);
+ else
+ *voutctrl4 &= ~BIT(2);
+ break;
+
+ case CX25840_PAD_VACTIVE:
+ if (invert)
+ *voutctrl4 |= BIT(5);
+ else
+ *voutctrl4 &= ~BIT(5);
+ break;
+
+ case CX25840_PAD_CBFLAG:
+ if (invert)
+ *voutctrl4 |= BIT(4);
+ else
+ *voutctrl4 &= ~BIT(4);
+ break;
+
+ case CX25840_PAD_VRESET:
+ if (invert)
+ *voutctrl4 |= BIT(0);
+ else
+ *voutctrl4 &= ~BIT(0);
+ break;
+ }
+
+ if (function != CX25840_PAD_DEFAULT)
+ return;
+
+ switch (pin) {
+ case CX25840_PIN_DVALID_PRGM0:
+ if (invert)
+ *voutctrl4 |= BIT(6);
+ else
+ *voutctrl4 &= ~BIT(6);
+ break;
+
+ case CX25840_PIN_HRESET_PRGM2:
+ if (invert)
+ *voutctrl4 |= BIT(1);
+ else
+ *voutctrl4 &= ~BIT(1);
+ break;
+ }
+}
+
+static int cx25840_s_io_pin_config(struct v4l2_subdev *sd, size_t n,
+ struct v4l2_subdev_io_pin_config *p)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ unsigned int i;
+ u8 pinctrl[6], pinconf[10], voutctrl4;
+
+ for (i = 0; i < 6; i++)
+ pinctrl[i] = cx25840_read(client, 0x114 + i);
+
+ for (i = 0; i < 10; i++)
+ pinconf[i] = cx25840_read(client, 0x11c + i);
+
+ voutctrl4 = cx25840_read(client, 0x407);
+
+ for (i = 0; i < n; i++) {
+ u8 strength = p[i].strength;
+
+ if (strength != CX25840_PIN_DRIVE_SLOW &&
+ strength != CX25840_PIN_DRIVE_MEDIUM &&
+ strength != CX25840_PIN_DRIVE_FAST) {
+ v4l_err(client,
+ "invalid drive speed for pin %u (%u), assuming fast\n",
+ (unsigned int)p[i].pin,
+ (unsigned int)strength);
+
+ strength = CX25840_PIN_DRIVE_FAST;
+ }
+
+ switch (p[i].pin) {
+ case CX25840_PIN_DVALID_PRGM0:
+ if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_DISABLE))
+ pinctrl[0] &= ~BIT(6);
+ else
+ pinctrl[0] |= BIT(6);
+
+ pinconf[3] &= 0xf0;
+ pinconf[3] |= cx25840_function_to_pad(client,
+ p[i].function);
+
+ cx25840_set_invert(&pinctrl[3], &voutctrl4,
+ p[i].function,
+ CX25840_PIN_DVALID_PRGM0,
+ p[i].flags &
+ BIT(V4L2_SUBDEV_IO_PIN_ACTIVE_LOW));
+
+ pinctrl[4] &= ~(3 << 2); /* CX25840_PIN_DRIVE_MEDIUM */
+ switch (strength) {
+ case CX25840_PIN_DRIVE_SLOW:
+ pinctrl[4] |= 1 << 2;
+ break;
+
+ case CX25840_PIN_DRIVE_FAST:
+ pinctrl[4] |= 2 << 2;
+ break;
+ }
+
+ break;
+
+ case CX25840_PIN_HRESET_PRGM2:
+ if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_DISABLE))
+ pinctrl[1] &= ~BIT(0);
+ else
+ pinctrl[1] |= BIT(0);
+
+ pinconf[4] &= 0xf0;
+ pinconf[4] |= cx25840_function_to_pad(client,
+ p[i].function);
+
+ cx25840_set_invert(&pinctrl[3], &voutctrl4,
+ p[i].function,
+ CX25840_PIN_HRESET_PRGM2,
+ p[i].flags &
+ BIT(V4L2_SUBDEV_IO_PIN_ACTIVE_LOW));
+
+ pinctrl[4] &= ~(3 << 2); /* CX25840_PIN_DRIVE_MEDIUM */
+ switch (strength) {
+ case CX25840_PIN_DRIVE_SLOW:
+ pinctrl[4] |= 1 << 2;
+ break;
+
+ case CX25840_PIN_DRIVE_FAST:
+ pinctrl[4] |= 2 << 2;
+ break;
+ }
+
+ break;
+
+ case CX25840_PIN_PLL_CLK_PRGM7:
+ if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_DISABLE))
+ pinctrl[2] &= ~BIT(2);
+ else
+ pinctrl[2] |= BIT(2);
+
+ switch (p[i].function) {
+ case CX25840_PAD_XTI_X5_DLL:
+ pinconf[6] = 0;
+ break;
+
+ case CX25840_PAD_AUX_PLL:
+ pinconf[6] = 1;
+ break;
+
+ case CX25840_PAD_VID_PLL:
+ pinconf[6] = 5;
+ break;
+
+ case CX25840_PAD_XTI:
+ pinconf[6] = 2;
+ break;
+
+ default:
+ pinconf[6] = 3;
+ pinconf[6] |=
+ cx25840_function_to_pad(client,
+ p[i].function)
+ << 4;
+ }
+
+ break;
+
+ default:
+ v4l_err(client, "invalid or unsupported pin %u\n",
+ (unsigned int)p[i].pin);
+ break;
+ }
+ }
+
+ cx25840_write(client, 0x407, voutctrl4);
+
+ for (i = 0; i < 6; i++)
+ cx25840_write(client, 0x114 + i, pinctrl[i]);
+
+ for (i = 0; i < 10; i++)
+ cx25840_write(client, 0x11c + i, pinconf[i]);
+
+ return 0;
+}
+
static int common_s_io_pin_config(struct v4l2_subdev *sd, size_t n,
- struct v4l2_subdev_io_pin_config *pincfg)
+ struct v4l2_subdev_io_pin_config *pincfg)
{
struct cx25840_state *state = to_state(sd);
if (is_cx2388x(state))
return cx23885_s_io_pin_config(sd, n, pincfg);
+ else if (is_cx2584x(state))
+ return cx25840_s_io_pin_config(sd, n, pincfg);
return 0;
}
@@ -321,8 +537,10 @@ static int common_s_io_pin_config(struct v4l2_subdev *sd, size_t n,
static void init_dll1(struct i2c_client *client)
{
- /* This is the Hauppauge sequence used to
- * initialize the Delay Lock Loop 1 (ADC DLL). */
+ /*
+ * This is the Hauppauge sequence used to
+ * initialize the Delay Lock Loop 1 (ADC DLL).
+ */
cx25840_write(client, 0x159, 0x23);
cx25840_write(client, 0x15a, 0x87);
cx25840_write(client, 0x15b, 0x06);
@@ -337,8 +555,10 @@ static void init_dll1(struct i2c_client *client)
static void init_dll2(struct i2c_client *client)
{
- /* This is the Hauppauge sequence used to
- * initialize the Delay Lock Loop 2 (ADC DLL). */
+ /*
+ * This is the Hauppauge sequence used to
+ * initialize the Delay Lock Loop 2 (ADC DLL).
+ */
cx25840_write(client, 0x15d, 0xe3);
cx25840_write(client, 0x15e, 0x86);
cx25840_write(client, 0x15f, 0x06);
@@ -350,7 +570,11 @@ static void init_dll2(struct i2c_client *client)
static void cx25836_initialize(struct i2c_client *client)
{
- /* reset configuration is described on page 3-77 of the CX25836 datasheet */
+ /*
+ *reset configuration is described on page 3-77
+ * of the CX25836 datasheet
+ */
+
/* 2. */
cx25840_and_or(client, 0x000, ~0x01, 0x01);
cx25840_and_or(client, 0x000, ~0x01, 0x00);
@@ -376,10 +600,96 @@ static void cx25836_initialize(struct i2c_client *client)
static void cx25840_work_handler(struct work_struct *work)
{
struct cx25840_state *state = container_of(work, struct cx25840_state, fw_work);
+
cx25840_loadfw(state->c);
wake_up(&state->fw_wait);
}
+#define CX25840_VCONFIG_SET_BIT(state, opt_msk, voc, idx, bit, oneval) \
+ do { \
+ if ((state)->vid_config & (opt_msk)) { \
+ if (((state)->vid_config & (opt_msk)) == \
+ (oneval)) \
+ (voc)[idx] |= BIT(bit); \
+ else \
+ (voc)[idx] &= ~BIT(bit); \
+ } \
+ } while (0)
+
+/* apply current vconfig to hardware regs */
+static void cx25840_vconfig_apply(struct i2c_client *client)
+{
+ struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+ u8 voutctrl[3];
+ unsigned int i;
+
+ for (i = 0; i < 3; i++)
+ voutctrl[i] = cx25840_read(client, 0x404 + i);
+
+ if (state->vid_config & CX25840_VCONFIG_FMT_MASK)
+ voutctrl[0] &= ~3;
+ switch (state->vid_config & CX25840_VCONFIG_FMT_MASK) {
+ case CX25840_VCONFIG_FMT_BT656:
+ voutctrl[0] |= 1;
+ break;
+
+ case CX25840_VCONFIG_FMT_VIP11:
+ voutctrl[0] |= 2;
+ break;
+
+ case CX25840_VCONFIG_FMT_VIP2:
+ voutctrl[0] |= 3;
+ break;
+
+ case CX25840_VCONFIG_FMT_BT601:
+ /* zero */
+ default:
+ break;
+ }
+
+ CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_RES_MASK, voutctrl,
+ 0, 2, CX25840_VCONFIG_RES_10BIT);
+ CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_VBIRAW_MASK, voutctrl,
+ 0, 3, CX25840_VCONFIG_VBIRAW_ENABLED);
+ CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_ANCDATA_MASK, voutctrl,
+ 0, 4, CX25840_VCONFIG_ANCDATA_ENABLED);
+ CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_TASKBIT_MASK, voutctrl,
+ 0, 5, CX25840_VCONFIG_TASKBIT_ONE);
+ CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_ACTIVE_MASK, voutctrl,
+ 1, 2, CX25840_VCONFIG_ACTIVE_HORIZONTAL);
+ CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_VALID_MASK, voutctrl,
+ 1, 3, CX25840_VCONFIG_VALID_ANDACTIVE);
+ CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_HRESETW_MASK, voutctrl,
+ 1, 4, CX25840_VCONFIG_HRESETW_PIXCLK);
+
+ if (state->vid_config & CX25840_VCONFIG_CLKGATE_MASK)
+ voutctrl[1] &= ~(3 << 6);
+ switch (state->vid_config & CX25840_VCONFIG_CLKGATE_MASK) {
+ case CX25840_VCONFIG_CLKGATE_VALID:
+ voutctrl[1] |= 2;
+ break;
+
+ case CX25840_VCONFIG_CLKGATE_VALIDACTIVE:
+ voutctrl[1] |= 3;
+ break;
+
+ case CX25840_VCONFIG_CLKGATE_NONE:
+ /* zero */
+ default:
+ break;
+ }
+
+ CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_DCMODE_MASK, voutctrl,
+ 2, 0, CX25840_VCONFIG_DCMODE_BYTES);
+ CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_IDID0S_MASK, voutctrl,
+ 2, 1, CX25840_VCONFIG_IDID0S_LINECNT);
+ CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_VIPCLAMP_MASK, voutctrl,
+ 2, 4, CX25840_VCONFIG_VIPCLAMP_ENABLED);
+
+ for (i = 0; i < 3; i++)
+ cx25840_write(client, 0x404 + i, voutctrl[i]);
+}
+
static void cx25840_initialize(struct i2c_client *client)
{
DEFINE_WAIT(wait);
@@ -389,8 +699,10 @@ static void cx25840_initialize(struct i2c_client *client)
/* datasheet startup in numbered steps, refer to page 3-77 */
/* 2. */
cx25840_and_or(client, 0x803, ~0x10, 0x00);
- /* The default of this register should be 4, but I get 0 instead.
- * Set this register to 4 manually. */
+ /*
+ * The default of this register should be 4, but I get 0 instead.
+ * Set this register to 4 manually.
+ */
cx25840_write(client, 0x000, 0x04);
/* 3. */
init_dll1(client);
@@ -400,10 +712,12 @@ static void cx25840_initialize(struct i2c_client *client)
cx25840_write(client, 0x13c, 0x01);
cx25840_write(client, 0x13c, 0x00);
/* 5. */
- /* Do the firmware load in a work handler to prevent.
- Otherwise the kernel is blocked waiting for the
- bit-banging i2c interface to finish uploading the
- firmware. */
+ /*
+ * Do the firmware load in a work handler to prevent.
+ * Otherwise the kernel is blocked waiting for the
+ * bit-banging i2c interface to finish uploading the
+ * firmware.
+ */
INIT_WORK(&state->fw_work, cx25840_work_handler);
init_waitqueue_head(&state->fw_wait);
q = create_singlethread_workqueue("cx25840_fw");
@@ -446,6 +760,9 @@ static void cx25840_initialize(struct i2c_client *client)
/* (re)set input */
set_input(client, state->vid_input, state->aud_input);
+ if (state->generic_mode)
+ cx25840_vconfig_apply(client);
+
/* start microcontroller */
cx25840_and_or(client, 0x803, ~0x10, 0x10);
}
@@ -632,10 +949,12 @@ static void cx23885_initialize(struct i2c_client *client)
cx25840_write(client, 0x160, 0x1d);
cx25840_write(client, 0x164, 0x00);
- /* Do the firmware load in a work handler to prevent.
- Otherwise the kernel is blocked waiting for the
- bit-banging i2c interface to finish uploading the
- firmware. */
+ /*
+ * Do the firmware load in a work handler to prevent.
+ * Otherwise the kernel is blocked waiting for the
+ * bit-banging i2c interface to finish uploading the
+ * firmware.
+ */
INIT_WORK(&state->fw_work, cx25840_work_handler);
init_waitqueue_head(&state->fw_wait);
q = create_singlethread_workqueue("cx25840_fw");
@@ -647,7 +966,8 @@ static void cx23885_initialize(struct i2c_client *client)
destroy_workqueue(q);
}
- /* Call the cx23888 specific std setup func, we no longer rely on
+ /*
+ * Call the cx23888 specific std setup func, we no longer rely on
* the generic cx24840 func.
*/
if (is_cx23888(state))
@@ -669,7 +989,9 @@ static void cx23885_initialize(struct i2c_client *client)
cx25840_write(client, CX25840_AUD_INT_STAT_REG, 0xff);
/* CC raw enable */
- /* - VIP 1.1 control codes - 10bit, blue field enable.
+
+ /*
+ * - VIP 1.1 control codes - 10bit, blue field enable.
* - enable raw data during vertical blanking.
* - enable ancillary Data insertion for 656 or VIP.
*/
@@ -752,10 +1074,12 @@ static void cx231xx_initialize(struct i2c_client *client)
/* White crush, Chroma AGC & Chroma Killer enabled */
cx25840_write(client, 0x401, 0xe8);
- /* Do the firmware load in a work handler to prevent.
- Otherwise the kernel is blocked waiting for the
- bit-banging i2c interface to finish uploading the
- firmware. */
+ /*
+ * Do the firmware load in a work handler to prevent.
+ * Otherwise the kernel is blocked waiting for the
+ * bit-banging i2c interface to finish uploading the
+ * firmware.
+ */
INIT_WORK(&state->fw_work, cx25840_work_handler);
init_waitqueue_head(&state->fw_wait);
q = create_singlethread_workqueue("cx25840_fw");
@@ -800,13 +1124,20 @@ void cx25840_std_setup(struct i2c_client *client)
else
cx25840_write(client, 0x49f, 0x14);
+ /* generic mode uses the values that the chip autoconfig would set */
if (std & V4L2_STD_625_50) {
hblank = 132;
hactive = 720;
burst = 93;
- vblank = 36;
- vactive = 580;
- vblank656 = 40;
+ if (state->generic_mode) {
+ vblank = 34;
+ vactive = 576;
+ vblank656 = 38;
+ } else {
+ vblank = 36;
+ vactive = 580;
+ vblank656 = 40;
+ }
src_decimation = 0x21f;
luma_lpf = 2;
@@ -815,6 +1146,10 @@ void cx25840_std_setup(struct i2c_client *client)
comb = 0;
sc = 0x0a425f;
} else if (std == V4L2_STD_PAL_Nc) {
+ if (state->generic_mode) {
+ burst = 95;
+ luma_lpf = 1;
+ }
uv_lpf = 1;
comb = 0x20;
sc = 556453;
@@ -829,12 +1164,20 @@ void cx25840_std_setup(struct i2c_client *client)
vactive = 487;
luma_lpf = 1;
uv_lpf = 1;
+ if (state->generic_mode) {
+ vblank = 20;
+ vblank656 = 24;
+ }
src_decimation = 0x21f;
if (std == V4L2_STD_PAL_60) {
- vblank = 26;
- vblank656 = 26;
- burst = 0x5b;
+ if (!state->generic_mode) {
+ vblank = 26;
+ vblank656 = 26;
+ burst = 0x5b;
+ } else {
+ burst = 0x59;
+ }
luma_lpf = 2;
comb = 0x20;
sc = 688739;
@@ -845,8 +1188,10 @@ void cx25840_std_setup(struct i2c_client *client)
comb = 0x20;
sc = 555452;
} else {
- vblank = 26;
- vblank656 = 26;
+ if (!state->generic_mode) {
+ vblank = 26;
+ vblank656 = 26;
+ }
burst = 0x5b;
comb = 0x66;
sc = 556063;
@@ -867,24 +1212,28 @@ void cx25840_std_setup(struct i2c_client *client)
int pll = (28636363L * ((((u64)pll_int) << 25L) + pll_frac)) >> 25L;
pll /= pll_post;
- v4l_dbg(1, cx25840_debug, client, "PLL = %d.%06d MHz\n",
- pll / 1000000, pll % 1000000);
- v4l_dbg(1, cx25840_debug, client, "PLL/8 = %d.%06d MHz\n",
- pll / 8000000, (pll / 8) % 1000000);
+ v4l_dbg(1, cx25840_debug, client,
+ "PLL = %d.%06d MHz\n",
+ pll / 1000000, pll % 1000000);
+ v4l_dbg(1, cx25840_debug, client,
+ "PLL/8 = %d.%06d MHz\n",
+ pll / 8000000, (pll / 8) % 1000000);
fin = ((u64)src_decimation * pll) >> 12;
v4l_dbg(1, cx25840_debug, client,
- "ADC Sampling freq = %d.%06d MHz\n",
- fin / 1000000, fin % 1000000);
+ "ADC Sampling freq = %d.%06d MHz\n",
+ fin / 1000000, fin % 1000000);
fsc = (((u64)sc) * pll) >> 24L;
v4l_dbg(1, cx25840_debug, client,
- "Chroma sub-carrier freq = %d.%06d MHz\n",
- fsc / 1000000, fsc % 1000000);
+ "Chroma sub-carrier freq = %d.%06d MHz\n",
+ fsc / 1000000, fsc % 1000000);
- v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, vblank %i, vactive %i, vblank656 %i, src_dec %i, burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x, sc 0x%06x\n",
+ v4l_dbg(1, cx25840_debug, client,
+ "hblank %i, hactive %i, vblank %i, vactive %i, vblank656 %i, src_dec %i, burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x, sc 0x%06x\n",
hblank, hactive, vblank, vactive, vblank656,
- src_decimation, burst, luma_lpf, uv_lpf, comb, sc);
+ src_decimation, burst, luma_lpf, uv_lpf,
+ comb, sc);
}
}
@@ -939,10 +1288,10 @@ static void input_change(struct i2c_client *client)
/* Follow step 8c and 8d of section 3.16 in the cx25840 datasheet */
if (std & V4L2_STD_SECAM) {
cx25840_write(client, 0x402, 0);
- }
- else {
+ } else {
cx25840_write(client, 0x402, 0x04);
- cx25840_write(client, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11);
+ cx25840_write(client, 0x49f,
+ (std & V4L2_STD_NTSC) ? 0x14 : 0x11);
}
cx25840_and_or(client, 0x401, ~0x60, 0);
cx25840_and_or(client, 0x401, ~0x60, 0x60);
@@ -956,13 +1305,14 @@ static void input_change(struct i2c_client *client)
if (state->radio) {
cx25840_write(client, 0x808, 0xf9);
cx25840_write(client, 0x80b, 0x00);
- }
- else if (std & V4L2_STD_525_60) {
- /* Certain Hauppauge PVR150 models have a hardware bug
- that causes audio to drop out. For these models the
- audio standard must be set explicitly.
- To be precise: it affects cards with tuner models
- 85, 99 and 112 (model numbers from tveeprom). */
+ } else if (std & V4L2_STD_525_60) {
+ /*
+ * Certain Hauppauge PVR150 models have a hardware bug
+ * that causes audio to drop out. For these models the
+ * audio standard must be set explicitly.
+ * To be precise: it affects cards with tuner models
+ * 85, 99 and 112 (model numbers from tveeprom).
+ */
int hw_fix = state->pvr150_workaround;
if (std == V4L2_STD_NTSC_M_JP) {
@@ -979,35 +1329,40 @@ static void input_change(struct i2c_client *client)
} else if (std & V4L2_STD_PAL) {
/* Autodetect audio standard and audio system */
cx25840_write(client, 0x808, 0xff);
- /* Since system PAL-L is pretty much non-existent and
- not used by any public broadcast network, force
- 6.5 MHz carrier to be interpreted as System DK,
- this avoids DK audio detection instability */
+ /*
+ * Since system PAL-L is pretty much non-existent and
+ * not used by any public broadcast network, force
+ * 6.5 MHz carrier to be interpreted as System DK,
+ * this avoids DK audio detection instability
+ */
cx25840_write(client, 0x80b, 0x00);
} else if (std & V4L2_STD_SECAM) {
/* Autodetect audio standard and audio system */
cx25840_write(client, 0x808, 0xff);
- /* If only one of SECAM-DK / SECAM-L is required, then force
- 6.5MHz carrier, else autodetect it */
+ /*
+ * If only one of SECAM-DK / SECAM-L is required, then force
+ * 6.5MHz carrier, else autodetect it
+ */
if ((std & V4L2_STD_SECAM_DK) &&
!(std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))) {
/* 6.5 MHz carrier to be interpreted as System DK */
cx25840_write(client, 0x80b, 0x00);
- } else if (!(std & V4L2_STD_SECAM_DK) &&
- (std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))) {
+ } else if (!(std & V4L2_STD_SECAM_DK) &&
+ (std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))) {
/* 6.5 MHz carrier to be interpreted as System L */
cx25840_write(client, 0x80b, 0x08);
- } else {
+ } else {
/* 6.5 MHz carrier to be autodetected */
cx25840_write(client, 0x80b, 0x10);
- }
+ }
}
cx25840_and_or(client, 0x810, ~0x01, 0);
}
-static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input,
- enum cx25840_audio_input aud_input)
+static int set_input(struct i2c_client *client,
+ enum cx25840_video_input vid_input,
+ enum cx25840_audio_input aud_input)
{
struct cx25840_state *state = to_state(i2c_get_clientdata(client));
u8 is_composite = (vid_input >= CX25840_COMPOSITE1 &&
@@ -1032,7 +1387,7 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
vid_input);
reg = vid_input & 0xff;
is_composite = !is_component &&
- ((vid_input & CX25840_SVIDEO_ON) != CX25840_SVIDEO_ON);
+ ((vid_input & CX25840_SVIDEO_ON) != CX25840_SVIDEO_ON);
v4l_dbg(1, cx25840_debug, client, "mux cfg 0x%x comp=%d\n",
reg, is_composite);
@@ -1040,8 +1395,10 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
reg = 0xf0 + (vid_input - CX25840_COMPOSITE1);
} else {
if ((vid_input & ~0xff0) ||
- luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA8 ||
- chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) {
+ luma < CX25840_SVIDEO_LUMA1 ||
+ luma > CX25840_SVIDEO_LUMA8 ||
+ chroma < CX25840_SVIDEO_CHROMA4 ||
+ chroma > CX25840_SVIDEO_CHROMA8) {
v4l_err(client, "0x%04x is not a valid video input!\n",
vid_input);
return -EINVAL;
@@ -1065,12 +1422,24 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
case CX25840_AUDIO_SERIAL:
/* do nothing, use serial audio input */
break;
- case CX25840_AUDIO4: reg &= ~0x30; break;
- case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break;
- case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break;
- case CX25840_AUDIO7: reg &= ~0xc0; break;
- case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break;
-
+ case CX25840_AUDIO4:
+ reg &= ~0x30;
+ break;
+ case CX25840_AUDIO5:
+ reg &= ~0x30;
+ reg |= 0x10;
+ break;
+ case CX25840_AUDIO6:
+ reg &= ~0x30;
+ reg |= 0x20;
+ break;
+ case CX25840_AUDIO7:
+ reg &= ~0xc0;
+ break;
+ case CX25840_AUDIO8:
+ reg &= ~0xc0;
+ reg |= 0x40;
+ break;
default:
v4l_err(client, "0x%04x is not a valid audio input!\n",
aud_input);
@@ -1087,7 +1456,6 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02);
if (is_cx2388x(state)) {
-
/* Enable or disable the DIF for tuner use */
if (is_dif) {
cx25840_and_or(client, 0x102, ~0x80, 0x80);
@@ -1118,15 +1486,23 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
cx25840_write4(client, 0x410, 0xffff0dbf);
cx25840_write4(client, 0x414, 0x00137d03);
- cx25840_write4(client, state->vbi_regs_offset + 0x42c, 0x42600000);
- cx25840_write4(client, state->vbi_regs_offset + 0x430, 0x0000039b);
- cx25840_write4(client, state->vbi_regs_offset + 0x438, 0x00000000);
-
- cx25840_write4(client, state->vbi_regs_offset + 0x440, 0xF8E3E824);
- cx25840_write4(client, state->vbi_regs_offset + 0x444, 0x401040dc);
- cx25840_write4(client, state->vbi_regs_offset + 0x448, 0xcd3f02a0);
- cx25840_write4(client, state->vbi_regs_offset + 0x44c, 0x161f1000);
- cx25840_write4(client, state->vbi_regs_offset + 0x450, 0x00000802);
+ cx25840_write4(client, state->vbi_regs_offset + 0x42c,
+ 0x42600000);
+ cx25840_write4(client, state->vbi_regs_offset + 0x430,
+ 0x0000039b);
+ cx25840_write4(client, state->vbi_regs_offset + 0x438,
+ 0x00000000);
+
+ cx25840_write4(client, state->vbi_regs_offset + 0x440,
+ 0xF8E3E824);
+ cx25840_write4(client, state->vbi_regs_offset + 0x444,
+ 0x401040dc);
+ cx25840_write4(client, state->vbi_regs_offset + 0x448,
+ 0xcd3f02a0);
+ cx25840_write4(client, state->vbi_regs_offset + 0x44c,
+ 0x161f1000);
+ cx25840_write4(client, state->vbi_regs_offset + 0x450,
+ 0x00000802);
cx25840_write4(client, 0x91c, 0x01000000);
cx25840_write4(client, 0x8e0, 0x03063870);
@@ -1193,8 +1569,9 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
* Only one of the two will be in use.
*/
cx25840_write4(client, AFE_CTRL, val);
- } else
+ } else {
cx25840_and_or(client, 0x102, ~0x2, 0);
+ }
}
state->vid_input = vid_input;
@@ -1233,29 +1610,32 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
cx25840_write(client, 0x919, 0x01);
}
- if (is_cx2388x(state) && ((aud_input == CX25840_AUDIO7) ||
- (aud_input == CX25840_AUDIO6))) {
+ if (is_cx2388x(state) &&
+ ((aud_input == CX25840_AUDIO7) || (aud_input == CX25840_AUDIO6))) {
/* Configure audio from LR1 or LR2 input */
cx25840_write4(client, 0x910, 0);
cx25840_write4(client, 0x8d0, 0x63073);
- } else
- if (is_cx2388x(state) && (aud_input == CX25840_AUDIO8)) {
+ } else if (is_cx2388x(state) && (aud_input == CX25840_AUDIO8)) {
/* Configure audio from tuner/sif input */
cx25840_write4(client, 0x910, 0x12b000c9);
cx25840_write4(client, 0x8d0, 0x1f063870);
}
if (is_cx23888(state)) {
- /* HVR1850 */
- /* AUD_IO_CTRL - I2S Input, Parallel1*/
- /* - Channel 1 src - Parallel1 (Merlin out) */
- /* - Channel 2 src - Parallel2 (Merlin out) */
- /* - Channel 3 src - Parallel3 (Merlin AC97 out) */
- /* - I2S source and dir - Merlin, output */
+ /*
+ * HVR1850
+ *
+ * AUD_IO_CTRL - I2S Input, Parallel1
+ * - Channel 1 src - Parallel1 (Merlin out)
+ * - Channel 2 src - Parallel2 (Merlin out)
+ * - Channel 3 src - Parallel3 (Merlin AC97 out)
+ * - I2S source and dir - Merlin, output
+ */
cx25840_write4(client, 0x124, 0x100);
if (!is_dif) {
- /* Stop microcontroller if we don't need it
+ /*
+ * Stop microcontroller if we don't need it
* to avoid audio popping on svideo/composite use.
*/
cx25840_and_or(client, 0x803, ~0x10, 0x00);
@@ -1297,11 +1677,14 @@ static int set_v4lstd(struct i2c_client *client)
fmt = 0xc;
}
- v4l_dbg(1, cx25840_debug, client, "changing video std to fmt %i\n",fmt);
+ v4l_dbg(1, cx25840_debug, client,
+ "changing video std to fmt %i\n", fmt);
- /* Follow step 9 of section 3.16 in the cx25840 datasheet.
- Without this PAL may display a vertical ghosting effect.
- This happens for example with the Yuan MPC622. */
+ /*
+ * Follow step 9 of section 3.16 in the cx25840 datasheet.
+ * Without this PAL may display a vertical ghosting effect.
+ * This happens for example with the Yuan MPC622.
+ */
if (fmt >= 4 && fmt < 8) {
/* Set format to NTSC-M */
cx25840_and_or(client, 0x400, ~0xf, 1);
@@ -1363,14 +1746,15 @@ static int cx25840_s_ctrl(struct v4l2_ctrl *ctrl)
/* ----------------------------------------------------------------------- */
static int cx25840_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_format *format)
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *fmt = &format->format;
struct cx25840_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
- int HSC, VSC, Vsrc, Hsrc, filter, Vlines;
- int is_50Hz = !(state->std & V4L2_STD_525_60);
+ u32 hsc, vsc, v_src, h_src, v_add;
+ int filter;
+ int is_50hz = !(state->std & V4L2_STD_525_60);
if (format->pad || fmt->code != MEDIA_BUS_FMT_FIXED)
return -EINVAL;
@@ -1379,42 +1763,63 @@ static int cx25840_set_fmt(struct v4l2_subdev *sd,
fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
if (is_cx23888(state)) {
- Vsrc = (cx25840_read(client, 0x42a) & 0x3f) << 4;
- Vsrc |= (cx25840_read(client, 0x429) & 0xf0) >> 4;
+ v_src = (cx25840_read(client, 0x42a) & 0x3f) << 4;
+ v_src |= (cx25840_read(client, 0x429) & 0xf0) >> 4;
} else {
- Vsrc = (cx25840_read(client, 0x476) & 0x3f) << 4;
- Vsrc |= (cx25840_read(client, 0x475) & 0xf0) >> 4;
+ v_src = (cx25840_read(client, 0x476) & 0x3f) << 4;
+ v_src |= (cx25840_read(client, 0x475) & 0xf0) >> 4;
}
if (is_cx23888(state)) {
- Hsrc = (cx25840_read(client, 0x426) & 0x3f) << 4;
- Hsrc |= (cx25840_read(client, 0x425) & 0xf0) >> 4;
+ h_src = (cx25840_read(client, 0x426) & 0x3f) << 4;
+ h_src |= (cx25840_read(client, 0x425) & 0xf0) >> 4;
} else {
- Hsrc = (cx25840_read(client, 0x472) & 0x3f) << 4;
- Hsrc |= (cx25840_read(client, 0x471) & 0xf0) >> 4;
+ h_src = (cx25840_read(client, 0x472) & 0x3f) << 4;
+ h_src |= (cx25840_read(client, 0x471) & 0xf0) >> 4;
}
- Vlines = fmt->height + (is_50Hz ? 4 : 7);
+ if (!state->generic_mode) {
+ v_add = is_50hz ? 4 : 7;
- /*
- * We keep 1 margin for the Vsrc < Vlines check since the
- * cx23888 reports a Vsrc of 486 instead of 487 for the NTSC
- * height. Without that margin the cx23885 fails in this
- * check.
- */
- if ((fmt->width == 0) || (Vlines == 0) ||
- (fmt->width * 16 < Hsrc) || (Hsrc < fmt->width) ||
- (Vlines * 8 < Vsrc) || (Vsrc + 1 < Vlines)) {
- v4l_err(client, "%dx%d is not a valid size!\n",
- fmt->width, fmt->height);
- return -ERANGE;
+ /*
+ * cx23888 in 525-line mode is programmed for 486 active lines
+ * while other chips use 487 active lines.
+ *
+ * See reg 0x428 bits [21:12] in cx23888_std_setup() vs
+ * vactive in cx25840_std_setup().
+ */
+ if (is_cx23888(state) && !is_50hz)
+ v_add--;
+ } else {
+ v_add = 0;
}
+
+ if (h_src == 0 ||
+ v_src <= v_add) {
+ v4l_err(client,
+ "chip reported picture size (%u x %u) is far too small\n",
+ (unsigned int)h_src, (unsigned int)v_src);
+ /*
+ * that's the best we can do since the output picture
+ * size is completely unknown in this case
+ */
+ return -EINVAL;
+ }
+
+ fmt->width = clamp(fmt->width, (h_src + 15) / 16, h_src);
+
+ if (v_add * 8 >= v_src)
+ fmt->height = clamp(fmt->height, (u32)1, v_src - v_add);
+ else
+ fmt->height = clamp(fmt->height, (v_src - v_add * 8 + 7) / 8,
+ v_src - v_add);
+
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
return 0;
- HSC = (Hsrc * (1 << 20)) / fmt->width - (1 << 20);
- VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9));
- VSC &= 0x1fff;
+ hsc = (h_src * (1 << 20)) / fmt->width - (1 << 20);
+ vsc = (1 << 16) - (v_src * (1 << 9) / (fmt->height + v_add) - (1 << 9));
+ vsc &= 0x1fff;
if (fmt->width >= 385)
filter = 0;
@@ -1425,21 +1830,23 @@ static int cx25840_set_fmt(struct v4l2_subdev *sd,
else
filter = 3;
- v4l_dbg(1, cx25840_debug, client, "decoder set size %dx%d -> scale %ux%u\n",
- fmt->width, fmt->height, HSC, VSC);
+ v4l_dbg(1, cx25840_debug, client,
+ "decoder set size %u x %u with scale %x x %x\n",
+ (unsigned int)fmt->width, (unsigned int)fmt->height,
+ (unsigned int)hsc, (unsigned int)vsc);
- /* HSCALE=HSC */
+ /* HSCALE=hsc */
if (is_cx23888(state)) {
- cx25840_write4(client, 0x434, HSC | (1 << 24));
- /* VSCALE=VSC VS_INTRLACE=1 VFILT=filter */
- cx25840_write4(client, 0x438, VSC | (1 << 19) | (filter << 16));
+ cx25840_write4(client, 0x434, hsc | (1 << 24));
+ /* VSCALE=vsc VS_INTRLACE=1 VFILT=filter */
+ cx25840_write4(client, 0x438, vsc | (1 << 19) | (filter << 16));
} else {
- cx25840_write(client, 0x418, HSC & 0xff);
- cx25840_write(client, 0x419, (HSC >> 8) & 0xff);
- cx25840_write(client, 0x41a, HSC >> 16);
- /* VSCALE=VSC */
- cx25840_write(client, 0x41c, VSC & 0xff);
- cx25840_write(client, 0x41d, VSC >> 8);
+ cx25840_write(client, 0x418, hsc & 0xff);
+ cx25840_write(client, 0x419, (hsc >> 8) & 0xff);
+ cx25840_write(client, 0x41a, hsc >> 16);
+ /* VSCALE=vsc */
+ cx25840_write(client, 0x41c, vsc & 0xff);
+ cx25840_write(client, 0x41d, vsc >> 8);
/* VS_INTRLACE=1 VFILT=filter */
cx25840_write(client, 0x41e, 0x8 | filter);
}
@@ -1466,23 +1873,25 @@ static void log_video_status(struct i2c_client *client)
int vid_input = state->vid_input;
v4l_info(client, "Video signal: %spresent\n",
- (gen_stat2 & 0x20) ? "" : "not ");
+ (gen_stat2 & 0x20) ? "" : "not ");
v4l_info(client, "Detected format: %s\n",
- fmt_strs[gen_stat1 & 0xf]);
+ fmt_strs[gen_stat1 & 0xf]);
v4l_info(client, "Specified standard: %s\n",
- vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
+ vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
if (vid_input >= CX25840_COMPOSITE1 &&
vid_input <= CX25840_COMPOSITE8) {
v4l_info(client, "Specified video input: Composite %d\n",
- vid_input - CX25840_COMPOSITE1 + 1);
+ vid_input - CX25840_COMPOSITE1 + 1);
} else {
- v4l_info(client, "Specified video input: S-Video (Luma In%d, Chroma In%d)\n",
- (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
+ v4l_info(client,
+ "Specified video input: S-Video (Luma In%d, Chroma In%d)\n",
+ (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
}
- v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq);
+ v4l_info(client, "Specified audioclock freq: %d Hz\n",
+ state->audclk_freq);
}
/* ----------------------------------------------------------------------- */
@@ -1501,177 +1910,434 @@ static void log_audio_status(struct i2c_client *client)
char *p;
switch (mod_det_stat0) {
- case 0x00: p = "mono"; break;
- case 0x01: p = "stereo"; break;
- case 0x02: p = "dual"; break;
- case 0x04: p = "tri"; break;
- case 0x10: p = "mono with SAP"; break;
- case 0x11: p = "stereo with SAP"; break;
- case 0x12: p = "dual with SAP"; break;
- case 0x14: p = "tri with SAP"; break;
- case 0xfe: p = "forced mode"; break;
- default: p = "not defined";
+ case 0x00:
+ p = "mono";
+ break;
+ case 0x01:
+ p = "stereo";
+ break;
+ case 0x02:
+ p = "dual";
+ break;
+ case 0x04:
+ p = "tri";
+ break;
+ case 0x10:
+ p = "mono with SAP";
+ break;
+ case 0x11:
+ p = "stereo with SAP";
+ break;
+ case 0x12:
+ p = "dual with SAP";
+ break;
+ case 0x14:
+ p = "tri with SAP";
+ break;
+ case 0xfe:
+ p = "forced mode";
+ break;
+ default:
+ p = "not defined";
}
v4l_info(client, "Detected audio mode: %s\n", p);
switch (mod_det_stat1) {
- case 0x00: p = "not defined"; break;
- case 0x01: p = "EIAJ"; break;
- case 0x02: p = "A2-M"; break;
- case 0x03: p = "A2-BG"; break;
- case 0x04: p = "A2-DK1"; break;
- case 0x05: p = "A2-DK2"; break;
- case 0x06: p = "A2-DK3"; break;
- case 0x07: p = "A1 (6.0 MHz FM Mono)"; break;
- case 0x08: p = "AM-L"; break;
- case 0x09: p = "NICAM-BG"; break;
- case 0x0a: p = "NICAM-DK"; break;
- case 0x0b: p = "NICAM-I"; break;
- case 0x0c: p = "NICAM-L"; break;
- case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break;
- case 0x0e: p = "IF FM Radio"; break;
- case 0x0f: p = "BTSC"; break;
- case 0x10: p = "high-deviation FM"; break;
- case 0x11: p = "very high-deviation FM"; break;
- case 0xfd: p = "unknown audio standard"; break;
- case 0xfe: p = "forced audio standard"; break;
- case 0xff: p = "no detected audio standard"; break;
- default: p = "not defined";
+ case 0x00:
+ p = "not defined";
+ break;
+ case 0x01:
+ p = "EIAJ";
+ break;
+ case 0x02:
+ p = "A2-M";
+ break;
+ case 0x03:
+ p = "A2-BG";
+ break;
+ case 0x04:
+ p = "A2-DK1";
+ break;
+ case 0x05:
+ p = "A2-DK2";
+ break;
+ case 0x06:
+ p = "A2-DK3";
+ break;
+ case 0x07:
+ p = "A1 (6.0 MHz FM Mono)";
+ break;
+ case 0x08:
+ p = "AM-L";
+ break;
+ case 0x09:
+ p = "NICAM-BG";
+ break;
+ case 0x0a:
+ p = "NICAM-DK";
+ break;
+ case 0x0b:
+ p = "NICAM-I";
+ break;
+ case 0x0c:
+ p = "NICAM-L";
+ break;
+ case 0x0d:
+ p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)";
+ break;
+ case 0x0e:
+ p = "IF FM Radio";
+ break;
+ case 0x0f:
+ p = "BTSC";
+ break;
+ case 0x10:
+ p = "high-deviation FM";
+ break;
+ case 0x11:
+ p = "very high-deviation FM";
+ break;
+ case 0xfd:
+ p = "unknown audio standard";
+ break;
+ case 0xfe:
+ p = "forced audio standard";
+ break;
+ case 0xff:
+ p = "no detected audio standard";
+ break;
+ default:
+ p = "not defined";
}
v4l_info(client, "Detected audio standard: %s\n", p);
v4l_info(client, "Audio microcontroller: %s\n",
- (download_ctl & 0x10) ?
- ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped");
+ (download_ctl & 0x10) ?
+ ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped");
switch (audio_config >> 4) {
- case 0x00: p = "undefined"; break;
- case 0x01: p = "BTSC"; break;
- case 0x02: p = "EIAJ"; break;
- case 0x03: p = "A2-M"; break;
- case 0x04: p = "A2-BG"; break;
- case 0x05: p = "A2-DK1"; break;
- case 0x06: p = "A2-DK2"; break;
- case 0x07: p = "A2-DK3"; break;
- case 0x08: p = "A1 (6.0 MHz FM Mono)"; break;
- case 0x09: p = "AM-L"; break;
- case 0x0a: p = "NICAM-BG"; break;
- case 0x0b: p = "NICAM-DK"; break;
- case 0x0c: p = "NICAM-I"; break;
- case 0x0d: p = "NICAM-L"; break;
- case 0x0e: p = "FM radio"; break;
- case 0x0f: p = "automatic detection"; break;
- default: p = "undefined";
+ case 0x00:
+ p = "undefined";
+ break;
+ case 0x01:
+ p = "BTSC";
+ break;
+ case 0x02:
+ p = "EIAJ";
+ break;
+ case 0x03:
+ p = "A2-M";
+ break;
+ case 0x04:
+ p = "A2-BG";
+ break;
+ case 0x05:
+ p = "A2-DK1";
+ break;
+ case 0x06:
+ p = "A2-DK2";
+ break;
+ case 0x07:
+ p = "A2-DK3";
+ break;
+ case 0x08:
+ p = "A1 (6.0 MHz FM Mono)";
+ break;
+ case 0x09:
+ p = "AM-L";
+ break;
+ case 0x0a:
+ p = "NICAM-BG";
+ break;
+ case 0x0b:
+ p = "NICAM-DK";
+ break;
+ case 0x0c:
+ p = "NICAM-I";
+ break;
+ case 0x0d:
+ p = "NICAM-L";
+ break;
+ case 0x0e:
+ p = "FM radio";
+ break;
+ case 0x0f:
+ p = "automatic detection";
+ break;
+ default:
+ p = "undefined";
}
v4l_info(client, "Configured audio standard: %s\n", p);
if ((audio_config >> 4) < 0xF) {
switch (audio_config & 0xF) {
- case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break;
- case 0x01: p = "MONO2 (LANGUAGE B)"; break;
- case 0x02: p = "MONO3 (STEREO forced MONO)"; break;
- case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break;
- case 0x04: p = "STEREO"; break;
- case 0x05: p = "DUAL1 (AB)"; break;
- case 0x06: p = "DUAL2 (AC) (FM)"; break;
- case 0x07: p = "DUAL3 (BC) (FM)"; break;
- case 0x08: p = "DUAL4 (AC) (AM)"; break;
- case 0x09: p = "DUAL5 (BC) (AM)"; break;
- case 0x0a: p = "SAP"; break;
- default: p = "undefined";
+ case 0x00:
+ p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)";
+ break;
+ case 0x01:
+ p = "MONO2 (LANGUAGE B)";
+ break;
+ case 0x02:
+ p = "MONO3 (STEREO forced MONO)";
+ break;
+ case 0x03:
+ p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)";
+ break;
+ case 0x04:
+ p = "STEREO";
+ break;
+ case 0x05:
+ p = "DUAL1 (AB)";
+ break;
+ case 0x06:
+ p = "DUAL2 (AC) (FM)";
+ break;
+ case 0x07:
+ p = "DUAL3 (BC) (FM)";
+ break;
+ case 0x08:
+ p = "DUAL4 (AC) (AM)";
+ break;
+ case 0x09:
+ p = "DUAL5 (BC) (AM)";
+ break;
+ case 0x0a:
+ p = "SAP";
+ break;
+ default:
+ p = "undefined";
}
v4l_info(client, "Configured audio mode: %s\n", p);
} else {
switch (audio_config & 0xF) {
- case 0x00: p = "BG"; break;
- case 0x01: p = "DK1"; break;
- case 0x02: p = "DK2"; break;
- case 0x03: p = "DK3"; break;
- case 0x04: p = "I"; break;
- case 0x05: p = "L"; break;
- case 0x06: p = "BTSC"; break;
- case 0x07: p = "EIAJ"; break;
- case 0x08: p = "A2-M"; break;
- case 0x09: p = "FM Radio"; break;
- case 0x0f: p = "automatic standard and mode detection"; break;
- default: p = "undefined";
+ case 0x00:
+ p = "BG";
+ break;
+ case 0x01:
+ p = "DK1";
+ break;
+ case 0x02:
+ p = "DK2";
+ break;
+ case 0x03:
+ p = "DK3";
+ break;
+ case 0x04:
+ p = "I";
+ break;
+ case 0x05:
+ p = "L";
+ break;
+ case 0x06:
+ p = "BTSC";
+ break;
+ case 0x07:
+ p = "EIAJ";
+ break;
+ case 0x08:
+ p = "A2-M";
+ break;
+ case 0x09:
+ p = "FM Radio";
+ break;
+ case 0x0f:
+ p = "automatic standard and mode detection";
+ break;
+ default:
+ p = "undefined";
}
v4l_info(client, "Configured audio system: %s\n", p);
}
if (aud_input) {
- v4l_info(client, "Specified audio input: Tuner (In%d)\n", aud_input);
+ v4l_info(client, "Specified audio input: Tuner (In%d)\n",
+ aud_input);
} else {
v4l_info(client, "Specified audio input: External\n");
}
switch (pref_mode & 0xf) {
- case 0: p = "mono/language A"; break;
- case 1: p = "language B"; break;
- case 2: p = "language C"; break;
- case 3: p = "analog fallback"; break;
- case 4: p = "stereo"; break;
- case 5: p = "language AC"; break;
- case 6: p = "language BC"; break;
- case 7: p = "language AB"; break;
- default: p = "undefined";
+ case 0:
+ p = "mono/language A";
+ break;
+ case 1:
+ p = "language B";
+ break;
+ case 2:
+ p = "language C";
+ break;
+ case 3:
+ p = "analog fallback";
+ break;
+ case 4:
+ p = "stereo";
+ break;
+ case 5:
+ p = "language AC";
+ break;
+ case 6:
+ p = "language BC";
+ break;
+ case 7:
+ p = "language AB";
+ break;
+ default:
+ p = "undefined";
}
v4l_info(client, "Preferred audio mode: %s\n", p);
if ((audio_config & 0xf) == 0xf) {
switch ((afc0 >> 3) & 0x3) {
- case 0: p = "system DK"; break;
- case 1: p = "system L"; break;
- case 2: p = "autodetect"; break;
- default: p = "undefined";
+ case 0:
+ p = "system DK";
+ break;
+ case 1:
+ p = "system L";
+ break;
+ case 2:
+ p = "autodetect";
+ break;
+ default:
+ p = "undefined";
}
v4l_info(client, "Selected 65 MHz format: %s\n", p);
switch (afc0 & 0x7) {
- case 0: p = "chroma"; break;
- case 1: p = "BTSC"; break;
- case 2: p = "EIAJ"; break;
- case 3: p = "A2-M"; break;
- case 4: p = "autodetect"; break;
- default: p = "undefined";
+ case 0:
+ p = "chroma";
+ break;
+ case 1:
+ p = "BTSC";
+ break;
+ case 2:
+ p = "EIAJ";
+ break;
+ case 3:
+ p = "A2-M";
+ break;
+ case 4:
+ p = "autodetect";
+ break;
+ default:
+ p = "undefined";
}
v4l_info(client, "Selected 45 MHz format: %s\n", p);
}
}
+#define CX25840_VCONFIG_OPTION(state, cfg_in, opt_msk) \
+ do { \
+ if ((cfg_in) & (opt_msk)) { \
+ (state)->vid_config &= ~(opt_msk); \
+ (state)->vid_config |= (cfg_in) & (opt_msk); \
+ } \
+ } while (0)
+
+/* apply incoming options to the current vconfig */
+static void cx25840_vconfig_add(struct cx25840_state *state, u32 cfg_in)
+{
+ CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_FMT_MASK);
+ CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_RES_MASK);
+ CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_VBIRAW_MASK);
+ CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_ANCDATA_MASK);
+ CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_TASKBIT_MASK);
+ CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_ACTIVE_MASK);
+ CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_VALID_MASK);
+ CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_HRESETW_MASK);
+ CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_CLKGATE_MASK);
+ CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_DCMODE_MASK);
+ CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_IDID0S_MASK);
+ CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_VIPCLAMP_MASK);
+}
+
/* ----------------------------------------------------------------------- */
-/* This load_fw operation must be called to load the driver's firmware.
- Without this the audio standard detection will fail and you will
- only get mono.
+/*
+ * Initializes the device in the generic mode.
+ * For cx2584x chips also adds additional video output settings provided
+ * in @val parameter (CX25840_VCONFIG_*).
+ *
+ * The generic mode disables some of the ivtv-related hacks in this driver.
+ * For cx2584x chips it also enables setting video output configuration while
+ * setting it according to datasheet defaults by default.
+ */
+static int cx25840_init(struct v4l2_subdev *sd, u32 val)
+{
+ struct cx25840_state *state = to_state(sd);
- Since loading the firmware is often problematic when the driver is
- compiled into the kernel I recommend postponing calling this function
- until the first open of the video device. Another reason for
- postponing it is that loading this firmware takes a long time (seconds)
- due to the slow i2c bus speed. So it will speed up the boot process if
- you can avoid loading the fw as long as the video device isn't used. */
-static int cx25840_load_fw(struct v4l2_subdev *sd)
+ state->generic_mode = true;
+
+ if (is_cx2584x(state)) {
+ /* set datasheet video output defaults */
+ state->vid_config = CX25840_VCONFIG_FMT_BT656 |
+ CX25840_VCONFIG_RES_8BIT |
+ CX25840_VCONFIG_VBIRAW_DISABLED |
+ CX25840_VCONFIG_ANCDATA_ENABLED |
+ CX25840_VCONFIG_TASKBIT_ONE |
+ CX25840_VCONFIG_ACTIVE_HORIZONTAL |
+ CX25840_VCONFIG_VALID_NORMAL |
+ CX25840_VCONFIG_HRESETW_NORMAL |
+ CX25840_VCONFIG_CLKGATE_NONE |
+ CX25840_VCONFIG_DCMODE_DWORDS |
+ CX25840_VCONFIG_IDID0S_NORMAL |
+ CX25840_VCONFIG_VIPCLAMP_DISABLED;
+
+ /* add additional settings */
+ cx25840_vconfig_add(state, val);
+ } else {
+ /* TODO: generic mode needs to be developed for other chips */
+ WARN_ON(1);
+ }
+
+ return 0;
+}
+
+static int cx25840_reset(struct v4l2_subdev *sd, u32 val)
{
struct cx25840_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
+ if (is_cx2583x(state))
+ cx25836_initialize(client);
+ else if (is_cx2388x(state))
+ cx23885_initialize(client);
+ else if (is_cx231xx(state))
+ cx231xx_initialize(client);
+ else
+ cx25840_initialize(client);
+
+ state->is_initialized = 1;
+
+ return 0;
+}
+
+/*
+ * This load_fw operation must be called to load the driver's firmware.
+ * This will load the firmware on the first invocation (further ones are NOP).
+ * Without this the audio standard detection will fail and you will
+ * only get mono.
+ * Alternatively, you can call the reset operation instead of this one.
+ *
+ * Since loading the firmware is often problematic when the driver is
+ * compiled into the kernel I recommend postponing calling this function
+ * until the first open of the video device. Another reason for
+ * postponing it is that loading this firmware takes a long time (seconds)
+ * due to the slow i2c bus speed. So it will speed up the boot process if
+ * you can avoid loading the fw as long as the video device isn't used.
+ */
+static int cx25840_load_fw(struct v4l2_subdev *sd)
+{
+ struct cx25840_state *state = to_state(sd);
+
if (!state->is_initialized) {
/* initialize and load firmware */
- state->is_initialized = 1;
- if (is_cx2583x(state))
- cx25836_initialize(client);
- else if (is_cx2388x(state))
- cx23885_initialize(client);
- else if (is_cx231xx(state))
- cx231xx_initialize(client);
- else
- cx25840_initialize(client);
+ cx25840_reset(sd, 0);
}
return 0;
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int cx25840_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+static int cx25840_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -1680,7 +2346,8 @@ static int cx25840_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
return 0;
}
-static int cx25840_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
+static int cx25840_s_register(struct v4l2_subdev *sd,
+ const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -1699,7 +2366,7 @@ static int cx25840_s_audio_stream(struct v4l2_subdev *sd, int enable)
return 0;
v4l_dbg(1, cx25840_debug, client, "%s audio output\n",
- enable ? "enable" : "disable");
+ enable ? "enable" : "disable");
if (enable) {
v = cx25840_read(client, 0x115) | 0x80;
@@ -1722,7 +2389,7 @@ static int cx25840_s_stream(struct v4l2_subdev *sd, int enable)
u8 v;
v4l_dbg(1, cx25840_debug, client, "%s video output\n",
- enable ? "enable" : "disable");
+ enable ? "enable" : "disable");
/*
* It's not clear what should be done for these devices.
@@ -1749,7 +2416,7 @@ static int cx25840_s_stream(struct v4l2_subdev *sd, int enable)
}
/* Query the current detected video format */
-static int cx25840_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
+static int cx25840_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -1775,10 +2442,11 @@ static int cx25840_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
};
u32 fmt = (cx25840_read4(client, 0x40c) >> 8) & 0xf;
- *std = stds[ fmt ];
+ *std = stds[fmt];
- v4l_dbg(1, cx25840_debug, client, "g_std fmt = %x, v4l2_std_id = 0x%x\n",
- fmt, (unsigned int)stds[ fmt ]);
+ v4l_dbg(1, cx25840_debug, client,
+ "querystd fmt = %x, v4l2_std_id = 0x%x\n",
+ fmt, (unsigned int)stds[fmt]);
return 0;
}
@@ -1787,7 +2455,8 @@ static int cx25840_g_input_status(struct v4l2_subdev *sd, u32 *status)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- /* A limited function that checks for signal status and returns
+ /*
+ * A limited function that checks for signal status and returns
* the state.
*/
@@ -1798,6 +2467,15 @@ static int cx25840_g_input_status(struct v4l2_subdev *sd, u32 *status)
return 0;
}
+static int cx25840_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+ struct cx25840_state *state = to_state(sd);
+
+ *std = state->std;
+
+ return 0;
+}
+
static int cx25840_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
{
struct cx25840_state *state = to_state(sd);
@@ -1827,6 +2505,11 @@ static int cx25840_s_video_routing(struct v4l2_subdev *sd,
if (is_cx23888(state))
cx23888_std_setup(client);
+ if (is_cx2584x(state) && state->generic_mode && config) {
+ cx25840_vconfig_add(state, config);
+ cx25840_vconfig_apply(client);
+ }
+
return set_input(client, input, state->aud_input);
}
@@ -1841,7 +2524,8 @@ static int cx25840_s_audio_routing(struct v4l2_subdev *sd,
return set_input(client, state->vid_input, input);
}
-static int cx25840_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *freq)
+static int cx25840_s_frequency(struct v4l2_subdev *sd,
+ const struct v4l2_frequency *freq)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -1864,9 +2548,8 @@ static int cx25840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
if (is_cx2583x(state))
return 0;
- vt->capability |=
- V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
- V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
+ vt->capability |= V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
+ V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
mode = cx25840_read(client, 0x804);
@@ -1896,54 +2579,46 @@ static int cx25840_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt)
return 0;
switch (vt->audmode) {
- case V4L2_TUNER_MODE_MONO:
- /* mono -> mono
- stereo -> mono
- bilingual -> lang1 */
- cx25840_and_or(client, 0x809, ~0xf, 0x00);
- break;
- case V4L2_TUNER_MODE_STEREO:
- case V4L2_TUNER_MODE_LANG1:
- /* mono -> mono
- stereo -> stereo
- bilingual -> lang1 */
- cx25840_and_or(client, 0x809, ~0xf, 0x04);
- break;
- case V4L2_TUNER_MODE_LANG1_LANG2:
- /* mono -> mono
- stereo -> stereo
- bilingual -> lang1/lang2 */
- cx25840_and_or(client, 0x809, ~0xf, 0x07);
- break;
- case V4L2_TUNER_MODE_LANG2:
- /* mono -> mono
- stereo -> stereo
- bilingual -> lang2 */
- cx25840_and_or(client, 0x809, ~0xf, 0x01);
- break;
- default:
- return -EINVAL;
+ case V4L2_TUNER_MODE_MONO:
+ /*
+ * mono -> mono
+ * stereo -> mono
+ * bilingual -> lang1
+ */
+ cx25840_and_or(client, 0x809, ~0xf, 0x00);
+ break;
+ case V4L2_TUNER_MODE_STEREO:
+ case V4L2_TUNER_MODE_LANG1:
+ /*
+ * mono -> mono
+ * stereo -> stereo
+ * bilingual -> lang1
+ */
+ cx25840_and_or(client, 0x809, ~0xf, 0x04);
+ break;
+ case V4L2_TUNER_MODE_LANG1_LANG2:
+ /*
+ * mono -> mono
+ * stereo -> stereo
+ * bilingual -> lang1/lang2
+ */
+ cx25840_and_or(client, 0x809, ~0xf, 0x07);
+ break;
+ case V4L2_TUNER_MODE_LANG2:
+ /*
+ * mono -> mono
+ * stereo -> stereo
+ * bilingual -> lang2
+ */
+ cx25840_and_or(client, 0x809, ~0xf, 0x01);
+ break;
+ default:
+ return -EINVAL;
}
state->audmode = vt->audmode;
return 0;
}
-static int cx25840_reset(struct v4l2_subdev *sd, u32 val)
-{
- struct cx25840_state *state = to_state(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (is_cx2583x(state))
- cx25836_initialize(client);
- else if (is_cx2388x(state))
- cx23885_initialize(client);
- else if (is_cx231xx(state))
- cx231xx_initialize(client);
- else
- cx25840_initialize(client);
- return 0;
-}
-
static int cx25840_log_status(struct v4l2_subdev *sd)
{
struct cx25840_state *state = to_state(sd);
@@ -5050,6 +5725,8 @@ static const struct v4l2_ctrl_ops cx25840_ctrl_ops = {
static const struct v4l2_subdev_core_ops cx25840_core_ops = {
.log_status = cx25840_log_status,
.reset = cx25840_reset,
+ /* calling the (optional) init op will turn on the generic mode */
+ .init = cx25840_init,
.load_fw = cx25840_load_fw,
.s_io_pin_config = common_s_io_pin_config,
#ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -5073,8 +5750,9 @@ static const struct v4l2_subdev_audio_ops cx25840_audio_ops = {
};
static const struct v4l2_subdev_video_ops cx25840_video_ops = {
- .s_std = cx25840_s_std,
.g_std = cx25840_g_std,
+ .s_std = cx25840_s_std,
+ .querystd = cx25840_querystd,
.s_routing = cx25840_s_video_routing,
.s_stream = cx25840_s_stream,
.g_input_status = cx25840_g_input_status,
@@ -5110,22 +5788,28 @@ static u32 get_cx2388x_ident(struct i2c_client *client)
/* Come out of digital power down */
cx25840_write(client, 0x000, 0);
- /* Detecting whether the part is cx23885/7/8 is more
+ /*
+ * Detecting whether the part is cx23885/7/8 is more
* difficult than it needs to be. No ID register. Instead we
* probe certain registers indicated in the datasheets to look
- * for specific defaults that differ between the silicon designs. */
+ * for specific defaults that differ between the silicon designs.
+ */
/* It's either 885/7 if the IR Tx Clk Divider register exists */
if (cx25840_read4(client, 0x204) & 0xffff) {
- /* CX23885 returns bogus repetitive byte values for the DIF,
- * which doesn't exist for it. (Ex. 8a8a8a8a or 31313131) */
+ /*
+ * CX23885 returns bogus repetitive byte values for the DIF,
+ * which doesn't exist for it. (Ex. 8a8a8a8a or 31313131)
+ */
ret = cx25840_read4(client, 0x300);
if (((ret & 0xffff0000) >> 16) == (ret & 0xffff)) {
/* No DIF */
ret = CX23885_AV;
} else {
- /* CX23887 has a broken DIF, but the registers
- * appear valid (but unused), good enough to detect. */
+ /*
+ * CX23887 has a broken DIF, but the registers
+ * appear valid (but unused), good enough to detect.
+ */
ret = CX23887_AV;
}
} else if (cx25840_read4(client, 0x300) & 0x0fffffff) {
@@ -5157,14 +5841,18 @@ static int cx25840_probe(struct i2c_client *client,
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
- v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", client->addr << 1);
+ v4l_dbg(1, cx25840_debug, client,
+ "detecting cx25840 client on address 0x%x\n",
+ client->addr << 1);
device_id = cx25840_read(client, 0x101) << 8;
device_id |= cx25840_read(client, 0x100);
v4l_dbg(1, cx25840_debug, client, "device_id = 0x%04x\n", device_id);
- /* The high byte of the device ID should be
- * 0x83 for the cx2583x and 0x84 for the cx2584x */
+ /*
+ * The high byte of the device ID should be
+ * 0x83 for the cx2583x and 0x84 for the cx2584x
+ */
if ((device_id & 0xff00) == 0x8300) {
id = CX25836 + ((device_id >> 4) & 0xf) - 6;
} else if ((device_id & 0xff00) == 0x8400) {
@@ -5178,7 +5866,8 @@ static int cx25840_probe(struct i2c_client *client,
v4l_err(client,
"likely a confused/unresponsive cx2388[578] A/V decoder found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- v4l_err(client, "A method to reset it from the cx25840 driver software is not known at this time\n");
+ v4l_err(client,
+ "A method to reset it from the cx25840 driver software is not known at this time\n");
return -ENODEV;
} else {
v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n");
@@ -5186,7 +5875,7 @@ static int cx25840_probe(struct i2c_client *client,
}
state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
- if (state == NULL)
+ if (!state)
return -ENOMEM;
sd = &state->sd;
@@ -5213,7 +5902,7 @@ static int cx25840_probe(struct i2c_client *client,
sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
ret = media_entity_pads_init(&sd->entity, ARRAY_SIZE(state->pads),
- state->pads);
+ state->pads);
if (ret < 0) {
v4l_info(client, "failed to initialize media entity!\n");
return ret;
@@ -5241,8 +5930,10 @@ static int cx25840_probe(struct i2c_client *client,
case CX25841:
case CX25842:
case CX25843:
- /* Note: revision '(device_id & 0x0f) == 2' was never built. The
- marking skips from 0x1 == 22 to 0x3 == 23. */
+ /*
+ * Note: revision '(device_id & 0x0f) == 2' was never built.
+ * The marking skips from 0x1 == 22 to 0x3 == 23.
+ */
v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n",
(device_id & 0xfff0) >> 4,
(device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1
@@ -5270,13 +5961,13 @@ static int cx25840_probe(struct i2c_client *client,
state->std = V4L2_STD_NTSC_M;
v4l2_ctrl_handler_init(&state->hdl, 9);
v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops,
- V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops,
- V4L2_CID_CONTRAST, 0, 127, 1, 64);
+ V4L2_CID_CONTRAST, 0, 127, 1, 64);
v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops,
- V4L2_CID_SATURATION, 0, 127, 1, 64);
+ V4L2_CID_SATURATION, 0, 127, 1, 64);
v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops,
- V4L2_CID_HUE, -128, 127, 1, 0);
+ V4L2_CID_HUE, -128, 127, 1, 0);
if (!is_cx2583x(state)) {
default_volume = cx25840_read(client, 0x8d4);
/*
@@ -5288,8 +5979,7 @@ static int cx25840_probe(struct i2c_client *client,
/* Bottom out at -96 dB, v4l2 vol range 0x2e00-0x2fff */
default_volume = 228;
cx25840_write(client, 0x8d4, 228);
- }
- else if (default_volume < 20) {
+ } else if (default_volume < 20) {
/* Top out at + 8 dB, v4l2 vol range 0xfe00-0xffff */
default_volume = 20;
cx25840_write(client, 0x8d4, 20);
@@ -5297,20 +5987,23 @@ static int cx25840_probe(struct i2c_client *client,
default_volume = (((228 - default_volume) >> 1) + 23) << 9;
state->volume = v4l2_ctrl_new_std(&state->hdl,
- &cx25840_audio_ctrl_ops, V4L2_CID_AUDIO_VOLUME,
- 0, 65535, 65535 / 100, default_volume);
+ &cx25840_audio_ctrl_ops,
+ V4L2_CID_AUDIO_VOLUME,
+ 0, 65535, 65535 / 100,
+ default_volume);
state->mute = v4l2_ctrl_new_std(&state->hdl,
- &cx25840_audio_ctrl_ops, V4L2_CID_AUDIO_MUTE,
- 0, 1, 1, 0);
+ &cx25840_audio_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE,
+ 0, 1, 1, 0);
v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops,
- V4L2_CID_AUDIO_BALANCE,
- 0, 65535, 65535 / 100, 32768);
+ V4L2_CID_AUDIO_BALANCE,
+ 0, 65535, 65535 / 100, 32768);
v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops,
- V4L2_CID_AUDIO_BASS,
- 0, 65535, 65535 / 100, 32768);
+ V4L2_CID_AUDIO_BASS,
+ 0, 65535, 65535 / 100, 32768);
v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops,
- V4L2_CID_AUDIO_TREBLE,
- 0, 65535, 65535 / 100, 32768);
+ V4L2_CID_AUDIO_TREBLE,
+ 0, 65535, 65535 / 100, 32768);
}
sd->ctrl_handler = &state->hdl;
if (state->hdl.error) {
diff --git a/drivers/media/i2c/cx25840/cx25840-core.h b/drivers/media/i2c/cx25840/cx25840-core.h
index 7fa5787635ea..8b89e90687a1 100644
--- a/drivers/media/i2c/cx25840/cx25840-core.h
+++ b/drivers/media/i2c/cx25840/cx25840-core.h
@@ -7,7 +7,6 @@
#ifndef _CX25840_CORE_H_
#define _CX25840_CORE_H_
-
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
@@ -44,10 +43,15 @@ enum cx25840_media_pads {
* @mute: audio mute V4L2 control (non-cx2583x devices only)
* @pvr150_workaround: whether we enable workaround for Hauppauge PVR150
* hardware bug (audio dropping out)
+ * @generic_mode: whether we disable ivtv-specific hacks
+ * this mode gets turned on when the bridge driver calls
+ * cx25840 subdevice init core op
* @radio: set if we are currently in the radio mode, otherwise
* the current mode is non-radio (that is, video)
* @std: currently set video standard
* @vid_input: currently set video input
+ * @vid_config: currently set video output configuration
+ * only used in the generic mode
* @aud_input: currently set audio input
* @audclk_freq: currently set audio sample rate
* @audmode: currently set audio mode (when in non-radio mode)
@@ -74,9 +78,11 @@ struct cx25840_state {
struct v4l2_ctrl *mute;
};
int pvr150_workaround;
+ bool generic_mode;
int radio;
v4l2_std_id std;
enum cx25840_video_input vid_input;
+ u32 vid_config;
enum cx25840_audio_input aud_input;
u32 audclk_freq;
int audmode;
@@ -84,7 +90,7 @@ struct cx25840_state {
enum cx25840_model id;
u32 rev;
int is_initialized;
- unsigned vbi_regs_offset;
+ unsigned int vbi_regs_offset;
wait_queue_head_t fw_wait;
struct work_struct fw_work;
struct cx25840_ir_state *ir_state;
@@ -109,6 +115,14 @@ static inline bool is_cx2583x(struct cx25840_state *state)
state->id == CX25837;
}
+static inline bool is_cx2584x(struct cx25840_state *state)
+{
+ return state->id == CX25840 ||
+ state->id == CX25841 ||
+ state->id == CX25842 ||
+ state->id == CX25843;
+}
+
static inline bool is_cx231xx(struct cx25840_state *state)
{
return state->id == CX2310X_AV;
@@ -142,7 +156,8 @@ int cx25840_write(struct i2c_client *client, u16 addr, u8 value);
int cx25840_write4(struct i2c_client *client, u16 addr, u32 value);
u8 cx25840_read(struct i2c_client *client, u16 addr);
u32 cx25840_read4(struct i2c_client *client, u16 addr);
-int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned mask, u8 value);
+int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned int mask,
+ u8 value);
int cx25840_and_or4(struct i2c_client *client, u16 addr, u32 and_mask,
u32 or_value);
void cx25840_std_setup(struct i2c_client *client);
@@ -161,9 +176,12 @@ extern const struct v4l2_ctrl_ops cx25840_audio_ctrl_ops;
/* ----------------------------------------------------------------------- */
/* cx25850-vbi.c */
int cx25840_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt);
-int cx25840_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt);
-int cx25840_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt);
-int cx25840_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi);
+int cx25840_s_sliced_fmt(struct v4l2_subdev *sd,
+ struct v4l2_sliced_vbi_format *fmt);
+int cx25840_g_sliced_fmt(struct v4l2_subdev *sd,
+ struct v4l2_sliced_vbi_format *fmt);
+int cx25840_decode_vbi_line(struct v4l2_subdev *sd,
+ struct v4l2_decode_vbi_line *vbi);
/* ----------------------------------------------------------------------- */
/* cx25850-ir.c */
diff --git a/drivers/media/i2c/cx25840/cx25840-vbi.c b/drivers/media/i2c/cx25840/cx25840-vbi.c
index 643335f0f827..a066d5f0fec9 100644
--- a/drivers/media/i2c/cx25840/cx25840-vbi.c
+++ b/drivers/media/i2c/cx25840/cx25840-vbi.c
@@ -86,6 +86,7 @@ int cx25840_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *
memset(svbi->service_lines, 0, sizeof(svbi->service_lines));
svbi->service_set = 0;
/* we're done if raw VBI is active */
+ /* TODO: this will have to be changed for generic_mode VBI */
if ((cx25840_read(client, 0x404) & 0x10) == 0)
return 0;
@@ -128,6 +129,7 @@ int cx25840_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt)
cx25840_write(client, 0x54f, vbi_offset);
else
cx25840_write(client, 0x47f, vbi_offset);
+ /* TODO: this will have to be changed for generic_mode VBI */
cx25840_write(client, 0x404, 0x2e);
return 0;
}
@@ -148,6 +150,7 @@ int cx25840_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *
cx25840_std_setup(client);
/* Sliced VBI */
+ /* TODO: this will have to be changed for generic_mode VBI */
cx25840_write(client, 0x404, 0x32); /* Ancillary data */
cx25840_write(client, 0x406, 0x13);
if (is_cx23888(state))
@@ -202,6 +205,7 @@ int cx25840_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *
}
cx25840_write(client, state->vbi_regs_offset + 0x43c, 0x16);
+ /* TODO: this will have to be changed for generic_mode VBI */
if (is_cx23888(state))
cx25840_write(client, 0x428, is_pal ? 0x2a : 0x22);
else
diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
index 83e9961b0505..159a3a604f0e 100644
--- a/drivers/media/i2c/imx214.c
+++ b/drivers/media/i2c/imx214.c
@@ -1111,6 +1111,6 @@ static struct i2c_driver imx214_i2c_driver = {
module_i2c_driver(imx214_i2c_driver);
-MODULE_DESCRIPTION("Sony IMX214 Camera drier");
+MODULE_DESCRIPTION("Sony IMX214 Camera driver");
MODULE_AUTHOR("Ricardo Ribalda <ricardo.ribalda@gmail.com>");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/lm3646.c b/drivers/media/i2c/lm3646.c
index 73fbe3c37fc9..d8a8853f9a2b 100644
--- a/drivers/media/i2c/lm3646.c
+++ b/drivers/media/i2c/lm3646.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/media/i2c/lm3646.c
* General device driver for TI lm3646, Dual FLASH LED Driver
@@ -6,10 +7,6 @@
*
* Contact: Daniel Jeong <gshark.jeong@gmail.com>
* Ldd-Mlp <ldd-mlp@list.ti.com>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/media/i2c/mt9m001.c b/drivers/media/i2c/mt9m001.c
index 4b23fde937b3..2df743cbe09d 100644
--- a/drivers/media/i2c/mt9m001.c
+++ b/drivers/media/i2c/mt9m001.c
@@ -730,7 +730,7 @@ static int mt9m001_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct mt9m001 *mt9m001;
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adapter = client->adapter;
int ret;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c
index 5168bb5880c4..12cb012d91f7 100644
--- a/drivers/media/i2c/mt9m111.c
+++ b/drivers/media/i2c/mt9m111.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for MT9M111/MT9M112/MT9M131 CMOS Image Sensor from Micron/Aptina
*
* Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr>
- *
- * 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.
*/
#include <linux/videodev2.h>
#include <linux/slab.h>
@@ -13,6 +10,7 @@
#include <linux/log2.h>
#include <linux/gpio.h>
#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
#include <linux/v4l2-mediabus.h>
#include <linux/module.h>
#include <linux/property.h>
@@ -243,6 +241,7 @@ struct mt9m111 {
int power_count;
const struct mt9m111_datafmt *fmt;
int lastpage; /* PageMap cache value */
+ struct regulator *regulator;
bool is_streaming;
/* user point of view - 0: falling 1: rising edge */
unsigned int pclk_sample:1;
@@ -982,11 +981,23 @@ static int mt9m111_power_on(struct mt9m111 *mt9m111)
if (ret < 0)
return ret;
+ ret = regulator_enable(mt9m111->regulator);
+ if (ret < 0)
+ goto out_clk_disable;
+
ret = mt9m111_resume(mt9m111);
- if (ret < 0) {
- dev_err(&client->dev, "Failed to resume the sensor: %d\n", ret);
- v4l2_clk_disable(mt9m111->clk);
- }
+ if (ret < 0)
+ goto out_regulator_disable;
+
+ return 0;
+
+out_regulator_disable:
+ regulator_disable(mt9m111->regulator);
+
+out_clk_disable:
+ v4l2_clk_disable(mt9m111->clk);
+
+ dev_err(&client->dev, "Failed to resume the sensor: %d\n", ret);
return ret;
}
@@ -994,6 +1005,7 @@ static int mt9m111_power_on(struct mt9m111 *mt9m111)
static void mt9m111_power_off(struct mt9m111 *mt9m111)
{
mt9m111_suspend(mt9m111);
+ regulator_disable(mt9m111->regulator);
v4l2_clk_disable(mt9m111->clk);
}
@@ -1235,7 +1247,7 @@ static int mt9m111_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct mt9m111 *mt9m111;
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adapter = client->adapter;
int ret;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
@@ -1248,14 +1260,23 @@ static int mt9m111_probe(struct i2c_client *client,
if (!mt9m111)
return -ENOMEM;
- ret = mt9m111_probe_fw(client, mt9m111);
- if (ret)
- return ret;
+ if (dev_fwnode(&client->dev)) {
+ ret = mt9m111_probe_fw(client, mt9m111);
+ if (ret)
+ return ret;
+ }
mt9m111->clk = v4l2_clk_get(&client->dev, "mclk");
if (IS_ERR(mt9m111->clk))
return PTR_ERR(mt9m111->clk);
+ mt9m111->regulator = devm_regulator_get(&client->dev, "vdd");
+ if (IS_ERR(mt9m111->regulator)) {
+ dev_err(&client->dev, "regulator not found: %ld\n",
+ PTR_ERR(mt9m111->regulator));
+ return PTR_ERR(mt9m111->regulator);
+ }
+
/* Default HIGHPOWER context */
mt9m111->ctx = &context_b;
diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c
index 715be3632b01..dc23b9ed510a 100644
--- a/drivers/media/i2c/mt9p031.c
+++ b/drivers/media/i2c/mt9p031.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for MT9P031 CMOS Image Sensor from Aptina
*
@@ -6,10 +7,6 @@
* Copyright (C) 2011, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
*
* Based on the MT9V032 driver and Bastian Hecht's code.
- *
- * 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.
*/
#include <linux/clk.h>
@@ -1034,7 +1031,7 @@ static int mt9p031_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct mt9p031_platform_data *pdata = mt9p031_get_pdata(client);
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adapter = client->adapter;
struct mt9p031 *mt9p031;
unsigned int i;
int ret;
diff --git a/drivers/media/i2c/mt9t001.c b/drivers/media/i2c/mt9t001.c
index f683d2cb0486..2e96ff5234b4 100644
--- a/drivers/media/i2c/mt9t001.c
+++ b/drivers/media/i2c/mt9t001.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for MT9T001 CMOS Image Sensor from Aptina (Micron)
*
@@ -6,10 +7,6 @@
* Based on the MT9M001 driver,
*
* Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c
index 67f69ad6ecf4..4b9b98cf6674 100644
--- a/drivers/media/i2c/mt9v032.c
+++ b/drivers/media/i2c/mt9v032.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for MT9V022, MT9V024, MT9V032, and MT9V034 CMOS Image Sensors
*
@@ -6,10 +7,6 @@
* Based on the MT9M001 driver,
*
* Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c
index 45bb872db3c5..aac6f77afa0f 100644
--- a/drivers/media/i2c/ov13858.c
+++ b/drivers/media/i2c/ov13858.c
@@ -1224,7 +1224,7 @@ static int ov13858_set_ctrl(struct v4l2_ctrl *ctrl)
ov13858->exposure->minimum,
max, ov13858->exposure->step, max);
break;
- };
+ }
/*
* Applying V4L2 control value only happens
@@ -1262,7 +1262,7 @@ static int ov13858_set_ctrl(struct v4l2_ctrl *ctrl)
"ctrl(id:0x%x,val:0x%x) is not handled\n",
ctrl->id, ctrl->val);
break;
- };
+ }
pm_runtime_put(&client->dev);
diff --git a/drivers/media/i2c/ov2640.c b/drivers/media/i2c/ov2640.c
index 83031cfc7914..ecd167d7c4d2 100644
--- a/drivers/media/i2c/ov2640.c
+++ b/drivers/media/i2c/ov2640.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ov2640 Camera Driver
*
@@ -7,10 +8,6 @@
*
* Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved.
* Copyright (C) 2006, OmniVision
- *
- * 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.
*/
#include <linux/init.h>
@@ -1197,7 +1194,7 @@ static int ov2640_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct ov2640_priv *priv;
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adapter = client->adapter;
int ret;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
diff --git a/drivers/media/i2c/ov2685.c b/drivers/media/i2c/ov2685.c
index 98a1f2e312b5..6814583d9606 100644
--- a/drivers/media/i2c/ov2685.c
+++ b/drivers/media/i2c/ov2685.c
@@ -576,7 +576,7 @@ static int ov2685_set_ctrl(struct v4l2_ctrl *ctrl)
__func__, ctrl->id, ctrl->val);
ret = -EINVAL;
break;
- };
+ }
pm_runtime_put(&client->dev);
diff --git a/drivers/media/i2c/ov5695.c b/drivers/media/i2c/ov5695.c
index 5d107c53364d..e65a94353175 100644
--- a/drivers/media/i2c/ov5695.c
+++ b/drivers/media/i2c/ov5695.c
@@ -1143,7 +1143,7 @@ static int ov5695_set_ctrl(struct v4l2_ctrl *ctrl)
dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n",
__func__, ctrl->id, ctrl->val);
break;
- };
+ }
pm_runtime_put(&client->dev);
diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index 1b972e591b48..5b9af5e5b7f1 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* V4L2 subdevice driver for OmniVision OV6650 Camera Sensor
*
@@ -18,10 +19,6 @@
* Hardware specific bits initially based on former work by Matt Callow
* drivers/media/video/omap/sensor_ov6650.c
* Copyright (C) 2006 Matt Callow
- *
- * 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.
*/
#include <linux/bitops.h>
@@ -1009,7 +1006,6 @@ static int ov6650_probe(struct i2c_client *client,
priv->colorspace = V4L2_COLORSPACE_JPEG;
priv->subdev.internal_ops = &ov6650_internal_ops;
- priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
ret = v4l2_async_register_subdev(&priv->subdev);
if (ret)
diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c
index 54e80a60aa57..70bb870b1d08 100644
--- a/drivers/media/i2c/ov7740.c
+++ b/drivers/media/i2c/ov7740.c
@@ -532,7 +532,7 @@ static int ov7740_set_ctrl(struct v4l2_ctrl *ctrl)
struct i2c_client *client = v4l2_get_subdevdata(&ov7740->subdev);
struct regmap *regmap = ov7740->regmap;
int ret;
- u8 val = 0;
+ u8 val;
if (!pm_runtime_get_if_in_use(&client->dev))
return 0;
@@ -551,6 +551,7 @@ static int ov7740_set_ctrl(struct v4l2_ctrl *ctrl)
ret = ov7740_set_contrast(regmap, ctrl->val);
break;
case V4L2_CID_VFLIP:
+ val = ctrl->val ? REG0C_IMG_FLIP : 0x00;
ret = regmap_update_bits(regmap, REG_REG0C,
REG0C_IMG_FLIP, val);
break;
@@ -561,16 +562,16 @@ static int ov7740_set_ctrl(struct v4l2_ctrl *ctrl)
break;
case V4L2_CID_AUTOGAIN:
if (!ctrl->val)
- return ov7740_set_gain(regmap, ov7740->gain->val);
-
- ret = ov7740_set_autogain(regmap, ctrl->val);
+ ret = ov7740_set_gain(regmap, ov7740->gain->val);
+ else
+ ret = ov7740_set_autogain(regmap, ctrl->val);
break;
case V4L2_CID_EXPOSURE_AUTO:
if (ctrl->val == V4L2_EXPOSURE_MANUAL)
- return ov7740_set_exp(regmap, ov7740->exposure->val);
-
- ret = ov7740_set_autoexp(regmap, ctrl->val);
+ ret = ov7740_set_exp(regmap, ov7740->exposure->val);
+ else
+ ret = ov7740_set_autoexp(regmap, ctrl->val);
break;
default:
ret = -EINVAL;
@@ -785,7 +786,11 @@ static int ov7740_try_fmt_internal(struct v4l2_subdev *sd,
fsize++;
}
-
+ if (i >= ARRAY_SIZE(ov7740_framesizes)) {
+ fsize = &ov7740_framesizes[0];
+ fmt->width = fsize->width;
+ fmt->height = fsize->height;
+ }
if (ret_frmsize != NULL)
*ret_frmsize = fsize;
@@ -1007,8 +1012,6 @@ static int ov7740_init_controls(struct ov7740 *ov7740)
ov7740->gain = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
V4L2_CID_GAIN, 0, 1023, 1, 500);
- if (ov7740->gain)
- ov7740->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
ov7740->auto_gain = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
@@ -1026,7 +1029,6 @@ static int ov7740_init_controls(struct ov7740 *ov7740)
v4l2_ctrl_auto_cluster(2, &ov7740->auto_gain, 0, true);
v4l2_ctrl_auto_cluster(2, &ov7740->auto_exposure,
V4L2_EXPOSURE_MANUAL, true);
- v4l2_ctrl_cluster(2, &ov7740->hflip);
if (ctrl_hdlr->error) {
ret = ctrl_hdlr->error;
diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c
index dbf1095b9440..cd347d6b7b9d 100644
--- a/drivers/media/i2c/ov8856.c
+++ b/drivers/media/i2c/ov8856.c
@@ -195,11 +195,11 @@ static const struct ov8856_reg mode_3280x2464_regs[] = {
{0x3800, 0x00},
{0x3801, 0x00},
{0x3802, 0x00},
- {0x3803, 0x07},
+ {0x3803, 0x06},
{0x3804, 0x0c},
{0x3805, 0xdf},
{0x3806, 0x09},
- {0x3807, 0xa6},
+ {0x3807, 0xa7},
{0x3808, 0x0c},
{0x3809, 0xd0},
{0x380a, 0x09},
@@ -211,7 +211,7 @@ static const struct ov8856_reg mode_3280x2464_regs[] = {
{0x3810, 0x00},
{0x3811, 0x00},
{0x3812, 0x00},
- {0x3813, 0x00},
+ {0x3813, 0x01},
{0x3814, 0x01},
{0x3815, 0x01},
{0x3816, 0x00},
@@ -385,11 +385,11 @@ static const struct ov8856_reg mode_1640x1232_regs[] = {
{0x3800, 0x00},
{0x3801, 0x00},
{0x3802, 0x00},
- {0x3803, 0x07},
+ {0x3803, 0x06},
{0x3804, 0x0c},
{0x3805, 0xdf},
{0x3806, 0x09},
- {0x3807, 0xa6},
+ {0x3807, 0xa7},
{0x3808, 0x06},
{0x3809, 0x68},
{0x380a, 0x04},
@@ -401,7 +401,7 @@ static const struct ov8856_reg mode_1640x1232_regs[] = {
{0x3810, 0x00},
{0x3811, 0x00},
{0x3812, 0x00},
- {0x3813, 0x00},
+ {0x3813, 0x01},
{0x3814, 0x03},
{0x3815, 0x01},
{0x3816, 0x00},
diff --git a/drivers/media/i2c/ov9640.c b/drivers/media/i2c/ov9640.c
index d6831f28378b..482609665305 100644
--- a/drivers/media/i2c/ov9640.c
+++ b/drivers/media/i2c/ov9640.c
@@ -691,14 +691,14 @@ static int ov9640_probe(struct i2c_client *client,
priv->gpio_power = devm_gpiod_get(&client->dev, "Camera power",
GPIOD_OUT_LOW);
- if (IS_ERR_OR_NULL(priv->gpio_power)) {
+ if (IS_ERR(priv->gpio_power)) {
ret = PTR_ERR(priv->gpio_power);
return ret;
}
priv->gpio_reset = devm_gpiod_get(&client->dev, "Camera reset",
GPIOD_OUT_HIGH);
- if (IS_ERR_OR_NULL(priv->gpio_reset)) {
+ if (IS_ERR(priv->gpio_reset)) {
ret = PTR_ERR(priv->gpio_reset);
return ret;
}
diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c
index eefd57ec2a73..30ab2225fbd0 100644
--- a/drivers/media/i2c/ov9650.c
+++ b/drivers/media/i2c/ov9650.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Omnivision OV9650/OV9652 CMOS Image Sensor driver
*
@@ -6,10 +7,6 @@
* Register definitions and initial settings based on a driver written
* by Vladimir Fonov.
* Copyright (c) 2010, Vladimir Fonov
- *
- * 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.
*/
#include <linux/clk.h>
#include <linux/delay.h>
diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c
index 727db7c0670a..8e6de06b3e72 100644
--- a/drivers/media/i2c/s5k5baf.c
+++ b/drivers/media/i2c/s5k5baf.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for Samsung S5K5BAF UXGA 1/5" 2M CMOS Image Sensor
* with embedded SoC ISP.
@@ -7,10 +8,6 @@
*
* Based on S5K6AA driver authored by Sylwester Nawrocki
* Copyright (C) 2013, Samsung Electronics Co., Ltd.
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/media/i2c/s5k6a3.c b/drivers/media/i2c/s5k6a3.c
index 2e140272794b..3b7721f81be2 100644
--- a/drivers/media/i2c/s5k6a3.c
+++ b/drivers/media/i2c/s5k6a3.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Samsung S5K6A3 image sensor driver
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.c b/drivers/media/i2c/smiapp/smiapp-quirk.c
index e46d72cee566..ab96d6067fc3 100644
--- a/drivers/media/i2c/smiapp/smiapp-quirk.c
+++ b/drivers/media/i2c/smiapp/smiapp-quirk.c
@@ -194,7 +194,7 @@ static int jt8ev1_post_streamoff(struct smiapp_sensor *sensor)
return rval;
/* Wait for 1 ms + one line => 2 ms is likely enough */
- usleep_range(2000, 2000);
+ usleep_range(2000, 2050);
/* Restore it */
rval = smiapp_write_8(sensor, 0x3205, 0x00);
diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c
index 9369f38dbf3d..81285b8d5cfb 100644
--- a/drivers/media/i2c/st-mipid02.c
+++ b/drivers/media/i2c/st-mipid02.c
@@ -61,7 +61,10 @@ static const u32 mipid02_supported_fmt_codes[] = {
MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10,
MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SGBRG12_1X12,
MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SRGGB12_1X12,
- MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_BGR888_1X24
+ MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_BGR888_1X24,
+ MEDIA_BUS_FMT_RGB565_2X8_LE, MEDIA_BUS_FMT_RGB565_2X8_BE,
+ MEDIA_BUS_FMT_YUYV8_2X8, MEDIA_BUS_FMT_UYVY8_2X8,
+ MEDIA_BUS_FMT_JPEG_1X8
};
/* regulator supplies */
@@ -99,6 +102,7 @@ struct mipid02_dev {
u8 data_lane1_reg1;
u8 mode_reg1;
u8 mode_reg2;
+ u8 data_selection_ctrl;
u8 data_id_rreg;
u8 pix_width_ctrl;
u8 pix_width_ctrl_emb;
@@ -128,6 +132,10 @@ static int bpp_from_code(__u32 code)
case MEDIA_BUS_FMT_SRGGB12_1X12:
return 12;
case MEDIA_BUS_FMT_UYVY8_1X16:
+ case MEDIA_BUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
+ case MEDIA_BUS_FMT_RGB565_2X8_LE:
+ case MEDIA_BUS_FMT_RGB565_2X8_BE:
return 16;
case MEDIA_BUS_FMT_BGR888_1X24:
return 24;
@@ -155,9 +163,14 @@ static u8 data_type_from_code(__u32 code)
case MEDIA_BUS_FMT_SRGGB12_1X12:
return 0x2c;
case MEDIA_BUS_FMT_UYVY8_1X16:
+ case MEDIA_BUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
return 0x1e;
case MEDIA_BUS_FMT_BGR888_1X24:
return 0x24;
+ case MEDIA_BUS_FMT_RGB565_2X8_LE:
+ case MEDIA_BUS_FMT_RGB565_2X8_BE:
+ return 0x22;
default:
return 0;
}
@@ -331,6 +344,25 @@ static int mipid02_detect(struct mipid02_dev *bridge)
return mipid02_read_reg(bridge, MIPID02_CLK_LANE_WR_REG1, &reg);
}
+static u32 mipid02_get_link_freq_from_cid_link_freq(struct mipid02_dev *bridge,
+ struct v4l2_subdev *subdev)
+{
+ struct v4l2_querymenu qm = {.id = V4L2_CID_LINK_FREQ, };
+ struct v4l2_ctrl *ctrl;
+ int ret;
+
+ ctrl = v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_LINK_FREQ);
+ if (!ctrl)
+ return 0;
+ qm.index = v4l2_ctrl_g_ctrl(ctrl);
+
+ ret = v4l2_querymenu(subdev->ctrl_handler, &qm);
+ if (ret)
+ return 0;
+
+ return qm.value;
+}
+
static u32 mipid02_get_link_freq_from_cid_pixel_rate(struct mipid02_dev *bridge,
struct v4l2_subdev *subdev)
{
@@ -358,10 +390,14 @@ static int mipid02_configure_from_rx_speed(struct mipid02_dev *bridge)
struct v4l2_subdev *subdev = bridge->s_subdev;
u32 link_freq;
- link_freq = mipid02_get_link_freq_from_cid_pixel_rate(bridge, subdev);
+ link_freq = mipid02_get_link_freq_from_cid_link_freq(bridge, subdev);
if (!link_freq) {
- dev_err(&client->dev, "Failed to detect link frequency");
- return -EINVAL;
+ link_freq = mipid02_get_link_freq_from_cid_pixel_rate(bridge,
+ subdev);
+ if (!link_freq) {
+ dev_err(&client->dev, "Failed to get link frequency");
+ return -EINVAL;
+ }
}
dev_dbg(&client->dev, "detect link_freq = %d Hz", link_freq);
@@ -452,6 +488,7 @@ static int mipid02_configure_from_tx(struct mipid02_dev *bridge)
{
struct v4l2_fwnode_endpoint *ep = &bridge->tx;
+ bridge->r.data_selection_ctrl = SELECTION_MANUAL_WIDTH;
bridge->r.pix_width_ctrl = ep->bus.parallel.bus_width;
bridge->r.pix_width_ctrl_emb = ep->bus.parallel.bus_width;
if (ep->bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
@@ -467,10 +504,15 @@ static int mipid02_configure_from_code(struct mipid02_dev *bridge)
u8 data_type;
bridge->r.data_id_rreg = 0;
- data_type = data_type_from_code(bridge->fmt.code);
- if (!data_type)
- return -EINVAL;
- bridge->r.data_id_rreg = data_type;
+
+ if (bridge->fmt.code != MEDIA_BUS_FMT_JPEG_1X8) {
+ bridge->r.data_selection_ctrl |= SELECTION_MANUAL_DATA;
+
+ data_type = data_type_from_code(bridge->fmt.code);
+ if (!data_type)
+ return -EINVAL;
+ bridge->r.data_id_rreg = data_type;
+ }
return 0;
}
@@ -554,7 +596,7 @@ static int mipid02_stream_enable(struct mipid02_dev *bridge)
if (ret)
goto error;
ret = mipid02_write_reg(bridge, MIPID02_DATA_SELECTION_CTRL,
- SELECTION_MANUAL_DATA | SELECTION_MANUAL_WIDTH);
+ bridge->r.data_selection_ctrl);
if (ret)
goto error;
ret = mipid02_write_reg(bridge, MIPID02_PIX_WIDTH_CTRL,
diff --git a/drivers/media/i2c/tda7432.c b/drivers/media/i2c/tda7432.c
index 06a78c2cdaab..cbdc9be0a597 100644
--- a/drivers/media/i2c/tda7432.c
+++ b/drivers/media/i2c/tda7432.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* For the STS-Thompson TDA7432 audio processor chip
*
@@ -9,7 +10,7 @@
*
* Copyright (c) 2000 Eric Sandeen <eric_sandeen@bigfoot.com>
* Copyright (c) 2006 Mauro Carvalho Chehab <mchehab@kernel.org>
- * This code is placed under the terms of the GNU General Public License
+ *
* Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu)
* Which was based on tda8425.c by Greg Alexander (c) 1998
*
diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c
index 3ada3bb27402..a7fbe5b400c2 100644
--- a/drivers/media/i2c/tvp514x.c
+++ b/drivers/media/i2c/tvp514x.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/media/i2c/tvp514x.c
*
@@ -13,16 +14,6 @@
* Manjunath Hadli <mrh@ti.com>
* Karicheri Muralidharan <m-karicheri2@ti.com>
* Prabhakar Lad <prabhakar.lad@ti.com>
- *
- * This package 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <linux/i2c.h>
diff --git a/drivers/media/i2c/tvp514x_regs.h b/drivers/media/i2c/tvp514x_regs.h
index 1e6c0857590e..cc236c968f67 100644
--- a/drivers/media/i2c/tvp514x_regs.h
+++ b/drivers/media/i2c/tvp514x_regs.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* drivers/media/i2c/tvp514x_regs.h
*
@@ -10,16 +11,6 @@
* Hardik Shah <hardik.shah@ti.com>
* Manjunath Hadli <mrh@ti.com>
* Karicheri Muralidharan <m-karicheri2@ti.com>
- *
- * This package 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#ifndef _TVP514X_REGS_H
diff --git a/drivers/media/i2c/tw9910.c b/drivers/media/i2c/tw9910.c
index 4d7cd736b930..a25a350b0ddc 100644
--- a/drivers/media/i2c/tw9910.c
+++ b/drivers/media/i2c/tw9910.c
@@ -934,8 +934,7 @@ static int tw9910_probe(struct i2c_client *client,
{
struct tw9910_priv *priv;
struct tw9910_video_info *info;
- struct i2c_adapter *adapter =
- to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adapter = client->adapter;
int ret;
if (!client->dev.platform_data) {
diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c
index abd3152df7d0..078141712c88 100644
--- a/drivers/media/i2c/video-i2c.c
+++ b/drivers/media/i2c/video-i2c.c
@@ -190,12 +190,8 @@ static int mlx90640_setup(struct video_i2c_data *data)
unsigned int n, idx;
for (n = 0; n < data->chip->num_frame_intervals - 1; n++) {
- if (data->frame_interval.numerator
- != data->chip->frame_intervals[n].numerator)
- continue;
-
- if (data->frame_interval.denominator
- == data->chip->frame_intervals[n].denominator)
+ if (V4L2_FRACT_COMPARE(data->frame_interval, ==,
+ data->chip->frame_intervals[n]))
break;
}
diff --git a/drivers/media/mc/Kconfig b/drivers/media/mc/Kconfig
new file mode 100644
index 000000000000..3b9795cfcb36
--- /dev/null
+++ b/drivers/media/mc/Kconfig
@@ -0,0 +1,33 @@
+#
+# Media controller
+# Selectable only for webcam/grabbers, as other drivers don't use it
+#
+
+config MEDIA_CONTROLLER
+ bool "Media Controller API"
+ depends on MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT
+ help
+ Enable the media controller API used to query media devices internal
+ topology and configure it dynamically.
+
+ This API is mostly used by camera interfaces in embedded platforms.
+
+config MEDIA_CONTROLLER_DVB
+ bool "Enable Media controller for DVB (EXPERIMENTAL)"
+ depends on MEDIA_CONTROLLER && DVB_CORE
+ help
+ Enable the media controller API support for DVB.
+
+ This is currently experimental.
+
+config MEDIA_CONTROLLER_REQUEST_API
+ bool "Enable Media controller Request API (EXPERIMENTAL)"
+ depends on MEDIA_CONTROLLER && STAGING_MEDIA
+ help
+ DO NOT ENABLE THIS OPTION UNLESS YOU KNOW WHAT YOU'RE DOING.
+
+ This option enables the Request API for the Media controller and V4L2
+ interfaces. It is currently needed by a few stateless codec drivers.
+
+ There is currently no intention to provide API or ABI stability for
+ this new API as of yet.
diff --git a/drivers/media/mc/Makefile b/drivers/media/mc/Makefile
new file mode 100644
index 000000000000..119037f0e686
--- /dev/null
+++ b/drivers/media/mc/Makefile
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0
+
+mc-objs := mc-device.o mc-devnode.o mc-entity.o \
+ mc-request.o
+
+ifeq ($(CONFIG_USB),y)
+ mc-objs += mc-dev-allocator.o
+endif
+
+obj-$(CONFIG_MEDIA_SUPPORT) += mc.o
diff --git a/drivers/media/media-dev-allocator.c b/drivers/media/mc/mc-dev-allocator.c
index ae17887dec59..ae17887dec59 100644
--- a/drivers/media/media-dev-allocator.c
+++ b/drivers/media/mc/mc-dev-allocator.c
diff --git a/drivers/media/media-device.c b/drivers/media/mc/mc-device.c
index 9ae481ddd975..e19df5165e78 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/mc/mc-device.c
@@ -494,6 +494,7 @@ static long media_device_enum_links32(struct media_device *mdev,
{
struct media_links_enum links;
compat_uptr_t pads_ptr, links_ptr;
+ int ret;
memset(&links, 0, sizeof(links));
@@ -505,7 +506,14 @@ static long media_device_enum_links32(struct media_device *mdev,
links.pads = compat_ptr(pads_ptr);
links.links = compat_ptr(links_ptr);
- return media_device_enum_links(mdev, &links);
+ ret = media_device_enum_links(mdev, &links);
+ if (ret)
+ return ret;
+
+ if (copy_to_user(ulinks->reserved, links.reserved,
+ sizeof(ulinks->reserved)))
+ return -EFAULT;
+ return 0;
}
#define MEDIA_IOC_ENUM_LINKS32 _IOWR('|', 0x02, struct media_links_enum32)
diff --git a/drivers/media/media-devnode.c b/drivers/media/mc/mc-devnode.c
index f11382afe23b..f11382afe23b 100644
--- a/drivers/media/media-devnode.c
+++ b/drivers/media/mc/mc-devnode.c
diff --git a/drivers/media/media-entity.c b/drivers/media/mc/mc-entity.c
index 7c429ce98bae..7c429ce98bae 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/mc/mc-entity.c
diff --git a/drivers/media/media-request.c b/drivers/media/mc/mc-request.c
index e3fca436c75b..e3fca436c75b 100644
--- a/drivers/media/media-request.c
+++ b/drivers/media/mc/mc-request.c
diff --git a/drivers/media/pci/bt8xx/bttv-audio-hook.c b/drivers/media/pci/bt8xx/bttv-audio-hook.c
index 8febe7358a8f..da1914a20b81 100644
--- a/drivers/media/pci/bt8xx/bttv-audio-hook.c
+++ b/drivers/media/pci/bt8xx/bttv-audio-hook.c
@@ -1,8 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Handlers for board audio hooks, split from bttv-cards
*
* Copyright (c) 2006 Mauro Carvalho Chehab <mchehab@kernel.org>
- * This code is placed under the terms of the GNU General Public License
*/
#include "bttv-audio-hook.h"
diff --git a/drivers/media/pci/bt8xx/bttv-audio-hook.h b/drivers/media/pci/bt8xx/bttv-audio-hook.h
index c61b9ac4f4e3..d6a1a5a60a56 100644
--- a/drivers/media/pci/bt8xx/bttv-audio-hook.h
+++ b/drivers/media/pci/bt8xx/bttv-audio-hook.h
@@ -1,4 +1,6 @@
/*
+ * SPDX-License-Identifier: GPL-2.0
+ *
* Handlers for board audio hooks, split from bttv-cards
*
* Copyright (c) 2006 Mauro Carvalho Chehab <mchehab@kernel.org>
diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c
index 636e6a2549a9..612d1c0010c1 100644
--- a/drivers/media/pci/bt8xx/bttv-driver.c
+++ b/drivers/media/pci/bt8xx/bttv-driver.c
@@ -2453,7 +2453,6 @@ static int bttv_s_fmt_vid_overlay(struct file *file, void *priv,
static int bttv_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- struct video_device *vdev = video_devdata(file);
struct bttv_fh *fh = priv;
struct bttv *btv = fh->btv;
@@ -2464,17 +2463,17 @@ static int bttv_querycap(struct file *file, void *priv,
strscpy(cap->card, btv->video_dev.name, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info),
"PCI:%s", pci_name(btv->c.pci));
- cap->capabilities =
- V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING |
- V4L2_CAP_DEVICE_CAPS;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS;
if (no_overlay <= 0)
cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
if (video_is_registered(&btv->vbi_dev))
cap->capabilities |= V4L2_CAP_VBI_CAPTURE;
- if (video_is_registered(&btv->radio_dev))
+ if (video_is_registered(&btv->radio_dev)) {
cap->capabilities |= V4L2_CAP_RADIO;
+ if (btv->has_tea575x)
+ cap->capabilities |= V4L2_CAP_HW_FREQ_SEEK;
+ }
/*
* No need to lock here: those vars are initialized during board
@@ -2484,27 +2483,6 @@ static int bttv_querycap(struct file *file, void *priv,
cap->capabilities |= V4L2_CAP_RDS_CAPTURE;
if (btv->tuner_type != TUNER_ABSENT)
cap->capabilities |= V4L2_CAP_TUNER;
- if (vdev->vfl_type == VFL_TYPE_GRABBER)
- cap->device_caps = cap->capabilities &
- (V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING |
- V4L2_CAP_VIDEO_OVERLAY |
- V4L2_CAP_TUNER);
- else if (vdev->vfl_type == VFL_TYPE_VBI)
- cap->device_caps = cap->capabilities &
- (V4L2_CAP_VBI_CAPTURE |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING |
- V4L2_CAP_TUNER);
- else {
- cap->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
- if (btv->has_saa6588)
- cap->device_caps |= V4L2_CAP_READWRITE |
- V4L2_CAP_RDS_CAPTURE;
- if (btv->has_tea575x)
- cap->device_caps |= V4L2_CAP_HW_FREQ_SEEK;
- }
return 0;
}
@@ -3939,6 +3917,12 @@ static int bttv_register_video(struct bttv *btv)
/* video */
vdev_init(btv, &btv->video_dev, &bttv_video_template, "video");
+ btv->video_dev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER |
+ V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+ if (btv->tuner_type != TUNER_ABSENT)
+ btv->video_dev.device_caps |= V4L2_CAP_TUNER;
+ if (no_overlay <= 0)
+ btv->video_dev.device_caps |= V4L2_CAP_VIDEO_OVERLAY;
if (video_register_device(&btv->video_dev, VFL_TYPE_GRABBER,
video_nr[btv->c.nr]) < 0)
@@ -3953,6 +3937,10 @@ static int bttv_register_video(struct bttv *btv)
/* vbi */
vdev_init(btv, &btv->vbi_dev, &bttv_video_template, "vbi");
+ btv->vbi_dev.device_caps = V4L2_CAP_VBI_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING | V4L2_CAP_TUNER;
+ if (btv->tuner_type != TUNER_ABSENT)
+ btv->vbi_dev.device_caps |= V4L2_CAP_TUNER;
if (video_register_device(&btv->vbi_dev, VFL_TYPE_VBI,
vbi_nr[btv->c.nr]) < 0)
@@ -3964,6 +3952,12 @@ static int bttv_register_video(struct bttv *btv)
return 0;
/* radio */
vdev_init(btv, &btv->radio_dev, &radio_template, "radio");
+ btv->radio_dev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
+ if (btv->has_saa6588)
+ btv->radio_dev.device_caps |= V4L2_CAP_READWRITE |
+ V4L2_CAP_RDS_CAPTURE;
+ if (btv->has_tea575x)
+ btv->radio_dev.device_caps |= V4L2_CAP_HW_FREQ_SEEK;
btv->radio_dev.ctrl_handler = &btv->radio_ctrl_handler;
if (video_register_device(&btv->radio_dev, VFL_TYPE_RADIO,
radio_nr[btv->c.nr]) < 0)
diff --git a/drivers/media/pci/cobalt/Kconfig b/drivers/media/pci/cobalt/Kconfig
index 6c6c60abe9b1..e0e7df460a92 100644
--- a/drivers/media/pci/cobalt/Kconfig
+++ b/drivers/media/pci/cobalt/Kconfig
@@ -3,7 +3,7 @@ config VIDEO_COBALT
tristate "Cisco Cobalt support"
depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
depends on PCI_MSI && MTD_COMPLEX_MAPPINGS
- depends on GPIOLIB || COMPILE_TEST
+ depends on (GPIOLIB && DRM_I2C_ADV7511=n) || COMPILE_TEST
depends on SND
depends on MTD
select I2C_ALGOBIT
diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c b/drivers/media/pci/cobalt/cobalt-v4l2.c
index f9fa3a7c3b8f..39dabd4da60f 100644
--- a/drivers/media/pci/cobalt/cobalt-v4l2.c
+++ b/drivers/media/pci/cobalt/cobalt-v4l2.c
@@ -483,13 +483,8 @@ static int cobalt_querycap(struct file *file, void *priv_fh,
strscpy(vcap->card, "cobalt", sizeof(vcap->card));
snprintf(vcap->bus_info, sizeof(vcap->bus_info),
"PCIe:%s", pci_name(cobalt->pci_dev));
- vcap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
- if (s->is_output)
- vcap->device_caps |= V4L2_CAP_VIDEO_OUTPUT;
- else
- vcap->device_caps |= V4L2_CAP_VIDEO_CAPTURE;
- vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS |
- V4L2_CAP_VIDEO_CAPTURE;
+ vcap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE |
+ V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_DEVICE_CAPS;
if (cobalt->have_hsma_tx)
vcap->capabilities |= V4L2_CAP_VIDEO_OUTPUT;
return 0;
@@ -1274,6 +1269,11 @@ static int cobalt_node_register(struct cobalt *cobalt, int node)
q->lock = &s->lock;
q->dev = &cobalt->pci_dev->dev;
vdev->queue = q;
+ vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
+ if (s->is_output)
+ vdev->device_caps |= V4L2_CAP_VIDEO_OUTPUT;
+ else
+ vdev->device_caps |= V4L2_CAP_VIDEO_CAPTURE;
video_set_drvdata(vdev, s);
ret = vb2_queue_init(q);
diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c
index 9f5972f6d3a6..d9ffc9c359ca 100644
--- a/drivers/media/pci/cx18/cx18-ioctl.c
+++ b/drivers/media/pci/cx18/cx18-ioctl.c
@@ -385,16 +385,13 @@ static int cx18_querycap(struct file *file, void *fh,
struct v4l2_capability *vcap)
{
struct cx18_open_id *id = fh2id(fh);
- struct cx18_stream *s = video_drvdata(file);
struct cx18 *cx = id->cx;
strscpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));
strscpy(vcap->card, cx->card_name, sizeof(vcap->card));
snprintf(vcap->bus_info, sizeof(vcap->bus_info),
"PCI:%s", pci_name(cx->pci_dev));
- vcap->capabilities = cx->v4l2_cap; /* capabilities */
- vcap->device_caps = s->v4l2_dev_caps; /* device capabilities */
- vcap->capabilities |= V4L2_CAP_DEVICE_CAPS;
+ vcap->capabilities = cx->v4l2_cap | V4L2_CAP_DEVICE_CAPS;
return 0;
}
diff --git a/drivers/media/pci/cx18/cx18-streams.c b/drivers/media/pci/cx18/cx18-streams.c
index 9805e50c2477..b79718519b9b 100644
--- a/drivers/media/pci/cx18/cx18-streams.c
+++ b/drivers/media/pci/cx18/cx18-streams.c
@@ -411,6 +411,7 @@ static int cx18_reg_dev(struct cx18 *cx, int type)
return 0;
num = s->video_dev.num;
+ s->video_dev.device_caps = s->v4l2_dev_caps; /* device capabilities */
/* card number + user defined offset + device offset */
if (type != CX18_ENC_STREAM_TYPE_MPG) {
struct cx18_stream *s_mpg = &cx->streams[CX18_ENC_STREAM_TYPE_MPG];
diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c
index 8aa5f9b1498a..82f96a4091ac 100644
--- a/drivers/media/pci/cx23885/cx23885-417.c
+++ b/drivers/media/pci/cx23885/cx23885-417.c
@@ -1324,12 +1324,11 @@ static int vidioc_querycap(struct file *file, void *priv,
strscpy(cap->card, cx23885_boards[tsport->dev->board].name,
sizeof(cap->card));
sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING | V4L2_CAP_VBI_CAPTURE |
+ V4L2_CAP_AUDIO | V4L2_CAP_DEVICE_CAPS;
if (dev->tuner_type != TUNER_ABSENT)
- cap->device_caps |= V4L2_CAP_TUNER;
- cap->capabilities = cap->device_caps | V4L2_CAP_VBI_CAPTURE |
- V4L2_CAP_AUDIO | V4L2_CAP_DEVICE_CAPS;
+ cap->capabilities |= V4L2_CAP_TUNER;
return 0;
}
@@ -1542,6 +1541,10 @@ int cx23885_417_register(struct cx23885_dev *dev)
video_set_drvdata(dev->v4l_device, dev);
dev->v4l_device->lock = &dev->lock;
dev->v4l_device->queue = q;
+ dev->v4l_device->device_caps = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+ if (dev->tuner_type != TUNER_ABSENT)
+ dev->v4l_device->device_caps |= V4L2_CAP_TUNER;
err = video_register_device(dev->v4l_device,
VFL_TYPE_GRABBER, -1);
if (err < 0) {
diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c
index c9ef9ff7b0bd..4f386db33a11 100644
--- a/drivers/media/pci/cx23885/cx23885-dvb.c
+++ b/drivers/media/pci/cx23885/cx23885-dvb.c
@@ -2647,8 +2647,6 @@ int cx23885_dvb_register(struct cx23885_tsport *port)
dev->pci_bus,
dev->pci_slot);
- err = -ENODEV;
-
/* dvb stuff */
/* We have to init the queue for each frontend on a port. */
pr_info("%s: cx23885 based dvb card\n", dev->name);
diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c
index 0c59ecccc38a..b254473db9a3 100644
--- a/drivers/media/pci/cx23885/cx23885-video.c
+++ b/drivers/media/pci/cx23885/cx23885-video.c
@@ -627,21 +627,17 @@ static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
struct cx23885_dev *dev = video_drvdata(file);
- struct video_device *vdev = video_devdata(file);
strscpy(cap->driver, "cx23885", sizeof(cap->driver));
strscpy(cap->card, cx23885_boards[dev->board].name,
sizeof(cap->card));
sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
- cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_AUDIO;
+ cap->capabilities = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
+ V4L2_CAP_AUDIO | V4L2_CAP_VBI_CAPTURE |
+ V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE |
+ V4L2_CAP_DEVICE_CAPS;
if (dev->tuner_type != TUNER_ABSENT)
- cap->device_caps |= V4L2_CAP_TUNER;
- if (vdev->vfl_type == VFL_TYPE_VBI)
- cap->device_caps |= V4L2_CAP_VBI_CAPTURE;
- else
- cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE;
- cap->capabilities = cap->device_caps | V4L2_CAP_VBI_CAPTURE |
- V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_DEVICE_CAPS;
+ cap->capabilities |= V4L2_CAP_TUNER;
return 0;
}
@@ -1306,6 +1302,10 @@ int cx23885_video_register(struct cx23885_dev *dev)
dev->video_dev = cx23885_vdev_init(dev, dev->pci,
&cx23885_video_template, "video");
dev->video_dev->queue = &dev->vb2_vidq;
+ dev->video_dev->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
+ V4L2_CAP_AUDIO | V4L2_CAP_VIDEO_CAPTURE;
+ if (dev->tuner_type != TUNER_ABSENT)
+ dev->video_dev->device_caps |= V4L2_CAP_TUNER;
err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER,
video_nr[dev->nr]);
if (err < 0) {
@@ -1320,6 +1320,10 @@ int cx23885_video_register(struct cx23885_dev *dev)
dev->vbi_dev = cx23885_vdev_init(dev, dev->pci,
&cx23885_vbi_template, "vbi");
dev->vbi_dev->queue = &dev->vb2_vbiq;
+ dev->vbi_dev->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
+ V4L2_CAP_AUDIO | V4L2_CAP_VBI_CAPTURE;
+ if (dev->tuner_type != TUNER_ABSENT)
+ dev->vbi_dev->device_caps |= V4L2_CAP_TUNER;
err = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
vbi_nr[dev->nr]);
if (err < 0) {
diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c
index 1bb5dfc74e27..de7641170478 100644
--- a/drivers/media/pci/cx25821/cx25821-video.c
+++ b/drivers/media/pci/cx25821/cx25821-video.c
@@ -426,18 +426,13 @@ static int cx25821_vidioc_querycap(struct file *file, void *priv,
{
struct cx25821_channel *chan = video_drvdata(file);
struct cx25821_dev *dev = chan->dev;
- const u32 cap_input = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
- const u32 cap_output = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_READWRITE;
strscpy(cap->driver, "cx25821", sizeof(cap->driver));
strscpy(cap->card, cx25821_boards[dev->board].name, sizeof(cap->card));
sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
- if (chan->id >= VID_CHANNEL_NUM)
- cap->device_caps = cap_output;
- else
- cap->device_caps = cap_input;
- cap->capabilities = cap_input | cap_output | V4L2_CAP_DEVICE_CAPS;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
+ V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
+ V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -624,6 +619,8 @@ static const struct video_device cx25821_video_device = {
.minor = -1,
.ioctl_ops = &video_ioctl_ops,
.tvnorms = CX25821_NORMS,
+ .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING,
};
static const struct v4l2_file_operations video_out_fops = {
@@ -657,6 +654,7 @@ static const struct video_device cx25821_video_out_device = {
.minor = -1,
.ioctl_ops = &video_out_ioctl_ops,
.tvnorms = CX25821_NORMS,
+ .device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_READWRITE,
};
void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num)
diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c
index b4ad5d12054e..e1e71ae293ed 100644
--- a/drivers/media/pci/cx88/cx88-alsa.c
+++ b/drivers/media/pci/cx88/cx88-alsa.c
@@ -95,7 +95,7 @@ MODULE_PARM_DESC(index, "Index value for cx88x capture interface(s).");
MODULE_DESCRIPTION("ALSA driver module for cx2388x based TV cards");
MODULE_AUTHOR("Ricardo Cerqueira");
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@kernel.org>");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_VERSION(CX88_VERSION);
MODULE_SUPPORTED_DEVICE("{{Conexant,23881},{{Conexant,23882},{{Conexant,23883}");
diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c
index 0a10c9d192f3..200d68827073 100644
--- a/drivers/media/pci/cx88/cx88-blackbird.c
+++ b/drivers/media/pci/cx88/cx88-blackbird.c
@@ -28,7 +28,7 @@
MODULE_DESCRIPTION("driver for cx2388x/cx23416 based mpeg encoder cards");
MODULE_AUTHOR("Jelle Foks <jelle@foks.us>, Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_VERSION(CX88_VERSION);
static unsigned int debug;
@@ -1136,6 +1136,10 @@ static int blackbird_register_video(struct cx8802_dev *dev)
dev->mpeg_dev.ctrl_handler = &dev->cxhdl.hdl;
video_set_drvdata(&dev->mpeg_dev, dev);
dev->mpeg_dev.queue = &dev->vb2_mpegq;
+ dev->mpeg_dev.device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_CAPTURE;
+ if (dev->core->board.tuner_type != UNSET)
+ dev->mpeg_dev.device_caps |= V4L2_CAP_TUNER;
err = video_register_device(&dev->mpeg_dev, VFL_TYPE_GRABBER, -1);
if (err < 0) {
pr_info("can't register mpeg device\n");
diff --git a/drivers/media/pci/cx88/cx88-core.c b/drivers/media/pci/cx88/cx88-core.c
index 8597cb8274ab..dcadf78657d6 100644
--- a/drivers/media/pci/cx88/cx88-core.c
+++ b/drivers/media/pci/cx88/cx88-core.c
@@ -31,7 +31,7 @@
MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
/* ------------------------------------------------------------------ */
diff --git a/drivers/media/pci/cx88/cx88-i2c.c b/drivers/media/pci/cx88/cx88-i2c.c
index 50a9ae3fa596..7fc64aef1ef7 100644
--- a/drivers/media/pci/cx88/cx88-i2c.c
+++ b/drivers/media/pci/cx88/cx88-i2c.c
@@ -8,7 +8,6 @@
* & Marcus Metzler (mocm@thp.uni-koeln.de)
* (c) 2002 Yurij Sysoev <yurij@naturesoft.net>
* (c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
- *
* (c) 2005 Mauro Carvalho Chehab <mchehab@kernel.org>
* - Multituner support and i2c address binding
*/
diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c
index 27f690b54e0c..589f52d961eb 100644
--- a/drivers/media/pci/cx88/cx88-input.c
+++ b/drivers/media/pci/cx88/cx88-input.c
@@ -167,14 +167,14 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
static enum hrtimer_restart cx88_ir_work(struct hrtimer *timer)
{
- unsigned long missed;
+ u64 missed;
struct cx88_IR *ir = container_of(timer, struct cx88_IR, timer);
cx88_ir_handle_key(ir);
missed = hrtimer_forward_now(&ir->timer,
ktime_set(0, ir->polling * 1000000));
if (missed > 1)
- ir_dprintk("Missed ticks %ld\n", missed - 1);
+ ir_dprintk("Missed ticks %llu\n", missed - 1);
return HRTIMER_RESTART;
}
diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c
index 3b49ebb21b13..e59a74514c7c 100644
--- a/drivers/media/pci/cx88/cx88-video.c
+++ b/drivers/media/pci/cx88/cx88-video.c
@@ -33,7 +33,7 @@
MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_VERSION(CX88_VERSION);
/* ------------------------------------------------------------------ */
@@ -800,27 +800,12 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
int cx88_querycap(struct file *file, struct cx88_core *core,
struct v4l2_capability *cap)
{
- struct video_device *vdev = video_devdata(file);
-
strscpy(cap->card, core->board.name, sizeof(cap->card));
- cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+ cap->capabilities = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE |
+ V4L2_CAP_DEVICE_CAPS;
if (core->board.tuner_type != UNSET)
- cap->device_caps |= V4L2_CAP_TUNER;
- switch (vdev->vfl_type) {
- case VFL_TYPE_RADIO:
- cap->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
- break;
- case VFL_TYPE_GRABBER:
- cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE;
- break;
- case VFL_TYPE_VBI:
- cap->device_caps |= V4L2_CAP_VBI_CAPTURE;
- break;
- default:
- return -EINVAL;
- }
- cap->capabilities = cap->device_caps | V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_VBI_CAPTURE | V4L2_CAP_DEVICE_CAPS;
+ cap->capabilities |= V4L2_CAP_TUNER;
if (core->board.radio.type == CX88_RADIO)
cap->capabilities |= V4L2_CAP_RADIO;
return 0;
@@ -1473,6 +1458,10 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
video_set_drvdata(&dev->video_dev, dev);
dev->video_dev.ctrl_handler = &core->video_hdl;
dev->video_dev.queue = &dev->vb2_vidq;
+ dev->video_dev.device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_CAPTURE;
+ if (core->board.tuner_type != UNSET)
+ dev->video_dev.device_caps |= V4L2_CAP_TUNER;
err = video_register_device(&dev->video_dev, VFL_TYPE_GRABBER,
video_nr[core->nr]);
if (err < 0) {
@@ -1486,6 +1475,10 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
&cx8800_vbi_template, "vbi");
video_set_drvdata(&dev->vbi_dev, dev);
dev->vbi_dev.queue = &dev->vb2_vbiq;
+ dev->vbi_dev.device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
+ V4L2_CAP_VBI_CAPTURE;
+ if (core->board.tuner_type != UNSET)
+ dev->vbi_dev.device_caps |= V4L2_CAP_TUNER;
err = video_register_device(&dev->vbi_dev, VFL_TYPE_VBI,
vbi_nr[core->nr]);
if (err < 0) {
@@ -1500,6 +1493,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
&cx8800_radio_template, "radio");
video_set_drvdata(&dev->radio_dev, dev);
dev->radio_dev.ctrl_handler = &core->audio_hdl;
+ dev->radio_dev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
err = video_register_device(&dev->radio_dev, VFL_TYPE_RADIO,
radio_nr[core->nr]);
if (err < 0) {
diff --git a/drivers/media/pci/ddbridge/Kconfig b/drivers/media/pci/ddbridge/Kconfig
index eaac91d14654..dab34fb85c09 100644
--- a/drivers/media/pci/ddbridge/Kconfig
+++ b/drivers/media/pci/ddbridge/Kconfig
@@ -36,7 +36,6 @@ config DVB_DDBRIDGE_MSIENABLE
bool "Enable Message Signaled Interrupts (MSI) per default (EXPERIMENTAL)"
depends on DVB_DDBRIDGE
depends on PCI_MSI
- default n
help
Use PCI MSI (Message Signaled Interrupts) per default. Enabling this
might lead to I2C errors originating from the bridge in conjunction
diff --git a/drivers/media/pci/dt3155/Kconfig b/drivers/media/pci/dt3155/Kconfig
index d678ced93f17..a3d24b8a719b 100644
--- a/drivers/media/pci/dt3155/Kconfig
+++ b/drivers/media/pci/dt3155/Kconfig
@@ -3,7 +3,6 @@ config VIDEO_DT3155
tristate "DT3155 frame grabber"
depends on PCI && VIDEO_DEV && VIDEO_V4L2
select VIDEOBUF2_DMA_CONTIG
- default n
help
Enables dt3155 device driver for the DataTranslation DT3155 frame grabber.
Say Y here if you have this hardware.
diff --git a/drivers/media/pci/dt3155/dt3155.c b/drivers/media/pci/dt3155/dt3155.c
index d6d29e61aae9..b4cdda50e742 100644
--- a/drivers/media/pci/dt3155/dt3155.c
+++ b/drivers/media/pci/dt3155/dt3155.c
@@ -297,9 +297,6 @@ static int dt3155_querycap(struct file *filp, void *p,
strscpy(cap->driver, DT3155_NAME, sizeof(cap->driver));
strscpy(cap->card, DT3155_NAME " frame grabber", sizeof(cap->card));
sprintf(cap->bus_info, "PCI:%s", pci_name(pd->pdev));
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -490,6 +487,8 @@ static const struct video_device dt3155_vdev = {
.minor = -1,
.release = video_device_release_empty,
.tvnorms = V4L2_STD_ALL,
+ .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE,
};
static int dt3155_probe(struct pci_dev *pdev, const struct pci_device_id *id)
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
index 2a52a393fe74..c1d133e17e4b 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
@@ -1174,7 +1174,7 @@ static const struct v4l2_file_operations cio2_v4l2_fops = {
static const struct v4l2_ioctl_ops cio2_v4l2_ioctl_ops = {
.vidioc_querycap = cio2_v4l2_querycap,
- .vidioc_enum_fmt_vid_cap_mplane = cio2_v4l2_enum_fmt,
+ .vidioc_enum_fmt_vid_cap = cio2_v4l2_enum_fmt,
.vidioc_g_fmt_vid_cap_mplane = cio2_v4l2_g_fmt,
.vidioc_s_fmt_vid_cap_mplane = cio2_v4l2_s_fmt,
.vidioc_try_fmt_vid_cap_mplane = cio2_v4l2_try_fmt,
diff --git a/drivers/media/pci/ivtv/Kconfig b/drivers/media/pci/ivtv/Kconfig
index 079569955fb4..36c089103cf9 100644
--- a/drivers/media/pci/ivtv/Kconfig
+++ b/drivers/media/pci/ivtv/Kconfig
@@ -32,7 +32,6 @@ config VIDEO_IVTV
config VIDEO_IVTV_DEPRECATED_IOCTLS
bool "enable the DVB ioctls abuse on ivtv driver"
depends on VIDEO_IVTV
- default n
help
Enable the usage of the a DVB set of ioctls that were abused by
IVTV driver for a while.
@@ -77,7 +76,6 @@ config VIDEO_FB_IVTV
config VIDEO_FB_IVTV_FORCE_PAT
bool "force cx23415 framebuffer init with x86 PAT enabled"
depends on VIDEO_FB_IVTV && X86_PAT
- default n
help
With PAT enabled, the cx23415 framebuffer driver does not
utilize write-combined caching on the framebuffer memory.
diff --git a/drivers/media/pci/ivtv/ivtv-cards.h b/drivers/media/pci/ivtv/ivtv-cards.h
index 965def0cbfaa..f3e2c5634962 100644
--- a/drivers/media/pci/ivtv/ivtv-cards.h
+++ b/drivers/media/pci/ivtv/ivtv-cards.h
@@ -156,8 +156,7 @@
#define IVTV_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \
V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE | \
V4L2_CAP_SLICED_VBI_CAPTURE)
-#define IVTV_CAP_DECODER (V4L2_CAP_VIDEO_OUTPUT | \
- V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_OVERLAY)
+#define IVTV_CAP_DECODER (V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_SLICED_VBI_OUTPUT)
struct ivtv_card_video_input {
u8 video_type; /* video input type */
diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c
index d1e358a2273e..5595f6a274e7 100644
--- a/drivers/media/pci/ivtv/ivtv-ioctl.c
+++ b/drivers/media/pci/ivtv/ivtv-ioctl.c
@@ -734,18 +734,11 @@ static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vc
{
struct ivtv_open_id *id = fh2id(file->private_data);
struct ivtv *itv = id->itv;
- struct ivtv_stream *s = &itv->streams[id->type];
strscpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver));
strscpy(vcap->card, itv->card_name, sizeof(vcap->card));
snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->pdev));
vcap->capabilities = itv->v4l2_cap | V4L2_CAP_DEVICE_CAPS;
- vcap->device_caps = s->caps;
- if ((s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY) &&
- !itv->osd_video_pbase) {
- vcap->capabilities &= ~V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
- vcap->device_caps &= ~V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
- }
return 0;
}
diff --git a/drivers/media/pci/ivtv/ivtv-streams.c b/drivers/media/pci/ivtv/ivtv-streams.c
index a641f20e3f86..f7de9118f609 100644
--- a/drivers/media/pci/ivtv/ivtv-streams.c
+++ b/drivers/media/pci/ivtv/ivtv-streams.c
@@ -139,8 +139,7 @@ static struct {
"decoder MPG",
VFL_TYPE_GRABBER, IVTV_V4L2_DEC_MPG_OFFSET,
PCI_DMA_TODEVICE, 0,
- V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE |
- V4L2_CAP_VIDEO_OUTPUT_OVERLAY,
+ V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
&ivtv_v4l2_dec_fops
},
{ /* IVTV_DEC_STREAM_TYPE_VBI */
@@ -161,8 +160,7 @@ static struct {
"decoder YUV",
VFL_TYPE_GRABBER, IVTV_V4L2_DEC_YUV_OFFSET,
PCI_DMA_TODEVICE, 0,
- V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE |
- V4L2_CAP_VIDEO_OUTPUT_OVERLAY,
+ V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
&ivtv_v4l2_dec_fops
}
};
@@ -301,6 +299,14 @@ static int ivtv_reg_dev(struct ivtv *itv, int type)
if (s_mpg->vdev.v4l2_dev)
num = s_mpg->vdev.num + ivtv_stream_info[type].num_offset;
}
+ s->vdev.device_caps = s->caps;
+ if (itv->osd_video_pbase) {
+ itv->streams[IVTV_DEC_STREAM_TYPE_YUV].vdev.device_caps |=
+ V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
+ itv->streams[IVTV_DEC_STREAM_TYPE_MPG].vdev.device_caps |=
+ V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
+ itv->v4l2_cap |= V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
+ }
video_set_drvdata(&s->vdev, s);
/* Register device. First try the desired minor, then any free one. */
diff --git a/drivers/media/pci/ivtv/ivtvfb.c b/drivers/media/pci/ivtv/ivtvfb.c
index 299ff032f528..95a56cce9b65 100644
--- a/drivers/media/pci/ivtv/ivtvfb.c
+++ b/drivers/media/pci/ivtv/ivtvfb.c
@@ -1220,6 +1220,11 @@ static int ivtvfb_init_card(struct ivtv *itv)
/* Allocate DMA */
ivtv_udma_alloc(itv);
+ itv->streams[IVTV_DEC_STREAM_TYPE_YUV].vdev.device_caps |=
+ V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
+ itv->streams[IVTV_DEC_STREAM_TYPE_MPG].vdev.device_caps |=
+ V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
+ itv->v4l2_cap |= V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
return 0;
}
@@ -1246,6 +1251,11 @@ static int ivtvfb_callback_cleanup(struct device *dev, void *p)
struct osd_info *oi = itv->osd_info;
if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+ itv->streams[IVTV_DEC_STREAM_TYPE_YUV].vdev.device_caps &=
+ ~V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
+ itv->streams[IVTV_DEC_STREAM_TYPE_MPG].vdev.device_caps &=
+ ~V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
+ itv->v4l2_cap &= ~V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
unregister_framebuffer(&itv->osd_info->ivtvfb_info);
IVTVFB_INFO("Unregister framebuffer %d\n", itv->instance);
itv->ivtvfb_restore = NULL;
diff --git a/drivers/media/pci/meye/Kconfig b/drivers/media/pci/meye/Kconfig
index b0ba78abbdbb..b37da612dd0c 100644
--- a/drivers/media/pci/meye/Kconfig
+++ b/drivers/media/pci/meye/Kconfig
@@ -2,7 +2,8 @@
config VIDEO_MEYE
tristate "Sony Vaio Picturebook Motion Eye Video For Linux"
depends on PCI && VIDEO_V4L2
- depends on SONY_LAPTOP || COMPILE_TEST
+ depends on SONY_LAPTOP
+ depends on X86 || COMPILE_TEST
help
This is the video4linux driver for the Motion Eye camera found
in the Vaio Picturebook laptops. Please read the material in
diff --git a/drivers/media/pci/meye/meye.c b/drivers/media/pci/meye/meye.c
index bbe91b0f2565..8218810c899e 100644
--- a/drivers/media/pci/meye/meye.c
+++ b/drivers/media/pci/meye/meye.c
@@ -1013,11 +1013,6 @@ static int vidioc_querycap(struct file *file, void *fh,
strscpy(cap->driver, "meye", sizeof(cap->driver));
strscpy(cap->card, "meye", sizeof(cap->card));
sprintf(cap->bus_info, "PCI:%s", pci_name(meye.mchip_dev));
-
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
-
return 0;
}
@@ -1529,6 +1524,7 @@ static const struct video_device meye_template = {
.fops = &meye_fops,
.ioctl_ops = &meye_ioctl_ops,
.release = video_device_release_empty,
+ .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING,
};
static const struct v4l2_ctrl_ops meye_ctrl_ops = {
diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c
index 7a106bc11a2b..6185806a00e0 100644
--- a/drivers/media/pci/ngene/ngene-cards.c
+++ b/drivers/media/pci/ngene/ngene-cards.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ngene-cards.c: nGene PCIe bridge driver - card specific info
*
@@ -7,20 +8,6 @@
* Modifications for new nGene firmware,
* support for EEPROM-copying,
* support for new dual DVB-S2 card prototype
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * To obtain the license, point your browser to
- * http://www.gnu.org/copyleft/gpl.html
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c
index 27953b3610a3..b75ab7d29226 100644
--- a/drivers/media/pci/ngene/ngene-core.c
+++ b/drivers/media/pci/ngene/ngene-core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ngene.c: nGene PCIe bridge driver
*
@@ -7,20 +8,6 @@
* Modifications for new nGene firmware,
* support for EEPROM-copying,
* support for new dual DVB-S2 card prototype
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * To obtain the license, point your browser to
- * http://www.gnu.org/copyleft/gpl.html
*/
#include <linux/module.h>
diff --git a/drivers/media/pci/ngene/ngene-dvb.c b/drivers/media/pci/ngene/ngene-dvb.c
index 5147e83397a1..fda24ba3dc3c 100644
--- a/drivers/media/pci/ngene/ngene-dvb.c
+++ b/drivers/media/pci/ngene/ngene-dvb.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ngene-dvb.c: nGene PCIe bridge driver - DVB functions
*
@@ -7,20 +8,6 @@
* Modifications for new nGene firmware,
* support for EEPROM-copying,
* support for new dual DVB-S2 card prototype
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * To obtain the license, point your browser to
- * http://www.gnu.org/copyleft/gpl.html
*/
#include <linux/module.h>
diff --git a/drivers/media/pci/ngene/ngene-i2c.c b/drivers/media/pci/ngene/ngene-i2c.c
index 02a06f6c97f8..2e9e9774dc6f 100644
--- a/drivers/media/pci/ngene/ngene-i2c.c
+++ b/drivers/media/pci/ngene/ngene-i2c.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ngene-i2c.c: nGene PCIe bridge driver i2c functions
*
@@ -7,20 +8,6 @@
* Modifications for new nGene firmware,
* support for EEPROM-copying,
* support for new dual DVB-S2 card prototype
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * To obtain the license, point your browser to
- * http://www.gnu.org/copyleft/gpl.html
*/
/* FIXME - some of these can probably be removed */
diff --git a/drivers/media/pci/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h
index 01d9f1b58fcb..84f04e0e0cb9 100644
--- a/drivers/media/pci/ngene/ngene.h
+++ b/drivers/media/pci/ngene/ngene.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* ngene.h: nGene PCIe bridge driver
*
* Copyright (C) 2005-2007 Micronas
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * To obtain the license, point your browser to
- * http://www.gnu.org/copyleft/gpl.html
*/
#ifndef _NGENE_H_
diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c
index fa9a0ead46d5..2d582c02adbf 100644
--- a/drivers/media/pci/saa7134/saa7134-core.c
+++ b/drivers/media/pci/saa7134/saa7134-core.c
@@ -1206,6 +1206,14 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
dev->video_dev->ctrl_handler = &dev->ctrl_handler;
dev->video_dev->lock = &dev->lock;
dev->video_dev->queue = &dev->video_vbq;
+ dev->video_dev->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_CAPTURE;
+ if (dev->tuner_type != TUNER_ABSENT && dev->tuner_type != UNSET)
+ dev->video_dev->device_caps |= V4L2_CAP_TUNER;
+
+ if (saa7134_no_overlay <= 0)
+ dev->video_dev->device_caps |= V4L2_CAP_VIDEO_OVERLAY;
+
err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER,
video_nr[dev->nr]);
if (err < 0) {
@@ -1220,6 +1228,10 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
dev->vbi_dev->ctrl_handler = &dev->ctrl_handler;
dev->vbi_dev->lock = &dev->lock;
dev->vbi_dev->queue = &dev->vbi_vbq;
+ dev->vbi_dev->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
+ V4L2_CAP_VBI_CAPTURE;
+ if (dev->tuner_type != TUNER_ABSENT && dev->tuner_type != UNSET)
+ dev->vbi_dev->device_caps |= V4L2_CAP_TUNER;
err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI,
vbi_nr[dev->nr]);
@@ -1232,6 +1244,9 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
dev->radio_dev = vdev_init(dev,&saa7134_radio_template,"radio");
dev->radio_dev->ctrl_handler = &dev->radio_ctrl_handler;
dev->radio_dev->lock = &dev->lock;
+ dev->radio_dev->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
+ if (dev->has_rds)
+ dev->radio_dev->device_caps |= V4L2_CAP_RDS_CAPTURE;
err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO,
radio_nr[dev->nr]);
if (err < 0)
diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c
index 17eafaa5bf02..1a41a56afec6 100644
--- a/drivers/media/pci/saa7134/saa7134-empress.c
+++ b/drivers/media/pci/saa7134/saa7134-empress.c
@@ -287,6 +287,10 @@ static int empress_init(struct saa7134_dev *dev)
if (err)
return err;
dev->empress_dev->queue = q;
+ dev->empress_dev->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_CAPTURE;
+ if (dev->tuner_type != TUNER_ABSENT && dev->tuner_type != UNSET)
+ dev->empress_dev->device_caps |= V4L2_CAP_TUNER;
video_set_drvdata(dev->empress_dev, dev);
err = video_register_device(dev->empress_dev,VFL_TYPE_GRABBER,
diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c
index 89c1271476c7..606df51bb636 100644
--- a/drivers/media/pci/saa7134/saa7134-video.c
+++ b/drivers/media/pci/saa7134/saa7134-video.c
@@ -1489,50 +1489,20 @@ int saa7134_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
struct saa7134_dev *dev = video_drvdata(file);
- struct video_device *vdev = video_devdata(file);
- u32 radio_caps, video_caps, vbi_caps;
-
- unsigned int tuner_type = dev->tuner_type;
strscpy(cap->driver, "saa7134", sizeof(cap->driver));
strscpy(cap->card, saa7134_boards[dev->board].name,
sizeof(cap->card));
sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
-
- cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
- if ((tuner_type != TUNER_ABSENT) && (tuner_type != UNSET))
- cap->device_caps |= V4L2_CAP_TUNER;
-
- radio_caps = V4L2_CAP_RADIO;
+ cap->capabilities = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
+ V4L2_CAP_RADIO | V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_VBI_CAPTURE | V4L2_CAP_DEVICE_CAPS;
+ if (dev->tuner_type != TUNER_ABSENT && dev->tuner_type != UNSET)
+ cap->capabilities |= V4L2_CAP_TUNER;
if (dev->has_rds)
- radio_caps |= V4L2_CAP_RDS_CAPTURE;
-
- video_caps = V4L2_CAP_VIDEO_CAPTURE;
- if (saa7134_no_overlay <= 0 && !is_empress(file))
- video_caps |= V4L2_CAP_VIDEO_OVERLAY;
-
- vbi_caps = V4L2_CAP_VBI_CAPTURE;
-
- switch (vdev->vfl_type) {
- case VFL_TYPE_RADIO:
- cap->device_caps |= radio_caps;
- break;
- case VFL_TYPE_GRABBER:
- cap->device_caps |= video_caps;
- break;
- case VFL_TYPE_VBI:
- cap->device_caps |= vbi_caps;
- break;
- default:
- return -EINVAL;
- }
- cap->capabilities = radio_caps | video_caps | vbi_caps |
- cap->device_caps | V4L2_CAP_DEVICE_CAPS;
- if (vdev->vfl_type == VFL_TYPE_RADIO) {
- cap->device_caps &= ~V4L2_CAP_STREAMING;
- if (!dev->has_rds)
- cap->device_caps &= ~V4L2_CAP_READWRITE;
- }
+ cap->capabilities |= V4L2_CAP_RDS_CAPTURE;
+ if (saa7134_no_overlay <= 0)
+ cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
return 0;
}
diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c
index c594aff92e70..9ae04e18e6c6 100644
--- a/drivers/media/pci/saa7164/saa7164-core.c
+++ b/drivers/media/pci/saa7164/saa7164-core.c
@@ -1112,16 +1112,25 @@ static int saa7164_proc_show(struct seq_file *m, void *v)
return 0;
}
+static struct proc_dir_entry *saa7164_pe;
+
static int saa7164_proc_create(void)
{
- struct proc_dir_entry *pe;
-
- pe = proc_create_single("saa7164", S_IRUGO, NULL, saa7164_proc_show);
- if (!pe)
+ saa7164_pe = proc_create_single("saa7164", 0444, NULL, saa7164_proc_show);
+ if (!saa7164_pe)
return -ENOMEM;
return 0;
}
+
+static void saa7164_proc_destroy(void)
+{
+ if (saa7164_pe)
+ remove_proc_entry("saa7164", NULL);
+}
+#else
+static int saa7164_proc_create(void) { return 0; }
+static void saa7164_proc_destroy(void) {}
#endif
static int saa7164_thread_function(void *data)
@@ -1493,19 +1502,21 @@ static struct pci_driver saa7164_pci_driver = {
static int __init saa7164_init(void)
{
- printk(KERN_INFO "saa7164 driver loaded\n");
+ int ret = pci_register_driver(&saa7164_pci_driver);
+
+ if (ret)
+ return ret;
-#ifdef CONFIG_PROC_FS
saa7164_proc_create();
-#endif
- return pci_register_driver(&saa7164_pci_driver);
+
+ pr_info("saa7164 driver loaded\n");
+
+ return 0;
}
static void __exit saa7164_fini(void)
{
-#ifdef CONFIG_PROC_FS
- remove_proc_entry("saa7164", NULL);
-#endif
+ saa7164_proc_destroy();
pci_unregister_driver(&saa7164_pci_driver);
}
diff --git a/drivers/media/pci/saa7164/saa7164-encoder.c b/drivers/media/pci/saa7164/saa7164-encoder.c
index dcfabad8b284..43fdaa2d32bd 100644
--- a/drivers/media/pci/saa7164/saa7164-encoder.c
+++ b/drivers/media/pci/saa7164/saa7164-encoder.c
@@ -491,16 +491,9 @@ static int vidioc_querycap(struct file *file, void *priv,
strscpy(cap->card, saa7164_boards[dev->board].name,
sizeof(cap->card));
sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
-
- cap->device_caps =
- V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_READWRITE |
- V4L2_CAP_TUNER;
-
- cap->capabilities = cap->device_caps |
- V4L2_CAP_VBI_CAPTURE |
- V4L2_CAP_DEVICE_CAPS;
-
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE |
+ V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -973,6 +966,8 @@ static struct video_device saa7164_mpeg_template = {
.ioctl_ops = &mpeg_ioctl_ops,
.minor = -1,
.tvnorms = SAA7164_NORMS,
+ .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_TUNER,
};
static struct video_device *saa7164_encoder_alloc(
diff --git a/drivers/media/pci/saa7164/saa7164-vbi.c b/drivers/media/pci/saa7164/saa7164-vbi.c
index 154a04d17ce5..49d61a64c8cb 100644
--- a/drivers/media/pci/saa7164/saa7164-vbi.c
+++ b/drivers/media/pci/saa7164/saa7164-vbi.c
@@ -202,16 +202,9 @@ static int vidioc_querycap(struct file *file, void *priv,
strscpy(cap->card, saa7164_boards[dev->board].name,
sizeof(cap->card));
sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
-
- cap->device_caps =
- V4L2_CAP_VBI_CAPTURE |
- V4L2_CAP_READWRITE |
- V4L2_CAP_TUNER;
-
- cap->capabilities = cap->device_caps |
- V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_DEVICE_CAPS;
-
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE |
+ V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -675,6 +668,8 @@ static struct video_device saa7164_vbi_template = {
.ioctl_ops = &vbi_ioctl_ops,
.minor = -1,
.tvnorms = SAA7164_NORMS,
+ .device_caps = V4L2_CAP_VBI_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_TUNER,
};
static struct video_device *saa7164_vbi_alloc(
diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c
index 73698cc26dd5..609100a46ff8 100644
--- a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c
+++ b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c
@@ -771,9 +771,6 @@ static int solo_enc_querycap(struct file *file, void *priv,
solo_enc->ch);
snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
pci_name(solo_dev->pdev));
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -1191,6 +1188,8 @@ static const struct video_device solo_enc_template = {
.minor = -1,
.release = video_device_release,
.tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL,
+ .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING,
};
static const struct v4l2_ctrl_ops solo_ctrl_ops = {
diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2.c b/drivers/media/pci/solo6x10/solo6x10-v4l2.c
index 1ce431af8fc6..a968f75920b5 100644
--- a/drivers/media/pci/solo6x10/solo6x10-v4l2.c
+++ b/drivers/media/pci/solo6x10/solo6x10-v4l2.c
@@ -378,9 +378,6 @@ static int solo_querycap(struct file *file, void *priv,
strscpy(cap->card, "Softlogic 6x10", sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
pci_name(solo_dev->pdev));
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -628,6 +625,8 @@ static const struct video_device solo_v4l2_template = {
.minor = -1,
.release = video_device_release,
.tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL,
+ .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING,
};
static const struct v4l2_ctrl_ops solo_ctrl_ops = {
diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c
index 9de5b2a35519..e52e29814378 100644
--- a/drivers/media/pci/sta2x11/sta2x11_vip.c
+++ b/drivers/media/pci/sta2x11/sta2x11_vip.c
@@ -407,10 +407,6 @@ static int vidioc_querycap(struct file *file, void *priv,
strscpy(cap->card, KBUILD_MODNAME, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
pci_name(vip->pdev));
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
-
return 0;
}
@@ -759,6 +755,8 @@ static const struct video_device video_dev_template = {
.fops = &vip_fops,
.ioctl_ops = &vip_ioctl_ops,
.tvnorms = V4L2_STD_ALL,
+ .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING,
};
/**
diff --git a/drivers/media/pci/ttpci/Kconfig b/drivers/media/pci/ttpci/Kconfig
index d96d4fa20457..8a362ee9105f 100644
--- a/drivers/media/pci/ttpci/Kconfig
+++ b/drivers/media/pci/ttpci/Kconfig
@@ -1,13 +1,14 @@
# SPDX-License-Identifier: GPL-2.0-only
config DVB_AV7110_IR
bool
+ depends on RC_CORE=y || RC_CORE = DVB_AV7110
+ default DVB_AV7110
config DVB_AV7110
tristate "AV7110 cards"
depends on DVB_CORE && PCI && I2C
select TTPCI_EEPROM
select VIDEO_SAA7146_VV
- select DVB_AV7110_IR if INPUT_EVDEV=y || INPUT_EVDEV=DVB_AV7110
depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV
select DVB_VES1820 if MEDIA_SUBDRV_AUTOSELECT
select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT
diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c
index e6ee23544a6e..d0cdee1c6eb0 100644
--- a/drivers/media/pci/ttpci/av7110.c
+++ b/drivers/media/pci/ttpci/av7110.c
@@ -218,7 +218,7 @@ static void recover_arm(struct av7110 *av7110)
restart_feeds(av7110);
#if IS_ENABLED(CONFIG_DVB_AV7110_IR)
- av7110_check_ir_config(av7110, true);
+ av7110_set_ir_config(av7110);
#endif
}
@@ -250,10 +250,6 @@ static int arm_thread(void *data)
if (!av7110->arm_ready)
continue;
-#if IS_ENABLED(CONFIG_DVB_AV7110_IR)
- av7110_check_ir_config(av7110, false);
-#endif
-
if (mutex_lock_interruptible(&av7110->dcomlock))
break;
newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2);
@@ -659,9 +655,11 @@ static void gpioirq(unsigned long cookie)
return;
case DATA_IRCOMMAND:
- if (av7110->ir.ir_handler)
- av7110->ir.ir_handler(av7110,
- swahw32(irdebi(av7110, DEBINOSWAP, Reserved, 0, 4)));
+#if IS_ENABLED(CONFIG_DVB_AV7110_IR)
+ av7110_ir_handler(av7110,
+ swahw32(irdebi(av7110, DEBINOSWAP, Reserved,
+ 0, 4)));
+#endif
iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
break;
diff --git a/drivers/media/pci/ttpci/av7110.h b/drivers/media/pci/ttpci/av7110.h
index 8606ef5ebbe2..809d938ae166 100644
--- a/drivers/media/pci/ttpci/av7110.h
+++ b/drivers/media/pci/ttpci/av7110.h
@@ -81,23 +81,11 @@ struct av7110;
/* infrared remote control */
struct infrared {
- u16 key_map[256];
- struct input_dev *input_dev;
+ struct rc_dev *rcdev;
char input_phys[32];
- struct timer_list keyup_timer;
- struct tasklet_struct ir_tasklet;
- void (*ir_handler)(struct av7110 *av7110, u32 ircom);
- u32 ir_command;
u32 ir_config;
- u32 device_mask;
- u8 protocol;
- u8 inversion;
- u16 last_key;
- u16 last_toggle;
- bool keypressed;
};
-
/* place to store all the necessary device information */
struct av7110 {
@@ -304,9 +292,10 @@ struct av7110 {
extern int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
u16 subpid, u16 pcrpid);
-extern int av7110_check_ir_config(struct av7110 *av7110, int force);
-extern int av7110_ir_init(struct av7110 *av7110);
-extern void av7110_ir_exit(struct av7110 *av7110);
+void av7110_ir_handler(struct av7110 *av7110, u32 ircom);
+int av7110_set_ir_config(struct av7110 *av7110);
+int av7110_ir_init(struct av7110 *av7110);
+void av7110_ir_exit(struct av7110 *av7110);
/* msp3400 i2c subaddresses */
#define MSP_WR_DEM 0x10
diff --git a/drivers/media/pci/ttpci/av7110_ir.c b/drivers/media/pci/ttpci/av7110_ir.c
index dfa18878e5f0..432789a3c312 100644
--- a/drivers/media/pci/ttpci/av7110_ir.c
+++ b/drivers/media/pci/ttpci/av7110_ir.c
@@ -4,379 +4,156 @@
*
* Copyright (C) 1999-2003 Holger Waechtler <holger@convergence.de>
* Copyright (C) 2003-2007 Oliver Endriss <o.endriss@gmx.de>
+ * Copyright (C) 2019 Sean Young <sean@mess.org>
*/
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/proc_fs.h>
#include <linux/kernel.h>
-#include <linux/bitops.h>
+#include <media/rc-core.h>
#include "av7110.h"
#include "av7110_hw.h"
-
-#define AV_CNT 4
-
#define IR_RC5 0
#define IR_RCMM 1
#define IR_RC5_EXT 2 /* internal only */
-#define IR_ALL 0xffffffff
-
-#define UP_TIMEOUT (HZ*7/25)
-
-
-/* Note: enable ir debugging by or'ing debug with 16 */
-
-static int ir_protocol[AV_CNT] = { IR_RCMM, IR_RCMM, IR_RCMM, IR_RCMM};
-module_param_array(ir_protocol, int, NULL, 0644);
-MODULE_PARM_DESC(ir_protocol, "Infrared protocol: 0 RC5, 1 RCMM (default)");
-
-static int ir_inversion[AV_CNT];
-module_param_array(ir_inversion, int, NULL, 0644);
-MODULE_PARM_DESC(ir_inversion, "Inversion of infrared signal: 0 not inverted (default), 1 inverted");
-
-static uint ir_device_mask[AV_CNT] = { IR_ALL, IR_ALL, IR_ALL, IR_ALL };
-module_param_array(ir_device_mask, uint, NULL, 0644);
-MODULE_PARM_DESC(ir_device_mask, "Bitmask of infrared devices: bit 0..31 = device 0..31 (default: all)");
-
-
-static int av_cnt;
-static struct av7110 *av_list[AV_CNT];
-
-static u16 default_key_map [256] = {
- KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7,
- KEY_8, KEY_9, KEY_BACK, 0, KEY_POWER, KEY_MUTE, 0, KEY_INFO,
- KEY_VOLUMEUP, KEY_VOLUMEDOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- KEY_CHANNELUP, KEY_CHANNELDOWN, 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, 0, KEY_TEXT, 0, 0, KEY_TV, 0, 0, 0, 0, 0, KEY_SETUP, 0, 0,
- 0, 0, 0, KEY_SUBTITLE, 0, 0, KEY_LANGUAGE, 0,
- KEY_RADIO, 0, 0, 0, 0, KEY_EXIT, 0, 0,
- KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_OK, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_RED, KEY_GREEN, KEY_YELLOW,
- KEY_BLUE, 0, 0, 0, 0, 0, 0, 0, KEY_MENU, KEY_LIST, 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, 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, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, KEY_UP, KEY_UP, KEY_DOWN, KEY_DOWN,
- 0, 0, 0, 0, KEY_EPG, 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, 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, KEY_VCR
-};
-
-
-/* key-up timer */
-static void av7110_emit_keyup(struct timer_list *t)
-{
- struct infrared *ir = from_timer(ir, t, keyup_timer);
-
- if (!ir || !ir->keypressed)
- return;
-
- input_report_key(ir->input_dev, ir->last_key, 0);
- input_sync(ir->input_dev);
- ir->keypressed = false;
-}
-
-
-/* tasklet */
-static void av7110_emit_key(unsigned long parm)
+/* interrupt handler */
+void av7110_ir_handler(struct av7110 *av7110, u32 ircom)
{
- struct infrared *ir = (struct infrared *) parm;
- u32 ircom = ir->ir_command;
- u8 data;
- u8 addr;
- u16 toggle;
- u16 keycode;
-
- /* extract device address and data */
- switch (ir->protocol) {
- case IR_RC5: /* RC5: 5 bits device address, 6 bits data */
- data = ircom & 0x3f;
- addr = (ircom >> 6) & 0x1f;
- toggle = ircom & 0x0800;
- break;
+ struct rc_dev *rcdev = av7110->ir.rcdev;
+ enum rc_proto proto;
+ u32 command, addr, scancode;
+ u32 toggle;
- case IR_RCMM: /* RCMM: ? bits device address, ? bits data */
- data = ircom & 0xff;
- addr = (ircom >> 8) & 0x1f;
- toggle = ircom & 0x8000;
- break;
-
- case IR_RC5_EXT: /* extended RC5: 5 bits device address, 7 bits data */
- data = ircom & 0x3f;
- addr = (ircom >> 6) & 0x1f;
- /* invert 7th data bit for backward compatibility with RC5 keymaps */
- if (!(ircom & 0x1000))
- data |= 0x40;
- toggle = ircom & 0x0800;
- break;
-
- default:
- printk("%s invalid protocol %x\n", __func__, ir->protocol);
- return;
- }
-
- input_event(ir->input_dev, EV_MSC, MSC_RAW, (addr << 16) | data);
- input_event(ir->input_dev, EV_MSC, MSC_SCAN, data);
-
- keycode = ir->key_map[data];
-
- dprintk(16, "%s: code %08x -> addr %i data 0x%02x -> keycode %i\n",
- __func__, ircom, addr, data, keycode);
-
- /* check device address */
- if (!(ir->device_mask & (1 << addr)))
- return;
-
- if (!keycode) {
- printk ("%s: code %08x -> addr %i data 0x%02x -> unknown key!\n",
- __func__, ircom, addr, data);
- return;
- }
-
- if (ir->keypressed &&
- (ir->last_key != keycode || toggle != ir->last_toggle))
- input_event(ir->input_dev, EV_KEY, ir->last_key, 0);
-
- input_event(ir->input_dev, EV_KEY, keycode, 1);
- input_sync(ir->input_dev);
-
- ir->keypressed = true;
- ir->last_key = keycode;
- ir->last_toggle = toggle;
-
- mod_timer(&ir->keyup_timer, jiffies + UP_TIMEOUT);
-}
-
-
-/* register with input layer */
-static void input_register_keys(struct infrared *ir)
-{
- int i;
+ dprintk(4, "ir command = %08x\n", ircom);
- set_bit(EV_KEY, ir->input_dev->evbit);
- set_bit(EV_REP, ir->input_dev->evbit);
- set_bit(EV_MSC, ir->input_dev->evbit);
+ if (rcdev) {
+ switch (av7110->ir.ir_config) {
+ case IR_RC5: /* RC5: 5 bits device address, 6 bits command */
+ command = ircom & 0x3f;
+ addr = (ircom >> 6) & 0x1f;
+ scancode = RC_SCANCODE_RC5(addr, command);
+ toggle = ircom & 0x0800;
+ proto = RC_PROTO_RC5;
+ break;
- set_bit(MSC_RAW, ir->input_dev->mscbit);
- set_bit(MSC_SCAN, ir->input_dev->mscbit);
+ case IR_RCMM: /* RCMM: ? bits device address, ? bits command */
+ command = ircom & 0xff;
+ addr = (ircom >> 8) & 0x1f;
+ scancode = ircom;
+ toggle = ircom & 0x8000;
+ proto = RC_PROTO_UNKNOWN;
+ break;
- memset(ir->input_dev->keybit, 0, sizeof(ir->input_dev->keybit));
+ case IR_RC5_EXT:
+ /*
+ * extended RC5: 5 bits device address, 7 bits command
+ *
+ * Extended RC5 uses only one start bit. The second
+ * start bit is re-assigned bit 6 of the command bit.
+ */
+ command = ircom & 0x3f;
+ addr = (ircom >> 6) & 0x1f;
+ if (!(ircom & 0x1000))
+ command |= 0x40;
+ scancode = RC_SCANCODE_RC5(addr, command);
+ toggle = ircom & 0x0800;
+ proto = RC_PROTO_RC5;
+ break;
+ default:
+ dprintk(2, "unknown ir config %d\n",
+ av7110->ir.ir_config);
+ return;
+ }
- for (i = 0; i < ARRAY_SIZE(ir->key_map); i++) {
- if (ir->key_map[i] > KEY_MAX)
- ir->key_map[i] = 0;
- else if (ir->key_map[i] > KEY_RESERVED)
- set_bit(ir->key_map[i], ir->input_dev->keybit);
+ rc_keydown(rcdev, proto, scancode, toggle != 0);
}
-
- ir->input_dev->keycode = ir->key_map;
- ir->input_dev->keycodesize = sizeof(ir->key_map[0]);
- ir->input_dev->keycodemax = ARRAY_SIZE(ir->key_map);
}
-/* check for configuration changes */
-int av7110_check_ir_config(struct av7110 *av7110, int force)
+int av7110_set_ir_config(struct av7110 *av7110)
{
- int i;
- int modified = force;
- int ret = -ENODEV;
-
- for (i = 0; i < av_cnt; i++)
- if (av7110 == av_list[i])
- break;
-
- if (i < av_cnt && av7110) {
- if ((av7110->ir.protocol & 1) != ir_protocol[i] ||
- av7110->ir.inversion != ir_inversion[i])
- modified = true;
-
- if (modified) {
- /* protocol */
- if (ir_protocol[i]) {
- ir_protocol[i] = 1;
- av7110->ir.protocol = IR_RCMM;
- av7110->ir.ir_config = 0x0001;
- } else if (FW_VERSION(av7110->arm_app) >= 0x2620) {
- av7110->ir.protocol = IR_RC5_EXT;
- av7110->ir.ir_config = 0x0002;
- } else {
- av7110->ir.protocol = IR_RC5;
- av7110->ir.ir_config = 0x0000;
- }
- /* inversion */
- if (ir_inversion[i]) {
- ir_inversion[i] = 1;
- av7110->ir.ir_config |= 0x8000;
- }
- av7110->ir.inversion = ir_inversion[i];
- /* update ARM */
- ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1,
- av7110->ir.ir_config);
- } else
- ret = 0;
+ dprintk(4, "ir config = %08x\n", av7110->ir.ir_config);
- /* address */
- if (av7110->ir.device_mask != ir_device_mask[i])
- av7110->ir.device_mask = ir_device_mask[i];
- }
-
- return ret;
+ return av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1,
+ av7110->ir.ir_config);
}
-
-/* /proc/av7110_ir interface */
-static ssize_t av7110_ir_proc_write(struct file *file, const char __user *buffer,
- size_t count, loff_t *pos)
+static int change_protocol(struct rc_dev *rcdev, u64 *rc_type)
{
- char *page;
+ struct av7110 *av7110 = rcdev->priv;
u32 ir_config;
- int size = sizeof ir_config + sizeof av_list[0]->ir.key_map;
- int i;
- if (count < size)
+ if (*rc_type & RC_PROTO_BIT_UNKNOWN) {
+ ir_config = IR_RCMM;
+ *rc_type = RC_PROTO_UNKNOWN;
+ } else if (*rc_type & RC_PROTO_BIT_RC5) {
+ if (FW_VERSION(av7110->arm_app) >= 0x2620)
+ ir_config = IR_RC5_EXT;
+ else
+ ir_config = IR_RC5;
+ *rc_type = RC_PROTO_BIT_RC5;
+ } else {
return -EINVAL;
-
- page = vmalloc(size);
- if (!page)
- return -ENOMEM;
-
- if (copy_from_user(page, buffer, size)) {
- vfree(page);
- return -EFAULT;
}
- memcpy(&ir_config, page, sizeof ir_config);
-
- for (i = 0; i < av_cnt; i++) {
- /* keymap */
- memcpy(av_list[i]->ir.key_map, page + sizeof ir_config,
- sizeof(av_list[i]->ir.key_map));
- /* protocol, inversion, address */
- ir_protocol[i] = ir_config & 0x0001;
- ir_inversion[i] = ir_config & 0x8000 ? 1 : 0;
- if (ir_config & 0x4000)
- ir_device_mask[i] = 1 << ((ir_config >> 16) & 0x1f);
- else
- ir_device_mask[i] = IR_ALL;
- /* update configuration */
- av7110_check_ir_config(av_list[i], false);
- input_register_keys(&av_list[i]->ir);
- }
- vfree(page);
- return count;
-}
+ if (ir_config == av7110->ir.ir_config)
+ return 0;
-static const struct file_operations av7110_ir_proc_fops = {
- .owner = THIS_MODULE,
- .write = av7110_ir_proc_write,
- .llseek = noop_llseek,
-};
+ av7110->ir.ir_config = ir_config;
-/* interrupt handler */
-static void ir_handler(struct av7110 *av7110, u32 ircom)
-{
- dprintk(4, "ir command = %08x\n", ircom);
- av7110->ir.ir_command = ircom;
- tasklet_schedule(&av7110->ir.ir_tasklet);
+ return av7110_set_ir_config(av7110);
}
-
int av7110_ir_init(struct av7110 *av7110)
{
- struct input_dev *input_dev;
- static struct proc_dir_entry *e;
- int err;
-
- if (av_cnt >= ARRAY_SIZE(av_list))
- return -ENOSPC;
+ struct rc_dev *rcdev;
+ struct pci_dev *pci;
+ int ret;
- av_list[av_cnt++] = av7110;
- av7110_check_ir_config(av7110, true);
-
- timer_setup(&av7110->ir.keyup_timer, av7110_emit_keyup, 0);
-
- input_dev = input_allocate_device();
- if (!input_dev)
+ rcdev = rc_allocate_device(RC_DRIVER_SCANCODE);
+ if (!rcdev)
return -ENOMEM;
- av7110->ir.input_dev = input_dev;
- snprintf(av7110->ir.input_phys, sizeof(av7110->ir.input_phys),
- "pci-%s/ir0", pci_name(av7110->dev->pci));
+ pci = av7110->dev->pci;
- input_dev->name = "DVB on-card IR receiver";
-
- input_dev->phys = av7110->ir.input_phys;
- input_dev->id.bustype = BUS_PCI;
- input_dev->id.version = 2;
- if (av7110->dev->pci->subsystem_vendor) {
- input_dev->id.vendor = av7110->dev->pci->subsystem_vendor;
- input_dev->id.product = av7110->dev->pci->subsystem_device;
+ snprintf(av7110->ir.input_phys, sizeof(av7110->ir.input_phys),
+ "pci-%s/ir0", pci_name(pci));
+
+ rcdev->device_name = av7110->card_name;
+ rcdev->driver_name = KBUILD_MODNAME;
+ rcdev->input_phys = av7110->ir.input_phys;
+ rcdev->input_id.bustype = BUS_PCI;
+ rcdev->input_id.version = 2;
+ if (pci->subsystem_vendor) {
+ rcdev->input_id.vendor = pci->subsystem_vendor;
+ rcdev->input_id.product = pci->subsystem_device;
} else {
- input_dev->id.vendor = av7110->dev->pci->vendor;
- input_dev->id.product = av7110->dev->pci->device;
- }
- input_dev->dev.parent = &av7110->dev->pci->dev;
- /* initial keymap */
- memcpy(av7110->ir.key_map, default_key_map, sizeof av7110->ir.key_map);
- input_register_keys(&av7110->ir);
- err = input_register_device(input_dev);
- if (err) {
- input_free_device(input_dev);
- return err;
+ rcdev->input_id.vendor = pci->vendor;
+ rcdev->input_id.product = pci->device;
}
- /*
- * Input core's default autorepeat is 33 cps with 250 msec
- * delay, let's adjust to numbers more suitable for remote
- * control.
- */
- input_enable_softrepeat(input_dev, 250, 125);
+ rcdev->dev.parent = &pci->dev;
+ rcdev->allowed_protocols = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_UNKNOWN;
+ rcdev->change_protocol = change_protocol;
+ rcdev->map_name = RC_MAP_HAUPPAUGE;
+ rcdev->priv = av7110;
- if (av_cnt == 1) {
- e = proc_create("av7110_ir", S_IWUSR, NULL, &av7110_ir_proc_fops);
- if (e)
- proc_set_size(e, 4 + 256 * sizeof(u16));
- }
+ av7110->ir.rcdev = rcdev;
+ av7110->ir.ir_config = IR_RC5;
+ av7110_set_ir_config(av7110);
- tasklet_init(&av7110->ir.ir_tasklet, av7110_emit_key, (unsigned long) &av7110->ir);
- av7110->ir.ir_handler = ir_handler;
+ ret = rc_register_device(rcdev);
+ if (ret) {
+ av7110->ir.rcdev = NULL;
+ rc_free_device(rcdev);
+ }
- return 0;
+ return ret;
}
-
void av7110_ir_exit(struct av7110 *av7110)
{
- int i;
-
- if (av_cnt == 0)
- return;
-
- del_timer_sync(&av7110->ir.keyup_timer);
- av7110->ir.ir_handler = NULL;
- tasklet_kill(&av7110->ir.ir_tasklet);
-
- for (i = 0; i < av_cnt; i++)
- if (av_list[i] == av7110) {
- av_list[i] = av_list[av_cnt-1];
- av_list[av_cnt-1] = NULL;
- break;
- }
-
- if (av_cnt == 1)
- remove_proc_entry("av7110_ir", NULL);
-
- input_unregister_device(av7110->ir.input_dev);
-
- av_cnt--;
+ rc_unregister_device(av7110->ir.rcdev);
}
//MODULE_AUTHOR("Holger Waechtler <holger@convergence.de>, Oliver Endriss <o.endriss@gmx.de>");
diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c
index 5b469cf578f5..8e0952d65ad4 100644
--- a/drivers/media/pci/tw68/tw68-video.c
+++ b/drivers/media/pci/tw68/tw68-video.c
@@ -729,12 +729,6 @@ static int tw68_querycap(struct file *file, void *priv,
strscpy(cap->card, "Techwell Capture Card",
sizeof(cap->card));
sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
- cap->device_caps =
- V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
-
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -913,6 +907,8 @@ static const struct video_device tw68_video_template = {
.ioctl_ops = &video_ioctl_ops,
.release = video_device_release_empty,
.tvnorms = TW68_NORMS,
+ .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING,
};
/* ------------------------------------------------------------------ */
diff --git a/drivers/media/pci/tw686x/tw686x-video.c b/drivers/media/pci/tw686x/tw686x-video.c
index 377fb1e453fa..9be8c6e4fb69 100644
--- a/drivers/media/pci/tw686x/tw686x-video.c
+++ b/drivers/media/pci/tw686x/tw686x-video.c
@@ -765,9 +765,6 @@ static int tw686x_querycap(struct file *file, void *priv,
strscpy(cap->card, dev->name, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info),
"PCI:%s", pci_name(dev->pci_dev));
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
- V4L2_CAP_READWRITE;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -1280,6 +1277,8 @@ int tw686x_video_init(struct tw686x_dev *dev)
vdev->minor = -1;
vdev->lock = &vc->vb_mutex;
vdev->ctrl_handler = &vc->ctrl_handler;
+ vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
vc->device = vdev;
video_set_drvdata(vdev, vc);
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index f2b5f27ebacb..8a19654b393a 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -6,7 +6,6 @@
menuconfig V4L_PLATFORM_DRIVERS
bool "V4L platform devices"
depends on MEDIA_CAMERA_SUPPORT
- default n
help
Say Y here to enable support for platform-specific V4L drivers.
@@ -155,7 +154,6 @@ config VIDEO_TI_CAL
depends on SOC_DRA7XX || COMPILE_TEST
select VIDEOBUF2_DMA_CONTIG
select V4L2_FWNODE
- default n
help
Support for the TI CAL (Camera Adaptation Layer) block
found on DRA72X SoC.
@@ -168,7 +166,6 @@ menuconfig V4L_MEM2MEM_DRIVERS
bool "Memory-to-memory multimedia devices"
depends on VIDEO_V4L2
depends on MEDIA_CAMERA_SUPPORT
- default n
help
Say Y here to enable selecting drivers for V4L devices that
use system memory for both source and destination buffers, as opposed
@@ -236,7 +233,6 @@ config VIDEO_MEDIATEK_MDP
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
select VIDEO_MEDIATEK_VPU
- default n
help
It is a v4l2 driver and present in Mediatek MT8173 SoCs.
The driver supports for scaling and color space conversion.
@@ -252,7 +248,6 @@ config VIDEO_MEDIATEK_VCODEC
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
select VIDEO_MEDIATEK_VPU
- default n
help
Mediatek video codec driver provides HW capability to
encode and decode in a range of video formats
@@ -276,7 +271,6 @@ config VIDEO_SAMSUNG_S5P_G2D
depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
- default n
help
This is a v4l2 driver for Samsung S5P and EXYNOS4 G2D
2d graphics accelerator.
@@ -296,7 +290,6 @@ config VIDEO_SAMSUNG_S5P_MFC
depends on VIDEO_DEV && VIDEO_V4L2
depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
select VIDEOBUF2_DMA_CONTIG
- default n
help
MFC 5.1 and 6.x driver for V4L2
@@ -459,7 +452,6 @@ config VIDEO_ROCKCHIP_RGA
depends on ARCH_ROCKCHIP || COMPILE_TEST
select VIDEOBUF2_DMA_SG
select V4L2_MEM2MEM_DEV
- default n
help
This is a v4l2 driver for Rockchip SOC RGA 2d graphics accelerator.
Rockchip RGA is a separate 2D raster graphic acceleration unit.
@@ -477,7 +469,6 @@ config VIDEO_TI_VPE
select VIDEO_TI_VPDMA
select VIDEO_TI_SC
select VIDEO_TI_CSC
- default n
help
Support for the TI VPE(Video Processing Engine) block
found on DRA7XX SoC.
@@ -530,7 +521,6 @@ config VIDEO_VIM2M
depends on VIDEO_DEV && VIDEO_V4L2
select VIDEOBUF2_VMALLOC
select V4L2_MEM2MEM_DEV
- default n
help
This is a virtual test device for the memory-to-memory driver
framework.
@@ -542,7 +532,6 @@ endif #V4L_TEST_DRIVERS
menuconfig DVB_PLATFORM_DRIVERS
bool "DVB platform devices"
depends on MEDIA_DIGITAL_TV_SUPPORT
- default n
help
Say Y here to enable support for platform-specific Digital TV drivers.
@@ -678,7 +667,6 @@ endif #CEC_PLATFORM_DRIVERS
menuconfig SDR_PLATFORM_DRIVERS
bool "SDR platform devices"
depends on MEDIA_SDR_SUPPORT
- default n
help
Say Y here to enable support for platform-specific SDR Drivers.
diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c
index 8144fe36ad48..f899ac3b4a61 100644
--- a/drivers/media/platform/aspeed-video.c
+++ b/drivers/media/platform/aspeed-video.c
@@ -187,6 +187,7 @@ enum {
VIDEO_STREAMING,
VIDEO_FRAME_INPRG,
VIDEO_STOPPED,
+ VIDEO_CLOCKS_ON,
};
struct aspeed_video_addr {
@@ -440,7 +441,7 @@ static int aspeed_video_start_frame(struct aspeed_video *video)
if (!(seq_ctrl & VE_SEQ_CTRL_COMP_BUSY) ||
!(seq_ctrl & VE_SEQ_CTRL_CAP_BUSY)) {
- dev_err(video->dev, "Engine busy; don't start frame\n");
+ dev_dbg(video->dev, "Engine busy; don't start frame\n");
return -EBUSY;
}
@@ -462,8 +463,7 @@ static int aspeed_video_start_frame(struct aspeed_video *video)
aspeed_video_write(video, VE_COMP_ADDR, addr);
aspeed_video_update(video, VE_INTERRUPT_CTRL, 0,
- VE_INTERRUPT_COMP_COMPLETE |
- VE_INTERRUPT_CAPTURE_COMPLETE);
+ VE_INTERRUPT_COMP_COMPLETE);
aspeed_video_update(video, VE_SEQ_CTRL, 0,
VE_SEQ_CTRL_TRIG_CAPTURE | VE_SEQ_CTRL_TRIG_COMP);
@@ -483,19 +483,30 @@ static void aspeed_video_enable_mode_detect(struct aspeed_video *video)
static void aspeed_video_off(struct aspeed_video *video)
{
+ if (!test_bit(VIDEO_CLOCKS_ON, &video->flags))
+ return;
+
/* Disable interrupts */
aspeed_video_write(video, VE_INTERRUPT_CTRL, 0);
+ aspeed_video_write(video, VE_INTERRUPT_STATUS, 0xffffffff);
/* Turn off the relevant clocks */
- clk_disable_unprepare(video->vclk);
- clk_disable_unprepare(video->eclk);
+ clk_disable(video->vclk);
+ clk_disable(video->eclk);
+
+ clear_bit(VIDEO_CLOCKS_ON, &video->flags);
}
static void aspeed_video_on(struct aspeed_video *video)
{
+ if (test_bit(VIDEO_CLOCKS_ON, &video->flags))
+ return;
+
/* Turn on the relevant clocks */
- clk_prepare_enable(video->eclk);
- clk_prepare_enable(video->vclk);
+ clk_enable(video->eclk);
+ clk_enable(video->vclk);
+
+ set_bit(VIDEO_CLOCKS_ON, &video->flags);
}
static void aspeed_video_bufs_done(struct aspeed_video *video,
@@ -511,7 +522,7 @@ static void aspeed_video_bufs_done(struct aspeed_video *video,
spin_unlock_irqrestore(&video->lock, flags);
}
-static void aspeed_video_irq_res_change(struct aspeed_video *video)
+static void aspeed_video_irq_res_change(struct aspeed_video *video, ulong delay)
{
dev_dbg(video->dev, "Resolution changed; resetting\n");
@@ -521,7 +532,7 @@ static void aspeed_video_irq_res_change(struct aspeed_video *video)
aspeed_video_off(video);
aspeed_video_bufs_done(video, VB2_BUF_STATE_ERROR);
- schedule_delayed_work(&video->res_work, RESOLUTION_CHANGE_DELAY);
+ schedule_delayed_work(&video->res_work, delay);
}
static irqreturn_t aspeed_video_irq(int irq, void *arg)
@@ -534,7 +545,7 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg)
* re-initialize
*/
if (sts & VE_INTERRUPT_MODE_DETECT_WD) {
- aspeed_video_irq_res_change(video);
+ aspeed_video_irq_res_change(video, 0);
return IRQ_HANDLED;
}
@@ -544,7 +555,7 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg)
VE_INTERRUPT_MODE_DETECT, 0);
aspeed_video_write(video, VE_INTERRUPT_STATUS,
VE_INTERRUPT_MODE_DETECT);
-
+ sts &= ~VE_INTERRUPT_MODE_DETECT;
set_bit(VIDEO_MODE_DETECT_DONE, &video->flags);
wake_up_interruptible_all(&video->wait);
} else {
@@ -552,13 +563,13 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg)
* Signal acquired while NOT doing resolution
* detection; reset the engine and re-initialize
*/
- aspeed_video_irq_res_change(video);
+ aspeed_video_irq_res_change(video,
+ RESOLUTION_CHANGE_DELAY);
return IRQ_HANDLED;
}
}
- if ((sts & VE_INTERRUPT_COMP_COMPLETE) &&
- (sts & VE_INTERRUPT_CAPTURE_COMPLETE)) {
+ if (sts & VE_INTERRUPT_COMP_COMPLETE) {
struct aspeed_video_buffer *buf;
u32 frame_size = aspeed_video_read(video,
VE_OFFSET_COMP_STREAM);
@@ -587,17 +598,15 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg)
VE_SEQ_CTRL_FORCE_IDLE |
VE_SEQ_CTRL_TRIG_COMP, 0);
aspeed_video_update(video, VE_INTERRUPT_CTRL,
- VE_INTERRUPT_COMP_COMPLETE |
- VE_INTERRUPT_CAPTURE_COMPLETE, 0);
+ VE_INTERRUPT_COMP_COMPLETE, 0);
aspeed_video_write(video, VE_INTERRUPT_STATUS,
- VE_INTERRUPT_COMP_COMPLETE |
- VE_INTERRUPT_CAPTURE_COMPLETE);
-
+ VE_INTERRUPT_COMP_COMPLETE);
+ sts &= ~VE_INTERRUPT_COMP_COMPLETE;
if (test_bit(VIDEO_STREAMING, &video->flags) && buf)
aspeed_video_start_frame(video);
}
- return IRQ_HANDLED;
+ return sts ? IRQ_NONE : IRQ_HANDLED;
}
static void aspeed_video_check_and_set_polarity(struct aspeed_video *video)
@@ -723,27 +732,6 @@ static void aspeed_video_get_resolution(struct aspeed_video *video)
det->height = MIN_HEIGHT;
video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL;
- /*
- * Since we need max buffer size for detection, free the second source
- * buffer first.
- */
- if (video->srcs[1].size)
- aspeed_video_free_buf(video, &video->srcs[1]);
-
- if (video->srcs[0].size < VE_MAX_SRC_BUFFER_SIZE) {
- if (video->srcs[0].size)
- aspeed_video_free_buf(video, &video->srcs[0]);
-
- if (!aspeed_video_alloc_buf(video, &video->srcs[0],
- VE_MAX_SRC_BUFFER_SIZE)) {
- dev_err(video->dev,
- "Failed to allocate source buffers\n");
- return;
- }
- }
-
- aspeed_video_write(video, VE_SRC0_ADDR, video->srcs[0].dma);
-
do {
if (tries) {
set_current_state(TASK_INTERRUPTIBLE);
@@ -758,7 +746,7 @@ static void aspeed_video_get_resolution(struct aspeed_video *video)
res_check(video),
MODE_DETECT_TIMEOUT);
if (!rc) {
- dev_err(video->dev, "Timed out; first mode detect\n");
+ dev_dbg(video->dev, "Timed out; first mode detect\n");
clear_bit(VIDEO_RES_DETECT, &video->flags);
return;
}
@@ -776,7 +764,7 @@ static void aspeed_video_get_resolution(struct aspeed_video *video)
MODE_DETECT_TIMEOUT);
clear_bit(VIDEO_RES_DETECT, &video->flags);
if (!rc) {
- dev_err(video->dev, "Timed out; second mode detect\n");
+ dev_dbg(video->dev, "Timed out; second mode detect\n");
return;
}
@@ -810,7 +798,7 @@ static void aspeed_video_get_resolution(struct aspeed_video *video)
} while (invalid_resolution && (tries++ < INVALID_RESOLUTION_RETRIES));
if (invalid_resolution) {
- dev_err(video->dev, "Invalid resolution detected\n");
+ dev_dbg(video->dev, "Invalid resolution detected\n");
return;
}
@@ -836,8 +824,29 @@ static void aspeed_video_set_resolution(struct aspeed_video *video)
struct v4l2_bt_timings *act = &video->active_timings;
unsigned int size = act->width * act->height;
+ /* Set capture/compression frame sizes */
aspeed_video_calc_compressed_size(video, size);
+ if (video->active_timings.width == 1680) {
+ /*
+ * This is a workaround to fix a silicon bug on A1 and A2
+ * revisions. Since it doesn't break capturing operation of
+ * other revisions, use it for all revisions without checking
+ * the revision ID. It picked 1728 which is a very next
+ * 64-pixels aligned value to 1680 to minimize memory bandwidth
+ * and to get better access speed from video engine.
+ */
+ aspeed_video_write(video, VE_CAP_WINDOW,
+ 1728 << 16 | act->height);
+ size += (1728 - 1680) * video->active_timings.height;
+ } else {
+ aspeed_video_write(video, VE_CAP_WINDOW,
+ act->width << 16 | act->height);
+ }
+ aspeed_video_write(video, VE_COMP_WINDOW,
+ act->width << 16 | act->height);
+ aspeed_video_write(video, VE_SRC_SCANLINE_OFFSET, act->width * 4);
+
/* Don't use direct mode below 1024 x 768 (irqs don't fire) */
if (size < DIRECT_FETCH_THRESHOLD) {
aspeed_video_write(video, VE_TGS_0,
@@ -854,29 +863,16 @@ static void aspeed_video_set_resolution(struct aspeed_video *video)
aspeed_video_update(video, VE_CTRL, 0, VE_CTRL_DIRECT_FETCH);
}
- /* Set capture/compression frame sizes */
- aspeed_video_write(video, VE_CAP_WINDOW,
- act->width << 16 | act->height);
- aspeed_video_write(video, VE_COMP_WINDOW,
- act->width << 16 | act->height);
- aspeed_video_write(video, VE_SRC_SCANLINE_OFFSET, act->width * 4);
-
size *= 4;
- if (size == video->srcs[0].size / 2) {
- aspeed_video_write(video, VE_SRC1_ADDR,
- video->srcs[0].dma + size);
- } else if (size == video->srcs[0].size) {
- if (!aspeed_video_alloc_buf(video, &video->srcs[1], size))
- goto err_mem;
-
- aspeed_video_write(video, VE_SRC1_ADDR, video->srcs[1].dma);
- } else {
- aspeed_video_free_buf(video, &video->srcs[0]);
+ if (size != video->srcs[0].size) {
+ if (video->srcs[0].size)
+ aspeed_video_free_buf(video, &video->srcs[0]);
+ if (video->srcs[1].size)
+ aspeed_video_free_buf(video, &video->srcs[1]);
if (!aspeed_video_alloc_buf(video, &video->srcs[0], size))
goto err_mem;
-
if (!aspeed_video_alloc_buf(video, &video->srcs[1], size))
goto err_mem;
@@ -1445,7 +1441,7 @@ static void aspeed_video_stop_streaming(struct vb2_queue *q)
!test_bit(VIDEO_FRAME_INPRG, &video->flags),
STOP_TIMEOUT);
if (!rc) {
- dev_err(video->dev, "Timed out when stopping streaming\n");
+ dev_dbg(video->dev, "Timed out when stopping streaming\n");
/*
* Need to force stop any DMA and try and get HW into a good
@@ -1589,8 +1585,8 @@ static int aspeed_video_init(struct aspeed_video *video)
return -ENODEV;
}
- rc = devm_request_irq(dev, irq, aspeed_video_irq, IRQF_SHARED,
- DEVICE_NAME, video);
+ rc = devm_request_threaded_irq(dev, irq, NULL, aspeed_video_irq,
+ IRQF_ONESHOT, DEVICE_NAME, video);
if (rc < 0) {
dev_err(dev, "Unable to request IRQ %d\n", irq);
return rc;
@@ -1602,31 +1598,46 @@ static int aspeed_video_init(struct aspeed_video *video)
return PTR_ERR(video->eclk);
}
+ rc = clk_prepare(video->eclk);
+ if (rc)
+ return rc;
+
video->vclk = devm_clk_get(dev, "vclk");
if (IS_ERR(video->vclk)) {
dev_err(dev, "Unable to get VCLK\n");
- return PTR_ERR(video->vclk);
+ rc = PTR_ERR(video->vclk);
+ goto err_unprepare_eclk;
}
+ rc = clk_prepare(video->vclk);
+ if (rc)
+ goto err_unprepare_eclk;
+
of_reserved_mem_device_init(dev);
rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
if (rc) {
dev_err(dev, "Failed to set DMA mask\n");
- of_reserved_mem_device_release(dev);
- return rc;
+ goto err_release_reserved_mem;
}
if (!aspeed_video_alloc_buf(video, &video->jpeg,
VE_JPEG_HEADER_SIZE)) {
dev_err(dev, "Failed to allocate DMA for JPEG header\n");
- of_reserved_mem_device_release(dev);
- return rc;
+ goto err_release_reserved_mem;
}
aspeed_video_init_jpeg_table(video->jpeg.virt, video->yuv420);
return 0;
+
+err_release_reserved_mem:
+ of_reserved_mem_device_release(dev);
+ clk_unprepare(video->vclk);
+err_unprepare_eclk:
+ clk_unprepare(video->eclk);
+
+ return rc;
}
static int aspeed_video_probe(struct platform_device *pdev)
@@ -1670,6 +1681,11 @@ static int aspeed_video_remove(struct platform_device *pdev)
struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
struct aspeed_video *video = to_aspeed_video(v4l2_dev);
+ aspeed_video_off(video);
+
+ clk_unprepare(video->vclk);
+ clk_unprepare(video->eclk);
+
video_unregister_device(&video->vdev);
vb2_queue_release(&video->queue);
diff --git a/drivers/media/platform/atmel/Makefile b/drivers/media/platform/atmel/Makefile
index 484936604ccb..2dba38994a70 100644
--- a/drivers/media/platform/atmel/Makefile
+++ b/drivers/media/platform/atmel/Makefile
@@ -1,3 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_VIDEO_ATMEL_ISC) += atmel-isc.o
+atmel-isc-objs = atmel-sama5d2-isc.o atmel-isc-base.o
+
obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o
+obj-$(CONFIG_VIDEO_ATMEL_ISC) += atmel-isc.o
diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc-base.c
index 05b9cfb91d20..c1c776b348a9 100644
--- a/drivers/media/platform/atmel/atmel-isc.c
+++ b/drivers/media/platform/atmel/atmel-isc-base.c
@@ -1,24 +1,12 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Atmel Image Sensor Controller (ISC) driver
+ * Microchip Image Sensor Controller (ISC) common driver base
*
- * Copyright (C) 2016 Atmel
+ * Copyright (C) 2016-2019 Microchip Technology, Inc.
*
- * Author: Songjun Wu <songjun.wu@microchip.com>
+ * Author: Songjun Wu
+ * Author: Eugen Hristev <eugen.hristev@microchip.com>
*
- * Sensor-->PFE-->WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB-->RLP-->DMA
- *
- * ISC video pipeline integrates the following submodules:
- * PFE: Parallel Front End to sample the camera sensor input stream
- * WB: Programmable white balance in the Bayer domain
- * CFA: Color filter array interpolation module
- * CC: Programmable color correction
- * GAM: Gamma correction
- * CSC: Programmable color space conversion
- * CBC: Contrast and Brightness control
- * SUB: This module performs YCbCr444 to YCbCr420 chrominance subsampling
- * RLP: This module performs rounding, range limiting
- * and packing of the incoming data
*/
#include <linux/clk.h>
@@ -45,176 +33,19 @@
#include <media/videobuf2-dma-contig.h>
#include "atmel-isc-regs.h"
+#include "atmel-isc.h"
-#define ATMEL_ISC_NAME "atmel_isc"
-
-#define ISC_MAX_SUPPORT_WIDTH 2592
-#define ISC_MAX_SUPPORT_HEIGHT 1944
-
-#define ISC_CLK_MAX_DIV 255
-
-enum isc_clk_id {
- ISC_ISPCK = 0,
- ISC_MCK = 1,
-};
-
-struct isc_clk {
- struct clk_hw hw;
- struct clk *clk;
- struct regmap *regmap;
- spinlock_t lock;
- u8 id;
- u8 parent_id;
- u32 div;
- struct device *dev;
-};
-
-#define to_isc_clk(hw) container_of(hw, struct isc_clk, hw)
-
-struct isc_buffer {
- struct vb2_v4l2_buffer vb;
- struct list_head list;
-};
-
-struct isc_subdev_entity {
- struct v4l2_subdev *sd;
- struct v4l2_async_subdev *asd;
- struct v4l2_async_notifier notifier;
-
- u32 pfe_cfg0;
-
- struct list_head list;
-};
-
-/*
- * struct isc_format - ISC media bus format information
- This structure represents the interface between the ISC
- and the sensor. It's the input format received by
- the ISC.
- * @fourcc: Fourcc code for this format
- * @mbus_code: V4L2 media bus format code.
- * @cfa_baycfg: If this format is RAW BAYER, indicate the type of bayer.
- this is either BGBG, RGRG, etc.
- * @pfe_cfg0_bps: Number of hardware data lines connected to the ISC
- */
-
-struct isc_format {
- u32 fourcc;
- u32 mbus_code;
- u32 cfa_baycfg;
-
- bool sd_support;
- u32 pfe_cfg0_bps;
-};
-
-/* Pipeline bitmap */
-#define WB_ENABLE BIT(0)
-#define CFA_ENABLE BIT(1)
-#define CC_ENABLE BIT(2)
-#define GAM_ENABLE BIT(3)
-#define GAM_BENABLE BIT(4)
-#define GAM_GENABLE BIT(5)
-#define GAM_RENABLE BIT(6)
-#define CSC_ENABLE BIT(7)
-#define CBC_ENABLE BIT(8)
-#define SUB422_ENABLE BIT(9)
-#define SUB420_ENABLE BIT(10)
-
-#define GAM_ENABLES (GAM_RENABLE | GAM_GENABLE | GAM_BENABLE | GAM_ENABLE)
-
-/*
- * struct fmt_config - ISC format configuration and internal pipeline
- This structure represents the internal configuration
- of the ISC.
- It also holds the format that ISC will present to v4l2.
- * @sd_format: Pointer to an isc_format struct that holds the sensor
- configuration.
- * @fourcc: Fourcc code for this format.
- * @bpp: Bytes per pixel in the current format.
- * @rlp_cfg_mode: Configuration of the RLP (rounding, limiting packaging)
- * @dcfg_imode: Configuration of the input of the DMA module
- * @dctrl_dview: Configuration of the output of the DMA module
- * @bits_pipeline: Configuration of the pipeline, which modules are enabled
- */
-struct fmt_config {
- struct isc_format *sd_format;
-
- u32 fourcc;
- u8 bpp;
-
- u32 rlp_cfg_mode;
- u32 dcfg_imode;
- u32 dctrl_dview;
-
- u32 bits_pipeline;
-};
-
-#define HIST_ENTRIES 512
-#define HIST_BAYER (ISC_HIS_CFG_MODE_B + 1)
-
-enum{
- HIST_INIT = 0,
- HIST_ENABLED,
- HIST_DISABLED,
-};
-
-struct isc_ctrls {
- struct v4l2_ctrl_handler handler;
-
- u32 brightness;
- u32 contrast;
- u8 gamma_index;
- u8 awb;
-
- u32 r_gain;
- u32 b_gain;
-
- u32 hist_entry[HIST_ENTRIES];
- u32 hist_count[HIST_BAYER];
- u8 hist_id;
- u8 hist_stat;
-};
-
-#define ISC_PIPE_LINE_NODE_NUM 11
-
-struct isc_device {
- struct regmap *regmap;
- struct clk *hclock;
- struct clk *ispck;
- struct isc_clk isc_clks[2];
-
- struct device *dev;
- struct v4l2_device v4l2_dev;
- struct video_device video_dev;
-
- struct vb2_queue vb2_vidq;
- spinlock_t dma_queue_lock;
- struct list_head dma_queue;
- struct isc_buffer *cur_frm;
- unsigned int sequence;
- bool stop;
- struct completion comp;
-
- struct v4l2_format fmt;
- struct isc_format **user_formats;
- unsigned int num_user_formats;
-
- struct fmt_config config;
- struct fmt_config try_config;
-
- struct isc_ctrls ctrls;
- struct work_struct awb_work;
-
- struct mutex lock;
-
- struct regmap_field *pipeline[ISC_PIPE_LINE_NODE_NUM];
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "debug level (0-2)");
- struct isc_subdev_entity *current_subdev;
- struct list_head subdev_entities;
-};
+static unsigned int sensor_preferred = 1;
+module_param(sensor_preferred, uint, 0644);
+MODULE_PARM_DESC(sensor_preferred,
+ "Sensor is preferred to output the specified format (1-on 0-off), default 1");
/* This is a list of the formats that the ISC can *output* */
-static struct isc_format controller_formats[] = {
+const struct isc_format controller_formats[] = {
{
.fourcc = V4L2_PIX_FMT_ARGB444,
},
@@ -245,7 +76,7 @@ static struct isc_format controller_formats[] = {
};
/* This is a list of formats that the ISC can receive as *input* */
-static struct isc_format formats_list[] = {
+struct isc_format formats_list[] = {
{
.fourcc = V4L2_PIX_FMT_SBGGR8,
.mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
@@ -335,11 +166,8 @@ static struct isc_format formats_list[] = {
},
};
-#define GAMMA_MAX 2
-#define GAMMA_ENTRIES 64
-
/* Gamma table with gamma 1/2.2 */
-static const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES] = {
+const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES] = {
/* 0 --> gamma 1/1.8 */
{ 0x65, 0x66002F, 0x950025, 0xBB0020, 0xDB001D, 0xF8001A,
0x1130018, 0x12B0017, 0x1420016, 0x1580014, 0x16D0013, 0x1810012,
@@ -383,14 +211,39 @@ static const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES] = {
#define ISC_IS_FORMAT_RAW(mbus_code) \
(((mbus_code) & 0xf000) == 0x3000)
-static unsigned int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "debug level (0-2)");
+static inline void isc_update_awb_ctrls(struct isc_device *isc)
+{
+ struct isc_ctrls *ctrls = &isc->ctrls;
-static unsigned int sensor_preferred = 1;
-module_param(sensor_preferred, uint, 0644);
-MODULE_PARM_DESC(sensor_preferred,
- "Sensor is preferred to output the specified format (1-on 0-off), default 1");
+ regmap_write(isc->regmap, ISC_WB_O_RGR,
+ (ISC_WB_O_ZERO_VAL - (ctrls->offset[ISC_HIS_CFG_MODE_R])) |
+ ((ISC_WB_O_ZERO_VAL - ctrls->offset[ISC_HIS_CFG_MODE_GR]) << 16));
+ regmap_write(isc->regmap, ISC_WB_O_BGB,
+ (ISC_WB_O_ZERO_VAL - (ctrls->offset[ISC_HIS_CFG_MODE_B])) |
+ ((ISC_WB_O_ZERO_VAL - ctrls->offset[ISC_HIS_CFG_MODE_GB]) << 16));
+ regmap_write(isc->regmap, ISC_WB_G_RGR,
+ ctrls->gain[ISC_HIS_CFG_MODE_R] |
+ (ctrls->gain[ISC_HIS_CFG_MODE_GR] << 16));
+ regmap_write(isc->regmap, ISC_WB_G_BGB,
+ ctrls->gain[ISC_HIS_CFG_MODE_B] |
+ (ctrls->gain[ISC_HIS_CFG_MODE_GB] << 16));
+}
+
+static inline void isc_reset_awb_ctrls(struct isc_device *isc)
+{
+ unsigned int c;
+
+ for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) {
+ /* gains have a fixed point at 9 decimals */
+ isc->ctrls.gain[c] = 1 << 9;
+ /* offsets are in 2's complements, the value
+ * will be substracted from ISC_WB_O_ZERO_VAL to obtain
+ * 2's complement of a value between 0 and
+ * ISC_WB_O_ZERO_VAL >> 1
+ */
+ isc->ctrls.offset[c] = ISC_WB_O_ZERO_VAL;
+ }
+}
static int isc_wait_clk_stable(struct clk_hw *hw)
{
@@ -646,7 +499,7 @@ static int isc_clk_register(struct isc_device *isc, unsigned int id)
return 0;
}
-static int isc_clk_init(struct isc_device *isc)
+int isc_clk_init(struct isc_device *isc)
{
unsigned int i;
int ret;
@@ -663,7 +516,7 @@ static int isc_clk_init(struct isc_device *isc)
return 0;
}
-static void isc_clk_cleanup(struct isc_device *isc)
+void isc_clk_cleanup(struct isc_device *isc)
{
unsigned int i;
@@ -772,7 +625,9 @@ static void isc_start_dma(struct isc_device *isc)
dctrl_dview = isc->config.dctrl_dview;
regmap_write(regmap, ISC_DCTRL, dctrl_dview | ISC_DCTRL_IE_IS);
+ spin_lock(&isc->awb_lock);
regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_CAPTURE);
+ spin_unlock(&isc->awb_lock);
}
static void isc_set_pipeline(struct isc_device *isc, u32 pipeline)
@@ -794,11 +649,11 @@ static void isc_set_pipeline(struct isc_device *isc, u32 pipeline)
bay_cfg = isc->config.sd_format->cfa_baycfg;
+ if (ctrls->awb == ISC_WB_NONE)
+ isc_reset_awb_ctrls(isc);
+
regmap_write(regmap, ISC_WB_CFG, bay_cfg);
- regmap_write(regmap, ISC_WB_O_RGR, 0x0);
- regmap_write(regmap, ISC_WB_O_BGR, 0x0);
- regmap_write(regmap, ISC_WB_G_RGR, ctrls->r_gain | (0x1 << 25));
- regmap_write(regmap, ISC_WB_G_BGR, ctrls->b_gain | (0x1 << 25));
+ isc_update_awb_ctrls(isc);
regmap_write(regmap, ISC_CFA_CFG, bay_cfg | ISC_CFA_CFG_EITPOL);
@@ -848,13 +703,13 @@ static void isc_set_histogram(struct isc_device *isc, bool enable)
if (enable) {
regmap_write(regmap, ISC_HIS_CFG,
- ISC_HIS_CFG_MODE_R |
+ ISC_HIS_CFG_MODE_GR |
(isc->config.sd_format->cfa_baycfg
<< ISC_HIS_CFG_BAYSEL_SHIFT) |
ISC_HIS_CFG_RAR);
regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_EN);
regmap_write(regmap, ISC_INTEN, ISC_INT_HISDONE);
- ctrls->hist_id = ISC_HIS_CFG_MODE_R;
+ ctrls->hist_id = ISC_HIS_CFG_MODE_GR;
isc_update_profile(isc);
regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ);
@@ -897,7 +752,7 @@ static int isc_configure(struct isc_device *isc)
isc_set_pipeline(isc, pipeline);
/*
- * The current implemented histogram is available for RAW R, B, GB
+ * The current implemented histogram is available for RAW R, B, GB, GR
* channels. We need to check if sensor is outputting RAW BAYER
*/
if (isc->ctrls.awb &&
@@ -949,6 +804,10 @@ static int isc_start_streaming(struct vb2_queue *vq, unsigned int count)
spin_unlock_irqrestore(&isc->dma_queue_lock, flags);
+ /* if we streaming from RAW, we can do one-shot white balance adj */
+ if (ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code))
+ v4l2_ctrl_activate(isc->do_wb_ctrl, true);
+
return 0;
err_configure:
@@ -973,6 +832,8 @@ static void isc_stop_streaming(struct vb2_queue *vq)
struct isc_buffer *buf;
int ret;
+ v4l2_ctrl_activate(isc->do_wb_ctrl, false);
+
isc->stop = true;
/* Wait until the end of the current frame */
@@ -1433,7 +1294,7 @@ static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f,
ret = v4l2_subdev_call(isc->current_subdev->sd, pad, set_fmt,
&pad_cfg, &format);
if (ret < 0)
- goto isc_try_fmt_err;
+ goto isc_try_fmt_subdev_err;
v4l2_fill_pix_format(pixfmt, &format.format);
@@ -1448,6 +1309,7 @@ static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f,
isc_try_fmt_err:
v4l2_err(&isc->v4l2_dev, "Could not find any possible format for a working pipeline\n");
+isc_try_fmt_subdev_err:
memset(&isc->try_config, 0, sizeof(isc->try_config));
return ret;
@@ -1472,6 +1334,12 @@ static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f)
return ret;
isc->fmt = *f;
+
+ if (isc->try_config.sd_format && isc->config.sd_format &&
+ isc->try_config.sd_format != isc->config.sd_format) {
+ isc->ctrls.hist_stat = HIST_INIT;
+ isc_reset_awb_ctrls(isc);
+ }
/* make the try configuration active */
isc->config = isc->try_config;
@@ -1588,7 +1456,7 @@ static int isc_enum_frameintervals(struct file *file, void *fh,
.which = V4L2_SUBDEV_FORMAT_ACTIVE,
};
int ret = -EINVAL;
- int i;
+ unsigned int i;
for (i = 0; i < isc->num_user_formats; i++)
if (isc->user_formats[i]->fourcc == fival->pixel_format)
@@ -1708,7 +1576,7 @@ static const struct v4l2_file_operations isc_fops = {
.poll = vb2_fop_poll,
};
-static irqreturn_t isc_interrupt(int irq, void *dev_id)
+irqreturn_t isc_interrupt(int irq, void *dev_id)
{
struct isc_device *isc = (struct isc_device *)dev_id;
struct regmap *regmap = isc->regmap;
@@ -1755,7 +1623,7 @@ static irqreturn_t isc_interrupt(int irq, void *dev_id)
return ret;
}
-static void isc_hist_count(struct isc_device *isc)
+static void isc_hist_count(struct isc_device *isc, u32 *min, u32 *max)
{
struct regmap *regmap = isc->regmap;
struct isc_ctrls *ctrls = &isc->ctrls;
@@ -1763,25 +1631,99 @@ static void isc_hist_count(struct isc_device *isc)
u32 *hist_entry = &ctrls->hist_entry[0];
u32 i;
+ *min = 0;
+ *max = HIST_ENTRIES;
+
regmap_bulk_read(regmap, ISC_HIS_ENTRY, hist_entry, HIST_ENTRIES);
*hist_count = 0;
- for (i = 0; i < HIST_ENTRIES; i++)
+ /*
+ * we deliberately ignore the end of the histogram,
+ * the most white pixels
+ */
+ for (i = 1; i < HIST_ENTRIES; i++) {
+ if (*hist_entry && !*min)
+ *min = i;
+ if (*hist_entry)
+ *max = i;
*hist_count += i * (*hist_entry++);
+ }
+
+ if (!*min)
+ *min = 1;
}
static void isc_wb_update(struct isc_ctrls *ctrls)
{
u32 *hist_count = &ctrls->hist_count[0];
- u64 g_count = (u64)hist_count[ISC_HIS_CFG_MODE_GB] << 9;
- u32 hist_r = hist_count[ISC_HIS_CFG_MODE_R];
- u32 hist_b = hist_count[ISC_HIS_CFG_MODE_B];
+ u32 c, offset[4];
+ u64 avg = 0;
+ /* We compute two gains, stretch gain and grey world gain */
+ u32 s_gain[4], gw_gain[4];
+
+ /*
+ * According to Grey World, we need to set gains for R/B to normalize
+ * them towards the green channel.
+ * Thus we want to keep Green as fixed and adjust only Red/Blue
+ * Compute the average of the both green channels first
+ */
+ avg = (u64)hist_count[ISC_HIS_CFG_MODE_GR] +
+ (u64)hist_count[ISC_HIS_CFG_MODE_GB];
+ avg >>= 1;
- if (hist_r)
- ctrls->r_gain = div_u64(g_count, hist_r);
+ /* Green histogram is null, nothing to do */
+ if (!avg)
+ return;
- if (hist_b)
- ctrls->b_gain = div_u64(g_count, hist_b);
+ for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) {
+ /*
+ * the color offset is the minimum value of the histogram.
+ * we stretch this color to the full range by substracting
+ * this value from the color component.
+ */
+ offset[c] = ctrls->hist_minmax[c][HIST_MIN_INDEX];
+ /*
+ * The offset is always at least 1. If the offset is 1, we do
+ * not need to adjust it, so our result must be zero.
+ * the offset is computed in a histogram on 9 bits (0..512)
+ * but the offset in register is based on
+ * 12 bits pipeline (0..4096).
+ * we need to shift with the 3 bits that the histogram is
+ * ignoring
+ */
+ ctrls->offset[c] = (offset[c] - 1) << 3;
+
+ /* the offset is then taken and converted to 2's complements */
+ if (!ctrls->offset[c])
+ ctrls->offset[c] = ISC_WB_O_ZERO_VAL;
+
+ /*
+ * the stretch gain is the total number of histogram bins
+ * divided by the actual range of color component (Max - Min)
+ * If we compute gain like this, the actual color component
+ * will be stretched to the full histogram.
+ * We need to shift 9 bits for precision, we have 9 bits for
+ * decimals
+ */
+ s_gain[c] = (HIST_ENTRIES << 9) /
+ (ctrls->hist_minmax[c][HIST_MAX_INDEX] -
+ ctrls->hist_minmax[c][HIST_MIN_INDEX] + 1);
+
+ /*
+ * Now we have to compute the gain w.r.t. the average.
+ * Add/lose gain to the component towards the average.
+ * If it happens that the component is zero, use the
+ * fixed point value : 1.0 gain.
+ */
+ if (hist_count[c])
+ gw_gain[c] = div_u64(avg << 9, hist_count[c]);
+ else
+ gw_gain[c] = 1 << 9;
+
+ /* multiply both gains and adjust for decimals */
+ ctrls->gain[c] = s_gain[c] * gw_gain[c];
+ ctrls->gain[c] >>= 9;
+ }
}
static void isc_awb_work(struct work_struct *w)
@@ -1792,27 +1734,66 @@ static void isc_awb_work(struct work_struct *w)
struct isc_ctrls *ctrls = &isc->ctrls;
u32 hist_id = ctrls->hist_id;
u32 baysel;
+ unsigned long flags;
+ u32 min, max;
+
+ /* streaming is not active anymore */
+ if (isc->stop)
+ return;
if (ctrls->hist_stat != HIST_ENABLED)
return;
- isc_hist_count(isc);
+ isc_hist_count(isc, &min, &max);
+ ctrls->hist_minmax[hist_id][HIST_MIN_INDEX] = min;
+ ctrls->hist_minmax[hist_id][HIST_MAX_INDEX] = max;
if (hist_id != ISC_HIS_CFG_MODE_B) {
hist_id++;
} else {
isc_wb_update(ctrls);
- hist_id = ISC_HIS_CFG_MODE_R;
+ hist_id = ISC_HIS_CFG_MODE_GR;
}
ctrls->hist_id = hist_id;
baysel = isc->config.sd_format->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT;
+ /* if no more auto white balance, reset controls. */
+ if (ctrls->awb == ISC_WB_NONE)
+ isc_reset_awb_ctrls(isc);
+
pm_runtime_get_sync(isc->dev);
+ /*
+ * only update if we have all the required histograms and controls
+ * if awb has been disabled, we need to reset registers as well.
+ */
+ if (hist_id == ISC_HIS_CFG_MODE_GR || ctrls->awb == ISC_WB_NONE) {
+ /*
+ * It may happen that DMA Done IRQ will trigger while we are
+ * updating white balance registers here.
+ * In that case, only parts of the controls have been updated.
+ * We can avoid that by locking the section.
+ */
+ spin_lock_irqsave(&isc->awb_lock, flags);
+ isc_update_awb_ctrls(isc);
+ spin_unlock_irqrestore(&isc->awb_lock, flags);
+
+ /*
+ * if we are doing just the one time white balance adjustment,
+ * we are basically done.
+ */
+ if (ctrls->awb == ISC_WB_ONETIME) {
+ v4l2_info(&isc->v4l2_dev,
+ "Completed one time white-balance adjustment.\n");
+ ctrls->awb = ISC_WB_NONE;
+ }
+ }
regmap_write(regmap, ISC_HIS_CFG, hist_id | baysel | ISC_HIS_CFG_RAR);
isc_update_profile(isc);
- regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ);
+ /* if awb has been disabled, we don't need to start another histogram */
+ if (ctrls->awb)
+ regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ);
pm_runtime_put_sync(isc->dev);
}
@@ -1823,6 +1804,9 @@ static int isc_s_ctrl(struct v4l2_ctrl *ctrl)
struct isc_device, ctrls.handler);
struct isc_ctrls *ctrls = &isc->ctrls;
+ if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
+ return 0;
+
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
ctrls->brightness = ctrl->val & ISC_CBC_BRIGHT_MASK;
@@ -1834,11 +1818,33 @@ static int isc_s_ctrl(struct v4l2_ctrl *ctrl)
ctrls->gamma_index = ctrl->val;
break;
case V4L2_CID_AUTO_WHITE_BALANCE:
- ctrls->awb = ctrl->val;
- if (ctrls->hist_stat != HIST_ENABLED) {
- ctrls->r_gain = 0x1 << 9;
- ctrls->b_gain = 0x1 << 9;
- }
+ if (ctrl->val == 1)
+ ctrls->awb = ISC_WB_AUTO;
+ else
+ ctrls->awb = ISC_WB_NONE;
+
+ /* we did not configure ISC yet */
+ if (!isc->config.sd_format)
+ break;
+
+ if (ctrls->hist_stat != HIST_ENABLED)
+ isc_reset_awb_ctrls(isc);
+
+ if (isc->ctrls.awb == ISC_WB_AUTO &&
+ vb2_is_streaming(&isc->vb2_vidq) &&
+ ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code))
+ isc_set_histogram(isc, true);
+
+ break;
+ case V4L2_CID_DO_WHITE_BALANCE:
+ /* if AWB is enabled, do nothing */
+ if (ctrls->awb == ISC_WB_AUTO)
+ return 0;
+
+ ctrls->awb = ISC_WB_ONETIME;
+ isc_set_histogram(isc, true);
+ v4l2_dbg(1, debug, &isc->v4l2_dev,
+ "One time white-balance started.\n");
break;
default:
return -EINVAL;
@@ -1859,16 +1865,32 @@ static int isc_ctrl_init(struct isc_device *isc)
int ret;
ctrls->hist_stat = HIST_INIT;
+ isc_reset_awb_ctrls(isc);
- ret = v4l2_ctrl_handler_init(hdl, 4);
+ ret = v4l2_ctrl_handler_init(hdl, 5);
if (ret < 0)
return ret;
+ ctrls->brightness = 0;
+ ctrls->contrast = 256;
+
v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -1024, 1023, 1, 0);
v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 256);
v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, GAMMA_MAX, 1, 2);
v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
+ /* do_white_balance is a button, so min,max,step,default are ignored */
+ isc->do_wb_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_DO_WHITE_BALANCE,
+ 0, 0, 0, 0);
+
+ if (!isc->do_wb_ctrl) {
+ ret = hdl->error;
+ v4l2_ctrl_handler_free(hdl);
+ return ret;
+ }
+
+ v4l2_ctrl_activate(isc->do_wb_ctrl, false);
+
v4l2_ctrl_handler_setup(hdl);
return 0;
@@ -1994,7 +2016,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
struct isc_device, v4l2_dev);
struct video_device *vdev = &isc->video_dev;
struct vb2_queue *q = &isc->vb2_vidq;
- int ret;
+ int ret = 0;
INIT_WORK(&isc->awb_work, isc_awb_work);
@@ -2025,30 +2047,31 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
if (ret < 0) {
v4l2_err(&isc->v4l2_dev,
"vb2_queue_init() failed: %d\n", ret);
- return ret;
+ goto isc_async_complete_err;
}
/* Init video dma queues */
INIT_LIST_HEAD(&isc->dma_queue);
spin_lock_init(&isc->dma_queue_lock);
+ spin_lock_init(&isc->awb_lock);
ret = isc_formats_init(isc);
if (ret < 0) {
v4l2_err(&isc->v4l2_dev,
"Init format failed: %d\n", ret);
- return ret;
+ goto isc_async_complete_err;
}
ret = isc_set_default_fmt(isc);
if (ret) {
v4l2_err(&isc->v4l2_dev, "Could not set default format\n");
- return ret;
+ goto isc_async_complete_err;
}
ret = isc_ctrl_init(isc);
if (ret) {
v4l2_err(&isc->v4l2_dev, "Init isc ctrols failed: %d\n", ret);
- return ret;
+ goto isc_async_complete_err;
}
/* Register video device */
@@ -2068,19 +2091,23 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
if (ret < 0) {
v4l2_err(&isc->v4l2_dev,
"video_register_device failed: %d\n", ret);
- return ret;
+ goto isc_async_complete_err;
}
return 0;
+
+isc_async_complete_err:
+ mutex_destroy(&isc->lock);
+ return ret;
}
-static const struct v4l2_async_notifier_operations isc_async_ops = {
+const struct v4l2_async_notifier_operations isc_async_ops = {
.bound = isc_async_bound,
.unbind = isc_async_unbind,
.complete = isc_async_complete,
};
-static void isc_subdev_cleanup(struct isc_device *isc)
+void isc_subdev_cleanup(struct isc_device *isc)
{
struct isc_subdev_entity *subdev_entity;
@@ -2092,7 +2119,7 @@ static void isc_subdev_cleanup(struct isc_device *isc)
INIT_LIST_HEAD(&isc->subdev_entities);
}
-static int isc_pipeline_init(struct isc_device *isc)
+int isc_pipeline_init(struct isc_device *isc)
{
struct device *dev = isc->dev;
struct regmap *regmap = isc->regmap;
@@ -2125,300 +2152,12 @@ static int isc_pipeline_init(struct isc_device *isc)
return 0;
}
-static int isc_parse_dt(struct device *dev, struct isc_device *isc)
-{
- struct device_node *np = dev->of_node;
- struct device_node *epn = NULL, *rem;
- struct isc_subdev_entity *subdev_entity;
- unsigned int flags;
- int ret;
-
- INIT_LIST_HEAD(&isc->subdev_entities);
-
- while (1) {
- struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 };
-
- epn = of_graph_get_next_endpoint(np, epn);
- if (!epn)
- return 0;
-
- rem = of_graph_get_remote_port_parent(epn);
- if (!rem) {
- dev_notice(dev, "Remote device at %pOF not found\n",
- epn);
- continue;
- }
-
- ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn),
- &v4l2_epn);
- if (ret) {
- of_node_put(rem);
- ret = -EINVAL;
- dev_err(dev, "Could not parse the endpoint\n");
- break;
- }
-
- subdev_entity = devm_kzalloc(dev,
- sizeof(*subdev_entity), GFP_KERNEL);
- if (!subdev_entity) {
- of_node_put(rem);
- ret = -ENOMEM;
- break;
- }
-
- /* asd will be freed by the subsystem once it's added to the
- * notifier list
- */
- subdev_entity->asd = kzalloc(sizeof(*subdev_entity->asd),
- GFP_KERNEL);
- if (!subdev_entity->asd) {
- of_node_put(rem);
- ret = -ENOMEM;
- break;
- }
-
- flags = v4l2_epn.bus.parallel.flags;
-
- if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
- subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW;
-
- if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
- subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW;
-
- if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
- subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW;
-
- if (v4l2_epn.bus_type == V4L2_MBUS_BT656)
- subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC |
- ISC_PFE_CFG0_CCIR656;
-
- subdev_entity->asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
- subdev_entity->asd->match.fwnode =
- of_fwnode_handle(rem);
- list_add_tail(&subdev_entity->list, &isc->subdev_entities);
- }
-
- of_node_put(epn);
- return ret;
-}
-
/* regmap configuration */
#define ATMEL_ISC_REG_MAX 0xbfc
-static const struct regmap_config isc_regmap_config = {
+const struct regmap_config isc_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = ATMEL_ISC_REG_MAX,
};
-static int atmel_isc_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct isc_device *isc;
- struct resource *res;
- void __iomem *io_base;
- struct isc_subdev_entity *subdev_entity;
- int irq;
- int ret;
-
- isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL);
- if (!isc)
- return -ENOMEM;
-
- platform_set_drvdata(pdev, isc);
- isc->dev = dev;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- io_base = devm_ioremap_resource(dev, res);
- if (IS_ERR(io_base))
- return PTR_ERR(io_base);
-
- isc->regmap = devm_regmap_init_mmio(dev, io_base, &isc_regmap_config);
- if (IS_ERR(isc->regmap)) {
- ret = PTR_ERR(isc->regmap);
- dev_err(dev, "failed to init register map: %d\n", ret);
- return ret;
- }
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- ret = irq;
- dev_err(dev, "failed to get irq: %d\n", ret);
- return ret;
- }
-
- ret = devm_request_irq(dev, irq, isc_interrupt, 0,
- ATMEL_ISC_NAME, isc);
- if (ret < 0) {
- dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
- irq, ret);
- return ret;
- }
-
- ret = isc_pipeline_init(isc);
- if (ret)
- return ret;
-
- isc->hclock = devm_clk_get(dev, "hclock");
- if (IS_ERR(isc->hclock)) {
- ret = PTR_ERR(isc->hclock);
- dev_err(dev, "failed to get hclock: %d\n", ret);
- return ret;
- }
-
- ret = clk_prepare_enable(isc->hclock);
- if (ret) {
- dev_err(dev, "failed to enable hclock: %d\n", ret);
- return ret;
- }
-
- ret = isc_clk_init(isc);
- if (ret) {
- dev_err(dev, "failed to init isc clock: %d\n", ret);
- goto unprepare_hclk;
- }
-
- isc->ispck = isc->isc_clks[ISC_ISPCK].clk;
-
- ret = clk_prepare_enable(isc->ispck);
- if (ret) {
- dev_err(dev, "failed to enable ispck: %d\n", ret);
- goto unprepare_hclk;
- }
-
- /* ispck should be greater or equal to hclock */
- ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock));
- if (ret) {
- dev_err(dev, "failed to set ispck rate: %d\n", ret);
- goto unprepare_clk;
- }
-
- ret = v4l2_device_register(dev, &isc->v4l2_dev);
- if (ret) {
- dev_err(dev, "unable to register v4l2 device.\n");
- goto unprepare_clk;
- }
-
- ret = isc_parse_dt(dev, isc);
- if (ret) {
- dev_err(dev, "fail to parse device tree\n");
- goto unregister_v4l2_device;
- }
-
- if (list_empty(&isc->subdev_entities)) {
- dev_err(dev, "no subdev found\n");
- ret = -ENODEV;
- goto unregister_v4l2_device;
- }
-
- list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
- v4l2_async_notifier_init(&subdev_entity->notifier);
-
- ret = v4l2_async_notifier_add_subdev(&subdev_entity->notifier,
- subdev_entity->asd);
- if (ret) {
- fwnode_handle_put(subdev_entity->asd->match.fwnode);
- kfree(subdev_entity->asd);
- goto cleanup_subdev;
- }
-
- subdev_entity->notifier.ops = &isc_async_ops;
-
- ret = v4l2_async_notifier_register(&isc->v4l2_dev,
- &subdev_entity->notifier);
- if (ret) {
- dev_err(dev, "fail to register async notifier\n");
- goto cleanup_subdev;
- }
-
- if (video_is_registered(&isc->video_dev))
- break;
- }
-
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
- pm_request_idle(dev);
-
- return 0;
-
-cleanup_subdev:
- isc_subdev_cleanup(isc);
-
-unregister_v4l2_device:
- v4l2_device_unregister(&isc->v4l2_dev);
-
-unprepare_clk:
- clk_disable_unprepare(isc->ispck);
-unprepare_hclk:
- clk_disable_unprepare(isc->hclock);
-
- isc_clk_cleanup(isc);
-
- return ret;
-}
-
-static int atmel_isc_remove(struct platform_device *pdev)
-{
- struct isc_device *isc = platform_get_drvdata(pdev);
-
- pm_runtime_disable(&pdev->dev);
- clk_disable_unprepare(isc->ispck);
- clk_disable_unprepare(isc->hclock);
-
- isc_subdev_cleanup(isc);
-
- v4l2_device_unregister(&isc->v4l2_dev);
-
- isc_clk_cleanup(isc);
-
- return 0;
-}
-
-static int __maybe_unused isc_runtime_suspend(struct device *dev)
-{
- struct isc_device *isc = dev_get_drvdata(dev);
-
- clk_disable_unprepare(isc->ispck);
- clk_disable_unprepare(isc->hclock);
-
- return 0;
-}
-
-static int __maybe_unused isc_runtime_resume(struct device *dev)
-{
- struct isc_device *isc = dev_get_drvdata(dev);
- int ret;
-
- ret = clk_prepare_enable(isc->hclock);
- if (ret)
- return ret;
-
- return clk_prepare_enable(isc->ispck);
-}
-
-static const struct dev_pm_ops atmel_isc_dev_pm_ops = {
- SET_RUNTIME_PM_OPS(isc_runtime_suspend, isc_runtime_resume, NULL)
-};
-
-static const struct of_device_id atmel_isc_of_match[] = {
- { .compatible = "atmel,sama5d2-isc" },
- { }
-};
-MODULE_DEVICE_TABLE(of, atmel_isc_of_match);
-
-static struct platform_driver atmel_isc_driver = {
- .probe = atmel_isc_probe,
- .remove = atmel_isc_remove,
- .driver = {
- .name = ATMEL_ISC_NAME,
- .pm = &atmel_isc_dev_pm_ops,
- .of_match_table = of_match_ptr(atmel_isc_of_match),
- },
-};
-
-module_platform_driver(atmel_isc_driver);
-
-MODULE_AUTHOR("Songjun Wu <songjun.wu@microchip.com>");
-MODULE_DESCRIPTION("The V4L2 driver for Atmel-ISC");
-MODULE_LICENSE("GPL v2");
-MODULE_SUPPORTED_DEVICE("video");
diff --git a/drivers/media/platform/atmel/atmel-isc-regs.h b/drivers/media/platform/atmel/atmel-isc-regs.h
index 8f7f8efc71a7..c1283fb21bf6 100644
--- a/drivers/media/platform/atmel/atmel-isc-regs.h
+++ b/drivers/media/platform/atmel/atmel-isc-regs.h
@@ -100,13 +100,15 @@
#define ISC_WB_O_RGR 0x00000060
/* ISC White Balance Offset for B, GB Register */
-#define ISC_WB_O_BGR 0x00000064
+#define ISC_WB_O_BGB 0x00000064
/* ISC White Balance Gain for R, GR Register */
#define ISC_WB_G_RGR 0x00000068
/* ISC White Balance Gain for B, GB Register */
-#define ISC_WB_G_BGR 0x0000006c
+#define ISC_WB_G_BGB 0x0000006c
+
+#define ISC_WB_O_ZERO_VAL (1 << 13)
/* ISC Color Filter Array Control Register */
#define ISC_CFA_CTRL 0x00000070
diff --git a/drivers/media/platform/atmel/atmel-isc.h b/drivers/media/platform/atmel/atmel-isc.h
new file mode 100644
index 000000000000..bfaed2fad2b5
--- /dev/null
+++ b/drivers/media/platform/atmel/atmel-isc.h
@@ -0,0 +1,245 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Microchip Image Sensor Controller (ISC) driver header file
+ *
+ * Copyright (C) 2016-2019 Microchip Technology, Inc.
+ *
+ * Author: Songjun Wu
+ * Author: Eugen Hristev <eugen.hristev@microchip.com>
+ *
+ */
+#ifndef _ATMEL_ISC_H_
+
+#define ISC_MAX_SUPPORT_WIDTH 2592
+#define ISC_MAX_SUPPORT_HEIGHT 1944
+
+#define ISC_CLK_MAX_DIV 255
+
+enum isc_clk_id {
+ ISC_ISPCK = 0,
+ ISC_MCK = 1,
+};
+
+struct isc_clk {
+ struct clk_hw hw;
+ struct clk *clk;
+ struct regmap *regmap;
+ spinlock_t lock; /* serialize access to clock registers */
+ u8 id;
+ u8 parent_id;
+ u32 div;
+ struct device *dev;
+};
+
+#define to_isc_clk(v) container_of(v, struct isc_clk, hw)
+
+struct isc_buffer {
+ struct vb2_v4l2_buffer vb;
+ struct list_head list;
+};
+
+struct isc_subdev_entity {
+ struct v4l2_subdev *sd;
+ struct v4l2_async_subdev *asd;
+ struct v4l2_async_notifier notifier;
+
+ u32 pfe_cfg0;
+
+ struct list_head list;
+};
+
+/*
+ * struct isc_format - ISC media bus format information
+ This structure represents the interface between the ISC
+ and the sensor. It's the input format received by
+ the ISC.
+ * @fourcc: Fourcc code for this format
+ * @mbus_code: V4L2 media bus format code.
+ * @cfa_baycfg: If this format is RAW BAYER, indicate the type of bayer.
+ this is either BGBG, RGRG, etc.
+ * @pfe_cfg0_bps: Number of hardware data lines connected to the ISC
+ */
+
+struct isc_format {
+ u32 fourcc;
+ u32 mbus_code;
+ u32 cfa_baycfg;
+
+ bool sd_support;
+ u32 pfe_cfg0_bps;
+};
+
+/* Pipeline bitmap */
+#define WB_ENABLE BIT(0)
+#define CFA_ENABLE BIT(1)
+#define CC_ENABLE BIT(2)
+#define GAM_ENABLE BIT(3)
+#define GAM_BENABLE BIT(4)
+#define GAM_GENABLE BIT(5)
+#define GAM_RENABLE BIT(6)
+#define CSC_ENABLE BIT(7)
+#define CBC_ENABLE BIT(8)
+#define SUB422_ENABLE BIT(9)
+#define SUB420_ENABLE BIT(10)
+
+#define GAM_ENABLES (GAM_RENABLE | GAM_GENABLE | GAM_BENABLE | GAM_ENABLE)
+
+/*
+ * struct fmt_config - ISC format configuration and internal pipeline
+ This structure represents the internal configuration
+ of the ISC.
+ It also holds the format that ISC will present to v4l2.
+ * @sd_format: Pointer to an isc_format struct that holds the sensor
+ configuration.
+ * @fourcc: Fourcc code for this format.
+ * @bpp: Bytes per pixel in the current format.
+ * @rlp_cfg_mode: Configuration of the RLP (rounding, limiting packaging)
+ * @dcfg_imode: Configuration of the input of the DMA module
+ * @dctrl_dview: Configuration of the output of the DMA module
+ * @bits_pipeline: Configuration of the pipeline, which modules are enabled
+ */
+struct fmt_config {
+ struct isc_format *sd_format;
+
+ u32 fourcc;
+ u8 bpp;
+
+ u32 rlp_cfg_mode;
+ u32 dcfg_imode;
+ u32 dctrl_dview;
+
+ u32 bits_pipeline;
+};
+
+#define HIST_ENTRIES 512
+#define HIST_BAYER (ISC_HIS_CFG_MODE_B + 1)
+
+enum{
+ HIST_INIT = 0,
+ HIST_ENABLED,
+ HIST_DISABLED,
+};
+
+struct isc_ctrls {
+ struct v4l2_ctrl_handler handler;
+
+ u32 brightness;
+ u32 contrast;
+ u8 gamma_index;
+#define ISC_WB_NONE 0
+#define ISC_WB_AUTO 1
+#define ISC_WB_ONETIME 2
+ u8 awb;
+
+ /* one for each component : GR, R, GB, B */
+ u32 gain[HIST_BAYER];
+ u32 offset[HIST_BAYER];
+
+ u32 hist_entry[HIST_ENTRIES];
+ u32 hist_count[HIST_BAYER];
+ u8 hist_id;
+ u8 hist_stat;
+#define HIST_MIN_INDEX 0
+#define HIST_MAX_INDEX 1
+ u32 hist_minmax[HIST_BAYER][2];
+};
+
+#define ISC_PIPE_LINE_NODE_NUM 11
+
+/*
+ * struct isc_device - ISC device driver data/config struct
+ * @regmap: Register map
+ * @hclock: Hclock clock input (refer datasheet)
+ * @ispck: iscpck clock (refer datasheet)
+ * @isc_clks: ISC clocks
+ *
+ * @dev: Registered device driver
+ * @v4l2_dev: v4l2 registered device
+ * @video_dev: registered video device
+ *
+ * @vb2_vidq: video buffer 2 video queue
+ * @dma_queue_lock: lock to serialize the dma buffer queue
+ * @dma_queue: the queue for dma buffers
+ * @cur_frm: current isc frame/buffer
+ * @sequence: current frame number
+ * @stop: true if isc is not streaming, false if streaming
+ * @comp: completion reference that signals frame completion
+ *
+ * @fmt: current v42l format
+ * @user_formats: list of formats that are supported and agreed with sd
+ * @num_user_formats: how many formats are in user_formats
+ *
+ * @config: current ISC format configuration
+ * @try_config: the current ISC try format , not yet activated
+ *
+ * @ctrls: holds information about ISC controls
+ * @do_wb_ctrl: control regarding the DO_WHITE_BALANCE button
+ * @awb_work: workqueue reference for autowhitebalance histogram
+ * analysis
+ *
+ * @lock: lock for serializing userspace file operations
+ * with ISC operations
+ * @awb_lock: lock for serializing awb work queue operations
+ * with DMA/buffer operations
+ *
+ * @pipeline: configuration of the ISC pipeline
+ *
+ * @current_subdev: current subdevice: the sensor
+ * @subdev_entities: list of subdevice entitites
+ */
+struct isc_device {
+ struct regmap *regmap;
+ struct clk *hclock;
+ struct clk *ispck;
+ struct isc_clk isc_clks[2];
+
+ struct device *dev;
+ struct v4l2_device v4l2_dev;
+ struct video_device video_dev;
+
+ struct vb2_queue vb2_vidq;
+ spinlock_t dma_queue_lock; /* serialize access to dma queue */
+ struct list_head dma_queue;
+ struct isc_buffer *cur_frm;
+ unsigned int sequence;
+ bool stop;
+ struct completion comp;
+
+ struct v4l2_format fmt;
+ struct isc_format **user_formats;
+ unsigned int num_user_formats;
+
+ struct fmt_config config;
+ struct fmt_config try_config;
+
+ struct isc_ctrls ctrls;
+ struct v4l2_ctrl *do_wb_ctrl;
+ struct work_struct awb_work;
+
+ struct mutex lock; /* serialize access to file operations */
+ spinlock_t awb_lock; /* serialize access to DMA buffers from awb work queue */
+
+ struct regmap_field *pipeline[ISC_PIPE_LINE_NODE_NUM];
+
+ struct isc_subdev_entity *current_subdev;
+ struct list_head subdev_entities;
+};
+
+#define GAMMA_MAX 2
+#define GAMMA_ENTRIES 64
+
+#define ATMEL_ISC_NAME "atmel-isc"
+
+extern struct isc_format formats_list[];
+extern const struct isc_format controller_formats[];
+extern const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES];
+extern const struct regmap_config isc_regmap_config;
+extern const struct v4l2_async_notifier_operations isc_async_ops;
+
+irqreturn_t isc_interrupt(int irq, void *dev_id);
+int isc_pipeline_init(struct isc_device *isc);
+int isc_clk_init(struct isc_device *isc);
+void isc_subdev_cleanup(struct isc_device *isc);
+void isc_clk_cleanup(struct isc_device *isc);
+
+#endif
diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c
index 08b8d5583080..d7d94c1a39d3 100644
--- a/drivers/media/platform/atmel/atmel-isi.c
+++ b/drivers/media/platform/atmel/atmel-isi.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2011 Atmel Corporation
* Josh Wu, <josh.wu@atmel.com>
@@ -5,10 +6,6 @@
* Based on previous work by Lars Haring, <lars.haring@atmel.com>
* and Sedji Gaouaou
* Based on the bttv driver for Bt848 with respective copyright holders
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/media/platform/atmel/atmel-isi.h b/drivers/media/platform/atmel/atmel-isi.h
index 0acb32a2b65c..47a9108dba55 100644
--- a/drivers/media/platform/atmel/atmel-isi.h
+++ b/drivers/media/platform/atmel/atmel-isi.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Register definitions for the Atmel Image Sensor Interface.
*
@@ -6,10 +7,6 @@
*
* Based on previous work by Lars Haring, <lars.haring@atmel.com>
* and Sedji Gaouaou
- *
- * 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.
*/
#ifndef __ATMEL_ISI_H__
#define __ATMEL_ISI_H__
diff --git a/drivers/media/platform/atmel/atmel-sama5d2-isc.c b/drivers/media/platform/atmel/atmel-sama5d2-isc.c
new file mode 100644
index 000000000000..266df14da2d5
--- /dev/null
+++ b/drivers/media/platform/atmel/atmel-sama5d2-isc.c
@@ -0,0 +1,348 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Microchip Image Sensor Controller (ISC) driver
+ *
+ * Copyright (C) 2016-2019 Microchip Technology, Inc.
+ *
+ * Author: Songjun Wu
+ * Author: Eugen Hristev <eugen.hristev@microchip.com>
+ *
+ *
+ * Sensor-->PFE-->WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB-->RLP-->DMA
+ *
+ * ISC video pipeline integrates the following submodules:
+ * PFE: Parallel Front End to sample the camera sensor input stream
+ * WB: Programmable white balance in the Bayer domain
+ * CFA: Color filter array interpolation module
+ * CC: Programmable color correction
+ * GAM: Gamma correction
+ * CSC: Programmable color space conversion
+ * CBC: Contrast and Brightness control
+ * SUB: This module performs YCbCr444 to YCbCr420 chrominance subsampling
+ * RLP: This module performs rounding, range limiting
+ * and packing of the incoming data
+ */
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-image-sizes.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "atmel-isc-regs.h"
+#include "atmel-isc.h"
+
+#define ISC_MAX_SUPPORT_WIDTH 2592
+#define ISC_MAX_SUPPORT_HEIGHT 1944
+
+#define ISC_CLK_MAX_DIV 255
+
+static int isc_parse_dt(struct device *dev, struct isc_device *isc)
+{
+ struct device_node *np = dev->of_node;
+ struct device_node *epn = NULL, *rem;
+ struct isc_subdev_entity *subdev_entity;
+ unsigned int flags;
+ int ret;
+
+ INIT_LIST_HEAD(&isc->subdev_entities);
+
+ while (1) {
+ struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 };
+
+ epn = of_graph_get_next_endpoint(np, epn);
+ if (!epn)
+ return 0;
+
+ rem = of_graph_get_remote_port_parent(epn);
+ if (!rem) {
+ dev_notice(dev, "Remote device at %pOF not found\n",
+ epn);
+ continue;
+ }
+
+ ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn),
+ &v4l2_epn);
+ if (ret) {
+ of_node_put(rem);
+ ret = -EINVAL;
+ dev_err(dev, "Could not parse the endpoint\n");
+ break;
+ }
+
+ subdev_entity = devm_kzalloc(dev, sizeof(*subdev_entity),
+ GFP_KERNEL);
+ if (!subdev_entity) {
+ of_node_put(rem);
+ ret = -ENOMEM;
+ break;
+ }
+
+ /* asd will be freed by the subsystem once it's added to the
+ * notifier list
+ */
+ subdev_entity->asd = kzalloc(sizeof(*subdev_entity->asd),
+ GFP_KERNEL);
+ if (!subdev_entity->asd) {
+ of_node_put(rem);
+ ret = -ENOMEM;
+ break;
+ }
+
+ flags = v4l2_epn.bus.parallel.flags;
+
+ if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
+ subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW;
+
+ if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
+ subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW;
+
+ if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
+ subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW;
+
+ if (v4l2_epn.bus_type == V4L2_MBUS_BT656)
+ subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC |
+ ISC_PFE_CFG0_CCIR656;
+
+ subdev_entity->asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
+ subdev_entity->asd->match.fwnode = of_fwnode_handle(rem);
+ list_add_tail(&subdev_entity->list, &isc->subdev_entities);
+ }
+
+ of_node_put(epn);
+ return ret;
+}
+
+static int atmel_isc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct isc_device *isc;
+ struct resource *res;
+ void __iomem *io_base;
+ struct isc_subdev_entity *subdev_entity;
+ int irq;
+ int ret;
+
+ isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL);
+ if (!isc)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, isc);
+ isc->dev = dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ io_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(io_base))
+ return PTR_ERR(io_base);
+
+ isc->regmap = devm_regmap_init_mmio(dev, io_base, &isc_regmap_config);
+ if (IS_ERR(isc->regmap)) {
+ ret = PTR_ERR(isc->regmap);
+ dev_err(dev, "failed to init register map: %d\n", ret);
+ return ret;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ ret = irq;
+ dev_err(dev, "failed to get irq: %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_request_irq(dev, irq, isc_interrupt, 0,
+ ATMEL_ISC_NAME, isc);
+ if (ret < 0) {
+ dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
+ irq, ret);
+ return ret;
+ }
+
+ ret = isc_pipeline_init(isc);
+ if (ret)
+ return ret;
+
+ isc->hclock = devm_clk_get(dev, "hclock");
+ if (IS_ERR(isc->hclock)) {
+ ret = PTR_ERR(isc->hclock);
+ dev_err(dev, "failed to get hclock: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(isc->hclock);
+ if (ret) {
+ dev_err(dev, "failed to enable hclock: %d\n", ret);
+ return ret;
+ }
+
+ ret = isc_clk_init(isc);
+ if (ret) {
+ dev_err(dev, "failed to init isc clock: %d\n", ret);
+ goto unprepare_hclk;
+ }
+
+ isc->ispck = isc->isc_clks[ISC_ISPCK].clk;
+
+ ret = clk_prepare_enable(isc->ispck);
+ if (ret) {
+ dev_err(dev, "failed to enable ispck: %d\n", ret);
+ goto unprepare_hclk;
+ }
+
+ /* ispck should be greater or equal to hclock */
+ ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock));
+ if (ret) {
+ dev_err(dev, "failed to set ispck rate: %d\n", ret);
+ goto unprepare_clk;
+ }
+
+ ret = v4l2_device_register(dev, &isc->v4l2_dev);
+ if (ret) {
+ dev_err(dev, "unable to register v4l2 device.\n");
+ goto unprepare_clk;
+ }
+
+ ret = isc_parse_dt(dev, isc);
+ if (ret) {
+ dev_err(dev, "fail to parse device tree\n");
+ goto unregister_v4l2_device;
+ }
+
+ if (list_empty(&isc->subdev_entities)) {
+ dev_err(dev, "no subdev found\n");
+ ret = -ENODEV;
+ goto unregister_v4l2_device;
+ }
+
+ list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
+ v4l2_async_notifier_init(&subdev_entity->notifier);
+
+ ret = v4l2_async_notifier_add_subdev(&subdev_entity->notifier,
+ subdev_entity->asd);
+ if (ret) {
+ fwnode_handle_put(subdev_entity->asd->match.fwnode);
+ kfree(subdev_entity->asd);
+ goto cleanup_subdev;
+ }
+
+ subdev_entity->notifier.ops = &isc_async_ops;
+
+ ret = v4l2_async_notifier_register(&isc->v4l2_dev,
+ &subdev_entity->notifier);
+ if (ret) {
+ dev_err(dev, "fail to register async notifier\n");
+ goto cleanup_subdev;
+ }
+
+ if (video_is_registered(&isc->video_dev))
+ break;
+ }
+
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ pm_request_idle(dev);
+
+ return 0;
+
+cleanup_subdev:
+ isc_subdev_cleanup(isc);
+
+unregister_v4l2_device:
+ v4l2_device_unregister(&isc->v4l2_dev);
+
+unprepare_clk:
+ clk_disable_unprepare(isc->ispck);
+unprepare_hclk:
+ clk_disable_unprepare(isc->hclock);
+
+ isc_clk_cleanup(isc);
+
+ return ret;
+}
+
+static int atmel_isc_remove(struct platform_device *pdev)
+{
+ struct isc_device *isc = platform_get_drvdata(pdev);
+
+ pm_runtime_disable(&pdev->dev);
+
+ isc_subdev_cleanup(isc);
+
+ v4l2_device_unregister(&isc->v4l2_dev);
+
+ clk_disable_unprepare(isc->ispck);
+ clk_disable_unprepare(isc->hclock);
+
+ isc_clk_cleanup(isc);
+
+ return 0;
+}
+
+static int __maybe_unused isc_runtime_suspend(struct device *dev)
+{
+ struct isc_device *isc = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(isc->ispck);
+ clk_disable_unprepare(isc->hclock);
+
+ return 0;
+}
+
+static int __maybe_unused isc_runtime_resume(struct device *dev)
+{
+ struct isc_device *isc = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(isc->hclock);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(isc->ispck);
+ if (ret)
+ clk_disable_unprepare(isc->hclock);
+
+ return ret;
+}
+
+static const struct dev_pm_ops atmel_isc_dev_pm_ops = {
+ SET_RUNTIME_PM_OPS(isc_runtime_suspend, isc_runtime_resume, NULL)
+};
+
+static const struct of_device_id atmel_isc_of_match[] = {
+ { .compatible = "atmel,sama5d2-isc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, atmel_isc_of_match);
+
+static struct platform_driver atmel_isc_driver = {
+ .probe = atmel_isc_probe,
+ .remove = atmel_isc_remove,
+ .driver = {
+ .name = ATMEL_ISC_NAME,
+ .pm = &atmel_isc_dev_pm_ops,
+ .of_match_table = of_match_ptr(atmel_isc_of_match),
+ },
+};
+
+module_platform_driver(atmel_isc_driver);
+
+MODULE_AUTHOR("Songjun Wu");
+MODULE_DESCRIPTION("The V4L2 driver for Atmel-ISC");
+MODULE_LICENSE("GPL v2");
+MODULE_SUPPORTED_DEVICE("video");
diff --git a/drivers/media/platform/cec-gpio/cec-gpio.c b/drivers/media/platform/cec-gpio/cec-gpio.c
index d2861749d640..5b17d3a31896 100644
--- a/drivers/media/platform/cec-gpio/cec-gpio.c
+++ b/drivers/media/platform/cec-gpio/cec-gpio.c
@@ -17,7 +17,6 @@ struct cec_gpio {
struct gpio_desc *cec_gpio;
int cec_irq;
bool cec_is_low;
- bool cec_have_irq;
struct gpio_desc *hpd_gpio;
int hpd_irq;
@@ -55,9 +54,6 @@ static void cec_gpio_low(struct cec_adapter *adap)
if (cec->cec_is_low)
return;
- if (WARN_ON_ONCE(cec->cec_have_irq))
- free_irq(cec->cec_irq, cec);
- cec->cec_have_irq = false;
cec->cec_is_low = true;
gpiod_set_value(cec->cec_gpio, 0);
}
@@ -114,14 +110,7 @@ static bool cec_gpio_enable_irq(struct cec_adapter *adap)
{
struct cec_gpio *cec = cec_get_drvdata(adap);
- if (cec->cec_have_irq)
- return true;
-
- if (request_irq(cec->cec_irq, cec_gpio_irq_handler,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- adap->name, cec))
- return false;
- cec->cec_have_irq = true;
+ enable_irq(cec->cec_irq);
return true;
}
@@ -129,9 +118,7 @@ static void cec_gpio_disable_irq(struct cec_adapter *adap)
{
struct cec_gpio *cec = cec_get_drvdata(adap);
- if (cec->cec_have_irq)
- free_irq(cec->cec_irq, cec);
- cec->cec_have_irq = false;
+ disable_irq(cec->cec_irq);
}
static void cec_gpio_status(struct cec_adapter *adap, struct seq_file *file)
@@ -139,8 +126,7 @@ static void cec_gpio_status(struct cec_adapter *adap, struct seq_file *file)
struct cec_gpio *cec = cec_get_drvdata(adap);
seq_printf(file, "mode: %s\n", cec->cec_is_low ? "low-drive" : "read");
- if (cec->cec_have_irq)
- seq_printf(file, "using irq: %d\n", cec->cec_irq);
+ seq_printf(file, "using irq: %d\n", cec->cec_irq);
if (cec->hpd_gpio)
seq_printf(file, "hpd: %s\n",
cec->hpd_is_high ? "high" : "low");
@@ -215,6 +201,14 @@ static int cec_gpio_probe(struct platform_device *pdev)
if (IS_ERR(cec->adap))
return PTR_ERR(cec->adap);
+ ret = devm_request_irq(dev, cec->cec_irq, cec_gpio_irq_handler,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ cec->adap->name, cec);
+ if (ret)
+ return ret;
+
+ cec_gpio_disable_irq(cec->adap);
+
if (cec->hpd_gpio) {
cec->hpd_irq = gpiod_to_irq(cec->hpd_gpio);
ret = devm_request_threaded_irq(dev, cec->hpd_irq,
diff --git a/drivers/media/platform/coda/Makefile b/drivers/media/platform/coda/Makefile
index f13adacd924e..bbb16425a875 100644
--- a/drivers/media/platform/coda/Makefile
+++ b/drivers/media/platform/coda/Makefile
@@ -1,7 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
-ccflags-y += -I$(src)
-coda-objs := coda-common.o coda-bit.o coda-gdi.o coda-h264.o coda-jpeg.o
+coda-vpu-objs := coda-common.o coda-bit.o coda-gdi.o coda-h264.o coda-mpeg2.o coda-mpeg4.o coda-jpeg.o
-obj-$(CONFIG_VIDEO_CODA) += coda.o
+obj-$(CONFIG_VIDEO_CODA) += coda-vpu.o
obj-$(CONFIG_VIDEO_IMX_VDOA) += imx-vdoa.o
diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c
index 976f6aa69f41..00c7bed3dd57 100644
--- a/drivers/media/platform/coda/coda-bit.c
+++ b/drivers/media/platform/coda/coda-bit.c
@@ -98,6 +98,8 @@ static int coda_command_sync(struct coda_ctx *ctx, int cmd)
struct coda_dev *dev = ctx->dev;
int ret;
+ lockdep_assert_held(&dev->coda_mutex);
+
coda_command_async(ctx, cmd);
ret = coda_wait_timeout(dev);
trace_coda_bit_done(ctx);
@@ -112,6 +114,8 @@ int coda_hw_reset(struct coda_ctx *ctx)
unsigned int idx;
int ret;
+ lockdep_assert_held(&dev->coda_mutex);
+
if (!dev->rstc)
return -ENOENT;
@@ -176,7 +180,7 @@ static void coda_kfifo_sync_to_device_write(struct coda_ctx *ctx)
coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
}
-static int coda_bitstream_pad(struct coda_ctx *ctx, u32 size)
+static int coda_h264_bitstream_pad(struct coda_ctx *ctx, u32 size)
{
unsigned char *buf;
u32 n;
@@ -195,51 +199,122 @@ static int coda_bitstream_pad(struct coda_ctx *ctx, u32 size)
return (n < size) ? -ENOSPC : 0;
}
-static int coda_bitstream_queue(struct coda_ctx *ctx,
- struct vb2_v4l2_buffer *src_buf)
+int coda_bitstream_flush(struct coda_ctx *ctx)
{
- u32 src_size = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
- u32 n;
+ int ret;
- n = kfifo_in(&ctx->bitstream_fifo,
- vb2_plane_vaddr(&src_buf->vb2_buf, 0), src_size);
- if (n < src_size)
- return -ENOSPC;
+ if (ctx->inst_type != CODA_INST_DECODER || !ctx->use_bit)
+ return 0;
- src_buf->sequence = ctx->qsequence++;
+ ret = coda_command_sync(ctx, CODA_COMMAND_DEC_BUF_FLUSH);
+ if (ret < 0) {
+ v4l2_err(&ctx->dev->v4l2_dev, "failed to flush bitstream\n");
+ return ret;
+ }
+
+ kfifo_init(&ctx->bitstream_fifo, ctx->bitstream.vaddr,
+ ctx->bitstream.size);
+ coda_kfifo_sync_to_device_full(ctx);
return 0;
}
+static int coda_bitstream_queue(struct coda_ctx *ctx, const u8 *buf, u32 size)
+{
+ u32 n = kfifo_in(&ctx->bitstream_fifo, buf, size);
+
+ return (n < size) ? -ENOSPC : 0;
+}
+
+static u32 coda_buffer_parse_headers(struct coda_ctx *ctx,
+ struct vb2_v4l2_buffer *src_buf,
+ u32 payload)
+{
+ u8 *vaddr = vb2_plane_vaddr(&src_buf->vb2_buf, 0);
+ u32 size = 0;
+
+ switch (ctx->codec->src_fourcc) {
+ case V4L2_PIX_FMT_MPEG2:
+ size = coda_mpeg2_parse_headers(ctx, vaddr, payload);
+ break;
+ case V4L2_PIX_FMT_MPEG4:
+ size = coda_mpeg4_parse_headers(ctx, vaddr, payload);
+ break;
+ default:
+ break;
+ }
+
+ return size;
+}
+
static bool coda_bitstream_try_queue(struct coda_ctx *ctx,
struct vb2_v4l2_buffer *src_buf)
{
unsigned long payload = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
+ u8 *vaddr = vb2_plane_vaddr(&src_buf->vb2_buf, 0);
int ret;
+ int i;
if (coda_get_bitstream_payload(ctx) + payload + 512 >=
ctx->bitstream.size)
return false;
- if (vb2_plane_vaddr(&src_buf->vb2_buf, 0) == NULL) {
+ if (!vaddr) {
v4l2_err(&ctx->dev->v4l2_dev, "trying to queue empty buffer\n");
return true;
}
- /* Add zero padding before the first H.264 buffer, if it is too small */
+ if (ctx->qsequence == 0 && payload < 512) {
+ /*
+ * Add padding after the first buffer, if it is too small to be
+ * fetched by the CODA, by repeating the headers. Without
+ * repeated headers, or the first frame already queued, decoder
+ * sequence initialization fails with error code 0x2000 on i.MX6
+ * or error code 0x1 on i.MX51.
+ */
+ u32 header_size = coda_buffer_parse_headers(ctx, src_buf,
+ payload);
+
+ if (header_size) {
+ coda_dbg(1, ctx, "pad with %u-byte header\n",
+ header_size);
+ for (i = payload; i < 512; i += header_size) {
+ ret = coda_bitstream_queue(ctx, vaddr,
+ header_size);
+ if (ret < 0) {
+ v4l2_err(&ctx->dev->v4l2_dev,
+ "bitstream buffer overflow\n");
+ return false;
+ }
+ if (ctx->dev->devtype->product == CODA_960)
+ break;
+ }
+ } else {
+ coda_dbg(1, ctx,
+ "could not parse header, sequence initialization might fail\n");
+ }
+ }
+
+ /* Add padding before the first buffer, if it is too small */
if (ctx->qsequence == 0 && payload < 512 &&
ctx->codec->src_fourcc == V4L2_PIX_FMT_H264)
- coda_bitstream_pad(ctx, 512 - payload);
+ coda_h264_bitstream_pad(ctx, 512 - payload);
- ret = coda_bitstream_queue(ctx, src_buf);
+ ret = coda_bitstream_queue(ctx, vaddr, payload);
if (ret < 0) {
v4l2_err(&ctx->dev->v4l2_dev, "bitstream buffer overflow\n");
return false;
}
+
+ src_buf->sequence = ctx->qsequence++;
+
/* Sync read pointer to device */
if (ctx == v4l2_m2m_get_curr_priv(ctx->dev->m2m_dev))
coda_kfifo_sync_to_device_write(ctx);
+ /* Set the stream-end flag after the last buffer is queued */
+ if (src_buf->flags & V4L2_BUF_FLAG_LAST)
+ coda_bit_stream_end_flag(ctx);
ctx->hold = false;
return true;
@@ -327,6 +402,9 @@ void coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list)
meta->timestamp = src_buf->vb2_buf.timestamp;
meta->start = start;
meta->end = ctx->bitstream_fifo.kfifo.in;
+ meta->last = src_buf->flags & V4L2_BUF_FLAG_LAST;
+ if (meta->last)
+ coda_dbg(1, ctx, "marking last meta");
spin_lock(&ctx->buffer_meta_lock);
list_add_tail(&meta->list,
&ctx->buffer_meta_list);
@@ -391,7 +469,7 @@ static void coda_free_framebuffers(struct coda_ctx *ctx)
int i;
for (i = 0; i < CODA_MAX_FRAMEBUFFERS; i++)
- coda_free_aux_buf(ctx->dev, &ctx->internal_frames[i]);
+ coda_free_aux_buf(ctx->dev, &ctx->internal_frames[i].buf);
}
static int coda_alloc_framebuffers(struct coda_ctx *ctx,
@@ -431,7 +509,7 @@ static int coda_alloc_framebuffers(struct coda_ctx *ctx,
coda_free_framebuffers(ctx);
return -ENOMEM;
}
- ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i],
+ ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i].buf,
size, name);
kfree(name);
if (ret < 0) {
@@ -445,7 +523,7 @@ static int coda_alloc_framebuffers(struct coda_ctx *ctx,
u32 y, cb, cr, mvcol;
/* Start addresses of Y, Cb, Cr planes */
- y = ctx->internal_frames[i].paddr;
+ y = ctx->internal_frames[i].buf.paddr;
cb = y + ysize;
cr = y + ysize + ysize/4;
mvcol = y + ysize + ysize/4 + ysize/4;
@@ -597,6 +675,102 @@ static int coda_encode_header(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf,
return 0;
}
+static u32 coda_slice_mode(struct coda_ctx *ctx)
+{
+ int size, unit;
+
+ switch (ctx->params.slice_mode) {
+ case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE:
+ default:
+ return 0;
+ case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB:
+ size = ctx->params.slice_max_mb;
+ unit = 1;
+ break;
+ case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES:
+ size = ctx->params.slice_max_bits;
+ unit = 0;
+ break;
+ }
+
+ return ((size & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET) |
+ ((unit & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET) |
+ ((1 & CODA_SLICING_MODE_MASK) << CODA_SLICING_MODE_OFFSET);
+}
+
+static int coda_enc_param_change(struct coda_ctx *ctx)
+{
+ struct coda_dev *dev = ctx->dev;
+ u32 change_enable = 0;
+ u32 success;
+ int ret;
+
+ if (ctx->params.gop_size_changed) {
+ change_enable |= CODA_PARAM_CHANGE_RC_GOP;
+ coda_write(dev, ctx->params.gop_size,
+ CODA_CMD_ENC_PARAM_RC_GOP);
+ ctx->gopcounter = ctx->params.gop_size - 1;
+ ctx->params.gop_size_changed = false;
+ }
+ if (ctx->params.h264_intra_qp_changed) {
+ coda_dbg(1, ctx, "parameter change: intra Qp %u\n",
+ ctx->params.h264_intra_qp);
+
+ if (ctx->params.bitrate) {
+ change_enable |= CODA_PARAM_CHANGE_RC_INTRA_QP;
+ coda_write(dev, ctx->params.h264_intra_qp,
+ CODA_CMD_ENC_PARAM_RC_INTRA_QP);
+ }
+ ctx->params.h264_intra_qp_changed = false;
+ }
+ if (ctx->params.bitrate_changed) {
+ coda_dbg(1, ctx, "parameter change: bitrate %u kbit/s\n",
+ ctx->params.bitrate);
+ change_enable |= CODA_PARAM_CHANGE_RC_BITRATE;
+ coda_write(dev, ctx->params.bitrate,
+ CODA_CMD_ENC_PARAM_RC_BITRATE);
+ ctx->params.bitrate_changed = false;
+ }
+ if (ctx->params.framerate_changed) {
+ coda_dbg(1, ctx, "parameter change: frame rate %u/%u Hz\n",
+ ctx->params.framerate & 0xffff,
+ (ctx->params.framerate >> 16) + 1);
+ change_enable |= CODA_PARAM_CHANGE_RC_FRAME_RATE;
+ coda_write(dev, ctx->params.framerate,
+ CODA_CMD_ENC_PARAM_RC_FRAME_RATE);
+ ctx->params.framerate_changed = false;
+ }
+ if (ctx->params.intra_refresh_changed) {
+ coda_dbg(1, ctx, "parameter change: intra refresh MBs %u\n",
+ ctx->params.intra_refresh);
+ change_enable |= CODA_PARAM_CHANGE_INTRA_MB_NUM;
+ coda_write(dev, ctx->params.intra_refresh,
+ CODA_CMD_ENC_PARAM_INTRA_MB_NUM);
+ ctx->params.intra_refresh_changed = false;
+ }
+ if (ctx->params.slice_mode_changed) {
+ change_enable |= CODA_PARAM_CHANGE_SLICE_MODE;
+ coda_write(dev, coda_slice_mode(ctx),
+ CODA_CMD_ENC_PARAM_SLICE_MODE);
+ ctx->params.slice_mode_changed = false;
+ }
+
+ if (!change_enable)
+ return 0;
+
+ coda_write(dev, change_enable, CODA_CMD_ENC_PARAM_CHANGE_ENABLE);
+
+ ret = coda_command_sync(ctx, CODA_COMMAND_RC_CHANGE_PARAMETER);
+ if (ret < 0)
+ return ret;
+
+ success = coda_read(dev, CODA_RET_ENC_PARAM_CHANGE_SUCCESS);
+ if (success != 1)
+ coda_dbg(1, ctx, "parameter change failed: %u\n", success);
+
+ return 0;
+}
+
static phys_addr_t coda_iram_alloc(struct coda_iram_info *iram, size_t size)
{
phys_addr_t ret;
@@ -1035,33 +1209,16 @@ static int coda_start_encoding(struct coda_ctx *ctx)
* in JPEG mode
*/
if (dst_fourcc != V4L2_PIX_FMT_JPEG) {
- switch (ctx->params.slice_mode) {
- case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE:
- value = 0;
- break;
- case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB:
- value = (ctx->params.slice_max_mb &
- CODA_SLICING_SIZE_MASK)
- << CODA_SLICING_SIZE_OFFSET;
- value |= (1 & CODA_SLICING_UNIT_MASK)
- << CODA_SLICING_UNIT_OFFSET;
- value |= 1 & CODA_SLICING_MODE_MASK;
- break;
- case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES:
- value = (ctx->params.slice_max_bits &
- CODA_SLICING_SIZE_MASK)
- << CODA_SLICING_SIZE_OFFSET;
- value |= (0 & CODA_SLICING_UNIT_MASK)
- << CODA_SLICING_UNIT_OFFSET;
- value |= 1 & CODA_SLICING_MODE_MASK;
- break;
- }
+ value = coda_slice_mode(ctx);
coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE);
value = ctx->params.gop_size;
coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE);
}
if (ctx->params.bitrate) {
+ ctx->params.bitrate_changed = false;
+ ctx->params.h264_intra_qp_changed = false;
+
/* Rate control enabled */
value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK)
<< CODA_RATECONTROL_BITRATE_OFFSET;
@@ -1198,9 +1355,9 @@ static int coda_start_encoding(struct coda_ctx *ctx)
coda9_set_frame_cache(ctx, q_data_src->fourcc);
/* FIXME */
- coda_write(dev, ctx->internal_frames[2].paddr,
+ coda_write(dev, ctx->internal_frames[2].buf.paddr,
CODA9_CMD_SET_FRAME_SUBSAMP_A);
- coda_write(dev, ctx->internal_frames[3].paddr,
+ coda_write(dev, ctx->internal_frames[3].buf.paddr,
CODA9_CMD_SET_FRAME_SUBSAMP_B);
}
}
@@ -1316,6 +1473,13 @@ static int coda_prepare_encode(struct coda_ctx *ctx)
u32 rot_mode = 0;
u32 dst_fourcc;
u32 reg;
+ int ret;
+
+ ret = coda_enc_param_change(ctx);
+ if (ret < 0) {
+ v4l2_warn(&ctx->dev->v4l2_dev, "parameter change failed: %d\n",
+ ret);
+ }
src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
@@ -1452,12 +1616,25 @@ static int coda_prepare_encode(struct coda_ctx *ctx)
return 0;
}
+static char coda_frame_type_char(u32 flags)
+{
+ return (flags & V4L2_BUF_FLAG_KEYFRAME) ? 'I' :
+ (flags & V4L2_BUF_FLAG_PFRAME) ? 'P' :
+ (flags & V4L2_BUF_FLAG_BFRAME) ? 'B' : '?';
+}
+
static void coda_finish_encode(struct coda_ctx *ctx)
{
struct vb2_v4l2_buffer *src_buf, *dst_buf;
struct coda_dev *dev = ctx->dev;
u32 wr_ptr, start_ptr;
+ /*
+ * Lock to make sure that an encoder stop command running in parallel
+ * will either already have marked src_buf as last, or it will wake up
+ * the capture queue after the buffers are returned.
+ */
+ mutex_lock(&ctx->wakeup_mutex);
src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
@@ -1483,33 +1660,30 @@ static void coda_finish_encode(struct coda_ctx *ctx)
coda_read(dev, CODA_RET_ENC_PIC_SLICE_NUM);
coda_read(dev, CODA_RET_ENC_PIC_FLAG);
- if (coda_read(dev, CODA_RET_ENC_PIC_TYPE) == 0) {
+ dst_buf->flags &= ~(V4L2_BUF_FLAG_KEYFRAME |
+ V4L2_BUF_FLAG_PFRAME |
+ V4L2_BUF_FLAG_LAST);
+ if (coda_read(dev, CODA_RET_ENC_PIC_TYPE) == 0)
dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME;
- dst_buf->flags &= ~V4L2_BUF_FLAG_PFRAME;
- } else {
+ else
dst_buf->flags |= V4L2_BUF_FLAG_PFRAME;
- dst_buf->flags &= ~V4L2_BUF_FLAG_KEYFRAME;
- }
+ dst_buf->flags |= src_buf->flags & V4L2_BUF_FLAG_LAST;
- dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp;
- dst_buf->field = src_buf->field;
- dst_buf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
- dst_buf->flags |=
- src_buf->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
- dst_buf->timecode = src_buf->timecode;
+ v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false);
v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_DONE);
+ mutex_unlock(&ctx->wakeup_mutex);
ctx->gopcounter--;
if (ctx->gopcounter < 0)
ctx->gopcounter = ctx->params.gop_size - 1;
- coda_dbg(1, ctx, "job finished: encoded %c frame (%d)\n",
- (dst_buf->flags & V4L2_BUF_FLAG_KEYFRAME) ? 'I' : 'P',
- dst_buf->sequence);
+ coda_dbg(1, ctx, "job finished: encoded %c frame (%d)%s\n",
+ coda_frame_type_char(dst_buf->flags), dst_buf->sequence,
+ (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? " (last)" : "");
}
static void coda_seq_end_work(struct work_struct *work)
@@ -1579,8 +1753,7 @@ static int coda_alloc_bitstream_buffer(struct coda_ctx *ctx,
return 0;
ctx->bitstream.size = roundup_pow_of_two(q_data->sizeimage * 2);
- ctx->bitstream.vaddr = dma_alloc_wc(&ctx->dev->plat_dev->dev,
- ctx->bitstream.size,
+ ctx->bitstream.vaddr = dma_alloc_wc(ctx->dev->dev, ctx->bitstream.size,
&ctx->bitstream.paddr, GFP_KERNEL);
if (!ctx->bitstream.vaddr) {
v4l2_err(&ctx->dev->v4l2_dev,
@@ -1598,8 +1771,8 @@ static void coda_free_bitstream_buffer(struct coda_ctx *ctx)
if (ctx->bitstream.vaddr == NULL)
return;
- dma_free_wc(&ctx->dev->plat_dev->dev, ctx->bitstream.size,
- ctx->bitstream.vaddr, ctx->bitstream.paddr);
+ dma_free_wc(ctx->dev->dev, ctx->bitstream.size, ctx->bitstream.vaddr,
+ ctx->bitstream.paddr);
ctx->bitstream.vaddr = NULL;
kfifo_init(&ctx->bitstream_fifo, NULL, 0);
}
@@ -1656,7 +1829,7 @@ static bool coda_reorder_enable(struct coda_ctx *ctx)
return profile > V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE;
}
-static int __coda_start_decoding(struct coda_ctx *ctx)
+static int __coda_decoder_seq_init(struct coda_ctx *ctx)
{
struct coda_q_data *q_data_src, *q_data_dst;
u32 bitstream_buf, bitstream_size;
@@ -1666,6 +1839,8 @@ static int __coda_start_decoding(struct coda_ctx *ctx)
u32 val;
int ret;
+ lockdep_assert_held(&dev->coda_mutex);
+
coda_dbg(1, ctx, "Video Data Order Adapter: %s\n",
ctx->use_vdoa ? "Enabled" : "Disabled");
@@ -1677,8 +1852,6 @@ static int __coda_start_decoding(struct coda_ctx *ctx)
src_fourcc = q_data_src->fourcc;
dst_fourcc = q_data_dst->fourcc;
- coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
-
/* Update coda bitstream read and write pointers from kfifo */
coda_kfifo_sync_to_device_full(ctx);
@@ -1739,6 +1912,7 @@ static int __coda_start_decoding(struct coda_ctx *ctx)
v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n");
return ret;
}
+ ctx->sequence_offset = ~0U;
ctx->initialized = 1;
/* Update kfifo out pointer from coda bitstream read pointer */
@@ -1804,6 +1978,64 @@ static int __coda_start_decoding(struct coda_ctx *ctx)
(top_bottom & 0x3ff);
}
+ if (dev->devtype->product != CODA_DX6) {
+ u8 profile, level;
+
+ val = coda_read(dev, CODA7_RET_DEC_SEQ_HEADER_REPORT);
+ profile = val & 0xff;
+ level = (val >> 8) & 0x7f;
+
+ if (profile || level)
+ coda_update_profile_level_ctrls(ctx, profile, level);
+ }
+
+ return 0;
+}
+
+static void coda_dec_seq_init_work(struct work_struct *work)
+{
+ struct coda_ctx *ctx = container_of(work,
+ struct coda_ctx, seq_init_work);
+ struct coda_dev *dev = ctx->dev;
+ int ret;
+
+ mutex_lock(&ctx->buffer_mutex);
+ mutex_lock(&dev->coda_mutex);
+
+ if (ctx->initialized == 1)
+ goto out;
+
+ ret = __coda_decoder_seq_init(ctx);
+ if (ret < 0)
+ goto out;
+
+ ctx->initialized = 1;
+
+out:
+ mutex_unlock(&dev->coda_mutex);
+ mutex_unlock(&ctx->buffer_mutex);
+}
+
+static int __coda_start_decoding(struct coda_ctx *ctx)
+{
+ struct coda_q_data *q_data_src, *q_data_dst;
+ struct coda_dev *dev = ctx->dev;
+ u32 src_fourcc, dst_fourcc;
+ int ret;
+
+ if (!ctx->initialized) {
+ ret = __coda_decoder_seq_init(ctx);
+ if (ret < 0)
+ return ret;
+ }
+
+ q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ src_fourcc = q_data_src->fourcc;
+ dst_fourcc = q_data_dst->fourcc;
+
+ coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
+
ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc);
if (ret < 0) {
v4l2_err(&dev->v4l2_dev, "failed to allocate framebuffers\n");
@@ -1812,7 +2044,8 @@ static int __coda_start_decoding(struct coda_ctx *ctx)
/* Tell the decoder how many frame buffers we allocated. */
coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM);
- coda_write(dev, width, CODA_CMD_SET_FRAME_BUF_STRIDE);
+ coda_write(dev, round_up(q_data_dst->rect.width, 16),
+ CODA_CMD_SET_FRAME_BUF_STRIDE);
if (dev->devtype->product != CODA_DX6) {
/* Set secondary AXI IRAM */
@@ -1928,7 +2161,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
ctx->display_idx < ctx->num_internal_frames) {
vdoa_device_run(ctx->vdoa,
vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0),
- ctx->internal_frames[ctx->display_idx].paddr);
+ ctx->internal_frames[ctx->display_idx].buf.paddr);
} else {
if (dev->devtype->product == CODA_960) {
/*
@@ -2026,6 +2259,7 @@ static void coda_finish_decode(struct coda_ctx *ctx)
int width, height;
int decoded_idx;
int display_idx;
+ struct coda_internal_frame *decoded_frame = NULL;
u32 src_fourcc;
int success;
u32 err_mb;
@@ -2146,12 +2380,19 @@ static void coda_finish_decode(struct coda_ctx *ctx)
else if (ctx->display_idx < 0)
ctx->hold = true;
} else if (decoded_idx == -2) {
+ if (ctx->display_idx >= 0 &&
+ ctx->display_idx < ctx->num_internal_frames)
+ ctx->sequence_offset++;
/* no frame was decoded, we still return remaining buffers */
} else if (decoded_idx < 0 || decoded_idx >= ctx->num_internal_frames) {
v4l2_err(&dev->v4l2_dev,
"decoded frame index out of range: %d\n", decoded_idx);
} else {
- val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM) - 1;
+ decoded_frame = &ctx->internal_frames[decoded_idx];
+
+ val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM);
+ if (ctx->sequence_offset == -1)
+ ctx->sequence_offset = val;
val -= ctx->sequence_offset;
spin_lock(&ctx->buffer_meta_lock);
if (!list_empty(&ctx->buffer_meta_list)) {
@@ -2173,28 +2414,26 @@ static void coda_finish_decode(struct coda_ctx *ctx)
val, ctx->sequence_offset,
meta->sequence);
}
- ctx->frame_metas[decoded_idx] = *meta;
+ decoded_frame->meta = *meta;
kfree(meta);
} else {
spin_unlock(&ctx->buffer_meta_lock);
v4l2_err(&dev->v4l2_dev, "empty timestamp list!\n");
- memset(&ctx->frame_metas[decoded_idx], 0,
+ memset(&decoded_frame->meta, 0,
sizeof(struct coda_buffer_meta));
- ctx->frame_metas[decoded_idx].sequence = val;
+ decoded_frame->meta.sequence = val;
+ decoded_frame->meta.last = false;
ctx->sequence_offset++;
}
- trace_coda_dec_pic_done(ctx, &ctx->frame_metas[decoded_idx]);
+ trace_coda_dec_pic_done(ctx, &decoded_frame->meta);
val = coda_read(dev, CODA_RET_DEC_PIC_TYPE) & 0x7;
- if (val == 0)
- ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_KEYFRAME;
- else if (val == 1)
- ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_PFRAME;
- else
- ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_BFRAME;
+ decoded_frame->type = (val == 0) ? V4L2_BUF_FLAG_KEYFRAME :
+ (val == 1) ? V4L2_BUF_FLAG_PFRAME :
+ V4L2_BUF_FLAG_BFRAME;
- ctx->frame_errors[decoded_idx] = err_mb;
+ decoded_frame->error = err_mb;
}
if (display_idx == -1) {
@@ -2214,6 +2453,10 @@ static void coda_finish_decode(struct coda_ctx *ctx)
/* If a frame was copied out, return it */
if (ctx->display_idx >= 0 &&
ctx->display_idx < ctx->num_internal_frames) {
+ struct coda_internal_frame *ready_frame;
+
+ ready_frame = &ctx->internal_frames[ctx->display_idx];
+
dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
dst_buf->sequence = ctx->osequence++;
@@ -2221,8 +2464,25 @@ static void coda_finish_decode(struct coda_ctx *ctx)
dst_buf->flags &= ~(V4L2_BUF_FLAG_KEYFRAME |
V4L2_BUF_FLAG_PFRAME |
V4L2_BUF_FLAG_BFRAME);
- dst_buf->flags |= ctx->frame_types[ctx->display_idx];
- meta = &ctx->frame_metas[ctx->display_idx];
+ dst_buf->flags |= ready_frame->type;
+ meta = &ready_frame->meta;
+ if (meta->last && !coda_reorder_enable(ctx)) {
+ /*
+ * If this was the last decoded frame, and reordering
+ * is disabled, this will be the last display frame.
+ */
+ coda_dbg(1, ctx, "last meta, marking as last frame\n");
+ dst_buf->flags |= V4L2_BUF_FLAG_LAST;
+ } else if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG &&
+ display_idx == -1) {
+ /*
+ * If there is no designated presentation frame anymore,
+ * this frame has to be the last one.
+ */
+ coda_dbg(1, ctx,
+ "no more frames to return, marking as last frame\n");
+ dst_buf->flags |= V4L2_BUF_FLAG_LAST;
+ }
dst_buf->timecode = meta->timecode;
dst_buf->vb2_buf.timestamp = meta->timestamp;
@@ -2231,18 +2491,39 @@ static void coda_finish_decode(struct coda_ctx *ctx)
vb2_set_plane_payload(&dst_buf->vb2_buf, 0,
q_data_dst->sizeimage);
- if (ctx->frame_errors[ctx->display_idx] || err_vdoa)
+ if (ready_frame->error || err_vdoa)
coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_ERROR);
else
coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_DONE);
- coda_dbg(1, ctx, "job finished: decoded %c frame (%u/%u)\n",
- (dst_buf->flags & V4L2_BUF_FLAG_KEYFRAME) ? 'I' :
- ((dst_buf->flags & V4L2_BUF_FLAG_PFRAME) ? 'P' : 'B'),
- dst_buf->sequence, ctx->qsequence);
+ if (decoded_frame) {
+ coda_dbg(1, ctx, "job finished: decoded %c frame %u, returned %c frame %u (%u/%u)%s\n",
+ coda_frame_type_char(decoded_frame->type),
+ decoded_frame->meta.sequence,
+ coda_frame_type_char(dst_buf->flags),
+ ready_frame->meta.sequence,
+ dst_buf->sequence, ctx->qsequence,
+ (dst_buf->flags & V4L2_BUF_FLAG_LAST) ?
+ " (last)" : "");
+ } else {
+ coda_dbg(1, ctx, "job finished: no frame decoded (%d), returned %c frame %u (%u/%u)%s\n",
+ decoded_idx,
+ coda_frame_type_char(dst_buf->flags),
+ ready_frame->meta.sequence,
+ dst_buf->sequence, ctx->qsequence,
+ (dst_buf->flags & V4L2_BUF_FLAG_LAST) ?
+ " (last)" : "");
+ }
} else {
- coda_dbg(1, ctx, "job finished: no frame decoded (%u/%u)\n",
- ctx->osequence, ctx->qsequence);
+ if (decoded_frame) {
+ coda_dbg(1, ctx, "job finished: decoded %c frame %u, no frame returned (%d)\n",
+ coda_frame_type_char(decoded_frame->type),
+ decoded_frame->meta.sequence,
+ ctx->display_idx);
+ } else {
+ coda_dbg(1, ctx, "job finished: no frame decoded (%d) or returned (%d)\n",
+ decoded_idx, ctx->display_idx);
+ }
}
/* The rotator will copy the current display frame next time */
@@ -2286,6 +2567,7 @@ const struct coda_context_ops coda_bit_decode_ops = {
.prepare_run = coda_prepare_decode,
.finish_run = coda_finish_decode,
.run_timeout = coda_decode_timeout,
+ .seq_init_work = coda_dec_seq_init_work,
.seq_end_work = coda_seq_end_work,
.release = coda_bit_release,
};
@@ -2297,6 +2579,7 @@ irqreturn_t coda_irq_handler(int irq, void *data)
/* read status register to attend the IRQ */
coda_read(dev, CODA_REG_BIT_INT_STATUS);
+ coda_write(dev, 0, CODA_REG_BIT_INT_REASON);
coda_write(dev, CODA_REG_BIT_INT_CLEAR_SET,
CODA_REG_BIT_INT_CLEAR);
@@ -2304,7 +2587,6 @@ irqreturn_t coda_irq_handler(int irq, void *data)
if (ctx == NULL) {
v4l2_err(&dev->v4l2_dev,
"Instance released before the end of transaction\n");
- mutex_unlock(&dev->coda_mutex);
return IRQ_HANDLED;
}
diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c
index 6238047273f2..01428de2596e 100644
--- a/drivers/media/platform/coda/coda-common.c
+++ b/drivers/media/platform/coda/coda-common.c
@@ -74,7 +74,7 @@ MODULE_PARM_DESC(enable_bwb, "Enable BWB unit for decoding, may crash on certain
void coda_write(struct coda_dev *dev, u32 data, u32 reg)
{
- v4l2_dbg(2, coda_debug, &dev->v4l2_dev,
+ v4l2_dbg(3, coda_debug, &dev->v4l2_dev,
"%s: data=0x%x, reg=0x%x\n", __func__, data, reg);
writel(data, dev->regs_base + reg);
}
@@ -84,7 +84,7 @@ unsigned int coda_read(struct coda_dev *dev, u32 reg)
u32 data;
data = readl(dev->regs_base + reg);
- v4l2_dbg(2, coda_debug, &dev->v4l2_dev,
+ v4l2_dbg(3, coda_debug, &dev->v4l2_dev,
"%s: data=0x%x, reg=0x%x\n", __func__, data, reg);
return data;
}
@@ -879,14 +879,25 @@ static int coda_qbuf(struct file *file, void *priv,
{
struct coda_ctx *ctx = fh_to_ctx(priv);
+ if (ctx->inst_type == CODA_INST_DECODER &&
+ buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ buf->flags &= ~V4L2_BUF_FLAG_LAST;
+
return v4l2_m2m_qbuf(file, ctx->fh.m2m_ctx, buf);
}
-static bool coda_buf_is_end_of_stream(struct coda_ctx *ctx,
- struct vb2_v4l2_buffer *buf)
+static int coda_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
{
- return ((ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) &&
- (buf->sequence == (ctx->qsequence - 1)));
+ struct coda_ctx *ctx = fh_to_ctx(priv);
+ int ret;
+
+ ret = v4l2_m2m_dqbuf(file, ctx->fh.m2m_ctx, buf);
+
+ if (ctx->inst_type == CODA_INST_DECODER &&
+ buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ buf->flags &= ~V4L2_BUF_FLAG_LAST;
+
+ return ret;
}
void coda_m2m_buf_done(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf,
@@ -896,11 +907,8 @@ void coda_m2m_buf_done(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf,
.type = V4L2_EVENT_EOS
};
- if (coda_buf_is_end_of_stream(ctx, buf)) {
- buf->flags |= V4L2_BUF_FLAG_LAST;
-
+ if (buf->flags & V4L2_BUF_FLAG_LAST)
v4l2_event_queue_fh(&ctx->fh, &eos_event);
- }
v4l2_m2m_buf_done(buf, state);
}
@@ -1001,36 +1009,52 @@ static int coda_try_encoder_cmd(struct file *file, void *fh,
if (ctx->inst_type != CODA_INST_ENCODER)
return -ENOTTY;
- if (ec->cmd != V4L2_ENC_CMD_STOP)
- return -EINVAL;
+ return v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec);
+}
- if (ec->flags & V4L2_ENC_CMD_STOP_AT_GOP_END)
- return -EINVAL;
+static void coda_wake_up_capture_queue(struct coda_ctx *ctx)
+{
+ struct vb2_queue *dst_vq;
- return 0;
+ coda_dbg(1, ctx, "waking up capture queue\n");
+
+ dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ dst_vq->last_buffer_dequeued = true;
+ wake_up(&dst_vq->done_wq);
}
static int coda_encoder_cmd(struct file *file, void *fh,
struct v4l2_encoder_cmd *ec)
{
struct coda_ctx *ctx = fh_to_ctx(fh);
- struct vb2_queue *dst_vq;
+ struct vb2_v4l2_buffer *buf;
int ret;
ret = coda_try_encoder_cmd(file, fh, ec);
if (ret < 0)
return ret;
- /* Set the stream-end flag on this context */
- ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
+ mutex_lock(&ctx->wakeup_mutex);
+ buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx);
+ if (buf) {
+ /*
+ * If the last output buffer is still on the queue, make sure
+ * that decoder finish_run will see the last flag and report it
+ * to userspace.
+ */
+ buf->flags |= V4L2_BUF_FLAG_LAST;
+ } else {
+ /* Set the stream-end flag on this context */
+ ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
- /* If there is no buffer in flight, wake up */
- if (!ctx->streamon_out || ctx->qsequence == ctx->osequence) {
- dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
- V4L2_BUF_TYPE_VIDEO_CAPTURE);
- dst_vq->last_buffer_dequeued = true;
- wake_up(&dst_vq->done_wq);
+ /*
+ * If the last output buffer has already been taken from the
+ * queue, wake up the capture queue and signal end of stream
+ * via the -EPIPE mechanism.
+ */
+ coda_wake_up_capture_queue(ctx);
}
+ mutex_unlock(&ctx->wakeup_mutex);
return 0;
}
@@ -1043,32 +1067,89 @@ static int coda_try_decoder_cmd(struct file *file, void *fh,
if (ctx->inst_type != CODA_INST_DECODER)
return -ENOTTY;
- if (dc->cmd != V4L2_DEC_CMD_STOP)
- return -EINVAL;
-
- if (dc->flags & V4L2_DEC_CMD_STOP_TO_BLACK)
- return -EINVAL;
-
- if (!(dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) && (dc->stop.pts != 0))
- return -EINVAL;
-
- return 0;
+ return v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc);
}
static int coda_decoder_cmd(struct file *file, void *fh,
struct v4l2_decoder_cmd *dc)
{
struct coda_ctx *ctx = fh_to_ctx(fh);
+ struct coda_dev *dev = ctx->dev;
+ struct vb2_v4l2_buffer *buf;
+ struct vb2_queue *dst_vq;
+ bool stream_end;
+ bool wakeup;
int ret;
ret = coda_try_decoder_cmd(file, fh, dc);
if (ret < 0)
return ret;
- /* Set the stream-end flag on this context */
- coda_bit_stream_end_flag(ctx);
- ctx->hold = false;
- v4l2_m2m_try_schedule(ctx->fh.m2m_ctx);
+ switch (dc->cmd) {
+ case V4L2_DEC_CMD_START:
+ mutex_lock(&ctx->bitstream_mutex);
+ mutex_lock(&dev->coda_mutex);
+ coda_bitstream_flush(ctx);
+ mutex_unlock(&dev->coda_mutex);
+ dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ vb2_clear_last_buffer_dequeued(dst_vq);
+ ctx->bit_stream_param &= ~CODA_BIT_STREAM_END_FLAG;
+ coda_fill_bitstream(ctx, NULL);
+ mutex_unlock(&ctx->bitstream_mutex);
+ break;
+ case V4L2_DEC_CMD_STOP:
+ stream_end = false;
+ wakeup = false;
+
+ buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx);
+ if (buf) {
+ coda_dbg(1, ctx, "marking last pending buffer\n");
+
+ /* Mark last buffer */
+ buf->flags |= V4L2_BUF_FLAG_LAST;
+
+ if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) == 0) {
+ coda_dbg(1, ctx, "all remaining buffers queued\n");
+ stream_end = true;
+ }
+ } else {
+ coda_dbg(1, ctx, "marking last meta\n");
+
+ /* Mark last meta */
+ spin_lock(&ctx->buffer_meta_lock);
+ if (!list_empty(&ctx->buffer_meta_list)) {
+ struct coda_buffer_meta *meta;
+
+ meta = list_last_entry(&ctx->buffer_meta_list,
+ struct coda_buffer_meta,
+ list);
+ meta->last = true;
+ stream_end = true;
+ } else {
+ wakeup = true;
+ }
+ spin_unlock(&ctx->buffer_meta_lock);
+ }
+
+ if (stream_end) {
+ coda_dbg(1, ctx, "all remaining buffers queued\n");
+
+ /* Set the stream-end flag on this context */
+ coda_bit_stream_end_flag(ctx);
+ ctx->hold = false;
+ v4l2_m2m_try_schedule(ctx->fh.m2m_ctx);
+ }
+
+ if (wakeup) {
+ /* If there is no buffer in flight, wake up */
+ coda_wake_up_capture_queue(ctx);
+ }
+
+ break;
+ default:
+ return -EINVAL;
+ }
return 0;
}
@@ -1236,6 +1317,7 @@ static int coda_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
tpf = &a->parm.output.timeperframe;
coda_approximate_timeperframe(tpf);
ctx->params.framerate = coda_timeperframe_to_frate(tpf);
+ ctx->params.framerate_changed = true;
return 0;
}
@@ -1243,9 +1325,16 @@ static int coda_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
static int coda_subscribe_event(struct v4l2_fh *fh,
const struct v4l2_event_subscription *sub)
{
+ struct coda_ctx *ctx = fh_to_ctx(fh);
+
switch (sub->type) {
case V4L2_EVENT_EOS:
return v4l2_event_subscribe(fh, sub, 0, NULL);
+ case V4L2_EVENT_SOURCE_CHANGE:
+ if (ctx->inst_type == CODA_INST_DECODER)
+ return v4l2_event_subscribe(fh, sub, 0, NULL);
+ else
+ return -EINVAL;
default:
return v4l2_ctrl_subscribe_event(fh, sub);
}
@@ -1269,7 +1358,7 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = {
.vidioc_qbuf = coda_qbuf,
.vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
- .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+ .vidioc_dqbuf = coda_dqbuf,
.vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
.vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
@@ -1325,7 +1414,7 @@ static void coda_pic_run_work(struct work_struct *work)
if (!wait_for_completion_timeout(&ctx->completion,
msecs_to_jiffies(1000))) {
- dev_err(&dev->plat_dev->dev, "CODA PIC_RUN timeout\n");
+ dev_err(dev->dev, "CODA PIC_RUN timeout\n");
ctx->hold = true;
@@ -1412,7 +1501,7 @@ static int coda_job_ready(void *m2m_priv)
return 0;
}
- coda_dbg(1, ctx, "job ready\n");
+ coda_dbg(2, ctx, "job ready\n");
return 1;
}
@@ -1563,42 +1652,81 @@ static void coda_update_menu_ctrl(struct v4l2_ctrl *ctrl, int value)
v4l2_ctrl_unlock(ctrl);
}
-static void coda_update_h264_profile_ctrl(struct coda_ctx *ctx)
+void coda_update_profile_level_ctrls(struct coda_ctx *ctx, u8 profile_idc,
+ u8 level_idc)
{
const char * const *profile_names;
+ const char * const *level_names;
+ struct v4l2_ctrl *profile_ctrl;
+ struct v4l2_ctrl *level_ctrl;
+ const char *codec_name;
+ u32 profile_cid;
+ u32 level_cid;
int profile;
+ int level;
- profile = coda_h264_profile(ctx->params.h264_profile_idc);
- if (profile < 0) {
- v4l2_warn(&ctx->dev->v4l2_dev, "Invalid H264 Profile: %u\n",
- ctx->params.h264_profile_idc);
+ switch (ctx->codec->src_fourcc) {
+ case V4L2_PIX_FMT_H264:
+ codec_name = "H264";
+ profile_cid = V4L2_CID_MPEG_VIDEO_H264_PROFILE;
+ level_cid = V4L2_CID_MPEG_VIDEO_H264_LEVEL;
+ profile_ctrl = ctx->h264_profile_ctrl;
+ level_ctrl = ctx->h264_level_ctrl;
+ profile = coda_h264_profile(profile_idc);
+ level = coda_h264_level(level_idc);
+ break;
+ case V4L2_PIX_FMT_MPEG2:
+ codec_name = "MPEG-2";
+ profile_cid = V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE;
+ level_cid = V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL;
+ profile_ctrl = ctx->mpeg2_profile_ctrl;
+ level_ctrl = ctx->mpeg2_level_ctrl;
+ profile = coda_mpeg2_profile(profile_idc);
+ level = coda_mpeg2_level(level_idc);
+ break;
+ case V4L2_PIX_FMT_MPEG4:
+ codec_name = "MPEG-4";
+ profile_cid = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE;
+ level_cid = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL;
+ profile_ctrl = ctx->mpeg4_profile_ctrl;
+ level_ctrl = ctx->mpeg4_level_ctrl;
+ profile = coda_mpeg4_profile(profile_idc);
+ level = coda_mpeg4_level(level_idc);
+ break;
+ default:
return;
}
- coda_update_menu_ctrl(ctx->h264_profile_ctrl, profile);
-
- profile_names = v4l2_ctrl_get_menu(V4L2_CID_MPEG_VIDEO_H264_PROFILE);
-
- coda_dbg(1, ctx, "Parsed H264 Profile: %s\n", profile_names[profile]);
-}
+ profile_names = v4l2_ctrl_get_menu(profile_cid);
+ level_names = v4l2_ctrl_get_menu(level_cid);
-static void coda_update_h264_level_ctrl(struct coda_ctx *ctx)
-{
- const char * const *level_names;
- int level;
+ if (profile < 0) {
+ v4l2_warn(&ctx->dev->v4l2_dev, "Invalid %s profile: %u\n",
+ codec_name, profile_idc);
+ } else {
+ coda_dbg(1, ctx, "Parsed %s profile: %s\n", codec_name,
+ profile_names[profile]);
+ coda_update_menu_ctrl(profile_ctrl, profile);
+ }
- level = coda_h264_level(ctx->params.h264_level_idc);
if (level < 0) {
- v4l2_warn(&ctx->dev->v4l2_dev, "Invalid H264 Level: %u\n",
- ctx->params.h264_level_idc);
- return;
+ v4l2_warn(&ctx->dev->v4l2_dev, "Invalid %s level: %u\n",
+ codec_name, level_idc);
+ } else {
+ coda_dbg(1, ctx, "Parsed %s level: %s\n", codec_name,
+ level_names[level]);
+ coda_update_menu_ctrl(level_ctrl, level);
}
+}
- coda_update_menu_ctrl(ctx->h264_level_ctrl, level);
-
- level_names = v4l2_ctrl_get_menu(V4L2_CID_MPEG_VIDEO_H264_LEVEL);
+static void coda_queue_source_change_event(struct coda_ctx *ctx)
+{
+ static const struct v4l2_event source_change_event = {
+ .type = V4L2_EVENT_SOURCE_CHANGE,
+ .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
+ };
- coda_dbg(1, ctx, "Parsed H264 Level: %s\n", level_names[level]);
+ v4l2_event_queue_fh(&ctx->fh, &source_change_event);
}
static void coda_buf_queue(struct vb2_buffer *vb)
@@ -1631,8 +1759,9 @@ static void coda_buf_queue(struct vb2_buffer *vb)
*/
if (!ctx->params.h264_profile_idc) {
coda_sps_parse_profile(ctx, vb);
- coda_update_h264_profile_ctrl(ctx);
- coda_update_h264_level_ctrl(ctx);
+ coda_update_profile_level_ctrls(ctx,
+ ctx->params.h264_profile_idc,
+ ctx->params.h264_level_idc);
}
}
@@ -1642,6 +1771,22 @@ static void coda_buf_queue(struct vb2_buffer *vb)
/* This set buf->sequence = ctx->qsequence++ */
coda_fill_bitstream(ctx, NULL);
mutex_unlock(&ctx->bitstream_mutex);
+
+ if (!ctx->initialized) {
+ /*
+ * Run sequence initialization in case the queued
+ * buffer contained headers.
+ */
+ if (vb2_is_streaming(vb->vb2_queue) &&
+ ctx->ops->seq_init_work) {
+ queue_work(ctx->dev->workqueue,
+ &ctx->seq_init_work);
+ flush_work(&ctx->seq_init_work);
+ }
+
+ if (ctx->initialized)
+ coda_queue_source_change_event(ctx);
+ }
} else {
if (ctx->inst_type == CODA_INST_ENCODER &&
vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
@@ -1653,7 +1798,7 @@ static void coda_buf_queue(struct vb2_buffer *vb)
int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf,
size_t size, const char *name, struct dentry *parent)
{
- buf->vaddr = dma_alloc_coherent(&dev->plat_dev->dev, size, &buf->paddr,
+ buf->vaddr = dma_alloc_coherent(dev->dev, size, &buf->paddr,
GFP_KERNEL);
if (!buf->vaddr) {
v4l2_err(&dev->v4l2_dev,
@@ -1670,7 +1815,7 @@ int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf,
buf->dentry = debugfs_create_blob(name, 0644, parent,
&buf->blob);
if (!buf->dentry)
- dev_warn(&dev->plat_dev->dev,
+ dev_warn(dev->dev,
"failed to create debugfs entry %s\n", name);
}
@@ -1681,8 +1826,7 @@ void coda_free_aux_buf(struct coda_dev *dev,
struct coda_aux_buf *buf)
{
if (buf->vaddr) {
- dma_free_coherent(&dev->plat_dev->dev, buf->size,
- buf->vaddr, buf->paddr);
+ dma_free_coherent(dev->dev, buf->size, buf->vaddr, buf->paddr);
buf->vaddr = NULL;
buf->size = 0;
debugfs_remove(buf->dentry);
@@ -1715,10 +1859,21 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
coda_fill_bitstream(ctx, &list);
mutex_unlock(&ctx->bitstream_mutex);
- if (coda_get_bitstream_payload(ctx) < 512) {
+ if (ctx->dev->devtype->product != CODA_960 &&
+ coda_get_bitstream_payload(ctx) < 512) {
+ v4l2_err(v4l2_dev, "start payload < 512\n");
ret = -EINVAL;
goto err;
}
+
+ if (!ctx->initialized) {
+ /* Run sequence initialization */
+ if (ctx->ops->seq_init_work) {
+ queue_work(ctx->dev->workqueue,
+ &ctx->seq_init_work);
+ flush_work(&ctx->seq_init_work);
+ }
+ }
}
ctx->streamon_out = 1;
@@ -1853,11 +2008,16 @@ static const struct vb2_ops coda_qops = {
static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
{
+ const char * const *val_names = v4l2_ctrl_get_menu(ctrl->id);
struct coda_ctx *ctx =
container_of(ctrl->handler, struct coda_ctx, ctrls);
- coda_dbg(1, ctx, "s_ctrl: id = 0x%x, name = \"%s\", val = %d\n",
- ctrl->id, ctrl->name, ctrl->val);
+ if (val_names)
+ coda_dbg(2, ctx, "s_ctrl: id = 0x%x, name = \"%s\", val = %d (\"%s\")\n",
+ ctrl->id, ctrl->name, ctrl->val, val_names[ctrl->val]);
+ else
+ coda_dbg(2, ctx, "s_ctrl: id = 0x%x, name = \"%s\", val = %d\n",
+ ctrl->id, ctrl->name, ctrl->val);
switch (ctrl->id) {
case V4L2_CID_HFLIP:
@@ -1874,12 +2034,14 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
break;
case V4L2_CID_MPEG_VIDEO_BITRATE:
ctx->params.bitrate = ctrl->val / 1000;
+ ctx->params.bitrate_changed = true;
break;
case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
ctx->params.gop_size = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
ctx->params.h264_intra_qp = ctrl->val;
+ ctx->params.h264_intra_qp_changed = true;
break;
case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
ctx->params.h264_inter_qp = ctrl->val;
@@ -1919,23 +2081,29 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:
ctx->params.mpeg4_inter_qp = ctrl->val;
break;
+ case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE:
+ case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL:
case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
/* nothing to do, these are fixed */
break;
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
ctx->params.slice_mode = ctrl->val;
+ ctx->params.slice_mode_changed = true;
break;
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
ctx->params.slice_max_mb = ctrl->val;
+ ctx->params.slice_mode_changed = true;
break;
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
ctx->params.slice_max_bits = ctrl->val * 8;
+ ctx->params.slice_mode_changed = true;
break;
case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
break;
case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
ctx->params.intra_refresh = ctrl->val;
+ ctx->params.intra_refresh_changed = true;
break;
case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME:
ctx->params.force_ipicture = true;
@@ -2040,7 +2208,7 @@ static void coda_encode_ctrls(struct coda_ctx *ctx)
}
v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
- V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES, 0x0,
+ V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES, 0x0,
V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE);
v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, 1, 0x3fffffff, 1, 1);
@@ -2098,6 +2266,34 @@ static void coda_decode_ctrls(struct coda_ctx *ctx)
&coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL, max, 0, max);
if (ctx->h264_level_ctrl)
ctx->h264_level_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ ctx->mpeg2_profile_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls,
+ &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE,
+ V4L2_MPEG_VIDEO_MPEG2_PROFILE_HIGH, 0,
+ V4L2_MPEG_VIDEO_MPEG2_PROFILE_HIGH);
+ if (ctx->mpeg2_profile_ctrl)
+ ctx->mpeg2_profile_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ ctx->mpeg2_level_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls,
+ &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL,
+ V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH, 0,
+ V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH);
+ if (ctx->mpeg2_level_ctrl)
+ ctx->mpeg2_level_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ ctx->mpeg4_profile_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls,
+ &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
+ V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY, 0,
+ V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY);
+ if (ctx->mpeg4_profile_ctrl)
+ ctx->mpeg4_profile_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ ctx->mpeg4_level_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls,
+ &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
+ V4L2_MPEG_VIDEO_MPEG4_LEVEL_5, 0,
+ V4L2_MPEG_VIDEO_MPEG4_LEVEL_5);
+ if (ctx->mpeg4_level_ctrl)
+ ctx->mpeg4_level_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
}
static int coda_ctrls_setup(struct coda_ctx *ctx)
@@ -2154,7 +2350,7 @@ static int coda_queue_init(struct coda_ctx *ctx, struct vb2_queue *vq)
* queues to have at least one buffer queued.
*/
vq->min_buffers_needed = 1;
- vq->dev = &ctx->dev->plat_dev->dev;
+ vq->dev = ctx->dev->dev;
return vb2_queue_init(vq);
}
@@ -2240,6 +2436,8 @@ static int coda_open(struct file *file)
ctx->use_bit = !ctx->cvd->direct;
init_completion(&ctx->completion);
INIT_WORK(&ctx->pic_run_work, coda_pic_run_work);
+ if (ctx->ops->seq_init_work)
+ INIT_WORK(&ctx->seq_init_work, ctx->ops->seq_init_work);
if (ctx->ops->seq_end_work)
INIT_WORK(&ctx->seq_end_work, ctx->ops->seq_end_work);
v4l2_fh_init(&ctx->fh, video_devdata(file));
@@ -2277,7 +2475,7 @@ static int coda_open(struct file *file)
ctx->use_vdoa = false;
/* Power up and upload firmware if necessary */
- ret = pm_runtime_get_sync(&dev->plat_dev->dev);
+ ret = pm_runtime_get_sync(dev->dev);
if (ret < 0) {
v4l2_err(&dev->v4l2_dev, "failed to power up: %d\n", ret);
goto err_pm_get;
@@ -2312,6 +2510,7 @@ static int coda_open(struct file *file)
mutex_init(&ctx->bitstream_mutex);
mutex_init(&ctx->buffer_mutex);
+ mutex_init(&ctx->wakeup_mutex);
INIT_LIST_HEAD(&ctx->buffer_meta_list);
spin_lock_init(&ctx->buffer_meta_lock);
@@ -2324,7 +2523,7 @@ err_ctx_init:
err_clk_ahb:
clk_disable_unprepare(dev->clk_per);
err_clk_per:
- pm_runtime_put_sync(&dev->plat_dev->dev);
+ pm_runtime_put_sync(dev->dev);
err_pm_get:
v4l2_fh_del(&ctx->fh);
v4l2_fh_exit(&ctx->fh);
@@ -2363,7 +2562,7 @@ static int coda_release(struct file *file)
v4l2_ctrl_handler_free(&ctx->ctrls);
clk_disable_unprepare(dev->clk_ahb);
clk_disable_unprepare(dev->clk_per);
- pm_runtime_put_sync(&dev->plat_dev->dev);
+ pm_runtime_put_sync(dev->dev);
v4l2_fh_del(&ctx->fh);
v4l2_fh_exit(&ctx->fh);
ida_free(&dev->ida, ctx->idx);
@@ -2486,9 +2685,12 @@ err_clk_per:
static int coda_register_device(struct coda_dev *dev, int i)
{
struct video_device *vfd = &dev->vfd[i];
+ enum coda_inst_type type;
+ int ret;
if (i >= dev->devtype->num_vdevs)
return -EINVAL;
+ type = dev->devtype->vdevs[i]->type;
strscpy(vfd->name, dev->devtype->vdevs[i]->name, sizeof(vfd->name));
vfd->fops = &coda_fops;
@@ -2504,7 +2706,12 @@ static int coda_register_device(struct coda_dev *dev, int i)
v4l2_disable_ioctl(vfd, VIDIOC_G_CROP);
v4l2_disable_ioctl(vfd, VIDIOC_S_CROP);
- return video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+ if (!ret)
+ v4l2_info(&dev->v4l2_dev, "%s registered as %s\n",
+ type == CODA_INST_ENCODER ? "encoder" : "decoder",
+ video_device_node_name(vfd));
+ return ret;
}
static void coda_copy_firmware(struct coda_dev *dev, const u8 * const buf,
@@ -2550,18 +2757,16 @@ static int coda_firmware_request(struct coda_dev *dev)
fw = dev->devtype->firmware[dev->firmware];
- dev_dbg(&dev->plat_dev->dev, "requesting firmware '%s' for %s\n", fw,
+ dev_dbg(dev->dev, "requesting firmware '%s' for %s\n", fw,
coda_product_name(dev->devtype->product));
- return request_firmware_nowait(THIS_MODULE, true, fw,
- &dev->plat_dev->dev, GFP_KERNEL, dev,
- coda_fw_callback);
+ return request_firmware_nowait(THIS_MODULE, true, fw, dev->dev,
+ GFP_KERNEL, dev, coda_fw_callback);
}
static void coda_fw_callback(const struct firmware *fw, void *context)
{
struct coda_dev *dev = context;
- struct platform_device *pdev = dev->plat_dev;
int i, ret;
if (!fw) {
@@ -2579,7 +2784,7 @@ static void coda_fw_callback(const struct firmware *fw, void *context)
* firmware requests, report that the fallback firmware was
* found.
*/
- dev_info(&pdev->dev, "Using fallback firmware %s\n",
+ dev_info(dev->dev, "Using fallback firmware %s\n",
dev->devtype->firmware[dev->firmware]);
}
@@ -2618,10 +2823,7 @@ static void coda_fw_callback(const struct firmware *fw, void *context)
}
}
- v4l2_info(&dev->v4l2_dev, "codec registered as /dev/video[%d-%d]\n",
- dev->vfd[0].num, dev->vfd[i - 1].num);
-
- pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_put_sync(dev->dev);
return;
rel_vfd:
@@ -2629,7 +2831,7 @@ rel_vfd:
video_unregister_device(&dev->vfd[i]);
v4l2_m2m_release(dev->m2m_dev);
put_pm:
- pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_put_sync(dev->dev);
}
enum coda_platform {
@@ -2744,7 +2946,6 @@ static int coda_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
struct gen_pool *pool;
struct coda_dev *dev;
- struct resource *res;
int ret, irq;
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
@@ -2762,7 +2963,7 @@ static int coda_probe(struct platform_device *pdev)
spin_lock_init(&dev->irqlock);
- dev->plat_dev = pdev;
+ dev->dev = &pdev->dev;
dev->clk_per = devm_clk_get(&pdev->dev, "per");
if (IS_ERR(dev->clk_per)) {
dev_err(&pdev->dev, "Could not get per clock\n");
@@ -2776,8 +2977,7 @@ static int coda_probe(struct platform_device *pdev)
}
/* Get memory for physical registers */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- dev->regs_base = devm_ioremap_resource(&pdev->dev, res);
+ dev->regs_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(dev->regs_base))
return PTR_ERR(dev->regs_base);
@@ -2790,8 +2990,8 @@ static int coda_probe(struct platform_device *pdev)
return irq;
}
- ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, coda_irq_handler,
- IRQF_ONESHOT, dev_name(&pdev->dev), dev);
+ ret = devm_request_irq(&pdev->dev, irq, coda_irq_handler, 0,
+ dev_name(&pdev->dev), dev);
if (ret < 0) {
dev_err(&pdev->dev, "failed to request irq: %d\n", ret);
return ret;
diff --git a/drivers/media/platform/coda/coda-h264.c b/drivers/media/platform/coda/coda-h264.c
index a2fa29da1d31..8bd0aa8af114 100644
--- a/drivers/media/platform/coda/coda-h264.c
+++ b/drivers/media/platform/coda/coda-h264.c
@@ -10,7 +10,8 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/videodev2.h>
-#include <coda.h>
+
+#include "coda.h"
static const u8 coda_filler_size[8] = { 0, 7, 14, 13, 12, 11, 10, 9 };
diff --git a/drivers/media/platform/coda/coda-mpeg2.c b/drivers/media/platform/coda/coda-mpeg2.c
new file mode 100644
index 000000000000..6f3f6721d286
--- /dev/null
+++ b/drivers/media/platform/coda/coda-mpeg2.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Coda multi-standard codec IP - MPEG-2 helper functions
+ *
+ * Copyright (C) 2019 Pengutronix, Philipp Zabel
+ */
+
+#include <linux/kernel.h>
+#include <linux/videodev2.h>
+#include "coda.h"
+
+int coda_mpeg2_profile(int profile_idc)
+{
+ switch (profile_idc) {
+ case 5:
+ return V4L2_MPEG_VIDEO_MPEG2_PROFILE_SIMPLE;
+ case 4:
+ return V4L2_MPEG_VIDEO_MPEG2_PROFILE_MAIN;
+ case 3:
+ return V4L2_MPEG_VIDEO_MPEG2_PROFILE_SNR_SCALABLE;
+ case 2:
+ return V4L2_MPEG_VIDEO_MPEG2_PROFILE_SPATIALLY_SCALABLE;
+ case 1:
+ return V4L2_MPEG_VIDEO_MPEG2_PROFILE_HIGH;
+ default:
+ return -EINVAL;
+ }
+}
+
+int coda_mpeg2_level(int level_idc)
+{
+ switch (level_idc) {
+ case 10:
+ return V4L2_MPEG_VIDEO_MPEG2_LEVEL_LOW;
+ case 8:
+ return V4L2_MPEG_VIDEO_MPEG2_LEVEL_MAIN;
+ case 6:
+ return V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH_1440;
+ case 4:
+ return V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH;
+ default:
+ return -EINVAL;
+ }
+}
+
+/*
+ * Check if the buffer starts with the MPEG-2 sequence header (with or without
+ * quantization matrix) and extension header, for example:
+ *
+ * 00 00 01 b3 2d 01 e0 34 08 8b a3 81
+ * 10 11 11 12 12 12 13 13 13 13 14 14 14 14 14 15
+ * 15 15 15 15 15 16 16 16 16 16 16 16 17 17 17 17
+ * 17 17 17 17 18 18 18 19 18 18 18 19 1a 1a 1a 1a
+ * 19 1b 1b 1b 1b 1b 1c 1c 1c 1c 1e 1e 1e 1f 1f 21
+ * 00 00 01 b5 14 8a 00 01 00 00
+ *
+ * or:
+ *
+ * 00 00 01 b3 08 00 40 15 ff ff e0 28
+ * 00 00 01 b5 14 8a 00 01 00 00
+ *
+ * Returns the detected header size in bytes or 0.
+ */
+u32 coda_mpeg2_parse_headers(struct coda_ctx *ctx, u8 *buf, u32 size)
+{
+ static const u8 sequence_header_start[4] = { 0x00, 0x00, 0x01, 0xb3 };
+ static const union {
+ u8 extension_start[4];
+ u8 start_code_prefix[3];
+ } u = { { 0x00, 0x00, 0x01, 0xb5 } };
+
+ if (size < 22 ||
+ memcmp(buf, sequence_header_start, 4) != 0)
+ return 0;
+
+ if ((size == 22 ||
+ (size >= 25 && memcmp(buf + 22, u.start_code_prefix, 3) == 0)) &&
+ memcmp(buf + 12, u.extension_start, 4) == 0)
+ return 22;
+
+ if ((size == 86 ||
+ (size > 89 && memcmp(buf + 86, u.start_code_prefix, 3) == 0)) &&
+ memcmp(buf + 76, u.extension_start, 4) == 0)
+ return 86;
+
+ return 0;
+}
diff --git a/drivers/media/platform/coda/coda-mpeg4.c b/drivers/media/platform/coda/coda-mpeg4.c
new file mode 100644
index 000000000000..483a4fba1b4f
--- /dev/null
+++ b/drivers/media/platform/coda/coda-mpeg4.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Coda multi-standard codec IP - MPEG-4 helper functions
+ *
+ * Copyright (C) 2019 Pengutronix, Philipp Zabel
+ */
+
+#include <linux/kernel.h>
+#include <linux/videodev2.h>
+
+#include "coda.h"
+
+int coda_mpeg4_profile(int profile_idc)
+{
+ switch (profile_idc) {
+ case 0:
+ return V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE;
+ case 15:
+ return V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE;
+ case 2:
+ return V4L2_MPEG_VIDEO_MPEG4_PROFILE_CORE;
+ case 1:
+ return V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE_SCALABLE;
+ case 11:
+ return V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY;
+ default:
+ return -EINVAL;
+ }
+}
+
+int coda_mpeg4_level(int level_idc)
+{
+ switch (level_idc) {
+ case 0:
+ return V4L2_MPEG_VIDEO_MPEG4_LEVEL_0;
+ case 1:
+ return V4L2_MPEG_VIDEO_MPEG4_LEVEL_1;
+ case 2:
+ return V4L2_MPEG_VIDEO_MPEG4_LEVEL_2;
+ case 3:
+ return V4L2_MPEG_VIDEO_MPEG4_LEVEL_3;
+ case 4:
+ return V4L2_MPEG_VIDEO_MPEG4_LEVEL_4;
+ case 5:
+ return V4L2_MPEG_VIDEO_MPEG4_LEVEL_5;
+ default:
+ return -EINVAL;
+ }
+}
+
+/*
+ * Check if the buffer starts with the MPEG-4 visual object sequence and visual
+ * object headers, for example:
+ *
+ * 00 00 01 b0 f1
+ * 00 00 01 b5 a9 13 00 00 01 00 00 00 01 20 08
+ * d4 8d 88 00 f5 04 04 08 14 30 3f
+ *
+ * Returns the detected header size in bytes or 0.
+ */
+u32 coda_mpeg4_parse_headers(struct coda_ctx *ctx, u8 *buf, u32 size)
+{
+ static const u8 vos_start[4] = { 0x00, 0x00, 0x01, 0xb0 };
+ static const union {
+ u8 vo_start[4];
+ u8 start_code_prefix[3];
+ } u = { { 0x00, 0x00, 0x01, 0xb5 } };
+
+ if (size < 30 ||
+ memcmp(buf, vos_start, 4) != 0 ||
+ memcmp(buf + 5, u.vo_start, 4) != 0)
+ return 0;
+
+ if (size == 30 ||
+ (size >= 33 && memcmp(buf + 30, u.start_code_prefix, 3) == 0))
+ return 30;
+
+ if (size == 31 ||
+ (size >= 34 && memcmp(buf + 31, u.start_code_prefix, 3) == 0))
+ return 31;
+
+ if (size == 32 ||
+ (size >= 35 && memcmp(buf + 32, u.start_code_prefix, 3) == 0))
+ return 32;
+
+ return 0;
+}
diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h
index cfcfff7838cd..848bf1da401e 100644
--- a/drivers/media/platform/coda/coda.h
+++ b/drivers/media/platform/coda/coda.h
@@ -70,7 +70,7 @@ struct coda_aux_buf {
struct coda_dev {
struct v4l2_device v4l2_dev;
struct video_device vfd[5];
- struct platform_device *plat_dev;
+ struct device *dev;
const struct coda_devtype *devtype;
int firmware;
struct vdoa_data *vdoa;
@@ -118,6 +118,8 @@ struct coda_params {
s8 h264_chroma_qp_index_offset;
u8 h264_profile_idc;
u8 h264_level_idc;
+ u8 mpeg2_profile_idc;
+ u8 mpeg2_level_idc;
u8 mpeg4_intra_qp;
u8 mpeg4_inter_qp;
u8 gop_size;
@@ -135,6 +137,12 @@ struct coda_params {
u32 slice_max_bits;
u32 slice_max_mb;
bool force_ipicture;
+ bool gop_size_changed;
+ bool bitrate_changed;
+ bool framerate_changed;
+ bool h264_intra_qp_changed;
+ bool intra_refresh_changed;
+ bool slice_mode_changed;
};
struct coda_buffer_meta {
@@ -144,6 +152,7 @@ struct coda_buffer_meta {
u64 timestamp;
unsigned int start;
unsigned int end;
+ bool last;
};
/* Per-queue, driver-specific private data */
@@ -183,14 +192,23 @@ struct coda_context_ops {
int (*prepare_run)(struct coda_ctx *ctx);
void (*finish_run)(struct coda_ctx *ctx);
void (*run_timeout)(struct coda_ctx *ctx);
+ void (*seq_init_work)(struct work_struct *work);
void (*seq_end_work)(struct work_struct *work);
void (*release)(struct coda_ctx *ctx);
};
+struct coda_internal_frame {
+ struct coda_aux_buf buf;
+ struct coda_buffer_meta meta;
+ u32 type;
+ u32 error;
+};
+
struct coda_ctx {
struct coda_dev *dev;
struct mutex buffer_mutex;
struct work_struct pic_run_work;
+ struct work_struct seq_init_work;
struct work_struct seq_end_work;
struct completion completion;
const struct coda_video_device *cvd;
@@ -213,6 +231,10 @@ struct coda_ctx {
struct v4l2_ctrl_handler ctrls;
struct v4l2_ctrl *h264_profile_ctrl;
struct v4l2_ctrl *h264_level_ctrl;
+ struct v4l2_ctrl *mpeg2_profile_ctrl;
+ struct v4l2_ctrl *mpeg2_level_ctrl;
+ struct v4l2_ctrl *mpeg4_profile_ctrl;
+ struct v4l2_ctrl *mpeg4_level_ctrl;
struct v4l2_fh fh;
int gopcounter;
int runcounter;
@@ -225,10 +247,7 @@ struct coda_ctx {
struct coda_aux_buf parabuf;
struct coda_aux_buf psbuf;
struct coda_aux_buf slicebuf;
- struct coda_aux_buf internal_frames[CODA_MAX_FRAMEBUFFERS];
- u32 frame_types[CODA_MAX_FRAMEBUFFERS];
- struct coda_buffer_meta frame_metas[CODA_MAX_FRAMEBUFFERS];
- u32 frame_errors[CODA_MAX_FRAMEBUFFERS];
+ struct coda_internal_frame internal_frames[CODA_MAX_FRAMEBUFFERS];
struct list_head buffer_meta_list;
spinlock_t buffer_meta_lock;
int num_metas;
@@ -241,11 +260,18 @@ struct coda_ctx {
u32 bit_stream_param;
u32 frm_dis_flg;
u32 frame_mem_ctrl;
+ u32 para_change;
int display_idx;
struct dentry *debugfs_entry;
bool use_bit;
bool use_vdoa;
struct vdoa_ctx *vdoa;
+ /*
+ * wakeup mutex used to serialize encoder stop command and finish_run,
+ * ensures that finish_run always either flags the last returned buffer
+ * or wakes up the capture queue to signal EOS afterwards.
+ */
+ struct mutex wakeup_mutex;
};
extern int coda_debug;
@@ -310,6 +336,7 @@ static inline bool coda_bitstream_can_fetch_past(struct coda_ctx *ctx,
}
bool coda_bitstream_can_fetch_past(struct coda_ctx *ctx, unsigned int pos);
+int coda_bitstream_flush(struct coda_ctx *ctx);
void coda_bit_stream_end_flag(struct coda_ctx *ctx);
@@ -324,6 +351,16 @@ int coda_sps_parse_profile(struct coda_ctx *ctx, struct vb2_buffer *vb);
int coda_h264_sps_fixup(struct coda_ctx *ctx, int width, int height, char *buf,
int *size, int max_size);
+int coda_mpeg2_profile(int profile_idc);
+int coda_mpeg2_level(int level_idc);
+u32 coda_mpeg2_parse_headers(struct coda_ctx *ctx, u8 *buf, u32 size);
+int coda_mpeg4_profile(int profile_idc);
+int coda_mpeg4_level(int level_idc);
+u32 coda_mpeg4_parse_headers(struct coda_ctx *ctx, u8 *buf, u32 size);
+
+void coda_update_profile_level_ctrls(struct coda_ctx *ctx, u8 profile_idc,
+ u8 level_idc);
+
bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_buffer *vb);
int coda_jpeg_write_tables(struct coda_ctx *ctx);
void coda_set_jpeg_compression_quality(struct coda_ctx *ctx, int quality);
diff --git a/drivers/media/platform/coda/coda_regs.h b/drivers/media/platform/coda/coda_regs.h
index abf8e195f6c0..b17464b56d3d 100644
--- a/drivers/media/platform/coda/coda_regs.h
+++ b/drivers/media/platform/coda/coda_regs.h
@@ -177,7 +177,7 @@
#define CODA_RET_DEC_SEQ_FRATE_DR 0x1e8
#define CODA_RET_DEC_SEQ_JPG_PARA 0x1e4
#define CODA_RET_DEC_SEQ_JPG_THUMB_IND 0x1e8
-#define CODA9_RET_DEC_SEQ_HEADER_REPORT 0x1ec
+#define CODA7_RET_DEC_SEQ_HEADER_REPORT 0x1ec
/* Decoder Picture Run */
#define CODA_CMD_DEC_PIC_ROT_MODE 0x180
@@ -342,6 +342,24 @@
#define CODA_CMD_ENC_SEQ_JPG_THUMB_SIZE 0x1a4
#define CODA_CMD_ENC_SEQ_JPG_THUMB_OFFSET 0x1a8
+/* Encoder Parameter Change */
+#define CODA_CMD_ENC_PARAM_CHANGE_ENABLE 0x180
+#define CODA_PARAM_CHANGE_RC_GOP BIT(0)
+#define CODA_PARAM_CHANGE_RC_INTRA_QP BIT(1)
+#define CODA_PARAM_CHANGE_RC_BITRATE BIT(2)
+#define CODA_PARAM_CHANGE_RC_FRAME_RATE BIT(3)
+#define CODA_PARAM_CHANGE_INTRA_MB_NUM BIT(4)
+#define CODA_PARAM_CHANGE_SLICE_MODE BIT(5)
+#define CODA_PARAM_CHANGE_HEC_MODE BIT(6)
+#define CODA_CMD_ENC_PARAM_RC_GOP 0x184
+#define CODA_CMD_ENC_PARAM_RC_INTRA_QP 0x188
+#define CODA_CMD_ENC_PARAM_RC_BITRATE 0x18c
+#define CODA_CMD_ENC_PARAM_RC_FRAME_RATE 0x190
+#define CODA_CMD_ENC_PARAM_INTRA_MB_NUM 0x194
+#define CODA_CMD_ENC_PARAM_SLICE_MODE 0x198
+#define CODA_CMD_ENC_PARAM_HEC_MODE 0x19c
+#define CODA_RET_ENC_PARAM_CHANGE_SUCCESS 0x1c0
+
/* Encoder Picture Run */
#define CODA9_CMD_ENC_PIC_SRC_INDEX 0x180
#define CODA9_CMD_ENC_PIC_SRC_STRIDE 0x184
diff --git a/drivers/media/platform/coda/trace.h b/drivers/media/platform/coda/trace.h
index a672bfc4c6ba..6cf58237fff2 100644
--- a/drivers/media/platform/coda/trace.h
+++ b/drivers/media/platform/coda/trace.h
@@ -157,7 +157,7 @@ DEFINE_EVENT(coda_buf_meta_class, coda_dec_rot_done,
#endif /* __CODA_TRACE_H__ */
#undef TRACE_INCLUDE_PATH
-#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_PATH ../../drivers/media/platform/coda
#undef TRACE_INCLUDE_FILE
#define TRACE_INCLUDE_FILE trace
diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c
index 61809d2050fa..f0f7ef638c56 100644
--- a/drivers/media/platform/davinci/vpif_capture.c
+++ b/drivers/media/platform/davinci/vpif_capture.c
@@ -1376,6 +1376,14 @@ vpif_init_free_channel_objects:
return err;
}
+static inline void free_vpif_objs(void)
+{
+ int i;
+
+ for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++)
+ kfree(vpif_obj.dev[i]);
+}
+
static int vpif_async_bound(struct v4l2_async_notifier *notifier,
struct v4l2_subdev *subdev,
struct v4l2_async_subdev *asd)
@@ -1645,7 +1653,7 @@ static __init int vpif_probe(struct platform_device *pdev)
err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev);
if (err) {
v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n");
- goto cleanup;
+ goto vpif_free;
}
while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, res_idx))) {
@@ -1692,7 +1700,9 @@ static __init int vpif_probe(struct platform_device *pdev)
"registered sub device %s\n",
subdevdata->name);
}
- vpif_probe_complete();
+ err = vpif_probe_complete();
+ if (err)
+ goto probe_subdev_out;
} else {
vpif_obj.notifier.ops = &vpif_async_ops;
err = v4l2_async_notifier_register(&vpif_obj.v4l2_dev,
@@ -1711,6 +1721,8 @@ probe_subdev_out:
kfree(vpif_obj.sd);
vpif_unregister:
v4l2_device_unregister(&vpif_obj.v4l2_dev);
+vpif_free:
+ free_vpif_objs();
cleanup:
v4l2_async_notifier_cleanup(&vpif_obj.notifier);
diff --git a/drivers/media/platform/davinci/vpss.c b/drivers/media/platform/davinci/vpss.c
index 3f079ac1b080..d38d2bbb6f0f 100644
--- a/drivers/media/platform/davinci/vpss.c
+++ b/drivers/media/platform/davinci/vpss.c
@@ -498,9 +498,9 @@ static struct platform_driver vpss_driver = {
static void vpss_exit(void)
{
+ platform_driver_unregister(&vpss_driver);
iounmap(oper_cfg.vpss_regs_base2);
release_mem_region(VPSS_CLK_CTRL, 4);
- platform_driver_unregister(&vpss_driver);
}
static int __init vpss_init(void)
@@ -509,6 +509,11 @@ static int __init vpss_init(void)
return -EBUSY;
oper_cfg.vpss_regs_base2 = ioremap(VPSS_CLK_CTRL, 4);
+ if (unlikely(!oper_cfg.vpss_regs_base2)) {
+ release_mem_region(VPSS_CLK_CTRL, 4);
+ return -ENOMEM;
+ }
+
writel(VPSS_CLK_CTRL_VENCCLKEN |
VPSS_CLK_CTRL_DACCLKEN, oper_cfg.vpss_regs_base2);
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c
index ea46d7387221..854869f0024e 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/exynos-gsc/gsc-core.c
@@ -327,7 +327,7 @@ void gsc_check_src_scale_info(struct gsc_variant *var,
}
}
-int gsc_enum_fmt_mplane(struct v4l2_fmtdesc *f)
+int gsc_enum_fmt(struct v4l2_fmtdesc *f)
{
const struct gsc_fmt *fmt;
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.h b/drivers/media/platform/exynos-gsc/gsc-core.h
index c81f0a17d286..772183b090c2 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.h
+++ b/drivers/media/platform/exynos-gsc/gsc-core.h
@@ -1,12 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* header file for Samsung EXYNOS5 SoC series G-Scaler driver
- * 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.
*/
#ifndef GSC_CORE_H_
@@ -387,7 +385,7 @@ void gsc_m2m_job_finish(struct gsc_ctx *ctx, int vb_state);
u32 get_plane_size(struct gsc_frame *fr, unsigned int plane);
const struct gsc_fmt *get_format(int index);
const struct gsc_fmt *find_fmt(u32 *pixelformat, u32 *mbus_code, u32 index);
-int gsc_enum_fmt_mplane(struct v4l2_fmtdesc *f);
+int gsc_enum_fmt(struct v4l2_fmtdesc *f);
int gsc_try_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f);
void gsc_set_frame_size(struct gsc_frame *frame, int width, int height);
int gsc_g_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f);
diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c
index 677d7cc80785..35a1d0d6dd66 100644
--- a/drivers/media/platform/exynos-gsc/gsc-m2m.c
+++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c
@@ -294,15 +294,13 @@ static int gsc_m2m_querycap(struct file *file, void *fh,
strscpy(cap->card, GSC_MODULE_NAME " gscaler", sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
dev_name(&gsc->pdev->dev));
- cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
-static int gsc_m2m_enum_fmt_mplane(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
+static int gsc_m2m_enum_fmt(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
{
- return gsc_enum_fmt_mplane(f);
+ return gsc_enum_fmt(f);
}
static int gsc_m2m_g_fmt_mplane(struct file *file, void *fh,
@@ -558,8 +556,8 @@ static int gsc_m2m_s_selection(struct file *file, void *fh,
static const struct v4l2_ioctl_ops gsc_m2m_ioctl_ops = {
.vidioc_querycap = gsc_m2m_querycap,
- .vidioc_enum_fmt_vid_cap_mplane = gsc_m2m_enum_fmt_mplane,
- .vidioc_enum_fmt_vid_out_mplane = gsc_m2m_enum_fmt_mplane,
+ .vidioc_enum_fmt_vid_cap = gsc_m2m_enum_fmt,
+ .vidioc_enum_fmt_vid_out = gsc_m2m_enum_fmt,
.vidioc_g_fmt_vid_cap_mplane = gsc_m2m_g_fmt_mplane,
.vidioc_g_fmt_vid_out_mplane = gsc_m2m_g_fmt_mplane,
.vidioc_try_fmt_vid_cap_mplane = gsc_m2m_try_fmt_mplane,
@@ -759,6 +757,8 @@ int gsc_register_m2m_device(struct gsc_dev *gsc)
gsc->vdev.lock = &gsc->lock;
gsc->vdev.vfl_dir = VFL_DIR_M2M;
gsc->vdev.v4l2_dev = &gsc->v4l2_dev;
+ gsc->vdev.device_caps = V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_M2M_MPLANE;
snprintf(gsc->vdev.name, sizeof(gsc->vdev.name), "%s.%d:m2m",
GSC_MODULE_NAME, gsc->id);
diff --git a/drivers/media/platform/exynos-gsc/gsc-regs.h b/drivers/media/platform/exynos-gsc/gsc-regs.h
index 4678f9a6a4fd..d4f7ead6b322 100644
--- a/drivers/media/platform/exynos-gsc/gsc-regs.h
+++ b/drivers/media/platform/exynos-gsc/gsc-regs.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Register definition file for Samsung G-Scaler driver
- *
- * 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.
*/
#ifndef REGS_GSC_H_
diff --git a/drivers/media/platform/exynos4-is/common.c b/drivers/media/platform/exynos4-is/common.c
index 76f557548dfc..944b224eb621 100644
--- a/drivers/media/platform/exynos4-is/common.c
+++ b/drivers/media/platform/exynos4-is/common.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Samsung S5P/EXYNOS4 SoC Camera Subsystem driver
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
- *
- * 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.
*/
#include <linux/module.h>
@@ -37,15 +34,12 @@ struct v4l2_subdev *fimc_find_remote_sensor(struct media_entity *entity)
}
EXPORT_SYMBOL(fimc_find_remote_sensor);
-void __fimc_vidioc_querycap(struct device *dev, struct v4l2_capability *cap,
- unsigned int caps)
+void __fimc_vidioc_querycap(struct device *dev, struct v4l2_capability *cap)
{
strscpy(cap->driver, dev->driver->name, sizeof(cap->driver));
strscpy(cap->card, dev->driver->name, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info),
"platform:%s", dev_name(dev));
- cap->device_caps = caps;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
}
EXPORT_SYMBOL(__fimc_vidioc_querycap);
diff --git a/drivers/media/platform/exynos4-is/common.h b/drivers/media/platform/exynos4-is/common.h
index 75b9c71d9419..0389b66e5144 100644
--- a/drivers/media/platform/exynos4-is/common.h
+++ b/drivers/media/platform/exynos4-is/common.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
- *
- * 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.
*/
#include <linux/device.h>
@@ -12,5 +9,4 @@
#include <media/v4l2-subdev.h>
struct v4l2_subdev *fimc_find_remote_sensor(struct media_entity *entity);
-void __fimc_vidioc_querycap(struct device *dev, struct v4l2_capability *cap,
- unsigned int caps);
+void __fimc_vidioc_querycap(struct device *dev, struct v4l2_capability *cap);
diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c
index de4af0357a3c..66510365dd5d 100644
--- a/drivers/media/platform/exynos4-is/fimc-capture.c
+++ b/drivers/media/platform/exynos4-is/fimc-capture.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Samsung S5P/EXYNOS4 SoC series camera interface (camera capture) driver
*
* Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd.
* Sylwester Nawrocki <s.nawrocki@samsung.com>
- *
- * 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.
*/
#include <linux/module.h>
@@ -728,13 +725,12 @@ static int fimc_cap_querycap(struct file *file, void *priv,
{
struct fimc_dev *fimc = video_drvdata(file);
- __fimc_vidioc_querycap(&fimc->pdev->dev, cap, V4L2_CAP_STREAMING |
- V4L2_CAP_VIDEO_CAPTURE_MPLANE);
+ __fimc_vidioc_querycap(&fimc->pdev->dev, cap);
return 0;
}
-static int fimc_cap_enum_fmt_mplane(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
+static int fimc_cap_enum_fmt(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
{
struct fimc_fmt *fmt;
@@ -1361,7 +1357,7 @@ static int fimc_cap_s_selection(struct file *file, void *fh,
static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = {
.vidioc_querycap = fimc_cap_querycap,
- .vidioc_enum_fmt_vid_cap_mplane = fimc_cap_enum_fmt_mplane,
+ .vidioc_enum_fmt_vid_cap = fimc_cap_enum_fmt,
.vidioc_try_fmt_vid_cap_mplane = fimc_cap_try_fmt_mplane,
.vidioc_s_fmt_vid_cap_mplane = fimc_cap_s_fmt_mplane,
.vidioc_g_fmt_vid_cap_mplane = fimc_cap_g_fmt_mplane,
@@ -1765,6 +1761,7 @@ static int fimc_register_capture_device(struct fimc_dev *fimc,
vfd->release = video_device_release_empty;
vfd->queue = q;
vfd->lock = &fimc->lock;
+ vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE_MPLANE;
video_set_drvdata(vfd, fimc);
vid_cap = &fimc->vid_cap;
diff --git a/drivers/media/platform/exynos4-is/fimc-core.h b/drivers/media/platform/exynos4-is/fimc-core.h
index 9f751a5efd64..d130f664a60b 100644
--- a/drivers/media/platform/exynos4-is/fimc-core.h
+++ b/drivers/media/platform/exynos4-is/fimc-core.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd.
- *
- * 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.
*/
#ifndef FIMC_CORE_H_
diff --git a/drivers/media/platform/exynos4-is/fimc-is-command.h b/drivers/media/platform/exynos4-is/fimc-is-command.h
index b06b56b890d5..87978609ad55 100644
--- a/drivers/media/platform/exynos4-is/fimc-is-command.h
+++ b/drivers/media/platform/exynos4-is/fimc-is-command.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Samsung Exynos4x12 FIMC-IS (Imaging Subsystem) driver
*
@@ -7,10 +8,6 @@
*
* Authors: Younghwan Joo <yhwan.joo@samsung.com>
* Sylwester Nawrocki <s.nawrocki@samsung.com>
- *
- * 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.
*/
#ifndef FIMC_IS_CMD_H_
diff --git a/drivers/media/platform/exynos4-is/fimc-is-errno.c b/drivers/media/platform/exynos4-is/fimc-is-errno.c
index bbb08576492e..5d9f4c1cdc5e 100644
--- a/drivers/media/platform/exynos4-is/fimc-is-errno.c
+++ b/drivers/media/platform/exynos4-is/fimc-is-errno.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Samsung Exynos4 SoC series FIMC-IS slave interface driver
*
@@ -7,10 +8,6 @@
*
* Authors: Younghwan Joo <yhwan.joo@samsung.com>
* Sylwester Nawrocki <s.nawrocki@samsung.com>
- *
- * 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.
*/
#include "fimc-is-errno.h"
diff --git a/drivers/media/platform/exynos4-is/fimc-is-errno.h b/drivers/media/platform/exynos4-is/fimc-is-errno.h
index 77f4fc860be5..da36b48b8f9f 100644
--- a/drivers/media/platform/exynos4-is/fimc-is-errno.h
+++ b/drivers/media/platform/exynos4-is/fimc-is-errno.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Samsung Exynos4 SoC series FIMC-IS slave interface driver
*
@@ -7,10 +8,6 @@
*
* Authors: Younghwan Joo <yhwan.joo@samsung.com>
* Sylwester Nawrocki <s.nawrocki@samsung.com>
- *
- * 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.
*/
#ifndef FIMC_IS_ERR_H_
diff --git a/drivers/media/platform/exynos4-is/fimc-is-i2c.c b/drivers/media/platform/exynos4-is/fimc-is-i2c.c
index be937caf7645..83a28ef8e099 100644
--- a/drivers/media/platform/exynos4-is/fimc-is-i2c.c
+++ b/drivers/media/platform/exynos4-is/fimc-is-i2c.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
*
* Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/media/platform/exynos4-is/fimc-is-i2c.h b/drivers/media/platform/exynos4-is/fimc-is-i2c.h
index 0d38d6bb963b..a23bd20be6c8 100644
--- a/drivers/media/platform/exynos4-is/fimc-is-i2c.h
+++ b/drivers/media/platform/exynos4-is/fimc-is-i2c.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* Sylwester Nawrocki <s.nawrocki@samsung.com>
- *
- * 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.
*/
#define FIMC_IS_I2C_COMPATIBLE "samsung,exynos4212-i2c-isp"
diff --git a/drivers/media/platform/exynos4-is/fimc-is-param.c b/drivers/media/platform/exynos4-is/fimc-is-param.c
index 72b9b436c5c0..9c816ae3b3e5 100644
--- a/drivers/media/platform/exynos4-is/fimc-is-param.c
+++ b/drivers/media/platform/exynos4-is/fimc-is-param.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
*
@@ -5,10 +6,6 @@
*
* Authors: Younghwan Joo <yhwan.joo@samsung.com>
* Sylwester Nawrocki <s.nawrocki@samsung.com>
- *
- * 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.
*/
#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
diff --git a/drivers/media/platform/exynos4-is/fimc-is-param.h b/drivers/media/platform/exynos4-is/fimc-is-param.h
index 22923a3d405e..206904674927 100644
--- a/drivers/media/platform/exynos4-is/fimc-is-param.h
+++ b/drivers/media/platform/exynos4-is/fimc-is-param.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
*
@@ -5,10 +6,6 @@
*
* Authors: Younghwan Joo <yhwan.joo@samsung.com>
* Sylwester Nawrocki <s.nawrocki@samsung.com>
- *
- * 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.
*/
#ifndef FIMC_IS_PARAM_H_
#define FIMC_IS_PARAM_H_
diff --git a/drivers/media/platform/exynos4-is/fimc-is-regs.c b/drivers/media/platform/exynos4-is/fimc-is-regs.c
index e0e291066037..366e6393817d 100644
--- a/drivers/media/platform/exynos4-is/fimc-is-regs.c
+++ b/drivers/media/platform/exynos4-is/fimc-is-regs.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
*
@@ -5,10 +6,6 @@
*
* Authors: Younghwan Joo <yhwan.joo@samsung.com>
* Sylwester Nawrocki <s.nawrocki@samsung.com>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/media/platform/exynos4-is/fimc-is-regs.h b/drivers/media/platform/exynos4-is/fimc-is-regs.h
index 141e5ddadbeb..5d8b01bc84a2 100644
--- a/drivers/media/platform/exynos4-is/fimc-is-regs.h
+++ b/drivers/media/platform/exynos4-is/fimc-is-regs.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
*
@@ -5,10 +6,6 @@
*
* Authors: Sylwester Nawrocki <s.nawrocki@samsung.com>
* Younghwan Joo <yhwan.joo@samsung.com>
- *
- * 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.
*/
#ifndef FIMC_IS_REG_H_
#define FIMC_IS_REG_H_
diff --git a/drivers/media/platform/exynos4-is/fimc-is-sensor.c b/drivers/media/platform/exynos4-is/fimc-is-sensor.c
index 10e82e21b5d1..0e5b9fede4ae 100644
--- a/drivers/media/platform/exynos4-is/fimc-is-sensor.c
+++ b/drivers/media/platform/exynos4-is/fimc-is-sensor.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
- *
- * 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.
*/
#include "fimc-is-sensor.h"
diff --git a/drivers/media/platform/exynos4-is/fimc-is-sensor.h b/drivers/media/platform/exynos4-is/fimc-is-sensor.h
index 173ccffa4bcd..9aefc63889de 100644
--- a/drivers/media/platform/exynos4-is/fimc-is-sensor.h
+++ b/drivers/media/platform/exynos4-is/fimc-is-sensor.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
*
@@ -5,10 +6,6 @@
*
* Authors: Sylwester Nawrocki <s.nawrocki@samsung.com>
* Younghwan Joo <yhwan.joo@samsung.com>
- *
- * 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.
*/
#ifndef FIMC_IS_SENSOR_H_
#define FIMC_IS_SENSOR_H_
diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c
index 02da0b06e56a..e043d55133a3 100644
--- a/drivers/media/platform/exynos4-is/fimc-is.c
+++ b/drivers/media/platform/exynos4-is/fimc-is.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
*
@@ -5,10 +6,6 @@
*
* Authors: Sylwester Nawrocki <s.nawrocki@samsung.com>
* Younghwan Joo <yhwan.joo@samsung.com>
- *
- * 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.
*/
#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
diff --git a/drivers/media/platform/exynos4-is/fimc-is.h b/drivers/media/platform/exynos4-is/fimc-is.h
index ee05da034aa1..7ee96a058d40 100644
--- a/drivers/media/platform/exynos4-is/fimc-is.h
+++ b/drivers/media/platform/exynos4-is/fimc-is.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
*
@@ -5,10 +6,6 @@
*
* Authors: Younghwan Joo <yhwan.joo@samsung.com>
* Sylwester Nawrocki <s.nawrocki@samsung.com>
- *
- * 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.
*/
#ifndef FIMC_IS_H_
#define FIMC_IS_H_
diff --git a/drivers/media/platform/exynos4-is/fimc-isp-video.c b/drivers/media/platform/exynos4-is/fimc-isp-video.c
index bb35a2017f21..a75f932a289a 100644
--- a/drivers/media/platform/exynos4-is/fimc-isp-video.c
+++ b/drivers/media/platform/exynos4-is/fimc-isp-video.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
*
@@ -8,10 +9,6 @@
*
* The hardware handling code derived from a driver written by
* Younghwan Joo <yhwan.joo@samsung.com>.
- *
- * 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.
*/
#include <linux/bitops.h>
@@ -349,12 +346,12 @@ static int isp_video_querycap(struct file *file, void *priv,
{
struct fimc_isp *isp = video_drvdata(file);
- __fimc_vidioc_querycap(&isp->pdev->dev, cap, V4L2_CAP_STREAMING);
+ __fimc_vidioc_querycap(&isp->pdev->dev, cap);
return 0;
}
-static int isp_video_enum_fmt_mplane(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
+static int isp_video_enum_fmt(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
{
const struct fimc_fmt *fmt;
@@ -551,7 +548,7 @@ static int isp_video_reqbufs(struct file *file, void *priv,
static const struct v4l2_ioctl_ops isp_video_ioctl_ops = {
.vidioc_querycap = isp_video_querycap,
- .vidioc_enum_fmt_vid_cap_mplane = isp_video_enum_fmt_mplane,
+ .vidioc_enum_fmt_vid_cap = isp_video_enum_fmt,
.vidioc_try_fmt_vid_cap_mplane = isp_video_try_fmt_mplane,
.vidioc_s_fmt_vid_cap_mplane = isp_video_s_fmt_mplane,
.vidioc_g_fmt_vid_cap_mplane = isp_video_g_fmt_mplane,
@@ -614,6 +611,7 @@ int fimc_isp_video_device_register(struct fimc_isp *isp,
vdev->minor = -1;
vdev->release = video_device_release_empty;
vdev->lock = &isp->video_lock;
+ vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE_MPLANE;
iv->pad.flags = MEDIA_PAD_FL_SINK;
ret = media_entity_pads_init(&vdev->entity, 1, &iv->pad);
diff --git a/drivers/media/platform/exynos4-is/fimc-isp-video.h b/drivers/media/platform/exynos4-is/fimc-isp-video.h
index f79a1b348aa6..edcb3a5e3cb9 100644
--- a/drivers/media/platform/exynos4-is/fimc-isp-video.h
+++ b/drivers/media/platform/exynos4-is/fimc-isp-video.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* Sylwester Nawrocki <s.nawrocki@samsung.com>
- *
- * 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.
*/
#ifndef FIMC_ISP_VIDEO__
#define FIMC_ISP_VIDEO__
diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c
index 9a48c0f69320..907b83e6649d 100644
--- a/drivers/media/platform/exynos4-is/fimc-isp.c
+++ b/drivers/media/platform/exynos4-is/fimc-isp.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
*
@@ -5,10 +6,6 @@
*
* Authors: Sylwester Nawrocki <s.nawrocki@samsung.com>
* Younghwan Joo <yhwan.joo@samsung.com>
- *
- * 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.
*/
#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
diff --git a/drivers/media/platform/exynos4-is/fimc-isp.h b/drivers/media/platform/exynos4-is/fimc-isp.h
index 3cdd52491294..161fa01a8781 100644
--- a/drivers/media/platform/exynos4-is/fimc-isp.h
+++ b/drivers/media/platform/exynos4-is/fimc-isp.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
*
@@ -5,10 +6,6 @@
*
* Authors: Sylwester Nawrocki <s.nawrocki@samsung.com>
* Younghwan Joo <yhwan.joo@samsung.com>
- *
- * 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.
*/
#ifndef FIMC_ISP_H_
#define FIMC_ISP_H_
diff --git a/drivers/media/platform/exynos4-is/fimc-lite-reg.c b/drivers/media/platform/exynos4-is/fimc-lite-reg.c
index 16565a0b4bf1..85f765e0f4e1 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite-reg.c
+++ b/drivers/media/platform/exynos4-is/fimc-lite-reg.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Register interface file for EXYNOS FIMC-LITE (camera interface) driver
*
* Copyright (C) 2012 Samsung Electronics Co., Ltd.
* Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
- *
- * 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.
*/
#include <linux/bitops.h>
diff --git a/drivers/media/platform/exynos4-is/fimc-lite-reg.h b/drivers/media/platform/exynos4-is/fimc-lite-reg.h
index 10a7d7bbcc27..48f2cf1148b8 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite-reg.h
+++ b/drivers/media/platform/exynos4-is/fimc-lite-reg.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2012 Samsung Electronics Co., Ltd.
- *
- * 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.
*/
#ifndef FIMC_LITE_REG_H_
diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c
index 96f0a8a0dcae..c1f0aee02e5e 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite.c
+++ b/drivers/media/platform/exynos4-is/fimc-lite.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Samsung EXYNOS FIMC-LITE (camera host interface) driver
*
* Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd.
* Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
- *
- * 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.
*/
#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
@@ -658,14 +655,11 @@ static int fimc_lite_querycap(struct file *file, void *priv,
strscpy(cap->card, FIMC_LITE_DRV_NAME, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
dev_name(&fimc->pdev->dev));
-
- cap->device_caps = V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
-static int fimc_lite_enum_fmt_mplane(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
+static int fimc_lite_enum_fmt(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
{
const struct fimc_fmt *fmt;
@@ -954,7 +948,7 @@ static int fimc_lite_s_selection(struct file *file, void *fh,
static const struct v4l2_ioctl_ops fimc_lite_ioctl_ops = {
.vidioc_querycap = fimc_lite_querycap,
- .vidioc_enum_fmt_vid_cap_mplane = fimc_lite_enum_fmt_mplane,
+ .vidioc_enum_fmt_vid_cap = fimc_lite_enum_fmt,
.vidioc_try_fmt_vid_cap_mplane = fimc_lite_try_fmt_mplane,
.vidioc_s_fmt_vid_cap_mplane = fimc_lite_s_fmt_mplane,
.vidioc_g_fmt_vid_cap_mplane = fimc_lite_g_fmt_mplane,
@@ -1282,6 +1276,7 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd)
vfd->minor = -1;
vfd->release = video_device_release_empty;
vfd->queue = q;
+ vfd->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING;
fimc->reqbufs_count = 0;
INIT_LIST_HEAD(&fimc->pending_buf_q);
diff --git a/drivers/media/platform/exynos4-is/fimc-lite.h b/drivers/media/platform/exynos4-is/fimc-lite.h
index 3e238b8c834a..e6846c5fc9ac 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite.h
+++ b/drivers/media/platform/exynos4-is/fimc-lite.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2012 Samsung Electronics Co., Ltd.
- *
- * 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.
*/
#ifndef FIMC_LITE_H_
diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c
index b950c152fa28..62e876fc3555 100644
--- a/drivers/media/platform/exynos4-is/fimc-m2m.c
+++ b/drivers/media/platform/exynos4-is/fimc-m2m.c
@@ -232,14 +232,13 @@ static int fimc_m2m_querycap(struct file *file, void *fh,
struct v4l2_capability *cap)
{
struct fimc_dev *fimc = video_drvdata(file);
- unsigned int caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
- __fimc_vidioc_querycap(&fimc->pdev->dev, cap, caps);
+ __fimc_vidioc_querycap(&fimc->pdev->dev, cap);
return 0;
}
-static int fimc_m2m_enum_fmt_mplane(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
+static int fimc_m2m_enum_fmt(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
{
struct fimc_fmt *fmt;
@@ -529,8 +528,8 @@ static int fimc_m2m_s_selection(struct file *file, void *fh,
static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = {
.vidioc_querycap = fimc_m2m_querycap,
- .vidioc_enum_fmt_vid_cap_mplane = fimc_m2m_enum_fmt_mplane,
- .vidioc_enum_fmt_vid_out_mplane = fimc_m2m_enum_fmt_mplane,
+ .vidioc_enum_fmt_vid_cap = fimc_m2m_enum_fmt,
+ .vidioc_enum_fmt_vid_out = fimc_m2m_enum_fmt,
.vidioc_g_fmt_vid_cap_mplane = fimc_m2m_g_fmt_mplane,
.vidioc_g_fmt_vid_out_mplane = fimc_m2m_g_fmt_mplane,
.vidioc_try_fmt_vid_cap_mplane = fimc_m2m_try_fmt_mplane,
@@ -732,6 +731,7 @@ int fimc_register_m2m_device(struct fimc_dev *fimc,
vfd->release = video_device_release_empty;
vfd->lock = &fimc->lock;
vfd->vfl_dir = VFL_DIR_M2M;
+ vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
set_bit(V4L2_FL_QUIRK_INVERTED_CROP, &vfd->flags);
snprintf(vfd->name, sizeof(vfd->name), "fimc.%d.m2m", fimc->id);
diff --git a/drivers/media/platform/exynos4-is/fimc-reg.c b/drivers/media/platform/exynos4-is/fimc-reg.c
index 0806724553a2..5ce2bdebd424 100644
--- a/drivers/media/platform/exynos4-is/fimc-reg.c
+++ b/drivers/media/platform/exynos4-is/fimc-reg.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Register interface file for Samsung Camera Interface (FIMC) driver
*
* Copyright (C) 2010 - 2013 Samsung Electronics Co., Ltd.
* Sylwester Nawrocki <s.nawrocki@samsung.com>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/media/platform/exynos4-is/fimc-reg.h b/drivers/media/platform/exynos4-is/fimc-reg.h
index 6c97798c75a5..03ba6c2bc84b 100644
--- a/drivers/media/platform/exynos4-is/fimc-reg.h
+++ b/drivers/media/platform/exynos4-is/fimc-reg.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Samsung camera host interface (FIMC) registers definition
*
* Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd.
- *
- * 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.
*/
#ifndef FIMC_REG_H_
diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c
index 1b83a6ec745f..d53427a8db11 100644
--- a/drivers/media/platform/exynos4-is/media-dev.c
+++ b/drivers/media/platform/exynos4-is/media-dev.c
@@ -445,6 +445,7 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd,
pd->fimc_bus_type = FIMC_BUS_TYPE_ISP_WRITEBACK;
else
pd->fimc_bus_type = pd->sensor_bus_type;
+ of_node_put(np);
if (WARN_ON(index >= ARRAY_SIZE(fmd->sensor))) {
of_node_put(rem);
@@ -470,7 +471,8 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd,
static int fimc_md_register_sensor_entities(struct fimc_md *fmd)
{
struct device_node *parent = fmd->pdev->dev.of_node;
- struct device_node *node, *ports;
+ struct device_node *ports = NULL;
+ struct device_node *node;
int index = 0;
int ret;
@@ -519,12 +521,14 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd)
}
index++;
}
+ of_node_put(ports);
rpm_put:
pm_runtime_put(fmd->pmf);
return 0;
cleanup:
+ of_node_put(ports);
v4l2_async_notifier_cleanup(&fmd->subdev_notifier);
pm_runtime_put(fmd->pmf);
return ret;
diff --git a/drivers/media/platform/exynos4-is/media-dev.h b/drivers/media/platform/exynos4-is/media-dev.h
index a7c9490bbcb4..4b8f9ac52ebc 100644
--- a/drivers/media/platform/exynos4-is/media-dev.h
+++ b/drivers/media/platform/exynos4-is/media-dev.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd.
- *
- * 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.
*/
#ifndef FIMC_MDEVICE_H_
diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c
index 234e047e3e8f..3e9ac6066cf6 100644
--- a/drivers/media/platform/exynos4-is/mipi-csis.c
+++ b/drivers/media/platform/exynos4-is/mipi-csis.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Samsung S5P/EXYNOS SoC series MIPI-CSI receiver driver
*
* Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd.
* Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/media/platform/exynos4-is/mipi-csis.h b/drivers/media/platform/exynos4-is/mipi-csis.h
index 28c11c4085d8..193f253c7907 100644
--- a/drivers/media/platform/exynos4-is/mipi-csis.h
+++ b/drivers/media/platform/exynos4-is/mipi-csis.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver
*
* Copyright (C) 2011 Samsung Electronics Co., Ltd.
- *
- * 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.
*/
#ifndef S5P_MIPI_CSIS_H_
#define S5P_MIPI_CSIS_H_
diff --git a/drivers/media/platform/marvell-ccic/Kconfig b/drivers/media/platform/marvell-ccic/Kconfig
index 86b84474dd8c..3e3f86264762 100644
--- a/drivers/media/platform/marvell-ccic/Kconfig
+++ b/drivers/media/platform/marvell-ccic/Kconfig
@@ -2,6 +2,7 @@
config VIDEO_CAFE_CCIC
tristate "Marvell 88ALP01 (Cafe) CMOS Camera Controller support"
depends on PCI && I2C && VIDEO_V4L2
+ depends on COMMON_CLK
select VIDEO_OV7670
select VIDEOBUF2_VMALLOC
select VIDEOBUF2_DMA_CONTIG
@@ -15,6 +16,7 @@ config VIDEO_MMP_CAMERA
tristate "Marvell Armada 610 integrated camera controller support"
depends on I2C && VIDEO_V4L2
depends on ARCH_MMP || COMPILE_TEST
+ depends on COMMON_CLK
select VIDEO_OV7670
select I2C_GPIO
select VIDEOBUF2_VMALLOC
diff --git a/drivers/media/platform/marvell-ccic/cafe-driver.c b/drivers/media/platform/marvell-ccic/cafe-driver.c
index cd108b14b715..37fdcc53a1c4 100644
--- a/drivers/media/platform/marvell-ccic/cafe-driver.c
+++ b/drivers/media/platform/marvell-ccic/cafe-driver.c
@@ -9,6 +9,7 @@
*
* Copyright 2006-11 One Laptop Per Child Association, Inc.
* Copyright 2006-11 Jonathan Corbet <corbet@lwn.net>
+ * Copyright 2018 Lubomir Rintel <lkundrak@v3.sk>
*
* Written by Jonathan Corbet, corbet@lwn.net.
*
@@ -25,10 +26,12 @@
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
+#include <media/i2c/ov7670.h>
#include <linux/device.h>
#include <linux/wait.h>
#include <linux/delay.h>
#include <linux/io.h>
+#include <linux/clkdev.h>
#include "mcam-core.h"
@@ -50,6 +53,7 @@ struct cafe_camera {
int registered; /* Fully initialized? */
struct mcam_camera mcam;
struct pci_dev *pdev;
+ struct i2c_adapter *i2c_adapter;
wait_queue_head_t smbus_wait; /* Waiting on i2c events */
};
@@ -349,15 +353,15 @@ static int cafe_smbus_setup(struct cafe_camera *cam)
return ret;
}
- cam->mcam.i2c_adapter = adap;
+ cam->i2c_adapter = adap;
cafe_smbus_enable_irq(cam);
return 0;
}
static void cafe_smbus_shutdown(struct cafe_camera *cam)
{
- i2c_del_adapter(cam->mcam.i2c_adapter);
- kfree(cam->mcam.i2c_adapter);
+ i2c_del_adapter(cam->i2c_adapter);
+ kfree(cam->i2c_adapter);
}
@@ -450,6 +454,29 @@ static irqreturn_t cafe_irq(int irq, void *data)
return IRQ_RETVAL(handled);
}
+/* -------------------------------------------------------------------------- */
+
+static struct ov7670_config sensor_cfg = {
+ /*
+ * Exclude QCIF mode, because it only captures a tiny portion
+ * of the sensor FOV
+ */
+ .min_width = 320,
+ .min_height = 240,
+
+ /*
+ * Set the clock speed for the XO 1; I don't believe this
+ * driver has ever run anywhere else.
+ */
+ .clock_speed = 45,
+ .use_smbus = 1,
+};
+
+static struct i2c_board_info ov7670_info = {
+ .type = "ov7670",
+ .addr = 0x42 >> 1,
+ .platform_data = &sensor_cfg,
+};
/* -------------------------------------------------------------------------- */
/*
@@ -480,12 +507,6 @@ static int cafe_pci_probe(struct pci_dev *pdev,
mcam->dev = &pdev->dev;
snprintf(mcam->bus_info, sizeof(mcam->bus_info), "PCI:%s", pci_name(pdev));
/*
- * Set the clock speed for the XO 1; I don't believe this
- * driver has ever run anywhere else.
- */
- mcam->clock_speed = 45;
- mcam->use_smbus = 1;
- /*
* Vmalloc mode for buffers is traditional with this driver.
* We *might* be able to run DMA_contig, especially on a system
* with CMA in it.
@@ -511,11 +532,10 @@ static int cafe_pci_probe(struct pci_dev *pdev,
goto out_iounmap;
/*
- * Initialize the controller and leave it powered up. It will
- * stay that way until the sensor driver shows up.
+ * Initialize the controller.
*/
cafe_ctlr_init(mcam);
- cafe_ctlr_power_up(mcam);
+
/*
* Set up I2C/SMBUS communications. We have to drop the mutex here
* because the sensor could attach in this call chain, leading to
@@ -525,12 +545,24 @@ static int cafe_pci_probe(struct pci_dev *pdev,
if (ret)
goto out_pdown;
+ mcam->asd.match_type = V4L2_ASYNC_MATCH_I2C;
+ mcam->asd.match.i2c.adapter_id = i2c_adapter_id(cam->i2c_adapter);
+ mcam->asd.match.i2c.address = ov7670_info.addr;
+
ret = mccic_register(mcam);
- if (ret == 0) {
+ if (ret)
+ goto out_smbus_shutdown;
+
+ clkdev_create(mcam->mclk, "xclk", "%d-%04x",
+ i2c_adapter_id(cam->i2c_adapter), ov7670_info.addr);
+
+ if (i2c_new_device(cam->i2c_adapter, &ov7670_info)) {
cam->registered = 1;
return 0;
}
+ mccic_shutdown(mcam);
+out_smbus_shutdown:
cafe_smbus_shutdown(cam);
out_pdown:
cafe_ctlr_power_down(mcam);
diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c
index f1b301810260..dc30c48d4671 100644
--- a/drivers/media/platform/marvell-ccic/mcam-core.c
+++ b/drivers/media/platform/marvell-ccic/mcam-core.c
@@ -4,6 +4,7 @@
* so it needs platform-specific support outside of the core.
*
* Copyright 2011 Jonathan Corbet corbet@lwn.net
+ * Copyright 2018 Lubomir Rintel <lkundrak@v3.sk>
*/
#include <linux/kernel.h>
#include <linux/module.h>
@@ -21,12 +22,12 @@
#include <linux/vmalloc.h>
#include <linux/io.h>
#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-event.h>
-#include <media/i2c/ov7670.h>
#include <media/videobuf2-vmalloc.h>
#include <media/videobuf2-dma-contig.h>
#include <media/videobuf2-dma-sg.h>
@@ -93,6 +94,9 @@ MODULE_PARM_DESC(buffer_mode,
#define sensor_call(cam, o, f, args...) \
v4l2_subdev_call(cam->sensor, o, f, ##args)
+#define notifier_to_mcam(notifier) \
+ container_of(notifier, struct mcam_camera, notifier)
+
static struct mcam_format_struct {
__u8 *desc;
__u32 pixelformat;
@@ -200,7 +204,6 @@ struct mcam_vb_buffer {
struct list_head queue;
struct mcam_dma_desc *dma_desc; /* Descriptor virtual address */
dma_addr_t dma_desc_pa; /* Descriptor physical address */
- int dma_desc_nent; /* Number of mapped descriptors */
};
static inline struct mcam_vb_buffer *vb_to_mvb(struct vb2_v4l2_buffer *vb)
@@ -282,6 +285,8 @@ static void mcam_ctlr_stop(struct mcam_camera *cam)
static void mcam_enable_mipi(struct mcam_camera *mcam)
{
/* Using MIPI mode and enable MIPI */
+ if (mcam->calc_dphy)
+ mcam->calc_dphy(mcam);
cam_dbg(mcam, "camera: DPHY3=0x%x, DPHY5=0x%x, DPHY6=0x%x\n",
mcam->dphy[0], mcam->dphy[1], mcam->dphy[2]);
mcam_reg_write(mcam, REG_CSI2_DPHY3, mcam->dphy[0]);
@@ -301,9 +306,6 @@ static void mcam_enable_mipi(struct mcam_camera *mcam)
*/
mcam_reg_write(mcam, REG_CSI2_CTRL0,
CSI2_C0_MIPI_EN | CSI2_C0_ACT_LANE(mcam->lane));
- mcam_reg_write(mcam, REG_CLKCTRL,
- (mcam->mclk_src << 29) | mcam->mclk_div);
-
mcam->mipi_enabled = true;
}
}
@@ -608,9 +610,11 @@ static void mcam_dma_contig_done(struct mcam_camera *cam, int frame)
static void mcam_sg_next_buffer(struct mcam_camera *cam)
{
struct mcam_vb_buffer *buf;
+ struct sg_table *sg_table;
buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer, queue);
list_del_init(&buf->queue);
+ sg_table = vb2_dma_sg_plane_desc(&buf->vb_buf.vb2_buf, 0);
/*
* Very Bad Not Good Things happen if you don't clear
* C1_DESC_ENA before making any descriptor changes.
@@ -618,7 +622,7 @@ static void mcam_sg_next_buffer(struct mcam_camera *cam)
mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_ENA);
mcam_reg_write(cam, REG_DMA_DESC_Y, buf->dma_desc_pa);
mcam_reg_write(cam, REG_DESC_LEN_Y,
- buf->dma_desc_nent*sizeof(struct mcam_dma_desc));
+ sg_table->nents * sizeof(struct mcam_dma_desc));
mcam_reg_write(cam, REG_DESC_LEN_U, 0);
mcam_reg_write(cam, REG_DESC_LEN_V, 0);
mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA);
@@ -791,12 +795,6 @@ static void mcam_ctlr_image(struct mcam_camera *cam)
* Make sure it knows we want to use hsync/vsync.
*/
mcam_reg_write_mask(cam, REG_CTRL0, C0_SIF_HVSYNC, C0_SIFM_MASK);
- /*
- * This field controls the generation of EOF(DVP only)
- */
- if (cam->bus_type != V4L2_MBUS_CSI2_DPHY)
- mcam_reg_set_bit(cam, REG_CTRL0,
- C0_EOF_VSYNC | C0_VEDGE_CTRL);
}
@@ -832,31 +830,6 @@ static void mcam_ctlr_irq_disable(struct mcam_camera *cam)
mcam_reg_clear_bit(cam, REG_IRQMASK, FRAMEIRQS);
}
-
-
-static void mcam_ctlr_init(struct mcam_camera *cam)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&cam->dev_lock, flags);
- /*
- * Make sure it's not powered down.
- */
- mcam_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN);
- /*
- * Turn off the enable bit. It sure should be off anyway,
- * but it's good to be sure.
- */
- mcam_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE);
- /*
- * Clock the sensor appropriately. Controller clock should
- * be 48MHz, sensor "typical" value is half that.
- */
- mcam_reg_write_mask(cam, REG_CLKCTRL, 2, CLK_DIV_MASK);
- spin_unlock_irqrestore(&cam->dev_lock, flags);
-}
-
-
/*
* Stop the controller, and don't return until we're really sure that no
* further DMA is going on.
@@ -900,14 +873,15 @@ static int mcam_ctlr_power_up(struct mcam_camera *cam)
int ret;
spin_lock_irqsave(&cam->dev_lock, flags);
- ret = cam->plat_power_up(cam);
- if (ret) {
- spin_unlock_irqrestore(&cam->dev_lock, flags);
- return ret;
+ if (cam->plat_power_up) {
+ ret = cam->plat_power_up(cam);
+ if (ret) {
+ spin_unlock_irqrestore(&cam->dev_lock, flags);
+ return ret;
+ }
}
mcam_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN);
spin_unlock_irqrestore(&cam->dev_lock, flags);
- msleep(5); /* Just to be sure */
return 0;
}
@@ -922,10 +896,101 @@ static void mcam_ctlr_power_down(struct mcam_camera *cam)
* power down routine.
*/
mcam_reg_set_bit(cam, REG_CTRL1, C1_PWRDWN);
- cam->plat_power_down(cam);
+ if (cam->plat_power_down)
+ cam->plat_power_down(cam);
spin_unlock_irqrestore(&cam->dev_lock, flags);
}
+/* ---------------------------------------------------------------------- */
+/*
+ * Controller clocks.
+ */
+static void mcam_clk_enable(struct mcam_camera *mcam)
+{
+ unsigned int i;
+
+ for (i = 0; i < NR_MCAM_CLK; i++) {
+ if (!IS_ERR(mcam->clk[i]))
+ clk_prepare_enable(mcam->clk[i]);
+ }
+}
+
+static void mcam_clk_disable(struct mcam_camera *mcam)
+{
+ int i;
+
+ for (i = NR_MCAM_CLK - 1; i >= 0; i--) {
+ if (!IS_ERR(mcam->clk[i]))
+ clk_disable_unprepare(mcam->clk[i]);
+ }
+}
+
+/* ---------------------------------------------------------------------- */
+/*
+ * Master sensor clock.
+ */
+static int mclk_prepare(struct clk_hw *hw)
+{
+ struct mcam_camera *cam = container_of(hw, struct mcam_camera, mclk_hw);
+
+ clk_prepare(cam->clk[0]);
+ return 0;
+}
+
+static void mclk_unprepare(struct clk_hw *hw)
+{
+ struct mcam_camera *cam = container_of(hw, struct mcam_camera, mclk_hw);
+
+ clk_unprepare(cam->clk[0]);
+}
+
+static int mclk_enable(struct clk_hw *hw)
+{
+ struct mcam_camera *cam = container_of(hw, struct mcam_camera, mclk_hw);
+ int mclk_src;
+ int mclk_div;
+
+ /*
+ * Clock the sensor appropriately. Controller clock should
+ * be 48MHz, sensor "typical" value is half that.
+ */
+ if (cam->bus_type == V4L2_MBUS_CSI2_DPHY) {
+ mclk_src = cam->mclk_src;
+ mclk_div = cam->mclk_div;
+ } else {
+ mclk_src = 3;
+ mclk_div = 2;
+ }
+
+ clk_enable(cam->clk[0]);
+ mcam_reg_write(cam, REG_CLKCTRL, (mclk_src << 29) | mclk_div);
+ mcam_ctlr_power_up(cam);
+
+ return 0;
+}
+
+static void mclk_disable(struct clk_hw *hw)
+{
+ struct mcam_camera *cam = container_of(hw, struct mcam_camera, mclk_hw);
+
+ mcam_ctlr_power_down(cam);
+ clk_disable(cam->clk[0]);
+}
+
+static unsigned long mclk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return 48000000;
+}
+
+static const struct clk_ops mclk_ops = {
+ .prepare = mclk_prepare,
+ .unprepare = mclk_unprepare,
+ .enable = mclk_enable,
+ .disable = mclk_disable,
+ .recalc_rate = mclk_recalc_rate,
+};
+
/* -------------------------------------------------------------------- */
/*
* Communications with the sensor.
@@ -950,7 +1015,6 @@ static int mcam_cam_init(struct mcam_camera *cam)
ret = __mcam_cam_reset(cam);
/* Get/set parameters? */
cam->state = S_IDLE;
- mcam_ctlr_power_down(cam);
return ret;
}
@@ -1016,13 +1080,6 @@ static int mcam_read_setup(struct mcam_camera *cam)
spin_lock_irqsave(&cam->dev_lock, flags);
clear_bit(CF_DMA_ACTIVE, &cam->flags);
mcam_reset_buffers(cam);
- /*
- * Update CSI2_DPHY value
- */
- if (cam->calc_dphy)
- cam->calc_dphy(cam);
- cam_dbg(cam, "camera: DPHY sets: dphy3=0x%x, dphy5=0x%x, dphy6=0x%x\n",
- cam->dphy[0], cam->dphy[1], cam->dphy[2]);
if (cam->bus_type == V4L2_MBUS_CSI2_DPHY)
mcam_enable_mipi(cam);
else
@@ -1160,12 +1217,6 @@ static void mcam_vb_stop_streaming(struct vb2_queue *vq)
return;
mcam_ctlr_stop_dma(cam);
/*
- * Reset the CCIC PHY after stopping streaming,
- * otherwise, the CCIC may be unstable.
- */
- if (cam->ctlr_reset)
- cam->ctlr_reset(cam);
- /*
* VB2 reclaims the buffers, so we need to forget
* about them.
*/
@@ -1592,9 +1643,10 @@ static int mcam_v4l_open(struct file *filp)
if (ret)
goto out;
if (v4l2_fh_is_singular_file(filp)) {
- ret = mcam_ctlr_power_up(cam);
+ ret = sensor_call(cam, core, s_power, 1);
if (ret)
goto out;
+ mcam_clk_enable(cam);
__mcam_cam_reset(cam);
mcam_set_config_needed(cam, 1);
}
@@ -1616,7 +1668,8 @@ static int mcam_v4l_release(struct file *filp)
_vb2_fop_release(filp, NULL);
if (last_open) {
mcam_disable_mipi(cam);
- mcam_ctlr_power_down(cam);
+ sensor_call(cam, core, s_power, 0);
+ mcam_clk_disable(cam);
if (cam->buffer_mode == B_vmalloc && alloc_bufs_at_read)
mcam_free_dma_bufs(cam);
}
@@ -1726,23 +1779,95 @@ EXPORT_SYMBOL_GPL(mccic_irq);
/*
* Registration and such.
*/
-static struct ov7670_config sensor_cfg = {
+
+static int mccic_notify_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *subdev, struct v4l2_async_subdev *asd)
+{
+ struct mcam_camera *cam = notifier_to_mcam(notifier);
+ int ret;
+
+ mutex_lock(&cam->s_mutex);
+ if (cam->sensor) {
+ cam_err(cam, "sensor already bound\n");
+ ret = -EBUSY;
+ goto out;
+ }
+
+ v4l2_set_subdev_hostdata(subdev, cam);
+ cam->sensor = subdev;
+
+ ret = mcam_cam_init(cam);
+ if (ret) {
+ cam->sensor = NULL;
+ goto out;
+ }
+
+ ret = mcam_setup_vb2(cam);
+ if (ret) {
+ cam->sensor = NULL;
+ goto out;
+ }
+
+ cam->vdev = mcam_v4l_template;
+ cam->vdev.v4l2_dev = &cam->v4l2_dev;
+ cam->vdev.lock = &cam->s_mutex;
+ cam->vdev.queue = &cam->vb_queue;
+ video_set_drvdata(&cam->vdev, cam);
+ ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1);
+ if (ret) {
+ cam->sensor = NULL;
+ goto out;
+ }
+
+ cam_dbg(cam, "sensor %s bound\n", subdev->name);
+out:
+ mutex_unlock(&cam->s_mutex);
+ return ret;
+}
+
+static void mccic_notify_unbind(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *subdev, struct v4l2_async_subdev *asd)
+{
+ struct mcam_camera *cam = notifier_to_mcam(notifier);
+
+ mutex_lock(&cam->s_mutex);
+ if (cam->sensor != subdev) {
+ cam_err(cam, "sensor %s not bound\n", subdev->name);
+ goto out;
+ }
+
+ video_unregister_device(&cam->vdev);
+ cam->sensor = NULL;
+ cam_dbg(cam, "sensor %s unbound\n", subdev->name);
+
+out:
+ mutex_unlock(&cam->s_mutex);
+}
+
+static int mccic_notify_complete(struct v4l2_async_notifier *notifier)
+{
+ struct mcam_camera *cam = notifier_to_mcam(notifier);
+ int ret;
+
/*
- * Exclude QCIF mode, because it only captures a tiny portion
- * of the sensor FOV
+ * Get the v4l2 setup done.
*/
- .min_width = 320,
- .min_height = 240,
-};
+ ret = v4l2_ctrl_handler_init(&cam->ctrl_handler, 10);
+ if (!ret)
+ cam->v4l2_dev.ctrl_handler = &cam->ctrl_handler;
+ return ret;
+}
+
+static const struct v4l2_async_notifier_operations mccic_notify_ops = {
+ .bound = mccic_notify_bound,
+ .unbind = mccic_notify_unbind,
+ .complete = mccic_notify_complete,
+};
int mccic_register(struct mcam_camera *cam)
{
- struct i2c_board_info ov7670_info = {
- .type = "ov7670",
- .addr = 0x42 >> 1,
- .platform_data = &sensor_cfg,
- };
+ struct clk_init_data mclk_init = { };
int ret;
/*
@@ -1755,64 +1880,62 @@ int mccic_register(struct mcam_camera *cam)
printk(KERN_ERR "marvell-cam: Cafe can't do S/G I/O, attempting vmalloc mode instead\n");
cam->buffer_mode = B_vmalloc;
}
+
if (!mcam_buffer_mode_supported(cam->buffer_mode)) {
printk(KERN_ERR "marvell-cam: buffer mode %d unsupported\n",
cam->buffer_mode);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
+
/*
* Register with V4L
*/
ret = v4l2_device_register(cam->dev, &cam->v4l2_dev);
if (ret)
- return ret;
+ goto out;
mutex_init(&cam->s_mutex);
cam->state = S_NOTREADY;
mcam_set_config_needed(cam, 1);
cam->pix_format = mcam_def_pix_format;
cam->mbus_code = mcam_def_mbus_code;
- mcam_ctlr_init(cam);
/*
- * Get the v4l2 setup done.
+ * Register sensor notifier.
*/
- ret = v4l2_ctrl_handler_init(&cam->ctrl_handler, 10);
- if (ret)
- goto out_unregister;
- cam->v4l2_dev.ctrl_handler = &cam->ctrl_handler;
+ v4l2_async_notifier_init(&cam->notifier);
+ ret = v4l2_async_notifier_add_subdev(&cam->notifier, &cam->asd);
+ if (ret) {
+ cam_warn(cam, "failed to add subdev to a notifier");
+ goto out;
+ }
+
+ cam->notifier.ops = &mccic_notify_ops;
+ ret = v4l2_async_notifier_register(&cam->v4l2_dev, &cam->notifier);
+ if (ret < 0) {
+ cam_warn(cam, "failed to register a sensor notifier");
+ goto out;
+ }
/*
- * Try to find the sensor.
+ * Register sensor master clock.
*/
- sensor_cfg.clock_speed = cam->clock_speed;
- sensor_cfg.use_smbus = cam->use_smbus;
- cam->sensor_addr = ov7670_info.addr;
- cam->sensor = v4l2_i2c_new_subdev_board(&cam->v4l2_dev,
- cam->i2c_adapter, &ov7670_info, NULL);
- if (cam->sensor == NULL) {
- ret = -ENODEV;
- goto out_unregister;
- }
+ mclk_init.parent_names = NULL;
+ mclk_init.num_parents = 0;
+ mclk_init.ops = &mclk_ops;
+ mclk_init.name = "mclk";
- ret = mcam_cam_init(cam);
- if (ret)
- goto out_unregister;
+ of_property_read_string(cam->dev->of_node, "clock-output-names",
+ &mclk_init.name);
- ret = mcam_setup_vb2(cam);
- if (ret)
- goto out_unregister;
+ cam->mclk_hw.init = &mclk_init;
- mutex_lock(&cam->s_mutex);
- cam->vdev = mcam_v4l_template;
- cam->vdev.v4l2_dev = &cam->v4l2_dev;
- cam->vdev.lock = &cam->s_mutex;
- cam->vdev.queue = &cam->vb_queue;
- video_set_drvdata(&cam->vdev, cam);
- ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1);
- if (ret) {
- mutex_unlock(&cam->s_mutex);
- goto out_unregister;
+ cam->mclk = devm_clk_register(cam->dev, &cam->mclk_hw);
+ if (IS_ERR(cam->mclk)) {
+ ret = PTR_ERR(cam->mclk);
+ dev_err(cam->dev, "can't register clock\n");
+ goto out;
}
/*
@@ -1823,11 +1946,10 @@ int mccic_register(struct mcam_camera *cam)
cam_warn(cam, "Unable to alloc DMA buffers at load will try again later.");
}
- mutex_unlock(&cam->s_mutex);
return 0;
-out_unregister:
- v4l2_ctrl_handler_free(&cam->ctrl_handler);
+out:
+ v4l2_async_notifier_unregister(&cam->notifier);
v4l2_device_unregister(&cam->v4l2_dev);
return ret;
}
@@ -1843,12 +1965,12 @@ void mccic_shutdown(struct mcam_camera *cam)
*/
if (!list_empty(&cam->vdev.fh_list)) {
cam_warn(cam, "Removing a device with users!\n");
- mcam_ctlr_power_down(cam);
+ sensor_call(cam, core, s_power, 0);
}
if (cam->buffer_mode == B_vmalloc)
mcam_free_dma_bufs(cam);
- video_unregister_device(&cam->vdev);
v4l2_ctrl_handler_free(&cam->ctrl_handler);
+ v4l2_async_notifier_unregister(&cam->notifier);
v4l2_device_unregister(&cam->v4l2_dev);
}
EXPORT_SYMBOL_GPL(mccic_shutdown);
@@ -1865,7 +1987,8 @@ void mccic_suspend(struct mcam_camera *cam)
enum mcam_state cstate = cam->state;
mcam_ctlr_stop_dma(cam);
- mcam_ctlr_power_down(cam);
+ sensor_call(cam, core, s_power, 0);
+ mcam_clk_disable(cam);
cam->state = cstate;
}
mutex_unlock(&cam->s_mutex);
@@ -1878,14 +2001,15 @@ int mccic_resume(struct mcam_camera *cam)
mutex_lock(&cam->s_mutex);
if (!list_empty(&cam->vdev.fh_list)) {
- ret = mcam_ctlr_power_up(cam);
+ mcam_clk_enable(cam);
+ ret = sensor_call(cam, core, s_power, 1);
if (ret) {
mutex_unlock(&cam->s_mutex);
return ret;
}
__mcam_cam_reset(cam);
} else {
- mcam_ctlr_power_down(cam);
+ sensor_call(cam, core, s_power, 0);
}
mutex_unlock(&cam->s_mutex);
diff --git a/drivers/media/platform/marvell-ccic/mcam-core.h b/drivers/media/platform/marvell-ccic/mcam-core.h
index ad8955f9f0a1..2e3a7567a76a 100644
--- a/drivers/media/platform/marvell-ccic/mcam-core.h
+++ b/drivers/media/platform/marvell-ccic/mcam-core.h
@@ -8,6 +8,7 @@
#define _MCAM_CORE_H
#include <linux/list.h>
+#include <linux/clk-provider.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-dev.h>
@@ -102,21 +103,16 @@ struct mcam_camera {
* These fields should be set by the platform code prior to
* calling mcam_register().
*/
- struct i2c_adapter *i2c_adapter;
unsigned char __iomem *regs;
unsigned regs_size; /* size in bytes of the register space */
spinlock_t dev_lock;
struct device *dev; /* For messages, dma alloc */
enum mcam_chip_id chip_id;
- short int clock_speed; /* Sensor clock speed, default 30 */
- short int use_smbus; /* SMBUS or straight I2c? */
enum mcam_buffer_mode buffer_mode;
- int mclk_min; /* The minimal value of mclk */
int mclk_src; /* which clock source the mclk derives from */
int mclk_div; /* Clock Divider Value for MCLK */
- int ccic_id;
enum v4l2_mbus_type bus_type;
/* MIPI support */
/* The dphy config value, allocated in board file
@@ -130,6 +126,8 @@ struct mcam_camera {
/* clock tree support */
struct clk *clk[NR_MCAM_CLK];
+ struct clk_hw mclk_hw;
+ struct clk *mclk;
/*
* Callbacks from the core to the platform code.
@@ -137,7 +135,6 @@ struct mcam_camera {
int (*plat_power_up) (struct mcam_camera *cam);
void (*plat_power_down) (struct mcam_camera *cam);
void (*calc_dphy) (struct mcam_camera *cam);
- void (*ctlr_reset) (struct mcam_camera *cam);
/*
* Everything below here is private to the mcam core and
@@ -153,8 +150,9 @@ struct mcam_camera {
* Subsystem structures.
*/
struct video_device vdev;
+ struct v4l2_async_notifier notifier;
+ struct v4l2_async_subdev asd;
struct v4l2_subdev *sensor;
- unsigned short sensor_addr;
/* Videobuf2 stuff */
struct vb2_queue vb_queue;
diff --git a/drivers/media/platform/marvell-ccic/mmp-driver.c b/drivers/media/platform/marvell-ccic/mmp-driver.c
index bf4d4a47f1db..10559492e09e 100644
--- a/drivers/media/platform/marvell-ccic/mmp-driver.c
+++ b/drivers/media/platform/marvell-ccic/mmp-driver.c
@@ -4,13 +4,12 @@
* to work with the Armada 610 as used in the OLPC 1.75 system.
*
* Copyright 2011 Jonathan Corbet <corbet@lwn.net>
+ * Copyright 2018 Lubomir Rintel <lkundrak@v3.sk>
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/platform_data/i2c-gpio.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
@@ -18,10 +17,10 @@
#include <media/v4l2-device.h>
#include <linux/platform_data/media/mmp-camera.h>
#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
#include <linux/platform_device.h>
-#include <linux/gpio.h>
#include <linux/io.h>
-#include <linux/delay.h>
#include <linux/list.h>
#include <linux/pm.h>
#include <linux/clk.h>
@@ -32,10 +31,9 @@ MODULE_ALIAS("platform:mmp-camera");
MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
MODULE_LICENSE("GPL");
-static char *mcam_clks[] = {"CCICAXICLK", "CCICFUNCLK", "CCICPHYCLK"};
+static char *mcam_clks[] = {"axi", "func", "phy"};
struct mmp_camera {
- void __iomem *power_regs;
struct platform_device *pdev;
struct mcam_camera mcam;
struct list_head devlist;
@@ -91,118 +89,6 @@ static struct mmp_camera *mmpcam_find_device(struct platform_device *pdev)
return NULL;
}
-
-
-
-/*
- * Power-related registers; this almost certainly belongs
- * somewhere else.
- *
- * ARMADA 610 register manual, sec 7.2.1, p1842.
- */
-#define CPU_SUBSYS_PMU_BASE 0xd4282800
-#define REG_CCIC_DCGCR 0x28 /* CCIC dyn clock gate ctrl reg */
-#define REG_CCIC_CRCR 0x50 /* CCIC clk reset ctrl reg */
-#define REG_CCIC2_CRCR 0xf4 /* CCIC2 clk reset ctrl reg */
-
-static void mcam_clk_enable(struct mcam_camera *mcam)
-{
- unsigned int i;
-
- for (i = 0; i < NR_MCAM_CLK; i++) {
- if (!IS_ERR(mcam->clk[i]))
- clk_prepare_enable(mcam->clk[i]);
- }
-}
-
-static void mcam_clk_disable(struct mcam_camera *mcam)
-{
- int i;
-
- for (i = NR_MCAM_CLK - 1; i >= 0; i--) {
- if (!IS_ERR(mcam->clk[i]))
- clk_disable_unprepare(mcam->clk[i]);
- }
-}
-
-/*
- * Power control.
- */
-static void mmpcam_power_up_ctlr(struct mmp_camera *cam)
-{
- iowrite32(0x3f, cam->power_regs + REG_CCIC_DCGCR);
- iowrite32(0x3805b, cam->power_regs + REG_CCIC_CRCR);
- mdelay(1);
-}
-
-static int mmpcam_power_up(struct mcam_camera *mcam)
-{
- struct mmp_camera *cam = mcam_to_cam(mcam);
- struct mmp_camera_platform_data *pdata;
-
-/*
- * Turn on power and clocks to the controller.
- */
- mmpcam_power_up_ctlr(cam);
-/*
- * Provide power to the sensor.
- */
- mcam_reg_write(mcam, REG_CLKCTRL, 0x60000002);
- pdata = cam->pdev->dev.platform_data;
- gpio_set_value(pdata->sensor_power_gpio, 1);
- mdelay(5);
- mcam_reg_clear_bit(mcam, REG_CTRL1, 0x10000000);
- gpio_set_value(pdata->sensor_reset_gpio, 0); /* reset is active low */
- mdelay(5);
- gpio_set_value(pdata->sensor_reset_gpio, 1); /* reset is active low */
- mdelay(5);
-
- mcam_clk_enable(mcam);
-
- return 0;
-}
-
-static void mmpcam_power_down(struct mcam_camera *mcam)
-{
- struct mmp_camera *cam = mcam_to_cam(mcam);
- struct mmp_camera_platform_data *pdata;
-/*
- * Turn off clocks and set reset lines
- */
- iowrite32(0, cam->power_regs + REG_CCIC_DCGCR);
- iowrite32(0, cam->power_regs + REG_CCIC_CRCR);
-/*
- * Shut down the sensor.
- */
- pdata = cam->pdev->dev.platform_data;
- gpio_set_value(pdata->sensor_power_gpio, 0);
- gpio_set_value(pdata->sensor_reset_gpio, 0);
-
- mcam_clk_disable(mcam);
-}
-
-static void mcam_ctlr_reset(struct mcam_camera *mcam)
-{
- unsigned long val;
- struct mmp_camera *cam = mcam_to_cam(mcam);
-
- if (mcam->ccic_id) {
- /*
- * Using CCIC2
- */
- val = ioread32(cam->power_regs + REG_CCIC2_CRCR);
- iowrite32(val & ~0x2, cam->power_regs + REG_CCIC2_CRCR);
- iowrite32(val | 0x2, cam->power_regs + REG_CCIC2_CRCR);
- } else {
- /*
- * Using CCIC1
- */
- val = ioread32(cam->power_regs + REG_CCIC_CRCR);
- iowrite32(val & ~0x2, cam->power_regs + REG_CCIC_CRCR);
- iowrite32(val | 0x2, cam->power_regs + REG_CCIC_CRCR);
- }
-}
-
/*
* calc the dphy register values
* There are three dphy registers being used.
@@ -334,13 +220,10 @@ static int mmpcam_probe(struct platform_device *pdev)
struct mmp_camera *cam;
struct mcam_camera *mcam;
struct resource *res;
+ struct fwnode_handle *ep;
struct mmp_camera_platform_data *pdata;
int ret;
- pdata = pdev->dev.platform_data;
- if (!pdata)
- return -ENODEV;
-
cam = devm_kzalloc(&pdev->dev, sizeof(*cam), GFP_KERNEL);
if (cam == NULL)
return -ENOMEM;
@@ -348,25 +231,31 @@ static int mmpcam_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&cam->devlist);
mcam = &cam->mcam;
- mcam->plat_power_up = mmpcam_power_up;
- mcam->plat_power_down = mmpcam_power_down;
- mcam->ctlr_reset = mcam_ctlr_reset;
mcam->calc_dphy = mmpcam_calc_dphy;
mcam->dev = &pdev->dev;
- mcam->use_smbus = 0;
- mcam->ccic_id = pdev->id;
- mcam->mclk_min = pdata->mclk_min;
- mcam->mclk_src = pdata->mclk_src;
- mcam->mclk_div = pdata->mclk_div;
- mcam->bus_type = pdata->bus_type;
- mcam->dphy = pdata->dphy;
+ pdata = pdev->dev.platform_data;
+ if (pdata) {
+ mcam->mclk_src = pdata->mclk_src;
+ mcam->mclk_div = pdata->mclk_div;
+ mcam->bus_type = pdata->bus_type;
+ mcam->dphy = pdata->dphy;
+ mcam->lane = pdata->lane;
+ } else {
+ /*
+ * These are values that used to be hardcoded in mcam-core and
+ * work well on a OLPC XO 1.75 with a parallel bus sensor.
+ * If it turns out other setups make sense, the values should
+ * be obtained from the device tree.
+ */
+ mcam->mclk_src = 3;
+ mcam->mclk_div = 2;
+ }
if (mcam->bus_type == V4L2_MBUS_CSI2_DPHY) {
cam->mipi_clk = devm_clk_get(mcam->dev, "mipi");
if ((IS_ERR(cam->mipi_clk) && mcam->dphy[2] == 0))
return PTR_ERR(cam->mipi_clk);
}
mcam->mipi_enabled = false;
- mcam->lane = pdata->lane;
mcam->chip_id = MCAM_ARMADA610;
mcam->buffer_mode = B_DMA_sg;
strscpy(mcam->bus_info, "platform:mmp-camera", sizeof(mcam->bus_info));
@@ -379,54 +268,39 @@ static int mmpcam_probe(struct platform_device *pdev)
if (IS_ERR(mcam->regs))
return PTR_ERR(mcam->regs);
mcam->regs_size = resource_size(res);
+
+ mcam_init_clk(mcam);
+
/*
- * Power/clock memory is elsewhere; get it too. Perhaps this
- * should really be managed outside of this driver?
- */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- cam->power_regs = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(cam->power_regs))
- return PTR_ERR(cam->power_regs);
- /*
- * Find the i2c adapter. This assumes, of course, that the
- * i2c bus is already up and functioning.
+ * Create a match of the sensor against its OF node.
*/
- mcam->i2c_adapter = platform_get_drvdata(pdata->i2c_device);
- if (mcam->i2c_adapter == NULL) {
- dev_err(&pdev->dev, "No i2c adapter\n");
+ ep = fwnode_graph_get_next_endpoint(of_fwnode_handle(pdev->dev.of_node),
+ NULL);
+ if (!ep)
return -ENODEV;
- }
- /*
- * Sensor GPIO pins.
- */
- ret = devm_gpio_request(&pdev->dev, pdata->sensor_power_gpio,
- "cam-power");
- if (ret) {
- dev_err(&pdev->dev, "Can't get sensor power gpio %d",
- pdata->sensor_power_gpio);
- return ret;
- }
- gpio_direction_output(pdata->sensor_power_gpio, 0);
- ret = devm_gpio_request(&pdev->dev, pdata->sensor_reset_gpio,
- "cam-reset");
- if (ret) {
- dev_err(&pdev->dev, "Can't get sensor reset gpio %d",
- pdata->sensor_reset_gpio);
- return ret;
- }
- gpio_direction_output(pdata->sensor_reset_gpio, 0);
- mcam_init_clk(mcam);
+ mcam->asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
+ mcam->asd.match.fwnode = fwnode_graph_get_remote_port_parent(ep);
+
+ fwnode_handle_put(ep);
/*
- * Power the device up and hand it off to the core.
+ * Register the device with the core.
*/
- ret = mmpcam_power_up(mcam);
- if (ret)
- return ret;
ret = mccic_register(mcam);
if (ret)
- goto out_power_down;
+ return ret;
+
+ /*
+ * Add OF clock provider.
+ */
+ ret = of_clk_add_provider(pdev->dev.of_node, of_clk_src_simple_get,
+ mcam->mclk);
+ if (ret) {
+ dev_err(&pdev->dev, "can't add DT clock provider\n");
+ goto out;
+ }
+
/*
* Finally, set up our IRQ now that the core is ready to
* deal with it.
@@ -434,7 +308,7 @@ static int mmpcam_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res == NULL) {
ret = -ENODEV;
- goto out_unregister;
+ goto out;
}
cam->irq = res->start;
ret = devm_request_irq(&pdev->dev, cam->irq, mmpcam_irq, IRQF_SHARED,
@@ -444,10 +318,10 @@ static int mmpcam_probe(struct platform_device *pdev)
return 0;
}
-out_unregister:
+out:
+ fwnode_handle_put(mcam->asd.match.fwnode);
mccic_shutdown(mcam);
-out_power_down:
- mmpcam_power_down(mcam);
+
return ret;
}
@@ -458,7 +332,6 @@ static int mmpcam_remove(struct mmp_camera *cam)
mmpcam_remove_device(cam);
mccic_shutdown(mcam);
- mmpcam_power_down(mcam);
return 0;
}
@@ -490,17 +363,15 @@ static int mmpcam_resume(struct platform_device *pdev)
{
struct mmp_camera *cam = mmpcam_find_device(pdev);
- /*
- * Power up unconditionally just in case the core tries to
- * touch a register even if nothing was active before; trust
- * me, it's better this way.
- */
- mmpcam_power_up_ctlr(cam);
return mccic_resume(&cam->mcam);
}
#endif
+static const struct of_device_id mmpcam_of_match[] = {
+ { .compatible = "marvell,mmp2-ccic", },
+ {},
+};
static struct platform_driver mmpcam_driver = {
.probe = mmpcam_probe,
@@ -511,6 +382,7 @@ static struct platform_driver mmpcam_driver = {
#endif
.driver = {
.name = "mmp-camera",
+ .of_match_table = of_match_ptr(mmpcam_of_match),
}
};
diff --git a/drivers/media/platform/meson/ao-cec-g12a.c b/drivers/media/platform/meson/ao-cec-g12a.c
index 3620a1e310f5..fb52e5dd044a 100644
--- a/drivers/media/platform/meson/ao-cec-g12a.c
+++ b/drivers/media/platform/meson/ao-cec-g12a.c
@@ -365,28 +365,22 @@ static int meson_ao_cec_g12a_read(void *context, unsigned int addr,
{
struct meson_ao_cec_g12a_device *ao_cec = context;
u32 reg = FIELD_PREP(CECB_RW_ADDR, addr);
- unsigned long flags;
int ret = 0;
- spin_lock_irqsave(&ao_cec->cec_reg_lock, flags);
-
ret = regmap_write(ao_cec->regmap, CECB_RW_REG, reg);
if (ret)
- goto read_out;
+ return ret;
ret = regmap_read_poll_timeout(ao_cec->regmap, CECB_RW_REG, reg,
!(reg & CECB_RW_BUS_BUSY),
5, 1000);
if (ret)
- goto read_out;
+ return ret;
ret = regmap_read(ao_cec->regmap, CECB_RW_REG, &reg);
*data = FIELD_GET(CECB_RW_RD_DATA, reg);
-read_out:
- spin_unlock_irqrestore(&ao_cec->cec_reg_lock, flags);
-
return ret;
}
@@ -394,19 +388,11 @@ static int meson_ao_cec_g12a_write(void *context, unsigned int addr,
unsigned int data)
{
struct meson_ao_cec_g12a_device *ao_cec = context;
- unsigned long flags;
u32 reg = FIELD_PREP(CECB_RW_ADDR, addr) |
FIELD_PREP(CECB_RW_WR_DATA, data) |
CECB_RW_WRITE_EN;
- int ret = 0;
- spin_lock_irqsave(&ao_cec->cec_reg_lock, flags);
-
- ret = regmap_write(ao_cec->regmap, CECB_RW_REG, reg);
-
- spin_unlock_irqrestore(&ao_cec->cec_reg_lock, flags);
-
- return ret;
+ return regmap_write(ao_cec->regmap, CECB_RW_REG, reg);
}
static const struct regmap_config meson_ao_cec_g12a_cec_regmap_conf = {
@@ -415,7 +401,6 @@ static const struct regmap_config meson_ao_cec_g12a_cec_regmap_conf = {
.reg_read = meson_ao_cec_g12a_read,
.reg_write = meson_ao_cec_g12a_write,
.max_register = 0xffff,
- .fast_io = true,
};
static inline void
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c
index 656444e7ca2b..ee802fc3bcdf 100644
--- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c
+++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c
@@ -518,7 +518,7 @@ static int mtk_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
return -EINVAL;
}
- vb = vq->bufs[buf->index];
+ vb = vb2_get_buffer(vq, buf->index);
jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(vb);
jpeg_src_buf->flags = (buf->m.planes[0].bytesused == 0) ?
MTK_JPEG_BUF_FLAGS_LAST_FRAME : MTK_JPEG_BUF_FLAGS_INIT;
@@ -528,8 +528,8 @@ end:
static const struct v4l2_ioctl_ops mtk_jpeg_ioctl_ops = {
.vidioc_querycap = mtk_jpeg_querycap,
- .vidioc_enum_fmt_vid_cap_mplane = mtk_jpeg_enum_fmt_vid_cap,
- .vidioc_enum_fmt_vid_out_mplane = mtk_jpeg_enum_fmt_vid_out,
+ .vidioc_enum_fmt_vid_cap = mtk_jpeg_enum_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_out = mtk_jpeg_enum_fmt_vid_out,
.vidioc_try_fmt_vid_cap_mplane = mtk_jpeg_try_fmt_vid_cap_mplane,
.vidioc_try_fmt_vid_out_mplane = mtk_jpeg_try_fmt_vid_out_mplane,
.vidioc_g_fmt_vid_cap_mplane = mtk_jpeg_g_fmt_vid_mplane,
diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
index b28e3dd4885c..7c9e2d69e21a 100644
--- a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
+++ b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
@@ -612,7 +612,7 @@ static int mtk_mdp_m2m_querycap(struct file *file, void *fh,
return 0;
}
-static int mtk_mdp_enum_fmt_mplane(struct v4l2_fmtdesc *f, u32 type)
+static int mtk_mdp_enum_fmt(struct v4l2_fmtdesc *f, u32 type)
{
const struct mtk_mdp_fmt *fmt;
@@ -625,16 +625,16 @@ static int mtk_mdp_enum_fmt_mplane(struct v4l2_fmtdesc *f, u32 type)
return 0;
}
-static int mtk_mdp_m2m_enum_fmt_mplane_vid_cap(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
+static int mtk_mdp_m2m_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
{
- return mtk_mdp_enum_fmt_mplane(f, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+ return mtk_mdp_enum_fmt(f, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
}
-static int mtk_mdp_m2m_enum_fmt_mplane_vid_out(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
+static int mtk_mdp_m2m_enum_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
{
- return mtk_mdp_enum_fmt_mplane(f, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+ return mtk_mdp_enum_fmt(f, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
}
static int mtk_mdp_m2m_g_fmt_mplane(struct file *file, void *fh,
@@ -927,8 +927,8 @@ static int mtk_mdp_m2m_s_selection(struct file *file, void *fh,
static const struct v4l2_ioctl_ops mtk_mdp_m2m_ioctl_ops = {
.vidioc_querycap = mtk_mdp_m2m_querycap,
- .vidioc_enum_fmt_vid_cap_mplane = mtk_mdp_m2m_enum_fmt_mplane_vid_cap,
- .vidioc_enum_fmt_vid_out_mplane = mtk_mdp_m2m_enum_fmt_mplane_vid_out,
+ .vidioc_enum_fmt_vid_cap = mtk_mdp_m2m_enum_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_out = mtk_mdp_m2m_enum_fmt_vid_out,
.vidioc_g_fmt_vid_cap_mplane = mtk_mdp_m2m_g_fmt_mplane,
.vidioc_g_fmt_vid_out_mplane = mtk_mdp_m2m_g_fmt_mplane,
.vidioc_try_fmt_vid_cap_mplane = mtk_mdp_m2m_try_fmt_mplane,
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
index 7ae588e62ed8..90d1a67db7e5 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: PC Chen <pc.chen@mediatek.com>
@@ -24,7 +24,7 @@
#define DFT_CFG_WIDTH MTK_VDEC_MIN_W
#define DFT_CFG_HEIGHT MTK_VDEC_MIN_H
-static struct mtk_video_fmt mtk_video_formats[] = {
+static const struct mtk_video_fmt mtk_video_formats[] = {
{
.fourcc = V4L2_PIX_FMT_H264,
.type = MTK_FMT_DEC,
@@ -68,9 +68,9 @@ static const struct mtk_codec_framesizes mtk_vdec_framesizes[] = {
#define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(mtk_vdec_framesizes)
#define NUM_FORMATS ARRAY_SIZE(mtk_video_formats)
-static struct mtk_video_fmt *mtk_vdec_find_format(struct v4l2_format *f)
+static const struct mtk_video_fmt *mtk_vdec_find_format(struct v4l2_format *f)
{
- struct mtk_video_fmt *fmt;
+ const struct mtk_video_fmt *fmt;
unsigned int k;
for (k = 0; k < NUM_FORMATS; k++) {
@@ -122,8 +122,9 @@ static struct vb2_buffer *get_display_buffer(struct mtk_vcodec_ctx *ctx)
if (dstbuf->used) {
vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 0,
ctx->picinfo.fb_sz[0]);
- vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 1,
- ctx->picinfo.fb_sz[1]);
+ if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2)
+ vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 1,
+ ctx->picinfo.fb_sz[1]);
mtk_v4l2_debug(2,
"[%d]status=%x queue id=%d to done_list %d",
@@ -271,7 +272,7 @@ static void mtk_vdec_flush_decoder(struct mtk_vcodec_ctx *ctx)
static void mtk_vdec_update_fmt(struct mtk_vcodec_ctx *ctx,
unsigned int pixelformat)
{
- struct mtk_video_fmt *fmt;
+ const struct mtk_video_fmt *fmt;
struct mtk_q_data *dst_q_data;
unsigned int k;
@@ -394,7 +395,8 @@ static void mtk_vdec_worker(struct work_struct *work)
vdec_if_decode(ctx, NULL, NULL, &res_chg);
clean_display_buffer(ctx);
vb2_set_plane_payload(&dst_buf_info->vb.vb2_buf, 0, 0);
- vb2_set_plane_payload(&dst_buf_info->vb.vb2_buf, 1, 0);
+ if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2)
+ vb2_set_plane_payload(&dst_buf_info->vb.vb2_buf, 1, 0);
dst_buf->flags |= V4L2_BUF_FLAG_LAST;
v4l2_m2m_buf_done(&dst_buf_info->vb, VB2_BUF_STATE_DONE);
clean_free_buffer(ctx);
@@ -644,7 +646,8 @@ static int vidioc_vdec_subscribe_evt(struct v4l2_fh *fh,
}
}
-static int vidioc_try_fmt(struct v4l2_format *f, struct mtk_video_fmt *fmt)
+static int vidioc_try_fmt(struct v4l2_format *f,
+ const struct mtk_video_fmt *fmt)
{
struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
int i;
@@ -717,7 +720,7 @@ static int vidioc_try_fmt(struct v4l2_format *f, struct mtk_video_fmt *fmt)
static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct mtk_video_fmt *fmt;
+ const struct mtk_video_fmt *fmt;
fmt = mtk_vdec_find_format(f);
if (!fmt) {
@@ -732,7 +735,7 @@ static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv,
struct v4l2_format *f)
{
struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
- struct mtk_video_fmt *fmt;
+ const struct mtk_video_fmt *fmt;
fmt = mtk_vdec_find_format(f);
if (!fmt) {
@@ -826,7 +829,7 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv,
struct v4l2_pix_format_mplane *pix_mp;
struct mtk_q_data *q_data;
int ret = 0;
- struct mtk_video_fmt *fmt;
+ const struct mtk_video_fmt *fmt;
mtk_v4l2_debug(3, "[%d]", ctx->id);
@@ -925,7 +928,7 @@ static int vidioc_enum_framesizes(struct file *file, void *priv,
static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue)
{
- struct mtk_video_fmt *fmt;
+ const struct mtk_video_fmt *fmt;
int i, j = 0;
for (i = 0; i < NUM_FORMATS; i++) {
@@ -949,14 +952,14 @@ static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue)
return 0;
}
-static int vidioc_vdec_enum_fmt_vid_cap_mplane(struct file *file, void *pirv,
- struct v4l2_fmtdesc *f)
+static int vidioc_vdec_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
{
return vidioc_enum_fmt(f, false);
}
-static int vidioc_vdec_enum_fmt_vid_out_mplane(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
+static int vidioc_vdec_enum_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
{
return vidioc_enum_fmt(f, true);
}
@@ -1324,7 +1327,8 @@ static void vb2ops_vdec_stop_streaming(struct vb2_queue *q)
while ((dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx))) {
vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
- vb2_set_plane_payload(&dst_buf->vb2_buf, 1, 0);
+ if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2)
+ vb2_set_plane_payload(&dst_buf->vb2_buf, 1, 0);
v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
}
@@ -1453,8 +1457,8 @@ const struct v4l2_ioctl_ops mtk_vdec_ioctl_ops = {
.vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
- .vidioc_enum_fmt_vid_cap_mplane = vidioc_vdec_enum_fmt_vid_cap_mplane,
- .vidioc_enum_fmt_vid_out_mplane = vidioc_vdec_enum_fmt_vid_out_mplane,
+ .vidioc_enum_fmt_vid_cap = vidioc_vdec_enum_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_out = vidioc_vdec_enum_fmt_vid_out,
.vidioc_enum_framesizes = vidioc_enum_framesizes,
.vidioc_querycap = vidioc_vdec_querycap,
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h
index 3861d4433be9..e0c5338bde3d 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: PC Chen <pc.chen@mediatek.com>
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
index 372d37824377..00d090df11bb 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: PC Chen <pc.chen@mediatek.com>
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c
index 273f78f129da..5a6ec8fb52da 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: Tiffany Lin <tiffany.lin@mediatek.com>
@@ -34,8 +34,8 @@ int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *mtkdev)
}
pdev = of_find_device_by_node(node);
+ of_node_put(node);
if (WARN_ON(!pdev)) {
- of_node_put(node);
return -1;
}
pm->larbvdec = &pdev->dev;
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h
index 74555cc5a893..872d8bf8cfaf 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: Tiffany Lin <tiffany.lin@mediatek.com>
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
index 1044176d8e6f..c95de5d08dda 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: PC Chen <pc.chen@mediatek.com>
@@ -129,7 +129,7 @@ struct mtk_q_data {
enum v4l2_field field;
unsigned int bytesperline[MTK_VCODEC_MAX_PLANES];
unsigned int sizeimage[MTK_VCODEC_MAX_PLANES];
- struct mtk_video_fmt *fmt;
+ const struct mtk_video_fmt *fmt;
};
/**
@@ -273,7 +273,7 @@ struct mtk_vcodec_ctx {
const struct vdec_common_if *dec_if;
const struct venc_common_if *enc_if;
- unsigned long drv_handle;
+ void *drv_handle;
struct vdec_pic_info picinfo;
int dpb_size;
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
index 0cf5744b4c28..fd8de027e83e 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: PC Chen <pc.chen@mediatek.com>
@@ -29,7 +29,7 @@
static void mtk_venc_worker(struct work_struct *work);
-static struct mtk_video_fmt mtk_video_formats[] = {
+static const struct mtk_video_fmt mtk_video_formats[] = {
{
.fourcc = V4L2_PIX_FMT_NV12M,
.type = MTK_FMT_FRAME,
@@ -158,7 +158,7 @@ static const struct v4l2_ctrl_ops mtk_vcodec_enc_ctrl_ops = {
static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue)
{
- struct mtk_video_fmt *fmt;
+ const struct mtk_video_fmt *fmt;
int i, j = 0;
for (i = 0; i < NUM_FORMATS; ++i) {
@@ -199,14 +199,14 @@ static int vidioc_enum_framesizes(struct file *file, void *fh,
return -EINVAL;
}
-static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv,
- struct v4l2_fmtdesc *f)
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
{
return vidioc_enum_fmt(f, false);
}
-static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov,
- struct v4l2_fmtdesc *f)
+static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
{
return vidioc_enum_fmt(f, true);
}
@@ -266,9 +266,9 @@ static struct mtk_q_data *mtk_venc_get_q_data(struct mtk_vcodec_ctx *ctx,
return &ctx->q_data[MTK_Q_DATA_DST];
}
-static struct mtk_video_fmt *mtk_venc_find_format(struct v4l2_format *f)
+static const struct mtk_video_fmt *mtk_venc_find_format(struct v4l2_format *f)
{
- struct mtk_video_fmt *fmt;
+ const struct mtk_video_fmt *fmt;
unsigned int k;
for (k = 0; k < NUM_FORMATS; k++) {
@@ -283,7 +283,8 @@ static struct mtk_video_fmt *mtk_venc_find_format(struct v4l2_format *f)
/* V4L2 specification suggests the driver corrects the format struct if any of
* the dimensions is unsupported
*/
-static int vidioc_try_fmt(struct v4l2_format *f, struct mtk_video_fmt *fmt)
+static int vidioc_try_fmt(struct v4l2_format *f,
+ const struct mtk_video_fmt *fmt)
{
struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
int i;
@@ -419,7 +420,7 @@ static int vidioc_venc_s_fmt_cap(struct file *file, void *priv,
struct vb2_queue *vq;
struct mtk_q_data *q_data;
int i, ret;
- struct mtk_video_fmt *fmt;
+ const struct mtk_video_fmt *fmt;
vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
if (!vq) {
@@ -481,7 +482,7 @@ static int vidioc_venc_s_fmt_out(struct file *file, void *priv,
struct vb2_queue *vq;
struct mtk_q_data *q_data;
int ret, i;
- struct mtk_video_fmt *fmt;
+ const struct mtk_video_fmt *fmt;
struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
@@ -580,7 +581,7 @@ static int vidioc_venc_g_fmt(struct file *file, void *priv,
static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct mtk_video_fmt *fmt;
+ const struct mtk_video_fmt *fmt;
struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
fmt = mtk_venc_find_format(f);
@@ -599,7 +600,7 @@ static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv,
static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct mtk_video_fmt *fmt;
+ const struct mtk_video_fmt *fmt;
fmt = mtk_venc_find_format(f);
if (!fmt) {
@@ -717,8 +718,8 @@ const struct v4l2_ioctl_ops mtk_venc_ioctl_ops = {
.vidioc_dqbuf = vidioc_venc_dqbuf,
.vidioc_querycap = vidioc_venc_querycap,
- .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane,
- .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
.vidioc_enum_framesizes = vidioc_enum_framesizes,
.vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap_mplane,
@@ -864,12 +865,18 @@ static int vb2ops_venc_start_streaming(struct vb2_queue *q, unsigned int count)
err_set_param:
for (i = 0; i < q->num_buffers; ++i) {
- if (q->bufs[i]->state == VB2_BUF_STATE_ACTIVE) {
+ struct vb2_buffer *buf = vb2_get_buffer(q, i);
+
+ /*
+ * FIXME: This check is not needed as only active buffers
+ * can be marked as done.
+ */
+ if (buf->state == VB2_BUF_STATE_ACTIVE) {
mtk_v4l2_debug(0, "[%d] id=%d, type=%d, %d -> VB2_BUF_STATE_QUEUED",
ctx->id, i, q->type,
- (int)q->bufs[i]->state);
- v4l2_m2m_buf_done(to_vb2_v4l2_buffer(q->bufs[i]),
- VB2_BUF_STATE_QUEUED);
+ (int)buf->state);
+ v4l2_m2m_buf_done(to_vb2_v4l2_buffer(buf),
+ VB2_BUF_STATE_QUEUED);
}
}
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.h
index 8248cb628882..a9c9f86b9c83 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.h
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: PC Chen <pc.chen@mediatek.com>
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
index b15e9d2ef6a9..1d82aa2b6017 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: PC Chen <pc.chen@mediatek.com>
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c
index 4740ae5e9a8e..3e2bfded79a6 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: Tiffany Lin <tiffany.lin@mediatek.com>
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.h
index 63165fc1b84a..b7ecdfd74823 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.h
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: Tiffany Lin <tiffany.lin@mediatek.com>
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.c
index f8aae7cc5f57..a3c7a380c930 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: Tiffany Lin <tiffany.lin@mediatek.com>
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.h
index ba632528fa72..638cd1f3526a 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.h
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: Tiffany Lin <tiffany.lin@mediatek.com>
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c
index 13f7061bfb50..d48f542db1a9 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: PC Chen <pc.chen@mediatek.com>
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h
index 677adb990e28..b999d7b84ed1 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: PC Chen <pc.chen@mediatek.com>
diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c
index 455dbe4887c1..c5f8f1fca44c 100644
--- a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c
+++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: PC Chen <pc.chen@mediatek.com>
@@ -266,7 +266,7 @@ static void get_dpb_size(struct vdec_h264_inst *inst, unsigned int *dpb_sz)
mtk_vcodec_debug(inst, "sz=%d", *dpb_sz);
}
-static int vdec_h264_init(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec)
+static int vdec_h264_init(struct mtk_vcodec_ctx *ctx)
{
struct vdec_h264_inst *inst = NULL;
int err;
@@ -295,7 +295,7 @@ static int vdec_h264_init(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec)
mtk_vcodec_debug(inst, "H264 Instance >> %p", inst);
- *h_vdec = (unsigned long)inst;
+ ctx->drv_handle = inst;
return 0;
error_deinit:
@@ -306,7 +306,7 @@ error_free_inst:
return err;
}
-static void vdec_h264_deinit(unsigned long h_vdec)
+static void vdec_h264_deinit(void *h_vdec)
{
struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec;
@@ -331,7 +331,7 @@ static int find_start_code(unsigned char *data, unsigned int data_sz)
return -1;
}
-static int vdec_h264_decode(unsigned long h_vdec, struct mtk_vcodec_mem *bs,
+static int vdec_h264_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
struct vdec_fb *fb, bool *res_chg)
{
struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec;
@@ -451,8 +451,8 @@ static void vdec_h264_get_fb(struct vdec_h264_inst *inst,
list->count--;
}
-static int vdec_h264_get_param(unsigned long h_vdec,
- enum vdec_get_param_type type, void *out)
+static int vdec_h264_get_param(void *h_vdec, enum vdec_get_param_type type,
+ void *out)
{
struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec;
@@ -485,16 +485,9 @@ static int vdec_h264_get_param(unsigned long h_vdec,
return 0;
}
-static struct vdec_common_if vdec_h264_if = {
+const struct vdec_common_if vdec_h264_if = {
.init = vdec_h264_init,
.decode = vdec_h264_decode,
.get_param = vdec_h264_get_param,
.deinit = vdec_h264_deinit,
};
-
-struct vdec_common_if *get_h264_dec_comm_if(void);
-
-struct vdec_common_if *get_h264_dec_comm_if(void)
-{
- return &vdec_h264_if;
-}
diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c
index 91139cef6283..63a8708ce682 100644
--- a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c
+++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: Jungchang Tsao <jungchang.tsao@mediatek.com>
@@ -388,7 +388,7 @@ static void free_working_buf(struct vdec_vp8_inst *inst)
inst->vsi->dec.working_buf_dma = 0;
}
-static int vdec_vp8_init(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec)
+static int vdec_vp8_init(struct mtk_vcodec_ctx *ctx)
{
struct vdec_vp8_inst *inst;
int err;
@@ -419,7 +419,7 @@ static int vdec_vp8_init(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec)
get_hw_reg_base(inst);
mtk_vcodec_debug(inst, "VP8 Instance >> %p", inst);
- *h_vdec = (unsigned long)inst;
+ ctx->drv_handle = inst;
return 0;
error_deinit:
@@ -429,7 +429,7 @@ error_free_inst:
return err;
}
-static int vdec_vp8_decode(unsigned long h_vdec, struct mtk_vcodec_mem *bs,
+static int vdec_vp8_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
struct vdec_fb *fb, bool *res_chg)
{
struct vdec_vp8_inst *inst = (struct vdec_vp8_inst *)h_vdec;
@@ -565,8 +565,8 @@ static void get_crop_info(struct vdec_vp8_inst *inst, struct v4l2_rect *cr)
cr->left, cr->top, cr->width, cr->height);
}
-static int vdec_vp8_get_param(unsigned long h_vdec,
- enum vdec_get_param_type type, void *out)
+static int vdec_vp8_get_param(void *h_vdec, enum vdec_get_param_type type,
+ void *out)
{
struct vdec_vp8_inst *inst = (struct vdec_vp8_inst *)h_vdec;
@@ -599,7 +599,7 @@ static int vdec_vp8_get_param(unsigned long h_vdec,
return 0;
}
-static void vdec_vp8_deinit(unsigned long h_vdec)
+static void vdec_vp8_deinit(void *h_vdec)
{
struct vdec_vp8_inst *inst = (struct vdec_vp8_inst *)h_vdec;
@@ -610,16 +610,9 @@ static void vdec_vp8_deinit(unsigned long h_vdec)
kfree(inst);
}
-static struct vdec_common_if vdec_vp8_if = {
+const struct vdec_common_if vdec_vp8_if = {
.init = vdec_vp8_init,
.decode = vdec_vp8_decode,
.get_param = vdec_vp8_get_param,
.deinit = vdec_vp8_deinit,
};
-
-struct vdec_common_if *get_vp8_dec_comm_if(void);
-
-struct vdec_common_if *get_vp8_dec_comm_if(void)
-{
- return &vdec_vp8_if;
-}
diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c
index c1904ad5e69b..5066c283d86d 100644
--- a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c
+++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: Daniel Hsiao <daniel.hsiao@mediatek.com>
@@ -757,7 +757,7 @@ static int validate_vsi_array_indexes(struct vdec_vp9_inst *inst,
return 0;
}
-static void vdec_vp9_deinit(unsigned long h_vdec)
+static void vdec_vp9_deinit(void *h_vdec)
{
struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec;
struct mtk_vcodec_mem *mem;
@@ -779,7 +779,7 @@ static void vdec_vp9_deinit(unsigned long h_vdec)
vp9_free_inst(inst);
}
-static int vdec_vp9_init(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec)
+static int vdec_vp9_init(struct mtk_vcodec_ctx *ctx)
{
struct vdec_vp9_inst *inst;
@@ -803,7 +803,7 @@ static int vdec_vp9_init(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec)
inst->vsi = (struct vdec_vp9_vsi *)inst->vpu.vsi;
init_all_fb_lists(inst);
- (*h_vdec) = (unsigned long)inst;
+ ctx->drv_handle = inst;
return 0;
err_deinit_inst:
@@ -812,8 +812,8 @@ err_deinit_inst:
return -EINVAL;
}
-static int vdec_vp9_decode(unsigned long h_vdec, struct mtk_vcodec_mem *bs,
- struct vdec_fb *fb, bool *res_chg)
+static int vdec_vp9_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
+ struct vdec_fb *fb, bool *res_chg)
{
int ret = 0;
struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec;
@@ -969,8 +969,8 @@ static void get_crop_info(struct vdec_vp9_inst *inst, struct v4l2_rect *cr)
cr->left, cr->top, cr->width, cr->height);
}
-static int vdec_vp9_get_param(unsigned long h_vdec,
- enum vdec_get_param_type type, void *out)
+static int vdec_vp9_get_param(void *h_vdec, enum vdec_get_param_type type,
+ void *out)
{
struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec;
int ret = 0;
@@ -1000,16 +1000,9 @@ static int vdec_vp9_get_param(unsigned long h_vdec,
return ret;
}
-static struct vdec_common_if vdec_vp9_if = {
+const struct vdec_common_if vdec_vp9_if = {
.init = vdec_vp9_init,
.decode = vdec_vp9_decode,
.get_param = vdec_vp9_get_param,
.deinit = vdec_vp9_deinit,
};
-
-struct vdec_common_if *get_vp9_dec_comm_if(void);
-
-struct vdec_common_if *get_vp9_dec_comm_if(void)
-{
- return &vdec_vp9_if;
-}
diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_base.h b/drivers/media/platform/mtk-vcodec/vdec_drv_base.h
index b6cb922fc400..ceb4db4cb3be 100644
--- a/drivers/media/platform/mtk-vcodec/vdec_drv_base.h
+++ b/drivers/media/platform/mtk-vcodec/vdec_drv_base.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: PC Chen <pc.chen@mediatek.com>
@@ -17,7 +17,7 @@ struct vdec_common_if {
* @ctx : [in] mtk v4l2 context
* @h_vdec : [out] driver handle
*/
- int (*init)(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec);
+ int (*init)(struct mtk_vcodec_ctx *ctx);
/**
* (*decode)() - trigger decode
@@ -26,7 +26,7 @@ struct vdec_common_if {
* @fb : [in] frame buffer to store decoded frame
* @res_chg : [out] resolution change happen
*/
- int (*decode)(unsigned long h_vdec, struct mtk_vcodec_mem *bs,
+ int (*decode)(void *h_vdec, struct mtk_vcodec_mem *bs,
struct vdec_fb *fb, bool *res_chg);
/**
@@ -35,14 +35,14 @@ struct vdec_common_if {
* @type : [in] input parameter type
* @out : [out] buffer to store query result
*/
- int (*get_param)(unsigned long h_vdec, enum vdec_get_param_type type,
+ int (*get_param)(void *h_vdec, enum vdec_get_param_type type,
void *out);
/**
* (*deinit)() - deinitialize driver.
* @h_vdec : [in] driver handle to be deinit
*/
- void (*deinit)(unsigned long h_vdec);
+ void (*deinit)(void *h_vdec);
};
#endif
diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c
index 5c98a76a77b7..2e43dd4486e0 100644
--- a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c
+++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: PC Chen <pc.chen@mediatek.com>
@@ -15,23 +15,19 @@
#include "mtk_vcodec_dec_pm.h"
#include "mtk_vpu.h"
-const struct vdec_common_if *get_h264_dec_comm_if(void);
-const struct vdec_common_if *get_vp8_dec_comm_if(void);
-const struct vdec_common_if *get_vp9_dec_comm_if(void);
-
int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc)
{
int ret = 0;
switch (fourcc) {
case V4L2_PIX_FMT_H264:
- ctx->dec_if = get_h264_dec_comm_if();
+ ctx->dec_if = &vdec_h264_if;
break;
case V4L2_PIX_FMT_VP8:
- ctx->dec_if = get_vp8_dec_comm_if();
+ ctx->dec_if = &vdec_vp8_if;
break;
case V4L2_PIX_FMT_VP9:
- ctx->dec_if = get_vp9_dec_comm_if();
+ ctx->dec_if = &vdec_vp9_if;
break;
default:
return -EINVAL;
@@ -39,7 +35,7 @@ int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc)
mtk_vdec_lock(ctx);
mtk_vcodec_dec_clock_on(&ctx->dev->pm);
- ret = ctx->dec_if->init(ctx, &ctx->drv_handle);
+ ret = ctx->dec_if->init(ctx);
mtk_vcodec_dec_clock_off(&ctx->dev->pm);
mtk_vdec_unlock(ctx);
@@ -66,7 +62,7 @@ int vdec_if_decode(struct mtk_vcodec_ctx *ctx, struct mtk_vcodec_mem *bs,
}
}
- if (ctx->drv_handle == 0)
+ if (!ctx->drv_handle)
return -EIO;
mtk_vdec_lock(ctx);
@@ -89,7 +85,7 @@ int vdec_if_get_param(struct mtk_vcodec_ctx *ctx, enum vdec_get_param_type type,
{
int ret = 0;
- if (ctx->drv_handle == 0)
+ if (!ctx->drv_handle)
return -EIO;
mtk_vdec_lock(ctx);
@@ -101,7 +97,7 @@ int vdec_if_get_param(struct mtk_vcodec_ctx *ctx, enum vdec_get_param_type type,
void vdec_if_deinit(struct mtk_vcodec_ctx *ctx)
{
- if (ctx->drv_handle == 0)
+ if (!ctx->drv_handle)
return;
mtk_vdec_lock(ctx);
@@ -110,5 +106,5 @@ void vdec_if_deinit(struct mtk_vcodec_ctx *ctx)
mtk_vcodec_dec_clock_off(&ctx->dev->pm);
mtk_vdec_unlock(ctx);
- ctx->drv_handle = 0;
+ ctx->drv_handle = NULL;
}
diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.h b/drivers/media/platform/mtk-vcodec/vdec_drv_if.h
index 409623574145..270d8dc9984b 100644
--- a/drivers/media/platform/mtk-vcodec/vdec_drv_if.h
+++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: PC Chen <pc.chen@mediatek.com>
@@ -54,6 +54,10 @@ struct vdec_fb_node {
struct vdec_fb *fb;
};
+extern const struct vdec_common_if vdec_h264_if;
+extern const struct vdec_common_if vdec_vp8_if;
+extern const struct vdec_common_if vdec_vp9_if;
+
/**
* vdec_if_init() - initialize decode driver
* @ctx : [in] v4l2 context
diff --git a/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h b/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h
index b05dcdeb7734..47a1c1c0fd04 100644
--- a/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h
+++ b/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: PC Chen <pc.chen@mediatek.com>
diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c
index 035ba917ed0e..3f38cc4509ef 100644
--- a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c
+++ b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: PC Chen <pc.chen@mediatek.com>
diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h
index 6701778ea5d9..b76f717e4fd7 100644
--- a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h
+++ b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: PC Chen <pc.chen@mediatek.com>
diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
index 3125eaf2a326..b9624f8df0e9 100644
--- a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
+++ b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: Jungchang Tsao <jungchang.tsao@mediatek.com>
@@ -458,7 +458,7 @@ static void h264_encode_filler(struct venc_h264_inst *inst, void *buf,
memset(p, 0xff, size);
}
-static int h264_enc_init(struct mtk_vcodec_ctx *ctx, unsigned long *handle)
+static int h264_enc_init(struct mtk_vcodec_ctx *ctx)
{
int ret = 0;
struct venc_h264_inst *inst;
@@ -484,12 +484,12 @@ static int h264_enc_init(struct mtk_vcodec_ctx *ctx, unsigned long *handle)
if (ret)
kfree(inst);
else
- (*handle) = (unsigned long)inst;
+ ctx->drv_handle = inst;
return ret;
}
-static int h264_enc_encode(unsigned long handle,
+static int h264_enc_encode(void *handle,
enum venc_start_opt opt,
struct venc_frm_buf *frm_buf,
struct mtk_vcodec_mem *bs_buf,
@@ -584,7 +584,7 @@ encode_err:
return ret;
}
-static int h264_enc_set_param(unsigned long handle,
+static int h264_enc_set_param(void *handle,
enum venc_set_param_type type,
struct venc_enc_param *enc_prm)
{
@@ -637,7 +637,7 @@ static int h264_enc_set_param(unsigned long handle,
return ret;
}
-static int h264_enc_deinit(unsigned long handle)
+static int h264_enc_deinit(void *handle)
{
int ret = 0;
struct venc_h264_inst *inst = (struct venc_h264_inst *)handle;
@@ -655,16 +655,9 @@ static int h264_enc_deinit(unsigned long handle)
return ret;
}
-static const struct venc_common_if venc_h264_if = {
+const struct venc_common_if venc_h264_if = {
.init = h264_enc_init,
.encode = h264_enc_encode,
.set_param = h264_enc_set_param,
.deinit = h264_enc_deinit,
};
-
-const struct venc_common_if *get_h264_enc_comm_if(void);
-
-const struct venc_common_if *get_h264_enc_comm_if(void)
-{
- return &venc_h264_if;
-}
diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c
index ba19cdc4e4f1..8d36f0362efe 100644
--- a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c
+++ b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: Daniel Hsiao <daniel.hsiao@mediatek.com>
@@ -323,7 +323,7 @@ static int vp8_enc_encode_frame(struct venc_vp8_inst *inst,
return ret;
}
-static int vp8_enc_init(struct mtk_vcodec_ctx *ctx, unsigned long *handle)
+static int vp8_enc_init(struct mtk_vcodec_ctx *ctx)
{
int ret = 0;
struct venc_vp8_inst *inst;
@@ -349,12 +349,12 @@ static int vp8_enc_init(struct mtk_vcodec_ctx *ctx, unsigned long *handle)
if (ret)
kfree(inst);
else
- (*handle) = (unsigned long)inst;
+ ctx->drv_handle = inst;
return ret;
}
-static int vp8_enc_encode(unsigned long handle,
+static int vp8_enc_encode(void *handle,
enum venc_start_opt opt,
struct venc_frm_buf *frm_buf,
struct mtk_vcodec_mem *bs_buf,
@@ -391,7 +391,7 @@ encode_err:
return ret;
}
-static int vp8_enc_set_param(unsigned long handle,
+static int vp8_enc_set_param(void *handle,
enum venc_set_param_type type,
struct venc_enc_param *enc_prm)
{
@@ -442,7 +442,7 @@ static int vp8_enc_set_param(unsigned long handle,
return ret;
}
-static int vp8_enc_deinit(unsigned long handle)
+static int vp8_enc_deinit(void *handle)
{
int ret = 0;
struct venc_vp8_inst *inst = (struct venc_vp8_inst *)handle;
@@ -460,16 +460,9 @@ static int vp8_enc_deinit(unsigned long handle)
return ret;
}
-static const struct venc_common_if venc_vp8_if = {
+const struct venc_common_if venc_vp8_if = {
.init = vp8_enc_init,
.encode = vp8_enc_encode,
.set_param = vp8_enc_set_param,
.deinit = vp8_enc_deinit,
};
-
-const struct venc_common_if *get_vp8_enc_comm_if(void);
-
-const struct venc_common_if *get_vp8_enc_comm_if(void)
-{
- return &venc_vp8_if;
-}
diff --git a/drivers/media/platform/mtk-vcodec/venc_drv_base.h b/drivers/media/platform/mtk-vcodec/venc_drv_base.h
index 81620683b94f..3d718411dc73 100644
--- a/drivers/media/platform/mtk-vcodec/venc_drv_base.h
+++ b/drivers/media/platform/mtk-vcodec/venc_drv_base.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: Daniel Hsiao <daniel.hsiao@mediatek.com>
@@ -19,7 +19,7 @@ struct venc_common_if {
* @ctx: [in] mtk v4l2 context
* @handle: [out] driver handle
*/
- int (*init)(struct mtk_vcodec_ctx *ctx, unsigned long *handle);
+ int (*init)(struct mtk_vcodec_ctx *ctx);
/**
* (*encode)() - trigger encode
@@ -29,7 +29,7 @@ struct venc_common_if {
* @bs_buf: [in] bitstream buffer to store output bitstream
* @result: [out] encode result
*/
- int (*encode)(unsigned long handle, enum venc_start_opt opt,
+ int (*encode)(void *handle, enum venc_start_opt opt,
struct venc_frm_buf *frm_buf,
struct mtk_vcodec_mem *bs_buf,
struct venc_done_result *result);
@@ -40,14 +40,14 @@ struct venc_common_if {
* @type: [in] parameter type
* @in: [in] buffer to store the parameter
*/
- int (*set_param)(unsigned long handle, enum venc_set_param_type type,
+ int (*set_param)(void *handle, enum venc_set_param_type type,
struct venc_enc_param *in);
/**
* (*deinit)() - deinitialize driver.
* @handle: [in] driver handle
*/
- int (*deinit)(unsigned long handle);
+ int (*deinit)(void *handle);
};
#endif
diff --git a/drivers/media/platform/mtk-vcodec/venc_drv_if.c b/drivers/media/platform/mtk-vcodec/venc_drv_if.c
index 608c08b2ab8f..c6bb82ac2dcd 100644
--- a/drivers/media/platform/mtk-vcodec/venc_drv_if.c
+++ b/drivers/media/platform/mtk-vcodec/venc_drv_if.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: Daniel Hsiao <daniel.hsiao@mediatek.com>
@@ -17,19 +17,16 @@
#include "mtk_vcodec_enc_pm.h"
#include "mtk_vpu.h"
-const struct venc_common_if *get_h264_enc_comm_if(void);
-const struct venc_common_if *get_vp8_enc_comm_if(void);
-
int venc_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc)
{
int ret = 0;
switch (fourcc) {
case V4L2_PIX_FMT_VP8:
- ctx->enc_if = get_vp8_enc_comm_if();
+ ctx->enc_if = &venc_vp8_if;
break;
case V4L2_PIX_FMT_H264:
- ctx->enc_if = get_h264_enc_comm_if();
+ ctx->enc_if = &venc_h264_if;
break;
default:
return -EINVAL;
@@ -37,7 +34,7 @@ int venc_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc)
mtk_venc_lock(ctx);
mtk_vcodec_enc_clock_on(&ctx->dev->pm);
- ret = ctx->enc_if->init(ctx, (unsigned long *)&ctx->drv_handle);
+ ret = ctx->enc_if->init(ctx);
mtk_vcodec_enc_clock_off(&ctx->dev->pm);
mtk_venc_unlock(ctx);
@@ -89,7 +86,7 @@ int venc_if_deinit(struct mtk_vcodec_ctx *ctx)
{
int ret = 0;
- if (ctx->drv_handle == 0)
+ if (!ctx->drv_handle)
return 0;
mtk_venc_lock(ctx);
@@ -98,7 +95,7 @@ int venc_if_deinit(struct mtk_vcodec_ctx *ctx)
mtk_vcodec_enc_clock_off(&ctx->dev->pm);
mtk_venc_unlock(ctx);
- ctx->drv_handle = 0;
+ ctx->drv_handle = NULL;
return ret;
}
diff --git a/drivers/media/platform/mtk-vcodec/venc_drv_if.h b/drivers/media/platform/mtk-vcodec/venc_drv_if.h
index bbba1cec7be4..52fc9cc812fc 100644
--- a/drivers/media/platform/mtk-vcodec/venc_drv_if.h
+++ b/drivers/media/platform/mtk-vcodec/venc_drv_if.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: Daniel Hsiao <daniel.hsiao@mediatek.com>
@@ -110,6 +110,9 @@ struct venc_done_result {
bool is_key_frm;
};
+extern const struct venc_common_if venc_h264_if;
+extern const struct venc_common_if venc_vp8_if;
+
/*
* venc_if_init - Create the driver handle
* @ctx: device context
diff --git a/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h b/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h
index be34780760f4..28ee04ca6241 100644
--- a/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h
+++ b/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: Jungchang Tsao <jungchang.tsao@mediatek.com>
diff --git a/drivers/media/platform/mtk-vcodec/venc_vpu_if.c b/drivers/media/platform/mtk-vcodec/venc_vpu_if.c
index 7daf8694c62e..3e931b0ed096 100644
--- a/drivers/media/platform/mtk-vcodec/venc_vpu_if.c
+++ b/drivers/media/platform/mtk-vcodec/venc_vpu_if.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: PoChun Lin <pochun.lin@mediatek.com>
diff --git a/drivers/media/platform/mtk-vcodec/venc_vpu_if.h b/drivers/media/platform/mtk-vcodec/venc_vpu_if.h
index a6b6d0eafb50..ba301a138a5a 100644
--- a/drivers/media/platform/mtk-vcodec/venc_vpu_if.h
+++ b/drivers/media/platform/mtk-vcodec/venc_vpu_if.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: PoChun Lin <pochun.lin@mediatek.com>
diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.c b/drivers/media/platform/mtk-vpu/mtk_vpu.c
index da655d166d52..cc2ff40d060d 100644
--- a/drivers/media/platform/mtk-vpu/mtk_vpu.c
+++ b/drivers/media/platform/mtk-vpu/mtk_vpu.c
@@ -460,9 +460,9 @@ struct platform_device *vpu_get_plat_device(struct platform_device *pdev)
}
vpu_pdev = of_find_device_by_node(vpu_node);
+ of_node_put(vpu_node);
if (WARN_ON(!vpu_pdev)) {
dev_err(dev, "vpu pdev failed\n");
- of_node_put(vpu_node);
return NULL;
}
diff --git a/drivers/media/platform/omap/Kconfig b/drivers/media/platform/omap/Kconfig
index 08a606a5adff..1a99dff21ca0 100644
--- a/drivers/media/platform/omap/Kconfig
+++ b/drivers/media/platform/omap/Kconfig
@@ -14,6 +14,5 @@ config VIDEO_OMAP2_VOUT
select VIDEOBUF_DMA_CONTIG
select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3
select FRAME_VECTOR
- default n
help
V4L2 Display driver support for OMAP2/3 based boards.
diff --git a/drivers/media/platform/omap3isp/cfa_coef_table.h b/drivers/media/platform/omap3isp/cfa_coef_table.h
index e75b0eb2519b..786200c5e4fa 100644
--- a/drivers/media/platform/omap3isp/cfa_coef_table.h
+++ b/drivers/media/platform/omap3isp/cfa_coef_table.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* cfa_coef_table.h
*
@@ -7,10 +8,6 @@
*
* Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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.
*/
{ 244, 0, 247, 0, 12, 27, 36, 247, 250, 0, 27, 0, 4, 250, 12, 244,
diff --git a/drivers/media/platform/omap3isp/gamma_table.h b/drivers/media/platform/omap3isp/gamma_table.h
index 3b507078016d..442c82c2eb22 100644
--- a/drivers/media/platform/omap3isp/gamma_table.h
+++ b/drivers/media/platform/omap3isp/gamma_table.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* gamma_table.h
*
@@ -8,10 +9,6 @@
*
* Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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.
*/
0, 0, 1, 2, 3, 3, 4, 5, 6, 8, 10, 12, 14, 16, 18, 20,
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
index bd57174d81a7..83216fc7156b 100644
--- a/drivers/media/platform/omap3isp/isp.c
+++ b/drivers/media/platform/omap3isp/isp.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* isp.c
*
@@ -36,10 +37,6 @@
* Thara Gopinath <thara@ti.com>
* Toni Leinonen <toni.leinonen@nokia.com>
* Troy Laramy <t-laramy@ti.com>
- *
- * 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.
*/
#include <asm/cacheflush.h>
@@ -2006,6 +2003,8 @@ static int isp_remove(struct platform_device *pdev)
media_entity_enum_cleanup(&isp->crashed);
v4l2_async_notifier_cleanup(&isp->notifier);
+ kfree(isp);
+
return 0;
}
@@ -2196,7 +2195,7 @@ static int isp_probe(struct platform_device *pdev)
int ret;
int i, m;
- isp = devm_kzalloc(&pdev->dev, sizeof(*isp), GFP_KERNEL);
+ isp = kzalloc(sizeof(*isp), GFP_KERNEL);
if (!isp) {
dev_err(&pdev->dev, "could not allocate memory\n");
return -ENOMEM;
@@ -2205,17 +2204,19 @@ static int isp_probe(struct platform_device *pdev)
ret = fwnode_property_read_u32(of_fwnode_handle(pdev->dev.of_node),
"ti,phy-type", &isp->phy_type);
if (ret)
- return ret;
+ goto error_release_isp;
isp->syscon = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
"syscon");
- if (IS_ERR(isp->syscon))
- return PTR_ERR(isp->syscon);
+ if (IS_ERR(isp->syscon)) {
+ ret = PTR_ERR(isp->syscon);
+ goto error_release_isp;
+ }
ret = of_property_read_u32_index(pdev->dev.of_node,
"syscon", 1, &isp->syscon_offset);
if (ret)
- return ret;
+ goto error_release_isp;
isp->autoidle = autoidle;
@@ -2372,6 +2373,8 @@ error_isp:
error:
v4l2_async_notifier_cleanup(&isp->notifier);
mutex_destroy(&isp->isp_mutex);
+error_release_isp:
+ kfree(isp);
return ret;
}
@@ -2383,7 +2386,7 @@ static const struct dev_pm_ops omap3isp_pm_ops = {
.complete = isp_pm_complete,
};
-static struct platform_device_id omap3isp_id_table[] = {
+static const struct platform_device_id omap3isp_id_table[] = {
{ "omap3isp", 0 },
{ },
};
diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h
index 8b9043db94b3..a9d760fbf349 100644
--- a/drivers/media/platform/omap3isp/isp.h
+++ b/drivers/media/platform/omap3isp/isp.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* isp.h
*
@@ -8,10 +9,6 @@
*
* Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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.
*/
#ifndef OMAP3_ISP_CORE_H
diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c
index 261ad1175f98..1ba8a5ba343f 100644
--- a/drivers/media/platform/omap3isp/ispccdc.c
+++ b/drivers/media/platform/omap3isp/ispccdc.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ispccdc.c
*
@@ -8,10 +9,6 @@
*
* Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/media/platform/omap3isp/ispccdc.h b/drivers/media/platform/omap3isp/ispccdc.h
index 3440a7097940..7883365d7203 100644
--- a/drivers/media/platform/omap3isp/ispccdc.h
+++ b/drivers/media/platform/omap3isp/ispccdc.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* ispccdc.h
*
@@ -8,10 +9,6 @@
*
* Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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.
*/
#ifndef OMAP3_ISP_CCDC_H
diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c
index 2dea423ffc0e..efca45bb02c8 100644
--- a/drivers/media/platform/omap3isp/ispccp2.c
+++ b/drivers/media/platform/omap3isp/ispccp2.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ispccp2.c
*
@@ -8,10 +9,6 @@
*
* Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/media/platform/omap3isp/ispccp2.h b/drivers/media/platform/omap3isp/ispccp2.h
index 4662bffa79e3..03e6af3de1d9 100644
--- a/drivers/media/platform/omap3isp/ispccp2.h
+++ b/drivers/media/platform/omap3isp/ispccp2.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* ispccp2.h
*
@@ -8,10 +9,6 @@
*
* Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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.
*/
#ifndef OMAP3_ISP_CCP2_H
diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c
index da66ea65be5d..e85917f4a50c 100644
--- a/drivers/media/platform/omap3isp/ispcsi2.c
+++ b/drivers/media/platform/omap3isp/ispcsi2.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ispcsi2.c
*
@@ -8,10 +9,6 @@
*
* Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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.
*/
#include <linux/delay.h>
#include <media/v4l2-common.h>
diff --git a/drivers/media/platform/omap3isp/ispcsi2.h b/drivers/media/platform/omap3isp/ispcsi2.h
index 453ed62fe394..036b97f8470e 100644
--- a/drivers/media/platform/omap3isp/ispcsi2.h
+++ b/drivers/media/platform/omap3isp/ispcsi2.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* ispcsi2.h
*
@@ -8,10 +9,6 @@
*
* Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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.
*/
#ifndef OMAP3_ISP_CSI2_H
diff --git a/drivers/media/platform/omap3isp/ispcsiphy.c b/drivers/media/platform/omap3isp/ispcsiphy.c
index a28fb79abaac..6dc7359c5131 100644
--- a/drivers/media/platform/omap3isp/ispcsiphy.c
+++ b/drivers/media/platform/omap3isp/ispcsiphy.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ispcsiphy.c
*
@@ -8,10 +9,6 @@
*
* Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/media/platform/omap3isp/ispcsiphy.h b/drivers/media/platform/omap3isp/ispcsiphy.h
index 91543a09b28a..ed9b8d221e3f 100644
--- a/drivers/media/platform/omap3isp/ispcsiphy.h
+++ b/drivers/media/platform/omap3isp/ispcsiphy.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* ispcsiphy.h
*
@@ -8,10 +9,6 @@
*
* Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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.
*/
#ifndef OMAP3_ISP_CSI_PHY_H
diff --git a/drivers/media/platform/omap3isp/isph3a.h b/drivers/media/platform/omap3isp/isph3a.h
index e5b28d0f3b0f..5144f7689dda 100644
--- a/drivers/media/platform/omap3isp/isph3a.h
+++ b/drivers/media/platform/omap3isp/isph3a.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* isph3a.h
*
@@ -9,10 +10,6 @@
* Contacts: David Cohen <dacohen@gmail.com>
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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.
*/
#ifndef OMAP3_ISP_H3A_H
diff --git a/drivers/media/platform/omap3isp/isph3a_aewb.c b/drivers/media/platform/omap3isp/isph3a_aewb.c
index 3c82dea4d375..e6c54c4bbfca 100644
--- a/drivers/media/platform/omap3isp/isph3a_aewb.c
+++ b/drivers/media/platform/omap3isp/isph3a_aewb.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* isph3a.c
*
@@ -9,10 +10,6 @@
* Contacts: David Cohen <dacohen@gmail.com>
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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.
*/
#include <linux/slab.h>
@@ -291,9 +288,10 @@ int omap3isp_h3a_aewb_init(struct isp_device *isp)
{
struct ispstat *aewb = &isp->isp_aewb;
struct omap3isp_h3a_aewb_config *aewb_cfg;
- struct omap3isp_h3a_aewb_config *aewb_recover_cfg;
+ struct omap3isp_h3a_aewb_config *aewb_recover_cfg = NULL;
+ int ret;
- aewb_cfg = devm_kzalloc(isp->dev, sizeof(*aewb_cfg), GFP_KERNEL);
+ aewb_cfg = kzalloc(sizeof(*aewb_cfg), GFP_KERNEL);
if (!aewb_cfg)
return -ENOMEM;
@@ -303,12 +301,12 @@ int omap3isp_h3a_aewb_init(struct isp_device *isp)
aewb->isp = isp;
/* Set recover state configuration */
- aewb_recover_cfg = devm_kzalloc(isp->dev, sizeof(*aewb_recover_cfg),
- GFP_KERNEL);
+ aewb_recover_cfg = kzalloc(sizeof(*aewb_recover_cfg), GFP_KERNEL);
if (!aewb_recover_cfg) {
dev_err(aewb->isp->dev,
"AEWB: cannot allocate memory for recover configuration.\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err;
}
aewb_recover_cfg->saturation_limit = OMAP3ISP_AEWB_MAX_SATURATION_LIM;
@@ -325,13 +323,22 @@ int omap3isp_h3a_aewb_init(struct isp_device *isp)
if (h3a_aewb_validate_params(aewb, aewb_recover_cfg)) {
dev_err(aewb->isp->dev,
"AEWB: recover configuration is invalid.\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err;
}
aewb_recover_cfg->buf_size = h3a_aewb_get_buf_size(aewb_recover_cfg);
aewb->recover_priv = aewb_recover_cfg;
- return omap3isp_stat_init(aewb, "AEWB", &h3a_aewb_subdev_ops);
+ ret = omap3isp_stat_init(aewb, "AEWB", &h3a_aewb_subdev_ops);
+
+err:
+ if (ret) {
+ kfree(aewb_cfg);
+ kfree(aewb_recover_cfg);
+ }
+
+ return ret;
}
/*
diff --git a/drivers/media/platform/omap3isp/isph3a_af.c b/drivers/media/platform/omap3isp/isph3a_af.c
index 4da25c84f0c6..a65cfdfa9637 100644
--- a/drivers/media/platform/omap3isp/isph3a_af.c
+++ b/drivers/media/platform/omap3isp/isph3a_af.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* isph3a_af.c
*
@@ -9,10 +10,6 @@
* Contacts: David Cohen <dacohen@gmail.com>
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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.
*/
/* Linux specific include files */
@@ -354,9 +351,10 @@ int omap3isp_h3a_af_init(struct isp_device *isp)
{
struct ispstat *af = &isp->isp_af;
struct omap3isp_h3a_af_config *af_cfg;
- struct omap3isp_h3a_af_config *af_recover_cfg;
+ struct omap3isp_h3a_af_config *af_recover_cfg = NULL;
+ int ret;
- af_cfg = devm_kzalloc(isp->dev, sizeof(*af_cfg), GFP_KERNEL);
+ af_cfg = kzalloc(sizeof(*af_cfg), GFP_KERNEL);
if (af_cfg == NULL)
return -ENOMEM;
@@ -366,12 +364,12 @@ int omap3isp_h3a_af_init(struct isp_device *isp)
af->isp = isp;
/* Set recover state configuration */
- af_recover_cfg = devm_kzalloc(isp->dev, sizeof(*af_recover_cfg),
- GFP_KERNEL);
+ af_recover_cfg = kzalloc(sizeof(*af_recover_cfg), GFP_KERNEL);
if (!af_recover_cfg) {
dev_err(af->isp->dev,
"AF: cannot allocate memory for recover configuration.\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err;
}
af_recover_cfg->paxel.h_start = OMAP3ISP_AF_PAXEL_HZSTART_MIN;
@@ -383,13 +381,22 @@ int omap3isp_h3a_af_init(struct isp_device *isp)
if (h3a_af_validate_params(af, af_recover_cfg)) {
dev_err(af->isp->dev,
"AF: recover configuration is invalid.\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err;
}
af_recover_cfg->buf_size = h3a_af_get_buf_size(af_recover_cfg);
af->recover_priv = af_recover_cfg;
- return omap3isp_stat_init(af, "AF", &h3a_af_subdev_ops);
+ ret = omap3isp_stat_init(af, "AF", &h3a_af_subdev_ops);
+
+err:
+ if (ret) {
+ kfree(af_cfg);
+ kfree(af_recover_cfg);
+ }
+
+ return ret;
}
void omap3isp_h3a_af_cleanup(struct isp_device *isp)
diff --git a/drivers/media/platform/omap3isp/isphist.c b/drivers/media/platform/omap3isp/isphist.c
index d4be3d0e06f9..0ef78aace6da 100644
--- a/drivers/media/platform/omap3isp/isphist.c
+++ b/drivers/media/platform/omap3isp/isphist.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* isphist.c
*
@@ -9,10 +10,6 @@
* Contacts: David Cohen <dacohen@gmail.com>
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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.
*/
#include <linux/delay.h>
@@ -478,9 +475,9 @@ int omap3isp_hist_init(struct isp_device *isp)
{
struct ispstat *hist = &isp->isp_hist;
struct omap3isp_hist_config *hist_cfg;
- int ret = -1;
+ int ret;
- hist_cfg = devm_kzalloc(isp->dev, sizeof(*hist_cfg), GFP_KERNEL);
+ hist_cfg = kzalloc(sizeof(*hist_cfg), GFP_KERNEL);
if (hist_cfg == NULL)
return -ENOMEM;
@@ -502,7 +499,7 @@ int omap3isp_hist_init(struct isp_device *isp)
if (IS_ERR(hist->dma_ch)) {
ret = PTR_ERR(hist->dma_ch);
if (ret == -EPROBE_DEFER)
- return ret;
+ goto err;
hist->dma_ch = NULL;
dev_warn(isp->dev,
@@ -518,9 +515,12 @@ int omap3isp_hist_init(struct isp_device *isp)
hist->event_type = V4L2_EVENT_OMAP3ISP_HIST;
ret = omap3isp_stat_init(hist, "histogram", &hist_subdev_ops);
+
+err:
if (ret) {
- if (hist->dma_ch)
+ if (!IS_ERR_OR_NULL(hist->dma_ch))
dma_release_channel(hist->dma_ch);
+ kfree(hist_cfg);
}
return ret;
diff --git a/drivers/media/platform/omap3isp/isphist.h b/drivers/media/platform/omap3isp/isphist.h
index 3b5415517dcd..93cd27a3b617 100644
--- a/drivers/media/platform/omap3isp/isphist.h
+++ b/drivers/media/platform/omap3isp/isphist.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* isphist.h
*
@@ -9,10 +10,6 @@
* Contacts: David Cohen <dacohen@gmail.com>
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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.
*/
#ifndef OMAP3_ISP_HIST_H
diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c
index 6ea6aeafd751..40e22400cf5e 100644
--- a/drivers/media/platform/omap3isp/isppreview.c
+++ b/drivers/media/platform/omap3isp/isppreview.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* isppreview.c
*
@@ -8,10 +9,6 @@
*
* Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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.
*/
#include <linux/device.h>
diff --git a/drivers/media/platform/omap3isp/isppreview.h b/drivers/media/platform/omap3isp/isppreview.h
index 16fdc03a3d43..5fff1ec3624f 100644
--- a/drivers/media/platform/omap3isp/isppreview.h
+++ b/drivers/media/platform/omap3isp/isppreview.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* isppreview.h
*
@@ -8,10 +9,6 @@
*
* Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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.
*/
#ifndef OMAP3_ISP_PREVIEW_H
diff --git a/drivers/media/platform/omap3isp/ispreg.h b/drivers/media/platform/omap3isp/ispreg.h
index d08483919a77..38e2b99b3f10 100644
--- a/drivers/media/platform/omap3isp/ispreg.h
+++ b/drivers/media/platform/omap3isp/ispreg.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* ispreg.h
*
@@ -8,10 +9,6 @@
*
* Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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.
*/
#ifndef OMAP3_ISP_REG_H
diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c
index b281cae036b3..21ca6954df72 100644
--- a/drivers/media/platform/omap3isp/ispresizer.c
+++ b/drivers/media/platform/omap3isp/ispresizer.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ispresizer.c
*
@@ -8,10 +9,6 @@
*
* Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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.
*/
#include <linux/device.h>
diff --git a/drivers/media/platform/omap3isp/ispresizer.h b/drivers/media/platform/omap3isp/ispresizer.h
index 5414542912e2..28cc89940ead 100644
--- a/drivers/media/platform/omap3isp/ispresizer.h
+++ b/drivers/media/platform/omap3isp/ispresizer.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* ispresizer.h
*
@@ -8,10 +9,6 @@
*
* Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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.
*/
#ifndef OMAP3_ISP_RESIZER_H
diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c
index 47353fee26c3..62b2eacb96fd 100644
--- a/drivers/media/platform/omap3isp/ispstat.c
+++ b/drivers/media/platform/omap3isp/ispstat.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ispstat.c
*
@@ -9,10 +10,6 @@
* Contacts: David Cohen <dacohen@gmail.com>
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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.
*/
#include <linux/dma-mapping.h>
@@ -1040,7 +1037,7 @@ static int isp_stat_init_entities(struct ispstat *stat, const char *name,
v4l2_subdev_init(subdev, sd_ops);
snprintf(subdev->name, V4L2_SUBDEV_NAME_SIZE, "OMAP3 ISP %s", name);
- subdev->grp_id = 1 << 16; /* group ID for isp subdevs */
+ subdev->grp_id = BIT(16); /* group ID for isp subdevs */
subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
v4l2_set_subdevdata(subdev, stat);
@@ -1078,4 +1075,6 @@ void omap3isp_stat_cleanup(struct ispstat *stat)
mutex_destroy(&stat->ioctl_lock);
isp_stat_bufs_free(stat);
kfree(stat->buf);
+ kfree(stat->priv);
+ kfree(stat->recover_priv);
}
diff --git a/drivers/media/platform/omap3isp/ispstat.h b/drivers/media/platform/omap3isp/ispstat.h
index 923b38cfc682..b548e617cf62 100644
--- a/drivers/media/platform/omap3isp/ispstat.h
+++ b/drivers/media/platform/omap3isp/ispstat.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* ispstat.h
*
@@ -9,10 +10,6 @@
* Contacts: David Cohen <dacohen@gmail.com>
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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.
*/
#ifndef OMAP3_ISP_STAT_H
diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c
index 078d64114b24..499a7284c5a8 100644
--- a/drivers/media/platform/omap3isp/ispvideo.c
+++ b/drivers/media/platform/omap3isp/ispvideo.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ispvideo.c
*
@@ -7,10 +8,6 @@
*
* Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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.
*/
#include <asm/cacheflush.h>
@@ -1495,6 +1492,5 @@ int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev)
void omap3isp_video_unregister(struct isp_video *video)
{
- if (video_is_registered(&video->video))
- video_unregister_device(&video->video);
+ video_unregister_device(&video->video);
}
diff --git a/drivers/media/platform/omap3isp/ispvideo.h b/drivers/media/platform/omap3isp/ispvideo.h
index f6a2082b4a0a..a0908670c0cf 100644
--- a/drivers/media/platform/omap3isp/ispvideo.h
+++ b/drivers/media/platform/omap3isp/ispvideo.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* ispvideo.h
*
@@ -7,10 +8,6 @@
*
* Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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.
*/
#ifndef OMAP3_ISP_VIDEO_H
diff --git a/drivers/media/platform/omap3isp/luma_enhance_table.h b/drivers/media/platform/omap3isp/luma_enhance_table.h
index 81c5b1566469..d5fbf9241f48 100644
--- a/drivers/media/platform/omap3isp/luma_enhance_table.h
+++ b/drivers/media/platform/omap3isp/luma_enhance_table.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* luma_enhance_table.h
*
@@ -8,10 +9,6 @@
*
* Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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.
*/
1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552,
diff --git a/drivers/media/platform/omap3isp/noise_filter_table.h b/drivers/media/platform/omap3isp/noise_filter_table.h
index 5073f9847937..da66bd0a3b9f 100644
--- a/drivers/media/platform/omap3isp/noise_filter_table.h
+++ b/drivers/media/platform/omap3isp/noise_filter_table.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* noise_filter_table.h
*
@@ -8,10 +9,6 @@
*
* Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Sakari Ailus <sakari.ailus@iki.fi>
- *
- * 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.
*/
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c
index 6addc5ea8494..1c9bfaabc54c 100644
--- a/drivers/media/platform/pxa_camera.c
+++ b/drivers/media/platform/pxa_camera.c
@@ -1388,7 +1388,7 @@ static int pxa_buffer_init(struct pxa_camera_dev *pcdev,
break;
default:
return -EINVAL;
- };
+ }
buf->nb_planes = nb_channels;
ret = sg_split(sgt->sgl, sgt->nents, 0, nb_channels,
diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c
index 58aebe7114cd..1d50dfbbb762 100644
--- a/drivers/media/platform/qcom/camss/camss-video.c
+++ b/drivers/media/platform/qcom/camss/camss-video.c
@@ -703,7 +703,7 @@ static int video_s_input(struct file *file, void *fh, unsigned int input)
static const struct v4l2_ioctl_ops msm_vid_ioctl_ops = {
.vidioc_querycap = video_querycap,
- .vidioc_enum_fmt_vid_cap_mplane = video_enum_fmt,
+ .vidioc_enum_fmt_vid_cap = video_enum_fmt,
.vidioc_g_fmt_vid_cap_mplane = video_g_fmt,
.vidioc_s_fmt_vid_cap_mplane = video_s_fmt,
.vidioc_try_fmt_vid_cap_mplane = video_try_fmt,
diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c
index db8e40b55d72..0acc7576cc58 100644
--- a/drivers/media/platform/qcom/venus/core.c
+++ b/drivers/media/platform/qcom/venus/core.c
@@ -446,7 +446,7 @@ static const struct venus_resources msm8996_res = {
.reg_tbl_size = ARRAY_SIZE(msm8996_reg_preset),
.clks = {"core", "iface", "bus", "mbus" },
.clks_num = 4,
- .max_load = 3110400, /* 4096x2160@90 */
+ .max_load = 2563200,
.hfi_version = HFI_VERSION_3XX,
.vmem_id = VIDC_RESOURCE_NONE,
.vmem_size = 0,
@@ -469,7 +469,7 @@ static const struct venus_resources sdm845_res = {
.freq_tbl_size = ARRAY_SIZE(sdm845_freq_table),
.clks = {"core", "iface", "bus" },
.clks_num = 3,
- .max_load = 2563200,
+ .max_load = 3110400, /* 4096x2160@90 */
.hfi_version = HFI_VERSION_4XX,
.vmem_id = VIDC_RESOURCE_NONE,
.vmem_size = 0,
diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c
index 1eba23409ff3..d3d1748a7ef6 100644
--- a/drivers/media/platform/qcom/venus/firmware.c
+++ b/drivers/media/platform/qcom/venus/firmware.c
@@ -78,11 +78,11 @@ static int venus_load_fw(struct venus_core *core, const char *fwname,
ret = of_address_to_resource(node, 0, &r);
if (ret)
- return ret;
+ goto err_put_node;
ret = request_firmware(&mdt, fwname, dev);
if (ret < 0)
- return ret;
+ goto err_put_node;
fw_size = qcom_mdt_get_size(mdt);
if (fw_size < 0) {
@@ -116,6 +116,8 @@ static int venus_load_fw(struct venus_core *core, const char *fwname,
memunmap(mem_va);
err_release_fw:
release_firmware(mdt);
+err_put_node:
+ of_node_put(node);
return ret;
}
diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c
index 7d0017613113..71b06dfc6dc4 100644
--- a/drivers/media/platform/qcom/venus/helpers.c
+++ b/drivers/media/platform/qcom/venus/helpers.c
@@ -458,6 +458,13 @@ static bool is_dynamic_bufmode(struct venus_inst *inst)
struct venus_core *core = inst->core;
struct venus_caps *caps;
+ /*
+ * v4 doesn't send BUFFER_ALLOC_MODE_SUPPORTED property and supports
+ * dynamic buffer mode by default for HFI_BUFFER_OUTPUT/OUTPUT2.
+ */
+ if (IS_V4(core))
+ return true;
+
caps = venus_caps_by_codec(core, inst->hfi_codec, inst->session_type);
if (!caps)
return false;
diff --git a/drivers/media/platform/qcom/venus/hfi_cmds.c b/drivers/media/platform/qcom/venus/hfi_cmds.c
index 8efd55a2ad70..4f645076abfb 100644
--- a/drivers/media/platform/qcom/venus/hfi_cmds.c
+++ b/drivers/media/platform/qcom/venus/hfi_cmds.c
@@ -1205,6 +1205,8 @@ pkt_session_set_property_4xx(struct hfi_session_set_property_pkt *pkt,
break;
}
case HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE:
+ case HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER:
+ case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE:
/* not implemented on Venus 4xx */
return -ENOTSUPP;
default:
diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c
index 6205ad8b3201..e1f998656c07 100644
--- a/drivers/media/platform/qcom/venus/vdec.c
+++ b/drivers/media/platform/qcom/venus/vdec.c
@@ -482,8 +482,8 @@ unlock:
static const struct v4l2_ioctl_ops vdec_ioctl_ops = {
.vidioc_querycap = vdec_querycap,
- .vidioc_enum_fmt_vid_cap_mplane = vdec_enum_fmt,
- .vidioc_enum_fmt_vid_out_mplane = vdec_enum_fmt,
+ .vidioc_enum_fmt_vid_cap = vdec_enum_fmt,
+ .vidioc_enum_fmt_vid_out = vdec_enum_fmt,
.vidioc_s_fmt_vid_cap_mplane = vdec_s_fmt,
.vidioc_s_fmt_vid_out_mplane = vdec_s_fmt,
.vidioc_g_fmt_vid_cap_mplane = vdec_g_fmt,
diff --git a/drivers/media/platform/qcom/venus/vdec_ctrls.c b/drivers/media/platform/qcom/venus/vdec_ctrls.c
index 68e0f7d0b8fc..300350bfe8bd 100644
--- a/drivers/media/platform/qcom/venus/vdec_ctrls.c
+++ b/drivers/media/platform/qcom/venus/vdec_ctrls.c
@@ -66,7 +66,7 @@ static int vdec_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
break;
default:
return -EINVAL;
- };
+ }
return 0;
}
diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c
index 7a4815d52c12..a5f3d2c46bea 100644
--- a/drivers/media/platform/qcom/venus/venc.c
+++ b/drivers/media/platform/qcom/venus/venc.c
@@ -607,8 +607,8 @@ static int venc_enum_frameintervals(struct file *file, void *fh,
static const struct v4l2_ioctl_ops venc_ioctl_ops = {
.vidioc_querycap = venc_querycap,
- .vidioc_enum_fmt_vid_cap_mplane = venc_enum_fmt,
- .vidioc_enum_fmt_vid_out_mplane = venc_enum_fmt,
+ .vidioc_enum_fmt_vid_cap = venc_enum_fmt,
+ .vidioc_enum_fmt_vid_out = venc_enum_fmt,
.vidioc_s_fmt_vid_cap_mplane = venc_s_fmt,
.vidioc_s_fmt_vid_out_mplane = venc_s_fmt,
.vidioc_g_fmt_vid_cap_mplane = venc_g_fmt,
diff --git a/drivers/media/platform/qcom/venus/venc_ctrls.c b/drivers/media/platform/qcom/venus/venc_ctrls.c
index 8832285d8c15..877c0b3299e9 100644
--- a/drivers/media/platform/qcom/venus/venc_ctrls.c
+++ b/drivers/media/platform/qcom/venus/venc_ctrls.c
@@ -108,6 +108,9 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
ctr->profile.h264 = ctrl->val;
break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:
+ ctr->profile.hevc = ctrl->val;
+ break;
case V4L2_CID_MPEG_VIDEO_VP8_PROFILE:
ctr->profile.vpx = ctrl->val;
break;
@@ -117,6 +120,9 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
ctr->level.h264 = ctrl->val;
break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL:
+ ctr->level.hevc = ctrl->val;
+ break;
case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
ctr->h264_i_qp = ctrl->val;
break;
@@ -208,7 +214,7 @@ int venc_ctrl_init(struct venus_inst *inst)
{
int ret;
- ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 28);
+ ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 30);
if (ret)
return ret;
@@ -237,6 +243,19 @@ int venc_ctrl_init(struct venus_inst *inst)
0, V4L2_MPEG_VIDEO_MPEG4_LEVEL_0);
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
+ V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10,
+ ~((1 << V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) |
+ (1 << V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) |
+ (1 << V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10)),
+ V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN);
+
+ v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
+ V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2,
+ 0, V4L2_MPEG_VIDEO_HEVC_LEVEL_1);
+
+ v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_PROFILE,
V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH,
~((1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
@@ -265,7 +284,7 @@ int venc_ctrl_init(struct venus_inst *inst)
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
- V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES,
+ V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES,
0, V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE);
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c
index 8f097e514900..c14af1b929df 100644
--- a/drivers/media/platform/rcar-vin/rcar-csi2.c
+++ b/drivers/media/platform/rcar-vin/rcar-csi2.c
@@ -1019,10 +1019,8 @@ static int rcsi2_probe_resources(struct rcar_csi2 *priv,
return ret;
priv->rstc = devm_reset_control_get(&pdev->dev, NULL);
- if (IS_ERR(priv->rstc))
- return PTR_ERR(priv->rstc);
- return 0;
+ return PTR_ERR_OR_ZERO(priv->rstc);
}
static const struct rcar_csi2_info rcar_csi2_info_r8a7795 = {
diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c
index 7cbdcbf9b090..0936bcd98df1 100644
--- a/drivers/media/platform/rcar-vin/rcar-v4l2.c
+++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c
@@ -749,103 +749,65 @@ static const struct v4l2_ioctl_ops rvin_mc_ioctl_ops = {
* File Operations
*/
-static int rvin_power_on(struct rvin_dev *vin)
+static int rvin_power_parallel(struct rvin_dev *vin, bool on)
{
- int ret;
struct v4l2_subdev *sd = vin_to_source(vin);
-
- pm_runtime_get_sync(vin->v4l2_dev.dev);
-
- ret = v4l2_subdev_call(sd, core, s_power, 1);
- if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
- return ret;
- return 0;
-}
-
-static int rvin_power_off(struct rvin_dev *vin)
-{
+ int power = on ? 1 : 0;
int ret;
- struct v4l2_subdev *sd = vin_to_source(vin);
-
- ret = v4l2_subdev_call(sd, core, s_power, 0);
-
- pm_runtime_put(vin->v4l2_dev.dev);
+ ret = v4l2_subdev_call(sd, core, s_power, power);
if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
return ret;
return 0;
}
-static int rvin_initialize_device(struct file *file)
+static int rvin_open(struct file *file)
{
struct rvin_dev *vin = video_drvdata(file);
int ret;
- struct v4l2_format f = {
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .fmt.pix = {
- .width = vin->format.width,
- .height = vin->format.height,
- .field = vin->format.field,
- .colorspace = vin->format.colorspace,
- .pixelformat = vin->format.pixelformat,
- },
- };
-
- ret = rvin_power_on(vin);
+ ret = pm_runtime_get_sync(vin->dev);
if (ret < 0)
return ret;
- pm_runtime_enable(&vin->vdev.dev);
- ret = pm_runtime_resume(&vin->vdev.dev);
- if (ret < 0 && ret != -ENOSYS)
- goto eresume;
-
- /*
- * Try to configure with default parameters. Notice: this is the
- * very first open, so, we cannot race against other calls,
- * apart from someone else calling open() simultaneously, but
- * .host_lock is protecting us against it.
- */
- ret = rvin_s_fmt_vid_cap(file, NULL, &f);
- if (ret < 0)
- goto esfmt;
-
- v4l2_ctrl_handler_setup(&vin->ctrl_handler);
-
- return 0;
-esfmt:
- pm_runtime_disable(&vin->vdev.dev);
-eresume:
- rvin_power_off(vin);
-
- return ret;
-}
-
-static int rvin_open(struct file *file)
-{
- struct rvin_dev *vin = video_drvdata(file);
- int ret;
-
- mutex_lock(&vin->lock);
+ ret = mutex_lock_interruptible(&vin->lock);
+ if (ret)
+ goto err_pm;
file->private_data = vin;
ret = v4l2_fh_open(file);
if (ret)
- goto unlock;
-
- if (!v4l2_fh_is_singular_file(file))
- goto unlock;
+ goto err_unlock;
- if (rvin_initialize_device(file)) {
- v4l2_fh_release(file);
- ret = -ENODEV;
+ if (vin->info->use_mc) {
+ ret = v4l2_pipeline_pm_use(&vin->vdev.entity, 1);
+ if (ret < 0)
+ goto err_open;
+ } else {
+ if (v4l2_fh_is_singular_file(file)) {
+ ret = rvin_power_parallel(vin, true);
+ if (ret < 0)
+ goto err_open;
+
+ ret = v4l2_ctrl_handler_setup(&vin->ctrl_handler);
+ if (ret)
+ goto err_parallel;
+ }
}
+ mutex_unlock(&vin->lock);
-unlock:
+ return 0;
+err_parallel:
+ rvin_power_parallel(vin, false);
+err_open:
+ v4l2_fh_release(file);
+err_unlock:
mutex_unlock(&vin->lock);
+err_pm:
+ pm_runtime_put(vin->dev);
+
return ret;
}
@@ -863,18 +825,17 @@ static int rvin_release(struct file *file)
/* the release helper will cleanup any on-going streaming */
ret = _vb2_fop_release(file, NULL);
- /*
- * If this was the last open file.
- * Then de-initialize hw module.
- */
- if (fh_singular) {
- pm_runtime_suspend(&vin->vdev.dev);
- pm_runtime_disable(&vin->vdev.dev);
- rvin_power_off(vin);
+ if (vin->info->use_mc) {
+ v4l2_pipeline_pm_use(&vin->vdev.entity, 0);
+ } else {
+ if (fh_singular)
+ rvin_power_parallel(vin, false);
}
mutex_unlock(&vin->lock);
+ pm_runtime_put(vin->dev);
+
return ret;
}
@@ -888,74 +849,6 @@ static const struct v4l2_file_operations rvin_fops = {
.read = vb2_fop_read,
};
-/* -----------------------------------------------------------------------------
- * Media controller file operations
- */
-
-static int rvin_mc_open(struct file *file)
-{
- struct rvin_dev *vin = video_drvdata(file);
- int ret;
-
- ret = mutex_lock_interruptible(&vin->lock);
- if (ret)
- return ret;
-
- ret = pm_runtime_get_sync(vin->dev);
- if (ret < 0)
- goto err_unlock;
-
- ret = v4l2_pipeline_pm_use(&vin->vdev.entity, 1);
- if (ret < 0)
- goto err_pm;
-
- file->private_data = vin;
-
- ret = v4l2_fh_open(file);
- if (ret)
- goto err_v4l2pm;
-
- mutex_unlock(&vin->lock);
-
- return 0;
-err_v4l2pm:
- v4l2_pipeline_pm_use(&vin->vdev.entity, 0);
-err_pm:
- pm_runtime_put(vin->dev);
-err_unlock:
- mutex_unlock(&vin->lock);
-
- return ret;
-}
-
-static int rvin_mc_release(struct file *file)
-{
- struct rvin_dev *vin = video_drvdata(file);
- int ret;
-
- mutex_lock(&vin->lock);
-
- /* the release helper will cleanup any on-going streaming. */
- ret = _vb2_fop_release(file, NULL);
-
- v4l2_pipeline_pm_use(&vin->vdev.entity, 0);
- pm_runtime_put(vin->dev);
-
- mutex_unlock(&vin->lock);
-
- return ret;
-}
-
-static const struct v4l2_file_operations rvin_mc_fops = {
- .owner = THIS_MODULE,
- .unlocked_ioctl = video_ioctl2,
- .open = rvin_mc_open,
- .release = rvin_mc_release,
- .poll = vb2_fop_poll,
- .mmap = vb2_fop_mmap,
- .read = vb2_fop_read,
-};
-
void rvin_v4l2_unregister(struct rvin_dev *vin)
{
if (!video_is_registered(&vin->vdev))
@@ -996,6 +889,7 @@ int rvin_v4l2_register(struct rvin_dev *vin)
snprintf(vdev->name, sizeof(vdev->name), "VIN%u output", vin->id);
vdev->release = video_device_release_empty;
vdev->lock = &vin->lock;
+ vdev->fops = &rvin_fops;
vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
V4L2_CAP_READWRITE;
@@ -1007,10 +901,8 @@ int rvin_v4l2_register(struct rvin_dev *vin)
vin->format.colorspace = RVIN_DEFAULT_COLORSPACE;
if (vin->info->use_mc) {
- vdev->fops = &rvin_mc_fops;
vdev->ioctl_ops = &rvin_mc_ioctl_ops;
} else {
- vdev->fops = &rvin_fops;
vdev->ioctl_ops = &rvin_ioctl_ops;
rvin_reset_format(vin);
}
diff --git a/drivers/media/platform/rcar_fdp1.c b/drivers/media/platform/rcar_fdp1.c
index 6a90bc4c476e..43aae9b6bb20 100644
--- a/drivers/media/platform/rcar_fdp1.c
+++ b/drivers/media/platform/rcar_fdp1.c
@@ -257,6 +257,8 @@ MODULE_PARM_DESC(debug, "activate debug info");
#define FD1_IP_H3_ES1 0x02010101
#define FD1_IP_M3W 0x02010202
#define FD1_IP_H3 0x02010203
+#define FD1_IP_M3N 0x02010204
+#define FD1_IP_E3 0x02010205
/* LUTs */
#define FD1_LUT_DIF_ADJ 0x1000
@@ -1730,8 +1732,8 @@ static const char * const fdp1_ctrl_deint_menu[] = {
static const struct v4l2_ioctl_ops fdp1_ioctl_ops = {
.vidioc_querycap = fdp1_vidioc_querycap,
- .vidioc_enum_fmt_vid_cap_mplane = fdp1_enum_fmt_vid_cap,
- .vidioc_enum_fmt_vid_out_mplane = fdp1_enum_fmt_vid_out,
+ .vidioc_enum_fmt_vid_cap = fdp1_enum_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_out = fdp1_enum_fmt_vid_out,
.vidioc_g_fmt_vid_cap_mplane = fdp1_g_fmt,
.vidioc_g_fmt_vid_out_mplane = fdp1_g_fmt,
.vidioc_try_fmt_vid_cap_mplane = fdp1_try_fmt,
@@ -2365,6 +2367,12 @@ static int fdp1_probe(struct platform_device *pdev)
case FD1_IP_H3:
dprintk(fdp1, "FDP1 Version R-Car H3\n");
break;
+ case FD1_IP_M3N:
+ dprintk(fdp1, "FDP1 Version R-Car M3N\n");
+ break;
+ case FD1_IP_E3:
+ dprintk(fdp1, "FDP1 Version R-Car E3\n");
+ break;
default:
dev_err(fdp1->dev, "FDP1 Unidentifiable (0x%08x)\n",
hw_version);
diff --git a/drivers/media/platform/rcar_jpu.c b/drivers/media/platform/rcar_jpu.c
index 1dfd2eb65920..1c3f507acfc9 100644
--- a/drivers/media/platform/rcar_jpu.c
+++ b/drivers/media/platform/rcar_jpu.c
@@ -671,8 +671,6 @@ static int jpu_querycap(struct file *file, void *priv,
strscpy(cap->driver, DRV_NAME, sizeof(cap->driver));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
dev_name(ctx->jpu->dev));
- cap->device_caps |= V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
- cap->capabilities = V4L2_CAP_DEVICE_CAPS | cap->device_caps;
memset(cap->reserved, 0, sizeof(cap->reserved));
return 0;
@@ -948,8 +946,8 @@ static int jpu_streamon(struct file *file, void *priv, enum v4l2_buf_type type)
static const struct v4l2_ioctl_ops jpu_ioctl_ops = {
.vidioc_querycap = jpu_querycap,
- .vidioc_enum_fmt_vid_cap_mplane = jpu_enum_fmt_cap,
- .vidioc_enum_fmt_vid_out_mplane = jpu_enum_fmt_out,
+ .vidioc_enum_fmt_vid_cap = jpu_enum_fmt_cap,
+ .vidioc_enum_fmt_vid_out = jpu_enum_fmt_out,
.vidioc_g_fmt_vid_cap_mplane = jpu_g_fmt,
.vidioc_g_fmt_vid_out_mplane = jpu_g_fmt,
.vidioc_try_fmt_vid_cap_mplane = jpu_try_fmt,
@@ -1662,6 +1660,8 @@ static int jpu_probe(struct platform_device *pdev)
jpu->vfd_encoder.lock = &jpu->mutex;
jpu->vfd_encoder.v4l2_dev = &jpu->v4l2_dev;
jpu->vfd_encoder.vfl_dir = VFL_DIR_M2M;
+ jpu->vfd_encoder.device_caps = V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_M2M_MPLANE;
ret = video_register_device(&jpu->vfd_encoder, VFL_TYPE_GRABBER, -1);
if (ret) {
@@ -1679,6 +1679,8 @@ static int jpu_probe(struct platform_device *pdev)
jpu->vfd_decoder.lock = &jpu->mutex;
jpu->vfd_decoder.v4l2_dev = &jpu->v4l2_dev;
jpu->vfd_decoder.vfl_dir = VFL_DIR_M2M;
+ jpu->vfd_decoder.device_caps = V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_M2M_MPLANE;
ret = video_register_device(&jpu->vfd_decoder, VFL_TYPE_GRABBER, -1);
if (ret) {
diff --git a/drivers/media/platform/renesas-ceu.c b/drivers/media/platform/renesas-ceu.c
index 150196f7cf96..57d0c0f9fa4b 100644
--- a/drivers/media/platform/renesas-ceu.c
+++ b/drivers/media/platform/renesas-ceu.c
@@ -1339,7 +1339,7 @@ static int ceu_enum_frameintervals(struct file *file, void *fh,
static const struct v4l2_ioctl_ops ceu_ioctl_ops = {
.vidioc_querycap = ceu_querycap,
- .vidioc_enum_fmt_vid_cap_mplane = ceu_enum_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_cap = ceu_enum_fmt_vid_cap,
.vidioc_try_fmt_vid_cap_mplane = ceu_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap_mplane = ceu_s_fmt_vid_cap,
.vidioc_g_fmt_vid_cap_mplane = ceu_g_fmt_vid_cap,
diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c
index c3fc94ef251e..a876d0873ebc 100644
--- a/drivers/media/platform/s3c-camif/camif-capture.c
+++ b/drivers/media/platform/s3c-camif/camif-capture.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* s3c24xx/s3c64xx SoC series Camera Interface (CAMIF) driver
*
@@ -6,10 +7,6 @@
*
* Based on drivers/media/platform/s5p-fimc,
* Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd.
- *
- * 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.
*/
#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
diff --git a/drivers/media/platform/s3c-camif/camif-core.h b/drivers/media/platform/s3c-camif/camif-core.h
index be5e7357dffc..efdc00b4ec6f 100644
--- a/drivers/media/platform/s3c-camif/camif-core.h
+++ b/drivers/media/platform/s3c-camif/camif-core.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* s3c24xx/s3c64xx SoC series Camera Interface (CAMIF) driver
*
* Copyright (C) 2012 Sylwester Nawrocki <sylvester.nawrocki@gmail.com>
* Copyright (C) 2012 Tomasz Figa <tomasz.figa@gmail.com>
- *
- * 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.
*/
#ifndef CAMIF_CORE_H_
diff --git a/drivers/media/platform/s3c-camif/camif-regs.c b/drivers/media/platform/s3c-camif/camif-regs.c
index 812fb3a7c4e3..1a65532dc36d 100644
--- a/drivers/media/platform/s3c-camif/camif-regs.c
+++ b/drivers/media/platform/s3c-camif/camif-regs.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Samsung s3c24xx/s3c64xx SoC CAMIF driver
*
* Copyright (C) 2012 Sylwester Nawrocki <sylvester.nawrocki@gmail.com>
* Copyright (C) 2012 Tomasz Figa <tomasz.figa@gmail.com>
- *
- * 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.
*/
#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
diff --git a/drivers/media/platform/s3c-camif/camif-regs.h b/drivers/media/platform/s3c-camif/camif-regs.h
index 5ad36c1c2a5d..29f839cdb486 100644
--- a/drivers/media/platform/s3c-camif/camif-regs.h
+++ b/drivers/media/platform/s3c-camif/camif-regs.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Register definition file for s3c24xx/s3c64xx SoC CAMIF driver
*
* Copyright (C) 2012 Sylwester Nawrocki <sylvester.nawrocki@gmail.com>
* Copyright (C) 2012 Tomasz Figa <tomasz.figa@gmail.com>
- *
- * 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.
*/
#ifndef CAMIF_REGS_H_
diff --git a/drivers/media/platform/s5p-cec/exynos_hdmi_cec.h b/drivers/media/platform/s5p-cec/exynos_hdmi_cec.h
index 7d9453505dce..325db8c432bd 100644
--- a/drivers/media/platform/s5p-cec/exynos_hdmi_cec.h
+++ b/drivers/media/platform/s5p-cec/exynos_hdmi_cec.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/* drivers/media/platform/s5p-cec/exynos_hdmi_cec.h
*
* Copyright (c) 2010, 2014 Samsung Electronics
* http://www.samsung.com/
*
* Header file for interface of Samsung Exynos hdmi cec hardware
- *
- * 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.
*/
#ifndef _EXYNOS_HDMI_CEC_H_
diff --git a/drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c b/drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c
index 146ae6f25cdb..eb981ebce362 100644
--- a/drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c
+++ b/drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c
*
* Copyright (c) 2009, 2014 Samsung Electronics
* http://www.samsung.com/
*
* cec ftn file for Samsung TVOUT driver
- *
- * 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.
*/
#include <linux/io.h>
diff --git a/drivers/media/platform/s5p-cec/regs-cec.h b/drivers/media/platform/s5p-cec/regs-cec.h
index b2e7e129920e..447f717028a2 100644
--- a/drivers/media/platform/s5p-cec/regs-cec.h
+++ b/drivers/media/platform/s5p-cec/regs-cec.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/* drivers/media/platform/s5p-cec/regs-cec.h
*
* Copyright (c) 2010 Samsung Electronics
* http://www.samsung.com/
*
* register header file for Samsung TVOUT driver
- *
- * 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.
*/
#ifndef __EXYNOS_REGS__H
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index 8cc730eccb6c..a3bc884b7df1 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* linux/drivers/media/platform/s5p-jpeg/jpeg-core.c
*
* Copyright (c) 2011-2014 Samsung Electronics Co., Ltd.
@@ -5,10 +6,6 @@
*
* Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
* Author: Jacek Anaszewski <j.anaszewski@samsung.com>
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.h b/drivers/media/platform/s5p-jpeg/jpeg-core.h
index 144c102ff05f..34f87f6c02f2 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.h
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/* linux/drivers/media/platform/s5p-jpeg/jpeg-core.h
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
- *
- * 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.
*/
#ifndef JPEG_CORE_H_
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c
index 0861842b2dfc..637a5104d948 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* linux/drivers/media/platform/exynos3250-jpeg/jpeg-hw.h
*
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Jacek Anaszewski <j.anaszewski@samsung.com>
- *
- * 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.
*/
#include <linux/io.h>
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.h b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.h
index b6e3be8b5008..68160befce39 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.h
+++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/* linux/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.h
*
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Jacek Anaszewski <j.anaszewski@samsung.com>
- *
- * 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.
*/
#ifndef JPEG_HW_EXYNOS3250_H_
#define JPEG_HW_EXYNOS3250_H_
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c
index c72789bae6ed..0828cfa783fe 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2013 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
* Author: Jacek Anaszewski <j.anaszewski@samsung.com>
*
* Register interface file for JPEG driver on Exynos4x12.
- *
- * 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.
*/
#include <linux/io.h>
#include <linux/delay.h>
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.h b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.h
index cf6ec055d63a..3e2887526960 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.h
+++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (c) 2013 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
* Author: Jacek Anaszewski <j.anaszewski@samsung.com>
*
* Header file of the register interface for JPEG driver on Exynos4x12.
- *
- * 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.
*/
#ifndef JPEG_HW_EXYNOS4_H_
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c
index 59c6263a71bf..491e9248286c 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* linux/drivers/media/platform/s5p-jpeg/jpeg-hw.h
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
- *
- * 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.
*/
#include <linux/io.h>
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h
index bfe746f8f750..98ddf7097562 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h
+++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/* linux/drivers/media/platform/s5p-jpeg/jpeg-hw.h
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
- *
- * 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.
*/
#ifndef JPEG_HW_S5P_H_
#define JPEG_HW_S5P_H_
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-regs.h b/drivers/media/platform/s5p-jpeg/jpeg-regs.h
index 574f0e8021e5..bab7fa46b89a 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-regs.h
+++ b/drivers/media/platform/s5p-jpeg/jpeg-regs.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/* linux/drivers/media/platform/s5p-jpeg/jpeg-regs.h
*
* Register definition file for Samsung JPEG codec driver
@@ -7,10 +8,6 @@
*
* Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
* Author: Jacek Anaszewski <j.anaszewski@samsung.com>
- *
- * 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.
*/
#ifndef JPEG_REGS_H_
diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v6.h b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h
index c0166ee9a455..fa49fe580e1a 100644
--- a/drivers/media/platform/s5p-mfc/regs-mfc-v6.h
+++ b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Register definition file for Samsung MFC V6.x Interface (FIMV) driver
*
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
- *
- * 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.
*/
#ifndef _REGS_FIMV_V6_H
diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v7.h b/drivers/media/platform/s5p-mfc/regs-mfc-v7.h
index 9f220769d970..4a7adfdaa359 100644
--- a/drivers/media/platform/s5p-mfc/regs-mfc-v7.h
+++ b/drivers/media/platform/s5p-mfc/regs-mfc-v7.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Register definition file for Samsung MFC V7.x Interface (FIMV) driver
*
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
- *
- * 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.
*/
#ifndef _REGS_MFC_V7_H
diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v8.h b/drivers/media/platform/s5p-mfc/regs-mfc-v8.h
index bd639ae71023..162e3c7e920f 100644
--- a/drivers/media/platform/s5p-mfc/regs-mfc-v8.h
+++ b/drivers/media/platform/s5p-mfc/regs-mfc-v8.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Register definition file for Samsung MFC V8.x Interface (FIMV) driver
*
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
- *
- * 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.
*/
#ifndef _REGS_MFC_V8_H
diff --git a/drivers/media/platform/s5p-mfc/regs-mfc.h b/drivers/media/platform/s5p-mfc/regs-mfc.h
index 57b7e0be0596..9171e8181c18 100644
--- a/drivers/media/platform/s5p-mfc/regs-mfc.h
+++ b/drivers/media/platform/s5p-mfc/regs-mfc.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Register definition file for Samsung MFC V5.1 Interface (FIMV) driver
*
* Kamil Debski, Copyright (c) 2010 Samsung Electronics
* http://www.samsung.com/
- *
- * 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.
*/
#ifndef _REGS_FIMV_H
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c
index 4e936b95018a..b776f83e395e 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c
@@ -523,7 +523,8 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx,
dev);
ctx->mv_count = s5p_mfc_hw_call(dev->mfc_ops, get_mv_count,
dev);
- ctx->scratch_buf_size = s5p_mfc_hw_call(dev->mfc_ops,
+ if (FW_HAS_E_MIN_SCRATCH_BUF(dev))
+ ctx->scratch_buf_size = s5p_mfc_hw_call(dev->mfc_ops,
get_min_scratch_buf_size, dev);
if (ctx->img_width == 0 || ctx->img_height == 0)
ctx->state = MFCINST_ERROR;
@@ -1344,6 +1345,7 @@ static int s5p_mfc_probe(struct platform_device *pdev)
vfd->lock = &dev->mfc_mutex;
vfd->v4l2_dev = &dev->v4l2_dev;
vfd->vfl_dir = VFL_DIR_M2M;
+ vfd->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
set_bit(V4L2_FL_QUIRK_INVERTED_CROP, &vfd->flags);
snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_DEC_NAME);
dev->vfd_dec = vfd;
@@ -1362,6 +1364,7 @@ static int s5p_mfc_probe(struct platform_device *pdev)
vfd->lock = &dev->mfc_mutex;
vfd->v4l2_dev = &dev->v4l2_dev;
vfd->vfl_dir = VFL_DIR_M2M;
+ vfd->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_ENC_NAME);
dev->vfd_enc = vfd;
video_set_drvdata(vfd, dev);
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h b/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h
index 1936a5b868f5..752bbe4fe48e 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* drivers/media/platform/s5p-mfc/s5p_mfc_debug.h
*
@@ -6,10 +7,6 @@
*
* Kamil Debski, Copyright (c) 2011 Samsung Electronics
* http://www.samsung.com/
- *
- * 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.
*/
#ifndef S5P_MFC_DEBUG_H_
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
index d12fc4f397b6..4017c8b471f4 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
@@ -271,13 +271,6 @@ static int vidioc_querycap(struct file *file, void *priv,
strscpy(cap->card, dev->vfd_dec->name, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
dev_name(&dev->plat_dev->dev));
- /*
- * This is only a mem-to-mem video device. The capture and output
- * device capability flags are left only for backward compatibility
- * and are scheduled for removal.
- */
- cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -309,14 +302,14 @@ static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f,
return 0;
}
-static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv,
- struct v4l2_fmtdesc *f)
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv,
+ struct v4l2_fmtdesc *f)
{
return vidioc_enum_fmt(file, f, false);
}
-static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
+static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
{
return vidioc_enum_fmt(file, f, true);
}
@@ -883,8 +876,8 @@ static int vidioc_subscribe_event(struct v4l2_fh *fh,
/* v4l2_ioctl_ops */
static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
- .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane,
- .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
.vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt,
.vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt,
.vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt,
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
index 74090a68f807..97e76480e942 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
@@ -130,7 +130,7 @@ static struct mfc_control controls[] = {
.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
- .maximum = V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES,
+ .maximum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES,
.default_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
.menu_skip_mask = 0,
},
@@ -1313,13 +1313,6 @@ static int vidioc_querycap(struct file *file, void *priv,
strscpy(cap->card, dev->vfd_enc->name, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
dev_name(&dev->plat_dev->dev));
- /*
- * This is only a mem-to-mem video device. The capture and output
- * device capability flags are left only for backward compatibility
- * and are scheduled for removal.
- */
- cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -1350,14 +1343,14 @@ static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f,
return -EINVAL;
}
-static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv,
- struct v4l2_fmtdesc *f)
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv,
+ struct v4l2_fmtdesc *f)
{
return vidioc_enum_fmt(file, f, false);
}
-static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov,
- struct v4l2_fmtdesc *f)
+static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
{
return vidioc_enum_fmt(file, f, true);
}
@@ -2339,8 +2332,8 @@ static int vidioc_subscribe_event(struct v4l2_fh *fh,
static const struct v4l2_ioctl_ops s5p_mfc_enc_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
- .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane,
- .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
.vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt,
.vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt,
.vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt,
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_intr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_intr.c
index 5b8f0e085e6d..0a38f6d70ee9 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_intr.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_intr.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/media/platform/samsung/mfc5/s5p_mfc_intr.c
*
@@ -6,10 +7,6 @@
*
* Kamil Debski, Copyright (C) 2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_intr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_intr.h
index 18341a88514e..d32860db17d2 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_intr.h
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_intr.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* drivers/media/platform/samsung/mfc5/s5p_mfc_intr.h
*
@@ -6,10 +7,6 @@
*
* Kamil Debski, Copyright (C) 2011 Samsung Electronics
* http://www.samsung.com/
- *
- * 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.
*/
#ifndef S5P_MFC_INTR_H_
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c
index 7f33cf23947f..bb65671eea91 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/media/platform/s5p-mfc/s5p_mfc_opr.c
*
@@ -6,10 +7,6 @@
*
* Kamil Debski, Copyright (c) 2012 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
- *
- * 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.
*/
#include "s5p_mfc_debug.h"
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h
index 8c295f0f9740..1c5d2d4c0543 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* drivers/media/platform/s5p-mfc/s5p_mfc_opr.h
*
@@ -6,10 +7,6 @@
*
* Kamil Debski, Copyright (C) 2012 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
- *
- * 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.
*/
#ifndef S5P_MFC_OPR_H_
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
index 6144e95f6425..f76a07400966 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/media/platform/samsung/mfc5/s5p_mfc_opr_v5.c
*
@@ -6,10 +7,6 @@
*
* Kamil Debski, Copyright (c) 2011 Samsung Electronics
* http://www.samsung.com/
- *
- * 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.
*/
#include "s5p_mfc_common.h"
@@ -695,9 +692,9 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
/* multi-slice control */
/* multi-slice MB number or bit size */
mfc_write(dev, p->slice_mode, S5P_FIMV_ENC_MSLICE_CTRL);
- if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) {
+ if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) {
mfc_write(dev, p->slice_mb, S5P_FIMV_ENC_MSLICE_MB);
- } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) {
+ } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES) {
mfc_write(dev, p->slice_bit, S5P_FIMV_ENC_MSLICE_BIT);
} else {
mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_MB);
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.h
index ffee39a127d5..b53d376ead60 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.h
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* drivers/media/platform/samsung/mfc5/s5p_mfc_opr_v5.h
*
@@ -6,10 +7,6 @@
*
* Kamil Debski, Copyright (C) 2011 Samsung Electronics
* http://www.samsung.com/
- *
- * 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.
*/
#ifndef S5P_MFC_OPR_V5_H_
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
index 281699ab7fe1..f7621a9051cb 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
*
@@ -6,10 +7,6 @@
*
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
- *
- * 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.
*/
#undef DEBUG
@@ -736,10 +733,10 @@ static int s5p_mfc_set_slice_mode(struct s5p_mfc_ctx *ctx)
/* multi-slice control */
/* multi-slice MB number or bit size */
writel(ctx->slice_mode, mfc_regs->e_mslice_mode);
- if (ctx->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) {
+ if (ctx->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) {
writel(ctx->slice_size.mb, mfc_regs->e_mslice_size_mb);
} else if (ctx->slice_mode ==
- V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) {
+ V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES) {
writel(ctx->slice_size.bits, mfc_regs->e_mslice_size_bits);
} else {
writel(0x0, mfc_regs->e_mslice_size_mb);
@@ -779,11 +776,11 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
/* multi-slice MB number or bit size */
ctx->slice_mode = p->slice_mode;
reg = 0;
- if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) {
+ if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) {
reg |= (0x1 << 3);
writel(reg, mfc_regs->e_enc_options);
ctx->slice_size.mb = p->slice_mb;
- } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) {
+ } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES) {
reg |= (0x1 << 3);
writel(reg, mfc_regs->e_enc_options);
ctx->slice_size.bits = p->slice_bit;
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h
index f013b291ae5b..8ca514bf5e37 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h
*
@@ -6,10 +7,6 @@
*
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
- *
- * 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.
*/
#ifndef S5P_MFC_OPR_V6_H_
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
index 2e62f8721fa5..7d52431c2c83 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
@@ -34,6 +34,11 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev)
for (i = 0; i < pm->num_clocks; i++) {
pm->clocks[i] = devm_clk_get(pm->device, pm->clk_names[i]);
if (IS_ERR(pm->clocks[i])) {
+ /* additional clocks are optional */
+ if (i && PTR_ERR(pm->clocks[i]) == -ENOENT) {
+ pm->clocks[i] = NULL;
+ continue;
+ }
mfc_err("Failed to get clock: %s\n",
pm->clk_names[i]);
return PTR_ERR(pm->clocks[i]);
diff --git a/drivers/media/platform/seco-cec/seco-cec.c b/drivers/media/platform/seco-cec/seco-cec.c
index e5080d6f5b2d..1d0133f01e00 100644
--- a/drivers/media/platform/seco-cec/seco-cec.c
+++ b/drivers/media/platform/seco-cec/seco-cec.c
@@ -18,7 +18,7 @@
#include <linux/platform_device.h>
/* CEC Framework */
-#include <media/cec.h>
+#include <media/cec-notifier.h>
#include "seco-cec.h"
diff --git a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c
index 075d4695ee4d..a79250a7f812 100644
--- a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c
+++ b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c
@@ -143,7 +143,7 @@ int c8sectpfe_frontend_attach(struct dvb_frontend **fe,
"%s: stv0367ter_attach failed for NIM card %s\n"
, __func__, dvb_card_str(tsin->dvb_card));
return -ENODEV;
- };
+ }
/*
* init the demod so that i2c gate_ctrl
@@ -203,7 +203,7 @@ int c8sectpfe_frontend_attach(struct dvb_frontend **fe,
"%s: stv6110x_attach failed for NIM card %s\n"
, __func__, dvb_card_str(tsin->dvb_card));
return -ENODEV;
- };
+ }
stv090x_config.tuner_init = fe2->tuner_init;
stv090x_config.tuner_set_mode = fe2->tuner_set_mode;
diff --git a/drivers/media/platform/sti/hva/hva-v4l2.c b/drivers/media/platform/sti/hva/hva-v4l2.c
index c42623dccfd6..64004d15a9c9 100644
--- a/drivers/media/platform/sti/hva/hva-v4l2.c
+++ b/drivers/media/platform/sti/hva/hva-v4l2.c
@@ -566,6 +566,7 @@ static int hva_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
*/
struct vb2_queue *vq;
struct hva_stream *stream;
+ struct vb2_buffer *vb2_buf;
vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, buf->type);
@@ -575,7 +576,8 @@ static int hva_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
return -EINVAL;
}
- stream = (struct hva_stream *)vq->bufs[buf->index];
+ vb2_buf = vb2_get_buffer(vq, buf->index);
+ stream = to_hva_stream(to_vb2_v4l2_buffer(vb2_buf));
stream->bytesused = buf->bytesused;
}
diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c
index b9dad0accd1b..d855e9c09c08 100644
--- a/drivers/media/platform/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/stm32/stm32-dcmi.c
@@ -1702,7 +1702,7 @@ static int dcmi_probe(struct platform_device *pdev)
if (irq <= 0) {
if (irq != -EPROBE_DEFER)
dev_err(&pdev->dev, "Could not get irq\n");
- return irq;
+ return irq ? irq : -ENXIO;
}
dcmi->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
index 4c79eb64a7a7..6e0e894154f4 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
@@ -924,6 +924,7 @@ static int sun6i_csi_remove(struct platform_device *pdev)
static const struct of_device_id sun6i_csi_of_match[] = {
{ .compatible = "allwinner,sun6i-a31-csi", },
+ { .compatible = "allwinner,sun8i-a83t-csi", },
{ .compatible = "allwinner,sun8i-h3-csi", },
{ .compatible = "allwinner,sun8i-v3s-csi", },
{ .compatible = "allwinner,sun50i-a64-csi", },
diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c
index 8d075683e448..9e86d761546b 100644
--- a/drivers/media/platform/ti-vpe/cal.c
+++ b/drivers/media/platform/ti-vpe/cal.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TI CAL camera interface driver
*
* Copyright (c) 2015 Texas Instruments Inc.
* Benoit Parrot, <bparrot@ti.com>
- *
- * 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
*/
#include <linux/interrupt.h>
diff --git a/drivers/media/platform/ti-vpe/cal_regs.h b/drivers/media/platform/ti-vpe/cal_regs.h
index 82b3dcf87128..68cfc922b422 100644
--- a/drivers/media/platform/ti-vpe/cal_regs.h
+++ b/drivers/media/platform/ti-vpe/cal_regs.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* TI CAL camera interface driver
*
* Copyright (c) 2015 Texas Instruments Inc.
*
* Benoit Parrot, <bparrot@ti.com>
- *
- * 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.
*/
#ifndef __TI_CAL_REGS_H
diff --git a/drivers/media/platform/ti-vpe/csc.c b/drivers/media/platform/ti-vpe/csc.c
index 44b8465cf101..eda2a5985da7 100644
--- a/drivers/media/platform/ti-vpe/csc.c
+++ b/drivers/media/platform/ti-vpe/csc.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Color space converter library
*
@@ -6,10 +7,6 @@
* David Griego, <dagriego@biglakesoftware.com>
* Dale Farnsworth, <dale@farnsworth.org>
* Archit Taneja, <archit@ti.com>
- *
- * 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.
*/
#include <linux/err.h>
diff --git a/drivers/media/platform/ti-vpe/csc.h b/drivers/media/platform/ti-vpe/csc.h
index 024700b15152..de9a58af2ca8 100644
--- a/drivers/media/platform/ti-vpe/csc.h
+++ b/drivers/media/platform/ti-vpe/csc.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2013 Texas Instruments Inc.
*
* David Griego, <dagriego@biglakesoftware.com>
* Dale Farnsworth, <dale@farnsworth.org>
* Archit Taneja, <archit@ti.com>
- *
- * 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.
*/
#ifndef TI_CSC_H
#define TI_CSC_H
diff --git a/drivers/media/platform/ti-vpe/sc.c b/drivers/media/platform/ti-vpe/sc.c
index e9273b713782..98f95082a6fd 100644
--- a/drivers/media/platform/ti-vpe/sc.c
+++ b/drivers/media/platform/ti-vpe/sc.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Scaler library
*
@@ -6,10 +7,6 @@
* David Griego, <dagriego@biglakesoftware.com>
* Dale Farnsworth, <dale@farnsworth.org>
* Archit Taneja, <archit@ti.com>
- *
- * 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.
*/
#include <linux/err.h>
diff --git a/drivers/media/platform/ti-vpe/sc.h b/drivers/media/platform/ti-vpe/sc.h
index f1fe80b38c9f..d55de44d5257 100644
--- a/drivers/media/platform/ti-vpe/sc.h
+++ b/drivers/media/platform/ti-vpe/sc.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2013 Texas Instruments Inc.
*
* David Griego, <dagriego@biglakesoftware.com>
* Dale Farnsworth, <dale@farnsworth.org>
* Archit Taneja, <archit@ti.com>
- *
- * 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.
*/
#ifndef TI_SC_H
#define TI_SC_H
diff --git a/drivers/media/platform/ti-vpe/sc_coeff.h b/drivers/media/platform/ti-vpe/sc_coeff.h
index 5bfa5c03aec6..c525d1764099 100644
--- a/drivers/media/platform/ti-vpe/sc_coeff.h
+++ b/drivers/media/platform/ti-vpe/sc_coeff.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* VPE SC coefs
*
@@ -6,10 +7,6 @@
* David Griego, <dagriego@biglakesoftware.com>
* Dale Farnsworth, <dale@farnsworth.org>
* Archit Taneja, <archit@ti.com>
- *
- * 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.
*/
#ifndef __TI_SC_COEFF_H
diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c
index 78d716c93649..fd37d79e1619 100644
--- a/drivers/media/platform/ti-vpe/vpdma.c
+++ b/drivers/media/platform/ti-vpe/vpdma.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* VPDMA helper library
*
@@ -6,10 +7,6 @@
* David Griego, <dagriego@biglakesoftware.com>
* Dale Farnsworth, <dale@farnsworth.org>
* Archit Taneja, <archit@ti.com>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/media/platform/ti-vpe/vpdma.h b/drivers/media/platform/ti-vpe/vpdma.h
index 7e611501c291..28bc94129348 100644
--- a/drivers/media/platform/ti-vpe/vpdma.h
+++ b/drivers/media/platform/ti-vpe/vpdma.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2013 Texas Instruments Inc.
*
* David Griego, <dagriego@biglakesoftware.com>
* Dale Farnsworth, <dale@farnsworth.org>
* Archit Taneja, <archit@ti.com>
- *
- * 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.
*/
#ifndef __TI_VPDMA_H_
diff --git a/drivers/media/platform/ti-vpe/vpdma_priv.h b/drivers/media/platform/ti-vpe/vpdma_priv.h
index 72c7f13b4a9d..c488609bc162 100644
--- a/drivers/media/platform/ti-vpe/vpdma_priv.h
+++ b/drivers/media/platform/ti-vpe/vpdma_priv.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2013 Texas Instruments Inc.
*
* David Griego, <dagriego@biglakesoftware.com>
* Dale Farnsworth, <dale@farnsworth.org>
* Archit Taneja, <archit@ti.com>
- *
- * 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.
*/
#ifndef _TI_VPDMA_PRIV_H_
diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c
index 1e40eafec284..dda04498ac56 100644
--- a/drivers/media/platform/ti-vpe/vpe.c
+++ b/drivers/media/platform/ti-vpe/vpe.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TI VPE mem2mem driver, based on the virtual v4l2-mem2mem example driver
*
@@ -11,10 +12,6 @@
* Marek Szyprowski, <m.szyprowski@samsung.com>
*
* Based on the virtual v4l2-mem2mem example device
- *
- * 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
*/
#include <linux/delay.h>
@@ -1495,8 +1492,6 @@ static int vpe_querycap(struct file *file, void *priv,
strscpy(cap->card, VPE_MODULE_NAME, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
VPE_MODULE_NAME);
- cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -1973,12 +1968,12 @@ static const struct v4l2_ctrl_ops vpe_ctrl_ops = {
static const struct v4l2_ioctl_ops vpe_ioctl_ops = {
.vidioc_querycap = vpe_querycap,
- .vidioc_enum_fmt_vid_cap_mplane = vpe_enum_fmt,
+ .vidioc_enum_fmt_vid_cap = vpe_enum_fmt,
.vidioc_g_fmt_vid_cap_mplane = vpe_g_fmt,
.vidioc_try_fmt_vid_cap_mplane = vpe_try_fmt,
.vidioc_s_fmt_vid_cap_mplane = vpe_s_fmt,
- .vidioc_enum_fmt_vid_out_mplane = vpe_enum_fmt,
+ .vidioc_enum_fmt_vid_out = vpe_enum_fmt,
.vidioc_g_fmt_vid_out_mplane = vpe_g_fmt,
.vidioc_try_fmt_vid_out_mplane = vpe_try_fmt,
.vidioc_s_fmt_vid_out_mplane = vpe_s_fmt,
@@ -2411,6 +2406,7 @@ static const struct video_device vpe_videodev = {
.minor = -1,
.release = video_device_release_empty,
.vfl_dir = VFL_DIR_M2M,
+ .device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING,
};
static const struct v4l2_m2m_ops m2m_ops = {
diff --git a/drivers/media/platform/ti-vpe/vpe_regs.h b/drivers/media/platform/ti-vpe/vpe_regs.h
index 74283d79eae1..9969bea0dded 100644
--- a/drivers/media/platform/ti-vpe/vpe_regs.h
+++ b/drivers/media/platform/ti-vpe/vpe_regs.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2013 Texas Instruments Inc.
*
* David Griego, <dagriego@biglakesoftware.com>
* Dale Farnsworth, <dale@farnsworth.org>
* Archit Taneja, <archit@ti.com>
- *
- * 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.
*/
#ifndef __TI_VPE_REGS_H
diff --git a/drivers/media/platform/vicodec/Kconfig b/drivers/media/platform/vicodec/Kconfig
index 36bb0e934252..89456665cb16 100644
--- a/drivers/media/platform/vicodec/Kconfig
+++ b/drivers/media/platform/vicodec/Kconfig
@@ -4,7 +4,6 @@ config VIDEO_VICODEC
depends on VIDEO_DEV && VIDEO_V4L2
select VIDEOBUF2_VMALLOC
select V4L2_MEM2MEM_DEV
- default n
help
Driver for a Virtual Codec
diff --git a/drivers/media/platform/vicodec/vicodec-core.c b/drivers/media/platform/vicodec/vicodec-core.c
index bd01a9206aa6..7e7c1e80f29f 100644
--- a/drivers/media/platform/vicodec/vicodec-core.c
+++ b/drivers/media/platform/vicodec/vicodec-core.c
@@ -84,6 +84,7 @@ struct vicodec_q_data {
unsigned int visible_width;
unsigned int visible_height;
unsigned int sizeimage;
+ unsigned int vb2_sizeimage;
unsigned int sequence;
const struct v4l2_fwht_pixfmt_info *info;
};
@@ -116,12 +117,14 @@ struct vicodec_ctx {
struct vicodec_dev *dev;
bool is_enc;
bool is_stateless;
+ bool is_draining;
+ bool next_is_last;
+ bool has_stopped;
spinlock_t *lock;
struct v4l2_ctrl_handler hdl;
struct vb2_v4l2_buffer *last_src_buf;
- struct vb2_v4l2_buffer *last_dst_buf;
/* Source and destination queue data */
struct vicodec_q_data q_data[2];
@@ -138,6 +141,10 @@ struct vicodec_ctx {
bool source_changed;
};
+static const struct v4l2_event vicodec_eos_event = {
+ .type = V4L2_EVENT_EOS
+};
+
static inline struct vicodec_ctx *file2ctx(struct file *file)
{
return container_of(file->private_data, struct vicodec_ctx, fh);
@@ -329,6 +336,10 @@ static int device_process(struct vicodec_ctx *ctx,
copy_cap_to_ref(p_dst, ctx->state.info, &ctx->state);
vb2_set_plane_payload(&dst_vb->vb2_buf, 0, q_dst->sizeimage);
+ if (ntohl(ctx->state.header.flags) & FWHT_FL_I_FRAME)
+ dst_vb->flags |= V4L2_BUF_FLAG_KEYFRAME;
+ else
+ dst_vb->flags |= V4L2_BUF_FLAG_PFRAME;
}
return ret;
}
@@ -397,9 +408,6 @@ static enum vb2_buffer_state get_next_header(struct vicodec_ctx *ctx,
/* device_run() - prepares and starts the device */
static void device_run(void *priv)
{
- static const struct v4l2_event eos_event = {
- .type = V4L2_EVENT_EOS
- };
struct vicodec_ctx *ctx = priv;
struct vicodec_dev *dev = ctx->dev;
struct vb2_v4l2_buffer *src_buf, *dst_buf;
@@ -407,7 +415,6 @@ static void device_run(void *priv)
u32 state;
struct media_request *src_req;
-
src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
src_req = src_buf->vb2_buf.req_obj.req;
@@ -421,14 +428,14 @@ static void device_run(void *priv)
else
dst_buf->sequence = q_dst->sequence++;
dst_buf->flags &= ~V4L2_BUF_FLAG_LAST;
- v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, !ctx->is_enc);
-
- ctx->last_dst_buf = dst_buf;
+ v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false);
spin_lock(ctx->lock);
if (!ctx->comp_has_next_frame && src_buf == ctx->last_src_buf) {
dst_buf->flags |= V4L2_BUF_FLAG_LAST;
- v4l2_event_queue_fh(&ctx->fh, &eos_event);
+ v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
+ ctx->is_draining = false;
+ ctx->has_stopped = true;
}
if (ctx->is_enc || ctx->is_stateless) {
src_buf->sequence = q_src->sequence++;
@@ -442,14 +449,14 @@ static void device_run(void *priv)
ctx->comp_has_next_frame = false;
}
v4l2_m2m_buf_done(dst_buf, state);
- if (ctx->is_stateless && src_req)
- v4l2_ctrl_request_complete(src_req, &ctx->hdl);
ctx->comp_size = 0;
ctx->header_size = 0;
ctx->comp_magic_cnt = 0;
ctx->comp_has_frame = false;
spin_unlock(ctx->lock);
+ if (ctx->is_stateless && src_req)
+ v4l2_ctrl_request_complete(src_req, &ctx->hdl);
if (ctx->is_enc)
v4l2_m2m_job_finish(dev->stateful_enc.m2m_dev, ctx->fh.m2m_ctx);
@@ -579,6 +586,8 @@ static int job_ready(void *priv)
unsigned int max_to_copy;
unsigned int comp_frame_size;
+ if (ctx->has_stopped)
+ return 0;
if (ctx->source_changed)
return 0;
if (ctx->is_stateless || ctx->is_enc || ctx->comp_has_frame)
@@ -598,6 +607,8 @@ restart:
if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
state = get_next_header(ctx, &p, p_src + sz - p);
if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
+ if (ctx->is_draining && src_buf == ctx->last_src_buf)
+ return 1;
job_remove_src_buf(ctx, state);
goto restart;
}
@@ -625,6 +636,8 @@ restart:
p += copy;
ctx->comp_size += copy;
if (ctx->comp_size < max_to_copy) {
+ if (ctx->is_draining && src_buf == ctx->last_src_buf)
+ return 1;
job_remove_src_buf(ctx, state);
goto restart;
}
@@ -666,7 +679,6 @@ restart:
v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
update_capture_data_from_header(ctx);
- ctx->first_source_change_sent = true;
v4l2_event_queue_fh(&ctx->fh, &rs_event);
set_last_buffer(dst_buf, src_buf, ctx);
ctx->source_changed = true;
@@ -713,7 +725,8 @@ static int enum_fmt(struct v4l2_fmtdesc *f, struct vicodec_ctx *ctx,
const struct v4l2_fwht_pixfmt_info *info =
get_q_data(ctx, f->type)->info;
- if (!info || ctx->is_enc)
+ if (ctx->is_enc ||
+ !vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q))
info = v4l2_fwht_get_pixfmt(f->index);
else
info = v4l2_fwht_find_nth_fmt(info->width_div,
@@ -764,9 +777,6 @@ static int vidioc_g_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
q_data = get_q_data(ctx, f->type);
info = q_data->info;
- if (!info)
- info = v4l2_fwht_get_pixfmt(0);
-
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
@@ -1032,16 +1042,10 @@ static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
default:
return -EINVAL;
}
- if (q_data->visible_width > q_data->coded_width)
- q_data->visible_width = q_data->coded_width;
- if (q_data->visible_height > q_data->coded_height)
- q_data->visible_height = q_data->coded_height;
-
dprintk(ctx->dev,
- "Setting format for type %d, coded wxh: %dx%d, visible wxh: %dx%d, fourcc: %08x\n",
+ "Setting format for type %d, coded wxh: %dx%d, fourcc: 0x%08x\n",
f->type, q_data->coded_width, q_data->coded_height,
- q_data->visible_width, q_data->visible_height,
q_data->info->id);
return 0;
@@ -1063,18 +1067,58 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
struct v4l2_format *f)
{
struct vicodec_ctx *ctx = file2ctx(file);
- struct v4l2_pix_format_mplane *pix_mp;
+ struct vicodec_q_data *q_data;
+ struct vicodec_q_data *q_data_cap;
struct v4l2_pix_format *pix;
+ struct v4l2_pix_format_mplane *pix_mp;
+ u32 coded_w = 0, coded_h = 0;
+ unsigned int size = 0;
int ret;
+ q_data = get_q_data(ctx, f->type);
+ q_data_cap = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+
ret = vidioc_try_fmt_vid_out(file, priv, f);
if (ret)
return ret;
+ if (ctx->is_enc) {
+ struct vb2_queue *vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+ struct vb2_queue *vq_cap = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ const struct v4l2_fwht_pixfmt_info *info = ctx->is_stateless ?
+ &pixfmt_stateless_fwht : &pixfmt_fwht;
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ coded_w = f->fmt.pix.width;
+ coded_h = f->fmt.pix.height;
+ } else {
+ coded_w = f->fmt.pix_mp.width;
+ coded_h = f->fmt.pix_mp.height;
+ }
+ if (vb2_is_busy(vq) && (coded_w != q_data->coded_width ||
+ coded_h != q_data->coded_height))
+ return -EBUSY;
+ size = coded_w * coded_h *
+ info->sizeimage_mult / info->sizeimage_div;
+ if (!ctx->is_stateless)
+ size += sizeof(struct fwht_cframe_hdr);
+
+ if (vb2_is_busy(vq_cap) && size > q_data_cap->sizeimage)
+ return -EBUSY;
+ }
+
ret = vidioc_s_fmt(file2ctx(file), f);
if (!ret) {
+ if (ctx->is_enc) {
+ q_data->visible_width = coded_w;
+ q_data->visible_height = coded_h;
+ q_data_cap->coded_width = coded_w;
+ q_data_cap->coded_height = coded_h;
+ q_data_cap->sizeimage = size;
+ }
+
switch (f->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
pix = &f->fmt.pix;
ctx->state.colorspace = pix->colorspace;
@@ -1082,7 +1126,6 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
ctx->state.ycbcr_enc = pix->ycbcr_enc;
ctx->state.quantization = pix->quantization;
break;
- case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
pix_mp = &f->fmt.pix_mp;
ctx->state.colorspace = pix_mp->colorspace;
@@ -1173,31 +1216,39 @@ static int vidioc_s_selection(struct file *file, void *priv,
return 0;
}
-static void vicodec_mark_last_buf(struct vicodec_ctx *ctx)
+static int vicodec_mark_last_buf(struct vicodec_ctx *ctx)
{
- static const struct v4l2_event eos_event = {
- .type = V4L2_EVENT_EOS
- };
+ struct vb2_v4l2_buffer *next_dst_buf;
+ int ret = 0;
spin_lock(ctx->lock);
- ctx->last_src_buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx);
- if (!ctx->last_src_buf && ctx->last_dst_buf) {
- ctx->last_dst_buf->flags |= V4L2_BUF_FLAG_LAST;
- v4l2_event_queue_fh(&ctx->fh, &eos_event);
+ if (ctx->is_draining) {
+ ret = -EBUSY;
+ goto unlock;
}
- spin_unlock(ctx->lock);
-}
+ if (ctx->has_stopped)
+ goto unlock;
-static int vicodec_try_encoder_cmd(struct file *file, void *fh,
- struct v4l2_encoder_cmd *ec)
-{
- if (ec->cmd != V4L2_ENC_CMD_STOP)
- return -EINVAL;
+ ctx->last_src_buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx);
+ ctx->is_draining = true;
+ if (ctx->last_src_buf)
+ goto unlock;
+
+ next_dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+ if (!next_dst_buf) {
+ ctx->next_is_last = true;
+ goto unlock;
+ }
- if (ec->flags & V4L2_ENC_CMD_STOP_AT_GOP_END)
- return -EINVAL;
+ next_dst_buf->flags |= V4L2_BUF_FLAG_LAST;
+ vb2_buffer_done(&next_dst_buf->vb2_buf, VB2_BUF_STATE_DONE);
+ ctx->is_draining = false;
+ ctx->has_stopped = true;
+ v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
- return 0;
+unlock:
+ spin_unlock(ctx->lock);
+ return ret;
}
static int vicodec_encoder_cmd(struct file *file, void *fh,
@@ -1206,27 +1257,26 @@ static int vicodec_encoder_cmd(struct file *file, void *fh,
struct vicodec_ctx *ctx = file2ctx(file);
int ret;
- ret = vicodec_try_encoder_cmd(file, fh, ec);
+ ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec);
if (ret < 0)
return ret;
- vicodec_mark_last_buf(ctx);
- return 0;
-}
-
-static int vicodec_try_decoder_cmd(struct file *file, void *fh,
- struct v4l2_decoder_cmd *dc)
-{
- if (dc->cmd != V4L2_DEC_CMD_STOP)
- return -EINVAL;
-
- if (dc->flags & V4L2_DEC_CMD_STOP_TO_BLACK)
- return -EINVAL;
-
- if (!(dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) && (dc->stop.pts != 0))
- return -EINVAL;
+ if (!vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q) ||
+ !vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q))
+ return 0;
- return 0;
+ if (ec->cmd == V4L2_ENC_CMD_STOP)
+ return vicodec_mark_last_buf(ctx);
+ ret = 0;
+ spin_lock(ctx->lock);
+ if (ctx->is_draining) {
+ ret = -EBUSY;
+ } else if (ctx->has_stopped) {
+ ctx->has_stopped = false;
+ vb2_clear_last_buffer_dequeued(&ctx->fh.m2m_ctx->cap_q_ctx.q);
+ }
+ spin_unlock(ctx->lock);
+ return ret;
}
static int vicodec_decoder_cmd(struct file *file, void *fh,
@@ -1235,12 +1285,26 @@ static int vicodec_decoder_cmd(struct file *file, void *fh,
struct vicodec_ctx *ctx = file2ctx(file);
int ret;
- ret = vicodec_try_decoder_cmd(file, fh, dc);
+ ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc);
if (ret < 0)
return ret;
- vicodec_mark_last_buf(ctx);
- return 0;
+ if (!vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q) ||
+ !vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q))
+ return 0;
+
+ if (dc->cmd == V4L2_DEC_CMD_STOP)
+ return vicodec_mark_last_buf(ctx);
+ ret = 0;
+ spin_lock(ctx->lock);
+ if (ctx->is_draining) {
+ ret = -EBUSY;
+ } else if (ctx->has_stopped) {
+ ctx->has_stopped = false;
+ vb2_clear_last_buffer_dequeued(&ctx->fh.m2m_ctx->cap_q_ctx.q);
+ }
+ spin_unlock(ctx->lock);
+ return ret;
}
static int vicodec_enum_framesizes(struct file *file, void *fh,
@@ -1283,6 +1347,8 @@ static int vicodec_subscribe_event(struct v4l2_fh *fh,
return -EINVAL;
/* fall through */
case V4L2_EVENT_EOS:
+ if (ctx->is_stateless)
+ return -EINVAL;
return v4l2_event_subscribe(fh, sub, 0, NULL);
default:
return v4l2_ctrl_subscribe_event(fh, sub);
@@ -1297,7 +1363,6 @@ static const struct v4l2_ioctl_ops vicodec_ioctl_ops = {
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap,
.vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap,
.vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap,
@@ -1307,7 +1372,6 @@ static const struct v4l2_ioctl_ops vicodec_ioctl_ops = {
.vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
.vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
- .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out,
.vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_vid_out,
.vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out,
.vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out,
@@ -1326,9 +1390,9 @@ static const struct v4l2_ioctl_ops vicodec_ioctl_ops = {
.vidioc_g_selection = vidioc_g_selection,
.vidioc_s_selection = vidioc_s_selection,
- .vidioc_try_encoder_cmd = vicodec_try_encoder_cmd,
+ .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd,
.vidioc_encoder_cmd = vicodec_encoder_cmd,
- .vidioc_try_decoder_cmd = vicodec_try_decoder_cmd,
+ .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd,
.vidioc_decoder_cmd = vicodec_decoder_cmd,
.vidioc_enum_framesizes = vicodec_enum_framesizes,
@@ -1354,6 +1418,7 @@ static int vicodec_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
*nplanes = 1;
sizes[0] = size;
+ q_data->vb2_sizeimage = size;
return 0;
}
@@ -1384,11 +1449,11 @@ static int vicodec_buf_prepare(struct vb2_buffer *vb)
}
}
- if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
+ if (vb2_plane_size(vb, 0) < q_data->vb2_sizeimage) {
dprintk(ctx->dev,
"%s data will not fit into plane (%lu < %lu)\n",
__func__, vb2_plane_size(vb, 0),
- (long)q_data->sizeimage);
+ (long)q_data->vb2_sizeimage);
return -EINVAL;
}
@@ -1412,6 +1477,25 @@ static void vicodec_buf_queue(struct vb2_buffer *vb)
.u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
};
+ if (vb2_is_streaming(vq_cap)) {
+ if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type) &&
+ ctx->next_is_last) {
+ unsigned int i;
+
+ for (i = 0; i < vb->num_planes; i++)
+ vb->planes[i].bytesused = 0;
+ vbuf->flags = V4L2_BUF_FLAG_LAST;
+ vbuf->field = V4L2_FIELD_NONE;
+ vbuf->sequence = get_q_data(ctx, vb->vb2_queue->type)->sequence++;
+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+ ctx->is_draining = false;
+ ctx->has_stopped = true;
+ ctx->next_is_last = false;
+ v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
+ return;
+ }
+ }
+
/* buf_queue handles only the first source change event */
if (ctx->first_source_change_sent) {
v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
@@ -1519,16 +1603,11 @@ static int vicodec_start_streaming(struct vb2_queue *q,
unsigned int total_planes_size;
u8 *new_comp_frame = NULL;
- if (!info)
- return -EINVAL;
-
chroma_div = info->width_div * info->height_div;
q_data->sequence = 0;
if (V4L2_TYPE_IS_OUTPUT(q->type))
ctx->last_src_buf = NULL;
- else
- ctx->last_dst_buf = NULL;
state->gop_cnt = 0;
@@ -1604,6 +1683,32 @@ static void vicodec_stop_streaming(struct vb2_queue *q)
vicodec_return_bufs(q, VB2_BUF_STATE_ERROR);
+ if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+ if (ctx->is_draining) {
+ struct vb2_v4l2_buffer *next_dst_buf;
+
+ spin_lock(ctx->lock);
+ ctx->last_src_buf = NULL;
+ next_dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+ if (!next_dst_buf) {
+ ctx->next_is_last = true;
+ } else {
+ next_dst_buf->flags |= V4L2_BUF_FLAG_LAST;
+ vb2_buffer_done(&next_dst_buf->vb2_buf, VB2_BUF_STATE_DONE);
+ ctx->is_draining = false;
+ ctx->has_stopped = true;
+ v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
+ }
+ spin_unlock(ctx->lock);
+ }
+ } else {
+ ctx->is_draining = false;
+ ctx->has_stopped = false;
+ ctx->next_is_last = false;
+ }
+ if (!ctx->is_enc && V4L2_TYPE_IS_OUTPUT(q->type))
+ ctx->first_source_change_sent = false;
+
if ((!V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) ||
(V4L2_TYPE_IS_OUTPUT(q->type) && ctx->is_enc)) {
if (!ctx->is_stateless)
@@ -1771,11 +1876,13 @@ static const struct v4l2_ctrl_config vicodec_ctrl_stateless_state = {
*/
static int vicodec_open(struct file *file)
{
+ const struct v4l2_fwht_pixfmt_info *info = v4l2_fwht_get_pixfmt(0);
struct video_device *vfd = video_devdata(file);
struct vicodec_dev *dev = video_drvdata(file);
struct vicodec_ctx *ctx = NULL;
struct v4l2_ctrl_handler *hdl;
- unsigned int size;
+ unsigned int raw_size;
+ unsigned int comp_size;
int rc = 0;
if (mutex_lock_interruptible(vfd->lock))
@@ -1795,13 +1902,16 @@ static int vicodec_open(struct file *file)
file->private_data = &ctx->fh;
ctx->dev = dev;
hdl = &ctx->hdl;
- v4l2_ctrl_handler_init(hdl, 4);
+ v4l2_ctrl_handler_init(hdl, 5);
v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE,
1, 16, 1, 10);
v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_FWHT_I_FRAME_QP,
1, 31, 1, 20);
v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_FWHT_P_FRAME_QP,
1, 31, 1, 20);
+ if (ctx->is_enc)
+ v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops,
+ V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 1, 1, 1, 1);
if (ctx->is_stateless)
v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_stateless_state, NULL);
if (hdl->error) {
@@ -1814,7 +1924,7 @@ static int vicodec_open(struct file *file)
v4l2_ctrl_handler_setup(hdl);
if (ctx->is_enc)
- ctx->q_data[V4L2_M2M_SRC].info = v4l2_fwht_get_pixfmt(0);
+ ctx->q_data[V4L2_M2M_SRC].info = info;
else if (ctx->is_stateless)
ctx->q_data[V4L2_M2M_SRC].info = &pixfmt_stateless_fwht;
else
@@ -1823,22 +1933,24 @@ static int vicodec_open(struct file *file)
ctx->q_data[V4L2_M2M_SRC].coded_height = 720;
ctx->q_data[V4L2_M2M_SRC].visible_width = 1280;
ctx->q_data[V4L2_M2M_SRC].visible_height = 720;
- size = 1280 * 720 * ctx->q_data[V4L2_M2M_SRC].info->sizeimage_mult /
- ctx->q_data[V4L2_M2M_SRC].info->sizeimage_div;
- if (ctx->is_enc || ctx->is_stateless)
- ctx->q_data[V4L2_M2M_SRC].sizeimage = size;
+ raw_size = 1280 * 720 * info->sizeimage_mult / info->sizeimage_div;
+ comp_size = 1280 * 720 * pixfmt_fwht.sizeimage_mult /
+ pixfmt_fwht.sizeimage_div;
+ if (ctx->is_enc)
+ ctx->q_data[V4L2_M2M_SRC].sizeimage = raw_size;
+ else if (ctx->is_stateless)
+ ctx->q_data[V4L2_M2M_SRC].sizeimage = comp_size;
else
ctx->q_data[V4L2_M2M_SRC].sizeimage =
- size + sizeof(struct fwht_cframe_hdr);
+ comp_size + sizeof(struct fwht_cframe_hdr);
+ ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC];
if (ctx->is_enc) {
- ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC];
ctx->q_data[V4L2_M2M_DST].info = &pixfmt_fwht;
- ctx->q_data[V4L2_M2M_DST].sizeimage = 1280 * 720 *
- ctx->q_data[V4L2_M2M_DST].info->sizeimage_mult /
- ctx->q_data[V4L2_M2M_DST].info->sizeimage_div +
- sizeof(struct fwht_cframe_hdr);
+ ctx->q_data[V4L2_M2M_DST].sizeimage =
+ comp_size + sizeof(struct fwht_cframe_hdr);
} else {
- ctx->q_data[V4L2_M2M_DST].info = NULL;
+ ctx->q_data[V4L2_M2M_DST].info = info;
+ ctx->q_data[V4L2_M2M_DST].sizeimage = raw_size;
}
ctx->state.colorspace = V4L2_COLORSPACE_REC709;
@@ -2013,18 +2125,31 @@ static int register_instance(struct vicodec_dev *dev,
return 0;
}
+static void vicodec_v4l2_dev_release(struct v4l2_device *v4l2_dev)
+{
+ struct vicodec_dev *dev = container_of(v4l2_dev, struct vicodec_dev, v4l2_dev);
+
+ v4l2_device_unregister(&dev->v4l2_dev);
+ v4l2_m2m_release(dev->stateful_enc.m2m_dev);
+ v4l2_m2m_release(dev->stateful_dec.m2m_dev);
+ v4l2_m2m_release(dev->stateless_dec.m2m_dev);
+ kfree(dev);
+}
+
static int vicodec_probe(struct platform_device *pdev)
{
struct vicodec_dev *dev;
int ret;
- dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
if (ret)
- return ret;
+ goto free_dev;
+
+ dev->v4l2_dev.release = vicodec_v4l2_dev_release;
#ifdef CONFIG_MEDIA_CONTROLLER
dev->mdev.dev = &pdev->dev;
@@ -2102,6 +2227,8 @@ unreg_sf_enc:
v4l2_m2m_release(dev->stateful_enc.m2m_dev);
unreg_dev:
v4l2_device_unregister(&dev->v4l2_dev);
+free_dev:
+ kfree(dev);
return ret;
}
@@ -2120,12 +2247,10 @@ static int vicodec_remove(struct platform_device *pdev)
media_device_cleanup(&dev->mdev);
#endif
- v4l2_m2m_release(dev->stateful_enc.m2m_dev);
- v4l2_m2m_release(dev->stateful_dec.m2m_dev);
video_unregister_device(&dev->stateful_enc.vfd);
video_unregister_device(&dev->stateful_dec.vfd);
video_unregister_device(&dev->stateless_dec.vfd);
- v4l2_device_unregister(&dev->v4l2_dev);
+ v4l2_device_put(&dev->v4l2_dev);
return 0;
}
diff --git a/drivers/media/platform/vim2m.c b/drivers/media/platform/vim2m.c
index 243c82b5d537..acd3bd48c7e2 100644
--- a/drivers/media/platform/vim2m.c
+++ b/drivers/media/platform/vim2m.c
@@ -1359,7 +1359,7 @@ static int vim2m_probe(struct platform_device *pdev)
MEDIA_ENT_F_PROC_VIDEO_SCALER);
if (ret) {
v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n");
- goto error_m2m;
+ goto error_dev;
}
ret = media_device_register(&dev->mdev);
@@ -1373,11 +1373,11 @@ static int vim2m_probe(struct platform_device *pdev)
#ifdef CONFIG_MEDIA_CONTROLLER
error_m2m_mc:
v4l2_m2m_unregister_media_controller(dev->m2m_dev);
-error_m2m:
- v4l2_m2m_release(dev->m2m_dev);
#endif
error_dev:
video_unregister_device(&dev->vfd);
+ /* vim2m_device_release called by video_unregister_device to release various objects */
+ return ret;
error_v4l2:
v4l2_device_unregister(&dev->v4l2_dev);
error_free:
diff --git a/drivers/media/platform/vimc/Kconfig b/drivers/media/platform/vimc/Kconfig
index beba6acce593..bd221d3e1a4a 100644
--- a/drivers/media/platform/vimc/Kconfig
+++ b/drivers/media/platform/vimc/Kconfig
@@ -4,7 +4,6 @@ config VIDEO_VIMC
depends on VIDEO_DEV && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
select VIDEOBUF2_VMALLOC
select VIDEO_V4L2_TPG
- default n
help
Skeleton driver for Virtual Media Controller
diff --git a/drivers/media/platform/vimc/Makefile b/drivers/media/platform/vimc/Makefile
index c4fc8e7d365a..96d06f030c31 100644
--- a/drivers/media/platform/vimc/Makefile
+++ b/drivers/media/platform/vimc/Makefile
@@ -1,11 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
-vimc-objs := vimc-core.o
-vimc_capture-objs := vimc-capture.o
-vimc_common-objs := vimc-common.o
-vimc_debayer-objs := vimc-debayer.o
-vimc_scaler-objs := vimc-scaler.o
-vimc_sensor-objs := vimc-sensor.o
-vimc_streamer-objs := vimc-streamer.o
+vimc-y := vimc-core.o vimc-common.o vimc-streamer.o
-obj-$(CONFIG_VIDEO_VIMC) += vimc.o vimc_capture.o vimc_common.o vimc-debayer.o \
- vimc_scaler.o vimc_sensor.o vimc_streamer.o
+obj-$(CONFIG_VIDEO_VIMC) += vimc.o vimc-capture.o vimc-debayer.o \
+ vimc-scaler.o vimc-sensor.o
diff --git a/drivers/media/platform/vimc/vimc-capture.c b/drivers/media/platform/vimc/vimc-capture.c
index 946dc0908566..664855708fdf 100644
--- a/drivers/media/platform/vimc/vimc-capture.c
+++ b/drivers/media/platform/vimc/vimc-capture.c
@@ -142,12 +142,15 @@ static int vimc_cap_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct vimc_cap_device *vcap = video_drvdata(file);
+ int ret;
/* Do not change the format while stream is on */
if (vb2_is_busy(&vcap->queue))
return -EBUSY;
- vimc_cap_try_fmt_vid_cap(file, priv, f);
+ ret = vimc_cap_try_fmt_vid_cap(file, priv, f);
+ if (ret)
+ return ret;
dev_dbg(vcap->dev, "%s: format update: "
"old:%dx%d (0x%x, %d, %d, %d, %d) "
diff --git a/drivers/media/platform/vimc/vimc-common.c b/drivers/media/platform/vimc/vimc-common.c
index f4d2073076ed..03016f204d05 100644
--- a/drivers/media/platform/vimc/vimc-common.c
+++ b/drivers/media/platform/vimc/vimc-common.c
@@ -377,7 +377,3 @@ void vimc_ent_sd_unregister(struct vimc_ent_device *ved, struct v4l2_subdev *sd)
v4l2_device_unregister_subdev(sd);
}
EXPORT_SYMBOL_GPL(vimc_ent_sd_unregister);
-
-MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC) Common");
-MODULE_AUTHOR("Helen Koike <helen.fornazier@gmail.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/vimc/vimc-core.c b/drivers/media/platform/vimc/vimc-core.c
index 03707bdcbfa8..571c55aa0e16 100644
--- a/drivers/media/platform/vimc/vimc-core.c
+++ b/drivers/media/platform/vimc/vimc-core.c
@@ -234,10 +234,7 @@ static void vimc_comp_unbind(struct device *master)
static int vimc_comp_compare(struct device *comp, void *data)
{
- const struct platform_device *pdev = to_platform_device(comp);
- const char *name = data;
-
- return !strcmp(pdev->dev.platform_data, name);
+ return comp == data;
}
static struct component_match *vimc_add_subdevs(struct vimc_device *vimc)
@@ -267,7 +264,7 @@ static struct component_match *vimc_add_subdevs(struct vimc_device *vimc)
}
component_match_add(&vimc->pdev.dev, &match, vimc_comp_compare,
- (void *)vimc->pipe_cfg->ents[i].name);
+ &vimc->subdevs[i]->dev);
}
return match;
diff --git a/drivers/media/platform/vimc/vimc-debayer.c b/drivers/media/platform/vimc/vimc-debayer.c
index 3ae8c12f5fa3..00598fbf3cba 100644
--- a/drivers/media/platform/vimc/vimc-debayer.c
+++ b/drivers/media/platform/vimc/vimc-debayer.c
@@ -16,14 +16,16 @@
#include "vimc-common.h"
#define VIMC_DEB_DRV_NAME "vimc-debayer"
-/* This module only supports tranforming a bayer format to V4L2_PIX_FMT_RGB24 */
+/* This module only supports transforming a bayer format
+ * to V4L2_PIX_FMT_RGB24
+ */
#define VIMC_DEB_SRC_PIXFMT V4L2_PIX_FMT_RGB24
#define VIMC_DEB_SRC_MBUS_FMT_DEFAULT MEDIA_BUS_FMT_RGB888_1X24
static unsigned int deb_mean_win_size = 3;
module_param(deb_mean_win_size, uint, 0000);
MODULE_PARM_DESC(deb_mean_win_size, " the window size to calculate the mean.\n"
- "NOTE: the window size need to be an odd number, as the main pixel "
+ "NOTE: the window size needs to be an odd number, as the main pixel "
"stays in the center of the window, otherwise the next odd number "
"is considered");
@@ -260,7 +262,7 @@ static int vimc_deb_set_fmt(struct v4l2_subdev *sd,
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
/* Do not change the format while stream is on */
- if (vdeb->src_frame)
+ if (vdeb->ved.stream)
return -EBUSY;
sink_fmt = &vdeb->sink_fmt;
@@ -327,9 +329,6 @@ static int vimc_deb_s_stream(struct v4l2_subdev *sd, int enable)
const struct v4l2_format_info *pix_info;
unsigned int frame_size;
- if (vdeb->src_frame)
- return 0;
-
/* We only support translating bayer to RGB24 */
if (src_pixelformat != V4L2_PIX_FMT_RGB24) {
dev_err(vdeb->dev,
diff --git a/drivers/media/platform/vimc/vimc-scaler.c b/drivers/media/platform/vimc/vimc-scaler.c
index 5f31c1e351a3..c7123a45c55b 100644
--- a/drivers/media/platform/vimc/vimc-scaler.c
+++ b/drivers/media/platform/vimc/vimc-scaler.c
@@ -148,7 +148,7 @@ static int vimc_sca_set_fmt(struct v4l2_subdev *sd,
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
/* Do not change the format while stream is on */
- if (vsca->src_frame)
+ if (vsca->ved.stream)
return -EBUSY;
sink_fmt = &vsca->sink_fmt;
@@ -203,9 +203,6 @@ static int vimc_sca_s_stream(struct v4l2_subdev *sd, int enable)
const struct v4l2_format_info *pix_info;
unsigned int frame_size;
- if (vsca->src_frame)
- return 0;
-
if (!vimc_sca_is_pixfmt_supported(pixelformat)) {
dev_err(vsca->dev, "pixfmt (0x%08x) is not supported\n",
pixelformat);
@@ -327,7 +324,7 @@ static void *vimc_sca_process_frame(struct vimc_ent_device *ved,
ved);
/* If the stream in this node is not active, just return */
- if (!vsca->src_frame)
+ if (!ved->stream)
return ERR_PTR(-EINVAL);
vimc_sca_fill_src_frame(vsca, sink_frame);
diff --git a/drivers/media/platform/vimc/vimc-sensor.c b/drivers/media/platform/vimc/vimc-sensor.c
index 46a25f705456..51359472eef2 100644
--- a/drivers/media/platform/vimc/vimc-sensor.c
+++ b/drivers/media/platform/vimc/vimc-sensor.c
@@ -131,7 +131,7 @@ static int vimc_sen_set_fmt(struct v4l2_subdev *sd,
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
/* Do not change the format while stream is on */
- if (vsen->frame)
+ if (vsen->ved.stream)
return -EBUSY;
mf = &vsen->mbus_format;
@@ -187,10 +187,6 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable)
const struct v4l2_format_info *pix_info;
unsigned int frame_size;
- if (vsen->kthread_sen)
- /* tpg is already executing */
- return 0;
-
/* Calculate the frame size */
pix_info = v4l2_format_info(pixelformat);
frame_size = vsen->mbus_format.width * pix_info->bpp[0] *
@@ -211,7 +207,6 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable)
vfree(vsen->frame);
vsen->frame = NULL;
- return 0;
}
return 0;
diff --git a/drivers/media/platform/vimc/vimc-streamer.c b/drivers/media/platform/vimc/vimc-streamer.c
index 26b674259489..3b3f36357a0e 100644
--- a/drivers/media/platform/vimc/vimc-streamer.c
+++ b/drivers/media/platform/vimc/vimc-streamer.c
@@ -122,6 +122,14 @@ static int vimc_streamer_pipeline_init(struct vimc_stream *stream,
return -EINVAL;
}
+/*
+ * vimc_streamer_thread - process frames through the pipeline
+ *
+ * @data: vimc_stream struct of the current stream
+ *
+ * From the source to the sink, gets a frame from each subdevice and send to
+ * the next one of the pipeline at a fixed framerate.
+ */
static int vimc_streamer_thread(void *data)
{
struct vimc_stream *stream = data;
@@ -149,6 +157,20 @@ static int vimc_streamer_thread(void *data)
return 0;
}
+/*
+ * vimc_streamer_s_stream - start/stop the streaming on the media pipeline
+ *
+ * @stream: the pointer to the stream structure of the current stream
+ * @ved: pointer to the vimc entity of the entity of the stream
+ * @enable: flag to determine if stream should start/stop
+ *
+ * When starting, check if there is no stream->kthread allocated. This should
+ * indicate that a stream is already running. Then, it initializes
+ * the pipeline, creates and runs a kthread to consume buffers through the
+ * pipeline.
+ * When stopping, analogously check if there is a stream running, stop
+ * the thread and terminates the pipeline.
+ */
int vimc_streamer_s_stream(struct vimc_stream *stream,
struct vimc_ent_device *ved,
int enable)
@@ -188,7 +210,3 @@ int vimc_streamer_s_stream(struct vimc_stream *stream,
return 0;
}
EXPORT_SYMBOL_GPL(vimc_streamer_s_stream);
-
-MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC) Streamer");
-MODULE_AUTHOR("Lucas A. M. Magalhães <lucmaga@gmail.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/vivid/Kconfig b/drivers/media/platform/vivid/Kconfig
index b172bcc11758..e2ff06edfa93 100644
--- a/drivers/media/platform/vivid/Kconfig
+++ b/drivers/media/platform/vivid/Kconfig
@@ -11,7 +11,6 @@ config VIDEO_VIVID
select VIDEOBUF2_VMALLOC
select VIDEOBUF2_DMA_CONTIG
select VIDEO_V4L2_TPG
- default n
help
Enables a virtual video driver. This driver emulates a webcam,
TV, S-Video and HDMI capture hardware, including VBI support for
diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c
index 7047df6f0e0e..bc2a176937a4 100644
--- a/drivers/media/platform/vivid/vivid-core.c
+++ b/drivers/media/platform/vivid/vivid-core.c
@@ -500,20 +500,18 @@ static const struct v4l2_file_operations vivid_radio_fops = {
static const struct v4l2_ioctl_ops vivid_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
- .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid,
+ .vidioc_enum_fmt_vid_cap = vivid_enum_fmt_vid,
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_mplane,
.vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap_mplane,
.vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap_mplane,
.vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap_mplane,
- .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid,
+ .vidioc_enum_fmt_vid_out = vivid_enum_fmt_vid,
.vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out,
.vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
.vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
- .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_mplane,
.vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_vid_out_mplane,
.vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out_mplane,
.vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out_mplane,
@@ -669,6 +667,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_std_id tvnorms_cap = 0, tvnorms_out = 0;
int ret;
int i;
+#ifdef CONFIG_VIDEO_VIVID_CEC
+ unsigned int cec_tx_bus_cnt = 0;
+#endif
/* allocate main vivid state structure */
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
@@ -722,6 +723,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
in_type_counter[HDMI]--;
dev->num_inputs--;
}
+ dev->num_hdmi_inputs = in_type_counter[HDMI];
/* how many outputs do we have and of what type? */
dev->num_outputs = num_outputs[inst];
@@ -732,6 +734,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
for (i = 0; i < dev->num_outputs; i++) {
dev->output_type[i] = ((output_types[inst] >> i) & 1) ? HDMI : SVID;
dev->output_name_counter[i] = out_type_counter[dev->output_type[i]]++;
+ dev->display_present[i] = true;
}
dev->has_audio_outputs = out_type_counter[SVID];
if (out_type_counter[HDMI] == 16) {
@@ -743,6 +746,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
out_type_counter[HDMI]--;
dev->num_outputs--;
}
+ dev->num_hdmi_outputs = out_type_counter[HDMI];
/* do we create a video capture device? */
dev->has_vid_cap = node_type & 0x0001;
@@ -1001,13 +1005,15 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->webcam_size_idx = 1;
dev->webcam_ival_idx = 3;
tpg_s_fourcc(&dev->tpg, dev->fmt_cap->fourcc);
- dev->std_cap = V4L2_STD_PAL;
dev->std_out = V4L2_STD_PAL;
if (dev->input_type[0] == TV || dev->input_type[0] == SVID)
tvnorms_cap = V4L2_STD_ALL;
if (dev->output_type[0] == SVID)
tvnorms_out = V4L2_STD_ALL;
- dev->dv_timings_cap = def_dv_timings;
+ for (i = 0; i < MAX_INPUTS; i++) {
+ dev->dv_timings_cap[i] = def_dv_timings;
+ dev->std_cap[i] = V4L2_STD_PAL;
+ }
dev->dv_timings_out = def_dv_timings;
dev->tv_freq = 2804 /* 175.25 * 16 */;
dev->tv_audmode = V4L2_TUNER_MODE_STEREO;
@@ -1037,6 +1043,17 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
if (ret)
goto unreg_dev;
+ /* enable/disable interface specific controls */
+ if (dev->num_outputs && dev->output_type[0] != HDMI)
+ v4l2_ctrl_activate(dev->ctrl_display_present, false);
+ if (dev->num_inputs && dev->input_type[0] != HDMI) {
+ v4l2_ctrl_activate(dev->ctrl_dv_timings_signal_mode, false);
+ v4l2_ctrl_activate(dev->ctrl_dv_timings, false);
+ } else if (dev->num_inputs && dev->input_type[0] == HDMI) {
+ v4l2_ctrl_activate(dev->ctrl_std_signal_mode, false);
+ v4l2_ctrl_activate(dev->ctrl_standard, false);
+ }
+
/*
* update the capture and output formats to do a proper initial
* configuration.
@@ -1044,14 +1061,6 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
vivid_update_format_cap(dev, false);
vivid_update_format_out(dev);
- v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_cap);
- v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_out);
- v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vbi_cap);
- v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vbi_out);
- v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_rx);
- v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_tx);
- v4l2_ctrl_handler_setup(&dev->ctrl_hdl_sdr_cap);
-
/* initialize overlay */
dev->fb_cap.fmt.width = dev->src_rect.width;
dev->fb_cap.fmt.height = dev->src_rect.height;
@@ -1212,6 +1221,47 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->fb_info.node);
}
+#ifdef CONFIG_VIDEO_VIVID_CEC
+ if (dev->has_vid_cap && in_type_counter[HDMI]) {
+ struct cec_adapter *adap;
+
+ adap = vivid_cec_alloc_adap(dev, 0, false);
+ ret = PTR_ERR_OR_ZERO(adap);
+ if (ret < 0)
+ goto unreg_dev;
+ dev->cec_rx_adap = adap;
+ }
+
+ if (dev->has_vid_out) {
+ for (i = 0; i < dev->num_outputs; i++) {
+ struct cec_adapter *adap;
+
+ if (dev->output_type[i] != HDMI)
+ continue;
+
+ dev->cec_output2bus_map[i] = cec_tx_bus_cnt;
+ adap = vivid_cec_alloc_adap(dev, cec_tx_bus_cnt, true);
+ ret = PTR_ERR_OR_ZERO(adap);
+ if (ret < 0) {
+ for (i = 0; i < dev->num_outputs; i++)
+ cec_delete_adapter(dev->cec_tx_adap[i]);
+ goto unreg_dev;
+ }
+
+ dev->cec_tx_adap[cec_tx_bus_cnt] = adap;
+ cec_tx_bus_cnt++;
+ }
+ }
+#endif
+
+ v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_cap);
+ v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_out);
+ v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vbi_cap);
+ v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vbi_out);
+ v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_rx);
+ v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_tx);
+ v4l2_ctrl_handler_setup(&dev->ctrl_hdl_sdr_cap);
+
/* finally start creating the device nodes */
if (dev->has_vid_cap) {
vfd = &dev->vid_cap_dev;
@@ -1241,22 +1291,15 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
#ifdef CONFIG_VIDEO_VIVID_CEC
if (in_type_counter[HDMI]) {
- struct cec_adapter *adap;
-
- adap = vivid_cec_alloc_adap(dev, 0, false);
- ret = PTR_ERR_OR_ZERO(adap);
- if (ret < 0)
- goto unreg_dev;
- dev->cec_rx_adap = adap;
- ret = cec_register_adapter(adap, &pdev->dev);
+ ret = cec_register_adapter(dev->cec_rx_adap, &pdev->dev);
if (ret < 0) {
- cec_delete_adapter(adap);
+ cec_delete_adapter(dev->cec_rx_adap);
dev->cec_rx_adap = NULL;
goto unreg_dev;
}
- cec_s_phys_addr(adap, 0, false);
+ cec_s_phys_addr(dev->cec_rx_adap, 0, false);
v4l2_info(&dev->v4l2_dev, "CEC adapter %s registered for HDMI input 0\n",
- dev_name(&adap->devnode.dev));
+ dev_name(&dev->cec_rx_adap->devnode.dev));
}
#endif
@@ -1268,10 +1311,6 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
}
if (dev->has_vid_out) {
-#ifdef CONFIG_VIDEO_VIVID_CEC
- unsigned int bus_cnt = 0;
-#endif
-
vfd = &dev->vid_out_dev;
snprintf(vfd->name, sizeof(vfd->name),
"vivid-%03d-vid-out", inst);
@@ -1299,30 +1338,21 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
#endif
#ifdef CONFIG_VIDEO_VIVID_CEC
- for (i = 0; i < dev->num_outputs; i++) {
- struct cec_adapter *adap;
-
- if (dev->output_type[i] != HDMI)
- continue;
- dev->cec_output2bus_map[i] = bus_cnt;
- adap = vivid_cec_alloc_adap(dev, bus_cnt, true);
- ret = PTR_ERR_OR_ZERO(adap);
- if (ret < 0)
- goto unreg_dev;
- dev->cec_tx_adap[bus_cnt] = adap;
- ret = cec_register_adapter(adap, &pdev->dev);
+ for (i = 0; i < cec_tx_bus_cnt; i++) {
+ ret = cec_register_adapter(dev->cec_tx_adap[i], &pdev->dev);
if (ret < 0) {
- cec_delete_adapter(adap);
- dev->cec_tx_adap[bus_cnt] = NULL;
+ for (; i < cec_tx_bus_cnt; i++) {
+ cec_delete_adapter(dev->cec_tx_adap[i]);
+ dev->cec_tx_adap[i] = NULL;
+ }
goto unreg_dev;
}
v4l2_info(&dev->v4l2_dev, "CEC adapter %s registered for HDMI output %d\n",
- dev_name(&adap->devnode.dev), bus_cnt);
- bus_cnt++;
- if (bus_cnt <= out_type_counter[HDMI])
- cec_s_phys_addr(adap, bus_cnt << 12, false);
+ dev_name(&dev->cec_tx_adap[i]->devnode.dev), i);
+ if (i <= out_type_counter[HDMI])
+ cec_s_phys_addr(dev->cec_tx_adap[i], i << 12, false);
else
- cec_s_phys_addr(adap, 0x1000, false);
+ cec_s_phys_addr(dev->cec_tx_adap[i], 0x1000, false);
}
#endif
diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h
index 6697c7009629..7ebb14673c75 100644
--- a/drivers/media/platform/vivid/vivid-core.h
+++ b/drivers/media/platform/vivid/vivid-core.h
@@ -22,18 +22,6 @@
#define dprintk(dev, level, fmt, arg...) \
v4l2_dbg(level, vivid_debug, &dev->v4l2_dev, fmt, ## arg)
-/* Maximum allowed frame rate
- *
- * vivid will allow setting timeperframe in [1/FPS_MAX - FPS_MAX/1] range.
- *
- * Ideally FPS_MAX should be infinity, i.e. practically UINT_MAX, but that
- * might hit application errors when they manipulate these values.
- *
- * Besides, for tpf < 10ms image-generation logic should be changed, to avoid
- * producing frames with equal content.
- */
-#define FPS_MAX 100
-
/* The maximum number of clip rectangles */
#define MAX_CLIPS 16
/* The maximum number of inputs */
@@ -180,9 +168,11 @@ struct vivid_dev {
/* supported features */
bool multiplanar;
unsigned num_inputs;
+ unsigned int num_hdmi_inputs;
u8 input_type[MAX_INPUTS];
u8 input_name_counter[MAX_INPUTS];
unsigned num_outputs;
+ unsigned int num_hdmi_outputs;
u8 output_type[MAX_OUTPUTS];
u8 output_name_counter[MAX_OUTPUTS];
bool has_audio_inputs;
@@ -237,6 +227,7 @@ struct vivid_dev {
struct v4l2_ctrl *ctrl_dv_timings_signal_mode;
struct v4l2_ctrl *ctrl_dv_timings;
};
+ struct v4l2_ctrl *ctrl_display_present;
struct v4l2_ctrl *ctrl_has_crop_cap;
struct v4l2_ctrl *ctrl_has_compose_cap;
struct v4l2_ctrl *ctrl_has_scaler_cap;
@@ -245,6 +236,11 @@ struct vivid_dev {
struct v4l2_ctrl *ctrl_has_scaler_out;
struct v4l2_ctrl *ctrl_tx_mode;
struct v4l2_ctrl *ctrl_tx_rgb_range;
+ struct v4l2_ctrl *ctrl_tx_edid_present;
+ struct v4l2_ctrl *ctrl_tx_hotplug;
+ struct v4l2_ctrl *ctrl_tx_rxsense;
+
+ struct v4l2_ctrl *ctrl_rx_power_present;
struct v4l2_ctrl *radio_tx_rds_pi;
struct v4l2_ctrl *radio_tx_rds_pty;
@@ -299,23 +295,24 @@ struct vivid_dev {
bool time_wrap;
u64 time_wrap_offset;
unsigned perc_dropped_buffers;
- enum vivid_signal_mode std_signal_mode;
- unsigned query_std_last;
- v4l2_std_id query_std;
- enum tpg_video_aspect std_aspect_ratio;
+ enum vivid_signal_mode std_signal_mode[MAX_INPUTS];
+ unsigned int query_std_last[MAX_INPUTS];
+ v4l2_std_id query_std[MAX_INPUTS];
+ enum tpg_video_aspect std_aspect_ratio[MAX_INPUTS];
- enum vivid_signal_mode dv_timings_signal_mode;
+ enum vivid_signal_mode dv_timings_signal_mode[MAX_INPUTS];
char **query_dv_timings_qmenu;
char *query_dv_timings_qmenu_strings;
unsigned query_dv_timings_size;
- unsigned query_dv_timings_last;
- unsigned query_dv_timings;
- enum tpg_video_aspect dv_timings_aspect_ratio;
+ unsigned int query_dv_timings_last[MAX_INPUTS];
+ unsigned int query_dv_timings[MAX_INPUTS];
+ enum tpg_video_aspect dv_timings_aspect_ratio[MAX_INPUTS];
/* Input */
unsigned input;
- v4l2_std_id std_cap;
- struct v4l2_dv_timings dv_timings_cap;
+ v4l2_std_id std_cap[MAX_INPUTS];
+ struct v4l2_dv_timings dv_timings_cap[MAX_INPUTS];
+ int dv_timings_cap_sel[MAX_INPUTS];
u32 service_set_cap;
struct vivid_vbi_gen_data vbi_gen;
u8 *edid;
@@ -328,6 +325,8 @@ struct vivid_dev {
unsigned tv_field_cap;
unsigned tv_audio_input;
+ u32 power_present;
+
/* Capture Overlay */
struct v4l2_framebuffer fb_cap;
struct v4l2_fh *overlay_cap_owner;
@@ -360,6 +359,7 @@ struct vivid_dev {
u8 *scaled_line;
u8 *blended_line;
unsigned cur_scaled_line;
+ bool display_present[MAX_OUTPUTS];
/* Output Overlay */
void *fb_vbase_out;
diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c
index 4cd526ff248b..3e916c8befb7 100644
--- a/drivers/media/platform/vivid/vivid-ctrls.c
+++ b/drivers/media/platform/vivid/vivid-ctrls.c
@@ -18,6 +18,7 @@
#include "vivid-radio-common.h"
#include "vivid-osd.h"
#include "vivid-ctrls.h"
+#include "vivid-cec.h"
#define VIVID_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000)
#define VIVID_CID_BUTTON (VIVID_CID_CUSTOM_BASE + 0)
@@ -68,6 +69,7 @@
#define VIVID_CID_PERCENTAGE_FILL (VIVID_CID_VIVID_BASE + 41)
#define VIVID_CID_REDUCED_FPS (VIVID_CID_VIVID_BASE + 42)
#define VIVID_CID_HSV_ENC (VIVID_CID_VIVID_BASE + 43)
+#define VIVID_CID_DISPLAY_PRESENT (VIVID_CID_VIVID_BASE + 44)
#define VIVID_CID_STD_SIGNAL_MODE (VIVID_CID_VIVID_BASE + 60)
#define VIVID_CID_STANDARD (VIVID_CID_VIVID_BASE + 61)
@@ -357,7 +359,7 @@ static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl)
V4L2_COLORSPACE_470_SYSTEM_BG,
};
struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vid_cap);
- unsigned i;
+ unsigned int i, j;
switch (ctrl->id) {
case VIVID_CID_TEST_PATTERN:
@@ -463,20 +465,35 @@ static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl)
tpg_s_show_square(&dev->tpg, ctrl->val);
break;
case VIVID_CID_STD_ASPECT_RATIO:
- dev->std_aspect_ratio = ctrl->val;
+ dev->std_aspect_ratio[dev->input] = ctrl->val;
tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev));
break;
case VIVID_CID_DV_TIMINGS_SIGNAL_MODE:
- dev->dv_timings_signal_mode = dev->ctrl_dv_timings_signal_mode->val;
- if (dev->dv_timings_signal_mode == SELECTED_DV_TIMINGS)
- dev->query_dv_timings = dev->ctrl_dv_timings->val;
+ dev->dv_timings_signal_mode[dev->input] =
+ dev->ctrl_dv_timings_signal_mode->val;
+ dev->query_dv_timings[dev->input] = dev->ctrl_dv_timings->val;
+
+ dev->power_present = 0;
+ for (i = 0, j = 0;
+ i < ARRAY_SIZE(dev->dv_timings_signal_mode);
+ i++)
+ if (dev->input_type[i] == HDMI) {
+ if (dev->dv_timings_signal_mode[i] != NO_SIGNAL)
+ dev->power_present |= (1 << j);
+ j++;
+ }
+ __v4l2_ctrl_s_ctrl(dev->ctrl_rx_power_present,
+ dev->power_present);
+
v4l2_ctrl_activate(dev->ctrl_dv_timings,
- dev->dv_timings_signal_mode == SELECTED_DV_TIMINGS);
+ dev->dv_timings_signal_mode[dev->input] ==
+ SELECTED_DV_TIMINGS);
+
vivid_update_quality(dev);
vivid_send_source_change(dev, HDMI);
break;
case VIVID_CID_DV_TIMINGS_ASPECT_RATIO:
- dev->dv_timings_aspect_ratio = ctrl->val;
+ dev->dv_timings_aspect_ratio[dev->input] = ctrl->val;
tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev));
break;
case VIVID_CID_TSTAMP_SRC:
@@ -908,6 +925,8 @@ static int vivid_vid_out_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vid_out);
struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt;
+ u32 display_present = 0;
+ unsigned int i, j, bus_idx;
switch (ctrl->id) {
case VIVID_CID_HAS_CROP_OUT:
@@ -941,6 +960,37 @@ static int vivid_vid_out_s_ctrl(struct v4l2_ctrl *ctrl)
if (dev->loop_video)
vivid_send_source_change(dev, HDMI);
break;
+ case VIVID_CID_DISPLAY_PRESENT:
+ if (dev->output_type[dev->output] != HDMI)
+ break;
+
+ dev->display_present[dev->output] = ctrl->val;
+ for (i = 0, j = 0; i < dev->num_outputs; i++)
+ if (dev->output_type[i] == HDMI)
+ display_present |=
+ dev->display_present[i] << j++;
+
+ __v4l2_ctrl_s_ctrl(dev->ctrl_tx_rxsense, display_present);
+
+ if (dev->edid_blocks) {
+ __v4l2_ctrl_s_ctrl(dev->ctrl_tx_edid_present,
+ display_present);
+ __v4l2_ctrl_s_ctrl(dev->ctrl_tx_hotplug,
+ display_present);
+ }
+
+ bus_idx = dev->cec_output2bus_map[dev->output];
+ if (!dev->cec_tx_adap[bus_idx])
+ break;
+
+ if (ctrl->val && dev->edid_blocks)
+ cec_s_phys_addr(dev->cec_tx_adap[bus_idx],
+ dev->cec_tx_adap[bus_idx]->phys_addr,
+ false);
+ else
+ cec_phys_addr_invalidate(dev->cec_tx_adap[bus_idx]);
+
+ break;
}
return 0;
}
@@ -979,6 +1029,15 @@ static const struct v4l2_ctrl_config vivid_ctrl_has_scaler_out = {
.step = 1,
};
+static const struct v4l2_ctrl_config vivid_ctrl_display_present = {
+ .ops = &vivid_vid_out_ctrl_ops,
+ .id = VIVID_CID_DISPLAY_PRESENT,
+ .name = "Display Present",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .max = 1,
+ .def = 1,
+ .step = 1,
+};
/* Streaming Controls */
@@ -1127,10 +1186,14 @@ static int vivid_sdtv_cap_s_ctrl(struct v4l2_ctrl *ctrl)
switch (ctrl->id) {
case VIVID_CID_STD_SIGNAL_MODE:
- dev->std_signal_mode = dev->ctrl_std_signal_mode->val;
- if (dev->std_signal_mode == SELECTED_STD)
- dev->query_std = vivid_standard[dev->ctrl_standard->val];
- v4l2_ctrl_activate(dev->ctrl_standard, dev->std_signal_mode == SELECTED_STD);
+ dev->std_signal_mode[dev->input] =
+ dev->ctrl_std_signal_mode->val;
+ if (dev->std_signal_mode[dev->input] == SELECTED_STD)
+ dev->query_std[dev->input] =
+ vivid_standard[dev->ctrl_standard->val];
+ v4l2_ctrl_activate(dev->ctrl_standard,
+ dev->std_signal_mode[dev->input] ==
+ SELECTED_STD);
vivid_update_quality(dev);
vivid_send_source_change(dev, TV);
vivid_send_source_change(dev, SVID);
@@ -1549,7 +1612,7 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
v4l2_ctrl_new_custom(hdl_vbi_cap, &vivid_ctrl_vbi_cap_interlaced, NULL);
}
- if (has_hdmi && dev->has_vid_cap) {
+ if (dev->num_hdmi_inputs) {
dev->ctrl_dv_timings_signal_mode = v4l2_ctrl_new_custom(hdl_vid_cap,
&vivid_ctrl_dv_timings_signal_mode, NULL);
@@ -1569,8 +1632,13 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
&vivid_vid_cap_ctrl_ops,
V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL,
0, V4L2_DV_RGB_RANGE_AUTO);
+ dev->ctrl_rx_power_present = v4l2_ctrl_new_std(hdl_vid_cap,
+ NULL, V4L2_CID_DV_RX_POWER_PRESENT, 0,
+ (2 << (dev->num_hdmi_inputs - 1)) - 1, 0,
+ (2 << (dev->num_hdmi_inputs - 1)) - 1);
+
}
- if (has_hdmi && dev->has_vid_out) {
+ if (dev->num_hdmi_outputs) {
/*
* We aren't doing anything with this at the moment, but
* HDMI outputs typically have this controls.
@@ -1581,6 +1649,20 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
dev->ctrl_tx_mode = v4l2_ctrl_new_std_menu(hdl_vid_out, NULL,
V4L2_CID_DV_TX_MODE, V4L2_DV_TX_MODE_HDMI,
0, V4L2_DV_TX_MODE_HDMI);
+ dev->ctrl_display_present = v4l2_ctrl_new_custom(hdl_vid_out,
+ &vivid_ctrl_display_present, NULL);
+ dev->ctrl_tx_hotplug = v4l2_ctrl_new_std(hdl_vid_out,
+ NULL, V4L2_CID_DV_TX_HOTPLUG, 0,
+ (2 << (dev->num_hdmi_outputs - 1)) - 1, 0,
+ (2 << (dev->num_hdmi_outputs - 1)) - 1);
+ dev->ctrl_tx_rxsense = v4l2_ctrl_new_std(hdl_vid_out,
+ NULL, V4L2_CID_DV_TX_RXSENSE, 0,
+ (2 << (dev->num_hdmi_outputs - 1)) - 1, 0,
+ (2 << (dev->num_hdmi_outputs - 1)) - 1);
+ dev->ctrl_tx_edid_present = v4l2_ctrl_new_std(hdl_vid_out,
+ NULL, V4L2_CID_DV_TX_EDID_PRESENT, 0,
+ (2 << (dev->num_hdmi_outputs - 1)) - 1, 0,
+ (2 << (dev->num_hdmi_outputs - 1)) - 1);
}
if ((dev->has_vid_cap && dev->has_vid_out) ||
(dev->has_vbi_cap && dev->has_vbi_out))
diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c
index f8006a30c12f..6cf495a7d5cc 100644
--- a/drivers/media/platform/vivid/vivid-kthread-cap.c
+++ b/drivers/media/platform/vivid/vivid-kthread-cap.c
@@ -43,7 +43,7 @@
static inline v4l2_std_id vivid_get_std_cap(const struct vivid_dev *dev)
{
if (vivid_is_sdtv_cap(dev))
- return dev->std_cap;
+ return dev->std_cap[dev->input];
return 0;
}
@@ -408,7 +408,7 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf)
unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_cap) ? 2 : 1;
unsigned line_height = 16 / factor;
bool is_tv = vivid_is_sdtv_cap(dev);
- bool is_60hz = is_tv && (dev->std_cap & V4L2_STD_525_60);
+ bool is_60hz = is_tv && (dev->std_cap[dev->input] & V4L2_STD_525_60);
unsigned p;
int line = 1;
u8 *basep[TPG_MAX_PLANES][2];
@@ -419,9 +419,9 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf)
if (dev->loop_video && dev->can_loop_video &&
((vivid_is_svid_cap(dev) &&
- !VIVID_INVALID_SIGNAL(dev->std_signal_mode)) ||
+ !VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) ||
(vivid_is_hdmi_cap(dev) &&
- !VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode))))
+ !VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode[dev->input]))))
is_loop = true;
buf->vb.sequence = dev->vid_cap_seq_count;
diff --git a/drivers/media/platform/vivid/vivid-osd.c b/drivers/media/platform/vivid/vivid-osd.c
index 1a89593b0c86..f2e789bdf4a6 100644
--- a/drivers/media/platform/vivid/vivid-osd.c
+++ b/drivers/media/platform/vivid/vivid-osd.c
@@ -155,7 +155,7 @@ static int _vivid_fb_check_var(struct fb_var_screeninfo *var, struct vivid_dev *
var->nonstd = 0;
var->vmode &= ~FB_VMODE_MASK;
- var->vmode = FB_VMODE_NONINTERLACED;
+ var->vmode |= FB_VMODE_NONINTERLACED;
/* Dummy values */
var->hsync_len = 24;
diff --git a/drivers/media/platform/vivid/vivid-vbi-cap.c b/drivers/media/platform/vivid/vivid-vbi-cap.c
index 40ecd7902b56..1a9348eea781 100644
--- a/drivers/media/platform/vivid/vivid-vbi-cap.c
+++ b/drivers/media/platform/vivid/vivid-vbi-cap.c
@@ -18,7 +18,7 @@
static void vivid_sliced_vbi_cap_fill(struct vivid_dev *dev, unsigned seqnr)
{
struct vivid_vbi_gen_data *vbi_gen = &dev->vbi_gen;
- bool is_60hz = dev->std_cap & V4L2_STD_525_60;
+ bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60;
vivid_vbi_gen_sliced(vbi_gen, is_60hz, seqnr);
@@ -65,7 +65,7 @@ static void vivid_sliced_vbi_cap_fill(struct vivid_dev *dev, unsigned seqnr)
static void vivid_g_fmt_vbi_cap(struct vivid_dev *dev, struct v4l2_vbi_format *vbi)
{
- bool is_60hz = dev->std_cap & V4L2_STD_525_60;
+ bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60;
vbi->sampling_rate = 27000000;
vbi->offset = 24;
@@ -93,7 +93,7 @@ void vivid_raw_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf)
memset(vbuf, 0x10, vb2_plane_size(&buf->vb.vb2_buf, 0));
- if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode))
+ if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input]))
vivid_vbi_gen_raw(&dev->vbi_gen, &vbi, vbuf);
}
@@ -111,7 +111,7 @@ void vivid_sliced_vbi_cap_process(struct vivid_dev *dev,
vivid_sliced_vbi_cap_fill(dev, buf->vb.sequence);
memset(vbuf, 0, vb2_plane_size(&buf->vb.vb2_buf, 0));
- if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode)) {
+ if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) {
unsigned i;
for (i = 0; i < 25; i++)
@@ -124,7 +124,7 @@ static int vbi_cap_queue_setup(struct vb2_queue *vq,
unsigned sizes[], struct device *alloc_devs[])
{
struct vivid_dev *dev = vb2_get_drv_priv(vq);
- bool is_60hz = dev->std_cap & V4L2_STD_525_60;
+ bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60;
unsigned size = vq->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ?
36 * sizeof(struct v4l2_sliced_vbi_data) :
1440 * 2 * (is_60hz ? 12 : 18);
@@ -144,7 +144,7 @@ static int vbi_cap_queue_setup(struct vb2_queue *vq,
static int vbi_cap_buf_prepare(struct vb2_buffer *vb)
{
struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
- bool is_60hz = dev->std_cap & V4L2_STD_525_60;
+ bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60;
unsigned size = vb->vb2_queue->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ?
36 * sizeof(struct v4l2_sliced_vbi_data) :
1440 * 2 * (is_60hz ? 12 : 18);
@@ -302,7 +302,7 @@ int vidioc_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_forma
{
struct vivid_dev *dev = video_drvdata(file);
struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced;
- bool is_60hz = dev->std_cap & V4L2_STD_525_60;
+ bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60;
u32 service_set = vbi->service_set;
if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap)
@@ -337,7 +337,7 @@ int vidioc_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_
bool is_60hz;
if (vdev->vfl_dir == VFL_DIR_RX) {
- is_60hz = dev->std_cap & V4L2_STD_525_60;
+ is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60;
if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap ||
cap->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
return -EINVAL;
diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c
index 530ac8decb25..8cbaa0c998ed 100644
--- a/drivers/media/platform/vivid/vivid-vid-cap.c
+++ b/drivers/media/platform/vivid/vivid-vid-cap.c
@@ -21,11 +21,6 @@
#include "vivid-kthread-cap.h"
#include "vivid-vid-cap.h"
-/* timeperframe: min/max and default */
-static const struct v4l2_fract
- tpf_min = {.numerator = 1, .denominator = FPS_MAX},
- tpf_max = {.numerator = FPS_MAX, .denominator = 1};
-
static const struct vivid_fmt formats_ovl[] = {
{
.fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
@@ -196,7 +191,7 @@ static void vid_cap_buf_finish(struct vb2_buffer *vb)
* test this.
*/
vbuf->flags |= V4L2_BUF_FLAG_TIMECODE;
- if (dev->std_cap & V4L2_STD_525_60)
+ if (dev->std_cap[dev->input] & V4L2_STD_525_60)
fps = 30;
tc->type = (fps == 30) ? V4L2_TC_TYPE_30FPS : V4L2_TC_TYPE_25FPS;
tc->flags = 0;
@@ -299,11 +294,13 @@ void vivid_update_quality(struct vivid_dev *dev)
tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0);
return;
}
- if (vivid_is_hdmi_cap(dev) && VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode)) {
+ if (vivid_is_hdmi_cap(dev) &&
+ VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode[dev->input])) {
tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0);
return;
}
- if (vivid_is_sdtv_cap(dev) && VIVID_INVALID_SIGNAL(dev->std_signal_mode)) {
+ if (vivid_is_sdtv_cap(dev) &&
+ VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) {
tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0);
return;
}
@@ -358,10 +355,10 @@ static enum tpg_quality vivid_get_quality(struct vivid_dev *dev, s32 *afc)
enum tpg_video_aspect vivid_get_video_aspect(const struct vivid_dev *dev)
{
if (vivid_is_sdtv_cap(dev))
- return dev->std_aspect_ratio;
+ return dev->std_aspect_ratio[dev->input];
if (vivid_is_hdmi_cap(dev))
- return dev->dv_timings_aspect_ratio;
+ return dev->dv_timings_aspect_ratio[dev->input];
return TPG_VIDEO_ASPECT_IMAGE;
}
@@ -369,7 +366,7 @@ enum tpg_video_aspect vivid_get_video_aspect(const struct vivid_dev *dev)
static enum tpg_pixel_aspect vivid_get_pixel_aspect(const struct vivid_dev *dev)
{
if (vivid_is_sdtv_cap(dev))
- return (dev->std_cap & V4L2_STD_525_60) ?
+ return (dev->std_cap[dev->input] & V4L2_STD_525_60) ?
TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL;
if (vivid_is_hdmi_cap(dev) &&
@@ -386,7 +383,7 @@ static enum tpg_pixel_aspect vivid_get_pixel_aspect(const struct vivid_dev *dev)
*/
void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls)
{
- struct v4l2_bt_timings *bt = &dev->dv_timings_cap.bt;
+ struct v4l2_bt_timings *bt = &dev->dv_timings_cap[dev->input].bt;
unsigned size;
u64 pixelclock;
@@ -403,7 +400,7 @@ void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls)
case SVID:
dev->field_cap = dev->tv_field_cap;
dev->src_rect.width = 720;
- if (dev->std_cap & V4L2_STD_525_60) {
+ if (dev->std_cap[dev->input] & V4L2_STD_525_60) {
dev->src_rect.height = 480;
dev->timeperframe_vid_cap = (struct v4l2_fract) { 1001, 30000 };
dev->service_set_cap = V4L2_SLICED_CAPTION_525;
@@ -486,8 +483,8 @@ static enum v4l2_field vivid_field_cap(struct vivid_dev *dev, enum v4l2_field fi
}
}
if (vivid_is_hdmi_cap(dev))
- return dev->dv_timings_cap.bt.interlaced ? V4L2_FIELD_ALTERNATE :
- V4L2_FIELD_NONE;
+ return dev->dv_timings_cap[dev->input].bt.interlaced ?
+ V4L2_FIELD_ALTERNATE : V4L2_FIELD_NONE;
return V4L2_FIELD_NONE;
}
@@ -586,7 +583,7 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv,
h = sz->height;
} else if (vivid_is_sdtv_cap(dev)) {
w = 720;
- h = (dev->std_cap & V4L2_STD_525_60) ? 480 : 576;
+ h = (dev->std_cap[dev->input] & V4L2_STD_525_60) ? 480 : 576;
} else {
w = dev->src_rect.width;
h = dev->src_rect.height;
@@ -1310,10 +1307,10 @@ int vidioc_enum_input(struct file *file, void *priv,
dev->input_name_counter[inp->index]);
inp->capabilities = V4L2_IN_CAP_DV_TIMINGS;
if (dev->edid_blocks == 0 ||
- dev->dv_timings_signal_mode == NO_SIGNAL)
+ dev->dv_timings_signal_mode[dev->input] == NO_SIGNAL)
inp->status |= V4L2_IN_ST_NO_SIGNAL;
- else if (dev->dv_timings_signal_mode == NO_LOCK ||
- dev->dv_timings_signal_mode == OUT_OF_RANGE)
+ else if (dev->dv_timings_signal_mode[dev->input] == NO_LOCK ||
+ dev->dv_timings_signal_mode[dev->input] == OUT_OF_RANGE)
inp->status |= V4L2_IN_ST_NO_H_LOCK;
break;
}
@@ -1322,9 +1319,9 @@ int vidioc_enum_input(struct file *file, void *priv,
if (dev->sensor_vflip)
inp->status |= V4L2_IN_ST_VFLIP;
if (dev->input == inp->index && vivid_is_sdtv_cap(dev)) {
- if (dev->std_signal_mode == NO_SIGNAL) {
+ if (dev->std_signal_mode[dev->input] == NO_SIGNAL) {
inp->status |= V4L2_IN_ST_NO_SIGNAL;
- } else if (dev->std_signal_mode == NO_LOCK) {
+ } else if (dev->std_signal_mode[dev->input] == NO_LOCK) {
inp->status |= V4L2_IN_ST_NO_H_LOCK;
} else if (vivid_is_tv_cap(dev)) {
switch (tpg_g_quality(&dev->tpg)) {
@@ -1353,7 +1350,7 @@ int vidioc_g_input(struct file *file, void *priv, unsigned *i)
int vidioc_s_input(struct file *file, void *priv, unsigned i)
{
struct vivid_dev *dev = video_drvdata(file);
- struct v4l2_bt_timings *bt = &dev->dv_timings_cap.bt;
+ struct v4l2_bt_timings *bt = &dev->dv_timings_cap[dev->input].bt;
unsigned brightness;
if (i >= dev->num_inputs)
@@ -1407,6 +1404,29 @@ int vidioc_s_input(struct file *file, void *priv, unsigned i)
v4l2_ctrl_modify_range(dev->brightness,
128 * i, 255 + 128 * i, 1, 128 + 128 * i);
v4l2_ctrl_s_ctrl(dev->brightness, brightness);
+
+ /* Restore per-input states. */
+ v4l2_ctrl_activate(dev->ctrl_dv_timings_signal_mode,
+ vivid_is_hdmi_cap(dev));
+ v4l2_ctrl_activate(dev->ctrl_dv_timings, vivid_is_hdmi_cap(dev) &&
+ dev->dv_timings_signal_mode[dev->input] ==
+ SELECTED_DV_TIMINGS);
+ v4l2_ctrl_activate(dev->ctrl_std_signal_mode, vivid_is_sdtv_cap(dev));
+ v4l2_ctrl_activate(dev->ctrl_standard, vivid_is_sdtv_cap(dev) &&
+ dev->std_signal_mode[dev->input]);
+
+ if (vivid_is_hdmi_cap(dev)) {
+ v4l2_ctrl_s_ctrl(dev->ctrl_dv_timings_signal_mode,
+ dev->dv_timings_signal_mode[dev->input]);
+ v4l2_ctrl_s_ctrl(dev->ctrl_dv_timings,
+ dev->query_dv_timings[dev->input]);
+ } else if (vivid_is_sdtv_cap(dev)) {
+ v4l2_ctrl_s_ctrl(dev->ctrl_std_signal_mode,
+ dev->std_signal_mode[dev->input]);
+ v4l2_ctrl_s_ctrl(dev->ctrl_standard,
+ dev->std_signal_mode[dev->input]);
+ }
+
return 0;
}
@@ -1499,8 +1519,9 @@ int vivid_video_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
} else if (qual == TPG_QUAL_GRAY) {
vt->rxsubchans = V4L2_TUNER_SUB_MONO;
} else {
- unsigned channel_nr = dev->tv_freq / (6 * 16);
- unsigned options = (dev->std_cap & V4L2_STD_NTSC_M) ? 4 : 3;
+ unsigned int channel_nr = dev->tv_freq / (6 * 16);
+ unsigned int options =
+ (dev->std_cap[dev->input] & V4L2_STD_NTSC_M) ? 4 : 3;
switch (channel_nr % options) {
case 0:
@@ -1510,7 +1531,7 @@ int vivid_video_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
break;
case 2:
- if (dev->std_cap & V4L2_STD_NTSC_M)
+ if (dev->std_cap[dev->input] & V4L2_STD_NTSC_M)
vt->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_SAP;
else
vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
@@ -1567,23 +1588,25 @@ const char * const vivid_ctrl_standard_strings[] = {
int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *id)
{
struct vivid_dev *dev = video_drvdata(file);
+ unsigned int last = dev->query_std_last[dev->input];
if (!vivid_is_sdtv_cap(dev))
return -ENODATA;
- if (dev->std_signal_mode == NO_SIGNAL ||
- dev->std_signal_mode == NO_LOCK) {
+ if (dev->std_signal_mode[dev->input] == NO_SIGNAL ||
+ dev->std_signal_mode[dev->input] == NO_LOCK) {
*id = V4L2_STD_UNKNOWN;
return 0;
}
if (vivid_is_tv_cap(dev) && tpg_g_quality(&dev->tpg) == TPG_QUAL_NOISE) {
*id = V4L2_STD_UNKNOWN;
- } else if (dev->std_signal_mode == CURRENT_STD) {
- *id = dev->std_cap;
- } else if (dev->std_signal_mode == SELECTED_STD) {
- *id = dev->query_std;
+ } else if (dev->std_signal_mode[dev->input] == CURRENT_STD) {
+ *id = dev->std_cap[dev->input];
+ } else if (dev->std_signal_mode[dev->input] == SELECTED_STD) {
+ *id = dev->query_std[dev->input];
} else {
- *id = vivid_standard[dev->query_std_last];
- dev->query_std_last = (dev->query_std_last + 1) % ARRAY_SIZE(vivid_standard);
+ *id = vivid_standard[last];
+ dev->query_std_last[dev->input] =
+ (last + 1) % ARRAY_SIZE(vivid_standard);
}
return 0;
@@ -1595,11 +1618,11 @@ int vivid_vid_cap_s_std(struct file *file, void *priv, v4l2_std_id id)
if (!vivid_is_sdtv_cap(dev))
return -ENODATA;
- if (dev->std_cap == id)
+ if (dev->std_cap[dev->input] == id)
return 0;
if (vb2_is_busy(&dev->vb_vid_cap_q) || vb2_is_busy(&dev->vb_vbi_cap_q))
return -EBUSY;
- dev->std_cap = id;
+ dev->std_cap[dev->input] = id;
vivid_update_format_cap(dev, false);
return 0;
}
@@ -1676,12 +1699,13 @@ int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh,
!valid_cvt_gtf_timings(timings))
return -EINVAL;
- if (v4l2_match_dv_timings(timings, &dev->dv_timings_cap, 0, false))
+ if (v4l2_match_dv_timings(timings, &dev->dv_timings_cap[dev->input],
+ 0, false))
return 0;
if (vb2_is_busy(&dev->vb_vid_cap_q))
return -EBUSY;
- dev->dv_timings_cap = *timings;
+ dev->dv_timings_cap[dev->input] = *timings;
vivid_update_format_cap(dev, false);
return 0;
}
@@ -1690,26 +1714,31 @@ int vidioc_query_dv_timings(struct file *file, void *_fh,
struct v4l2_dv_timings *timings)
{
struct vivid_dev *dev = video_drvdata(file);
+ unsigned int input = dev->input;
+ unsigned int last = dev->query_dv_timings_last[input];
if (!vivid_is_hdmi_cap(dev))
return -ENODATA;
- if (dev->dv_timings_signal_mode == NO_SIGNAL ||
+ if (dev->dv_timings_signal_mode[input] == NO_SIGNAL ||
dev->edid_blocks == 0)
return -ENOLINK;
- if (dev->dv_timings_signal_mode == NO_LOCK)
+ if (dev->dv_timings_signal_mode[input] == NO_LOCK)
return -ENOLCK;
- if (dev->dv_timings_signal_mode == OUT_OF_RANGE) {
+ if (dev->dv_timings_signal_mode[input] == OUT_OF_RANGE) {
timings->bt.pixelclock = vivid_dv_timings_cap.bt.max_pixelclock * 2;
return -ERANGE;
}
- if (dev->dv_timings_signal_mode == CURRENT_DV_TIMINGS) {
- *timings = dev->dv_timings_cap;
- } else if (dev->dv_timings_signal_mode == SELECTED_DV_TIMINGS) {
- *timings = v4l2_dv_timings_presets[dev->query_dv_timings];
+ if (dev->dv_timings_signal_mode[input] == CURRENT_DV_TIMINGS) {
+ *timings = dev->dv_timings_cap[input];
+ } else if (dev->dv_timings_signal_mode[input] ==
+ SELECTED_DV_TIMINGS) {
+ *timings =
+ v4l2_dv_timings_presets[dev->query_dv_timings[input]];
} else {
- *timings = v4l2_dv_timings_presets[dev->query_dv_timings_last];
- dev->query_dv_timings_last = (dev->query_dv_timings_last + 1) %
- dev->query_dv_timings_size;
+ *timings =
+ v4l2_dv_timings_presets[last];
+ dev->query_dv_timings_last[input] =
+ (last + 1) % dev->query_dv_timings_size;
}
return 0;
}
@@ -1719,7 +1748,8 @@ int vidioc_s_edid(struct file *file, void *_fh,
{
struct vivid_dev *dev = video_drvdata(file);
u16 phys_addr;
- unsigned int i;
+ u32 display_present = 0;
+ unsigned int i, j;
int ret;
memset(edid->reserved, 0, sizeof(edid->reserved));
@@ -1729,6 +1759,8 @@ int vidioc_s_edid(struct file *file, void *_fh,
return -EINVAL;
if (edid->blocks == 0) {
dev->edid_blocks = 0;
+ v4l2_ctrl_s_ctrl(dev->ctrl_tx_edid_present, 0);
+ v4l2_ctrl_s_ctrl(dev->ctrl_tx_hotplug, 0);
phys_addr = CEC_PHYS_ADDR_INVALID;
goto set_phys_addr;
}
@@ -1747,13 +1779,23 @@ int vidioc_s_edid(struct file *file, void *_fh,
dev->edid_blocks = edid->blocks;
memcpy(dev->edid, edid->edid, edid->blocks * 128);
+ for (i = 0, j = 0; i < dev->num_outputs; i++)
+ if (dev->output_type[i] == HDMI)
+ display_present |=
+ dev->display_present[i] << j++;
+
+ v4l2_ctrl_s_ctrl(dev->ctrl_tx_edid_present, display_present);
+ v4l2_ctrl_s_ctrl(dev->ctrl_tx_hotplug, display_present);
+
set_phys_addr:
/* TODO: a proper hotplug detect cycle should be emulated here */
cec_s_phys_addr(dev->cec_rx_adap, phys_addr, false);
for (i = 0; i < MAX_OUTPUTS && dev->cec_tx_adap[i]; i++)
cec_s_phys_addr(dev->cec_tx_adap[i],
- v4l2_phys_addr_for_input(phys_addr, i + 1),
+ dev->display_present[i] ?
+ v4l2_phys_addr_for_input(phys_addr, i + 1) :
+ CEC_PHYS_ADDR_INVALID,
false);
return 0;
}
@@ -1865,8 +1907,6 @@ int vivid_vid_cap_s_parm(struct file *file, void *priv,
i = ival_sz - 1;
dev->webcam_ival_idx = i;
tpf = webcam_intervals[dev->webcam_ival_idx];
- tpf = V4L2_FRACT_COMPARE(tpf, <, tpf_min) ? tpf_min : tpf;
- tpf = V4L2_FRACT_COMPARE(tpf, >, tpf_max) ? tpf_max : tpf;
/* resync the thread's timings */
dev->cap_seq_resync = true;
diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c
index 74b83bcc6119..1f33eb1a76b6 100644
--- a/drivers/media/platform/vivid/vivid-vid-common.c
+++ b/drivers/media/platform/vivid/vivid-vid-common.c
@@ -645,7 +645,7 @@ bool vivid_vid_can_loop(struct vivid_dev *dev)
dev->field_cap == V4L2_FIELD_SEQ_BT)
return false;
if (vivid_is_svid_cap(dev) && vivid_is_svid_out(dev)) {
- if (!(dev->std_cap & V4L2_STD_525_60) !=
+ if (!(dev->std_cap[dev->input] & V4L2_STD_525_60) !=
!(dev->std_out & V4L2_STD_525_60))
return false;
return true;
@@ -797,26 +797,6 @@ int vivid_enum_fmt_vid(struct file *file, void *priv,
return 0;
}
-int vidioc_enum_fmt_vid_mplane(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
-{
- struct vivid_dev *dev = video_drvdata(file);
-
- if (!dev->multiplanar)
- return -ENOTTY;
- return vivid_enum_fmt_vid(file, priv, f);
-}
-
-int vidioc_enum_fmt_vid(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
-{
- struct vivid_dev *dev = video_drvdata(file);
-
- if (dev->multiplanar)
- return -ENOTTY;
- return vivid_enum_fmt_vid(file, priv, f);
-}
-
int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
{
struct vivid_dev *dev = video_drvdata(file);
@@ -825,7 +805,7 @@ int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
if (vdev->vfl_dir == VFL_DIR_RX) {
if (!vivid_is_sdtv_cap(dev))
return -ENODATA;
- *id = dev->std_cap;
+ *id = dev->std_cap[dev->input];
} else {
if (!vivid_is_svid_out(dev))
return -ENODATA;
@@ -843,7 +823,7 @@ int vidioc_g_dv_timings(struct file *file, void *_fh,
if (vdev->vfl_dir == VFL_DIR_RX) {
if (!vivid_is_hdmi_cap(dev))
return -ENODATA;
- *timings = dev->dv_timings_cap;
+ *timings = dev->dv_timings_cap[dev->input];
} else {
if (!vivid_is_hdmi_out(dev))
return -ENODATA;
@@ -907,6 +887,8 @@ int vidioc_g_edid(struct file *file, void *_fh,
return -EINVAL;
if (dev->output_type[edid->pad] != HDMI)
return -EINVAL;
+ if (!dev->display_present[edid->pad])
+ return -ENODATA;
bus_idx = dev->cec_output2bus_map[edid->pad];
adap = dev->cec_tx_adap[bus_idx];
}
diff --git a/drivers/media/platform/vivid/vivid-vid-common.h b/drivers/media/platform/vivid/vivid-vid-common.h
index 29b6c0b40a1b..d908d9725283 100644
--- a/drivers/media/platform/vivid/vivid-vid-common.h
+++ b/drivers/media/platform/vivid/vivid-vid-common.h
@@ -28,8 +28,6 @@ void vivid_send_source_change(struct vivid_dev *dev, unsigned type);
int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r);
int vivid_enum_fmt_vid(struct file *file, void *priv, struct v4l2_fmtdesc *f);
-int vidioc_enum_fmt_vid_mplane(struct file *file, void *priv, struct v4l2_fmtdesc *f);
-int vidioc_enum_fmt_vid(struct file *file, void *priv, struct v4l2_fmtdesc *f);
int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id);
int vidioc_g_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings);
int vidioc_enum_dv_timings(struct file *file, void *_fh, struct v4l2_enum_dv_timings *timings);
diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c
index 9350ca65dd91..148b663a6075 100644
--- a/drivers/media/platform/vivid/vivid-vid-out.c
+++ b/drivers/media/platform/vivid/vivid-vid-out.c
@@ -1094,6 +1094,12 @@ int vidioc_s_output(struct file *file, void *priv, unsigned o)
dev->vbi_out_dev.tvnorms = dev->vid_out_dev.tvnorms;
vivid_update_format_out(dev);
+
+ v4l2_ctrl_activate(dev->ctrl_display_present, vivid_is_hdmi_out(dev));
+ if (vivid_is_hdmi_out(dev))
+ v4l2_ctrl_s_ctrl(dev->ctrl_display_present,
+ dev->display_present[dev->output]);
+
return 0;
}
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index 4b41687b2bde..eb79d99787bd 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -233,7 +233,6 @@ source "drivers/media/radio/wl128x/Kconfig"
menuconfig V4L_RADIO_ISA_DRIVERS
bool "ISA radio devices"
depends on ISA || COMPILE_TEST
- default n
help
Say Y here to enable support for these ISA drivers.
diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c
index 9f7e68498321..9a45cda05779 100644
--- a/drivers/media/radio/dsbr100.c
+++ b/drivers/media/radio/dsbr100.c
@@ -168,8 +168,6 @@ static int vidioc_querycap(struct file *file, void *priv,
strscpy(v->driver, "dsbr100", sizeof(v->driver));
strscpy(v->card, "D-Link R-100 USB FM Radio", sizeof(v->card));
usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
- v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
- v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -378,6 +376,7 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
radio->videodev.release = video_device_release_empty;
radio->videodev.lock = &radio->v4l2_lock;
radio->videodev.ctrl_handler = &radio->hdl;
+ radio->videodev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
radio->usbdev = interface_to_usbdev(intf);
radio->curfreq = FREQ_MIN * FREQ_MUL;
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index 12160894839c..a5db9b4dc3de 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -357,9 +357,6 @@ static int vidioc_querycap(struct file *file, void *priv,
strscpy(v->driver, "ADS Cadet", sizeof(v->driver));
strscpy(v->card, "ADS Cadet", sizeof(v->card));
strscpy(v->bus_info, "ISA:radio-cadet", sizeof(v->bus_info));
- v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO |
- V4L2_CAP_READWRITE | V4L2_CAP_RDS_CAPTURE;
- v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -646,6 +643,8 @@ static int __init cadet_init(void)
dev->vdev.ioctl_ops = &cadet_ioctl_ops;
dev->vdev.release = video_device_release_empty;
dev->vdev.lock = &dev->lock;
+ dev->vdev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO |
+ V4L2_CAP_READWRITE | V4L2_CAP_RDS_CAPTURE;
video_set_drvdata(&dev->vdev, dev);
res = video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr);
diff --git a/drivers/media/radio/radio-isa.c b/drivers/media/radio/radio-isa.c
index 9f9c08393756..ad2ac16ff12d 100644
--- a/drivers/media/radio/radio-isa.c
+++ b/drivers/media/radio/radio-isa.c
@@ -37,9 +37,6 @@ static int radio_isa_querycap(struct file *file, void *priv,
strscpy(v->driver, isa->drv->driver.driver.name, sizeof(v->driver));
strscpy(v->card, isa->drv->card, sizeof(v->card));
snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", isa->v4l2_dev.name);
-
- v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
- v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -240,6 +237,7 @@ static int radio_isa_common_probe(struct radio_isa_card *isa,
isa->vdev.fops = &radio_isa_fops;
isa->vdev.ioctl_ops = &radio_isa_ioctl_ops;
isa->vdev.release = video_device_release_empty;
+ isa->vdev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
video_set_drvdata(&isa->vdev, isa);
isa->freq = FREQ_LOW;
isa->stereo = drv->has_stereo;
diff --git a/drivers/media/radio/radio-keene.c b/drivers/media/radio/radio-keene.c
index 4d41857946de..a35648316aa8 100644
--- a/drivers/media/radio/radio-keene.c
+++ b/drivers/media/radio/radio-keene.c
@@ -168,8 +168,6 @@ static int vidioc_querycap(struct file *file, void *priv,
strscpy(v->driver, "radio-keene", sizeof(v->driver));
strscpy(v->card, "Keene FM Transmitter", sizeof(v->card));
usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
- v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_MODULATOR;
- v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -361,6 +359,7 @@ static int usb_keene_probe(struct usb_interface *intf,
radio->vdev.lock = &radio->lock;
radio->vdev.release = video_device_release_empty;
radio->vdev.vfl_dir = VFL_DIR_TX;
+ radio->vdev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_MODULATOR;
radio->usbdev = interface_to_usbdev(intf);
radio->intf = intf;
diff --git a/drivers/media/radio/radio-ma901.c b/drivers/media/radio/radio-ma901.c
index cbcf0ed69223..657c3dda6648 100644
--- a/drivers/media/radio/radio-ma901.c
+++ b/drivers/media/radio/radio-ma901.c
@@ -191,8 +191,6 @@ static int vidioc_querycap(struct file *file, void *priv,
strscpy(v->driver, "radio-ma901", sizeof(v->driver));
strscpy(v->card, "Masterkit MA901 USB FM Radio", sizeof(v->card));
usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
- v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
- v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -398,6 +396,7 @@ static int usb_ma901radio_probe(struct usb_interface *intf,
radio->vdev.ioctl_ops = &usb_ma901radio_ioctl_ops;
radio->vdev.release = video_device_release_empty;
radio->vdev.lock = &radio->lock;
+ radio->vdev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
radio->usbdev = interface_to_usbdev(intf);
radio->intf = intf;
diff --git a/drivers/media/radio/radio-miropcm20.c b/drivers/media/radio/radio-miropcm20.c
index 95d12cbff5c9..99788834c646 100644
--- a/drivers/media/radio/radio-miropcm20.c
+++ b/drivers/media/radio/radio-miropcm20.c
@@ -204,8 +204,6 @@ static int vidioc_querycap(struct file *file, void *priv,
strscpy(v->driver, "Miro PCM20", sizeof(v->driver));
strscpy(v->card, "Miro PCM20", sizeof(v->card));
snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", dev->v4l2_dev.name);
- v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE;
- v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -481,6 +479,8 @@ static int __init pcm20_init(void)
dev->vdev.ioctl_ops = &pcm20_ioctl_ops;
dev->vdev.release = video_device_release_empty;
dev->vdev.lock = &dev->lock;
+ dev->vdev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO |
+ V4L2_CAP_RDS_CAPTURE;
video_set_drvdata(&dev->vdev, dev);
snd_aci_cmd(dev->aci, ACI_SET_TUNERMONO,
dev->audmode == V4L2_TUNER_MODE_MONO, -1);
diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c
index f53f9064e1e9..cb0437b4c331 100644
--- a/drivers/media/radio/radio-mr800.c
+++ b/drivers/media/radio/radio-mr800.c
@@ -260,9 +260,6 @@ static int vidioc_querycap(struct file *file, void *priv,
strscpy(v->driver, "radio-mr800", sizeof(v->driver));
strscpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card));
usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
- v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER |
- V4L2_CAP_HW_FREQ_SEEK;
- v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -545,6 +542,8 @@ static int usb_amradio_probe(struct usb_interface *intf,
radio->vdev.ioctl_ops = &usb_amradio_ioctl_ops;
radio->vdev.release = video_device_release_empty;
radio->vdev.lock = &radio->lock;
+ radio->vdev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER |
+ V4L2_CAP_HW_FREQ_SEEK;
radio->usbdev = interface_to_usbdev(intf);
radio->intf = intf;
diff --git a/drivers/media/radio/radio-raremono.c b/drivers/media/radio/radio-raremono.c
index 5e782b3c2fa9..c3180d53c282 100644
--- a/drivers/media/radio/radio-raremono.c
+++ b/drivers/media/radio/radio-raremono.c
@@ -184,8 +184,6 @@ static int vidioc_querycap(struct file *file, void *priv,
strscpy(v->driver, "radio-raremono", sizeof(v->driver));
strscpy(v->card, "Thanko's Raremono", sizeof(v->card));
usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
- v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
- v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -271,6 +269,14 @@ static int vidioc_g_frequency(struct file *file, void *priv,
return 0;
}
+static void raremono_device_release(struct v4l2_device *v4l2_dev)
+{
+ struct raremono_device *radio = to_raremono_dev(v4l2_dev);
+
+ kfree(radio->buffer);
+ kfree(radio);
+}
+
/* File system interface */
static const struct v4l2_file_operations usb_raremono_fops = {
.owner = THIS_MODULE,
@@ -295,12 +301,14 @@ static int usb_raremono_probe(struct usb_interface *intf,
struct raremono_device *radio;
int retval = 0;
- radio = devm_kzalloc(&intf->dev, sizeof(struct raremono_device), GFP_KERNEL);
- if (radio)
- radio->buffer = devm_kmalloc(&intf->dev, BUFFER_LENGTH, GFP_KERNEL);
-
- if (!radio || !radio->buffer)
+ radio = kzalloc(sizeof(*radio), GFP_KERNEL);
+ if (!radio)
+ return -ENOMEM;
+ radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
+ if (!radio->buffer) {
+ kfree(radio);
return -ENOMEM;
+ }
radio->usbdev = interface_to_usbdev(intf);
radio->intf = intf;
@@ -324,7 +332,8 @@ static int usb_raremono_probe(struct usb_interface *intf,
if (retval != 3 ||
(get_unaligned_be16(&radio->buffer[1]) & 0xfff) == 0x0242) {
dev_info(&intf->dev, "this is not Thanko's Raremono.\n");
- return -ENODEV;
+ retval = -ENODEV;
+ goto free_mem;
}
dev_info(&intf->dev, "Thanko's Raremono connected: (%04X:%04X)\n",
@@ -333,7 +342,7 @@ static int usb_raremono_probe(struct usb_interface *intf,
retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev);
if (retval < 0) {
dev_err(&intf->dev, "couldn't register v4l2_device\n");
- return retval;
+ goto free_mem;
}
mutex_init(&radio->lock);
@@ -345,6 +354,8 @@ static int usb_raremono_probe(struct usb_interface *intf,
radio->vdev.ioctl_ops = &usb_raremono_ioctl_ops;
radio->vdev.lock = &radio->lock;
radio->vdev.release = video_device_release_empty;
+ radio->vdev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ radio->v4l2_dev.release = raremono_device_release;
usb_set_intfdata(intf, &radio->v4l2_dev);
@@ -360,6 +371,10 @@ static int usb_raremono_probe(struct usb_interface *intf,
}
dev_err(&intf->dev, "could not register video device\n");
v4l2_device_unregister(&radio->v4l2_dev);
+
+free_mem:
+ kfree(radio->buffer);
+ kfree(radio);
return retval;
}
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index 434c03338d7f..54a40d60e4fd 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -133,8 +133,6 @@ static int vidioc_querycap(struct file *file, void *priv,
strscpy(v->driver, "radio-sf16fmi", sizeof(v->driver));
strscpy(v->card, "SF16-FMI/FMP/FMD radio", sizeof(v->card));
strscpy(v->bus_info, "ISA:radio-sf16fmi", sizeof(v->bus_info));
- v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
- v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -345,6 +343,7 @@ static int __init fmi_init(void)
fmi->vdev.fops = &fmi_fops;
fmi->vdev.ioctl_ops = &fmi_ioctl_ops;
fmi->vdev.release = video_device_release_empty;
+ fmi->vdev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
video_set_drvdata(&fmi->vdev, fmi);
mutex_init(&fmi->lock);
diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c
index 645242314a09..b203296de977 100644
--- a/drivers/media/radio/radio-si476x.c
+++ b/drivers/media/radio/radio-si476x.c
@@ -336,19 +336,6 @@ static int si476x_radio_querycap(struct file *file, void *priv,
strscpy(capability->card, DRIVER_CARD, sizeof(capability->card));
snprintf(capability->bus_info, sizeof(capability->bus_info),
"platform:%s", radio->v4l2dev.name);
-
- capability->device_caps = V4L2_CAP_TUNER
- | V4L2_CAP_RADIO
- | V4L2_CAP_HW_FREQ_SEEK;
-
- si476x_core_lock(radio->core);
- if (!si476x_core_is_a_secondary_tuner(radio->core))
- capability->device_caps |= V4L2_CAP_RDS_CAPTURE
- | V4L2_CAP_READWRITE;
- si476x_core_unlock(radio->core);
-
- capability->capabilities = capability->device_caps
- | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -1459,6 +1446,14 @@ static int si476x_radio_probe(struct platform_device *pdev)
radio->videodev.v4l2_dev = &radio->v4l2dev;
radio->videodev.ioctl_ops = &si4761_ioctl_ops;
+ radio->videodev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO |
+ V4L2_CAP_HW_FREQ_SEEK;
+
+ si476x_core_lock(radio->core);
+ if (!si476x_core_is_a_secondary_tuner(radio->core))
+ radio->videodev.device_caps |= V4L2_CAP_RDS_CAPTURE |
+ V4L2_CAP_READWRITE;
+ si476x_core_unlock(radio->core);
video_set_drvdata(&radio->videodev, radio);
platform_set_drvdata(pdev, radio);
diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c
index b740646adc53..877a24e5c577 100644
--- a/drivers/media/radio/radio-tea5764.c
+++ b/drivers/media/radio/radio-tea5764.c
@@ -282,8 +282,6 @@ static int vidioc_querycap(struct file *file, void *priv,
strscpy(v->card, dev->name, sizeof(v->card));
snprintf(v->bus_info, sizeof(v->bus_info),
"I2C:%s", dev_name(&dev->dev));
- v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
- v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -465,6 +463,7 @@ static int tea5764_i2c_probe(struct i2c_client *client,
video_set_drvdata(&radio->vdev, radio);
radio->vdev.lock = &radio->mutex;
radio->vdev.v4l2_dev = v4l2_dev;
+ radio->vdev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
/* initialize and power off the chip */
tea5764_i2c_read(radio);
diff --git a/drivers/media/radio/radio-tea5777.c b/drivers/media/radio/radio-tea5777.c
index 49d4beba341e..fb9de7bbcd19 100644
--- a/drivers/media/radio/radio-tea5777.c
+++ b/drivers/media/radio/radio-tea5777.c
@@ -260,9 +260,6 @@ static int vidioc_querycap(struct file *file, void *priv,
strscpy(v->card, tea->card, sizeof(v->card));
strlcat(v->card, " TEA5777", sizeof(v->card));
strscpy(v->bus_info, tea->bus_info, sizeof(v->bus_info));
- v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
- v->device_caps |= V4L2_CAP_HW_FREQ_SEEK;
- v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -553,6 +550,8 @@ int radio_tea5777_init(struct radio_tea5777 *tea, struct module *owner)
strscpy(tea->vd.name, tea->v4l2_dev->name, sizeof(tea->vd.name));
tea->vd.lock = &tea->mutex;
tea->vd.v4l2_dev = tea->v4l2_dev;
+ tea->vd.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO |
+ V4L2_CAP_HW_FREQ_SEEK;
tea->fops = tea575x_fops;
tea->fops.owner = owner;
tea->vd.fops = &tea->fops;
diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c
index 7d196f8ad3b5..948ee3eec914 100644
--- a/drivers/media/radio/radio-timb.c
+++ b/drivers/media/radio/radio-timb.c
@@ -34,8 +34,6 @@ static int timbradio_vidioc_querycap(struct file *file, void *priv,
strscpy(v->driver, DRIVER_NAME, sizeof(v->driver));
strscpy(v->card, "Timberdale Radio", sizeof(v->card));
snprintf(v->bus_info, sizeof(v->bus_info), "platform:"DRIVER_NAME);
- v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
- v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -114,6 +112,7 @@ static int timbradio_probe(struct platform_device *pdev)
tr->video_dev.release = video_device_release_empty;
tr->video_dev.minor = -1;
tr->video_dev.lock = &tr->lock;
+ tr->video_dev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
strscpy(tr->v4l2_dev.name, DRIVER_NAME, sizeof(tr->v4l2_dev.name));
err = v4l2_device_register(NULL, &tr->v4l2_dev);
diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c
index 330de50f8920..104ac41c6f96 100644
--- a/drivers/media/radio/radio-wl1273.c
+++ b/drivers/media/radio/radio-wl1273.c
@@ -1284,14 +1284,6 @@ static int wl1273_fm_vidioc_querycap(struct file *file, void *priv,
sizeof(capability->card));
strscpy(capability->bus_info, radio->bus_type,
sizeof(capability->bus_info));
-
- capability->device_caps = V4L2_CAP_HW_FREQ_SEEK |
- V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_AUDIO |
- V4L2_CAP_RDS_CAPTURE | V4L2_CAP_MODULATOR |
- V4L2_CAP_RDS_OUTPUT;
- capability->capabilities = capability->device_caps |
- V4L2_CAP_DEVICE_CAPS;
-
return 0;
}
@@ -1980,6 +1972,10 @@ static const struct video_device wl1273_viddev_template = {
.name = WL1273_FM_DRIVER_NAME,
.release = wl1273_vdev_release,
.vfl_dir = VFL_DIR_TX,
+ .device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER |
+ V4L2_CAP_RADIO | V4L2_CAP_AUDIO |
+ V4L2_CAP_RDS_CAPTURE | V4L2_CAP_MODULATOR |
+ V4L2_CAP_RDS_OUTPUT,
};
static int wl1273_fm_radio_remove(struct platform_device *pdev)
diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c
index a3152d646c3a..7d53422b3b56 100644
--- a/drivers/media/radio/si470x/radio-si470x-i2c.c
+++ b/drivers/media/radio/si470x/radio-si470x-i2c.c
@@ -223,10 +223,6 @@ static int si470x_vidioc_querycap(struct file *file, void *priv,
{
strscpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
strscpy(capability->card, DRIVER_CARD, sizeof(capability->card));
- capability->device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_READWRITE |
- V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE;
- capability->capabilities = capability->device_caps | V4L2_CAP_DEVICE_CAPS;
-
return 0;
}
@@ -382,6 +378,9 @@ static int si470x_i2c_probe(struct i2c_client *client,
radio->videodev.lock = &radio->lock;
radio->videodev.v4l2_dev = &radio->v4l2_dev;
radio->videodev.release = video_device_release_empty;
+ radio->videodev.device_caps =
+ V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_READWRITE | V4L2_CAP_TUNER |
+ V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE;
video_set_drvdata(&radio->videodev, radio);
radio->gpio_reset = devm_gpiod_get_optional(&client->dev, "reset",
diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c
index 58e622d57373..49073747b1e7 100644
--- a/drivers/media/radio/si470x/radio-si470x-usb.c
+++ b/drivers/media/radio/si470x/radio-si470x-usb.c
@@ -514,9 +514,6 @@ static int si470x_vidioc_querycap(struct file *file, void *priv,
strscpy(capability->card, DRIVER_CARD, sizeof(capability->card));
usb_make_path(radio->usbdev, capability->bus_info,
sizeof(capability->bus_info));
- capability->device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_READWRITE |
- V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE;
- capability->capabilities = capability->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -670,6 +667,9 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
radio->videodev.lock = &radio->lock;
radio->videodev.v4l2_dev = &radio->v4l2_dev;
radio->videodev.release = video_device_release_empty;
+ radio->videodev.device_caps =
+ V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_READWRITE | V4L2_CAP_TUNER |
+ V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE;
video_set_drvdata(&radio->videodev, radio);
/* get device and chip versions */
diff --git a/drivers/media/radio/si4713/radio-platform-si4713.c b/drivers/media/radio/si4713/radio-platform-si4713.c
index 70d51d3607ff..a7dfe5f55c18 100644
--- a/drivers/media/radio/si4713/radio-platform-si4713.c
+++ b/drivers/media/radio/si4713/radio-platform-si4713.c
@@ -63,9 +63,6 @@ static int radio_si4713_querycap(struct file *file, void *priv,
sizeof(capability->card));
strscpy(capability->bus_info, "platform:radio-si4713",
sizeof(capability->bus_info));
- capability->device_caps = V4L2_CAP_MODULATOR | V4L2_CAP_RDS_OUTPUT;
- capability->capabilities = capability->device_caps | V4L2_CAP_DEVICE_CAPS;
-
return 0;
}
@@ -175,6 +172,7 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev)
rsdev->radio_dev.ctrl_handler = sd->ctrl_handler;
/* Serialize all access to the si4713 */
rsdev->radio_dev.lock = &rsdev->lock;
+ rsdev->radio_dev.device_caps = V4L2_CAP_MODULATOR | V4L2_CAP_RDS_OUTPUT;
video_set_drvdata(&rsdev->radio_dev, rsdev);
if (video_register_device(&rsdev->radio_dev, VFL_TYPE_RADIO, radio_nr)) {
dev_err(&pdev->dev, "Could not register video device.\n");
diff --git a/drivers/media/radio/si4713/radio-usb-si4713.c b/drivers/media/radio/si4713/radio-usb-si4713.c
index 23065ecce979..33274189c83c 100644
--- a/drivers/media/radio/si4713/radio-usb-si4713.c
+++ b/drivers/media/radio/si4713/radio-usb-si4713.c
@@ -70,9 +70,6 @@ static int vidioc_querycap(struct file *file, void *priv,
strscpy(v->driver, "radio-usb-si4713", sizeof(v->driver));
strscpy(v->card, "Si4713 FM Transmitter", sizeof(v->card));
usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
- v->device_caps = V4L2_CAP_MODULATOR | V4L2_CAP_RDS_OUTPUT;
- v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
-
return 0;
}
@@ -475,6 +472,7 @@ static int usb_si4713_probe(struct usb_interface *intf,
radio->vdev.lock = &radio->lock;
radio->vdev.release = video_device_release_empty;
radio->vdev.vfl_dir = VFL_DIR_TX;
+ radio->vdev.device_caps = V4L2_CAP_MODULATOR | V4L2_CAP_RDS_OUTPUT;
video_set_drvdata(&radio->vdev, radio);
diff --git a/drivers/media/radio/tea575x.c b/drivers/media/radio/tea575x.c
index 64613dd145a1..b0303cf00387 100644
--- a/drivers/media/radio/tea575x.c
+++ b/drivers/media/radio/tea575x.c
@@ -226,10 +226,6 @@ static int vidioc_querycap(struct file *file, void *priv,
strscpy(v->card, tea->card, sizeof(v->card));
strlcat(v->card, tea->tea5759 ? " TEA5759" : " TEA5757", sizeof(v->card));
strscpy(v->bus_info, tea->bus_info, sizeof(v->bus_info));
- v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
- if (!tea->cannot_read_data)
- v->device_caps |= V4L2_CAP_HW_FREQ_SEEK;
- v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -529,6 +525,9 @@ int snd_tea575x_init(struct snd_tea575x *tea, struct module *owner)
strscpy(tea->vd.name, tea->v4l2_dev->name, sizeof(tea->vd.name));
tea->vd.lock = &tea->mutex;
tea->vd.v4l2_dev = tea->v4l2_dev;
+ tea->vd.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ if (!tea->cannot_read_data)
+ tea->vd.device_caps |= V4L2_CAP_HW_FREQ_SEEK;
tea->fops = tea575x_fops;
tea->fops.owner = owner;
tea->vd.fops = &tea->fops;
diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c
index c80a6df47f5e..1c146d14dbbd 100644
--- a/drivers/media/radio/wl128x/fmdrv_v4l2.c
+++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c
@@ -185,13 +185,6 @@ static int fm_v4l2_vidioc_querycap(struct file *file, void *priv,
strscpy(capability->card, FM_DRV_CARD_SHORT_NAME,
sizeof(capability->card));
sprintf(capability->bus_info, "UART");
- capability->device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER |
- V4L2_CAP_RADIO | V4L2_CAP_MODULATOR |
- V4L2_CAP_AUDIO | V4L2_CAP_READWRITE |
- V4L2_CAP_RDS_CAPTURE;
- capability->capabilities = capability->device_caps |
- V4L2_CAP_DEVICE_CAPS;
-
return 0;
}
@@ -515,6 +508,9 @@ static const struct video_device fm_viddev_template = {
* but that would affect applications using this driver.
*/
.vfl_dir = VFL_DIR_M2M,
+ .device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER | V4L2_CAP_RADIO |
+ V4L2_CAP_MODULATOR | V4L2_CAP_AUDIO |
+ V4L2_CAP_READWRITE | V4L2_CAP_RDS_CAPTURE,
};
int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr)
@@ -541,6 +537,7 @@ int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr)
/* Register with V4L2 subsystem as RADIO device */
if (video_register_device(&gradio_dev, VFL_TYPE_RADIO, radio_nr)) {
+ v4l2_device_unregister(&fmdev->v4l2_dev);
fmerr("Could not register video device\n");
return -ENOMEM;
}
@@ -554,6 +551,8 @@ int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr)
if (ret < 0) {
fmerr("(fmdev): Can't init ctrl handler\n");
v4l2_ctrl_handler_free(&fmdev->ctrl_handler);
+ video_unregister_device(fmdev->radio_dev);
+ v4l2_device_unregister(&fmdev->v4l2_dev);
return -EBUSY;
}
diff --git a/drivers/media/rc/bpf-lirc.c b/drivers/media/rc/bpf-lirc.c
index ee657003c1a1..0a0ce620e4a2 100644
--- a/drivers/media/rc/bpf-lirc.c
+++ b/drivers/media/rc/bpf-lirc.c
@@ -8,6 +8,9 @@
#include <linux/bpf_lirc.h>
#include "rc-core-priv.h"
+#define lirc_rcu_dereference(p) \
+ rcu_dereference_protected(p, lockdep_is_held(&ir_raw_handler_lock))
+
/*
* BPF interface for raw IR
*/
@@ -136,7 +139,7 @@ const struct bpf_verifier_ops lirc_mode2_verifier_ops = {
static int lirc_bpf_attach(struct rc_dev *rcdev, struct bpf_prog *prog)
{
- struct bpf_prog_array __rcu *old_array;
+ struct bpf_prog_array *old_array;
struct bpf_prog_array *new_array;
struct ir_raw_event_ctrl *raw;
int ret;
@@ -154,12 +157,12 @@ static int lirc_bpf_attach(struct rc_dev *rcdev, struct bpf_prog *prog)
goto unlock;
}
- if (raw->progs && bpf_prog_array_length(raw->progs) >= BPF_MAX_PROGS) {
+ old_array = lirc_rcu_dereference(raw->progs);
+ if (old_array && bpf_prog_array_length(old_array) >= BPF_MAX_PROGS) {
ret = -E2BIG;
goto unlock;
}
- old_array = raw->progs;
ret = bpf_prog_array_copy(old_array, NULL, prog, &new_array);
if (ret < 0)
goto unlock;
@@ -174,7 +177,7 @@ unlock:
static int lirc_bpf_detach(struct rc_dev *rcdev, struct bpf_prog *prog)
{
- struct bpf_prog_array __rcu *old_array;
+ struct bpf_prog_array *old_array;
struct bpf_prog_array *new_array;
struct ir_raw_event_ctrl *raw;
int ret;
@@ -192,7 +195,7 @@ static int lirc_bpf_detach(struct rc_dev *rcdev, struct bpf_prog *prog)
goto unlock;
}
- old_array = raw->progs;
+ old_array = lirc_rcu_dereference(raw->progs);
ret = bpf_prog_array_copy(old_array, prog, NULL, &new_array);
/*
* Do not use bpf_prog_array_delete_safe() as we would end up
@@ -223,21 +226,22 @@ void lirc_bpf_run(struct rc_dev *rcdev, u32 sample)
/*
* This should be called once the rc thread has been stopped, so there can be
* no concurrent bpf execution.
+ *
+ * Should be called with the ir_raw_handler_lock held.
*/
void lirc_bpf_free(struct rc_dev *rcdev)
{
struct bpf_prog_array_item *item;
+ struct bpf_prog_array *array;
- if (!rcdev->raw->progs)
+ array = lirc_rcu_dereference(rcdev->raw->progs);
+ if (!array)
return;
- item = rcu_dereference(rcdev->raw->progs)->items;
- while (item->prog) {
+ for (item = array->items; item->prog; item++)
bpf_prog_put(item->prog);
- item++;
- }
- bpf_prog_array_free(rcdev->raw->progs);
+ bpf_prog_array_free(array);
}
int lirc_prog_attach(const union bpf_attr *attr, struct bpf_prog *prog)
@@ -290,7 +294,7 @@ int lirc_prog_detach(const union bpf_attr *attr)
int lirc_prog_query(const union bpf_attr *attr, union bpf_attr __user *uattr)
{
__u32 __user *prog_ids = u64_to_user_ptr(attr->query.prog_ids);
- struct bpf_prog_array __rcu *progs;
+ struct bpf_prog_array *progs;
struct rc_dev *rcdev;
u32 cnt, flags = 0;
int ret;
@@ -311,7 +315,7 @@ int lirc_prog_query(const union bpf_attr *attr, union bpf_attr __user *uattr)
if (ret)
goto put;
- progs = rcdev->raw->progs;
+ progs = lirc_rcu_dereference(rcdev->raw->progs);
cnt = progs ? bpf_prog_array_length(progs) : 0;
if (copy_to_user(&uattr->query.prog_cnt, &cnt, sizeof(cnt))) {
diff --git a/drivers/media/rc/ir-spi.c b/drivers/media/rc/ir-spi.c
index 66334e8d63ba..c58f2d38a458 100644
--- a/drivers/media/rc/ir-spi.c
+++ b/drivers/media/rc/ir-spi.c
@@ -161,6 +161,7 @@ static const struct of_device_id ir_spi_of_match[] = {
{ .compatible = "ir-spi-led" },
{},
};
+MODULE_DEVICE_TABLE(of, ir_spi_of_match);
static struct spi_driver ir_spi_driver = {
.probe = ir_spi_probe,
diff --git a/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c b/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c
index 732687ce0637..0a867ca90038 100644
--- a/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c
+++ b/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c
@@ -12,16 +12,16 @@
static struct rc_map_table adstech_dvb_t_pci[] = {
/* Keys 0 to 9 */
- { 0x4d, KEY_0 },
- { 0x57, KEY_1 },
- { 0x4f, KEY_2 },
- { 0x53, KEY_3 },
- { 0x56, KEY_4 },
- { 0x4e, KEY_5 },
- { 0x5e, KEY_6 },
- { 0x54, KEY_7 },
- { 0x4c, KEY_8 },
- { 0x5c, KEY_9 },
+ { 0x4d, KEY_NUMERIC_0 },
+ { 0x57, KEY_NUMERIC_1 },
+ { 0x4f, KEY_NUMERIC_2 },
+ { 0x53, KEY_NUMERIC_3 },
+ { 0x56, KEY_NUMERIC_4 },
+ { 0x4e, KEY_NUMERIC_5 },
+ { 0x5e, KEY_NUMERIC_6 },
+ { 0x54, KEY_NUMERIC_7 },
+ { 0x4c, KEY_NUMERIC_8 },
+ { 0x5c, KEY_NUMERIC_9 },
{ 0x5b, KEY_POWER },
{ 0x5f, KEY_MUTE },
diff --git a/drivers/media/rc/keymaps/rc-alink-dtu-m.c b/drivers/media/rc/keymaps/rc-alink-dtu-m.c
index 530af333af8e..8a2ccaf3b817 100644
--- a/drivers/media/rc/keymaps/rc-alink-dtu-m.c
+++ b/drivers/media/rc/keymaps/rc-alink-dtu-m.c
@@ -11,22 +11,22 @@
/* A-Link DTU(m) slim remote, 6 rows, 3 columns. */
static struct rc_map_table alink_dtu_m[] = {
{ 0x0800, KEY_VOLUMEUP },
- { 0x0801, KEY_1 },
- { 0x0802, KEY_3 },
- { 0x0803, KEY_7 },
- { 0x0804, KEY_9 },
+ { 0x0801, KEY_NUMERIC_1 },
+ { 0x0802, KEY_NUMERIC_3 },
+ { 0x0803, KEY_NUMERIC_7 },
+ { 0x0804, KEY_NUMERIC_9 },
{ 0x0805, KEY_NEW }, /* symbol: PIP */
- { 0x0806, KEY_0 },
+ { 0x0806, KEY_NUMERIC_0 },
{ 0x0807, KEY_CHANNEL }, /* JUMP */
- { 0x080d, KEY_5 },
- { 0x080f, KEY_2 },
+ { 0x080d, KEY_NUMERIC_5 },
+ { 0x080f, KEY_NUMERIC_2 },
{ 0x0812, KEY_POWER2 },
{ 0x0814, KEY_CHANNELUP },
{ 0x0816, KEY_VOLUMEDOWN },
- { 0x0818, KEY_6 },
+ { 0x0818, KEY_NUMERIC_6 },
{ 0x081a, KEY_MUTE },
- { 0x081b, KEY_8 },
- { 0x081c, KEY_4 },
+ { 0x081b, KEY_NUMERIC_8 },
+ { 0x081c, KEY_NUMERIC_4 },
{ 0x081d, KEY_CHANNELDOWN },
};
diff --git a/drivers/media/rc/keymaps/rc-anysee.c b/drivers/media/rc/keymaps/rc-anysee.c
index 9d1eee1f0515..34da03c46104 100644
--- a/drivers/media/rc/keymaps/rc-anysee.c
+++ b/drivers/media/rc/keymaps/rc-anysee.c
@@ -9,16 +9,16 @@
#include <linux/module.h>
static struct rc_map_table anysee[] = {
- { 0x0800, KEY_0 },
- { 0x0801, KEY_1 },
- { 0x0802, KEY_2 },
- { 0x0803, KEY_3 },
- { 0x0804, KEY_4 },
- { 0x0805, KEY_5 },
- { 0x0806, KEY_6 },
- { 0x0807, KEY_7 },
- { 0x0808, KEY_8 },
- { 0x0809, KEY_9 },
+ { 0x0800, KEY_NUMERIC_0 },
+ { 0x0801, KEY_NUMERIC_1 },
+ { 0x0802, KEY_NUMERIC_2 },
+ { 0x0803, KEY_NUMERIC_3 },
+ { 0x0804, KEY_NUMERIC_4 },
+ { 0x0805, KEY_NUMERIC_5 },
+ { 0x0806, KEY_NUMERIC_6 },
+ { 0x0807, KEY_NUMERIC_7 },
+ { 0x0808, KEY_NUMERIC_8 },
+ { 0x0809, KEY_NUMERIC_9 },
{ 0x080a, KEY_POWER2 }, /* [red power button] */
{ 0x080b, KEY_VIDEO }, /* [*] MODE */
{ 0x080c, KEY_CHANNEL }, /* [symbol counterclockwise arrow] */
diff --git a/drivers/media/rc/keymaps/rc-apac-viewcomp.c b/drivers/media/rc/keymaps/rc-apac-viewcomp.c
index af2e7fdc7b85..bdc47e25d46e 100644
--- a/drivers/media/rc/keymaps/rc-apac-viewcomp.c
+++ b/drivers/media/rc/keymaps/rc-apac-viewcomp.c
@@ -12,16 +12,16 @@
static struct rc_map_table apac_viewcomp[] = {
- { 0x01, KEY_1 },
- { 0x02, KEY_2 },
- { 0x03, KEY_3 },
- { 0x04, KEY_4 },
- { 0x05, KEY_5 },
- { 0x06, KEY_6 },
- { 0x07, KEY_7 },
- { 0x08, KEY_8 },
- { 0x09, KEY_9 },
- { 0x00, KEY_0 },
+ { 0x01, KEY_NUMERIC_1 },
+ { 0x02, KEY_NUMERIC_2 },
+ { 0x03, KEY_NUMERIC_3 },
+ { 0x04, KEY_NUMERIC_4 },
+ { 0x05, KEY_NUMERIC_5 },
+ { 0x06, KEY_NUMERIC_6 },
+ { 0x07, KEY_NUMERIC_7 },
+ { 0x08, KEY_NUMERIC_8 },
+ { 0x09, KEY_NUMERIC_9 },
+ { 0x00, KEY_NUMERIC_0 },
{ 0x17, KEY_LAST }, /* +100 */
{ 0x0a, KEY_LIST }, /* recall */
diff --git a/drivers/media/rc/keymaps/rc-astrometa-t2hybrid.c b/drivers/media/rc/keymaps/rc-astrometa-t2hybrid.c
index 727e35c31039..1d322137898e 100644
--- a/drivers/media/rc/keymaps/rc-astrometa-t2hybrid.c
+++ b/drivers/media/rc/keymaps/rc-astrometa-t2hybrid.c
@@ -21,21 +21,21 @@ static struct rc_map_table t2hybrid[] = {
{ 0x40, KEY_ZOOM }, /* Fullscreen */
{ 0x1e, KEY_VOLUMEUP },
- { 0x12, KEY_0 },
+ { 0x12, KEY_NUMERIC_0 },
{ 0x02, KEY_CHANNELDOWN },
{ 0x1c, KEY_AGAIN }, /* Recall */
- { 0x09, KEY_1 },
- { 0x1d, KEY_2 },
- { 0x1f, KEY_3 },
+ { 0x09, KEY_NUMERIC_1 },
+ { 0x1d, KEY_NUMERIC_2 },
+ { 0x1f, KEY_NUMERIC_3 },
- { 0x0d, KEY_4 },
- { 0x19, KEY_5 },
- { 0x1b, KEY_6 },
+ { 0x0d, KEY_NUMERIC_4 },
+ { 0x19, KEY_NUMERIC_5 },
+ { 0x1b, KEY_NUMERIC_6 },
- { 0x11, KEY_7 },
- { 0x15, KEY_8 },
- { 0x17, KEY_9 },
+ { 0x11, KEY_NUMERIC_7 },
+ { 0x15, KEY_NUMERIC_8 },
+ { 0x17, KEY_NUMERIC_9 },
};
static struct rc_map_list t2hybrid_map = {
diff --git a/drivers/media/rc/keymaps/rc-asus-pc39.c b/drivers/media/rc/keymaps/rc-asus-pc39.c
index 13a935c3ac59..7a4b3a6e3a49 100644
--- a/drivers/media/rc/keymaps/rc-asus-pc39.c
+++ b/drivers/media/rc/keymaps/rc-asus-pc39.c
@@ -16,16 +16,16 @@
static struct rc_map_table asus_pc39[] = {
/* Keys 0 to 9 */
- { 0x082a, KEY_0 },
- { 0x0816, KEY_1 },
- { 0x0812, KEY_2 },
- { 0x0814, KEY_3 },
- { 0x0836, KEY_4 },
- { 0x0832, KEY_5 },
- { 0x0834, KEY_6 },
- { 0x080e, KEY_7 },
- { 0x080a, KEY_8 },
- { 0x080c, KEY_9 },
+ { 0x082a, KEY_NUMERIC_0 },
+ { 0x0816, KEY_NUMERIC_1 },
+ { 0x0812, KEY_NUMERIC_2 },
+ { 0x0814, KEY_NUMERIC_3 },
+ { 0x0836, KEY_NUMERIC_4 },
+ { 0x0832, KEY_NUMERIC_5 },
+ { 0x0834, KEY_NUMERIC_6 },
+ { 0x080e, KEY_NUMERIC_7 },
+ { 0x080a, KEY_NUMERIC_8 },
+ { 0x080c, KEY_NUMERIC_9 },
{ 0x0801, KEY_RADIO }, /* radio */
{ 0x083c, KEY_MENU }, /* dvd/menu */
diff --git a/drivers/media/rc/keymaps/rc-asus-ps3-100.c b/drivers/media/rc/keymaps/rc-asus-ps3-100.c
index 7f836fcc68ac..09b60fa335e3 100644
--- a/drivers/media/rc/keymaps/rc-asus-ps3-100.c
+++ b/drivers/media/rc/keymaps/rc-asus-ps3-100.c
@@ -20,16 +20,16 @@ static struct rc_map_table asus_ps3_100[] = {
{ 0x0807, KEY_GREEN }, /* green */
/* Keys 0 to 9 */
- { 0x082a, KEY_0 },
- { 0x0816, KEY_1 },
- { 0x0812, KEY_2 },
- { 0x0814, KEY_3 },
- { 0x0836, KEY_4 },
- { 0x0832, KEY_5 },
- { 0x0834, KEY_6 },
- { 0x080e, KEY_7 },
- { 0x080a, KEY_8 },
- { 0x080c, KEY_9 },
+ { 0x082a, KEY_NUMERIC_0 },
+ { 0x0816, KEY_NUMERIC_1 },
+ { 0x0812, KEY_NUMERIC_2 },
+ { 0x0814, KEY_NUMERIC_3 },
+ { 0x0836, KEY_NUMERIC_4 },
+ { 0x0832, KEY_NUMERIC_5 },
+ { 0x0834, KEY_NUMERIC_6 },
+ { 0x080e, KEY_NUMERIC_7 },
+ { 0x080a, KEY_NUMERIC_8 },
+ { 0x080c, KEY_NUMERIC_9 },
{ 0x0815, KEY_VOLUMEUP },
{ 0x0826, KEY_VOLUMEDOWN },
diff --git a/drivers/media/rc/keymaps/rc-ati-x10.c b/drivers/media/rc/keymaps/rc-ati-x10.c
index 2f800dd5aa19..31fe1106b708 100644
--- a/drivers/media/rc/keymaps/rc-ati-x10.c
+++ b/drivers/media/rc/keymaps/rc-ati-x10.c
@@ -49,18 +49,18 @@ static struct rc_map_table ati_x10[] = {
* has problems with keycodes greater than 255, so avoid those high
* keycodes in default maps.
*/
- { 0x0d, KEY_1 },
- { 0x0e, KEY_2 },
- { 0x0f, KEY_3 },
- { 0x10, KEY_4 },
- { 0x11, KEY_5 },
- { 0x12, KEY_6 },
- { 0x13, KEY_7 },
- { 0x14, KEY_8 },
- { 0x15, KEY_9 },
+ { 0x0d, KEY_NUMERIC_1 },
+ { 0x0e, KEY_NUMERIC_2 },
+ { 0x0f, KEY_NUMERIC_3 },
+ { 0x10, KEY_NUMERIC_4 },
+ { 0x11, KEY_NUMERIC_5 },
+ { 0x12, KEY_NUMERIC_6 },
+ { 0x13, KEY_NUMERIC_7 },
+ { 0x14, KEY_NUMERIC_8 },
+ { 0x15, KEY_NUMERIC_9 },
{ 0x16, KEY_MENU }, /* "menu": DVD root menu */
/* KEY_NUMERIC_STAR? */
- { 0x17, KEY_0 },
+ { 0x17, KEY_NUMERIC_0 },
{ 0x18, KEY_SETUP }, /* "check": DVD setup menu */
/* KEY_NUMERIC_POUND? */
diff --git a/drivers/media/rc/keymaps/rc-avermedia-a16d.c b/drivers/media/rc/keymaps/rc-avermedia-a16d.c
index 5549c043cfe4..6467ff6e48d7 100644
--- a/drivers/media/rc/keymaps/rc-avermedia-a16d.c
+++ b/drivers/media/rc/keymaps/rc-avermedia-a16d.c
@@ -11,17 +11,17 @@
static struct rc_map_table avermedia_a16d[] = {
{ 0x20, KEY_LIST},
{ 0x00, KEY_POWER},
- { 0x28, KEY_1},
- { 0x18, KEY_2},
- { 0x38, KEY_3},
- { 0x24, KEY_4},
- { 0x14, KEY_5},
- { 0x34, KEY_6},
- { 0x2c, KEY_7},
- { 0x1c, KEY_8},
- { 0x3c, KEY_9},
+ { 0x28, KEY_NUMERIC_1},
+ { 0x18, KEY_NUMERIC_2},
+ { 0x38, KEY_NUMERIC_3},
+ { 0x24, KEY_NUMERIC_4},
+ { 0x14, KEY_NUMERIC_5},
+ { 0x34, KEY_NUMERIC_6},
+ { 0x2c, KEY_NUMERIC_7},
+ { 0x1c, KEY_NUMERIC_8},
+ { 0x3c, KEY_NUMERIC_9},
{ 0x12, KEY_SUBTITLE},
- { 0x22, KEY_0},
+ { 0x22, KEY_NUMERIC_0},
{ 0x32, KEY_REWIND},
{ 0x3a, KEY_SHUFFLE},
{ 0x02, KEY_PRINT},
diff --git a/drivers/media/rc/keymaps/rc-avermedia-cardbus.c b/drivers/media/rc/keymaps/rc-avermedia-cardbus.c
index 74edcd82e685..54fc6d9022c2 100644
--- a/drivers/media/rc/keymaps/rc-avermedia-cardbus.c
+++ b/drivers/media/rc/keymaps/rc-avermedia-cardbus.c
@@ -15,19 +15,19 @@ static struct rc_map_table avermedia_cardbus[] = {
{ 0x01, KEY_TUNER }, /* TV/FM */
{ 0x03, KEY_TEXT }, /* Teletext */
{ 0x04, KEY_EPG },
- { 0x05, KEY_1 },
- { 0x06, KEY_2 },
- { 0x07, KEY_3 },
+ { 0x05, KEY_NUMERIC_1 },
+ { 0x06, KEY_NUMERIC_2 },
+ { 0x07, KEY_NUMERIC_3 },
{ 0x08, KEY_AUDIO },
- { 0x09, KEY_4 },
- { 0x0a, KEY_5 },
- { 0x0b, KEY_6 },
+ { 0x09, KEY_NUMERIC_4 },
+ { 0x0a, KEY_NUMERIC_5 },
+ { 0x0b, KEY_NUMERIC_6 },
{ 0x0c, KEY_ZOOM }, /* Full screen */
- { 0x0d, KEY_7 },
- { 0x0e, KEY_8 },
- { 0x0f, KEY_9 },
+ { 0x0d, KEY_NUMERIC_7 },
+ { 0x0e, KEY_NUMERIC_8 },
+ { 0x0f, KEY_NUMERIC_9 },
{ 0x10, KEY_PAGEUP }, /* 16-CH PREV */
- { 0x11, KEY_0 },
+ { 0x11, KEY_NUMERIC_0 },
{ 0x12, KEY_INFO },
{ 0x13, KEY_AGAIN }, /* CH RTN - channel return */
{ 0x14, KEY_MUTE },
diff --git a/drivers/media/rc/keymaps/rc-avermedia-dvbt.c b/drivers/media/rc/keymaps/rc-avermedia-dvbt.c
index 796184160a48..92c6df3360b3 100644
--- a/drivers/media/rc/keymaps/rc-avermedia-dvbt.c
+++ b/drivers/media/rc/keymaps/rc-avermedia-dvbt.c
@@ -11,16 +11,16 @@
/* Matt Jesson <dvb@jesson.eclipse.co.uk */
static struct rc_map_table avermedia_dvbt[] = {
- { 0x28, KEY_0 }, /* '0' / 'enter' */
- { 0x22, KEY_1 }, /* '1' */
- { 0x12, KEY_2 }, /* '2' / 'up arrow' */
- { 0x32, KEY_3 }, /* '3' */
- { 0x24, KEY_4 }, /* '4' / 'left arrow' */
- { 0x14, KEY_5 }, /* '5' */
- { 0x34, KEY_6 }, /* '6' / 'right arrow' */
- { 0x26, KEY_7 }, /* '7' */
- { 0x16, KEY_8 }, /* '8' / 'down arrow' */
- { 0x36, KEY_9 }, /* '9' */
+ { 0x28, KEY_NUMERIC_0 }, /* '0' / 'enter' */
+ { 0x22, KEY_NUMERIC_1 }, /* '1' */
+ { 0x12, KEY_NUMERIC_2 }, /* '2' / 'up arrow' */
+ { 0x32, KEY_NUMERIC_3 }, /* '3' */
+ { 0x24, KEY_NUMERIC_4 }, /* '4' / 'left arrow' */
+ { 0x14, KEY_NUMERIC_5 }, /* '5' */
+ { 0x34, KEY_NUMERIC_6 }, /* '6' / 'right arrow' */
+ { 0x26, KEY_NUMERIC_7 }, /* '7' */
+ { 0x16, KEY_NUMERIC_8 }, /* '8' / 'down arrow' */
+ { 0x36, KEY_NUMERIC_9 }, /* '9' */
{ 0x20, KEY_VIDEO }, /* 'source' */
{ 0x10, KEY_TEXT }, /* 'teletext' */
diff --git a/drivers/media/rc/keymaps/rc-avermedia-m135a.c b/drivers/media/rc/keymaps/rc-avermedia-m135a.c
index d275d98d066a..311ddeb061ca 100644
--- a/drivers/media/rc/keymaps/rc-avermedia-m135a.c
+++ b/drivers/media/rc/keymaps/rc-avermedia-m135a.c
@@ -24,16 +24,16 @@ static struct rc_map_table avermedia_m135a[] = {
{ 0x022e, KEY_DOT }, /* '.' */
{ 0x0201, KEY_MODE }, /* TV/FM or SOURCE */
- { 0x0205, KEY_1 },
- { 0x0206, KEY_2 },
- { 0x0207, KEY_3 },
- { 0x0209, KEY_4 },
- { 0x020a, KEY_5 },
- { 0x020b, KEY_6 },
- { 0x020d, KEY_7 },
- { 0x020e, KEY_8 },
- { 0x020f, KEY_9 },
- { 0x0211, KEY_0 },
+ { 0x0205, KEY_NUMERIC_1 },
+ { 0x0206, KEY_NUMERIC_2 },
+ { 0x0207, KEY_NUMERIC_3 },
+ { 0x0209, KEY_NUMERIC_4 },
+ { 0x020a, KEY_NUMERIC_5 },
+ { 0x020b, KEY_NUMERIC_6 },
+ { 0x020d, KEY_NUMERIC_7 },
+ { 0x020e, KEY_NUMERIC_8 },
+ { 0x020f, KEY_NUMERIC_9 },
+ { 0x0211, KEY_NUMERIC_0 },
{ 0x0213, KEY_RIGHT }, /* -> or L */
{ 0x0212, KEY_LEFT }, /* <- or R */
@@ -70,17 +70,17 @@ static struct rc_map_table avermedia_m135a[] = {
{ 0x0406, KEY_MUTE },
{ 0x0408, KEY_MODE }, /* TV/FM */
- { 0x0409, KEY_1 },
- { 0x040a, KEY_2 },
- { 0x040b, KEY_3 },
- { 0x040c, KEY_4 },
- { 0x040d, KEY_5 },
- { 0x040e, KEY_6 },
- { 0x040f, KEY_7 },
- { 0x0410, KEY_8 },
- { 0x0411, KEY_9 },
+ { 0x0409, KEY_NUMERIC_1 },
+ { 0x040a, KEY_NUMERIC_2 },
+ { 0x040b, KEY_NUMERIC_3 },
+ { 0x040c, KEY_NUMERIC_4 },
+ { 0x040d, KEY_NUMERIC_5 },
+ { 0x040e, KEY_NUMERIC_6 },
+ { 0x040f, KEY_NUMERIC_7 },
+ { 0x0410, KEY_NUMERIC_8 },
+ { 0x0411, KEY_NUMERIC_9 },
{ 0x044c, KEY_DOT }, /* '.' */
- { 0x0412, KEY_0 },
+ { 0x0412, KEY_NUMERIC_0 },
{ 0x0407, KEY_REFRESH }, /* Refresh/Reload */
{ 0x0413, KEY_AUDIO },
diff --git a/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c b/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c
index 6a70aba92dfb..a970ed5a090b 100644
--- a/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c
+++ b/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c
@@ -18,17 +18,17 @@ static struct rc_map_table avermedia_m733a_rm_k6[] = {
{ 0x0406, KEY_MUTE },
{ 0x0408, KEY_MODE }, /* TV/FM */
- { 0x0409, KEY_1 },
- { 0x040a, KEY_2 },
- { 0x040b, KEY_3 },
- { 0x040c, KEY_4 },
- { 0x040d, KEY_5 },
- { 0x040e, KEY_6 },
- { 0x040f, KEY_7 },
- { 0x0410, KEY_8 },
- { 0x0411, KEY_9 },
+ { 0x0409, KEY_NUMERIC_1 },
+ { 0x040a, KEY_NUMERIC_2 },
+ { 0x040b, KEY_NUMERIC_3 },
+ { 0x040c, KEY_NUMERIC_4 },
+ { 0x040d, KEY_NUMERIC_5 },
+ { 0x040e, KEY_NUMERIC_6 },
+ { 0x040f, KEY_NUMERIC_7 },
+ { 0x0410, KEY_NUMERIC_8 },
+ { 0x0411, KEY_NUMERIC_9 },
{ 0x044c, KEY_DOT }, /* '.' */
- { 0x0412, KEY_0 },
+ { 0x0412, KEY_NUMERIC_0 },
{ 0x0407, KEY_REFRESH }, /* Refresh/Reload */
{ 0x0413, KEY_AUDIO },
diff --git a/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c b/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c
index 61348894c93b..cf8a4fd107f4 100644
--- a/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c
+++ b/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c
@@ -20,16 +20,16 @@ static struct rc_map_table avermedia_rm_ks[] = {
{ 0x0506, KEY_MUTE }, /* Mute */
{ 0x0507, KEY_AGAIN }, /* Recall */
{ 0x0508, KEY_VIDEO }, /* Source */
- { 0x0509, KEY_1 }, /* 1 */
- { 0x050a, KEY_2 }, /* 2 */
- { 0x050b, KEY_3 }, /* 3 */
- { 0x050c, KEY_4 }, /* 4 */
- { 0x050d, KEY_5 }, /* 5 */
- { 0x050e, KEY_6 }, /* 6 */
- { 0x050f, KEY_7 }, /* 7 */
- { 0x0510, KEY_8 }, /* 8 */
- { 0x0511, KEY_9 }, /* 9 */
- { 0x0512, KEY_0 }, /* 0 */
+ { 0x0509, KEY_NUMERIC_1 }, /* 1 */
+ { 0x050a, KEY_NUMERIC_2 }, /* 2 */
+ { 0x050b, KEY_NUMERIC_3 }, /* 3 */
+ { 0x050c, KEY_NUMERIC_4 }, /* 4 */
+ { 0x050d, KEY_NUMERIC_5 }, /* 5 */
+ { 0x050e, KEY_NUMERIC_6 }, /* 6 */
+ { 0x050f, KEY_NUMERIC_7 }, /* 7 */
+ { 0x0510, KEY_NUMERIC_8 }, /* 8 */
+ { 0x0511, KEY_NUMERIC_9 }, /* 9 */
+ { 0x0512, KEY_NUMERIC_0 }, /* 0 */
{ 0x0513, KEY_AUDIO }, /* Audio */
{ 0x0515, KEY_EPG }, /* EPG */
{ 0x0516, KEY_PLAYPAUSE }, /* Play/Pause */
diff --git a/drivers/media/rc/keymaps/rc-avermedia.c b/drivers/media/rc/keymaps/rc-avermedia.c
index 631ff52564f0..f96f229b70bb 100644
--- a/drivers/media/rc/keymaps/rc-avermedia.c
+++ b/drivers/media/rc/keymaps/rc-avermedia.c
@@ -11,16 +11,16 @@
/* Alex Hermann <gaaf@gmx.net> */
static struct rc_map_table avermedia[] = {
- { 0x28, KEY_1 },
- { 0x18, KEY_2 },
- { 0x38, KEY_3 },
- { 0x24, KEY_4 },
- { 0x14, KEY_5 },
- { 0x34, KEY_6 },
- { 0x2c, KEY_7 },
- { 0x1c, KEY_8 },
- { 0x3c, KEY_9 },
- { 0x22, KEY_0 },
+ { 0x28, KEY_NUMERIC_1 },
+ { 0x18, KEY_NUMERIC_2 },
+ { 0x38, KEY_NUMERIC_3 },
+ { 0x24, KEY_NUMERIC_4 },
+ { 0x14, KEY_NUMERIC_5 },
+ { 0x34, KEY_NUMERIC_6 },
+ { 0x2c, KEY_NUMERIC_7 },
+ { 0x1c, KEY_NUMERIC_8 },
+ { 0x3c, KEY_NUMERIC_9 },
+ { 0x22, KEY_NUMERIC_0 },
{ 0x20, KEY_TV }, /* TV/FM */
{ 0x10, KEY_CD }, /* CD */
diff --git a/drivers/media/rc/keymaps/rc-avertv-303.c b/drivers/media/rc/keymaps/rc-avertv-303.c
index 47ca8b7ea532..a3e2e945c769 100644
--- a/drivers/media/rc/keymaps/rc-avertv-303.c
+++ b/drivers/media/rc/keymaps/rc-avertv-303.c
@@ -11,16 +11,16 @@
/* AVERTV STUDIO 303 Remote */
static struct rc_map_table avertv_303[] = {
- { 0x2a, KEY_1 },
- { 0x32, KEY_2 },
- { 0x3a, KEY_3 },
- { 0x4a, KEY_4 },
- { 0x52, KEY_5 },
- { 0x5a, KEY_6 },
- { 0x6a, KEY_7 },
- { 0x72, KEY_8 },
- { 0x7a, KEY_9 },
- { 0x0e, KEY_0 },
+ { 0x2a, KEY_NUMERIC_1 },
+ { 0x32, KEY_NUMERIC_2 },
+ { 0x3a, KEY_NUMERIC_3 },
+ { 0x4a, KEY_NUMERIC_4 },
+ { 0x52, KEY_NUMERIC_5 },
+ { 0x5a, KEY_NUMERIC_6 },
+ { 0x6a, KEY_NUMERIC_7 },
+ { 0x72, KEY_NUMERIC_8 },
+ { 0x7a, KEY_NUMERIC_9 },
+ { 0x0e, KEY_NUMERIC_0 },
{ 0x02, KEY_POWER },
{ 0x22, KEY_VIDEO },
diff --git a/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c b/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c
index 8e7e95306a5c..5fc8e4cd102e 100644
--- a/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c
+++ b/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c
@@ -10,18 +10,18 @@
static struct rc_map_table azurewave_ad_tu700[] = {
{ 0x0000, KEY_TAB }, /* Tab */
- { 0x0001, KEY_2 },
+ { 0x0001, KEY_NUMERIC_2 },
{ 0x0002, KEY_CHANNELDOWN },
- { 0x0003, KEY_1 },
+ { 0x0003, KEY_NUMERIC_1 },
{ 0x0004, KEY_MENU }, /* Record List */
{ 0x0005, KEY_CHANNELUP },
- { 0x0006, KEY_3 },
+ { 0x0006, KEY_NUMERIC_3 },
{ 0x0007, KEY_SLEEP }, /* Hibernate */
{ 0x0008, KEY_VIDEO }, /* A/V */
- { 0x0009, KEY_4 },
+ { 0x0009, KEY_NUMERIC_4 },
{ 0x000a, KEY_VOLUMEDOWN },
{ 0x000c, KEY_CANCEL }, /* Cancel */
- { 0x000d, KEY_7 },
+ { 0x000d, KEY_NUMERIC_7 },
{ 0x000e, KEY_AGAIN }, /* Recall */
{ 0x000f, KEY_TEXT }, /* Teletext */
{ 0x0010, KEY_MUTE },
@@ -29,17 +29,17 @@ static struct rc_map_table azurewave_ad_tu700[] = {
{ 0x0012, KEY_FASTFORWARD }, /* FF >> */
{ 0x0013, KEY_BACK }, /* Back */
{ 0x0014, KEY_PLAY },
- { 0x0015, KEY_0 },
+ { 0x0015, KEY_NUMERIC_0 },
{ 0x0016, KEY_POWER2 }, /* [red power button] */
{ 0x0017, KEY_FAVORITES }, /* Favorite List */
{ 0x0018, KEY_RED },
- { 0x0019, KEY_8 },
+ { 0x0019, KEY_NUMERIC_8 },
{ 0x001a, KEY_STOP },
- { 0x001b, KEY_9 },
+ { 0x001b, KEY_NUMERIC_9 },
{ 0x001c, KEY_EPG }, /* Info/EPG */
- { 0x001d, KEY_5 },
+ { 0x001d, KEY_NUMERIC_5 },
{ 0x001e, KEY_VOLUMEUP },
- { 0x001f, KEY_6 },
+ { 0x001f, KEY_NUMERIC_6 },
{ 0x0040, KEY_REWIND }, /* FR << */
{ 0x0041, KEY_PREVIOUS }, /* Replay */
{ 0x0042, KEY_NEXT }, /* Skip */
diff --git a/drivers/media/rc/keymaps/rc-behold-columbus.c b/drivers/media/rc/keymaps/rc-behold-columbus.c
index b68380a76010..8579b3d5128d 100644
--- a/drivers/media/rc/keymaps/rc-behold-columbus.c
+++ b/drivers/media/rc/keymaps/rc-behold-columbus.c
@@ -37,24 +37,24 @@ static struct rc_map_table behold_columbus[] = {
* 0x07 0x08 0x09 0x10 *
* 7 8 9 Zoom *
* */
- { 0x01, KEY_1 },
- { 0x02, KEY_2 },
- { 0x03, KEY_3 },
+ { 0x01, KEY_NUMERIC_1 },
+ { 0x02, KEY_NUMERIC_2 },
+ { 0x03, KEY_NUMERIC_3 },
{ 0x0D, KEY_SETUP }, /* Setup key */
- { 0x04, KEY_4 },
- { 0x05, KEY_5 },
- { 0x06, KEY_6 },
+ { 0x04, KEY_NUMERIC_4 },
+ { 0x05, KEY_NUMERIC_5 },
+ { 0x06, KEY_NUMERIC_6 },
{ 0x19, KEY_CAMERA }, /* Snapshot key */
- { 0x07, KEY_7 },
- { 0x08, KEY_8 },
- { 0x09, KEY_9 },
+ { 0x07, KEY_NUMERIC_7 },
+ { 0x08, KEY_NUMERIC_8 },
+ { 0x09, KEY_NUMERIC_9 },
{ 0x10, KEY_ZOOM },
/* 0x0A 0x00 0x0B 0x0C *
* RECALL 0 ChannelUp VolumeUp *
* */
{ 0x0A, KEY_AGAIN },
- { 0x00, KEY_0 },
+ { 0x00, KEY_NUMERIC_0 },
{ 0x0B, KEY_CHANNELUP },
{ 0x0C, KEY_VOLUMEUP },
diff --git a/drivers/media/rc/keymaps/rc-behold.c b/drivers/media/rc/keymaps/rc-behold.c
index 2b7cddb2f36d..28397ce05a7f 100644
--- a/drivers/media/rc/keymaps/rc-behold.c
+++ b/drivers/media/rc/keymaps/rc-behold.c
@@ -37,21 +37,21 @@ static struct rc_map_table behold[] = {
* 0x07 0x08 0x09 *
* 7 8 9 *
* */
- { 0x866b01, KEY_1 },
- { 0x866b02, KEY_2 },
- { 0x866b03, KEY_3 },
- { 0x866b04, KEY_4 },
- { 0x866b05, KEY_5 },
- { 0x866b06, KEY_6 },
- { 0x866b07, KEY_7 },
- { 0x866b08, KEY_8 },
- { 0x866b09, KEY_9 },
+ { 0x866b01, KEY_NUMERIC_1 },
+ { 0x866b02, KEY_NUMERIC_2 },
+ { 0x866b03, KEY_NUMERIC_3 },
+ { 0x866b04, KEY_NUMERIC_4 },
+ { 0x866b05, KEY_NUMERIC_5 },
+ { 0x866b06, KEY_NUMERIC_6 },
+ { 0x866b07, KEY_NUMERIC_7 },
+ { 0x866b08, KEY_NUMERIC_8 },
+ { 0x866b09, KEY_NUMERIC_9 },
/* 0x0a 0x00 0x17 *
* RECALL 0 MODE *
* */
{ 0x866b0a, KEY_AGAIN },
- { 0x866b00, KEY_0 },
+ { 0x866b00, KEY_NUMERIC_0 },
{ 0x866b17, KEY_MODE },
/* 0x14 0x10 *
diff --git a/drivers/media/rc/keymaps/rc-budget-ci-old.c b/drivers/media/rc/keymaps/rc-budget-ci-old.c
index 56f051af6154..6ca822256862 100644
--- a/drivers/media/rc/keymaps/rc-budget-ci-old.c
+++ b/drivers/media/rc/keymaps/rc-budget-ci-old.c
@@ -16,16 +16,16 @@
*/
static struct rc_map_table budget_ci_old[] = {
- { 0x00, KEY_0 },
- { 0x01, KEY_1 },
- { 0x02, KEY_2 },
- { 0x03, KEY_3 },
- { 0x04, KEY_4 },
- { 0x05, KEY_5 },
- { 0x06, KEY_6 },
- { 0x07, KEY_7 },
- { 0x08, KEY_8 },
- { 0x09, KEY_9 },
+ { 0x00, KEY_NUMERIC_0 },
+ { 0x01, KEY_NUMERIC_1 },
+ { 0x02, KEY_NUMERIC_2 },
+ { 0x03, KEY_NUMERIC_3 },
+ { 0x04, KEY_NUMERIC_4 },
+ { 0x05, KEY_NUMERIC_5 },
+ { 0x06, KEY_NUMERIC_6 },
+ { 0x07, KEY_NUMERIC_7 },
+ { 0x08, KEY_NUMERIC_8 },
+ { 0x09, KEY_NUMERIC_9 },
{ 0x0a, KEY_ENTER },
{ 0x0b, KEY_RED },
{ 0x0c, KEY_POWER }, /* RADIO on Hauppauge */
diff --git a/drivers/media/rc/keymaps/rc-cinergy-1400.c b/drivers/media/rc/keymaps/rc-cinergy-1400.c
index dacb13c53bb4..4433d28b219c 100644
--- a/drivers/media/rc/keymaps/rc-cinergy-1400.c
+++ b/drivers/media/rc/keymaps/rc-cinergy-1400.c
@@ -12,16 +12,16 @@
static struct rc_map_table cinergy_1400[] = {
{ 0x01, KEY_POWER },
- { 0x02, KEY_1 },
- { 0x03, KEY_2 },
- { 0x04, KEY_3 },
- { 0x05, KEY_4 },
- { 0x06, KEY_5 },
- { 0x07, KEY_6 },
- { 0x08, KEY_7 },
- { 0x09, KEY_8 },
- { 0x0a, KEY_9 },
- { 0x0c, KEY_0 },
+ { 0x02, KEY_NUMERIC_1 },
+ { 0x03, KEY_NUMERIC_2 },
+ { 0x04, KEY_NUMERIC_3 },
+ { 0x05, KEY_NUMERIC_4 },
+ { 0x06, KEY_NUMERIC_5 },
+ { 0x07, KEY_NUMERIC_6 },
+ { 0x08, KEY_NUMERIC_7 },
+ { 0x09, KEY_NUMERIC_8 },
+ { 0x0a, KEY_NUMERIC_9 },
+ { 0x0c, KEY_NUMERIC_0 },
{ 0x0b, KEY_VIDEO },
{ 0x0d, KEY_REFRESH },
diff --git a/drivers/media/rc/keymaps/rc-cinergy.c b/drivers/media/rc/keymaps/rc-cinergy.c
index 6ab2e51b764d..b34a37b8fe61 100644
--- a/drivers/media/rc/keymaps/rc-cinergy.c
+++ b/drivers/media/rc/keymaps/rc-cinergy.c
@@ -9,16 +9,16 @@
#include <linux/module.h>
static struct rc_map_table cinergy[] = {
- { 0x00, KEY_0 },
- { 0x01, KEY_1 },
- { 0x02, KEY_2 },
- { 0x03, KEY_3 },
- { 0x04, KEY_4 },
- { 0x05, KEY_5 },
- { 0x06, KEY_6 },
- { 0x07, KEY_7 },
- { 0x08, KEY_8 },
- { 0x09, KEY_9 },
+ { 0x00, KEY_NUMERIC_0 },
+ { 0x01, KEY_NUMERIC_1 },
+ { 0x02, KEY_NUMERIC_2 },
+ { 0x03, KEY_NUMERIC_3 },
+ { 0x04, KEY_NUMERIC_4 },
+ { 0x05, KEY_NUMERIC_5 },
+ { 0x06, KEY_NUMERIC_6 },
+ { 0x07, KEY_NUMERIC_7 },
+ { 0x08, KEY_NUMERIC_8 },
+ { 0x09, KEY_NUMERIC_9 },
{ 0x0a, KEY_POWER },
{ 0x0b, KEY_MEDIA }, /* app */
diff --git a/drivers/media/rc/keymaps/rc-d680-dmb.c b/drivers/media/rc/keymaps/rc-d680-dmb.c
index f67aa597a75b..d491a5e9750f 100644
--- a/drivers/media/rc/keymaps/rc-d680-dmb.c
+++ b/drivers/media/rc/keymaps/rc-d680-dmb.c
@@ -11,16 +11,16 @@
static struct rc_map_table rc_map_d680_dmb_table[] = {
{ 0x0038, KEY_SWITCHVIDEOMODE }, /* TV/AV */
{ 0x080c, KEY_ZOOM },
- { 0x0800, KEY_0 },
- { 0x0001, KEY_1 },
- { 0x0802, KEY_2 },
- { 0x0003, KEY_3 },
- { 0x0804, KEY_4 },
- { 0x0005, KEY_5 },
- { 0x0806, KEY_6 },
- { 0x0007, KEY_7 },
- { 0x0808, KEY_8 },
- { 0x0009, KEY_9 },
+ { 0x0800, KEY_NUMERIC_0 },
+ { 0x0001, KEY_NUMERIC_1 },
+ { 0x0802, KEY_NUMERIC_2 },
+ { 0x0003, KEY_NUMERIC_3 },
+ { 0x0804, KEY_NUMERIC_4 },
+ { 0x0005, KEY_NUMERIC_5 },
+ { 0x0806, KEY_NUMERIC_6 },
+ { 0x0007, KEY_NUMERIC_7 },
+ { 0x0808, KEY_NUMERIC_8 },
+ { 0x0009, KEY_NUMERIC_9 },
{ 0x000a, KEY_MUTE },
{ 0x0829, KEY_BACK },
{ 0x0012, KEY_CHANNELUP },
diff --git a/drivers/media/rc/keymaps/rc-delock-61959.c b/drivers/media/rc/keymaps/rc-delock-61959.c
index c60fc1e46fc5..529435e8d416 100644
--- a/drivers/media/rc/keymaps/rc-delock-61959.c
+++ b/drivers/media/rc/keymaps/rc-delock-61959.c
@@ -14,16 +14,16 @@ static struct rc_map_table delock_61959[] = {
{ 0x866b16, KEY_POWER2 }, /* Power */
{ 0x866b0c, KEY_POWER }, /* Shut Down */
- { 0x866b00, KEY_1},
- { 0x866b01, KEY_2},
- { 0x866b02, KEY_3},
- { 0x866b03, KEY_4},
- { 0x866b04, KEY_5},
- { 0x866b05, KEY_6},
- { 0x866b06, KEY_7},
- { 0x866b07, KEY_8},
- { 0x866b08, KEY_9},
- { 0x866b14, KEY_0},
+ { 0x866b00, KEY_NUMERIC_1},
+ { 0x866b01, KEY_NUMERIC_2},
+ { 0x866b02, KEY_NUMERIC_3},
+ { 0x866b03, KEY_NUMERIC_4},
+ { 0x866b04, KEY_NUMERIC_5},
+ { 0x866b05, KEY_NUMERIC_6},
+ { 0x866b06, KEY_NUMERIC_7},
+ { 0x866b07, KEY_NUMERIC_8},
+ { 0x866b08, KEY_NUMERIC_9},
+ { 0x866b14, KEY_NUMERIC_0},
{ 0x866b0a, KEY_ZOOM}, /* Full Screen */
{ 0x866b10, KEY_CAMERA}, /* Photo */
diff --git a/drivers/media/rc/keymaps/rc-dib0700-nec.c b/drivers/media/rc/keymaps/rc-dib0700-nec.c
index 4ee801acb089..f1fcdf16f485 100644
--- a/drivers/media/rc/keymaps/rc-dib0700-nec.c
+++ b/drivers/media/rc/keymaps/rc-dib0700-nec.c
@@ -17,16 +17,16 @@ static struct rc_map_table dib0700_nec_table[] = {
/* Key codes for the Pixelview SBTVD remote */
{ 0x866b13, KEY_MUTE },
{ 0x866b12, KEY_POWER },
- { 0x866b01, KEY_1 },
- { 0x866b02, KEY_2 },
- { 0x866b03, KEY_3 },
- { 0x866b04, KEY_4 },
- { 0x866b05, KEY_5 },
- { 0x866b06, KEY_6 },
- { 0x866b07, KEY_7 },
- { 0x866b08, KEY_8 },
- { 0x866b09, KEY_9 },
- { 0x866b00, KEY_0 },
+ { 0x866b01, KEY_NUMERIC_1 },
+ { 0x866b02, KEY_NUMERIC_2 },
+ { 0x866b03, KEY_NUMERIC_3 },
+ { 0x866b04, KEY_NUMERIC_4 },
+ { 0x866b05, KEY_NUMERIC_5 },
+ { 0x866b06, KEY_NUMERIC_6 },
+ { 0x866b07, KEY_NUMERIC_7 },
+ { 0x866b08, KEY_NUMERIC_8 },
+ { 0x866b09, KEY_NUMERIC_9 },
+ { 0x866b00, KEY_NUMERIC_0 },
{ 0x866b0d, KEY_CHANNELUP },
{ 0x866b19, KEY_CHANNELDOWN },
{ 0x866b10, KEY_VOLUMEUP },
@@ -60,17 +60,17 @@ static struct rc_map_table dib0700_nec_table[] = {
/* Key codes for the Elgato EyeTV Diversity silver remote */
{ 0x4501, KEY_POWER },
{ 0x4502, KEY_MUTE },
- { 0x4503, KEY_1 },
- { 0x4504, KEY_2 },
- { 0x4505, KEY_3 },
- { 0x4506, KEY_4 },
- { 0x4507, KEY_5 },
- { 0x4508, KEY_6 },
- { 0x4509, KEY_7 },
- { 0x450a, KEY_8 },
- { 0x450b, KEY_9 },
+ { 0x4503, KEY_NUMERIC_1 },
+ { 0x4504, KEY_NUMERIC_2 },
+ { 0x4505, KEY_NUMERIC_3 },
+ { 0x4506, KEY_NUMERIC_4 },
+ { 0x4507, KEY_NUMERIC_5 },
+ { 0x4508, KEY_NUMERIC_6 },
+ { 0x4509, KEY_NUMERIC_7 },
+ { 0x450a, KEY_NUMERIC_8 },
+ { 0x450b, KEY_NUMERIC_9 },
{ 0x450c, KEY_LAST },
- { 0x450d, KEY_0 },
+ { 0x450d, KEY_NUMERIC_0 },
{ 0x450e, KEY_ENTER },
{ 0x450f, KEY_RED },
{ 0x4510, KEY_CHANNELUP },
diff --git a/drivers/media/rc/keymaps/rc-dib0700-rc5.c b/drivers/media/rc/keymaps/rc-dib0700-rc5.c
index ef4085a0fda3..002fffcba95d 100644
--- a/drivers/media/rc/keymaps/rc-dib0700-rc5.c
+++ b/drivers/media/rc/keymaps/rc-dib0700-rc5.c
@@ -22,16 +22,16 @@ static struct rc_map_table dib0700_rc5_table[] = {
{ 0x0709, KEY_VOLUMEDOWN },
{ 0x0706, KEY_CHANNELUP },
{ 0x070c, KEY_CHANNELDOWN },
- { 0x070f, KEY_1 },
- { 0x0715, KEY_2 },
- { 0x0710, KEY_3 },
- { 0x0718, KEY_4 },
- { 0x071b, KEY_5 },
- { 0x071e, KEY_6 },
- { 0x0711, KEY_7 },
- { 0x0721, KEY_8 },
- { 0x0712, KEY_9 },
- { 0x0727, KEY_0 },
+ { 0x070f, KEY_NUMERIC_1 },
+ { 0x0715, KEY_NUMERIC_2 },
+ { 0x0710, KEY_NUMERIC_3 },
+ { 0x0718, KEY_NUMERIC_4 },
+ { 0x071b, KEY_NUMERIC_5 },
+ { 0x071e, KEY_NUMERIC_6 },
+ { 0x0711, KEY_NUMERIC_7 },
+ { 0x0721, KEY_NUMERIC_8 },
+ { 0x0712, KEY_NUMERIC_9 },
+ { 0x0727, KEY_NUMERIC_0 },
{ 0x0724, KEY_SCREEN }, /* 'Square' key */
{ 0x072a, KEY_TEXT }, /* 'T' key */
{ 0x072d, KEY_REWIND },
@@ -43,17 +43,17 @@ static struct rc_map_table dib0700_rc5_table[] = {
/* Key codes for the Terratec Cinergy DT XS Diversity, similar to cinergyT2.c */
{ 0xeb01, KEY_POWER },
- { 0xeb02, KEY_1 },
- { 0xeb03, KEY_2 },
- { 0xeb04, KEY_3 },
- { 0xeb05, KEY_4 },
- { 0xeb06, KEY_5 },
- { 0xeb07, KEY_6 },
- { 0xeb08, KEY_7 },
- { 0xeb09, KEY_8 },
- { 0xeb0a, KEY_9 },
+ { 0xeb02, KEY_NUMERIC_1 },
+ { 0xeb03, KEY_NUMERIC_2 },
+ { 0xeb04, KEY_NUMERIC_3 },
+ { 0xeb05, KEY_NUMERIC_4 },
+ { 0xeb06, KEY_NUMERIC_5 },
+ { 0xeb07, KEY_NUMERIC_6 },
+ { 0xeb08, KEY_NUMERIC_7 },
+ { 0xeb09, KEY_NUMERIC_8 },
+ { 0xeb0a, KEY_NUMERIC_9 },
{ 0xeb0b, KEY_VIDEO },
- { 0xeb0c, KEY_0 },
+ { 0xeb0c, KEY_NUMERIC_0 },
{ 0xeb0d, KEY_REFRESH },
{ 0xeb0f, KEY_EPG },
{ 0xeb10, KEY_UP },
@@ -92,16 +92,16 @@ static struct rc_map_table dib0700_rc5_table[] = {
{ 0xeb5c, KEY_NEXT },
/* Key codes for the Haupauge WinTV Nova-TD, copied from nova-t-usb2.c (Nova-T USB2) */
- { 0x1e00, KEY_0 },
- { 0x1e01, KEY_1 },
- { 0x1e02, KEY_2 },
- { 0x1e03, KEY_3 },
- { 0x1e04, KEY_4 },
- { 0x1e05, KEY_5 },
- { 0x1e06, KEY_6 },
- { 0x1e07, KEY_7 },
- { 0x1e08, KEY_8 },
- { 0x1e09, KEY_9 },
+ { 0x1e00, KEY_NUMERIC_0 },
+ { 0x1e01, KEY_NUMERIC_1 },
+ { 0x1e02, KEY_NUMERIC_2 },
+ { 0x1e03, KEY_NUMERIC_3 },
+ { 0x1e04, KEY_NUMERIC_4 },
+ { 0x1e05, KEY_NUMERIC_5 },
+ { 0x1e06, KEY_NUMERIC_6 },
+ { 0x1e07, KEY_NUMERIC_7 },
+ { 0x1e08, KEY_NUMERIC_8 },
+ { 0x1e09, KEY_NUMERIC_9 },
{ 0x1e0a, KEY_KPASTERISK },
{ 0x1e0b, KEY_RED },
{ 0x1e0c, KEY_RADIO },
@@ -144,16 +144,16 @@ static struct rc_map_table dib0700_rc5_table[] = {
{ 0x0f4e, KEY_PRINT }, /* PREVIEW */
{ 0x0840, KEY_SCREEN }, /* full screen toggle*/
{ 0x0f71, KEY_DOT }, /* frequency */
- { 0x0743, KEY_0 },
- { 0x0c41, KEY_1 },
- { 0x0443, KEY_2 },
- { 0x0b7f, KEY_3 },
- { 0x0e41, KEY_4 },
- { 0x0643, KEY_5 },
- { 0x097f, KEY_6 },
- { 0x0d7e, KEY_7 },
- { 0x057c, KEY_8 },
- { 0x0a40, KEY_9 },
+ { 0x0743, KEY_NUMERIC_0 },
+ { 0x0c41, KEY_NUMERIC_1 },
+ { 0x0443, KEY_NUMERIC_2 },
+ { 0x0b7f, KEY_NUMERIC_3 },
+ { 0x0e41, KEY_NUMERIC_4 },
+ { 0x0643, KEY_NUMERIC_5 },
+ { 0x097f, KEY_NUMERIC_6 },
+ { 0x0d7e, KEY_NUMERIC_7 },
+ { 0x057c, KEY_NUMERIC_8 },
+ { 0x0a40, KEY_NUMERIC_9 },
{ 0x0e4e, KEY_CLEAR },
{ 0x047c, KEY_CHANNEL }, /* show channel number */
{ 0x0f41, KEY_LAST }, /* recall */
@@ -168,16 +168,16 @@ static struct rc_map_table dib0700_rc5_table[] = {
{ 0x007d, KEY_CHANNELDOWN },
/* Key codes for Nova-TD "credit card" remote control. */
- { 0x1d00, KEY_0 },
- { 0x1d01, KEY_1 },
- { 0x1d02, KEY_2 },
- { 0x1d03, KEY_3 },
- { 0x1d04, KEY_4 },
- { 0x1d05, KEY_5 },
- { 0x1d06, KEY_6 },
- { 0x1d07, KEY_7 },
- { 0x1d08, KEY_8 },
- { 0x1d09, KEY_9 },
+ { 0x1d00, KEY_NUMERIC_0 },
+ { 0x1d01, KEY_NUMERIC_1 },
+ { 0x1d02, KEY_NUMERIC_2 },
+ { 0x1d03, KEY_NUMERIC_3 },
+ { 0x1d04, KEY_NUMERIC_4 },
+ { 0x1d05, KEY_NUMERIC_5 },
+ { 0x1d06, KEY_NUMERIC_6 },
+ { 0x1d07, KEY_NUMERIC_7 },
+ { 0x1d08, KEY_NUMERIC_8 },
+ { 0x1d09, KEY_NUMERIC_9 },
{ 0x1d0a, KEY_TEXT },
{ 0x1d0d, KEY_MENU },
{ 0x1d0f, KEY_MUTE },
diff --git a/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c b/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c
index f4d0799dcc72..2466d8c50226 100644
--- a/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c
+++ b/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c
@@ -12,14 +12,14 @@ static struct rc_map_table digitalnow_tinytwin[] = {
{ 0x0000, KEY_MUTE }, /* [symbol speaker] */
{ 0x0001, KEY_VOLUMEUP },
{ 0x0002, KEY_POWER2 }, /* TV [power button] */
- { 0x0003, KEY_2 },
- { 0x0004, KEY_3 },
- { 0x0005, KEY_4 },
- { 0x0006, KEY_6 },
- { 0x0007, KEY_7 },
- { 0x0008, KEY_8 },
+ { 0x0003, KEY_NUMERIC_2 },
+ { 0x0004, KEY_NUMERIC_3 },
+ { 0x0005, KEY_NUMERIC_4 },
+ { 0x0006, KEY_NUMERIC_6 },
+ { 0x0007, KEY_NUMERIC_7 },
+ { 0x0008, KEY_NUMERIC_8 },
{ 0x0009, KEY_NUMERIC_STAR }, /* [*] */
- { 0x000a, KEY_0 },
+ { 0x000a, KEY_NUMERIC_0 },
{ 0x000b, KEY_NUMERIC_POUND }, /* [#] */
{ 0x000c, KEY_RIGHT }, /* [right arrow] */
{ 0x000d, KEY_HOMEPAGE }, /* [symbol home] Start */
@@ -36,10 +36,10 @@ static struct rc_map_table digitalnow_tinytwin[] = {
{ 0x0019, KEY_BLUE }, /* [blue] MyTV */
{ 0x001a, KEY_REWIND }, /* REW [<<] */
{ 0x001b, KEY_PLAY }, /* PLAY */
- { 0x001c, KEY_5 },
- { 0x001d, KEY_9 },
+ { 0x001c, KEY_NUMERIC_5 },
+ { 0x001d, KEY_NUMERIC_9 },
{ 0x001e, KEY_VOLUMEDOWN },
- { 0x001f, KEY_1 },
+ { 0x001f, KEY_NUMERIC_1 },
{ 0x0040, KEY_STOP }, /* STOP */
{ 0x0042, KEY_PAUSE }, /* PAUSE */
{ 0x0043, KEY_SCREEN }, /* Aspect */
diff --git a/drivers/media/rc/keymaps/rc-digittrade.c b/drivers/media/rc/keymaps/rc-digittrade.c
index 6849f1a5721c..65bc8ad7e52c 100644
--- a/drivers/media/rc/keymaps/rc-digittrade.c
+++ b/drivers/media/rc/keymaps/rc-digittrade.c
@@ -14,11 +14,11 @@
/* Digittrade DVB-T USB Stick */
static struct rc_map_table digittrade[] = {
- { 0x0000, KEY_9 },
+ { 0x0000, KEY_NUMERIC_9 },
{ 0x0001, KEY_EPG }, /* EPG */
{ 0x0002, KEY_VOLUMEDOWN }, /* Vol Dn */
{ 0x0003, KEY_TEXT }, /* TELETEXT */
- { 0x0004, KEY_8 },
+ { 0x0004, KEY_NUMERIC_8 },
{ 0x0005, KEY_MUTE }, /* MUTE */
{ 0x0006, KEY_POWER2 }, /* POWER */
{ 0x0009, KEY_ZOOM }, /* FULLSCREEN */
@@ -26,22 +26,22 @@ static struct rc_map_table digittrade[] = {
{ 0x000d, KEY_SUBTITLE }, /* SUBTITLE */
{ 0x000e, KEY_STOP }, /* STOP */
{ 0x0010, KEY_OK }, /* RETURN */
- { 0x0011, KEY_2 },
- { 0x0012, KEY_4 },
- { 0x0015, KEY_3 },
- { 0x0016, KEY_5 },
+ { 0x0011, KEY_NUMERIC_2 },
+ { 0x0012, KEY_NUMERIC_4 },
+ { 0x0015, KEY_NUMERIC_3 },
+ { 0x0016, KEY_NUMERIC_5 },
{ 0x0017, KEY_CHANNELDOWN }, /* Ch Dn */
{ 0x0019, KEY_CHANNELUP }, /* CH Up */
{ 0x001a, KEY_PAUSE }, /* PAUSE */
- { 0x001b, KEY_1 },
+ { 0x001b, KEY_NUMERIC_1 },
{ 0x001d, KEY_AUDIO }, /* DUAL SOUND */
{ 0x001e, KEY_PLAY }, /* PLAY */
{ 0x001f, KEY_CAMERA }, /* SNAPSHOT */
{ 0x0040, KEY_VOLUMEUP }, /* Vol Up */
- { 0x0048, KEY_7 },
- { 0x004c, KEY_6 },
+ { 0x0048, KEY_NUMERIC_7 },
+ { 0x004c, KEY_NUMERIC_6 },
{ 0x004d, KEY_PLAYPAUSE }, /* TIMESHIFT */
- { 0x0054, KEY_0 },
+ { 0x0054, KEY_NUMERIC_0 },
};
static struct rc_map_list digittrade_map = {
diff --git a/drivers/media/rc/keymaps/rc-dm1105-nec.c b/drivers/media/rc/keymaps/rc-dm1105-nec.c
index d853cd9a0936..cd0b985c994d 100644
--- a/drivers/media/rc/keymaps/rc-dm1105-nec.c
+++ b/drivers/media/rc/keymaps/rc-dm1105-nec.c
@@ -15,16 +15,16 @@
static struct rc_map_table dm1105_nec[] = {
{ 0x0a, KEY_POWER2}, /* power */
{ 0x0c, KEY_MUTE}, /* mute */
- { 0x11, KEY_1},
- { 0x12, KEY_2},
- { 0x13, KEY_3},
- { 0x14, KEY_4},
- { 0x15, KEY_5},
- { 0x16, KEY_6},
- { 0x17, KEY_7},
- { 0x18, KEY_8},
- { 0x19, KEY_9},
- { 0x10, KEY_0},
+ { 0x11, KEY_NUMERIC_1},
+ { 0x12, KEY_NUMERIC_2},
+ { 0x13, KEY_NUMERIC_3},
+ { 0x14, KEY_NUMERIC_4},
+ { 0x15, KEY_NUMERIC_5},
+ { 0x16, KEY_NUMERIC_6},
+ { 0x17, KEY_NUMERIC_7},
+ { 0x18, KEY_NUMERIC_8},
+ { 0x19, KEY_NUMERIC_9},
+ { 0x10, KEY_NUMERIC_0},
{ 0x1c, KEY_CHANNELUP}, /* ch+ */
{ 0x0f, KEY_CHANNELDOWN}, /* ch- */
{ 0x1a, KEY_VOLUMEUP}, /* vol+ */
diff --git a/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c b/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c
index cdc1d8c990cb..a82f64dc9411 100644
--- a/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c
+++ b/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c
@@ -13,16 +13,16 @@
static struct rc_map_table dntv_live_dvb_t[] = {
{ 0x00, KEY_ESC }, /* 'go up a level?' */
/* Keys 0 to 9 */
- { 0x0a, KEY_0 },
- { 0x01, KEY_1 },
- { 0x02, KEY_2 },
- { 0x03, KEY_3 },
- { 0x04, KEY_4 },
- { 0x05, KEY_5 },
- { 0x06, KEY_6 },
- { 0x07, KEY_7 },
- { 0x08, KEY_8 },
- { 0x09, KEY_9 },
+ { 0x0a, KEY_NUMERIC_0 },
+ { 0x01, KEY_NUMERIC_1 },
+ { 0x02, KEY_NUMERIC_2 },
+ { 0x03, KEY_NUMERIC_3 },
+ { 0x04, KEY_NUMERIC_4 },
+ { 0x05, KEY_NUMERIC_5 },
+ { 0x06, KEY_NUMERIC_6 },
+ { 0x07, KEY_NUMERIC_7 },
+ { 0x08, KEY_NUMERIC_8 },
+ { 0x09, KEY_NUMERIC_9 },
{ 0x0b, KEY_TUNER }, /* tv/fm */
{ 0x0c, KEY_SEARCH }, /* scan */
diff --git a/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c b/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c
index 38e1d1b837da..d3f5048a0220 100644
--- a/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c
+++ b/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c
@@ -18,17 +18,17 @@ static struct rc_map_table dntv_live_dvbt_pro[] = {
{ 0x58, KEY_TUNER }, /* digital Radio */
{ 0x5a, KEY_RADIO }, /* FM radio */
{ 0x59, KEY_DVD }, /* dvd menu */
- { 0x03, KEY_1 },
- { 0x01, KEY_2 },
- { 0x06, KEY_3 },
- { 0x09, KEY_4 },
- { 0x1d, KEY_5 },
- { 0x1f, KEY_6 },
- { 0x0d, KEY_7 },
- { 0x19, KEY_8 },
- { 0x1b, KEY_9 },
+ { 0x03, KEY_NUMERIC_1 },
+ { 0x01, KEY_NUMERIC_2 },
+ { 0x06, KEY_NUMERIC_3 },
+ { 0x09, KEY_NUMERIC_4 },
+ { 0x1d, KEY_NUMERIC_5 },
+ { 0x1f, KEY_NUMERIC_6 },
+ { 0x0d, KEY_NUMERIC_7 },
+ { 0x19, KEY_NUMERIC_8 },
+ { 0x1b, KEY_NUMERIC_9 },
{ 0x0c, KEY_CANCEL },
- { 0x15, KEY_0 },
+ { 0x15, KEY_NUMERIC_0 },
{ 0x4a, KEY_CLEAR },
{ 0x13, KEY_BACK },
{ 0x00, KEY_TAB },
diff --git a/drivers/media/rc/keymaps/rc-dtt200u.c b/drivers/media/rc/keymaps/rc-dtt200u.c
index 86fd6a1668af..e7f87baa3212 100644
--- a/drivers/media/rc/keymaps/rc-dtt200u.c
+++ b/drivers/media/rc/keymaps/rc-dtt200u.c
@@ -12,21 +12,21 @@ static struct rc_map_table dtt200u_table[] = {
{ 0x8001, KEY_MUTE },
{ 0x8002, KEY_CHANNELDOWN },
{ 0x8003, KEY_VOLUMEDOWN },
- { 0x8004, KEY_1 },
- { 0x8005, KEY_2 },
- { 0x8006, KEY_3 },
- { 0x8007, KEY_4 },
- { 0x8008, KEY_5 },
- { 0x8009, KEY_6 },
- { 0x800a, KEY_7 },
+ { 0x8004, KEY_NUMERIC_1 },
+ { 0x8005, KEY_NUMERIC_2 },
+ { 0x8006, KEY_NUMERIC_3 },
+ { 0x8007, KEY_NUMERIC_4 },
+ { 0x8008, KEY_NUMERIC_5 },
+ { 0x8009, KEY_NUMERIC_6 },
+ { 0x800a, KEY_NUMERIC_7 },
{ 0x800c, KEY_ZOOM },
- { 0x800d, KEY_0 },
+ { 0x800d, KEY_NUMERIC_0 },
{ 0x800e, KEY_SELECT },
{ 0x8012, KEY_POWER },
{ 0x801a, KEY_CHANNELUP },
- { 0x801b, KEY_8 },
+ { 0x801b, KEY_NUMERIC_8 },
{ 0x801e, KEY_VOLUMEUP },
- { 0x801f, KEY_9 },
+ { 0x801f, KEY_NUMERIC_9 },
};
static struct rc_map_list dtt200u_map = {
diff --git a/drivers/media/rc/keymaps/rc-dvbsky.c b/drivers/media/rc/keymaps/rc-dvbsky.c
index 4b61f60a4854..f5063af2e5bc 100644
--- a/drivers/media/rc/keymaps/rc-dvbsky.c
+++ b/drivers/media/rc/keymaps/rc-dvbsky.c
@@ -13,16 +13,16 @@
*/
static struct rc_map_table rc5_dvbsky[] = {
- { 0x0000, KEY_0 },
- { 0x0001, KEY_1 },
- { 0x0002, KEY_2 },
- { 0x0003, KEY_3 },
- { 0x0004, KEY_4 },
- { 0x0005, KEY_5 },
- { 0x0006, KEY_6 },
- { 0x0007, KEY_7 },
- { 0x0008, KEY_8 },
- { 0x0009, KEY_9 },
+ { 0x0000, KEY_NUMERIC_0 },
+ { 0x0001, KEY_NUMERIC_1 },
+ { 0x0002, KEY_NUMERIC_2 },
+ { 0x0003, KEY_NUMERIC_3 },
+ { 0x0004, KEY_NUMERIC_4 },
+ { 0x0005, KEY_NUMERIC_5 },
+ { 0x0006, KEY_NUMERIC_6 },
+ { 0x0007, KEY_NUMERIC_7 },
+ { 0x0008, KEY_NUMERIC_8 },
+ { 0x0009, KEY_NUMERIC_9 },
{ 0x000a, KEY_MUTE },
{ 0x000d, KEY_OK },
{ 0x000b, KEY_STOP },
diff --git a/drivers/media/rc/keymaps/rc-dvico-mce.c b/drivers/media/rc/keymaps/rc-dvico-mce.c
index 8342c32f58fd..b1bb8cdb3705 100644
--- a/drivers/media/rc/keymaps/rc-dvico-mce.c
+++ b/drivers/media/rc/keymaps/rc-dvico-mce.c
@@ -35,17 +35,17 @@ static struct rc_map_table rc_map_dvico_mce_table[] = {
{ 0x0152, KEY_CAMERA },
{ 0x015a, KEY_TUNER }, /* Live */
{ 0x0119, KEY_OPEN },
- { 0x010b, KEY_1 },
- { 0x0117, KEY_2 },
- { 0x011b, KEY_3 },
- { 0x0107, KEY_4 },
- { 0x0150, KEY_5 },
- { 0x0154, KEY_6 },
- { 0x0148, KEY_7 },
- { 0x014c, KEY_8 },
- { 0x0158, KEY_9 },
+ { 0x010b, KEY_NUMERIC_1 },
+ { 0x0117, KEY_NUMERIC_2 },
+ { 0x011b, KEY_NUMERIC_3 },
+ { 0x0107, KEY_NUMERIC_4 },
+ { 0x0150, KEY_NUMERIC_5 },
+ { 0x0154, KEY_NUMERIC_6 },
+ { 0x0148, KEY_NUMERIC_7 },
+ { 0x014c, KEY_NUMERIC_8 },
+ { 0x0158, KEY_NUMERIC_9 },
{ 0x0113, KEY_ANGLE }, /* Aspect */
- { 0x0103, KEY_0 },
+ { 0x0103, KEY_NUMERIC_0 },
{ 0x011f, KEY_ZOOM },
{ 0x0143, KEY_REWIND },
{ 0x0147, KEY_PLAYPAUSE },
diff --git a/drivers/media/rc/keymaps/rc-dvico-portable.c b/drivers/media/rc/keymaps/rc-dvico-portable.c
index 366bd10bf987..ec12ba6995dc 100644
--- a/drivers/media/rc/keymaps/rc-dvico-portable.c
+++ b/drivers/media/rc/keymaps/rc-dvico-portable.c
@@ -24,17 +24,17 @@ static struct rc_map_table rc_map_dvico_portable_table[] = {
{ 0x0316, KEY_CAMERA },
{ 0x0340, KEY_TUNER }, /* ATV/DTV */
{ 0x0345, KEY_OPEN },
- { 0x0319, KEY_1 },
- { 0x0318, KEY_2 },
- { 0x031b, KEY_3 },
- { 0x031a, KEY_4 },
- { 0x0358, KEY_5 },
- { 0x0359, KEY_6 },
- { 0x0315, KEY_7 },
- { 0x0314, KEY_8 },
- { 0x0317, KEY_9 },
+ { 0x0319, KEY_NUMERIC_1 },
+ { 0x0318, KEY_NUMERIC_2 },
+ { 0x031b, KEY_NUMERIC_3 },
+ { 0x031a, KEY_NUMERIC_4 },
+ { 0x0358, KEY_NUMERIC_5 },
+ { 0x0359, KEY_NUMERIC_6 },
+ { 0x0315, KEY_NUMERIC_7 },
+ { 0x0314, KEY_NUMERIC_8 },
+ { 0x0317, KEY_NUMERIC_9 },
{ 0x0344, KEY_ANGLE }, /* Aspect */
- { 0x0355, KEY_0 },
+ { 0x0355, KEY_NUMERIC_0 },
{ 0x0307, KEY_ZOOM },
{ 0x030a, KEY_REWIND },
{ 0x0308, KEY_PLAYPAUSE },
diff --git a/drivers/media/rc/keymaps/rc-em-terratec.c b/drivers/media/rc/keymaps/rc-em-terratec.c
index cbbba21484fb..a1f59aa6ff23 100644
--- a/drivers/media/rc/keymaps/rc-em-terratec.c
+++ b/drivers/media/rc/keymaps/rc-em-terratec.c
@@ -13,19 +13,19 @@ static struct rc_map_table em_terratec[] = {
{ 0x02, KEY_SELECT },
{ 0x03, KEY_MUTE },
{ 0x04, KEY_POWER },
- { 0x05, KEY_1 },
- { 0x06, KEY_2 },
- { 0x07, KEY_3 },
+ { 0x05, KEY_NUMERIC_1 },
+ { 0x06, KEY_NUMERIC_2 },
+ { 0x07, KEY_NUMERIC_3 },
{ 0x08, KEY_CHANNELUP },
- { 0x09, KEY_4 },
- { 0x0a, KEY_5 },
- { 0x0b, KEY_6 },
+ { 0x09, KEY_NUMERIC_4 },
+ { 0x0a, KEY_NUMERIC_5 },
+ { 0x0b, KEY_NUMERIC_6 },
{ 0x0c, KEY_CHANNELDOWN },
- { 0x0d, KEY_7 },
- { 0x0e, KEY_8 },
- { 0x0f, KEY_9 },
+ { 0x0d, KEY_NUMERIC_7 },
+ { 0x0e, KEY_NUMERIC_8 },
+ { 0x0f, KEY_NUMERIC_9 },
{ 0x10, KEY_VOLUMEUP },
- { 0x11, KEY_0 },
+ { 0x11, KEY_NUMERIC_0 },
{ 0x12, KEY_MENU },
{ 0x13, KEY_PRINT },
{ 0x14, KEY_VOLUMEDOWN },
diff --git a/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c b/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c
index 057c13b765ef..7a00471b6005 100644
--- a/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c
+++ b/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c
@@ -16,16 +16,16 @@ static struct rc_map_table encore_enltv_fm53[] = {
{ 0x10, KEY_POWER2},
{ 0x06, KEY_MUTE},
- { 0x09, KEY_1},
- { 0x1d, KEY_2},
- { 0x1f, KEY_3},
- { 0x19, KEY_4},
- { 0x1b, KEY_5},
- { 0x11, KEY_6},
- { 0x17, KEY_7},
- { 0x12, KEY_8},
- { 0x16, KEY_9},
- { 0x48, KEY_0},
+ { 0x09, KEY_NUMERIC_1},
+ { 0x1d, KEY_NUMERIC_2},
+ { 0x1f, KEY_NUMERIC_3},
+ { 0x19, KEY_NUMERIC_4},
+ { 0x1b, KEY_NUMERIC_5},
+ { 0x11, KEY_NUMERIC_6},
+ { 0x17, KEY_NUMERIC_7},
+ { 0x12, KEY_NUMERIC_8},
+ { 0x16, KEY_NUMERIC_9},
+ { 0x48, KEY_NUMERIC_0},
{ 0x04, KEY_LIST}, /* -/-- */
{ 0x40, KEY_LAST}, /* recall */
diff --git a/drivers/media/rc/keymaps/rc-encore-enltv.c b/drivers/media/rc/keymaps/rc-encore-enltv.c
index 5b4e832d5fac..712210097b4d 100644
--- a/drivers/media/rc/keymaps/rc-encore-enltv.c
+++ b/drivers/media/rc/keymaps/rc-encore-enltv.c
@@ -22,16 +22,16 @@ static struct rc_map_table encore_enltv[] = {
{ 0x01, KEY_AUDIO }, /* music */
{ 0x02, KEY_CAMERA }, /* picture */
- { 0x1f, KEY_1 },
- { 0x03, KEY_2 },
- { 0x04, KEY_3 },
- { 0x05, KEY_4 },
- { 0x1c, KEY_5 },
- { 0x06, KEY_6 },
- { 0x07, KEY_7 },
- { 0x08, KEY_8 },
- { 0x1d, KEY_9 },
- { 0x0a, KEY_0 },
+ { 0x1f, KEY_NUMERIC_1 },
+ { 0x03, KEY_NUMERIC_2 },
+ { 0x04, KEY_NUMERIC_3 },
+ { 0x05, KEY_NUMERIC_4 },
+ { 0x1c, KEY_NUMERIC_5 },
+ { 0x06, KEY_NUMERIC_6 },
+ { 0x07, KEY_NUMERIC_7 },
+ { 0x08, KEY_NUMERIC_8 },
+ { 0x1d, KEY_NUMERIC_9 },
+ { 0x0a, KEY_NUMERIC_0 },
{ 0x09, KEY_LIST }, /* -/-- */
{ 0x0b, KEY_LAST }, /* recall */
diff --git a/drivers/media/rc/keymaps/rc-encore-enltv2.c b/drivers/media/rc/keymaps/rc-encore-enltv2.c
index cd0555924456..a08470b4f187 100644
--- a/drivers/media/rc/keymaps/rc-encore-enltv2.c
+++ b/drivers/media/rc/keymaps/rc-encore-enltv2.c
@@ -14,16 +14,16 @@
static struct rc_map_table encore_enltv2[] = {
{ 0x4c, KEY_POWER2 },
{ 0x4a, KEY_TUNER },
- { 0x40, KEY_1 },
- { 0x60, KEY_2 },
- { 0x50, KEY_3 },
- { 0x70, KEY_4 },
- { 0x48, KEY_5 },
- { 0x68, KEY_6 },
- { 0x58, KEY_7 },
- { 0x78, KEY_8 },
- { 0x44, KEY_9 },
- { 0x54, KEY_0 },
+ { 0x40, KEY_NUMERIC_1 },
+ { 0x60, KEY_NUMERIC_2 },
+ { 0x50, KEY_NUMERIC_3 },
+ { 0x70, KEY_NUMERIC_4 },
+ { 0x48, KEY_NUMERIC_5 },
+ { 0x68, KEY_NUMERIC_6 },
+ { 0x58, KEY_NUMERIC_7 },
+ { 0x78, KEY_NUMERIC_8 },
+ { 0x44, KEY_NUMERIC_9 },
+ { 0x54, KEY_NUMERIC_0 },
{ 0x64, KEY_LAST }, /* +100 */
{ 0x4e, KEY_AGAIN }, /* Recall */
diff --git a/drivers/media/rc/keymaps/rc-eztv.c b/drivers/media/rc/keymaps/rc-eztv.c
index 0e481d51fcb5..4e494d953e33 100644
--- a/drivers/media/rc/keymaps/rc-eztv.c
+++ b/drivers/media/rc/keymaps/rc-eztv.c
@@ -46,16 +46,16 @@ static struct rc_map_table eztv[] = {
{ 0x2d, KEY_PLAY }, /* play */
{ 0x2e, KEY_CAMERA }, /* snapshot / shuffle */
- { 0x00, KEY_0 },
- { 0x05, KEY_1 },
- { 0x06, KEY_2 },
- { 0x07, KEY_3 },
- { 0x09, KEY_4 },
- { 0x0a, KEY_5 },
- { 0x0b, KEY_6 },
- { 0x0d, KEY_7 },
- { 0x0e, KEY_8 },
- { 0x0f, KEY_9 },
+ { 0x00, KEY_NUMERIC_0 },
+ { 0x05, KEY_NUMERIC_1 },
+ { 0x06, KEY_NUMERIC_2 },
+ { 0x07, KEY_NUMERIC_3 },
+ { 0x09, KEY_NUMERIC_4 },
+ { 0x0a, KEY_NUMERIC_5 },
+ { 0x0b, KEY_NUMERIC_6 },
+ { 0x0d, KEY_NUMERIC_7 },
+ { 0x0e, KEY_NUMERIC_8 },
+ { 0x0f, KEY_NUMERIC_9 },
{ 0x2a, KEY_VOLUMEUP },
{ 0x11, KEY_VOLUMEDOWN },
diff --git a/drivers/media/rc/keymaps/rc-flydvb.c b/drivers/media/rc/keymaps/rc-flydvb.c
index 45940d7c92d0..202a1fbd1935 100644
--- a/drivers/media/rc/keymaps/rc-flydvb.c
+++ b/drivers/media/rc/keymaps/rc-flydvb.c
@@ -12,17 +12,17 @@ static struct rc_map_table flydvb[] = {
{ 0x01, KEY_ZOOM }, /* Full Screen */
{ 0x00, KEY_POWER }, /* Power */
- { 0x03, KEY_1 },
- { 0x04, KEY_2 },
- { 0x05, KEY_3 },
- { 0x07, KEY_4 },
- { 0x08, KEY_5 },
- { 0x09, KEY_6 },
- { 0x0b, KEY_7 },
- { 0x0c, KEY_8 },
- { 0x0d, KEY_9 },
+ { 0x03, KEY_NUMERIC_1 },
+ { 0x04, KEY_NUMERIC_2 },
+ { 0x05, KEY_NUMERIC_3 },
+ { 0x07, KEY_NUMERIC_4 },
+ { 0x08, KEY_NUMERIC_5 },
+ { 0x09, KEY_NUMERIC_6 },
+ { 0x0b, KEY_NUMERIC_7 },
+ { 0x0c, KEY_NUMERIC_8 },
+ { 0x0d, KEY_NUMERIC_9 },
{ 0x06, KEY_AGAIN }, /* Recall */
- { 0x0f, KEY_0 },
+ { 0x0f, KEY_NUMERIC_0 },
{ 0x10, KEY_MUTE }, /* Mute */
{ 0x02, KEY_RADIO }, /* TV/Radio */
{ 0x1b, KEY_LANGUAGE }, /* SAP (Second Audio Program) */
diff --git a/drivers/media/rc/keymaps/rc-flyvideo.c b/drivers/media/rc/keymaps/rc-flyvideo.c
index b2d4e4c7b192..a44467fb15cb 100644
--- a/drivers/media/rc/keymaps/rc-flyvideo.c
+++ b/drivers/media/rc/keymaps/rc-flyvideo.c
@@ -9,16 +9,16 @@
#include <linux/module.h>
static struct rc_map_table flyvideo[] = {
- { 0x0f, KEY_0 },
- { 0x03, KEY_1 },
- { 0x04, KEY_2 },
- { 0x05, KEY_3 },
- { 0x07, KEY_4 },
- { 0x08, KEY_5 },
- { 0x09, KEY_6 },
- { 0x0b, KEY_7 },
- { 0x0c, KEY_8 },
- { 0x0d, KEY_9 },
+ { 0x0f, KEY_NUMERIC_0 },
+ { 0x03, KEY_NUMERIC_1 },
+ { 0x04, KEY_NUMERIC_2 },
+ { 0x05, KEY_NUMERIC_3 },
+ { 0x07, KEY_NUMERIC_4 },
+ { 0x08, KEY_NUMERIC_5 },
+ { 0x09, KEY_NUMERIC_6 },
+ { 0x0b, KEY_NUMERIC_7 },
+ { 0x0c, KEY_NUMERIC_8 },
+ { 0x0d, KEY_NUMERIC_9 },
{ 0x0e, KEY_MODE }, /* Air/Cable */
{ 0x11, KEY_VIDEO }, /* Video */
diff --git a/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c b/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c
index 1c63fc7d4576..253199f5531a 100644
--- a/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c
+++ b/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c
@@ -12,16 +12,16 @@
static struct rc_map_table fusionhdtv_mce[] = {
- { 0x0b, KEY_1 },
- { 0x17, KEY_2 },
- { 0x1b, KEY_3 },
- { 0x07, KEY_4 },
- { 0x50, KEY_5 },
- { 0x54, KEY_6 },
- { 0x48, KEY_7 },
- { 0x4c, KEY_8 },
- { 0x58, KEY_9 },
- { 0x03, KEY_0 },
+ { 0x0b, KEY_NUMERIC_1 },
+ { 0x17, KEY_NUMERIC_2 },
+ { 0x1b, KEY_NUMERIC_3 },
+ { 0x07, KEY_NUMERIC_4 },
+ { 0x50, KEY_NUMERIC_5 },
+ { 0x54, KEY_NUMERIC_6 },
+ { 0x48, KEY_NUMERIC_7 },
+ { 0x4c, KEY_NUMERIC_8 },
+ { 0x58, KEY_NUMERIC_9 },
+ { 0x03, KEY_NUMERIC_0 },
{ 0x5e, KEY_OK },
{ 0x51, KEY_UP },
diff --git a/drivers/media/rc/keymaps/rc-gadmei-rm008z.c b/drivers/media/rc/keymaps/rc-gadmei-rm008z.c
index 4a0a9786914f..c630ef306f11 100644
--- a/drivers/media/rc/keymaps/rc-gadmei-rm008z.c
+++ b/drivers/media/rc/keymaps/rc-gadmei-rm008z.c
@@ -21,16 +21,16 @@ static struct rc_map_table gadmei_rm008z[] = {
{ 0x0b, KEY_AUDIO}, /* SV */
{ 0x0f, KEY_RADIO}, /* FM */
- { 0x00, KEY_1},
- { 0x01, KEY_2},
- { 0x02, KEY_3},
- { 0x03, KEY_4},
- { 0x04, KEY_5},
- { 0x05, KEY_6},
- { 0x06, KEY_7},
- { 0x07, KEY_8},
- { 0x08, KEY_9},
- { 0x09, KEY_0},
+ { 0x00, KEY_NUMERIC_1},
+ { 0x01, KEY_NUMERIC_2},
+ { 0x02, KEY_NUMERIC_3},
+ { 0x03, KEY_NUMERIC_4},
+ { 0x04, KEY_NUMERIC_5},
+ { 0x05, KEY_NUMERIC_6},
+ { 0x06, KEY_NUMERIC_7},
+ { 0x07, KEY_NUMERIC_8},
+ { 0x08, KEY_NUMERIC_9},
+ { 0x09, KEY_NUMERIC_0},
{ 0x0a, KEY_INFO}, /* OSD */
{ 0x1c, KEY_BACKSPACE}, /* LAST */
diff --git a/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c b/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c
index cc876a85cc31..c966c130b05d 100644
--- a/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c
+++ b/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c
@@ -15,16 +15,16 @@
static struct rc_map_table genius_tvgo_a11mce[] = {
/* Keys 0 to 9 */
- { 0x48, KEY_0 },
- { 0x09, KEY_1 },
- { 0x1d, KEY_2 },
- { 0x1f, KEY_3 },
- { 0x19, KEY_4 },
- { 0x1b, KEY_5 },
- { 0x11, KEY_6 },
- { 0x17, KEY_7 },
- { 0x12, KEY_8 },
- { 0x16, KEY_9 },
+ { 0x48, KEY_NUMERIC_0 },
+ { 0x09, KEY_NUMERIC_1 },
+ { 0x1d, KEY_NUMERIC_2 },
+ { 0x1f, KEY_NUMERIC_3 },
+ { 0x19, KEY_NUMERIC_4 },
+ { 0x1b, KEY_NUMERIC_5 },
+ { 0x11, KEY_NUMERIC_6 },
+ { 0x17, KEY_NUMERIC_7 },
+ { 0x12, KEY_NUMERIC_8 },
+ { 0x16, KEY_NUMERIC_9 },
{ 0x54, KEY_RECORD }, /* recording */
{ 0x06, KEY_MUTE }, /* mute */
diff --git a/drivers/media/rc/keymaps/rc-gotview7135.c b/drivers/media/rc/keymaps/rc-gotview7135.c
index 6b94bd39d977..0dc4ef36d76f 100644
--- a/drivers/media/rc/keymaps/rc-gotview7135.c
+++ b/drivers/media/rc/keymaps/rc-gotview7135.c
@@ -14,16 +14,16 @@ static struct rc_map_table gotview7135[] = {
{ 0x11, KEY_POWER },
{ 0x35, KEY_TV },
- { 0x1b, KEY_0 },
- { 0x29, KEY_1 },
- { 0x19, KEY_2 },
- { 0x39, KEY_3 },
- { 0x1f, KEY_4 },
- { 0x2c, KEY_5 },
- { 0x21, KEY_6 },
- { 0x24, KEY_7 },
- { 0x18, KEY_8 },
- { 0x2b, KEY_9 },
+ { 0x1b, KEY_NUMERIC_0 },
+ { 0x29, KEY_NUMERIC_1 },
+ { 0x19, KEY_NUMERIC_2 },
+ { 0x39, KEY_NUMERIC_3 },
+ { 0x1f, KEY_NUMERIC_4 },
+ { 0x2c, KEY_NUMERIC_5 },
+ { 0x21, KEY_NUMERIC_6 },
+ { 0x24, KEY_NUMERIC_7 },
+ { 0x18, KEY_NUMERIC_8 },
+ { 0x2b, KEY_NUMERIC_9 },
{ 0x3b, KEY_AGAIN }, /* LOOP */
{ 0x06, KEY_AUDIO },
{ 0x31, KEY_PRINT }, /* PREVIEW */
diff --git a/drivers/media/rc/keymaps/rc-hauppauge.c b/drivers/media/rc/keymaps/rc-hauppauge.c
index 582aa9012443..82552360c3c3 100644
--- a/drivers/media/rc/keymaps/rc-hauppauge.c
+++ b/drivers/media/rc/keymaps/rc-hauppauge.c
@@ -67,20 +67,20 @@ static struct rc_map_table rc5_hauppauge_new[] = {
{ 0x1e30, KEY_PAUSE }, /* pause */
{ 0x1e1e, KEY_NEXTSONG }, /* skip >| */
- { 0x1e01, KEY_1 },
- { 0x1e02, KEY_2 },
- { 0x1e03, KEY_3 },
+ { 0x1e01, KEY_NUMERIC_1 },
+ { 0x1e02, KEY_NUMERIC_2 },
+ { 0x1e03, KEY_NUMERIC_3 },
- { 0x1e04, KEY_4 },
- { 0x1e05, KEY_5 },
- { 0x1e06, KEY_6 },
+ { 0x1e04, KEY_NUMERIC_4 },
+ { 0x1e05, KEY_NUMERIC_5 },
+ { 0x1e06, KEY_NUMERIC_6 },
- { 0x1e07, KEY_7 },
- { 0x1e08, KEY_8 },
- { 0x1e09, KEY_9 },
+ { 0x1e07, KEY_NUMERIC_7 },
+ { 0x1e08, KEY_NUMERIC_8 },
+ { 0x1e09, KEY_NUMERIC_9 },
{ 0x1e0a, KEY_TEXT }, /* keypad asterisk as well */
- { 0x1e00, KEY_0 },
+ { 0x1e00, KEY_NUMERIC_0 },
{ 0x1e0e, KEY_SUBTITLE }, /* also the Pound key (#) */
{ 0x1e0b, KEY_RED }, /* red button */
@@ -96,16 +96,16 @@ static struct rc_map_table rc5_hauppauge_new[] = {
{ 0x1f3b, KEY_SELECT }, /* GO */
/* Keys 0 to 9 */
- { 0x1f00, KEY_0 },
- { 0x1f01, KEY_1 },
- { 0x1f02, KEY_2 },
- { 0x1f03, KEY_3 },
- { 0x1f04, KEY_4 },
- { 0x1f05, KEY_5 },
- { 0x1f06, KEY_6 },
- { 0x1f07, KEY_7 },
- { 0x1f08, KEY_8 },
- { 0x1f09, KEY_9 },
+ { 0x1f00, KEY_NUMERIC_0 },
+ { 0x1f01, KEY_NUMERIC_1 },
+ { 0x1f02, KEY_NUMERIC_2 },
+ { 0x1f03, KEY_NUMERIC_3 },
+ { 0x1f04, KEY_NUMERIC_4 },
+ { 0x1f05, KEY_NUMERIC_5 },
+ { 0x1f06, KEY_NUMERIC_6 },
+ { 0x1f07, KEY_NUMERIC_7 },
+ { 0x1f08, KEY_NUMERIC_8 },
+ { 0x1f09, KEY_NUMERIC_9 },
{ 0x1f1f, KEY_EXIT }, /* back/exit */
{ 0x1f0d, KEY_MENU },
@@ -140,16 +140,16 @@ static struct rc_map_table rc5_hauppauge_new[] = {
* Keycodes for DSR-0112 remote bundled with Haupauge MiniStick
* Keycodes start with address = 0x1d
*/
- { 0x1d00, KEY_0 },
- { 0x1d01, KEY_1 },
- { 0x1d02, KEY_2 },
- { 0x1d03, KEY_3 },
- { 0x1d04, KEY_4 },
- { 0x1d05, KEY_5 },
- { 0x1d06, KEY_6 },
- { 0x1d07, KEY_7 },
- { 0x1d08, KEY_8 },
- { 0x1d09, KEY_9 },
+ { 0x1d00, KEY_NUMERIC_0 },
+ { 0x1d01, KEY_NUMERIC_1 },
+ { 0x1d02, KEY_NUMERIC_2 },
+ { 0x1d03, KEY_NUMERIC_3 },
+ { 0x1d04, KEY_NUMERIC_4 },
+ { 0x1d05, KEY_NUMERIC_5 },
+ { 0x1d06, KEY_NUMERIC_6 },
+ { 0x1d07, KEY_NUMERIC_7 },
+ { 0x1d08, KEY_NUMERIC_8 },
+ { 0x1d09, KEY_NUMERIC_9 },
{ 0x1d0a, KEY_TEXT },
{ 0x1d0d, KEY_MENU },
{ 0x1d0f, KEY_MUTE },
@@ -190,16 +190,16 @@ static struct rc_map_table rc5_hauppauge_new[] = {
{ 0x1c17, KEY_RIGHT },
{ 0x1c25, KEY_OK },
- { 0x1c00, KEY_0 },
- { 0x1c01, KEY_1 },
- { 0x1c02, KEY_2 },
- { 0x1c03, KEY_3 },
- { 0x1c04, KEY_4 },
- { 0x1c05, KEY_5 },
- { 0x1c06, KEY_6 },
- { 0x1c07, KEY_7 },
- { 0x1c08, KEY_8 },
- { 0x1c09, KEY_9 },
+ { 0x1c00, KEY_NUMERIC_0 },
+ { 0x1c01, KEY_NUMERIC_1 },
+ { 0x1c02, KEY_NUMERIC_2 },
+ { 0x1c03, KEY_NUMERIC_3 },
+ { 0x1c04, KEY_NUMERIC_4 },
+ { 0x1c05, KEY_NUMERIC_5 },
+ { 0x1c06, KEY_NUMERIC_6 },
+ { 0x1c07, KEY_NUMERIC_7 },
+ { 0x1c08, KEY_NUMERIC_8 },
+ { 0x1c09, KEY_NUMERIC_9 },
{ 0x1c1f, KEY_EXIT }, /* BACK */
{ 0x1c0d, KEY_MENU },
@@ -233,6 +233,7 @@ static struct rc_map_table rc5_hauppauge_new[] = {
* This one also uses RC-5 protocol
* Keycodes start with address = 0x00
*/
+ { 0x000f, KEY_TV },
{ 0x001f, KEY_TV },
{ 0x0020, KEY_CHANNELUP },
{ 0x000c, KEY_RADIO },
@@ -245,20 +246,20 @@ static struct rc_map_table rc5_hauppauge_new[] = {
{ 0x0021, KEY_CHANNELDOWN },
{ 0x0022, KEY_VIDEO }, /* source */
- { 0x0001, KEY_1 },
- { 0x0002, KEY_2 },
- { 0x0003, KEY_3 },
+ { 0x0001, KEY_NUMERIC_1 },
+ { 0x0002, KEY_NUMERIC_2 },
+ { 0x0003, KEY_NUMERIC_3 },
- { 0x0004, KEY_4 },
- { 0x0005, KEY_5 },
- { 0x0006, KEY_6 },
+ { 0x0004, KEY_NUMERIC_4 },
+ { 0x0005, KEY_NUMERIC_5 },
+ { 0x0006, KEY_NUMERIC_6 },
- { 0x0007, KEY_7 },
- { 0x0008, KEY_8 },
- { 0x0009, KEY_9 },
+ { 0x0007, KEY_NUMERIC_7 },
+ { 0x0008, KEY_NUMERIC_8 },
+ { 0x0009, KEY_NUMERIC_9 },
{ 0x001e, KEY_RED }, /* Reserved */
- { 0x0000, KEY_0 },
+ { 0x0000, KEY_NUMERIC_0 },
{ 0x0026, KEY_SLEEP }, /* Minimize */
};
diff --git a/drivers/media/rc/keymaps/rc-hisi-poplar.c b/drivers/media/rc/keymaps/rc-hisi-poplar.c
index b4dbec6e70ce..49a18e916915 100644
--- a/drivers/media/rc/keymaps/rc-hisi-poplar.c
+++ b/drivers/media/rc/keymaps/rc-hisi-poplar.c
@@ -9,16 +9,16 @@
#include <media/rc-map.h>
static struct rc_map_table hisi_poplar_keymap[] = {
- { 0x0000b292, KEY_1},
- { 0x0000b293, KEY_2},
- { 0x0000b2cc, KEY_3},
- { 0x0000b28e, KEY_4},
- { 0x0000b28f, KEY_5},
- { 0x0000b2c8, KEY_6},
- { 0x0000b28a, KEY_7},
- { 0x0000b28b, KEY_8},
- { 0x0000b2c4, KEY_9},
- { 0x0000b287, KEY_0},
+ { 0x0000b292, KEY_NUMERIC_1},
+ { 0x0000b293, KEY_NUMERIC_2},
+ { 0x0000b2cc, KEY_NUMERIC_3},
+ { 0x0000b28e, KEY_NUMERIC_4},
+ { 0x0000b28f, KEY_NUMERIC_5},
+ { 0x0000b2c8, KEY_NUMERIC_6},
+ { 0x0000b28a, KEY_NUMERIC_7},
+ { 0x0000b28b, KEY_NUMERIC_8},
+ { 0x0000b2c4, KEY_NUMERIC_9},
+ { 0x0000b287, KEY_NUMERIC_0},
{ 0x0000b282, KEY_HOMEPAGE},
{ 0x0000b2ca, KEY_UP},
{ 0x0000b299, KEY_LEFT},
diff --git a/drivers/media/rc/keymaps/rc-hisi-tv-demo.c b/drivers/media/rc/keymaps/rc-hisi-tv-demo.c
index 8e25b40714f8..c73068b653f7 100644
--- a/drivers/media/rc/keymaps/rc-hisi-tv-demo.c
+++ b/drivers/media/rc/keymaps/rc-hisi-tv-demo.c
@@ -9,16 +9,16 @@
#include <media/rc-map.h>
static struct rc_map_table hisi_tv_demo_keymap[] = {
- { 0x00000092, KEY_1},
- { 0x00000093, KEY_2},
- { 0x000000cc, KEY_3},
- { 0x0000009f, KEY_4},
- { 0x0000008e, KEY_5},
- { 0x0000008f, KEY_6},
- { 0x000000c8, KEY_7},
- { 0x00000094, KEY_8},
- { 0x0000008a, KEY_9},
- { 0x0000008b, KEY_0},
+ { 0x00000092, KEY_NUMERIC_1},
+ { 0x00000093, KEY_NUMERIC_2},
+ { 0x000000cc, KEY_NUMERIC_3},
+ { 0x0000009f, KEY_NUMERIC_4},
+ { 0x0000008e, KEY_NUMERIC_5},
+ { 0x0000008f, KEY_NUMERIC_6},
+ { 0x000000c8, KEY_NUMERIC_7},
+ { 0x00000094, KEY_NUMERIC_8},
+ { 0x0000008a, KEY_NUMERIC_9},
+ { 0x0000008b, KEY_NUMERIC_0},
{ 0x000000ce, KEY_ENTER},
{ 0x000000ca, KEY_UP},
{ 0x00000099, KEY_LEFT},
diff --git a/drivers/media/rc/keymaps/rc-iodata-bctv7e.c b/drivers/media/rc/keymaps/rc-iodata-bctv7e.c
index 6ced43458f2a..9cc6ea0f4226 100644
--- a/drivers/media/rc/keymaps/rc-iodata-bctv7e.c
+++ b/drivers/media/rc/keymaps/rc-iodata-bctv7e.c
@@ -17,16 +17,16 @@ static struct rc_map_table iodata_bctv7e[] = {
{ 0x00, KEY_POWER },
/* Keys 0 to 9 */
- { 0x44, KEY_0 }, /* 10 */
- { 0x50, KEY_1 },
- { 0x30, KEY_2 },
- { 0x70, KEY_3 },
- { 0x48, KEY_4 },
- { 0x28, KEY_5 },
- { 0x68, KEY_6 },
- { 0x58, KEY_7 },
- { 0x38, KEY_8 },
- { 0x78, KEY_9 },
+ { 0x44, KEY_NUMERIC_0 }, /* 10 */
+ { 0x50, KEY_NUMERIC_1 },
+ { 0x30, KEY_NUMERIC_2 },
+ { 0x70, KEY_NUMERIC_3 },
+ { 0x48, KEY_NUMERIC_4 },
+ { 0x28, KEY_NUMERIC_5 },
+ { 0x68, KEY_NUMERIC_6 },
+ { 0x58, KEY_NUMERIC_7 },
+ { 0x38, KEY_NUMERIC_8 },
+ { 0x78, KEY_NUMERIC_9 },
{ 0x10, KEY_L }, /* Live */
{ 0x08, KEY_TIME }, /* Time Shift */
diff --git a/drivers/media/rc/keymaps/rc-it913x-v1.c b/drivers/media/rc/keymaps/rc-it913x-v1.c
index d8eaba9834c2..1e049f26a246 100644
--- a/drivers/media/rc/keymaps/rc-it913x-v1.c
+++ b/drivers/media/rc/keymaps/rc-it913x-v1.c
@@ -11,22 +11,22 @@
static struct rc_map_table it913x_v1_rc[] = {
/* Type 1 */
{ 0x61d601, KEY_VIDEO }, /* Source */
- { 0x61d602, KEY_3 },
+ { 0x61d602, KEY_NUMERIC_3 },
{ 0x61d603, KEY_POWER }, /* ShutDown */
- { 0x61d604, KEY_1 },
- { 0x61d605, KEY_5 },
- { 0x61d606, KEY_6 },
+ { 0x61d604, KEY_NUMERIC_1 },
+ { 0x61d605, KEY_NUMERIC_5 },
+ { 0x61d606, KEY_NUMERIC_6 },
{ 0x61d607, KEY_CHANNELDOWN }, /* CH- */
- { 0x61d608, KEY_2 },
+ { 0x61d608, KEY_NUMERIC_2 },
{ 0x61d609, KEY_CHANNELUP }, /* CH+ */
- { 0x61d60a, KEY_9 },
+ { 0x61d60a, KEY_NUMERIC_9 },
{ 0x61d60b, KEY_ZOOM }, /* Zoom */
- { 0x61d60c, KEY_7 },
- { 0x61d60d, KEY_8 },
+ { 0x61d60c, KEY_NUMERIC_7 },
+ { 0x61d60d, KEY_NUMERIC_8 },
{ 0x61d60e, KEY_VOLUMEUP }, /* Vol+ */
- { 0x61d60f, KEY_4 },
+ { 0x61d60f, KEY_NUMERIC_4 },
{ 0x61d610, KEY_ESC }, /* [back up arrow] */
- { 0x61d611, KEY_0 },
+ { 0x61d611, KEY_NUMERIC_0 },
{ 0x61d612, KEY_OK }, /* [enter arrow] */
{ 0x61d613, KEY_VOLUMEDOWN }, /* Vol- */
{ 0x61d614, KEY_RECORD }, /* Rec */
@@ -43,16 +43,16 @@ static struct rc_map_table it913x_v1_rc[] = {
{ 0x61d61f, KEY_BLUE },
{ 0x61d643, KEY_POWER2 }, /* [red power button] */
/* Type 2 - 20 buttons */
- { 0x807f0d, KEY_0 },
- { 0x807f04, KEY_1 },
- { 0x807f05, KEY_2 },
- { 0x807f06, KEY_3 },
- { 0x807f07, KEY_4 },
- { 0x807f08, KEY_5 },
- { 0x807f09, KEY_6 },
- { 0x807f0a, KEY_7 },
- { 0x807f1b, KEY_8 },
- { 0x807f1f, KEY_9 },
+ { 0x807f0d, KEY_NUMERIC_0 },
+ { 0x807f04, KEY_NUMERIC_1 },
+ { 0x807f05, KEY_NUMERIC_2 },
+ { 0x807f06, KEY_NUMERIC_3 },
+ { 0x807f07, KEY_NUMERIC_4 },
+ { 0x807f08, KEY_NUMERIC_5 },
+ { 0x807f09, KEY_NUMERIC_6 },
+ { 0x807f0a, KEY_NUMERIC_7 },
+ { 0x807f1b, KEY_NUMERIC_8 },
+ { 0x807f1f, KEY_NUMERIC_9 },
{ 0x807f12, KEY_POWER },
{ 0x807f01, KEY_MEDIA_REPEAT}, /* Recall */
{ 0x807f19, KEY_PAUSE }, /* Timeshift */
diff --git a/drivers/media/rc/keymaps/rc-it913x-v2.c b/drivers/media/rc/keymaps/rc-it913x-v2.c
index 26747a327d91..da3107da26b7 100644
--- a/drivers/media/rc/keymaps/rc-it913x-v2.c
+++ b/drivers/media/rc/keymaps/rc-it913x-v2.c
@@ -20,31 +20,31 @@ static struct rc_map_table it913x_v2_rc[] = {
{ 0x807f04, KEY_VOLUMEUP }, /* Volume- */
{ 0x807f05, KEY_SCREEN }, /* FullScreen */
{ 0x807f06, KEY_VOLUMEDOWN }, /* Volume- */
- { 0x807f07, KEY_0 }, /* 0 */
+ { 0x807f07, KEY_NUMERIC_0 }, /* 0 */
{ 0x807f08, KEY_CHANNELDOWN }, /* Channel- */
{ 0x807f09, KEY_PREVIOUS }, /* Recall */
- { 0x807f0a, KEY_1 }, /* 1 */
- { 0x807f1b, KEY_2 }, /* 2 */
- { 0x807f1f, KEY_3 }, /* 3 */
- { 0x807f0c, KEY_4 }, /* 4 */
- { 0x807f0d, KEY_5 }, /* 5 */
- { 0x807f0e, KEY_6 }, /* 6 */
- { 0x807f00, KEY_7 }, /* 7 */
- { 0x807f0f, KEY_8 }, /* 8 */
- { 0x807f19, KEY_9 }, /* 9 */
+ { 0x807f0a, KEY_NUMERIC_1 }, /* 1 */
+ { 0x807f1b, KEY_NUMERIC_2 }, /* 2 */
+ { 0x807f1f, KEY_NUMERIC_3 }, /* 3 */
+ { 0x807f0c, KEY_NUMERIC_4 }, /* 4 */
+ { 0x807f0d, KEY_NUMERIC_5 }, /* 5 */
+ { 0x807f0e, KEY_NUMERIC_6 }, /* 6 */
+ { 0x807f00, KEY_NUMERIC_7 }, /* 7 */
+ { 0x807f0f, KEY_NUMERIC_8 }, /* 8 */
+ { 0x807f19, KEY_NUMERIC_9 }, /* 9 */
/* Type 2 */
/* keys stereo, snapshot unassigned */
- { 0x866b00, KEY_0 },
- { 0x866b01, KEY_1 },
- { 0x866b02, KEY_2 },
- { 0x866b03, KEY_3 },
- { 0x866b04, KEY_4 },
- { 0x866b05, KEY_5 },
- { 0x866b06, KEY_6 },
- { 0x866b07, KEY_7 },
- { 0x866b08, KEY_8 },
- { 0x866b09, KEY_9 },
+ { 0x866b00, KEY_NUMERIC_0 },
+ { 0x866b01, KEY_NUMERIC_1 },
+ { 0x866b02, KEY_NUMERIC_2 },
+ { 0x866b03, KEY_NUMERIC_3 },
+ { 0x866b04, KEY_NUMERIC_4 },
+ { 0x866b05, KEY_NUMERIC_5 },
+ { 0x866b06, KEY_NUMERIC_6 },
+ { 0x866b07, KEY_NUMERIC_7 },
+ { 0x866b08, KEY_NUMERIC_8 },
+ { 0x866b09, KEY_NUMERIC_9 },
{ 0x866b12, KEY_POWER },
{ 0x866b13, KEY_MUTE },
{ 0x866b0a, KEY_PREVIOUS }, /* Recall */
diff --git a/drivers/media/rc/keymaps/rc-kaiomy.c b/drivers/media/rc/keymaps/rc-kaiomy.c
index a00051339842..548760e86a2d 100644
--- a/drivers/media/rc/keymaps/rc-kaiomy.c
+++ b/drivers/media/rc/keymaps/rc-kaiomy.c
@@ -18,19 +18,19 @@ static struct rc_map_table kaiomy[] = {
{ 0x0b, KEY_ZOOM},
{ 0x03, KEY_POWER},
- { 0x04, KEY_1},
- { 0x08, KEY_2},
- { 0x02, KEY_3},
+ { 0x04, KEY_NUMERIC_1},
+ { 0x08, KEY_NUMERIC_2},
+ { 0x02, KEY_NUMERIC_3},
- { 0x0f, KEY_4},
- { 0x05, KEY_5},
- { 0x06, KEY_6},
+ { 0x0f, KEY_NUMERIC_4},
+ { 0x05, KEY_NUMERIC_5},
+ { 0x06, KEY_NUMERIC_6},
- { 0x0c, KEY_7},
- { 0x0d, KEY_8},
- { 0x0a, KEY_9},
+ { 0x0c, KEY_NUMERIC_7},
+ { 0x0d, KEY_NUMERIC_8},
+ { 0x0a, KEY_NUMERIC_9},
- { 0x11, KEY_0},
+ { 0x11, KEY_NUMERIC_0},
{ 0x09, KEY_CHANNELUP},
{ 0x07, KEY_CHANNELDOWN},
diff --git a/drivers/media/rc/keymaps/rc-kworld-315u.c b/drivers/media/rc/keymaps/rc-kworld-315u.c
index ed0e0586dea2..f5aed4b96019 100644
--- a/drivers/media/rc/keymaps/rc-kworld-315u.c
+++ b/drivers/media/rc/keymaps/rc-kworld-315u.c
@@ -17,23 +17,23 @@ static struct rc_map_table kworld_315u[] = {
{ 0x610b, KEY_ZOOM },
{ 0x6103, KEY_POWER2 }, /* shutdown */
- { 0x6104, KEY_1 },
- { 0x6108, KEY_2 },
- { 0x6102, KEY_3 },
+ { 0x6104, KEY_NUMERIC_1 },
+ { 0x6108, KEY_NUMERIC_2 },
+ { 0x6102, KEY_NUMERIC_3 },
{ 0x6109, KEY_CHANNELUP },
- { 0x610f, KEY_4 },
- { 0x6105, KEY_5 },
- { 0x6106, KEY_6 },
+ { 0x610f, KEY_NUMERIC_4 },
+ { 0x6105, KEY_NUMERIC_5 },
+ { 0x6106, KEY_NUMERIC_6 },
{ 0x6107, KEY_CHANNELDOWN },
- { 0x610c, KEY_7 },
- { 0x610d, KEY_8 },
- { 0x610a, KEY_9 },
+ { 0x610c, KEY_NUMERIC_7 },
+ { 0x610d, KEY_NUMERIC_8 },
+ { 0x610a, KEY_NUMERIC_9 },
{ 0x610e, KEY_VOLUMEUP },
{ 0x6110, KEY_LAST },
- { 0x6111, KEY_0 },
+ { 0x6111, KEY_NUMERIC_0 },
{ 0x6112, KEY_ENTER },
{ 0x6113, KEY_VOLUMEDOWN },
diff --git a/drivers/media/rc/keymaps/rc-kworld-pc150u.c b/drivers/media/rc/keymaps/rc-kworld-pc150u.c
index 9c60cf4f3bf2..7938761eb994 100644
--- a/drivers/media/rc/keymaps/rc-kworld-pc150u.c
+++ b/drivers/media/rc/keymaps/rc-kworld-pc150u.c
@@ -20,16 +20,16 @@ static struct rc_map_table kworld_pc150u[] = {
{ 0x16, KEY_EJECTCLOSECD }, /* -> ) */
{ 0x1d, KEY_POWER2 },
- { 0x00, KEY_1 },
- { 0x01, KEY_2 },
- { 0x02, KEY_3 },
- { 0x03, KEY_4 },
- { 0x04, KEY_5 },
- { 0x05, KEY_6 },
- { 0x06, KEY_7 },
- { 0x07, KEY_8 },
- { 0x08, KEY_9 },
- { 0x0a, KEY_0 },
+ { 0x00, KEY_NUMERIC_1 },
+ { 0x01, KEY_NUMERIC_2 },
+ { 0x02, KEY_NUMERIC_3 },
+ { 0x03, KEY_NUMERIC_4 },
+ { 0x04, KEY_NUMERIC_5 },
+ { 0x05, KEY_NUMERIC_6 },
+ { 0x06, KEY_NUMERIC_7 },
+ { 0x07, KEY_NUMERIC_8 },
+ { 0x08, KEY_NUMERIC_9 },
+ { 0x0a, KEY_NUMERIC_0 },
{ 0x09, KEY_AGAIN },
{ 0x14, KEY_MUTE },
diff --git a/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c b/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c
index db5edde3eeb1..75389b74e02d 100644
--- a/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c
+++ b/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c
@@ -17,16 +17,20 @@ static struct rc_map_table kworld_plus_tv_analog[] = {
{ 0x16, KEY_CLOSECD }, /* -> ) */
{ 0x1d, KEY_POWER2 },
- { 0x00, KEY_1 },
- { 0x01, KEY_2 },
- { 0x02, KEY_3 }, /* Two keys have the same code: 3 and left */
- { 0x03, KEY_4 }, /* Two keys have the same code: 3 and right */
- { 0x04, KEY_5 },
- { 0x05, KEY_6 },
- { 0x06, KEY_7 },
- { 0x07, KEY_8 },
- { 0x08, KEY_9 },
- { 0x0a, KEY_0 },
+ { 0x00, KEY_NUMERIC_1 },
+ { 0x01, KEY_NUMERIC_2 },
+
+ /* Two keys have the same code: 3 and left */
+ { 0x02, KEY_NUMERIC_3 },
+
+ /* Two keys have the same code: 4 and right */
+ { 0x03, KEY_NUMERIC_4 },
+ { 0x04, KEY_NUMERIC_5 },
+ { 0x05, KEY_NUMERIC_6 },
+ { 0x06, KEY_NUMERIC_7 },
+ { 0x07, KEY_NUMERIC_8 },
+ { 0x08, KEY_NUMERIC_9 },
+ { 0x0a, KEY_NUMERIC_0 },
{ 0x09, KEY_AGAIN },
{ 0x14, KEY_MUTE },
diff --git a/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c b/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c
index afee942e0edf..2f2b981e1995 100644
--- a/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c
+++ b/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c
@@ -12,20 +12,20 @@ static struct rc_map_table leadtek_y04g0051[] = {
{ 0x0300, KEY_POWER2 },
{ 0x0303, KEY_SCREEN },
{ 0x0304, KEY_RIGHT },
- { 0x0305, KEY_1 },
- { 0x0306, KEY_2 },
- { 0x0307, KEY_3 },
+ { 0x0305, KEY_NUMERIC_1 },
+ { 0x0306, KEY_NUMERIC_2 },
+ { 0x0307, KEY_NUMERIC_3 },
{ 0x0308, KEY_LEFT },
- { 0x0309, KEY_4 },
- { 0x030a, KEY_5 },
- { 0x030b, KEY_6 },
+ { 0x0309, KEY_NUMERIC_4 },
+ { 0x030a, KEY_NUMERIC_5 },
+ { 0x030b, KEY_NUMERIC_6 },
{ 0x030c, KEY_UP },
- { 0x030d, KEY_7 },
- { 0x030e, KEY_8 },
- { 0x030f, KEY_9 },
+ { 0x030d, KEY_NUMERIC_7 },
+ { 0x030e, KEY_NUMERIC_8 },
+ { 0x030f, KEY_NUMERIC_9 },
{ 0x0310, KEY_DOWN },
{ 0x0311, KEY_AGAIN },
- { 0x0312, KEY_0 },
+ { 0x0312, KEY_NUMERIC_0 },
{ 0x0313, KEY_OK }, /* 1st ok */
{ 0x0314, KEY_MUTE },
{ 0x0316, KEY_OK }, /* 2nd ok */
diff --git a/drivers/media/rc/keymaps/rc-lme2510.c b/drivers/media/rc/keymaps/rc-lme2510.c
index b0901a8a72a6..181e48f0cb67 100644
--- a/drivers/media/rc/keymaps/rc-lme2510.c
+++ b/drivers/media/rc/keymaps/rc-lme2510.c
@@ -10,16 +10,16 @@
static struct rc_map_table lme2510_rc[] = {
/* Type 1 - 26 buttons */
- { 0xef12ba45, KEY_0 },
- { 0xef12a05f, KEY_1 },
- { 0xef12af50, KEY_2 },
- { 0xef12a25d, KEY_3 },
- { 0xef12be41, KEY_4 },
- { 0xef12f50a, KEY_5 },
- { 0xef12bd42, KEY_6 },
- { 0xef12b847, KEY_7 },
- { 0xef12b649, KEY_8 },
- { 0xef12fa05, KEY_9 },
+ { 0xef12ba45, KEY_NUMERIC_0 },
+ { 0xef12a05f, KEY_NUMERIC_1 },
+ { 0xef12af50, KEY_NUMERIC_2 },
+ { 0xef12a25d, KEY_NUMERIC_3 },
+ { 0xef12be41, KEY_NUMERIC_4 },
+ { 0xef12f50a, KEY_NUMERIC_5 },
+ { 0xef12bd42, KEY_NUMERIC_6 },
+ { 0xef12b847, KEY_NUMERIC_7 },
+ { 0xef12b649, KEY_NUMERIC_8 },
+ { 0xef12fa05, KEY_NUMERIC_9 },
{ 0xef12bc43, KEY_POWER },
{ 0xef12b946, KEY_SUBTITLE },
{ 0xef12f906, KEY_PAUSE },
@@ -37,16 +37,16 @@ static struct rc_map_table lme2510_rc[] = {
{ 0xef12f807, KEY_EPG },
{ 0xef12fe01, KEY_STOP },
/* Type 2 - 20 buttons */
- { 0xff40ea15, KEY_0 },
- { 0xff40f708, KEY_1 },
- { 0xff40f609, KEY_2 },
- { 0xff40f50a, KEY_3 },
- { 0xff40f30c, KEY_4 },
- { 0xff40f20d, KEY_5 },
- { 0xff40f10e, KEY_6 },
- { 0xff40ef10, KEY_7 },
- { 0xff40ee11, KEY_8 },
- { 0xff40ed12, KEY_9 },
+ { 0xff40ea15, KEY_NUMERIC_0 },
+ { 0xff40f708, KEY_NUMERIC_1 },
+ { 0xff40f609, KEY_NUMERIC_2 },
+ { 0xff40f50a, KEY_NUMERIC_3 },
+ { 0xff40f30c, KEY_NUMERIC_4 },
+ { 0xff40f20d, KEY_NUMERIC_5 },
+ { 0xff40f10e, KEY_NUMERIC_6 },
+ { 0xff40ef10, KEY_NUMERIC_7 },
+ { 0xff40ee11, KEY_NUMERIC_8 },
+ { 0xff40ed12, KEY_NUMERIC_9 },
{ 0xff40ff00, KEY_POWER },
{ 0xff40fb04, KEY_MEDIA_REPEAT}, /* Recall */
{ 0xff40e51a, KEY_PAUSE }, /* Timeshift */
@@ -58,16 +58,16 @@ static struct rc_map_table lme2510_rc[] = {
{ 0xff40e718, KEY_RECORD },
{ 0xff40e916, KEY_STOP },
/* Type 3 - 20 buttons */
- { 0xff00e31c, KEY_0 },
- { 0xff00f807, KEY_1 },
- { 0xff00ea15, KEY_2 },
- { 0xff00f609, KEY_3 },
- { 0xff00e916, KEY_4 },
- { 0xff00e619, KEY_5 },
- { 0xff00f20d, KEY_6 },
- { 0xff00f30c, KEY_7 },
- { 0xff00e718, KEY_8 },
- { 0xff00a15e, KEY_9 },
+ { 0xff00e31c, KEY_NUMERIC_0 },
+ { 0xff00f807, KEY_NUMERIC_1 },
+ { 0xff00ea15, KEY_NUMERIC_2 },
+ { 0xff00f609, KEY_NUMERIC_3 },
+ { 0xff00e916, KEY_NUMERIC_4 },
+ { 0xff00e619, KEY_NUMERIC_5 },
+ { 0xff00f20d, KEY_NUMERIC_6 },
+ { 0xff00f30c, KEY_NUMERIC_7 },
+ { 0xff00e718, KEY_NUMERIC_8 },
+ { 0xff00a15e, KEY_NUMERIC_9 },
{ 0xff00ba45, KEY_POWER },
{ 0xff00bb44, KEY_MEDIA_REPEAT}, /* Recall */
{ 0xff00b54a, KEY_PAUSE }, /* Timeshift */
diff --git a/drivers/media/rc/keymaps/rc-manli.c b/drivers/media/rc/keymaps/rc-manli.c
index 5e9a49e2dd6a..e884aeb5c3d6 100644
--- a/drivers/media/rc/keymaps/rc-manli.c
+++ b/drivers/media/rc/keymaps/rc-manli.c
@@ -35,22 +35,22 @@ static struct rc_map_table manli[] = {
* 0x07 0x08 0x09 *
* 7 8 9 *
* */
- { 0x01, KEY_1 },
- { 0x02, KEY_2 },
- { 0x03, KEY_3 },
- { 0x04, KEY_4 },
- { 0x05, KEY_5 },
- { 0x06, KEY_6 },
- { 0x07, KEY_7 },
- { 0x08, KEY_8 },
- { 0x09, KEY_9 },
+ { 0x01, KEY_NUMERIC_1 },
+ { 0x02, KEY_NUMERIC_2 },
+ { 0x03, KEY_NUMERIC_3 },
+ { 0x04, KEY_NUMERIC_4 },
+ { 0x05, KEY_NUMERIC_5 },
+ { 0x06, KEY_NUMERIC_6 },
+ { 0x07, KEY_NUMERIC_7 },
+ { 0x08, KEY_NUMERIC_8 },
+ { 0x09, KEY_NUMERIC_9 },
/* 0x0a 0x00 0x17 *
* RECALL 0 +100 *
* PLUS *
* */
{ 0x0a, KEY_AGAIN }, /*XXX KEY_REWIND? */
- { 0x00, KEY_0 },
+ { 0x00, KEY_NUMERIC_0 },
{ 0x17, KEY_DIGITS }, /*XXX*/
/* 0x14 0x10 *
diff --git a/drivers/media/rc/keymaps/rc-medion-x10-digitainer.c b/drivers/media/rc/keymaps/rc-medion-x10-digitainer.c
index 407706b246f2..bf74912859b3 100644
--- a/drivers/media/rc/keymaps/rc-medion-x10-digitainer.c
+++ b/drivers/media/rc/keymaps/rc-medion-x10-digitainer.c
@@ -63,16 +63,16 @@ static struct rc_map_table medion_x10_digitainer[] = {
{ 0x27, KEY_RECORD },
{ 0x26, KEY_FORWARD },
- { 0x0d, KEY_1 },
- { 0x0e, KEY_2 },
- { 0x0f, KEY_3 },
- { 0x10, KEY_4 },
- { 0x11, KEY_5 },
- { 0x12, KEY_6 },
- { 0x13, KEY_7 },
- { 0x14, KEY_8 },
- { 0x15, KEY_9 },
- { 0x17, KEY_0 },
+ { 0x0d, KEY_NUMERIC_1 },
+ { 0x0e, KEY_NUMERIC_2 },
+ { 0x0f, KEY_NUMERIC_3 },
+ { 0x10, KEY_NUMERIC_4 },
+ { 0x11, KEY_NUMERIC_5 },
+ { 0x12, KEY_NUMERIC_6 },
+ { 0x13, KEY_NUMERIC_7 },
+ { 0x14, KEY_NUMERIC_8 },
+ { 0x15, KEY_NUMERIC_9 },
+ { 0x17, KEY_NUMERIC_0 },
/* these do not actually exist on this remote, but these scancodes
* exist on all other Medion X10 remotes and adding them here allows
diff --git a/drivers/media/rc/keymaps/rc-medion-x10-or2x.c b/drivers/media/rc/keymaps/rc-medion-x10-or2x.c
index 2ff5c454304d..293045c9aaa5 100644
--- a/drivers/media/rc/keymaps/rc-medion-x10-or2x.c
+++ b/drivers/media/rc/keymaps/rc-medion-x10-or2x.c
@@ -52,16 +52,16 @@ static struct rc_map_table medion_x10_or2x[] = {
{ 0x29, KEY_PAUSE },
{ 0x27, KEY_RECORD },
- { 0x0d, KEY_1 },
- { 0x0e, KEY_2 },
- { 0x0f, KEY_3 },
- { 0x10, KEY_4 },
- { 0x11, KEY_5 },
- { 0x12, KEY_6 },
- { 0x13, KEY_7 },
- { 0x14, KEY_8 },
- { 0x15, KEY_9 },
- { 0x17, KEY_0 },
+ { 0x0d, KEY_NUMERIC_1 },
+ { 0x0e, KEY_NUMERIC_2 },
+ { 0x0f, KEY_NUMERIC_3 },
+ { 0x10, KEY_NUMERIC_4 },
+ { 0x11, KEY_NUMERIC_5 },
+ { 0x12, KEY_NUMERIC_6 },
+ { 0x13, KEY_NUMERIC_7 },
+ { 0x14, KEY_NUMERIC_8 },
+ { 0x15, KEY_NUMERIC_9 },
+ { 0x17, KEY_NUMERIC_0 },
{ 0x30, KEY_CLEAR },
{ 0x36, KEY_ENTER },
{ 0x37, KEY_NUMERIC_STAR },
diff --git a/drivers/media/rc/keymaps/rc-medion-x10.c b/drivers/media/rc/keymaps/rc-medion-x10.c
index 66b962dc982b..843dba3bad73 100644
--- a/drivers/media/rc/keymaps/rc-medion-x10.c
+++ b/drivers/media/rc/keymaps/rc-medion-x10.c
@@ -37,16 +37,16 @@ static struct rc_map_table medion_x10[] = {
{ 0x35, KEY_BLUE }, /* blue */
{ 0x16, KEY_TEXT }, /* TXT */
- { 0x0d, KEY_1 },
- { 0x0e, KEY_2 },
- { 0x0f, KEY_3 },
- { 0x10, KEY_4 },
- { 0x11, KEY_5 },
- { 0x12, KEY_6 },
- { 0x13, KEY_7 },
- { 0x14, KEY_8 },
- { 0x15, KEY_9 },
- { 0x17, KEY_0 },
+ { 0x0d, KEY_NUMERIC_1 },
+ { 0x0e, KEY_NUMERIC_2 },
+ { 0x0f, KEY_NUMERIC_3 },
+ { 0x10, KEY_NUMERIC_4 },
+ { 0x11, KEY_NUMERIC_5 },
+ { 0x12, KEY_NUMERIC_6 },
+ { 0x13, KEY_NUMERIC_7 },
+ { 0x14, KEY_NUMERIC_8 },
+ { 0x15, KEY_NUMERIC_9 },
+ { 0x17, KEY_NUMERIC_0 },
{ 0x1c, KEY_SEARCH }, /* TV/RAD, CH SRC */
{ 0x20, KEY_DELETE }, /* DELETE */
diff --git a/drivers/media/rc/keymaps/rc-msi-digivox-ii.c b/drivers/media/rc/keymaps/rc-msi-digivox-ii.c
index d361554e8a2d..ab001d2dac67 100644
--- a/drivers/media/rc/keymaps/rc-msi-digivox-ii.c
+++ b/drivers/media/rc/keymaps/rc-msi-digivox-ii.c
@@ -9,23 +9,23 @@
#include <linux/module.h>
static struct rc_map_table msi_digivox_ii[] = {
- { 0x0302, KEY_2 },
+ { 0x0302, KEY_NUMERIC_2 },
{ 0x0303, KEY_UP }, /* up */
- { 0x0304, KEY_3 },
+ { 0x0304, KEY_NUMERIC_3 },
{ 0x0305, KEY_CHANNELDOWN },
- { 0x0308, KEY_5 },
- { 0x0309, KEY_0 },
- { 0x030b, KEY_8 },
+ { 0x0308, KEY_NUMERIC_5 },
+ { 0x0309, KEY_NUMERIC_0 },
+ { 0x030b, KEY_NUMERIC_8 },
{ 0x030d, KEY_DOWN }, /* down */
- { 0x0310, KEY_9 },
- { 0x0311, KEY_7 },
+ { 0x0310, KEY_NUMERIC_9 },
+ { 0x0311, KEY_NUMERIC_7 },
{ 0x0314, KEY_VOLUMEUP },
{ 0x0315, KEY_CHANNELUP },
{ 0x0316, KEY_OK },
{ 0x0317, KEY_POWER2 },
- { 0x031a, KEY_1 },
- { 0x031c, KEY_4 },
- { 0x031d, KEY_6 },
+ { 0x031a, KEY_NUMERIC_1 },
+ { 0x031c, KEY_NUMERIC_4 },
+ { 0x031d, KEY_NUMERIC_6 },
{ 0x031f, KEY_VOLUMEDOWN },
};
diff --git a/drivers/media/rc/keymaps/rc-msi-digivox-iii.c b/drivers/media/rc/keymaps/rc-msi-digivox-iii.c
index 31d41564a438..6129d3e925e5 100644
--- a/drivers/media/rc/keymaps/rc-msi-digivox-iii.c
+++ b/drivers/media/rc/keymaps/rc-msi-digivox-iii.c
@@ -14,22 +14,22 @@
since rc-kworld-315u.c lacks NEC extended address byte. */
static struct rc_map_table msi_digivox_iii[] = {
{ 0x61d601, KEY_VIDEO }, /* Source */
- { 0x61d602, KEY_3 },
+ { 0x61d602, KEY_NUMERIC_3 },
{ 0x61d603, KEY_POWER }, /* ShutDown */
- { 0x61d604, KEY_1 },
- { 0x61d605, KEY_5 },
- { 0x61d606, KEY_6 },
+ { 0x61d604, KEY_NUMERIC_1 },
+ { 0x61d605, KEY_NUMERIC_5 },
+ { 0x61d606, KEY_NUMERIC_6 },
{ 0x61d607, KEY_CHANNELDOWN }, /* CH- */
- { 0x61d608, KEY_2 },
+ { 0x61d608, KEY_NUMERIC_2 },
{ 0x61d609, KEY_CHANNELUP }, /* CH+ */
- { 0x61d60a, KEY_9 },
+ { 0x61d60a, KEY_NUMERIC_9 },
{ 0x61d60b, KEY_ZOOM }, /* Zoom */
- { 0x61d60c, KEY_7 },
- { 0x61d60d, KEY_8 },
+ { 0x61d60c, KEY_NUMERIC_7 },
+ { 0x61d60d, KEY_NUMERIC_8 },
{ 0x61d60e, KEY_VOLUMEUP }, /* Vol+ */
- { 0x61d60f, KEY_4 },
+ { 0x61d60f, KEY_NUMERIC_4 },
{ 0x61d610, KEY_ESC }, /* [back up arrow] */
- { 0x61d611, KEY_0 },
+ { 0x61d611, KEY_NUMERIC_0 },
{ 0x61d612, KEY_OK }, /* [enter arrow] */
{ 0x61d613, KEY_VOLUMEDOWN }, /* Vol- */
{ 0x61d614, KEY_RECORD }, /* Rec */
diff --git a/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c b/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c
index 78cf2c286083..42270a7ef3ee 100644
--- a/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c
+++ b/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c
@@ -44,16 +44,16 @@ static struct rc_map_table msi_tvanywhere_plus[] = {
<< FUNC >> RESET
*/
- { 0x01, KEY_1 }, /* 1 */
- { 0x0b, KEY_2 }, /* 2 */
- { 0x1b, KEY_3 }, /* 3 */
- { 0x05, KEY_4 }, /* 4 */
- { 0x09, KEY_5 }, /* 5 */
- { 0x15, KEY_6 }, /* 6 */
- { 0x06, KEY_7 }, /* 7 */
- { 0x0a, KEY_8 }, /* 8 */
- { 0x12, KEY_9 }, /* 9 */
- { 0x02, KEY_0 }, /* 0 */
+ { 0x01, KEY_NUMERIC_1 }, /* 1 */
+ { 0x0b, KEY_NUMERIC_2 }, /* 2 */
+ { 0x1b, KEY_NUMERIC_3 }, /* 3 */
+ { 0x05, KEY_NUMERIC_4 }, /* 4 */
+ { 0x09, KEY_NUMERIC_5 }, /* 5 */
+ { 0x15, KEY_NUMERIC_6 }, /* 6 */
+ { 0x06, KEY_NUMERIC_7 }, /* 7 */
+ { 0x0a, KEY_NUMERIC_8 }, /* 8 */
+ { 0x12, KEY_NUMERIC_9 }, /* 9 */
+ { 0x02, KEY_NUMERIC_0 }, /* 0 */
{ 0x10, KEY_KPPLUS }, /* + */
{ 0x13, KEY_AGAIN }, /* Recall */
diff --git a/drivers/media/rc/keymaps/rc-msi-tvanywhere.c b/drivers/media/rc/keymaps/rc-msi-tvanywhere.c
index 359a57be3a66..45793c641009 100644
--- a/drivers/media/rc/keymaps/rc-msi-tvanywhere.c
+++ b/drivers/media/rc/keymaps/rc-msi-tvanywhere.c
@@ -12,16 +12,16 @@
static struct rc_map_table msi_tvanywhere[] = {
/* Keys 0 to 9 */
- { 0x00, KEY_0 },
- { 0x01, KEY_1 },
- { 0x02, KEY_2 },
- { 0x03, KEY_3 },
- { 0x04, KEY_4 },
- { 0x05, KEY_5 },
- { 0x06, KEY_6 },
- { 0x07, KEY_7 },
- { 0x08, KEY_8 },
- { 0x09, KEY_9 },
+ { 0x00, KEY_NUMERIC_0 },
+ { 0x01, KEY_NUMERIC_1 },
+ { 0x02, KEY_NUMERIC_2 },
+ { 0x03, KEY_NUMERIC_3 },
+ { 0x04, KEY_NUMERIC_4 },
+ { 0x05, KEY_NUMERIC_5 },
+ { 0x06, KEY_NUMERIC_6 },
+ { 0x07, KEY_NUMERIC_7 },
+ { 0x08, KEY_NUMERIC_8 },
+ { 0x09, KEY_NUMERIC_9 },
{ 0x0c, KEY_MUTE },
{ 0x0f, KEY_SCREEN }, /* Full Screen */
diff --git a/drivers/media/rc/keymaps/rc-nebula.c b/drivers/media/rc/keymaps/rc-nebula.c
index 17d7c1b324da..2dc6061f69b3 100644
--- a/drivers/media/rc/keymaps/rc-nebula.c
+++ b/drivers/media/rc/keymaps/rc-nebula.c
@@ -9,16 +9,16 @@
#include <linux/module.h>
static struct rc_map_table nebula[] = {
- { 0x0000, KEY_0 },
- { 0x0001, KEY_1 },
- { 0x0002, KEY_2 },
- { 0x0003, KEY_3 },
- { 0x0004, KEY_4 },
- { 0x0005, KEY_5 },
- { 0x0006, KEY_6 },
- { 0x0007, KEY_7 },
- { 0x0008, KEY_8 },
- { 0x0009, KEY_9 },
+ { 0x0000, KEY_NUMERIC_0 },
+ { 0x0001, KEY_NUMERIC_1 },
+ { 0x0002, KEY_NUMERIC_2 },
+ { 0x0003, KEY_NUMERIC_3 },
+ { 0x0004, KEY_NUMERIC_4 },
+ { 0x0005, KEY_NUMERIC_5 },
+ { 0x0006, KEY_NUMERIC_6 },
+ { 0x0007, KEY_NUMERIC_7 },
+ { 0x0008, KEY_NUMERIC_8 },
+ { 0x0009, KEY_NUMERIC_9 },
{ 0x000a, KEY_TV },
{ 0x000b, KEY_AUX },
{ 0x000c, KEY_DVD },
diff --git a/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c b/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c
index 76beef44a8d7..b12c54d47db3 100644
--- a/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c
+++ b/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c
@@ -23,16 +23,16 @@ static struct rc_map_table nec_terratec_cinergy_xs[] = {
{ 0x1444, KEY_TEXT}, /* Teletext */
{ 0x1445, KEY_DELETE},
- { 0x1402, KEY_1},
- { 0x1403, KEY_2},
- { 0x1404, KEY_3},
- { 0x1405, KEY_4},
- { 0x1406, KEY_5},
- { 0x1407, KEY_6},
- { 0x1408, KEY_7},
- { 0x1409, KEY_8},
- { 0x140a, KEY_9},
- { 0x140c, KEY_0},
+ { 0x1402, KEY_NUMERIC_1},
+ { 0x1403, KEY_NUMERIC_2},
+ { 0x1404, KEY_NUMERIC_3},
+ { 0x1405, KEY_NUMERIC_4},
+ { 0x1406, KEY_NUMERIC_5},
+ { 0x1407, KEY_NUMERIC_6},
+ { 0x1408, KEY_NUMERIC_7},
+ { 0x1409, KEY_NUMERIC_8},
+ { 0x140a, KEY_NUMERIC_9},
+ { 0x140c, KEY_NUMERIC_0},
{ 0x140b, KEY_TUNER}, /* AV */
{ 0x140d, KEY_MODE}, /* A.B */
@@ -79,16 +79,16 @@ static struct rc_map_table nec_terratec_cinergy_xs[] = {
/* Terratec Black IR, with most keys in black */
{ 0x04eb01, KEY_POWER2},
- { 0x04eb02, KEY_1},
- { 0x04eb03, KEY_2},
- { 0x04eb04, KEY_3},
- { 0x04eb05, KEY_4},
- { 0x04eb06, KEY_5},
- { 0x04eb07, KEY_6},
- { 0x04eb08, KEY_7},
- { 0x04eb09, KEY_8},
- { 0x04eb0a, KEY_9},
- { 0x04eb0c, KEY_0},
+ { 0x04eb02, KEY_NUMERIC_1},
+ { 0x04eb03, KEY_NUMERIC_2},
+ { 0x04eb04, KEY_NUMERIC_3},
+ { 0x04eb05, KEY_NUMERIC_4},
+ { 0x04eb06, KEY_NUMERIC_5},
+ { 0x04eb07, KEY_NUMERIC_6},
+ { 0x04eb08, KEY_NUMERIC_7},
+ { 0x04eb09, KEY_NUMERIC_8},
+ { 0x04eb0a, KEY_NUMERIC_9},
+ { 0x04eb0c, KEY_NUMERIC_0},
{ 0x04eb0b, KEY_TEXT}, /* TXT */
{ 0x04eb0d, KEY_REFRESH}, /* Refresh */
diff --git a/drivers/media/rc/keymaps/rc-norwood.c b/drivers/media/rc/keymaps/rc-norwood.c
index 3765705c5549..acd5b1ccf8d0 100644
--- a/drivers/media/rc/keymaps/rc-norwood.c
+++ b/drivers/media/rc/keymaps/rc-norwood.c
@@ -14,16 +14,16 @@
static struct rc_map_table norwood[] = {
/* Keys 0 to 9 */
- { 0x20, KEY_0 },
- { 0x21, KEY_1 },
- { 0x22, KEY_2 },
- { 0x23, KEY_3 },
- { 0x24, KEY_4 },
- { 0x25, KEY_5 },
- { 0x26, KEY_6 },
- { 0x27, KEY_7 },
- { 0x28, KEY_8 },
- { 0x29, KEY_9 },
+ { 0x20, KEY_NUMERIC_0 },
+ { 0x21, KEY_NUMERIC_1 },
+ { 0x22, KEY_NUMERIC_2 },
+ { 0x23, KEY_NUMERIC_3 },
+ { 0x24, KEY_NUMERIC_4 },
+ { 0x25, KEY_NUMERIC_5 },
+ { 0x26, KEY_NUMERIC_6 },
+ { 0x27, KEY_NUMERIC_7 },
+ { 0x28, KEY_NUMERIC_8 },
+ { 0x29, KEY_NUMERIC_9 },
{ 0x78, KEY_VIDEO }, /* Video Source */
{ 0x2c, KEY_EXIT }, /* Open/Close software */
diff --git a/drivers/media/rc/keymaps/rc-npgtech.c b/drivers/media/rc/keymaps/rc-npgtech.c
index abaf7f6d4cb7..98a755e8bc18 100644
--- a/drivers/media/rc/keymaps/rc-npgtech.c
+++ b/drivers/media/rc/keymaps/rc-npgtech.c
@@ -12,16 +12,16 @@ static struct rc_map_table npgtech[] = {
{ 0x1d, KEY_SWITCHVIDEOMODE }, /* switch inputs */
{ 0x2a, KEY_FRONT },
- { 0x3e, KEY_1 },
- { 0x02, KEY_2 },
- { 0x06, KEY_3 },
- { 0x0a, KEY_4 },
- { 0x0e, KEY_5 },
- { 0x12, KEY_6 },
- { 0x16, KEY_7 },
- { 0x1a, KEY_8 },
- { 0x1e, KEY_9 },
- { 0x3a, KEY_0 },
+ { 0x3e, KEY_NUMERIC_1 },
+ { 0x02, KEY_NUMERIC_2 },
+ { 0x06, KEY_NUMERIC_3 },
+ { 0x0a, KEY_NUMERIC_4 },
+ { 0x0e, KEY_NUMERIC_5 },
+ { 0x12, KEY_NUMERIC_6 },
+ { 0x16, KEY_NUMERIC_7 },
+ { 0x1a, KEY_NUMERIC_8 },
+ { 0x1e, KEY_NUMERIC_9 },
+ { 0x3a, KEY_NUMERIC_0 },
{ 0x22, KEY_NUMLOCK }, /* -/-- */
{ 0x20, KEY_REFRESH },
diff --git a/drivers/media/rc/keymaps/rc-pctv-sedna.c b/drivers/media/rc/keymaps/rc-pctv-sedna.c
index e3462c5c8984..c3bb1ecdd0ca 100644
--- a/drivers/media/rc/keymaps/rc-pctv-sedna.c
+++ b/drivers/media/rc/keymaps/rc-pctv-sedna.c
@@ -14,16 +14,16 @@
Also for the remote bundled with Kozumi KTV-01C card */
static struct rc_map_table pctv_sedna[] = {
- { 0x00, KEY_0 },
- { 0x01, KEY_1 },
- { 0x02, KEY_2 },
- { 0x03, KEY_3 },
- { 0x04, KEY_4 },
- { 0x05, KEY_5 },
- { 0x06, KEY_6 },
- { 0x07, KEY_7 },
- { 0x08, KEY_8 },
- { 0x09, KEY_9 },
+ { 0x00, KEY_NUMERIC_0 },
+ { 0x01, KEY_NUMERIC_1 },
+ { 0x02, KEY_NUMERIC_2 },
+ { 0x03, KEY_NUMERIC_3 },
+ { 0x04, KEY_NUMERIC_4 },
+ { 0x05, KEY_NUMERIC_5 },
+ { 0x06, KEY_NUMERIC_6 },
+ { 0x07, KEY_NUMERIC_7 },
+ { 0x08, KEY_NUMERIC_8 },
+ { 0x09, KEY_NUMERIC_9 },
{ 0x0a, KEY_AGAIN }, /* Recall */
{ 0x0b, KEY_CHANNELUP },
diff --git a/drivers/media/rc/keymaps/rc-pinnacle-color.c b/drivers/media/rc/keymaps/rc-pinnacle-color.c
index 63c2851e9dfe..b862725635b9 100644
--- a/drivers/media/rc/keymaps/rc-pinnacle-color.c
+++ b/drivers/media/rc/keymaps/rc-pinnacle-color.c
@@ -49,16 +49,16 @@ static struct rc_map_table pinnacle_color[] = {
{ 0x4c, KEY_STOP },
{ 0x54, KEY_NEXT },
- { 0x69, KEY_0 },
- { 0x6a, KEY_1 },
- { 0x6b, KEY_2 },
- { 0x6c, KEY_3 },
- { 0x6d, KEY_4 },
- { 0x6e, KEY_5 },
- { 0x6f, KEY_6 },
- { 0x70, KEY_7 },
- { 0x71, KEY_8 },
- { 0x72, KEY_9 },
+ { 0x69, KEY_NUMERIC_0 },
+ { 0x6a, KEY_NUMERIC_1 },
+ { 0x6b, KEY_NUMERIC_2 },
+ { 0x6c, KEY_NUMERIC_3 },
+ { 0x6d, KEY_NUMERIC_4 },
+ { 0x6e, KEY_NUMERIC_5 },
+ { 0x6f, KEY_NUMERIC_6 },
+ { 0x70, KEY_NUMERIC_7 },
+ { 0x71, KEY_NUMERIC_8 },
+ { 0x72, KEY_NUMERIC_9 },
{ 0x74, KEY_CHANNEL },
{ 0x0a, KEY_BACKSPACE },
diff --git a/drivers/media/rc/keymaps/rc-pinnacle-grey.c b/drivers/media/rc/keymaps/rc-pinnacle-grey.c
index 31794d4180db..3853b653cee6 100644
--- a/drivers/media/rc/keymaps/rc-pinnacle-grey.c
+++ b/drivers/media/rc/keymaps/rc-pinnacle-grey.c
@@ -9,16 +9,16 @@
#include <linux/module.h>
static struct rc_map_table pinnacle_grey[] = {
- { 0x3a, KEY_0 },
- { 0x31, KEY_1 },
- { 0x32, KEY_2 },
- { 0x33, KEY_3 },
- { 0x34, KEY_4 },
- { 0x35, KEY_5 },
- { 0x36, KEY_6 },
- { 0x37, KEY_7 },
- { 0x38, KEY_8 },
- { 0x39, KEY_9 },
+ { 0x3a, KEY_NUMERIC_0 },
+ { 0x31, KEY_NUMERIC_1 },
+ { 0x32, KEY_NUMERIC_2 },
+ { 0x33, KEY_NUMERIC_3 },
+ { 0x34, KEY_NUMERIC_4 },
+ { 0x35, KEY_NUMERIC_5 },
+ { 0x36, KEY_NUMERIC_6 },
+ { 0x37, KEY_NUMERIC_7 },
+ { 0x38, KEY_NUMERIC_8 },
+ { 0x39, KEY_NUMERIC_9 },
{ 0x2f, KEY_POWER },
diff --git a/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c
index 876aeb6e1d9c..96d8112fb468 100644
--- a/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c
+++ b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c
@@ -20,16 +20,16 @@ static struct rc_map_table pinnacle_pctv_hd[] = {
{ 0x0709, KEY_VOLUMEDOWN },
{ 0x0706, KEY_CHANNELUP },
{ 0x070c, KEY_CHANNELDOWN },
- { 0x070f, KEY_1 },
- { 0x0715, KEY_2 },
- { 0x0710, KEY_3 },
- { 0x0718, KEY_4 },
- { 0x071b, KEY_5 },
- { 0x071e, KEY_6 },
- { 0x0711, KEY_7 },
- { 0x0721, KEY_8 },
- { 0x0712, KEY_9 },
- { 0x0727, KEY_0 },
+ { 0x070f, KEY_NUMERIC_1 },
+ { 0x0715, KEY_NUMERIC_2 },
+ { 0x0710, KEY_NUMERIC_3 },
+ { 0x0718, KEY_NUMERIC_4 },
+ { 0x071b, KEY_NUMERIC_5 },
+ { 0x071e, KEY_NUMERIC_6 },
+ { 0x0711, KEY_NUMERIC_7 },
+ { 0x0721, KEY_NUMERIC_8 },
+ { 0x0712, KEY_NUMERIC_9 },
+ { 0x0727, KEY_NUMERIC_0 },
{ 0x0724, KEY_ZOOM }, /* 'Square' key */
{ 0x072a, KEY_SUBTITLE }, /* 'T' key */
{ 0x072d, KEY_REWIND },
diff --git a/drivers/media/rc/keymaps/rc-pixelview-002t.c b/drivers/media/rc/keymaps/rc-pixelview-002t.c
index c0550e09f255..c3439c46644c 100644
--- a/drivers/media/rc/keymaps/rc-pixelview-002t.c
+++ b/drivers/media/rc/keymaps/rc-pixelview-002t.c
@@ -16,16 +16,16 @@ static struct rc_map_table pixelview_002t[] = {
{ 0x866b13, KEY_MUTE },
{ 0x866b12, KEY_POWER2 }, /* power */
- { 0x866b01, KEY_1 },
- { 0x866b02, KEY_2 },
- { 0x866b03, KEY_3 },
- { 0x866b04, KEY_4 },
- { 0x866b05, KEY_5 },
- { 0x866b06, KEY_6 },
- { 0x866b07, KEY_7 },
- { 0x866b08, KEY_8 },
- { 0x866b09, KEY_9 },
- { 0x866b00, KEY_0 },
+ { 0x866b01, KEY_NUMERIC_1 },
+ { 0x866b02, KEY_NUMERIC_2 },
+ { 0x866b03, KEY_NUMERIC_3 },
+ { 0x866b04, KEY_NUMERIC_4 },
+ { 0x866b05, KEY_NUMERIC_5 },
+ { 0x866b06, KEY_NUMERIC_6 },
+ { 0x866b07, KEY_NUMERIC_7 },
+ { 0x866b08, KEY_NUMERIC_8 },
+ { 0x866b09, KEY_NUMERIC_9 },
+ { 0x866b00, KEY_NUMERIC_0 },
{ 0x866b0d, KEY_CHANNELUP },
{ 0x866b19, KEY_CHANNELDOWN },
diff --git a/drivers/media/rc/keymaps/rc-pixelview-mk12.c b/drivers/media/rc/keymaps/rc-pixelview-mk12.c
index 864c8ea5d8e3..ea11ccde8442 100644
--- a/drivers/media/rc/keymaps/rc-pixelview-mk12.c
+++ b/drivers/media/rc/keymaps/rc-pixelview-mk12.c
@@ -16,16 +16,16 @@ static struct rc_map_table pixelview_mk12[] = {
{ 0x866b03, KEY_TUNER }, /* Timeshift */
{ 0x866b1e, KEY_POWER2 }, /* power */
- { 0x866b01, KEY_1 },
- { 0x866b0b, KEY_2 },
- { 0x866b1b, KEY_3 },
- { 0x866b05, KEY_4 },
- { 0x866b09, KEY_5 },
- { 0x866b15, KEY_6 },
- { 0x866b06, KEY_7 },
- { 0x866b0a, KEY_8 },
- { 0x866b12, KEY_9 },
- { 0x866b02, KEY_0 },
+ { 0x866b01, KEY_NUMERIC_1 },
+ { 0x866b0b, KEY_NUMERIC_2 },
+ { 0x866b1b, KEY_NUMERIC_3 },
+ { 0x866b05, KEY_NUMERIC_4 },
+ { 0x866b09, KEY_NUMERIC_5 },
+ { 0x866b15, KEY_NUMERIC_6 },
+ { 0x866b06, KEY_NUMERIC_7 },
+ { 0x866b0a, KEY_NUMERIC_8 },
+ { 0x866b12, KEY_NUMERIC_9 },
+ { 0x866b02, KEY_NUMERIC_0 },
{ 0x866b13, KEY_AGAIN }, /* loop */
{ 0x866b10, KEY_DIGITS }, /* +100 */
diff --git a/drivers/media/rc/keymaps/rc-pixelview-new.c b/drivers/media/rc/keymaps/rc-pixelview-new.c
index e4e34f2ccf74..0259666831b0 100644
--- a/drivers/media/rc/keymaps/rc-pixelview-new.c
+++ b/drivers/media/rc/keymaps/rc-pixelview-new.c
@@ -17,16 +17,16 @@ static struct rc_map_table pixelview_new[] = {
{ 0x3c, KEY_TIME }, /* Timeshift */
{ 0x12, KEY_POWER },
- { 0x3d, KEY_1 },
- { 0x38, KEY_2 },
- { 0x18, KEY_3 },
- { 0x35, KEY_4 },
- { 0x39, KEY_5 },
- { 0x15, KEY_6 },
- { 0x36, KEY_7 },
- { 0x3a, KEY_8 },
- { 0x1e, KEY_9 },
- { 0x3e, KEY_0 },
+ { 0x3d, KEY_NUMERIC_1 },
+ { 0x38, KEY_NUMERIC_2 },
+ { 0x18, KEY_NUMERIC_3 },
+ { 0x35, KEY_NUMERIC_4 },
+ { 0x39, KEY_NUMERIC_5 },
+ { 0x15, KEY_NUMERIC_6 },
+ { 0x36, KEY_NUMERIC_7 },
+ { 0x3a, KEY_NUMERIC_8 },
+ { 0x1e, KEY_NUMERIC_9 },
+ { 0x3e, KEY_NUMERIC_0 },
{ 0x1c, KEY_AGAIN }, /* LOOP */
{ 0x3f, KEY_VIDEO }, /* Source */
diff --git a/drivers/media/rc/keymaps/rc-pixelview.c b/drivers/media/rc/keymaps/rc-pixelview.c
index 988919735165..29f6d2c013e4 100644
--- a/drivers/media/rc/keymaps/rc-pixelview.c
+++ b/drivers/media/rc/keymaps/rc-pixelview.c
@@ -25,16 +25,16 @@ static struct rc_map_table pixelview[] = {
{ 0x19, KEY_ZOOM }, /* zoom */
{ 0x0f, KEY_TEXT }, /* min */
- { 0x01, KEY_1 },
- { 0x0b, KEY_2 },
- { 0x1b, KEY_3 },
- { 0x05, KEY_4 },
- { 0x09, KEY_5 },
- { 0x15, KEY_6 },
- { 0x06, KEY_7 },
- { 0x0a, KEY_8 },
- { 0x12, KEY_9 },
- { 0x02, KEY_0 },
+ { 0x01, KEY_NUMERIC_1 },
+ { 0x0b, KEY_NUMERIC_2 },
+ { 0x1b, KEY_NUMERIC_3 },
+ { 0x05, KEY_NUMERIC_4 },
+ { 0x09, KEY_NUMERIC_5 },
+ { 0x15, KEY_NUMERIC_6 },
+ { 0x06, KEY_NUMERIC_7 },
+ { 0x0a, KEY_NUMERIC_8 },
+ { 0x12, KEY_NUMERIC_9 },
+ { 0x02, KEY_NUMERIC_0 },
{ 0x10, KEY_LAST }, /* +100 */
{ 0x13, KEY_LIST }, /* recall */
diff --git a/drivers/media/rc/keymaps/rc-powercolor-real-angel.c b/drivers/media/rc/keymaps/rc-powercolor-real-angel.c
index cf98cf8dc13c..66fe2e52e7c8 100644
--- a/drivers/media/rc/keymaps/rc-powercolor-real-angel.c
+++ b/drivers/media/rc/keymaps/rc-powercolor-real-angel.c
@@ -16,16 +16,16 @@
static struct rc_map_table powercolor_real_angel[] = {
{ 0x38, KEY_SWITCHVIDEOMODE }, /* switch inputs */
{ 0x0c, KEY_MEDIA }, /* Turn ON/OFF App */
- { 0x00, KEY_0 },
- { 0x01, KEY_1 },
- { 0x02, KEY_2 },
- { 0x03, KEY_3 },
- { 0x04, KEY_4 },
- { 0x05, KEY_5 },
- { 0x06, KEY_6 },
- { 0x07, KEY_7 },
- { 0x08, KEY_8 },
- { 0x09, KEY_9 },
+ { 0x00, KEY_NUMERIC_0 },
+ { 0x01, KEY_NUMERIC_1 },
+ { 0x02, KEY_NUMERIC_2 },
+ { 0x03, KEY_NUMERIC_3 },
+ { 0x04, KEY_NUMERIC_4 },
+ { 0x05, KEY_NUMERIC_5 },
+ { 0x06, KEY_NUMERIC_6 },
+ { 0x07, KEY_NUMERIC_7 },
+ { 0x08, KEY_NUMERIC_8 },
+ { 0x09, KEY_NUMERIC_9 },
{ 0x0a, KEY_DIGITS }, /* single, double, triple digit */
{ 0x29, KEY_PREVIOUS }, /* previous channel */
{ 0x12, KEY_BRIGHTNESSUP },
diff --git a/drivers/media/rc/keymaps/rc-proteus-2309.c b/drivers/media/rc/keymaps/rc-proteus-2309.c
index d2c13d0e7bff..36eebefd975c 100644
--- a/drivers/media/rc/keymaps/rc-proteus-2309.c
+++ b/drivers/media/rc/keymaps/rc-proteus-2309.c
@@ -12,16 +12,16 @@
static struct rc_map_table proteus_2309[] = {
/* numeric */
- { 0x00, KEY_0 },
- { 0x01, KEY_1 },
- { 0x02, KEY_2 },
- { 0x03, KEY_3 },
- { 0x04, KEY_4 },
- { 0x05, KEY_5 },
- { 0x06, KEY_6 },
- { 0x07, KEY_7 },
- { 0x08, KEY_8 },
- { 0x09, KEY_9 },
+ { 0x00, KEY_NUMERIC_0 },
+ { 0x01, KEY_NUMERIC_1 },
+ { 0x02, KEY_NUMERIC_2 },
+ { 0x03, KEY_NUMERIC_3 },
+ { 0x04, KEY_NUMERIC_4 },
+ { 0x05, KEY_NUMERIC_5 },
+ { 0x06, KEY_NUMERIC_6 },
+ { 0x07, KEY_NUMERIC_7 },
+ { 0x08, KEY_NUMERIC_8 },
+ { 0x09, KEY_NUMERIC_9 },
{ 0x5c, KEY_POWER }, /* power */
{ 0x20, KEY_ZOOM }, /* full screen */
diff --git a/drivers/media/rc/keymaps/rc-purpletv.c b/drivers/media/rc/keymaps/rc-purpletv.c
index c8011f4d96ea..bf4543fecb6f 100644
--- a/drivers/media/rc/keymaps/rc-purpletv.c
+++ b/drivers/media/rc/keymaps/rc-purpletv.c
@@ -13,16 +13,16 @@ static struct rc_map_table purpletv[] = {
{ 0x6f, KEY_MUTE },
{ 0x10, KEY_BACKSPACE }, /* Recall */
- { 0x11, KEY_0 },
- { 0x04, KEY_1 },
- { 0x05, KEY_2 },
- { 0x06, KEY_3 },
- { 0x08, KEY_4 },
- { 0x09, KEY_5 },
- { 0x0a, KEY_6 },
- { 0x0c, KEY_7 },
- { 0x0d, KEY_8 },
- { 0x0e, KEY_9 },
+ { 0x11, KEY_NUMERIC_0 },
+ { 0x04, KEY_NUMERIC_1 },
+ { 0x05, KEY_NUMERIC_2 },
+ { 0x06, KEY_NUMERIC_3 },
+ { 0x08, KEY_NUMERIC_4 },
+ { 0x09, KEY_NUMERIC_5 },
+ { 0x0a, KEY_NUMERIC_6 },
+ { 0x0c, KEY_NUMERIC_7 },
+ { 0x0d, KEY_NUMERIC_8 },
+ { 0x0e, KEY_NUMERIC_9 },
{ 0x12, KEY_DOT }, /* 100+ */
{ 0x07, KEY_VOLUMEUP },
diff --git a/drivers/media/rc/keymaps/rc-pv951.c b/drivers/media/rc/keymaps/rc-pv951.c
index 5235ee899c30..69db55463000 100644
--- a/drivers/media/rc/keymaps/rc-pv951.c
+++ b/drivers/media/rc/keymaps/rc-pv951.c
@@ -11,16 +11,16 @@
/* Mark Phalan <phalanm@o2.ie> */
static struct rc_map_table pv951[] = {
- { 0x00, KEY_0 },
- { 0x01, KEY_1 },
- { 0x02, KEY_2 },
- { 0x03, KEY_3 },
- { 0x04, KEY_4 },
- { 0x05, KEY_5 },
- { 0x06, KEY_6 },
- { 0x07, KEY_7 },
- { 0x08, KEY_8 },
- { 0x09, KEY_9 },
+ { 0x00, KEY_NUMERIC_0 },
+ { 0x01, KEY_NUMERIC_1 },
+ { 0x02, KEY_NUMERIC_2 },
+ { 0x03, KEY_NUMERIC_3 },
+ { 0x04, KEY_NUMERIC_4 },
+ { 0x05, KEY_NUMERIC_5 },
+ { 0x06, KEY_NUMERIC_6 },
+ { 0x07, KEY_NUMERIC_7 },
+ { 0x08, KEY_NUMERIC_8 },
+ { 0x09, KEY_NUMERIC_9 },
{ 0x12, KEY_POWER },
{ 0x10, KEY_MUTE },
diff --git a/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c b/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c
index 1cf786649675..33bb458b81fd 100644
--- a/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c
+++ b/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c
@@ -14,16 +14,16 @@ static struct rc_map_table real_audio_220_32_keys[] = {
{ 0x1c, KEY_RADIO},
{ 0x12, KEY_POWER2},
- { 0x01, KEY_1},
- { 0x02, KEY_2},
- { 0x03, KEY_3},
- { 0x04, KEY_4},
- { 0x05, KEY_5},
- { 0x06, KEY_6},
- { 0x07, KEY_7},
- { 0x08, KEY_8},
- { 0x09, KEY_9},
- { 0x00, KEY_0},
+ { 0x01, KEY_NUMERIC_1},
+ { 0x02, KEY_NUMERIC_2},
+ { 0x03, KEY_NUMERIC_3},
+ { 0x04, KEY_NUMERIC_4},
+ { 0x05, KEY_NUMERIC_5},
+ { 0x06, KEY_NUMERIC_6},
+ { 0x07, KEY_NUMERIC_7},
+ { 0x08, KEY_NUMERIC_8},
+ { 0x09, KEY_NUMERIC_9},
+ { 0x00, KEY_NUMERIC_0},
{ 0x0c, KEY_VOLUMEUP},
{ 0x18, KEY_VOLUMEDOWN},
diff --git a/drivers/media/rc/keymaps/rc-reddo.c b/drivers/media/rc/keymaps/rc-reddo.c
index a68003381540..b70390d19e78 100644
--- a/drivers/media/rc/keymaps/rc-reddo.c
+++ b/drivers/media/rc/keymaps/rc-reddo.c
@@ -23,21 +23,21 @@
static struct rc_map_table reddo[] = {
{ 0x61d601, KEY_EPG }, /* EPG */
- { 0x61d602, KEY_3 },
- { 0x61d604, KEY_1 },
- { 0x61d605, KEY_5 },
- { 0x61d606, KEY_6 },
+ { 0x61d602, KEY_NUMERIC_3 },
+ { 0x61d604, KEY_NUMERIC_1 },
+ { 0x61d605, KEY_NUMERIC_5 },
+ { 0x61d606, KEY_NUMERIC_6 },
{ 0x61d607, KEY_CHANNELDOWN }, /* CH- */
- { 0x61d608, KEY_2 },
+ { 0x61d608, KEY_NUMERIC_2 },
{ 0x61d609, KEY_CHANNELUP }, /* CH+ */
- { 0x61d60a, KEY_9 },
+ { 0x61d60a, KEY_NUMERIC_9 },
{ 0x61d60b, KEY_ZOOM }, /* Zoom */
- { 0x61d60c, KEY_7 },
- { 0x61d60d, KEY_8 },
+ { 0x61d60c, KEY_NUMERIC_7 },
+ { 0x61d60d, KEY_NUMERIC_8 },
{ 0x61d60e, KEY_VOLUMEUP }, /* Vol+ */
- { 0x61d60f, KEY_4 },
+ { 0x61d60f, KEY_NUMERIC_4 },
{ 0x61d610, KEY_ESC }, /* [back up arrow] */
- { 0x61d611, KEY_0 },
+ { 0x61d611, KEY_NUMERIC_0 },
{ 0x61d612, KEY_OK }, /* [enter arrow] */
{ 0x61d613, KEY_VOLUMEDOWN }, /* Vol- */
{ 0x61d614, KEY_RECORD }, /* Rec */
diff --git a/drivers/media/rc/keymaps/rc-snapstream-firefly.c b/drivers/media/rc/keymaps/rc-snapstream-firefly.c
index 8d55b4ccee83..e3d5bff3bd9e 100644
--- a/drivers/media/rc/keymaps/rc-snapstream-firefly.c
+++ b/drivers/media/rc/keymaps/rc-snapstream-firefly.c
@@ -12,16 +12,16 @@ static struct rc_map_table snapstream_firefly[] = {
{ 0x2c, KEY_ZOOM }, /* Maximize */
{ 0x02, KEY_CLOSE },
- { 0x0d, KEY_1 },
- { 0x0e, KEY_2 },
- { 0x0f, KEY_3 },
- { 0x10, KEY_4 },
- { 0x11, KEY_5 },
- { 0x12, KEY_6 },
- { 0x13, KEY_7 },
- { 0x14, KEY_8 },
- { 0x15, KEY_9 },
- { 0x17, KEY_0 },
+ { 0x0d, KEY_NUMERIC_1 },
+ { 0x0e, KEY_NUMERIC_2 },
+ { 0x0f, KEY_NUMERIC_3 },
+ { 0x10, KEY_NUMERIC_4 },
+ { 0x11, KEY_NUMERIC_5 },
+ { 0x12, KEY_NUMERIC_6 },
+ { 0x13, KEY_NUMERIC_7 },
+ { 0x14, KEY_NUMERIC_8 },
+ { 0x15, KEY_NUMERIC_9 },
+ { 0x17, KEY_NUMERIC_0 },
{ 0x16, KEY_BACK },
{ 0x18, KEY_KPENTER }, /* ent */
diff --git a/drivers/media/rc/keymaps/rc-su3000.c b/drivers/media/rc/keymaps/rc-su3000.c
index 1c82737e3999..64cfc01aa48f 100644
--- a/drivers/media/rc/keymaps/rc-su3000.c
+++ b/drivers/media/rc/keymaps/rc-su3000.c
@@ -10,16 +10,16 @@
static struct rc_map_table su3000[] = {
{ 0x25, KEY_POWER }, /* right-bottom Red */
{ 0x0a, KEY_MUTE }, /* -/-- */
- { 0x01, KEY_1 },
- { 0x02, KEY_2 },
- { 0x03, KEY_3 },
- { 0x04, KEY_4 },
- { 0x05, KEY_5 },
- { 0x06, KEY_6 },
- { 0x07, KEY_7 },
- { 0x08, KEY_8 },
- { 0x09, KEY_9 },
- { 0x00, KEY_0 },
+ { 0x01, KEY_NUMERIC_1 },
+ { 0x02, KEY_NUMERIC_2 },
+ { 0x03, KEY_NUMERIC_3 },
+ { 0x04, KEY_NUMERIC_4 },
+ { 0x05, KEY_NUMERIC_5 },
+ { 0x06, KEY_NUMERIC_6 },
+ { 0x07, KEY_NUMERIC_7 },
+ { 0x08, KEY_NUMERIC_8 },
+ { 0x09, KEY_NUMERIC_9 },
+ { 0x00, KEY_NUMERIC_0 },
{ 0x20, KEY_UP }, /* CH+ */
{ 0x21, KEY_DOWN }, /* CH+ */
{ 0x12, KEY_VOLUMEUP }, /* Brightness Up */
diff --git a/drivers/media/rc/keymaps/rc-tango.c b/drivers/media/rc/keymaps/rc-tango.c
index 1c6e8875d46f..2b9cef6ef5b5 100644
--- a/drivers/media/rc/keymaps/rc-tango.c
+++ b/drivers/media/rc/keymaps/rc-tango.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2017 Sigma Designs
- *
- * 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.
*/
#include <linux/module.h>
@@ -20,16 +17,16 @@ static struct rc_map_table tango_table[] = {
{ 0x4cb51, KEY_MUTE },
{ 0x4cb52, KEY_VOLUMEDOWN },
- { 0x4cb41, KEY_1 },
- { 0x4cb03, KEY_2 },
- { 0x4cb42, KEY_3 },
- { 0x4cb45, KEY_4 },
- { 0x4cb07, KEY_5 },
- { 0x4cb46, KEY_6 },
- { 0x4cb55, KEY_7 },
- { 0x4cb17, KEY_8 },
- { 0x4cb56, KEY_9 },
- { 0x4cb1b, KEY_0 },
+ { 0x4cb41, KEY_NUMERIC_1 },
+ { 0x4cb03, KEY_NUMERIC_2 },
+ { 0x4cb42, KEY_NUMERIC_3 },
+ { 0x4cb45, KEY_NUMERIC_4 },
+ { 0x4cb07, KEY_NUMERIC_5 },
+ { 0x4cb46, KEY_NUMERIC_6 },
+ { 0x4cb55, KEY_NUMERIC_7 },
+ { 0x4cb17, KEY_NUMERIC_8 },
+ { 0x4cb56, KEY_NUMERIC_9 },
+ { 0x4cb1b, KEY_NUMERIC_0 },
{ 0x4cb59, KEY_DELETE },
{ 0x4cb5a, KEY_CAPSLOCK },
diff --git a/drivers/media/rc/keymaps/rc-tbs-nec.c b/drivers/media/rc/keymaps/rc-tbs-nec.c
index 42766cb877c3..420980925f29 100644
--- a/drivers/media/rc/keymaps/rc-tbs-nec.c
+++ b/drivers/media/rc/keymaps/rc-tbs-nec.c
@@ -11,16 +11,16 @@
static struct rc_map_table tbs_nec[] = {
{ 0x84, KEY_POWER2}, /* power */
{ 0x94, KEY_MUTE}, /* mute */
- { 0x87, KEY_1},
- { 0x86, KEY_2},
- { 0x85, KEY_3},
- { 0x8b, KEY_4},
- { 0x8a, KEY_5},
- { 0x89, KEY_6},
- { 0x8f, KEY_7},
- { 0x8e, KEY_8},
- { 0x8d, KEY_9},
- { 0x92, KEY_0},
+ { 0x87, KEY_NUMERIC_1},
+ { 0x86, KEY_NUMERIC_2},
+ { 0x85, KEY_NUMERIC_3},
+ { 0x8b, KEY_NUMERIC_4},
+ { 0x8a, KEY_NUMERIC_5},
+ { 0x89, KEY_NUMERIC_6},
+ { 0x8f, KEY_NUMERIC_7},
+ { 0x8e, KEY_NUMERIC_8},
+ { 0x8d, KEY_NUMERIC_9},
+ { 0x92, KEY_NUMERIC_0},
{ 0xc0, KEY_10CHANNELSUP}, /* 10+ */
{ 0xd0, KEY_10CHANNELSDOWN}, /* 10- */
{ 0x96, KEY_CHANNELUP}, /* ch+ */
diff --git a/drivers/media/rc/keymaps/rc-technisat-ts35.c b/drivers/media/rc/keymaps/rc-technisat-ts35.c
index 34bd04a75277..9a917ea0ceba 100644
--- a/drivers/media/rc/keymaps/rc-technisat-ts35.c
+++ b/drivers/media/rc/keymaps/rc-technisat-ts35.c
@@ -13,16 +13,16 @@ static struct rc_map_table technisat_ts35[] = {
{0x1c, KEY_AB},
{0x33, KEY_POWER},
- {0x3e, KEY_1},
- {0x3d, KEY_2},
- {0x3c, KEY_3},
- {0x3b, KEY_4},
- {0x3a, KEY_5},
- {0x39, KEY_6},
- {0x38, KEY_7},
- {0x37, KEY_8},
- {0x36, KEY_9},
- {0x3f, KEY_0},
+ {0x3e, KEY_NUMERIC_1},
+ {0x3d, KEY_NUMERIC_2},
+ {0x3c, KEY_NUMERIC_3},
+ {0x3b, KEY_NUMERIC_4},
+ {0x3a, KEY_NUMERIC_5},
+ {0x39, KEY_NUMERIC_6},
+ {0x38, KEY_NUMERIC_7},
+ {0x37, KEY_NUMERIC_8},
+ {0x36, KEY_NUMERIC_9},
+ {0x3f, KEY_NUMERIC_0},
{0x35, KEY_DIGITS},
{0x2c, KEY_TV},
diff --git a/drivers/media/rc/keymaps/rc-technisat-usb2.c b/drivers/media/rc/keymaps/rc-technisat-usb2.c
index 58b3baf5ee96..942100686c82 100644
--- a/drivers/media/rc/keymaps/rc-technisat-usb2.c
+++ b/drivers/media/rc/keymaps/rc-technisat-usb2.c
@@ -30,18 +30,18 @@
static struct rc_map_table technisat_usb2[] = {
{0x0a0c, KEY_POWER},
- {0x0a01, KEY_1},
- {0x0a02, KEY_2},
- {0x0a03, KEY_3},
+ {0x0a01, KEY_NUMERIC_1},
+ {0x0a02, KEY_NUMERIC_2},
+ {0x0a03, KEY_NUMERIC_3},
{0x0a0d, KEY_MUTE},
- {0x0a04, KEY_4},
- {0x0a05, KEY_5},
- {0x0a06, KEY_6},
+ {0x0a04, KEY_NUMERIC_4},
+ {0x0a05, KEY_NUMERIC_5},
+ {0x0a06, KEY_NUMERIC_6},
{0x0a38, KEY_VIDEO}, /* EXT */
- {0x0a07, KEY_7},
- {0x0a08, KEY_8},
- {0x0a09, KEY_9},
- {0x0a00, KEY_0},
+ {0x0a07, KEY_NUMERIC_7},
+ {0x0a08, KEY_NUMERIC_8},
+ {0x0a09, KEY_NUMERIC_9},
+ {0x0a00, KEY_NUMERIC_0},
{0x0a4f, KEY_INFO},
{0x0a20, KEY_CHANNELUP},
{0x0a52, KEY_MENU},
diff --git a/drivers/media/rc/keymaps/rc-terratec-cinergy-c-pci.c b/drivers/media/rc/keymaps/rc-terratec-cinergy-c-pci.c
index 4b2741b158c4..da06f844d8fb 100644
--- a/drivers/media/rc/keymaps/rc-terratec-cinergy-c-pci.c
+++ b/drivers/media/rc/keymaps/rc-terratec-cinergy-c-pci.c
@@ -9,17 +9,17 @@
static struct rc_map_table terratec_cinergy_c_pci[] = {
{ 0x3e, KEY_POWER},
- { 0x3d, KEY_1},
- { 0x3c, KEY_2},
- { 0x3b, KEY_3},
- { 0x3a, KEY_4},
- { 0x39, KEY_5},
- { 0x38, KEY_6},
- { 0x37, KEY_7},
- { 0x36, KEY_8},
- { 0x35, KEY_9},
+ { 0x3d, KEY_NUMERIC_1},
+ { 0x3c, KEY_NUMERIC_2},
+ { 0x3b, KEY_NUMERIC_3},
+ { 0x3a, KEY_NUMERIC_4},
+ { 0x39, KEY_NUMERIC_5},
+ { 0x38, KEY_NUMERIC_6},
+ { 0x37, KEY_NUMERIC_7},
+ { 0x36, KEY_NUMERIC_8},
+ { 0x35, KEY_NUMERIC_9},
{ 0x34, KEY_VIDEO_NEXT}, /* AV */
- { 0x33, KEY_0},
+ { 0x33, KEY_NUMERIC_0},
{ 0x32, KEY_REFRESH},
{ 0x30, KEY_EPG},
{ 0x2f, KEY_UP},
diff --git a/drivers/media/rc/keymaps/rc-terratec-cinergy-s2-hd.c b/drivers/media/rc/keymaps/rc-terratec-cinergy-s2-hd.c
index 631f86665206..a1844b531572 100644
--- a/drivers/media/rc/keymaps/rc-terratec-cinergy-s2-hd.c
+++ b/drivers/media/rc/keymaps/rc-terratec-cinergy-s2-hd.c
@@ -42,17 +42,17 @@ static struct rc_map_table terratec_cinergy_s2_hd[] = {
{ 0x2f, KEY_UP},
{ 0x30, KEY_EPG},
{ 0x32, KEY_VIDEO}, /* A<=>B */
- { 0x33, KEY_0},
+ { 0x33, KEY_NUMERIC_0},
{ 0x34, KEY_VCR}, /* AV */
- { 0x35, KEY_9},
- { 0x36, KEY_8},
- { 0x37, KEY_7},
- { 0x38, KEY_6},
- { 0x39, KEY_5},
- { 0x3a, KEY_4},
- { 0x3b, KEY_3},
- { 0x3c, KEY_2},
- { 0x3d, KEY_1},
+ { 0x35, KEY_NUMERIC_9},
+ { 0x36, KEY_NUMERIC_8},
+ { 0x37, KEY_NUMERIC_7},
+ { 0x38, KEY_NUMERIC_6},
+ { 0x39, KEY_NUMERIC_5},
+ { 0x3a, KEY_NUMERIC_4},
+ { 0x3b, KEY_NUMERIC_3},
+ { 0x3c, KEY_NUMERIC_2},
+ { 0x3d, KEY_NUMERIC_1},
{ 0x3e, KEY_POWER},
};
diff --git a/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c b/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c
index 6cf53a56bce4..fe587e3f0240 100644
--- a/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c
+++ b/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c
@@ -16,20 +16,20 @@ static struct rc_map_table terratec_cinergy_xs[] = {
{ 0x41, KEY_HOME},
{ 0x01, KEY_POWER},
{ 0x42, KEY_MENU},
- { 0x02, KEY_1},
- { 0x03, KEY_2},
- { 0x04, KEY_3},
+ { 0x02, KEY_NUMERIC_1},
+ { 0x03, KEY_NUMERIC_2},
+ { 0x04, KEY_NUMERIC_3},
{ 0x43, KEY_SUBTITLE},
- { 0x05, KEY_4},
- { 0x06, KEY_5},
- { 0x07, KEY_6},
+ { 0x05, KEY_NUMERIC_4},
+ { 0x06, KEY_NUMERIC_5},
+ { 0x07, KEY_NUMERIC_6},
{ 0x44, KEY_TEXT},
- { 0x08, KEY_7},
- { 0x09, KEY_8},
- { 0x0a, KEY_9},
+ { 0x08, KEY_NUMERIC_7},
+ { 0x09, KEY_NUMERIC_8},
+ { 0x0a, KEY_NUMERIC_9},
{ 0x45, KEY_DELETE},
{ 0x0b, KEY_TUNER},
- { 0x0c, KEY_0},
+ { 0x0c, KEY_NUMERIC_0},
{ 0x0d, KEY_MODE},
{ 0x46, KEY_TV},
{ 0x47, KEY_DVD},
diff --git a/drivers/media/rc/keymaps/rc-terratec-slim-2.c b/drivers/media/rc/keymaps/rc-terratec-slim-2.c
index bd1c1761b550..a54a59f90313 100644
--- a/drivers/media/rc/keymaps/rc-terratec-slim-2.c
+++ b/drivers/media/rc/keymaps/rc-terratec-slim-2.c
@@ -17,21 +17,21 @@ static struct rc_map_table terratec_slim_2[] = {
{ 0x8001, KEY_MUTE }, /* MUTE */
{ 0x8002, KEY_VOLUMEDOWN },
{ 0x8003, KEY_CHANNELDOWN },
- { 0x8004, KEY_1 },
- { 0x8005, KEY_2 },
- { 0x8006, KEY_3 },
- { 0x8007, KEY_4 },
- { 0x8008, KEY_5 },
- { 0x8009, KEY_6 },
- { 0x800a, KEY_7 },
+ { 0x8004, KEY_NUMERIC_1 },
+ { 0x8005, KEY_NUMERIC_2 },
+ { 0x8006, KEY_NUMERIC_3 },
+ { 0x8007, KEY_NUMERIC_4 },
+ { 0x8008, KEY_NUMERIC_5 },
+ { 0x8009, KEY_NUMERIC_6 },
+ { 0x800a, KEY_NUMERIC_7 },
{ 0x800c, KEY_ZOOM }, /* [fullscreen] */
- { 0x800d, KEY_0 },
+ { 0x800d, KEY_NUMERIC_0 },
{ 0x800e, KEY_AGAIN }, /* [two arrows forming a circle] */
{ 0x8012, KEY_POWER2 }, /* [red power button] */
{ 0x801a, KEY_VOLUMEUP },
- { 0x801b, KEY_8 },
+ { 0x801b, KEY_NUMERIC_8 },
{ 0x801e, KEY_CHANNELUP },
- { 0x801f, KEY_9 },
+ { 0x801f, KEY_NUMERIC_9 },
};
static struct rc_map_list terratec_slim_2_map = {
diff --git a/drivers/media/rc/keymaps/rc-terratec-slim.c b/drivers/media/rc/keymaps/rc-terratec-slim.c
index b44942691388..146e3a3480dc 100644
--- a/drivers/media/rc/keymaps/rc-terratec-slim.c
+++ b/drivers/media/rc/keymaps/rc-terratec-slim.c
@@ -11,16 +11,16 @@
/* TerraTec slim remote, 7 rows, 4 columns. */
/* Uses NEC extended 0x02bd. */
static struct rc_map_table terratec_slim[] = {
- { 0x02bd00, KEY_1 },
- { 0x02bd01, KEY_2 },
- { 0x02bd02, KEY_3 },
- { 0x02bd03, KEY_4 },
- { 0x02bd04, KEY_5 },
- { 0x02bd05, KEY_6 },
- { 0x02bd06, KEY_7 },
- { 0x02bd07, KEY_8 },
- { 0x02bd08, KEY_9 },
- { 0x02bd09, KEY_0 },
+ { 0x02bd00, KEY_NUMERIC_1 },
+ { 0x02bd01, KEY_NUMERIC_2 },
+ { 0x02bd02, KEY_NUMERIC_3 },
+ { 0x02bd03, KEY_NUMERIC_4 },
+ { 0x02bd04, KEY_NUMERIC_5 },
+ { 0x02bd05, KEY_NUMERIC_6 },
+ { 0x02bd06, KEY_NUMERIC_7 },
+ { 0x02bd07, KEY_NUMERIC_8 },
+ { 0x02bd08, KEY_NUMERIC_9 },
+ { 0x02bd09, KEY_NUMERIC_0 },
{ 0x02bd0a, KEY_MUTE },
{ 0x02bd0b, KEY_NEW }, /* symbol: PIP */
{ 0x02bd0e, KEY_VOLUMEDOWN },
diff --git a/drivers/media/rc/keymaps/rc-tevii-nec.c b/drivers/media/rc/keymaps/rc-tevii-nec.c
index 58fcc72f528e..5b96e9a38e9d 100644
--- a/drivers/media/rc/keymaps/rc-tevii-nec.c
+++ b/drivers/media/rc/keymaps/rc-tevii-nec.c
@@ -11,16 +11,16 @@
static struct rc_map_table tevii_nec[] = {
{ 0x0a, KEY_POWER2},
{ 0x0c, KEY_MUTE},
- { 0x11, KEY_1},
- { 0x12, KEY_2},
- { 0x13, KEY_3},
- { 0x14, KEY_4},
- { 0x15, KEY_5},
- { 0x16, KEY_6},
- { 0x17, KEY_7},
- { 0x18, KEY_8},
- { 0x19, KEY_9},
- { 0x10, KEY_0},
+ { 0x11, KEY_NUMERIC_1},
+ { 0x12, KEY_NUMERIC_2},
+ { 0x13, KEY_NUMERIC_3},
+ { 0x14, KEY_NUMERIC_4},
+ { 0x15, KEY_NUMERIC_5},
+ { 0x16, KEY_NUMERIC_6},
+ { 0x17, KEY_NUMERIC_7},
+ { 0x18, KEY_NUMERIC_8},
+ { 0x19, KEY_NUMERIC_9},
+ { 0x10, KEY_NUMERIC_0},
{ 0x1c, KEY_MENU},
{ 0x0f, KEY_VOLUMEDOWN},
{ 0x1a, KEY_LAST},
diff --git a/drivers/media/rc/keymaps/rc-total-media-in-hand-02.c b/drivers/media/rc/keymaps/rc-total-media-in-hand-02.c
index 7dfaf05f4934..40b773ba45b9 100644
--- a/drivers/media/rc/keymaps/rc-total-media-in-hand-02.c
+++ b/drivers/media/rc/keymaps/rc-total-media-in-hand-02.c
@@ -10,16 +10,16 @@
static struct rc_map_table total_media_in_hand_02[] = {
- { 0x0000, KEY_0 },
- { 0x0001, KEY_1 },
- { 0x0002, KEY_2 },
- { 0x0003, KEY_3 },
- { 0x0004, KEY_4 },
- { 0x0005, KEY_5 },
- { 0x0006, KEY_6 },
- { 0x0007, KEY_7 },
- { 0x0008, KEY_8 },
- { 0x0009, KEY_9 },
+ { 0x0000, KEY_NUMERIC_0 },
+ { 0x0001, KEY_NUMERIC_1 },
+ { 0x0002, KEY_NUMERIC_2 },
+ { 0x0003, KEY_NUMERIC_3 },
+ { 0x0004, KEY_NUMERIC_4 },
+ { 0x0005, KEY_NUMERIC_5 },
+ { 0x0006, KEY_NUMERIC_6 },
+ { 0x0007, KEY_NUMERIC_7 },
+ { 0x0008, KEY_NUMERIC_8 },
+ { 0x0009, KEY_NUMERIC_9 },
{ 0x000a, KEY_MUTE },
{ 0x000b, KEY_STOP }, /* Stop */
{ 0x000c, KEY_POWER2 }, /* Turn on/off application */
diff --git a/drivers/media/rc/keymaps/rc-total-media-in-hand.c b/drivers/media/rc/keymaps/rc-total-media-in-hand.c
index a12569425b8b..2144db485d83 100644
--- a/drivers/media/rc/keymaps/rc-total-media-in-hand.c
+++ b/drivers/media/rc/keymaps/rc-total-media-in-hand.c
@@ -10,16 +10,16 @@
/* Uses NEC extended 0x02bd */
static struct rc_map_table total_media_in_hand[] = {
- { 0x02bd00, KEY_1 },
- { 0x02bd01, KEY_2 },
- { 0x02bd02, KEY_3 },
- { 0x02bd03, KEY_4 },
- { 0x02bd04, KEY_5 },
- { 0x02bd05, KEY_6 },
- { 0x02bd06, KEY_7 },
- { 0x02bd07, KEY_8 },
- { 0x02bd08, KEY_9 },
- { 0x02bd09, KEY_0 },
+ { 0x02bd00, KEY_NUMERIC_1 },
+ { 0x02bd01, KEY_NUMERIC_2 },
+ { 0x02bd02, KEY_NUMERIC_3 },
+ { 0x02bd03, KEY_NUMERIC_4 },
+ { 0x02bd04, KEY_NUMERIC_5 },
+ { 0x02bd05, KEY_NUMERIC_6 },
+ { 0x02bd06, KEY_NUMERIC_7 },
+ { 0x02bd07, KEY_NUMERIC_8 },
+ { 0x02bd08, KEY_NUMERIC_9 },
+ { 0x02bd09, KEY_NUMERIC_0 },
{ 0x02bd0a, KEY_MUTE },
{ 0x02bd0b, KEY_CYCLEWINDOWS }, /* yellow, [min / max] */
{ 0x02bd0c, KEY_VIDEO }, /* TV / AV */
diff --git a/drivers/media/rc/keymaps/rc-trekstor.c b/drivers/media/rc/keymaps/rc-trekstor.c
index 8576831b20bd..e938e0da51a6 100644
--- a/drivers/media/rc/keymaps/rc-trekstor.c
+++ b/drivers/media/rc/keymaps/rc-trekstor.c
@@ -12,7 +12,7 @@
/* Imported from af9015.h.
Initial keytable was from Marc Schneider <macke@macke.org> */
static struct rc_map_table trekstor[] = {
- { 0x0084, KEY_0 },
+ { 0x0084, KEY_NUMERIC_0 },
{ 0x0085, KEY_MUTE }, /* Mute */
{ 0x0086, KEY_HOMEPAGE }, /* Home */
{ 0x0087, KEY_UP }, /* Up */
@@ -24,17 +24,17 @@ static struct rc_map_table trekstor[] = {
{ 0x008d, KEY_PLAY }, /* Play/Pause */
{ 0x008e, KEY_STOP }, /* Stop */
{ 0x008f, KEY_EPG }, /* Info/EPG */
- { 0x0090, KEY_7 },
- { 0x0091, KEY_4 },
- { 0x0092, KEY_1 },
+ { 0x0090, KEY_NUMERIC_7 },
+ { 0x0091, KEY_NUMERIC_4 },
+ { 0x0092, KEY_NUMERIC_1 },
{ 0x0093, KEY_CHANNELDOWN }, /* Channel - */
- { 0x0094, KEY_8 },
- { 0x0095, KEY_5 },
- { 0x0096, KEY_2 },
+ { 0x0094, KEY_NUMERIC_8 },
+ { 0x0095, KEY_NUMERIC_5 },
+ { 0x0096, KEY_NUMERIC_2 },
{ 0x0097, KEY_CHANNELUP }, /* Channel + */
- { 0x0098, KEY_9 },
- { 0x0099, KEY_6 },
- { 0x009a, KEY_3 },
+ { 0x0098, KEY_NUMERIC_9 },
+ { 0x0099, KEY_NUMERIC_6 },
+ { 0x009a, KEY_NUMERIC_3 },
{ 0x009b, KEY_VOLUMEDOWN }, /* Volume - */
{ 0x009c, KEY_TV }, /* TV */
{ 0x009d, KEY_RECORD }, /* Record */
diff --git a/drivers/media/rc/keymaps/rc-tt-1500.c b/drivers/media/rc/keymaps/rc-tt-1500.c
index 52f239d2c025..ff70aab13b48 100644
--- a/drivers/media/rc/keymaps/rc-tt-1500.c
+++ b/drivers/media/rc/keymaps/rc-tt-1500.c
@@ -13,16 +13,16 @@
static struct rc_map_table tt_1500[] = {
{ 0x1501, KEY_POWER },
{ 0x1502, KEY_SHUFFLE }, /* ? double-arrow key */
- { 0x1503, KEY_1 },
- { 0x1504, KEY_2 },
- { 0x1505, KEY_3 },
- { 0x1506, KEY_4 },
- { 0x1507, KEY_5 },
- { 0x1508, KEY_6 },
- { 0x1509, KEY_7 },
- { 0x150a, KEY_8 },
- { 0x150b, KEY_9 },
- { 0x150c, KEY_0 },
+ { 0x1503, KEY_NUMERIC_1 },
+ { 0x1504, KEY_NUMERIC_2 },
+ { 0x1505, KEY_NUMERIC_3 },
+ { 0x1506, KEY_NUMERIC_4 },
+ { 0x1507, KEY_NUMERIC_5 },
+ { 0x1508, KEY_NUMERIC_6 },
+ { 0x1509, KEY_NUMERIC_7 },
+ { 0x150a, KEY_NUMERIC_8 },
+ { 0x150b, KEY_NUMERIC_9 },
+ { 0x150c, KEY_NUMERIC_0 },
{ 0x150d, KEY_UP },
{ 0x150e, KEY_LEFT },
{ 0x150f, KEY_OK },
diff --git a/drivers/media/rc/keymaps/rc-twinhan-dtv-cab-ci.c b/drivers/media/rc/keymaps/rc-twinhan-dtv-cab-ci.c
index a72cb06a811e..5fc696d9e583 100644
--- a/drivers/media/rc/keymaps/rc-twinhan-dtv-cab-ci.c
+++ b/drivers/media/rc/keymaps/rc-twinhan-dtv-cab-ci.c
@@ -15,16 +15,16 @@ static struct rc_map_table twinhan_dtv_cab_ci[] = {
{ 0x23, KEY_EPG},
{ 0x3b, KEY_F22}, /* Record List */
- { 0x3c, KEY_1},
- { 0x3e, KEY_2},
- { 0x39, KEY_3},
- { 0x36, KEY_4},
- { 0x22, KEY_5},
- { 0x20, KEY_6},
- { 0x32, KEY_7},
- { 0x26, KEY_8},
- { 0x24, KEY_9},
- { 0x2a, KEY_0},
+ { 0x3c, KEY_NUMERIC_1},
+ { 0x3e, KEY_NUMERIC_2},
+ { 0x39, KEY_NUMERIC_3},
+ { 0x36, KEY_NUMERIC_4},
+ { 0x22, KEY_NUMERIC_5},
+ { 0x20, KEY_NUMERIC_6},
+ { 0x32, KEY_NUMERIC_7},
+ { 0x26, KEY_NUMERIC_8},
+ { 0x24, KEY_NUMERIC_9},
+ { 0x2a, KEY_NUMERIC_0},
{ 0x33, KEY_CANCEL},
{ 0x2c, KEY_BACK},
diff --git a/drivers/media/rc/keymaps/rc-twinhan1027.c b/drivers/media/rc/keymaps/rc-twinhan1027.c
index 3ee28bcf31dc..e1cdcfa792dc 100644
--- a/drivers/media/rc/keymaps/rc-twinhan1027.c
+++ b/drivers/media/rc/keymaps/rc-twinhan1027.c
@@ -10,16 +10,16 @@ static struct rc_map_table twinhan_vp1027[] = {
{ 0x1c, KEY_EPG },
{ 0x04, KEY_LIST },
- { 0x03, KEY_1 },
- { 0x01, KEY_2 },
- { 0x06, KEY_3 },
- { 0x09, KEY_4 },
- { 0x1d, KEY_5 },
- { 0x1f, KEY_6 },
- { 0x0d, KEY_7 },
- { 0x19, KEY_8 },
- { 0x1b, KEY_9 },
- { 0x15, KEY_0 },
+ { 0x03, KEY_NUMERIC_1 },
+ { 0x01, KEY_NUMERIC_2 },
+ { 0x06, KEY_NUMERIC_3 },
+ { 0x09, KEY_NUMERIC_4 },
+ { 0x1d, KEY_NUMERIC_5 },
+ { 0x1f, KEY_NUMERIC_6 },
+ { 0x0d, KEY_NUMERIC_7 },
+ { 0x19, KEY_NUMERIC_8 },
+ { 0x1b, KEY_NUMERIC_9 },
+ { 0x15, KEY_NUMERIC_0 },
{ 0x0c, KEY_CANCEL },
{ 0x4a, KEY_CLEAR },
diff --git a/drivers/media/rc/keymaps/rc-videomate-m1f.c b/drivers/media/rc/keymaps/rc-videomate-m1f.c
index d2d183759a03..e16b9b851c72 100644
--- a/drivers/media/rc/keymaps/rc-videomate-m1f.c
+++ b/drivers/media/rc/keymaps/rc-videomate-m1f.c
@@ -41,17 +41,17 @@ static struct rc_map_table videomate_k100[] = {
{ 0x10, KEY_PREVIOUS },
{ 0x0d, KEY_PAUSE },
{ 0x0f, KEY_NEXT },
- { 0x1e, KEY_1 },
- { 0x1f, KEY_2 },
- { 0x20, KEY_3 },
- { 0x21, KEY_4 },
- { 0x22, KEY_5 },
- { 0x23, KEY_6 },
- { 0x24, KEY_7 },
- { 0x25, KEY_8 },
- { 0x26, KEY_9 },
+ { 0x1e, KEY_NUMERIC_1 },
+ { 0x1f, KEY_NUMERIC_2 },
+ { 0x20, KEY_NUMERIC_3 },
+ { 0x21, KEY_NUMERIC_4 },
+ { 0x22, KEY_NUMERIC_5 },
+ { 0x23, KEY_NUMERIC_6 },
+ { 0x24, KEY_NUMERIC_7 },
+ { 0x25, KEY_NUMERIC_8 },
+ { 0x26, KEY_NUMERIC_9 },
{ 0x2a, KEY_NUMERIC_STAR }, /* * key */
- { 0x1d, KEY_0 },
+ { 0x1d, KEY_NUMERIC_0 },
{ 0x29, KEY_SUBTITLE }, /* # key */
{ 0x27, KEY_CLEAR },
{ 0x34, KEY_SCREEN },
diff --git a/drivers/media/rc/keymaps/rc-videomate-s350.c b/drivers/media/rc/keymaps/rc-videomate-s350.c
index e4d4dff06a24..a867d7a08055 100644
--- a/drivers/media/rc/keymaps/rc-videomate-s350.c
+++ b/drivers/media/rc/keymaps/rc-videomate-s350.c
@@ -22,16 +22,16 @@ static struct rc_map_table videomate_s350[] = {
{ 0x13, KEY_CHANNELDOWN},
{ 0x14, KEY_MUTE},
{ 0x15, KEY_VOLUMEDOWN},
- { 0x16, KEY_1},
- { 0x17, KEY_2},
- { 0x18, KEY_3},
- { 0x19, KEY_4},
- { 0x1a, KEY_5},
- { 0x1b, KEY_6},
- { 0x1c, KEY_7},
- { 0x1d, KEY_8},
- { 0x1e, KEY_9},
- { 0x1f, KEY_0},
+ { 0x16, KEY_NUMERIC_1},
+ { 0x17, KEY_NUMERIC_2},
+ { 0x18, KEY_NUMERIC_3},
+ { 0x19, KEY_NUMERIC_4},
+ { 0x1a, KEY_NUMERIC_5},
+ { 0x1b, KEY_NUMERIC_6},
+ { 0x1c, KEY_NUMERIC_7},
+ { 0x1d, KEY_NUMERIC_8},
+ { 0x1e, KEY_NUMERIC_9},
+ { 0x1f, KEY_NUMERIC_0},
{ 0x21, KEY_SLEEP},
{ 0x24, KEY_ZOOM},
{ 0x25, KEY_LAST}, /* Recall */
diff --git a/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c b/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c
index 7c4890944407..fdc3b0e1350f 100644
--- a/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c
+++ b/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c
@@ -42,16 +42,16 @@ static struct rc_map_table videomate_tv_pvr[] = {
{ 0x04, KEY_RECORD },
- { 0x16, KEY_1 },
- { 0x17, KEY_2 },
- { 0x18, KEY_3 },
- { 0x19, KEY_4 },
- { 0x1a, KEY_5 },
- { 0x1b, KEY_6 },
- { 0x1c, KEY_7 },
- { 0x1d, KEY_8 },
- { 0x1e, KEY_9 },
- { 0x1f, KEY_0 },
+ { 0x16, KEY_NUMERIC_1 },
+ { 0x17, KEY_NUMERIC_2 },
+ { 0x18, KEY_NUMERIC_3 },
+ { 0x19, KEY_NUMERIC_4 },
+ { 0x1a, KEY_NUMERIC_5 },
+ { 0x1b, KEY_NUMERIC_6 },
+ { 0x1c, KEY_NUMERIC_7 },
+ { 0x1d, KEY_NUMERIC_8 },
+ { 0x1e, KEY_NUMERIC_9 },
+ { 0x1f, KEY_NUMERIC_0 },
{ 0x20, KEY_LANGUAGE },
{ 0x21, KEY_SLEEP },
diff --git a/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c b/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c
index e443192dbe14..999ba4e084ae 100644
--- a/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c
+++ b/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c
@@ -13,16 +13,16 @@
*/
static struct rc_map_table winfast_usbii_deluxe[] = {
- { 0x62, KEY_0},
- { 0x75, KEY_1},
- { 0x76, KEY_2},
- { 0x77, KEY_3},
- { 0x79, KEY_4},
- { 0x7a, KEY_5},
- { 0x7b, KEY_6},
- { 0x7d, KEY_7},
- { 0x7e, KEY_8},
- { 0x7f, KEY_9},
+ { 0x62, KEY_NUMERIC_0},
+ { 0x75, KEY_NUMERIC_1},
+ { 0x76, KEY_NUMERIC_2},
+ { 0x77, KEY_NUMERIC_3},
+ { 0x79, KEY_NUMERIC_4},
+ { 0x7a, KEY_NUMERIC_5},
+ { 0x7b, KEY_NUMERIC_6},
+ { 0x7d, KEY_NUMERIC_7},
+ { 0x7e, KEY_NUMERIC_8},
+ { 0x7f, KEY_NUMERIC_9},
{ 0x38, KEY_CAMERA}, /* SNAPSHOT */
{ 0x37, KEY_RECORD}, /* RECORD */
diff --git a/drivers/media/rc/keymaps/rc-winfast.c b/drivers/media/rc/keymaps/rc-winfast.c
index ee7f4c349fd6..be52a3e1f8ae 100644
--- a/drivers/media/rc/keymaps/rc-winfast.c
+++ b/drivers/media/rc/keymaps/rc-winfast.c
@@ -12,16 +12,16 @@
static struct rc_map_table winfast[] = {
/* Keys 0 to 9 */
- { 0x12, KEY_0 },
- { 0x05, KEY_1 },
- { 0x06, KEY_2 },
- { 0x07, KEY_3 },
- { 0x09, KEY_4 },
- { 0x0a, KEY_5 },
- { 0x0b, KEY_6 },
- { 0x0d, KEY_7 },
- { 0x0e, KEY_8 },
- { 0x0f, KEY_9 },
+ { 0x12, KEY_NUMERIC_0 },
+ { 0x05, KEY_NUMERIC_1 },
+ { 0x06, KEY_NUMERIC_2 },
+ { 0x07, KEY_NUMERIC_3 },
+ { 0x09, KEY_NUMERIC_4 },
+ { 0x0a, KEY_NUMERIC_5 },
+ { 0x0b, KEY_NUMERIC_6 },
+ { 0x0d, KEY_NUMERIC_7 },
+ { 0x0e, KEY_NUMERIC_8 },
+ { 0x0f, KEY_NUMERIC_9 },
{ 0x00, KEY_POWER2 },
{ 0x1b, KEY_AUDIO }, /* Audio Source */
diff --git a/drivers/media/rc/keymaps/rc-xbox-dvd.c b/drivers/media/rc/keymaps/rc-xbox-dvd.c
index 42815ab57bff..9d656042a81f 100644
--- a/drivers/media/rc/keymaps/rc-xbox-dvd.c
+++ b/drivers/media/rc/keymaps/rc-xbox-dvd.c
@@ -14,16 +14,16 @@ static struct rc_map_table xbox_dvd[] = {
{0xaa9, KEY_LEFT},
{0xac3, KEY_INFO},
- {0xac6, KEY_9},
- {0xac7, KEY_8},
- {0xac8, KEY_7},
- {0xac9, KEY_6},
- {0xaca, KEY_5},
- {0xacb, KEY_4},
- {0xacc, KEY_3},
- {0xacd, KEY_2},
- {0xace, KEY_1},
- {0xacf, KEY_0},
+ {0xac6, KEY_NUMERIC_9},
+ {0xac7, KEY_NUMERIC_8},
+ {0xac8, KEY_NUMERIC_7},
+ {0xac9, KEY_NUMERIC_6},
+ {0xaca, KEY_NUMERIC_5},
+ {0xacb, KEY_NUMERIC_4},
+ {0xacc, KEY_NUMERIC_3},
+ {0xacd, KEY_NUMERIC_2},
+ {0xace, KEY_NUMERIC_1},
+ {0xacf, KEY_NUMERIC_0},
{0xad5, KEY_ANGLE},
{0xad8, KEY_BACK},
diff --git a/drivers/media/rc/keymaps/rc-zx-irdec.c b/drivers/media/rc/keymaps/rc-zx-irdec.c
index 5bf3ab002afc..7bb0c05eb759 100644
--- a/drivers/media/rc/keymaps/rc-zx-irdec.c
+++ b/drivers/media/rc/keymaps/rc-zx-irdec.c
@@ -1,26 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2017 Sanechips Technology Co., Ltd.
* Copyright 2017 Linaro Ltd.
- *
- * 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.
*/
#include <linux/module.h>
#include <media/rc-map.h>
static struct rc_map_table zx_irdec_table[] = {
- { 0x01, KEY_1 },
- { 0x02, KEY_2 },
- { 0x03, KEY_3 },
- { 0x04, KEY_4 },
- { 0x05, KEY_5 },
- { 0x06, KEY_6 },
- { 0x07, KEY_7 },
- { 0x08, KEY_8 },
- { 0x09, KEY_9 },
- { 0x31, KEY_0 },
+ { 0x01, KEY_NUMERIC_1 },
+ { 0x02, KEY_NUMERIC_2 },
+ { 0x03, KEY_NUMERIC_3 },
+ { 0x04, KEY_NUMERIC_4 },
+ { 0x05, KEY_NUMERIC_5 },
+ { 0x06, KEY_NUMERIC_6 },
+ { 0x07, KEY_NUMERIC_7 },
+ { 0x08, KEY_NUMERIC_8 },
+ { 0x09, KEY_NUMERIC_9 },
+ { 0x31, KEY_NUMERIC_0 },
{ 0x16, KEY_DELETE },
{ 0x0a, KEY_MODE }, /* Input method */
{ 0x0c, KEY_VOLUMEUP },
diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c
index 10830605c734..f078f8a3aec8 100644
--- a/drivers/media/rc/lirc_dev.c
+++ b/drivers/media/rc/lirc_dev.c
@@ -19,7 +19,7 @@
#include "rc-core-priv.h"
#include <uapi/linux/lirc.h>
-#define LIRCBUF_SIZE 256
+#define LIRCBUF_SIZE 1024
static dev_t lirc_base_dev;
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index 72862e4bec62..4d5351ebb940 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -1176,8 +1176,8 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0);
rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK);
if (unlikely(!rawir.duration)) {
- dev_warn(ir->dev, "nonsensical irdata %02x with duration 0",
- ir->buf_in[i]);
+ dev_dbg(ir->dev, "nonsensical irdata %02x with duration 0",
+ ir->buf_in[i]);
break;
}
if (rawir.pulse) {
diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c
index 9e1a978a5fd9..72a7bbbf6b1f 100644
--- a/drivers/media/rc/meson-ir.c
+++ b/drivers/media/rc/meson-ir.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-License-Identifier: GPL-2.0
/*
* Driver for Amlogic Meson IR remote receiver
*
@@ -113,10 +113,8 @@ static int meson_ir_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ir->reg = devm_ioremap_resource(dev, res);
- if (IS_ERR(ir->reg)) {
- dev_err(dev, "failed to map registers\n");
+ if (IS_ERR(ir->reg))
return PTR_ERR(ir->reg);
- }
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
diff --git a/drivers/media/rc/mtk-cir.c b/drivers/media/rc/mtk-cir.c
index 46101efe017b..50fb0aebb8d4 100644
--- a/drivers/media/rc/mtk-cir.c
+++ b/drivers/media/rc/mtk-cir.c
@@ -320,10 +320,8 @@ static int mtk_ir_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ir->base = devm_ioremap_resource(dev, res);
- if (IS_ERR(ir->base)) {
- dev_err(dev, "failed to map registers\n");
+ if (IS_ERR(ir->base))
return PTR_ERR(ir->base);
- }
ir->rc = devm_rc_allocate_device(dev, RC_DRIVER_IR_RAW);
if (!ir->rc) {
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index be5fd129d728..13da4c5c7d17 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -1502,7 +1502,7 @@ static ssize_t store_wakeup_protocols(struct device *device,
const char *buf, size_t len)
{
struct rc_dev *dev = to_rc_dev(device);
- enum rc_proto protocol;
+ enum rc_proto protocol = RC_PROTO_UNKNOWN;
ssize_t rc;
u64 allowed;
int i;
@@ -1511,9 +1511,7 @@ static ssize_t store_wakeup_protocols(struct device *device,
allowed = dev->allowed_wakeup_protocols;
- if (sysfs_streq(buf, "none")) {
- protocol = RC_PROTO_UNKNOWN;
- } else {
+ if (!sysfs_streq(buf, "none")) {
for (i = 0; i < ARRAY_SIZE(protocols); i++) {
if ((allowed & (1ULL << i)) &&
sysfs_streq(buf, protocols[i].name)) {
diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c
index a48f68539231..aa719d0ae6b0 100644
--- a/drivers/media/rc/sunxi-cir.c
+++ b/drivers/media/rc/sunxi-cir.c
@@ -195,7 +195,6 @@ static int sunxi_ir_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ir->base = devm_ioremap_resource(dev, res);
if (IS_ERR(ir->base)) {
- dev_err(dev, "failed to map registers\n");
ret = PTR_ERR(ir->base);
goto exit_clkdisable_clk;
}
diff --git a/drivers/media/rc/zx-irdec.c b/drivers/media/rc/zx-irdec.c
index 12d322ec8a29..948ad90ae5d8 100644
--- a/drivers/media/rc/zx-irdec.c
+++ b/drivers/media/rc/zx-irdec.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2017 Sanechips Technology Co., Ltd.
* Copyright 2017 Linaro Ltd.
- *
- * 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.
*/
#include <linux/device.h>
diff --git a/drivers/media/spi/Kconfig b/drivers/media/spi/Kconfig
index ba464efdab03..08386abb9bbc 100644
--- a/drivers/media/spi/Kconfig
+++ b/drivers/media/spi/Kconfig
@@ -2,7 +2,7 @@
if VIDEO_V4L2
menu "SPI helper chips"
- visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST
+ visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST || EXPERT
config VIDEO_GS1662
tristate "Gennum Serializers video"
diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig
index 72805e5abc68..a7108e575e9b 100644
--- a/drivers/media/tuners/Kconfig
+++ b/drivers/media/tuners/Kconfig
@@ -16,7 +16,7 @@ config MEDIA_TUNER
select MEDIA_TUNER_MC44S803 if MEDIA_SUBDRV_AUTOSELECT
menu "Customize TV tuners"
- visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST
+ visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST || EXPERT
depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT || MEDIA_SDR_SUPPORT
config MEDIA_TUNER_SIMPLE
diff --git a/drivers/media/tuners/mt2063.c b/drivers/media/tuners/mt2063.c
index f4c8a7293ebb..2240d214dfac 100644
--- a/drivers/media/tuners/mt2063.c
+++ b/drivers/media/tuners/mt2063.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for mt2063 Micronas tuner
*
@@ -7,16 +8,6 @@
* Henry Wang <Henry.wang@AzureWave.com>
* Made publicly available by Terratec, at:
* http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz
- * The original driver's license is GPL, as declared with MODULE_LICENSE()
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation under version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/init.h>
diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c
index 7be893def190..e87040d6eca7 100644
--- a/drivers/media/tuners/si2157.c
+++ b/drivers/media/tuners/si2157.c
@@ -129,6 +129,7 @@ static int si2157_init(struct dvb_frontend *fe)
chip_id = cmd.args[1] << 24 | cmd.args[2] << 16 | cmd.args[3] << 8 |
cmd.args[4] << 0;
+ #define SI2177_A30 ('A' << 24 | 77 << 16 | '3' << 8 | '0' << 0)
#define SI2158_A20 ('A' << 24 | 58 << 16 | '2' << 8 | '0' << 0)
#define SI2148_A20 ('A' << 24 | 48 << 16 | '2' << 8 | '0' << 0)
#define SI2157_A30 ('A' << 24 | 57 << 16 | '3' << 8 | '0' << 0)
@@ -144,6 +145,9 @@ static int si2157_init(struct dvb_frontend *fe)
case SI2141_A10:
fw_name = SI2141_A10_FIRMWARE;
break;
+ case SI2177_A30:
+ fw_name = SI2157_A30_FIRMWARE;
+ break;
case SI2157_A30:
case SI2147_A30:
case SI2146_A10:
@@ -520,6 +524,7 @@ static const struct i2c_device_id si2157_id_table[] = {
{"si2157", SI2157_CHIPTYPE_SI2157},
{"si2146", SI2157_CHIPTYPE_SI2146},
{"si2141", SI2157_CHIPTYPE_SI2141},
+ {"si2177", SI2157_CHIPTYPE_SI2177},
{}
};
MODULE_DEVICE_TABLE(i2c, si2157_id_table);
@@ -541,3 +546,4 @@ MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
MODULE_LICENSE("GPL");
MODULE_FIRMWARE(SI2158_A20_FIRMWARE);
MODULE_FIRMWARE(SI2141_A10_FIRMWARE);
+MODULE_FIRMWARE(SI2157_A30_FIRMWARE);
diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h
index 7d16934c7708..2bda903358da 100644
--- a/drivers/media/tuners/si2157_priv.h
+++ b/drivers/media/tuners/si2157_priv.h
@@ -41,6 +41,7 @@ struct si2157_dev {
#define SI2157_CHIPTYPE_SI2157 0
#define SI2157_CHIPTYPE_SI2146 1
#define SI2157_CHIPTYPE_SI2141 2
+#define SI2157_CHIPTYPE_SI2177 3
/* firmware command struct */
#define SI2157_ARGLEN 30
@@ -52,5 +53,5 @@ struct si2157_cmd {
#define SI2158_A20_FIRMWARE "dvb-tuner-si2158-a20-01.fw"
#define SI2141_A10_FIRMWARE "dvb-tuner-si2141-a10-01.fw"
-
+#define SI2157_A30_FIRMWARE "dvb-tuner-si2157-a30-01.fw"
#endif
diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c
index 3329de6671ce..b35231ffe503 100644
--- a/drivers/media/usb/airspy/airspy.c
+++ b/drivers/media/usb/airspy/airspy.c
@@ -613,10 +613,6 @@ static int airspy_querycap(struct file *file, void *fh,
strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
strscpy(cap->card, s->vdev.name, sizeof(cap->card));
usb_make_path(s->udev, cap->bus_info, sizeof(cap->bus_info));
- cap->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING |
- V4L2_CAP_READWRITE | V4L2_CAP_TUNER;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
-
return 0;
}
@@ -1057,6 +1053,8 @@ static int airspy_probe(struct usb_interface *intf,
s->v4l2_dev.ctrl_handler = &s->hdl;
s->vdev.v4l2_dev = &s->v4l2_dev;
s->vdev.lock = &s->v4l2_lock;
+ s->vdev.device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE | V4L2_CAP_TUNER;
ret = video_register_device(&s->vdev, VFL_TYPE_SDR, -1);
if (ret) {
diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c
index f746f6e2f686..a8a72d5fbd12 100644
--- a/drivers/media/usb/au0828/au0828-core.c
+++ b/drivers/media/usb/au0828/au0828-core.c
@@ -719,6 +719,12 @@ static int au0828_usb_probe(struct usb_interface *interface,
/* Setup */
au0828_card_setup(dev);
+ /*
+ * Store the pointer to the au0828_dev so it can be accessed in
+ * au0828_usb_disconnect
+ */
+ usb_set_intfdata(interface, dev);
+
/* Analog TV */
retval = au0828_analog_register(dev, interface);
if (retval) {
@@ -737,12 +743,6 @@ static int au0828_usb_probe(struct usb_interface *interface,
/* Remote controller */
au0828_rc_register(dev);
- /*
- * Store the pointer to the au0828_dev so it can be accessed in
- * au0828_usb_disconnect
- */
- usb_set_intfdata(interface, dev);
-
pr_info("Registered device AU0828 [%s]\n",
dev->board.name == NULL ? "Unset" : dev->board.name);
diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c
index a414a25e48a8..5e00019bce8a 100644
--- a/drivers/media/usb/au0828/au0828-video.c
+++ b/drivers/media/usb/au0828/au0828-video.c
@@ -1182,7 +1182,6 @@ static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd,
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- struct video_device *vdev = video_devdata(file);
struct au0828_dev *dev = video_drvdata(file);
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
@@ -1193,16 +1192,10 @@ static int vidioc_querycap(struct file *file, void *priv,
usb_make_path(dev->usbdev, cap->bus_info, sizeof(cap->bus_info));
/* set the device capabilities */
- cap->device_caps = V4L2_CAP_AUDIO |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING |
- V4L2_CAP_TUNER;
- if (vdev->vfl_type == VFL_TYPE_GRABBER)
- cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE;
- else
- cap->device_caps |= V4L2_CAP_VBI_CAPTURE;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS |
- V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE;
+ cap->capabilities =
+ V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
+ V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -1991,6 +1984,9 @@ int au0828_analog_register(struct au0828_dev *dev,
dev->vdev.lock = &dev->lock;
dev->vdev.queue = &dev->vb_vidq;
dev->vdev.queue->lock = &dev->vb_queue_lock;
+ dev->vdev.device_caps =
+ V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
+ V4L2_CAP_TUNER | V4L2_CAP_VIDEO_CAPTURE;
strscpy(dev->vdev.name, "au0828a video", sizeof(dev->vdev.name));
/* Setup the VBI device */
@@ -1999,6 +1995,9 @@ int au0828_analog_register(struct au0828_dev *dev,
dev->vbi_dev.lock = &dev->lock;
dev->vbi_dev.queue = &dev->vb_vbiq;
dev->vbi_dev.queue->lock = &dev->vb_vbi_queue_lock;
+ dev->vbi_dev.device_caps =
+ V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
+ V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE;
strscpy(dev->vbi_dev.name, "au0828a vbi", sizeof(dev->vbi_dev.name));
/* Init entities at the Media Controller */
diff --git a/drivers/media/usb/cpia2/cpia2_usb.c b/drivers/media/usb/cpia2/cpia2_usb.c
index b2268981c963..17468f7d78ed 100644
--- a/drivers/media/usb/cpia2/cpia2_usb.c
+++ b/drivers/media/usb/cpia2/cpia2_usb.c
@@ -893,7 +893,6 @@ static void cpia2_usb_disconnect(struct usb_interface *intf)
cpia2_unregister_camera(cam);
v4l2_device_disconnect(&cam->v4l2_dev);
mutex_unlock(&cam->v4l2_lock);
- v4l2_device_put(&cam->v4l2_dev);
if(cam->buffers) {
DBG("Wakeup waiting processes\n");
@@ -902,6 +901,8 @@ static void cpia2_usb_disconnect(struct usb_interface *intf)
wake_up_interruptible(&cam->wq_stream);
}
+ v4l2_device_put(&cam->v4l2_dev);
+
LOG("CPiA2 camera disconnected.\n");
}
diff --git a/drivers/media/usb/cpia2/cpia2_v4l.c b/drivers/media/usb/cpia2/cpia2_v4l.c
index da6a5b2f86d1..0feae825cebb 100644
--- a/drivers/media/usb/cpia2/cpia2_v4l.c
+++ b/drivers/media/usb/cpia2/cpia2_v4l.c
@@ -250,13 +250,6 @@ static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *v
if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) <0)
memset(vc->bus_info,0, sizeof(vc->bus_info));
-
- vc->device_caps = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
- vc->capabilities = vc->device_caps |
- V4L2_CAP_DEVICE_CAPS;
-
return 0;
}
@@ -1152,6 +1145,8 @@ int cpia2_register_camera(struct camera_data *cam)
cam->vdev.lock = &cam->v4l2_lock;
cam->vdev.ctrl_handler = hdl;
cam->vdev.v4l2_dev = &cam->v4l2_dev;
+ cam->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING;
reset_camera_struct_v4l(cam);
diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c
index 26b05df698f0..e0d98ba8fdbf 100644
--- a/drivers/media/usb/cx231xx/cx231xx-cards.c
+++ b/drivers/media/usb/cx231xx/cx231xx-cards.c
@@ -1023,6 +1023,8 @@ struct usb_device_id cx231xx_id_table[] = {
.driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER},
{USB_DEVICE(0x2040, 0xb123),
.driver_info = CX231XX_BOARD_HAUPPAUGE_955Q},
+ {USB_DEVICE(0x2040, 0xb124),
+ .driver_info = CX231XX_BOARD_HAUPPAUGE_955Q},
{USB_DEVICE(0x2040, 0xb151),
.driver_info = CX231XX_BOARD_HAUPPAUGE_935C},
{USB_DEVICE(0x2040, 0xb150),
diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c
index 8fbb9523c88d..e205f7f0a56a 100644
--- a/drivers/media/usb/cx231xx/cx231xx-dvb.c
+++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c
@@ -1147,6 +1147,7 @@ static int dvb_fini(struct cx231xx *dev)
if (dev->dvb) {
unregister_dvb(dev->dvb);
+ kfree(dev->dvb);
dev->dvb = NULL;
}
diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c
index f8820478d46b..b651ac7713ea 100644
--- a/drivers/media/usb/cx231xx/cx231xx-video.c
+++ b/drivers/media/usb/cx231xx/cx231xx-video.c
@@ -1555,30 +1555,19 @@ static int vidioc_streamoff(struct file *file, void *priv,
int cx231xx_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- struct video_device *vdev = video_devdata(file);
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
strscpy(cap->driver, "cx231xx", sizeof(cap->driver));
strscpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card));
usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
-
- if (vdev->vfl_type == VFL_TYPE_RADIO)
- cap->device_caps = V4L2_CAP_RADIO;
- else {
- cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
- if (vdev->vfl_type == VFL_TYPE_VBI)
- cap->device_caps |= V4L2_CAP_VBI_CAPTURE;
- else
- cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE;
- }
- if (dev->tuner_type != TUNER_ABSENT)
- cap->device_caps |= V4L2_CAP_TUNER;
- cap->capabilities = cap->device_caps | V4L2_CAP_READWRITE |
+ cap->capabilities = V4L2_CAP_READWRITE |
V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS;
if (video_is_registered(&dev->radio_dev))
cap->capabilities |= V4L2_CAP_RADIO;
+ if (dev->tuner_type != TUNER_ABSENT)
+ cap->capabilities |= V4L2_CAP_TUNER;
return 0;
}
@@ -2234,6 +2223,11 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
dev_err(dev->dev, "failed to initialize video media entity!\n");
#endif
dev->vdev.ctrl_handler = &dev->ctrl_handler;
+ dev->vdev.device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_CAPTURE;
+ if (dev->tuner_type != TUNER_ABSENT)
+ dev->vdev.device_caps |= V4L2_CAP_TUNER;
+
/* register v4l2 video video_device */
ret = video_register_device(&dev->vdev, VFL_TYPE_GRABBER,
video_nr[dev->devno]);
@@ -2262,6 +2256,11 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
dev_err(dev->dev, "failed to initialize vbi media entity!\n");
#endif
dev->vbi_dev.ctrl_handler = &dev->ctrl_handler;
+ dev->vbi_dev.device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
+ V4L2_CAP_VBI_CAPTURE;
+ if (dev->tuner_type != TUNER_ABSENT)
+ dev->vbi_dev.device_caps |= V4L2_CAP_TUNER;
+
/* register v4l2 vbi video_device */
ret = video_register_device(&dev->vbi_dev, VFL_TYPE_VBI,
vbi_nr[dev->devno]);
@@ -2277,6 +2276,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
cx231xx_vdev_init(dev, &dev->radio_dev,
&cx231xx_radio_template, "radio");
dev->radio_dev.ctrl_handler = &dev->radio_ctrl_handler;
+ dev->radio_dev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
ret = video_register_device(&dev->radio_dev, VFL_TYPE_RADIO,
radio_nr[dev->devno]);
if (ret < 0) {
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c
index de52309eaaab..3afd18733614 100644
--- a/drivers/media/usb/dvb-usb-v2/af9035.c
+++ b/drivers/media/usb/dvb-usb-v2/af9035.c
@@ -107,8 +107,6 @@ static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req)
memcpy(req->rbuf, &state->buf[ACK_HDR_LEN], req->rlen);
exit:
mutex_unlock(&d->usb_mutex);
- if (ret < 0)
- dev_dbg(&intf->dev, "failed=%d\n", ret);
return ret;
}
diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c
index 48fb0d41e03b..fb6d99dea31a 100644
--- a/drivers/media/usb/dvb-usb-v2/anysee.c
+++ b/drivers/media/usb/dvb-usb-v2/anysee.c
@@ -56,7 +56,7 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d,
/* TODO FIXME: dvb_usb_generic_rw() fails rarely with error code -32
* (EPIPE, Broken pipe). Function supports currently msleep() as a
* parameter but I would not like to use it, since according to
- * Documentation/timers/timers-howto.txt it should not be used such
+ * Documentation/timers/timers-howto.rst it should not be used such
* short, under < 20ms, sleeps. Repeating failed message would be
* better choice as not to add unwanted delays...
* Fixing that correctly is one of those or both;
diff --git a/drivers/media/usb/dvb-usb-v2/az6007.c b/drivers/media/usb/dvb-usb-v2/az6007.c
index 746926364535..62ee09f28a0b 100644
--- a/drivers/media/usb/dvb-usb-v2/az6007.c
+++ b/drivers/media/usb/dvb-usb-v2/az6007.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for AzureWave 6007 DVB-C/T USB2.0 and clones
*
@@ -10,15 +11,6 @@
* Copyright (c) 2010-2012 Mauro Carvalho Chehab
* Driver modified by in order to work with upstream drxk driver, and
* tons of bugs got fixed, and converted to use dvb-usb-v2.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation under version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include "drxk.h"
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c
index 91729a39a306..7e817ea506c6 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c
@@ -24,14 +24,19 @@ static int dvb_usb_v2_generic_io(struct dvb_usb_device *d,
ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev,
d->props->generic_bulk_ctrl_endpoint), wbuf, wlen,
&actual_length, 2000);
- if (ret < 0)
+ if (ret) {
dev_err(&d->udev->dev, "%s: usb_bulk_msg() failed=%d\n",
KBUILD_MODNAME, ret);
- else
- ret = actual_length != wlen ? -EIO : 0;
+ return ret;
+ }
+ if (actual_length != wlen) {
+ dev_err(&d->udev->dev, "%s: usb_bulk_msg() write length=%d, actual=%d\n",
+ KBUILD_MODNAME, wlen, actual_length);
+ return -EIO;
+ }
- /* an answer is expected, and no error before */
- if (!ret && rbuf && rlen) {
+ /* an answer is expected */
+ if (rbuf && rlen) {
if (d->props->generic_bulk_ctrl_delay)
usleep_range(d->props->generic_bulk_ctrl_delay,
d->props->generic_bulk_ctrl_delay
diff --git a/drivers/media/usb/dvb-usb-v2/dvbsky.c b/drivers/media/usb/dvb-usb-v2/dvbsky.c
index c41e10bd6ef7..8610487f2d72 100644
--- a/drivers/media/usb/dvb-usb-v2/dvbsky.c
+++ b/drivers/media/usb/dvb-usb-v2/dvbsky.c
@@ -91,8 +91,6 @@ static int dvbsky_gpio_ctrl(struct dvb_usb_device *d, u8 gport, u8 value)
obuf[1] = gport;
obuf[2] = value;
ret = dvbsky_usb_generic_rw(d, obuf, 3, ibuf, 1);
- if (ret)
- dev_err(&d->udev->dev, "failed=%d\n", ret);
return ret;
}
@@ -130,8 +128,6 @@ static int dvbsky_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
obuf[3] = msg[0].addr;
ret = dvbsky_usb_generic_rw(d, obuf, 4,
ibuf, msg[0].len + 1);
- if (ret)
- dev_err(&d->udev->dev, "failed=%d\n", ret);
if (!ret)
memcpy(msg[0].buf, &ibuf[1], msg[0].len);
} else {
@@ -142,8 +138,6 @@ static int dvbsky_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
memcpy(&obuf[3], msg[0].buf, msg[0].len);
ret = dvbsky_usb_generic_rw(d, obuf,
msg[0].len + 3, ibuf, 1);
- if (ret)
- dev_err(&d->udev->dev, "failed=%d\n", ret);
}
} else {
if ((msg[0].len > 60) || (msg[1].len > 60)) {
@@ -161,9 +155,6 @@ static int dvbsky_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
memcpy(&obuf[4], msg[0].buf, msg[0].len);
ret = dvbsky_usb_generic_rw(d, obuf,
msg[0].len + 4, ibuf, msg[1].len + 1);
- if (ret)
- dev_err(&d->udev->dev, "failed=%d\n", ret);
-
if (!ret)
memcpy(msg[1].buf, &ibuf[1], msg[1].len);
}
@@ -192,8 +183,6 @@ static int dvbsky_rc_query(struct dvb_usb_device *d)
obuf[0] = 0x10;
ret = dvbsky_usb_generic_rw(d, obuf, 1, ibuf, 2);
- if (ret)
- dev_err(&d->udev->dev, "failed=%d\n", ret);
if (ret == 0)
code = (ibuf[0] << 8) | ibuf[1];
if (code != 0xffff) {
diff --git a/drivers/media/usb/dvb-usb/Kconfig b/drivers/media/usb/dvb-usb/Kconfig
index 87dbae875177..1a3e5f965ae4 100644
--- a/drivers/media/usb/dvb-usb/Kconfig
+++ b/drivers/media/usb/dvb-usb/Kconfig
@@ -139,12 +139,24 @@ config DVB_USB_CXUSB
select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT
help
Say Y here to support the Conexant USB2.0 hybrid reference design.
- Currently, only DVB and ATSC modes are supported, analog mode
- shall be added in the future. Devices that require this module:
+ DVB and ATSC modes are supported, for a basic analog mode support
+ see the next option ("Analog support for the Conexant USB2.0 hybrid
+ reference design").
+ Devices that require this module:
Medion MD95700 hybrid USB2.0 device.
DViCO FusionHDTV (Bluebird) USB2.0 devices
+config DVB_USB_CXUSB_ANALOG
+ bool "Analog support for the Conexant USB2.0 hybrid reference design"
+ depends on DVB_USB_CXUSB && VIDEO_V4L2
+ select VIDEO_CX25840
+ select VIDEOBUF2_VMALLOC
+ help
+ Say Y here to enable basic analog mode support for the Conexant
+ USB2.0 hybrid reference design.
+ Currently this mode is supported only on a Medion MD95700 device.
+
config DVB_USB_M920X
tristate "Uli m920x DVB-T USB2.0 support"
depends on DVB_USB
diff --git a/drivers/media/usb/dvb-usb/Makefile b/drivers/media/usb/dvb-usb/Makefile
index 407d90ca8be0..28e4806a87cd 100644
--- a/drivers/media/usb/dvb-usb/Makefile
+++ b/drivers/media/usb/dvb-usb/Makefile
@@ -42,6 +42,9 @@ dvb-usb-digitv-objs := digitv.o
obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-digitv.o
dvb-usb-cxusb-objs := cxusb.o
+ifeq ($(CONFIG_DVB_USB_CXUSB_ANALOG),y)
+dvb-usb-cxusb-objs += cxusb-analog.o
+endif
obj-$(CONFIG_DVB_USB_CXUSB) += dvb-usb-cxusb.o
dvb-usb-ttusb2-objs := ttusb2.o
diff --git a/drivers/media/usb/dvb-usb/cxusb-analog.c b/drivers/media/usb/dvb-usb/cxusb-analog.c
new file mode 100644
index 000000000000..0699f718d052
--- /dev/null
+++ b/drivers/media/usb/dvb-usb/cxusb-analog.c
@@ -0,0 +1,1845 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// DVB USB compliant linux driver for Conexant USB reference design -
+// (analog part).
+//
+// Copyright (C) 2011, 2017, 2018
+// Maciej S. Szmigiero (mail@maciej.szmigiero.name)
+//
+// In case there are new analog / DVB-T hybrid devices released in the market
+// using the same general design as Medion MD95700: a CX25840 video decoder
+// outputting a BT.656 stream to a USB bridge chip which then forwards it to
+// the host in isochronous USB packets this code should be made generic, with
+// board specific bits implemented via separate card structures.
+//
+// This is, however, unlikely as the Medion model was released
+// years ago (in 2005).
+//
+// TODO:
+// * audio support,
+// * finish radio support (requires audio of course),
+// * VBI support,
+// * controls support
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/ktime.h>
+#include <linux/vmalloc.h>
+#include <media/drv-intf/cx25840.h>
+#include <media/tuner.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-subdev.h>
+#include <media/videobuf2-vmalloc.h>
+
+#include "cxusb.h"
+
+static int cxusb_medion_v_queue_setup(struct vb2_queue *q,
+ unsigned int *num_buffers,
+ unsigned int *num_planes,
+ unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct dvb_usb_device *dvbdev = vb2_get_drv_priv(q);
+ struct cxusb_medion_dev *cxdev = dvbdev->priv;
+ unsigned int size = cxdev->width * cxdev->height * 2;
+
+ if (*num_planes > 0) {
+ if (*num_planes != 1)
+ return -EINVAL;
+
+ if (sizes[0] < size)
+ return -EINVAL;
+ } else {
+ *num_planes = 1;
+ sizes[0] = size;
+ }
+
+ return 0;
+}
+
+static int cxusb_medion_v_buf_init(struct vb2_buffer *vb)
+{
+ struct dvb_usb_device *dvbdev = vb2_get_drv_priv(vb->vb2_queue);
+ struct cxusb_medion_dev *cxdev = dvbdev->priv;
+
+ cxusb_vprintk(dvbdev, OPS, "buffer init\n");
+
+ if (vb2_plane_size(vb, 0) < cxdev->width * cxdev->height * 2)
+ return -ENOMEM;
+
+ cxusb_vprintk(dvbdev, OPS, "buffer OK\n");
+
+ return 0;
+}
+
+static void cxusb_auxbuf_init(struct dvb_usb_device *dvbdev,
+ struct cxusb_medion_auxbuf *auxbuf,
+ u8 *buf, unsigned int len)
+{
+ cxusb_vprintk(dvbdev, AUXB, "initializing auxbuf of len %u\n", len);
+
+ auxbuf->buf = buf;
+ auxbuf->len = len;
+ auxbuf->paylen = 0;
+}
+
+static void cxusb_auxbuf_head_trim(struct dvb_usb_device *dvbdev,
+ struct cxusb_medion_auxbuf *auxbuf,
+ unsigned int pos)
+{
+ if (pos == 0)
+ return;
+
+ if (WARN_ON(pos > auxbuf->paylen))
+ return;
+
+ cxusb_vprintk(dvbdev, AUXB,
+ "trimming auxbuf len by %u to %u\n",
+ pos, auxbuf->paylen - pos);
+
+ memmove(auxbuf->buf, auxbuf->buf + pos, auxbuf->paylen - pos);
+ auxbuf->paylen -= pos;
+}
+
+static unsigned int cxusb_auxbuf_paylen(struct cxusb_medion_auxbuf *auxbuf)
+{
+ return auxbuf->paylen;
+}
+
+static bool cxusb_auxbuf_make_space(struct dvb_usb_device *dvbdev,
+ struct cxusb_medion_auxbuf *auxbuf,
+ unsigned int howmuch)
+{
+ unsigned int freespace;
+
+ if (WARN_ON(howmuch >= auxbuf->len))
+ howmuch = auxbuf->len - 1;
+
+ freespace = auxbuf->len - cxusb_auxbuf_paylen(auxbuf);
+
+ cxusb_vprintk(dvbdev, AUXB, "freespace is %u\n", freespace);
+
+ if (freespace >= howmuch)
+ return true;
+
+ howmuch -= freespace;
+
+ cxusb_vprintk(dvbdev, AUXB, "will overwrite %u bytes of buffer\n",
+ howmuch);
+
+ cxusb_auxbuf_head_trim(dvbdev, auxbuf, howmuch);
+
+ return false;
+}
+
+/* returns false if some data was overwritten */
+static bool cxusb_auxbuf_append_urb(struct dvb_usb_device *dvbdev,
+ struct cxusb_medion_auxbuf *auxbuf,
+ struct urb *urb)
+{
+ unsigned long len;
+ int i;
+ bool ret;
+
+ for (i = 0, len = 0; i < urb->number_of_packets; i++)
+ len += urb->iso_frame_desc[i].actual_length;
+
+ ret = cxusb_auxbuf_make_space(dvbdev, auxbuf, len);
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ unsigned int to_copy;
+
+ to_copy = urb->iso_frame_desc[i].actual_length;
+
+ memcpy(auxbuf->buf + auxbuf->paylen, urb->transfer_buffer +
+ urb->iso_frame_desc[i].offset, to_copy);
+
+ auxbuf->paylen += to_copy;
+ }
+
+ return ret;
+}
+
+static bool cxusb_auxbuf_copy(struct cxusb_medion_auxbuf *auxbuf,
+ unsigned int pos, unsigned char *dest,
+ unsigned int len)
+{
+ if (pos + len > auxbuf->paylen)
+ return false;
+
+ memcpy(dest, auxbuf->buf + pos, len);
+
+ return true;
+}
+
+static bool cxusb_medion_cf_refc_fld_chg(struct dvb_usb_device *dvbdev,
+ struct cxusb_bt656_params *bt656,
+ bool firstfield,
+ unsigned int maxlines,
+ unsigned int maxlinesamples,
+ unsigned char buf[4])
+{
+ bool firstfield_code = (buf[3] & CXUSB_BT656_FIELD_MASK) ==
+ CXUSB_BT656_FIELD_1;
+ unsigned int remlines;
+
+ if (bt656->line == 0 || firstfield == firstfield_code)
+ return false;
+
+ if (bt656->fmode == LINE_SAMPLES) {
+ unsigned int remsamples = maxlinesamples -
+ bt656->linesamples;
+
+ cxusb_vprintk(dvbdev, BT656,
+ "field %c after line %u field change\n",
+ firstfield ? '1' : '2', bt656->line);
+
+ if (bt656->buf && remsamples > 0) {
+ memset(bt656->buf, 0, remsamples);
+ bt656->buf += remsamples;
+
+ cxusb_vprintk(dvbdev, BT656,
+ "field %c line %u %u samples still remaining (of %u)\n",
+ firstfield ? '1' : '2',
+ bt656->line, remsamples,
+ maxlinesamples);
+ }
+
+ bt656->line++;
+ }
+
+ remlines = maxlines - bt656->line;
+ if (bt656->buf && remlines > 0) {
+ memset(bt656->buf, 0, remlines * maxlinesamples);
+ bt656->buf += remlines * maxlinesamples;
+
+ cxusb_vprintk(dvbdev, BT656,
+ "field %c %u lines still remaining (of %u)\n",
+ firstfield ? '1' : '2', remlines,
+ maxlines);
+ }
+
+ return true;
+}
+
+static void cxusb_medion_cf_refc_start_sch(struct dvb_usb_device *dvbdev,
+ struct cxusb_bt656_params *bt656,
+ bool firstfield,
+ unsigned char buf[4])
+{
+ bool firstfield_code = (buf[3] & CXUSB_BT656_FIELD_MASK) ==
+ CXUSB_BT656_FIELD_1;
+ bool sav_code = (buf[3] & CXUSB_BT656_SEAV_MASK) ==
+ CXUSB_BT656_SEAV_SAV;
+ bool vbi_code = (buf[3] & CXUSB_BT656_VBI_MASK) ==
+ CXUSB_BT656_VBI_ON;
+
+ if (!sav_code || firstfield != firstfield_code)
+ return;
+
+ if (!vbi_code) {
+ cxusb_vprintk(dvbdev, BT656, "line start @ pos %u\n",
+ bt656->pos);
+
+ bt656->linesamples = 0;
+ bt656->fmode = LINE_SAMPLES;
+ } else {
+ cxusb_vprintk(dvbdev, BT656, "VBI start @ pos %u\n",
+ bt656->pos);
+
+ bt656->fmode = VBI_SAMPLES;
+ }
+}
+
+static void cxusb_medion_cf_refc_line_smpl(struct dvb_usb_device *dvbdev,
+ struct cxusb_bt656_params *bt656,
+ bool firstfield,
+ unsigned int maxlinesamples,
+ unsigned char buf[4])
+{
+ bool sav_code = (buf[3] & CXUSB_BT656_SEAV_MASK) ==
+ CXUSB_BT656_SEAV_SAV;
+ unsigned int remsamples;
+
+ if (sav_code)
+ cxusb_vprintk(dvbdev, BT656,
+ "SAV in line samples @ line %u, pos %u\n",
+ bt656->line, bt656->pos);
+
+ remsamples = maxlinesamples - bt656->linesamples;
+ if (bt656->buf && remsamples > 0) {
+ memset(bt656->buf, 0, remsamples);
+ bt656->buf += remsamples;
+
+ cxusb_vprintk(dvbdev, BT656,
+ "field %c line %u %u samples still remaining (of %u)\n",
+ firstfield ? '1' : '2', bt656->line, remsamples,
+ maxlinesamples);
+ }
+
+ bt656->fmode = START_SEARCH;
+ bt656->line++;
+}
+
+static void cxusb_medion_cf_refc_vbi_smpl(struct dvb_usb_device *dvbdev,
+ struct cxusb_bt656_params *bt656,
+ unsigned char buf[4])
+{
+ bool sav_code = (buf[3] & CXUSB_BT656_SEAV_MASK) ==
+ CXUSB_BT656_SEAV_SAV;
+
+ if (sav_code)
+ cxusb_vprintk(dvbdev, BT656, "SAV in VBI samples @ pos %u\n",
+ bt656->pos);
+
+ bt656->fmode = START_SEARCH;
+}
+
+/* returns whether the whole 4-byte code should be skipped in the buffer */
+static bool cxusb_medion_cf_ref_code(struct dvb_usb_device *dvbdev,
+ struct cxusb_bt656_params *bt656,
+ bool firstfield,
+ unsigned int maxlines,
+ unsigned int maxlinesamples,
+ unsigned char buf[4])
+{
+ if (bt656->fmode == START_SEARCH) {
+ cxusb_medion_cf_refc_start_sch(dvbdev, bt656, firstfield, buf);
+ } else if (bt656->fmode == LINE_SAMPLES) {
+ cxusb_medion_cf_refc_line_smpl(dvbdev, bt656, firstfield,
+ maxlinesamples, buf);
+ return false;
+ } else if (bt656->fmode == VBI_SAMPLES) {
+ cxusb_medion_cf_refc_vbi_smpl(dvbdev, bt656, buf);
+ return false;
+ }
+
+ return true;
+}
+
+static bool cxusb_medion_cs_start_sch(struct dvb_usb_device *dvbdev,
+ struct cxusb_medion_auxbuf *auxbuf,
+ struct cxusb_bt656_params *bt656,
+ unsigned int maxlinesamples)
+{
+ unsigned char buf[64];
+ unsigned int idx;
+ unsigned int tocheck = clamp_t(size_t, maxlinesamples / 4, 3,
+ sizeof(buf));
+
+ if (!cxusb_auxbuf_copy(auxbuf, bt656->pos + 1, buf, tocheck))
+ return false;
+
+ for (idx = 0; idx <= tocheck - 3; idx++)
+ if (memcmp(buf + idx, CXUSB_BT656_PREAMBLE, 3) == 0) {
+ bt656->pos += (1 + idx);
+ return true;
+ }
+
+ cxusb_vprintk(dvbdev, BT656, "line %u early start, pos %u\n",
+ bt656->line, bt656->pos);
+
+ bt656->linesamples = 0;
+ bt656->fmode = LINE_SAMPLES;
+
+ return true;
+}
+
+static void cxusb_medion_cs_line_smpl(struct cxusb_bt656_params *bt656,
+ unsigned int maxlinesamples,
+ unsigned char val)
+{
+ if (bt656->buf)
+ *(bt656->buf++) = val;
+
+ bt656->linesamples++;
+ bt656->pos++;
+
+ if (bt656->linesamples >= maxlinesamples) {
+ bt656->fmode = START_SEARCH;
+ bt656->line++;
+ }
+}
+
+static bool cxusb_medion_copy_samples(struct dvb_usb_device *dvbdev,
+ struct cxusb_medion_auxbuf *auxbuf,
+ struct cxusb_bt656_params *bt656,
+ unsigned int maxlinesamples,
+ unsigned char val)
+{
+ if (bt656->fmode == START_SEARCH && bt656->line > 0)
+ return cxusb_medion_cs_start_sch(dvbdev, auxbuf, bt656,
+ maxlinesamples);
+ else if (bt656->fmode == LINE_SAMPLES)
+ cxusb_medion_cs_line_smpl(bt656, maxlinesamples, val);
+ else /* TODO: copy VBI samples */
+ bt656->pos++;
+
+ return true;
+}
+
+static bool cxusb_medion_copy_field(struct dvb_usb_device *dvbdev,
+ struct cxusb_medion_auxbuf *auxbuf,
+ struct cxusb_bt656_params *bt656,
+ bool firstfield,
+ unsigned int maxlines,
+ unsigned int maxlinesmpls)
+{
+ while (bt656->line < maxlines) {
+ unsigned char val;
+
+ if (!cxusb_auxbuf_copy(auxbuf, bt656->pos, &val, 1))
+ break;
+
+ if (val == CXUSB_BT656_PREAMBLE[0]) {
+ unsigned char buf[4];
+
+ buf[0] = val;
+ if (!cxusb_auxbuf_copy(auxbuf, bt656->pos + 1,
+ buf + 1, 3))
+ break;
+
+ if (buf[1] == CXUSB_BT656_PREAMBLE[1] &&
+ buf[2] == CXUSB_BT656_PREAMBLE[2]) {
+ /*
+ * is this a field change?
+ * if so, terminate copying the current field
+ */
+ if (cxusb_medion_cf_refc_fld_chg(dvbdev,
+ bt656,
+ firstfield,
+ maxlines,
+ maxlinesmpls,
+ buf))
+ return true;
+
+ if (cxusb_medion_cf_ref_code(dvbdev, bt656,
+ firstfield,
+ maxlines,
+ maxlinesmpls,
+ buf))
+ bt656->pos += 4;
+
+ continue;
+ }
+ }
+
+ if (!cxusb_medion_copy_samples(dvbdev, auxbuf, bt656,
+ maxlinesmpls, val))
+ break;
+ }
+
+ if (bt656->line < maxlines) {
+ cxusb_vprintk(dvbdev, BT656,
+ "end of buffer pos = %u, line = %u\n",
+ bt656->pos, bt656->line);
+ return false;
+ }
+
+ return true;
+}
+
+static bool cxusb_medion_v_process_auxbuf(struct cxusb_medion_dev *cxdev,
+ bool reset)
+{
+ struct dvb_usb_device *dvbdev = cxdev->dvbdev;
+ struct cxusb_bt656_params *bt656 = &cxdev->bt656;
+
+ /*
+ * if this is a new frame
+ * fetch a buffer from list
+ */
+ if (bt656->mode == NEW_FRAME) {
+ if (!list_empty(&cxdev->buflist)) {
+ cxdev->vbuf =
+ list_first_entry(&cxdev->buflist,
+ struct cxusb_medion_vbuffer,
+ list);
+ list_del(&cxdev->vbuf->list);
+ } else {
+ dev_warn(&dvbdev->udev->dev, "no free buffers\n");
+ }
+ }
+
+ if (bt656->mode == NEW_FRAME || reset) {
+ cxusb_vprintk(dvbdev, URB, "will copy field 1\n");
+ bt656->pos = 0;
+ bt656->mode = FIRST_FIELD;
+ bt656->fmode = START_SEARCH;
+ bt656->line = 0;
+
+ if (cxdev->vbuf) {
+ cxdev->vbuf->vb2.vb2_buf.timestamp = ktime_get_ns();
+ bt656->buf = vb2_plane_vaddr(&cxdev->vbuf->vb2.vb2_buf,
+ 0);
+ }
+ }
+
+ if (bt656->mode == FIRST_FIELD) {
+ if (!cxusb_medion_copy_field(dvbdev, &cxdev->auxbuf, bt656,
+ true, cxdev->height / 2,
+ cxdev->width * 2))
+ return false;
+
+ /*
+ * do not trim buffer there in case
+ * we need to reset the search later
+ */
+
+ cxusb_vprintk(dvbdev, URB, "will copy field 2\n");
+ bt656->mode = SECOND_FIELD;
+ bt656->fmode = START_SEARCH;
+ bt656->line = 0;
+ }
+
+ if (bt656->mode == SECOND_FIELD) {
+ if (!cxusb_medion_copy_field(dvbdev, &cxdev->auxbuf, bt656,
+ false, cxdev->height / 2,
+ cxdev->width * 2))
+ return false;
+
+ cxusb_auxbuf_head_trim(dvbdev, &cxdev->auxbuf, bt656->pos);
+
+ bt656->mode = NEW_FRAME;
+
+ if (cxdev->vbuf) {
+ vb2_set_plane_payload(&cxdev->vbuf->vb2.vb2_buf, 0,
+ cxdev->width * cxdev->height * 2);
+
+ cxdev->vbuf->vb2.field = cxdev->field_order;
+ cxdev->vbuf->vb2.sequence = cxdev->vbuf_sequence++;
+
+ vb2_buffer_done(&cxdev->vbuf->vb2.vb2_buf,
+ VB2_BUF_STATE_DONE);
+
+ cxdev->vbuf = NULL;
+ cxdev->bt656.buf = NULL;
+
+ cxusb_vprintk(dvbdev, URB, "frame done\n");
+ } else {
+ cxusb_vprintk(dvbdev, URB, "frame skipped\n");
+ cxdev->vbuf_sequence++;
+ }
+ }
+
+ return true;
+}
+
+static bool cxusb_medion_v_complete_handle_urb(struct cxusb_medion_dev *cxdev,
+ bool *auxbuf_reset)
+{
+ struct dvb_usb_device *dvbdev = cxdev->dvbdev;
+ unsigned int urbn;
+ struct urb *urb;
+ int ret;
+
+ *auxbuf_reset = false;
+
+ urbn = cxdev->nexturb;
+ if (!test_bit(urbn, &cxdev->urbcomplete))
+ return false;
+
+ clear_bit(urbn, &cxdev->urbcomplete);
+
+ do {
+ cxdev->nexturb++;
+ cxdev->nexturb %= CXUSB_VIDEO_URBS;
+ urb = cxdev->streamurbs[cxdev->nexturb];
+ } while (!urb);
+
+ urb = cxdev->streamurbs[urbn];
+ cxusb_vprintk(dvbdev, URB, "URB %u status = %d\n", urbn, urb->status);
+
+ if (urb->status == 0 || urb->status == -EXDEV) {
+ int i;
+ unsigned long len;
+
+ for (i = 0, len = 0; i < urb->number_of_packets; i++)
+ len += urb->iso_frame_desc[i].actual_length;
+
+ cxusb_vprintk(dvbdev, URB, "URB %u data len = %lu\n", urbn,
+ len);
+
+ if (len > 0) {
+ cxusb_vprintk(dvbdev, URB, "appending URB\n");
+
+ /*
+ * append new data to auxbuf while
+ * overwriting old data if necessary
+ *
+ * if any overwrite happens then we can no
+ * longer rely on consistency of the whole
+ * data so let's start again the current
+ * auxbuf frame assembling process from
+ * the beginning
+ */
+ *auxbuf_reset =
+ !cxusb_auxbuf_append_urb(dvbdev,
+ &cxdev->auxbuf,
+ urb);
+ }
+ }
+
+ cxusb_vprintk(dvbdev, URB, "URB %u resubmit\n", urbn);
+
+ ret = usb_submit_urb(urb, GFP_KERNEL);
+ if (ret != 0)
+ dev_err(&dvbdev->udev->dev,
+ "unable to resubmit URB %u (%d), you'll have to restart streaming\n",
+ urbn, ret);
+
+ /* next URB is complete already? reschedule us then to handle it */
+ return test_bit(cxdev->nexturb, &cxdev->urbcomplete);
+}
+
+static void cxusb_medion_v_complete_work(struct work_struct *work)
+{
+ struct cxusb_medion_dev *cxdev = container_of(work,
+ struct cxusb_medion_dev,
+ urbwork);
+ struct dvb_usb_device *dvbdev = cxdev->dvbdev;
+ bool auxbuf_reset;
+ bool reschedule;
+
+ mutex_lock(cxdev->videodev->lock);
+
+ cxusb_vprintk(dvbdev, URB, "worker called, stop_streaming = %d\n",
+ (int)cxdev->stop_streaming);
+
+ if (cxdev->stop_streaming)
+ goto unlock;
+
+ reschedule = cxusb_medion_v_complete_handle_urb(cxdev, &auxbuf_reset);
+
+ if (cxusb_medion_v_process_auxbuf(cxdev, auxbuf_reset))
+ /* reschedule us until auxbuf no longer can produce any frame */
+ reschedule = true;
+
+ if (reschedule) {
+ cxusb_vprintk(dvbdev, URB, "rescheduling worker\n");
+ schedule_work(&cxdev->urbwork);
+ }
+
+unlock:
+ mutex_unlock(cxdev->videodev->lock);
+}
+
+static void cxusb_medion_v_complete(struct urb *u)
+{
+ struct dvb_usb_device *dvbdev = u->context;
+ struct cxusb_medion_dev *cxdev = dvbdev->priv;
+ unsigned int i;
+
+ for (i = 0; i < CXUSB_VIDEO_URBS; i++)
+ if (cxdev->streamurbs[i] == u)
+ break;
+
+ if (i >= CXUSB_VIDEO_URBS) {
+ dev_err(&dvbdev->udev->dev,
+ "complete on unknown URB\n");
+ return;
+ }
+
+ cxusb_vprintk(dvbdev, URB, "URB %u complete\n", i);
+
+ set_bit(i, &cxdev->urbcomplete);
+ schedule_work(&cxdev->urbwork);
+}
+
+static void cxusb_medion_urbs_free(struct cxusb_medion_dev *cxdev)
+{
+ unsigned int i;
+
+ for (i = 0; i < CXUSB_VIDEO_URBS; i++)
+ if (cxdev->streamurbs[i]) {
+ kfree(cxdev->streamurbs[i]->transfer_buffer);
+ usb_free_urb(cxdev->streamurbs[i]);
+ cxdev->streamurbs[i] = NULL;
+ }
+}
+
+static void cxusb_medion_return_buffers(struct cxusb_medion_dev *cxdev,
+ bool requeue)
+{
+ struct cxusb_medion_vbuffer *vbuf, *vbuf_tmp;
+
+ list_for_each_entry_safe(vbuf, vbuf_tmp, &cxdev->buflist,
+ list) {
+ list_del(&vbuf->list);
+ vb2_buffer_done(&vbuf->vb2.vb2_buf,
+ requeue ? VB2_BUF_STATE_QUEUED :
+ VB2_BUF_STATE_ERROR);
+ }
+
+ if (cxdev->vbuf) {
+ vb2_buffer_done(&cxdev->vbuf->vb2.vb2_buf,
+ requeue ? VB2_BUF_STATE_QUEUED :
+ VB2_BUF_STATE_ERROR);
+
+ cxdev->vbuf = NULL;
+ cxdev->bt656.buf = NULL;
+ }
+}
+
+static int cxusb_medion_v_ss_auxbuf_alloc(struct cxusb_medion_dev *cxdev,
+ int *npackets)
+{
+ struct dvb_usb_device *dvbdev = cxdev->dvbdev;
+ u8 *buf;
+ unsigned int framelen, urblen, auxbuflen;
+
+ framelen = (cxdev->width * 2 + 4 + 4) *
+ (cxdev->height + 50 /* VBI lines */);
+
+ /*
+ * try to fit a whole frame into each URB, as long as doing so
+ * does not require very high order memory allocations
+ */
+ BUILD_BUG_ON(CXUSB_VIDEO_URB_MAX_SIZE / CXUSB_VIDEO_PKT_SIZE >
+ CXUSB_VIDEO_MAX_FRAME_PKTS);
+ *npackets = min_t(int, (framelen + CXUSB_VIDEO_PKT_SIZE - 1) /
+ CXUSB_VIDEO_PKT_SIZE,
+ CXUSB_VIDEO_URB_MAX_SIZE / CXUSB_VIDEO_PKT_SIZE);
+ urblen = *npackets * CXUSB_VIDEO_PKT_SIZE;
+
+ cxusb_vprintk(dvbdev, URB,
+ "each URB will have %d packets for total of %u bytes (%u x %u @ %u)\n",
+ *npackets, urblen, (unsigned int)cxdev->width,
+ (unsigned int)cxdev->height, framelen);
+
+ auxbuflen = framelen + urblen;
+
+ buf = vmalloc(auxbuflen);
+ if (!buf)
+ return -ENOMEM;
+
+ cxusb_auxbuf_init(dvbdev, &cxdev->auxbuf, buf, auxbuflen);
+
+ return 0;
+}
+
+static u32 cxusb_medion_norm2field_order(v4l2_std_id norm)
+{
+ bool is625 = norm & V4L2_STD_625_50;
+ bool is525 = norm & V4L2_STD_525_60;
+
+ if (!is625 && !is525)
+ return V4L2_FIELD_NONE;
+
+ if (is625 && is525)
+ return V4L2_FIELD_NONE;
+
+ if (is625)
+ return V4L2_FIELD_SEQ_TB;
+ else /* is525 */
+ return V4L2_FIELD_SEQ_BT;
+}
+
+static u32 cxusb_medion_field_order(struct cxusb_medion_dev *cxdev)
+{
+ struct dvb_usb_device *dvbdev = cxdev->dvbdev;
+ u32 field;
+ int ret;
+ v4l2_std_id norm;
+
+ /* TV tuner is PAL-only so it is always TB */
+ if (cxdev->input == 0)
+ return V4L2_FIELD_SEQ_TB;
+
+ field = cxusb_medion_norm2field_order(cxdev->norm);
+ if (field != V4L2_FIELD_NONE)
+ return field;
+
+ ret = v4l2_subdev_call(cxdev->cx25840, video, g_std, &norm);
+ if (ret != 0) {
+ cxusb_vprintk(dvbdev, OPS,
+ "cannot get current standard for input %u\n",
+ (unsigned int)cxdev->input);
+ } else {
+ field = cxusb_medion_norm2field_order(norm);
+ if (field != V4L2_FIELD_NONE)
+ return field;
+ }
+
+ dev_warn(&dvbdev->udev->dev,
+ "cannot determine field order for the current standard setup and received signal, using TB\n");
+ return V4L2_FIELD_SEQ_TB;
+}
+
+static int cxusb_medion_v_start_streaming(struct vb2_queue *q,
+ unsigned int count)
+{
+ struct dvb_usb_device *dvbdev = vb2_get_drv_priv(q);
+ struct cxusb_medion_dev *cxdev = dvbdev->priv;
+ u8 streamon_params[2] = { 0x03, 0x00 };
+ int npackets, i;
+ int ret;
+
+ cxusb_vprintk(dvbdev, OPS, "should start streaming\n");
+
+ if (cxdev->stop_streaming) {
+ /* stream is being stopped */
+ ret = -EBUSY;
+ goto ret_retbufs;
+ }
+
+ cxdev->field_order = cxusb_medion_field_order(cxdev);
+
+ ret = v4l2_subdev_call(cxdev->cx25840, video, s_stream, 1);
+ if (ret != 0) {
+ dev_err(&dvbdev->udev->dev,
+ "unable to start stream (%d)\n", ret);
+ goto ret_retbufs;
+ }
+
+ ret = cxusb_ctrl_msg(dvbdev, CMD_STREAMING_ON, streamon_params, 2,
+ NULL, 0);
+ if (ret != 0) {
+ dev_err(&dvbdev->udev->dev,
+ "unable to start streaming (%d)\n", ret);
+ goto ret_unstream_cx;
+ }
+
+ ret = cxusb_medion_v_ss_auxbuf_alloc(cxdev, &npackets);
+ if (ret != 0)
+ goto ret_unstream_md;
+
+ for (i = 0; i < CXUSB_VIDEO_URBS; i++) {
+ int framen;
+ u8 *streambuf;
+ struct urb *surb;
+
+ /*
+ * TODO: change this to an array of single pages to avoid
+ * doing a large continuous allocation when (if)
+ * s-g isochronous USB transfers are supported
+ */
+ streambuf = kmalloc(npackets * CXUSB_VIDEO_PKT_SIZE,
+ GFP_KERNEL);
+ if (!streambuf) {
+ if (i < 2) {
+ ret = -ENOMEM;
+ goto ret_freeab;
+ }
+ break;
+ }
+
+ surb = usb_alloc_urb(npackets, GFP_KERNEL);
+ if (!surb) {
+ kfree(streambuf);
+ ret = -ENOMEM;
+ goto ret_freeu;
+ }
+
+ cxdev->streamurbs[i] = surb;
+ surb->dev = dvbdev->udev;
+ surb->context = dvbdev;
+ surb->pipe = usb_rcvisocpipe(dvbdev->udev, 2);
+
+ surb->interval = 1;
+ surb->transfer_flags = URB_ISO_ASAP;
+
+ surb->transfer_buffer = streambuf;
+
+ surb->complete = cxusb_medion_v_complete;
+ surb->number_of_packets = npackets;
+ surb->transfer_buffer_length = npackets * CXUSB_VIDEO_PKT_SIZE;
+
+ for (framen = 0; framen < npackets; framen++) {
+ surb->iso_frame_desc[framen].offset =
+ CXUSB_VIDEO_PKT_SIZE * framen;
+
+ surb->iso_frame_desc[framen].length =
+ CXUSB_VIDEO_PKT_SIZE;
+ }
+ }
+
+ cxdev->urbcomplete = 0;
+ cxdev->nexturb = 0;
+ cxdev->vbuf_sequence = 0;
+
+ cxdev->vbuf = NULL;
+ cxdev->bt656.mode = NEW_FRAME;
+ cxdev->bt656.buf = NULL;
+
+ for (i = 0; i < CXUSB_VIDEO_URBS; i++)
+ if (cxdev->streamurbs[i]) {
+ ret = usb_submit_urb(cxdev->streamurbs[i],
+ GFP_KERNEL);
+ if (ret != 0)
+ dev_err(&dvbdev->udev->dev,
+ "URB %d submission failed (%d)\n", i,
+ ret);
+ }
+
+ return 0;
+
+ret_freeu:
+ cxusb_medion_urbs_free(cxdev);
+
+ret_freeab:
+ vfree(cxdev->auxbuf.buf);
+
+ret_unstream_md:
+ cxusb_ctrl_msg(dvbdev, CMD_STREAMING_OFF, NULL, 0, NULL, 0);
+
+ret_unstream_cx:
+ v4l2_subdev_call(cxdev->cx25840, video, s_stream, 0);
+
+ret_retbufs:
+ cxusb_medion_return_buffers(cxdev, true);
+
+ return ret;
+}
+
+static void cxusb_medion_v_stop_streaming(struct vb2_queue *q)
+{
+ struct dvb_usb_device *dvbdev = vb2_get_drv_priv(q);
+ struct cxusb_medion_dev *cxdev = dvbdev->priv;
+ int ret;
+ unsigned int i;
+
+ cxusb_vprintk(dvbdev, OPS, "should stop streaming\n");
+
+ if (WARN_ON(cxdev->stop_streaming))
+ return;
+
+ cxdev->stop_streaming = true;
+
+ cxusb_ctrl_msg(dvbdev, CMD_STREAMING_OFF, NULL, 0, NULL, 0);
+
+ ret = v4l2_subdev_call(cxdev->cx25840, video, s_stream, 0);
+ if (ret != 0)
+ dev_err(&dvbdev->udev->dev, "unable to stop stream (%d)\n",
+ ret);
+
+ /* let URB completion run */
+ mutex_unlock(cxdev->videodev->lock);
+
+ for (i = 0; i < CXUSB_VIDEO_URBS; i++)
+ if (cxdev->streamurbs[i])
+ usb_kill_urb(cxdev->streamurbs[i]);
+
+ flush_work(&cxdev->urbwork);
+
+ mutex_lock(cxdev->videodev->lock);
+
+ /* free transfer buffer and URB */
+ vfree(cxdev->auxbuf.buf);
+
+ cxusb_medion_urbs_free(cxdev);
+
+ cxusb_medion_return_buffers(cxdev, false);
+
+ cxdev->stop_streaming = false;
+}
+
+static void cxusub_medion_v_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *v4l2buf = to_vb2_v4l2_buffer(vb);
+ struct cxusb_medion_vbuffer *vbuf =
+ container_of(v4l2buf, struct cxusb_medion_vbuffer, vb2);
+ struct dvb_usb_device *dvbdev = vb2_get_drv_priv(vb->vb2_queue);
+ struct cxusb_medion_dev *cxdev = dvbdev->priv;
+
+ /* cxusb_vprintk(dvbdev, OPS, "mmmm.. a fresh buffer...\n"); */
+
+ list_add_tail(&vbuf->list, &cxdev->buflist);
+}
+
+static const struct vb2_ops cxdev_video_qops = {
+ .queue_setup = cxusb_medion_v_queue_setup,
+ .buf_init = cxusb_medion_v_buf_init,
+ .start_streaming = cxusb_medion_v_start_streaming,
+ .stop_streaming = cxusb_medion_v_stop_streaming,
+ .buf_queue = cxusub_medion_v_buf_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish
+};
+
+static const __u32 videocaps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER |
+ V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+static const __u32 radiocaps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+
+static int cxusb_medion_v_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct dvb_usb_device *dvbdev = video_drvdata(file);
+
+ strscpy(cap->driver, dvbdev->udev->dev.driver->name,
+ sizeof(cap->driver));
+ strscpy(cap->card, "Medion 95700", sizeof(cap->card));
+ usb_make_path(dvbdev->udev, cap->bus_info, sizeof(cap->bus_info));
+
+ cap->capabilities = videocaps | radiocaps | V4L2_CAP_DEVICE_CAPS;
+
+ return 0;
+}
+
+static int cxusb_medion_v_enum_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f)
+{
+ if (f->index != 0)
+ return -EINVAL;
+
+ f->pixelformat = V4L2_PIX_FMT_UYVY;
+
+ return 0;
+}
+
+static int cxusb_medion_g_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct dvb_usb_device *dvbdev = video_drvdata(file);
+ struct cxusb_medion_dev *cxdev = dvbdev->priv;
+
+ f->fmt.pix.width = cxdev->width;
+ f->fmt.pix.height = cxdev->height;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
+ f->fmt.pix.field = vb2_start_streaming_called(&cxdev->videoqueue) ?
+ cxdev->field_order : cxusb_medion_field_order(cxdev);
+ f->fmt.pix.bytesperline = cxdev->width * 2;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height;
+
+ return 0;
+}
+
+static int cxusb_medion_try_s_fmt_vid_cap(struct file *file,
+ struct v4l2_format *f,
+ bool isset)
+{
+ struct dvb_usb_device *dvbdev = video_drvdata(file);
+ struct cxusb_medion_dev *cxdev = dvbdev->priv;
+ struct v4l2_subdev_format subfmt;
+ u32 field;
+ int ret;
+
+ if (isset && vb2_is_busy(&cxdev->videoqueue))
+ return -EBUSY;
+
+ field = vb2_start_streaming_called(&cxdev->videoqueue) ?
+ cxdev->field_order : cxusb_medion_field_order(cxdev);
+
+ memset(&subfmt, 0, sizeof(subfmt));
+ subfmt.which = isset ? V4L2_SUBDEV_FORMAT_ACTIVE :
+ V4L2_SUBDEV_FORMAT_TRY;
+ subfmt.format.width = f->fmt.pix.width & ~1;
+ subfmt.format.height = f->fmt.pix.height & ~1;
+ subfmt.format.code = MEDIA_BUS_FMT_FIXED;
+ subfmt.format.field = field;
+ subfmt.format.colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+ ret = v4l2_subdev_call(cxdev->cx25840, pad, set_fmt, NULL, &subfmt);
+ if (ret != 0)
+ return ret;
+
+ f->fmt.pix.width = subfmt.format.width;
+ f->fmt.pix.height = subfmt.format.height;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
+ f->fmt.pix.field = field;
+ f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
+ f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+ if (isset) {
+ cxdev->width = f->fmt.pix.width;
+ cxdev->height = f->fmt.pix.height;
+ }
+
+ return 0;
+}
+
+static int cxusb_medion_try_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ return cxusb_medion_try_s_fmt_vid_cap(file, f, false);
+}
+
+static int cxusb_medion_s_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ return cxusb_medion_try_s_fmt_vid_cap(file, f, true);
+}
+
+static const struct {
+ struct v4l2_input input;
+ u32 inputcfg;
+} cxusb_medion_inputs[] = {
+ { .input = { .name = "TV tuner", .type = V4L2_INPUT_TYPE_TUNER,
+ .tuner = 0, .std = V4L2_STD_PAL },
+ .inputcfg = CX25840_COMPOSITE2, },
+
+ { .input = { .name = "Composite", .type = V4L2_INPUT_TYPE_CAMERA,
+ .std = V4L2_STD_ALL },
+ .inputcfg = CX25840_COMPOSITE1, },
+
+ { .input = { .name = "S-Video", .type = V4L2_INPUT_TYPE_CAMERA,
+ .std = V4L2_STD_ALL },
+ .inputcfg = CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }
+};
+
+#define CXUSB_INPUT_CNT ARRAY_SIZE(cxusb_medion_inputs)
+
+static int cxusb_medion_enum_input(struct file *file, void *fh,
+ struct v4l2_input *inp)
+{
+ struct dvb_usb_device *dvbdev = video_drvdata(file);
+ struct cxusb_medion_dev *cxdev = dvbdev->priv;
+ u32 index = inp->index;
+
+ if (index >= CXUSB_INPUT_CNT)
+ return -EINVAL;
+
+ *inp = cxusb_medion_inputs[index].input;
+ inp->index = index;
+ inp->capabilities |= V4L2_IN_CAP_STD;
+
+ if (index == cxdev->input) {
+ int ret;
+ u32 status = 0;
+
+ ret = v4l2_subdev_call(cxdev->cx25840, video, g_input_status,
+ &status);
+ if (ret != 0)
+ dev_warn(&dvbdev->udev->dev,
+ "cx25840 input status query failed (%d)\n",
+ ret);
+ else
+ inp->status = status;
+ }
+
+ return 0;
+}
+
+static int cxusb_medion_g_input(struct file *file, void *fh,
+ unsigned int *i)
+{
+ struct dvb_usb_device *dvbdev = video_drvdata(file);
+ struct cxusb_medion_dev *cxdev = dvbdev->priv;
+
+ *i = cxdev->input;
+
+ return 0;
+}
+
+static int cxusb_medion_set_norm(struct cxusb_medion_dev *cxdev,
+ v4l2_std_id norm)
+{
+ struct dvb_usb_device *dvbdev = cxdev->dvbdev;
+ int ret;
+
+ cxusb_vprintk(dvbdev, OPS,
+ "trying to set standard for input %u to %lx\n",
+ (unsigned int)cxdev->input,
+ (unsigned long)norm);
+
+ /* no autodetection support */
+ if (norm == V4L2_STD_UNKNOWN)
+ return -EINVAL;
+
+ /* on composite or S-Video any std is acceptable */
+ if (cxdev->input != 0) {
+ ret = v4l2_subdev_call(cxdev->cx25840, video, s_std, norm);
+ if (ret)
+ return ret;
+
+ goto ret_savenorm;
+ }
+
+ /* TV tuner is only able to demodulate PAL */
+ if ((norm & ~V4L2_STD_PAL) != 0)
+ return -EINVAL;
+
+ ret = v4l2_subdev_call(cxdev->tda9887, video, s_std, norm);
+ if (ret != 0) {
+ dev_err(&dvbdev->udev->dev,
+ "tda9887 norm setup failed (%d)\n",
+ ret);
+ return ret;
+ }
+
+ ret = v4l2_subdev_call(cxdev->tuner, video, s_std, norm);
+ if (ret != 0) {
+ dev_err(&dvbdev->udev->dev,
+ "tuner norm setup failed (%d)\n",
+ ret);
+ return ret;
+ }
+
+ ret = v4l2_subdev_call(cxdev->cx25840, video, s_std, norm);
+ if (ret != 0) {
+ dev_err(&dvbdev->udev->dev,
+ "cx25840 norm setup failed (%d)\n",
+ ret);
+ return ret;
+ }
+
+ret_savenorm:
+ cxdev->norm = norm;
+
+ return 0;
+}
+
+static int cxusb_medion_s_input(struct file *file, void *fh,
+ unsigned int i)
+{
+ struct dvb_usb_device *dvbdev = video_drvdata(file);
+ struct cxusb_medion_dev *cxdev = dvbdev->priv;
+ int ret;
+ v4l2_std_id norm;
+
+ if (i >= CXUSB_INPUT_CNT)
+ return -EINVAL;
+
+ ret = v4l2_subdev_call(cxdev->cx25840, video, s_routing,
+ cxusb_medion_inputs[i].inputcfg, 0, 0);
+ if (ret != 0)
+ return ret;
+
+ cxdev->input = i;
+ cxdev->videodev->tvnorms = cxusb_medion_inputs[i].input.std;
+
+ norm = cxdev->norm & cxusb_medion_inputs[i].input.std;
+ if (norm == 0)
+ norm = cxusb_medion_inputs[i].input.std;
+
+ cxusb_medion_set_norm(cxdev, norm);
+
+ return 0;
+}
+
+static int cxusb_medion_g_tuner(struct file *file, void *fh,
+ struct v4l2_tuner *tuner)
+{
+ struct dvb_usb_device *dvbdev = video_drvdata(file);
+ struct cxusb_medion_dev *cxdev = dvbdev->priv;
+ struct video_device *vdev = video_devdata(file);
+ int ret;
+
+ if (tuner->index != 0)
+ return -EINVAL;
+
+ if (vdev->vfl_type == VFL_TYPE_GRABBER)
+ tuner->type = V4L2_TUNER_ANALOG_TV;
+ else
+ tuner->type = V4L2_TUNER_RADIO;
+
+ tuner->capability = 0;
+ tuner->afc = 0;
+
+ /*
+ * fills:
+ * always: capability (static), rangelow (static), rangehigh (static)
+ * radio mode: afc (may fail silently), rxsubchans (static), audmode
+ */
+ ret = v4l2_subdev_call(cxdev->tda9887, tuner, g_tuner, tuner);
+ if (ret != 0)
+ return ret;
+
+ /*
+ * fills:
+ * always: capability (static), rangelow (static), rangehigh (static)
+ * radio mode: rxsubchans (always stereo), audmode,
+ * signal (might be wrong)
+ */
+ ret = v4l2_subdev_call(cxdev->tuner, tuner, g_tuner, tuner);
+ if (ret != 0)
+ return ret;
+
+ tuner->signal = 0;
+
+ /*
+ * fills: TV mode: capability, rxsubchans, audmode, signal
+ */
+ ret = v4l2_subdev_call(cxdev->cx25840, tuner, g_tuner, tuner);
+ if (ret != 0)
+ return ret;
+
+ if (vdev->vfl_type == VFL_TYPE_GRABBER)
+ strscpy(tuner->name, "TV tuner", sizeof(tuner->name));
+ else
+ strscpy(tuner->name, "Radio tuner", sizeof(tuner->name));
+
+ memset(tuner->reserved, 0, sizeof(tuner->reserved));
+
+ return 0;
+}
+
+static int cxusb_medion_s_tuner(struct file *file, void *fh,
+ const struct v4l2_tuner *tuner)
+{
+ struct dvb_usb_device *dvbdev = video_drvdata(file);
+ struct cxusb_medion_dev *cxdev = dvbdev->priv;
+ struct video_device *vdev = video_devdata(file);
+ int ret;
+
+ if (tuner->index != 0)
+ return -EINVAL;
+
+ ret = v4l2_subdev_call(cxdev->tda9887, tuner, s_tuner, tuner);
+ if (ret != 0)
+ return ret;
+
+ ret = v4l2_subdev_call(cxdev->tuner, tuner, s_tuner, tuner);
+ if (ret != 0)
+ return ret;
+
+ /*
+ * make sure that cx25840 is in a correct TV / radio mode,
+ * since calls above may have changed it for tuner / IF demod
+ */
+ if (vdev->vfl_type == VFL_TYPE_GRABBER)
+ v4l2_subdev_call(cxdev->cx25840, video, s_std, cxdev->norm);
+ else
+ v4l2_subdev_call(cxdev->cx25840, tuner, s_radio);
+
+ return v4l2_subdev_call(cxdev->cx25840, tuner, s_tuner, tuner);
+}
+
+static int cxusb_medion_g_frequency(struct file *file, void *fh,
+ struct v4l2_frequency *freq)
+{
+ struct dvb_usb_device *dvbdev = video_drvdata(file);
+ struct cxusb_medion_dev *cxdev = dvbdev->priv;
+
+ if (freq->tuner != 0)
+ return -EINVAL;
+
+ return v4l2_subdev_call(cxdev->tuner, tuner, g_frequency, freq);
+}
+
+static int cxusb_medion_s_frequency(struct file *file, void *fh,
+ const struct v4l2_frequency *freq)
+{
+ struct dvb_usb_device *dvbdev = video_drvdata(file);
+ struct cxusb_medion_dev *cxdev = dvbdev->priv;
+ struct video_device *vdev = video_devdata(file);
+ int ret;
+
+ if (freq->tuner != 0)
+ return -EINVAL;
+
+ ret = v4l2_subdev_call(cxdev->tda9887, tuner, s_frequency, freq);
+ if (ret != 0)
+ return ret;
+
+ ret = v4l2_subdev_call(cxdev->tuner, tuner, s_frequency, freq);
+ if (ret != 0)
+ return ret;
+
+ /*
+ * make sure that cx25840 is in a correct TV / radio mode,
+ * since calls above may have changed it for tuner / IF demod
+ */
+ if (vdev->vfl_type == VFL_TYPE_GRABBER)
+ v4l2_subdev_call(cxdev->cx25840, video, s_std, cxdev->norm);
+ else
+ v4l2_subdev_call(cxdev->cx25840, tuner, s_radio);
+
+ return v4l2_subdev_call(cxdev->cx25840, tuner, s_frequency, freq);
+}
+
+static int cxusb_medion_g_std(struct file *file, void *fh,
+ v4l2_std_id *norm)
+{
+ struct dvb_usb_device *dvbdev = video_drvdata(file);
+ struct cxusb_medion_dev *cxdev = dvbdev->priv;
+
+ *norm = cxdev->norm;
+
+ if (*norm == V4L2_STD_UNKNOWN)
+ return -ENODATA;
+
+ return 0;
+}
+
+static int cxusb_medion_s_std(struct file *file, void *fh,
+ v4l2_std_id norm)
+{
+ struct dvb_usb_device *dvbdev = video_drvdata(file);
+ struct cxusb_medion_dev *cxdev = dvbdev->priv;
+
+ return cxusb_medion_set_norm(cxdev, norm);
+}
+
+static int cxusb_medion_querystd(struct file *file, void *fh,
+ v4l2_std_id *norm)
+{
+ struct dvb_usb_device *dvbdev = video_drvdata(file);
+ struct cxusb_medion_dev *cxdev = dvbdev->priv;
+ v4l2_std_id norm_mask;
+ int ret;
+
+ /*
+ * make sure we don't have improper std bits set for the TV tuner
+ * (could happen when no signal was present yet after reset)
+ */
+ if (cxdev->input == 0)
+ norm_mask = V4L2_STD_PAL;
+ else
+ norm_mask = V4L2_STD_ALL;
+
+ ret = v4l2_subdev_call(cxdev->cx25840, video, querystd, norm);
+ if (ret != 0) {
+ cxusb_vprintk(dvbdev, OPS,
+ "cannot get detected standard for input %u\n",
+ (unsigned int)cxdev->input);
+ return ret;
+ }
+
+ cxusb_vprintk(dvbdev, OPS, "input %u detected standard is %lx\n",
+ (unsigned int)cxdev->input, (unsigned long)*norm);
+ *norm &= norm_mask;
+
+ return 0;
+}
+
+static int cxusb_medion_log_status(struct file *file, void *fh)
+{
+ struct dvb_usb_device *dvbdev = video_drvdata(file);
+ struct cxusb_medion_dev *cxdev = dvbdev->priv;
+
+ v4l2_device_call_all(&cxdev->v4l2dev, 0, core, log_status);
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops cxusb_video_ioctl = {
+ .vidioc_querycap = cxusb_medion_v_querycap,
+ .vidioc_enum_fmt_vid_cap = cxusb_medion_v_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = cxusb_medion_g_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = cxusb_medion_s_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = cxusb_medion_try_fmt_vid_cap,
+ .vidioc_enum_input = cxusb_medion_enum_input,
+ .vidioc_g_input = cxusb_medion_g_input,
+ .vidioc_s_input = cxusb_medion_s_input,
+ .vidioc_g_tuner = cxusb_medion_g_tuner,
+ .vidioc_s_tuner = cxusb_medion_s_tuner,
+ .vidioc_g_frequency = cxusb_medion_g_frequency,
+ .vidioc_s_frequency = cxusb_medion_s_frequency,
+ .vidioc_g_std = cxusb_medion_g_std,
+ .vidioc_s_std = cxusb_medion_s_std,
+ .vidioc_querystd = cxusb_medion_querystd,
+ .vidioc_log_status = cxusb_medion_log_status,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff
+};
+
+static const struct v4l2_ioctl_ops cxusb_radio_ioctl = {
+ .vidioc_querycap = cxusb_medion_v_querycap,
+ .vidioc_g_tuner = cxusb_medion_g_tuner,
+ .vidioc_s_tuner = cxusb_medion_s_tuner,
+ .vidioc_g_frequency = cxusb_medion_g_frequency,
+ .vidioc_s_frequency = cxusb_medion_s_frequency,
+ .vidioc_log_status = cxusb_medion_log_status
+};
+
+/*
+ * in principle, this should be const, but s_io_pin_config is declared
+ * to take non-const, and gcc complains
+ */
+static struct v4l2_subdev_io_pin_config cxusub_medion_pin_config[] = {
+ { .pin = CX25840_PIN_DVALID_PRGM0, .function = CX25840_PAD_DEFAULT,
+ .strength = CX25840_PIN_DRIVE_MEDIUM },
+ { .pin = CX25840_PIN_PLL_CLK_PRGM7, .function = CX25840_PAD_AUX_PLL },
+ { .pin = CX25840_PIN_HRESET_PRGM2, .function = CX25840_PAD_ACTIVE,
+ .strength = CX25840_PIN_DRIVE_MEDIUM }
+};
+
+int cxusb_medion_analog_init(struct dvb_usb_device *dvbdev)
+{
+ struct cxusb_medion_dev *cxdev = dvbdev->priv;
+ u8 tuner_analog_msg_data[] = { 0x9c, 0x60, 0x85, 0x54 };
+ struct i2c_msg tuner_analog_msg = { .addr = 0x61, .flags = 0,
+ .buf = tuner_analog_msg_data,
+ .len =
+ sizeof(tuner_analog_msg_data) };
+ struct v4l2_subdev_format subfmt;
+ int ret;
+
+ /* switch tuner to analog mode so IF demod will become accessible */
+ ret = i2c_transfer(&dvbdev->i2c_adap, &tuner_analog_msg, 1);
+ if (ret != 1)
+ dev_warn(&dvbdev->udev->dev,
+ "tuner analog switch failed (%d)\n", ret);
+
+ /*
+ * cx25840 might have lost power during mode switching so we need
+ * to set it again
+ */
+ ret = v4l2_subdev_call(cxdev->cx25840, core, reset, 0);
+ if (ret != 0)
+ dev_warn(&dvbdev->udev->dev,
+ "cx25840 reset failed (%d)\n", ret);
+
+ ret = v4l2_subdev_call(cxdev->cx25840, video, s_routing,
+ CX25840_COMPOSITE1, 0, 0);
+ if (ret != 0)
+ dev_warn(&dvbdev->udev->dev,
+ "cx25840 initial input setting failed (%d)\n", ret);
+
+ /* composite */
+ cxdev->input = 1;
+ cxdev->videodev->tvnorms = V4L2_STD_ALL;
+ cxdev->norm = V4L2_STD_PAL;
+
+ /* TODO: setup audio samples insertion */
+
+ ret = v4l2_subdev_call(cxdev->cx25840, core, s_io_pin_config,
+ ARRAY_SIZE(cxusub_medion_pin_config),
+ cxusub_medion_pin_config);
+ if (ret != 0)
+ dev_warn(&dvbdev->udev->dev,
+ "cx25840 pin config failed (%d)\n", ret);
+
+ /* make sure that we aren't in radio mode */
+ v4l2_subdev_call(cxdev->tda9887, video, s_std, cxdev->norm);
+ v4l2_subdev_call(cxdev->tuner, video, s_std, cxdev->norm);
+ v4l2_subdev_call(cxdev->cx25840, video, s_std, cxdev->norm);
+
+ memset(&subfmt, 0, sizeof(subfmt));
+ subfmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ subfmt.format.width = cxdev->width;
+ subfmt.format.height = cxdev->height;
+ subfmt.format.code = MEDIA_BUS_FMT_FIXED;
+ subfmt.format.field = V4L2_FIELD_SEQ_TB;
+ subfmt.format.colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+ ret = v4l2_subdev_call(cxdev->cx25840, pad, set_fmt, NULL, &subfmt);
+ if (ret != 0)
+ dev_warn(&dvbdev->udev->dev,
+ "cx25840 format set failed (%d)\n", ret);
+
+ if (ret == 0) {
+ cxdev->width = subfmt.format.width;
+ cxdev->height = subfmt.format.height;
+ }
+
+ return 0;
+}
+
+static int cxusb_videoradio_open(struct file *f)
+{
+ struct dvb_usb_device *dvbdev = video_drvdata(f);
+ int ret;
+
+ /*
+ * no locking needed since this call only modifies analog
+ * state if there are no other analog handles currenly
+ * opened so ops done via them cannot create a conflict
+ */
+ ret = cxusb_medion_get(dvbdev, CXUSB_OPEN_ANALOG);
+ if (ret != 0)
+ return ret;
+
+ ret = v4l2_fh_open(f);
+ if (ret != 0)
+ goto ret_release;
+
+ cxusb_vprintk(dvbdev, OPS, "got open\n");
+
+ return 0;
+
+ret_release:
+ cxusb_medion_put(dvbdev);
+
+ return ret;
+}
+
+static int cxusb_videoradio_release(struct file *f)
+{
+ struct video_device *vdev = video_devdata(f);
+ struct dvb_usb_device *dvbdev = video_drvdata(f);
+ int ret;
+
+ cxusb_vprintk(dvbdev, OPS, "got release\n");
+
+ if (vdev->vfl_type == VFL_TYPE_GRABBER)
+ ret = vb2_fop_release(f);
+ else
+ ret = v4l2_fh_release(f);
+
+ cxusb_medion_put(dvbdev);
+
+ return ret;
+}
+
+static const struct v4l2_file_operations cxusb_video_fops = {
+ .owner = THIS_MODULE,
+ .read = vb2_fop_read,
+ .poll = vb2_fop_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = vb2_fop_mmap,
+ .open = cxusb_videoradio_open,
+ .release = cxusb_videoradio_release
+};
+
+static const struct v4l2_file_operations cxusb_radio_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = video_ioctl2,
+ .open = cxusb_videoradio_open,
+ .release = cxusb_videoradio_release
+};
+
+static void cxusb_medion_v4l2_release(struct v4l2_device *v4l2_dev)
+{
+ struct cxusb_medion_dev *cxdev =
+ container_of(v4l2_dev, struct cxusb_medion_dev, v4l2dev);
+ struct dvb_usb_device *dvbdev = cxdev->dvbdev;
+
+ cxusb_vprintk(dvbdev, OPS, "v4l2 device release\n");
+
+ v4l2_device_unregister(&cxdev->v4l2dev);
+
+ mutex_destroy(&cxdev->dev_lock);
+
+ while (completion_done(&cxdev->v4l2_release))
+ schedule();
+
+ complete(&cxdev->v4l2_release);
+}
+
+static void cxusb_medion_videodev_release(struct video_device *vdev)
+{
+ struct dvb_usb_device *dvbdev = video_get_drvdata(vdev);
+
+ cxusb_vprintk(dvbdev, OPS, "video device release\n");
+
+ vb2_queue_release(vdev->queue);
+
+ video_device_release(vdev);
+}
+
+static int cxusb_medion_register_analog_video(struct dvb_usb_device *dvbdev)
+{
+ struct cxusb_medion_dev *cxdev = dvbdev->priv;
+ int ret;
+
+ cxdev->videoqueue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ cxdev->videoqueue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ |
+ VB2_DMABUF;
+ cxdev->videoqueue.ops = &cxdev_video_qops;
+ cxdev->videoqueue.mem_ops = &vb2_vmalloc_memops;
+ cxdev->videoqueue.drv_priv = dvbdev;
+ cxdev->videoqueue.buf_struct_size =
+ sizeof(struct cxusb_medion_vbuffer);
+ cxdev->videoqueue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ cxdev->videoqueue.min_buffers_needed = 6;
+ cxdev->videoqueue.lock = &cxdev->dev_lock;
+
+ ret = vb2_queue_init(&cxdev->videoqueue);
+ if (ret) {
+ dev_err(&dvbdev->udev->dev,
+ "video queue init failed, ret = %d\n", ret);
+ return ret;
+ }
+
+ cxdev->videodev = video_device_alloc();
+ if (!cxdev->videodev) {
+ dev_err(&dvbdev->udev->dev, "video device alloc failed\n");
+ ret = -ENOMEM;
+ goto ret_qrelease;
+ }
+
+ cxdev->videodev->device_caps = videocaps;
+ cxdev->videodev->fops = &cxusb_video_fops;
+ cxdev->videodev->v4l2_dev = &cxdev->v4l2dev;
+ cxdev->videodev->queue = &cxdev->videoqueue;
+ strscpy(cxdev->videodev->name, "cxusb", sizeof(cxdev->videodev->name));
+ cxdev->videodev->vfl_dir = VFL_DIR_RX;
+ cxdev->videodev->ioctl_ops = &cxusb_video_ioctl;
+ cxdev->videodev->tvnorms = V4L2_STD_ALL;
+ cxdev->videodev->release = cxusb_medion_videodev_release;
+ cxdev->videodev->lock = &cxdev->dev_lock;
+ video_set_drvdata(cxdev->videodev, dvbdev);
+
+ ret = video_register_device(cxdev->videodev, VFL_TYPE_GRABBER, -1);
+ if (ret) {
+ dev_err(&dvbdev->udev->dev,
+ "video device register failed, ret = %d\n", ret);
+ goto ret_vrelease;
+ }
+
+ return 0;
+
+ret_vrelease:
+ video_device_release(cxdev->videodev);
+
+ret_qrelease:
+ vb2_queue_release(&cxdev->videoqueue);
+
+ return ret;
+}
+
+static int cxusb_medion_register_analog_radio(struct dvb_usb_device *dvbdev)
+{
+ struct cxusb_medion_dev *cxdev = dvbdev->priv;
+ int ret;
+
+ cxdev->radiodev = video_device_alloc();
+ if (!cxdev->radiodev) {
+ dev_err(&dvbdev->udev->dev, "radio device alloc failed\n");
+ return -ENOMEM;
+ }
+
+ cxdev->radiodev->device_caps = radiocaps;
+ cxdev->radiodev->fops = &cxusb_radio_fops;
+ cxdev->radiodev->v4l2_dev = &cxdev->v4l2dev;
+ strscpy(cxdev->radiodev->name, "cxusb", sizeof(cxdev->radiodev->name));
+ cxdev->radiodev->vfl_dir = VFL_DIR_RX;
+ cxdev->radiodev->ioctl_ops = &cxusb_radio_ioctl;
+ cxdev->radiodev->release = video_device_release;
+ cxdev->radiodev->lock = &cxdev->dev_lock;
+ video_set_drvdata(cxdev->radiodev, dvbdev);
+
+ ret = video_register_device(cxdev->radiodev, VFL_TYPE_RADIO, -1);
+ if (ret) {
+ dev_err(&dvbdev->udev->dev,
+ "radio device register failed, ret = %d\n", ret);
+ video_device_release(cxdev->radiodev);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int cxusb_medion_register_analog_subdevs(struct dvb_usb_device *dvbdev)
+{
+ struct cxusb_medion_dev *cxdev = dvbdev->priv;
+ int ret;
+ struct tuner_setup tun_setup;
+
+ /* attach cx25840 capture chip */
+ cxdev->cx25840 = v4l2_i2c_new_subdev(&cxdev->v4l2dev,
+ &dvbdev->i2c_adap,
+ "cx25840", 0x44, NULL);
+ if (!cxdev->cx25840) {
+ dev_err(&dvbdev->udev->dev, "cx25840 not found\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Initialize cx25840 chip by calling its subdevice init core op.
+ *
+ * This switches it into the generic mode that disables some of
+ * ivtv-related hacks in the cx25840 driver while allowing setting
+ * of the chip video output configuration (passed in the call below
+ * as the last argument).
+ */
+ ret = v4l2_subdev_call(cxdev->cx25840, core, init,
+ CX25840_VCONFIG_FMT_BT656 |
+ CX25840_VCONFIG_RES_8BIT |
+ CX25840_VCONFIG_VBIRAW_DISABLED |
+ CX25840_VCONFIG_ANCDATA_DISABLED |
+ CX25840_VCONFIG_ACTIVE_COMPOSITE |
+ CX25840_VCONFIG_VALID_ANDACTIVE |
+ CX25840_VCONFIG_HRESETW_NORMAL |
+ CX25840_VCONFIG_CLKGATE_NONE |
+ CX25840_VCONFIG_DCMODE_DWORDS);
+ if (ret != 0) {
+ dev_err(&dvbdev->udev->dev,
+ "cx25840 init failed (%d)\n", ret);
+ return ret;
+ }
+
+ /* attach analog tuner */
+ cxdev->tuner = v4l2_i2c_new_subdev(&cxdev->v4l2dev,
+ &dvbdev->i2c_adap,
+ "tuner", 0x61, NULL);
+ if (!cxdev->tuner) {
+ dev_err(&dvbdev->udev->dev, "tuner not found\n");
+ return -ENODEV;
+ }
+
+ /* configure it */
+ memset(&tun_setup, 0, sizeof(tun_setup));
+ tun_setup.addr = 0x61;
+ tun_setup.type = TUNER_PHILIPS_FMD1216ME_MK3;
+ tun_setup.mode_mask = T_RADIO | T_ANALOG_TV;
+ v4l2_subdev_call(cxdev->tuner, tuner, s_type_addr, &tun_setup);
+
+ /* attach IF demod */
+ cxdev->tda9887 = v4l2_i2c_new_subdev(&cxdev->v4l2dev,
+ &dvbdev->i2c_adap,
+ "tuner", 0x43, NULL);
+ if (!cxdev->tda9887) {
+ dev_err(&dvbdev->udev->dev, "tda9887 not found\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+int cxusb_medion_register_analog(struct dvb_usb_device *dvbdev)
+{
+ struct cxusb_medion_dev *cxdev = dvbdev->priv;
+ int ret;
+
+ mutex_init(&cxdev->dev_lock);
+
+ init_completion(&cxdev->v4l2_release);
+
+ cxdev->v4l2dev.release = cxusb_medion_v4l2_release;
+
+ ret = v4l2_device_register(&dvbdev->udev->dev, &cxdev->v4l2dev);
+ if (ret != 0) {
+ dev_err(&dvbdev->udev->dev,
+ "V4L2 device registration failed, ret = %d\n", ret);
+ mutex_destroy(&cxdev->dev_lock);
+ return ret;
+ }
+
+ ret = cxusb_medion_register_analog_subdevs(dvbdev);
+ if (ret)
+ goto ret_unregister;
+
+ INIT_WORK(&cxdev->urbwork, cxusb_medion_v_complete_work);
+ INIT_LIST_HEAD(&cxdev->buflist);
+
+ cxdev->width = 320;
+ cxdev->height = 240;
+
+ ret = cxusb_medion_register_analog_video(dvbdev);
+ if (ret)
+ goto ret_unregister;
+
+ ret = cxusb_medion_register_analog_radio(dvbdev);
+ if (ret)
+ goto ret_vunreg;
+
+ return 0;
+
+ret_vunreg:
+ video_unregister_device(cxdev->videodev);
+
+ret_unregister:
+ v4l2_device_put(&cxdev->v4l2dev);
+ wait_for_completion(&cxdev->v4l2_release);
+
+ return ret;
+}
+
+void cxusb_medion_unregister_analog(struct dvb_usb_device *dvbdev)
+{
+ struct cxusb_medion_dev *cxdev = dvbdev->priv;
+
+ cxusb_vprintk(dvbdev, OPS, "unregistering analog\n");
+
+ video_unregister_device(cxdev->radiodev);
+ video_unregister_device(cxdev->videodev);
+
+ v4l2_device_put(&cxdev->v4l2dev);
+ wait_for_completion(&cxdev->v4l2_release);
+
+ cxusb_vprintk(dvbdev, OPS, "analog unregistered\n");
+}
diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c
index 8039ba4ebf68..bac0778f7def 100644
--- a/drivers/media/usb/dvb-usb/cxusb.c
+++ b/drivers/media/usb/dvb-usb/cxusb.c
@@ -12,18 +12,21 @@
* design, so it can be reused for the "analogue-only" device (if it will
* appear at all).
*
- * TODO: Use the cx25840-driver for the analogue part
*
* Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@posteo.de)
* Copyright (C) 2006 Michael Krufky (mkrufky@linuxtv.org)
* Copyright (C) 2006, 2007 Chris Pascoe (c.pascoe@itee.uq.edu.au)
+ * Copyright (C) 2011, 2017 Maciej S. Szmigiero (mail@maciej.szmigiero.name)
*
* see Documentation/media/dvb-drivers/dvb-usb.rst for more information
*/
#include <media/tuner.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/device.h>
#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
#include "cxusb.h"
@@ -44,17 +47,45 @@
#include "si2157.h"
/* debug */
-static int dvb_usb_cxusb_debug;
+int dvb_usb_cxusb_debug;
module_param_named(debug, dvb_usb_cxusb_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
+MODULE_PARM_DESC(debug, "set debugging level (see cxusb.h)."
+ DVB_USB_DEBUG_STATUS);
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-#define deb_info(args...) dprintk(dvb_usb_cxusb_debug, 0x03, args)
-#define deb_i2c(args...) dprintk(dvb_usb_cxusb_debug, 0x02, args)
+#define deb_info(args...) dprintk(dvb_usb_cxusb_debug, CXUSB_DBG_MISC, args)
+#define deb_i2c(args...) dprintk(dvb_usb_cxusb_debug, CXUSB_DBG_I2C, args)
-static int cxusb_ctrl_msg(struct dvb_usb_device *d,
- u8 cmd, const u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+enum cxusb_table_index {
+ MEDION_MD95700,
+ DVICO_BLUEBIRD_LG064F_COLD,
+ DVICO_BLUEBIRD_LG064F_WARM,
+ DVICO_BLUEBIRD_DUAL_1_COLD,
+ DVICO_BLUEBIRD_DUAL_1_WARM,
+ DVICO_BLUEBIRD_LGZ201_COLD,
+ DVICO_BLUEBIRD_LGZ201_WARM,
+ DVICO_BLUEBIRD_TH7579_COLD,
+ DVICO_BLUEBIRD_TH7579_WARM,
+ DIGITALNOW_BLUEBIRD_DUAL_1_COLD,
+ DIGITALNOW_BLUEBIRD_DUAL_1_WARM,
+ DVICO_BLUEBIRD_DUAL_2_COLD,
+ DVICO_BLUEBIRD_DUAL_2_WARM,
+ DVICO_BLUEBIRD_DUAL_4,
+ DVICO_BLUEBIRD_DVB_T_NANO_2,
+ DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM,
+ AVERMEDIA_VOLAR_A868R,
+ DVICO_BLUEBIRD_DUAL_4_REV_2,
+ CONEXANT_D680_DMB,
+ MYGICA_D689,
+ MYGICA_T230,
+ NR__cxusb_table_index
+};
+
+static struct usb_device_id cxusb_table[];
+
+int cxusb_ctrl_msg(struct dvb_usb_device *d,
+ u8 cmd, const u8 *wbuf, int wlen, u8 *rbuf, int rlen)
{
struct cxusb_state *st = d->priv;
int ret;
@@ -86,7 +117,8 @@ static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff)
struct cxusb_state *st = d->priv;
u8 o[2], i;
- if (st->gpio_write_state[GPIO_TUNER] == onoff)
+ if (st->gpio_write_state[GPIO_TUNER] == onoff &&
+ !st->gpio_write_refresh[GPIO_TUNER])
return;
o[0] = GPIO_TUNER;
@@ -97,10 +129,11 @@ static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff)
deb_info("gpio_write failed.\n");
st->gpio_write_state[GPIO_TUNER] = onoff;
+ st->gpio_write_refresh[GPIO_TUNER] = false;
}
static int cxusb_bluebird_gpio_rw(struct dvb_usb_device *d, u8 changemask,
- u8 newval)
+ u8 newval)
{
u8 o[2], gpio_state;
int rc;
@@ -128,7 +161,7 @@ static void cxusb_nano2_led(struct dvb_usb_device *d, int onoff)
}
static int cxusb_d680_dmb_gpio_tuner(struct dvb_usb_device *d,
- u8 addr, int onoff)
+ u8 addr, int onoff)
{
u8 o[2] = {addr, onoff};
u8 i;
@@ -138,12 +171,12 @@ static int cxusb_d680_dmb_gpio_tuner(struct dvb_usb_device *d,
if (rc < 0)
return rc;
+
if (i == 0x01)
return 0;
- else {
- deb_info("gpio_write failed.\n");
- return -EIO;
- }
+
+ deb_info("gpio_write failed.\n");
+ return -EIO;
}
/* I2C */
@@ -158,7 +191,6 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
return -EAGAIN;
for (i = 0; i < num; i++) {
-
if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_MEDION)
switch (msg[i].addr) {
case 0x63:
@@ -184,13 +216,13 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
obuf[2] = msg[i].addr;
if (cxusb_ctrl_msg(d, CMD_I2C_READ,
obuf, 3,
- ibuf, 1+msg[i].len) < 0) {
+ ibuf, 1 + msg[i].len) < 0) {
warn("i2c read failed");
break;
}
memcpy(msg[i].buf, &ibuf[1], msg[i].len);
- } else if (i+1 < num && (msg[i+1].flags & I2C_M_RD) &&
- msg[i].addr == msg[i+1].addr) {
+ } else if (i + 1 < num && (msg[i + 1].flags & I2C_M_RD) &&
+ msg[i].addr == msg[i + 1].addr) {
/* write to then read from same address */
u8 obuf[MAX_XFER_SIZE], ibuf[MAX_XFER_SIZE];
@@ -207,19 +239,19 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
goto unlock;
}
obuf[0] = msg[i].len;
- obuf[1] = msg[i+1].len;
+ obuf[1] = msg[i + 1].len;
obuf[2] = msg[i].addr;
memcpy(&obuf[3], msg[i].buf, msg[i].len);
if (cxusb_ctrl_msg(d, CMD_I2C_READ,
- obuf, 3+msg[i].len,
- ibuf, 1+msg[i+1].len) < 0)
+ obuf, 3 + msg[i].len,
+ ibuf, 1 + msg[i + 1].len) < 0)
break;
if (ibuf[0] != 0x08)
deb_i2c("i2c read may have failed\n");
- memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len);
+ memcpy(msg[i + 1].buf, &ibuf[1], msg[i + 1].len);
i++;
} else {
@@ -237,7 +269,7 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
memcpy(&obuf[2], msg[i].buf, msg[i].len);
if (cxusb_ctrl_msg(d, CMD_I2C_WRITE, obuf,
- 2+msg[i].len, &ibuf,1) < 0)
+ 2 + msg[i].len, &ibuf, 1) < 0)
break;
if (ibuf != 0x08)
deb_i2c("i2c write may have failed\n");
@@ -256,7 +288,7 @@ unlock:
static u32 cxusb_i2c_func(struct i2c_adapter *adapter)
{
- return I2C_FUNC_I2C;
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
static struct i2c_algorithm cxusb_i2c_algo = {
@@ -264,29 +296,67 @@ static struct i2c_algorithm cxusb_i2c_algo = {
.functionality = cxusb_i2c_func,
};
-static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff)
+static int _cxusb_power_ctrl(struct dvb_usb_device *d, int onoff)
{
u8 b = 0;
+
+ deb_info("setting power %s\n", onoff ? "ON" : "OFF");
+
if (onoff)
return cxusb_ctrl_msg(d, CMD_POWER_ON, &b, 1, NULL, 0);
else
return cxusb_ctrl_msg(d, CMD_POWER_OFF, &b, 1, NULL, 0);
}
+static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ bool is_medion = d->props.devices[0].warm_ids[0] == &cxusb_table[MEDION_MD95700];
+ int ret;
+
+ if (is_medion && !onoff) {
+ struct cxusb_medion_dev *cxdev = d->priv;
+
+ mutex_lock(&cxdev->open_lock);
+
+ if (cxdev->open_type == CXUSB_OPEN_ANALOG) {
+ deb_info("preventing DVB core from setting power OFF while we are in analog mode\n");
+ ret = -EBUSY;
+ goto ret_unlock;
+ }
+ }
+
+ ret = _cxusb_power_ctrl(d, onoff);
+
+ret_unlock:
+ if (is_medion && !onoff) {
+ struct cxusb_medion_dev *cxdev = d->priv;
+
+ mutex_unlock(&cxdev->open_lock);
+ }
+
+ return ret;
+}
+
static int cxusb_aver_power_ctrl(struct dvb_usb_device *d, int onoff)
{
int ret;
+
if (!onoff)
return cxusb_ctrl_msg(d, CMD_POWER_OFF, NULL, 0, NULL, 0);
if (d->state == DVB_USB_STATE_INIT &&
usb_set_interface(d->udev, 0, 0) < 0)
err("set interface failed");
- do {} while (!(ret = cxusb_ctrl_msg(d, CMD_POWER_ON, NULL, 0, NULL, 0)) &&
- !(ret = cxusb_ctrl_msg(d, 0x15, NULL, 0, NULL, 0)) &&
- !(ret = cxusb_ctrl_msg(d, 0x17, NULL, 0, NULL, 0)) && 0);
+ do {
+ /* Nothing */
+ } while (!(ret = cxusb_ctrl_msg(d, CMD_POWER_ON, NULL, 0, NULL, 0)) &&
+ !(ret = cxusb_ctrl_msg(d, 0x15, NULL, 0, NULL, 0)) &&
+ !(ret = cxusb_ctrl_msg(d, 0x17, NULL, 0, NULL, 0)) && 0);
+
if (!ret) {
- /* FIXME: We don't know why, but we need to configure the
- * lgdt3303 with the register settings below on resume */
+ /*
+ * FIXME: We don't know why, but we need to configure the
+ * lgdt3303 with the register settings below on resume
+ */
int i;
u8 buf;
static const u8 bufs[] = {
@@ -304,7 +374,7 @@ static int cxusb_aver_power_ctrl(struct dvb_usb_device *d, int onoff)
msleep(20);
for (i = 0; i < ARRAY_SIZE(bufs); i += 4 / sizeof(u8)) {
ret = cxusb_ctrl_msg(d, CMD_I2C_WRITE,
- bufs+i, 4, &buf, 1);
+ bufs + i, 4, &buf, 1);
if (ret)
break;
if (buf != 0x8)
@@ -317,6 +387,7 @@ static int cxusb_aver_power_ctrl(struct dvb_usb_device *d, int onoff)
static int cxusb_bluebird_power_ctrl(struct dvb_usb_device *d, int onoff)
{
u8 b = 0;
+
if (onoff)
return cxusb_ctrl_msg(d, CMD_POWER_ON, &b, 1, NULL, 0);
else
@@ -338,6 +409,7 @@ static int cxusb_d680_dmb_power_ctrl(struct dvb_usb_device *d, int onoff)
{
int ret;
u8 b;
+
ret = cxusb_power_ctrl(d, onoff);
if (!onoff)
return ret;
@@ -350,11 +422,26 @@ static int cxusb_d680_dmb_power_ctrl(struct dvb_usb_device *d, int onoff)
static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
{
+ struct dvb_usb_device *dvbdev = adap->dev;
+ bool is_medion = dvbdev->props.devices[0].warm_ids[0] ==
+ &cxusb_table[MEDION_MD95700];
u8 buf[2] = { 0x03, 0x00 };
+
+ if (is_medion && onoff) {
+ int ret;
+
+ ret = cxusb_medion_get(dvbdev, CXUSB_OPEN_DIGITAL);
+ if (ret != 0)
+ return ret;
+ }
+
if (onoff)
- cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON, buf, 2, NULL, 0);
+ cxusb_ctrl_msg(dvbdev, CMD_STREAMING_ON, buf, 2, NULL, 0);
else
- cxusb_ctrl_msg(adap->dev, CMD_STREAMING_OFF, NULL, 0, NULL, 0);
+ cxusb_ctrl_msg(dvbdev, CMD_STREAMING_OFF, NULL, 0, NULL, 0);
+
+ if (is_medion && !onoff)
+ cxusb_medion_put(dvbdev);
return 0;
}
@@ -370,7 +457,7 @@ static int cxusb_aver_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
}
static int cxusb_read_status(struct dvb_frontend *fe,
- enum fe_status *status)
+ enum fe_status *status)
{
struct dvb_usb_adapter *adap = (struct dvb_usb_adapter *)fe->dvb->priv;
struct cxusb_state *state = (struct cxusb_state *)adap->dev->priv;
@@ -403,8 +490,8 @@ static void cxusb_d680_dmb_drain_message(struct dvb_usb_device *d)
return;
while (1) {
if (usb_bulk_msg(d->udev,
- usb_rcvbulkpipe(d->udev, ep),
- junk, junk_len, &rd_count, timeout) < 0)
+ usb_rcvbulkpipe(d->udev, ep),
+ junk, junk_len, &rd_count, timeout) < 0)
break;
if (!rd_count)
break;
@@ -426,8 +513,8 @@ static void cxusb_d680_dmb_drain_video(struct dvb_usb_device *d)
return;
while (1) {
if (usb_bulk_msg(d->udev,
- usb_rcvbulkpipe(d->udev, p->endpoint),
- junk, junk_len, &rd_count, timeout) < 0)
+ usb_rcvbulkpipe(d->udev, p->endpoint),
+ junk, junk_len, &rd_count, timeout) < 0)
break;
if (!rd_count)
break;
@@ -435,17 +522,18 @@ static void cxusb_d680_dmb_drain_video(struct dvb_usb_device *d)
kfree(junk);
}
-static int cxusb_d680_dmb_streaming_ctrl(
- struct dvb_usb_adapter *adap, int onoff)
+static int cxusb_d680_dmb_streaming_ctrl(struct dvb_usb_adapter *adap,
+ int onoff)
{
if (onoff) {
u8 buf[2] = { 0x03, 0x00 };
+
cxusb_d680_dmb_drain_video(adap->dev);
return cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON,
- buf, sizeof(buf), NULL, 0);
+ buf, sizeof(buf), NULL, 0);
} else {
int ret = cxusb_ctrl_msg(adap->dev,
- CMD_STREAMING_OFF, NULL, 0, NULL, 0);
+ CMD_STREAMING_OFF, NULL, 0, NULL, 0);
return ret;
}
}
@@ -465,8 +553,12 @@ static int cxusb_rc_query(struct dvb_usb_device *d)
static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d)
{
u8 ircode[4];
- struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD,
- .buf = ircode, .len = 4 };
+ struct i2c_msg msg = {
+ .addr = 0x6b,
+ .flags = I2C_M_RD,
+ .buf = ircode,
+ .len = 4
+ };
if (cxusb_i2c_xfer(&d->i2c_adap, &msg, 1) != 1)
return 0;
@@ -490,13 +582,13 @@ static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d)
return 0;
}
-static int cxusb_dee1601_demod_init(struct dvb_frontend* fe)
+static int cxusb_dee1601_demod_init(struct dvb_frontend *fe)
{
- static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x28 };
- static u8 reset [] = { RESET, 0x80 };
- static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
- static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0x20 };
- static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 };
+ static u8 clock_config[] = { CLOCK_CTL, 0x38, 0x28 };
+ static u8 reset[] = { RESET, 0x80 };
+ static u8 adc_ctl_1_cfg[] = { ADC_CTL_1, 0x40 };
+ static u8 agc_cfg[] = { AGC_TARGET, 0x28, 0x20 };
+ static u8 gpp_ctl_cfg[] = { GPP_CTL, 0x33 };
static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
mt352_write(fe, clock_config, sizeof(clock_config));
@@ -511,13 +603,14 @@ static int cxusb_dee1601_demod_init(struct dvb_frontend* fe)
return 0;
}
-static int cxusb_mt352_demod_init(struct dvb_frontend* fe)
-{ /* used in both lgz201 and th7579 */
- static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x29 };
- static u8 reset [] = { RESET, 0x80 };
- static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
- static u8 agc_cfg [] = { AGC_TARGET, 0x24, 0x20 };
- static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 };
+static int cxusb_mt352_demod_init(struct dvb_frontend *fe)
+{
+ /* used in both lgz201 and th7579 */
+ static u8 clock_config[] = { CLOCK_CTL, 0x38, 0x29 };
+ static u8 reset[] = { RESET, 0x80 };
+ static u8 adc_ctl_1_cfg[] = { ADC_CTL_1, 0x40 };
+ static u8 agc_cfg[] = { AGC_TARGET, 0x24, 0x20 };
+ static u8 gpp_ctl_cfg[] = { GPP_CTL, 0x33 };
static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
mt352_write(fe, clock_config, sizeof(clock_config));
@@ -627,9 +720,21 @@ static struct max2165_config mygica_d689_max2165_cfg = {
/* Callbacks for DVB USB */
static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
{
+ struct dvb_usb_device *dvbdev = adap->dev;
+ bool is_medion = dvbdev->props.devices[0].warm_ids[0] ==
+ &cxusb_table[MEDION_MD95700];
+
dvb_attach(simple_tuner_attach, adap->fe_adap[0].fe,
- &adap->dev->i2c_adap, 0x61,
+ &dvbdev->i2c_adap, 0x61,
TUNER_PHILIPS_FMD1216ME_MK3);
+
+ if (is_medion && adap->fe_adap[0].fe)
+ /*
+ * make sure that DVB core won't put to sleep (reset, really)
+ * tuner when we might be open in analog mode
+ */
+ adap->fe_adap[0].fe->ops.tuner_ops.sleep = NULL;
+
return 0;
}
@@ -642,7 +747,8 @@ static int cxusb_dee1601_tuner_attach(struct dvb_usb_adapter *adap)
static int cxusb_lgz201_tuner_attach(struct dvb_usb_adapter *adap)
{
- dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, NULL, DVB_PLL_LG_Z201);
+ dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61,
+ NULL, DVB_PLL_LG_Z201);
return 0;
}
@@ -702,7 +808,7 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap)
adap->fe_adap[0].fe->callback = dvico_bluebird_xc2028_callback;
fe = dvb_attach(xc2028_attach, adap->fe_adap[0].fe, &cfg);
- if (fe == NULL || fe->ops.tuner_ops.set_config == NULL)
+ if (!fe || !fe->ops.tuner_ops.set_config)
return -EIO;
fe->ops.tuner_ops.set_config(fe, &ctl);
@@ -720,33 +826,120 @@ static int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
static int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap)
{
struct dvb_frontend *fe;
+
fe = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe,
&adap->dev->i2c_adap, &d680_dmb_tuner);
- return (fe == NULL) ? -EIO : 0;
+ return (!fe) ? -EIO : 0;
}
static int cxusb_mygica_d689_tuner_attach(struct dvb_usb_adapter *adap)
{
struct dvb_frontend *fe;
+
fe = dvb_attach(max2165_attach, adap->fe_adap[0].fe,
&adap->dev->i2c_adap, &mygica_d689_max2165_cfg);
- return (fe == NULL) ? -EIO : 0;
+ return (!fe) ? -EIO : 0;
}
-static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap)
+static int cxusb_medion_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
{
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct dvb_usb_device *dvbdev = adap->dev;
+
+ if (acquire)
+ return cxusb_medion_get(dvbdev, CXUSB_OPEN_DIGITAL);
+
+ cxusb_medion_put(dvbdev);
+
+ return 0;
+}
+
+static int cxusb_medion_set_mode(struct dvb_usb_device *dvbdev, bool digital)
+{
+ struct cxusb_state *st = dvbdev->priv;
+ int ret;
u8 b;
- if (usb_set_interface(adap->dev->udev, 0, 6) < 0)
- err("set interface failed");
+ unsigned int i;
- cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, &b, 1);
+ /*
+ * switching mode while doing an I2C transaction often causes
+ * the device to crash
+ */
+ mutex_lock(&dvbdev->i2c_mutex);
+
+ if (digital) {
+ ret = usb_set_interface(dvbdev->udev, 0, 6);
+ if (ret != 0) {
+ dev_err(&dvbdev->udev->dev,
+ "digital interface selection failed (%d)\n",
+ ret);
+ goto ret_unlock;
+ }
+ } else {
+ ret = usb_set_interface(dvbdev->udev, 0, 1);
+ if (ret != 0) {
+ dev_err(&dvbdev->udev->dev,
+ "analog interface selection failed (%d)\n",
+ ret);
+ goto ret_unlock;
+ }
+ }
+
+ /* pipes need to be cleared after setting interface */
+ ret = usb_clear_halt(dvbdev->udev, usb_rcvbulkpipe(dvbdev->udev, 1));
+ if (ret != 0)
+ dev_warn(&dvbdev->udev->dev,
+ "clear halt on IN pipe failed (%d)\n",
+ ret);
+
+ ret = usb_clear_halt(dvbdev->udev, usb_sndbulkpipe(dvbdev->udev, 1));
+ if (ret != 0)
+ dev_warn(&dvbdev->udev->dev,
+ "clear halt on OUT pipe failed (%d)\n",
+ ret);
+
+ ret = cxusb_ctrl_msg(dvbdev, digital ? CMD_DIGITAL : CMD_ANALOG,
+ NULL, 0, &b, 1);
+ if (ret != 0) {
+ dev_err(&dvbdev->udev->dev, "mode switch failed (%d)\n",
+ ret);
+ goto ret_unlock;
+ }
+
+ /* mode switch seems to reset GPIO states */
+ for (i = 0; i < ARRAY_SIZE(st->gpio_write_refresh); i++)
+ st->gpio_write_refresh[i] = true;
+
+ret_unlock:
+ mutex_unlock(&dvbdev->i2c_mutex);
+
+ return ret;
+}
+
+static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ struct dvb_usb_device *dvbdev = adap->dev;
+ bool is_medion = dvbdev->props.devices[0].warm_ids[0] ==
+ &cxusb_table[MEDION_MD95700];
+
+ if (is_medion) {
+ int ret;
+
+ ret = cxusb_medion_set_mode(dvbdev, true);
+ if (ret)
+ return ret;
+ }
adap->fe_adap[0].fe = dvb_attach(cx22702_attach, &cxusb_cx22702_config,
- &adap->dev->i2c_adap);
- if ((adap->fe_adap[0].fe) != NULL)
- return 0;
+ &dvbdev->i2c_adap);
+ if (!adap->fe_adap[0].fe)
+ return -EIO;
- return -EIO;
+ if (is_medion)
+ adap->fe_adap[0].fe->ops.ts_bus_ctrl =
+ cxusb_medion_fe_ts_bus_ctrl;
+
+ return 0;
}
static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap)
@@ -760,7 +953,7 @@ static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap)
&cxusb_lgdt3303_config,
0x0e,
&adap->dev->i2c_adap);
- if ((adap->fe_adap[0].fe) != NULL)
+ if (adap->fe_adap[0].fe)
return 0;
return -EIO;
@@ -772,7 +965,7 @@ static int cxusb_aver_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap)
&cxusb_aver_lgdt3303_config,
0x0e,
&adap->dev->i2c_adap);
- if (adap->fe_adap[0].fe != NULL)
+ if (adap->fe_adap[0].fe)
return 0;
return -EIO;
@@ -788,7 +981,7 @@ static int cxusb_mt352_frontend_attach(struct dvb_usb_adapter *adap)
adap->fe_adap[0].fe = dvb_attach(mt352_attach, &cxusb_mt352_config,
&adap->dev->i2c_adap);
- if ((adap->fe_adap[0].fe) != NULL)
+ if (adap->fe_adap[0].fe)
return 0;
return -EIO;
@@ -803,13 +996,13 @@ static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap)
adap->fe_adap[0].fe = dvb_attach(mt352_attach, &cxusb_dee1601_config,
&adap->dev->i2c_adap);
- if ((adap->fe_adap[0].fe) != NULL)
+ if (adap->fe_adap[0].fe)
return 0;
adap->fe_adap[0].fe = dvb_attach(zl10353_attach,
&cxusb_zl10353_dee1601_config,
&adap->dev->i2c_adap);
- if ((adap->fe_adap[0].fe) != NULL)
+ if (adap->fe_adap[0].fe)
return 0;
return -EIO;
@@ -819,8 +1012,12 @@ static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap)
{
u8 ircode[4];
int i;
- struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD,
- .buf = ircode, .len = 4 };
+ struct i2c_msg msg = {
+ .addr = 0x6b,
+ .flags = I2C_M_RD,
+ .buf = ircode,
+ .len = 4
+ };
if (usb_set_interface(adap->dev->udev, 0, 1) < 0)
err("set interface failed");
@@ -836,7 +1033,7 @@ static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap)
dvb_attach(zl10353_attach,
&cxusb_zl10353_xc3028_config_no_i2c_gate,
&adap->dev->i2c_adap);
- if ((adap->fe_adap[0].fe) == NULL)
+ if (!adap->fe_adap[0].fe)
return -EIO;
/* try to determine if there is no IR decoder on the I2C bus */
@@ -934,7 +1131,7 @@ static struct dib7000p_config cxusb_dualdig4_rev2_config = {
};
struct dib0700_adapter_state {
- int (*set_param_save)(struct dvb_frontend *);
+ int (*set_param_save)(struct dvb_frontend *fe);
struct dib7000p_ops dib7000p_ops;
};
@@ -953,14 +1150,15 @@ static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap)
return -ENODEV;
if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
- &cxusb_dualdig4_rev2_config) < 0) {
- printk(KERN_WARNING "Unable to enumerate dib7000p\n");
+ &cxusb_dualdig4_rev2_config) < 0) {
+ pr_warn("Unable to enumerate dib7000p\n");
return -ENODEV;
}
- adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x80,
- &cxusb_dualdig4_rev2_config);
- if (adap->fe_adap[0].fe == NULL)
+ adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap,
+ 0x80,
+ &cxusb_dualdig4_rev2_config);
+ if (!adap->fe_adap[0].fe)
return -EIO;
return 0;
@@ -993,11 +1191,16 @@ static int dib7070_set_param_override(struct dvb_frontend *fe)
struct dib0700_adapter_state *state = adap->priv;
u16 offset;
- u8 band = BAND_OF_FREQUENCY(p->frequency/1000);
+ u8 band = BAND_OF_FREQUENCY(p->frequency / 1000);
+
switch (band) {
- case BAND_VHF: offset = 950; break;
+ case BAND_VHF:
+ offset = 950;
+ break;
default:
- case BAND_UHF: offset = 550; break;
+ case BAND_UHF:
+ offset = 550;
+ break;
}
state->dib7000p_ops.set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
@@ -1019,7 +1222,7 @@ static int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap)
DIBX000_I2C_INTERFACE_TUNER, 1);
if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c,
- &dib7070p_dib0070_config) == NULL)
+ &dib7070p_dib0070_config) == NULL)
return -ENODEV;
st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
@@ -1042,13 +1245,13 @@ static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap)
adap->fe_adap[0].fe = dvb_attach(zl10353_attach,
&cxusb_zl10353_xc3028_config,
&adap->dev->i2c_adap);
- if ((adap->fe_adap[0].fe) != NULL)
+ if (adap->fe_adap[0].fe)
return 0;
adap->fe_adap[0].fe = dvb_attach(mt352_attach,
&cxusb_mt352_xc3028_config,
&adap->dev->i2c_adap);
- if ((adap->fe_adap[0].fe) != NULL)
+ if (adap->fe_adap[0].fe)
return 0;
return -EIO;
@@ -1079,11 +1282,14 @@ static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap)
/* Unblock all USB pipes */
usb_clear_halt(d->udev,
- usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+ usb_sndbulkpipe(d->udev,
+ d->props.generic_bulk_ctrl_endpoint));
usb_clear_halt(d->udev,
- usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+ usb_rcvbulkpipe(d->udev,
+ d->props.generic_bulk_ctrl_endpoint));
usb_clear_halt(d->udev,
- usb_rcvbulkpipe(d->udev, d->props.adapter[0].fe[0].stream.endpoint));
+ usb_rcvbulkpipe(d->udev,
+ d->props.adapter[0].fe[0].stream.endpoint));
/* Drain USB pipes to avoid hang after reboot */
for (n = 0; n < 5; n++) {
@@ -1105,8 +1311,9 @@ static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap)
msleep(100);
/* Attach frontend */
- adap->fe_adap[0].fe = dvb_attach(lgs8gxx_attach, &d680_lgs8gl5_cfg, &d->i2c_adap);
- if (adap->fe_adap[0].fe == NULL)
+ adap->fe_adap[0].fe = dvb_attach(lgs8gxx_attach,
+ &d680_lgs8gl5_cfg, &d->i2c_adap);
+ if (!adap->fe_adap[0].fe)
return -EIO;
return 0;
@@ -1136,12 +1343,14 @@ static int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap)
/* Unblock all USB pipes */
usb_clear_halt(d->udev,
- usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+ usb_sndbulkpipe(d->udev,
+ d->props.generic_bulk_ctrl_endpoint));
usb_clear_halt(d->udev,
- usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+ usb_rcvbulkpipe(d->udev,
+ d->props.generic_bulk_ctrl_endpoint));
usb_clear_halt(d->udev,
- usb_rcvbulkpipe(d->udev, d->props.adapter[0].fe[0].stream.endpoint));
-
+ usb_rcvbulkpipe(d->udev,
+ d->props.adapter[0].fe[0].stream.endpoint));
/* Reset the tuner */
if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 0) < 0) {
@@ -1156,9 +1365,10 @@ static int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap)
msleep(100);
/* Attach frontend */
- adap->fe_adap[0].fe = dvb_attach(atbm8830_attach, &mygica_d689_atbm8830_cfg,
- &d->i2c_adap);
- if (adap->fe_adap[0].fe == NULL)
+ adap->fe_adap[0].fe = dvb_attach(atbm8830_attach,
+ &mygica_d689_atbm8830_cfg,
+ &d->i2c_adap);
+ if (!adap->fe_adap[0].fe)
return -EIO;
return 0;
@@ -1181,11 +1391,14 @@ static int cxusb_mygica_t230_frontend_attach(struct dvb_usb_adapter *adap)
/* Unblock all USB pipes */
usb_clear_halt(d->udev,
- usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+ usb_sndbulkpipe(d->udev,
+ d->props.generic_bulk_ctrl_endpoint));
usb_clear_halt(d->udev,
- usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+ usb_rcvbulkpipe(d->udev,
+ d->props.generic_bulk_ctrl_endpoint));
usb_clear_halt(d->udev,
- usb_rcvbulkpipe(d->udev, d->props.adapter[0].fe[0].stream.endpoint));
+ usb_rcvbulkpipe(d->udev,
+ d->props.adapter[0].fe[0].stream.endpoint));
/* attach frontend */
si2168_config.i2c_adapter = &adapter;
@@ -1198,7 +1411,7 @@ static int cxusb_mygica_t230_frontend_attach(struct dvb_usb_adapter *adap)
info.platform_data = &si2168_config;
request_module(info.type);
client_demod = i2c_new_device(&d->i2c_adap, &info);
- if (client_demod == NULL || client_demod->dev.driver == NULL)
+ if (!client_demod || !client_demod->dev.driver)
return -ENODEV;
if (!try_module_get(client_demod->dev.driver->owner)) {
@@ -1218,7 +1431,7 @@ static int cxusb_mygica_t230_frontend_attach(struct dvb_usb_adapter *adap)
info.platform_data = &si2157_config;
request_module(info.type);
client_tuner = i2c_new_device(adapter, &info);
- if (client_tuner == NULL || client_tuner->dev.driver == NULL) {
+ if (!client_tuner || !client_tuner->dev.driver) {
module_put(client_demod->dev.driver->owner);
i2c_unregister_device(client_demod);
return -ENODEV;
@@ -1309,6 +1522,104 @@ static int bluebird_patch_dvico_firmware_download(struct usb_device *udev,
return -EINVAL;
}
+int cxusb_medion_get(struct dvb_usb_device *dvbdev,
+ enum cxusb_open_type open_type)
+{
+ struct cxusb_medion_dev *cxdev = dvbdev->priv;
+ int ret = 0;
+
+ mutex_lock(&cxdev->open_lock);
+
+ if (WARN_ON((cxdev->open_type == CXUSB_OPEN_INIT ||
+ cxdev->open_type == CXUSB_OPEN_NONE) &&
+ cxdev->open_ctr != 0)) {
+ ret = -EINVAL;
+ goto ret_unlock;
+ }
+
+ if (cxdev->open_type == CXUSB_OPEN_INIT) {
+ ret = -EAGAIN;
+ goto ret_unlock;
+ }
+
+ if (cxdev->open_ctr == 0) {
+ if (cxdev->open_type != open_type) {
+ deb_info("will acquire and switch to %s\n",
+ open_type == CXUSB_OPEN_ANALOG ?
+ "analog" : "digital");
+
+ if (open_type == CXUSB_OPEN_ANALOG) {
+ ret = _cxusb_power_ctrl(dvbdev, 1);
+ if (ret != 0)
+ dev_warn(&dvbdev->udev->dev,
+ "powerup for analog switch failed (%d)\n",
+ ret);
+
+ ret = cxusb_medion_set_mode(dvbdev, false);
+ if (ret != 0)
+ goto ret_unlock;
+
+ ret = cxusb_medion_analog_init(dvbdev);
+ if (ret != 0)
+ goto ret_unlock;
+ } else { /* digital */
+ ret = _cxusb_power_ctrl(dvbdev, 1);
+ if (ret != 0)
+ dev_warn(&dvbdev->udev->dev,
+ "powerup for digital switch failed (%d)\n",
+ ret);
+
+ ret = cxusb_medion_set_mode(dvbdev, true);
+ if (ret != 0)
+ goto ret_unlock;
+ }
+
+ cxdev->open_type = open_type;
+ } else {
+ deb_info("reacquired idle %s\n",
+ open_type == CXUSB_OPEN_ANALOG ?
+ "analog" : "digital");
+ }
+
+ cxdev->open_ctr = 1;
+ } else if (cxdev->open_type == open_type) {
+ cxdev->open_ctr++;
+ deb_info("acquired %s\n", open_type == CXUSB_OPEN_ANALOG ?
+ "analog" : "digital");
+ } else {
+ ret = -EBUSY;
+ }
+
+ret_unlock:
+ mutex_unlock(&cxdev->open_lock);
+
+ return ret;
+}
+
+void cxusb_medion_put(struct dvb_usb_device *dvbdev)
+{
+ struct cxusb_medion_dev *cxdev = dvbdev->priv;
+
+ mutex_lock(&cxdev->open_lock);
+
+ if (cxdev->open_type == CXUSB_OPEN_INIT) {
+ WARN_ON(cxdev->open_ctr != 0);
+ cxdev->open_type = CXUSB_OPEN_NONE;
+ goto unlock;
+ }
+
+ if (!WARN_ON(cxdev->open_ctr < 1)) {
+ cxdev->open_ctr--;
+
+ deb_info("release %s\n",
+ cxdev->open_type == CXUSB_OPEN_ANALOG ?
+ "analog" : "digital");
+ }
+
+unlock:
+ mutex_unlock(&cxdev->open_lock);
+}
+
/* DVB USB Driver stuff */
static struct dvb_usb_device_properties cxusb_medion_properties;
static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties;
@@ -1324,41 +1635,141 @@ static struct dvb_usb_device_properties cxusb_d680_dmb_properties;
static struct dvb_usb_device_properties cxusb_mygica_d689_properties;
static struct dvb_usb_device_properties cxusb_mygica_t230_properties;
+static int cxusb_medion_priv_init(struct dvb_usb_device *dvbdev)
+{
+ struct cxusb_medion_dev *cxdev = dvbdev->priv;
+
+ cxdev->dvbdev = dvbdev;
+ cxdev->open_type = CXUSB_OPEN_INIT;
+ mutex_init(&cxdev->open_lock);
+
+ return 0;
+}
+
+static void cxusb_medion_priv_destroy(struct dvb_usb_device *dvbdev)
+{
+ struct cxusb_medion_dev *cxdev = dvbdev->priv;
+
+ mutex_destroy(&cxdev->open_lock);
+}
+
+static bool cxusb_medion_check_altsetting(struct usb_host_interface *as)
+{
+ unsigned int ctr;
+
+ for (ctr = 0; ctr < as->desc.bNumEndpoints; ctr++) {
+ if ((as->endpoint[ctr].desc.bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK) != 2)
+ continue;
+
+ if (as->endpoint[ctr].desc.bEndpointAddress & USB_DIR_IN &&
+ ((as->endpoint[ctr].desc.bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_ISOC))
+ return true;
+
+ break;
+ }
+
+ return false;
+}
+
+static bool cxusb_medion_check_intf(struct usb_interface *intf)
+{
+ unsigned int ctr;
+
+ if (intf->num_altsetting < 2) {
+ dev_err(intf->usb_dev, "no alternate interface");
+
+ return false;
+ }
+
+ for (ctr = 0; ctr < intf->num_altsetting; ctr++) {
+ if (intf->altsetting[ctr].desc.bAlternateSetting != 1)
+ continue;
+
+ if (cxusb_medion_check_altsetting(&intf->altsetting[ctr]))
+ return true;
+
+ break;
+ }
+
+ dev_err(intf->usb_dev, "no iso interface");
+
+ return false;
+}
+
static int cxusb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
- if (0 == dvb_usb_device_init(intf, &cxusb_medion_properties,
- THIS_MODULE, NULL, adapter_nr) ||
- 0 == dvb_usb_device_init(intf, &cxusb_bluebird_lgh064f_properties,
- THIS_MODULE, NULL, adapter_nr) ||
- 0 == dvb_usb_device_init(intf, &cxusb_bluebird_dee1601_properties,
- THIS_MODULE, NULL, adapter_nr) ||
- 0 == dvb_usb_device_init(intf, &cxusb_bluebird_lgz201_properties,
- THIS_MODULE, NULL, adapter_nr) ||
- 0 == dvb_usb_device_init(intf, &cxusb_bluebird_dtt7579_properties,
- THIS_MODULE, NULL, adapter_nr) ||
- 0 == dvb_usb_device_init(intf, &cxusb_bluebird_dualdig4_properties,
- THIS_MODULE, NULL, adapter_nr) ||
- 0 == dvb_usb_device_init(intf, &cxusb_bluebird_nano2_properties,
- THIS_MODULE, NULL, adapter_nr) ||
- 0 == dvb_usb_device_init(intf,
- &cxusb_bluebird_nano2_needsfirmware_properties,
- THIS_MODULE, NULL, adapter_nr) ||
- 0 == dvb_usb_device_init(intf, &cxusb_aver_a868r_properties,
- THIS_MODULE, NULL, adapter_nr) ||
- 0 == dvb_usb_device_init(intf,
- &cxusb_bluebird_dualdig4_rev2_properties,
- THIS_MODULE, NULL, adapter_nr) ||
- 0 == dvb_usb_device_init(intf, &cxusb_d680_dmb_properties,
- THIS_MODULE, NULL, adapter_nr) ||
- 0 == dvb_usb_device_init(intf, &cxusb_mygica_d689_properties,
- THIS_MODULE, NULL, adapter_nr) ||
- 0 == dvb_usb_device_init(intf, &cxusb_mygica_t230_properties,
- THIS_MODULE, NULL, adapter_nr) ||
- 0)
+ struct dvb_usb_device *dvbdev;
+ int ret;
+
+ /* Medion 95700 */
+ if (!dvb_usb_device_init(intf, &cxusb_medion_properties,
+ THIS_MODULE, &dvbdev, adapter_nr)) {
+ if (!cxusb_medion_check_intf(intf)) {
+ ret = -ENODEV;
+ goto ret_uninit;
+ }
+
+ _cxusb_power_ctrl(dvbdev, 1);
+ ret = cxusb_medion_set_mode(dvbdev, false);
+ if (ret)
+ goto ret_uninit;
+
+ ret = cxusb_medion_register_analog(dvbdev);
+
+ cxusb_medion_set_mode(dvbdev, true);
+ _cxusb_power_ctrl(dvbdev, 0);
+
+ if (ret != 0)
+ goto ret_uninit;
+
+ /* release device from INIT mode to normal operation */
+ cxusb_medion_put(dvbdev);
+
+ return 0;
+ } else if (!dvb_usb_device_init(intf,
+ &cxusb_bluebird_lgh064f_properties,
+ THIS_MODULE, NULL, adapter_nr) ||
+ !dvb_usb_device_init(intf,
+ &cxusb_bluebird_dee1601_properties,
+ THIS_MODULE, NULL, adapter_nr) ||
+ !dvb_usb_device_init(intf,
+ &cxusb_bluebird_lgz201_properties,
+ THIS_MODULE, NULL, adapter_nr) ||
+ !dvb_usb_device_init(intf,
+ &cxusb_bluebird_dtt7579_properties,
+ THIS_MODULE, NULL, adapter_nr) ||
+ !dvb_usb_device_init(intf,
+ &cxusb_bluebird_dualdig4_properties,
+ THIS_MODULE, NULL, adapter_nr) ||
+ !dvb_usb_device_init(intf,
+ &cxusb_bluebird_nano2_properties,
+ THIS_MODULE, NULL, adapter_nr) ||
+ !dvb_usb_device_init(intf,
+ &cxusb_bluebird_nano2_needsfirmware_properties,
+ THIS_MODULE, NULL, adapter_nr) ||
+ !dvb_usb_device_init(intf, &cxusb_aver_a868r_properties,
+ THIS_MODULE, NULL, adapter_nr) ||
+ !dvb_usb_device_init(intf,
+ &cxusb_bluebird_dualdig4_rev2_properties,
+ THIS_MODULE, NULL, adapter_nr) ||
+ !dvb_usb_device_init(intf, &cxusb_d680_dmb_properties,
+ THIS_MODULE, NULL, adapter_nr) ||
+ !dvb_usb_device_init(intf, &cxusb_mygica_d689_properties,
+ THIS_MODULE, NULL, adapter_nr) ||
+ !dvb_usb_device_init(intf, &cxusb_mygica_t230_properties,
+ THIS_MODULE, NULL, adapter_nr) ||
+ 0)
return 0;
return -EINVAL;
+
+ret_uninit:
+ dvb_usb_device_exit(intf);
+
+ return ret;
}
static void cxusb_disconnect(struct usb_interface *intf)
@@ -1367,6 +1778,9 @@ static void cxusb_disconnect(struct usb_interface *intf)
struct cxusb_state *st = d->priv;
struct i2c_client *client;
+ if (d->props.devices[0].warm_ids[0] == &cxusb_table[MEDION_MD95700])
+ cxusb_medion_unregister_analog(d);
+
/* remove I2C client for tuner */
client = st->i2c_client_tuner;
if (client) {
@@ -1384,31 +1798,6 @@ static void cxusb_disconnect(struct usb_interface *intf)
dvb_usb_device_exit(intf);
}
-enum cxusb_table_index {
- MEDION_MD95700,
- DVICO_BLUEBIRD_LG064F_COLD,
- DVICO_BLUEBIRD_LG064F_WARM,
- DVICO_BLUEBIRD_DUAL_1_COLD,
- DVICO_BLUEBIRD_DUAL_1_WARM,
- DVICO_BLUEBIRD_LGZ201_COLD,
- DVICO_BLUEBIRD_LGZ201_WARM,
- DVICO_BLUEBIRD_TH7579_COLD,
- DVICO_BLUEBIRD_TH7579_WARM,
- DIGITALNOW_BLUEBIRD_DUAL_1_COLD,
- DIGITALNOW_BLUEBIRD_DUAL_1_WARM,
- DVICO_BLUEBIRD_DUAL_2_COLD,
- DVICO_BLUEBIRD_DUAL_2_WARM,
- DVICO_BLUEBIRD_DUAL_4,
- DVICO_BLUEBIRD_DVB_T_NANO_2,
- DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM,
- AVERMEDIA_VOLAR_A868R,
- DVICO_BLUEBIRD_DUAL_4_REV_2,
- CONEXANT_D680_DMB,
- MYGICA_D689,
- MYGICA_T230,
- NR__cxusb_table_index
-};
-
static struct usb_device_id cxusb_table[NR__cxusb_table_index + 1] = {
[MEDION_MD95700] = {
USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700)
@@ -1438,10 +1827,12 @@ static struct usb_device_id cxusb_table[NR__cxusb_table_index + 1] = {
USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_WARM)
},
[DIGITALNOW_BLUEBIRD_DUAL_1_COLD] = {
- USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD)
+ USB_DEVICE(USB_VID_DVICO,
+ USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD)
},
[DIGITALNOW_BLUEBIRD_DUAL_1_WARM] = {
- USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM)
+ USB_DEVICE(USB_VID_DVICO,
+ USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM)
},
[DVICO_BLUEBIRD_DUAL_2_COLD] = {
USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD)
@@ -1456,7 +1847,8 @@ static struct usb_device_id cxusb_table[NR__cxusb_table_index + 1] = {
USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2)
},
[DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM] = {
- USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM)
+ USB_DEVICE(USB_VID_DVICO,
+ USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM)
},
[AVERMEDIA_VOLAR_A868R] = {
USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R)
@@ -1475,14 +1867,16 @@ static struct usb_device_id cxusb_table[NR__cxusb_table_index + 1] = {
},
{} /* Terminating entry */
};
-MODULE_DEVICE_TABLE (usb, cxusb_table);
+MODULE_DEVICE_TABLE(usb, cxusb_table);
static struct dvb_usb_device_properties cxusb_medion_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = CYPRESS_FX2,
- .size_of_priv = sizeof(struct cxusb_state),
+ .size_of_priv = sizeof(struct cxusb_medion_dev),
+ .priv_init = cxusb_medion_priv_init,
+ .priv_destroy = cxusb_medion_priv_destroy,
.num_adapters = 1,
.adapter = {
@@ -1503,7 +1897,7 @@ static struct dvb_usb_device_properties cxusb_medion_properties = {
}
}
},
- }},
+ } },
},
},
.power_ctrl = cxusb_power_ctrl,
@@ -1514,7 +1908,8 @@ static struct dvb_usb_device_properties cxusb_medion_properties = {
.num_device_descs = 1,
.devices = {
- { "Medion MD95700 (MDUSBTV-HYBRID)",
+ {
+ "Medion MD95700 (MDUSBTV-HYBRID)",
{ NULL },
{ &cxusb_table[MEDION_MD95700], NULL },
},
@@ -1527,8 +1922,10 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = {
.usb_ctrl = DEVICE_SPECIFIC,
.firmware = "dvb-usb-bluebird-01.fw",
.download_firmware = bluebird_patch_dvico_firmware_download,
- /* use usb alt setting 0 for EP4 transfer (dvb-t),
- use usb alt setting 7 for EP2 transfer (atsc) */
+ /*
+ * use usb alt setting 0 for EP4 transfer (dvb-t),
+ * use usb alt setting 7 for EP2 transfer (atsc)
+ */
.size_of_priv = sizeof(struct cxusb_state),
@@ -1552,7 +1949,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = {
}
}
},
- }},
+ } },
},
},
@@ -1585,8 +1982,10 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = {
.usb_ctrl = DEVICE_SPECIFIC,
.firmware = "dvb-usb-bluebird-01.fw",
.download_firmware = bluebird_patch_dvico_firmware_download,
- /* use usb alt setting 0 for EP4 transfer (dvb-t),
- use usb alt setting 7 for EP2 transfer (atsc) */
+ /*
+ * use usb alt setting 0 for EP4 transfer (dvb-t),
+ * use usb alt setting 7 for EP2 transfer (atsc)
+ */
.size_of_priv = sizeof(struct cxusb_state),
@@ -1609,7 +2008,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = {
}
}
},
- }},
+ } },
},
},
@@ -1634,7 +2033,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = {
{ &cxusb_table[DVICO_BLUEBIRD_DUAL_1_WARM], NULL },
},
{ "DigitalNow DVB-T Dual USB",
- { &cxusb_table[DIGITALNOW_BLUEBIRD_DUAL_1_COLD], NULL },
+ { &cxusb_table[DIGITALNOW_BLUEBIRD_DUAL_1_COLD], NULL },
{ &cxusb_table[DIGITALNOW_BLUEBIRD_DUAL_1_WARM], NULL },
},
{ "DViCO FusionHDTV DVB-T Dual Digital 2",
@@ -1650,8 +2049,10 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = {
.usb_ctrl = DEVICE_SPECIFIC,
.firmware = "dvb-usb-bluebird-01.fw",
.download_firmware = bluebird_patch_dvico_firmware_download,
- /* use usb alt setting 0 for EP4 transfer (dvb-t),
- use usb alt setting 7 for EP2 transfer (atsc) */
+ /*
+ * use usb alt setting 0 for EP4 transfer (dvb-t),
+ * use usb alt setting 7 for EP2 transfer (atsc)
+ */
.size_of_priv = sizeof(struct cxusb_state),
@@ -1675,7 +2076,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = {
}
}
},
- }},
+ } },
},
},
.power_ctrl = cxusb_bluebird_power_ctrl,
@@ -1706,8 +2107,11 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = {
.usb_ctrl = DEVICE_SPECIFIC,
.firmware = "dvb-usb-bluebird-01.fw",
.download_firmware = bluebird_patch_dvico_firmware_download,
- /* use usb alt setting 0 for EP4 transfer (dvb-t),
- use usb alt setting 7 for EP2 transfer (atsc) */
+
+ /*
+ * use usb alt setting 0 for EP4 transfer (dvb-t),
+ * use usb alt setting 7 for EP2 transfer (atsc)
+ */
.size_of_priv = sizeof(struct cxusb_state),
@@ -1731,7 +2135,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = {
}
}
},
- }},
+ } },
},
},
.power_ctrl = cxusb_bluebird_power_ctrl,
@@ -1783,7 +2187,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = {
}
}
},
- }},
+ } },
},
},
@@ -1837,7 +2241,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = {
}
}
},
- }},
+ } },
},
},
@@ -1864,7 +2268,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = {
}
};
-static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties = {
+static struct dvb_usb_device_properties
+cxusb_bluebird_nano2_needsfirmware_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = DEVICE_SPECIFIC,
@@ -1893,7 +2298,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_prope
}
}
},
- }},
+ } },
},
},
@@ -1912,10 +2317,11 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_prope
},
.num_device_descs = 1,
- .devices = {
- { "DViCO FusionHDTV DVB-T NANO2 w/o firmware",
+ .devices = { {
+ "DViCO FusionHDTV DVB-T NANO2 w/o firmware",
{ &cxusb_table[DVICO_BLUEBIRD_DVB_T_NANO_2], NULL },
- { &cxusb_table[DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM], NULL },
+ { &cxusb_table[DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM],
+ NULL },
},
}
};
@@ -1946,7 +2352,7 @@ static struct dvb_usb_device_properties cxusb_aver_a868r_properties = {
}
}
},
- }},
+ } },
},
},
.power_ctrl = cxusb_aver_power_ctrl,
@@ -1992,7 +2398,7 @@ struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = {
}
}
},
- }},
+ } },
},
},
@@ -2046,7 +2452,7 @@ static struct dvb_usb_device_properties cxusb_d680_dmb_properties = {
}
}
},
- }},
+ } },
},
},
@@ -2101,7 +2507,7 @@ static struct dvb_usb_device_properties cxusb_mygica_d689_properties = {
}
}
},
- }},
+ } },
},
},
@@ -2195,6 +2601,6 @@ module_usb_driver(cxusb_driver);
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
+MODULE_AUTHOR("Maciej S. Szmigiero <mail@maciej.szmigiero.name>");
MODULE_DESCRIPTION("Driver for Conexant USB2.0 hybrid reference design");
-MODULE_VERSION("1.0-alpha");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb/cxusb.h b/drivers/media/usb/dvb-usb/cxusb.h
index 88f9b9804b25..9e374e53125b 100644
--- a/drivers/media/usb/dvb-usb/cxusb.h
+++ b/drivers/media/usb/dvb-usb/cxusb.h
@@ -2,9 +2,29 @@
#ifndef _DVB_USB_CXUSB_H_
#define _DVB_USB_CXUSB_H_
+#include <linux/completion.h>
+#include <linux/i2c.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/usb.h>
+#include <linux/workqueue.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-v4l2.h>
+
#define DVB_USB_LOG_PREFIX "cxusb"
#include "dvb-usb.h"
+#define CXUSB_VIDEO_URBS (5)
+#define CXUSB_VIDEO_URB_MAX_SIZE (512 * 1024)
+
+#define CXUSB_VIDEO_PKT_SIZE 3030
+#define CXUSB_VIDEO_MAX_FRAME_PKTS 346
+#define CXUSB_VIDEO_MAX_FRAME_SIZE (CXUSB_VIDEO_MAX_FRAME_PKTS * \
+ CXUSB_VIDEO_PKT_SIZE)
+
/* usb commands - some of it are guesses, don't have a reference yet */
#define CMD_BLUEBIRD_GPIO_RW 0x05
@@ -29,11 +49,26 @@
#define CMD_ANALOG 0x50
#define CMD_DIGITAL 0x51
+#define CXUSB_BT656_PREAMBLE ((const u8 *)"\xff\x00\x00")
+
+#define CXUSB_BT656_FIELD_MASK BIT(6)
+#define CXUSB_BT656_FIELD_1 0
+#define CXUSB_BT656_FIELD_2 BIT(6)
+
+#define CXUSB_BT656_VBI_MASK BIT(5)
+#define CXUSB_BT656_VBI_ON BIT(5)
+#define CXUSB_BT656_VBI_OFF 0
+
+#define CXUSB_BT656_SEAV_MASK BIT(4)
+#define CXUSB_BT656_SEAV_EAV BIT(4)
+#define CXUSB_BT656_SEAV_SAV 0
+
/* Max transfer size done by I2C transfer functions */
#define MAX_XFER_SIZE 80
struct cxusb_state {
u8 gpio_write_state[3];
+ bool gpio_write_refresh[3];
struct i2c_client *i2c_client_demod;
struct i2c_client *i2c_client_tuner;
@@ -42,7 +77,128 @@ struct cxusb_state {
struct mutex stream_mutex;
u8 last_lock;
int (*fe_read_status)(struct dvb_frontend *fe,
- enum fe_status *status);
+ enum fe_status *status);
+};
+
+enum cxusb_open_type {
+ CXUSB_OPEN_INIT,
+ CXUSB_OPEN_NONE,
+ CXUSB_OPEN_ANALOG,
+ CXUSB_OPEN_DIGITAL
+};
+
+struct cxusb_medion_auxbuf {
+ u8 *buf;
+ unsigned int len;
+ unsigned int paylen;
+};
+
+enum cxusb_bt656_mode {
+ NEW_FRAME, FIRST_FIELD, SECOND_FIELD
+};
+
+enum cxusb_bt656_fmode {
+ START_SEARCH, LINE_SAMPLES, VBI_SAMPLES
};
+struct cxusb_bt656_params {
+ enum cxusb_bt656_mode mode;
+ enum cxusb_bt656_fmode fmode;
+ unsigned int pos;
+ unsigned int line;
+ unsigned int linesamples;
+ u8 *buf;
+};
+
+struct cxusb_medion_dev {
+ /* has to be the first one */
+ struct cxusb_state state;
+
+ struct dvb_usb_device *dvbdev;
+
+ enum cxusb_open_type open_type;
+ unsigned int open_ctr;
+ struct mutex open_lock;
+
+#ifdef CONFIG_DVB_USB_CXUSB_ANALOG
+ struct v4l2_device v4l2dev;
+ struct v4l2_subdev *cx25840;
+ struct v4l2_subdev *tuner;
+ struct v4l2_subdev *tda9887;
+ struct video_device *videodev, *radiodev;
+ struct mutex dev_lock;
+
+ struct vb2_queue videoqueue;
+ u32 input;
+ bool stop_streaming;
+ u32 width, height;
+ u32 field_order;
+ struct cxusb_medion_auxbuf auxbuf;
+ v4l2_std_id norm;
+
+ struct urb *streamurbs[CXUSB_VIDEO_URBS];
+ unsigned long urbcomplete;
+ struct work_struct urbwork;
+ unsigned int nexturb;
+
+ struct cxusb_bt656_params bt656;
+ struct cxusb_medion_vbuffer *vbuf;
+ __u32 vbuf_sequence;
+
+ struct list_head buflist;
+
+ struct completion v4l2_release;
+#endif
+};
+
+struct cxusb_medion_vbuffer {
+ struct vb2_v4l2_buffer vb2;
+ struct list_head list;
+};
+
+/* defines for "debug" module parameter */
+#define CXUSB_DBG_RC BIT(0)
+#define CXUSB_DBG_I2C BIT(1)
+#define CXUSB_DBG_MISC BIT(2)
+#define CXUSB_DBG_BT656 BIT(3)
+#define CXUSB_DBG_URB BIT(4)
+#define CXUSB_DBG_OPS BIT(5)
+#define CXUSB_DBG_AUXB BIT(6)
+
+extern int dvb_usb_cxusb_debug;
+
+#define cxusb_vprintk(dvbdev, lvl, ...) do { \
+ struct cxusb_medion_dev *_cxdev = (dvbdev)->priv; \
+ if (dvb_usb_cxusb_debug & CXUSB_DBG_##lvl) \
+ v4l2_printk(KERN_DEBUG, \
+ &_cxdev->v4l2dev, __VA_ARGS__); \
+ } while (0)
+
+int cxusb_ctrl_msg(struct dvb_usb_device *d,
+ u8 cmd, const u8 *wbuf, int wlen, u8 *rbuf, int rlen);
+
+#ifdef CONFIG_DVB_USB_CXUSB_ANALOG
+int cxusb_medion_analog_init(struct dvb_usb_device *dvbdev);
+int cxusb_medion_register_analog(struct dvb_usb_device *dvbdev);
+void cxusb_medion_unregister_analog(struct dvb_usb_device *dvbdev);
+#else
+static inline int cxusb_medion_analog_init(struct dvb_usb_device *dvbdev)
+{
+ return -EINVAL;
+}
+
+static inline int cxusb_medion_register_analog(struct dvb_usb_device *dvbdev)
+{
+ return 0;
+}
+
+static inline void cxusb_medion_unregister_analog(struct dvb_usb_device *dvbdev)
+{
+}
+#endif
+
+int cxusb_medion_get(struct dvb_usb_device *dvbdev,
+ enum cxusb_open_type open_type);
+void cxusb_medion_put(struct dvb_usb_device *dvbdev);
+
#endif
diff --git a/drivers/media/usb/dvb-usb/dibusb-mb.c b/drivers/media/usb/dvb-usb/dibusb-mb.c
index 408920577716..d4ea72bf09c5 100644
--- a/drivers/media/usb/dvb-usb/dibusb-mb.c
+++ b/drivers/media/usb/dvb-usb/dibusb-mb.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* DVB USB compliant linux driver for mobile DVB-T USB devices based on
* reference designs made by DiBcom (http://www.dibcom.fr/) (DiB3000M-B)
*
@@ -6,10 +7,6 @@
* based on GPL code from DiBcom, which has
* Copyright (C) 2004 Amaury Demol for DiBcom
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation, version 2.
- *
* see Documentation/media/dvb-drivers/dvb-usb.rst for more information
*/
#include "dibusb.h"
diff --git a/drivers/media/usb/dvb-usb/dibusb-mc.c b/drivers/media/usb/dvb-usb/dibusb-mc.c
index bce8ffe640ca..ada3bee296c2 100644
--- a/drivers/media/usb/dvb-usb/dibusb-mc.c
+++ b/drivers/media/usb/dvb-usb/dibusb-mc.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* DVB USB compliant linux driver for mobile DVB-T USB devices based on
* reference designs made by DiBcom (http://www.dibcom.fr/) (DiB3000M-C/P)
*
@@ -6,10 +7,6 @@
* based on GPL code from DiBcom, which has
* Copyright (C) 2004 Amaury Demol for DiBcom
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation, version 2.
- *
* see Documentation/media/dvb-drivers/dvb-usb.rst for more information
*/
#include "dibusb.h"
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-dvb.c b/drivers/media/usb/dvb-usb/dvb-usb-dvb.c
index 8056053c9ab0..0a7f8ba90992 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb-dvb.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-dvb.c
@@ -56,9 +56,6 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
* for reception.
*/
if (adap->feedcount == onoff && adap->feedcount > 0) {
- deb_ts("submitting all URBs\n");
- usb_urb_submit(&adap->fe_adap[adap->active_fe].stream);
-
deb_ts("controlling pid parser\n");
if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER &&
adap->props.fe[adap->active_fe].caps &
@@ -80,6 +77,8 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
}
}
+ deb_ts("submitting all URBs\n");
+ usb_urb_submit(&adap->fe_adap[adap->active_fe].stream);
}
return 0;
}
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-init.c b/drivers/media/usb/dvb-usb/dvb-usb-init.c
index e97f6edc98de..16a0b4a359ea 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb-init.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-init.c
@@ -130,6 +130,10 @@ static int dvb_usb_exit(struct dvb_usb_device *d)
dvb_usb_i2c_exit(d);
deb_info("state should be zero now: %x\n", d->state);
d->state = DVB_USB_STATE_INIT;
+
+ if (d->priv != NULL && d->props.priv_destroy != NULL)
+ d->props.priv_destroy(d);
+
kfree(d->priv);
kfree(d);
return 0;
@@ -151,6 +155,15 @@ static int dvb_usb_init(struct dvb_usb_device *d, short *adapter_nums)
err("no memory for priv in 'struct dvb_usb_device'");
return -ENOMEM;
}
+
+ if (d->props.priv_init != NULL) {
+ ret = d->props.priv_init(d);
+ if (ret != 0) {
+ kfree(d->priv);
+ d->priv = NULL;
+ return ret;
+ }
+ }
}
/* check the capabilities and set appropriate variables */
@@ -284,12 +297,15 @@ EXPORT_SYMBOL(dvb_usb_device_init);
void dvb_usb_device_exit(struct usb_interface *intf)
{
struct dvb_usb_device *d = usb_get_intfdata(intf);
- const char *name = "generic DVB-USB module";
+ const char *default_name = "generic DVB-USB module";
+ char name[40];
usb_set_intfdata(intf, NULL);
if (d != NULL && d->desc != NULL) {
- name = d->desc->name;
+ strscpy(name, d->desc->name, sizeof(name));
dvb_usb_exit(d);
+ } else {
+ strscpy(name, default_name, sizeof(name));
}
info("%s successfully deinitialized and disconnected.", name);
diff --git a/drivers/media/usb/dvb-usb/dvb-usb.h b/drivers/media/usb/dvb-usb/dvb-usb.h
index 32829bdd5f22..2eb0e24e8943 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb.h
+++ b/drivers/media/usb/dvb-usb/dvb-usb.h
@@ -129,6 +129,9 @@ struct usb_data_stream_properties {
* @frontend_ctrl: called to power on/off active frontend.
* @streaming_ctrl: called to start and stop the MPEG2-TS streaming of the
* device (not URB submitting/killing).
+ * This callback will be called without data URBs being active - data URBs
+ * will be submitted only after streaming_ctrl(1) returns successfully and
+ * they will be killed before streaming_ctrl(0) gets called.
* @pid_filter_ctrl: called to en/disable the PID filter, if any.
* @pid_filter: called to set/unset a PID for filtering.
* @frontend_attach: called to attach the possible frontends (fill fe-field
@@ -234,6 +237,11 @@ enum dvb_usb_mode {
*
* @size_of_priv: how many bytes shall be allocated for the private field
* of struct dvb_usb_device.
+ * @priv_init: optional callback to initialize the variable that private field
+ * of struct dvb_usb_device has pointer to just after it had been allocated and
+ * zeroed.
+ * @priv_destroy: just like priv_init, only called before deallocating
+ * the memory pointed by private field of struct dvb_usb_device.
*
* @power_ctrl: called to enable/disable power of the device.
* @read_mac_address: called to read the MAC address of the device.
@@ -275,6 +283,8 @@ struct dvb_usb_device_properties {
int no_reconnect;
int size_of_priv;
+ int (*priv_init)(struct dvb_usb_device *);
+ void (*priv_destroy)(struct dvb_usb_device *);
int num_adapters;
struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE];
diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
index d85ea1af6aa1..5aa15a7a49de 100644
--- a/drivers/media/usb/em28xx/em28xx-input.c
+++ b/drivers/media/usb/em28xx/em28xx-input.c
@@ -24,6 +24,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/usb.h>
+#include <linux/usb/input.h>
#include <linux/slab.h>
#include <linux/bitrev.h>
@@ -58,7 +59,6 @@ struct em28xx_ir_poll_result {
struct em28xx_IR {
struct em28xx *dev;
struct rc_dev *rc;
- char name[32];
char phys[32];
/* poll decoder */
@@ -277,21 +277,8 @@ static int em2874_polling_getkey(struct em28xx_IR *ir,
break;
case RC_PROTO_BIT_NEC:
- poll_result->scancode = msg[1] << 8 | msg[2];
- if ((msg[3] ^ msg[4]) != 0xff) { /* 32 bits NEC */
- poll_result->protocol = RC_PROTO_NEC32;
- poll_result->scancode = RC_SCANCODE_NEC32((msg[1] << 24) |
- (msg[2] << 16) |
- (msg[3] << 8) |
- (msg[4]));
- } else if ((msg[1] ^ msg[2]) != 0xff) { /* 24 bits NEC */
- poll_result->protocol = RC_PROTO_NECX;
- poll_result->scancode = RC_SCANCODE_NECX(msg[1] << 8 |
- msg[2], msg[3]);
- } else { /* Normal NEC */
- poll_result->protocol = RC_PROTO_NEC;
- poll_result->scancode = RC_SCANCODE_NEC(msg[1], msg[3]);
- }
+ poll_result->scancode = ir_nec_bytes_to_scancode(msg[1], msg[2], msg[3], msg[4],
+ &poll_result->protocol);
break;
case RC_PROTO_BIT_RC6_0:
@@ -617,10 +604,7 @@ static int em28xx_register_snapshot_button(struct em28xx *dev)
set_bit(EM28XX_SNAPSHOT_KEY, input_dev->keybit);
input_dev->keycodesize = 0;
input_dev->keycodemax = 0;
- input_dev->id.bustype = BUS_USB;
- input_dev->id.vendor = le16_to_cpu(udev->descriptor.idVendor);
- input_dev->id.product = le16_to_cpu(udev->descriptor.idProduct);
- input_dev->id.version = 1;
+ usb_to_input_id(udev, &input_dev->id);
input_dev->dev.parent = &dev->intf->dev;
err = input_register_device(input_dev);
@@ -832,19 +816,12 @@ static int em28xx_ir_init(struct em28xx *dev)
/* This is how often we ask the chip for IR information */
ir->polling = 100; /* ms */
- /* init input device */
- snprintf(ir->name, sizeof(ir->name), "%s IR",
- dev_name(&dev->intf->dev));
-
usb_make_path(udev, ir->phys, sizeof(ir->phys));
strlcat(ir->phys, "/input0", sizeof(ir->phys));
- rc->device_name = ir->name;
+ rc->device_name = em28xx_boards[dev->model].name;
rc->input_phys = ir->phys;
- rc->input_id.bustype = BUS_USB;
- rc->input_id.version = 1;
- rc->input_id.vendor = le16_to_cpu(udev->descriptor.idVendor);
- rc->input_id.product = le16_to_cpu(udev->descriptor.idProduct);
+ usb_to_input_id(udev, &rc->input_id);
rc->dev.parent = &dev->intf->dev;
rc->driver_name = MODULE_NAME;
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index f43717ea831d..0512e1959394 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -1984,7 +1984,6 @@ static int vidioc_s_register(struct file *file, void *priv,
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- struct video_device *vdev = video_devdata(file);
struct em28xx *dev = video_drvdata(file);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
struct usb_device *udev = interface_to_usbdev(dev->intf);
@@ -1993,23 +1992,12 @@ static int vidioc_querycap(struct file *file, void *priv,
strscpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
usb_make_path(udev, cap->bus_info, sizeof(cap->bus_info));
- if (vdev->vfl_type == VFL_TYPE_GRABBER)
- cap->device_caps = V4L2_CAP_READWRITE |
- V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
- else if (vdev->vfl_type == VFL_TYPE_RADIO)
- cap->device_caps = V4L2_CAP_RADIO;
- else
- cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE;
-
+ cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_READWRITE |
+ V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
if (dev->int_audio_type != EM28XX_INT_AUDIO_NONE)
- cap->device_caps |= V4L2_CAP_AUDIO;
-
+ cap->capabilities |= V4L2_CAP_AUDIO;
if (dev->tuner_type != TUNER_ABSENT)
- cap->device_caps |= V4L2_CAP_TUNER;
-
- cap->capabilities = cap->device_caps |
- V4L2_CAP_DEVICE_CAPS | V4L2_CAP_READWRITE |
- V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ cap->capabilities |= V4L2_CAP_TUNER;
if (video_is_registered(&v4l2->vbi_dev))
cap->capabilities |= V4L2_CAP_VBI_CAPTURE;
if (video_is_registered(&v4l2->radio_dev))
@@ -2782,6 +2770,13 @@ static int em28xx_v4l2_init(struct em28xx *dev)
mutex_init(&v4l2->vb_vbi_queue_lock);
v4l2->vdev.queue = &v4l2->vb_vidq;
v4l2->vdev.queue->lock = &v4l2->vb_queue_lock;
+ v4l2->vdev.device_caps = V4L2_CAP_READWRITE | V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING;
+ if (dev->int_audio_type != EM28XX_INT_AUDIO_NONE)
+ v4l2->vdev.device_caps |= V4L2_CAP_AUDIO;
+ if (dev->tuner_type != TUNER_ABSENT)
+ v4l2->vdev.device_caps |= V4L2_CAP_TUNER;
+
/* disable inapplicable ioctls */
if (dev->is_webcam) {
@@ -2818,6 +2813,10 @@ static int em28xx_v4l2_init(struct em28xx *dev)
v4l2->vbi_dev.queue = &v4l2->vb_vbiq;
v4l2->vbi_dev.queue->lock = &v4l2->vb_vbi_queue_lock;
+ v4l2->vbi_dev.device_caps = V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE;
+ if (dev->tuner_type != TUNER_ABSENT)
+ v4l2->vbi_dev.device_caps |= V4L2_CAP_TUNER;
/* disable inapplicable ioctls */
v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_S_PARM);
@@ -2845,6 +2844,7 @@ static int em28xx_v4l2_init(struct em28xx *dev)
if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) {
em28xx_vdev_init(dev, &v4l2->radio_dev, &em28xx_radio_template,
"radio");
+ v4l2->radio_dev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
ret = video_register_device(&v4l2->radio_dev, VFL_TYPE_RADIO,
radio_nr[dev->devno]);
if (ret < 0) {
diff --git a/drivers/media/usb/go7007/go7007-v4l2.c b/drivers/media/usb/go7007/go7007-v4l2.c
index b63b7bb7745c..88edfef80b40 100644
--- a/drivers/media/usb/go7007/go7007-v4l2.c
+++ b/drivers/media/usb/go7007/go7007-v4l2.c
@@ -279,15 +279,6 @@ static int vidioc_querycap(struct file *file, void *priv,
strscpy(cap->driver, "go7007", sizeof(cap->driver));
strscpy(cap->card, go->name, sizeof(cap->card));
strscpy(cap->bus_info, go->bus_info, sizeof(cap->bus_info));
-
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
-
- if (go->board_info->num_aud_inputs)
- cap->device_caps |= V4L2_CAP_AUDIO;
- if (go->board_info->flags & GO7007_BOARD_HAS_TUNER)
- cap->device_caps |= V4L2_CAP_TUNER;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -1114,6 +1105,12 @@ int go7007_v4l2_init(struct go7007 *go)
*vdev = go7007_template;
vdev->lock = &go->serialize_lock;
vdev->queue = &go->vidq;
+ vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING;
+ if (go->board_info->num_aud_inputs)
+ vdev->device_caps |= V4L2_CAP_AUDIO;
+ if (go->board_info->flags & GO7007_BOARD_HAS_TUNER)
+ vdev->device_caps |= V4L2_CAP_TUNER;
video_set_drvdata(vdev, go);
vdev->v4l2_dev = &go->v4l2_dev;
if (!v4l2_device_has_op(&go->v4l2_dev, 0, video, querystd))
diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c
index a7ed5257cdba..be11f7830bca 100644
--- a/drivers/media/usb/gspca/gspca.c
+++ b/drivers/media/usb/gspca/gspca.c
@@ -1209,10 +1209,6 @@ static int vidioc_querycap(struct file *file, void *priv,
}
usb_make_path(gspca_dev->dev, (char *) cap->bus_info,
sizeof(cap->bus_info));
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE
- | V4L2_CAP_STREAMING
- | V4L2_CAP_READWRITE;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -1508,6 +1504,8 @@ int gspca_dev_probe2(struct usb_interface *intf,
gspca_dev->empty_packet = -1; /* don't check the empty packets */
gspca_dev->vdev = gspca_template;
gspca_dev->vdev.v4l2_dev = &gspca_dev->v4l2_dev;
+ gspca_dev->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
video_set_drvdata(&gspca_dev->vdev, gspca_dev);
gspca_dev->module = module;
diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c
index 7d4a9452f545..cec841ad7495 100644
--- a/drivers/media/usb/hackrf/hackrf.c
+++ b/drivers/media/usb/hackrf/hackrf.c
@@ -896,19 +896,13 @@ static int hackrf_querycap(struct file *file, void *fh,
{
struct hackrf_dev *dev = video_drvdata(file);
struct usb_interface *intf = dev->intf;
- struct video_device *vdev = video_devdata(file);
dev_dbg(&intf->dev, "\n");
- cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
- if (vdev->vfl_dir == VFL_DIR_RX)
- cap->device_caps |= V4L2_CAP_SDR_CAPTURE | V4L2_CAP_TUNER;
- else
- cap->device_caps |= V4L2_CAP_SDR_OUTPUT | V4L2_CAP_MODULATOR;
-
cap->capabilities = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_TUNER |
V4L2_CAP_SDR_OUTPUT | V4L2_CAP_MODULATOR |
- V4L2_CAP_DEVICE_CAPS | cap->device_caps;
+ V4L2_CAP_STREAMING | V4L2_CAP_READWRITE |
+ V4L2_CAP_DEVICE_CAPS;
strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
strscpy(cap->card, dev->rx_vdev.name, sizeof(cap->card));
usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
@@ -1487,6 +1481,8 @@ static int hackrf_probe(struct usb_interface *intf,
dev->rx_vdev.ctrl_handler = &dev->rx_ctrl_handler;
dev->rx_vdev.lock = &dev->v4l2_lock;
dev->rx_vdev.vfl_dir = VFL_DIR_RX;
+ dev->rx_vdev.device_caps = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE |
+ V4L2_CAP_SDR_CAPTURE | V4L2_CAP_TUNER;
video_set_drvdata(&dev->rx_vdev, dev);
ret = video_register_device(&dev->rx_vdev, VFL_TYPE_SDR, -1);
if (ret) {
@@ -1505,6 +1501,8 @@ static int hackrf_probe(struct usb_interface *intf,
dev->tx_vdev.ctrl_handler = &dev->tx_ctrl_handler;
dev->tx_vdev.lock = &dev->v4l2_lock;
dev->tx_vdev.vfl_dir = VFL_DIR_TX;
+ dev->tx_vdev.device_caps = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE |
+ V4L2_CAP_SDR_OUTPUT | V4L2_CAP_MODULATOR;
video_set_drvdata(&dev->tx_vdev, dev);
ret = video_register_device(&dev->tx_vdev, VFL_TYPE_SDR, -1);
if (ret) {
diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c
index 7580fc5f2f12..5b3e67b80627 100644
--- a/drivers/media/usb/hdpvr/hdpvr-video.c
+++ b/drivers/media/usb/hdpvr/hdpvr-video.c
@@ -435,7 +435,7 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count,
/* wait for the first buffer */
if (!(file->f_flags & O_NONBLOCK)) {
if (wait_event_interruptible(dev->wait_data,
- hdpvr_get_next_buffer(dev)))
+ !list_empty_careful(&dev->rec_buff_list)))
return -ERESTARTSYS;
}
@@ -461,10 +461,17 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count,
goto err;
}
if (!err) {
- v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
- "timeout: restart streaming\n");
+ v4l2_info(&dev->v4l2_dev,
+ "timeout: restart streaming\n");
+ mutex_lock(&dev->io_mutex);
hdpvr_stop_streaming(dev);
- msecs_to_jiffies(4000);
+ mutex_unlock(&dev->io_mutex);
+ /*
+ * The FW needs about 4 seconds after streaming
+ * stopped before it is ready to restart
+ * streaming.
+ */
+ msleep(4000);
err = hdpvr_start_streaming(dev);
if (err) {
ret = err;
@@ -577,9 +584,6 @@ static int vidioc_querycap(struct file *file, void *priv,
strscpy(cap->driver, "hdpvr", sizeof(cap->driver));
strscpy(cap->card, "Hauppauge HD PVR", sizeof(cap->card));
usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO |
- V4L2_CAP_READWRITE;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -1127,9 +1131,7 @@ static void hdpvr_device_release(struct video_device *vdev)
struct hdpvr_device *dev = video_get_drvdata(vdev);
hdpvr_delete(dev);
- mutex_lock(&dev->io_mutex);
flush_work(&dev->worker);
- mutex_unlock(&dev->io_mutex);
v4l2_device_unregister(&dev->v4l2_dev);
v4l2_ctrl_handler_free(&dev->hdl);
@@ -1150,6 +1152,8 @@ static const struct video_device hdpvr_video_template = {
.release = hdpvr_device_release,
.ioctl_ops = &hdpvr_ioctl_ops,
.tvnorms = V4L2_STD_ALL,
+ .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO |
+ V4L2_CAP_READWRITE,
};
static const struct v4l2_ctrl_ops hdpvr_ctrl_ops = {
diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c
index b405bc3c2781..4c9b2a12acfb 100644
--- a/drivers/media/usb/msi2500/msi2500.c
+++ b/drivers/media/usb/msi2500/msi2500.c
@@ -598,9 +598,6 @@ static int msi2500_querycap(struct file *file, void *fh,
strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
strscpy(cap->card, dev->vdev.name, sizeof(cap->card));
usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
- cap->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING |
- V4L2_CAP_READWRITE | V4L2_CAP_TUNER;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -1274,6 +1271,8 @@ static int msi2500_probe(struct usb_interface *intf,
dev->v4l2_dev.ctrl_handler = &dev->hdl;
dev->vdev.v4l2_dev = &dev->v4l2_dev;
dev->vdev.lock = &dev->v4l2_lock;
+ dev->vdev.device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE | V4L2_CAP_TUNER;
ret = video_register_device(&dev->vdev, VFL_TYPE_SDR, -1);
if (ret) {
diff --git a/drivers/media/usb/pvrusb2/Kconfig b/drivers/media/usb/pvrusb2/Kconfig
index 64f9df067269..e6a4f730591b 100644
--- a/drivers/media/usb/pvrusb2/Kconfig
+++ b/drivers/media/usb/pvrusb2/Kconfig
@@ -41,6 +41,8 @@ config VIDEO_PVRUSB2_DVB
select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT
select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT
select DVB_TDA10048 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_LGDT3306A if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-audio.c b/drivers/media/usb/pvrusb2/pvrusb2-audio.c
index 356afa250cd6..13051f0e2512 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-audio.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-audio.c
@@ -1,18 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include "pvrusb2-audio.h"
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-audio.h b/drivers/media/usb/pvrusb2/pvrusb2-audio.h
index 4f3898473165..87fb4c0747ad 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-audio.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-audio.h
@@ -1,18 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#ifndef __PVRUSB2_AUDIO_H
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-context.c b/drivers/media/usb/pvrusb2/pvrusb2-context.c
index d9e8481e9e28..14170a5d72b3 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-context.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-context.c
@@ -1,16 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include "pvrusb2-context.h"
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-context.h b/drivers/media/usb/pvrusb2/pvrusb2-context.h
index 13e00c529611..5840b2ce8f1e 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-context.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-context.h
@@ -1,16 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#ifndef __PVRUSB2_CONTEXT_H
#define __PVRUSB2_CONTEXT_H
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c b/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c
index 679f3ff3b0a5..7eefa0f86ad4 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c
@@ -1,18 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
/*
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.h b/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.h
index 90dfb8b3f3e5..800841ba8376 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.h
@@ -1,18 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#ifndef __PVRUSB2_CS53L32A_H
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-ctrl.c b/drivers/media/usb/pvrusb2/pvrusb2-ctrl.c
index 5f4ba84e5557..9f71d8c2a3c6 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-ctrl.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-ctrl.c
@@ -1,17 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include "pvrusb2-ctrl.h"
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-ctrl.h b/drivers/media/usb/pvrusb2/pvrusb2-ctrl.h
index 4b9152e36fe4..7dd4b73f783c 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-ctrl.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-ctrl.h
@@ -1,17 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#ifndef __PVRUSB2_CTRL_H
#define __PVRUSB2_CTRL_H
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c
index d5bec0f69bec..e4b31ae02f59 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c
@@ -1,18 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
/*
@@ -111,10 +101,35 @@ static const struct routing_scheme routing_defav400 = {
.cnt = ARRAY_SIZE(routing_schemeav400),
};
+static const struct routing_scheme_item routing_scheme160xxx[] = {
+ [PVR2_CVAL_INPUT_TV] = {
+ .vid = CX25840_COMPOSITE7,
+ .aud = CX25840_AUDIO8,
+ },
+ [PVR2_CVAL_INPUT_RADIO] = {
+ .vid = CX25840_COMPOSITE4,
+ .aud = CX25840_AUDIO6,
+ },
+ [PVR2_CVAL_INPUT_COMPOSITE] = {
+ .vid = CX25840_COMPOSITE3,
+ .aud = CX25840_AUDIO_SERIAL,
+ },
+ [PVR2_CVAL_INPUT_SVIDEO] = {
+ .vid = CX25840_SVIDEO1,
+ .aud = CX25840_AUDIO_SERIAL,
+ },
+};
+
+static const struct routing_scheme routing_def160xxx = {
+ .def = routing_scheme160xxx,
+ .cnt = ARRAY_SIZE(routing_scheme160xxx),
+};
+
static const struct routing_scheme *routing_schemes[] = {
[PVR2_ROUTING_SCHEME_HAUPPAUGE] = &routing_def0,
[PVR2_ROUTING_SCHEME_GOTVIEW] = &routing_defgv,
[PVR2_ROUTING_SCHEME_AV400] = &routing_defav400,
+ [PVR2_ROUTING_SCHEME_HAUP160XXX] = &routing_def160xxx,
};
void pvr2_cx25840_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.h b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.h
index dfddc88750d9..57c9504793e0 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.h
@@ -1,18 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#ifndef __PVRUSB2_CX2584X_V4L_H
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-debug.h b/drivers/media/usb/pvrusb2/pvrusb2-debug.h
index 1323f949f454..7854c1d87af1 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-debug.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-debug.h
@@ -1,16 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#ifndef __PVRUSB2_DEBUG_H
#define __PVRUSB2_DEBUG_H
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c
index d3f3bd96885f..84cfb5ce8b8d 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c
@@ -1,17 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <linux/string.h>
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-debugifc.h b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.h
index fcaaa8dd68b8..9b9c0f553480 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-debugifc.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.h
@@ -1,17 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#ifndef __PVRUSB2_DEBUGIFC_H
#define __PVRUSB2_DEBUGIFC_H
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-devattr.c b/drivers/media/usb/pvrusb2/pvrusb2-devattr.c
index 06de1c83f444..1fcf63218885 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-devattr.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-devattr.c
@@ -1,17 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
*
- *
* Copyright (C) 2007 Mike Isely <isely@pobox.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
/*
@@ -37,6 +27,9 @@ pvr2_device_desc structures.
#include "tda18271.h"
#include "tda8290.h"
#include "tuner-simple.h"
+#include "si2157.h"
+#include "lgdt3306a.h"
+#include "si2168.h"
#endif
@@ -188,10 +181,10 @@ static struct lgdt330x_config pvr2_lgdt3303_config = {
static int pvr2_lgdt3303_attach(struct pvr2_dvb_adapter *adap)
{
- adap->fe = dvb_attach(lgdt330x_attach, &pvr2_lgdt3303_config,
- 0x0e,
- &adap->channel.hdw->i2c_adap);
- if (adap->fe)
+ adap->fe[0] = dvb_attach(lgdt330x_attach, &pvr2_lgdt3303_config,
+ 0x0e,
+ &adap->channel.hdw->i2c_adap);
+ if (adap->fe[0])
return 0;
return -EIO;
@@ -199,7 +192,7 @@ static int pvr2_lgdt3303_attach(struct pvr2_dvb_adapter *adap)
static int pvr2_lgh06xf_attach(struct pvr2_dvb_adapter *adap)
{
- dvb_attach(simple_tuner_attach, adap->fe,
+ dvb_attach(simple_tuner_attach, adap->fe[0],
&adap->channel.hdw->i2c_adap, 0x61,
TUNER_LG_TDVS_H06XF);
@@ -248,10 +241,10 @@ static struct lgdt330x_config pvr2_lgdt3302_config = {
static int pvr2_lgdt3302_attach(struct pvr2_dvb_adapter *adap)
{
- adap->fe = dvb_attach(lgdt330x_attach, &pvr2_lgdt3302_config,
- 0x0e,
- &adap->channel.hdw->i2c_adap);
- if (adap->fe)
+ adap->fe[0] = dvb_attach(lgdt330x_attach, &pvr2_lgdt3302_config,
+ 0x0e,
+ &adap->channel.hdw->i2c_adap);
+ if (adap->fe[0])
return 0;
return -EIO;
@@ -259,7 +252,7 @@ static int pvr2_lgdt3302_attach(struct pvr2_dvb_adapter *adap)
static int pvr2_fcv1236d_attach(struct pvr2_dvb_adapter *adap)
{
- dvb_attach(simple_tuner_attach, adap->fe,
+ dvb_attach(simple_tuner_attach, adap->fe[0],
&adap->channel.hdw->i2c_adap, 0x61,
TUNER_PHILIPS_FCV1236D);
@@ -335,9 +328,9 @@ static struct tda18271_config hauppauge_tda18271_dvb_config = {
static int pvr2_tda10048_attach(struct pvr2_dvb_adapter *adap)
{
- adap->fe = dvb_attach(tda10048_attach, &hauppauge_tda10048_config,
- &adap->channel.hdw->i2c_adap);
- if (adap->fe)
+ adap->fe[0] = dvb_attach(tda10048_attach, &hauppauge_tda10048_config,
+ &adap->channel.hdw->i2c_adap);
+ if (adap->fe[0])
return 0;
return -EIO;
@@ -345,10 +338,10 @@ static int pvr2_tda10048_attach(struct pvr2_dvb_adapter *adap)
static int pvr2_73xxx_tda18271_8295_attach(struct pvr2_dvb_adapter *adap)
{
- dvb_attach(tda829x_attach, adap->fe,
+ dvb_attach(tda829x_attach, adap->fe[0],
&adap->channel.hdw->i2c_adap, 0x42,
&tda829x_no_probe);
- dvb_attach(tda18271_attach, adap->fe, 0x60,
+ dvb_attach(tda18271_attach, adap->fe[0], 0x60,
&adap->channel.hdw->i2c_adap,
&hauppauge_tda18271_dvb_config);
@@ -433,9 +426,9 @@ static struct tda18271_config hauppauge_tda18271_config = {
static int pvr2_s5h1409_attach(struct pvr2_dvb_adapter *adap)
{
- adap->fe = dvb_attach(s5h1409_attach, &pvr2_s5h1409_config,
- &adap->channel.hdw->i2c_adap);
- if (adap->fe)
+ adap->fe[0] = dvb_attach(s5h1409_attach, &pvr2_s5h1409_config,
+ &adap->channel.hdw->i2c_adap);
+ if (adap->fe[0])
return 0;
return -EIO;
@@ -443,9 +436,9 @@ static int pvr2_s5h1409_attach(struct pvr2_dvb_adapter *adap)
static int pvr2_s5h1411_attach(struct pvr2_dvb_adapter *adap)
{
- adap->fe = dvb_attach(s5h1411_attach, &pvr2_s5h1411_config,
- &adap->channel.hdw->i2c_adap);
- if (adap->fe)
+ adap->fe[0] = dvb_attach(s5h1411_attach, &pvr2_s5h1411_config,
+ &adap->channel.hdw->i2c_adap);
+ if (adap->fe[0])
return 0;
return -EIO;
@@ -453,10 +446,10 @@ static int pvr2_s5h1411_attach(struct pvr2_dvb_adapter *adap)
static int pvr2_tda18271_8295_attach(struct pvr2_dvb_adapter *adap)
{
- dvb_attach(tda829x_attach, adap->fe,
+ dvb_attach(tda829x_attach, adap->fe[0],
&adap->channel.hdw->i2c_adap, 0x42,
&tda829x_no_probe);
- dvb_attach(tda18271_attach, adap->fe, 0x60,
+ dvb_attach(tda18271_attach, adap->fe[0], 0x60,
&adap->channel.hdw->i2c_adap,
&hauppauge_tda18271_config);
@@ -525,7 +518,166 @@ static const struct pvr2_device_desc pvr2_device_751xx = {
#endif
};
+/*------------------------------------------------------------------------*/
+/* Hauppauge PVR-USB2 Model 160000 / 160111 -- HVR-1955 / HVR-1975 */
+
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+static int pvr2_si2157_attach(struct pvr2_dvb_adapter *adap);
+static int pvr2_si2168_attach(struct pvr2_dvb_adapter *adap);
+static int pvr2_dual_fe_attach(struct pvr2_dvb_adapter *adap);
+static int pvr2_lgdt3306a_attach(struct pvr2_dvb_adapter *adap);
+
+static const struct pvr2_dvb_props pvr2_160000_dvb_props = {
+ .frontend_attach = pvr2_dual_fe_attach,
+ .tuner_attach = pvr2_si2157_attach,
+};
+
+static const struct pvr2_dvb_props pvr2_160111_dvb_props = {
+ .frontend_attach = pvr2_lgdt3306a_attach,
+ .tuner_attach = pvr2_si2157_attach,
+};
+
+static int pvr2_si2157_attach(struct pvr2_dvb_adapter *adap)
+{
+ struct si2157_config si2157_config = {};
+
+ si2157_config.inversion = 1;
+ si2157_config.fe = adap->fe[0];
+
+ adap->i2c_client_tuner = dvb_module_probe("si2157", "si2177",
+ &adap->channel.hdw->i2c_adap,
+ 0x60, &si2157_config);
+
+ if (!adap->i2c_client_tuner)
+ return -ENODEV;
+
+ return 0;
+}
+
+static int pvr2_si2168_attach(struct pvr2_dvb_adapter *adap)
+{
+ struct si2168_config si2168_config = {};
+ struct i2c_adapter *adapter;
+
+ pr_debug("%s()\n", __func__);
+
+ si2168_config.fe = &adap->fe[1];
+ si2168_config.i2c_adapter = &adapter;
+ si2168_config.ts_mode = SI2168_TS_PARALLEL; /*2, 1-serial, 2-parallel.*/
+ si2168_config.ts_clock_gapped = 1; /*0-disabled, 1-enabled.*/
+ si2168_config.ts_clock_inv = 0; /*0-not-invert, 1-invert*/
+ si2168_config.spectral_inversion = 1; /*0-not-invert, 1-invert*/
+
+ adap->i2c_client_demod[1] = dvb_module_probe("si2168", NULL,
+ &adap->channel.hdw->i2c_adap,
+ 0x64, &si2168_config);
+
+ if (!adap->i2c_client_demod[1])
+ return -ENODEV;
+
+ return 0;
+}
+
+static int pvr2_lgdt3306a_attach(struct pvr2_dvb_adapter *adap)
+{
+ struct lgdt3306a_config lgdt3306a_config;
+ struct i2c_adapter *adapter;
+
+ pr_debug("%s()\n", __func__);
+
+ lgdt3306a_config.fe = &adap->fe[0];
+ lgdt3306a_config.i2c_adapter = &adapter;
+ lgdt3306a_config.deny_i2c_rptr = 1;
+ lgdt3306a_config.spectral_inversion = 1;
+ lgdt3306a_config.qam_if_khz = 4000;
+ lgdt3306a_config.vsb_if_khz = 3250;
+ lgdt3306a_config.mpeg_mode = LGDT3306A_MPEG_PARALLEL;
+ lgdt3306a_config.tpclk_edge = LGDT3306A_TPCLK_FALLING_EDGE;
+ lgdt3306a_config.tpvalid_polarity = LGDT3306A_TP_VALID_LOW;
+ lgdt3306a_config.xtalMHz = 25, /* demod clock MHz; 24/25 supported */
+
+ adap->i2c_client_demod[0] = dvb_module_probe("lgdt3306a", NULL,
+ &adap->channel.hdw->i2c_adap,
+ 0x59, &lgdt3306a_config);
+
+ if (!adap->i2c_client_demod[0])
+ return -ENODEV;
+ return 0;
+}
+
+static int pvr2_dual_fe_attach(struct pvr2_dvb_adapter *adap)
+{
+ pr_debug("%s()\n", __func__);
+
+ if (pvr2_lgdt3306a_attach(adap) != 0)
+ return -ENODEV;
+
+ if (pvr2_si2168_attach(adap) != 0) {
+ dvb_module_release(adap->i2c_client_demod[0]);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+#endif
+
+#define PVR2_FIRMWARE_160xxx "v4l-pvrusb2-160xxx-01.fw"
+static const char *pvr2_fw1_names_160xxx[] = {
+ PVR2_FIRMWARE_160xxx,
+};
+
+static const struct pvr2_device_client_desc pvr2_cli_160xxx[] = {
+ { .module_id = PVR2_CLIENT_ID_CX25840 },
+};
+
+static const struct pvr2_device_desc pvr2_device_160000 = {
+ .description = "WinTV HVR-1975 Model 160000",
+ .shortname = "160000",
+ .client_table.lst = pvr2_cli_160xxx,
+ .client_table.cnt = ARRAY_SIZE(pvr2_cli_160xxx),
+ .fx2_firmware.lst = pvr2_fw1_names_160xxx,
+ .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_160xxx),
+ .default_tuner_type = TUNER_ABSENT,
+ .flag_has_cx25840 = 1,
+ .flag_has_hauppauge_rom = 1,
+ .flag_has_analogtuner = 1,
+ .flag_has_composite = 1,
+ .flag_has_svideo = 1,
+ .flag_fx2_16kb = 1,
+ .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+ .digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE,
+ .default_std_mask = V4L2_STD_NTSC_M,
+ .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE,
+ .ir_scheme = PVR2_IR_SCHEME_ZILOG,
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+ .dvb_props = &pvr2_160000_dvb_props,
+#endif
+};
+
+static const struct pvr2_device_desc pvr2_device_160111 = {
+ .description = "WinTV HVR-1955 Model 160111",
+ .shortname = "160111",
+ .client_table.lst = pvr2_cli_160xxx,
+ .client_table.cnt = ARRAY_SIZE(pvr2_cli_160xxx),
+ .fx2_firmware.lst = pvr2_fw1_names_160xxx,
+ .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_160xxx),
+ .default_tuner_type = TUNER_ABSENT,
+ .flag_has_cx25840 = 1,
+ .flag_has_hauppauge_rom = 1,
+ .flag_has_analogtuner = 1,
+ .flag_has_composite = 1,
+ .flag_has_svideo = 1,
+ .flag_fx2_16kb = 1,
+ .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+ .digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE,
+ .default_std_mask = V4L2_STD_NTSC_M,
+ .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE,
+ .ir_scheme = PVR2_IR_SCHEME_ZILOG,
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+ .dvb_props = &pvr2_160111_dvb_props,
+#endif
+};
/*------------------------------------------------------------------------*/
@@ -552,6 +704,10 @@ struct usb_device_id pvr2_device_table[] = {
.driver_info = (kernel_ulong_t)&pvr2_device_751xx},
{ USB_DEVICE(0x0ccd, 0x0039),
.driver_info = (kernel_ulong_t)&pvr2_device_av400},
+ { USB_DEVICE(0x2040, 0x7502),
+ .driver_info = (kernel_ulong_t)&pvr2_device_160111},
+ { USB_DEVICE(0x2040, 0x7510),
+ .driver_info = (kernel_ulong_t)&pvr2_device_160000},
{ }
};
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-devattr.h b/drivers/media/usb/pvrusb2/pvrusb2-devattr.h
index c1e7d4822cd1..3c88f05d82d9 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-devattr.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-devattr.h
@@ -1,17 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#ifndef __PVRUSB2_DEVATTR_H
#define __PVRUSB2_DEVATTR_H
@@ -66,6 +56,7 @@ struct pvr2_string_table {
#define PVR2_ROUTING_SCHEME_GOTVIEW 1
#define PVR2_ROUTING_SCHEME_ONAIR 2
#define PVR2_ROUTING_SCHEME_AV400 3
+#define PVR2_ROUTING_SCHEME_HAUP160XXX 4
#define PVR2_DIGITAL_SCHEME_NONE 0
#define PVR2_DIGITAL_SCHEME_HAUPPAUGE 1
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-dvb.c b/drivers/media/usb/pvrusb2/pvrusb2-dvb.c
index 4b32b2141169..6954584526a3 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-dvb.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-dvb.c
@@ -1,17 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* pvrusb2-dvb.c - linux-dvb api interface to the pvrusb2 driver.
*
* Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <linux/kthread.h>
@@ -343,26 +334,19 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap)
goto done;
}
- if ((dvb_props->frontend_attach(adap) == 0) && (adap->fe)) {
-
- if (dvb_register_frontend(&adap->dvb_adap, adap->fe)) {
+ if (dvb_props->frontend_attach(adap) == 0 && adap->fe[0]) {
+ if (dvb_register_frontend(&adap->dvb_adap, adap->fe[0])) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"frontend registration failed!");
- dvb_frontend_detach(adap->fe);
- adap->fe = NULL;
ret = -ENODEV;
- goto done;
+ goto fail_frontend0;
}
+ if (adap->fe[0]->ops.analog_ops.standby)
+ adap->fe[0]->ops.analog_ops.standby(adap->fe[0]);
- if (dvb_props->tuner_attach)
- dvb_props->tuner_attach(adap);
-
- if (adap->fe->ops.analog_ops.standby)
- adap->fe->ops.analog_ops.standby(adap->fe);
-
- /* Ensure all frontends negotiate bus access */
- adap->fe->ops.ts_bus_ctrl = pvr2_dvb_bus_ctrl;
-
+ pvr2_trace(PVR2_TRACE_INFO, "transferring fe[%d] ts_bus_ctrl() to pvr2_dvb_bus_ctrl()",
+ adap->fe[0]->id);
+ adap->fe[0]->ops.ts_bus_ctrl = pvr2_dvb_bus_ctrl;
} else {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"no frontend was attached!");
@@ -370,17 +354,74 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap)
return ret;
}
- done:
+ if (dvb_props->tuner_attach && dvb_props->tuner_attach(adap)) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS, "tuner attach failed");
+ ret = -ENODEV;
+ goto fail_tuner;
+ }
+
+ if (adap->fe[1]) {
+ adap->fe[1]->id = 1;
+ adap->fe[1]->tuner_priv = adap->fe[0]->tuner_priv;
+ memcpy(&adap->fe[1]->ops.tuner_ops,
+ &adap->fe[0]->ops.tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
+ if (dvb_register_frontend(&adap->dvb_adap, adap->fe[1])) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "frontend registration failed!");
+ ret = -ENODEV;
+ goto fail_frontend1;
+ }
+ /* MFE lock */
+ adap->dvb_adap.mfe_shared = 1;
+
+ if (adap->fe[1]->ops.analog_ops.standby)
+ adap->fe[1]->ops.analog_ops.standby(adap->fe[1]);
+
+ pvr2_trace(PVR2_TRACE_INFO, "transferring fe[%d] ts_bus_ctrl() to pvr2_dvb_bus_ctrl()",
+ adap->fe[1]->id);
+ adap->fe[1]->ops.ts_bus_ctrl = pvr2_dvb_bus_ctrl;
+ }
+done:
pvr2_channel_limit_inputs(&adap->channel, 0);
return ret;
+
+fail_frontend1:
+ dvb_frontend_detach(adap->fe[1]);
+ adap->fe[1] = NULL;
+fail_tuner:
+ dvb_unregister_frontend(adap->fe[0]);
+fail_frontend0:
+ dvb_frontend_detach(adap->fe[0]);
+ adap->fe[0] = NULL;
+ dvb_module_release(adap->i2c_client_tuner);
+ dvb_module_release(adap->i2c_client_demod[1]);
+ dvb_module_release(adap->i2c_client_demod[0]);
+
+ return ret;
}
static int pvr2_dvb_frontend_exit(struct pvr2_dvb_adapter *adap)
{
- if (adap->fe != NULL) {
- dvb_unregister_frontend(adap->fe);
- dvb_frontend_detach(adap->fe);
+ if (adap->fe[1]) {
+ dvb_unregister_frontend(adap->fe[1]);
+ dvb_frontend_detach(adap->fe[1]);
+ adap->fe[1] = NULL;
}
+ if (adap->fe[0]) {
+ dvb_unregister_frontend(adap->fe[0]);
+ dvb_frontend_detach(adap->fe[0]);
+ adap->fe[0] = NULL;
+ }
+
+ dvb_module_release(adap->i2c_client_tuner);
+ adap->i2c_client_tuner = NULL;
+ dvb_module_release(adap->i2c_client_demod[1]);
+ adap->i2c_client_demod[1] = NULL;
+ dvb_module_release(adap->i2c_client_demod[0]);
+ adap->i2c_client_demod[0] = NULL;
+
return 0;
}
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-dvb.h b/drivers/media/usb/pvrusb2/pvrusb2-dvb.h
index e7f71fb94a6e..c0b27f5211bf 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-dvb.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-dvb.h
@@ -18,7 +18,10 @@ struct pvr2_dvb_adapter {
struct dmxdev dmxdev;
struct dvb_demux demux;
struct dvb_net dvb_net;
- struct dvb_frontend *fe;
+ struct dvb_frontend *fe[2];
+
+ struct i2c_client *i2c_client_demod[2];
+ struct i2c_client *i2c_client_tuner;
int feedcount;
int max_feed_count;
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c
index 8b643d511a0b..79f0e0c6df37 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c
@@ -1,18 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <linux/slab.h>
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-eeprom.h b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.h
index 1d81cac30f3d..a65cc695fd68 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-eeprom.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.h
@@ -1,18 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#ifndef __PVRUSB2_EEPROM_H
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-encoder.c b/drivers/media/usb/pvrusb2/pvrusb2-encoder.c
index 43e43404095f..fb3178d909ce 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-encoder.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-encoder.c
@@ -1,18 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <linux/device.h> // for linux/firmware.h
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-encoder.h b/drivers/media/usb/pvrusb2/pvrusb2-encoder.h
index 10d7f0b48264..bcb5ab65f4fb 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-encoder.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-encoder.h
@@ -1,18 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#ifndef __PVRUSB2_ENCODER_H
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h b/drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h
index 0a01de4e54db..e54aa42b4115 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h
@@ -1,17 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
*
- *
* Copyright (C) 2007 Michael Krufky <mkrufky@linuxtv.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#ifndef _PVRUSB2_FX2_CMD_H_
@@ -38,6 +28,10 @@
#define FX2CMD_FWPOST1 0x52u
+/* These 2 only exist on Model 160xxx */
+#define FX2CMD_HCW_DEMOD_RESET_PIN 0xd4u
+#define FX2CMD_HCW_MAKO_SLEEP_PIN 0xd5u
+
#define FX2CMD_POWER_OFF 0xdcu
#define FX2CMD_POWER_ON 0xdeu
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h
index 7a824196d5fa..7c998ca616ac 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h
@@ -1,17 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#ifndef __PVRUSB2_HDW_INTERNAL_H
#define __PVRUSB2_HDW_INTERNAL_H
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
index 816c85786c2a..6fe8b9af858a 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
@@ -1,17 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <linux/errno.h>
@@ -316,6 +306,8 @@ static const struct pvr2_fx2cmd_descdef pvr2_fx2cmd_desc[] = {
{FX2CMD_ONAIR_DTV_STREAMING_OFF, "onair dtv stream off"},
{FX2CMD_ONAIR_DTV_POWER_ON, "onair dtv power on"},
{FX2CMD_ONAIR_DTV_POWER_OFF, "onair dtv power off"},
+ {FX2CMD_HCW_DEMOD_RESET_PIN, "hcw demod reset pin"},
+ {FX2CMD_HCW_MAKO_SLEEP_PIN, "hcw mako sleep pin"},
};
@@ -1680,7 +1672,7 @@ static int pvr2_decoder_enable(struct pvr2_hdw *hdw,int enablefl)
}
if (!hdw->flag_decoder_missed) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "WARNING: No decoder present");
+ "***WARNING*** No decoder present");
hdw->flag_decoder_missed = !0;
trace_stbit("flag_decoder_missed",
hdw->flag_decoder_missed);
@@ -2139,10 +2131,28 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
((0) << 16));
}
- // This step MUST happen after the earlier powerup step.
+ /* This step MUST happen after the earlier powerup step */
pvr2_i2c_core_init(hdw);
if (!pvr2_hdw_dev_ok(hdw)) return;
+ /* Reset demod only on Hauppauge 160xxx platform */
+ if (le16_to_cpu(hdw->usb_dev->descriptor.idVendor) == 0x2040 &&
+ (le16_to_cpu(hdw->usb_dev->descriptor.idProduct) == 0x7502 ||
+ le16_to_cpu(hdw->usb_dev->descriptor.idProduct) == 0x7510)) {
+ pr_info("%s(): resetting 160xxx demod\n", __func__);
+ /* TODO: not sure this is proper place to reset once only */
+ pvr2_issue_simple_cmd(hdw,
+ FX2CMD_HCW_DEMOD_RESET_PIN |
+ (1 << 8) |
+ ((0) << 16));
+ usleep_range(10000, 10500);
+ pvr2_issue_simple_cmd(hdw,
+ FX2CMD_HCW_DEMOD_RESET_PIN |
+ (1 << 8) |
+ ((1) << 16));
+ usleep_range(10000, 10500);
+ }
+
pvr2_hdw_load_modules(hdw);
if (!pvr2_hdw_dev_ok(hdw)) return;
@@ -2366,7 +2376,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
if (hdw_desc->flag_is_experimental) {
pvr2_trace(PVR2_TRACE_INFO, "**********");
pvr2_trace(PVR2_TRACE_INFO,
- "WARNING: Support for this device (%s) is experimental.",
+ "***WARNING*** Support for this device (%s) is experimental.",
hdw_desc->description);
pvr2_trace(PVR2_TRACE_INFO,
"Important functionality might not be entirely working.");
@@ -4012,6 +4022,20 @@ int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *hdw)
static int pvr2_hdw_cmd_hcw_demod_reset(struct pvr2_hdw *hdw, int onoff)
{
hdw->flag_ok = !0;
+
+ /* Use this for Hauppauge 160xxx only */
+ if (le16_to_cpu(hdw->usb_dev->descriptor.idVendor) == 0x2040 &&
+ (le16_to_cpu(hdw->usb_dev->descriptor.idProduct) == 0x7502 ||
+ le16_to_cpu(hdw->usb_dev->descriptor.idProduct) == 0x7510)) {
+ pr_debug("%s(): resetting demod on Hauppauge 160xxx platform skipped\n",
+ __func__);
+ /* Can't reset 160xxx or it will trash Demod tristate */
+ return pvr2_issue_simple_cmd(hdw,
+ FX2CMD_HCW_MAKO_SLEEP_PIN |
+ (1 << 8) |
+ ((onoff ? 1 : 0) << 16));
+ }
+
return pvr2_issue_simple_cmd(hdw,
FX2CMD_HCW_DEMOD_RESETIN |
(1 << 8) |
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.h b/drivers/media/usb/pvrusb2/pvrusb2-hdw.h
index bd2b7a67b732..860f0a6b099c 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.h
@@ -1,17 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#ifndef __PVRUSB2_HDW_H
#define __PVRUSB2_HDW_H
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c
index 8f023085c2d9..275394bafe7d 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c
@@ -1,17 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <linux/i2c.h>
@@ -343,11 +333,11 @@ static int i2c_hack_cx25840(struct pvr2_hdw *hdw,
if ((ret != 0) || (*rdata == 0x04) || (*rdata == 0x0a)) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "WARNING: Detected a wedged cx25840 chip; the device will not work.");
+ "***WARNING*** Detected a wedged cx25840 chip; the device will not work.");
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "WARNING: Try power cycling the pvrusb2 device.");
+ "***WARNING*** Try power cycling the pvrusb2 device.");
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "WARNING: Disabling further access to the device to prevent other foul-ups.");
+ "***WARNING*** Disabling further access to the device to prevent other foul-ups.");
// This blocks all further communication with the part.
hdw->i2c_func[0x44] = NULL;
pvr2_hdw_render_useless(hdw);
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.h b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.h
index 1c44dee7fd69..6da66a80a1aa 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.h
@@ -1,17 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#ifndef __PVRUSB2_I2C_CORE_H
#define __PVRUSB2_I2C_CORE_H
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-io.c b/drivers/media/usb/pvrusb2/pvrusb2-io.c
index 6d153fc23ec2..675dc7153e2b 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-io.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-io.c
@@ -1,17 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include "pvrusb2-io.h"
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-io.h b/drivers/media/usb/pvrusb2/pvrusb2-io.h
index e769aeb9d529..80e4f831f5e2 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-io.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-io.h
@@ -1,17 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#ifndef __PVRUSB2_IO_H
#define __PVRUSB2_IO_H
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-ioread.c b/drivers/media/usb/pvrusb2/pvrusb2-ioread.c
index 602097bdcf14..46f8013849b9 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-ioread.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-ioread.c
@@ -1,17 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include "pvrusb2-ioread.h"
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-ioread.h b/drivers/media/usb/pvrusb2/pvrusb2-ioread.h
index 5827ea09c5e3..33df00a7e515 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-ioread.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-ioread.h
@@ -1,17 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#ifndef __PVRUSB2_IOREAD_H
#define __PVRUSB2_IOREAD_H
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-main.c b/drivers/media/usb/pvrusb2/pvrusb2-main.c
index 23672dd352f5..ce4d566e4e5a 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-main.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-main.c
@@ -1,18 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-std.c b/drivers/media/usb/pvrusb2/pvrusb2-std.c
index 6b651f8b54df..e7ab41401577 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-std.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-std.c
@@ -1,17 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include "pvrusb2-std.h"
@@ -353,7 +343,7 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
bcnt = pvr2_std_id_to_str(buf,sizeof(buf),fmsk);
pvr2_trace(
PVR2_TRACE_ERROR_LEGS,
- "WARNING: Failed to classify the following standard(s): %.*s",
+ "***WARNING*** Failed to classify the following standard(s): %.*s",
bcnt,buf);
}
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-std.h b/drivers/media/usb/pvrusb2/pvrusb2-std.h
index b48304f41472..d8b4c6dc72fe 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-std.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-std.h
@@ -1,17 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#ifndef __PVRUSB2_STD_H
#define __PVRUSB2_STD_H
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c
index 7bc6d090358e..3e42e209be37 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c
@@ -1,17 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <linux/string.h>
@@ -802,7 +792,8 @@ struct pvr2_sysfs_class *pvr2_sysfs_class_create(void)
void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *clp)
{
pvr2_sysfs_trace("Unregistering pvr2_sysfs_class id=%p", clp);
- class_unregister(&clp->class);
+ if (clp)
+ class_unregister(&clp->class);
}
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.h b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.h
index 431f4fd19015..ac580ff39b5f 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.h
@@ -1,17 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#ifndef __PVRUSB2_SYSFS_H
#define __PVRUSB2_SYSFS_H
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-util.h b/drivers/media/usb/pvrusb2/pvrusb2-util.h
index b03ca3ef1ba0..7059772a4906 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-util.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-util.h
@@ -1,17 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#ifndef __PVRUSB2_UTIL_H
#define __PVRUSB2_UTIL_H
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
index cb6668580d77..0aff2f396392 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
@@ -1,18 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <linux/kernel.h>
@@ -128,17 +118,6 @@ static int pvr2_querycap(struct file *file, void *priv, struct v4l2_capability *
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER |
V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
V4L2_CAP_READWRITE | V4L2_CAP_DEVICE_CAPS;
- switch (fh->pdi->devbase.vfl_type) {
- case VFL_TYPE_GRABBER:
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO;
- break;
- case VFL_TYPE_RADIO:
- cap->device_caps = V4L2_CAP_RADIO;
- break;
- default:
- return -EINVAL;
- }
- cap->device_caps |= V4L2_CAP_TUNER | V4L2_CAP_READWRITE;
return 0;
}
@@ -1205,6 +1184,8 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
int unit_number;
struct pvr2_hdw *hdw;
int *nr_ptr = NULL;
+ u32 caps = V4L2_CAP_TUNER | V4L2_CAP_READWRITE;
+
dip->v4lp = vp;
hdw = vp->channel.mc_head->hdw;
@@ -1215,6 +1196,7 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
dip->config = pvr2_config_mpeg;
dip->minor_type = pvr2_v4l_type_video;
nr_ptr = video_nr;
+ caps |= V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO;
if (!dip->stream) {
pr_err(KBUILD_MODNAME
": Failed to set up pvrusb2 v4l video dev due to missing stream instance\n");
@@ -1225,12 +1207,14 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
dip->config = pvr2_config_vbi;
dip->minor_type = pvr2_v4l_type_vbi;
nr_ptr = vbi_nr;
+ caps |= V4L2_CAP_VBI_CAPTURE;
break;
case VFL_TYPE_RADIO:
dip->stream = &vp->channel.mc_head->video_stream;
dip->config = pvr2_config_mpeg;
dip->minor_type = pvr2_v4l_type_radio;
nr_ptr = radio_nr;
+ caps |= V4L2_CAP_RADIO;
break;
default:
/* Bail out (this should be impossible) */
@@ -1241,6 +1225,7 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
dip->devbase = vdev_template;
dip->devbase.release = pvr2_video_device_release;
dip->devbase.ioctl_ops = &pvr2_ioctl_ops;
+ dip->devbase.device_caps = caps;
{
int val;
pvr2_ctrl_get_value(
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.h b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.h
index ec755ee8f86a..e1f9f09b6dd0 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.h
@@ -1,17 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#ifndef __PVRUSB2_V4L2_H
#define __PVRUSB2_V4L2_H
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c
index b68aec2124b2..16dd3e859977 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c
@@ -1,18 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
/*
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.h b/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.h
index fa33f20655f4..2a1776ba4b2d 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.h
@@ -1,18 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#ifndef __PVRUSB2_VIDEO_V4L_H
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-wm8775.c b/drivers/media/usb/pvrusb2/pvrusb2-wm8775.c
index 8f357f771ba7..5f800f4a829c 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-wm8775.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-wm8775.c
@@ -1,18 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
/*
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-wm8775.h b/drivers/media/usb/pvrusb2/pvrusb2-wm8775.h
index c4ac7c2701d0..806d8b758570 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-wm8775.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-wm8775.h
@@ -1,18 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#ifndef __PVRUSB2_WM8775_H
diff --git a/drivers/media/usb/pvrusb2/pvrusb2.h b/drivers/media/usb/pvrusb2/pvrusb2.h
index 955290ba2d54..1185b72a5fed 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2.h
@@ -1,18 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
*
- *
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#ifndef __PVRUSB2_H
diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c
index a15ad0f3faf1..9b76cf133d52 100644
--- a/drivers/media/usb/pwc/pwc-if.c
+++ b/drivers/media/usb/pwc/pwc-if.c
@@ -1113,6 +1113,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
pdev->v4l2_dev.ctrl_handler = &pdev->ctrl_handler;
pdev->vdev.v4l2_dev = &pdev->v4l2_dev;
pdev->vdev.lock = &pdev->v4l2_lock;
+ pdev->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE;
rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, -1);
if (rc < 0) {
diff --git a/drivers/media/usb/pwc/pwc-v4l.c b/drivers/media/usb/pwc/pwc-v4l.c
index 5212898db77c..76c498cccc49 100644
--- a/drivers/media/usb/pwc/pwc-v4l.c
+++ b/drivers/media/usb/pwc/pwc-v4l.c
@@ -483,9 +483,6 @@ static int pwc_querycap(struct file *file, void *fh, struct v4l2_capability *cap
strscpy(cap->driver, PWC_NAME, sizeof(cap->driver));
strscpy(cap->card, pdev->vdev.name, sizeof(cap->card));
usb_make_path(pdev->udev, cap->bus_info, sizeof(cap->bus_info));
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
- V4L2_CAP_READWRITE;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
diff --git a/drivers/media/usb/pwc/pwc.h b/drivers/media/usb/pwc/pwc.h
index 8aa7e868e6b1..3362962d0d00 100644
--- a/drivers/media/usb/pwc/pwc.h
+++ b/drivers/media/usb/pwc/pwc.h
@@ -43,15 +43,15 @@
/* Trace certain actions in the driver */
-#define PWC_DEBUG_LEVEL_MODULE (1<<0)
-#define PWC_DEBUG_LEVEL_PROBE (1<<1)
-#define PWC_DEBUG_LEVEL_OPEN (1<<2)
-#define PWC_DEBUG_LEVEL_READ (1<<3)
-#define PWC_DEBUG_LEVEL_MEMORY (1<<4)
-#define PWC_DEBUG_LEVEL_FLOW (1<<5)
-#define PWC_DEBUG_LEVEL_SIZE (1<<6)
-#define PWC_DEBUG_LEVEL_IOCTL (1<<7)
-#define PWC_DEBUG_LEVEL_TRACE (1<<8)
+#define PWC_DEBUG_LEVEL_MODULE BIT(0)
+#define PWC_DEBUG_LEVEL_PROBE BIT(1)
+#define PWC_DEBUG_LEVEL_OPEN BIT(2)
+#define PWC_DEBUG_LEVEL_READ BIT(3)
+#define PWC_DEBUG_LEVEL_MEMORY BIT(4)
+#define PWC_DEBUG_LEVEL_FLOW BIT(5)
+#define PWC_DEBUG_LEVEL_SIZE BIT(6)
+#define PWC_DEBUG_LEVEL_IOCTL BIT(7)
+#define PWC_DEBUG_LEVEL_TRACE BIT(8)
#define PWC_DEBUG_MODULE(fmt, args...) PWC_DEBUG(MODULE, fmt, ##args)
#define PWC_DEBUG_PROBE(fmt, args...) PWC_DEBUG(PROBE, fmt, ##args)
diff --git a/drivers/media/usb/s2255/Kconfig b/drivers/media/usb/s2255/Kconfig
index e0e3c0ba3f23..e4a0c914d9c3 100644
--- a/drivers/media/usb/s2255/Kconfig
+++ b/drivers/media/usb/s2255/Kconfig
@@ -3,7 +3,6 @@ config USB_S2255
tristate "USB Sensoray 2255 video capture device"
depends on VIDEO_V4L2
select VIDEOBUF2_VMALLOC
- default n
help
Say Y here if you want support for the Sensoray 2255 USB device.
This driver can be compiled as a module, called s2255drv.
diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c
index 3eccbd48bdac..aa90558479f7 100644
--- a/drivers/media/usb/s2255/s2255drv.c
+++ b/drivers/media/usb/s2255/s2255drv.c
@@ -724,9 +724,6 @@ static int vidioc_querycap(struct file *file, void *priv,
strscpy(cap->driver, "s2255", sizeof(cap->driver));
strscpy(cap->card, "s2255", sizeof(cap->card));
usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
- V4L2_CAP_READWRITE;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -1657,6 +1654,8 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
vc->vdev.ctrl_handler = &vc->hdl;
vc->vdev.lock = &dev->lock;
vc->vdev.v4l2_dev = &dev->v4l2_dev;
+ vc->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
video_set_drvdata(&vc->vdev, vc);
if (video_nr == -1)
ret = video_register_device(&vc->vdev,
diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c
index 38016632c6d8..b71a0f4b40b5 100644
--- a/drivers/media/usb/stk1160/stk1160-v4l.c
+++ b/drivers/media/usb/stk1160/stk1160-v4l.c
@@ -337,11 +337,6 @@ static int vidioc_querycap(struct file *file,
strscpy(cap->driver, "stk1160", sizeof(cap->driver));
strscpy(cap->card, "stk1160", sizeof(cap->card));
usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
- cap->device_caps =
- V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_STREAMING |
- V4L2_CAP_READWRITE;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -821,6 +816,8 @@ int stk1160_video_register(struct stk1160 *dev)
/* This will be used to set video_device parent */
dev->vdev.v4l2_dev = &dev->v4l2_dev;
+ dev->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE;
/* NTSC is default */
dev->norm = V4L2_STD_NTSC_M;
diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c
index cb7d6454bbe1..be8041e3e6b8 100644
--- a/drivers/media/usb/stkwebcam/stk-webcam.c
+++ b/drivers/media/usb/stkwebcam/stk-webcam.c
@@ -798,10 +798,6 @@ static int stk_vidioc_querycap(struct file *filp,
strscpy(cap->driver, "stk", sizeof(cap->driver));
strscpy(cap->card, "stk", sizeof(cap->card));
usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
-
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE
- | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -1261,6 +1257,8 @@ static int stk_register_video_device(struct stk_camera *dev)
dev->vdev = stk_v4l_data;
dev->vdev.lock = &dev->lock;
dev->vdev.v4l2_dev = &dev->v4l2_dev;
+ dev->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING;
video_set_drvdata(&dev->vdev, dev);
err = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1);
if (err)
diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c
index 072210f5f92f..85fcddfb0202 100644
--- a/drivers/media/usb/tm6000/tm6000-video.c
+++ b/drivers/media/usb/tm6000/tm6000-video.c
@@ -854,22 +854,17 @@ static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev;
- struct video_device *vdev = video_devdata(file);
strscpy(cap->driver, "tm6000", sizeof(cap->driver));
strscpy(cap->card, "Trident TVMaster TM5600/6000/6010",
sizeof(cap->card));
usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_DEVICE_CAPS;
if (dev->tuner_type != TUNER_ABSENT)
- cap->device_caps |= V4L2_CAP_TUNER;
- if (vdev->vfl_type == VFL_TYPE_GRABBER)
- cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_STREAMING |
- V4L2_CAP_READWRITE;
- else
- cap->device_caps |= V4L2_CAP_RADIO;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS |
- V4L2_CAP_RADIO | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+ cap->capabilities |= V4L2_CAP_TUNER;
+ if (dev->caps.has_radio)
+ cap->capabilities |= V4L2_CAP_RADIO;
return 0;
}
@@ -1639,6 +1634,10 @@ int tm6000_v4l2_register(struct tm6000_core *dev)
vdev_init(dev, &dev->vfd, &tm6000_template, "video");
dev->vfd.ctrl_handler = &dev->ctrl_handler;
+ dev->vfd.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE;
+ if (dev->tuner_type != TUNER_ABSENT)
+ dev->vfd.device_caps |= V4L2_CAP_TUNER;
/* init video dma queues */
INIT_LIST_HEAD(&dev->vidq.active);
@@ -1659,6 +1658,7 @@ int tm6000_v4l2_register(struct tm6000_core *dev)
vdev_init(dev, &dev->radio_dev, &tm6000_radio_template,
"radio");
dev->radio_dev.ctrl_handler = &dev->radio_ctrl_handler;
+ dev->radio_dev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
ret = video_register_device(&dev->radio_dev, VFL_TYPE_RADIO,
radio_nr);
if (ret < 0) {
diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c
index 4a1eab711bdc..51f784479e91 100644
--- a/drivers/media/usb/usbtv/usbtv-video.c
+++ b/drivers/media/usb/usbtv/usbtv-video.c
@@ -603,9 +603,6 @@ static int usbtv_querycap(struct file *file, void *priv,
strscpy(cap->driver, "usbtv", sizeof(cap->driver));
strscpy(cap->card, "usbtv", sizeof(cap->card));
usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE;
- cap->device_caps |= V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -942,6 +939,8 @@ int usbtv_video_init(struct usbtv *usbtv)
usbtv->vdev.tvnorms = USBTV_TV_STD;
usbtv->vdev.queue = &usbtv->vb2q;
usbtv->vdev.lock = &usbtv->v4l2_lock;
+ usbtv->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING;
video_set_drvdata(&usbtv->vdev, usbtv);
ret = video_register_device(&usbtv->vdev, VFL_TYPE_GRABBER, -1);
if (ret < 0) {
diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c
index 6d42154e3d0a..93750af82d98 100644
--- a/drivers/media/usb/usbvision/usbvision-video.c
+++ b/drivers/media/usb/usbvision/usbvision-video.c
@@ -452,24 +452,18 @@ static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *vc)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- struct video_device *vdev = video_devdata(file);
strscpy(vc->driver, "USBVision", sizeof(vc->driver));
strscpy(vc->card,
usbvision_device_data[usbvision->dev_model].model_string,
sizeof(vc->card));
usb_make_path(usbvision->dev, vc->bus_info, sizeof(vc->bus_info));
- vc->device_caps = usbvision->have_tuner ? V4L2_CAP_TUNER : 0;
- if (vdev->vfl_type == VFL_TYPE_GRABBER)
- vc->device_caps |= V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
- else
- vc->device_caps |= V4L2_CAP_RADIO;
-
- vc->capabilities = vc->device_caps | V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS;
+ vc->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS;
if (usbvision_device_data[usbvision->dev_model].radio)
vc->capabilities |= V4L2_CAP_RADIO;
+ if (usbvision->have_tuner)
+ vc->capabilities |= V4L2_CAP_TUNER;
return 0;
}
@@ -1267,6 +1261,11 @@ static int usbvision_register_video(struct usb_usbvision *usbvision)
v4l2_disable_ioctl(&usbvision->vdev, VIDIOC_G_FREQUENCY);
v4l2_disable_ioctl(&usbvision->vdev, VIDIOC_S_TUNER);
}
+ usbvision->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+ if (usbvision->have_tuner)
+ usbvision->vdev.device_caps |= V4L2_CAP_TUNER;
+
if (video_register_device(&usbvision->vdev, VFL_TYPE_GRABBER, video_nr) < 0)
goto err_exit;
printk(KERN_INFO "USBVision[%d]: registered USBVision Video device %s [v4l2]\n",
@@ -1277,6 +1276,7 @@ static int usbvision_register_video(struct usb_usbvision *usbvision)
/* usbvision has radio */
usbvision_vdev_init(usbvision, &usbvision->rdev,
&usbvision_radio_template, "USBVision Radio");
+ usbvision->rdev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
if (video_register_device(&usbvision->rdev, VFL_TYPE_RADIO, radio_nr) < 0)
goto err_exit;
printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device %s [v4l2]\n",
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 26163a5bde7d..e399b9fad757 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -2345,7 +2345,9 @@ void uvc_ctrl_cleanup_device(struct uvc_device *dev)
struct uvc_entity *entity;
unsigned int i;
- cancel_work_sync(&dev->async_ctrl.work);
+ /* Can be uninitialized if we are aborting on probe error. */
+ if (dev->async_ctrl.work.func)
+ cancel_work_sync(&dev->async_ctrl.work);
/* Free controls and control mappings for all entities. */
list_for_each_entry(entity, &dev->entities, list) {
diff --git a/drivers/media/usb/uvc/uvc_debugfs.c b/drivers/media/usb/uvc/uvc_debugfs.c
index 8ba54139a087..d2b109959d82 100644
--- a/drivers/media/usb/uvc/uvc_debugfs.c
+++ b/drivers/media/usb/uvc/uvc_debugfs.c
@@ -74,12 +74,13 @@ void uvc_debugfs_init_stream(struct uvc_streaming *stream)
{
struct usb_device *udev = stream->dev->udev;
struct dentry *dent;
- char dir_name[32];
+ char dir_name[33];
if (uvc_debugfs_root_dir == NULL)
return;
- sprintf(dir_name, "%u-%u", udev->bus->busnum, udev->devnum);
+ snprintf(dir_name, sizeof(dir_name), "%u-%u-%u", udev->bus->busnum,
+ udev->devnum, stream->intfnum);
dent = debugfs_create_dir(dir_name, uvc_debugfs_root_dir);
if (IS_ERR_OR_NULL(dent)) {
diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c
index 37a7992585df..a9bcba4fa9c6 100644
--- a/drivers/media/usb/zr364xx/zr364xx.c
+++ b/drivers/media/usb/zr364xx/zr364xx.c
@@ -694,14 +694,10 @@ static int zr364xx_vidioc_querycap(struct file *file, void *priv,
struct zr364xx_camera *cam = video_drvdata(file);
strscpy(cap->driver, DRIVER_DESC, sizeof(cap->driver));
- strscpy(cap->card, cam->udev->product, sizeof(cap->card));
+ if (cam->udev->product)
+ strscpy(cap->card, cam->udev->product, sizeof(cap->card));
strscpy(cap->bus_info, dev_name(&cam->udev->dev),
sizeof(cap->bus_info));
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
-
return 0;
}
@@ -1328,6 +1324,8 @@ static const struct video_device zr364xx_template = {
.fops = &zr364xx_fops,
.ioctl_ops = &zr364xx_ioctl_ops,
.release = video_device_release_empty,
+ .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING,
};
diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
index 8b9d4b3ec10e..7c5f62f196e5 100644
--- a/drivers/media/v4l2-core/Kconfig
+++ b/drivers/media/v4l2-core/Kconfig
@@ -13,7 +13,6 @@ config VIDEO_V4L2
config VIDEO_ADV_DEBUG
bool "Enable advanced debug functionality on V4L2 drivers"
- default n
help
Say Y here to enable advanced debugging functionality on some
V4L devices.
@@ -21,7 +20,6 @@ config VIDEO_ADV_DEBUG
config VIDEO_FIXED_MINOR_RANGES
bool "Enable old-style fixed minor ranges on drivers/video devices"
- default n
help
Say Y here to enable the old-style fixed-range minor assignments.
Only useful if you rely on the old behavior and use mknod instead of udev.
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 15b0c44a76e7..8d307b538f52 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* V4L2 asynchronous subdevice registration API
*
* Copyright (C) 2012-2013, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- *
- * 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.
*/
#include <linux/device.h>
diff --git a/drivers/media/v4l2-core/v4l2-clk.c b/drivers/media/v4l2-core/v4l2-clk.c
index 90628d7a04de..91274eee6977 100644
--- a/drivers/media/v4l2-core/v4l2-clk.c
+++ b/drivers/media/v4l2-core/v4l2-clk.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* V4L2 clock service
*
* Copyright (C) 2012-2013, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- *
- * 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.
*/
#include <linux/atomic.h>
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index c9efb2de710d..f8ad1c580a3e 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -321,6 +321,16 @@ static unsigned int clamp_align(unsigned int x, unsigned int min,
return x;
}
+static unsigned int clamp_roundup(unsigned int x, unsigned int min,
+ unsigned int max, unsigned int alignment)
+{
+ x = clamp(x, min, max);
+ if (alignment)
+ x = round_up(x, alignment);
+
+ return x;
+}
+
void v4l_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax,
unsigned int walign,
u32 *h, unsigned int hmin, unsigned int hmax,
@@ -531,8 +541,25 @@ static inline unsigned int v4l2_format_block_height(const struct v4l2_format_inf
return info->block_h[plane];
}
+void v4l2_apply_frmsize_constraints(u32 *width, u32 *height,
+ const struct v4l2_frmsize_stepwise *frmsize)
+{
+ if (!frmsize)
+ return;
+
+ /*
+ * Clamp width/height to meet min/max constraints and round it up to
+ * macroblock alignment.
+ */
+ *width = clamp_roundup(*width, frmsize->min_width, frmsize->max_width,
+ frmsize->step_width);
+ *height = clamp_roundup(*height, frmsize->min_height, frmsize->max_height,
+ frmsize->step_height);
+}
+EXPORT_SYMBOL_GPL(v4l2_apply_frmsize_constraints);
+
int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt,
- int pixelformat, int width, int height)
+ u32 pixelformat, u32 width, u32 height)
{
const struct v4l2_format_info *info;
struct v4l2_plane_pix_format *plane;
@@ -586,7 +613,8 @@ int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt,
}
EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt_mp);
-int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, int pixelformat, int width, int height)
+int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat,
+ u32 width, u32 height)
{
const struct v4l2_format_info *info;
int i;
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 7d3a33258748..371537dd8cd3 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -394,6 +394,21 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
"Explicit",
NULL,
};
+ static const char * const mpeg_mpeg2_level[] = {
+ "Low",
+ "Main",
+ "High 1440",
+ "High",
+ NULL,
+ };
+ static const char * const mpeg2_profile[] = {
+ "Simple",
+ "Main",
+ "SNR Scalable",
+ "Spatially Scalable",
+ "High",
+ NULL,
+ };
static const char * const mpeg_mpeg4_level[] = {
"0",
"0b",
@@ -610,6 +625,10 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
return h264_fp_arrangement_type;
case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE:
return h264_fmo_map_type;
+ case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL:
+ return mpeg_mpeg2_level;
+ case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE:
+ return mpeg2_profile;
case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
return mpeg_mpeg4_level;
case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
@@ -820,6 +839,13 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP: return "H264 I-Frame Maximum QP Value";
case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP: return "H264 P-Frame Minimum QP Value";
case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP: return "H264 P-Frame Maximum QP Value";
+ case V4L2_CID_MPEG_VIDEO_H264_SPS: return "H264 Sequence Parameter Set";
+ case V4L2_CID_MPEG_VIDEO_H264_PPS: return "H264 Picture Parameter Set";
+ case V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX: return "H264 Scaling Matrix";
+ case V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS: return "H264 Slice Parameters";
+ case V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS: return "H264 Decode Parameters";
+ case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: return "MPEG2 Level";
+ case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: return "MPEG2 Profile";
case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: return "MPEG4 I-Frame QP Value";
case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP: return "MPEG4 P-Frame QP Value";
case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP: return "MPEG4 B-Frame QP Value";
@@ -1145,6 +1171,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_FLASH_STROBE_STOP:
case V4L2_CID_AUTO_FOCUS_START:
case V4L2_CID_AUTO_FOCUS_STOP:
+ case V4L2_CID_DO_WHITE_BALANCE:
*type = V4L2_CTRL_TYPE_BUTTON;
*flags |= V4L2_CTRL_FLAG_WRITE_ONLY |
V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
@@ -1184,6 +1211,8 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:
case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE:
case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE:
+ case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL:
+ case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE:
case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
@@ -1301,6 +1330,21 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_MPEG_VIDEO_FWHT_PARAMS:
*type = V4L2_CTRL_TYPE_FWHT_PARAMS;
break;
+ case V4L2_CID_MPEG_VIDEO_H264_SPS:
+ *type = V4L2_CTRL_TYPE_H264_SPS;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_PPS:
+ *type = V4L2_CTRL_TYPE_H264_PPS;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX:
+ *type = V4L2_CTRL_TYPE_H264_SCALING_MATRIX;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS:
+ *type = V4L2_CTRL_TYPE_H264_SLICE_PARAMS;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS:
+ *type = V4L2_CTRL_TYPE_H264_DECODE_PARAMS;
+ break;
default:
*type = V4L2_CTRL_TYPE_INTEGER;
break;
@@ -1450,6 +1494,32 @@ static bool std_equal(const struct v4l2_ctrl *ctrl, u32 idx,
}
}
+static void std_init_compound(const struct v4l2_ctrl *ctrl, u32 idx,
+ union v4l2_ctrl_ptr ptr)
+{
+ struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params;
+ void *p = ptr.p + idx * ctrl->elem_size;
+
+ memset(p, 0, ctrl->elem_size);
+
+ /*
+ * The cast is needed to get rid of a gcc warning complaining that
+ * V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS is not part of the
+ * v4l2_ctrl_type enum.
+ */
+ switch ((u32)ctrl->type) {
+ case V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS:
+ p_mpeg2_slice_params = p;
+ /* 4:2:0 */
+ p_mpeg2_slice_params->sequence.chroma_format = 1;
+ /* interlaced top field */
+ p_mpeg2_slice_params->picture.picture_structure = 1;
+ p_mpeg2_slice_params->picture.picture_coding_type =
+ V4L2_MPEG2_PICTURE_CODING_TYPE_I;
+ break;
+ }
+}
+
static void std_init(const struct v4l2_ctrl *ctrl, u32 idx,
union v4l2_ctrl_ptr ptr)
{
@@ -1469,6 +1539,10 @@ static void std_init(const struct v4l2_ctrl *ctrl, u32 idx,
case V4L2_CTRL_TYPE_BOOLEAN:
ptr.p_s32[idx] = ctrl->default_value;
break;
+ case V4L2_CTRL_TYPE_BUTTON:
+ case V4L2_CTRL_TYPE_CTRL_CLASS:
+ ptr.p_s32[idx] = 0;
+ break;
case V4L2_CTRL_TYPE_U8:
ptr.p_u8[idx] = ctrl->default_value;
break;
@@ -1479,8 +1553,7 @@ static void std_init(const struct v4l2_ctrl *ctrl, u32 idx,
ptr.p_u32[idx] = ctrl->default_value;
break;
default:
- idx *= ctrl->elem_size;
- memset(ptr.p + idx, 0, ctrl->elem_size);
+ std_init_compound(ctrl, idx, ptr);
break;
}
}
@@ -1670,6 +1743,13 @@ static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx,
case V4L2_CTRL_TYPE_FWHT_PARAMS:
return 0;
+ case V4L2_CTRL_TYPE_H264_SPS:
+ case V4L2_CTRL_TYPE_H264_PPS:
+ case V4L2_CTRL_TYPE_H264_SCALING_MATRIX:
+ case V4L2_CTRL_TYPE_H264_SLICE_PARAMS:
+ case V4L2_CTRL_TYPE_H264_DECODE_PARAMS:
+ return 0;
+
default:
return -EINVAL;
}
@@ -2149,15 +2229,6 @@ static int handler_new_ref(struct v4l2_ctrl_handler *hdl,
if (size_extra_req)
new_ref->p_req.p = &new_ref[1];
- if (ctrl->handler == hdl) {
- /* By default each control starts in a cluster of its own.
- new_ref->ctrl is basically a cluster array with one
- element, so that's perfect to use as the cluster pointer.
- But only do this for the handler that owns the control. */
- ctrl->cluster = &new_ref->ctrl;
- ctrl->ncontrols = 1;
- }
-
INIT_LIST_HEAD(&new_ref->node);
mutex_lock(hdl->lock);
@@ -2190,6 +2261,15 @@ insert_in_hash:
hdl->buckets[bucket] = new_ref;
if (ctrl_ref)
*ctrl_ref = new_ref;
+ if (ctrl->handler == hdl) {
+ /* By default each control starts in a cluster of its own.
+ * new_ref->ctrl is basically a cluster array with one
+ * element, so that's perfect to use as the cluster pointer.
+ * But only do this for the handler that owns the control.
+ */
+ ctrl->cluster = &new_ref->ctrl;
+ ctrl->ncontrols = 1;
+ }
unlock:
mutex_unlock(hdl->lock);
@@ -2253,6 +2333,21 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
case V4L2_CTRL_TYPE_FWHT_PARAMS:
elem_size = sizeof(struct v4l2_ctrl_fwht_params);
break;
+ case V4L2_CTRL_TYPE_H264_SPS:
+ elem_size = sizeof(struct v4l2_ctrl_h264_sps);
+ break;
+ case V4L2_CTRL_TYPE_H264_PPS:
+ elem_size = sizeof(struct v4l2_ctrl_h264_pps);
+ break;
+ case V4L2_CTRL_TYPE_H264_SCALING_MATRIX:
+ elem_size = sizeof(struct v4l2_ctrl_h264_scaling_matrix);
+ break;
+ case V4L2_CTRL_TYPE_H264_SLICE_PARAMS:
+ elem_size = sizeof(struct v4l2_ctrl_h264_slice_params);
+ break;
+ case V4L2_CTRL_TYPE_H264_DECODE_PARAMS:
+ elem_size = sizeof(struct v4l2_ctrl_h264_decode_params);
+ break;
default:
if (type < V4L2_CTRL_COMPOUND_TYPES)
elem_size = sizeof(s32);
@@ -2369,16 +2464,15 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
v4l2_ctrl_fill(cfg->id, &name, &type, &min, &max, &step,
&def, &flags);
- is_menu = (cfg->type == V4L2_CTRL_TYPE_MENU ||
- cfg->type == V4L2_CTRL_TYPE_INTEGER_MENU);
+ is_menu = (type == V4L2_CTRL_TYPE_MENU ||
+ type == V4L2_CTRL_TYPE_INTEGER_MENU);
if (is_menu)
WARN_ON(step);
else
WARN_ON(cfg->menu_skip_mask);
- if (cfg->type == V4L2_CTRL_TYPE_MENU && qmenu == NULL)
+ if (type == V4L2_CTRL_TYPE_MENU && !qmenu) {
qmenu = v4l2_ctrl_get_menu(cfg->id);
- else if (cfg->type == V4L2_CTRL_TYPE_INTEGER_MENU &&
- qmenu_int == NULL) {
+ } else if (type == V4L2_CTRL_TYPE_INTEGER_MENU && !qmenu_int) {
handler_set_err(hdl, -EINVAL);
return NULL;
}
diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
index 414636dedffd..cbb74f748555 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -589,11 +589,9 @@ static void determine_valid_ioctls(struct video_device *vdev)
if (is_vid || is_tch) {
/* video and metadata specific ioctls */
if ((is_rx && (ops->vidioc_enum_fmt_vid_cap ||
- ops->vidioc_enum_fmt_vid_cap_mplane ||
ops->vidioc_enum_fmt_vid_overlay ||
ops->vidioc_enum_fmt_meta_cap)) ||
(is_tx && (ops->vidioc_enum_fmt_vid_out ||
- ops->vidioc_enum_fmt_vid_out_mplane ||
ops->vidioc_enum_fmt_meta_out)))
set_bit(_IOC_NR(VIDIOC_ENUM_FMT), valid_ioctls);
if ((is_rx && (ops->vidioc_g_fmt_vid_cap ||
diff --git a/drivers/media/v4l2-core/v4l2-flash-led-class.c b/drivers/media/v4l2-core/v4l2-flash-led-class.c
index 1697932af5ea..10ddcc48aa17 100644
--- a/drivers/media/v4l2-core/v4l2-flash-led-class.c
+++ b/drivers/media/v4l2-core/v4l2-flash-led-class.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* V4L2 flash LED sub-device registration helpers.
*
* Copyright (C) 2015 Samsung Electronics Co., Ltd
* Author: Jacek Anaszewski <j.anaszewski@samsung.com>
- *
- * 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.
*/
#include <linux/led-class-flash.h>
diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index c2d980ab3af7..7e740d332a54 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -209,10 +209,10 @@ static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode,
have_clk_lane = true;
}
- if (lanes_used & BIT(clock_lane)) {
- if (have_clk_lane || !use_default_lane_mapping)
- pr_warn("duplicated lane %u in clock-lanes, using defaults\n",
- v);
+ if (have_clk_lane && lanes_used & BIT(clock_lane) &&
+ !use_default_lane_mapping) {
+ pr_warn("duplicated lane %u in clock-lanes, using defaults\n",
+ v);
use_default_lane_mapping = true;
}
@@ -1095,7 +1095,7 @@ v4l2_fwnode_reference_parse_int_props(struct device *dev,
}
}
- return PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode);
+ return !fwnode || PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode);
error:
fwnode_handle_put(fwnode);
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 6859bdac86fe..b1f4b991dba6 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1321,6 +1321,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_H264: descr = "H.264"; break;
case V4L2_PIX_FMT_H264_NO_SC: descr = "H.264 (No Start Codes)"; break;
case V4L2_PIX_FMT_H264_MVC: descr = "H.264 MVC"; break;
+ case V4L2_PIX_FMT_H264_SLICE_RAW: descr = "H.264 Parsed Slice Data"; break;
case V4L2_PIX_FMT_H263: descr = "H.263"; break;
case V4L2_PIX_FMT_MPEG1: descr = "MPEG-1 ES"; break;
case V4L2_PIX_FMT_MPEG2: descr = "MPEG-2 ES"; break;
@@ -1377,8 +1378,10 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops,
struct file *file, void *fh, void *arg)
{
+ struct video_device *vdev = video_devdata(file);
struct v4l2_fmtdesc *p = arg;
int ret = check_fmt(file, p->type);
+ u32 cap_mask;
if (ret)
return ret;
@@ -1386,30 +1389,34 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops,
switch (p->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ cap_mask = V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+ V4L2_CAP_VIDEO_M2M_MPLANE;
+ if (!!(vdev->device_caps & cap_mask) !=
+ (p->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE))
+ break;
+
if (unlikely(!ops->vidioc_enum_fmt_vid_cap))
break;
ret = ops->vidioc_enum_fmt_vid_cap(file, fh, arg);
break;
- case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- if (unlikely(!ops->vidioc_enum_fmt_vid_cap_mplane))
- break;
- ret = ops->vidioc_enum_fmt_vid_cap_mplane(file, fh, arg);
- break;
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
if (unlikely(!ops->vidioc_enum_fmt_vid_overlay))
break;
ret = ops->vidioc_enum_fmt_vid_overlay(file, fh, arg);
break;
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ cap_mask = V4L2_CAP_VIDEO_OUTPUT_MPLANE |
+ V4L2_CAP_VIDEO_M2M_MPLANE;
+ if (!!(vdev->device_caps & cap_mask) !=
+ (p->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE))
+ break;
+
if (unlikely(!ops->vidioc_enum_fmt_vid_out))
break;
ret = ops->vidioc_enum_fmt_vid_out(file, fh, arg);
break;
- case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
- if (unlikely(!ops->vidioc_enum_fmt_vid_out_mplane))
- break;
- ret = ops->vidioc_enum_fmt_vid_out_mplane(file, fh, arg);
- break;
case V4L2_BUF_TYPE_SDR_CAPTURE:
if (unlikely(!ops->vidioc_enum_fmt_sdr_cap))
break;
diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c
index fd96df98c780..4f5176702937 100644
--- a/drivers/media/v4l2-core/v4l2-mem2mem.c
+++ b/drivers/media/v4l2-core/v4l2-mem2mem.c
@@ -1118,6 +1118,35 @@ int v4l2_m2m_ioctl_streamoff(struct file *file, void *priv,
}
EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_streamoff);
+int v4l2_m2m_ioctl_try_encoder_cmd(struct file *file, void *fh,
+ struct v4l2_encoder_cmd *ec)
+{
+ if (ec->cmd != V4L2_ENC_CMD_STOP && ec->cmd != V4L2_ENC_CMD_START)
+ return -EINVAL;
+
+ ec->flags = 0;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_try_encoder_cmd);
+
+int v4l2_m2m_ioctl_try_decoder_cmd(struct file *file, void *fh,
+ struct v4l2_decoder_cmd *dc)
+{
+ if (dc->cmd != V4L2_DEC_CMD_STOP && dc->cmd != V4L2_DEC_CMD_START)
+ return -EINVAL;
+
+ dc->flags = 0;
+
+ if (dc->cmd == V4L2_DEC_CMD_STOP) {
+ dc->stop.pts = 0;
+ } else if (dc->cmd == V4L2_DEC_CMD_START) {
+ dc->start.speed = 0;
+ dc->start.format = V4L2_DEC_START_FMT_NONE;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_try_decoder_cmd);
+
/*
* v4l2_file_operations helpers. It is assumed here same lock is used
* for the output and the capture buffer queue.
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index f24978b80440..21fb90d66bfc 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -112,56 +112,217 @@ static int subdev_close(struct file *file)
return 0;
}
-#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
-static int check_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_format *format)
+static inline int check_which(__u32 which)
{
- if (format->which != V4L2_SUBDEV_FORMAT_TRY &&
- format->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ if (which != V4L2_SUBDEV_FORMAT_TRY &&
+ which != V4L2_SUBDEV_FORMAT_ACTIVE)
return -EINVAL;
- if (format->pad >= sd->entity.num_pads)
+ return 0;
+}
+
+static inline int check_pad(struct v4l2_subdev *sd, __u32 pad)
+{
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ if (sd->entity.graph_obj.mdev) {
+ if (pad >= sd->entity.num_pads)
+ return -EINVAL;
+ return 0;
+ }
+#endif
+ /* allow pad 0 on subdevices not registered as media entities */
+ if (pad > 0)
+ return -EINVAL;
+ return 0;
+}
+
+static int check_cfg(__u32 which, struct v4l2_subdev_pad_config *cfg)
+{
+ if (which == V4L2_SUBDEV_FORMAT_TRY && !cfg)
return -EINVAL;
return 0;
}
-static int check_crop(struct v4l2_subdev *sd, struct v4l2_subdev_crop *crop)
+static inline int check_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
{
- if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
- crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ if (!format)
return -EINVAL;
- if (crop->pad >= sd->entity.num_pads)
+ return check_which(format->which) ? : check_pad(sd, format->pad) ? :
+ check_cfg(format->which, cfg);
+}
+
+static int call_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
+{
+ return check_format(sd, cfg, format) ? :
+ sd->ops->pad->get_fmt(sd, cfg, format);
+}
+
+static int call_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
+{
+ return check_format(sd, cfg, format) ? :
+ sd->ops->pad->set_fmt(sd, cfg, format);
+}
+
+static int call_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (!code)
return -EINVAL;
- return 0;
+ return check_which(code->which) ? : check_pad(sd, code->pad) ? :
+ check_cfg(code->which, cfg) ? :
+ sd->ops->pad->enum_mbus_code(sd, cfg, code);
}
-static int check_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_selection *sel)
+static int call_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
{
- if (sel->which != V4L2_SUBDEV_FORMAT_TRY &&
- sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ if (!fse)
return -EINVAL;
- if (sel->pad >= sd->entity.num_pads)
+ return check_which(fse->which) ? : check_pad(sd, fse->pad) ? :
+ check_cfg(fse->which, cfg) ? :
+ sd->ops->pad->enum_frame_size(sd, cfg, fse);
+}
+
+static inline int check_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ if (!fi)
return -EINVAL;
- return 0;
+ return check_pad(sd, fi->pad);
+}
+
+static int call_g_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ return check_frame_interval(sd, fi) ? :
+ sd->ops->video->g_frame_interval(sd, fi);
+}
+
+static int call_s_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ return check_frame_interval(sd, fi) ? :
+ sd->ops->video->s_frame_interval(sd, fi);
+}
+
+static int call_enum_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_interval_enum *fie)
+{
+ if (!fie)
+ return -EINVAL;
+
+ return check_which(fie->which) ? : check_pad(sd, fie->pad) ? :
+ check_cfg(fie->which, cfg) ? :
+ sd->ops->pad->enum_frame_interval(sd, cfg, fie);
+}
+
+static inline int check_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_selection *sel)
+{
+ if (!sel)
+ return -EINVAL;
+
+ return check_which(sel->which) ? : check_pad(sd, sel->pad) ? :
+ check_cfg(sel->which, cfg);
+}
+
+static int call_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_selection *sel)
+{
+ return check_selection(sd, cfg, sel) ? :
+ sd->ops->pad->get_selection(sd, cfg, sel);
+}
+
+static int call_set_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_selection *sel)
+{
+ return check_selection(sd, cfg, sel) ? :
+ sd->ops->pad->set_selection(sd, cfg, sel);
}
-static int check_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
+static inline int check_edid(struct v4l2_subdev *sd,
+ struct v4l2_subdev_edid *edid)
{
- if (edid->pad >= sd->entity.num_pads)
+ if (!edid)
return -EINVAL;
if (edid->blocks && edid->edid == NULL)
return -EINVAL;
- return 0;
+ return check_pad(sd, edid->pad);
+}
+
+static int call_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
+{
+ return check_edid(sd, edid) ? : sd->ops->pad->get_edid(sd, edid);
+}
+
+static int call_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
+{
+ return check_edid(sd, edid) ? : sd->ops->pad->set_edid(sd, edid);
+}
+
+static int call_dv_timings_cap(struct v4l2_subdev *sd,
+ struct v4l2_dv_timings_cap *cap)
+{
+ if (!cap)
+ return -EINVAL;
+
+ return check_pad(sd, cap->pad) ? :
+ sd->ops->pad->dv_timings_cap(sd, cap);
}
-#endif
+
+static int call_enum_dv_timings(struct v4l2_subdev *sd,
+ struct v4l2_enum_dv_timings *dvt)
+{
+ if (!dvt)
+ return -EINVAL;
+
+ return check_pad(sd, dvt->pad) ? :
+ sd->ops->pad->enum_dv_timings(sd, dvt);
+}
+
+static const struct v4l2_subdev_pad_ops v4l2_subdev_call_pad_wrappers = {
+ .get_fmt = call_get_fmt,
+ .set_fmt = call_set_fmt,
+ .enum_mbus_code = call_enum_mbus_code,
+ .enum_frame_size = call_enum_frame_size,
+ .enum_frame_interval = call_enum_frame_interval,
+ .get_selection = call_get_selection,
+ .set_selection = call_set_selection,
+ .get_edid = call_get_edid,
+ .set_edid = call_set_edid,
+ .dv_timings_cap = call_dv_timings_cap,
+ .enum_dv_timings = call_enum_dv_timings,
+};
+
+static const struct v4l2_subdev_video_ops v4l2_subdev_call_video_wrappers = {
+ .g_frame_interval = call_g_frame_interval,
+ .s_frame_interval = call_s_frame_interval,
+};
+
+const struct v4l2_subdev_ops v4l2_subdev_call_wrappers = {
+ .pad = &v4l2_subdev_call_pad_wrappers,
+ .video = &v4l2_subdev_call_video_wrappers,
+};
+EXPORT_SYMBOL(v4l2_subdev_call_wrappers);
static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
@@ -284,10 +445,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
case VIDIOC_SUBDEV_G_FMT: {
struct v4l2_subdev_format *format = arg;
- rval = check_format(sd, format);
- if (rval)
- return rval;
-
memset(format->reserved, 0, sizeof(format->reserved));
memset(format->format.reserved, 0, sizeof(format->format.reserved));
return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh->pad, format);
@@ -296,10 +453,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
case VIDIOC_SUBDEV_S_FMT: {
struct v4l2_subdev_format *format = arg;
- rval = check_format(sd, format);
- if (rval)
- return rval;
-
memset(format->reserved, 0, sizeof(format->reserved));
memset(format->format.reserved, 0, sizeof(format->format.reserved));
return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh->pad, format);
@@ -309,10 +462,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
struct v4l2_subdev_crop *crop = arg;
struct v4l2_subdev_selection sel;
- rval = check_crop(sd, crop);
- if (rval)
- return rval;
-
memset(crop->reserved, 0, sizeof(crop->reserved));
memset(&sel, 0, sizeof(sel));
sel.which = crop->which;
@@ -332,10 +481,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
struct v4l2_subdev_selection sel;
memset(crop->reserved, 0, sizeof(crop->reserved));
- rval = check_crop(sd, crop);
- if (rval)
- return rval;
-
memset(&sel, 0, sizeof(sel));
sel.which = crop->which;
sel.pad = crop->pad;
@@ -353,13 +498,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
case VIDIOC_SUBDEV_ENUM_MBUS_CODE: {
struct v4l2_subdev_mbus_code_enum *code = arg;
- if (code->which != V4L2_SUBDEV_FORMAT_TRY &&
- code->which != V4L2_SUBDEV_FORMAT_ACTIVE)
- return -EINVAL;
-
- if (code->pad >= sd->entity.num_pads)
- return -EINVAL;
-
memset(code->reserved, 0, sizeof(code->reserved));
return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh->pad,
code);
@@ -368,13 +506,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
case VIDIOC_SUBDEV_ENUM_FRAME_SIZE: {
struct v4l2_subdev_frame_size_enum *fse = arg;
- if (fse->which != V4L2_SUBDEV_FORMAT_TRY &&
- fse->which != V4L2_SUBDEV_FORMAT_ACTIVE)
- return -EINVAL;
-
- if (fse->pad >= sd->entity.num_pads)
- return -EINVAL;
-
memset(fse->reserved, 0, sizeof(fse->reserved));
return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh->pad,
fse);
@@ -383,9 +514,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
case VIDIOC_SUBDEV_G_FRAME_INTERVAL: {
struct v4l2_subdev_frame_interval *fi = arg;
- if (fi->pad >= sd->entity.num_pads)
- return -EINVAL;
-
memset(fi->reserved, 0, sizeof(fi->reserved));
return v4l2_subdev_call(sd, video, g_frame_interval, arg);
}
@@ -393,9 +521,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
case VIDIOC_SUBDEV_S_FRAME_INTERVAL: {
struct v4l2_subdev_frame_interval *fi = arg;
- if (fi->pad >= sd->entity.num_pads)
- return -EINVAL;
-
memset(fi->reserved, 0, sizeof(fi->reserved));
return v4l2_subdev_call(sd, video, s_frame_interval, arg);
}
@@ -403,13 +528,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: {
struct v4l2_subdev_frame_interval_enum *fie = arg;
- if (fie->which != V4L2_SUBDEV_FORMAT_TRY &&
- fie->which != V4L2_SUBDEV_FORMAT_ACTIVE)
- return -EINVAL;
-
- if (fie->pad >= sd->entity.num_pads)
- return -EINVAL;
-
memset(fie->reserved, 0, sizeof(fie->reserved));
return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh->pad,
fie);
@@ -418,10 +536,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
case VIDIOC_SUBDEV_G_SELECTION: {
struct v4l2_subdev_selection *sel = arg;
- rval = check_selection(sd, sel);
- if (rval)
- return rval;
-
memset(sel->reserved, 0, sizeof(sel->reserved));
return v4l2_subdev_call(
sd, pad, get_selection, subdev_fh->pad, sel);
@@ -430,10 +544,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
case VIDIOC_SUBDEV_S_SELECTION: {
struct v4l2_subdev_selection *sel = arg;
- rval = check_selection(sd, sel);
- if (rval)
- return rval;
-
memset(sel->reserved, 0, sizeof(sel->reserved));
return v4l2_subdev_call(
sd, pad, set_selection, subdev_fh->pad, sel);
@@ -442,38 +552,24 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
case VIDIOC_G_EDID: {
struct v4l2_subdev_edid *edid = arg;
- rval = check_edid(sd, edid);
- if (rval)
- return rval;
-
return v4l2_subdev_call(sd, pad, get_edid, edid);
}
case VIDIOC_S_EDID: {
struct v4l2_subdev_edid *edid = arg;
- rval = check_edid(sd, edid);
- if (rval)
- return rval;
-
return v4l2_subdev_call(sd, pad, set_edid, edid);
}
case VIDIOC_SUBDEV_DV_TIMINGS_CAP: {
struct v4l2_dv_timings_cap *cap = arg;
- if (cap->pad >= sd->entity.num_pads)
- return -EINVAL;
-
return v4l2_subdev_call(sd, pad, dv_timings_cap, cap);
}
case VIDIOC_SUBDEV_ENUM_DV_TIMINGS: {
struct v4l2_enum_dv_timings *dvt = arg;
- if (dvt->pad >= sd->entity.num_pads)
- return -EINVAL;
-
return v4l2_subdev_call(sd, pad, enum_dv_timings, dvt);
}
diff --git a/drivers/media/v4l2-core/videobuf-core.c b/drivers/media/v4l2-core/videobuf-core.c
index bf7dfb2a34af..7ef3e4d22bf6 100644
--- a/drivers/media/v4l2-core/videobuf-core.c
+++ b/drivers/media/v4l2-core/videobuf-core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* generic helper functions for handling video4linux capture buffers
*
@@ -7,10 +8,6 @@
* (c) 2001,02 Gerd Knorr <kraxel@bytesex.org>
* (c) 2006 Mauro Carvalho Chehab, <mchehab@kernel.org>
* (c) 2006 Ted Walther and John Sokol
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2
*/
#include <linux/init.h>
diff --git a/drivers/media/v4l2-core/videobuf-dma-contig.c b/drivers/media/v4l2-core/videobuf-dma-contig.c
index e1bf50df4c70..76b4ac7b1678 100644
--- a/drivers/media/v4l2-core/videobuf-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf-dma-contig.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* helper functions for physically contiguous capture buffers
*
@@ -8,10 +9,6 @@
*
* Based on videobuf-vmalloc.c,
* (c) 2007 Mauro Carvalho Chehab, <mchehab@kernel.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2
*/
#include <linux/init.h>
@@ -280,7 +277,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
struct videobuf_dma_contig_memory *mem;
struct videobuf_mapping *map;
int retval;
- unsigned long size;
dev_dbg(q->dev, "%s\n", __func__);
@@ -303,7 +299,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
goto error;
/* Try to remap memory */
- size = vma->vm_end - vma->vm_start;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
/* the "vm_pgoff" is just used in v4l2 to find the
@@ -314,7 +309,7 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
*/
vma->vm_pgoff = 0;
- retval = vm_iomap_memory(vma, mem->dma_handle, size);
+ retval = vm_iomap_memory(vma, mem->dma_handle, mem->size);
if (retval) {
dev_err(q->dev, "mmap: remap failed with error %d. ",
retval);
diff --git a/drivers/media/v4l2-core/videobuf-dma-sg.c b/drivers/media/v4l2-core/videobuf-dma-sg.c
index 870a2a526e0b..66a6c6c236a7 100644
--- a/drivers/media/v4l2-core/videobuf-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf-dma-sg.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* helper functions for SG DMA video4linux capture buffers
*
@@ -12,10 +13,6 @@
* (c) 2001,02 Gerd Knorr <kraxel@bytesex.org>
* (c) 2006 Mauro Carvalho Chehab, <mchehab@kernel.org>
* (c) 2006 Ted Walther and John Sokol
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2
*/
#include <linux/init.h>
diff --git a/drivers/media/v4l2-core/videobuf-vmalloc.c b/drivers/media/v4l2-core/videobuf-vmalloc.c
index cb50f1957828..f8bd5a369560 100644
--- a/drivers/media/v4l2-core/videobuf-vmalloc.c
+++ b/drivers/media/v4l2-core/videobuf-vmalloc.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* helper functions for vmalloc video4linux capture buffers
*
@@ -6,11 +7,7 @@
* into PAGE_SIZE chunks). They also assume the driver does not need
* to touch the video data.
*
- * (c) 2007 Mauro Carvalho Chehab, <mchehab@kernel.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2
+ * (c) 2007 Mauro Carvalho Chehab <mchehab@kernel.org>
*/
#include <linux/init.h>
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index 392ad4f5c570..dbdee02bb592 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -123,7 +123,7 @@ config FSL_IFC
config JZ4780_NEMC
bool "Ingenic JZ4780 SoC NEMC driver"
default y
- depends on MACH_JZ4780 || COMPILE_TEST
+ depends on MIPS || COMPILE_TEST
depends on HAS_IOMEM && OF
help
This driver is for the NAND/External Memory Controller (NEMC) in
diff --git a/drivers/memory/brcmstb_dpfe.c b/drivers/memory/brcmstb_dpfe.c
index 04599eccd604..3065a8bc8fd6 100644
--- a/drivers/memory/brcmstb_dpfe.c
+++ b/drivers/memory/brcmstb_dpfe.c
@@ -1,10 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* DDR PHY Front End (DPFE) driver for Broadcom set top box SoCs
*
* Copyright (c) 2017 Broadcom
- *
- * Released under the GPLv2 only.
- * SPDX-License-Identifier: GPL-2.0
*/
/*
diff --git a/drivers/memory/da8xx-ddrctl.c b/drivers/memory/da8xx-ddrctl.c
index 030afbe29d0c..e8f9b3f461f5 100644
--- a/drivers/memory/da8xx-ddrctl.c
+++ b/drivers/memory/da8xx-ddrctl.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TI da8xx DDR2/mDDR controller driver
*
@@ -5,10 +6,6 @@
*
* Author:
* Bartosz Golaszewski <bgolaszewski@baylibre.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c
index 2f214440008c..ee67a9a5d775 100644
--- a/drivers/memory/emif.c
+++ b/drivers/memory/emif.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* EMIF driver
*
@@ -5,10 +6,6 @@
*
* Aneesh V <aneesh@ti.com>
* Santosh Shilimkar <santosh.shilimkar@ti.com>
- *
- * 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.
*/
#include <linux/err.h>
#include <linux/kernel.h>
diff --git a/drivers/memory/emif.h b/drivers/memory/emif.h
index 6b71fadb3cfa..55aeb36a5bf2 100644
--- a/drivers/memory/emif.h
+++ b/drivers/memory/emif.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Defines for the EMIF driver
*
* Copyright (C) 2012 Texas Instruments, Inc.
*
* Benoit Cousson (b-cousson@ti.com)
- *
- * 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.
*/
#ifndef __EMIF_H
#define __EMIF_H
diff --git a/drivers/memory/jz4780-nemc.c b/drivers/memory/jz4780-nemc.c
index bcf06adefc96..b232ed279fc3 100644
--- a/drivers/memory/jz4780-nemc.c
+++ b/drivers/memory/jz4780-nemc.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* JZ4780 NAND/external memory controller (NEMC)
*
* Copyright (c) 2015 Imagination Technologies
* Author: Alex Smith <alex@alex-smith.me.uk>
- *
- * 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.
*/
#include <linux/clk.h>
@@ -44,9 +41,14 @@
#define NEMC_NFCSR_NFCEn(n) BIT((((n) - 1) << 1) + 1)
#define NEMC_NFCSR_TNFEn(n) BIT(16 + (n) - 1)
+struct jz_soc_info {
+ u8 tas_tah_cycles_max;
+};
+
struct jz4780_nemc {
spinlock_t lock;
struct device *dev;
+ const struct jz_soc_info *soc_info;
void __iomem *base;
struct clk *clk;
uint32_t clk_period;
@@ -59,7 +61,7 @@ struct jz4780_nemc {
*
* Return: The number of unique NEMC banks referred to by the specified NEMC
* child device. Unique here means that a device that references the same bank
- * multiple times in the its "reg" property will only count once.
+ * multiple times in its "reg" property will only count once.
*/
unsigned int jz4780_nemc_num_banks(struct device *dev)
{
@@ -161,7 +163,7 @@ static bool jz4780_nemc_configure_bank(struct jz4780_nemc *nemc,
* Conversion of tBP and tAW cycle counts to values supported by the
* hardware (round up to the next supported value).
*/
- static const uint32_t convert_tBP_tAW[] = {
+ static const u8 convert_tBP_tAW[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
/* 11 - 12 -> 12 cycles */
@@ -202,7 +204,7 @@ static bool jz4780_nemc_configure_bank(struct jz4780_nemc *nemc,
if (of_property_read_u32(node, "ingenic,nemc-tAS", &val) == 0) {
smcr &= ~NEMC_SMCR_TAS_MASK;
cycles = jz4780_nemc_ns_to_cycles(nemc, val);
- if (cycles > 15) {
+ if (cycles > nemc->soc_info->tas_tah_cycles_max) {
dev_err(nemc->dev, "tAS %u is too high (%u cycles)\n",
val, cycles);
return false;
@@ -214,7 +216,7 @@ static bool jz4780_nemc_configure_bank(struct jz4780_nemc *nemc,
if (of_property_read_u32(node, "ingenic,nemc-tAH", &val) == 0) {
smcr &= ~NEMC_SMCR_TAH_MASK;
cycles = jz4780_nemc_ns_to_cycles(nemc, val);
- if (cycles > 15) {
+ if (cycles > nemc->soc_info->tas_tah_cycles_max) {
dev_err(nemc->dev, "tAH %u is too high (%u cycles)\n",
val, cycles);
return false;
@@ -278,6 +280,10 @@ static int jz4780_nemc_probe(struct platform_device *pdev)
if (!nemc)
return -ENOMEM;
+ nemc->soc_info = device_get_match_data(dev);
+ if (!nemc->soc_info)
+ return -EINVAL;
+
spin_lock_init(&nemc->lock);
nemc->dev = dev;
@@ -370,8 +376,17 @@ static int jz4780_nemc_remove(struct platform_device *pdev)
return 0;
}
+static const struct jz_soc_info jz4740_soc_info = {
+ .tas_tah_cycles_max = 7,
+};
+
+static const struct jz_soc_info jz4780_soc_info = {
+ .tas_tah_cycles_max = 15,
+};
+
static const struct of_device_id jz4780_nemc_dt_match[] = {
- { .compatible = "ingenic,jz4780-nemc" },
+ { .compatible = "ingenic,jz4740-nemc", .data = &jz4740_soc_info, },
+ { .compatible = "ingenic,jz4780-nemc", .data = &jz4780_soc_info, },
{},
};
diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index f6297599433f..eff26c1b1394 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* GPMC support functions
*
@@ -7,10 +8,6 @@
*
* Copyright (C) 2009 Texas Instruments
* Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
- *
- * 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.
*/
#include <linux/irq.h>
#include <linux/kernel.h>
@@ -22,6 +19,7 @@
#include <linux/io.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/consumer.h> /* GPIO descriptor enum */
+#include <linux/gpio/machine.h>
#include <linux/interrupt.h>
#include <linux/irqdomain.h>
#include <linux/platform_device.h>
@@ -2172,7 +2170,8 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
waitpin_desc = gpiochip_request_own_desc(&gpmc->gpio_chip,
wait_pin, "WAITPIN",
- 0);
+ GPIO_ACTIVE_HIGH,
+ GPIOD_IN);
if (IS_ERR(waitpin_desc)) {
dev_err(&pdev->dev, "invalid wait-pin: %d\n", wait_pin);
ret = PTR_ERR(waitpin_desc);
diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c
index 163b6c69e651..3d8d322511c5 100644
--- a/drivers/memory/tegra/mc.c
+++ b/drivers/memory/tegra/mc.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/clk.h>
diff --git a/drivers/memory/tegra/mc.h b/drivers/memory/tegra/mc.h
index 392993955c93..f9353494b708 100644
--- a/drivers/memory/tegra/mc.h
+++ b/drivers/memory/tegra/mc.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#ifndef MEMORY_TEGRA_MC_H
diff --git a/drivers/memory/tegra/tegra114.c b/drivers/memory/tegra/tegra114.c
index 62305fafd641..ac8351b5beeb 100644
--- a/drivers/memory/tegra/tegra114.c
+++ b/drivers/memory/tegra/tegra114.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/of.h>
diff --git a/drivers/memory/tegra/tegra124.c b/drivers/memory/tegra/tegra124.c
index 8f8487bda642..41f08b2effd2 100644
--- a/drivers/memory/tegra/tegra124.c
+++ b/drivers/memory/tegra/tegra124.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/of.h>
diff --git a/drivers/memory/tegra/tegra186.c b/drivers/memory/tegra/tegra186.c
index ffda903c49bb..441213a35930 100644
--- a/drivers/memory/tegra/tegra186.c
+++ b/drivers/memory/tegra/tegra186.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/io.h>
diff --git a/drivers/memory/tegra/tegra20.c b/drivers/memory/tegra/tegra20.c
index 121237b16add..a8098bff91d9 100644
--- a/drivers/memory/tegra/tegra20.c
+++ b/drivers/memory/tegra/tegra20.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <dt-bindings/memory/tegra20-mc.h>
diff --git a/drivers/memory/tegra/tegra210.c b/drivers/memory/tegra/tegra210.c
index aa22cda637eb..b420268173fc 100644
--- a/drivers/memory/tegra/tegra210.c
+++ b/drivers/memory/tegra/tegra210.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2015 NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <dt-bindings/memory/tegra210-mc.h>
diff --git a/drivers/memory/tegra/tegra30.c b/drivers/memory/tegra/tegra30.c
index c9af0f682ead..14788fc2f9e8 100644
--- a/drivers/memory/tegra/tegra30.c
+++ b/drivers/memory/tegra/tegra30.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/of.h>
diff --git a/drivers/memory/ti-aemif.c b/drivers/memory/ti-aemif.c
index 475e5b3790ed..db526dbf71ee 100644
--- a/drivers/memory/ti-aemif.c
+++ b/drivers/memory/ti-aemif.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TI AEMIF driver
*
@@ -6,10 +7,6 @@
* Authors:
* Murali Karicheri <m-karicheri2@ti.com>
* Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c
index 1246d69ba187..693ee73eb291 100644
--- a/drivers/memstick/core/memstick.c
+++ b/drivers/memstick/core/memstick.c
@@ -1,15 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Sony MemoryStick support
*
* Copyright (C) 2007 Alex Dubov <oakad@yahoo.com>
*
- * 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.
- *
* Special thanks to Carlos Corbacho for providing various MemoryStick cards
* that made this driver possible.
- *
*/
#include <linux/memstick.h>
@@ -629,13 +625,18 @@ static int __init memstick_init(void)
return -ENOMEM;
rc = bus_register(&memstick_bus_type);
- if (!rc)
- rc = class_register(&memstick_host_class);
+ if (rc)
+ goto error_destroy_workqueue;
- if (!rc)
- return 0;
+ rc = class_register(&memstick_host_class);
+ if (rc)
+ goto error_bus_unregister;
+
+ return 0;
+error_bus_unregister:
bus_unregister(&memstick_bus_type);
+error_destroy_workqueue:
destroy_workqueue(workqueue);
return rc;
diff --git a/drivers/memstick/core/ms_block.c b/drivers/memstick/core/ms_block.c
index 82daccc9ea62..384927ebde74 100644
--- a/drivers/memstick/core/ms_block.c
+++ b/drivers/memstick/core/ms_block.c
@@ -1,15 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ms_block.c - Sony MemoryStick (legacy) storage support
* Copyright (C) 2013 Maxim Levitsky <maximlevitsky@gmail.com>
*
- * 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.
- *
* Minor portions of the driver were copied from mspro_block.c which is
* Copyright (C) 2007 Alex Dubov <oakad@yahoo.com>
- *
*/
#define DRIVER_NAME "ms_block"
#define pr_fmt(fmt) DRIVER_NAME ": " fmt
diff --git a/drivers/memstick/core/ms_block.h b/drivers/memstick/core/ms_block.h
index 9ba84e0ced63..122e1a8a8bd5 100644
--- a/drivers/memstick/core/ms_block.h
+++ b/drivers/memstick/core/ms_block.h
@@ -1,18 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* ms_block.h - Sony MemoryStick (legacy) storage support
* Copyright (C) 2013 Maxim Levitsky <maximlevitsky@gmail.com>
*
- * 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.
- *
* Minor portions of the driver are copied from mspro_block.c which is
* Copyright (C) 2007 Alex Dubov <oakad@yahoo.com>
*
* Also ms structures were copied from old broken driver by same author
* These probably come from MS spec
- *
*/
#ifndef MS_BLOCK_NEW_H
diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c
index 9545e87b6085..cd6b8d4f2335 100644
--- a/drivers/memstick/core/mspro_block.c
+++ b/drivers/memstick/core/mspro_block.c
@@ -1,15 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Sony MemoryStick Pro storage support
*
* Copyright (C) 2007 Alex Dubov <oakad@yahoo.com>
*
- * 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.
- *
* Special thanks to Carlos Corbacho for providing various MemoryStick cards
* that made this driver possible.
- *
*/
#include <linux/blk-mq.h>
diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c
index 5733e8fe1aef..32747425297d 100644
--- a/drivers/memstick/host/jmb38x_ms.c
+++ b/drivers/memstick/host/jmb38x_ms.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* jmb38x_ms.c - JMicron jmb38x MemoryStick card reader
*
* Copyright (C) 2008 Alex Dubov <oakad@yahoo.com>
- *
- * 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.
- *
*/
#include <linux/spinlock.h>
diff --git a/drivers/memstick/host/r592.c b/drivers/memstick/host/r592.c
index 627d6e62fe31..2932f421b3ea 100644
--- a/drivers/memstick/host/r592.c
+++ b/drivers/memstick/host/r592.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2010 - Maxim Levitsky
* driver for Ricoh memstick readers
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/memstick/host/r592.h b/drivers/memstick/host/r592.h
index c5726c1e8832..c161db70c8f5 100644
--- a/drivers/memstick/host/r592.h
+++ b/drivers/memstick/host/r592.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2010 - Maxim Levitsky
* driver for Ricoh memstick readers
- *
- * 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.
*/
#ifndef R592_H
diff --git a/drivers/memstick/host/rtsx_usb_ms.c b/drivers/memstick/host/rtsx_usb_ms.c
index 97308dc28ccf..102dbb8080da 100644
--- a/drivers/memstick/host/rtsx_usb_ms.c
+++ b/drivers/memstick/host/rtsx_usb_ms.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* Realtek USB Memstick Card Interface driver
*
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
* Author:
* Roger Tseng <rogerable@realtek.com>
*/
diff --git a/drivers/memstick/host/tifm_ms.c b/drivers/memstick/host/tifm_ms.c
index 6b13ac56eb27..5b966b54d6e9 100644
--- a/drivers/memstick/host/tifm_ms.c
+++ b/drivers/memstick/host/tifm_ms.c
@@ -1,15 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TI FlashMedia driver
*
* Copyright (C) 2007 Alex Dubov <oakad@yahoo.com>
*
- * 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.
- *
* Special thanks to Carlos Corbacho for providing various MemoryStick cards
* that made this driver possible.
- *
*/
#include <linux/tifm.h>
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index d8882b0a1338..c2dd322691d1 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -6001,13 +6001,12 @@ mpt_findImVolumes(MPT_ADAPTER *ioc)
if (mpt_config(ioc, &cfg) != 0)
goto out;
- mem = kmalloc(iocpage2sz, GFP_KERNEL);
+ mem = kmemdup(pIoc2, iocpage2sz, GFP_KERNEL);
if (!mem) {
rc = -ENOMEM;
goto out;
}
- memcpy(mem, (u8 *)pIoc2, iocpage2sz);
ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
mpt_read_ioc_pg_3(ioc);
diff --git a/drivers/mfd/88pm80x.c b/drivers/mfd/88pm80x.c
index 3f24ecbe2576..be036e7e787b 100644
--- a/drivers/mfd/88pm80x.c
+++ b/drivers/mfd/88pm80x.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* I2C driver for Marvell 88PM80x
*
@@ -5,10 +6,6 @@
* Haojian Zhuang <haojian.zhuang@marvell.com>
* Joseph(Yossi) Hanin <yhanin@marvell.com>
* Qiao Zhou <zhouqiao@marvell.com>
- *
- * 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.
*/
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c
index 227b99018657..9e0bd135730f 100644
--- a/drivers/mfd/88pm860x-core.c
+++ b/drivers/mfd/88pm860x-core.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Base driver for Marvell 88PM8607
*
* Copyright (C) 2009 Marvell International Ltd.
*
* Author: Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c
index 7b9052ea7413..a000aed35755 100644
--- a/drivers/mfd/88pm860x-i2c.c
+++ b/drivers/mfd/88pm860x-i2c.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* I2C driver for Marvell 88PM860x
*
* Copyright (C) 2009 Marvell International Ltd.
*
* Author: Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- * 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.
*/
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index a17d275bf1d4..f129f9678940 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -261,6 +261,13 @@ config MFD_MADERA_SPI
Support for the Cirrus Logic Madera platform audio SoC
core functionality controlled via SPI.
+config MFD_CS47L15
+ bool "Cirrus Logic CS47L15"
+ select PINCTRL_CS47L15
+ depends on MFD_MADERA
+ help
+ Support for Cirrus Logic CS47L15 Smart Codec
+
config MFD_CS47L35
bool "Cirrus Logic CS47L35"
select PINCTRL_CS47L35
@@ -282,6 +289,13 @@ config MFD_CS47L90
help
Support for Cirrus Logic CS47L90 and CS47L91 Smart Codecs
+config MFD_CS47L92
+ bool "Cirrus Logic CS47L92/93"
+ select PINCTRL_CS47L92
+ depends on MFD_MADERA
+ help
+ Support for Cirrus Logic CS42L92, CS47L92 and CS47L93 Smart Codecs
+
config MFD_ASIC3
bool "Compaq ASIC3"
depends on GPIOLIB && ARM
@@ -1031,14 +1045,14 @@ config MFD_RC5T583
different functionality of the device.
config MFD_RK808
- tristate "Rockchip RK805/RK808/RK818 Power Management Chip"
+ tristate "Rockchip RK805/RK808/RK809/RK817/RK818 Power Management Chip"
depends on I2C && OF
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
help
- If you say yes here you get support for the RK805, RK808 and RK818
- Power Management chips.
+ If you say yes here you get support for the RK805, RK808, RK809,
+ RK817 and RK818 Power Management chips.
This driver provides common support for accessing the device
through I2C interface. The device supports multiple sub-devices
including interrupts, RTC, LDO & DCDC regulators, and onkey.
@@ -1336,9 +1350,8 @@ config MFD_TI_LMU
select REGMAP_I2C
help
Say yes here to enable support for TI LMU chips.
-
- TI LMU MFD supports LM3532, LM3631, LM3632, LM3633, LM3695 and LM3697.
- It consists of backlight, LED and regulator driver.
+ TI LMU MFD supports LM3532, LM3631, LM3632, LM3633, LM3695 and
+ LM36274. It consists of backlight, LED and regulator driver.
It provides consistent device controls for lighting functions.
config MFD_OMAP_USB_HOST
@@ -1891,6 +1904,23 @@ config MFD_ROHM_BD718XX
NXP i.MX8. It contains 8 BUCK outputs and 7 LDOs, voltage monitoring
and emergency shut down as well as 32,768KHz clock output.
+config MFD_ROHM_BD70528
+ tristate "ROHM BD70528 Power Management IC"
+ depends on I2C=y
+ depends on OF
+ select REGMAP_I2C
+ select REGMAP_IRQ
+ select MFD_CORE
+ help
+ Select this option to get support for the ROHM BD70528 Power
+ Management IC. BD71837 is general purpose single-chip power
+ management IC for battery-powered portable devices. It contains
+ 3 ultra-low current consumption buck converters, 3 LDOs and 2 LED
+ drivers. Also included are 4 GPIOs, a real-time clock (RTC), a 32kHz
+ crystal oscillator, high-accuracy VREF for use with an external ADC,
+ 10 bits SAR ADC for battery temperature monitor and 1S battery
+ charger.
+
config MFD_STM32_LPTIMER
tristate "Support for STM32 Low-Power Timer"
depends on (ARCH_STM32 && OF) || COMPILE_TEST
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 52b1a90ff515..f026ada68f6a 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -75,6 +75,9 @@ obj-$(CONFIG_MFD_WM8994) += wm8994.o
obj-$(CONFIG_MFD_WM97xx) += wm97xx-core.o
madera-objs := madera-core.o
+ifeq ($(CONFIG_MFD_CS47L15),y)
+madera-objs += cs47l15-tables.o
+endif
ifeq ($(CONFIG_MFD_CS47L35),y)
madera-objs += cs47l35-tables.o
endif
@@ -84,6 +87,9 @@ endif
ifeq ($(CONFIG_MFD_CS47L90),y)
madera-objs += cs47l90-tables.o
endif
+ifeq ($(CONFIG_MFD_CS47L92),y)
+madera-objs += cs47l92-tables.o
+endif
obj-$(CONFIG_MFD_MADERA) += madera.o
obj-$(CONFIG_MFD_MADERA_I2C) += madera-i2c.o
obj-$(CONFIG_MFD_MADERA_SPI) += madera-spi.o
@@ -247,5 +253,7 @@ obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o
obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o
obj-$(CONFIG_MFD_SC27XX_PMIC) += sprd-sc27xx-spi.o
obj-$(CONFIG_RAVE_SP_CORE) += rave-sp.o
+obj-$(CONFIG_MFD_ROHM_BD70528) += rohm-bd70528.o
obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o
obj-$(CONFIG_MFD_STMFX) += stmfx.o
+
diff --git a/drivers/mfd/ac100.c b/drivers/mfd/ac100.c
index 9bc69cd7807d..6d49d7fb5f14 100644
--- a/drivers/mfd/ac100.c
+++ b/drivers/mfd/ac100.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* MFD core driver for X-Powers' AC100 Audio Codec IC
*
@@ -12,10 +13,6 @@
* Copyright (2016) Chen-Yu Tsai
*
* Author: Chen-Yu Tsai <wens@csie.org>
- *
- * 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.
*/
#include <linux/interrupt.h>
diff --git a/drivers/mfd/altera-sysmgr.c b/drivers/mfd/altera-sysmgr.c
index 8976f82785bb..2ee14d8a6d31 100644
--- a/drivers/mfd/altera-sysmgr.c
+++ b/drivers/mfd/altera-sysmgr.c
@@ -92,9 +92,9 @@ static struct regmap_config altr_sysmgr_regmap_cfg = {
* Matching function used by driver_find_device().
* Return: True if match is found, otherwise false.
*/
-static int sysmgr_match_phandle(struct device *dev, void *data)
+static int sysmgr_match_phandle(struct device *dev, const void *data)
{
- return dev->of_node == (struct device_node *)data;
+ return dev->of_node == (const struct device_node *)data;
}
/**
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c
index 27b61639cdc7..4a31907a4525 100644
--- a/drivers/mfd/arizona-core.c
+++ b/drivers/mfd/arizona-core.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Arizona core driver
*
* Copyright 2012 Wolfson Microelectronics plc
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
- *
- * 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.
*/
#include <linux/clk.h>
@@ -996,7 +993,7 @@ int arizona_dev_init(struct arizona *arizona)
unsigned int reg, val;
int (*apply_patch)(struct arizona *) = NULL;
const struct mfd_cell *subdevs = NULL;
- int n_subdevs, ret, i;
+ int n_subdevs = 0, ret, i;
dev_set_drvdata(arizona->dev, arizona);
mutex_init(&arizona->clk_lock);
diff --git a/drivers/mfd/arizona-i2c.c b/drivers/mfd/arizona-i2c.c
index 5fe12961cfe5..4b58e3ad6eb6 100644
--- a/drivers/mfd/arizona-i2c.c
+++ b/drivers/mfd/arizona-i2c.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Arizona-i2c.c -- Arizona I2C bus interface
*
* Copyright 2012 Wolfson Microelectronics plc
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
- *
- * 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.
*/
#include <linux/err.h>
diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c
index a307832d7e45..077d9ab112b7 100644
--- a/drivers/mfd/arizona-irq.c
+++ b/drivers/mfd/arizona-irq.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Arizona interrupt support
*
* Copyright 2012 Wolfson Microelectronics plc
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/mfd/arizona-spi.c b/drivers/mfd/arizona-spi.c
index 5c1ccdeb9b70..2633e147b76c 100644
--- a/drivers/mfd/arizona-spi.c
+++ b/drivers/mfd/arizona-spi.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* arizona-spi.c -- Arizona SPI bus interface
*
* Copyright 2012 Wolfson Microelectronics plc
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
- *
- * 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.
*/
#include <linux/err.h>
diff --git a/drivers/mfd/arizona.h b/drivers/mfd/arizona.h
index a0bddc5bd043..995efc6d7f32 100644
--- a/drivers/mfd/arizona.h
+++ b/drivers/mfd/arizona.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* wm5102.h -- WM5102 MFD internals
*
* Copyright 2012 Wolfson Microelectronics plc
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
- *
- * 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.
*/
#ifndef _WM5102_H
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index 1531302a50ec..83b18c998d6f 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -1,19 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* driver/mfd/asic3.c
*
* Compaq ASIC3 support.
*
- * 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.
- *
* Copyright 2001 Compaq Computer Corporation.
* Copyright 2004-2005 Phil Blundell
* Copyright 2007-2008 OpenedHand Ltd.
*
* Authors: Phil Blundell <pb@handhelds.org>,
* Samuel Ortiz <sameo@openedhand.com>
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/mfd/atmel-flexcom.c b/drivers/mfd/atmel-flexcom.c
index f684a93a3340..d2f5c073fdf3 100644
--- a/drivers/mfd/atmel-flexcom.c
+++ b/drivers/mfd/atmel-flexcom.c
@@ -1,21 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for Atmel Flexcom
*
* Copyright (C) 2015 Atmel Corporation
*
* Author: Cyrille Pitchen <cyrille.pitchen@atmel.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
diff --git a/drivers/mfd/atmel-hlcdc.c b/drivers/mfd/atmel-hlcdc.c
index 35a9e16f9902..64013c57a920 100644
--- a/drivers/mfd/atmel-hlcdc.c
+++ b/drivers/mfd/atmel-hlcdc.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 Free Electrons
* Copyright (C) 2014 Atmel
*
* Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/clk.h>
diff --git a/drivers/mfd/atmel-smc.c b/drivers/mfd/atmel-smc.c
index 0adbd2e796fe..1fa2ec950e7d 100644
--- a/drivers/mfd/atmel-smc.c
+++ b/drivers/mfd/atmel-smc.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Atmel SMC (Static Memory Controller) helper functions.
*
@@ -5,10 +6,6 @@
* Copyright (C) 2017 Free Electrons
*
* Author: Boris Brezillon <boris.brezillon@free-electrons.com>
- *
- * 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.
*/
#include <linux/mfd/syscon/atmel-smc.h>
diff --git a/drivers/mfd/axp20x-i2c.c b/drivers/mfd/axp20x-i2c.c
index c2e8a0dee7f8..14f9df74f855 100644
--- a/drivers/mfd/axp20x-i2c.c
+++ b/drivers/mfd/axp20x-i2c.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* I2C driver for the X-Powers' Power Management ICs
*
@@ -10,10 +11,6 @@
* Copyright (C) 2014 Carlo Caione
*
* Author: Carlo Caione <carlo@caione.org>
- *
- * 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.
*/
#include <linux/acpi.h>
diff --git a/drivers/mfd/axp20x-rsb.c b/drivers/mfd/axp20x-rsb.c
index 7ddbd9e8dd03..4cdc79f5cc48 100644
--- a/drivers/mfd/axp20x-rsb.c
+++ b/drivers/mfd/axp20x-rsb.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* RSB driver for the X-Powers' Power Management ICs
*
@@ -10,10 +11,6 @@
* Copyright (C) 2015 Chen-Yu Tsai
*
* Author: Chen-Yu Tsai <wens@csie.org>
- *
- * 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.
*/
#include <linux/acpi.h>
diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
index 2215660dfa05..a4aaadaa0cb0 100644
--- a/drivers/mfd/axp20x.c
+++ b/drivers/mfd/axp20x.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* MFD core driver for the X-Powers' Power Management ICs
*
@@ -10,10 +11,6 @@
* Copyright (C) 2014 Carlo Caione
*
* Author: Carlo Caione <carlo@caione.org>
- *
- * 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.
*/
#include <linux/acpi.h>
diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c
index 5d5c41ac3845..2a9ac5213893 100644
--- a/drivers/mfd/cros_ec.c
+++ b/drivers/mfd/cros_ec.c
@@ -102,12 +102,16 @@ static int cros_ec_sleep_event(struct cros_ec_device *ec_dev, u8 sleep_event)
/* For now, report failure to transition to S0ix with a warning. */
if (ret >= 0 && ec_dev->host_sleep_v1 &&
- (sleep_event == HOST_SLEEP_EVENT_S0IX_RESUME))
+ (sleep_event == HOST_SLEEP_EVENT_S0IX_RESUME)) {
+ ec_dev->last_resume_result =
+ buf.u.resp1.resume_response.sleep_transitions;
+
WARN_ONCE(buf.u.resp1.resume_response.sleep_transitions &
EC_HOST_RESUME_SLEEP_TIMEOUT,
"EC detected sleep transition timeout. Total slp_s0 transitions: %d",
buf.u.resp1.resume_response.sleep_transitions &
EC_HOST_RESUME_SLEEP_TRANSITIONS_MASK);
+ }
return ret;
}
diff --git a/drivers/mfd/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c
index a5391f96eafd..41dccced5026 100644
--- a/drivers/mfd/cros_ec_dev.c
+++ b/drivers/mfd/cros_ec_dev.c
@@ -285,13 +285,15 @@ static void cros_ec_sensors_register(struct cros_ec_dev *ec)
resp = (struct ec_response_motion_sense *)msg->data;
sensor_num = resp->dump.sensor_count;
- /* Allocate 1 extra sensors in FIFO are needed */
- sensor_cells = kcalloc(sensor_num + 1, sizeof(struct mfd_cell),
+ /*
+ * Allocate 2 extra sensors if lid angle sensor and/or FIFO are needed.
+ */
+ sensor_cells = kcalloc(sensor_num + 2, sizeof(struct mfd_cell),
GFP_KERNEL);
if (sensor_cells == NULL)
goto error;
- sensor_platforms = kcalloc(sensor_num + 1,
+ sensor_platforms = kcalloc(sensor_num,
sizeof(struct cros_ec_sensor_platform),
GFP_KERNEL);
if (sensor_platforms == NULL)
@@ -351,6 +353,11 @@ static void cros_ec_sensors_register(struct cros_ec_dev *ec)
sensor_cells[id].name = "cros-ec-ring";
id++;
}
+ if (cros_ec_check_features(ec,
+ EC_FEATURE_REFINED_TABLET_MODE_HYSTERESIS)) {
+ sensor_cells[id].name = "cros-ec-lid-angle";
+ id++;
+ }
ret = mfd_add_devices(ec->dev, 0, sensor_cells, id,
NULL, 0, NULL);
@@ -364,6 +371,72 @@ error:
kfree(msg);
}
+static struct cros_ec_sensor_platform sensor_platforms[] = {
+ { .sensor_num = 0 },
+ { .sensor_num = 1 }
+};
+
+static const struct mfd_cell cros_ec_accel_legacy_cells[] = {
+ {
+ .name = "cros-ec-accel-legacy",
+ .platform_data = &sensor_platforms[0],
+ .pdata_size = sizeof(struct cros_ec_sensor_platform),
+ },
+ {
+ .name = "cros-ec-accel-legacy",
+ .platform_data = &sensor_platforms[1],
+ .pdata_size = sizeof(struct cros_ec_sensor_platform),
+ }
+};
+
+static void cros_ec_accel_legacy_register(struct cros_ec_dev *ec)
+{
+ struct cros_ec_device *ec_dev = ec->ec_dev;
+ u8 status;
+ int ret;
+
+ /*
+ * ECs that need legacy support are the main EC, directly connected to
+ * the AP.
+ */
+ if (ec->cmd_offset != 0)
+ return;
+
+ /*
+ * Check if EC supports direct memory reads and if EC has
+ * accelerometers.
+ */
+ if (ec_dev->cmd_readmem) {
+ ret = ec_dev->cmd_readmem(ec_dev, EC_MEMMAP_ACC_STATUS, 1,
+ &status);
+ if (ret < 0) {
+ dev_warn(ec->dev, "EC direct read error.\n");
+ return;
+ }
+
+ /* Check if EC has accelerometers. */
+ if (!(status & EC_MEMMAP_ACC_STATUS_PRESENCE_BIT)) {
+ dev_info(ec->dev, "EC does not have accelerometers.\n");
+ return;
+ }
+ }
+
+ /*
+ * The device may still support accelerometers:
+ * it would be an older ARM based device that do not suppor the
+ * EC_CMD_GET_FEATURES command.
+ *
+ * Register 2 accelerometers, we will fail in the IIO driver if there
+ * are no sensors.
+ */
+ ret = mfd_add_devices(ec->dev, PLATFORM_DEVID_AUTO,
+ cros_ec_accel_legacy_cells,
+ ARRAY_SIZE(cros_ec_accel_legacy_cells),
+ NULL, 0, NULL);
+ if (ret)
+ dev_err(ec_dev->dev, "failed to add EC sensors\n");
+}
+
static const struct mfd_cell cros_ec_cec_cells[] = {
{ .name = "cros-ec-cec" }
};
@@ -440,6 +513,16 @@ static int ec_device_probe(struct platform_device *pdev)
ec_platform->ec_name = CROS_EC_DEV_TP_NAME;
}
+ /* Check whether this is actually a SCP rather than an EC. */
+ if (cros_ec_check_features(ec, EC_FEATURE_SCP)) {
+ dev_info(dev, "CrOS SCP MCU detected.\n");
+ /*
+ * Help userspace differentiating ECs from SCP,
+ * regardless of the probing order.
+ */
+ ec_platform->ec_name = CROS_EC_DEV_SCP_NAME;
+ }
+
/*
* Add the class device
* Link to the character device for creating the /dev entry
@@ -459,6 +542,9 @@ static int ec_device_probe(struct platform_device *pdev)
/* check whether this EC is a sensor hub. */
if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE))
cros_ec_sensors_register(ec);
+ else
+ /* Workaroud for older EC firmware */
+ cros_ec_accel_legacy_register(ec);
/* Check whether this EC instance has CEC host command support */
if (cros_ec_check_features(ec, EC_FEATURE_CEC)) {
diff --git a/drivers/mfd/cs47l15-tables.c b/drivers/mfd/cs47l15-tables.c
new file mode 100644
index 000000000000..f81b45336690
--- /dev/null
+++ b/drivers/mfd/cs47l15-tables.c
@@ -0,0 +1,1299 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Regmap tables for CS47L15 codec
+ *
+ * Copyright (C) 2016-2019 Cirrus Logic, Inc. and
+ * Cirrus Logic International Semiconductor Ltd.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include <linux/mfd/madera/core.h>
+#include <linux/mfd/madera/registers.h>
+
+#include "madera.h"
+
+static const struct reg_sequence cs47l15_reva_16_patch[] = {
+ { 0x8C, 0x5555 },
+ { 0x8C, 0xAAAA },
+ { 0x314, 0x0080 },
+ { 0x4A8, 0x6023 },
+ { 0x4A9, 0x6023 },
+ { 0x4D4, 0x0008 },
+ { 0x4CF, 0x0F00 },
+ { 0x4D7, 0x1B2B },
+ { 0x8C, 0xCCCC },
+ { 0x8C, 0x3333 },
+};
+
+int cs47l15_patch(struct madera *madera)
+{
+ int ret;
+
+ ret = regmap_register_patch(madera->regmap,
+ cs47l15_reva_16_patch,
+ ARRAY_SIZE(cs47l15_reva_16_patch));
+ if (ret < 0) {
+ dev_err(madera->dev,
+ "Error in applying 16-bit patch: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cs47l15_patch);
+
+static const struct reg_default cs47l15_reg_default[] = {
+ { 0x00000020, 0x0000 }, /* R32 (0x20) - Tone Generator 1 */
+ { 0x00000021, 0x1000 }, /* R33 (0x21) - Tone Generator 2 */
+ { 0x00000022, 0x0000 }, /* R34 (0x22) - Tone Generator 3 */
+ { 0x00000023, 0x1000 }, /* R35 (0x23) - Tone Generator 4 */
+ { 0x00000024, 0x0000 }, /* R36 (0x24) - Tone Generator 5 */
+ { 0x00000030, 0x0000 }, /* R48 (0x30) - PWM Drive 1 */
+ { 0x00000031, 0x0100 }, /* R49 (0x31) - PWM Drive 2 */
+ { 0x00000032, 0x0100 }, /* R50 (0x32) - PWM Drive 3 */
+ { 0x00000061, 0x01ff }, /* R97 (0x61) - Sample Rate Sequence Select 1 */
+ { 0x00000062, 0x01ff }, /* R98 (0x62) - Sample Rate Sequence Select 2 */
+ { 0x00000063, 0x01ff }, /* R99 (0x63) - Sample Rate Sequence Select 3 */
+ { 0x00000064, 0x01ff }, /* R100 (0x64) - Sample Rate Sequence Select 4 */
+ { 0x00000066, 0x01ff }, /* R102 (0x66) - Always On Triggers Sequence Select 1 */
+ { 0x00000067, 0x01ff }, /* R103 (0x67) - Always On Triggers Sequence Select 2 */
+ { 0x00000090, 0x0000 }, /* R144 (0x90) - Haptics Control 1 */
+ { 0x00000091, 0x7fff }, /* R145 (0x91) - Haptics Control 2 */
+ { 0x00000092, 0x0000 }, /* R146 (0x92) - Haptics Phase 1 Intensity */
+ { 0x00000093, 0x0000 }, /* R147 (0x93) - Haptics Phase 1 Duration */
+ { 0x00000094, 0x0000 }, /* R148 (0x94) - Haptics Phase 2 Intensity */
+ { 0x00000095, 0x0000 }, /* R149 (0x95) - Haptics Phase 2 Duration */
+ { 0x00000096, 0x0000 }, /* R150 (0x96) - Haptics Phase 3 Intensity */
+ { 0x00000097, 0x0000 }, /* R151 (0x97) - Haptics Phase 3 Duration */
+ { 0x000000a0, 0x0000 }, /* R160 (0xA0) - Comfort Noise Generator */
+ { 0x00000100, 0x0002 }, /* R256 (0x100) - Clock 32K 1 */
+ { 0x00000101, 0x0404 }, /* R257 (0x101) - System Clock 1 */
+ { 0x00000102, 0x0011 }, /* R258 (0x102) - Sample Rate 1 */
+ { 0x00000103, 0x0011 }, /* R259 (0x103) - Sample Rate 2 */
+ { 0x00000104, 0x0011 }, /* R260 (0x104) - Sample Rate 3 */
+ { 0x00000120, 0x0304 }, /* R288 (0x120) - DSP Clock 1 */
+ { 0x00000122, 0x0000 }, /* R290 (0x122) - DSP Clock 2 */
+ { 0x00000149, 0x0000 }, /* R329 (0x149) - Output System Clock */
+ { 0x00000152, 0x0000 }, /* R338 (0x152) - Rate Estimator 1 */
+ { 0x00000153, 0x0000 }, /* R339 (0x153) - Rate Estimator 2 */
+ { 0x00000154, 0x0000 }, /* R340 (0x154) - Rate Estimator 3 */
+ { 0x00000155, 0x0000 }, /* R341 (0x155) - Rate Estimator 4 */
+ { 0x00000156, 0x0000 }, /* R342 (0x156) - Rate Estimator 5 */
+ { 0x00000171, 0x0002 }, /* R369 (0x171) - FLL1 Control 1 */
+ { 0x00000172, 0x0008 }, /* R370 (0x172) - FLL1 Control 2 */
+ { 0x00000173, 0x0018 }, /* R371 (0x173) - FLL1 Control 3 */
+ { 0x00000174, 0x007d }, /* R372 (0x174) - FLL1 Control 4 */
+ { 0x00000175, 0x0000 }, /* R373 (0x175) - FLL1 Control 5 */
+ { 0x00000176, 0x0000 }, /* R374 (0x176) - FLL1 Control 6 */
+ { 0x00000179, 0x0000 }, /* R377 (0x179) - FLL1 Control 7 */
+ { 0x0000017a, 0x2906 }, /* R378 (0x17A) - FLL1 EFS 2 */
+ { 0x00000181, 0x0000 }, /* R385 (0x181) - FLL1 Synchroniser 1 */
+ { 0x00000182, 0x0000 }, /* R386 (0x182) - FLL1 Synchroniser 2 */
+ { 0x00000183, 0x0000 }, /* R387 (0x183) - FLL1 Synchroniser 3 */
+ { 0x00000184, 0x0000 }, /* R388 (0x184) - FLL1 Synchroniser 4 */
+ { 0x00000185, 0x0000 }, /* R389 (0x185) - FLL1 Synchroniser 5 */
+ { 0x00000186, 0x0000 }, /* R390 (0x186) - FLL1 Synchroniser 6 */
+ { 0x00000187, 0x0001 }, /* R391 (0x187) - FLL1 Synchroniser 7 */
+ { 0x00000189, 0x0000 }, /* R393 (0x189) - FLL1 Spread Spectrum */
+ { 0x0000018a, 0x0004 }, /* R394 (0x18A) - FLL1 GPIO Clock */
+ { 0x000001d1, 0x0004 }, /* R465 (0x1D1) - FLL AO Control 1 */
+ { 0x000001d2, 0x0004 }, /* R466 (0x1D2) - FLL AO Control 2 */
+ { 0x000001d3, 0x0000 }, /* R467 (0x1D3) - FLL AO Control 3 */
+ { 0x000001d4, 0x0000 }, /* R468 (0x1D4) - FLL AO Control 4 */
+ { 0x000001d5, 0x0001 }, /* R469 (0x1D5) - FLL AO Control 5 */
+ { 0x000001d6, 0x8004 }, /* R470 (0x1D6) - FLL AO Control 6 */
+ { 0x000001d8, 0x0000 }, /* R472 (0x1D8) - FLL AO Control 7 */
+ { 0x000001da, 0x0077 }, /* R474 (0x1DA) - FLL AO Control 8 */
+ { 0x000001db, 0x0000 }, /* R475 (0x1DB) - FLL AO Control 9 */
+ { 0x000001dc, 0x06da }, /* R476 (0x1DC) - FLL AO Control 10 */
+ { 0x000001dd, 0x0011 }, /* R477 (0x1DD) - FLL AO Control 11 */
+ { 0x00000218, 0x00e6 }, /* R536 (0x218) - Mic Bias Ctrl 1 */
+ { 0x0000021c, 0x0222 }, /* R540 (0x21C) - Mic Bias Ctrl 5 */
+ { 0x00000299, 0x0000 }, /* R665 (0x299) - Headphone Detect 0 */
+ { 0x0000029b, 0x0000 }, /* R667 (0x29B) - Headphone Detect 1 */
+ { 0x000002a2, 0x0010 }, /* R674 (0x2A2) - Mic Detect 1 Control 0 */
+ { 0x000002a3, 0x1102 }, /* R675 (0x2A3) - Mic Detect 1 Control 1 */
+ { 0x000002a4, 0x009f }, /* R676 (0x2A4) - Mic Detect 1 Control 2 */
+ { 0x000002a6, 0x3d3d }, /* R678 (0x2A6) - Mic Detect 1 Level 1 */
+ { 0x000002a7, 0x3d3d }, /* R679 (0x2A7) - Mic Detect 1 Level 2 */
+ { 0x000002a8, 0x333d }, /* R680 (0x2A8) - Mic Detect 1 Level 3 */
+ { 0x000002a9, 0x202d }, /* R681 (0x2A9) - Mic Detect 1 Level 4 */
+ { 0x000002c6, 0x0010 }, /* R710 (0x2C6) - Micd Clamp Control */
+ { 0x000002c8, 0x0000 }, /* R712 (0x2C8) - GP Switch 1 */
+ { 0x000002d3, 0x0000 }, /* R723 (0x2D3) - Jack Detect Analogue */
+ { 0x00000300, 0x0000 }, /* R768 (0x300) - Input Enables */
+ { 0x00000308, 0x0000 }, /* R776 (0x308) - Input Rate */
+ { 0x00000309, 0x0022 }, /* R777 (0x309) - Input Volume Ramp */
+ { 0x0000030c, 0x0002 }, /* R780 (0x30C) - HPF Control */
+ { 0x00000310, 0x0080 }, /* R784 (0x310) - IN1L Control */
+ { 0x00000311, 0x0180 }, /* R785 (0x311) - ADC Digital Volume 1L */
+ { 0x00000312, 0x0500 }, /* R786 (0x312) - DMIC1L Control */
+ { 0x00000313, 0x0000 }, /* R787 (0x313) - IN1L Rate Control */
+ { 0x00000314, 0x0080 }, /* R788 (0x314) - IN1R Control */
+ { 0x00000315, 0x0180 }, /* R789 (0x315) - ADC Digital Volume 1R */
+ { 0x00000316, 0x0000 }, /* R790 (0x316) - DMIC1R Control */
+ { 0x00000317, 0x0000 }, /* R791 (0x317) - IN1R Rate Control */
+ { 0x00000318, 0x0000 }, /* R792 (0x318) - IN2L Control */
+ { 0x00000319, 0x0180 }, /* R793 (0x319) - ADC Digital Volume 2L */
+ { 0x0000031a, 0x0500 }, /* R794 (0x31A) - DMIC2L Control */
+ { 0x0000031b, 0x0000 }, /* R795 (0x31B) - IN2L Rate Control */
+ { 0x0000031c, 0x0800 }, /* R796 (0x31C) - IN2R Control */
+ { 0x0000031d, 0x0180 }, /* R797 (0x31D) - ADC Digital Volume 2R */
+ { 0x0000031e, 0x0000 }, /* R798 (0x31E) - DMIC2R Control */
+ { 0x0000031f, 0x0000 }, /* R799 (0x31F) - IN2R Rate Control */
+ { 0x000003a8, 0x2000 }, /* R936 (0x3A8) - CS47L15 ADC Int Bias */
+ { 0x000003c4, 0x0000 }, /* R964 (0x3C4) - CS47L15 PGA Bias Sel */
+ { 0x00000400, 0x0000 }, /* R1024 (0x400) - Output Enables 1 */
+ { 0x00000408, 0x0000 }, /* R1032 (0x408) - Output Rate 1 */
+ { 0x00000409, 0x0022 }, /* R1033 (0x409) - Output Volume Ramp */
+ { 0x00000410, 0x0080 }, /* R1040 (0x410) - Output Path Config 1L */
+ { 0x00000411, 0x0180 }, /* R1041 (0x411) - DAC Digital Volume 1L */
+ { 0x00000412, 0x0000 }, /* R1042 (0x412) - Output Path Config 1 */
+ { 0x00000413, 0x0001 }, /* R1043 (0x413) - Noise Gate Select 1L */
+ { 0x00000414, 0x0080 }, /* R1044 (0x414) - Output Path Config 1R */
+ { 0x00000415, 0x0180 }, /* R1045 (0x415) - DAC Digital Volume 1R */
+ { 0x00000417, 0x0002 }, /* R1047 (0x417) - Noise Gate Select 1R */
+ { 0x0000041a, 0x0600 }, /* R1050 (0x41A) - Output Path Config 2 */
+ { 0x00000428, 0x0000 }, /* R1064 (0x428) - Output Path Config 4L */
+ { 0x00000429, 0x0180 }, /* R1065 (0x429) - DAC Digital Volume 4L */
+ { 0x0000042b, 0x0040 }, /* R1067 (0x42B) - Noise Gate Select 4L */
+ { 0x00000430, 0x0000 }, /* R1072 (0x430) - Output Path Config 5L */
+ { 0x00000431, 0x0180 }, /* R1073 (0x431) - DAC Digital Volume 5L */
+ { 0x00000433, 0x0100 }, /* R1075 (0x433) - Noise Gate Select 5L */
+ { 0x00000434, 0x0000 }, /* R1076 (0x434) - Output Path Config 5R */
+ { 0x00000435, 0x0180 }, /* R1077 (0x435) - DAC Digital Volume 5R */
+ { 0x00000437, 0x0200 }, /* R1079 (0x437) - Noise Gate Select 5R */
+ { 0x00000450, 0x0000 }, /* R1104 (0x450) - DAC AEC Control 1 */
+ { 0x00000451, 0x0000 }, /* R1105 (0x451) - DAC AEC Control 2 */
+ { 0x00000458, 0x0000 }, /* R1112 (0x458) - Noise Gate Control */
+ { 0x00000490, 0x0069 }, /* R1168 (0x490) - PDM SPK1 Ctrl 1 */
+ { 0x00000491, 0x0000 }, /* R1169 (0x491) - PDM SPK1 Ctrl 2 */
+ { 0x000004a0, 0x3080 }, /* R1184 (0x4A0) - HP1 Short Circuit Ctrl */
+ { 0x000004a8, 0x6023 }, /* R1192 (0x4A8) - HP Test Ctrl 5 */
+ { 0x000004a9, 0x6023 }, /* R1193 (0x4A9) - HP Test Ctrl 6 */
+ { 0x00000500, 0x000c }, /* R1280 (0x500) - AIF1 BCLK Ctrl */
+ { 0x00000501, 0x0000 }, /* R1281 (0x501) - AIF1 Tx Pin Ctrl */
+ { 0x00000502, 0x0000 }, /* R1282 (0x502) - AIF1 Rx Pin Ctrl */
+ { 0x00000503, 0x0000 }, /* R1283 (0x503) - AIF1 Rate Ctrl */
+ { 0x00000504, 0x0000 }, /* R1284 (0x504) - AIF1 Format */
+ { 0x00000506, 0x0040 }, /* R1286 (0x506) - AIF1 Rx BCLK Rate */
+ { 0x00000507, 0x1818 }, /* R1287 (0x507) - AIF1 Frame Ctrl 1 */
+ { 0x00000508, 0x1818 }, /* R1288 (0x508) - AIF1 Frame Ctrl 2 */
+ { 0x00000509, 0x0000 }, /* R1289 (0x509) - AIF1 Frame Ctrl 3 */
+ { 0x0000050a, 0x0001 }, /* R1290 (0x50A) - AIF1 Frame Ctrl 4 */
+ { 0x0000050b, 0x0002 }, /* R1291 (0x50B) - AIF1 Frame Ctrl 5 */
+ { 0x0000050c, 0x0003 }, /* R1292 (0x50C) - AIF1 Frame Ctrl 6 */
+ { 0x0000050d, 0x0004 }, /* R1293 (0x50D) - AIF1 Frame Ctrl 7 */
+ { 0x0000050e, 0x0005 }, /* R1294 (0x50E) - AIF1 Frame Ctrl 8 */
+ { 0x00000511, 0x0000 }, /* R1297 (0x511) - AIF1 Frame Ctrl 11 */
+ { 0x00000512, 0x0001 }, /* R1298 (0x512) - AIF1 Frame Ctrl 12 */
+ { 0x00000513, 0x0002 }, /* R1299 (0x513) - AIF1 Frame Ctrl 13 */
+ { 0x00000514, 0x0003 }, /* R1300 (0x514) - AIF1 Frame Ctrl 14 */
+ { 0x00000515, 0x0004 }, /* R1301 (0x515) - AIF1 Frame Ctrl 15 */
+ { 0x00000516, 0x0005 }, /* R1302 (0x516) - AIF1 Frame Ctrl 16 */
+ { 0x00000519, 0x0000 }, /* R1305 (0x519) - AIF1 Tx Enables */
+ { 0x0000051a, 0x0000 }, /* R1306 (0x51A) - AIF1 Rx Enables */
+ { 0x00000540, 0x000c }, /* R1344 (0x540) - AIF2 BCLK Ctrl */
+ { 0x00000541, 0x0000 }, /* R1345 (0x541) - AIF2 Tx Pin Ctrl */
+ { 0x00000542, 0x0000 }, /* R1346 (0x542) - AIF2 Rx Pin Ctrl */
+ { 0x00000543, 0x0000 }, /* R1347 (0x543) - AIF2 Rate Ctrl */
+ { 0x00000544, 0x0000 }, /* R1348 (0x544) - AIF2 Format */
+ { 0x00000546, 0x0040 }, /* R1350 (0x546) - AIF2 Rx BCLK Rate */
+ { 0x00000547, 0x1818 }, /* R1351 (0x547) - AIF2 Frame Ctrl 1 */
+ { 0x00000548, 0x1818 }, /* R1352 (0x548) - AIF2 Frame Ctrl 2 */
+ { 0x00000549, 0x0000 }, /* R1353 (0x549) - AIF2 Frame Ctrl 3 */
+ { 0x0000054a, 0x0001 }, /* R1354 (0x54A) - AIF2 Frame Ctrl 4 */
+ { 0x0000054b, 0x0002 }, /* R1355 (0x54B) - AIF2 Frame Ctrl 5 */
+ { 0x0000054c, 0x0003 }, /* R1356 (0x54C) - AIF2 Frame Ctrl 6 */
+ { 0x00000551, 0x0000 }, /* R1361 (0x551) - AIF2 Frame Ctrl 11 */
+ { 0x00000552, 0x0001 }, /* R1362 (0x552) - AIF2 Frame Ctrl 12 */
+ { 0x00000553, 0x0002 }, /* R1363 (0x553) - AIF2 Frame Ctrl 13 */
+ { 0x00000554, 0x0003 }, /* R1364 (0x554) - AIF2 Frame Ctrl 14 */
+ { 0x00000559, 0x0000 }, /* R1369 (0x559) - AIF2 Tx Enables */
+ { 0x0000055a, 0x0000 }, /* R1370 (0x55A) - AIF2 Rx Enables */
+ { 0x00000580, 0x000c }, /* R1408 (0x580) - AIF3 BCLK Ctrl */
+ { 0x00000581, 0x0000 }, /* R1409 (0x581) - AIF3 Tx Pin Ctrl */
+ { 0x00000582, 0x0000 }, /* R1410 (0x582) - AIF3 Rx Pin Ctrl */
+ { 0x00000583, 0x0000 }, /* R1411 (0x583) - AIF3 Rate Ctrl */
+ { 0x00000584, 0x0000 }, /* R1412 (0x584) - AIF3 Format */
+ { 0x00000586, 0x0040 }, /* R1414 (0x586) - AIF3 Rx BCLK Rate */
+ { 0x00000587, 0x1818 }, /* R1415 (0x587) - AIF3 Frame Ctrl 1 */
+ { 0x00000588, 0x1818 }, /* R1416 (0x588) - AIF3 Frame Ctrl 2 */
+ { 0x00000589, 0x0000 }, /* R1417 (0x589) - AIF3 Frame Ctrl 3 */
+ { 0x0000058a, 0x0001 }, /* R1418 (0x58A) - AIF3 Frame Ctrl 4 */
+ { 0x00000591, 0x0000 }, /* R1425 (0x591) - AIF3 Frame Ctrl 11 */
+ { 0x00000592, 0x0001 }, /* R1426 (0x592) - AIF3 Frame Ctrl 12 */
+ { 0x00000599, 0x0000 }, /* R1433 (0x599) - AIF3 Tx Enables */
+ { 0x0000059a, 0x0000 }, /* R1434 (0x59A) - AIF3 Rx Enables */
+ { 0x000005c2, 0x0000 }, /* R1474 (0x5C2) - SPD1 Tx Control */
+ { 0x00000640, 0x0000 }, /* R1600 (0x640) - PWM1MIX Input 1 Source */
+ { 0x00000641, 0x0080 }, /* R1601 (0x641) - PWM1MIX Input 1 Volume */
+ { 0x00000642, 0x0000 }, /* R1602 (0x642) - PWM1MIX Input 2 Source */
+ { 0x00000643, 0x0080 }, /* R1603 (0x643) - PWM1MIX Input 2 Volume */
+ { 0x00000644, 0x0000 }, /* R1604 (0x644) - PWM1MIX Input 3 Source */
+ { 0x00000645, 0x0080 }, /* R1605 (0x645) - PWM1MIX Input 3 Volume */
+ { 0x00000646, 0x0000 }, /* R1606 (0x646) - PWM1MIX Input 4 Source */
+ { 0x00000647, 0x0080 }, /* R1607 (0x647) - PWM1MIX Input 4 Volume */
+ { 0x00000648, 0x0000 }, /* R1608 (0x648) - PWM2MIX Input 1 Source */
+ { 0x00000649, 0x0080 }, /* R1609 (0x649) - PWM2MIX Input 1 Volume */
+ { 0x0000064a, 0x0000 }, /* R1610 (0x64A) - PWM2MIX Input 2 Source */
+ { 0x0000064b, 0x0080 }, /* R1611 (0x64B) - PWM2MIX Input 2 Volume */
+ { 0x0000064c, 0x0000 }, /* R1612 (0x64C) - PWM2MIX Input 3 Source */
+ { 0x0000064d, 0x0080 }, /* R1613 (0x64D) - PWM2MIX Input 3 Volume */
+ { 0x0000064e, 0x0000 }, /* R1614 (0x64E) - PWM2MIX Input 4 Source */
+ { 0x0000064f, 0x0080 }, /* R1615 (0x64F) - PWM2MIX Input 4 Volume */
+ { 0x00000680, 0x0000 }, /* R1664 (0x680) - OUT1LMIX Input 1 Source */
+ { 0x00000681, 0x0080 }, /* R1665 (0x681) - OUT1LMIX Input 1 Volume */
+ { 0x00000682, 0x0000 }, /* R1666 (0x682) - OUT1LMIX Input 2 Source */
+ { 0x00000683, 0x0080 }, /* R1667 (0x683) - OUT1LMIX Input 2 Volume */
+ { 0x00000684, 0x0000 }, /* R1668 (0x684) - OUT1LMIX Input 3 Source */
+ { 0x00000685, 0x0080 }, /* R1669 (0x685) - OUT1LMIX Input 3 Volume */
+ { 0x00000686, 0x0000 }, /* R1670 (0x686) - OUT1LMIX Input 4 Source */
+ { 0x00000687, 0x0080 }, /* R1671 (0x687) - OUT1LMIX Input 4 Volume */
+ { 0x00000688, 0x0000 }, /* R1672 (0x688) - OUT1RMIX Input 1 Source */
+ { 0x00000689, 0x0080 }, /* R1673 (0x689) - OUT1RMIX Input 1 Volume */
+ { 0x0000068a, 0x0000 }, /* R1674 (0x68A) - OUT1RMIX Input 2 Source */
+ { 0x0000068b, 0x0080 }, /* R1675 (0x68B) - OUT1RMIX Input 2 Volume */
+ { 0x0000068c, 0x0000 }, /* R1676 (0x68C) - OUT1RMIX Input 3 Source */
+ { 0x0000068d, 0x0080 }, /* R1677 (0x68D) - OUT1RMIX Input 3 Volume */
+ { 0x0000068e, 0x0000 }, /* R1678 (0x68E) - OUT1RMIX Input 4 Source */
+ { 0x0000068f, 0x0080 }, /* R1679 (0x68F) - OUT1RMIX Input 4 Volume */
+ { 0x000006b0, 0x0000 }, /* R1712 (0x6B0) - OUT4LMIX Input 1 Source */
+ { 0x000006b1, 0x0080 }, /* R1713 (0x6B1) - OUT4LMIX Input 1 Volume */
+ { 0x000006b2, 0x0000 }, /* R1714 (0x6B2) - OUT4LMIX Input 2 Source */
+ { 0x000006b3, 0x0080 }, /* R1715 (0x6B3) - OUT4LMIX Input 2 Volume */
+ { 0x000006b4, 0x0000 }, /* R1716 (0x6B4) - OUT4LMIX Input 3 Source */
+ { 0x000006b5, 0x0080 }, /* R1717 (0x6B5) - OUT4LMIX Input 3 Volume */
+ { 0x000006b6, 0x0000 }, /* R1718 (0x6B6) - OUT4LMIX Input 4 Source */
+ { 0x000006b7, 0x0080 }, /* R1719 (0x6B7) - OUT4LMIX Input 4 Volume */
+ { 0x000006c0, 0x0000 }, /* R1728 (0x6C0) - OUT5LMIX Input 1 Source */
+ { 0x000006c1, 0x0080 }, /* R1729 (0x6C1) - OUT5LMIX Input 1 Volume */
+ { 0x000006c2, 0x0000 }, /* R1730 (0x6C2) - OUT5LMIX Input 2 Source */
+ { 0x000006c3, 0x0080 }, /* R1731 (0x6C3) - OUT5LMIX Input 2 Volume */
+ { 0x000006c4, 0x0000 }, /* R1732 (0x6C4) - OUT5LMIX Input 3 Source */
+ { 0x000006c5, 0x0080 }, /* R1733 (0x6C5) - OUT5LMIX Input 3 Volume */
+ { 0x000006c6, 0x0000 }, /* R1734 (0x6C6) - OUT5LMIX Input 4 Source */
+ { 0x000006c7, 0x0080 }, /* R1735 (0x6C7) - OUT5LMIX Input 4 Volume */
+ { 0x000006c8, 0x0000 }, /* R1736 (0x6C8) - OUT5RMIX Input 1 Source */
+ { 0x000006c9, 0x0080 }, /* R1737 (0x6C9) - OUT5RMIX Input 1 Volume */
+ { 0x000006ca, 0x0000 }, /* R1738 (0x6CA) - OUT5RMIX Input 2 Source */
+ { 0x000006cb, 0x0080 }, /* R1739 (0x6CB) - OUT5RMIX Input 2 Volume */
+ { 0x000006cc, 0x0000 }, /* R1740 (0x6CC) - OUT5RMIX Input 3 Source */
+ { 0x000006cd, 0x0080 }, /* R1741 (0x6CD) - OUT5RMIX Input 3 Volume */
+ { 0x000006ce, 0x0000 }, /* R1742 (0x6CE) - OUT5RMIX Input 4 Source */
+ { 0x000006cf, 0x0080 }, /* R1743 (0x6CF) - OUT5RMIX Input 4 Volume */
+ { 0x00000700, 0x0000 }, /* R1792 (0x700) - AIF1TX1MIX Input 1 Source */
+ { 0x00000701, 0x0080 }, /* R1793 (0x701) - AIF1TX1MIX Input 1 Volume */
+ { 0x00000702, 0x0000 }, /* R1794 (0x702) - AIF1TX1MIX Input 2 Source */
+ { 0x00000703, 0x0080 }, /* R1795 (0x703) - AIF1TX1MIX Input 2 Volume */
+ { 0x00000704, 0x0000 }, /* R1796 (0x704) - AIF1TX1MIX Input 3 Source */
+ { 0x00000705, 0x0080 }, /* R1797 (0x705) - AIF1TX1MIX Input 3 Volume */
+ { 0x00000706, 0x0000 }, /* R1798 (0x706) - AIF1TX1MIX Input 4 Source */
+ { 0x00000707, 0x0080 }, /* R1799 (0x707) - AIF1TX1MIX Input 4 Volume */
+ { 0x00000708, 0x0000 }, /* R1800 (0x708) - AIF1TX2MIX Input 1 Source */
+ { 0x00000709, 0x0080 }, /* R1801 (0x709) - AIF1TX2MIX Input 1 Volume */
+ { 0x0000070a, 0x0000 }, /* R1802 (0x70A) - AIF1TX2MIX Input 2 Source */
+ { 0x0000070b, 0x0080 }, /* R1803 (0x70B) - AIF1TX2MIX Input 2 Volume */
+ { 0x0000070c, 0x0000 }, /* R1804 (0x70C) - AIF1TX2MIX Input 3 Source */
+ { 0x0000070d, 0x0080 }, /* R1805 (0x70D) - AIF1TX2MIX Input 3 Volume */
+ { 0x0000070e, 0x0000 }, /* R1806 (0x70E) - AIF1TX2MIX Input 4 Source */
+ { 0x0000070f, 0x0080 }, /* R1807 (0x70F) - AIF1TX2MIX Input 4 Volume */
+ { 0x00000710, 0x0000 }, /* R1808 (0x710) - AIF1TX3MIX Input 1 Source */
+ { 0x00000711, 0x0080 }, /* R1809 (0x711) - AIF1TX3MIX Input 1 Volume */
+ { 0x00000712, 0x0000 }, /* R1810 (0x712) - AIF1TX3MIX Input 2 Source */
+ { 0x00000713, 0x0080 }, /* R1811 (0x713) - AIF1TX3MIX Input 2 Volume */
+ { 0x00000714, 0x0000 }, /* R1812 (0x714) - AIF1TX3MIX Input 3 Source */
+ { 0x00000715, 0x0080 }, /* R1813 (0x715) - AIF1TX3MIX Input 3 Volume */
+ { 0x00000716, 0x0000 }, /* R1814 (0x716) - AIF1TX3MIX Input 4 Source */
+ { 0x00000717, 0x0080 }, /* R1815 (0x717) - AIF1TX3MIX Input 4 Volume */
+ { 0x00000718, 0x0000 }, /* R1816 (0x718) - AIF1TX4MIX Input 1 Source */
+ { 0x00000719, 0x0080 }, /* R1817 (0x719) - AIF1TX4MIX Input 1 Volume */
+ { 0x0000071a, 0x0000 }, /* R1818 (0x71A) - AIF1TX4MIX Input 2 Source */
+ { 0x0000071b, 0x0080 }, /* R1819 (0x71B) - AIF1TX4MIX Input 2 Volume */
+ { 0x0000071c, 0x0000 }, /* R1820 (0x71C) - AIF1TX4MIX Input 3 Source */
+ { 0x0000071d, 0x0080 }, /* R1821 (0x71D) - AIF1TX4MIX Input 3 Volume */
+ { 0x0000071e, 0x0000 }, /* R1822 (0x71E) - AIF1TX4MIX Input 4 Source */
+ { 0x0000071f, 0x0080 }, /* R1823 (0x71F) - AIF1TX4MIX Input 4 Volume */
+ { 0x00000720, 0x0000 }, /* R1824 (0x720) - AIF1TX5MIX Input 1 Source */
+ { 0x00000721, 0x0080 }, /* R1825 (0x721) - AIF1TX5MIX Input 1 Volume */
+ { 0x00000722, 0x0000 }, /* R1826 (0x722) - AIF1TX5MIX Input 2 Source */
+ { 0x00000723, 0x0080 }, /* R1827 (0x723) - AIF1TX5MIX Input 2 Volume */
+ { 0x00000724, 0x0000 }, /* R1828 (0x724) - AIF1TX5MIX Input 3 Source */
+ { 0x00000725, 0x0080 }, /* R1829 (0x725) - AIF1TX5MIX Input 3 Volume */
+ { 0x00000726, 0x0000 }, /* R1830 (0x726) - AIF1TX5MIX Input 4 Source */
+ { 0x00000727, 0x0080 }, /* R1831 (0x727) - AIF1TX5MIX Input 4 Volume */
+ { 0x00000728, 0x0000 }, /* R1832 (0x728) - AIF1TX6MIX Input 1 Source */
+ { 0x00000729, 0x0080 }, /* R1833 (0x729) - AIF1TX6MIX Input 1 Volume */
+ { 0x0000072a, 0x0000 }, /* R1834 (0x72A) - AIF1TX6MIX Input 2 Source */
+ { 0x0000072b, 0x0080 }, /* R1835 (0x72B) - AIF1TX6MIX Input 2 Volume */
+ { 0x0000072c, 0x0000 }, /* R1836 (0x72C) - AIF1TX6MIX Input 3 Source */
+ { 0x0000072d, 0x0080 }, /* R1837 (0x72D) - AIF1TX6MIX Input 3 Volume */
+ { 0x0000072e, 0x0000 }, /* R1838 (0x72E) - AIF1TX6MIX Input 4 Source */
+ { 0x0000072f, 0x0080 }, /* R1839 (0x72F) - AIF1TX6MIX Input 4 Volume */
+ { 0x00000740, 0x0000 }, /* R1856 (0x740) - AIF2TX1MIX Input 1 Source */
+ { 0x00000741, 0x0080 }, /* R1857 (0x741) - AIF2TX1MIX Input 1 Volume */
+ { 0x00000742, 0x0000 }, /* R1858 (0x742) - AIF2TX1MIX Input 2 Source */
+ { 0x00000743, 0x0080 }, /* R1859 (0x743) - AIF2TX1MIX Input 2 Volume */
+ { 0x00000744, 0x0000 }, /* R1860 (0x744) - AIF2TX1MIX Input 3 Source */
+ { 0x00000745, 0x0080 }, /* R1861 (0x745) - AIF2TX1MIX Input 3 Volume */
+ { 0x00000746, 0x0000 }, /* R1862 (0x746) - AIF2TX1MIX Input 4 Source */
+ { 0x00000747, 0x0080 }, /* R1863 (0x747) - AIF2TX1MIX Input 4 Volume */
+ { 0x00000748, 0x0000 }, /* R1864 (0x748) - AIF2TX2MIX Input 1 Source */
+ { 0x00000749, 0x0080 }, /* R1865 (0x749) - AIF2TX2MIX Input 1 Volume */
+ { 0x0000074a, 0x0000 }, /* R1866 (0x74A) - AIF2TX2MIX Input 2 Source */
+ { 0x0000074b, 0x0080 }, /* R1867 (0x74B) - AIF2TX2MIX Input 2 Volume */
+ { 0x0000074c, 0x0000 }, /* R1868 (0x74C) - AIF2TX2MIX Input 3 Source */
+ { 0x0000074d, 0x0080 }, /* R1869 (0x74D) - AIF2TX2MIX Input 3 Volume */
+ { 0x0000074e, 0x0000 }, /* R1870 (0x74E) - AIF2TX2MIX Input 4 Source */
+ { 0x0000074f, 0x0080 }, /* R1871 (0x74F) - AIF2TX2MIX Input 4 Volume */
+ { 0x00000750, 0x0000 }, /* R1872 (0x750) - AIF2TX3MIX Input 1 Source */
+ { 0x00000751, 0x0080 }, /* R1873 (0x751) - AIF2TX3MIX Input 1 Volume */
+ { 0x00000752, 0x0000 }, /* R1874 (0x752) - AIF2TX3MIX Input 2 Source */
+ { 0x00000753, 0x0080 }, /* R1875 (0x753) - AIF2TX3MIX Input 2 Volume */
+ { 0x00000754, 0x0000 }, /* R1876 (0x754) - AIF2TX3MIX Input 3 Source */
+ { 0x00000755, 0x0080 }, /* R1877 (0x755) - AIF2TX3MIX Input 3 Volume */
+ { 0x00000756, 0x0000 }, /* R1878 (0x756) - AIF2TX3MIX Input 4 Source */
+ { 0x00000757, 0x0080 }, /* R1879 (0x757) - AIF2TX3MIX Input 4 Volume */
+ { 0x00000758, 0x0000 }, /* R1880 (0x758) - AIF2TX4MIX Input 1 Source */
+ { 0x00000759, 0x0080 }, /* R1881 (0x759) - AIF2TX4MIX Input 1 Volume */
+ { 0x0000075a, 0x0000 }, /* R1882 (0x75A) - AIF2TX4MIX Input 2 Source */
+ { 0x0000075b, 0x0080 }, /* R1883 (0x75B) - AIF2TX4MIX Input 2 Volume */
+ { 0x0000075c, 0x0000 }, /* R1884 (0x75C) - AIF2TX4MIX Input 3 Source */
+ { 0x0000075d, 0x0080 }, /* R1885 (0x75D) - AIF2TX4MIX Input 3 Volume */
+ { 0x0000075e, 0x0000 }, /* R1886 (0x75E) - AIF2TX4MIX Input 4 Source */
+ { 0x0000075f, 0x0080 }, /* R1887 (0x75F) - AIF2TX4MIX Input 4 Volume */
+ { 0x00000780, 0x0000 }, /* R1920 (0x780) - AIF3TX1MIX Input 1 Source */
+ { 0x00000781, 0x0080 }, /* R1921 (0x781) - AIF3TX1MIX Input 1 Volume */
+ { 0x00000782, 0x0000 }, /* R1922 (0x782) - AIF3TX1MIX Input 2 Source */
+ { 0x00000783, 0x0080 }, /* R1923 (0x783) - AIF3TX1MIX Input 2 Volume */
+ { 0x00000784, 0x0000 }, /* R1924 (0x784) - AIF3TX1MIX Input 3 Source */
+ { 0x00000785, 0x0080 }, /* R1925 (0x785) - AIF3TX1MIX Input 3 Volume */
+ { 0x00000786, 0x0000 }, /* R1926 (0x786) - AIF3TX1MIX Input 4 Source */
+ { 0x00000787, 0x0080 }, /* R1927 (0x787) - AIF3TX1MIX Input 4 Volume */
+ { 0x00000788, 0x0000 }, /* R1928 (0x788) - AIF3TX2MIX Input 1 Source */
+ { 0x00000789, 0x0080 }, /* R1929 (0x789) - AIF3TX2MIX Input 1 Volume */
+ { 0x0000078a, 0x0000 }, /* R1930 (0x78A) - AIF3TX2MIX Input 2 Source */
+ { 0x0000078b, 0x0080 }, /* R1931 (0x78B) - AIF3TX2MIX Input 2 Volume */
+ { 0x0000078c, 0x0000 }, /* R1932 (0x78C) - AIF3TX2MIX Input 3 Source */
+ { 0x0000078d, 0x0080 }, /* R1933 (0x78D) - AIF3TX2MIX Input 3 Volume */
+ { 0x0000078e, 0x0000 }, /* R1934 (0x78E) - AIF3TX2MIX Input 4 Source */
+ { 0x0000078f, 0x0080 }, /* R1935 (0x78F) - AIF3TX2MIX Input 4 Volume */
+ { 0x00000800, 0x0000 }, /* R2048 (0x800) - SPDIF1TX1MIX Input 1 Source */
+ { 0x00000801, 0x0080 }, /* R2049 (0x801) - SPDIF1TX1MIX Input 1 Volume */
+ { 0x00000808, 0x0000 }, /* R2056 (0x808) - SPDIF1TX2MIX Input 1 Source */
+ { 0x00000809, 0x0080 }, /* R2057 (0x809) - SPDIF1TX2MIX Input 1 Volume */
+ { 0x00000880, 0x0000 }, /* R2176 (0x880) - EQ1MIX Input 1 Source */
+ { 0x00000881, 0x0080 }, /* R2177 (0x881) - EQ1MIX Input 1 Volume */
+ { 0x00000882, 0x0000 }, /* R2178 (0x882) - EQ1MIX Input 2 Source */
+ { 0x00000883, 0x0080 }, /* R2179 (0x883) - EQ1MIX Input 2 Volume */
+ { 0x00000884, 0x0000 }, /* R2180 (0x884) - EQ1MIX Input 3 Source */
+ { 0x00000885, 0x0080 }, /* R2181 (0x885) - EQ1MIX Input 3 Volume */
+ { 0x00000886, 0x0000 }, /* R2182 (0x886) - EQ1MIX Input 4 Source */
+ { 0x00000887, 0x0080 }, /* R2183 (0x887) - EQ1MIX Input 4 Volume */
+ { 0x00000888, 0x0000 }, /* R2184 (0x888) - EQ2MIX Input 1 Source */
+ { 0x00000889, 0x0080 }, /* R2185 (0x889) - EQ2MIX Input 1 Volume */
+ { 0x0000088a, 0x0000 }, /* R2186 (0x88A) - EQ2MIX Input 2 Source */
+ { 0x0000088b, 0x0080 }, /* R2187 (0x88B) - EQ2MIX Input 2 Volume */
+ { 0x0000088c, 0x0000 }, /* R2188 (0x88C) - EQ2MIX Input 3 Source */
+ { 0x0000088d, 0x0080 }, /* R2189 (0x88D) - EQ2MIX Input 3 Volume */
+ { 0x0000088e, 0x0000 }, /* R2190 (0x88E) - EQ2MIX Input 4 Source */
+ { 0x0000088f, 0x0080 }, /* R2191 (0x88F) - EQ2MIX Input 4 Volume */
+ { 0x00000890, 0x0000 }, /* R2192 (0x890) - EQ3MIX Input 1 Source */
+ { 0x00000891, 0x0080 }, /* R2193 (0x891) - EQ3MIX Input 1 Volume */
+ { 0x00000892, 0x0000 }, /* R2194 (0x892) - EQ3MIX Input 2 Source */
+ { 0x00000893, 0x0080 }, /* R2195 (0x893) - EQ3MIX Input 2 Volume */
+ { 0x00000894, 0x0000 }, /* R2196 (0x894) - EQ3MIX Input 3 Source */
+ { 0x00000895, 0x0080 }, /* R2197 (0x895) - EQ3MIX Input 3 Volume */
+ { 0x00000896, 0x0000 }, /* R2198 (0x896) - EQ3MIX Input 4 Source */
+ { 0x00000897, 0x0080 }, /* R2199 (0x897) - EQ3MIX Input 4 Volume */
+ { 0x00000898, 0x0000 }, /* R2200 (0x898) - EQ4MIX Input 1 Source */
+ { 0x00000899, 0x0080 }, /* R2201 (0x899) - EQ4MIX Input 1 Volume */
+ { 0x0000089a, 0x0000 }, /* R2202 (0x89A) - EQ4MIX Input 2 Source */
+ { 0x0000089b, 0x0080 }, /* R2203 (0x89B) - EQ4MIX Input 2 Volume */
+ { 0x0000089c, 0x0000 }, /* R2204 (0x89C) - EQ4MIX Input 3 Source */
+ { 0x0000089d, 0x0080 }, /* R2205 (0x89D) - EQ4MIX Input 3 Volume */
+ { 0x0000089e, 0x0000 }, /* R2206 (0x89E) - EQ4MIX Input 4 Source */
+ { 0x0000089f, 0x0080 }, /* R2207 (0x89F) - EQ4MIX Input 4 Volume */
+ { 0x000008c0, 0x0000 }, /* R2240 (0x8C0) - DRC1LMIX Input 1 Source */
+ { 0x000008c1, 0x0080 }, /* R2241 (0x8C1) - DRC1LMIX Input 1 Volume */
+ { 0x000008c2, 0x0000 }, /* R2242 (0x8C2) - DRC1LMIX Input 2 Source */
+ { 0x000008c3, 0x0080 }, /* R2243 (0x8C3) - DRC1LMIX Input 2 Volume */
+ { 0x000008c4, 0x0000 }, /* R2244 (0x8C4) - DRC1LMIX Input 3 Source */
+ { 0x000008c5, 0x0080 }, /* R2245 (0x8C5) - DRC1LMIX Input 3 Volume */
+ { 0x000008c6, 0x0000 }, /* R2246 (0x8C6) - DRC1LMIX Input 4 Source */
+ { 0x000008c7, 0x0080 }, /* R2247 (0x8C7) - DRC1LMIX Input 4 Volume */
+ { 0x000008c8, 0x0000 }, /* R2248 (0x8C8) - DRC1RMIX Input 1 Source */
+ { 0x000008c9, 0x0080 }, /* R2249 (0x8C9) - DRC1RMIX Input 1 Volume */
+ { 0x000008ca, 0x0000 }, /* R2250 (0x8CA) - DRC1RMIX Input 2 Source */
+ { 0x000008cb, 0x0080 }, /* R2251 (0x8CB) - DRC1RMIX Input 2 Volume */
+ { 0x000008cc, 0x0000 }, /* R2252 (0x8CC) - DRC1RMIX Input 3 Source */
+ { 0x000008cd, 0x0080 }, /* R2253 (0x8CD) - DRC1RMIX Input 3 Volume */
+ { 0x000008ce, 0x0000 }, /* R2254 (0x8CE) - DRC1RMIX Input 4 Source */
+ { 0x000008cf, 0x0080 }, /* R2255 (0x8CF) - DRC1RMIX Input 4 Volume */
+ { 0x000008d0, 0x0000 }, /* R2256 (0x8D0) - DRC2LMIX Input 1 Source */
+ { 0x000008d1, 0x0080 }, /* R2257 (0x8D1) - DRC2LMIX Input 1 Volume */
+ { 0x000008d2, 0x0000 }, /* R2258 (0x8D2) - DRC2LMIX Input 2 Source */
+ { 0x000008d3, 0x0080 }, /* R2259 (0x8D3) - DRC2LMIX Input 2 Volume */
+ { 0x000008d4, 0x0000 }, /* R2260 (0x8D4) - DRC2LMIX Input 3 Source */
+ { 0x000008d5, 0x0080 }, /* R2261 (0x8D5) - DRC2LMIX Input 3 Volume */
+ { 0x000008d6, 0x0000 }, /* R2262 (0x8D6) - DRC2LMIX Input 4 Source */
+ { 0x000008d7, 0x0080 }, /* R2263 (0x8D7) - DRC2LMIX Input 4 Volume */
+ { 0x000008d8, 0x0000 }, /* R2264 (0x8D8) - DRC2RMIX Input 1 Source */
+ { 0x000008d9, 0x0080 }, /* R2265 (0x8D9) - DRC2RMIX Input 1 Volume */
+ { 0x000008da, 0x0000 }, /* R2266 (0x8DA) - DRC2RMIX Input 2 Source */
+ { 0x000008db, 0x0080 }, /* R2267 (0x8DB) - DRC2RMIX Input 2 Volume */
+ { 0x000008dc, 0x0000 }, /* R2268 (0x8DC) - DRC2RMIX Input 3 Source */
+ { 0x000008dd, 0x0080 }, /* R2269 (0x8DD) - DRC2RMIX Input 3 Volume */
+ { 0x000008de, 0x0000 }, /* R2270 (0x8DE) - DRC2RMIX Input 4 Source */
+ { 0x000008df, 0x0080 }, /* R2271 (0x8DF) - DRC2RMIX Input 4 Volume */
+ { 0x00000900, 0x0000 }, /* R2304 (0x900) - HPLP1MIX Input 1 Source */
+ { 0x00000901, 0x0080 }, /* R2305 (0x901) - HPLP1MIX Input 1 Volume */
+ { 0x00000902, 0x0000 }, /* R2306 (0x902) - HPLP1MIX Input 2 Source */
+ { 0x00000903, 0x0080 }, /* R2307 (0x903) - HPLP1MIX Input 2 Volume */
+ { 0x00000904, 0x0000 }, /* R2308 (0x904) - HPLP1MIX Input 3 Source */
+ { 0x00000905, 0x0080 }, /* R2309 (0x905) - HPLP1MIX Input 3 Volume */
+ { 0x00000906, 0x0000 }, /* R2310 (0x906) - HPLP1MIX Input 4 Source */
+ { 0x00000907, 0x0080 }, /* R2311 (0x907) - HPLP1MIX Input 4 Volume */
+ { 0x00000908, 0x0000 }, /* R2312 (0x908) - HPLP2MIX Input 1 Source */
+ { 0x00000909, 0x0080 }, /* R2313 (0x909) - HPLP2MIX Input 1 Volume */
+ { 0x0000090a, 0x0000 }, /* R2314 (0x90A) - HPLP2MIX Input 2 Source */
+ { 0x0000090b, 0x0080 }, /* R2315 (0x90B) - HPLP2MIX Input 2 Volume */
+ { 0x0000090c, 0x0000 }, /* R2316 (0x90C) - HPLP2MIX Input 3 Source */
+ { 0x0000090d, 0x0080 }, /* R2317 (0x90D) - HPLP2MIX Input 3 Volume */
+ { 0x0000090e, 0x0000 }, /* R2318 (0x90E) - HPLP2MIX Input 4 Source */
+ { 0x0000090f, 0x0080 }, /* R2319 (0x90F) - HPLP2MIX Input 4 Volume */
+ { 0x00000910, 0x0000 }, /* R2320 (0x910) - HPLP3MIX Input 1 Source */
+ { 0x00000911, 0x0080 }, /* R2321 (0x911) - HPLP3MIX Input 1 Volume */
+ { 0x00000912, 0x0000 }, /* R2322 (0x912) - HPLP3MIX Input 2 Source */
+ { 0x00000913, 0x0080 }, /* R2323 (0x913) - HPLP3MIX Input 2 Volume */
+ { 0x00000914, 0x0000 }, /* R2324 (0x914) - HPLP3MIX Input 3 Source */
+ { 0x00000915, 0x0080 }, /* R2325 (0x915) - HPLP3MIX Input 3 Volume */
+ { 0x00000916, 0x0000 }, /* R2326 (0x916) - HPLP3MIX Input 4 Source */
+ { 0x00000917, 0x0080 }, /* R2327 (0x917) - HPLP3MIX Input 4 Volume */
+ { 0x00000918, 0x0000 }, /* R2328 (0x918) - HPLP4MIX Input 1 Source */
+ { 0x00000919, 0x0080 }, /* R2329 (0x919) - HPLP4MIX Input 1 Volume */
+ { 0x0000091a, 0x0000 }, /* R2330 (0x91A) - HPLP4MIX Input 2 Source */
+ { 0x0000091b, 0x0080 }, /* R2331 (0x91B) - HPLP4MIX Input 2 Volume */
+ { 0x0000091c, 0x0000 }, /* R2332 (0x91C) - HPLP4MIX Input 3 Source */
+ { 0x0000091d, 0x0080 }, /* R2333 (0x91D) - HPLP4MIX Input 3 Volume */
+ { 0x0000091e, 0x0000 }, /* R2334 (0x91E) - HPLP4MIX Input 4 Source */
+ { 0x0000091f, 0x0080 }, /* R2335 (0x91F) - HPLP4MIX Input 4 Volume */
+ { 0x00000940, 0x0000 }, /* R2368 (0x940) - DSP1LMIX Input 1 Source */
+ { 0x00000941, 0x0080 }, /* R2369 (0x941) - DSP1LMIX Input 1 Volume */
+ { 0x00000942, 0x0000 }, /* R2370 (0x942) - DSP1LMIX Input 2 Source */
+ { 0x00000943, 0x0080 }, /* R2371 (0x943) - DSP1LMIX Input 2 Volume */
+ { 0x00000944, 0x0000 }, /* R2372 (0x944) - DSP1LMIX Input 3 Source */
+ { 0x00000945, 0x0080 }, /* R2373 (0x945) - DSP1LMIX Input 3 Volume */
+ { 0x00000946, 0x0000 }, /* R2374 (0x946) - DSP1LMIX Input 4 Source */
+ { 0x00000947, 0x0080 }, /* R2375 (0x947) - DSP1LMIX Input 4 Volume */
+ { 0x00000948, 0x0000 }, /* R2376 (0x948) - DSP1RMIX Input 1 Source */
+ { 0x00000949, 0x0080 }, /* R2377 (0x949) - DSP1RMIX Input 1 Volume */
+ { 0x0000094a, 0x0000 }, /* R2378 (0x94A) - DSP1RMIX Input 2 Source */
+ { 0x0000094b, 0x0080 }, /* R2379 (0x94B) - DSP1RMIX Input 2 Volume */
+ { 0x0000094c, 0x0000 }, /* R2380 (0x94C) - DSP1RMIX Input 3 Source */
+ { 0x0000094d, 0x0080 }, /* R2381 (0x94D) - DSP1RMIX Input 3 Volume */
+ { 0x0000094e, 0x0000 }, /* R2382 (0x94E) - DSP1RMIX Input 4 Source */
+ { 0x0000094f, 0x0080 }, /* R2383 (0x94F) - DSP1RMIX Input 4 Volume */
+ { 0x00000950, 0x0000 }, /* R2384 (0x950) - DSP1AUX1MIX Input 1 Source */
+ { 0x00000958, 0x0000 }, /* R2392 (0x958) - DSP1AUX2MIX Input 1 Source */
+ { 0x00000960, 0x0000 }, /* R2400 (0x960) - DSP1AUX3MIX Input 1 Source */
+ { 0x00000968, 0x0000 }, /* R2408 (0x968) - DSP1AUX4MIX Input 1 Source */
+ { 0x00000970, 0x0000 }, /* R2416 (0x970) - DSP1AUX5MIX Input 1 Source */
+ { 0x00000978, 0x0000 }, /* R2424 (0x978) - DSP1AUX6MIX Input 1 Source */
+ { 0x00000b00, 0x0000 }, /* R2816 (0xB00) - ISRC1DEC1MIX Input 1 Source */
+ { 0x00000b08, 0x0000 }, /* R2824 (0xB08) - ISRC1DEC2MIX Input 1 Source */
+ { 0x00000b10, 0x0000 }, /* R2832 (0xB10) - ISRC1DEC3MIX Input 1 Source */
+ { 0x00000b18, 0x0000 }, /* R2840 (0xB18) - ISRC1DEC4MIX Input 1 Source */
+ { 0x00000b20, 0x0000 }, /* R2848 (0xB20) - ISRC1INT1MIX Input 1 Source */
+ { 0x00000b28, 0x0000 }, /* R2856 (0xB28) - ISRC1INT2MIX Input 1 Source */
+ { 0x00000b30, 0x0000 }, /* R2864 (0xB30) - ISRC1INT3MIX Input 1 Source */
+ { 0x00000b38, 0x0000 }, /* R2872 (0xB38) - ISRC1INT4MIX Input 1 Source */
+ { 0x00000b40, 0x0000 }, /* R2880 (0xB40) - ISRC2DEC1MIX Input 1 Source */
+ { 0x00000b48, 0x0000 }, /* R2888 (0xB48) - ISRC2DEC2MIX Input 1 Source */
+ { 0x00000b50, 0x0000 }, /* R2896 (0xB50) - ISRC2DEC3MIX Input 1 Source */
+ { 0x00000b58, 0x0000 }, /* R2904 (0xB58) - ISRC2DEC4MIX Input 1 Source */
+ { 0x00000b60, 0x0000 }, /* R2912 (0xB60) - ISRC2INT1MIX Input 1 Source */
+ { 0x00000b68, 0x0000 }, /* R2920 (0xB68) - ISRC2INT2MIX Input 1 Source */
+ { 0x00000b70, 0x0000 }, /* R2928 (0xB70) - ISRC2INT3MIX Input 1 Source */
+ { 0x00000b78, 0x0000 }, /* R2936 (0xB78) - ISRC2INT4MIX Input 1 Source */
+ { 0x00000e00, 0x0000 }, /* R3584 (0xE00) - FX Ctrl 1 */
+ { 0x00000e10, 0x6318 }, /* R3600 (0xE10) - EQ1 1 */
+ { 0x00000e11, 0x6300 }, /* R3601 (0xE11) - EQ1 2 */
+ { 0x00000e12, 0x0fc8 }, /* R3602 (0xE12) - EQ1 3 */
+ { 0x00000e13, 0x03fe }, /* R3603 (0xE13) - EQ1 4 */
+ { 0x00000e14, 0x00e0 }, /* R3604 (0xE14) - EQ1 5 */
+ { 0x00000e15, 0x1ec4 }, /* R3605 (0xE15) - EQ1 6 */
+ { 0x00000e16, 0xf136 }, /* R3606 (0xE16) - EQ1 7 */
+ { 0x00000e17, 0x0409 }, /* R3607 (0xE17) - EQ1 8 */
+ { 0x00000e18, 0x04cc }, /* R3608 (0xE18) - EQ1 9 */
+ { 0x00000e19, 0x1c9b }, /* R3609 (0xE19) - EQ1 10 */
+ { 0x00000e1a, 0xf337 }, /* R3610 (0xE1A) - EQ1 11 */
+ { 0x00000e1b, 0x040b }, /* R3611 (0xE1B) - EQ1 12 */
+ { 0x00000e1c, 0x0cbb }, /* R3612 (0xE1C) - EQ1 13 */
+ { 0x00000e1d, 0x16f8 }, /* R3613 (0xE1D) - EQ1 14 */
+ { 0x00000e1e, 0xf7d9 }, /* R3614 (0xE1E) - EQ1 15 */
+ { 0x00000e1f, 0x040a }, /* R3615 (0xE1F) - EQ1 16 */
+ { 0x00000e20, 0x1f14 }, /* R3616 (0xE20) - EQ1 17 */
+ { 0x00000e21, 0x058c }, /* R3617 (0xE21) - EQ1 18 */
+ { 0x00000e22, 0x0563 }, /* R3618 (0xE22) - EQ1 19 */
+ { 0x00000e23, 0x4000 }, /* R3619 (0xE23) - EQ1 20 */
+ { 0x00000e24, 0x0b75 }, /* R3620 (0xE24) - EQ1 21 */
+ { 0x00000e26, 0x6318 }, /* R3622 (0xE26) - EQ2 1 */
+ { 0x00000e27, 0x6300 }, /* R3623 (0xE27) - EQ2 2 */
+ { 0x00000e28, 0x0fc8 }, /* R3624 (0xE28) - EQ2 3 */
+ { 0x00000e29, 0x03fe }, /* R3625 (0xE29) - EQ2 4 */
+ { 0x00000e2a, 0x00e0 }, /* R3626 (0xE2A) - EQ2 5 */
+ { 0x00000e2b, 0x1ec4 }, /* R3627 (0xE2B) - EQ2 6 */
+ { 0x00000e2c, 0xf136 }, /* R3628 (0xE2C) - EQ2 7 */
+ { 0x00000e2d, 0x0409 }, /* R3629 (0xE2D) - EQ2 8 */
+ { 0x00000e2e, 0x04cc }, /* R3630 (0xE2E) - EQ2 9 */
+ { 0x00000e2f, 0x1c9b }, /* R3631 (0xE2F) - EQ2 10 */
+ { 0x00000e30, 0xf337 }, /* R3632 (0xE30) - EQ2 11 */
+ { 0x00000e31, 0x040b }, /* R3633 (0xE31) - EQ2 12 */
+ { 0x00000e32, 0x0cbb }, /* R3634 (0xE32) - EQ2 13 */
+ { 0x00000e33, 0x16f8 }, /* R3635 (0xE33) - EQ2 14 */
+ { 0x00000e34, 0xf7d9 }, /* R3636 (0xE34) - EQ2 15 */
+ { 0x00000e35, 0x040a }, /* R3637 (0xE35) - EQ2 16 */
+ { 0x00000e36, 0x1f14 }, /* R3638 (0xE36) - EQ2 17 */
+ { 0x00000e37, 0x058c }, /* R3639 (0xE37) - EQ2 18 */
+ { 0x00000e38, 0x0563 }, /* R3640 (0xE38) - EQ2 19 */
+ { 0x00000e39, 0x4000 }, /* R3641 (0xE39) - EQ2 20 */
+ { 0x00000e3a, 0x0b75 }, /* R3642 (0xE3A) - EQ2 21 */
+ { 0x00000e3c, 0x6318 }, /* R3644 (0xE3C) - EQ3 1 */
+ { 0x00000e3d, 0x6300 }, /* R3645 (0xE3D) - EQ3 2 */
+ { 0x00000e3e, 0x0fc8 }, /* R3646 (0xE3E) - EQ3 3 */
+ { 0x00000e3f, 0x03fe }, /* R3647 (0xE3F) - EQ3 4 */
+ { 0x00000e40, 0x00e0 }, /* R3648 (0xE40) - EQ3 5 */
+ { 0x00000e41, 0x1ec4 }, /* R3649 (0xE41) - EQ3 6 */
+ { 0x00000e42, 0xf136 }, /* R3650 (0xE42) - EQ3 7 */
+ { 0x00000e43, 0x0409 }, /* R3651 (0xE43) - EQ3 8 */
+ { 0x00000e44, 0x04cc }, /* R3652 (0xE44) - EQ3 9 */
+ { 0x00000e45, 0x1c9b }, /* R3653 (0xE45) - EQ3 10 */
+ { 0x00000e46, 0xf337 }, /* R3654 (0xE46) - EQ3 11 */
+ { 0x00000e47, 0x040b }, /* R3655 (0xE47) - EQ3 12 */
+ { 0x00000e48, 0x0cbb }, /* R3656 (0xE48) - EQ3 13 */
+ { 0x00000e49, 0x16f8 }, /* R3657 (0xE49) - EQ3 14 */
+ { 0x00000e4a, 0xf7d9 }, /* R3658 (0xE4A) - EQ3 15 */
+ { 0x00000e4b, 0x040a }, /* R3659 (0xE4B) - EQ3 16 */
+ { 0x00000e4c, 0x1f14 }, /* R3660 (0xE4C) - EQ3 17 */
+ { 0x00000e4d, 0x058c }, /* R3661 (0xE4D) - EQ3 18 */
+ { 0x00000e4e, 0x0563 }, /* R3662 (0xE4E) - EQ3 19 */
+ { 0x00000e4f, 0x4000 }, /* R3663 (0xE4F) - EQ3 20 */
+ { 0x00000e50, 0x0b75 }, /* R3664 (0xE50) - EQ3 21 */
+ { 0x00000e52, 0x6318 }, /* R3666 (0xE52) - EQ4 1 */
+ { 0x00000e53, 0x6300 }, /* R3667 (0xE53) - EQ4 2 */
+ { 0x00000e54, 0x0fc8 }, /* R3668 (0xE54) - EQ4 3 */
+ { 0x00000e55, 0x03fe }, /* R3669 (0xE55) - EQ4 4 */
+ { 0x00000e56, 0x00e0 }, /* R3670 (0xE56) - EQ4 5 */
+ { 0x00000e57, 0x1ec4 }, /* R3671 (0xE57) - EQ4 6 */
+ { 0x00000e58, 0xf136 }, /* R3672 (0xE58) - EQ4 7 */
+ { 0x00000e59, 0x0409 }, /* R3673 (0xE59) - EQ4 8 */
+ { 0x00000e5a, 0x04cc }, /* R3674 (0xE5A) - EQ4 9 */
+ { 0x00000e5b, 0x1c9b }, /* R3675 (0xE5B) - EQ4 10 */
+ { 0x00000e5c, 0xf337 }, /* R3676 (0xE5C) - EQ4 11 */
+ { 0x00000e5d, 0x040b }, /* R3677 (0xE5D) - EQ4 12 */
+ { 0x00000e5e, 0x0cbb }, /* R3678 (0xE5E) - EQ4 13 */
+ { 0x00000e5f, 0x16f8 }, /* R3679 (0xE5F) - EQ4 14 */
+ { 0x00000e60, 0xf7d9 }, /* R3680 (0xE60) - EQ4 15 */
+ { 0x00000e61, 0x040a }, /* R3681 (0xE61) - EQ4 16 */
+ { 0x00000e62, 0x1f14 }, /* R3682 (0xE62) - EQ4 17 */
+ { 0x00000e63, 0x058c }, /* R3683 (0xE63) - EQ4 18 */
+ { 0x00000e64, 0x0563 }, /* R3684 (0xE64) - EQ4 19 */
+ { 0x00000e65, 0x4000 }, /* R3685 (0xE65) - EQ4 20 */
+ { 0x00000e66, 0x0b75 }, /* R3686 (0xE66) - EQ4 21 */
+ { 0x00000e80, 0x0018 }, /* R3712 (0xE80) - DRC1 Ctrl 1 */
+ { 0x00000e81, 0x0933 }, /* R3713 (0xE81) - DRC1 Ctrl 2 */
+ { 0x00000e82, 0x0018 }, /* R3714 (0xE82) - DRC1 Ctrl 3 */
+ { 0x00000e83, 0x0000 }, /* R3715 (0xE83) - DRC1 Ctrl 4 */
+ { 0x00000e84, 0x0000 }, /* R3716 (0xE84) - DRC1 Ctrl 5 */
+ { 0x00000e88, 0x0018 }, /* R3720 (0xE88) - DRC2 Ctrl 1 */
+ { 0x00000e89, 0x0933 }, /* R3721 (0xE89) - DRC2 Ctrl 2 */
+ { 0x00000e8a, 0x0018 }, /* R3722 (0xE8A) - DRC2 Ctrl 3 */
+ { 0x00000e8b, 0x0000 }, /* R3723 (0xE8B) - DRC2 Ctrl 4 */
+ { 0x00000e8c, 0x0000 }, /* R3724 (0xE8C) - DRC2 Ctrl 5 */
+ { 0x00000ec0, 0x0000 }, /* R3776 (0xEC0) - HPLPF1 1 */
+ { 0x00000ec1, 0x0000 }, /* R3777 (0xEC1) - HPLPF1 2 */
+ { 0x00000ec4, 0x0000 }, /* R3780 (0xEC4) - HPLPF2 1 */
+ { 0x00000ec5, 0x0000 }, /* R3781 (0xEC5) - HPLPF2 2 */
+ { 0x00000ec8, 0x0000 }, /* R3784 (0xEC8) - HPLPF3 1 */
+ { 0x00000ec9, 0x0000 }, /* R3785 (0xEC9) - HPLPF3 2 */
+ { 0x00000ecc, 0x0000 }, /* R3788 (0xECC) - HPLPF4 1 */
+ { 0x00000ecd, 0x0000 }, /* R3789 (0xECD) - HPLPF4 2 */
+ { 0x00000ef0, 0x0000 }, /* R3824 (0xEF0) - ISRC1 Ctrl 1 */
+ { 0x00000ef1, 0x0001 }, /* R3825 (0xEF1) - ISRC1 Ctrl 2 */
+ { 0x00000ef2, 0x0000 }, /* R3826 (0xEF2) - ISRC1 Ctrl 3 */
+ { 0x00000ef3, 0x0000 }, /* R3827 (0xEF3) - ISRC2 Ctrl 1 */
+ { 0x00000ef4, 0x0001 }, /* R3828 (0xEF4) - ISRC2 Ctrl 2 */
+ { 0x00000ef5, 0x0000 }, /* R3829 (0xEF5) - ISRC2 Ctrl 3 */
+ { 0x00001700, 0x2801 }, /* R5888 (0x1700) - GPIO1 Ctrl 1 */
+ { 0x00001701, 0xe800 }, /* R5889 (0x1701) - GPIO1 Ctrl 2 */
+ { 0x00001702, 0x2801 }, /* R5890 (0x1702) - GPIO2 Ctrl 1 */
+ { 0x00001703, 0xe800 }, /* R5891 (0x1703) - GPIO2 Ctrl 2 */
+ { 0x00001704, 0x2801 }, /* R5892 (0x1704) - GPIO3 Ctrl 1 */
+ { 0x00001705, 0xe800 }, /* R5893 (0x1705) - GPIO3 Ctrl 2 */
+ { 0x00001706, 0x2801 }, /* R5894 (0x1706) - GPIO4 Ctrl 1 */
+ { 0x00001707, 0xe800 }, /* R5895 (0x1707) - GPIO4 Ctrl 2 */
+ { 0x00001708, 0x2801 }, /* R5896 (0x1708) - GPIO5 Ctrl 1 */
+ { 0x00001709, 0xe800 }, /* R5897 (0x1709) - GPIO5 Ctrl 2 */
+ { 0x0000170a, 0x2801 }, /* R5898 (0x170A) - GPIO6 Ctrl 1 */
+ { 0x0000170b, 0xe800 }, /* R5899 (0x170B) - GPIO6 Ctrl 2 */
+ { 0x0000170c, 0x2801 }, /* R5900 (0x170C) - GPIO7 Ctrl 1 */
+ { 0x0000170d, 0xe800 }, /* R5901 (0x170D) - GPIO7 Ctrl 2 */
+ { 0x0000170e, 0x2801 }, /* R5902 (0x170E) - GPIO8 Ctrl 1 */
+ { 0x0000170f, 0xe800 }, /* R5903 (0x170F) - GPIO8 Ctrl 2 */
+ { 0x00001710, 0x2801 }, /* R5904 (0x1710) - GPIO9 Ctrl 1 */
+ { 0x00001711, 0xe800 }, /* R5905 (0x1711) - GPIO9 Ctrl 2 */
+ { 0x00001712, 0x2801 }, /* R5906 (0x1712) - GPIO10 Ctrl 1 */
+ { 0x00001713, 0xe800 }, /* R5907 (0x1713) - GPIO10 Ctrl 2 */
+ { 0x00001714, 0x2801 }, /* R5908 (0x1714) - GPIO11 Ctrl 1 */
+ { 0x00001715, 0xe800 }, /* R5909 (0x1715) - GPIO11 Ctrl 2 */
+ { 0x00001716, 0x2801 }, /* R5910 (0x1716) - GPIO12 Ctrl 1 */
+ { 0x00001717, 0xe800 }, /* R5911 (0x1717) - GPIO12 Ctrl 2 */
+ { 0x00001718, 0x2801 }, /* R5912 (0x1718) - GPIO13 Ctrl 1 */
+ { 0x00001719, 0xe800 }, /* R5913 (0x1719) - GPIO13 Ctrl 2 */
+ { 0x0000171a, 0x2801 }, /* R5914 (0x171A) - GPIO14 Ctrl 1 */
+ { 0x0000171b, 0xe800 }, /* R5915 (0x171B) - GPIO14 Ctrl 2 */
+ { 0x0000171c, 0x2801 }, /* R5916 (0x171C) - GPIO15 Ctrl 1 */
+ { 0x0000171d, 0xe800 }, /* R5917 (0x171D) - GPIO15 Ctrl 2 */
+ { 0x00001840, 0xffff }, /* R6208 (0x1840) - IRQ1 Mask 1 */
+ { 0x00001841, 0xffff }, /* R6209 (0x1841) - IRQ1 Mask 2 */
+ { 0x00001842, 0xffff }, /* R6210 (0x1842) - IRQ1 Mask 3 */
+ { 0x00001843, 0xffff }, /* R6211 (0x1843) - IRQ1 Mask 4 */
+ { 0x00001844, 0xffff }, /* R6212 (0x1844) - IRQ1 Mask 5 */
+ { 0x00001845, 0xffff }, /* R6213 (0x1845) - IRQ1 Mask 6 */
+ { 0x00001846, 0xffff }, /* R6214 (0x1846) - IRQ1 Mask 7 */
+ { 0x00001847, 0xffff }, /* R6215 (0x1847) - IRQ1 Mask 8 */
+ { 0x00001848, 0xffff }, /* R6216 (0x1848) - IRQ1 Mask 9 */
+ { 0x00001849, 0xffff }, /* R6217 (0x1849) - IRQ1 Mask 10 */
+ { 0x0000184a, 0xffff }, /* R6218 (0x184A) - IRQ1 Mask 11 */
+ { 0x0000184b, 0xffff }, /* R6219 (0x184B) - IRQ1 Mask 12 */
+ { 0x0000184c, 0xffff }, /* R6220 (0x184C) - IRQ1 Mask 13 */
+ { 0x0000184d, 0xffff }, /* R6221 (0x184D) - IRQ1 Mask 14 */
+ { 0x0000184e, 0xffff }, /* R6222 (0x184E) - IRQ1 Mask 15 */
+ { 0x0000184f, 0xffff }, /* R6223 (0x184F) - IRQ1 Mask 16 */
+ { 0x00001850, 0xffff }, /* R6224 (0x1850) - IRQ1 Mask 17 */
+ { 0x00001851, 0xffff }, /* R6225 (0x1851) - IRQ1 Mask 18 */
+ { 0x00001852, 0xffff }, /* R6226 (0x1852) - IRQ1 Mask 19 */
+ { 0x00001853, 0xffff }, /* R6227 (0x1853) - IRQ1 Mask 20 */
+ { 0x00001854, 0xffff }, /* R6228 (0x1854) - IRQ1 Mask 21 */
+ { 0x00001855, 0xffff }, /* R6229 (0x1855) - IRQ1 Mask 22 */
+ { 0x00001856, 0xffff }, /* R6230 (0x1856) - IRQ1 Mask 23 */
+ { 0x00001857, 0xffff }, /* R6231 (0x1857) - IRQ1 Mask 24 */
+ { 0x00001858, 0xffff }, /* R6232 (0x1858) - IRQ1 Mask 25 */
+ { 0x00001859, 0xffff }, /* R6233 (0x1859) - IRQ1 Mask 26 */
+ { 0x0000185a, 0xffff }, /* R6234 (0x185A) - IRQ1 Mask 27 */
+ { 0x0000185b, 0xffff }, /* R6235 (0x185B) - IRQ1 Mask 28 */
+ { 0x0000185c, 0xffff }, /* R6236 (0x185C) - IRQ1 Mask 29 */
+ { 0x0000185d, 0xffff }, /* R6237 (0x185D) - IRQ1 Mask 30 */
+ { 0x0000185e, 0xffff }, /* R6238 (0x185E) - IRQ1 Mask 31 */
+ { 0x0000185f, 0xffff }, /* R6239 (0x185F) - IRQ1 Mask 32 */
+ { 0x00001860, 0xffff }, /* R6240 (0x1860) - IRQ1 Mask 33 */
+ { 0x00001a06, 0x0000 }, /* R6662 (0x1A06) - Interrupt Debounce 7 */
+ { 0x00001a80, 0x4400 }, /* R6784 (0x1A80) - IRQ1 Ctrl */
+};
+
+static bool cs47l15_is_adsp_memory(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x080000 ... 0x088ffe:
+ case 0x0a0000 ... 0x0a9ffe:
+ case 0x0c0000 ... 0x0c1ffe:
+ case 0x0e0000 ... 0x0e1ffe:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool cs47l15_16bit_readable_register(struct device *dev,
+ unsigned int reg)
+{
+ switch (reg) {
+ case MADERA_SOFTWARE_RESET:
+ case MADERA_HARDWARE_REVISION:
+ case MADERA_WRITE_SEQUENCER_CTRL_0 ... MADERA_WRITE_SEQUENCER_CTRL_2:
+ case MADERA_TONE_GENERATOR_1 ... MADERA_TONE_GENERATOR_5:
+ case MADERA_PWM_DRIVE_1 ... MADERA_PWM_DRIVE_3:
+ case MADERA_SAMPLE_RATE_SEQUENCE_SELECT_1:
+ case MADERA_SAMPLE_RATE_SEQUENCE_SELECT_2:
+ case MADERA_SAMPLE_RATE_SEQUENCE_SELECT_3:
+ case MADERA_SAMPLE_RATE_SEQUENCE_SELECT_4:
+ case MADERA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_1:
+ case MADERA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_2:
+ case MADERA_HAPTICS_CONTROL_1 ... MADERA_HAPTICS_CONTROL_2:
+ case MADERA_HAPTICS_PHASE_1_INTENSITY:
+ case MADERA_HAPTICS_PHASE_1_DURATION:
+ case MADERA_HAPTICS_PHASE_2_INTENSITY:
+ case MADERA_HAPTICS_PHASE_2_DURATION:
+ case MADERA_HAPTICS_PHASE_3_INTENSITY:
+ case MADERA_HAPTICS_PHASE_3_DURATION:
+ case MADERA_HAPTICS_STATUS:
+ case MADERA_COMFORT_NOISE_GENERATOR:
+ case MADERA_CLOCK_32K_1:
+ case MADERA_SYSTEM_CLOCK_1:
+ case MADERA_SAMPLE_RATE_1 ... MADERA_SAMPLE_RATE_3:
+ case MADERA_SAMPLE_RATE_1_STATUS:
+ case MADERA_SAMPLE_RATE_2_STATUS:
+ case MADERA_SAMPLE_RATE_3_STATUS:
+ case MADERA_DSP_CLOCK_1:
+ case MADERA_DSP_CLOCK_2:
+ case MADERA_OUTPUT_SYSTEM_CLOCK:
+ case MADERA_RATE_ESTIMATOR_1 ... MADERA_RATE_ESTIMATOR_5:
+ case MADERA_FLL1_CONTROL_1 ... MADERA_FLL1_CONTROL_6:
+ case MADERA_FLL1_CONTROL_7:
+ case MADERA_FLL1_EFS_2:
+ case MADERA_FLL1_SYNCHRONISER_1 ... MADERA_FLL1_SYNCHRONISER_7:
+ case MADERA_FLL1_SPREAD_SPECTRUM:
+ case MADERA_FLL1_GPIO_CLOCK:
+ case MADERA_FLLAO_CONTROL_1:
+ case MADERA_FLLAO_CONTROL_2:
+ case MADERA_FLLAO_CONTROL_3:
+ case MADERA_FLLAO_CONTROL_4:
+ case MADERA_FLLAO_CONTROL_5:
+ case MADERA_FLLAO_CONTROL_6:
+ case MADERA_FLLAO_CONTROL_7:
+ case MADERA_FLLAO_CONTROL_8:
+ case MADERA_FLLAO_CONTROL_9:
+ case MADERA_FLLAO_CONTROL_10:
+ case MADERA_FLLAO_CONTROL_11:
+ case MADERA_MIC_BIAS_CTRL_1:
+ case MADERA_MIC_BIAS_CTRL_5:
+ case MADERA_HP_CTRL_1L:
+ case MADERA_HP_CTRL_1R:
+ case MADERA_ACCESSORY_DETECT_MODE_1:
+ case MADERA_HEADPHONE_DETECT_0:
+ case MADERA_HEADPHONE_DETECT_1:
+ case MADERA_HEADPHONE_DETECT_2:
+ case MADERA_HEADPHONE_DETECT_3:
+ case MADERA_HEADPHONE_DETECT_5:
+ case MADERA_MICD_CLAMP_CONTROL:
+ case MADERA_MIC_DETECT_1_CONTROL_0:
+ case MADERA_MIC_DETECT_1_CONTROL_1:
+ case MADERA_MIC_DETECT_1_CONTROL_2:
+ case MADERA_MIC_DETECT_1_CONTROL_3:
+ case MADERA_MIC_DETECT_1_LEVEL_1 ... MADERA_MIC_DETECT_1_LEVEL_4:
+ case MADERA_MIC_DETECT_1_CONTROL_4:
+ case MADERA_GP_SWITCH_1:
+ case MADERA_JACK_DETECT_ANALOGUE:
+ case MADERA_INPUT_ENABLES:
+ case MADERA_INPUT_ENABLES_STATUS:
+ case MADERA_INPUT_RATE:
+ case MADERA_INPUT_VOLUME_RAMP:
+ case MADERA_HPF_CONTROL:
+ case MADERA_IN1L_CONTROL:
+ case MADERA_ADC_DIGITAL_VOLUME_1L:
+ case MADERA_DMIC1L_CONTROL:
+ case MADERA_IN1L_RATE_CONTROL:
+ case MADERA_IN1R_CONTROL:
+ case MADERA_ADC_DIGITAL_VOLUME_1R:
+ case MADERA_DMIC1R_CONTROL:
+ case MADERA_IN1R_RATE_CONTROL:
+ case MADERA_IN2L_CONTROL:
+ case MADERA_ADC_DIGITAL_VOLUME_2L:
+ case MADERA_DMIC2L_CONTROL:
+ case MADERA_IN2L_RATE_CONTROL:
+ case MADERA_IN2R_CONTROL:
+ case MADERA_ADC_DIGITAL_VOLUME_2R:
+ case MADERA_DMIC2R_CONTROL:
+ case MADERA_IN2R_RATE_CONTROL:
+ case CS47L15_ADC_INT_BIAS:
+ case CS47L15_PGA_BIAS_SEL:
+ case MADERA_OUTPUT_ENABLES_1:
+ case MADERA_OUTPUT_STATUS_1:
+ case MADERA_RAW_OUTPUT_STATUS_1:
+ case MADERA_OUTPUT_RATE_1:
+ case MADERA_OUTPUT_VOLUME_RAMP:
+ case MADERA_OUTPUT_PATH_CONFIG_1L:
+ case MADERA_DAC_DIGITAL_VOLUME_1L:
+ case MADERA_OUTPUT_PATH_CONFIG_1:
+ case MADERA_NOISE_GATE_SELECT_1L:
+ case MADERA_OUTPUT_PATH_CONFIG_1R:
+ case MADERA_DAC_DIGITAL_VOLUME_1R:
+ case MADERA_NOISE_GATE_SELECT_1R:
+ case MADERA_OUTPUT_PATH_CONFIG_2:
+ case MADERA_OUTPUT_PATH_CONFIG_4L:
+ case MADERA_DAC_DIGITAL_VOLUME_4L:
+ case MADERA_NOISE_GATE_SELECT_4L:
+ case MADERA_OUTPUT_PATH_CONFIG_5L:
+ case MADERA_DAC_DIGITAL_VOLUME_5L:
+ case MADERA_NOISE_GATE_SELECT_5L:
+ case MADERA_OUTPUT_PATH_CONFIG_5R:
+ case MADERA_DAC_DIGITAL_VOLUME_5R:
+ case MADERA_NOISE_GATE_SELECT_5R:
+ case MADERA_DAC_AEC_CONTROL_1:
+ case MADERA_DAC_AEC_CONTROL_2:
+ case MADERA_NOISE_GATE_CONTROL:
+ case MADERA_PDM_SPK1_CTRL_1 ... MADERA_PDM_SPK1_CTRL_2:
+ case MADERA_HP1_SHORT_CIRCUIT_CTRL:
+ case MADERA_HP_TEST_CTRL_5:
+ case MADERA_HP_TEST_CTRL_6:
+ case MADERA_AIF1_BCLK_CTRL:
+ case MADERA_AIF1_TX_PIN_CTRL:
+ case MADERA_AIF1_RX_PIN_CTRL:
+ case MADERA_AIF1_RATE_CTRL:
+ case MADERA_AIF1_FORMAT:
+ case MADERA_AIF1_RX_BCLK_RATE:
+ case MADERA_AIF1_FRAME_CTRL_1 ... MADERA_AIF1_FRAME_CTRL_8:
+ case MADERA_AIF1_FRAME_CTRL_11 ... MADERA_AIF1_FRAME_CTRL_16:
+ case MADERA_AIF1_TX_ENABLES:
+ case MADERA_AIF1_RX_ENABLES:
+ case MADERA_AIF2_BCLK_CTRL:
+ case MADERA_AIF2_TX_PIN_CTRL:
+ case MADERA_AIF2_RX_PIN_CTRL:
+ case MADERA_AIF2_RATE_CTRL:
+ case MADERA_AIF2_FORMAT:
+ case MADERA_AIF2_RX_BCLK_RATE:
+ case MADERA_AIF2_FRAME_CTRL_1 ... MADERA_AIF2_FRAME_CTRL_6:
+ case MADERA_AIF2_FRAME_CTRL_11 ... MADERA_AIF2_FRAME_CTRL_14:
+ case MADERA_AIF2_TX_ENABLES:
+ case MADERA_AIF2_RX_ENABLES:
+ case MADERA_AIF3_BCLK_CTRL:
+ case MADERA_AIF3_TX_PIN_CTRL:
+ case MADERA_AIF3_RX_PIN_CTRL:
+ case MADERA_AIF3_RATE_CTRL:
+ case MADERA_AIF3_FORMAT:
+ case MADERA_AIF3_RX_BCLK_RATE:
+ case MADERA_AIF3_FRAME_CTRL_1 ... MADERA_AIF3_FRAME_CTRL_4:
+ case MADERA_AIF3_FRAME_CTRL_11 ... MADERA_AIF3_FRAME_CTRL_12:
+ case MADERA_AIF3_TX_ENABLES:
+ case MADERA_AIF3_RX_ENABLES:
+ case MADERA_SPD1_TX_CONTROL:
+ case MADERA_SPD1_TX_CHANNEL_STATUS_1:
+ case MADERA_SPD1_TX_CHANNEL_STATUS_2:
+ case MADERA_SPD1_TX_CHANNEL_STATUS_3:
+ case MADERA_PWM1MIX_INPUT_1_SOURCE:
+ case MADERA_PWM1MIX_INPUT_1_VOLUME:
+ case MADERA_PWM1MIX_INPUT_2_SOURCE:
+ case MADERA_PWM1MIX_INPUT_2_VOLUME:
+ case MADERA_PWM1MIX_INPUT_3_SOURCE:
+ case MADERA_PWM1MIX_INPUT_3_VOLUME:
+ case MADERA_PWM1MIX_INPUT_4_SOURCE:
+ case MADERA_PWM1MIX_INPUT_4_VOLUME:
+ case MADERA_PWM2MIX_INPUT_1_SOURCE:
+ case MADERA_PWM2MIX_INPUT_1_VOLUME:
+ case MADERA_PWM2MIX_INPUT_2_SOURCE:
+ case MADERA_PWM2MIX_INPUT_2_VOLUME:
+ case MADERA_PWM2MIX_INPUT_3_SOURCE:
+ case MADERA_PWM2MIX_INPUT_3_VOLUME:
+ case MADERA_PWM2MIX_INPUT_4_SOURCE:
+ case MADERA_PWM2MIX_INPUT_4_VOLUME:
+ case MADERA_OUT1LMIX_INPUT_1_SOURCE:
+ case MADERA_OUT1LMIX_INPUT_1_VOLUME:
+ case MADERA_OUT1LMIX_INPUT_2_SOURCE:
+ case MADERA_OUT1LMIX_INPUT_2_VOLUME:
+ case MADERA_OUT1LMIX_INPUT_3_SOURCE:
+ case MADERA_OUT1LMIX_INPUT_3_VOLUME:
+ case MADERA_OUT1LMIX_INPUT_4_SOURCE:
+ case MADERA_OUT1LMIX_INPUT_4_VOLUME:
+ case MADERA_OUT1RMIX_INPUT_1_SOURCE:
+ case MADERA_OUT1RMIX_INPUT_1_VOLUME:
+ case MADERA_OUT1RMIX_INPUT_2_SOURCE:
+ case MADERA_OUT1RMIX_INPUT_2_VOLUME:
+ case MADERA_OUT1RMIX_INPUT_3_SOURCE:
+ case MADERA_OUT1RMIX_INPUT_3_VOLUME:
+ case MADERA_OUT1RMIX_INPUT_4_SOURCE:
+ case MADERA_OUT1RMIX_INPUT_4_VOLUME:
+ case MADERA_OUT4LMIX_INPUT_1_SOURCE:
+ case MADERA_OUT4LMIX_INPUT_1_VOLUME:
+ case MADERA_OUT4LMIX_INPUT_2_SOURCE:
+ case MADERA_OUT4LMIX_INPUT_2_VOLUME:
+ case MADERA_OUT4LMIX_INPUT_3_SOURCE:
+ case MADERA_OUT4LMIX_INPUT_3_VOLUME:
+ case MADERA_OUT4LMIX_INPUT_4_SOURCE:
+ case MADERA_OUT4LMIX_INPUT_4_VOLUME:
+ case MADERA_OUT5LMIX_INPUT_1_SOURCE:
+ case MADERA_OUT5LMIX_INPUT_1_VOLUME:
+ case MADERA_OUT5LMIX_INPUT_2_SOURCE:
+ case MADERA_OUT5LMIX_INPUT_2_VOLUME:
+ case MADERA_OUT5LMIX_INPUT_3_SOURCE:
+ case MADERA_OUT5LMIX_INPUT_3_VOLUME:
+ case MADERA_OUT5LMIX_INPUT_4_SOURCE:
+ case MADERA_OUT5LMIX_INPUT_4_VOLUME:
+ case MADERA_OUT5RMIX_INPUT_1_SOURCE:
+ case MADERA_OUT5RMIX_INPUT_1_VOLUME:
+ case MADERA_OUT5RMIX_INPUT_2_SOURCE:
+ case MADERA_OUT5RMIX_INPUT_2_VOLUME:
+ case MADERA_OUT5RMIX_INPUT_3_SOURCE:
+ case MADERA_OUT5RMIX_INPUT_3_VOLUME:
+ case MADERA_OUT5RMIX_INPUT_4_SOURCE:
+ case MADERA_OUT5RMIX_INPUT_4_VOLUME:
+ case MADERA_AIF1TX1MIX_INPUT_1_SOURCE:
+ case MADERA_AIF1TX1MIX_INPUT_1_VOLUME:
+ case MADERA_AIF1TX1MIX_INPUT_2_SOURCE:
+ case MADERA_AIF1TX1MIX_INPUT_2_VOLUME:
+ case MADERA_AIF1TX1MIX_INPUT_3_SOURCE:
+ case MADERA_AIF1TX1MIX_INPUT_3_VOLUME:
+ case MADERA_AIF1TX1MIX_INPUT_4_SOURCE:
+ case MADERA_AIF1TX1MIX_INPUT_4_VOLUME:
+ case MADERA_AIF1TX2MIX_INPUT_1_SOURCE:
+ case MADERA_AIF1TX2MIX_INPUT_1_VOLUME:
+ case MADERA_AIF1TX2MIX_INPUT_2_SOURCE:
+ case MADERA_AIF1TX2MIX_INPUT_2_VOLUME:
+ case MADERA_AIF1TX2MIX_INPUT_3_SOURCE:
+ case MADERA_AIF1TX2MIX_INPUT_3_VOLUME:
+ case MADERA_AIF1TX2MIX_INPUT_4_SOURCE:
+ case MADERA_AIF1TX2MIX_INPUT_4_VOLUME:
+ case MADERA_AIF1TX3MIX_INPUT_1_SOURCE:
+ case MADERA_AIF1TX3MIX_INPUT_1_VOLUME:
+ case MADERA_AIF1TX3MIX_INPUT_2_SOURCE:
+ case MADERA_AIF1TX3MIX_INPUT_2_VOLUME:
+ case MADERA_AIF1TX3MIX_INPUT_3_SOURCE:
+ case MADERA_AIF1TX3MIX_INPUT_3_VOLUME:
+ case MADERA_AIF1TX3MIX_INPUT_4_SOURCE:
+ case MADERA_AIF1TX3MIX_INPUT_4_VOLUME:
+ case MADERA_AIF1TX4MIX_INPUT_1_SOURCE:
+ case MADERA_AIF1TX4MIX_INPUT_1_VOLUME:
+ case MADERA_AIF1TX4MIX_INPUT_2_SOURCE:
+ case MADERA_AIF1TX4MIX_INPUT_2_VOLUME:
+ case MADERA_AIF1TX4MIX_INPUT_3_SOURCE:
+ case MADERA_AIF1TX4MIX_INPUT_3_VOLUME:
+ case MADERA_AIF1TX4MIX_INPUT_4_SOURCE:
+ case MADERA_AIF1TX4MIX_INPUT_4_VOLUME:
+ case MADERA_AIF1TX5MIX_INPUT_1_SOURCE:
+ case MADERA_AIF1TX5MIX_INPUT_1_VOLUME:
+ case MADERA_AIF1TX5MIX_INPUT_2_SOURCE:
+ case MADERA_AIF1TX5MIX_INPUT_2_VOLUME:
+ case MADERA_AIF1TX5MIX_INPUT_3_SOURCE:
+ case MADERA_AIF1TX5MIX_INPUT_3_VOLUME:
+ case MADERA_AIF1TX5MIX_INPUT_4_SOURCE:
+ case MADERA_AIF1TX5MIX_INPUT_4_VOLUME:
+ case MADERA_AIF1TX6MIX_INPUT_1_SOURCE:
+ case MADERA_AIF1TX6MIX_INPUT_1_VOLUME:
+ case MADERA_AIF1TX6MIX_INPUT_2_SOURCE:
+ case MADERA_AIF1TX6MIX_INPUT_2_VOLUME:
+ case MADERA_AIF1TX6MIX_INPUT_3_SOURCE:
+ case MADERA_AIF1TX6MIX_INPUT_3_VOLUME:
+ case MADERA_AIF1TX6MIX_INPUT_4_SOURCE:
+ case MADERA_AIF1TX6MIX_INPUT_4_VOLUME:
+ case MADERA_AIF2TX1MIX_INPUT_1_SOURCE:
+ case MADERA_AIF2TX1MIX_INPUT_1_VOLUME:
+ case MADERA_AIF2TX1MIX_INPUT_2_SOURCE:
+ case MADERA_AIF2TX1MIX_INPUT_2_VOLUME:
+ case MADERA_AIF2TX1MIX_INPUT_3_SOURCE:
+ case MADERA_AIF2TX1MIX_INPUT_3_VOLUME:
+ case MADERA_AIF2TX1MIX_INPUT_4_SOURCE:
+ case MADERA_AIF2TX1MIX_INPUT_4_VOLUME:
+ case MADERA_AIF2TX2MIX_INPUT_1_SOURCE:
+ case MADERA_AIF2TX2MIX_INPUT_1_VOLUME:
+ case MADERA_AIF2TX2MIX_INPUT_2_SOURCE:
+ case MADERA_AIF2TX2MIX_INPUT_2_VOLUME:
+ case MADERA_AIF2TX2MIX_INPUT_3_SOURCE:
+ case MADERA_AIF2TX2MIX_INPUT_3_VOLUME:
+ case MADERA_AIF2TX2MIX_INPUT_4_SOURCE:
+ case MADERA_AIF2TX2MIX_INPUT_4_VOLUME:
+ case MADERA_AIF2TX3MIX_INPUT_1_SOURCE:
+ case MADERA_AIF2TX3MIX_INPUT_1_VOLUME:
+ case MADERA_AIF2TX3MIX_INPUT_2_SOURCE:
+ case MADERA_AIF2TX3MIX_INPUT_2_VOLUME:
+ case MADERA_AIF2TX3MIX_INPUT_3_SOURCE:
+ case MADERA_AIF2TX3MIX_INPUT_3_VOLUME:
+ case MADERA_AIF2TX3MIX_INPUT_4_SOURCE:
+ case MADERA_AIF2TX3MIX_INPUT_4_VOLUME:
+ case MADERA_AIF2TX4MIX_INPUT_1_SOURCE:
+ case MADERA_AIF2TX4MIX_INPUT_1_VOLUME:
+ case MADERA_AIF2TX4MIX_INPUT_2_SOURCE:
+ case MADERA_AIF2TX4MIX_INPUT_2_VOLUME:
+ case MADERA_AIF2TX4MIX_INPUT_3_SOURCE:
+ case MADERA_AIF2TX4MIX_INPUT_3_VOLUME:
+ case MADERA_AIF2TX4MIX_INPUT_4_SOURCE:
+ case MADERA_AIF2TX4MIX_INPUT_4_VOLUME:
+ case MADERA_AIF3TX1MIX_INPUT_1_SOURCE:
+ case MADERA_AIF3TX1MIX_INPUT_1_VOLUME:
+ case MADERA_AIF3TX1MIX_INPUT_2_SOURCE:
+ case MADERA_AIF3TX1MIX_INPUT_2_VOLUME:
+ case MADERA_AIF3TX1MIX_INPUT_3_SOURCE:
+ case MADERA_AIF3TX1MIX_INPUT_3_VOLUME:
+ case MADERA_AIF3TX1MIX_INPUT_4_SOURCE:
+ case MADERA_AIF3TX1MIX_INPUT_4_VOLUME:
+ case MADERA_AIF3TX2MIX_INPUT_1_SOURCE:
+ case MADERA_AIF3TX2MIX_INPUT_1_VOLUME:
+ case MADERA_AIF3TX2MIX_INPUT_2_SOURCE:
+ case MADERA_AIF3TX2MIX_INPUT_2_VOLUME:
+ case MADERA_AIF3TX2MIX_INPUT_3_SOURCE:
+ case MADERA_AIF3TX2MIX_INPUT_3_VOLUME:
+ case MADERA_AIF3TX2MIX_INPUT_4_SOURCE:
+ case MADERA_AIF3TX2MIX_INPUT_4_VOLUME:
+ case MADERA_SPDIF1TX1MIX_INPUT_1_SOURCE:
+ case MADERA_SPDIF1TX1MIX_INPUT_1_VOLUME:
+ case MADERA_SPDIF1TX2MIX_INPUT_1_SOURCE:
+ case MADERA_SPDIF1TX2MIX_INPUT_1_VOLUME:
+ case MADERA_EQ1MIX_INPUT_1_SOURCE:
+ case MADERA_EQ1MIX_INPUT_1_VOLUME:
+ case MADERA_EQ1MIX_INPUT_2_SOURCE:
+ case MADERA_EQ1MIX_INPUT_2_VOLUME:
+ case MADERA_EQ1MIX_INPUT_3_SOURCE:
+ case MADERA_EQ1MIX_INPUT_3_VOLUME:
+ case MADERA_EQ1MIX_INPUT_4_SOURCE:
+ case MADERA_EQ1MIX_INPUT_4_VOLUME:
+ case MADERA_EQ2MIX_INPUT_1_SOURCE:
+ case MADERA_EQ2MIX_INPUT_1_VOLUME:
+ case MADERA_EQ2MIX_INPUT_2_SOURCE:
+ case MADERA_EQ2MIX_INPUT_2_VOLUME:
+ case MADERA_EQ2MIX_INPUT_3_SOURCE:
+ case MADERA_EQ2MIX_INPUT_3_VOLUME:
+ case MADERA_EQ2MIX_INPUT_4_SOURCE:
+ case MADERA_EQ2MIX_INPUT_4_VOLUME:
+ case MADERA_EQ3MIX_INPUT_1_SOURCE:
+ case MADERA_EQ3MIX_INPUT_1_VOLUME:
+ case MADERA_EQ3MIX_INPUT_2_SOURCE:
+ case MADERA_EQ3MIX_INPUT_2_VOLUME:
+ case MADERA_EQ3MIX_INPUT_3_SOURCE:
+ case MADERA_EQ3MIX_INPUT_3_VOLUME:
+ case MADERA_EQ3MIX_INPUT_4_SOURCE:
+ case MADERA_EQ3MIX_INPUT_4_VOLUME:
+ case MADERA_EQ4MIX_INPUT_1_SOURCE:
+ case MADERA_EQ4MIX_INPUT_1_VOLUME:
+ case MADERA_EQ4MIX_INPUT_2_SOURCE:
+ case MADERA_EQ4MIX_INPUT_2_VOLUME:
+ case MADERA_EQ4MIX_INPUT_3_SOURCE:
+ case MADERA_EQ4MIX_INPUT_3_VOLUME:
+ case MADERA_EQ4MIX_INPUT_4_SOURCE:
+ case MADERA_EQ4MIX_INPUT_4_VOLUME:
+ case MADERA_DRC1LMIX_INPUT_1_SOURCE:
+ case MADERA_DRC1LMIX_INPUT_1_VOLUME:
+ case MADERA_DRC1LMIX_INPUT_2_SOURCE:
+ case MADERA_DRC1LMIX_INPUT_2_VOLUME:
+ case MADERA_DRC1LMIX_INPUT_3_SOURCE:
+ case MADERA_DRC1LMIX_INPUT_3_VOLUME:
+ case MADERA_DRC1LMIX_INPUT_4_SOURCE:
+ case MADERA_DRC1LMIX_INPUT_4_VOLUME:
+ case MADERA_DRC1RMIX_INPUT_1_SOURCE:
+ case MADERA_DRC1RMIX_INPUT_1_VOLUME:
+ case MADERA_DRC1RMIX_INPUT_2_SOURCE:
+ case MADERA_DRC1RMIX_INPUT_2_VOLUME:
+ case MADERA_DRC1RMIX_INPUT_3_SOURCE:
+ case MADERA_DRC1RMIX_INPUT_3_VOLUME:
+ case MADERA_DRC1RMIX_INPUT_4_SOURCE:
+ case MADERA_DRC1RMIX_INPUT_4_VOLUME:
+ case MADERA_DRC2LMIX_INPUT_1_SOURCE:
+ case MADERA_DRC2LMIX_INPUT_1_VOLUME:
+ case MADERA_DRC2LMIX_INPUT_2_SOURCE:
+ case MADERA_DRC2LMIX_INPUT_2_VOLUME:
+ case MADERA_DRC2LMIX_INPUT_3_SOURCE:
+ case MADERA_DRC2LMIX_INPUT_3_VOLUME:
+ case MADERA_DRC2LMIX_INPUT_4_SOURCE:
+ case MADERA_DRC2LMIX_INPUT_4_VOLUME:
+ case MADERA_DRC2RMIX_INPUT_1_SOURCE:
+ case MADERA_DRC2RMIX_INPUT_1_VOLUME:
+ case MADERA_DRC2RMIX_INPUT_2_SOURCE:
+ case MADERA_DRC2RMIX_INPUT_2_VOLUME:
+ case MADERA_DRC2RMIX_INPUT_3_SOURCE:
+ case MADERA_DRC2RMIX_INPUT_3_VOLUME:
+ case MADERA_DRC2RMIX_INPUT_4_SOURCE:
+ case MADERA_DRC2RMIX_INPUT_4_VOLUME:
+ case MADERA_HPLP1MIX_INPUT_1_SOURCE:
+ case MADERA_HPLP1MIX_INPUT_1_VOLUME:
+ case MADERA_HPLP1MIX_INPUT_2_SOURCE:
+ case MADERA_HPLP1MIX_INPUT_2_VOLUME:
+ case MADERA_HPLP1MIX_INPUT_3_SOURCE:
+ case MADERA_HPLP1MIX_INPUT_3_VOLUME:
+ case MADERA_HPLP1MIX_INPUT_4_SOURCE:
+ case MADERA_HPLP1MIX_INPUT_4_VOLUME:
+ case MADERA_HPLP2MIX_INPUT_1_SOURCE:
+ case MADERA_HPLP2MIX_INPUT_1_VOLUME:
+ case MADERA_HPLP2MIX_INPUT_2_SOURCE:
+ case MADERA_HPLP2MIX_INPUT_2_VOLUME:
+ case MADERA_HPLP2MIX_INPUT_3_SOURCE:
+ case MADERA_HPLP2MIX_INPUT_3_VOLUME:
+ case MADERA_HPLP2MIX_INPUT_4_SOURCE:
+ case MADERA_HPLP2MIX_INPUT_4_VOLUME:
+ case MADERA_HPLP3MIX_INPUT_1_SOURCE:
+ case MADERA_HPLP3MIX_INPUT_1_VOLUME:
+ case MADERA_HPLP3MIX_INPUT_2_SOURCE:
+ case MADERA_HPLP3MIX_INPUT_2_VOLUME:
+ case MADERA_HPLP3MIX_INPUT_3_SOURCE:
+ case MADERA_HPLP3MIX_INPUT_3_VOLUME:
+ case MADERA_HPLP3MIX_INPUT_4_SOURCE:
+ case MADERA_HPLP3MIX_INPUT_4_VOLUME:
+ case MADERA_HPLP4MIX_INPUT_1_SOURCE:
+ case MADERA_HPLP4MIX_INPUT_1_VOLUME:
+ case MADERA_HPLP4MIX_INPUT_2_SOURCE:
+ case MADERA_HPLP4MIX_INPUT_2_VOLUME:
+ case MADERA_HPLP4MIX_INPUT_3_SOURCE:
+ case MADERA_HPLP4MIX_INPUT_3_VOLUME:
+ case MADERA_HPLP4MIX_INPUT_4_SOURCE:
+ case MADERA_HPLP4MIX_INPUT_4_VOLUME:
+ case MADERA_DSP1LMIX_INPUT_1_SOURCE:
+ case MADERA_DSP1LMIX_INPUT_1_VOLUME:
+ case MADERA_DSP1LMIX_INPUT_2_SOURCE:
+ case MADERA_DSP1LMIX_INPUT_2_VOLUME:
+ case MADERA_DSP1LMIX_INPUT_3_SOURCE:
+ case MADERA_DSP1LMIX_INPUT_3_VOLUME:
+ case MADERA_DSP1LMIX_INPUT_4_SOURCE:
+ case MADERA_DSP1LMIX_INPUT_4_VOLUME:
+ case MADERA_DSP1RMIX_INPUT_1_SOURCE:
+ case MADERA_DSP1RMIX_INPUT_1_VOLUME:
+ case MADERA_DSP1RMIX_INPUT_2_SOURCE:
+ case MADERA_DSP1RMIX_INPUT_2_VOLUME:
+ case MADERA_DSP1RMIX_INPUT_3_SOURCE:
+ case MADERA_DSP1RMIX_INPUT_3_VOLUME:
+ case MADERA_DSP1RMIX_INPUT_4_SOURCE:
+ case MADERA_DSP1RMIX_INPUT_4_VOLUME:
+ case MADERA_DSP1AUX1MIX_INPUT_1_SOURCE:
+ case MADERA_DSP1AUX2MIX_INPUT_1_SOURCE:
+ case MADERA_DSP1AUX3MIX_INPUT_1_SOURCE:
+ case MADERA_DSP1AUX4MIX_INPUT_1_SOURCE:
+ case MADERA_DSP1AUX5MIX_INPUT_1_SOURCE:
+ case MADERA_DSP1AUX6MIX_INPUT_1_SOURCE:
+ case MADERA_ISRC1DEC1MIX_INPUT_1_SOURCE:
+ case MADERA_ISRC1DEC2MIX_INPUT_1_SOURCE:
+ case MADERA_ISRC1DEC3MIX_INPUT_1_SOURCE:
+ case MADERA_ISRC1DEC4MIX_INPUT_1_SOURCE:
+ case MADERA_ISRC1INT1MIX_INPUT_1_SOURCE:
+ case MADERA_ISRC1INT2MIX_INPUT_1_SOURCE:
+ case MADERA_ISRC1INT3MIX_INPUT_1_SOURCE:
+ case MADERA_ISRC1INT4MIX_INPUT_1_SOURCE:
+ case MADERA_ISRC2DEC1MIX_INPUT_1_SOURCE:
+ case MADERA_ISRC2DEC2MIX_INPUT_1_SOURCE:
+ case MADERA_ISRC2DEC3MIX_INPUT_1_SOURCE:
+ case MADERA_ISRC2DEC4MIX_INPUT_1_SOURCE:
+ case MADERA_ISRC2INT1MIX_INPUT_1_SOURCE:
+ case MADERA_ISRC2INT2MIX_INPUT_1_SOURCE:
+ case MADERA_ISRC2INT3MIX_INPUT_1_SOURCE:
+ case MADERA_ISRC2INT4MIX_INPUT_1_SOURCE:
+ case MADERA_FX_CTRL1 ... MADERA_FX_CTRL2:
+ case MADERA_EQ1_1 ... MADERA_EQ1_21:
+ case MADERA_EQ2_1 ... MADERA_EQ2_21:
+ case MADERA_EQ3_1 ... MADERA_EQ3_21:
+ case MADERA_EQ4_1 ... MADERA_EQ4_21:
+ case MADERA_DRC1_CTRL1 ... MADERA_DRC1_CTRL5:
+ case MADERA_DRC2_CTRL1 ... MADERA_DRC2_CTRL5:
+ case MADERA_HPLPF1_1 ... MADERA_HPLPF1_2:
+ case MADERA_HPLPF2_1 ... MADERA_HPLPF2_2:
+ case MADERA_HPLPF3_1 ... MADERA_HPLPF3_2:
+ case MADERA_HPLPF4_1 ... MADERA_HPLPF4_2:
+ case MADERA_ISRC_1_CTRL_1 ... MADERA_ISRC_1_CTRL_3:
+ case MADERA_ISRC_2_CTRL_1 ... MADERA_ISRC_2_CTRL_3:
+ case MADERA_GPIO1_CTRL_1 ... MADERA_GPIO15_CTRL_2:
+ case MADERA_IRQ1_STATUS_1 ... MADERA_IRQ1_STATUS_33:
+ case MADERA_IRQ1_MASK_1 ... MADERA_IRQ1_MASK_33:
+ case MADERA_IRQ1_RAW_STATUS_1 ... MADERA_IRQ1_RAW_STATUS_33:
+ case MADERA_INTERRUPT_DEBOUNCE_7:
+ case MADERA_IRQ1_CTRL:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool cs47l15_16bit_volatile_register(struct device *dev,
+ unsigned int reg)
+{
+ switch (reg) {
+ case MADERA_SOFTWARE_RESET:
+ case MADERA_HARDWARE_REVISION:
+ case MADERA_WRITE_SEQUENCER_CTRL_0 ... MADERA_WRITE_SEQUENCER_CTRL_2:
+ case MADERA_HAPTICS_STATUS:
+ case MADERA_SAMPLE_RATE_1_STATUS:
+ case MADERA_SAMPLE_RATE_2_STATUS:
+ case MADERA_SAMPLE_RATE_3_STATUS:
+ case MADERA_HP_CTRL_1L:
+ case MADERA_HP_CTRL_1R:
+ case MADERA_MIC_DETECT_1_CONTROL_3:
+ case MADERA_MIC_DETECT_1_CONTROL_4:
+ case MADERA_HEADPHONE_DETECT_2:
+ case MADERA_HEADPHONE_DETECT_3:
+ case MADERA_HEADPHONE_DETECT_5:
+ case MADERA_INPUT_ENABLES_STATUS:
+ case MADERA_OUTPUT_STATUS_1:
+ case MADERA_RAW_OUTPUT_STATUS_1:
+ case MADERA_SPD1_TX_CHANNEL_STATUS_1:
+ case MADERA_SPD1_TX_CHANNEL_STATUS_2:
+ case MADERA_SPD1_TX_CHANNEL_STATUS_3:
+ case MADERA_FX_CTRL2:
+ case MADERA_IRQ1_STATUS_1 ... MADERA_IRQ1_STATUS_33:
+ case MADERA_IRQ1_RAW_STATUS_1 ... MADERA_IRQ1_RAW_STATUS_33:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool cs47l15_32bit_readable_register(struct device *dev,
+ unsigned int reg)
+{
+ switch (reg) {
+ case MADERA_WSEQ_SEQUENCE_1 ... MADERA_WSEQ_SEQUENCE_225:
+ case MADERA_OTP_HPDET_CAL_1 ... MADERA_OTP_HPDET_CAL_2:
+ case MADERA_DSP1_CONFIG_1 ... MADERA_DSP1_PMEM_ERR_ADDR___XMEM_ERR_ADDR:
+ return true;
+ default:
+ return cs47l15_is_adsp_memory(dev, reg);
+ }
+}
+
+static bool cs47l15_32bit_volatile_register(struct device *dev,
+ unsigned int reg)
+{
+ switch (reg) {
+ case MADERA_WSEQ_SEQUENCE_1 ... MADERA_WSEQ_SEQUENCE_225:
+ case MADERA_OTP_HPDET_CAL_1 ... MADERA_OTP_HPDET_CAL_2:
+ case MADERA_DSP1_CONFIG_1 ... MADERA_DSP1_PMEM_ERR_ADDR___XMEM_ERR_ADDR:
+ return true;
+ default:
+ return cs47l15_is_adsp_memory(dev, reg);
+ }
+}
+
+const struct regmap_config cs47l15_16bit_spi_regmap = {
+ .name = "cs47l15_16bit",
+ .reg_bits = 32,
+ .pad_bits = 16,
+ .val_bits = 16,
+
+ .max_register = MADERA_INTERRUPT_RAW_STATUS_1,
+ .readable_reg = &cs47l15_16bit_readable_register,
+ .volatile_reg = &cs47l15_16bit_volatile_register,
+
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = cs47l15_reg_default,
+ .num_reg_defaults = ARRAY_SIZE(cs47l15_reg_default),
+};
+EXPORT_SYMBOL_GPL(cs47l15_16bit_spi_regmap);
+
+const struct regmap_config cs47l15_16bit_i2c_regmap = {
+ .name = "cs47l15_16bit",
+ .reg_bits = 32,
+ .val_bits = 16,
+
+ .max_register = MADERA_INTERRUPT_RAW_STATUS_1,
+ .readable_reg = &cs47l15_16bit_readable_register,
+ .volatile_reg = &cs47l15_16bit_volatile_register,
+
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = cs47l15_reg_default,
+ .num_reg_defaults = ARRAY_SIZE(cs47l15_reg_default),
+};
+EXPORT_SYMBOL_GPL(cs47l15_16bit_i2c_regmap);
+
+const struct regmap_config cs47l15_32bit_spi_regmap = {
+ .name = "cs47l15_32bit",
+ .reg_bits = 32,
+ .reg_stride = 2,
+ .pad_bits = 16,
+ .val_bits = 32,
+
+ .max_register = MADERA_DSP1_PMEM_ERR_ADDR___XMEM_ERR_ADDR,
+ .readable_reg = &cs47l15_32bit_readable_register,
+ .volatile_reg = &cs47l15_32bit_volatile_register,
+
+ .cache_type = REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL_GPL(cs47l15_32bit_spi_regmap);
+
+const struct regmap_config cs47l15_32bit_i2c_regmap = {
+ .name = "cs47l15_32bit",
+ .reg_bits = 32,
+ .reg_stride = 2,
+ .val_bits = 32,
+
+ .max_register = MADERA_DSP1_PMEM_ERR_ADDR___XMEM_ERR_ADDR,
+ .readable_reg = &cs47l15_32bit_readable_register,
+ .volatile_reg = &cs47l15_32bit_volatile_register,
+
+ .cache_type = REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL_GPL(cs47l15_32bit_i2c_regmap);
diff --git a/drivers/mfd/cs47l24-tables.c b/drivers/mfd/cs47l24-tables.c
index c090974340ad..c289d92a5c1d 100644
--- a/drivers/mfd/cs47l24-tables.c
+++ b/drivers/mfd/cs47l24-tables.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Data tables for CS47L24 codec
*
* Copyright 2015 Cirrus Logic, Inc.
*
* Author: Richard Fitzgerald <rf@opensource.wolfsonmicro.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/mfd/cs47l35-tables.c b/drivers/mfd/cs47l35-tables.c
index 338b825127f1..a0bc6c5100d6 100644
--- a/drivers/mfd/cs47l35-tables.c
+++ b/drivers/mfd/cs47l35-tables.c
@@ -1,12 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Regmap tables for CS47L35 codec
*
* Copyright (C) 2015-2017 Cirrus Logic
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by the
- * Free Software Foundation; version 2.
*/
#include <linux/device.h>
@@ -109,9 +105,8 @@ static const struct reg_default cs47l35_reg_default[] = {
{ 0x00000174, 0x007d }, /* R372 (0x174) - FLL1 Control 4 */
{ 0x00000175, 0x0000 }, /* R373 (0x175) - FLL1 Control 5 */
{ 0x00000176, 0x0000 }, /* R374 (0x176) - FLL1 Control 6 */
- { 0x00000177, 0x0281 }, /* R375 (0x177) - FLL1 Loop Filter Test 1 */
{ 0x00000179, 0x0000 }, /* R377 (0x179) - FLL1 Control 7 */
- { 0x0000017a, 0x0b06 }, /* R378 (0x17a) - FLL1 EFS2 */
+ { 0x0000017a, 0x2906 }, /* R378 (0x17a) - FLL1 EFS2 */
{ 0x0000017f, 0x0000 }, /* R383 (0x17f) - FLL1 Synchroniser 1 */
{ 0x00000180, 0x0000 }, /* R384 (0x180) - FLL1 Synchroniser 2 */
{ 0x00000181, 0x0000 }, /* R385 (0x181) - FLL1 Synchroniser 3 */
@@ -174,9 +169,6 @@ static const struct reg_default cs47l35_reg_default[] = {
{ 0x00000434, 0x0000 }, /* R1076 (0x434) - Output Path Config 5R */
{ 0x00000435, 0x0180 }, /* R1077 (0x435) - DAC Digital Volume 5R */
{ 0x00000437, 0x0200 }, /* R1079 (0x437) - Noise Gate Select 5R */
- { 0x00000440, 0x0003 }, /* R1088 (0x440) - DRE Enable */
- { 0x00000448, 0x0a83 }, /* R1096 (0x448) - eDRE Enable */
- { 0x0000044a, 0x0000 }, /* R1098 (0x44a) - eDRE Manual */
{ 0x00000450, 0x0000 }, /* R1104 (0x450) - DAC AEC Control 1 */
{ 0x00000451, 0x0000 }, /* R1105 (0x451) - DAC AEC Control 2 */
{ 0x00000458, 0x0000 }, /* R1112 (0x458) - Noise Gate Control */
@@ -720,28 +712,6 @@ static const struct reg_default cs47l35_reg_default[] = {
{ 0x00000ef3, 0x0000 }, /* R3827 (0xef3) - ISRC 2 CTRL 1 */
{ 0x00000ef4, 0x0001 }, /* R3828 (0xef4) - ISRC 2 CTRL 2 */
{ 0x00000ef5, 0x0000 }, /* R3829 (0xef5) - ISRC 2 CTRL 3 */
- { 0x00001300, 0x0000 }, /* R4864 (0x1300) - DAC Comp 1 */
- { 0x00001302, 0x0000 }, /* R4866 (0x1302) - DAC Comp 2 */
- { 0x00001380, 0x0000 }, /* R4992 (0x1380) - FRF Coefficient 1L 1 */
- { 0x00001381, 0x0000 }, /* R4993 (0x1381) - FRF Coefficient 1L 2 */
- { 0x00001382, 0x0000 }, /* R4994 (0x1382) - FRF Coefficient 1L 3 */
- { 0x00001383, 0x0000 }, /* R4995 (0x1383) - FRF Coefficient 1L 4 */
- { 0x00001390, 0x0000 }, /* R5008 (0x1390) - FRF Coefficient 1R 1 */
- { 0x00001391, 0x0000 }, /* R5009 (0x1391) - FRF Coefficient 1R 2 */
- { 0x00001392, 0x0000 }, /* R5010 (0x1392) - FRF Coefficient 1R 3 */
- { 0x00001393, 0x0000 }, /* R5011 (0x1393) - FRF Coefficient 1R 4 */
- { 0x000013a0, 0x0000 }, /* R5024 (0x13a0) - FRF Coefficient 4L 1 */
- { 0x000013a1, 0x0000 }, /* R5025 (0x13a1) - FRF Coefficient 4L 2 */
- { 0x000013a2, 0x0000 }, /* R5026 (0x13a2) - FRF Coefficient 4L 3 */
- { 0x000013a3, 0x0000 }, /* R5027 (0x13a3) - FRF Coefficient 4L 4 */
- { 0x000013b0, 0x0000 }, /* R5040 (0x13b0) - FRF Coefficient 5L 1 */
- { 0x000013b1, 0x0000 }, /* R5041 (0x13b1) - FRF Coefficient 5L 2 */
- { 0x000013b2, 0x0000 }, /* R5042 (0x13b2) - FRF Coefficient 5L 3 */
- { 0x000013b3, 0x0000 }, /* R5043 (0x13b3) - FRF Coefficient 5L 4 */
- { 0x000013c0, 0x0000 }, /* R5040 (0x13c0) - FRF Coefficient 5R 1 */
- { 0x000013c1, 0x0000 }, /* R5041 (0x13c1) - FRF Coefficient 5R 2 */
- { 0x000013c2, 0x0000 }, /* R5042 (0x13c2) - FRF Coefficient 5R 3 */
- { 0x000013c3, 0x0000 }, /* R5043 (0x13c3) - FRF Coefficient 5R 4 */
{ 0x00001700, 0x2001 }, /* R5888 (0x1700) - GPIO1 Control 1 */
{ 0x00001701, 0xf000 }, /* R5889 (0x1701) - GPIO1 Control 2 */
{ 0x00001702, 0x2001 }, /* R5890 (0x1702) - GPIO2 Control 1 */
@@ -892,7 +862,6 @@ static bool cs47l35_16bit_readable_register(struct device *dev,
case MADERA_FLL1_CONTROL_6:
case MADERA_FLL1_CONTROL_7:
case MADERA_FLL1_EFS_2:
- case MADERA_FLL1_LOOP_FILTER_TEST_1:
case CS47L35_FLL1_SYNCHRONISER_1:
case CS47L35_FLL1_SYNCHRONISER_2:
case CS47L35_FLL1_SYNCHRONISER_3:
@@ -967,9 +936,6 @@ static bool cs47l35_16bit_readable_register(struct device *dev,
case MADERA_OUTPUT_PATH_CONFIG_5R:
case MADERA_DAC_DIGITAL_VOLUME_5R:
case MADERA_NOISE_GATE_SELECT_5R:
- case MADERA_DRE_ENABLE:
- case MADERA_EDRE_ENABLE:
- case MADERA_EDRE_MANUAL:
case MADERA_DAC_AEC_CONTROL_1:
case MADERA_DAC_AEC_CONTROL_2:
case MADERA_NOISE_GATE_CONTROL:
@@ -1439,28 +1405,6 @@ static bool cs47l35_16bit_readable_register(struct device *dev,
case MADERA_ISRC_2_CTRL_1:
case MADERA_ISRC_2_CTRL_2:
case MADERA_ISRC_2_CTRL_3:
- case MADERA_DAC_COMP_1:
- case MADERA_DAC_COMP_2:
- case MADERA_FRF_COEFFICIENT_1L_1:
- case MADERA_FRF_COEFFICIENT_1L_2:
- case MADERA_FRF_COEFFICIENT_1L_3:
- case MADERA_FRF_COEFFICIENT_1L_4:
- case MADERA_FRF_COEFFICIENT_1R_1:
- case MADERA_FRF_COEFFICIENT_1R_2:
- case MADERA_FRF_COEFFICIENT_1R_3:
- case MADERA_FRF_COEFFICIENT_1R_4:
- case CS47L35_FRF_COEFFICIENT_4L_1:
- case CS47L35_FRF_COEFFICIENT_4L_2:
- case CS47L35_FRF_COEFFICIENT_4L_3:
- case CS47L35_FRF_COEFFICIENT_4L_4:
- case CS47L35_FRF_COEFFICIENT_5L_1:
- case CS47L35_FRF_COEFFICIENT_5L_2:
- case CS47L35_FRF_COEFFICIENT_5L_3:
- case CS47L35_FRF_COEFFICIENT_5L_4:
- case CS47L35_FRF_COEFFICIENT_5R_1:
- case CS47L35_FRF_COEFFICIENT_5R_2:
- case CS47L35_FRF_COEFFICIENT_5R_3:
- case CS47L35_FRF_COEFFICIENT_5R_4:
case MADERA_GPIO1_CTRL_1 ... MADERA_GPIO16_CTRL_2:
case MADERA_IRQ1_STATUS_1 ... MADERA_IRQ1_STATUS_33:
case MADERA_IRQ1_MASK_1 ... MADERA_IRQ1_MASK_33:
diff --git a/drivers/mfd/cs47l85-tables.c b/drivers/mfd/cs47l85-tables.c
index 43803145d8e5..270d8eda3f5f 100644
--- a/drivers/mfd/cs47l85-tables.c
+++ b/drivers/mfd/cs47l85-tables.c
@@ -1,12 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Regmap tables for CS47L85 codec
*
* Copyright (C) 2015-2017 Cirrus Logic
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by the
- * Free Software Foundation; version 2.
*/
#include <linux/device.h>
@@ -402,7 +398,6 @@ static const struct reg_default cs47l85_reg_default[] = {
{ 0x00000174, 0x007d }, /* R372 (0x174) - FLL1 Control 4 */
{ 0x00000175, 0x0000 }, /* R373 (0x175) - FLL1 Control 5 */
{ 0x00000176, 0x0000 }, /* R374 (0x176) - FLL1 Control 6 */
- { 0x00000177, 0x0281 }, /* R375 (0x177) - FLL1 Loop Filter Test 1 */
{ 0x00000179, 0x0000 }, /* R377 (0x179) - FLL1 Control 7 */
{ 0x00000181, 0x0000 }, /* R385 (0x181) - FLL1 Synchroniser 1 */
{ 0x00000182, 0x0000 }, /* R386 (0x182) - FLL1 Synchroniser 2 */
@@ -419,7 +414,6 @@ static const struct reg_default cs47l85_reg_default[] = {
{ 0x00000194, 0x007d }, /* R404 (0x194) - FLL2 Control 4 */
{ 0x00000195, 0x0000 }, /* R405 (0x195) - FLL2 Control 5 */
{ 0x00000196, 0x0000 }, /* R406 (0x196) - FLL2 Control 6 */
- { 0x00000197, 0x0281 }, /* R407 (0x197) - FLL2 Loop Filter Test 1 */
{ 0x00000199, 0x0000 }, /* R409 (0x199) - FLL2 Control 7 */
{ 0x000001a1, 0x0000 }, /* R417 (0x1a1) - FLL2 Synchroniser 1 */
{ 0x000001a2, 0x0000 }, /* R418 (0x1a2) - FLL2 Synchroniser 2 */
@@ -436,7 +430,6 @@ static const struct reg_default cs47l85_reg_default[] = {
{ 0x000001b4, 0x007d }, /* R436 (0x1b4) - FLL3 Control 4 */
{ 0x000001b5, 0x0000 }, /* R437 (0x1b5) - FLL3 Control 5 */
{ 0x000001b6, 0x0000 }, /* R438 (0x1b6) - FLL3 Control 6 */
- { 0x000001b7, 0x0281 }, /* R439 (0x1b7) - FLL3 Loop Filter Test 1 */
{ 0x000001b9, 0x0000 }, /* R441 (0x1b9) - FLL3 Control 7 */
{ 0x000001c1, 0x0000 }, /* R449 (0x1c1) - FLL3 Synchroniser 1 */
{ 0x000001c2, 0x0000 }, /* R450 (0x1c2) - FLL3 Synchroniser 2 */
@@ -546,9 +539,6 @@ static const struct reg_default cs47l85_reg_default[] = {
{ 0x0000043c, 0x0000 }, /* R1084 (0x43c) - Output Path Config 6R */
{ 0x0000043d, 0x0180 }, /* R1085 (0x43d) - DAC Digital Volume 6R */
{ 0x0000043f, 0x0800 }, /* R1087 (0x43f) - Noise Gate Select 6R */
- { 0x00000440, 0x003f }, /* R1088 (0x440) - DRE Enable */
- { 0x00000448, 0x003f }, /* R1096 (0x448) - EDRE Enable */
- { 0x0000044a, 0x0000 }, /* R1098 (0x44a) - EDRE Manual */
{ 0x00000450, 0x0000 }, /* R1104 (0x450) - DAC AEC Control 1 */
{ 0x00000451, 0x0000 }, /* R1105 (0x451) - DAC AEC Control 2 */
{ 0x00000458, 0x0000 }, /* R1112 (0x458) - Noise Gate Control */
@@ -556,7 +546,7 @@ static const struct reg_default cs47l85_reg_default[] = {
{ 0x00000491, 0x0000 }, /* R1169 (0x491) - PDM SPK1 CTRL 2 */
{ 0x00000492, 0x0069 }, /* R1170 (0x492) - PDM SPK2 CTRL 1 */
{ 0x00000493, 0x0000 }, /* R1171 (0x493) - PDM SPK2 CTRL 2 */
- { 0x000004a0, 0x3210 }, /* R1184 (0x4a0) - HP1 Short Circuit Ctrl */
+ { 0x000004a0, 0x3280 }, /* R1184 (0x4a0) - HP1 Short Circuit Ctrl */
{ 0x000004a1, 0x3200 }, /* R1185 (0x4a1) - HP2 Short Circuit Ctrl */
{ 0x000004a2, 0x3200 }, /* R1186 (0x4a2) - HP3 Short Circuit Ctrl */
{ 0x000004a8, 0x7020 }, /* R1192 (0x4a8) - HP Test Ctrl 5 */
@@ -1365,11 +1355,11 @@ static const struct reg_default cs47l85_reg_default[] = {
{ 0x00000e82, 0x0018 }, /* R3714 (0xe82) - DRC1 ctrl3 */
{ 0x00000e83, 0x0000 }, /* R3715 (0xe83) - DRC1 ctrl4 */
{ 0x00000e84, 0x0000 }, /* R3716 (0xe84) - DRC1 ctrl5 */
- { 0x00000e88, 0x0933 }, /* R3720 (0xe88) - DRC2 ctrl1 */
- { 0x00000e89, 0x0018 }, /* R3721 (0xe89) - DRC2 ctrl2 */
- { 0x00000e8a, 0x0000 }, /* R3722 (0xe8a) - DRC2 ctrl3 */
+ { 0x00000e88, 0x0018 }, /* R3720 (0xe88) - DRC2 ctrl1 */
+ { 0x00000e89, 0x0933 }, /* R3721 (0xe89) - DRC2 ctrl2 */
+ { 0x00000e8a, 0x0018 }, /* R3722 (0xe8a) - DRC2 ctrl3 */
{ 0x00000e8b, 0x0000 }, /* R3723 (0xe8b) - DRC2 ctrl4 */
- { 0x00000e8c, 0x0040 }, /* R3724 (0xe8c) - DRC2 ctrl5 */
+ { 0x00000e8c, 0x0000 }, /* R3724 (0xe8c) - DRC2 ctrl5 */
{ 0x00000ec0, 0x0000 }, /* R3776 (0xec0) - HPLPF1_1 */
{ 0x00000ec1, 0x0000 }, /* R3777 (0xec1) - HPLPF1_2 */
{ 0x00000ec4, 0x0000 }, /* R3780 (0xec4) - HPLPF2_1 */
@@ -1577,56 +1567,6 @@ static const struct reg_default cs47l85_reg_default[] = {
{ 0x00000fc3, 0x0000 }, /* R4035 (0xfc3) - ANC Coefficient */
{ 0x00000fc4, 0x0000 }, /* R4036 (0xfc4) - ANC Coefficient */
{ 0x00000fc5, 0x0000 }, /* R4037 (0xfc5) - ANC Coefficient */
- { 0x00001300, 0x0000 }, /* R4864 (0x1300) - DAC Comp 1 */
- { 0x00001302, 0x0000 }, /* R4866 (0x1302) - DAC Comp 2 */
- { 0x00001380, 0x0000 }, /* R4992 (0x1380) - FRF Coefficient 1L 1 */
- { 0x00001381, 0x0000 }, /* R4993 (0x1381) - FRF Coefficient 1L 2 */
- { 0x00001382, 0x0000 }, /* R4994 (0x1382) - FRF Coefficient 1L 3 */
- { 0x00001383, 0x0000 }, /* R4995 (0x1383) - FRF Coefficient 1L 4 */
- { 0x00001390, 0x0000 }, /* R5008 (0x1390) - FRF Coefficient 1R 1 */
- { 0x00001391, 0x0000 }, /* R5009 (0x1391) - FRF Coefficient 1R 2 */
- { 0x00001392, 0x0000 }, /* R5010 (0x1392) - FRF Coefficient 1R 3 */
- { 0x00001393, 0x0000 }, /* R5011 (0x1393) - FRF Coefficient 1R 4 */
- { 0x000013a0, 0x0000 }, /* R5024 (0x13a0) - FRF Coefficient 2L 1 */
- { 0x000013a1, 0x0000 }, /* R5025 (0x13a1) - FRF Coefficient 2L 2 */
- { 0x000013a2, 0x0000 }, /* R5026 (0x13a2) - FRF Coefficient 2L 3 */
- { 0x000013a3, 0x0000 }, /* R5027 (0x13a3) - FRF Coefficient 2L 4 */
- { 0x000013b0, 0x0000 }, /* R5040 (0x13b0) - FRF Coefficient 2R 1 */
- { 0x000013b1, 0x0000 }, /* R5041 (0x13b1) - FRF Coefficient 2R 2 */
- { 0x000013b2, 0x0000 }, /* R5042 (0x13b2) - FRF Coefficient 2R 3 */
- { 0x000013b3, 0x0000 }, /* R5043 (0x13b3) - FRF Coefficient 2R 4 */
- { 0x000013c0, 0x0000 }, /* R5040 (0x13c0) - FRF Coefficient 3L 1 */
- { 0x000013c1, 0x0000 }, /* R5041 (0x13c1) - FRF Coefficient 3L 2 */
- { 0x000013c2, 0x0000 }, /* R5042 (0x13c2) - FRF Coefficient 3L 3 */
- { 0x000013c3, 0x0000 }, /* R5043 (0x13c3) - FRF Coefficient 3L 4 */
- { 0x000013d0, 0x0000 }, /* R5072 (0x13d0) - FRF Coefficient 3R 1 */
- { 0x000013d1, 0x0000 }, /* R5073 (0x13d1) - FRF Coefficient 3R 2 */
- { 0x000013d2, 0x0000 }, /* R5074 (0x13d2) - FRF Coefficient 3R 3 */
- { 0x000013d3, 0x0000 }, /* R5075 (0x13d3) - FRF Coefficient 3R 4 */
- { 0x000013e0, 0x0000 }, /* R5088 (0x13e0) - FRF Coefficient 4L 1 */
- { 0x000013e1, 0x0000 }, /* R5089 (0x13e1) - FRF Coefficient 4L 2 */
- { 0x000013e2, 0x0000 }, /* R5090 (0x13e2) - FRF Coefficient 4L 3 */
- { 0x000013e3, 0x0000 }, /* R5091 (0x13e3) - FRF Coefficient 4L 4 */
- { 0x000013f0, 0x0000 }, /* R5104 (0x13f0) - FRF Coefficient 4R 1 */
- { 0x000013f1, 0x0000 }, /* R5105 (0x13f1) - FRF Coefficient 4R 2 */
- { 0x000013f2, 0x0000 }, /* R5106 (0x13f2) - FRF Coefficient 4R 3 */
- { 0x000013f3, 0x0000 }, /* R5107 (0x13f3) - FRF Coefficient 4R 4 */
- { 0x00001400, 0x0000 }, /* R5120 (0x1400) - FRF Coefficient 5L 1 */
- { 0x00001401, 0x0000 }, /* R5121 (0x1401) - FRF Coefficient 5L 2 */
- { 0x00001402, 0x0000 }, /* R5122 (0x1402) - FRF Coefficient 5L 3 */
- { 0x00001403, 0x0000 }, /* R5123 (0x1403) - FRF Coefficient 5L 4 */
- { 0x00001410, 0x0000 }, /* R5136 (0x1410) - FRF Coefficient 5R 1 */
- { 0x00001411, 0x0000 }, /* R5137 (0x1411) - FRF Coefficient 5R 2 */
- { 0x00001412, 0x0000 }, /* R5138 (0x1412) - FRF Coefficient 5R 3 */
- { 0x00001413, 0x0000 }, /* R5139 (0x1413) - FRF Coefficient 5R 4 */
- { 0x00001420, 0x0000 }, /* R5152 (0x1420) - FRF Coefficient 6L 1 */
- { 0x00001421, 0x0000 }, /* R5153 (0x1421) - FRF Coefficient 6L 2 */
- { 0x00001422, 0x0000 }, /* R5154 (0x1422) - FRF Coefficient 6L 3 */
- { 0x00001423, 0x0000 }, /* R5155 (0x1423) - FRF Coefficient 6L 4 */
- { 0x00001430, 0x0000 }, /* R5168 (0x1430) - FRF Coefficient 6R 1 */
- { 0x00001431, 0x0000 }, /* R5169 (0x1431) - FRF Coefficient 6R 2 */
- { 0x00001432, 0x0000 }, /* R5170 (0x1432) - FRF Coefficient 6R 3 */
- { 0x00001433, 0x0000 }, /* R5171 (0x1433) - FRF Coefficient 6R 4 */
{ 0x00001700, 0x2001 }, /* R5888 (0x1700) - GPIO1 Control 1 */
{ 0x00001701, 0xe000 }, /* R5889 (0x1701) - GPIO1 Control 2 */
{ 0x00001702, 0x2001 }, /* R5890 (0x1702) - GPIO2 Control 1 */
@@ -1845,7 +1785,6 @@ static bool cs47l85_16bit_readable_register(struct device *dev,
case MADERA_FLL1_CONTROL_5:
case MADERA_FLL1_CONTROL_6:
case MADERA_FLL1_CONTROL_7:
- case MADERA_FLL1_LOOP_FILTER_TEST_1:
case MADERA_FLL1_SYNCHRONISER_1:
case MADERA_FLL1_SYNCHRONISER_2:
case MADERA_FLL1_SYNCHRONISER_3:
@@ -1862,7 +1801,6 @@ static bool cs47l85_16bit_readable_register(struct device *dev,
case MADERA_FLL2_CONTROL_5:
case MADERA_FLL2_CONTROL_6:
case MADERA_FLL2_CONTROL_7:
- case MADERA_FLL2_LOOP_FILTER_TEST_1:
case MADERA_FLL2_SYNCHRONISER_1:
case MADERA_FLL2_SYNCHRONISER_2:
case MADERA_FLL2_SYNCHRONISER_3:
@@ -1879,7 +1817,6 @@ static bool cs47l85_16bit_readable_register(struct device *dev,
case MADERA_FLL3_CONTROL_5:
case MADERA_FLL3_CONTROL_6:
case MADERA_FLL3_CONTROL_7:
- case MADERA_FLL3_LOOP_FILTER_TEST_1:
case MADERA_FLL3_SYNCHRONISER_1:
case MADERA_FLL3_SYNCHRONISER_2:
case MADERA_FLL3_SYNCHRONISER_3:
@@ -2004,9 +1941,6 @@ static bool cs47l85_16bit_readable_register(struct device *dev,
case MADERA_OUTPUT_PATH_CONFIG_6R:
case MADERA_DAC_DIGITAL_VOLUME_6R:
case MADERA_NOISE_GATE_SELECT_6R:
- case MADERA_DRE_ENABLE:
- case MADERA_EDRE_ENABLE:
- case MADERA_EDRE_MANUAL:
case MADERA_DAC_AEC_CONTROL_1:
case MADERA_DAC_AEC_CONTROL_2:
case MADERA_NOISE_GATE_CONTROL:
@@ -2792,56 +2726,6 @@ static bool cs47l85_16bit_readable_register(struct device *dev,
case MADERA_FCR_FILTER_CONTROL:
case MADERA_FCR_ADC_REFORMATTER_CONTROL:
case MADERA_FCR_COEFF_START ... MADERA_FCR_COEFF_END:
- case MADERA_DAC_COMP_1:
- case MADERA_DAC_COMP_2:
- case MADERA_FRF_COEFFICIENT_1L_1:
- case MADERA_FRF_COEFFICIENT_1L_2:
- case MADERA_FRF_COEFFICIENT_1L_3:
- case MADERA_FRF_COEFFICIENT_1L_4:
- case MADERA_FRF_COEFFICIENT_1R_1:
- case MADERA_FRF_COEFFICIENT_1R_2:
- case MADERA_FRF_COEFFICIENT_1R_3:
- case MADERA_FRF_COEFFICIENT_1R_4:
- case MADERA_FRF_COEFFICIENT_2L_1:
- case MADERA_FRF_COEFFICIENT_2L_2:
- case MADERA_FRF_COEFFICIENT_2L_3:
- case MADERA_FRF_COEFFICIENT_2L_4:
- case MADERA_FRF_COEFFICIENT_2R_1:
- case MADERA_FRF_COEFFICIENT_2R_2:
- case MADERA_FRF_COEFFICIENT_2R_3:
- case MADERA_FRF_COEFFICIENT_2R_4:
- case MADERA_FRF_COEFFICIENT_3L_1:
- case MADERA_FRF_COEFFICIENT_3L_2:
- case MADERA_FRF_COEFFICIENT_3L_3:
- case MADERA_FRF_COEFFICIENT_3L_4:
- case MADERA_FRF_COEFFICIENT_3R_1:
- case MADERA_FRF_COEFFICIENT_3R_2:
- case MADERA_FRF_COEFFICIENT_3R_3:
- case MADERA_FRF_COEFFICIENT_3R_4:
- case MADERA_FRF_COEFFICIENT_4L_1:
- case MADERA_FRF_COEFFICIENT_4L_2:
- case MADERA_FRF_COEFFICIENT_4L_3:
- case MADERA_FRF_COEFFICIENT_4L_4:
- case MADERA_FRF_COEFFICIENT_4R_1:
- case MADERA_FRF_COEFFICIENT_4R_2:
- case MADERA_FRF_COEFFICIENT_4R_3:
- case MADERA_FRF_COEFFICIENT_4R_4:
- case MADERA_FRF_COEFFICIENT_5L_1:
- case MADERA_FRF_COEFFICIENT_5L_2:
- case MADERA_FRF_COEFFICIENT_5L_3:
- case MADERA_FRF_COEFFICIENT_5L_4:
- case MADERA_FRF_COEFFICIENT_5R_1:
- case MADERA_FRF_COEFFICIENT_5R_2:
- case MADERA_FRF_COEFFICIENT_5R_3:
- case MADERA_FRF_COEFFICIENT_5R_4:
- case MADERA_FRF_COEFFICIENT_6L_1:
- case MADERA_FRF_COEFFICIENT_6L_2:
- case MADERA_FRF_COEFFICIENT_6L_3:
- case MADERA_FRF_COEFFICIENT_6L_4:
- case MADERA_FRF_COEFFICIENT_6R_1:
- case MADERA_FRF_COEFFICIENT_6R_2:
- case MADERA_FRF_COEFFICIENT_6R_3:
- case MADERA_FRF_COEFFICIENT_6R_4:
case MADERA_GPIO1_CTRL_1 ... MADERA_GPIO40_CTRL_2:
case MADERA_IRQ1_STATUS_1 ... MADERA_IRQ1_STATUS_33:
case MADERA_IRQ1_MASK_1 ... MADERA_IRQ1_MASK_33:
diff --git a/drivers/mfd/cs47l90-tables.c b/drivers/mfd/cs47l90-tables.c
index c040d3d7232a..7345fc09c0bb 100644
--- a/drivers/mfd/cs47l90-tables.c
+++ b/drivers/mfd/cs47l90-tables.c
@@ -1,12 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Regmap tables for CS47L90 codec
*
* Copyright (C) 2015-2017 Cirrus Logic
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by the
- * Free Software Foundation; version 2.
*/
#include <linux/device.h>
@@ -119,7 +115,6 @@ static const struct reg_default cs47l90_reg_default[] = {
{ 0x00000174, 0x007d }, /* R372 (0x174) - FLL1 Control 4 */
{ 0x00000175, 0x0000 }, /* R373 (0x175) - FLL1 Control 5 */
{ 0x00000176, 0x0000 }, /* R374 (0x176) - FLL1 Control 6 */
- { 0x00000177, 0x0281 }, /* R375 (0x177) - FLL1 Loop Filter Test 1 */
{ 0x00000179, 0x0000 }, /* R377 (0x179) - FLL1 Control 7 */
{ 0x0000017a, 0x2906 }, /* R377 (0x17a) - FLL1 Efs 2 */
{ 0x00000181, 0x0000 }, /* R385 (0x181) - FLL1 Synchroniser 1 */
@@ -137,7 +132,6 @@ static const struct reg_default cs47l90_reg_default[] = {
{ 0x00000194, 0x007d }, /* R404 (0x194) - FLL2 Control 4 */
{ 0x00000195, 0x0000 }, /* R405 (0x195) - FLL2 Control 5 */
{ 0x00000196, 0x0000 }, /* R406 (0x196) - FLL2 Control 6 */
- { 0x00000197, 0x0281 }, /* R407 (0x197) - FLL2 Loop Filter Test 1 */
{ 0x00000199, 0x0000 }, /* R409 (0x199) - FLL2 Control 7 */
{ 0x0000019a, 0x2906 }, /* R410 (0x19a) - FLL2 Efs 2 */
{ 0x000001a1, 0x0000 }, /* R417 (0x1a1) - FLL2 Synchroniser 1 */
@@ -260,8 +254,6 @@ static const struct reg_default cs47l90_reg_default[] = {
{ 0x00000434, 0x0000 }, /* R1076 (0x434) - Output Path Config 5R */
{ 0x00000435, 0x0180 }, /* R1077 (0x435) - DAC Digital Volume 5R */
{ 0x00000437, 0x0200 }, /* R1079 (0x437) - Noise Gate Select 5R */
- { 0x00000440, 0x003f }, /* R1088 (0x440) - DRE Enable */
- { 0x00000448, 0x003f }, /* R1096 (0x448) - eDRE Enable */
{ 0x00000450, 0x0000 }, /* R1104 (0x450) - DAC AEC Control 1 */
{ 0x00000451, 0x0000 }, /* R1104 (0x450) - DAC AEC Control 2 */
{ 0x00000458, 0x0000 }, /* R1112 (0x458) - Noise Gate Control */
@@ -1262,40 +1254,6 @@ static const struct reg_default cs47l90_reg_default[] = {
{ 0x00000fc3, 0x0000 }, /* R4035 (0xfc3) - ANC Coefficient */
{ 0x00000fc4, 0x0000 }, /* R4036 (0xfc4) - ANC Coefficient */
{ 0x00000fc5, 0x0000 }, /* R4037 (0xfc5) - ANC Coefficient */
- { 0x00001300, 0x050E }, /* R4864 (0x1300) - DAC Comp 1 */
- { 0x00001302, 0x0101 }, /* R4866 (0x1302) - DAC Comp 2 */
- { 0x00001380, 0x0425 }, /* R4992 (0x1380) - FRF Coefficient 1L 1 */
- { 0x00001381, 0xF6D8 }, /* R4993 (0x1381) - FRF Coefficient 1L 2 */
- { 0x00001382, 0x0632 }, /* R4994 (0x1382) - FRF Coefficient 1L 3 */
- { 0x00001383, 0xFEC8 }, /* R4995 (0x1383) - FRF Coefficient 1L 4 */
- { 0x00001390, 0x042F }, /* R5008 (0x1390) - FRF Coefficient 1R 1 */
- { 0x00001391, 0xF6CA }, /* R5009 (0x1391) - FRF Coefficient 1R 2 */
- { 0x00001392, 0x0637 }, /* R5010 (0x1392) - FRF Coefficient 1R 3 */
- { 0x00001393, 0xFEC8 }, /* R5011 (0x1393) - FRF Coefficient 1R 4 */
- { 0x000013a0, 0x0000 }, /* R5024 (0x13a0) - FRF Coefficient 2L 1 */
- { 0x000013a1, 0x0000 }, /* R5025 (0x13a1) - FRF Coefficient 2L 2 */
- { 0x000013a2, 0x0000 }, /* R5026 (0x13a2) - FRF Coefficient 2L 3 */
- { 0x000013a3, 0x0000 }, /* R5027 (0x13a3) - FRF Coefficient 2L 4 */
- { 0x000013b0, 0x0000 }, /* R5040 (0x13b0) - FRF Coefficient 2R 1 */
- { 0x000013b1, 0x0000 }, /* R5041 (0x13b1) - FRF Coefficient 2R 2 */
- { 0x000013b2, 0x0000 }, /* R5042 (0x13b2) - FRF Coefficient 2R 3 */
- { 0x000013b3, 0x0000 }, /* R5043 (0x13b3) - FRF Coefficient 2R 4 */
- { 0x000013c0, 0x0000 }, /* R5040 (0x13c0) - FRF Coefficient 3L 1 */
- { 0x000013c1, 0x0000 }, /* R5041 (0x13c1) - FRF Coefficient 3L 2 */
- { 0x000013c2, 0x0000 }, /* R5042 (0x13c2) - FRF Coefficient 3L 3 */
- { 0x000013c3, 0x0000 }, /* R5043 (0x13c3) - FRF Coefficient 3L 4 */
- { 0x000013d0, 0x0000 }, /* R5072 (0x13d0) - FRF Coefficient 3R 1 */
- { 0x000013d1, 0x0000 }, /* R5073 (0x13d1) - FRF Coefficient 3R 2 */
- { 0x000013d2, 0x0000 }, /* R5074 (0x13d2) - FRF Coefficient 3R 3 */
- { 0x000013d3, 0x0000 }, /* R5075 (0x13d3) - FRF Coefficient 3R 4 */
- { 0x00001400, 0x0000 }, /* R5120 (0x1400) - FRF Coefficient 5L 1 */
- { 0x00001401, 0x0000 }, /* R5121 (0x1401) - FRF Coefficient 5L 2 */
- { 0x00001402, 0x0000 }, /* R5122 (0x1402) - FRF Coefficient 5L 3 */
- { 0x00001403, 0x0000 }, /* R5123 (0x1403) - FRF Coefficient 5L 4 */
- { 0x00001410, 0x0000 }, /* R5136 (0x1410) - FRF Coefficient 5R 1 */
- { 0x00001411, 0x0000 }, /* R5137 (0x1411) - FRF Coefficient 5R 2 */
- { 0x00001412, 0x0000 }, /* R5138 (0x1412) - FRF Coefficient 5R 3 */
- { 0x00001413, 0x0000 }, /* R5139 (0x1413) - FRF Coefficient 5R 4 */
{ 0x00001480, 0x0000 }, /* R5248 (0x1480) - DFC1_CTRL */
{ 0x00001482, 0x1f00 }, /* R5250 (0x1482) - DFC1_RX */
{ 0x00001484, 0x1f00 }, /* R5252 (0x1486) - DFC1_TX */
@@ -1535,7 +1493,6 @@ static bool cs47l90_16bit_readable_register(struct device *dev,
case MADERA_FLL1_CONTROL_6:
case MADERA_FLL1_CONTROL_7:
case MADERA_FLL1_EFS_2:
- case MADERA_FLL1_LOOP_FILTER_TEST_1:
case MADERA_FLL1_SYNCHRONISER_1:
case MADERA_FLL1_SYNCHRONISER_2:
case MADERA_FLL1_SYNCHRONISER_3:
@@ -1553,7 +1510,6 @@ static bool cs47l90_16bit_readable_register(struct device *dev,
case MADERA_FLL2_CONTROL_6:
case MADERA_FLL2_CONTROL_7:
case MADERA_FLL2_EFS_2:
- case MADERA_FLL2_LOOP_FILTER_TEST_1:
case MADERA_FLL2_SYNCHRONISER_1:
case MADERA_FLL2_SYNCHRONISER_2:
case MADERA_FLL2_SYNCHRONISER_3:
@@ -1690,8 +1646,6 @@ static bool cs47l90_16bit_readable_register(struct device *dev,
case MADERA_OUTPUT_PATH_CONFIG_5R:
case MADERA_DAC_DIGITAL_VOLUME_5R:
case MADERA_NOISE_GATE_SELECT_5R:
- case MADERA_DRE_ENABLE:
- case MADERA_EDRE_ENABLE:
case MADERA_DAC_AEC_CONTROL_1:
case MADERA_DAC_AEC_CONTROL_2:
case MADERA_NOISE_GATE_CONTROL:
@@ -2449,40 +2403,6 @@ static bool cs47l90_16bit_readable_register(struct device *dev,
case MADERA_FCR_FILTER_CONTROL:
case MADERA_FCR_ADC_REFORMATTER_CONTROL:
case MADERA_FCR_COEFF_START ... MADERA_FCR_COEFF_END:
- case MADERA_DAC_COMP_1:
- case MADERA_DAC_COMP_2:
- case MADERA_FRF_COEFFICIENT_1L_1:
- case MADERA_FRF_COEFFICIENT_1L_2:
- case MADERA_FRF_COEFFICIENT_1L_3:
- case MADERA_FRF_COEFFICIENT_1L_4:
- case MADERA_FRF_COEFFICIENT_1R_1:
- case MADERA_FRF_COEFFICIENT_1R_2:
- case MADERA_FRF_COEFFICIENT_1R_3:
- case MADERA_FRF_COEFFICIENT_1R_4:
- case MADERA_FRF_COEFFICIENT_2L_1:
- case MADERA_FRF_COEFFICIENT_2L_2:
- case MADERA_FRF_COEFFICIENT_2L_3:
- case MADERA_FRF_COEFFICIENT_2L_4:
- case MADERA_FRF_COEFFICIENT_2R_1:
- case MADERA_FRF_COEFFICIENT_2R_2:
- case MADERA_FRF_COEFFICIENT_2R_3:
- case MADERA_FRF_COEFFICIENT_2R_4:
- case MADERA_FRF_COEFFICIENT_3L_1:
- case MADERA_FRF_COEFFICIENT_3L_2:
- case MADERA_FRF_COEFFICIENT_3L_3:
- case MADERA_FRF_COEFFICIENT_3L_4:
- case MADERA_FRF_COEFFICIENT_3R_1:
- case MADERA_FRF_COEFFICIENT_3R_2:
- case MADERA_FRF_COEFFICIENT_3R_3:
- case MADERA_FRF_COEFFICIENT_3R_4:
- case MADERA_FRF_COEFFICIENT_5L_1:
- case MADERA_FRF_COEFFICIENT_5L_2:
- case MADERA_FRF_COEFFICIENT_5L_3:
- case MADERA_FRF_COEFFICIENT_5L_4:
- case MADERA_FRF_COEFFICIENT_5R_1:
- case MADERA_FRF_COEFFICIENT_5R_2:
- case MADERA_FRF_COEFFICIENT_5R_3:
- case MADERA_FRF_COEFFICIENT_5R_4:
case MADERA_DFC1_CTRL:
case MADERA_DFC1_RX:
case MADERA_DFC1_TX:
diff --git a/drivers/mfd/cs47l92-tables.c b/drivers/mfd/cs47l92-tables.c
new file mode 100644
index 000000000000..f296e355df4d
--- /dev/null
+++ b/drivers/mfd/cs47l92-tables.c
@@ -0,0 +1,1947 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Regmap tables for CS47L92 codec
+ *
+ * Copyright (C) 2016-2019 Cirrus Logic, Inc. and
+ * Cirrus Logic International Semiconductor Ltd.
+ *
+ * Author: Stuart Henderson <stuarth@opensource.cirrus.com>
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include <linux/mfd/madera/core.h>
+#include <linux/mfd/madera/registers.h>
+
+#include "madera.h"
+
+static const struct reg_sequence cs47l92_reva_16_patch[] = {
+ { 0x3A2, 0x2C29 },
+ { 0x3A3, 0x0E00 },
+ { 0x281, 0x0000 },
+ { 0x282, 0x0000 },
+ { 0x4EA, 0x0100 },
+ { 0x22B, 0x0000 },
+ { 0x4A0, 0x0080 },
+ { 0x4A1, 0x0000 },
+ { 0x4A2, 0x0000 },
+ { 0x180B, 0x033F },
+ { 0x190B, 0x033F },
+ { 0x442, 0x0304 },
+ { 0x34C, 0x0003 },
+ { 0x124, 0x0C49 },
+ { 0x120, 0x0345 },
+ { 0x120, 0x0305 },
+ { 0x4FA, 0x5064 },
+ { 0x1300, 0x050E },
+ { 0x1302, 0x0101 },
+ { 0x1380, 0x02E0 },
+ { 0x1381, 0xF942 },
+ { 0x1382, 0x04CE },
+ { 0x1383, 0xFF06 },
+ { 0x1390, 0x0304 },
+ { 0x1391, 0xF8FF },
+ { 0x1392, 0x04F3 },
+ { 0x1393, 0xFF00 },
+ { 0x13A0, 0x02E0 },
+ { 0x13A1, 0xF942 },
+ { 0x13A2, 0x04CE },
+ { 0x13A3, 0xFF06 },
+ { 0x13B0, 0x0304 },
+ { 0x13B1, 0xF8FF },
+ { 0x13B2, 0x04F3 },
+ { 0x13B3, 0xFF00 },
+ { 0x412, 0x0005 },
+ { 0x41A, 0x0005 },
+ { 0x422, 0x0005 },
+};
+
+static const struct reg_sequence cs47l92_reva_32_patch[] = {
+ { 0x3030, 0x04A00C01 },
+ { 0x3032, 0x0225F501 },
+ { 0x3044, 0x04A00C00 },
+ { 0x3046, 0x0225FF01 },
+ { 0x3080, 0x04A00C01 },
+ { 0x3082, 0x0226F501 },
+ { 0x3094, 0x04A00C00 },
+ { 0x3096, 0x0226FF01 },
+ { 0x30D1, 0x04A10C01 },
+ { 0x30D2, 0x0227F501 },
+ { 0x30E4, 0x04A10C00 },
+ { 0x30E6, 0x0227FF01 },
+ { 0x3120, 0x04A10C01 },
+ { 0x3122, 0x0228F501 },
+ { 0x3134, 0x04A10C00 },
+ { 0x3136, 0x0228FF01 },
+ { 0x3170, 0x04A20C01 },
+ { 0x3172, 0x022B0101 },
+ { 0x3174, 0x0229F501 },
+ { 0x3184, 0x04A20C00 },
+ { 0x3186, 0x022B0100 },
+ { 0x3188, 0x0229FF01 },
+ { 0x31C0, 0x04A20C01 },
+ { 0x31C2, 0x022B0001 },
+ { 0x31C4, 0x022AF501 },
+ { 0x31D4, 0x04A20C00 },
+ { 0x31D6, 0x022B0000 },
+ { 0x31D8, 0x022AFF01 },
+};
+
+int cs47l92_patch(struct madera *madera)
+{
+ int ret;
+
+ ret = regmap_register_patch(madera->regmap,
+ cs47l92_reva_16_patch,
+ ARRAY_SIZE(cs47l92_reva_16_patch));
+ if (ret < 0) {
+ dev_err(madera->dev,
+ "Error in applying 16-bit patch: %d\n", ret);
+ return ret;
+ }
+
+ ret = regmap_register_patch(madera->regmap_32bit,
+ cs47l92_reva_32_patch,
+ ARRAY_SIZE(cs47l92_reva_32_patch));
+ if (ret < 0) {
+ dev_err(madera->dev,
+ "Error in applying 32-bit patch: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cs47l92_patch);
+
+static const struct reg_default cs47l92_reg_default[] = {
+ { 0x00000020, 0x0000 }, /* R32 (0x20) - Tone Generator 1 */
+ { 0x00000021, 0x1000 }, /* R33 (0x21) - Tone Generator 2 */
+ { 0x00000022, 0x0000 }, /* R34 (0x22) - Tone Generator 3 */
+ { 0x00000023, 0x1000 }, /* R35 (0x23) - Tone Generator 4 */
+ { 0x00000024, 0x0000 }, /* R36 (0x24) - Tone Generator 5 */
+ { 0x00000030, 0x0000 }, /* R48 (0x30) - PWM Drive 1 */
+ { 0x00000031, 0x0100 }, /* R49 (0x31) - PWM Drive 2 */
+ { 0x00000032, 0x0100 }, /* R50 (0x32) - PWM Drive 3 */
+ { 0x00000061, 0x01ff }, /* R97 (0x61) - Sample Rate Sequence Select 1 */
+ { 0x00000062, 0x01ff }, /* R98 (0x62) - Sample Rate Sequence Select 2 */
+ { 0x00000063, 0x01ff }, /* R99 (0x63) - Sample Rate Sequence Select 3 */
+ { 0x00000064, 0x01ff }, /* R100 (0x64) - Sample Rate Sequence Select 4 */
+ { 0x00000090, 0x0000 }, /* R144 (0x90) - Haptics Control 1 */
+ { 0x00000091, 0x7fff }, /* R145 (0x91) - Haptics Control 2 */
+ { 0x00000092, 0x0000 }, /* R146 (0x92) - Haptics Phase 1 Intensity */
+ { 0x00000093, 0x0000 }, /* R147 (0x93) - Haptics Phase 1 Duration */
+ { 0x00000094, 0x0000 }, /* R148 (0x94) - Haptics Phase 2 Intensity */
+ { 0x00000095, 0x0000 }, /* R149 (0x95) - Haptics Phase 2 Duration */
+ { 0x00000096, 0x0000 }, /* R150 (0x96) - Haptics Phase 3 Intensity */
+ { 0x00000097, 0x0000 }, /* R151 (0x97) - Haptics Phase 3 Duration */
+ { 0x000000a0, 0x0000 }, /* R160 (0xa0) - Comfort Noise Generator */
+ { 0x00000100, 0x0002 }, /* R256 (0x100) - Clock 32k 1 */
+ { 0x00000101, 0x0404 }, /* R257 (0x101) - System Clock 1 */
+ { 0x00000102, 0x0011 }, /* R258 (0x102) - Sample Rate 1 */
+ { 0x00000103, 0x0011 }, /* R259 (0x103) - Sample Rate 2 */
+ { 0x00000104, 0x0011 }, /* R260 (0x104) - Sample Rate 3 */
+ { 0x00000112, 0x0305 }, /* R274 (0x112) - Async Clock 1 */
+ { 0x00000113, 0x0011 }, /* R275 (0x113) - Async Sample Rate 1 */
+ { 0x00000114, 0x0011 }, /* R276 (0x114) - Async Sample Rate 2 */
+ { 0x00000120, 0x0305 }, /* R288 (0x120) - DSP Clock 1 */
+ { 0x00000122, 0x0000 }, /* R290 (0x122) - DSP Clock 2 */
+ { 0x00000149, 0x0000 }, /* R329 (0x149) - Output System Clock */
+ { 0x0000014a, 0x0000 }, /* R330 (0x14a) - Output Async Clock */
+ { 0x00000152, 0x0000 }, /* R338 (0x152) - Rate Estimator 1 */
+ { 0x00000153, 0x0000 }, /* R339 (0x153) - Rate Estimator 2 */
+ { 0x00000154, 0x0000 }, /* R340 (0x154) - Rate Estimator 3 */
+ { 0x00000155, 0x0000 }, /* R341 (0x155) - Rate Estimator 4 */
+ { 0x00000156, 0x0000 }, /* R342 (0x156) - Rate Estimator 5 */
+ { 0x00000171, 0x7004 }, /* R369 (0x171) - FLL1 Control 1 */
+ { 0x00000172, 0x0004 }, /* R370 (0x172) - FLL1 Control 2 */
+ { 0x00000173, 0x0000 }, /* R371 (0x173) - FLL1 Control 3 */
+ { 0x00000174, 0x0000 }, /* R372 (0x174) - FLL1 Control 4 */
+ { 0x00000175, 0x0001 }, /* R373 (0x175) - FLL1 Control 5 */
+ { 0x00000176, 0x8000 }, /* R374 (0x176) - FLL1 Control 6 */
+ { 0x00000177, 0x0680 }, /* R375 (0x177) - FLL1 Control 7 */
+ { 0x00000178, 0x21f0 }, /* R376 (0x178) - FLL1 Control 8 */
+ { 0x00000179, 0x0000 }, /* R377 (0x179) - FLL1 Control 9 */
+ { 0x0000017a, 0x0000 }, /* R378 (0x17a) - FLL1 Control 10 */
+ { 0x0000017b, 0x0011 }, /* R379 (0x17b) - FLL1 Control 11 */
+ { 0x0000017d, 0x33e8 }, /* R381 (0x17d) - FLL1 Digital Test 1 */
+ { 0x00000181, 0x7000 }, /* R385 (0x181) - FLL1 Synchroniser 1 */
+ { 0x00000182, 0x0004 }, /* R386 (0x182) - FLL1 Synchroniser 2 */
+ { 0x00000183, 0x0000 }, /* R387 (0x183) - FLL1 Synchroniser 3 */
+ { 0x00000184, 0x0000 }, /* R388 (0x184) - FLL1 Synchroniser 4 */
+ { 0x00000185, 0x0001 }, /* R389 (0x185) - FLL1 Synchroniser 5 */
+ { 0x00000186, 0x0000 }, /* R390 (0x186) - FLL1 Synchroniser 6 */
+ { 0x0000018e, 0x0c04 }, /* R398 (0x18e) - FLL1 GPIO Clock */
+ { 0x00000191, 0x7000 }, /* R401 (0x191) - FLL2 Control 1 */
+ { 0x00000192, 0x0004 }, /* R402 (0x192) - FLL2 Control 2 */
+ { 0x00000193, 0x0000 }, /* R403 (0x193) - FLL2 Control 3 */
+ { 0x00000194, 0x0000 }, /* R404 (0x194) - FLL2 Control 4 */
+ { 0x00000195, 0x0001 }, /* R405 (0x195) - FLL2 Control 5 */
+ { 0x00000196, 0x8000 }, /* R406 (0x196) - FLL2 Control 6 */
+ { 0x00000197, 0x0680 }, /* R407 (0x197) - FLL2 Control 7 */
+ { 0x00000198, 0x21f0 }, /* R408 (0x198) - FLL2 Control 8 */
+ { 0x00000199, 0x0000 }, /* R409 (0x199) - FLL2 Control 9 */
+ { 0x0000019a, 0x0000 }, /* R410 (0x19a) - FLL2 Control 10 */
+ { 0x0000019b, 0x0011 }, /* R411 (0x19b) - FLL2 Control 11 */
+ { 0x0000019d, 0x33e8 }, /* R413 (0x19d) - FLL2 Digital Test 1 */
+ { 0x000001a1, 0x7000 }, /* R417 (0x1a1) - FLL2 Synchroniser 1 */
+ { 0x000001a2, 0x0004 }, /* R418 (0x1a2) - FLL2 Synchroniser 2 */
+ { 0x000001a3, 0x0000 }, /* R419 (0x1a3) - FLL2 Synchroniser 3 */
+ { 0x000001a4, 0x0000 }, /* R420 (0x1a4) - FLL2 Synchroniser 4 */
+ { 0x000001a5, 0x0001 }, /* R421 (0x1a5) - FLL2 Synchroniser 5 */
+ { 0x000001a6, 0x0000 }, /* R422 (0x1a6) - FLL2 Synchroniser 6 */
+ { 0x000001ae, 0x0c04 }, /* R430 (0x1ae) - FLL2 GPIO Clock */
+ { 0x00000200, 0x0006 }, /* R512 (0x200) - Mic Charge Pump 1 */
+ { 0x00000213, 0x03e4 }, /* R531 (0x213) - LDO2 Control 1 */
+ { 0x00000218, 0x00e6 }, /* R536 (0x218) - Mic Bias Ctrl 1 */
+ { 0x00000219, 0x00e6 }, /* R537 (0x219) - Mic Bias Ctrl 2 */
+ { 0x0000021c, 0x2222 }, /* R540 (0x21c) - Mic Bias Ctrl 5 */
+ { 0x0000021e, 0x0022 }, /* R542 (0x21e) - Mic Bias Ctrl 6 */
+ { 0x00000293, 0x0080 }, /* R659 (0x293) - Accessory Detect Mode 1 */
+ { 0x00000299, 0x0000 }, /* R665 (0x299) - Headphone Detect 0 */
+ { 0x0000029b, 0x0000 }, /* R667 (0x29b) - Headphone Detect 1 */
+ { 0x000002a2, 0x0010 }, /* R674 (0x2a2) - Mic Detect 1 Control 0 */
+ { 0x000002a3, 0x1102 }, /* R675 (0x2a3) - Mic Detect 1 Control 1 */
+ { 0x000002a4, 0x009f }, /* R676 (0x2a4) - Mic Detect 1 Control 2 */
+ { 0x000002a6, 0x3d3d }, /* R678 (0x2a6) - Mic Detect 1 Level 1 */
+ { 0x000002a7, 0x3d3d }, /* R679 (0x2a7) - Mic Detect 1 Level 2 */
+ { 0x000002a8, 0x333d }, /* R680 (0x2a8) - Mic Detect 1 Level 3 */
+ { 0x000002a9, 0x202d }, /* R681 (0x2a9) - Mic Detect 1 Level 4 */
+ { 0x000002b2, 0x0010 }, /* R690 (0x2b2) - Mic Detect 2 Control 0 */
+ { 0x000002b3, 0x1102 }, /* R691 (0x2b3) - Mic Detect 2 Control 1 */
+ { 0x000002b4, 0x009f }, /* R692 (0x2b4) - Mic Detect 2 Control 2 */
+ { 0x000002b6, 0x3d3d }, /* R694 (0x2b6) - Mic Detect 2 Level 1 */
+ { 0x000002b7, 0x3d3d }, /* R695 (0x2b7) - Mic Detect 2 Level 2 */
+ { 0x000002b8, 0x333d }, /* R696 (0x2b8) - Mic Detect 2 Level 3 */
+ { 0x000002b9, 0x202d }, /* R697 (0x2b9) - Mic Detect 2 Level 4 */
+ { 0x000002c6, 0x0210 }, /* R710 (0x2c6) - Micd Clamp control */
+ { 0x000002c8, 0x0000 }, /* R712 (0x2c8) - GP Switch 1 */
+ { 0x000002d3, 0x0000 }, /* R723 (0x2d3) - Jack Detect Analogue */
+ { 0x00000300, 0x0000 }, /* R768 (0x300) - Input Enables */
+ { 0x00000308, 0x0400 }, /* R776 (0x308) - Input Rate */
+ { 0x00000309, 0x0022 }, /* R777 (0x309) - Input Volume Ramp */
+ { 0x0000030c, 0x0002 }, /* R780 (0x30c) - HPF Control */
+ { 0x00000310, 0x0080 }, /* R784 (0x310) - IN1L Control */
+ { 0x00000311, 0x0180 }, /* R785 (0x311) - ADC Digital Volume 1L */
+ { 0x00000312, 0x0500 }, /* R786 (0x312) - DMIC1L Control */
+ { 0x00000313, 0x0000 }, /* R787 (0x313) - IN1L Rate Control */
+ { 0x00000314, 0x0080 }, /* R788 (0x314) - IN1R Control */
+ { 0x00000315, 0x0180 }, /* R789 (0x315) - ADC Digital Volume 1R */
+ { 0x00000316, 0x0000 }, /* R790 (0x316) - DMIC1R Control */
+ { 0x00000317, 0x0000 }, /* R791 (0x317) - IN1R Rate Control */
+ { 0x00000318, 0x0080 }, /* R792 (0x318) - IN2L Control */
+ { 0x00000319, 0x0180 }, /* R793 (0x319) - ADC Digital Volume 2L */
+ { 0x0000031a, 0x0500 }, /* R794 (0x31a) - DMIC2L Control */
+ { 0x0000031b, 0x0000 }, /* R795 (0x31b) - IN2L Rate Control */
+ { 0x0000031c, 0x0080 }, /* R796 (0x31c) - IN2R Control */
+ { 0x0000031d, 0x0180 }, /* R797 (0x31d) - ADC Digital Volume 2R */
+ { 0x0000031e, 0x0000 }, /* R798 (0x31e) - DMIC2R Control */
+ { 0x0000031f, 0x0000 }, /* R799 (0x31f) - IN2R Rate Control */
+ { 0x00000320, 0x0000 }, /* R800 (0x320) - IN3L Control */
+ { 0x00000321, 0x0180 }, /* R801 (0x321) - ADC Digital Volume 3L */
+ { 0x00000322, 0x0500 }, /* R802 (0x322) - DMIC3L Control */
+ { 0x00000323, 0x0000 }, /* R803 (0x323) - IN3L Rate Control */
+ { 0x00000324, 0x0000 }, /* R804 (0x324) - IN3R Control */
+ { 0x00000325, 0x0180 }, /* R805 (0x325) - ADC Digital Volume 3R */
+ { 0x00000326, 0x0000 }, /* R806 (0x326) - DMIC3R Control */
+ { 0x00000327, 0x0000 }, /* R807 (0x327) - IN3R Rate Control */
+ { 0x00000328, 0x0000 }, /* R808 (0x328) - IN4L Control */
+ { 0x00000329, 0x0180 }, /* R809 (0x329) - ADC Digital Volume 4L */
+ { 0x0000032a, 0x0500 }, /* R810 (0x32a) - DMIC4L Control */
+ { 0x0000032b, 0x0000 }, /* R811 (0x32b) - IN4L Rate Control */
+ { 0x0000032c, 0x0000 }, /* R812 (0x32c) - IN4R Control */
+ { 0x0000032d, 0x0180 }, /* R813 (0x32d) - ADC Digital Volume 4R */
+ { 0x0000032e, 0x0000 }, /* R814 (0x32e) - DMIC4R Control */
+ { 0x0000032f, 0x0000 }, /* R815 (0x32f) - IN4R Rate Control */
+ { 0x00000400, 0x0000 }, /* R1024 (0x400) - Output Enables 1 */
+ { 0x00000408, 0x0040 }, /* R1032 (0x408) - Output Rate 1 */
+ { 0x00000409, 0x0022 }, /* R1033 (0x409) - Output Volume Ramp */
+ { 0x00000410, 0x0080 }, /* R1040 (0x410) - Output Path Config 1L */
+ { 0x00000411, 0x0180 }, /* R1041 (0x411) - DAC Digital Volume 1L */
+ { 0x00000412, 0x0005 }, /* R1042 (0x412) - Output Path Config 1 */
+ { 0x00000413, 0x0001 }, /* R1043 (0x413) - Noise Gate Select 1L */
+ { 0x00000414, 0x0080 }, /* R1044 (0x414) - Output Path Config 1R */
+ { 0x00000415, 0x0180 }, /* R1045 (0x415) - DAC Digital Volume 1R */
+ { 0x00000417, 0x0002 }, /* R1047 (0x417) - Noise Gate Select 1R */
+ { 0x00000418, 0x0080 }, /* R1048 (0x418) - Output Path Config 2L */
+ { 0x00000419, 0x0180 }, /* R1049 (0x419) - DAC Digital Volume 2L */
+ { 0x0000041a, 0x0005 }, /* R1050 (0x41a) - Output Path Config 2 */
+ { 0x0000041b, 0x0004 }, /* R1051 (0x41b) - Noise Gate Select 2L */
+ { 0x0000041c, 0x0080 }, /* R1052 (0x41c) - Output Path Config 2R */
+ { 0x0000041d, 0x0180 }, /* R1053 (0x41d) - DAC Digital Volume 2R */
+ { 0x0000041f, 0x0008 }, /* R1055 (0x41f) - Noise Gate Select 2R */
+ { 0x00000420, 0x0080 }, /* R1056 (0x420) - Output Path Config 3L */
+ { 0x00000421, 0x0180 }, /* R1057 (0x421) - DAC Digital Volume 3L */
+ { 0x00000422, 0x0005 }, /* R1058 (0x422) - Output Path Config 3 */
+ { 0x00000423, 0x0010 }, /* R1059 (0x423) - Noise Gate Select 3L */
+ { 0x00000424, 0x0080 }, /* R1060 (0x424) - Output Path Config 3R */
+ { 0x00000425, 0x0180 }, /* R1061 (0x425) - DAC Digital Volume 3R */
+ { 0x00000427, 0x0020 }, /* R1063 (0x427) - Noise Gate Select 3R */
+ { 0x00000430, 0x0000 }, /* R1072 (0x430) - Output Path Config 5L */
+ { 0x00000431, 0x0180 }, /* R1073 (0x431) - DAC Digital Volume 5L */
+ { 0x00000433, 0x0100 }, /* R1075 (0x433) - Noise Gate Select 5L */
+ { 0x00000434, 0x0000 }, /* R1076 (0x434) - Output Path Config 5R */
+ { 0x00000435, 0x0180 }, /* R1077 (0x435) - DAC Digital Volume 5R */
+ { 0x00000437, 0x0200 }, /* R1079 (0x437) - Noise Gate Select 5R */
+ { 0x00000450, 0x0000 }, /* R1104 (0x450) - DAC AEC Control 1 */
+ { 0x00000451, 0x0000 }, /* R1105 (0x451) - DAC AEC Control 2 */
+ { 0x00000458, 0x0000 }, /* R1112 (0x458) - Noise Gate Control */
+ { 0x00000490, 0x0069 }, /* R1168 (0x490) - PDM SPK1 Ctrl 1 */
+ { 0x00000491, 0x0000 }, /* R1169 (0x491) - PDM SPK1 Ctrl 2 */
+ { 0x000004a0, 0x0080 }, /* R1184 (0x4a0) - HP1 Short Circuit Ctrl */
+ { 0x000004a1, 0x0000 }, /* R1185 (0x4a1) - HP2 Short Circuit Ctrl */
+ { 0x000004a2, 0x0000 }, /* R1186 (0x4a2) - HP3 Short Circuit Ctrl */
+ { 0x00000500, 0x000c }, /* R1280 (0x500) - AIF1 BCLK Ctrl */
+ { 0x00000501, 0x0000 }, /* R1281 (0x501) - AIF1 Tx Pin Ctrl */
+ { 0x00000502, 0x0000 }, /* R1282 (0x502) - AIF1 Rx Pin Ctrl */
+ { 0x00000503, 0x0000 }, /* R1283 (0x503) - AIF1 Rate Ctrl */
+ { 0x00000504, 0x0000 }, /* R1284 (0x504) - AIF1 Format */
+ { 0x00000506, 0x0040 }, /* R1286 (0x506) - AIF1 Rx BCLK Rate */
+ { 0x00000507, 0x1818 }, /* R1287 (0x507) - AIF1 Frame Ctrl 1 */
+ { 0x00000508, 0x1818 }, /* R1288 (0x508) - AIF1 Frame Ctrl 2 */
+ { 0x00000509, 0x0000 }, /* R1289 (0x509) - AIF1 Frame Ctrl 3 */
+ { 0x0000050a, 0x0001 }, /* R1290 (0x50a) - AIF1 Frame Ctrl 4 */
+ { 0x0000050b, 0x0002 }, /* R1291 (0x50b) - AIF1 Frame Ctrl 5 */
+ { 0x0000050c, 0x0003 }, /* R1292 (0x50c) - AIF1 Frame Ctrl 6 */
+ { 0x0000050d, 0x0004 }, /* R1293 (0x50d) - AIF1 Frame Ctrl 7 */
+ { 0x0000050e, 0x0005 }, /* R1294 (0x50e) - AIF1 Frame Ctrl 8 */
+ { 0x0000050f, 0x0006 }, /* R1295 (0x50f) - AIF1 Frame Ctrl 9 */
+ { 0x00000510, 0x0007 }, /* R1296 (0x510) - AIF1 Frame Ctrl 10 */
+ { 0x00000511, 0x0000 }, /* R1297 (0x511) - AIF1 Frame Ctrl 11 */
+ { 0x00000512, 0x0001 }, /* R1298 (0x512) - AIF1 Frame Ctrl 12 */
+ { 0x00000513, 0x0002 }, /* R1299 (0x513) - AIF1 Frame Ctrl 13 */
+ { 0x00000514, 0x0003 }, /* R1300 (0x514) - AIF1 Frame Ctrl 14 */
+ { 0x00000515, 0x0004 }, /* R1301 (0x515) - AIF1 Frame Ctrl 15 */
+ { 0x00000516, 0x0005 }, /* R1302 (0x516) - AIF1 Frame Ctrl 16 */
+ { 0x00000517, 0x0006 }, /* R1303 (0x517) - AIF1 Frame Ctrl 17 */
+ { 0x00000518, 0x0007 }, /* R1304 (0x518) - AIF1 Frame Ctrl 18 */
+ { 0x00000519, 0x0000 }, /* R1305 (0x519) - AIF1 Tx Enables */
+ { 0x0000051a, 0x0000 }, /* R1306 (0x51a) - AIF1 Rx Enables */
+ { 0x00000540, 0x000c }, /* R1344 (0x540) - AIF2 BCLK Ctrl */
+ { 0x00000541, 0x0000 }, /* R1345 (0x541) - AIF2 Tx Pin Ctrl */
+ { 0x00000542, 0x0000 }, /* R1346 (0x542) - AIF2 Rx Pin Ctrl */
+ { 0x00000543, 0x0000 }, /* R1347 (0x543) - AIF2 Rate Ctrl */
+ { 0x00000544, 0x0000 }, /* R1348 (0x544) - AIF2 Format */
+ { 0x00000546, 0x0040 }, /* R1350 (0x546) - AIF2 Rx BCLK Rate */
+ { 0x00000547, 0x1818 }, /* R1351 (0x547) - AIF2 Frame Ctrl 1 */
+ { 0x00000548, 0x1818 }, /* R1352 (0x548) - AIF2 Frame Ctrl 2 */
+ { 0x00000549, 0x0000 }, /* R1353 (0x549) - AIF2 Frame Ctrl 3 */
+ { 0x0000054a, 0x0001 }, /* R1354 (0x54a) - AIF2 Frame Ctrl 4 */
+ { 0x0000054b, 0x0002 }, /* R1355 (0x54b) - AIF2 Frame Ctrl 5 */
+ { 0x0000054c, 0x0003 }, /* R1356 (0x54c) - AIF2 Frame Ctrl 6 */
+ { 0x0000054d, 0x0004 }, /* R1357 (0x54d) - AIF2 Frame Ctrl 7 */
+ { 0x0000054e, 0x0005 }, /* R1358 (0x54e) - AIF2 Frame Ctrl 8 */
+ { 0x0000054f, 0x0006 }, /* R1359 (0x54f) - AIF2 Frame Ctrl 9 */
+ { 0x00000550, 0x0007 }, /* R1360 (0x550) - AIF2 Frame Ctrl 10 */
+ { 0x00000551, 0x0000 }, /* R1361 (0x551) - AIF2 Frame Ctrl 11 */
+ { 0x00000552, 0x0001 }, /* R1362 (0x552) - AIF2 Frame Ctrl 12 */
+ { 0x00000553, 0x0002 }, /* R1363 (0x553) - AIF2 Frame Ctrl 13 */
+ { 0x00000554, 0x0003 }, /* R1364 (0x554) - AIF2 Frame Ctrl 14 */
+ { 0x00000555, 0x0004 }, /* R1365 (0x555) - AIF2 Frame Ctrl 15 */
+ { 0x00000556, 0x0005 }, /* R1366 (0x556) - AIF2 Frame Ctrl 16 */
+ { 0x00000557, 0x0006 }, /* R1367 (0x557) - AIF2 Frame Ctrl 17 */
+ { 0x00000558, 0x0007 }, /* R1368 (0x558) - AIF2 Frame Ctrl 18 */
+ { 0x00000559, 0x0000 }, /* R1369 (0x559) - AIF2 Tx Enables */
+ { 0x0000055a, 0x0000 }, /* R1370 (0x55a) - AIF2 Rx Enables */
+ { 0x00000580, 0x000c }, /* R1408 (0x580) - AIF3 BCLK Ctrl */
+ { 0x00000581, 0x0000 }, /* R1409 (0x581) - AIF3 Tx Pin Ctrl */
+ { 0x00000582, 0x0000 }, /* R1410 (0x582) - AIF3 Rx Pin Ctrl */
+ { 0x00000583, 0x0000 }, /* R1411 (0x583) - AIF3 Rate Ctrl */
+ { 0x00000584, 0x0000 }, /* R1412 (0x584) - AIF3 Format */
+ { 0x00000586, 0x0040 }, /* R1414 (0x586) - AIF3 Rx BCLK Rate */
+ { 0x00000587, 0x1818 }, /* R1415 (0x587) - AIF3 Frame Ctrl 1 */
+ { 0x00000588, 0x1818 }, /* R1416 (0x588) - AIF3 Frame Ctrl 2 */
+ { 0x00000589, 0x0000 }, /* R1417 (0x589) - AIF3 Frame Ctrl 3 */
+ { 0x0000058a, 0x0001 }, /* R1418 (0x58a) - AIF3 Frame Ctrl 4 */
+ { 0x0000058b, 0x0002 }, /* R1419 (0x58b) - AIF3 Frame Ctrl 5 */
+ { 0x0000058c, 0x0003 }, /* R1420 (0x58c) - AIF3 Frame Ctrl 6 */
+ { 0x0000058d, 0x0004 }, /* R1421 (0x58d) - AIF3 Frame Ctrl 7 */
+ { 0x0000058e, 0x0005 }, /* R1422 (0x58e) - AIF3 Frame Ctrl 8 */
+ { 0x0000058f, 0x0006 }, /* R1423 (0x58f) - AIF3 Frame Ctrl 9 */
+ { 0x00000590, 0x0007 }, /* R1424 (0x590) - AIF3 Frame Ctrl 10 */
+ { 0x00000591, 0x0000 }, /* R1425 (0x591) - AIF3 Frame Ctrl 11 */
+ { 0x00000592, 0x0001 }, /* R1426 (0x592) - AIF3 Frame Ctrl 12 */
+ { 0x00000593, 0x0002 }, /* R1427 (0x593) - AIF3 Frame Ctrl 13 */
+ { 0x00000594, 0x0003 }, /* R1428 (0x594) - AIF3 Frame Ctrl 14 */
+ { 0x00000595, 0x0004 }, /* R1429 (0x595) - AIF3 Frame Ctrl 15 */
+ { 0x00000596, 0x0005 }, /* R1430 (0x596) - AIF3 Frame Ctrl 16 */
+ { 0x00000597, 0x0006 }, /* R1431 (0x597) - AIF3 Frame Ctrl 17 */
+ { 0x00000598, 0x0007 }, /* R1432 (0x598) - AIF3 Frame Ctrl 18 */
+ { 0x00000599, 0x0000 }, /* R1433 (0x599) - AIF3 Tx Enables */
+ { 0x0000059a, 0x0000 }, /* R1434 (0x59a) - AIF3 Rx Enables */
+ { 0x000005c2, 0x0000 }, /* R1474 (0x5c2) - SPD1 Tx Control */
+ { 0x000005e3, 0x0000 }, /* R1507 (0x5e3) - SLIMBus Framer Ref Gear */
+ { 0x000005e5, 0x0000 }, /* R1509 (0x5e5) - SLIMBus Rates 1 */
+ { 0x000005e6, 0x0000 }, /* R1510 (0x5e6) - SLIMBus Rates 2 */
+ { 0x000005e7, 0x0000 }, /* R1511 (0x5e7) - SLIMBus Rates 3 */
+ { 0x000005e8, 0x0000 }, /* R1512 (0x5e8) - SLIMBus Rates 4 */
+ { 0x000005e9, 0x0000 }, /* R1513 (0x5e9) - SLIMBus Rates 5 */
+ { 0x000005ea, 0x0000 }, /* R1514 (0x5ea) - SLIMBus Rates 6 */
+ { 0x000005eb, 0x0000 }, /* R1515 (0x5eb) - SLIMBus Rates 7 */
+ { 0x000005ec, 0x0000 }, /* R1516 (0x5ec) - SLIMBus Rates 8 */
+ { 0x000005f5, 0x0000 }, /* R1525 (0x5f5) - SLIMBus RX Channel Enable */
+ { 0x000005f6, 0x0000 }, /* R1526 (0x5f6) - SLIMBus TX Channel Enable */
+ { 0x00000640, 0x0000 }, /* R1600 (0x640) - PWM1MIX Input 1 Source */
+ { 0x00000641, 0x0080 }, /* R1601 (0x641) - PWM1MIX Input 1 Volume */
+ { 0x00000642, 0x0000 }, /* R1602 (0x642) - PWM1MIX Input 2 Source */
+ { 0x00000643, 0x0080 }, /* R1603 (0x643) - PWM1MIX Input 2 Volume */
+ { 0x00000644, 0x0000 }, /* R1604 (0x644) - PWM1MIX Input 3 Source */
+ { 0x00000645, 0x0080 }, /* R1605 (0x645) - PWM1MIX Input 3 Volume */
+ { 0x00000646, 0x0000 }, /* R1606 (0x646) - PWM1MIX Input 4 Source */
+ { 0x00000647, 0x0080 }, /* R1607 (0x647) - PWM1MIX Input 4 Volume */
+ { 0x00000648, 0x0000 }, /* R1608 (0x648) - PWM2MIX Input 1 Source */
+ { 0x00000649, 0x0080 }, /* R1609 (0x649) - PWM2MIX Input 1 Volume */
+ { 0x0000064a, 0x0000 }, /* R1610 (0x64a) - PWM2MIX Input 2 Source */
+ { 0x0000064b, 0x0080 }, /* R1611 (0x64b) - PWM2MIX Input 2 Volume */
+ { 0x0000064c, 0x0000 }, /* R1612 (0x64c) - PWM2MIX Input 3 Source */
+ { 0x0000064d, 0x0080 }, /* R1613 (0x64d) - PWM2MIX Input 3 Volume */
+ { 0x0000064e, 0x0000 }, /* R1614 (0x64e) - PWM2MIX Input 4 Source */
+ { 0x0000064f, 0x0080 }, /* R1615 (0x64f) - PWM2MIX Input 4 Volume */
+ { 0x00000680, 0x0000 }, /* R1664 (0x680) - OUT1LMIX Input 1 Source */
+ { 0x00000681, 0x0080 }, /* R1665 (0x681) - OUT1LMIX Input 1 Volume */
+ { 0x00000682, 0x0000 }, /* R1666 (0x682) - OUT1LMIX Input 2 Source */
+ { 0x00000683, 0x0080 }, /* R1667 (0x683) - OUT1LMIX Input 2 Volume */
+ { 0x00000684, 0x0000 }, /* R1668 (0x684) - OUT1LMIX Input 3 Source */
+ { 0x00000685, 0x0080 }, /* R1669 (0x685) - OUT1LMIX Input 3 Volume */
+ { 0x00000686, 0x0000 }, /* R1670 (0x686) - OUT1LMIX Input 4 Source */
+ { 0x00000687, 0x0080 }, /* R1671 (0x687) - OUT1LMIX Input 4 Volume */
+ { 0x00000688, 0x0000 }, /* R1672 (0x688) - OUT1RMIX Input 1 Source */
+ { 0x00000689, 0x0080 }, /* R1673 (0x689) - OUT1RMIX Input 1 Volume */
+ { 0x0000068a, 0x0000 }, /* R1674 (0x68a) - OUT1RMIX Input 2 Source */
+ { 0x0000068b, 0x0080 }, /* R1675 (0x68b) - OUT1RMIX Input 2 Volume */
+ { 0x0000068c, 0x0000 }, /* R1676 (0x68c) - OUT1RMIX Input 3 Source */
+ { 0x0000068d, 0x0080 }, /* R1677 (0x68d) - OUT1RMIX Input 3 Volume */
+ { 0x0000068e, 0x0000 }, /* R1678 (0x68e) - OUT1RMIX Input 4 Source */
+ { 0x0000068f, 0x0080 }, /* R1679 (0x68f) - OUT1RMIX Input 4 Volume */
+ { 0x00000690, 0x0000 }, /* R1680 (0x690) - OUT2LMIX Input 1 Source */
+ { 0x00000691, 0x0080 }, /* R1681 (0x691) - OUT2LMIX Input 1 Volume */
+ { 0x00000692, 0x0000 }, /* R1682 (0x692) - OUT2LMIX Input 2 Source */
+ { 0x00000693, 0x0080 }, /* R1683 (0x693) - OUT2LMIX Input 2 Volume */
+ { 0x00000694, 0x0000 }, /* R1684 (0x694) - OUT2LMIX Input 3 Source */
+ { 0x00000695, 0x0080 }, /* R1685 (0x695) - OUT2LMIX Input 3 Volume */
+ { 0x00000696, 0x0000 }, /* R1686 (0x696) - OUT2LMIX Input 4 Source */
+ { 0x00000697, 0x0080 }, /* R1687 (0x697) - OUT2LMIX Input 4 Volume */
+ { 0x00000698, 0x0000 }, /* R1688 (0x698) - OUT2RMIX Input 1 Source */
+ { 0x00000699, 0x0080 }, /* R1689 (0x699) - OUT2RMIX Input 1 Volume */
+ { 0x0000069a, 0x0000 }, /* R1690 (0x69a) - OUT2RMIX Input 2 Source */
+ { 0x0000069b, 0x0080 }, /* R1691 (0x69b) - OUT2RMIX Input 2 Volume */
+ { 0x0000069c, 0x0000 }, /* R1692 (0x69c) - OUT2RMIX Input 3 Source */
+ { 0x0000069d, 0x0080 }, /* R1693 (0x69d) - OUT2RMIX Input 3 Volume */
+ { 0x0000069e, 0x0000 }, /* R1694 (0x69e) - OUT2RMIX Input 4 Source */
+ { 0x0000069f, 0x0080 }, /* R1695 (0x69f) - OUT2RMIX Input 4 Volume */
+ { 0x000006a0, 0x0000 }, /* R1696 (0x6a0) - OUT3LMIX Input 1 Source */
+ { 0x000006a1, 0x0080 }, /* R1697 (0x6a1) - OUT3LMIX Input 1 Volume */
+ { 0x000006a2, 0x0000 }, /* R1698 (0x6a2) - OUT3LMIX Input 2 Source */
+ { 0x000006a3, 0x0080 }, /* R1699 (0x6a3) - OUT3LMIX Input 2 Volume */
+ { 0x000006a4, 0x0000 }, /* R1700 (0x6a4) - OUT3LMIX Input 3 Source */
+ { 0x000006a5, 0x0080 }, /* R1701 (0x6a5) - OUT3LMIX Input 3 Volume */
+ { 0x000006a6, 0x0000 }, /* R1702 (0x6a6) - OUT3LMIX Input 4 Source */
+ { 0x000006a7, 0x0080 }, /* R1703 (0x6a7) - OUT3LMIX Input 4 Volume */
+ { 0x000006a8, 0x0000 }, /* R1704 (0x6a8) - OUT3RMIX Input 1 Source */
+ { 0x000006a9, 0x0080 }, /* R1705 (0x6a9) - OUT3RMIX Input 1 Volume */
+ { 0x000006aa, 0x0000 }, /* R1706 (0x6aa) - OUT3RMIX Input 2 Source */
+ { 0x000006ab, 0x0080 }, /* R1707 (0x6ab) - OUT3RMIX Input 2 Volume */
+ { 0x000006ac, 0x0000 }, /* R1708 (0x6ac) - OUT3RMIX Input 3 Source */
+ { 0x000006ad, 0x0080 }, /* R1709 (0x6ad) - OUT3RMIX Input 3 Volume */
+ { 0x000006ae, 0x0000 }, /* R1710 (0x6ae) - OUT3RMIX Input 4 Source */
+ { 0x000006af, 0x0080 }, /* R1711 (0x6af) - OUT3RMIX Input 4 Volume */
+ { 0x000006c0, 0x0000 }, /* R1728 (0x6c0) - OUT5LMIX Input 1 Source */
+ { 0x000006c1, 0x0080 }, /* R1729 (0x6c1) - OUT5LMIX Input 1 Volume */
+ { 0x000006c2, 0x0000 }, /* R1730 (0x6c2) - OUT5LMIX Input 2 Source */
+ { 0x000006c3, 0x0080 }, /* R1731 (0x6c3) - OUT5LMIX Input 2 Volume */
+ { 0x000006c4, 0x0000 }, /* R1732 (0x6c4) - OUT5LMIX Input 3 Source */
+ { 0x000006c5, 0x0080 }, /* R1733 (0x6c5) - OUT5LMIX Input 3 Volume */
+ { 0x000006c6, 0x0000 }, /* R1734 (0x6c6) - OUT5LMIX Input 4 Source */
+ { 0x000006c7, 0x0080 }, /* R1735 (0x6c7) - OUT5LMIX Input 4 Volume */
+ { 0x000006c8, 0x0000 }, /* R1736 (0x6c8) - OUT5RMIX Input 1 Source */
+ { 0x000006c9, 0x0080 }, /* R1737 (0x6c9) - OUT5RMIX Input 1 Volume */
+ { 0x000006ca, 0x0000 }, /* R1738 (0x6ca) - OUT5RMIX Input 2 Source */
+ { 0x000006cb, 0x0080 }, /* R1739 (0x6cb) - OUT5RMIX Input 2 Volume */
+ { 0x000006cc, 0x0000 }, /* R1740 (0x6cc) - OUT5RMIX Input 3 Source */
+ { 0x000006cd, 0x0080 }, /* R1741 (0x6cd) - OUT5RMIX Input 3 Volume */
+ { 0x000006ce, 0x0000 }, /* R1742 (0x6ce) - OUT5RMIX Input 4 Source */
+ { 0x000006cf, 0x0080 }, /* R1743 (0x6cf) - OUT5RMIX Input 4 Volume */
+ { 0x00000700, 0x0000 }, /* R1792 (0x700) - AIF1TX1MIX Input 1 Source */
+ { 0x00000701, 0x0080 }, /* R1793 (0x701) - AIF1TX1MIX Input 1 Volume */
+ { 0x00000702, 0x0000 }, /* R1794 (0x702) - AIF1TX1MIX Input 2 Source */
+ { 0x00000703, 0x0080 }, /* R1795 (0x703) - AIF1TX1MIX Input 2 Volume */
+ { 0x00000704, 0x0000 }, /* R1796 (0x704) - AIF1TX1MIX Input 3 Source */
+ { 0x00000705, 0x0080 }, /* R1797 (0x705) - AIF1TX1MIX Input 3 Volume */
+ { 0x00000706, 0x0000 }, /* R1798 (0x706) - AIF1TX1MIX Input 4 Source */
+ { 0x00000707, 0x0080 }, /* R1799 (0x707) - AIF1TX1MIX Input 4 Volume */
+ { 0x00000708, 0x0000 }, /* R1800 (0x708) - AIF1TX2MIX Input 1 Source */
+ { 0x00000709, 0x0080 }, /* R1801 (0x709) - AIF1TX2MIX Input 1 Volume */
+ { 0x0000070a, 0x0000 }, /* R1802 (0x70a) - AIF1TX2MIX Input 2 Source */
+ { 0x0000070b, 0x0080 }, /* R1803 (0x70b) - AIF1TX2MIX Input 2 Volume */
+ { 0x0000070c, 0x0000 }, /* R1804 (0x70c) - AIF1TX2MIX Input 3 Source */
+ { 0x0000070d, 0x0080 }, /* R1805 (0x70d) - AIF1TX2MIX Input 3 Volume */
+ { 0x0000070e, 0x0000 }, /* R1806 (0x70e) - AIF1TX2MIX Input 4 Source */
+ { 0x0000070f, 0x0080 }, /* R1807 (0x70f) - AIF1TX2MIX Input 4 Volume */
+ { 0x00000710, 0x0000 }, /* R1808 (0x710) - AIF1TX3MIX Input 1 Source */
+ { 0x00000711, 0x0080 }, /* R1809 (0x711) - AIF1TX3MIX Input 1 Volume */
+ { 0x00000712, 0x0000 }, /* R1810 (0x712) - AIF1TX3MIX Input 2 Source */
+ { 0x00000713, 0x0080 }, /* R1811 (0x713) - AIF1TX3MIX Input 2 Volume */
+ { 0x00000714, 0x0000 }, /* R1812 (0x714) - AIF1TX3MIX Input 3 Source */
+ { 0x00000715, 0x0080 }, /* R1813 (0x715) - AIF1TX3MIX Input 3 Volume */
+ { 0x00000716, 0x0000 }, /* R1814 (0x716) - AIF1TX3MIX Input 4 Source */
+ { 0x00000717, 0x0080 }, /* R1815 (0x717) - AIF1TX3MIX Input 4 Volume */
+ { 0x00000718, 0x0000 }, /* R1816 (0x718) - AIF1TX4MIX Input 1 Source */
+ { 0x00000719, 0x0080 }, /* R1817 (0x719) - AIF1TX4MIX Input 1 Volume */
+ { 0x0000071a, 0x0000 }, /* R1818 (0x71a) - AIF1TX4MIX Input 2 Source */
+ { 0x0000071b, 0x0080 }, /* R1819 (0x71b) - AIF1TX4MIX Input 2 Volume */
+ { 0x0000071c, 0x0000 }, /* R1820 (0x71c) - AIF1TX4MIX Input 3 Source */
+ { 0x0000071d, 0x0080 }, /* R1821 (0x71d) - AIF1TX4MIX Input 3 Volume */
+ { 0x0000071e, 0x0000 }, /* R1822 (0x71e) - AIF1TX4MIX Input 4 Source */
+ { 0x0000071f, 0x0080 }, /* R1823 (0x71f) - AIF1TX4MIX Input 4 Volume */
+ { 0x00000720, 0x0000 }, /* R1824 (0x720) - AIF1TX5MIX Input 1 Source */
+ { 0x00000721, 0x0080 }, /* R1825 (0x721) - AIF1TX5MIX Input 1 Volume */
+ { 0x00000722, 0x0000 }, /* R1826 (0x722) - AIF1TX5MIX Input 2 Source */
+ { 0x00000723, 0x0080 }, /* R1827 (0x723) - AIF1TX5MIX Input 2 Volume */
+ { 0x00000724, 0x0000 }, /* R1828 (0x724) - AIF1TX5MIX Input 3 Source */
+ { 0x00000725, 0x0080 }, /* R1829 (0x725) - AIF1TX5MIX Input 3 Volume */
+ { 0x00000726, 0x0000 }, /* R1830 (0x726) - AIF1TX5MIX Input 4 Source */
+ { 0x00000727, 0x0080 }, /* R1831 (0x727) - AIF1TX5MIX Input 4 Volume */
+ { 0x00000728, 0x0000 }, /* R1832 (0x728) - AIF1TX6MIX Input 1 Source */
+ { 0x00000729, 0x0080 }, /* R1833 (0x729) - AIF1TX6MIX Input 1 Volume */
+ { 0x0000072a, 0x0000 }, /* R1834 (0x72a) - AIF1TX6MIX Input 2 Source */
+ { 0x0000072b, 0x0080 }, /* R1835 (0x72b) - AIF1TX6MIX Input 2 Volume */
+ { 0x0000072c, 0x0000 }, /* R1836 (0x72c) - AIF1TX6MIX Input 3 Source */
+ { 0x0000072d, 0x0080 }, /* R1837 (0x72d) - AIF1TX6MIX Input 3 Volume */
+ { 0x0000072e, 0x0000 }, /* R1838 (0x72e) - AIF1TX6MIX Input 4 Source */
+ { 0x0000072f, 0x0080 }, /* R1839 (0x72f) - AIF1TX6MIX Input 4 Volume */
+ { 0x00000730, 0x0000 }, /* R1840 (0x730) - AIF1TX7MIX Input 1 Source */
+ { 0x00000731, 0x0080 }, /* R1841 (0x731) - AIF1TX7MIX Input 1 Volume */
+ { 0x00000732, 0x0000 }, /* R1842 (0x732) - AIF1TX7MIX Input 2 Source */
+ { 0x00000733, 0x0080 }, /* R1843 (0x733) - AIF1TX7MIX Input 2 Volume */
+ { 0x00000734, 0x0000 }, /* R1844 (0x734) - AIF1TX7MIX Input 3 Source */
+ { 0x00000735, 0x0080 }, /* R1845 (0x735) - AIF1TX7MIX Input 3 Volume */
+ { 0x00000736, 0x0000 }, /* R1846 (0x736) - AIF1TX7MIX Input 4 Source */
+ { 0x00000737, 0x0080 }, /* R1847 (0x737) - AIF1TX7MIX Input 4 Volume */
+ { 0x00000738, 0x0000 }, /* R1848 (0x738) - AIF1TX8MIX Input 1 Source */
+ { 0x00000739, 0x0080 }, /* R1849 (0x739) - AIF1TX8MIX Input 1 Volume */
+ { 0x0000073a, 0x0000 }, /* R1850 (0x73a) - AIF1TX8MIX Input 2 Source */
+ { 0x0000073b, 0x0080 }, /* R1851 (0x73b) - AIF1TX8MIX Input 2 Volume */
+ { 0x0000073c, 0x0000 }, /* R1852 (0x73c) - AIF1TX8MIX Input 3 Source */
+ { 0x0000073d, 0x0080 }, /* R1853 (0x73d) - AIF1TX8MIX Input 3 Volume */
+ { 0x0000073e, 0x0000 }, /* R1854 (0x73e) - AIF1TX8MIX Input 4 Source */
+ { 0x0000073f, 0x0080 }, /* R1855 (0x73f) - AIF1TX8MIX Input 4 Volume */
+ { 0x00000740, 0x0000 }, /* R1856 (0x740) - AIF2TX1MIX Input 1 Source */
+ { 0x00000741, 0x0080 }, /* R1857 (0x741) - AIF2TX1MIX Input 1 Volume */
+ { 0x00000742, 0x0000 }, /* R1858 (0x742) - AIF2TX1MIX Input 2 Source */
+ { 0x00000743, 0x0080 }, /* R1859 (0x743) - AIF2TX1MIX Input 2 Volume */
+ { 0x00000744, 0x0000 }, /* R1860 (0x744) - AIF2TX1MIX Input 3 Source */
+ { 0x00000745, 0x0080 }, /* R1861 (0x745) - AIF2TX1MIX Input 3 Volume */
+ { 0x00000746, 0x0000 }, /* R1862 (0x746) - AIF2TX1MIX Input 4 Source */
+ { 0x00000747, 0x0080 }, /* R1863 (0x747) - AIF2TX1MIX Input 4 Volume */
+ { 0x00000748, 0x0000 }, /* R1864 (0x748) - AIF2TX2MIX Input 1 Source */
+ { 0x00000749, 0x0080 }, /* R1865 (0x749) - AIF2TX2MIX Input 1 Volume */
+ { 0x0000074a, 0x0000 }, /* R1866 (0x74a) - AIF2TX2MIX Input 2 Source */
+ { 0x0000074b, 0x0080 }, /* R1867 (0x74b) - AIF2TX2MIX Input 2 Volume */
+ { 0x0000074c, 0x0000 }, /* R1868 (0x74c) - AIF2TX2MIX Input 3 Source */
+ { 0x0000074d, 0x0080 }, /* R1869 (0x74d) - AIF2TX2MIX Input 3 Volume */
+ { 0x0000074e, 0x0000 }, /* R1870 (0x74e) - AIF2TX2MIX Input 4 Source */
+ { 0x0000074f, 0x0080 }, /* R1871 (0x74f) - AIF2TX2MIX Input 4 Volume */
+ { 0x00000750, 0x0000 }, /* R1872 (0x750) - AIF2TX3MIX Input 1 Source */
+ { 0x00000751, 0x0080 }, /* R1873 (0x751) - AIF2TX3MIX Input 1 Volume */
+ { 0x00000752, 0x0000 }, /* R1874 (0x752) - AIF2TX3MIX Input 2 Source */
+ { 0x00000753, 0x0080 }, /* R1875 (0x753) - AIF2TX3MIX Input 2 Volume */
+ { 0x00000754, 0x0000 }, /* R1876 (0x754) - AIF2TX3MIX Input 3 Source */
+ { 0x00000755, 0x0080 }, /* R1877 (0x755) - AIF2TX3MIX Input 3 Volume */
+ { 0x00000756, 0x0000 }, /* R1878 (0x756) - AIF2TX3MIX Input 4 Source */
+ { 0x00000757, 0x0080 }, /* R1879 (0x757) - AIF2TX3MIX Input 4 Volume */
+ { 0x00000758, 0x0000 }, /* R1880 (0x758) - AIF2TX4MIX Input 1 Source */
+ { 0x00000759, 0x0080 }, /* R1881 (0x759) - AIF2TX4MIX Input 1 Volume */
+ { 0x0000075a, 0x0000 }, /* R1882 (0x75a) - AIF2TX4MIX Input 2 Source */
+ { 0x0000075b, 0x0080 }, /* R1883 (0x75b) - AIF2TX4MIX Input 2 Volume */
+ { 0x0000075c, 0x0000 }, /* R1884 (0x75c) - AIF2TX4MIX Input 3 Source */
+ { 0x0000075d, 0x0080 }, /* R1885 (0x75d) - AIF2TX4MIX Input 3 Volume */
+ { 0x0000075e, 0x0000 }, /* R1886 (0x75e) - AIF2TX4MIX Input 4 Source */
+ { 0x0000075f, 0x0080 }, /* R1887 (0x75f) - AIF2TX4MIX Input 4 Volume */
+ { 0x00000760, 0x0000 }, /* R1888 (0x760) - AIF2TX5MIX Input 1 Source */
+ { 0x00000761, 0x0080 }, /* R1889 (0x761) - AIF2TX5MIX Input 1 Volume */
+ { 0x00000762, 0x0000 }, /* R1890 (0x762) - AIF2TX5MIX Input 2 Source */
+ { 0x00000763, 0x0080 }, /* R1891 (0x763) - AIF2TX5MIX Input 2 Volume */
+ { 0x00000764, 0x0000 }, /* R1892 (0x764) - AIF2TX5MIX Input 3 Source */
+ { 0x00000765, 0x0080 }, /* R1893 (0x765) - AIF2TX5MIX Input 3 Volume */
+ { 0x00000766, 0x0000 }, /* R1894 (0x766) - AIF2TX5MIX Input 4 Source */
+ { 0x00000767, 0x0080 }, /* R1895 (0x767) - AIF2TX5MIX Input 4 Volume */
+ { 0x00000768, 0x0000 }, /* R1896 (0x768) - AIF2TX6MIX Input 1 Source */
+ { 0x00000769, 0x0080 }, /* R1897 (0x769) - AIF2TX6MIX Input 1 Volume */
+ { 0x0000076a, 0x0000 }, /* R1898 (0x76a) - AIF2TX6MIX Input 2 Source */
+ { 0x0000076b, 0x0080 }, /* R1899 (0x76b) - AIF2TX6MIX Input 2 Volume */
+ { 0x0000076c, 0x0000 }, /* R1900 (0x76c) - AIF2TX6MIX Input 3 Source */
+ { 0x0000076d, 0x0080 }, /* R1901 (0x76d) - AIF2TX6MIX Input 3 Volume */
+ { 0x0000076e, 0x0000 }, /* R1902 (0x76e) - AIF2TX6MIX Input 4 Source */
+ { 0x0000076f, 0x0080 }, /* R1903 (0x76f) - AIF2TX6MIX Input 4 Volume */
+ { 0x00000770, 0x0000 }, /* R1904 (0x770) - AIF2TX7MIX Input 1 Source */
+ { 0x00000771, 0x0080 }, /* R1905 (0x771) - AIF2TX7MIX Input 1 Volume */
+ { 0x00000772, 0x0000 }, /* R1906 (0x772) - AIF2TX7MIX Input 2 Source */
+ { 0x00000773, 0x0080 }, /* R1907 (0x773) - AIF2TX7MIX Input 2 Volume */
+ { 0x00000774, 0x0000 }, /* R1908 (0x774) - AIF2TX7MIX Input 3 Source */
+ { 0x00000775, 0x0080 }, /* R1909 (0x775) - AIF2TX7MIX Input 3 Volume */
+ { 0x00000776, 0x0000 }, /* R1910 (0x776) - AIF2TX7MIX Input 4 Source */
+ { 0x00000777, 0x0080 }, /* R1911 (0x777) - AIF2TX7MIX Input 4 Volume */
+ { 0x00000778, 0x0000 }, /* R1912 (0x778) - AIF2TX8MIX Input 1 Source */
+ { 0x00000779, 0x0080 }, /* R1913 (0x779) - AIF2TX8MIX Input 1 Volume */
+ { 0x0000077a, 0x0000 }, /* R1914 (0x77a) - AIF2TX8MIX Input 2 Source */
+ { 0x0000077b, 0x0080 }, /* R1915 (0x77b) - AIF2TX8MIX Input 2 Volume */
+ { 0x0000077c, 0x0000 }, /* R1916 (0x77c) - AIF2TX8MIX Input 3 Source */
+ { 0x0000077d, 0x0080 }, /* R1917 (0x77d) - AIF2TX8MIX Input 3 Volume */
+ { 0x0000077e, 0x0000 }, /* R1918 (0x77e) - AIF2TX8MIX Input 4 Source */
+ { 0x0000077f, 0x0080 }, /* R1919 (0x77f) - AIF2TX8MIX Input 4 Volume */
+ { 0x00000780, 0x0000 }, /* R1920 (0x780) - AIF3TX1MIX Input 1 Source */
+ { 0x00000781, 0x0080 }, /* R1921 (0x781) - AIF3TX1MIX Input 1 Volume */
+ { 0x00000782, 0x0000 }, /* R1922 (0x782) - AIF3TX1MIX Input 2 Source */
+ { 0x00000783, 0x0080 }, /* R1923 (0x783) - AIF3TX1MIX Input 2 Volume */
+ { 0x00000784, 0x0000 }, /* R1924 (0x784) - AIF3TX1MIX Input 3 Source */
+ { 0x00000785, 0x0080 }, /* R1925 (0x785) - AIF3TX1MIX Input 3 Volume */
+ { 0x00000786, 0x0000 }, /* R1926 (0x786) - AIF3TX1MIX Input 4 Source */
+ { 0x00000787, 0x0080 }, /* R1927 (0x787) - AIF3TX1MIX Input 4 Volume */
+ { 0x00000788, 0x0000 }, /* R1928 (0x788) - AIF3TX2MIX Input 1 Source */
+ { 0x00000789, 0x0080 }, /* R1929 (0x789) - AIF3TX2MIX Input 1 Volume */
+ { 0x0000078a, 0x0000 }, /* R1930 (0x78a) - AIF3TX2MIX Input 2 Source */
+ { 0x0000078b, 0x0080 }, /* R1931 (0x78b) - AIF3TX2MIX Input 2 Volume */
+ { 0x0000078c, 0x0000 }, /* R1932 (0x78c) - AIF3TX2MIX Input 3 Source */
+ { 0x0000078d, 0x0080 }, /* R1933 (0x78d) - AIF3TX2MIX Input 3 Volume */
+ { 0x0000078e, 0x0000 }, /* R1934 (0x78e) - AIF3TX2MIX Input 4 Source */
+ { 0x0000078f, 0x0080 }, /* R1935 (0x78f) - AIF3TX2MIX Input 4 Volume */
+ { 0x00000790, 0x0000 }, /* R1936 (0x790) - AIF3TX3MIX Input 1 Source */
+ { 0x00000791, 0x0080 }, /* R1937 (0x791) - AIF3TX3MIX Input 1 Volume */
+ { 0x00000792, 0x0000 }, /* R1938 (0x792) - AIF3TX3MIX Input 2 Source */
+ { 0x00000793, 0x0080 }, /* R1939 (0x793) - AIF3TX3MIX Input 2 Volume */
+ { 0x00000794, 0x0000 }, /* R1940 (0x794) - AIF3TX3MIX Input 3 Source */
+ { 0x00000795, 0x0080 }, /* R1941 (0x795) - AIF3TX3MIX Input 3 Volume */
+ { 0x00000796, 0x0000 }, /* R1942 (0x796) - AIF3TX3MIX Input 4 Source */
+ { 0x00000797, 0x0080 }, /* R1943 (0x797) - AIF3TX3MIX Input 4 Volume */
+ { 0x00000798, 0x0000 }, /* R1944 (0x798) - AIF3TX4MIX Input 1 Source */
+ { 0x00000799, 0x0080 }, /* R1945 (0x799) - AIF3TX4MIX Input 1 Volume */
+ { 0x0000079a, 0x0000 }, /* R1946 (0x79a) - AIF3TX4MIX Input 2 Source */
+ { 0x0000079b, 0x0080 }, /* R1947 (0x79b) - AIF3TX4MIX Input 2 Volume */
+ { 0x0000079c, 0x0000 }, /* R1948 (0x79c) - AIF3TX4MIX Input 3 Source */
+ { 0x0000079d, 0x0080 }, /* R1949 (0x79d) - AIF3TX4MIX Input 3 Volume */
+ { 0x0000079e, 0x0000 }, /* R1950 (0x79e) - AIF3TX4MIX Input 4 Source */
+ { 0x0000079f, 0x0080 }, /* R1951 (0x79f) - AIF3TX4MIX Input 4 Volume */
+ { 0x000007a0, 0x0000 }, /* R1952 (0x7a0) - AIF3TX5MIX Input 1 Source */
+ { 0x000007a1, 0x0080 }, /* R1953 (0x7a1) - AIF3TX5MIX Input 1 Volume */
+ { 0x000007a2, 0x0000 }, /* R1954 (0x7a2) - AIF3TX5MIX Input 2 Source */
+ { 0x000007a3, 0x0080 }, /* R1955 (0x7a3) - AIF3TX5MIX Input 2 Volume */
+ { 0x000007a4, 0x0000 }, /* R1956 (0x7a4) - AIF3TX5MIX Input 3 Source */
+ { 0x000007a5, 0x0080 }, /* R1957 (0x7a5) - AIF3TX5MIX Input 3 Volume */
+ { 0x000007a6, 0x0000 }, /* R1958 (0x7a6) - AIF3TX5MIX Input 4 Source */
+ { 0x000007a7, 0x0080 }, /* R1959 (0x7a7) - AIF3TX5MIX Input 4 Volume */
+ { 0x000007a8, 0x0000 }, /* R1960 (0x7a8) - AIF3TX6MIX Input 1 Source */
+ { 0x000007a9, 0x0080 }, /* R1961 (0x7a9) - AIF3TX6MIX Input 1 Volume */
+ { 0x000007aa, 0x0000 }, /* R1962 (0x7aa) - AIF3TX6MIX Input 2 Source */
+ { 0x000007ab, 0x0080 }, /* R1963 (0x7ab) - AIF3TX6MIX Input 2 Volume */
+ { 0x000007ac, 0x0000 }, /* R1964 (0x7ac) - AIF3TX6MIX Input 3 Source */
+ { 0x000007ad, 0x0080 }, /* R1965 (0x7ad) - AIF3TX6MIX Input 3 Volume */
+ { 0x000007ae, 0x0000 }, /* R1966 (0x7ae) - AIF3TX6MIX Input 4 Source */
+ { 0x000007af, 0x0080 }, /* R1967 (0x7af) - AIF3TX6MIX Input 4 Volume */
+ { 0x000007b0, 0x0000 }, /* R1968 (0x7b0) - AIF3TX7MIX Input 1 Source */
+ { 0x000007b1, 0x0080 }, /* R1969 (0x7b1) - AIF3TX7MIX Input 1 Volume */
+ { 0x000007b2, 0x0000 }, /* R1970 (0x7b2) - AIF3TX7MIX Input 2 Source */
+ { 0x000007b3, 0x0080 }, /* R1971 (0x7b3) - AIF3TX7MIX Input 2 Volume */
+ { 0x000007b4, 0x0000 }, /* R1972 (0x7b4) - AIF3TX7MIX Input 3 Source */
+ { 0x000007b5, 0x0080 }, /* R1973 (0x7b5) - AIF3TX7MIX Input 3 Volume */
+ { 0x000007b6, 0x0000 }, /* R1974 (0x7b6) - AIF3TX7MIX Input 4 Source */
+ { 0x000007b7, 0x0080 }, /* R1975 (0x7b7) - AIF3TX7MIX Input 4 Volume */
+ { 0x000007b8, 0x0000 }, /* R1976 (0x7b8) - AIF3TX8MIX Input 1 Source */
+ { 0x000007b9, 0x0080 }, /* R1977 (0x7b9) - AIF3TX8MIX Input 1 Volume */
+ { 0x000007ba, 0x0000 }, /* R1978 (0x7ba) - AIF3TX8MIX Input 2 Source */
+ { 0x000007bb, 0x0080 }, /* R1979 (0x7bb) - AIF3TX8MIX Input 2 Volume */
+ { 0x000007bc, 0x0000 }, /* R1980 (0x7bc) - AIF3TX8MIX Input 3 Source */
+ { 0x000007bd, 0x0080 }, /* R1981 (0x7bd) - AIF3TX8MIX Input 3 Volume */
+ { 0x000007be, 0x0000 }, /* R1982 (0x7be) - AIF3TX8MIX Input 4 Source */
+ { 0x000007bf, 0x0080 }, /* R1983 (0x7bf) - AIF3TX8MIX Input 4 Volume */
+ { 0x000007c0, 0x0000 }, /* R1984 (0x7c0) - SLIMTX1MIX Input 1 Source */
+ { 0x000007c1, 0x0080 }, /* R1985 (0x7c1) - SLIMTX1MIX Input 1 Volume */
+ { 0x000007c2, 0x0000 }, /* R1986 (0x7c2) - SLIMTX1MIX Input 2 Source */
+ { 0x000007c3, 0x0080 }, /* R1987 (0x7c3) - SLIMTX1MIX Input 2 Volume */
+ { 0x000007c4, 0x0000 }, /* R1988 (0x7c4) - SLIMTX1MIX Input 3 Source */
+ { 0x000007c5, 0x0080 }, /* R1989 (0x7c5) - SLIMTX1MIX Input 3 Volume */
+ { 0x000007c6, 0x0000 }, /* R1990 (0x7c6) - SLIMTX1MIX Input 4 Source */
+ { 0x000007c7, 0x0080 }, /* R1991 (0x7c7) - SLIMTX1MIX Input 4 Volume */
+ { 0x000007c8, 0x0000 }, /* R1992 (0x7c8) - SLIMTX2MIX Input 1 Source */
+ { 0x000007c9, 0x0080 }, /* R1993 (0x7c9) - SLIMTX2MIX Input 1 Volume */
+ { 0x000007ca, 0x0000 }, /* R1994 (0x7ca) - SLIMTX2MIX Input 2 Source */
+ { 0x000007cb, 0x0080 }, /* R1995 (0x7cb) - SLIMTX2MIX Input 2 Volume */
+ { 0x000007cc, 0x0000 }, /* R1996 (0x7cc) - SLIMTX2MIX Input 3 Source */
+ { 0x000007cd, 0x0080 }, /* R1997 (0x7cd) - SLIMTX2MIX Input 3 Volume */
+ { 0x000007ce, 0x0000 }, /* R1998 (0x7ce) - SLIMTX2MIX Input 4 Source */
+ { 0x000007cf, 0x0080 }, /* R1999 (0x7cf) - SLIMTX2MIX Input 4 Volume */
+ { 0x000007d0, 0x0000 }, /* R2000 (0x7d0) - SLIMTX3MIX Input 1 Source */
+ { 0x000007d1, 0x0080 }, /* R2001 (0x7d1) - SLIMTX3MIX Input 1 Volume */
+ { 0x000007d2, 0x0000 }, /* R2002 (0x7d2) - SLIMTX3MIX Input 2 Source */
+ { 0x000007d3, 0x0080 }, /* R2003 (0x7d3) - SLIMTX3MIX Input 2 Volume */
+ { 0x000007d4, 0x0000 }, /* R2004 (0x7d4) - SLIMTX3MIX Input 3 Source */
+ { 0x000007d5, 0x0080 }, /* R2005 (0x7d5) - SLIMTX3MIX Input 3 Volume */
+ { 0x000007d6, 0x0000 }, /* R2006 (0x7d6) - SLIMTX3MIX Input 4 Source */
+ { 0x000007d7, 0x0080 }, /* R2007 (0x7d7) - SLIMTX3MIX Input 4 Volume */
+ { 0x000007d8, 0x0000 }, /* R2008 (0x7d8) - SLIMTX4MIX Input 1 Source */
+ { 0x000007d9, 0x0080 }, /* R2009 (0x7d9) - SLIMTX4MIX Input 1 Volume */
+ { 0x000007da, 0x0000 }, /* R2010 (0x7da) - SLIMTX4MIX Input 2 Source */
+ { 0x000007db, 0x0080 }, /* R2011 (0x7db) - SLIMTX4MIX Input 2 Volume */
+ { 0x000007dc, 0x0000 }, /* R2012 (0x7dc) - SLIMTX4MIX Input 3 Source */
+ { 0x000007dd, 0x0080 }, /* R2013 (0x7dd) - SLIMTX4MIX Input 3 Volume */
+ { 0x000007de, 0x0000 }, /* R2014 (0x7de) - SLIMTX4MIX Input 4 Source */
+ { 0x000007df, 0x0080 }, /* R2015 (0x7df) - SLIMTX4MIX Input 4 Volume */
+ { 0x000007e0, 0x0000 }, /* R2016 (0x7e0) - SLIMTX5MIX Input 1 Source */
+ { 0x000007e1, 0x0080 }, /* R2017 (0x7e1) - SLIMTX5MIX Input 1 Volume */
+ { 0x000007e2, 0x0000 }, /* R2018 (0x7e2) - SLIMTX5MIX Input 2 Source */
+ { 0x000007e3, 0x0080 }, /* R2019 (0x7e3) - SLIMTX5MIX Input 2 Volume */
+ { 0x000007e4, 0x0000 }, /* R2020 (0x7e4) - SLIMTX5MIX Input 3 Source */
+ { 0x000007e5, 0x0080 }, /* R2021 (0x7e5) - SLIMTX5MIX Input 3 Volume */
+ { 0x000007e6, 0x0000 }, /* R2022 (0x7e6) - SLIMTX5MIX Input 4 Source */
+ { 0x000007e7, 0x0080 }, /* R2023 (0x7e7) - SLIMTX5MIX Input 4 Volume */
+ { 0x000007e8, 0x0000 }, /* R2024 (0x7e8) - SLIMTX6MIX Input 1 Source */
+ { 0x000007e9, 0x0080 }, /* R2025 (0x7e9) - SLIMTX6MIX Input 1 Volume */
+ { 0x000007ea, 0x0000 }, /* R2026 (0x7ea) - SLIMTX6MIX Input 2 Source */
+ { 0x000007eb, 0x0080 }, /* R2027 (0x7eb) - SLIMTX6MIX Input 2 Volume */
+ { 0x000007ec, 0x0000 }, /* R2028 (0x7ec) - SLIMTX6MIX Input 3 Source */
+ { 0x000007ed, 0x0080 }, /* R2029 (0x7ed) - SLIMTX6MIX Input 3 Volume */
+ { 0x000007ee, 0x0000 }, /* R2030 (0x7ee) - SLIMTX6MIX Input 4 Source */
+ { 0x000007ef, 0x0080 }, /* R2031 (0x7ef) - SLIMTX6MIX Input 4 Volume */
+ { 0x000007f0, 0x0000 }, /* R2032 (0x7f0) - SLIMTX7MIX Input 1 Source */
+ { 0x000007f1, 0x0080 }, /* R2033 (0x7f1) - SLIMTX7MIX Input 1 Volume */
+ { 0x000007f2, 0x0000 }, /* R2034 (0x7f2) - SLIMTX7MIX Input 2 Source */
+ { 0x000007f3, 0x0080 }, /* R2035 (0x7f3) - SLIMTX7MIX Input 2 Volume */
+ { 0x000007f4, 0x0000 }, /* R2036 (0x7f4) - SLIMTX7MIX Input 3 Source */
+ { 0x000007f5, 0x0080 }, /* R2037 (0x7f5) - SLIMTX7MIX Input 3 Volume */
+ { 0x000007f6, 0x0000 }, /* R2038 (0x7f6) - SLIMTX7MIX Input 4 Source */
+ { 0x000007f7, 0x0080 }, /* R2039 (0x7f7) - SLIMTX7MIX Input 4 Volume */
+ { 0x000007f8, 0x0000 }, /* R2040 (0x7f8) - SLIMTX8MIX Input 1 Source */
+ { 0x000007f9, 0x0080 }, /* R2041 (0x7f9) - SLIMTX8MIX Input 1 Volume */
+ { 0x000007fa, 0x0000 }, /* R2042 (0x7fa) - SLIMTX8MIX Input 2 Source */
+ { 0x000007fb, 0x0080 }, /* R2043 (0x7fb) - SLIMTX8MIX Input 2 Volume */
+ { 0x000007fc, 0x0000 }, /* R2044 (0x7fc) - SLIMTX8MIX Input 3 Source */
+ { 0x000007fd, 0x0080 }, /* R2045 (0x7fd) - SLIMTX8MIX Input 3 Volume */
+ { 0x000007fe, 0x0000 }, /* R2046 (0x7fe) - SLIMTX8MIX Input 4 Source */
+ { 0x000007ff, 0x0080 }, /* R2047 (0x7ff) - SLIMTX8MIX Input 4 Volume */
+ { 0x00000800, 0x0000 }, /* R2048 (0x800) - SPDIF1TX1MIX Input 1 Source */
+ { 0x00000801, 0x0080 }, /* R2049 (0x801) - SPDIF1TX1MIX Input 1 Volume */
+ { 0x00000808, 0x0000 }, /* R2056 (0x808) - SPDIF1TX2MIX Input 1 Source */
+ { 0x00000809, 0x0080 }, /* R2057 (0x809) - SPDIF1TX2MIX Input 1 Volume */
+ { 0x00000880, 0x0000 }, /* R2176 (0x880) - EQ1MIX Input 1 Source */
+ { 0x00000881, 0x0080 }, /* R2177 (0x881) - EQ1MIX Input 1 Volume */
+ { 0x00000882, 0x0000 }, /* R2178 (0x882) - EQ1MIX Input 2 Source */
+ { 0x00000883, 0x0080 }, /* R2179 (0x883) - EQ1MIX Input 2 Volume */
+ { 0x00000884, 0x0000 }, /* R2180 (0x884) - EQ1MIX Input 3 Source */
+ { 0x00000885, 0x0080 }, /* R2181 (0x885) - EQ1MIX Input 3 Volume */
+ { 0x00000886, 0x0000 }, /* R2182 (0x886) - EQ1MIX Input 4 Source */
+ { 0x00000887, 0x0080 }, /* R2183 (0x887) - EQ1MIX Input 4 Volume */
+ { 0x00000888, 0x0000 }, /* R2184 (0x888) - EQ2MIX Input 1 Source */
+ { 0x00000889, 0x0080 }, /* R2185 (0x889) - EQ2MIX Input 1 Volume */
+ { 0x0000088a, 0x0000 }, /* R2186 (0x88a) - EQ2MIX Input 2 Source */
+ { 0x0000088b, 0x0080 }, /* R2187 (0x88b) - EQ2MIX Input 2 Volume */
+ { 0x0000088c, 0x0000 }, /* R2188 (0x88c) - EQ2MIX Input 3 Source */
+ { 0x0000088d, 0x0080 }, /* R2189 (0x88d) - EQ2MIX Input 3 Volume */
+ { 0x0000088e, 0x0000 }, /* R2190 (0x88e) - EQ2MIX Input 4 Source */
+ { 0x0000088f, 0x0080 }, /* R2191 (0x88f) - EQ2MIX Input 4 Volume */
+ { 0x00000890, 0x0000 }, /* R2192 (0x890) - EQ3MIX Input 1 Source */
+ { 0x00000891, 0x0080 }, /* R2193 (0x891) - EQ3MIX Input 1 Volume */
+ { 0x00000892, 0x0000 }, /* R2194 (0x892) - EQ3MIX Input 2 Source */
+ { 0x00000893, 0x0080 }, /* R2195 (0x893) - EQ3MIX Input 2 Volume */
+ { 0x00000894, 0x0000 }, /* R2196 (0x894) - EQ3MIX Input 3 Source */
+ { 0x00000895, 0x0080 }, /* R2197 (0x895) - EQ3MIX Input 3 Volume */
+ { 0x00000896, 0x0000 }, /* R2198 (0x896) - EQ3MIX Input 4 Source */
+ { 0x00000897, 0x0080 }, /* R2199 (0x897) - EQ3MIX Input 4 Volume */
+ { 0x00000898, 0x0000 }, /* R2200 (0x898) - EQ4MIX Input 1 Source */
+ { 0x00000899, 0x0080 }, /* R2201 (0x899) - EQ4MIX Input 1 Volume */
+ { 0x0000089a, 0x0000 }, /* R2202 (0x89a) - EQ4MIX Input 2 Source */
+ { 0x0000089b, 0x0080 }, /* R2203 (0x89b) - EQ4MIX Input 2 Volume */
+ { 0x0000089c, 0x0000 }, /* R2204 (0x89c) - EQ4MIX Input 3 Source */
+ { 0x0000089d, 0x0080 }, /* R2205 (0x89d) - EQ4MIX Input 3 Volume */
+ { 0x0000089e, 0x0000 }, /* R2206 (0x89e) - EQ4MIX Input 4 Source */
+ { 0x0000089f, 0x0080 }, /* R2207 (0x89f) - EQ4MIX Input 4 Volume */
+ { 0x000008c0, 0x0000 }, /* R2240 (0x8c0) - DRC1LMIX Input 1 Source */
+ { 0x000008c1, 0x0080 }, /* R2241 (0x8c1) - DRC1LMIX Input 1 Volume */
+ { 0x000008c2, 0x0000 }, /* R2242 (0x8c2) - DRC1LMIX Input 2 Source */
+ { 0x000008c3, 0x0080 }, /* R2243 (0x8c3) - DRC1LMIX Input 2 Volume */
+ { 0x000008c4, 0x0000 }, /* R2244 (0x8c4) - DRC1LMIX Input 3 Source */
+ { 0x000008c5, 0x0080 }, /* R2245 (0x8c5) - DRC1LMIX Input 3 Volume */
+ { 0x000008c6, 0x0000 }, /* R2246 (0x8c6) - DRC1LMIX Input 4 Source */
+ { 0x000008c7, 0x0080 }, /* R2247 (0x8c7) - DRC1LMIX Input 4 Volume */
+ { 0x000008c8, 0x0000 }, /* R2248 (0x8c8) - DRC1RMIX Input 1 Source */
+ { 0x000008c9, 0x0080 }, /* R2249 (0x8c9) - DRC1RMIX Input 1 Volume */
+ { 0x000008ca, 0x0000 }, /* R2250 (0x8ca) - DRC1RMIX Input 2 Source */
+ { 0x000008cb, 0x0080 }, /* R2251 (0x8cb) - DRC1RMIX Input 2 Volume */
+ { 0x000008cc, 0x0000 }, /* R2252 (0x8cc) - DRC1RMIX Input 3 Source */
+ { 0x000008cd, 0x0080 }, /* R2253 (0x8cd) - DRC1RMIX Input 3 Volume */
+ { 0x000008ce, 0x0000 }, /* R2254 (0x8ce) - DRC1RMIX Input 4 Source */
+ { 0x000008cf, 0x0080 }, /* R2255 (0x8cf) - DRC1RMIX Input 4 Volume */
+ { 0x000008d0, 0x0000 }, /* R2256 (0x8d0) - DRC2LMIX Input 1 Source */
+ { 0x000008d1, 0x0080 }, /* R2257 (0x8d1) - DRC2LMIX Input 1 Volume */
+ { 0x000008d2, 0x0000 }, /* R2258 (0x8d2) - DRC2LMIX Input 2 Source */
+ { 0x000008d3, 0x0080 }, /* R2259 (0x8d3) - DRC2LMIX Input 2 Volume */
+ { 0x000008d4, 0x0000 }, /* R2260 (0x8d4) - DRC2LMIX Input 3 Source */
+ { 0x000008d5, 0x0080 }, /* R2261 (0x8d5) - DRC2LMIX Input 3 Volume */
+ { 0x000008d6, 0x0000 }, /* R2262 (0x8d6) - DRC2LMIX Input 4 Source */
+ { 0x000008d7, 0x0080 }, /* R2263 (0x8d7) - DRC2LMIX Input 4 Volume */
+ { 0x000008d8, 0x0000 }, /* R2264 (0x8d8) - DRC2RMIX Input 1 Source */
+ { 0x000008d9, 0x0080 }, /* R2265 (0x8d9) - DRC2RMIX Input 1 Volume */
+ { 0x000008da, 0x0000 }, /* R2266 (0x8da) - DRC2RMIX Input 2 Source */
+ { 0x000008db, 0x0080 }, /* R2267 (0x8db) - DRC2RMIX Input 2 Volume */
+ { 0x000008dc, 0x0000 }, /* R2268 (0x8dc) - DRC2RMIX Input 3 Source */
+ { 0x000008dd, 0x0080 }, /* R2269 (0x8dd) - DRC2RMIX Input 3 Volume */
+ { 0x000008de, 0x0000 }, /* R2270 (0x8de) - DRC2RMIX Input 4 Source */
+ { 0x000008df, 0x0080 }, /* R2271 (0x8df) - DRC2RMIX Input 4 Volume */
+ { 0x00000900, 0x0000 }, /* R2304 (0x900) - HPLP1MIX Input 1 Source */
+ { 0x00000901, 0x0080 }, /* R2305 (0x901) - HPLP1MIX Input 1 Volume */
+ { 0x00000902, 0x0000 }, /* R2306 (0x902) - HPLP1MIX Input 2 Source */
+ { 0x00000903, 0x0080 }, /* R2307 (0x903) - HPLP1MIX Input 2 Volume */
+ { 0x00000904, 0x0000 }, /* R2308 (0x904) - HPLP1MIX Input 3 Source */
+ { 0x00000905, 0x0080 }, /* R2309 (0x905) - HPLP1MIX Input 3 Volume */
+ { 0x00000906, 0x0000 }, /* R2310 (0x906) - HPLP1MIX Input 4 Source */
+ { 0x00000907, 0x0080 }, /* R2311 (0x907) - HPLP1MIX Input 4 Volume */
+ { 0x00000908, 0x0000 }, /* R2312 (0x908) - HPLP2MIX Input 1 Source */
+ { 0x00000909, 0x0080 }, /* R2313 (0x909) - HPLP2MIX Input 1 Volume */
+ { 0x0000090a, 0x0000 }, /* R2314 (0x90a) - HPLP2MIX Input 2 Source */
+ { 0x0000090b, 0x0080 }, /* R2315 (0x90b) - HPLP2MIX Input 2 Volume */
+ { 0x0000090c, 0x0000 }, /* R2316 (0x90c) - HPLP2MIX Input 3 Source */
+ { 0x0000090d, 0x0080 }, /* R2317 (0x90d) - HPLP2MIX Input 3 Volume */
+ { 0x0000090e, 0x0000 }, /* R2318 (0x90e) - HPLP2MIX Input 4 Source */
+ { 0x0000090f, 0x0080 }, /* R2319 (0x90f) - HPLP2MIX Input 4 Volume */
+ { 0x00000910, 0x0000 }, /* R2320 (0x910) - HPLP3MIX Input 1 Source */
+ { 0x00000911, 0x0080 }, /* R2321 (0x911) - HPLP3MIX Input 1 Volume */
+ { 0x00000912, 0x0000 }, /* R2322 (0x912) - HPLP3MIX Input 2 Source */
+ { 0x00000913, 0x0080 }, /* R2323 (0x913) - HPLP3MIX Input 2 Volume */
+ { 0x00000914, 0x0000 }, /* R2324 (0x914) - HPLP3MIX Input 3 Source */
+ { 0x00000915, 0x0080 }, /* R2325 (0x915) - HPLP3MIX Input 3 Volume */
+ { 0x00000916, 0x0000 }, /* R2326 (0x916) - HPLP3MIX Input 4 Source */
+ { 0x00000917, 0x0080 }, /* R2327 (0x917) - HPLP3MIX Input 4 Volume */
+ { 0x00000918, 0x0000 }, /* R2328 (0x918) - HPLP4MIX Input 1 Source */
+ { 0x00000919, 0x0080 }, /* R2329 (0x919) - HPLP4MIX Input 1 Volume */
+ { 0x0000091a, 0x0000 }, /* R2330 (0x91a) - HPLP4MIX Input 2 Source */
+ { 0x0000091b, 0x0080 }, /* R2331 (0x91b) - HPLP4MIX Input 2 Volume */
+ { 0x0000091c, 0x0000 }, /* R2332 (0x91c) - HPLP4MIX Input 3 Source */
+ { 0x0000091d, 0x0080 }, /* R2333 (0x91d) - HPLP4MIX Input 3 Volume */
+ { 0x0000091e, 0x0000 }, /* R2334 (0x91e) - HPLP4MIX Input 4 Source */
+ { 0x0000091f, 0x0080 }, /* R2335 (0x91f) - HPLP4MIX Input 4 Volume */
+ { 0x00000940, 0x0000 }, /* R2368 (0x940) - DSP1LMIX Input 1 Source */
+ { 0x00000941, 0x0080 }, /* R2369 (0x941) - DSP1LMIX Input 1 Volume */
+ { 0x00000942, 0x0000 }, /* R2370 (0x942) - DSP1LMIX Input 2 Source */
+ { 0x00000943, 0x0080 }, /* R2371 (0x943) - DSP1LMIX Input 2 Volume */
+ { 0x00000944, 0x0000 }, /* R2372 (0x944) - DSP1LMIX Input 3 Source */
+ { 0x00000945, 0x0080 }, /* R2373 (0x945) - DSP1LMIX Input 3 Volume */
+ { 0x00000946, 0x0000 }, /* R2374 (0x946) - DSP1LMIX Input 4 Source */
+ { 0x00000947, 0x0080 }, /* R2375 (0x947) - DSP1LMIX Input 4 Volume */
+ { 0x00000948, 0x0000 }, /* R2376 (0x948) - DSP1RMIX Input 1 Source */
+ { 0x00000949, 0x0080 }, /* R2377 (0x949) - DSP1RMIX Input 1 Volume */
+ { 0x0000094a, 0x0000 }, /* R2378 (0x94a) - DSP1RMIX Input 2 Source */
+ { 0x0000094b, 0x0080 }, /* R2379 (0x94b) - DSP1RMIX Input 2 Volume */
+ { 0x0000094c, 0x0000 }, /* R2380 (0x94c) - DSP1RMIX Input 3 Source */
+ { 0x0000094d, 0x0080 }, /* R2381 (0x94d) - DSP1RMIX Input 3 Volume */
+ { 0x0000094e, 0x0000 }, /* R2382 (0x94e) - DSP1RMIX Input 4 Source */
+ { 0x0000094f, 0x0080 }, /* R2383 (0x94f) - DSP1RMIX Input 4 Volume */
+ { 0x00000950, 0x0000 }, /* R2384 (0x950) - DSP1AUX1MIX Input 1 Source */
+ { 0x00000958, 0x0000 }, /* R2392 (0x958) - DSP1AUX2MIX Input 1 Source */
+ { 0x00000960, 0x0000 }, /* R2400 (0x960) - DSP1AUX3MIX Input 1 Source */
+ { 0x00000968, 0x0000 }, /* R2408 (0x968) - DSP1AUX4MIX Input 1 Source */
+ { 0x00000970, 0x0000 }, /* R2416 (0x970) - DSP1AUX5MIX Input 1 Source */
+ { 0x00000978, 0x0000 }, /* R2424 (0x978) - DSP1AUX6MIX Input 1 Source */
+ { 0x00000a80, 0x0000 }, /* R2688 (0xa80) - ASRC1 1LMIX Input 1 Source */
+ { 0x00000a88, 0x0000 }, /* R2696 (0xa88) - ASRC1 1RMIX Input 1 Source */
+ { 0x00000a90, 0x0000 }, /* R2704 (0xa90) - ASRC1 2LMIX Input 1 Source */
+ { 0x00000a98, 0x0000 }, /* R2712 (0xa98) - ASRC1 2RMIX Input 1 Source */
+ { 0x00000b00, 0x0000 }, /* R2816 (0xb00) - ISRC1DEC1MIX Input 1 Source */
+ { 0x00000b08, 0x0000 }, /* R2824 (0xb08) - ISRC1DEC2MIX Input 1 Source */
+ { 0x00000b20, 0x0000 }, /* R2848 (0xb20) - ISRC1INT1MIX Input 1 Source */
+ { 0x00000b28, 0x0000 }, /* R2856 (0xb28) - ISRC1INT2MIX Input 1 Source */
+ { 0x00000b40, 0x0000 }, /* R2880 (0xb40) - ISRC2DEC1MIX Input 1 Source */
+ { 0x00000b48, 0x0000 }, /* R2888 (0xb48) - ISRC2DEC2MIX Input 1 Source */
+ { 0x00000b60, 0x0000 }, /* R2912 (0xb60) - ISRC2INT1MIX Input 1 Source */
+ { 0x00000b68, 0x0000 }, /* R2920 (0xb68) - ISRC2INT2MIX Input 1 Source */
+ { 0x00000dc0, 0x0000 }, /* R3520 (0xdc0) - DFC1MIX Input 1 Source */
+ { 0x00000dc8, 0x0000 }, /* R3528 (0xdc8) - DFC2MIX Input 1 Source */
+ { 0x00000dd0, 0x0000 }, /* R3536 (0xdd0) - DFC3MIX Input 1 Source */
+ { 0x00000dd8, 0x0000 }, /* R3544 (0xdd8) - DFC4MIX Input 1 Source */
+ { 0x00000de0, 0x0000 }, /* R3552 (0xde0) - DFC5MIX Input 1 Source */
+ { 0x00000de8, 0x0000 }, /* R3560 (0xde8) - DFC6MIX Input 1 Source */
+ { 0x00000df0, 0x0000 }, /* R3568 (0xdf0) - DFC7MIX Input 1 Source */
+ { 0x00000df8, 0x0000 }, /* R3576 (0xdf8) - DFC8MIX Input 1 Source */
+ { 0x00000e00, 0x0000 }, /* R3584 (0xe00) - FX Ctrl 1 */
+ { 0x00000e10, 0x6318 }, /* R3600 (0xe10) - EQ1 1 */
+ { 0x00000e11, 0x6300 }, /* R3601 (0xe11) - EQ1 2 */
+ { 0x00000e12, 0x0fc8 }, /* R3602 (0xe12) - EQ1 3 */
+ { 0x00000e13, 0x03fe }, /* R3603 (0xe13) - EQ1 4 */
+ { 0x00000e14, 0x00e0 }, /* R3604 (0xe14) - EQ1 5 */
+ { 0x00000e15, 0x1ec4 }, /* R3605 (0xe15) - EQ1 6 */
+ { 0x00000e16, 0xf136 }, /* R3606 (0xe16) - EQ1 7 */
+ { 0x00000e17, 0x0409 }, /* R3607 (0xe17) - EQ1 8 */
+ { 0x00000e18, 0x04cc }, /* R3608 (0xe18) - EQ1 9 */
+ { 0x00000e19, 0x1c9b }, /* R3609 (0xe19) - EQ1 10 */
+ { 0x00000e1a, 0xf337 }, /* R3610 (0xe1a) - EQ1 11 */
+ { 0x00000e1b, 0x040b }, /* R3611 (0xe1b) - EQ1 12 */
+ { 0x00000e1c, 0x0cbb }, /* R3612 (0xe1c) - EQ1 13 */
+ { 0x00000e1d, 0x16f8 }, /* R3613 (0xe1d) - EQ1 14 */
+ { 0x00000e1e, 0xf7d9 }, /* R3614 (0xe1e) - EQ1 15 */
+ { 0x00000e1f, 0x040a }, /* R3615 (0xe1f) - EQ1 16 */
+ { 0x00000e20, 0x1f14 }, /* R3616 (0xe20) - EQ1 17 */
+ { 0x00000e21, 0x058c }, /* R3617 (0xe21) - EQ1 18 */
+ { 0x00000e22, 0x0563 }, /* R3618 (0xe22) - EQ1 19 */
+ { 0x00000e23, 0x4000 }, /* R3619 (0xe23) - EQ1 20 */
+ { 0x00000e24, 0x0b75 }, /* R3620 (0xe24) - EQ1 21 */
+ { 0x00000e26, 0x6318 }, /* R3622 (0xe26) - EQ2 1 */
+ { 0x00000e27, 0x6300 }, /* R3623 (0xe27) - EQ2 2 */
+ { 0x00000e28, 0x0fc8 }, /* R3624 (0xe28) - EQ2 3 */
+ { 0x00000e29, 0x03fe }, /* R3625 (0xe29) - EQ2 4 */
+ { 0x00000e2a, 0x00e0 }, /* R3626 (0xe2a) - EQ2 5 */
+ { 0x00000e2b, 0x1ec4 }, /* R3627 (0xe2b) - EQ2 6 */
+ { 0x00000e2c, 0xf136 }, /* R3628 (0xe2c) - EQ2 7 */
+ { 0x00000e2d, 0x0409 }, /* R3629 (0xe2d) - EQ2 8 */
+ { 0x00000e2e, 0x04cc }, /* R3630 (0xe2e) - EQ2 9 */
+ { 0x00000e2f, 0x1c9b }, /* R3631 (0xe2f) - EQ2 10 */
+ { 0x00000e30, 0xf337 }, /* R3632 (0xe30) - EQ2 11 */
+ { 0x00000e31, 0x040b }, /* R3633 (0xe31) - EQ2 12 */
+ { 0x00000e32, 0x0cbb }, /* R3634 (0xe32) - EQ2 13 */
+ { 0x00000e33, 0x16f8 }, /* R3635 (0xe33) - EQ2 14 */
+ { 0x00000e34, 0xf7d9 }, /* R3636 (0xe34) - EQ2 15 */
+ { 0x00000e35, 0x040a }, /* R3637 (0xe35) - EQ2 16 */
+ { 0x00000e36, 0x1f14 }, /* R3638 (0xe36) - EQ2 17 */
+ { 0x00000e37, 0x058c }, /* R3639 (0xe37) - EQ2 18 */
+ { 0x00000e38, 0x0563 }, /* R3640 (0xe38) - EQ2 19 */
+ { 0x00000e39, 0x4000 }, /* R3641 (0xe39) - EQ2 20 */
+ { 0x00000e3a, 0x0b75 }, /* R3642 (0xe3a) - EQ2 21 */
+ { 0x00000e3c, 0x6318 }, /* R3644 (0xe3c) - EQ3 1 */
+ { 0x00000e3d, 0x6300 }, /* R3645 (0xe3d) - EQ3 2 */
+ { 0x00000e3e, 0x0fc8 }, /* R3646 (0xe3e) - EQ3 3 */
+ { 0x00000e3f, 0x03fe }, /* R3647 (0xe3f) - EQ3 4 */
+ { 0x00000e40, 0x00e0 }, /* R3648 (0xe40) - EQ3 5 */
+ { 0x00000e41, 0x1ec4 }, /* R3649 (0xe41) - EQ3 6 */
+ { 0x00000e42, 0xf136 }, /* R3650 (0xe42) - EQ3 7 */
+ { 0x00000e43, 0x0409 }, /* R3651 (0xe43) - EQ3 8 */
+ { 0x00000e44, 0x04cc }, /* R3652 (0xe44) - EQ3 9 */
+ { 0x00000e45, 0x1c9b }, /* R3653 (0xe45) - EQ3 10 */
+ { 0x00000e46, 0xf337 }, /* R3654 (0xe46) - EQ3 11 */
+ { 0x00000e47, 0x040b }, /* R3655 (0xe47) - EQ3 12 */
+ { 0x00000e48, 0x0cbb }, /* R3656 (0xe48) - EQ3 13 */
+ { 0x00000e49, 0x16f8 }, /* R3657 (0xe49) - EQ3 14 */
+ { 0x00000e4a, 0xf7d9 }, /* R3658 (0xe4a) - EQ3 15 */
+ { 0x00000e4b, 0x040a }, /* R3659 (0xe4b) - EQ3 16 */
+ { 0x00000e4c, 0x1f14 }, /* R3660 (0xe4c) - EQ3 17 */
+ { 0x00000e4d, 0x058c }, /* R3661 (0xe4d) - EQ3 18 */
+ { 0x00000e4e, 0x0563 }, /* R3662 (0xe4e) - EQ3 19 */
+ { 0x00000e4f, 0x4000 }, /* R3663 (0xe4f) - EQ3 20 */
+ { 0x00000e50, 0x0b75 }, /* R3664 (0xe50) - EQ3 21 */
+ { 0x00000e52, 0x6318 }, /* R3666 (0xe52) - EQ4 1 */
+ { 0x00000e53, 0x6300 }, /* R3667 (0xe53) - EQ4 2 */
+ { 0x00000e54, 0x0fc8 }, /* R3668 (0xe54) - EQ4 3 */
+ { 0x00000e55, 0x03fe }, /* R3669 (0xe55) - EQ4 4 */
+ { 0x00000e56, 0x00e0 }, /* R3670 (0xe56) - EQ4 5 */
+ { 0x00000e57, 0x1ec4 }, /* R3671 (0xe57) - EQ4 6 */
+ { 0x00000e58, 0xf136 }, /* R3672 (0xe58) - EQ4 7 */
+ { 0x00000e59, 0x0409 }, /* R3673 (0xe59) - EQ4 8 */
+ { 0x00000e5a, 0x04cc }, /* R3674 (0xe5a) - EQ4 9 */
+ { 0x00000e5b, 0x1c9b }, /* R3675 (0xe5b) - EQ4 10 */
+ { 0x00000e5c, 0xf337 }, /* R3676 (0xe5c) - EQ4 11 */
+ { 0x00000e5d, 0x040b }, /* R3677 (0xe5d) - EQ4 12 */
+ { 0x00000e5e, 0x0cbb }, /* R3678 (0xe5e) - EQ4 13 */
+ { 0x00000e5f, 0x16f8 }, /* R3679 (0xe5f) - EQ4 14 */
+ { 0x00000e60, 0xf7d9 }, /* R3680 (0xe60) - EQ4 15 */
+ { 0x00000e61, 0x040a }, /* R3681 (0xe61) - EQ4 16 */
+ { 0x00000e62, 0x1f14 }, /* R3682 (0xe62) - EQ4 17 */
+ { 0x00000e63, 0x058c }, /* R3683 (0xe63) - EQ4 18 */
+ { 0x00000e64, 0x0563 }, /* R3684 (0xe64) - EQ4 19 */
+ { 0x00000e65, 0x4000 }, /* R3685 (0xe65) - EQ4 20 */
+ { 0x00000e66, 0x0b75 }, /* R3686 (0xe66) - EQ4 21 */
+ { 0x00000e80, 0x0018 }, /* R3712 (0xe80) - DRC1 Ctrl 1 */
+ { 0x00000e81, 0x0933 }, /* R3713 (0xe81) - DRC1 Ctrl 2 */
+ { 0x00000e82, 0x0018 }, /* R3714 (0xe82) - DRC1 Ctrl 3 */
+ { 0x00000e83, 0x0000 }, /* R3715 (0xe83) - DRC1 Ctrl 4 */
+ { 0x00000e84, 0x0000 }, /* R3716 (0xe84) - DRC1 Ctrl 5 */
+ { 0x00000e88, 0x0018 }, /* R3720 (0xe88) - DRC2 Ctrl 1 */
+ { 0x00000e89, 0x0933 }, /* R3721 (0xe89) - DRC2 Ctrl 2 */
+ { 0x00000e8a, 0x0018 }, /* R3722 (0xe8a) - DRC2 Ctrl 3 */
+ { 0x00000e8b, 0x0000 }, /* R3723 (0xe8b) - DRC2 Ctrl 4 */
+ { 0x00000e8c, 0x0000 }, /* R3724 (0xe8c) - DRC2 Ctrl 5 */
+ { 0x00000ec0, 0x0000 }, /* R3776 (0xec0) - HPLPF1 1 */
+ { 0x00000ec1, 0x0000 }, /* R3777 (0xec1) - HPLPF1 2 */
+ { 0x00000ec4, 0x0000 }, /* R3780 (0xec4) - HPLPF2 1 */
+ { 0x00000ec5, 0x0000 }, /* R3781 (0xec5) - HPLPF2 2 */
+ { 0x00000ec8, 0x0000 }, /* R3784 (0xec8) - HPLPF3 1 */
+ { 0x00000ec9, 0x0000 }, /* R3785 (0xec9) - HPLPF3 2 */
+ { 0x00000ecc, 0x0000 }, /* R3788 (0xecc) - HPLPF4 1 */
+ { 0x00000ecd, 0x0000 }, /* R3789 (0xecd) - HPLPF4 2 */
+ { 0x00000ee0, 0x0000 }, /* R3808 (0xee0) - ASRC1 Enable */
+ { 0x00000ee2, 0x0000 }, /* R3810 (0xee2) - ASRC1 Rate 1 */
+ { 0x00000ee3, 0x4000 }, /* R3811 (0xee3) - ASRC1 Rate 2 */
+ { 0x00000ef0, 0x0000 }, /* R3824 (0xef0) - ISRC1 Ctrl 1 */
+ { 0x00000ef1, 0x0001 }, /* R3825 (0xef1) - ISRC1 Ctrl 2 */
+ { 0x00000ef2, 0x0000 }, /* R3826 (0xef2) - ISRC1 Ctrl 3 */
+ { 0x00000ef3, 0x0000 }, /* R3827 (0xef3) - ISRC2 Ctrl 1 */
+ { 0x00000ef4, 0x0001 }, /* R3828 (0xef4) - ISRC2 Ctrl 2 */
+ { 0x00000ef5, 0x0000 }, /* R3829 (0xef5) - ISRC2 Ctrl 3 */
+ { 0x000010c0, 0x0008 }, /* R4288 (0x10c0) - AUXPDM1 Ctrl 0 */
+ { 0x000010c1, 0x4000 }, /* R4289 (0x10c1) - AUXPDM1 Ctrl 1 */
+ { 0x00001480, 0x0000 }, /* R5248 (0x1480) - DFC1 Ctrl W0 */
+ { 0x00001482, 0x1f00 }, /* R5250 (0x1482) - DFC1 Rx W0 */
+ { 0x00001484, 0x1f00 }, /* R5252 (0x1484) - DFC1 Tx W0 */
+ { 0x00001486, 0x0000 }, /* R5254 (0x1486) - DFC2 Ctrl W0 */
+ { 0x00001488, 0x1f00 }, /* R5256 (0x1488) - DFC2 Rx W0 */
+ { 0x0000148a, 0x1f00 }, /* R5258 (0x148a) - DFC2 Tx W0 */
+ { 0x0000148c, 0x0000 }, /* R5260 (0x148c) - DFC3 Ctrl W0 */
+ { 0x0000148e, 0x1f00 }, /* R5262 (0x148e) - DFC3 Rx W0 */
+ { 0x00001490, 0x1f00 }, /* R5264 (0x1490) - DFC3 Tx W0 */
+ { 0x00001492, 0x0000 }, /* R5266 (0x1492) - DFC4 Ctrl W0 */
+ { 0x00001494, 0x1f00 }, /* R5268 (0x1494) - DFC4 Rx W0 */
+ { 0x00001496, 0x1f00 }, /* R5270 (0x1496) - DFC4 Tx W0 */
+ { 0x00001498, 0x0000 }, /* R5272 (0x1498) - DFC5 Ctrl W0 */
+ { 0x0000149a, 0x1f00 }, /* R5274 (0x149a) - DFC5 Rx W0 */
+ { 0x0000149c, 0x1f00 }, /* R5276 (0x149c) - DFC5 Tx W0 */
+ { 0x0000149e, 0x0000 }, /* R5278 (0x149e) - DFC6 Ctrl W0 */
+ { 0x000014a0, 0x1f00 }, /* R5280 (0x14a0) - DFC6 Rx W0 */
+ { 0x000014a2, 0x1f00 }, /* R5282 (0x14a2) - DFC6 Tx W0 */
+ { 0x000014a4, 0x0000 }, /* R5284 (0x14a4) - DFC7 Ctrl W0 */
+ { 0x000014a6, 0x1f00 }, /* R5286 (0x14a6) - DFC7 Rx W0 */
+ { 0x000014a8, 0x1f00 }, /* R5288 (0x14a8) - DFC7 Tx W0 */
+ { 0x000014aa, 0x0000 }, /* R5290 (0x14aa) - DFC8 Ctrl W0 */
+ { 0x000014ac, 0x1f00 }, /* R5292 (0x14ac) - DFC8 Rx W0 */
+ { 0x000014ae, 0x1f00 }, /* R5294 (0x14ae) - DFC8 Tx W0 */
+ { 0x00001700, 0x2001 }, /* R5888 (0x1700) - GPIO1 Ctrl 1 */
+ { 0x00001701, 0xf000 }, /* R5889 (0x1701) - GPIO1 Ctrl 2 */
+ { 0x00001702, 0x2001 }, /* R5890 (0x1702) - GPIO2 Ctrl 1 */
+ { 0x00001703, 0xf000 }, /* R5891 (0x1703) - GPIO2 Ctrl 2 */
+ { 0x00001704, 0x2001 }, /* R5892 (0x1704) - GPIO3 Ctrl 1 */
+ { 0x00001705, 0xf000 }, /* R5893 (0x1705) - GPIO3 Ctrl 2 */
+ { 0x00001706, 0x2001 }, /* R5894 (0x1706) - GPIO4 Ctrl 1 */
+ { 0x00001707, 0xf000 }, /* R5895 (0x1707) - GPIO4 Ctrl 2 */
+ { 0x00001708, 0x2001 }, /* R5896 (0x1708) - GPIO5 Ctrl 1 */
+ { 0x00001709, 0xf000 }, /* R5897 (0x1709) - GPIO5 Ctrl 2 */
+ { 0x0000170a, 0x2001 }, /* R5898 (0x170a) - GPIO6 Ctrl 1 */
+ { 0x0000170b, 0xf000 }, /* R5899 (0x170b) - GPIO6 Ctrl 2 */
+ { 0x0000170c, 0x2001 }, /* R5900 (0x170c) - GPIO7 Ctrl 1 */
+ { 0x0000170d, 0xf000 }, /* R5901 (0x170d) - GPIO7 Ctrl 2 */
+ { 0x0000170e, 0x2001 }, /* R5902 (0x170e) - GPIO8 Ctrl 1 */
+ { 0x0000170f, 0xf000 }, /* R5903 (0x170f) - GPIO8 Ctrl 2 */
+ { 0x00001710, 0x2001 }, /* R5904 (0x1710) - GPIO9 Ctrl 1 */
+ { 0x00001711, 0xf000 }, /* R5905 (0x1711) - GPIO9 Ctrl 2 */
+ { 0x00001712, 0x2001 }, /* R5906 (0x1712) - GPIO10 Ctrl 1 */
+ { 0x00001713, 0xf000 }, /* R5907 (0x1713) - GPIO10 Ctrl 2 */
+ { 0x00001714, 0x2001 }, /* R5908 (0x1714) - GPIO11 Ctrl 1 */
+ { 0x00001715, 0xf000 }, /* R5909 (0x1715) - GPIO11 Ctrl 2 */
+ { 0x00001716, 0x2001 }, /* R5910 (0x1716) - GPIO12 Ctrl 1 */
+ { 0x00001717, 0xf000 }, /* R5911 (0x1717) - GPIO12 Ctrl 2 */
+ { 0x00001718, 0x2001 }, /* R5912 (0x1718) - GPIO13 Ctrl 1 */
+ { 0x00001719, 0xf000 }, /* R5913 (0x1719) - GPIO13 Ctrl 2 */
+ { 0x0000171a, 0x2001 }, /* R5914 (0x171a) - GPIO14 Ctrl 1 */
+ { 0x0000171b, 0xf000 }, /* R5915 (0x171b) - GPIO14 Ctrl 2 */
+ { 0x0000171c, 0x2001 }, /* R5916 (0x171c) - GPIO15 Ctrl 1 */
+ { 0x0000171d, 0xf000 }, /* R5917 (0x171d) - GPIO15 Ctrl 2 */
+ { 0x0000171e, 0x2001 }, /* R5918 (0x171e) - GPIO16 Ctrl 1 */
+ { 0x0000171f, 0xf000 }, /* R5919 (0x171f) - GPIO16 Ctrl 2 */
+ { 0x00001840, 0x1200 }, /* R6208 (0x1840) - IRQ1 Mask 1 */
+ { 0x00001841, 0x77e0 }, /* R6209 (0x1841) - IRQ1 Mask 2 */
+ { 0x00001842, 0xffff }, /* R6210 (0x1842) - IRQ1 Mask 3 */
+ { 0x00001843, 0xffff }, /* R6211 (0x1843) - IRQ1 Mask 4 */
+ { 0x00001844, 0xffff }, /* R6212 (0x1844) - IRQ1 Mask 5 */
+ { 0x00001845, 0x0301 }, /* R6213 (0x1845) - IRQ1 Mask 6 */
+ { 0x00001846, 0x0f3f }, /* R6214 (0x1846) - IRQ1 Mask 7 */
+ { 0x00001847, 0xffff }, /* R6215 (0x1847) - IRQ1 Mask 8 */
+ { 0x00001848, 0x031f }, /* R6216 (0x1848) - IRQ1 Mask 9 */
+ { 0x00001849, 0x031f }, /* R6217 (0x1849) - IRQ1 Mask 10 */
+ { 0x0000184a, 0xffff }, /* R6218 (0x184a) - IRQ1 Mask 11 */
+ { 0x0000184b, 0x033f }, /* R6219 (0x184b) - IRQ1 Mask 12 */
+ { 0x0000184c, 0x003f }, /* R6220 (0x184c) - IRQ1 Mask 13 */
+ { 0x0000184d, 0x003f }, /* R6221 (0x184d) - IRQ1 Mask 14 */
+ { 0x0000184e, 0x1000 }, /* R6222 (0x184e) - IRQ1 Mask 15 */
+ { 0x0000184f, 0xffff }, /* R6223 (0x184f) - IRQ1 Mask 16 */
+ { 0x00001850, 0xffff }, /* R6224 (0x1850) - IRQ1 Mask 17 */
+ { 0x00001851, 0xffff }, /* R6225 (0x1851) - IRQ1 Mask 18 */
+ { 0x00001852, 0xffff }, /* R6226 (0x1852) - IRQ1 Mask 19 */
+ { 0x00001853, 0xffff }, /* R6227 (0x1853) - IRQ1 Mask 20 */
+ { 0x00001854, 0x0001 }, /* R6228 (0x1854) - IRQ1 Mask 21 */
+ { 0x00001855, 0x0001 }, /* R6229 (0x1855) - IRQ1 Mask 22 */
+ { 0x00001856, 0x0001 }, /* R6230 (0x1856) - IRQ1 Mask 23 */
+ { 0x00001857, 0x0001 }, /* R6231 (0x1857) - IRQ1 Mask 24 */
+ { 0x00001858, 0x0001 }, /* R6232 (0x1858) - IRQ1 Mask 25 */
+ { 0x00001859, 0xffff }, /* R6233 (0x1859) - IRQ1 Mask 26 */
+ { 0x0000185a, 0x0001 }, /* R6234 (0x185a) - IRQ1 Mask 27 */
+ { 0x0000185b, 0x0001 }, /* R6235 (0x185b) - IRQ1 Mask 28 */
+ { 0x0000185c, 0xffff }, /* R6236 (0x185c) - IRQ1 Mask 29 */
+ { 0x0000185d, 0x0001 }, /* R6237 (0x185d) - IRQ1 Mask 30 */
+ { 0x0000185e, 0xffff }, /* R6238 (0x185e) - IRQ1 Mask 31 */
+ { 0x0000185f, 0xffff }, /* R6239 (0x185f) - IRQ1 Mask 32 */
+ { 0x00001860, 0x0001 }, /* R6240 (0x1860) - IRQ1 Mask 33 */
+ { 0x00001a06, 0x0000 }, /* R6662 (0x1a06) - Interrupt Debounce 7 */
+ { 0x00001a80, 0x4400 }, /* R6784 (0x1a80) - IRQ1 Ctrl */
+};
+
+static bool cs47l92_is_adsp_memory(unsigned int reg)
+{
+ switch (reg) {
+ case 0x080000 ... 0x082ffe:
+ case 0x0a0000 ... 0x0a1ffe:
+ case 0x0c0000 ... 0x0c1ffe:
+ case 0x0e0000 ... 0x0e1ffe:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool cs47l92_16bit_readable_register(struct device *dev,
+ unsigned int reg)
+{
+ switch (reg) {
+ case MADERA_SOFTWARE_RESET:
+ case MADERA_HARDWARE_REVISION:
+ case MADERA_WRITE_SEQUENCER_CTRL_0 ... MADERA_WRITE_SEQUENCER_CTRL_2:
+ case MADERA_TONE_GENERATOR_1 ... MADERA_TONE_GENERATOR_5:
+ case MADERA_PWM_DRIVE_1 ... MADERA_PWM_DRIVE_3:
+ case MADERA_SAMPLE_RATE_SEQUENCE_SELECT_1:
+ case MADERA_SAMPLE_RATE_SEQUENCE_SELECT_2:
+ case MADERA_SAMPLE_RATE_SEQUENCE_SELECT_3:
+ case MADERA_SAMPLE_RATE_SEQUENCE_SELECT_4:
+ case MADERA_HAPTICS_CONTROL_1 ... MADERA_HAPTICS_CONTROL_2:
+ case MADERA_HAPTICS_PHASE_1_INTENSITY:
+ case MADERA_HAPTICS_PHASE_1_DURATION:
+ case MADERA_HAPTICS_PHASE_2_INTENSITY:
+ case MADERA_HAPTICS_PHASE_2_DURATION:
+ case MADERA_HAPTICS_PHASE_3_INTENSITY:
+ case MADERA_HAPTICS_PHASE_3_DURATION:
+ case MADERA_HAPTICS_STATUS:
+ case MADERA_COMFORT_NOISE_GENERATOR:
+ case MADERA_CLOCK_32K_1:
+ case MADERA_SYSTEM_CLOCK_1:
+ case MADERA_SAMPLE_RATE_1 ... MADERA_SAMPLE_RATE_3:
+ case MADERA_SAMPLE_RATE_1_STATUS:
+ case MADERA_SAMPLE_RATE_2_STATUS:
+ case MADERA_SAMPLE_RATE_3_STATUS:
+ case MADERA_ASYNC_CLOCK_1:
+ case MADERA_ASYNC_SAMPLE_RATE_1:
+ case MADERA_ASYNC_SAMPLE_RATE_1_STATUS:
+ case MADERA_ASYNC_SAMPLE_RATE_2:
+ case MADERA_ASYNC_SAMPLE_RATE_2_STATUS:
+ case MADERA_DSP_CLOCK_1:
+ case MADERA_DSP_CLOCK_2:
+ case MADERA_OUTPUT_SYSTEM_CLOCK:
+ case MADERA_OUTPUT_ASYNC_CLOCK:
+ case MADERA_RATE_ESTIMATOR_1 ... MADERA_RATE_ESTIMATOR_5:
+ case MADERA_FLL1_CONTROL_1 ... MADERA_FLL1_CONTROL_6:
+ case CS47L92_FLL1_CONTROL_7 ... CS47L92_FLL1_CONTROL_10:
+ case MADERA_FLL1_CONTROL_11:
+ case MADERA_FLL1_DIGITAL_TEST_1:
+ case MADERA_FLL1_SYNCHRONISER_1 ... MADERA_FLL1_SYNCHRONISER_6:
+ case CS47L92_FLL1_GPIO_CLOCK:
+ case MADERA_FLL2_CONTROL_1 ... MADERA_FLL2_CONTROL_6:
+ case CS47L92_FLL2_CONTROL_7 ... CS47L92_FLL2_CONTROL_10:
+ case MADERA_FLL2_CONTROL_11:
+ case MADERA_FLL2_DIGITAL_TEST_1:
+ case MADERA_FLL2_SYNCHRONISER_1 ... MADERA_FLL2_SYNCHRONISER_6:
+ case CS47L92_FLL2_GPIO_CLOCK:
+ case MADERA_MIC_CHARGE_PUMP_1:
+ case MADERA_LDO2_CONTROL_1:
+ case MADERA_MIC_BIAS_CTRL_1:
+ case MADERA_MIC_BIAS_CTRL_2:
+ case MADERA_MIC_BIAS_CTRL_5:
+ case MADERA_MIC_BIAS_CTRL_6:
+ case MADERA_HP_CTRL_1L:
+ case MADERA_HP_CTRL_1R:
+ case MADERA_HP_CTRL_2L:
+ case MADERA_HP_CTRL_2R:
+ case MADERA_HP_CTRL_3L:
+ case MADERA_HP_CTRL_3R:
+ case MADERA_ACCESSORY_DETECT_MODE_1:
+ case MADERA_HEADPHONE_DETECT_0:
+ case MADERA_HEADPHONE_DETECT_1:
+ case MADERA_HEADPHONE_DETECT_2:
+ case MADERA_HEADPHONE_DETECT_3:
+ case MADERA_HEADPHONE_DETECT_5:
+ case MADERA_MICD_CLAMP_CONTROL:
+ case MADERA_MIC_DETECT_1_CONTROL_0:
+ case MADERA_MIC_DETECT_1_CONTROL_1:
+ case MADERA_MIC_DETECT_1_CONTROL_2:
+ case MADERA_MIC_DETECT_1_CONTROL_3:
+ case MADERA_MIC_DETECT_1_CONTROL_4:
+ case MADERA_MIC_DETECT_1_LEVEL_1 ... MADERA_MIC_DETECT_1_LEVEL_4:
+ case MADERA_MIC_DETECT_2_CONTROL_0:
+ case MADERA_MIC_DETECT_2_CONTROL_1:
+ case MADERA_MIC_DETECT_2_CONTROL_2:
+ case MADERA_MIC_DETECT_2_CONTROL_3:
+ case MADERA_MIC_DETECT_2_CONTROL_4:
+ case MADERA_MIC_DETECT_2_LEVEL_1 ... MADERA_MIC_DETECT_2_LEVEL_4:
+ case MADERA_GP_SWITCH_1:
+ case MADERA_JACK_DETECT_ANALOGUE:
+ case MADERA_INPUT_ENABLES:
+ case MADERA_INPUT_ENABLES_STATUS:
+ case MADERA_INPUT_RATE:
+ case MADERA_INPUT_VOLUME_RAMP:
+ case MADERA_HPF_CONTROL:
+ case MADERA_IN1L_CONTROL:
+ case MADERA_ADC_DIGITAL_VOLUME_1L:
+ case MADERA_DMIC1L_CONTROL:
+ case MADERA_IN1L_RATE_CONTROL:
+ case MADERA_IN1R_CONTROL:
+ case MADERA_ADC_DIGITAL_VOLUME_1R:
+ case MADERA_DMIC1R_CONTROL:
+ case MADERA_IN1R_RATE_CONTROL:
+ case MADERA_IN2L_CONTROL:
+ case MADERA_ADC_DIGITAL_VOLUME_2L:
+ case MADERA_DMIC2L_CONTROL:
+ case MADERA_IN2L_RATE_CONTROL:
+ case MADERA_IN2R_CONTROL:
+ case MADERA_ADC_DIGITAL_VOLUME_2R:
+ case MADERA_DMIC2R_CONTROL:
+ case MADERA_IN2R_RATE_CONTROL:
+ case MADERA_IN3L_CONTROL:
+ case MADERA_ADC_DIGITAL_VOLUME_3L:
+ case MADERA_DMIC3L_CONTROL:
+ case MADERA_IN3L_RATE_CONTROL:
+ case MADERA_IN3R_CONTROL:
+ case MADERA_ADC_DIGITAL_VOLUME_3R:
+ case MADERA_DMIC3R_CONTROL:
+ case MADERA_IN3R_RATE_CONTROL:
+ case MADERA_IN4L_CONTROL:
+ case MADERA_ADC_DIGITAL_VOLUME_4L:
+ case MADERA_DMIC4L_CONTROL:
+ case MADERA_IN4L_RATE_CONTROL:
+ case MADERA_IN4R_CONTROL:
+ case MADERA_ADC_DIGITAL_VOLUME_4R:
+ case MADERA_DMIC4R_CONTROL:
+ case MADERA_IN4R_RATE_CONTROL:
+ case MADERA_OUTPUT_ENABLES_1:
+ case MADERA_OUTPUT_STATUS_1:
+ case MADERA_RAW_OUTPUT_STATUS_1:
+ case MADERA_OUTPUT_RATE_1:
+ case MADERA_OUTPUT_VOLUME_RAMP:
+ case MADERA_OUTPUT_PATH_CONFIG_1L:
+ case MADERA_DAC_DIGITAL_VOLUME_1L:
+ case MADERA_OUTPUT_PATH_CONFIG_1:
+ case MADERA_NOISE_GATE_SELECT_1L:
+ case MADERA_OUTPUT_PATH_CONFIG_1R:
+ case MADERA_DAC_DIGITAL_VOLUME_1R:
+ case MADERA_NOISE_GATE_SELECT_1R:
+ case MADERA_OUTPUT_PATH_CONFIG_2L:
+ case MADERA_DAC_DIGITAL_VOLUME_2L:
+ case MADERA_OUTPUT_PATH_CONFIG_2:
+ case MADERA_NOISE_GATE_SELECT_2L:
+ case MADERA_OUTPUT_PATH_CONFIG_2R:
+ case MADERA_DAC_DIGITAL_VOLUME_2R:
+ case MADERA_NOISE_GATE_SELECT_2R:
+ case MADERA_OUTPUT_PATH_CONFIG_3L:
+ case MADERA_DAC_DIGITAL_VOLUME_3L:
+ case MADERA_OUTPUT_PATH_CONFIG_3:
+ case MADERA_NOISE_GATE_SELECT_3L:
+ case MADERA_OUTPUT_PATH_CONFIG_3R:
+ case MADERA_DAC_DIGITAL_VOLUME_3R:
+ case MADERA_NOISE_GATE_SELECT_3R:
+ case MADERA_OUTPUT_PATH_CONFIG_5L:
+ case MADERA_DAC_DIGITAL_VOLUME_5L:
+ case MADERA_NOISE_GATE_SELECT_5L:
+ case MADERA_OUTPUT_PATH_CONFIG_5R:
+ case MADERA_DAC_DIGITAL_VOLUME_5R:
+ case MADERA_NOISE_GATE_SELECT_5R:
+ case MADERA_DAC_AEC_CONTROL_1 ... MADERA_DAC_AEC_CONTROL_2:
+ case MADERA_NOISE_GATE_CONTROL:
+ case MADERA_PDM_SPK1_CTRL_1 ... MADERA_PDM_SPK1_CTRL_2:
+ case MADERA_HP1_SHORT_CIRCUIT_CTRL:
+ case MADERA_HP2_SHORT_CIRCUIT_CTRL:
+ case MADERA_HP3_SHORT_CIRCUIT_CTRL:
+ case MADERA_AIF1_BCLK_CTRL:
+ case MADERA_AIF1_TX_PIN_CTRL:
+ case MADERA_AIF1_RX_PIN_CTRL:
+ case MADERA_AIF1_RATE_CTRL:
+ case MADERA_AIF1_FORMAT:
+ case MADERA_AIF1_RX_BCLK_RATE:
+ case MADERA_AIF1_FRAME_CTRL_1 ... MADERA_AIF1_FRAME_CTRL_18:
+ case MADERA_AIF1_TX_ENABLES:
+ case MADERA_AIF1_RX_ENABLES:
+ case MADERA_AIF2_BCLK_CTRL:
+ case MADERA_AIF2_TX_PIN_CTRL:
+ case MADERA_AIF2_RX_PIN_CTRL:
+ case MADERA_AIF2_RATE_CTRL:
+ case MADERA_AIF2_FORMAT:
+ case MADERA_AIF2_RX_BCLK_RATE:
+ case MADERA_AIF2_FRAME_CTRL_1 ... MADERA_AIF2_FRAME_CTRL_18:
+ case MADERA_AIF2_TX_ENABLES:
+ case MADERA_AIF2_RX_ENABLES:
+ case MADERA_AIF3_BCLK_CTRL:
+ case MADERA_AIF3_TX_PIN_CTRL:
+ case MADERA_AIF3_RX_PIN_CTRL:
+ case MADERA_AIF3_RATE_CTRL:
+ case MADERA_AIF3_FORMAT:
+ case MADERA_AIF3_RX_BCLK_RATE:
+ case MADERA_AIF3_FRAME_CTRL_1 ... MADERA_AIF3_FRAME_CTRL_18:
+ case MADERA_AIF3_TX_ENABLES:
+ case MADERA_AIF3_RX_ENABLES:
+ case MADERA_SPD1_TX_CONTROL:
+ case MADERA_SPD1_TX_CHANNEL_STATUS_1:
+ case MADERA_SPD1_TX_CHANNEL_STATUS_2:
+ case MADERA_SPD1_TX_CHANNEL_STATUS_3:
+ case MADERA_SLIMBUS_FRAMER_REF_GEAR:
+ case MADERA_SLIMBUS_RATES_1 ... MADERA_SLIMBUS_RATES_8:
+ case MADERA_SLIMBUS_RX_CHANNEL_ENABLE:
+ case MADERA_SLIMBUS_TX_CHANNEL_ENABLE:
+ case MADERA_SLIMBUS_RX_PORT_STATUS:
+ case MADERA_SLIMBUS_TX_PORT_STATUS:
+ case MADERA_PWM1MIX_INPUT_1_SOURCE:
+ case MADERA_PWM1MIX_INPUT_1_VOLUME:
+ case MADERA_PWM1MIX_INPUT_2_SOURCE:
+ case MADERA_PWM1MIX_INPUT_2_VOLUME:
+ case MADERA_PWM1MIX_INPUT_3_SOURCE:
+ case MADERA_PWM1MIX_INPUT_3_VOLUME:
+ case MADERA_PWM1MIX_INPUT_4_SOURCE:
+ case MADERA_PWM1MIX_INPUT_4_VOLUME:
+ case MADERA_PWM2MIX_INPUT_1_SOURCE:
+ case MADERA_PWM2MIX_INPUT_1_VOLUME:
+ case MADERA_PWM2MIX_INPUT_2_SOURCE:
+ case MADERA_PWM2MIX_INPUT_2_VOLUME:
+ case MADERA_PWM2MIX_INPUT_3_SOURCE:
+ case MADERA_PWM2MIX_INPUT_3_VOLUME:
+ case MADERA_PWM2MIX_INPUT_4_SOURCE:
+ case MADERA_PWM2MIX_INPUT_4_VOLUME:
+ case MADERA_OUT1LMIX_INPUT_1_SOURCE:
+ case MADERA_OUT1LMIX_INPUT_1_VOLUME:
+ case MADERA_OUT1LMIX_INPUT_2_SOURCE:
+ case MADERA_OUT1LMIX_INPUT_2_VOLUME:
+ case MADERA_OUT1LMIX_INPUT_3_SOURCE:
+ case MADERA_OUT1LMIX_INPUT_3_VOLUME:
+ case MADERA_OUT1LMIX_INPUT_4_SOURCE:
+ case MADERA_OUT1LMIX_INPUT_4_VOLUME:
+ case MADERA_OUT1RMIX_INPUT_1_SOURCE:
+ case MADERA_OUT1RMIX_INPUT_1_VOLUME:
+ case MADERA_OUT1RMIX_INPUT_2_SOURCE:
+ case MADERA_OUT1RMIX_INPUT_2_VOLUME:
+ case MADERA_OUT1RMIX_INPUT_3_SOURCE:
+ case MADERA_OUT1RMIX_INPUT_3_VOLUME:
+ case MADERA_OUT1RMIX_INPUT_4_SOURCE:
+ case MADERA_OUT1RMIX_INPUT_4_VOLUME:
+ case MADERA_OUT2LMIX_INPUT_1_SOURCE:
+ case MADERA_OUT2LMIX_INPUT_1_VOLUME:
+ case MADERA_OUT2LMIX_INPUT_2_SOURCE:
+ case MADERA_OUT2LMIX_INPUT_2_VOLUME:
+ case MADERA_OUT2LMIX_INPUT_3_SOURCE:
+ case MADERA_OUT2LMIX_INPUT_3_VOLUME:
+ case MADERA_OUT2LMIX_INPUT_4_SOURCE:
+ case MADERA_OUT2LMIX_INPUT_4_VOLUME:
+ case MADERA_OUT2RMIX_INPUT_1_SOURCE:
+ case MADERA_OUT2RMIX_INPUT_1_VOLUME:
+ case MADERA_OUT2RMIX_INPUT_2_SOURCE:
+ case MADERA_OUT2RMIX_INPUT_2_VOLUME:
+ case MADERA_OUT2RMIX_INPUT_3_SOURCE:
+ case MADERA_OUT2RMIX_INPUT_3_VOLUME:
+ case MADERA_OUT2RMIX_INPUT_4_SOURCE:
+ case MADERA_OUT2RMIX_INPUT_4_VOLUME:
+ case MADERA_OUT3LMIX_INPUT_1_SOURCE:
+ case MADERA_OUT3LMIX_INPUT_1_VOLUME:
+ case MADERA_OUT3LMIX_INPUT_2_SOURCE:
+ case MADERA_OUT3LMIX_INPUT_2_VOLUME:
+ case MADERA_OUT3LMIX_INPUT_3_SOURCE:
+ case MADERA_OUT3LMIX_INPUT_3_VOLUME:
+ case MADERA_OUT3LMIX_INPUT_4_SOURCE:
+ case MADERA_OUT3LMIX_INPUT_4_VOLUME:
+ case MADERA_OUT3RMIX_INPUT_1_SOURCE:
+ case MADERA_OUT3RMIX_INPUT_1_VOLUME:
+ case MADERA_OUT3RMIX_INPUT_2_SOURCE:
+ case MADERA_OUT3RMIX_INPUT_2_VOLUME:
+ case MADERA_OUT3RMIX_INPUT_3_SOURCE:
+ case MADERA_OUT3RMIX_INPUT_3_VOLUME:
+ case MADERA_OUT3RMIX_INPUT_4_SOURCE:
+ case MADERA_OUT3RMIX_INPUT_4_VOLUME:
+ case MADERA_OUT5LMIX_INPUT_1_SOURCE:
+ case MADERA_OUT5LMIX_INPUT_1_VOLUME:
+ case MADERA_OUT5LMIX_INPUT_2_SOURCE:
+ case MADERA_OUT5LMIX_INPUT_2_VOLUME:
+ case MADERA_OUT5LMIX_INPUT_3_SOURCE:
+ case MADERA_OUT5LMIX_INPUT_3_VOLUME:
+ case MADERA_OUT5LMIX_INPUT_4_SOURCE:
+ case MADERA_OUT5LMIX_INPUT_4_VOLUME:
+ case MADERA_OUT5RMIX_INPUT_1_SOURCE:
+ case MADERA_OUT5RMIX_INPUT_1_VOLUME:
+ case MADERA_OUT5RMIX_INPUT_2_SOURCE:
+ case MADERA_OUT5RMIX_INPUT_2_VOLUME:
+ case MADERA_OUT5RMIX_INPUT_3_SOURCE:
+ case MADERA_OUT5RMIX_INPUT_3_VOLUME:
+ case MADERA_OUT5RMIX_INPUT_4_SOURCE:
+ case MADERA_OUT5RMIX_INPUT_4_VOLUME:
+ case MADERA_AIF1TX1MIX_INPUT_1_SOURCE:
+ case MADERA_AIF1TX1MIX_INPUT_1_VOLUME:
+ case MADERA_AIF1TX1MIX_INPUT_2_SOURCE:
+ case MADERA_AIF1TX1MIX_INPUT_2_VOLUME:
+ case MADERA_AIF1TX1MIX_INPUT_3_SOURCE:
+ case MADERA_AIF1TX1MIX_INPUT_3_VOLUME:
+ case MADERA_AIF1TX1MIX_INPUT_4_SOURCE:
+ case MADERA_AIF1TX1MIX_INPUT_4_VOLUME:
+ case MADERA_AIF1TX2MIX_INPUT_1_SOURCE:
+ case MADERA_AIF1TX2MIX_INPUT_1_VOLUME:
+ case MADERA_AIF1TX2MIX_INPUT_2_SOURCE:
+ case MADERA_AIF1TX2MIX_INPUT_2_VOLUME:
+ case MADERA_AIF1TX2MIX_INPUT_3_SOURCE:
+ case MADERA_AIF1TX2MIX_INPUT_3_VOLUME:
+ case MADERA_AIF1TX2MIX_INPUT_4_SOURCE:
+ case MADERA_AIF1TX2MIX_INPUT_4_VOLUME:
+ case MADERA_AIF1TX3MIX_INPUT_1_SOURCE:
+ case MADERA_AIF1TX3MIX_INPUT_1_VOLUME:
+ case MADERA_AIF1TX3MIX_INPUT_2_SOURCE:
+ case MADERA_AIF1TX3MIX_INPUT_2_VOLUME:
+ case MADERA_AIF1TX3MIX_INPUT_3_SOURCE:
+ case MADERA_AIF1TX3MIX_INPUT_3_VOLUME:
+ case MADERA_AIF1TX3MIX_INPUT_4_SOURCE:
+ case MADERA_AIF1TX3MIX_INPUT_4_VOLUME:
+ case MADERA_AIF1TX4MIX_INPUT_1_SOURCE:
+ case MADERA_AIF1TX4MIX_INPUT_1_VOLUME:
+ case MADERA_AIF1TX4MIX_INPUT_2_SOURCE:
+ case MADERA_AIF1TX4MIX_INPUT_2_VOLUME:
+ case MADERA_AIF1TX4MIX_INPUT_3_SOURCE:
+ case MADERA_AIF1TX4MIX_INPUT_3_VOLUME:
+ case MADERA_AIF1TX4MIX_INPUT_4_SOURCE:
+ case MADERA_AIF1TX4MIX_INPUT_4_VOLUME:
+ case MADERA_AIF1TX5MIX_INPUT_1_SOURCE:
+ case MADERA_AIF1TX5MIX_INPUT_1_VOLUME:
+ case MADERA_AIF1TX5MIX_INPUT_2_SOURCE:
+ case MADERA_AIF1TX5MIX_INPUT_2_VOLUME:
+ case MADERA_AIF1TX5MIX_INPUT_3_SOURCE:
+ case MADERA_AIF1TX5MIX_INPUT_3_VOLUME:
+ case MADERA_AIF1TX5MIX_INPUT_4_SOURCE:
+ case MADERA_AIF1TX5MIX_INPUT_4_VOLUME:
+ case MADERA_AIF1TX6MIX_INPUT_1_SOURCE:
+ case MADERA_AIF1TX6MIX_INPUT_1_VOLUME:
+ case MADERA_AIF1TX6MIX_INPUT_2_SOURCE:
+ case MADERA_AIF1TX6MIX_INPUT_2_VOLUME:
+ case MADERA_AIF1TX6MIX_INPUT_3_SOURCE:
+ case MADERA_AIF1TX6MIX_INPUT_3_VOLUME:
+ case MADERA_AIF1TX6MIX_INPUT_4_SOURCE:
+ case MADERA_AIF1TX6MIX_INPUT_4_VOLUME:
+ case MADERA_AIF1TX7MIX_INPUT_1_SOURCE:
+ case MADERA_AIF1TX7MIX_INPUT_1_VOLUME:
+ case MADERA_AIF1TX7MIX_INPUT_2_SOURCE:
+ case MADERA_AIF1TX7MIX_INPUT_2_VOLUME:
+ case MADERA_AIF1TX7MIX_INPUT_3_SOURCE:
+ case MADERA_AIF1TX7MIX_INPUT_3_VOLUME:
+ case MADERA_AIF1TX7MIX_INPUT_4_SOURCE:
+ case MADERA_AIF1TX7MIX_INPUT_4_VOLUME:
+ case MADERA_AIF1TX8MIX_INPUT_1_SOURCE:
+ case MADERA_AIF1TX8MIX_INPUT_1_VOLUME:
+ case MADERA_AIF1TX8MIX_INPUT_2_SOURCE:
+ case MADERA_AIF1TX8MIX_INPUT_2_VOLUME:
+ case MADERA_AIF1TX8MIX_INPUT_3_SOURCE:
+ case MADERA_AIF1TX8MIX_INPUT_3_VOLUME:
+ case MADERA_AIF1TX8MIX_INPUT_4_SOURCE:
+ case MADERA_AIF1TX8MIX_INPUT_4_VOLUME:
+ case MADERA_AIF2TX1MIX_INPUT_1_SOURCE:
+ case MADERA_AIF2TX1MIX_INPUT_1_VOLUME:
+ case MADERA_AIF2TX1MIX_INPUT_2_SOURCE:
+ case MADERA_AIF2TX1MIX_INPUT_2_VOLUME:
+ case MADERA_AIF2TX1MIX_INPUT_3_SOURCE:
+ case MADERA_AIF2TX1MIX_INPUT_3_VOLUME:
+ case MADERA_AIF2TX1MIX_INPUT_4_SOURCE:
+ case MADERA_AIF2TX1MIX_INPUT_4_VOLUME:
+ case MADERA_AIF2TX2MIX_INPUT_1_SOURCE:
+ case MADERA_AIF2TX2MIX_INPUT_1_VOLUME:
+ case MADERA_AIF2TX2MIX_INPUT_2_SOURCE:
+ case MADERA_AIF2TX2MIX_INPUT_2_VOLUME:
+ case MADERA_AIF2TX2MIX_INPUT_3_SOURCE:
+ case MADERA_AIF2TX2MIX_INPUT_3_VOLUME:
+ case MADERA_AIF2TX2MIX_INPUT_4_SOURCE:
+ case MADERA_AIF2TX2MIX_INPUT_4_VOLUME:
+ case MADERA_AIF2TX3MIX_INPUT_1_SOURCE:
+ case MADERA_AIF2TX3MIX_INPUT_1_VOLUME:
+ case MADERA_AIF2TX3MIX_INPUT_2_SOURCE:
+ case MADERA_AIF2TX3MIX_INPUT_2_VOLUME:
+ case MADERA_AIF2TX3MIX_INPUT_3_SOURCE:
+ case MADERA_AIF2TX3MIX_INPUT_3_VOLUME:
+ case MADERA_AIF2TX3MIX_INPUT_4_SOURCE:
+ case MADERA_AIF2TX3MIX_INPUT_4_VOLUME:
+ case MADERA_AIF2TX4MIX_INPUT_1_SOURCE:
+ case MADERA_AIF2TX4MIX_INPUT_1_VOLUME:
+ case MADERA_AIF2TX4MIX_INPUT_2_SOURCE:
+ case MADERA_AIF2TX4MIX_INPUT_2_VOLUME:
+ case MADERA_AIF2TX4MIX_INPUT_3_SOURCE:
+ case MADERA_AIF2TX4MIX_INPUT_3_VOLUME:
+ case MADERA_AIF2TX4MIX_INPUT_4_SOURCE:
+ case MADERA_AIF2TX4MIX_INPUT_4_VOLUME:
+ case MADERA_AIF2TX5MIX_INPUT_1_SOURCE:
+ case MADERA_AIF2TX5MIX_INPUT_1_VOLUME:
+ case MADERA_AIF2TX5MIX_INPUT_2_SOURCE:
+ case MADERA_AIF2TX5MIX_INPUT_2_VOLUME:
+ case MADERA_AIF2TX5MIX_INPUT_3_SOURCE:
+ case MADERA_AIF2TX5MIX_INPUT_3_VOLUME:
+ case MADERA_AIF2TX5MIX_INPUT_4_SOURCE:
+ case MADERA_AIF2TX5MIX_INPUT_4_VOLUME:
+ case MADERA_AIF2TX6MIX_INPUT_1_SOURCE:
+ case MADERA_AIF2TX6MIX_INPUT_1_VOLUME:
+ case MADERA_AIF2TX6MIX_INPUT_2_SOURCE:
+ case MADERA_AIF2TX6MIX_INPUT_2_VOLUME:
+ case MADERA_AIF2TX6MIX_INPUT_3_SOURCE:
+ case MADERA_AIF2TX6MIX_INPUT_3_VOLUME:
+ case MADERA_AIF2TX6MIX_INPUT_4_SOURCE:
+ case MADERA_AIF2TX6MIX_INPUT_4_VOLUME:
+ case MADERA_AIF2TX7MIX_INPUT_1_SOURCE:
+ case MADERA_AIF2TX7MIX_INPUT_1_VOLUME:
+ case MADERA_AIF2TX7MIX_INPUT_2_SOURCE:
+ case MADERA_AIF2TX7MIX_INPUT_2_VOLUME:
+ case MADERA_AIF2TX7MIX_INPUT_3_SOURCE:
+ case MADERA_AIF2TX7MIX_INPUT_3_VOLUME:
+ case MADERA_AIF2TX7MIX_INPUT_4_SOURCE:
+ case MADERA_AIF2TX7MIX_INPUT_4_VOLUME:
+ case MADERA_AIF2TX8MIX_INPUT_1_SOURCE:
+ case MADERA_AIF2TX8MIX_INPUT_1_VOLUME:
+ case MADERA_AIF2TX8MIX_INPUT_2_SOURCE:
+ case MADERA_AIF2TX8MIX_INPUT_2_VOLUME:
+ case MADERA_AIF2TX8MIX_INPUT_3_SOURCE:
+ case MADERA_AIF2TX8MIX_INPUT_3_VOLUME:
+ case MADERA_AIF2TX8MIX_INPUT_4_SOURCE:
+ case MADERA_AIF2TX8MIX_INPUT_4_VOLUME:
+ case MADERA_AIF3TX1MIX_INPUT_1_SOURCE:
+ case MADERA_AIF3TX1MIX_INPUT_1_VOLUME:
+ case MADERA_AIF3TX1MIX_INPUT_2_SOURCE:
+ case MADERA_AIF3TX1MIX_INPUT_2_VOLUME:
+ case MADERA_AIF3TX1MIX_INPUT_3_SOURCE:
+ case MADERA_AIF3TX1MIX_INPUT_3_VOLUME:
+ case MADERA_AIF3TX1MIX_INPUT_4_SOURCE:
+ case MADERA_AIF3TX1MIX_INPUT_4_VOLUME:
+ case MADERA_AIF3TX2MIX_INPUT_1_SOURCE:
+ case MADERA_AIF3TX2MIX_INPUT_1_VOLUME:
+ case MADERA_AIF3TX2MIX_INPUT_2_SOURCE:
+ case MADERA_AIF3TX2MIX_INPUT_2_VOLUME:
+ case MADERA_AIF3TX2MIX_INPUT_3_SOURCE:
+ case MADERA_AIF3TX2MIX_INPUT_3_VOLUME:
+ case MADERA_AIF3TX2MIX_INPUT_4_SOURCE:
+ case MADERA_AIF3TX2MIX_INPUT_4_VOLUME:
+ case MADERA_AIF3TX3MIX_INPUT_1_SOURCE:
+ case MADERA_AIF3TX3MIX_INPUT_1_VOLUME:
+ case MADERA_AIF3TX3MIX_INPUT_2_SOURCE:
+ case MADERA_AIF3TX3MIX_INPUT_2_VOLUME:
+ case MADERA_AIF3TX3MIX_INPUT_3_SOURCE:
+ case MADERA_AIF3TX3MIX_INPUT_3_VOLUME:
+ case MADERA_AIF3TX3MIX_INPUT_4_SOURCE:
+ case MADERA_AIF3TX3MIX_INPUT_4_VOLUME:
+ case MADERA_AIF3TX4MIX_INPUT_1_SOURCE:
+ case MADERA_AIF3TX4MIX_INPUT_1_VOLUME:
+ case MADERA_AIF3TX4MIX_INPUT_2_SOURCE:
+ case MADERA_AIF3TX4MIX_INPUT_2_VOLUME:
+ case MADERA_AIF3TX4MIX_INPUT_3_SOURCE:
+ case MADERA_AIF3TX4MIX_INPUT_3_VOLUME:
+ case MADERA_AIF3TX4MIX_INPUT_4_SOURCE:
+ case MADERA_AIF3TX4MIX_INPUT_4_VOLUME:
+ case CS47L92_AIF3TX5MIX_INPUT_1_SOURCE:
+ case CS47L92_AIF3TX5MIX_INPUT_1_VOLUME:
+ case CS47L92_AIF3TX5MIX_INPUT_2_SOURCE:
+ case CS47L92_AIF3TX5MIX_INPUT_2_VOLUME:
+ case CS47L92_AIF3TX5MIX_INPUT_3_SOURCE:
+ case CS47L92_AIF3TX5MIX_INPUT_3_VOLUME:
+ case CS47L92_AIF3TX5MIX_INPUT_4_SOURCE:
+ case CS47L92_AIF3TX5MIX_INPUT_4_VOLUME:
+ case CS47L92_AIF3TX6MIX_INPUT_1_SOURCE:
+ case CS47L92_AIF3TX6MIX_INPUT_1_VOLUME:
+ case CS47L92_AIF3TX6MIX_INPUT_2_SOURCE:
+ case CS47L92_AIF3TX6MIX_INPUT_2_VOLUME:
+ case CS47L92_AIF3TX6MIX_INPUT_3_SOURCE:
+ case CS47L92_AIF3TX6MIX_INPUT_3_VOLUME:
+ case CS47L92_AIF3TX6MIX_INPUT_4_SOURCE:
+ case CS47L92_AIF3TX6MIX_INPUT_4_VOLUME:
+ case CS47L92_AIF3TX7MIX_INPUT_1_SOURCE:
+ case CS47L92_AIF3TX7MIX_INPUT_1_VOLUME:
+ case CS47L92_AIF3TX7MIX_INPUT_2_SOURCE:
+ case CS47L92_AIF3TX7MIX_INPUT_2_VOLUME:
+ case CS47L92_AIF3TX7MIX_INPUT_3_SOURCE:
+ case CS47L92_AIF3TX7MIX_INPUT_3_VOLUME:
+ case CS47L92_AIF3TX7MIX_INPUT_4_SOURCE:
+ case CS47L92_AIF3TX7MIX_INPUT_4_VOLUME:
+ case CS47L92_AIF3TX8MIX_INPUT_1_SOURCE:
+ case CS47L92_AIF3TX8MIX_INPUT_1_VOLUME:
+ case CS47L92_AIF3TX8MIX_INPUT_2_SOURCE:
+ case CS47L92_AIF3TX8MIX_INPUT_2_VOLUME:
+ case CS47L92_AIF3TX8MIX_INPUT_3_SOURCE:
+ case CS47L92_AIF3TX8MIX_INPUT_3_VOLUME:
+ case CS47L92_AIF3TX8MIX_INPUT_4_SOURCE:
+ case CS47L92_AIF3TX8MIX_INPUT_4_VOLUME:
+ case MADERA_SLIMTX1MIX_INPUT_1_SOURCE:
+ case MADERA_SLIMTX1MIX_INPUT_1_VOLUME:
+ case MADERA_SLIMTX1MIX_INPUT_2_SOURCE:
+ case MADERA_SLIMTX1MIX_INPUT_2_VOLUME:
+ case MADERA_SLIMTX1MIX_INPUT_3_SOURCE:
+ case MADERA_SLIMTX1MIX_INPUT_3_VOLUME:
+ case MADERA_SLIMTX1MIX_INPUT_4_SOURCE:
+ case MADERA_SLIMTX1MIX_INPUT_4_VOLUME:
+ case MADERA_SLIMTX2MIX_INPUT_1_SOURCE:
+ case MADERA_SLIMTX2MIX_INPUT_1_VOLUME:
+ case MADERA_SLIMTX2MIX_INPUT_2_SOURCE:
+ case MADERA_SLIMTX2MIX_INPUT_2_VOLUME:
+ case MADERA_SLIMTX2MIX_INPUT_3_SOURCE:
+ case MADERA_SLIMTX2MIX_INPUT_3_VOLUME:
+ case MADERA_SLIMTX2MIX_INPUT_4_SOURCE:
+ case MADERA_SLIMTX2MIX_INPUT_4_VOLUME:
+ case MADERA_SLIMTX3MIX_INPUT_1_SOURCE:
+ case MADERA_SLIMTX3MIX_INPUT_1_VOLUME:
+ case MADERA_SLIMTX3MIX_INPUT_2_SOURCE:
+ case MADERA_SLIMTX3MIX_INPUT_2_VOLUME:
+ case MADERA_SLIMTX3MIX_INPUT_3_SOURCE:
+ case MADERA_SLIMTX3MIX_INPUT_3_VOLUME:
+ case MADERA_SLIMTX3MIX_INPUT_4_SOURCE:
+ case MADERA_SLIMTX3MIX_INPUT_4_VOLUME:
+ case MADERA_SLIMTX4MIX_INPUT_1_SOURCE:
+ case MADERA_SLIMTX4MIX_INPUT_1_VOLUME:
+ case MADERA_SLIMTX4MIX_INPUT_2_SOURCE:
+ case MADERA_SLIMTX4MIX_INPUT_2_VOLUME:
+ case MADERA_SLIMTX4MIX_INPUT_3_SOURCE:
+ case MADERA_SLIMTX4MIX_INPUT_3_VOLUME:
+ case MADERA_SLIMTX4MIX_INPUT_4_SOURCE:
+ case MADERA_SLIMTX4MIX_INPUT_4_VOLUME:
+ case MADERA_SLIMTX5MIX_INPUT_1_SOURCE:
+ case MADERA_SLIMTX5MIX_INPUT_1_VOLUME:
+ case MADERA_SLIMTX5MIX_INPUT_2_SOURCE:
+ case MADERA_SLIMTX5MIX_INPUT_2_VOLUME:
+ case MADERA_SLIMTX5MIX_INPUT_3_SOURCE:
+ case MADERA_SLIMTX5MIX_INPUT_3_VOLUME:
+ case MADERA_SLIMTX5MIX_INPUT_4_SOURCE:
+ case MADERA_SLIMTX5MIX_INPUT_4_VOLUME:
+ case MADERA_SLIMTX6MIX_INPUT_1_SOURCE:
+ case MADERA_SLIMTX6MIX_INPUT_1_VOLUME:
+ case MADERA_SLIMTX6MIX_INPUT_2_SOURCE:
+ case MADERA_SLIMTX6MIX_INPUT_2_VOLUME:
+ case MADERA_SLIMTX6MIX_INPUT_3_SOURCE:
+ case MADERA_SLIMTX6MIX_INPUT_3_VOLUME:
+ case MADERA_SLIMTX6MIX_INPUT_4_SOURCE:
+ case MADERA_SLIMTX6MIX_INPUT_4_VOLUME:
+ case MADERA_SLIMTX7MIX_INPUT_1_SOURCE:
+ case MADERA_SLIMTX7MIX_INPUT_1_VOLUME:
+ case MADERA_SLIMTX7MIX_INPUT_2_SOURCE:
+ case MADERA_SLIMTX7MIX_INPUT_2_VOLUME:
+ case MADERA_SLIMTX7MIX_INPUT_3_SOURCE:
+ case MADERA_SLIMTX7MIX_INPUT_3_VOLUME:
+ case MADERA_SLIMTX7MIX_INPUT_4_SOURCE:
+ case MADERA_SLIMTX7MIX_INPUT_4_VOLUME:
+ case MADERA_SLIMTX8MIX_INPUT_1_SOURCE:
+ case MADERA_SLIMTX8MIX_INPUT_1_VOLUME:
+ case MADERA_SLIMTX8MIX_INPUT_2_SOURCE:
+ case MADERA_SLIMTX8MIX_INPUT_2_VOLUME:
+ case MADERA_SLIMTX8MIX_INPUT_3_SOURCE:
+ case MADERA_SLIMTX8MIX_INPUT_3_VOLUME:
+ case MADERA_SLIMTX8MIX_INPUT_4_SOURCE:
+ case MADERA_SLIMTX8MIX_INPUT_4_VOLUME:
+ case MADERA_SPDIF1TX1MIX_INPUT_1_SOURCE:
+ case MADERA_SPDIF1TX1MIX_INPUT_1_VOLUME:
+ case MADERA_SPDIF1TX2MIX_INPUT_1_SOURCE:
+ case MADERA_SPDIF1TX2MIX_INPUT_1_VOLUME:
+ case MADERA_EQ1MIX_INPUT_1_SOURCE:
+ case MADERA_EQ1MIX_INPUT_1_VOLUME:
+ case MADERA_EQ1MIX_INPUT_2_SOURCE:
+ case MADERA_EQ1MIX_INPUT_2_VOLUME:
+ case MADERA_EQ1MIX_INPUT_3_SOURCE:
+ case MADERA_EQ1MIX_INPUT_3_VOLUME:
+ case MADERA_EQ1MIX_INPUT_4_SOURCE:
+ case MADERA_EQ1MIX_INPUT_4_VOLUME:
+ case MADERA_EQ2MIX_INPUT_1_SOURCE:
+ case MADERA_EQ2MIX_INPUT_1_VOLUME:
+ case MADERA_EQ2MIX_INPUT_2_SOURCE:
+ case MADERA_EQ2MIX_INPUT_2_VOLUME:
+ case MADERA_EQ2MIX_INPUT_3_SOURCE:
+ case MADERA_EQ2MIX_INPUT_3_VOLUME:
+ case MADERA_EQ2MIX_INPUT_4_SOURCE:
+ case MADERA_EQ2MIX_INPUT_4_VOLUME:
+ case MADERA_EQ3MIX_INPUT_1_SOURCE:
+ case MADERA_EQ3MIX_INPUT_1_VOLUME:
+ case MADERA_EQ3MIX_INPUT_2_SOURCE:
+ case MADERA_EQ3MIX_INPUT_2_VOLUME:
+ case MADERA_EQ3MIX_INPUT_3_SOURCE:
+ case MADERA_EQ3MIX_INPUT_3_VOLUME:
+ case MADERA_EQ3MIX_INPUT_4_SOURCE:
+ case MADERA_EQ3MIX_INPUT_4_VOLUME:
+ case MADERA_EQ4MIX_INPUT_1_SOURCE:
+ case MADERA_EQ4MIX_INPUT_1_VOLUME:
+ case MADERA_EQ4MIX_INPUT_2_SOURCE:
+ case MADERA_EQ4MIX_INPUT_2_VOLUME:
+ case MADERA_EQ4MIX_INPUT_3_SOURCE:
+ case MADERA_EQ4MIX_INPUT_3_VOLUME:
+ case MADERA_EQ4MIX_INPUT_4_SOURCE:
+ case MADERA_EQ4MIX_INPUT_4_VOLUME:
+ case MADERA_DRC1LMIX_INPUT_1_SOURCE:
+ case MADERA_DRC1LMIX_INPUT_1_VOLUME:
+ case MADERA_DRC1LMIX_INPUT_2_SOURCE:
+ case MADERA_DRC1LMIX_INPUT_2_VOLUME:
+ case MADERA_DRC1LMIX_INPUT_3_SOURCE:
+ case MADERA_DRC1LMIX_INPUT_3_VOLUME:
+ case MADERA_DRC1LMIX_INPUT_4_SOURCE:
+ case MADERA_DRC1LMIX_INPUT_4_VOLUME:
+ case MADERA_DRC1RMIX_INPUT_1_SOURCE:
+ case MADERA_DRC1RMIX_INPUT_1_VOLUME:
+ case MADERA_DRC1RMIX_INPUT_2_SOURCE:
+ case MADERA_DRC1RMIX_INPUT_2_VOLUME:
+ case MADERA_DRC1RMIX_INPUT_3_SOURCE:
+ case MADERA_DRC1RMIX_INPUT_3_VOLUME:
+ case MADERA_DRC1RMIX_INPUT_4_SOURCE:
+ case MADERA_DRC1RMIX_INPUT_4_VOLUME:
+ case MADERA_DRC2LMIX_INPUT_1_SOURCE:
+ case MADERA_DRC2LMIX_INPUT_1_VOLUME:
+ case MADERA_DRC2LMIX_INPUT_2_SOURCE:
+ case MADERA_DRC2LMIX_INPUT_2_VOLUME:
+ case MADERA_DRC2LMIX_INPUT_3_SOURCE:
+ case MADERA_DRC2LMIX_INPUT_3_VOLUME:
+ case MADERA_DRC2LMIX_INPUT_4_SOURCE:
+ case MADERA_DRC2LMIX_INPUT_4_VOLUME:
+ case MADERA_DRC2RMIX_INPUT_1_SOURCE:
+ case MADERA_DRC2RMIX_INPUT_1_VOLUME:
+ case MADERA_DRC2RMIX_INPUT_2_SOURCE:
+ case MADERA_DRC2RMIX_INPUT_2_VOLUME:
+ case MADERA_DRC2RMIX_INPUT_3_SOURCE:
+ case MADERA_DRC2RMIX_INPUT_3_VOLUME:
+ case MADERA_DRC2RMIX_INPUT_4_SOURCE:
+ case MADERA_DRC2RMIX_INPUT_4_VOLUME:
+ case MADERA_HPLP1MIX_INPUT_1_SOURCE:
+ case MADERA_HPLP1MIX_INPUT_1_VOLUME:
+ case MADERA_HPLP1MIX_INPUT_2_SOURCE:
+ case MADERA_HPLP1MIX_INPUT_2_VOLUME:
+ case MADERA_HPLP1MIX_INPUT_3_SOURCE:
+ case MADERA_HPLP1MIX_INPUT_3_VOLUME:
+ case MADERA_HPLP1MIX_INPUT_4_SOURCE:
+ case MADERA_HPLP1MIX_INPUT_4_VOLUME:
+ case MADERA_HPLP2MIX_INPUT_1_SOURCE:
+ case MADERA_HPLP2MIX_INPUT_1_VOLUME:
+ case MADERA_HPLP2MIX_INPUT_2_SOURCE:
+ case MADERA_HPLP2MIX_INPUT_2_VOLUME:
+ case MADERA_HPLP2MIX_INPUT_3_SOURCE:
+ case MADERA_HPLP2MIX_INPUT_3_VOLUME:
+ case MADERA_HPLP2MIX_INPUT_4_SOURCE:
+ case MADERA_HPLP2MIX_INPUT_4_VOLUME:
+ case MADERA_HPLP3MIX_INPUT_1_SOURCE:
+ case MADERA_HPLP3MIX_INPUT_1_VOLUME:
+ case MADERA_HPLP3MIX_INPUT_2_SOURCE:
+ case MADERA_HPLP3MIX_INPUT_2_VOLUME:
+ case MADERA_HPLP3MIX_INPUT_3_SOURCE:
+ case MADERA_HPLP3MIX_INPUT_3_VOLUME:
+ case MADERA_HPLP3MIX_INPUT_4_SOURCE:
+ case MADERA_HPLP3MIX_INPUT_4_VOLUME:
+ case MADERA_HPLP4MIX_INPUT_1_SOURCE:
+ case MADERA_HPLP4MIX_INPUT_1_VOLUME:
+ case MADERA_HPLP4MIX_INPUT_2_SOURCE:
+ case MADERA_HPLP4MIX_INPUT_2_VOLUME:
+ case MADERA_HPLP4MIX_INPUT_3_SOURCE:
+ case MADERA_HPLP4MIX_INPUT_3_VOLUME:
+ case MADERA_HPLP4MIX_INPUT_4_SOURCE:
+ case MADERA_HPLP4MIX_INPUT_4_VOLUME:
+ case MADERA_DSP1LMIX_INPUT_1_SOURCE:
+ case MADERA_DSP1LMIX_INPUT_1_VOLUME:
+ case MADERA_DSP1LMIX_INPUT_2_SOURCE:
+ case MADERA_DSP1LMIX_INPUT_2_VOLUME:
+ case MADERA_DSP1LMIX_INPUT_3_SOURCE:
+ case MADERA_DSP1LMIX_INPUT_3_VOLUME:
+ case MADERA_DSP1LMIX_INPUT_4_SOURCE:
+ case MADERA_DSP1LMIX_INPUT_4_VOLUME:
+ case MADERA_DSP1RMIX_INPUT_1_SOURCE:
+ case MADERA_DSP1RMIX_INPUT_1_VOLUME:
+ case MADERA_DSP1RMIX_INPUT_2_SOURCE:
+ case MADERA_DSP1RMIX_INPUT_2_VOLUME:
+ case MADERA_DSP1RMIX_INPUT_3_SOURCE:
+ case MADERA_DSP1RMIX_INPUT_3_VOLUME:
+ case MADERA_DSP1RMIX_INPUT_4_SOURCE:
+ case MADERA_DSP1RMIX_INPUT_4_VOLUME:
+ case MADERA_DSP1AUX1MIX_INPUT_1_SOURCE:
+ case MADERA_DSP1AUX2MIX_INPUT_1_SOURCE:
+ case MADERA_DSP1AUX3MIX_INPUT_1_SOURCE:
+ case MADERA_DSP1AUX4MIX_INPUT_1_SOURCE:
+ case MADERA_DSP1AUX5MIX_INPUT_1_SOURCE:
+ case MADERA_DSP1AUX6MIX_INPUT_1_SOURCE:
+ case MADERA_ASRC1_1LMIX_INPUT_1_SOURCE:
+ case MADERA_ASRC1_1RMIX_INPUT_1_SOURCE:
+ case MADERA_ASRC1_2LMIX_INPUT_1_SOURCE:
+ case MADERA_ASRC1_2RMIX_INPUT_1_SOURCE:
+ case MADERA_ISRC1DEC1MIX_INPUT_1_SOURCE:
+ case MADERA_ISRC1DEC2MIX_INPUT_1_SOURCE:
+ case MADERA_ISRC1INT1MIX_INPUT_1_SOURCE:
+ case MADERA_ISRC1INT2MIX_INPUT_1_SOURCE:
+ case MADERA_ISRC2DEC1MIX_INPUT_1_SOURCE:
+ case MADERA_ISRC2DEC2MIX_INPUT_1_SOURCE:
+ case MADERA_ISRC2INT1MIX_INPUT_1_SOURCE:
+ case MADERA_ISRC2INT2MIX_INPUT_1_SOURCE:
+ case MADERA_DFC1MIX_INPUT_1_SOURCE:
+ case MADERA_DFC2MIX_INPUT_1_SOURCE:
+ case MADERA_DFC3MIX_INPUT_1_SOURCE:
+ case MADERA_DFC4MIX_INPUT_1_SOURCE:
+ case MADERA_DFC5MIX_INPUT_1_SOURCE:
+ case MADERA_DFC6MIX_INPUT_1_SOURCE:
+ case MADERA_DFC7MIX_INPUT_1_SOURCE:
+ case MADERA_DFC8MIX_INPUT_1_SOURCE:
+ case MADERA_FX_CTRL1 ... MADERA_FX_CTRL2:
+ case MADERA_EQ1_1 ... MADERA_EQ1_21:
+ case MADERA_EQ2_1 ... MADERA_EQ2_21:
+ case MADERA_EQ3_1 ... MADERA_EQ3_21:
+ case MADERA_EQ4_1 ... MADERA_EQ4_21:
+ case MADERA_DRC1_CTRL1 ... MADERA_DRC1_CTRL5:
+ case MADERA_DRC2_CTRL1 ... MADERA_DRC2_CTRL5:
+ case MADERA_HPLPF1_1 ... MADERA_HPLPF1_2:
+ case MADERA_HPLPF2_1 ... MADERA_HPLPF2_2:
+ case MADERA_HPLPF3_1 ... MADERA_HPLPF3_2:
+ case MADERA_HPLPF4_1 ... MADERA_HPLPF4_2:
+ case MADERA_ASRC1_ENABLE:
+ case MADERA_ASRC1_STATUS:
+ case MADERA_ASRC1_RATE1 ... MADERA_ASRC1_RATE2:
+ case MADERA_ISRC_1_CTRL_1 ... MADERA_ISRC_1_CTRL_3:
+ case MADERA_ISRC_2_CTRL_1 ... MADERA_ISRC_2_CTRL_3:
+ case MADERA_AUXPDM1_CTRL_0 ... MADERA_AUXPDM1_CTRL_1:
+ case MADERA_DFC1_CTRL:
+ case MADERA_DFC1_RX:
+ case MADERA_DFC1_TX:
+ case MADERA_DFC2_CTRL:
+ case MADERA_DFC2_RX:
+ case MADERA_DFC2_TX:
+ case MADERA_DFC3_CTRL:
+ case MADERA_DFC3_RX:
+ case MADERA_DFC3_TX:
+ case MADERA_DFC4_CTRL:
+ case MADERA_DFC4_RX:
+ case MADERA_DFC4_TX:
+ case MADERA_DFC5_CTRL:
+ case MADERA_DFC5_RX:
+ case MADERA_DFC5_TX:
+ case MADERA_DFC6_CTRL:
+ case MADERA_DFC6_RX:
+ case MADERA_DFC6_TX:
+ case MADERA_DFC7_CTRL:
+ case MADERA_DFC7_RX:
+ case MADERA_DFC7_TX:
+ case MADERA_DFC8_CTRL:
+ case MADERA_DFC8_RX:
+ case MADERA_DFC8_TX:
+ case MADERA_DFC_STATUS:
+ case MADERA_GPIO1_CTRL_1 ... MADERA_GPIO16_CTRL_2:
+ case MADERA_IRQ1_STATUS_1 ... MADERA_IRQ1_STATUS_33:
+ case MADERA_IRQ1_MASK_1 ... MADERA_IRQ1_MASK_33:
+ case MADERA_IRQ1_RAW_STATUS_1 ... MADERA_IRQ1_RAW_STATUS_33:
+ case MADERA_INTERRUPT_DEBOUNCE_7:
+ case MADERA_IRQ1_CTRL:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool cs47l92_16bit_volatile_register(struct device *dev,
+ unsigned int reg)
+{
+ switch (reg) {
+ case MADERA_SOFTWARE_RESET:
+ case MADERA_HARDWARE_REVISION:
+ case MADERA_WRITE_SEQUENCER_CTRL_0 ... MADERA_WRITE_SEQUENCER_CTRL_2:
+ case MADERA_HAPTICS_STATUS:
+ case MADERA_SAMPLE_RATE_1_STATUS:
+ case MADERA_SAMPLE_RATE_2_STATUS:
+ case MADERA_SAMPLE_RATE_3_STATUS:
+ case MADERA_ASYNC_SAMPLE_RATE_1_STATUS:
+ case MADERA_ASYNC_SAMPLE_RATE_2_STATUS:
+ case MADERA_HP_CTRL_1L:
+ case MADERA_HP_CTRL_1R:
+ case MADERA_HP_CTRL_2L:
+ case MADERA_HP_CTRL_2R:
+ case MADERA_HP_CTRL_3L:
+ case MADERA_HP_CTRL_3R:
+ case MADERA_MIC_DETECT_1_CONTROL_3:
+ case MADERA_MIC_DETECT_1_CONTROL_4:
+ case MADERA_MIC_DETECT_2_CONTROL_3:
+ case MADERA_MIC_DETECT_2_CONTROL_4:
+ case MADERA_HEADPHONE_DETECT_2:
+ case MADERA_HEADPHONE_DETECT_3:
+ case MADERA_HEADPHONE_DETECT_5:
+ case MADERA_INPUT_ENABLES_STATUS:
+ case MADERA_OUTPUT_STATUS_1:
+ case MADERA_RAW_OUTPUT_STATUS_1:
+ case MADERA_SPD1_TX_CHANNEL_STATUS_1:
+ case MADERA_SPD1_TX_CHANNEL_STATUS_2:
+ case MADERA_SPD1_TX_CHANNEL_STATUS_3:
+ case MADERA_SLIMBUS_RX_PORT_STATUS:
+ case MADERA_SLIMBUS_TX_PORT_STATUS:
+ case MADERA_FX_CTRL2:
+ case MADERA_ASRC1_STATUS:
+ case MADERA_DFC_STATUS:
+ case MADERA_IRQ1_STATUS_1 ... MADERA_IRQ1_STATUS_33:
+ case MADERA_IRQ1_RAW_STATUS_1 ... MADERA_IRQ1_RAW_STATUS_33:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool cs47l92_32bit_readable_register(struct device *dev,
+ unsigned int reg)
+{
+ switch (reg) {
+ case MADERA_WSEQ_SEQUENCE_1 ... MADERA_WSEQ_SEQUENCE_508:
+ case MADERA_OTP_HPDET_CAL_1 ... MADERA_OTP_HPDET_CAL_2:
+ case MADERA_DSP1_CONFIG_1 ... MADERA_DSP1_PMEM_ERR_ADDR___XMEM_ERR_ADDR:
+ return true;
+ default:
+ return cs47l92_is_adsp_memory(reg);
+ }
+}
+
+static bool cs47l92_32bit_volatile_register(struct device *dev,
+ unsigned int reg)
+{
+ switch (reg) {
+ case MADERA_WSEQ_SEQUENCE_1 ... MADERA_WSEQ_SEQUENCE_508:
+ case MADERA_OTP_HPDET_CAL_1 ... MADERA_OTP_HPDET_CAL_2:
+ case MADERA_DSP1_CONFIG_1 ... MADERA_DSP1_PMEM_ERR_ADDR___XMEM_ERR_ADDR:
+ return true;
+ default:
+ return cs47l92_is_adsp_memory(reg);
+ }
+}
+
+const struct regmap_config cs47l92_16bit_spi_regmap = {
+ .name = "cs47l92_16bit",
+ .reg_bits = 32,
+ .pad_bits = 16,
+ .val_bits = 16,
+ .reg_format_endian = REGMAP_ENDIAN_BIG,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+
+ .max_register = MADERA_INTERRUPT_RAW_STATUS_1,
+ .readable_reg = &cs47l92_16bit_readable_register,
+ .volatile_reg = &cs47l92_16bit_volatile_register,
+
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = cs47l92_reg_default,
+ .num_reg_defaults = ARRAY_SIZE(cs47l92_reg_default),
+};
+EXPORT_SYMBOL_GPL(cs47l92_16bit_spi_regmap);
+
+const struct regmap_config cs47l92_16bit_i2c_regmap = {
+ .name = "cs47l92_16bit",
+ .reg_bits = 32,
+ .val_bits = 16,
+ .reg_format_endian = REGMAP_ENDIAN_BIG,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+
+ .max_register = MADERA_INTERRUPT_RAW_STATUS_1,
+ .readable_reg = &cs47l92_16bit_readable_register,
+ .volatile_reg = &cs47l92_16bit_volatile_register,
+
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = cs47l92_reg_default,
+ .num_reg_defaults = ARRAY_SIZE(cs47l92_reg_default),
+};
+EXPORT_SYMBOL_GPL(cs47l92_16bit_i2c_regmap);
+
+const struct regmap_config cs47l92_32bit_spi_regmap = {
+ .name = "cs47l92_32bit",
+ .reg_bits = 32,
+ .reg_stride = 2,
+ .pad_bits = 16,
+ .val_bits = 32,
+ .reg_format_endian = REGMAP_ENDIAN_BIG,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+
+ .max_register = MADERA_DSP1_PMEM_ERR_ADDR___XMEM_ERR_ADDR,
+ .readable_reg = &cs47l92_32bit_readable_register,
+ .volatile_reg = &cs47l92_32bit_volatile_register,
+
+ .cache_type = REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL_GPL(cs47l92_32bit_spi_regmap);
+
+const struct regmap_config cs47l92_32bit_i2c_regmap = {
+ .name = "cs47l92_32bit",
+ .reg_bits = 32,
+ .reg_stride = 2,
+ .val_bits = 32,
+ .reg_format_endian = REGMAP_ENDIAN_BIG,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+
+ .max_register = MADERA_DSP1_PMEM_ERR_ADDR___XMEM_ERR_ADDR,
+ .readable_reg = &cs47l92_32bit_readable_register,
+ .volatile_reg = &cs47l92_32bit_volatile_register,
+
+ .cache_type = REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL_GPL(cs47l92_32bit_i2c_regmap);
diff --git a/drivers/mfd/cs5535-mfd.c b/drivers/mfd/cs5535-mfd.c
index 0b49940c490e..f1825c0ccbd0 100644
--- a/drivers/mfd/cs5535-mfd.c
+++ b/drivers/mfd/cs5535-mfd.c
@@ -100,22 +100,10 @@ static struct mfd_cell cs5535_mfd_cells[] = {
},
};
-#ifdef CONFIG_OLPC
-static void cs5535_clone_olpc_cells(void)
-{
- static const char *acpi_clones[] = {
- "olpc-xo1-pm-acpi",
- "olpc-xo1-sci-acpi"
- };
-
- if (!machine_is_olpc())
- return;
-
- mfd_clone_cell("cs5535-acpi", acpi_clones, ARRAY_SIZE(acpi_clones));
-}
-#else
-static void cs5535_clone_olpc_cells(void) { }
-#endif
+static const char *olpc_acpi_clones[] = {
+ "olpc-xo1-pm-acpi",
+ "olpc-xo1-sci-acpi"
+};
static int cs5535_mfd_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
@@ -145,7 +133,9 @@ static int cs5535_mfd_probe(struct pci_dev *pdev,
dev_err(&pdev->dev, "MFD add devices failed: %d\n", err);
goto err_disable;
}
- cs5535_clone_olpc_cells();
+
+ if (machine_is_olpc())
+ mfd_clone_cell("cs5535-acpi", olpc_acpi_clones, ARRAY_SIZE(olpc_acpi_clones));
dev_info(&pdev->dev, "%zu devices registered.\n",
ARRAY_SIZE(cs5535_mfd_cells));
diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c
index 09f367571c58..a818fbb55988 100644
--- a/drivers/mfd/da903x.c
+++ b/drivers/mfd/da903x.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Base driver for Dialog Semiconductor DA9030/DA9034
*
@@ -6,10 +7,6 @@
*
* Copyright (C) 2006-2008 Marvell International Ltd.
* Eric Miao <eric.miao@marvell.com>
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/mfd/da9052-irq.c b/drivers/mfd/da9052-irq.c
index cd4ca849ca44..abbdbf0337e2 100644
--- a/drivers/mfd/da9052-irq.c
+++ b/drivers/mfd/da9052-irq.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* DA9052 interrupt support
*
@@ -7,10 +8,6 @@
* Copyright 2012 Wolfson Microelectronics plc
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
- *
- * 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.
*/
#include <linux/device.h>
diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c
index 542b47c6bcd2..f505e3e1274b 100644
--- a/drivers/mfd/ezx-pcap.c
+++ b/drivers/mfd/ezx-pcap.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for Motorola PCAP2 as present in EZX phones
*
* Copyright (C) 2006 Harald Welte <laforge@openezx.org>
* Copyright (C) 2009 Daniel Ribeiro <drwyrm@gmail.com>
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/mfd/fsl-imx25-tsadc.c b/drivers/mfd/fsl-imx25-tsadc.c
index dbb85caaafed..20791cab7263 100644
--- a/drivers/mfd/fsl-imx25-tsadc.c
+++ b/drivers/mfd/fsl-imx25-tsadc.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014-2015 Pengutronix, Markus Pargmann <mpa@pengutronix.de>
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/mfd/hi6421-pmic-core.c b/drivers/mfd/hi6421-pmic-core.c
index 6fb7ba272e09..edfc172b8607 100644
--- a/drivers/mfd/hi6421-pmic-core.c
+++ b/drivers/mfd/hi6421-pmic-core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Device driver for Hi6421 PMIC
*
@@ -7,10 +8,6 @@
* http://www.linaro.org
*
* Author: Guodong Xu <guodong.xu@linaro.org>
- *
- * 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.
*/
#include <linux/device.h>
diff --git a/drivers/mfd/hi655x-pmic.c b/drivers/mfd/hi655x-pmic.c
index 96c07fa1802a..7e3959aaa285 100644
--- a/drivers/mfd/hi655x-pmic.c
+++ b/drivers/mfd/hi655x-pmic.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Device driver for MFD hi655x PMIC
*
@@ -6,10 +7,6 @@
* Authors:
* Chen Feng <puck.chen@hisilicon.com>
* Fei Wang <w.f@huawei.com>
- *
- * 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.
*/
#include <linux/gpio.h>
@@ -112,6 +109,8 @@ static int hi655x_pmic_probe(struct platform_device *pdev)
pmic->regmap = devm_regmap_init_mmio_clk(dev, NULL, base,
&hi655x_regmap_config);
+ if (IS_ERR(pmic->regmap))
+ return PTR_ERR(pmic->regmap);
regmap_read(pmic->regmap, HI655X_BUS_ADDR(HI655X_VER_REG), &pmic->ver);
if ((pmic->ver < PMU_VER_START) || (pmic->ver > PMU_VER_END)) {
diff --git a/drivers/mfd/intel-lpss-acpi.c b/drivers/mfd/intel-lpss-acpi.c
index 6d9f03363ee7..61ffb8b393e4 100644
--- a/drivers/mfd/intel-lpss-acpi.c
+++ b/drivers/mfd/intel-lpss-acpi.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Intel LPSS ACPI support.
*
@@ -5,10 +6,6 @@
*
* Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
* Mika Westerberg <mika.westerberg@linux.intel.com>
- *
- * 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.
*/
#include <linux/acpi.h>
diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c
index 6b111be944d9..ade6e1ce5a98 100644
--- a/drivers/mfd/intel-lpss-pci.c
+++ b/drivers/mfd/intel-lpss-pci.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Intel LPSS PCI support.
*
@@ -5,10 +6,6 @@
*
* Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
* Mika Westerberg <mika.westerberg@linux.intel.com>
- *
- * 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.
*/
#include <linux/ioport.h>
@@ -186,10 +183,10 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x31bc), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x31be), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x31c0), (kernel_ulong_t)&bxt_uart_info },
- { PCI_VDEVICE(INTEL, 0x31ee), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x31c2), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x31c4), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x31c6), (kernel_ulong_t)&bxt_info },
+ { PCI_VDEVICE(INTEL, 0x31ee), (kernel_ulong_t)&bxt_uart_info },
/* ICL-LP */
{ PCI_VDEVICE(INTEL, 0x34a8), (kernel_ulong_t)&spt_uart_info },
{ PCI_VDEVICE(INTEL, 0x34a9), (kernel_ulong_t)&spt_uart_info },
@@ -203,6 +200,21 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x34ea), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x34eb), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x34fb), (kernel_ulong_t)&spt_info },
+ /* EHL */
+ { PCI_VDEVICE(INTEL, 0x4b28), (kernel_ulong_t)&bxt_uart_info },
+ { PCI_VDEVICE(INTEL, 0x4b29), (kernel_ulong_t)&bxt_uart_info },
+ { PCI_VDEVICE(INTEL, 0x4b2a), (kernel_ulong_t)&bxt_info },
+ { PCI_VDEVICE(INTEL, 0x4b2b), (kernel_ulong_t)&bxt_info },
+ { PCI_VDEVICE(INTEL, 0x4b37), (kernel_ulong_t)&bxt_info },
+ { PCI_VDEVICE(INTEL, 0x4b44), (kernel_ulong_t)&bxt_i2c_info },
+ { PCI_VDEVICE(INTEL, 0x4b45), (kernel_ulong_t)&bxt_i2c_info },
+ { PCI_VDEVICE(INTEL, 0x4b4b), (kernel_ulong_t)&bxt_i2c_info },
+ { PCI_VDEVICE(INTEL, 0x4b4c), (kernel_ulong_t)&bxt_i2c_info },
+ { PCI_VDEVICE(INTEL, 0x4b4d), (kernel_ulong_t)&bxt_uart_info },
+ { PCI_VDEVICE(INTEL, 0x4b78), (kernel_ulong_t)&bxt_i2c_info },
+ { PCI_VDEVICE(INTEL, 0x4b79), (kernel_ulong_t)&bxt_i2c_info },
+ { PCI_VDEVICE(INTEL, 0x4b7a), (kernel_ulong_t)&bxt_i2c_info },
+ { PCI_VDEVICE(INTEL, 0x4b7b), (kernel_ulong_t)&bxt_i2c_info },
/* APL */
{ PCI_VDEVICE(INTEL, 0x5aac), (kernel_ulong_t)&apl_i2c_info },
{ PCI_VDEVICE(INTEL, 0x5aae), (kernel_ulong_t)&apl_i2c_info },
@@ -236,7 +248,6 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x9da9), (kernel_ulong_t)&spt_uart_info },
{ PCI_VDEVICE(INTEL, 0x9daa), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0x9dab), (kernel_ulong_t)&spt_info },
- { PCI_VDEVICE(INTEL, 0x9dfb), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0x9dc5), (kernel_ulong_t)&cnl_i2c_info },
{ PCI_VDEVICE(INTEL, 0x9dc6), (kernel_ulong_t)&cnl_i2c_info },
{ PCI_VDEVICE(INTEL, 0x9dc7), (kernel_ulong_t)&spt_uart_info },
@@ -244,6 +255,7 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x9de9), (kernel_ulong_t)&cnl_i2c_info },
{ PCI_VDEVICE(INTEL, 0x9dea), (kernel_ulong_t)&cnl_i2c_info },
{ PCI_VDEVICE(INTEL, 0x9deb), (kernel_ulong_t)&cnl_i2c_info },
+ { PCI_VDEVICE(INTEL, 0x9dfb), (kernel_ulong_t)&spt_info },
/* SPT-H */
{ PCI_VDEVICE(INTEL, 0xa127), (kernel_ulong_t)&spt_uart_info },
{ PCI_VDEVICE(INTEL, 0xa128), (kernel_ulong_t)&spt_uart_info },
@@ -268,12 +280,12 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0xa329), (kernel_ulong_t)&spt_uart_info },
{ PCI_VDEVICE(INTEL, 0xa32a), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0xa32b), (kernel_ulong_t)&spt_info },
- { PCI_VDEVICE(INTEL, 0xa37b), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0xa347), (kernel_ulong_t)&spt_uart_info },
{ PCI_VDEVICE(INTEL, 0xa368), (kernel_ulong_t)&cnl_i2c_info },
{ PCI_VDEVICE(INTEL, 0xa369), (kernel_ulong_t)&cnl_i2c_info },
{ PCI_VDEVICE(INTEL, 0xa36a), (kernel_ulong_t)&cnl_i2c_info },
{ PCI_VDEVICE(INTEL, 0xa36b), (kernel_ulong_t)&cnl_i2c_info },
+ { PCI_VDEVICE(INTEL, 0xa37b), (kernel_ulong_t)&spt_info },
{ }
};
MODULE_DEVICE_TABLE(pci, intel_lpss_pci_ids);
diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c
index fc6aa4c50144..277f48f1cc1c 100644
--- a/drivers/mfd/intel-lpss.c
+++ b/drivers/mfd/intel-lpss.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Intel Sunrisepoint LPSS core support.
*
@@ -7,10 +8,6 @@
* Mika Westerberg <mika.westerberg@linux.intel.com>
* Heikki Krogerus <heikki.krogerus@linux.intel.com>
* Jarkko Nikula <jarkko.nikula@linux.intel.com>
- *
- * 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.
*/
#include <linux/clk.h>
@@ -546,6 +543,7 @@ module_init(intel_lpss_init);
static void __exit intel_lpss_exit(void)
{
+ ida_destroy(&intel_lpss_devid_ida);
debugfs_remove(intel_lpss_debugfs);
}
module_exit(intel_lpss_exit);
diff --git a/drivers/mfd/intel-lpss.h b/drivers/mfd/intel-lpss.h
index 3a120fecd2dc..4ae58a86bb42 100644
--- a/drivers/mfd/intel-lpss.h
+++ b/drivers/mfd/intel-lpss.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Intel LPSS core support.
*
@@ -5,10 +6,6 @@
*
* Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
* Mika Westerberg <mika.westerberg@linux.intel.com>
- *
- * 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.
*/
#ifndef __MFD_INTEL_LPSS_H
diff --git a/drivers/mfd/ipaq-micro.c b/drivers/mfd/ipaq-micro.c
index cd762d08f116..a1d9be82734d 100644
--- a/drivers/mfd/ipaq-micro.c
+++ b/drivers/mfd/ipaq-micro.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Compaq iPAQ h3xxx Atmel microcontroller companion support
*
@@ -8,10 +9,6 @@
* Author : Alessandro Gardich <gremlin@gremlin.it>
* Author : Dmitry Artamonow <mad_soft@inbox.ru>
* Author : Linus Walleij <linus.walleij@linaro.org>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/mfd/lp3943.c b/drivers/mfd/lp3943.c
index 65a2a8f14e74..13cb89be3d66 100644
--- a/drivers/mfd/lp3943.c
+++ b/drivers/mfd/lp3943.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TI/National Semiconductor LP3943 MFD Core Driver
*
@@ -5,10 +6,6 @@
*
* Author: Milo Kim <milo.kim@ti.com>
*
- * 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.
- *
* Driver structure:
* LP3943 is an integrated device capable of driving 16 output channels.
* It can be used for a GPIO expander and PWM generators.
diff --git a/drivers/mfd/lp87565.c b/drivers/mfd/lp87565.c
index 7960109c05e3..4a5c8ade4ae0 100644
--- a/drivers/mfd/lp87565.c
+++ b/drivers/mfd/lp87565.c
@@ -30,6 +30,10 @@ static const struct of_device_id of_lp87565_match_table[] = {
.compatible = "ti,lp87565-q1",
.data = (void *)LP87565_DEVICE_TYPE_LP87565_Q1,
},
+ {
+ .compatible = "ti,lp87561-q1",
+ .data = (void *)LP87565_DEVICE_TYPE_LP87561_Q1,
+ },
{}
};
MODULE_DEVICE_TABLE(of, of_lp87565_match_table);
diff --git a/drivers/mfd/lp8788-irq.c b/drivers/mfd/lp8788-irq.c
index 792d51bae20f..348439a3fbbd 100644
--- a/drivers/mfd/lp8788-irq.c
+++ b/drivers/mfd/lp8788-irq.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TI LP8788 MFD - interrupt handler
*
* Copyright 2012 Texas Instruments
*
* Author: Milo(Woogyom) Kim <milo.kim@ti.com>
- *
- * 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.
- *
*/
#include <linux/delay.h>
diff --git a/drivers/mfd/lp8788.c b/drivers/mfd/lp8788.c
index acf616559512..768d556b3fe9 100644
--- a/drivers/mfd/lp8788.c
+++ b/drivers/mfd/lp8788.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TI LP8788 MFD - core interface
*
* Copyright 2012 Texas Instruments
*
* Author: Milo(Woogyom) Kim <milo.kim@ti.com>
- *
- * 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.
- *
*/
#include <linux/err.h>
diff --git a/drivers/mfd/madera-core.c b/drivers/mfd/madera-core.c
index 2a77988d0462..29540cbf7593 100644
--- a/drivers/mfd/madera-core.c
+++ b/drivers/mfd/madera-core.c
@@ -1,12 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Core MFD support for Cirrus Logic Madera codecs
*
* Copyright (C) 2015-2018 Cirrus Logic
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by the
- * Free Software Foundation; version 2.
*/
#include <linux/device.h>
@@ -31,9 +27,11 @@
#include "madera.h"
+#define CS47L15_SILICON_ID 0x6370
#define CS47L35_SILICON_ID 0x6360
#define CS47L85_SILICON_ID 0x6338
#define CS47L90_SILICON_ID 0x6364
+#define CS47L92_SILICON_ID 0x6371
#define MADERA_32KZ_MCLK2 1
@@ -46,6 +44,28 @@ static const struct mfd_cell madera_ldo1_devs[] = {
{ .name = "madera-ldo1" },
};
+static const char * const cs47l15_supplies[] = {
+ "MICVDD",
+ "CPVDD1",
+ "SPKVDD",
+};
+
+static const struct mfd_cell cs47l15_devs[] = {
+ { .name = "madera-pinctrl", },
+ { .name = "madera-irq" },
+ { .name = "madera-gpio" },
+ {
+ .name = "madera-extcon",
+ .parent_supplies = cs47l15_supplies,
+ .num_parent_supplies = 1, /* We only need MICVDD */
+ },
+ {
+ .name = "cs47l15-codec",
+ .parent_supplies = cs47l15_supplies,
+ .num_parent_supplies = ARRAY_SIZE(cs47l15_supplies),
+ },
+};
+
static const char * const cs47l35_supplies[] = {
"MICVDD",
"DBVDD2",
@@ -59,7 +79,11 @@ static const struct mfd_cell cs47l35_devs[] = {
{ .name = "madera-irq", },
{ .name = "madera-micsupp", },
{ .name = "madera-gpio", },
- { .name = "madera-extcon", },
+ {
+ .name = "madera-extcon",
+ .parent_supplies = cs47l35_supplies,
+ .num_parent_supplies = 1, /* We only need MICVDD */
+ },
{
.name = "cs47l35-codec",
.parent_supplies = cs47l35_supplies,
@@ -83,7 +107,11 @@ static const struct mfd_cell cs47l85_devs[] = {
{ .name = "madera-irq", },
{ .name = "madera-micsupp" },
{ .name = "madera-gpio", },
- { .name = "madera-extcon", },
+ {
+ .name = "madera-extcon",
+ .parent_supplies = cs47l85_supplies,
+ .num_parent_supplies = 1, /* We only need MICVDD */
+ },
{
.name = "cs47l85-codec",
.parent_supplies = cs47l85_supplies,
@@ -105,7 +133,11 @@ static const struct mfd_cell cs47l90_devs[] = {
{ .name = "madera-irq", },
{ .name = "madera-micsupp", },
{ .name = "madera-gpio", },
- { .name = "madera-extcon", },
+ {
+ .name = "madera-extcon",
+ .parent_supplies = cs47l90_supplies,
+ .num_parent_supplies = 1, /* We only need MICVDD */
+ },
{
.name = "cs47l90-codec",
.parent_supplies = cs47l90_supplies,
@@ -113,10 +145,35 @@ static const struct mfd_cell cs47l90_devs[] = {
},
};
+static const char * const cs47l92_supplies[] = {
+ "MICVDD",
+ "CPVDD1",
+ "CPVDD2",
+};
+
+static const struct mfd_cell cs47l92_devs[] = {
+ { .name = "madera-pinctrl" },
+ { .name = "madera-irq", },
+ { .name = "madera-micsupp", },
+ { .name = "madera-gpio" },
+ {
+ .name = "madera-extcon",
+ .parent_supplies = cs47l92_supplies,
+ .num_parent_supplies = 1, /* We only need MICVDD */
+ },
+ {
+ .name = "cs47l92-codec",
+ .parent_supplies = cs47l92_supplies,
+ .num_parent_supplies = ARRAY_SIZE(cs47l92_supplies),
+ },
+};
+
/* Used by madera-i2c and madera-spi drivers */
const char *madera_name_from_type(enum madera_type type)
{
switch (type) {
+ case CS47L15:
+ return "CS47L15";
case CS47L35:
return "CS47L35";
case CS47L85:
@@ -125,6 +182,12 @@ const char *madera_name_from_type(enum madera_type type)
return "CS47L90";
case CS47L91:
return "CS47L91";
+ case CS42L92:
+ return "CS42L92";
+ case CS47L92:
+ return "CS47L92";
+ case CS47L93:
+ return "CS47L93";
case WM1840:
return "WM1840";
default:
@@ -139,7 +202,7 @@ EXPORT_SYMBOL_GPL(madera_name_from_type);
static int madera_wait_for_boot(struct madera *madera)
{
ktime_t timeout;
- unsigned int val;
+ unsigned int val = 0;
int ret = 0;
/*
@@ -279,13 +342,18 @@ const struct dev_pm_ops madera_pm_ops = {
EXPORT_SYMBOL_GPL(madera_pm_ops);
const struct of_device_id madera_of_match[] = {
+ { .compatible = "cirrus,cs47l15", .data = (void *)CS47L15 },
{ .compatible = "cirrus,cs47l35", .data = (void *)CS47L35 },
{ .compatible = "cirrus,cs47l85", .data = (void *)CS47L85 },
{ .compatible = "cirrus,cs47l90", .data = (void *)CS47L90 },
{ .compatible = "cirrus,cs47l91", .data = (void *)CS47L91 },
+ { .compatible = "cirrus,cs42l92", .data = (void *)CS42L92 },
+ { .compatible = "cirrus,cs47l92", .data = (void *)CS47L92 },
+ { .compatible = "cirrus,cs47l93", .data = (void *)CS47L93 },
{ .compatible = "cirrus,wm1840", .data = (void *)WM1840 },
{}
};
+MODULE_DEVICE_TABLE(of, madera_of_match);
EXPORT_SYMBOL_GPL(madera_of_match);
static int madera_get_reset_gpio(struct madera *madera)
@@ -326,6 +394,10 @@ static void madera_set_micbias_info(struct madera *madera)
* childbiases for each micbias. Unspecified values default to 0.
*/
switch (madera->type) {
+ case CS47L15:
+ madera->num_micbias = 1;
+ madera->num_childbias[0] = 3;
+ return;
case CS47L35:
madera->num_micbias = 2;
madera->num_childbias[0] = 2;
@@ -342,6 +414,13 @@ static void madera_set_micbias_info(struct madera *madera)
madera->num_childbias[0] = 4;
madera->num_childbias[1] = 4;
return;
+ case CS42L92:
+ case CS47L92:
+ case CS47L93:
+ madera->num_micbias = 2;
+ madera->num_childbias[0] = 4;
+ madera->num_childbias[1] = 2;
+ return;
default:
return;
}
@@ -389,9 +468,13 @@ int madera_dev_init(struct madera *madera)
* No devm_ because we need to control shutdown order of children.
*/
switch (madera->type) {
+ case CS47L15:
case CS47L35:
case CS47L90:
case CS47L91:
+ case CS42L92:
+ case CS47L92:
+ case CS47L93:
break;
case CS47L85:
case WM1840:
@@ -458,6 +541,19 @@ int madera_dev_init(struct madera *madera)
}
switch (hwid) {
+ case CS47L15_SILICON_ID:
+ if (IS_ENABLED(CONFIG_MFD_CS47L15)) {
+ switch (madera->type) {
+ case CS47L15:
+ patch_fn = &cs47l15_patch;
+ mfd_devs = cs47l15_devs;
+ n_devs = ARRAY_SIZE(cs47l15_devs);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
case CS47L35_SILICON_ID:
if (IS_ENABLED(CONFIG_MFD_CS47L35)) {
switch (madera->type) {
@@ -499,6 +595,21 @@ int madera_dev_init(struct madera *madera)
}
}
break;
+ case CS47L92_SILICON_ID:
+ if (IS_ENABLED(CONFIG_MFD_CS47L92)) {
+ switch (madera->type) {
+ case CS42L92:
+ case CS47L92:
+ case CS47L93:
+ patch_fn = cs47l92_patch;
+ mfd_devs = cs47l92_devs;
+ n_devs = ARRAY_SIZE(cs47l92_devs);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
default:
dev_err(madera->dev, "Unknown device ID: %x\n", hwid);
ret = -EINVAL;
diff --git a/drivers/mfd/madera-i2c.c b/drivers/mfd/madera-i2c.c
index 05ae94be01d8..6b965eb034b6 100644
--- a/drivers/mfd/madera-i2c.c
+++ b/drivers/mfd/madera-i2c.c
@@ -1,12 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* I2C bus interface to Cirrus Logic Madera codecs
*
* Copyright (C) 2015-2018 Cirrus Logic
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by the
- * Free Software Foundation; version 2.
*/
#include <linux/device.h>
@@ -39,6 +35,12 @@ static int madera_i2c_probe(struct i2c_client *i2c,
type = id->driver_data;
switch (type) {
+ case CS47L15:
+ if (IS_ENABLED(CONFIG_MFD_CS47L15)) {
+ regmap_16bit_config = &cs47l15_16bit_i2c_regmap;
+ regmap_32bit_config = &cs47l15_32bit_i2c_regmap;
+ }
+ break;
case CS47L35:
if (IS_ENABLED(CONFIG_MFD_CS47L35)) {
regmap_16bit_config = &cs47l35_16bit_i2c_regmap;
@@ -59,6 +61,14 @@ static int madera_i2c_probe(struct i2c_client *i2c,
regmap_32bit_config = &cs47l90_32bit_i2c_regmap;
}
break;
+ case CS42L92:
+ case CS47L92:
+ case CS47L93:
+ if (IS_ENABLED(CONFIG_MFD_CS47L92)) {
+ regmap_16bit_config = &cs47l92_16bit_i2c_regmap;
+ regmap_32bit_config = &cs47l92_32bit_i2c_regmap;
+ }
+ break;
default:
dev_err(&i2c->dev,
"Unknown Madera I2C device type %ld\n", type);
@@ -113,10 +123,14 @@ static int madera_i2c_remove(struct i2c_client *i2c)
}
static const struct i2c_device_id madera_i2c_id[] = {
+ { "cs47l15", CS47L15 },
{ "cs47l35", CS47L35 },
{ "cs47l85", CS47L85 },
{ "cs47l90", CS47L90 },
{ "cs47l91", CS47L91 },
+ { "cs42l92", CS42L92 },
+ { "cs47l92", CS47L92 },
+ { "cs47l93", CS47L93 },
{ "wm1840", WM1840 },
{ }
};
diff --git a/drivers/mfd/madera-spi.c b/drivers/mfd/madera-spi.c
index 4c398b278bba..e860f5ff0933 100644
--- a/drivers/mfd/madera-spi.c
+++ b/drivers/mfd/madera-spi.c
@@ -1,12 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* SPI bus interface to Cirrus Logic Madera codecs
*
* Copyright (C) 2015-2018 Cirrus Logic
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by the
- * Free Software Foundation; version 2.
*/
#include <linux/device.h>
@@ -39,6 +35,12 @@ static int madera_spi_probe(struct spi_device *spi)
type = id->driver_data;
switch (type) {
+ case CS47L15:
+ if (IS_ENABLED(CONFIG_MFD_CS47L15)) {
+ regmap_16bit_config = &cs47l15_16bit_spi_regmap;
+ regmap_32bit_config = &cs47l15_32bit_spi_regmap;
+ }
+ break;
case CS47L35:
if (IS_ENABLED(CONFIG_MFD_CS47L35)) {
regmap_16bit_config = &cs47l35_16bit_spi_regmap;
@@ -59,6 +61,14 @@ static int madera_spi_probe(struct spi_device *spi)
regmap_32bit_config = &cs47l90_32bit_spi_regmap;
}
break;
+ case CS42L92:
+ case CS47L92:
+ case CS47L93:
+ if (IS_ENABLED(CONFIG_MFD_CS47L92)) {
+ regmap_16bit_config = &cs47l92_16bit_spi_regmap;
+ regmap_32bit_config = &cs47l92_32bit_spi_regmap;
+ }
+ break;
default:
dev_err(&spi->dev,
"Unknown Madera SPI device type %ld\n", type);
@@ -112,10 +122,14 @@ static int madera_spi_remove(struct spi_device *spi)
}
static const struct spi_device_id madera_spi_ids[] = {
+ { "cs47l15", CS47L15 },
{ "cs47l35", CS47L35 },
{ "cs47l85", CS47L85 },
{ "cs47l90", CS47L90 },
{ "cs47l91", CS47L91 },
+ { "cs42l92", CS42L92 },
+ { "cs47l92", CS47L92 },
+ { "cs47l93", CS47L93 },
{ "wm1840", WM1840 },
{ }
};
diff --git a/drivers/mfd/madera.h b/drivers/mfd/madera.h
index 891b84efb9a7..9002056785a2 100644
--- a/drivers/mfd/madera.h
+++ b/drivers/mfd/madera.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* MFD internals for Cirrus Logic Madera codecs
*
* Copyright 2015-2018 Cirrus Logic
- *
- * 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.
*/
#ifndef MADERA_MFD_H
@@ -24,6 +21,12 @@ int madera_dev_exit(struct madera *madera);
const char *madera_name_from_type(enum madera_type type);
+extern const struct regmap_config cs47l15_16bit_spi_regmap;
+extern const struct regmap_config cs47l15_32bit_spi_regmap;
+extern const struct regmap_config cs47l15_16bit_i2c_regmap;
+extern const struct regmap_config cs47l15_32bit_i2c_regmap;
+int cs47l15_patch(struct madera *madera);
+
extern const struct regmap_config cs47l35_16bit_spi_regmap;
extern const struct regmap_config cs47l35_32bit_spi_regmap;
extern const struct regmap_config cs47l35_16bit_i2c_regmap;
@@ -41,4 +44,11 @@ extern const struct regmap_config cs47l90_32bit_spi_regmap;
extern const struct regmap_config cs47l90_16bit_i2c_regmap;
extern const struct regmap_config cs47l90_32bit_i2c_regmap;
int cs47l90_patch(struct madera *madera);
+
+extern const struct regmap_config cs47l92_16bit_spi_regmap;
+extern const struct regmap_config cs47l92_32bit_spi_regmap;
+extern const struct regmap_config cs47l92_16bit_i2c_regmap;
+extern const struct regmap_config cs47l92_32bit_i2c_regmap;
+int cs47l92_patch(struct madera *madera);
+
#endif
diff --git a/drivers/mfd/max77620.c b/drivers/mfd/max77620.c
index 436361ce3737..0c28965fcc6a 100644
--- a/drivers/mfd/max77620.c
+++ b/drivers/mfd/max77620.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Maxim MAX77620 MFD Driver
*
@@ -7,10 +8,6 @@
* Laxman Dewangan <ldewangan@nvidia.com>
* Chaitanya Bandi <bandik@nvidia.com>
* Mallikarjun Kasoju <mkasoju@nvidia.com>
- *
- * 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.
*/
/****************** Teminology used in driver ********************
diff --git a/drivers/mfd/max8907.c b/drivers/mfd/max8907.c
index 2974c8b1273b..cc01f706cb32 100644
--- a/drivers/mfd/max8907.c
+++ b/drivers/mfd/max8907.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* max8907.c - mfd driver for MAX8907
*
* Copyright (C) 2010 Gyungoh Yoo <jack.yoo@maxim-ic.com>
* Copyright (C) 2010-2012, NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/err.h>
diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c
index 87c724ba9793..0af6833b4080 100644
--- a/drivers/mfd/max8925-core.c
+++ b/drivers/mfd/max8925-core.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Base driver for Maxim MAX8925
*
* Copyright (C) 2009-2010 Marvell International Ltd.
* Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c
index 10063236132c..20bb19b71109 100644
--- a/drivers/mfd/max8925-i2c.c
+++ b/drivers/mfd/max8925-i2c.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* I2C driver for Maxim MAX8925
*
* Copyright (C) 2009 Marvell International Ltd.
* Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- * 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.
*/
#include <linux/kernel.h>
#include <linux/init.h>
diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c
index d0bf50e3568d..1abe7432aad8 100644
--- a/drivers/mfd/mc13xxx-core.c
+++ b/drivers/mfd/mc13xxx-core.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2009-2010 Pengutronix
* Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
*
* loosely based on an earlier driver that has
* Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/mfd/mc13xxx-i2c.c b/drivers/mfd/mc13xxx-i2c.c
index 67e4c9aa7d18..65b4dd8e5afb 100644
--- a/drivers/mfd/mc13xxx-i2c.c
+++ b/drivers/mfd/mc13xxx-i2c.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2009-2010 Creative Product Design
* Marc Reilly marc@cpdesign.com.au
- *
- * 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.
*/
#include <linux/slab.h>
diff --git a/drivers/mfd/mc13xxx-spi.c b/drivers/mfd/mc13xxx-spi.c
index ee3411cc5ce4..286ddcf5ddc6 100644
--- a/drivers/mfd/mc13xxx-spi.c
+++ b/drivers/mfd/mc13xxx-spi.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2009-2010 Pengutronix
* Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
*
* loosely based on an earlier driver that has
* Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
- *
- * 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.
*/
#include <linux/slab.h>
diff --git a/drivers/mfd/mc13xxx.h b/drivers/mfd/mc13xxx.h
index 33677d1dcf66..ce6eec52e8eb 100644
--- a/drivers/mfd/mc13xxx.h
+++ b/drivers/mfd/mc13xxx.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2012 Creative Product Design
* Marc Reilly <marc@cpdesign.com.au>
- *
- * 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.
*/
#ifndef __DRIVERS_MFD_MC13XXX_H
#define __DRIVERS_MFD_MC13XXX_H
diff --git a/drivers/mfd/menelaus.c b/drivers/mfd/menelaus.c
index 5c77787efe3d..b64d3315a5e1 100644
--- a/drivers/mfd/menelaus.c
+++ b/drivers/mfd/menelaus.c
@@ -1125,8 +1125,6 @@ static inline void menelaus_rtc_init(struct menelaus_chip *m)
menelaus_remove_irq_work(MENELAUS_RTCALM_IRQ);
device_init_wakeup(&m->client->dev, 0);
}
- dev_err(&m->client->dev, "can't register RTC: %d\n",
- (int) PTR_ERR(m->rtc));
the_menelaus->rtc = NULL;
}
}
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
index 1ade4c8cc91f..23276a80e3b4 100644
--- a/drivers/mfd/mfd-core.c
+++ b/drivers/mfd/mfd-core.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/mfd/mfd-core.c
*
* core MFD support
* Copyright (c) 2006 Ian Molton
* Copyright (c) 2007,2008 Dmitry Baryshkov
- *
- * 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.
- *
*/
#include <linux/kernel.h>
@@ -179,6 +175,7 @@ static int mfd_add_device(struct device *parent, int id,
for_each_child_of_node(parent->of_node, np) {
if (of_device_is_compatible(np, cell->of_compatible)) {
pdev->dev.of_node = np;
+ pdev->dev.fwnode = &np->fwnode;
break;
}
}
diff --git a/drivers/mfd/motorola-cpcap.c b/drivers/mfd/motorola-cpcap.c
index 20d9692640e1..52f38e57cdc1 100644
--- a/drivers/mfd/motorola-cpcap.c
+++ b/drivers/mfd/motorola-cpcap.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Motorola CPCAP PMIC core driver
*
* Copyright (C) 2016 Tony Lindgren <tony@atomide.com>
- *
- * 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.
*/
#include <linux/device.h>
diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c
index 908c1f45e64a..601cefb5c9d8 100644
--- a/drivers/mfd/rk808.c
+++ b/drivers/mfd/rk808.c
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
+#include <linux/syscore_ops.h>
struct rk808_reg_data {
int addr;
@@ -54,6 +55,27 @@ static bool rk808_is_volatile_reg(struct device *dev, unsigned int reg)
return false;
}
+static bool rk817_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+ /*
+ * Notes:
+ * - Technically the ROUND_30s bit makes RTC_CTRL_REG volatile, but
+ * we don't use that feature. It's better to cache.
+ */
+
+ switch (reg) {
+ case RK817_SECONDS_REG ... RK817_WEEKS_REG:
+ case RK817_RTC_STATUS_REG:
+ case RK817_INT_STS_REG0:
+ case RK817_INT_STS_REG1:
+ case RK817_INT_STS_REG2:
+ case RK817_SYS_STS:
+ return true;
+ }
+
+ return true;
+}
+
static const struct regmap_config rk818_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
@@ -78,6 +100,14 @@ static const struct regmap_config rk808_regmap_config = {
.volatile_reg = rk808_is_volatile_reg,
};
+static const struct regmap_config rk817_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = RK817_GPIO_INT_CFG,
+ .cache_type = REGCACHE_NONE,
+ .volatile_reg = rk817_is_volatile_reg,
+};
+
static struct resource rtc_resources[] = {
{
.start = RK808_IRQ_RTC_ALARM,
@@ -86,6 +116,10 @@ static struct resource rtc_resources[] = {
}
};
+static struct resource rk817_rtc_resources[] = {
+ DEFINE_RES_IRQ(RK817_IRQ_RTC_ALARM),
+};
+
static struct resource rk805_key_resources[] = {
{
.start = RK805_IRQ_PWRON_FALL,
@@ -99,6 +133,11 @@ static struct resource rk805_key_resources[] = {
}
};
+static struct resource rk817_pwrkey_resources[] = {
+ DEFINE_RES_IRQ(RK817_IRQ_PWRON_RISE),
+ DEFINE_RES_IRQ(RK817_IRQ_PWRON_FALL),
+};
+
static const struct mfd_cell rk805s[] = {
{ .name = "rk808-clkout", },
{ .name = "rk808-regulator", },
@@ -124,6 +163,21 @@ static const struct mfd_cell rk808s[] = {
},
};
+static const struct mfd_cell rk817s[] = {
+ { .name = "rk808-clkout",},
+ { .name = "rk808-regulator",},
+ {
+ .name = "rk8xx-pwrkey",
+ .num_resources = ARRAY_SIZE(rk817_pwrkey_resources),
+ .resources = &rk817_pwrkey_resources[0],
+ },
+ {
+ .name = "rk808-rtc",
+ .num_resources = ARRAY_SIZE(rk817_rtc_resources),
+ .resources = &rk817_rtc_resources[0],
+ },
+};
+
static const struct mfd_cell rk818s[] = {
{ .name = "rk808-clkout", },
{ .name = "rk808-regulator", },
@@ -159,6 +213,13 @@ static const struct rk808_reg_data rk808_pre_init_reg[] = {
VB_LO_SEL_3500MV },
};
+static const struct rk808_reg_data rk817_pre_init_reg[] = {
+ {RK817_RTC_CTRL_REG, RTC_STOP, RTC_STOP},
+ {RK817_GPIO_INT_CFG, RK817_INT_POL_MSK, RK817_INT_POL_H},
+ {RK817_SYS_CFG(1), RK817_HOTDIE_TEMP_MSK | RK817_TSD_TEMP_MSK,
+ RK817_HOTDIE_105 | RK817_TSD_140},
+};
+
static const struct rk808_reg_data rk818_pre_init_reg[] = {
/* improve efficiency */
{ RK818_BUCK2_CONFIG_REG, BUCK2_RATE_MASK, BUCK_ILMIN_250MA },
@@ -324,6 +385,33 @@ static const struct regmap_irq rk818_irqs[] = {
},
};
+static const struct regmap_irq rk817_irqs[RK817_IRQ_END] = {
+ REGMAP_IRQ_REG_LINE(0, 8),
+ REGMAP_IRQ_REG_LINE(1, 8),
+ REGMAP_IRQ_REG_LINE(2, 8),
+ REGMAP_IRQ_REG_LINE(3, 8),
+ REGMAP_IRQ_REG_LINE(4, 8),
+ REGMAP_IRQ_REG_LINE(5, 8),
+ REGMAP_IRQ_REG_LINE(6, 8),
+ REGMAP_IRQ_REG_LINE(7, 8),
+ REGMAP_IRQ_REG_LINE(8, 8),
+ REGMAP_IRQ_REG_LINE(9, 8),
+ REGMAP_IRQ_REG_LINE(10, 8),
+ REGMAP_IRQ_REG_LINE(11, 8),
+ REGMAP_IRQ_REG_LINE(12, 8),
+ REGMAP_IRQ_REG_LINE(13, 8),
+ REGMAP_IRQ_REG_LINE(14, 8),
+ REGMAP_IRQ_REG_LINE(15, 8),
+ REGMAP_IRQ_REG_LINE(16, 8),
+ REGMAP_IRQ_REG_LINE(17, 8),
+ REGMAP_IRQ_REG_LINE(18, 8),
+ REGMAP_IRQ_REG_LINE(19, 8),
+ REGMAP_IRQ_REG_LINE(20, 8),
+ REGMAP_IRQ_REG_LINE(21, 8),
+ REGMAP_IRQ_REG_LINE(22, 8),
+ REGMAP_IRQ_REG_LINE(23, 8)
+};
+
static struct regmap_irq_chip rk805_irq_chip = {
.name = "rk805",
.irqs = rk805_irqs,
@@ -347,6 +435,18 @@ static const struct regmap_irq_chip rk808_irq_chip = {
.init_ack_masked = true,
};
+static struct regmap_irq_chip rk817_irq_chip = {
+ .name = "rk817",
+ .irqs = rk817_irqs,
+ .num_irqs = ARRAY_SIZE(rk817_irqs),
+ .num_regs = 3,
+ .irq_reg_stride = 2,
+ .status_base = RK817_INT_STS_REG0,
+ .mask_base = RK817_INT_STS_MSK_REG0,
+ .ack_base = RK817_INT_STS_REG0,
+ .init_ack_masked = true,
+};
+
static const struct regmap_irq_chip rk818_irq_chip = {
.name = "rk818",
.irqs = rk818_irqs,
@@ -366,17 +466,29 @@ static void rk805_device_shutdown(void)
int ret;
struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
- if (!rk808) {
- dev_warn(&rk808_i2c_client->dev,
- "have no rk805, so do nothing here\n");
+ if (!rk808)
return;
- }
ret = regmap_update_bits(rk808->regmap,
RK805_DEV_CTRL_REG,
DEV_OFF, DEV_OFF);
if (ret)
- dev_err(&rk808_i2c_client->dev, "power off error!\n");
+ dev_err(&rk808_i2c_client->dev, "Failed to shutdown device!\n");
+}
+
+static void rk805_device_shutdown_prepare(void)
+{
+ int ret;
+ struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
+
+ if (!rk808)
+ return;
+
+ ret = regmap_update_bits(rk808->regmap,
+ RK805_GPIO_IO_POL_REG,
+ SLP_SD_MSK, SHUTDOWN_FUN);
+ if (ret)
+ dev_err(&rk808_i2c_client->dev, "Failed to shutdown device!\n");
}
static void rk808_device_shutdown(void)
@@ -384,17 +496,14 @@ static void rk808_device_shutdown(void)
int ret;
struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
- if (!rk808) {
- dev_warn(&rk808_i2c_client->dev,
- "have no rk808, so do nothing here\n");
+ if (!rk808)
return;
- }
ret = regmap_update_bits(rk808->regmap,
RK808_DEVCTRL_REG,
DEV_OFF_RST, DEV_OFF_RST);
if (ret)
- dev_err(&rk808_i2c_client->dev, "power off error!\n");
+ dev_err(&rk808_i2c_client->dev, "Failed to shutdown device!\n");
}
static void rk818_device_shutdown(void)
@@ -402,22 +511,43 @@ static void rk818_device_shutdown(void)
int ret;
struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
- if (!rk808) {
- dev_warn(&rk808_i2c_client->dev,
- "have no rk818, so do nothing here\n");
+ if (!rk808)
return;
- }
ret = regmap_update_bits(rk808->regmap,
RK818_DEVCTRL_REG,
DEV_OFF, DEV_OFF);
if (ret)
- dev_err(&rk808_i2c_client->dev, "power off error!\n");
+ dev_err(&rk808_i2c_client->dev, "Failed to shutdown device!\n");
+}
+
+static void rk8xx_syscore_shutdown(void)
+{
+ struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
+ int ret;
+
+ if (system_state == SYSTEM_POWER_OFF &&
+ (rk808->variant == RK809_ID || rk808->variant == RK817_ID)) {
+ ret = regmap_update_bits(rk808->regmap,
+ RK817_SYS_CFG(3),
+ RK817_SLPPIN_FUNC_MSK,
+ SLPPIN_DN_FUN);
+ if (ret) {
+ dev_warn(&rk808_i2c_client->dev,
+ "Cannot switch to power down function\n");
+ }
+ }
}
+static struct syscore_ops rk808_syscore_ops = {
+ .shutdown = rk8xx_syscore_shutdown,
+};
+
static const struct of_device_id rk808_of_match[] = {
{ .compatible = "rockchip,rk805" },
{ .compatible = "rockchip,rk808" },
+ { .compatible = "rockchip,rk809" },
+ { .compatible = "rockchip,rk817" },
{ .compatible = "rockchip,rk818" },
{ },
};
@@ -430,10 +560,10 @@ static int rk808_probe(struct i2c_client *client,
struct rk808 *rk808;
const struct rk808_reg_data *pre_init_reg;
const struct mfd_cell *cells;
- void (*pm_pwroff_fn)(void);
int nr_pre_init_regs;
int nr_cells;
int pm_off = 0, msb, lsb;
+ unsigned char pmic_id_msb, pmic_id_lsb;
int ret;
int i;
@@ -441,15 +571,24 @@ static int rk808_probe(struct i2c_client *client,
if (!rk808)
return -ENOMEM;
+ if (of_device_is_compatible(np, "rockchip,rk817") ||
+ of_device_is_compatible(np, "rockchip,rk809")) {
+ pmic_id_msb = RK817_ID_MSB;
+ pmic_id_lsb = RK817_ID_LSB;
+ } else {
+ pmic_id_msb = RK808_ID_MSB;
+ pmic_id_lsb = RK808_ID_LSB;
+ }
+
/* Read chip variant */
- msb = i2c_smbus_read_byte_data(client, RK808_ID_MSB);
+ msb = i2c_smbus_read_byte_data(client, pmic_id_msb);
if (msb < 0) {
dev_err(&client->dev, "failed to read the chip id at 0x%x\n",
RK808_ID_MSB);
return msb;
}
- lsb = i2c_smbus_read_byte_data(client, RK808_ID_LSB);
+ lsb = i2c_smbus_read_byte_data(client, pmic_id_lsb);
if (lsb < 0) {
dev_err(&client->dev, "failed to read the chip id at 0x%x\n",
RK808_ID_LSB);
@@ -467,7 +606,8 @@ static int rk808_probe(struct i2c_client *client,
nr_pre_init_regs = ARRAY_SIZE(rk805_pre_init_reg);
cells = rk805s;
nr_cells = ARRAY_SIZE(rk805s);
- pm_pwroff_fn = rk805_device_shutdown;
+ rk808->pm_pwroff_fn = rk805_device_shutdown;
+ rk808->pm_pwroff_prep_fn = rk805_device_shutdown_prepare;
break;
case RK808_ID:
rk808->regmap_cfg = &rk808_regmap_config;
@@ -476,7 +616,7 @@ static int rk808_probe(struct i2c_client *client,
nr_pre_init_regs = ARRAY_SIZE(rk808_pre_init_reg);
cells = rk808s;
nr_cells = ARRAY_SIZE(rk808s);
- pm_pwroff_fn = rk808_device_shutdown;
+ rk808->pm_pwroff_fn = rk808_device_shutdown;
break;
case RK818_ID:
rk808->regmap_cfg = &rk818_regmap_config;
@@ -485,7 +625,17 @@ static int rk808_probe(struct i2c_client *client,
nr_pre_init_regs = ARRAY_SIZE(rk818_pre_init_reg);
cells = rk818s;
nr_cells = ARRAY_SIZE(rk818s);
- pm_pwroff_fn = rk818_device_shutdown;
+ rk808->pm_pwroff_fn = rk818_device_shutdown;
+ break;
+ case RK809_ID:
+ case RK817_ID:
+ rk808->regmap_cfg = &rk817_regmap_config;
+ rk808->regmap_irq_chip = &rk817_irq_chip;
+ pre_init_reg = rk817_pre_init_reg;
+ nr_pre_init_regs = ARRAY_SIZE(rk817_pre_init_reg);
+ cells = rk817s;
+ nr_cells = ARRAY_SIZE(rk817s);
+ register_syscore_ops(&rk808_syscore_ops);
break;
default:
dev_err(&client->dev, "Unsupported RK8XX ID %lu\n",
@@ -540,7 +690,13 @@ static int rk808_probe(struct i2c_client *client,
"rockchip,system-power-controller");
if (pm_off && !pm_power_off) {
rk808_i2c_client = client;
- pm_power_off = pm_pwroff_fn;
+ pm_power_off = rk808->pm_pwroff_fn;
+ }
+
+ if (pm_off && !pm_power_off_prepare) {
+ if (!rk808_i2c_client)
+ rk808_i2c_client = client;
+ pm_power_off_prepare = rk808->pm_pwroff_prep_fn;
}
return 0;
@@ -555,15 +711,70 @@ static int rk808_remove(struct i2c_client *client)
struct rk808 *rk808 = i2c_get_clientdata(client);
regmap_del_irq_chip(client->irq, rk808->irq_data);
- pm_power_off = NULL;
+
+ /**
+ * pm_power_off may points to a function from another module.
+ * Check if the pointer is set by us and only then overwrite it.
+ */
+ if (rk808->pm_pwroff_fn && pm_power_off == rk808->pm_pwroff_fn)
+ pm_power_off = NULL;
+
+ /**
+ * As above, check if the pointer is set by us before overwrite.
+ */
+ if (rk808->pm_pwroff_prep_fn &&
+ pm_power_off_prepare == rk808->pm_pwroff_prep_fn)
+ pm_power_off_prepare = NULL;
return 0;
}
+static int rk8xx_suspend(struct device *dev)
+{
+ struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
+ int ret = 0;
+
+ switch (rk808->variant) {
+ case RK809_ID:
+ case RK817_ID:
+ ret = regmap_update_bits(rk808->regmap,
+ RK817_SYS_CFG(3),
+ RK817_SLPPIN_FUNC_MSK,
+ SLPPIN_SLP_FUN);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static int rk8xx_resume(struct device *dev)
+{
+ struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
+ int ret = 0;
+
+ switch (rk808->variant) {
+ case RK809_ID:
+ case RK817_ID:
+ ret = regmap_update_bits(rk808->regmap,
+ RK817_SYS_CFG(3),
+ RK817_SLPPIN_FUNC_MSK,
+ SLPPIN_NULL_FUN);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+SIMPLE_DEV_PM_OPS(rk8xx_pm_ops, rk8xx_suspend, rk8xx_resume);
+
static struct i2c_driver rk808_i2c_driver = {
.driver = {
.name = "rk808",
.of_match_table = rk808_of_match,
+ .pm = &rk8xx_pm_ops,
},
.probe = rk808_probe,
.remove = rk808_remove,
diff --git a/drivers/mfd/rohm-bd70528.c b/drivers/mfd/rohm-bd70528.c
new file mode 100644
index 000000000000..55599d5c5c86
--- /dev/null
+++ b/drivers/mfd/rohm-bd70528.c
@@ -0,0 +1,316 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Copyright (C) 2019 ROHM Semiconductors
+//
+// ROHM BD70528 PMIC driver
+
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/rohm-bd70528.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+#define BD70528_NUM_OF_GPIOS 4
+
+static const struct resource rtc_irqs[] = {
+ DEFINE_RES_IRQ_NAMED(BD70528_INT_RTC_ALARM, "bd70528-rtc-alm"),
+ DEFINE_RES_IRQ_NAMED(BD70528_INT_ELPS_TIM, "bd70528-elapsed-timer"),
+};
+
+static const struct resource charger_irqs[] = {
+ DEFINE_RES_IRQ_NAMED(BD70528_INT_BAT_OV_RES, "bd70528-bat-ov-res"),
+ DEFINE_RES_IRQ_NAMED(BD70528_INT_BAT_OV_DET, "bd70528-bat-ov-det"),
+ DEFINE_RES_IRQ_NAMED(BD70528_INT_DBAT_DET, "bd70528-bat-dead"),
+ DEFINE_RES_IRQ_NAMED(BD70528_INT_BATTSD_COLD_RES, "bd70528-bat-warmed"),
+ DEFINE_RES_IRQ_NAMED(BD70528_INT_BATTSD_COLD_DET, "bd70528-bat-cold"),
+ DEFINE_RES_IRQ_NAMED(BD70528_INT_BATTSD_HOT_RES, "bd70528-bat-cooled"),
+ DEFINE_RES_IRQ_NAMED(BD70528_INT_BATTSD_HOT_DET, "bd70528-bat-hot"),
+ DEFINE_RES_IRQ_NAMED(BD70528_INT_CHG_TSD, "bd70528-chg-tshd"),
+ DEFINE_RES_IRQ_NAMED(BD70528_INT_BAT_RMV, "bd70528-bat-removed"),
+ DEFINE_RES_IRQ_NAMED(BD70528_INT_BAT_DET, "bd70528-bat-detected"),
+ DEFINE_RES_IRQ_NAMED(BD70528_INT_DCIN2_OV_RES, "bd70528-dcin2-ov-res"),
+ DEFINE_RES_IRQ_NAMED(BD70528_INT_DCIN2_OV_DET, "bd70528-dcin2-ov-det"),
+ DEFINE_RES_IRQ_NAMED(BD70528_INT_DCIN2_RMV, "bd70528-dcin2-removed"),
+ DEFINE_RES_IRQ_NAMED(BD70528_INT_DCIN2_DET, "bd70528-dcin2-detected"),
+ DEFINE_RES_IRQ_NAMED(BD70528_INT_DCIN1_RMV, "bd70528-dcin1-removed"),
+ DEFINE_RES_IRQ_NAMED(BD70528_INT_DCIN1_DET, "bd70528-dcin1-detected"),
+};
+
+static struct mfd_cell bd70528_mfd_cells[] = {
+ { .name = "bd70528-pmic", },
+ { .name = "bd70528-gpio", },
+ /*
+ * We use BD71837 driver to drive the clock block. Only differences to
+ * BD70528 clock gate are the register address and mask.
+ */
+ { .name = "bd718xx-clk", },
+ { .name = "bd70528-wdt", },
+ {
+ .name = "bd70528-power",
+ .resources = charger_irqs,
+ .num_resources = ARRAY_SIZE(charger_irqs),
+ }, {
+ .name = "bd70528-rtc",
+ .resources = rtc_irqs,
+ .num_resources = ARRAY_SIZE(rtc_irqs),
+ },
+};
+
+static const struct regmap_range volatile_ranges[] = {
+ {
+ .range_min = BD70528_REG_INT_MAIN,
+ .range_max = BD70528_REG_INT_OP_FAIL,
+ }, {
+ .range_min = BD70528_REG_RTC_COUNT_H,
+ .range_max = BD70528_REG_RTC_ALM_REPEAT,
+ }, {
+ /*
+ * WDT control reg is special. Magic values must be written to
+ * it in order to change the control. Should not be cached.
+ */
+ .range_min = BD70528_REG_WDT_CTRL,
+ .range_max = BD70528_REG_WDT_CTRL,
+ }, {
+ /*
+ * BD70528 also contains a few other registers which require
+ * magic sequences to be written in order to update the value.
+ * At least SHIPMODE, HWRESET, WARMRESET,and STANDBY
+ */
+ .range_min = BD70528_REG_SHIPMODE,
+ .range_max = BD70528_REG_STANDBY,
+ },
+};
+
+static const struct regmap_access_table volatile_regs = {
+ .yes_ranges = &volatile_ranges[0],
+ .n_yes_ranges = ARRAY_SIZE(volatile_ranges),
+};
+
+static struct regmap_config bd70528_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_table = &volatile_regs,
+ .max_register = BD70528_MAX_REGISTER,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+/*
+ * Mapping of main IRQ register bits to sub-IRQ register offsets so that we can
+ * access corect sub-IRQ registers based on bits that are set in main IRQ
+ * register.
+ */
+
+/* bit [0] - Shutdown register */
+unsigned int bit0_offsets[] = {0}; /* Shutdown register */
+unsigned int bit1_offsets[] = {1}; /* Power failure register */
+unsigned int bit2_offsets[] = {2}; /* VR FAULT register */
+unsigned int bit3_offsets[] = {3}; /* PMU register interrupts */
+unsigned int bit4_offsets[] = {4, 5}; /* Charger 1 and Charger 2 registers */
+unsigned int bit5_offsets[] = {6}; /* RTC register */
+unsigned int bit6_offsets[] = {7}; /* GPIO register */
+unsigned int bit7_offsets[] = {8}; /* Invalid operation register */
+
+static struct regmap_irq_sub_irq_map bd70528_sub_irq_offsets[] = {
+ REGMAP_IRQ_MAIN_REG_OFFSET(bit0_offsets),
+ REGMAP_IRQ_MAIN_REG_OFFSET(bit1_offsets),
+ REGMAP_IRQ_MAIN_REG_OFFSET(bit2_offsets),
+ REGMAP_IRQ_MAIN_REG_OFFSET(bit3_offsets),
+ REGMAP_IRQ_MAIN_REG_OFFSET(bit4_offsets),
+ REGMAP_IRQ_MAIN_REG_OFFSET(bit5_offsets),
+ REGMAP_IRQ_MAIN_REG_OFFSET(bit6_offsets),
+ REGMAP_IRQ_MAIN_REG_OFFSET(bit7_offsets),
+};
+
+static struct regmap_irq bd70528_irqs[] = {
+ REGMAP_IRQ_REG(BD70528_INT_LONGPUSH, 0, BD70528_INT_LONGPUSH_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_WDT, 0, BD70528_INT_WDT_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_HWRESET, 0, BD70528_INT_HWRESET_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_RSTB_FAULT, 0, BD70528_INT_RSTB_FAULT_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_VBAT_UVLO, 0, BD70528_INT_VBAT_UVLO_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_TSD, 0, BD70528_INT_TSD_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_RSTIN, 0, BD70528_INT_RSTIN_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_BUCK1_FAULT, 1,
+ BD70528_INT_BUCK1_FAULT_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_BUCK2_FAULT, 1,
+ BD70528_INT_BUCK2_FAULT_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_BUCK3_FAULT, 1,
+ BD70528_INT_BUCK3_FAULT_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_LDO1_FAULT, 1, BD70528_INT_LDO1_FAULT_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_LDO2_FAULT, 1, BD70528_INT_LDO2_FAULT_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_LDO3_FAULT, 1, BD70528_INT_LDO3_FAULT_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_LED1_FAULT, 1, BD70528_INT_LED1_FAULT_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_LED2_FAULT, 1, BD70528_INT_LED2_FAULT_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_BUCK1_OCP, 2, BD70528_INT_BUCK1_OCP_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_BUCK2_OCP, 2, BD70528_INT_BUCK2_OCP_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_BUCK3_OCP, 2, BD70528_INT_BUCK3_OCP_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_LED1_OCP, 2, BD70528_INT_LED1_OCP_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_LED2_OCP, 2, BD70528_INT_LED2_OCP_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_BUCK1_FULLON, 2,
+ BD70528_INT_BUCK1_FULLON_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_BUCK2_FULLON, 2,
+ BD70528_INT_BUCK2_FULLON_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_SHORTPUSH, 3, BD70528_INT_SHORTPUSH_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_AUTO_WAKEUP, 3,
+ BD70528_INT_AUTO_WAKEUP_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_STATE_CHANGE, 3,
+ BD70528_INT_STATE_CHANGE_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_BAT_OV_RES, 4, BD70528_INT_BAT_OV_RES_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_BAT_OV_DET, 4, BD70528_INT_BAT_OV_DET_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_DBAT_DET, 4, BD70528_INT_DBAT_DET_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_BATTSD_COLD_RES, 4,
+ BD70528_INT_BATTSD_COLD_RES_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_BATTSD_COLD_DET, 4,
+ BD70528_INT_BATTSD_COLD_DET_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_BATTSD_HOT_RES, 4,
+ BD70528_INT_BATTSD_HOT_RES_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_BATTSD_HOT_DET, 4,
+ BD70528_INT_BATTSD_HOT_DET_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_CHG_TSD, 4, BD70528_INT_CHG_TSD_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_BAT_RMV, 5, BD70528_INT_BAT_RMV_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_BAT_DET, 5, BD70528_INT_BAT_DET_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_DCIN2_OV_RES, 5,
+ BD70528_INT_DCIN2_OV_RES_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_DCIN2_OV_DET, 5,
+ BD70528_INT_DCIN2_OV_DET_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_DCIN2_RMV, 5, BD70528_INT_DCIN2_RMV_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_DCIN2_DET, 5, BD70528_INT_DCIN2_DET_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_DCIN1_RMV, 5, BD70528_INT_DCIN1_RMV_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_DCIN1_DET, 5, BD70528_INT_DCIN1_DET_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_RTC_ALARM, 6, BD70528_INT_RTC_ALARM_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_ELPS_TIM, 6, BD70528_INT_ELPS_TIM_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_GPIO0, 7, BD70528_INT_GPIO0_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_GPIO1, 7, BD70528_INT_GPIO1_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_GPIO2, 7, BD70528_INT_GPIO2_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_GPIO3, 7, BD70528_INT_GPIO3_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_BUCK1_DVS_OPFAIL, 8,
+ BD70528_INT_BUCK1_DVS_OPFAIL_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_BUCK2_DVS_OPFAIL, 8,
+ BD70528_INT_BUCK2_DVS_OPFAIL_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_BUCK3_DVS_OPFAIL, 8,
+ BD70528_INT_BUCK3_DVS_OPFAIL_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_LED1_VOLT_OPFAIL, 8,
+ BD70528_INT_LED1_VOLT_OPFAIL_MASK),
+ REGMAP_IRQ_REG(BD70528_INT_LED2_VOLT_OPFAIL, 8,
+ BD70528_INT_LED2_VOLT_OPFAIL_MASK),
+};
+
+static struct regmap_irq_chip bd70528_irq_chip = {
+ .name = "bd70528_irq",
+ .main_status = BD70528_REG_INT_MAIN,
+ .irqs = &bd70528_irqs[0],
+ .num_irqs = ARRAY_SIZE(bd70528_irqs),
+ .status_base = BD70528_REG_INT_SHDN,
+ .mask_base = BD70528_REG_INT_SHDN_MASK,
+ .ack_base = BD70528_REG_INT_SHDN,
+ .type_base = BD70528_REG_GPIO1_IN,
+ .init_ack_masked = true,
+ .num_regs = 9,
+ .num_main_regs = 1,
+ .num_type_reg = 4,
+ .sub_reg_offsets = &bd70528_sub_irq_offsets[0],
+ .num_main_status_bits = 8,
+ .irq_reg_stride = 1,
+};
+
+static int bd70528_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct bd70528_data *bd70528;
+ struct regmap_irq_chip_data *irq_data;
+ int ret, i;
+
+ if (!i2c->irq) {
+ dev_err(&i2c->dev, "No IRQ configured\n");
+ return -EINVAL;
+ }
+
+ bd70528 = devm_kzalloc(&i2c->dev, sizeof(*bd70528), GFP_KERNEL);
+ if (!bd70528)
+ return -ENOMEM;
+
+ mutex_init(&bd70528->rtc_timer_lock);
+
+ dev_set_drvdata(&i2c->dev, &bd70528->chip);
+
+ bd70528->chip.chip_type = ROHM_CHIP_TYPE_BD70528;
+ bd70528->chip.regmap = devm_regmap_init_i2c(i2c, &bd70528_regmap);
+ if (IS_ERR(bd70528->chip.regmap)) {
+ dev_err(&i2c->dev, "Failed to initialize Regmap\n");
+ return PTR_ERR(bd70528->chip.regmap);
+ }
+
+ /*
+ * Disallow type setting for all IRQs by default as most of them do not
+ * support setting type.
+ */
+ for (i = 0; i < ARRAY_SIZE(bd70528_irqs); i++)
+ bd70528_irqs[i].type.types_supported = 0;
+
+ /* Set IRQ typesetting information for GPIO pins 0 - 3 */
+ for (i = 0; i < BD70528_NUM_OF_GPIOS; i++) {
+ struct regmap_irq_type *type;
+
+ type = &bd70528_irqs[BD70528_INT_GPIO0 + i].type;
+ type->type_reg_offset = 2 * i;
+ type->type_rising_val = 0x20;
+ type->type_falling_val = 0x10;
+ type->type_level_high_val = 0x40;
+ type->type_level_low_val = 0x50;
+ type->types_supported = (IRQ_TYPE_EDGE_BOTH |
+ IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW);
+ }
+
+ ret = devm_regmap_add_irq_chip(&i2c->dev, bd70528->chip.regmap,
+ i2c->irq, IRQF_ONESHOT, 0,
+ &bd70528_irq_chip, &irq_data);
+ if (ret) {
+ dev_err(&i2c->dev, "Failed to add IRQ chip\n");
+ return ret;
+ }
+ dev_dbg(&i2c->dev, "Registered %d IRQs for chip\n",
+ bd70528_irq_chip.num_irqs);
+
+ /*
+ * BD70528 IRQ controller is not touching the main mask register.
+ * So enable the GPIO block interrupts at main level. We can just leave
+ * them enabled as the IRQ controller should disable IRQs from
+ * sub-registers when IRQ is disabled or freed.
+ */
+ ret = regmap_update_bits(bd70528->chip.regmap,
+ BD70528_REG_INT_MAIN_MASK,
+ BD70528_INT_GPIO_MASK, 0);
+
+ ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO,
+ bd70528_mfd_cells,
+ ARRAY_SIZE(bd70528_mfd_cells), NULL, 0,
+ regmap_irq_get_domain(irq_data));
+ if (ret)
+ dev_err(&i2c->dev, "Failed to create subdevices\n");
+
+ return ret;
+}
+
+static const struct of_device_id bd70528_of_match[] = {
+ { .compatible = "rohm,bd70528", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, bd70528_of_match);
+
+static struct i2c_driver bd70528_drv = {
+ .driver = {
+ .name = "rohm-bd70528",
+ .of_match_table = bd70528_of_match,
+ },
+ .probe = &bd70528_i2c_probe,
+};
+
+module_i2c_driver(bd70528_drv);
+
+MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
+MODULE_DESCRIPTION("ROHM BD70528 Power Management IC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/rohm-bd718x7.c b/drivers/mfd/rohm-bd718x7.c
index a29d529a96f4..85e7f5133365 100644
--- a/drivers/mfd/rohm-bd718x7.c
+++ b/drivers/mfd/rohm-bd718x7.c
@@ -81,6 +81,44 @@ static const struct regmap_config bd718xx_regmap_config = {
.cache_type = REGCACHE_RBTREE,
};
+static int bd718xx_init_press_duration(struct bd718xx *bd718xx)
+{
+ struct device* dev = bd718xx->chip.dev;
+ u32 short_press_ms, long_press_ms;
+ u32 short_press_value, long_press_value;
+ int ret;
+
+ ret = of_property_read_u32(dev->of_node, "rohm,short-press-ms",
+ &short_press_ms);
+ if (!ret) {
+ short_press_value = min(15u, (short_press_ms + 250) / 500);
+ ret = regmap_update_bits(bd718xx->chip.regmap,
+ BD718XX_REG_PWRONCONFIG0,
+ BD718XX_PWRBTN_PRESS_DURATION_MASK,
+ short_press_value);
+ if (ret) {
+ dev_err(dev, "Failed to init pwron short press\n");
+ return ret;
+ }
+ }
+
+ ret = of_property_read_u32(dev->of_node, "rohm,long-press-ms",
+ &long_press_ms);
+ if (!ret) {
+ long_press_value = min(15u, (long_press_ms + 500) / 1000);
+ ret = regmap_update_bits(bd718xx->chip.regmap,
+ BD718XX_REG_PWRONCONFIG1,
+ BD718XX_PWRBTN_PRESS_DURATION_MASK,
+ long_press_value);
+ if (ret) {
+ dev_err(dev, "Failed to init pwron long press\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static int bd718xx_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -98,18 +136,19 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c,
return -ENOMEM;
bd718xx->chip_irq = i2c->irq;
- bd718xx->chip_type = (unsigned int)(uintptr_t)
+ bd718xx->chip.chip_type = (unsigned int)(uintptr_t)
of_device_get_match_data(&i2c->dev);
- bd718xx->dev = &i2c->dev;
+ bd718xx->chip.dev = &i2c->dev;
dev_set_drvdata(&i2c->dev, bd718xx);
- bd718xx->regmap = devm_regmap_init_i2c(i2c, &bd718xx_regmap_config);
- if (IS_ERR(bd718xx->regmap)) {
+ bd718xx->chip.regmap = devm_regmap_init_i2c(i2c,
+ &bd718xx_regmap_config);
+ if (IS_ERR(bd718xx->chip.regmap)) {
dev_err(&i2c->dev, "regmap initialization failed\n");
- return PTR_ERR(bd718xx->regmap);
+ return PTR_ERR(bd718xx->chip.regmap);
}
- ret = devm_regmap_add_irq_chip(&i2c->dev, bd718xx->regmap,
+ ret = devm_regmap_add_irq_chip(&i2c->dev, bd718xx->chip.regmap,
bd718xx->chip_irq, IRQF_ONESHOT, 0,
&bd718xx_irq_chip, &bd718xx->irq_data);
if (ret) {
@@ -117,28 +156,9 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c,
return ret;
}
- /* Configure short press to 10 milliseconds */
- ret = regmap_update_bits(bd718xx->regmap,
- BD718XX_REG_PWRONCONFIG0,
- BD718XX_PWRBTN_PRESS_DURATION_MASK,
- BD718XX_PWRBTN_SHORT_PRESS_10MS);
- if (ret) {
- dev_err(&i2c->dev,
- "Failed to configure button short press timeout\n");
- return ret;
- }
-
- /* Configure long press to 10 seconds */
- ret = regmap_update_bits(bd718xx->regmap,
- BD718XX_REG_PWRONCONFIG1,
- BD718XX_PWRBTN_PRESS_DURATION_MASK,
- BD718XX_PWRBTN_LONG_PRESS_10S);
-
- if (ret) {
- dev_err(&i2c->dev,
- "Failed to configure button long press timeout\n");
+ ret = bd718xx_init_press_duration(bd718xx);
+ if (ret)
return ret;
- }
ret = regmap_irq_get_virq(bd718xx->irq_data, BD718XX_INT_PWRBTN_S);
@@ -149,7 +169,7 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c,
button.irq = ret;
- ret = devm_mfd_add_devices(bd718xx->dev, PLATFORM_DEVID_AUTO,
+ ret = devm_mfd_add_devices(bd718xx->chip.dev, PLATFORM_DEVID_AUTO,
bd718xx_mfd_cells,
ARRAY_SIZE(bd718xx_mfd_cells), NULL, 0,
regmap_irq_get_domain(bd718xx->irq_data));
@@ -162,11 +182,11 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c,
static const struct of_device_id bd718xx_of_match[] = {
{
.compatible = "rohm,bd71837",
- .data = (void *)BD718XX_TYPE_BD71837,
+ .data = (void *)ROHM_CHIP_TYPE_BD71837,
},
{
.compatible = "rohm,bd71847",
- .data = (void *)BD718XX_TYPE_BD71847,
+ .data = (void *)ROHM_CHIP_TYPE_BD71847,
},
{ }
};
diff --git a/drivers/mfd/sky81452.c b/drivers/mfd/sky81452.c
index 30a2a677100f..76eedfae8553 100644
--- a/drivers/mfd/sky81452.c
+++ b/drivers/mfd/sky81452.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* sky81452.c SKY81452 MFD driver
*
* Copyright 2014 Skyworks Solutions Inc.
* Author : Gyungoh Yoo <jack.yoo@skyworksinc.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
index d217debf382e..9b9b06d36cb1 100644
--- a/drivers/mfd/sm501.c
+++ b/drivers/mfd/sm501.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* linux/drivers/mfd/sm501.c
*
* Copyright (C) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
* Vincent Sanders <vince@simtec.co.uk>
*
- * 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.
- *
* SM501 MFD driver
*/
diff --git a/drivers/mfd/stmfx.c b/drivers/mfd/stmfx.c
index fe8efba2d45f..857991cb3cbb 100644
--- a/drivers/mfd/stmfx.c
+++ b/drivers/mfd/stmfx.c
@@ -204,12 +204,11 @@ static struct irq_chip stmfx_irq_chip = {
static irqreturn_t stmfx_irq_handler(int irq, void *data)
{
struct stmfx *stmfx = data;
- unsigned long n, pending;
- u32 ack;
- int ret;
+ unsigned long bits;
+ u32 pending, ack;
+ int n, ret;
- ret = regmap_read(stmfx->map, STMFX_REG_IRQ_PENDING,
- (u32 *)&pending);
+ ret = regmap_read(stmfx->map, STMFX_REG_IRQ_PENDING, &pending);
if (ret)
return IRQ_NONE;
@@ -224,7 +223,8 @@ static irqreturn_t stmfx_irq_handler(int irq, void *data)
return IRQ_NONE;
}
- for_each_set_bit(n, &pending, STMFX_REG_IRQ_SRC_MAX)
+ bits = pending;
+ for_each_set_bit(n, &bits, STMFX_REG_IRQ_SRC_MAX)
handle_nested_irq(irq_find_mapping(stmfx->irq_domain, n));
return IRQ_HANDLED;
diff --git a/drivers/mfd/stmpe-i2c.c b/drivers/mfd/stmpe-i2c.c
index 863c39a3353c..61aa020199f5 100644
--- a/drivers/mfd/stmpe-i2c.c
+++ b/drivers/mfd/stmpe-i2c.c
@@ -1,10 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ST Microelectronics MFD: stmpe's i2c client specific driver
*
* Copyright (C) ST-Ericsson SA 2010
* Copyright (C) ST Microelectronics SA 2011
*
- * License Terms: GNU General Public License, version 2
* Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
* Author: Viresh Kumar <vireshk@kernel.org> for ST Microelectronics
*/
diff --git a/drivers/mfd/stmpe-spi.c b/drivers/mfd/stmpe-spi.c
index f8b14ab8b9d7..7351734f7593 100644
--- a/drivers/mfd/stmpe-spi.c
+++ b/drivers/mfd/stmpe-spi.c
@@ -1,9 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ST Microelectronics MFD: stmpe's spi client specific driver
*
* Copyright (C) ST Microelectronics SA 2011
*
- * License Terms: GNU General Public License, version 2
* Author: Viresh Kumar <vireshk@kernel.org> for ST Microelectronics
*/
diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c
index f2acb1f6a29c..1aee3b3253fc 100644
--- a/drivers/mfd/stmpe.c
+++ b/drivers/mfd/stmpe.c
@@ -1,9 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ST Microelectronics MFD: stmpe's driver
*
* Copyright (C) ST-Ericsson SA 2010
*
- * License Terms: GNU General Public License, version 2
* Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
*/
diff --git a/drivers/mfd/stmpe.h b/drivers/mfd/stmpe.h
index f7efdd8a5fc6..83491e99ba3c 100644
--- a/drivers/mfd/stmpe.h
+++ b/drivers/mfd/stmpe.h
@@ -1,7 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) ST-Ericsson SA 2010
*
- * License Terms: GNU General Public License, version 2
* Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
*/
diff --git a/drivers/mfd/sun4i-gpadc.c b/drivers/mfd/sun4i-gpadc.c
index 9cfc88134d03..b346fbce3c01 100644
--- a/drivers/mfd/sun4i-gpadc.c
+++ b/drivers/mfd/sun4i-gpadc.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* ADC MFD core driver for sunxi platforms
*
* Copyright (c) 2016 Quentin Schulz <quentin.schulz@free-electrons.com>
- *
- * 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.
*/
#include <linux/interrupt.h>
diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c
index 8ce1e41d632c..b65e585fc8c6 100644
--- a/drivers/mfd/syscon.c
+++ b/drivers/mfd/syscon.c
@@ -190,27 +190,6 @@ struct regmap *syscon_regmap_lookup_by_compatible(const char *s)
}
EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_compatible);
-static int syscon_match_pdevname(struct device *dev, void *data)
-{
- return !strcmp(dev_name(dev), (const char *)data);
-}
-
-struct regmap *syscon_regmap_lookup_by_pdevname(const char *s)
-{
- struct device *dev;
- struct syscon *syscon;
-
- dev = driver_find_device(&syscon_driver.driver, NULL, (void *)s,
- syscon_match_pdevname);
- if (!dev)
- return ERR_PTR(-EPROBE_DEFER);
-
- syscon = dev_get_drvdata(dev);
-
- return syscon->regmap;
-}
-EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_pdevname);
-
struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np,
const char *property)
{
diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c
index e9cfb147345e..70da0c4ae457 100644
--- a/drivers/mfd/t7l66xb.c
+++ b/drivers/mfd/t7l66xb.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
*
* Toshiba T7L66XB core mfd support
@@ -5,10 +6,6 @@
* Copyright (c) 2005, 2007, 2008 Ian Molton
* Copyright (c) 2008 Dmitry Baryshkov
*
- * 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.
- *
* T7L66 features:
*
* Supported in this driver:
diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c
index cc9e563f23aa..67c9995bb1aa 100644
--- a/drivers/mfd/tc3589x.c
+++ b/drivers/mfd/tc3589x.c
@@ -1,7 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) ST-Ericsson SA 2010
*
- * License Terms: GNU General Public License, version 2
* Author: Hanumath Prasad <hanumath.prasad@stericsson.com> for ST-Ericsson
* Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
*/
diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c
index f417c6fecfe2..c66a701ab21c 100644
--- a/drivers/mfd/tc6387xb.c
+++ b/drivers/mfd/tc6387xb.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Toshiba TC6387XB support
* Copyright (c) 2005 Ian Molton
*
- * 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.
- *
* This file contains TC6387XB base support.
- *
*/
#include <linux/module.h>
diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c
index 6943048a64c2..05d5059ca203 100644
--- a/drivers/mfd/tc6393xb.c
+++ b/drivers/mfd/tc6393xb.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Toshiba TC6393XB SoC support
*
@@ -8,10 +9,6 @@
*
* Based on code written by Sharp/Lineo for 2.4 kernels
* Based on locomo.c
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/mfd/ti-lmu.c b/drivers/mfd/ti-lmu.c
index b06cb908d1aa..fd6e8c417baa 100644
--- a/drivers/mfd/ti-lmu.c
+++ b/drivers/mfd/ti-lmu.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TI LMU (Lighting Management Unit) Core Driver
*
* Copyright 2017 Texas Instruments
*
* Author: Milo Kim <milo.kim@ti.com>
- *
- * 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.
*/
#include <linux/delay.h>
@@ -111,17 +108,14 @@ static const struct mfd_cell lm3695_devices[] = {
},
};
-static const struct mfd_cell lm3697_devices[] = {
- {
- .name = "ti-lmu-backlight",
- .id = LM3697,
- .of_compatible = "ti,lm3697-backlight",
- },
- /* Monitoring driver for open/short circuit detection */
+static const struct mfd_cell lm36274_devices[] = {
+ LM363X_REGULATOR(LM36274_BOOST),
+ LM363X_REGULATOR(LM36274_LDO_POS),
+ LM363X_REGULATOR(LM36274_LDO_NEG),
{
- .name = "ti-lmu-fault-monitor",
- .id = LM3697,
- .of_compatible = "ti,lm3697-fault-monitor",
+ .name = "lm36274-leds",
+ .id = LM36274,
+ .of_compatible = "ti,lm36274-backlight",
},
};
@@ -137,7 +131,7 @@ TI_LMU_DATA(lm3631, LM3631_MAX_REG);
TI_LMU_DATA(lm3632, LM3632_MAX_REG);
TI_LMU_DATA(lm3633, LM3633_MAX_REG);
TI_LMU_DATA(lm3695, LM3695_MAX_REG);
-TI_LMU_DATA(lm3697, LM3697_MAX_REG);
+TI_LMU_DATA(lm36274, LM36274_MAX_REG);
static int ti_lmu_probe(struct i2c_client *cl, const struct i2c_device_id *id)
{
@@ -206,7 +200,7 @@ static const struct of_device_id ti_lmu_of_match[] = {
{ .compatible = "ti,lm3632", .data = &lm3632_data },
{ .compatible = "ti,lm3633", .data = &lm3633_data },
{ .compatible = "ti,lm3695", .data = &lm3695_data },
- { .compatible = "ti,lm3697", .data = &lm3697_data },
+ { .compatible = "ti,lm36274", .data = &lm36274_data },
{ }
};
MODULE_DEVICE_TABLE(of, ti_lmu_of_match);
@@ -216,7 +210,7 @@ static const struct i2c_device_id ti_lmu_ids[] = {
{ "lm3632", LM3632 },
{ "lm3633", LM3633 },
{ "lm3695", LM3695 },
- { "lm3697", LM3697 },
+ { "lm36274", LM36274 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ti_lmu_ids);
diff --git a/drivers/mfd/tmio_core.c b/drivers/mfd/tmio_core.c
index ebf54cc28f7a..7ee873551482 100644
--- a/drivers/mfd/tmio_core.c
+++ b/drivers/mfd/tmio_core.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright(c) 2009 Ian Molton <spyro@f2s.com>
- *
- * 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.
*/
#include <linux/export.h>
diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c
index 9c7925ca13cf..c8aadd39324e 100644
--- a/drivers/mfd/tps6586x.c
+++ b/drivers/mfd/tps6586x.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Core driver for TI TPS6586x PMIC family
*
@@ -9,10 +10,6 @@
* Mike Rapoport <mike@compulab.co.il>
* Copyright (C) 2006-2008 Marvell International Ltd.
* Eric Miao <eric.miao@marvell.com>
- *
- * 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.
*/
#include <linux/interrupt.h>
diff --git a/drivers/mfd/ucb1400_core.c b/drivers/mfd/ucb1400_core.c
index ebb20edf9c17..8c3832a58ef6 100644
--- a/drivers/mfd/ucb1400_core.c
+++ b/drivers/mfd/ucb1400_core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Core functions for:
* Philips UCB1400 multifunction chip
@@ -11,10 +12,6 @@
* If something doesn't work and it worked before spliting, e-mail me,
* dont bother Nicolas please ;-)
*
- * 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.
- *
* This code is heavily based on ucb1x00-*.c copyrighted by Russell King
* covering the UCB1100, UCB1200 and UCB1300.. Support for the UCB1400 has
* been made separate from ucb1x00-core/ucb1x00-ts on Russell's request.
diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c
index 1e0e20c0e082..6e1b38f9f26c 100644
--- a/drivers/mfd/ucb1x00-ts.c
+++ b/drivers/mfd/ucb1x00-ts.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Touchscreen driver for UCB1x00-based touchscreens
*
* Copyright (C) 2001 Russell King, All Rights Reserved.
* Copyright (C) 2005 Pavel Machek
*
- * 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.
- *
* 21-Jan-2002 <jco@ict.es> :
*
* Added support for synchronous A/D mode. This mode is useful to
diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c
index 853113d97c1e..6bba39657991 100644
--- a/drivers/mfd/wm5102-tables.c
+++ b/drivers/mfd/wm5102-tables.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* wm5102-tables.c -- WM5102 data tables
*
* Copyright 2012 Wolfson Microelectronics plc
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
- *
- * 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.
*/
#include <linux/device.h>
diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c
index 16c6e2accfaa..65b9b1d6daec 100644
--- a/drivers/mfd/wm5110-tables.c
+++ b/drivers/mfd/wm5110-tables.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* wm5110-tables.c -- WM5110 data tables
*
* Copyright 2012 Wolfson Microelectronics plc
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/mfd/wm8997-tables.c b/drivers/mfd/wm8997-tables.c
index ca41a561bfd3..3476787c485e 100644
--- a/drivers/mfd/wm8997-tables.c
+++ b/drivers/mfd/wm8997-tables.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* wm8997-tables.c -- WM8997 data tables
*
* Copyright 2012 Wolfson Microelectronics plc
*
* Author: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/mfd/wm8998-tables.c b/drivers/mfd/wm8998-tables.c
index a0de3002cdad..ebf0eadd2075 100644
--- a/drivers/mfd/wm8998-tables.c
+++ b/drivers/mfd/wm8998-tables.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* wm8998-tables.c -- data tables for wm8998-class codecs
*
* Copyright 2014 Wolfson Microelectronics plc
*
* Author: Richard Fitzgerald <rf@opensource.wolfsonmicro.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 85fc77148d19..6abfc8e92fcc 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -9,7 +9,6 @@ config SENSORS_LIS3LV02D
tristate
depends on INPUT
select INPUT_POLLDEV
- default n
config AD525X_DPOT
tristate "Analog Devices Digital Potentiometers"
@@ -62,7 +61,6 @@ config ATMEL_TCLIB
config DUMMY_IRQ
tristate "Dummy IRQ handler"
- default n
---help---
This module accepts a single 'irq' parameter, which it should register for.
The sole purpose of this module is to help with debugging of systems on
@@ -118,7 +116,6 @@ config PHANTOM
config INTEL_MID_PTI
tristate "Parallel Trace Interface for MIPI P1149.7 cJTAG standard"
depends on PCI && TTY && (X86_INTEL_MID || COMPILE_TEST)
- default n
help
The PTI (Parallel Trace Interface) driver directs
trace data routed from various parts in the system out
@@ -194,7 +191,6 @@ config ATMEL_SSC
config ENCLOSURE_SERVICES
tristate "Enclosure Services"
- default n
help
Provides support for intelligent enclosures (bays which
contain storage devices). You also need either a host
@@ -218,7 +214,6 @@ config SGI_XP
config CS5535_MFGPT
tristate "CS5535/CS5536 Geode Multi-Function General Purpose Timer (MFGPT) support"
depends on MFD_CS5535
- default n
help
This driver provides access to MFGPT functionality for other
drivers that need timers. MFGPTs are available in the CS5535 and
@@ -251,7 +246,6 @@ config CS5535_CLOCK_EVENT_SRC
config HP_ILO
tristate "Channel interface driver for the HP iLO processor"
depends on PCI
- default n
help
The channel interface driver allows applications to communicate
with iLO management processors present on HP ProLiant servers.
@@ -286,7 +280,6 @@ config QCOM_FASTRPC
config SGI_GRU
tristate "SGI GRU driver"
depends on X86_UV && SMP
- default n
select MMU_NOTIFIER
---help---
The GRU is a hardware resource located in the system chipset. The GRU
@@ -301,7 +294,6 @@ config SGI_GRU
config SGI_GRU_DEBUG
bool "SGI GRU driver debug"
depends on SGI_GRU
- default n
---help---
This option enables additional debugging code for the SGI GRU driver.
If you are unsure, say N.
@@ -359,7 +351,6 @@ config SENSORS_BH1770
config SENSORS_APDS990X
tristate "APDS990X combined als and proximity sensors"
depends on I2C
- default n
---help---
Say Y here if you want to build a driver for Avago APDS990x
combined ambient light and proximity sensor chip.
@@ -387,7 +378,6 @@ config DS1682
config SPEAR13XX_PCIE_GADGET
bool "PCIe gadget support for SPEAr13XX platform"
depends on ARCH_SPEAR13XX && BROKEN
- default n
help
This option enables gadget support for PCIe controller. If
board file defines any controller as PCIe endpoint then a sysfs
@@ -397,6 +387,7 @@ config SPEAR13XX_PCIE_GADGET
config VMWARE_BALLOON
tristate "VMware Balloon Driver"
depends on VMWARE_VMCI && X86 && HYPERVISOR_GUEST
+ select MEMORY_BALLOON
help
This is VMware physical memory management driver which acts
like a "balloon" that can be inflated to reclaim physical pages
@@ -431,15 +422,6 @@ config PCH_PHUB
To compile this driver as a module, choose M here: the module will
be called pch_phub.
-config USB_SWITCH_FSA9480
- tristate "FSA9480 USB Switch"
- depends on I2C
- help
- The FSA9480 is a USB port accessory detector and switch.
- The FSA9480 is fully controlled using I2C and enables USB data,
- stereo and mono audio, video, microphone and UART data to use
- a common connector port.
-
config LATTICE_ECP3_CONFIG
tristate "Lattice ECP3 FPGA bitstream configuration via SPI"
depends on SPI && SYSFS
@@ -481,6 +463,18 @@ config PCI_ENDPOINT_TEST
Enable this configuration option to enable the host side test driver
for PCI Endpoint.
+config XILINX_SDFEC
+ tristate "Xilinx SDFEC 16"
+ help
+ This option enables support for the Xilinx SDFEC (Soft Decision
+ Forward Error Correction) driver. This enables a char driver
+ for the SDFEC.
+
+ You may select this driver if your design instantiates the
+ SDFEC(16nm) hardened block. To compile this as a module choose M.
+
+ If unsure, say N.
+
config MISC_RTSX
tristate
default MISC_RTSX_PCI || MISC_RTSX_USB
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index b9affcdaa3d6..abd8ae249746 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -42,7 +42,6 @@ obj-$(CONFIG_VMWARE_BALLOON) += vmw_balloon.o
obj-$(CONFIG_PCH_PHUB) += pch_phub.o
obj-y += ti-st/
obj-y += lis3lv02d/
-obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/
obj-$(CONFIG_INTEL_MEI) += mei/
obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/
@@ -59,3 +58,4 @@ obj-$(CONFIG_OCXL) += ocxl/
obj-y += cardreader/
obj-$(CONFIG_PVPANIC) += pvpanic.o
obj-$(CONFIG_HABANA_AI) += habanalabs/
+obj-$(CONFIG_XILINX_SDFEC) += xilinx_sdfec.o
diff --git a/drivers/misc/altera-stapl/Kconfig b/drivers/misc/altera-stapl/Kconfig
index b34863544365..6c4c6575ec31 100644
--- a/drivers/misc/altera-stapl/Kconfig
+++ b/drivers/misc/altera-stapl/Kconfig
@@ -5,6 +5,5 @@ comment "Altera FPGA firmware download module (requires I2C)"
config ALTERA_STAPL
tristate "Altera FPGA firmware download module"
depends on I2C
- default n
help
An Altera FPGA module. Say Y when you want to support this tool.
diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c
index d8e3cc2dc747..ab4144ea1f11 100644
--- a/drivers/misc/atmel-ssc.c
+++ b/drivers/misc/atmel-ssc.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Atmel SSC driver
*
* Copyright (C) 2007 Atmel Corporation
- *
- * 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.
*/
#include <linux/platform_device.h>
diff --git a/drivers/misc/c2port/Kconfig b/drivers/misc/c2port/Kconfig
index 192e25094bd4..e20516ffd91e 100644
--- a/drivers/misc/c2port/Kconfig
+++ b/drivers/misc/c2port/Kconfig
@@ -5,7 +5,6 @@
menuconfig C2PORT
tristate "Silicon Labs C2 port support"
- default n
help
This option enables support for Silicon Labs C2 port used to
program Silicon micro controller chips (and other 8051 compatible).
@@ -24,7 +23,6 @@ if C2PORT
config C2PORT_DURAMAR_2150
tristate "C2 port support for Eurotech's Duramar 2150"
depends on X86
- default n
help
This option enables C2 support for the Eurotech's Duramar 2150
on board micro controller.
diff --git a/drivers/misc/c2port/c2port-duramar2150.c b/drivers/misc/c2port/c2port-duramar2150.c
index 3dc61ea7dc64..7e370949e00e 100644
--- a/drivers/misc/c2port/c2port-duramar2150.c
+++ b/drivers/misc/c2port/c2port-duramar2150.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Silicon Labs C2 port Linux support for Eurotech Duramar 2150
*
* Copyright (c) 2008 Rodolfo Giometti <giometti@linux.it>
* Copyright (c) 2008 Eurotech S.p.A. <info@eurotech.it>
- *
- * 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
*/
#include <linux/errno.h>
diff --git a/drivers/misc/c2port/core.c b/drivers/misc/c2port/core.c
index 1c5b7aec13d4..33bba1802289 100644
--- a/drivers/misc/c2port/core.c
+++ b/drivers/misc/c2port/core.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Silicon Labs C2 port core Linux support
*
* Copyright (c) 2007 Rodolfo Giometti <giometti@linux.it>
* Copyright (c) 2007 Eurotech S.p.A. <info@eurotech.it>
- *
- * 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
*/
#include <linux/module.h>
diff --git a/drivers/misc/cardreader/rtsx_usb.c b/drivers/misc/cardreader/rtsx_usb.c
index f7a66f614085..a328cab11014 100644
--- a/drivers/misc/cardreader/rtsx_usb.c
+++ b/drivers/misc/cardreader/rtsx_usb.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* Driver for Realtek USB card reader
*
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
* Author:
* Roger Tseng <rogerable@realtek.com>
*/
diff --git a/drivers/misc/cb710/Kconfig b/drivers/misc/cb710/Kconfig
index 3c7356d55423..a696d7509024 100644
--- a/drivers/misc/cb710/Kconfig
+++ b/drivers/misc/cb710/Kconfig
@@ -15,7 +15,6 @@ config CB710_CORE
config CB710_DEBUG
bool "Enable driver debugging"
depends on CB710_CORE != n
- default n
help
This is an option for use by developers; most people should
say N here. This adds a lot of debugging output to dmesg.
diff --git a/drivers/misc/cb710/core.c b/drivers/misc/cb710/core.c
index 2c43fd09d602..b290bc2ee240 100644
--- a/drivers/misc/cb710/core.c
+++ b/drivers/misc/cb710/core.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* cb710/core.c
*
* Copyright by Michał Mirosław, 2008-2009
- *
- * 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.
*/
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/misc/cb710/debug.c b/drivers/misc/cb710/debug.c
index fcb3b8e30c52..20d672edf7cd 100644
--- a/drivers/misc/cb710/debug.c
+++ b/drivers/misc/cb710/debug.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* cb710/debug.c
*
* Copyright by Michał Mirosław, 2008-2009
- *
- * 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.
*/
#include <linux/cb710.h>
#include <linux/kernel.h>
diff --git a/drivers/misc/cb710/sgbuf2.c b/drivers/misc/cb710/sgbuf2.c
index 2a40d0efdff5..dfd2969e3628 100644
--- a/drivers/misc/cb710/sgbuf2.c
+++ b/drivers/misc/cb710/sgbuf2.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* cb710/sgbuf2.c
*
* Copyright by Michał Mirosław, 2008-2009
- *
- * 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.
*/
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/misc/cxl/Kconfig b/drivers/misc/cxl/Kconfig
index f1d9a843e361..39eec9031487 100644
--- a/drivers/misc/cxl/Kconfig
+++ b/drivers/misc/cxl/Kconfig
@@ -5,16 +5,13 @@
config CXL_BASE
bool
- default n
select PPC_COPRO_BASE
config CXL_AFU_DRIVER_OPS
bool
- default n
config CXL_LIB
bool
- default n
config CXL
tristate "Support for IBM Coherent Accelerators (CXL)"
diff --git a/drivers/misc/cxl/api.c b/drivers/misc/cxl/api.c
index a450694d5a62..b493de962153 100644
--- a/drivers/misc/cxl/api.c
+++ b/drivers/misc/cxl/api.c
@@ -9,6 +9,7 @@
#include <misc/cxl.h>
#include <linux/module.h>
#include <linux/mount.h>
+#include <linux/pseudo_fs.h>
#include <linux/sched/mm.h>
#include <linux/mmu_context.h>
@@ -33,21 +34,15 @@
static int cxl_fs_cnt;
static struct vfsmount *cxl_vfs_mount;
-static const struct dentry_operations cxl_fs_dops = {
- .d_dname = simple_dname,
-};
-
-static struct dentry *cxl_fs_mount(struct file_system_type *fs_type, int flags,
- const char *dev_name, void *data)
+static int cxl_fs_init_fs_context(struct fs_context *fc)
{
- return mount_pseudo(fs_type, "cxl:", NULL, &cxl_fs_dops,
- CXL_PSEUDO_FS_MAGIC);
+ return init_pseudo(fc, CXL_PSEUDO_FS_MAGIC) ? 0 : -ENOMEM;
}
static struct file_system_type cxl_fs_type = {
.name = "cxl",
.owner = THIS_MODULE,
- .mount = cxl_fs_mount,
+ .init_fs_context = cxl_fs_init_fs_context,
.kill_sb = kill_anon_super,
};
diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h
index a73c9e669d78..5dc0f6093f9d 100644
--- a/drivers/misc/cxl/cxl.h
+++ b/drivers/misc/cxl/cxl.h
@@ -908,11 +908,11 @@ void cxl_update_dedicated_ivtes_psl8(struct cxl_context *ctx);
#ifdef CONFIG_DEBUG_FS
-int cxl_debugfs_init(void);
+void cxl_debugfs_init(void);
void cxl_debugfs_exit(void);
-int cxl_debugfs_adapter_add(struct cxl *adapter);
+void cxl_debugfs_adapter_add(struct cxl *adapter);
void cxl_debugfs_adapter_remove(struct cxl *adapter);
-int cxl_debugfs_afu_add(struct cxl_afu *afu);
+void cxl_debugfs_afu_add(struct cxl_afu *afu);
void cxl_debugfs_afu_remove(struct cxl_afu *afu);
void cxl_debugfs_add_adapter_regs_psl9(struct cxl *adapter, struct dentry *dir);
void cxl_debugfs_add_adapter_regs_psl8(struct cxl *adapter, struct dentry *dir);
@@ -921,27 +921,24 @@ void cxl_debugfs_add_afu_regs_psl8(struct cxl_afu *afu, struct dentry *dir);
#else /* CONFIG_DEBUG_FS */
-static inline int __init cxl_debugfs_init(void)
+static inline void __init cxl_debugfs_init(void)
{
- return 0;
}
static inline void cxl_debugfs_exit(void)
{
}
-static inline int cxl_debugfs_adapter_add(struct cxl *adapter)
+static inline void cxl_debugfs_adapter_add(struct cxl *adapter)
{
- return 0;
}
static inline void cxl_debugfs_adapter_remove(struct cxl *adapter)
{
}
-static inline int cxl_debugfs_afu_add(struct cxl_afu *afu)
+static inline void cxl_debugfs_afu_add(struct cxl_afu *afu)
{
- return 0;
}
static inline void cxl_debugfs_afu_remove(struct cxl_afu *afu)
diff --git a/drivers/misc/cxl/debugfs.c b/drivers/misc/cxl/debugfs.c
index 1fda22c24c93..7b987bf498b5 100644
--- a/drivers/misc/cxl/debugfs.c
+++ b/drivers/misc/cxl/debugfs.c
@@ -26,11 +26,11 @@ static int debugfs_io_u64_set(void *data, u64 val)
DEFINE_DEBUGFS_ATTRIBUTE(fops_io_x64, debugfs_io_u64_get, debugfs_io_u64_set,
"0x%016llx\n");
-static struct dentry *debugfs_create_io_x64(const char *name, umode_t mode,
- struct dentry *parent, u64 __iomem *value)
+static void debugfs_create_io_x64(const char *name, umode_t mode,
+ struct dentry *parent, u64 __iomem *value)
{
- return debugfs_create_file_unsafe(name, mode, parent,
- (void __force *)value, &fops_io_x64);
+ debugfs_create_file_unsafe(name, mode, parent, (void __force *)value,
+ &fops_io_x64);
}
void cxl_debugfs_add_adapter_regs_psl9(struct cxl *adapter, struct dentry *dir)
@@ -54,25 +54,22 @@ void cxl_debugfs_add_adapter_regs_psl8(struct cxl *adapter, struct dentry *dir)
debugfs_create_io_x64("trace", S_IRUSR | S_IWUSR, dir, _cxl_p1_addr(adapter, CXL_PSL_TRACE));
}
-int cxl_debugfs_adapter_add(struct cxl *adapter)
+void cxl_debugfs_adapter_add(struct cxl *adapter)
{
struct dentry *dir;
char buf[32];
if (!cxl_debugfs)
- return -ENODEV;
+ return;
snprintf(buf, 32, "card%i", adapter->adapter_num);
dir = debugfs_create_dir(buf, cxl_debugfs);
- if (IS_ERR(dir))
- return PTR_ERR(dir);
adapter->debugfs = dir;
debugfs_create_io_x64("err_ivte", S_IRUSR, dir, _cxl_p1_addr(adapter, CXL_PSL_ErrIVTE));
if (adapter->native->sl_ops->debugfs_add_adapter_regs)
adapter->native->sl_ops->debugfs_add_adapter_regs(adapter, dir);
- return 0;
}
void cxl_debugfs_adapter_remove(struct cxl *adapter)
@@ -96,18 +93,16 @@ void cxl_debugfs_add_afu_regs_psl8(struct cxl_afu *afu, struct dentry *dir)
debugfs_create_io_x64("trace", S_IRUSR | S_IWUSR, dir, _cxl_p1n_addr(afu, CXL_PSL_SLICE_TRACE));
}
-int cxl_debugfs_afu_add(struct cxl_afu *afu)
+void cxl_debugfs_afu_add(struct cxl_afu *afu)
{
struct dentry *dir;
char buf[32];
if (!afu->adapter->debugfs)
- return -ENODEV;
+ return;
snprintf(buf, 32, "psl%i.%i", afu->adapter->adapter_num, afu->slice);
dir = debugfs_create_dir(buf, afu->adapter->debugfs);
- if (IS_ERR(dir))
- return PTR_ERR(dir);
afu->debugfs = dir;
debugfs_create_io_x64("sr", S_IRUSR, dir, _cxl_p1n_addr(afu, CXL_PSL_SR_An));
@@ -118,8 +113,6 @@ int cxl_debugfs_afu_add(struct cxl_afu *afu)
if (afu->adapter->native->sl_ops->debugfs_add_afu_regs)
afu->adapter->native->sl_ops->debugfs_add_afu_regs(afu, dir);
-
- return 0;
}
void cxl_debugfs_afu_remove(struct cxl_afu *afu)
@@ -127,19 +120,12 @@ void cxl_debugfs_afu_remove(struct cxl_afu *afu)
debugfs_remove_recursive(afu->debugfs);
}
-int __init cxl_debugfs_init(void)
+void __init cxl_debugfs_init(void)
{
- struct dentry *ent;
-
if (!cpu_has_feature(CPU_FTR_HVMODE))
- return 0;
-
- ent = debugfs_create_dir("cxl", NULL);
- if (IS_ERR(ent))
- return PTR_ERR(ent);
- cxl_debugfs = ent;
+ return;
- return 0;
+ cxl_debugfs = debugfs_create_dir("cxl", NULL);
}
void cxl_debugfs_exit(void)
diff --git a/drivers/misc/ds1682.c b/drivers/misc/ds1682.c
index 98a921ea9ee8..42f316c2d719 100644
--- a/drivers/misc/ds1682.c
+++ b/drivers/misc/ds1682.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Dallas Semiconductor DS1682 Elapsed Time Recorder device driver
*
* Written by: Grant Likely <grant.likely@secretlab.ca>
*
* Copyright (C) 2007 Secret Lab Technologies Ltd.
- *
- * 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.
*/
/*
diff --git a/drivers/misc/dummy-irq.c b/drivers/misc/dummy-irq.c
index 76a1015d5783..fe3bfcb31a4c 100644
--- a/drivers/misc/dummy-irq.c
+++ b/drivers/misc/dummy-irq.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Dummy IRQ handler driver.
*
@@ -10,11 +11,6 @@
* Copyright (C) 2013 Jiri Kosina
*/
-/*
- * 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.
- */
#include <linux/module.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
diff --git a/drivers/misc/echo/Kconfig b/drivers/misc/echo/Kconfig
index 39656413e70d..be70b263e271 100644
--- a/drivers/misc/echo/Kconfig
+++ b/drivers/misc/echo/Kconfig
@@ -1,7 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
config ECHO
tristate "Line Echo Canceller support"
- default n
---help---
This driver provides line echo cancelling support for mISDN and
Zaptel drivers.
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 63aa541c9608..35bf2477693d 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -507,38 +507,24 @@ static const struct at24_chip_data *at24_get_chip_data(struct device *dev)
return cdata;
}
-static void at24_remove_dummy_clients(struct at24_data *at24)
-{
- int i;
-
- for (i = 1; i < at24->num_addresses; i++)
- i2c_unregister_device(at24->client[i].client);
-}
-
static int at24_make_dummy_client(struct at24_data *at24, unsigned int index,
struct regmap_config *regmap_config)
{
struct i2c_client *base_client, *dummy_client;
- unsigned short int addr;
struct regmap *regmap;
struct device *dev;
base_client = at24->client[0].client;
dev = &base_client->dev;
- addr = base_client->addr + index;
- dummy_client = i2c_new_dummy(base_client->adapter,
- base_client->addr + index);
- if (!dummy_client) {
- dev_err(dev, "address 0x%02x unavailable\n", addr);
- return -EADDRINUSE;
- }
+ dummy_client = devm_i2c_new_dummy_device(dev, base_client->adapter,
+ base_client->addr + index);
+ if (IS_ERR(dummy_client))
+ return PTR_ERR(dummy_client);
regmap = devm_regmap_init_i2c(dummy_client, regmap_config);
- if (IS_ERR(regmap)) {
- i2c_unregister_device(dummy_client);
+ if (IS_ERR(regmap))
return PTR_ERR(regmap);
- }
at24->client[index].client = dummy_client;
at24->client[index].regmap = regmap;
@@ -580,7 +566,6 @@ static int at24_probe(struct i2c_client *client)
unsigned int i, num_addresses;
struct at24_data *at24;
struct regmap *regmap;
- size_t at24_size;
bool writable;
u8 test_byte;
int err;
@@ -597,8 +582,8 @@ static int at24_probe(struct i2c_client *client)
if (err)
/*
* This is slow, but we can't know all eeproms, so we better
- * play safe. Specifying custom eeprom-types via platform_data
- * is recommended anyhow.
+ * play safe. Specifying custom eeprom-types via device tree
+ * or properties is recommended anyhow.
*/
page_size = 1;
@@ -664,8 +649,8 @@ static int at24_probe(struct i2c_client *client)
if (IS_ERR(regmap))
return PTR_ERR(regmap);
- at24_size = sizeof(*at24) + num_addresses * sizeof(struct at24_client);
- at24 = devm_kzalloc(dev, at24_size, GFP_KERNEL);
+ at24 = devm_kzalloc(dev, struct_size(at24, client, num_addresses),
+ GFP_KERNEL);
if (!at24)
return -ENOMEM;
@@ -693,27 +678,8 @@ static int at24_probe(struct i2c_client *client)
/* use dummy devices for multiple-address chips */
for (i = 1; i < num_addresses; i++) {
err = at24_make_dummy_client(at24, i, &regmap_config);
- if (err) {
- at24_remove_dummy_clients(at24);
+ if (err)
return err;
- }
- }
-
- i2c_set_clientdata(client, at24);
-
- /* enable runtime pm */
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
-
- /*
- * Perform a one-byte test read to verify that the
- * chip is functional.
- */
- err = at24_read(at24, 0, &test_byte, 1);
- pm_runtime_idle(dev);
- if (err) {
- err = -ENODEV;
- goto err_clients;
}
nvmem_config.name = dev_name(dev);
@@ -731,9 +697,24 @@ static int at24_probe(struct i2c_client *client)
nvmem_config.size = byte_len;
at24->nvmem = devm_nvmem_register(dev, &nvmem_config);
- if (IS_ERR(at24->nvmem)) {
- err = PTR_ERR(at24->nvmem);
- goto err_clients;
+ if (IS_ERR(at24->nvmem))
+ return PTR_ERR(at24->nvmem);
+
+ i2c_set_clientdata(client, at24);
+
+ /* enable runtime pm */
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ /*
+ * Perform a one-byte test read to verify that the
+ * chip is functional.
+ */
+ err = at24_read(at24, 0, &test_byte, 1);
+ pm_runtime_idle(dev);
+ if (err) {
+ pm_runtime_disable(dev);
+ return -ENODEV;
}
dev_info(dev, "%u byte %s EEPROM, %s, %u bytes/write\n",
@@ -741,21 +722,10 @@ static int at24_probe(struct i2c_client *client)
writable ? "writable" : "read-only", at24->write_max);
return 0;
-
-err_clients:
- at24_remove_dummy_clients(at24);
- pm_runtime_disable(dev);
-
- return err;
}
static int at24_remove(struct i2c_client *client)
{
- struct at24_data *at24;
-
- at24 = i2c_get_clientdata(client);
-
- at24_remove_dummy_clients(at24);
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
diff --git a/drivers/misc/eeprom/digsy_mtc_eeprom.c b/drivers/misc/eeprom/digsy_mtc_eeprom.c
index fbde2516c04f..f1f766b70965 100644
--- a/drivers/misc/eeprom/digsy_mtc_eeprom.c
+++ b/drivers/misc/eeprom/digsy_mtc_eeprom.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* EEPROMs access control driver for display configuration EEPROMs
* on DigsyMTC board.
*
* (C) 2011 DENX Software Engineering, Anatolij Gustschin <agust@denx.de>
*
- * 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.
- *
* FIXME: this driver is used on a device-tree probed platform: it
* should be defined as a bit-banged SPI device and probed from the device
* tree and not like this with static grabbing of a few numbered GPIO
diff --git a/drivers/misc/eeprom/ee1004.c b/drivers/misc/eeprom/ee1004.c
index be3263df278a..6f00c33cfe22 100644
--- a/drivers/misc/eeprom/ee1004.c
+++ b/drivers/misc/eeprom/ee1004.c
@@ -2,7 +2,7 @@
/*
* ee1004 - driver for DDR4 SPD EEPROMs
*
- * Copyright (C) 2017 Jean Delvare
+ * Copyright (C) 2017-2019 Jean Delvare
*
* Based on the at24 driver:
* Copyright (C) 2005-2007 David Brownell
@@ -53,6 +53,24 @@ MODULE_DEVICE_TABLE(i2c, ee1004_ids);
/*-------------------------------------------------------------------------*/
+static int ee1004_get_current_page(void)
+{
+ int err;
+
+ err = i2c_smbus_read_byte(ee1004_set_page[0]);
+ if (err == -ENXIO) {
+ /* Nack means page 1 is selected */
+ return 1;
+ }
+ if (err < 0) {
+ /* Anything else is a real error, bail out */
+ return err;
+ }
+
+ /* Ack means page 0 is selected, returned value meaningless */
+ return 0;
+}
+
static ssize_t ee1004_eeprom_read(struct i2c_client *client, char *buf,
unsigned int offset, size_t count)
{
@@ -102,6 +120,16 @@ static ssize_t ee1004_read(struct file *filp, struct kobject *kobj,
/* Data is ignored */
status = i2c_smbus_write_byte(ee1004_set_page[page],
0x00);
+ if (status == -ENXIO) {
+ /*
+ * Don't give up just yet. Some memory
+ * modules will select the page but not
+ * ack the command. Check which page is
+ * selected now.
+ */
+ if (ee1004_get_current_page() == page)
+ status = 0;
+ }
if (status < 0) {
dev_err(dev, "Failed to select page %d (%d)\n",
page, status);
@@ -186,17 +214,10 @@ static int ee1004_probe(struct i2c_client *client,
}
/* Remember current page to avoid unneeded page select */
- err = i2c_smbus_read_byte(ee1004_set_page[0]);
- if (err == -ENXIO) {
- /* Nack means page 1 is selected */
- ee1004_current_page = 1;
- } else if (err < 0) {
- /* Anything else is a real error, bail out */
+ err = ee1004_get_current_page();
+ if (err < 0)
goto err_clients;
- } else {
- /* Ack means page 0 is selected, returned value meaningless */
- ee1004_current_page = 0;
- }
+ ee1004_current_page = err;
dev_dbg(&client->dev, "Currently selected page: %d\n",
ee1004_current_page);
mutex_unlock(&ee1004_bus_lock);
diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c
index c6dd9ad9bf7b..94cfb675fe4e 100644
--- a/drivers/misc/eeprom/eeprom_93xx46.c
+++ b/drivers/misc/eeprom/eeprom_93xx46.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for 93xx46 EEPROMs
*
* (C) 2011 DENX Software Engineering, Anatolij Gustschin <agust@denx.de>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/misc/eeprom/idt_89hpesx.c b/drivers/misc/eeprom/idt_89hpesx.c
index 8a4659518c33..81c70e5bc168 100644
--- a/drivers/misc/eeprom/idt_89hpesx.c
+++ b/drivers/misc/eeprom/idt_89hpesx.c
@@ -115,7 +115,6 @@ static struct dentry *csr_dbgdir;
* @client: i2c client used to perform IO operations
*
* @ee_file: EEPROM read/write sysfs-file
- * @csr_file: CSR read/write debugfs-node
*/
struct idt_smb_seq;
struct idt_89hpesx_dev {
@@ -137,7 +136,6 @@ struct idt_89hpesx_dev {
struct bin_attribute *ee_file;
struct dentry *csr_dir;
- struct dentry *csr_file;
};
/*
@@ -1378,8 +1376,8 @@ static void idt_create_dbgfs_files(struct idt_89hpesx_dev *pdev)
pdev->csr_dir = debugfs_create_dir(fname, csr_dbgdir);
/* Create Debugfs file for CSR read/write operations */
- pdev->csr_file = debugfs_create_file(cli->name, 0600,
- pdev->csr_dir, pdev, &csr_dbgfs_ops);
+ debugfs_create_file(cli->name, 0600, pdev->csr_dir, pdev,
+ &csr_dbgfs_ops);
}
/*
diff --git a/drivers/misc/fsa9480.c b/drivers/misc/fsa9480.c
deleted file mode 100644
index 607b489a6501..000000000000
--- a/drivers/misc/fsa9480.c
+++ /dev/null
@@ -1,550 +0,0 @@
-/*
- * fsa9480.c - FSA9480 micro USB switch device driver
- *
- * Copyright (C) 2010 Samsung Electronics
- * Minkyu Kang <mk7.kang@samsung.com>
- * Wonguk Jeong <wonguk.jeong@samsung.com>
- *
- * 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/i2c.h>
-#include <linux/platform_data/fsa9480.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/workqueue.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/pm_runtime.h>
-
-/* FSA9480 I2C registers */
-#define FSA9480_REG_DEVID 0x01
-#define FSA9480_REG_CTRL 0x02
-#define FSA9480_REG_INT1 0x03
-#define FSA9480_REG_INT2 0x04
-#define FSA9480_REG_INT1_MASK 0x05
-#define FSA9480_REG_INT2_MASK 0x06
-#define FSA9480_REG_ADC 0x07
-#define FSA9480_REG_TIMING1 0x08
-#define FSA9480_REG_TIMING2 0x09
-#define FSA9480_REG_DEV_T1 0x0a
-#define FSA9480_REG_DEV_T2 0x0b
-#define FSA9480_REG_BTN1 0x0c
-#define FSA9480_REG_BTN2 0x0d
-#define FSA9480_REG_CK 0x0e
-#define FSA9480_REG_CK_INT1 0x0f
-#define FSA9480_REG_CK_INT2 0x10
-#define FSA9480_REG_CK_INTMASK1 0x11
-#define FSA9480_REG_CK_INTMASK2 0x12
-#define FSA9480_REG_MANSW1 0x13
-#define FSA9480_REG_MANSW2 0x14
-
-/* Control */
-#define CON_SWITCH_OPEN (1 << 4)
-#define CON_RAW_DATA (1 << 3)
-#define CON_MANUAL_SW (1 << 2)
-#define CON_WAIT (1 << 1)
-#define CON_INT_MASK (1 << 0)
-#define CON_MASK (CON_SWITCH_OPEN | CON_RAW_DATA | \
- CON_MANUAL_SW | CON_WAIT)
-
-/* Device Type 1 */
-#define DEV_USB_OTG (1 << 7)
-#define DEV_DEDICATED_CHG (1 << 6)
-#define DEV_USB_CHG (1 << 5)
-#define DEV_CAR_KIT (1 << 4)
-#define DEV_UART (1 << 3)
-#define DEV_USB (1 << 2)
-#define DEV_AUDIO_2 (1 << 1)
-#define DEV_AUDIO_1 (1 << 0)
-
-#define DEV_T1_USB_MASK (DEV_USB_OTG | DEV_USB)
-#define DEV_T1_UART_MASK (DEV_UART)
-#define DEV_T1_CHARGER_MASK (DEV_DEDICATED_CHG | DEV_USB_CHG)
-
-/* Device Type 2 */
-#define DEV_AV (1 << 6)
-#define DEV_TTY (1 << 5)
-#define DEV_PPD (1 << 4)
-#define DEV_JIG_UART_OFF (1 << 3)
-#define DEV_JIG_UART_ON (1 << 2)
-#define DEV_JIG_USB_OFF (1 << 1)
-#define DEV_JIG_USB_ON (1 << 0)
-
-#define DEV_T2_USB_MASK (DEV_JIG_USB_OFF | DEV_JIG_USB_ON)
-#define DEV_T2_UART_MASK (DEV_JIG_UART_OFF | DEV_JIG_UART_ON)
-#define DEV_T2_JIG_MASK (DEV_JIG_USB_OFF | DEV_JIG_USB_ON | \
- DEV_JIG_UART_OFF | DEV_JIG_UART_ON)
-
-/*
- * Manual Switch
- * D- [7:5] / D+ [4:2]
- * 000: Open all / 001: USB / 010: AUDIO / 011: UART / 100: V_AUDIO
- */
-#define SW_VAUDIO ((4 << 5) | (4 << 2))
-#define SW_UART ((3 << 5) | (3 << 2))
-#define SW_AUDIO ((2 << 5) | (2 << 2))
-#define SW_DHOST ((1 << 5) | (1 << 2))
-#define SW_AUTO ((0 << 5) | (0 << 2))
-
-/* Interrupt 1 */
-#define INT_DETACH (1 << 1)
-#define INT_ATTACH (1 << 0)
-
-struct fsa9480_usbsw {
- struct i2c_client *client;
- struct fsa9480_platform_data *pdata;
- int dev1;
- int dev2;
- int mansw;
-};
-
-static struct fsa9480_usbsw *chip;
-
-static int fsa9480_write_reg(struct i2c_client *client,
- int reg, int value)
-{
- int ret;
-
- ret = i2c_smbus_write_byte_data(client, reg, value);
-
- if (ret < 0)
- dev_err(&client->dev, "%s: err %d\n", __func__, ret);
-
- return ret;
-}
-
-static int fsa9480_read_reg(struct i2c_client *client, int reg)
-{
- int ret;
-
- ret = i2c_smbus_read_byte_data(client, reg);
-
- if (ret < 0)
- dev_err(&client->dev, "%s: err %d\n", __func__, ret);
-
- return ret;
-}
-
-static int fsa9480_read_irq(struct i2c_client *client, int *value)
-{
- int ret;
-
- ret = i2c_smbus_read_i2c_block_data(client,
- FSA9480_REG_INT1, 2, (u8 *)value);
- *value &= 0xffff;
-
- if (ret < 0)
- dev_err(&client->dev, "%s: err %d\n", __func__, ret);
-
- return ret;
-}
-
-static void fsa9480_set_switch(const char *buf)
-{
- struct fsa9480_usbsw *usbsw = chip;
- struct i2c_client *client = usbsw->client;
- unsigned int value;
- unsigned int path = 0;
-
- value = fsa9480_read_reg(client, FSA9480_REG_CTRL);
-
- if (!strncmp(buf, "VAUDIO", 6)) {
- path = SW_VAUDIO;
- value &= ~CON_MANUAL_SW;
- } else if (!strncmp(buf, "UART", 4)) {
- path = SW_UART;
- value &= ~CON_MANUAL_SW;
- } else if (!strncmp(buf, "AUDIO", 5)) {
- path = SW_AUDIO;
- value &= ~CON_MANUAL_SW;
- } else if (!strncmp(buf, "DHOST", 5)) {
- path = SW_DHOST;
- value &= ~CON_MANUAL_SW;
- } else if (!strncmp(buf, "AUTO", 4)) {
- path = SW_AUTO;
- value |= CON_MANUAL_SW;
- } else {
- printk(KERN_ERR "Wrong command\n");
- return;
- }
-
- usbsw->mansw = path;
- fsa9480_write_reg(client, FSA9480_REG_MANSW1, path);
- fsa9480_write_reg(client, FSA9480_REG_CTRL, value);
-}
-
-static ssize_t fsa9480_get_switch(char *buf)
-{
- struct fsa9480_usbsw *usbsw = chip;
- struct i2c_client *client = usbsw->client;
- unsigned int value;
-
- value = fsa9480_read_reg(client, FSA9480_REG_MANSW1);
-
- if (value == SW_VAUDIO)
- return sprintf(buf, "VAUDIO\n");
- else if (value == SW_UART)
- return sprintf(buf, "UART\n");
- else if (value == SW_AUDIO)
- return sprintf(buf, "AUDIO\n");
- else if (value == SW_DHOST)
- return sprintf(buf, "DHOST\n");
- else if (value == SW_AUTO)
- return sprintf(buf, "AUTO\n");
- else
- return sprintf(buf, "%x", value);
-}
-
-static ssize_t fsa9480_show_device(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct fsa9480_usbsw *usbsw = dev_get_drvdata(dev);
- struct i2c_client *client = usbsw->client;
- int dev1, dev2;
-
- dev1 = fsa9480_read_reg(client, FSA9480_REG_DEV_T1);
- dev2 = fsa9480_read_reg(client, FSA9480_REG_DEV_T2);
-
- if (!dev1 && !dev2)
- return sprintf(buf, "NONE\n");
-
- /* USB */
- if (dev1 & DEV_T1_USB_MASK || dev2 & DEV_T2_USB_MASK)
- return sprintf(buf, "USB\n");
-
- /* UART */
- if (dev1 & DEV_T1_UART_MASK || dev2 & DEV_T2_UART_MASK)
- return sprintf(buf, "UART\n");
-
- /* CHARGER */
- if (dev1 & DEV_T1_CHARGER_MASK)
- return sprintf(buf, "CHARGER\n");
-
- /* JIG */
- if (dev2 & DEV_T2_JIG_MASK)
- return sprintf(buf, "JIG\n");
-
- return sprintf(buf, "UNKNOWN\n");
-}
-
-static ssize_t fsa9480_show_manualsw(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return fsa9480_get_switch(buf);
-
-}
-
-static ssize_t fsa9480_set_manualsw(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- fsa9480_set_switch(buf);
-
- return count;
-}
-
-static DEVICE_ATTR(device, S_IRUGO, fsa9480_show_device, NULL);
-static DEVICE_ATTR(switch, S_IRUGO | S_IWUSR,
- fsa9480_show_manualsw, fsa9480_set_manualsw);
-
-static struct attribute *fsa9480_attributes[] = {
- &dev_attr_device.attr,
- &dev_attr_switch.attr,
- NULL
-};
-
-static const struct attribute_group fsa9480_group = {
- .attrs = fsa9480_attributes,
-};
-
-static void fsa9480_detect_dev(struct fsa9480_usbsw *usbsw, int intr)
-{
- int val1, val2, ctrl;
- struct fsa9480_platform_data *pdata = usbsw->pdata;
- struct i2c_client *client = usbsw->client;
-
- val1 = fsa9480_read_reg(client, FSA9480_REG_DEV_T1);
- val2 = fsa9480_read_reg(client, FSA9480_REG_DEV_T2);
- ctrl = fsa9480_read_reg(client, FSA9480_REG_CTRL);
-
- dev_info(&client->dev, "intr: 0x%x, dev1: 0x%x, dev2: 0x%x\n",
- intr, val1, val2);
-
- if (!intr)
- goto out;
-
- if (intr & INT_ATTACH) { /* Attached */
- /* USB */
- if (val1 & DEV_T1_USB_MASK || val2 & DEV_T2_USB_MASK) {
- if (pdata->usb_cb)
- pdata->usb_cb(FSA9480_ATTACHED);
-
- if (usbsw->mansw) {
- fsa9480_write_reg(client,
- FSA9480_REG_MANSW1, usbsw->mansw);
- }
- }
-
- /* UART */
- if (val1 & DEV_T1_UART_MASK || val2 & DEV_T2_UART_MASK) {
- if (pdata->uart_cb)
- pdata->uart_cb(FSA9480_ATTACHED);
-
- if (!(ctrl & CON_MANUAL_SW)) {
- fsa9480_write_reg(client,
- FSA9480_REG_MANSW1, SW_UART);
- }
- }
-
- /* CHARGER */
- if (val1 & DEV_T1_CHARGER_MASK) {
- if (pdata->charger_cb)
- pdata->charger_cb(FSA9480_ATTACHED);
- }
-
- /* JIG */
- if (val2 & DEV_T2_JIG_MASK) {
- if (pdata->jig_cb)
- pdata->jig_cb(FSA9480_ATTACHED);
- }
- } else if (intr & INT_DETACH) { /* Detached */
- /* USB */
- if (usbsw->dev1 & DEV_T1_USB_MASK ||
- usbsw->dev2 & DEV_T2_USB_MASK) {
- if (pdata->usb_cb)
- pdata->usb_cb(FSA9480_DETACHED);
- }
-
- /* UART */
- if (usbsw->dev1 & DEV_T1_UART_MASK ||
- usbsw->dev2 & DEV_T2_UART_MASK) {
- if (pdata->uart_cb)
- pdata->uart_cb(FSA9480_DETACHED);
- }
-
- /* CHARGER */
- if (usbsw->dev1 & DEV_T1_CHARGER_MASK) {
- if (pdata->charger_cb)
- pdata->charger_cb(FSA9480_DETACHED);
- }
-
- /* JIG */
- if (usbsw->dev2 & DEV_T2_JIG_MASK) {
- if (pdata->jig_cb)
- pdata->jig_cb(FSA9480_DETACHED);
- }
- }
-
- usbsw->dev1 = val1;
- usbsw->dev2 = val2;
-
-out:
- ctrl &= ~CON_INT_MASK;
- fsa9480_write_reg(client, FSA9480_REG_CTRL, ctrl);
-}
-
-static irqreturn_t fsa9480_irq_handler(int irq, void *data)
-{
- struct fsa9480_usbsw *usbsw = data;
- struct i2c_client *client = usbsw->client;
- int intr;
-
- /* clear interrupt */
- fsa9480_read_irq(client, &intr);
-
- /* device detection */
- fsa9480_detect_dev(usbsw, intr);
-
- return IRQ_HANDLED;
-}
-
-static int fsa9480_irq_init(struct fsa9480_usbsw *usbsw)
-{
- struct fsa9480_platform_data *pdata = usbsw->pdata;
- struct i2c_client *client = usbsw->client;
- int ret;
- int intr;
- unsigned int ctrl = CON_MASK;
-
- /* clear interrupt */
- fsa9480_read_irq(client, &intr);
-
- /* unmask interrupt (attach/detach only) */
- fsa9480_write_reg(client, FSA9480_REG_INT1_MASK, 0xfc);
- fsa9480_write_reg(client, FSA9480_REG_INT2_MASK, 0x1f);
-
- usbsw->mansw = fsa9480_read_reg(client, FSA9480_REG_MANSW1);
-
- if (usbsw->mansw)
- ctrl &= ~CON_MANUAL_SW; /* Manual Switching Mode */
-
- fsa9480_write_reg(client, FSA9480_REG_CTRL, ctrl);
-
- if (pdata && pdata->cfg_gpio)
- pdata->cfg_gpio();
-
- if (client->irq) {
- ret = request_threaded_irq(client->irq, NULL,
- fsa9480_irq_handler,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
- "fsa9480 micro USB", usbsw);
- if (ret) {
- dev_err(&client->dev, "failed to request IRQ\n");
- return ret;
- }
-
- if (pdata)
- device_init_wakeup(&client->dev, pdata->wakeup);
- }
-
- return 0;
-}
-
-static int fsa9480_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- struct fsa9480_usbsw *usbsw;
- int ret = 0;
-
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- return -EIO;
-
- usbsw = kzalloc(sizeof(struct fsa9480_usbsw), GFP_KERNEL);
- if (!usbsw) {
- dev_err(&client->dev, "failed to allocate driver data\n");
- return -ENOMEM;
- }
-
- usbsw->client = client;
- usbsw->pdata = client->dev.platform_data;
-
- chip = usbsw;
-
- i2c_set_clientdata(client, usbsw);
-
- ret = fsa9480_irq_init(usbsw);
- if (ret)
- goto fail1;
-
- ret = sysfs_create_group(&client->dev.kobj, &fsa9480_group);
- if (ret) {
- dev_err(&client->dev,
- "failed to create fsa9480 attribute group\n");
- goto fail2;
- }
-
- /* ADC Detect Time: 500ms */
- fsa9480_write_reg(client, FSA9480_REG_TIMING1, 0x6);
-
- if (chip->pdata->reset_cb)
- chip->pdata->reset_cb();
-
- /* device detection */
- fsa9480_detect_dev(usbsw, INT_ATTACH);
-
- pm_runtime_set_active(&client->dev);
-
- return 0;
-
-fail2:
- if (client->irq)
- free_irq(client->irq, usbsw);
-fail1:
- kfree(usbsw);
- return ret;
-}
-
-static int fsa9480_remove(struct i2c_client *client)
-{
- struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client);
-
- if (client->irq)
- free_irq(client->irq, usbsw);
-
- sysfs_remove_group(&client->dev.kobj, &fsa9480_group);
- device_init_wakeup(&client->dev, 0);
- kfree(usbsw);
- return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-
-static int fsa9480_suspend(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client);
- struct fsa9480_platform_data *pdata = usbsw->pdata;
-
- if (device_may_wakeup(&client->dev) && client->irq)
- enable_irq_wake(client->irq);
-
- if (pdata->usb_power)
- pdata->usb_power(0);
-
- return 0;
-}
-
-static int fsa9480_resume(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client);
- int dev1, dev2;
-
- if (device_may_wakeup(&client->dev) && client->irq)
- disable_irq_wake(client->irq);
-
- /*
- * Clear Pending interrupt. Note that detect_dev does what
- * the interrupt handler does. So, we don't miss pending and
- * we reenable interrupt if there is one.
- */
- fsa9480_read_reg(client, FSA9480_REG_INT1);
- fsa9480_read_reg(client, FSA9480_REG_INT2);
-
- dev1 = fsa9480_read_reg(client, FSA9480_REG_DEV_T1);
- dev2 = fsa9480_read_reg(client, FSA9480_REG_DEV_T2);
-
- /* device detection */
- fsa9480_detect_dev(usbsw, (dev1 || dev2) ? INT_ATTACH : INT_DETACH);
-
- return 0;
-}
-
-static SIMPLE_DEV_PM_OPS(fsa9480_pm_ops, fsa9480_suspend, fsa9480_resume);
-#define FSA9480_PM_OPS (&fsa9480_pm_ops)
-
-#else
-
-#define FSA9480_PM_OPS NULL
-
-#endif /* CONFIG_PM_SLEEP */
-
-static const struct i2c_device_id fsa9480_id[] = {
- {"fsa9480", 0},
- {}
-};
-MODULE_DEVICE_TABLE(i2c, fsa9480_id);
-
-static struct i2c_driver fsa9480_i2c_driver = {
- .driver = {
- .name = "fsa9480",
- .pm = FSA9480_PM_OPS,
- },
- .probe = fsa9480_probe,
- .remove = fsa9480_remove,
- .id_table = fsa9480_id,
-};
-
-module_i2c_driver(fsa9480_i2c_driver);
-
-MODULE_AUTHOR("Minkyu Kang <mk7.kang@samsung.com>");
-MODULE_DESCRIPTION("FSA9480 USB Switch driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/misc/genwqe/Kconfig b/drivers/misc/genwqe/Kconfig
index a8a608713d26..97f64bcf9fe0 100644
--- a/drivers/misc/genwqe/Kconfig
+++ b/drivers/misc/genwqe/Kconfig
@@ -7,7 +7,6 @@ menuconfig GENWQE
tristate "GenWQE PCIe Accelerator"
depends on PCI && 64BIT
select CRC_ITU_T
- default n
help
Enables PCIe card driver for IBM GenWQE accelerators.
The user-space interface is described in
diff --git a/drivers/misc/genwqe/card_base.c b/drivers/misc/genwqe/card_base.c
index ab7f2cd21c93..1dc6c7c5cbce 100644
--- a/drivers/misc/genwqe/card_base.c
+++ b/drivers/misc/genwqe/card_base.c
@@ -1369,10 +1369,6 @@ static int __init genwqe_init_module(void)
class_genwqe->devnode = genwqe_devnode;
debugfs_genwqe = debugfs_create_dir(GENWQE_DEVNAME, NULL);
- if (!debugfs_genwqe) {
- rc = -ENOMEM;
- goto err_out;
- }
rc = pci_register_driver(&genwqe_driver);
if (rc != 0) {
@@ -1384,7 +1380,6 @@ static int __init genwqe_init_module(void)
err_out0:
debugfs_remove(debugfs_genwqe);
- err_out:
class_destroy(class_genwqe);
return rc;
}
diff --git a/drivers/misc/genwqe/card_base.h b/drivers/misc/genwqe/card_base.h
index 2f6dd2f37942..0e902977d35f 100644
--- a/drivers/misc/genwqe/card_base.h
+++ b/drivers/misc/genwqe/card_base.h
@@ -437,7 +437,7 @@ int genwqe_device_create(struct genwqe_dev *cd);
int genwqe_device_remove(struct genwqe_dev *cd);
/* debugfs */
-int genwqe_init_debugfs(struct genwqe_dev *cd);
+void genwqe_init_debugfs(struct genwqe_dev *cd);
void genqwe_exit_debugfs(struct genwqe_dev *cd);
int genwqe_read_softreset(struct genwqe_dev *cd);
diff --git a/drivers/misc/genwqe/card_debugfs.c b/drivers/misc/genwqe/card_debugfs.c
index 49c945d0c488..1b5b82e65268 100644
--- a/drivers/misc/genwqe/card_debugfs.c
+++ b/drivers/misc/genwqe/card_debugfs.c
@@ -316,11 +316,9 @@ static int info_show(struct seq_file *s, void *unused)
DEFINE_SHOW_ATTRIBUTE(info);
-int genwqe_init_debugfs(struct genwqe_dev *cd)
+void genwqe_init_debugfs(struct genwqe_dev *cd)
{
struct dentry *root;
- struct dentry *file;
- int ret;
char card_name[64];
char name[64];
unsigned int i;
@@ -328,153 +326,50 @@ int genwqe_init_debugfs(struct genwqe_dev *cd)
sprintf(card_name, "%s%d_card", GENWQE_DEVNAME, cd->card_idx);
root = debugfs_create_dir(card_name, cd->debugfs_genwqe);
- if (!root) {
- ret = -ENOMEM;
- goto err0;
- }
/* non privileged interfaces are done here */
- file = debugfs_create_file("ddcb_info", S_IRUGO, root, cd,
- &ddcb_info_fops);
- if (!file) {
- ret = -ENOMEM;
- goto err1;
- }
-
- file = debugfs_create_file("info", S_IRUGO, root, cd,
- &info_fops);
- if (!file) {
- ret = -ENOMEM;
- goto err1;
- }
-
- file = debugfs_create_x64("err_inject", 0666, root, &cd->err_inject);
- if (!file) {
- ret = -ENOMEM;
- goto err1;
- }
-
- file = debugfs_create_u32("ddcb_software_timeout", 0666, root,
- &cd->ddcb_software_timeout);
- if (!file) {
- ret = -ENOMEM;
- goto err1;
- }
-
- file = debugfs_create_u32("kill_timeout", 0666, root,
- &cd->kill_timeout);
- if (!file) {
- ret = -ENOMEM;
- goto err1;
- }
+ debugfs_create_file("ddcb_info", S_IRUGO, root, cd, &ddcb_info_fops);
+ debugfs_create_file("info", S_IRUGO, root, cd, &info_fops);
+ debugfs_create_x64("err_inject", 0666, root, &cd->err_inject);
+ debugfs_create_u32("ddcb_software_timeout", 0666, root,
+ &cd->ddcb_software_timeout);
+ debugfs_create_u32("kill_timeout", 0666, root, &cd->kill_timeout);
/* privileged interfaces follow here */
if (!genwqe_is_privileged(cd)) {
cd->debugfs_root = root;
- return 0;
+ return;
}
- file = debugfs_create_file("curr_regs", S_IRUGO, root, cd,
- &curr_regs_fops);
- if (!file) {
- ret = -ENOMEM;
- goto err1;
- }
-
- file = debugfs_create_file("curr_dbg_uid0", S_IRUGO, root, cd,
- &curr_dbg_uid0_fops);
- if (!file) {
- ret = -ENOMEM;
- goto err1;
- }
-
- file = debugfs_create_file("curr_dbg_uid1", S_IRUGO, root, cd,
- &curr_dbg_uid1_fops);
- if (!file) {
- ret = -ENOMEM;
- goto err1;
- }
-
- file = debugfs_create_file("curr_dbg_uid2", S_IRUGO, root, cd,
- &curr_dbg_uid2_fops);
- if (!file) {
- ret = -ENOMEM;
- goto err1;
- }
-
- file = debugfs_create_file("prev_regs", S_IRUGO, root, cd,
- &prev_regs_fops);
- if (!file) {
- ret = -ENOMEM;
- goto err1;
- }
-
- file = debugfs_create_file("prev_dbg_uid0", S_IRUGO, root, cd,
- &prev_dbg_uid0_fops);
- if (!file) {
- ret = -ENOMEM;
- goto err1;
- }
-
- file = debugfs_create_file("prev_dbg_uid1", S_IRUGO, root, cd,
- &prev_dbg_uid1_fops);
- if (!file) {
- ret = -ENOMEM;
- goto err1;
- }
-
- file = debugfs_create_file("prev_dbg_uid2", S_IRUGO, root, cd,
- &prev_dbg_uid2_fops);
- if (!file) {
- ret = -ENOMEM;
- goto err1;
- }
+ debugfs_create_file("curr_regs", S_IRUGO, root, cd, &curr_regs_fops);
+ debugfs_create_file("curr_dbg_uid0", S_IRUGO, root, cd,
+ &curr_dbg_uid0_fops);
+ debugfs_create_file("curr_dbg_uid1", S_IRUGO, root, cd,
+ &curr_dbg_uid1_fops);
+ debugfs_create_file("curr_dbg_uid2", S_IRUGO, root, cd,
+ &curr_dbg_uid2_fops);
+ debugfs_create_file("prev_regs", S_IRUGO, root, cd, &prev_regs_fops);
+ debugfs_create_file("prev_dbg_uid0", S_IRUGO, root, cd,
+ &prev_dbg_uid0_fops);
+ debugfs_create_file("prev_dbg_uid1", S_IRUGO, root, cd,
+ &prev_dbg_uid1_fops);
+ debugfs_create_file("prev_dbg_uid2", S_IRUGO, root, cd,
+ &prev_dbg_uid2_fops);
for (i = 0; i < GENWQE_MAX_VFS; i++) {
sprintf(name, "vf%u_jobtimeout_msec", i);
-
- file = debugfs_create_u32(name, 0666, root,
- &cd->vf_jobtimeout_msec[i]);
- if (!file) {
- ret = -ENOMEM;
- goto err1;
- }
+ debugfs_create_u32(name, 0666, root,
+ &cd->vf_jobtimeout_msec[i]);
}
- file = debugfs_create_file("jobtimer", S_IRUGO, root, cd,
- &jtimer_fops);
- if (!file) {
- ret = -ENOMEM;
- goto err1;
- }
-
- file = debugfs_create_file("queue_working_time", S_IRUGO, root, cd,
- &queue_working_time_fops);
- if (!file) {
- ret = -ENOMEM;
- goto err1;
- }
-
- file = debugfs_create_u32("skip_recovery", 0666, root,
- &cd->skip_recovery);
- if (!file) {
- ret = -ENOMEM;
- goto err1;
- }
-
- file = debugfs_create_u32("use_platform_recovery", 0666, root,
- &cd->use_platform_recovery);
- if (!file) {
- ret = -ENOMEM;
- goto err1;
- }
+ debugfs_create_file("jobtimer", S_IRUGO, root, cd, &jtimer_fops);
+ debugfs_create_file("queue_working_time", S_IRUGO, root, cd,
+ &queue_working_time_fops);
+ debugfs_create_u32("skip_recovery", 0666, root, &cd->skip_recovery);
+ debugfs_create_u32("use_platform_recovery", 0666, root,
+ &cd->use_platform_recovery);
cd->debugfs_root = root;
- return 0;
-err1:
- debugfs_remove_recursive(root);
-err0:
- return ret;
}
void genqwe_exit_debugfs(struct genwqe_dev *cd)
diff --git a/drivers/misc/genwqe/card_dev.c b/drivers/misc/genwqe/card_dev.c
index 3bc51f19c734..0e34c0568fed 100644
--- a/drivers/misc/genwqe/card_dev.c
+++ b/drivers/misc/genwqe/card_dev.c
@@ -1301,14 +1301,10 @@ int genwqe_device_create(struct genwqe_dev *cd)
goto err_cdev;
}
- rc = genwqe_init_debugfs(cd);
- if (rc != 0)
- goto err_debugfs;
+ genwqe_init_debugfs(cd);
return 0;
- err_debugfs:
- device_destroy(cd->class_genwqe, cd->devnum_genwqe);
err_cdev:
cdev_del(&cd->cdev_genwqe);
err_add:
diff --git a/drivers/misc/habanalabs/asid.c b/drivers/misc/habanalabs/asid.c
index f54e7971a762..2c01461701a3 100644
--- a/drivers/misc/habanalabs/asid.c
+++ b/drivers/misc/habanalabs/asid.c
@@ -18,7 +18,7 @@ int hl_asid_init(struct hl_device *hdev)
mutex_init(&hdev->asid_mutex);
- /* ASID 0 is reserved for KMD */
+ /* ASID 0 is reserved for KMD and device CPU */
set_bit(0, hdev->asid_bitmap);
return 0;
diff --git a/drivers/misc/habanalabs/command_submission.c b/drivers/misc/habanalabs/command_submission.c
index 6fe785e26859..6ad83d5ef4b0 100644
--- a/drivers/misc/habanalabs/command_submission.c
+++ b/drivers/misc/habanalabs/command_submission.c
@@ -682,14 +682,12 @@ int hl_cs_ioctl(struct hl_fpriv *hpriv, void *data)
u32 tmp;
rc = hl_poll_timeout_memory(hdev,
- (u64) (uintptr_t) &ctx->thread_ctx_switch_wait_token,
- jiffies_to_usecs(hdev->timeout_jiffies),
- &tmp);
+ &ctx->thread_ctx_switch_wait_token, tmp, (tmp == 1),
+ 100, jiffies_to_usecs(hdev->timeout_jiffies));
- if (rc || !tmp) {
+ if (rc == -ETIMEDOUT) {
dev_err(hdev->dev,
- "context switch phase didn't finish in time\n");
- rc = -ETIMEDOUT;
+ "context switch phase timeout (%d)\n", tmp);
goto out;
}
}
diff --git a/drivers/misc/habanalabs/context.c b/drivers/misc/habanalabs/context.c
index f4c92f110a72..8682590e3f6e 100644
--- a/drivers/misc/habanalabs/context.c
+++ b/drivers/misc/habanalabs/context.c
@@ -31,9 +31,13 @@ static void hl_ctx_fini(struct hl_ctx *ctx)
* Coresight might be still working by accessing addresses
* related to the stopped engines. Hence stop it explicitly.
*/
- hdev->asic_funcs->halt_coresight(hdev);
+ if (hdev->in_debug)
+ hl_device_set_debug_mode(hdev, false);
+
hl_vm_ctx_fini(ctx);
hl_asid_free(hdev, ctx->asid);
+ } else {
+ hl_mmu_ctx_fini(ctx);
}
}
@@ -117,6 +121,11 @@ int hl_ctx_init(struct hl_device *hdev, struct hl_ctx *ctx, bool is_kernel_ctx)
if (is_kernel_ctx) {
ctx->asid = HL_KERNEL_ASID_ID; /* KMD gets ASID 0 */
+ rc = hl_mmu_ctx_init(ctx);
+ if (rc) {
+ dev_err(hdev->dev, "Failed to init mmu ctx module\n");
+ goto mem_ctx_err;
+ }
} else {
ctx->asid = hl_asid_alloc(hdev);
if (!ctx->asid) {
diff --git a/drivers/misc/habanalabs/debugfs.c b/drivers/misc/habanalabs/debugfs.c
index ba418aaa404c..18e499c900c7 100644
--- a/drivers/misc/habanalabs/debugfs.c
+++ b/drivers/misc/habanalabs/debugfs.c
@@ -355,7 +355,7 @@ static int mmu_show(struct seq_file *s, void *data)
struct hl_debugfs_entry *entry = s->private;
struct hl_dbg_device_entry *dev_entry = entry->dev_entry;
struct hl_device *hdev = dev_entry->hdev;
- struct hl_ctx *ctx = hdev->user_ctx;
+ struct hl_ctx *ctx;
u64 hop0_addr = 0, hop0_pte_addr = 0, hop0_pte = 0,
hop1_addr = 0, hop1_pte_addr = 0, hop1_pte = 0,
@@ -367,6 +367,11 @@ static int mmu_show(struct seq_file *s, void *data)
if (!hdev->mmu_enable)
return 0;
+ if (dev_entry->mmu_asid == HL_KERNEL_ASID_ID)
+ ctx = hdev->kernel_ctx;
+ else
+ ctx = hdev->user_ctx;
+
if (!ctx) {
dev_err(hdev->dev, "no ctx available\n");
return 0;
@@ -495,6 +500,36 @@ err:
return -EINVAL;
}
+static int engines_show(struct seq_file *s, void *data)
+{
+ struct hl_debugfs_entry *entry = s->private;
+ struct hl_dbg_device_entry *dev_entry = entry->dev_entry;
+ struct hl_device *hdev = dev_entry->hdev;
+
+ hdev->asic_funcs->is_device_idle(hdev, NULL, s);
+
+ return 0;
+}
+
+static bool hl_is_device_va(struct hl_device *hdev, u64 addr)
+{
+ struct asic_fixed_properties *prop = &hdev->asic_prop;
+
+ if (!hdev->mmu_enable)
+ goto out;
+
+ if (hdev->dram_supports_virtual_memory &&
+ addr >= prop->va_space_dram_start_address &&
+ addr < prop->va_space_dram_end_address)
+ return true;
+
+ if (addr >= prop->va_space_host_start_address &&
+ addr < prop->va_space_host_end_address)
+ return true;
+out:
+ return false;
+}
+
static int device_va_to_pa(struct hl_device *hdev, u64 virt_addr,
u64 *phys_addr)
{
@@ -568,7 +603,6 @@ static ssize_t hl_data_read32(struct file *f, char __user *buf,
{
struct hl_dbg_device_entry *entry = file_inode(f)->i_private;
struct hl_device *hdev = entry->hdev;
- struct asic_fixed_properties *prop = &hdev->asic_prop;
char tmp_buf[32];
u64 addr = entry->addr;
u32 val;
@@ -577,11 +611,8 @@ static ssize_t hl_data_read32(struct file *f, char __user *buf,
if (*ppos)
return 0;
- if (addr >= prop->va_space_dram_start_address &&
- addr < prop->va_space_dram_end_address &&
- hdev->mmu_enable &&
- hdev->dram_supports_virtual_memory) {
- rc = device_va_to_pa(hdev, entry->addr, &addr);
+ if (hl_is_device_va(hdev, addr)) {
+ rc = device_va_to_pa(hdev, addr, &addr);
if (rc)
return rc;
}
@@ -602,7 +633,6 @@ static ssize_t hl_data_write32(struct file *f, const char __user *buf,
{
struct hl_dbg_device_entry *entry = file_inode(f)->i_private;
struct hl_device *hdev = entry->hdev;
- struct asic_fixed_properties *prop = &hdev->asic_prop;
u64 addr = entry->addr;
u32 value;
ssize_t rc;
@@ -611,11 +641,8 @@ static ssize_t hl_data_write32(struct file *f, const char __user *buf,
if (rc)
return rc;
- if (addr >= prop->va_space_dram_start_address &&
- addr < prop->va_space_dram_end_address &&
- hdev->mmu_enable &&
- hdev->dram_supports_virtual_memory) {
- rc = device_va_to_pa(hdev, entry->addr, &addr);
+ if (hl_is_device_va(hdev, addr)) {
+ rc = device_va_to_pa(hdev, addr, &addr);
if (rc)
return rc;
}
@@ -877,6 +904,7 @@ static const struct hl_info_list hl_debugfs_list[] = {
{"userptr", userptr_show, NULL},
{"vm", vm_show, NULL},
{"mmu", mmu_show, mmu_write},
+ {"engines", engines_show, NULL}
};
static int hl_debugfs_open(struct inode *inode, struct file *file)
diff --git a/drivers/misc/habanalabs/device.c b/drivers/misc/habanalabs/device.c
index 0b19d3eefb98..0c4894dd9c02 100644
--- a/drivers/misc/habanalabs/device.c
+++ b/drivers/misc/habanalabs/device.c
@@ -231,6 +231,7 @@ static int device_early_init(struct hl_device *hdev)
mutex_init(&hdev->fd_open_cnt_lock);
mutex_init(&hdev->send_cpu_message_lock);
+ mutex_init(&hdev->debug_lock);
mutex_init(&hdev->mmu_cache_lock);
INIT_LIST_HEAD(&hdev->hw_queues_mirror_list);
spin_lock_init(&hdev->hw_queues_mirror_lock);
@@ -262,6 +263,7 @@ early_fini:
static void device_early_fini(struct hl_device *hdev)
{
mutex_destroy(&hdev->mmu_cache_lock);
+ mutex_destroy(&hdev->debug_lock);
mutex_destroy(&hdev->send_cpu_message_lock);
hl_cb_mgr_fini(hdev, &hdev->kernel_cb_mgr);
@@ -324,7 +326,15 @@ static int device_late_init(struct hl_device *hdev)
{
int rc;
- INIT_DELAYED_WORK(&hdev->work_freq, set_freq_to_low_job);
+ if (hdev->asic_funcs->late_init) {
+ rc = hdev->asic_funcs->late_init(hdev);
+ if (rc) {
+ dev_err(hdev->dev,
+ "failed late initialization for the H/W\n");
+ return rc;
+ }
+ }
+
hdev->high_pll = hdev->asic_prop.high_pll;
/* force setting to low frequency */
@@ -335,17 +345,9 @@ static int device_late_init(struct hl_device *hdev)
else
hdev->asic_funcs->set_pll_profile(hdev, PLL_LAST);
- if (hdev->asic_funcs->late_init) {
- rc = hdev->asic_funcs->late_init(hdev);
- if (rc) {
- dev_err(hdev->dev,
- "failed late initialization for the H/W\n");
- return rc;
- }
- }
-
+ INIT_DELAYED_WORK(&hdev->work_freq, set_freq_to_low_job);
schedule_delayed_work(&hdev->work_freq,
- usecs_to_jiffies(HL_PLL_LOW_JOB_FREQ_USEC));
+ usecs_to_jiffies(HL_PLL_LOW_JOB_FREQ_USEC));
if (hdev->heartbeat) {
INIT_DELAYED_WORK(&hdev->work_heartbeat, hl_device_heartbeat);
@@ -420,6 +422,52 @@ int hl_device_set_frequency(struct hl_device *hdev, enum hl_pll_frequency freq)
return 1;
}
+int hl_device_set_debug_mode(struct hl_device *hdev, bool enable)
+{
+ int rc = 0;
+
+ mutex_lock(&hdev->debug_lock);
+
+ if (!enable) {
+ if (!hdev->in_debug) {
+ dev_err(hdev->dev,
+ "Failed to disable debug mode because device was not in debug mode\n");
+ rc = -EFAULT;
+ goto out;
+ }
+
+ hdev->asic_funcs->halt_coresight(hdev);
+ hdev->in_debug = 0;
+
+ goto out;
+ }
+
+ if (hdev->in_debug) {
+ dev_err(hdev->dev,
+ "Failed to enable debug mode because device is already in debug mode\n");
+ rc = -EFAULT;
+ goto out;
+ }
+
+ mutex_lock(&hdev->fd_open_cnt_lock);
+
+ if (atomic_read(&hdev->fd_open_cnt) > 1) {
+ dev_err(hdev->dev,
+ "Failed to enable debug mode. More then a single user is using the device\n");
+ rc = -EPERM;
+ goto unlock_fd_open_lock;
+ }
+
+ hdev->in_debug = 1;
+
+unlock_fd_open_lock:
+ mutex_unlock(&hdev->fd_open_cnt_lock);
+out:
+ mutex_unlock(&hdev->debug_lock);
+
+ return rc;
+}
+
/*
* hl_device_suspend - initiate device suspend
*
@@ -647,13 +695,6 @@ again:
hdev->hard_reset_pending = true;
- if (!hdev->pdev) {
- dev_err(hdev->dev,
- "Reset action is NOT supported in simulator\n");
- rc = -EINVAL;
- goto out_err;
- }
-
device_reset_work = kzalloc(sizeof(*device_reset_work),
GFP_ATOMIC);
if (!device_reset_work) {
@@ -704,6 +745,7 @@ again:
if (hard_reset) {
hl_vm_fini(hdev);
+ hl_mmu_fini(hdev);
hl_eq_reset(hdev, &hdev->event_queue);
}
@@ -731,6 +773,13 @@ again:
goto out_err;
}
+ rc = hl_mmu_init(hdev);
+ if (rc) {
+ dev_err(hdev->dev,
+ "Failed to initialize MMU S/W after hard reset\n");
+ goto out_err;
+ }
+
/* Allocate the kernel context */
hdev->kernel_ctx = kzalloc(sizeof(*hdev->kernel_ctx),
GFP_KERNEL);
@@ -902,11 +951,18 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass)
goto cq_fini;
}
+ /* MMU S/W must be initialized before kernel context is created */
+ rc = hl_mmu_init(hdev);
+ if (rc) {
+ dev_err(hdev->dev, "Failed to initialize MMU S/W structures\n");
+ goto eq_fini;
+ }
+
/* Allocate the kernel context */
hdev->kernel_ctx = kzalloc(sizeof(*hdev->kernel_ctx), GFP_KERNEL);
if (!hdev->kernel_ctx) {
rc = -ENOMEM;
- goto eq_fini;
+ goto mmu_fini;
}
hdev->user_ctx = NULL;
@@ -954,8 +1010,6 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass)
goto out_disabled;
}
- /* After test_queues, KMD can start sending messages to device CPU */
-
rc = device_late_init(hdev);
if (rc) {
dev_err(hdev->dev, "Failed late initialization\n");
@@ -1001,6 +1055,8 @@ release_ctx:
"kernel ctx is still alive on initialization failure\n");
free_ctx:
kfree(hdev->kernel_ctx);
+mmu_fini:
+ hl_mmu_fini(hdev);
eq_fini:
hl_eq_fini(hdev, &hdev->event_queue);
cq_fini:
@@ -1105,6 +1161,8 @@ void hl_device_fini(struct hl_device *hdev)
hl_vm_fini(hdev);
+ hl_mmu_fini(hdev);
+
hl_eq_fini(hdev, &hdev->event_queue);
for (i = 0 ; i < hdev->asic_prop.completion_queues_count ; i++)
@@ -1126,95 +1184,6 @@ void hl_device_fini(struct hl_device *hdev)
}
/*
- * hl_poll_timeout_memory - Periodically poll a host memory address
- * until it is not zero or a timeout occurs
- * @hdev: pointer to habanalabs device structure
- * @addr: Address to poll
- * @timeout_us: timeout in us
- * @val: Variable to read the value into
- *
- * Returns 0 on success and -ETIMEDOUT upon a timeout. In either
- * case, the last read value at @addr is stored in @val. Must not
- * be called from atomic context if sleep_us or timeout_us are used.
- *
- * The function sleeps for 100us with timeout value of
- * timeout_us
- */
-int hl_poll_timeout_memory(struct hl_device *hdev, u64 addr,
- u32 timeout_us, u32 *val)
-{
- /*
- * address in this function points always to a memory location in the
- * host's (server's) memory. That location is updated asynchronously
- * either by the direct access of the device or by another core
- */
- u32 *paddr = (u32 *) (uintptr_t) addr;
- ktime_t timeout;
-
- /* timeout should be longer when working with simulator */
- if (!hdev->pdev)
- timeout_us *= 10;
-
- timeout = ktime_add_us(ktime_get(), timeout_us);
-
- might_sleep();
-
- for (;;) {
- /*
- * Flush CPU read/write buffers to make sure we read updates
- * done by other cores or by the device
- */
- mb();
- *val = *paddr;
- if (*val)
- break;
- if (ktime_compare(ktime_get(), timeout) > 0) {
- *val = *paddr;
- break;
- }
- usleep_range((100 >> 2) + 1, 100);
- }
-
- return *val ? 0 : -ETIMEDOUT;
-}
-
-/*
- * hl_poll_timeout_devicememory - Periodically poll a device memory address
- * until it is not zero or a timeout occurs
- * @hdev: pointer to habanalabs device structure
- * @addr: Device address to poll
- * @timeout_us: timeout in us
- * @val: Variable to read the value into
- *
- * Returns 0 on success and -ETIMEDOUT upon a timeout. In either
- * case, the last read value at @addr is stored in @val. Must not
- * be called from atomic context if sleep_us or timeout_us are used.
- *
- * The function sleeps for 100us with timeout value of
- * timeout_us
- */
-int hl_poll_timeout_device_memory(struct hl_device *hdev, void __iomem *addr,
- u32 timeout_us, u32 *val)
-{
- ktime_t timeout = ktime_add_us(ktime_get(), timeout_us);
-
- might_sleep();
-
- for (;;) {
- *val = readl(addr);
- if (*val)
- break;
- if (ktime_compare(ktime_get(), timeout) > 0) {
- *val = readl(addr);
- break;
- }
- usleep_range((100 >> 2) + 1, 100);
- }
-
- return *val ? 0 : -ETIMEDOUT;
-}
-
-/*
* MMIO register access helper functions.
*/
diff --git a/drivers/misc/habanalabs/firmware_if.c b/drivers/misc/habanalabs/firmware_if.c
index eda5d7fcb79f..cc8168bacb24 100644
--- a/drivers/misc/habanalabs/firmware_if.c
+++ b/drivers/misc/habanalabs/firmware_if.c
@@ -29,13 +29,13 @@ int hl_fw_push_fw_to_device(struct hl_device *hdev, const char *fw_name,
rc = request_firmware(&fw, fw_name, hdev->dev);
if (rc) {
- dev_err(hdev->dev, "Failed to request %s\n", fw_name);
+ dev_err(hdev->dev, "Firmware file %s is not found!\n", fw_name);
goto out;
}
fw_size = fw->size;
if ((fw_size % 4) != 0) {
- dev_err(hdev->dev, "illegal %s firmware size %zu\n",
+ dev_err(hdev->dev, "Illegal %s firmware size %zu\n",
fw_name, fw_size);
rc = -EINVAL;
goto out;
@@ -85,12 +85,6 @@ int hl_fw_send_cpu_message(struct hl_device *hdev, u32 hw_queue_id, u32 *msg,
u32 tmp;
int rc = 0;
- if (len > HL_CPU_CB_SIZE) {
- dev_err(hdev->dev, "Invalid CPU message size of %d bytes\n",
- len);
- return -ENOMEM;
- }
-
pkt = hdev->asic_funcs->cpu_accessible_dma_pool_alloc(hdev, len,
&pkt_dma_addr);
if (!pkt) {
@@ -117,33 +111,28 @@ int hl_fw_send_cpu_message(struct hl_device *hdev, u32 hw_queue_id, u32 *msg,
goto out;
}
- rc = hl_poll_timeout_memory(hdev, (u64) (uintptr_t) &pkt->fence,
- timeout, &tmp);
+ rc = hl_poll_timeout_memory(hdev, &pkt->fence, tmp,
+ (tmp == ARMCP_PACKET_FENCE_VAL), 1000, timeout);
hl_hw_queue_inc_ci_kernel(hdev, hw_queue_id);
if (rc == -ETIMEDOUT) {
- dev_err(hdev->dev, "Timeout while waiting for device CPU\n");
+ dev_err(hdev->dev, "Device CPU packet timeout (0x%x)\n", tmp);
hdev->device_cpu_disabled = true;
goto out;
}
- if (tmp == ARMCP_PACKET_FENCE_VAL) {
- u32 ctl = le32_to_cpu(pkt->ctl);
+ tmp = le32_to_cpu(pkt->ctl);
- rc = (ctl & ARMCP_PKT_CTL_RC_MASK) >> ARMCP_PKT_CTL_RC_SHIFT;
- if (rc) {
- dev_err(hdev->dev,
- "F/W ERROR %d for CPU packet %d\n",
- rc, (ctl & ARMCP_PKT_CTL_OPCODE_MASK)
+ rc = (tmp & ARMCP_PKT_CTL_RC_MASK) >> ARMCP_PKT_CTL_RC_SHIFT;
+ if (rc) {
+ dev_err(hdev->dev, "F/W ERROR %d for CPU packet %d\n",
+ rc,
+ (tmp & ARMCP_PKT_CTL_OPCODE_MASK)
>> ARMCP_PKT_CTL_OPCODE_SHIFT);
- rc = -EINVAL;
- } else if (result) {
- *result = (long) le64_to_cpu(pkt->result);
- }
- } else {
- dev_err(hdev->dev, "CPU packet wrong fence value\n");
- rc = -EINVAL;
+ rc = -EIO;
+ } else if (result) {
+ *result = (long) le64_to_cpu(pkt->result);
}
out:
@@ -186,9 +175,6 @@ void *hl_fw_cpu_accessible_dma_pool_alloc(struct hl_device *hdev, size_t size,
{
u64 kernel_addr;
- /* roundup to HL_CPU_PKT_SIZE */
- size = (size + (HL_CPU_PKT_SIZE - 1)) & HL_CPU_PKT_MASK;
-
kernel_addr = gen_pool_alloc(hdev->cpu_accessible_dma_pool, size);
*dma_handle = hdev->cpu_accessible_dma_address +
@@ -200,9 +186,6 @@ void *hl_fw_cpu_accessible_dma_pool_alloc(struct hl_device *hdev, size_t size,
void hl_fw_cpu_accessible_dma_pool_free(struct hl_device *hdev, size_t size,
void *vaddr)
{
- /* roundup to HL_CPU_PKT_SIZE */
- size = (size + (HL_CPU_PKT_SIZE - 1)) & HL_CPU_PKT_MASK;
-
gen_pool_free(hdev->cpu_accessible_dma_pool, (u64) (uintptr_t) vaddr,
size);
}
@@ -256,7 +239,7 @@ int hl_fw_armcp_info_get(struct hl_device *hdev)
HL_ARMCP_INFO_TIMEOUT_USEC, &result);
if (rc) {
dev_err(hdev->dev,
- "Failed to send armcp info pkt, error %d\n", rc);
+ "Failed to send ArmCP info pkt, error %d\n", rc);
goto out;
}
@@ -291,7 +274,7 @@ int hl_fw_get_eeprom_data(struct hl_device *hdev, void *data, size_t max_size)
max_size, &eeprom_info_dma_addr);
if (!eeprom_info_cpu_addr) {
dev_err(hdev->dev,
- "Failed to allocate DMA memory for EEPROM info packet\n");
+ "Failed to allocate DMA memory for ArmCP EEPROM packet\n");
return -ENOMEM;
}
@@ -307,7 +290,7 @@ int hl_fw_get_eeprom_data(struct hl_device *hdev, void *data, size_t max_size)
if (rc) {
dev_err(hdev->dev,
- "Failed to send armcp EEPROM pkt, error %d\n", rc);
+ "Failed to send ArmCP EEPROM packet, error %d\n", rc);
goto out;
}
diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c
index 02d116b01a1a..75294ec65257 100644
--- a/drivers/misc/habanalabs/goya/goya.c
+++ b/drivers/misc/habanalabs/goya/goya.c
@@ -14,6 +14,8 @@
#include <linux/genalloc.h>
#include <linux/hwmon.h>
#include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/iommu.h>
+#include <linux/seq_file.h>
/*
* GOYA security scheme:
@@ -89,6 +91,30 @@
#define GOYA_CB_POOL_CB_CNT 512
#define GOYA_CB_POOL_CB_SIZE 0x20000 /* 128KB */
+#define IS_QM_IDLE(engine, qm_glbl_sts0) \
+ (((qm_glbl_sts0) & engine##_QM_IDLE_MASK) == engine##_QM_IDLE_MASK)
+#define IS_DMA_QM_IDLE(qm_glbl_sts0) IS_QM_IDLE(DMA, qm_glbl_sts0)
+#define IS_TPC_QM_IDLE(qm_glbl_sts0) IS_QM_IDLE(TPC, qm_glbl_sts0)
+#define IS_MME_QM_IDLE(qm_glbl_sts0) IS_QM_IDLE(MME, qm_glbl_sts0)
+
+#define IS_CMDQ_IDLE(engine, cmdq_glbl_sts0) \
+ (((cmdq_glbl_sts0) & engine##_CMDQ_IDLE_MASK) == \
+ engine##_CMDQ_IDLE_MASK)
+#define IS_TPC_CMDQ_IDLE(cmdq_glbl_sts0) \
+ IS_CMDQ_IDLE(TPC, cmdq_glbl_sts0)
+#define IS_MME_CMDQ_IDLE(cmdq_glbl_sts0) \
+ IS_CMDQ_IDLE(MME, cmdq_glbl_sts0)
+
+#define IS_DMA_IDLE(dma_core_sts0) \
+ !((dma_core_sts0) & DMA_CH_0_STS0_DMA_BUSY_MASK)
+
+#define IS_TPC_IDLE(tpc_cfg_sts) \
+ (((tpc_cfg_sts) & TPC_CFG_IDLE_MASK) == TPC_CFG_IDLE_MASK)
+
+#define IS_MME_IDLE(mme_arch_sts) \
+ (((mme_arch_sts) & MME_ARCH_IDLE_MASK) == MME_ARCH_IDLE_MASK)
+
+
static const char goya_irq_name[GOYA_MSIX_ENTRIES][GOYA_MAX_STRING_LEN] = {
"goya cq 0", "goya cq 1", "goya cq 2", "goya cq 3",
"goya cq 4", "goya cpu eq"
@@ -297,6 +323,11 @@ static u32 goya_all_events[] = {
GOYA_ASYNC_EVENT_ID_DMA_BM_CH4
};
+static int goya_mmu_clear_pgt_range(struct hl_device *hdev);
+static int goya_mmu_set_dram_default_page(struct hl_device *hdev);
+static int goya_mmu_add_mappings_for_device_cpu(struct hl_device *hdev);
+static void goya_mmu_prepare(struct hl_device *hdev, u32 asid);
+
void goya_get_fixed_properties(struct hl_device *hdev)
{
struct asic_fixed_properties *prop = &hdev->asic_prop;
@@ -467,7 +498,7 @@ static int goya_early_init(struct hl_device *hdev)
prop->dram_pci_bar_size = pci_resource_len(pdev, DDR_BAR_ID);
- rc = hl_pci_init(hdev, 39);
+ rc = hl_pci_init(hdev, 48);
if (rc)
return rc;
@@ -539,9 +570,36 @@ int goya_late_init(struct hl_device *hdev)
struct asic_fixed_properties *prop = &hdev->asic_prop;
int rc;
+ goya_fetch_psoc_frequency(hdev);
+
+ rc = goya_mmu_clear_pgt_range(hdev);
+ if (rc) {
+ dev_err(hdev->dev,
+ "Failed to clear MMU page tables range %d\n", rc);
+ return rc;
+ }
+
+ rc = goya_mmu_set_dram_default_page(hdev);
+ if (rc) {
+ dev_err(hdev->dev, "Failed to set DRAM default page %d\n", rc);
+ return rc;
+ }
+
+ rc = goya_mmu_add_mappings_for_device_cpu(hdev);
+ if (rc)
+ return rc;
+
+ rc = goya_init_cpu_queues(hdev);
+ if (rc)
+ return rc;
+
+ rc = goya_test_cpu_queue(hdev);
+ if (rc)
+ return rc;
+
rc = goya_armcp_info_get(hdev);
if (rc) {
- dev_err(hdev->dev, "Failed to get armcp info\n");
+ dev_err(hdev->dev, "Failed to get armcp info %d\n", rc);
return rc;
}
@@ -553,33 +611,15 @@ int goya_late_init(struct hl_device *hdev)
rc = hl_fw_send_pci_access_msg(hdev, ARMCP_PACKET_ENABLE_PCI_ACCESS);
if (rc) {
- dev_err(hdev->dev, "Failed to enable PCI access from CPU\n");
+ dev_err(hdev->dev,
+ "Failed to enable PCI access from CPU %d\n", rc);
return rc;
}
WREG32(mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR,
GOYA_ASYNC_EVENT_ID_INTS_REGISTER);
- goya_fetch_psoc_frequency(hdev);
-
- rc = goya_mmu_clear_pgt_range(hdev);
- if (rc) {
- dev_err(hdev->dev, "Failed to clear MMU page tables range\n");
- goto disable_pci_access;
- }
-
- rc = goya_mmu_set_dram_default_page(hdev);
- if (rc) {
- dev_err(hdev->dev, "Failed to set DRAM default page\n");
- goto disable_pci_access;
- }
-
return 0;
-
-disable_pci_access:
- hl_fw_send_pci_access_msg(hdev, ARMCP_PACKET_DISABLE_PCI_ACCESS);
-
- return rc;
}
/*
@@ -655,7 +695,10 @@ static int goya_sw_init(struct hl_device *hdev)
goto free_dma_pool;
}
- hdev->cpu_accessible_dma_pool = gen_pool_create(HL_CPU_PKT_SHIFT, -1);
+ dev_dbg(hdev->dev, "cpu accessible memory at bus address 0x%llx\n",
+ hdev->cpu_accessible_dma_address);
+
+ hdev->cpu_accessible_dma_pool = gen_pool_create(ilog2(32), -1);
if (!hdev->cpu_accessible_dma_pool) {
dev_err(hdev->dev,
"Failed to create CPU accessible DMA pool\n");
@@ -786,7 +829,6 @@ static void goya_init_dma_ch(struct hl_device *hdev, int dma_id)
else
sob_addr = CFG_BASE + mmSYNC_MNGR_SOB_OBJ_1007;
- WREG32(mmDMA_CH_0_WR_COMP_ADDR_LO + reg_off, lower_32_bits(sob_addr));
WREG32(mmDMA_CH_0_WR_COMP_ADDR_HI + reg_off, upper_32_bits(sob_addr));
WREG32(mmDMA_CH_0_WR_COMP_WDATA + reg_off, 0x80000001);
}
@@ -973,9 +1015,9 @@ int goya_init_cpu_queues(struct hl_device *hdev)
WREG32(mmPSOC_GLOBAL_CONF_SCRATCHPAD_3, upper_32_bits(eq->bus_address));
WREG32(mmPSOC_GLOBAL_CONF_SCRATCHPAD_8,
- lower_32_bits(hdev->cpu_accessible_dma_address));
+ lower_32_bits(VA_CPU_ACCESSIBLE_MEM_ADDR));
WREG32(mmPSOC_GLOBAL_CONF_SCRATCHPAD_9,
- upper_32_bits(hdev->cpu_accessible_dma_address));
+ upper_32_bits(VA_CPU_ACCESSIBLE_MEM_ADDR));
WREG32(mmPSOC_GLOBAL_CONF_SCRATCHPAD_5, HL_QUEUE_SIZE_IN_BYTES);
WREG32(mmPSOC_GLOBAL_CONF_SCRATCHPAD_4, HL_EQ_SIZE_IN_BYTES);
@@ -1001,7 +1043,7 @@ int goya_init_cpu_queues(struct hl_device *hdev)
if (err) {
dev_err(hdev->dev,
- "Failed to communicate with ARM CPU (ArmCP timeout)\n");
+ "Failed to setup communication with device CPU\n");
return -EIO;
}
@@ -2061,10 +2103,12 @@ static void goya_halt_engines(struct hl_device *hdev, bool hard_reset)
goya_disable_external_queues(hdev);
goya_disable_internal_queues(hdev);
- if (hard_reset)
+ if (hard_reset) {
goya_disable_msix(hdev);
- else
+ goya_mmu_remove_device_cpu_mappings(hdev);
+ } else {
goya_sync_irqs(hdev);
+ }
}
/*
@@ -2277,14 +2321,14 @@ static int goya_init_cpu(struct hl_device *hdev, u32 cpu_timeout)
goya_read_device_fw_version(hdev, FW_COMP_UBOOT);
goya_read_device_fw_version(hdev, FW_COMP_PREBOOT);
- if (status == CPU_BOOT_STATUS_SRAM_AVAIL)
- goto out;
-
if (!hdev->fw_loading) {
dev_info(hdev->dev, "Skip loading FW\n");
goto out;
}
+ if (status == CPU_BOOT_STATUS_SRAM_AVAIL)
+ goto out;
+
rc = goya_push_linux_to_device(hdev);
if (rc)
return rc;
@@ -2466,34 +2510,11 @@ static int goya_hw_init(struct hl_device *hdev)
if (rc)
goto disable_queues;
- rc = goya_init_cpu_queues(hdev);
- if (rc) {
- dev_err(hdev->dev, "failed to initialize CPU H/W queues %d\n",
- rc);
- goto disable_msix;
- }
-
- /*
- * Check if we managed to set the DMA mask to more then 32 bits. If so,
- * let's try to increase it again because in Goya we set the initial
- * dma mask to less then 39 bits so that the allocation of the memory
- * area for the device's cpu will be under 39 bits
- */
- if (hdev->dma_mask > 32) {
- rc = hl_pci_set_dma_mask(hdev, 48);
- if (rc)
- goto disable_pci_access;
- }
-
/* Perform read from the device to flush all MSI-X configuration */
val = RREG32(mmPCIE_DBI_DEVICE_ID_VENDOR_ID_REG);
return 0;
-disable_pci_access:
- hl_fw_send_pci_access_msg(hdev, ARMCP_PACKET_DISABLE_PCI_ACCESS);
-disable_msix:
- goya_disable_msix(hdev);
disable_queues:
goya_disable_internal_queues(hdev);
goya_disable_external_queues(hdev);
@@ -2629,7 +2650,6 @@ static int goya_cb_mmap(struct hl_device *hdev, struct vm_area_struct *vma,
void goya_ring_doorbell(struct hl_device *hdev, u32 hw_queue_id, u32 pi)
{
u32 db_reg_offset, db_value;
- bool invalid_queue = false;
switch (hw_queue_id) {
case GOYA_QUEUE_ID_DMA_0:
@@ -2653,10 +2673,7 @@ void goya_ring_doorbell(struct hl_device *hdev, u32 hw_queue_id, u32 pi)
break;
case GOYA_QUEUE_ID_CPU_PQ:
- if (hdev->cpu_queues_enable)
- db_reg_offset = mmCPU_IF_PF_PQ_PI;
- else
- invalid_queue = true;
+ db_reg_offset = mmCPU_IF_PF_PQ_PI;
break;
case GOYA_QUEUE_ID_MME:
@@ -2696,12 +2713,8 @@ void goya_ring_doorbell(struct hl_device *hdev, u32 hw_queue_id, u32 pi)
break;
default:
- invalid_queue = true;
- }
-
- if (invalid_queue) {
/* Should never get here */
- dev_err(hdev->dev, "h/w queue %d is invalid. Can't set pi\n",
+ dev_err(hdev->dev, "H/W queue %d is invalid. Can't set pi\n",
hw_queue_id);
return;
}
@@ -2808,7 +2821,6 @@ static int goya_send_job_on_qman0(struct hl_device *hdev, struct hl_cs_job *job)
dma_addr_t fence_dma_addr;
struct hl_cb *cb;
u32 tmp, timeout;
- char buf[16] = {};
int rc;
if (hdev->pldm)
@@ -2816,10 +2828,9 @@ static int goya_send_job_on_qman0(struct hl_device *hdev, struct hl_cs_job *job)
else
timeout = HL_DEVICE_TIMEOUT_USEC;
- if (!hdev->asic_funcs->is_device_idle(hdev, buf, sizeof(buf))) {
+ if (!hdev->asic_funcs->is_device_idle(hdev, NULL, NULL)) {
dev_err_ratelimited(hdev->dev,
- "Can't send KMD job on QMAN0 because %s is busy\n",
- buf);
+ "Can't send KMD job on QMAN0 because the device is not idle\n");
return -EBUSY;
}
@@ -2831,16 +2842,8 @@ static int goya_send_job_on_qman0(struct hl_device *hdev, struct hl_cs_job *job)
return -ENOMEM;
}
- *fence_ptr = 0;
-
goya_qman0_set_security(hdev, true);
- /*
- * goya cs parser saves space for 2xpacket_msg_prot at end of CB. For
- * synchronized kernel jobs we only need space for 1 packet_msg_prot
- */
- job->job_cb_size -= sizeof(struct packet_msg_prot);
-
cb = job->patched_cb;
fence_pkt = (struct packet_msg_prot *) (uintptr_t) (cb->kernel_address +
@@ -2860,14 +2863,14 @@ static int goya_send_job_on_qman0(struct hl_device *hdev, struct hl_cs_job *job)
goto free_fence_ptr;
}
- rc = hl_poll_timeout_memory(hdev, (u64) (uintptr_t) fence_ptr, timeout,
- &tmp);
+ rc = hl_poll_timeout_memory(hdev, fence_ptr, tmp,
+ (tmp == GOYA_QMAN0_FENCE_VAL), 1000, timeout);
hl_hw_queue_inc_ci_kernel(hdev, GOYA_QUEUE_ID_DMA_0);
- if ((rc) || (tmp != GOYA_QMAN0_FENCE_VAL)) {
- dev_err(hdev->dev, "QMAN0 Job hasn't finished in time\n");
- rc = -ETIMEDOUT;
+ if (rc == -ETIMEDOUT) {
+ dev_err(hdev->dev, "QMAN0 Job timeout (0x%x)\n", tmp);
+ goto free_fence_ptr;
}
free_fence_ptr:
@@ -2941,20 +2944,19 @@ int goya_test_queue(struct hl_device *hdev, u32 hw_queue_id)
goto free_pkt;
}
- rc = hl_poll_timeout_memory(hdev, (u64) (uintptr_t) fence_ptr,
- GOYA_TEST_QUEUE_WAIT_USEC, &tmp);
+ rc = hl_poll_timeout_memory(hdev, fence_ptr, tmp, (tmp == fence_val),
+ 1000, GOYA_TEST_QUEUE_WAIT_USEC);
hl_hw_queue_inc_ci_kernel(hdev, hw_queue_id);
- if ((!rc) && (tmp == fence_val)) {
- dev_info(hdev->dev,
- "queue test on H/W queue %d succeeded\n",
- hw_queue_id);
- } else {
+ if (rc == -ETIMEDOUT) {
dev_err(hdev->dev,
"H/W queue %d test failed (scratch(0x%08llX) == 0x%08X)\n",
hw_queue_id, (unsigned long long) fence_dma_addr, tmp);
- rc = -EINVAL;
+ rc = -EIO;
+ } else {
+ dev_info(hdev->dev, "queue test on H/W queue %d succeeded\n",
+ hw_queue_id);
}
free_pkt:
@@ -2990,12 +2992,6 @@ int goya_test_queues(struct hl_device *hdev)
ret_val = -EINVAL;
}
- if (hdev->cpu_queues_enable) {
- rc = goya_test_cpu_queue(hdev);
- if (rc)
- ret_val = -EINVAL;
- }
-
return ret_val;
}
@@ -3028,7 +3024,13 @@ static void goya_dma_pool_free(struct hl_device *hdev, void *vaddr,
void *goya_cpu_accessible_dma_pool_alloc(struct hl_device *hdev, size_t size,
dma_addr_t *dma_handle)
{
- return hl_fw_cpu_accessible_dma_pool_alloc(hdev, size, dma_handle);
+ void *vaddr;
+
+ vaddr = hl_fw_cpu_accessible_dma_pool_alloc(hdev, size, dma_handle);
+ *dma_handle = (*dma_handle) - hdev->cpu_accessible_dma_address +
+ VA_CPU_ACCESSIBLE_MEM_ADDR;
+
+ return vaddr;
}
void goya_cpu_accessible_dma_pool_free(struct hl_device *hdev, size_t size,
@@ -3907,8 +3909,8 @@ int goya_cs_parser(struct hl_device *hdev, struct hl_cs_parser *parser)
return goya_parse_cb_no_mmu(hdev, parser);
}
-void goya_add_end_of_cb_packets(u64 kernel_address, u32 len, u64 cq_addr,
- u32 cq_val, u32 msix_vec)
+void goya_add_end_of_cb_packets(struct hl_device *hdev, u64 kernel_address,
+ u32 len, u64 cq_addr, u32 cq_val, u32 msix_vec)
{
struct packet_msg_prot *cq_pkt;
u32 tmp;
@@ -3939,6 +3941,11 @@ void goya_update_eq_ci(struct hl_device *hdev, u32 val)
void goya_restore_phase_topology(struct hl_device *hdev)
{
+
+}
+
+static void goya_clear_sm_regs(struct hl_device *hdev)
+{
int i, num_of_sob_in_longs, num_of_mon_in_longs;
num_of_sob_in_longs =
@@ -3958,10 +3965,11 @@ void goya_restore_phase_topology(struct hl_device *hdev)
}
/*
- * goya_debugfs_read32 - read a 32bit value from a given device address
+ * goya_debugfs_read32 - read a 32bit value from a given device or a host mapped
+ * address.
*
* @hdev: pointer to hl_device structure
- * @addr: address in device
+ * @addr: device or host mapped address
* @val: returned value
*
* In case of DDR address that is not mapped into the default aperture that
@@ -4002,6 +4010,10 @@ static int goya_debugfs_read32(struct hl_device *hdev, u64 addr, u32 *val)
}
if (ddr_bar_addr == U64_MAX)
rc = -EIO;
+
+ } else if (addr >= HOST_PHYS_BASE && !iommu_present(&pci_bus_type)) {
+ *val = *(u32 *) phys_to_virt(addr - HOST_PHYS_BASE);
+
} else {
rc = -EFAULT;
}
@@ -4010,10 +4022,11 @@ static int goya_debugfs_read32(struct hl_device *hdev, u64 addr, u32 *val)
}
/*
- * goya_debugfs_write32 - write a 32bit value to a given device address
+ * goya_debugfs_write32 - write a 32bit value to a given device or a host mapped
+ * address.
*
* @hdev: pointer to hl_device structure
- * @addr: address in device
+ * @addr: device or host mapped address
* @val: returned value
*
* In case of DDR address that is not mapped into the default aperture that
@@ -4054,6 +4067,10 @@ static int goya_debugfs_write32(struct hl_device *hdev, u64 addr, u32 val)
}
if (ddr_bar_addr == U64_MAX)
rc = -EIO;
+
+ } else if (addr >= HOST_PHYS_BASE && !iommu_present(&pci_bus_type)) {
+ *(u32 *) phys_to_virt(addr - HOST_PHYS_BASE) = val;
+
} else {
rc = -EFAULT;
}
@@ -4086,6 +4103,47 @@ static void goya_write_pte(struct hl_device *hdev, u64 addr, u64 val)
static const char *_goya_get_event_desc(u16 event_type)
{
switch (event_type) {
+ case GOYA_ASYNC_EVENT_ID_PCIE_IF:
+ return "PCIe_if";
+ case GOYA_ASYNC_EVENT_ID_TPC0_ECC:
+ case GOYA_ASYNC_EVENT_ID_TPC1_ECC:
+ case GOYA_ASYNC_EVENT_ID_TPC2_ECC:
+ case GOYA_ASYNC_EVENT_ID_TPC3_ECC:
+ case GOYA_ASYNC_EVENT_ID_TPC4_ECC:
+ case GOYA_ASYNC_EVENT_ID_TPC5_ECC:
+ case GOYA_ASYNC_EVENT_ID_TPC6_ECC:
+ case GOYA_ASYNC_EVENT_ID_TPC7_ECC:
+ return "TPC%d_ecc";
+ case GOYA_ASYNC_EVENT_ID_MME_ECC:
+ return "MME_ecc";
+ case GOYA_ASYNC_EVENT_ID_MME_ECC_EXT:
+ return "MME_ecc_ext";
+ case GOYA_ASYNC_EVENT_ID_MMU_ECC:
+ return "MMU_ecc";
+ case GOYA_ASYNC_EVENT_ID_DMA_MACRO:
+ return "DMA_macro";
+ case GOYA_ASYNC_EVENT_ID_DMA_ECC:
+ return "DMA_ecc";
+ case GOYA_ASYNC_EVENT_ID_CPU_IF_ECC:
+ return "CPU_if_ecc";
+ case GOYA_ASYNC_EVENT_ID_PSOC_MEM:
+ return "PSOC_mem";
+ case GOYA_ASYNC_EVENT_ID_PSOC_CORESIGHT:
+ return "PSOC_coresight";
+ case GOYA_ASYNC_EVENT_ID_SRAM0 ... GOYA_ASYNC_EVENT_ID_SRAM29:
+ return "SRAM%d";
+ case GOYA_ASYNC_EVENT_ID_GIC500:
+ return "GIC500";
+ case GOYA_ASYNC_EVENT_ID_PLL0 ... GOYA_ASYNC_EVENT_ID_PLL6:
+ return "PLL%d";
+ case GOYA_ASYNC_EVENT_ID_AXI_ECC:
+ return "AXI_ecc";
+ case GOYA_ASYNC_EVENT_ID_L2_RAM_ECC:
+ return "L2_ram_ecc";
+ case GOYA_ASYNC_EVENT_ID_PSOC_GPIO_05_SW_RESET:
+ return "PSOC_gpio_05_sw_reset";
+ case GOYA_ASYNC_EVENT_ID_PSOC_GPIO_10_VRHOT_ICRIT:
+ return "PSOC_gpio_10_vrhot_icrit";
case GOYA_ASYNC_EVENT_ID_PCIE_DEC:
return "PCIe_dec";
case GOYA_ASYNC_EVENT_ID_TPC0_DEC:
@@ -4128,6 +4186,17 @@ static const char *_goya_get_event_desc(u16 event_type)
return "DMA%d_qm";
case GOYA_ASYNC_EVENT_ID_DMA0_CH ... GOYA_ASYNC_EVENT_ID_DMA4_CH:
return "DMA%d_ch";
+ case GOYA_ASYNC_EVENT_ID_TPC0_BMON_SPMU:
+ case GOYA_ASYNC_EVENT_ID_TPC1_BMON_SPMU:
+ case GOYA_ASYNC_EVENT_ID_TPC2_BMON_SPMU:
+ case GOYA_ASYNC_EVENT_ID_TPC3_BMON_SPMU:
+ case GOYA_ASYNC_EVENT_ID_TPC4_BMON_SPMU:
+ case GOYA_ASYNC_EVENT_ID_TPC5_BMON_SPMU:
+ case GOYA_ASYNC_EVENT_ID_TPC6_BMON_SPMU:
+ case GOYA_ASYNC_EVENT_ID_TPC7_BMON_SPMU:
+ return "TPC%d_bmon_spmu";
+ case GOYA_ASYNC_EVENT_ID_DMA_BM_CH0 ... GOYA_ASYNC_EVENT_ID_DMA_BM_CH4:
+ return "DMA_bm_ch%d";
default:
return "N/A";
}
@@ -4138,6 +4207,25 @@ static void goya_get_event_desc(u16 event_type, char *desc, size_t size)
u8 index;
switch (event_type) {
+ case GOYA_ASYNC_EVENT_ID_TPC0_ECC:
+ case GOYA_ASYNC_EVENT_ID_TPC1_ECC:
+ case GOYA_ASYNC_EVENT_ID_TPC2_ECC:
+ case GOYA_ASYNC_EVENT_ID_TPC3_ECC:
+ case GOYA_ASYNC_EVENT_ID_TPC4_ECC:
+ case GOYA_ASYNC_EVENT_ID_TPC5_ECC:
+ case GOYA_ASYNC_EVENT_ID_TPC6_ECC:
+ case GOYA_ASYNC_EVENT_ID_TPC7_ECC:
+ index = (event_type - GOYA_ASYNC_EVENT_ID_TPC0_ECC) / 3;
+ snprintf(desc, size, _goya_get_event_desc(event_type), index);
+ break;
+ case GOYA_ASYNC_EVENT_ID_SRAM0 ... GOYA_ASYNC_EVENT_ID_SRAM29:
+ index = event_type - GOYA_ASYNC_EVENT_ID_SRAM0;
+ snprintf(desc, size, _goya_get_event_desc(event_type), index);
+ break;
+ case GOYA_ASYNC_EVENT_ID_PLL0 ... GOYA_ASYNC_EVENT_ID_PLL6:
+ index = event_type - GOYA_ASYNC_EVENT_ID_PLL0;
+ snprintf(desc, size, _goya_get_event_desc(event_type), index);
+ break;
case GOYA_ASYNC_EVENT_ID_TPC0_DEC:
case GOYA_ASYNC_EVENT_ID_TPC1_DEC:
case GOYA_ASYNC_EVENT_ID_TPC2_DEC:
@@ -4176,6 +4264,21 @@ static void goya_get_event_desc(u16 event_type, char *desc, size_t size)
index = event_type - GOYA_ASYNC_EVENT_ID_DMA0_CH;
snprintf(desc, size, _goya_get_event_desc(event_type), index);
break;
+ case GOYA_ASYNC_EVENT_ID_TPC0_BMON_SPMU:
+ case GOYA_ASYNC_EVENT_ID_TPC1_BMON_SPMU:
+ case GOYA_ASYNC_EVENT_ID_TPC2_BMON_SPMU:
+ case GOYA_ASYNC_EVENT_ID_TPC3_BMON_SPMU:
+ case GOYA_ASYNC_EVENT_ID_TPC4_BMON_SPMU:
+ case GOYA_ASYNC_EVENT_ID_TPC5_BMON_SPMU:
+ case GOYA_ASYNC_EVENT_ID_TPC6_BMON_SPMU:
+ case GOYA_ASYNC_EVENT_ID_TPC7_BMON_SPMU:
+ index = (event_type - GOYA_ASYNC_EVENT_ID_TPC0_BMON_SPMU) / 10;
+ snprintf(desc, size, _goya_get_event_desc(event_type), index);
+ break;
+ case GOYA_ASYNC_EVENT_ID_DMA_BM_CH0 ... GOYA_ASYNC_EVENT_ID_DMA_BM_CH4:
+ index = event_type - GOYA_ASYNC_EVENT_ID_DMA_BM_CH0;
+ snprintf(desc, size, _goya_get_event_desc(event_type), index);
+ break;
default:
snprintf(desc, size, _goya_get_event_desc(event_type));
break;
@@ -4226,7 +4329,8 @@ static void goya_print_mmu_error_info(struct hl_device *hdev)
}
}
-static void goya_print_irq_info(struct hl_device *hdev, u16 event_type)
+static void goya_print_irq_info(struct hl_device *hdev, u16 event_type,
+ bool razwi)
{
char desc[20] = "";
@@ -4234,8 +4338,10 @@ static void goya_print_irq_info(struct hl_device *hdev, u16 event_type)
dev_err(hdev->dev, "Received H/W interrupt %d [\"%s\"]\n",
event_type, desc);
- goya_print_razwi_info(hdev);
- goya_print_mmu_error_info(hdev);
+ if (razwi) {
+ goya_print_razwi_info(hdev);
+ goya_print_mmu_error_info(hdev);
+ }
}
static int goya_unmask_irq_arr(struct hl_device *hdev, u32 *irq_arr,
@@ -4339,19 +4445,12 @@ void goya_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entry)
case GOYA_ASYNC_EVENT_ID_PSOC_CORESIGHT:
case GOYA_ASYNC_EVENT_ID_SRAM0 ... GOYA_ASYNC_EVENT_ID_SRAM29:
case GOYA_ASYNC_EVENT_ID_GIC500:
- case GOYA_ASYNC_EVENT_ID_PLL0:
- case GOYA_ASYNC_EVENT_ID_PLL1:
- case GOYA_ASYNC_EVENT_ID_PLL3:
- case GOYA_ASYNC_EVENT_ID_PLL4:
- case GOYA_ASYNC_EVENT_ID_PLL5:
- case GOYA_ASYNC_EVENT_ID_PLL6:
+ case GOYA_ASYNC_EVENT_ID_PLL0 ... GOYA_ASYNC_EVENT_ID_PLL6:
case GOYA_ASYNC_EVENT_ID_AXI_ECC:
case GOYA_ASYNC_EVENT_ID_L2_RAM_ECC:
case GOYA_ASYNC_EVENT_ID_PSOC_GPIO_05_SW_RESET:
case GOYA_ASYNC_EVENT_ID_PSOC_GPIO_10_VRHOT_ICRIT:
- dev_err(hdev->dev,
- "Received H/W interrupt %d, reset the chip\n",
- event_type);
+ goya_print_irq_info(hdev, event_type, false);
hl_device_reset(hdev, true, false);
break;
@@ -4382,7 +4481,7 @@ void goya_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entry)
case GOYA_ASYNC_EVENT_ID_MME_CMDQ:
case GOYA_ASYNC_EVENT_ID_DMA0_QM ... GOYA_ASYNC_EVENT_ID_DMA4_QM:
case GOYA_ASYNC_EVENT_ID_DMA0_CH ... GOYA_ASYNC_EVENT_ID_DMA4_CH:
- goya_print_irq_info(hdev, event_type);
+ goya_print_irq_info(hdev, event_type, true);
goya_unmask_irq(hdev, event_type);
break;
@@ -4394,12 +4493,9 @@ void goya_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entry)
case GOYA_ASYNC_EVENT_ID_TPC5_BMON_SPMU:
case GOYA_ASYNC_EVENT_ID_TPC6_BMON_SPMU:
case GOYA_ASYNC_EVENT_ID_TPC7_BMON_SPMU:
- case GOYA_ASYNC_EVENT_ID_DMA_BM_CH0:
- case GOYA_ASYNC_EVENT_ID_DMA_BM_CH1:
- case GOYA_ASYNC_EVENT_ID_DMA_BM_CH2:
- case GOYA_ASYNC_EVENT_ID_DMA_BM_CH3:
- case GOYA_ASYNC_EVENT_ID_DMA_BM_CH4:
- dev_info(hdev->dev, "Received H/W interrupt %d\n", event_type);
+ case GOYA_ASYNC_EVENT_ID_DMA_BM_CH0 ... GOYA_ASYNC_EVENT_ID_DMA_BM_CH4:
+ goya_print_irq_info(hdev, event_type, false);
+ goya_unmask_irq(hdev, event_type);
break;
default:
@@ -4418,36 +4514,47 @@ void *goya_get_events_stat(struct hl_device *hdev, u32 *size)
return goya->events_stat;
}
-static int goya_memset_device_memory(struct hl_device *hdev, u64 addr, u32 size,
+static int goya_memset_device_memory(struct hl_device *hdev, u64 addr, u64 size,
u64 val, bool is_dram)
{
struct packet_lin_dma *lin_dma_pkt;
struct hl_cs_job *job;
u32 cb_size, ctl;
struct hl_cb *cb;
- int rc;
+ int rc, lin_dma_pkts_cnt;
- cb = hl_cb_kernel_create(hdev, PAGE_SIZE);
+ lin_dma_pkts_cnt = DIV_ROUND_UP_ULL(size, SZ_2G);
+ cb_size = lin_dma_pkts_cnt * sizeof(struct packet_lin_dma) +
+ sizeof(struct packet_msg_prot);
+ cb = hl_cb_kernel_create(hdev, cb_size);
if (!cb)
- return -EFAULT;
+ return -ENOMEM;
lin_dma_pkt = (struct packet_lin_dma *) (uintptr_t) cb->kernel_address;
- memset(lin_dma_pkt, 0, sizeof(*lin_dma_pkt));
- cb_size = sizeof(*lin_dma_pkt);
-
- ctl = ((PACKET_LIN_DMA << GOYA_PKT_CTL_OPCODE_SHIFT) |
- (1 << GOYA_PKT_LIN_DMA_CTL_MEMSET_SHIFT) |
- (1 << GOYA_PKT_LIN_DMA_CTL_WO_SHIFT) |
- (1 << GOYA_PKT_CTL_RB_SHIFT) |
- (1 << GOYA_PKT_CTL_MB_SHIFT));
- ctl |= (is_dram ? DMA_HOST_TO_DRAM : DMA_HOST_TO_SRAM) <<
- GOYA_PKT_LIN_DMA_CTL_DMA_DIR_SHIFT;
- lin_dma_pkt->ctl = cpu_to_le32(ctl);
+ do {
+ memset(lin_dma_pkt, 0, sizeof(*lin_dma_pkt));
+
+ ctl = ((PACKET_LIN_DMA << GOYA_PKT_CTL_OPCODE_SHIFT) |
+ (1 << GOYA_PKT_LIN_DMA_CTL_MEMSET_SHIFT) |
+ (1 << GOYA_PKT_LIN_DMA_CTL_WO_SHIFT) |
+ (1 << GOYA_PKT_CTL_RB_SHIFT) |
+ (1 << GOYA_PKT_CTL_MB_SHIFT));
+ ctl |= (is_dram ? DMA_HOST_TO_DRAM : DMA_HOST_TO_SRAM) <<
+ GOYA_PKT_LIN_DMA_CTL_DMA_DIR_SHIFT;
+ lin_dma_pkt->ctl = cpu_to_le32(ctl);
+
+ lin_dma_pkt->src_addr = cpu_to_le64(val);
+ lin_dma_pkt->dst_addr = cpu_to_le64(addr);
+ if (lin_dma_pkts_cnt > 1)
+ lin_dma_pkt->tsize = cpu_to_le32(SZ_2G);
+ else
+ lin_dma_pkt->tsize = cpu_to_le32(size);
- lin_dma_pkt->src_addr = cpu_to_le64(val);
- lin_dma_pkt->dst_addr = cpu_to_le64(addr);
- lin_dma_pkt->tsize = cpu_to_le32(size);
+ size -= SZ_2G;
+ addr += SZ_2G;
+ lin_dma_pkt++;
+ } while (--lin_dma_pkts_cnt);
job = hl_cs_allocate_job(hdev, true);
if (!job) {
@@ -4462,8 +4569,7 @@ static int goya_memset_device_memory(struct hl_device *hdev, u64 addr, u32 size,
job->user_cb_size = cb_size;
job->hw_queue_id = GOYA_QUEUE_ID_DMA_0;
job->patched_cb = job->user_cb;
- job->job_cb_size = job->user_cb_size +
- sizeof(struct packet_msg_prot) * 2;
+ job->job_cb_size = job->user_cb_size;
hl_debugfs_add_job(hdev, job);
@@ -4485,10 +4591,12 @@ release_cb:
int goya_context_switch(struct hl_device *hdev, u32 asid)
{
struct asic_fixed_properties *prop = &hdev->asic_prop;
- u64 addr = prop->sram_base_address;
+ u64 addr = prop->sram_base_address, sob_addr;
u32 size = hdev->pldm ? 0x10000 : prop->sram_size;
u64 val = 0x7777777777777777ull;
- int rc;
+ int rc, dma_id;
+ u32 channel_off = mmDMA_CH_1_WR_COMP_ADDR_LO -
+ mmDMA_CH_0_WR_COMP_ADDR_LO;
rc = goya_memset_device_memory(hdev, addr, size, val, false);
if (rc) {
@@ -4496,13 +4604,27 @@ int goya_context_switch(struct hl_device *hdev, u32 asid)
return rc;
}
+ /* we need to reset registers that the user is allowed to change */
+ sob_addr = CFG_BASE + mmSYNC_MNGR_SOB_OBJ_1007;
+ WREG32(mmDMA_CH_0_WR_COMP_ADDR_LO, lower_32_bits(sob_addr));
+
+ for (dma_id = 1 ; dma_id < NUMBER_OF_EXT_HW_QUEUES ; dma_id++) {
+ sob_addr = CFG_BASE + mmSYNC_MNGR_SOB_OBJ_1000 +
+ (dma_id - 1) * 4;
+ WREG32(mmDMA_CH_0_WR_COMP_ADDR_LO + channel_off * dma_id,
+ lower_32_bits(sob_addr));
+ }
+
WREG32(mmTPC_PLL_CLK_RLX_0, 0x200020);
+
goya_mmu_prepare(hdev, asid);
+ goya_clear_sm_regs(hdev);
+
return 0;
}
-int goya_mmu_clear_pgt_range(struct hl_device *hdev)
+static int goya_mmu_clear_pgt_range(struct hl_device *hdev)
{
struct asic_fixed_properties *prop = &hdev->asic_prop;
struct goya_device *goya = hdev->asic_specific;
@@ -4516,7 +4638,7 @@ int goya_mmu_clear_pgt_range(struct hl_device *hdev)
return goya_memset_device_memory(hdev, addr, size, 0, true);
}
-int goya_mmu_set_dram_default_page(struct hl_device *hdev)
+static int goya_mmu_set_dram_default_page(struct hl_device *hdev)
{
struct goya_device *goya = hdev->asic_specific;
u64 addr = hdev->asic_prop.mmu_dram_default_page_addr;
@@ -4529,7 +4651,123 @@ int goya_mmu_set_dram_default_page(struct hl_device *hdev)
return goya_memset_device_memory(hdev, addr, size, val, true);
}
-void goya_mmu_prepare(struct hl_device *hdev, u32 asid)
+static int goya_mmu_add_mappings_for_device_cpu(struct hl_device *hdev)
+{
+ struct asic_fixed_properties *prop = &hdev->asic_prop;
+ struct goya_device *goya = hdev->asic_specific;
+ s64 off, cpu_off;
+ int rc;
+
+ if (!(goya->hw_cap_initialized & HW_CAP_MMU))
+ return 0;
+
+ for (off = 0 ; off < CPU_FW_IMAGE_SIZE ; off += PAGE_SIZE_2MB) {
+ rc = hl_mmu_map(hdev->kernel_ctx, prop->dram_base_address + off,
+ prop->dram_base_address + off, PAGE_SIZE_2MB);
+ if (rc) {
+ dev_err(hdev->dev, "Map failed for address 0x%llx\n",
+ prop->dram_base_address + off);
+ goto unmap;
+ }
+ }
+
+ if (!(hdev->cpu_accessible_dma_address & (PAGE_SIZE_2MB - 1))) {
+ rc = hl_mmu_map(hdev->kernel_ctx, VA_CPU_ACCESSIBLE_MEM_ADDR,
+ hdev->cpu_accessible_dma_address, PAGE_SIZE_2MB);
+
+ if (rc) {
+ dev_err(hdev->dev,
+ "Map failed for CPU accessible memory\n");
+ off -= PAGE_SIZE_2MB;
+ goto unmap;
+ }
+ } else {
+ for (cpu_off = 0 ; cpu_off < SZ_2M ; cpu_off += PAGE_SIZE_4KB) {
+ rc = hl_mmu_map(hdev->kernel_ctx,
+ VA_CPU_ACCESSIBLE_MEM_ADDR + cpu_off,
+ hdev->cpu_accessible_dma_address + cpu_off,
+ PAGE_SIZE_4KB);
+ if (rc) {
+ dev_err(hdev->dev,
+ "Map failed for CPU accessible memory\n");
+ cpu_off -= PAGE_SIZE_4KB;
+ goto unmap_cpu;
+ }
+ }
+ }
+
+ goya_mmu_prepare_reg(hdev, mmCPU_IF_ARUSER_OVR, HL_KERNEL_ASID_ID);
+ goya_mmu_prepare_reg(hdev, mmCPU_IF_AWUSER_OVR, HL_KERNEL_ASID_ID);
+ WREG32(mmCPU_IF_ARUSER_OVR_EN, 0x7FF);
+ WREG32(mmCPU_IF_AWUSER_OVR_EN, 0x7FF);
+
+ /* Make sure configuration is flushed to device */
+ RREG32(mmCPU_IF_AWUSER_OVR_EN);
+
+ goya->device_cpu_mmu_mappings_done = true;
+
+ return 0;
+
+unmap_cpu:
+ for (; cpu_off >= 0 ; cpu_off -= PAGE_SIZE_4KB)
+ if (hl_mmu_unmap(hdev->kernel_ctx,
+ VA_CPU_ACCESSIBLE_MEM_ADDR + cpu_off,
+ PAGE_SIZE_4KB))
+ dev_warn_ratelimited(hdev->dev,
+ "failed to unmap address 0x%llx\n",
+ VA_CPU_ACCESSIBLE_MEM_ADDR + cpu_off);
+unmap:
+ for (; off >= 0 ; off -= PAGE_SIZE_2MB)
+ if (hl_mmu_unmap(hdev->kernel_ctx,
+ prop->dram_base_address + off, PAGE_SIZE_2MB))
+ dev_warn_ratelimited(hdev->dev,
+ "failed to unmap address 0x%llx\n",
+ prop->dram_base_address + off);
+
+ return rc;
+}
+
+void goya_mmu_remove_device_cpu_mappings(struct hl_device *hdev)
+{
+ struct asic_fixed_properties *prop = &hdev->asic_prop;
+ struct goya_device *goya = hdev->asic_specific;
+ u32 off, cpu_off;
+
+ if (!(goya->hw_cap_initialized & HW_CAP_MMU))
+ return;
+
+ if (!goya->device_cpu_mmu_mappings_done)
+ return;
+
+ WREG32(mmCPU_IF_ARUSER_OVR_EN, 0);
+ WREG32(mmCPU_IF_AWUSER_OVR_EN, 0);
+
+ if (!(hdev->cpu_accessible_dma_address & (PAGE_SIZE_2MB - 1))) {
+ if (hl_mmu_unmap(hdev->kernel_ctx, VA_CPU_ACCESSIBLE_MEM_ADDR,
+ PAGE_SIZE_2MB))
+ dev_warn(hdev->dev,
+ "Failed to unmap CPU accessible memory\n");
+ } else {
+ for (cpu_off = 0 ; cpu_off < SZ_2M ; cpu_off += PAGE_SIZE_4KB)
+ if (hl_mmu_unmap(hdev->kernel_ctx,
+ VA_CPU_ACCESSIBLE_MEM_ADDR + cpu_off,
+ PAGE_SIZE_4KB))
+ dev_warn_ratelimited(hdev->dev,
+ "failed to unmap address 0x%llx\n",
+ VA_CPU_ACCESSIBLE_MEM_ADDR + cpu_off);
+ }
+
+ for (off = 0 ; off < CPU_FW_IMAGE_SIZE ; off += PAGE_SIZE_2MB)
+ if (hl_mmu_unmap(hdev->kernel_ctx,
+ prop->dram_base_address + off, PAGE_SIZE_2MB))
+ dev_warn_ratelimited(hdev->dev,
+ "Failed to unmap address 0x%llx\n",
+ prop->dram_base_address + off);
+
+ goya->device_cpu_mmu_mappings_done = false;
+}
+
+static void goya_mmu_prepare(struct hl_device *hdev, u32 asid)
{
struct goya_device *goya = hdev->asic_specific;
int i;
@@ -4676,57 +4914,82 @@ int goya_armcp_info_get(struct hl_device *hdev)
return 0;
}
-static bool goya_is_device_idle(struct hl_device *hdev, char *buf, size_t size)
+static bool goya_is_device_idle(struct hl_device *hdev, u32 *mask,
+ struct seq_file *s)
{
- u64 offset, dma_qm_reg, tpc_qm_reg, tpc_cmdq_reg, tpc_cfg_reg;
+ const char *fmt = "%-5d%-9s%#-14x%#-16x%#x\n";
+ const char *dma_fmt = "%-5d%-9s%#-14x%#x\n";
+ u32 qm_glbl_sts0, cmdq_glbl_sts0, dma_core_sts0, tpc_cfg_sts,
+ mme_arch_sts;
+ bool is_idle = true, is_eng_idle;
+ u64 offset;
int i;
+ if (s)
+ seq_puts(s, "\nDMA is_idle QM_GLBL_STS0 DMA_CORE_STS0\n"
+ "--- ------- ------------ -------------\n");
+
offset = mmDMA_QM_1_GLBL_STS0 - mmDMA_QM_0_GLBL_STS0;
for (i = 0 ; i < DMA_MAX_NUM ; i++) {
- dma_qm_reg = mmDMA_QM_0_GLBL_STS0 + i * offset;
+ qm_glbl_sts0 = RREG32(mmDMA_QM_0_GLBL_STS0 + i * offset);
+ dma_core_sts0 = RREG32(mmDMA_CH_0_STS0 + i * offset);
+ is_eng_idle = IS_DMA_QM_IDLE(qm_glbl_sts0) &&
+ IS_DMA_IDLE(dma_core_sts0);
+ is_idle &= is_eng_idle;
- if ((RREG32(dma_qm_reg) & DMA_QM_IDLE_MASK) !=
- DMA_QM_IDLE_MASK)
- return HL_ENG_BUSY(buf, size, "DMA%d_QM", i);
+ if (mask)
+ *mask |= !is_eng_idle << (GOYA_ENGINE_ID_DMA_0 + i);
+ if (s)
+ seq_printf(s, dma_fmt, i, is_eng_idle ? "Y" : "N",
+ qm_glbl_sts0, dma_core_sts0);
}
+ if (s)
+ seq_puts(s,
+ "\nTPC is_idle QM_GLBL_STS0 CMDQ_GLBL_STS0 CFG_STATUS\n"
+ "--- ------- ------------ -------------- ----------\n");
+
offset = mmTPC1_QM_GLBL_STS0 - mmTPC0_QM_GLBL_STS0;
for (i = 0 ; i < TPC_MAX_NUM ; i++) {
- tpc_qm_reg = mmTPC0_QM_GLBL_STS0 + i * offset;
- tpc_cmdq_reg = mmTPC0_CMDQ_GLBL_STS0 + i * offset;
- tpc_cfg_reg = mmTPC0_CFG_STATUS + i * offset;
-
- if ((RREG32(tpc_qm_reg) & TPC_QM_IDLE_MASK) !=
- TPC_QM_IDLE_MASK)
- return HL_ENG_BUSY(buf, size, "TPC%d_QM", i);
-
- if ((RREG32(tpc_cmdq_reg) & TPC_CMDQ_IDLE_MASK) !=
- TPC_CMDQ_IDLE_MASK)
- return HL_ENG_BUSY(buf, size, "TPC%d_CMDQ", i);
-
- if ((RREG32(tpc_cfg_reg) & TPC_CFG_IDLE_MASK) !=
- TPC_CFG_IDLE_MASK)
- return HL_ENG_BUSY(buf, size, "TPC%d_CFG", i);
- }
-
- if ((RREG32(mmMME_QM_GLBL_STS0) & MME_QM_IDLE_MASK) !=
- MME_QM_IDLE_MASK)
- return HL_ENG_BUSY(buf, size, "MME_QM");
-
- if ((RREG32(mmMME_CMDQ_GLBL_STS0) & MME_CMDQ_IDLE_MASK) !=
- MME_CMDQ_IDLE_MASK)
- return HL_ENG_BUSY(buf, size, "MME_CMDQ");
-
- if ((RREG32(mmMME_ARCH_STATUS) & MME_ARCH_IDLE_MASK) !=
- MME_ARCH_IDLE_MASK)
- return HL_ENG_BUSY(buf, size, "MME_ARCH");
-
- if (RREG32(mmMME_SHADOW_0_STATUS) & MME_SHADOW_IDLE_MASK)
- return HL_ENG_BUSY(buf, size, "MME");
-
- return true;
+ qm_glbl_sts0 = RREG32(mmTPC0_QM_GLBL_STS0 + i * offset);
+ cmdq_glbl_sts0 = RREG32(mmTPC0_CMDQ_GLBL_STS0 + i * offset);
+ tpc_cfg_sts = RREG32(mmTPC0_CFG_STATUS + i * offset);
+ is_eng_idle = IS_TPC_QM_IDLE(qm_glbl_sts0) &&
+ IS_TPC_CMDQ_IDLE(cmdq_glbl_sts0) &&
+ IS_TPC_IDLE(tpc_cfg_sts);
+ is_idle &= is_eng_idle;
+
+ if (mask)
+ *mask |= !is_eng_idle << (GOYA_ENGINE_ID_TPC_0 + i);
+ if (s)
+ seq_printf(s, fmt, i, is_eng_idle ? "Y" : "N",
+ qm_glbl_sts0, cmdq_glbl_sts0, tpc_cfg_sts);
+ }
+
+ if (s)
+ seq_puts(s,
+ "\nMME is_idle QM_GLBL_STS0 CMDQ_GLBL_STS0 ARCH_STATUS\n"
+ "--- ------- ------------ -------------- -----------\n");
+
+ qm_glbl_sts0 = RREG32(mmMME_QM_GLBL_STS0);
+ cmdq_glbl_sts0 = RREG32(mmMME_CMDQ_GLBL_STS0);
+ mme_arch_sts = RREG32(mmMME_ARCH_STATUS);
+ is_eng_idle = IS_MME_QM_IDLE(qm_glbl_sts0) &&
+ IS_MME_CMDQ_IDLE(cmdq_glbl_sts0) &&
+ IS_MME_IDLE(mme_arch_sts);
+ is_idle &= is_eng_idle;
+
+ if (mask)
+ *mask |= !is_eng_idle << GOYA_ENGINE_ID_MME_0;
+ if (s) {
+ seq_printf(s, fmt, 0, is_eng_idle ? "Y" : "N", qm_glbl_sts0,
+ cmdq_glbl_sts0, mme_arch_sts);
+ seq_puts(s, "\n");
+ }
+
+ return is_idle;
}
static void goya_hw_queues_lock(struct hl_device *hdev)
diff --git a/drivers/misc/habanalabs/goya/goyaP.h b/drivers/misc/habanalabs/goya/goyaP.h
index c83cab0d641e..f8c611883dc1 100644
--- a/drivers/misc/habanalabs/goya/goyaP.h
+++ b/drivers/misc/habanalabs/goya/goyaP.h
@@ -126,6 +126,12 @@
#define VA_DDR_SPACE_SIZE (VA_DDR_SPACE_END - \
VA_DDR_SPACE_START) /* 128GB */
+#if (HL_CPU_ACCESSIBLE_MEM_SIZE != SZ_2M)
+#error "HL_CPU_ACCESSIBLE_MEM_SIZE must be exactly 2MB to enable MMU mapping"
+#endif
+
+#define VA_CPU_ACCESSIBLE_MEM_ADDR 0x8000000000ull
+
#define DMA_MAX_TRANSFER_SIZE U32_MAX
#define HW_CAP_PLL 0x00000001
@@ -157,6 +163,7 @@ struct goya_device {
u64 ddr_bar_cur_addr;
u32 events_stat[GOYA_ASYNC_EVENT_ID_SIZE];
u32 hw_cap_initialized;
+ u8 device_cpu_mmu_mappings_done;
};
void goya_get_fixed_properties(struct hl_device *hdev);
@@ -204,18 +211,14 @@ int goya_armcp_info_get(struct hl_device *hdev);
int goya_debug_coresight(struct hl_device *hdev, void *data);
void goya_halt_coresight(struct hl_device *hdev);
-void goya_mmu_prepare(struct hl_device *hdev, u32 asid);
-int goya_mmu_clear_pgt_range(struct hl_device *hdev);
-int goya_mmu_set_dram_default_page(struct hl_device *hdev);
-
int goya_suspend(struct hl_device *hdev);
int goya_resume(struct hl_device *hdev);
void goya_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entry);
void *goya_get_events_stat(struct hl_device *hdev, u32 *size);
-void goya_add_end_of_cb_packets(u64 kernel_address, u32 len, u64 cq_addr,
- u32 cq_val, u32 msix_vec);
+void goya_add_end_of_cb_packets(struct hl_device *hdev, u64 kernel_address,
+ u32 len, u64 cq_addr, u32 cq_val, u32 msix_vec);
int goya_cs_parser(struct hl_device *hdev, struct hl_cs_parser *parser);
void *goya_get_int_queue_base(struct hl_device *hdev, u32 queue_id,
dma_addr_t *dma_handle, u16 *queue_len);
@@ -225,5 +228,6 @@ void *goya_cpu_accessible_dma_pool_alloc(struct hl_device *hdev, size_t size,
dma_addr_t *dma_handle);
void goya_cpu_accessible_dma_pool_free(struct hl_device *hdev, size_t size,
void *vaddr);
+void goya_mmu_remove_device_cpu_mappings(struct hl_device *hdev);
#endif /* GOYAP_H_ */
diff --git a/drivers/misc/habanalabs/goya/goya_security.c b/drivers/misc/habanalabs/goya/goya_security.c
index d95d1b2f860d..d6ec12b3e692 100644
--- a/drivers/misc/habanalabs/goya/goya_security.c
+++ b/drivers/misc/habanalabs/goya/goya_security.c
@@ -677,6 +677,17 @@ static void goya_init_tpc_protection_bits(struct hl_device *hdev)
goya_pb_set_block(hdev, mmTPC0_RD_REGULATOR_BASE);
goya_pb_set_block(hdev, mmTPC0_WR_REGULATOR_BASE);
+ pb_addr = (mmTPC0_CFG_SEMAPHORE & ~0xFFF) + PROT_BITS_OFFS;
+ word_offset = ((mmTPC0_CFG_SEMAPHORE & PROT_BITS_OFFS) >> 7) << 2;
+
+ mask = 1 << ((mmTPC0_CFG_SEMAPHORE & 0x7F) >> 2);
+ mask |= 1 << ((mmTPC0_CFG_VFLAGS & 0x7F) >> 2);
+ mask |= 1 << ((mmTPC0_CFG_SFLAGS & 0x7F) >> 2);
+ mask |= 1 << ((mmTPC0_CFG_LFSR_POLYNOM & 0x7F) >> 2);
+ mask |= 1 << ((mmTPC0_CFG_STATUS & 0x7F) >> 2);
+
+ WREG32(pb_addr + word_offset, ~mask);
+
pb_addr = (mmTPC0_CFG_CFG_BASE_ADDRESS_HIGH & ~0xFFF) + PROT_BITS_OFFS;
word_offset = ((mmTPC0_CFG_CFG_BASE_ADDRESS_HIGH &
PROT_BITS_OFFS) >> 7) << 2;
@@ -684,6 +695,11 @@ static void goya_init_tpc_protection_bits(struct hl_device *hdev)
mask |= 1 << ((mmTPC0_CFG_CFG_SUBTRACT_VALUE & 0x7F) >> 2);
mask |= 1 << ((mmTPC0_CFG_SM_BASE_ADDRESS_LOW & 0x7F) >> 2);
mask |= 1 << ((mmTPC0_CFG_SM_BASE_ADDRESS_HIGH & 0x7F) >> 2);
+ mask |= 1 << ((mmTPC0_CFG_CFG_SUBTRACT_VALUE & 0x7F) >> 2);
+ mask |= 1 << ((mmTPC0_CFG_TPC_STALL & 0x7F) >> 2);
+ mask |= 1 << ((mmTPC0_CFG_MSS_CONFIG & 0x7F) >> 2);
+ mask |= 1 << ((mmTPC0_CFG_TPC_INTR_CAUSE & 0x7F) >> 2);
+ mask |= 1 << ((mmTPC0_CFG_TPC_INTR_MASK & 0x7F) >> 2);
WREG32(pb_addr + word_offset, ~mask);
diff --git a/drivers/misc/habanalabs/habanalabs.h b/drivers/misc/habanalabs/habanalabs.h
index adef7d9d7488..10da9940ee0d 100644
--- a/drivers/misc/habanalabs/habanalabs.h
+++ b/drivers/misc/habanalabs/habanalabs.h
@@ -34,6 +34,8 @@
#define HL_ARMCP_INFO_TIMEOUT_USEC 10000000 /* 10s */
#define HL_ARMCP_EEPROM_TIMEOUT_USEC 10000000 /* 10s */
+#define HL_PCI_ELBI_TIMEOUT_MSEC 10 /* 10ms */
+
#define HL_MAX_QUEUES 128
#define HL_MAX_JOBS_PER_CS 64
@@ -123,7 +125,7 @@ enum hl_device_hw_state {
/**
* struct asic_fixed_properties - ASIC specific immutable properties.
* @hw_queues_props: H/W queues properties.
- * @armcp_info: received various information from ArmCP regarding the H/W. e.g.
+ * @armcp_info: received various information from ArmCP regarding the H/W, e.g.
* available sensors.
* @uboot_ver: F/W U-boot version.
* @preboot_ver: F/W Preboot version.
@@ -318,18 +320,8 @@ struct hl_cs_job;
#define HL_EQ_LENGTH 64
#define HL_EQ_SIZE_IN_BYTES (HL_EQ_LENGTH * HL_EQ_ENTRY_SIZE)
-#define HL_CPU_PKT_SHIFT 5
-#define HL_CPU_PKT_SIZE (1 << HL_CPU_PKT_SHIFT)
-#define HL_CPU_PKT_MASK (~((1 << HL_CPU_PKT_SHIFT) - 1))
-#define HL_CPU_MAX_PKTS_IN_CB 32
-#define HL_CPU_CB_SIZE (HL_CPU_PKT_SIZE * \
- HL_CPU_MAX_PKTS_IN_CB)
-#define HL_CPU_CB_QUEUE_SIZE (HL_QUEUE_LENGTH * HL_CPU_CB_SIZE)
-
-/* KMD <-> ArmCP shared memory size (EQ + PQ + CPU CB queue) */
-#define HL_CPU_ACCESSIBLE_MEM_SIZE (HL_EQ_SIZE_IN_BYTES + \
- HL_QUEUE_SIZE_IN_BYTES + \
- HL_CPU_CB_QUEUE_SIZE)
+/* KMD <-> ArmCP shared memory size */
+#define HL_CPU_ACCESSIBLE_MEM_SIZE SZ_2M
/**
* struct hl_hw_queue - describes a H/W transport queue.
@@ -543,8 +535,9 @@ struct hl_asic_funcs {
enum dma_data_direction dir);
u32 (*get_dma_desc_list_size)(struct hl_device *hdev,
struct sg_table *sgt);
- void (*add_end_of_cb_packets)(u64 kernel_address, u32 len, u64 cq_addr,
- u32 cq_val, u32 msix_num);
+ void (*add_end_of_cb_packets)(struct hl_device *hdev,
+ u64 kernel_address, u32 len,
+ u64 cq_addr, u32 cq_val, u32 msix_num);
void (*update_eq_ci)(struct hl_device *hdev, u32 val);
int (*context_switch)(struct hl_device *hdev, u32 asid);
void (*restore_phase_topology)(struct hl_device *hdev);
@@ -564,7 +557,8 @@ struct hl_asic_funcs {
u32 asid, u64 va, u64 size);
int (*send_heartbeat)(struct hl_device *hdev);
int (*debug_coresight)(struct hl_device *hdev, void *data);
- bool (*is_device_idle)(struct hl_device *hdev, char *buf, size_t size);
+ bool (*is_device_idle)(struct hl_device *hdev, u32 *mask,
+ struct seq_file *s);
int (*soft_reset_late_init)(struct hl_device *hdev);
void (*hw_queues_lock)(struct hl_device *hdev);
void (*hw_queues_unlock)(struct hl_device *hdev);
@@ -1065,12 +1059,59 @@ void hl_wreg(struct hl_device *hdev, u32 reg, u32 val);
(cond) ? 0 : -ETIMEDOUT; \
})
+/*
+ * address in this macro points always to a memory location in the
+ * host's (server's) memory. That location is updated asynchronously
+ * either by the direct access of the device or by another core
+ */
+#define hl_poll_timeout_memory(hdev, addr, val, cond, sleep_us, timeout_us) \
+({ \
+ ktime_t __timeout; \
+ /* timeout should be longer when working with simulator */ \
+ if (hdev->pdev) \
+ __timeout = ktime_add_us(ktime_get(), timeout_us); \
+ else \
+ __timeout = ktime_add_us(ktime_get(), (timeout_us * 10)); \
+ might_sleep_if(sleep_us); \
+ for (;;) { \
+ /* Verify we read updates done by other cores or by device */ \
+ mb(); \
+ (val) = *((u32 *) (uintptr_t) (addr)); \
+ if (cond) \
+ break; \
+ if (timeout_us && ktime_compare(ktime_get(), __timeout) > 0) { \
+ (val) = *((u32 *) (uintptr_t) (addr)); \
+ break; \
+ } \
+ if (sleep_us) \
+ usleep_range((sleep_us >> 2) + 1, sleep_us); \
+ } \
+ (cond) ? 0 : -ETIMEDOUT; \
+})
-#define HL_ENG_BUSY(buf, size, fmt, ...) ({ \
- if (buf) \
- snprintf(buf, size, fmt, ##__VA_ARGS__); \
- false; \
- })
+#define hl_poll_timeout_device_memory(hdev, addr, val, cond, sleep_us, \
+ timeout_us) \
+({ \
+ ktime_t __timeout; \
+ /* timeout should be longer when working with simulator */ \
+ if (hdev->pdev) \
+ __timeout = ktime_add_us(ktime_get(), timeout_us); \
+ else \
+ __timeout = ktime_add_us(ktime_get(), (timeout_us * 10)); \
+ might_sleep_if(sleep_us); \
+ for (;;) { \
+ (val) = readl(addr); \
+ if (cond) \
+ break; \
+ if (timeout_us && ktime_compare(ktime_get(), __timeout) > 0) { \
+ (val) = readl(addr); \
+ break; \
+ } \
+ if (sleep_us) \
+ usleep_range((sleep_us >> 2) + 1, sleep_us); \
+ } \
+ (cond) ? 0 : -ETIMEDOUT; \
+})
struct hwmon_chip_info;
@@ -1117,6 +1158,7 @@ struct hl_device_reset_work {
* lock here so we can flush user processes which are opening
* the device while we are trying to hard reset it
* @send_cpu_message_lock: enforces only one message in KMD <-> ArmCP queue.
+ * @debug_lock: protects critical section of setting debug mode for device
* @asic_prop: ASIC specific immutable properties.
* @asic_funcs: ASIC specific functions.
* @asic_specific: ASIC specific information to use only from ASIC files.
@@ -1159,6 +1201,8 @@ struct hl_device_reset_work {
* @mmu_enable: is MMU enabled.
* @device_cpu_disabled: is the device CPU disabled (due to timeouts)
* @dma_mask: the dma mask that was set for this device
+ * @in_debug: is device under debug. This, together with fd_open_cnt, enforces
+ * that only a single user is configuring the debug infrastructure.
*/
struct hl_device {
struct pci_dev *pdev;
@@ -1188,6 +1232,7 @@ struct hl_device {
/* TODO: remove fd_open_cnt_lock for multiple process support */
struct mutex fd_open_cnt_lock;
struct mutex send_cpu_message_lock;
+ struct mutex debug_lock;
struct asic_fixed_properties asic_prop;
const struct hl_asic_funcs *asic_funcs;
void *asic_specific;
@@ -1230,6 +1275,7 @@ struct hl_device {
u8 init_done;
u8 device_cpu_disabled;
u8 dma_mask;
+ u8 in_debug;
/* Parameters for bring-up */
u8 mmu_enable;
@@ -1325,13 +1371,10 @@ static inline bool hl_mem_area_crosses_range(u64 address, u32 size,
int hl_device_open(struct inode *inode, struct file *filp);
bool hl_device_disabled_or_in_reset(struct hl_device *hdev);
enum hl_device_status hl_device_status(struct hl_device *hdev);
+int hl_device_set_debug_mode(struct hl_device *hdev, bool enable);
int create_hdev(struct hl_device **dev, struct pci_dev *pdev,
enum hl_asic_type asic_type, int minor);
void destroy_hdev(struct hl_device *hdev);
-int hl_poll_timeout_memory(struct hl_device *hdev, u64 addr, u32 timeout_us,
- u32 *val);
-int hl_poll_timeout_device_memory(struct hl_device *hdev, void __iomem *addr,
- u32 timeout_us, u32 *val);
int hl_hw_queues_create(struct hl_device *hdev);
void hl_hw_queues_destroy(struct hl_device *hdev);
int hl_hw_queue_send_cb_no_cmpl(struct hl_device *hdev, u32 hw_queue_id,
diff --git a/drivers/misc/habanalabs/habanalabs_drv.c b/drivers/misc/habanalabs/habanalabs_drv.c
index 5f4d155be767..6f6dbe93f1df 100644
--- a/drivers/misc/habanalabs/habanalabs_drv.c
+++ b/drivers/misc/habanalabs/habanalabs_drv.c
@@ -105,9 +105,17 @@ int hl_device_open(struct inode *inode, struct file *filp)
return -EPERM;
}
+ if (hdev->in_debug) {
+ dev_err_ratelimited(hdev->dev,
+ "Can't open %s because it is being debugged by another user\n",
+ dev_name(hdev->dev));
+ mutex_unlock(&hdev->fd_open_cnt_lock);
+ return -EPERM;
+ }
+
if (atomic_read(&hdev->fd_open_cnt)) {
dev_info_ratelimited(hdev->dev,
- "Device %s is already attached to application\n",
+ "Can't open %s because another user is working on it\n",
dev_name(hdev->dev));
mutex_unlock(&hdev->fd_open_cnt_lock);
return -EBUSY;
@@ -164,6 +172,17 @@ close_device:
return rc;
}
+static void set_driver_behavior_per_device(struct hl_device *hdev)
+{
+ hdev->mmu_enable = 1;
+ hdev->cpu_enable = 1;
+ hdev->fw_loading = 1;
+ hdev->cpu_queues_enable = 1;
+ hdev->heartbeat = 1;
+
+ hdev->reset_pcilink = 0;
+}
+
/*
* create_hdev - create habanalabs device instance
*
@@ -188,29 +207,25 @@ int create_hdev(struct hl_device **dev, struct pci_dev *pdev,
if (!hdev)
return -ENOMEM;
+ /* First, we must find out which ASIC are we handling. This is needed
+ * to configure the behavior of the driver (kernel parameters)
+ */
+ if (pdev) {
+ hdev->asic_type = get_asic_type(pdev->device);
+ if (hdev->asic_type == ASIC_INVALID) {
+ dev_err(&pdev->dev, "Unsupported ASIC\n");
+ rc = -ENODEV;
+ goto free_hdev;
+ }
+ } else {
+ hdev->asic_type = asic_type;
+ }
+
hdev->major = hl_major;
hdev->reset_on_lockup = reset_on_lockup;
-
- /* Parameters for bring-up - set them to defaults */
- hdev->mmu_enable = 1;
- hdev->cpu_enable = 1;
- hdev->reset_pcilink = 0;
- hdev->cpu_queues_enable = 1;
- hdev->fw_loading = 1;
hdev->pldm = 0;
- hdev->heartbeat = 1;
-
- /* If CPU is disabled, no point in loading FW */
- if (!hdev->cpu_enable)
- hdev->fw_loading = 0;
- /* If we don't load FW, no need to initialize CPU queues */
- if (!hdev->fw_loading)
- hdev->cpu_queues_enable = 0;
-
- /* If CPU queues not enabled, no way to do heartbeat */
- if (!hdev->cpu_queues_enable)
- hdev->heartbeat = 0;
+ set_driver_behavior_per_device(hdev);
if (timeout_locked)
hdev->timeout_jiffies = msecs_to_jiffies(timeout_locked * 1000);
@@ -220,17 +235,6 @@ int create_hdev(struct hl_device **dev, struct pci_dev *pdev,
hdev->disabled = true;
hdev->pdev = pdev; /* can be NULL in case of simulator device */
- if (pdev) {
- hdev->asic_type = get_asic_type(pdev->device);
- if (hdev->asic_type == ASIC_INVALID) {
- dev_err(&pdev->dev, "Unsupported ASIC\n");
- rc = -ENODEV;
- goto free_hdev;
- }
- } else {
- hdev->asic_type = asic_type;
- }
-
/* Set default DMA mask to 32 bits */
hdev->dma_mask = 32;
diff --git a/drivers/misc/habanalabs/habanalabs_ioctl.c b/drivers/misc/habanalabs/habanalabs_ioctl.c
index eeefb22023e9..07127576b3e8 100644
--- a/drivers/misc/habanalabs/habanalabs_ioctl.c
+++ b/drivers/misc/habanalabs/habanalabs_ioctl.c
@@ -119,7 +119,8 @@ static int hw_idle(struct hl_device *hdev, struct hl_info_args *args)
if ((!max_size) || (!out))
return -EINVAL;
- hw_idle.is_idle = hdev->asic_funcs->is_device_idle(hdev, NULL, 0);
+ hw_idle.is_idle = hdev->asic_funcs->is_device_idle(hdev,
+ &hw_idle.busy_engines_mask, NULL);
return copy_to_user(out, &hw_idle,
min((size_t) max_size, sizeof(hw_idle))) ? -EFAULT : 0;
@@ -140,7 +141,7 @@ static int debug_coresight(struct hl_device *hdev, struct hl_debug_args *args)
params->op = args->op;
if (args->input_ptr && args->input_size) {
- input = memdup_user((const void __user *) args->input_ptr,
+ input = memdup_user(u64_to_user_ptr(args->input_ptr),
args->input_size);
if (IS_ERR(input)) {
rc = PTR_ERR(input);
@@ -254,10 +255,18 @@ static int hl_debug_ioctl(struct hl_fpriv *hpriv, void *data)
case HL_DEBUG_OP_BMON:
case HL_DEBUG_OP_SPMU:
case HL_DEBUG_OP_TIMESTAMP:
+ if (!hdev->in_debug) {
+ dev_err_ratelimited(hdev->dev,
+ "Rejecting debug configuration request because device not in debug mode\n");
+ return -EFAULT;
+ }
args->input_size =
min(args->input_size, hl_debug_struct_size[args->op]);
rc = debug_coresight(hdev, args);
break;
+ case HL_DEBUG_OP_SET_MODE:
+ rc = hl_device_set_debug_mode(hdev, (bool) args->enable);
+ break;
default:
dev_err(hdev->dev, "Invalid request %d\n", args->op);
rc = -ENOTTY;
diff --git a/drivers/misc/habanalabs/hw_queue.c b/drivers/misc/habanalabs/hw_queue.c
index 2894d8975933..e3b5517897ea 100644
--- a/drivers/misc/habanalabs/hw_queue.c
+++ b/drivers/misc/habanalabs/hw_queue.c
@@ -265,7 +265,7 @@ static void ext_hw_queue_schedule_job(struct hl_cs_job *job)
cq = &hdev->completion_queue[q->hw_queue_id];
cq_addr = cq->bus_address + cq->pi * sizeof(struct hl_cq_entry);
- hdev->asic_funcs->add_end_of_cb_packets(cb->kernel_address, len,
+ hdev->asic_funcs->add_end_of_cb_packets(hdev, cb->kernel_address, len,
cq_addr,
__le32_to_cpu(cq_pkt.data),
q->hw_queue_id);
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/dma_ch_0_masks.h b/drivers/misc/habanalabs/include/goya/asic_reg/dma_ch_0_masks.h
new file mode 100644
index 000000000000..028143408401
--- /dev/null
+++ b/drivers/misc/habanalabs/include/goya/asic_reg/dma_ch_0_masks.h
@@ -0,0 +1,418 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright 2016-2018 HabanaLabs, Ltd.
+ * All Rights Reserved.
+ *
+ */
+
+/************************************
+ ** This is an auto-generated file **
+ ** DO NOT EDIT BELOW **
+ ************************************/
+
+#ifndef ASIC_REG_DMA_CH_0_MASKS_H_
+#define ASIC_REG_DMA_CH_0_MASKS_H_
+
+/*
+ *****************************************
+ * DMA_CH_0 (Prototype: DMA_CH)
+ *****************************************
+ */
+
+/* DMA_CH_0_CFG0 */
+#define DMA_CH_0_CFG0_RD_MAX_OUTSTAND_SHIFT 0
+#define DMA_CH_0_CFG0_RD_MAX_OUTSTAND_MASK 0x3FF
+#define DMA_CH_0_CFG0_WR_MAX_OUTSTAND_SHIFT 16
+#define DMA_CH_0_CFG0_WR_MAX_OUTSTAND_MASK 0xFFF0000
+
+/* DMA_CH_0_CFG1 */
+#define DMA_CH_0_CFG1_RD_BUF_MAX_SIZE_SHIFT 0
+#define DMA_CH_0_CFG1_RD_BUF_MAX_SIZE_MASK 0x3FF
+
+/* DMA_CH_0_ERRMSG_ADDR_LO */
+#define DMA_CH_0_ERRMSG_ADDR_LO_VAL_SHIFT 0
+#define DMA_CH_0_ERRMSG_ADDR_LO_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_ERRMSG_ADDR_HI */
+#define DMA_CH_0_ERRMSG_ADDR_HI_VAL_SHIFT 0
+#define DMA_CH_0_ERRMSG_ADDR_HI_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_ERRMSG_WDATA */
+#define DMA_CH_0_ERRMSG_WDATA_VAL_SHIFT 0
+#define DMA_CH_0_ERRMSG_WDATA_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_RD_COMP_ADDR_LO */
+#define DMA_CH_0_RD_COMP_ADDR_LO_VAL_SHIFT 0
+#define DMA_CH_0_RD_COMP_ADDR_LO_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_RD_COMP_ADDR_HI */
+#define DMA_CH_0_RD_COMP_ADDR_HI_VAL_SHIFT 0
+#define DMA_CH_0_RD_COMP_ADDR_HI_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_RD_COMP_WDATA */
+#define DMA_CH_0_RD_COMP_WDATA_VAL_SHIFT 0
+#define DMA_CH_0_RD_COMP_WDATA_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_WR_COMP_ADDR_LO */
+#define DMA_CH_0_WR_COMP_ADDR_LO_VAL_SHIFT 0
+#define DMA_CH_0_WR_COMP_ADDR_LO_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_WR_COMP_ADDR_HI */
+#define DMA_CH_0_WR_COMP_ADDR_HI_VAL_SHIFT 0
+#define DMA_CH_0_WR_COMP_ADDR_HI_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_WR_COMP_WDATA */
+#define DMA_CH_0_WR_COMP_WDATA_VAL_SHIFT 0
+#define DMA_CH_0_WR_COMP_WDATA_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_LDMA_SRC_ADDR_LO */
+#define DMA_CH_0_LDMA_SRC_ADDR_LO_VAL_SHIFT 0
+#define DMA_CH_0_LDMA_SRC_ADDR_LO_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_LDMA_SRC_ADDR_HI */
+#define DMA_CH_0_LDMA_SRC_ADDR_HI_VAL_SHIFT 0
+#define DMA_CH_0_LDMA_SRC_ADDR_HI_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_LDMA_DST_ADDR_LO */
+#define DMA_CH_0_LDMA_DST_ADDR_LO_VAL_SHIFT 0
+#define DMA_CH_0_LDMA_DST_ADDR_LO_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_LDMA_DST_ADDR_HI */
+#define DMA_CH_0_LDMA_DST_ADDR_HI_VAL_SHIFT 0
+#define DMA_CH_0_LDMA_DST_ADDR_HI_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_LDMA_TSIZE */
+#define DMA_CH_0_LDMA_TSIZE_VAL_SHIFT 0
+#define DMA_CH_0_LDMA_TSIZE_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_COMIT_TRANSFER */
+#define DMA_CH_0_COMIT_TRANSFER_PCI_UPS_WKORDR_SHIFT 0
+#define DMA_CH_0_COMIT_TRANSFER_PCI_UPS_WKORDR_MASK 0x1
+#define DMA_CH_0_COMIT_TRANSFER_RD_COMP_EN_SHIFT 1
+#define DMA_CH_0_COMIT_TRANSFER_RD_COMP_EN_MASK 0x2
+#define DMA_CH_0_COMIT_TRANSFER_WR_COMP_EN_SHIFT 2
+#define DMA_CH_0_COMIT_TRANSFER_WR_COMP_EN_MASK 0x4
+#define DMA_CH_0_COMIT_TRANSFER_NOSNOOP_SHIFT 3
+#define DMA_CH_0_COMIT_TRANSFER_NOSNOOP_MASK 0x8
+#define DMA_CH_0_COMIT_TRANSFER_SRC_ADDR_INC_DIS_SHIFT 4
+#define DMA_CH_0_COMIT_TRANSFER_SRC_ADDR_INC_DIS_MASK 0x10
+#define DMA_CH_0_COMIT_TRANSFER_DST_ADDR_INC_DIS_SHIFT 5
+#define DMA_CH_0_COMIT_TRANSFER_DST_ADDR_INC_DIS_MASK 0x20
+#define DMA_CH_0_COMIT_TRANSFER_MEM_SET_SHIFT 6
+#define DMA_CH_0_COMIT_TRANSFER_MEM_SET_MASK 0x40
+#define DMA_CH_0_COMIT_TRANSFER_MOD_TENSOR_SHIFT 15
+#define DMA_CH_0_COMIT_TRANSFER_MOD_TENSOR_MASK 0x8000
+#define DMA_CH_0_COMIT_TRANSFER_CTL_SHIFT 16
+#define DMA_CH_0_COMIT_TRANSFER_CTL_MASK 0xFFFF0000
+
+/* DMA_CH_0_STS0 */
+#define DMA_CH_0_STS0_DMA_BUSY_SHIFT 0
+#define DMA_CH_0_STS0_DMA_BUSY_MASK 0x1
+#define DMA_CH_0_STS0_RD_STS_CTX_FULL_SHIFT 1
+#define DMA_CH_0_STS0_RD_STS_CTX_FULL_MASK 0x2
+#define DMA_CH_0_STS0_WR_STS_CTX_FULL_SHIFT 2
+#define DMA_CH_0_STS0_WR_STS_CTX_FULL_MASK 0x4
+
+/* DMA_CH_0_STS1 */
+#define DMA_CH_0_STS1_RD_STS_CTX_CNT_SHIFT 0
+#define DMA_CH_0_STS1_RD_STS_CTX_CNT_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_STS2 */
+#define DMA_CH_0_STS2_WR_STS_CTX_CNT_SHIFT 0
+#define DMA_CH_0_STS2_WR_STS_CTX_CNT_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_STS3 */
+#define DMA_CH_0_STS3_RD_STS_TRN_CNT_SHIFT 0
+#define DMA_CH_0_STS3_RD_STS_TRN_CNT_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_STS4 */
+#define DMA_CH_0_STS4_WR_STS_TRN_CNT_SHIFT 0
+#define DMA_CH_0_STS4_WR_STS_TRN_CNT_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_SRC_ADDR_LO_STS */
+#define DMA_CH_0_SRC_ADDR_LO_STS_VAL_SHIFT 0
+#define DMA_CH_0_SRC_ADDR_LO_STS_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_SRC_ADDR_HI_STS */
+#define DMA_CH_0_SRC_ADDR_HI_STS_VAL_SHIFT 0
+#define DMA_CH_0_SRC_ADDR_HI_STS_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_SRC_TSIZE_STS */
+#define DMA_CH_0_SRC_TSIZE_STS_VAL_SHIFT 0
+#define DMA_CH_0_SRC_TSIZE_STS_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_DST_ADDR_LO_STS */
+#define DMA_CH_0_DST_ADDR_LO_STS_VAL_SHIFT 0
+#define DMA_CH_0_DST_ADDR_LO_STS_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_DST_ADDR_HI_STS */
+#define DMA_CH_0_DST_ADDR_HI_STS_VAL_SHIFT 0
+#define DMA_CH_0_DST_ADDR_HI_STS_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_DST_TSIZE_STS */
+#define DMA_CH_0_DST_TSIZE_STS_VAL_SHIFT 0
+#define DMA_CH_0_DST_TSIZE_STS_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_RD_RATE_LIM_EN */
+#define DMA_CH_0_RD_RATE_LIM_EN_VAL_SHIFT 0
+#define DMA_CH_0_RD_RATE_LIM_EN_VAL_MASK 0x1
+
+/* DMA_CH_0_RD_RATE_LIM_RST_TOKEN */
+#define DMA_CH_0_RD_RATE_LIM_RST_TOKEN_VAL_SHIFT 0
+#define DMA_CH_0_RD_RATE_LIM_RST_TOKEN_VAL_MASK 0xFFFF
+
+/* DMA_CH_0_RD_RATE_LIM_SAT */
+#define DMA_CH_0_RD_RATE_LIM_SAT_VAL_SHIFT 0
+#define DMA_CH_0_RD_RATE_LIM_SAT_VAL_MASK 0xFFFF
+
+/* DMA_CH_0_RD_RATE_LIM_TOUT */
+#define DMA_CH_0_RD_RATE_LIM_TOUT_VAL_SHIFT 0
+#define DMA_CH_0_RD_RATE_LIM_TOUT_VAL_MASK 0x7FFFFFFF
+
+/* DMA_CH_0_WR_RATE_LIM_EN */
+#define DMA_CH_0_WR_RATE_LIM_EN_VAL_SHIFT 0
+#define DMA_CH_0_WR_RATE_LIM_EN_VAL_MASK 0x1
+
+/* DMA_CH_0_WR_RATE_LIM_RST_TOKEN */
+#define DMA_CH_0_WR_RATE_LIM_RST_TOKEN_VAL_SHIFT 0
+#define DMA_CH_0_WR_RATE_LIM_RST_TOKEN_VAL_MASK 0xFFFF
+
+/* DMA_CH_0_WR_RATE_LIM_SAT */
+#define DMA_CH_0_WR_RATE_LIM_SAT_VAL_SHIFT 0
+#define DMA_CH_0_WR_RATE_LIM_SAT_VAL_MASK 0xFFFF
+
+/* DMA_CH_0_WR_RATE_LIM_TOUT */
+#define DMA_CH_0_WR_RATE_LIM_TOUT_VAL_SHIFT 0
+#define DMA_CH_0_WR_RATE_LIM_TOUT_VAL_MASK 0x7FFFFFFF
+
+/* DMA_CH_0_CFG2 */
+#define DMA_CH_0_CFG2_FORCE_WORD_SHIFT 0
+#define DMA_CH_0_CFG2_FORCE_WORD_MASK 0x1
+
+/* DMA_CH_0_TDMA_CTL */
+#define DMA_CH_0_TDMA_CTL_DTYPE_SHIFT 0
+#define DMA_CH_0_TDMA_CTL_DTYPE_MASK 0x7
+
+/* DMA_CH_0_TDMA_SRC_BASE_ADDR_LO */
+#define DMA_CH_0_TDMA_SRC_BASE_ADDR_LO_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_SRC_BASE_ADDR_LO_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_BASE_ADDR_HI */
+#define DMA_CH_0_TDMA_SRC_BASE_ADDR_HI_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_SRC_BASE_ADDR_HI_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_ROI_BASE_0 */
+#define DMA_CH_0_TDMA_SRC_ROI_BASE_0_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_SRC_ROI_BASE_0_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_ROI_SIZE_0 */
+#define DMA_CH_0_TDMA_SRC_ROI_SIZE_0_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_SRC_ROI_SIZE_0_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_VALID_ELEMENTS_0 */
+#define DMA_CH_0_TDMA_SRC_VALID_ELEMENTS_0_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_SRC_VALID_ELEMENTS_0_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_START_OFFSET_0 */
+#define DMA_CH_0_TDMA_SRC_START_OFFSET_0_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_SRC_START_OFFSET_0_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_STRIDE_0 */
+#define DMA_CH_0_TDMA_SRC_STRIDE_0_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_SRC_STRIDE_0_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_ROI_BASE_1 */
+#define DMA_CH_0_TDMA_SRC_ROI_BASE_1_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_SRC_ROI_BASE_1_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_ROI_SIZE_1 */
+#define DMA_CH_0_TDMA_SRC_ROI_SIZE_1_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_SRC_ROI_SIZE_1_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_VALID_ELEMENTS_1 */
+#define DMA_CH_0_TDMA_SRC_VALID_ELEMENTS_1_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_SRC_VALID_ELEMENTS_1_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_START_OFFSET_1 */
+#define DMA_CH_0_TDMA_SRC_START_OFFSET_1_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_SRC_START_OFFSET_1_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_STRIDE_1 */
+#define DMA_CH_0_TDMA_SRC_STRIDE_1_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_SRC_STRIDE_1_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_ROI_BASE_2 */
+#define DMA_CH_0_TDMA_SRC_ROI_BASE_2_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_SRC_ROI_BASE_2_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_ROI_SIZE_2 */
+#define DMA_CH_0_TDMA_SRC_ROI_SIZE_2_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_SRC_ROI_SIZE_2_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_VALID_ELEMENTS_2 */
+#define DMA_CH_0_TDMA_SRC_VALID_ELEMENTS_2_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_SRC_VALID_ELEMENTS_2_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_START_OFFSET_2 */
+#define DMA_CH_0_TDMA_SRC_START_OFFSET_2_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_SRC_START_OFFSET_2_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_STRIDE_2 */
+#define DMA_CH_0_TDMA_SRC_STRIDE_2_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_SRC_STRIDE_2_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_ROI_BASE_3 */
+#define DMA_CH_0_TDMA_SRC_ROI_BASE_3_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_SRC_ROI_BASE_3_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_ROI_SIZE_3 */
+#define DMA_CH_0_TDMA_SRC_ROI_SIZE_3_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_SRC_ROI_SIZE_3_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_VALID_ELEMENTS_3 */
+#define DMA_CH_0_TDMA_SRC_VALID_ELEMENTS_3_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_SRC_VALID_ELEMENTS_3_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_START_OFFSET_3 */
+#define DMA_CH_0_TDMA_SRC_START_OFFSET_3_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_SRC_START_OFFSET_3_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_STRIDE_3 */
+#define DMA_CH_0_TDMA_SRC_STRIDE_3_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_SRC_STRIDE_3_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_ROI_BASE_4 */
+#define DMA_CH_0_TDMA_SRC_ROI_BASE_4_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_SRC_ROI_BASE_4_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_ROI_SIZE_4 */
+#define DMA_CH_0_TDMA_SRC_ROI_SIZE_4_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_SRC_ROI_SIZE_4_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_VALID_ELEMENTS_4 */
+#define DMA_CH_0_TDMA_SRC_VALID_ELEMENTS_4_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_SRC_VALID_ELEMENTS_4_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_START_OFFSET_4 */
+#define DMA_CH_0_TDMA_SRC_START_OFFSET_4_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_SRC_START_OFFSET_4_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_SRC_STRIDE_4 */
+#define DMA_CH_0_TDMA_SRC_STRIDE_4_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_SRC_STRIDE_4_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_BASE_ADDR_LO */
+#define DMA_CH_0_TDMA_DST_BASE_ADDR_LO_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_DST_BASE_ADDR_LO_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_BASE_ADDR_HI */
+#define DMA_CH_0_TDMA_DST_BASE_ADDR_HI_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_DST_BASE_ADDR_HI_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_ROI_BASE_0 */
+#define DMA_CH_0_TDMA_DST_ROI_BASE_0_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_DST_ROI_BASE_0_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_ROI_SIZE_0 */
+#define DMA_CH_0_TDMA_DST_ROI_SIZE_0_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_DST_ROI_SIZE_0_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_VALID_ELEMENTS_0 */
+#define DMA_CH_0_TDMA_DST_VALID_ELEMENTS_0_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_DST_VALID_ELEMENTS_0_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_START_OFFSET_0 */
+#define DMA_CH_0_TDMA_DST_START_OFFSET_0_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_DST_START_OFFSET_0_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_STRIDE_0 */
+#define DMA_CH_0_TDMA_DST_STRIDE_0_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_DST_STRIDE_0_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_ROI_BASE_1 */
+#define DMA_CH_0_TDMA_DST_ROI_BASE_1_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_DST_ROI_BASE_1_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_ROI_SIZE_1 */
+#define DMA_CH_0_TDMA_DST_ROI_SIZE_1_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_DST_ROI_SIZE_1_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_VALID_ELEMENTS_1 */
+#define DMA_CH_0_TDMA_DST_VALID_ELEMENTS_1_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_DST_VALID_ELEMENTS_1_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_START_OFFSET_1 */
+#define DMA_CH_0_TDMA_DST_START_OFFSET_1_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_DST_START_OFFSET_1_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_STRIDE_1 */
+#define DMA_CH_0_TDMA_DST_STRIDE_1_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_DST_STRIDE_1_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_ROI_BASE_2 */
+#define DMA_CH_0_TDMA_DST_ROI_BASE_2_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_DST_ROI_BASE_2_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_ROI_SIZE_2 */
+#define DMA_CH_0_TDMA_DST_ROI_SIZE_2_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_DST_ROI_SIZE_2_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_VALID_ELEMENTS_2 */
+#define DMA_CH_0_TDMA_DST_VALID_ELEMENTS_2_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_DST_VALID_ELEMENTS_2_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_START_OFFSET_2 */
+#define DMA_CH_0_TDMA_DST_START_OFFSET_2_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_DST_START_OFFSET_2_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_STRIDE_2 */
+#define DMA_CH_0_TDMA_DST_STRIDE_2_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_DST_STRIDE_2_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_ROI_BASE_3 */
+#define DMA_CH_0_TDMA_DST_ROI_BASE_3_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_DST_ROI_BASE_3_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_ROI_SIZE_3 */
+#define DMA_CH_0_TDMA_DST_ROI_SIZE_3_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_DST_ROI_SIZE_3_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_VALID_ELEMENTS_3 */
+#define DMA_CH_0_TDMA_DST_VALID_ELEMENTS_3_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_DST_VALID_ELEMENTS_3_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_START_OFFSET_3 */
+#define DMA_CH_0_TDMA_DST_START_OFFSET_3_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_DST_START_OFFSET_3_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_STRIDE_3 */
+#define DMA_CH_0_TDMA_DST_STRIDE_3_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_DST_STRIDE_3_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_ROI_BASE_4 */
+#define DMA_CH_0_TDMA_DST_ROI_BASE_4_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_DST_ROI_BASE_4_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_ROI_SIZE_4 */
+#define DMA_CH_0_TDMA_DST_ROI_SIZE_4_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_DST_ROI_SIZE_4_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_VALID_ELEMENTS_4 */
+#define DMA_CH_0_TDMA_DST_VALID_ELEMENTS_4_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_DST_VALID_ELEMENTS_4_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_START_OFFSET_4 */
+#define DMA_CH_0_TDMA_DST_START_OFFSET_4_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_DST_START_OFFSET_4_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_TDMA_DST_STRIDE_4 */
+#define DMA_CH_0_TDMA_DST_STRIDE_4_VAL_SHIFT 0
+#define DMA_CH_0_TDMA_DST_STRIDE_4_VAL_MASK 0xFFFFFFFF
+
+/* DMA_CH_0_MEM_INIT_BUSY */
+#define DMA_CH_0_MEM_INIT_BUSY_SBC_DATA_SHIFT 0
+#define DMA_CH_0_MEM_INIT_BUSY_SBC_DATA_MASK 0xFF
+#define DMA_CH_0_MEM_INIT_BUSY_SBC_MD_SHIFT 8
+#define DMA_CH_0_MEM_INIT_BUSY_SBC_MD_MASK 0x100
+
+#endif /* ASIC_REG_DMA_CH_0_MASKS_H_ */
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/goya_regs.h b/drivers/misc/habanalabs/include/goya/asic_reg/goya_regs.h
index 506e71e201e1..19b0f0ef1d0b 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/goya_regs.h
+++ b/drivers/misc/habanalabs/include/goya/asic_reg/goya_regs.h
@@ -88,6 +88,7 @@
#include "psoc_global_conf_masks.h"
#include "dma_macro_masks.h"
#include "dma_qm_0_masks.h"
+#include "dma_ch_0_masks.h"
#include "tpc0_qm_masks.h"
#include "tpc0_cmdq_masks.h"
#include "mme_qm_masks.h"
diff --git a/drivers/misc/habanalabs/memory.c b/drivers/misc/habanalabs/memory.c
index 693877e37fd8..42d237cae1dc 100644
--- a/drivers/misc/habanalabs/memory.c
+++ b/drivers/misc/habanalabs/memory.c
@@ -1657,17 +1657,10 @@ int hl_vm_init(struct hl_device *hdev)
struct hl_vm *vm = &hdev->vm;
int rc;
- rc = hl_mmu_init(hdev);
- if (rc) {
- dev_err(hdev->dev, "Failed to init MMU\n");
- return rc;
- }
-
vm->dram_pg_pool = gen_pool_create(__ffs(prop->dram_page_size), -1);
if (!vm->dram_pg_pool) {
dev_err(hdev->dev, "Failed to create dram page pool\n");
- rc = -ENOMEM;
- goto pool_create_err;
+ return -ENOMEM;
}
kref_init(&vm->dram_pg_pool_refcount);
@@ -1693,8 +1686,6 @@ int hl_vm_init(struct hl_device *hdev)
pool_add_err:
gen_pool_destroy(vm->dram_pg_pool);
-pool_create_err:
- hl_mmu_fini(hdev);
return rc;
}
@@ -1724,7 +1715,5 @@ void hl_vm_fini(struct hl_device *hdev)
dev_warn(hdev->dev, "dram_pg_pool was not destroyed on %s\n",
__func__);
- hl_mmu_fini(hdev);
-
vm->init_done = false;
}
diff --git a/drivers/misc/habanalabs/mmu.c b/drivers/misc/habanalabs/mmu.c
index 10aee3141444..176c315836f1 100644
--- a/drivers/misc/habanalabs/mmu.c
+++ b/drivers/misc/habanalabs/mmu.c
@@ -241,8 +241,9 @@ static int dram_default_mapping_init(struct hl_ctx *ctx)
hop2_pte_addr, hop3_pte_addr, pte_val;
int rc, i, j, hop3_allocated = 0;
- if (!hdev->dram_supports_virtual_memory ||
- !hdev->dram_default_page_mapping)
+ if ((!hdev->dram_supports_virtual_memory) ||
+ (!hdev->dram_default_page_mapping) ||
+ (ctx->asid == HL_KERNEL_ASID_ID))
return 0;
num_of_hop3 = prop->dram_size_for_default_page_mapping;
@@ -340,8 +341,9 @@ static void dram_default_mapping_fini(struct hl_ctx *ctx)
hop2_pte_addr, hop3_pte_addr;
int i, j;
- if (!hdev->dram_supports_virtual_memory ||
- !hdev->dram_default_page_mapping)
+ if ((!hdev->dram_supports_virtual_memory) ||
+ (!hdev->dram_default_page_mapping) ||
+ (ctx->asid == HL_KERNEL_ASID_ID))
return;
num_of_hop3 = prop->dram_size_for_default_page_mapping;
@@ -385,12 +387,8 @@ static void dram_default_mapping_fini(struct hl_ctx *ctx)
* @hdev: habanalabs device structure.
*
* This function does the following:
- * - Allocate max_asid zeroed hop0 pgts so no mapping is available.
- * - Enable MMU in H/W.
- * - Invalidate the MMU cache.
* - Create a pool of pages for pgt_infos.
- *
- * This function depends on DMA QMAN to be working!
+ * - Create a shadow table for pgt
*
* Return: 0 for success, non-zero for failure.
*/
@@ -915,6 +913,10 @@ int hl_mmu_map(struct hl_ctx *ctx, u64 virt_addr, u64 phys_addr, u32 page_size)
return -EFAULT;
}
+ WARN_ONCE((phys_addr & (real_page_size - 1)),
+ "Mapping 0x%llx with page size of 0x%x is erroneous! Address must be divisible by page size",
+ phys_addr, real_page_size);
+
npages = page_size / real_page_size;
real_virt_addr = virt_addr;
real_phys_addr = phys_addr;
diff --git a/drivers/misc/habanalabs/pci.c b/drivers/misc/habanalabs/pci.c
index 0e78a04d63f4..c98d88c7a5c6 100644
--- a/drivers/misc/habanalabs/pci.c
+++ b/drivers/misc/habanalabs/pci.c
@@ -10,6 +10,8 @@
#include <linux/pci.h>
+#define HL_PLDM_PCI_ELBI_TIMEOUT_MSEC (HL_PCI_ELBI_TIMEOUT_MSEC * 10)
+
/**
* hl_pci_bars_map() - Map PCI BARs.
* @hdev: Pointer to hl_device structure.
@@ -88,8 +90,14 @@ static int hl_pci_elbi_write(struct hl_device *hdev, u64 addr, u32 data)
{
struct pci_dev *pdev = hdev->pdev;
ktime_t timeout;
+ u64 msec;
u32 val;
+ if (hdev->pldm)
+ msec = HL_PLDM_PCI_ELBI_TIMEOUT_MSEC;
+ else
+ msec = HL_PCI_ELBI_TIMEOUT_MSEC;
+
/* Clear previous status */
pci_write_config_dword(pdev, mmPCI_CONFIG_ELBI_STS, 0);
@@ -98,7 +106,7 @@ static int hl_pci_elbi_write(struct hl_device *hdev, u64 addr, u32 data)
pci_write_config_dword(pdev, mmPCI_CONFIG_ELBI_CTRL,
PCI_CONFIG_ELBI_CTRL_WRITE);
- timeout = ktime_add_ms(ktime_get(), 10);
+ timeout = ktime_add_ms(ktime_get(), msec);
for (;;) {
pci_read_config_dword(pdev, mmPCI_CONFIG_ELBI_STS, &val);
if (val & PCI_CONFIG_ELBI_STS_MASK)
diff --git a/drivers/misc/habanalabs/sysfs.c b/drivers/misc/habanalabs/sysfs.c
index c900ab15cceb..25eb46d29d88 100644
--- a/drivers/misc/habanalabs/sysfs.c
+++ b/drivers/misc/habanalabs/sysfs.c
@@ -328,10 +328,6 @@ static ssize_t pci_addr_show(struct device *dev, struct device_attribute *attr,
{
struct hl_device *hdev = dev_get_drvdata(dev);
- /* Use dummy, fixed address for simulator */
- if (!hdev->pdev)
- return sprintf(buf, "0000:%02d:00.0\n", hdev->id);
-
return sprintf(buf, "%04x:%02x:%02x.%x\n",
pci_domain_nr(hdev->pdev->bus),
hdev->pdev->bus->number,
diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c
index 4989dcb2df14..35fec1bf1b3d 100644
--- a/drivers/misc/ibmasm/ibmasmfs.c
+++ b/drivers/misc/ibmasm/ibmasmfs.c
@@ -60,6 +60,7 @@
*/
#include <linux/fs.h>
+#include <linux/fs_context.h>
#include <linux/pagemap.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
@@ -74,13 +75,21 @@ static LIST_HEAD(service_processors);
static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode);
static void ibmasmfs_create_files (struct super_block *sb);
-static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent);
+static int ibmasmfs_fill_super(struct super_block *sb, struct fs_context *fc);
+static int ibmasmfs_get_tree(struct fs_context *fc)
+{
+ return get_tree_single(fc, ibmasmfs_fill_super);
+}
-static struct dentry *ibmasmfs_mount(struct file_system_type *fst,
- int flags, const char *name, void *data)
+static const struct fs_context_operations ibmasmfs_context_ops = {
+ .get_tree = ibmasmfs_get_tree,
+};
+
+static int ibmasmfs_init_fs_context(struct fs_context *fc)
{
- return mount_single(fst, flags, data, ibmasmfs_fill_super);
+ fc->ops = &ibmasmfs_context_ops;
+ return 0;
}
static const struct super_operations ibmasmfs_s_ops = {
@@ -93,12 +102,12 @@ static const struct file_operations *ibmasmfs_dir_ops = &simple_dir_operations;
static struct file_system_type ibmasmfs_type = {
.owner = THIS_MODULE,
.name = "ibmasmfs",
- .mount = ibmasmfs_mount,
+ .init_fs_context = ibmasmfs_init_fs_context,
.kill_sb = kill_litter_super,
};
MODULE_ALIAS_FS("ibmasmfs");
-static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent)
+static int ibmasmfs_fill_super(struct super_block *sb, struct fs_context *fc)
{
struct inode *root;
diff --git a/drivers/misc/isl29003.c b/drivers/misc/isl29003.c
index 3431a825f24e..c12406f610d5 100644
--- a/drivers/misc/isl29003.c
+++ b/drivers/misc/isl29003.c
@@ -3,7 +3,7 @@
* isl29003.c - Linux kernel module for
* Intersil ISL29003 ambient light sensor
*
- * See file:Documentation/misc-devices/isl29003
+ * See file:Documentation/misc-devices/isl29003.rst
*
* Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
*
@@ -377,7 +377,7 @@ static int isl29003_init_client(struct i2c_client *client)
static int isl29003_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adapter = client->adapter;
struct isl29003_data *data;
int err = 0;
diff --git a/drivers/misc/lis3lv02d/Kconfig b/drivers/misc/lis3lv02d/Kconfig
index 4cfad45229c8..bb2fec4b5880 100644
--- a/drivers/misc/lis3lv02d/Kconfig
+++ b/drivers/misc/lis3lv02d/Kconfig
@@ -7,7 +7,6 @@ config SENSORS_LIS3_SPI
tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (SPI)"
depends on !ACPI && SPI_MASTER && INPUT
select SENSORS_LIS3LV02D
- default n
help
This driver provides support for the LIS3LV02Dx accelerometer connected
via SPI. The accelerometer data is readable via
@@ -24,7 +23,6 @@ config SENSORS_LIS3_I2C
tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (I2C)"
depends on I2C && INPUT
select SENSORS_LIS3LV02D
- default n
help
This driver provides support for the LIS3LV02Dx accelerometer connected
via I2C. The accelerometer data is readable via
diff --git a/drivers/misc/lkdtm/Makefile b/drivers/misc/lkdtm/Makefile
index 951c984de61a..fb10eafe9bde 100644
--- a/drivers/misc/lkdtm/Makefile
+++ b/drivers/misc/lkdtm/Makefile
@@ -15,8 +15,7 @@ KCOV_INSTRUMENT_rodata.o := n
OBJCOPYFLAGS :=
OBJCOPYFLAGS_rodata_objcopy.o := \
- --set-section-flags .text=alloc,readonly \
- --rename-section .text=.rodata
+ --rename-section .text=.rodata,alloc,readonly,load
targets += rodata.o rodata_objcopy.o
$(obj)/rodata_objcopy.o: $(obj)/rodata.o FORCE
$(call if_changed,objcopy)
diff --git a/drivers/misc/lkdtm/bugs.c b/drivers/misc/lkdtm/bugs.c
index 17f839dee976..1606658b9b7e 100644
--- a/drivers/misc/lkdtm/bugs.c
+++ b/drivers/misc/lkdtm/bugs.c
@@ -236,7 +236,7 @@ void lkdtm_CORRUPT_USER_DS(void)
set_fs(KERNEL_DS);
/* Make sure we do not keep running with a KERNEL_DS! */
- force_sig(SIGKILL, current);
+ force_sig(SIGKILL);
}
/* Test that VMAP_STACK is actually allocating with a leading guard page */
@@ -266,3 +266,69 @@ void lkdtm_STACK_GUARD_PAGE_TRAILING(void)
pr_err("FAIL: accessed page after stack!\n");
}
+
+void lkdtm_UNSET_SMEP(void)
+{
+#ifdef CONFIG_X86_64
+#define MOV_CR4_DEPTH 64
+ void (*direct_write_cr4)(unsigned long val);
+ unsigned char *insn;
+ unsigned long cr4;
+ int i;
+
+ cr4 = native_read_cr4();
+
+ if ((cr4 & X86_CR4_SMEP) != X86_CR4_SMEP) {
+ pr_err("FAIL: SMEP not in use\n");
+ return;
+ }
+ cr4 &= ~(X86_CR4_SMEP);
+
+ pr_info("trying to clear SMEP normally\n");
+ native_write_cr4(cr4);
+ if (cr4 == native_read_cr4()) {
+ pr_err("FAIL: pinning SMEP failed!\n");
+ cr4 |= X86_CR4_SMEP;
+ pr_info("restoring SMEP\n");
+ native_write_cr4(cr4);
+ return;
+ }
+ pr_info("ok: SMEP did not get cleared\n");
+
+ /*
+ * To test the post-write pinning verification we need to call
+ * directly into the middle of native_write_cr4() where the
+ * cr4 write happens, skipping any pinning. This searches for
+ * the cr4 writing instruction.
+ */
+ insn = (unsigned char *)native_write_cr4;
+ for (i = 0; i < MOV_CR4_DEPTH; i++) {
+ /* mov %rdi, %cr4 */
+ if (insn[i] == 0x0f && insn[i+1] == 0x22 && insn[i+2] == 0xe7)
+ break;
+ /* mov %rdi,%rax; mov %rax, %cr4 */
+ if (insn[i] == 0x48 && insn[i+1] == 0x89 &&
+ insn[i+2] == 0xf8 && insn[i+3] == 0x0f &&
+ insn[i+4] == 0x22 && insn[i+5] == 0xe0)
+ break;
+ }
+ if (i >= MOV_CR4_DEPTH) {
+ pr_info("ok: cannot locate cr4 writing call gadget\n");
+ return;
+ }
+ direct_write_cr4 = (void *)(insn + i);
+
+ pr_info("trying to clear SMEP with call gadget\n");
+ direct_write_cr4(cr4);
+ if (native_read_cr4() & X86_CR4_SMEP) {
+ pr_info("ok: SMEP removal was reverted\n");
+ } else {
+ pr_err("FAIL: cleared SMEP not detected!\n");
+ cr4 |= X86_CR4_SMEP;
+ pr_info("restoring SMEP\n");
+ native_write_cr4(cr4);
+ }
+#else
+ pr_err("FAIL: this test is x86_64-only\n");
+#endif
+}
diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c
index 8a1428d4f138..66ae6b2a6950 100644
--- a/drivers/misc/lkdtm/core.c
+++ b/drivers/misc/lkdtm/core.c
@@ -15,7 +15,7 @@
*
* Debugfs support added by Simon Kagstrom <simon.kagstrom@netinsight.net>
*
- * See Documentation/fault-injection/provoke-crashes.txt for instructions
+ * See Documentation/fault-injection/provoke-crashes.rst for instructions
*/
#include "lkdtm.h"
#include <linux/fs.h>
@@ -114,12 +114,16 @@ static const struct crashtype crashtypes[] = {
CRASHTYPE(CORRUPT_USER_DS),
CRASHTYPE(STACK_GUARD_PAGE_LEADING),
CRASHTYPE(STACK_GUARD_PAGE_TRAILING),
+ CRASHTYPE(UNSET_SMEP),
CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE),
CRASHTYPE(OVERWRITE_ALLOCATION),
CRASHTYPE(WRITE_AFTER_FREE),
CRASHTYPE(READ_AFTER_FREE),
CRASHTYPE(WRITE_BUDDY_AFTER_FREE),
CRASHTYPE(READ_BUDDY_AFTER_FREE),
+ CRASHTYPE(SLAB_FREE_DOUBLE),
+ CRASHTYPE(SLAB_FREE_CROSS),
+ CRASHTYPE(SLAB_FREE_PAGE),
CRASHTYPE(SOFTLOCKUP),
CRASHTYPE(HARDLOCKUP),
CRASHTYPE(SPINLOCKUP),
@@ -387,7 +391,7 @@ static int __init lkdtm_module_init(void)
{
struct crashpoint *crashpoint = NULL;
const struct crashtype *crashtype = NULL;
- int ret = -EINVAL;
+ int ret;
int i;
/* Neither or both of these need to be set */
@@ -426,25 +430,17 @@ static int __init lkdtm_module_init(void)
lkdtm_bugs_init(&recur_count);
lkdtm_perms_init();
lkdtm_usercopy_init();
+ lkdtm_heap_init();
/* Register debugfs interface */
lkdtm_debugfs_root = debugfs_create_dir("provoke-crash", NULL);
- if (!lkdtm_debugfs_root) {
- pr_err("creating root dir failed\n");
- return -ENODEV;
- }
/* Install debugfs trigger files. */
for (i = 0; i < ARRAY_SIZE(crashpoints); i++) {
struct crashpoint *cur = &crashpoints[i];
- struct dentry *de;
- de = debugfs_create_file(cur->name, 0644, lkdtm_debugfs_root,
- cur, &cur->fops);
- if (de == NULL) {
- pr_err("could not create crashpoint %s\n", cur->name);
- goto out_err;
- }
+ debugfs_create_file(cur->name, 0644, lkdtm_debugfs_root, cur,
+ &cur->fops);
}
/* Install crashpoint if one was selected. */
@@ -472,6 +468,7 @@ static void __exit lkdtm_module_exit(void)
debugfs_remove_recursive(lkdtm_debugfs_root);
/* Handle test-specific clean-up. */
+ lkdtm_heap_exit();
lkdtm_usercopy_exit();
if (lkdtm_kprobe != NULL)
diff --git a/drivers/misc/lkdtm/heap.c b/drivers/misc/lkdtm/heap.c
index 65026d7de130..3c5cec85edce 100644
--- a/drivers/misc/lkdtm/heap.c
+++ b/drivers/misc/lkdtm/heap.c
@@ -7,6 +7,10 @@
#include <linux/slab.h>
#include <linux/sched.h>
+static struct kmem_cache *double_free_cache;
+static struct kmem_cache *a_cache;
+static struct kmem_cache *b_cache;
+
/*
* This tries to stay within the next largest power-of-2 kmalloc cache
* to avoid actually overwriting anything important if it's not detected
@@ -146,3 +150,71 @@ void lkdtm_READ_BUDDY_AFTER_FREE(void)
kfree(val);
}
+
+void lkdtm_SLAB_FREE_DOUBLE(void)
+{
+ int *val;
+
+ val = kmem_cache_alloc(double_free_cache, GFP_KERNEL);
+ if (!val) {
+ pr_info("Unable to allocate double_free_cache memory.\n");
+ return;
+ }
+
+ /* Just make sure we got real memory. */
+ *val = 0x12345678;
+ pr_info("Attempting double slab free ...\n");
+ kmem_cache_free(double_free_cache, val);
+ kmem_cache_free(double_free_cache, val);
+}
+
+void lkdtm_SLAB_FREE_CROSS(void)
+{
+ int *val;
+
+ val = kmem_cache_alloc(a_cache, GFP_KERNEL);
+ if (!val) {
+ pr_info("Unable to allocate a_cache memory.\n");
+ return;
+ }
+
+ /* Just make sure we got real memory. */
+ *val = 0x12345679;
+ pr_info("Attempting cross-cache slab free ...\n");
+ kmem_cache_free(b_cache, val);
+}
+
+void lkdtm_SLAB_FREE_PAGE(void)
+{
+ unsigned long p = __get_free_page(GFP_KERNEL);
+
+ pr_info("Attempting non-Slab slab free ...\n");
+ kmem_cache_free(NULL, (void *)p);
+ free_page(p);
+}
+
+/*
+ * We have constructors to keep the caches distinctly separated without
+ * needing to boot with "slab_nomerge".
+ */
+static void ctor_double_free(void *region)
+{ }
+static void ctor_a(void *region)
+{ }
+static void ctor_b(void *region)
+{ }
+
+void __init lkdtm_heap_init(void)
+{
+ double_free_cache = kmem_cache_create("lkdtm-heap-double_free",
+ 64, 0, 0, ctor_double_free);
+ a_cache = kmem_cache_create("lkdtm-heap-a", 64, 0, 0, ctor_a);
+ b_cache = kmem_cache_create("lkdtm-heap-b", 64, 0, 0, ctor_b);
+}
+
+void __exit lkdtm_heap_exit(void)
+{
+ kmem_cache_destroy(double_free_cache);
+ kmem_cache_destroy(a_cache);
+ kmem_cache_destroy(b_cache);
+}
diff --git a/drivers/misc/lkdtm/lkdtm.h b/drivers/misc/lkdtm/lkdtm.h
index 23dc565b4307..6a284a87a037 100644
--- a/drivers/misc/lkdtm/lkdtm.h
+++ b/drivers/misc/lkdtm/lkdtm.h
@@ -26,13 +26,19 @@ void lkdtm_CORRUPT_LIST_DEL(void);
void lkdtm_CORRUPT_USER_DS(void);
void lkdtm_STACK_GUARD_PAGE_LEADING(void);
void lkdtm_STACK_GUARD_PAGE_TRAILING(void);
+void lkdtm_UNSET_SMEP(void);
/* lkdtm_heap.c */
+void __init lkdtm_heap_init(void);
+void __exit lkdtm_heap_exit(void);
void lkdtm_OVERWRITE_ALLOCATION(void);
void lkdtm_WRITE_AFTER_FREE(void);
void lkdtm_READ_AFTER_FREE(void);
void lkdtm_WRITE_BUDDY_AFTER_FREE(void);
void lkdtm_READ_BUDDY_AFTER_FREE(void);
+void lkdtm_SLAB_FREE_DOUBLE(void);
+void lkdtm_SLAB_FREE_CROSS(void);
+void lkdtm_SLAB_FREE_PAGE(void);
/* lkdtm_perms.c */
void __init lkdtm_perms_init(void);
diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c
index 0970142bcace..a26c716c61a1 100644
--- a/drivers/misc/mei/debugfs.c
+++ b/drivers/misc/mei/debugfs.c
@@ -8,6 +8,7 @@
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/debugfs.h>
+#include <linux/seq_file.h>
#include <linux/mei.h>
@@ -15,104 +16,56 @@
#include "client.h"
#include "hw.h"
-static ssize_t mei_dbgfs_read_meclients(struct file *fp, char __user *ubuf,
- size_t cnt, loff_t *ppos)
+static int mei_dbgfs_meclients_show(struct seq_file *m, void *unused)
{
- struct mei_device *dev = fp->private_data;
+ struct mei_device *dev = m->private;
struct mei_me_client *me_cl;
- size_t bufsz = 1;
- char *buf;
int i = 0;
- int pos = 0;
- int ret;
-#define HDR \
-" |id|fix| UUID |con|msg len|sb|refc|\n"
+ if (!dev)
+ return -ENODEV;
down_read(&dev->me_clients_rwsem);
- list_for_each_entry(me_cl, &dev->me_clients, list)
- bufsz++;
-
- bufsz *= sizeof(HDR) + 1;
- buf = kzalloc(bufsz, GFP_KERNEL);
- if (!buf) {
- up_read(&dev->me_clients_rwsem);
- return -ENOMEM;
- }
- pos += scnprintf(buf + pos, bufsz - pos, HDR);
-#undef HDR
+ seq_puts(m, " |id|fix| UUID |con|msg len|sb|refc|\n");
/* if the driver is not enabled the list won't be consistent */
if (dev->dev_state != MEI_DEV_ENABLED)
goto out;
list_for_each_entry(me_cl, &dev->me_clients, list) {
-
- if (mei_me_cl_get(me_cl)) {
- pos += scnprintf(buf + pos, bufsz - pos,
- "%2d|%2d|%3d|%pUl|%3d|%7d|%2d|%4d|\n",
- i++, me_cl->client_id,
- me_cl->props.fixed_address,
- &me_cl->props.protocol_name,
- me_cl->props.max_number_of_connections,
- me_cl->props.max_msg_length,
- me_cl->props.single_recv_buf,
- kref_read(&me_cl->refcnt));
-
- mei_me_cl_put(me_cl);
- }
+ if (!mei_me_cl_get(me_cl))
+ continue;
+
+ seq_printf(m, "%2d|%2d|%3d|%pUl|%3d|%7d|%2d|%4d|\n",
+ i++, me_cl->client_id,
+ me_cl->props.fixed_address,
+ &me_cl->props.protocol_name,
+ me_cl->props.max_number_of_connections,
+ me_cl->props.max_msg_length,
+ me_cl->props.single_recv_buf,
+ kref_read(&me_cl->refcnt));
+ mei_me_cl_put(me_cl);
}
out:
up_read(&dev->me_clients_rwsem);
- ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos);
- kfree(buf);
- return ret;
+ return 0;
}
+DEFINE_SHOW_ATTRIBUTE(mei_dbgfs_meclients);
-static const struct file_operations mei_dbgfs_fops_meclients = {
- .open = simple_open,
- .read = mei_dbgfs_read_meclients,
- .llseek = generic_file_llseek,
-};
-
-static ssize_t mei_dbgfs_read_active(struct file *fp, char __user *ubuf,
- size_t cnt, loff_t *ppos)
+static int mei_dbgfs_active_show(struct seq_file *m, void *unused)
{
- struct mei_device *dev = fp->private_data;
+ struct mei_device *dev = m->private;
struct mei_cl *cl;
- size_t bufsz = 1;
- char *buf;
int i = 0;
- int pos = 0;
- int ret;
-
-#define HDR " |me|host|state|rd|wr|wrq\n"
if (!dev)
return -ENODEV;
mutex_lock(&dev->device_lock);
- /*
- * if the driver is not enabled the list won't be consistent,
- * we output empty table
- */
- if (dev->dev_state == MEI_DEV_ENABLED)
- list_for_each_entry(cl, &dev->file_list, link)
- bufsz++;
-
- bufsz *= sizeof(HDR) + 1;
-
- buf = kzalloc(bufsz, GFP_KERNEL);
- if (!buf) {
- mutex_unlock(&dev->device_lock);
- return -ENOMEM;
- }
-
- pos += scnprintf(buf + pos, bufsz - pos, HDR);
-#undef HDR
+ seq_puts(m, " |me|host|state|rd|wr|wrq\n");
/* if the driver is not enabled the list won't be consistent */
if (dev->dev_state != MEI_DEV_ENABLED)
@@ -120,76 +73,44 @@ static ssize_t mei_dbgfs_read_active(struct file *fp, char __user *ubuf,
list_for_each_entry(cl, &dev->file_list, link) {
- pos += scnprintf(buf + pos, bufsz - pos,
- "%3d|%2d|%4d|%5d|%2d|%2d|%3u\n",
- i, mei_cl_me_id(cl), cl->host_client_id, cl->state,
- !list_empty(&cl->rd_completed), cl->writing_state,
- cl->tx_cb_queued);
+ seq_printf(m, "%3d|%2d|%4d|%5d|%2d|%2d|%3u\n",
+ i, mei_cl_me_id(cl), cl->host_client_id, cl->state,
+ !list_empty(&cl->rd_completed), cl->writing_state,
+ cl->tx_cb_queued);
i++;
}
out:
mutex_unlock(&dev->device_lock);
- ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos);
- kfree(buf);
- return ret;
+ return 0;
}
+DEFINE_SHOW_ATTRIBUTE(mei_dbgfs_active);
-static const struct file_operations mei_dbgfs_fops_active = {
- .open = simple_open,
- .read = mei_dbgfs_read_active,
- .llseek = generic_file_llseek,
-};
-
-static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf,
- size_t cnt, loff_t *ppos)
+static int mei_dbgfs_devstate_show(struct seq_file *m, void *unused)
{
- struct mei_device *dev = fp->private_data;
- const size_t bufsz = 1024;
- char *buf = kzalloc(bufsz, GFP_KERNEL);
- int pos = 0;
- int ret;
-
- if (!buf)
- return -ENOMEM;
+ struct mei_device *dev = m->private;
- pos += scnprintf(buf + pos, bufsz - pos, "dev: %s\n",
- mei_dev_state_str(dev->dev_state));
- pos += scnprintf(buf + pos, bufsz - pos, "hbm: %s\n",
- mei_hbm_state_str(dev->hbm_state));
+ seq_printf(m, "dev: %s\n", mei_dev_state_str(dev->dev_state));
+ seq_printf(m, "hbm: %s\n", mei_hbm_state_str(dev->hbm_state));
if (dev->hbm_state >= MEI_HBM_ENUM_CLIENTS &&
dev->hbm_state <= MEI_HBM_STARTED) {
- pos += scnprintf(buf + pos, bufsz - pos, "hbm features:\n");
- pos += scnprintf(buf + pos, bufsz - pos, "\tPG: %01d\n",
- dev->hbm_f_pg_supported);
- pos += scnprintf(buf + pos, bufsz - pos, "\tDC: %01d\n",
- dev->hbm_f_dc_supported);
- pos += scnprintf(buf + pos, bufsz - pos, "\tIE: %01d\n",
- dev->hbm_f_ie_supported);
- pos += scnprintf(buf + pos, bufsz - pos, "\tDOT: %01d\n",
- dev->hbm_f_dot_supported);
- pos += scnprintf(buf + pos, bufsz - pos, "\tEV: %01d\n",
- dev->hbm_f_ev_supported);
- pos += scnprintf(buf + pos, bufsz - pos, "\tFA: %01d\n",
- dev->hbm_f_fa_supported);
- pos += scnprintf(buf + pos, bufsz - pos, "\tOS: %01d\n",
- dev->hbm_f_os_supported);
- pos += scnprintf(buf + pos, bufsz - pos, "\tDR: %01d\n",
- dev->hbm_f_dr_supported);
+ seq_puts(m, "hbm features:\n");
+ seq_printf(m, "\tPG: %01d\n", dev->hbm_f_pg_supported);
+ seq_printf(m, "\tDC: %01d\n", dev->hbm_f_dc_supported);
+ seq_printf(m, "\tIE: %01d\n", dev->hbm_f_ie_supported);
+ seq_printf(m, "\tDOT: %01d\n", dev->hbm_f_dot_supported);
+ seq_printf(m, "\tEV: %01d\n", dev->hbm_f_ev_supported);
+ seq_printf(m, "\tFA: %01d\n", dev->hbm_f_fa_supported);
+ seq_printf(m, "\tOS: %01d\n", dev->hbm_f_os_supported);
+ seq_printf(m, "\tDR: %01d\n", dev->hbm_f_dr_supported);
}
- pos += scnprintf(buf + pos, bufsz - pos, "pg: %s, %s\n",
- mei_pg_is_enabled(dev) ? "ENABLED" : "DISABLED",
- mei_pg_state_str(mei_pg_state(dev)));
- ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos);
- kfree(buf);
- return ret;
+ seq_printf(m, "pg: %s, %s\n",
+ mei_pg_is_enabled(dev) ? "ENABLED" : "DISABLED",
+ mei_pg_state_str(mei_pg_state(dev)));
+ return 0;
}
-static const struct file_operations mei_dbgfs_fops_devstate = {
- .open = simple_open,
- .read = mei_dbgfs_read_devstate,
- .llseek = generic_file_llseek,
-};
+DEFINE_SHOW_ATTRIBUTE(mei_dbgfs_devstate);
static ssize_t mei_dbgfs_write_allow_fa(struct file *file,
const char __user *user_buf,
@@ -208,7 +129,7 @@ static ssize_t mei_dbgfs_write_allow_fa(struct file *file,
return ret;
}
-static const struct file_operations mei_dbgfs_fops_allow_fa = {
+static const struct file_operations mei_dbgfs_allow_fa_fops = {
.open = simple_open,
.read = debugfs_read_file_bool,
.write = mei_dbgfs_write_allow_fa,
@@ -233,47 +154,21 @@ void mei_dbgfs_deregister(struct mei_device *dev)
*
* @dev: the mei device structure
* @name: the mei device name
- *
- * Return: 0 on success, <0 on failure.
*/
-int mei_dbgfs_register(struct mei_device *dev, const char *name)
+void mei_dbgfs_register(struct mei_device *dev, const char *name)
{
- struct dentry *dir, *f;
+ struct dentry *dir;
dir = debugfs_create_dir(name, NULL);
- if (!dir)
- return -ENOMEM;
-
dev->dbgfs_dir = dir;
- f = debugfs_create_file("meclients", S_IRUSR, dir,
- dev, &mei_dbgfs_fops_meclients);
- if (!f) {
- dev_err(dev->dev, "meclients: registration failed\n");
- goto err;
- }
- f = debugfs_create_file("active", S_IRUSR, dir,
- dev, &mei_dbgfs_fops_active);
- if (!f) {
- dev_err(dev->dev, "active: registration failed\n");
- goto err;
- }
- f = debugfs_create_file("devstate", S_IRUSR, dir,
- dev, &mei_dbgfs_fops_devstate);
- if (!f) {
- dev_err(dev->dev, "devstate: registration failed\n");
- goto err;
- }
- f = debugfs_create_file("allow_fixed_address", S_IRUSR | S_IWUSR, dir,
- &dev->allow_fixed_address,
- &mei_dbgfs_fops_allow_fa);
- if (!f) {
- dev_err(dev->dev, "allow_fixed_address: registration failed\n");
- goto err;
- }
- return 0;
-err:
- mei_dbgfs_deregister(dev);
- return -ENODEV;
+ debugfs_create_file("meclients", S_IRUSR, dir, dev,
+ &mei_dbgfs_meclients_fops);
+ debugfs_create_file("active", S_IRUSR, dir, dev,
+ &mei_dbgfs_active_fops);
+ debugfs_create_file("devstate", S_IRUSR, dir, dev,
+ &mei_dbgfs_devstate_fops);
+ debugfs_create_file("allow_fixed_address", S_IRUSR | S_IWUSR, dir,
+ &dev->allow_fixed_address,
+ &mei_dbgfs_allow_fa_fops);
}
-
diff --git a/drivers/misc/mei/hdcp/mei_hdcp.c b/drivers/misc/mei/hdcp/mei_hdcp.c
index 417865129407..c681f6fab342 100644
--- a/drivers/misc/mei/hdcp/mei_hdcp.c
+++ b/drivers/misc/mei/hdcp/mei_hdcp.c
@@ -2,7 +2,7 @@
/*
* Copyright © 2019 Intel Corporation
*
- * Mei_hdcp.c: HDCP client driver for mei bus
+ * mei_hdcp.c: HDCP client driver for mei bus
*
* Author:
* Ramalingam C <ramalingam.c@intel.com>
@@ -11,12 +11,9 @@
/**
* DOC: MEI_HDCP Client Driver
*
- * This is a client driver to the mei_bus to make the HDCP2.2 services of
- * ME FW available for the interested consumers like I915.
- *
- * This module will act as a translation layer between HDCP protocol
- * implementor(I915) and ME FW by translating HDCP2.2 authentication
- * messages to ME FW command payloads and vice versa.
+ * The mei_hdcp driver acts as a translation layer between HDCP 2.2
+ * protocol implementer (I915) and ME FW by translating HDCP2.2
+ * negotiation messages to ME FW command payloads and vice versa.
*/
#include <linux/module.h>
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index ad02097d7fee..f894d1f8a53e 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -984,16 +984,10 @@ int mei_register(struct mei_device *dev, struct device *parent)
goto err_dev_create;
}
- ret = mei_dbgfs_register(dev, dev_name(clsdev));
- if (ret) {
- dev_err(clsdev, "cannot register debugfs ret = %d\n", ret);
- goto err_dev_dbgfs;
- }
+ mei_dbgfs_register(dev, dev_name(clsdev));
return 0;
-err_dev_dbgfs:
- device_destroy(mei_class, devno);
err_dev_create:
cdev_del(&dev->cdev);
err_dev_add:
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index fca832fcac57..f71a023aed3c 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -718,13 +718,10 @@ bool mei_hbuf_acquire(struct mei_device *dev);
bool mei_write_is_idle(struct mei_device *dev);
#if IS_ENABLED(CONFIG_DEBUG_FS)
-int mei_dbgfs_register(struct mei_device *dev, const char *name);
+void mei_dbgfs_register(struct mei_device *dev, const char *name);
void mei_dbgfs_deregister(struct mei_device *dev);
#else
-static inline int mei_dbgfs_register(struct mei_device *dev, const char *name)
-{
- return 0;
-}
+static inline void mei_dbgfs_register(struct mei_device *dev, const char *name) {}
static inline void mei_dbgfs_deregister(struct mei_device *dev) {}
#endif /* CONFIG_DEBUG_FS */
diff --git a/drivers/misc/mic/card/mic_debugfs.c b/drivers/misc/mic/card/mic_debugfs.c
index bf7a60ccc66c..3ee3d2402634 100644
--- a/drivers/misc/mic/card/mic_debugfs.c
+++ b/drivers/misc/mic/card/mic_debugfs.c
@@ -51,25 +51,13 @@ DEFINE_SHOW_ATTRIBUTE(mic_intr);
*/
void __init mic_create_card_debug_dir(struct mic_driver *mdrv)
{
- struct dentry *d;
-
if (!mic_dbg)
return;
mdrv->dbg_dir = debugfs_create_dir(mdrv->name, mic_dbg);
- if (!mdrv->dbg_dir) {
- dev_err(mdrv->dev, "Cant create dbg_dir %s\n", mdrv->name);
- return;
- }
-
- d = debugfs_create_file("intr_test", 0444, mdrv->dbg_dir,
- mdrv, &mic_intr_fops);
- if (!d) {
- dev_err(mdrv->dev,
- "Cant create dbg intr_test %s\n", mdrv->name);
- return;
- }
+ debugfs_create_file("intr_test", 0444, mdrv->dbg_dir, mdrv,
+ &mic_intr_fops);
}
/**
@@ -89,8 +77,6 @@ void mic_delete_card_debug_dir(struct mic_driver *mdrv)
void __init mic_init_card_debugfs(void)
{
mic_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL);
- if (!mic_dbg)
- pr_err("can't create debugfs dir\n");
}
/**
diff --git a/drivers/misc/mic/cosm/cosm_debugfs.c b/drivers/misc/mic/cosm/cosm_debugfs.c
index 8e3f4589f16d..2fc9f4bf7001 100644
--- a/drivers/misc/mic/cosm/cosm_debugfs.c
+++ b/drivers/misc/mic/cosm/cosm_debugfs.c
@@ -93,8 +93,6 @@ void cosm_create_debug_dir(struct cosm_device *cdev)
scnprintf(name, sizeof(name), "mic%d", cdev->index);
cdev->dbg_dir = debugfs_create_dir(name, cosm_dbg);
- if (!cdev->dbg_dir)
- return;
debugfs_create_file("log_buf", 0444, cdev->dbg_dir, cdev,
&log_buf_fops);
@@ -113,8 +111,6 @@ void cosm_delete_debug_dir(struct cosm_device *cdev)
void cosm_init_debugfs(void)
{
cosm_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL);
- if (!cosm_dbg)
- pr_err("can't create debugfs dir\n");
}
void cosm_exit_debugfs(void)
diff --git a/drivers/misc/mic/host/mic_debugfs.c b/drivers/misc/mic/host/mic_debugfs.c
index 7ef8efe9552f..8a8e41677501 100644
--- a/drivers/misc/mic/host/mic_debugfs.c
+++ b/drivers/misc/mic/host/mic_debugfs.c
@@ -113,8 +113,6 @@ void mic_create_debug_dir(struct mic_device *mdev)
scnprintf(name, sizeof(name), "mic%d", mdev->id);
mdev->dbg_dir = debugfs_create_dir(name, mic_dbg);
- if (!mdev->dbg_dir)
- return;
debugfs_create_file("smpt", 0444, mdev->dbg_dir, mdev,
&mic_smpt_fops);
@@ -143,8 +141,6 @@ void mic_delete_debug_dir(struct mic_device *mdev)
void __init mic_init_debugfs(void)
{
mic_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL);
- if (!mic_dbg)
- pr_err("can't create debugfs dir\n");
}
/**
diff --git a/drivers/misc/mic/scif/scif_debugfs.c b/drivers/misc/mic/scif/scif_debugfs.c
index a6820480105a..8fe38e7ca6e6 100644
--- a/drivers/misc/mic/scif/scif_debugfs.c
+++ b/drivers/misc/mic/scif/scif_debugfs.c
@@ -103,11 +103,6 @@ DEFINE_SHOW_ATTRIBUTE(scif_rma);
void __init scif_init_debugfs(void)
{
scif_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL);
- if (!scif_dbg) {
- dev_err(scif_info.mdev.this_device,
- "can't create debugfs dir scif\n");
- return;
- }
debugfs_create_file("scif_dev", 0444, scif_dbg, NULL, &scif_dev_fops);
debugfs_create_file("scif_rma", 0444, scif_dbg, NULL, &scif_rma_fops);
diff --git a/drivers/misc/mic/scif/scif_main.c b/drivers/misc/mic/scif/scif_main.c
index 490e3bdc1941..e2278bf9f11d 100644
--- a/drivers/misc/mic/scif/scif_main.c
+++ b/drivers/misc/mic/scif/scif_main.c
@@ -133,6 +133,7 @@ static int scif_setup_scifdev(void)
static void scif_destroy_scifdev(void)
{
kfree(scif_dev);
+ scif_dev = NULL;
}
static int scif_probe(struct scif_hw_dev *sdev)
diff --git a/drivers/misc/mic/vop/vop_debugfs.c b/drivers/misc/mic/vop/vop_debugfs.c
index ed59cd75e182..9d4f175f4dd1 100644
--- a/drivers/misc/mic/vop/vop_debugfs.c
+++ b/drivers/misc/mic/vop/vop_debugfs.c
@@ -174,10 +174,6 @@ void vop_init_debugfs(struct vop_info *vi)
snprintf(name, sizeof(name), "%s%d", KBUILD_MODNAME, vi->vpdev->dnode);
vi->dbg = debugfs_create_dir(name, NULL);
- if (!vi->dbg) {
- pr_err("can't create debugfs dir vop\n");
- return;
- }
debugfs_create_file("dp", 0444, vi->dbg, vi, &vop_dp_fops);
debugfs_create_file("vdev_info", 0444, vi->dbg, vi, &vop_vdev_info_fops);
}
diff --git a/drivers/misc/ocxl/Kconfig b/drivers/misc/ocxl/Kconfig
index 7fb6d39d4c5a..1916fa65f2f2 100644
--- a/drivers/misc/ocxl/Kconfig
+++ b/drivers/misc/ocxl/Kconfig
@@ -5,7 +5,6 @@
config OCXL_BASE
bool
- default n
select PPC_COPRO_BASE
config OCXL
diff --git a/drivers/misc/ocxl/config.c b/drivers/misc/ocxl/config.c
index 5e65acb8e134..c8e19bfb5ef9 100644
--- a/drivers/misc/ocxl/config.c
+++ b/drivers/misc/ocxl/config.c
@@ -20,11 +20,14 @@
#define OCXL_DVSEC_TEMPL_MMIO_GLOBAL_SZ 0x28
#define OCXL_DVSEC_TEMPL_MMIO_PP 0x30
#define OCXL_DVSEC_TEMPL_MMIO_PP_SZ 0x38
-#define OCXL_DVSEC_TEMPL_MEM_SZ 0x3C
-#define OCXL_DVSEC_TEMPL_WWID 0x40
+#define OCXL_DVSEC_TEMPL_ALL_MEM_SZ 0x3C
+#define OCXL_DVSEC_TEMPL_LPC_MEM_START 0x40
+#define OCXL_DVSEC_TEMPL_WWID 0x48
+#define OCXL_DVSEC_TEMPL_LPC_MEM_SZ 0x58
#define OCXL_MAX_AFU_PER_FUNCTION 64
-#define OCXL_TEMPL_LEN 0x58
+#define OCXL_TEMPL_LEN_1_0 0x58
+#define OCXL_TEMPL_LEN_1_1 0x60
#define OCXL_TEMPL_NAME_LEN 24
#define OCXL_CFG_TIMEOUT 3
@@ -269,34 +272,72 @@ static int read_afu_info(struct pci_dev *dev, struct ocxl_fn_config *fn,
return 0;
}
+/**
+ * Read the template version from the AFU
+ * dev: the device for the AFU
+ * fn: the AFU offsets
+ * len: outputs the template length
+ * version: outputs the major<<8,minor version
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int read_template_version(struct pci_dev *dev, struct ocxl_fn_config *fn,
+ u16 *len, u16 *version)
+{
+ u32 val32;
+ u8 major, minor;
+ int rc;
+
+ rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_VERSION, &val32);
+ if (rc)
+ return rc;
+
+ *len = EXTRACT_BITS(val32, 16, 31);
+ major = EXTRACT_BITS(val32, 8, 15);
+ minor = EXTRACT_BITS(val32, 0, 7);
+ *version = (major << 8) + minor;
+ return 0;
+}
+
int ocxl_config_check_afu_index(struct pci_dev *dev,
struct ocxl_fn_config *fn, int afu_idx)
{
- u32 val;
- int rc, templ_major, templ_minor, len;
+ int rc;
+ u16 templ_version;
+ u16 len, expected_len;
pci_write_config_byte(dev,
fn->dvsec_afu_info_pos + OCXL_DVSEC_AFU_INFO_AFU_IDX,
afu_idx);
- rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_VERSION, &val);
+
+ rc = read_template_version(dev, fn, &len, &templ_version);
if (rc)
return rc;
- /* AFU index map can have holes */
- if (!val)
+ /* AFU index map can have holes, in which case we read all 0's */
+ if (!templ_version && !len)
return 0;
- templ_major = EXTRACT_BITS(val, 8, 15);
- templ_minor = EXTRACT_BITS(val, 0, 7);
dev_dbg(&dev->dev, "AFU descriptor template version %d.%d\n",
- templ_major, templ_minor);
-
- len = EXTRACT_BITS(val, 16, 31);
- if (len != OCXL_TEMPL_LEN) {
- dev_warn(&dev->dev,
- "Unexpected template length in AFU information (%#x)\n",
- len);
+ templ_version >> 8, templ_version & 0xFF);
+
+ switch (templ_version) {
+ case 0x0005: // v0.5 was used prior to the spec approval
+ case 0x0100:
+ expected_len = OCXL_TEMPL_LEN_1_0;
+ break;
+ case 0x0101:
+ expected_len = OCXL_TEMPL_LEN_1_1;
+ break;
+ default:
+ dev_warn(&dev->dev, "Unknown AFU template version %#x\n",
+ templ_version);
+ expected_len = len;
}
+ if (len != expected_len)
+ dev_warn(&dev->dev,
+ "Unexpected template length %#x in AFU information, expected %#x for version %#x\n",
+ len, expected_len, templ_version);
return 1;
}
@@ -434,6 +475,102 @@ static int validate_afu(struct pci_dev *dev, struct ocxl_afu_config *afu)
return 0;
}
+/**
+ * Populate AFU metadata regarding LPC memory
+ * dev: the device for the AFU
+ * fn: the AFU offsets
+ * afu: the AFU struct to populate the LPC metadata into
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int read_afu_lpc_memory_info(struct pci_dev *dev,
+ struct ocxl_fn_config *fn,
+ struct ocxl_afu_config *afu)
+{
+ int rc;
+ u32 val32;
+ u16 templ_version;
+ u16 templ_len;
+ u64 total_mem_size = 0;
+ u64 lpc_mem_size = 0;
+
+ afu->lpc_mem_offset = 0;
+ afu->lpc_mem_size = 0;
+ afu->special_purpose_mem_offset = 0;
+ afu->special_purpose_mem_size = 0;
+ /*
+ * For AFUs following template v1.0, the LPC memory covers the
+ * total memory. Its size is a power of 2.
+ *
+ * For AFUs with template >= v1.01, the total memory size is
+ * still a power of 2, but it is split in 2 parts:
+ * - the LPC memory, whose size can now be anything
+ * - the remainder memory is a special purpose memory, whose
+ * definition is AFU-dependent. It is not accessible through
+ * the usual commands for LPC memory
+ */
+ rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_ALL_MEM_SZ, &val32);
+ if (rc)
+ return rc;
+
+ val32 = EXTRACT_BITS(val32, 0, 7);
+ if (!val32)
+ return 0; /* No LPC memory */
+
+ /*
+ * The configuration space spec allows for a memory size of up
+ * to 2^255 bytes.
+ *
+ * Current generation hardware uses 56-bit physical addresses,
+ * but we won't be able to get near close to that, as we won't
+ * have a hole big enough in the memory map. Let it pass in
+ * the driver for now. We'll get an error from the firmware
+ * when trying to configure something too big.
+ */
+ total_mem_size = 1ull << val32;
+
+ rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_LPC_MEM_START, &val32);
+ if (rc)
+ return rc;
+
+ afu->lpc_mem_offset = val32;
+
+ rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_LPC_MEM_START + 4, &val32);
+ if (rc)
+ return rc;
+
+ afu->lpc_mem_offset |= (u64) val32 << 32;
+
+ rc = read_template_version(dev, fn, &templ_len, &templ_version);
+ if (rc)
+ return rc;
+
+ if (templ_version >= 0x0101) {
+ rc = read_afu_info(dev, fn,
+ OCXL_DVSEC_TEMPL_LPC_MEM_SZ, &val32);
+ if (rc)
+ return rc;
+ lpc_mem_size = val32;
+
+ rc = read_afu_info(dev, fn,
+ OCXL_DVSEC_TEMPL_LPC_MEM_SZ + 4, &val32);
+ if (rc)
+ return rc;
+ lpc_mem_size |= (u64) val32 << 32;
+ } else {
+ lpc_mem_size = total_mem_size;
+ }
+ afu->lpc_mem_size = lpc_mem_size;
+
+ if (lpc_mem_size < total_mem_size) {
+ afu->special_purpose_mem_offset =
+ afu->lpc_mem_offset + lpc_mem_size;
+ afu->special_purpose_mem_size =
+ total_mem_size - lpc_mem_size;
+ }
+ return 0;
+}
+
int ocxl_config_read_afu(struct pci_dev *dev, struct ocxl_fn_config *fn,
struct ocxl_afu_config *afu, u8 afu_idx)
{
@@ -467,10 +604,9 @@ int ocxl_config_read_afu(struct pci_dev *dev, struct ocxl_fn_config *fn,
if (rc)
return rc;
- rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_MEM_SZ, &val32);
+ rc = read_afu_lpc_memory_info(dev, fn, afu);
if (rc)
return rc;
- afu->log_mem_size = EXTRACT_BITS(val32, 0, 7);
rc = read_afu_control(dev, afu);
if (rc)
@@ -487,7 +623,12 @@ int ocxl_config_read_afu(struct pci_dev *dev, struct ocxl_fn_config *fn,
dev_dbg(&dev->dev, " pp mmio bar = %hhu\n", afu->pp_mmio_bar);
dev_dbg(&dev->dev, " pp mmio offset = %#llx\n", afu->pp_mmio_offset);
dev_dbg(&dev->dev, " pp mmio stride = %#x\n", afu->pp_mmio_stride);
- dev_dbg(&dev->dev, " mem size (log) = %hhu\n", afu->log_mem_size);
+ dev_dbg(&dev->dev, " lpc_mem offset = %#llx\n", afu->lpc_mem_offset);
+ dev_dbg(&dev->dev, " lpc_mem size = %#llx\n", afu->lpc_mem_size);
+ dev_dbg(&dev->dev, " special purpose mem offset = %#llx\n",
+ afu->special_purpose_mem_offset);
+ dev_dbg(&dev->dev, " special purpose mem size = %#llx\n",
+ afu->special_purpose_mem_size);
dev_dbg(&dev->dev, " pasid supported (log) = %u\n",
afu->pasid_supported_log);
dev_dbg(&dev->dev, " actag supported = %u\n",
diff --git a/drivers/misc/ocxl/context.c b/drivers/misc/ocxl/context.c
index bab9c9364184..994563a078eb 100644
--- a/drivers/misc/ocxl/context.c
+++ b/drivers/misc/ocxl/context.c
@@ -69,6 +69,7 @@ static void xsl_fault_error(void *data, u64 addr, u64 dsisr)
int ocxl_context_attach(struct ocxl_context *ctx, u64 amr, struct mm_struct *mm)
{
int rc;
+ unsigned long pidr = 0;
// Locks both status & tidr
mutex_lock(&ctx->status_mutex);
@@ -77,9 +78,11 @@ int ocxl_context_attach(struct ocxl_context *ctx, u64 amr, struct mm_struct *mm)
goto out;
}
- rc = ocxl_link_add_pe(ctx->afu->fn->link, ctx->pasid,
- mm->context.id, ctx->tidr, amr, mm,
- xsl_fault_error, ctx);
+ if (mm)
+ pidr = mm->context.id;
+
+ rc = ocxl_link_add_pe(ctx->afu->fn->link, ctx->pasid, pidr, ctx->tidr,
+ amr, mm, xsl_fault_error, ctx);
if (rc)
goto out;
diff --git a/drivers/misc/ocxl/link.c b/drivers/misc/ocxl/link.c
index cce5b0d64505..58d111afd9f6 100644
--- a/drivers/misc/ocxl/link.c
+++ b/drivers/misc/ocxl/link.c
@@ -224,6 +224,17 @@ static irqreturn_t xsl_fault_handler(int irq, void *data)
ack_irq(spa, ADDRESS_ERROR);
return IRQ_HANDLED;
}
+
+ if (!pe_data->mm) {
+ /*
+ * translation fault from a kernel context - an OpenCAPI
+ * device tried to access a bad kernel address
+ */
+ rcu_read_unlock();
+ pr_warn("Unresolved OpenCAPI xsl fault in kernel context\n");
+ ack_irq(spa, ADDRESS_ERROR);
+ return IRQ_HANDLED;
+ }
WARN_ON(pe_data->mm->context.id != pid);
if (mmget_not_zero(pe_data->mm)) {
@@ -523,7 +534,13 @@ int ocxl_link_add_pe(void *link_handle, int pasid, u32 pidr, u32 tidr,
pe->amr = cpu_to_be64(amr);
pe->software_state = cpu_to_be32(SPA_PE_VALID);
- mm_context_add_copro(mm);
+ /*
+ * For user contexts, register a copro so that TLBIs are seen
+ * by the nest MMU. If we have a kernel context, TLBIs are
+ * already global.
+ */
+ if (mm)
+ mm_context_add_copro(mm);
/*
* Barrier is to make sure PE is visible in the SPA before it
* is used by the device. It also helps with the global TLBI
@@ -546,7 +563,8 @@ int ocxl_link_add_pe(void *link_handle, int pasid, u32 pidr, u32 tidr,
* have a reference on mm_users. Incrementing mm_count solves
* the problem.
*/
- mmgrab(mm);
+ if (mm)
+ mmgrab(mm);
trace_ocxl_context_add(current->pid, spa->spa_mem, pasid, pidr, tidr);
unlock:
mutex_unlock(&spa->spa_lock);
@@ -652,8 +670,10 @@ int ocxl_link_remove_pe(void *link_handle, int pasid)
if (!pe_data) {
WARN(1, "Couldn't find pe data when removing PE\n");
} else {
- mm_context_remove_copro(pe_data->mm);
- mmdrop(pe_data->mm);
+ if (pe_data->mm) {
+ mm_context_remove_copro(pe_data->mm);
+ mmdrop(pe_data->mm);
+ }
kfree_rcu(pe_data, rcu);
}
unlock:
diff --git a/drivers/misc/ocxl/pci.c b/drivers/misc/ocxl/pci.c
index f2a3ef4b9bdd..cb920aa88d3a 100644
--- a/drivers/misc/ocxl/pci.c
+++ b/drivers/misc/ocxl/pci.c
@@ -41,7 +41,7 @@ static int ocxl_probe(struct pci_dev *dev, const struct pci_device_id *id)
return 0;
}
-void ocxl_remove(struct pci_dev *dev)
+static void ocxl_remove(struct pci_dev *dev)
{
struct ocxl_fn *fn;
struct ocxl_afu *afu;
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index 6765f10837ac..6e208a060a58 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -793,7 +793,7 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x) },
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA72x) },
{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0x81c0) },
- { PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, 0xedda) },
+ { PCI_DEVICE_DATA(SYNOPSYS, EDDA, NULL) },
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_AM654),
.driver_data = (kernel_ulong_t)&am654_data
},
diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c
index 3eba1c420cc0..782ce95d3f17 100644
--- a/drivers/misc/sgi-xp/xpc_partition.c
+++ b/drivers/misc/sgi-xp/xpc_partition.c
@@ -70,7 +70,7 @@ xpc_get_rsvd_page_pa(int nasid)
unsigned long rp_pa = nasid; /* seed with nasid */
size_t len = 0;
size_t buf_len = 0;
- void *buf = buf;
+ void *buf = NULL;
void *buf_base = NULL;
enum xp_retval (*get_partition_rsvd_page_pa)
(void *, u64 *, unsigned long *, size_t *) =
diff --git a/drivers/misc/sram.h b/drivers/misc/sram.h
index c181ce4c8fca..9c1d21ff7347 100644
--- a/drivers/misc/sram.h
+++ b/drivers/misc/sram.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Defines for the SRAM driver
- *
- * 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.
*/
#ifndef __SRAM_H
#define __SRAM_H
diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c
index 18ca938b86e6..a36ed1ff5967 100644
--- a/drivers/misc/ti-st/st_kim.c
+++ b/drivers/misc/ti-st/st_kim.c
@@ -748,10 +748,6 @@ static int kim_probe(struct platform_device *pdev)
pr_info("sysfs entries created\n");
kim_debugfs_dir = debugfs_create_dir("ti-st", NULL);
- if (!kim_debugfs_dir) {
- pr_err(" debugfs entries creation failed ");
- return 0;
- }
debugfs_create_file("version", S_IRUGO, kim_debugfs_dir,
kim_gdata, &version_fops);
diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c
index cc729f7ab32e..e6b40aa8fb42 100644
--- a/drivers/misc/tifm_7xx1.c
+++ b/drivers/misc/tifm_7xx1.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* tifm_7xx1.c - TI FlashMedia driver
*
* Copyright (C) 2006 Alex Dubov <oakad@yahoo.com>
- *
- * 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.
- *
*/
#include <linux/tifm.h>
diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c
index a511b2a713b3..667e574a7df2 100644
--- a/drivers/misc/tifm_core.c
+++ b/drivers/misc/tifm_core.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* tifm_core.c - TI FlashMedia driver
*
* Copyright (C) 2006 Alex Dubov <oakad@yahoo.com>
- *
- * 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.
- *
*/
#include <linux/tifm.h>
diff --git a/drivers/misc/tsl2550.c b/drivers/misc/tsl2550.c
index 5b7afd6190fe..09db397df287 100644
--- a/drivers/misc/tsl2550.c
+++ b/drivers/misc/tsl2550.c
@@ -336,7 +336,7 @@ static struct i2c_driver tsl2550_driver;
static int tsl2550_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adapter = client->adapter;
struct tsl2550_data *data;
int *opmode, err = 0;
diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c
index ad807d5a3141..8840299420e0 100644
--- a/drivers/misc/vmw_balloon.c
+++ b/drivers/misc/vmw_balloon.c
@@ -28,6 +28,9 @@
#include <linux/rwsem.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <linux/mount.h>
+#include <linux/pseudo_fs.h>
+#include <linux/balloon_compaction.h>
#include <linux/vmw_vmci_defs.h>
#include <linux/vmw_vmci_api.h>
#include <asm/hypervisor.h>
@@ -38,25 +41,20 @@ MODULE_ALIAS("dmi:*:svnVMware*:*");
MODULE_ALIAS("vmware_vmmemctl");
MODULE_LICENSE("GPL");
-/*
- * Use __GFP_HIGHMEM to allow pages from HIGHMEM zone. We don't allow wait
- * (__GFP_RECLAIM) for huge page allocations. Use __GFP_NOWARN, to suppress page
- * allocation failure warnings. Disallow access to emergency low-memory pools.
- */
-#define VMW_HUGE_PAGE_ALLOC_FLAGS (__GFP_HIGHMEM|__GFP_NOWARN| \
- __GFP_NOMEMALLOC)
+static bool __read_mostly vmwballoon_shrinker_enable;
+module_param(vmwballoon_shrinker_enable, bool, 0444);
+MODULE_PARM_DESC(vmwballoon_shrinker_enable,
+ "Enable non-cooperative out-of-memory protection. Disabled by default as it may degrade performance.");
-/*
- * Use __GFP_HIGHMEM to allow pages from HIGHMEM zone. We allow lightweight
- * reclamation (__GFP_NORETRY). Use __GFP_NOWARN, to suppress page allocation
- * failure warnings. Disallow access to emergency low-memory pools.
- */
-#define VMW_PAGE_ALLOC_FLAGS (__GFP_HIGHMEM|__GFP_NOWARN| \
- __GFP_NOMEMALLOC|__GFP_NORETRY)
+/* Delay in seconds after shrink before inflation. */
+#define VMBALLOON_SHRINK_DELAY (5)
/* Maximum number of refused pages we accumulate during inflation cycle */
#define VMW_BALLOON_MAX_REFUSED 16
+/* Magic number for the balloon mount-point */
+#define BALLOON_VMW_MAGIC 0x0ba11007
+
/*
* Hypervisor communication port definitions.
*/
@@ -229,29 +227,26 @@ enum vmballoon_stat_general {
VMW_BALLOON_STAT_TIMER,
VMW_BALLOON_STAT_DOORBELL,
VMW_BALLOON_STAT_RESET,
- VMW_BALLOON_STAT_LAST = VMW_BALLOON_STAT_RESET
+ VMW_BALLOON_STAT_SHRINK,
+ VMW_BALLOON_STAT_SHRINK_FREE,
+ VMW_BALLOON_STAT_LAST = VMW_BALLOON_STAT_SHRINK_FREE
};
#define VMW_BALLOON_STAT_NUM (VMW_BALLOON_STAT_LAST + 1)
-
static DEFINE_STATIC_KEY_TRUE(vmw_balloon_batching);
static DEFINE_STATIC_KEY_FALSE(balloon_stat_enabled);
struct vmballoon_ctl {
struct list_head pages;
struct list_head refused_pages;
+ struct list_head prealloc_pages;
unsigned int n_refused_pages;
unsigned int n_pages;
enum vmballoon_page_size_type page_size;
enum vmballoon_op op;
};
-struct vmballoon_page_size {
- /* list of reserved physical pages */
- struct list_head pages;
-};
-
/**
* struct vmballoon_batch_entry - a batch entry for lock or unlock.
*
@@ -266,8 +261,6 @@ struct vmballoon_batch_entry {
} __packed;
struct vmballoon {
- struct vmballoon_page_size page_sizes[VMW_BALLOON_NUM_PAGE_SIZES];
-
/**
* @max_page_size: maximum supported page size for ballooning.
*
@@ -340,6 +333,15 @@ struct vmballoon {
*/
struct page *page;
+ /**
+ * @shrink_timeout: timeout until the next inflation.
+ *
+ * After an shrink event, indicates the time in jiffies after which
+ * inflation is allowed again. Can be written concurrently with reads,
+ * so must use READ_ONCE/WRITE_ONCE when accessing.
+ */
+ unsigned long shrink_timeout;
+
/* statistics */
struct vmballoon_stats *stats;
@@ -348,9 +350,21 @@ struct vmballoon {
struct dentry *dbg_entry;
#endif
+ /**
+ * @b_dev_info: balloon device information descriptor.
+ */
+ struct balloon_dev_info b_dev_info;
+
struct delayed_work dwork;
/**
+ * @huge_pages - list of the inflated 2MB pages.
+ *
+ * Protected by @b_dev_info.pages_lock .
+ */
+ struct list_head huge_pages;
+
+ /**
* @vmci_doorbell.
*
* Protected by @conf_sem.
@@ -368,6 +382,20 @@ struct vmballoon {
* Lock ordering: @conf_sem -> @comm_lock .
*/
spinlock_t comm_lock;
+
+ /**
+ * @shrinker: shrinker interface that is used to avoid over-inflation.
+ */
+ struct shrinker shrinker;
+
+ /**
+ * @shrinker_registered: whether the shrinker was registered.
+ *
+ * The shrinker interface does not handle gracefully the removal of
+ * shrinker that was not registered before. This indication allows to
+ * simplify the unregistration process.
+ */
+ bool shrinker_registered;
};
static struct vmballoon balloon;
@@ -642,15 +670,25 @@ static int vmballoon_alloc_page_list(struct vmballoon *b,
unsigned int i;
for (i = 0; i < req_n_pages; i++) {
- if (ctl->page_size == VMW_BALLOON_2M_PAGE)
- page = alloc_pages(VMW_HUGE_PAGE_ALLOC_FLAGS,
- VMW_BALLOON_2M_ORDER);
- else
- page = alloc_page(VMW_PAGE_ALLOC_FLAGS);
-
- /* Update statistics */
- vmballoon_stats_page_inc(b, VMW_BALLOON_PAGE_STAT_ALLOC,
- ctl->page_size);
+ /*
+ * First check if we happen to have pages that were allocated
+ * before. This happens when 2MB page rejected during inflation
+ * by the hypervisor, and then split into 4KB pages.
+ */
+ if (!list_empty(&ctl->prealloc_pages)) {
+ page = list_first_entry(&ctl->prealloc_pages,
+ struct page, lru);
+ list_del(&page->lru);
+ } else {
+ if (ctl->page_size == VMW_BALLOON_2M_PAGE)
+ page = alloc_pages(__GFP_HIGHMEM|__GFP_NOWARN|
+ __GFP_NOMEMALLOC, VMW_BALLOON_2M_ORDER);
+ else
+ page = balloon_page_alloc();
+
+ vmballoon_stats_page_inc(b, VMW_BALLOON_PAGE_STAT_ALLOC,
+ ctl->page_size);
+ }
if (page) {
vmballoon_mark_page_offline(page, ctl->page_size);
@@ -896,7 +934,8 @@ static void vmballoon_release_page_list(struct list_head *page_list,
__free_pages(page, vmballoon_page_order(page_size));
}
- *n_pages = 0;
+ if (n_pages)
+ *n_pages = 0;
}
@@ -942,6 +981,10 @@ static int64_t vmballoon_change(struct vmballoon *b)
size - target < vmballoon_page_in_frames(VMW_BALLOON_2M_PAGE))
return 0;
+ /* If an out-of-memory recently occurred, inflation is disallowed. */
+ if (target > size && time_before(jiffies, READ_ONCE(b->shrink_timeout)))
+ return 0;
+
return target - size;
}
@@ -961,9 +1004,22 @@ static void vmballoon_enqueue_page_list(struct vmballoon *b,
unsigned int *n_pages,
enum vmballoon_page_size_type page_size)
{
- struct vmballoon_page_size *page_size_info = &b->page_sizes[page_size];
+ unsigned long flags;
+
+ if (page_size == VMW_BALLOON_4K_PAGE) {
+ balloon_page_list_enqueue(&b->b_dev_info, pages);
+ } else {
+ /*
+ * Keep the huge pages in a local list which is not available
+ * for the balloon compaction mechanism.
+ */
+ spin_lock_irqsave(&b->b_dev_info.pages_lock, flags);
+ list_splice_init(pages, &b->huge_pages);
+ __count_vm_events(BALLOON_INFLATE, *n_pages *
+ vmballoon_page_in_frames(VMW_BALLOON_2M_PAGE));
+ spin_unlock_irqrestore(&b->b_dev_info.pages_lock, flags);
+ }
- list_splice_init(pages, &page_size_info->pages);
*n_pages = 0;
}
@@ -986,19 +1042,58 @@ static void vmballoon_dequeue_page_list(struct vmballoon *b,
enum vmballoon_page_size_type page_size,
unsigned int n_req_pages)
{
- struct vmballoon_page_size *page_size_info = &b->page_sizes[page_size];
struct page *page, *tmp;
unsigned int i = 0;
+ unsigned long flags;
- list_for_each_entry_safe(page, tmp, &page_size_info->pages, lru) {
+ /* In the case of 4k pages, use the compaction infrastructure */
+ if (page_size == VMW_BALLOON_4K_PAGE) {
+ *n_pages = balloon_page_list_dequeue(&b->b_dev_info, pages,
+ n_req_pages);
+ return;
+ }
+
+ /* 2MB pages */
+ spin_lock_irqsave(&b->b_dev_info.pages_lock, flags);
+ list_for_each_entry_safe(page, tmp, &b->huge_pages, lru) {
list_move(&page->lru, pages);
if (++i == n_req_pages)
break;
}
+
+ __count_vm_events(BALLOON_DEFLATE,
+ i * vmballoon_page_in_frames(VMW_BALLOON_2M_PAGE));
+ spin_unlock_irqrestore(&b->b_dev_info.pages_lock, flags);
*n_pages = i;
}
/**
+ * vmballoon_split_refused_pages() - Split the 2MB refused pages to 4k.
+ *
+ * If inflation of 2MB pages was denied by the hypervisor, it is likely to be
+ * due to one or few 4KB pages. These 2MB pages may keep being allocated and
+ * then being refused. To prevent this case, this function splits the refused
+ * pages into 4KB pages and adds them into @prealloc_pages list.
+ *
+ * @ctl: pointer for the %struct vmballoon_ctl, which defines the operation.
+ */
+static void vmballoon_split_refused_pages(struct vmballoon_ctl *ctl)
+{
+ struct page *page, *tmp;
+ unsigned int i, order;
+
+ order = vmballoon_page_order(ctl->page_size);
+
+ list_for_each_entry_safe(page, tmp, &ctl->refused_pages, lru) {
+ list_del(&page->lru);
+ split_page(page, order);
+ for (i = 0; i < (1 << order); i++)
+ list_add(&page[i].lru, &ctl->prealloc_pages);
+ }
+ ctl->n_refused_pages = 0;
+}
+
+/**
* vmballoon_inflate() - Inflate the balloon towards its target size.
*
* @b: pointer to the balloon.
@@ -1009,6 +1104,7 @@ static void vmballoon_inflate(struct vmballoon *b)
struct vmballoon_ctl ctl = {
.pages = LIST_HEAD_INIT(ctl.pages),
.refused_pages = LIST_HEAD_INIT(ctl.refused_pages),
+ .prealloc_pages = LIST_HEAD_INIT(ctl.prealloc_pages),
.page_size = b->max_page_size,
.op = VMW_BALLOON_INFLATE
};
@@ -1056,10 +1152,10 @@ static void vmballoon_inflate(struct vmballoon *b)
break;
/*
- * Ignore errors from locking as we now switch to 4k
- * pages and we might get different errors.
+ * Split the refused pages to 4k. This will also empty
+ * the refused pages list.
*/
- vmballoon_release_refused_pages(b, &ctl);
+ vmballoon_split_refused_pages(&ctl);
ctl.page_size--;
}
@@ -1073,6 +1169,8 @@ static void vmballoon_inflate(struct vmballoon *b)
*/
if (ctl.n_refused_pages != 0)
vmballoon_release_refused_pages(b, &ctl);
+
+ vmballoon_release_page_list(&ctl.prealloc_pages, NULL, ctl.page_size);
}
/**
@@ -1411,6 +1509,90 @@ static void vmballoon_work(struct work_struct *work)
}
+/**
+ * vmballoon_shrinker_scan() - deflate the balloon due to memory pressure.
+ * @shrinker: pointer to the balloon shrinker.
+ * @sc: page reclaim information.
+ *
+ * Returns: number of pages that were freed during deflation.
+ */
+static unsigned long vmballoon_shrinker_scan(struct shrinker *shrinker,
+ struct shrink_control *sc)
+{
+ struct vmballoon *b = &balloon;
+ unsigned long deflated_frames;
+
+ pr_debug("%s - size: %llu", __func__, atomic64_read(&b->size));
+
+ vmballoon_stats_gen_inc(b, VMW_BALLOON_STAT_SHRINK);
+
+ /*
+ * If the lock is also contended for read, we cannot easily reclaim and
+ * we bail out.
+ */
+ if (!down_read_trylock(&b->conf_sem))
+ return 0;
+
+ deflated_frames = vmballoon_deflate(b, sc->nr_to_scan, true);
+
+ vmballoon_stats_gen_add(b, VMW_BALLOON_STAT_SHRINK_FREE,
+ deflated_frames);
+
+ /*
+ * Delay future inflation for some time to mitigate the situations in
+ * which balloon continuously grows and shrinks. Use WRITE_ONCE() since
+ * the access is asynchronous.
+ */
+ WRITE_ONCE(b->shrink_timeout, jiffies + HZ * VMBALLOON_SHRINK_DELAY);
+
+ up_read(&b->conf_sem);
+
+ return deflated_frames;
+}
+
+/**
+ * vmballoon_shrinker_count() - return the number of ballooned pages.
+ * @shrinker: pointer to the balloon shrinker.
+ * @sc: page reclaim information.
+ *
+ * Returns: number of 4k pages that are allocated for the balloon and can
+ * therefore be reclaimed under pressure.
+ */
+static unsigned long vmballoon_shrinker_count(struct shrinker *shrinker,
+ struct shrink_control *sc)
+{
+ struct vmballoon *b = &balloon;
+
+ return atomic64_read(&b->size);
+}
+
+static void vmballoon_unregister_shrinker(struct vmballoon *b)
+{
+ if (b->shrinker_registered)
+ unregister_shrinker(&b->shrinker);
+ b->shrinker_registered = false;
+}
+
+static int vmballoon_register_shrinker(struct vmballoon *b)
+{
+ int r;
+
+ /* Do nothing if the shrinker is not enabled */
+ if (!vmwballoon_shrinker_enable)
+ return 0;
+
+ b->shrinker.scan_objects = vmballoon_shrinker_scan;
+ b->shrinker.count_objects = vmballoon_shrinker_count;
+ b->shrinker.seeks = DEFAULT_SEEKS;
+
+ r = register_shrinker(&b->shrinker);
+
+ if (r == 0)
+ b->shrinker_registered = true;
+
+ return r;
+}
+
/*
* DEBUGFS Interface
*/
@@ -1428,6 +1610,8 @@ static const char * const vmballoon_stat_names[] = {
[VMW_BALLOON_STAT_TIMER] = "timer",
[VMW_BALLOON_STAT_DOORBELL] = "doorbell",
[VMW_BALLOON_STAT_RESET] = "reset",
+ [VMW_BALLOON_STAT_SHRINK] = "shrink",
+ [VMW_BALLOON_STAT_SHRINK_FREE] = "shrinkFree"
};
static int vmballoon_enable_stats(struct vmballoon *b)
@@ -1516,19 +1700,10 @@ static int vmballoon_debug_show(struct seq_file *f, void *offset)
DEFINE_SHOW_ATTRIBUTE(vmballoon_debug);
-static int __init vmballoon_debugfs_init(struct vmballoon *b)
+static void __init vmballoon_debugfs_init(struct vmballoon *b)
{
- int error;
-
b->dbg_entry = debugfs_create_file("vmmemctl", S_IRUGO, NULL, b,
&vmballoon_debug_fops);
- if (IS_ERR(b->dbg_entry)) {
- error = PTR_ERR(b->dbg_entry);
- pr_err("failed to create debugfs entry, error: %d\n", error);
- return error;
- }
-
- return 0;
}
static void __exit vmballoon_debugfs_exit(struct vmballoon *b)
@@ -1541,9 +1716,8 @@ static void __exit vmballoon_debugfs_exit(struct vmballoon *b)
#else
-static inline int vmballoon_debugfs_init(struct vmballoon *b)
+static inline void vmballoon_debugfs_init(struct vmballoon *b)
{
- return 0;
}
static inline void vmballoon_debugfs_exit(struct vmballoon *b)
@@ -1552,9 +1726,197 @@ static inline void vmballoon_debugfs_exit(struct vmballoon *b)
#endif /* CONFIG_DEBUG_FS */
+
+#ifdef CONFIG_BALLOON_COMPACTION
+
+static int vmballoon_init_fs_context(struct fs_context *fc)
+{
+ return init_pseudo(fc, BALLOON_VMW_MAGIC) ? 0 : -ENOMEM;
+}
+
+static struct file_system_type vmballoon_fs = {
+ .name = "balloon-vmware",
+ .init_fs_context = vmballoon_init_fs_context,
+ .kill_sb = kill_anon_super,
+};
+
+static struct vfsmount *vmballoon_mnt;
+
+/**
+ * vmballoon_migratepage() - migrates a balloon page.
+ * @b_dev_info: balloon device information descriptor.
+ * @newpage: the page to which @page should be migrated.
+ * @page: a ballooned page that should be migrated.
+ * @mode: migration mode, ignored.
+ *
+ * This function is really open-coded, but that is according to the interface
+ * that balloon_compaction provides.
+ *
+ * Return: zero on success, -EAGAIN when migration cannot be performed
+ * momentarily, and -EBUSY if migration failed and should be retried
+ * with that specific page.
+ */
+static int vmballoon_migratepage(struct balloon_dev_info *b_dev_info,
+ struct page *newpage, struct page *page,
+ enum migrate_mode mode)
+{
+ unsigned long status, flags;
+ struct vmballoon *b;
+ int ret;
+
+ b = container_of(b_dev_info, struct vmballoon, b_dev_info);
+
+ /*
+ * If the semaphore is taken, there is ongoing configuration change
+ * (i.e., balloon reset), so try again.
+ */
+ if (!down_read_trylock(&b->conf_sem))
+ return -EAGAIN;
+
+ spin_lock(&b->comm_lock);
+ /*
+ * We must start by deflating and not inflating, as otherwise the
+ * hypervisor may tell us that it has enough memory and the new page is
+ * not needed. Since the old page is isolated, we cannot use the list
+ * interface to unlock it, as the LRU field is used for isolation.
+ * Instead, we use the native interface directly.
+ */
+ vmballoon_add_page(b, 0, page);
+ status = vmballoon_lock_op(b, 1, VMW_BALLOON_4K_PAGE,
+ VMW_BALLOON_DEFLATE);
+
+ if (status == VMW_BALLOON_SUCCESS)
+ status = vmballoon_status_page(b, 0, &page);
+
+ /*
+ * If a failure happened, let the migration mechanism know that it
+ * should not retry.
+ */
+ if (status != VMW_BALLOON_SUCCESS) {
+ spin_unlock(&b->comm_lock);
+ ret = -EBUSY;
+ goto out_unlock;
+ }
+
+ /*
+ * The page is isolated, so it is safe to delete it without holding
+ * @pages_lock . We keep holding @comm_lock since we will need it in a
+ * second.
+ */
+ balloon_page_delete(page);
+
+ put_page(page);
+
+ /* Inflate */
+ vmballoon_add_page(b, 0, newpage);
+ status = vmballoon_lock_op(b, 1, VMW_BALLOON_4K_PAGE,
+ VMW_BALLOON_INFLATE);
+
+ if (status == VMW_BALLOON_SUCCESS)
+ status = vmballoon_status_page(b, 0, &newpage);
+
+ spin_unlock(&b->comm_lock);
+
+ if (status != VMW_BALLOON_SUCCESS) {
+ /*
+ * A failure happened. While we can deflate the page we just
+ * inflated, this deflation can also encounter an error. Instead
+ * we will decrease the size of the balloon to reflect the
+ * change and report failure.
+ */
+ atomic64_dec(&b->size);
+ ret = -EBUSY;
+ } else {
+ /*
+ * Success. Take a reference for the page, and we will add it to
+ * the list after acquiring the lock.
+ */
+ get_page(newpage);
+ ret = MIGRATEPAGE_SUCCESS;
+ }
+
+ /* Update the balloon list under the @pages_lock */
+ spin_lock_irqsave(&b->b_dev_info.pages_lock, flags);
+
+ /*
+ * On inflation success, we already took a reference for the @newpage.
+ * If we succeed just insert it to the list and update the statistics
+ * under the lock.
+ */
+ if (ret == MIGRATEPAGE_SUCCESS) {
+ balloon_page_insert(&b->b_dev_info, newpage);
+ __count_vm_event(BALLOON_MIGRATE);
+ }
+
+ /*
+ * We deflated successfully, so regardless to the inflation success, we
+ * need to reduce the number of isolated_pages.
+ */
+ b->b_dev_info.isolated_pages--;
+ spin_unlock_irqrestore(&b->b_dev_info.pages_lock, flags);
+
+out_unlock:
+ up_read(&b->conf_sem);
+ return ret;
+}
+
+/**
+ * vmballoon_compaction_deinit() - removes compaction related data.
+ *
+ * @b: pointer to the balloon.
+ */
+static void vmballoon_compaction_deinit(struct vmballoon *b)
+{
+ if (!IS_ERR(b->b_dev_info.inode))
+ iput(b->b_dev_info.inode);
+
+ b->b_dev_info.inode = NULL;
+ kern_unmount(vmballoon_mnt);
+ vmballoon_mnt = NULL;
+}
+
+/**
+ * vmballoon_compaction_init() - initialized compaction for the balloon.
+ *
+ * @b: pointer to the balloon.
+ *
+ * If during the initialization a failure occurred, this function does not
+ * perform cleanup. The caller must call vmballoon_compaction_deinit() in this
+ * case.
+ *
+ * Return: zero on success or error code on failure.
+ */
+static __init int vmballoon_compaction_init(struct vmballoon *b)
+{
+ vmballoon_mnt = kern_mount(&vmballoon_fs);
+ if (IS_ERR(vmballoon_mnt))
+ return PTR_ERR(vmballoon_mnt);
+
+ b->b_dev_info.migratepage = vmballoon_migratepage;
+ b->b_dev_info.inode = alloc_anon_inode(vmballoon_mnt->mnt_sb);
+
+ if (IS_ERR(b->b_dev_info.inode))
+ return PTR_ERR(b->b_dev_info.inode);
+
+ b->b_dev_info.inode->i_mapping->a_ops = &balloon_aops;
+ return 0;
+}
+
+#else /* CONFIG_BALLOON_COMPACTION */
+
+static void vmballoon_compaction_deinit(struct vmballoon *b)
+{
+}
+
+static int vmballoon_compaction_init(struct vmballoon *b)
+{
+ return 0;
+}
+
+#endif /* CONFIG_BALLOON_COMPACTION */
+
static int __init vmballoon_init(void)
{
- enum vmballoon_page_size_type page_size;
int error;
/*
@@ -1564,17 +1926,22 @@ static int __init vmballoon_init(void)
if (x86_hyper_type != X86_HYPER_VMWARE)
return -ENODEV;
- for (page_size = VMW_BALLOON_4K_PAGE;
- page_size <= VMW_BALLOON_LAST_SIZE; page_size++)
- INIT_LIST_HEAD(&balloon.page_sizes[page_size].pages);
-
-
INIT_DELAYED_WORK(&balloon.dwork, vmballoon_work);
- error = vmballoon_debugfs_init(&balloon);
+ error = vmballoon_register_shrinker(&balloon);
+ if (error)
+ goto fail;
+
+ /*
+ * Initialization of compaction must be done after the call to
+ * balloon_devinfo_init() .
+ */
+ balloon_devinfo_init(&balloon.b_dev_info);
+ error = vmballoon_compaction_init(&balloon);
if (error)
- return error;
+ goto fail;
+ INIT_LIST_HEAD(&balloon.huge_pages);
spin_lock_init(&balloon.comm_lock);
init_rwsem(&balloon.conf_sem);
balloon.vmci_doorbell = VMCI_INVALID_HANDLE;
@@ -1584,7 +1951,13 @@ static int __init vmballoon_init(void)
queue_delayed_work(system_freezable_wq, &balloon.dwork, 0);
+ vmballoon_debugfs_init(&balloon);
+
return 0;
+fail:
+ vmballoon_unregister_shrinker(&balloon);
+ vmballoon_compaction_deinit(&balloon);
+ return error;
}
/*
@@ -1597,6 +1970,7 @@ late_initcall(vmballoon_init);
static void __exit vmballoon_exit(void)
{
+ vmballoon_unregister_shrinker(&balloon);
vmballoon_vmci_cleanup(&balloon);
cancel_delayed_work_sync(&balloon.dwork);
@@ -1609,5 +1983,8 @@ static void __exit vmballoon_exit(void)
*/
vmballoon_send_start(&balloon, 0);
vmballoon_pop(&balloon);
+
+ /* Only once we popped the balloon, compaction can be deinit */
+ vmballoon_compaction_deinit(&balloon);
}
module_exit(vmballoon_exit);
diff --git a/drivers/misc/vmw_vmci/vmci_context.c b/drivers/misc/vmw_vmci/vmci_context.c
index 300ed69fe2c7..16695366ec92 100644
--- a/drivers/misc/vmw_vmci/vmci_context.c
+++ b/drivers/misc/vmw_vmci/vmci_context.c
@@ -21,6 +21,9 @@
#include "vmci_driver.h"
#include "vmci_event.h"
+/* Use a wide upper bound for the maximum contexts. */
+#define VMCI_MAX_CONTEXTS 2000
+
/*
* List of current VMCI contexts. Contexts can be added by
* vmci_ctx_create() and removed via vmci_ctx_destroy().
@@ -117,19 +120,22 @@ struct vmci_ctx *vmci_ctx_create(u32 cid, u32 priv_flags,
/* Initialize host-specific VMCI context. */
init_waitqueue_head(&context->host_context.wait_queue);
- context->queue_pair_array = vmci_handle_arr_create(0);
+ context->queue_pair_array =
+ vmci_handle_arr_create(0, VMCI_MAX_GUEST_QP_COUNT);
if (!context->queue_pair_array) {
error = -ENOMEM;
goto err_free_ctx;
}
- context->doorbell_array = vmci_handle_arr_create(0);
+ context->doorbell_array =
+ vmci_handle_arr_create(0, VMCI_MAX_GUEST_DOORBELL_COUNT);
if (!context->doorbell_array) {
error = -ENOMEM;
goto err_free_qp_array;
}
- context->pending_doorbell_array = vmci_handle_arr_create(0);
+ context->pending_doorbell_array =
+ vmci_handle_arr_create(0, VMCI_MAX_GUEST_DOORBELL_COUNT);
if (!context->pending_doorbell_array) {
error = -ENOMEM;
goto err_free_db_array;
@@ -204,7 +210,7 @@ static int ctx_fire_notification(u32 context_id, u32 priv_flags)
* We create an array to hold the subscribers we find when
* scanning through all contexts.
*/
- subscriber_array = vmci_handle_arr_create(0);
+ subscriber_array = vmci_handle_arr_create(0, VMCI_MAX_CONTEXTS);
if (subscriber_array == NULL)
return VMCI_ERROR_NO_MEM;
@@ -623,20 +629,26 @@ int vmci_ctx_add_notification(u32 context_id, u32 remote_cid)
spin_lock(&context->lock);
- list_for_each_entry(n, &context->notifier_list, node) {
- if (vmci_handle_is_equal(n->handle, notifier->handle)) {
- exists = true;
- break;
+ if (context->n_notifiers < VMCI_MAX_CONTEXTS) {
+ list_for_each_entry(n, &context->notifier_list, node) {
+ if (vmci_handle_is_equal(n->handle, notifier->handle)) {
+ exists = true;
+ break;
+ }
}
- }
- if (exists) {
- kfree(notifier);
- result = VMCI_ERROR_ALREADY_EXISTS;
+ if (exists) {
+ kfree(notifier);
+ result = VMCI_ERROR_ALREADY_EXISTS;
+ } else {
+ list_add_tail_rcu(&notifier->node,
+ &context->notifier_list);
+ context->n_notifiers++;
+ result = VMCI_SUCCESS;
+ }
} else {
- list_add_tail_rcu(&notifier->node, &context->notifier_list);
- context->n_notifiers++;
- result = VMCI_SUCCESS;
+ kfree(notifier);
+ result = VMCI_ERROR_NO_MEM;
}
spin_unlock(&context->lock);
@@ -721,8 +733,7 @@ static int vmci_ctx_get_chkpt_doorbells(struct vmci_ctx *context,
u32 *buf_size, void **pbuf)
{
struct dbell_cpt_state *dbells;
- size_t n_doorbells;
- int i;
+ u32 i, n_doorbells;
n_doorbells = vmci_handle_arr_get_size(context->doorbell_array);
if (n_doorbells > 0) {
@@ -860,7 +871,8 @@ int vmci_ctx_rcv_notifications_get(u32 context_id,
spin_lock(&context->lock);
*db_handle_array = context->pending_doorbell_array;
- context->pending_doorbell_array = vmci_handle_arr_create(0);
+ context->pending_doorbell_array =
+ vmci_handle_arr_create(0, VMCI_MAX_GUEST_DOORBELL_COUNT);
if (!context->pending_doorbell_array) {
context->pending_doorbell_array = *db_handle_array;
*db_handle_array = NULL;
@@ -942,12 +954,11 @@ int vmci_ctx_dbell_create(u32 context_id, struct vmci_handle handle)
return VMCI_ERROR_NOT_FOUND;
spin_lock(&context->lock);
- if (!vmci_handle_arr_has_entry(context->doorbell_array, handle)) {
- vmci_handle_arr_append_entry(&context->doorbell_array, handle);
- result = VMCI_SUCCESS;
- } else {
+ if (!vmci_handle_arr_has_entry(context->doorbell_array, handle))
+ result = vmci_handle_arr_append_entry(&context->doorbell_array,
+ handle);
+ else
result = VMCI_ERROR_DUPLICATE_ENTRY;
- }
spin_unlock(&context->lock);
vmci_ctx_put(context);
@@ -1083,15 +1094,16 @@ int vmci_ctx_notify_dbell(u32 src_cid,
if (!vmci_handle_arr_has_entry(
dst_context->pending_doorbell_array,
handle)) {
- vmci_handle_arr_append_entry(
+ result = vmci_handle_arr_append_entry(
&dst_context->pending_doorbell_array,
handle);
-
- ctx_signal_notify(dst_context);
- wake_up(&dst_context->host_context.wait_queue);
-
+ if (result == VMCI_SUCCESS) {
+ ctx_signal_notify(dst_context);
+ wake_up(&dst_context->host_context.wait_queue);
+ }
+ } else {
+ result = VMCI_SUCCESS;
}
- result = VMCI_SUCCESS;
}
spin_unlock(&dst_context->lock);
}
@@ -1118,13 +1130,11 @@ int vmci_ctx_qp_create(struct vmci_ctx *context, struct vmci_handle handle)
if (context == NULL || vmci_handle_is_invalid(handle))
return VMCI_ERROR_INVALID_ARGS;
- if (!vmci_handle_arr_has_entry(context->queue_pair_array, handle)) {
- vmci_handle_arr_append_entry(&context->queue_pair_array,
- handle);
- result = VMCI_SUCCESS;
- } else {
+ if (!vmci_handle_arr_has_entry(context->queue_pair_array, handle))
+ result = vmci_handle_arr_append_entry(
+ &context->queue_pair_array, handle);
+ else
result = VMCI_ERROR_DUPLICATE_ENTRY;
- }
return result;
}
diff --git a/drivers/misc/vmw_vmci/vmci_handle_array.c b/drivers/misc/vmw_vmci/vmci_handle_array.c
index c527388f5d7b..de7fee7ead1b 100644
--- a/drivers/misc/vmw_vmci/vmci_handle_array.c
+++ b/drivers/misc/vmw_vmci/vmci_handle_array.c
@@ -8,24 +8,29 @@
#include <linux/slab.h>
#include "vmci_handle_array.h"
-static size_t handle_arr_calc_size(size_t capacity)
+static size_t handle_arr_calc_size(u32 capacity)
{
- return sizeof(struct vmci_handle_arr) +
+ return VMCI_HANDLE_ARRAY_HEADER_SIZE +
capacity * sizeof(struct vmci_handle);
}
-struct vmci_handle_arr *vmci_handle_arr_create(size_t capacity)
+struct vmci_handle_arr *vmci_handle_arr_create(u32 capacity, u32 max_capacity)
{
struct vmci_handle_arr *array;
+ if (max_capacity == 0 || capacity > max_capacity)
+ return NULL;
+
if (capacity == 0)
- capacity = VMCI_HANDLE_ARRAY_DEFAULT_SIZE;
+ capacity = min((u32)VMCI_HANDLE_ARRAY_DEFAULT_CAPACITY,
+ max_capacity);
array = kmalloc(handle_arr_calc_size(capacity), GFP_ATOMIC);
if (!array)
return NULL;
array->capacity = capacity;
+ array->max_capacity = max_capacity;
array->size = 0;
return array;
@@ -36,27 +41,34 @@ void vmci_handle_arr_destroy(struct vmci_handle_arr *array)
kfree(array);
}
-void vmci_handle_arr_append_entry(struct vmci_handle_arr **array_ptr,
- struct vmci_handle handle)
+int vmci_handle_arr_append_entry(struct vmci_handle_arr **array_ptr,
+ struct vmci_handle handle)
{
struct vmci_handle_arr *array = *array_ptr;
if (unlikely(array->size >= array->capacity)) {
/* reallocate. */
struct vmci_handle_arr *new_array;
- size_t new_capacity = array->capacity * VMCI_ARR_CAP_MULT;
- size_t new_size = handle_arr_calc_size(new_capacity);
+ u32 capacity_bump = min(array->max_capacity - array->capacity,
+ array->capacity);
+ size_t new_size = handle_arr_calc_size(array->capacity +
+ capacity_bump);
+
+ if (array->size >= array->max_capacity)
+ return VMCI_ERROR_NO_MEM;
new_array = krealloc(array, new_size, GFP_ATOMIC);
if (!new_array)
- return;
+ return VMCI_ERROR_NO_MEM;
- new_array->capacity = new_capacity;
+ new_array->capacity += capacity_bump;
*array_ptr = array = new_array;
}
array->entries[array->size] = handle;
array->size++;
+
+ return VMCI_SUCCESS;
}
/*
@@ -66,7 +78,7 @@ struct vmci_handle vmci_handle_arr_remove_entry(struct vmci_handle_arr *array,
struct vmci_handle entry_handle)
{
struct vmci_handle handle = VMCI_INVALID_HANDLE;
- size_t i;
+ u32 i;
for (i = 0; i < array->size; i++) {
if (vmci_handle_is_equal(array->entries[i], entry_handle)) {
@@ -101,7 +113,7 @@ struct vmci_handle vmci_handle_arr_remove_tail(struct vmci_handle_arr *array)
* Handle at given index, VMCI_INVALID_HANDLE if invalid index.
*/
struct vmci_handle
-vmci_handle_arr_get_entry(const struct vmci_handle_arr *array, size_t index)
+vmci_handle_arr_get_entry(const struct vmci_handle_arr *array, u32 index)
{
if (unlikely(index >= array->size))
return VMCI_INVALID_HANDLE;
@@ -112,7 +124,7 @@ vmci_handle_arr_get_entry(const struct vmci_handle_arr *array, size_t index)
bool vmci_handle_arr_has_entry(const struct vmci_handle_arr *array,
struct vmci_handle entry_handle)
{
- size_t i;
+ u32 i;
for (i = 0; i < array->size; i++)
if (vmci_handle_is_equal(array->entries[i], entry_handle))
diff --git a/drivers/misc/vmw_vmci/vmci_handle_array.h b/drivers/misc/vmw_vmci/vmci_handle_array.h
index bd1559a548e9..96193f85be5b 100644
--- a/drivers/misc/vmw_vmci/vmci_handle_array.h
+++ b/drivers/misc/vmw_vmci/vmci_handle_array.h
@@ -9,32 +9,41 @@
#define _VMCI_HANDLE_ARRAY_H_
#include <linux/vmw_vmci_defs.h>
+#include <linux/limits.h>
#include <linux/types.h>
-#define VMCI_HANDLE_ARRAY_DEFAULT_SIZE 4
-#define VMCI_ARR_CAP_MULT 2 /* Array capacity multiplier */
-
struct vmci_handle_arr {
- size_t capacity;
- size_t size;
+ u32 capacity;
+ u32 max_capacity;
+ u32 size;
+ u32 pad;
struct vmci_handle entries[];
};
-struct vmci_handle_arr *vmci_handle_arr_create(size_t capacity);
+#define VMCI_HANDLE_ARRAY_HEADER_SIZE \
+ offsetof(struct vmci_handle_arr, entries)
+/* Select a default capacity that results in a 64 byte sized array */
+#define VMCI_HANDLE_ARRAY_DEFAULT_CAPACITY 6
+/* Make sure that the max array size can be expressed by a u32 */
+#define VMCI_HANDLE_ARRAY_MAX_CAPACITY \
+ ((U32_MAX - VMCI_HANDLE_ARRAY_HEADER_SIZE - 1) / \
+ sizeof(struct vmci_handle))
+
+struct vmci_handle_arr *vmci_handle_arr_create(u32 capacity, u32 max_capacity);
void vmci_handle_arr_destroy(struct vmci_handle_arr *array);
-void vmci_handle_arr_append_entry(struct vmci_handle_arr **array_ptr,
- struct vmci_handle handle);
+int vmci_handle_arr_append_entry(struct vmci_handle_arr **array_ptr,
+ struct vmci_handle handle);
struct vmci_handle vmci_handle_arr_remove_entry(struct vmci_handle_arr *array,
struct vmci_handle
entry_handle);
struct vmci_handle vmci_handle_arr_remove_tail(struct vmci_handle_arr *array);
struct vmci_handle
-vmci_handle_arr_get_entry(const struct vmci_handle_arr *array, size_t index);
+vmci_handle_arr_get_entry(const struct vmci_handle_arr *array, u32 index);
bool vmci_handle_arr_has_entry(const struct vmci_handle_arr *array,
struct vmci_handle entry_handle);
struct vmci_handle *vmci_handle_arr_get_handles(struct vmci_handle_arr *array);
-static inline size_t vmci_handle_arr_get_size(
+static inline u32 vmci_handle_arr_get_size(
const struct vmci_handle_arr *array)
{
return array->size;
diff --git a/drivers/misc/xilinx_sdfec.c b/drivers/misc/xilinx_sdfec.c
new file mode 100644
index 000000000000..f257d3812110
--- /dev/null
+++ b/drivers/misc/xilinx_sdfec.c
@@ -0,0 +1,345 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Xilinx SDFEC
+ *
+ * Copyright (C) 2019 Xilinx, Inc.
+ *
+ * Description:
+ * This driver is developed for SDFEC16 (Soft Decision FEC 16nm)
+ * IP. It exposes a char device which supports file operations
+ * like open(), close() and ioctl().
+ */
+
+#include <linux/miscdevice.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+
+#define DEV_NAME_LEN 12
+
+static struct idr dev_idr;
+static struct mutex dev_idr_lock;
+
+/**
+ * struct xsdfec_clks - For managing SD-FEC clocks
+ * @core_clk: Main processing clock for core
+ * @axi_clk: AXI4-Lite memory-mapped clock
+ * @din_words_clk: DIN Words AXI4-Stream Slave clock
+ * @din_clk: DIN AXI4-Stream Slave clock
+ * @dout_clk: DOUT Words AXI4-Stream Slave clock
+ * @dout_words_clk: DOUT AXI4-Stream Slave clock
+ * @ctrl_clk: Control AXI4-Stream Slave clock
+ * @status_clk: Status AXI4-Stream Slave clock
+ */
+struct xsdfec_clks {
+ struct clk *core_clk;
+ struct clk *axi_clk;
+ struct clk *din_words_clk;
+ struct clk *din_clk;
+ struct clk *dout_clk;
+ struct clk *dout_words_clk;
+ struct clk *ctrl_clk;
+ struct clk *status_clk;
+};
+
+/**
+ * struct xsdfec_dev - Driver data for SDFEC
+ * @regs: device physical base address
+ * @dev: pointer to device struct
+ * @miscdev: Misc device handle
+ * @error_data_lock: Error counter and states spinlock
+ * @clks: Clocks managed by the SDFEC driver
+ * @dev_name: Device name
+ * @dev_id: Device ID
+ *
+ * This structure contains necessary state for SDFEC driver to operate
+ */
+struct xsdfec_dev {
+ void __iomem *regs;
+ struct device *dev;
+ struct miscdevice miscdev;
+ /* Spinlock to protect state_updated and stats_updated */
+ spinlock_t error_data_lock;
+ struct xsdfec_clks clks;
+ char dev_name[DEV_NAME_LEN];
+ int dev_id;
+};
+
+static const struct file_operations xsdfec_fops = {
+ .owner = THIS_MODULE,
+};
+
+static int xsdfec_clk_init(struct platform_device *pdev,
+ struct xsdfec_clks *clks)
+{
+ int err;
+
+ clks->core_clk = devm_clk_get(&pdev->dev, "core_clk");
+ if (IS_ERR(clks->core_clk)) {
+ dev_err(&pdev->dev, "failed to get core_clk");
+ return PTR_ERR(clks->core_clk);
+ }
+
+ clks->axi_clk = devm_clk_get(&pdev->dev, "s_axi_aclk");
+ if (IS_ERR(clks->axi_clk)) {
+ dev_err(&pdev->dev, "failed to get axi_clk");
+ return PTR_ERR(clks->axi_clk);
+ }
+
+ clks->din_words_clk = devm_clk_get(&pdev->dev, "s_axis_din_words_aclk");
+ if (IS_ERR(clks->din_words_clk)) {
+ if (PTR_ERR(clks->din_words_clk) != -ENOENT) {
+ err = PTR_ERR(clks->din_words_clk);
+ return err;
+ }
+ clks->din_words_clk = NULL;
+ }
+
+ clks->din_clk = devm_clk_get(&pdev->dev, "s_axis_din_aclk");
+ if (IS_ERR(clks->din_clk)) {
+ if (PTR_ERR(clks->din_clk) != -ENOENT) {
+ err = PTR_ERR(clks->din_clk);
+ return err;
+ }
+ clks->din_clk = NULL;
+ }
+
+ clks->dout_clk = devm_clk_get(&pdev->dev, "m_axis_dout_aclk");
+ if (IS_ERR(clks->dout_clk)) {
+ if (PTR_ERR(clks->dout_clk) != -ENOENT) {
+ err = PTR_ERR(clks->dout_clk);
+ return err;
+ }
+ clks->dout_clk = NULL;
+ }
+
+ clks->dout_words_clk =
+ devm_clk_get(&pdev->dev, "s_axis_dout_words_aclk");
+ if (IS_ERR(clks->dout_words_clk)) {
+ if (PTR_ERR(clks->dout_words_clk) != -ENOENT) {
+ err = PTR_ERR(clks->dout_words_clk);
+ return err;
+ }
+ clks->dout_words_clk = NULL;
+ }
+
+ clks->ctrl_clk = devm_clk_get(&pdev->dev, "s_axis_ctrl_aclk");
+ if (IS_ERR(clks->ctrl_clk)) {
+ if (PTR_ERR(clks->ctrl_clk) != -ENOENT) {
+ err = PTR_ERR(clks->ctrl_clk);
+ return err;
+ }
+ clks->ctrl_clk = NULL;
+ }
+
+ clks->status_clk = devm_clk_get(&pdev->dev, "m_axis_status_aclk");
+ if (IS_ERR(clks->status_clk)) {
+ if (PTR_ERR(clks->status_clk) != -ENOENT) {
+ err = PTR_ERR(clks->status_clk);
+ return err;
+ }
+ clks->status_clk = NULL;
+ }
+
+ err = clk_prepare_enable(clks->core_clk);
+ if (err) {
+ dev_err(&pdev->dev, "failed to enable core_clk (%d)", err);
+ return err;
+ }
+
+ err = clk_prepare_enable(clks->axi_clk);
+ if (err) {
+ dev_err(&pdev->dev, "failed to enable axi_clk (%d)", err);
+ goto err_disable_core_clk;
+ }
+
+ err = clk_prepare_enable(clks->din_clk);
+ if (err) {
+ dev_err(&pdev->dev, "failed to enable din_clk (%d)", err);
+ goto err_disable_axi_clk;
+ }
+
+ err = clk_prepare_enable(clks->din_words_clk);
+ if (err) {
+ dev_err(&pdev->dev, "failed to enable din_words_clk (%d)", err);
+ goto err_disable_din_clk;
+ }
+
+ err = clk_prepare_enable(clks->dout_clk);
+ if (err) {
+ dev_err(&pdev->dev, "failed to enable dout_clk (%d)", err);
+ goto err_disable_din_words_clk;
+ }
+
+ err = clk_prepare_enable(clks->dout_words_clk);
+ if (err) {
+ dev_err(&pdev->dev, "failed to enable dout_words_clk (%d)",
+ err);
+ goto err_disable_dout_clk;
+ }
+
+ err = clk_prepare_enable(clks->ctrl_clk);
+ if (err) {
+ dev_err(&pdev->dev, "failed to enable ctrl_clk (%d)", err);
+ goto err_disable_dout_words_clk;
+ }
+
+ err = clk_prepare_enable(clks->status_clk);
+ if (err) {
+ dev_err(&pdev->dev, "failed to enable status_clk (%d)\n", err);
+ goto err_disable_ctrl_clk;
+ }
+
+ return err;
+
+err_disable_ctrl_clk:
+ clk_disable_unprepare(clks->ctrl_clk);
+err_disable_dout_words_clk:
+ clk_disable_unprepare(clks->dout_words_clk);
+err_disable_dout_clk:
+ clk_disable_unprepare(clks->dout_clk);
+err_disable_din_words_clk:
+ clk_disable_unprepare(clks->din_words_clk);
+err_disable_din_clk:
+ clk_disable_unprepare(clks->din_clk);
+err_disable_axi_clk:
+ clk_disable_unprepare(clks->axi_clk);
+err_disable_core_clk:
+ clk_disable_unprepare(clks->core_clk);
+
+ return err;
+}
+
+static void xsdfec_disable_all_clks(struct xsdfec_clks *clks)
+{
+ clk_disable_unprepare(clks->status_clk);
+ clk_disable_unprepare(clks->ctrl_clk);
+ clk_disable_unprepare(clks->dout_words_clk);
+ clk_disable_unprepare(clks->dout_clk);
+ clk_disable_unprepare(clks->din_words_clk);
+ clk_disable_unprepare(clks->din_clk);
+ clk_disable_unprepare(clks->core_clk);
+ clk_disable_unprepare(clks->axi_clk);
+}
+
+static void xsdfec_idr_remove(struct xsdfec_dev *xsdfec)
+{
+ mutex_lock(&dev_idr_lock);
+ idr_remove(&dev_idr, xsdfec->dev_id);
+ mutex_unlock(&dev_idr_lock);
+}
+
+static int xsdfec_probe(struct platform_device *pdev)
+{
+ struct xsdfec_dev *xsdfec;
+ struct device *dev;
+ struct resource *res;
+ int err;
+
+ xsdfec = devm_kzalloc(&pdev->dev, sizeof(*xsdfec), GFP_KERNEL);
+ if (!xsdfec)
+ return -ENOMEM;
+
+ xsdfec->dev = &pdev->dev;
+ spin_lock_init(&xsdfec->error_data_lock);
+
+ err = xsdfec_clk_init(pdev, &xsdfec->clks);
+ if (err)
+ return err;
+
+ dev = xsdfec->dev;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ xsdfec->regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(xsdfec->regs)) {
+ err = PTR_ERR(xsdfec->regs);
+ goto err_xsdfec_dev;
+ }
+
+ /* Save driver private data */
+ platform_set_drvdata(pdev, xsdfec);
+
+ mutex_lock(&dev_idr_lock);
+ err = idr_alloc(&dev_idr, xsdfec->dev_name, 0, 0, GFP_KERNEL);
+ mutex_unlock(&dev_idr_lock);
+ if (err < 0)
+ goto err_xsdfec_dev;
+ xsdfec->dev_id = err;
+
+ snprintf(xsdfec->dev_name, DEV_NAME_LEN, "xsdfec%d", xsdfec->dev_id);
+ xsdfec->miscdev.minor = MISC_DYNAMIC_MINOR;
+ xsdfec->miscdev.name = xsdfec->dev_name;
+ xsdfec->miscdev.fops = &xsdfec_fops;
+ xsdfec->miscdev.parent = dev;
+ err = misc_register(&xsdfec->miscdev);
+ if (err) {
+ dev_err(dev, "error:%d. Unable to register device", err);
+ goto err_xsdfec_idr;
+ }
+ return 0;
+
+err_xsdfec_idr:
+ xsdfec_idr_remove(xsdfec);
+err_xsdfec_dev:
+ xsdfec_disable_all_clks(&xsdfec->clks);
+ return err;
+}
+
+static int xsdfec_remove(struct platform_device *pdev)
+{
+ struct xsdfec_dev *xsdfec;
+
+ xsdfec = platform_get_drvdata(pdev);
+ misc_deregister(&xsdfec->miscdev);
+ xsdfec_idr_remove(xsdfec);
+ xsdfec_disable_all_clks(&xsdfec->clks);
+ return 0;
+}
+
+static const struct of_device_id xsdfec_of_match[] = {
+ {
+ .compatible = "xlnx,sd-fec-1.1",
+ },
+ { /* end of table */ }
+};
+MODULE_DEVICE_TABLE(of, xsdfec_of_match);
+
+static struct platform_driver xsdfec_driver = {
+ .driver = {
+ .name = "xilinx-sdfec",
+ .of_match_table = xsdfec_of_match,
+ },
+ .probe = xsdfec_probe,
+ .remove = xsdfec_remove,
+};
+
+static int __init xsdfec_init(void)
+{
+ int err;
+
+ mutex_init(&dev_idr_lock);
+ idr_init(&dev_idr);
+ err = platform_driver_register(&xsdfec_driver);
+ if (err < 0) {
+ pr_err("%s Unabled to register SDFEC driver", __func__);
+ return err;
+ }
+ return 0;
+}
+
+static void __exit xsdfec_exit(void)
+{
+ platform_driver_unregister(&xsdfec_driver);
+ idr_destroy(&dev_idr);
+}
+
+module_init(xsdfec_init);
+module_exit(xsdfec_exit);
+
+MODULE_AUTHOR("Xilinx, Inc");
+MODULE_DESCRIPTION("Xilinx SD-FEC16 Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index fc92c6c1c9a4..74de3f2dda38 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/mmc/core/bus.c
*
* Copyright (C) 2003 Russell King, All Rights Reserved.
* Copyright (C) 2007 Pierre Ossman
*
- * 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.
- *
* MMC card bus driver model
*/
diff --git a/drivers/mmc/core/bus.h b/drivers/mmc/core/bus.h
index 72b0ef03f10a..8105852c4b62 100644
--- a/drivers/mmc/core/bus.h
+++ b/drivers/mmc/core/bus.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/drivers/mmc/core/bus.h
*
* Copyright (C) 2003 Russell King, All Rights Reserved.
* Copyright 2007 Pierre Ossman
- *
- * 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.
*/
#ifndef _MMC_CORE_BUS_H
#define _MMC_CORE_BUS_H
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 6db36dc870b5..221127324709 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/mmc/core/core.c
*
@@ -5,10 +6,6 @@
* SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
* Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved.
* MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/init.h>
@@ -144,8 +141,9 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
int err = cmd->error;
/* Flag re-tuning needed on CRC errors */
- if ((cmd->opcode != MMC_SEND_TUNING_BLOCK &&
- cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200) &&
+ if (cmd->opcode != MMC_SEND_TUNING_BLOCK &&
+ cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200 &&
+ !host->retune_crc_disable &&
(err == -EILSEQ || (mrq->sbc && mrq->sbc->error == -EILSEQ) ||
(mrq->data && mrq->data->error == -EILSEQ) ||
(mrq->stop && mrq->stop->error == -EILSEQ)))
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index b5083b13d594..328c78dbee66 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/drivers/mmc/core/core.h
*
* Copyright (C) 2003 Russell King, All Rights Reserved.
* Copyright 2007 Pierre Ossman
- *
- * 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.
*/
#ifndef _MMC_CORE_CORE_H
#define _MMC_CORE_CORE_H
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index d2275c5a2311..09e0c7659469 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Debugfs support for hosts and cards
*
* Copyright (C) 2008 Atmel Corporation
- *
- * 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.
*/
#include <linux/moduleparam.h>
#include <linux/export.h>
@@ -230,45 +227,21 @@ void mmc_add_host_debugfs(struct mmc_host *host)
struct dentry *root;
root = debugfs_create_dir(mmc_hostname(host), NULL);
- if (IS_ERR(root))
- /* Don't complain -- debugfs just isn't enabled */
- return;
- if (!root)
- /* Complain -- debugfs is enabled, but it failed to
- * create the directory. */
- goto err_root;
-
host->debugfs_root = root;
- if (!debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops))
- goto err_node;
-
- if (!debugfs_create_x32("caps", S_IRUSR, root, &host->caps))
- goto err_node;
-
- if (!debugfs_create_x32("caps2", S_IRUSR, root, &host->caps2))
- goto err_node;
-
- if (!debugfs_create_file("clock", S_IRUSR | S_IWUSR, root, host,
- &mmc_clock_fops))
- goto err_node;
+ debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops);
+ debugfs_create_x32("caps", S_IRUSR, root, &host->caps);
+ debugfs_create_x32("caps2", S_IRUSR, root, &host->caps2);
+ debugfs_create_file("clock", S_IRUSR | S_IWUSR, root, host,
+ &mmc_clock_fops);
#ifdef CONFIG_FAIL_MMC_REQUEST
if (fail_request)
setup_fault_attr(&fail_default_attr, fail_request);
host->fail_mmc_request = fail_default_attr;
- if (IS_ERR(fault_create_debugfs_attr("fail_mmc_request",
- root,
- &host->fail_mmc_request)))
- goto err_node;
+ fault_create_debugfs_attr("fail_mmc_request", root,
+ &host->fail_mmc_request);
#endif
- return;
-
-err_node:
- debugfs_remove_recursive(root);
- host->debugfs_root = NULL;
-err_root:
- dev_err(&host->class_dev, "failed to initialize debugfs\n");
}
void mmc_remove_host_debugfs(struct mmc_host *host)
@@ -285,25 +258,9 @@ void mmc_add_card_debugfs(struct mmc_card *card)
return;
root = debugfs_create_dir(mmc_card_id(card), host->debugfs_root);
- if (IS_ERR(root))
- /* Don't complain -- debugfs just isn't enabled */
- return;
- if (!root)
- /* Complain -- debugfs is enabled, but it failed to
- * create the directory. */
- goto err;
-
card->debugfs_root = root;
- if (!debugfs_create_x32("state", S_IRUSR, root, &card->state))
- goto err;
-
- return;
-
-err:
- debugfs_remove_recursive(root);
- card->debugfs_root = NULL;
- dev_err(&card->dev, "failed to initialize debugfs\n");
+ debugfs_create_x32("state", S_IRUSR, root, &card->state);
}
void mmc_remove_card_debugfs(struct mmc_card *card)
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 6a51f7a06ce7..105b7a7c0251 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/mmc/core/host.c
*
@@ -5,10 +6,6 @@
* Copyright (C) 2007-2008 Pierre Ossman
* Copyright (C) 2010 Linus Walleij
*
- * 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.
- *
* MMC host class device management
*/
diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h
index 4805438c02ff..5e3b9534ffb2 100644
--- a/drivers/mmc/core/host.h
+++ b/drivers/mmc/core/host.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/drivers/mmc/core/host.h
*
* Copyright (C) 2003 Russell King, All Rights Reserved.
* Copyright 2007 Pierre Ossman
- *
- * 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.
*/
#ifndef _MMC_CORE_HOST_H
#define _MMC_CORE_HOST_H
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 3e786ba204c3..c8804895595f 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/mmc/core/mmc.c
*
* Copyright (C) 2003-2004 Russell King, All Rights Reserved.
* Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
* MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/err.h>
@@ -1212,13 +1209,13 @@ static int mmc_select_hs400(struct mmc_card *card)
mmc_set_timing(host, MMC_TIMING_MMC_HS400);
mmc_set_bus_speed(card);
+ if (host->ops->hs400_complete)
+ host->ops->hs400_complete(host);
+
err = mmc_switch_status(card);
if (err)
goto out_err;
- if (host->ops->hs400_complete)
- host->ops->hs400_complete(host);
-
return 0;
out_err:
diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c
index b27df2d2b5ae..492dd4596314 100644
--- a/drivers/mmc/core/mmc_test.c
+++ b/drivers/mmc/core/mmc_test.c
@@ -3167,15 +3167,7 @@ static int __mmc_test_register_dbgfs_file(struct mmc_card *card,
struct mmc_test_dbgfs_file *df;
if (card->debugfs_root)
- file = debugfs_create_file(name, mode, card->debugfs_root,
- card, fops);
-
- if (IS_ERR_OR_NULL(file)) {
- dev_err(&card->dev,
- "Can't create %s. Perhaps debugfs is disabled.\n",
- name);
- return -ENODEV;
- }
+ debugfs_create_file(name, mode, card->debugfs_root, card, fops);
df = kmalloc(sizeof(*df), GFP_KERNEL);
if (!df) {
diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c
index 92900a095796..e327f80ebe70 100644
--- a/drivers/mmc/core/queue.c
+++ b/drivers/mmc/core/queue.c
@@ -1,11 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2003 Russell King, All Rights Reserved.
* Copyright 2006-2007 Pierre Ossman
- *
- * 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.
- *
*/
#include <linux/slab.h>
#include <linux/module.h>
@@ -354,18 +350,15 @@ static const struct blk_mq_ops mmc_mq_ops = {
static void mmc_setup_queue(struct mmc_queue *mq, struct mmc_card *card)
{
struct mmc_host *host = card->host;
- u64 limit = BLK_BOUNCE_HIGH;
unsigned block_size = 512;
- if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
- limit = (u64)dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT;
-
blk_queue_flag_set(QUEUE_FLAG_NONROT, mq->queue);
blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, mq->queue);
if (mmc_can_erase(card))
mmc_queue_setup_discard(mq->queue, card);
- blk_queue_bounce_limit(mq->queue, limit);
+ if (!mmc_dev(host)->dma_mask || !*mmc_dev(host)->dma_mask)
+ blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_HIGH);
blk_queue_max_hw_sectors(mq->queue,
min(host->max_blk_count, host->max_req_size / 512));
blk_queue_max_segments(mq->queue, host->max_segs);
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index d3d32f9a2cb1..d681e8aaca83 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/mmc/core/sd.c
*
* Copyright (C) 2003-2004 Russell King, All Rights Reserved.
* SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
* Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/err.h>
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index d1aa1c7577bb..8dd8fc32ecca 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -559,7 +559,7 @@ static void mmc_sdio_resend_if_cond(struct mmc_host *host,
* we're trying to reinitialise.
*/
static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
- struct mmc_card *oldcard, int powered_resume)
+ struct mmc_card *oldcard)
{
struct mmc_card *card;
int err;
@@ -582,11 +582,9 @@ try_again:
/*
* Inform the card of the voltage
*/
- if (!powered_resume) {
- err = mmc_send_io_op_cond(host, ocr, &rocr);
- if (err)
- goto err;
- }
+ err = mmc_send_io_op_cond(host, ocr, &rocr);
+ if (err)
+ goto err;
/*
* For SPI, enable CRC as appropriate.
@@ -645,7 +643,7 @@ try_again:
* try to init uhs card. sdio_read_cccr will take over this task
* to make sure which speed mode should work.
*/
- if (!powered_resume && (rocr & ocr & R4_18V_PRESENT)) {
+ if (rocr & ocr & R4_18V_PRESENT) {
err = mmc_set_uhs_voltage(host, ocr_card);
if (err == -EAGAIN) {
mmc_sdio_resend_if_cond(host, card);
@@ -659,7 +657,7 @@ try_again:
/*
* For native busses: set card RCA and quit open drain mode.
*/
- if (!powered_resume && !mmc_host_is_spi(host)) {
+ if (!mmc_host_is_spi(host)) {
err = mmc_send_relative_addr(host, &card->rca);
if (err)
goto remove;
@@ -687,7 +685,7 @@ try_again:
/*
* Select card, as all following commands rely on that.
*/
- if (!powered_resume && !mmc_host_is_spi(host)) {
+ if (!mmc_host_is_spi(host)) {
err = mmc_select_card(card);
if (err)
goto remove;
@@ -816,10 +814,27 @@ err:
return err;
}
-static int mmc_sdio_reinit_card(struct mmc_host *host, bool powered_resume)
+static int mmc_sdio_reinit_card(struct mmc_host *host)
{
int ret;
+ /*
+ * Reset the card by performing the same steps that are taken by
+ * mmc_rescan_try_freq() and mmc_attach_sdio() during a "normal" probe.
+ *
+ * sdio_reset() is technically not needed. Having just powered up the
+ * hardware, it should already be in reset state. However, some
+ * platforms (such as SD8686 on OLPC) do not instantly cut power,
+ * meaning that a reset is required when restoring power soon after
+ * powering off. It is harmless in other cases.
+ *
+ * The CMD5 reset (mmc_send_io_op_cond()), according to the SDIO spec,
+ * is not necessary for non-removable cards. However, it is required
+ * for OLPC SD8686 (which expects a [CMD5,5,3,7] init sequence), and
+ * harmless in other situations.
+ *
+ */
+
sdio_reset(host);
mmc_go_idle(host);
mmc_send_if_cond(host, host->card->ocr);
@@ -828,8 +843,7 @@ static int mmc_sdio_reinit_card(struct mmc_host *host, bool powered_resume)
if (ret)
return ret;
- return mmc_sdio_init_card(host, host->card->ocr, host->card,
- powered_resume);
+ return mmc_sdio_init_card(host, host->card->ocr, host->card);
}
/*
@@ -937,6 +951,10 @@ static int mmc_sdio_pre_suspend(struct mmc_host *host)
*/
static int mmc_sdio_suspend(struct mmc_host *host)
{
+ /* Prevent processing of SDIO IRQs in suspended state. */
+ mmc_card_set_suspended(host->card);
+ cancel_delayed_work_sync(&host->sdio_irq_work);
+
mmc_claim_host(host);
if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host))
@@ -961,7 +979,11 @@ static int mmc_sdio_resume(struct mmc_host *host)
/* Basic card reinitialization. */
mmc_claim_host(host);
- /* Restore power if needed */
+ /*
+ * Restore power and reinitialize the card when needed. Note that a
+ * removable card is checked from a detect work later on in the resume
+ * process.
+ */
if (!mmc_card_keep_power(host)) {
mmc_power_up(host, host->card->ocr);
/*
@@ -975,61 +997,32 @@ static int mmc_sdio_resume(struct mmc_host *host)
pm_runtime_set_active(&host->card->dev);
pm_runtime_enable(&host->card->dev);
}
- }
-
- /* No need to reinitialize powered-resumed nonremovable cards */
- if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) {
- err = mmc_sdio_reinit_card(host, mmc_card_keep_power(host));
- } else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
+ err = mmc_sdio_reinit_card(host);
+ } else if (mmc_card_wake_sdio_irq(host)) {
/* We may have switched to 1-bit mode during suspend */
err = sdio_enable_4bit_bus(host->card);
}
- if (!err && host->sdio_irqs) {
+ if (err)
+ goto out;
+
+ /* Allow SDIO IRQs to be processed again. */
+ mmc_card_clr_suspended(host->card);
+
+ if (host->sdio_irqs) {
if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD))
wake_up_process(host->sdio_irq_thread);
else if (host->caps & MMC_CAP_SDIO_IRQ)
host->ops->enable_sdio_irq(host, 1);
}
+out:
mmc_release_host(host);
host->pm_flags &= ~MMC_PM_KEEP_POWER;
return err;
}
-static int mmc_sdio_power_restore(struct mmc_host *host)
-{
- int ret;
-
- /*
- * Reset the card by performing the same steps that are taken by
- * mmc_rescan_try_freq() and mmc_attach_sdio() during a "normal" probe.
- *
- * sdio_reset() is technically not needed. Having just powered up the
- * hardware, it should already be in reset state. However, some
- * platforms (such as SD8686 on OLPC) do not instantly cut power,
- * meaning that a reset is required when restoring power soon after
- * powering off. It is harmless in other cases.
- *
- * The CMD5 reset (mmc_send_io_op_cond()), according to the SDIO spec,
- * is not necessary for non-removable cards. However, it is required
- * for OLPC SD8686 (which expects a [CMD5,5,3,7] init sequence), and
- * harmless in other situations.
- *
- */
-
- mmc_claim_host(host);
-
- ret = mmc_sdio_reinit_card(host, mmc_card_keep_power(host));
- if (!ret && host->sdio_irqs)
- mmc_signal_sdio_irq(host);
-
- mmc_release_host(host);
-
- return ret;
-}
-
static int mmc_sdio_runtime_suspend(struct mmc_host *host)
{
/* No references to the card, cut the power to it. */
@@ -1047,7 +1040,7 @@ static int mmc_sdio_runtime_resume(struct mmc_host *host)
/* Restore power and re-initialize. */
mmc_claim_host(host);
mmc_power_up(host, host->card->ocr);
- ret = mmc_sdio_power_restore(host);
+ ret = mmc_sdio_reinit_card(host);
mmc_release_host(host);
return ret;
@@ -1056,7 +1049,7 @@ static int mmc_sdio_runtime_resume(struct mmc_host *host)
static int mmc_sdio_hw_reset(struct mmc_host *host)
{
mmc_power_cycle(host, host->card->ocr);
- return mmc_sdio_power_restore(host);
+ return mmc_sdio_reinit_card(host);
}
static int mmc_sdio_sw_reset(struct mmc_host *host)
@@ -1068,7 +1061,7 @@ static int mmc_sdio_sw_reset(struct mmc_host *host)
mmc_set_initial_state(host);
mmc_set_initial_signal_voltage(host);
- return mmc_sdio_reinit_card(host, 0);
+ return mmc_sdio_reinit_card(host);
}
static const struct mmc_bus_ops mmc_sdio_ops = {
@@ -1118,7 +1111,7 @@ int mmc_attach_sdio(struct mmc_host *host)
/*
* Detect and init the card.
*/
- err = mmc_sdio_init_card(host, rocr, NULL, 0);
+ err = mmc_sdio_init_card(host, rocr, NULL);
if (err)
goto err;
diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c
index f79f0b0caab8..2ba00acf64e6 100644
--- a/drivers/mmc/core/sdio_io.c
+++ b/drivers/mmc/core/sdio_io.c
@@ -15,6 +15,7 @@
#include "sdio_ops.h"
#include "core.h"
#include "card.h"
+#include "host.h"
/**
* sdio_claim_host - exclusively claim a bus for a certain SDIO function
@@ -734,3 +735,79 @@ int sdio_set_host_pm_flags(struct sdio_func *func, mmc_pm_flag_t flags)
return 0;
}
EXPORT_SYMBOL_GPL(sdio_set_host_pm_flags);
+
+/**
+ * sdio_retune_crc_disable - temporarily disable retuning on CRC errors
+ * @func: SDIO function attached to host
+ *
+ * If the SDIO card is known to be in a state where it might produce
+ * CRC errors on the bus in response to commands (like if we know it is
+ * transitioning between power states), an SDIO function driver can
+ * call this function to temporarily disable the SD/MMC core behavior of
+ * triggering an automatic retuning.
+ *
+ * This function should be called while the host is claimed and the host
+ * should remain claimed until sdio_retune_crc_enable() is called.
+ * Specifically, the expected sequence of calls is:
+ * - sdio_claim_host()
+ * - sdio_retune_crc_disable()
+ * - some number of calls like sdio_writeb() and sdio_readb()
+ * - sdio_retune_crc_enable()
+ * - sdio_release_host()
+ */
+void sdio_retune_crc_disable(struct sdio_func *func)
+{
+ func->card->host->retune_crc_disable = true;
+}
+EXPORT_SYMBOL_GPL(sdio_retune_crc_disable);
+
+/**
+ * sdio_retune_crc_enable - re-enable retuning on CRC errors
+ * @func: SDIO function attached to host
+ *
+ * This is the compement to sdio_retune_crc_disable().
+ */
+void sdio_retune_crc_enable(struct sdio_func *func)
+{
+ func->card->host->retune_crc_disable = false;
+}
+EXPORT_SYMBOL_GPL(sdio_retune_crc_enable);
+
+/**
+ * sdio_retune_hold_now - start deferring retuning requests till release
+ * @func: SDIO function attached to host
+ *
+ * This function can be called if it's currently a bad time to do
+ * a retune of the SDIO card. Retune requests made during this time
+ * will be held and we'll actually do the retune sometime after the
+ * release.
+ *
+ * This function could be useful if an SDIO card is in a power state
+ * where it can respond to a small subset of commands that doesn't
+ * include the retuning command. Care should be taken when using
+ * this function since (presumably) the retuning request we might be
+ * deferring was made for a good reason.
+ *
+ * This function should be called while the host is claimed.
+ */
+void sdio_retune_hold_now(struct sdio_func *func)
+{
+ mmc_retune_hold_now(func->card->host);
+}
+EXPORT_SYMBOL_GPL(sdio_retune_hold_now);
+
+/**
+ * sdio_retune_release - signal that it's OK to retune now
+ * @func: SDIO function attached to host
+ *
+ * This is the complement to sdio_retune_hold_now(). Calling this
+ * function won't make a retune happen right away but will allow
+ * them to be scheduled normally.
+ *
+ * This function should be called while the host is claimed.
+ */
+void sdio_retune_release(struct sdio_func *func)
+{
+ mmc_retune_release(func->card->host);
+}
+EXPORT_SYMBOL_GPL(sdio_retune_release);
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
index 931e6226c0b3..0bcc5e83bd1a 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -34,6 +34,10 @@ static int process_sdio_pending_irqs(struct mmc_host *host)
unsigned char pending;
struct sdio_func *func;
+ /* Don't process SDIO IRQs if the card is suspended. */
+ if (mmc_card_suspended(card))
+ return 0;
+
/*
* Optimization, if there is only 1 function interrupt registered
* and we know an IRQ was signaled then call irq handler directly.
@@ -88,7 +92,7 @@ static int process_sdio_pending_irqs(struct mmc_host *host)
return ret;
}
-void sdio_run_irqs(struct mmc_host *host)
+static void sdio_run_irqs(struct mmc_host *host)
{
mmc_claim_host(host);
if (host->sdio_irqs) {
@@ -99,7 +103,6 @@ void sdio_run_irqs(struct mmc_host *host)
}
mmc_release_host(host);
}
-EXPORT_SYMBOL_GPL(sdio_run_irqs);
void sdio_irq_work(struct work_struct *work)
{
diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c
index 4afc6b87b465..da2596c5fa28 100644
--- a/drivers/mmc/core/slot-gpio.c
+++ b/drivers/mmc/core/slot-gpio.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic GPIO card-detect helper
*
* Copyright (C) 2011, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- *
- * 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.
*/
#include <linux/err.h>
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 931770f17087..14d89a108edd 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -996,7 +996,7 @@ config MMC_SDHCI_OMAP
config MMC_SDHCI_AM654
tristate "Support for the SDHCI Controller in TI's AM654 SOCs"
- depends on MMC_SDHCI_PLTFM && OF
+ depends on MMC_SDHCI_PLTFM && OF && REGMAP_MMIO
select MMC_SDHCI_IO_ACCESSORS
help
This selects the Secure Digital Host Controller Interface (SDHCI)
diff --git a/drivers/mmc/host/alcor.c b/drivers/mmc/host/alcor.c
index e481535cba2b..1aee485d56d4 100644
--- a/drivers/mmc/host/alcor.c
+++ b/drivers/mmc/host/alcor.c
@@ -672,7 +672,7 @@ static void alcor_set_clock(struct alcor_sdmmc_host *host, unsigned int clock)
tmp_clock = DIV_ROUND_UP(cfg->clk_src_freq, tmp_div);
tmp_diff = abs(clock - tmp_clock);
- if (tmp_diff >= 0 && tmp_diff < diff) {
+ if (tmp_diff < diff) {
diff = tmp_diff;
clk_src = cfg->clk_src_reg;
clk_div = tmp_div;
diff --git a/drivers/mmc/host/android-goldfish.c b/drivers/mmc/host/android-goldfish.c
index 61e4e2a213c9..914e17bab3be 100644
--- a/drivers/mmc/host/android-goldfish.c
+++ b/drivers/mmc/host/android-goldfish.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2007, Google Inc.
* Copyright 2012, Intel Inc.
@@ -7,10 +8,6 @@
* Written by Tuukka Tikkanen and Juha Yrjölä <juha.yrjola@nokia.com>
* Misc hacks here and there by Tony Lindgren <tony@atomide.com>
* Other hacks (DMA, SD, etc) by David Brownell
- *
- * 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.
*/
#include <linux/module.h>
@@ -113,7 +110,6 @@ struct goldfish_mmc_host {
struct mmc_request *mrq;
struct mmc_command *cmd;
struct mmc_data *data;
- struct mmc_host *mmc;
struct device *dev;
unsigned char id; /* 16xx chips have 2 MMC blocks */
void *virt_base;
@@ -175,7 +171,7 @@ goldfish_mmc_start_command(struct goldfish_mmc_host *host, struct mmc_command *c
resptype = 3;
break;
default:
- dev_err(mmc_dev(host->mmc),
+ dev_err(mmc_dev(mmc_from_priv(host)),
"Invalid response type: %04x\n", mmc_resp_type(cmd));
break;
}
@@ -221,8 +217,8 @@ static void goldfish_mmc_xfer_done(struct goldfish_mmc_host *host,
data->sg->length);
}
host->data->bytes_xfered += data->sg->length;
- dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len,
- dma_data_dir);
+ dma_unmap_sg(mmc_dev(mmc_from_priv(host)), data->sg,
+ host->sg_len, dma_data_dir);
}
host->data = NULL;
@@ -236,7 +232,7 @@ static void goldfish_mmc_xfer_done(struct goldfish_mmc_host *host,
if (!data->stop) {
host->mrq = NULL;
- mmc_request_done(host->mmc, data->mrq);
+ mmc_request_done(mmc_from_priv(host), data->mrq);
return;
}
@@ -278,7 +274,7 @@ static void goldfish_mmc_cmd_done(struct goldfish_mmc_host *host,
if (host->data == NULL || cmd->error) {
host->mrq = NULL;
- mmc_request_done(host->mmc, cmd->mrq);
+ mmc_request_done(mmc_from_priv(host), cmd->mrq);
}
}
@@ -313,7 +309,7 @@ static irqreturn_t goldfish_mmc_irq(int irq, void *dev_id)
struct mmc_request *mrq = host->mrq;
mrq->cmd->error = -ETIMEDOUT;
host->mrq = NULL;
- mmc_request_done(host->mmc, mrq);
+ mmc_request_done(mmc_from_priv(host), mrq);
}
if (end_command)
@@ -339,12 +335,13 @@ static irqreturn_t goldfish_mmc_irq(int irq, void *dev_id)
u32 state = GOLDFISH_MMC_READ(host, MMC_STATE);
pr_info("%s: Card detect now %d\n", __func__,
(state & MMC_STATE_INSERTED));
- mmc_detect_change(host->mmc, 0);
+ mmc_detect_change(mmc_from_priv(host), 0);
}
if (!end_command && !end_transfer && !state_changed && !cmd_timeout) {
status = GOLDFISH_MMC_READ(host, MMC_INT_STATUS);
- dev_info(mmc_dev(host->mmc),"spurious irq 0x%04x\n", status);
+ dev_info(mmc_dev(mmc_from_priv(host)), "spurious irq 0x%04x\n",
+ status);
if (status != 0) {
GOLDFISH_MMC_WRITE(host, MMC_INT_STATUS, status);
GOLDFISH_MMC_WRITE(host, MMC_INT_ENABLE, 0);
@@ -383,7 +380,7 @@ static void goldfish_mmc_prepare_data(struct goldfish_mmc_host *host,
dma_data_dir = mmc_get_dma_dir(data);
- host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg,
+ host->sg_len = dma_map_sg(mmc_dev(mmc_from_priv(host)), data->sg,
sg_len, dma_data_dir);
host->dma_done = 0;
host->dma_in_use = 1;
@@ -461,7 +458,6 @@ static int goldfish_mmc_probe(struct platform_device *pdev)
}
host = mmc_priv(mmc);
- host->mmc = mmc;
pr_err("mmc: Mapping %lX to %lX\n", (long)res->start, (long)res->end);
host->reg_base = ioremap(res->start, resource_size(res));
@@ -508,8 +504,7 @@ static int goldfish_mmc_probe(struct platform_device *pdev)
ret = device_create_file(&pdev->dev, &dev_attr_cover_switch);
if (ret)
- dev_warn(mmc_dev(host->mmc),
- "Unable to create sysfs attributes\n");
+ dev_warn(mmc_dev(mmc), "Unable to create sysfs attributes\n");
GOLDFISH_MMC_WRITE(host, MMC_SET_BUFFER, host->phys_base);
GOLDFISH_MMC_WRITE(host, MMC_INT_ENABLE,
@@ -525,7 +520,7 @@ err_request_irq_failed:
dma_alloc_failed:
iounmap(host->reg_base);
ioremap_failed:
- mmc_free_host(host->mmc);
+ mmc_free_host(mmc);
err_alloc_host_failed:
return ret;
}
@@ -533,14 +528,15 @@ err_alloc_host_failed:
static int goldfish_mmc_remove(struct platform_device *pdev)
{
struct goldfish_mmc_host *host = platform_get_drvdata(pdev);
+ struct mmc_host *mmc = mmc_from_priv(host);
BUG_ON(host == NULL);
- mmc_remove_host(host->mmc);
+ mmc_remove_host(mmc);
free_irq(host->irq, host);
dma_free_coherent(&pdev->dev, BUFFER_SIZE, host->virt_base, host->phys_base);
iounmap(host->reg_base);
- mmc_free_host(host->mmc);
+ mmc_free_host(mmc);
return 0;
}
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index 735aa5871358..9ee0bc0ce6d0 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Atmel MultiMedia Card Interface driver
*
* Copyright (C) 2004-2008 Atmel Corporation
- *
- * 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.
*/
#include <linux/blkdev.h>
#include <linux/clk.h>
@@ -579,42 +576,18 @@ static void atmci_init_debugfs(struct atmel_mci_slot *slot)
struct mmc_host *mmc = slot->mmc;
struct atmel_mci *host = slot->host;
struct dentry *root;
- struct dentry *node;
root = mmc->debugfs_root;
if (!root)
return;
- node = debugfs_create_file("regs", S_IRUSR, root, host,
- &atmci_regs_fops);
- if (IS_ERR(node))
- return;
- if (!node)
- goto err;
-
- node = debugfs_create_file("req", S_IRUSR, root, slot,
- &atmci_req_fops);
- if (!node)
- goto err;
-
- node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
- if (!node)
- goto err;
-
- node = debugfs_create_x32("pending_events", S_IRUSR, root,
- (u32 *)&host->pending_events);
- if (!node)
- goto err;
-
- node = debugfs_create_x32("completed_events", S_IRUSR, root,
- (u32 *)&host->completed_events);
- if (!node)
- goto err;
-
- return;
-
-err:
- dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
+ debugfs_create_file("regs", S_IRUSR, root, host, &atmci_regs_fops);
+ debugfs_create_file("req", S_IRUSR, root, slot, &atmci_req_fops);
+ debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
+ debugfs_create_x32("pending_events", S_IRUSR, root,
+ (u32 *)&host->pending_events);
+ debugfs_create_x32("completed_events", S_IRUSR, root,
+ (u32 *)&host->completed_events);
}
#if defined(CONFIG_OF)
diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c
index 9b4be67330dd..bc8aeb47a7b4 100644
--- a/drivers/mmc/host/au1xmmc.c
+++ b/drivers/mmc/host/au1xmmc.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/mmc/host/au1xmmc.c - AU1XX0 MMC driver
*
@@ -16,9 +17,6 @@
* All Rights Reserved.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
/* Why don't we use the SD controllers' carddetect feature?
diff --git a/drivers/mmc/host/cb710-mmc.c b/drivers/mmc/host/cb710-mmc.c
index 4c477dcd2ada..e33270e40539 100644
--- a/drivers/mmc/host/cb710-mmc.c
+++ b/drivers/mmc/host/cb710-mmc.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* cb710/mmc.c
*
* Copyright by Michał Mirosław, 2008-2009
- *
- * 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.
*/
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/mmc/host/cb710-mmc.h b/drivers/mmc/host/cb710-mmc.h
index 8ecd9e56636a..5e053077dbed 100644
--- a/drivers/mmc/host/cb710-mmc.h
+++ b/drivers/mmc/host/cb710-mmc.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* cb710/cb710-mmc.h
*
* Copyright by Michał Mirosław, 2008-2009
- *
- * 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.
*/
#ifndef LINUX_CB710_MMC_H
#define LINUX_CB710_MMC_H
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index b53b6b7d4dd4..faaaf52a46d2 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -169,40 +169,18 @@ static void dw_mci_init_debugfs(struct dw_mci_slot *slot)
struct mmc_host *mmc = slot->mmc;
struct dw_mci *host = slot->host;
struct dentry *root;
- struct dentry *node;
root = mmc->debugfs_root;
if (!root)
return;
- node = debugfs_create_file("regs", S_IRUSR, root, host,
- &dw_mci_regs_fops);
- if (!node)
- goto err;
-
- node = debugfs_create_file("req", S_IRUSR, root, slot,
- &dw_mci_req_fops);
- if (!node)
- goto err;
-
- node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
- if (!node)
- goto err;
-
- node = debugfs_create_x32("pending_events", S_IRUSR, root,
- (u32 *)&host->pending_events);
- if (!node)
- goto err;
-
- node = debugfs_create_x32("completed_events", S_IRUSR, root,
- (u32 *)&host->completed_events);
- if (!node)
- goto err;
-
- return;
-
-err:
- dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
+ debugfs_create_file("regs", S_IRUSR, root, host, &dw_mci_regs_fops);
+ debugfs_create_file("req", S_IRUSR, root, slot, &dw_mci_req_fops);
+ debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
+ debugfs_create_x32("pending_events", S_IRUSR, root,
+ (u32 *)&host->pending_events);
+ debugfs_create_x32("completed_events", S_IRUSR, root,
+ (u32 *)&host->completed_events);
}
#endif /* defined(CONFIG_DEBUG_FS) */
diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c
index 5582561586b4..037311db3551 100644
--- a/drivers/mmc/host/meson-gx-mmc.c
+++ b/drivers/mmc/host/meson-gx-mmc.c
@@ -1,22 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Amlogic SD/eMMC driver for the GX/S905 family SoCs
*
* Copyright (c) 2016 BayLibre, SAS.
* Author: Kevin Hilman <khilman@baylibre.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- * The full GNU General Public License is included in this distribution
- * in the file called COPYING.
*/
#include <linux/kernel.h>
#include <linux/module.h>
@@ -129,6 +116,9 @@
#define SD_EMMC_TXD 0x94
#define SD_EMMC_LAST_REG SD_EMMC_TXD
+#define SD_EMMC_SRAM_DATA_BUF_LEN 1536
+#define SD_EMMC_SRAM_DATA_BUF_OFF 0x200
+
#define SD_EMMC_CFG_BLK_SIZE 512 /* internal buffer max: 512 bytes */
#define SD_EMMC_CFG_RESP_TIMEOUT 256 /* in clock cycles */
#define SD_EMMC_CMD_TIMEOUT 1024 /* in ms */
@@ -168,6 +158,8 @@ struct meson_host {
unsigned long req_rate;
bool ddr;
+ bool dram_access_quirk;
+
struct pinctrl *pinctrl;
struct pinctrl_state *pins_default;
struct pinctrl_state *pins_clk_gate;
@@ -232,12 +224,21 @@ static struct mmc_command *meson_mmc_get_next_command(struct mmc_command *cmd)
static void meson_mmc_get_transfer_mode(struct mmc_host *mmc,
struct mmc_request *mrq)
{
+ struct meson_host *host = mmc_priv(mmc);
struct mmc_data *data = mrq->data;
struct scatterlist *sg;
int i;
bool use_desc_chain_mode = true;
/*
+ * When Controller DMA cannot directly access DDR memory, disable
+ * support for Chain Mode to directly use the internal SRAM using
+ * the bounce buffer mode.
+ */
+ if (host->dram_access_quirk)
+ return;
+
+ /*
* Broken SDIO with AP6255-based WiFi on Khadas VIM Pro has been
* reported. For some strange reason this occurs in descriptor
* chain mode only. So let's fall back to bounce buffer mode
@@ -1049,6 +1050,10 @@ static int meson_mmc_probe(struct platform_device *pdev)
host->dev = &pdev->dev;
dev_set_drvdata(&pdev->dev, host);
+ /* The G12A SDIO Controller needs an SRAM bounce buffer */
+ host->dram_access_quirk = device_property_read_bool(&pdev->dev,
+ "amlogic,dram-access-quirk");
+
/* Get regulators and the supported OCR mask */
host->vqmmc_enabled = false;
ret = mmc_regulator_get_supply(mmc);
@@ -1146,9 +1151,16 @@ static int meson_mmc_probe(struct platform_device *pdev)
goto err_init_clk;
mmc->caps |= MMC_CAP_CMD23;
- mmc->max_blk_count = CMD_CFG_LENGTH_MASK;
+ if (host->dram_access_quirk) {
+ /* Limit to the available sram memory */
+ mmc->max_segs = SD_EMMC_SRAM_DATA_BUF_LEN / mmc->max_blk_size;
+ mmc->max_blk_count = mmc->max_segs;
+ } else {
+ mmc->max_blk_count = CMD_CFG_LENGTH_MASK;
+ mmc->max_segs = SD_EMMC_DESC_BUF_LEN /
+ sizeof(struct sd_emmc_desc);
+ }
mmc->max_req_size = mmc->max_blk_count * mmc->max_blk_size;
- mmc->max_segs = SD_EMMC_DESC_BUF_LEN / sizeof(struct sd_emmc_desc);
mmc->max_seg_size = mmc->max_req_size;
/*
@@ -1158,15 +1170,27 @@ static int meson_mmc_probe(struct platform_device *pdev)
*/
mmc->caps2 &= ~MMC_CAP2_HS400;
- /* data bounce buffer */
- host->bounce_buf_size = mmc->max_req_size;
- host->bounce_buf =
- dma_alloc_coherent(host->dev, host->bounce_buf_size,
- &host->bounce_dma_addr, GFP_KERNEL);
- if (host->bounce_buf == NULL) {
- dev_err(host->dev, "Unable to map allocate DMA bounce buffer.\n");
- ret = -ENOMEM;
- goto err_free_irq;
+ if (host->dram_access_quirk) {
+ /*
+ * The MMC Controller embeds 1,5KiB of internal SRAM
+ * that can be used to be used as bounce buffer.
+ * In the case of the G12A SDIO controller, use these
+ * instead of the DDR memory
+ */
+ host->bounce_buf_size = SD_EMMC_SRAM_DATA_BUF_LEN;
+ host->bounce_buf = host->regs + SD_EMMC_SRAM_DATA_BUF_OFF;
+ host->bounce_dma_addr = res->start + SD_EMMC_SRAM_DATA_BUF_OFF;
+ } else {
+ /* data bounce buffer */
+ host->bounce_buf_size = mmc->max_req_size;
+ host->bounce_buf =
+ dma_alloc_coherent(host->dev, host->bounce_buf_size,
+ &host->bounce_dma_addr, GFP_KERNEL);
+ if (host->bounce_buf == NULL) {
+ dev_err(host->dev, "Unable to map allocate DMA bounce buffer.\n");
+ ret = -ENOMEM;
+ goto err_free_irq;
+ }
}
host->descs = dma_alloc_coherent(host->dev, SD_EMMC_DESC_BUF_LEN,
@@ -1183,8 +1207,9 @@ static int meson_mmc_probe(struct platform_device *pdev)
return 0;
err_bounce_buf:
- dma_free_coherent(host->dev, host->bounce_buf_size,
- host->bounce_buf, host->bounce_dma_addr);
+ if (!host->dram_access_quirk)
+ dma_free_coherent(host->dev, host->bounce_buf_size,
+ host->bounce_buf, host->bounce_dma_addr);
err_free_irq:
free_irq(host->irq, host);
err_init_clk:
@@ -1208,8 +1233,10 @@ static int meson_mmc_remove(struct platform_device *pdev)
dma_free_coherent(host->dev, SD_EMMC_DESC_BUF_LEN,
host->descs, host->descs_dma_addr);
- dma_free_coherent(host->dev, host->bounce_buf_size,
- host->bounce_buf, host->bounce_dma_addr);
+
+ if (!host->dram_access_quirk)
+ dma_free_coherent(host->dev, host->bounce_buf_size,
+ host->bounce_buf, host->bounce_dma_addr);
clk_disable_unprepare(host->mmc_clk);
clk_disable_unprepare(host->core_clk);
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 356833a606d5..b8554bf38f72 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/mmc/host/mmci.c - ARM PrimeCell MMCI PL180/1 driver
*
* Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
* Copyright (C) 2010 ST-Ericsson SA
- *
- * 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.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index 4f071bd34e59..833236ecb31e 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/drivers/mmc/host/mmci.h - ARM PrimeCell MMCI PL180/1 driver
*
* Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#define MMCIPOWER 0x000
#define MCI_PWR_OFF 0x00
diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index 5a6d885994e6..33f4b6387ef7 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -1023,6 +1023,8 @@ static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq)
msdc_track_cmd_data(host, mrq->cmd, mrq->data);
if (mrq->data)
msdc_unprepare_data(host, mrq);
+ if (host->error)
+ msdc_reset_hw(host);
mmc_request_done(host->mmc, mrq);
}
@@ -1375,24 +1377,25 @@ static void msdc_request_timeout(struct work_struct *work)
}
}
-static void __msdc_enable_sdio_irq(struct mmc_host *mmc, int enb)
+static void __msdc_enable_sdio_irq(struct msdc_host *host, int enb)
{
- unsigned long flags;
- struct msdc_host *host = mmc_priv(mmc);
-
- spin_lock_irqsave(&host->lock, flags);
- if (enb)
+ if (enb) {
sdr_set_bits(host->base + MSDC_INTEN, MSDC_INTEN_SDIOIRQ);
- else
+ sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE);
+ } else {
sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INTEN_SDIOIRQ);
- spin_unlock_irqrestore(&host->lock, flags);
+ sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE);
+ }
}
static void msdc_enable_sdio_irq(struct mmc_host *mmc, int enb)
{
+ unsigned long flags;
struct msdc_host *host = mmc_priv(mmc);
- __msdc_enable_sdio_irq(mmc, enb);
+ spin_lock_irqsave(&host->lock, flags);
+ __msdc_enable_sdio_irq(host, enb);
+ spin_unlock_irqrestore(&host->lock, flags);
if (enb)
pm_runtime_get_noresume(host->dev);
@@ -1414,6 +1417,8 @@ static irqreturn_t msdc_irq(int irq, void *dev_id)
spin_lock_irqsave(&host->lock, flags);
events = readl(host->base + MSDC_INT);
event_mask = readl(host->base + MSDC_INTEN);
+ if ((events & event_mask) & MSDC_INT_SDIOIRQ)
+ __msdc_enable_sdio_irq(host, 0);
/* clear interrupts */
writel(events & event_mask, host->base + MSDC_INT);
@@ -1422,10 +1427,8 @@ static irqreturn_t msdc_irq(int irq, void *dev_id)
data = host->data;
spin_unlock_irqrestore(&host->lock, flags);
- if ((events & event_mask) & MSDC_INT_SDIOIRQ) {
- __msdc_enable_sdio_irq(host->mmc, 0);
+ if ((events & event_mask) & MSDC_INT_SDIOIRQ)
sdio_signal_irq(host->mmc);
- }
if ((events & event_mask) & MSDC_INT_CDSC) {
if (host->internal_cd)
@@ -1564,10 +1567,7 @@ static void msdc_init_hw(struct msdc_host *host)
sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIO);
/* Config SDIO device detect interrupt function */
- if (host->mmc->caps & MMC_CAP_SDIO_IRQ)
- sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE);
- else
- sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE);
+ sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE);
/* Configure to default data timeout */
sdr_set_field(host->base + SDC_CFG, SDC_CFG_DTOC, 3);
@@ -2095,7 +2095,12 @@ static void msdc_hw_reset(struct mmc_host *mmc)
static void msdc_ack_sdio_irq(struct mmc_host *mmc)
{
- __msdc_enable_sdio_irq(mmc, 1);
+ unsigned long flags;
+ struct msdc_host *host = mmc_priv(mmc);
+
+ spin_lock_irqsave(&host->lock, flags);
+ __msdc_enable_sdio_irq(host, 1);
+ spin_unlock_irqrestore(&host->lock, flags);
}
static int msdc_get_cd(struct mmc_host *mmc)
diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c
index 9cb93e15b197..74a0a7fbbf7f 100644
--- a/drivers/mmc/host/mvsdio.c
+++ b/drivers/mmc/host/mvsdio.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Marvell MMC/SD/SDIO driver
*
* Authors: Maen Suleiman, Nicolas Pitre
* Copyright (C) 2008-2009 Marvell Ltd.
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/mmc/host/mvsdio.h b/drivers/mmc/host/mvsdio.h
index 7d9727b9f5aa..2f1458ac6cc3 100644
--- a/drivers/mmc/host/mvsdio.h
+++ b/drivers/mmc/host/mvsdio.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2008 Marvell Semiconductors, All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#ifndef __MVSDIO_H
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c
index 45f7b9b53d48..750604f7fac9 100644
--- a/drivers/mmc/host/mxcmmc.c
+++ b/drivers/mmc/host/mxcmmc.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/mmc/host/mxcmmc.c - Freescale i.MX MMCI driver
*
@@ -10,11 +11,6 @@
* Copyright (C) 2006 Pavel Pisa, PiKRON <ppisa@pikron.com>
*
* derived from pxamci.c by Russell King
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
index b2873a2432b6..d74e73c95fdf 100644
--- a/drivers/mmc/host/omap.c
+++ b/drivers/mmc/host/omap.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/mmc/host/omap.c
*
@@ -5,10 +6,6 @@
* Written by Tuukka Tikkanen and Juha Yrjölä<juha.yrjola@nokia.com>
* Misc hacks here and there by Tony Lindgren <tony@atomide.com>
* Other hacks (DMA, SD, etc) by David Brownell
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index e7d80c83da2c..024acc1b0a2e 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/mmc/host/pxa.c - PXA MMCI driver
*
* Copyright (C) 2003 Russell King, All Rights Reserved.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* This hardware is really sick:
* - No way to clear interrupts.
* - Have to turn off the clock whenever we touch the device.
diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
index 5e9e36ed2107..64d3b5fb7fe5 100644
--- a/drivers/mmc/host/renesas_sdhi_core.c
+++ b/drivers/mmc/host/renesas_sdhi_core.c
@@ -610,21 +610,25 @@ static void renesas_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable)
renesas_sdhi_sdbuf_width(host, enable ? width : 16);
}
-static const struct renesas_sdhi_quirks sdhi_quirks_h3_m3w_es1 = {
+static const struct renesas_sdhi_quirks sdhi_quirks_4tap_nohs400 = {
.hs400_disabled = true,
.hs400_4taps = true,
};
-static const struct renesas_sdhi_quirks sdhi_quirks_h3_es2 = {
- .hs400_disabled = false,
+static const struct renesas_sdhi_quirks sdhi_quirks_4tap = {
.hs400_4taps = true,
};
+static const struct renesas_sdhi_quirks sdhi_quirks_nohs400 = {
+ .hs400_disabled = true,
+};
+
static const struct soc_device_attribute sdhi_quirks_match[] = {
- { .soc_id = "r8a7795", .revision = "ES1.*", .data = &sdhi_quirks_h3_m3w_es1 },
- { .soc_id = "r8a7795", .revision = "ES2.0", .data = &sdhi_quirks_h3_es2 },
- { .soc_id = "r8a7796", .revision = "ES1.0", .data = &sdhi_quirks_h3_m3w_es1 },
- { .soc_id = "r8a7796", .revision = "ES1.1", .data = &sdhi_quirks_h3_m3w_es1 },
+ { .soc_id = "r8a7795", .revision = "ES1.*", .data = &sdhi_quirks_4tap_nohs400 },
+ { .soc_id = "r8a7795", .revision = "ES2.0", .data = &sdhi_quirks_4tap },
+ { .soc_id = "r8a7796", .revision = "ES1.[012]", .data = &sdhi_quirks_4tap_nohs400 },
+ { .soc_id = "r8a774a1", .revision = "ES1.[012]", .data = &sdhi_quirks_4tap_nohs400 },
+ { .soc_id = "r8a77980", .data = &sdhi_quirks_nohs400 },
{ /* Sentinel. */ },
};
@@ -770,6 +774,8 @@ int renesas_sdhi_probe(struct platform_device *pdev,
/* All SDHI have SDIO status bits which must be 1 */
mmc_data->flags |= TMIO_MMC_SDIO_STATUS_SETBITS;
+ pm_runtime_enable(&pdev->dev);
+
ret = renesas_sdhi_clk_enable(host);
if (ret)
goto efree;
@@ -850,6 +856,8 @@ edisclk:
efree:
tmio_mmc_host_free(host);
+ pm_runtime_disable(&pdev->dev);
+
return ret;
}
EXPORT_SYMBOL_GPL(renesas_sdhi_probe);
@@ -861,6 +869,8 @@ int renesas_sdhi_remove(struct platform_device *pdev)
tmio_mmc_host_remove(host);
renesas_sdhi_clk_disable(host);
+ pm_runtime_disable(&pdev->dev);
+
return 0;
}
EXPORT_SYMBOL_GPL(renesas_sdhi_remove);
diff --git a/drivers/mmc/host/rtsx_usb_sdmmc.c b/drivers/mmc/host/rtsx_usb_sdmmc.c
index 669c6ab021c8..81d0dfe553a8 100644
--- a/drivers/mmc/host/rtsx_usb_sdmmc.c
+++ b/drivers/mmc/host/rtsx_usb_sdmmc.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* Realtek USB SD/MMC Card Interface driver
*
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
* Author:
* Roger Tseng <rogerable@realtek.com>
*/
diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c
index f31333e831a7..ccc5f095775f 100644
--- a/drivers/mmc/host/s3cmci.c
+++ b/drivers/mmc/host/s3cmci.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/mmc/s3cmci.h - Samsung S3C MCI driver
*
@@ -5,10 +6,6 @@
*
* Current driver maintained by Ben Dooks and Simtec Electronics
* Copyright (C) 2008 Simtec Electronics <ben-linux@fluff.org>
- *
- * 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.
*/
#include <linux/module.h>
@@ -1452,33 +1449,18 @@ DEFINE_SHOW_ATTRIBUTE(s3cmci_regs);
static void s3cmci_debugfs_attach(struct s3cmci_host *host)
{
struct device *dev = &host->pdev->dev;
+ struct dentry *root;
- host->debug_root = debugfs_create_dir(dev_name(dev), NULL);
- if (IS_ERR(host->debug_root)) {
- dev_err(dev, "failed to create debugfs root\n");
- return;
- }
-
- host->debug_state = debugfs_create_file("state", 0444,
- host->debug_root, host,
- &s3cmci_state_fops);
-
- if (IS_ERR(host->debug_state))
- dev_err(dev, "failed to create debug state file\n");
-
- host->debug_regs = debugfs_create_file("regs", 0444,
- host->debug_root, host,
- &s3cmci_regs_fops);
+ root = debugfs_create_dir(dev_name(dev), NULL);
+ host->debug_root = root;
- if (IS_ERR(host->debug_regs))
- dev_err(dev, "failed to create debug regs file\n");
+ debugfs_create_file("state", 0444, root, host, &s3cmci_state_fops);
+ debugfs_create_file("regs", 0444, root, host, &s3cmci_regs_fops);
}
static void s3cmci_debugfs_remove(struct s3cmci_host *host)
{
- debugfs_remove(host->debug_regs);
- debugfs_remove(host->debug_state);
- debugfs_remove(host->debug_root);
+ debugfs_remove_recursive(host->debug_root);
}
#else
diff --git a/drivers/mmc/host/s3cmci.h b/drivers/mmc/host/s3cmci.h
index 30c2c0dd1bc8..8b65d7ad9f97 100644
--- a/drivers/mmc/host/s3cmci.h
+++ b/drivers/mmc/host/s3cmci.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/drivers/mmc/s3cmci.h - Samsung S3C MCI driver
*
* Copyright (C) 2004-2006 Thomas Kleffel, All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
enum s3cmci_waitfor {
@@ -70,8 +67,6 @@ struct s3cmci_host {
#ifdef CONFIG_DEBUG_FS
struct dentry *debug_root;
- struct dentry *debug_state;
- struct dentry *debug_regs;
#endif
#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
diff --git a/drivers/mmc/host/sdhci-cns3xxx.c b/drivers/mmc/host/sdhci-cns3xxx.c
index bd286db7f9af..811eab1b8964 100644
--- a/drivers/mmc/host/sdhci-cns3xxx.c
+++ b/drivers/mmc/host/sdhci-cns3xxx.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* SDHCI support for CNS3xxx SoC
*
@@ -6,10 +7,6 @@
*
* Authors: Scott Shu
* Anton Vorontsov <avorontsov@mvista.com>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 5fc76a1993d0..9cf14b359c14 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -575,11 +575,14 @@ static int msm_init_cm_dll(struct sdhci_host *host)
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
int wait_cnt = 50;
- unsigned long flags;
+ unsigned long flags, xo_clk = 0;
u32 config;
const struct sdhci_msm_offset *msm_offset =
msm_host->offset;
+ if (msm_host->use_14lpp_dll_reset && !IS_ERR_OR_NULL(msm_host->xo_clk))
+ xo_clk = clk_get_rate(msm_host->xo_clk);
+
spin_lock_irqsave(&host->lock, flags);
/*
@@ -627,10 +630,10 @@ static int msm_init_cm_dll(struct sdhci_host *host)
config &= CORE_FLL_CYCLE_CNT;
if (config)
mclk_freq = DIV_ROUND_CLOSEST_ULL((host->clock * 8),
- clk_get_rate(msm_host->xo_clk));
+ xo_clk);
else
mclk_freq = DIV_ROUND_CLOSEST_ULL((host->clock * 4),
- clk_get_rate(msm_host->xo_clk));
+ xo_clk);
config = readl_relaxed(host->ioaddr +
msm_offset->core_dll_config_2);
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index 68c5866f5c85..4dd43b1adf2c 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -830,9 +830,17 @@ static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
bool hs400_tuning;
+ unsigned int clk;
u32 val;
int ret;
+ /* For tuning mode, the sd clock divisor value
+ * must be larger than 3 according to reference manual.
+ */
+ clk = esdhc->peripheral_clock / 3;
+ if (host->clock > clk)
+ esdhc_of_set_clock(host, clk);
+
if (esdhc->quirk_limited_clk_division &&
host->flags & SDHCI_HS400_TUNING)
esdhc_of_set_clock(host, host->clock);
@@ -1040,11 +1048,12 @@ static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host)
/*
* esdhc->peripheral_clock would be assigned with a value
* which is eSDHC base clock when use periperal clock.
- * For ls1046a, the clock value got by common clk API is
- * peripheral clock while the eSDHC base clock is 1/2
- * peripheral clock.
+ * For some platforms, the clock value got by common clk
+ * API is peripheral clock while the eSDHC base clock is
+ * 1/2 peripheral clock.
*/
- if (of_device_is_compatible(np, "fsl,ls1046a-esdhc"))
+ if (of_device_is_compatible(np, "fsl,ls1046a-esdhc") ||
+ of_device_is_compatible(np, "fsl,ls1028a-esdhc"))
esdhc->peripheral_clock = clk_get_rate(clk) / 2;
else
esdhc->peripheral_clock = clk_get_rate(clk);
diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c
index 4154ee11b47d..4041878eb0f3 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -1668,6 +1668,8 @@ static const struct pci_device_id pci_ids[] = {
SDHCI_PCI_DEVICE(INTEL, CNPH_SD, intel_byt_sd),
SDHCI_PCI_DEVICE(INTEL, ICP_EMMC, intel_glk_emmc),
SDHCI_PCI_DEVICE(INTEL, ICP_SD, intel_byt_sd),
+ SDHCI_PCI_DEVICE(INTEL, EHL_EMMC, intel_glk_emmc),
+ SDHCI_PCI_DEVICE(INTEL, EHL_SD, intel_byt_sd),
SDHCI_PCI_DEVICE(INTEL, CML_EMMC, intel_glk_emmc),
SDHCI_PCI_DEVICE(INTEL, CML_SD, intel_byt_sd),
SDHCI_PCI_DEVICE(O2, 8120, o2),
@@ -2040,8 +2042,6 @@ static int sdhci_pci_probe(struct pci_dev *pdev,
slots = PCI_SLOT_INFO_SLOTS(slots) + 1;
dev_dbg(&pdev->dev, "found %d slot(s)\n", slots);
- if (slots == 0)
- return -ENODEV;
BUG_ON(slots > MAX_SLOTS);
diff --git a/drivers/mmc/host/sdhci-pci-o2micro.c b/drivers/mmc/host/sdhci-pci-o2micro.c
index b29bf4e7dcb4..9dc4548271b4 100644
--- a/drivers/mmc/host/sdhci-pci-o2micro.c
+++ b/drivers/mmc/host/sdhci-pci-o2micro.c
@@ -115,6 +115,7 @@ static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode)
*/
if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) {
current_bus_width = mmc->ios.bus_width;
+ mmc->ios.bus_width = MMC_BUS_WIDTH_4;
sdhci_set_bus_width(host, MMC_BUS_WIDTH_4);
}
@@ -126,8 +127,10 @@ static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode)
sdhci_end_tuning(host);
- if (current_bus_width == MMC_BUS_WIDTH_8)
+ if (current_bus_width == MMC_BUS_WIDTH_8) {
+ mmc->ios.bus_width = MMC_BUS_WIDTH_8;
sdhci_set_bus_width(host, current_bus_width);
+ }
host->flags &= ~SDHCI_HS400_TUNING;
return 0;
@@ -392,11 +395,21 @@ int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot)
{
struct sdhci_pci_chip *chip;
struct sdhci_host *host;
- u32 reg;
+ u32 reg, caps;
int ret;
chip = slot->chip;
host = slot->host;
+
+ caps = sdhci_readl(host, SDHCI_CAPABILITIES);
+
+ /*
+ * mmc_select_bus_width() will test the bus to determine the actual bus
+ * width.
+ */
+ if (caps & SDHCI_CAN_DO_8BIT)
+ host->mmc->caps |= MMC_CAP_8_BIT_DATA;
+
switch (chip->pdev->device) {
case PCI_DEVICE_ID_O2_SDS0:
case PCI_DEVICE_ID_O2_SEABIRD0:
diff --git a/drivers/mmc/host/sdhci-pci.h b/drivers/mmc/host/sdhci-pci.h
index e5dc6e44c7a4..cdd15f357d01 100644
--- a/drivers/mmc/host/sdhci-pci.h
+++ b/drivers/mmc/host/sdhci-pci.h
@@ -50,6 +50,8 @@
#define PCI_DEVICE_ID_INTEL_CNPH_SD 0xa375
#define PCI_DEVICE_ID_INTEL_ICP_EMMC 0x34c4
#define PCI_DEVICE_ID_INTEL_ICP_SD 0x34f8
+#define PCI_DEVICE_ID_INTEL_EHL_EMMC 0x4b47
+#define PCI_DEVICE_ID_INTEL_EHL_SD 0x4b48
#define PCI_DEVICE_ID_INTEL_CML_EMMC 0x02c4
#define PCI_DEVICE_ID_INTEL_CML_SD 0x02f5
diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
index 6109987fc3b5..2af445b8c325 100644
--- a/drivers/mmc/host/sdhci-pltfm.h
+++ b/drivers/mmc/host/sdhci-pltfm.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2010 MontaVista Software, LLC.
*
* Author: Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * 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.
*/
#ifndef _DRIVERS_MMC_SDHCI_PLTFM_H
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
index 9ef89d00970e..8e4a8ba33f05 100644
--- a/drivers/mmc/host/sdhci-s3c.c
+++ b/drivers/mmc/host/sdhci-s3c.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* linux/drivers/mmc/host/sdhci-s3c.c
*
* Copyright 2008 Openmoko Inc.
@@ -6,10 +7,6 @@
* http://armlinux.simtec.co.uk/
*
* SDHCI (HSMMC) support for Samsung SoC
- *
- * 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.
*/
#include <linux/spinlock.h>
diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c
index 9a822e2e9f0b..6ee340a3fb3a 100644
--- a/drivers/mmc/host/sdhci-sprd.c
+++ b/drivers/mmc/host/sdhci-sprd.c
@@ -12,6 +12,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
@@ -22,6 +23,15 @@
/* SDHCI_ARGUMENT2 register high 16bit */
#define SDHCI_SPRD_ARG2_STUFF GENMASK(31, 16)
+#define SDHCI_SPRD_REG_32_DLL_CFG 0x200
+#define SDHCI_SPRD_DLL_ALL_CPST_EN (BIT(18) | BIT(24) | BIT(25) | BIT(26) | BIT(27))
+#define SDHCI_SPRD_DLL_EN BIT(21)
+#define SDHCI_SPRD_DLL_SEARCH_MODE BIT(16)
+#define SDHCI_SPRD_DLL_INIT_COUNT 0xc00
+#define SDHCI_SPRD_DLL_PHASE_INTERNAL 0x3
+
+#define SDHCI_SPRD_REG_32_DLL_DLY 0x204
+
#define SDHCI_SPRD_REG_32_DLL_DLY_OFFSET 0x208
#define SDHCIBSPRD_IT_WR_DLY_INV BIT(5)
#define SDHCI_SPRD_BIT_CMD_DLY_INV BIT(13)
@@ -41,6 +51,7 @@
/* SDHCI_HOST_CONTROL2 */
#define SDHCI_SPRD_CTRL_HS200 0x0005
#define SDHCI_SPRD_CTRL_HS400 0x0006
+#define SDHCI_SPRD_CTRL_HS400ES 0x0007
/*
* According to the standard specification, BIT(3) of SDHCI_SOFTWARE_RESET is
@@ -55,13 +66,36 @@
#define SDHCI_SPRD_CLK_MAX_DIV 1023
#define SDHCI_SPRD_CLK_DEF_RATE 26000000
+#define SDHCI_SPRD_PHY_DLL_CLK 52000000
struct sdhci_sprd_host {
u32 version;
struct clk *clk_sdio;
struct clk *clk_enable;
+ struct clk *clk_2x_enable;
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pins_uhs;
+ struct pinctrl_state *pins_default;
u32 base_rate;
int flags; /* backup of host attribute */
+ u32 phy_delay[MMC_TIMING_MMC_HS400 + 2];
+};
+
+struct sdhci_sprd_phy_cfg {
+ const char *property;
+ u8 timing;
+};
+
+static const struct sdhci_sprd_phy_cfg sdhci_sprd_phy_cfgs[] = {
+ { "sprd,phy-delay-legacy", MMC_TIMING_LEGACY, },
+ { "sprd,phy-delay-sd-highspeed", MMC_TIMING_SD_HS, },
+ { "sprd,phy-delay-sd-uhs-sdr50", MMC_TIMING_UHS_SDR50, },
+ { "sprd,phy-delay-sd-uhs-sdr104", MMC_TIMING_UHS_SDR104, },
+ { "sprd,phy-delay-mmc-highspeed", MMC_TIMING_MMC_HS, },
+ { "sprd,phy-delay-mmc-ddr52", MMC_TIMING_MMC_DDR52, },
+ { "sprd,phy-delay-mmc-hs200", MMC_TIMING_MMC_HS200, },
+ { "sprd,phy-delay-mmc-hs400", MMC_TIMING_MMC_HS400, },
+ { "sprd,phy-delay-mmc-hs400es", MMC_TIMING_MMC_HS400 + 1, },
};
#define TO_SPRD_HOST(host) sdhci_pltfm_priv(sdhci_priv(host))
@@ -131,6 +165,15 @@ static inline void sdhci_sprd_sd_clk_off(struct sdhci_host *host)
sdhci_writew(host, ctrl, SDHCI_CLOCK_CONTROL);
}
+static inline void sdhci_sprd_sd_clk_on(struct sdhci_host *host)
+{
+ u16 ctrl;
+
+ ctrl = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+ ctrl |= SDHCI_CLOCK_CARD_EN;
+ sdhci_writew(host, ctrl, SDHCI_CLOCK_CONTROL);
+}
+
static inline void
sdhci_sprd_set_dll_invert(struct sdhci_host *host, u32 mask, bool en)
{
@@ -189,9 +232,33 @@ static inline void _sdhci_sprd_set_clock(struct sdhci_host *host,
}
}
+static void sdhci_sprd_enable_phy_dll(struct sdhci_host *host)
+{
+ u32 tmp;
+
+ tmp = sdhci_readl(host, SDHCI_SPRD_REG_32_DLL_CFG);
+ tmp &= ~(SDHCI_SPRD_DLL_EN | SDHCI_SPRD_DLL_ALL_CPST_EN);
+ sdhci_writel(host, tmp, SDHCI_SPRD_REG_32_DLL_CFG);
+ /* wait 1ms */
+ usleep_range(1000, 1250);
+
+ tmp = sdhci_readl(host, SDHCI_SPRD_REG_32_DLL_CFG);
+ tmp |= SDHCI_SPRD_DLL_ALL_CPST_EN | SDHCI_SPRD_DLL_SEARCH_MODE |
+ SDHCI_SPRD_DLL_INIT_COUNT | SDHCI_SPRD_DLL_PHASE_INTERNAL;
+ sdhci_writel(host, tmp, SDHCI_SPRD_REG_32_DLL_CFG);
+ /* wait 1ms */
+ usleep_range(1000, 1250);
+
+ tmp = sdhci_readl(host, SDHCI_SPRD_REG_32_DLL_CFG);
+ tmp |= SDHCI_SPRD_DLL_EN;
+ sdhci_writel(host, tmp, SDHCI_SPRD_REG_32_DLL_CFG);
+ /* wait 1ms */
+ usleep_range(1000, 1250);
+}
+
static void sdhci_sprd_set_clock(struct sdhci_host *host, unsigned int clock)
{
- bool en = false;
+ bool en = false, clk_changed = false;
if (clock == 0) {
sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
@@ -203,9 +270,19 @@ static void sdhci_sprd_set_clock(struct sdhci_host *host, unsigned int clock)
en = true;
sdhci_sprd_set_dll_invert(host, SDHCI_SPRD_BIT_CMD_DLY_INV |
SDHCI_SPRD_BIT_POSRD_DLY_INV, en);
+ clk_changed = true;
} else {
_sdhci_sprd_set_clock(host, clock);
}
+
+ /*
+ * According to the Spreadtrum SD host specification, when we changed
+ * the clock to be more than 52M, we should enable the PHY DLL which
+ * is used to track the clock frequency to make the clock work more
+ * stable. Otherwise deviation may occur of the higher clock.
+ */
+ if (clk_changed && clock > SDHCI_SPRD_PHY_DLL_CLK)
+ sdhci_sprd_enable_phy_dll(host);
}
static unsigned int sdhci_sprd_get_max_clock(struct sdhci_host *host)
@@ -223,6 +300,9 @@ static unsigned int sdhci_sprd_get_min_clock(struct sdhci_host *host)
static void sdhci_sprd_set_uhs_signaling(struct sdhci_host *host,
unsigned int timing)
{
+ struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
+ struct mmc_host *mmc = host->mmc;
+ u32 *p = sprd_host->phy_delay;
u16 ctrl_2;
if (timing == host->timing)
@@ -261,6 +341,9 @@ static void sdhci_sprd_set_uhs_signaling(struct sdhci_host *host,
}
sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+
+ if (!mmc->ios.enhanced_strobe)
+ sdhci_writel(host, p[timing], SDHCI_SPRD_REG_32_DLL_DLY);
}
static void sdhci_sprd_hw_reset(struct sdhci_host *host)
@@ -284,6 +367,12 @@ static void sdhci_sprd_hw_reset(struct sdhci_host *host)
usleep_range(300, 500);
}
+static unsigned int sdhci_sprd_get_max_timeout_count(struct sdhci_host *host)
+{
+ /* The Spredtrum controller actual maximum timeout count is 1 << 31 */
+ return 1 << 31;
+}
+
static struct sdhci_ops sdhci_sprd_ops = {
.read_l = sdhci_sprd_readl,
.write_l = sdhci_sprd_writel,
@@ -295,6 +384,7 @@ static struct sdhci_ops sdhci_sprd_ops = {
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_sprd_set_uhs_signaling,
.hw_reset = sdhci_sprd_hw_reset,
+ .get_max_timeout_count = sdhci_sprd_get_max_timeout_count,
};
static void sdhci_sprd_request(struct mmc_host *mmc, struct mmc_request *mrq)
@@ -317,6 +407,99 @@ static void sdhci_sprd_request(struct mmc_host *mmc, struct mmc_request *mrq)
sdhci_request(mmc, mrq);
}
+static int sdhci_sprd_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
+ int ret;
+
+ if (!IS_ERR(mmc->supply.vqmmc)) {
+ ret = mmc_regulator_set_vqmmc(mmc, ios);
+ if (ret) {
+ pr_err("%s: Switching signalling voltage failed\n",
+ mmc_hostname(mmc));
+ return ret;
+ }
+ }
+
+ if (IS_ERR(sprd_host->pinctrl))
+ return 0;
+
+ switch (ios->signal_voltage) {
+ case MMC_SIGNAL_VOLTAGE_180:
+ ret = pinctrl_select_state(sprd_host->pinctrl,
+ sprd_host->pins_uhs);
+ if (ret) {
+ pr_err("%s: failed to select uhs pin state\n",
+ mmc_hostname(mmc));
+ return ret;
+ }
+ break;
+
+ default:
+ /* fall-through */
+ case MMC_SIGNAL_VOLTAGE_330:
+ ret = pinctrl_select_state(sprd_host->pinctrl,
+ sprd_host->pins_default);
+ if (ret) {
+ pr_err("%s: failed to select default pin state\n",
+ mmc_hostname(mmc));
+ return ret;
+ }
+ break;
+ }
+
+ /* Wait for 300 ~ 500 us for pin state stable */
+ usleep_range(300, 500);
+ sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+
+ return 0;
+}
+
+static void sdhci_sprd_hs400_enhanced_strobe(struct mmc_host *mmc,
+ struct mmc_ios *ios)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
+ u32 *p = sprd_host->phy_delay;
+ u16 ctrl_2;
+
+ if (!ios->enhanced_strobe)
+ return;
+
+ sdhci_sprd_sd_clk_off(host);
+
+ /* Set HS400 enhanced strobe mode */
+ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
+ ctrl_2 |= SDHCI_SPRD_CTRL_HS400ES;
+ sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+
+ sdhci_sprd_sd_clk_on(host);
+
+ /* Set the PHY DLL delay value for HS400 enhanced strobe mode */
+ sdhci_writel(host, p[MMC_TIMING_MMC_HS400 + 1],
+ SDHCI_SPRD_REG_32_DLL_DLY);
+}
+
+static void sdhci_sprd_phy_param_parse(struct sdhci_sprd_host *sprd_host,
+ struct device_node *np)
+{
+ u32 *p = sprd_host->phy_delay;
+ int ret, i, index;
+ u32 val[4];
+
+ for (i = 0; i < ARRAY_SIZE(sdhci_sprd_phy_cfgs); i++) {
+ ret = of_property_read_u32_array(np,
+ sdhci_sprd_phy_cfgs[i].property, val, 4);
+ if (ret)
+ continue;
+
+ index = sdhci_sprd_phy_cfgs[i].timing;
+ p[index] = val[0] | (val[1] << 8) | (val[2] << 16) | (val[3] << 24);
+ }
+}
+
static const struct sdhci_pltfm_data sdhci_sprd_pdata = {
.quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK,
.quirks2 = SDHCI_QUIRK2_BROKEN_HS200 |
@@ -338,6 +521,16 @@ static int sdhci_sprd_probe(struct platform_device *pdev)
host->dma_mask = DMA_BIT_MASK(64);
pdev->dev.dma_mask = &host->dma_mask;
host->mmc_host_ops.request = sdhci_sprd_request;
+ host->mmc_host_ops.hs400_enhanced_strobe =
+ sdhci_sprd_hs400_enhanced_strobe;
+ /*
+ * We can not use the standard ops to change and detect the voltage
+ * signal for Spreadtrum SD host controller, since our voltage regulator
+ * for I/O is fixed in hardware, that means we do not need control
+ * the standard SD host controller to change the I/O voltage.
+ */
+ host->mmc_host_ops.start_signal_voltage_switch =
+ sdhci_sprd_voltage_switch;
host->mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED |
MMC_CAP_ERASE | MMC_CAP_CMD23;
@@ -346,6 +539,24 @@ static int sdhci_sprd_probe(struct platform_device *pdev)
goto pltfm_free;
sprd_host = TO_SPRD_HOST(host);
+ sdhci_sprd_phy_param_parse(sprd_host, pdev->dev.of_node);
+
+ sprd_host->pinctrl = devm_pinctrl_get(&pdev->dev);
+ if (!IS_ERR(sprd_host->pinctrl)) {
+ sprd_host->pins_uhs =
+ pinctrl_lookup_state(sprd_host->pinctrl, "state_uhs");
+ if (IS_ERR(sprd_host->pins_uhs)) {
+ ret = PTR_ERR(sprd_host->pins_uhs);
+ goto pltfm_free;
+ }
+
+ sprd_host->pins_default =
+ pinctrl_lookup_state(sprd_host->pinctrl, "default");
+ if (IS_ERR(sprd_host->pins_default)) {
+ ret = PTR_ERR(sprd_host->pins_default);
+ goto pltfm_free;
+ }
+ }
clk = devm_clk_get(&pdev->dev, "sdio");
if (IS_ERR(clk)) {
@@ -364,14 +575,22 @@ static int sdhci_sprd_probe(struct platform_device *pdev)
}
sprd_host->clk_enable = clk;
+ clk = devm_clk_get(&pdev->dev, "2x_enable");
+ if (!IS_ERR(clk))
+ sprd_host->clk_2x_enable = clk;
+
ret = clk_prepare_enable(sprd_host->clk_sdio);
if (ret)
goto pltfm_free;
- clk_prepare_enable(sprd_host->clk_enable);
+ ret = clk_prepare_enable(sprd_host->clk_enable);
if (ret)
goto clk_disable;
+ ret = clk_prepare_enable(sprd_host->clk_2x_enable);
+ if (ret)
+ goto clk_disable2;
+
sdhci_sprd_init_config(host);
host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
sprd_host->version = ((host->version & SDHCI_VENDOR_VER_MASK) >>
@@ -408,6 +627,9 @@ pm_runtime_disable:
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
+ clk_disable_unprepare(sprd_host->clk_2x_enable);
+
+clk_disable2:
clk_disable_unprepare(sprd_host->clk_enable);
clk_disable:
@@ -427,6 +649,7 @@ static int sdhci_sprd_remove(struct platform_device *pdev)
mmc_remove_host(mmc);
clk_disable_unprepare(sprd_host->clk_sdio);
clk_disable_unprepare(sprd_host->clk_enable);
+ clk_disable_unprepare(sprd_host->clk_2x_enable);
mmc_free_host(mmc);
@@ -449,6 +672,7 @@ static int sdhci_sprd_runtime_suspend(struct device *dev)
clk_disable_unprepare(sprd_host->clk_sdio);
clk_disable_unprepare(sprd_host->clk_enable);
+ clk_disable_unprepare(sprd_host->clk_2x_enable);
return 0;
}
@@ -459,19 +683,28 @@ static int sdhci_sprd_runtime_resume(struct device *dev)
struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
int ret;
- ret = clk_prepare_enable(sprd_host->clk_enable);
+ ret = clk_prepare_enable(sprd_host->clk_2x_enable);
if (ret)
return ret;
+ ret = clk_prepare_enable(sprd_host->clk_enable);
+ if (ret)
+ goto clk_2x_disable;
+
ret = clk_prepare_enable(sprd_host->clk_sdio);
- if (ret) {
- clk_disable_unprepare(sprd_host->clk_enable);
- return ret;
- }
+ if (ret)
+ goto clk_disable;
sdhci_runtime_resume_host(host);
-
return 0;
+
+clk_disable:
+ clk_disable_unprepare(sprd_host->clk_enable);
+
+clk_2x_disable:
+ clk_disable_unprepare(sprd_host->clk_2x_enable);
+
+ return ret;
}
#endif
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index 781a3e106d9a..f4d4761cf20a 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -1541,8 +1541,11 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
clk = devm_clk_get(mmc_dev(host->mmc), NULL);
if (IS_ERR(clk)) {
- dev_err(mmc_dev(host->mmc), "clk err\n");
rc = PTR_ERR(clk);
+
+ if (rc != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "failed to get clock: %d\n", rc);
+
goto err_clk_get;
}
clk_prepare_enable(clk);
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 199712e7adbb..89fd96596a1f 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -89,7 +89,7 @@
#define SDHCI_CTRL_ADMA32 0x10
#define SDHCI_CTRL_ADMA64 0x18
#define SDHCI_CTRL_ADMA3 0x18
-#define SDHCI_CTRL_8BITBUS 0x20
+#define SDHCI_CTRL_8BITBUS 0x20
#define SDHCI_CTRL_CDTEST_INS 0x40
#define SDHCI_CTRL_CDTEST_EN 0x80
diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c
index 3222ea4d584d..bb90757ecace 100644
--- a/drivers/mmc/host/sdhci_am654.c
+++ b/drivers/mmc/host/sdhci_am654.c
@@ -6,6 +6,7 @@
*
*/
#include <linux/clk.h>
+#include <linux/of.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
@@ -36,11 +37,14 @@
#define OTAPDLYSEL_SHIFT 12
#define OTAPDLYSEL_MASK GENMASK(15, 12)
#define STRBSEL_SHIFT 24
-#define STRBSEL_MASK GENMASK(27, 24)
+#define STRBSEL_4BIT_MASK GENMASK(27, 24)
+#define STRBSEL_8BIT_MASK GENMASK(31, 24)
#define SEL50_SHIFT 8
#define SEL50_MASK BIT(SEL50_SHIFT)
#define SEL100_SHIFT 9
#define SEL100_MASK BIT(SEL100_SHIFT)
+#define FREQSEL_SHIFT 8
+#define FREQSEL_MASK GENMASK(10, 8)
#define DLL_TRIM_ICP_SHIFT 4
#define DLL_TRIM_ICP_MASK GENMASK(7, 4)
#define DR_TY_SHIFT 20
@@ -77,19 +81,29 @@ struct sdhci_am654_data {
int trm_icp;
int drv_strength;
bool dll_on;
+ int strb_sel;
+ u32 flags;
+};
+
+struct sdhci_am654_driver_data {
+ const struct sdhci_pltfm_data *pdata;
+ u32 flags;
+#define IOMUX_PRESENT (1 << 0)
+#define FREQSEL_2_BIT (1 << 1)
+#define STRBSEL_4_BIT (1 << 2)
+#define DLL_PRESENT (1 << 3)
};
static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
- int sel50, sel100;
+ int sel50, sel100, freqsel;
u32 mask, val;
int ret;
if (sdhci_am654->dll_on) {
- regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
- ENDLL_MASK, 0);
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL1, ENDLL_MASK, 0);
sdhci_am654->dll_on = false;
}
@@ -101,27 +115,53 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)
mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
val = (1 << OTAPDLYENA_SHIFT) |
(sdhci_am654->otap_del_sel << OTAPDLYSEL_SHIFT);
- regmap_update_bits(sdhci_am654->base, PHY_CTRL4,
- mask, val);
- switch (clock) {
- case 200000000:
- sel50 = 0;
- sel100 = 0;
- break;
- case 100000000:
- sel50 = 0;
- sel100 = 1;
- break;
- default:
- sel50 = 1;
- sel100 = 0;
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val);
+ /* Write to STRBSEL for HS400 speed mode */
+ if (host->mmc->ios.timing == MMC_TIMING_MMC_HS400) {
+ if (sdhci_am654->flags & STRBSEL_4_BIT)
+ mask = STRBSEL_4BIT_MASK;
+ else
+ mask = STRBSEL_8BIT_MASK;
+
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask,
+ sdhci_am654->strb_sel <<
+ STRBSEL_SHIFT);
+ }
+
+ if (sdhci_am654->flags & FREQSEL_2_BIT) {
+ switch (clock) {
+ case 200000000:
+ sel50 = 0;
+ sel100 = 0;
+ break;
+ case 100000000:
+ sel50 = 0;
+ sel100 = 1;
+ break;
+ default:
+ sel50 = 1;
+ sel100 = 0;
+ }
+
+ /* Configure PHY DLL frequency */
+ mask = SEL50_MASK | SEL100_MASK;
+ val = (sel50 << SEL50_SHIFT) | (sel100 << SEL100_SHIFT);
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL5, mask,
+ val);
+ } else {
+ switch (clock) {
+ case 200000000:
+ freqsel = 0x0;
+ break;
+ default:
+ freqsel = 0x4;
+ }
+
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL5,
+ FREQSEL_MASK,
+ freqsel << FREQSEL_SHIFT);
}
- /* Configure PHY DLL frequency */
- mask = SEL50_MASK | SEL100_MASK;
- val = (sel50 << SEL50_SHIFT) | (sel100 << SEL100_SHIFT);
- regmap_update_bits(sdhci_am654->base, PHY_CTRL5,
- mask, val);
/* Configure DLL TRIM */
mask = DLL_TRIM_ICP_MASK;
val = sdhci_am654->trm_icp << DLL_TRIM_ICP_SHIFT;
@@ -129,24 +169,41 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)
/* Configure DLL driver strength */
mask |= DR_TY_MASK;
val |= sdhci_am654->drv_strength << DR_TY_SHIFT;
- regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
- mask, val);
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL1, mask, val);
/* Enable DLL */
- regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
- ENDLL_MASK, 0x1 << ENDLL_SHIFT);
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL1, ENDLL_MASK,
+ 0x1 << ENDLL_SHIFT);
/*
* Poll for DLL ready. Use a one second timeout.
* Works in all experiments done so far
*/
- ret = regmap_read_poll_timeout(sdhci_am654->base,
- PHY_STAT1, val,
- val & DLLRDY_MASK,
- 1000, 1000000);
+ ret = regmap_read_poll_timeout(sdhci_am654->base, PHY_STAT1,
+ val, val & DLLRDY_MASK, 1000,
+ 1000000);
+ if (ret) {
+ dev_err(mmc_dev(host->mmc), "DLL failed to relock\n");
+ return;
+ }
sdhci_am654->dll_on = true;
}
}
+static void sdhci_j721e_4bit_set_clock(struct sdhci_host *host,
+ unsigned int clock)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
+ int val, mask;
+
+ mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
+ val = (1 << OTAPDLYENA_SHIFT) |
+ (sdhci_am654->otap_del_sel << OTAPDLYSEL_SHIFT);
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val);
+
+ sdhci_set_clock(host, clock);
+}
+
static void sdhci_am654_set_power(struct sdhci_host *host, unsigned char mode,
unsigned short vdd)
{
@@ -197,6 +254,56 @@ static const struct sdhci_pltfm_data sdhci_am654_pdata = {
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
};
+static const struct sdhci_am654_driver_data sdhci_am654_drvdata = {
+ .pdata = &sdhci_am654_pdata,
+ .flags = IOMUX_PRESENT | FREQSEL_2_BIT | STRBSEL_4_BIT | DLL_PRESENT,
+};
+
+static struct sdhci_ops sdhci_j721e_8bit_ops = {
+ .get_max_clock = sdhci_pltfm_clk_get_max_clock,
+ .get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
+ .set_uhs_signaling = sdhci_set_uhs_signaling,
+ .set_bus_width = sdhci_set_bus_width,
+ .set_power = sdhci_am654_set_power,
+ .set_clock = sdhci_am654_set_clock,
+ .write_b = sdhci_am654_write_b,
+ .reset = sdhci_reset,
+};
+
+static const struct sdhci_pltfm_data sdhci_j721e_8bit_pdata = {
+ .ops = &sdhci_j721e_8bit_ops,
+ .quirks = SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
+ SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
+ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
+};
+
+static const struct sdhci_am654_driver_data sdhci_j721e_8bit_drvdata = {
+ .pdata = &sdhci_j721e_8bit_pdata,
+ .flags = DLL_PRESENT,
+};
+
+static struct sdhci_ops sdhci_j721e_4bit_ops = {
+ .get_max_clock = sdhci_pltfm_clk_get_max_clock,
+ .get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
+ .set_uhs_signaling = sdhci_set_uhs_signaling,
+ .set_bus_width = sdhci_set_bus_width,
+ .set_power = sdhci_am654_set_power,
+ .set_clock = sdhci_j721e_4bit_set_clock,
+ .write_b = sdhci_am654_write_b,
+ .reset = sdhci_reset,
+};
+
+static const struct sdhci_pltfm_data sdhci_j721e_4bit_pdata = {
+ .ops = &sdhci_j721e_4bit_ops,
+ .quirks = SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
+ SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
+ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
+};
+
+static const struct sdhci_am654_driver_data sdhci_j721e_4bit_drvdata = {
+ .pdata = &sdhci_j721e_4bit_pdata,
+ .flags = IOMUX_PRESENT,
+};
static int sdhci_am654_init(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -208,30 +315,34 @@ static int sdhci_am654_init(struct sdhci_host *host)
/* Reset OTAP to default value */
mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
- regmap_update_bits(sdhci_am654->base, PHY_CTRL4,
- mask, 0x0);
-
- regmap_read(sdhci_am654->base, PHY_STAT1, &val);
- if (~val & CALDONE_MASK) {
- /* Calibrate IO lines */
- regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
- PDB_MASK, PDB_MASK);
- ret = regmap_read_poll_timeout(sdhci_am654->base, PHY_STAT1,
- val, val & CALDONE_MASK, 1, 20);
- if (ret)
- return ret;
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, 0x0);
+
+ if (sdhci_am654->flags & DLL_PRESENT) {
+ regmap_read(sdhci_am654->base, PHY_STAT1, &val);
+ if (~val & CALDONE_MASK) {
+ /* Calibrate IO lines */
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
+ PDB_MASK, PDB_MASK);
+ ret = regmap_read_poll_timeout(sdhci_am654->base,
+ PHY_STAT1, val,
+ val & CALDONE_MASK,
+ 1, 20);
+ if (ret)
+ return ret;
+ }
}
/* Enable pins by setting IO mux to 0 */
- regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
- IOMUX_ENABLE_MASK, 0);
+ if (sdhci_am654->flags & IOMUX_PRESENT)
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL1,
+ IOMUX_ENABLE_MASK, 0);
/* Set slot type based on SD or eMMC */
if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
ctl_cfg_2 = SLOTTYPE_EMBEDDED;
- regmap_update_bits(sdhci_am654->base, CTL_CFG_2,
- SLOTTYPE_MASK, ctl_cfg_2);
+ regmap_update_bits(sdhci_am654->base, CTL_CFG_2, SLOTTYPE_MASK,
+ ctl_cfg_2);
return sdhci_add_host(host);
}
@@ -243,51 +354,73 @@ static int sdhci_am654_get_of_property(struct platform_device *pdev,
int drv_strength;
int ret;
- ret = device_property_read_u32(dev, "ti,trm-icp",
- &sdhci_am654->trm_icp);
- if (ret)
- return ret;
-
ret = device_property_read_u32(dev, "ti,otap-del-sel",
&sdhci_am654->otap_del_sel);
if (ret)
return ret;
- ret = device_property_read_u32(dev, "ti,driver-strength-ohm",
- &drv_strength);
- if (ret)
- return ret;
+ if (sdhci_am654->flags & DLL_PRESENT) {
+ ret = device_property_read_u32(dev, "ti,trm-icp",
+ &sdhci_am654->trm_icp);
+ if (ret)
+ return ret;
- switch (drv_strength) {
- case 50:
- sdhci_am654->drv_strength = DRIVER_STRENGTH_50_OHM;
- break;
- case 33:
- sdhci_am654->drv_strength = DRIVER_STRENGTH_33_OHM;
- break;
- case 66:
- sdhci_am654->drv_strength = DRIVER_STRENGTH_66_OHM;
- break;
- case 100:
- sdhci_am654->drv_strength = DRIVER_STRENGTH_100_OHM;
- break;
- case 40:
- sdhci_am654->drv_strength = DRIVER_STRENGTH_40_OHM;
- break;
- default:
- dev_err(dev, "Invalid driver strength\n");
- return -EINVAL;
+ ret = device_property_read_u32(dev, "ti,driver-strength-ohm",
+ &drv_strength);
+ if (ret)
+ return ret;
+
+ switch (drv_strength) {
+ case 50:
+ sdhci_am654->drv_strength = DRIVER_STRENGTH_50_OHM;
+ break;
+ case 33:
+ sdhci_am654->drv_strength = DRIVER_STRENGTH_33_OHM;
+ break;
+ case 66:
+ sdhci_am654->drv_strength = DRIVER_STRENGTH_66_OHM;
+ break;
+ case 100:
+ sdhci_am654->drv_strength = DRIVER_STRENGTH_100_OHM;
+ break;
+ case 40:
+ sdhci_am654->drv_strength = DRIVER_STRENGTH_40_OHM;
+ break;
+ default:
+ dev_err(dev, "Invalid driver strength\n");
+ return -EINVAL;
+ }
}
+ device_property_read_u32(dev, "ti,strobe-sel", &sdhci_am654->strb_sel);
+
sdhci_get_of_property(pdev);
return 0;
}
+static const struct of_device_id sdhci_am654_of_match[] = {
+ {
+ .compatible = "ti,am654-sdhci-5.1",
+ .data = &sdhci_am654_drvdata,
+ },
+ {
+ .compatible = "ti,j721e-sdhci-8bit",
+ .data = &sdhci_j721e_8bit_drvdata,
+ },
+ {
+ .compatible = "ti,j721e-sdhci-4bit",
+ .data = &sdhci_j721e_4bit_drvdata,
+ },
+ { /* sentinel */ }
+};
+
static int sdhci_am654_probe(struct platform_device *pdev)
{
+ const struct sdhci_am654_driver_data *drvdata;
struct sdhci_pltfm_host *pltfm_host;
struct sdhci_am654_data *sdhci_am654;
+ const struct of_device_id *match;
struct sdhci_host *host;
struct resource *res;
struct clk *clk_xin;
@@ -295,12 +428,15 @@ static int sdhci_am654_probe(struct platform_device *pdev)
void __iomem *base;
int ret;
- host = sdhci_pltfm_init(pdev, &sdhci_am654_pdata, sizeof(*sdhci_am654));
+ match = of_match_node(sdhci_am654_of_match, pdev->dev.of_node);
+ drvdata = match->data;
+ host = sdhci_pltfm_init(pdev, drvdata->pdata, sizeof(*sdhci_am654));
if (IS_ERR(host))
return PTR_ERR(host);
pltfm_host = sdhci_priv(host);
sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
+ sdhci_am654->flags = drvdata->flags;
clk_xin = devm_clk_get(dev, "clk_xin");
if (IS_ERR(clk_xin)) {
@@ -375,11 +511,6 @@ static int sdhci_am654_remove(struct platform_device *pdev)
return 0;
}
-static const struct of_device_id sdhci_am654_of_match[] = {
- { .compatible = "ti,am654-sdhci-5.1" },
- { /* sentinel */ }
-};
-
static struct platform_driver sdhci_am654_driver = {
.driver = {
.name = "sdhci-am654",
diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c
index 35dd34b82a4d..54271b92ee59 100644
--- a/drivers/mmc/host/tifm_sd.c
+++ b/drivers/mmc/host/tifm_sd.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* tifm_sd.c - TI FlashMedia driver
*
* Copyright (C) 2006 Alex Dubov <oakad@yahoo.com>
*
- * 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.
- *
* Special thanks to Brad Campbell for extensive testing of this driver.
- *
*/
diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c
index 93e83ad25976..8539e10784b4 100644
--- a/drivers/mmc/host/tmio_mmc.c
+++ b/drivers/mmc/host/tmio_mmc.c
@@ -172,6 +172,8 @@ static int tmio_mmc_probe(struct platform_device *pdev)
host->mmc->f_max = pdata->hclk;
host->mmc->f_min = pdata->hclk / 512;
+ pm_runtime_enable(&pdev->dev);
+
ret = tmio_mmc_host_probe(host);
if (ret)
goto host_free;
@@ -191,6 +193,7 @@ host_remove:
tmio_mmc_host_remove(host);
host_free:
tmio_mmc_host_free(host);
+ pm_runtime_disable(&pdev->dev);
cell_disable:
if (cell->disable)
cell->disable(pdev);
@@ -207,6 +210,8 @@ static int tmio_mmc_remove(struct platform_device *pdev)
if (cell->disable)
cell->disable(pdev);
+ pm_runtime_disable(&pdev->dev);
+
return 0;
}
diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c
index 84cb7d2aacdf..2cb3f951c3e2 100644
--- a/drivers/mmc/host/tmio_mmc_core.c
+++ b/drivers/mmc/host/tmio_mmc_core.c
@@ -26,6 +26,7 @@
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/dma-mapping.h>
#include <linux/highmem.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -45,7 +46,6 @@
#include <linux/scatterlist.h>
#include <linux/sizes.h>
#include <linux/spinlock.h>
-#include <linux/swiotlb.h>
#include <linux/workqueue.h>
#include "tmio_mmc.h"
@@ -1153,6 +1153,15 @@ void tmio_mmc_host_free(struct tmio_mmc_host *host)
}
EXPORT_SYMBOL_GPL(tmio_mmc_host_free);
+/**
+ * tmio_mmc_host_probe() - Common probe for all implementations
+ * @_host: Host to probe
+ *
+ * Perform tasks common to all implementations probe functions.
+ *
+ * The caller should have called pm_runtime_enable() prior to calling
+ * the common probe function.
+ */
int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
{
struct platform_device *pdev = _host->pdev;
@@ -1190,19 +1199,9 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
mmc->max_blk_size = TMIO_MAX_BLK_SIZE;
mmc->max_blk_count = pdata->max_blk_count ? :
(PAGE_SIZE / mmc->max_blk_size) * mmc->max_segs;
- mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
- /*
- * Since swiotlb has memory size limitation, this will calculate
- * the maximum size locally (because we don't have any APIs for it now)
- * and check the current max_req_size. And then, this will update
- * the max_req_size if needed as a workaround.
- */
- if (swiotlb_max_segment()) {
- unsigned int max_size = (1 << IO_TLB_SHIFT) * IO_TLB_SEGSIZE;
-
- if (mmc->max_req_size > max_size)
- mmc->max_req_size = max_size;
- }
+ mmc->max_req_size = min_t(size_t,
+ mmc->max_blk_size * mmc->max_blk_count,
+ dma_max_mapping_size(&pdev->dev));
mmc->max_seg_size = mmc->max_req_size;
if (mmc_can_gpio_ro(mmc))
@@ -1261,7 +1260,6 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
pm_runtime_set_active(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
pm_runtime_use_autosuspend(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
ret = mmc_add_host(mmc);
if (ret)
@@ -1297,7 +1295,6 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host)
pm_runtime_dont_use_autosuspend(&pdev->dev);
pm_runtime_put_sync(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
}
EXPORT_SYMBOL_GPL(tmio_mmc_host_remove);
diff --git a/drivers/mmc/host/uniphier-sd.c b/drivers/mmc/host/uniphier-sd.c
index 91a2be41edf6..49aad9a79c18 100644
--- a/drivers/mmc/host/uniphier-sd.c
+++ b/drivers/mmc/host/uniphier-sd.c
@@ -631,6 +631,7 @@ static int uniphier_sd_probe(struct platform_device *pdev)
host->clk_disable = uniphier_sd_clk_disable;
host->set_clock = uniphier_sd_set_clock;
+ pm_runtime_enable(&pdev->dev);
ret = uniphier_sd_clk_enable(host);
if (ret)
goto free_host;
@@ -652,6 +653,7 @@ static int uniphier_sd_probe(struct platform_device *pdev)
free_host:
tmio_mmc_host_free(host);
+ pm_runtime_disable(&pdev->dev);
return ret;
}
@@ -662,6 +664,7 @@ static int uniphier_sd_remove(struct platform_device *pdev)
tmio_mmc_host_remove(host);
uniphier_sd_clk_disable(host);
+ pm_runtime_disable(&pdev->dev);
return 0;
}
diff --git a/drivers/mmc/host/wmt-sdmmc.c b/drivers/mmc/host/wmt-sdmmc.c
index 4fd6da29489e..2c4ba1fa4bbf 100644
--- a/drivers/mmc/host/wmt-sdmmc.c
+++ b/drivers/mmc/host/wmt-sdmmc.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* WM8505/WM8650 SD/MMC Host Controller
*
* Copyright (C) 2010 Tony Prisk
* Copyright (C) 2008 WonderMedia Technologies, 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
*/
#include <linux/init.h>
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index fb31a7f649a3..80a6e2dcd085 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -274,4 +274,6 @@ source "drivers/mtd/spi-nor/Kconfig"
source "drivers/mtd/ubi/Kconfig"
+source "drivers/mtd/hyperbus/Kconfig"
+
endif # MTD
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 806287e80e84..62d649a959e2 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -34,3 +34,4 @@ obj-y += chips/ lpddr/ maps/ devices/ nand/ tests/
obj-$(CONFIG_MTD_SPI_NOR) += spi-nor/
obj-$(CONFIG_MTD_UBI) += ubi/
+obj-$(CONFIG_MTD_HYPERBUS) += hyperbus/
diff --git a/drivers/mtd/bcm47xxpart.c b/drivers/mtd/bcm47xxpart.c
index fc424b185b08..6012a10f10c8 100644
--- a/drivers/mtd/bcm47xxpart.c
+++ b/drivers/mtd/bcm47xxpart.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* BCM47XX MTD partitioning
*
* Copyright © 2012 Rafał Miłecki <zajec5@gmail.com>
- *
- * 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.
- *
*/
#include <linux/bcm47xx_nvram.h>
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index c8fa5906bdf9..f4da7bd552e9 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -49,6 +49,16 @@
#define SST49LF008A 0x005a
#define AT49BV6416 0x00d6
+/*
+ * Status Register bit description. Used by flash devices that don't
+ * support DQ polling (e.g. HyperFlash)
+ */
+#define CFI_SR_DRB BIT(7)
+#define CFI_SR_ESB BIT(5)
+#define CFI_SR_PSB BIT(4)
+#define CFI_SR_WBASB BIT(3)
+#define CFI_SR_SLSB BIT(1)
+
static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
static int cfi_amdstd_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
@@ -97,6 +107,50 @@ static struct mtd_chip_driver cfi_amdstd_chipdrv = {
.module = THIS_MODULE
};
+/*
+ * Use status register to poll for Erase/write completion when DQ is not
+ * supported. This is indicated by Bit[1:0] of SoftwareFeatures field in
+ * CFI Primary Vendor-Specific Extended Query table 1.5
+ */
+static int cfi_use_status_reg(struct cfi_private *cfi)
+{
+ struct cfi_pri_amdstd *extp = cfi->cmdset_priv;
+ u8 poll_mask = CFI_POLL_STATUS_REG | CFI_POLL_DQ;
+
+ return extp->MinorVersion >= '5' &&
+ (extp->SoftwareFeatures & poll_mask) == CFI_POLL_STATUS_REG;
+}
+
+static void cfi_check_err_status(struct map_info *map, struct flchip *chip,
+ unsigned long adr)
+{
+ struct cfi_private *cfi = map->fldrv_priv;
+ map_word status;
+
+ if (!cfi_use_status_reg(cfi))
+ return;
+
+ cfi_send_gen_cmd(0x70, cfi->addr_unlock1, chip->start, map, cfi,
+ cfi->device_type, NULL);
+ status = map_read(map, adr);
+
+ if (map_word_bitsset(map, status, CMD(0x3a))) {
+ unsigned long chipstatus = MERGESTATUS(status);
+
+ if (chipstatus & CFI_SR_ESB)
+ pr_err("%s erase operation failed, status %lx\n",
+ map->name, chipstatus);
+ if (chipstatus & CFI_SR_PSB)
+ pr_err("%s program operation failed, status %lx\n",
+ map->name, chipstatus);
+ if (chipstatus & CFI_SR_WBASB)
+ pr_err("%s buffer program command aborted, status %lx\n",
+ map->name, chipstatus);
+ if (chipstatus & CFI_SR_SLSB)
+ pr_err("%s sector write protected, status %lx\n",
+ map->name, chipstatus);
+ }
+}
/* #define DEBUG_CFI_FEATURES */
@@ -742,10 +796,25 @@ static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd)
* correctly and is therefore not done (particularly with interleaved chips
* as each chip must be checked independently of the others).
*/
-static int __xipram chip_ready(struct map_info *map, unsigned long addr)
+static int __xipram chip_ready(struct map_info *map, struct flchip *chip,
+ unsigned long addr)
{
+ struct cfi_private *cfi = map->fldrv_priv;
map_word d, t;
+ if (cfi_use_status_reg(cfi)) {
+ map_word ready = CMD(CFI_SR_DRB);
+ /*
+ * For chips that support status register, check device
+ * ready bit
+ */
+ cfi_send_gen_cmd(0x70, cfi->addr_unlock1, chip->start, map, cfi,
+ cfi->device_type, NULL);
+ d = map_read(map, addr);
+
+ return map_word_andequal(map, d, ready, ready);
+ }
+
d = map_read(map, addr);
t = map_read(map, addr);
@@ -767,10 +836,30 @@ static int __xipram chip_ready(struct map_info *map, unsigned long addr)
* as each chip must be checked independently of the others).
*
*/
-static int __xipram chip_good(struct map_info *map, unsigned long addr, map_word expected)
+static int __xipram chip_good(struct map_info *map, struct flchip *chip,
+ unsigned long addr, map_word expected)
{
+ struct cfi_private *cfi = map->fldrv_priv;
map_word oldd, curd;
+ if (cfi_use_status_reg(cfi)) {
+ map_word ready = CMD(CFI_SR_DRB);
+ map_word err = CMD(CFI_SR_PSB | CFI_SR_ESB);
+ /*
+ * For chips that support status register, check device
+ * ready bit and Erase/Program status bit to know if
+ * operation succeeded.
+ */
+ cfi_send_gen_cmd(0x70, cfi->addr_unlock1, chip->start, map, cfi,
+ cfi->device_type, NULL);
+ curd = map_read(map, addr);
+
+ if (map_word_andequal(map, curd, ready, ready))
+ return !map_word_bitsset(map, curd, err);
+
+ return 0;
+ }
+
oldd = map_read(map, addr);
curd = map_read(map, addr);
@@ -792,7 +881,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
case FL_STATUS:
for (;;) {
- if (chip_ready(map, adr))
+ if (chip_ready(map, chip, adr))
break;
if (time_after(jiffies, timeo)) {
@@ -830,7 +919,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
chip->state = FL_ERASE_SUSPENDING;
chip->erase_suspended = 1;
for (;;) {
- if (chip_ready(map, adr))
+ if (chip_ready(map, chip, adr))
break;
if (time_after(jiffies, timeo)) {
@@ -1362,7 +1451,7 @@ static int do_otp_lock(struct map_info *map, struct flchip *chip, loff_t adr,
/* wait for chip to become ready */
timeo = jiffies + msecs_to_jiffies(2);
for (;;) {
- if (chip_ready(map, adr))
+ if (chip_ready(map, chip, adr))
break;
if (time_after(jiffies, timeo)) {
@@ -1628,22 +1717,24 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
continue;
}
- if (time_after(jiffies, timeo) && !chip_ready(map, adr)){
+ if (time_after(jiffies, timeo) &&
+ !chip_ready(map, chip, adr)) {
xip_enable(map, chip, adr);
printk(KERN_WARNING "MTD %s(): software timeout\n", __func__);
xip_disable(map, chip, adr);
break;
}
- if (chip_ready(map, adr))
+ if (chip_ready(map, chip, adr))
break;
/* Latency issues. Drop the lock, wait a while and retry */
UDELAY(map, chip, adr, 1);
}
/* Did we succeed? */
- if (!chip_good(map, adr, datum)) {
+ if (!chip_good(map, chip, adr, datum)) {
/* reset on all failures. */
+ cfi_check_err_status(map, chip, adr);
map_write(map, CMD(0xF0), chip->start);
/* FIXME - should have reset delay before continuing */
@@ -1881,10 +1972,11 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
* We check "time_after" and "!chip_good" before checking "chip_good" to avoid
* the failure due to scheduling.
*/
- if (time_after(jiffies, timeo) && !chip_good(map, adr, datum))
+ if (time_after(jiffies, timeo) &&
+ !chip_good(map, chip, adr, datum))
break;
- if (chip_good(map, adr, datum)) {
+ if (chip_good(map, chip, adr, datum)) {
xip_enable(map, chip, adr);
goto op_done;
}
@@ -1901,6 +1993,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
* See e.g.
* http://www.spansion.com/Support/Application%20Notes/MirrorBit_Write_Buffer_Prog_Page_Buffer_Read_AN.pdf
*/
+ cfi_check_err_status(map, chip, adr);
cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi,
cfi->device_type, NULL);
cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi,
@@ -2018,7 +2111,7 @@ static int cfi_amdstd_panic_wait(struct map_info *map, struct flchip *chip,
* If the driver thinks the chip is idle, and no toggle bits
* are changing, then the chip is actually idle for sure.
*/
- if (chip->state == FL_READY && chip_ready(map, adr))
+ if (chip->state == FL_READY && chip_ready(map, chip, adr))
return 0;
/*
@@ -2035,7 +2128,7 @@ static int cfi_amdstd_panic_wait(struct map_info *map, struct flchip *chip,
/* wait for the chip to become ready */
for (i = 0; i < jiffies_to_usecs(timeo); i++) {
- if (chip_ready(map, adr))
+ if (chip_ready(map, chip, adr))
return 0;
udelay(1);
@@ -2099,14 +2192,15 @@ retry:
map_write(map, datum, adr);
for (i = 0; i < jiffies_to_usecs(uWriteTimeout); i++) {
- if (chip_ready(map, adr))
+ if (chip_ready(map, chip, adr))
break;
udelay(1);
}
- if (!chip_good(map, adr, datum)) {
+ if (!chip_good(map, chip, adr, datum)) {
/* reset on all failures. */
+ cfi_check_err_status(map, chip, adr);
map_write(map, CMD(0xF0), chip->start);
/* FIXME - should have reset delay before continuing */
@@ -2300,7 +2394,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip)
chip->erase_suspended = 0;
}
- if (chip_good(map, adr, map_word_ff(map)))
+ if (chip_good(map, chip, adr, map_word_ff(map)))
break;
if (time_after(jiffies, timeo)) {
@@ -2316,6 +2410,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip)
/* Did we succeed? */
if (ret) {
/* reset on all failures. */
+ cfi_check_err_status(map, chip, adr);
map_write(map, CMD(0xF0), chip->start);
/* FIXME - should have reset delay before continuing */
@@ -2396,7 +2491,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
chip->erase_suspended = 0;
}
- if (chip_good(map, adr, map_word_ff(map)))
+ if (chip_good(map, chip, adr, map_word_ff(map)))
break;
if (time_after(jiffies, timeo)) {
@@ -2412,6 +2507,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
/* Did we succeed? */
if (ret) {
/* reset on all failures. */
+ cfi_check_err_status(map, chip, adr);
map_write(map, CMD(0xF0), chip->start);
/* FIXME - should have reset delay before continuing */
@@ -2533,8 +2629,6 @@ struct ppb_lock {
int locked;
};
-#define MAX_SECTORS 512
-
#define DO_XXLOCK_ONEBLOCK_LOCK ((void *)1)
#define DO_XXLOCK_ONEBLOCK_UNLOCK ((void *)2)
#define DO_XXLOCK_ONEBLOCK_GETLOCK ((void *)3)
@@ -2589,7 +2683,7 @@ static int __maybe_unused do_ppb_xxlock(struct map_info *map,
*/
timeo = jiffies + msecs_to_jiffies(2000); /* 2s max (un)locking */
for (;;) {
- if (chip_ready(map, adr))
+ if (chip_ready(map, chip, adr))
break;
if (time_after(jiffies, timeo)) {
@@ -2633,6 +2727,7 @@ static int __maybe_unused cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs,
int i;
int sectors;
int ret;
+ int max_sectors;
/*
* PPB unlocking always unlocks all sectors of the flash chip.
@@ -2640,7 +2735,11 @@ static int __maybe_unused cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs,
* first check the locking status of all sectors and save
* it for future use.
*/
- sect = kcalloc(MAX_SECTORS, sizeof(struct ppb_lock), GFP_KERNEL);
+ max_sectors = 0;
+ for (i = 0; i < mtd->numeraseregions; i++)
+ max_sectors += regions[i].numblocks;
+
+ sect = kcalloc(max_sectors, sizeof(struct ppb_lock), GFP_KERNEL);
if (!sect)
return -ENOMEM;
@@ -2689,9 +2788,9 @@ static int __maybe_unused cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs,
}
sectors++;
- if (sectors >= MAX_SECTORS) {
+ if (sectors >= max_sectors) {
printk(KERN_ERR "Only %d sectors for PPB locking supported!\n",
- MAX_SECTORS);
+ max_sectors);
kfree(sect);
return -EINVAL;
}
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index ef0e476b2525..49abbc52457d 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -48,7 +48,7 @@ config MTD_MS02NV
If you want to compile this driver as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
- say M here and read <file:Documentation/kbuild/modules.txt>.
+ say M here and read <file:Documentation/kbuild/modules.rst>.
The module will be called ms02-nv.
config MTD_DATAFLASH
diff --git a/drivers/mtd/hyperbus/Kconfig b/drivers/mtd/hyperbus/Kconfig
new file mode 100644
index 000000000000..cff6bbd226f5
--- /dev/null
+++ b/drivers/mtd/hyperbus/Kconfig
@@ -0,0 +1,23 @@
+menuconfig MTD_HYPERBUS
+ tristate "HyperBus support"
+ select MTD_CFI
+ select MTD_MAP_BANK_WIDTH_2
+ select MTD_CFI_AMDSTD
+ select MTD_COMPLEX_MAPPINGS
+ help
+ This is the framework for the HyperBus which can be used by
+ the HyperBus Controller driver to communicate with
+ HyperFlash. See Cypress HyperBus specification for more
+ details
+
+if MTD_HYPERBUS
+
+config HBMC_AM654
+ tristate "HyperBus controller driver for AM65x SoC"
+ select MULTIPLEXER
+ select MUX_MMIO
+ help
+ This is the driver for HyperBus controller on TI's AM65x and
+ other SoCs
+
+endif # MTD_HYPERBUS
diff --git a/drivers/mtd/hyperbus/Makefile b/drivers/mtd/hyperbus/Makefile
new file mode 100644
index 000000000000..8a936e066f48
--- /dev/null
+++ b/drivers/mtd/hyperbus/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_MTD_HYPERBUS) += hyperbus-core.o
+obj-$(CONFIG_HBMC_AM654) += hbmc-am654.o
diff --git a/drivers/mtd/hyperbus/hbmc-am654.c b/drivers/mtd/hyperbus/hbmc-am654.c
new file mode 100644
index 000000000000..08d543b124cd
--- /dev/null
+++ b/drivers/mtd/hyperbus/hbmc-am654.c
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+// Author: Vignesh Raghavendra <vigneshr@ti.com>
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mtd/cfi.h>
+#include <linux/mtd/hyperbus.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mux/consumer.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/types.h>
+
+#define AM654_HBMC_CALIB_COUNT 25
+
+struct am654_hbmc_priv {
+ struct hyperbus_ctlr ctlr;
+ struct hyperbus_device hbdev;
+ struct mux_control *mux_ctrl;
+};
+
+static int am654_hbmc_calibrate(struct hyperbus_device *hbdev)
+{
+ struct map_info *map = &hbdev->map;
+ struct cfi_private cfi;
+ int count = AM654_HBMC_CALIB_COUNT;
+ int pass_count = 0;
+ int ret;
+
+ cfi.interleave = 1;
+ cfi.device_type = CFI_DEVICETYPE_X16;
+ cfi_send_gen_cmd(0xF0, 0, 0, map, &cfi, cfi.device_type, NULL);
+ cfi_send_gen_cmd(0x98, 0x55, 0, map, &cfi, cfi.device_type, NULL);
+
+ while (count--) {
+ ret = cfi_qry_present(map, 0, &cfi);
+ if (ret)
+ pass_count++;
+ else
+ pass_count = 0;
+ if (pass_count == 5)
+ break;
+ }
+
+ cfi_qry_mode_off(0, map, &cfi);
+
+ return ret;
+}
+
+static const struct hyperbus_ops am654_hbmc_ops = {
+ .calibrate = am654_hbmc_calibrate,
+};
+
+static int am654_hbmc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct am654_hbmc_priv *priv;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, priv);
+
+ if (of_property_read_bool(dev->of_node, "mux-controls")) {
+ struct mux_control *control = devm_mux_control_get(dev, NULL);
+
+ if (IS_ERR(control))
+ return PTR_ERR(control);
+
+ ret = mux_control_select(control, 1);
+ if (ret) {
+ dev_err(dev, "Failed to select HBMC mux\n");
+ return ret;
+ }
+ priv->mux_ctrl = control;
+ }
+
+ pm_runtime_enable(dev);
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(dev);
+ goto disable_pm;
+ }
+
+ priv->ctlr.dev = dev;
+ priv->ctlr.ops = &am654_hbmc_ops;
+ priv->hbdev.ctlr = &priv->ctlr;
+ priv->hbdev.np = of_get_next_child(dev->of_node, NULL);
+ ret = hyperbus_register_device(&priv->hbdev);
+ if (ret) {
+ dev_err(dev, "failed to register controller\n");
+ pm_runtime_put_sync(&pdev->dev);
+ goto disable_pm;
+ }
+
+ return 0;
+disable_pm:
+ pm_runtime_disable(dev);
+ if (priv->mux_ctrl)
+ mux_control_deselect(priv->mux_ctrl);
+ return ret;
+}
+
+static int am654_hbmc_remove(struct platform_device *pdev)
+{
+ struct am654_hbmc_priv *priv = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = hyperbus_unregister_device(&priv->hbdev);
+ if (priv->mux_ctrl)
+ mux_control_deselect(priv->mux_ctrl);
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
+ return ret;
+}
+
+static const struct of_device_id am654_hbmc_dt_ids[] = {
+ {
+ .compatible = "ti,am654-hbmc",
+ },
+ { /* end of table */ }
+};
+
+MODULE_DEVICE_TABLE(of, am654_hbmc_dt_ids);
+
+static struct platform_driver am654_hbmc_platform_driver = {
+ .probe = am654_hbmc_probe,
+ .remove = am654_hbmc_remove,
+ .driver = {
+ .name = "hbmc-am654",
+ .of_match_table = am654_hbmc_dt_ids,
+ },
+};
+
+module_platform_driver(am654_hbmc_platform_driver);
+
+MODULE_DESCRIPTION("HBMC driver for AM654 SoC");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:hbmc-am654");
+MODULE_AUTHOR("Vignesh Raghavendra <vigneshr@ti.com>");
diff --git a/drivers/mtd/hyperbus/hyperbus-core.c b/drivers/mtd/hyperbus/hyperbus-core.c
new file mode 100644
index 000000000000..6af9ea34117d
--- /dev/null
+++ b/drivers/mtd/hyperbus/hyperbus-core.c
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+// Author: Vignesh Raghavendra <vigneshr@ti.com>
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mtd/hyperbus.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/mtd.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/types.h>
+
+static struct hyperbus_device *map_to_hbdev(struct map_info *map)
+{
+ return container_of(map, struct hyperbus_device, map);
+}
+
+static map_word hyperbus_read16(struct map_info *map, unsigned long addr)
+{
+ struct hyperbus_device *hbdev = map_to_hbdev(map);
+ struct hyperbus_ctlr *ctlr = hbdev->ctlr;
+ map_word read_data;
+
+ read_data.x[0] = ctlr->ops->read16(hbdev, addr);
+
+ return read_data;
+}
+
+static void hyperbus_write16(struct map_info *map, map_word d,
+ unsigned long addr)
+{
+ struct hyperbus_device *hbdev = map_to_hbdev(map);
+ struct hyperbus_ctlr *ctlr = hbdev->ctlr;
+
+ ctlr->ops->write16(hbdev, addr, d.x[0]);
+}
+
+static void hyperbus_copy_from(struct map_info *map, void *to,
+ unsigned long from, ssize_t len)
+{
+ struct hyperbus_device *hbdev = map_to_hbdev(map);
+ struct hyperbus_ctlr *ctlr = hbdev->ctlr;
+
+ ctlr->ops->copy_from(hbdev, to, from, len);
+}
+
+static void hyperbus_copy_to(struct map_info *map, unsigned long to,
+ const void *from, ssize_t len)
+{
+ struct hyperbus_device *hbdev = map_to_hbdev(map);
+ struct hyperbus_ctlr *ctlr = hbdev->ctlr;
+
+ ctlr->ops->copy_to(hbdev, to, from, len);
+}
+
+int hyperbus_register_device(struct hyperbus_device *hbdev)
+{
+ const struct hyperbus_ops *ops;
+ struct hyperbus_ctlr *ctlr;
+ struct device_node *np;
+ struct map_info *map;
+ struct resource res;
+ struct device *dev;
+ int ret;
+
+ if (!hbdev || !hbdev->np || !hbdev->ctlr || !hbdev->ctlr->dev) {
+ pr_err("hyperbus: please fill all the necessary fields!\n");
+ return -EINVAL;
+ }
+
+ np = hbdev->np;
+ ctlr = hbdev->ctlr;
+ if (!of_device_is_compatible(np, "cypress,hyperflash"))
+ return -ENODEV;
+
+ hbdev->memtype = HYPERFLASH;
+
+ ret = of_address_to_resource(np, 0, &res);
+ if (ret)
+ return ret;
+
+ dev = ctlr->dev;
+ map = &hbdev->map;
+ map->size = resource_size(&res);
+ map->virt = devm_ioremap_resource(dev, &res);
+ if (IS_ERR(map->virt))
+ return PTR_ERR(map->virt);
+
+ map->name = dev_name(dev);
+ map->bankwidth = 2;
+ map->device_node = np;
+
+ simple_map_init(map);
+ ops = ctlr->ops;
+ if (ops) {
+ if (ops->read16)
+ map->read = hyperbus_read16;
+ if (ops->write16)
+ map->write = hyperbus_write16;
+ if (ops->copy_to)
+ map->copy_to = hyperbus_copy_to;
+ if (ops->copy_from)
+ map->copy_from = hyperbus_copy_from;
+
+ if (ops->calibrate && !ctlr->calibrated) {
+ ret = ops->calibrate(hbdev);
+ if (!ret) {
+ dev_err(dev, "Calibration failed\n");
+ return -ENODEV;
+ }
+ ctlr->calibrated = true;
+ }
+ }
+
+ hbdev->mtd = do_map_probe("cfi_probe", map);
+ if (!hbdev->mtd) {
+ dev_err(dev, "probing of hyperbus device failed\n");
+ return -ENODEV;
+ }
+
+ hbdev->mtd->dev.parent = dev;
+ mtd_set_of_node(hbdev->mtd, np);
+
+ ret = mtd_device_register(hbdev->mtd, NULL, 0);
+ if (ret) {
+ dev_err(dev, "failed to register mtd device\n");
+ map_destroy(hbdev->mtd);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(hyperbus_register_device);
+
+int hyperbus_unregister_device(struct hyperbus_device *hbdev)
+{
+ int ret = 0;
+
+ if (hbdev && hbdev->mtd) {
+ ret = mtd_device_unregister(hbdev->mtd);
+ map_destroy(hbdev->mtd);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(hyperbus_unregister_device);
+
+MODULE_DESCRIPTION("HyperBus Framework");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Vignesh Raghavendra <vigneshr@ti.com>");
diff --git a/drivers/mtd/maps/impa7.c b/drivers/mtd/maps/impa7.c
index 815e2db87955..b41401852fb7 100644
--- a/drivers/mtd/maps/impa7.c
+++ b/drivers/mtd/maps/impa7.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Handle mapping of the NOR flash on implementa A7 boards
*
* Copyright 2002 SYSGO Real-Time Solutions GmbH
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/mtd/maps/lantiq-flash.c b/drivers/mtd/maps/lantiq-flash.c
index 77b1d8013295..67a1dbfdd72c 100644
--- a/drivers/mtd/maps/lantiq-flash.c
+++ b/drivers/mtd/maps/lantiq-flash.c
@@ -1,7 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
- * 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.
*
* Copyright (C) 2004 Liu Peng Infineon IFAP DC COM CPE
* Copyright (C) 2010 John Crispin <john@phrozen.org>
diff --git a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c
index 7b3bb40aff72..9a49f8a06fb8 100644
--- a/drivers/mtd/maps/pci.c
+++ b/drivers/mtd/maps/pci.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/mtd/maps/pci.c
*
* Copyright (C) 2001 Russell King, All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* Generic PCI memory map driver. We support the following boards:
* - Intel IQ80310 ATU.
* - Intel EBSA285 (blank rom programming mode). Tested working 27/09/2001
diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c
index 2cde28ed95c9..cebb346877a9 100644
--- a/drivers/mtd/maps/pxa2xx-flash.c
+++ b/drivers/mtd/maps/pxa2xx-flash.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Map driver for Intel XScale PXA2xx platforms.
*
* Author: Nicolas Pitre
* Copyright: (C) 2001 MontaVista Software 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.
*/
#include <linux/module.h>
diff --git a/drivers/mtd/maps/rbtx4939-flash.c b/drivers/mtd/maps/rbtx4939-flash.c
index 80a187167c92..39c86c0b0ec1 100644
--- a/drivers/mtd/maps/rbtx4939-flash.c
+++ b/drivers/mtd/maps/rbtx4939-flash.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* rbtx4939-flash (based on physmap.c)
*
* This is a simplified physmap driver with map_init callback function.
*
- * 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.
- *
* Copyright (C) 2009 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
*/
diff --git a/drivers/mtd/maps/vmu-flash.c b/drivers/mtd/maps/vmu-flash.c
index c5d4b6589488..177bf134e189 100644
--- a/drivers/mtd/maps/vmu-flash.c
+++ b/drivers/mtd/maps/vmu-flash.c
@@ -1,11 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* vmu-flash.c
* Driver for SEGA Dreamcast Visual Memory Unit
*
* Copyright (c) Adrian McMenamin 2002 - 2009
* Copyright (c) Paul Mundt 2001
- *
- * Licensed under version 2 of the
- * GNU General Public Licence
*/
#include <linux/init.h>
#include <linux/slab.h>
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
index 7324ff832b41..170a7221b35f 100644
--- a/drivers/mtd/mtdconcat.c
+++ b/drivers/mtd/mtdconcat.c
@@ -437,7 +437,8 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
return err;
}
-static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+static int concat_xxlock(struct mtd_info *mtd, loff_t ofs, uint64_t len,
+ bool is_lock)
{
struct mtd_concat *concat = CONCAT(mtd);
int i, err = -EINVAL;
@@ -456,7 +457,10 @@ static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
else
size = len;
- err = mtd_lock(subdev, ofs, size);
+ if (is_lock)
+ err = mtd_lock(subdev, ofs, size);
+ else
+ err = mtd_unlock(subdev, ofs, size);
if (err)
break;
@@ -471,35 +475,33 @@ static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
return err;
}
+static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+{
+ return concat_xxlock(mtd, ofs, len, true);
+}
+
static int concat_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
+ return concat_xxlock(mtd, ofs, len, false);
+}
+
+static int concat_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+{
struct mtd_concat *concat = CONCAT(mtd);
- int i, err = 0;
+ int i, err = -EINVAL;
for (i = 0; i < concat->num_subdev; i++) {
struct mtd_info *subdev = concat->subdev[i];
- uint64_t size;
if (ofs >= subdev->size) {
- size = 0;
ofs -= subdev->size;
continue;
}
- if (ofs + len > subdev->size)
- size = subdev->size - ofs;
- else
- size = len;
-
- err = mtd_unlock(subdev, ofs, size);
- if (err)
- break;
- len -= size;
- if (len == 0)
+ if (ofs + len > subdev->size)
break;
- err = -EINVAL;
- ofs = 0;
+ return mtd_is_locked(subdev, ofs, len);
}
return err;
@@ -704,6 +706,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
concat->mtd._sync = concat_sync;
concat->mtd._lock = concat_lock;
concat->mtd._unlock = concat_unlock;
+ concat->mtd._is_locked = concat_is_locked;
concat->mtd._suspend = concat_suspend;
concat->mtd._resume = concat_resume;
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 453242d6cf56..408615f29e57 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -1124,6 +1124,9 @@ int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
return -EROFS;
if (!len)
return 0;
+ if (!mtd->oops_panic_write)
+ mtd->oops_panic_write = true;
+
return mtd->_panic_write(mtd, to, len, retlen, buf);
}
EXPORT_SYMBOL_GPL(mtd_panic_write);
diff --git a/drivers/mtd/nand/onenand/generic.c b/drivers/mtd/nand/onenand/generic.c
index acad17ec6581..8b6f4da5d720 100644
--- a/drivers/mtd/nand/onenand/generic.c
+++ b/drivers/mtd/nand/onenand/generic.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2005 Samsung Electronics
* Kyungmin Park <kyungmin.park@samsung.com>
*
- * 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.
- *
* Overview:
* This is a device driver for the OneNAND flash for generic boards.
*/
diff --git a/drivers/mtd/nand/onenand/onenand_base.c b/drivers/mtd/nand/onenand/onenand_base.c
index f41d76248550..a1f8fe1abb10 100644
--- a/drivers/mtd/nand/onenand/onenand_base.c
+++ b/drivers/mtd/nand/onenand/onenand_base.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright © 2005-2009 Samsung Electronics
* Copyright © 2007 Nokia Corporation
@@ -12,10 +13,6 @@
* Flex-OneNAND support
* Amul Kumar Saha <amul.saha at samsung.com>
* OTP support
- *
- * 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.
*/
#include <linux/kernel.h>
@@ -3260,6 +3257,8 @@ static void onenand_check_features(struct mtd_info *mtd)
/* Lock scheme */
switch (density) {
+ case ONENAND_DEVICE_DENSITY_8Gb:
+ this->options |= ONENAND_HAS_NOP_1;
case ONENAND_DEVICE_DENSITY_4Gb:
if (ONENAND_IS_DDP(this))
this->options |= ONENAND_HAS_2PLANE;
@@ -3280,12 +3279,15 @@ static void onenand_check_features(struct mtd_info *mtd)
if ((this->version_id & 0xf) == 0xe)
this->options |= ONENAND_HAS_NOP_1;
}
+ this->options |= ONENAND_HAS_UNLOCK_ALL;
+ break;
case ONENAND_DEVICE_DENSITY_2Gb:
/* 2Gb DDP does not have 2 plane */
if (!ONENAND_IS_DDP(this))
this->options |= ONENAND_HAS_2PLANE;
this->options |= ONENAND_HAS_UNLOCK_ALL;
+ break;
case ONENAND_DEVICE_DENSITY_1Gb:
/* A-Die has all block unlock */
diff --git a/drivers/mtd/nand/onenand/samsung.c b/drivers/mtd/nand/onenand/samsung.c
index e64d0fdf7eb5..55e5536a5850 100644
--- a/drivers/mtd/nand/onenand/samsung.c
+++ b/drivers/mtd/nand/onenand/samsung.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Samsung S3C64XX/S5PC1XX OneNAND driver
*
@@ -5,10 +6,6 @@
* Kyungmin Park <kyungmin.park@samsung.com>
* Marek Szyprowski <m.szyprowski@samsung.com>
*
- * 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.
- *
* Implementation:
* S3C64XX: emulate the pseudo BufferRAM
* S5PC110: use DMA
diff --git a/drivers/mtd/nand/onenand/samsung.h b/drivers/mtd/nand/onenand/samsung.h
index 9016dc0136a8..892bbb6ca4fe 100644
--- a/drivers/mtd/nand/onenand/samsung.h
+++ b/drivers/mtd/nand/onenand/samsung.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2008-2010 Samsung Electronics
* Kyungmin Park <kyungmin.park@samsung.com>
- *
- * 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.
*/
#ifndef __SAMSUNG_ONENAND_H__
#define __SAMSUNG_ONENAND_H__
diff --git a/drivers/mtd/nand/raw/au1550nd.c b/drivers/mtd/nand/raw/au1550nd.c
index a963002663ed..97a97a9ccc36 100644
--- a/drivers/mtd/nand/raw/au1550nd.c
+++ b/drivers/mtd/nand/raw/au1550nd.c
@@ -1,10 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2004 Embedded Edge, LLC
- *
- * 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.
- *
*/
#include <linux/slab.h>
diff --git a/drivers/mtd/nand/raw/bcm47xxnflash/main.c b/drivers/mtd/nand/raw/bcm47xxnflash/main.c
index d79694160845..8dae97c1dbe7 100644
--- a/drivers/mtd/nand/raw/bcm47xxnflash/main.c
+++ b/drivers/mtd/nand/raw/bcm47xxnflash/main.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* BCM47XX NAND flash driver
*
* Copyright (C) 2012 Rafał Miłecki <zajec5@gmail.com>
- *
- * 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.
- *
*/
#include "bcm47xxnflash.h"
diff --git a/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c
index a53ffb3d64b0..591775173034 100644
--- a/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c
+++ b/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* BCM47XX NAND flash driver
*
* Copyright (C) 2012 Rafał Miłecki <zajec5@gmail.com>
- *
- * 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.
- *
*/
#include "bcm47xxnflash.h"
diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
index 873527753f52..33310b8a6eb8 100644
--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
@@ -84,6 +84,12 @@ struct brcm_nand_dma_desc {
#define FLASH_DMA_ECC_ERROR (1 << 8)
#define FLASH_DMA_CORR_ERROR (1 << 9)
+/* Bitfields for DMA_MODE */
+#define FLASH_DMA_MODE_STOP_ON_ERROR BIT(1) /* stop in Uncorr ECC error */
+#define FLASH_DMA_MODE_MODE BIT(0) /* link list */
+#define FLASH_DMA_MODE_MASK (FLASH_DMA_MODE_STOP_ON_ERROR | \
+ FLASH_DMA_MODE_MODE)
+
/* 512B flash cache in the NAND controller HW */
#define FC_SHIFT 9U
#define FC_BYTES 512U
@@ -96,6 +102,51 @@ struct brcm_nand_dma_desc {
#define NAND_CTRL_RDY (INTFC_CTLR_READY | INTFC_FLASH_READY)
#define NAND_POLL_STATUS_TIMEOUT_MS 100
+/* flash_dma registers */
+enum flash_dma_reg {
+ FLASH_DMA_REVISION = 0,
+ FLASH_DMA_FIRST_DESC,
+ FLASH_DMA_FIRST_DESC_EXT,
+ FLASH_DMA_CTRL,
+ FLASH_DMA_MODE,
+ FLASH_DMA_STATUS,
+ FLASH_DMA_INTERRUPT_DESC,
+ FLASH_DMA_INTERRUPT_DESC_EXT,
+ FLASH_DMA_ERROR_STATUS,
+ FLASH_DMA_CURRENT_DESC,
+ FLASH_DMA_CURRENT_DESC_EXT,
+};
+
+/* flash_dma registers v1*/
+static const u16 flash_dma_regs_v1[] = {
+ [FLASH_DMA_REVISION] = 0x00,
+ [FLASH_DMA_FIRST_DESC] = 0x04,
+ [FLASH_DMA_FIRST_DESC_EXT] = 0x08,
+ [FLASH_DMA_CTRL] = 0x0c,
+ [FLASH_DMA_MODE] = 0x10,
+ [FLASH_DMA_STATUS] = 0x14,
+ [FLASH_DMA_INTERRUPT_DESC] = 0x18,
+ [FLASH_DMA_INTERRUPT_DESC_EXT] = 0x1c,
+ [FLASH_DMA_ERROR_STATUS] = 0x20,
+ [FLASH_DMA_CURRENT_DESC] = 0x24,
+ [FLASH_DMA_CURRENT_DESC_EXT] = 0x28,
+};
+
+/* flash_dma registers v4 */
+static const u16 flash_dma_regs_v4[] = {
+ [FLASH_DMA_REVISION] = 0x00,
+ [FLASH_DMA_FIRST_DESC] = 0x08,
+ [FLASH_DMA_FIRST_DESC_EXT] = 0x0c,
+ [FLASH_DMA_CTRL] = 0x10,
+ [FLASH_DMA_MODE] = 0x14,
+ [FLASH_DMA_STATUS] = 0x18,
+ [FLASH_DMA_INTERRUPT_DESC] = 0x20,
+ [FLASH_DMA_INTERRUPT_DESC_EXT] = 0x24,
+ [FLASH_DMA_ERROR_STATUS] = 0x28,
+ [FLASH_DMA_CURRENT_DESC] = 0x30,
+ [FLASH_DMA_CURRENT_DESC_EXT] = 0x34,
+};
+
/* Controller feature flags */
enum {
BRCMNAND_HAS_1K_SECTORS = BIT(0),
@@ -128,6 +179,8 @@ struct brcmnand_controller {
/* List of NAND hosts (one for each chip-select) */
struct list_head host_list;
+ /* flash_dma reg */
+ const u16 *flash_dma_offsets;
struct brcm_nand_dma_desc *dma_desc;
dma_addr_t dma_pa;
@@ -151,6 +204,7 @@ struct brcmnand_controller {
u32 nand_cs_nand_xor;
u32 corr_stat_threshold;
u32 flash_dma_mode;
+ bool pio_poll_mode;
};
struct brcmnand_cfg {
@@ -462,7 +516,7 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
/* Register offsets */
if (ctrl->nand_version >= 0x0702)
ctrl->reg_offsets = brcmnand_regs_v72;
- else if (ctrl->nand_version >= 0x0701)
+ else if (ctrl->nand_version == 0x0701)
ctrl->reg_offsets = brcmnand_regs_v71;
else if (ctrl->nand_version >= 0x0600)
ctrl->reg_offsets = brcmnand_regs_v60;
@@ -507,7 +561,7 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
}
/* Maximum spare area sector size (per 512B) */
- if (ctrl->nand_version >= 0x0702)
+ if (ctrl->nand_version == 0x0702)
ctrl->max_oob = 128;
else if (ctrl->nand_version >= 0x0600)
ctrl->max_oob = 64;
@@ -538,6 +592,15 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
return 0;
}
+static void brcmnand_flash_dma_revision_init(struct brcmnand_controller *ctrl)
+{
+ /* flash_dma register offsets */
+ if (ctrl->nand_version >= 0x0703)
+ ctrl->flash_dma_offsets = flash_dma_regs_v4;
+ else
+ ctrl->flash_dma_offsets = flash_dma_regs_v1;
+}
+
static inline u32 brcmnand_read_reg(struct brcmnand_controller *ctrl,
enum brcmnand_reg reg)
{
@@ -580,6 +643,54 @@ static inline void brcmnand_write_fc(struct brcmnand_controller *ctrl,
__raw_writel(val, ctrl->nand_fc + word * 4);
}
+static void brcmnand_clear_ecc_addr(struct brcmnand_controller *ctrl)
+{
+
+ /* Clear error addresses */
+ brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_ADDR, 0);
+ brcmnand_write_reg(ctrl, BRCMNAND_CORR_ADDR, 0);
+ brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_EXT_ADDR, 0);
+ brcmnand_write_reg(ctrl, BRCMNAND_CORR_EXT_ADDR, 0);
+}
+
+static u64 brcmnand_get_uncorrecc_addr(struct brcmnand_controller *ctrl)
+{
+ u64 err_addr;
+
+ err_addr = brcmnand_read_reg(ctrl, BRCMNAND_UNCORR_ADDR);
+ err_addr |= ((u64)(brcmnand_read_reg(ctrl,
+ BRCMNAND_UNCORR_EXT_ADDR)
+ & 0xffff) << 32);
+
+ return err_addr;
+}
+
+static u64 brcmnand_get_correcc_addr(struct brcmnand_controller *ctrl)
+{
+ u64 err_addr;
+
+ err_addr = brcmnand_read_reg(ctrl, BRCMNAND_CORR_ADDR);
+ err_addr |= ((u64)(brcmnand_read_reg(ctrl,
+ BRCMNAND_CORR_EXT_ADDR)
+ & 0xffff) << 32);
+
+ return err_addr;
+}
+
+static void brcmnand_set_cmd_addr(struct mtd_info *mtd, u64 addr)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct brcmnand_host *host = nand_get_controller_data(chip);
+ struct brcmnand_controller *ctrl = host->ctrl;
+
+ brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS,
+ (host->cs << 16) | ((addr >> 32) & 0xffff));
+ (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS);
+ brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS,
+ lower_32_bits(addr));
+ (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
+}
+
static inline u16 brcmnand_cs_offset(struct brcmnand_controller *ctrl, int cs,
enum brcmnand_cs_reg reg)
{
@@ -612,7 +723,7 @@ static void brcmnand_wr_corr_thresh(struct brcmnand_host *host, u8 val)
enum brcmnand_reg reg = BRCMNAND_CORR_THRESHOLD;
int cs = host->cs;
- if (ctrl->nand_version >= 0x0702)
+ if (ctrl->nand_version == 0x0702)
bits = 7;
else if (ctrl->nand_version >= 0x0600)
bits = 6;
@@ -666,7 +777,7 @@ enum {
static inline u32 brcmnand_spare_area_mask(struct brcmnand_controller *ctrl)
{
- if (ctrl->nand_version >= 0x0702)
+ if (ctrl->nand_version == 0x0702)
return GENMASK(7, 0);
else if (ctrl->nand_version >= 0x0600)
return GENMASK(6, 0);
@@ -796,39 +907,44 @@ static inline void brcmnand_set_wp(struct brcmnand_controller *ctrl, bool en)
* Flash DMA
***********************************************************************/
-enum flash_dma_reg {
- FLASH_DMA_REVISION = 0x00,
- FLASH_DMA_FIRST_DESC = 0x04,
- FLASH_DMA_FIRST_DESC_EXT = 0x08,
- FLASH_DMA_CTRL = 0x0c,
- FLASH_DMA_MODE = 0x10,
- FLASH_DMA_STATUS = 0x14,
- FLASH_DMA_INTERRUPT_DESC = 0x18,
- FLASH_DMA_INTERRUPT_DESC_EXT = 0x1c,
- FLASH_DMA_ERROR_STATUS = 0x20,
- FLASH_DMA_CURRENT_DESC = 0x24,
- FLASH_DMA_CURRENT_DESC_EXT = 0x28,
-};
-
static inline bool has_flash_dma(struct brcmnand_controller *ctrl)
{
return ctrl->flash_dma_base;
}
+static inline void disable_ctrl_irqs(struct brcmnand_controller *ctrl)
+{
+ if (ctrl->pio_poll_mode)
+ return;
+
+ if (has_flash_dma(ctrl)) {
+ ctrl->flash_dma_base = 0;
+ disable_irq(ctrl->dma_irq);
+ }
+
+ disable_irq(ctrl->irq);
+ ctrl->pio_poll_mode = true;
+}
+
static inline bool flash_dma_buf_ok(const void *buf)
{
return buf && !is_vmalloc_addr(buf) &&
likely(IS_ALIGNED((uintptr_t)buf, 4));
}
-static inline void flash_dma_writel(struct brcmnand_controller *ctrl, u8 offs,
- u32 val)
+static inline void flash_dma_writel(struct brcmnand_controller *ctrl,
+ enum flash_dma_reg dma_reg, u32 val)
{
+ u16 offs = ctrl->flash_dma_offsets[dma_reg];
+
brcmnand_writel(val, ctrl->flash_dma_base + offs);
}
-static inline u32 flash_dma_readl(struct brcmnand_controller *ctrl, u8 offs)
+static inline u32 flash_dma_readl(struct brcmnand_controller *ctrl,
+ enum flash_dma_reg dma_reg)
{
+ u16 offs = ctrl->flash_dma_offsets[dma_reg];
+
return brcmnand_readl(ctrl->flash_dma_base + offs);
}
@@ -931,7 +1047,7 @@ static int brcmnand_bch_ooblayout_ecc(struct mtd_info *mtd, int section,
if (section >= sectors)
return -ERANGE;
- oobregion->offset = (section * (sas + 1)) - chip->ecc.bytes;
+ oobregion->offset = ((section + 1) * sas) - chip->ecc.bytes;
oobregion->length = chip->ecc.bytes;
return 0;
@@ -1205,9 +1321,12 @@ static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd)
{
struct brcmnand_controller *ctrl = host->ctrl;
int ret;
+ u64 cmd_addr;
+
+ cmd_addr = brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
+
+ dev_dbg(ctrl->dev, "send native cmd %d addr 0x%llx\n", cmd, cmd_addr);
- dev_dbg(ctrl->dev, "send native cmd %d addr_lo 0x%x\n", cmd,
- brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS));
BUG_ON(ctrl->cmd_pending != 0);
ctrl->cmd_pending = cmd;
@@ -1229,15 +1348,42 @@ static void brcmnand_cmd_ctrl(struct nand_chip *chip, int dat,
/* intentionally left blank */
}
+static bool brcmstb_nand_wait_for_completion(struct nand_chip *chip)
+{
+ struct brcmnand_host *host = nand_get_controller_data(chip);
+ struct brcmnand_controller *ctrl = host->ctrl;
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ bool err = false;
+ int sts;
+
+ if (mtd->oops_panic_write) {
+ /* switch to interrupt polling and PIO mode */
+ disable_ctrl_irqs(ctrl);
+ sts = bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY,
+ NAND_CTRL_RDY, 0);
+ err = (sts < 0) ? true : false;
+ } else {
+ unsigned long timeo = msecs_to_jiffies(
+ NAND_POLL_STATUS_TIMEOUT_MS);
+ /* wait for completion interrupt */
+ sts = wait_for_completion_timeout(&ctrl->done, timeo);
+ err = (sts <= 0) ? true : false;
+ }
+
+ return err;
+}
+
static int brcmnand_waitfunc(struct nand_chip *chip)
{
struct brcmnand_host *host = nand_get_controller_data(chip);
struct brcmnand_controller *ctrl = host->ctrl;
- unsigned long timeo = msecs_to_jiffies(100);
+ bool err = false;
dev_dbg(ctrl->dev, "wait on native cmd %d\n", ctrl->cmd_pending);
- if (ctrl->cmd_pending &&
- wait_for_completion_timeout(&ctrl->done, timeo) <= 0) {
+ if (ctrl->cmd_pending)
+ err = brcmstb_nand_wait_for_completion(chip);
+
+ if (err) {
u32 cmd = brcmnand_read_reg(ctrl, BRCMNAND_CMD_START)
>> brcmnand_cmd_shift(ctrl);
@@ -1366,12 +1512,7 @@ static void brcmnand_cmdfunc(struct nand_chip *chip, unsigned command,
if (!native_cmd)
return;
- brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS,
- (host->cs << 16) | ((addr >> 32) & 0xffff));
- (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS);
- brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS, lower_32_bits(addr));
- (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
-
+ brcmnand_set_cmd_addr(mtd, addr);
brcmnand_send_cmd(host, native_cmd);
brcmnand_waitfunc(chip);
@@ -1589,20 +1730,10 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
struct brcmnand_controller *ctrl = host->ctrl;
int i, j, ret = 0;
- /* Clear error addresses */
- brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_ADDR, 0);
- brcmnand_write_reg(ctrl, BRCMNAND_CORR_ADDR, 0);
- brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_EXT_ADDR, 0);
- brcmnand_write_reg(ctrl, BRCMNAND_CORR_EXT_ADDR, 0);
-
- brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS,
- (host->cs << 16) | ((addr >> 32) & 0xffff));
- (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS);
+ brcmnand_clear_ecc_addr(ctrl);
for (i = 0; i < trans; i++, addr += FC_BYTES) {
- brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS,
- lower_32_bits(addr));
- (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
+ brcmnand_set_cmd_addr(mtd, addr);
/* SPARE_AREA_READ does not use ECC, so just use PAGE_READ */
brcmnand_send_cmd(host, CMD_PAGE_READ);
brcmnand_waitfunc(chip);
@@ -1622,21 +1753,15 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
host->hwcfg.sector_size_1k);
if (!ret) {
- *err_addr = brcmnand_read_reg(ctrl,
- BRCMNAND_UNCORR_ADDR) |
- ((u64)(brcmnand_read_reg(ctrl,
- BRCMNAND_UNCORR_EXT_ADDR)
- & 0xffff) << 32);
+ *err_addr = brcmnand_get_uncorrecc_addr(ctrl);
+
if (*err_addr)
ret = -EBADMSG;
}
if (!ret) {
- *err_addr = brcmnand_read_reg(ctrl,
- BRCMNAND_CORR_ADDR) |
- ((u64)(brcmnand_read_reg(ctrl,
- BRCMNAND_CORR_EXT_ADDR)
- & 0xffff) << 32);
+ *err_addr = brcmnand_get_correcc_addr(ctrl);
+
if (*err_addr)
ret = -EUCLEAN;
}
@@ -1703,7 +1828,7 @@ static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip,
dev_dbg(ctrl->dev, "read %llx -> %p\n", (unsigned long long)addr, buf);
try_dmaread:
- brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_COUNT, 0);
+ brcmnand_clear_ecc_addr(ctrl);
if (has_flash_dma(ctrl) && !oob && flash_dma_buf_ok(buf)) {
err = brcmnand_dma_trans(host, addr, buf, trans * FC_BYTES,
@@ -1850,15 +1975,9 @@ static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip,
goto out;
}
- brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS,
- (host->cs << 16) | ((addr >> 32) & 0xffff));
- (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS);
-
for (i = 0; i < trans; i++, addr += FC_BYTES) {
/* full address MUST be set before populating FC */
- brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS,
- lower_32_bits(addr));
- (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
+ brcmnand_set_cmd_addr(mtd, addr);
if (buf) {
brcmnand_soc_data_bus_prepare(ctrl->soc, false);
@@ -2136,6 +2255,17 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
return -EINVAL;
}
+ if (chip->ecc.mode != NAND_ECC_NONE &&
+ (!chip->ecc.size || !chip->ecc.strength)) {
+ if (chip->base.eccreq.step_size && chip->base.eccreq.strength) {
+ /* use detected ECC parameters */
+ chip->ecc.size = chip->base.eccreq.step_size;
+ chip->ecc.strength = chip->base.eccreq.strength;
+ dev_info(ctrl->dev, "Using ECC step-size %d, strength %d\n",
+ chip->ecc.size, chip->ecc.strength);
+ }
+ }
+
switch (chip->ecc.size) {
case 512:
if (chip->ecc.algo == NAND_ECC_HAMMING)
@@ -2395,6 +2525,7 @@ static const struct of_device_id brcmnand_of_match[] = {
{ .compatible = "brcm,brcmnand-v7.0" },
{ .compatible = "brcm,brcmnand-v7.1" },
{ .compatible = "brcm,brcmnand-v7.2" },
+ { .compatible = "brcm,brcmnand-v7.3" },
{},
};
MODULE_DEVICE_TABLE(of, brcmnand_of_match);
@@ -2481,7 +2612,11 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
goto err;
}
- flash_dma_writel(ctrl, FLASH_DMA_MODE, 1); /* linked-list */
+ /* initialize the dma version */
+ brcmnand_flash_dma_revision_init(ctrl);
+
+ /* linked-list and stop on error */
+ flash_dma_writel(ctrl, FLASH_DMA_MODE, FLASH_DMA_MODE_MASK);
flash_dma_writel(ctrl, FLASH_DMA_ERROR_STATUS, 0);
/* Allocate descriptor(s) */
diff --git a/drivers/mtd/nand/raw/cmx270_nand.c b/drivers/mtd/nand/raw/cmx270_nand.c
index 143e4acacaae..045b6175ae79 100644
--- a/drivers/mtd/nand/raw/cmx270_nand.c
+++ b/drivers/mtd/nand/raw/cmx270_nand.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2006 Compulab, Ltd.
* Mike Rapoport <mike@compulab.co.il>
@@ -6,11 +7,6 @@
* Copyright (C) 2002 Marius Gröger (mag@sysgo.de)
* Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
*
- *
- * 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.
- *
* Overview:
* This is a device driver for the NAND flash device found on the
* CM-X270 board.
diff --git a/drivers/mtd/nand/raw/cs553x_nand.c b/drivers/mtd/nand/raw/cs553x_nand.c
index c6f578aff5d9..e2322cee3229 100644
--- a/drivers/mtd/nand/raw/cs553x_nand.c
+++ b/drivers/mtd/nand/raw/cs553x_nand.c
@@ -1,19 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* (C) 2005, 2006 Red Hat Inc.
*
* Author: David Woodhouse <dwmw2@infradead.org>
* Tom Sylla <tom.sylla@amd.com>
*
- * 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.
- *
* Overview:
* This is a device driver for the NAND flash controller found on
* the AMD CS5535/CS5536 companion chipsets for the Geode processor.
* mtd-id for command line partitioning is cs553x_nand_cs[0-3]
* where 0-3 reflects the chip select for NAND.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c
index 6c7ca41354be..a6964feeec77 100644
--- a/drivers/mtd/nand/raw/fsmc_nand.c
+++ b/drivers/mtd/nand/raw/fsmc_nand.c
@@ -613,28 +613,20 @@ static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op,
for (op_id = 0; op_id < op->ninstrs; op_id++) {
instr = &op->instrs[op_id];
+ nand_op_trace(" ", instr);
+
switch (instr->type) {
case NAND_OP_CMD_INSTR:
- pr_debug(" ->CMD [0x%02x]\n",
- instr->ctx.cmd.opcode);
-
writeb_relaxed(instr->ctx.cmd.opcode, host->cmd_va);
break;
case NAND_OP_ADDR_INSTR:
- pr_debug(" ->ADDR [%d cyc]",
- instr->ctx.addr.naddrs);
-
for (i = 0; i < instr->ctx.addr.naddrs; i++)
writeb_relaxed(instr->ctx.addr.addrs[i],
host->addr_va);
break;
case NAND_OP_DATA_IN_INSTR:
- pr_debug(" ->DATA_IN [%d B%s]\n", instr->ctx.data.len,
- instr->ctx.data.force_8bit ?
- ", force 8-bit" : "");
-
if (host->mode == USE_DMA_ACCESS)
fsmc_read_buf_dma(host, instr->ctx.data.buf.in,
instr->ctx.data.len);
@@ -644,10 +636,6 @@ static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op,
break;
case NAND_OP_DATA_OUT_INSTR:
- pr_debug(" ->DATA_OUT [%d B%s]\n", instr->ctx.data.len,
- instr->ctx.data.force_8bit ?
- ", force 8-bit" : "");
-
if (host->mode == USE_DMA_ACCESS)
fsmc_write_buf_dma(host,
instr->ctx.data.buf.out,
@@ -658,9 +646,6 @@ static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op,
break;
case NAND_OP_WAITRDY_INSTR:
- pr_debug(" ->WAITRDY [max %d ms]\n",
- instr->ctx.waitrdy.timeout_ms);
-
ret = nand_soft_waitrdy(chip,
instr->ctx.waitrdy.timeout_ms);
break;
diff --git a/drivers/mtd/nand/raw/gpio.c b/drivers/mtd/nand/raw/gpio.c
index a6c9a824a7d4..f6b12354024f 100644
--- a/drivers/mtd/nand/raw/gpio.c
+++ b/drivers/mtd/nand/raw/gpio.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Updated, and converted to generic GPIO based driver by Russell King.
*
@@ -9,11 +10,6 @@
* Device driver for NAND flash that uses a memory mapped interface to
* read/write the NAND commands and data, and GPIO pins for control signals
* (the DT binding refers to this as "GPIO assisted NAND flash")
- *
- * 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.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/mtd/nand/raw/gpmi-nand/Makefile b/drivers/mtd/nand/raw/gpmi-nand/Makefile
index 30ceee9704d1..9bd81a31e02e 100644
--- a/drivers/mtd/nand/raw/gpmi-nand/Makefile
+++ b/drivers/mtd/nand/raw/gpmi-nand/Makefile
@@ -1,4 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi_nand.o
gpmi_nand-objs += gpmi-nand.o
-gpmi_nand-objs += gpmi-lib.o
diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c
deleted file mode 100644
index a8b26d2e793c..000000000000
--- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c
+++ /dev/null
@@ -1,934 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Freescale GPMI NAND Flash Driver
- *
- * Copyright (C) 2008-2011 Freescale Semiconductor, Inc.
- * Copyright (C) 2008 Embedded Alley Solutions, Inc.
- */
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/slab.h>
-
-#include "gpmi-nand.h"
-#include "gpmi-regs.h"
-#include "bch-regs.h"
-
-/* Converts time to clock cycles */
-#define TO_CYCLES(duration, period) DIV_ROUND_UP_ULL(duration, period)
-
-#define MXS_SET_ADDR 0x4
-#define MXS_CLR_ADDR 0x8
-/*
- * Clear the bit and poll it cleared. This is usually called with
- * a reset address and mask being either SFTRST(bit 31) or CLKGATE
- * (bit 30).
- */
-static int clear_poll_bit(void __iomem *addr, u32 mask)
-{
- int timeout = 0x400;
-
- /* clear the bit */
- writel(mask, addr + MXS_CLR_ADDR);
-
- /*
- * SFTRST needs 3 GPMI clocks to settle, the reference manual
- * recommends to wait 1us.
- */
- udelay(1);
-
- /* poll the bit becoming clear */
- while ((readl(addr) & mask) && --timeout)
- /* nothing */;
-
- return !timeout;
-}
-
-#define MODULE_CLKGATE (1 << 30)
-#define MODULE_SFTRST (1 << 31)
-/*
- * The current mxs_reset_block() will do two things:
- * [1] enable the module.
- * [2] reset the module.
- *
- * In most of the cases, it's ok.
- * But in MX23, there is a hardware bug in the BCH block (see erratum #2847).
- * If you try to soft reset the BCH block, it becomes unusable until
- * the next hard reset. This case occurs in the NAND boot mode. When the board
- * boots by NAND, the ROM of the chip will initialize the BCH blocks itself.
- * So If the driver tries to reset the BCH again, the BCH will not work anymore.
- * You will see a DMA timeout in this case. The bug has been fixed
- * in the following chips, such as MX28.
- *
- * To avoid this bug, just add a new parameter `just_enable` for
- * the mxs_reset_block(), and rewrite it here.
- */
-static int gpmi_reset_block(void __iomem *reset_addr, bool just_enable)
-{
- int ret;
- int timeout = 0x400;
-
- /* clear and poll SFTRST */
- ret = clear_poll_bit(reset_addr, MODULE_SFTRST);
- if (unlikely(ret))
- goto error;
-
- /* clear CLKGATE */
- writel(MODULE_CLKGATE, reset_addr + MXS_CLR_ADDR);
-
- if (!just_enable) {
- /* set SFTRST to reset the block */
- writel(MODULE_SFTRST, reset_addr + MXS_SET_ADDR);
- udelay(1);
-
- /* poll CLKGATE becoming set */
- while ((!(readl(reset_addr) & MODULE_CLKGATE)) && --timeout)
- /* nothing */;
- if (unlikely(!timeout))
- goto error;
- }
-
- /* clear and poll SFTRST */
- ret = clear_poll_bit(reset_addr, MODULE_SFTRST);
- if (unlikely(ret))
- goto error;
-
- /* clear and poll CLKGATE */
- ret = clear_poll_bit(reset_addr, MODULE_CLKGATE);
- if (unlikely(ret))
- goto error;
-
- return 0;
-
-error:
- pr_err("%s(%p): module reset timeout\n", __func__, reset_addr);
- return -ETIMEDOUT;
-}
-
-static int __gpmi_enable_clk(struct gpmi_nand_data *this, bool v)
-{
- struct clk *clk;
- int ret;
- int i;
-
- for (i = 0; i < GPMI_CLK_MAX; i++) {
- clk = this->resources.clock[i];
- if (!clk)
- break;
-
- if (v) {
- ret = clk_prepare_enable(clk);
- if (ret)
- goto err_clk;
- } else {
- clk_disable_unprepare(clk);
- }
- }
- return 0;
-
-err_clk:
- for (; i > 0; i--)
- clk_disable_unprepare(this->resources.clock[i - 1]);
- return ret;
-}
-
-int gpmi_enable_clk(struct gpmi_nand_data *this)
-{
- return __gpmi_enable_clk(this, true);
-}
-
-int gpmi_disable_clk(struct gpmi_nand_data *this)
-{
- return __gpmi_enable_clk(this, false);
-}
-
-int gpmi_init(struct gpmi_nand_data *this)
-{
- struct resources *r = &this->resources;
- int ret;
-
- ret = gpmi_enable_clk(this);
- if (ret)
- return ret;
- ret = gpmi_reset_block(r->gpmi_regs, false);
- if (ret)
- goto err_out;
-
- /*
- * Reset BCH here, too. We got failures otherwise :(
- * See later BCH reset for explanation of MX23 and MX28 handling
- */
- ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MXS(this));
- if (ret)
- goto err_out;
-
- /* Choose NAND mode. */
- writel(BM_GPMI_CTRL1_GPMI_MODE, r->gpmi_regs + HW_GPMI_CTRL1_CLR);
-
- /* Set the IRQ polarity. */
- writel(BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY,
- r->gpmi_regs + HW_GPMI_CTRL1_SET);
-
- /* Disable Write-Protection. */
- writel(BM_GPMI_CTRL1_DEV_RESET, r->gpmi_regs + HW_GPMI_CTRL1_SET);
-
- /* Select BCH ECC. */
- writel(BM_GPMI_CTRL1_BCH_MODE, r->gpmi_regs + HW_GPMI_CTRL1_SET);
-
- /*
- * Decouple the chip select from dma channel. We use dma0 for all
- * the chips.
- */
- writel(BM_GPMI_CTRL1_DECOUPLE_CS, r->gpmi_regs + HW_GPMI_CTRL1_SET);
-
- gpmi_disable_clk(this);
- return 0;
-err_out:
- gpmi_disable_clk(this);
- return ret;
-}
-
-/* This function is very useful. It is called only when the bug occur. */
-void gpmi_dump_info(struct gpmi_nand_data *this)
-{
- struct resources *r = &this->resources;
- struct bch_geometry *geo = &this->bch_geometry;
- u32 reg;
- int i;
-
- dev_err(this->dev, "Show GPMI registers :\n");
- for (i = 0; i <= HW_GPMI_DEBUG / 0x10 + 1; i++) {
- reg = readl(r->gpmi_regs + i * 0x10);
- dev_err(this->dev, "offset 0x%.3x : 0x%.8x\n", i * 0x10, reg);
- }
-
- /* start to print out the BCH info */
- dev_err(this->dev, "Show BCH registers :\n");
- for (i = 0; i <= HW_BCH_VERSION / 0x10 + 1; i++) {
- reg = readl(r->bch_regs + i * 0x10);
- dev_err(this->dev, "offset 0x%.3x : 0x%.8x\n", i * 0x10, reg);
- }
- dev_err(this->dev, "BCH Geometry :\n"
- "GF length : %u\n"
- "ECC Strength : %u\n"
- "Page Size in Bytes : %u\n"
- "Metadata Size in Bytes : %u\n"
- "ECC Chunk Size in Bytes: %u\n"
- "ECC Chunk Count : %u\n"
- "Payload Size in Bytes : %u\n"
- "Auxiliary Size in Bytes: %u\n"
- "Auxiliary Status Offset: %u\n"
- "Block Mark Byte Offset : %u\n"
- "Block Mark Bit Offset : %u\n",
- geo->gf_len,
- geo->ecc_strength,
- geo->page_size,
- geo->metadata_size,
- geo->ecc_chunk_size,
- geo->ecc_chunk_count,
- geo->payload_size,
- geo->auxiliary_size,
- geo->auxiliary_status_offset,
- geo->block_mark_byte_offset,
- geo->block_mark_bit_offset);
-}
-
-/* Configures the geometry for BCH. */
-int bch_set_geometry(struct gpmi_nand_data *this)
-{
- struct resources *r = &this->resources;
- struct bch_geometry *bch_geo = &this->bch_geometry;
- unsigned int block_count;
- unsigned int block_size;
- unsigned int metadata_size;
- unsigned int ecc_strength;
- unsigned int page_size;
- unsigned int gf_len;
- int ret;
-
- ret = common_nfc_set_geometry(this);
- if (ret)
- return ret;
-
- block_count = bch_geo->ecc_chunk_count - 1;
- block_size = bch_geo->ecc_chunk_size;
- metadata_size = bch_geo->metadata_size;
- ecc_strength = bch_geo->ecc_strength >> 1;
- page_size = bch_geo->page_size;
- gf_len = bch_geo->gf_len;
-
- ret = gpmi_enable_clk(this);
- if (ret)
- return ret;
-
- /*
- * Due to erratum #2847 of the MX23, the BCH cannot be soft reset on this
- * chip, otherwise it will lock up. So we skip resetting BCH on the MX23.
- * and MX28.
- */
- ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MXS(this));
- if (ret)
- goto err_out;
-
- /* Configure layout 0. */
- writel(BF_BCH_FLASH0LAYOUT0_NBLOCKS(block_count)
- | BF_BCH_FLASH0LAYOUT0_META_SIZE(metadata_size)
- | BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength, this)
- | BF_BCH_FLASH0LAYOUT0_GF(gf_len, this)
- | BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(block_size, this),
- r->bch_regs + HW_BCH_FLASH0LAYOUT0);
-
- writel(BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size)
- | BF_BCH_FLASH0LAYOUT1_ECCN(ecc_strength, this)
- | BF_BCH_FLASH0LAYOUT1_GF(gf_len, this)
- | BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(block_size, this),
- r->bch_regs + HW_BCH_FLASH0LAYOUT1);
-
- /* Set *all* chip selects to use layout 0. */
- writel(0, r->bch_regs + HW_BCH_LAYOUTSELECT);
-
- /* Enable interrupts. */
- writel(BM_BCH_CTRL_COMPLETE_IRQ_EN,
- r->bch_regs + HW_BCH_CTRL_SET);
-
- gpmi_disable_clk(this);
- return 0;
-err_out:
- gpmi_disable_clk(this);
- return ret;
-}
-
-/*
- * <1> Firstly, we should know what's the GPMI-clock means.
- * The GPMI-clock is the internal clock in the gpmi nand controller.
- * If you set 100MHz to gpmi nand controller, the GPMI-clock's period
- * is 10ns. Mark the GPMI-clock's period as GPMI-clock-period.
- *
- * <2> Secondly, we should know what's the frequency on the nand chip pins.
- * The frequency on the nand chip pins is derived from the GPMI-clock.
- * We can get it from the following equation:
- *
- * F = G / (DS + DH)
- *
- * F : the frequency on the nand chip pins.
- * G : the GPMI clock, such as 100MHz.
- * DS : GPMI_HW_GPMI_TIMING0:DATA_SETUP
- * DH : GPMI_HW_GPMI_TIMING0:DATA_HOLD
- *
- * <3> Thirdly, when the frequency on the nand chip pins is above 33MHz,
- * the nand EDO(extended Data Out) timing could be applied.
- * The GPMI implements a feedback read strobe to sample the read data.
- * The feedback read strobe can be delayed to support the nand EDO timing
- * where the read strobe may deasserts before the read data is valid, and
- * read data is valid for some time after read strobe.
- *
- * The following figure illustrates some aspects of a NAND Flash read:
- *
- * |<---tREA---->|
- * | |
- * | | |
- * |<--tRP-->| |
- * | | |
- * __ ___|__________________________________
- * RDN \________/ |
- * |
- * /---------\
- * Read Data --------------< >---------
- * \---------/
- * | |
- * |<-D->|
- * FeedbackRDN ________ ____________
- * \___________/
- *
- * D stands for delay, set in the HW_GPMI_CTRL1:RDN_DELAY.
- *
- *
- * <4> Now, we begin to describe how to compute the right RDN_DELAY.
- *
- * 4.1) From the aspect of the nand chip pins:
- * Delay = (tREA + C - tRP) {1}
- *
- * tREA : the maximum read access time.
- * C : a constant to adjust the delay. default is 4000ps.
- * tRP : the read pulse width, which is exactly:
- * tRP = (GPMI-clock-period) * DATA_SETUP
- *
- * 4.2) From the aspect of the GPMI nand controller:
- * Delay = RDN_DELAY * 0.125 * RP {2}
- *
- * RP : the DLL reference period.
- * if (GPMI-clock-period > DLL_THRETHOLD)
- * RP = GPMI-clock-period / 2;
- * else
- * RP = GPMI-clock-period;
- *
- * Set the HW_GPMI_CTRL1:HALF_PERIOD if GPMI-clock-period
- * is greater DLL_THRETHOLD. In other SOCs, the DLL_THRETHOLD
- * is 16000ps, but in mx6q, we use 12000ps.
- *
- * 4.3) since {1} equals {2}, we get:
- *
- * (tREA + 4000 - tRP) * 8
- * RDN_DELAY = ----------------------- {3}
- * RP
- */
-static void gpmi_nfc_compute_timings(struct gpmi_nand_data *this,
- const struct nand_sdr_timings *sdr)
-{
- struct gpmi_nfc_hardware_timing *hw = &this->hw;
- unsigned int dll_threshold_ps = this->devdata->max_chain_delay;
- unsigned int period_ps, reference_period_ps;
- unsigned int data_setup_cycles, data_hold_cycles, addr_setup_cycles;
- unsigned int tRP_ps;
- bool use_half_period;
- int sample_delay_ps, sample_delay_factor;
- u16 busy_timeout_cycles;
- u8 wrn_dly_sel;
-
- if (sdr->tRC_min >= 30000) {
- /* ONFI non-EDO modes [0-3] */
- hw->clk_rate = 22000000;
- wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS;
- } else if (sdr->tRC_min >= 25000) {
- /* ONFI EDO mode 4 */
- hw->clk_rate = 80000000;
- wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY;
- } else {
- /* ONFI EDO mode 5 */
- hw->clk_rate = 100000000;
- wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY;
- }
-
- /* SDR core timings are given in picoseconds */
- period_ps = div_u64((u64)NSEC_PER_SEC * 1000, hw->clk_rate);
-
- addr_setup_cycles = TO_CYCLES(sdr->tALS_min, period_ps);
- data_setup_cycles = TO_CYCLES(sdr->tDS_min, period_ps);
- data_hold_cycles = TO_CYCLES(sdr->tDH_min, period_ps);
- busy_timeout_cycles = TO_CYCLES(sdr->tWB_max + sdr->tR_max, period_ps);
-
- hw->timing0 = BF_GPMI_TIMING0_ADDRESS_SETUP(addr_setup_cycles) |
- BF_GPMI_TIMING0_DATA_HOLD(data_hold_cycles) |
- BF_GPMI_TIMING0_DATA_SETUP(data_setup_cycles);
- hw->timing1 = BF_GPMI_TIMING1_BUSY_TIMEOUT(busy_timeout_cycles * 4096);
-
- /*
- * Derive NFC ideal delay from {3}:
- *
- * (tREA + 4000 - tRP) * 8
- * RDN_DELAY = -----------------------
- * RP
- */
- if (period_ps > dll_threshold_ps) {
- use_half_period = true;
- reference_period_ps = period_ps / 2;
- } else {
- use_half_period = false;
- reference_period_ps = period_ps;
- }
-
- tRP_ps = data_setup_cycles * period_ps;
- sample_delay_ps = (sdr->tREA_max + 4000 - tRP_ps) * 8;
- if (sample_delay_ps > 0)
- sample_delay_factor = sample_delay_ps / reference_period_ps;
- else
- sample_delay_factor = 0;
-
- hw->ctrl1n = BF_GPMI_CTRL1_WRN_DLY_SEL(wrn_dly_sel);
- if (sample_delay_factor)
- hw->ctrl1n |= BF_GPMI_CTRL1_RDN_DELAY(sample_delay_factor) |
- BM_GPMI_CTRL1_DLL_ENABLE |
- (use_half_period ? BM_GPMI_CTRL1_HALF_PERIOD : 0);
-}
-
-void gpmi_nfc_apply_timings(struct gpmi_nand_data *this)
-{
- struct gpmi_nfc_hardware_timing *hw = &this->hw;
- struct resources *r = &this->resources;
- void __iomem *gpmi_regs = r->gpmi_regs;
- unsigned int dll_wait_time_us;
-
- clk_set_rate(r->clock[0], hw->clk_rate);
-
- writel(hw->timing0, gpmi_regs + HW_GPMI_TIMING0);
- writel(hw->timing1, gpmi_regs + HW_GPMI_TIMING1);
-
- /*
- * Clear several CTRL1 fields, DLL must be disabled when setting
- * RDN_DELAY or HALF_PERIOD.
- */
- writel(BM_GPMI_CTRL1_CLEAR_MASK, gpmi_regs + HW_GPMI_CTRL1_CLR);
- writel(hw->ctrl1n, gpmi_regs + HW_GPMI_CTRL1_SET);
-
- /* Wait 64 clock cycles before using the GPMI after enabling the DLL */
- dll_wait_time_us = USEC_PER_SEC / hw->clk_rate * 64;
- if (!dll_wait_time_us)
- dll_wait_time_us = 1;
-
- /* Wait for the DLL to settle. */
- udelay(dll_wait_time_us);
-}
-
-int gpmi_setup_data_interface(struct nand_chip *chip, int chipnr,
- const struct nand_data_interface *conf)
-{
- struct gpmi_nand_data *this = nand_get_controller_data(chip);
- const struct nand_sdr_timings *sdr;
-
- /* Retrieve required NAND timings */
- sdr = nand_get_sdr_timings(conf);
- if (IS_ERR(sdr))
- return PTR_ERR(sdr);
-
- /* Only MX6 GPMI controller can reach EDO timings */
- if (sdr->tRC_min <= 25000 && !GPMI_IS_MX6(this))
- return -ENOTSUPP;
-
- /* Stop here if this call was just a check */
- if (chipnr < 0)
- return 0;
-
- /* Do the actual derivation of the controller timings */
- gpmi_nfc_compute_timings(this, sdr);
-
- this->hw.must_apply_timings = true;
-
- return 0;
-}
-
-/* Clears a BCH interrupt. */
-void gpmi_clear_bch(struct gpmi_nand_data *this)
-{
- struct resources *r = &this->resources;
- writel(BM_BCH_CTRL_COMPLETE_IRQ, r->bch_regs + HW_BCH_CTRL_CLR);
-}
-
-/* Returns the Ready/Busy status of the given chip. */
-int gpmi_is_ready(struct gpmi_nand_data *this, unsigned chip)
-{
- struct resources *r = &this->resources;
- uint32_t mask = 0;
- uint32_t reg = 0;
-
- if (GPMI_IS_MX23(this)) {
- mask = MX23_BM_GPMI_DEBUG_READY0 << chip;
- reg = readl(r->gpmi_regs + HW_GPMI_DEBUG);
- } else if (GPMI_IS_MX28(this) || GPMI_IS_MX6(this)) {
- /*
- * In the imx6, all the ready/busy pins are bound
- * together. So we only need to check chip 0.
- */
- if (GPMI_IS_MX6(this))
- chip = 0;
-
- /* MX28 shares the same R/B register as MX6Q. */
- mask = MX28_BF_GPMI_STAT_READY_BUSY(1 << chip);
- reg = readl(r->gpmi_regs + HW_GPMI_STAT);
- } else
- dev_err(this->dev, "unknown arch.\n");
- return reg & mask;
-}
-
-int gpmi_send_command(struct gpmi_nand_data *this)
-{
- struct dma_chan *channel = get_dma_chan(this);
- struct dma_async_tx_descriptor *desc;
- struct scatterlist *sgl;
- int chip = this->current_chip;
- int ret;
- u32 pio[3];
-
- /* [1] send out the PIO words */
- pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__WRITE)
- | BM_GPMI_CTRL0_WORD_LENGTH
- | BF_GPMI_CTRL0_CS(chip, this)
- | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
- | BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_CLE)
- | BM_GPMI_CTRL0_ADDRESS_INCREMENT
- | BF_GPMI_CTRL0_XFER_COUNT(this->command_length);
- pio[1] = pio[2] = 0;
- desc = dmaengine_prep_slave_sg(channel,
- (struct scatterlist *)pio,
- ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
- if (!desc)
- return -EINVAL;
-
- /* [2] send out the COMMAND + ADDRESS string stored in @buffer */
- sgl = &this->cmd_sgl;
-
- sg_init_one(sgl, this->cmd_buffer, this->command_length);
- dma_map_sg(this->dev, sgl, 1, DMA_TO_DEVICE);
- desc = dmaengine_prep_slave_sg(channel,
- sgl, 1, DMA_MEM_TO_DEV,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- if (!desc)
- return -EINVAL;
-
- /* [3] submit the DMA */
- ret = start_dma_without_bch_irq(this, desc);
-
- dma_unmap_sg(this->dev, sgl, 1, DMA_TO_DEVICE);
-
- return ret;
-}
-
-int gpmi_send_data(struct gpmi_nand_data *this, const void *buf, int len)
-{
- struct dma_async_tx_descriptor *desc;
- struct dma_chan *channel = get_dma_chan(this);
- int chip = this->current_chip;
- int ret;
- uint32_t command_mode;
- uint32_t address;
- u32 pio[2];
-
- /* [1] PIO */
- command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WRITE;
- address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
-
- pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
- | BM_GPMI_CTRL0_WORD_LENGTH
- | BF_GPMI_CTRL0_CS(chip, this)
- | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
- | BF_GPMI_CTRL0_ADDRESS(address)
- | BF_GPMI_CTRL0_XFER_COUNT(len);
- pio[1] = 0;
- desc = dmaengine_prep_slave_sg(channel, (struct scatterlist *)pio,
- ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
- if (!desc)
- return -EINVAL;
-
- /* [2] send DMA request */
- prepare_data_dma(this, buf, len, DMA_TO_DEVICE);
- desc = dmaengine_prep_slave_sg(channel, &this->data_sgl,
- 1, DMA_MEM_TO_DEV,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- if (!desc)
- return -EINVAL;
-
- /* [3] submit the DMA */
- ret = start_dma_without_bch_irq(this, desc);
-
- dma_unmap_sg(this->dev, &this->data_sgl, 1, DMA_TO_DEVICE);
-
- return ret;
-}
-
-int gpmi_read_data(struct gpmi_nand_data *this, void *buf, int len)
-{
- struct dma_async_tx_descriptor *desc;
- struct dma_chan *channel = get_dma_chan(this);
- int chip = this->current_chip;
- int ret;
- u32 pio[2];
- bool direct;
-
- /* [1] : send PIO */
- pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__READ)
- | BM_GPMI_CTRL0_WORD_LENGTH
- | BF_GPMI_CTRL0_CS(chip, this)
- | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
- | BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA)
- | BF_GPMI_CTRL0_XFER_COUNT(len);
- pio[1] = 0;
- desc = dmaengine_prep_slave_sg(channel,
- (struct scatterlist *)pio,
- ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
- if (!desc)
- return -EINVAL;
-
- /* [2] : send DMA request */
- direct = prepare_data_dma(this, buf, len, DMA_FROM_DEVICE);
- desc = dmaengine_prep_slave_sg(channel, &this->data_sgl,
- 1, DMA_DEV_TO_MEM,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- if (!desc)
- return -EINVAL;
-
- /* [3] : submit the DMA */
-
- ret = start_dma_without_bch_irq(this, desc);
-
- dma_unmap_sg(this->dev, &this->data_sgl, 1, DMA_FROM_DEVICE);
- if (!direct)
- memcpy(buf, this->data_buffer_dma, len);
-
- return ret;
-}
-
-int gpmi_send_page(struct gpmi_nand_data *this,
- dma_addr_t payload, dma_addr_t auxiliary)
-{
- struct bch_geometry *geo = &this->bch_geometry;
- uint32_t command_mode;
- uint32_t address;
- uint32_t ecc_command;
- uint32_t buffer_mask;
- struct dma_async_tx_descriptor *desc;
- struct dma_chan *channel = get_dma_chan(this);
- int chip = this->current_chip;
- u32 pio[6];
-
- /* A DMA descriptor that does an ECC page read. */
- command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WRITE;
- address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
- ecc_command = BV_GPMI_ECCCTRL_ECC_CMD__BCH_ENCODE;
- buffer_mask = BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE |
- BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY;
-
- pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
- | BM_GPMI_CTRL0_WORD_LENGTH
- | BF_GPMI_CTRL0_CS(chip, this)
- | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
- | BF_GPMI_CTRL0_ADDRESS(address)
- | BF_GPMI_CTRL0_XFER_COUNT(0);
- pio[1] = 0;
- pio[2] = BM_GPMI_ECCCTRL_ENABLE_ECC
- | BF_GPMI_ECCCTRL_ECC_CMD(ecc_command)
- | BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask);
- pio[3] = geo->page_size;
- pio[4] = payload;
- pio[5] = auxiliary;
-
- desc = dmaengine_prep_slave_sg(channel,
- (struct scatterlist *)pio,
- ARRAY_SIZE(pio), DMA_TRANS_NONE,
- DMA_CTRL_ACK);
- if (!desc)
- return -EINVAL;
-
- return start_dma_with_bch_irq(this, desc);
-}
-
-int gpmi_read_page(struct gpmi_nand_data *this,
- dma_addr_t payload, dma_addr_t auxiliary)
-{
- struct bch_geometry *geo = &this->bch_geometry;
- uint32_t command_mode;
- uint32_t address;
- uint32_t ecc_command;
- uint32_t buffer_mask;
- struct dma_async_tx_descriptor *desc;
- struct dma_chan *channel = get_dma_chan(this);
- int chip = this->current_chip;
- u32 pio[6];
-
- /* [1] Wait for the chip to report ready. */
- command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY;
- address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
-
- pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
- | BM_GPMI_CTRL0_WORD_LENGTH
- | BF_GPMI_CTRL0_CS(chip, this)
- | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
- | BF_GPMI_CTRL0_ADDRESS(address)
- | BF_GPMI_CTRL0_XFER_COUNT(0);
- pio[1] = 0;
- desc = dmaengine_prep_slave_sg(channel,
- (struct scatterlist *)pio, 2,
- DMA_TRANS_NONE, 0);
- if (!desc)
- return -EINVAL;
-
- /* [2] Enable the BCH block and read. */
- command_mode = BV_GPMI_CTRL0_COMMAND_MODE__READ;
- address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
- ecc_command = BV_GPMI_ECCCTRL_ECC_CMD__BCH_DECODE;
- buffer_mask = BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE
- | BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY;
-
- pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
- | BM_GPMI_CTRL0_WORD_LENGTH
- | BF_GPMI_CTRL0_CS(chip, this)
- | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
- | BF_GPMI_CTRL0_ADDRESS(address)
- | BF_GPMI_CTRL0_XFER_COUNT(geo->page_size);
-
- pio[1] = 0;
- pio[2] = BM_GPMI_ECCCTRL_ENABLE_ECC
- | BF_GPMI_ECCCTRL_ECC_CMD(ecc_command)
- | BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask);
- pio[3] = geo->page_size;
- pio[4] = payload;
- pio[5] = auxiliary;
- desc = dmaengine_prep_slave_sg(channel,
- (struct scatterlist *)pio,
- ARRAY_SIZE(pio), DMA_TRANS_NONE,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- if (!desc)
- return -EINVAL;
-
- /* [3] Disable the BCH block */
- command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY;
- address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
-
- pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
- | BM_GPMI_CTRL0_WORD_LENGTH
- | BF_GPMI_CTRL0_CS(chip, this)
- | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
- | BF_GPMI_CTRL0_ADDRESS(address)
- | BF_GPMI_CTRL0_XFER_COUNT(geo->page_size);
- pio[1] = 0;
- pio[2] = 0; /* clear GPMI_HW_GPMI_ECCCTRL, disable the BCH. */
- desc = dmaengine_prep_slave_sg(channel,
- (struct scatterlist *)pio, 3,
- DMA_TRANS_NONE,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- if (!desc)
- return -EINVAL;
-
- /* [4] submit the DMA */
- return start_dma_with_bch_irq(this, desc);
-}
-
-/**
- * gpmi_copy_bits - copy bits from one memory region to another
- * @dst: destination buffer
- * @dst_bit_off: bit offset we're starting to write at
- * @src: source buffer
- * @src_bit_off: bit offset we're starting to read from
- * @nbits: number of bits to copy
- *
- * This functions copies bits from one memory region to another, and is used by
- * the GPMI driver to copy ECC sections which are not guaranteed to be byte
- * aligned.
- *
- * src and dst should not overlap.
- *
- */
-void gpmi_copy_bits(u8 *dst, size_t dst_bit_off,
- const u8 *src, size_t src_bit_off,
- size_t nbits)
-{
- size_t i;
- size_t nbytes;
- u32 src_buffer = 0;
- size_t bits_in_src_buffer = 0;
-
- if (!nbits)
- return;
-
- /*
- * Move src and dst pointers to the closest byte pointer and store bit
- * offsets within a byte.
- */
- src += src_bit_off / 8;
- src_bit_off %= 8;
-
- dst += dst_bit_off / 8;
- dst_bit_off %= 8;
-
- /*
- * Initialize the src_buffer value with bits available in the first
- * byte of data so that we end up with a byte aligned src pointer.
- */
- if (src_bit_off) {
- src_buffer = src[0] >> src_bit_off;
- if (nbits >= (8 - src_bit_off)) {
- bits_in_src_buffer += 8 - src_bit_off;
- } else {
- src_buffer &= GENMASK(nbits - 1, 0);
- bits_in_src_buffer += nbits;
- }
- nbits -= bits_in_src_buffer;
- src++;
- }
-
- /* Calculate the number of bytes that can be copied from src to dst. */
- nbytes = nbits / 8;
-
- /* Try to align dst to a byte boundary. */
- if (dst_bit_off) {
- if (bits_in_src_buffer < (8 - dst_bit_off) && nbytes) {
- src_buffer |= src[0] << bits_in_src_buffer;
- bits_in_src_buffer += 8;
- src++;
- nbytes--;
- }
-
- if (bits_in_src_buffer >= (8 - dst_bit_off)) {
- dst[0] &= GENMASK(dst_bit_off - 1, 0);
- dst[0] |= src_buffer << dst_bit_off;
- src_buffer >>= (8 - dst_bit_off);
- bits_in_src_buffer -= (8 - dst_bit_off);
- dst_bit_off = 0;
- dst++;
- if (bits_in_src_buffer > 7) {
- bits_in_src_buffer -= 8;
- dst[0] = src_buffer;
- dst++;
- src_buffer >>= 8;
- }
- }
- }
-
- if (!bits_in_src_buffer && !dst_bit_off) {
- /*
- * Both src and dst pointers are byte aligned, thus we can
- * just use the optimized memcpy function.
- */
- if (nbytes)
- memcpy(dst, src, nbytes);
- } else {
- /*
- * src buffer is not byte aligned, hence we have to copy each
- * src byte to the src_buffer variable before extracting a byte
- * to store in dst.
- */
- for (i = 0; i < nbytes; i++) {
- src_buffer |= src[i] << bits_in_src_buffer;
- dst[i] = src_buffer;
- src_buffer >>= 8;
- }
- }
- /* Update dst and src pointers */
- dst += nbytes;
- src += nbytes;
-
- /*
- * nbits is the number of remaining bits. It should not exceed 8 as
- * we've already copied as much bytes as possible.
- */
- nbits %= 8;
-
- /*
- * If there's no more bits to copy to the destination and src buffer
- * was already byte aligned, then we're done.
- */
- if (!nbits && !bits_in_src_buffer)
- return;
-
- /* Copy the remaining bits to src_buffer */
- if (nbits)
- src_buffer |= (*src & GENMASK(nbits - 1, 0)) <<
- bits_in_src_buffer;
- bits_in_src_buffer += nbits;
-
- /*
- * In case there were not enough bits to get a byte aligned dst buffer
- * prepare the src_buffer variable to match the dst organization (shift
- * src_buffer by dst_bit_off and retrieve the least significant bits
- * from dst).
- */
- if (dst_bit_off)
- src_buffer = (src_buffer << dst_bit_off) |
- (*dst & GENMASK(dst_bit_off - 1, 0));
- bits_in_src_buffer += dst_bit_off;
-
- /*
- * Keep most significant bits from dst if we end up with an unaligned
- * number of bits.
- */
- nbytes = bits_in_src_buffer / 8;
- if (bits_in_src_buffer % 8) {
- src_buffer |= (dst[nbytes] &
- GENMASK(7, bits_in_src_buffer % 8)) <<
- (nbytes * 8);
- nbytes++;
- }
-
- /* Copy the remaining bytes to dst */
- for (i = 0; i < nbytes; i++) {
- dst[i] = src_buffer;
- src_buffer >>= 8;
- }
-}
diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
index 40df20d1adf5..334fe3130285 100644
--- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
@@ -6,6 +6,7 @@
* Copyright (C) 2008 Embedded Alley Solutions, Inc.
*/
#include <linux/clk.h>
+#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/sched/task_stack.h>
#include <linux/interrupt.h>
@@ -13,7 +14,10 @@
#include <linux/mtd/partitions.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/dma/mxs-dma.h>
#include "gpmi-nand.h"
+#include "gpmi-regs.h"
#include "bch-regs.h"
/* Resource names for the GPMI NAND driver. */
@@ -21,149 +25,208 @@
#define GPMI_NAND_BCH_REGS_ADDR_RES_NAME "bch"
#define GPMI_NAND_BCH_INTERRUPT_RES_NAME "bch"
-/* add our owner bbt descriptor */
-static uint8_t scan_ff_pattern[] = { 0xff };
-static struct nand_bbt_descr gpmi_bbt_descr = {
- .options = 0,
- .offs = 0,
- .len = 1,
- .pattern = scan_ff_pattern
-};
+/* Converts time to clock cycles */
+#define TO_CYCLES(duration, period) DIV_ROUND_UP_ULL(duration, period)
+#define MXS_SET_ADDR 0x4
+#define MXS_CLR_ADDR 0x8
/*
- * We may change the layout if we can get the ECC info from the datasheet,
- * else we will use all the (page + OOB).
+ * Clear the bit and poll it cleared. This is usually called with
+ * a reset address and mask being either SFTRST(bit 31) or CLKGATE
+ * (bit 30).
*/
-static int gpmi_ooblayout_ecc(struct mtd_info *mtd, int section,
- struct mtd_oob_region *oobregion)
+static int clear_poll_bit(void __iomem *addr, u32 mask)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
- struct gpmi_nand_data *this = nand_get_controller_data(chip);
- struct bch_geometry *geo = &this->bch_geometry;
+ int timeout = 0x400;
- if (section)
- return -ERANGE;
+ /* clear the bit */
+ writel(mask, addr + MXS_CLR_ADDR);
- oobregion->offset = 0;
- oobregion->length = geo->page_size - mtd->writesize;
+ /*
+ * SFTRST needs 3 GPMI clocks to settle, the reference manual
+ * recommends to wait 1us.
+ */
+ udelay(1);
- return 0;
+ /* poll the bit becoming clear */
+ while ((readl(addr) & mask) && --timeout)
+ /* nothing */;
+
+ return !timeout;
}
-static int gpmi_ooblayout_free(struct mtd_info *mtd, int section,
- struct mtd_oob_region *oobregion)
+#define MODULE_CLKGATE (1 << 30)
+#define MODULE_SFTRST (1 << 31)
+/*
+ * The current mxs_reset_block() will do two things:
+ * [1] enable the module.
+ * [2] reset the module.
+ *
+ * In most of the cases, it's ok.
+ * But in MX23, there is a hardware bug in the BCH block (see erratum #2847).
+ * If you try to soft reset the BCH block, it becomes unusable until
+ * the next hard reset. This case occurs in the NAND boot mode. When the board
+ * boots by NAND, the ROM of the chip will initialize the BCH blocks itself.
+ * So If the driver tries to reset the BCH again, the BCH will not work anymore.
+ * You will see a DMA timeout in this case. The bug has been fixed
+ * in the following chips, such as MX28.
+ *
+ * To avoid this bug, just add a new parameter `just_enable` for
+ * the mxs_reset_block(), and rewrite it here.
+ */
+static int gpmi_reset_block(void __iomem *reset_addr, bool just_enable)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
- struct gpmi_nand_data *this = nand_get_controller_data(chip);
- struct bch_geometry *geo = &this->bch_geometry;
+ int ret;
+ int timeout = 0x400;
+
+ /* clear and poll SFTRST */
+ ret = clear_poll_bit(reset_addr, MODULE_SFTRST);
+ if (unlikely(ret))
+ goto error;
+
+ /* clear CLKGATE */
+ writel(MODULE_CLKGATE, reset_addr + MXS_CLR_ADDR);
+
+ if (!just_enable) {
+ /* set SFTRST to reset the block */
+ writel(MODULE_SFTRST, reset_addr + MXS_SET_ADDR);
+ udelay(1);
+
+ /* poll CLKGATE becoming set */
+ while ((!(readl(reset_addr) & MODULE_CLKGATE)) && --timeout)
+ /* nothing */;
+ if (unlikely(!timeout))
+ goto error;
+ }
- if (section)
- return -ERANGE;
+ /* clear and poll SFTRST */
+ ret = clear_poll_bit(reset_addr, MODULE_SFTRST);
+ if (unlikely(ret))
+ goto error;
- /* The available oob size we have. */
- if (geo->page_size < mtd->writesize + mtd->oobsize) {
- oobregion->offset = geo->page_size - mtd->writesize;
- oobregion->length = mtd->oobsize - oobregion->offset;
- }
+ /* clear and poll CLKGATE */
+ ret = clear_poll_bit(reset_addr, MODULE_CLKGATE);
+ if (unlikely(ret))
+ goto error;
return 0;
+
+error:
+ pr_err("%s(%p): module reset timeout\n", __func__, reset_addr);
+ return -ETIMEDOUT;
}
-static const char * const gpmi_clks_for_mx2x[] = {
- "gpmi_io",
-};
+static int __gpmi_enable_clk(struct gpmi_nand_data *this, bool v)
+{
+ struct clk *clk;
+ int ret;
+ int i;
-static const struct mtd_ooblayout_ops gpmi_ooblayout_ops = {
- .ecc = gpmi_ooblayout_ecc,
- .free = gpmi_ooblayout_free,
-};
+ for (i = 0; i < GPMI_CLK_MAX; i++) {
+ clk = this->resources.clock[i];
+ if (!clk)
+ break;
-static const struct gpmi_devdata gpmi_devdata_imx23 = {
- .type = IS_MX23,
- .bch_max_ecc_strength = 20,
- .max_chain_delay = 16000,
- .clks = gpmi_clks_for_mx2x,
- .clks_count = ARRAY_SIZE(gpmi_clks_for_mx2x),
-};
+ if (v) {
+ ret = clk_prepare_enable(clk);
+ if (ret)
+ goto err_clk;
+ } else {
+ clk_disable_unprepare(clk);
+ }
+ }
+ return 0;
-static const struct gpmi_devdata gpmi_devdata_imx28 = {
- .type = IS_MX28,
- .bch_max_ecc_strength = 20,
- .max_chain_delay = 16000,
- .clks = gpmi_clks_for_mx2x,
- .clks_count = ARRAY_SIZE(gpmi_clks_for_mx2x),
-};
+err_clk:
+ for (; i > 0; i--)
+ clk_disable_unprepare(this->resources.clock[i - 1]);
+ return ret;
+}
-static const char * const gpmi_clks_for_mx6[] = {
- "gpmi_io", "gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch",
-};
+static int gpmi_init(struct gpmi_nand_data *this)
+{
+ struct resources *r = &this->resources;
+ int ret;
-static const struct gpmi_devdata gpmi_devdata_imx6q = {
- .type = IS_MX6Q,
- .bch_max_ecc_strength = 40,
- .max_chain_delay = 12000,
- .clks = gpmi_clks_for_mx6,
- .clks_count = ARRAY_SIZE(gpmi_clks_for_mx6),
-};
+ ret = gpmi_reset_block(r->gpmi_regs, false);
+ if (ret)
+ goto err_out;
-static const struct gpmi_devdata gpmi_devdata_imx6sx = {
- .type = IS_MX6SX,
- .bch_max_ecc_strength = 62,
- .max_chain_delay = 12000,
- .clks = gpmi_clks_for_mx6,
- .clks_count = ARRAY_SIZE(gpmi_clks_for_mx6),
-};
+ /*
+ * Reset BCH here, too. We got failures otherwise :(
+ * See later BCH reset for explanation of MX23 and MX28 handling
+ */
+ ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MXS(this));
+ if (ret)
+ goto err_out;
-static const char * const gpmi_clks_for_mx7d[] = {
- "gpmi_io", "gpmi_bch_apb",
-};
+ /* Choose NAND mode. */
+ writel(BM_GPMI_CTRL1_GPMI_MODE, r->gpmi_regs + HW_GPMI_CTRL1_CLR);
-static const struct gpmi_devdata gpmi_devdata_imx7d = {
- .type = IS_MX7D,
- .bch_max_ecc_strength = 62,
- .max_chain_delay = 12000,
- .clks = gpmi_clks_for_mx7d,
- .clks_count = ARRAY_SIZE(gpmi_clks_for_mx7d),
-};
+ /* Set the IRQ polarity. */
+ writel(BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY,
+ r->gpmi_regs + HW_GPMI_CTRL1_SET);
-static irqreturn_t bch_irq(int irq, void *cookie)
-{
- struct gpmi_nand_data *this = cookie;
+ /* Disable Write-Protection. */
+ writel(BM_GPMI_CTRL1_DEV_RESET, r->gpmi_regs + HW_GPMI_CTRL1_SET);
- gpmi_clear_bch(this);
- complete(&this->bch_done);
- return IRQ_HANDLED;
+ /* Select BCH ECC. */
+ writel(BM_GPMI_CTRL1_BCH_MODE, r->gpmi_regs + HW_GPMI_CTRL1_SET);
+
+ /*
+ * Decouple the chip select from dma channel. We use dma0 for all
+ * the chips.
+ */
+ writel(BM_GPMI_CTRL1_DECOUPLE_CS, r->gpmi_regs + HW_GPMI_CTRL1_SET);
+
+ return 0;
+err_out:
+ return ret;
}
-/*
- * Calculate the ECC strength by hand:
- * E : The ECC strength.
- * G : the length of Galois Field.
- * N : The chunk count of per page.
- * O : the oobsize of the NAND chip.
- * M : the metasize of per page.
- *
- * The formula is :
- * E * G * N
- * ------------ <= (O - M)
- * 8
- *
- * So, we get E by:
- * (O - M) * 8
- * E <= -------------
- * G * N
- */
-static inline int get_ecc_strength(struct gpmi_nand_data *this)
+/* This function is very useful. It is called only when the bug occur. */
+static void gpmi_dump_info(struct gpmi_nand_data *this)
{
+ struct resources *r = &this->resources;
struct bch_geometry *geo = &this->bch_geometry;
- struct mtd_info *mtd = nand_to_mtd(&this->nand);
- int ecc_strength;
+ u32 reg;
+ int i;
- ecc_strength = ((mtd->oobsize - geo->metadata_size) * 8)
- / (geo->gf_len * geo->ecc_chunk_count);
+ dev_err(this->dev, "Show GPMI registers :\n");
+ for (i = 0; i <= HW_GPMI_DEBUG / 0x10 + 1; i++) {
+ reg = readl(r->gpmi_regs + i * 0x10);
+ dev_err(this->dev, "offset 0x%.3x : 0x%.8x\n", i * 0x10, reg);
+ }
- /* We need the minor even number. */
- return round_down(ecc_strength, 2);
+ /* start to print out the BCH info */
+ dev_err(this->dev, "Show BCH registers :\n");
+ for (i = 0; i <= HW_BCH_VERSION / 0x10 + 1; i++) {
+ reg = readl(r->bch_regs + i * 0x10);
+ dev_err(this->dev, "offset 0x%.3x : 0x%.8x\n", i * 0x10, reg);
+ }
+ dev_err(this->dev, "BCH Geometry :\n"
+ "GF length : %u\n"
+ "ECC Strength : %u\n"
+ "Page Size in Bytes : %u\n"
+ "Metadata Size in Bytes : %u\n"
+ "ECC Chunk Size in Bytes: %u\n"
+ "ECC Chunk Count : %u\n"
+ "Payload Size in Bytes : %u\n"
+ "Auxiliary Size in Bytes: %u\n"
+ "Auxiliary Status Offset: %u\n"
+ "Block Mark Byte Offset : %u\n"
+ "Block Mark Bit Offset : %u\n",
+ geo->gf_len,
+ geo->ecc_strength,
+ geo->page_size,
+ geo->metadata_size,
+ geo->ecc_chunk_size,
+ geo->ecc_chunk_count,
+ geo->payload_size,
+ geo->auxiliary_size,
+ geo->auxiliary_status_offset,
+ geo->block_mark_byte_offset,
+ geo->block_mark_bit_offset);
}
static inline bool gpmi_check_ecc(struct gpmi_nand_data *this)
@@ -296,6 +359,37 @@ static int set_geometry_by_ecc_info(struct gpmi_nand_data *this,
return 0;
}
+/*
+ * Calculate the ECC strength by hand:
+ * E : The ECC strength.
+ * G : the length of Galois Field.
+ * N : The chunk count of per page.
+ * O : the oobsize of the NAND chip.
+ * M : the metasize of per page.
+ *
+ * The formula is :
+ * E * G * N
+ * ------------ <= (O - M)
+ * 8
+ *
+ * So, we get E by:
+ * (O - M) * 8
+ * E <= -------------
+ * G * N
+ */
+static inline int get_ecc_strength(struct gpmi_nand_data *this)
+{
+ struct bch_geometry *geo = &this->bch_geometry;
+ struct mtd_info *mtd = nand_to_mtd(&this->nand);
+ int ecc_strength;
+
+ ecc_strength = ((mtd->oobsize - geo->metadata_size) * 8)
+ / (geo->gf_len * geo->ecc_chunk_count);
+
+ /* We need the minor even number. */
+ return round_down(ecc_strength, 2);
+}
+
static int legacy_set_geometry(struct gpmi_nand_data *this)
{
struct bch_geometry *geo = &this->bch_geometry;
@@ -408,7 +502,7 @@ static int legacy_set_geometry(struct gpmi_nand_data *this)
return 0;
}
-int common_nfc_set_geometry(struct gpmi_nand_data *this)
+static int common_nfc_set_geometry(struct gpmi_nand_data *this)
{
struct nand_chip *chip = &this->nand;
@@ -430,18 +524,288 @@ int common_nfc_set_geometry(struct gpmi_nand_data *this)
return 0;
}
-struct dma_chan *get_dma_chan(struct gpmi_nand_data *this)
+/* Configures the geometry for BCH. */
+static int bch_set_geometry(struct gpmi_nand_data *this)
+{
+ struct resources *r = &this->resources;
+ int ret;
+
+ ret = common_nfc_set_geometry(this);
+ if (ret)
+ return ret;
+
+ ret = pm_runtime_get_sync(this->dev);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Due to erratum #2847 of the MX23, the BCH cannot be soft reset on this
+ * chip, otherwise it will lock up. So we skip resetting BCH on the MX23.
+ * and MX28.
+ */
+ ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MXS(this));
+ if (ret)
+ goto err_out;
+
+ /* Set *all* chip selects to use layout 0. */
+ writel(0, r->bch_regs + HW_BCH_LAYOUTSELECT);
+
+ ret = 0;
+err_out:
+ pm_runtime_mark_last_busy(this->dev);
+ pm_runtime_put_autosuspend(this->dev);
+
+ return ret;
+}
+
+/*
+ * <1> Firstly, we should know what's the GPMI-clock means.
+ * The GPMI-clock is the internal clock in the gpmi nand controller.
+ * If you set 100MHz to gpmi nand controller, the GPMI-clock's period
+ * is 10ns. Mark the GPMI-clock's period as GPMI-clock-period.
+ *
+ * <2> Secondly, we should know what's the frequency on the nand chip pins.
+ * The frequency on the nand chip pins is derived from the GPMI-clock.
+ * We can get it from the following equation:
+ *
+ * F = G / (DS + DH)
+ *
+ * F : the frequency on the nand chip pins.
+ * G : the GPMI clock, such as 100MHz.
+ * DS : GPMI_HW_GPMI_TIMING0:DATA_SETUP
+ * DH : GPMI_HW_GPMI_TIMING0:DATA_HOLD
+ *
+ * <3> Thirdly, when the frequency on the nand chip pins is above 33MHz,
+ * the nand EDO(extended Data Out) timing could be applied.
+ * The GPMI implements a feedback read strobe to sample the read data.
+ * The feedback read strobe can be delayed to support the nand EDO timing
+ * where the read strobe may deasserts before the read data is valid, and
+ * read data is valid for some time after read strobe.
+ *
+ * The following figure illustrates some aspects of a NAND Flash read:
+ *
+ * |<---tREA---->|
+ * | |
+ * | | |
+ * |<--tRP-->| |
+ * | | |
+ * __ ___|__________________________________
+ * RDN \________/ |
+ * |
+ * /---------\
+ * Read Data --------------< >---------
+ * \---------/
+ * | |
+ * |<-D->|
+ * FeedbackRDN ________ ____________
+ * \___________/
+ *
+ * D stands for delay, set in the HW_GPMI_CTRL1:RDN_DELAY.
+ *
+ *
+ * <4> Now, we begin to describe how to compute the right RDN_DELAY.
+ *
+ * 4.1) From the aspect of the nand chip pins:
+ * Delay = (tREA + C - tRP) {1}
+ *
+ * tREA : the maximum read access time.
+ * C : a constant to adjust the delay. default is 4000ps.
+ * tRP : the read pulse width, which is exactly:
+ * tRP = (GPMI-clock-period) * DATA_SETUP
+ *
+ * 4.2) From the aspect of the GPMI nand controller:
+ * Delay = RDN_DELAY * 0.125 * RP {2}
+ *
+ * RP : the DLL reference period.
+ * if (GPMI-clock-period > DLL_THRETHOLD)
+ * RP = GPMI-clock-period / 2;
+ * else
+ * RP = GPMI-clock-period;
+ *
+ * Set the HW_GPMI_CTRL1:HALF_PERIOD if GPMI-clock-period
+ * is greater DLL_THRETHOLD. In other SOCs, the DLL_THRETHOLD
+ * is 16000ps, but in mx6q, we use 12000ps.
+ *
+ * 4.3) since {1} equals {2}, we get:
+ *
+ * (tREA + 4000 - tRP) * 8
+ * RDN_DELAY = ----------------------- {3}
+ * RP
+ */
+static void gpmi_nfc_compute_timings(struct gpmi_nand_data *this,
+ const struct nand_sdr_timings *sdr)
+{
+ struct gpmi_nfc_hardware_timing *hw = &this->hw;
+ unsigned int dll_threshold_ps = this->devdata->max_chain_delay;
+ unsigned int period_ps, reference_period_ps;
+ unsigned int data_setup_cycles, data_hold_cycles, addr_setup_cycles;
+ unsigned int tRP_ps;
+ bool use_half_period;
+ int sample_delay_ps, sample_delay_factor;
+ u16 busy_timeout_cycles;
+ u8 wrn_dly_sel;
+
+ if (sdr->tRC_min >= 30000) {
+ /* ONFI non-EDO modes [0-3] */
+ hw->clk_rate = 22000000;
+ wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS;
+ } else if (sdr->tRC_min >= 25000) {
+ /* ONFI EDO mode 4 */
+ hw->clk_rate = 80000000;
+ wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY;
+ } else {
+ /* ONFI EDO mode 5 */
+ hw->clk_rate = 100000000;
+ wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY;
+ }
+
+ /* SDR core timings are given in picoseconds */
+ period_ps = div_u64((u64)NSEC_PER_SEC * 1000, hw->clk_rate);
+
+ addr_setup_cycles = TO_CYCLES(sdr->tALS_min, period_ps);
+ data_setup_cycles = TO_CYCLES(sdr->tDS_min, period_ps);
+ data_hold_cycles = TO_CYCLES(sdr->tDH_min, period_ps);
+ busy_timeout_cycles = TO_CYCLES(sdr->tWB_max + sdr->tR_max, period_ps);
+
+ hw->timing0 = BF_GPMI_TIMING0_ADDRESS_SETUP(addr_setup_cycles) |
+ BF_GPMI_TIMING0_DATA_HOLD(data_hold_cycles) |
+ BF_GPMI_TIMING0_DATA_SETUP(data_setup_cycles);
+ hw->timing1 = BF_GPMI_TIMING1_BUSY_TIMEOUT(busy_timeout_cycles * 4096);
+
+ /*
+ * Derive NFC ideal delay from {3}:
+ *
+ * (tREA + 4000 - tRP) * 8
+ * RDN_DELAY = -----------------------
+ * RP
+ */
+ if (period_ps > dll_threshold_ps) {
+ use_half_period = true;
+ reference_period_ps = period_ps / 2;
+ } else {
+ use_half_period = false;
+ reference_period_ps = period_ps;
+ }
+
+ tRP_ps = data_setup_cycles * period_ps;
+ sample_delay_ps = (sdr->tREA_max + 4000 - tRP_ps) * 8;
+ if (sample_delay_ps > 0)
+ sample_delay_factor = sample_delay_ps / reference_period_ps;
+ else
+ sample_delay_factor = 0;
+
+ hw->ctrl1n = BF_GPMI_CTRL1_WRN_DLY_SEL(wrn_dly_sel);
+ if (sample_delay_factor)
+ hw->ctrl1n |= BF_GPMI_CTRL1_RDN_DELAY(sample_delay_factor) |
+ BM_GPMI_CTRL1_DLL_ENABLE |
+ (use_half_period ? BM_GPMI_CTRL1_HALF_PERIOD : 0);
+}
+
+static void gpmi_nfc_apply_timings(struct gpmi_nand_data *this)
+{
+ struct gpmi_nfc_hardware_timing *hw = &this->hw;
+ struct resources *r = &this->resources;
+ void __iomem *gpmi_regs = r->gpmi_regs;
+ unsigned int dll_wait_time_us;
+
+ clk_set_rate(r->clock[0], hw->clk_rate);
+
+ writel(hw->timing0, gpmi_regs + HW_GPMI_TIMING0);
+ writel(hw->timing1, gpmi_regs + HW_GPMI_TIMING1);
+
+ /*
+ * Clear several CTRL1 fields, DLL must be disabled when setting
+ * RDN_DELAY or HALF_PERIOD.
+ */
+ writel(BM_GPMI_CTRL1_CLEAR_MASK, gpmi_regs + HW_GPMI_CTRL1_CLR);
+ writel(hw->ctrl1n, gpmi_regs + HW_GPMI_CTRL1_SET);
+
+ /* Wait 64 clock cycles before using the GPMI after enabling the DLL */
+ dll_wait_time_us = USEC_PER_SEC / hw->clk_rate * 64;
+ if (!dll_wait_time_us)
+ dll_wait_time_us = 1;
+
+ /* Wait for the DLL to settle. */
+ udelay(dll_wait_time_us);
+}
+
+static int gpmi_setup_data_interface(struct nand_chip *chip, int chipnr,
+ const struct nand_data_interface *conf)
+{
+ struct gpmi_nand_data *this = nand_get_controller_data(chip);
+ const struct nand_sdr_timings *sdr;
+
+ /* Retrieve required NAND timings */
+ sdr = nand_get_sdr_timings(conf);
+ if (IS_ERR(sdr))
+ return PTR_ERR(sdr);
+
+ /* Only MX6 GPMI controller can reach EDO timings */
+ if (sdr->tRC_min <= 25000 && !GPMI_IS_MX6(this))
+ return -ENOTSUPP;
+
+ /* Stop here if this call was just a check */
+ if (chipnr < 0)
+ return 0;
+
+ /* Do the actual derivation of the controller timings */
+ gpmi_nfc_compute_timings(this, sdr);
+
+ this->hw.must_apply_timings = true;
+
+ return 0;
+}
+
+/* Clears a BCH interrupt. */
+static void gpmi_clear_bch(struct gpmi_nand_data *this)
+{
+ struct resources *r = &this->resources;
+ writel(BM_BCH_CTRL_COMPLETE_IRQ, r->bch_regs + HW_BCH_CTRL_CLR);
+}
+
+static struct dma_chan *get_dma_chan(struct gpmi_nand_data *this)
{
/* We use the DMA channel 0 to access all the nand chips. */
return this->dma_chans[0];
}
+/* This will be called after the DMA operation is finished. */
+static void dma_irq_callback(void *param)
+{
+ struct gpmi_nand_data *this = param;
+ struct completion *dma_c = &this->dma_done;
+
+ complete(dma_c);
+}
+
+static irqreturn_t bch_irq(int irq, void *cookie)
+{
+ struct gpmi_nand_data *this = cookie;
+
+ gpmi_clear_bch(this);
+ complete(&this->bch_done);
+ return IRQ_HANDLED;
+}
+
+static int gpmi_raw_len_to_len(struct gpmi_nand_data *this, int raw_len)
+{
+ /*
+ * raw_len is the length to read/write including bch data which
+ * we are passed in exec_op. Calculate the data length from it.
+ */
+ if (this->bch)
+ return ALIGN_DOWN(raw_len, this->bch_geometry.ecc_chunk_size);
+ else
+ return raw_len;
+}
+
/* Can we use the upper's buffer directly for DMA? */
-bool prepare_data_dma(struct gpmi_nand_data *this, const void *buf, int len,
- enum dma_data_direction dr)
+static bool prepare_data_dma(struct gpmi_nand_data *this, const void *buf,
+ int raw_len, struct scatterlist *sgl,
+ enum dma_data_direction dr)
{
- struct scatterlist *sgl = &this->data_sgl;
int ret;
+ int len = gpmi_raw_len_to_len(this, raw_len);
/* first try to map the upper buffer directly */
if (virt_addr_valid(buf) && !object_is_on_stack(buf)) {
@@ -457,7 +821,7 @@ map_fail:
/* We have to use our own DMA buffer. */
sg_init_one(sgl, this->data_buffer_dma, len);
- if (dr == DMA_TO_DEVICE)
+ if (dr == DMA_TO_DEVICE && buf != this->data_buffer_dma)
memcpy(this->data_buffer_dma, buf, len);
dma_map_sg(this->dev, sgl, 1, dr);
@@ -465,67 +829,263 @@ map_fail:
return false;
}
-/* This will be called after the DMA operation is finished. */
-static void dma_irq_callback(void *param)
+/**
+ * gpmi_copy_bits - copy bits from one memory region to another
+ * @dst: destination buffer
+ * @dst_bit_off: bit offset we're starting to write at
+ * @src: source buffer
+ * @src_bit_off: bit offset we're starting to read from
+ * @nbits: number of bits to copy
+ *
+ * This functions copies bits from one memory region to another, and is used by
+ * the GPMI driver to copy ECC sections which are not guaranteed to be byte
+ * aligned.
+ *
+ * src and dst should not overlap.
+ *
+ */
+static void gpmi_copy_bits(u8 *dst, size_t dst_bit_off, const u8 *src,
+ size_t src_bit_off, size_t nbits)
{
- struct gpmi_nand_data *this = param;
- struct completion *dma_c = &this->dma_done;
+ size_t i;
+ size_t nbytes;
+ u32 src_buffer = 0;
+ size_t bits_in_src_buffer = 0;
- complete(dma_c);
-}
+ if (!nbits)
+ return;
-int start_dma_without_bch_irq(struct gpmi_nand_data *this,
- struct dma_async_tx_descriptor *desc)
-{
- struct completion *dma_c = &this->dma_done;
- unsigned long timeout;
+ /*
+ * Move src and dst pointers to the closest byte pointer and store bit
+ * offsets within a byte.
+ */
+ src += src_bit_off / 8;
+ src_bit_off %= 8;
- init_completion(dma_c);
+ dst += dst_bit_off / 8;
+ dst_bit_off %= 8;
- desc->callback = dma_irq_callback;
- desc->callback_param = this;
- dmaengine_submit(desc);
- dma_async_issue_pending(get_dma_chan(this));
+ /*
+ * Initialize the src_buffer value with bits available in the first
+ * byte of data so that we end up with a byte aligned src pointer.
+ */
+ if (src_bit_off) {
+ src_buffer = src[0] >> src_bit_off;
+ if (nbits >= (8 - src_bit_off)) {
+ bits_in_src_buffer += 8 - src_bit_off;
+ } else {
+ src_buffer &= GENMASK(nbits - 1, 0);
+ bits_in_src_buffer += nbits;
+ }
+ nbits -= bits_in_src_buffer;
+ src++;
+ }
- /* Wait for the interrupt from the DMA block. */
- timeout = wait_for_completion_timeout(dma_c, msecs_to_jiffies(1000));
- if (!timeout) {
- dev_err(this->dev, "DMA timeout, last DMA\n");
- gpmi_dump_info(this);
- return -ETIMEDOUT;
+ /* Calculate the number of bytes that can be copied from src to dst. */
+ nbytes = nbits / 8;
+
+ /* Try to align dst to a byte boundary. */
+ if (dst_bit_off) {
+ if (bits_in_src_buffer < (8 - dst_bit_off) && nbytes) {
+ src_buffer |= src[0] << bits_in_src_buffer;
+ bits_in_src_buffer += 8;
+ src++;
+ nbytes--;
+ }
+
+ if (bits_in_src_buffer >= (8 - dst_bit_off)) {
+ dst[0] &= GENMASK(dst_bit_off - 1, 0);
+ dst[0] |= src_buffer << dst_bit_off;
+ src_buffer >>= (8 - dst_bit_off);
+ bits_in_src_buffer -= (8 - dst_bit_off);
+ dst_bit_off = 0;
+ dst++;
+ if (bits_in_src_buffer > 7) {
+ bits_in_src_buffer -= 8;
+ dst[0] = src_buffer;
+ dst++;
+ src_buffer >>= 8;
+ }
+ }
+ }
+
+ if (!bits_in_src_buffer && !dst_bit_off) {
+ /*
+ * Both src and dst pointers are byte aligned, thus we can
+ * just use the optimized memcpy function.
+ */
+ if (nbytes)
+ memcpy(dst, src, nbytes);
+ } else {
+ /*
+ * src buffer is not byte aligned, hence we have to copy each
+ * src byte to the src_buffer variable before extracting a byte
+ * to store in dst.
+ */
+ for (i = 0; i < nbytes; i++) {
+ src_buffer |= src[i] << bits_in_src_buffer;
+ dst[i] = src_buffer;
+ src_buffer >>= 8;
+ }
+ }
+ /* Update dst and src pointers */
+ dst += nbytes;
+ src += nbytes;
+
+ /*
+ * nbits is the number of remaining bits. It should not exceed 8 as
+ * we've already copied as much bytes as possible.
+ */
+ nbits %= 8;
+
+ /*
+ * If there's no more bits to copy to the destination and src buffer
+ * was already byte aligned, then we're done.
+ */
+ if (!nbits && !bits_in_src_buffer)
+ return;
+
+ /* Copy the remaining bits to src_buffer */
+ if (nbits)
+ src_buffer |= (*src & GENMASK(nbits - 1, 0)) <<
+ bits_in_src_buffer;
+ bits_in_src_buffer += nbits;
+
+ /*
+ * In case there were not enough bits to get a byte aligned dst buffer
+ * prepare the src_buffer variable to match the dst organization (shift
+ * src_buffer by dst_bit_off and retrieve the least significant bits
+ * from dst).
+ */
+ if (dst_bit_off)
+ src_buffer = (src_buffer << dst_bit_off) |
+ (*dst & GENMASK(dst_bit_off - 1, 0));
+ bits_in_src_buffer += dst_bit_off;
+
+ /*
+ * Keep most significant bits from dst if we end up with an unaligned
+ * number of bits.
+ */
+ nbytes = bits_in_src_buffer / 8;
+ if (bits_in_src_buffer % 8) {
+ src_buffer |= (dst[nbytes] &
+ GENMASK(7, bits_in_src_buffer % 8)) <<
+ (nbytes * 8);
+ nbytes++;
+ }
+
+ /* Copy the remaining bytes to dst */
+ for (i = 0; i < nbytes; i++) {
+ dst[i] = src_buffer;
+ src_buffer >>= 8;
}
- return 0;
}
+/* add our owner bbt descriptor */
+static uint8_t scan_ff_pattern[] = { 0xff };
+static struct nand_bbt_descr gpmi_bbt_descr = {
+ .options = 0,
+ .offs = 0,
+ .len = 1,
+ .pattern = scan_ff_pattern
+};
+
/*
- * This function is used in BCH reading or BCH writing pages.
- * It will wait for the BCH interrupt as long as ONE second.
- * Actually, we must wait for two interrupts :
- * [1] firstly the DMA interrupt and
- * [2] secondly the BCH interrupt.
+ * We may change the layout if we can get the ECC info from the datasheet,
+ * else we will use all the (page + OOB).
*/
-int start_dma_with_bch_irq(struct gpmi_nand_data *this,
- struct dma_async_tx_descriptor *desc)
+static int gpmi_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobregion)
{
- struct completion *bch_c = &this->bch_done;
- unsigned long timeout;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct gpmi_nand_data *this = nand_get_controller_data(chip);
+ struct bch_geometry *geo = &this->bch_geometry;
- /* Prepare to receive an interrupt from the BCH block. */
- init_completion(bch_c);
+ if (section)
+ return -ERANGE;
- /* start the DMA */
- start_dma_without_bch_irq(this, desc);
+ oobregion->offset = 0;
+ oobregion->length = geo->page_size - mtd->writesize;
- /* Wait for the interrupt from the BCH block. */
- timeout = wait_for_completion_timeout(bch_c, msecs_to_jiffies(1000));
- if (!timeout) {
- dev_err(this->dev, "BCH timeout\n");
- gpmi_dump_info(this);
- return -ETIMEDOUT;
+ return 0;
+}
+
+static int gpmi_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobregion)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct gpmi_nand_data *this = nand_get_controller_data(chip);
+ struct bch_geometry *geo = &this->bch_geometry;
+
+ if (section)
+ return -ERANGE;
+
+ /* The available oob size we have. */
+ if (geo->page_size < mtd->writesize + mtd->oobsize) {
+ oobregion->offset = geo->page_size - mtd->writesize;
+ oobregion->length = mtd->oobsize - oobregion->offset;
}
+
return 0;
}
+static const char * const gpmi_clks_for_mx2x[] = {
+ "gpmi_io",
+};
+
+static const struct mtd_ooblayout_ops gpmi_ooblayout_ops = {
+ .ecc = gpmi_ooblayout_ecc,
+ .free = gpmi_ooblayout_free,
+};
+
+static const struct gpmi_devdata gpmi_devdata_imx23 = {
+ .type = IS_MX23,
+ .bch_max_ecc_strength = 20,
+ .max_chain_delay = 16000,
+ .clks = gpmi_clks_for_mx2x,
+ .clks_count = ARRAY_SIZE(gpmi_clks_for_mx2x),
+};
+
+static const struct gpmi_devdata gpmi_devdata_imx28 = {
+ .type = IS_MX28,
+ .bch_max_ecc_strength = 20,
+ .max_chain_delay = 16000,
+ .clks = gpmi_clks_for_mx2x,
+ .clks_count = ARRAY_SIZE(gpmi_clks_for_mx2x),
+};
+
+static const char * const gpmi_clks_for_mx6[] = {
+ "gpmi_io", "gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch",
+};
+
+static const struct gpmi_devdata gpmi_devdata_imx6q = {
+ .type = IS_MX6Q,
+ .bch_max_ecc_strength = 40,
+ .max_chain_delay = 12000,
+ .clks = gpmi_clks_for_mx6,
+ .clks_count = ARRAY_SIZE(gpmi_clks_for_mx6),
+};
+
+static const struct gpmi_devdata gpmi_devdata_imx6sx = {
+ .type = IS_MX6SX,
+ .bch_max_ecc_strength = 62,
+ .max_chain_delay = 12000,
+ .clks = gpmi_clks_for_mx6,
+ .clks_count = ARRAY_SIZE(gpmi_clks_for_mx6),
+};
+
+static const char * const gpmi_clks_for_mx7d[] = {
+ "gpmi_io", "gpmi_bch_apb",
+};
+
+static const struct gpmi_devdata gpmi_devdata_imx7d = {
+ .type = IS_MX7D,
+ .bch_max_ecc_strength = 62,
+ .max_chain_delay = 12000,
+ .clks = gpmi_clks_for_mx7d,
+ .clks_count = ARRAY_SIZE(gpmi_clks_for_mx7d),
+};
+
static int acquire_register_block(struct gpmi_nand_data *this,
const char *res_name)
{
@@ -667,68 +1227,20 @@ static void release_resources(struct gpmi_nand_data *this)
release_dma_channels(this);
}
-static int send_page_prepare(struct gpmi_nand_data *this,
- const void *source, unsigned length,
- void *alt_virt, dma_addr_t alt_phys, unsigned alt_size,
- const void **use_virt, dma_addr_t *use_phys)
-{
- struct device *dev = this->dev;
-
- if (virt_addr_valid(source)) {
- dma_addr_t source_phys;
-
- source_phys = dma_map_single(dev, (void *)source, length,
- DMA_TO_DEVICE);
- if (dma_mapping_error(dev, source_phys)) {
- if (alt_size < length) {
- dev_err(dev, "Alternate buffer is too small\n");
- return -ENOMEM;
- }
- goto map_failed;
- }
- *use_virt = source;
- *use_phys = source_phys;
- return 0;
- }
-map_failed:
- /*
- * Copy the content of the source buffer into the alternate
- * buffer and set up the return values accordingly.
- */
- memcpy(alt_virt, source, length);
-
- *use_virt = alt_virt;
- *use_phys = alt_phys;
- return 0;
-}
-
-static void send_page_end(struct gpmi_nand_data *this,
- const void *source, unsigned length,
- void *alt_virt, dma_addr_t alt_phys, unsigned alt_size,
- const void *used_virt, dma_addr_t used_phys)
-{
- struct device *dev = this->dev;
- if (used_virt == source)
- dma_unmap_single(dev, used_phys, length, DMA_TO_DEVICE);
-}
-
static void gpmi_free_dma_buffer(struct gpmi_nand_data *this)
{
struct device *dev = this->dev;
+ struct bch_geometry *geo = &this->bch_geometry;
- if (this->page_buffer_virt && virt_addr_valid(this->page_buffer_virt))
- dma_free_coherent(dev, this->page_buffer_size,
- this->page_buffer_virt,
- this->page_buffer_phys);
- kfree(this->cmd_buffer);
+ if (this->auxiliary_virt && virt_addr_valid(this->auxiliary_virt))
+ dma_free_coherent(dev, geo->auxiliary_size,
+ this->auxiliary_virt,
+ this->auxiliary_phys);
kfree(this->data_buffer_dma);
kfree(this->raw_buffer);
- this->cmd_buffer = NULL;
this->data_buffer_dma = NULL;
this->raw_buffer = NULL;
- this->page_buffer_virt = NULL;
- this->page_buffer_size = 0;
}
/* Allocate the DMA buffers */
@@ -738,11 +1250,6 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this)
struct device *dev = this->dev;
struct mtd_info *mtd = nand_to_mtd(&this->nand);
- /* [1] Allocate a command buffer. PAGE_SIZE is enough. */
- this->cmd_buffer = kzalloc(PAGE_SIZE, GFP_DMA | GFP_KERNEL);
- if (this->cmd_buffer == NULL)
- goto error_alloc;
-
/*
* [2] Allocate a read/write data buffer.
* The gpmi_alloc_dma_buffer can be called twice.
@@ -756,29 +1263,15 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this)
if (this->data_buffer_dma == NULL)
goto error_alloc;
- /*
- * [3] Allocate the page buffer.
- *
- * Both the payload buffer and the auxiliary buffer must appear on
- * 32-bit boundaries. We presume the size of the payload buffer is a
- * power of two and is much larger than four, which guarantees the
- * auxiliary buffer will appear on a 32-bit boundary.
- */
- this->page_buffer_size = geo->payload_size + geo->auxiliary_size;
- this->page_buffer_virt = dma_alloc_coherent(dev, this->page_buffer_size,
- &this->page_buffer_phys, GFP_DMA);
- if (!this->page_buffer_virt)
+ this->auxiliary_virt = dma_alloc_coherent(dev, geo->auxiliary_size,
+ &this->auxiliary_phys, GFP_DMA);
+ if (!this->auxiliary_virt)
goto error_alloc;
- this->raw_buffer = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
+ this->raw_buffer = kzalloc((mtd->writesize ?: PAGE_SIZE) + mtd->oobsize, GFP_KERNEL);
if (!this->raw_buffer)
goto error_alloc;
- /* Slice up the page buffer. */
- this->payload_virt = this->page_buffer_virt;
- this->payload_phys = this->page_buffer_phys;
- this->auxiliary_virt = this->payload_virt + geo->payload_size;
- this->auxiliary_phys = this->payload_phys + geo->payload_size;
return 0;
error_alloc:
@@ -786,106 +1279,6 @@ error_alloc:
return -ENOMEM;
}
-static void gpmi_cmd_ctrl(struct nand_chip *chip, int data, unsigned int ctrl)
-{
- struct gpmi_nand_data *this = nand_get_controller_data(chip);
- int ret;
-
- /*
- * Every operation begins with a command byte and a series of zero or
- * more address bytes. These are distinguished by either the Address
- * Latch Enable (ALE) or Command Latch Enable (CLE) signals being
- * asserted. When MTD is ready to execute the command, it will deassert
- * both latch enables.
- *
- * Rather than run a separate DMA operation for every single byte, we
- * queue them up and run a single DMA operation for the entire series
- * of command and data bytes. NAND_CMD_NONE means the END of the queue.
- */
- if ((ctrl & (NAND_ALE | NAND_CLE))) {
- if (data != NAND_CMD_NONE)
- this->cmd_buffer[this->command_length++] = data;
- return;
- }
-
- if (!this->command_length)
- return;
-
- ret = gpmi_send_command(this);
- if (ret)
- dev_err(this->dev, "Chip: %u, Error %d\n",
- this->current_chip, ret);
-
- this->command_length = 0;
-}
-
-static int gpmi_dev_ready(struct nand_chip *chip)
-{
- struct gpmi_nand_data *this = nand_get_controller_data(chip);
-
- return gpmi_is_ready(this, this->current_chip);
-}
-
-static void gpmi_select_chip(struct nand_chip *chip, int chipnr)
-{
- struct gpmi_nand_data *this = nand_get_controller_data(chip);
- int ret;
-
- /*
- * For power consumption matters, disable/enable the clock each time a
- * die is selected/unselected.
- */
- if (this->current_chip < 0 && chipnr >= 0) {
- ret = gpmi_enable_clk(this);
- if (ret)
- dev_err(this->dev, "Failed to enable the clock\n");
- } else if (this->current_chip >= 0 && chipnr < 0) {
- ret = gpmi_disable_clk(this);
- if (ret)
- dev_err(this->dev, "Failed to disable the clock\n");
- }
-
- /*
- * This driver currently supports only one NAND chip. Plus, dies share
- * the same configuration. So once timings have been applied on the
- * controller side, they will not change anymore. When the time will
- * come, the check on must_apply_timings will have to be dropped.
- */
- if (chipnr >= 0 && this->hw.must_apply_timings) {
- this->hw.must_apply_timings = false;
- gpmi_nfc_apply_timings(this);
- }
-
- this->current_chip = chipnr;
-}
-
-static void gpmi_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
-{
- struct gpmi_nand_data *this = nand_get_controller_data(chip);
-
- dev_dbg(this->dev, "len is %d\n", len);
-
- gpmi_read_data(this, buf, len);
-}
-
-static void gpmi_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
-{
- struct gpmi_nand_data *this = nand_get_controller_data(chip);
-
- dev_dbg(this->dev, "len is %d\n", len);
-
- gpmi_send_data(this, buf, len);
-}
-
-static uint8_t gpmi_read_byte(struct nand_chip *chip)
-{
- struct gpmi_nand_data *this = nand_get_controller_data(chip);
- uint8_t *buf = this->data_buffer_dma;
-
- gpmi_read_buf(chip, buf, 1);
- return buf[0];
-}
-
/*
* Handles block mark swapping.
* It can be called in swapping the block mark, or swapping it back,
@@ -934,54 +1327,20 @@ static void block_mark_swapping(struct gpmi_nand_data *this,
p[1] = (p[1] & mask) | (from_oob >> (8 - bit));
}
-static int gpmi_ecc_read_page_data(struct nand_chip *chip,
- uint8_t *buf, int oob_required,
- int page)
+static int gpmi_count_bitflips(struct nand_chip *chip, void *buf, int first,
+ int last, int meta)
{
struct gpmi_nand_data *this = nand_get_controller_data(chip);
struct bch_geometry *nfc_geo = &this->bch_geometry;
struct mtd_info *mtd = nand_to_mtd(chip);
- dma_addr_t payload_phys;
- unsigned int i;
+ int i;
unsigned char *status;
- unsigned int max_bitflips = 0;
- int ret;
- bool direct = false;
-
- dev_dbg(this->dev, "page number is : %d\n", page);
-
- payload_phys = this->payload_phys;
-
- if (virt_addr_valid(buf)) {
- dma_addr_t dest_phys;
-
- dest_phys = dma_map_single(this->dev, buf, nfc_geo->payload_size,
- DMA_FROM_DEVICE);
- if (!dma_mapping_error(this->dev, dest_phys)) {
- payload_phys = dest_phys;
- direct = true;
- }
- }
-
- /* go! */
- ret = gpmi_read_page(this, payload_phys, this->auxiliary_phys);
-
- if (direct)
- dma_unmap_single(this->dev, payload_phys, nfc_geo->payload_size,
- DMA_FROM_DEVICE);
-
- if (ret) {
- dev_err(this->dev, "Error in ECC-based read: %d\n", ret);
- return ret;
- }
+ unsigned int max_bitflips = 0;
/* Loop over status bytes, accumulating ECC status. */
- status = this->auxiliary_virt + nfc_geo->auxiliary_status_offset;
-
- if (!direct)
- memcpy(buf, this->payload_virt, nfc_geo->payload_size);
+ status = this->auxiliary_virt + ALIGN(meta, 4);
- for (i = 0; i < nfc_geo->ecc_chunk_count; i++, status++) {
+ for (i = first; i < last; i++, status++) {
if ((*status == STATUS_GOOD) || (*status == STATUS_ERASED))
continue;
@@ -1061,6 +1420,50 @@ static int gpmi_ecc_read_page_data(struct nand_chip *chip,
max_bitflips = max_t(unsigned int, max_bitflips, *status);
}
+ return max_bitflips;
+}
+
+static void gpmi_bch_layout_std(struct gpmi_nand_data *this)
+{
+ struct bch_geometry *geo = &this->bch_geometry;
+ unsigned int ecc_strength = geo->ecc_strength >> 1;
+ unsigned int gf_len = geo->gf_len;
+ unsigned int block_size = geo->ecc_chunk_size;
+
+ this->bch_flashlayout0 =
+ BF_BCH_FLASH0LAYOUT0_NBLOCKS(geo->ecc_chunk_count - 1) |
+ BF_BCH_FLASH0LAYOUT0_META_SIZE(geo->metadata_size) |
+ BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength, this) |
+ BF_BCH_FLASH0LAYOUT0_GF(gf_len, this) |
+ BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(block_size, this);
+
+ this->bch_flashlayout1 =
+ BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(geo->page_size) |
+ BF_BCH_FLASH0LAYOUT1_ECCN(ecc_strength, this) |
+ BF_BCH_FLASH0LAYOUT1_GF(gf_len, this) |
+ BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(block_size, this);
+}
+
+static int gpmi_ecc_read_page(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
+{
+ struct gpmi_nand_data *this = nand_get_controller_data(chip);
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct bch_geometry *geo = &this->bch_geometry;
+ unsigned int max_bitflips;
+ int ret;
+
+ gpmi_bch_layout_std(this);
+ this->bch = true;
+
+ ret = nand_read_page_op(chip, page, 0, buf, geo->page_size);
+ if (ret)
+ return ret;
+
+ max_bitflips = gpmi_count_bitflips(chip, buf, 0,
+ geo->ecc_chunk_count,
+ geo->auxiliary_status_offset);
+
/* handle the block mark swapping */
block_mark_swapping(this, buf, this->auxiliary_virt);
@@ -1082,30 +1485,20 @@ static int gpmi_ecc_read_page_data(struct nand_chip *chip,
return max_bitflips;
}
-static int gpmi_ecc_read_page(struct nand_chip *chip, uint8_t *buf,
- int oob_required, int page)
-{
- nand_read_page_op(chip, page, 0, NULL, 0);
-
- return gpmi_ecc_read_page_data(chip, buf, oob_required, page);
-}
-
/* Fake a virtual small page for the subpage read */
static int gpmi_ecc_read_subpage(struct nand_chip *chip, uint32_t offs,
uint32_t len, uint8_t *buf, int page)
{
struct gpmi_nand_data *this = nand_get_controller_data(chip);
- void __iomem *bch_regs = this->resources.bch_regs;
- struct bch_geometry old_geo = this->bch_geometry;
struct bch_geometry *geo = &this->bch_geometry;
int size = chip->ecc.size; /* ECC chunk size */
int meta, n, page_size;
- u32 r1_old, r2_old, r1_new, r2_new;
unsigned int max_bitflips;
+ unsigned int ecc_strength;
int first, last, marker_pos;
int ecc_parity_size;
int col = 0;
- int old_swap_block_mark = this->swap_block_mark;
+ int ret;
/* The size of ECC parity */
ecc_parity_size = geo->gf_len * geo->ecc_strength / 8;
@@ -1138,43 +1531,33 @@ static int gpmi_ecc_read_subpage(struct nand_chip *chip, uint32_t offs,
buf = buf + first * size;
}
- nand_read_page_op(chip, page, col, NULL, 0);
-
- /* Save the old environment */
- r1_old = r1_new = readl(bch_regs + HW_BCH_FLASH0LAYOUT0);
- r2_old = r2_new = readl(bch_regs + HW_BCH_FLASH0LAYOUT1);
+ ecc_parity_size = geo->gf_len * geo->ecc_strength / 8;
- /* change the BCH registers and bch_geometry{} */
n = last - first + 1;
page_size = meta + (size + ecc_parity_size) * n;
+ ecc_strength = geo->ecc_strength >> 1;
- r1_new &= ~(BM_BCH_FLASH0LAYOUT0_NBLOCKS |
- BM_BCH_FLASH0LAYOUT0_META_SIZE);
- r1_new |= BF_BCH_FLASH0LAYOUT0_NBLOCKS(n - 1)
- | BF_BCH_FLASH0LAYOUT0_META_SIZE(meta);
- writel(r1_new, bch_regs + HW_BCH_FLASH0LAYOUT0);
+ this->bch_flashlayout0 = BF_BCH_FLASH0LAYOUT0_NBLOCKS(n - 1) |
+ BF_BCH_FLASH0LAYOUT0_META_SIZE(meta) |
+ BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength, this) |
+ BF_BCH_FLASH0LAYOUT0_GF(geo->gf_len, this) |
+ BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(geo->ecc_chunk_size, this);
- r2_new &= ~BM_BCH_FLASH0LAYOUT1_PAGE_SIZE;
- r2_new |= BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size);
- writel(r2_new, bch_regs + HW_BCH_FLASH0LAYOUT1);
+ this->bch_flashlayout1 = BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size) |
+ BF_BCH_FLASH0LAYOUT1_ECCN(ecc_strength, this) |
+ BF_BCH_FLASH0LAYOUT1_GF(geo->gf_len, this) |
+ BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(geo->ecc_chunk_size, this);
- geo->ecc_chunk_count = n;
- geo->payload_size = n * size;
- geo->page_size = page_size;
- geo->auxiliary_status_offset = ALIGN(meta, 4);
+ this->bch = true;
+
+ ret = nand_read_page_op(chip, page, col, buf, page_size);
+ if (ret)
+ return ret;
dev_dbg(this->dev, "page:%d(%d:%d)%d, chunk:(%d:%d), BCH PG size:%d\n",
page, offs, len, col, first, n, page_size);
- /* Read the subpage now */
- this->swap_block_mark = false;
- max_bitflips = gpmi_ecc_read_page_data(chip, buf, 0, page);
-
- /* Restore */
- writel(r1_old, bch_regs + HW_BCH_FLASH0LAYOUT0);
- writel(r2_old, bch_regs + HW_BCH_FLASH0LAYOUT1);
- this->bch_geometry = old_geo;
- this->swap_block_mark = old_swap_block_mark;
+ max_bitflips = gpmi_count_bitflips(chip, buf, first, last, meta);
return max_bitflips;
}
@@ -1185,81 +1568,29 @@ static int gpmi_ecc_write_page(struct nand_chip *chip, const uint8_t *buf,
struct mtd_info *mtd = nand_to_mtd(chip);
struct gpmi_nand_data *this = nand_get_controller_data(chip);
struct bch_geometry *nfc_geo = &this->bch_geometry;
- const void *payload_virt;
- dma_addr_t payload_phys;
- const void *auxiliary_virt;
- dma_addr_t auxiliary_phys;
- int ret;
+ int ret;
dev_dbg(this->dev, "ecc write page.\n");
- nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+ gpmi_bch_layout_std(this);
+ this->bch = true;
+
+ memcpy(this->auxiliary_virt, chip->oob_poi, nfc_geo->auxiliary_size);
if (this->swap_block_mark) {
/*
- * If control arrives here, we're doing block mark swapping.
- * Since we can't modify the caller's buffers, we must copy them
- * into our own.
- */
- memcpy(this->payload_virt, buf, mtd->writesize);
- payload_virt = this->payload_virt;
- payload_phys = this->payload_phys;
-
- memcpy(this->auxiliary_virt, chip->oob_poi,
- nfc_geo->auxiliary_size);
- auxiliary_virt = this->auxiliary_virt;
- auxiliary_phys = this->auxiliary_phys;
-
- /* Handle block mark swapping. */
- block_mark_swapping(this,
- (void *)payload_virt, (void *)auxiliary_virt);
- } else {
- /*
- * If control arrives here, we're not doing block mark swapping,
- * so we can to try and use the caller's buffers.
+ * When doing bad block marker swapping we must always copy the
+ * input buffer as we can't modify the const buffer.
*/
- ret = send_page_prepare(this,
- buf, mtd->writesize,
- this->payload_virt, this->payload_phys,
- nfc_geo->payload_size,
- &payload_virt, &payload_phys);
- if (ret) {
- dev_err(this->dev, "Inadequate payload DMA buffer\n");
- return 0;
- }
-
- ret = send_page_prepare(this,
- chip->oob_poi, mtd->oobsize,
- this->auxiliary_virt, this->auxiliary_phys,
- nfc_geo->auxiliary_size,
- &auxiliary_virt, &auxiliary_phys);
- if (ret) {
- dev_err(this->dev, "Inadequate auxiliary DMA buffer\n");
- goto exit_auxiliary;
- }
+ memcpy(this->data_buffer_dma, buf, mtd->writesize);
+ buf = this->data_buffer_dma;
+ block_mark_swapping(this, this->data_buffer_dma,
+ this->auxiliary_virt);
}
- /* Ask the NFC. */
- ret = gpmi_send_page(this, payload_phys, auxiliary_phys);
- if (ret)
- dev_err(this->dev, "Error in ECC-based write: %d\n", ret);
-
- if (!this->swap_block_mark) {
- send_page_end(this, chip->oob_poi, mtd->oobsize,
- this->auxiliary_virt, this->auxiliary_phys,
- nfc_geo->auxiliary_size,
- auxiliary_virt, auxiliary_phys);
-exit_auxiliary:
- send_page_end(this, buf, mtd->writesize,
- this->payload_virt, this->payload_phys,
- nfc_geo->payload_size,
- payload_virt, payload_phys);
- }
+ ret = nand_prog_page_op(chip, page, 0, buf, nfc_geo->page_size);
- if (ret)
- return ret;
-
- return nand_prog_page_end_op(chip);
+ return ret;
}
/*
@@ -1326,14 +1657,16 @@ static int gpmi_ecc_read_oob(struct nand_chip *chip, int page)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct gpmi_nand_data *this = nand_get_controller_data(chip);
+ int ret;
- dev_dbg(this->dev, "page number is %d\n", page);
/* clear the OOB buffer */
memset(chip->oob_poi, ~0, mtd->oobsize);
/* Read out the conventional OOB. */
- nand_read_page_op(chip, page, mtd->writesize, NULL, 0);
- chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize);
+ ret = nand_read_page_op(chip, page, mtd->writesize, chip->oob_poi,
+ mtd->oobsize);
+ if (ret)
+ return ret;
/*
* Now, we want to make sure the block mark is correct. In the
@@ -1342,8 +1675,9 @@ static int gpmi_ecc_read_oob(struct nand_chip *chip, int page)
*/
if (GPMI_IS_MX23(this)) {
/* Read the block mark into the first byte of the OOB buffer. */
- nand_read_page_op(chip, page, 0, NULL, 0);
- chip->oob_poi[0] = chip->legacy.read_byte(chip);
+ ret = nand_read_page_op(chip, page, 0, chip->oob_poi, 1);
+ if (ret)
+ return ret;
}
return 0;
@@ -1392,9 +1726,12 @@ static int gpmi_ecc_read_page_raw(struct nand_chip *chip, uint8_t *buf,
size_t oob_byte_off;
uint8_t *oob = chip->oob_poi;
int step;
+ int ret;
- nand_read_page_op(chip, page, 0, tmp_buf,
- mtd->writesize + mtd->oobsize);
+ ret = nand_read_page_op(chip, page, 0, tmp_buf,
+ mtd->writesize + mtd->oobsize);
+ if (ret)
+ return ret;
/*
* If required, swap the bad block marker and the data stored in the
@@ -1606,13 +1943,12 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
unsigned int stride;
unsigned int page;
u8 *buffer = nand_get_data_buf(chip);
- int saved_chip_number;
int found_an_ncb_fingerprint = false;
+ int ret;
/* Compute the number of strides in a search area. */
search_area_size_in_strides = 1 << rom_geo->search_area_stride_exponent;
- saved_chip_number = this->current_chip;
nand_select_target(chip, 0);
/*
@@ -1630,8 +1966,10 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
* Read the NCB fingerprint. The fingerprint is four bytes long
* and starts in the 12th byte of the page.
*/
- nand_read_page_op(chip, page, 12, NULL, 0);
- chip->legacy.read_buf(chip, buffer, strlen(fingerprint));
+ ret = nand_read_page_op(chip, page, 12, buffer,
+ strlen(fingerprint));
+ if (ret)
+ continue;
/* Look for the fingerprint. */
if (!memcmp(buffer, fingerprint, strlen(fingerprint))) {
@@ -1641,10 +1979,7 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
}
- if (saved_chip_number >= 0)
- nand_select_target(chip, saved_chip_number);
- else
- nand_deselect_target(chip);
+ nand_deselect_target(chip);
if (found_an_ncb_fingerprint)
dev_dbg(dev, "\tFound a fingerprint\n");
@@ -1668,7 +2003,6 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
unsigned int stride;
unsigned int page;
u8 *buffer = nand_get_data_buf(chip);
- int saved_chip_number;
int status;
/* Compute the search area geometry. */
@@ -1685,8 +2019,6 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
dev_dbg(dev, "\tin Strides: %u\n", search_area_size_in_strides);
dev_dbg(dev, "\tin Pages : %u\n", search_area_size_in_pages);
- /* Select chip 0. */
- saved_chip_number = this->current_chip;
nand_select_target(chip, 0);
/* Loop over blocks in the first search area, erasing them. */
@@ -1718,11 +2050,7 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
dev_err(dev, "[%s] Write failed.\n", __func__);
}
- /* Deselect chip 0. */
- if (saved_chip_number >= 0)
- nand_select_target(chip, saved_chip_number);
- else
- nand_deselect_target(chip);
+ nand_deselect_target(chip);
return 0;
}
@@ -1773,10 +2101,13 @@ static int mx23_boot_init(struct gpmi_nand_data *this)
/* Send the command to read the conventional block mark. */
nand_select_target(chip, chipnr);
- nand_read_page_op(chip, page, mtd->writesize, NULL, 0);
- block_mark = chip->legacy.read_byte(chip);
+ ret = nand_read_page_op(chip, page, mtd->writesize, &block_mark,
+ 1);
nand_deselect_target(chip);
+ if (ret)
+ continue;
+
/*
* Check if the block is marked bad. If so, we need to mark it
* again, but this time the result will be a mark in the
@@ -1890,9 +2221,330 @@ static int gpmi_nand_attach_chip(struct nand_chip *chip)
return 0;
}
+static struct gpmi_transfer *get_next_transfer(struct gpmi_nand_data *this)
+{
+ struct gpmi_transfer *transfer = &this->transfers[this->ntransfers];
+
+ this->ntransfers++;
+
+ if (this->ntransfers == GPMI_MAX_TRANSFERS)
+ return NULL;
+
+ return transfer;
+}
+
+static struct dma_async_tx_descriptor *gpmi_chain_command(
+ struct gpmi_nand_data *this, u8 cmd, const u8 *addr, int naddr)
+{
+ struct dma_chan *channel = get_dma_chan(this);
+ struct dma_async_tx_descriptor *desc;
+ struct gpmi_transfer *transfer;
+ int chip = this->nand.cur_cs;
+ u32 pio[3];
+
+ /* [1] send out the PIO words */
+ pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__WRITE)
+ | BM_GPMI_CTRL0_WORD_LENGTH
+ | BF_GPMI_CTRL0_CS(chip, this)
+ | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
+ | BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_CLE)
+ | BM_GPMI_CTRL0_ADDRESS_INCREMENT
+ | BF_GPMI_CTRL0_XFER_COUNT(naddr + 1);
+ pio[1] = 0;
+ pio[2] = 0;
+ desc = mxs_dmaengine_prep_pio(channel, pio, ARRAY_SIZE(pio),
+ DMA_TRANS_NONE, 0);
+ if (!desc)
+ return NULL;
+
+ transfer = get_next_transfer(this);
+ if (!transfer)
+ return NULL;
+
+ transfer->cmdbuf[0] = cmd;
+ if (naddr)
+ memcpy(&transfer->cmdbuf[1], addr, naddr);
+
+ sg_init_one(&transfer->sgl, transfer->cmdbuf, naddr + 1);
+ dma_map_sg(this->dev, &transfer->sgl, 1, DMA_TO_DEVICE);
+
+ transfer->direction = DMA_TO_DEVICE;
+
+ desc = dmaengine_prep_slave_sg(channel, &transfer->sgl, 1, DMA_MEM_TO_DEV,
+ MXS_DMA_CTRL_WAIT4END);
+ return desc;
+}
+
+static struct dma_async_tx_descriptor *gpmi_chain_wait_ready(
+ struct gpmi_nand_data *this)
+{
+ struct dma_chan *channel = get_dma_chan(this);
+ u32 pio[2];
+
+ pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY)
+ | BM_GPMI_CTRL0_WORD_LENGTH
+ | BF_GPMI_CTRL0_CS(this->nand.cur_cs, this)
+ | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
+ | BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA)
+ | BF_GPMI_CTRL0_XFER_COUNT(0);
+ pio[1] = 0;
+
+ return mxs_dmaengine_prep_pio(channel, pio, 2, DMA_TRANS_NONE,
+ MXS_DMA_CTRL_WAIT4END | MXS_DMA_CTRL_WAIT4RDY);
+}
+
+static struct dma_async_tx_descriptor *gpmi_chain_data_read(
+ struct gpmi_nand_data *this, void *buf, int raw_len, bool *direct)
+{
+ struct dma_async_tx_descriptor *desc;
+ struct dma_chan *channel = get_dma_chan(this);
+ struct gpmi_transfer *transfer;
+ u32 pio[6] = {};
+
+ transfer = get_next_transfer(this);
+ if (!transfer)
+ return NULL;
+
+ transfer->direction = DMA_FROM_DEVICE;
+
+ *direct = prepare_data_dma(this, buf, raw_len, &transfer->sgl,
+ DMA_FROM_DEVICE);
+
+ pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__READ)
+ | BM_GPMI_CTRL0_WORD_LENGTH
+ | BF_GPMI_CTRL0_CS(this->nand.cur_cs, this)
+ | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
+ | BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA)
+ | BF_GPMI_CTRL0_XFER_COUNT(raw_len);
+
+ if (this->bch) {
+ pio[2] = BM_GPMI_ECCCTRL_ENABLE_ECC
+ | BF_GPMI_ECCCTRL_ECC_CMD(BV_GPMI_ECCCTRL_ECC_CMD__BCH_DECODE)
+ | BF_GPMI_ECCCTRL_BUFFER_MASK(BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE
+ | BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY);
+ pio[3] = raw_len;
+ pio[4] = transfer->sgl.dma_address;
+ pio[5] = this->auxiliary_phys;
+ }
+
+ desc = mxs_dmaengine_prep_pio(channel, pio, ARRAY_SIZE(pio),
+ DMA_TRANS_NONE, 0);
+ if (!desc)
+ return NULL;
+
+ if (!this->bch)
+ desc = dmaengine_prep_slave_sg(channel, &transfer->sgl, 1,
+ DMA_DEV_TO_MEM,
+ MXS_DMA_CTRL_WAIT4END);
+
+ return desc;
+}
+
+static struct dma_async_tx_descriptor *gpmi_chain_data_write(
+ struct gpmi_nand_data *this, const void *buf, int raw_len)
+{
+ struct dma_chan *channel = get_dma_chan(this);
+ struct dma_async_tx_descriptor *desc;
+ struct gpmi_transfer *transfer;
+ u32 pio[6] = {};
+
+ transfer = get_next_transfer(this);
+ if (!transfer)
+ return NULL;
+
+ transfer->direction = DMA_TO_DEVICE;
+
+ prepare_data_dma(this, buf, raw_len, &transfer->sgl, DMA_TO_DEVICE);
+
+ pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__WRITE)
+ | BM_GPMI_CTRL0_WORD_LENGTH
+ | BF_GPMI_CTRL0_CS(this->nand.cur_cs, this)
+ | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
+ | BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA)
+ | BF_GPMI_CTRL0_XFER_COUNT(raw_len);
+
+ if (this->bch) {
+ pio[2] = BM_GPMI_ECCCTRL_ENABLE_ECC
+ | BF_GPMI_ECCCTRL_ECC_CMD(BV_GPMI_ECCCTRL_ECC_CMD__BCH_ENCODE)
+ | BF_GPMI_ECCCTRL_BUFFER_MASK(BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE |
+ BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY);
+ pio[3] = raw_len;
+ pio[4] = transfer->sgl.dma_address;
+ pio[5] = this->auxiliary_phys;
+ }
+
+ desc = mxs_dmaengine_prep_pio(channel, pio, ARRAY_SIZE(pio),
+ DMA_TRANS_NONE,
+ (this->bch ? MXS_DMA_CTRL_WAIT4END : 0));
+ if (!desc)
+ return NULL;
+
+ if (!this->bch)
+ desc = dmaengine_prep_slave_sg(channel, &transfer->sgl, 1,
+ DMA_MEM_TO_DEV,
+ MXS_DMA_CTRL_WAIT4END);
+
+ return desc;
+}
+
+static int gpmi_nfc_exec_op(struct nand_chip *chip,
+ const struct nand_operation *op,
+ bool check_only)
+{
+ const struct nand_op_instr *instr;
+ struct gpmi_nand_data *this = nand_get_controller_data(chip);
+ struct dma_async_tx_descriptor *desc = NULL;
+ int i, ret, buf_len = 0, nbufs = 0;
+ u8 cmd = 0;
+ void *buf_read = NULL;
+ const void *buf_write = NULL;
+ bool direct = false;
+ struct completion *completion;
+ unsigned long to;
+
+ this->ntransfers = 0;
+ for (i = 0; i < GPMI_MAX_TRANSFERS; i++)
+ this->transfers[i].direction = DMA_NONE;
+
+ ret = pm_runtime_get_sync(this->dev);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * This driver currently supports only one NAND chip. Plus, dies share
+ * the same configuration. So once timings have been applied on the
+ * controller side, they will not change anymore. When the time will
+ * come, the check on must_apply_timings will have to be dropped.
+ */
+ if (this->hw.must_apply_timings) {
+ this->hw.must_apply_timings = false;
+ gpmi_nfc_apply_timings(this);
+ }
+
+ dev_dbg(this->dev, "%s: %d instructions\n", __func__, op->ninstrs);
+
+ for (i = 0; i < op->ninstrs; i++) {
+ instr = &op->instrs[i];
+
+ nand_op_trace(" ", instr);
+
+ switch (instr->type) {
+ case NAND_OP_WAITRDY_INSTR:
+ desc = gpmi_chain_wait_ready(this);
+ break;
+ case NAND_OP_CMD_INSTR:
+ cmd = instr->ctx.cmd.opcode;
+
+ /*
+ * When this command has an address cycle chain it
+ * together with the address cycle
+ */
+ if (i + 1 != op->ninstrs &&
+ op->instrs[i + 1].type == NAND_OP_ADDR_INSTR)
+ continue;
+
+ desc = gpmi_chain_command(this, cmd, NULL, 0);
+
+ break;
+ case NAND_OP_ADDR_INSTR:
+ desc = gpmi_chain_command(this, cmd, instr->ctx.addr.addrs,
+ instr->ctx.addr.naddrs);
+ break;
+ case NAND_OP_DATA_OUT_INSTR:
+ buf_write = instr->ctx.data.buf.out;
+ buf_len = instr->ctx.data.len;
+ nbufs++;
+
+ desc = gpmi_chain_data_write(this, buf_write, buf_len);
+
+ break;
+ case NAND_OP_DATA_IN_INSTR:
+ if (!instr->ctx.data.len)
+ break;
+ buf_read = instr->ctx.data.buf.in;
+ buf_len = instr->ctx.data.len;
+ nbufs++;
+
+ desc = gpmi_chain_data_read(this, buf_read, buf_len,
+ &direct);
+ break;
+ }
+
+ if (!desc) {
+ ret = -ENXIO;
+ goto unmap;
+ }
+ }
+
+ dev_dbg(this->dev, "%s setup done\n", __func__);
+
+ if (nbufs > 1) {
+ dev_err(this->dev, "Multiple data instructions not supported\n");
+ ret = -EINVAL;
+ goto unmap;
+ }
+
+ if (this->bch) {
+ writel(this->bch_flashlayout0,
+ this->resources.bch_regs + HW_BCH_FLASH0LAYOUT0);
+ writel(this->bch_flashlayout1,
+ this->resources.bch_regs + HW_BCH_FLASH0LAYOUT1);
+ }
+
+ if (this->bch && buf_read) {
+ writel(BM_BCH_CTRL_COMPLETE_IRQ_EN,
+ this->resources.bch_regs + HW_BCH_CTRL_SET);
+ completion = &this->bch_done;
+ } else {
+ desc->callback = dma_irq_callback;
+ desc->callback_param = this;
+ completion = &this->dma_done;
+ }
+
+ init_completion(completion);
+
+ dmaengine_submit(desc);
+ dma_async_issue_pending(get_dma_chan(this));
+
+ to = wait_for_completion_timeout(completion, msecs_to_jiffies(1000));
+ if (!to) {
+ dev_err(this->dev, "DMA timeout, last DMA\n");
+ gpmi_dump_info(this);
+ ret = -ETIMEDOUT;
+ goto unmap;
+ }
+
+ writel(BM_BCH_CTRL_COMPLETE_IRQ_EN,
+ this->resources.bch_regs + HW_BCH_CTRL_CLR);
+ gpmi_clear_bch(this);
+
+ ret = 0;
+
+unmap:
+ for (i = 0; i < this->ntransfers; i++) {
+ struct gpmi_transfer *transfer = &this->transfers[i];
+
+ if (transfer->direction != DMA_NONE)
+ dma_unmap_sg(this->dev, &transfer->sgl, 1,
+ transfer->direction);
+ }
+
+ if (!ret && buf_read && !direct)
+ memcpy(buf_read, this->data_buffer_dma,
+ gpmi_raw_len_to_len(this, buf_len));
+
+ this->bch = false;
+
+ pm_runtime_mark_last_busy(this->dev);
+ pm_runtime_put_autosuspend(this->dev);
+
+ return ret;
+}
+
static const struct nand_controller_ops gpmi_nand_controller_ops = {
.attach_chip = gpmi_nand_attach_chip,
.setup_data_interface = gpmi_setup_data_interface,
+ .exec_op = gpmi_nfc_exec_op,
};
static int gpmi_nand_init(struct gpmi_nand_data *this)
@@ -1901,9 +2553,6 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
- /* init current chip */
- this->current_chip = -1;
-
/* init the MTD data structures */
mtd->name = "gpmi-nand";
mtd->dev.parent = this->dev;
@@ -1911,14 +2560,8 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
/* init the nand_chip{}, we don't support a 16-bit NAND Flash bus. */
nand_set_controller_data(chip, this);
nand_set_flash_node(chip, this->pdev->dev.of_node);
- chip->legacy.select_chip = gpmi_select_chip;
- chip->legacy.cmd_ctrl = gpmi_cmd_ctrl;
- chip->legacy.dev_ready = gpmi_dev_ready;
- chip->legacy.read_byte = gpmi_read_byte;
- chip->legacy.read_buf = gpmi_read_buf;
- chip->legacy.write_buf = gpmi_write_buf;
- chip->badblock_pattern = &gpmi_bbt_descr;
chip->legacy.block_markbad = gpmi_block_markbad;
+ chip->badblock_pattern = &gpmi_bbt_descr;
chip->options |= NAND_NO_SUBPAGE_WRITE;
/* Set up swap_block_mark, must be set before the gpmi_set_geometry() */
@@ -1934,7 +2577,10 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
if (ret)
goto err_out;
- chip->legacy.dummy_controller.ops = &gpmi_nand_controller_ops;
+ nand_controller_init(&this->base);
+ this->base.ops = &gpmi_nand_controller_ops;
+ chip->controller = &this->base;
+
ret = nand_scan(chip, GPMI_IS_MX6(this) ? 2 : 1);
if (ret)
goto err_out;
@@ -2004,6 +2650,16 @@ static int gpmi_nand_probe(struct platform_device *pdev)
if (ret)
goto exit_acquire_resources;
+ ret = __gpmi_enable_clk(this, true);
+ if (ret)
+ goto exit_nfc_init;
+
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 500);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
+
ret = gpmi_init(this);
if (ret)
goto exit_nfc_init;
@@ -2012,11 +2668,16 @@ static int gpmi_nand_probe(struct platform_device *pdev)
if (ret)
goto exit_nfc_init;
+ pm_runtime_mark_last_busy(&pdev->dev);
+ pm_runtime_put_autosuspend(&pdev->dev);
+
dev_info(this->dev, "driver registered.\n");
return 0;
exit_nfc_init:
+ pm_runtime_put(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
release_resources(this);
exit_acquire_resources:
@@ -2027,6 +2688,9 @@ static int gpmi_nand_remove(struct platform_device *pdev)
{
struct gpmi_nand_data *this = platform_get_drvdata(pdev);
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
nand_release(&this->nand);
gpmi_free_dma_buffer(this);
release_resources(this);
@@ -2069,8 +2733,23 @@ static int gpmi_pm_resume(struct device *dev)
}
#endif /* CONFIG_PM_SLEEP */
+static int __maybe_unused gpmi_runtime_suspend(struct device *dev)
+{
+ struct gpmi_nand_data *this = dev_get_drvdata(dev);
+
+ return __gpmi_enable_clk(this, false);
+}
+
+static int __maybe_unused gpmi_runtime_resume(struct device *dev)
+{
+ struct gpmi_nand_data *this = dev_get_drvdata(dev);
+
+ return __gpmi_enable_clk(this, true);
+}
+
static const struct dev_pm_ops gpmi_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(gpmi_pm_suspend, gpmi_pm_resume)
+ SET_RUNTIME_PM_OPS(gpmi_runtime_suspend, gpmi_runtime_resume, NULL)
};
static struct platform_driver gpmi_nand_driver = {
diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h
index a804a4a5bd46..fdc5ed7de083 100644
--- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h
+++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h
@@ -103,6 +103,14 @@ struct gpmi_nfc_hardware_timing {
u32 ctrl1n;
};
+#define GPMI_MAX_TRANSFERS 8
+
+struct gpmi_transfer {
+ u8 cmdbuf[8];
+ struct scatterlist sgl;
+ enum dma_data_direction direction;
+};
+
struct gpmi_nand_data {
/* Devdata */
const struct gpmi_devdata *devdata;
@@ -126,25 +134,18 @@ struct gpmi_nand_data {
struct boot_rom_geometry rom_geometry;
/* MTD / NAND */
+ struct nand_controller base;
struct nand_chip nand;
- /* General-use Variables */
- int current_chip;
- unsigned int command_length;
+ struct gpmi_transfer transfers[GPMI_MAX_TRANSFERS];
+ int ntransfers;
- struct scatterlist cmd_sgl;
- char *cmd_buffer;
+ bool bch;
+ uint32_t bch_flashlayout0;
+ uint32_t bch_flashlayout1;
- struct scatterlist data_sgl;
char *data_buffer_dma;
- void *page_buffer_virt;
- dma_addr_t page_buffer_phys;
- unsigned int page_buffer_size;
-
- void *payload_virt;
- dma_addr_t payload_phys;
-
void *auxiliary_virt;
dma_addr_t auxiliary_phys;
@@ -154,45 +155,8 @@ struct gpmi_nand_data {
#define DMA_CHANS 8
struct dma_chan *dma_chans[DMA_CHANS];
struct completion dma_done;
-
- /* private */
- void *private;
};
-/* Common Services */
-int common_nfc_set_geometry(struct gpmi_nand_data *);
-struct dma_chan *get_dma_chan(struct gpmi_nand_data *);
-bool prepare_data_dma(struct gpmi_nand_data *, const void *buf, int len,
- enum dma_data_direction dr);
-int start_dma_without_bch_irq(struct gpmi_nand_data *,
- struct dma_async_tx_descriptor *);
-int start_dma_with_bch_irq(struct gpmi_nand_data *,
- struct dma_async_tx_descriptor *);
-
-/* GPMI-NAND helper function library */
-int gpmi_init(struct gpmi_nand_data *);
-void gpmi_clear_bch(struct gpmi_nand_data *);
-void gpmi_dump_info(struct gpmi_nand_data *);
-int bch_set_geometry(struct gpmi_nand_data *);
-int gpmi_is_ready(struct gpmi_nand_data *, unsigned chip);
-int gpmi_send_command(struct gpmi_nand_data *);
-int gpmi_enable_clk(struct gpmi_nand_data *this);
-int gpmi_disable_clk(struct gpmi_nand_data *this);
-int gpmi_setup_data_interface(struct nand_chip *chip, int chipnr,
- const struct nand_data_interface *conf);
-void gpmi_nfc_apply_timings(struct gpmi_nand_data *this);
-int gpmi_read_data(struct gpmi_nand_data *, void *buf, int len);
-int gpmi_send_data(struct gpmi_nand_data *, const void *buf, int len);
-
-int gpmi_send_page(struct gpmi_nand_data *,
- dma_addr_t payload, dma_addr_t auxiliary);
-int gpmi_read_page(struct gpmi_nand_data *,
- dma_addr_t payload, dma_addr_t auxiliary);
-
-void gpmi_copy_bits(u8 *dst, size_t dst_bit_off,
- const u8 *src, size_t src_bit_off,
- size_t nbits);
-
/* BCH : Status Block Completion Codes */
#define STATUS_GOOD 0x00
#define STATUS_ERASED 0xff
diff --git a/drivers/mtd/nand/raw/ingenic/Kconfig b/drivers/mtd/nand/raw/ingenic/Kconfig
index 19a96ce515c1..66b7cffdb0c2 100644
--- a/drivers/mtd/nand/raw/ingenic/Kconfig
+++ b/drivers/mtd/nand/raw/ingenic/Kconfig
@@ -16,7 +16,7 @@ config MTD_NAND_JZ4780
if MTD_NAND_JZ4780
config MTD_NAND_INGENIC_ECC
- tristate
+ bool
config MTD_NAND_JZ4740_ECC
tristate "Hardware BCH support for JZ4740 SoC"
diff --git a/drivers/mtd/nand/raw/ingenic/Makefile b/drivers/mtd/nand/raw/ingenic/Makefile
index 1ac4f455baea..b63d36889263 100644
--- a/drivers/mtd/nand/raw/ingenic/Makefile
+++ b/drivers/mtd/nand/raw/ingenic/Makefile
@@ -2,7 +2,9 @@
obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o
obj-$(CONFIG_MTD_NAND_JZ4780) += ingenic_nand.o
-obj-$(CONFIG_MTD_NAND_INGENIC_ECC) += ingenic_ecc.o
+ingenic_nand-y += ingenic_nand_drv.o
+ingenic_nand-$(CONFIG_MTD_NAND_INGENIC_ECC) += ingenic_ecc.o
+
obj-$(CONFIG_MTD_NAND_JZ4740_ECC) += jz4740_ecc.o
obj-$(CONFIG_MTD_NAND_JZ4725B_BCH) += jz4725b_bch.o
obj-$(CONFIG_MTD_NAND_JZ4780_BCH) += jz4780_bch.o
diff --git a/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c b/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c
index d3e085c5685a..c954189606f6 100644
--- a/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c
+++ b/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c
@@ -30,7 +30,6 @@ int ingenic_ecc_calculate(struct ingenic_ecc *ecc,
{
return ecc->ops->calculate(ecc, params, buf, ecc_code);
}
-EXPORT_SYMBOL(ingenic_ecc_calculate);
/**
* ingenic_ecc_correct() - detect and correct bit errors
@@ -51,7 +50,6 @@ int ingenic_ecc_correct(struct ingenic_ecc *ecc,
{
return ecc->ops->correct(ecc, params, buf, ecc_code);
}
-EXPORT_SYMBOL(ingenic_ecc_correct);
/**
* ingenic_ecc_get() - get the ECC controller device
@@ -111,7 +109,6 @@ struct ingenic_ecc *of_ingenic_ecc_get(struct device_node *of_node)
}
return ecc;
}
-EXPORT_SYMBOL(of_ingenic_ecc_get);
/**
* ingenic_ecc_release() - release the ECC controller device
@@ -122,7 +119,6 @@ void ingenic_ecc_release(struct ingenic_ecc *ecc)
clk_disable_unprepare(ecc->clk);
put_device(ecc->dev);
}
-EXPORT_SYMBOL(ingenic_ecc_release);
int ingenic_ecc_probe(struct platform_device *pdev)
{
@@ -159,8 +155,3 @@ int ingenic_ecc_probe(struct platform_device *pdev)
return 0;
}
EXPORT_SYMBOL(ingenic_ecc_probe);
-
-MODULE_AUTHOR("Alex Smith <alex@alex-smith.me.uk>");
-MODULE_AUTHOR("Harvey Hunt <harveyhuntnexus@gmail.com>");
-MODULE_DESCRIPTION("Ingenic ECC common driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/nand/raw/ingenic/ingenic_nand.c b/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c
index d7b7c0f13909..d7b7c0f13909 100644
--- a/drivers/mtd/nand/raw/ingenic/ingenic_nand.c
+++ b/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c
diff --git a/drivers/mtd/nand/raw/mtk_ecc.c b/drivers/mtd/nand/raw/mtk_ecc.c
index 0f90e060dae8..74595b644b7c 100644
--- a/drivers/mtd/nand/raw/mtk_ecc.c
+++ b/drivers/mtd/nand/raw/mtk_ecc.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-License-Identifier: GPL-2.0 OR MIT
/*
* MTK ECC controller driver.
* Copyright (C) 2016 MediaTek Inc.
@@ -596,4 +596,4 @@ module_platform_driver(mtk_ecc_driver);
MODULE_AUTHOR("Xiaolei Li <xiaolei.li@mediatek.com>");
MODULE_DESCRIPTION("MTK Nand ECC Driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("Dual MIT/GPL");
diff --git a/drivers/mtd/nand/raw/mtk_ecc.h b/drivers/mtd/nand/raw/mtk_ecc.h
index a455df080952..0e48c36e6ca0 100644
--- a/drivers/mtd/nand/raw/mtk_ecc.h
+++ b/drivers/mtd/nand/raw/mtk_ecc.h
@@ -1,12 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/*
* MTK SDG1 ECC controller
*
* Copyright (c) 2016 Mediatek
* Authors: Xiaolei Li <xiaolei.li@mediatek.com>
* Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
- * 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.
*/
#ifndef __DRIVERS_MTD_NAND_MTK_ECC_H__
diff --git a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c
index dceff28c9a31..373d47d1ba4c 100644
--- a/drivers/mtd/nand/raw/mtk_nand.c
+++ b/drivers/mtd/nand/raw/mtk_nand.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-License-Identifier: GPL-2.0 OR MIT
/*
* MTK NAND Flash controller driver.
* Copyright (C) 2016 MediaTek Inc.
@@ -79,6 +79,10 @@
#define NFI_FDMM(x) (0xA4 + (x) * sizeof(u32) * 2)
#define NFI_FDM_MAX_SIZE (8)
#define NFI_FDM_MIN_SIZE (1)
+#define NFI_DEBUG_CON1 (0x220)
+#define STROBE_MASK GENMASK(4, 3)
+#define STROBE_SHIFT (3)
+#define MAX_STROBE_DLY (3)
#define NFI_MASTER_STA (0x224)
#define MASTER_STA_MASK (0x0FFF)
#define NFI_EMPTY_THRESH (0x23C)
@@ -150,6 +154,8 @@ struct mtk_nfc {
struct list_head chips;
u8 *buffer;
+
+ unsigned long assigned_cs;
};
/*
@@ -500,7 +506,8 @@ static int mtk_nfc_setup_data_interface(struct nand_chip *chip, int csline,
{
struct mtk_nfc *nfc = nand_get_controller_data(chip);
const struct nand_sdr_timings *timings;
- u32 rate, tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt;
+ u32 rate, tpoecs, tprecs, tc2r, tw2r, twh, twst = 0, trlt = 0;
+ u32 temp, tsel = 0;
timings = nand_get_sdr_timings(conf);
if (IS_ERR(timings))
@@ -536,14 +543,53 @@ static int mtk_nfc_setup_data_interface(struct nand_chip *chip, int csline,
twh = DIV_ROUND_UP(twh * rate, 1000000) - 1;
twh &= 0xf;
- twst = timings->tWP_min / 1000;
+ /* Calculate real WE#/RE# hold time in nanosecond */
+ temp = (twh + 1) * 1000000 / rate;
+ /* nanosecond to picosecond */
+ temp *= 1000;
+
+ /*
+ * WE# low level time should be expaned to meet WE# pulse time
+ * and WE# cycle time at the same time.
+ */
+ if (temp < timings->tWC_min)
+ twst = timings->tWC_min - temp;
+ twst = max(timings->tWP_min, twst) / 1000;
twst = DIV_ROUND_UP(twst * rate, 1000000) - 1;
twst &= 0xf;
- trlt = max(timings->tREA_max, timings->tRP_min) / 1000;
+ /*
+ * RE# low level time should be expaned to meet RE# pulse time
+ * and RE# cycle time at the same time.
+ */
+ if (temp < timings->tRC_min)
+ trlt = timings->tRC_min - temp;
+ trlt = max(trlt, timings->tRP_min) / 1000;
trlt = DIV_ROUND_UP(trlt * rate, 1000000) - 1;
trlt &= 0xf;
+ /* Calculate RE# pulse time in nanosecond. */
+ temp = (trlt + 1) * 1000000 / rate;
+ /* nanosecond to picosecond */
+ temp *= 1000;
+ /*
+ * If RE# access time is bigger than RE# pulse time,
+ * delay sampling data timing.
+ */
+ if (temp < timings->tREA_max) {
+ tsel = timings->tREA_max / 1000;
+ tsel = DIV_ROUND_UP(tsel * rate, 1000000);
+ tsel -= (trlt + 1);
+ if (tsel > MAX_STROBE_DLY) {
+ trlt += tsel - MAX_STROBE_DLY;
+ tsel = MAX_STROBE_DLY;
+ }
+ }
+ temp = nfi_readl(nfc, NFI_DEBUG_CON1);
+ temp &= ~STROBE_MASK;
+ temp |= tsel << STROBE_SHIFT;
+ nfi_writel(nfc, temp, NFI_DEBUG_CON1);
+
/*
* ACCON: access timing control register
* -------------------------------------
@@ -835,19 +881,21 @@ static int mtk_nfc_write_oob_std(struct nand_chip *chip, int page)
return mtk_nfc_write_page_raw(chip, NULL, 1, page);
}
-static int mtk_nfc_update_ecc_stats(struct mtd_info *mtd, u8 *buf, u32 sectors)
+static int mtk_nfc_update_ecc_stats(struct mtd_info *mtd, u8 *buf, u32 start,
+ u32 sectors)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct mtk_nfc *nfc = nand_get_controller_data(chip);
struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
struct mtk_ecc_stats stats;
+ u32 reg_size = mtk_nand->fdm.reg_size;
int rc, i;
rc = nfi_readl(nfc, NFI_STA) & STA_EMP_PAGE;
if (rc) {
memset(buf, 0xff, sectors * chip->ecc.size);
for (i = 0; i < sectors; i++)
- memset(oob_ptr(chip, i), 0xff, mtk_nand->fdm.reg_size);
+ memset(oob_ptr(chip, start + i), 0xff, reg_size);
return 0;
}
@@ -867,7 +915,7 @@ static int mtk_nfc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
u32 spare = mtk_nand->spare_per_sector;
u32 column, sectors, start, end, reg;
dma_addr_t addr;
- int bitflips;
+ int bitflips = 0;
size_t len;
u8 *buf;
int rc;
@@ -934,14 +982,11 @@ static int mtk_nfc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
if (rc < 0) {
dev_err(nfc->dev, "subpage done timeout\n");
bitflips = -EIO;
- } else {
- bitflips = 0;
- if (!raw) {
- rc = mtk_ecc_wait_done(nfc->ecc, ECC_DECODE);
- bitflips = rc < 0 ? -ETIMEDOUT :
- mtk_nfc_update_ecc_stats(mtd, buf, sectors);
- mtk_nfc_read_fdm(chip, start, sectors);
- }
+ } else if (!raw) {
+ rc = mtk_ecc_wait_done(nfc->ecc, ECC_DECODE);
+ bitflips = rc < 0 ? -ETIMEDOUT :
+ mtk_nfc_update_ecc_stats(mtd, buf, start, sectors);
+ mtk_nfc_read_fdm(chip, start, sectors);
}
dma_unmap_single(nfc->dev, addr, len, DMA_FROM_DEVICE);
@@ -1315,6 +1360,17 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
dev_err(dev, "reg property failure : %d\n", ret);
return ret;
}
+
+ if (tmp >= MTK_NAND_MAX_NSELS) {
+ dev_err(dev, "invalid CS: %u\n", tmp);
+ return -EINVAL;
+ }
+
+ if (test_and_set_bit(tmp, &nfc->assigned_cs)) {
+ dev_err(dev, "CS %u already assigned\n", tmp);
+ return -EINVAL;
+ }
+
chip->sels[i] = tmp;
}
@@ -1589,6 +1645,6 @@ static struct platform_driver mtk_nfc_driver = {
module_platform_driver(mtk_nfc_driver);
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("Dual MIT/GPL");
MODULE_AUTHOR("Xiaolei Li <xiaolei.li@mediatek.com>");
MODULE_DESCRIPTION("MTK Nand Flash Controller Driver");
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 2cf71060d6f8..91f046d4d452 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Overview:
* This is the generic MTD driver for NAND flash devices. It should be
@@ -20,11 +21,6 @@
* Check, if mtd->ecctype should be set to MTD_ECC_HW
* if we have HW ECC support.
* BBT table is not serialized, has to be fixed
- *
- * 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.
- *
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -2115,35 +2111,7 @@ static void nand_op_parser_trace(const struct nand_op_parser_ctx *ctx)
if (instr == &ctx->subop.instrs[0])
prefix = " ->";
- switch (instr->type) {
- case NAND_OP_CMD_INSTR:
- pr_debug("%sCMD [0x%02x]\n", prefix,
- instr->ctx.cmd.opcode);
- break;
- case NAND_OP_ADDR_INSTR:
- pr_debug("%sADDR [%d cyc: %*ph]\n", prefix,
- instr->ctx.addr.naddrs,
- instr->ctx.addr.naddrs < 64 ?
- instr->ctx.addr.naddrs : 64,
- instr->ctx.addr.addrs);
- break;
- case NAND_OP_DATA_IN_INSTR:
- pr_debug("%sDATA_IN [%d B%s]\n", prefix,
- instr->ctx.data.len,
- instr->ctx.data.force_8bit ?
- ", force 8-bit" : "");
- break;
- case NAND_OP_DATA_OUT_INSTR:
- pr_debug("%sDATA_OUT [%d B%s]\n", prefix,
- instr->ctx.data.len,
- instr->ctx.data.force_8bit ?
- ", force 8-bit" : "");
- break;
- case NAND_OP_WAITRDY_INSTR:
- pr_debug("%sWAITRDY [max %d ms]\n", prefix,
- instr->ctx.waitrdy.timeout_ms);
- break;
- }
+ nand_op_trace(prefix, instr);
if (instr == &ctx->subop.instrs[ctx->subop.ninstrs - 1])
prefix = " ";
@@ -2156,6 +2124,22 @@ static void nand_op_parser_trace(const struct nand_op_parser_ctx *ctx)
}
#endif
+static int nand_op_parser_cmp_ctx(const struct nand_op_parser_ctx *a,
+ const struct nand_op_parser_ctx *b)
+{
+ if (a->subop.ninstrs < b->subop.ninstrs)
+ return -1;
+ else if (a->subop.ninstrs > b->subop.ninstrs)
+ return 1;
+
+ if (a->subop.last_instr_end_off < b->subop.last_instr_end_off)
+ return -1;
+ else if (a->subop.last_instr_end_off > b->subop.last_instr_end_off)
+ return 1;
+
+ return 0;
+}
+
/**
* nand_op_parser_exec_op - exec_op parser
* @chip: the NAND chip
@@ -2190,32 +2174,40 @@ int nand_op_parser_exec_op(struct nand_chip *chip,
unsigned int i;
while (ctx.subop.instrs < op->instrs + op->ninstrs) {
- int ret;
+ const struct nand_op_parser_pattern *pattern;
+ struct nand_op_parser_ctx best_ctx;
+ int ret, best_pattern = -1;
for (i = 0; i < parser->npatterns; i++) {
- const struct nand_op_parser_pattern *pattern;
+ struct nand_op_parser_ctx test_ctx = ctx;
pattern = &parser->patterns[i];
- if (!nand_op_parser_match_pat(pattern, &ctx))
+ if (!nand_op_parser_match_pat(pattern, &test_ctx))
continue;
- nand_op_parser_trace(&ctx);
-
- if (check_only)
- break;
-
- ret = pattern->exec(chip, &ctx.subop);
- if (ret)
- return ret;
+ if (best_pattern >= 0 &&
+ nand_op_parser_cmp_ctx(&test_ctx, &best_ctx) <= 0)
+ continue;
- break;
+ best_pattern = i;
+ best_ctx = test_ctx;
}
- if (i == parser->npatterns) {
+ if (best_pattern < 0) {
pr_debug("->exec_op() parser: pattern not found!\n");
return -ENOTSUPP;
}
+ ctx = best_ctx;
+ nand_op_parser_trace(&ctx);
+
+ if (!check_only) {
+ pattern = &parser->patterns[best_pattern];
+ ret = pattern->exec(chip, &ctx.subop);
+ if (ret)
+ return ret;
+ }
+
/*
* Update the context structure by pointing to the start of the
* next subop.
@@ -4666,7 +4658,6 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
memorg = nanddev_get_memorg(&chip->base);
memorg->planes_per_lun = 1;
memorg->luns_per_target = 1;
- memorg->ntargets = 1;
/*
* Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
@@ -5031,6 +5022,8 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips,
if (ret)
return ret;
+ memorg->ntargets = maxchips;
+
/* Read the flash type */
ret = nand_detect(chip, table);
if (ret) {
diff --git a/drivers/mtd/nand/raw/nand_bbt.c b/drivers/mtd/nand/raw/nand_bbt.c
index fd3c10216eda..2ef15ef94525 100644
--- a/drivers/mtd/nand/raw/nand_bbt.c
+++ b/drivers/mtd/nand/raw/nand_bbt.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Overview:
* Bad block table support for the NAND driver
*
* Copyright © 2004 Thomas Gleixner (tglx@linutronix.de)
*
- * 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.
- *
* Description:
*
* When nand_scan_bbt is called, then it tries to find the bad block table
@@ -54,7 +51,6 @@
* Following assumptions are made:
* - bbts start at a page boundary, if autolocated on a block boundary
* - the space necessary for a bbt in FLASH does not exceed a block boundary
- *
*/
#include <linux/slab.h>
diff --git a/drivers/mtd/nand/raw/nand_bch.c b/drivers/mtd/nand/raw/nand_bch.c
index 55aa4c1cd414..17527310c3a1 100644
--- a/drivers/mtd/nand/raw/nand_bch.c
+++ b/drivers/mtd/nand/raw/nand_bch.c
@@ -170,7 +170,7 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
goto fail;
}
- nbc->eccmask = kmalloc(eccbytes, GFP_KERNEL);
+ nbc->eccmask = kzalloc(eccbytes, GFP_KERNEL);
nbc->errloc = kmalloc_array(t, sizeof(*nbc->errloc), GFP_KERNEL);
if (!nbc->eccmask || !nbc->errloc)
goto fail;
@@ -182,7 +182,6 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
goto fail;
memset(erased_page, 0xff, eccsize);
- memset(nbc->eccmask, 0, eccbytes);
encode_bch(nbc->bch, erased_page, eccsize, nbc->eccmask);
kfree(erased_page);
diff --git a/drivers/mtd/nand/raw/nand_ecc.c b/drivers/mtd/nand/raw/nand_ecc.c
index 223fbd8052b3..09fdced659f5 100644
--- a/drivers/mtd/nand/raw/nand_ecc.c
+++ b/drivers/mtd/nand/raw/nand_ecc.c
@@ -11,7 +11,7 @@
* Thomas Gleixner (tglx@linutronix.de)
*
* Information on how this algorithm works and how it was developed
- * can be found in Documentation/mtd/nand_ecc.txt
+ * can be found in Documentation/driver-api/mtd/nand_ecc.rst
*/
#include <linux/types.h>
diff --git a/drivers/mtd/nand/raw/nand_ids.c b/drivers/mtd/nand/raw/nand_ids.c
index ea5a342cd91e..ba27902fc54b 100644
--- a/drivers/mtd/nand/raw/nand_ids.c
+++ b/drivers/mtd/nand/raw/nand_ids.c
@@ -1,10 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de)
- *
- * 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.
- *
*/
#include <linux/sizes.h>
diff --git a/drivers/mtd/nand/raw/nand_macronix.c b/drivers/mtd/nand/raw/nand_macronix.c
index fad57c378dd2..58511aeb0c9a 100644
--- a/drivers/mtd/nand/raw/nand_macronix.c
+++ b/drivers/mtd/nand/raw/nand_macronix.c
@@ -8,6 +8,50 @@
#include "internals.h"
+#define MACRONIX_READ_RETRY_BIT BIT(0)
+#define MACRONIX_NUM_READ_RETRY_MODES 6
+
+struct nand_onfi_vendor_macronix {
+ u8 reserved;
+ u8 reliability_func;
+} __packed;
+
+static int macronix_nand_setup_read_retry(struct nand_chip *chip, int mode)
+{
+ u8 feature[ONFI_SUBFEATURE_PARAM_LEN];
+
+ if (!chip->parameters.supports_set_get_features ||
+ !test_bit(ONFI_FEATURE_ADDR_READ_RETRY,
+ chip->parameters.set_feature_list))
+ return -ENOTSUPP;
+
+ feature[0] = mode;
+ return nand_set_features(chip, ONFI_FEATURE_ADDR_READ_RETRY, feature);
+}
+
+static void macronix_nand_onfi_init(struct nand_chip *chip)
+{
+ struct nand_parameters *p = &chip->parameters;
+ struct nand_onfi_vendor_macronix *mxic;
+
+ if (!p->onfi)
+ return;
+
+ mxic = (struct nand_onfi_vendor_macronix *)p->onfi->vendor;
+ if ((mxic->reliability_func & MACRONIX_READ_RETRY_BIT) == 0)
+ return;
+
+ chip->read_retries = MACRONIX_NUM_READ_RETRY_MODES;
+ chip->setup_read_retry = macronix_nand_setup_read_retry;
+
+ if (p->supports_set_get_features) {
+ bitmap_set(p->set_feature_list,
+ ONFI_FEATURE_ADDR_READ_RETRY, 1);
+ bitmap_set(p->get_feature_list,
+ ONFI_FEATURE_ADDR_READ_RETRY, 1);
+ }
+}
+
/*
* Macronix AC series does not support using SET/GET_FEATURES to change
* the timings unlike what is declared in the parameter page. Unflag
@@ -56,6 +100,7 @@ static int macronix_nand_init(struct nand_chip *chip)
chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE;
macronix_nand_fix_broken_get_timings(chip);
+ macronix_nand_onfi_init(chip);
return 0;
}
diff --git a/drivers/mtd/nand/raw/nand_timings.c b/drivers/mtd/nand/raw/nand_timings.c
index bea3062d71d6..f64b06a71dfa 100644
--- a/drivers/mtd/nand/raw/nand_timings.c
+++ b/drivers/mtd/nand/raw/nand_timings.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 Free Electrons
*
* Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
- *
- * 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.
- *
*/
#include <linux/kernel.h>
#include <linux/err.h>
diff --git a/drivers/mtd/nand/raw/omap2.c b/drivers/mtd/nand/raw/omap2.c
index a9a275342a41..8d881a28140e 100644
--- a/drivers/mtd/nand/raw/omap2.c
+++ b/drivers/mtd/nand/raw/omap2.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright © 2004 Texas Instruments, Jian Zhang <jzhang@ti.com>
* Copyright © 2004 Micron Technology Inc.
* Copyright © 2004 David Brownell
- *
- * 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.
*/
#include <linux/platform_device.h>
diff --git a/drivers/mtd/nand/raw/oxnas_nand.c b/drivers/mtd/nand/raw/oxnas_nand.c
index 0e52dc29141c..30c51f772de6 100644
--- a/drivers/mtd/nand/raw/oxnas_nand.c
+++ b/drivers/mtd/nand/raw/oxnas_nand.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Oxford Semiconductor OXNAS NAND driver
@@ -6,11 +7,6 @@
* Author: Vitaly Wool <vitalywool@gmail.com>
* Copyright (C) 2013 Ma Haijun <mahaijuns@gmail.com>
* Copyright (C) 2012 John Crispin <blogic@openwrt.org>
- *
- * 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.
- *
*/
#include <linux/err.h>
diff --git a/drivers/mtd/nand/raw/plat_nand.c b/drivers/mtd/nand/raw/plat_nand.c
index a994b76daa50..dc0f3074ddbf 100644
--- a/drivers/mtd/nand/raw/plat_nand.c
+++ b/drivers/mtd/nand/raw/plat_nand.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic NAND driver
*
* Author: Vitaly Wool <vitalywool@gmail.com>
- *
- * 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.
- *
*/
#include <linux/err.h>
diff --git a/drivers/mtd/nand/raw/r852.c b/drivers/mtd/nand/raw/r852.c
index 7b99831aa046..dae0d235bb17 100644
--- a/drivers/mtd/nand/raw/r852.c
+++ b/drivers/mtd/nand/raw/r852.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright © 2009 - Maxim Levitsky
* driver for Ricoh xD readers
- *
- * 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.
*/
#define DRV_NAME "r852"
diff --git a/drivers/mtd/nand/raw/r852.h b/drivers/mtd/nand/raw/r852.h
index bc67f5bf67e8..e9ce299c499d 100644
--- a/drivers/mtd/nand/raw/r852.h
+++ b/drivers/mtd/nand/raw/r852.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright © 2009 - Maxim Levitsky
* driver for Ricoh xD readers
- *
- * 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.
*/
#include <linux/pci.h>
diff --git a/drivers/mtd/nand/raw/sharpsl.c b/drivers/mtd/nand/raw/sharpsl.c
index c82f26c8b58c..b47a9eaff89b 100644
--- a/drivers/mtd/nand/raw/sharpsl.c
+++ b/drivers/mtd/nand/raw/sharpsl.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2004 Richard Purdie
* Copyright (C) 2008 Dmitry Baryshkov
*
* Based on Sharp's NAND driver sharp_sl.c
- *
- * 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.
- *
*/
#include <linux/genhd.h>
diff --git a/drivers/mtd/nand/raw/sm_common.c b/drivers/mtd/nand/raw/sm_common.c
index 409d036858dc..ba24cb36d0b9 100644
--- a/drivers/mtd/nand/raw/sm_common.c
+++ b/drivers/mtd/nand/raw/sm_common.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright © 2009 - Maxim Levitsky
* Common routines & support for xD format
- *
- * 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.
*/
#include <linux/kernel.h>
#include <linux/mtd/rawnand.h>
diff --git a/drivers/mtd/nand/raw/sm_common.h b/drivers/mtd/nand/raw/sm_common.h
index 1581671b05ae..57fc9f86f9ee 100644
--- a/drivers/mtd/nand/raw/sm_common.h
+++ b/drivers/mtd/nand/raw/sm_common.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright © 2009 - Maxim Levitsky
* Common routines & support for SmartMedia/xD format
- *
- * 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.
*/
#include <linux/bitops.h>
#include <linux/mtd/mtd.h>
diff --git a/drivers/mtd/nand/raw/socrates_nand.c b/drivers/mtd/nand/raw/socrates_nand.c
index 8be9a50c7880..20f40c0e812c 100644
--- a/drivers/mtd/nand/raw/socrates_nand.c
+++ b/drivers/mtd/nand/raw/socrates_nand.c
@@ -1,11 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright © 2008 Ilya Yanok, Emcraft Systems
- *
- *
- * 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.
- *
*/
#include <linux/slab.h>
diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c
index 999ca6a66036..e63acc077c18 100644
--- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c
+++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c
@@ -37,6 +37,8 @@
/* Max ECC buffer length */
#define FMC2_MAX_ECC_BUF_LEN (FMC2_BCHDSRS_LEN * FMC2_MAX_SG)
+#define FMC2_TIMEOUT_MS 1000
+
/* Timings */
#define FMC2_THIZ 1
#define FMC2_TIO 8000
@@ -530,7 +532,8 @@ static int stm32_fmc2_ham_calculate(struct nand_chip *chip, const u8 *data,
int ret;
ret = readl_relaxed_poll_timeout(fmc2->io_base + FMC2_SR,
- sr, sr & FMC2_SR_NWRF, 10, 1000);
+ sr, sr & FMC2_SR_NWRF, 10,
+ FMC2_TIMEOUT_MS);
if (ret) {
dev_err(fmc2->dev, "ham timeout\n");
return ret;
@@ -611,7 +614,7 @@ static int stm32_fmc2_bch_calculate(struct nand_chip *chip, const u8 *data,
/* Wait until the BCH code is ready */
if (!wait_for_completion_timeout(&fmc2->complete,
- msecs_to_jiffies(1000))) {
+ msecs_to_jiffies(FMC2_TIMEOUT_MS))) {
dev_err(fmc2->dev, "bch timeout\n");
stm32_fmc2_disable_bch_irq(fmc2);
return -ETIMEDOUT;
@@ -696,7 +699,7 @@ static int stm32_fmc2_bch_correct(struct nand_chip *chip, u8 *dat,
/* Wait until the decoding error is ready */
if (!wait_for_completion_timeout(&fmc2->complete,
- msecs_to_jiffies(1000))) {
+ msecs_to_jiffies(FMC2_TIMEOUT_MS))) {
dev_err(fmc2->dev, "bch timeout\n");
stm32_fmc2_disable_bch_irq(fmc2);
return -ETIMEDOUT;
@@ -969,7 +972,7 @@ static int stm32_fmc2_xfer(struct nand_chip *chip, const u8 *buf,
/* Wait end of sequencer transfer */
if (!wait_for_completion_timeout(&fmc2->complete,
- msecs_to_jiffies(1000))) {
+ msecs_to_jiffies(FMC2_TIMEOUT_MS))) {
dev_err(fmc2->dev, "seq timeout\n");
stm32_fmc2_disable_seq_irq(fmc2);
dmaengine_terminate_all(dma_ch);
@@ -981,7 +984,7 @@ static int stm32_fmc2_xfer(struct nand_chip *chip, const u8 *buf,
/* Wait DMA data transfer completion */
if (!wait_for_completion_timeout(&fmc2->dma_data_complete,
- msecs_to_jiffies(100))) {
+ msecs_to_jiffies(FMC2_TIMEOUT_MS))) {
dev_err(fmc2->dev, "data DMA timeout\n");
dmaengine_terminate_all(dma_ch);
ret = -ETIMEDOUT;
@@ -990,7 +993,7 @@ static int stm32_fmc2_xfer(struct nand_chip *chip, const u8 *buf,
/* Wait DMA ECC transfer completion */
if (!write_data && !raw) {
if (!wait_for_completion_timeout(&fmc2->dma_ecc_complete,
- msecs_to_jiffies(100))) {
+ msecs_to_jiffies(FMC2_TIMEOUT_MS))) {
dev_err(fmc2->dev, "ECC DMA timeout\n");
dmaengine_terminate_all(fmc2->dma_ecc_ch);
ret = -ETIMEDOUT;
@@ -1909,6 +1912,12 @@ static int stm32_fmc2_probe(struct platform_device *pdev)
}
irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ if (irq != -EPROBE_DEFER)
+ dev_err(dev, "IRQ error missing or invalid\n");
+ return irq;
+ }
+
ret = devm_request_irq(dev, irq, stm32_fmc2_irq, 0,
dev_name(dev), fmc2);
if (ret) {
diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c
index b021a5720b42..89773293c64d 100644
--- a/drivers/mtd/nand/raw/sunxi_nand.c
+++ b/drivers/mtd/nand/raw/sunxi_nand.c
@@ -51,6 +51,7 @@
#define NFC_REG_USER_DATA(x) (0x0050 + ((x) * 4))
#define NFC_REG_SPARE_AREA 0x00A0
#define NFC_REG_PAT_ID 0x00A4
+#define NFC_REG_MDMA_CNT 0x00C4
#define NFC_RAM0_BASE 0x0400
#define NFC_RAM1_BASE 0x0800
@@ -69,6 +70,7 @@
#define NFC_PAGE_SHIFT(x) (((x) < 10 ? 0 : (x) - 10) << 8)
#define NFC_SAM BIT(12)
#define NFC_RAM_METHOD BIT(14)
+#define NFC_DMA_TYPE_NORMAL BIT(15)
#define NFC_DEBUG_CTL BIT(31)
/* define bit use in NFC_ST */
@@ -205,14 +207,13 @@ static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand)
* NAND Controller capabilities structure: stores NAND controller capabilities
* for distinction between compatible strings.
*
- * @sram_through_ahb: On A23, we choose to access the internal RAM through AHB
- * instead of MBUS (less configuration). A10, A10s, A13 and
- * A20 use the MBUS but no extra configuration is needed.
+ * @extra_mbus_conf: Contrary to A10, A10s and A13, accessing internal RAM
+ * through MBUS on A23/A33 needs extra configuration.
* @reg_io_data: I/O data register
* @dma_maxburst: DMA maxburst
*/
struct sunxi_nfc_caps {
- bool sram_through_ahb;
+ bool extra_mbus_conf;
unsigned int reg_io_data;
unsigned int dma_maxburst;
};
@@ -368,28 +369,12 @@ static int sunxi_nfc_dma_op_prepare(struct sunxi_nfc *nfc, const void *buf,
goto err_unmap_buf;
}
- /*
- * On A23, we suppose the "internal RAM" (p.12 of the NFC user manual)
- * refers to the NAND controller's internal SRAM. This memory is mapped
- * and so is accessible from the AHB. It seems that it can also be
- * accessed by the MBUS. MBUS accesses are mandatory when using the
- * internal DMA instead of the external DMA engine.
- *
- * During DMA I/O operation, either we access this memory from the AHB
- * by clearing the NFC_RAM_METHOD bit, or we set the bit and use the
- * MBUS. In this case, we should also configure the MBUS DMA length
- * NFC_REG_MDMA_CNT(0xC4) to be chunksize * nchunks. NAND I/O over MBUS
- * are also limited to 32kiB pages.
- */
- if (nfc->caps->sram_through_ahb)
- writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_RAM_METHOD,
- nfc->regs + NFC_REG_CTL);
- else
- writel(readl(nfc->regs + NFC_REG_CTL) | NFC_RAM_METHOD,
- nfc->regs + NFC_REG_CTL);
-
+ writel(readl(nfc->regs + NFC_REG_CTL) | NFC_RAM_METHOD,
+ nfc->regs + NFC_REG_CTL);
writel(nchunks, nfc->regs + NFC_REG_SECTOR_NUM);
writel(chunksize, nfc->regs + NFC_REG_CNT);
+ if (nfc->caps->extra_mbus_conf)
+ writel(chunksize * nchunks, nfc->regs + NFC_REG_MDMA_CNT);
dmat = dmaengine_submit(dmad);
@@ -2151,6 +2136,11 @@ static int sunxi_nfc_probe(struct platform_device *pdev)
dmac_cfg.src_maxburst = nfc->caps->dma_maxburst;
dmac_cfg.dst_maxburst = nfc->caps->dma_maxburst;
dmaengine_slave_config(nfc->dmac, &dmac_cfg);
+
+ if (nfc->caps->extra_mbus_conf)
+ writel(readl(nfc->regs + NFC_REG_CTL) |
+ NFC_DMA_TYPE_NORMAL, nfc->regs + NFC_REG_CTL);
+
} else {
dev_warn(dev, "failed to request rxtx DMA channel\n");
}
@@ -2200,7 +2190,7 @@ static const struct sunxi_nfc_caps sunxi_nfc_a10_caps = {
};
static const struct sunxi_nfc_caps sunxi_nfc_a23_caps = {
- .sram_through_ahb = true,
+ .extra_mbus_conf = true,
.reg_io_data = NFC_REG_A23_IO_DATA,
.dma_maxburst = 8,
};
diff --git a/drivers/mtd/nand/raw/tango_nand.c b/drivers/mtd/nand/raw/tango_nand.c
index cb3beda88789..b3f2cabcc7c0 100644
--- a/drivers/mtd/nand/raw/tango_nand.c
+++ b/drivers/mtd/nand/raw/tango_nand.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2016 Sigma Designs
- *
- * 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.
*/
#include <linux/io.h>
diff --git a/drivers/mtd/nand/raw/txx9ndfmc.c b/drivers/mtd/nand/raw/txx9ndfmc.c
index 97978227aa55..2642d5bb3241 100644
--- a/drivers/mtd/nand/raw/txx9ndfmc.c
+++ b/drivers/mtd/nand/raw/txx9ndfmc.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TXx9 NAND flash memory controller driver
* Based on RBTX49xx patch from CELF patch archive.
*
- * 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.
- *
* (C) Copyright TOSHIBA CORPORATION 2004-2007
* All Rights Reserved.
*/
diff --git a/drivers/mtd/nand/raw/xway_nand.c b/drivers/mtd/nand/raw/xway_nand.c
index 4cb78106af14..834f794816a9 100644
--- a/drivers/mtd/nand/raw/xway_nand.c
+++ b/drivers/mtd/nand/raw/xway_nand.c
@@ -1,7 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
- * 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.
*
* Copyright © 2012 John Crispin <john@phrozen.org>
* Copyright © 2016 Hauke Mehrtens <hauke@hauke-m.de>
diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
index 753125082640..9662b9c1d5a9 100644
--- a/drivers/mtd/nand/spi/Makefile
+++ b/drivers/mtd/nand/spi/Makefile
@@ -1,3 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
-spinand-objs := core.o gigadevice.o macronix.o micron.o toshiba.o winbond.o
+spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o
obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 4c15bb58c623..89f6beefb01c 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -511,12 +511,12 @@ static int spinand_mtd_read(struct mtd_info *mtd, loff_t from,
if (ret == -EBADMSG) {
ecc_failed = true;
mtd->ecc_stats.failed++;
- ret = 0;
} else {
mtd->ecc_stats.corrected += ret;
max_bitflips = max_t(unsigned int, max_bitflips, ret);
}
+ ret = 0;
ops->retlen += iter.req.datalen;
ops->oobretlen += iter.req.ooblen;
}
@@ -757,6 +757,7 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = {
&gigadevice_spinand_manufacturer,
&macronix_spinand_manufacturer,
&micron_spinand_manufacturer,
+ &paragon_spinand_manufacturer,
&toshiba_spinand_manufacturer,
&winbond_spinand_manufacturer,
};
@@ -845,7 +846,7 @@ spinand_select_op_variant(struct spinand_device *spinand,
*/
int spinand_match_and_init(struct spinand_device *spinand,
const struct spinand_info *table,
- unsigned int table_size, u8 devid)
+ unsigned int table_size, u16 devid)
{
struct nand_device *nand = spinand_to_nand(spinand);
unsigned int i;
diff --git a/drivers/mtd/nand/spi/gigadevice.c b/drivers/mtd/nand/spi/gigadevice.c
index e5586390026a..e99d425aa93f 100644
--- a/drivers/mtd/nand/spi/gigadevice.c
+++ b/drivers/mtd/nand/spi/gigadevice.c
@@ -9,11 +9,17 @@
#include <linux/mtd/spinand.h>
#define SPINAND_MFR_GIGADEVICE 0xC8
+
#define GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS (1 << 4)
#define GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS (3 << 4)
#define GD5FXGQ4UEXXG_REG_STATUS2 0xf0
+#define GD5FXGQ4UXFXXG_STATUS_ECC_MASK (7 << 4)
+#define GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS (0 << 4)
+#define GD5FXGQ4UXFXXG_STATUS_ECC_1_3_BITFLIPS (1 << 4)
+#define GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR (7 << 4)
+
static SPINAND_OP_VARIANTS(read_cache_variants,
SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
@@ -22,6 +28,14 @@ static SPINAND_OP_VARIANTS(read_cache_variants,
SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+static SPINAND_OP_VARIANTS(read_cache_variants_f,
+ SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_X4_OP_3A(0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_X2_OP_3A(0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_OP_3A(true, 0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_OP_3A(false, 0, 0, NULL, 0));
+
static SPINAND_OP_VARIANTS(write_cache_variants,
SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
SPINAND_PROG_LOAD(true, 0, NULL, 0));
@@ -59,6 +73,11 @@ static int gd5fxgq4xa_ooblayout_free(struct mtd_info *mtd, int section,
return 0;
}
+static const struct mtd_ooblayout_ops gd5fxgq4xa_ooblayout = {
+ .ecc = gd5fxgq4xa_ooblayout_ecc,
+ .free = gd5fxgq4xa_ooblayout_free,
+};
+
static int gd5fxgq4xa_ecc_get_status(struct spinand_device *spinand,
u8 status)
{
@@ -83,7 +102,7 @@ static int gd5fxgq4xa_ecc_get_status(struct spinand_device *spinand,
return -EINVAL;
}
-static int gd5fxgq4uexxg_ooblayout_ecc(struct mtd_info *mtd, int section,
+static int gd5fxgq4_variant2_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
if (section)
@@ -95,7 +114,7 @@ static int gd5fxgq4uexxg_ooblayout_ecc(struct mtd_info *mtd, int section,
return 0;
}
-static int gd5fxgq4uexxg_ooblayout_free(struct mtd_info *mtd, int section,
+static int gd5fxgq4_variant2_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
if (section)
@@ -108,6 +127,11 @@ static int gd5fxgq4uexxg_ooblayout_free(struct mtd_info *mtd, int section,
return 0;
}
+static const struct mtd_ooblayout_ops gd5fxgq4_variant2_ooblayout = {
+ .ecc = gd5fxgq4_variant2_ooblayout_ecc,
+ .free = gd5fxgq4_variant2_ooblayout_free,
+};
+
static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
u8 status)
{
@@ -150,15 +174,25 @@ static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
return -EINVAL;
}
-static const struct mtd_ooblayout_ops gd5fxgq4xa_ooblayout = {
- .ecc = gd5fxgq4xa_ooblayout_ecc,
- .free = gd5fxgq4xa_ooblayout_free,
-};
+static int gd5fxgq4ufxxg_ecc_get_status(struct spinand_device *spinand,
+ u8 status)
+{
+ switch (status & GD5FXGQ4UXFXXG_STATUS_ECC_MASK) {
+ case GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS:
+ return 0;
-static const struct mtd_ooblayout_ops gd5fxgq4uexxg_ooblayout = {
- .ecc = gd5fxgq4uexxg_ooblayout_ecc,
- .free = gd5fxgq4uexxg_ooblayout_free,
-};
+ case GD5FXGQ4UXFXXG_STATUS_ECC_1_3_BITFLIPS:
+ return 3;
+
+ case GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR:
+ return -EBADMSG;
+
+ default: /* (2 << 4) through (6 << 4) are 4-8 corrected errors */
+ return ((status & GD5FXGQ4UXFXXG_STATUS_ECC_MASK) >> 4) + 2;
+ }
+
+ return -EINVAL;
+}
static const struct spinand_info gigadevice_spinand_table[] = {
SPINAND_INFO("GD5F1GQ4xA", 0xF1,
@@ -180,7 +214,7 @@ static const struct spinand_info gigadevice_spinand_table[] = {
SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
gd5fxgq4xa_ecc_get_status)),
SPINAND_INFO("GD5F4GQ4xA", 0xF4,
- NAND_MEMORG(1, 2048, 64, 64, 4096, 40, 1, 1, 1),
+ NAND_MEMORG(1, 2048, 64, 64, 4096, 80, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
@@ -195,25 +229,40 @@ static const struct spinand_info gigadevice_spinand_table[] = {
&write_cache_variants,
&update_cache_variants),
0,
- SPINAND_ECCINFO(&gd5fxgq4uexxg_ooblayout,
+ SPINAND_ECCINFO(&gd5fxgq4_variant2_ooblayout,
gd5fxgq4uexxg_ecc_get_status)),
+ SPINAND_INFO("GD5F1GQ4UFxxG", 0xb148,
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
+ &write_cache_variants,
+ &update_cache_variants),
+ 0,
+ SPINAND_ECCINFO(&gd5fxgq4_variant2_ooblayout,
+ gd5fxgq4ufxxg_ecc_get_status)),
};
static int gigadevice_spinand_detect(struct spinand_device *spinand)
{
u8 *id = spinand->id.data;
+ u16 did;
int ret;
/*
- * For GD NANDs, There is an address byte needed to shift in before IDs
- * are read out, so the first byte in raw_id is dummy.
+ * Earlier GDF5-series devices (A,E) return [0][MID][DID]
+ * Later (F) devices return [MID][DID1][DID2]
*/
- if (id[1] != SPINAND_MFR_GIGADEVICE)
+
+ if (id[0] == SPINAND_MFR_GIGADEVICE)
+ did = (id[1] << 8) + id[2];
+ else if (id[0] == 0 && id[1] == SPINAND_MFR_GIGADEVICE)
+ did = id[2];
+ else
return 0;
ret = spinand_match_and_init(spinand, gigadevice_spinand_table,
ARRAY_SIZE(gigadevice_spinand_table),
- id[2]);
+ did);
if (ret)
return ret;
diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c
index 6502727049a8..21def3f8fb36 100644
--- a/drivers/mtd/nand/spi/macronix.c
+++ b/drivers/mtd/nand/spi/macronix.c
@@ -100,7 +100,7 @@ static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand,
static const struct spinand_info macronix_spinand_table[] = {
SPINAND_INFO("MX35LF1GE4AB", 0x12,
- NAND_MEMORG(1, 2048, 64, 64, 1024, 40, 1, 1, 1),
+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(4, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
@@ -109,7 +109,7 @@ static const struct spinand_info macronix_spinand_table[] = {
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
SPINAND_INFO("MX35LF2GE4AB", 0x22,
- NAND_MEMORG(1, 2048, 64, 64, 2048, 20, 2, 1, 1),
+ NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 1, 1),
NAND_ECCREQ(4, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
diff --git a/drivers/mtd/nand/spi/paragon.c b/drivers/mtd/nand/spi/paragon.c
new file mode 100644
index 000000000000..52307681cbd0
--- /dev/null
+++ b/drivers/mtd/nand/spi/paragon.c
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Jeff Kletsky
+ *
+ * Author: Jeff Kletsky <git-commits@allycomm.com>
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/mtd/spinand.h>
+
+
+#define SPINAND_MFR_PARAGON 0xa1
+
+
+#define PN26G0XA_STATUS_ECC_BITMASK (3 << 4)
+
+#define PN26G0XA_STATUS_ECC_NONE_DETECTED (0 << 4)
+#define PN26G0XA_STATUS_ECC_1_7_CORRECTED (1 << 4)
+#define PN26G0XA_STATUS_ECC_ERRORED (2 << 4)
+#define PN26G0XA_STATUS_ECC_8_CORRECTED (3 << 4)
+
+
+static SPINAND_OP_VARIANTS(read_cache_variants,
+ SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+
+static SPINAND_OP_VARIANTS(write_cache_variants,
+ SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
+ SPINAND_PROG_LOAD(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(update_cache_variants,
+ SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
+ SPINAND_PROG_LOAD(false, 0, NULL, 0));
+
+
+static int pn26g0xa_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ if (section > 3)
+ return -ERANGE;
+
+ region->offset = 6 + (15 * section); /* 4 BBM + 2 user bytes */
+ region->length = 13;
+
+ return 0;
+}
+
+static int pn26g0xa_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ if (section > 4)
+ return -ERANGE;
+
+ if (section == 4) {
+ region->offset = 64;
+ region->length = 64;
+ } else {
+ region->offset = 4 + (15 * section);
+ region->length = 2;
+ }
+
+ return 0;
+}
+
+static int pn26g0xa_ecc_get_status(struct spinand_device *spinand,
+ u8 status)
+{
+ switch (status & PN26G0XA_STATUS_ECC_BITMASK) {
+ case PN26G0XA_STATUS_ECC_NONE_DETECTED:
+ return 0;
+
+ case PN26G0XA_STATUS_ECC_1_7_CORRECTED:
+ return 7; /* Return upper limit by convention */
+
+ case PN26G0XA_STATUS_ECC_8_CORRECTED:
+ return 8;
+
+ case PN26G0XA_STATUS_ECC_ERRORED:
+ return -EBADMSG;
+
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static const struct mtd_ooblayout_ops pn26g0xa_ooblayout = {
+ .ecc = pn26g0xa_ooblayout_ecc,
+ .free = pn26g0xa_ooblayout_free,
+};
+
+
+static const struct spinand_info paragon_spinand_table[] = {
+ SPINAND_INFO("PN26G01A", 0xe1,
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 21, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ 0,
+ SPINAND_ECCINFO(&pn26g0xa_ooblayout,
+ pn26g0xa_ecc_get_status)),
+ SPINAND_INFO("PN26G02A", 0xe2,
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 41, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ 0,
+ SPINAND_ECCINFO(&pn26g0xa_ooblayout,
+ pn26g0xa_ecc_get_status)),
+};
+
+static int paragon_spinand_detect(struct spinand_device *spinand)
+{
+ u8 *id = spinand->id.data;
+ int ret;
+
+ /* Read ID returns [0][MID][DID] */
+
+ if (id[1] != SPINAND_MFR_PARAGON)
+ return 0;
+
+ ret = spinand_match_and_init(spinand, paragon_spinand_table,
+ ARRAY_SIZE(paragon_spinand_table),
+ id[2]);
+ if (ret)
+ return ret;
+
+ return 1;
+}
+
+static const struct spinand_manufacturer_ops paragon_spinand_manuf_ops = {
+ .detect = paragon_spinand_detect,
+};
+
+const struct spinand_manufacturer paragon_spinand_manufacturer = {
+ .id = SPINAND_MFR_PARAGON,
+ .name = "Paragon",
+ .ops = &paragon_spinand_manuf_ops,
+};
diff --git a/drivers/mtd/parsers/afs.c b/drivers/mtd/parsers/afs.c
index f24d768eee30..752b6cf005f7 100644
--- a/drivers/mtd/parsers/afs.c
+++ b/drivers/mtd/parsers/afs.c
@@ -371,8 +371,7 @@ static int parse_afs_partitions(struct mtd_info *mtd,
out_free_parts:
while (i >= 0) {
- if (parts[i].name)
- kfree(parts[i].name);
+ kfree(parts[i].name);
i--;
}
kfree(parts);
diff --git a/drivers/mtd/parsers/parser_trx.c b/drivers/mtd/parsers/parser_trx.c
index 4a89a68622fe..8541182134d4 100644
--- a/drivers/mtd/parsers/parser_trx.c
+++ b/drivers/mtd/parsers/parser_trx.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Parser for TRX format partitions
*
* Copyright (C) 2012 - 2017 Rafał Miłecki <rafal@milecki.pl>
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c
index e0955a98a0f4..dfc47a444b90 100644
--- a/drivers/mtd/sm_ftl.c
+++ b/drivers/mtd/sm_ftl.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright © 2009 - Maxim Levitsky
* SmartMedia/xD translation layer
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/mtd/sm_ftl.h b/drivers/mtd/sm_ftl.h
index 0a46d75cdc6a..6aed8b60de16 100644
--- a/drivers/mtd/sm_ftl.h
+++ b/drivers/mtd/sm_ftl.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright © 2009 - Maxim Levitsky
* SmartMedia/xD translation layer
@@ -5,10 +6,6 @@
* Based loosly on ssfdc.c which is
* © 2005 Eptar srl
* Author: Claudio Lanconelli <lanconelli.claudio@eptar.com>
- *
- * 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.
*/
#include <linux/mtd/blktrans.h>
diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
index 8e14248d2720..6de83277ce8b 100644
--- a/drivers/mtd/spi-nor/Kconfig
+++ b/drivers/mtd/spi-nor/Kconfig
@@ -105,11 +105,4 @@ config SPI_INTEL_SPI_PLATFORM
To compile this driver as a module, choose M here: the module
will be called intel-spi-platform.
-config SPI_STM32_QUADSPI
- tristate "STM32 Quad SPI controller"
- depends on ARCH_STM32 || COMPILE_TEST
- help
- This enables support for the STM32 Quad SPI controller.
- We only connect the NOR to this controller.
-
endif # MTD_SPI_NOR
diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile
index 189a15cca3ec..9c5ed03cdc19 100644
--- a/drivers/mtd/spi-nor/Makefile
+++ b/drivers/mtd/spi-nor/Makefile
@@ -8,4 +8,3 @@ obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o
obj-$(CONFIG_SPI_INTEL_SPI) += intel-spi.o
obj-$(CONFIG_SPI_INTEL_SPI_PCI) += intel-spi-pci.o
obj-$(CONFIG_SPI_INTEL_SPI_PLATFORM) += intel-spi-platform.o
-obj-$(CONFIG_SPI_STM32_QUADSPI) += stm32-quadspi.o
diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c
index 67ade2c81b21..67f15a1f16fd 100644
--- a/drivers/mtd/spi-nor/cadence-quadspi.c
+++ b/drivers/mtd/spi-nor/cadence-quadspi.c
@@ -23,6 +23,7 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/reset.h>
#include <linux/sched.h>
#include <linux/spi/spi.h>
#include <linux/timer.h>
@@ -1325,6 +1326,7 @@ static int cqspi_probe(struct platform_device *pdev)
struct cqspi_st *cqspi;
struct resource *res;
struct resource *res_ahb;
+ struct reset_control *rstc, *rstc_ocp;
const struct cqspi_driver_platdata *ddata;
int ret;
int irq;
@@ -1391,6 +1393,25 @@ static int cqspi_probe(struct platform_device *pdev)
goto probe_clk_failed;
}
+ /* Obtain QSPI reset control */
+ rstc = devm_reset_control_get_optional_exclusive(dev, "qspi");
+ if (IS_ERR(rstc)) {
+ dev_err(dev, "Cannot get QSPI reset.\n");
+ return PTR_ERR(rstc);
+ }
+
+ rstc_ocp = devm_reset_control_get_optional_exclusive(dev, "qspi-ocp");
+ if (IS_ERR(rstc_ocp)) {
+ dev_err(dev, "Cannot get QSPI OCP reset.\n");
+ return PTR_ERR(rstc_ocp);
+ }
+
+ reset_control_assert(rstc);
+ reset_control_deassert(rstc);
+
+ reset_control_assert(rstc_ocp);
+ reset_control_deassert(rstc_ocp);
+
cqspi->master_ref_clk_hz = clk_get_rate(cqspi->clk);
ddata = of_device_get_match_data(dev);
if (ddata && (ddata->quirks & CQSPI_NEEDS_WR_DELAY))
diff --git a/drivers/mtd/spi-nor/intel-spi-pci.c b/drivers/mtd/spi-nor/intel-spi-pci.c
index bfbfc17ed6aa..b83c4ab6cd9f 100644
--- a/drivers/mtd/spi-nor/intel-spi-pci.c
+++ b/drivers/mtd/spi-nor/intel-spi-pci.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Intel PCH/PCU SPI flash PCI driver.
*
* Copyright (C) 2016, Intel Corporation
* Author: Mika Westerberg <mika.westerberg@linux.intel.com>
- *
- * 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.
*/
#include <linux/ioport.h>
@@ -67,6 +64,7 @@ static const struct pci_device_id intel_spi_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x18e0), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&bxt_info },
+ { PCI_VDEVICE(INTEL, 0x4b24), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0xa1a4), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0xa224), (unsigned long)&bxt_info },
{ },
diff --git a/drivers/mtd/spi-nor/intel-spi-platform.c b/drivers/mtd/spi-nor/intel-spi-platform.c
index 5c943df9398f..f80f1086f928 100644
--- a/drivers/mtd/spi-nor/intel-spi-platform.c
+++ b/drivers/mtd/spi-nor/intel-spi-platform.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Intel PCH/PCU SPI flash platform driver.
*
* Copyright (C) 2016, Intel Corporation
* Author: Mika Westerberg <mika.westerberg@linux.intel.com>
- *
- * 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.
*/
#include <linux/ioport.h>
diff --git a/drivers/mtd/spi-nor/intel-spi.c b/drivers/mtd/spi-nor/intel-spi.c
index d60cbf23d9aa..1ccf23fe7e4b 100644
--- a/drivers/mtd/spi-nor/intel-spi.c
+++ b/drivers/mtd/spi-nor/intel-spi.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Intel PCH/PCU SPI flash driver.
*
* Copyright (C) 2016, Intel Corporation
* Author: Mika Westerberg <mika.westerberg@linux.intel.com>
- *
- * 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.
*/
#include <linux/err.h>
diff --git a/drivers/mtd/spi-nor/intel-spi.h b/drivers/mtd/spi-nor/intel-spi.h
index 5ab7dc250050..e2f41b8827bf 100644
--- a/drivers/mtd/spi-nor/intel-spi.h
+++ b/drivers/mtd/spi-nor/intel-spi.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Intel PCH/PCU SPI flash driver.
*
* Copyright (C) 2016, Intel Corporation
* Author: Mika Westerberg <mika.westerberg@linux.intel.com>
- *
- * 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.
*/
#ifndef INTEL_SPI_H
diff --git a/drivers/mtd/spi-nor/nxp-spifi.c b/drivers/mtd/spi-nor/nxp-spifi.c
index 0c9094ec5966..4a871587392b 100644
--- a/drivers/mtd/spi-nor/nxp-spifi.c
+++ b/drivers/mtd/spi-nor/nxp-spifi.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* SPI-NOR driver for NXP SPI Flash Interface (SPIFI)
*
@@ -5,11 +6,6 @@
*
* Based on Freescale QuadSPI driver:
* Copyright (C) 2013 Freescale Semiconductor, 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.
- *
*/
#include <linux/clk.h>
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 73172d7f512b..03cc788511d5 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -200,7 +200,7 @@ struct sfdp_header {
* register does not modify status register 2.
* - 101b: QE is bit 1 of status register 2. Status register 1 is read using
* Read Status instruction 05h. Status register2 is read using
- * instruction 35h. QE is set via Writ Status instruction 01h with
+ * instruction 35h. QE is set via Write Status instruction 01h with
* two data bytes where bit 1 of the second byte is one.
* [...]
*/
@@ -1636,6 +1636,95 @@ static int sr2_bit7_quad_enable(struct spi_nor *nor)
return 0;
}
+/**
+ * spi_nor_clear_sr_bp() - clear the Status Register Block Protection bits.
+ * @nor: pointer to a 'struct spi_nor'
+ *
+ * Read-modify-write function that clears the Block Protection bits from the
+ * Status Register without affecting other bits.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_clear_sr_bp(struct spi_nor *nor)
+{
+ int ret;
+ u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+
+ ret = read_sr(nor);
+ if (ret < 0) {
+ dev_err(nor->dev, "error while reading status register\n");
+ return ret;
+ }
+
+ write_enable(nor);
+
+ ret = write_sr(nor, ret & ~mask);
+ if (ret) {
+ dev_err(nor->dev, "write to status register failed\n");
+ return ret;
+ }
+
+ ret = spi_nor_wait_till_ready(nor);
+ if (ret)
+ dev_err(nor->dev, "timeout while writing status register\n");
+ return ret;
+}
+
+/**
+ * spi_nor_spansion_clear_sr_bp() - clear the Status Register Block Protection
+ * bits on spansion flashes.
+ * @nor: pointer to a 'struct spi_nor'
+ *
+ * Read-modify-write function that clears the Block Protection bits from the
+ * Status Register without affecting other bits. The function is tightly
+ * coupled with the spansion_quad_enable() function. Both assume that the Write
+ * Register with 16 bits, together with the Read Configuration Register (35h)
+ * instructions are supported.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_spansion_clear_sr_bp(struct spi_nor *nor)
+{
+ int ret;
+ u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+ u8 sr_cr[2] = {0};
+
+ /* Check current Quad Enable bit value. */
+ ret = read_cr(nor);
+ if (ret < 0) {
+ dev_err(nor->dev,
+ "error while reading configuration register\n");
+ return ret;
+ }
+
+ /*
+ * When the configuration register Quad Enable bit is one, only the
+ * Write Status (01h) command with two data bytes may be used.
+ */
+ if (ret & CR_QUAD_EN_SPAN) {
+ sr_cr[1] = ret;
+
+ ret = read_sr(nor);
+ if (ret < 0) {
+ dev_err(nor->dev,
+ "error while reading status register\n");
+ return ret;
+ }
+ sr_cr[0] = ret & ~mask;
+
+ ret = write_sr_cr(nor, sr_cr);
+ if (ret)
+ dev_err(nor->dev, "16-bit write register failed\n");
+ return ret;
+ }
+
+ /*
+ * If the Quad Enable bit is zero, use the Write Status (01h) command
+ * with one data byte.
+ */
+ return spi_nor_clear_sr_bp(nor);
+}
+
/* Used when the "_ext_id" is two bytes at most */
#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \
.id = { \
@@ -1687,6 +1776,28 @@ static int sr2_bit7_quad_enable(struct spi_nor *nor)
.flags = SPI_NOR_NO_FR | SPI_S3AN,
static int
+is25lp256_post_bfpt_fixups(struct spi_nor *nor,
+ const struct sfdp_parameter_header *bfpt_header,
+ const struct sfdp_bfpt *bfpt,
+ struct spi_nor_flash_parameter *params)
+{
+ /*
+ * IS25LP256 supports 4B opcodes, but the BFPT advertises a
+ * BFPT_DWORD1_ADDRESS_BYTES_3_ONLY address width.
+ * Overwrite the address width advertised by the BFPT.
+ */
+ if ((bfpt->dwords[BFPT_DWORD(1)] & BFPT_DWORD1_ADDRESS_BYTES_MASK) ==
+ BFPT_DWORD1_ADDRESS_BYTES_3_ONLY)
+ nor->addr_width = 4;
+
+ return 0;
+}
+
+static struct spi_nor_fixups is25lp256_fixups = {
+ .post_bfpt = is25lp256_post_bfpt_fixups,
+};
+
+static int
mx25l25635_post_bfpt_fixups(struct spi_nor *nor,
const struct sfdp_parameter_header *bfpt_header,
const struct sfdp_bfpt *bfpt,
@@ -1827,7 +1938,8 @@ static const struct flash_info spi_nor_ids[] = {
SECT_4K | SPI_NOR_DUAL_READ) },
{ "is25lp256", INFO(0x9d6019, 0, 64 * 1024, 512,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
- SPI_NOR_4B_OPCODES) },
+ SPI_NOR_4B_OPCODES)
+ .fixups = &is25lp256_fixups },
{ "is25wp032", INFO(0x9d7016, 0, 64 * 1024, 64,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "is25wp064", INFO(0x9d7017, 0, 64 * 1024, 128,
@@ -1880,6 +1992,9 @@ static const struct flash_info spi_nor_ids[] = {
{ "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
{ "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
{ "n25q00a", INFO(0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
+ { "mt25ql02g", INFO(0x20ba22, 0, 64 * 1024, 4096,
+ SECT_4K | USE_FSR | SPI_NOR_QUAD_READ |
+ NO_CHIP_ERASE) },
{ "mt25qu02g", INFO(0x20bb22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
/* Micron */
@@ -1996,6 +2111,11 @@ static const struct flash_info spi_nor_ids[] = {
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
},
{ "w25x32", INFO(0xef3016, 0, 64 * 1024, 64, SECT_4K) },
+ {
+ "w25q16jv-im/jm", INFO(0xef7015, 0, 64 * 1024, 32,
+ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+ SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
+ },
{ "w25q20cl", INFO(0xef4012, 0, 64 * 1024, 4, SECT_4K) },
{ "w25q20bw", INFO(0xef5012, 0, 64 * 1024, 4, SECT_4K) },
{ "w25q20ew", INFO(0xef6012, 0, 64 * 1024, 4, SECT_4K) },
@@ -2062,7 +2182,7 @@ static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN);
if (tmp < 0) {
- dev_dbg(nor->dev, "error %d reading JEDEC ID\n", tmp);
+ dev_err(nor->dev, "error %d reading JEDEC ID\n", tmp);
return ERR_PTR(tmp);
}
@@ -3660,6 +3780,8 @@ static int spi_nor_init_params(struct spi_nor *nor,
default:
/* Kept only for backward compatibility purpose. */
params->quad_enable = spansion_quad_enable;
+ if (nor->clear_sr_bp)
+ nor->clear_sr_bp = spi_nor_spansion_clear_sr_bp;
break;
}
@@ -3912,17 +4034,13 @@ static int spi_nor_init(struct spi_nor *nor)
{
int err;
- /*
- * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
- * with the software protection bits set
- */
- if (JEDEC_MFR(nor->info) == SNOR_MFR_ATMEL ||
- JEDEC_MFR(nor->info) == SNOR_MFR_INTEL ||
- JEDEC_MFR(nor->info) == SNOR_MFR_SST ||
- nor->info->flags & SPI_NOR_HAS_LOCK) {
- write_enable(nor);
- write_sr(nor, 0);
- spi_nor_wait_till_ready(nor);
+ if (nor->clear_sr_bp) {
+ err = nor->clear_sr_bp(nor);
+ if (err) {
+ dev_err(nor->dev,
+ "fail to clear block protection bits\n");
+ return err;
+ }
}
if (nor->quad_enable) {
@@ -4047,6 +4165,16 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
if (info->flags & SPI_S3AN)
nor->flags |= SNOR_F_READY_XSR_RDY;
+ /*
+ * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
+ * with the software protection bits set.
+ */
+ if (JEDEC_MFR(nor->info) == SNOR_MFR_ATMEL ||
+ JEDEC_MFR(nor->info) == SNOR_MFR_INTEL ||
+ JEDEC_MFR(nor->info) == SNOR_MFR_SST ||
+ nor->info->flags & SPI_NOR_HAS_LOCK)
+ nor->clear_sr_bp = spi_nor_clear_sr_bp;
+
/* Parse the Serial Flash Discoverable Parameters table. */
ret = spi_nor_init_params(nor, &params);
if (ret)
diff --git a/drivers/mtd/spi-nor/stm32-quadspi.c b/drivers/mtd/spi-nor/stm32-quadspi.c
deleted file mode 100644
index 13e9fc961d3b..000000000000
--- a/drivers/mtd/spi-nor/stm32-quadspi.c
+++ /dev/null
@@ -1,720 +0,0 @@
-/*
- * Driver for stm32 quadspi controller
- *
- * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
- * Author(s): Ludovic Barre author <ludovic.barre@st.com>.
- *
- * License terms: GPL V2.0.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along with
- * This program. If not, see <http://www.gnu.org/licenses/>.
- */
-#include <linux/clk.h>
-#include <linux/errno.h>
-#include <linux/io.h>
-#include <linux/iopoll.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/spi-nor.h>
-#include <linux/mutex.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/reset.h>
-#include <linux/sizes.h>
-
-#define QUADSPI_CR 0x00
-#define CR_EN BIT(0)
-#define CR_ABORT BIT(1)
-#define CR_DMAEN BIT(2)
-#define CR_TCEN BIT(3)
-#define CR_SSHIFT BIT(4)
-#define CR_DFM BIT(6)
-#define CR_FSEL BIT(7)
-#define CR_FTHRES_SHIFT 8
-#define CR_FTHRES_MASK GENMASK(12, 8)
-#define CR_FTHRES(n) (((n) << CR_FTHRES_SHIFT) & CR_FTHRES_MASK)
-#define CR_TEIE BIT(16)
-#define CR_TCIE BIT(17)
-#define CR_FTIE BIT(18)
-#define CR_SMIE BIT(19)
-#define CR_TOIE BIT(20)
-#define CR_PRESC_SHIFT 24
-#define CR_PRESC_MASK GENMASK(31, 24)
-#define CR_PRESC(n) (((n) << CR_PRESC_SHIFT) & CR_PRESC_MASK)
-
-#define QUADSPI_DCR 0x04
-#define DCR_CSHT_SHIFT 8
-#define DCR_CSHT_MASK GENMASK(10, 8)
-#define DCR_CSHT(n) (((n) << DCR_CSHT_SHIFT) & DCR_CSHT_MASK)
-#define DCR_FSIZE_SHIFT 16
-#define DCR_FSIZE_MASK GENMASK(20, 16)
-#define DCR_FSIZE(n) (((n) << DCR_FSIZE_SHIFT) & DCR_FSIZE_MASK)
-
-#define QUADSPI_SR 0x08
-#define SR_TEF BIT(0)
-#define SR_TCF BIT(1)
-#define SR_FTF BIT(2)
-#define SR_SMF BIT(3)
-#define SR_TOF BIT(4)
-#define SR_BUSY BIT(5)
-#define SR_FLEVEL_SHIFT 8
-#define SR_FLEVEL_MASK GENMASK(13, 8)
-
-#define QUADSPI_FCR 0x0c
-#define FCR_CTCF BIT(1)
-
-#define QUADSPI_DLR 0x10
-
-#define QUADSPI_CCR 0x14
-#define CCR_INST_SHIFT 0
-#define CCR_INST_MASK GENMASK(7, 0)
-#define CCR_INST(n) (((n) << CCR_INST_SHIFT) & CCR_INST_MASK)
-#define CCR_IMODE_NONE (0U << 8)
-#define CCR_IMODE_1 (1U << 8)
-#define CCR_IMODE_2 (2U << 8)
-#define CCR_IMODE_4 (3U << 8)
-#define CCR_ADMODE_NONE (0U << 10)
-#define CCR_ADMODE_1 (1U << 10)
-#define CCR_ADMODE_2 (2U << 10)
-#define CCR_ADMODE_4 (3U << 10)
-#define CCR_ADSIZE_SHIFT 12
-#define CCR_ADSIZE_MASK GENMASK(13, 12)
-#define CCR_ADSIZE(n) (((n) << CCR_ADSIZE_SHIFT) & CCR_ADSIZE_MASK)
-#define CCR_ABMODE_NONE (0U << 14)
-#define CCR_ABMODE_1 (1U << 14)
-#define CCR_ABMODE_2 (2U << 14)
-#define CCR_ABMODE_4 (3U << 14)
-#define CCR_ABSIZE_8 (0U << 16)
-#define CCR_ABSIZE_16 (1U << 16)
-#define CCR_ABSIZE_24 (2U << 16)
-#define CCR_ABSIZE_32 (3U << 16)
-#define CCR_DCYC_SHIFT 18
-#define CCR_DCYC_MASK GENMASK(22, 18)
-#define CCR_DCYC(n) (((n) << CCR_DCYC_SHIFT) & CCR_DCYC_MASK)
-#define CCR_DMODE_NONE (0U << 24)
-#define CCR_DMODE_1 (1U << 24)
-#define CCR_DMODE_2 (2U << 24)
-#define CCR_DMODE_4 (3U << 24)
-#define CCR_FMODE_INDW (0U << 26)
-#define CCR_FMODE_INDR (1U << 26)
-#define CCR_FMODE_APM (2U << 26)
-#define CCR_FMODE_MM (3U << 26)
-
-#define QUADSPI_AR 0x18
-#define QUADSPI_ABR 0x1c
-#define QUADSPI_DR 0x20
-#define QUADSPI_PSMKR 0x24
-#define QUADSPI_PSMAR 0x28
-#define QUADSPI_PIR 0x2c
-#define QUADSPI_LPTR 0x30
-#define LPTR_DFT_TIMEOUT 0x10
-
-#define FSIZE_VAL(size) (__fls(size) - 1)
-
-#define STM32_MAX_MMAP_SZ SZ_256M
-#define STM32_MAX_NORCHIP 2
-
-#define STM32_QSPI_FIFO_SZ 32
-#define STM32_QSPI_FIFO_TIMEOUT_US 30000
-#define STM32_QSPI_BUSY_TIMEOUT_US 100000
-
-struct stm32_qspi_flash {
- struct spi_nor nor;
- struct stm32_qspi *qspi;
- u32 cs;
- u32 fsize;
- u32 presc;
- u32 read_mode;
- bool registered;
- u32 prefetch_limit;
-};
-
-struct stm32_qspi {
- struct device *dev;
- void __iomem *io_base;
- void __iomem *mm_base;
- resource_size_t mm_size;
- u32 nor_num;
- struct clk *clk;
- u32 clk_rate;
- struct stm32_qspi_flash flash[STM32_MAX_NORCHIP];
- struct completion cmd_completion;
-
- /*
- * to protect device configuration, could be different between
- * 2 flash access (bk1, bk2)
- */
- struct mutex lock;
-};
-
-struct stm32_qspi_cmd {
- u8 addr_width;
- u8 dummy;
- bool tx_data;
- u8 opcode;
- u32 framemode;
- u32 qspimode;
- u32 addr;
- size_t len;
- void *buf;
-};
-
-static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi)
-{
- u32 cr;
- int err = 0;
-
- if (readl_relaxed(qspi->io_base + QUADSPI_SR) & SR_TCF)
- return 0;
-
- reinit_completion(&qspi->cmd_completion);
- cr = readl_relaxed(qspi->io_base + QUADSPI_CR);
- writel_relaxed(cr | CR_TCIE, qspi->io_base + QUADSPI_CR);
-
- if (!wait_for_completion_interruptible_timeout(&qspi->cmd_completion,
- msecs_to_jiffies(1000)))
- err = -ETIMEDOUT;
-
- writel_relaxed(cr, qspi->io_base + QUADSPI_CR);
- return err;
-}
-
-static int stm32_qspi_wait_nobusy(struct stm32_qspi *qspi)
-{
- u32 sr;
-
- return readl_relaxed_poll_timeout(qspi->io_base + QUADSPI_SR, sr,
- !(sr & SR_BUSY), 10,
- STM32_QSPI_BUSY_TIMEOUT_US);
-}
-
-static void stm32_qspi_set_framemode(struct spi_nor *nor,
- struct stm32_qspi_cmd *cmd, bool read)
-{
- u32 dmode = CCR_DMODE_1;
-
- cmd->framemode = CCR_IMODE_1;
-
- if (read) {
- switch (nor->read_proto) {
- default:
- case SNOR_PROTO_1_1_1:
- dmode = CCR_DMODE_1;
- break;
- case SNOR_PROTO_1_1_2:
- dmode = CCR_DMODE_2;
- break;
- case SNOR_PROTO_1_1_4:
- dmode = CCR_DMODE_4;
- break;
- }
- }
-
- cmd->framemode |= cmd->tx_data ? dmode : 0;
- cmd->framemode |= cmd->addr_width ? CCR_ADMODE_1 : 0;
-}
-
-static void stm32_qspi_read_fifo(u8 *val, void __iomem *addr)
-{
- *val = readb_relaxed(addr);
-}
-
-static void stm32_qspi_write_fifo(u8 *val, void __iomem *addr)
-{
- writeb_relaxed(*val, addr);
-}
-
-static int stm32_qspi_tx_poll(struct stm32_qspi *qspi,
- const struct stm32_qspi_cmd *cmd)
-{
- void (*tx_fifo)(u8 *, void __iomem *);
- u32 len = cmd->len, sr;
- u8 *buf = cmd->buf;
- int ret;
-
- if (cmd->qspimode == CCR_FMODE_INDW)
- tx_fifo = stm32_qspi_write_fifo;
- else
- tx_fifo = stm32_qspi_read_fifo;
-
- while (len--) {
- ret = readl_relaxed_poll_timeout(qspi->io_base + QUADSPI_SR,
- sr, (sr & SR_FTF), 10,
- STM32_QSPI_FIFO_TIMEOUT_US);
- if (ret) {
- dev_err(qspi->dev, "fifo timeout (stat:%#x)\n", sr);
- return ret;
- }
- tx_fifo(buf++, qspi->io_base + QUADSPI_DR);
- }
-
- return 0;
-}
-
-static int stm32_qspi_tx_mm(struct stm32_qspi *qspi,
- const struct stm32_qspi_cmd *cmd)
-{
- memcpy_fromio(cmd->buf, qspi->mm_base + cmd->addr, cmd->len);
- return 0;
-}
-
-static int stm32_qspi_tx(struct stm32_qspi *qspi,
- const struct stm32_qspi_cmd *cmd)
-{
- if (!cmd->tx_data)
- return 0;
-
- if (cmd->qspimode == CCR_FMODE_MM)
- return stm32_qspi_tx_mm(qspi, cmd);
-
- return stm32_qspi_tx_poll(qspi, cmd);
-}
-
-static int stm32_qspi_send(struct stm32_qspi_flash *flash,
- const struct stm32_qspi_cmd *cmd)
-{
- struct stm32_qspi *qspi = flash->qspi;
- u32 ccr, dcr, cr;
- u32 last_byte;
- int err;
-
- err = stm32_qspi_wait_nobusy(qspi);
- if (err)
- goto abort;
-
- dcr = readl_relaxed(qspi->io_base + QUADSPI_DCR) & ~DCR_FSIZE_MASK;
- dcr |= DCR_FSIZE(flash->fsize);
- writel_relaxed(dcr, qspi->io_base + QUADSPI_DCR);
-
- cr = readl_relaxed(qspi->io_base + QUADSPI_CR);
- cr &= ~CR_PRESC_MASK & ~CR_FSEL;
- cr |= CR_PRESC(flash->presc);
- cr |= flash->cs ? CR_FSEL : 0;
- writel_relaxed(cr, qspi->io_base + QUADSPI_CR);
-
- if (cmd->tx_data)
- writel_relaxed(cmd->len - 1, qspi->io_base + QUADSPI_DLR);
-
- ccr = cmd->framemode | cmd->qspimode;
-
- if (cmd->dummy)
- ccr |= CCR_DCYC(cmd->dummy);
-
- if (cmd->addr_width)
- ccr |= CCR_ADSIZE(cmd->addr_width - 1);
-
- ccr |= CCR_INST(cmd->opcode);
- writel_relaxed(ccr, qspi->io_base + QUADSPI_CCR);
-
- if (cmd->addr_width && cmd->qspimode != CCR_FMODE_MM)
- writel_relaxed(cmd->addr, qspi->io_base + QUADSPI_AR);
-
- err = stm32_qspi_tx(qspi, cmd);
- if (err)
- goto abort;
-
- if (cmd->qspimode != CCR_FMODE_MM) {
- err = stm32_qspi_wait_cmd(qspi);
- if (err)
- goto abort;
- writel_relaxed(FCR_CTCF, qspi->io_base + QUADSPI_FCR);
- } else {
- last_byte = cmd->addr + cmd->len;
- if (last_byte > flash->prefetch_limit)
- goto abort;
- }
-
- return err;
-
-abort:
- cr = readl_relaxed(qspi->io_base + QUADSPI_CR) | CR_ABORT;
- writel_relaxed(cr, qspi->io_base + QUADSPI_CR);
-
- if (err)
- dev_err(qspi->dev, "%s abort err:%d\n", __func__, err);
-
- return err;
-}
-
-static int stm32_qspi_read_reg(struct spi_nor *nor,
- u8 opcode, u8 *buf, int len)
-{
- struct stm32_qspi_flash *flash = nor->priv;
- struct device *dev = flash->qspi->dev;
- struct stm32_qspi_cmd cmd;
-
- dev_dbg(dev, "read_reg: cmd:%#.2x buf:%pK len:%#x\n", opcode, buf, len);
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = opcode;
- cmd.tx_data = true;
- cmd.len = len;
- cmd.buf = buf;
- cmd.qspimode = CCR_FMODE_INDR;
-
- stm32_qspi_set_framemode(nor, &cmd, false);
-
- return stm32_qspi_send(flash, &cmd);
-}
-
-static int stm32_qspi_write_reg(struct spi_nor *nor, u8 opcode,
- u8 *buf, int len)
-{
- struct stm32_qspi_flash *flash = nor->priv;
- struct device *dev = flash->qspi->dev;
- struct stm32_qspi_cmd cmd;
-
- dev_dbg(dev, "write_reg: cmd:%#.2x buf:%pK len:%#x\n", opcode, buf, len);
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = opcode;
- cmd.tx_data = !!(buf && len > 0);
- cmd.len = len;
- cmd.buf = buf;
- cmd.qspimode = CCR_FMODE_INDW;
-
- stm32_qspi_set_framemode(nor, &cmd, false);
-
- return stm32_qspi_send(flash, &cmd);
-}
-
-static ssize_t stm32_qspi_read(struct spi_nor *nor, loff_t from, size_t len,
- u_char *buf)
-{
- struct stm32_qspi_flash *flash = nor->priv;
- struct stm32_qspi *qspi = flash->qspi;
- struct stm32_qspi_cmd cmd;
- int err;
-
- dev_dbg(qspi->dev, "read(%#.2x): buf:%pK from:%#.8x len:%#zx\n",
- nor->read_opcode, buf, (u32)from, len);
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = nor->read_opcode;
- cmd.addr_width = nor->addr_width;
- cmd.addr = (u32)from;
- cmd.tx_data = true;
- cmd.dummy = nor->read_dummy;
- cmd.len = len;
- cmd.buf = buf;
- cmd.qspimode = flash->read_mode;
-
- stm32_qspi_set_framemode(nor, &cmd, true);
- err = stm32_qspi_send(flash, &cmd);
-
- return err ? err : len;
-}
-
-static ssize_t stm32_qspi_write(struct spi_nor *nor, loff_t to, size_t len,
- const u_char *buf)
-{
- struct stm32_qspi_flash *flash = nor->priv;
- struct device *dev = flash->qspi->dev;
- struct stm32_qspi_cmd cmd;
- int err;
-
- dev_dbg(dev, "write(%#.2x): buf:%p to:%#.8x len:%#zx\n",
- nor->program_opcode, buf, (u32)to, len);
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = nor->program_opcode;
- cmd.addr_width = nor->addr_width;
- cmd.addr = (u32)to;
- cmd.tx_data = true;
- cmd.len = len;
- cmd.buf = (void *)buf;
- cmd.qspimode = CCR_FMODE_INDW;
-
- stm32_qspi_set_framemode(nor, &cmd, false);
- err = stm32_qspi_send(flash, &cmd);
-
- return err ? err : len;
-}
-
-static int stm32_qspi_erase(struct spi_nor *nor, loff_t offs)
-{
- struct stm32_qspi_flash *flash = nor->priv;
- struct device *dev = flash->qspi->dev;
- struct stm32_qspi_cmd cmd;
-
- dev_dbg(dev, "erase(%#.2x):offs:%#x\n", nor->erase_opcode, (u32)offs);
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = nor->erase_opcode;
- cmd.addr_width = nor->addr_width;
- cmd.addr = (u32)offs;
- cmd.qspimode = CCR_FMODE_INDW;
-
- stm32_qspi_set_framemode(nor, &cmd, false);
-
- return stm32_qspi_send(flash, &cmd);
-}
-
-static irqreturn_t stm32_qspi_irq(int irq, void *dev_id)
-{
- struct stm32_qspi *qspi = (struct stm32_qspi *)dev_id;
- u32 cr, sr, fcr = 0;
-
- cr = readl_relaxed(qspi->io_base + QUADSPI_CR);
- sr = readl_relaxed(qspi->io_base + QUADSPI_SR);
-
- if ((cr & CR_TCIE) && (sr & SR_TCF)) {
- /* tx complete */
- fcr |= FCR_CTCF;
- complete(&qspi->cmd_completion);
- } else {
- dev_info_ratelimited(qspi->dev, "spurious interrupt\n");
- }
-
- writel_relaxed(fcr, qspi->io_base + QUADSPI_FCR);
-
- return IRQ_HANDLED;
-}
-
-static int stm32_qspi_prep(struct spi_nor *nor, enum spi_nor_ops ops)
-{
- struct stm32_qspi_flash *flash = nor->priv;
- struct stm32_qspi *qspi = flash->qspi;
-
- mutex_lock(&qspi->lock);
- return 0;
-}
-
-static void stm32_qspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
-{
- struct stm32_qspi_flash *flash = nor->priv;
- struct stm32_qspi *qspi = flash->qspi;
-
- mutex_unlock(&qspi->lock);
-}
-
-static int stm32_qspi_flash_setup(struct stm32_qspi *qspi,
- struct device_node *np)
-{
- struct spi_nor_hwcaps hwcaps = {
- .mask = SNOR_HWCAPS_READ |
- SNOR_HWCAPS_READ_FAST |
- SNOR_HWCAPS_PP,
- };
- u32 width, presc, cs_num, max_rate = 0;
- struct stm32_qspi_flash *flash;
- struct mtd_info *mtd;
- int ret;
-
- of_property_read_u32(np, "reg", &cs_num);
- if (cs_num >= STM32_MAX_NORCHIP)
- return -EINVAL;
-
- of_property_read_u32(np, "spi-max-frequency", &max_rate);
- if (!max_rate)
- return -EINVAL;
-
- presc = DIV_ROUND_UP(qspi->clk_rate, max_rate) - 1;
-
- if (of_property_read_u32(np, "spi-rx-bus-width", &width))
- width = 1;
-
- if (width == 4)
- hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;
- else if (width == 2)
- hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2;
- else if (width != 1)
- return -EINVAL;
-
- flash = &qspi->flash[cs_num];
- flash->qspi = qspi;
- flash->cs = cs_num;
- flash->presc = presc;
-
- flash->nor.dev = qspi->dev;
- spi_nor_set_flash_node(&flash->nor, np);
- flash->nor.priv = flash;
- mtd = &flash->nor.mtd;
-
- flash->nor.read = stm32_qspi_read;
- flash->nor.write = stm32_qspi_write;
- flash->nor.erase = stm32_qspi_erase;
- flash->nor.read_reg = stm32_qspi_read_reg;
- flash->nor.write_reg = stm32_qspi_write_reg;
- flash->nor.prepare = stm32_qspi_prep;
- flash->nor.unprepare = stm32_qspi_unprep;
-
- writel_relaxed(LPTR_DFT_TIMEOUT, qspi->io_base + QUADSPI_LPTR);
-
- writel_relaxed(CR_PRESC(presc) | CR_FTHRES(3) | CR_TCEN | CR_SSHIFT
- | CR_EN, qspi->io_base + QUADSPI_CR);
-
- /*
- * in stm32 qspi controller, QUADSPI_DCR register has a fsize field
- * which define the size of nor flash.
- * if fsize is NULL, the controller can't sent spi-nor command.
- * set a temporary value just to discover the nor flash with
- * "spi_nor_scan". After, the right value (mtd->size) can be set.
- */
- flash->fsize = FSIZE_VAL(SZ_1K);
-
- ret = spi_nor_scan(&flash->nor, NULL, &hwcaps);
- if (ret) {
- dev_err(qspi->dev, "device scan failed\n");
- return ret;
- }
-
- flash->fsize = FSIZE_VAL(mtd->size);
- flash->prefetch_limit = mtd->size - STM32_QSPI_FIFO_SZ;
-
- flash->read_mode = CCR_FMODE_MM;
- if (mtd->size > qspi->mm_size)
- flash->read_mode = CCR_FMODE_INDR;
-
- writel_relaxed(DCR_CSHT(1), qspi->io_base + QUADSPI_DCR);
-
- ret = mtd_device_register(mtd, NULL, 0);
- if (ret) {
- dev_err(qspi->dev, "mtd device parse failed\n");
- return ret;
- }
-
- flash->registered = true;
-
- dev_dbg(qspi->dev, "read mm:%s cs:%d bus:%d\n",
- flash->read_mode == CCR_FMODE_MM ? "yes" : "no", cs_num, width);
-
- return 0;
-}
-
-static void stm32_qspi_mtd_free(struct stm32_qspi *qspi)
-{
- int i;
-
- for (i = 0; i < STM32_MAX_NORCHIP; i++)
- if (qspi->flash[i].registered)
- mtd_device_unregister(&qspi->flash[i].nor.mtd);
-}
-
-static int stm32_qspi_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct device_node *flash_np;
- struct reset_control *rstc;
- struct stm32_qspi *qspi;
- struct resource *res;
- int ret, irq;
-
- qspi = devm_kzalloc(dev, sizeof(*qspi), GFP_KERNEL);
- if (!qspi)
- return -ENOMEM;
-
- qspi->nor_num = of_get_child_count(dev->of_node);
- if (!qspi->nor_num || qspi->nor_num > STM32_MAX_NORCHIP)
- return -ENODEV;
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi");
- qspi->io_base = devm_ioremap_resource(dev, res);
- if (IS_ERR(qspi->io_base))
- return PTR_ERR(qspi->io_base);
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_mm");
- qspi->mm_base = devm_ioremap_resource(dev, res);
- if (IS_ERR(qspi->mm_base))
- return PTR_ERR(qspi->mm_base);
-
- qspi->mm_size = resource_size(res);
-
- irq = platform_get_irq(pdev, 0);
- ret = devm_request_irq(dev, irq, stm32_qspi_irq, 0,
- dev_name(dev), qspi);
- if (ret) {
- dev_err(dev, "failed to request irq\n");
- return ret;
- }
-
- init_completion(&qspi->cmd_completion);
-
- qspi->clk = devm_clk_get(dev, NULL);
- if (IS_ERR(qspi->clk))
- return PTR_ERR(qspi->clk);
-
- qspi->clk_rate = clk_get_rate(qspi->clk);
- if (!qspi->clk_rate)
- return -EINVAL;
-
- ret = clk_prepare_enable(qspi->clk);
- if (ret) {
- dev_err(dev, "can not enable the clock\n");
- return ret;
- }
-
- rstc = devm_reset_control_get_exclusive(dev, NULL);
- if (!IS_ERR(rstc)) {
- reset_control_assert(rstc);
- udelay(2);
- reset_control_deassert(rstc);
- }
-
- qspi->dev = dev;
- platform_set_drvdata(pdev, qspi);
- mutex_init(&qspi->lock);
-
- for_each_available_child_of_node(dev->of_node, flash_np) {
- ret = stm32_qspi_flash_setup(qspi, flash_np);
- if (ret) {
- dev_err(dev, "unable to setup flash chip\n");
- goto err_flash;
- }
- }
-
- return 0;
-
-err_flash:
- mutex_destroy(&qspi->lock);
- stm32_qspi_mtd_free(qspi);
-
- clk_disable_unprepare(qspi->clk);
- return ret;
-}
-
-static int stm32_qspi_remove(struct platform_device *pdev)
-{
- struct stm32_qspi *qspi = platform_get_drvdata(pdev);
-
- /* disable qspi */
- writel_relaxed(0, qspi->io_base + QUADSPI_CR);
-
- stm32_qspi_mtd_free(qspi);
- mutex_destroy(&qspi->lock);
-
- clk_disable_unprepare(qspi->clk);
- return 0;
-}
-
-static const struct of_device_id stm32_qspi_match[] = {
- {.compatible = "st,stm32f469-qspi"},
- {}
-};
-MODULE_DEVICE_TABLE(of, stm32_qspi_match);
-
-static struct platform_driver stm32_qspi_driver = {
- .probe = stm32_qspi_probe,
- .remove = stm32_qspi_remove,
- .driver = {
- .name = "stm32-quadspi",
- .of_match_table = stm32_qspi_match,
- },
-};
-module_platform_driver(stm32_qspi_driver);
-
-MODULE_AUTHOR("Ludovic Barre <ludovic.barre@st.com>");
-MODULE_DESCRIPTION("STMicroelectronics STM32 quad spi driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/ssfdc.c b/drivers/mtd/ssfdc.c
index 7a1e54546f4a..1d05c121904c 100644
--- a/drivers/mtd/ssfdc.c
+++ b/drivers/mtd/ssfdc.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Linux driver for SSFDC Flash Translation Layer (Read only)
* © 2005 Eptar srl
* Author: Claudio Lanconelli <lanconelli.claudio@eptar.com>
*
* Based on NTFL and MTDBLOCK_RO drivers
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
index 7659d6c5f718..e5c571fd232c 100644
--- a/drivers/mux/Kconfig
+++ b/drivers/mux/Kconfig
@@ -46,14 +46,14 @@ config MUX_GPIO
be called mux-gpio.
config MUX_MMIO
- tristate "MMIO register bitfield-controlled Multiplexer"
- depends on (OF && MFD_SYSCON) || COMPILE_TEST
+ tristate "MMIO/Regmap register bitfield-controlled Multiplexer"
+ depends on OF || COMPILE_TEST
help
- MMIO register bitfield-controlled Multiplexer controller.
+ MMIO/Regmap register bitfield-controlled Multiplexer controller.
- The driver builds multiplexer controllers for bitfields in a syscon
- register. For N bit wide bitfields, there will be 2^N possible
- multiplexer states.
+ The driver builds multiplexer controllers for bitfields in either
+ a syscon register or a driver regmap register. For N bit wide
+ bitfields, there will be 2^N possible multiplexer states.
To compile the driver as a module, choose M here: the module will
be called mux-mmio.
diff --git a/drivers/mux/mmio.c b/drivers/mux/mmio.c
index 935ac44aa209..44a7a0e885b8 100644
--- a/drivers/mux/mmio.c
+++ b/drivers/mux/mmio.c
@@ -28,6 +28,7 @@ static const struct mux_control_ops mux_mmio_ops = {
static const struct of_device_id mux_mmio_dt_ids[] = {
{ .compatible = "mmio-mux", },
+ { .compatible = "reg-mux", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mux_mmio_dt_ids);
@@ -43,7 +44,10 @@ static int mux_mmio_probe(struct platform_device *pdev)
int ret;
int i;
- regmap = syscon_node_to_regmap(np->parent);
+ if (of_device_is_compatible(np, "mmio-mux"))
+ regmap = syscon_node_to_regmap(np->parent);
+ else
+ regmap = dev_get_regmap(dev->parent, NULL) ?: ERR_PTR(-ENODEV);
if (IS_ERR(regmap)) {
ret = PTR_ERR(regmap);
dev_err(dev, "failed to get regmap: %d\n", ret);
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index dfd6f315d2cc..e3b25f310936 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -325,17 +325,17 @@ static u16 __get_link_speed(struct port *port)
default:
/* unknown speed value from ethtool. shouldn't happen */
if (slave->speed != SPEED_UNKNOWN)
- pr_warn_once("%s: unknown ethtool speed (%d) for port %d (set it to 0)\n",
+ pr_warn_once("%s: (slave %s): unknown ethtool speed (%d) for port %d (set it to 0)\n",
slave->bond->dev->name,
- slave->speed,
+ slave->dev->name, slave->speed,
port->actor_port_number);
speed = 0;
break;
}
}
- netdev_dbg(slave->bond->dev, "Port %d Received link speed %d update from adapter\n",
- port->actor_port_number, speed);
+ slave_dbg(slave->bond->dev, slave->dev, "Port %d Received link speed %d update from adapter\n",
+ port->actor_port_number, speed);
return speed;
}
@@ -359,14 +359,14 @@ static u8 __get_duplex(struct port *port)
switch (slave->duplex) {
case DUPLEX_FULL:
retval = 0x1;
- netdev_dbg(slave->bond->dev, "Port %d Received status full duplex update from adapter\n",
- port->actor_port_number);
+ slave_dbg(slave->bond->dev, slave->dev, "Port %d Received status full duplex update from adapter\n",
+ port->actor_port_number);
break;
case DUPLEX_HALF:
default:
retval = 0x0;
- netdev_dbg(slave->bond->dev, "Port %d Received status NOT full duplex update from adapter\n",
- port->actor_port_number);
+ slave_dbg(slave->bond->dev, slave->dev, "Port %d Received status NOT full duplex update from adapter\n",
+ port->actor_port_number);
break;
}
}
@@ -500,10 +500,12 @@ static void __record_pdu(struct lacpdu *lacpdu, struct port *port)
if ((port->sm_vars & AD_PORT_MATCHED) &&
(lacpdu->actor_state & AD_STATE_SYNCHRONIZATION)) {
partner->port_state |= AD_STATE_SYNCHRONIZATION;
- pr_debug("%s partner sync=1\n", port->slave->dev->name);
+ slave_dbg(port->slave->bond->dev, port->slave->dev,
+ "partner sync=1\n");
} else {
partner->port_state &= ~AD_STATE_SYNCHRONIZATION;
- pr_debug("%s partner sync=0\n", port->slave->dev->name);
+ slave_dbg(port->slave->bond->dev, port->slave->dev,
+ "partner sync=0\n");
}
}
}
@@ -789,8 +791,9 @@ static inline void __update_lacpdu_from_port(struct port *port)
lacpdu->actor_port_priority = htons(port->actor_port_priority);
lacpdu->actor_port = htons(port->actor_port_number);
lacpdu->actor_state = port->actor_oper_port_state;
- pr_debug("update lacpdu: %s, actor port state %x\n",
- port->slave->dev->name, port->actor_oper_port_state);
+ slave_dbg(port->slave->bond->dev, port->slave->dev,
+ "update lacpdu: actor port state %x\n",
+ port->actor_oper_port_state);
/* lacpdu->reserved_3_1 initialized
* lacpdu->tlv_type_partner_info initialized
@@ -1022,11 +1025,11 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
/* check if the state machine was changed */
if (port->sm_mux_state != last_state) {
- pr_debug("Mux Machine: Port=%d (%s), Last State=%d, Curr State=%d\n",
- port->actor_port_number,
- port->slave->dev->name,
- last_state,
- port->sm_mux_state);
+ slave_dbg(port->slave->bond->dev, port->slave->dev,
+ "Mux Machine: Port=%d, Last State=%d, Curr State=%d\n",
+ port->actor_port_number,
+ last_state,
+ port->sm_mux_state);
switch (port->sm_mux_state) {
case AD_MUX_DETACHED:
port->actor_oper_port_state &= ~AD_STATE_SYNCHRONIZATION;
@@ -1140,11 +1143,11 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
/* check if the State machine was changed or new lacpdu arrived */
if ((port->sm_rx_state != last_state) || (lacpdu)) {
- pr_debug("Rx Machine: Port=%d (%s), Last State=%d, Curr State=%d\n",
- port->actor_port_number,
- port->slave->dev->name,
- last_state,
- port->sm_rx_state);
+ slave_dbg(port->slave->bond->dev, port->slave->dev,
+ "Rx Machine: Port=%d, Last State=%d, Curr State=%d\n",
+ port->actor_port_number,
+ last_state,
+ port->sm_rx_state);
switch (port->sm_rx_state) {
case AD_RX_INITIALIZE:
if (!(port->actor_oper_port_key & AD_DUPLEX_KEY_MASKS))
@@ -1192,9 +1195,8 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
/* detect loopback situation */
if (MAC_ADDRESS_EQUAL(&(lacpdu->actor_system),
&(port->actor_system))) {
- netdev_err(port->slave->bond->dev, "An illegal loopback occurred on adapter (%s)\n"
- "Check the configuration to verify that all adapters are connected to 802.3ad compliant switch ports\n",
- port->slave->dev->name);
+ slave_err(port->slave->bond->dev, port->slave->dev, "An illegal loopback occurred on slave\n"
+ "Check the configuration to verify that all adapters are connected to 802.3ad compliant switch ports\n");
return;
}
__update_selected(lacpdu, port);
@@ -1263,8 +1265,10 @@ static void ad_tx_machine(struct port *port)
__update_lacpdu_from_port(port);
if (ad_lacpdu_send(port) >= 0) {
- pr_debug("Sent LACPDU on port %d\n",
- port->actor_port_number);
+ slave_dbg(port->slave->bond->dev,
+ port->slave->dev,
+ "Sent LACPDU on port %d\n",
+ port->actor_port_number);
/* mark ntt as false, so it will not be sent
* again until demanded
@@ -1343,9 +1347,10 @@ static void ad_periodic_machine(struct port *port)
/* check if the state machine was changed */
if (port->sm_periodic_state != last_state) {
- pr_debug("Periodic Machine: Port=%d, Last State=%d, Curr State=%d\n",
- port->actor_port_number, last_state,
- port->sm_periodic_state);
+ slave_dbg(port->slave->bond->dev, port->slave->dev,
+ "Periodic Machine: Port=%d, Last State=%d, Curr State=%d\n",
+ port->actor_port_number, last_state,
+ port->sm_periodic_state);
switch (port->sm_periodic_state) {
case AD_NO_PERIODIC:
port->sm_periodic_timer_counter = 0;
@@ -1421,9 +1426,9 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)
port->next_port_in_aggregator = NULL;
port->actor_port_aggregator_identifier = 0;
- netdev_dbg(bond->dev, "Port %d left LAG %d\n",
- port->actor_port_number,
- temp_aggregator->aggregator_identifier);
+ slave_dbg(bond->dev, port->slave->dev, "Port %d left LAG %d\n",
+ port->actor_port_number,
+ temp_aggregator->aggregator_identifier);
/* if the aggregator is empty, clear its
* parameters, and set it ready to be attached
*/
@@ -1436,10 +1441,10 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)
/* meaning: the port was related to an aggregator
* but was not on the aggregator port list
*/
- net_warn_ratelimited("%s: Warning: Port %d (on %s) was related to aggregator %d but was not on its port list\n",
+ net_warn_ratelimited("%s: (slave %s): Warning: Port %d was related to aggregator %d but was not on its port list\n",
port->slave->bond->dev->name,
- port->actor_port_number,
port->slave->dev->name,
+ port->actor_port_number,
port->aggregator->aggregator_identifier);
}
}
@@ -1470,9 +1475,9 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)
port->next_port_in_aggregator = aggregator->lag_ports;
port->aggregator->num_of_ports++;
aggregator->lag_ports = port;
- netdev_dbg(bond->dev, "Port %d joined LAG %d(existing LAG)\n",
- port->actor_port_number,
- port->aggregator->aggregator_identifier);
+ slave_dbg(bond->dev, slave->dev, "Port %d joined LAG %d (existing LAG)\n",
+ port->actor_port_number,
+ port->aggregator->aggregator_identifier);
/* mark this port as selected */
port->sm_vars |= AD_PORT_SELECTED;
@@ -1517,12 +1522,13 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)
/* mark this port as selected */
port->sm_vars |= AD_PORT_SELECTED;
- netdev_dbg(bond->dev, "Port %d joined LAG %d(new LAG)\n",
- port->actor_port_number,
- port->aggregator->aggregator_identifier);
+ slave_dbg(bond->dev, port->slave->dev, "Port %d joined LAG %d (new LAG)\n",
+ port->actor_port_number,
+ port->aggregator->aggregator_identifier);
} else {
- netdev_err(bond->dev, "Port %d (on %s) did not find a suitable aggregator\n",
- port->actor_port_number, port->slave->dev->name);
+ slave_err(bond->dev, port->slave->dev,
+ "Port %d did not find a suitable aggregator\n",
+ port->actor_port_number);
}
}
/* if all aggregator's ports are READY_N == TRUE, set ready=TRUE
@@ -1601,8 +1607,9 @@ static struct aggregator *ad_agg_selection_test(struct aggregator *best,
break;
default:
- net_warn_ratelimited("%s: Impossible agg select mode %d\n",
+ net_warn_ratelimited("%s: (slave %s): Impossible agg select mode %d\n",
curr->slave->bond->dev->name,
+ curr->slave->dev->name,
__get_agg_selection_mode(curr->lag_ports));
break;
}
@@ -1703,36 +1710,37 @@ static void ad_agg_selection_logic(struct aggregator *agg,
/* if there is new best aggregator, activate it */
if (best) {
- netdev_dbg(bond->dev, "best Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n",
+ netdev_dbg(bond->dev, "(slave %s): best Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n",
+ best->slave ? best->slave->dev->name : "NULL",
best->aggregator_identifier, best->num_of_ports,
best->actor_oper_aggregator_key,
best->partner_oper_aggregator_key,
best->is_individual, best->is_active);
- netdev_dbg(bond->dev, "best ports %p slave %p %s\n",
- best->lag_ports, best->slave,
- best->slave ? best->slave->dev->name : "NULL");
+ netdev_dbg(bond->dev, "(slave %s): best ports %p slave %p\n",
+ best->slave ? best->slave->dev->name : "NULL",
+ best->lag_ports, best->slave);
bond_for_each_slave_rcu(bond, slave, iter) {
agg = &(SLAVE_AD_INFO(slave)->aggregator);
- netdev_dbg(bond->dev, "Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n",
- agg->aggregator_identifier, agg->num_of_ports,
- agg->actor_oper_aggregator_key,
- agg->partner_oper_aggregator_key,
- agg->is_individual, agg->is_active);
+ slave_dbg(bond->dev, slave->dev, "Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n",
+ agg->aggregator_identifier, agg->num_of_ports,
+ agg->actor_oper_aggregator_key,
+ agg->partner_oper_aggregator_key,
+ agg->is_individual, agg->is_active);
}
- /* check if any partner replys */
- if (best->is_individual) {
+ /* check if any partner replies */
+ if (best->is_individual)
net_warn_ratelimited("%s: Warning: No 802.3ad response from the link partner for any adapters in the bond\n",
- best->slave ?
- best->slave->bond->dev->name : "NULL");
- }
+ bond->dev->name);
best->is_active = 1;
- netdev_dbg(bond->dev, "LAG %d chosen as the active LAG\n",
+ netdev_dbg(bond->dev, "(slave %s): LAG %d chosen as the active LAG\n",
+ best->slave ? best->slave->dev->name : "NULL",
best->aggregator_identifier);
- netdev_dbg(bond->dev, "Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n",
+ netdev_dbg(bond->dev, "(slave %s): Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n",
+ best->slave ? best->slave->dev->name : "NULL",
best->aggregator_identifier, best->num_of_ports,
best->actor_oper_aggregator_key,
best->partner_oper_aggregator_key,
@@ -1788,7 +1796,9 @@ static void ad_clear_agg(struct aggregator *aggregator)
aggregator->lag_ports = NULL;
aggregator->is_active = 0;
aggregator->num_of_ports = 0;
- pr_debug("LAG %d was cleared\n",
+ pr_debug("%s: LAG %d was cleared\n",
+ aggregator->slave ?
+ aggregator->slave->dev->name : "NULL",
aggregator->aggregator_identifier);
}
}
@@ -1885,9 +1895,10 @@ static void ad_enable_collecting_distributing(struct port *port,
bool *update_slave_arr)
{
if (port->aggregator->is_active) {
- pr_debug("Enabling port %d(LAG %d)\n",
- port->actor_port_number,
- port->aggregator->aggregator_identifier);
+ slave_dbg(port->slave->bond->dev, port->slave->dev,
+ "Enabling port %d (LAG %d)\n",
+ port->actor_port_number,
+ port->aggregator->aggregator_identifier);
__enable_port(port);
/* Slave array needs update */
*update_slave_arr = true;
@@ -1905,9 +1916,10 @@ static void ad_disable_collecting_distributing(struct port *port,
if (port->aggregator &&
!MAC_ADDRESS_EQUAL(&(port->aggregator->partner_system),
&(null_mac_addr))) {
- pr_debug("Disabling port %d(LAG %d)\n",
- port->actor_port_number,
- port->aggregator->aggregator_identifier);
+ slave_dbg(port->slave->bond->dev, port->slave->dev,
+ "Disabling port %d (LAG %d)\n",
+ port->actor_port_number,
+ port->aggregator->aggregator_identifier);
__disable_port(port);
/* Slave array needs an update */
*update_slave_arr = true;
@@ -1920,7 +1932,7 @@ static void ad_disable_collecting_distributing(struct port *port,
* @port: the port we're looking at
*/
static void ad_marker_info_received(struct bond_marker *marker_info,
- struct port *port)
+ struct port *port)
{
struct bond_marker marker;
@@ -1933,10 +1945,10 @@ static void ad_marker_info_received(struct bond_marker *marker_info,
marker.tlv_type = AD_MARKER_RESPONSE_SUBTYPE;
/* send the marker response */
- if (ad_marker_send(port, &marker) >= 0) {
- pr_debug("Sent Marker Response on port %d\n",
- port->actor_port_number);
- }
+ if (ad_marker_send(port, &marker) >= 0)
+ slave_dbg(port->slave->bond->dev, port->slave->dev,
+ "Sent Marker Response on port %d\n",
+ port->actor_port_number);
}
/**
@@ -2085,13 +2097,12 @@ void bond_3ad_unbind_slave(struct slave *slave)
/* if slave is null, the whole port is not initialized */
if (!port->slave) {
- netdev_warn(bond->dev, "Trying to unbind an uninitialized port on %s\n",
- slave->dev->name);
+ slave_warn(bond->dev, slave->dev, "Trying to unbind an uninitialized port\n");
goto out;
}
- netdev_dbg(bond->dev, "Unbinding Link Aggregation Group %d\n",
- aggregator->aggregator_identifier);
+ slave_dbg(bond->dev, slave->dev, "Unbinding Link Aggregation Group %d\n",
+ aggregator->aggregator_identifier);
/* Tell the partner that this port is not suitable for aggregation */
port->actor_oper_port_state &= ~AD_STATE_SYNCHRONIZATION;
@@ -2129,13 +2140,13 @@ void bond_3ad_unbind_slave(struct slave *slave)
* new aggregator
*/
if ((new_aggregator) && ((!new_aggregator->lag_ports) || ((new_aggregator->lag_ports == port) && !new_aggregator->lag_ports->next_port_in_aggregator))) {
- netdev_dbg(bond->dev, "Some port(s) related to LAG %d - replacing with LAG %d\n",
- aggregator->aggregator_identifier,
- new_aggregator->aggregator_identifier);
+ slave_dbg(bond->dev, slave->dev, "Some port(s) related to LAG %d - replacing with LAG %d\n",
+ aggregator->aggregator_identifier,
+ new_aggregator->aggregator_identifier);
if ((new_aggregator->lag_ports == port) &&
new_aggregator->is_active) {
- netdev_info(bond->dev, "Removing an active aggregator\n");
+ slave_info(bond->dev, slave->dev, "Removing an active aggregator\n");
select_new_active_agg = 1;
}
@@ -2166,7 +2177,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
ad_agg_selection_logic(__get_first_agg(port),
&dummy_slave_update);
} else {
- netdev_warn(bond->dev, "unbinding aggregator, and could not find a new aggregator for its ports\n");
+ slave_warn(bond->dev, slave->dev, "unbinding aggregator, and could not find a new aggregator for its ports\n");
}
} else {
/* in case that the only port related to this
@@ -2175,7 +2186,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
select_new_active_agg = aggregator->is_active;
ad_clear_agg(aggregator);
if (select_new_active_agg) {
- netdev_info(bond->dev, "Removing an active aggregator\n");
+ slave_info(bond->dev, slave->dev, "Removing an active aggregator\n");
/* select new active aggregator */
temp_aggregator = __get_first_agg(port);
if (temp_aggregator)
@@ -2185,7 +2196,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
}
}
- netdev_dbg(bond->dev, "Unbinding port %d\n", port->actor_port_number);
+ slave_dbg(bond->dev, slave->dev, "Unbinding port %d\n", port->actor_port_number);
/* find the aggregator that this port is connected to */
bond_for_each_slave(bond, slave_iter, iter) {
@@ -2208,7 +2219,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
select_new_active_agg = temp_aggregator->is_active;
ad_clear_agg(temp_aggregator);
if (select_new_active_agg) {
- netdev_info(bond->dev, "Removing an active aggregator\n");
+ slave_info(bond->dev, slave->dev, "Removing an active aggregator\n");
/* select new active aggregator */
ad_agg_selection_logic(__get_first_agg(port),
&dummy_slave_update);
@@ -2379,9 +2390,9 @@ static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave)
switch (lacpdu->subtype) {
case AD_TYPE_LACPDU:
ret = RX_HANDLER_CONSUMED;
- netdev_dbg(slave->bond->dev,
- "Received LACPDU on port %d slave %s\n",
- port->actor_port_number, slave->dev->name);
+ slave_dbg(slave->bond->dev, slave->dev,
+ "Received LACPDU on port %d\n",
+ port->actor_port_number);
/* Protect against concurrent state machines */
spin_lock(&slave->bond->mode_lock);
ad_rx_machine(lacpdu, port);
@@ -2395,18 +2406,18 @@ static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave)
marker = (struct bond_marker *)lacpdu;
switch (marker->tlv_type) {
case AD_MARKER_INFORMATION_SUBTYPE:
- netdev_dbg(slave->bond->dev, "Received Marker Information on port %d\n",
- port->actor_port_number);
+ slave_dbg(slave->bond->dev, slave->dev, "Received Marker Information on port %d\n",
+ port->actor_port_number);
ad_marker_info_received(marker, port);
break;
case AD_MARKER_RESPONSE_SUBTYPE:
- netdev_dbg(slave->bond->dev, "Received Marker Response on port %d\n",
- port->actor_port_number);
+ slave_dbg(slave->bond->dev, slave->dev, "Received Marker Response on port %d\n",
+ port->actor_port_number);
ad_marker_response_received(marker, port);
break;
default:
- netdev_dbg(slave->bond->dev, "Received an unknown Marker subtype on slot %d\n",
- port->actor_port_number);
+ slave_dbg(slave->bond->dev, slave->dev, "Received an unknown Marker subtype on port %d\n",
+ port->actor_port_number);
stat = &SLAVE_AD_INFO(slave)->stats.marker_unknown_rx;
atomic64_inc(stat);
stat = &BOND_AD_INFO(bond).stats.marker_unknown_rx;
@@ -2456,9 +2467,10 @@ static void ad_update_actor_keys(struct port *port, bool reset)
if (!reset) {
if (!speed) {
- netdev_err(port->slave->dev,
- "speed changed to 0 for port %s",
- port->slave->dev->name);
+ slave_err(port->slave->bond->dev,
+ port->slave->dev,
+ "speed changed to 0 on port %d\n",
+ port->actor_port_number);
} else if (duplex && ospeed != speed) {
/* Speed change restarts LACP state-machine */
port->sm_vars |= AD_PORT_BEGIN;
@@ -2483,17 +2495,16 @@ void bond_3ad_adapter_speed_duplex_changed(struct slave *slave)
/* if slave is null, the whole port is not initialized */
if (!port->slave) {
- netdev_warn(slave->bond->dev,
- "speed/duplex changed for uninitialized port %s\n",
- slave->dev->name);
+ slave_warn(slave->bond->dev, slave->dev,
+ "speed/duplex changed for uninitialized port\n");
return;
}
spin_lock_bh(&slave->bond->mode_lock);
ad_update_actor_keys(port, false);
spin_unlock_bh(&slave->bond->mode_lock);
- netdev_dbg(slave->bond->dev, "Port %d slave %s changed speed/duplex\n",
- port->actor_port_number, slave->dev->name);
+ slave_dbg(slave->bond->dev, slave->dev, "Port %d changed speed/duplex\n",
+ port->actor_port_number);
}
/**
@@ -2513,8 +2524,7 @@ void bond_3ad_handle_link_change(struct slave *slave, char link)
/* if slave is null, the whole port is not initialized */
if (!port->slave) {
- netdev_warn(slave->bond->dev, "link status changed for uninitialized port on %s\n",
- slave->dev->name);
+ slave_warn(slave->bond->dev, slave->dev, "link status changed for uninitialized port\n");
return;
}
@@ -2539,9 +2549,9 @@ void bond_3ad_handle_link_change(struct slave *slave, char link)
spin_unlock_bh(&slave->bond->mode_lock);
- netdev_dbg(slave->bond->dev, "Port %d changed link status to %s\n",
- port->actor_port_number,
- link == BOND_LINK_UP ? "UP" : "DOWN");
+ slave_dbg(slave->bond->dev, slave->dev, "Port %d changed link status to %s\n",
+ port->actor_port_number,
+ link == BOND_LINK_UP ? "UP" : "DOWN");
/* RTNL is held and mode_lock is released so it's safe
* to update slave_array here.
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 790e41c6fdd0..8c79bad2a9a5 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -300,7 +300,7 @@ static int rlb_arp_recv(const struct sk_buff *skb, struct bonding *bond,
if (arp->op_code == htons(ARPOP_REPLY)) {
/* update rx hash table for this ARP */
rlb_update_entry_from_arp(bond, arp);
- netdev_dbg(bond->dev, "Server received an ARP Reply from client\n");
+ slave_dbg(bond->dev, slave->dev, "Server received an ARP Reply from client\n");
}
out:
return RX_HANDLER_ANOTHER;
@@ -442,8 +442,9 @@ static void rlb_update_client(struct rlb_client_info *client_info)
client_info->slave->dev->dev_addr,
client_info->mac_dst);
if (!skb) {
- netdev_err(client_info->slave->bond->dev,
- "failed to create an ARP packet\n");
+ slave_err(client_info->slave->bond->dev,
+ client_info->slave->dev,
+ "failed to create an ARP packet\n");
continue;
}
@@ -667,14 +668,15 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond)
if (tx_slave)
bond_hw_addr_copy(arp->mac_src, tx_slave->dev->dev_addr,
tx_slave->dev->addr_len);
- netdev_dbg(bond->dev, "Server sent ARP Reply packet\n");
+ netdev_dbg(bond->dev, "(slave %s): Server sent ARP Reply packet\n",
+ tx_slave ? tx_slave->dev->name : "NULL");
} else if (arp->op_code == htons(ARPOP_REQUEST)) {
/* Create an entry in the rx_hashtbl for this client as a
* place holder.
* When the arp reply is received the entry will be updated
* with the correct unicast address of the client.
*/
- rlb_choose_channel(skb, bond);
+ tx_slave = rlb_choose_channel(skb, bond);
/* The ARP reply packets must be delayed so that
* they can cancel out the influence of the ARP request.
@@ -687,7 +689,8 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond)
* updated with their assigned mac.
*/
rlb_req_update_subnet_clients(bond, arp->ip_src);
- netdev_dbg(bond->dev, "Server sent ARP Request packet\n");
+ netdev_dbg(bond->dev, "(slave %s): Server sent ARP Request packet\n",
+ tx_slave ? tx_slave->dev->name : "NULL");
}
return tx_slave;
@@ -923,9 +926,8 @@ static void alb_send_lp_vid(struct slave *slave, u8 mac_addr[],
skb->priority = TC_PRIO_CONTROL;
skb->dev = slave->dev;
- netdev_dbg(slave->bond->dev,
- "Send learning packet: dev %s mac %pM vlan %d\n",
- slave->dev->name, mac_addr, vid);
+ slave_dbg(slave->bond->dev, slave->dev,
+ "Send learning packet: mac %pM vlan %d\n", mac_addr, vid);
if (vid)
__vlan_hwaccel_put_tag(skb, vlan_proto, vid);
@@ -1016,8 +1018,7 @@ static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[],
memcpy(ss.__data, addr, len);
ss.ss_family = dev->type;
if (dev_set_mac_address(dev, (struct sockaddr *)&ss, NULL)) {
- netdev_err(slave->bond->dev, "dev_set_mac_address of dev %s failed! ALB mode requires that the base driver support setting the hw address also when the network device's interface is open\n",
- dev->name);
+ slave_err(slave->bond->dev, dev, "dev_set_mac_address on slave failed! ALB mode requires that the base driver support setting the hw address also when the network device's interface is open\n");
return -EOPNOTSUPP;
}
return 0;
@@ -1192,12 +1193,11 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
alb_set_slave_mac_addr(slave, free_mac_slave->perm_hwaddr,
free_mac_slave->dev->addr_len);
- netdev_warn(bond->dev, "the hw address of slave %s is in use by the bond; giving it the hw address of %s\n",
- slave->dev->name, free_mac_slave->dev->name);
+ slave_warn(bond->dev, slave->dev, "the slave hw address is in use by the bond; giving it the hw address of %s\n",
+ free_mac_slave->dev->name);
} else if (has_bond_addr) {
- netdev_err(bond->dev, "the hw address of slave %s is in use by the bond; couldn't find a slave with a free hw address to give it (this should not have happened)\n",
- slave->dev->name);
+ slave_err(bond->dev, slave->dev, "the slave hw address is in use by the bond; couldn't find a slave with a free hw address to give it (this should not have happened)\n");
return -EFAULT;
}
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 407f4095a37a..9b7016abca2f 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -613,8 +613,8 @@ static int bond_set_dev_addr(struct net_device *bond_dev,
{
int err;
- netdev_dbg(bond_dev, "bond_dev=%p slave_dev=%p slave_dev->name=%s slave_dev->addr_len=%d\n",
- bond_dev, slave_dev, slave_dev->name, slave_dev->addr_len);
+ slave_dbg(bond_dev, slave_dev, "bond_dev=%p slave_dev=%p slave_dev->addr_len=%d\n",
+ bond_dev, slave_dev, slave_dev->addr_len);
err = dev_pre_changeaddr_notify(bond_dev, slave_dev->dev_addr, NULL);
if (err)
return err;
@@ -661,8 +661,8 @@ static void bond_do_fail_over_mac(struct bonding *bond,
if (new_active) {
rv = bond_set_dev_addr(bond->dev, new_active->dev);
if (rv)
- netdev_err(bond->dev, "Error %d setting MAC of slave %s\n",
- -rv, bond->dev->name);
+ slave_err(bond->dev, new_active->dev, "Error %d setting bond MAC from slave\n",
+ -rv);
}
break;
case BOND_FOM_FOLLOW:
@@ -692,8 +692,8 @@ static void bond_do_fail_over_mac(struct bonding *bond,
rv = dev_set_mac_address(new_active->dev,
(struct sockaddr *)&ss, NULL);
if (rv) {
- netdev_err(bond->dev, "Error %d setting MAC of slave %s\n",
- -rv, new_active->dev->name);
+ slave_err(bond->dev, new_active->dev, "Error %d setting MAC of new active slave\n",
+ -rv);
goto out;
}
@@ -707,8 +707,8 @@ static void bond_do_fail_over_mac(struct bonding *bond,
rv = dev_set_mac_address(old_active->dev,
(struct sockaddr *)&ss, NULL);
if (rv)
- netdev_err(bond->dev, "Error %d setting MAC of slave %s\n",
- -rv, new_active->dev->name);
+ slave_err(bond->dev, old_active->dev, "Error %d setting MAC of old active slave\n",
+ -rv);
out:
break;
default:
@@ -796,6 +796,8 @@ static bool bond_should_notify_peers(struct bonding *bond)
slave ? slave->dev->name : "NULL");
if (!slave || !bond->send_peer_notif ||
+ bond->send_peer_notif %
+ max(1, bond->params.peer_notif_delay) != 0 ||
!netif_carrier_ok(bond->dev) ||
test_bit(__LINK_STATE_LINKWATCH_PENDING, &slave->dev->state))
return false;
@@ -834,9 +836,8 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
if (new_active->link == BOND_LINK_BACK) {
if (bond_uses_primary(bond)) {
- netdev_info(bond->dev, "making interface %s the new active one %d ms earlier\n",
- new_active->dev->name,
- (bond->params.updelay - new_active->delay) * bond->params.miimon);
+ slave_info(bond->dev, new_active->dev, "making interface the new active one %d ms earlier\n",
+ (bond->params.updelay - new_active->delay) * bond->params.miimon);
}
new_active->delay = 0;
@@ -850,8 +851,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
bond_alb_handle_link_change(bond, new_active, BOND_LINK_UP);
} else {
if (bond_uses_primary(bond)) {
- netdev_info(bond->dev, "making interface %s the new active one\n",
- new_active->dev->name);
+ slave_info(bond->dev, new_active->dev, "making interface the new active one\n");
}
}
}
@@ -888,15 +888,18 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
if (netif_running(bond->dev)) {
bond->send_peer_notif =
- bond->params.num_peer_notif;
+ bond->params.num_peer_notif *
+ max(1, bond->params.peer_notif_delay);
should_notify_peers =
bond_should_notify_peers(bond);
}
call_netdevice_notifiers(NETDEV_BONDING_FAILOVER, bond->dev);
- if (should_notify_peers)
+ if (should_notify_peers) {
+ bond->send_peer_notif--;
call_netdevice_notifiers(NETDEV_NOTIFY_PEERS,
bond->dev);
+ }
}
}
@@ -939,7 +942,7 @@ void bond_select_active_slave(struct bonding *bond)
return;
if (netif_carrier_ok(bond->dev))
- netdev_info(bond->dev, "first active interface up!\n");
+ netdev_info(bond->dev, "active interface up!\n");
else
netdev_info(bond->dev, "now running without any active interface!\n");
}
@@ -1077,12 +1080,16 @@ static netdev_features_t bond_fix_features(struct net_device *dev,
#define BOND_ENC_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | \
NETIF_F_RXCSUM | NETIF_F_ALL_TSO)
+#define BOND_MPLS_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | \
+ NETIF_F_ALL_TSO)
+
static void bond_compute_features(struct bonding *bond)
{
unsigned int dst_release_flag = IFF_XMIT_DST_RELEASE |
IFF_XMIT_DST_RELEASE_PERM;
netdev_features_t vlan_features = BOND_VLAN_FEATURES;
netdev_features_t enc_features = BOND_ENC_FEATURES;
+ netdev_features_t mpls_features = BOND_MPLS_FEATURES;
struct net_device *bond_dev = bond->dev;
struct list_head *iter;
struct slave *slave;
@@ -1093,6 +1100,7 @@ static void bond_compute_features(struct bonding *bond)
if (!bond_has_slaves(bond))
goto done;
vlan_features &= NETIF_F_ALL_FOR_ALL;
+ mpls_features &= NETIF_F_ALL_FOR_ALL;
bond_for_each_slave(bond, slave, iter) {
vlan_features = netdev_increment_features(vlan_features,
@@ -1101,6 +1109,11 @@ static void bond_compute_features(struct bonding *bond)
enc_features = netdev_increment_features(enc_features,
slave->dev->hw_enc_features,
BOND_ENC_FEATURES);
+
+ mpls_features = netdev_increment_features(mpls_features,
+ slave->dev->mpls_features,
+ BOND_MPLS_FEATURES);
+
dst_release_flag &= slave->dev->priv_flags;
if (slave->dev->hard_header_len > max_hard_header_len)
max_hard_header_len = slave->dev->hard_header_len;
@@ -1114,6 +1127,7 @@ done:
bond_dev->vlan_features = vlan_features;
bond_dev->hw_enc_features = enc_features | NETIF_F_GSO_ENCAP_ALL |
NETIF_F_GSO_UDP_L4;
+ bond_dev->mpls_features = mpls_features;
bond_dev->gso_max_segs = gso_max_segs;
netif_set_gso_max_size(bond_dev, gso_max_size);
@@ -1369,15 +1383,14 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
if (!bond->params.use_carrier &&
slave_dev->ethtool_ops->get_link == NULL &&
slave_ops->ndo_do_ioctl == NULL) {
- netdev_warn(bond_dev, "no link monitoring support for %s\n",
- slave_dev->name);
+ slave_warn(bond_dev, slave_dev, "no link monitoring support\n");
}
/* already in-use? */
if (netdev_is_rx_handler_busy(slave_dev)) {
NL_SET_ERR_MSG(extack, "Device is in use and cannot be enslaved");
- netdev_err(bond_dev,
- "Error: Device is in use and cannot be enslaved\n");
+ slave_err(bond_dev, slave_dev,
+ "Error: Device is in use and cannot be enslaved\n");
return -EBUSY;
}
@@ -1390,21 +1403,16 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
/* vlan challenged mutual exclusion */
/* no need to lock since we're protected by rtnl_lock */
if (slave_dev->features & NETIF_F_VLAN_CHALLENGED) {
- netdev_dbg(bond_dev, "%s is NETIF_F_VLAN_CHALLENGED\n",
- slave_dev->name);
+ slave_dbg(bond_dev, slave_dev, "is NETIF_F_VLAN_CHALLENGED\n");
if (vlan_uses_dev(bond_dev)) {
NL_SET_ERR_MSG(extack, "Can not enslave VLAN challenged device to VLAN enabled bond");
- netdev_err(bond_dev, "Error: cannot enslave VLAN challenged slave %s on VLAN enabled bond %s\n",
- slave_dev->name, bond_dev->name);
+ slave_err(bond_dev, slave_dev, "Error: cannot enslave VLAN challenged slave on VLAN enabled bond\n");
return -EPERM;
} else {
- netdev_warn(bond_dev, "enslaved VLAN challenged slave %s. Adding VLANs will be blocked as long as %s is part of bond %s\n",
- slave_dev->name, slave_dev->name,
- bond_dev->name);
+ slave_warn(bond_dev, slave_dev, "enslaved VLAN challenged slave. Adding VLANs will be blocked as long as it is part of bond.\n");
}
} else {
- netdev_dbg(bond_dev, "%s is !NETIF_F_VLAN_CHALLENGED\n",
- slave_dev->name);
+ slave_dbg(bond_dev, slave_dev, "is !NETIF_F_VLAN_CHALLENGED\n");
}
/* Old ifenslave binaries are no longer supported. These can
@@ -1414,8 +1422,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
*/
if (slave_dev->flags & IFF_UP) {
NL_SET_ERR_MSG(extack, "Device can not be enslaved while up");
- netdev_err(bond_dev, "%s is up - this may be due to an out of date ifenslave\n",
- slave_dev->name);
+ slave_err(bond_dev, slave_dev, "slave is up - this may be due to an out of date ifenslave\n");
return -EPERM;
}
@@ -1428,14 +1435,14 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
*/
if (!bond_has_slaves(bond)) {
if (bond_dev->type != slave_dev->type) {
- netdev_dbg(bond_dev, "change device type from %d to %d\n",
- bond_dev->type, slave_dev->type);
+ slave_dbg(bond_dev, slave_dev, "change device type from %d to %d\n",
+ bond_dev->type, slave_dev->type);
res = call_netdevice_notifiers(NETDEV_PRE_TYPE_CHANGE,
bond_dev);
res = notifier_to_errno(res);
if (res) {
- netdev_err(bond_dev, "refused to change device type\n");
+ slave_err(bond_dev, slave_dev, "refused to change device type\n");
return -EBUSY;
}
@@ -1455,31 +1462,31 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
}
} else if (bond_dev->type != slave_dev->type) {
NL_SET_ERR_MSG(extack, "Device type is different from other slaves");
- netdev_err(bond_dev, "%s ether type (%d) is different from other slaves (%d), can not enslave it\n",
- slave_dev->name, slave_dev->type, bond_dev->type);
+ slave_err(bond_dev, slave_dev, "ether type (%d) is different from other slaves (%d), can not enslave it\n",
+ slave_dev->type, bond_dev->type);
return -EINVAL;
}
if (slave_dev->type == ARPHRD_INFINIBAND &&
BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) {
NL_SET_ERR_MSG(extack, "Only active-backup mode is supported for infiniband slaves");
- netdev_warn(bond_dev, "Type (%d) supports only active-backup mode\n",
- slave_dev->type);
+ slave_warn(bond_dev, slave_dev, "Type (%d) supports only active-backup mode\n",
+ slave_dev->type);
res = -EOPNOTSUPP;
goto err_undo_flags;
}
if (!slave_ops->ndo_set_mac_address ||
slave_dev->type == ARPHRD_INFINIBAND) {
- netdev_warn(bond_dev, "The slave device specified does not support setting the MAC address\n");
+ slave_warn(bond_dev, slave_dev, "The slave device specified does not support setting the MAC address\n");
if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP &&
bond->params.fail_over_mac != BOND_FOM_ACTIVE) {
if (!bond_has_slaves(bond)) {
bond->params.fail_over_mac = BOND_FOM_ACTIVE;
- netdev_warn(bond_dev, "Setting fail_over_mac to active for active-backup mode\n");
+ slave_warn(bond_dev, slave_dev, "Setting fail_over_mac to active for active-backup mode\n");
} else {
NL_SET_ERR_MSG(extack, "Slave device does not support setting the MAC address, but fail_over_mac is not set to active");
- netdev_err(bond_dev, "The slave device specified does not support setting the MAC address, but fail_over_mac is not set to active\n");
+ slave_err(bond_dev, slave_dev, "The slave device specified does not support setting the MAC address, but fail_over_mac is not set to active\n");
res = -EOPNOTSUPP;
goto err_undo_flags;
}
@@ -1515,7 +1522,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
new_slave->original_mtu = slave_dev->mtu;
res = dev_set_mtu(slave_dev, bond->dev->mtu);
if (res) {
- netdev_dbg(bond_dev, "Error %d calling dev_set_mtu\n", res);
+ slave_err(bond_dev, slave_dev, "Error %d calling dev_set_mtu\n", res);
goto err_free;
}
@@ -1536,7 +1543,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
res = dev_set_mac_address(slave_dev, (struct sockaddr *)&ss,
extack);
if (res) {
- netdev_dbg(bond_dev, "Error %d calling set_mac_address\n", res);
+ slave_err(bond_dev, slave_dev, "Error %d calling set_mac_address\n", res);
goto err_restore_mtu;
}
}
@@ -1547,7 +1554,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
/* open the slave since the application closed it */
res = dev_open(slave_dev, extack);
if (res) {
- netdev_dbg(bond_dev, "Opening slave %s failed\n", slave_dev->name);
+ slave_err(bond_dev, slave_dev, "Opening slave failed\n");
goto err_restore_mac;
}
@@ -1566,8 +1573,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
res = vlan_vids_add_by_dev(slave_dev, bond_dev);
if (res) {
- netdev_err(bond_dev, "Couldn't add bond vlan ids to %s\n",
- slave_dev->name);
+ slave_err(bond_dev, slave_dev, "Couldn't add bond vlan ids\n");
goto err_close;
}
@@ -1597,12 +1603,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
* supported); thus, we don't need to change
* the messages for netif_carrier.
*/
- netdev_warn(bond_dev, "MII and ETHTOOL support not available for interface %s, and arp_interval/arp_ip_target module parameters not specified, thus bonding will not detect link failures! see bonding.txt for details\n",
- slave_dev->name);
+ slave_warn(bond_dev, slave_dev, "MII and ETHTOOL support not available for slave, and arp_interval/arp_ip_target module parameters not specified, thus bonding will not detect link failures! see bonding.txt for details\n");
} else if (link_reporting == -1) {
/* unable get link status using mii/ethtool */
- netdev_warn(bond_dev, "can't get link status from interface %s; the network driver associated with this interface does not support MII or ETHTOOL link status reporting, thus miimon has no effect on this interface\n",
- slave_dev->name);
+ slave_warn(bond_dev, slave_dev, "can't get link status from slave; the network driver associated with this interface does not support MII or ETHTOOL link status reporting, thus miimon has no effect on this interface\n");
}
}
@@ -1636,9 +1640,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
if (new_slave->link != BOND_LINK_DOWN)
new_slave->last_link_up = jiffies;
- netdev_dbg(bond_dev, "Initial state of slave_dev is BOND_LINK_%s\n",
- new_slave->link == BOND_LINK_DOWN ? "DOWN" :
- (new_slave->link == BOND_LINK_UP ? "UP" : "BACK"));
+ slave_dbg(bond_dev, slave_dev, "Initial state of slave is BOND_LINK_%s\n",
+ new_slave->link == BOND_LINK_DOWN ? "DOWN" :
+ (new_slave->link == BOND_LINK_UP ? "UP" : "BACK"));
if (bond_uses_primary(bond) && bond->params.primary[0]) {
/* if there is a primary slave, remember it */
@@ -1679,7 +1683,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
bond_set_slave_inactive_flags(new_slave, BOND_SLAVE_NOTIFY_NOW);
break;
default:
- netdev_dbg(bond_dev, "This slave is always active in trunk mode\n");
+ slave_dbg(bond_dev, slave_dev, "This slave is always active in trunk mode\n");
/* always active in trunk mode */
bond_set_active_slave(new_slave);
@@ -1698,7 +1702,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
#ifdef CONFIG_NET_POLL_CONTROLLER
if (bond->dev->npinfo) {
if (slave_enable_netpoll(new_slave)) {
- netdev_info(bond_dev, "master_dev is using netpoll, but new slave device does not support netpoll\n");
+ slave_info(bond_dev, slave_dev, "master_dev is using netpoll, but new slave device does not support netpoll\n");
res = -EBUSY;
goto err_detach;
}
@@ -1711,19 +1715,19 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
res = netdev_rx_handler_register(slave_dev, bond_handle_frame,
new_slave);
if (res) {
- netdev_dbg(bond_dev, "Error %d calling netdev_rx_handler_register\n", res);
+ slave_dbg(bond_dev, slave_dev, "Error %d calling netdev_rx_handler_register\n", res);
goto err_detach;
}
res = bond_master_upper_dev_link(bond, new_slave, extack);
if (res) {
- netdev_dbg(bond_dev, "Error %d calling bond_master_upper_dev_link\n", res);
+ slave_dbg(bond_dev, slave_dev, "Error %d calling bond_master_upper_dev_link\n", res);
goto err_unregister;
}
res = bond_sysfs_slave_add(new_slave);
if (res) {
- netdev_dbg(bond_dev, "Error %d calling bond_sysfs_slave_add\n", res);
+ slave_dbg(bond_dev, slave_dev, "Error %d calling bond_sysfs_slave_add\n", res);
goto err_upper_unlink;
}
@@ -1777,10 +1781,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
bond_update_slave_arr(bond, NULL);
- netdev_info(bond_dev, "Enslaving %s as %s interface with %s link\n",
- slave_dev->name,
- bond_is_active_slave(new_slave) ? "an active" : "a backup",
- new_slave->link != BOND_LINK_DOWN ? "an up" : "a down");
+ slave_info(bond_dev, slave_dev, "Enslaving as %s interface with %s link\n",
+ bond_is_active_slave(new_slave) ? "an active" : "a backup",
+ new_slave->link != BOND_LINK_DOWN ? "an up" : "a down");
/* enslave is successful */
bond_queue_slave_event(new_slave);
@@ -1875,8 +1878,7 @@ static int __bond_release_one(struct net_device *bond_dev,
/* slave is not a slave or master is not master of this slave */
if (!(slave_dev->flags & IFF_SLAVE) ||
!netdev_has_upper_dev(slave_dev, bond_dev)) {
- netdev_dbg(bond_dev, "cannot release %s\n",
- slave_dev->name);
+ slave_dbg(bond_dev, slave_dev, "cannot release slave\n");
return -EINVAL;
}
@@ -1885,8 +1887,7 @@ static int __bond_release_one(struct net_device *bond_dev,
slave = bond_get_slave_by_dev(bond, slave_dev);
if (!slave) {
/* not a slave of this bond */
- netdev_info(bond_dev, "%s not enslaved\n",
- slave_dev->name);
+ slave_info(bond_dev, slave_dev, "interface not enslaved\n");
unblock_netpoll_tx();
return -EINVAL;
}
@@ -1910,9 +1911,8 @@ static int __bond_release_one(struct net_device *bond_dev,
if (bond_mode_can_use_xmit_hash(bond))
bond_update_slave_arr(bond, slave);
- netdev_info(bond_dev, "Releasing %s interface %s\n",
- bond_is_active_slave(slave) ? "active" : "backup",
- slave_dev->name);
+ slave_info(bond_dev, slave_dev, "Releasing %s interface\n",
+ bond_is_active_slave(slave) ? "active" : "backup");
oldcurrent = rcu_access_pointer(bond->curr_active_slave);
@@ -1922,9 +1922,8 @@ static int __bond_release_one(struct net_device *bond_dev,
BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP)) {
if (ether_addr_equal_64bits(bond_dev->dev_addr, slave->perm_hwaddr) &&
bond_has_slaves(bond))
- netdev_warn(bond_dev, "the permanent HWaddr of %s - %pM - is still in use by %s - set the HWaddr of %s to a different address to avoid conflicts\n",
- slave_dev->name, slave->perm_hwaddr,
- bond_dev->name, slave_dev->name);
+ slave_warn(bond_dev, slave_dev, "the permanent HWaddr of slave - %pM - is still in use by bond - set the HWaddr of slave to a different address to avoid conflicts\n",
+ slave->perm_hwaddr);
}
if (rtnl_dereference(bond->primary_slave) == slave)
@@ -1972,8 +1971,7 @@ static int __bond_release_one(struct net_device *bond_dev,
bond_compute_features(bond);
if (!(bond_dev->features & NETIF_F_VLAN_CHALLENGED) &&
(old_features & NETIF_F_VLAN_CHALLENGED))
- netdev_info(bond_dev, "last VLAN challenged slave %s left bond %s - VLAN blocking is removed\n",
- slave_dev->name, bond_dev->name);
+ slave_info(bond_dev, slave_dev, "last VLAN challenged slave left bond - VLAN blocking is removed\n");
vlan_vids_del_by_dev(slave_dev, bond_dev);
@@ -2033,8 +2031,8 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
/* First release a slave and then destroy the bond if no more slaves are left.
* Must be under rtnl_lock when this function is called.
*/
-static int bond_release_and_destroy(struct net_device *bond_dev,
- struct net_device *slave_dev)
+static int bond_release_and_destroy(struct net_device *bond_dev,
+ struct net_device *slave_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
int ret;
@@ -2042,8 +2040,7 @@ static int bond_release_and_destroy(struct net_device *bond_dev,
ret = __bond_release_one(bond_dev, slave_dev, false, true);
if (ret == 0 && !bond_has_slaves(bond)) {
bond_dev->priv_flags |= IFF_DISABLE_NETPOLL;
- netdev_info(bond_dev, "Destroying bond %s\n",
- bond_dev->name);
+ netdev_info(bond_dev, "Destroying bond\n");
bond_remove_proc_entry(bond);
unregister_netdevice(bond_dev);
}
@@ -2101,13 +2098,12 @@ static int bond_miimon_inspect(struct bonding *bond)
commit++;
slave->delay = bond->params.downdelay;
if (slave->delay) {
- netdev_info(bond->dev, "link status down for %sinterface %s, disabling it in %d ms\n",
- (BOND_MODE(bond) ==
- BOND_MODE_ACTIVEBACKUP) ?
- (bond_is_active_slave(slave) ?
- "active " : "backup ") : "",
- slave->dev->name,
- bond->params.downdelay * bond->params.miimon);
+ slave_info(bond->dev, slave->dev, "link status down for %sinterface, disabling it in %d ms\n",
+ (BOND_MODE(bond) ==
+ BOND_MODE_ACTIVEBACKUP) ?
+ (bond_is_active_slave(slave) ?
+ "active " : "backup ") : "",
+ bond->params.downdelay * bond->params.miimon);
}
/*FALLTHRU*/
case BOND_LINK_FAIL:
@@ -2115,10 +2111,9 @@ static int bond_miimon_inspect(struct bonding *bond)
/* recovered before downdelay expired */
bond_propose_link_state(slave, BOND_LINK_UP);
slave->last_link_up = jiffies;
- netdev_info(bond->dev, "link status up again after %d ms for interface %s\n",
- (bond->params.downdelay - slave->delay) *
- bond->params.miimon,
- slave->dev->name);
+ slave_info(bond->dev, slave->dev, "link status up again after %d ms\n",
+ (bond->params.downdelay - slave->delay) *
+ bond->params.miimon);
commit++;
continue;
}
@@ -2141,20 +2136,18 @@ static int bond_miimon_inspect(struct bonding *bond)
slave->delay = bond->params.updelay;
if (slave->delay) {
- netdev_info(bond->dev, "link status up for interface %s, enabling it in %d ms\n",
- slave->dev->name,
- ignore_updelay ? 0 :
- bond->params.updelay *
- bond->params.miimon);
+ slave_info(bond->dev, slave->dev, "link status up, enabling it in %d ms\n",
+ ignore_updelay ? 0 :
+ bond->params.updelay *
+ bond->params.miimon);
}
/*FALLTHRU*/
case BOND_LINK_BACK:
if (!link_state) {
bond_propose_link_state(slave, BOND_LINK_DOWN);
- netdev_info(bond->dev, "link status down again after %d ms for interface %s\n",
- (bond->params.updelay - slave->delay) *
- bond->params.miimon,
- slave->dev->name);
+ slave_info(bond->dev, slave->dev, "link status down again after %d ms\n",
+ (bond->params.updelay - slave->delay) *
+ bond->params.miimon);
commit++;
continue;
}
@@ -2210,9 +2203,8 @@ static void bond_miimon_commit(struct bonding *bond)
bond_needs_speed_duplex(bond)) {
slave->link = BOND_LINK_DOWN;
if (net_ratelimit())
- netdev_warn(bond->dev,
- "failed to get link speed/duplex for %s\n",
- slave->dev->name);
+ slave_warn(bond->dev, slave->dev,
+ "failed to get link speed/duplex\n");
continue;
}
bond_set_slave_link_state(slave, BOND_LINK_UP,
@@ -2231,10 +2223,9 @@ static void bond_miimon_commit(struct bonding *bond)
bond_set_backup_slave(slave);
}
- netdev_info(bond->dev, "link status definitely up for interface %s, %u Mbps %s duplex\n",
- slave->dev->name,
- slave->speed == SPEED_UNKNOWN ? 0 : slave->speed,
- slave->duplex ? "full" : "half");
+ slave_info(bond->dev, slave->dev, "link status definitely up, %u Mbps %s duplex\n",
+ slave->speed == SPEED_UNKNOWN ? 0 : slave->speed,
+ slave->duplex ? "full" : "half");
bond_miimon_link_change(bond, slave, BOND_LINK_UP);
@@ -2255,8 +2246,7 @@ static void bond_miimon_commit(struct bonding *bond)
bond_set_slave_inactive_flags(slave,
BOND_SLAVE_NOTIFY_NOW);
- netdev_info(bond->dev, "link status definitely down for interface %s, disabling it\n",
- slave->dev->name);
+ slave_info(bond->dev, slave->dev, "link status definitely down, disabling slave\n");
bond_miimon_link_change(bond, slave, BOND_LINK_DOWN);
@@ -2266,8 +2256,8 @@ static void bond_miimon_commit(struct bonding *bond)
continue;
default:
- netdev_err(bond->dev, "invalid new link %d on slave %s\n",
- slave->new_link, slave->dev->name);
+ slave_err(bond->dev, slave->dev, "invalid new link %d on slave\n",
+ slave->new_link);
slave->new_link = BOND_LINK_NOCHANGE;
continue;
@@ -2294,6 +2284,7 @@ static void bond_mii_monitor(struct work_struct *work)
struct bonding *bond = container_of(work, struct bonding,
mii_work.work);
bool should_notify_peers = false;
+ bool commit;
unsigned long delay;
struct slave *slave;
struct list_head *iter;
@@ -2304,12 +2295,19 @@ static void bond_mii_monitor(struct work_struct *work)
goto re_arm;
rcu_read_lock();
-
should_notify_peers = bond_should_notify_peers(bond);
-
- if (bond_miimon_inspect(bond)) {
+ commit = !!bond_miimon_inspect(bond);
+ if (bond->send_peer_notif) {
rcu_read_unlock();
+ if (rtnl_trylock()) {
+ bond->send_peer_notif--;
+ rtnl_unlock();
+ }
+ } else {
+ rcu_read_unlock();
+ }
+ if (commit) {
/* Race avoidance with bond_close cancel of workqueue */
if (!rtnl_trylock()) {
delay = 1;
@@ -2323,8 +2321,7 @@ static void bond_mii_monitor(struct work_struct *work)
bond_miimon_commit(bond);
rtnl_unlock(); /* might sleep, hold no other locks */
- } else
- rcu_read_unlock();
+ }
re_arm:
if (bond->params.miimon)
@@ -2364,15 +2361,16 @@ static bool bond_has_this_ip(struct bonding *bond, __be32 ip)
* switches in VLAN mode (especially if ports are configured as
* "native" to a VLAN) might not pass non-tagged frames.
*/
-static void bond_arp_send(struct net_device *slave_dev, int arp_op,
- __be32 dest_ip, __be32 src_ip,
- struct bond_vlan_tag *tags)
+static void bond_arp_send(struct slave *slave, int arp_op, __be32 dest_ip,
+ __be32 src_ip, struct bond_vlan_tag *tags)
{
struct sk_buff *skb;
struct bond_vlan_tag *outer_tag = tags;
+ struct net_device *slave_dev = slave->dev;
+ struct net_device *bond_dev = slave->bond->dev;
- netdev_dbg(slave_dev, "arp %d on slave %s: dst %pI4 src %pI4\n",
- arp_op, slave_dev->name, &dest_ip, &src_ip);
+ slave_dbg(bond_dev, slave_dev, "arp %d on slave: dst %pI4 src %pI4\n",
+ arp_op, &dest_ip, &src_ip);
skb = arp_create(arp_op, ETH_P_ARP, dest_ip, slave_dev, src_ip,
NULL, slave_dev->dev_addr, NULL);
@@ -2394,8 +2392,8 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op,
continue;
}
- netdev_dbg(slave_dev, "inner tag: proto %X vid %X\n",
- ntohs(outer_tag->vlan_proto), tags->vlan_id);
+ slave_dbg(bond_dev, slave_dev, "inner tag: proto %X vid %X\n",
+ ntohs(outer_tag->vlan_proto), tags->vlan_id);
skb = vlan_insert_tag_set_proto(skb, tags->vlan_proto,
tags->vlan_id);
if (!skb) {
@@ -2407,8 +2405,8 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op,
}
/* Set the outer tag */
if (outer_tag->vlan_id) {
- netdev_dbg(slave_dev, "outer tag: proto %X vid %X\n",
- ntohs(outer_tag->vlan_proto), outer_tag->vlan_id);
+ slave_dbg(bond_dev, slave_dev, "outer tag: proto %X vid %X\n",
+ ntohs(outer_tag->vlan_proto), outer_tag->vlan_id);
__vlan_hwaccel_put_tag(skb, outer_tag->vlan_proto,
outer_tag->vlan_id);
}
@@ -2465,7 +2463,8 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
int i;
for (i = 0; i < BOND_MAX_ARP_TARGETS && targets[i]; i++) {
- netdev_dbg(bond->dev, "basa: target %pI4\n", &targets[i]);
+ slave_dbg(bond->dev, slave->dev, "%s: target %pI4\n",
+ __func__, &targets[i]);
tags = NULL;
/* Find out through which dev should the packet go */
@@ -2479,7 +2478,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
net_warn_ratelimited("%s: no route to arp_ip_target %pI4 and arp_validate is set\n",
bond->dev->name,
&targets[i]);
- bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
+ bond_arp_send(slave, ARPOP_REQUEST, targets[i],
0, tags);
continue;
}
@@ -2496,7 +2495,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
goto found;
/* Not our device - skip */
- netdev_dbg(bond->dev, "no path to arp_ip_target %pI4 via rt.dev %s\n",
+ slave_dbg(bond->dev, slave->dev, "no path to arp_ip_target %pI4 via rt.dev %s\n",
&targets[i], rt->dst.dev ? rt->dst.dev->name : "NULL");
ip_rt_put(rt);
@@ -2505,8 +2504,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
found:
addr = bond_confirm_addr(rt->dst.dev, targets[i], 0);
ip_rt_put(rt);
- bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
- addr, tags);
+ bond_arp_send(slave, ARPOP_REQUEST, targets[i], addr, tags);
kfree(tags);
}
}
@@ -2516,15 +2514,15 @@ static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32
int i;
if (!sip || !bond_has_this_ip(bond, tip)) {
- netdev_dbg(bond->dev, "bva: sip %pI4 tip %pI4 not found\n",
- &sip, &tip);
+ slave_dbg(bond->dev, slave->dev, "%s: sip %pI4 tip %pI4 not found\n",
+ __func__, &sip, &tip);
return;
}
i = bond_get_targets_ip(bond->params.arp_targets, sip);
if (i == -1) {
- netdev_dbg(bond->dev, "bva: sip %pI4 not found in targets\n",
- &sip);
+ slave_dbg(bond->dev, slave->dev, "%s: sip %pI4 not found in targets\n",
+ __func__, &sip);
return;
}
slave->last_rx = jiffies;
@@ -2552,8 +2550,8 @@ int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond,
alen = arp_hdr_len(bond->dev);
- netdev_dbg(bond->dev, "bond_arp_rcv: skb->dev %s\n",
- skb->dev->name);
+ slave_dbg(bond->dev, slave->dev, "%s: skb->dev %s\n",
+ __func__, skb->dev->name);
if (alen > skb_headlen(skb)) {
arp = kmalloc(alen, GFP_ATOMIC);
@@ -2577,10 +2575,10 @@ int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond,
arp_ptr += 4 + bond->dev->addr_len;
memcpy(&tip, arp_ptr, 4);
- netdev_dbg(bond->dev, "bond_arp_rcv: %s/%d av %d sv %d sip %pI4 tip %pI4\n",
- slave->dev->name, bond_slave_state(slave),
- bond->params.arp_validate, slave_do_arp_validate(bond, slave),
- &sip, &tip);
+ slave_dbg(bond->dev, slave->dev, "%s: %s/%d av %d sv %d sip %pI4 tip %pI4\n",
+ __func__, slave->dev->name, bond_slave_state(slave),
+ bond->params.arp_validate, slave_do_arp_validate(bond, slave),
+ &sip, &tip);
curr_active_slave = rcu_dereference(bond->curr_active_slave);
curr_arp_slave = rcu_dereference(bond->current_arp_slave);
@@ -2683,12 +2681,10 @@ static void bond_loadbalance_arp_mon(struct bonding *bond)
* is closed.
*/
if (!oldcurrent) {
- netdev_info(bond->dev, "link status definitely up for interface %s\n",
- slave->dev->name);
+ slave_info(bond->dev, slave->dev, "link status definitely up\n");
do_failover = 1;
} else {
- netdev_info(bond->dev, "interface %s is now up\n",
- slave->dev->name);
+ slave_info(bond->dev, slave->dev, "interface is now up\n");
}
}
} else {
@@ -2707,8 +2703,7 @@ static void bond_loadbalance_arp_mon(struct bonding *bond)
if (slave->link_failure_count < UINT_MAX)
slave->link_failure_count++;
- netdev_info(bond->dev, "interface %s is now down\n",
- slave->dev->name);
+ slave_info(bond->dev, slave->dev, "interface is now down\n");
if (slave == oldcurrent)
do_failover = 1;
@@ -2858,8 +2853,7 @@ static void bond_ab_arp_commit(struct bonding *bond)
RCU_INIT_POINTER(bond->current_arp_slave, NULL);
}
- netdev_info(bond->dev, "link status definitely up for interface %s\n",
- slave->dev->name);
+ slave_info(bond->dev, slave->dev, "link status definitely up\n");
if (!rtnl_dereference(bond->curr_active_slave) ||
slave == rtnl_dereference(bond->primary_slave))
@@ -2878,8 +2872,7 @@ static void bond_ab_arp_commit(struct bonding *bond)
bond_set_slave_inactive_flags(slave,
BOND_SLAVE_NOTIFY_NOW);
- netdev_info(bond->dev, "link status definitely down for interface %s, disabling it\n",
- slave->dev->name);
+ slave_info(bond->dev, slave->dev, "link status definitely down, disabling slave\n");
if (slave == rtnl_dereference(bond->curr_active_slave)) {
RCU_INIT_POINTER(bond->current_arp_slave, NULL);
@@ -2889,8 +2882,8 @@ static void bond_ab_arp_commit(struct bonding *bond)
continue;
default:
- netdev_err(bond->dev, "impossible: new_link %d on slave %s\n",
- slave->new_link, slave->dev->name);
+ slave_err(bond->dev, slave->dev, "impossible: new_link %d on slave\n",
+ slave->new_link);
continue;
}
@@ -2961,8 +2954,7 @@ static bool bond_ab_arp_probe(struct bonding *bond)
bond_set_slave_inactive_flags(slave,
BOND_SLAVE_NOTIFY_LATER);
- netdev_info(bond->dev, "backup interface %s is now down\n",
- slave->dev->name);
+ slave_info(bond->dev, slave->dev, "backup interface is now down\n");
}
if (slave == curr_arp_slave)
found = true;
@@ -3074,6 +3066,8 @@ static int bond_master_netdev_event(unsigned long event,
{
struct bonding *event_bond = netdev_priv(bond_dev);
+ netdev_dbg(bond_dev, "%s called\n", __func__);
+
switch (event) {
case NETDEV_CHANGENAME:
return bond_event_changename(event_bond);
@@ -3083,10 +3077,6 @@ static int bond_master_netdev_event(unsigned long event,
case NETDEV_REGISTER:
bond_create_proc_entry(event_bond);
break;
- case NETDEV_NOTIFY_PEERS:
- if (event_bond->send_peer_notif)
- event_bond->send_peer_notif--;
- break;
default:
break;
}
@@ -3105,12 +3095,17 @@ static int bond_slave_netdev_event(unsigned long event,
* before netdev_rx_handler_register is called in which case
* slave will be NULL
*/
- if (!slave)
+ if (!slave) {
+ netdev_dbg(slave_dev, "%s called on NULL slave\n", __func__);
return NOTIFY_DONE;
+ }
+
bond_dev = slave->bond->dev;
bond = slave->bond;
primary = rtnl_dereference(bond->primary_slave);
+ slave_dbg(bond_dev, slave_dev, "%s called\n", __func__);
+
switch (event) {
case NETDEV_UNREGISTER:
if (bond_dev->type != ARPHRD_ETHER)
@@ -3212,7 +3207,8 @@ static int bond_netdev_event(struct notifier_block *this,
{
struct net_device *event_dev = netdev_notifier_info_to_dev(ptr);
- netdev_dbg(event_dev, "event: %lx\n", event);
+ netdev_dbg(event_dev, "%s received %s\n",
+ __func__, netdev_cmd_to_name(event));
if (!(event_dev->priv_flags & IFF_BONDING))
return NOTIFY_DONE;
@@ -3220,16 +3216,13 @@ static int bond_netdev_event(struct notifier_block *this,
if (event_dev->flags & IFF_MASTER) {
int ret;
- netdev_dbg(event_dev, "IFF_MASTER\n");
ret = bond_master_netdev_event(event, event_dev);
if (ret != NOTIFY_DONE)
return ret;
}
- if (event_dev->flags & IFF_SLAVE) {
- netdev_dbg(event_dev, "IFF_SLAVE\n");
+ if (event_dev->flags & IFF_SLAVE)
return bond_slave_netdev_event(event, event_dev);
- }
return NOTIFY_DONE;
}
@@ -3546,12 +3539,11 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
slave_dev = __dev_get_by_name(net, ifr->ifr_slave);
- netdev_dbg(bond_dev, "slave_dev=%p:\n", slave_dev);
+ slave_dbg(bond_dev, slave_dev, "slave_dev=%p:\n", slave_dev);
if (!slave_dev)
return -ENODEV;
- netdev_dbg(bond_dev, "slave_dev->name=%s:\n", slave_dev->name);
switch (cmd) {
case BOND_ENSLAVE_OLD:
case SIOCBONDENSLAVE:
@@ -3676,7 +3668,7 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)
netdev_dbg(bond_dev, "bond=%p, new_mtu=%d\n", bond, new_mtu);
bond_for_each_slave(bond, slave, iter) {
- netdev_dbg(bond_dev, "s %p c_m %p\n",
+ slave_dbg(bond_dev, slave->dev, "s %p c_m %p\n",
slave, slave->dev->netdev_ops->ndo_change_mtu);
res = dev_set_mtu(slave->dev, new_mtu);
@@ -3690,8 +3682,8 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)
* means changing their mtu from timer context, which
* is probably not a good idea.
*/
- netdev_dbg(bond_dev, "err %d %s\n", res,
- slave->dev->name);
+ slave_dbg(bond_dev, slave->dev, "err %d setting mtu to %d\n",
+ res, new_mtu);
goto unwind;
}
}
@@ -3709,10 +3701,9 @@ unwind:
break;
tmp_res = dev_set_mtu(rollback_slave->dev, bond_dev->mtu);
- if (tmp_res) {
- netdev_dbg(bond_dev, "unwind err %d dev %s\n",
- tmp_res, rollback_slave->dev->name);
- }
+ if (tmp_res)
+ slave_dbg(bond_dev, rollback_slave->dev, "unwind err %d\n",
+ tmp_res);
}
return res;
@@ -3736,7 +3727,7 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
return bond_alb_set_mac_address(bond_dev, addr);
- netdev_dbg(bond_dev, "bond=%p\n", bond);
+ netdev_dbg(bond_dev, "%s: bond=%p\n", __func__, bond);
/* If fail_over_mac is enabled, do nothing and return success.
* Returning an error causes ifenslave to fail.
@@ -3749,7 +3740,8 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
return -EADDRNOTAVAIL;
bond_for_each_slave(bond, slave, iter) {
- netdev_dbg(bond_dev, "slave %p %s\n", slave, slave->dev->name);
+ slave_dbg(bond_dev, slave->dev, "%s: slave=%p\n",
+ __func__, slave);
res = dev_set_mac_address(slave->dev, addr, NULL);
if (res) {
/* TODO: consider downing the slave
@@ -3758,7 +3750,8 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
* breakage anyway until ARP finish
* updating, so...
*/
- netdev_dbg(bond_dev, "err %d %s\n", res, slave->dev->name);
+ slave_dbg(bond_dev, slave->dev, "%s: err %d\n",
+ __func__, res);
goto unwind;
}
}
@@ -3781,8 +3774,8 @@ unwind:
tmp_res = dev_set_mac_address(rollback_slave->dev,
(struct sockaddr *)&tmp_ss, NULL);
if (tmp_res) {
- netdev_dbg(bond_dev, "unwind err %d dev %s\n",
- tmp_res, rollback_slave->dev->name);
+ slave_dbg(bond_dev, rollback_slave->dev, "%s: unwind err %d\n",
+ __func__, tmp_res);
}
}
@@ -3866,8 +3859,8 @@ static netdev_tx_t bond_xmit_roundrobin(struct sk_buff *skb,
struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
- struct iphdr *iph = ip_hdr(skb);
struct slave *slave;
+ int slave_cnt;
u32 slave_id;
/* Start with the curr_active_slave that joined the bond as the
@@ -3876,23 +3869,32 @@ static netdev_tx_t bond_xmit_roundrobin(struct sk_buff *skb,
* send the join/membership reports. The curr_active_slave found
* will send all of this type of traffic.
*/
- if (iph->protocol == IPPROTO_IGMP && skb->protocol == htons(ETH_P_IP)) {
- slave = rcu_dereference(bond->curr_active_slave);
- if (slave)
- bond_dev_queue_xmit(bond, skb, slave->dev);
- else
- bond_xmit_slave_id(bond, skb, 0);
- } else {
- int slave_cnt = READ_ONCE(bond->slave_cnt);
+ if (skb->protocol == htons(ETH_P_IP)) {
+ int noff = skb_network_offset(skb);
+ struct iphdr *iph;
- if (likely(slave_cnt)) {
- slave_id = bond_rr_gen_slave_id(bond);
- bond_xmit_slave_id(bond, skb, slave_id % slave_cnt);
- } else {
- bond_tx_drop(bond_dev, skb);
+ if (unlikely(!pskb_may_pull(skb, noff + sizeof(*iph))))
+ goto non_igmp;
+
+ iph = ip_hdr(skb);
+ if (iph->protocol == IPPROTO_IGMP) {
+ slave = rcu_dereference(bond->curr_active_slave);
+ if (slave)
+ bond_dev_queue_xmit(bond, skb, slave->dev);
+ else
+ bond_xmit_slave_id(bond, skb, 0);
+ return NETDEV_TX_OK;
}
}
+non_igmp:
+ slave_cnt = READ_ONCE(bond->slave_cnt);
+ if (likely(slave_cnt)) {
+ slave_id = bond_rr_gen_slave_id(bond);
+ bond_xmit_slave_id(bond, skb, slave_id % slave_cnt);
+ } else {
+ bond_tx_drop(bond_dev, skb);
+ }
return NETDEV_TX_OK;
}
@@ -4003,9 +4005,8 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave)
if (skipslave == slave)
continue;
- netdev_dbg(bond->dev,
- "Adding slave dev %s to tx hash array[%d]\n",
- slave->dev->name, new_arr->count);
+ slave_dbg(bond->dev, slave->dev, "Adding slave to tx hash array[%d]\n",
+ new_arr->count);
new_arr->arr[new_arr->count++] = slave;
}
@@ -4320,12 +4321,12 @@ void bond_setup(struct net_device *bond_dev)
bond_dev->features |= NETIF_F_NETNS_LOCAL;
bond_dev->hw_features = BOND_VLAN_FEATURES |
- NETIF_F_HW_VLAN_CTAG_TX |
NETIF_F_HW_VLAN_CTAG_RX |
NETIF_F_HW_VLAN_CTAG_FILTER;
bond_dev->hw_features |= NETIF_F_GSO_ENCAP_ALL | NETIF_F_GSO_UDP_L4;
bond_dev->features |= bond_dev->hw_features;
+ bond_dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX;
}
/* Destroy a bonding device.
@@ -4707,6 +4708,7 @@ static int bond_check_params(struct bond_params *params)
params->arp_all_targets = arp_all_targets_value;
params->updelay = updelay;
params->downdelay = downdelay;
+ params->peer_notif_delay = 0;
params->use_carrier = use_carrier;
params->lacp_fast = lacp_fast;
params->primary[0] = 0;
diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c
index b24cce48ae35..b43b51646b11 100644
--- a/drivers/net/bonding/bond_netlink.c
+++ b/drivers/net/bonding/bond_netlink.c
@@ -108,6 +108,7 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = {
[IFLA_BOND_AD_ACTOR_SYSTEM] = { .type = NLA_BINARY,
.len = ETH_ALEN },
[IFLA_BOND_TLB_DYNAMIC_LB] = { .type = NLA_U8 },
+ [IFLA_BOND_PEER_NOTIF_DELAY] = { .type = NLA_U32 },
};
static const struct nla_policy bond_slave_policy[IFLA_BOND_SLAVE_MAX + 1] = {
@@ -215,6 +216,14 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
if (err)
return err;
}
+ if (data[IFLA_BOND_PEER_NOTIF_DELAY]) {
+ int delay = nla_get_u32(data[IFLA_BOND_PEER_NOTIF_DELAY]);
+
+ bond_opt_initval(&newval, delay);
+ err = __bond_opt_set(bond, BOND_OPT_PEER_NOTIF_DELAY, &newval);
+ if (err)
+ return err;
+ }
if (data[IFLA_BOND_USE_CARRIER]) {
int use_carrier = nla_get_u8(data[IFLA_BOND_USE_CARRIER]);
@@ -494,6 +503,7 @@ static size_t bond_get_size(const struct net_device *bond_dev)
nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_USER_PORT_KEY */
nla_total_size(ETH_ALEN) + /* IFLA_BOND_AD_ACTOR_SYSTEM */
nla_total_size(sizeof(u8)) + /* IFLA_BOND_TLB_DYNAMIC_LB */
+ nla_total_size(sizeof(u32)) + /* IFLA_BOND_PEER_NOTIF_DELAY */
0;
}
@@ -536,6 +546,10 @@ static int bond_fill_info(struct sk_buff *skb,
bond->params.downdelay * bond->params.miimon))
goto nla_put_failure;
+ if (nla_put_u32(skb, IFLA_BOND_PEER_NOTIF_DELAY,
+ bond->params.peer_notif_delay * bond->params.miimon))
+ goto nla_put_failure;
+
if (nla_put_u8(skb, IFLA_BOND_USE_CARRIER, bond->params.use_carrier))
goto nla_put_failure;
diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
index 9677418e0362..ddb3916d3506 100644
--- a/drivers/net/bonding/bond_options.c
+++ b/drivers/net/bonding/bond_options.c
@@ -24,6 +24,8 @@ static int bond_option_updelay_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_downdelay_set(struct bonding *bond,
const struct bond_opt_value *newval);
+static int bond_option_peer_notif_delay_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
static int bond_option_use_carrier_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_arp_interval_set(struct bonding *bond,
@@ -424,6 +426,13 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = {
.desc = "Number of peer notifications to send on failover event",
.values = bond_num_peer_notif_tbl,
.set = bond_option_num_peer_notif_set
+ },
+ [BOND_OPT_PEER_NOTIF_DELAY] = {
+ .id = BOND_OPT_PEER_NOTIF_DELAY,
+ .name = "peer_notif_delay",
+ .desc = "Delay between each peer notification on failover event, in milliseconds",
+ .values = bond_intmax_tbl,
+ .set = bond_option_peer_notif_delay_set
}
};
@@ -783,14 +792,12 @@ static int bond_option_active_slave_set(struct bonding *bond,
if (slave_dev) {
if (!netif_is_bond_slave(slave_dev)) {
- netdev_err(bond->dev, "Device %s is not bonding slave\n",
- slave_dev->name);
+ slave_err(bond->dev, slave_dev, "Device is not bonding slave\n");
return -EINVAL;
}
if (bond->dev != netdev_master_upper_dev_get(slave_dev)) {
- netdev_err(bond->dev, "Device %s is not our slave\n",
- slave_dev->name);
+ slave_err(bond->dev, slave_dev, "Device is not our slave\n");
return -EINVAL;
}
}
@@ -809,18 +816,15 @@ static int bond_option_active_slave_set(struct bonding *bond,
if (new_active == old_active) {
/* do nothing */
- netdev_dbg(bond->dev, "%s is already the current active slave\n",
- new_active->dev->name);
+ slave_dbg(bond->dev, new_active->dev, "is already the current active slave\n");
} else {
if (old_active && (new_active->link == BOND_LINK_UP) &&
bond_slave_is_up(new_active)) {
- netdev_dbg(bond->dev, "Setting %s as active slave\n",
- new_active->dev->name);
+ slave_dbg(bond->dev, new_active->dev, "Setting as active slave\n");
bond_change_active_slave(bond, new_active);
} else {
- netdev_err(bond->dev, "Could not set %s as active slave; either %s is down or the link is down\n",
- new_active->dev->name,
- new_active->dev->name);
+ slave_err(bond->dev, new_active->dev, "Could not set as active slave; either %s is down or the link is down\n",
+ new_active->dev->name);
ret = -EINVAL;
}
}
@@ -846,6 +850,9 @@ static int bond_option_miimon_set(struct bonding *bond,
if (bond->params.downdelay)
netdev_dbg(bond->dev, "Note: Updating downdelay (to %d) since it is a multiple of the miimon value\n",
bond->params.downdelay * bond->params.miimon);
+ if (bond->params.peer_notif_delay)
+ netdev_dbg(bond->dev, "Note: Updating peer_notif_delay (to %d) since it is a multiple of the miimon value\n",
+ bond->params.peer_notif_delay * bond->params.miimon);
if (newval->value && bond->params.arp_interval) {
netdev_dbg(bond->dev, "MII monitoring cannot be used with ARP monitoring - disabling ARP monitoring...\n");
bond->params.arp_interval = 0;
@@ -869,52 +876,59 @@ static int bond_option_miimon_set(struct bonding *bond,
return 0;
}
-/* Set up and down delays. These must be multiples of the
- * MII monitoring value, and are stored internally as the multiplier.
- * Thus, we must translate to MS for the real world.
+/* Set up, down and peer notification delays. These must be multiples
+ * of the MII monitoring value, and are stored internally as the
+ * multiplier. Thus, we must translate to MS for the real world.
*/
-static int bond_option_updelay_set(struct bonding *bond,
- const struct bond_opt_value *newval)
+static int _bond_option_delay_set(struct bonding *bond,
+ const struct bond_opt_value *newval,
+ const char *name,
+ int *target)
{
int value = newval->value;
if (!bond->params.miimon) {
- netdev_err(bond->dev, "Unable to set up delay as MII monitoring is disabled\n");
+ netdev_err(bond->dev, "Unable to set %s as MII monitoring is disabled\n",
+ name);
return -EPERM;
}
if ((value % bond->params.miimon) != 0) {
- netdev_warn(bond->dev, "up delay (%d) is not a multiple of miimon (%d), updelay rounded to %d ms\n",
+ netdev_warn(bond->dev,
+ "%s (%d) is not a multiple of miimon (%d), value rounded to %d ms\n",
+ name,
value, bond->params.miimon,
(value / bond->params.miimon) *
bond->params.miimon);
}
- bond->params.updelay = value / bond->params.miimon;
- netdev_dbg(bond->dev, "Setting up delay to %d\n",
- bond->params.updelay * bond->params.miimon);
+ *target = value / bond->params.miimon;
+ netdev_dbg(bond->dev, "Setting %s to %d\n",
+ name,
+ *target * bond->params.miimon);
return 0;
}
+static int bond_option_updelay_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
+{
+ return _bond_option_delay_set(bond, newval, "up delay",
+ &bond->params.updelay);
+}
+
static int bond_option_downdelay_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
- int value = newval->value;
-
- if (!bond->params.miimon) {
- netdev_err(bond->dev, "Unable to set down delay as MII monitoring is disabled\n");
- return -EPERM;
- }
- if ((value % bond->params.miimon) != 0) {
- netdev_warn(bond->dev, "down delay (%d) is not a multiple of miimon (%d), delay rounded to %d ms\n",
- value, bond->params.miimon,
- (value / bond->params.miimon) *
- bond->params.miimon);
- }
- bond->params.downdelay = value / bond->params.miimon;
- netdev_dbg(bond->dev, "Setting down delay to %d\n",
- bond->params.downdelay * bond->params.miimon);
+ return _bond_option_delay_set(bond, newval, "down delay",
+ &bond->params.downdelay);
+}
- return 0;
+static int bond_option_peer_notif_delay_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
+{
+ int ret = _bond_option_delay_set(bond, newval,
+ "peer notification delay",
+ &bond->params.peer_notif_delay);
+ return ret;
}
static int bond_option_use_carrier_set(struct bonding *bond,
@@ -1132,8 +1146,7 @@ static int bond_option_primary_set(struct bonding *bond,
bond_for_each_slave(bond, slave, iter) {
if (strncmp(slave->dev->name, primary, IFNAMSIZ) == 0) {
- netdev_dbg(bond->dev, "Setting %s as primary slave\n",
- slave->dev->name);
+ slave_dbg(bond->dev, slave->dev, "Setting as primary slave\n");
rcu_assign_pointer(bond->primary_slave, slave);
strcpy(bond->params.primary, slave->dev->name);
bond->force_primary = true;
@@ -1150,8 +1163,8 @@ static int bond_option_primary_set(struct bonding *bond,
strncpy(bond->params.primary, primary, IFNAMSIZ);
bond->params.primary[IFNAMSIZ - 1] = 0;
- netdev_dbg(bond->dev, "Recording %s as primary, but it has not been enslaved to %s yet\n",
- primary, bond->dev->name);
+ netdev_dbg(bond->dev, "Recording %s as primary, but it has not been enslaved yet\n",
+ primary);
out:
unblock_netpoll_tx();
@@ -1378,12 +1391,12 @@ static int bond_option_slaves_set(struct bonding *bond,
switch (command[0]) {
case '+':
- netdev_dbg(bond->dev, "Adding slave %s\n", dev->name);
+ slave_dbg(bond->dev, dev, "Enslaving interface\n");
ret = bond_enslave(bond->dev, dev, NULL);
break;
case '-':
- netdev_dbg(bond->dev, "Removing slave %s\n", dev->name);
+ slave_dbg(bond->dev, dev, "Releasing interface\n");
ret = bond_release(bond->dev, dev);
break;
@@ -1447,7 +1460,7 @@ static int bond_option_ad_actor_system_set(struct bonding *bond,
return 0;
err:
- netdev_err(bond->dev, "Invalid MAC address.\n");
+ netdev_err(bond->dev, "Invalid ad_actor_system MAC address.\n");
return -EINVAL;
}
diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c
index 9f7d83e827c3..fd5c9cbe45b1 100644
--- a/drivers/net/bonding/bond_procfs.c
+++ b/drivers/net/bonding/bond_procfs.c
@@ -104,6 +104,8 @@ static void bond_info_show_master(struct seq_file *seq)
bond->params.updelay * bond->params.miimon);
seq_printf(seq, "Down Delay (ms): %d\n",
bond->params.downdelay * bond->params.miimon);
+ seq_printf(seq, "Peer Notification Delay (ms): %d\n",
+ bond->params.peer_notif_delay * bond->params.miimon);
/* ARP information */
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 94214eaf53c5..2d615a93685e 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -327,6 +327,18 @@ static ssize_t bonding_show_updelay(struct device *d,
static DEVICE_ATTR(updelay, 0644,
bonding_show_updelay, bonding_sysfs_store_option);
+static ssize_t bonding_show_peer_notif_delay(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct bonding *bond = to_bond(d);
+
+ return sprintf(buf, "%d\n",
+ bond->params.peer_notif_delay * bond->params.miimon);
+}
+static DEVICE_ATTR(peer_notif_delay, 0644,
+ bonding_show_peer_notif_delay, bonding_sysfs_store_option);
+
/* Show the LACP interval. */
static ssize_t bonding_show_lacp(struct device *d,
struct device_attribute *attr,
@@ -718,6 +730,7 @@ static struct attribute *per_bond_attrs[] = {
&dev_attr_arp_ip_target.attr,
&dev_attr_downdelay.attr,
&dev_attr_updelay.attr,
+ &dev_attr_peer_notif_delay.attr,
&dev_attr_lacp_rate.attr,
&dev_attr_ad_select.attr,
&dev_attr_xmit_hash_policy.attr,
diff --git a/drivers/net/caif/caif_hsi.c b/drivers/net/caif/caif_hsi.c
index b2f10b6ad6e5..bbb2575d4728 100644
--- a/drivers/net/caif/caif_hsi.c
+++ b/drivers/net/caif/caif_hsi.c
@@ -1455,7 +1455,7 @@ static void __exit cfhsi_exit_module(void)
rtnl_lock();
list_for_each_safe(list_node, n, &cfhsi_list) {
cfhsi = list_entry(list_node, struct cfhsi, list);
- unregister_netdev(cfhsi->ndev);
+ unregister_netdevice(cfhsi->ndev);
}
rtnl_unlock();
}
diff --git a/drivers/net/can/cc770/cc770.c b/drivers/net/can/cc770/cc770.c
index da636a22c542..7cdc232cbfea 100644
--- a/drivers/net/can/cc770/cc770.c
+++ b/drivers/net/can/cc770/cc770.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Core driver for the CC770 and AN82527 CAN controllers
*
* Copyright (C) 2009, 2011 Wolfgang Grandegger <wg@grandegger.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the version 2 of the GNU General Public License
- * as published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/net/can/cc770/cc770.h b/drivers/net/can/cc770/cc770.h
index 95752e1d1283..948541491ab5 100644
--- a/drivers/net/can/cc770/cc770.h
+++ b/drivers/net/can/cc770/cc770.h
@@ -1,16 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Core driver for the CC770 and AN82527 CAN controllers
*
* Copyright (C) 2009, 2011 Wolfgang Grandegger <wg@grandegger.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the version 2 of the GNU General Public License
- * as published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#ifndef CC770_DEV_H
diff --git a/drivers/net/can/cc770/cc770_isa.c b/drivers/net/can/cc770/cc770_isa.c
index fcd34698074f..b9047d8110d5 100644
--- a/drivers/net/can/cc770/cc770_isa.c
+++ b/drivers/net/can/cc770/cc770_isa.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for CC770 and AN82527 CAN controllers on the legacy ISA bus
*
* Copyright (C) 2009, 2011 Wolfgang Grandegger <wg@grandegger.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the version 2 of the GNU General Public License
- * as published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
/*
diff --git a/drivers/net/can/cc770/cc770_platform.c b/drivers/net/can/cc770/cc770_platform.c
index 866e5e12fdd2..8d916e2ee6c2 100644
--- a/drivers/net/can/cc770/cc770_platform.c
+++ b/drivers/net/can/cc770/cc770_platform.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for CC770 and AN82527 CAN controllers on the platform bus
*
* Copyright (C) 2009, 2011 Wolfgang Grandegger <wg@grandegger.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the version 2 of the GNU General Public License
- * as published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
/*
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index 1c66fb2ad76b..f2fe344593d5 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -166,7 +166,7 @@
#define FLEXCAN_MB_CNT_LENGTH(x) (((x) & 0xf) << 16)
#define FLEXCAN_MB_CNT_TIMESTAMP(x) ((x) & 0xffff)
-#define FLEXCAN_TIMEOUT_US (50)
+#define FLEXCAN_TIMEOUT_US (250)
/* FLEXCAN hardware feature flags
*
@@ -1583,9 +1583,6 @@ static int flexcan_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "failed to setup stop-mode\n");
}
- dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n",
- priv->regs, dev->irq);
-
return 0;
failed_register:
diff --git a/drivers/net/can/led.c b/drivers/net/can/led.c
index c1b667675fa1..db14897f8e16 100644
--- a/drivers/net/can/led.c
+++ b/drivers/net/can/led.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2012, Fabio Baltieri <fabio.baltieri@gmail.com>
* Copyright 2012, Kurt Van Dijck <kurt.van.dijck@eia.be>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c
index 9b449400376b..deb274a19ba0 100644
--- a/drivers/net/can/m_can/m_can.c
+++ b/drivers/net/can/m_can/m_can.c
@@ -822,6 +822,27 @@ static int m_can_poll(struct napi_struct *napi, int quota)
if (!irqstatus)
goto end;
+ /* Errata workaround for issue "Needless activation of MRAF irq"
+ * During frame reception while the MCAN is in Error Passive state
+ * and the Receive Error Counter has the value MCAN_ECR.REC = 127,
+ * it may happen that MCAN_IR.MRAF is set although there was no
+ * Message RAM access failure.
+ * If MCAN_IR.MRAF is enabled, an interrupt to the Host CPU is generated
+ * The Message RAM Access Failure interrupt routine needs to check
+ * whether MCAN_ECR.RP = ’1’ and MCAN_ECR.REC = 127.
+ * In this case, reset MCAN_IR.MRAF. No further action is required.
+ */
+ if ((priv->version <= 31) && (irqstatus & IR_MRAF) &&
+ (m_can_read(priv, M_CAN_ECR) & ECR_RP)) {
+ struct can_berr_counter bec;
+
+ __m_can_get_berr_counter(dev, &bec);
+ if (bec.rxerr == 127) {
+ m_can_write(priv, M_CAN_IR, IR_MRAF);
+ irqstatus &= ~IR_MRAF;
+ }
+ }
+
psr = m_can_read(priv, M_CAN_PSR);
if (irqstatus & IR_ERR_STATE)
work_done += m_can_handle_state_errors(dev, psr);
diff --git a/drivers/net/can/peak_canfd/peak_canfd.c b/drivers/net/can/peak_canfd/peak_canfd.c
index 5696d7e80751..6b0c6a99fc8d 100644
--- a/drivers/net/can/peak_canfd/peak_canfd.c
+++ b/drivers/net/can/peak_canfd/peak_canfd.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2007, 2011 Wolfgang Grandegger <wg@grandegger.com>
* Copyright (C) 2012 Stephane Grosjean <s.grosjean@peak-system.com>
*
* Copyright (C) 2016 PEAK System-Technik GmbH
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the version 2 of the GNU General Public License
- * as published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/can.h>
diff --git a/drivers/net/can/peak_canfd/peak_pciefd_main.c b/drivers/net/can/peak_canfd/peak_pciefd_main.c
index c458d5fdc8d3..7f6a3b971da9 100644
--- a/drivers/net/can/peak_canfd/peak_pciefd_main.c
+++ b/drivers/net/can/peak_canfd/peak_pciefd_main.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2007, 2011 Wolfgang Grandegger <wg@grandegger.com>
* Copyright (C) 2012 Stephane Grosjean <s.grosjean@peak-system.com>
@@ -5,15 +6,6 @@
* Derived from the PCAN project file driver/src/pcan_pci.c:
*
* Copyright (C) 2001-2006 PEAK System-Technik GmbH
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the version 2 of the GNU General Public License
- * as published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/kernel.h>
diff --git a/drivers/net/can/sja1000/ems_pcmcia.c b/drivers/net/can/sja1000/ems_pcmcia.c
index 381de998d2f1..770304eaef95 100644
--- a/drivers/net/can/sja1000/ems_pcmcia.c
+++ b/drivers/net/can/sja1000/ems_pcmcia.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2008 Sebastian Haas (initial chardev implementation)
* Copyright (C) 2010 Markus Plessing <plessing@ems-wuensche.com>
* Rework for mainline by Oliver Hartkopp <socketcan@hartkopp.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the version 2 of the GNU General Public License
- * as published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/kernel.h>
diff --git a/drivers/net/can/sja1000/peak_pci.c b/drivers/net/can/sja1000/peak_pci.c
index a97b81d1d0da..68366d57916c 100644
--- a/drivers/net/can/sja1000/peak_pci.c
+++ b/drivers/net/can/sja1000/peak_pci.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2007, 2011 Wolfgang Grandegger <wg@grandegger.com>
* Copyright (C) 2012 Stephane Grosjean <s.grosjean@peak-system.com>
@@ -5,15 +6,6 @@
* Derived from the PCAN project file driver/src/pcan_pci.c:
*
* Copyright (C) 2001-2006 PEAK System-Technik GmbH
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the version 2 of the GNU General Public License
- * as published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/kernel.h>
diff --git a/drivers/net/can/sja1000/peak_pcmcia.c b/drivers/net/can/sja1000/peak_pcmcia.c
index b8c39ede7cd5..185c7f7d38a4 100644
--- a/drivers/net/can/sja1000/peak_pcmcia.c
+++ b/drivers/net/can/sja1000/peak_pcmcia.c
@@ -1,18 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2010-2012 Stephane Grosjean <s.grosjean@peak-system.com>
*
* CAN driver for PEAK-System PCAN-PC Card
* Derived from the PCAN project file driver/src/pcan_pccard.c
* Copyright (C) 2006-2010 PEAK System-Technik GmbH
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the version 2 of the GNU General Public License
- * as published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/net/can/softing/softing_main.c b/drivers/net/can/softing/softing_main.c
index 68bb58a57f3b..8242fb287cbb 100644
--- a/drivers/net/can/softing/softing_main.c
+++ b/drivers/net/can/softing/softing_main.c
@@ -683,7 +683,7 @@ static void softing_netdev_cleanup(struct net_device *netdev)
static ssize_t show_##name(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
- struct softing *card = platform_get_drvdata(to_platform_device(dev)); \
+ struct softing *card = dev_get_drvdata(dev); \
return sprintf(buf, "%u\n", card->member); \
} \
static DEVICE_ATTR(name, 0444, show_##name, NULL)
@@ -692,7 +692,7 @@ static DEVICE_ATTR(name, 0444, show_##name, NULL)
static ssize_t show_##name(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
- struct softing *card = platform_get_drvdata(to_platform_device(dev)); \
+ struct softing *card = dev_get_drvdata(dev); \
return sprintf(buf, "%s\n", card->member); \
} \
static DEVICE_ATTR(name, 0444, show_##name, NULL)
diff --git a/drivers/net/can/spi/Kconfig b/drivers/net/can/spi/Kconfig
index 2e7e535e9237..1c50788055cb 100644
--- a/drivers/net/can/spi/Kconfig
+++ b/drivers/net/can/spi/Kconfig
@@ -9,9 +9,10 @@ config CAN_HI311X
Driver for the Holt HI311x SPI CAN controllers.
config CAN_MCP251X
- tristate "Microchip MCP251x SPI CAN controllers"
+ tristate "Microchip MCP251x and MCP25625 SPI CAN controllers"
depends on HAS_DMA
---help---
- Driver for the Microchip MCP251x SPI CAN controllers.
+ Driver for the Microchip MCP251x and MCP25625 SPI CAN
+ controllers.
endmenu
diff --git a/drivers/net/can/spi/hi311x.c b/drivers/net/can/spi/hi311x.c
index ddaf46239e39..03a711c3221b 100644
--- a/drivers/net/can/spi/hi311x.c
+++ b/drivers/net/can/spi/hi311x.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* CAN bus driver for Holt HI3110 CAN Controller with SPI Interface
*
* Copyright(C) Timesys Corporation 2016
@@ -11,10 +12,6 @@
* - Sascha Hauer, Marc Kleine-Budde, Pengutronix
* - Simon Kallweit, intefo AG
* Copyright 2007
- *
- * 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.
*/
#include <linux/can/core.h>
diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c
index 78e29fa06fe6..44e99e3d7134 100644
--- a/drivers/net/can/spi/mcp251x.c
+++ b/drivers/net/can/spi/mcp251x.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * CAN bus driver for Microchip 251x CAN Controller with SPI Interface
+ * CAN bus driver for Microchip 251x/25625 CAN Controller with SPI Interface
*
* MCP2510 support and bug fixes by Christian Pellegrin
* <chripell@evolware.org>
@@ -28,7 +28,7 @@
* static struct spi_board_info spi_board_info[] = {
* {
* .modalias = "mcp2510",
- * // or "mcp2515" depending on your controller
+ * // "mcp2515" or "mcp25625" depending on your controller
* .platform_data = &mcp251x_info,
* .irq = IRQ_EINT13,
* .max_speed_hz = 2*1000*1000,
@@ -224,6 +224,7 @@ static const struct can_bittiming_const mcp251x_bittiming_const = {
enum mcp251x_model {
CAN_MCP251X_MCP2510 = 0x2510,
CAN_MCP251X_MCP2515 = 0x2515,
+ CAN_MCP251X_MCP25625 = 0x25625,
};
struct mcp251x_priv {
@@ -266,7 +267,6 @@ static inline int mcp251x_is_##_model(struct spi_device *spi) \
}
MCP251X_IS(2510);
-MCP251X_IS(2515);
static void mcp251x_clean(struct net_device *net)
{
@@ -625,7 +625,7 @@ static int mcp251x_hw_reset(struct spi_device *spi)
/* Wait for oscillator startup timer after reset */
mdelay(MCP251X_OST_DELAY_MS);
-
+
reg = mcp251x_read_reg(spi, CANSTAT);
if ((reg & CANCTRL_REQOP_MASK) != CANCTRL_REQOP_CONF)
return -ENODEV;
@@ -806,9 +806,8 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
/* receive buffer 0 */
if (intf & CANINTF_RX0IF) {
mcp251x_hw_rx(spi, 0);
- /*
- * Free one buffer ASAP
- * (The MCP2515 does this automatically.)
+ /* Free one buffer ASAP
+ * (The MCP2515/25625 does this automatically.)
*/
if (mcp251x_is_2510(spi))
mcp251x_write_bits(spi, CANINTF, CANINTF_RX0IF, 0x00);
@@ -817,7 +816,7 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
/* receive buffer 1 */
if (intf & CANINTF_RX1IF) {
mcp251x_hw_rx(spi, 1);
- /* the MCP2515 does this automatically */
+ /* The MCP2515/25625 does this automatically. */
if (mcp251x_is_2510(spi))
clear_intf |= CANINTF_RX1IF;
}
@@ -992,6 +991,10 @@ static const struct of_device_id mcp251x_of_match[] = {
.compatible = "microchip,mcp2515",
.data = (void *)CAN_MCP251X_MCP2515,
},
+ {
+ .compatible = "microchip,mcp25625",
+ .data = (void *)CAN_MCP251X_MCP25625,
+ },
{ }
};
MODULE_DEVICE_TABLE(of, mcp251x_of_match);
@@ -1005,6 +1008,10 @@ static const struct spi_device_id mcp251x_id_table[] = {
.name = "mcp2515",
.driver_data = (kernel_ulong_t)CAN_MCP251X_MCP2515,
},
+ {
+ .name = "mcp25625",
+ .driver_data = (kernel_ulong_t)CAN_MCP251X_MCP25625,
+ },
{ }
};
MODULE_DEVICE_TABLE(spi, mcp251x_id_table);
@@ -1245,5 +1252,5 @@ module_spi_driver(mcp251x_can_driver);
MODULE_AUTHOR("Chris Elston <celston@katalix.com>, "
"Christian Pellegrin <chripell@evolware.org>");
-MODULE_DESCRIPTION("Microchip 251x CAN driver");
+MODULE_DESCRIPTION("Microchip 251x/25625 CAN driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
index ac3522b77303..4b3d0ddcda79 100644
--- a/drivers/net/can/usb/Kconfig
+++ b/drivers/net/can/usb/Kconfig
@@ -102,12 +102,6 @@ config CAN_PEAK_USB
(see also http://www.peak-system.com).
-config CAN_MCBA_USB
- tristate "Microchip CAN BUS Analyzer interface"
- ---help---
- This driver supports the CAN BUS Analyzer interface
- from Microchip (http://www.microchip.com/development-tools/).
-
config CAN_UCAN
tristate "Theobroma Systems UCAN interface"
---help---
diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c
index f2024404b8d6..63203ff452b5 100644
--- a/drivers/net/can/xilinx_can.c
+++ b/drivers/net/can/xilinx_can.c
@@ -1435,7 +1435,7 @@ static const struct xcan_devtype_data xcan_canfd_data = {
XCAN_FLAG_RXMNF |
XCAN_FLAG_TX_MAILBOXES |
XCAN_FLAG_RX_FIFO_MULTI,
- .bittiming_const = &xcan_bittiming_const,
+ .bittiming_const = &xcan_bittiming_const_canfd,
.btr_ts2_shift = XCAN_BTR_TS2_SHIFT_CANFD,
.btr_sjw_shift = XCAN_BTR_SJW_SHIFT_CANFD,
.bus_clk_name = "s_axi_aclk",
diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig
index b91e78e3598f..f6232ce8481f 100644
--- a/drivers/net/dsa/Kconfig
+++ b/drivers/net/dsa/Kconfig
@@ -99,8 +99,8 @@ config NET_DSA_SMSC_LAN9303_MDIO
for MDIO managed mode.
config NET_DSA_VITESSE_VSC73XX
- tristate "Vitesse VSC7385/7388/7395/7398 support"
- depends on OF && SPI
+ tristate
+ depends on OF
depends on NET_DSA
select FIXED_PHY
select VITESSE_PHY
@@ -109,4 +109,24 @@ config NET_DSA_VITESSE_VSC73XX
This enables support for the Vitesse VSC7385, VSC7388,
VSC7395 and VSC7398 SparX integrated ethernet switches.
+config NET_DSA_VITESSE_VSC73XX_SPI
+ tristate "Vitesse VSC7385/7388/7395/7398 SPI mode support"
+ depends on OF
+ depends on NET_DSA
+ depends on SPI
+ select NET_DSA_VITESSE_VSC73XX
+ ---help---
+ This enables support for the Vitesse VSC7385, VSC7388, VSC7395
+ and VSC7398 SparX integrated ethernet switches in SPI managed mode.
+
+config NET_DSA_VITESSE_VSC73XX_PLATFORM
+ tristate "Vitesse VSC7385/7388/7395/7398 Platform mode support"
+ depends on OF
+ depends on NET_DSA
+ depends on HAS_IOMEM
+ select NET_DSA_VITESSE_VSC73XX
+ ---help---
+ This enables support for the Vitesse VSC7385, VSC7388, VSC7395
+ and VSC7398 SparX integrated ethernet switches, connected over
+ a CPU-attached address bus and work in memory-mapped I/O mode.
endmenu
diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile
index fefb6aaa82ba..ae70b79628d6 100644
--- a/drivers/net/dsa/Makefile
+++ b/drivers/net/dsa/Makefile
@@ -9,12 +9,14 @@ obj-$(CONFIG_NET_DSA_LANTIQ_GSWIP) += lantiq_gswip.o
obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o
obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o
obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o
-obj-$(CONFIG_NET_DSA_REALTEK_SMI) += realtek.o
-realtek-objs := realtek-smi.o rtl8366.o rtl8366rb.o
+obj-$(CONFIG_NET_DSA_REALTEK_SMI) += realtek-smi.o
+realtek-smi-objs := realtek-smi-core.o rtl8366.o rtl8366rb.o
obj-$(CONFIG_NET_DSA_SMSC_LAN9303) += lan9303-core.o
obj-$(CONFIG_NET_DSA_SMSC_LAN9303_I2C) += lan9303_i2c.o
obj-$(CONFIG_NET_DSA_SMSC_LAN9303_MDIO) += lan9303_mdio.o
-obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX) += vitesse-vsc73xx.o
+obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX) += vitesse-vsc73xx-core.o
+obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX_PLATFORM) += vitesse-vsc73xx-platform.o
+obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX_SPI) += vitesse-vsc73xx-spi.o
obj-y += b53/
obj-y += microchip/
obj-y += mv88e6xxx/
diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c
index c8040ecf4425..907af62846ba 100644
--- a/drivers/net/dsa/b53/b53_common.c
+++ b/drivers/net/dsa/b53/b53_common.c
@@ -955,13 +955,13 @@ static int b53_setup(struct dsa_switch *ds)
if (ret)
dev_err(ds->dev, "failed to apply configuration\n");
- /* Configure IMP/CPU port, disable unused ports. Enabled
+ /* Configure IMP/CPU port, disable all other ports. Enabled
* ports will be configured with .port_enable
*/
for (port = 0; port < dev->num_ports; port++) {
if (dsa_is_cpu_port(ds, port))
b53_enable_cpu_port(dev, port);
- else if (dsa_is_unused_port(ds, port))
+ else
b53_disable_port(ds, port);
}
diff --git a/drivers/net/dsa/microchip/Kconfig b/drivers/net/dsa/microchip/Kconfig
index 2c3a6751bdaf..fe0a13b79c4b 100644
--- a/drivers/net/dsa/microchip/Kconfig
+++ b/drivers/net/dsa/microchip/Kconfig
@@ -13,5 +13,6 @@ menuconfig NET_DSA_MICROCHIP_KSZ9477
config NET_DSA_MICROCHIP_KSZ9477_SPI
tristate "KSZ9477 series SPI connected switch driver"
depends on NET_DSA_MICROCHIP_KSZ9477 && SPI
+ select REGMAP_SPI
help
Select to enable support for registering switches configured through SPI.
diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c
index c026d15721f6..a8c97f7a79b7 100644
--- a/drivers/net/dsa/microchip/ksz9477.c
+++ b/drivers/net/dsa/microchip/ksz9477.c
@@ -65,51 +65,36 @@ static const struct {
{ 0x83, "tx_discards" },
};
-static void ksz9477_cfg32(struct ksz_device *dev, u32 addr, u32 bits, bool set)
+static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set)
{
- u32 data;
+ regmap_update_bits(dev->regmap[0], addr, bits, set ? bits : 0);
+}
- ksz_read32(dev, addr, &data);
- if (set)
- data |= bits;
- else
- data &= ~bits;
- ksz_write32(dev, addr, data);
+static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits,
+ bool set)
+{
+ regmap_update_bits(dev->regmap[0], PORT_CTRL_ADDR(port, offset),
+ bits, set ? bits : 0);
+}
+
+static void ksz9477_cfg32(struct ksz_device *dev, u32 addr, u32 bits, bool set)
+{
+ regmap_update_bits(dev->regmap[2], addr, bits, set ? bits : 0);
}
static void ksz9477_port_cfg32(struct ksz_device *dev, int port, int offset,
u32 bits, bool set)
{
- u32 addr;
- u32 data;
-
- addr = PORT_CTRL_ADDR(port, offset);
- ksz_read32(dev, addr, &data);
-
- if (set)
- data |= bits;
- else
- data &= ~bits;
-
- ksz_write32(dev, addr, data);
+ regmap_update_bits(dev->regmap[2], PORT_CTRL_ADDR(port, offset),
+ bits, set ? bits : 0);
}
-static int ksz9477_wait_vlan_ctrl_ready(struct ksz_device *dev, u32 waiton,
- int timeout)
+static int ksz9477_wait_vlan_ctrl_ready(struct ksz_device *dev)
{
- u8 data;
+ unsigned int val;
- do {
- ksz_read8(dev, REG_SW_VLAN_CTRL, &data);
- if (!(data & waiton))
- break;
- usleep_range(1, 10);
- } while (timeout-- > 0);
-
- if (timeout <= 0)
- return -ETIMEDOUT;
-
- return 0;
+ return regmap_read_poll_timeout(dev->regmap[0], REG_SW_VLAN_CTRL,
+ val, !(val & VLAN_START), 10, 1000);
}
static int ksz9477_get_vlan_table(struct ksz_device *dev, u16 vid,
@@ -123,8 +108,8 @@ static int ksz9477_get_vlan_table(struct ksz_device *dev, u16 vid,
ksz_write8(dev, REG_SW_VLAN_CTRL, VLAN_READ | VLAN_START);
/* wait to be cleared */
- ret = ksz9477_wait_vlan_ctrl_ready(dev, VLAN_START, 1000);
- if (ret < 0) {
+ ret = ksz9477_wait_vlan_ctrl_ready(dev);
+ if (ret) {
dev_dbg(dev->dev, "Failed to read vlan table\n");
goto exit;
}
@@ -156,8 +141,8 @@ static int ksz9477_set_vlan_table(struct ksz_device *dev, u16 vid,
ksz_write8(dev, REG_SW_VLAN_CTRL, VLAN_START | VLAN_WRITE);
/* wait to be cleared */
- ret = ksz9477_wait_vlan_ctrl_ready(dev, VLAN_START, 1000);
- if (ret < 0) {
+ ret = ksz9477_wait_vlan_ctrl_ready(dev);
+ if (ret) {
dev_dbg(dev->dev, "Failed to write vlan table\n");
goto exit;
}
@@ -191,55 +176,35 @@ static void ksz9477_write_table(struct ksz_device *dev, u32 *table)
ksz_write32(dev, REG_SW_ALU_VAL_D, table[3]);
}
-static int ksz9477_wait_alu_ready(struct ksz_device *dev, u32 waiton,
- int timeout)
+static int ksz9477_wait_alu_ready(struct ksz_device *dev)
{
- u32 data;
-
- do {
- ksz_read32(dev, REG_SW_ALU_CTRL__4, &data);
- if (!(data & waiton))
- break;
- usleep_range(1, 10);
- } while (timeout-- > 0);
+ unsigned int val;
- if (timeout <= 0)
- return -ETIMEDOUT;
-
- return 0;
+ return regmap_read_poll_timeout(dev->regmap[2], REG_SW_ALU_CTRL__4,
+ val, !(val & ALU_START), 10, 1000);
}
-static int ksz9477_wait_alu_sta_ready(struct ksz_device *dev, u32 waiton,
- int timeout)
+static int ksz9477_wait_alu_sta_ready(struct ksz_device *dev)
{
- u32 data;
+ unsigned int val;
- do {
- ksz_read32(dev, REG_SW_ALU_STAT_CTRL__4, &data);
- if (!(data & waiton))
- break;
- usleep_range(1, 10);
- } while (timeout-- > 0);
-
- if (timeout <= 0)
- return -ETIMEDOUT;
-
- return 0;
+ return regmap_read_poll_timeout(dev->regmap[2],
+ REG_SW_ALU_STAT_CTRL__4,
+ val, !(val & ALU_STAT_START),
+ 10, 1000);
}
static int ksz9477_reset_switch(struct ksz_device *dev)
{
u8 data8;
- u16 data16;
u32 data32;
/* reset switch */
ksz_cfg(dev, REG_SW_OPERATION, SW_RESET, true);
/* turn off SPI DO Edge select */
- ksz_read8(dev, REG_SW_GLOBAL_SERIAL_CTRL_0, &data8);
- data8 &= ~SPI_AUTO_EDGE_DETECTION;
- ksz_write8(dev, REG_SW_GLOBAL_SERIAL_CTRL_0, data8);
+ regmap_update_bits(dev->regmap[0], REG_SW_GLOBAL_SERIAL_CTRL_0,
+ SPI_AUTO_EDGE_DETECTION, 0);
/* default configuration */
ksz_read8(dev, REG_SW_LUE_CTRL_1, &data8);
@@ -253,10 +218,14 @@ static int ksz9477_reset_switch(struct ksz_device *dev)
ksz_read32(dev, REG_SW_PORT_INT_STATUS__4, &data32);
/* set broadcast storm protection 10% rate */
- ksz_read16(dev, REG_SW_MAC_CTRL_2, &data16);
- data16 &= ~BROADCAST_STORM_RATE;
- data16 |= (BROADCAST_STORM_VALUE * BROADCAST_STORM_PROT_RATE) / 100;
- ksz_write16(dev, REG_SW_MAC_CTRL_2, data16);
+ regmap_update_bits(dev->regmap[1], REG_SW_MAC_CTRL_2,
+ BROADCAST_STORM_RATE,
+ (BROADCAST_STORM_VALUE *
+ BROADCAST_STORM_PROT_RATE) / 100);
+
+ if (dev->synclko_125)
+ ksz_write8(dev, REG_SW_GLOBAL_OUTPUT_CTRL__1,
+ SW_ENABLE_REFCLKO | SW_REFCLKO_IS_125MHZ);
return 0;
}
@@ -264,12 +233,8 @@ static int ksz9477_reset_switch(struct ksz_device *dev)
static void ksz9477_r_mib_cnt(struct ksz_device *dev, int port, u16 addr,
u64 *cnt)
{
- struct ksz_poll_ctx ctx = {
- .dev = dev,
- .port = port,
- .offset = REG_PORT_MIB_CTRL_STAT__4,
- };
struct ksz_port *p = &dev->ports[port];
+ unsigned int val;
u32 data;
int ret;
@@ -279,11 +244,11 @@ static void ksz9477_r_mib_cnt(struct ksz_device *dev, int port, u16 addr,
data |= (addr << MIB_COUNTER_INDEX_S);
ksz_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4, data);
- ret = readx_poll_timeout(ksz_pread32_poll, &ctx, data,
- !(data & MIB_COUNTER_READ), 10, 1000);
-
+ ret = regmap_read_poll_timeout(dev->regmap[2],
+ PORT_CTRL_ADDR(port, REG_PORT_MIB_CTRL_STAT__4),
+ val, !(val & MIB_COUNTER_READ), 10, 1000);
/* failed to read MIB. get out of loop */
- if (ret < 0) {
+ if (ret) {
dev_dbg(dev->dev, "Failed to get MIB\n");
return;
}
@@ -518,10 +483,10 @@ static void ksz9477_flush_dyn_mac_table(struct ksz_device *dev, int port)
{
u8 data;
- ksz_read8(dev, REG_SW_LUE_CTRL_2, &data);
- data &= ~(SW_FLUSH_OPTION_M << SW_FLUSH_OPTION_S);
- data |= (SW_FLUSH_OPTION_DYN_MAC << SW_FLUSH_OPTION_S);
- ksz_write8(dev, REG_SW_LUE_CTRL_2, data);
+ regmap_update_bits(dev->regmap[0], REG_SW_LUE_CTRL_2,
+ SW_FLUSH_OPTION_M << SW_FLUSH_OPTION_S,
+ SW_FLUSH_OPTION_DYN_MAC << SW_FLUSH_OPTION_S);
+
if (port < dev->mib_port_cnt) {
/* flush individual port */
ksz_pread8(dev, port, P_STP_CTRL, &data);
@@ -648,8 +613,8 @@ static int ksz9477_port_fdb_add(struct dsa_switch *ds, int port,
ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_READ | ALU_START);
/* wait to be finished */
- ret = ksz9477_wait_alu_ready(dev, ALU_START, 1000);
- if (ret < 0) {
+ ret = ksz9477_wait_alu_ready(dev);
+ if (ret) {
dev_dbg(dev->dev, "Failed to read ALU\n");
goto exit;
}
@@ -672,8 +637,8 @@ static int ksz9477_port_fdb_add(struct dsa_switch *ds, int port,
ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_WRITE | ALU_START);
/* wait to be finished */
- ret = ksz9477_wait_alu_ready(dev, ALU_START, 1000);
- if (ret < 0)
+ ret = ksz9477_wait_alu_ready(dev);
+ if (ret)
dev_dbg(dev->dev, "Failed to write ALU\n");
exit:
@@ -705,8 +670,8 @@ static int ksz9477_port_fdb_del(struct dsa_switch *ds, int port,
ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_READ | ALU_START);
/* wait to be finished */
- ret = ksz9477_wait_alu_ready(dev, ALU_START, 1000);
- if (ret < 0) {
+ ret = ksz9477_wait_alu_ready(dev);
+ if (ret) {
dev_dbg(dev->dev, "Failed to read ALU\n");
goto exit;
}
@@ -739,8 +704,8 @@ static int ksz9477_port_fdb_del(struct dsa_switch *ds, int port,
ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_WRITE | ALU_START);
/* wait to be finished */
- ret = ksz9477_wait_alu_ready(dev, ALU_START, 1000);
- if (ret < 0)
+ ret = ksz9477_wait_alu_ready(dev);
+ if (ret)
dev_dbg(dev->dev, "Failed to write ALU\n");
exit:
@@ -846,7 +811,7 @@ static void ksz9477_port_mdb_add(struct dsa_switch *ds, int port,
ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data);
/* wait to be finished */
- if (ksz9477_wait_alu_sta_ready(dev, ALU_STAT_START, 1000) < 0) {
+ if (ksz9477_wait_alu_sta_ready(dev)) {
dev_dbg(dev->dev, "Failed to read ALU STATIC\n");
goto exit;
}
@@ -887,7 +852,7 @@ static void ksz9477_port_mdb_add(struct dsa_switch *ds, int port,
ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data);
/* wait to be finished */
- if (ksz9477_wait_alu_sta_ready(dev, ALU_STAT_START, 1000) < 0)
+ if (ksz9477_wait_alu_sta_ready(dev))
dev_dbg(dev->dev, "Failed to read ALU STATIC\n");
exit:
@@ -917,8 +882,8 @@ static int ksz9477_port_mdb_del(struct dsa_switch *ds, int port,
ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data);
/* wait to be finished */
- ret = ksz9477_wait_alu_sta_ready(dev, ALU_STAT_START, 1000);
- if (ret < 0) {
+ ret = ksz9477_wait_alu_sta_ready(dev);
+ if (ret) {
dev_dbg(dev->dev, "Failed to read ALU STATIC\n");
goto exit;
}
@@ -959,8 +924,8 @@ static int ksz9477_port_mdb_del(struct dsa_switch *ds, int port,
ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data);
/* wait to be finished */
- ret = ksz9477_wait_alu_sta_ready(dev, ALU_STAT_START, 1000);
- if (ret < 0)
+ ret = ksz9477_wait_alu_sta_ready(dev);
+ if (ret)
dev_dbg(dev->dev, "Failed to read ALU STATIC\n");
exit:
@@ -1165,6 +1130,62 @@ static phy_interface_t ksz9477_get_interface(struct ksz_device *dev, int port)
return interface;
}
+static void ksz9477_port_mmd_write(struct ksz_device *dev, int port,
+ u8 dev_addr, u16 reg_addr, u16 val)
+{
+ ksz_pwrite16(dev, port, REG_PORT_PHY_MMD_SETUP,
+ MMD_SETUP(PORT_MMD_OP_INDEX, dev_addr));
+ ksz_pwrite16(dev, port, REG_PORT_PHY_MMD_INDEX_DATA, reg_addr);
+ ksz_pwrite16(dev, port, REG_PORT_PHY_MMD_SETUP,
+ MMD_SETUP(PORT_MMD_OP_DATA_NO_INCR, dev_addr));
+ ksz_pwrite16(dev, port, REG_PORT_PHY_MMD_INDEX_DATA, val);
+}
+
+static void ksz9477_phy_errata_setup(struct ksz_device *dev, int port)
+{
+ /* Apply PHY settings to address errata listed in
+ * KSZ9477, KSZ9897, KSZ9896, KSZ9567, KSZ8565
+ * Silicon Errata and Data Sheet Clarification documents:
+ *
+ * Register settings are needed to improve PHY receive performance
+ */
+ ksz9477_port_mmd_write(dev, port, 0x01, 0x6f, 0xdd0b);
+ ksz9477_port_mmd_write(dev, port, 0x01, 0x8f, 0x6032);
+ ksz9477_port_mmd_write(dev, port, 0x01, 0x9d, 0x248c);
+ ksz9477_port_mmd_write(dev, port, 0x01, 0x75, 0x0060);
+ ksz9477_port_mmd_write(dev, port, 0x01, 0xd3, 0x7777);
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x06, 0x3008);
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x08, 0x2001);
+
+ /* Transmit waveform amplitude can be improved
+ * (1000BASE-T, 100BASE-TX, 10BASE-Te)
+ */
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x04, 0x00d0);
+
+ /* Energy Efficient Ethernet (EEE) feature select must
+ * be manually disabled (except on KSZ8565 which is 100Mbit)
+ */
+ if (dev->features & GBIT_SUPPORT)
+ ksz9477_port_mmd_write(dev, port, 0x07, 0x3c, 0x0000);
+
+ /* Register settings are required to meet data sheet
+ * supply current specifications
+ */
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x13, 0x6eff);
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x14, 0xe6ff);
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x15, 0x6eff);
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x16, 0xe6ff);
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x17, 0x00ff);
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x18, 0x43ff);
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x19, 0xc3ff);
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x1a, 0x6fff);
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x1b, 0x07ff);
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x1c, 0x0fff);
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x1d, 0xe7ff);
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x1e, 0xefff);
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x20, 0xeeee);
+}
+
static void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port)
{
u8 data8;
@@ -1203,6 +1224,8 @@ static void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port)
PORT_FORCE_TX_FLOW_CTRL | PORT_FORCE_RX_FLOW_CTRL,
false);
+ if (dev->phy_errata_9477)
+ ksz9477_phy_errata_setup(dev, port);
} else {
/* force flow control */
ksz_port_cfg(dev, port, REG_PORT_CTRL_0,
@@ -1474,6 +1497,7 @@ struct ksz_chip_data {
int num_statics;
int cpu_ports;
int port_cnt;
+ bool phy_errata_9477;
};
static const struct ksz_chip_data ksz9477_switch_chips[] = {
@@ -1485,6 +1509,7 @@ static const struct ksz_chip_data ksz9477_switch_chips[] = {
.num_statics = 16,
.cpu_ports = 0x7F, /* can be configured as cpu port */
.port_cnt = 7, /* total physical port count */
+ .phy_errata_9477 = true,
},
{
.chip_id = 0x00989700,
@@ -1494,6 +1519,7 @@ static const struct ksz_chip_data ksz9477_switch_chips[] = {
.num_statics = 16,
.cpu_ports = 0x7F, /* can be configured as cpu port */
.port_cnt = 7, /* total physical port count */
+ .phy_errata_9477 = true,
},
{
.chip_id = 0x00989300,
@@ -1522,6 +1548,7 @@ static int ksz9477_switch_init(struct ksz_device *dev)
dev->num_statics = chip->num_statics;
dev->port_cnt = chip->port_cnt;
dev->cpu_ports = chip->cpu_ports;
+ dev->phy_errata_9477 = chip->phy_errata_9477;
break;
}
diff --git a/drivers/net/dsa/microchip/ksz9477_spi.c b/drivers/net/dsa/microchip/ksz9477_spi.c
index 75178624d3f5..5a9e27b337a8 100644
--- a/drivers/net/dsa/microchip/ksz9477_spi.c
+++ b/drivers/net/dsa/microchip/ksz9477_spi.c
@@ -10,119 +10,43 @@
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include "ksz_priv.h"
-#include "ksz_spi.h"
-
-/* SPI frame opcodes */
-#define KS_SPIOP_RD 3
-#define KS_SPIOP_WR 2
+#include "ksz_common.h"
#define SPI_ADDR_SHIFT 24
-#define SPI_ADDR_MASK (BIT(SPI_ADDR_SHIFT) - 1)
+#define SPI_ADDR_ALIGN 3
#define SPI_TURNAROUND_SHIFT 5
-/* Enough to read all switch port registers. */
-#define SPI_TX_BUF_LEN 0x100
-
-static int ksz9477_spi_read_reg(struct spi_device *spi, u32 reg, u8 *val,
- unsigned int len)
-{
- u32 txbuf;
- int ret;
-
- txbuf = reg & SPI_ADDR_MASK;
- txbuf |= KS_SPIOP_RD << SPI_ADDR_SHIFT;
- txbuf <<= SPI_TURNAROUND_SHIFT;
- txbuf = cpu_to_be32(txbuf);
-
- ret = spi_write_then_read(spi, &txbuf, 4, val, len);
- return ret;
-}
-
-static int ksz9477_spi_write_reg(struct spi_device *spi, u32 reg, u8 *val,
- unsigned int len)
-{
- u32 *txbuf = (u32 *)val;
-
- *txbuf = reg & SPI_ADDR_MASK;
- *txbuf |= (KS_SPIOP_WR << SPI_ADDR_SHIFT);
- *txbuf <<= SPI_TURNAROUND_SHIFT;
- *txbuf = cpu_to_be32(*txbuf);
-
- return spi_write(spi, txbuf, 4 + len);
-}
-
-static int ksz_spi_read(struct ksz_device *dev, u32 reg, u8 *data,
- unsigned int len)
-{
- struct spi_device *spi = dev->priv;
-
- return ksz9477_spi_read_reg(spi, reg, data, len);
-}
-
-static int ksz_spi_write(struct ksz_device *dev, u32 reg, void *data,
- unsigned int len)
-{
- struct spi_device *spi = dev->priv;
-
- if (len > SPI_TX_BUF_LEN)
- len = SPI_TX_BUF_LEN;
- memcpy(&dev->txbuf[4], data, len);
- return ksz9477_spi_write_reg(spi, reg, dev->txbuf, len);
-}
-
-static int ksz_spi_read24(struct ksz_device *dev, u32 reg, u32 *val)
-{
- int ret;
-
- *val = 0;
- ret = ksz_spi_read(dev, reg, (u8 *)val, 3);
- if (!ret) {
- *val = be32_to_cpu(*val);
- /* convert to 24bit */
- *val >>= 8;
- }
-
- return ret;
-}
-
-static int ksz_spi_write24(struct ksz_device *dev, u32 reg, u32 value)
-{
- /* make it to big endian 24bit from MSB */
- value <<= 8;
- value = cpu_to_be32(value);
- return ksz_spi_write(dev, reg, &value, 3);
-}
-
-static const struct ksz_io_ops ksz9477_spi_ops = {
- .read8 = ksz_spi_read8,
- .read16 = ksz_spi_read16,
- .read24 = ksz_spi_read24,
- .read32 = ksz_spi_read32,
- .write8 = ksz_spi_write8,
- .write16 = ksz_spi_write16,
- .write24 = ksz_spi_write24,
- .write32 = ksz_spi_write32,
- .get = ksz_spi_get,
- .set = ksz_spi_set,
-};
+KSZ_REGMAP_TABLE(ksz9477, 32, SPI_ADDR_SHIFT,
+ SPI_TURNAROUND_SHIFT, SPI_ADDR_ALIGN);
static int ksz9477_spi_probe(struct spi_device *spi)
{
struct ksz_device *dev;
- int ret;
+ int i, ret;
- dev = ksz_switch_alloc(&spi->dev, &ksz9477_spi_ops, spi);
+ dev = ksz_switch_alloc(&spi->dev, spi);
if (!dev)
return -ENOMEM;
+ for (i = 0; i < ARRAY_SIZE(ksz9477_regmap_config); i++) {
+ dev->regmap[i] = devm_regmap_init_spi(spi,
+ &ksz9477_regmap_config[i]);
+ if (IS_ERR(dev->regmap[i])) {
+ ret = PTR_ERR(dev->regmap[i]);
+ dev_err(&spi->dev,
+ "Failed to initialize regmap%i: %d\n",
+ ksz9477_regmap_config[i].val_bits, ret);
+ return ret;
+ }
+ }
+
if (spi->dev.platform_data)
dev->pdata = spi->dev.platform_data;
- dev->txbuf = devm_kzalloc(dev->dev, 4 + SPI_TX_BUF_LEN, GFP_KERNEL);
-
ret = ksz9477_switch_register(dev);
/* Main DSA driver may not be started yet. */
diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
index 39dace8e3512..a3d2d67894bd 100644
--- a/drivers/net/dsa/microchip/ksz_common.c
+++ b/drivers/net/dsa/microchip/ksz_common.c
@@ -83,6 +83,9 @@ static void ksz_mib_read_work(struct work_struct *work)
int i;
for (i = 0; i < dev->mib_port_cnt; i++) {
+ if (dsa_is_unused_port(dev->ds, i))
+ continue;
+
p = &dev->ports[i];
mib = &p->mib;
mutex_lock(&mib->cnt_mutex);
@@ -393,9 +396,7 @@ void ksz_disable_port(struct dsa_switch *ds, int port)
}
EXPORT_SYMBOL_GPL(ksz_disable_port);
-struct ksz_device *ksz_switch_alloc(struct device *base,
- const struct ksz_io_ops *ops,
- void *priv)
+struct ksz_device *ksz_switch_alloc(struct device *base, void *priv)
{
struct dsa_switch *ds;
struct ksz_device *swdev;
@@ -413,7 +414,6 @@ struct ksz_device *ksz_switch_alloc(struct device *base,
swdev->ds = ds;
swdev->priv = priv;
- swdev->ops = ops;
return swdev;
}
@@ -433,13 +433,12 @@ int ksz_switch_register(struct ksz_device *dev,
return PTR_ERR(dev->reset_gpio);
if (dev->reset_gpio) {
- gpiod_set_value(dev->reset_gpio, 1);
+ gpiod_set_value_cansleep(dev->reset_gpio, 1);
mdelay(10);
- gpiod_set_value(dev->reset_gpio, 0);
+ gpiod_set_value_cansleep(dev->reset_gpio, 0);
}
mutex_init(&dev->dev_mutex);
- mutex_init(&dev->reg_mutex);
mutex_init(&dev->stats_mutex);
mutex_init(&dev->alu_mutex);
mutex_init(&dev->vlan_mutex);
@@ -460,6 +459,8 @@ int ksz_switch_register(struct ksz_device *dev,
ret = of_get_phy_mode(dev->dev->of_node);
if (ret >= 0)
dev->interface = ret;
+ dev->synclko_125 = of_property_read_bool(dev->dev->of_node,
+ "microchip,synclko-125");
}
ret = dsa_register_switch(dev->ds);
@@ -484,7 +485,7 @@ void ksz_switch_remove(struct ksz_device *dev)
dsa_unregister_switch(dev->ds);
if (dev->reset_gpio)
- gpiod_set_value(dev->reset_gpio, 1);
+ gpiod_set_value_cansleep(dev->reset_gpio, 1);
}
EXPORT_SYMBOL(ksz_switch_remove);
diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h
index 21cd794e18f1..ee7096d8af07 100644
--- a/drivers/net/dsa/microchip/ksz_common.h
+++ b/drivers/net/dsa/microchip/ksz_common.h
@@ -7,6 +7,8 @@
#ifndef __KSZ_COMMON_H
#define __KSZ_COMMON_H
+#include <linux/regmap.h>
+
void ksz_port_cleanup(struct ksz_device *dev, int port);
void ksz_update_port_member(struct ksz_device *dev, int port);
void ksz_init_mib_timer(struct ksz_device *dev);
@@ -41,114 +43,44 @@ void ksz_disable_port(struct dsa_switch *ds, int port);
static inline int ksz_read8(struct ksz_device *dev, u32 reg, u8 *val)
{
- int ret;
-
- mutex_lock(&dev->reg_mutex);
- ret = dev->ops->read8(dev, reg, val);
- mutex_unlock(&dev->reg_mutex);
+ unsigned int value;
+ int ret = regmap_read(dev->regmap[0], reg, &value);
+ *val = value;
return ret;
}
static inline int ksz_read16(struct ksz_device *dev, u32 reg, u16 *val)
{
- int ret;
-
- mutex_lock(&dev->reg_mutex);
- ret = dev->ops->read16(dev, reg, val);
- mutex_unlock(&dev->reg_mutex);
-
- return ret;
-}
-
-static inline int ksz_read24(struct ksz_device *dev, u32 reg, u32 *val)
-{
- int ret;
-
- mutex_lock(&dev->reg_mutex);
- ret = dev->ops->read24(dev, reg, val);
- mutex_unlock(&dev->reg_mutex);
+ unsigned int value;
+ int ret = regmap_read(dev->regmap[1], reg, &value);
+ *val = value;
return ret;
}
static inline int ksz_read32(struct ksz_device *dev, u32 reg, u32 *val)
{
- int ret;
-
- mutex_lock(&dev->reg_mutex);
- ret = dev->ops->read32(dev, reg, val);
- mutex_unlock(&dev->reg_mutex);
+ unsigned int value;
+ int ret = regmap_read(dev->regmap[2], reg, &value);
+ *val = value;
return ret;
}
static inline int ksz_write8(struct ksz_device *dev, u32 reg, u8 value)
{
- int ret;
-
- mutex_lock(&dev->reg_mutex);
- ret = dev->ops->write8(dev, reg, value);
- mutex_unlock(&dev->reg_mutex);
-
- return ret;
+ return regmap_write(dev->regmap[0], reg, value);
}
static inline int ksz_write16(struct ksz_device *dev, u32 reg, u16 value)
{
- int ret;
-
- mutex_lock(&dev->reg_mutex);
- ret = dev->ops->write16(dev, reg, value);
- mutex_unlock(&dev->reg_mutex);
-
- return ret;
-}
-
-static inline int ksz_write24(struct ksz_device *dev, u32 reg, u32 value)
-{
- int ret;
-
- mutex_lock(&dev->reg_mutex);
- ret = dev->ops->write24(dev, reg, value);
- mutex_unlock(&dev->reg_mutex);
-
- return ret;
+ return regmap_write(dev->regmap[1], reg, value);
}
static inline int ksz_write32(struct ksz_device *dev, u32 reg, u32 value)
{
- int ret;
-
- mutex_lock(&dev->reg_mutex);
- ret = dev->ops->write32(dev, reg, value);
- mutex_unlock(&dev->reg_mutex);
-
- return ret;
-}
-
-static inline int ksz_get(struct ksz_device *dev, u32 reg, void *data,
- size_t len)
-{
- int ret;
-
- mutex_lock(&dev->reg_mutex);
- ret = dev->ops->get(dev, reg, data, len);
- mutex_unlock(&dev->reg_mutex);
-
- return ret;
-}
-
-static inline int ksz_set(struct ksz_device *dev, u32 reg, void *data,
- size_t len)
-{
- int ret;
-
- mutex_lock(&dev->reg_mutex);
- ret = dev->ops->set(dev, reg, data, len);
- mutex_unlock(&dev->reg_mutex);
-
- return ret;
+ return regmap_write(dev->regmap[2], reg, value);
}
static inline void ksz_pread8(struct ksz_device *dev, int port, int offset,
@@ -187,47 +119,36 @@ static inline void ksz_pwrite32(struct ksz_device *dev, int port, int offset,
ksz_write32(dev, dev->dev_ops->get_port_addr(port, offset), data);
}
-static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set)
-{
- u8 data;
-
- ksz_read8(dev, addr, &data);
- if (set)
- data |= bits;
- else
- data &= ~bits;
- ksz_write8(dev, addr, data);
-}
-
-static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits,
- bool set)
-{
- u32 addr;
- u8 data;
-
- addr = dev->dev_ops->get_port_addr(port, offset);
- ksz_read8(dev, addr, &data);
-
- if (set)
- data |= bits;
- else
- data &= ~bits;
-
- ksz_write8(dev, addr, data);
-}
-
-struct ksz_poll_ctx {
- struct ksz_device *dev;
- int port;
- int offset;
-};
-
-static inline u32 ksz_pread32_poll(struct ksz_poll_ctx *ctx)
-{
- u32 data;
-
- ksz_pread32(ctx->dev, ctx->port, ctx->offset, &data);
- return data;
-}
+/* Regmap tables generation */
+#define KSZ_SPI_OP_RD 3
+#define KSZ_SPI_OP_WR 2
+
+#define KSZ_SPI_OP_FLAG_MASK(opcode, swp, regbits, regpad) \
+ swab##swp((opcode) << ((regbits) + (regpad)))
+
+#define KSZ_REGMAP_ENTRY(width, swp, regbits, regpad, regalign) \
+ { \
+ .val_bits = (width), \
+ .reg_stride = (width) / 8, \
+ .reg_bits = (regbits) + (regalign), \
+ .pad_bits = (regpad), \
+ .max_register = BIT(regbits) - 1, \
+ .cache_type = REGCACHE_NONE, \
+ .read_flag_mask = \
+ KSZ_SPI_OP_FLAG_MASK(KSZ_SPI_OP_RD, swp, \
+ regbits, regpad), \
+ .write_flag_mask = \
+ KSZ_SPI_OP_FLAG_MASK(KSZ_SPI_OP_WR, swp, \
+ regbits, regpad), \
+ .reg_format_endian = REGMAP_ENDIAN_BIG, \
+ .val_format_endian = REGMAP_ENDIAN_BIG \
+ }
+
+#define KSZ_REGMAP_TABLE(ksz, swp, regbits, regpad, regalign) \
+ static const struct regmap_config ksz##_regmap_config[] = { \
+ KSZ_REGMAP_ENTRY(8, swp, (regbits), (regpad), (regalign)), \
+ KSZ_REGMAP_ENTRY(16, swp, (regbits), (regpad), (regalign)), \
+ KSZ_REGMAP_ENTRY(32, swp, (regbits), (regpad), (regalign)), \
+ }
#endif
diff --git a/drivers/net/dsa/microchip/ksz_priv.h b/drivers/net/dsa/microchip/ksz_priv.h
index b52e5ca17ab4..beacf0e40f42 100644
--- a/drivers/net/dsa/microchip/ksz_priv.h
+++ b/drivers/net/dsa/microchip/ksz_priv.h
@@ -14,8 +14,6 @@
#include <linux/etherdevice.h>
#include <net/dsa.h>
-struct ksz_io_ops;
-
struct vlan_table {
u32 table[3];
};
@@ -49,14 +47,13 @@ struct ksz_device {
const char *name;
struct mutex dev_mutex; /* device access */
- struct mutex reg_mutex; /* register access */
struct mutex stats_mutex; /* status access */
struct mutex alu_mutex; /* ALU access */
struct mutex vlan_mutex; /* vlan access */
- const struct ksz_io_ops *ops;
const struct ksz_dev_ops *dev_ops;
struct device *dev;
+ struct regmap *regmap[3];
void *priv;
@@ -77,11 +74,11 @@ struct ksz_device {
int last_port; /* ports after that not used */
phy_interface_t interface;
u32 regs_size;
+ bool phy_errata_9477;
+ bool synclko_125;
struct vlan_table *vlan_cache;
- u8 *txbuf;
-
struct ksz_port *ports;
struct timer_list mib_read_timer;
struct work_struct mib_read;
@@ -100,19 +97,6 @@ struct ksz_device {
u16 port_mask;
};
-struct ksz_io_ops {
- int (*read8)(struct ksz_device *dev, u32 reg, u8 *value);
- int (*read16)(struct ksz_device *dev, u32 reg, u16 *value);
- int (*read24)(struct ksz_device *dev, u32 reg, u32 *value);
- int (*read32)(struct ksz_device *dev, u32 reg, u32 *value);
- int (*write8)(struct ksz_device *dev, u32 reg, u8 value);
- int (*write16)(struct ksz_device *dev, u32 reg, u16 value);
- int (*write24)(struct ksz_device *dev, u32 reg, u32 value);
- int (*write32)(struct ksz_device *dev, u32 reg, u32 value);
- int (*get)(struct ksz_device *dev, u32 reg, void *data, size_t len);
- int (*set)(struct ksz_device *dev, u32 reg, void *data, size_t len);
-};
-
struct alu_struct {
/* entry 1 */
u8 is_static:1;
@@ -161,8 +145,7 @@ struct ksz_dev_ops {
void (*exit)(struct ksz_device *dev);
};
-struct ksz_device *ksz_switch_alloc(struct device *base,
- const struct ksz_io_ops *ops, void *priv);
+struct ksz_device *ksz_switch_alloc(struct device *base, void *priv);
int ksz_switch_register(struct ksz_device *dev,
const struct ksz_dev_ops *ops);
void ksz_switch_remove(struct ksz_device *dev);
diff --git a/drivers/net/dsa/microchip/ksz_spi.h b/drivers/net/dsa/microchip/ksz_spi.h
deleted file mode 100644
index 427811bd60b3..000000000000
--- a/drivers/net/dsa/microchip/ksz_spi.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0
- * Microchip KSZ series SPI access common header
- *
- * Copyright (C) 2017-2018 Microchip Technology Inc.
- * Tristram Ha <Tristram.Ha@microchip.com>
- */
-
-#ifndef __KSZ_SPI_H
-#define __KSZ_SPI_H
-
-/* Chip dependent SPI access */
-static int ksz_spi_read(struct ksz_device *dev, u32 reg, u8 *data,
- unsigned int len);
-static int ksz_spi_write(struct ksz_device *dev, u32 reg, void *data,
- unsigned int len);
-
-static int ksz_spi_read8(struct ksz_device *dev, u32 reg, u8 *val)
-{
- return ksz_spi_read(dev, reg, val, 1);
-}
-
-static int ksz_spi_read16(struct ksz_device *dev, u32 reg, u16 *val)
-{
- int ret = ksz_spi_read(dev, reg, (u8 *)val, 2);
-
- if (!ret)
- *val = be16_to_cpu(*val);
-
- return ret;
-}
-
-static int ksz_spi_read32(struct ksz_device *dev, u32 reg, u32 *val)
-{
- int ret = ksz_spi_read(dev, reg, (u8 *)val, 4);
-
- if (!ret)
- *val = be32_to_cpu(*val);
-
- return ret;
-}
-
-static int ksz_spi_write8(struct ksz_device *dev, u32 reg, u8 value)
-{
- return ksz_spi_write(dev, reg, &value, 1);
-}
-
-static int ksz_spi_write16(struct ksz_device *dev, u32 reg, u16 value)
-{
- value = cpu_to_be16(value);
- return ksz_spi_write(dev, reg, &value, 2);
-}
-
-static int ksz_spi_write32(struct ksz_device *dev, u32 reg, u32 value)
-{
- value = cpu_to_be32(value);
- return ksz_spi_write(dev, reg, &value, 4);
-}
-
-static int ksz_spi_get(struct ksz_device *dev, u32 reg, void *data, size_t len)
-{
- return ksz_spi_read(dev, reg, data, len);
-}
-
-static int ksz_spi_set(struct ksz_device *dev, u32 reg, void *data, size_t len)
-{
- return ksz_spi_write(dev, reg, data, len);
-}
-
-#endif
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index c7d352da5448..3181e95586d6 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -428,24 +428,48 @@ static int
mt7530_pad_clk_setup(struct dsa_switch *ds, int mode)
{
struct mt7530_priv *priv = ds->priv;
- u32 ncpo1, ssc_delta, trgint, i;
+ u32 ncpo1, ssc_delta, trgint, i, xtal;
+
+ xtal = mt7530_read(priv, MT7530_MHWTRAP) & HWTRAP_XTAL_MASK;
+
+ if (xtal == HWTRAP_XTAL_20MHZ) {
+ dev_err(priv->dev,
+ "%s: MT7530 with a 20MHz XTAL is not supported!\n",
+ __func__);
+ return -EINVAL;
+ }
switch (mode) {
case PHY_INTERFACE_MODE_RGMII:
trgint = 0;
+ /* PLL frequency: 125MHz */
ncpo1 = 0x0c80;
- ssc_delta = 0x87;
break;
case PHY_INTERFACE_MODE_TRGMII:
trgint = 1;
- ncpo1 = 0x1400;
- ssc_delta = 0x57;
+ if (priv->id == ID_MT7621) {
+ /* PLL frequency: 150MHz: 1.2GBit */
+ if (xtal == HWTRAP_XTAL_40MHZ)
+ ncpo1 = 0x0780;
+ if (xtal == HWTRAP_XTAL_25MHZ)
+ ncpo1 = 0x0a00;
+ } else { /* PLL frequency: 250MHz: 2.0Gbit */
+ if (xtal == HWTRAP_XTAL_40MHZ)
+ ncpo1 = 0x0c80;
+ if (xtal == HWTRAP_XTAL_25MHZ)
+ ncpo1 = 0x1400;
+ }
break;
default:
dev_err(priv->dev, "xMII mode %d not supported\n", mode);
return -EINVAL;
}
+ if (xtal == HWTRAP_XTAL_25MHZ)
+ ssc_delta = 0x57;
+ else
+ ssc_delta = 0x87;
+
mt7530_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_MASK,
P6_INTF_MODE(trgint));
@@ -507,7 +531,9 @@ mt7530_pad_clk_setup(struct dsa_switch *ds, int mode)
mt7530_rmw(priv, MT7530_TRGMII_RD(i),
RD_TAP_MASK, RD_TAP(16));
else
- mt7623_trgmii_set(priv, GSW_INTF_MODE, INTF_MODE_TRGMII);
+ if (priv->id != ID_MT7621)
+ mt7623_trgmii_set(priv, GSW_INTF_MODE,
+ INTF_MODE_TRGMII);
return 0;
}
@@ -613,13 +639,13 @@ static void mt7530_adjust_link(struct dsa_switch *ds, int port,
struct mt7530_priv *priv = ds->priv;
if (phy_is_pseudo_fixed_link(phydev)) {
- if (priv->id == ID_MT7530) {
- dev_dbg(priv->dev, "phy-mode for master device = %x\n",
- phydev->interface);
+ dev_dbg(priv->dev, "phy-mode for master device = %x\n",
+ phydev->interface);
- /* Setup TX circuit incluing relevant PAD and driving */
- mt7530_pad_clk_setup(ds, phydev->interface);
+ /* Setup TX circuit incluing relevant PAD and driving */
+ mt7530_pad_clk_setup(ds, phydev->interface);
+ if (priv->id == ID_MT7530) {
/* Setup RX circuit, relevant PAD and driving on the
* host which must be placed after the setup on the
* device side is all finished.
diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h
index 4331429969fa..bfac90f48102 100644
--- a/drivers/net/dsa/mt7530.h
+++ b/drivers/net/dsa/mt7530.h
@@ -244,6 +244,10 @@ enum mt7530_vlan_port_attr {
/* Register for hw trap status */
#define MT7530_HWTRAP 0x7800
+#define HWTRAP_XTAL_MASK (BIT(10) | BIT(9))
+#define HWTRAP_XTAL_25MHZ (BIT(10) | BIT(9))
+#define HWTRAP_XTAL_40MHZ (BIT(10))
+#define HWTRAP_XTAL_20MHZ (BIT(9))
/* Register for hw trap modification */
#define MT7530_MHWTRAP 0x7804
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 063c7a671b41..6b17cd961d06 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -118,9 +118,9 @@ static irqreturn_t mv88e6xxx_g1_irq_thread_work(struct mv88e6xxx_chip *chip)
u16 ctl1;
int err;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &reg);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err)
goto out;
@@ -135,13 +135,13 @@ static irqreturn_t mv88e6xxx_g1_irq_thread_work(struct mv88e6xxx_chip *chip)
}
}
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &ctl1);
if (err)
goto unlock;
err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &reg);
unlock:
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err)
goto out;
ctl1 &= GENMASK(chip->g1_irq.nirqs, 0);
@@ -162,7 +162,7 @@ static void mv88e6xxx_g1_irq_bus_lock(struct irq_data *d)
{
struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
}
static void mv88e6xxx_g1_irq_bus_sync_unlock(struct irq_data *d)
@@ -184,7 +184,7 @@ static void mv88e6xxx_g1_irq_bus_sync_unlock(struct irq_data *d)
goto out;
out:
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
}
static const struct irq_chip mv88e6xxx_g1_irq_chip = {
@@ -239,9 +239,9 @@ static void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip)
*/
free_irq(chip->irq, chip);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
mv88e6xxx_g1_irq_free_common(chip);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
}
static int mv88e6xxx_g1_irq_setup_common(struct mv88e6xxx_chip *chip)
@@ -310,12 +310,12 @@ static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip)
*/
irq_set_lockdep_class(chip->irq, &lock_key, &request_key);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
err = request_threaded_irq(chip->irq, NULL,
mv88e6xxx_g1_irq_thread_fn,
IRQF_ONESHOT | IRQF_SHARED,
dev_name(chip->dev), chip);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (err)
mv88e6xxx_g1_irq_free_common(chip);
@@ -359,9 +359,9 @@ static void mv88e6xxx_irq_poll_free(struct mv88e6xxx_chip *chip)
kthread_cancel_delayed_work_sync(&chip->irq_poll_work);
kthread_destroy_worker(chip->kworker);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
mv88e6xxx_g1_irq_free_common(chip);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
}
int mv88e6xxx_wait(struct mv88e6xxx_chip *chip, int addr, int reg, u16 mask)
@@ -496,11 +496,11 @@ static void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port,
mv88e6xxx_phy_is_internal(ds, port))
return;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_setup_mac(chip, port, phydev->link, phydev->speed,
phydev->duplex, phydev->pause,
phydev->interface);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err && err != -EOPNOTSUPP)
dev_err(ds->dev, "p%d: failed to configure MAC\n", port);
@@ -616,12 +616,12 @@ static int mv88e6xxx_link_state(struct dsa_switch *ds, int port,
struct mv88e6xxx_chip *chip = ds->priv;
int err;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (chip->info->ops->port_link_state)
err = chip->info->ops->port_link_state(chip, port, state);
else
err = -EOPNOTSUPP;
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -651,10 +651,10 @@ static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port,
}
pause = !!phylink_test(state->advertising, Pause);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_setup_mac(chip, port, link, speed, duplex, pause,
state->interface);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err && err != -EOPNOTSUPP)
dev_err(ds->dev, "p%d: failed to configure MAC\n", port);
@@ -665,9 +665,9 @@ static void mv88e6xxx_mac_link_force(struct dsa_switch *ds, int port, int link)
struct mv88e6xxx_chip *chip = ds->priv;
int err;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = chip->info->ops->port_set_link(chip, port, link);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err)
dev_err(chip->dev, "p%d: failed to force MAC link\n", port);
@@ -825,6 +825,12 @@ static int mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip,
STATS_TYPE_BANK0 | STATS_TYPE_PORT);
}
+static int mv88e6250_stats_get_strings(struct mv88e6xxx_chip *chip,
+ uint8_t *data)
+{
+ return mv88e6xxx_stats_get_strings(chip, data, STATS_TYPE_BANK0);
+}
+
static int mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip,
uint8_t *data)
{
@@ -859,7 +865,7 @@ static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port,
if (stringset != ETH_SS_STATS)
return;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (chip->info->ops->stats_get_strings)
count = chip->info->ops->stats_get_strings(chip, data);
@@ -872,7 +878,7 @@ static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port,
data += count * ETH_GSTRING_LEN;
mv88e6xxx_atu_vtu_get_strings(data);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
}
static int mv88e6xxx_stats_get_sset_count(struct mv88e6xxx_chip *chip,
@@ -895,6 +901,11 @@ static int mv88e6095_stats_get_sset_count(struct mv88e6xxx_chip *chip)
STATS_TYPE_PORT);
}
+static int mv88e6250_stats_get_sset_count(struct mv88e6xxx_chip *chip)
+{
+ return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0);
+}
+
static int mv88e6320_stats_get_sset_count(struct mv88e6xxx_chip *chip)
{
return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
@@ -910,7 +921,7 @@ static int mv88e6xxx_get_sset_count(struct dsa_switch *ds, int port, int sset)
if (sset != ETH_SS_STATS)
return 0;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (chip->info->ops->stats_get_sset_count)
count = chip->info->ops->stats_get_sset_count(chip);
if (count < 0)
@@ -927,7 +938,7 @@ static int mv88e6xxx_get_sset_count(struct dsa_switch *ds, int port, int sset)
count += ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings);
out:
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return count;
}
@@ -942,11 +953,11 @@ static int mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
stat = &mv88e6xxx_hw_stats[i];
if (stat->type & types) {
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
bank1_select,
histogram);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
j++;
}
@@ -962,6 +973,13 @@ static int mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
}
+static int mv88e6250_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
+ uint64_t *data)
+{
+ return mv88e6xxx_stats_get_stats(chip, port, data, STATS_TYPE_BANK0,
+ 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
+}
+
static int mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
uint64_t *data)
{
@@ -998,14 +1016,14 @@ static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port,
if (chip->info->ops->stats_get_stats)
count = chip->info->ops->stats_get_stats(chip, port, data);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (chip->info->ops->serdes_get_stats) {
data += count;
count = chip->info->ops->serdes_get_stats(chip, port, data);
}
data += count;
mv88e6xxx_atu_vtu_get_stats(chip, port, data);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
}
static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
@@ -1014,10 +1032,10 @@ static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
struct mv88e6xxx_chip *chip = ds->priv;
int ret;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
ret = mv88e6xxx_stats_snapshot(chip, port);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (ret < 0)
return;
@@ -1044,7 +1062,7 @@ static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
memset(p, 0xff, 32 * sizeof(u16));
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
for (i = 0; i < 32; i++) {
@@ -1053,7 +1071,7 @@ static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
p[i] = reg;
}
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
}
static int mv88e6xxx_get_mac_eee(struct dsa_switch *ds, int port,
@@ -1119,9 +1137,9 @@ static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port,
struct mv88e6xxx_chip *chip = ds->priv;
int err;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_set_state(chip, port, state);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err)
dev_err(ds->dev, "p%d: failed to update state\n", port);
@@ -1306,9 +1324,9 @@ static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port)
struct mv88e6xxx_chip *chip = ds->priv;
int err;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_g1_atu_remove(chip, 0, port, false);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err)
dev_err(ds->dev, "p%d: failed to flush ATU\n", port);
@@ -1436,7 +1454,7 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
if (!vid_begin)
return -EOPNOTSUPP;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
do {
err = mv88e6xxx_vtu_getnext(chip, &vlan);
@@ -1476,7 +1494,7 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
} while (vlan.vid < vid_end);
unlock:
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -1492,9 +1510,9 @@ static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
if (!chip->info->max_vid)
return -EOPNOTSUPP;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_set_8021q_mode(chip, port, mode);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -1628,7 +1646,7 @@ static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
else
member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_TAGGED;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid)
if (_mv88e6xxx_port_vlan_add(chip, port, vid, member))
@@ -1639,7 +1657,7 @@ static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
dev_err(ds->dev, "p%d: failed to set PVID %d\n", port,
vlan->vid_end);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
}
static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_chip *chip,
@@ -1685,7 +1703,7 @@ static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
if (!chip->info->max_vid)
return -EOPNOTSUPP;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_get_pvid(chip, port, &pvid);
if (err)
@@ -1704,7 +1722,7 @@ static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
}
unlock:
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -1715,10 +1733,10 @@ static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
struct mv88e6xxx_chip *chip = ds->priv;
int err;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -1729,10 +1747,10 @@ static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
struct mv88e6xxx_chip *chip = ds->priv;
int err;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
MV88E6XXX_G1_ATU_DATA_STATE_UNUSED);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -1749,9 +1767,7 @@ static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip,
eth_broadcast_addr(addr.mac);
do {
- mutex_lock(&chip->reg_lock);
err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr);
- mutex_unlock(&chip->reg_lock);
if (err)
return err;
@@ -1784,10 +1800,7 @@ static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port,
int err;
/* Dump port's default Filtering Information Database (VLAN ID 0) */
- mutex_lock(&chip->reg_lock);
err = mv88e6xxx_port_get_fid(chip, port, &fid);
- mutex_unlock(&chip->reg_lock);
-
if (err)
return err;
@@ -1797,9 +1810,7 @@ static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port,
/* Dump VLANs' Filtering Information Databases */
do {
- mutex_lock(&chip->reg_lock);
err = mv88e6xxx_vtu_getnext(chip, &vlan);
- mutex_unlock(&chip->reg_lock);
if (err)
return err;
@@ -1819,8 +1830,13 @@ static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
dsa_fdb_dump_cb_t *cb, void *data)
{
struct mv88e6xxx_chip *chip = ds->priv;
+ int err;
- return mv88e6xxx_port_db_dump(chip, port, cb, data);
+ mv88e6xxx_reg_lock(chip);
+ err = mv88e6xxx_port_db_dump(chip, port, cb, data);
+ mv88e6xxx_reg_unlock(chip);
+
+ return err;
}
static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip,
@@ -1867,9 +1883,9 @@ static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
struct mv88e6xxx_chip *chip = ds->priv;
int err;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_bridge_map(chip, br);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -1879,11 +1895,11 @@ static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
{
struct mv88e6xxx_chip *chip = ds->priv;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (mv88e6xxx_bridge_map(chip, br) ||
mv88e6xxx_port_vlan_map(chip, port))
dev_err(ds->dev, "failed to remap in-chip Port VLAN\n");
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
}
static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds, int dev,
@@ -1895,9 +1911,9 @@ static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds, int dev,
if (!mv88e6xxx_has_pvt(chip))
return 0;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_pvt_map(chip, dev, port);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -1910,10 +1926,10 @@ static void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds, int dev,
if (!mv88e6xxx_has_pvt(chip))
return;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (mv88e6xxx_pvt_map(chip, dev, port))
dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n");
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
}
static int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip)
@@ -2264,14 +2280,14 @@ static int mv88e6xxx_port_enable(struct dsa_switch *ds, int port,
struct mv88e6xxx_chip *chip = ds->priv;
int err;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_serdes_power(chip, port, true);
if (!err && chip->info->ops->serdes_irq_setup)
err = chip->info->ops->serdes_irq_setup(chip, port);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -2280,7 +2296,7 @@ static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port)
{
struct mv88e6xxx_chip *chip = ds->priv;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (mv88e6xxx_port_set_state(chip, port, BR_STATE_DISABLED))
dev_err(chip->dev, "failed to disable port\n");
@@ -2291,7 +2307,7 @@ static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port)
if (mv88e6xxx_serdes_power(chip, port, false))
dev_err(chip->dev, "failed to power off SERDES\n");
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
}
static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds,
@@ -2300,9 +2316,9 @@ static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds,
struct mv88e6xxx_chip *chip = ds->priv;
int err;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_g1_atu_set_age_time(chip, ageing_time);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -2432,7 +2448,7 @@ static int mv88e6xxx_setup(struct dsa_switch *ds)
chip->ds = ds;
ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (chip->info->ops->setup_errata) {
err = chip->info->ops->setup_errata(chip);
@@ -2539,7 +2555,7 @@ static int mv88e6xxx_setup(struct dsa_switch *ds)
goto unlock;
unlock:
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -2554,9 +2570,9 @@ static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg)
if (!chip->info->ops->phy_read)
return -EOPNOTSUPP;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = chip->info->ops->phy_read(chip, bus, phy, reg, &val);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (reg == MII_PHYSID2) {
/* Some internal PHYs don't have a model number. */
@@ -2589,9 +2605,9 @@ static int mv88e6xxx_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
if (!chip->info->ops->phy_write)
return -EOPNOTSUPP;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = chip->info->ops->phy_write(chip, bus, phy, reg, val);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -2606,9 +2622,9 @@ static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip,
int err;
if (external) {
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_g2_scratch_gpio_set_smi(chip, true);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err)
return err;
@@ -2729,9 +2745,9 @@ static int mv88e6xxx_get_eeprom(struct dsa_switch *ds,
if (!chip->info->ops->get_eeprom)
return -EOPNOTSUPP;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = chip->info->ops->get_eeprom(chip, eeprom, data);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err)
return err;
@@ -2753,9 +2769,9 @@ static int mv88e6xxx_set_eeprom(struct dsa_switch *ds,
if (eeprom->magic != 0xc3ec4951)
return -EINVAL;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = chip->info->ops->set_eeprom(chip, eeprom, data);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -3444,6 +3460,44 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
.phylink_validate = mv88e6352_phylink_validate,
};
+static const struct mv88e6xxx_ops mv88e6250_ops = {
+ /* MV88E6XXX_FAMILY_6250 */
+ .ieee_pri_map = mv88e6250_g1_ieee_pri_map,
+ .ip_pri_map = mv88e6085_g1_ip_pri_map,
+ .irl_init_all = mv88e6352_g2_irl_init_all,
+ .get_eeprom = mv88e6xxx_g2_get_eeprom16,
+ .set_eeprom = mv88e6xxx_g2_set_eeprom16,
+ .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
+ .phy_read = mv88e6xxx_g2_smi_phy_read,
+ .phy_write = mv88e6xxx_g2_smi_phy_write,
+ .port_set_link = mv88e6xxx_port_set_link,
+ .port_set_duplex = mv88e6xxx_port_set_duplex,
+ .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
+ .port_set_speed = mv88e6250_port_set_speed,
+ .port_tag_remap = mv88e6095_port_tag_remap,
+ .port_set_frame_mode = mv88e6351_port_set_frame_mode,
+ .port_set_egress_floods = mv88e6352_port_set_egress_floods,
+ .port_set_ether_type = mv88e6351_port_set_ether_type,
+ .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
+ .port_pause_limit = mv88e6097_port_pause_limit,
+ .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
+ .port_link_state = mv88e6250_port_link_state,
+ .stats_snapshot = mv88e6320_g1_stats_snapshot,
+ .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
+ .stats_get_sset_count = mv88e6250_stats_get_sset_count,
+ .stats_get_strings = mv88e6250_stats_get_strings,
+ .stats_get_stats = mv88e6250_stats_get_stats,
+ .set_cpu_port = mv88e6095_g1_set_cpu_port,
+ .set_egress_port = mv88e6095_g1_set_egress_port,
+ .watchdog_ops = &mv88e6250_watchdog_ops,
+ .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
+ .pot_clear = mv88e6xxx_g2_pot_clear,
+ .reset = mv88e6250_g1_reset,
+ .vtu_getnext = mv88e6250_g1_vtu_getnext,
+ .vtu_loadpurge = mv88e6250_g1_vtu_loadpurge,
+ .phylink_validate = mv88e6065_phylink_validate,
+};
+
static const struct mv88e6xxx_ops mv88e6290_ops = {
/* MV88E6XXX_FAMILY_6390 */
.setup_errata = mv88e6390_setup_errata,
@@ -4229,6 +4283,27 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.ops = &mv88e6240_ops,
},
+ [MV88E6250] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6250,
+ .family = MV88E6XXX_FAMILY_6250,
+ .name = "Marvell 88E6250",
+ .num_databases = 64,
+ .num_ports = 7,
+ .num_internal_phys = 5,
+ .max_vid = 4095,
+ .port_base_addr = 0x08,
+ .phy_base_addr = 0x00,
+ .global1_addr = 0x0f,
+ .global2_addr = 0x07,
+ .age_time_coeff = 15000,
+ .g1_irqs = 9,
+ .g2_irqs = 10,
+ .atu_move_port_mask = 0xf,
+ .dual_chip = true,
+ .tag_protocol = DSA_TAG_PROTO_DSA,
+ .ops = &mv88e6250_ops,
+ },
+
[MV88E6290] = {
.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6290,
.family = MV88E6XXX_FAMILY_6390,
@@ -4457,9 +4532,9 @@ static int mv88e6xxx_detect(struct mv88e6xxx_chip *chip)
u16 id;
int err;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_read(chip, 0, MV88E6XXX_PORT_SWITCH_ID, &id);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err)
return err;
@@ -4522,12 +4597,12 @@ static void mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port,
{
struct mv88e6xxx_chip *chip = ds->priv;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid,
MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC))
dev_err(ds->dev, "p%d: failed to load multicast MAC address\n",
port);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
}
static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port,
@@ -4536,10 +4611,10 @@ static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port,
struct mv88e6xxx_chip *chip = ds->priv;
int err;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid,
MV88E6XXX_G1_ATU_DATA_STATE_UNUSED);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -4550,12 +4625,12 @@ static int mv88e6xxx_port_egress_floods(struct dsa_switch *ds, int port,
struct mv88e6xxx_chip *chip = ds->priv;
int err = -EOPNOTSUPP;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (chip->info->ops->port_set_egress_floods)
err = chip->info->ops->port_set_egress_floods(chip, port,
unicast,
multicast);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -4711,6 +4786,8 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev)
err = PTR_ERR(chip->reset);
goto out;
}
+ if (chip->reset)
+ usleep_range(1000, 2000);
err = mv88e6xxx_detect(chip);
if (err)
@@ -4726,9 +4803,9 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev)
chip->eeprom_len = pdata->eeprom_len;
}
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_switch_reset(chip);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err)
goto out;
@@ -4747,12 +4824,12 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev)
* the PHYs will link their interrupts to these interrupt
* controllers
*/
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (chip->irq > 0)
err = mv88e6xxx_g1_irq_setup(chip);
else
err = mv88e6xxx_irq_poll_setup(chip);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err)
goto out;
@@ -4837,6 +4914,10 @@ static const struct of_device_id mv88e6xxx_of_match[] = {
.compatible = "marvell,mv88e6190",
.data = &mv88e6xxx_table[MV88E6190],
},
+ {
+ .compatible = "marvell,mv88e6250",
+ .data = &mv88e6xxx_table[MV88E6250],
+ },
{ /* sentinel */ },
};
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index d3e10111a6fe..4646e46d47f2 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -58,6 +58,7 @@ enum mv88e6xxx_model {
MV88E6190X,
MV88E6191,
MV88E6240,
+ MV88E6250,
MV88E6290,
MV88E6320,
MV88E6321,
@@ -76,6 +77,7 @@ enum mv88e6xxx_family {
MV88E6XXX_FAMILY_6097, /* 6046 6085 6096 6097 */
MV88E6XXX_FAMILY_6165, /* 6123 6161 6165 */
MV88E6XXX_FAMILY_6185, /* 6108 6121 6122 6131 6152 6155 6182 6185 */
+ MV88E6XXX_FAMILY_6250, /* 6250 */
MV88E6XXX_FAMILY_6320, /* 6320 6321 */
MV88E6XXX_FAMILY_6341, /* 6141 6341 */
MV88E6XXX_FAMILY_6351, /* 6171 6175 6350 6351 */
@@ -108,6 +110,12 @@ struct mv88e6xxx_info {
* when it is non-zero, and use indirect access to internal registers.
*/
bool multi_chip;
+ /* Dual-chip Addressing Mode
+ * Some chips respond to only half of the 32 SMI addresses,
+ * allowing two to coexist on the same SMI interface.
+ */
+ bool dual_chip;
+
enum dsa_tag_protocol tag_protocol;
/* Mask for FromPort and ToPort value of PortVec used in ATU Move
@@ -572,4 +580,14 @@ int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, int link,
phy_interface_t mode);
struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip);
+static inline void mv88e6xxx_reg_lock(struct mv88e6xxx_chip *chip)
+{
+ mutex_lock(&chip->reg_lock);
+}
+
+static inline void mv88e6xxx_reg_unlock(struct mv88e6xxx_chip *chip)
+{
+ mutex_unlock(&chip->reg_lock);
+}
+
#endif /* _MV88E6XXX_CHIP_H */
diff --git a/drivers/net/dsa/mv88e6xxx/global1.c b/drivers/net/dsa/mv88e6xxx/global1.c
index 09b8a3d0dd37..1323ef30a5e9 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.c
+++ b/drivers/net/dsa/mv88e6xxx/global1.c
@@ -178,7 +178,7 @@ int mv88e6185_g1_reset(struct mv88e6xxx_chip *chip)
return mv88e6185_g1_wait_ppu_polling(chip);
}
-int mv88e6352_g1_reset(struct mv88e6xxx_chip *chip)
+int mv88e6250_g1_reset(struct mv88e6xxx_chip *chip)
{
u16 val;
int err;
@@ -194,7 +194,14 @@ int mv88e6352_g1_reset(struct mv88e6xxx_chip *chip)
if (err)
return err;
- err = mv88e6xxx_g1_wait_init_ready(chip);
+ return mv88e6xxx_g1_wait_init_ready(chip);
+}
+
+int mv88e6352_g1_reset(struct mv88e6xxx_chip *chip)
+{
+ int err;
+
+ err = mv88e6250_g1_reset(chip);
if (err)
return err;
@@ -295,6 +302,12 @@ int mv88e6085_g1_ieee_pri_map(struct mv88e6xxx_chip *chip)
return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IEEE_PRI, 0xfa41);
}
+int mv88e6250_g1_ieee_pri_map(struct mv88e6xxx_chip *chip)
+{
+ /* Reset the IEEE Tag priorities to defaults */
+ return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IEEE_PRI, 0xfa50);
+}
+
/* Offset 0x1a: Monitor Control */
/* Offset 0x1a: Monitor & MGMT Control on some devices */
@@ -375,26 +388,26 @@ int mv88e6390_g1_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
u16 ptr;
int err;
- /* 01:c2:80:00:00:00:00-01:c2:80:00:00:00:07 are Management */
- ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C280000000XLO;
+ /* 01:80:c2:00:00:00-01:80:c2:00:00:07 are Management */
+ ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C200000XLO;
err = mv88e6390_g1_monitor_write(chip, ptr, 0xff);
if (err)
return err;
- /* 01:c2:80:00:00:00:08-01:c2:80:00:00:00:0f are Management */
- ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C280000000XHI;
+ /* 01:80:c2:00:00:08-01:80:c2:00:00:0f are Management */
+ ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C200000XHI;
err = mv88e6390_g1_monitor_write(chip, ptr, 0xff);
if (err)
return err;
- /* 01:c2:80:00:00:00:20-01:c2:80:00:00:00:27 are Management */
- ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C280000002XLO;
+ /* 01:80:c2:00:00:20-01:80:c2:00:00:27 are Management */
+ ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C200002XLO;
err = mv88e6390_g1_monitor_write(chip, ptr, 0xff);
if (err)
return err;
- /* 01:c2:80:00:00:00:28-01:c2:80:00:00:00:2f are Management */
- ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C280000002XHI;
+ /* 01:80:c2:00:00:28-01:80:c2:00:00:2f are Management */
+ ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C200002XHI;
err = mv88e6390_g1_monitor_write(chip, ptr, 0xff);
if (err)
return err;
@@ -461,7 +474,7 @@ int mv88e6xxx_g1_set_device_number(struct mv88e6xxx_chip *chip, int index)
/* Offset 0x1d: Statistics Operation 2 */
-int mv88e6xxx_g1_stats_wait(struct mv88e6xxx_chip *chip)
+static int mv88e6xxx_g1_stats_wait(struct mv88e6xxx_chip *chip)
{
return mv88e6xxx_g1_wait(chip, MV88E6XXX_G1_STATS_OP,
MV88E6XXX_G1_STATS_OP_BUSY);
diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h
index 7bd5ab733a3f..d444266f7d78 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.h
+++ b/drivers/net/dsa/mv88e6xxx/global1.h
@@ -186,10 +186,10 @@
#define MV88E6390_G1_MONITOR_MGMT_CTL 0x1a
#define MV88E6390_G1_MONITOR_MGMT_CTL_UPDATE 0x8000
#define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_MASK 0x3f00
-#define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C280000000XLO 0x0000
-#define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C280000000XHI 0x0100
-#define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C280000002XLO 0x0200
-#define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C280000002XHI 0x0300
+#define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C200000XLO 0x0000
+#define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C200000XHI 0x0100
+#define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C200002XLO 0x0200
+#define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C200002XHI 0x0300
#define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_INGRESS_DEST 0x2000
#define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_EGRESS_DEST 0x2100
#define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_CPU_DEST 0x3000
@@ -255,11 +255,11 @@ int mv88e6xxx_g1_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr);
int mv88e6185_g1_reset(struct mv88e6xxx_chip *chip);
int mv88e6352_g1_reset(struct mv88e6xxx_chip *chip);
+int mv88e6250_g1_reset(struct mv88e6xxx_chip *chip);
int mv88e6185_g1_ppu_enable(struct mv88e6xxx_chip *chip);
int mv88e6185_g1_ppu_disable(struct mv88e6xxx_chip *chip);
-int mv88e6xxx_g1_stats_wait(struct mv88e6xxx_chip *chip);
int mv88e6xxx_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port);
int mv88e6320_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port);
int mv88e6390_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port);
@@ -274,7 +274,9 @@ int mv88e6390_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port);
int mv88e6390_g1_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip);
int mv88e6085_g1_ip_pri_map(struct mv88e6xxx_chip *chip);
+
int mv88e6085_g1_ieee_pri_map(struct mv88e6xxx_chip *chip);
+int mv88e6250_g1_ieee_pri_map(struct mv88e6xxx_chip *chip);
int mv88e6185_g1_set_cascade_port(struct mv88e6xxx_chip *chip, int port);
@@ -301,6 +303,10 @@ int mv88e6185_g1_vtu_getnext(struct mv88e6xxx_chip *chip,
struct mv88e6xxx_vtu_entry *entry);
int mv88e6185_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip,
struct mv88e6xxx_vtu_entry *entry);
+int mv88e6250_g1_vtu_getnext(struct mv88e6xxx_chip *chip,
+ struct mv88e6xxx_vtu_entry *entry);
+int mv88e6250_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip,
+ struct mv88e6xxx_vtu_entry *entry);
int mv88e6352_g1_vtu_getnext(struct mv88e6xxx_chip *chip,
struct mv88e6xxx_vtu_entry *entry);
int mv88e6352_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip,
diff --git a/drivers/net/dsa/mv88e6xxx/global1_atu.c b/drivers/net/dsa/mv88e6xxx/global1_atu.c
index 4542dfa5fc69..1cf388e9bd94 100644
--- a/drivers/net/dsa/mv88e6xxx/global1_atu.c
+++ b/drivers/net/dsa/mv88e6xxx/global1_atu.c
@@ -90,7 +90,7 @@ static int mv88e6xxx_g1_atu_op(struct mv88e6xxx_chip *chip, u16 fid, u16 op)
if (err)
return err;
} else {
- if (mv88e6xxx_num_databases(chip) > 16) {
+ if (mv88e6xxx_num_databases(chip) > 64) {
/* ATU DBNum[7:4] are located in ATU Control 15:12 */
err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL,
&val);
@@ -102,6 +102,9 @@ static int mv88e6xxx_g1_atu_op(struct mv88e6xxx_chip *chip, u16 fid, u16 op)
val);
if (err)
return err;
+ } else if (mv88e6xxx_num_databases(chip) > 16) {
+ /* ATU DBNum[5:4] are located in ATU Operation 9:8 */
+ op |= (fid & 0x30) << 4;
}
/* ATU DBNum[3:0] are located in ATU Operation 3:0 */
@@ -314,7 +317,7 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
int err;
u16 val;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_g1_atu_op(chip, 0,
MV88E6XXX_G1_ATU_OP_GET_CLR_VIOLATION);
@@ -361,12 +364,12 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
entry.mac, entry.portvec, spid);
chip->ports[spid].atu_full_violation++;
}
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return IRQ_HANDLED;
out:
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
dev_err(chip->dev, "ATU problem: error %d while handling interrupt\n",
err);
diff --git a/drivers/net/dsa/mv88e6xxx/global1_vtu.c b/drivers/net/dsa/mv88e6xxx/global1_vtu.c
index 3e9be3f51196..6cac997360e8 100644
--- a/drivers/net/dsa/mv88e6xxx/global1_vtu.c
+++ b/drivers/net/dsa/mv88e6xxx/global1_vtu.c
@@ -303,6 +303,35 @@ static int mv88e6xxx_g1_vtu_getnext(struct mv88e6xxx_chip *chip,
return mv88e6xxx_g1_vtu_vid_read(chip, entry);
}
+int mv88e6250_g1_vtu_getnext(struct mv88e6xxx_chip *chip,
+ struct mv88e6xxx_vtu_entry *entry)
+{
+ u16 val;
+ int err;
+
+ err = mv88e6xxx_g1_vtu_getnext(chip, entry);
+ if (err)
+ return err;
+
+ if (entry->valid) {
+ err = mv88e6185_g1_vtu_data_read(chip, entry);
+ if (err)
+ return err;
+
+ /* VTU DBNum[3:0] are located in VTU Operation 3:0
+ * VTU DBNum[5:4] are located in VTU Operation 9:8
+ */
+ err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_OP, &val);
+ if (err)
+ return err;
+
+ entry->fid = val & 0x000f;
+ entry->fid |= (val & 0x0300) >> 4;
+ }
+
+ return 0;
+}
+
int mv88e6185_g1_vtu_getnext(struct mv88e6xxx_chip *chip,
struct mv88e6xxx_vtu_entry *entry)
{
@@ -392,6 +421,35 @@ int mv88e6390_g1_vtu_getnext(struct mv88e6xxx_chip *chip,
return 0;
}
+int mv88e6250_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip,
+ struct mv88e6xxx_vtu_entry *entry)
+{
+ u16 op = MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE;
+ int err;
+
+ err = mv88e6xxx_g1_vtu_op_wait(chip);
+ if (err)
+ return err;
+
+ err = mv88e6xxx_g1_vtu_vid_write(chip, entry);
+ if (err)
+ return err;
+
+ if (entry->valid) {
+ err = mv88e6185_g1_vtu_data_write(chip, entry);
+ if (err)
+ return err;
+
+ /* VTU DBNum[3:0] are located in VTU Operation 3:0
+ * VTU DBNum[5:4] are located in VTU Operation 9:8
+ */
+ op |= entry->fid & 0x000f;
+ op |= (entry->fid & 0x0030) << 4;
+ }
+
+ return mv88e6xxx_g1_vtu_op(chip, op);
+}
+
int mv88e6185_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip,
struct mv88e6xxx_vtu_entry *entry)
{
@@ -415,7 +473,7 @@ int mv88e6185_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip,
* VTU DBNum[7:4] are located in VTU Operation 11:8
*/
op |= entry->fid & 0x000f;
- op |= (entry->fid & 0x00f0) << 8;
+ op |= (entry->fid & 0x00f0) << 4;
}
return mv88e6xxx_g1_vtu_op(chip, op);
@@ -521,7 +579,7 @@ static irqreturn_t mv88e6xxx_g1_vtu_prob_irq_thread_fn(int irq, void *dev_id)
int err;
u16 val;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_GET_CLR_VIOLATION);
if (err)
@@ -549,12 +607,12 @@ static irqreturn_t mv88e6xxx_g1_vtu_prob_irq_thread_fn(int irq, void *dev_id)
chip->ports[spid].vtu_miss_violation++;
}
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return IRQ_HANDLED;
out:
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
dev_err(chip->dev, "VTU problem: error %d while handling interrupt\n",
err);
diff --git a/drivers/net/dsa/mv88e6xxx/global2.c b/drivers/net/dsa/mv88e6xxx/global2.c
index 1546171210a1..2305b94b3051 100644
--- a/drivers/net/dsa/mv88e6xxx/global2.c
+++ b/drivers/net/dsa/mv88e6xxx/global2.c
@@ -812,6 +812,32 @@ const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops = {
.irq_free = mv88e6097_watchdog_free,
};
+static void mv88e6250_watchdog_free(struct mv88e6xxx_chip *chip)
+{
+ u16 reg;
+
+ mv88e6xxx_g2_read(chip, MV88E6250_G2_WDOG_CTL, &reg);
+
+ reg &= ~(MV88E6250_G2_WDOG_CTL_EGRESS_ENABLE |
+ MV88E6250_G2_WDOG_CTL_QC_ENABLE);
+
+ mv88e6xxx_g2_write(chip, MV88E6250_G2_WDOG_CTL, reg);
+}
+
+static int mv88e6250_watchdog_setup(struct mv88e6xxx_chip *chip)
+{
+ return mv88e6xxx_g2_write(chip, MV88E6250_G2_WDOG_CTL,
+ MV88E6250_G2_WDOG_CTL_EGRESS_ENABLE |
+ MV88E6250_G2_WDOG_CTL_QC_ENABLE |
+ MV88E6250_G2_WDOG_CTL_SWRESET);
+}
+
+const struct mv88e6xxx_irq_ops mv88e6250_watchdog_ops = {
+ .irq_action = mv88e6097_watchdog_action,
+ .irq_setup = mv88e6250_watchdog_setup,
+ .irq_free = mv88e6250_watchdog_free,
+};
+
static int mv88e6390_watchdog_setup(struct mv88e6xxx_chip *chip)
{
return mv88e6xxx_g2_update(chip, MV88E6390_G2_WDOG_CTL,
@@ -867,20 +893,20 @@ static irqreturn_t mv88e6xxx_g2_watchdog_thread_fn(int irq, void *dev_id)
struct mv88e6xxx_chip *chip = dev_id;
irqreturn_t ret = IRQ_NONE;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (chip->info->ops->watchdog_ops->irq_action)
ret = chip->info->ops->watchdog_ops->irq_action(chip, irq);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return ret;
}
static void mv88e6xxx_g2_watchdog_free(struct mv88e6xxx_chip *chip)
{
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (chip->info->ops->watchdog_ops->irq_free)
chip->info->ops->watchdog_ops->irq_free(chip);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
free_irq(chip->watchdog_irq, chip);
irq_dispose_mapping(chip->watchdog_irq);
@@ -902,10 +928,10 @@ static int mv88e6xxx_g2_watchdog_setup(struct mv88e6xxx_chip *chip)
if (err)
return err;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (chip->info->ops->watchdog_ops->irq_setup)
err = chip->info->ops->watchdog_ops->irq_setup(chip);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -960,9 +986,9 @@ static irqreturn_t mv88e6xxx_g2_irq_thread_fn(int irq, void *dev_id)
int err;
u16 reg;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_g2_int_source(chip, &reg);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err)
goto out;
@@ -981,7 +1007,7 @@ static void mv88e6xxx_g2_irq_bus_lock(struct irq_data *d)
{
struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
}
static void mv88e6xxx_g2_irq_bus_sync_unlock(struct irq_data *d)
@@ -993,7 +1019,7 @@ static void mv88e6xxx_g2_irq_bus_sync_unlock(struct irq_data *d)
if (err)
dev_err(chip->dev, "failed to mask interrupts\n");
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
}
static const struct irq_chip mv88e6xxx_g2_irq_chip = {
diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h
index bfb2c6123f55..a664fc25f132 100644
--- a/drivers/net/dsa/mv88e6xxx/global2.h
+++ b/drivers/net/dsa/mv88e6xxx/global2.h
@@ -202,6 +202,18 @@
#define MV88E6XXX_G2_SCRATCH_MISC_DATA_MASK 0x00ff
/* Offset 0x1B: Watch Dog Control Register */
+#define MV88E6250_G2_WDOG_CTL 0x1b
+#define MV88E6250_G2_WDOG_CTL_QC_HISTORY 0x0100
+#define MV88E6250_G2_WDOG_CTL_QC_EVENT 0x0080
+#define MV88E6250_G2_WDOG_CTL_QC_ENABLE 0x0040
+#define MV88E6250_G2_WDOG_CTL_EGRESS_HISTORY 0x0020
+#define MV88E6250_G2_WDOG_CTL_EGRESS_EVENT 0x0010
+#define MV88E6250_G2_WDOG_CTL_EGRESS_ENABLE 0x0008
+#define MV88E6250_G2_WDOG_CTL_FORCE_IRQ 0x0004
+#define MV88E6250_G2_WDOG_CTL_HISTORY 0x0002
+#define MV88E6250_G2_WDOG_CTL_SWRESET 0x0001
+
+/* Offset 0x1B: Watch Dog Control Register */
#define MV88E6352_G2_WDOG_CTL 0x1b
#define MV88E6352_G2_WDOG_CTL_EGRESS_EVENT 0x0080
#define MV88E6352_G2_WDOG_CTL_RMU_TIMEOUT 0x0040
@@ -330,6 +342,7 @@ int mv88e6xxx_g2_device_mapping_write(struct mv88e6xxx_chip *chip, int target,
int port);
extern const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops;
+extern const struct mv88e6xxx_irq_ops mv88e6250_watchdog_ops;
extern const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops;
extern const struct mv88e6xxx_avb_ops mv88e6165_avb_ops;
@@ -480,6 +493,7 @@ static inline int mv88e6xxx_g2_pot_clear(struct mv88e6xxx_chip *chip)
}
static const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops = {};
+static const struct mv88e6xxx_irq_ops mv88e6250_watchdog_ops = {};
static const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops = {};
static const struct mv88e6xxx_avb_ops mv88e6165_avb_ops = {};
diff --git a/drivers/net/dsa/mv88e6xxx/hwtstamp.c b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
index 7f95a636561d..a4c488b12e8f 100644
--- a/drivers/net/dsa/mv88e6xxx/hwtstamp.c
+++ b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
@@ -147,7 +147,7 @@ static int mv88e6xxx_set_hwtstamp_config(struct mv88e6xxx_chip *chip, int port,
return -ERANGE;
}
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (tstamp_enable) {
chip->enable_count += 1;
if (chip->enable_count == 1 && ptp_ops->global_enable)
@@ -161,7 +161,7 @@ static int mv88e6xxx_set_hwtstamp_config(struct mv88e6xxx_chip *chip, int port,
if (chip->enable_count == 0 && ptp_ops->global_disable)
ptp_ops->global_disable(chip);
}
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
/* Once hardware has been configured, enable timestamp checks
* in the RX/TX paths.
@@ -301,10 +301,10 @@ static void mv88e6xxx_get_rxts(struct mv88e6xxx_chip *chip,
skb_queue_splice_tail_init(rxq, &received);
spin_unlock_irqrestore(&rxq->lock, flags);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_ptp_read(chip, ps->port_id,
reg, buf, ARRAY_SIZE(buf));
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err)
pr_err("failed to get the receive time stamp\n");
@@ -314,9 +314,9 @@ static void mv88e6xxx_get_rxts(struct mv88e6xxx_chip *chip,
seq_id = buf[3];
if (status & MV88E6XXX_PTP_TS_VALID) {
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_ptp_write(chip, ps->port_id, reg, 0);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err)
pr_err("failed to clear the receive status\n");
}
@@ -327,9 +327,9 @@ static void mv88e6xxx_get_rxts(struct mv88e6xxx_chip *chip,
if (mv88e6xxx_ts_valid(status) && seq_match(skb, seq_id)) {
ns = timehi << 16 | timelo;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
ns = timecounter_cyc2time(&chip->tstamp_tc, ns);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
shwt = skb_hwtstamps(skb);
memset(shwt, 0, sizeof(*shwt));
shwt->hwtstamp = ns_to_ktime(ns);
@@ -405,12 +405,12 @@ static int mv88e6xxx_txtstamp_work(struct mv88e6xxx_chip *chip,
if (!ps->tx_skb)
return 0;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_ptp_read(chip, ps->port_id,
ptp_ops->dep_sts_reg,
departure_block,
ARRAY_SIZE(departure_block));
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err)
goto free_and_clear_skb;
@@ -430,9 +430,9 @@ static int mv88e6xxx_txtstamp_work(struct mv88e6xxx_chip *chip,
}
/* We have the timestamp; go ahead and clear valid now */
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
mv88e6xxx_port_ptp_write(chip, ps->port_id, ptp_ops->dep_sts_reg, 0);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
status = departure_block[0] & MV88E6XXX_PTP_TS_STATUS_MASK;
if (status != MV88E6XXX_PTP_TS_STATUS_NORMAL) {
@@ -447,9 +447,9 @@ static int mv88e6xxx_txtstamp_work(struct mv88e6xxx_chip *chip,
memset(&shhwtstamps, 0, sizeof(shhwtstamps));
time_raw = ((u32)departure_block[2] << 16) | departure_block[1];
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
ns = timecounter_cyc2time(&chip->tstamp_tc, time_raw);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
shhwtstamps.hwtstamp = ns_to_ktime(ns);
dev_dbg(chip->dev,
diff --git a/drivers/net/dsa/mv88e6xxx/phy.c b/drivers/net/dsa/mv88e6xxx/phy.c
index 2952db73f55c..252b5b3a3efe 100644
--- a/drivers/net/dsa/mv88e6xxx/phy.c
+++ b/drivers/net/dsa/mv88e6xxx/phy.c
@@ -137,7 +137,7 @@ static void mv88e6xxx_phy_ppu_reenable_work(struct work_struct *ugly)
chip = container_of(ugly, struct mv88e6xxx_chip, ppu_work);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (mutex_trylock(&chip->ppu_mutex)) {
if (mv88e6xxx_phy_ppu_enable(chip) == 0)
@@ -145,7 +145,7 @@ static void mv88e6xxx_phy_ppu_reenable_work(struct work_struct *ugly)
mutex_unlock(&chip->ppu_mutex);
}
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
}
static void mv88e6xxx_phy_ppu_reenable_timer(struct timer_list *t)
diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c
index 9a2b4b385a2c..04309ef0a1cc 100644
--- a/drivers/net/dsa/mv88e6xxx/port.c
+++ b/drivers/net/dsa/mv88e6xxx/port.c
@@ -290,6 +290,18 @@ int mv88e6185_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
return mv88e6xxx_port_set_speed(chip, port, speed, false, false);
}
+/* Support 10, 100 Mbps (e.g. 88E6250 family) */
+int mv88e6250_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
+{
+ if (speed == SPEED_MAX)
+ speed = 100;
+
+ if (speed > 100)
+ return -EOPNOTSUPP;
+
+ return mv88e6xxx_port_set_speed(chip, port, speed, false, false);
+}
+
/* Support 10, 100, 200, 1000, 2500 Mbps (e.g. 88E6341) */
int mv88e6341_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
{
@@ -517,6 +529,71 @@ int mv88e6352_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode)
return 0;
}
+int mv88e6250_port_link_state(struct mv88e6xxx_chip *chip, int port,
+ struct phylink_link_state *state)
+{
+ int err;
+ u16 reg;
+
+ err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
+ if (err)
+ return err;
+
+ if (port < 5) {
+ switch (reg & MV88E6250_PORT_STS_PORTMODE_MASK) {
+ case MV88E6250_PORT_STS_PORTMODE_PHY_10_HALF:
+ state->speed = SPEED_10;
+ state->duplex = DUPLEX_HALF;
+ break;
+ case MV88E6250_PORT_STS_PORTMODE_PHY_100_HALF:
+ state->speed = SPEED_100;
+ state->duplex = DUPLEX_HALF;
+ break;
+ case MV88E6250_PORT_STS_PORTMODE_PHY_10_FULL:
+ state->speed = SPEED_10;
+ state->duplex = DUPLEX_FULL;
+ break;
+ case MV88E6250_PORT_STS_PORTMODE_PHY_100_FULL:
+ state->speed = SPEED_100;
+ state->duplex = DUPLEX_FULL;
+ break;
+ default:
+ state->speed = SPEED_UNKNOWN;
+ state->duplex = DUPLEX_UNKNOWN;
+ break;
+ }
+ } else {
+ switch (reg & MV88E6250_PORT_STS_PORTMODE_MASK) {
+ case MV88E6250_PORT_STS_PORTMODE_MII_10_HALF:
+ state->speed = SPEED_10;
+ state->duplex = DUPLEX_HALF;
+ break;
+ case MV88E6250_PORT_STS_PORTMODE_MII_100_HALF:
+ state->speed = SPEED_100;
+ state->duplex = DUPLEX_HALF;
+ break;
+ case MV88E6250_PORT_STS_PORTMODE_MII_10_FULL:
+ state->speed = SPEED_10;
+ state->duplex = DUPLEX_FULL;
+ break;
+ case MV88E6250_PORT_STS_PORTMODE_MII_100_FULL:
+ state->speed = SPEED_100;
+ state->duplex = DUPLEX_FULL;
+ break;
+ default:
+ state->speed = SPEED_UNKNOWN;
+ state->duplex = DUPLEX_UNKNOWN;
+ break;
+ }
+ }
+
+ state->link = !!(reg & MV88E6250_PORT_STS_LINK);
+ state->an_enabled = 1;
+ state->an_complete = state->link;
+
+ return 0;
+}
+
int mv88e6352_port_link_state(struct mv88e6xxx_chip *chip, int port,
struct phylink_link_state *state)
{
diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h
index f2fba3f73199..8d5a6cd6fb19 100644
--- a/drivers/net/dsa/mv88e6xxx/port.h
+++ b/drivers/net/dsa/mv88e6xxx/port.h
@@ -19,6 +19,16 @@
#define MV88E6XXX_PORT_STS_MY_PAUSE 0x4000
#define MV88E6XXX_PORT_STS_HD_FLOW 0x2000
#define MV88E6XXX_PORT_STS_PHY_DETECT 0x1000
+#define MV88E6250_PORT_STS_LINK 0x1000
+#define MV88E6250_PORT_STS_PORTMODE_MASK 0x0f00
+#define MV88E6250_PORT_STS_PORTMODE_PHY_10_HALF 0x0800
+#define MV88E6250_PORT_STS_PORTMODE_PHY_100_HALF 0x0900
+#define MV88E6250_PORT_STS_PORTMODE_PHY_10_FULL 0x0a00
+#define MV88E6250_PORT_STS_PORTMODE_PHY_100_FULL 0x0b00
+#define MV88E6250_PORT_STS_PORTMODE_MII_10_HALF 0x0c00
+#define MV88E6250_PORT_STS_PORTMODE_MII_100_HALF 0x0d00
+#define MV88E6250_PORT_STS_PORTMODE_MII_10_FULL 0x0e00
+#define MV88E6250_PORT_STS_PORTMODE_MII_100_FULL 0x0f00
#define MV88E6XXX_PORT_STS_LINK 0x0800
#define MV88E6XXX_PORT_STS_DUPLEX 0x0400
#define MV88E6XXX_PORT_STS_SPEED_MASK 0x0300
@@ -108,6 +118,7 @@
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6191 0x1910
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6185 0x1a70
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6240 0x2400
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6250 0x2500
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6290 0x2900
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6321 0x3100
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6141 0x3400
@@ -275,6 +286,7 @@ int mv88e6xxx_port_set_duplex(struct mv88e6xxx_chip *chip, int port, int dup);
int mv88e6065_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed);
int mv88e6185_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed);
+int mv88e6250_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed);
int mv88e6341_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed);
int mv88e6352_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed);
int mv88e6390_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed);
@@ -328,6 +340,8 @@ int mv88e6185_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
int mv88e6352_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
int mv88e6185_port_link_state(struct mv88e6xxx_chip *chip, int port,
struct phylink_link_state *state);
+int mv88e6250_port_link_state(struct mv88e6xxx_chip *chip, int port,
+ struct phylink_link_state *state);
int mv88e6352_port_link_state(struct mv88e6xxx_chip *chip, int port,
struct phylink_link_state *state);
int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port);
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.c b/drivers/net/dsa/mv88e6xxx/ptp.c
index 7b40c5886b75..768d256f7c9f 100644
--- a/drivers/net/dsa/mv88e6xxx/ptp.c
+++ b/drivers/net/dsa/mv88e6xxx/ptp.c
@@ -138,10 +138,10 @@ static void mv88e6352_tai_event_work(struct work_struct *ugly)
u32 raw_ts;
int err;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_tai_read(chip, MV88E6XXX_TAI_EVENT_STATUS,
status, ARRAY_SIZE(status));
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err) {
dev_err(chip->dev, "failed to read TAI status register\n");
@@ -158,18 +158,18 @@ static void mv88e6352_tai_event_work(struct work_struct *ugly)
/* Clear the valid bit so the next timestamp can come in */
status[0] &= ~MV88E6XXX_TAI_EVENT_STATUS_VALID;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_tai_write(chip, MV88E6XXX_TAI_EVENT_STATUS, status[0]);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
/* This is an external timestamp */
ev.type = PTP_CLOCK_EXTTS;
/* We only have one timestamping channel. */
ev.index = 0;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
ev.timestamp = timecounter_cyc2time(&chip->tstamp_tc, raw_ts);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
ptp_clock_event(chip->ptp_clock, &ev);
out:
@@ -192,12 +192,12 @@ static int mv88e6xxx_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
adj *= scaled_ppm;
diff = div_u64(adj, CC_MULT_DEM);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
timecounter_read(&chip->tstamp_tc);
chip->tstamp_cc.mult = neg_adj ? mult - diff : mult + diff;
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return 0;
}
@@ -206,9 +206,9 @@ static int mv88e6xxx_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
{
struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
timecounter_adjtime(&chip->tstamp_tc, delta);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return 0;
}
@@ -219,9 +219,9 @@ static int mv88e6xxx_ptp_gettime(struct ptp_clock_info *ptp,
struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
u64 ns;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
ns = timecounter_read(&chip->tstamp_tc);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
*ts = ns_to_timespec64(ns);
@@ -236,9 +236,9 @@ static int mv88e6xxx_ptp_settime(struct ptp_clock_info *ptp,
ns = timespec64_to_ns(ts);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
timecounter_init(&chip->tstamp_tc, &chip->tstamp_cc, ns);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return 0;
}
@@ -256,7 +256,7 @@ static int mv88e6352_ptp_enable_extts(struct mv88e6xxx_chip *chip,
if (pin < 0)
return -EBUSY;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (on) {
func = MV88E6352_G2_SCRATCH_GPIO_PCTL_EVREQ;
@@ -278,7 +278,7 @@ static int mv88e6352_ptp_enable_extts(struct mv88e6xxx_chip *chip,
}
out:
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c
index d986c5d55bf1..20c526c2a9ee 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.c
+++ b/drivers/net/dsa/mv88e6xxx/serdes.c
@@ -208,7 +208,7 @@ static irqreturn_t mv88e6352_serdes_thread_fn(int irq, void *dev_id)
u16 status;
int err;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6352_serdes_read(chip, MV88E6352_SERDES_INT_STATUS, &status);
if (err)
@@ -219,7 +219,7 @@ static irqreturn_t mv88e6352_serdes_thread_fn(int irq, void *dev_id)
mv88e6352_serdes_irq_link(chip, port->port);
}
out:
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return ret;
}
@@ -253,12 +253,12 @@ int mv88e6352_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port)
/* Requesting the IRQ will trigger irq callbacks. So we cannot
* hold the reg_lock.
*/
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
err = request_threaded_irq(chip->ports[port].serdes_irq, NULL,
mv88e6352_serdes_thread_fn,
IRQF_ONESHOT, "mv88e6xxx-serdes",
&chip->ports[port]);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (err) {
dev_err(chip->dev, "Unable to request SERDES interrupt: %d\n",
@@ -279,9 +279,9 @@ void mv88e6352_serdes_irq_free(struct mv88e6xxx_chip *chip, int port)
/* Freeing the IRQ will trigger irq callbacks. So we cannot
* hold the reg_lock.
*/
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
free_irq(chip->ports[port].serdes_irq, &chip->ports[port]);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
chip->ports[port].serdes_irq = 0;
}
@@ -621,7 +621,7 @@ static irqreturn_t mv88e6390_serdes_thread_fn(int irq, void *dev_id)
lane = mv88e6390x_serdes_get_lane(chip, port->port);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
switch (cmode) {
case MV88E6XXX_PORT_STS_CMODE_SGMII:
@@ -637,7 +637,7 @@ static irqreturn_t mv88e6390_serdes_thread_fn(int irq, void *dev_id)
}
}
out:
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return ret;
}
@@ -666,12 +666,12 @@ int mv88e6390x_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port)
/* Requesting the IRQ will trigger irq callbacks. So we cannot
* hold the reg_lock.
*/
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
err = request_threaded_irq(chip->ports[port].serdes_irq, NULL,
mv88e6390_serdes_thread_fn,
IRQF_ONESHOT, "mv88e6xxx-serdes",
&chip->ports[port]);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (err) {
dev_err(chip->dev, "Unable to request SERDES interrupt: %d\n",
@@ -705,9 +705,9 @@ void mv88e6390x_serdes_irq_free(struct mv88e6xxx_chip *chip, int port)
/* Freeing the IRQ will trigger irq callbacks. So we cannot
* hold the reg_lock.
*/
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
free_irq(chip->ports[port].serdes_irq, &chip->ports[port]);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
chip->ports[port].serdes_irq = 0;
}
diff --git a/drivers/net/dsa/mv88e6xxx/smi.c b/drivers/net/dsa/mv88e6xxx/smi.c
index 92e9324f1fb9..5fc78a063843 100644
--- a/drivers/net/dsa/mv88e6xxx/smi.c
+++ b/drivers/net/dsa/mv88e6xxx/smi.c
@@ -20,6 +20,10 @@
* When ADDR is non-zero, the chip uses Multi-chip Addressing Mode, allowing
* multiple devices to share the SMI interface. In this mode it responds to only
* 2 registers, used to indirectly access the internal SMI devices.
+ *
+ * Some chips use a different scheme: Only the ADDR4 pin is used for
+ * configuration, and the device responds to 16 of the 32 SMI
+ * addresses, allowing two to coexist on the same SMI interface.
*/
static int mv88e6xxx_smi_direct_read(struct mv88e6xxx_chip *chip,
@@ -72,6 +76,23 @@ static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_direct_ops = {
.write = mv88e6xxx_smi_direct_write,
};
+static int mv88e6xxx_smi_dual_direct_read(struct mv88e6xxx_chip *chip,
+ int dev, int reg, u16 *data)
+{
+ return mv88e6xxx_smi_direct_read(chip, chip->sw_addr + dev, reg, data);
+}
+
+static int mv88e6xxx_smi_dual_direct_write(struct mv88e6xxx_chip *chip,
+ int dev, int reg, u16 data)
+{
+ return mv88e6xxx_smi_direct_write(chip, chip->sw_addr + dev, reg, data);
+}
+
+static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_dual_direct_ops = {
+ .read = mv88e6xxx_smi_dual_direct_read,
+ .write = mv88e6xxx_smi_dual_direct_write,
+};
+
/* Offset 0x00: SMI Command Register
* Offset 0x01: SMI Data Register
*/
@@ -140,7 +161,9 @@ static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_indirect_ops = {
int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip,
struct mii_bus *bus, int sw_addr)
{
- if (sw_addr == 0)
+ if (chip->info->dual_chip)
+ chip->smi_ops = &mv88e6xxx_smi_dual_direct_ops;
+ else if (sw_addr == 0)
chip->smi_ops = &mv88e6xxx_smi_direct_ops;
else if (chip->info->multi_chip)
chip->smi_ops = &mv88e6xxx_smi_indirect_ops;
diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c
index c4fa400efdcc..232e8cc96f6d 100644
--- a/drivers/net/dsa/qca8k.c
+++ b/drivers/net/dsa/qca8k.c
@@ -14,6 +14,7 @@
#include <linux/of_platform.h>
#include <linux/if_bridge.h>
#include <linux/mdio.h>
+#include <linux/gpio/consumer.h>
#include <linux/etherdevice.h>
#include "qca8k.h"
@@ -1046,6 +1047,20 @@ qca8k_sw_probe(struct mdio_device *mdiodev)
priv->bus = mdiodev->bus;
priv->dev = &mdiodev->dev;
+ priv->reset_gpio = devm_gpiod_get_optional(priv->dev, "reset",
+ GPIOD_ASIS);
+ if (IS_ERR(priv->reset_gpio))
+ return PTR_ERR(priv->reset_gpio);
+
+ if (priv->reset_gpio) {
+ gpiod_set_value_cansleep(priv->reset_gpio, 1);
+ /* The active low duration must be greater than 10 ms
+ * and checkpatch.pl wants 20 ms.
+ */
+ msleep(20);
+ gpiod_set_value_cansleep(priv->reset_gpio, 0);
+ }
+
/* read the switches ID register */
id = qca8k_read(priv, QCA8K_REG_MASK_CTRL);
id >>= QCA8K_MASK_CTRL_ID_S;
diff --git a/drivers/net/dsa/qca8k.h b/drivers/net/dsa/qca8k.h
index 91557433ce2f..42d6ea24eb14 100644
--- a/drivers/net/dsa/qca8k.h
+++ b/drivers/net/dsa/qca8k.h
@@ -10,6 +10,7 @@
#include <linux/delay.h>
#include <linux/regmap.h>
+#include <linux/gpio.h>
#define QCA8K_NUM_PORTS 7
@@ -174,6 +175,7 @@ struct qca8k_priv {
struct mutex reg_mutex;
struct device *dev;
struct dsa_switch_ops ops;
+ struct gpio_desc *reset_gpio;
};
struct qca8k_mib_desc {
diff --git a/drivers/net/dsa/realtek-smi.c b/drivers/net/dsa/realtek-smi-core.c
index ad41ec63cc9f..dc0509c02d29 100644
--- a/drivers/net/dsa/realtek-smi.c
+++ b/drivers/net/dsa/realtek-smi-core.c
@@ -40,7 +40,7 @@
#include <linux/bitops.h>
#include <linux/if_bridge.h>
-#include "realtek-smi.h"
+#include "realtek-smi-core.h"
#define REALTEK_SMI_ACK_RETRY_COUNT 5
#define REALTEK_SMI_HW_STOP_DELAY 25 /* msecs */
diff --git a/drivers/net/dsa/realtek-smi.h b/drivers/net/dsa/realtek-smi-core.h
index 9a63b51e1d82..9a63b51e1d82 100644
--- a/drivers/net/dsa/realtek-smi.h
+++ b/drivers/net/dsa/realtek-smi-core.h
diff --git a/drivers/net/dsa/rtl8366.c b/drivers/net/dsa/rtl8366.c
index 6dedd43442cc..ca3d17e43ed8 100644
--- a/drivers/net/dsa/rtl8366.c
+++ b/drivers/net/dsa/rtl8366.c
@@ -11,7 +11,7 @@
#include <linux/if_bridge.h>
#include <net/dsa.h>
-#include "realtek-smi.h"
+#include "realtek-smi-core.h"
int rtl8366_mc_is_used(struct realtek_smi *smi, int mc_index, int *used)
{
@@ -307,7 +307,8 @@ int rtl8366_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering)
struct rtl8366_vlan_4k vlan4k;
int ret;
- if (!smi->ops->is_vlan_valid(smi, port))
+ /* Use VLAN nr port + 1 since VLAN0 is not valid */
+ if (!smi->ops->is_vlan_valid(smi, port + 1))
return -EINVAL;
dev_info(smi->dev, "%s filtering on port %d\n",
@@ -318,12 +319,12 @@ int rtl8366_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering)
* The hardware support filter ID (FID) 0..7, I have no clue how to
* support this in the driver when the callback only says on/off.
*/
- ret = smi->ops->get_vlan_4k(smi, port, &vlan4k);
+ ret = smi->ops->get_vlan_4k(smi, port + 1, &vlan4k);
if (ret)
return ret;
/* Just set the filter to FID 1 for now then */
- ret = rtl8366_set_vlan(smi, port,
+ ret = rtl8366_set_vlan(smi, port + 1,
vlan4k.member,
vlan4k.untag,
1);
diff --git a/drivers/net/dsa/rtl8366rb.c b/drivers/net/dsa/rtl8366rb.c
index 40b3974970c6..a268085ffad2 100644
--- a/drivers/net/dsa/rtl8366rb.c
+++ b/drivers/net/dsa/rtl8366rb.c
@@ -20,7 +20,7 @@
#include <linux/of_irq.h>
#include <linux/regmap.h>
-#include "realtek-smi.h"
+#include "realtek-smi-core.h"
#define RTL8366RB_PORT_NUM_CPU 5
#define RTL8366RB_NUM_PORTS 6
diff --git a/drivers/net/dsa/sja1105/Kconfig b/drivers/net/dsa/sja1105/Kconfig
index 1144fc5f61a8..770134a66e48 100644
--- a/drivers/net/dsa/sja1105/Kconfig
+++ b/drivers/net/dsa/sja1105/Kconfig
@@ -9,10 +9,17 @@ tristate "NXP SJA1105 Ethernet switch family support"
This is the driver for the NXP SJA1105 automotive Ethernet switch
family. These are 5-port devices and are managed over an SPI
interface. Probing is handled based on OF bindings and so is the
- linkage to phylib. The driver supports the following revisions:
+ linkage to PHYLINK. The driver supports the following revisions:
- SJA1105E (Gen. 1, No TT-Ethernet)
- SJA1105T (Gen. 1, TT-Ethernet)
- SJA1105P (Gen. 2, No SGMII, No TT-Ethernet)
- SJA1105Q (Gen. 2, No SGMII, TT-Ethernet)
- SJA1105R (Gen. 2, SGMII, No TT-Ethernet)
- SJA1105S (Gen. 2, SGMII, TT-Ethernet)
+
+config NET_DSA_SJA1105_PTP
+ bool "Support for the PTP clock on the NXP SJA1105 Ethernet switch"
+ depends on NET_DSA_SJA1105
+ help
+ This enables support for timestamping and PTP clock manipulations in
+ the SJA1105 DSA driver.
diff --git a/drivers/net/dsa/sja1105/Makefile b/drivers/net/dsa/sja1105/Makefile
index 941848de8b46..4483113e6259 100644
--- a/drivers/net/dsa/sja1105/Makefile
+++ b/drivers/net/dsa/sja1105/Makefile
@@ -8,3 +8,7 @@ sja1105-objs := \
sja1105_clocking.o \
sja1105_static_config.o \
sja1105_dynamic_config.o \
+
+ifdef CONFIG_NET_DSA_SJA1105_PTP
+sja1105-objs += sja1105_ptp.o
+endif
diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h
index b043bfc408f2..78094db32622 100644
--- a/drivers/net/dsa/sja1105/sja1105.h
+++ b/drivers/net/dsa/sja1105/sja1105.h
@@ -5,6 +5,8 @@
#ifndef _SJA1105_H
#define _SJA1105_H
+#include <linux/ptp_clock_kernel.h>
+#include <linux/timecounter.h>
#include <linux/dsa/sja1105.h>
#include <net/dsa.h>
#include <linux/mutex.h>
@@ -27,9 +29,14 @@ struct sja1105_regs {
u64 rgu;
u64 config;
u64 rmii_pll1;
+ u64 ptp_control;
+ u64 ptpclk;
+ u64 ptpclkrate;
+ u64 ptptsclk;
+ u64 ptpegr_ts[SJA1105_NUM_PORTS];
u64 pad_mii_tx[SJA1105_NUM_PORTS];
+ u64 pad_mii_id[SJA1105_NUM_PORTS];
u64 cgu_idiv[SJA1105_NUM_PORTS];
- u64 rgmii_pad_mii_tx[SJA1105_NUM_PORTS];
u64 mii_tx_clk[SJA1105_NUM_PORTS];
u64 mii_rx_clk[SJA1105_NUM_PORTS];
u64 mii_ext_tx_clk[SJA1105_NUM_PORTS];
@@ -50,11 +57,26 @@ struct sja1105_info {
* switch core and device_id)
*/
u64 part_no;
+ /* E/T and P/Q/R/S have partial timestamps of different sizes.
+ * They must be reconstructed on both families anyway to get the full
+ * 64-bit values back.
+ */
+ int ptp_ts_bits;
+ /* Also SPI commands are of different sizes to retrieve
+ * the egress timestamps.
+ */
+ int ptpegr_ts_bytes;
const struct sja1105_dynamic_table_ops *dyn_ops;
const struct sja1105_table_ops *static_ops;
const struct sja1105_regs *regs;
+ int (*ptp_cmd)(const void *ctx, const void *data);
int (*reset_cmd)(const void *ctx, const void *data);
int (*setup_rgmii_delay)(const void *ctx, int port);
+ /* Prototypes from include/net/dsa.h */
+ int (*fdb_add_cmd)(struct dsa_switch *ds, int port,
+ const unsigned char *addr, u16 vid);
+ int (*fdb_del_cmd)(struct dsa_switch *ds, int port,
+ const unsigned char *addr, u16 vid);
const char *name;
};
@@ -67,13 +89,25 @@ struct sja1105_private {
struct spi_device *spidev;
struct dsa_switch *ds;
struct sja1105_port ports[SJA1105_NUM_PORTS];
+ struct ptp_clock_info ptp_caps;
+ struct ptp_clock *clock;
+ /* The cycle counter translates the PTP timestamps (based on
+ * a free-running counter) into a software time domain.
+ */
+ struct cyclecounter tstamp_cc;
+ struct timecounter tstamp_tc;
+ struct delayed_work refresh_work;
+ /* Serializes all operations on the cycle counter */
+ struct mutex ptp_lock;
/* Serializes transmission of management frames so that
* the switch doesn't confuse them with one another.
*/
struct mutex mgmt_lock;
+ struct sja1105_tagger_data tagger_data;
};
#include "sja1105_dynamic_config.h"
+#include "sja1105_ptp.h"
struct sja1105_spi_message {
u64 access;
@@ -97,6 +131,8 @@ int sja1105_spi_send_long_packed_buf(const struct sja1105_private *priv,
sja1105_spi_rw_mode_t rw, u64 base_addr,
void *packed_buf, u64 buf_len);
int sja1105_static_config_upload(struct sja1105_private *priv);
+int sja1105_inhibit_tx(const struct sja1105_private *priv,
+ unsigned long port_bitmap, bool tx_inhibited);
extern struct sja1105_info sja1105e_info;
extern struct sja1105_info sja1105t_info;
@@ -125,6 +161,7 @@ typedef enum {
SJA1105_SPEED_AUTO = 0,
} sja1105_speed_t;
+int sja1105pqrs_setup_rgmii_delay(const void *ctx, int port);
int sja1105_clocking_setup_port(struct sja1105_private *priv, int port);
int sja1105_clocking_setup(struct sja1105_private *priv);
@@ -142,7 +179,20 @@ int sja1105_dynamic_config_write(struct sja1105_private *priv,
enum sja1105_blk_idx blk_idx,
int index, void *entry, bool keep);
-u8 sja1105_fdb_hash(struct sja1105_private *priv, const u8 *addr, u16 vid);
+enum sja1105_iotag {
+ SJA1105_C_TAG = 0, /* Inner VLAN header */
+ SJA1105_S_TAG = 1, /* Outer VLAN header */
+};
+
+u8 sja1105et_fdb_hash(struct sja1105_private *priv, const u8 *addr, u16 vid);
+int sja1105et_fdb_add(struct dsa_switch *ds, int port,
+ const unsigned char *addr, u16 vid);
+int sja1105et_fdb_del(struct dsa_switch *ds, int port,
+ const unsigned char *addr, u16 vid);
+int sja1105pqrs_fdb_add(struct dsa_switch *ds, int port,
+ const unsigned char *addr, u16 vid);
+int sja1105pqrs_fdb_del(struct dsa_switch *ds, int port,
+ const unsigned char *addr, u16 vid);
/* Common implementations for the static and dynamic configs */
size_t sja1105_l2_forwarding_entry_packing(void *buf, void *entry_ptr,
diff --git a/drivers/net/dsa/sja1105/sja1105_clocking.c b/drivers/net/dsa/sja1105/sja1105_clocking.c
index 94bfe0ee50a8..608126a15d72 100644
--- a/drivers/net/dsa/sja1105/sja1105_clocking.c
+++ b/drivers/net/dsa/sja1105/sja1105_clocking.c
@@ -19,6 +19,17 @@ struct sja1105_cfg_pad_mii_tx {
u64 clk_ipud;
};
+struct sja1105_cfg_pad_mii_id {
+ u64 rxc_stable_ovr;
+ u64 rxc_delay;
+ u64 rxc_bypass;
+ u64 rxc_pd;
+ u64 txc_stable_ovr;
+ u64 txc_delay;
+ u64 txc_bypass;
+ u64 txc_pd;
+};
+
/* UM10944 Table 82.
* IDIV_0_C to IDIV_4_C control registers
* (addr. 10000Bh to 10000Fh)
@@ -373,11 +384,88 @@ static int sja1105_rgmii_cfg_pad_tx_config(struct sja1105_private *priv,
sja1105_cfg_pad_mii_tx_packing(packed_buf, &pad_mii_tx, PACK);
return sja1105_spi_send_packed_buf(priv, SPI_WRITE,
- regs->rgmii_pad_mii_tx[port],
+ regs->pad_mii_tx[port],
packed_buf, SJA1105_SIZE_CGU_CMD);
}
-static int sja1105_rgmii_clocking_setup(struct sja1105_private *priv, int port)
+static void
+sja1105_cfg_pad_mii_id_packing(void *buf, struct sja1105_cfg_pad_mii_id *cmd,
+ enum packing_op op)
+{
+ const int size = SJA1105_SIZE_CGU_CMD;
+
+ sja1105_packing(buf, &cmd->rxc_stable_ovr, 15, 15, size, op);
+ sja1105_packing(buf, &cmd->rxc_delay, 14, 10, size, op);
+ sja1105_packing(buf, &cmd->rxc_bypass, 9, 9, size, op);
+ sja1105_packing(buf, &cmd->rxc_pd, 8, 8, size, op);
+ sja1105_packing(buf, &cmd->txc_stable_ovr, 7, 7, size, op);
+ sja1105_packing(buf, &cmd->txc_delay, 6, 2, size, op);
+ sja1105_packing(buf, &cmd->txc_bypass, 1, 1, size, op);
+ sja1105_packing(buf, &cmd->txc_pd, 0, 0, size, op);
+}
+
+/* Valid range in degrees is an integer between 73.8 and 101.7 */
+static inline u64 sja1105_rgmii_delay(u64 phase)
+{
+ /* UM11040.pdf: The delay in degree phase is 73.8 + delay_tune * 0.9.
+ * To avoid floating point operations we'll multiply by 10
+ * and get 1 decimal point precision.
+ */
+ phase *= 10;
+ return (phase - 738) / 9;
+}
+
+/* The RGMII delay setup procedure is 2-step and gets called upon each
+ * .phylink_mac_config. Both are strategic.
+ * The reason is that the RX Tunable Delay Line of the SJA1105 MAC has issues
+ * with recovering from a frequency change of the link partner's RGMII clock.
+ * The easiest way to recover from this is to temporarily power down the TDL,
+ * as it will re-lock at the new frequency afterwards.
+ */
+int sja1105pqrs_setup_rgmii_delay(const void *ctx, int port)
+{
+ const struct sja1105_private *priv = ctx;
+ const struct sja1105_regs *regs = priv->info->regs;
+ struct sja1105_cfg_pad_mii_id pad_mii_id = {0};
+ u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+ int rc;
+
+ if (priv->rgmii_rx_delay[port])
+ pad_mii_id.rxc_delay = sja1105_rgmii_delay(90);
+ if (priv->rgmii_tx_delay[port])
+ pad_mii_id.txc_delay = sja1105_rgmii_delay(90);
+
+ /* Stage 1: Turn the RGMII delay lines off. */
+ pad_mii_id.rxc_bypass = 1;
+ pad_mii_id.rxc_pd = 1;
+ pad_mii_id.txc_bypass = 1;
+ pad_mii_id.txc_pd = 1;
+ sja1105_cfg_pad_mii_id_packing(packed_buf, &pad_mii_id, PACK);
+
+ rc = sja1105_spi_send_packed_buf(priv, SPI_WRITE,
+ regs->pad_mii_id[port],
+ packed_buf, SJA1105_SIZE_CGU_CMD);
+ if (rc < 0)
+ return rc;
+
+ /* Stage 2: Turn the RGMII delay lines on. */
+ if (priv->rgmii_rx_delay[port]) {
+ pad_mii_id.rxc_bypass = 0;
+ pad_mii_id.rxc_pd = 0;
+ }
+ if (priv->rgmii_tx_delay[port]) {
+ pad_mii_id.txc_bypass = 0;
+ pad_mii_id.txc_pd = 0;
+ }
+ sja1105_cfg_pad_mii_id_packing(packed_buf, &pad_mii_id, PACK);
+
+ return sja1105_spi_send_packed_buf(priv, SPI_WRITE,
+ regs->pad_mii_id[port],
+ packed_buf, SJA1105_SIZE_CGU_CMD);
+}
+
+static int sja1105_rgmii_clocking_setup(struct sja1105_private *priv, int port,
+ sja1105_mii_role_t role)
{
struct device *dev = priv->ds->dev;
struct sja1105_mac_config_entry *mac;
@@ -429,6 +517,12 @@ static int sja1105_rgmii_clocking_setup(struct sja1105_private *priv, int port)
}
if (!priv->info->setup_rgmii_delay)
return 0;
+ /* The role has no hardware effect for RGMII. However we use it as
+ * a proxy for this interface being a MAC-to-MAC connection, with
+ * the RGMII internal delays needing to be applied by us.
+ */
+ if (role == XMII_MAC)
+ return 0;
return priv->info->setup_rgmii_delay(priv, port);
}
@@ -575,7 +669,7 @@ int sja1105_clocking_setup_port(struct sja1105_private *priv, int port)
rc = sja1105_rmii_clocking_setup(priv, port, role);
break;
case XMII_MODE_RGMII:
- rc = sja1105_rgmii_clocking_setup(priv, port);
+ rc = sja1105_rgmii_clocking_setup(priv, port, role);
break;
default:
dev_err(dev, "Invalid interface mode specified: %d\n",
diff --git a/drivers/net/dsa/sja1105/sja1105_dynamic_config.c b/drivers/net/dsa/sja1105/sja1105_dynamic_config.c
index e73ab28bf632..6bfb1696a6f2 100644
--- a/drivers/net/dsa/sja1105/sja1105_dynamic_config.c
+++ b/drivers/net/dsa/sja1105/sja1105_dynamic_config.c
@@ -3,6 +3,98 @@
*/
#include "sja1105.h"
+/* In the dynamic configuration interface, the switch exposes a register-like
+ * view of some of the static configuration tables.
+ * Many times the field organization of the dynamic tables is abbreviated (not
+ * all fields are dynamically reconfigurable) and different from the static
+ * ones, but the key reason for having it is that we can spare a switch reset
+ * for settings that can be changed dynamically.
+ *
+ * This file creates a per-switch-family abstraction called
+ * struct sja1105_dynamic_table_ops and two operations that work with it:
+ * - sja1105_dynamic_config_write
+ * - sja1105_dynamic_config_read
+ *
+ * Compared to the struct sja1105_table_ops from sja1105_static_config.c,
+ * the dynamic accessors work with a compound buffer:
+ *
+ * packed_buf
+ *
+ * |
+ * V
+ * +-----------------------------------------+------------------+
+ * | ENTRY BUFFER | COMMAND BUFFER |
+ * +-----------------------------------------+------------------+
+ *
+ * <----------------------- packed_size ------------------------>
+ *
+ * The ENTRY BUFFER may or may not have the same layout, or size, as its static
+ * configuration table entry counterpart. When it does, the same packing
+ * function is reused (bar exceptional cases - see
+ * sja1105pqrs_dyn_l2_lookup_entry_packing).
+ *
+ * The reason for the COMMAND BUFFER being at the end is to be able to send
+ * a dynamic write command through a single SPI burst. By the time the switch
+ * reacts to the command, the ENTRY BUFFER is already populated with the data
+ * sent by the core.
+ *
+ * The COMMAND BUFFER is always SJA1105_SIZE_DYN_CMD bytes (one 32-bit word) in
+ * size.
+ *
+ * Sometimes the ENTRY BUFFER does not really exist (when the number of fields
+ * that can be reconfigured is small), then the switch repurposes some of the
+ * unused 32 bits of the COMMAND BUFFER to hold ENTRY data.
+ *
+ * The key members of struct sja1105_dynamic_table_ops are:
+ * - .entry_packing: A function that deals with packing an ENTRY structure
+ * into an SPI buffer, or retrieving an ENTRY structure
+ * from one.
+ * The @packed_buf pointer it's given does always point to
+ * the ENTRY portion of the buffer.
+ * - .cmd_packing: A function that deals with packing/unpacking the COMMAND
+ * structure to/from the SPI buffer.
+ * It is given the same @packed_buf pointer as .entry_packing,
+ * so most of the time, the @packed_buf points *behind* the
+ * COMMAND offset inside the buffer.
+ * To access the COMMAND portion of the buffer, the function
+ * knows its correct offset.
+ * Giving both functions the same pointer is handy because in
+ * extreme cases (see sja1105pqrs_dyn_l2_lookup_entry_packing)
+ * the .entry_packing is able to jump to the COMMAND portion,
+ * or vice-versa (sja1105pqrs_l2_lookup_cmd_packing).
+ * - .access: A bitmap of:
+ * OP_READ: Set if the hardware manual marks the ENTRY portion of the
+ * dynamic configuration table buffer as R (readable) after
+ * an SPI read command (the switch will populate the buffer).
+ * OP_WRITE: Set if the manual marks the ENTRY portion of the dynamic
+ * table buffer as W (writable) after an SPI write command
+ * (the switch will read the fields provided in the buffer).
+ * OP_DEL: Set if the manual says the VALIDENT bit is supported in the
+ * COMMAND portion of this dynamic config buffer (i.e. the
+ * specified entry can be invalidated through a SPI write
+ * command).
+ * OP_SEARCH: Set if the manual says that the index of an entry can
+ * be retrieved in the COMMAND portion of the buffer based
+ * on its ENTRY portion, as a result of a SPI write command.
+ * Only the TCAM-based FDB table on SJA1105 P/Q/R/S supports
+ * this.
+ * - .max_entry_count: The number of entries, counting from zero, that can be
+ * reconfigured through the dynamic interface. If a static
+ * table can be reconfigured at all dynamically, this
+ * number always matches the maximum number of supported
+ * static entries.
+ * - .packed_size: The length in bytes of the compound ENTRY + COMMAND BUFFER.
+ * Note that sometimes the compound buffer may contain holes in
+ * it (see sja1105_vlan_lookup_cmd_packing). The @packed_buf is
+ * contiguous however, so @packed_size includes any unused
+ * bytes.
+ * - .addr: The base SPI address at which the buffer must be written to the
+ * switch's memory. When looking at the hardware manual, this must
+ * always match the lowest documented address for the ENTRY, and not
+ * that of the COMMAND, since the other 32-bit words will follow along
+ * at the correct addresses.
+ */
+
#define SJA1105_SIZE_DYN_CMD 4
#define SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY \
@@ -35,17 +127,70 @@
#define SJA1105_MAX_DYN_CMD_SIZE \
SJA1105PQRS_SIZE_MAC_CONFIG_DYN_CMD
+struct sja1105_dyn_cmd {
+ bool search;
+ u64 valid;
+ u64 rdwrset;
+ u64 errors;
+ u64 valident;
+ u64 index;
+};
+
+enum sja1105_hostcmd {
+ SJA1105_HOSTCMD_SEARCH = 1,
+ SJA1105_HOSTCMD_READ = 2,
+ SJA1105_HOSTCMD_WRITE = 3,
+ SJA1105_HOSTCMD_INVALIDATE = 4,
+};
+
static void
sja1105pqrs_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
enum packing_op op)
{
u8 *p = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
const int size = SJA1105_SIZE_DYN_CMD;
+ u64 hostcmd;
sja1105_packing(p, &cmd->valid, 31, 31, size, op);
sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
sja1105_packing(p, &cmd->errors, 29, 29, size, op);
sja1105_packing(p, &cmd->valident, 27, 27, size, op);
+
+ /* VALIDENT is supposed to indicate "keep or not", but in SJA1105 E/T,
+ * using it to delete a management route was unsupported. UM10944
+ * said about it:
+ *
+ * In case of a write access with the MGMTROUTE flag set,
+ * the flag will be ignored. It will always be found cleared
+ * for read accesses with the MGMTROUTE flag set.
+ *
+ * SJA1105 P/Q/R/S keeps the same behavior w.r.t. VALIDENT, but there
+ * is now another flag called HOSTCMD which does more stuff (quoting
+ * from UM11040):
+ *
+ * A write request is accepted only when HOSTCMD is set to write host
+ * or invalid. A read request is accepted only when HOSTCMD is set to
+ * search host or read host.
+ *
+ * So it is possible to translate a RDWRSET/VALIDENT combination into
+ * HOSTCMD so that we keep the dynamic command API in place, and
+ * at the same time achieve compatibility with the management route
+ * command structure.
+ */
+ if (cmd->rdwrset == SPI_READ) {
+ if (cmd->search)
+ hostcmd = SJA1105_HOSTCMD_SEARCH;
+ else
+ hostcmd = SJA1105_HOSTCMD_READ;
+ } else {
+ /* SPI_WRITE */
+ if (cmd->valident)
+ hostcmd = SJA1105_HOSTCMD_WRITE;
+ else
+ hostcmd = SJA1105_HOSTCMD_INVALIDATE;
+ }
+ sja1105_packing(p, &hostcmd, 25, 23, size, op);
+
/* Hack - The hardware takes the 'index' field within
* struct sja1105_l2_lookup_entry as the index on which this command
* will operate. However it will ignore everything else, so 'index'
@@ -54,9 +199,66 @@ sja1105pqrs_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
* such that our API doesn't need to ask for a full-blown entry
* structure when e.g. a delete is requested.
*/
- sja1105_packing(buf, &cmd->index, 29, 20,
+ sja1105_packing(buf, &cmd->index, 15, 6,
SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY, op);
- /* TODO hostcmd */
+}
+
+/* The switch is so retarded that it makes our command/entry abstraction
+ * crumble apart.
+ *
+ * On P/Q/R/S, the switch tries to say whether a FDB entry
+ * is statically programmed or dynamically learned via a flag called LOCKEDS.
+ * The hardware manual says about this fiels:
+ *
+ * On write will specify the format of ENTRY.
+ * On read the flag will be found cleared at times the VALID flag is found
+ * set. The flag will also be found cleared in response to a read having the
+ * MGMTROUTE flag set. In response to a read with the MGMTROUTE flag
+ * cleared, the flag be set if the most recent access operated on an entry
+ * that was either loaded by configuration or through dynamic reconfiguration
+ * (as opposed to automatically learned entries).
+ *
+ * The trouble with this flag is that it's part of the *command* to access the
+ * dynamic interface, and not part of the *entry* retrieved from it.
+ * Otherwise said, for a sja1105_dynamic_config_read, LOCKEDS is supposed to be
+ * an output from the switch into the command buffer, and for a
+ * sja1105_dynamic_config_write, the switch treats LOCKEDS as an input
+ * (hence we can write either static, or automatically learned entries, from
+ * the core).
+ * But the manual contradicts itself in the last phrase where it says that on
+ * read, LOCKEDS will be set to 1 for all FDB entries written through the
+ * dynamic interface (therefore, the value of LOCKEDS from the
+ * sja1105_dynamic_config_write is not really used for anything, it'll store a
+ * 1 anyway).
+ * This means you can't really write a FDB entry with LOCKEDS=0 (automatically
+ * learned) into the switch, which kind of makes sense.
+ * As for reading through the dynamic interface, it doesn't make too much sense
+ * to put LOCKEDS into the command, since the switch will inevitably have to
+ * ignore it (otherwise a command would be like "read the FDB entry 123, but
+ * only if it's dynamically learned" <- well how am I supposed to know?) and
+ * just use it as an output buffer for its findings. But guess what... that's
+ * what the entry buffer is for!
+ * Unfortunately, what really breaks this abstraction is the fact that it
+ * wasn't designed having the fact in mind that the switch can output
+ * entry-related data as writeback through the command buffer.
+ * However, whether a FDB entry is statically or dynamically learned *is* part
+ * of the entry and not the command data, no matter what the switch thinks.
+ * In order to do that, we'll need to wrap around the
+ * sja1105pqrs_l2_lookup_entry_packing from sja1105_static_config.c, and take
+ * a peek outside of the caller-supplied @buf (the entry buffer), to reach the
+ * command buffer.
+ */
+static size_t
+sja1105pqrs_dyn_l2_lookup_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ struct sja1105_l2_lookup_entry *entry = entry_ptr;
+ u8 *cmd = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
+ const int size = SJA1105_SIZE_DYN_CMD;
+
+ sja1105_packing(cmd, &entry->lockeds, 28, 28, size, op);
+
+ return sja1105pqrs_l2_lookup_entry_packing(buf, entry_ptr, op);
}
static void
@@ -107,6 +309,36 @@ static size_t sja1105et_mgmt_route_entry_packing(void *buf, void *entry_ptr,
return size;
}
+static void
+sja1105pqrs_mgmt_route_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
+ enum packing_op op)
+{
+ u8 *p = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
+ u64 mgmtroute = 1;
+
+ sja1105pqrs_l2_lookup_cmd_packing(buf, cmd, op);
+ if (op == PACK)
+ sja1105_pack(p, &mgmtroute, 26, 26, SJA1105_SIZE_DYN_CMD);
+}
+
+static size_t sja1105pqrs_mgmt_route_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ const size_t size = SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
+ struct sja1105_mgmt_entry *entry = entry_ptr;
+
+ /* In P/Q/R/S, enfport got renamed to mgmtvalid, but its purpose
+ * is the same (driver uses it to confirm that frame was sent).
+ * So just keep the name from E/T.
+ */
+ sja1105_packing(buf, &entry->tsreg, 71, 71, size, op);
+ sja1105_packing(buf, &entry->takets, 70, 70, size, op);
+ sja1105_packing(buf, &entry->macaddr, 69, 22, size, op);
+ sja1105_packing(buf, &entry->destports, 21, 17, size, op);
+ sja1105_packing(buf, &entry->enfport, 16, 16, size, op);
+ return size;
+}
+
/* In E/T, entry is at addresses 0x27-0x28. There is a 4 byte gap at 0x29,
* and command is at 0x2a. Similarly in P/Q/R/S there is a 1 register gap
* between entry (0x2d, 0x2e) and command (0x30).
@@ -240,6 +472,7 @@ sja1105et_general_params_entry_packing(void *buf, void *entry_ptr,
#define OP_READ BIT(0)
#define OP_WRITE BIT(1)
#define OP_DEL BIT(2)
+#define OP_SEARCH BIT(3)
/* SJA1105E/T: First generation */
struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = {
@@ -293,6 +526,7 @@ struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = {
.addr = 0x38,
},
[BLK_IDX_L2_FORWARDING_PARAMS] = {0},
+ [BLK_IDX_AVB_PARAMS] = {0},
[BLK_IDX_GENERAL_PARAMS] = {
.entry_packing = sja1105et_general_params_entry_packing,
.cmd_packing = sja1105et_general_params_cmd_packing,
@@ -304,14 +538,22 @@ struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = {
[BLK_IDX_XMII_PARAMS] = {0},
};
-/* SJA1105P/Q/R/S: Second generation: TODO */
+/* SJA1105P/Q/R/S: Second generation */
struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = {
[BLK_IDX_L2_LOOKUP] = {
- .entry_packing = sja1105pqrs_l2_lookup_entry_packing,
+ .entry_packing = sja1105pqrs_dyn_l2_lookup_entry_packing,
.cmd_packing = sja1105pqrs_l2_lookup_cmd_packing,
- .access = (OP_READ | OP_WRITE | OP_DEL),
+ .access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH),
.max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT,
- .packed_size = SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD,
+ .packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD,
+ .addr = 0x24,
+ },
+ [BLK_IDX_MGMT_ROUTE] = {
+ .entry_packing = sja1105pqrs_mgmt_route_entry_packing,
+ .cmd_packing = sja1105pqrs_mgmt_route_cmd_packing,
+ .access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH),
+ .max_entry_count = SJA1105_NUM_PORTS,
+ .packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD,
.addr = 0x24,
},
[BLK_IDX_L2_POLICING] = {0},
@@ -348,6 +590,7 @@ struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = {
.addr = 0x38,
},
[BLK_IDX_L2_FORWARDING_PARAMS] = {0},
+ [BLK_IDX_AVB_PARAMS] = {0},
[BLK_IDX_GENERAL_PARAMS] = {
.entry_packing = sja1105et_general_params_entry_packing,
.cmd_packing = sja1105et_general_params_cmd_packing,
@@ -359,6 +602,24 @@ struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = {
[BLK_IDX_XMII_PARAMS] = {0},
};
+/* Provides read access to the settings through the dynamic interface
+ * of the switch.
+ * @blk_idx is used as key to select from the sja1105_dynamic_table_ops.
+ * The selection is limited by the hardware in respect to which
+ * configuration blocks can be read through the dynamic interface.
+ * @index is used to retrieve a particular table entry. If negative,
+ * (and if the @blk_idx supports the searching operation) a search
+ * is performed by the @entry parameter.
+ * @entry Type-casted to an unpacked structure that holds a table entry
+ * of the type specified in @blk_idx.
+ * Usually an output argument. If @index is negative, then this
+ * argument is used as input/output: it should be pre-populated
+ * with the element to search for. Entries which support the
+ * search operation will have an "index" field (not the @index
+ * argument to this function) and that is where the found index
+ * will be returned (or left unmodified - thus negative - if not
+ * found).
+ */
int sja1105_dynamic_config_read(struct sja1105_private *priv,
enum sja1105_blk_idx blk_idx,
int index, void *entry)
@@ -375,8 +636,10 @@ int sja1105_dynamic_config_read(struct sja1105_private *priv,
ops = &priv->info->dyn_ops[blk_idx];
- if (index >= ops->max_entry_count)
+ if (index >= 0 && index >= ops->max_entry_count)
return -ERANGE;
+ if (index < 0 && !(ops->access & OP_SEARCH))
+ return -EOPNOTSUPP;
if (!(ops->access & OP_READ))
return -EOPNOTSUPP;
if (ops->packed_size > SJA1105_MAX_DYN_CMD_SIZE)
@@ -388,9 +651,20 @@ int sja1105_dynamic_config_read(struct sja1105_private *priv,
cmd.valid = true; /* Trigger action on table entry */
cmd.rdwrset = SPI_READ; /* Action is read */
- cmd.index = index;
+ if (index < 0) {
+ /* Avoid copying a signed negative number to an u64 */
+ cmd.index = 0;
+ cmd.search = true;
+ } else {
+ cmd.index = index;
+ cmd.search = false;
+ }
+ cmd.valident = true;
ops->cmd_packing(packed_buf, &cmd, PACK);
+ if (cmd.search)
+ ops->entry_packing(packed_buf, entry, PACK);
+
/* Send SPI write operation: read config table entry */
rc = sja1105_spi_send_packed_buf(priv, SPI_WRITE, ops->addr,
packed_buf, ops->packed_size);
@@ -416,7 +690,7 @@ int sja1105_dynamic_config_read(struct sja1105_private *priv,
* So don't error out in that case.
*/
if (!cmd.valident && blk_idx != BLK_IDX_MGMT_ROUTE)
- return -EINVAL;
+ return -ENOENT;
cpu_relax();
} while (cmd.valid && --retries);
@@ -448,6 +722,8 @@ int sja1105_dynamic_config_write(struct sja1105_private *priv,
if (index >= ops->max_entry_count)
return -ERANGE;
+ if (index < 0)
+ return -ERANGE;
if (!(ops->access & OP_WRITE))
return -EOPNOTSUPP;
if (!keep && !(ops->access & OP_DEL))
@@ -510,7 +786,7 @@ static u8 sja1105_crc8_add(u8 crc, u8 byte, u8 poly)
* is also received as argument in the Koopman notation that the switch
* hardware stores it in.
*/
-u8 sja1105_fdb_hash(struct sja1105_private *priv, const u8 *addr, u16 vid)
+u8 sja1105et_fdb_hash(struct sja1105_private *priv, const u8 *addr, u16 vid)
{
struct sja1105_l2_lookup_params_entry *l2_lookup_params =
priv->static_config.tables[BLK_IDX_L2_LOOKUP_PARAMS].entries;
diff --git a/drivers/net/dsa/sja1105/sja1105_dynamic_config.h b/drivers/net/dsa/sja1105/sja1105_dynamic_config.h
index 77be59546a55..740dadf43f01 100644
--- a/drivers/net/dsa/sja1105/sja1105_dynamic_config.h
+++ b/drivers/net/dsa/sja1105/sja1105_dynamic_config.h
@@ -7,13 +7,10 @@
#include "sja1105.h"
#include <linux/packing.h>
-struct sja1105_dyn_cmd {
- u64 valid;
- u64 rdwrset;
- u64 errors;
- u64 valident;
- u64 index;
-};
+/* Special index that can be used for sja1105_dynamic_config_read */
+#define SJA1105_SEARCH -1
+
+struct sja1105_dyn_cmd;
struct sja1105_dynamic_table_ops {
/* This returns size_t just to keep same prototype as the
diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c
index 1c3959efebc4..32bf3a7cc3b6 100644
--- a/drivers/net/dsa/sja1105/sja1105_main.c
+++ b/drivers/net/dsa/sja1105/sja1105_main.c
@@ -70,8 +70,7 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv)
/* Keep standard IFG of 12 bytes on egress. */
.ifg = 0,
/* Always put the MAC speed in automatic mode, where it can be
- * retrieved from the PHY object through phylib and
- * sja1105_adjust_port_config.
+ * adjusted at runtime by PHYLINK.
*/
.speed = SJA1105_SPEED_AUTO,
/* No static correction for 1-step 1588 events */
@@ -81,7 +80,7 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv)
.maxage = 0xFF,
/* Internal VLAN (pvid) to apply to untagged ingress */
.vlanprio = 0,
- .vlanid = 0,
+ .vlanid = 1,
.ing_mirr = false,
.egr_mirr = false,
/* Don't drop traffic with other EtherType than ETH_P_IP */
@@ -116,7 +115,6 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv)
if (!table->entries)
return -ENOMEM;
- /* Override table based on phylib DT bindings */
table->entry_count = SJA1105_NUM_PORTS;
mac = table->entries;
@@ -157,7 +155,7 @@ static int sja1105_init_mii_settings(struct sja1105_private *priv,
if (!table->entries)
return -ENOMEM;
- /* Override table based on phylib DT bindings */
+ /* Override table based on PHYLINK DT bindings */
table->entry_count = SJA1105_MAX_XMII_PARAMS_COUNT;
mii = table->entries;
@@ -205,11 +203,16 @@ static int sja1105_init_static_fdb(struct sja1105_private *priv)
static int sja1105_init_l2_lookup_params(struct sja1105_private *priv)
{
struct sja1105_table *table;
+ u64 max_fdb_entries = SJA1105_MAX_L2_LOOKUP_COUNT / SJA1105_NUM_PORTS;
struct sja1105_l2_lookup_params_entry default_l2_lookup_params = {
/* Learned FDB entries are forgotten after 300 seconds */
.maxage = SJA1105_AGEING_TIME_MS(300000),
/* All entries within a FDB bin are available for learning */
.dyn_tbsz = SJA1105ET_FDB_BIN_SIZE,
+ /* And the P/Q/R/S equivalent setting: */
+ .start_dynspc = 0,
+ .maxaddrp = {max_fdb_entries, max_fdb_entries, max_fdb_entries,
+ max_fdb_entries, max_fdb_entries, },
/* 2^8 + 2^5 + 2^3 + 2^2 + 2^1 + 1 in Koopman notation */
.poly = 0x97,
/* This selects between Independent VLAN Learning (IVL) and
@@ -225,6 +228,13 @@ static int sja1105_init_l2_lookup_params(struct sja1105_private *priv)
* Maybe correlate with no_linklocal_learn from bridge driver?
*/
.no_mgmt_learn = true,
+ /* P/Q/R/S only */
+ .use_static = true,
+ /* Dynamically learned FDB entries can overwrite other (older)
+ * dynamic FDB entries
+ */
+ .owr_dyn = true,
+ .drpnolearn = true,
};
table = &priv->static_config.tables[BLK_IDX_L2_LOOKUP_PARAMS];
@@ -257,20 +267,15 @@ static int sja1105_init_static_vlan(struct sja1105_private *priv)
.vmemb_port = 0,
.vlan_bc = 0,
.tag_port = 0,
- .vlanid = 0,
+ .vlanid = 1,
};
int i;
table = &priv->static_config.tables[BLK_IDX_VLAN_LOOKUP];
- /* The static VLAN table will only contain the initial pvid of 0.
+ /* The static VLAN table will only contain the initial pvid of 1.
* All other VLANs are to be configured through dynamic entries,
* and kept in the static configuration table as backing memory.
- * The pvid of 0 is sufficient to pass traffic while the ports are
- * standalone and when vlan_filtering is disabled. When filtering
- * gets enabled, the switchdev core sets up the VLAN ID 1 and sets
- * it as the new pvid. Actually 'pvid 1' still comes up in 'bridge
- * vlan' even when vlan_filtering is off, but it has no effect.
*/
if (table->entry_count) {
kfree(table->entries);
@@ -284,7 +289,7 @@ static int sja1105_init_static_vlan(struct sja1105_private *priv)
table->entry_count = 1;
- /* VLAN ID 0: all DT-defined ports are members; no restrictions on
+ /* VLAN 1: all DT-defined ports are members; no restrictions on
* forwarding; always transmit priority-tagged frames as untagged.
*/
for (i = 0; i < SJA1105_NUM_PORTS; i++) {
@@ -380,14 +385,14 @@ static int sja1105_init_general_params(struct sja1105_private *priv)
.mirr_ptacu = 0,
.switchid = priv->ds->index,
/* Priority queue for link-local frames trapped to CPU */
- .hostprio = 0,
+ .hostprio = 7,
.mac_fltres1 = SJA1105_LINKLOCAL_FILTER_A,
.mac_flt1 = SJA1105_LINKLOCAL_FILTER_A_MASK,
- .incl_srcpt1 = true,
+ .incl_srcpt1 = false,
.send_meta1 = false,
.mac_fltres0 = SJA1105_LINKLOCAL_FILTER_B,
.mac_flt0 = SJA1105_LINKLOCAL_FILTER_B_MASK,
- .incl_srcpt0 = true,
+ .incl_srcpt0 = false,
.send_meta0 = false,
/* The destination for traffic matching mac_fltres1 and
* mac_fltres0 on all ports except host_port. Such traffic
@@ -499,6 +504,39 @@ static int sja1105_init_l2_policing(struct sja1105_private *priv)
return 0;
}
+static int sja1105_init_avb_params(struct sja1105_private *priv,
+ bool on)
+{
+ struct sja1105_avb_params_entry *avb;
+ struct sja1105_table *table;
+
+ table = &priv->static_config.tables[BLK_IDX_AVB_PARAMS];
+
+ /* Discard previous AVB Parameters Table */
+ if (table->entry_count) {
+ kfree(table->entries);
+ table->entry_count = 0;
+ }
+
+ /* Configure the reception of meta frames only if requested */
+ if (!on)
+ return 0;
+
+ table->entries = kcalloc(SJA1105_MAX_AVB_PARAMS_COUNT,
+ table->ops->unpacked_entry_size, GFP_KERNEL);
+ if (!table->entries)
+ return -ENOMEM;
+
+ table->entry_count = SJA1105_MAX_AVB_PARAMS_COUNT;
+
+ avb = table->entries;
+
+ avb->destmeta = SJA1105_META_DMAC;
+ avb->srcmeta = SJA1105_META_SMAC;
+
+ return 0;
+}
+
static int sja1105_static_config_load(struct sja1105_private *priv,
struct sja1105_dt_port *ports)
{
@@ -539,6 +577,9 @@ static int sja1105_static_config_load(struct sja1105_private *priv,
rc = sja1105_init_general_params(priv);
if (rc < 0)
return rc;
+ rc = sja1105_init_avb_params(priv, false);
+ if (rc < 0)
+ return rc;
/* Send initial configuration to hardware via SPI */
return sja1105_static_config_upload(priv);
@@ -644,26 +685,18 @@ static int sja1105_parse_dt(struct sja1105_private *priv,
return rc;
}
-/* Convert back and forth MAC speed from Mbps to SJA1105 encoding */
+/* Convert link speed from SJA1105 to ethtool encoding */
static int sja1105_speed[] = {
- [SJA1105_SPEED_AUTO] = 0,
- [SJA1105_SPEED_10MBPS] = 10,
- [SJA1105_SPEED_100MBPS] = 100,
- [SJA1105_SPEED_1000MBPS] = 1000,
+ [SJA1105_SPEED_AUTO] = SPEED_UNKNOWN,
+ [SJA1105_SPEED_10MBPS] = SPEED_10,
+ [SJA1105_SPEED_100MBPS] = SPEED_100,
+ [SJA1105_SPEED_1000MBPS] = SPEED_1000,
};
-/* Set link speed and enable/disable traffic I/O in the MAC configuration
- * for a specific port.
- *
- * @speed_mbps: If 0, leave the speed unchanged, else adapt MAC to PHY speed.
- * @enabled: Manage Rx and Tx settings for this port. If false, overrides the
- * settings from the STP state, but not persistently (does not
- * overwrite the static MAC info for this port).
- */
+/* Set link speed in the MAC configuration for a specific port. */
static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
- int speed_mbps, bool enabled)
+ int speed_mbps)
{
- struct sja1105_mac_config_entry dyn_mac;
struct sja1105_xmii_params_entry *mii;
struct sja1105_mac_config_entry *mac;
struct device *dev = priv->ds->dev;
@@ -671,21 +704,33 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
sja1105_speed_t speed;
int rc;
- mii = priv->static_config.tables[BLK_IDX_XMII_PARAMS].entries;
+ /* On P/Q/R/S, one can read from the device via the MAC reconfiguration
+ * tables. On E/T, MAC reconfig tables are not readable, only writable.
+ * We have to *know* what the MAC looks like. For the sake of keeping
+ * the code common, we'll use the static configuration tables as a
+ * reasonable approximation for both E/T and P/Q/R/S.
+ */
mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;
+ mii = priv->static_config.tables[BLK_IDX_XMII_PARAMS].entries;
switch (speed_mbps) {
- case 0:
- /* No speed update requested */
+ case SPEED_UNKNOWN:
+ /* PHYLINK called sja1105_mac_config() to inform us about
+ * the state->interface, but AN has not completed and the
+ * speed is not yet valid. UM10944.pdf says that setting
+ * SJA1105_SPEED_AUTO at runtime disables the port, so that is
+ * ok for power consumption in case AN will never complete -
+ * otherwise PHYLINK should come back with a new update.
+ */
speed = SJA1105_SPEED_AUTO;
break;
- case 10:
+ case SPEED_10:
speed = SJA1105_SPEED_10MBPS;
break;
- case 100:
+ case SPEED_100:
speed = SJA1105_SPEED_100MBPS;
break;
- case 1000:
+ case SPEED_1000:
speed = SJA1105_SPEED_1000MBPS;
break;
default:
@@ -693,26 +738,16 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
return -EINVAL;
}
- /* If requested, overwrite SJA1105_SPEED_AUTO from the static MAC
- * configuration table, since this will be used for the clocking setup,
- * and we no longer need to store it in the static config (already told
- * hardware we want auto during upload phase).
+ /* Overwrite SJA1105_SPEED_AUTO from the static MAC configuration
+ * table, since this will be used for the clocking setup, and we no
+ * longer need to store it in the static config (already told hardware
+ * we want auto during upload phase).
*/
mac[port].speed = speed;
- /* On P/Q/R/S, one can read from the device via the MAC reconfiguration
- * tables. On E/T, MAC reconfig tables are not readable, only writable.
- * We have to *know* what the MAC looks like. For the sake of keeping
- * the code common, we'll use the static configuration tables as a
- * reasonable approximation for both E/T and P/Q/R/S.
- */
- dyn_mac = mac[port];
- dyn_mac.ingress = enabled && mac[port].ingress;
- dyn_mac.egress = enabled && mac[port].egress;
-
/* Write to the dynamic reconfiguration tables */
- rc = sja1105_dynamic_config_write(priv, BLK_IDX_MAC_CONFIG,
- port, &dyn_mac, true);
+ rc = sja1105_dynamic_config_write(priv, BLK_IDX_MAC_CONFIG, port,
+ &mac[port], true);
if (rc < 0) {
dev_err(dev, "Failed to write MAC config: %d\n", rc);
return rc;
@@ -724,9 +759,6 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
* the clock setup does interrupt the clock signal for a certain time
* which causes trouble for all PHYs relying on this signal.
*/
- if (!enabled)
- return 0;
-
phy_mode = mii->xmii_mode[port];
if (phy_mode != XMII_MODE_RGMII)
return 0;
@@ -734,15 +766,67 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
return sja1105_clocking_setup_port(priv, port);
}
-static void sja1105_adjust_link(struct dsa_switch *ds, int port,
- struct phy_device *phydev)
+/* The SJA1105 MAC programming model is through the static config (the xMII
+ * Mode table cannot be dynamically reconfigured), and we have to program
+ * that early (earlier than PHYLINK calls us, anyway).
+ * So just error out in case the connected PHY attempts to change the initial
+ * system interface MII protocol from what is defined in the DT, at least for
+ * now.
+ */
+static bool sja1105_phy_mode_mismatch(struct sja1105_private *priv, int port,
+ phy_interface_t interface)
+{
+ struct sja1105_xmii_params_entry *mii;
+ sja1105_phy_interface_t phy_mode;
+
+ mii = priv->static_config.tables[BLK_IDX_XMII_PARAMS].entries;
+ phy_mode = mii->xmii_mode[port];
+
+ switch (interface) {
+ case PHY_INTERFACE_MODE_MII:
+ return (phy_mode != XMII_MODE_MII);
+ case PHY_INTERFACE_MODE_RMII:
+ return (phy_mode != XMII_MODE_RMII);
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ return (phy_mode != XMII_MODE_RGMII);
+ default:
+ return true;
+ }
+}
+
+static void sja1105_mac_config(struct dsa_switch *ds, int port,
+ unsigned int link_an_mode,
+ const struct phylink_link_state *state)
{
struct sja1105_private *priv = ds->priv;
- if (!phydev->link)
- sja1105_adjust_port_config(priv, port, 0, false);
- else
- sja1105_adjust_port_config(priv, port, phydev->speed, true);
+ if (sja1105_phy_mode_mismatch(priv, port, state->interface))
+ return;
+
+ if (link_an_mode == MLO_AN_INBAND) {
+ dev_err(ds->dev, "In-band AN not supported!\n");
+ return;
+ }
+
+ sja1105_adjust_port_config(priv, port, state->speed);
+}
+
+static void sja1105_mac_link_down(struct dsa_switch *ds, int port,
+ unsigned int mode,
+ phy_interface_t interface)
+{
+ sja1105_inhibit_tx(ds->priv, BIT(port), true);
+}
+
+static void sja1105_mac_link_up(struct dsa_switch *ds, int port,
+ unsigned int mode,
+ phy_interface_t interface,
+ struct phy_device *phydev)
+{
+ sja1105_inhibit_tx(ds->priv, BIT(port), false);
}
static void sja1105_phylink_validate(struct dsa_switch *ds, int port,
@@ -759,6 +843,16 @@ static void sja1105_phylink_validate(struct dsa_switch *ds, int port,
mii = priv->static_config.tables[BLK_IDX_XMII_PARAMS].entries;
+ /* include/linux/phylink.h says:
+ * When @state->interface is %PHY_INTERFACE_MODE_NA, phylink
+ * expects the MAC driver to return all supported link modes.
+ */
+ if (state->interface != PHY_INTERFACE_MODE_NA &&
+ sja1105_phy_mode_mismatch(priv, port, state->interface)) {
+ bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
+ return;
+ }
+
/* The MAC does not support pause frames, and also doesn't
* support half-duplex traffic modes.
*/
@@ -774,6 +868,77 @@ static void sja1105_phylink_validate(struct dsa_switch *ds, int port,
__ETHTOOL_LINK_MODE_MASK_NBITS);
}
+static int
+sja1105_find_static_fdb_entry(struct sja1105_private *priv, int port,
+ const struct sja1105_l2_lookup_entry *requested)
+{
+ struct sja1105_l2_lookup_entry *l2_lookup;
+ struct sja1105_table *table;
+ int i;
+
+ table = &priv->static_config.tables[BLK_IDX_L2_LOOKUP];
+ l2_lookup = table->entries;
+
+ for (i = 0; i < table->entry_count; i++)
+ if (l2_lookup[i].macaddr == requested->macaddr &&
+ l2_lookup[i].vlanid == requested->vlanid &&
+ l2_lookup[i].destports & BIT(port))
+ return i;
+
+ return -1;
+}
+
+/* We want FDB entries added statically through the bridge command to persist
+ * across switch resets, which are a common thing during normal SJA1105
+ * operation. So we have to back them up in the static configuration tables
+ * and hence apply them on next static config upload... yay!
+ */
+static int
+sja1105_static_fdb_change(struct sja1105_private *priv, int port,
+ const struct sja1105_l2_lookup_entry *requested,
+ bool keep)
+{
+ struct sja1105_l2_lookup_entry *l2_lookup;
+ struct sja1105_table *table;
+ int rc, match;
+
+ table = &priv->static_config.tables[BLK_IDX_L2_LOOKUP];
+
+ match = sja1105_find_static_fdb_entry(priv, port, requested);
+ if (match < 0) {
+ /* Can't delete a missing entry. */
+ if (!keep)
+ return 0;
+
+ /* No match => new entry */
+ rc = sja1105_table_resize(table, table->entry_count + 1);
+ if (rc)
+ return rc;
+
+ match = table->entry_count - 1;
+ }
+
+ /* Assign pointer after the resize (it may be new memory) */
+ l2_lookup = table->entries;
+
+ /* We have a match.
+ * If the job was to add this FDB entry, it's already done (mostly
+ * anyway, since the port forwarding mask may have changed, case in
+ * which we update it).
+ * Otherwise we have to delete it.
+ */
+ if (keep) {
+ l2_lookup[match] = *requested;
+ return 0;
+ }
+
+ /* To remove, the strategy is to overwrite the element with
+ * the last one, and then reduce the array size by 1
+ */
+ l2_lookup[match] = l2_lookup[table->entry_count - 1];
+ return sja1105_table_resize(table, table->entry_count - 1);
+}
+
/* First-generation switches have a 4-way set associative TCAM that
* holds the FDB entries. An FDB index spans from 0 to 1023 and is comprised of
* a "bin" (grouping of 4 entries) and a "way" (an entry within a bin).
@@ -785,10 +950,10 @@ static inline int sja1105et_fdb_index(int bin, int way)
return bin * SJA1105ET_FDB_BIN_SIZE + way;
}
-static int sja1105_is_fdb_entry_in_bin(struct sja1105_private *priv, int bin,
- const u8 *addr, u16 vid,
- struct sja1105_l2_lookup_entry *match,
- int *last_unused)
+static int sja1105et_is_fdb_entry_in_bin(struct sja1105_private *priv, int bin,
+ const u8 *addr, u16 vid,
+ struct sja1105_l2_lookup_entry *match,
+ int *last_unused)
{
int way;
@@ -817,19 +982,19 @@ static int sja1105_is_fdb_entry_in_bin(struct sja1105_private *priv, int bin,
return -1;
}
-static int sja1105_fdb_add(struct dsa_switch *ds, int port,
- const unsigned char *addr, u16 vid)
+int sja1105et_fdb_add(struct dsa_switch *ds, int port,
+ const unsigned char *addr, u16 vid)
{
struct sja1105_l2_lookup_entry l2_lookup = {0};
struct sja1105_private *priv = ds->priv;
struct device *dev = ds->dev;
int last_unused = -1;
- int bin, way;
+ int bin, way, rc;
- bin = sja1105_fdb_hash(priv, addr, vid);
+ bin = sja1105et_fdb_hash(priv, addr, vid);
- way = sja1105_is_fdb_entry_in_bin(priv, bin, addr, vid,
- &l2_lookup, &last_unused);
+ way = sja1105et_is_fdb_entry_in_bin(priv, bin, addr, vid,
+ &l2_lookup, &last_unused);
if (way >= 0) {
/* We have an FDB entry. Is our port in the destination
* mask? If yes, we need to do nothing. If not, we need
@@ -868,22 +1033,26 @@ static int sja1105_fdb_add(struct dsa_switch *ds, int port,
}
l2_lookup.index = sja1105et_fdb_index(bin, way);
- return sja1105_dynamic_config_write(priv, BLK_IDX_L2_LOOKUP,
- l2_lookup.index, &l2_lookup,
- true);
+ rc = sja1105_dynamic_config_write(priv, BLK_IDX_L2_LOOKUP,
+ l2_lookup.index, &l2_lookup,
+ true);
+ if (rc < 0)
+ return rc;
+
+ return sja1105_static_fdb_change(priv, port, &l2_lookup, true);
}
-static int sja1105_fdb_del(struct dsa_switch *ds, int port,
- const unsigned char *addr, u16 vid)
+int sja1105et_fdb_del(struct dsa_switch *ds, int port,
+ const unsigned char *addr, u16 vid)
{
struct sja1105_l2_lookup_entry l2_lookup = {0};
struct sja1105_private *priv = ds->priv;
- int index, bin, way;
+ int index, bin, way, rc;
bool keep;
- bin = sja1105_fdb_hash(priv, addr, vid);
- way = sja1105_is_fdb_entry_in_bin(priv, bin, addr, vid,
- &l2_lookup, NULL);
+ bin = sja1105et_fdb_hash(priv, addr, vid);
+ way = sja1105et_is_fdb_entry_in_bin(priv, bin, addr, vid,
+ &l2_lookup, NULL);
if (way < 0)
return 0;
index = sja1105et_fdb_index(bin, way);
@@ -893,15 +1062,176 @@ static int sja1105_fdb_del(struct dsa_switch *ds, int port,
* need to completely evict the FDB entry.
* Otherwise we just write it back.
*/
- if (l2_lookup.destports & BIT(port))
- l2_lookup.destports &= ~BIT(port);
+ l2_lookup.destports &= ~BIT(port);
+
+ if (l2_lookup.destports)
+ keep = true;
+ else
+ keep = false;
+
+ rc = sja1105_dynamic_config_write(priv, BLK_IDX_L2_LOOKUP,
+ index, &l2_lookup, keep);
+ if (rc < 0)
+ return rc;
+
+ return sja1105_static_fdb_change(priv, port, &l2_lookup, keep);
+}
+
+int sja1105pqrs_fdb_add(struct dsa_switch *ds, int port,
+ const unsigned char *addr, u16 vid)
+{
+ struct sja1105_l2_lookup_entry l2_lookup = {0};
+ struct sja1105_private *priv = ds->priv;
+ int rc, i;
+
+ /* Search for an existing entry in the FDB table */
+ l2_lookup.macaddr = ether_addr_to_u64(addr);
+ l2_lookup.vlanid = vid;
+ l2_lookup.iotag = SJA1105_S_TAG;
+ l2_lookup.mask_macaddr = GENMASK_ULL(ETH_ALEN * 8 - 1, 0);
+ l2_lookup.mask_vlanid = VLAN_VID_MASK;
+ l2_lookup.mask_iotag = BIT(0);
+ l2_lookup.destports = BIT(port);
+
+ rc = sja1105_dynamic_config_read(priv, BLK_IDX_L2_LOOKUP,
+ SJA1105_SEARCH, &l2_lookup);
+ if (rc == 0) {
+ /* Found and this port is already in the entry's
+ * port mask => job done
+ */
+ if (l2_lookup.destports & BIT(port))
+ return 0;
+ /* l2_lookup.index is populated by the switch in case it
+ * found something.
+ */
+ l2_lookup.destports |= BIT(port);
+ goto skip_finding_an_index;
+ }
+
+ /* Not found, so try to find an unused spot in the FDB.
+ * This is slightly inefficient because the strategy is knock-knock at
+ * every possible position from 0 to 1023.
+ */
+ for (i = 0; i < SJA1105_MAX_L2_LOOKUP_COUNT; i++) {
+ rc = sja1105_dynamic_config_read(priv, BLK_IDX_L2_LOOKUP,
+ i, NULL);
+ if (rc < 0)
+ break;
+ }
+ if (i == SJA1105_MAX_L2_LOOKUP_COUNT) {
+ dev_err(ds->dev, "FDB is full, cannot add entry.\n");
+ return -EINVAL;
+ }
+ l2_lookup.lockeds = true;
+ l2_lookup.index = i;
+
+skip_finding_an_index:
+ rc = sja1105_dynamic_config_write(priv, BLK_IDX_L2_LOOKUP,
+ l2_lookup.index, &l2_lookup,
+ true);
+ if (rc < 0)
+ return rc;
+
+ return sja1105_static_fdb_change(priv, port, &l2_lookup, true);
+}
+
+int sja1105pqrs_fdb_del(struct dsa_switch *ds, int port,
+ const unsigned char *addr, u16 vid)
+{
+ struct sja1105_l2_lookup_entry l2_lookup = {0};
+ struct sja1105_private *priv = ds->priv;
+ bool keep;
+ int rc;
+
+ l2_lookup.macaddr = ether_addr_to_u64(addr);
+ l2_lookup.vlanid = vid;
+ l2_lookup.iotag = SJA1105_S_TAG;
+ l2_lookup.mask_macaddr = GENMASK_ULL(ETH_ALEN * 8 - 1, 0);
+ l2_lookup.mask_vlanid = VLAN_VID_MASK;
+ l2_lookup.mask_iotag = BIT(0);
+ l2_lookup.destports = BIT(port);
+
+ rc = sja1105_dynamic_config_read(priv, BLK_IDX_L2_LOOKUP,
+ SJA1105_SEARCH, &l2_lookup);
+ if (rc < 0)
+ return 0;
+
+ l2_lookup.destports &= ~BIT(port);
+
+ /* Decide whether we remove just this port from the FDB entry,
+ * or if we remove it completely.
+ */
if (l2_lookup.destports)
keep = true;
else
keep = false;
- return sja1105_dynamic_config_write(priv, BLK_IDX_L2_LOOKUP,
- index, &l2_lookup, keep);
+ rc = sja1105_dynamic_config_write(priv, BLK_IDX_L2_LOOKUP,
+ l2_lookup.index, &l2_lookup, keep);
+ if (rc < 0)
+ return rc;
+
+ return sja1105_static_fdb_change(priv, port, &l2_lookup, keep);
+}
+
+static int sja1105_fdb_add(struct dsa_switch *ds, int port,
+ const unsigned char *addr, u16 vid)
+{
+ struct sja1105_private *priv = ds->priv;
+ u16 rx_vid, tx_vid;
+ int rc, i;
+
+ if (dsa_port_is_vlan_filtering(&ds->ports[port]))
+ return priv->info->fdb_add_cmd(ds, port, addr, vid);
+
+ /* Since we make use of VLANs even when the bridge core doesn't tell us
+ * to, translate these FDB entries into the correct dsa_8021q ones.
+ * The basic idea (also repeats for removal below) is:
+ * - Each of the other front-panel ports needs to be able to forward a
+ * pvid-tagged (aka tagged with their rx_vid) frame that matches this
+ * DMAC.
+ * - The CPU port (aka the tx_vid of this port) needs to be able to
+ * send a frame matching this DMAC to the specified port.
+ * For a better picture see net/dsa/tag_8021q.c.
+ */
+ for (i = 0; i < SJA1105_NUM_PORTS; i++) {
+ if (i == port)
+ continue;
+ if (i == dsa_upstream_port(priv->ds, port))
+ continue;
+
+ rx_vid = dsa_8021q_rx_vid(ds, i);
+ rc = priv->info->fdb_add_cmd(ds, port, addr, rx_vid);
+ if (rc < 0)
+ return rc;
+ }
+ tx_vid = dsa_8021q_tx_vid(ds, port);
+ return priv->info->fdb_add_cmd(ds, port, addr, tx_vid);
+}
+
+static int sja1105_fdb_del(struct dsa_switch *ds, int port,
+ const unsigned char *addr, u16 vid)
+{
+ struct sja1105_private *priv = ds->priv;
+ u16 rx_vid, tx_vid;
+ int rc, i;
+
+ if (dsa_port_is_vlan_filtering(&ds->ports[port]))
+ return priv->info->fdb_del_cmd(ds, port, addr, vid);
+
+ for (i = 0; i < SJA1105_NUM_PORTS; i++) {
+ if (i == port)
+ continue;
+ if (i == dsa_upstream_port(priv->ds, port))
+ continue;
+
+ rx_vid = dsa_8021q_rx_vid(ds, i);
+ rc = priv->info->fdb_del_cmd(ds, port, addr, rx_vid);
+ if (rc < 0)
+ return rc;
+ }
+ tx_vid = dsa_8021q_tx_vid(ds, port);
+ return priv->info->fdb_del_cmd(ds, port, addr, tx_vid);
}
static int sja1105_fdb_dump(struct dsa_switch *ds, int port,
@@ -909,8 +1239,12 @@ static int sja1105_fdb_dump(struct dsa_switch *ds, int port,
{
struct sja1105_private *priv = ds->priv;
struct device *dev = ds->dev;
+ u16 rx_vid, tx_vid;
int i;
+ rx_vid = dsa_8021q_rx_vid(ds, port);
+ tx_vid = dsa_8021q_tx_vid(ds, port);
+
for (i = 0; i < SJA1105_MAX_L2_LOOKUP_COUNT; i++) {
struct sja1105_l2_lookup_entry l2_lookup = {0};
u8 macaddr[ETH_ALEN];
@@ -919,7 +1253,7 @@ static int sja1105_fdb_dump(struct dsa_switch *ds, int port,
rc = sja1105_dynamic_config_read(priv, BLK_IDX_L2_LOOKUP,
i, &l2_lookup);
/* No fdb entry at i, not an issue */
- if (rc == -EINVAL)
+ if (rc == -ENOENT)
continue;
if (rc) {
dev_err(dev, "Failed to dump FDB: %d\n", rc);
@@ -935,7 +1269,41 @@ static int sja1105_fdb_dump(struct dsa_switch *ds, int port,
if (!(l2_lookup.destports & BIT(port)))
continue;
u64_to_ether_addr(l2_lookup.macaddr, macaddr);
- cb(macaddr, l2_lookup.vlanid, false, data);
+
+ /* On SJA1105 E/T, the switch doesn't implement the LOCKEDS
+ * bit, so it doesn't tell us whether a FDB entry is static
+ * or not.
+ * But, of course, we can find out - we're the ones who added
+ * it in the first place.
+ */
+ if (priv->info->device_id == SJA1105E_DEVICE_ID ||
+ priv->info->device_id == SJA1105T_DEVICE_ID) {
+ int match;
+
+ match = sja1105_find_static_fdb_entry(priv, port,
+ &l2_lookup);
+ l2_lookup.lockeds = (match >= 0);
+ }
+
+ /* We need to hide the dsa_8021q VLANs from the user. This
+ * basically means hiding the duplicates and only showing
+ * the pvid that is supposed to be active in standalone and
+ * non-vlan_filtering modes (aka 1).
+ * - For statically added FDB entries (bridge fdb add), we
+ * can convert the TX VID (coming from the CPU port) into the
+ * pvid and ignore the RX VIDs of the other ports.
+ * - For dynamically learned FDB entries, a single entry with
+ * no duplicates is learned - that which has the real port's
+ * pvid, aka RX VID.
+ */
+ if (!dsa_port_is_vlan_filtering(&ds->ports[port])) {
+ if (l2_lookup.vlanid == tx_vid ||
+ l2_lookup.vlanid == rx_vid)
+ l2_lookup.vlanid = 1;
+ else
+ continue;
+ }
+ cb(macaddr, l2_lookup.vlanid, l2_lookup.lockeds, data);
}
return 0;
}
@@ -1056,27 +1424,6 @@ static void sja1105_bridge_leave(struct dsa_switch *ds, int port,
sja1105_bridge_member(ds, port, br, false);
}
-static u8 sja1105_stp_state_get(struct sja1105_private *priv, int port)
-{
- struct sja1105_mac_config_entry *mac;
-
- mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;
-
- if (!mac[port].ingress && !mac[port].egress && !mac[port].dyn_learn)
- return BR_STATE_BLOCKING;
- if (mac[port].ingress && !mac[port].egress && !mac[port].dyn_learn)
- return BR_STATE_LISTENING;
- if (mac[port].ingress && !mac[port].egress && mac[port].dyn_learn)
- return BR_STATE_LEARNING;
- if (mac[port].ingress && mac[port].egress && mac[port].dyn_learn)
- return BR_STATE_FORWARDING;
- /* This is really an error condition if the MAC was in none of the STP
- * states above. But treating the port as disabled does nothing, which
- * is adequate, and it also resets the MAC to a known state later on.
- */
- return BR_STATE_DISABLED;
-}
-
/* For situations where we need to change a setting at runtime that is only
* available through the static configuration, resetting the switch in order
* to upload the new static config is unavoidable. Back up the settings we
@@ -1087,27 +1434,18 @@ static int sja1105_static_config_reload(struct sja1105_private *priv)
{
struct sja1105_mac_config_entry *mac;
int speed_mbps[SJA1105_NUM_PORTS];
- u8 stp_state[SJA1105_NUM_PORTS];
int rc, i;
mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;
- /* Back up settings changed by sja1105_adjust_port_config and
- * sja1105_bridge_stp_state_set and restore their defaults.
+ /* Back up the dynamic link speed changed by sja1105_adjust_port_config
+ * in order to temporarily restore it to SJA1105_SPEED_AUTO - which the
+ * switch wants to see in the static config in order to allow us to
+ * change it through the dynamic interface later.
*/
for (i = 0; i < SJA1105_NUM_PORTS; i++) {
speed_mbps[i] = sja1105_speed[mac[i].speed];
mac[i].speed = SJA1105_SPEED_AUTO;
- if (i == dsa_upstream_port(priv->ds, i)) {
- mac[i].ingress = true;
- mac[i].egress = true;
- mac[i].dyn_learn = true;
- } else {
- stp_state[i] = sja1105_stp_state_get(priv, i);
- mac[i].ingress = false;
- mac[i].egress = false;
- mac[i].dyn_learn = false;
- }
}
/* Reset switch and send updated static configuration */
@@ -1124,13 +1462,7 @@ static int sja1105_static_config_reload(struct sja1105_private *priv)
goto out;
for (i = 0; i < SJA1105_NUM_PORTS; i++) {
- bool enabled = (speed_mbps[i] != 0);
-
- if (i != dsa_upstream_port(priv->ds, i))
- sja1105_bridge_stp_state_set(priv->ds, i, stp_state[i]);
-
- rc = sja1105_adjust_port_config(priv, i, speed_mbps[i],
- enabled);
+ rc = sja1105_adjust_port_config(priv, i, speed_mbps[i]);
if (rc < 0)
goto out;
}
@@ -1138,23 +1470,6 @@ out:
return rc;
}
-/* The TPID setting belongs to the General Parameters table,
- * which can only be partially reconfigured at runtime (and not the TPID).
- * So a switch reset is required.
- */
-static int sja1105_change_tpid(struct sja1105_private *priv,
- u16 tpid, u16 tpid2)
-{
- struct sja1105_general_params_entry *general_params;
- struct sja1105_table *table;
-
- table = &priv->static_config.tables[BLK_IDX_GENERAL_PARAMS];
- general_params = table->entries;
- general_params->tpid = tpid;
- general_params->tpid2 = tpid2;
- return sja1105_static_config_reload(priv);
-}
-
static int sja1105_pvid_apply(struct sja1105_private *priv, int port, u16 pvid)
{
struct sja1105_mac_config_entry *mac;
@@ -1273,17 +1588,41 @@ static int sja1105_vlan_prepare(struct dsa_switch *ds, int port,
return 0;
}
+/* The TPID setting belongs to the General Parameters table,
+ * which can only be partially reconfigured at runtime (and not the TPID).
+ * So a switch reset is required.
+ */
static int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled)
{
+ struct sja1105_general_params_entry *general_params;
struct sja1105_private *priv = ds->priv;
+ struct sja1105_table *table;
+ u16 tpid, tpid2;
int rc;
- if (enabled)
+ if (enabled) {
/* Enable VLAN filtering. */
- rc = sja1105_change_tpid(priv, ETH_P_8021Q, ETH_P_8021AD);
- else
+ tpid = ETH_P_8021AD;
+ tpid2 = ETH_P_8021Q;
+ } else {
/* Disable VLAN filtering. */
- rc = sja1105_change_tpid(priv, ETH_P_SJA1105, ETH_P_SJA1105);
+ tpid = ETH_P_SJA1105;
+ tpid2 = ETH_P_SJA1105;
+ }
+
+ table = &priv->static_config.tables[BLK_IDX_GENERAL_PARAMS];
+ general_params = table->entries;
+ /* EtherType used to identify outer tagged (S-tag) VLAN traffic */
+ general_params->tpid = tpid;
+ /* EtherType used to identify inner tagged (C-tag) VLAN traffic */
+ general_params->tpid2 = tpid2;
+ /* When VLAN filtering is on, we need to at least be able to
+ * decode management traffic through the "backup plan".
+ */
+ general_params->incl_srcpt1 = enabled;
+ general_params->incl_srcpt0 = enabled;
+
+ rc = sja1105_static_config_reload(priv);
if (rc)
dev_err(ds->dev, "Failed to change VLAN Ethertype\n");
@@ -1372,6 +1711,11 @@ static int sja1105_setup(struct dsa_switch *ds)
return rc;
}
+ rc = sja1105_ptp_clock_register(priv);
+ if (rc < 0) {
+ dev_err(ds->dev, "Failed to register PTP clock: %d\n", rc);
+ return rc;
+ }
/* Create and send configuration down to device */
rc = sja1105_static_config_load(priv, ports);
if (rc < 0) {
@@ -1401,8 +1745,16 @@ static int sja1105_setup(struct dsa_switch *ds)
return sja1105_setup_8021q_tagging(ds, true);
}
+static void sja1105_teardown(struct dsa_switch *ds)
+{
+ struct sja1105_private *priv = ds->priv;
+
+ cancel_work_sync(&priv->tagger_data.rxtstamp_work);
+ skb_queue_purge(&priv->tagger_data.skb_rxtstamp_queue);
+}
+
static int sja1105_mgmt_xmit(struct dsa_switch *ds, int port, int slot,
- struct sk_buff *skb)
+ struct sk_buff *skb, bool takets)
{
struct sja1105_mgmt_entry mgmt_route = {0};
struct sja1105_private *priv = ds->priv;
@@ -1415,6 +1767,8 @@ static int sja1105_mgmt_xmit(struct dsa_switch *ds, int port, int slot,
mgmt_route.macaddr = ether_addr_to_u64(hdr->h_dest);
mgmt_route.destports = BIT(port);
mgmt_route.enfport = 1;
+ mgmt_route.tsreg = 0;
+ mgmt_route.takets = takets;
rc = sja1105_dynamic_config_write(priv, BLK_IDX_MGMT_ROUTE,
slot, &mgmt_route, true);
@@ -1446,6 +1800,8 @@ static int sja1105_mgmt_xmit(struct dsa_switch *ds, int port, int slot,
if (!timeout) {
/* Clean up the management route so that a follow-up
* frame may not match on it by mistake.
+ * This is only hardware supported on P/Q/R/S - on E/T it is
+ * a no-op and we are silently discarding the -EOPNOTSUPP.
*/
sja1105_dynamic_config_write(priv, BLK_IDX_MGMT_ROUTE,
slot, &mgmt_route, false);
@@ -1464,7 +1820,11 @@ static netdev_tx_t sja1105_port_deferred_xmit(struct dsa_switch *ds, int port,
{
struct sja1105_private *priv = ds->priv;
struct sja1105_port *sp = &priv->ports[port];
+ struct skb_shared_hwtstamps shwt = {0};
int slot = sp->mgmt_slot;
+ struct sk_buff *clone;
+ u64 now, ts;
+ int rc;
/* The tragic fact about the switch having 4x2 slots for installing
* management routes is that all of them except one are actually
@@ -1482,8 +1842,36 @@ static netdev_tx_t sja1105_port_deferred_xmit(struct dsa_switch *ds, int port,
*/
mutex_lock(&priv->mgmt_lock);
- sja1105_mgmt_xmit(ds, port, slot, skb);
+ /* The clone, if there, was made by dsa_skb_tx_timestamp */
+ clone = DSA_SKB_CB(skb)->clone;
+
+ sja1105_mgmt_xmit(ds, port, slot, skb, !!clone);
+
+ if (!clone)
+ goto out;
+
+ skb_shinfo(clone)->tx_flags |= SKBTX_IN_PROGRESS;
+
+ mutex_lock(&priv->ptp_lock);
+
+ now = priv->tstamp_cc.read(&priv->tstamp_cc);
+
+ rc = sja1105_ptpegr_ts_poll(priv, slot, &ts);
+ if (rc < 0) {
+ dev_err(ds->dev, "xmit: timed out polling for tstamp\n");
+ kfree_skb(clone);
+ goto out_unlock_ptp;
+ }
+
+ ts = sja1105_tstamp_reconstruct(priv, now, ts);
+ ts = timecounter_cyc2time(&priv->tstamp_tc, ts);
+
+ shwt.hwtstamp = ns_to_ktime(ts);
+ skb_complete_tx_timestamp(clone, &shwt);
+out_unlock_ptp:
+ mutex_unlock(&priv->ptp_lock);
+out:
mutex_unlock(&priv->mgmt_lock);
return NETDEV_TX_OK;
}
@@ -1512,15 +1900,180 @@ static int sja1105_set_ageing_time(struct dsa_switch *ds,
return sja1105_static_config_reload(priv);
}
+/* Caller must hold priv->tagger_data.meta_lock */
+static int sja1105_change_rxtstamping(struct sja1105_private *priv,
+ bool on)
+{
+ struct sja1105_general_params_entry *general_params;
+ struct sja1105_table *table;
+ int rc;
+
+ table = &priv->static_config.tables[BLK_IDX_GENERAL_PARAMS];
+ general_params = table->entries;
+ general_params->send_meta1 = on;
+ general_params->send_meta0 = on;
+
+ rc = sja1105_init_avb_params(priv, on);
+ if (rc < 0)
+ return rc;
+
+ /* Initialize the meta state machine to a known state */
+ if (priv->tagger_data.stampable_skb) {
+ kfree_skb(priv->tagger_data.stampable_skb);
+ priv->tagger_data.stampable_skb = NULL;
+ }
+
+ return sja1105_static_config_reload(priv);
+}
+
+static int sja1105_hwtstamp_set(struct dsa_switch *ds, int port,
+ struct ifreq *ifr)
+{
+ struct sja1105_private *priv = ds->priv;
+ struct hwtstamp_config config;
+ bool rx_on;
+ int rc;
+
+ if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
+ return -EFAULT;
+
+ switch (config.tx_type) {
+ case HWTSTAMP_TX_OFF:
+ priv->ports[port].hwts_tx_en = false;
+ break;
+ case HWTSTAMP_TX_ON:
+ priv->ports[port].hwts_tx_en = true;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ switch (config.rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ rx_on = false;
+ break;
+ default:
+ rx_on = true;
+ break;
+ }
+
+ if (rx_on != priv->tagger_data.hwts_rx_en) {
+ spin_lock(&priv->tagger_data.meta_lock);
+ rc = sja1105_change_rxtstamping(priv, rx_on);
+ spin_unlock(&priv->tagger_data.meta_lock);
+ if (rc < 0) {
+ dev_err(ds->dev,
+ "Failed to change RX timestamping: %d\n", rc);
+ return -EFAULT;
+ }
+ priv->tagger_data.hwts_rx_en = rx_on;
+ }
+
+ if (copy_to_user(ifr->ifr_data, &config, sizeof(config)))
+ return -EFAULT;
+ return 0;
+}
+
+static int sja1105_hwtstamp_get(struct dsa_switch *ds, int port,
+ struct ifreq *ifr)
+{
+ struct sja1105_private *priv = ds->priv;
+ struct hwtstamp_config config;
+
+ config.flags = 0;
+ if (priv->ports[port].hwts_tx_en)
+ config.tx_type = HWTSTAMP_TX_ON;
+ else
+ config.tx_type = HWTSTAMP_TX_OFF;
+ if (priv->tagger_data.hwts_rx_en)
+ config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
+ else
+ config.rx_filter = HWTSTAMP_FILTER_NONE;
+
+ return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
+ -EFAULT : 0;
+}
+
+#define to_tagger(d) \
+ container_of((d), struct sja1105_tagger_data, rxtstamp_work)
+#define to_sja1105(d) \
+ container_of((d), struct sja1105_private, tagger_data)
+
+static void sja1105_rxtstamp_work(struct work_struct *work)
+{
+ struct sja1105_tagger_data *data = to_tagger(work);
+ struct sja1105_private *priv = to_sja1105(data);
+ struct sk_buff *skb;
+ u64 now;
+
+ mutex_lock(&priv->ptp_lock);
+
+ now = priv->tstamp_cc.read(&priv->tstamp_cc);
+
+ while ((skb = skb_dequeue(&data->skb_rxtstamp_queue)) != NULL) {
+ struct skb_shared_hwtstamps *shwt = skb_hwtstamps(skb);
+ u64 ts;
+
+ *shwt = (struct skb_shared_hwtstamps) {0};
+
+ ts = SJA1105_SKB_CB(skb)->meta_tstamp;
+ ts = sja1105_tstamp_reconstruct(priv, now, ts);
+ ts = timecounter_cyc2time(&priv->tstamp_tc, ts);
+
+ shwt->hwtstamp = ns_to_ktime(ts);
+ netif_rx_ni(skb);
+ }
+
+ mutex_unlock(&priv->ptp_lock);
+}
+
+/* Called from dsa_skb_defer_rx_timestamp */
+static bool sja1105_port_rxtstamp(struct dsa_switch *ds, int port,
+ struct sk_buff *skb, unsigned int type)
+{
+ struct sja1105_private *priv = ds->priv;
+ struct sja1105_tagger_data *data = &priv->tagger_data;
+
+ if (!data->hwts_rx_en)
+ return false;
+
+ /* We need to read the full PTP clock to reconstruct the Rx
+ * timestamp. For that we need a sleepable context.
+ */
+ skb_queue_tail(&data->skb_rxtstamp_queue, skb);
+ schedule_work(&data->rxtstamp_work);
+ return true;
+}
+
+/* Called from dsa_skb_tx_timestamp. This callback is just to make DSA clone
+ * the skb and have it available in DSA_SKB_CB in the .port_deferred_xmit
+ * callback, where we will timestamp it synchronously.
+ */
+static bool sja1105_port_txtstamp(struct dsa_switch *ds, int port,
+ struct sk_buff *skb, unsigned int type)
+{
+ struct sja1105_private *priv = ds->priv;
+ struct sja1105_port *sp = &priv->ports[port];
+
+ if (!sp->hwts_tx_en)
+ return false;
+
+ return true;
+}
+
static const struct dsa_switch_ops sja1105_switch_ops = {
.get_tag_protocol = sja1105_get_tag_protocol,
.setup = sja1105_setup,
- .adjust_link = sja1105_adjust_link,
+ .teardown = sja1105_teardown,
.set_ageing_time = sja1105_set_ageing_time,
.phylink_validate = sja1105_phylink_validate,
+ .phylink_mac_config = sja1105_mac_config,
+ .phylink_mac_link_up = sja1105_mac_link_up,
+ .phylink_mac_link_down = sja1105_mac_link_down,
.get_strings = sja1105_get_strings,
.get_ethtool_stats = sja1105_get_ethtool_stats,
.get_sset_count = sja1105_get_sset_count,
+ .get_ts_info = sja1105_get_ts_info,
.port_fdb_dump = sja1105_fdb_dump,
.port_fdb_add = sja1105_fdb_add,
.port_fdb_del = sja1105_fdb_del,
@@ -1535,6 +2088,10 @@ static const struct dsa_switch_ops sja1105_switch_ops = {
.port_mdb_add = sja1105_mdb_add,
.port_mdb_del = sja1105_mdb_del,
.port_deferred_xmit = sja1105_port_deferred_xmit,
+ .port_hwtstamp_get = sja1105_hwtstamp_get,
+ .port_hwtstamp_set = sja1105_hwtstamp_set,
+ .port_rxtstamp = sja1105_port_rxtstamp,
+ .port_txtstamp = sja1105_port_txtstamp,
};
static int sja1105_check_device_id(struct sja1105_private *priv)
@@ -1575,6 +2132,7 @@ static int sja1105_check_device_id(struct sja1105_private *priv)
static int sja1105_probe(struct spi_device *spi)
{
+ struct sja1105_tagger_data *tagger_data;
struct device *dev = &spi->dev;
struct sja1105_private *priv;
struct dsa_switch *ds;
@@ -1629,12 +2187,17 @@ static int sja1105_probe(struct spi_device *spi)
ds->priv = priv;
priv->ds = ds;
+ tagger_data = &priv->tagger_data;
+ skb_queue_head_init(&tagger_data->skb_rxtstamp_queue);
+ INIT_WORK(&tagger_data->rxtstamp_work, sja1105_rxtstamp_work);
+
/* Connections between dsa_port and sja1105_port */
for (i = 0; i < SJA1105_NUM_PORTS; i++) {
struct sja1105_port *sp = &priv->ports[i];
ds->ports[i].priv = sp;
sp->dp = &ds->ports[i];
+ sp->data = tagger_data;
}
mutex_init(&priv->mgmt_lock);
@@ -1645,6 +2208,7 @@ static int sja1105_remove(struct spi_device *spi)
{
struct sja1105_private *priv = spi_get_drvdata(spi);
+ sja1105_ptp_clock_unregister(priv);
dsa_unregister_switch(priv->ds);
sja1105_static_config_free(&priv->static_config);
return 0;
diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.c b/drivers/net/dsa/sja1105/sja1105_ptp.c
new file mode 100644
index 000000000000..d19cfdf681af
--- /dev/null
+++ b/drivers/net/dsa/sja1105/sja1105_ptp.c
@@ -0,0 +1,393 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2019, Vladimir Oltean <olteanv@gmail.com>
+ */
+#include "sja1105.h"
+
+/* The adjfine API clamps ppb between [-32,768,000, 32,768,000], and
+ * therefore scaled_ppm between [-2,147,483,648, 2,147,483,647].
+ * Set the maximum supported ppb to a round value smaller than the maximum.
+ *
+ * Percentually speaking, this is a +/- 0.032x adjustment of the
+ * free-running counter (0.968x to 1.032x).
+ */
+#define SJA1105_MAX_ADJ_PPB 32000000
+#define SJA1105_SIZE_PTP_CMD 4
+
+/* Timestamps are in units of 8 ns clock ticks (equivalent to a fixed
+ * 125 MHz clock) so the scale factor (MULT / SHIFT) needs to be 8.
+ * Furthermore, wisely pick SHIFT as 28 bits, which translates
+ * MULT into 2^31 (0x80000000). This is the same value around which
+ * the hardware PTPCLKRATE is centered, so the same ppb conversion
+ * arithmetic can be reused.
+ */
+#define SJA1105_CC_SHIFT 28
+#define SJA1105_CC_MULT (8 << SJA1105_CC_SHIFT)
+
+/* Having 33 bits of cycle counter left until a 64-bit overflow during delta
+ * conversion, we multiply this by the 8 ns counter resolution and arrive at
+ * a comfortable 68.71 second refresh interval until the delta would cause
+ * an integer overflow, in absence of any other readout.
+ * Approximate to 1 minute.
+ */
+#define SJA1105_REFRESH_INTERVAL (HZ * 60)
+
+/* This range is actually +/- SJA1105_MAX_ADJ_PPB
+ * divided by 1000 (ppb -> ppm) and with a 16-bit
+ * "fractional" part (actually fixed point).
+ * |
+ * v
+ * Convert scaled_ppm from the +/- ((10^6) << 16) range
+ * into the +/- (1 << 31) range.
+ *
+ * This forgoes a "ppb" numeric representation (up to NSEC_PER_SEC)
+ * and defines the scaling factor between scaled_ppm and the actual
+ * frequency adjustments (both cycle counter and hardware).
+ *
+ * ptpclkrate = scaled_ppm * 2^31 / (10^6 * 2^16)
+ * simplifies to
+ * ptpclkrate = scaled_ppm * 2^9 / 5^6
+ */
+#define SJA1105_CC_MULT_NUM (1 << 9)
+#define SJA1105_CC_MULT_DEM 15625
+
+#define ptp_to_sja1105(d) container_of((d), struct sja1105_private, ptp_caps)
+#define cc_to_sja1105(d) container_of((d), struct sja1105_private, tstamp_cc)
+#define dw_to_sja1105(d) container_of((d), struct sja1105_private, refresh_work)
+
+struct sja1105_ptp_cmd {
+ u64 resptp; /* reset */
+};
+
+int sja1105_get_ts_info(struct dsa_switch *ds, int port,
+ struct ethtool_ts_info *info)
+{
+ struct sja1105_private *priv = ds->priv;
+
+ /* Called during cleanup */
+ if (!priv->clock)
+ return -ENODEV;
+
+ info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE;
+ info->tx_types = (1 << HWTSTAMP_TX_OFF) |
+ (1 << HWTSTAMP_TX_ON);
+ info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT);
+ info->phc_index = ptp_clock_index(priv->clock);
+ return 0;
+}
+
+int sja1105et_ptp_cmd(const void *ctx, const void *data)
+{
+ const struct sja1105_ptp_cmd *cmd = data;
+ const struct sja1105_private *priv = ctx;
+ const struct sja1105_regs *regs = priv->info->regs;
+ const int size = SJA1105_SIZE_PTP_CMD;
+ u8 buf[SJA1105_SIZE_PTP_CMD] = {0};
+ /* No need to keep this as part of the structure */
+ u64 valid = 1;
+
+ sja1105_pack(buf, &valid, 31, 31, size);
+ sja1105_pack(buf, &cmd->resptp, 2, 2, size);
+
+ return sja1105_spi_send_packed_buf(priv, SPI_WRITE, regs->ptp_control,
+ buf, SJA1105_SIZE_PTP_CMD);
+}
+
+int sja1105pqrs_ptp_cmd(const void *ctx, const void *data)
+{
+ const struct sja1105_ptp_cmd *cmd = data;
+ const struct sja1105_private *priv = ctx;
+ const struct sja1105_regs *regs = priv->info->regs;
+ const int size = SJA1105_SIZE_PTP_CMD;
+ u8 buf[SJA1105_SIZE_PTP_CMD] = {0};
+ /* No need to keep this as part of the structure */
+ u64 valid = 1;
+
+ sja1105_pack(buf, &valid, 31, 31, size);
+ sja1105_pack(buf, &cmd->resptp, 3, 3, size);
+
+ return sja1105_spi_send_packed_buf(priv, SPI_WRITE, regs->ptp_control,
+ buf, SJA1105_SIZE_PTP_CMD);
+}
+
+/* The switch returns partial timestamps (24 bits for SJA1105 E/T, which wrap
+ * around in 0.135 seconds, and 32 bits for P/Q/R/S, wrapping around in 34.35
+ * seconds).
+ *
+ * This receives the RX or TX MAC timestamps, provided by hardware as
+ * the lower bits of the cycle counter, sampled at the time the timestamp was
+ * collected.
+ *
+ * To reconstruct into a full 64-bit-wide timestamp, the cycle counter is
+ * read and the high-order bits are filled in.
+ *
+ * Must be called within one wraparound period of the partial timestamp since
+ * it was generated by the MAC.
+ */
+u64 sja1105_tstamp_reconstruct(struct sja1105_private *priv, u64 now,
+ u64 ts_partial)
+{
+ u64 partial_tstamp_mask = CYCLECOUNTER_MASK(priv->info->ptp_ts_bits);
+ u64 ts_reconstructed;
+
+ ts_reconstructed = (now & ~partial_tstamp_mask) | ts_partial;
+
+ /* Check lower bits of current cycle counter against the timestamp.
+ * If the current cycle counter is lower than the partial timestamp,
+ * then wraparound surely occurred and must be accounted for.
+ */
+ if ((now & partial_tstamp_mask) <= ts_partial)
+ ts_reconstructed -= (partial_tstamp_mask + 1);
+
+ return ts_reconstructed;
+}
+
+/* Reads the SPI interface for an egress timestamp generated by the switch
+ * for frames sent using management routes.
+ *
+ * SJA1105 E/T layout of the 4-byte SPI payload:
+ *
+ * 31 23 15 7 0
+ * | | | | |
+ * +-----+-----+-----+ ^
+ * ^ |
+ * | |
+ * 24-bit timestamp Update bit
+ *
+ *
+ * SJA1105 P/Q/R/S layout of the 8-byte SPI payload:
+ *
+ * 31 23 15 7 0 63 55 47 39 32
+ * | | | | | | | | | |
+ * ^ +-----+-----+-----+-----+
+ * | ^
+ * | |
+ * Update bit 32-bit timestamp
+ *
+ * Notice that the update bit is in the same place.
+ * To have common code for E/T and P/Q/R/S for reading the timestamp,
+ * we need to juggle with the offset and the bit indices.
+ */
+int sja1105_ptpegr_ts_poll(struct sja1105_private *priv, int port, u64 *ts)
+{
+ const struct sja1105_regs *regs = priv->info->regs;
+ int tstamp_bit_start, tstamp_bit_end;
+ int timeout = 10;
+ u8 packed_buf[8];
+ u64 update;
+ int rc;
+
+ do {
+ rc = sja1105_spi_send_packed_buf(priv, SPI_READ,
+ regs->ptpegr_ts[port],
+ packed_buf,
+ priv->info->ptpegr_ts_bytes);
+ if (rc < 0)
+ return rc;
+
+ sja1105_unpack(packed_buf, &update, 0, 0,
+ priv->info->ptpegr_ts_bytes);
+ if (update)
+ break;
+
+ usleep_range(10, 50);
+ } while (--timeout);
+
+ if (!timeout)
+ return -ETIMEDOUT;
+
+ /* Point the end bit to the second 32-bit word on P/Q/R/S,
+ * no-op on E/T.
+ */
+ tstamp_bit_end = (priv->info->ptpegr_ts_bytes - 4) * 8;
+ /* Shift the 24-bit timestamp on E/T to be collected from 31:8.
+ * No-op on P/Q/R/S.
+ */
+ tstamp_bit_end += 32 - priv->info->ptp_ts_bits;
+ tstamp_bit_start = tstamp_bit_end + priv->info->ptp_ts_bits - 1;
+
+ *ts = 0;
+
+ sja1105_unpack(packed_buf, ts, tstamp_bit_start, tstamp_bit_end,
+ priv->info->ptpegr_ts_bytes);
+
+ return 0;
+}
+
+int sja1105_ptp_reset(struct sja1105_private *priv)
+{
+ struct dsa_switch *ds = priv->ds;
+ struct sja1105_ptp_cmd cmd = {0};
+ int rc;
+
+ mutex_lock(&priv->ptp_lock);
+
+ cmd.resptp = 1;
+ dev_dbg(ds->dev, "Resetting PTP clock\n");
+ rc = priv->info->ptp_cmd(priv, &cmd);
+
+ timecounter_init(&priv->tstamp_tc, &priv->tstamp_cc,
+ ktime_to_ns(ktime_get_real()));
+
+ mutex_unlock(&priv->ptp_lock);
+
+ return rc;
+}
+
+static int sja1105_ptp_gettime(struct ptp_clock_info *ptp,
+ struct timespec64 *ts)
+{
+ struct sja1105_private *priv = ptp_to_sja1105(ptp);
+ u64 ns;
+
+ mutex_lock(&priv->ptp_lock);
+ ns = timecounter_read(&priv->tstamp_tc);
+ mutex_unlock(&priv->ptp_lock);
+
+ *ts = ns_to_timespec64(ns);
+
+ return 0;
+}
+
+static int sja1105_ptp_settime(struct ptp_clock_info *ptp,
+ const struct timespec64 *ts)
+{
+ struct sja1105_private *priv = ptp_to_sja1105(ptp);
+ u64 ns = timespec64_to_ns(ts);
+
+ mutex_lock(&priv->ptp_lock);
+ timecounter_init(&priv->tstamp_tc, &priv->tstamp_cc, ns);
+ mutex_unlock(&priv->ptp_lock);
+
+ return 0;
+}
+
+static int sja1105_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
+{
+ struct sja1105_private *priv = ptp_to_sja1105(ptp);
+ s64 clkrate;
+
+ clkrate = (s64)scaled_ppm * SJA1105_CC_MULT_NUM;
+ clkrate = div_s64(clkrate, SJA1105_CC_MULT_DEM);
+
+ mutex_lock(&priv->ptp_lock);
+
+ /* Force a readout to update the timer *before* changing its frequency.
+ *
+ * This way, its corrected time curve can at all times be modeled
+ * as a linear "A * x + B" function, where:
+ *
+ * - B are past frequency adjustments and offset shifts, all
+ * accumulated into the cycle_last variable.
+ *
+ * - A is the new frequency adjustments we're just about to set.
+ *
+ * Reading now makes B accumulate the correct amount of time,
+ * corrected at the old rate, before changing it.
+ *
+ * Hardware timestamps then become simple points on the curve and
+ * are approximated using the above function. This is still better
+ * than letting the switch take the timestamps using the hardware
+ * rate-corrected clock (PTPCLKVAL) - the comparison in this case would
+ * be that we're shifting the ruler at the same time as we're taking
+ * measurements with it.
+ *
+ * The disadvantage is that it's possible to receive timestamps when
+ * a frequency adjustment took place in the near past.
+ * In this case they will be approximated using the new ppb value
+ * instead of a compound function made of two segments (one at the old
+ * and the other at the new rate) - introducing some inaccuracy.
+ */
+ timecounter_read(&priv->tstamp_tc);
+
+ priv->tstamp_cc.mult = SJA1105_CC_MULT + clkrate;
+
+ mutex_unlock(&priv->ptp_lock);
+
+ return 0;
+}
+
+static int sja1105_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+ struct sja1105_private *priv = ptp_to_sja1105(ptp);
+
+ mutex_lock(&priv->ptp_lock);
+ timecounter_adjtime(&priv->tstamp_tc, delta);
+ mutex_unlock(&priv->ptp_lock);
+
+ return 0;
+}
+
+static u64 sja1105_ptptsclk_read(const struct cyclecounter *cc)
+{
+ struct sja1105_private *priv = cc_to_sja1105(cc);
+ const struct sja1105_regs *regs = priv->info->regs;
+ u64 ptptsclk = 0;
+ int rc;
+
+ rc = sja1105_spi_send_int(priv, SPI_READ, regs->ptptsclk,
+ &ptptsclk, 8);
+ if (rc < 0)
+ dev_err_ratelimited(priv->ds->dev,
+ "failed to read ptp cycle counter: %d\n",
+ rc);
+ return ptptsclk;
+}
+
+static void sja1105_ptp_overflow_check(struct work_struct *work)
+{
+ struct delayed_work *dw = to_delayed_work(work);
+ struct sja1105_private *priv = dw_to_sja1105(dw);
+ struct timespec64 ts;
+
+ sja1105_ptp_gettime(&priv->ptp_caps, &ts);
+
+ schedule_delayed_work(&priv->refresh_work, SJA1105_REFRESH_INTERVAL);
+}
+
+static const struct ptp_clock_info sja1105_ptp_caps = {
+ .owner = THIS_MODULE,
+ .name = "SJA1105 PHC",
+ .adjfine = sja1105_ptp_adjfine,
+ .adjtime = sja1105_ptp_adjtime,
+ .gettime64 = sja1105_ptp_gettime,
+ .settime64 = sja1105_ptp_settime,
+ .max_adj = SJA1105_MAX_ADJ_PPB,
+};
+
+int sja1105_ptp_clock_register(struct sja1105_private *priv)
+{
+ struct dsa_switch *ds = priv->ds;
+
+ /* Set up the cycle counter */
+ priv->tstamp_cc = (struct cyclecounter) {
+ .read = sja1105_ptptsclk_read,
+ .mask = CYCLECOUNTER_MASK(64),
+ .shift = SJA1105_CC_SHIFT,
+ .mult = SJA1105_CC_MULT,
+ };
+ mutex_init(&priv->ptp_lock);
+ INIT_DELAYED_WORK(&priv->refresh_work, sja1105_ptp_overflow_check);
+
+ schedule_delayed_work(&priv->refresh_work, SJA1105_REFRESH_INTERVAL);
+
+ priv->ptp_caps = sja1105_ptp_caps;
+
+ priv->clock = ptp_clock_register(&priv->ptp_caps, ds->dev);
+ if (IS_ERR_OR_NULL(priv->clock))
+ return PTR_ERR(priv->clock);
+
+ return sja1105_ptp_reset(priv);
+}
+
+void sja1105_ptp_clock_unregister(struct sja1105_private *priv)
+{
+ if (IS_ERR_OR_NULL(priv->clock))
+ return;
+
+ cancel_delayed_work_sync(&priv->refresh_work);
+ ptp_clock_unregister(priv->clock);
+ priv->clock = NULL;
+}
diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.h b/drivers/net/dsa/sja1105/sja1105_ptp.h
new file mode 100644
index 000000000000..af456b0a4d27
--- /dev/null
+++ b/drivers/net/dsa/sja1105/sja1105_ptp.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright (c) 2019, Vladimir Oltean <olteanv@gmail.com>
+ */
+#ifndef _SJA1105_PTP_H
+#define _SJA1105_PTP_H
+
+#if IS_ENABLED(CONFIG_NET_DSA_SJA1105_PTP)
+
+int sja1105_ptp_clock_register(struct sja1105_private *priv);
+
+void sja1105_ptp_clock_unregister(struct sja1105_private *priv);
+
+int sja1105_ptpegr_ts_poll(struct sja1105_private *priv, int port, u64 *ts);
+
+int sja1105et_ptp_cmd(const void *ctx, const void *data);
+
+int sja1105pqrs_ptp_cmd(const void *ctx, const void *data);
+
+int sja1105_get_ts_info(struct dsa_switch *ds, int port,
+ struct ethtool_ts_info *ts);
+
+u64 sja1105_tstamp_reconstruct(struct sja1105_private *priv, u64 now,
+ u64 ts_partial);
+
+int sja1105_ptp_reset(struct sja1105_private *priv);
+
+#else
+
+static inline int sja1105_ptp_clock_register(struct sja1105_private *priv)
+{
+ return 0;
+}
+
+static inline void sja1105_ptp_clock_unregister(struct sja1105_private *priv)
+{
+ return;
+}
+
+static inline int
+sja1105_ptpegr_ts_poll(struct sja1105_private *priv, int port, u64 *ts)
+{
+ return 0;
+}
+
+static inline u64 sja1105_tstamp_reconstruct(struct sja1105_private *priv,
+ u64 now, u64 ts_partial)
+{
+ return 0;
+}
+
+static inline int sja1105_ptp_reset(struct sja1105_private *priv)
+{
+ return 0;
+}
+
+#define sja1105et_ptp_cmd NULL
+
+#define sja1105pqrs_ptp_cmd NULL
+
+#define sja1105_get_ts_info NULL
+
+#endif /* IS_ENABLED(CONFIG_NET_DSA_SJA1105_PTP) */
+
+#endif /* _SJA1105_PTP_H */
diff --git a/drivers/net/dsa/sja1105/sja1105_spi.c b/drivers/net/dsa/sja1105/sja1105_spi.c
index 2eb70b8acfc3..84dc603138cf 100644
--- a/drivers/net/dsa/sja1105/sja1105_spi.c
+++ b/drivers/net/dsa/sja1105/sja1105_spi.c
@@ -283,20 +283,22 @@ static int sja1105_cold_reset(const struct sja1105_private *priv)
return priv->info->reset_cmd(priv, &reset);
}
-static int sja1105_inhibit_tx(const struct sja1105_private *priv,
- const unsigned long *port_bitmap)
+int sja1105_inhibit_tx(const struct sja1105_private *priv,
+ unsigned long port_bitmap, bool tx_inhibited)
{
const struct sja1105_regs *regs = priv->info->regs;
u64 inhibit_cmd;
- int port, rc;
+ int rc;
rc = sja1105_spi_send_int(priv, SPI_READ, regs->port_control,
&inhibit_cmd, SJA1105_SIZE_PORT_CTRL);
if (rc < 0)
return rc;
- for_each_set_bit(port, port_bitmap, SJA1105_NUM_PORTS)
- inhibit_cmd |= BIT(port);
+ if (tx_inhibited)
+ inhibit_cmd |= port_bitmap;
+ else
+ inhibit_cmd &= ~port_bitmap;
return sja1105_spi_send_int(priv, SPI_WRITE, regs->port_control,
&inhibit_cmd, SJA1105_SIZE_PORT_CTRL);
@@ -413,7 +415,7 @@ int sja1105_static_config_upload(struct sja1105_private *priv)
* Tx on all ports and waiting for current packet to drain.
* Otherwise, the PHY will see an unterminated Ethernet packet.
*/
- rc = sja1105_inhibit_tx(priv, &port_bitmap);
+ rc = sja1105_inhibit_tx(priv, port_bitmap, true);
if (rc < 0) {
dev_err(dev, "Failed to inhibit Tx on ports\n");
return -ENXIO;
@@ -478,7 +480,12 @@ int sja1105_static_config_upload(struct sja1105_private *priv)
dev_info(dev, "Succeeded after %d tried\n", RETRIES - retries);
}
+ rc = sja1105_ptp_reset(priv);
+ if (rc < 0)
+ dev_err(dev, "Failed to reset PTP clock: %d\n", rc);
+
dev_info(dev, "Reset switch and programmed static config\n");
+
out:
kfree(config_buf);
return rc;
@@ -491,11 +498,10 @@ static struct sja1105_regs sja1105et_regs = {
.port_control = 0x11,
.config = 0x020000,
.rgu = 0x100440,
+ /* UM10944.pdf, Table 86, ACU Register overview */
.pad_mii_tx = {0x100800, 0x100802, 0x100804, 0x100806, 0x100808},
.rmii_pll1 = 0x10000A,
.cgu_idiv = {0x10000B, 0x10000C, 0x10000D, 0x10000E, 0x10000F},
- /* UM10944.pdf, Table 86, ACU Register overview */
- .rgmii_pad_mii_tx = {0x100800, 0x100802, 0x100804, 0x100806, 0x100808},
.mac = {0x200, 0x202, 0x204, 0x206, 0x208},
.mac_hl1 = {0x400, 0x410, 0x420, 0x430, 0x440},
.mac_hl2 = {0x600, 0x610, 0x620, 0x630, 0x640},
@@ -507,6 +513,11 @@ static struct sja1105_regs sja1105et_regs = {
.rgmii_tx_clk = {0x100016, 0x10001D, 0x100024, 0x10002B, 0x100032},
.rmii_ref_clk = {0x100015, 0x10001C, 0x100023, 0x10002A, 0x100031},
.rmii_ext_tx_clk = {0x100018, 0x10001F, 0x100026, 0x10002D, 0x100034},
+ .ptpegr_ts = {0xC0, 0xC2, 0xC4, 0xC6, 0xC8},
+ .ptp_control = 0x17,
+ .ptpclk = 0x18, /* Spans 0x18 to 0x19 */
+ .ptpclkrate = 0x1A,
+ .ptptsclk = 0x1B, /* Spans 0x1B to 0x1C */
};
static struct sja1105_regs sja1105pqrs_regs = {
@@ -516,11 +527,11 @@ static struct sja1105_regs sja1105pqrs_regs = {
.port_control = 0x12,
.config = 0x020000,
.rgu = 0x100440,
+ /* UM10944.pdf, Table 86, ACU Register overview */
.pad_mii_tx = {0x100800, 0x100802, 0x100804, 0x100806, 0x100808},
+ .pad_mii_id = {0x100810, 0x100811, 0x100812, 0x100813, 0x100814},
.rmii_pll1 = 0x10000A,
.cgu_idiv = {0x10000B, 0x10000C, 0x10000D, 0x10000E, 0x10000F},
- /* UM10944.pdf, Table 86, ACU Register overview */
- .rgmii_pad_mii_tx = {0x100800, 0x100802, 0x100804, 0x100806, 0x100808},
.mac = {0x200, 0x202, 0x204, 0x206, 0x208},
.mac_hl1 = {0x400, 0x410, 0x420, 0x430, 0x440},
.mac_hl2 = {0x600, 0x610, 0x620, 0x630, 0x640},
@@ -533,6 +544,11 @@ static struct sja1105_regs sja1105pqrs_regs = {
.rmii_ref_clk = {0x100015, 0x10001B, 0x100021, 0x100027, 0x10002D},
.rmii_ext_tx_clk = {0x100017, 0x10001D, 0x100023, 0x100029, 0x10002F},
.qlevel = {0x604, 0x614, 0x624, 0x634, 0x644},
+ .ptpegr_ts = {0xC0, 0xC4, 0xC8, 0xCC, 0xD0},
+ .ptp_control = 0x18,
+ .ptpclk = 0x19,
+ .ptpclkrate = 0x1B,
+ .ptptsclk = 0x1C,
};
struct sja1105_info sja1105e_info = {
@@ -540,7 +556,12 @@ struct sja1105_info sja1105e_info = {
.part_no = SJA1105ET_PART_NO,
.static_ops = sja1105e_table_ops,
.dyn_ops = sja1105et_dyn_ops,
+ .ptp_ts_bits = 24,
+ .ptpegr_ts_bytes = 4,
.reset_cmd = sja1105et_reset_cmd,
+ .fdb_add_cmd = sja1105et_fdb_add,
+ .fdb_del_cmd = sja1105et_fdb_del,
+ .ptp_cmd = sja1105et_ptp_cmd,
.regs = &sja1105et_regs,
.name = "SJA1105E",
};
@@ -549,7 +570,12 @@ struct sja1105_info sja1105t_info = {
.part_no = SJA1105ET_PART_NO,
.static_ops = sja1105t_table_ops,
.dyn_ops = sja1105et_dyn_ops,
+ .ptp_ts_bits = 24,
+ .ptpegr_ts_bytes = 4,
.reset_cmd = sja1105et_reset_cmd,
+ .fdb_add_cmd = sja1105et_fdb_add,
+ .fdb_del_cmd = sja1105et_fdb_del,
+ .ptp_cmd = sja1105et_ptp_cmd,
.regs = &sja1105et_regs,
.name = "SJA1105T",
};
@@ -558,7 +584,13 @@ struct sja1105_info sja1105p_info = {
.part_no = SJA1105P_PART_NO,
.static_ops = sja1105p_table_ops,
.dyn_ops = sja1105pqrs_dyn_ops,
+ .ptp_ts_bits = 32,
+ .ptpegr_ts_bytes = 8,
+ .setup_rgmii_delay = sja1105pqrs_setup_rgmii_delay,
.reset_cmd = sja1105pqrs_reset_cmd,
+ .fdb_add_cmd = sja1105pqrs_fdb_add,
+ .fdb_del_cmd = sja1105pqrs_fdb_del,
+ .ptp_cmd = sja1105pqrs_ptp_cmd,
.regs = &sja1105pqrs_regs,
.name = "SJA1105P",
};
@@ -567,7 +599,13 @@ struct sja1105_info sja1105q_info = {
.part_no = SJA1105Q_PART_NO,
.static_ops = sja1105q_table_ops,
.dyn_ops = sja1105pqrs_dyn_ops,
+ .ptp_ts_bits = 32,
+ .ptpegr_ts_bytes = 8,
+ .setup_rgmii_delay = sja1105pqrs_setup_rgmii_delay,
.reset_cmd = sja1105pqrs_reset_cmd,
+ .fdb_add_cmd = sja1105pqrs_fdb_add,
+ .fdb_del_cmd = sja1105pqrs_fdb_del,
+ .ptp_cmd = sja1105pqrs_ptp_cmd,
.regs = &sja1105pqrs_regs,
.name = "SJA1105Q",
};
@@ -576,7 +614,13 @@ struct sja1105_info sja1105r_info = {
.part_no = SJA1105R_PART_NO,
.static_ops = sja1105r_table_ops,
.dyn_ops = sja1105pqrs_dyn_ops,
+ .ptp_ts_bits = 32,
+ .ptpegr_ts_bytes = 8,
+ .setup_rgmii_delay = sja1105pqrs_setup_rgmii_delay,
.reset_cmd = sja1105pqrs_reset_cmd,
+ .fdb_add_cmd = sja1105pqrs_fdb_add,
+ .fdb_del_cmd = sja1105pqrs_fdb_del,
+ .ptp_cmd = sja1105pqrs_ptp_cmd,
.regs = &sja1105pqrs_regs,
.name = "SJA1105R",
};
@@ -586,6 +630,12 @@ struct sja1105_info sja1105s_info = {
.static_ops = sja1105s_table_ops,
.dyn_ops = sja1105pqrs_dyn_ops,
.regs = &sja1105pqrs_regs,
+ .ptp_ts_bits = 32,
+ .ptpegr_ts_bytes = 8,
+ .setup_rgmii_delay = sja1105pqrs_setup_rgmii_delay,
.reset_cmd = sja1105pqrs_reset_cmd,
+ .fdb_add_cmd = sja1105pqrs_fdb_add,
+ .fdb_del_cmd = sja1105pqrs_fdb_del,
+ .ptp_cmd = sja1105pqrs_ptp_cmd,
.name = "SJA1105S",
};
diff --git a/drivers/net/dsa/sja1105/sja1105_static_config.c b/drivers/net/dsa/sja1105/sja1105_static_config.c
index b3c992b0abb0..b31c737dc560 100644
--- a/drivers/net/dsa/sja1105/sja1105_static_config.c
+++ b/drivers/net/dsa/sja1105/sja1105_static_config.c
@@ -91,6 +91,28 @@ u32 sja1105_crc32(const void *buf, size_t len)
return ~crc;
}
+static size_t sja1105et_avb_params_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ const size_t size = SJA1105ET_SIZE_AVB_PARAMS_ENTRY;
+ struct sja1105_avb_params_entry *entry = entry_ptr;
+
+ sja1105_packing(buf, &entry->destmeta, 95, 48, size, op);
+ sja1105_packing(buf, &entry->srcmeta, 47, 0, size, op);
+ return size;
+}
+
+static size_t sja1105pqrs_avb_params_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ const size_t size = SJA1105PQRS_SIZE_AVB_PARAMS_ENTRY;
+ struct sja1105_avb_params_entry *entry = entry_ptr;
+
+ sja1105_packing(buf, &entry->destmeta, 125, 78, size, op);
+ sja1105_packing(buf, &entry->srcmeta, 77, 30, size, op);
+ return size;
+}
+
static size_t sja1105et_general_params_entry_packing(void *buf, void *entry_ptr,
enum packing_op op)
{
@@ -208,11 +230,20 @@ sja1105pqrs_l2_lookup_params_entry_packing(void *buf, void *entry_ptr,
{
const size_t size = SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_ENTRY;
struct sja1105_l2_lookup_params_entry *entry = entry_ptr;
+ int offset, i;
+ for (i = 0, offset = 58; i < 5; i++, offset += 11)
+ sja1105_packing(buf, &entry->maxaddrp[i],
+ offset + 10, offset + 0, size, op);
sja1105_packing(buf, &entry->maxage, 57, 43, size, op);
+ sja1105_packing(buf, &entry->start_dynspc, 42, 33, size, op);
+ sja1105_packing(buf, &entry->drpnolearn, 32, 28, size, op);
sja1105_packing(buf, &entry->shared_learn, 27, 27, size, op);
sja1105_packing(buf, &entry->no_enf_hostprt, 26, 26, size, op);
sja1105_packing(buf, &entry->no_mgmt_learn, 25, 25, size, op);
+ sja1105_packing(buf, &entry->use_static, 24, 24, size, op);
+ sja1105_packing(buf, &entry->owr_dyn, 23, 23, size, op);
+ sja1105_packing(buf, &entry->learn_once, 22, 22, size, op);
return size;
}
@@ -236,10 +267,20 @@ size_t sja1105pqrs_l2_lookup_entry_packing(void *buf, void *entry_ptr,
const size_t size = SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
struct sja1105_l2_lookup_entry *entry = entry_ptr;
- /* These are static L2 lookup entries, so the structure
- * should match UM11040 Table 16/17 definitions when
- * LOCKEDS is 1.
- */
+ if (entry->lockeds) {
+ sja1105_packing(buf, &entry->tsreg, 159, 159, size, op);
+ sja1105_packing(buf, &entry->mirrvlan, 158, 147, size, op);
+ sja1105_packing(buf, &entry->takets, 146, 146, size, op);
+ sja1105_packing(buf, &entry->mirr, 145, 145, size, op);
+ sja1105_packing(buf, &entry->retag, 144, 144, size, op);
+ } else {
+ sja1105_packing(buf, &entry->touched, 159, 159, size, op);
+ sja1105_packing(buf, &entry->age, 158, 144, size, op);
+ }
+ sja1105_packing(buf, &entry->mask_iotag, 143, 143, size, op);
+ sja1105_packing(buf, &entry->mask_vlanid, 142, 131, size, op);
+ sja1105_packing(buf, &entry->mask_macaddr, 130, 83, size, op);
+ sja1105_packing(buf, &entry->iotag, 82, 82, size, op);
sja1105_packing(buf, &entry->vlanid, 81, 70, size, op);
sja1105_packing(buf, &entry->macaddr, 69, 22, size, op);
sja1105_packing(buf, &entry->destports, 21, 17, size, op);
@@ -413,6 +454,7 @@ static u64 blk_id_map[BLK_IDX_MAX] = {
[BLK_IDX_MAC_CONFIG] = BLKID_MAC_CONFIG,
[BLK_IDX_L2_LOOKUP_PARAMS] = BLKID_L2_LOOKUP_PARAMS,
[BLK_IDX_L2_FORWARDING_PARAMS] = BLKID_L2_FORWARDING_PARAMS,
+ [BLK_IDX_AVB_PARAMS] = BLKID_AVB_PARAMS,
[BLK_IDX_GENERAL_PARAMS] = BLKID_GENERAL_PARAMS,
[BLK_IDX_XMII_PARAMS] = BLKID_XMII_PARAMS,
};
@@ -442,7 +484,7 @@ const char *sja1105_static_config_error_msg[] = {
"vl-forwarding-parameters-table.partspc.",
};
-sja1105_config_valid_t
+static sja1105_config_valid_t
static_config_check_memory_size(const struct sja1105_table *tables)
{
const struct sja1105_l2_forwarding_params_entry *l2_fwd_params;
@@ -614,6 +656,12 @@ struct sja1105_table_ops sja1105e_table_ops[BLK_IDX_MAX] = {
.packed_entry_size = SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY,
.max_entry_count = SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT,
},
+ [BLK_IDX_AVB_PARAMS] = {
+ .packing = sja1105et_avb_params_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_avb_params_entry),
+ .packed_entry_size = SJA1105ET_SIZE_AVB_PARAMS_ENTRY,
+ .max_entry_count = SJA1105_MAX_AVB_PARAMS_COUNT,
+ },
[BLK_IDX_GENERAL_PARAMS] = {
.packing = sja1105et_general_params_entry_packing,
.unpacked_entry_size = sizeof(struct sja1105_general_params_entry),
@@ -672,6 +720,12 @@ struct sja1105_table_ops sja1105t_table_ops[BLK_IDX_MAX] = {
.packed_entry_size = SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY,
.max_entry_count = SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT,
},
+ [BLK_IDX_AVB_PARAMS] = {
+ .packing = sja1105et_avb_params_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_avb_params_entry),
+ .packed_entry_size = SJA1105ET_SIZE_AVB_PARAMS_ENTRY,
+ .max_entry_count = SJA1105_MAX_AVB_PARAMS_COUNT,
+ },
[BLK_IDX_GENERAL_PARAMS] = {
.packing = sja1105et_general_params_entry_packing,
.unpacked_entry_size = sizeof(struct sja1105_general_params_entry),
@@ -730,6 +784,12 @@ struct sja1105_table_ops sja1105p_table_ops[BLK_IDX_MAX] = {
.packed_entry_size = SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY,
.max_entry_count = SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT,
},
+ [BLK_IDX_AVB_PARAMS] = {
+ .packing = sja1105pqrs_avb_params_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_avb_params_entry),
+ .packed_entry_size = SJA1105PQRS_SIZE_AVB_PARAMS_ENTRY,
+ .max_entry_count = SJA1105_MAX_AVB_PARAMS_COUNT,
+ },
[BLK_IDX_GENERAL_PARAMS] = {
.packing = sja1105pqrs_general_params_entry_packing,
.unpacked_entry_size = sizeof(struct sja1105_general_params_entry),
@@ -788,6 +848,12 @@ struct sja1105_table_ops sja1105q_table_ops[BLK_IDX_MAX] = {
.packed_entry_size = SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY,
.max_entry_count = SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT,
},
+ [BLK_IDX_AVB_PARAMS] = {
+ .packing = sja1105pqrs_avb_params_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_avb_params_entry),
+ .packed_entry_size = SJA1105PQRS_SIZE_AVB_PARAMS_ENTRY,
+ .max_entry_count = SJA1105_MAX_AVB_PARAMS_COUNT,
+ },
[BLK_IDX_GENERAL_PARAMS] = {
.packing = sja1105pqrs_general_params_entry_packing,
.unpacked_entry_size = sizeof(struct sja1105_general_params_entry),
@@ -846,6 +912,12 @@ struct sja1105_table_ops sja1105r_table_ops[BLK_IDX_MAX] = {
.packed_entry_size = SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY,
.max_entry_count = SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT,
},
+ [BLK_IDX_AVB_PARAMS] = {
+ .packing = sja1105pqrs_avb_params_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_avb_params_entry),
+ .packed_entry_size = SJA1105PQRS_SIZE_AVB_PARAMS_ENTRY,
+ .max_entry_count = SJA1105_MAX_AVB_PARAMS_COUNT,
+ },
[BLK_IDX_GENERAL_PARAMS] = {
.packing = sja1105pqrs_general_params_entry_packing,
.unpacked_entry_size = sizeof(struct sja1105_general_params_entry),
@@ -904,6 +976,12 @@ struct sja1105_table_ops sja1105s_table_ops[BLK_IDX_MAX] = {
.packed_entry_size = SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY,
.max_entry_count = SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT,
},
+ [BLK_IDX_AVB_PARAMS] = {
+ .packing = sja1105pqrs_avb_params_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_avb_params_entry),
+ .packed_entry_size = SJA1105PQRS_SIZE_AVB_PARAMS_ENTRY,
+ .max_entry_count = SJA1105_MAX_AVB_PARAMS_COUNT,
+ },
[BLK_IDX_GENERAL_PARAMS] = {
.packing = sja1105pqrs_general_params_entry_packing,
.unpacked_entry_size = sizeof(struct sja1105_general_params_entry),
diff --git a/drivers/net/dsa/sja1105/sja1105_static_config.h b/drivers/net/dsa/sja1105/sja1105_static_config.h
index 069ca8fd059c..684465fc0882 100644
--- a/drivers/net/dsa/sja1105/sja1105_static_config.h
+++ b/drivers/net/dsa/sja1105/sja1105_static_config.h
@@ -20,10 +20,12 @@
#define SJA1105ET_SIZE_MAC_CONFIG_ENTRY 28
#define SJA1105ET_SIZE_L2_LOOKUP_PARAMS_ENTRY 4
#define SJA1105ET_SIZE_GENERAL_PARAMS_ENTRY 40
+#define SJA1105ET_SIZE_AVB_PARAMS_ENTRY 12
#define SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY 20
#define SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY 32
#define SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_ENTRY 16
#define SJA1105PQRS_SIZE_GENERAL_PARAMS_ENTRY 44
+#define SJA1105PQRS_SIZE_AVB_PARAMS_ENTRY 16
/* UM10944.pdf Page 11, Table 2. Configuration Blocks */
enum {
@@ -34,6 +36,7 @@ enum {
BLKID_MAC_CONFIG = 0x09,
BLKID_L2_LOOKUP_PARAMS = 0x0D,
BLKID_L2_FORWARDING_PARAMS = 0x0E,
+ BLKID_AVB_PARAMS = 0x10,
BLKID_GENERAL_PARAMS = 0x11,
BLKID_XMII_PARAMS = 0x4E,
};
@@ -46,6 +49,7 @@ enum sja1105_blk_idx {
BLK_IDX_MAC_CONFIG,
BLK_IDX_L2_LOOKUP_PARAMS,
BLK_IDX_L2_FORWARDING_PARAMS,
+ BLK_IDX_AVB_PARAMS,
BLK_IDX_GENERAL_PARAMS,
BLK_IDX_XMII_PARAMS,
BLK_IDX_MAX,
@@ -64,6 +68,7 @@ enum sja1105_blk_idx {
#define SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT 1
#define SJA1105_MAX_GENERAL_PARAMS_COUNT 1
#define SJA1105_MAX_XMII_PARAMS_COUNT 1
+#define SJA1105_MAX_AVB_PARAMS_COUNT 1
#define SJA1105_MAX_FRAME_MEMORY 929
@@ -122,9 +127,36 @@ struct sja1105_l2_lookup_entry {
u64 destports;
u64 enfport;
u64 index;
+ /* P/Q/R/S only */
+ u64 mask_iotag;
+ u64 mask_vlanid;
+ u64 mask_macaddr;
+ u64 iotag;
+ u64 lockeds;
+ union {
+ /* LOCKEDS=1: Static FDB entries */
+ struct {
+ u64 tsreg;
+ u64 mirrvlan;
+ u64 takets;
+ u64 mirr;
+ u64 retag;
+ };
+ /* LOCKEDS=0: Dynamically learned FDB entries */
+ struct {
+ u64 touched;
+ u64 age;
+ };
+ };
};
struct sja1105_l2_lookup_params_entry {
+ u64 maxaddrp[5]; /* P/Q/R/S only */
+ u64 start_dynspc; /* P/Q/R/S only */
+ u64 drpnolearn; /* P/Q/R/S only */
+ u64 use_static; /* P/Q/R/S only */
+ u64 owr_dyn; /* P/Q/R/S only */
+ u64 learn_once; /* P/Q/R/S only */
u64 maxage; /* Shared */
u64 dyn_tbsz; /* E/T only */
u64 poly; /* E/T only */
@@ -153,6 +185,11 @@ struct sja1105_l2_policing_entry {
u64 partition;
};
+struct sja1105_avb_params_entry {
+ u64 destmeta;
+ u64 srcmeta;
+};
+
struct sja1105_mac_config_entry {
u64 top[8];
u64 base[8];
diff --git a/drivers/net/dsa/vitesse-vsc73xx.c b/drivers/net/dsa/vitesse-vsc73xx-core.c
index d4780610ea8a..614377ef7956 100644
--- a/drivers/net/dsa/vitesse-vsc73xx.c
+++ b/drivers/net/dsa/vitesse-vsc73xx-core.c
@@ -10,10 +10,6 @@
* handling the switch in a memory-mapped manner by connecting to that external
* CPU's memory bus.
*
- * This driver (currently) only takes control of the switch chip over SPI and
- * configures it to route packages around when connected to a CPU port. The
- * chip has embedded PHYs and VLAN support so we model it using DSA.
- *
* Copyright (C) 2018 Linus Wallej <linus.walleij@linaro.org>
* Includes portions of code from the firmware uploader by:
* Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
@@ -24,8 +20,6 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_mdio.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
#include <linux/bitops.h>
#include <linux/if_bridge.h>
#include <linux/etherdevice.h>
@@ -34,6 +28,8 @@
#include <linux/random.h>
#include <net/dsa.h>
+#include "vitesse-vsc73xx.h"
+
#define VSC73XX_BLOCK_MAC 0x1 /* Subblocks 0-4, 6 (CPU port) */
#define VSC73XX_BLOCK_ANALYZER 0x2 /* Only subblock 0 */
#define VSC73XX_BLOCK_MII 0x3 /* Subblocks 0 and 1 */
@@ -255,13 +251,6 @@
#define VSC73XX_GLORESET_PHY_RESET BIT(1)
#define VSC73XX_GLORESET_MASTER_RESET BIT(0)
-#define VSC73XX_CMD_MODE_READ 0
-#define VSC73XX_CMD_MODE_WRITE 1
-#define VSC73XX_CMD_MODE_SHIFT 4
-#define VSC73XX_CMD_BLOCK_SHIFT 5
-#define VSC73XX_CMD_BLOCK_MASK 0x7
-#define VSC73XX_CMD_SUBBLOCK_MASK 0xf
-
#define VSC7385_CLOCK_DELAY ((3 << 4) | 3)
#define VSC7385_CLOCK_DELAY_MASK ((3 << 4) | 3)
@@ -274,20 +263,6 @@
VSC73XX_ICPU_CTRL_CLK_EN | \
VSC73XX_ICPU_CTRL_SRST)
-/**
- * struct vsc73xx - VSC73xx state container
- */
-struct vsc73xx {
- struct device *dev;
- struct gpio_desc *reset;
- struct spi_device *spi;
- struct dsa_switch *ds;
- struct gpio_chip gc;
- u16 chipid;
- u8 addr[ETH_ALEN];
- struct mutex lock; /* Protects SPI traffic */
-};
-
#define IS_7385(a) ((a)->chipid == VSC73XX_CHIPID_ID_7385)
#define IS_7388(a) ((a)->chipid == VSC73XX_CHIPID_ID_7388)
#define IS_7395(a) ((a)->chipid == VSC73XX_CHIPID_ID_7395)
@@ -365,7 +340,7 @@ static const struct vsc73xx_counter vsc73xx_tx_counters[] = {
{ 29, "TxQoSClass3" }, /* non-standard counter */
};
-static int vsc73xx_is_addr_valid(u8 block, u8 subblock)
+int vsc73xx_is_addr_valid(u8 block, u8 subblock)
{
switch (block) {
case VSC73XX_BLOCK_MAC:
@@ -396,96 +371,18 @@ static int vsc73xx_is_addr_valid(u8 block, u8 subblock)
return 0;
}
-
-static u8 vsc73xx_make_addr(u8 mode, u8 block, u8 subblock)
-{
- u8 ret;
-
- ret = (block & VSC73XX_CMD_BLOCK_MASK) << VSC73XX_CMD_BLOCK_SHIFT;
- ret |= (mode & 1) << VSC73XX_CMD_MODE_SHIFT;
- ret |= subblock & VSC73XX_CMD_SUBBLOCK_MASK;
-
- return ret;
-}
+EXPORT_SYMBOL(vsc73xx_is_addr_valid);
static int vsc73xx_read(struct vsc73xx *vsc, u8 block, u8 subblock, u8 reg,
u32 *val)
{
- struct spi_transfer t[2];
- struct spi_message m;
- u8 cmd[4];
- u8 buf[4];
- int ret;
-
- if (!vsc73xx_is_addr_valid(block, subblock))
- return -EINVAL;
-
- spi_message_init(&m);
-
- memset(&t, 0, sizeof(t));
-
- t[0].tx_buf = cmd;
- t[0].len = sizeof(cmd);
- spi_message_add_tail(&t[0], &m);
-
- t[1].rx_buf = buf;
- t[1].len = sizeof(buf);
- spi_message_add_tail(&t[1], &m);
-
- cmd[0] = vsc73xx_make_addr(VSC73XX_CMD_MODE_READ, block, subblock);
- cmd[1] = reg;
- cmd[2] = 0;
- cmd[3] = 0;
-
- mutex_lock(&vsc->lock);
- ret = spi_sync(vsc->spi, &m);
- mutex_unlock(&vsc->lock);
-
- if (ret)
- return ret;
-
- *val = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
-
- return 0;
+ return vsc->ops->read(vsc, block, subblock, reg, val);
}
static int vsc73xx_write(struct vsc73xx *vsc, u8 block, u8 subblock, u8 reg,
u32 val)
{
- struct spi_transfer t[2];
- struct spi_message m;
- u8 cmd[2];
- u8 buf[4];
- int ret;
-
- if (!vsc73xx_is_addr_valid(block, subblock))
- return -EINVAL;
-
- spi_message_init(&m);
-
- memset(&t, 0, sizeof(t));
-
- t[0].tx_buf = cmd;
- t[0].len = sizeof(cmd);
- spi_message_add_tail(&t[0], &m);
-
- t[1].tx_buf = buf;
- t[1].len = sizeof(buf);
- spi_message_add_tail(&t[1], &m);
-
- cmd[0] = vsc73xx_make_addr(VSC73XX_CMD_MODE_WRITE, block, subblock);
- cmd[1] = reg;
-
- buf[0] = (val >> 24) & 0xff;
- buf[1] = (val >> 16) & 0xff;
- buf[2] = (val >> 8) & 0xff;
- buf[3] = val & 0xff;
-
- mutex_lock(&vsc->lock);
- ret = spi_sync(vsc->spi, &m);
- mutex_unlock(&vsc->lock);
-
- return ret;
+ return vsc->ops->write(vsc, block, subblock, reg, val);
}
static int vsc73xx_update_bits(struct vsc73xx *vsc, u8 block, u8 subblock,
@@ -520,22 +417,8 @@ static int vsc73xx_detect(struct vsc73xx *vsc)
}
if (val == 0xffffffff) {
- dev_info(vsc->dev, "chip seems dead, assert reset\n");
- gpiod_set_value_cansleep(vsc->reset, 1);
- /* Reset pulse should be 20ns minimum, according to datasheet
- * table 245, so 10us should be fine
- */
- usleep_range(10, 100);
- gpiod_set_value_cansleep(vsc->reset, 0);
- /* Wait 20ms according to datasheet table 245 */
- msleep(20);
-
- ret = vsc73xx_read(vsc, VSC73XX_BLOCK_SYSTEM, 0,
- VSC73XX_ICPU_MBOX_VAL, &val);
- if (val == 0xffffffff) {
- dev_err(vsc->dev, "seems not to help, giving up\n");
- return -ENODEV;
- }
+ dev_info(vsc->dev, "chip seems dead.\n");
+ return -EAGAIN;
}
ret = vsc73xx_read(vsc, VSC73XX_BLOCK_SYSTEM, 0,
@@ -586,9 +469,8 @@ static int vsc73xx_detect(struct vsc73xx *vsc)
}
if (icpu_si_boot_en && !icpu_pi_en) {
dev_err(vsc->dev,
- "iCPU enabled boots from SI, no external memory\n");
- dev_err(vsc->dev, "no idea how to deal with this\n");
- return -ENODEV;
+ "iCPU enabled boots from PI/SI, no external memory\n");
+ return -EAGAIN;
}
if (!icpu_si_boot_en && icpu_pi_en) {
dev_err(vsc->dev,
@@ -1245,21 +1127,11 @@ static int vsc73xx_gpio_probe(struct vsc73xx *vsc)
return 0;
}
-static int vsc73xx_probe(struct spi_device *spi)
+int vsc73xx_probe(struct vsc73xx *vsc)
{
- struct device *dev = &spi->dev;
- struct vsc73xx *vsc;
+ struct device *dev = vsc->dev;
int ret;
- vsc = devm_kzalloc(dev, sizeof(*vsc), GFP_KERNEL);
- if (!vsc)
- return -ENOMEM;
-
- spi_set_drvdata(spi, vsc);
- vsc->spi = spi_dev_get(spi);
- vsc->dev = dev;
- mutex_init(&vsc->lock);
-
/* Release reset, if any */
vsc->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(vsc->reset)) {
@@ -1270,15 +1142,20 @@ static int vsc73xx_probe(struct spi_device *spi)
/* Wait 20ms according to datasheet table 245 */
msleep(20);
- spi->mode = SPI_MODE_0;
- spi->bits_per_word = 8;
- ret = spi_setup(spi);
- if (ret < 0) {
- dev_err(dev, "spi setup failed.\n");
- return ret;
- }
-
ret = vsc73xx_detect(vsc);
+ if (ret == -EAGAIN) {
+ dev_err(vsc->dev,
+ "Chip seems to be out of control. Assert reset and try again.\n");
+ gpiod_set_value_cansleep(vsc->reset, 1);
+ /* Reset pulse should be 20ns minimum, according to datasheet
+ * table 245, so 10us should be fine
+ */
+ usleep_range(10, 100);
+ gpiod_set_value_cansleep(vsc->reset, 0);
+ /* Wait 20ms according to datasheet table 245 */
+ msleep(20);
+ ret = vsc73xx_detect(vsc);
+ }
if (ret) {
dev_err(dev, "no chip found (%d)\n", ret);
return -ENODEV;
@@ -1321,43 +1198,16 @@ static int vsc73xx_probe(struct spi_device *spi)
return 0;
}
+EXPORT_SYMBOL(vsc73xx_probe);
-static int vsc73xx_remove(struct spi_device *spi)
+int vsc73xx_remove(struct vsc73xx *vsc)
{
- struct vsc73xx *vsc = spi_get_drvdata(spi);
-
dsa_unregister_switch(vsc->ds);
gpiod_set_value(vsc->reset, 1);
return 0;
}
-
-static const struct of_device_id vsc73xx_of_match[] = {
- {
- .compatible = "vitesse,vsc7385",
- },
- {
- .compatible = "vitesse,vsc7388",
- },
- {
- .compatible = "vitesse,vsc7395",
- },
- {
- .compatible = "vitesse,vsc7398",
- },
- { },
-};
-MODULE_DEVICE_TABLE(of, vsc73xx_of_match);
-
-static struct spi_driver vsc73xx_driver = {
- .probe = vsc73xx_probe,
- .remove = vsc73xx_remove,
- .driver = {
- .name = "vsc73xx",
- .of_match_table = vsc73xx_of_match,
- },
-};
-module_spi_driver(vsc73xx_driver);
+EXPORT_SYMBOL(vsc73xx_remove);
MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
MODULE_DESCRIPTION("Vitesse VSC7385/7388/7395/7398 driver");
diff --git a/drivers/net/dsa/vitesse-vsc73xx-platform.c b/drivers/net/dsa/vitesse-vsc73xx-platform.c
new file mode 100644
index 000000000000..0541785f9fee
--- /dev/null
+++ b/drivers/net/dsa/vitesse-vsc73xx-platform.c
@@ -0,0 +1,164 @@
+// SPDX-License-Identifier: GPL-2.0
+/* DSA driver for:
+ * Vitesse VSC7385 SparX-G5 5+1-port Integrated Gigabit Ethernet Switch
+ * Vitesse VSC7388 SparX-G8 8-port Integrated Gigabit Ethernet Switch
+ * Vitesse VSC7395 SparX-G5e 5+1-port Integrated Gigabit Ethernet Switch
+ * Vitesse VSC7398 SparX-G8e 8-port Integrated Gigabit Ethernet Switch
+ *
+ * This driver takes control of the switch chip connected over CPU-attached
+ * address bus and configures it to route packages around when connected to
+ * a CPU port.
+ *
+ * Copyright (C) 2019 Pawel Dembicki <paweldembicki@gmail.com>
+ * Based on vitesse-vsc-spi.c by:
+ * Copyright (C) 2018 Linus Wallej <linus.walleij@linaro.org>
+ * Includes portions of code from the firmware uploader by:
+ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "vitesse-vsc73xx.h"
+
+#define VSC73XX_CMD_PLATFORM_BLOCK_SHIFT 14
+#define VSC73XX_CMD_PLATFORM_BLOCK_MASK 0x7
+#define VSC73XX_CMD_PLATFORM_SUBBLOCK_SHIFT 10
+#define VSC73XX_CMD_PLATFORM_SUBBLOCK_MASK 0xf
+#define VSC73XX_CMD_PLATFORM_REGISTER_SHIFT 2
+
+/**
+ * struct vsc73xx_platform - VSC73xx Platform state container
+ */
+struct vsc73xx_platform {
+ struct platform_device *pdev;
+ void __iomem *base_addr;
+ struct vsc73xx vsc;
+};
+
+static const struct vsc73xx_ops vsc73xx_platform_ops;
+
+static u32 vsc73xx_make_addr(u8 block, u8 subblock, u8 reg)
+{
+ u32 ret;
+
+ ret = (block & VSC73XX_CMD_PLATFORM_BLOCK_MASK)
+ << VSC73XX_CMD_PLATFORM_BLOCK_SHIFT;
+ ret |= (subblock & VSC73XX_CMD_PLATFORM_SUBBLOCK_MASK)
+ << VSC73XX_CMD_PLATFORM_SUBBLOCK_SHIFT;
+ ret |= reg << VSC73XX_CMD_PLATFORM_REGISTER_SHIFT;
+
+ return ret;
+}
+
+static int vsc73xx_platform_read(struct vsc73xx *vsc, u8 block, u8 subblock,
+ u8 reg, u32 *val)
+{
+ struct vsc73xx_platform *vsc_platform = vsc->priv;
+ u32 offset;
+
+ if (!vsc73xx_is_addr_valid(block, subblock))
+ return -EINVAL;
+
+ offset = vsc73xx_make_addr(block, subblock, reg);
+ /* By default vsc73xx running in big-endian mode.
+ * (See "Register Addressing" section 5.5.3 in the VSC7385 manual.)
+ */
+ *val = ioread32be(vsc_platform->base_addr + offset);
+
+ return 0;
+}
+
+static int vsc73xx_platform_write(struct vsc73xx *vsc, u8 block, u8 subblock,
+ u8 reg, u32 val)
+{
+ struct vsc73xx_platform *vsc_platform = vsc->priv;
+ u32 offset;
+
+ if (!vsc73xx_is_addr_valid(block, subblock))
+ return -EINVAL;
+
+ offset = vsc73xx_make_addr(block, subblock, reg);
+ iowrite32be(val, vsc_platform->base_addr + offset);
+
+ return 0;
+}
+
+static int vsc73xx_platform_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct vsc73xx_platform *vsc_platform;
+ struct resource *res = NULL;
+ int ret;
+
+ vsc_platform = devm_kzalloc(dev, sizeof(*vsc_platform), GFP_KERNEL);
+ if (!vsc_platform)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, vsc_platform);
+ vsc_platform->pdev = pdev;
+ vsc_platform->vsc.dev = dev;
+ vsc_platform->vsc.priv = vsc_platform;
+ vsc_platform->vsc.ops = &vsc73xx_platform_ops;
+
+ /* obtain I/O memory space */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "cannot obtain I/O memory space\n");
+ ret = -ENXIO;
+ return ret;
+ }
+
+ vsc_platform->base_addr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(vsc_platform->base_addr)) {
+ dev_err(&pdev->dev, "cannot request I/O memory space\n");
+ ret = -ENXIO;
+ return ret;
+ }
+
+ return vsc73xx_probe(&vsc_platform->vsc);
+}
+
+static int vsc73xx_platform_remove(struct platform_device *pdev)
+{
+ struct vsc73xx_platform *vsc_platform = platform_get_drvdata(pdev);
+
+ return vsc73xx_remove(&vsc_platform->vsc);
+}
+
+static const struct vsc73xx_ops vsc73xx_platform_ops = {
+ .read = vsc73xx_platform_read,
+ .write = vsc73xx_platform_write,
+};
+
+static const struct of_device_id vsc73xx_of_match[] = {
+ {
+ .compatible = "vitesse,vsc7385",
+ },
+ {
+ .compatible = "vitesse,vsc7388",
+ },
+ {
+ .compatible = "vitesse,vsc7395",
+ },
+ {
+ .compatible = "vitesse,vsc7398",
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, vsc73xx_of_match);
+
+static struct platform_driver vsc73xx_platform_driver = {
+ .probe = vsc73xx_platform_probe,
+ .remove = vsc73xx_platform_remove,
+ .driver = {
+ .name = "vsc73xx-platform",
+ .of_match_table = vsc73xx_of_match,
+ },
+};
+module_platform_driver(vsc73xx_platform_driver);
+
+MODULE_AUTHOR("Pawel Dembicki <paweldembicki@gmail.com>");
+MODULE_DESCRIPTION("Vitesse VSC7385/7388/7395/7398 Platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/dsa/vitesse-vsc73xx-spi.c b/drivers/net/dsa/vitesse-vsc73xx-spi.c
new file mode 100644
index 000000000000..e73c8fcddc9f
--- /dev/null
+++ b/drivers/net/dsa/vitesse-vsc73xx-spi.c
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: GPL-2.0
+/* DSA driver for:
+ * Vitesse VSC7385 SparX-G5 5+1-port Integrated Gigabit Ethernet Switch
+ * Vitesse VSC7388 SparX-G8 8-port Integrated Gigabit Ethernet Switch
+ * Vitesse VSC7395 SparX-G5e 5+1-port Integrated Gigabit Ethernet Switch
+ * Vitesse VSC7398 SparX-G8e 8-port Integrated Gigabit Ethernet Switch
+ *
+ * This driver takes control of the switch chip over SPI and
+ * configures it to route packages around when connected to a CPU port.
+ *
+ * Copyright (C) 2018 Linus Wallej <linus.walleij@linaro.org>
+ * Includes portions of code from the firmware uploader by:
+ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/spi/spi.h>
+
+#include "vitesse-vsc73xx.h"
+
+#define VSC73XX_CMD_SPI_MODE_READ 0
+#define VSC73XX_CMD_SPI_MODE_WRITE 1
+#define VSC73XX_CMD_SPI_MODE_SHIFT 4
+#define VSC73XX_CMD_SPI_BLOCK_SHIFT 5
+#define VSC73XX_CMD_SPI_BLOCK_MASK 0x7
+#define VSC73XX_CMD_SPI_SUBBLOCK_MASK 0xf
+
+/**
+ * struct vsc73xx_spi - VSC73xx SPI state container
+ */
+struct vsc73xx_spi {
+ struct spi_device *spi;
+ struct mutex lock; /* Protects SPI traffic */
+ struct vsc73xx vsc;
+};
+
+static const struct vsc73xx_ops vsc73xx_spi_ops;
+
+static u8 vsc73xx_make_addr(u8 mode, u8 block, u8 subblock)
+{
+ u8 ret;
+
+ ret =
+ (block & VSC73XX_CMD_SPI_BLOCK_MASK) << VSC73XX_CMD_SPI_BLOCK_SHIFT;
+ ret |= (mode & 1) << VSC73XX_CMD_SPI_MODE_SHIFT;
+ ret |= subblock & VSC73XX_CMD_SPI_SUBBLOCK_MASK;
+
+ return ret;
+}
+
+static int vsc73xx_spi_read(struct vsc73xx *vsc, u8 block, u8 subblock, u8 reg,
+ u32 *val)
+{
+ struct vsc73xx_spi *vsc_spi = vsc->priv;
+ struct spi_transfer t[2];
+ struct spi_message m;
+ u8 cmd[4];
+ u8 buf[4];
+ int ret;
+
+ if (!vsc73xx_is_addr_valid(block, subblock))
+ return -EINVAL;
+
+ spi_message_init(&m);
+
+ memset(&t, 0, sizeof(t));
+
+ t[0].tx_buf = cmd;
+ t[0].len = sizeof(cmd);
+ spi_message_add_tail(&t[0], &m);
+
+ t[1].rx_buf = buf;
+ t[1].len = sizeof(buf);
+ spi_message_add_tail(&t[1], &m);
+
+ cmd[0] = vsc73xx_make_addr(VSC73XX_CMD_SPI_MODE_READ, block, subblock);
+ cmd[1] = reg;
+ cmd[2] = 0;
+ cmd[3] = 0;
+
+ mutex_lock(&vsc_spi->lock);
+ ret = spi_sync(vsc_spi->spi, &m);
+ mutex_unlock(&vsc_spi->lock);
+
+ if (ret)
+ return ret;
+
+ *val = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
+
+ return 0;
+}
+
+static int vsc73xx_spi_write(struct vsc73xx *vsc, u8 block, u8 subblock, u8 reg,
+ u32 val)
+{
+ struct vsc73xx_spi *vsc_spi = vsc->priv;
+ struct spi_transfer t[2];
+ struct spi_message m;
+ u8 cmd[2];
+ u8 buf[4];
+ int ret;
+
+ if (!vsc73xx_is_addr_valid(block, subblock))
+ return -EINVAL;
+
+ spi_message_init(&m);
+
+ memset(&t, 0, sizeof(t));
+
+ t[0].tx_buf = cmd;
+ t[0].len = sizeof(cmd);
+ spi_message_add_tail(&t[0], &m);
+
+ t[1].tx_buf = buf;
+ t[1].len = sizeof(buf);
+ spi_message_add_tail(&t[1], &m);
+
+ cmd[0] = vsc73xx_make_addr(VSC73XX_CMD_SPI_MODE_WRITE, block, subblock);
+ cmd[1] = reg;
+
+ buf[0] = (val >> 24) & 0xff;
+ buf[1] = (val >> 16) & 0xff;
+ buf[2] = (val >> 8) & 0xff;
+ buf[3] = val & 0xff;
+
+ mutex_lock(&vsc_spi->lock);
+ ret = spi_sync(vsc_spi->spi, &m);
+ mutex_unlock(&vsc_spi->lock);
+
+ return ret;
+}
+
+static int vsc73xx_spi_probe(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+ struct vsc73xx_spi *vsc_spi;
+ int ret;
+
+ vsc_spi = devm_kzalloc(dev, sizeof(*vsc_spi), GFP_KERNEL);
+ if (!vsc_spi)
+ return -ENOMEM;
+
+ spi_set_drvdata(spi, vsc_spi);
+ vsc_spi->spi = spi_dev_get(spi);
+ vsc_spi->vsc.dev = dev;
+ vsc_spi->vsc.priv = vsc_spi;
+ vsc_spi->vsc.ops = &vsc73xx_spi_ops;
+ mutex_init(&vsc_spi->lock);
+
+ spi->mode = SPI_MODE_0;
+ spi->bits_per_word = 8;
+ ret = spi_setup(spi);
+ if (ret < 0) {
+ dev_err(dev, "spi setup failed.\n");
+ return ret;
+ }
+
+ return vsc73xx_probe(&vsc_spi->vsc);
+}
+
+static int vsc73xx_spi_remove(struct spi_device *spi)
+{
+ struct vsc73xx_spi *vsc_spi = spi_get_drvdata(spi);
+
+ return vsc73xx_remove(&vsc_spi->vsc);
+}
+
+static const struct vsc73xx_ops vsc73xx_spi_ops = {
+ .read = vsc73xx_spi_read,
+ .write = vsc73xx_spi_write,
+};
+
+static const struct of_device_id vsc73xx_of_match[] = {
+ {
+ .compatible = "vitesse,vsc7385",
+ },
+ {
+ .compatible = "vitesse,vsc7388",
+ },
+ {
+ .compatible = "vitesse,vsc7395",
+ },
+ {
+ .compatible = "vitesse,vsc7398",
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, vsc73xx_of_match);
+
+static struct spi_driver vsc73xx_spi_driver = {
+ .probe = vsc73xx_spi_probe,
+ .remove = vsc73xx_spi_remove,
+ .driver = {
+ .name = "vsc73xx-spi",
+ .of_match_table = vsc73xx_of_match,
+ },
+};
+module_spi_driver(vsc73xx_spi_driver);
+
+MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
+MODULE_DESCRIPTION("Vitesse VSC7385/7388/7395/7398 SPI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/dsa/vitesse-vsc73xx.h b/drivers/net/dsa/vitesse-vsc73xx.h
new file mode 100644
index 000000000000..7478f8d4e0a9
--- /dev/null
+++ b/drivers/net/dsa/vitesse-vsc73xx.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include <linux/device.h>
+#include <linux/etherdevice.h>
+#include <linux/gpio/driver.h>
+
+/**
+ * struct vsc73xx - VSC73xx state container
+ */
+struct vsc73xx {
+ struct device *dev;
+ struct gpio_desc *reset;
+ struct dsa_switch *ds;
+ struct gpio_chip gc;
+ u16 chipid;
+ u8 addr[ETH_ALEN];
+ const struct vsc73xx_ops *ops;
+ void *priv;
+};
+
+struct vsc73xx_ops {
+ int (*read)(struct vsc73xx *vsc, u8 block, u8 subblock, u8 reg,
+ u32 *val);
+ int (*write)(struct vsc73xx *vsc, u8 block, u8 subblock, u8 reg,
+ u32 val);
+};
+
+int vsc73xx_is_addr_valid(u8 block, u8 subblock);
+int vsc73xx_probe(struct vsc73xx *vsc);
+int vsc73xx_remove(struct vsc73xx *vsc);
diff --git a/drivers/net/ethernet/8390/Kconfig b/drivers/net/ethernet/8390/Kconfig
index bb09319feedf..2a3e2450968e 100644
--- a/drivers/net/ethernet/8390/Kconfig
+++ b/drivers/net/ethernet/8390/Kconfig
@@ -50,7 +50,7 @@ config XSURF100
tristate "Amiga XSurf 100 AX88796/NE2000 clone support"
depends on ZORRO
select AX88796
- select ASIX_PHY
+ select AX88796B_PHY
help
This driver is for the Individual Computers X-Surf 100 Ethernet
card (based on the Asix AX88796 chip). If you have such a card,
diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c
index 3dcc61821ed5..172947fc051a 100644
--- a/drivers/net/ethernet/8390/ax88796.c
+++ b/drivers/net/ethernet/8390/ax88796.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* drivers/net/ethernet/8390/ax88796.c
*
* Copyright 2005,2007 Simtec Electronics
@@ -5,10 +6,6 @@
*
* Asix AX88796 10/100 Ethernet controller support
* Based on ne.c, by Donald Becker, et-al.
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/net/ethernet/8390/etherh.c b/drivers/net/ethernet/8390/etherh.c
index 77191a281866..bd22a534b1c0 100644
--- a/drivers/net/ethernet/8390/etherh.c
+++ b/drivers/net/ethernet/8390/etherh.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/acorn/net/etherh.c
*
* Copyright (C) 2000-2002 Russell King
*
- * 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.
- *
* NS8390 I-cubed EtherH and ANT EtherM specific driver
* Thanks to I-Cubed for information on their cards.
* EtherM conversion (C) 1999 Chris Kemp and Tim Watterton
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index fe115b7caba0..93a2d4deb27c 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -76,6 +76,7 @@ source "drivers/net/ethernet/ezchip/Kconfig"
source "drivers/net/ethernet/faraday/Kconfig"
source "drivers/net/ethernet/freescale/Kconfig"
source "drivers/net/ethernet/fujitsu/Kconfig"
+source "drivers/net/ethernet/google/Kconfig"
source "drivers/net/ethernet/hisilicon/Kconfig"
source "drivers/net/ethernet/hp/Kconfig"
source "drivers/net/ethernet/huawei/Kconfig"
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index 7b5bf9682066..fb9155cffcff 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_NET_VENDOR_EZCHIP) += ezchip/
obj-$(CONFIG_NET_VENDOR_FARADAY) += faraday/
obj-$(CONFIG_NET_VENDOR_FREESCALE) += freescale/
obj-$(CONFIG_NET_VENDOR_FUJITSU) += fujitsu/
+obj-$(CONFIG_NET_VENDOR_GOOGLE) += google/
obj-$(CONFIG_NET_VENDOR_HISILICON) += hisilicon/
obj-$(CONFIG_NET_VENDOR_HP) += hp/
obj-$(CONFIG_NET_VENDOR_HUAWEI) += huawei/
diff --git a/drivers/net/ethernet/alacritech/slicoss.c b/drivers/net/ethernet/alacritech/slicoss.c
index 4f7e792e50e9..80ef3e15bd22 100644
--- a/drivers/net/ethernet/alacritech/slicoss.c
+++ b/drivers/net/ethernet/alacritech/slicoss.c
@@ -1,19 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for Gigabit Ethernet adapters based on the Session Layer
* Interface (SLIC) technology by Alacritech. The driver does not
* support the hardware acceleration features provided by these cards.
*
* Copyright (C) 2016 Lino Sanfilippo <LinoSanfilippo@gmx.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/net/ethernet/allwinner/sun4i-emac.c b/drivers/net/ethernet/allwinner/sun4i-emac.c
index 9e06dff619c3..3434730a7699 100644
--- a/drivers/net/ethernet/allwinner/sun4i-emac.c
+++ b/drivers/net/ethernet/allwinner/sun4i-emac.c
@@ -224,8 +224,8 @@ static int emac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
static void emac_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
- strlcpy(info->driver, DRV_NAME, sizeof(DRV_NAME));
- strlcpy(info->version, DRV_VERSION, sizeof(DRV_VERSION));
+ strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_VERSION, sizeof(info->version));
strlcpy(info->bus_info, dev_name(&dev->dev), sizeof(info->bus_info));
}
@@ -818,7 +818,6 @@ static int emac_probe(struct platform_device *pdev)
SET_NETDEV_DEV(ndev, &pdev->dev);
db = netdev_priv(ndev);
- memset(db, 0, sizeof(*db));
db->dev = &pdev->dev;
db->ndev = ndev;
diff --git a/drivers/net/ethernet/amazon/ena/ena_admin_defs.h b/drivers/net/ethernet/amazon/ena/ena_admin_defs.h
index 9f80b73f90b1..d19f2ecf8e84 100644
--- a/drivers/net/ethernet/amazon/ena/ena_admin_defs.h
+++ b/drivers/net/ethernet/amazon/ena/ena_admin_defs.h
@@ -60,6 +60,7 @@ enum ena_admin_aq_feature_id {
ENA_ADMIN_MAX_QUEUES_NUM = 2,
ENA_ADMIN_HW_HINTS = 3,
ENA_ADMIN_LLQ = 4,
+ ENA_ADMIN_MAX_QUEUES_EXT = 7,
ENA_ADMIN_RSS_HASH_FUNCTION = 10,
ENA_ADMIN_STATELESS_OFFLOAD_CONFIG = 11,
ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG = 12,
@@ -421,7 +422,13 @@ struct ena_admin_get_set_feature_common_desc {
/* as appears in ena_admin_aq_feature_id */
u8 feature_id;
- u16 reserved16;
+ /* The driver specifies the max feature version it supports and the
+ * device responds with the currently supported feature version. The
+ * field is zero based
+ */
+ u8 feature_version;
+
+ u8 reserved8;
};
struct ena_admin_device_attr_feature_desc {
@@ -524,6 +531,39 @@ struct ena_admin_feature_llq_desc {
/* the stride control the driver selected to use */
u16 descriptors_stride_ctrl_enabled;
+
+ /* Maximum size in bytes taken by llq entries in a single tx burst.
+ * Set to 0 when there is no such limit.
+ */
+ u32 max_tx_burst_size;
+};
+
+struct ena_admin_queue_ext_feature_fields {
+ u32 max_tx_sq_num;
+
+ u32 max_tx_cq_num;
+
+ u32 max_rx_sq_num;
+
+ u32 max_rx_cq_num;
+
+ u32 max_tx_sq_depth;
+
+ u32 max_tx_cq_depth;
+
+ u32 max_rx_sq_depth;
+
+ u32 max_rx_cq_depth;
+
+ u32 max_tx_header_size;
+
+ /* Maximum Descriptors number, including meta descriptor, allowed for
+ * a single Tx packet
+ */
+ u16 max_per_packet_tx_descs;
+
+ /* Maximum Descriptors number allowed for a single Rx packet */
+ u16 max_per_packet_rx_descs;
};
struct ena_admin_queue_feature_desc {
@@ -832,6 +872,19 @@ struct ena_admin_get_feat_cmd {
u32 raw[11];
};
+struct ena_admin_queue_ext_feature_desc {
+ /* version */
+ u8 version;
+
+ u8 reserved1[3];
+
+ union {
+ struct ena_admin_queue_ext_feature_fields max_queue_ext;
+
+ u32 raw[10];
+ };
+};
+
struct ena_admin_get_feat_resp {
struct ena_admin_acq_common_desc acq_common_desc;
@@ -844,6 +897,8 @@ struct ena_admin_get_feat_resp {
struct ena_admin_queue_feature_desc max_queue;
+ struct ena_admin_queue_ext_feature_desc max_queue_ext;
+
struct ena_admin_feature_aenq_desc aenq;
struct ena_admin_get_feature_link_desc link;
@@ -908,7 +963,9 @@ struct ena_admin_aenq_common_desc {
u16 syndrom;
- /* 0 : phase */
+ /* 0 : phase
+ * 7:1 : reserved - MBZ
+ */
u8 flags;
u8 reserved1[3];
diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c
index 7f8266b191ae..911a2e7a375a 100644
--- a/drivers/net/ethernet/amazon/ena/ena_com.c
+++ b/drivers/net/ethernet/amazon/ena/ena_com.c
@@ -91,7 +91,7 @@ struct ena_com_stats_ctx {
struct ena_admin_acq_get_stats_resp get_resp;
};
-static inline int ena_com_mem_addr_set(struct ena_com_dev *ena_dev,
+static int ena_com_mem_addr_set(struct ena_com_dev *ena_dev,
struct ena_common_mem_addr *ena_addr,
dma_addr_t addr)
{
@@ -115,7 +115,7 @@ static int ena_com_admin_init_sq(struct ena_com_admin_queue *queue)
GFP_KERNEL);
if (!sq->entries) {
- pr_err("memory allocation failed");
+ pr_err("memory allocation failed\n");
return -ENOMEM;
}
@@ -137,7 +137,7 @@ static int ena_com_admin_init_cq(struct ena_com_admin_queue *queue)
GFP_KERNEL);
if (!cq->entries) {
- pr_err("memory allocation failed");
+ pr_err("memory allocation failed\n");
return -ENOMEM;
}
@@ -160,7 +160,7 @@ static int ena_com_admin_init_aenq(struct ena_com_dev *dev,
GFP_KERNEL);
if (!aenq->entries) {
- pr_err("memory allocation failed");
+ pr_err("memory allocation failed\n");
return -ENOMEM;
}
@@ -190,7 +190,7 @@ static int ena_com_admin_init_aenq(struct ena_com_dev *dev,
return 0;
}
-static inline void comp_ctxt_release(struct ena_com_admin_queue *queue,
+static void comp_ctxt_release(struct ena_com_admin_queue *queue,
struct ena_comp_ctx *comp_ctx)
{
comp_ctx->occupied = false;
@@ -277,7 +277,7 @@ static struct ena_comp_ctx *__ena_com_submit_admin_cmd(struct ena_com_admin_queu
return comp_ctx;
}
-static inline int ena_com_init_comp_ctxt(struct ena_com_admin_queue *queue)
+static int ena_com_init_comp_ctxt(struct ena_com_admin_queue *queue)
{
size_t size = queue->q_depth * sizeof(struct ena_comp_ctx);
struct ena_comp_ctx *comp_ctx;
@@ -285,7 +285,7 @@ static inline int ena_com_init_comp_ctxt(struct ena_com_admin_queue *queue)
queue->comp_ctx = devm_kzalloc(queue->q_dmadev, size, GFP_KERNEL);
if (unlikely(!queue->comp_ctx)) {
- pr_err("memory allocation failed");
+ pr_err("memory allocation failed\n");
return -ENOMEM;
}
@@ -356,7 +356,7 @@ static int ena_com_init_io_sq(struct ena_com_dev *ena_dev,
}
if (!io_sq->desc_addr.virt_addr) {
- pr_err("memory allocation failed");
+ pr_err("memory allocation failed\n");
return -ENOMEM;
}
}
@@ -382,7 +382,7 @@ static int ena_com_init_io_sq(struct ena_com_dev *ena_dev,
devm_kzalloc(ena_dev->dmadev, size, GFP_KERNEL);
if (!io_sq->bounce_buf_ctrl.base_buffer) {
- pr_err("bounce buffer memory allocation failed");
+ pr_err("bounce buffer memory allocation failed\n");
return -ENOMEM;
}
@@ -396,6 +396,10 @@ static int ena_com_init_io_sq(struct ena_com_dev *ena_dev,
0x0, io_sq->llq_info.desc_list_entry_size);
io_sq->llq_buf_ctrl.descs_left_in_line =
io_sq->llq_info.descs_num_before_header;
+
+ if (io_sq->llq_info.max_entries_in_tx_burst > 0)
+ io_sq->entries_in_tx_burst_left =
+ io_sq->llq_info.max_entries_in_tx_burst;
}
io_sq->tail = 0;
@@ -436,7 +440,7 @@ static int ena_com_init_io_cq(struct ena_com_dev *ena_dev,
}
if (!io_cq->cdesc_addr.virt_addr) {
- pr_err("memory allocation failed");
+ pr_err("memory allocation failed\n");
return -ENOMEM;
}
@@ -727,6 +731,9 @@ static int ena_com_config_llq_info(struct ena_com_dev *ena_dev,
supported_feat, llq_info->descs_num_before_header);
}
+ llq_info->max_entries_in_tx_burst =
+ (u16)(llq_features->max_tx_burst_size / llq_default_cfg->llq_ring_entry_size_value);
+
rc = ena_com_set_llq(ena_dev);
if (rc)
pr_err("Cannot set LLQ configuration: %d\n", rc);
@@ -755,16 +762,26 @@ static int ena_com_wait_and_process_admin_cq_interrupts(struct ena_comp_ctx *com
admin_queue->stats.no_completion++;
spin_unlock_irqrestore(&admin_queue->q_lock, flags);
- if (comp_ctx->status == ENA_CMD_COMPLETED)
- pr_err("The ena device have completion but the driver didn't receive any MSI-X interrupt (cmd %d)\n",
- comp_ctx->cmd_opcode);
- else
- pr_err("The ena device doesn't send any completion for the admin cmd %d status %d\n",
+ if (comp_ctx->status == ENA_CMD_COMPLETED) {
+ pr_err("The ena device sent a completion but the driver didn't receive a MSI-X interrupt (cmd %d), autopolling mode is %s\n",
+ comp_ctx->cmd_opcode,
+ admin_queue->auto_polling ? "ON" : "OFF");
+ /* Check if fallback to polling is enabled */
+ if (admin_queue->auto_polling)
+ admin_queue->polling = true;
+ } else {
+ pr_err("The ena device doesn't send a completion for the admin cmd %d status %d\n",
comp_ctx->cmd_opcode, comp_ctx->status);
-
- admin_queue->running_state = false;
- ret = -ETIME;
- goto err;
+ }
+ /* Check if shifted to polling mode.
+ * This will happen if there is a completion without an interrupt
+ * and autopolling mode is enabled. Continuing normal execution in such case
+ */
+ if (!admin_queue->polling) {
+ admin_queue->running_state = false;
+ ret = -ETIME;
+ goto err;
+ }
}
ret = ena_com_comp_status_to_errno(comp_ctx->comp_status);
@@ -822,7 +839,7 @@ static u32 ena_com_reg_bar_read32(struct ena_com_dev *ena_dev, u16 offset)
}
if (read_resp->reg_off != offset) {
- pr_err("Read failure: wrong offset provided");
+ pr_err("Read failure: wrong offset provided\n");
ret = ENA_MMIO_READ_TIMEOUT;
} else {
ret = read_resp->reg_val;
@@ -961,7 +978,8 @@ static int ena_com_get_feature_ex(struct ena_com_dev *ena_dev,
struct ena_admin_get_feat_resp *get_resp,
enum ena_admin_aq_feature_id feature_id,
dma_addr_t control_buf_dma_addr,
- u32 control_buff_size)
+ u32 control_buff_size,
+ u8 feature_ver)
{
struct ena_com_admin_queue *admin_queue;
struct ena_admin_get_feat_cmd get_cmd;
@@ -992,7 +1010,7 @@ static int ena_com_get_feature_ex(struct ena_com_dev *ena_dev,
}
get_cmd.control_buffer.length = control_buff_size;
-
+ get_cmd.feat_common.feature_version = feature_ver;
get_cmd.feat_common.feature_id = feature_id;
ret = ena_com_execute_admin_command(admin_queue,
@@ -1012,13 +1030,15 @@ static int ena_com_get_feature_ex(struct ena_com_dev *ena_dev,
static int ena_com_get_feature(struct ena_com_dev *ena_dev,
struct ena_admin_get_feat_resp *get_resp,
- enum ena_admin_aq_feature_id feature_id)
+ enum ena_admin_aq_feature_id feature_id,
+ u8 feature_ver)
{
return ena_com_get_feature_ex(ena_dev,
get_resp,
feature_id,
0,
- 0);
+ 0,
+ feature_ver);
}
static int ena_com_hash_key_allocate(struct ena_com_dev *ena_dev)
@@ -1078,7 +1098,7 @@ static int ena_com_indirect_table_allocate(struct ena_com_dev *ena_dev,
int ret;
ret = ena_com_get_feature(ena_dev, &get_resp,
- ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG);
+ ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG, 0);
if (unlikely(ret))
return ret;
@@ -1498,7 +1518,7 @@ int ena_com_set_aenq_config(struct ena_com_dev *ena_dev, u32 groups_flag)
struct ena_admin_get_feat_resp get_resp;
int ret;
- ret = ena_com_get_feature(ena_dev, &get_resp, ENA_ADMIN_AENQ_CONFIG);
+ ret = ena_com_get_feature(ena_dev, &get_resp, ENA_ADMIN_AENQ_CONFIG, 0);
if (ret) {
pr_info("Can't get aenq configuration\n");
return ret;
@@ -1643,6 +1663,12 @@ void ena_com_set_admin_polling_mode(struct ena_com_dev *ena_dev, bool polling)
ena_dev->admin_queue.polling = polling;
}
+void ena_com_set_admin_auto_polling_mode(struct ena_com_dev *ena_dev,
+ bool polling)
+{
+ ena_dev->admin_queue.auto_polling = polling;
+}
+
int ena_com_mmio_reg_read_request_init(struct ena_com_dev *ena_dev)
{
struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read;
@@ -1867,7 +1893,7 @@ void ena_com_destroy_io_queue(struct ena_com_dev *ena_dev, u16 qid)
int ena_com_get_link_params(struct ena_com_dev *ena_dev,
struct ena_admin_get_feat_resp *resp)
{
- return ena_com_get_feature(ena_dev, resp, ENA_ADMIN_LINK_CONFIG);
+ return ena_com_get_feature(ena_dev, resp, ENA_ADMIN_LINK_CONFIG, 0);
}
int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev,
@@ -1877,7 +1903,7 @@ int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev,
int rc;
rc = ena_com_get_feature(ena_dev, &get_resp,
- ENA_ADMIN_DEVICE_ATTRIBUTES);
+ ENA_ADMIN_DEVICE_ATTRIBUTES, 0);
if (rc)
return rc;
@@ -1885,17 +1911,34 @@ int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev,
sizeof(get_resp.u.dev_attr));
ena_dev->supported_features = get_resp.u.dev_attr.supported_features;
- rc = ena_com_get_feature(ena_dev, &get_resp,
- ENA_ADMIN_MAX_QUEUES_NUM);
- if (rc)
- return rc;
+ if (ena_dev->supported_features & BIT(ENA_ADMIN_MAX_QUEUES_EXT)) {
+ rc = ena_com_get_feature(ena_dev, &get_resp,
+ ENA_ADMIN_MAX_QUEUES_EXT,
+ ENA_FEATURE_MAX_QUEUE_EXT_VER);
+ if (rc)
+ return rc;
- memcpy(&get_feat_ctx->max_queues, &get_resp.u.max_queue,
- sizeof(get_resp.u.max_queue));
- ena_dev->tx_max_header_size = get_resp.u.max_queue.max_header_size;
+ if (get_resp.u.max_queue_ext.version != ENA_FEATURE_MAX_QUEUE_EXT_VER)
+ return -EINVAL;
+
+ memcpy(&get_feat_ctx->max_queue_ext, &get_resp.u.max_queue_ext,
+ sizeof(get_resp.u.max_queue_ext));
+ ena_dev->tx_max_header_size =
+ get_resp.u.max_queue_ext.max_queue_ext.max_tx_header_size;
+ } else {
+ rc = ena_com_get_feature(ena_dev, &get_resp,
+ ENA_ADMIN_MAX_QUEUES_NUM, 0);
+ memcpy(&get_feat_ctx->max_queues, &get_resp.u.max_queue,
+ sizeof(get_resp.u.max_queue));
+ ena_dev->tx_max_header_size =
+ get_resp.u.max_queue.max_header_size;
+
+ if (rc)
+ return rc;
+ }
rc = ena_com_get_feature(ena_dev, &get_resp,
- ENA_ADMIN_AENQ_CONFIG);
+ ENA_ADMIN_AENQ_CONFIG, 0);
if (rc)
return rc;
@@ -1903,7 +1946,7 @@ int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev,
sizeof(get_resp.u.aenq));
rc = ena_com_get_feature(ena_dev, &get_resp,
- ENA_ADMIN_STATELESS_OFFLOAD_CONFIG);
+ ENA_ADMIN_STATELESS_OFFLOAD_CONFIG, 0);
if (rc)
return rc;
@@ -1913,7 +1956,7 @@ int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev,
/* Driver hints isn't mandatory admin command. So in case the
* command isn't supported set driver hints to 0
*/
- rc = ena_com_get_feature(ena_dev, &get_resp, ENA_ADMIN_HW_HINTS);
+ rc = ena_com_get_feature(ena_dev, &get_resp, ENA_ADMIN_HW_HINTS, 0);
if (!rc)
memcpy(&get_feat_ctx->hw_hints, &get_resp.u.hw_hints,
@@ -1924,7 +1967,7 @@ int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev,
else
return rc;
- rc = ena_com_get_feature(ena_dev, &get_resp, ENA_ADMIN_LLQ);
+ rc = ena_com_get_feature(ena_dev, &get_resp, ENA_ADMIN_LLQ, 0);
if (!rc)
memcpy(&get_feat_ctx->llq, &get_resp.u.llq,
sizeof(get_resp.u.llq));
@@ -2161,7 +2204,7 @@ int ena_com_get_offload_settings(struct ena_com_dev *ena_dev,
struct ena_admin_get_feat_resp resp;
ret = ena_com_get_feature(ena_dev, &resp,
- ENA_ADMIN_STATELESS_OFFLOAD_CONFIG);
+ ENA_ADMIN_STATELESS_OFFLOAD_CONFIG, 0);
if (unlikely(ret)) {
pr_err("Failed to get offload capabilities %d\n", ret);
return ret;
@@ -2190,7 +2233,7 @@ int ena_com_set_hash_function(struct ena_com_dev *ena_dev)
/* Validate hash function is supported */
ret = ena_com_get_feature(ena_dev, &get_resp,
- ENA_ADMIN_RSS_HASH_FUNCTION);
+ ENA_ADMIN_RSS_HASH_FUNCTION, 0);
if (unlikely(ret))
return ret;
@@ -2250,7 +2293,7 @@ int ena_com_fill_hash_function(struct ena_com_dev *ena_dev,
rc = ena_com_get_feature_ex(ena_dev, &get_resp,
ENA_ADMIN_RSS_HASH_FUNCTION,
rss->hash_key_dma_addr,
- sizeof(*rss->hash_key));
+ sizeof(*rss->hash_key), 0);
if (unlikely(rc))
return rc;
@@ -2302,7 +2345,7 @@ int ena_com_get_hash_function(struct ena_com_dev *ena_dev,
rc = ena_com_get_feature_ex(ena_dev, &get_resp,
ENA_ADMIN_RSS_HASH_FUNCTION,
rss->hash_key_dma_addr,
- sizeof(*rss->hash_key));
+ sizeof(*rss->hash_key), 0);
if (unlikely(rc))
return rc;
@@ -2327,7 +2370,7 @@ int ena_com_get_hash_ctrl(struct ena_com_dev *ena_dev,
rc = ena_com_get_feature_ex(ena_dev, &get_resp,
ENA_ADMIN_RSS_HASH_INPUT,
rss->hash_ctrl_dma_addr,
- sizeof(*rss->hash_ctrl));
+ sizeof(*rss->hash_ctrl), 0);
if (unlikely(rc))
return rc;
@@ -2563,7 +2606,7 @@ int ena_com_indirect_table_get(struct ena_com_dev *ena_dev, u32 *ind_tbl)
rc = ena_com_get_feature_ex(ena_dev, &get_resp,
ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG,
rss->rss_ind_tbl_dma_addr,
- tbl_size);
+ tbl_size, 0);
if (unlikely(rc))
return rc;
@@ -2778,7 +2821,7 @@ int ena_com_init_interrupt_moderation(struct ena_com_dev *ena_dev)
int rc;
rc = ena_com_get_feature(ena_dev, &get_resp,
- ENA_ADMIN_INTERRUPT_MODERATION);
+ ENA_ADMIN_INTERRUPT_MODERATION, 0);
if (rc) {
if (rc == -EOPNOTSUPP) {
@@ -2913,8 +2956,8 @@ int ena_com_config_dev_mode(struct ena_com_dev *ena_dev,
struct ena_admin_feature_llq_desc *llq_features,
struct ena_llq_configurations *llq_default_cfg)
{
+ struct ena_com_llq_info *llq_info = &ena_dev->llq_info;
int rc;
- int size;
if (!llq_features->max_llq_num) {
ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
@@ -2925,12 +2968,10 @@ int ena_com_config_dev_mode(struct ena_com_dev *ena_dev,
if (rc)
return rc;
- /* Validate the descriptor is not too big */
- size = ena_dev->tx_max_header_size;
- size += ena_dev->llq_info.descs_num_before_header *
- sizeof(struct ena_eth_io_tx_desc);
+ ena_dev->tx_max_header_size = llq_info->desc_list_entry_size -
+ (llq_info->descs_num_before_header * sizeof(struct ena_eth_io_tx_desc));
- if (unlikely(ena_dev->llq_info.desc_list_entry_size < size)) {
+ if (unlikely(ena_dev->tx_max_header_size == 0)) {
pr_err("the size of the LLQ entry is smaller than needed\n");
return -EINVAL;
}
diff --git a/drivers/net/ethernet/amazon/ena/ena_com.h b/drivers/net/ethernet/amazon/ena/ena_com.h
index 078d6f2b4f39..0d3664fe260d 100644
--- a/drivers/net/ethernet/amazon/ena/ena_com.h
+++ b/drivers/net/ethernet/amazon/ena/ena_com.h
@@ -101,6 +101,8 @@
#define ENA_HW_HINTS_NO_TIMEOUT 0xFFFF
+#define ENA_FEATURE_MAX_QUEUE_EXT_VER 1
+
enum ena_intr_moder_level {
ENA_INTR_MODER_LOWEST = 0,
ENA_INTR_MODER_LOW,
@@ -159,6 +161,7 @@ struct ena_com_llq_info {
u16 desc_list_entry_size;
u16 descs_num_before_header;
u16 descs_per_entry;
+ u16 max_entries_in_tx_burst;
};
struct ena_com_io_cq {
@@ -238,6 +241,7 @@ struct ena_com_io_sq {
u8 phase;
u8 desc_entry_size;
u8 dma_addr_bits;
+ u16 entries_in_tx_burst_left;
} ____cacheline_aligned;
struct ena_com_admin_cq {
@@ -281,6 +285,9 @@ struct ena_com_admin_queue {
/* Indicate if the admin queue should poll for completion */
bool polling;
+ /* Define if fallback to polling mode should occur */
+ bool auto_polling;
+
u16 curr_cmd_id;
/* Indicate that the ena was initialized and can
@@ -377,6 +384,7 @@ struct ena_com_dev {
struct ena_com_dev_get_features_ctx {
struct ena_admin_queue_feature_desc max_queues;
+ struct ena_admin_queue_ext_feature_desc max_queue_ext;
struct ena_admin_device_attr_feature_desc dev_attr;
struct ena_admin_feature_aenq_desc aenq;
struct ena_admin_feature_offload_desc offload;
@@ -536,6 +544,17 @@ void ena_com_set_admin_polling_mode(struct ena_com_dev *ena_dev, bool polling);
*/
bool ena_com_get_ena_admin_polling_mode(struct ena_com_dev *ena_dev);
+/* ena_com_set_admin_auto_polling_mode - Enable autoswitch to polling mode
+ * @ena_dev: ENA communication layer struct
+ * @polling: Enable/Disable polling mode
+ *
+ * Set the autopolling mode.
+ * If autopolling is on:
+ * In case of missing interrupt when data is available switch to polling.
+ */
+void ena_com_set_admin_auto_polling_mode(struct ena_com_dev *ena_dev,
+ bool polling);
+
/* ena_com_admin_q_comp_intr_handler - admin queue interrupt handler
* @ena_dev: ENA communication layer struct
*
diff --git a/drivers/net/ethernet/amazon/ena/ena_eth_com.c b/drivers/net/ethernet/amazon/ena/ena_eth_com.c
index f6c2d3855be8..38046bf0ff44 100644
--- a/drivers/net/ethernet/amazon/ena/ena_eth_com.c
+++ b/drivers/net/ethernet/amazon/ena/ena_eth_com.c
@@ -32,7 +32,7 @@
#include "ena_eth_com.h"
-static inline struct ena_eth_io_rx_cdesc_base *ena_com_get_next_rx_cdesc(
+static struct ena_eth_io_rx_cdesc_base *ena_com_get_next_rx_cdesc(
struct ena_com_io_cq *io_cq)
{
struct ena_eth_io_rx_cdesc_base *cdesc;
@@ -59,7 +59,7 @@ static inline struct ena_eth_io_rx_cdesc_base *ena_com_get_next_rx_cdesc(
return cdesc;
}
-static inline void *get_sq_desc_regular_queue(struct ena_com_io_sq *io_sq)
+static void *get_sq_desc_regular_queue(struct ena_com_io_sq *io_sq)
{
u16 tail_masked;
u32 offset;
@@ -71,7 +71,7 @@ static inline void *get_sq_desc_regular_queue(struct ena_com_io_sq *io_sq)
return (void *)((uintptr_t)io_sq->desc_addr.virt_addr + offset);
}
-static inline int ena_com_write_bounce_buffer_to_dev(struct ena_com_io_sq *io_sq,
+static int ena_com_write_bounce_buffer_to_dev(struct ena_com_io_sq *io_sq,
u8 *bounce_buffer)
{
struct ena_com_llq_info *llq_info = &io_sq->llq_info;
@@ -82,6 +82,17 @@ static inline int ena_com_write_bounce_buffer_to_dev(struct ena_com_io_sq *io_sq
dst_tail_mask = io_sq->tail & (io_sq->q_depth - 1);
dst_offset = dst_tail_mask * llq_info->desc_list_entry_size;
+ if (is_llq_max_tx_burst_exists(io_sq)) {
+ if (unlikely(!io_sq->entries_in_tx_burst_left)) {
+ pr_err("Error: trying to send more packets than tx burst allows\n");
+ return -ENOSPC;
+ }
+
+ io_sq->entries_in_tx_burst_left--;
+ pr_debug("decreasing entries_in_tx_burst_left of queue %d to %d\n",
+ io_sq->qid, io_sq->entries_in_tx_burst_left);
+ }
+
/* Make sure everything was written into the bounce buffer before
* writing the bounce buffer to the device
*/
@@ -100,7 +111,7 @@ static inline int ena_com_write_bounce_buffer_to_dev(struct ena_com_io_sq *io_sq
return 0;
}
-static inline int ena_com_write_header_to_bounce(struct ena_com_io_sq *io_sq,
+static int ena_com_write_header_to_bounce(struct ena_com_io_sq *io_sq,
u8 *header_src,
u16 header_len)
{
@@ -131,7 +142,7 @@ static inline int ena_com_write_header_to_bounce(struct ena_com_io_sq *io_sq,
return 0;
}
-static inline void *get_sq_desc_llq(struct ena_com_io_sq *io_sq)
+static void *get_sq_desc_llq(struct ena_com_io_sq *io_sq)
{
struct ena_com_llq_pkt_ctrl *pkt_ctrl = &io_sq->llq_buf_ctrl;
u8 *bounce_buffer;
@@ -151,7 +162,7 @@ static inline void *get_sq_desc_llq(struct ena_com_io_sq *io_sq)
return sq_desc;
}
-static inline int ena_com_close_bounce_buffer(struct ena_com_io_sq *io_sq)
+static int ena_com_close_bounce_buffer(struct ena_com_io_sq *io_sq)
{
struct ena_com_llq_pkt_ctrl *pkt_ctrl = &io_sq->llq_buf_ctrl;
struct ena_com_llq_info *llq_info = &io_sq->llq_info;
@@ -178,7 +189,7 @@ static inline int ena_com_close_bounce_buffer(struct ena_com_io_sq *io_sq)
return 0;
}
-static inline void *get_sq_desc(struct ena_com_io_sq *io_sq)
+static void *get_sq_desc(struct ena_com_io_sq *io_sq)
{
if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV)
return get_sq_desc_llq(io_sq);
@@ -186,7 +197,7 @@ static inline void *get_sq_desc(struct ena_com_io_sq *io_sq)
return get_sq_desc_regular_queue(io_sq);
}
-static inline int ena_com_sq_update_llq_tail(struct ena_com_io_sq *io_sq)
+static int ena_com_sq_update_llq_tail(struct ena_com_io_sq *io_sq)
{
struct ena_com_llq_pkt_ctrl *pkt_ctrl = &io_sq->llq_buf_ctrl;
struct ena_com_llq_info *llq_info = &io_sq->llq_info;
@@ -214,7 +225,7 @@ static inline int ena_com_sq_update_llq_tail(struct ena_com_io_sq *io_sq)
return 0;
}
-static inline int ena_com_sq_update_tail(struct ena_com_io_sq *io_sq)
+static int ena_com_sq_update_tail(struct ena_com_io_sq *io_sq)
{
if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV)
return ena_com_sq_update_llq_tail(io_sq);
@@ -228,7 +239,7 @@ static inline int ena_com_sq_update_tail(struct ena_com_io_sq *io_sq)
return 0;
}
-static inline struct ena_eth_io_rx_cdesc_base *
+static struct ena_eth_io_rx_cdesc_base *
ena_com_rx_cdesc_idx_to_ptr(struct ena_com_io_cq *io_cq, u16 idx)
{
idx &= (io_cq->q_depth - 1);
@@ -237,7 +248,7 @@ static inline struct ena_eth_io_rx_cdesc_base *
idx * io_cq->cdesc_entry_size_in_bytes);
}
-static inline u16 ena_com_cdesc_rx_pkt_get(struct ena_com_io_cq *io_cq,
+static u16 ena_com_cdesc_rx_pkt_get(struct ena_com_io_cq *io_cq,
u16 *first_cdesc_idx)
{
struct ena_eth_io_rx_cdesc_base *cdesc;
@@ -274,24 +285,7 @@ static inline u16 ena_com_cdesc_rx_pkt_get(struct ena_com_io_cq *io_cq,
return count;
}
-static inline bool ena_com_meta_desc_changed(struct ena_com_io_sq *io_sq,
- struct ena_com_tx_ctx *ena_tx_ctx)
-{
- int rc;
-
- if (ena_tx_ctx->meta_valid) {
- rc = memcmp(&io_sq->cached_tx_meta,
- &ena_tx_ctx->ena_meta,
- sizeof(struct ena_com_tx_meta));
-
- if (unlikely(rc != 0))
- return true;
- }
-
- return false;
-}
-
-static inline int ena_com_create_and_store_tx_meta_desc(struct ena_com_io_sq *io_sq,
+static int ena_com_create_and_store_tx_meta_desc(struct ena_com_io_sq *io_sq,
struct ena_com_tx_ctx *ena_tx_ctx)
{
struct ena_eth_io_tx_meta_desc *meta_desc = NULL;
@@ -340,7 +334,7 @@ static inline int ena_com_create_and_store_tx_meta_desc(struct ena_com_io_sq *io
return ena_com_sq_update_tail(io_sq);
}
-static inline void ena_com_rx_set_flags(struct ena_com_rx_ctx *ena_rx_ctx,
+static void ena_com_rx_set_flags(struct ena_com_rx_ctx *ena_rx_ctx,
struct ena_eth_io_rx_cdesc_base *cdesc)
{
ena_rx_ctx->l3_proto = cdesc->status &
diff --git a/drivers/net/ethernet/amazon/ena/ena_eth_com.h b/drivers/net/ethernet/amazon/ena/ena_eth_com.h
index 340d02b64ca6..77986c0ea52c 100644
--- a/drivers/net/ethernet/amazon/ena/ena_eth_com.h
+++ b/drivers/net/ethernet/amazon/ena/ena_eth_com.h
@@ -125,8 +125,55 @@ static inline bool ena_com_sq_have_enough_space(struct ena_com_io_sq *io_sq,
return ena_com_free_desc(io_sq) > temp;
}
+static inline bool ena_com_meta_desc_changed(struct ena_com_io_sq *io_sq,
+ struct ena_com_tx_ctx *ena_tx_ctx)
+{
+ if (!ena_tx_ctx->meta_valid)
+ return false;
+
+ return !!memcmp(&io_sq->cached_tx_meta,
+ &ena_tx_ctx->ena_meta,
+ sizeof(struct ena_com_tx_meta));
+}
+
+static inline bool is_llq_max_tx_burst_exists(struct ena_com_io_sq *io_sq)
+{
+ return (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) &&
+ io_sq->llq_info.max_entries_in_tx_burst > 0;
+}
+
+static inline bool ena_com_is_doorbell_needed(struct ena_com_io_sq *io_sq,
+ struct ena_com_tx_ctx *ena_tx_ctx)
+{
+ struct ena_com_llq_info *llq_info;
+ int descs_after_first_entry;
+ int num_entries_needed = 1;
+ u16 num_descs;
+
+ if (!is_llq_max_tx_burst_exists(io_sq))
+ return false;
+
+ llq_info = &io_sq->llq_info;
+ num_descs = ena_tx_ctx->num_bufs;
+
+ if (unlikely(ena_com_meta_desc_changed(io_sq, ena_tx_ctx)))
+ ++num_descs;
+
+ if (num_descs > llq_info->descs_num_before_header) {
+ descs_after_first_entry = num_descs - llq_info->descs_num_before_header;
+ num_entries_needed += DIV_ROUND_UP(descs_after_first_entry,
+ llq_info->descs_per_entry);
+ }
+
+ pr_debug("queue: %d num_descs: %d num_entries_needed: %d\n", io_sq->qid,
+ num_descs, num_entries_needed);
+
+ return num_entries_needed > io_sq->entries_in_tx_burst_left;
+}
+
static inline int ena_com_write_sq_doorbell(struct ena_com_io_sq *io_sq)
{
+ u16 max_entries_in_tx_burst = io_sq->llq_info.max_entries_in_tx_burst;
u16 tail = io_sq->tail;
pr_debug("write submission queue doorbell for queue: %d tail: %d\n",
@@ -134,6 +181,12 @@ static inline int ena_com_write_sq_doorbell(struct ena_com_io_sq *io_sq)
writel(tail, io_sq->db_addr);
+ if (is_llq_max_tx_burst_exists(io_sq)) {
+ pr_debug("reset available entries in tx burst for queue %d to %d\n",
+ io_sq->qid, max_entries_in_tx_burst);
+ io_sq->entries_in_tx_burst_left = max_entries_in_tx_burst;
+ }
+
return 0;
}
@@ -142,15 +195,17 @@ static inline int ena_com_update_dev_comp_head(struct ena_com_io_cq *io_cq)
u16 unreported_comp, head;
bool need_update;
- head = io_cq->head;
- unreported_comp = head - io_cq->last_head_update;
- need_update = unreported_comp > (io_cq->q_depth / ENA_COMP_HEAD_THRESH);
-
- if (io_cq->cq_head_db_reg && need_update) {
- pr_debug("Write completion queue doorbell for queue %d: head: %d\n",
- io_cq->qid, head);
- writel(head, io_cq->cq_head_db_reg);
- io_cq->last_head_update = head;
+ if (unlikely(io_cq->cq_head_db_reg)) {
+ head = io_cq->head;
+ unreported_comp = head - io_cq->last_head_update;
+ need_update = unreported_comp > (io_cq->q_depth / ENA_COMP_HEAD_THRESH);
+
+ if (unlikely(need_update)) {
+ pr_debug("Write completion queue doorbell for queue %d: head: %d\n",
+ io_cq->qid, head);
+ writel(head, io_cq->cq_head_db_reg);
+ io_cq->last_head_update = head;
+ }
}
return 0;
diff --git a/drivers/net/ethernet/amazon/ena/ena_ethtool.c b/drivers/net/ethernet/amazon/ena/ena_ethtool.c
index fe596bc30a96..b997c3ce9e2b 100644
--- a/drivers/net/ethernet/amazon/ena/ena_ethtool.c
+++ b/drivers/net/ethernet/amazon/ena/ena_ethtool.c
@@ -88,13 +88,14 @@ static const struct ena_stats ena_stats_tx_strings[] = {
static const struct ena_stats ena_stats_rx_strings[] = {
ENA_STAT_RX_ENTRY(cnt),
ENA_STAT_RX_ENTRY(bytes),
+ ENA_STAT_RX_ENTRY(rx_copybreak_pkt),
+ ENA_STAT_RX_ENTRY(csum_good),
ENA_STAT_RX_ENTRY(refil_partial),
ENA_STAT_RX_ENTRY(bad_csum),
ENA_STAT_RX_ENTRY(page_alloc_fail),
ENA_STAT_RX_ENTRY(skb_alloc_fail),
ENA_STAT_RX_ENTRY(dma_mapping_err),
ENA_STAT_RX_ENTRY(bad_desc_num),
- ENA_STAT_RX_ENTRY(rx_copybreak_pkt),
ENA_STAT_RX_ENTRY(bad_req_id),
ENA_STAT_RX_ENTRY(empty_rx_ring),
ENA_STAT_RX_ENTRY(csum_unchecked),
@@ -447,13 +448,32 @@ static void ena_get_ringparam(struct net_device *netdev,
struct ethtool_ringparam *ring)
{
struct ena_adapter *adapter = netdev_priv(netdev);
- struct ena_ring *tx_ring = &adapter->tx_ring[0];
- struct ena_ring *rx_ring = &adapter->rx_ring[0];
- ring->rx_max_pending = rx_ring->ring_size;
- ring->tx_max_pending = tx_ring->ring_size;
- ring->rx_pending = rx_ring->ring_size;
- ring->tx_pending = tx_ring->ring_size;
+ ring->tx_max_pending = adapter->max_tx_ring_size;
+ ring->rx_max_pending = adapter->max_rx_ring_size;
+ ring->tx_pending = adapter->tx_ring[0].ring_size;
+ ring->rx_pending = adapter->rx_ring[0].ring_size;
+}
+
+static int ena_set_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct ena_adapter *adapter = netdev_priv(netdev);
+ u32 new_tx_size, new_rx_size;
+
+ new_tx_size = ring->tx_pending < ENA_MIN_RING_SIZE ?
+ ENA_MIN_RING_SIZE : ring->tx_pending;
+ new_tx_size = rounddown_pow_of_two(new_tx_size);
+
+ new_rx_size = ring->rx_pending < ENA_MIN_RING_SIZE ?
+ ENA_MIN_RING_SIZE : ring->rx_pending;
+ new_rx_size = rounddown_pow_of_two(new_rx_size);
+
+ if (new_tx_size == adapter->requested_tx_ring_size &&
+ new_rx_size == adapter->requested_rx_ring_size)
+ return 0;
+
+ return ena_update_queue_sizes(adapter, new_tx_size, new_rx_size);
}
static u32 ena_flow_hash_to_flow_type(u16 hash_fields)
@@ -807,6 +827,7 @@ static const struct ethtool_ops ena_ethtool_ops = {
.get_coalesce = ena_get_coalesce,
.set_coalesce = ena_set_coalesce,
.get_ringparam = ena_get_ringparam,
+ .set_ringparam = ena_set_ringparam,
.get_sset_count = ena_get_sset_count,
.get_strings = ena_get_strings,
.get_ethtool_stats = ena_get_ethtool_stats,
diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c
index 9c83642922c7..664e3ed97ea9 100644
--- a/drivers/net/ethernet/amazon/ena/ena_netdev.c
+++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c
@@ -182,7 +182,7 @@ static void ena_init_io_rings(struct ena_adapter *adapter)
ena_init_io_rings_common(adapter, rxr, i);
/* TX specific ring state */
- txr->ring_size = adapter->tx_ring_size;
+ txr->ring_size = adapter->requested_tx_ring_size;
txr->tx_max_header_size = ena_dev->tx_max_header_size;
txr->tx_mem_queue_type = ena_dev->tx_mem_queue_type;
txr->sgl_size = adapter->max_tx_sgl_size;
@@ -190,7 +190,7 @@ static void ena_init_io_rings(struct ena_adapter *adapter)
ena_com_get_nonadaptive_moderation_interval_tx(ena_dev);
/* RX specific ring state */
- rxr->ring_size = adapter->rx_ring_size;
+ rxr->ring_size = adapter->requested_rx_ring_size;
rxr->rx_copybreak = adapter->rx_copybreak;
rxr->sgl_size = adapter->max_rx_sgl_size;
rxr->smoothed_interval =
@@ -228,11 +228,11 @@ static int ena_setup_tx_resources(struct ena_adapter *adapter, int qid)
}
size = sizeof(u16) * tx_ring->ring_size;
- tx_ring->free_tx_ids = vzalloc_node(size, node);
- if (!tx_ring->free_tx_ids) {
- tx_ring->free_tx_ids = vzalloc(size);
- if (!tx_ring->free_tx_ids)
- goto err_free_tx_ids;
+ tx_ring->free_ids = vzalloc_node(size, node);
+ if (!tx_ring->free_ids) {
+ tx_ring->free_ids = vzalloc(size);
+ if (!tx_ring->free_ids)
+ goto err_tx_free_ids;
}
size = tx_ring->tx_max_header_size;
@@ -245,7 +245,7 @@ static int ena_setup_tx_resources(struct ena_adapter *adapter, int qid)
/* Req id ring for TX out of order completions */
for (i = 0; i < tx_ring->ring_size; i++)
- tx_ring->free_tx_ids[i] = i;
+ tx_ring->free_ids[i] = i;
/* Reset tx statistics */
memset(&tx_ring->tx_stats, 0x0, sizeof(tx_ring->tx_stats));
@@ -256,9 +256,9 @@ static int ena_setup_tx_resources(struct ena_adapter *adapter, int qid)
return 0;
err_push_buf_intermediate_buf:
- vfree(tx_ring->free_tx_ids);
- tx_ring->free_tx_ids = NULL;
-err_free_tx_ids:
+ vfree(tx_ring->free_ids);
+ tx_ring->free_ids = NULL;
+err_tx_free_ids:
vfree(tx_ring->tx_buffer_info);
tx_ring->tx_buffer_info = NULL;
err_tx_buffer_info:
@@ -278,8 +278,8 @@ static void ena_free_tx_resources(struct ena_adapter *adapter, int qid)
vfree(tx_ring->tx_buffer_info);
tx_ring->tx_buffer_info = NULL;
- vfree(tx_ring->free_tx_ids);
- tx_ring->free_tx_ids = NULL;
+ vfree(tx_ring->free_ids);
+ tx_ring->free_ids = NULL;
vfree(tx_ring->push_buf_intermediate_buf);
tx_ring->push_buf_intermediate_buf = NULL;
@@ -326,7 +326,7 @@ static void ena_free_all_io_tx_resources(struct ena_adapter *adapter)
ena_free_tx_resources(adapter, i);
}
-static inline int validate_rx_req_id(struct ena_ring *rx_ring, u16 req_id)
+static int validate_rx_req_id(struct ena_ring *rx_ring, u16 req_id)
{
if (likely(req_id < rx_ring->ring_size))
return 0;
@@ -377,10 +377,10 @@ static int ena_setup_rx_resources(struct ena_adapter *adapter,
}
size = sizeof(u16) * rx_ring->ring_size;
- rx_ring->free_rx_ids = vzalloc_node(size, node);
- if (!rx_ring->free_rx_ids) {
- rx_ring->free_rx_ids = vzalloc(size);
- if (!rx_ring->free_rx_ids) {
+ rx_ring->free_ids = vzalloc_node(size, node);
+ if (!rx_ring->free_ids) {
+ rx_ring->free_ids = vzalloc(size);
+ if (!rx_ring->free_ids) {
vfree(rx_ring->rx_buffer_info);
rx_ring->rx_buffer_info = NULL;
return -ENOMEM;
@@ -389,7 +389,7 @@ static int ena_setup_rx_resources(struct ena_adapter *adapter,
/* Req id ring for receiving RX pkts out of order */
for (i = 0; i < rx_ring->ring_size; i++)
- rx_ring->free_rx_ids[i] = i;
+ rx_ring->free_ids[i] = i;
/* Reset rx statistics */
memset(&rx_ring->rx_stats, 0x0, sizeof(rx_ring->rx_stats));
@@ -415,8 +415,8 @@ static void ena_free_rx_resources(struct ena_adapter *adapter,
vfree(rx_ring->rx_buffer_info);
rx_ring->rx_buffer_info = NULL;
- vfree(rx_ring->free_rx_ids);
- rx_ring->free_rx_ids = NULL;
+ vfree(rx_ring->free_ids);
+ rx_ring->free_ids = NULL;
}
/* ena_setup_all_rx_resources - allocate I/O Rx queues resources for all queues
@@ -460,7 +460,7 @@ static void ena_free_all_io_rx_resources(struct ena_adapter *adapter)
ena_free_rx_resources(adapter, i);
}
-static inline int ena_alloc_rx_page(struct ena_ring *rx_ring,
+static int ena_alloc_rx_page(struct ena_ring *rx_ring,
struct ena_rx_buffer *rx_info, gfp_t gfp)
{
struct ena_com_buf *ena_buf;
@@ -531,7 +531,7 @@ static int ena_refill_rx_bufs(struct ena_ring *rx_ring, u32 num)
for (i = 0; i < num; i++) {
struct ena_rx_buffer *rx_info;
- req_id = rx_ring->free_rx_ids[next_to_use];
+ req_id = rx_ring->free_ids[next_to_use];
rc = validate_rx_req_id(rx_ring, req_id);
if (unlikely(rc < 0))
break;
@@ -594,7 +594,6 @@ static void ena_free_rx_bufs(struct ena_adapter *adapter,
/* ena_refill_all_rx_bufs - allocate all queues Rx buffers
* @adapter: board private structure
- *
*/
static void ena_refill_all_rx_bufs(struct ena_adapter *adapter)
{
@@ -621,7 +620,7 @@ static void ena_free_all_rx_bufs(struct ena_adapter *adapter)
ena_free_rx_bufs(adapter, i);
}
-static inline void ena_unmap_tx_skb(struct ena_ring *tx_ring,
+static void ena_unmap_tx_skb(struct ena_ring *tx_ring,
struct ena_tx_buffer *tx_info)
{
struct ena_com_buf *ena_buf;
@@ -797,7 +796,7 @@ static int ena_clean_tx_irq(struct ena_ring *tx_ring, u32 budget)
tx_pkts++;
total_done += tx_info->tx_descs;
- tx_ring->free_tx_ids[next_to_clean] = req_id;
+ tx_ring->free_ids[next_to_clean] = req_id;
next_to_clean = ENA_TX_RING_IDX_NEXT(next_to_clean,
tx_ring->ring_size);
}
@@ -911,7 +910,7 @@ static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring,
skb_put(skb, len);
skb->protocol = eth_type_trans(skb, rx_ring->netdev);
- rx_ring->free_rx_ids[*next_to_clean] = req_id;
+ rx_ring->free_ids[*next_to_clean] = req_id;
*next_to_clean = ENA_RX_RING_IDX_ADD(*next_to_clean, descs,
rx_ring->ring_size);
return skb;
@@ -935,7 +934,7 @@ static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring,
rx_info->page = NULL;
- rx_ring->free_rx_ids[*next_to_clean] = req_id;
+ rx_ring->free_ids[*next_to_clean] = req_id;
*next_to_clean =
ENA_RX_RING_IDX_NEXT(*next_to_clean,
rx_ring->ring_size);
@@ -956,7 +955,7 @@ static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring,
* @ena_rx_ctx: received packet context/metadata
* @skb: skb currently being received and modified
*/
-static inline void ena_rx_checksum(struct ena_ring *rx_ring,
+static void ena_rx_checksum(struct ena_ring *rx_ring,
struct ena_com_rx_ctx *ena_rx_ctx,
struct sk_buff *skb)
{
@@ -1001,6 +1000,9 @@ static inline void ena_rx_checksum(struct ena_ring *rx_ring,
if (likely(ena_rx_ctx->l4_csum_checked)) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
+ u64_stats_update_begin(&rx_ring->syncp);
+ rx_ring->rx_stats.csum_good++;
+ u64_stats_update_end(&rx_ring->syncp);
} else {
u64_stats_update_begin(&rx_ring->syncp);
rx_ring->rx_stats.csum_unchecked++;
@@ -1088,7 +1090,7 @@ static int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi,
/* exit if we failed to retrieve a buffer */
if (unlikely(!skb)) {
for (i = 0; i < ena_rx_ctx.descs; i++) {
- rx_ring->free_tx_ids[next_to_clean] =
+ rx_ring->free_ids[next_to_clean] =
rx_ring->ena_bufs[i].req_id;
next_to_clean =
ENA_RX_RING_IDX_NEXT(next_to_clean,
@@ -1153,7 +1155,7 @@ error:
return 0;
}
-inline void ena_adjust_intr_moderation(struct ena_ring *rx_ring,
+void ena_adjust_intr_moderation(struct ena_ring *rx_ring,
struct ena_ring *tx_ring)
{
/* We apply adaptive moderation on Rx path only.
@@ -1172,7 +1174,7 @@ inline void ena_adjust_intr_moderation(struct ena_ring *rx_ring,
rx_ring->per_napi_bytes = 0;
}
-static inline void ena_unmask_interrupt(struct ena_ring *tx_ring,
+static void ena_unmask_interrupt(struct ena_ring *tx_ring,
struct ena_ring *rx_ring)
{
struct ena_eth_io_intr_reg intr_reg;
@@ -1192,7 +1194,7 @@ static inline void ena_unmask_interrupt(struct ena_ring *tx_ring,
ena_com_unmask_intr(rx_ring->ena_com_io_cq, &intr_reg);
}
-static inline void ena_update_ring_numa_node(struct ena_ring *tx_ring,
+static void ena_update_ring_numa_node(struct ena_ring *tx_ring,
struct ena_ring *rx_ring)
{
int cpu = get_cpu();
@@ -1635,7 +1637,7 @@ static int ena_create_io_tx_queue(struct ena_adapter *adapter, int qid)
ctx.qid = ena_qid;
ctx.mem_queue_type = ena_dev->tx_mem_queue_type;
ctx.msix_vector = msix_vector;
- ctx.queue_size = adapter->tx_ring_size;
+ ctx.queue_size = tx_ring->ring_size;
ctx.numa_node = cpu_to_node(tx_ring->cpu);
rc = ena_com_create_io_queue(ena_dev, &ctx);
@@ -1702,7 +1704,7 @@ static int ena_create_io_rx_queue(struct ena_adapter *adapter, int qid)
ctx.direction = ENA_COM_IO_QUEUE_DIRECTION_RX;
ctx.mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
ctx.msix_vector = msix_vector;
- ctx.queue_size = adapter->rx_ring_size;
+ ctx.queue_size = rx_ring->ring_size;
ctx.numa_node = cpu_to_node(rx_ring->cpu);
rc = ena_com_create_io_queue(ena_dev, &ctx);
@@ -1749,6 +1751,112 @@ create_err:
return rc;
}
+static void set_io_rings_size(struct ena_adapter *adapter,
+ int new_tx_size, int new_rx_size)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_queues; i++) {
+ adapter->tx_ring[i].ring_size = new_tx_size;
+ adapter->rx_ring[i].ring_size = new_rx_size;
+ }
+}
+
+/* This function allows queue allocation to backoff when the system is
+ * low on memory. If there is not enough memory to allocate io queues
+ * the driver will try to allocate smaller queues.
+ *
+ * The backoff algorithm is as follows:
+ * 1. Try to allocate TX and RX and if successful.
+ * 1.1. return success
+ *
+ * 2. Divide by 2 the size of the larger of RX and TX queues (or both if their size is the same).
+ *
+ * 3. If TX or RX is smaller than 256
+ * 3.1. return failure.
+ * 4. else
+ * 4.1. go back to 1.
+ */
+static int create_queues_with_size_backoff(struct ena_adapter *adapter)
+{
+ int rc, cur_rx_ring_size, cur_tx_ring_size;
+ int new_rx_ring_size, new_tx_ring_size;
+
+ /* current queue sizes might be set to smaller than the requested
+ * ones due to past queue allocation failures.
+ */
+ set_io_rings_size(adapter, adapter->requested_tx_ring_size,
+ adapter->requested_rx_ring_size);
+
+ while (1) {
+ rc = ena_setup_all_tx_resources(adapter);
+ if (rc)
+ goto err_setup_tx;
+
+ rc = ena_create_all_io_tx_queues(adapter);
+ if (rc)
+ goto err_create_tx_queues;
+
+ rc = ena_setup_all_rx_resources(adapter);
+ if (rc)
+ goto err_setup_rx;
+
+ rc = ena_create_all_io_rx_queues(adapter);
+ if (rc)
+ goto err_create_rx_queues;
+
+ return 0;
+
+err_create_rx_queues:
+ ena_free_all_io_rx_resources(adapter);
+err_setup_rx:
+ ena_destroy_all_tx_queues(adapter);
+err_create_tx_queues:
+ ena_free_all_io_tx_resources(adapter);
+err_setup_tx:
+ if (rc != -ENOMEM) {
+ netif_err(adapter, ifup, adapter->netdev,
+ "Queue creation failed with error code %d\n",
+ rc);
+ return rc;
+ }
+
+ cur_tx_ring_size = adapter->tx_ring[0].ring_size;
+ cur_rx_ring_size = adapter->rx_ring[0].ring_size;
+
+ netif_err(adapter, ifup, adapter->netdev,
+ "Not enough memory to create queues with sizes TX=%d, RX=%d\n",
+ cur_tx_ring_size, cur_rx_ring_size);
+
+ new_tx_ring_size = cur_tx_ring_size;
+ new_rx_ring_size = cur_rx_ring_size;
+
+ /* Decrease the size of the larger queue, or
+ * decrease both if they are the same size.
+ */
+ if (cur_rx_ring_size <= cur_tx_ring_size)
+ new_tx_ring_size = cur_tx_ring_size / 2;
+ if (cur_rx_ring_size >= cur_tx_ring_size)
+ new_rx_ring_size = cur_rx_ring_size / 2;
+
+ if (new_tx_ring_size < ENA_MIN_RING_SIZE ||
+ new_rx_ring_size < ENA_MIN_RING_SIZE) {
+ netif_err(adapter, ifup, adapter->netdev,
+ "Queue creation failed with the smallest possible queue size of %d for both queues. Not retrying with smaller queues\n",
+ ENA_MIN_RING_SIZE);
+ return rc;
+ }
+
+ netif_err(adapter, ifup, adapter->netdev,
+ "Retrying queue creation with sizes TX=%d, RX=%d\n",
+ new_tx_ring_size,
+ new_rx_ring_size);
+
+ set_io_rings_size(adapter, new_tx_ring_size,
+ new_rx_ring_size);
+ }
+}
+
static int ena_up(struct ena_adapter *adapter)
{
int rc, i;
@@ -1768,25 +1876,9 @@ static int ena_up(struct ena_adapter *adapter)
if (rc)
goto err_req_irq;
- /* allocate transmit descriptors */
- rc = ena_setup_all_tx_resources(adapter);
+ rc = create_queues_with_size_backoff(adapter);
if (rc)
- goto err_setup_tx;
-
- /* allocate receive descriptors */
- rc = ena_setup_all_rx_resources(adapter);
- if (rc)
- goto err_setup_rx;
-
- /* Create TX queues */
- rc = ena_create_all_io_tx_queues(adapter);
- if (rc)
- goto err_create_tx_queues;
-
- /* Create RX queues */
- rc = ena_create_all_io_rx_queues(adapter);
- if (rc)
- goto err_create_rx_queues;
+ goto err_create_queues_with_backoff;
rc = ena_up_complete(adapter);
if (rc)
@@ -1815,14 +1907,11 @@ static int ena_up(struct ena_adapter *adapter)
return rc;
err_up:
- ena_destroy_all_rx_queues(adapter);
-err_create_rx_queues:
ena_destroy_all_tx_queues(adapter);
-err_create_tx_queues:
- ena_free_all_io_rx_resources(adapter);
-err_setup_rx:
ena_free_all_io_tx_resources(adapter);
-err_setup_tx:
+ ena_destroy_all_rx_queues(adapter);
+ ena_free_all_io_rx_resources(adapter);
+err_create_queues_with_backoff:
ena_free_io_irq(adapter);
err_req_irq:
ena_del_napi(adapter);
@@ -1942,6 +2031,20 @@ static int ena_close(struct net_device *netdev)
return 0;
}
+int ena_update_queue_sizes(struct ena_adapter *adapter,
+ u32 new_tx_size,
+ u32 new_rx_size)
+{
+ bool dev_up;
+
+ dev_up = test_bit(ENA_FLAG_DEV_UP, &adapter->flags);
+ ena_close(adapter->netdev);
+ adapter->requested_tx_ring_size = new_tx_size;
+ adapter->requested_rx_ring_size = new_rx_size;
+ ena_init_io_rings(adapter);
+ return dev_up ? ena_up(adapter) : 0;
+}
+
static void ena_tx_csum(struct ena_com_tx_ctx *ena_tx_ctx, struct sk_buff *skb)
{
u32 mss = skb_shinfo(skb)->gso_size;
@@ -2152,7 +2255,7 @@ static netdev_tx_t ena_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb_tx_timestamp(skb);
next_to_use = tx_ring->next_to_use;
- req_id = tx_ring->free_tx_ids[next_to_use];
+ req_id = tx_ring->free_ids[next_to_use];
tx_info = &tx_ring->tx_buffer_info[req_id];
tx_info->num_of_bufs = 0;
@@ -2172,6 +2275,13 @@ static netdev_tx_t ena_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* set flags and meta data */
ena_tx_csum(&ena_tx_ctx, skb);
+ if (unlikely(ena_com_is_doorbell_needed(tx_ring->ena_com_io_sq, &ena_tx_ctx))) {
+ netif_dbg(adapter, tx_queued, dev,
+ "llq tx max burst size of queue %d achieved, writing doorbell to send burst\n",
+ qid);
+ ena_com_write_sq_doorbell(tx_ring->ena_com_io_sq);
+ }
+
/* prepare the packet's descriptors to dma engine */
rc = ena_com_prepare_tx(tx_ring->ena_com_io_sq, &ena_tx_ctx,
&nb_hw_desc);
@@ -2447,13 +2557,6 @@ static int ena_device_validate_params(struct ena_adapter *adapter,
return -EINVAL;
}
- if ((get_feat_ctx->max_queues.max_cq_num < adapter->num_queues) ||
- (get_feat_ctx->max_queues.max_sq_num < adapter->num_queues)) {
- netif_err(adapter, drv, netdev,
- "Error, device doesn't support enough queues\n");
- return -EINVAL;
- }
-
if (get_feat_ctx->dev_attr.max_mtu < netdev->mtu) {
netif_err(adapter, drv, netdev,
"Error, device max mtu is smaller than netdev MTU\n");
@@ -3027,18 +3130,32 @@ static int ena_calc_io_queue_num(struct pci_dev *pdev,
struct ena_com_dev *ena_dev,
struct ena_com_dev_get_features_ctx *get_feat_ctx)
{
- int io_sq_num, io_queue_num;
+ int io_tx_sq_num, io_tx_cq_num, io_rx_num, io_queue_num;
- /* In case of LLQ use the llq number in the get feature cmd */
+ if (ena_dev->supported_features & BIT(ENA_ADMIN_MAX_QUEUES_EXT)) {
+ struct ena_admin_queue_ext_feature_fields *max_queue_ext =
+ &get_feat_ctx->max_queue_ext.max_queue_ext;
+ io_rx_num = min_t(int, max_queue_ext->max_rx_sq_num,
+ max_queue_ext->max_rx_cq_num);
+
+ io_tx_sq_num = max_queue_ext->max_tx_sq_num;
+ io_tx_cq_num = max_queue_ext->max_tx_cq_num;
+ } else {
+ struct ena_admin_queue_feature_desc *max_queues =
+ &get_feat_ctx->max_queues;
+ io_tx_sq_num = max_queues->max_sq_num;
+ io_tx_cq_num = max_queues->max_cq_num;
+ io_rx_num = min_t(int, io_tx_sq_num, io_tx_cq_num);
+ }
+
+ /* In case of LLQ use the llq fields for the tx SQ/CQ */
if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV)
- io_sq_num = get_feat_ctx->llq.max_llq_num;
- else
- io_sq_num = get_feat_ctx->max_queues.max_sq_num;
+ io_tx_sq_num = get_feat_ctx->llq.max_llq_num;
io_queue_num = min_t(int, num_online_cpus(), ENA_MAX_NUM_IO_QUEUES);
- io_queue_num = min_t(int, io_queue_num, io_sq_num);
- io_queue_num = min_t(int, io_queue_num,
- get_feat_ctx->max_queues.max_cq_num);
+ io_queue_num = min_t(int, io_queue_num, io_rx_num);
+ io_queue_num = min_t(int, io_queue_num, io_tx_sq_num);
+ io_queue_num = min_t(int, io_queue_num, io_tx_cq_num);
/* 1 IRQ for for mgmnt and 1 IRQs for each IO direction */
io_queue_num = min_t(int, io_queue_num, pci_msix_vec_count(pdev) - 1);
if (unlikely(!io_queue_num)) {
@@ -3212,7 +3329,7 @@ static void ena_release_bars(struct ena_com_dev *ena_dev, struct pci_dev *pdev)
pci_release_selected_regions(pdev, release_bars);
}
-static inline void set_default_llq_configurations(struct ena_llq_configurations *llq_config)
+static void set_default_llq_configurations(struct ena_llq_configurations *llq_config)
{
llq_config->llq_header_location = ENA_ADMIN_INLINE_HEADER;
llq_config->llq_ring_entry_size = ENA_ADMIN_LIST_ENTRY_SIZE_128B;
@@ -3221,36 +3338,70 @@ static inline void set_default_llq_configurations(struct ena_llq_configurations
llq_config->llq_ring_entry_size_value = 128;
}
-static int ena_calc_queue_size(struct pci_dev *pdev,
- struct ena_com_dev *ena_dev,
- u16 *max_tx_sgl_size,
- u16 *max_rx_sgl_size,
- struct ena_com_dev_get_features_ctx *get_feat_ctx)
+static int ena_calc_queue_size(struct ena_calc_queue_size_ctx *ctx)
{
- u32 queue_size = ENA_DEFAULT_RING_SIZE;
+ struct ena_admin_feature_llq_desc *llq = &ctx->get_feat_ctx->llq;
+ struct ena_com_dev *ena_dev = ctx->ena_dev;
+ u32 tx_queue_size = ENA_DEFAULT_RING_SIZE;
+ u32 rx_queue_size = ENA_DEFAULT_RING_SIZE;
+ u32 max_tx_queue_size;
+ u32 max_rx_queue_size;
- queue_size = min_t(u32, queue_size,
- get_feat_ctx->max_queues.max_cq_depth);
- queue_size = min_t(u32, queue_size,
- get_feat_ctx->max_queues.max_sq_depth);
+ if (ctx->ena_dev->supported_features & BIT(ENA_ADMIN_MAX_QUEUES_EXT)) {
+ struct ena_admin_queue_ext_feature_fields *max_queue_ext =
+ &ctx->get_feat_ctx->max_queue_ext.max_queue_ext;
+ max_rx_queue_size = min_t(u32, max_queue_ext->max_rx_cq_depth,
+ max_queue_ext->max_rx_sq_depth);
+ max_tx_queue_size = max_queue_ext->max_tx_cq_depth;
- if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV)
- queue_size = min_t(u32, queue_size,
- get_feat_ctx->llq.max_llq_depth);
+ if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV)
+ max_tx_queue_size = min_t(u32, max_tx_queue_size,
+ llq->max_llq_depth);
+ else
+ max_tx_queue_size = min_t(u32, max_tx_queue_size,
+ max_queue_ext->max_tx_sq_depth);
- queue_size = rounddown_pow_of_two(queue_size);
+ ctx->max_tx_sgl_size = min_t(u16, ENA_PKT_MAX_BUFS,
+ max_queue_ext->max_per_packet_tx_descs);
+ ctx->max_rx_sgl_size = min_t(u16, ENA_PKT_MAX_BUFS,
+ max_queue_ext->max_per_packet_rx_descs);
+ } else {
+ struct ena_admin_queue_feature_desc *max_queues =
+ &ctx->get_feat_ctx->max_queues;
+ max_rx_queue_size = min_t(u32, max_queues->max_cq_depth,
+ max_queues->max_sq_depth);
+ max_tx_queue_size = max_queues->max_cq_depth;
+
+ if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV)
+ max_tx_queue_size = min_t(u32, max_tx_queue_size,
+ llq->max_llq_depth);
+ else
+ max_tx_queue_size = min_t(u32, max_tx_queue_size,
+ max_queues->max_sq_depth);
- if (unlikely(!queue_size)) {
- dev_err(&pdev->dev, "Invalid queue size\n");
- return -EFAULT;
+ ctx->max_tx_sgl_size = min_t(u16, ENA_PKT_MAX_BUFS,
+ max_queues->max_packet_tx_descs);
+ ctx->max_rx_sgl_size = min_t(u16, ENA_PKT_MAX_BUFS,
+ max_queues->max_packet_rx_descs);
}
- *max_tx_sgl_size = min_t(u16, ENA_PKT_MAX_BUFS,
- get_feat_ctx->max_queues.max_packet_tx_descs);
- *max_rx_sgl_size = min_t(u16, ENA_PKT_MAX_BUFS,
- get_feat_ctx->max_queues.max_packet_rx_descs);
+ max_tx_queue_size = rounddown_pow_of_two(max_tx_queue_size);
+ max_rx_queue_size = rounddown_pow_of_two(max_rx_queue_size);
+
+ tx_queue_size = clamp_val(tx_queue_size, ENA_MIN_RING_SIZE,
+ max_tx_queue_size);
+ rx_queue_size = clamp_val(rx_queue_size, ENA_MIN_RING_SIZE,
+ max_rx_queue_size);
- return queue_size;
+ tx_queue_size = rounddown_pow_of_two(tx_queue_size);
+ rx_queue_size = rounddown_pow_of_two(rx_queue_size);
+
+ ctx->max_tx_queue_size = max_tx_queue_size;
+ ctx->max_rx_queue_size = max_rx_queue_size;
+ ctx->tx_queue_size = tx_queue_size;
+ ctx->rx_queue_size = rx_queue_size;
+
+ return 0;
}
/* ena_probe - Device Initialization Routine
@@ -3266,23 +3417,19 @@ static int ena_calc_queue_size(struct pci_dev *pdev,
static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct ena_com_dev_get_features_ctx get_feat_ctx;
- static int version_printed;
- struct net_device *netdev;
- struct ena_adapter *adapter;
+ struct ena_calc_queue_size_ctx calc_queue_ctx = { 0 };
struct ena_llq_configurations llq_config;
struct ena_com_dev *ena_dev = NULL;
- char *queue_type_str;
- static int adapters_found;
+ struct ena_adapter *adapter;
int io_queue_num, bars, rc;
- int queue_size;
- u16 tx_sgl_size = 0;
- u16 rx_sgl_size = 0;
+ struct net_device *netdev;
+ static int adapters_found;
+ char *queue_type_str;
bool wd_state;
dev_dbg(&pdev->dev, "%s\n", __func__);
- if (version_printed++ == 0)
- dev_info(&pdev->dev, "%s", version);
+ dev_info_once(&pdev->dev, "%s", version);
rc = pci_enable_device_mem(pdev);
if (rc) {
@@ -3334,20 +3481,25 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_device_destroy;
}
+ calc_queue_ctx.ena_dev = ena_dev;
+ calc_queue_ctx.get_feat_ctx = &get_feat_ctx;
+ calc_queue_ctx.pdev = pdev;
+
/* initial Tx interrupt delay, Assumes 1 usec granularity.
* Updated during device initialization with the real granularity
*/
ena_dev->intr_moder_tx_interval = ENA_INTR_INITIAL_TX_INTERVAL_USECS;
io_queue_num = ena_calc_io_queue_num(pdev, ena_dev, &get_feat_ctx);
- queue_size = ena_calc_queue_size(pdev, ena_dev, &tx_sgl_size,
- &rx_sgl_size, &get_feat_ctx);
- if ((queue_size <= 0) || (io_queue_num <= 0)) {
+ rc = ena_calc_queue_size(&calc_queue_ctx);
+ if (rc || io_queue_num <= 0) {
rc = -EFAULT;
goto err_device_destroy;
}
- dev_info(&pdev->dev, "creating %d io queues. queue size: %d. LLQ is %s\n",
- io_queue_num, queue_size,
+ dev_info(&pdev->dev, "creating %d io queues. rx queue size: %d tx queue size. %d LLQ is %s\n",
+ io_queue_num,
+ calc_queue_ctx.rx_queue_size,
+ calc_queue_ctx.tx_queue_size,
(ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) ?
"ENABLED" : "DISABLED");
@@ -3373,11 +3525,12 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE);
adapter->reset_reason = ENA_REGS_RESET_NORMAL;
- adapter->tx_ring_size = queue_size;
- adapter->rx_ring_size = queue_size;
-
- adapter->max_tx_sgl_size = tx_sgl_size;
- adapter->max_rx_sgl_size = rx_sgl_size;
+ adapter->requested_tx_ring_size = calc_queue_ctx.tx_queue_size;
+ adapter->requested_rx_ring_size = calc_queue_ctx.rx_queue_size;
+ adapter->max_tx_ring_size = calc_queue_ctx.max_tx_queue_size;
+ adapter->max_rx_ring_size = calc_queue_ctx.max_rx_queue_size;
+ adapter->max_tx_sgl_size = calc_queue_ctx.max_tx_sgl_size;
+ adapter->max_rx_sgl_size = calc_queue_ctx.max_rx_sgl_size;
adapter->num_queues = io_queue_num;
adapter->last_monitored_tx_qid = 0;
diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.h b/drivers/net/ethernet/amazon/ena/ena_netdev.h
index 63870072cbbd..efbcffd22215 100644
--- a/drivers/net/ethernet/amazon/ena/ena_netdev.h
+++ b/drivers/net/ethernet/amazon/ena/ena_netdev.h
@@ -44,8 +44,8 @@
#include "ena_eth_com.h"
#define DRV_MODULE_VER_MAJOR 2
-#define DRV_MODULE_VER_MINOR 0
-#define DRV_MODULE_VER_SUBMINOR 3
+#define DRV_MODULE_VER_MINOR 1
+#define DRV_MODULE_VER_SUBMINOR 0
#define DRV_MODULE_NAME "ena"
#ifndef DRV_MODULE_VERSION
@@ -79,6 +79,7 @@
#define ENA_BAR_MASK (BIT(ENA_REG_BAR) | BIT(ENA_MEM_BAR))
#define ENA_DEFAULT_RING_SIZE (1024)
+#define ENA_MIN_RING_SIZE (256)
#define ENA_TX_WAKEUP_THRESH (MAX_SKB_FRAGS + 2)
#define ENA_DEFAULT_RX_COPYBREAK (256 - NET_IP_ALIGN)
@@ -154,6 +155,18 @@ struct ena_napi {
u32 qid;
};
+struct ena_calc_queue_size_ctx {
+ struct ena_com_dev_get_features_ctx *get_feat_ctx;
+ struct ena_com_dev *ena_dev;
+ struct pci_dev *pdev;
+ u16 tx_queue_size;
+ u16 rx_queue_size;
+ u16 max_tx_queue_size;
+ u16 max_rx_queue_size;
+ u16 max_tx_sgl_size;
+ u16 max_rx_sgl_size;
+};
+
struct ena_tx_buffer {
struct sk_buff *skb;
/* num of ena desc for this specific skb
@@ -208,26 +221,24 @@ struct ena_stats_tx {
struct ena_stats_rx {
u64 cnt;
u64 bytes;
+ u64 rx_copybreak_pkt;
+ u64 csum_good;
u64 refil_partial;
u64 bad_csum;
u64 page_alloc_fail;
u64 skb_alloc_fail;
u64 dma_mapping_err;
u64 bad_desc_num;
- u64 rx_copybreak_pkt;
u64 bad_req_id;
u64 empty_rx_ring;
u64 csum_unchecked;
};
struct ena_ring {
- union {
- /* Holds the empty requests for TX/RX
- * out of order completions
- */
- u16 *free_tx_ids;
- u16 *free_rx_ids;
- };
+ /* Holds the empty requests for TX/RX
+ * out of order completions
+ */
+ u16 *free_ids;
union {
struct ena_tx_buffer *tx_buffer_info;
@@ -321,8 +332,11 @@ struct ena_adapter {
u32 tx_usecs, rx_usecs; /* interrupt moderation */
u32 tx_frames, rx_frames; /* interrupt moderation */
- u32 tx_ring_size;
- u32 rx_ring_size;
+ u32 requested_tx_ring_size;
+ u32 requested_rx_ring_size;
+
+ u32 max_tx_ring_size;
+ u32 max_rx_ring_size;
u32 msg_enable;
@@ -372,6 +386,10 @@ void ena_dump_stats_to_dmesg(struct ena_adapter *adapter);
void ena_dump_stats_to_buf(struct ena_adapter *adapter, u8 *buf);
+int ena_update_queue_sizes(struct ena_adapter *adapter,
+ u32 new_tx_size,
+ u32 new_rx_size);
+
int ena_get_sset_count(struct net_device *netdev, int sset);
#endif /* !(ENA_H) */
diff --git a/drivers/net/ethernet/amd/am79c961a.c b/drivers/net/ethernet/amd/am79c961a.c
index 265039c57023..0842da492a64 100644
--- a/drivers/net/ethernet/amd/am79c961a.c
+++ b/drivers/net/ethernet/amd/am79c961a.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/net/ethernet/amd/am79c961a.c
*
* by Russell King <rmk@arm.linux.org.uk> 1995-2001.
*
- * 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.
- *
* Derived from various things including skeleton.c
*
* This is a special driver for the am79c961A Lance chip used in the
diff --git a/drivers/net/ethernet/amd/am79c961a.h b/drivers/net/ethernet/amd/am79c961a.h
index fc5088c70731..73679e053ceb 100644
--- a/drivers/net/ethernet/amd/am79c961a.h
+++ b/drivers/net/ethernet/amd/am79c961a.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/drivers/net/ethernet/amd/am79c961a.h
- *
- * 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.
*/
#ifndef _LINUX_am79c961a_H
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h b/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h
index 173be45463ee..02f1b70c4e25 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h
@@ -9,6 +9,8 @@
#ifndef AQ_CFG_H
#define AQ_CFG_H
+#include <generated/utsrelease.h>
+
#define AQ_CFG_VECS_DEF 8U
#define AQ_CFG_TCS_DEF 1U
@@ -86,10 +88,7 @@
#define AQ_CFG_DRV_AUTHOR "aQuantia"
#define AQ_CFG_DRV_DESC "aQuantia Corporation(R) Network Driver"
#define AQ_CFG_DRV_NAME "atlantic"
-#define AQ_CFG_DRV_VERSION __stringify(NIC_MAJOR_DRIVER_VERSION)"."\
- __stringify(NIC_MINOR_DRIVER_VERSION)"."\
- __stringify(NIC_BUILD_DRIVER_VERSION)"."\
- __stringify(NIC_REVISION_DRIVER_VERSION) \
+#define AQ_CFG_DRV_VERSION UTS_RELEASE \
AQ_CFG_DRV_VERSION_SUFFIX
#endif /* AQ_CFG_H */
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_drvinfo.c b/drivers/net/ethernet/aquantia/atlantic/aq_drvinfo.c
index adad6a7acabe..6da65099047d 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_drvinfo.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_drvinfo.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2014-2019 aQuantia Corporation. */
/* File aq_drvinfo.c: Definition of common code for firmware info in sys.*/
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_drvinfo.h b/drivers/net/ethernet/aquantia/atlantic/aq_drvinfo.h
index 41fbb1358068..23a0487893a7 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_drvinfo.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_drvinfo.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (C) 2014-2017 aQuantia Corporation. */
/* File aq_drvinfo.h: Declaration of common code for firmware info in sys.*/
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_filters.c b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
index 18bc035da850..440690b18734 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2014-2017 aQuantia Corporation. */
/* File aq_filters.c: RX filters related functions. */
@@ -843,9 +843,14 @@ int aq_filters_vlans_update(struct aq_nic_s *aq_nic)
return err;
if (aq_nic->ndev->features & NETIF_F_HW_VLAN_CTAG_FILTER) {
- if (hweight < AQ_VLAN_MAX_FILTERS)
- err = aq_hw_ops->hw_filter_vlan_ctrl(aq_hw, true);
+ if (hweight < AQ_VLAN_MAX_FILTERS && hweight > 0) {
+ err = aq_hw_ops->hw_filter_vlan_ctrl(aq_hw,
+ !(aq_nic->packet_filter & IFF_PROMISC));
+ aq_nic->aq_nic_cfg.is_vlan_force_promisc = false;
+ } else {
/* otherwise left in promiscue mode */
+ aq_nic->aq_nic_cfg.is_vlan_force_promisc = true;
+ }
}
return err;
@@ -866,6 +871,7 @@ int aq_filters_vlan_offload_off(struct aq_nic_s *aq_nic)
if (unlikely(!aq_hw_ops->hw_filter_vlan_ctrl))
return -EOPNOTSUPP;
+ aq_nic->aq_nic_cfg.is_vlan_force_promisc = true;
err = aq_hw_ops->hw_filter_vlan_ctrl(aq_hw, false);
if (err)
return err;
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_filters.h b/drivers/net/ethernet/aquantia/atlantic/aq_filters.h
index c6a08c6585d5..122e06c88a33 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_filters.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_filters.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (C) 2014-2017 aQuantia Corporation. */
/* File aq_filters.h: RX filters related functions. */
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_main.c b/drivers/net/ethernet/aquantia/atlantic/aq_main.c
index 5315df5ff6f8..100722ad5c2d 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_main.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_main.c
@@ -108,11 +108,16 @@ err_exit:
static int aq_ndev_set_features(struct net_device *ndev,
netdev_features_t features)
{
+ bool is_vlan_rx_strip = !!(features & NETIF_F_HW_VLAN_CTAG_RX);
+ bool is_vlan_tx_insert = !!(features & NETIF_F_HW_VLAN_CTAG_TX);
struct aq_nic_s *aq_nic = netdev_priv(ndev);
- struct aq_nic_cfg_s *aq_cfg = aq_nic_get_cfg(aq_nic);
+ bool need_ndev_restart = false;
+ struct aq_nic_cfg_s *aq_cfg;
bool is_lro = false;
int err = 0;
+ aq_cfg = aq_nic_get_cfg(aq_nic);
+
if (!(features & NETIF_F_NTUPLE)) {
if (aq_nic->ndev->features & NETIF_F_NTUPLE) {
err = aq_clear_rxnfc_all_rules(aq_nic);
@@ -135,17 +140,32 @@ static int aq_ndev_set_features(struct net_device *ndev,
if (aq_cfg->is_lro != is_lro) {
aq_cfg->is_lro = is_lro;
-
- if (netif_running(ndev)) {
- aq_ndev_close(ndev);
- aq_ndev_open(ndev);
- }
+ need_ndev_restart = true;
}
}
- if ((aq_nic->ndev->features ^ features) & NETIF_F_RXCSUM)
+
+ if ((aq_nic->ndev->features ^ features) & NETIF_F_RXCSUM) {
err = aq_nic->aq_hw_ops->hw_set_offload(aq_nic->aq_hw,
aq_cfg);
+ if (unlikely(err))
+ goto err_exit;
+ }
+
+ if (aq_cfg->is_vlan_rx_strip != is_vlan_rx_strip) {
+ aq_cfg->is_vlan_rx_strip = is_vlan_rx_strip;
+ need_ndev_restart = true;
+ }
+ if (aq_cfg->is_vlan_tx_insert != is_vlan_tx_insert) {
+ aq_cfg->is_vlan_tx_insert = is_vlan_tx_insert;
+ need_ndev_restart = true;
+ }
+
+ if (need_ndev_restart && netif_running(ndev)) {
+ aq_ndev_close(ndev);
+ aq_ndev_open(ndev);
+ }
+
err_exit:
return err;
}
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index 0da5e161ec5d..e1392766e21e 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -126,6 +126,9 @@ void aq_nic_cfg_start(struct aq_nic_s *self)
cfg->link_speed_msk &= cfg->aq_hw_caps->link_speed_msk;
cfg->features = cfg->aq_hw_caps->hw_features;
+ cfg->is_vlan_rx_strip = !!(cfg->features & NETIF_F_HW_VLAN_CTAG_RX);
+ cfg->is_vlan_tx_insert = !!(cfg->features & NETIF_F_HW_VLAN_CTAG_TX);
+ cfg->is_vlan_force_promisc = true;
}
static int aq_nic_update_link_status(struct aq_nic_s *self)
@@ -285,7 +288,8 @@ void aq_nic_ndev_init(struct aq_nic_s *self)
self->ndev->hw_features |= aq_hw_caps->hw_features;
self->ndev->features = aq_hw_caps->hw_features;
self->ndev->vlan_features |= NETIF_F_HW_CSUM | NETIF_F_RXCSUM |
- NETIF_F_RXHASH | NETIF_F_SG | NETIF_F_LRO;
+ NETIF_F_RXHASH | NETIF_F_SG |
+ NETIF_F_LRO | NETIF_F_TSO;
self->ndev->priv_flags = aq_hw_caps->hw_priv_flags;
self->ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
@@ -426,26 +430,37 @@ static unsigned int aq_nic_map_skb(struct aq_nic_s *self,
unsigned int dx = ring->sw_tail;
struct aq_ring_buff_s *first = NULL;
struct aq_ring_buff_s *dx_buff = &ring->buff_ring[dx];
+ bool need_context_tag = false;
+
+ dx_buff->flags = 0U;
if (unlikely(skb_is_gso(skb))) {
- dx_buff->flags = 0U;
+ dx_buff->mss = skb_shinfo(skb)->gso_size;
+ dx_buff->is_gso = 1U;
dx_buff->len_pkt = skb->len;
dx_buff->len_l2 = ETH_HLEN;
dx_buff->len_l3 = ip_hdrlen(skb);
dx_buff->len_l4 = tcp_hdrlen(skb);
- dx_buff->mss = skb_shinfo(skb)->gso_size;
- dx_buff->is_txc = 1U;
dx_buff->eop_index = 0xffffU;
-
dx_buff->is_ipv6 =
(ip_hdr(skb)->version == 6) ? 1U : 0U;
+ need_context_tag = true;
+ }
+
+ if (self->aq_nic_cfg.is_vlan_tx_insert && skb_vlan_tag_present(skb)) {
+ dx_buff->vlan_tx_tag = skb_vlan_tag_get(skb);
+ dx_buff->len_pkt = skb->len;
+ dx_buff->is_vlan = 1U;
+ need_context_tag = true;
+ }
+ if (need_context_tag) {
dx = aq_ring_next_dx(ring, dx);
dx_buff = &ring->buff_ring[dx];
+ dx_buff->flags = 0U;
++ret;
}
- dx_buff->flags = 0U;
dx_buff->len = skb_headlen(skb);
dx_buff->pa = dma_map_single(aq_nic_get_dev(self),
skb->data,
@@ -534,7 +549,7 @@ mapping_error:
--ret, dx = aq_ring_next_dx(ring, dx)) {
dx_buff = &ring->buff_ring[dx];
- if (!dx_buff->is_txc && dx_buff->pa) {
+ if (!dx_buff->is_gso && !dx_buff->is_vlan && dx_buff->pa) {
if (unlikely(dx_buff->is_sop)) {
dma_unmap_single(aq_nic_get_dev(self),
dx_buff->pa,
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
index eb2e3c7c36f9..255b54a6ae07 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
@@ -35,6 +35,9 @@ struct aq_nic_cfg_s {
u32 flow_control;
u32 link_speed_msk;
u32 wol;
+ u8 is_vlan_rx_strip;
+ u8 is_vlan_tx_insert;
+ bool is_vlan_force_promisc;
u16 is_mc_list_enabled;
u16 mc_list_count;
bool is_autoneg;
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
index 2a7b91ed17c5..3901d7994ca1 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
@@ -409,6 +409,10 @@ int aq_ring_rx_clean(struct aq_ring_s *self,
}
}
+ if (buff->is_vlan)
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
+ buff->vlan_rx_tag);
+
skb->protocol = eth_type_trans(skb, ndev);
aq_rx_checksum(self, buff, skb);
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.h b/drivers/net/ethernet/aquantia/atlantic/aq_ring.h
index 6bd67210d0b7..47abd09d06c2 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.h
@@ -27,7 +27,7 @@ struct aq_rxpage {
* +----------+----------+----------+-----------
* 4/8bytes|len pkt |len pkt | | skb
* +----------+----------+----------+-----------
- * 4/8bytes|is_txc |len,flags |len |len,is_eop
+ * 4/8bytes|is_gso |len,flags |len |len,is_eop
* +----------+----------+----------+-----------
*
* This aq_ring_buff_s doesn't have endianness dependency.
@@ -44,6 +44,7 @@ struct __packed aq_ring_buff_s {
u8 is_hash_l4;
u8 rsvd1;
struct aq_rxpage rxdata;
+ u16 vlan_rx_tag;
};
/* EOP */
struct {
@@ -59,6 +60,7 @@ struct __packed aq_ring_buff_s {
u8 is_ipv6:1;
u8 rsvd2:7;
u32 len_pkt;
+ u16 vlan_tx_tag;
};
};
union {
@@ -70,11 +72,12 @@ struct __packed aq_ring_buff_s {
u32 is_cso_err:1;
u32 is_sop:1;
u32 is_eop:1;
- u32 is_txc:1;
+ u32 is_gso:1;
u32 is_mapped:1;
u32 is_cleaned:1;
u32 is_error:1;
- u32 rsvd3:6;
+ u32 is_vlan:1;
+ u32 rsvd3:5;
u16 eop_index;
u16 rsvd4;
};
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
index 0f140a9fe404..359a4d387185 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
@@ -451,7 +451,7 @@ static int hw_atl_a0_hw_ring_tx_xmit(struct aq_hw_s *self,
buff = &ring->buff_ring[ring->sw_tail];
- if (buff->is_txc) {
+ if (buff->is_gso) {
txd->ctl |= (buff->len_l3 << 31) |
(buff->len_l2 << 24) |
HW_ATL_A0_TXD_CTL_CMD_TCP |
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
index 1c7593d54035..30f7fc4c97ff 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
@@ -40,7 +40,9 @@
NETIF_F_TSO | \
NETIF_F_LRO | \
NETIF_F_NTUPLE | \
- NETIF_F_HW_VLAN_CTAG_FILTER, \
+ NETIF_F_HW_VLAN_CTAG_FILTER | \
+ NETIF_F_HW_VLAN_CTAG_RX | \
+ NETIF_F_HW_VLAN_CTAG_TX, \
.hw_priv_flags = IFF_UNICAST_FLT, \
.flow_control = true, \
.mtu = HW_ATL_B0_MTU_JUMBO, \
@@ -245,6 +247,9 @@ static int hw_atl_b0_hw_offload_set(struct aq_hw_s *self,
/* LSO offloads*/
hw_atl_tdm_large_send_offload_en_set(self, 0xFFFFFFFFU);
+ /* Outer VLAN tag offload */
+ hw_atl_rpo_outer_vlan_tag_mode_set(self, 1U);
+
/* LRO offloads */
{
unsigned int val = (8U < HW_ATL_B0_LRO_RXD_MAX) ? 0x3U :
@@ -487,6 +492,7 @@ static int hw_atl_b0_hw_ring_tx_xmit(struct aq_hw_s *self,
unsigned int buff_pa_len = 0U;
unsigned int pkt_len = 0U;
unsigned int frag_count = 0U;
+ bool is_vlan = false;
bool is_gso = false;
buff = &ring->buff_ring[ring->sw_tail];
@@ -501,36 +507,44 @@ static int hw_atl_b0_hw_ring_tx_xmit(struct aq_hw_s *self,
buff = &ring->buff_ring[ring->sw_tail];
- if (buff->is_txc) {
+ if (buff->is_gso) {
+ txd->ctl |= HW_ATL_B0_TXD_CTL_CMD_TCP;
+ txd->ctl |= HW_ATL_B0_TXD_CTL_DESC_TYPE_TXC;
txd->ctl |= (buff->len_l3 << 31) |
- (buff->len_l2 << 24) |
- HW_ATL_B0_TXD_CTL_CMD_TCP |
- HW_ATL_B0_TXD_CTL_DESC_TYPE_TXC;
- txd->ctl2 |= (buff->mss << 16) |
- (buff->len_l4 << 8) |
- (buff->len_l3 >> 1);
+ (buff->len_l2 << 24);
+ txd->ctl2 |= (buff->mss << 16);
+ is_gso = true;
pkt_len -= (buff->len_l4 +
buff->len_l3 +
buff->len_l2);
- is_gso = true;
-
if (buff->is_ipv6)
txd->ctl |= HW_ATL_B0_TXD_CTL_CMD_IPV6;
- } else {
+ txd->ctl2 |= (buff->len_l4 << 8) |
+ (buff->len_l3 >> 1);
+ }
+ if (buff->is_vlan) {
+ txd->ctl |= HW_ATL_B0_TXD_CTL_DESC_TYPE_TXC;
+ txd->ctl |= buff->vlan_tx_tag << 4;
+ is_vlan = true;
+ }
+ if (!buff->is_gso && !buff->is_vlan) {
buff_pa_len = buff->len;
txd->buf_addr = buff->pa;
txd->ctl |= (HW_ATL_B0_TXD_CTL_BLEN &
((u32)buff_pa_len << 4));
txd->ctl |= HW_ATL_B0_TXD_CTL_DESC_TYPE_TXD;
+
/* PAY_LEN */
txd->ctl2 |= HW_ATL_B0_TXD_CTL2_LEN & (pkt_len << 14);
- if (is_gso) {
- txd->ctl |= HW_ATL_B0_TXD_CTL_CMD_LSO;
+ if (is_gso || is_vlan) {
+ /* enable tx context */
txd->ctl2 |= HW_ATL_B0_TXD_CTL2_CTX_EN;
}
+ if (is_gso)
+ txd->ctl |= HW_ATL_B0_TXD_CTL_CMD_LSO;
/* Tx checksum offloads */
if (buff->is_ip_cso)
@@ -539,13 +553,16 @@ static int hw_atl_b0_hw_ring_tx_xmit(struct aq_hw_s *self,
if (buff->is_udp_cso || buff->is_tcp_cso)
txd->ctl |= HW_ATL_B0_TXD_CTL_CMD_TUCSO;
+ if (is_vlan)
+ txd->ctl |= HW_ATL_B0_TXD_CTL_CMD_VLAN;
+
if (unlikely(buff->is_eop)) {
txd->ctl |= HW_ATL_B0_TXD_CTL_EOP;
txd->ctl |= HW_ATL_B0_TXD_CTL_CMD_WB;
is_gso = false;
+ is_vlan = false;
}
}
-
ring->sw_tail = aq_ring_next_dx(ring, ring->sw_tail);
}
@@ -559,6 +576,7 @@ static int hw_atl_b0_hw_ring_rx_init(struct aq_hw_s *self,
{
u32 dma_desc_addr_lsw = (u32)aq_ring->dx_ring_pa;
u32 dma_desc_addr_msw = (u32)(((u64)aq_ring->dx_ring_pa) >> 32);
+ u32 vlan_rx_stripping = self->aq_nic_cfg->is_vlan_rx_strip;
hw_atl_rdm_rx_desc_en_set(self, false, aq_ring->idx);
@@ -578,7 +596,8 @@ static int hw_atl_b0_hw_ring_rx_init(struct aq_hw_s *self,
hw_atl_rdm_rx_desc_head_buff_size_set(self, 0U, aq_ring->idx);
hw_atl_rdm_rx_desc_head_splitting_set(self, 0U, aq_ring->idx);
- hw_atl_rpo_rx_desc_vlan_stripping_set(self, 0U, aq_ring->idx);
+ hw_atl_rpo_rx_desc_vlan_stripping_set(self, !!vlan_rx_stripping,
+ aq_ring->idx);
/* Rx ring set mode */
@@ -681,11 +700,15 @@ static int hw_atl_b0_hw_ring_rx_receive(struct aq_hw_s *self,
buff = &ring->buff_ring[ring->hw_head];
+ buff->flags = 0U;
+ buff->is_hash_l4 = 0U;
+
rx_stat = (0x0000003CU & rxd_wb->status) >> 2;
is_rx_check_sum_enabled = (rxd_wb->type >> 19) & 0x3U;
- pkt_type = 0xFFU & (rxd_wb->type >> 4);
+ pkt_type = (rxd_wb->type & HW_ATL_B0_RXD_WB_STAT_PKTTYPE) >>
+ HW_ATL_B0_RXD_WB_STAT_PKTTYPE_SHIFT;
if (is_rx_check_sum_enabled & BIT(0) &&
(0x0U == (pkt_type & 0x3U)))
@@ -706,6 +729,13 @@ static int hw_atl_b0_hw_ring_rx_receive(struct aq_hw_s *self,
buff->is_cso_err = 0U;
}
+ if (self->aq_nic_cfg->is_vlan_rx_strip &&
+ ((pkt_type & HW_ATL_B0_RXD_WB_PKTTYPE_VLAN) ||
+ (pkt_type & HW_ATL_B0_RXD_WB_PKTTYPE_VLAN_DOUBLE))) {
+ buff->is_vlan = 1;
+ buff->vlan_rx_tag = le16_to_cpu(rxd_wb->vlan);
+ }
+
if ((rx_stat & BIT(0)) || rxd_wb->type & 0x1000U) {
/* MAC error or DMA error */
buff->is_error = 1U;
@@ -778,8 +808,15 @@ static int hw_atl_b0_hw_packet_filter_set(struct aq_hw_s *self,
unsigned int packet_filter)
{
unsigned int i = 0U;
+ struct aq_nic_cfg_s *cfg = self->aq_nic_cfg;
+
+ hw_atl_rpfl2promiscuous_mode_en_set(self,
+ IS_FILTER_ENABLED(IFF_PROMISC));
+
+ hw_atl_rpf_vlan_prom_mode_en_set(self,
+ IS_FILTER_ENABLED(IFF_PROMISC) ||
+ cfg->is_vlan_force_promisc);
- hw_atl_rpfl2promiscuous_mode_en_set(self, IS_FILTER_ENABLED(IFF_PROMISC));
hw_atl_rpfl2multicast_flr_en_set(self,
IS_FILTER_ENABLED(IFF_ALLMULTI), 0);
@@ -788,13 +825,13 @@ static int hw_atl_b0_hw_packet_filter_set(struct aq_hw_s *self,
hw_atl_rpfl2broadcast_en_set(self, IS_FILTER_ENABLED(IFF_BROADCAST));
- self->aq_nic_cfg->is_mc_list_enabled = IS_FILTER_ENABLED(IFF_MULTICAST);
+ cfg->is_mc_list_enabled = IS_FILTER_ENABLED(IFF_MULTICAST);
for (i = HW_ATL_B0_MAC_MIN; i < HW_ATL_B0_MAC_MAX; ++i)
hw_atl_rpfl2_uc_flr_en_set(self,
- (self->aq_nic_cfg->is_mc_list_enabled &&
- (i <= self->aq_nic_cfg->mc_list_count)) ?
- 1U : 0U, i);
+ (cfg->is_mc_list_enabled &&
+ (i <= cfg->mc_list_count)) ?
+ 1U : 0U, i);
return aq_hw_err_from_flags(self);
}
@@ -1086,7 +1123,7 @@ static int hw_atl_b0_hw_vlan_set(struct aq_hw_s *self,
static int hw_atl_b0_hw_vlan_ctrl(struct aq_hw_s *self, bool enable)
{
/* set promisc in case of disabing the vland filter */
- hw_atl_rpf_vlan_prom_mode_en_set(self, !!!enable);
+ hw_atl_rpf_vlan_prom_mode_en_set(self, !enable);
return aq_hw_err_from_flags(self);
}
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h
index e4ba2ccf9830..808d8cd4252a 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h
@@ -107,10 +107,17 @@
#define HW_ATL_B0_RXD_NCEA0 (0x1)
#define HW_ATL_B0_RXD_WB_STAT_RSSTYPE (0x0000000F)
+#define HW_ATL_B0_RXD_WB_STAT_RSSTYPE_SHIFT (0x0)
#define HW_ATL_B0_RXD_WB_STAT_PKTTYPE (0x00000FF0)
+#define HW_ATL_B0_RXD_WB_STAT_PKTTYPE_SHIFT (0x4)
#define HW_ATL_B0_RXD_WB_STAT_RXCTRL (0x00180000)
+#define HW_ATL_B0_RXD_WB_STAT_RXCTRL_SHIFT (0x13)
#define HW_ATL_B0_RXD_WB_STAT_SPLHDR (0x00200000)
#define HW_ATL_B0_RXD_WB_STAT_HDRLEN (0xFFC00000)
+#define HW_ATL_B0_RXD_WB_STAT_HDRLEN_SHIFT (0x16)
+
+#define HW_ATL_B0_RXD_WB_PKTTYPE_VLAN BIT(5)
+#define HW_ATL_B0_RXD_WB_PKTTYPE_VLAN_DOUBLE BIT(6)
#define HW_ATL_B0_RXD_WB_STAT2_DD (0x0001)
#define HW_ATL_B0_RXD_WB_STAT2_EOP (0x0002)
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
index 451529069f28..1149812ae463 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
@@ -1004,6 +1004,22 @@ void hw_atl_rpo_rx_desc_vlan_stripping_set(struct aq_hw_s *aq_hw,
rx_desc_vlan_stripping);
}
+void hw_atl_rpo_outer_vlan_tag_mode_set(void *context,
+ u32 outervlantagmode)
+{
+ aq_hw_write_reg_bit(context, HW_ATL_RPO_OUTER_VL_INS_MODE_ADR,
+ HW_ATL_RPO_OUTER_VL_INS_MODE_MSK,
+ HW_ATL_RPO_OUTER_VL_INS_MODE_SHIFT,
+ outervlantagmode);
+}
+
+u32 hw_atl_rpo_outer_vlan_tag_mode_get(void *context)
+{
+ return aq_hw_read_reg_bit(context, HW_ATL_RPO_OUTER_VL_INS_MODE_ADR,
+ HW_ATL_RPO_OUTER_VL_INS_MODE_MSK,
+ HW_ATL_RPO_OUTER_VL_INS_MODE_SHIFT);
+}
+
void hw_atl_rpo_tcp_udp_crc_offload_en_set(struct aq_hw_s *aq_hw,
u32 tcp_udp_crc_offload_en)
{
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h
index 34b42ce43512..0c37abbabca5 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h
@@ -488,6 +488,11 @@ void hw_atl_rpo_rx_desc_vlan_stripping_set(struct aq_hw_s *aq_hw,
u32 rx_desc_vlan_stripping,
u32 descriptor);
+void hw_atl_rpo_outer_vlan_tag_mode_set(void *context,
+ u32 outervlantagmode);
+
+u32 hw_atl_rpo_outer_vlan_tag_mode_get(void *context);
+
/* set tcp/udp checksum offload enable */
void hw_atl_rpo_tcp_udp_crc_offload_en_set(struct aq_hw_s *aq_hw,
u32 tcp_udp_crc_offload_en);
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h
index fc1446f737bb..c3febcdfa92e 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h
@@ -1383,6 +1383,24 @@
/* default value of bitfield l4_chk_en */
#define HW_ATL_RPOL4CHK_EN_DEFAULT 0x0
+/* RX outer_vl_ins_mode Bitfield Definitions
+ * Preprocessor definitions for the bitfield "outer_vl_ins_mode".
+ * PORT="pif_rpo_outer_vl_mode_i"
+ */
+
+/* Register address for bitfield outer_vl_ins_mode */
+#define HW_ATL_RPO_OUTER_VL_INS_MODE_ADR 0x00005580
+/* Bitmask for bitfield outer_vl_ins_mode */
+#define HW_ATL_RPO_OUTER_VL_INS_MODE_MSK 0x00000004
+/* Inverted bitmask for bitfield outer_vl_ins_mode */
+#define HW_ATL_RPO_OUTER_VL_INS_MODE_MSKN 0xFFFFFFFB
+/* Lower bit position of bitfield outer_vl_ins_mode */
+#define HW_ATL_RPO_OUTER_VL_INS_MODE_SHIFT 2
+/* Width of bitfield outer_vl_ins_mode */
+#define HW_ATL_RPO_OUTER_VL_INS_MODE_WIDTH 1
+/* Default value of bitfield outer_vl_ins_mode */
+#define HW_ATL_RPO_OUTER_VL_INS_MODE_DEFAULT 0x0
+
/* rx reg_res_dsbl bitfield definitions
* preprocessor definitions for the bitfield "reg_res_dsbl".
* port="pif_rx_reg_res_dsbl_i"
diff --git a/drivers/net/ethernet/aquantia/atlantic/ver.h b/drivers/net/ethernet/aquantia/atlantic/ver.h
index 23374bffa92b..597654b51e01 100644
--- a/drivers/net/ethernet/aquantia/atlantic/ver.h
+++ b/drivers/net/ethernet/aquantia/atlantic/ver.h
@@ -7,11 +7,6 @@
#ifndef VER_H
#define VER_H
-#define NIC_MAJOR_DRIVER_VERSION 2
-#define NIC_MINOR_DRIVER_VERSION 0
-#define NIC_BUILD_DRIVER_VERSION 4
-#define NIC_REVISION_DRIVER_VERSION 0
-
#define AQ_CFG_DRV_VERSION_SUFFIX "-kern"
#endif /* VER_H */
diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
index 13a1d99b29c6..6f2c867785fe 100644
--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2004-2013 Synopsys, Inc. (www.synopsys.com)
*
- * 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.
- *
* Driver for the ARC EMAC 10100 (hardware revision 5)
*
* Contributors:
diff --git a/drivers/net/ethernet/atheros/Kconfig b/drivers/net/ethernet/atheros/Kconfig
index 953ff1f9ac70..0058051ba925 100644
--- a/drivers/net/ethernet/atheros/Kconfig
+++ b/drivers/net/ethernet/atheros/Kconfig
@@ -6,7 +6,7 @@
config NET_VENDOR_ATHEROS
bool "Atheros devices"
default y
- depends on PCI
+ depends on (PCI || ATH79)
---help---
If you have a network (Ethernet) card belonging to this class, say Y.
@@ -17,6 +17,14 @@ config NET_VENDOR_ATHEROS
if NET_VENDOR_ATHEROS
+config AG71XX
+ tristate "Atheros AR7XXX/AR9XXX built-in ethernet mac support"
+ depends on ATH79
+ select PHYLIB
+ help
+ If you wish to compile a kernel for AR7XXX/91XXX and enable
+ ethernet support, then you should always answer Y to this.
+
config ATL2
tristate "Atheros L2 Fast Ethernet support"
depends on PCI
diff --git a/drivers/net/ethernet/atheros/Makefile b/drivers/net/ethernet/atheros/Makefile
index aa3d394b87e6..aca696cb6425 100644
--- a/drivers/net/ethernet/atheros/Makefile
+++ b/drivers/net/ethernet/atheros/Makefile
@@ -3,6 +3,7 @@
# Makefile for the Atheros network device drivers.
#
+obj-$(CONFIG_AG71XX) += ag71xx.o
obj-$(CONFIG_ATL1) += atlx/
obj-$(CONFIG_ATL2) += atlx/
obj-$(CONFIG_ATL1E) += atl1e/
diff --git a/drivers/net/ethernet/atheros/ag71xx.c b/drivers/net/ethernet/atheros/ag71xx.c
new file mode 100644
index 000000000000..8b69d0d7e726
--- /dev/null
+++ b/drivers/net/ethernet/atheros/ag71xx.c
@@ -0,0 +1,1901 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Atheros AR71xx built-in ethernet mac driver
+ *
+ * Copyright (C) 2019 Oleksij Rempel <o.rempel@pengutronix.de>
+ *
+ * List of authors contributed to this driver before mainlining:
+ * Alexander Couzens <lynxis@fe80.eu>
+ * Christian Lamparter <chunkeey@gmail.com>
+ * Chuanhong Guo <gch981213@gmail.com>
+ * Daniel F. Dickinson <cshored@thecshore.com>
+ * David Bauer <mail@david-bauer.net>
+ * Felix Fietkau <nbd@nbd.name>
+ * Gabor Juhos <juhosg@freemail.hu>
+ * Hauke Mehrtens <hauke@hauke-m.de>
+ * Johann Neuhauser <johann@it-neuhauser.de>
+ * John Crispin <john@phrozen.org>
+ * Jo-Philipp Wich <jo@mein.io>
+ * Koen Vandeputte <koen.vandeputte@ncentric.com>
+ * Lucian Cristian <lucian.cristian@gmail.com>
+ * Matt Merhar <mattmerhar@protonmail.com>
+ * Milan Krstic <milan.krstic@gmail.com>
+ * Petr Å tetiar <ynezz@true.cz>
+ * Rosen Penev <rosenp@gmail.com>
+ * Stephen Walker <stephendwalker+github@gmail.com>
+ * Vittorio Gambaletta <openwrt@vittgam.net>
+ * Weijie Gao <hackpascal@gmail.com>
+ * Imre Kaloz <kaloz@openwrt.org>
+ */
+
+#include <linux/if_vlan.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_mdio.h>
+#include <linux/of_net.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+/* For our NAPI weight bigger does *NOT* mean better - it means more
+ * D-cache misses and lots more wasted cycles than we'll ever
+ * possibly gain from saving instructions.
+ */
+#define AG71XX_NAPI_WEIGHT 32
+#define AG71XX_OOM_REFILL (1 + HZ / 10)
+
+#define AG71XX_INT_ERR (AG71XX_INT_RX_BE | AG71XX_INT_TX_BE)
+#define AG71XX_INT_TX (AG71XX_INT_TX_PS)
+#define AG71XX_INT_RX (AG71XX_INT_RX_PR | AG71XX_INT_RX_OF)
+
+#define AG71XX_INT_POLL (AG71XX_INT_RX | AG71XX_INT_TX)
+#define AG71XX_INT_INIT (AG71XX_INT_ERR | AG71XX_INT_POLL)
+
+#define AG71XX_TX_MTU_LEN 1540
+
+#define AG71XX_TX_RING_SPLIT 512
+#define AG71XX_TX_RING_DS_PER_PKT DIV_ROUND_UP(AG71XX_TX_MTU_LEN, \
+ AG71XX_TX_RING_SPLIT)
+#define AG71XX_TX_RING_SIZE_DEFAULT 128
+#define AG71XX_RX_RING_SIZE_DEFAULT 256
+
+#define AG71XX_MDIO_RETRY 1000
+#define AG71XX_MDIO_DELAY 5
+#define AG71XX_MDIO_MAX_CLK 5000000
+
+/* Register offsets */
+#define AG71XX_REG_MAC_CFG1 0x0000
+#define MAC_CFG1_TXE BIT(0) /* Tx Enable */
+#define MAC_CFG1_STX BIT(1) /* Synchronize Tx Enable */
+#define MAC_CFG1_RXE BIT(2) /* Rx Enable */
+#define MAC_CFG1_SRX BIT(3) /* Synchronize Rx Enable */
+#define MAC_CFG1_TFC BIT(4) /* Tx Flow Control Enable */
+#define MAC_CFG1_RFC BIT(5) /* Rx Flow Control Enable */
+#define MAC_CFG1_SR BIT(31) /* Soft Reset */
+#define MAC_CFG1_INIT (MAC_CFG1_RXE | MAC_CFG1_TXE | \
+ MAC_CFG1_SRX | MAC_CFG1_STX)
+
+#define AG71XX_REG_MAC_CFG2 0x0004
+#define MAC_CFG2_FDX BIT(0)
+#define MAC_CFG2_PAD_CRC_EN BIT(2)
+#define MAC_CFG2_LEN_CHECK BIT(4)
+#define MAC_CFG2_IF_1000 BIT(9)
+#define MAC_CFG2_IF_10_100 BIT(8)
+
+#define AG71XX_REG_MAC_MFL 0x0010
+
+#define AG71XX_REG_MII_CFG 0x0020
+#define MII_CFG_CLK_DIV_4 0
+#define MII_CFG_CLK_DIV_6 2
+#define MII_CFG_CLK_DIV_8 3
+#define MII_CFG_CLK_DIV_10 4
+#define MII_CFG_CLK_DIV_14 5
+#define MII_CFG_CLK_DIV_20 6
+#define MII_CFG_CLK_DIV_28 7
+#define MII_CFG_CLK_DIV_34 8
+#define MII_CFG_CLK_DIV_42 9
+#define MII_CFG_CLK_DIV_50 10
+#define MII_CFG_CLK_DIV_58 11
+#define MII_CFG_CLK_DIV_66 12
+#define MII_CFG_CLK_DIV_74 13
+#define MII_CFG_CLK_DIV_82 14
+#define MII_CFG_CLK_DIV_98 15
+#define MII_CFG_RESET BIT(31)
+
+#define AG71XX_REG_MII_CMD 0x0024
+#define MII_CMD_READ BIT(0)
+
+#define AG71XX_REG_MII_ADDR 0x0028
+#define MII_ADDR_SHIFT 8
+
+#define AG71XX_REG_MII_CTRL 0x002c
+#define AG71XX_REG_MII_STATUS 0x0030
+#define AG71XX_REG_MII_IND 0x0034
+#define MII_IND_BUSY BIT(0)
+#define MII_IND_INVALID BIT(2)
+
+#define AG71XX_REG_MAC_IFCTL 0x0038
+#define MAC_IFCTL_SPEED BIT(16)
+
+#define AG71XX_REG_MAC_ADDR1 0x0040
+#define AG71XX_REG_MAC_ADDR2 0x0044
+#define AG71XX_REG_FIFO_CFG0 0x0048
+#define FIFO_CFG0_WTM BIT(0) /* Watermark Module */
+#define FIFO_CFG0_RXS BIT(1) /* Rx System Module */
+#define FIFO_CFG0_RXF BIT(2) /* Rx Fabric Module */
+#define FIFO_CFG0_TXS BIT(3) /* Tx System Module */
+#define FIFO_CFG0_TXF BIT(4) /* Tx Fabric Module */
+#define FIFO_CFG0_ALL (FIFO_CFG0_WTM | FIFO_CFG0_RXS | FIFO_CFG0_RXF \
+ | FIFO_CFG0_TXS | FIFO_CFG0_TXF)
+#define FIFO_CFG0_INIT (FIFO_CFG0_ALL << FIFO_CFG0_ENABLE_SHIFT)
+
+#define FIFO_CFG0_ENABLE_SHIFT 8
+
+#define AG71XX_REG_FIFO_CFG1 0x004c
+#define AG71XX_REG_FIFO_CFG2 0x0050
+#define AG71XX_REG_FIFO_CFG3 0x0054
+#define AG71XX_REG_FIFO_CFG4 0x0058
+#define FIFO_CFG4_DE BIT(0) /* Drop Event */
+#define FIFO_CFG4_DV BIT(1) /* RX_DV Event */
+#define FIFO_CFG4_FC BIT(2) /* False Carrier */
+#define FIFO_CFG4_CE BIT(3) /* Code Error */
+#define FIFO_CFG4_CR BIT(4) /* CRC error */
+#define FIFO_CFG4_LM BIT(5) /* Length Mismatch */
+#define FIFO_CFG4_LO BIT(6) /* Length out of range */
+#define FIFO_CFG4_OK BIT(7) /* Packet is OK */
+#define FIFO_CFG4_MC BIT(8) /* Multicast Packet */
+#define FIFO_CFG4_BC BIT(9) /* Broadcast Packet */
+#define FIFO_CFG4_DR BIT(10) /* Dribble */
+#define FIFO_CFG4_LE BIT(11) /* Long Event */
+#define FIFO_CFG4_CF BIT(12) /* Control Frame */
+#define FIFO_CFG4_PF BIT(13) /* Pause Frame */
+#define FIFO_CFG4_UO BIT(14) /* Unsupported Opcode */
+#define FIFO_CFG4_VT BIT(15) /* VLAN tag detected */
+#define FIFO_CFG4_FT BIT(16) /* Frame Truncated */
+#define FIFO_CFG4_UC BIT(17) /* Unicast Packet */
+#define FIFO_CFG4_INIT (FIFO_CFG4_DE | FIFO_CFG4_DV | FIFO_CFG4_FC | \
+ FIFO_CFG4_CE | FIFO_CFG4_CR | FIFO_CFG4_LM | \
+ FIFO_CFG4_LO | FIFO_CFG4_OK | FIFO_CFG4_MC | \
+ FIFO_CFG4_BC | FIFO_CFG4_DR | FIFO_CFG4_LE | \
+ FIFO_CFG4_CF | FIFO_CFG4_PF | FIFO_CFG4_UO | \
+ FIFO_CFG4_VT)
+
+#define AG71XX_REG_FIFO_CFG5 0x005c
+#define FIFO_CFG5_DE BIT(0) /* Drop Event */
+#define FIFO_CFG5_DV BIT(1) /* RX_DV Event */
+#define FIFO_CFG5_FC BIT(2) /* False Carrier */
+#define FIFO_CFG5_CE BIT(3) /* Code Error */
+#define FIFO_CFG5_LM BIT(4) /* Length Mismatch */
+#define FIFO_CFG5_LO BIT(5) /* Length Out of Range */
+#define FIFO_CFG5_OK BIT(6) /* Packet is OK */
+#define FIFO_CFG5_MC BIT(7) /* Multicast Packet */
+#define FIFO_CFG5_BC BIT(8) /* Broadcast Packet */
+#define FIFO_CFG5_DR BIT(9) /* Dribble */
+#define FIFO_CFG5_CF BIT(10) /* Control Frame */
+#define FIFO_CFG5_PF BIT(11) /* Pause Frame */
+#define FIFO_CFG5_UO BIT(12) /* Unsupported Opcode */
+#define FIFO_CFG5_VT BIT(13) /* VLAN tag detected */
+#define FIFO_CFG5_LE BIT(14) /* Long Event */
+#define FIFO_CFG5_FT BIT(15) /* Frame Truncated */
+#define FIFO_CFG5_16 BIT(16) /* unknown */
+#define FIFO_CFG5_17 BIT(17) /* unknown */
+#define FIFO_CFG5_SF BIT(18) /* Short Frame */
+#define FIFO_CFG5_BM BIT(19) /* Byte Mode */
+#define FIFO_CFG5_INIT (FIFO_CFG5_DE | FIFO_CFG5_DV | FIFO_CFG5_FC | \
+ FIFO_CFG5_CE | FIFO_CFG5_LO | FIFO_CFG5_OK | \
+ FIFO_CFG5_MC | FIFO_CFG5_BC | FIFO_CFG5_DR | \
+ FIFO_CFG5_CF | FIFO_CFG5_PF | FIFO_CFG5_VT | \
+ FIFO_CFG5_LE | FIFO_CFG5_FT | FIFO_CFG5_16 | \
+ FIFO_CFG5_17 | FIFO_CFG5_SF)
+
+#define AG71XX_REG_TX_CTRL 0x0180
+#define TX_CTRL_TXE BIT(0) /* Tx Enable */
+
+#define AG71XX_REG_TX_DESC 0x0184
+#define AG71XX_REG_TX_STATUS 0x0188
+#define TX_STATUS_PS BIT(0) /* Packet Sent */
+#define TX_STATUS_UR BIT(1) /* Tx Underrun */
+#define TX_STATUS_BE BIT(3) /* Bus Error */
+
+#define AG71XX_REG_RX_CTRL 0x018c
+#define RX_CTRL_RXE BIT(0) /* Rx Enable */
+
+#define AG71XX_DMA_RETRY 10
+#define AG71XX_DMA_DELAY 1
+
+#define AG71XX_REG_RX_DESC 0x0190
+#define AG71XX_REG_RX_STATUS 0x0194
+#define RX_STATUS_PR BIT(0) /* Packet Received */
+#define RX_STATUS_OF BIT(2) /* Rx Overflow */
+#define RX_STATUS_BE BIT(3) /* Bus Error */
+
+#define AG71XX_REG_INT_ENABLE 0x0198
+#define AG71XX_REG_INT_STATUS 0x019c
+#define AG71XX_INT_TX_PS BIT(0)
+#define AG71XX_INT_TX_UR BIT(1)
+#define AG71XX_INT_TX_BE BIT(3)
+#define AG71XX_INT_RX_PR BIT(4)
+#define AG71XX_INT_RX_OF BIT(6)
+#define AG71XX_INT_RX_BE BIT(7)
+
+#define AG71XX_REG_FIFO_DEPTH 0x01a8
+#define AG71XX_REG_RX_SM 0x01b0
+#define AG71XX_REG_TX_SM 0x01b4
+
+#define ETH_SWITCH_HEADER_LEN 2
+
+#define AG71XX_DEFAULT_MSG_ENABLE \
+ (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)
+
+#define DESC_EMPTY BIT(31)
+#define DESC_MORE BIT(24)
+#define DESC_PKTLEN_M 0xfff
+struct ag71xx_desc {
+ u32 data;
+ u32 ctrl;
+ u32 next;
+ u32 pad;
+} __aligned(4);
+
+#define AG71XX_DESC_SIZE roundup(sizeof(struct ag71xx_desc), \
+ L1_CACHE_BYTES)
+
+struct ag71xx_buf {
+ union {
+ struct {
+ struct sk_buff *skb;
+ unsigned int len;
+ } tx;
+ struct {
+ dma_addr_t dma_addr;
+ void *rx_buf;
+ } rx;
+ };
+};
+
+struct ag71xx_ring {
+ /* "Hot" fields in the data path. */
+ unsigned int curr;
+ unsigned int dirty;
+
+ /* "Cold" fields - not used in the data path. */
+ struct ag71xx_buf *buf;
+ u16 order;
+ u16 desc_split;
+ dma_addr_t descs_dma;
+ u8 *descs_cpu;
+};
+
+enum ag71xx_type {
+ AR7100,
+ AR7240,
+ AR9130,
+ AR9330,
+ AR9340,
+ QCA9530,
+ QCA9550,
+};
+
+struct ag71xx_dcfg {
+ u32 max_frame_len;
+ const u32 *fifodata;
+ u16 desc_pktlen_mask;
+ bool tx_hang_workaround;
+ enum ag71xx_type type;
+};
+
+struct ag71xx {
+ /* Critical data related to the per-packet data path are clustered
+ * early in this structure to help improve the D-cache footprint.
+ */
+ struct ag71xx_ring rx_ring ____cacheline_aligned;
+ struct ag71xx_ring tx_ring ____cacheline_aligned;
+
+ u16 rx_buf_size;
+ u8 rx_buf_offset;
+
+ struct net_device *ndev;
+ struct platform_device *pdev;
+ struct napi_struct napi;
+ u32 msg_enable;
+ const struct ag71xx_dcfg *dcfg;
+
+ /* From this point onwards we're not looking at per-packet fields. */
+ void __iomem *mac_base;
+
+ struct ag71xx_desc *stop_desc;
+ dma_addr_t stop_desc_dma;
+
+ int phy_if_mode;
+
+ struct delayed_work restart_work;
+ struct timer_list oom_timer;
+
+ struct reset_control *mac_reset;
+
+ u32 fifodata[3];
+ int mac_idx;
+
+ struct reset_control *mdio_reset;
+ struct mii_bus *mii_bus;
+ struct clk *clk_mdio;
+ struct clk *clk_eth;
+};
+
+static int ag71xx_desc_empty(struct ag71xx_desc *desc)
+{
+ return (desc->ctrl & DESC_EMPTY) != 0;
+}
+
+static struct ag71xx_desc *ag71xx_ring_desc(struct ag71xx_ring *ring, int idx)
+{
+ return (struct ag71xx_desc *)&ring->descs_cpu[idx * AG71XX_DESC_SIZE];
+}
+
+static int ag71xx_ring_size_order(int size)
+{
+ return fls(size - 1);
+}
+
+static bool ag71xx_is(struct ag71xx *ag, enum ag71xx_type type)
+{
+ return ag->dcfg->type == type;
+}
+
+static void ag71xx_wr(struct ag71xx *ag, unsigned int reg, u32 value)
+{
+ iowrite32(value, ag->mac_base + reg);
+ /* flush write */
+ (void)ioread32(ag->mac_base + reg);
+}
+
+static u32 ag71xx_rr(struct ag71xx *ag, unsigned int reg)
+{
+ return ioread32(ag->mac_base + reg);
+}
+
+static void ag71xx_sb(struct ag71xx *ag, unsigned int reg, u32 mask)
+{
+ void __iomem *r;
+
+ r = ag->mac_base + reg;
+ iowrite32(ioread32(r) | mask, r);
+ /* flush write */
+ (void)ioread32(r);
+}
+
+static void ag71xx_cb(struct ag71xx *ag, unsigned int reg, u32 mask)
+{
+ void __iomem *r;
+
+ r = ag->mac_base + reg;
+ iowrite32(ioread32(r) & ~mask, r);
+ /* flush write */
+ (void)ioread32(r);
+}
+
+static void ag71xx_int_enable(struct ag71xx *ag, u32 ints)
+{
+ ag71xx_sb(ag, AG71XX_REG_INT_ENABLE, ints);
+}
+
+static void ag71xx_int_disable(struct ag71xx *ag, u32 ints)
+{
+ ag71xx_cb(ag, AG71XX_REG_INT_ENABLE, ints);
+}
+
+static int ag71xx_mdio_wait_busy(struct ag71xx *ag)
+{
+ struct net_device *ndev = ag->ndev;
+ int i;
+
+ for (i = 0; i < AG71XX_MDIO_RETRY; i++) {
+ u32 busy;
+
+ udelay(AG71XX_MDIO_DELAY);
+
+ busy = ag71xx_rr(ag, AG71XX_REG_MII_IND);
+ if (!busy)
+ return 0;
+
+ udelay(AG71XX_MDIO_DELAY);
+ }
+
+ netif_err(ag, link, ndev, "MDIO operation timed out\n");
+
+ return -ETIMEDOUT;
+}
+
+static int ag71xx_mdio_mii_read(struct mii_bus *bus, int addr, int reg)
+{
+ struct ag71xx *ag = bus->priv;
+ int err, val;
+
+ err = ag71xx_mdio_wait_busy(ag);
+ if (err)
+ return err;
+
+ ag71xx_wr(ag, AG71XX_REG_MII_ADDR,
+ ((addr & 0x1f) << MII_ADDR_SHIFT) | (reg & 0xff));
+ /* enable read mode */
+ ag71xx_wr(ag, AG71XX_REG_MII_CMD, MII_CMD_READ);
+
+ err = ag71xx_mdio_wait_busy(ag);
+ if (err)
+ return err;
+
+ val = ag71xx_rr(ag, AG71XX_REG_MII_STATUS);
+ /* disable read mode */
+ ag71xx_wr(ag, AG71XX_REG_MII_CMD, 0);
+
+ netif_dbg(ag, link, ag->ndev, "mii_read: addr=%04x, reg=%04x, value=%04x\n",
+ addr, reg, val);
+
+ return val;
+}
+
+static int ag71xx_mdio_mii_write(struct mii_bus *bus, int addr, int reg,
+ u16 val)
+{
+ struct ag71xx *ag = bus->priv;
+
+ netif_dbg(ag, link, ag->ndev, "mii_write: addr=%04x, reg=%04x, value=%04x\n",
+ addr, reg, val);
+
+ ag71xx_wr(ag, AG71XX_REG_MII_ADDR,
+ ((addr & 0x1f) << MII_ADDR_SHIFT) | (reg & 0xff));
+ ag71xx_wr(ag, AG71XX_REG_MII_CTRL, val);
+
+ return ag71xx_mdio_wait_busy(ag);
+}
+
+static const u32 ar71xx_mdio_div_table[] = {
+ 4, 4, 6, 8, 10, 14, 20, 28,
+};
+
+static const u32 ar7240_mdio_div_table[] = {
+ 2, 2, 4, 6, 8, 12, 18, 26, 32, 40, 48, 56, 62, 70, 78, 96,
+};
+
+static const u32 ar933x_mdio_div_table[] = {
+ 4, 4, 6, 8, 10, 14, 20, 28, 34, 42, 50, 58, 66, 74, 82, 98,
+};
+
+static int ag71xx_mdio_get_divider(struct ag71xx *ag, u32 *div)
+{
+ unsigned long ref_clock;
+ const u32 *table;
+ int ndivs, i;
+
+ ref_clock = clk_get_rate(ag->clk_mdio);
+ if (!ref_clock)
+ return -EINVAL;
+
+ if (ag71xx_is(ag, AR9330) || ag71xx_is(ag, AR9340)) {
+ table = ar933x_mdio_div_table;
+ ndivs = ARRAY_SIZE(ar933x_mdio_div_table);
+ } else if (ag71xx_is(ag, AR7240)) {
+ table = ar7240_mdio_div_table;
+ ndivs = ARRAY_SIZE(ar7240_mdio_div_table);
+ } else {
+ table = ar71xx_mdio_div_table;
+ ndivs = ARRAY_SIZE(ar71xx_mdio_div_table);
+ }
+
+ for (i = 0; i < ndivs; i++) {
+ unsigned long t;
+
+ t = ref_clock / table[i];
+ if (t <= AG71XX_MDIO_MAX_CLK) {
+ *div = i;
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+static int ag71xx_mdio_reset(struct mii_bus *bus)
+{
+ struct ag71xx *ag = bus->priv;
+ int err;
+ u32 t;
+
+ err = ag71xx_mdio_get_divider(ag, &t);
+ if (err)
+ return err;
+
+ ag71xx_wr(ag, AG71XX_REG_MII_CFG, t | MII_CFG_RESET);
+ usleep_range(100, 200);
+
+ ag71xx_wr(ag, AG71XX_REG_MII_CFG, t);
+ usleep_range(100, 200);
+
+ return 0;
+}
+
+static int ag71xx_mdio_probe(struct ag71xx *ag)
+{
+ struct device *dev = &ag->pdev->dev;
+ struct net_device *ndev = ag->ndev;
+ static struct mii_bus *mii_bus;
+ struct device_node *np;
+ int err;
+
+ np = dev->of_node;
+ ag->mii_bus = NULL;
+
+ ag->clk_mdio = devm_clk_get(dev, "mdio");
+ if (IS_ERR(ag->clk_mdio)) {
+ netif_err(ag, probe, ndev, "Failed to get mdio clk.\n");
+ return PTR_ERR(ag->clk_mdio);
+ }
+
+ err = clk_prepare_enable(ag->clk_mdio);
+ if (err) {
+ netif_err(ag, probe, ndev, "Failed to enable mdio clk.\n");
+ return err;
+ }
+
+ mii_bus = devm_mdiobus_alloc(dev);
+ if (!mii_bus) {
+ err = -ENOMEM;
+ goto mdio_err_put_clk;
+ }
+
+ ag->mdio_reset = of_reset_control_get_exclusive(np, "mdio");
+ if (IS_ERR(ag->mdio_reset)) {
+ netif_err(ag, probe, ndev, "Failed to get reset mdio.\n");
+ return PTR_ERR(ag->mdio_reset);
+ }
+
+ mii_bus->name = "ag71xx_mdio";
+ mii_bus->read = ag71xx_mdio_mii_read;
+ mii_bus->write = ag71xx_mdio_mii_write;
+ mii_bus->reset = ag71xx_mdio_reset;
+ mii_bus->priv = ag;
+ mii_bus->parent = dev;
+ snprintf(mii_bus->id, MII_BUS_ID_SIZE, "%s.%d", np->name, ag->mac_idx);
+
+ if (!IS_ERR(ag->mdio_reset)) {
+ reset_control_assert(ag->mdio_reset);
+ msleep(100);
+ reset_control_deassert(ag->mdio_reset);
+ msleep(200);
+ }
+
+ err = of_mdiobus_register(mii_bus, np);
+ if (err)
+ goto mdio_err_put_clk;
+
+ ag->mii_bus = mii_bus;
+
+ return 0;
+
+mdio_err_put_clk:
+ clk_disable_unprepare(ag->clk_mdio);
+ return err;
+}
+
+static void ag71xx_mdio_remove(struct ag71xx *ag)
+{
+ if (ag->mii_bus)
+ mdiobus_unregister(ag->mii_bus);
+ clk_disable_unprepare(ag->clk_mdio);
+}
+
+static void ag71xx_hw_stop(struct ag71xx *ag)
+{
+ /* disable all interrupts and stop the rx/tx engine */
+ ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, 0);
+ ag71xx_wr(ag, AG71XX_REG_RX_CTRL, 0);
+ ag71xx_wr(ag, AG71XX_REG_TX_CTRL, 0);
+}
+
+static bool ag71xx_check_dma_stuck(struct ag71xx *ag)
+{
+ unsigned long timestamp;
+ u32 rx_sm, tx_sm, rx_fd;
+
+ timestamp = netdev_get_tx_queue(ag->ndev, 0)->trans_start;
+ if (likely(time_before(jiffies, timestamp + HZ / 10)))
+ return false;
+
+ if (!netif_carrier_ok(ag->ndev))
+ return false;
+
+ rx_sm = ag71xx_rr(ag, AG71XX_REG_RX_SM);
+ if ((rx_sm & 0x7) == 0x3 && ((rx_sm >> 4) & 0x7) == 0x6)
+ return true;
+
+ tx_sm = ag71xx_rr(ag, AG71XX_REG_TX_SM);
+ rx_fd = ag71xx_rr(ag, AG71XX_REG_FIFO_DEPTH);
+ if (((tx_sm >> 4) & 0x7) == 0 && ((rx_sm & 0x7) == 0) &&
+ ((rx_sm >> 4) & 0x7) == 0 && rx_fd == 0)
+ return true;
+
+ return false;
+}
+
+static int ag71xx_tx_packets(struct ag71xx *ag, bool flush)
+{
+ struct ag71xx_ring *ring = &ag->tx_ring;
+ int sent = 0, bytes_compl = 0, n = 0;
+ struct net_device *ndev = ag->ndev;
+ int ring_mask, ring_size;
+ bool dma_stuck = false;
+
+ ring_mask = BIT(ring->order) - 1;
+ ring_size = BIT(ring->order);
+
+ netif_dbg(ag, tx_queued, ndev, "processing TX ring\n");
+
+ while (ring->dirty + n != ring->curr) {
+ struct ag71xx_desc *desc;
+ struct sk_buff *skb;
+ unsigned int i;
+
+ i = (ring->dirty + n) & ring_mask;
+ desc = ag71xx_ring_desc(ring, i);
+ skb = ring->buf[i].tx.skb;
+
+ if (!flush && !ag71xx_desc_empty(desc)) {
+ if (ag->dcfg->tx_hang_workaround &&
+ ag71xx_check_dma_stuck(ag)) {
+ schedule_delayed_work(&ag->restart_work,
+ HZ / 2);
+ dma_stuck = true;
+ }
+ break;
+ }
+
+ if (flush)
+ desc->ctrl |= DESC_EMPTY;
+
+ n++;
+ if (!skb)
+ continue;
+
+ dev_kfree_skb_any(skb);
+ ring->buf[i].tx.skb = NULL;
+
+ bytes_compl += ring->buf[i].tx.len;
+
+ sent++;
+ ring->dirty += n;
+
+ while (n > 0) {
+ ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_PS);
+ n--;
+ }
+ }
+
+ netif_dbg(ag, tx_done, ndev, "%d packets sent out\n", sent);
+
+ if (!sent)
+ return 0;
+
+ ag->ndev->stats.tx_bytes += bytes_compl;
+ ag->ndev->stats.tx_packets += sent;
+
+ netdev_completed_queue(ag->ndev, sent, bytes_compl);
+ if ((ring->curr - ring->dirty) < (ring_size * 3) / 4)
+ netif_wake_queue(ag->ndev);
+
+ if (!dma_stuck)
+ cancel_delayed_work(&ag->restart_work);
+
+ return sent;
+}
+
+static void ag71xx_dma_wait_stop(struct ag71xx *ag)
+{
+ struct net_device *ndev = ag->ndev;
+ int i;
+
+ for (i = 0; i < AG71XX_DMA_RETRY; i++) {
+ u32 rx, tx;
+
+ mdelay(AG71XX_DMA_DELAY);
+
+ rx = ag71xx_rr(ag, AG71XX_REG_RX_CTRL) & RX_CTRL_RXE;
+ tx = ag71xx_rr(ag, AG71XX_REG_TX_CTRL) & TX_CTRL_TXE;
+ if (!rx && !tx)
+ return;
+ }
+
+ netif_err(ag, hw, ndev, "DMA stop operation timed out\n");
+}
+
+static void ag71xx_dma_reset(struct ag71xx *ag)
+{
+ struct net_device *ndev = ag->ndev;
+ u32 val;
+ int i;
+
+ /* stop RX and TX */
+ ag71xx_wr(ag, AG71XX_REG_RX_CTRL, 0);
+ ag71xx_wr(ag, AG71XX_REG_TX_CTRL, 0);
+
+ /* give the hardware some time to really stop all rx/tx activity
+ * clearing the descriptors too early causes random memory corruption
+ */
+ ag71xx_dma_wait_stop(ag);
+
+ /* clear descriptor addresses */
+ ag71xx_wr(ag, AG71XX_REG_TX_DESC, ag->stop_desc_dma);
+ ag71xx_wr(ag, AG71XX_REG_RX_DESC, ag->stop_desc_dma);
+
+ /* clear pending RX/TX interrupts */
+ for (i = 0; i < 256; i++) {
+ ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_PR);
+ ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_PS);
+ }
+
+ /* clear pending errors */
+ ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_BE | RX_STATUS_OF);
+ ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_BE | TX_STATUS_UR);
+
+ val = ag71xx_rr(ag, AG71XX_REG_RX_STATUS);
+ if (val)
+ netif_err(ag, hw, ndev, "unable to clear DMA Rx status: %08x\n",
+ val);
+
+ val = ag71xx_rr(ag, AG71XX_REG_TX_STATUS);
+
+ /* mask out reserved bits */
+ val &= ~0xff000000;
+
+ if (val)
+ netif_err(ag, hw, ndev, "unable to clear DMA Tx status: %08x\n",
+ val);
+}
+
+static void ag71xx_hw_setup(struct ag71xx *ag)
+{
+ u32 init = MAC_CFG1_INIT;
+
+ /* setup MAC configuration registers */
+ ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, init);
+
+ ag71xx_sb(ag, AG71XX_REG_MAC_CFG2,
+ MAC_CFG2_PAD_CRC_EN | MAC_CFG2_LEN_CHECK);
+
+ /* setup max frame length to zero */
+ ag71xx_wr(ag, AG71XX_REG_MAC_MFL, 0);
+
+ /* setup FIFO configuration registers */
+ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG0, FIFO_CFG0_INIT);
+ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG1, ag->fifodata[0]);
+ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG2, ag->fifodata[1]);
+ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG4, FIFO_CFG4_INIT);
+ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, FIFO_CFG5_INIT);
+}
+
+static unsigned int ag71xx_max_frame_len(unsigned int mtu)
+{
+ return ETH_SWITCH_HEADER_LEN + ETH_HLEN + VLAN_HLEN + mtu + ETH_FCS_LEN;
+}
+
+static void ag71xx_hw_set_macaddr(struct ag71xx *ag, unsigned char *mac)
+{
+ u32 t;
+
+ t = (((u32)mac[5]) << 24) | (((u32)mac[4]) << 16)
+ | (((u32)mac[3]) << 8) | ((u32)mac[2]);
+
+ ag71xx_wr(ag, AG71XX_REG_MAC_ADDR1, t);
+
+ t = (((u32)mac[1]) << 24) | (((u32)mac[0]) << 16);
+ ag71xx_wr(ag, AG71XX_REG_MAC_ADDR2, t);
+}
+
+static void ag71xx_fast_reset(struct ag71xx *ag)
+{
+ struct net_device *dev = ag->ndev;
+ u32 rx_ds;
+ u32 mii_reg;
+
+ ag71xx_hw_stop(ag);
+
+ mii_reg = ag71xx_rr(ag, AG71XX_REG_MII_CFG);
+ rx_ds = ag71xx_rr(ag, AG71XX_REG_RX_DESC);
+
+ ag71xx_tx_packets(ag, true);
+
+ reset_control_assert(ag->mac_reset);
+ usleep_range(10, 20);
+ reset_control_deassert(ag->mac_reset);
+ usleep_range(10, 20);
+
+ ag71xx_dma_reset(ag);
+ ag71xx_hw_setup(ag);
+ ag->tx_ring.curr = 0;
+ ag->tx_ring.dirty = 0;
+ netdev_reset_queue(ag->ndev);
+
+ /* setup max frame length */
+ ag71xx_wr(ag, AG71XX_REG_MAC_MFL,
+ ag71xx_max_frame_len(ag->ndev->mtu));
+
+ ag71xx_wr(ag, AG71XX_REG_RX_DESC, rx_ds);
+ ag71xx_wr(ag, AG71XX_REG_TX_DESC, ag->tx_ring.descs_dma);
+ ag71xx_wr(ag, AG71XX_REG_MII_CFG, mii_reg);
+
+ ag71xx_hw_set_macaddr(ag, dev->dev_addr);
+}
+
+static void ag71xx_hw_start(struct ag71xx *ag)
+{
+ /* start RX engine */
+ ag71xx_wr(ag, AG71XX_REG_RX_CTRL, RX_CTRL_RXE);
+
+ /* enable interrupts */
+ ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, AG71XX_INT_INIT);
+
+ netif_wake_queue(ag->ndev);
+}
+
+static void ag71xx_link_adjust(struct ag71xx *ag, bool update)
+{
+ struct phy_device *phydev = ag->ndev->phydev;
+ u32 cfg2;
+ u32 ifctl;
+ u32 fifo5;
+
+ if (!phydev->link && update) {
+ ag71xx_hw_stop(ag);
+ return;
+ }
+
+ if (!ag71xx_is(ag, AR7100) && !ag71xx_is(ag, AR9130))
+ ag71xx_fast_reset(ag);
+
+ cfg2 = ag71xx_rr(ag, AG71XX_REG_MAC_CFG2);
+ cfg2 &= ~(MAC_CFG2_IF_1000 | MAC_CFG2_IF_10_100 | MAC_CFG2_FDX);
+ cfg2 |= (phydev->duplex) ? MAC_CFG2_FDX : 0;
+
+ ifctl = ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL);
+ ifctl &= ~(MAC_IFCTL_SPEED);
+
+ fifo5 = ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5);
+ fifo5 &= ~FIFO_CFG5_BM;
+
+ switch (phydev->speed) {
+ case SPEED_1000:
+ cfg2 |= MAC_CFG2_IF_1000;
+ fifo5 |= FIFO_CFG5_BM;
+ break;
+ case SPEED_100:
+ cfg2 |= MAC_CFG2_IF_10_100;
+ ifctl |= MAC_IFCTL_SPEED;
+ break;
+ case SPEED_10:
+ cfg2 |= MAC_CFG2_IF_10_100;
+ break;
+ default:
+ WARN(1, "not supported speed %i\n", phydev->speed);
+ return;
+ }
+
+ if (ag->tx_ring.desc_split) {
+ ag->fifodata[2] &= 0xffff;
+ ag->fifodata[2] |= ((2048 - ag->tx_ring.desc_split) / 4) << 16;
+ }
+
+ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, ag->fifodata[2]);
+
+ ag71xx_wr(ag, AG71XX_REG_MAC_CFG2, cfg2);
+ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, fifo5);
+ ag71xx_wr(ag, AG71XX_REG_MAC_IFCTL, ifctl);
+
+ ag71xx_hw_start(ag);
+
+ if (update)
+ phy_print_status(phydev);
+}
+
+static void ag71xx_phy_link_adjust(struct net_device *ndev)
+{
+ struct ag71xx *ag = netdev_priv(ndev);
+
+ ag71xx_link_adjust(ag, true);
+}
+
+static int ag71xx_phy_connect(struct ag71xx *ag)
+{
+ struct device_node *np = ag->pdev->dev.of_node;
+ struct net_device *ndev = ag->ndev;
+ struct device_node *phy_node;
+ struct phy_device *phydev;
+ int ret;
+
+ if (of_phy_is_fixed_link(np)) {
+ ret = of_phy_register_fixed_link(np);
+ if (ret < 0) {
+ netif_err(ag, probe, ndev, "Failed to register fixed PHY link: %d\n",
+ ret);
+ return ret;
+ }
+
+ phy_node = of_node_get(np);
+ } else {
+ phy_node = of_parse_phandle(np, "phy-handle", 0);
+ }
+
+ if (!phy_node) {
+ netif_err(ag, probe, ndev, "Could not find valid phy node\n");
+ return -ENODEV;
+ }
+
+ phydev = of_phy_connect(ag->ndev, phy_node, ag71xx_phy_link_adjust,
+ 0, ag->phy_if_mode);
+
+ of_node_put(phy_node);
+
+ if (!phydev) {
+ netif_err(ag, probe, ndev, "Could not connect to PHY device\n");
+ return -ENODEV;
+ }
+
+ phy_attached_info(phydev);
+
+ return 0;
+}
+
+static void ag71xx_ring_tx_clean(struct ag71xx *ag)
+{
+ struct ag71xx_ring *ring = &ag->tx_ring;
+ int ring_mask = BIT(ring->order) - 1;
+ u32 bytes_compl = 0, pkts_compl = 0;
+ struct net_device *ndev = ag->ndev;
+
+ while (ring->curr != ring->dirty) {
+ struct ag71xx_desc *desc;
+ u32 i = ring->dirty & ring_mask;
+
+ desc = ag71xx_ring_desc(ring, i);
+ if (!ag71xx_desc_empty(desc)) {
+ desc->ctrl = 0;
+ ndev->stats.tx_errors++;
+ }
+
+ if (ring->buf[i].tx.skb) {
+ bytes_compl += ring->buf[i].tx.len;
+ pkts_compl++;
+ dev_kfree_skb_any(ring->buf[i].tx.skb);
+ }
+ ring->buf[i].tx.skb = NULL;
+ ring->dirty++;
+ }
+
+ /* flush descriptors */
+ wmb();
+
+ netdev_completed_queue(ndev, pkts_compl, bytes_compl);
+}
+
+static void ag71xx_ring_tx_init(struct ag71xx *ag)
+{
+ struct ag71xx_ring *ring = &ag->tx_ring;
+ int ring_size = BIT(ring->order);
+ int ring_mask = ring_size - 1;
+ int i;
+
+ for (i = 0; i < ring_size; i++) {
+ struct ag71xx_desc *desc = ag71xx_ring_desc(ring, i);
+
+ desc->next = (u32)(ring->descs_dma +
+ AG71XX_DESC_SIZE * ((i + 1) & ring_mask));
+
+ desc->ctrl = DESC_EMPTY;
+ ring->buf[i].tx.skb = NULL;
+ }
+
+ /* flush descriptors */
+ wmb();
+
+ ring->curr = 0;
+ ring->dirty = 0;
+ netdev_reset_queue(ag->ndev);
+}
+
+static void ag71xx_ring_rx_clean(struct ag71xx *ag)
+{
+ struct ag71xx_ring *ring = &ag->rx_ring;
+ int ring_size = BIT(ring->order);
+ int i;
+
+ if (!ring->buf)
+ return;
+
+ for (i = 0; i < ring_size; i++)
+ if (ring->buf[i].rx.rx_buf) {
+ dma_unmap_single(&ag->pdev->dev,
+ ring->buf[i].rx.dma_addr,
+ ag->rx_buf_size, DMA_FROM_DEVICE);
+ skb_free_frag(ring->buf[i].rx.rx_buf);
+ }
+}
+
+static int ag71xx_buffer_size(struct ag71xx *ag)
+{
+ return ag->rx_buf_size +
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+}
+
+static bool ag71xx_fill_rx_buf(struct ag71xx *ag, struct ag71xx_buf *buf,
+ int offset,
+ void *(*alloc)(unsigned int size))
+{
+ struct ag71xx_ring *ring = &ag->rx_ring;
+ struct ag71xx_desc *desc;
+ void *data;
+
+ desc = ag71xx_ring_desc(ring, buf - &ring->buf[0]);
+
+ data = alloc(ag71xx_buffer_size(ag));
+ if (!data)
+ return false;
+
+ buf->rx.rx_buf = data;
+ buf->rx.dma_addr = dma_map_single(&ag->pdev->dev, data, ag->rx_buf_size,
+ DMA_FROM_DEVICE);
+ desc->data = (u32)buf->rx.dma_addr + offset;
+ return true;
+}
+
+static int ag71xx_ring_rx_init(struct ag71xx *ag)
+{
+ struct ag71xx_ring *ring = &ag->rx_ring;
+ struct net_device *ndev = ag->ndev;
+ int ring_mask = BIT(ring->order) - 1;
+ int ring_size = BIT(ring->order);
+ unsigned int i;
+ int ret;
+
+ ret = 0;
+ for (i = 0; i < ring_size; i++) {
+ struct ag71xx_desc *desc = ag71xx_ring_desc(ring, i);
+
+ desc->next = (u32)(ring->descs_dma +
+ AG71XX_DESC_SIZE * ((i + 1) & ring_mask));
+
+ netif_dbg(ag, rx_status, ndev, "RX desc at %p, next is %08x\n",
+ desc, desc->next);
+ }
+
+ for (i = 0; i < ring_size; i++) {
+ struct ag71xx_desc *desc = ag71xx_ring_desc(ring, i);
+
+ if (!ag71xx_fill_rx_buf(ag, &ring->buf[i], ag->rx_buf_offset,
+ netdev_alloc_frag)) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ desc->ctrl = DESC_EMPTY;
+ }
+
+ /* flush descriptors */
+ wmb();
+
+ ring->curr = 0;
+ ring->dirty = 0;
+
+ return ret;
+}
+
+static int ag71xx_ring_rx_refill(struct ag71xx *ag)
+{
+ struct ag71xx_ring *ring = &ag->rx_ring;
+ int ring_mask = BIT(ring->order) - 1;
+ int offset = ag->rx_buf_offset;
+ unsigned int count;
+
+ count = 0;
+ for (; ring->curr - ring->dirty > 0; ring->dirty++) {
+ struct ag71xx_desc *desc;
+ unsigned int i;
+
+ i = ring->dirty & ring_mask;
+ desc = ag71xx_ring_desc(ring, i);
+
+ if (!ring->buf[i].rx.rx_buf &&
+ !ag71xx_fill_rx_buf(ag, &ring->buf[i], offset,
+ napi_alloc_frag))
+ break;
+
+ desc->ctrl = DESC_EMPTY;
+ count++;
+ }
+
+ /* flush descriptors */
+ wmb();
+
+ netif_dbg(ag, rx_status, ag->ndev, "%u rx descriptors refilled\n",
+ count);
+
+ return count;
+}
+
+static int ag71xx_rings_init(struct ag71xx *ag)
+{
+ struct ag71xx_ring *tx = &ag->tx_ring;
+ struct ag71xx_ring *rx = &ag->rx_ring;
+ int ring_size, tx_size;
+
+ ring_size = BIT(tx->order) + BIT(rx->order);
+ tx_size = BIT(tx->order);
+
+ tx->buf = kcalloc(ring_size, sizeof(*tx->buf), GFP_KERNEL);
+ if (!tx->buf)
+ return -ENOMEM;
+
+ tx->descs_cpu = dma_alloc_coherent(&ag->pdev->dev,
+ ring_size * AG71XX_DESC_SIZE,
+ &tx->descs_dma, GFP_ATOMIC);
+ if (!tx->descs_cpu) {
+ kfree(tx->buf);
+ tx->buf = NULL;
+ return -ENOMEM;
+ }
+
+ rx->buf = &tx->buf[BIT(tx->order)];
+ rx->descs_cpu = ((void *)tx->descs_cpu) + tx_size * AG71XX_DESC_SIZE;
+ rx->descs_dma = tx->descs_dma + tx_size * AG71XX_DESC_SIZE;
+
+ ag71xx_ring_tx_init(ag);
+ return ag71xx_ring_rx_init(ag);
+}
+
+static void ag71xx_rings_free(struct ag71xx *ag)
+{
+ struct ag71xx_ring *tx = &ag->tx_ring;
+ struct ag71xx_ring *rx = &ag->rx_ring;
+ int ring_size;
+
+ ring_size = BIT(tx->order) + BIT(rx->order);
+
+ if (tx->descs_cpu)
+ dma_free_coherent(&ag->pdev->dev, ring_size * AG71XX_DESC_SIZE,
+ tx->descs_cpu, tx->descs_dma);
+
+ kfree(tx->buf);
+
+ tx->descs_cpu = NULL;
+ rx->descs_cpu = NULL;
+ tx->buf = NULL;
+ rx->buf = NULL;
+}
+
+static void ag71xx_rings_cleanup(struct ag71xx *ag)
+{
+ ag71xx_ring_rx_clean(ag);
+ ag71xx_ring_tx_clean(ag);
+ ag71xx_rings_free(ag);
+
+ netdev_reset_queue(ag->ndev);
+}
+
+static void ag71xx_hw_init(struct ag71xx *ag)
+{
+ ag71xx_hw_stop(ag);
+
+ ag71xx_sb(ag, AG71XX_REG_MAC_CFG1, MAC_CFG1_SR);
+ usleep_range(20, 30);
+
+ reset_control_assert(ag->mac_reset);
+ msleep(100);
+ reset_control_deassert(ag->mac_reset);
+ msleep(200);
+
+ ag71xx_hw_setup(ag);
+
+ ag71xx_dma_reset(ag);
+}
+
+static int ag71xx_hw_enable(struct ag71xx *ag)
+{
+ int ret;
+
+ ret = ag71xx_rings_init(ag);
+ if (ret)
+ return ret;
+
+ napi_enable(&ag->napi);
+ ag71xx_wr(ag, AG71XX_REG_TX_DESC, ag->tx_ring.descs_dma);
+ ag71xx_wr(ag, AG71XX_REG_RX_DESC, ag->rx_ring.descs_dma);
+ netif_start_queue(ag->ndev);
+
+ return 0;
+}
+
+static void ag71xx_hw_disable(struct ag71xx *ag)
+{
+ netif_stop_queue(ag->ndev);
+
+ ag71xx_hw_stop(ag);
+ ag71xx_dma_reset(ag);
+
+ napi_disable(&ag->napi);
+ del_timer_sync(&ag->oom_timer);
+
+ ag71xx_rings_cleanup(ag);
+}
+
+static int ag71xx_open(struct net_device *ndev)
+{
+ struct ag71xx *ag = netdev_priv(ndev);
+ unsigned int max_frame_len;
+ int ret;
+
+ max_frame_len = ag71xx_max_frame_len(ndev->mtu);
+ ag->rx_buf_size =
+ SKB_DATA_ALIGN(max_frame_len + NET_SKB_PAD + NET_IP_ALIGN);
+
+ /* setup max frame length */
+ ag71xx_wr(ag, AG71XX_REG_MAC_MFL, max_frame_len);
+ ag71xx_hw_set_macaddr(ag, ndev->dev_addr);
+
+ ret = ag71xx_hw_enable(ag);
+ if (ret)
+ goto err;
+
+ ret = ag71xx_phy_connect(ag);
+ if (ret)
+ goto err;
+
+ phy_start(ndev->phydev);
+
+ return 0;
+
+err:
+ ag71xx_rings_cleanup(ag);
+ return ret;
+}
+
+static int ag71xx_stop(struct net_device *ndev)
+{
+ struct ag71xx *ag = netdev_priv(ndev);
+
+ phy_stop(ndev->phydev);
+ phy_disconnect(ndev->phydev);
+ ag71xx_hw_disable(ag);
+
+ return 0;
+}
+
+static int ag71xx_fill_dma_desc(struct ag71xx_ring *ring, u32 addr, int len)
+{
+ int i, ring_mask, ndesc, split;
+ struct ag71xx_desc *desc;
+
+ ring_mask = BIT(ring->order) - 1;
+ ndesc = 0;
+ split = ring->desc_split;
+
+ if (!split)
+ split = len;
+
+ while (len > 0) {
+ unsigned int cur_len = len;
+
+ i = (ring->curr + ndesc) & ring_mask;
+ desc = ag71xx_ring_desc(ring, i);
+
+ if (!ag71xx_desc_empty(desc))
+ return -1;
+
+ if (cur_len > split) {
+ cur_len = split;
+
+ /* TX will hang if DMA transfers <= 4 bytes,
+ * make sure next segment is more than 4 bytes long.
+ */
+ if (len <= split + 4)
+ cur_len -= 4;
+ }
+
+ desc->data = addr;
+ addr += cur_len;
+ len -= cur_len;
+
+ if (len > 0)
+ cur_len |= DESC_MORE;
+
+ /* prevent early tx attempt of this descriptor */
+ if (!ndesc)
+ cur_len |= DESC_EMPTY;
+
+ desc->ctrl = cur_len;
+ ndesc++;
+ }
+
+ return ndesc;
+}
+
+static netdev_tx_t ag71xx_hard_start_xmit(struct sk_buff *skb,
+ struct net_device *ndev)
+{
+ int i, n, ring_min, ring_mask, ring_size;
+ struct ag71xx *ag = netdev_priv(ndev);
+ struct ag71xx_ring *ring;
+ struct ag71xx_desc *desc;
+ dma_addr_t dma_addr;
+
+ ring = &ag->tx_ring;
+ ring_mask = BIT(ring->order) - 1;
+ ring_size = BIT(ring->order);
+
+ if (skb->len <= 4) {
+ netif_dbg(ag, tx_err, ndev, "packet len is too small\n");
+ goto err_drop;
+ }
+
+ dma_addr = dma_map_single(&ag->pdev->dev, skb->data, skb->len,
+ DMA_TO_DEVICE);
+
+ i = ring->curr & ring_mask;
+ desc = ag71xx_ring_desc(ring, i);
+
+ /* setup descriptor fields */
+ n = ag71xx_fill_dma_desc(ring, (u32)dma_addr,
+ skb->len & ag->dcfg->desc_pktlen_mask);
+ if (n < 0)
+ goto err_drop_unmap;
+
+ i = (ring->curr + n - 1) & ring_mask;
+ ring->buf[i].tx.len = skb->len;
+ ring->buf[i].tx.skb = skb;
+
+ netdev_sent_queue(ndev, skb->len);
+
+ skb_tx_timestamp(skb);
+
+ desc->ctrl &= ~DESC_EMPTY;
+ ring->curr += n;
+
+ /* flush descriptor */
+ wmb();
+
+ ring_min = 2;
+ if (ring->desc_split)
+ ring_min *= AG71XX_TX_RING_DS_PER_PKT;
+
+ if (ring->curr - ring->dirty >= ring_size - ring_min) {
+ netif_dbg(ag, tx_err, ndev, "tx queue full\n");
+ netif_stop_queue(ndev);
+ }
+
+ netif_dbg(ag, tx_queued, ndev, "packet injected into TX queue\n");
+
+ /* enable TX engine */
+ ag71xx_wr(ag, AG71XX_REG_TX_CTRL, TX_CTRL_TXE);
+
+ return NETDEV_TX_OK;
+
+err_drop_unmap:
+ dma_unmap_single(&ag->pdev->dev, dma_addr, skb->len, DMA_TO_DEVICE);
+
+err_drop:
+ ndev->stats.tx_dropped++;
+
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+}
+
+static int ag71xx_do_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
+{
+ if (!ndev->phydev)
+ return -EINVAL;
+
+ return phy_mii_ioctl(ndev->phydev, ifr, cmd);
+}
+
+static void ag71xx_oom_timer_handler(struct timer_list *t)
+{
+ struct ag71xx *ag = from_timer(ag, t, oom_timer);
+
+ napi_schedule(&ag->napi);
+}
+
+static void ag71xx_tx_timeout(struct net_device *ndev)
+{
+ struct ag71xx *ag = netdev_priv(ndev);
+
+ netif_err(ag, tx_err, ndev, "tx timeout\n");
+
+ schedule_delayed_work(&ag->restart_work, 1);
+}
+
+static void ag71xx_restart_work_func(struct work_struct *work)
+{
+ struct ag71xx *ag = container_of(work, struct ag71xx,
+ restart_work.work);
+ struct net_device *ndev = ag->ndev;
+
+ rtnl_lock();
+ ag71xx_hw_disable(ag);
+ ag71xx_hw_enable(ag);
+ if (ndev->phydev->link)
+ ag71xx_link_adjust(ag, false);
+ rtnl_unlock();
+}
+
+static int ag71xx_rx_packets(struct ag71xx *ag, int limit)
+{
+ struct net_device *ndev = ag->ndev;
+ int ring_mask, ring_size, done = 0;
+ unsigned int pktlen_mask, offset;
+ struct sk_buff *next, *skb;
+ struct ag71xx_ring *ring;
+ struct list_head rx_list;
+
+ ring = &ag->rx_ring;
+ pktlen_mask = ag->dcfg->desc_pktlen_mask;
+ offset = ag->rx_buf_offset;
+ ring_mask = BIT(ring->order) - 1;
+ ring_size = BIT(ring->order);
+
+ netif_dbg(ag, rx_status, ndev, "rx packets, limit=%d, curr=%u, dirty=%u\n",
+ limit, ring->curr, ring->dirty);
+
+ INIT_LIST_HEAD(&rx_list);
+
+ while (done < limit) {
+ unsigned int i = ring->curr & ring_mask;
+ struct ag71xx_desc *desc = ag71xx_ring_desc(ring, i);
+ int pktlen;
+ int err = 0;
+
+ if (ag71xx_desc_empty(desc))
+ break;
+
+ if ((ring->dirty + ring_size) == ring->curr) {
+ WARN_ONCE(1, "RX out of ring");
+ break;
+ }
+
+ ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_PR);
+
+ pktlen = desc->ctrl & pktlen_mask;
+ pktlen -= ETH_FCS_LEN;
+
+ dma_unmap_single(&ag->pdev->dev, ring->buf[i].rx.dma_addr,
+ ag->rx_buf_size, DMA_FROM_DEVICE);
+
+ ndev->stats.rx_packets++;
+ ndev->stats.rx_bytes += pktlen;
+
+ skb = build_skb(ring->buf[i].rx.rx_buf, ag71xx_buffer_size(ag));
+ if (!skb) {
+ skb_free_frag(ring->buf[i].rx.rx_buf);
+ goto next;
+ }
+
+ skb_reserve(skb, offset);
+ skb_put(skb, pktlen);
+
+ if (err) {
+ ndev->stats.rx_dropped++;
+ kfree_skb(skb);
+ } else {
+ skb->dev = ndev;
+ skb->ip_summed = CHECKSUM_NONE;
+ list_add_tail(&skb->list, &rx_list);
+ }
+
+next:
+ ring->buf[i].rx.rx_buf = NULL;
+ done++;
+
+ ring->curr++;
+ }
+
+ ag71xx_ring_rx_refill(ag);
+
+ list_for_each_entry_safe(skb, next, &rx_list, list)
+ skb->protocol = eth_type_trans(skb, ndev);
+ netif_receive_skb_list(&rx_list);
+
+ netif_dbg(ag, rx_status, ndev, "rx finish, curr=%u, dirty=%u, done=%d\n",
+ ring->curr, ring->dirty, done);
+
+ return done;
+}
+
+static int ag71xx_poll(struct napi_struct *napi, int limit)
+{
+ struct ag71xx *ag = container_of(napi, struct ag71xx, napi);
+ struct ag71xx_ring *rx_ring = &ag->rx_ring;
+ int rx_ring_size = BIT(rx_ring->order);
+ struct net_device *ndev = ag->ndev;
+ int tx_done, rx_done;
+ u32 status;
+
+ tx_done = ag71xx_tx_packets(ag, false);
+
+ netif_dbg(ag, rx_status, ndev, "processing RX ring\n");
+ rx_done = ag71xx_rx_packets(ag, limit);
+
+ if (!rx_ring->buf[rx_ring->dirty % rx_ring_size].rx.rx_buf)
+ goto oom;
+
+ status = ag71xx_rr(ag, AG71XX_REG_RX_STATUS);
+ if (unlikely(status & RX_STATUS_OF)) {
+ ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_OF);
+ ndev->stats.rx_fifo_errors++;
+
+ /* restart RX */
+ ag71xx_wr(ag, AG71XX_REG_RX_CTRL, RX_CTRL_RXE);
+ }
+
+ if (rx_done < limit) {
+ if (status & RX_STATUS_PR)
+ goto more;
+
+ status = ag71xx_rr(ag, AG71XX_REG_TX_STATUS);
+ if (status & TX_STATUS_PS)
+ goto more;
+
+ netif_dbg(ag, rx_status, ndev, "disable polling mode, rx=%d, tx=%d,limit=%d\n",
+ rx_done, tx_done, limit);
+
+ napi_complete(napi);
+
+ /* enable interrupts */
+ ag71xx_int_enable(ag, AG71XX_INT_POLL);
+ return rx_done;
+ }
+
+more:
+ netif_dbg(ag, rx_status, ndev, "stay in polling mode, rx=%d, tx=%d, limit=%d\n",
+ rx_done, tx_done, limit);
+ return limit;
+
+oom:
+ netif_err(ag, rx_err, ndev, "out of memory\n");
+
+ mod_timer(&ag->oom_timer, jiffies + AG71XX_OOM_REFILL);
+ napi_complete(napi);
+ return 0;
+}
+
+static irqreturn_t ag71xx_interrupt(int irq, void *dev_id)
+{
+ struct net_device *ndev = dev_id;
+ struct ag71xx *ag;
+ u32 status;
+
+ ag = netdev_priv(ndev);
+ status = ag71xx_rr(ag, AG71XX_REG_INT_STATUS);
+
+ if (unlikely(!status))
+ return IRQ_NONE;
+
+ if (unlikely(status & AG71XX_INT_ERR)) {
+ if (status & AG71XX_INT_TX_BE) {
+ ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_BE);
+ netif_err(ag, intr, ndev, "TX BUS error\n");
+ }
+ if (status & AG71XX_INT_RX_BE) {
+ ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_BE);
+ netif_err(ag, intr, ndev, "RX BUS error\n");
+ }
+ }
+
+ if (likely(status & AG71XX_INT_POLL)) {
+ ag71xx_int_disable(ag, AG71XX_INT_POLL);
+ netif_dbg(ag, intr, ndev, "enable polling mode\n");
+ napi_schedule(&ag->napi);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int ag71xx_change_mtu(struct net_device *ndev, int new_mtu)
+{
+ struct ag71xx *ag = netdev_priv(ndev);
+
+ ndev->mtu = new_mtu;
+ ag71xx_wr(ag, AG71XX_REG_MAC_MFL,
+ ag71xx_max_frame_len(ndev->mtu));
+
+ return 0;
+}
+
+static const struct net_device_ops ag71xx_netdev_ops = {
+ .ndo_open = ag71xx_open,
+ .ndo_stop = ag71xx_stop,
+ .ndo_start_xmit = ag71xx_hard_start_xmit,
+ .ndo_do_ioctl = ag71xx_do_ioctl,
+ .ndo_tx_timeout = ag71xx_tx_timeout,
+ .ndo_change_mtu = ag71xx_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
+static const u32 ar71xx_addr_ar7100[] = {
+ 0x19000000, 0x1a000000,
+};
+
+static int ag71xx_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ const struct ag71xx_dcfg *dcfg;
+ struct net_device *ndev;
+ struct resource *res;
+ const void *mac_addr;
+ int tx_size, err, i;
+ struct ag71xx *ag;
+
+ if (!np)
+ return -ENODEV;
+
+ ndev = devm_alloc_etherdev(&pdev->dev, sizeof(*ag));
+ if (!ndev)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EINVAL;
+
+ dcfg = of_device_get_match_data(&pdev->dev);
+ if (!dcfg)
+ return -EINVAL;
+
+ ag = netdev_priv(ndev);
+ ag->mac_idx = -1;
+ for (i = 0; i < ARRAY_SIZE(ar71xx_addr_ar7100); i++) {
+ if (ar71xx_addr_ar7100[i] == res->start)
+ ag->mac_idx = i;
+ }
+
+ if (ag->mac_idx < 0) {
+ netif_err(ag, probe, ndev, "unknown mac idx\n");
+ return -EINVAL;
+ }
+
+ ag->clk_eth = devm_clk_get(&pdev->dev, "eth");
+ if (IS_ERR(ag->clk_eth)) {
+ netif_err(ag, probe, ndev, "Failed to get eth clk.\n");
+ return PTR_ERR(ag->clk_eth);
+ }
+
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+
+ ag->pdev = pdev;
+ ag->ndev = ndev;
+ ag->dcfg = dcfg;
+ ag->msg_enable = netif_msg_init(-1, AG71XX_DEFAULT_MSG_ENABLE);
+ memcpy(ag->fifodata, dcfg->fifodata, sizeof(ag->fifodata));
+
+ ag->mac_reset = devm_reset_control_get(&pdev->dev, "mac");
+ if (IS_ERR(ag->mac_reset)) {
+ netif_err(ag, probe, ndev, "missing mac reset\n");
+ err = PTR_ERR(ag->mac_reset);
+ goto err_free;
+ }
+
+ ag->mac_base = devm_ioremap_nocache(&pdev->dev, res->start,
+ res->end - res->start + 1);
+ if (!ag->mac_base) {
+ err = -ENOMEM;
+ goto err_free;
+ }
+
+ ndev->irq = platform_get_irq(pdev, 0);
+ err = devm_request_irq(&pdev->dev, ndev->irq, ag71xx_interrupt,
+ 0x0, dev_name(&pdev->dev), ndev);
+ if (err) {
+ netif_err(ag, probe, ndev, "unable to request IRQ %d\n",
+ ndev->irq);
+ goto err_free;
+ }
+
+ ndev->netdev_ops = &ag71xx_netdev_ops;
+
+ INIT_DELAYED_WORK(&ag->restart_work, ag71xx_restart_work_func);
+ timer_setup(&ag->oom_timer, ag71xx_oom_timer_handler, 0);
+
+ tx_size = AG71XX_TX_RING_SIZE_DEFAULT;
+ ag->rx_ring.order = ag71xx_ring_size_order(AG71XX_RX_RING_SIZE_DEFAULT);
+
+ ndev->min_mtu = 68;
+ ndev->max_mtu = dcfg->max_frame_len - ag71xx_max_frame_len(0);
+
+ ag->rx_buf_offset = NET_SKB_PAD;
+ if (!ag71xx_is(ag, AR7100) && !ag71xx_is(ag, AR9130))
+ ag->rx_buf_offset += NET_IP_ALIGN;
+
+ if (ag71xx_is(ag, AR7100)) {
+ ag->tx_ring.desc_split = AG71XX_TX_RING_SPLIT;
+ tx_size *= AG71XX_TX_RING_DS_PER_PKT;
+ }
+ ag->tx_ring.order = ag71xx_ring_size_order(tx_size);
+
+ ag->stop_desc = dmam_alloc_coherent(&pdev->dev,
+ sizeof(struct ag71xx_desc),
+ &ag->stop_desc_dma, GFP_KERNEL);
+ if (!ag->stop_desc) {
+ err = -ENOMEM;
+ goto err_free;
+ }
+
+ ag->stop_desc->data = 0;
+ ag->stop_desc->ctrl = 0;
+ ag->stop_desc->next = (u32)ag->stop_desc_dma;
+
+ mac_addr = of_get_mac_address(np);
+ if (!IS_ERR(mac_addr))
+ memcpy(ndev->dev_addr, mac_addr, ETH_ALEN);
+ if (IS_ERR(mac_addr) || !is_valid_ether_addr(ndev->dev_addr)) {
+ netif_err(ag, probe, ndev, "invalid MAC address, using random address\n");
+ eth_random_addr(ndev->dev_addr);
+ }
+
+ ag->phy_if_mode = of_get_phy_mode(np);
+ if (ag->phy_if_mode < 0) {
+ netif_err(ag, probe, ndev, "missing phy-mode property in DT\n");
+ err = ag->phy_if_mode;
+ goto err_free;
+ }
+
+ netif_napi_add(ndev, &ag->napi, ag71xx_poll, AG71XX_NAPI_WEIGHT);
+
+ err = clk_prepare_enable(ag->clk_eth);
+ if (err) {
+ netif_err(ag, probe, ndev, "Failed to enable eth clk.\n");
+ goto err_free;
+ }
+
+ ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, 0);
+
+ ag71xx_hw_init(ag);
+
+ err = ag71xx_mdio_probe(ag);
+ if (err)
+ goto err_put_clk;
+
+ platform_set_drvdata(pdev, ndev);
+
+ err = register_netdev(ndev);
+ if (err) {
+ netif_err(ag, probe, ndev, "unable to register net device\n");
+ platform_set_drvdata(pdev, NULL);
+ goto err_mdio_remove;
+ }
+
+ netif_info(ag, probe, ndev, "Atheros AG71xx at 0x%08lx, irq %d, mode:%s\n",
+ (unsigned long)ag->mac_base, ndev->irq,
+ phy_modes(ag->phy_if_mode));
+
+ return 0;
+
+err_mdio_remove:
+ ag71xx_mdio_remove(ag);
+err_put_clk:
+ clk_disable_unprepare(ag->clk_eth);
+err_free:
+ free_netdev(ndev);
+ return err;
+}
+
+static int ag71xx_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct ag71xx *ag;
+
+ if (!ndev)
+ return 0;
+
+ ag = netdev_priv(ndev);
+ unregister_netdev(ndev);
+ ag71xx_mdio_remove(ag);
+ clk_disable_unprepare(ag->clk_eth);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static const u32 ar71xx_fifo_ar7100[] = {
+ 0x0fff0000, 0x00001fff, 0x00780fff,
+};
+
+static const u32 ar71xx_fifo_ar9130[] = {
+ 0x0fff0000, 0x00001fff, 0x008001ff,
+};
+
+static const u32 ar71xx_fifo_ar9330[] = {
+ 0x0010ffff, 0x015500aa, 0x01f00140,
+};
+
+static const struct ag71xx_dcfg ag71xx_dcfg_ar7100 = {
+ .type = AR7100,
+ .fifodata = ar71xx_fifo_ar7100,
+ .max_frame_len = 1540,
+ .desc_pktlen_mask = SZ_4K - 1,
+ .tx_hang_workaround = false,
+};
+
+static const struct ag71xx_dcfg ag71xx_dcfg_ar7240 = {
+ .type = AR7240,
+ .fifodata = ar71xx_fifo_ar7100,
+ .max_frame_len = 1540,
+ .desc_pktlen_mask = SZ_4K - 1,
+ .tx_hang_workaround = true,
+};
+
+static const struct ag71xx_dcfg ag71xx_dcfg_ar9130 = {
+ .type = AR9130,
+ .fifodata = ar71xx_fifo_ar9130,
+ .max_frame_len = 1540,
+ .desc_pktlen_mask = SZ_4K - 1,
+ .tx_hang_workaround = false,
+};
+
+static const struct ag71xx_dcfg ag71xx_dcfg_ar9330 = {
+ .type = AR9330,
+ .fifodata = ar71xx_fifo_ar9330,
+ .max_frame_len = 1540,
+ .desc_pktlen_mask = SZ_4K - 1,
+ .tx_hang_workaround = true,
+};
+
+static const struct ag71xx_dcfg ag71xx_dcfg_ar9340 = {
+ .type = AR9340,
+ .fifodata = ar71xx_fifo_ar9330,
+ .max_frame_len = SZ_16K - 1,
+ .desc_pktlen_mask = SZ_16K - 1,
+ .tx_hang_workaround = true,
+};
+
+static const struct ag71xx_dcfg ag71xx_dcfg_qca9530 = {
+ .type = QCA9530,
+ .fifodata = ar71xx_fifo_ar9330,
+ .max_frame_len = SZ_16K - 1,
+ .desc_pktlen_mask = SZ_16K - 1,
+ .tx_hang_workaround = true,
+};
+
+static const struct ag71xx_dcfg ag71xx_dcfg_qca9550 = {
+ .type = QCA9550,
+ .fifodata = ar71xx_fifo_ar9330,
+ .max_frame_len = 1540,
+ .desc_pktlen_mask = SZ_16K - 1,
+ .tx_hang_workaround = true,
+};
+
+static const struct of_device_id ag71xx_match[] = {
+ { .compatible = "qca,ar7100-eth", .data = &ag71xx_dcfg_ar7100 },
+ { .compatible = "qca,ar7240-eth", .data = &ag71xx_dcfg_ar7240 },
+ { .compatible = "qca,ar7241-eth", .data = &ag71xx_dcfg_ar7240 },
+ { .compatible = "qca,ar7242-eth", .data = &ag71xx_dcfg_ar7240 },
+ { .compatible = "qca,ar9130-eth", .data = &ag71xx_dcfg_ar9130 },
+ { .compatible = "qca,ar9330-eth", .data = &ag71xx_dcfg_ar9330 },
+ { .compatible = "qca,ar9340-eth", .data = &ag71xx_dcfg_ar9340 },
+ { .compatible = "qca,qca9530-eth", .data = &ag71xx_dcfg_qca9530 },
+ { .compatible = "qca,qca9550-eth", .data = &ag71xx_dcfg_qca9550 },
+ { .compatible = "qca,qca9560-eth", .data = &ag71xx_dcfg_qca9550 },
+ {}
+};
+
+static struct platform_driver ag71xx_driver = {
+ .probe = ag71xx_probe,
+ .remove = ag71xx_remove,
+ .driver = {
+ .name = "ag71xx",
+ .of_match_table = ag71xx_match,
+ }
+};
+
+module_platform_driver(ag71xx_driver);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
index 25bf085324b8..be7f9cebb675 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
@@ -2201,7 +2201,7 @@ static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb,
struct net_device *netdev)
{
struct atl1c_adapter *adapter = netdev_priv(netdev);
- u16 tpd_req = 1;
+ u16 tpd_req;
struct atl1c_tpd_desc *tpd;
enum atl1c_trans_queue type = atl1c_trans_normal;
diff --git a/drivers/net/ethernet/atheros/atlx/atl1.c b/drivers/net/ethernet/atheros/atlx/atl1.c
index 7c767ce9aafa..b5c6dc914720 100644
--- a/drivers/net/ethernet/atheros/atlx/atl1.c
+++ b/drivers/net/ethernet/atheros/atlx/atl1.c
@@ -1060,8 +1060,6 @@ static s32 atl1_setup_ring_resources(struct atl1_adapter *adapter)
goto err_nomem;
}
- memset(ring_header->desc, 0, ring_header->size);
-
/* init TPD ring */
tpd_ring->dma = ring_header->dma;
offset = (tpd_ring->dma & 0x7) ? (8 - (ring_header->dma & 0x7)) : 0;
diff --git a/drivers/net/ethernet/atheros/atlx/atl2.c b/drivers/net/ethernet/atheros/atlx/atl2.c
index 3a3fb5ce0fee..3aba38322717 100644
--- a/drivers/net/ethernet/atheros/atlx/atl2.c
+++ b/drivers/net/ethernet/atheros/atlx/atl2.c
@@ -291,7 +291,6 @@ static s32 atl2_setup_ring_resources(struct atl2_adapter *adapter)
&adapter->ring_dma);
if (!adapter->ring_vir_addr)
return -ENOMEM;
- memset(adapter->ring_vir_addr, 0, adapter->ring_size);
/* Init TXD Ring */
adapter->txd_dma = adapter->ring_dma ;
diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig
index b123509d385f..e9017caf024d 100644
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -8,6 +8,7 @@ config NET_VENDOR_BROADCOM
default y
depends on (SSB_POSSIBLE && HAS_DMA) || PCI || BCM63XX || \
SIBYTE_SB1xxx_SOC
+ select DIMLIB
---help---
If you have a network (Ethernet) chipset belonging to this class,
say Y.
@@ -198,6 +199,7 @@ config BNXT
select FW_LOADER
select LIBCRC32C
select NET_DEVLINK
+ select PAGE_POOL
---help---
This driver supports Broadcom NetXtreme-C/E 10/25/40/50 gigabit
Ethernet cards. To compile this driver as a module, choose M here:
diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c
index 85e610210477..291e4afd4a1a 100644
--- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c
@@ -2659,7 +2659,6 @@ static int bcm_enetsw_probe(struct platform_device *pdev)
if (!dev)
return -ENOMEM;
priv = netdev_priv(dev);
- memset(priv, 0, sizeof(*priv));
/* initialize default and fetch platform data */
priv->enet_is_sw = true;
diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c
index c623896e3ccb..b9c5cea8db16 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.c
+++ b/drivers/net/ethernet/broadcom/bcmsysport.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Broadcom BCM7xxx System Port Ethernet MAC driver
*
* Copyright (C) 2014 Broadcom Corporation
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -612,7 +609,7 @@ static int bcm_sysport_set_coalesce(struct net_device *dev,
struct ethtool_coalesce *ec)
{
struct bcm_sysport_priv *priv = netdev_priv(dev);
- struct net_dim_cq_moder moder;
+ struct dim_cq_moder moder;
u32 usecs, pkts;
unsigned int i;
@@ -995,7 +992,7 @@ static int bcm_sysport_poll(struct napi_struct *napi, int budget)
{
struct bcm_sysport_priv *priv =
container_of(napi, struct bcm_sysport_priv, napi);
- struct net_dim_sample dim_sample;
+ struct dim_sample dim_sample;
unsigned int work_done = 0;
work_done = bcm_sysport_desc_rx(priv, budget);
@@ -1019,8 +1016,8 @@ static int bcm_sysport_poll(struct napi_struct *napi, int budget)
}
if (priv->dim.use_dim) {
- net_dim_sample(priv->dim.event_ctr, priv->dim.packets,
- priv->dim.bytes, &dim_sample);
+ dim_update_sample(priv->dim.event_ctr, priv->dim.packets,
+ priv->dim.bytes, &dim_sample);
net_dim(&priv->dim.dim, dim_sample);
}
@@ -1090,16 +1087,16 @@ static void bcm_sysport_resume_from_wol(struct bcm_sysport_priv *priv)
static void bcm_sysport_dim_work(struct work_struct *work)
{
- struct net_dim *dim = container_of(work, struct net_dim, work);
+ struct dim *dim = container_of(work, struct dim, work);
struct bcm_sysport_net_dim *ndim =
container_of(dim, struct bcm_sysport_net_dim, dim);
struct bcm_sysport_priv *priv =
container_of(ndim, struct bcm_sysport_priv, dim);
- struct net_dim_cq_moder cur_profile =
- net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
+ struct dim_cq_moder cur_profile = net_dim_get_rx_moderation(dim->mode,
+ dim->profile_ix);
bcm_sysport_set_rx_coalesce(priv, cur_profile.usec, cur_profile.pkts);
- dim->state = NET_DIM_START_MEASURE;
+ dim->state = DIM_START_MEASURE;
}
/* RX and misc interrupt routine */
@@ -1440,7 +1437,7 @@ static void bcm_sysport_init_dim(struct bcm_sysport_priv *priv,
struct bcm_sysport_net_dim *dim = &priv->dim;
INIT_WORK(&dim->dim.work, cb);
- dim->dim.mode = NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE;
+ dim->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
dim->event_ctr = 0;
dim->packets = 0;
dim->bytes = 0;
@@ -1449,7 +1446,7 @@ static void bcm_sysport_init_dim(struct bcm_sysport_priv *priv,
static void bcm_sysport_init_rx_coalesce(struct bcm_sysport_priv *priv)
{
struct bcm_sysport_net_dim *dim = &priv->dim;
- struct net_dim_cq_moder moder;
+ struct dim_cq_moder moder;
u32 usecs, pkts;
usecs = priv->rx_coalesce_usecs;
diff --git a/drivers/net/ethernet/broadcom/bcmsysport.h b/drivers/net/ethernet/broadcom/bcmsysport.h
index 6f3141c86436..6d80735fbc7f 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.h
+++ b/drivers/net/ethernet/broadcom/bcmsysport.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Broadcom BCM7xxx System Port Ethernet MAC driver
*
* Copyright (C) 2014 Broadcom Corporation
- *
- * 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.
*/
#ifndef __BCM_SYSPORT_H
@@ -14,7 +11,7 @@
#include <linux/bitmap.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
-#include <linux/net_dim.h>
+#include <linux/dim.h>
/* Receive/transmit descriptor format */
#define DESC_ADDR_HI_STATUS_LEN 0x00
@@ -705,7 +702,7 @@ struct bcm_sysport_net_dim {
u16 event_ctr;
unsigned long packets;
unsigned long bytes;
- struct net_dim dim;
+ struct dim dim;
};
/* Software view of the TX ring */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index 008ad0ca89ba..656ed80647f0 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -684,7 +684,7 @@ static void *bnx2x_frag_alloc(const struct bnx2x_fastpath *fp, gfp_t gfp_mask)
if (unlikely(gfpflags_allow_blocking(gfp_mask)))
return (void *)__get_free_page(gfp_mask);
- return netdev_alloc_frag(fp->rx_frag_size);
+ return napi_alloc_frag(fp->rx_frag_size);
}
return kmalloc(fp->rx_buf_size + NET_SKB_PAD, gfp_mask);
@@ -3857,9 +3857,12 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
if (!(bp->flags & TX_TIMESTAMPING_EN)) {
+ bp->eth_stats.ptp_skip_tx_ts++;
BNX2X_ERR("Tx timestamping was not enabled, this packet will not be timestamped\n");
} else if (bp->ptp_tx_skb) {
- BNX2X_ERR("The device supports only a single outstanding packet to timestamp, this packet will not be timestamped\n");
+ bp->eth_stats.ptp_skip_tx_ts++;
+ netdev_err_once(bp->dev,
+ "Device supports only a single outstanding packet to timestamp, this packet won't be timestamped\n");
} else {
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
/* schedule check for Tx timestamp */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
index 0745cccd416d..4a0ba6801c9e 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
@@ -182,7 +182,9 @@ static const struct {
{ STATS_OFFSET32(driver_filtered_tx_pkt),
4, false, "driver_filtered_tx_pkt" },
{ STATS_OFFSET32(eee_tx_lpi),
- 4, true, "Tx LPI entry count"}
+ 4, true, "Tx LPI entry count"},
+ { STATS_OFFSET32(ptp_skip_tx_ts),
+ 4, false, "ptp_skipped_tx_tstamp" },
};
#define BNX2X_NUM_STATS ARRAY_SIZE(bnx2x_stats_arr)
@@ -1609,7 +1611,8 @@ static int bnx2x_get_module_info(struct net_device *dev,
}
if (!sff8472_comp ||
- (diag_type & SFP_EEPROM_DIAG_ADDR_CHANGE_REQ)) {
+ (diag_type & SFP_EEPROM_DIAG_ADDR_CHANGE_REQ) ||
+ !(diag_type & SFP_EEPROM_DDM_IMPLEMENTED)) {
modinfo->type = ETH_MODULE_SFF_8079;
modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
} else {
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
index b7d251108c19..7115f5025664 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
@@ -62,6 +62,7 @@
#define SFP_EEPROM_DIAG_TYPE_ADDR 0x5c
#define SFP_EEPROM_DIAG_TYPE_SIZE 1
#define SFP_EEPROM_DIAG_ADDR_CHANGE_REQ (1<<2)
+#define SFP_EEPROM_DDM_IMPLEMENTED (1<<6)
#define SFP_EEPROM_SFF_8472_COMP_ADDR 0x5e
#define SFP_EEPROM_SFF_8472_COMP_SIZE 1
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index 03ac10b1cd1e..2cc14db8f0ec 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -15214,11 +15214,24 @@ static void bnx2x_ptp_task(struct work_struct *work)
u32 val_seq;
u64 timestamp, ns;
struct skb_shared_hwtstamps shhwtstamps;
+ bool bail = true;
+ int i;
+
+ /* FW may take a while to complete timestamping; try a bit and if it's
+ * still not complete, may indicate an error state - bail out then.
+ */
+ for (i = 0; i < 10; i++) {
+ /* Read Tx timestamp registers */
+ val_seq = REG_RD(bp, port ? NIG_REG_P1_TLLH_PTP_BUF_SEQID :
+ NIG_REG_P0_TLLH_PTP_BUF_SEQID);
+ if (val_seq & 0x10000) {
+ bail = false;
+ break;
+ }
+ msleep(1 << i);
+ }
- /* Read Tx timestamp registers */
- val_seq = REG_RD(bp, port ? NIG_REG_P1_TLLH_PTP_BUF_SEQID :
- NIG_REG_P0_TLLH_PTP_BUF_SEQID);
- if (val_seq & 0x10000) {
+ if (!bail) {
/* There is a valid timestamp value */
timestamp = REG_RD(bp, port ? NIG_REG_P1_TLLH_PTP_BUF_TS_MSB :
NIG_REG_P0_TLLH_PTP_BUF_TS_MSB);
@@ -15233,16 +15246,18 @@ static void bnx2x_ptp_task(struct work_struct *work)
memset(&shhwtstamps, 0, sizeof(shhwtstamps));
shhwtstamps.hwtstamp = ns_to_ktime(ns);
skb_tstamp_tx(bp->ptp_tx_skb, &shhwtstamps);
- dev_kfree_skb_any(bp->ptp_tx_skb);
- bp->ptp_tx_skb = NULL;
DP(BNX2X_MSG_PTP, "Tx timestamp, timestamp cycles = %llu, ns = %llu\n",
timestamp, ns);
} else {
- DP(BNX2X_MSG_PTP, "There is no valid Tx timestamp yet\n");
- /* Reschedule to keep checking for a valid timestamp value */
- schedule_work(&bp->ptp_task);
+ DP(BNX2X_MSG_PTP,
+ "Tx timestamp is not recorded (register read=%u)\n",
+ val_seq);
+ bp->eth_stats.ptp_skip_tx_ts++;
}
+
+ dev_kfree_skb_any(bp->ptp_tx_skb);
+ bp->ptp_tx_skb = NULL;
}
void bnx2x_set_rx_ts(struct bnx2x *bp, struct sk_buff *skb)
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
index b2644ed13d06..d55e63692cf3 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
@@ -207,6 +207,9 @@ struct bnx2x_eth_stats {
u32 driver_filtered_tx_pkt;
/* src: Clear-on-Read register; Will not survive PMF Migration */
u32 eee_tx_lpi;
+
+ /* PTP */
+ u32 ptp_skip_tx_ts;
};
struct bnx2x_eth_q_stats {
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index f758b2e0591f..7134d2c3eb1c 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -54,6 +54,7 @@
#include <net/pkt_cls.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
+#include <net/page_pool.h>
#include "bnxt_hsi.h"
#include "bnxt.h"
@@ -668,19 +669,20 @@ next_tx_int:
}
static struct page *__bnxt_alloc_rx_page(struct bnxt *bp, dma_addr_t *mapping,
+ struct bnxt_rx_ring_info *rxr,
gfp_t gfp)
{
struct device *dev = &bp->pdev->dev;
struct page *page;
- page = alloc_page(gfp);
+ page = page_pool_dev_alloc_pages(rxr->page_pool);
if (!page)
return NULL;
*mapping = dma_map_page_attrs(dev, page, 0, PAGE_SIZE, bp->rx_dir,
DMA_ATTR_WEAK_ORDERING);
if (dma_mapping_error(dev, *mapping)) {
- __free_page(page);
+ page_pool_recycle_direct(rxr->page_pool, page);
return NULL;
}
*mapping += bp->rx_dma_offset;
@@ -716,7 +718,8 @@ int bnxt_alloc_rx_data(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
dma_addr_t mapping;
if (BNXT_RX_PAGE_MODE(bp)) {
- struct page *page = __bnxt_alloc_rx_page(bp, &mapping, gfp);
+ struct page *page =
+ __bnxt_alloc_rx_page(bp, &mapping, rxr, gfp);
if (!page)
return -ENOMEM;
@@ -1989,6 +1992,9 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
}
}
+ if (event & BNXT_REDIRECT_EVENT)
+ xdp_do_flush_map();
+
if (event & BNXT_TX_EVENT) {
struct bnxt_tx_ring_info *txr = bnapi->tx_ring;
u16 prod = txr->tx_prod;
@@ -2130,12 +2136,12 @@ static int bnxt_poll(struct napi_struct *napi, int budget)
}
}
if (bp->flags & BNXT_FLAG_DIM) {
- struct net_dim_sample dim_sample;
+ struct dim_sample dim_sample;
- net_dim_sample(cpr->event_ctr,
- cpr->rx_packets,
- cpr->rx_bytes,
- &dim_sample);
+ dim_update_sample(cpr->event_ctr,
+ cpr->rx_packets,
+ cpr->rx_bytes,
+ &dim_sample);
net_dim(&cpr->dim, dim_sample);
}
return work_done;
@@ -2254,9 +2260,23 @@ static void bnxt_free_tx_skbs(struct bnxt *bp)
for (j = 0; j < max_idx;) {
struct bnxt_sw_tx_bd *tx_buf = &txr->tx_buf_ring[j];
- struct sk_buff *skb = tx_buf->skb;
+ struct sk_buff *skb;
int k, last;
+ if (i < bp->tx_nr_rings_xdp &&
+ tx_buf->action == XDP_REDIRECT) {
+ dma_unmap_single(&pdev->dev,
+ dma_unmap_addr(tx_buf, mapping),
+ dma_unmap_len(tx_buf, len),
+ PCI_DMA_TODEVICE);
+ xdp_return_frame(tx_buf->xdpf);
+ tx_buf->action = 0;
+ tx_buf->xdpf = NULL;
+ j++;
+ continue;
+ }
+
+ skb = tx_buf->skb;
if (!skb) {
j++;
continue;
@@ -2343,7 +2363,7 @@ static void bnxt_free_rx_skbs(struct bnxt *bp)
dma_unmap_page_attrs(&pdev->dev, mapping,
PAGE_SIZE, bp->rx_dir,
DMA_ATTR_WEAK_ORDERING);
- __free_page(data);
+ page_pool_recycle_direct(rxr->page_pool, data);
} else {
dma_unmap_single_attrs(&pdev->dev, mapping,
bp->rx_buf_use_size,
@@ -2480,6 +2500,9 @@ static void bnxt_free_rx_rings(struct bnxt *bp)
if (xdp_rxq_info_is_reg(&rxr->xdp_rxq))
xdp_rxq_info_unreg(&rxr->xdp_rxq);
+ page_pool_destroy(rxr->page_pool);
+ rxr->page_pool = NULL;
+
kfree(rxr->rx_tpa);
rxr->rx_tpa = NULL;
@@ -2494,6 +2517,26 @@ static void bnxt_free_rx_rings(struct bnxt *bp)
}
}
+static int bnxt_alloc_rx_page_pool(struct bnxt *bp,
+ struct bnxt_rx_ring_info *rxr)
+{
+ struct page_pool_params pp = { 0 };
+
+ pp.pool_size = bp->rx_ring_size;
+ pp.nid = dev_to_node(&bp->pdev->dev);
+ pp.dev = &bp->pdev->dev;
+ pp.dma_dir = DMA_BIDIRECTIONAL;
+
+ rxr->page_pool = page_pool_create(&pp);
+ if (IS_ERR(rxr->page_pool)) {
+ int err = PTR_ERR(rxr->page_pool);
+
+ rxr->page_pool = NULL;
+ return err;
+ }
+ return 0;
+}
+
static int bnxt_alloc_rx_rings(struct bnxt *bp)
{
int i, rc, agg_rings = 0, tpa_rings = 0;
@@ -2513,10 +2556,22 @@ static int bnxt_alloc_rx_rings(struct bnxt *bp)
ring = &rxr->rx_ring_struct;
+ rc = bnxt_alloc_rx_page_pool(bp, rxr);
+ if (rc)
+ return rc;
+
rc = xdp_rxq_info_reg(&rxr->xdp_rxq, bp->dev, i);
if (rc < 0)
return rc;
+ rc = xdp_rxq_info_reg_mem_model(&rxr->xdp_rxq,
+ MEM_TYPE_PAGE_POOL,
+ rxr->page_pool);
+ if (rc) {
+ xdp_rxq_info_unreg(&rxr->xdp_rxq);
+ return rc;
+ }
+
rc = bnxt_alloc_ring(bp, &ring->ring_mem);
if (rc)
return rc;
@@ -2622,8 +2677,6 @@ static int bnxt_alloc_tx_rings(struct bnxt *bp)
mapping = txr->tx_push_mapping +
sizeof(struct tx_push_bd);
txr->data_mapping = cpu_to_le64(mapping);
-
- memset(txr->tx_push, 0, sizeof(struct tx_push_bd));
}
qidx = bp->tc_to_qidx[j];
ring->queue_id = bp->q_info[qidx].queue_id;
@@ -3022,7 +3075,7 @@ static int bnxt_alloc_vnics(struct bnxt *bp)
int num_vnics = 1;
#ifdef CONFIG_RFS_ACCEL
- if (bp->flags & BNXT_FLAG_RFS)
+ if ((bp->flags & (BNXT_FLAG_RFS | BNXT_FLAG_CHIP_P5)) == BNXT_FLAG_RFS)
num_vnics += bp->rx_nr_rings;
#endif
@@ -5508,7 +5561,16 @@ static int bnxt_cp_rings_in_use(struct bnxt *bp)
static int bnxt_get_func_stat_ctxs(struct bnxt *bp)
{
- return bp->cp_nr_rings + bnxt_get_ulp_stat_ctxs(bp);
+ int ulp_stat = bnxt_get_ulp_stat_ctxs(bp);
+ int cp = bp->cp_nr_rings;
+
+ if (!ulp_stat)
+ return cp;
+
+ if (bnxt_nq_rings_in_use(bp) > cp + bnxt_get_ulp_msix_num(bp))
+ return bnxt_get_ulp_msix_base(bp) + ulp_stat;
+
+ return cp + ulp_stat;
}
static bool bnxt_need_reserve_rings(struct bnxt *bp)
@@ -7124,6 +7186,9 @@ static int bnxt_alloc_rfs_vnics(struct bnxt *bp)
#ifdef CONFIG_RFS_ACCEL
int i, rc = 0;
+ if (bp->flags & BNXT_FLAG_CHIP_P5)
+ return 0;
+
for (i = 0; i < bp->rx_nr_rings; i++) {
struct bnxt_vnic_info *vnic;
u16 vnic_id = i + 1;
@@ -7477,11 +7542,7 @@ unsigned int bnxt_get_avail_cp_rings_for_en(struct bnxt *bp)
unsigned int bnxt_get_avail_stat_ctxs_for_en(struct bnxt *bp)
{
- unsigned int stat;
-
- stat = bnxt_get_max_func_stat_ctxs(bp) - bnxt_get_ulp_stat_ctxs(bp);
- stat -= bp->cp_nr_rings;
- return stat;
+ return bnxt_get_max_func_stat_ctxs(bp) - bnxt_get_func_stat_ctxs(bp);
}
int bnxt_get_avail_msix(struct bnxt *bp, int num)
@@ -7813,7 +7874,7 @@ static void bnxt_enable_napi(struct bnxt *bp)
if (bp->bnapi[i]->rx_ring) {
INIT_WORK(&cpr->dim.work, bnxt_dim_work);
- cpr->dim.mode = NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE;
+ cpr->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
}
napi_enable(&bp->bnapi[i]->napi);
}
@@ -9587,7 +9648,7 @@ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs,
return -ENOMEM;
vnics = 1;
- if (bp->flags & BNXT_FLAG_RFS)
+ if ((bp->flags & (BNXT_FLAG_RFS | BNXT_FLAG_CHIP_P5)) == BNXT_FLAG_RFS)
vnics += rx_rings;
if (bp->flags & BNXT_FLAG_AGG_RINGS)
@@ -9847,32 +9908,19 @@ static int bnxt_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
}
}
-static int bnxt_setup_tc_block(struct net_device *dev,
- struct tc_block_offload *f)
-{
- struct bnxt *bp = netdev_priv(dev);
-
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
- return -EOPNOTSUPP;
-
- switch (f->command) {
- case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block, bnxt_setup_tc_block_cb,
- bp, bp, f->extack);
- case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block, bnxt_setup_tc_block_cb, bp);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-}
+static LIST_HEAD(bnxt_block_cb_list);
static int bnxt_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data)
{
+ struct bnxt *bp = netdev_priv(dev);
+
switch (type) {
case TC_SETUP_BLOCK:
- return bnxt_setup_tc_block(dev, type_data);
+ return flow_block_cb_setup_simple(type_data,
+ &bnxt_block_cb_list,
+ bnxt_setup_tc_block_cb,
+ bp, bp, true);
case TC_SETUP_QDISC_MQPRIO: {
struct tc_mqprio_qopt *mqprio = type_data;
@@ -10233,6 +10281,7 @@ static const struct net_device_ops bnxt_netdev_ops = {
.ndo_udp_tunnel_add = bnxt_udp_tunnel_add,
.ndo_udp_tunnel_del = bnxt_udp_tunnel_del,
.ndo_bpf = bnxt_xdp,
+ .ndo_xdp_xmit = bnxt_xdp_xmit,
.ndo_bridge_getlink = bnxt_bridge_getlink,
.ndo_bridge_setlink = bnxt_bridge_setlink,
.ndo_get_devlink_port = bnxt_get_devlink_port,
@@ -10262,10 +10311,10 @@ static void bnxt_remove_one(struct pci_dev *pdev)
bnxt_dcb_free(bp);
kfree(bp->edev);
bp->edev = NULL;
+ bnxt_cleanup_pci(bp);
bnxt_free_ctx_mem(bp);
kfree(bp->ctx);
bp->ctx = NULL;
- bnxt_cleanup_pci(bp);
bnxt_free_port_stats(bp);
free_netdev(dev);
}
@@ -10859,6 +10908,7 @@ static void bnxt_shutdown(struct pci_dev *pdev)
if (system_state == SYSTEM_POWER_OFF) {
bnxt_clear_int_mode(bp);
+ pci_disable_device(pdev);
pci_wake_from_d3(pdev, bp->wol);
pci_set_power_state(pdev, PCI_D3hot);
}
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
index be438d82f939..16694b704d15 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
@@ -24,7 +24,9 @@
#include <net/devlink.h>
#include <net/dst_metadata.h>
#include <net/xdp.h>
-#include <linux/net_dim.h>
+#include <linux/dim.h>
+
+struct page_pool;
struct tx_bd {
__le32 tx_bd_len_flags_type;
@@ -587,15 +589,21 @@ struct nqe_cn {
#define BNXT_HWRM_CHNL_CHIMP 0
#define BNXT_HWRM_CHNL_KONG 1
-#define BNXT_RX_EVENT 1
-#define BNXT_AGG_EVENT 2
-#define BNXT_TX_EVENT 4
+#define BNXT_RX_EVENT 1
+#define BNXT_AGG_EVENT 2
+#define BNXT_TX_EVENT 4
+#define BNXT_REDIRECT_EVENT 8
struct bnxt_sw_tx_bd {
- struct sk_buff *skb;
+ union {
+ struct sk_buff *skb;
+ struct xdp_frame *xdpf;
+ };
DEFINE_DMA_UNMAP_ADDR(mapping);
+ DEFINE_DMA_UNMAP_LEN(len);
u8 is_gso;
u8 is_push;
+ u8 action;
union {
unsigned short nr_frags;
u16 rx_prod;
@@ -793,6 +801,7 @@ struct bnxt_rx_ring_info {
struct bnxt_ring_struct rx_ring_struct;
struct bnxt_ring_struct rx_agg_ring_struct;
struct xdp_rxq_info xdp_rxq;
+ struct page_pool *page_pool;
};
struct bnxt_cp_ring_info {
@@ -810,7 +819,7 @@ struct bnxt_cp_ring_info {
u64 rx_bytes;
u64 event_ctr;
- struct net_dim dim;
+ struct dim dim;
union {
struct tx_cmp *cp_desc_ring[MAX_CP_PAGES];
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c
index 70775158c8c4..07301cb87c03 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c
@@ -396,7 +396,7 @@ static int bnxt_hwrm_queue_dscp_qcaps(struct bnxt *bp)
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_QUEUE_DSCP_QCAPS, -1, -1);
mutex_lock(&bp->hwrm_cmd_lock);
- rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+ rc = _hwrm_send_message_silent(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (!rc) {
bp->max_dscp_value = (1 << resp->num_dscp_bits) - 1;
if (bp->max_dscp_value < 0x3f)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_debugfs.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_debugfs.c
index 94e208e9789f..61393f351a77 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_debugfs.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_debugfs.c
@@ -11,7 +11,7 @@
#include <linux/module.h>
#include <linux/pci.h>
#include "bnxt_hsi.h"
-#include <linux/net_dim.h>
+#include <linux/dim.h>
#include "bnxt.h"
#include "bnxt_debugfs.h"
@@ -21,7 +21,7 @@ static ssize_t debugfs_dim_read(struct file *filep,
char __user *buffer,
size_t count, loff_t *ppos)
{
- struct net_dim *dim = filep->private_data;
+ struct dim *dim = filep->private_data;
int len;
char *buf;
@@ -61,7 +61,7 @@ static const struct file_operations debugfs_dim_fops = {
.read = debugfs_dim_read,
};
-static struct dentry *debugfs_dim_ring_init(struct net_dim *dim, int ring_idx,
+static struct dentry *debugfs_dim_ring_init(struct dim *dim, int ring_idx,
struct dentry *dd)
{
static char qname[16];
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_dim.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_dim.c
index afa97c8bb081..6f6576dc417a 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_dim.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_dim.c
@@ -7,26 +7,25 @@
* the Free Software Foundation.
*/
-#include <linux/net_dim.h>
+#include <linux/dim.h>
#include "bnxt_hsi.h"
#include "bnxt.h"
void bnxt_dim_work(struct work_struct *work)
{
- struct net_dim *dim = container_of(work, struct net_dim,
- work);
+ struct dim *dim = container_of(work, struct dim, work);
struct bnxt_cp_ring_info *cpr = container_of(dim,
struct bnxt_cp_ring_info,
dim);
struct bnxt_napi *bnapi = container_of(cpr,
struct bnxt_napi,
cp_ring);
- struct net_dim_cq_moder cur_moder =
+ struct dim_cq_moder cur_moder =
net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
cpr->rx_ring_coal.coal_ticks = cur_moder.usec;
cpr->rx_ring_coal.coal_bufs = cur_moder.pkts;
bnxt_hwrm_set_ring_coal(bnapi->bp, bnapi);
- dim->state = NET_DIM_START_MEASURE;
+ dim->state = DIM_START_MEASURE;
}
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
index a6c7baf38036..c7ee63d69679 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
@@ -2799,7 +2799,7 @@ static int bnxt_run_loopback(struct bnxt *bp)
dev_kfree_skb(skb);
return -EIO;
}
- bnxt_xmit_xdp(bp, txr, map, pkt_size, 0);
+ bnxt_xmit_bd(bp, txr, map, pkt_size);
/* Sync BD data before updating doorbell */
wmb();
@@ -2842,7 +2842,7 @@ static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest,
bool offline = false;
u8 test_results = 0;
u8 test_mask = 0;
- int rc, i;
+ int rc = 0, i;
if (!bp->num_tests || !BNXT_SINGLE_PF(bp))
return;
@@ -2913,9 +2913,9 @@ static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest,
}
bnxt_hwrm_phy_loopback(bp, false, false);
bnxt_half_close_nic(bp);
- bnxt_open_nic(bp, false, true);
+ rc = bnxt_open_nic(bp, false, true);
}
- if (bnxt_test_irq(bp)) {
+ if (rc || bnxt_test_irq(bp)) {
buf[BNXT_IRQ_TEST_IDX] = 1;
etest->flags |= ETH_TEST_FL_FAILED;
}
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
index 44d6c5743fb9..6fe4a7174271 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
@@ -170,10 +170,10 @@ static int bnxt_tc_parse_actions(struct bnxt *bp,
}
static int bnxt_tc_parse_flow(struct bnxt *bp,
- struct tc_cls_flower_offload *tc_flow_cmd,
+ struct flow_cls_offload *tc_flow_cmd,
struct bnxt_tc_flow *flow)
{
- struct flow_rule *rule = tc_cls_flower_offload_flow_rule(tc_flow_cmd);
+ struct flow_rule *rule = flow_cls_offload_flow_rule(tc_flow_cmd);
struct flow_dissector *dissector = rule->match.dissector;
/* KEY_CONTROL and KEY_BASIC are needed for forming a meaningful key */
@@ -1262,7 +1262,7 @@ static void bnxt_tc_set_src_fid(struct bnxt *bp, struct bnxt_tc_flow *flow,
* The hash-tables are already protected by the rhashtable API.
*/
static int bnxt_tc_add_flow(struct bnxt *bp, u16 src_fid,
- struct tc_cls_flower_offload *tc_flow_cmd)
+ struct flow_cls_offload *tc_flow_cmd)
{
struct bnxt_tc_flow_node *new_node, *old_node;
struct bnxt_tc_info *tc_info = bp->tc_info;
@@ -1348,7 +1348,7 @@ done:
}
static int bnxt_tc_del_flow(struct bnxt *bp,
- struct tc_cls_flower_offload *tc_flow_cmd)
+ struct flow_cls_offload *tc_flow_cmd)
{
struct bnxt_tc_info *tc_info = bp->tc_info;
struct bnxt_tc_flow_node *flow_node;
@@ -1363,7 +1363,7 @@ static int bnxt_tc_del_flow(struct bnxt *bp,
}
static int bnxt_tc_get_flow_stats(struct bnxt *bp,
- struct tc_cls_flower_offload *tc_flow_cmd)
+ struct flow_cls_offload *tc_flow_cmd)
{
struct bnxt_tc_flow_stats stats, *curr_stats, *prev_stats;
struct bnxt_tc_info *tc_info = bp->tc_info;
@@ -1585,14 +1585,14 @@ void bnxt_tc_flow_stats_work(struct bnxt *bp)
}
int bnxt_tc_setup_flower(struct bnxt *bp, u16 src_fid,
- struct tc_cls_flower_offload *cls_flower)
+ struct flow_cls_offload *cls_flower)
{
switch (cls_flower->command) {
- case TC_CLSFLOWER_REPLACE:
+ case FLOW_CLS_REPLACE:
return bnxt_tc_add_flow(bp, src_fid, cls_flower);
- case TC_CLSFLOWER_DESTROY:
+ case FLOW_CLS_DESTROY:
return bnxt_tc_del_flow(bp, cls_flower);
- case TC_CLSFLOWER_STATS:
+ case FLOW_CLS_STATS:
return bnxt_tc_get_flow_stats(bp, cls_flower);
default:
return -EOPNOTSUPP;
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.h
index 8a0968967bc5..ffec57d1a5ec 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.h
@@ -196,7 +196,7 @@ struct bnxt_tc_flow_node {
};
int bnxt_tc_setup_flower(struct bnxt *bp, u16 src_fid,
- struct tc_cls_flower_offload *cls_flower);
+ struct flow_cls_offload *cls_flower);
int bnxt_init_tc(struct bnxt *bp);
void bnxt_shutdown_tc(struct bnxt *bp);
void bnxt_tc_flow_stats_work(struct bnxt *bp);
@@ -209,7 +209,7 @@ static inline bool bnxt_tc_flower_enabled(struct bnxt *bp)
#else /* CONFIG_BNXT_FLOWER_OFFLOAD */
static inline int bnxt_tc_setup_flower(struct bnxt *bp, u16 src_fid,
- struct tc_cls_flower_offload *cls_flower)
+ struct flow_cls_offload *cls_flower)
{
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c
index bfa342a98d08..fc77caf0a076 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c
@@ -157,8 +157,10 @@ static int bnxt_req_msix_vecs(struct bnxt_en_dev *edev, int ulp_id,
if (BNXT_NEW_RM(bp)) {
struct bnxt_hw_resc *hw_resc = &bp->hw_resc;
+ int resv_msix;
- avail_msix = hw_resc->resv_irqs - bp->cp_nr_rings;
+ resv_msix = hw_resc->resv_irqs - bp->cp_nr_rings;
+ avail_msix = min_t(int, resv_msix, avail_msix);
edev->ulp_tbl[ulp_id].msix_requested = avail_msix;
}
bnxt_fill_msix_vecs(bp, ent);
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c
index f760921389a3..f9bf7d7250ab 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c
@@ -161,34 +161,19 @@ static int bnxt_vf_rep_setup_tc_block_cb(enum tc_setup_type type,
}
}
-static int bnxt_vf_rep_setup_tc_block(struct net_device *dev,
- struct tc_block_offload *f)
-{
- struct bnxt_vf_rep *vf_rep = netdev_priv(dev);
-
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
- return -EOPNOTSUPP;
-
- switch (f->command) {
- case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block,
- bnxt_vf_rep_setup_tc_block_cb,
- vf_rep, vf_rep, f->extack);
- case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block,
- bnxt_vf_rep_setup_tc_block_cb, vf_rep);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-}
+static LIST_HEAD(bnxt_vf_block_cb_list);
static int bnxt_vf_rep_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data)
{
+ struct bnxt_vf_rep *vf_rep = netdev_priv(dev);
+
switch (type) {
case TC_SETUP_BLOCK:
- return bnxt_vf_rep_setup_tc_block(dev, type_data);
+ return flow_block_cb_setup_simple(type_data,
+ &bnxt_vf_block_cb_list,
+ bnxt_vf_rep_setup_tc_block_cb,
+ vf_rep, vf_rep, true);
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
index 0184ef6f05a7..c6f6f2033880 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
@@ -15,12 +15,14 @@
#include <linux/bpf.h>
#include <linux/bpf_trace.h>
#include <linux/filter.h>
+#include <net/page_pool.h>
#include "bnxt_hsi.h"
#include "bnxt.h"
#include "bnxt_xdp.h"
-void bnxt_xmit_xdp(struct bnxt *bp, struct bnxt_tx_ring_info *txr,
- dma_addr_t mapping, u32 len, u16 rx_prod)
+struct bnxt_sw_tx_bd *bnxt_xmit_bd(struct bnxt *bp,
+ struct bnxt_tx_ring_info *txr,
+ dma_addr_t mapping, u32 len)
{
struct bnxt_sw_tx_bd *tx_buf;
struct tx_bd *txbd;
@@ -29,7 +31,6 @@ void bnxt_xmit_xdp(struct bnxt *bp, struct bnxt_tx_ring_info *txr,
prod = txr->tx_prod;
tx_buf = &txr->tx_buf_ring[prod];
- tx_buf->rx_prod = rx_prod;
txbd = &txr->tx_desc_ring[TX_RING(prod)][TX_IDX(prod)];
flags = (len << TX_BD_LEN_SHIFT) | (1 << TX_BD_FLAGS_BD_CNT_SHIFT) |
@@ -40,30 +41,67 @@ void bnxt_xmit_xdp(struct bnxt *bp, struct bnxt_tx_ring_info *txr,
prod = NEXT_TX(prod);
txr->tx_prod = prod;
+ return tx_buf;
+}
+
+static void __bnxt_xmit_xdp(struct bnxt *bp, struct bnxt_tx_ring_info *txr,
+ dma_addr_t mapping, u32 len, u16 rx_prod)
+{
+ struct bnxt_sw_tx_bd *tx_buf;
+
+ tx_buf = bnxt_xmit_bd(bp, txr, mapping, len);
+ tx_buf->rx_prod = rx_prod;
+ tx_buf->action = XDP_TX;
+}
+
+static void __bnxt_xmit_xdp_redirect(struct bnxt *bp,
+ struct bnxt_tx_ring_info *txr,
+ dma_addr_t mapping, u32 len,
+ struct xdp_frame *xdpf)
+{
+ struct bnxt_sw_tx_bd *tx_buf;
+
+ tx_buf = bnxt_xmit_bd(bp, txr, mapping, len);
+ tx_buf->action = XDP_REDIRECT;
+ tx_buf->xdpf = xdpf;
+ dma_unmap_addr_set(tx_buf, mapping, mapping);
+ dma_unmap_len_set(tx_buf, len, 0);
}
void bnxt_tx_int_xdp(struct bnxt *bp, struct bnxt_napi *bnapi, int nr_pkts)
{
struct bnxt_tx_ring_info *txr = bnapi->tx_ring;
struct bnxt_rx_ring_info *rxr = bnapi->rx_ring;
+ bool rx_doorbell_needed = false;
struct bnxt_sw_tx_bd *tx_buf;
u16 tx_cons = txr->tx_cons;
u16 last_tx_cons = tx_cons;
- u16 rx_prod;
int i;
for (i = 0; i < nr_pkts; i++) {
- last_tx_cons = tx_cons;
+ tx_buf = &txr->tx_buf_ring[tx_cons];
+
+ if (tx_buf->action == XDP_REDIRECT) {
+ struct pci_dev *pdev = bp->pdev;
+
+ dma_unmap_single(&pdev->dev,
+ dma_unmap_addr(tx_buf, mapping),
+ dma_unmap_len(tx_buf, len),
+ PCI_DMA_TODEVICE);
+ xdp_return_frame(tx_buf->xdpf);
+ tx_buf->action = 0;
+ tx_buf->xdpf = NULL;
+ } else if (tx_buf->action == XDP_TX) {
+ rx_doorbell_needed = true;
+ last_tx_cons = tx_cons;
+ }
tx_cons = NEXT_TX(tx_cons);
}
txr->tx_cons = tx_cons;
- if (bnxt_tx_avail(bp, txr) == bp->tx_ring_size) {
- rx_prod = rxr->rx_prod;
- } else {
+ if (rx_doorbell_needed) {
tx_buf = &txr->tx_buf_ring[last_tx_cons];
- rx_prod = tx_buf->rx_prod;
+ bnxt_db_write(bp, &rxr->rx_db, tx_buf->rx_prod);
}
- bnxt_db_write(bp, &rxr->rx_db, rx_prod);
}
/* returns the following:
@@ -88,19 +126,19 @@ bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons,
return false;
pdev = bp->pdev;
- txr = rxr->bnapi->tx_ring;
rx_buf = &rxr->rx_buf_ring[cons];
offset = bp->rx_offset;
+ mapping = rx_buf->mapping - bp->rx_dma_offset;
+ dma_sync_single_for_cpu(&pdev->dev, mapping + offset, *len, bp->rx_dir);
+
+ txr = rxr->bnapi->tx_ring;
xdp.data_hard_start = *data_ptr - offset;
xdp.data = *data_ptr;
xdp_set_data_meta_invalid(&xdp);
xdp.data_end = *data_ptr + *len;
xdp.rxq = &rxr->xdp_rxq;
orig_data = xdp.data;
- mapping = rx_buf->mapping - bp->rx_dma_offset;
-
- dma_sync_single_for_cpu(&pdev->dev, mapping + offset, *len, bp->rx_dir);
rcu_read_lock();
act = bpf_prog_run_xdp(xdp_prog, &xdp);
@@ -132,10 +170,34 @@ bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons,
*event = BNXT_TX_EVENT;
dma_sync_single_for_device(&pdev->dev, mapping + offset, *len,
bp->rx_dir);
- bnxt_xmit_xdp(bp, txr, mapping + offset, *len,
- NEXT_RX(rxr->rx_prod));
+ __bnxt_xmit_xdp(bp, txr, mapping + offset, *len,
+ NEXT_RX(rxr->rx_prod));
bnxt_reuse_rx_data(rxr, cons, page);
return true;
+ case XDP_REDIRECT:
+ /* if we are calling this here then we know that the
+ * redirect is coming from a frame received by the
+ * bnxt_en driver.
+ */
+ dma_unmap_page_attrs(&pdev->dev, mapping,
+ PAGE_SIZE, bp->rx_dir,
+ DMA_ATTR_WEAK_ORDERING);
+
+ /* if we are unable to allocate a new buffer, abort and reuse */
+ if (bnxt_alloc_rx_data(bp, rxr, rxr->rx_prod, GFP_ATOMIC)) {
+ trace_xdp_exception(bp->dev, xdp_prog, act);
+ bnxt_reuse_rx_data(rxr, cons, page);
+ return true;
+ }
+
+ if (xdp_do_redirect(bp->dev, &xdp, xdp_prog)) {
+ trace_xdp_exception(bp->dev, xdp_prog, act);
+ page_pool_recycle_direct(rxr->page_pool, page);
+ return true;
+ }
+
+ *event |= BNXT_REDIRECT_EVENT;
+ break;
default:
bpf_warn_invalid_xdp_action(act);
/* Fall thru */
@@ -149,6 +211,56 @@ bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons,
return true;
}
+int bnxt_xdp_xmit(struct net_device *dev, int num_frames,
+ struct xdp_frame **frames, u32 flags)
+{
+ struct bnxt *bp = netdev_priv(dev);
+ struct bpf_prog *xdp_prog = READ_ONCE(bp->xdp_prog);
+ struct pci_dev *pdev = bp->pdev;
+ struct bnxt_tx_ring_info *txr;
+ dma_addr_t mapping;
+ int drops = 0;
+ int ring;
+ int i;
+
+ if (!test_bit(BNXT_STATE_OPEN, &bp->state) ||
+ !bp->tx_nr_rings_xdp ||
+ !xdp_prog)
+ return -EINVAL;
+
+ ring = smp_processor_id() % bp->tx_nr_rings_xdp;
+ txr = &bp->tx_ring[ring];
+
+ for (i = 0; i < num_frames; i++) {
+ struct xdp_frame *xdp = frames[i];
+
+ if (!txr || !bnxt_tx_avail(bp, txr) ||
+ !(bp->bnapi[ring]->flags & BNXT_NAPI_FLAG_XDP)) {
+ xdp_return_frame_rx_napi(xdp);
+ drops++;
+ continue;
+ }
+
+ mapping = dma_map_single(&pdev->dev, xdp->data, xdp->len,
+ DMA_TO_DEVICE);
+
+ if (dma_mapping_error(&pdev->dev, mapping)) {
+ xdp_return_frame_rx_napi(xdp);
+ drops++;
+ continue;
+ }
+ __bnxt_xmit_xdp_redirect(bp, txr, mapping, xdp->len, xdp);
+ }
+
+ if (flags & XDP_XMIT_FLUSH) {
+ /* Sync BD data before updating doorbell */
+ wmb();
+ bnxt_db_write(bp, &txr->tx_db, txr->tx_prod);
+ }
+
+ return num_frames - drops;
+}
+
/* Under rtnl_lock */
static int bnxt_xdp_set(struct bnxt *bp, struct bpf_prog *prog)
{
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h
index 414b748038ca..0df40c3beb05 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h
@@ -10,12 +10,15 @@
#ifndef BNXT_XDP_H
#define BNXT_XDP_H
-void bnxt_xmit_xdp(struct bnxt *bp, struct bnxt_tx_ring_info *txr,
- dma_addr_t mapping, u32 len, u16 rx_prod);
+struct bnxt_sw_tx_bd *bnxt_xmit_bd(struct bnxt *bp,
+ struct bnxt_tx_ring_info *txr,
+ dma_addr_t mapping, u32 len);
void bnxt_tx_int_xdp(struct bnxt *bp, struct bnxt_napi *bnapi, int nr_pkts);
bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons,
struct page *page, u8 **data_ptr, unsigned int *len,
u8 *event);
int bnxt_xdp(struct net_device *dev, struct netdev_bpf *xdp);
+int bnxt_xdp_xmit(struct net_device *dev, int num_frames,
+ struct xdp_frame **frames, u32 flags);
#endif
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 374b9ff05c88..a2b57807453b 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Broadcom GENET (Gigabit Ethernet) controller driver
*
* Copyright (c) 2014-2017 Broadcom
- *
- * 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.
*/
#define pr_fmt(fmt) "bcmgenet: " fmt
@@ -643,7 +640,7 @@ static void bcmgenet_set_rx_coalesce(struct bcmgenet_rx_ring *ring,
static void bcmgenet_set_ring_rx_coalesce(struct bcmgenet_rx_ring *ring,
struct ethtool_coalesce *ec)
{
- struct net_dim_cq_moder moder;
+ struct dim_cq_moder moder;
u32 usecs, pkts;
ring->rx_coalesce_usecs = ec->rx_coalesce_usecs;
@@ -1898,7 +1895,7 @@ static int bcmgenet_rx_poll(struct napi_struct *napi, int budget)
{
struct bcmgenet_rx_ring *ring = container_of(napi,
struct bcmgenet_rx_ring, napi);
- struct net_dim_sample dim_sample;
+ struct dim_sample dim_sample;
unsigned int work_done;
work_done = bcmgenet_desc_rx(ring, budget);
@@ -1909,8 +1906,8 @@ static int bcmgenet_rx_poll(struct napi_struct *napi, int budget)
}
if (ring->dim.use_dim) {
- net_dim_sample(ring->dim.event_ctr, ring->dim.packets,
- ring->dim.bytes, &dim_sample);
+ dim_update_sample(ring->dim.event_ctr, ring->dim.packets,
+ ring->dim.bytes, &dim_sample);
net_dim(&ring->dim.dim, dim_sample);
}
@@ -1919,16 +1916,16 @@ static int bcmgenet_rx_poll(struct napi_struct *napi, int budget)
static void bcmgenet_dim_work(struct work_struct *work)
{
- struct net_dim *dim = container_of(work, struct net_dim, work);
+ struct dim *dim = container_of(work, struct dim, work);
struct bcmgenet_net_dim *ndim =
container_of(dim, struct bcmgenet_net_dim, dim);
struct bcmgenet_rx_ring *ring =
container_of(ndim, struct bcmgenet_rx_ring, dim);
- struct net_dim_cq_moder cur_profile =
+ struct dim_cq_moder cur_profile =
net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
bcmgenet_set_rx_coalesce(ring, cur_profile.usec, cur_profile.pkts);
- dim->state = NET_DIM_START_MEASURE;
+ dim->state = DIM_START_MEASURE;
}
/* Assign skb to RX DMA descriptor. */
@@ -2085,7 +2082,7 @@ static void bcmgenet_init_dim(struct bcmgenet_rx_ring *ring,
struct bcmgenet_net_dim *dim = &ring->dim;
INIT_WORK(&dim->dim.work, cb);
- dim->dim.mode = NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE;
+ dim->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
dim->event_ctr = 0;
dim->packets = 0;
dim->bytes = 0;
@@ -2094,7 +2091,7 @@ static void bcmgenet_init_dim(struct bcmgenet_rx_ring *ring,
static void bcmgenet_init_rx_coalesce(struct bcmgenet_rx_ring *ring)
{
struct bcmgenet_net_dim *dim = &ring->dim;
- struct net_dim_cq_moder moder;
+ struct dim_cq_moder moder;
u32 usecs, pkts;
usecs = ring->rx_coalesce_usecs;
@@ -3086,39 +3083,42 @@ static void bcmgenet_timeout(struct net_device *dev)
netif_tx_wake_all_queues(dev);
}
-#define MAX_MC_COUNT 16
+#define MAX_MDF_FILTER 17
static inline void bcmgenet_set_mdf_addr(struct bcmgenet_priv *priv,
unsigned char *addr,
- int *i,
- int *mc)
+ int *i)
{
- u32 reg;
-
bcmgenet_umac_writel(priv, addr[0] << 8 | addr[1],
UMAC_MDF_ADDR + (*i * 4));
bcmgenet_umac_writel(priv, addr[2] << 24 | addr[3] << 16 |
addr[4] << 8 | addr[5],
UMAC_MDF_ADDR + ((*i + 1) * 4));
- reg = bcmgenet_umac_readl(priv, UMAC_MDF_CTRL);
- reg |= (1 << (MAX_MC_COUNT - *mc));
- bcmgenet_umac_writel(priv, reg, UMAC_MDF_CTRL);
*i += 2;
- (*mc)++;
}
static void bcmgenet_set_rx_mode(struct net_device *dev)
{
struct bcmgenet_priv *priv = netdev_priv(dev);
struct netdev_hw_addr *ha;
- int i, mc;
+ int i, nfilter;
u32 reg;
netif_dbg(priv, hw, dev, "%s: %08X\n", __func__, dev->flags);
- /* Promiscuous mode */
+ /* Number of filters needed */
+ nfilter = netdev_uc_count(dev) + netdev_mc_count(dev) + 2;
+
+ /*
+ * Turn on promicuous mode for three scenarios
+ * 1. IFF_PROMISC flag is set
+ * 2. IFF_ALLMULTI flag is set
+ * 3. The number of filters needed exceeds the number filters
+ * supported by the hardware.
+ */
reg = bcmgenet_umac_readl(priv, UMAC_CMD);
- if (dev->flags & IFF_PROMISC) {
+ if ((dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) ||
+ (nfilter > MAX_MDF_FILTER)) {
reg |= CMD_PROMISC;
bcmgenet_umac_writel(priv, reg, UMAC_CMD);
bcmgenet_umac_writel(priv, 0, UMAC_MDF_CTRL);
@@ -3128,32 +3128,24 @@ static void bcmgenet_set_rx_mode(struct net_device *dev)
bcmgenet_umac_writel(priv, reg, UMAC_CMD);
}
- /* UniMac doesn't support ALLMULTI */
- if (dev->flags & IFF_ALLMULTI) {
- netdev_warn(dev, "ALLMULTI is not supported\n");
- return;
- }
-
/* update MDF filter */
i = 0;
- mc = 0;
/* Broadcast */
- bcmgenet_set_mdf_addr(priv, dev->broadcast, &i, &mc);
+ bcmgenet_set_mdf_addr(priv, dev->broadcast, &i);
/* my own address.*/
- bcmgenet_set_mdf_addr(priv, dev->dev_addr, &i, &mc);
- /* Unicast list*/
- if (netdev_uc_count(dev) > (MAX_MC_COUNT - mc))
- return;
+ bcmgenet_set_mdf_addr(priv, dev->dev_addr, &i);
- if (!netdev_uc_empty(dev))
- netdev_for_each_uc_addr(ha, dev)
- bcmgenet_set_mdf_addr(priv, ha->addr, &i, &mc);
- /* Multicast */
- if (netdev_mc_empty(dev) || netdev_mc_count(dev) >= (MAX_MC_COUNT - mc))
- return;
+ /* Unicast */
+ netdev_for_each_uc_addr(ha, dev)
+ bcmgenet_set_mdf_addr(priv, ha->addr, &i);
+ /* Multicast */
netdev_for_each_mc_addr(ha, dev)
- bcmgenet_set_mdf_addr(priv, ha->addr, &i, &mc);
+ bcmgenet_set_mdf_addr(priv, ha->addr, &i);
+
+ /* Enable filters */
+ reg = GENMASK(MAX_MDF_FILTER - 1, MAX_MDF_FILTER - nfilter);
+ bcmgenet_umac_writel(priv, reg, UMAC_MDF_CTRL);
}
/* Set the hardware MAC address. */
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
index 14b49612aa86..4a8fc03d82fd 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2014-2017 Broadcom
- *
- * 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.
*/
#ifndef __BCMGENET_H__
@@ -16,7 +13,7 @@
#include <linux/mii.h>
#include <linux/if_vlan.h>
#include <linux/phy.h>
-#include <linux/net_dim.h>
+#include <linux/dim.h>
/* total number of Buffer Descriptors, same for Rx/Tx */
#define TOTAL_DESC 256
@@ -581,7 +578,7 @@ struct bcmgenet_net_dim {
u16 event_ctr;
unsigned long packets;
unsigned long bytes;
- struct net_dim dim;
+ struct dim dim;
};
struct bcmgenet_rx_ring {
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
index 57582efa362d..ea20d94bd050 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Broadcom GENET (Gigabit Ethernet) Wake-on-LAN support
*
* Copyright (c) 2014-2017 Broadcom
- *
- * 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.
*/
#define pr_fmt(fmt) "bcmgenet_wol: " fmt
diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c
index 51880d83131a..970e478a9017 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Broadcom GENET MDIO routines
*
* Copyright (c) 2014-2017 Broadcom
- *
- * 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.
*/
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index 6d1f9c822548..4c404d2213f9 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -6710,7 +6710,7 @@ static int tg3_alloc_rx_data(struct tg3 *tp, struct tg3_rx_prodring_set *tpr,
skb_size = SKB_DATA_ALIGN(data_size + TG3_RX_OFFSET(tp)) +
SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
if (skb_size <= PAGE_SIZE) {
- data = netdev_alloc_frag(skb_size);
+ data = napi_alloc_frag(skb_size);
*frag_size = skb_size;
} else {
data = kmalloc(skb_size, GFP_ATOMIC);
diff --git a/drivers/net/ethernet/cadence/Kconfig b/drivers/net/ethernet/cadence/Kconfig
index 1766697c9c5a..f4b3bd85dfe3 100644
--- a/drivers/net/ethernet/cadence/Kconfig
+++ b/drivers/net/ethernet/cadence/Kconfig
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
#
-# Atmel device configuration
+# Cadence device configuration
#
config NET_VENDOR_CADENCE
@@ -13,15 +13,15 @@ config NET_VENDOR_CADENCE
If unsure, say Y.
Note that the answer to this question doesn't directly affect the
- kernel: saying N will just cause the configurator to skip all
- the remaining Atmel network card questions. If you say Y, you will be
+ kernel: saying N will just cause the configurator to skip all the
+ remaining Cadence network card questions. If you say Y, you will be
asked for your specific card in the following questions.
if NET_VENDOR_CADENCE
config MACB
tristate "Cadence MACB/GEM support"
- depends on HAS_DMA
+ depends on HAS_DMA && COMMON_CLK
select PHYLIB
---help---
The Cadence MACB ethernet interface is found on many Atmel AT32 and
@@ -42,7 +42,7 @@ config MACB_USE_HWSTAMP
config MACB_PCI
tristate "Cadence PCI MACB/GEM support"
- depends on MACB && PCI && COMMON_CLK
+ depends on MACB && PCI
---help---
This is PCI wrapper for MACB driver.
diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
index 00ee5e8e0ff0..03983bd46eef 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Atmel MACB Ethernet Controller driver
*
* Copyright (C) 2004-2006 Atmel Corporation
- *
- * 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.
*/
#ifndef _MACB_H
#define _MACB_H
@@ -499,7 +496,11 @@
/* Bitfields in TISUBN */
#define GEM_SUBNSINCR_OFFSET 0
-#define GEM_SUBNSINCR_SIZE 16
+#define GEM_SUBNSINCRL_OFFSET 24
+#define GEM_SUBNSINCRL_SIZE 8
+#define GEM_SUBNSINCRH_OFFSET 0
+#define GEM_SUBNSINCRH_SIZE 16
+#define GEM_SUBNSINCR_SIZE 24
/* Bitfields in TI */
#define GEM_NSINCR_OFFSET 0
@@ -837,6 +838,9 @@ struct gem_tx_ts {
/* limit RX checksum offload to TCP and UDP packets */
#define GEM_RX_CSUM_CHECKED_MASK 2
+/* Scaled PPM fraction */
+#define PPM_FRACTION 16
+
/* struct macb_tx_skb - data about an skb which is being transmitted
* @skb: skb currently being transmitted, only set for the last buffer
* of the frame
@@ -1063,7 +1067,8 @@ struct macb_or_gem_ops {
int (*mog_alloc_rx_buffers)(struct macb *bp);
void (*mog_free_rx_buffers)(struct macb *bp);
void (*mog_init_rings)(struct macb *bp);
- int (*mog_rx)(struct macb_queue *queue, int budget);
+ int (*mog_rx)(struct macb_queue *queue, struct napi_struct *napi,
+ int budget);
};
/* MACB-PTP interface: adapt to platform needs. */
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index f825e3960540..5ca17e62dc3e 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -1,15 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Cadence MACB/GEM Ethernet Controller driver
*
* Copyright (C) 2004-2006 Atmel Corporation
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/crc32.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -40,6 +38,13 @@
#include <linux/pm_runtime.h>
#include "macb.h"
+/* This structure is only used for MACB on SiFive FU540 devices */
+struct sifive_fu540_macb_mgmt {
+ void __iomem *reg;
+ unsigned long rate;
+ struct clk_hw hw;
+};
+
#define MACB_RX_BUFFER_SIZE 128
#define RX_BUFFER_MULTIPLE 64 /* bytes */
@@ -984,7 +989,8 @@ static void discard_partial_frame(struct macb_queue *queue, unsigned int begin,
*/
}
-static int gem_rx(struct macb_queue *queue, int budget)
+static int gem_rx(struct macb_queue *queue, struct napi_struct *napi,
+ int budget)
{
struct macb *bp = queue->bp;
unsigned int len;
@@ -1066,7 +1072,7 @@ static int gem_rx(struct macb_queue *queue, int budget)
skb->data, 32, true);
#endif
- netif_receive_skb(skb);
+ napi_gro_receive(napi, skb);
}
gem_rx_refill(queue);
@@ -1074,8 +1080,8 @@ static int gem_rx(struct macb_queue *queue, int budget)
return count;
}
-static int macb_rx_frame(struct macb_queue *queue, unsigned int first_frag,
- unsigned int last_frag)
+static int macb_rx_frame(struct macb_queue *queue, struct napi_struct *napi,
+ unsigned int first_frag, unsigned int last_frag)
{
unsigned int len;
unsigned int frag;
@@ -1151,7 +1157,7 @@ static int macb_rx_frame(struct macb_queue *queue, unsigned int first_frag,
bp->dev->stats.rx_bytes += skb->len;
netdev_vdbg(bp->dev, "received skb of length %u, csum: %08x\n",
skb->len, skb->csum);
- netif_receive_skb(skb);
+ napi_gro_receive(napi, skb);
return 0;
}
@@ -1174,7 +1180,8 @@ static inline void macb_init_rx_ring(struct macb_queue *queue)
queue->rx_tail = 0;
}
-static int macb_rx(struct macb_queue *queue, int budget)
+static int macb_rx(struct macb_queue *queue, struct napi_struct *napi,
+ int budget)
{
struct macb *bp = queue->bp;
bool reset_rx_queue = false;
@@ -1211,7 +1218,7 @@ static int macb_rx(struct macb_queue *queue, int budget)
continue;
}
- dropped = macb_rx_frame(queue, first_frag, tail);
+ dropped = macb_rx_frame(queue, napi, first_frag, tail);
first_frag = -1;
if (unlikely(dropped < 0)) {
reset_rx_queue = true;
@@ -1265,7 +1272,7 @@ static int macb_poll(struct napi_struct *napi, int budget)
netdev_vdbg(bp->dev, "poll: status = %08lx, budget = %d\n",
(unsigned long)status, budget);
- work_done = bp->macbgem_ops.mog_rx(queue, budget);
+ work_done = bp->macbgem_ops.mog_rx(queue, napi, budget);
if (work_done < budget) {
napi_complete_done(napi, work_done);
@@ -3480,7 +3487,7 @@ static int macb_init(struct platform_device *pdev)
queue = &bp->queues[q];
queue->bp = bp;
- netif_napi_add(dev, &queue->napi, macb_poll, 64);
+ netif_napi_add(dev, &queue->napi, macb_poll, NAPI_POLL_WEIGHT);
if (hw_q) {
queue->ISR = GEM_ISR(hw_q - 1);
queue->IER = GEM_IER(hw_q - 1);
@@ -3619,6 +3626,8 @@ static int macb_init(struct platform_device *pdev)
/* max number of receive buffers */
#define AT91ETHER_MAX_RX_DESCR 9
+static struct sifive_fu540_macb_mgmt *mgmt;
+
/* Initialize and start the Receiver and Transmit subsystems */
static int at91ether_start(struct net_device *dev)
{
@@ -3946,6 +3955,116 @@ static int at91ether_init(struct platform_device *pdev)
return 0;
}
+static unsigned long fu540_macb_tx_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return mgmt->rate;
+}
+
+static long fu540_macb_tx_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ if (WARN_ON(rate < 2500000))
+ return 2500000;
+ else if (rate == 2500000)
+ return 2500000;
+ else if (WARN_ON(rate < 13750000))
+ return 2500000;
+ else if (WARN_ON(rate < 25000000))
+ return 25000000;
+ else if (rate == 25000000)
+ return 25000000;
+ else if (WARN_ON(rate < 75000000))
+ return 25000000;
+ else if (WARN_ON(rate < 125000000))
+ return 125000000;
+ else if (rate == 125000000)
+ return 125000000;
+
+ WARN_ON(rate > 125000000);
+
+ return 125000000;
+}
+
+static int fu540_macb_tx_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ rate = fu540_macb_tx_round_rate(hw, rate, &parent_rate);
+ if (rate != 125000000)
+ iowrite32(1, mgmt->reg);
+ else
+ iowrite32(0, mgmt->reg);
+ mgmt->rate = rate;
+
+ return 0;
+}
+
+static const struct clk_ops fu540_c000_ops = {
+ .recalc_rate = fu540_macb_tx_recalc_rate,
+ .round_rate = fu540_macb_tx_round_rate,
+ .set_rate = fu540_macb_tx_set_rate,
+};
+
+static int fu540_c000_clk_init(struct platform_device *pdev, struct clk **pclk,
+ struct clk **hclk, struct clk **tx_clk,
+ struct clk **rx_clk, struct clk **tsu_clk)
+{
+ struct clk_init_data init;
+ int err = 0;
+
+ err = macb_clk_init(pdev, pclk, hclk, tx_clk, rx_clk, tsu_clk);
+ if (err)
+ return err;
+
+ mgmt = devm_kzalloc(&pdev->dev, sizeof(*mgmt), GFP_KERNEL);
+ if (!mgmt)
+ return -ENOMEM;
+
+ init.name = "sifive-gemgxl-mgmt";
+ init.ops = &fu540_c000_ops;
+ init.flags = 0;
+ init.num_parents = 0;
+
+ mgmt->rate = 0;
+ mgmt->hw.init = &init;
+
+ *tx_clk = clk_register(NULL, &mgmt->hw);
+ if (IS_ERR(*tx_clk))
+ return PTR_ERR(*tx_clk);
+
+ err = clk_prepare_enable(*tx_clk);
+ if (err)
+ dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err);
+ else
+ dev_info(&pdev->dev, "Registered clk switch '%s'\n", init.name);
+
+ return 0;
+}
+
+static int fu540_c000_init(struct platform_device *pdev)
+{
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res)
+ return -ENODEV;
+
+ mgmt->reg = ioremap(res->start, resource_size(res));
+ if (!mgmt->reg)
+ return -ENOMEM;
+
+ return macb_init(pdev);
+}
+
+static const struct macb_config fu540_c000_config = {
+ .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_JUMBO |
+ MACB_CAPS_GEM_HAS_PTP,
+ .dma_burst_length = 16,
+ .clk_init = fu540_c000_clk_init,
+ .init = fu540_c000_init,
+ .jumbo_max_len = 10240,
+};
+
static const struct macb_config at91sam9260_config = {
.caps = MACB_CAPS_USRIO_HAS_CLKEN | MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII,
.clk_init = macb_clk_init,
@@ -4035,6 +4154,7 @@ static const struct of_device_id macb_dt_ids[] = {
{ .compatible = "cdns,emac", .data = &emac_config },
{ .compatible = "cdns,zynqmp-gem", .data = &zynqmp_config},
{ .compatible = "cdns,zynq-gem", .data = &zynq_config },
+ { .compatible = "sifive,fu540-macb", .data = &fu540_c000_config },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, macb_dt_ids);
@@ -4183,7 +4303,7 @@ static int macb_probe(struct platform_device *pdev)
if (PTR_ERR(mac) == -EPROBE_DEFER) {
err = -EPROBE_DEFER;
goto err_out_free_netdev;
- } else if (!IS_ERR(mac)) {
+ } else if (!IS_ERR_OR_NULL(mac)) {
ether_addr_copy(bp->dev->dev_addr, mac);
} else {
macb_get_hwaddr(bp);
@@ -4242,6 +4362,7 @@ err_out_free_netdev:
err_disable_clocks:
clk_disable_unprepare(tx_clk);
+ clk_unregister(tx_clk);
clk_disable_unprepare(hclk);
clk_disable_unprepare(pclk);
clk_disable_unprepare(rx_clk);
@@ -4276,6 +4397,7 @@ static int macb_remove(struct platform_device *pdev)
pm_runtime_dont_use_autosuspend(&pdev->dev);
if (!pm_runtime_suspended(&pdev->dev)) {
clk_disable_unprepare(bp->tx_clk);
+ clk_unregister(bp->tx_clk);
clk_disable_unprepare(bp->hclk);
clk_disable_unprepare(bp->pclk);
clk_disable_unprepare(bp->rx_clk);
diff --git a/drivers/net/ethernet/cadence/macb_ptp.c b/drivers/net/ethernet/cadence/macb_ptp.c
index 0a8aca8d3634..43a3f0dbf857 100644
--- a/drivers/net/ethernet/cadence/macb_ptp.c
+++ b/drivers/net/ethernet/cadence/macb_ptp.c
@@ -104,7 +104,10 @@ static int gem_tsu_incr_set(struct macb *bp, struct tsu_incr *incr_spec)
* to take effect.
*/
spin_lock_irqsave(&bp->tsu_clk_lock, flags);
- gem_writel(bp, TISUBN, GEM_BF(SUBNSINCR, incr_spec->sub_ns));
+ /* RegBit[15:0] = Subns[23:8]; RegBit[31:24] = Subns[7:0] */
+ gem_writel(bp, TISUBN, GEM_BF(SUBNSINCRL, incr_spec->sub_ns) |
+ GEM_BF(SUBNSINCRH, (incr_spec->sub_ns >>
+ GEM_SUBNSINCRL_SIZE)));
gem_writel(bp, TI, GEM_BF(NSINCR, incr_spec->ns));
spin_unlock_irqrestore(&bp->tsu_clk_lock, flags);
@@ -135,7 +138,7 @@ static int gem_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
* (temp / USEC_PER_SEC) + 0.5
*/
adj += (USEC_PER_SEC >> 1);
- adj >>= GEM_SUBNSINCR_SIZE; /* remove fractions */
+ adj >>= PPM_FRACTION; /* remove fractions */
adj = div_u64(adj, USEC_PER_SEC);
adj = neg_adj ? (word - adj) : (word + adj);
diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c
index 11d4e91ea754..99f49d059414 100644
--- a/drivers/net/ethernet/calxeda/xgmac.c
+++ b/drivers/net/ethernet/calxeda/xgmac.c
@@ -1855,7 +1855,7 @@ static void xgmac_pmt(void __iomem *ioaddr, unsigned long mode)
static int xgmac_suspend(struct device *dev)
{
- struct net_device *ndev = platform_get_drvdata(to_platform_device(dev));
+ struct net_device *ndev = dev_get_drvdata(dev);
struct xgmac_priv *priv = netdev_priv(ndev);
u32 value;
@@ -1881,7 +1881,7 @@ static int xgmac_suspend(struct device *dev)
static int xgmac_resume(struct device *dev)
{
- struct net_device *ndev = platform_get_drvdata(to_platform_device(dev));
+ struct net_device *ndev = dev_get_drvdata(dev);
struct xgmac_priv *priv = netdev_priv(ndev);
void __iomem *ioaddr = priv->base;
diff --git a/drivers/net/ethernet/cavium/liquidio/lio_core.c b/drivers/net/ethernet/cavium/liquidio/lio_core.c
index 1c50c10b5a16..d7e805749a5b 100644
--- a/drivers/net/ethernet/cavium/liquidio/lio_core.c
+++ b/drivers/net/ethernet/cavium/liquidio/lio_core.c
@@ -964,7 +964,7 @@ static void liquidio_schedule_droq_pkt_handlers(struct octeon_device *oct)
if (droq->ops.poll_mode) {
droq->ops.napi_fn(droq);
- oct_priv->napi_mask |= (1 << oq_no);
+ oct_priv->napi_mask |= BIT_ULL(oq_no);
} else {
tasklet_schedule(&oct_priv->droq_tasklet);
}
diff --git a/drivers/net/ethernet/cavium/liquidio/request_manager.c b/drivers/net/ethernet/cavium/liquidio/request_manager.c
index fcf20a8f92d9..032224178b64 100644
--- a/drivers/net/ethernet/cavium/liquidio/request_manager.c
+++ b/drivers/net/ethernet/cavium/liquidio/request_manager.c
@@ -218,15 +218,13 @@ int octeon_setup_iq(struct octeon_device *oct,
return 0;
}
oct->instr_queue[iq_no] =
- vmalloc_node(sizeof(struct octeon_instr_queue), numa_node);
+ vzalloc_node(sizeof(struct octeon_instr_queue), numa_node);
if (!oct->instr_queue[iq_no])
oct->instr_queue[iq_no] =
- vmalloc(sizeof(struct octeon_instr_queue));
+ vzalloc(sizeof(struct octeon_instr_queue));
if (!oct->instr_queue[iq_no])
return 1;
- memset(oct->instr_queue[iq_no], 0,
- sizeof(struct octeon_instr_queue));
oct->instr_queue[iq_no]->q_index = q_index;
oct->instr_queue[iq_no]->app_ctx = app_ctx;
diff --git a/drivers/net/ethernet/chelsio/cxgb4/Makefile b/drivers/net/ethernet/chelsio/cxgb4/Makefile
index 91d8a885deba..20390f6afbb4 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/Makefile
+++ b/drivers/net/ethernet/chelsio/cxgb4/Makefile
@@ -7,7 +7,7 @@ obj-$(CONFIG_CHELSIO_T4) += cxgb4.o
cxgb4-objs := cxgb4_main.o l2t.o smt.o t4_hw.o sge.o clip_tbl.o cxgb4_ethtool.o \
cxgb4_uld.o srq.o sched.o cxgb4_filter.o cxgb4_tc_u32.o \
- cxgb4_ptp.o cxgb4_tc_flower.o cxgb4_cudbg.o \
+ cxgb4_ptp.o cxgb4_tc_flower.o cxgb4_cudbg.o cxgb4_mps.o \
cudbg_common.o cudbg_lib.o cudbg_zlib.o
cxgb4-$(CONFIG_CHELSIO_T4_DCB) += cxgb4_dcb.o
cxgb4-$(CONFIG_CHELSIO_T4_FCOE) += cxgb4_fcoe.o
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
index a76529a7662d..c2e92786608b 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
@@ -1054,14 +1054,12 @@ static void cudbg_t4_fwcache(struct cudbg_init *pdbg_init,
}
}
-static int cudbg_collect_mem_region(struct cudbg_init *pdbg_init,
- struct cudbg_buffer *dbg_buff,
- struct cudbg_error *cudbg_err,
- u8 mem_type)
+static unsigned long cudbg_mem_region_size(struct cudbg_init *pdbg_init,
+ struct cudbg_error *cudbg_err,
+ u8 mem_type)
{
struct adapter *padap = pdbg_init->adap;
struct cudbg_meminfo mem_info;
- unsigned long size;
u8 mc_idx;
int rc;
@@ -1075,7 +1073,16 @@ static int cudbg_collect_mem_region(struct cudbg_init *pdbg_init,
if (rc)
return rc;
- size = mem_info.avail[mc_idx].limit - mem_info.avail[mc_idx].base;
+ return mem_info.avail[mc_idx].limit - mem_info.avail[mc_idx].base;
+}
+
+static int cudbg_collect_mem_region(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err,
+ u8 mem_type)
+{
+ unsigned long size = cudbg_mem_region_size(pdbg_init, cudbg_err, mem_type);
+
return cudbg_read_fw_mem(pdbg_init, dbg_buff, mem_type, size,
cudbg_err);
}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
index a8fe0808823d..1fbb640e896a 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
@@ -280,6 +280,7 @@ struct tp_params {
unsigned short tx_modq[NCHAN]; /* channel to modulation queue map */
u32 vlan_pri_map; /* cached TP_VLAN_PRI_MAP */
+ u32 filter_mask;
u32 ingress_config; /* cached TP_INGRESS_CONFIG */
/* cached TP_OUT_CONFIG compressed error vector
@@ -600,6 +601,7 @@ struct port_info {
u8 vin;
u8 vivld;
u8 smt_idx;
+ u8 rx_cchan;
};
struct dentry;
@@ -878,6 +880,7 @@ struct uld_msix_info {
unsigned short vec;
char desc[IFNAMSIZ + 10];
unsigned int idx;
+ cpumask_var_t aff_mask;
};
struct vf_info {
@@ -902,10 +905,6 @@ struct mbox_list {
struct list_head list;
};
-struct mps_encap_entry {
- atomic_t refcnt;
-};
-
#if IS_ENABLED(CONFIG_THERMAL)
struct ch_thermal {
struct thermal_zone_device *tzdev;
@@ -914,6 +913,14 @@ struct ch_thermal {
};
#endif
+struct mps_entries_ref {
+ struct list_head list;
+ u8 addr[ETH_ALEN];
+ u8 mask[ETH_ALEN];
+ u16 idx;
+ refcount_t refcnt;
+};
+
struct adapter {
void __iomem *regs;
void __iomem *bar2;
@@ -938,9 +945,10 @@ struct adapter {
struct cxgb4_virt_res vres;
unsigned int swintr;
- struct {
+ struct msix_info {
unsigned short vec;
char desc[IFNAMSIZ + 10];
+ cpumask_var_t aff_mask;
} msix_info[MAX_INGQ + 1];
struct uld_msix_info *msix_info_ulds; /* msix info for uld's */
struct uld_msix_bmap msix_bmap_ulds; /* msix bitmap for all uld */
@@ -965,7 +973,6 @@ struct adapter {
unsigned int rawf_start;
unsigned int rawf_cnt;
struct smt_data *smt;
- struct mps_encap_entry *mps_encap;
struct cxgb4_uld_info *uld;
void *uld_handle[CXGB4_ULD_MAX];
unsigned int num_uld;
@@ -973,6 +980,8 @@ struct adapter {
struct list_head list_node;
struct list_head rcu_node;
struct list_head mac_hlist; /* list of MAC addresses in MPS Hash */
+ struct list_head mps_ref;
+ spinlock_t mps_ref_lock; /* lock for syncing mps ref/def activities */
void *iscsi_ppm;
@@ -1898,5 +1907,46 @@ int cxgb4_dcb_enabled(const struct net_device *dev);
int cxgb4_thermal_init(struct adapter *adap);
int cxgb4_thermal_remove(struct adapter *adap);
+int cxgb4_set_msix_aff(struct adapter *adap, unsigned short vec,
+ cpumask_var_t *aff_mask, int idx);
+void cxgb4_clear_msix_aff(unsigned short vec, cpumask_var_t aff_mask);
+
+int cxgb4_change_mac(struct port_info *pi, unsigned int viid,
+ int *tcam_idx, const u8 *addr,
+ bool persistent, u8 *smt_idx);
+
+int cxgb4_alloc_mac_filt(struct adapter *adap, unsigned int viid,
+ bool free, unsigned int naddr,
+ const u8 **addr, u16 *idx,
+ u64 *hash, bool sleep_ok);
+int cxgb4_free_mac_filt(struct adapter *adap, unsigned int viid,
+ unsigned int naddr, const u8 **addr, bool sleep_ok);
+int cxgb4_init_mps_ref_entries(struct adapter *adap);
+void cxgb4_free_mps_ref_entries(struct adapter *adap);
+int cxgb4_alloc_encap_mac_filt(struct adapter *adap, unsigned int viid,
+ const u8 *addr, const u8 *mask,
+ unsigned int vni, unsigned int vni_mask,
+ u8 dip_hit, u8 lookup_type, bool sleep_ok);
+int cxgb4_free_encap_mac_filt(struct adapter *adap, unsigned int viid,
+ int idx, bool sleep_ok);
+int cxgb4_free_raw_mac_filt(struct adapter *adap,
+ unsigned int viid,
+ const u8 *addr,
+ const u8 *mask,
+ unsigned int idx,
+ u8 lookup_type,
+ u8 port_id,
+ bool sleep_ok);
+int cxgb4_alloc_raw_mac_filt(struct adapter *adap,
+ unsigned int viid,
+ const u8 *addr,
+ const u8 *mask,
+ unsigned int idx,
+ u8 lookup_type,
+ u8 port_id,
+ bool sleep_ok);
+int cxgb4_update_mac_filt(struct port_info *pi, unsigned int viid,
+ int *tcam_idx, const u8 *addr,
+ bool persistent, u8 *smt_idx);
#endif /* __CXGB4_H__ */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
index 4107007b6ec4..43b0f8c57da7 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
@@ -248,8 +248,9 @@ static int validate_filter(struct net_device *dev,
u32 fconf, iconf;
/* Check for unconfigured fields being used. */
- fconf = adapter->params.tp.vlan_pri_map;
iconf = adapter->params.tp.ingress_config;
+ fconf = fs->hash ? adapter->params.tp.filter_mask :
+ adapter->params.tp.vlan_pri_map;
if (unsupported(fconf, FCOE_F, fs->val.fcoe, fs->mask.fcoe) ||
unsupported(fconf, PORT_F, fs->val.iport, fs->mask.iport) ||
@@ -726,10 +727,8 @@ void clear_filter(struct adapter *adap, struct filter_entry *f)
cxgb4_smt_release(f->smt);
if (f->fs.val.encap_vld && f->fs.val.ovlan_vld)
- if (atomic_dec_and_test(&adap->mps_encap[f->fs.val.ovlan &
- 0x1ff].refcnt))
- t4_free_encap_mac_filt(adap, pi->viid,
- f->fs.val.ovlan & 0x1ff, 0);
+ t4_free_encap_mac_filt(adap, pi->viid,
+ f->fs.val.ovlan & 0x1ff, 0);
if ((f->fs.hash || is_t6(adap->params.chip)) && f->fs.type)
cxgb4_clip_release(f->dev, (const u32 *)&f->fs.val.lip, 1);
@@ -1041,7 +1040,7 @@ static void mk_act_open_req6(struct filter_entry *f, struct sk_buff *skb,
RSS_QUEUE_V(f->fs.iq) |
TX_QUEUE_V(f->fs.nat_mode) |
T5_OPT_2_VALID_F |
- RX_CHANNEL_F |
+ RX_CHANNEL_V(cxgb4_port_e2cchan(f->dev)) |
CONG_CNTRL_V((f->fs.action == FILTER_DROP) |
(f->fs.dirsteer << 1)) |
PACE_V((f->fs.maskhash) |
@@ -1081,7 +1080,7 @@ static void mk_act_open_req(struct filter_entry *f, struct sk_buff *skb,
RSS_QUEUE_V(f->fs.iq) |
TX_QUEUE_V(f->fs.nat_mode) |
T5_OPT_2_VALID_F |
- RX_CHANNEL_F |
+ RX_CHANNEL_V(cxgb4_port_e2cchan(f->dev)) |
CONG_CNTRL_V((f->fs.action == FILTER_DROP) |
(f->fs.dirsteer << 1)) |
PACE_V((f->fs.maskhash) |
@@ -1176,7 +1175,6 @@ static int cxgb4_set_hash_filter(struct net_device *dev,
if (ret < 0)
goto free_atid;
- atomic_inc(&adapter->mps_encap[ret].refcnt);
f->fs.val.ovlan = ret;
f->fs.mask.ovlan = 0xffff;
f->fs.val.ovlan_vld = 1;
@@ -1419,7 +1417,6 @@ int __cxgb4_set_filter(struct net_device *dev, int filter_id,
if (ret < 0)
goto free_clip;
- atomic_inc(&adapter->mps_encap[ret].refcnt);
f->fs.val.ovlan = ret;
f->fs.mask.ovlan = 0x1ff;
f->fs.val.ovlan_vld = 1;
@@ -1833,24 +1830,38 @@ void filter_rpl(struct adapter *adap, const struct cpl_set_tcb_rpl *rpl)
}
}
-int init_hash_filter(struct adapter *adap)
+void init_hash_filter(struct adapter *adap)
{
+ u32 reg;
+
/* On T6, verify the necessary register configs and warn the user in
* case of improper config
*/
if (is_t6(adap->params.chip)) {
- if (TCAM_ACTV_HIT_G(t4_read_reg(adap, LE_DB_RSP_CODE_0_A)) != 4)
- goto err;
+ if (is_offload(adap)) {
+ if (!(t4_read_reg(adap, TP_GLOBAL_CONFIG_A)
+ & ACTIVEFILTERCOUNTS_F)) {
+ dev_err(adap->pdev_dev, "Invalid hash filter + ofld config\n");
+ return;
+ }
+ } else {
+ reg = t4_read_reg(adap, LE_DB_RSP_CODE_0_A);
+ if (TCAM_ACTV_HIT_G(reg) != 4) {
+ dev_err(adap->pdev_dev, "Invalid hash filter config\n");
+ return;
+ }
+
+ reg = t4_read_reg(adap, LE_DB_RSP_CODE_1_A);
+ if (HASH_ACTV_HIT_G(reg) != 4) {
+ dev_err(adap->pdev_dev, "Invalid hash filter config\n");
+ return;
+ }
+ }
- if (HASH_ACTV_HIT_G(t4_read_reg(adap, LE_DB_RSP_CODE_1_A)) != 4)
- goto err;
} else {
dev_err(adap->pdev_dev, "Hash filter supported only on T6\n");
- return -EINVAL;
+ return;
}
+
adap->params.hash_filter = 1;
- return 0;
-err:
- dev_warn(adap->pdev_dev, "Invalid hash filter config!\n");
- return -EINVAL;
}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.h
index 8db5fca6dcc9..b0751c0611ec 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.h
@@ -50,7 +50,7 @@ int delete_filter(struct adapter *adapter, unsigned int fidx);
int writable_filter(struct filter_entry *f);
void clear_all_filters(struct adapter *adapter);
-int init_hash_filter(struct adapter *adap);
+void init_hash_filter(struct adapter *adap);
bool is_filter_exact_match(struct adapter *adap,
struct ch_filter_specification *fs);
#endif /* __CXGB4_FILTER_H */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index 715e4edcf4a2..67202b6f352e 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -366,13 +366,19 @@ static int cxgb4_mac_sync(struct net_device *netdev, const u8 *mac_addr)
int ret;
u64 mhash = 0;
u64 uhash = 0;
+ /* idx stores the index of allocated filters,
+ * its size should be modified based on the number of
+ * MAC addresses that we allocate filters for
+ */
+
+ u16 idx[1] = {};
bool free = false;
bool ucast = is_unicast_ether_addr(mac_addr);
const u8 *maclist[1] = {mac_addr};
struct hash_mac_addr *new_entry;
- ret = t4_alloc_mac_filt(adap, adap->mbox, pi->viid, free, 1, maclist,
- NULL, ucast ? &uhash : &mhash, false);
+ ret = cxgb4_alloc_mac_filt(adap, pi->viid, free, 1, maclist,
+ idx, ucast ? &uhash : &mhash, false);
if (ret < 0)
goto out;
/* if hash != 0, then add the addr to hash addr list
@@ -410,7 +416,7 @@ static int cxgb4_mac_unsync(struct net_device *netdev, const u8 *mac_addr)
}
}
- ret = t4_free_mac_filt(adap, adap->mbox, pi->viid, 1, maclist, false);
+ ret = cxgb4_free_mac_filt(adap, pi->viid, 1, maclist, false);
return ret < 0 ? -EINVAL : 0;
}
@@ -449,9 +455,9 @@ static int set_rxmode(struct net_device *dev, int mtu, bool sleep_ok)
* Addresses are programmed to hash region, if tcam runs out of entries.
*
*/
-static int cxgb4_change_mac(struct port_info *pi, unsigned int viid,
- int *tcam_idx, const u8 *addr, bool persist,
- u8 *smt_idx)
+int cxgb4_change_mac(struct port_info *pi, unsigned int viid,
+ int *tcam_idx, const u8 *addr, bool persist,
+ u8 *smt_idx)
{
struct adapter *adapter = pi->adapter;
struct hash_mac_addr *entry, *new_entry;
@@ -505,8 +511,8 @@ static int link_start(struct net_device *dev)
ret = t4_set_rxmode(pi->adapter, mb, pi->viid, dev->mtu, -1, -1, -1,
!!(dev->features & NETIF_F_HW_VLAN_CTAG_RX), true);
if (ret == 0)
- ret = cxgb4_change_mac(pi, pi->viid, &pi->xact_addr_filt,
- dev->dev_addr, true, &pi->smt_idx);
+ ret = cxgb4_update_mac_filt(pi, pi->viid, &pi->xact_addr_filt,
+ dev->dev_addr, true, &pi->smt_idx);
if (ret == 0)
ret = t4_link_l1cfg(pi->adapter, mb, pi->tx_chan,
&pi->link_cfg);
@@ -702,9 +708,38 @@ static void name_msix_vecs(struct adapter *adap)
}
}
+int cxgb4_set_msix_aff(struct adapter *adap, unsigned short vec,
+ cpumask_var_t *aff_mask, int idx)
+{
+ int rv;
+
+ if (!zalloc_cpumask_var(aff_mask, GFP_KERNEL)) {
+ dev_err(adap->pdev_dev, "alloc_cpumask_var failed\n");
+ return -ENOMEM;
+ }
+
+ cpumask_set_cpu(cpumask_local_spread(idx, dev_to_node(adap->pdev_dev)),
+ *aff_mask);
+
+ rv = irq_set_affinity_hint(vec, *aff_mask);
+ if (rv)
+ dev_warn(adap->pdev_dev,
+ "irq_set_affinity_hint %u failed %d\n",
+ vec, rv);
+
+ return 0;
+}
+
+void cxgb4_clear_msix_aff(unsigned short vec, cpumask_var_t aff_mask)
+{
+ irq_set_affinity_hint(vec, NULL);
+ free_cpumask_var(aff_mask);
+}
+
static int request_msix_queue_irqs(struct adapter *adap)
{
struct sge *s = &adap->sge;
+ struct msix_info *minfo;
int err, ethqidx;
int msi_index = 2;
@@ -714,32 +749,77 @@ static int request_msix_queue_irqs(struct adapter *adap)
return err;
for_each_ethrxq(s, ethqidx) {
- err = request_irq(adap->msix_info[msi_index].vec,
+ minfo = &adap->msix_info[msi_index];
+ err = request_irq(minfo->vec,
t4_sge_intr_msix, 0,
- adap->msix_info[msi_index].desc,
+ minfo->desc,
&s->ethrxq[ethqidx].rspq);
if (err)
goto unwind;
+
+ cxgb4_set_msix_aff(adap, minfo->vec,
+ &minfo->aff_mask, ethqidx);
msi_index++;
}
return 0;
unwind:
- while (--ethqidx >= 0)
- free_irq(adap->msix_info[--msi_index].vec,
- &s->ethrxq[ethqidx].rspq);
+ while (--ethqidx >= 0) {
+ msi_index--;
+ minfo = &adap->msix_info[msi_index];
+ cxgb4_clear_msix_aff(minfo->vec, minfo->aff_mask);
+ free_irq(minfo->vec, &s->ethrxq[ethqidx].rspq);
+ }
free_irq(adap->msix_info[1].vec, &s->fw_evtq);
return err;
}
static void free_msix_queue_irqs(struct adapter *adap)
{
- int i, msi_index = 2;
struct sge *s = &adap->sge;
+ struct msix_info *minfo;
+ int i, msi_index = 2;
free_irq(adap->msix_info[1].vec, &s->fw_evtq);
- for_each_ethrxq(s, i)
- free_irq(adap->msix_info[msi_index++].vec, &s->ethrxq[i].rspq);
+ for_each_ethrxq(s, i) {
+ minfo = &adap->msix_info[msi_index++];
+ cxgb4_clear_msix_aff(minfo->vec, minfo->aff_mask);
+ free_irq(minfo->vec, &s->ethrxq[i].rspq);
+ }
+}
+
+static int setup_ppod_edram(struct adapter *adap)
+{
+ unsigned int param, val;
+ int ret;
+
+ /* Driver sends FW_PARAMS_PARAM_DEV_PPOD_EDRAM read command to check
+ * if firmware supports ppod edram feature or not. If firmware
+ * returns 1, then driver can enable this feature by sending
+ * FW_PARAMS_PARAM_DEV_PPOD_EDRAM write command with value 1 to
+ * enable ppod edram feature.
+ */
+ param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
+ FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_PPOD_EDRAM));
+
+ ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, &param, &val);
+ if (ret < 0) {
+ dev_warn(adap->pdev_dev,
+ "querying PPOD_EDRAM support failed: %d\n",
+ ret);
+ return -1;
+ }
+
+ if (val != 1)
+ return -1;
+
+ ret = t4_set_params(adap, adap->mbox, adap->pf, 0, 1, &param, &val);
+ if (ret < 0) {
+ dev_err(adap->pdev_dev,
+ "setting PPOD_EDRAM failed: %d\n", ret);
+ return -1;
+ }
+ return 0;
}
/**
@@ -1646,6 +1726,18 @@ unsigned int cxgb4_port_chan(const struct net_device *dev)
}
EXPORT_SYMBOL(cxgb4_port_chan);
+/**
+ * cxgb4_port_e2cchan - get the HW c-channel of a port
+ * @dev: the net device for the port
+ *
+ * Return the HW RX c-channel of the given port.
+ */
+unsigned int cxgb4_port_e2cchan(const struct net_device *dev)
+{
+ return netdev2pinfo(dev)->rx_cchan;
+}
+EXPORT_SYMBOL(cxgb4_port_e2cchan);
+
unsigned int cxgb4_dbfifo_count(const struct net_device *dev, int lpfifo)
{
struct adapter *adap = netdev2adap(dev);
@@ -2934,8 +3026,8 @@ static int cxgb_set_mac_addr(struct net_device *dev, void *p)
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
- ret = cxgb4_change_mac(pi, pi->viid, &pi->xact_addr_filt,
- addr->sa_data, true, &pi->smt_idx);
+ ret = cxgb4_update_mac_filt(pi, pi->viid, &pi->xact_addr_filt,
+ addr->sa_data, true, &pi->smt_idx);
if (ret < 0)
return ret;
@@ -3043,14 +3135,14 @@ static int cxgb_set_tx_maxrate(struct net_device *dev, int index, u32 rate)
}
static int cxgb_setup_tc_flower(struct net_device *dev,
- struct tc_cls_flower_offload *cls_flower)
+ struct flow_cls_offload *cls_flower)
{
switch (cls_flower->command) {
- case TC_CLSFLOWER_REPLACE:
+ case FLOW_CLS_REPLACE:
return cxgb4_tc_flower_replace(dev, cls_flower);
- case TC_CLSFLOWER_DESTROY:
+ case FLOW_CLS_DESTROY:
return cxgb4_tc_flower_destroy(dev, cls_flower);
- case TC_CLSFLOWER_STATS:
+ case FLOW_CLS_STATS:
return cxgb4_tc_flower_stats(dev, cls_flower);
default:
return -EOPNOTSUPP;
@@ -3098,32 +3190,19 @@ static int cxgb_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
}
}
-static int cxgb_setup_tc_block(struct net_device *dev,
- struct tc_block_offload *f)
-{
- struct port_info *pi = netdev2pinfo(dev);
-
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
- return -EOPNOTSUPP;
-
- switch (f->command) {
- case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block, cxgb_setup_tc_block_cb,
- pi, dev, f->extack);
- case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block, cxgb_setup_tc_block_cb, pi);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-}
+static LIST_HEAD(cxgb_block_cb_list);
static int cxgb_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data)
{
+ struct port_info *pi = netdev2pinfo(dev);
+
switch (type) {
case TC_SETUP_BLOCK:
- return cxgb_setup_tc_block(dev, type_data);
+ return flow_block_cb_setup_simple(type_data,
+ &cxgb_block_cb_list,
+ cxgb_setup_tc_block_cb,
+ pi, dev, true);
default:
return -EOPNOTSUPP;
}
@@ -3187,8 +3266,6 @@ static void cxgb_del_udp_tunnel(struct net_device *netdev,
i);
return;
}
- atomic_dec(&adapter->mps_encap[adapter->rawf_start +
- pi->port_id].refcnt);
}
}
@@ -3277,7 +3354,6 @@ static void cxgb_add_udp_tunnel(struct net_device *netdev,
cxgb_del_udp_tunnel(netdev, ti);
return;
}
- atomic_inc(&adapter->mps_encap[ret].refcnt);
}
}
@@ -3905,14 +3981,14 @@ static int adap_init0_phy(struct adapter *adap)
*/
static int adap_init0_config(struct adapter *adapter, int reset)
{
+ char *fw_config_file, fw_config_file_path[256];
+ u32 finiver, finicsum, cfcsum, param, val;
struct fw_caps_config_cmd caps_cmd;
- const struct firmware *cf;
unsigned long mtype = 0, maddr = 0;
- u32 finiver, finicsum, cfcsum;
- int ret;
- int config_issued = 0;
- char *fw_config_file, fw_config_file_path[256];
+ const struct firmware *cf;
char *config_name = NULL;
+ int config_issued = 0;
+ int ret;
/*
* Reset device if necessary.
@@ -4020,6 +4096,24 @@ static int adap_init0_config(struct adapter *adapter, int reset)
goto bye;
}
+ val = 0;
+
+ /* Ofld + Hash filter is supported. Older fw will fail this request and
+ * it is fine.
+ */
+ param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
+ FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_HASHFILTER_WITH_OFLD));
+ ret = t4_set_params(adapter, adapter->mbox, adapter->pf, 0,
+ 1, &param, &val);
+
+ /* FW doesn't know about Hash filter + ofld support,
+ * it's not a problem, don't return an error.
+ */
+ if (ret < 0) {
+ dev_warn(adapter->pdev_dev,
+ "Hash filter with ofld is not supported by FW\n");
+ }
+
/*
* Issue a Capability Configuration command to the firmware to get it
* to parse the Configuration File. We don't use t4_fw_config_file()
@@ -4096,6 +4190,13 @@ static int adap_init0_config(struct adapter *adapter, int reset)
dev_err(adapter->pdev_dev,
"HMA configuration failed with error %d\n", ret);
+ if (is_t6(adapter->params.chip)) {
+ ret = setup_ppod_edram(adapter);
+ if (!ret)
+ dev_info(adapter->pdev_dev, "Successfully enabled "
+ "ppod edram feature\n");
+ }
+
/*
* And finally tell the firmware to initialize itself using the
* parameters from the Configuration File.
@@ -4580,6 +4681,13 @@ static int adap_init0(struct adapter *adap)
if (ret < 0)
goto bye;
+ /* hash filter has some mandatory register settings to be tested and for
+ * that it needs to test whether offload is enabled or not, hence
+ * checking and setting it here.
+ */
+ if (caps_cmd.ofldcaps)
+ adap->params.offload = 1;
+
if (caps_cmd.ofldcaps ||
(caps_cmd.niccaps & htons(FW_CAPS_CONFIG_NIC_HASHFILTER))) {
/* query offload-related parameters */
@@ -4619,11 +4727,8 @@ static int adap_init0(struct adapter *adap)
adap->params.ofldq_wr_cred = val[5];
if (caps_cmd.niccaps & htons(FW_CAPS_CONFIG_NIC_HASHFILTER)) {
- ret = init_hash_filter(adap);
- if (ret < 0)
- goto bye;
+ init_hash_filter(adap);
} else {
- adap->params.offload = 1;
adap->num_ofld_uld += 1;
}
}
@@ -4715,6 +4820,22 @@ static int adap_init0(struct adapter *adap)
goto bye;
adap->vres.iscsi.start = val[0];
adap->vres.iscsi.size = val[1] - val[0] + 1;
+ if (is_t6(adap->params.chip)) {
+ params[0] = FW_PARAM_PFVF(PPOD_EDRAM_START);
+ params[1] = FW_PARAM_PFVF(PPOD_EDRAM_END);
+ ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2,
+ params, val);
+ if (!ret) {
+ adap->vres.ppod_edram.start = val[0];
+ adap->vres.ppod_edram.size =
+ val[1] - val[0] + 1;
+
+ dev_info(adap->pdev_dev,
+ "ppod edram start 0x%x end 0x%x size 0x%x\n",
+ val[0], val[1],
+ adap->vres.ppod_edram.size);
+ }
+ }
/* LIO target and cxgb4i initiaitor */
adap->num_ofld_uld += 2;
}
@@ -5315,7 +5436,6 @@ static void free_some_resources(struct adapter *adapter)
{
unsigned int i;
- kvfree(adapter->mps_encap);
kvfree(adapter->smt);
kvfree(adapter->l2t);
kvfree(adapter->srq);
@@ -5841,12 +5961,6 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->params.offload = 0;
}
- adapter->mps_encap = kvcalloc(adapter->params.arch.mps_tcam_size,
- sizeof(struct mps_encap_entry),
- GFP_KERNEL);
- if (!adapter->mps_encap)
- dev_warn(&pdev->dev, "could not allocate MPS Encap entries, continuing\n");
-
#if IS_ENABLED(CONFIG_IPV6)
if (chip_ver <= CHELSIO_T5 &&
(!(t4_read_reg(adapter, LE_DB_CONFIG_A) & ASLIPCOMPEN_F))) {
@@ -5922,6 +6036,8 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* check for PCI Express bandwidth capabiltites */
pcie_print_link_status(pdev);
+ cxgb4_init_mps_ref_entries(adapter);
+
err = init_rss(adapter);
if (err)
goto out_free_dev;
@@ -6048,6 +6164,8 @@ static void remove_one(struct pci_dev *pdev)
disable_interrupts(adapter);
+ cxgb4_free_mps_ref_entries(adapter);
+
for_each_port(adapter, i)
if (adapter->port[i]->reg_state == NETREG_REGISTERED)
unregister_netdev(adapter->port[i]);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_mps.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_mps.c
new file mode 100644
index 000000000000..b1a073eea60b
--- /dev/null
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_mps.c
@@ -0,0 +1,241 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2019 Chelsio Communications, Inc. All rights reserved. */
+
+#include "cxgb4.h"
+
+static int cxgb4_mps_ref_dec_by_mac(struct adapter *adap,
+ const u8 *addr, const u8 *mask)
+{
+ u8 bitmask[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ struct mps_entries_ref *mps_entry, *tmp;
+ int ret = -EINVAL;
+
+ spin_lock_bh(&adap->mps_ref_lock);
+ list_for_each_entry_safe(mps_entry, tmp, &adap->mps_ref, list) {
+ if (ether_addr_equal(mps_entry->addr, addr) &&
+ ether_addr_equal(mps_entry->mask, mask ? mask : bitmask)) {
+ if (!refcount_dec_and_test(&mps_entry->refcnt)) {
+ spin_unlock_bh(&adap->mps_ref_lock);
+ return -EBUSY;
+ }
+ list_del(&mps_entry->list);
+ kfree(mps_entry);
+ ret = 0;
+ break;
+ }
+ }
+ spin_unlock_bh(&adap->mps_ref_lock);
+ return ret;
+}
+
+static int cxgb4_mps_ref_dec(struct adapter *adap, u16 idx)
+{
+ struct mps_entries_ref *mps_entry, *tmp;
+ int ret = -EINVAL;
+
+ spin_lock(&adap->mps_ref_lock);
+ list_for_each_entry_safe(mps_entry, tmp, &adap->mps_ref, list) {
+ if (mps_entry->idx == idx) {
+ if (!refcount_dec_and_test(&mps_entry->refcnt)) {
+ spin_unlock(&adap->mps_ref_lock);
+ return -EBUSY;
+ }
+ list_del(&mps_entry->list);
+ kfree(mps_entry);
+ ret = 0;
+ break;
+ }
+ }
+ spin_unlock(&adap->mps_ref_lock);
+ return ret;
+}
+
+static int cxgb4_mps_ref_inc(struct adapter *adap, const u8 *mac_addr,
+ u16 idx, const u8 *mask)
+{
+ u8 bitmask[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ struct mps_entries_ref *mps_entry;
+ int ret = 0;
+
+ spin_lock_bh(&adap->mps_ref_lock);
+ list_for_each_entry(mps_entry, &adap->mps_ref, list) {
+ if (mps_entry->idx == idx) {
+ refcount_inc(&mps_entry->refcnt);
+ goto unlock;
+ }
+ }
+ mps_entry = kzalloc(sizeof(*mps_entry), GFP_ATOMIC);
+ if (!mps_entry) {
+ ret = -ENOMEM;
+ goto unlock;
+ }
+ ether_addr_copy(mps_entry->mask, mask ? mask : bitmask);
+ ether_addr_copy(mps_entry->addr, mac_addr);
+ mps_entry->idx = idx;
+ refcount_set(&mps_entry->refcnt, 1);
+ list_add_tail(&mps_entry->list, &adap->mps_ref);
+unlock:
+ spin_unlock_bh(&adap->mps_ref_lock);
+ return ret;
+}
+
+int cxgb4_free_mac_filt(struct adapter *adap, unsigned int viid,
+ unsigned int naddr, const u8 **addr, bool sleep_ok)
+{
+ int ret, i;
+
+ for (i = 0; i < naddr; i++) {
+ if (!cxgb4_mps_ref_dec_by_mac(adap, addr[i], NULL)) {
+ ret = t4_free_mac_filt(adap, adap->mbox, viid,
+ 1, &addr[i], sleep_ok);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ /* return number of filters freed */
+ return naddr;
+}
+
+int cxgb4_alloc_mac_filt(struct adapter *adap, unsigned int viid,
+ bool free, unsigned int naddr, const u8 **addr,
+ u16 *idx, u64 *hash, bool sleep_ok)
+{
+ int ret, i;
+
+ ret = t4_alloc_mac_filt(adap, adap->mbox, viid, free,
+ naddr, addr, idx, hash, sleep_ok);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < naddr; i++) {
+ if (idx[i] != 0xffff) {
+ if (cxgb4_mps_ref_inc(adap, addr[i], idx[i], NULL)) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ }
+ }
+
+ goto out;
+error:
+ cxgb4_free_mac_filt(adap, viid, naddr, addr, sleep_ok);
+
+out:
+ /* Returns a negative error number or the number of filters allocated */
+ return ret;
+}
+
+int cxgb4_update_mac_filt(struct port_info *pi, unsigned int viid,
+ int *tcam_idx, const u8 *addr,
+ bool persistent, u8 *smt_idx)
+{
+ int ret;
+
+ ret = cxgb4_change_mac(pi, viid, tcam_idx,
+ addr, persistent, smt_idx);
+ if (ret < 0)
+ return ret;
+
+ cxgb4_mps_ref_inc(pi->adapter, addr, *tcam_idx, NULL);
+ return ret;
+}
+
+int cxgb4_free_raw_mac_filt(struct adapter *adap,
+ unsigned int viid,
+ const u8 *addr,
+ const u8 *mask,
+ unsigned int idx,
+ u8 lookup_type,
+ u8 port_id,
+ bool sleep_ok)
+{
+ int ret = 0;
+
+ if (!cxgb4_mps_ref_dec(adap, idx))
+ ret = t4_free_raw_mac_filt(adap, viid, addr,
+ mask, idx, lookup_type,
+ port_id, sleep_ok);
+
+ return ret;
+}
+
+int cxgb4_alloc_raw_mac_filt(struct adapter *adap,
+ unsigned int viid,
+ const u8 *addr,
+ const u8 *mask,
+ unsigned int idx,
+ u8 lookup_type,
+ u8 port_id,
+ bool sleep_ok)
+{
+ int ret;
+
+ ret = t4_alloc_raw_mac_filt(adap, viid, addr,
+ mask, idx, lookup_type,
+ port_id, sleep_ok);
+ if (ret < 0)
+ return ret;
+
+ if (cxgb4_mps_ref_inc(adap, addr, ret, mask)) {
+ ret = -ENOMEM;
+ t4_free_raw_mac_filt(adap, viid, addr,
+ mask, idx, lookup_type,
+ port_id, sleep_ok);
+ }
+
+ return ret;
+}
+
+int cxgb4_free_encap_mac_filt(struct adapter *adap, unsigned int viid,
+ int idx, bool sleep_ok)
+{
+ int ret = 0;
+
+ if (!cxgb4_mps_ref_dec(adap, idx))
+ ret = t4_free_encap_mac_filt(adap, viid, idx, sleep_ok);
+
+ return ret;
+}
+
+int cxgb4_alloc_encap_mac_filt(struct adapter *adap, unsigned int viid,
+ const u8 *addr, const u8 *mask,
+ unsigned int vni, unsigned int vni_mask,
+ u8 dip_hit, u8 lookup_type, bool sleep_ok)
+{
+ int ret;
+
+ ret = t4_alloc_encap_mac_filt(adap, viid, addr, mask, vni, vni_mask,
+ dip_hit, lookup_type, sleep_ok);
+ if (ret < 0)
+ return ret;
+
+ if (cxgb4_mps_ref_inc(adap, addr, ret, mask)) {
+ ret = -ENOMEM;
+ t4_free_encap_mac_filt(adap, viid, ret, sleep_ok);
+ }
+ return ret;
+}
+
+int cxgb4_init_mps_ref_entries(struct adapter *adap)
+{
+ spin_lock_init(&adap->mps_ref_lock);
+ INIT_LIST_HEAD(&adap->mps_ref);
+
+ return 0;
+}
+
+void cxgb4_free_mps_ref_entries(struct adapter *adap)
+{
+ struct mps_entries_ref *mps_entry, *tmp;
+
+ if (!list_empty(&adap->mps_ref))
+ return;
+
+ spin_lock(&adap->mps_ref_lock);
+ list_for_each_entry_safe(mps_entry, tmp, &adap->mps_ref, list) {
+ list_del(&mps_entry->list);
+ kfree(mps_entry);
+ }
+ spin_unlock(&adap->mps_ref_lock);
+}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
index cfaf8f618d1f..312599c6b35a 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
@@ -80,10 +80,10 @@ static struct ch_tc_flower_entry *ch_flower_lookup(struct adapter *adap,
}
static void cxgb4_process_flow_match(struct net_device *dev,
- struct tc_cls_flower_offload *cls,
+ struct flow_cls_offload *cls,
struct ch_filter_specification *fs)
{
- struct flow_rule *rule = tc_cls_flower_offload_flow_rule(cls);
+ struct flow_rule *rule = flow_cls_offload_flow_rule(cls);
u16 addr_type = 0;
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
@@ -223,9 +223,9 @@ static void cxgb4_process_flow_match(struct net_device *dev,
}
static int cxgb4_validate_flow_match(struct net_device *dev,
- struct tc_cls_flower_offload *cls)
+ struct flow_cls_offload *cls)
{
- struct flow_rule *rule = tc_cls_flower_offload_flow_rule(cls);
+ struct flow_rule *rule = flow_cls_offload_flow_rule(cls);
struct flow_dissector *dissector = rule->match.dissector;
u16 ethtype_mask = 0;
u16 ethtype_key = 0;
@@ -378,10 +378,10 @@ static void process_pedit_field(struct ch_filter_specification *fs, u32 val,
}
static void cxgb4_process_flow_actions(struct net_device *in,
- struct tc_cls_flower_offload *cls,
+ struct flow_cls_offload *cls,
struct ch_filter_specification *fs)
{
- struct flow_rule *rule = tc_cls_flower_offload_flow_rule(cls);
+ struct flow_rule *rule = flow_cls_offload_flow_rule(cls);
struct flow_action_entry *act;
int i;
@@ -544,9 +544,9 @@ static bool valid_pedit_action(struct net_device *dev,
}
static int cxgb4_validate_flow_actions(struct net_device *dev,
- struct tc_cls_flower_offload *cls)
+ struct flow_cls_offload *cls)
{
- struct flow_rule *rule = tc_cls_flower_offload_flow_rule(cls);
+ struct flow_rule *rule = flow_cls_offload_flow_rule(cls);
struct flow_action_entry *act;
bool act_redir = false;
bool act_pedit = false;
@@ -633,7 +633,7 @@ static int cxgb4_validate_flow_actions(struct net_device *dev,
}
int cxgb4_tc_flower_replace(struct net_device *dev,
- struct tc_cls_flower_offload *cls)
+ struct flow_cls_offload *cls)
{
struct adapter *adap = netdev2adap(dev);
struct ch_tc_flower_entry *ch_flower;
@@ -709,7 +709,7 @@ free_entry:
}
int cxgb4_tc_flower_destroy(struct net_device *dev,
- struct tc_cls_flower_offload *cls)
+ struct flow_cls_offload *cls)
{
struct adapter *adap = netdev2adap(dev);
struct ch_tc_flower_entry *ch_flower;
@@ -783,7 +783,7 @@ static void ch_flower_stats_cb(struct timer_list *t)
}
int cxgb4_tc_flower_stats(struct net_device *dev,
- struct tc_cls_flower_offload *cls)
+ struct flow_cls_offload *cls)
{
struct adapter *adap = netdev2adap(dev);
struct ch_tc_flower_stats *ofld_stats;
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h
index 050c8a50ae41..eb4c95248baf 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h
@@ -109,11 +109,11 @@ struct ch_tc_pedit_fields {
#define PEDIT_UDP_SPORT_DPORT 0x0
int cxgb4_tc_flower_replace(struct net_device *dev,
- struct tc_cls_flower_offload *cls);
+ struct flow_cls_offload *cls);
int cxgb4_tc_flower_destroy(struct net_device *dev,
- struct tc_cls_flower_offload *cls);
+ struct flow_cls_offload *cls);
int cxgb4_tc_flower_stats(struct net_device *dev,
- struct tc_cls_flower_offload *cls);
+ struct flow_cls_offload *cls);
int cxgb4_init_tc_flower(struct adapter *adap);
void cxgb4_cleanup_tc_flower(struct adapter *adap);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c
index 6c685b920713..5b602243d573 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c
@@ -352,25 +352,32 @@ static int
request_msix_queue_irqs_uld(struct adapter *adap, unsigned int uld_type)
{
struct sge_uld_rxq_info *rxq_info = adap->sge.uld_rxq_info[uld_type];
+ struct uld_msix_info *minfo;
int err = 0;
unsigned int idx, bmap_idx;
for_each_uldrxq(rxq_info, idx) {
bmap_idx = rxq_info->msix_tbl[idx];
- err = request_irq(adap->msix_info_ulds[bmap_idx].vec,
+ minfo = &adap->msix_info_ulds[bmap_idx];
+ err = request_irq(minfo->vec,
t4_sge_intr_msix, 0,
- adap->msix_info_ulds[bmap_idx].desc,
+ minfo->desc,
&rxq_info->uldrxq[idx].rspq);
if (err)
goto unwind;
+
+ cxgb4_set_msix_aff(adap, minfo->vec,
+ &minfo->aff_mask, idx);
}
return 0;
+
unwind:
while (idx-- > 0) {
bmap_idx = rxq_info->msix_tbl[idx];
+ minfo = &adap->msix_info_ulds[bmap_idx];
+ cxgb4_clear_msix_aff(minfo->vec, minfo->aff_mask);
free_msix_idx_in_bmap(adap, bmap_idx);
- free_irq(adap->msix_info_ulds[bmap_idx].vec,
- &rxq_info->uldrxq[idx].rspq);
+ free_irq(minfo->vec, &rxq_info->uldrxq[idx].rspq);
}
return err;
}
@@ -379,14 +386,16 @@ static void
free_msix_queue_irqs_uld(struct adapter *adap, unsigned int uld_type)
{
struct sge_uld_rxq_info *rxq_info = adap->sge.uld_rxq_info[uld_type];
+ struct uld_msix_info *minfo;
unsigned int idx, bmap_idx;
for_each_uldrxq(rxq_info, idx) {
bmap_idx = rxq_info->msix_tbl[idx];
+ minfo = &adap->msix_info_ulds[bmap_idx];
+ cxgb4_clear_msix_aff(minfo->vec, minfo->aff_mask);
free_msix_idx_in_bmap(adap, bmap_idx);
- free_irq(adap->msix_info_ulds[bmap_idx].vec,
- &rxq_info->uldrxq[idx].rspq);
+ free_irq(minfo->vec, &rxq_info->uldrxq[idx].rspq);
}
}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
index 21da34a4ca24..cee582e36134 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
@@ -292,6 +292,7 @@ struct cxgb4_virt_res { /* virtualized HW resources */
struct cxgb4_range ocq;
struct cxgb4_range key;
unsigned int ncrypto_fc;
+ struct cxgb4_range ppod_edram;
};
struct chcr_stats_debug {
@@ -393,6 +394,7 @@ int cxgb4_immdata_send(struct net_device *dev, unsigned int idx,
int cxgb4_crypto_send(struct net_device *dev, struct sk_buff *skb);
unsigned int cxgb4_dbfifo_count(const struct net_device *dev, int lpfifo);
unsigned int cxgb4_port_chan(const struct net_device *dev);
+unsigned int cxgb4_port_e2cchan(const struct net_device *dev);
unsigned int cxgb4_port_viid(const struct net_device *dev);
unsigned int cxgb4_tp_smt_idx(enum chip_type chip, unsigned int viid);
unsigned int cxgb4_port_idx(const struct net_device *dev);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/sched.c b/drivers/net/ethernet/chelsio/cxgb4/sched.c
index ba6c153ee45c..60218dc676a8 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/sched.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/sched.c
@@ -207,7 +207,6 @@ static int t4_sched_queue_bind(struct port_info *pi, struct ch_sched_queue *p)
goto out_err;
/* Bind queue to specified class */
- memset(qe, 0, sizeof(*qe));
qe->cntxt_id = qid;
memcpy(&qe->param, p, sizeof(qe->param));
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
index 93feb258067b..9dd5ed9a2965 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
@@ -6209,6 +6209,37 @@ unsigned int t4_get_mps_bg_map(struct adapter *adapter, int pidx)
}
/**
+ * t4_get_tp_e2c_map - return the E2C channel map associated with a port
+ * @adapter: the adapter
+ * @pidx: the port index
+ */
+static unsigned int t4_get_tp_e2c_map(struct adapter *adapter, int pidx)
+{
+ unsigned int nports;
+ u32 param, val = 0;
+ int ret;
+
+ nports = 1 << NUMPORTS_G(t4_read_reg(adapter, MPS_CMN_CTL_A));
+ if (pidx >= nports) {
+ CH_WARN(adapter, "TP E2C Channel Port Index %d >= Nports %d\n",
+ pidx, nports);
+ return 0;
+ }
+
+ /* FW version >= 1.16.44.0 can determine E2C channel map using
+ * FW_PARAMS_PARAM_DEV_TPCHMAP API.
+ */
+ param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
+ FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_TPCHMAP));
+ ret = t4_query_params_ns(adapter, adapter->mbox, adapter->pf,
+ 0, 1, &param, &val);
+ if (!ret)
+ return (val >> (8 * pidx)) & 0xff;
+
+ return 0;
+}
+
+/**
* t4_get_tp_ch_map - return TP ingress channels associated with a port
* @adapter: the adapter
* @pidx: the port index
@@ -9368,8 +9399,9 @@ int t4_init_sge_params(struct adapter *adapter)
*/
int t4_init_tp_params(struct adapter *adap, bool sleep_ok)
{
- int chan;
- u32 v;
+ u32 param, val, v;
+ int chan, ret;
+
v = t4_read_reg(adap, TP_TIMER_RESOLUTION_A);
adap->params.tp.tre = TIMERRESOLUTION_G(v);
@@ -9379,11 +9411,47 @@ int t4_init_tp_params(struct adapter *adap, bool sleep_ok)
for (chan = 0; chan < NCHAN; chan++)
adap->params.tp.tx_modq[chan] = chan;
- /* Cache the adapter's Compressed Filter Mode and global Incress
+ /* Cache the adapter's Compressed Filter Mode/Mask and global Ingress
* Configuration.
*/
- t4_tp_pio_read(adap, &adap->params.tp.vlan_pri_map, 1,
- TP_VLAN_PRI_MAP_A, sleep_ok);
+ param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
+ FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_FILTER) |
+ FW_PARAMS_PARAM_Y_V(FW_PARAM_DEV_FILTER_MODE_MASK));
+
+ /* Read current value */
+ ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1,
+ &param, &val);
+ if (ret == 0) {
+ dev_info(adap->pdev_dev,
+ "Current filter mode/mask 0x%x:0x%x\n",
+ FW_PARAMS_PARAM_FILTER_MODE_G(val),
+ FW_PARAMS_PARAM_FILTER_MASK_G(val));
+ adap->params.tp.vlan_pri_map =
+ FW_PARAMS_PARAM_FILTER_MODE_G(val);
+ adap->params.tp.filter_mask =
+ FW_PARAMS_PARAM_FILTER_MASK_G(val);
+ } else {
+ dev_info(adap->pdev_dev,
+ "Failed to read filter mode/mask via fw api, using indirect-reg-read\n");
+
+ /* Incase of older-fw (which doesn't expose the api
+ * FW_PARAM_DEV_FILTER_MODE_MASK) and newer-driver (which uses
+ * the fw api) combination, fall-back to older method of reading
+ * the filter mode from indirect-register
+ */
+ t4_tp_pio_read(adap, &adap->params.tp.vlan_pri_map, 1,
+ TP_VLAN_PRI_MAP_A, sleep_ok);
+
+ /* With the older-fw and newer-driver combination we might run
+ * into an issue when user wants to use hash filter region but
+ * the filter_mask is zero, in this case filter_mask validation
+ * is tough. To avoid that we set the filter_mask same as filter
+ * mode, which will behave exactly as the older way of ignoring
+ * the filter mask validation.
+ */
+ adap->params.tp.filter_mask = adap->params.tp.vlan_pri_map;
+ }
+
t4_tp_pio_read(adap, &adap->params.tp.ingress_config, 1,
TP_INGRESS_CONFIG_A, sleep_ok);
@@ -9594,6 +9662,7 @@ int t4_init_portinfo(struct port_info *pi, int mbox,
pi->tx_chan = port;
pi->lport = port;
pi->rss_size = rss_size;
+ pi->rx_cchan = t4_get_tp_e2c_map(pi->adapter, port);
/* If fw supports returning the VIN as part of FW_VI_CMD,
* save the returned values.
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
index eb222d40ddbf..a957a6e4d4c4 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
@@ -1334,6 +1334,10 @@
#define TP_OUT_CONFIG_A 0x7d04
#define TP_GLOBAL_CONFIG_A 0x7d08
+#define ACTIVEFILTERCOUNTS_S 22
+#define ACTIVEFILTERCOUNTS_V(x) ((x) << ACTIVEFILTERCOUNTS_S)
+#define ACTIVEFILTERCOUNTS_F ACTIVEFILTERCOUNTS_V(1U)
+
#define TP_CMM_TCB_BASE_A 0x7d10
#define TP_CMM_MM_BASE_A 0x7d14
#define TP_CMM_TIMER_BASE_A 0x7d18
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
index b2a618e72fcf..65313f6b5704 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
@@ -1221,6 +1221,23 @@ enum fw_params_mnem {
/*
* device parameters
*/
+
+#define FW_PARAMS_PARAM_FILTER_MODE_S 16
+#define FW_PARAMS_PARAM_FILTER_MODE_M 0xffff
+#define FW_PARAMS_PARAM_FILTER_MODE_V(x) \
+ ((x) << FW_PARAMS_PARAM_FILTER_MODE_S)
+#define FW_PARAMS_PARAM_FILTER_MODE_G(x) \
+ (((x) >> FW_PARAMS_PARAM_FILTER_MODE_S) & \
+ FW_PARAMS_PARAM_FILTER_MODE_M)
+
+#define FW_PARAMS_PARAM_FILTER_MASK_S 0
+#define FW_PARAMS_PARAM_FILTER_MASK_M 0xffff
+#define FW_PARAMS_PARAM_FILTER_MASK_V(x) \
+ ((x) << FW_PARAMS_PARAM_FILTER_MASK_S)
+#define FW_PARAMS_PARAM_FILTER_MASK_G(x) \
+ (((x) >> FW_PARAMS_PARAM_FILTER_MASK_S) & \
+ FW_PARAMS_PARAM_FILTER_MASK_M)
+
enum fw_params_param_dev {
FW_PARAMS_PARAM_DEV_CCLK = 0x00, /* chip core clock in khz */
FW_PARAMS_PARAM_DEV_PORTVEC = 0x01, /* the port vector */
@@ -1250,12 +1267,16 @@ enum fw_params_param_dev {
FW_PARAMS_PARAM_DEV_RI_FR_NSMR_TPTE_WR = 0x1C,
FW_PARAMS_PARAM_DEV_FILTER2_WR = 0x1D,
FW_PARAMS_PARAM_DEV_MPSBGMAP = 0x1E,
+ FW_PARAMS_PARAM_DEV_TPCHMAP = 0x1F,
FW_PARAMS_PARAM_DEV_HMA_SIZE = 0x20,
FW_PARAMS_PARAM_DEV_RDMA_WRITE_WITH_IMM = 0x21,
+ FW_PARAMS_PARAM_DEV_PPOD_EDRAM = 0x23,
FW_PARAMS_PARAM_DEV_RI_WRITE_CMPL_WR = 0x24,
FW_PARAMS_PARAM_DEV_OPAQUE_VIID_SMT_EXTN = 0x27,
+ FW_PARAMS_PARAM_DEV_HASHFILTER_WITH_OFLD = 0x28,
FW_PARAMS_PARAM_DEV_DBQ_TIMER = 0x29,
FW_PARAMS_PARAM_DEV_DBQ_TIMERTICK = 0x2A,
+ FW_PARAMS_PARAM_DEV_FILTER = 0x2E,
};
/*
@@ -1312,6 +1333,8 @@ enum fw_params_param_pfvf {
FW_PARAMS_PARAM_PFVF_RAWF_END = 0x37,
FW_PARAMS_PARAM_PFVF_NCRYPTO_LOOKASIDE = 0x39,
FW_PARAMS_PARAM_PFVF_PORT_CAPS32 = 0x3A,
+ FW_PARAMS_PARAM_PFVF_PPOD_EDRAM_START = 0x3B,
+ FW_PARAMS_PARAM_PFVF_PPOD_EDRAM_END = 0x3C,
FW_PARAMS_PARAM_PFVF_LINK_STATE = 0x40,
};
@@ -1347,6 +1370,11 @@ enum fw_params_param_dev_diag {
FW_PARAM_DEV_DIAG_MAXTMPTHRESH = 0x02,
};
+enum fw_params_param_dev_filter {
+ FW_PARAM_DEV_FILTER_VNIC_MODE = 0x00,
+ FW_PARAM_DEV_FILTER_MODE_MASK = 0x01,
+};
+
enum fw_params_param_dev_fwcache {
FW_PARAM_DEV_FWCACHE_FLUSH = 0x00,
FW_PARAM_DEV_FWCACHE_FLUSHINV = 0x01,
diff --git a/drivers/net/ethernet/chelsio/libcxgb/libcxgb_ppm.c b/drivers/net/ethernet/chelsio/libcxgb/libcxgb_ppm.c
index e2919005ead3..21034536c9c5 100644
--- a/drivers/net/ethernet/chelsio/libcxgb/libcxgb_ppm.c
+++ b/drivers/net/ethernet/chelsio/libcxgb/libcxgb_ppm.c
@@ -123,6 +123,9 @@ static int ppm_get_cpu_entries(struct cxgbi_ppm *ppm, unsigned int count,
unsigned int cpu;
int i;
+ if (!ppm->pool)
+ return -EINVAL;
+
cpu = get_cpu();
pool = per_cpu_ptr(ppm->pool, cpu);
spin_lock_bh(&pool->lock);
@@ -169,7 +172,9 @@ static int ppm_get_entries(struct cxgbi_ppm *ppm, unsigned int count,
}
ppm->next = i + count;
- if (ppm->next >= ppm->bmap_index_max)
+ if (ppm->max_index_in_edram && (ppm->next >= ppm->max_index_in_edram))
+ ppm->next = 0;
+ else if (ppm->next >= ppm->bmap_index_max)
ppm->next = 0;
spin_unlock_bh(&ppm->map_lock);
@@ -382,18 +387,36 @@ static struct cxgbi_ppm_pool *ppm_alloc_cpu_pool(unsigned int *total,
int cxgbi_ppm_init(void **ppm_pp, struct net_device *ndev,
struct pci_dev *pdev, void *lldev,
- struct cxgbi_tag_format *tformat,
- unsigned int ppmax,
- unsigned int llimit,
- unsigned int start,
- unsigned int reserve_factor)
+ struct cxgbi_tag_format *tformat, unsigned int iscsi_size,
+ unsigned int llimit, unsigned int start,
+ unsigned int reserve_factor, unsigned int iscsi_edram_start,
+ unsigned int iscsi_edram_size)
{
struct cxgbi_ppm *ppm = (struct cxgbi_ppm *)(*ppm_pp);
struct cxgbi_ppm_pool *pool = NULL;
- unsigned int ppmax_pool = 0;
unsigned int pool_index_max = 0;
- unsigned int alloc_sz;
+ unsigned int ppmax_pool = 0;
unsigned int ppod_bmap_size;
+ unsigned int alloc_sz;
+ unsigned int ppmax;
+
+ if (!iscsi_edram_start)
+ iscsi_edram_size = 0;
+
+ if (iscsi_edram_size &&
+ ((iscsi_edram_start + iscsi_edram_size) != start)) {
+ pr_err("iscsi ppod region not contiguous: EDRAM start 0x%x "
+ "size 0x%x DDR start 0x%x\n",
+ iscsi_edram_start, iscsi_edram_size, start);
+ return -EINVAL;
+ }
+
+ if (iscsi_edram_size) {
+ reserve_factor = 0;
+ start = iscsi_edram_start;
+ }
+
+ ppmax = (iscsi_edram_size + iscsi_size) >> PPOD_SIZE_SHIFT;
if (ppm) {
pr_info("ippm: %s, ppm 0x%p,0x%p already initialized, %u/%u.\n",
@@ -434,6 +457,14 @@ int cxgbi_ppm_init(void **ppm_pp, struct net_device *ndev,
__func__, ppmax, ppmax_pool, ppod_bmap_size, start,
end);
}
+ if (iscsi_edram_size) {
+ unsigned int first_ddr_idx =
+ iscsi_edram_size >> PPOD_SIZE_SHIFT;
+
+ ppm->max_index_in_edram = first_ddr_idx - 1;
+ bitmap_set(ppm->ppod_bmap, first_ddr_idx, 1);
+ pr_debug("reserved %u ppod in bitmap\n", first_ddr_idx);
+ }
spin_lock_init(&ppm->map_lock);
kref_init(&ppm->refcnt);
diff --git a/drivers/net/ethernet/chelsio/libcxgb/libcxgb_ppm.h b/drivers/net/ethernet/chelsio/libcxgb/libcxgb_ppm.h
index a91ad766cef0..7b02c200dd1e 100644
--- a/drivers/net/ethernet/chelsio/libcxgb/libcxgb_ppm.h
+++ b/drivers/net/ethernet/chelsio/libcxgb/libcxgb_ppm.h
@@ -143,6 +143,7 @@ struct cxgbi_ppm {
spinlock_t map_lock; /* ppm map lock */
unsigned int bmap_index_max;
unsigned int next;
+ unsigned int max_index_in_edram;
unsigned long *ppod_bmap;
struct cxgbi_ppod_data ppod_data[0];
};
@@ -324,9 +325,9 @@ int cxgbi_ppm_ppods_reserve(struct cxgbi_ppm *, unsigned short nr_pages,
unsigned long caller_data);
int cxgbi_ppm_init(void **ppm_pp, struct net_device *, struct pci_dev *,
void *lldev, struct cxgbi_tag_format *,
- unsigned int ppmax, unsigned int llimit,
- unsigned int start,
- unsigned int reserve_factor);
+ unsigned int iscsi_size, unsigned int llimit,
+ unsigned int start, unsigned int reserve_factor,
+ unsigned int edram_start, unsigned int edram_size);
int cxgbi_ppm_release(struct cxgbi_ppm *ppm);
void cxgbi_tagmask_check(unsigned int tagmask, struct cxgbi_tag_format *);
unsigned int cxgbi_tagmask_set(unsigned int ppmax);
diff --git a/drivers/net/ethernet/dnet.c b/drivers/net/ethernet/dnet.c
index 79521e27f0d1..e24979010969 100644
--- a/drivers/net/ethernet/dnet.c
+++ b/drivers/net/ethernet/dnet.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Dave DNET Ethernet Controller driver
*
* Copyright (C) 2008 Dave S.r.l. <www.dave.eu>
* Copyright (C) 2009 Ilya Yanok, Emcraft Systems Ltd, <yanok@emcraft.com>
- *
- * 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.
*/
#include <linux/io.h>
#include <linux/module.h>
diff --git a/drivers/net/ethernet/dnet.h b/drivers/net/ethernet/dnet.h
index d985080bbd5d..8af6c0705ab3 100644
--- a/drivers/net/ethernet/dnet.h
+++ b/drivers/net/ethernet/dnet.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Dave DNET Ethernet Controller driver
*
* Copyright (C) 2008 Dave S.r.l. <www.dave.eu>
- *
- * 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.
*/
#ifndef _DNET_H
#define _DNET_H
diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c
index fb308b330dc1..492f8769ac12 100644
--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c
+++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c
@@ -891,7 +891,7 @@ static void be_self_test(struct net_device *netdev, struct ethtool_test *test,
u64 *data)
{
struct be_adapter *adapter = netdev_priv(netdev);
- int status;
+ int status, cnt;
u8 link_status = 0;
if (adapter->function_caps & BE_FUNCTION_CAPS_SUPER_NIC) {
@@ -902,6 +902,9 @@ static void be_self_test(struct net_device *netdev, struct ethtool_test *test,
memset(data, 0, sizeof(u64) * ETHTOOL_TESTS_NUM);
+ /* check link status before offline tests */
+ link_status = netif_carrier_ok(netdev);
+
if (test->flags & ETH_TEST_FL_OFFLINE) {
if (be_loopback_test(adapter, BE_MAC_LOOPBACK, &data[0]) != 0)
test->flags |= ETH_TEST_FL_FAILED;
@@ -922,13 +925,26 @@ static void be_self_test(struct net_device *netdev, struct ethtool_test *test,
test->flags |= ETH_TEST_FL_FAILED;
}
- status = be_cmd_link_status_query(adapter, NULL, &link_status, 0);
- if (status) {
- test->flags |= ETH_TEST_FL_FAILED;
- data[4] = -1;
- } else if (!link_status) {
+ /* link status was down prior to test */
+ if (!link_status) {
test->flags |= ETH_TEST_FL_FAILED;
data[4] = 1;
+ return;
+ }
+
+ for (cnt = 10; cnt; cnt--) {
+ status = be_cmd_link_status_query(adapter, NULL, &link_status,
+ 0);
+ if (status) {
+ test->flags |= ETH_TEST_FL_FAILED;
+ data[4] = -1;
+ break;
+ }
+
+ if (link_status)
+ break;
+
+ msleep_interruptible(500);
}
}
@@ -1101,7 +1117,7 @@ static int be_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
cmd->data = be_get_rss_hash_opts(adapter, cmd->flow_type);
break;
case ETHTOOL_GRXRINGS:
- cmd->data = adapter->num_rx_qs - 1;
+ cmd->data = adapter->num_rx_qs;
break;
default:
return -EINVAL;
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 82015c8a5ed7..b7a246b33599 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -4697,8 +4697,12 @@ int be_update_queues(struct be_adapter *adapter)
struct net_device *netdev = adapter->netdev;
int status;
- if (netif_running(netdev))
+ if (netif_running(netdev)) {
+ /* device cannot transmit now, avoid dev_watchdog timeouts */
+ netif_carrier_off(netdev);
+
be_close(netdev);
+ }
be_cancel_worker(adapter);
diff --git a/drivers/net/ethernet/ethoc.c b/drivers/net/ethernet/ethoc.c
index 71da0490521b..ea4f17f5cce7 100644
--- a/drivers/net/ethernet/ethoc.c
+++ b/drivers/net/ethernet/ethoc.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/net/ethernet/ethoc.c
*
* Copyright (C) 2007-2008 Avionic Design Development GmbH
* Copyright (C) 2008-2009 Avionic Design GmbH
*
- * 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.
- *
* Written by Thierry Reding <thierry.reding@avionic-design.de>
*/
diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c
index 055f77c70fa3..030fed65393e 100644
--- a/drivers/net/ethernet/faraday/ftgmac100.c
+++ b/drivers/net/ethernet/faraday/ftgmac100.c
@@ -1062,7 +1062,7 @@ static int ftgmac100_mii_probe(struct ftgmac100 *priv, phy_interface_t intf)
}
/* Indicate that we support PAUSE frames (see comment in
- * Documentation/networking/phy.txt)
+ * Documentation/networking/phy.rst)
*/
phy_support_asym_pause(phydev);
diff --git a/drivers/net/ethernet/freescale/dpaa2/Kconfig b/drivers/net/ethernet/freescale/dpaa2/Kconfig
index 8bd384720f80..fbef2829f3de 100644
--- a/drivers/net/ethernet/freescale/dpaa2/Kconfig
+++ b/drivers/net/ethernet/freescale/dpaa2/Kconfig
@@ -10,8 +10,7 @@ config FSL_DPAA2_ETH
config FSL_DPAA2_PTP_CLOCK
tristate "Freescale DPAA2 PTP Clock"
- depends on FSL_DPAA2_ETH
- imply PTP_1588_CLOCK
+ depends on FSL_DPAA2_ETH && PTP_1588_CLOCK_QORIQ
default y
help
This driver adds support for using the DPAA2 1588 timer module
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
index 7d2390e3df77..0acb11557ed1 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
@@ -555,7 +555,7 @@ static int build_sg_fd(struct dpaa2_eth_priv *priv,
/* Prepare the HW SGT structure */
sgt_buf_size = priv->tx_data_offset +
sizeof(struct dpaa2_sg_entry) * num_dma_bufs;
- sgt_buf = netdev_alloc_frag(sgt_buf_size + DPAA2_ETH_TX_BUF_ALIGN);
+ sgt_buf = napi_alloc_frag(sgt_buf_size + DPAA2_ETH_TX_BUF_ALIGN);
if (unlikely(!sgt_buf)) {
err = -ENOMEM;
goto sgt_buf_alloc_failed;
@@ -757,6 +757,7 @@ static netdev_tx_t dpaa2_eth_tx(struct sk_buff *skb, struct net_device *net_dev)
u16 queue_mapping;
unsigned int needed_headroom;
u32 fd_len;
+ u8 prio = 0;
int err, i;
percpu_stats = this_cpu_ptr(priv->percpu_stats);
@@ -814,6 +815,18 @@ static netdev_tx_t dpaa2_eth_tx(struct sk_buff *skb, struct net_device *net_dev)
* a queue affined to the same core that processed the Rx frame
*/
queue_mapping = skb_get_queue_mapping(skb);
+
+ if (net_dev->num_tc) {
+ prio = netdev_txq_to_tc(net_dev, queue_mapping);
+ /* Hardware interprets priority level 0 as being the highest,
+ * so we need to do a reverse mapping to the netdev tc index
+ */
+ prio = net_dev->num_tc - prio - 1;
+ /* We have only one FQ array entry for all Tx hardware queues
+ * with the same flow id (but different priority levels)
+ */
+ queue_mapping %= dpaa2_eth_queue_count(priv);
+ }
fq = &priv->fq[queue_mapping];
fd_len = dpaa2_fd_get_len(&fd);
@@ -824,7 +837,7 @@ static netdev_tx_t dpaa2_eth_tx(struct sk_buff *skb, struct net_device *net_dev)
* the Tx confirmation callback for this frame
*/
for (i = 0; i < DPAA2_ETH_ENQUEUE_RETRIES; i++) {
- err = priv->enqueue(priv, fq, &fd, 0);
+ err = priv->enqueue(priv, fq, &fd, prio);
if (err != -EBUSY)
break;
}
@@ -997,13 +1010,6 @@ static int seed_pool(struct dpaa2_eth_priv *priv, u16 bpid)
int i, j;
int new_count;
- /* This is the lazy seeding of Rx buffer pools.
- * dpaa2_add_bufs() is also used on the Rx hotpath and calls
- * napi_alloc_frag(). The trouble with that is that it in turn ends up
- * calling this_cpu_ptr(), which mandates execution in atomic context.
- * Rather than splitting up the code, do a one-off preempt disable.
- */
- preempt_disable();
for (j = 0; j < priv->num_channels; j++) {
for (i = 0; i < DPAA2_ETH_NUM_BUFS;
i += DPAA2_ETH_BUFS_PER_CMD) {
@@ -1011,12 +1017,10 @@ static int seed_pool(struct dpaa2_eth_priv *priv, u16 bpid)
priv->channel[j]->buf_count += new_count;
if (new_count < DPAA2_ETH_BUFS_PER_CMD) {
- preempt_enable();
return -ENOMEM;
}
}
}
- preempt_enable();
return 0;
}
@@ -1872,6 +1876,78 @@ static int dpaa2_eth_xdp_xmit(struct net_device *net_dev, int n,
return n - drops;
}
+static int update_xps(struct dpaa2_eth_priv *priv)
+{
+ struct net_device *net_dev = priv->net_dev;
+ struct cpumask xps_mask;
+ struct dpaa2_eth_fq *fq;
+ int i, num_queues, netdev_queues;
+ int err = 0;
+
+ num_queues = dpaa2_eth_queue_count(priv);
+ netdev_queues = (net_dev->num_tc ? : 1) * num_queues;
+
+ /* The first <num_queues> entries in priv->fq array are Tx/Tx conf
+ * queues, so only process those
+ */
+ for (i = 0; i < netdev_queues; i++) {
+ fq = &priv->fq[i % num_queues];
+
+ cpumask_clear(&xps_mask);
+ cpumask_set_cpu(fq->target_cpu, &xps_mask);
+
+ err = netif_set_xps_queue(net_dev, &xps_mask, i);
+ if (err) {
+ netdev_warn_once(net_dev, "Error setting XPS queue\n");
+ break;
+ }
+ }
+
+ return err;
+}
+
+static int dpaa2_eth_setup_tc(struct net_device *net_dev,
+ enum tc_setup_type type, void *type_data)
+{
+ struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
+ struct tc_mqprio_qopt *mqprio = type_data;
+ u8 num_tc, num_queues;
+ int i;
+
+ if (type != TC_SETUP_QDISC_MQPRIO)
+ return -EINVAL;
+
+ mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
+ num_queues = dpaa2_eth_queue_count(priv);
+ num_tc = mqprio->num_tc;
+
+ if (num_tc == net_dev->num_tc)
+ return 0;
+
+ if (num_tc > dpaa2_eth_tc_count(priv)) {
+ netdev_err(net_dev, "Max %d traffic classes supported\n",
+ dpaa2_eth_tc_count(priv));
+ return -EINVAL;
+ }
+
+ if (!num_tc) {
+ netdev_reset_tc(net_dev);
+ netif_set_real_num_tx_queues(net_dev, num_queues);
+ goto out;
+ }
+
+ netdev_set_num_tc(net_dev, num_tc);
+ netif_set_real_num_tx_queues(net_dev, num_tc * num_queues);
+
+ for (i = 0; i < num_tc; i++)
+ netdev_set_tc_queue(net_dev, i, num_queues, i * num_queues);
+
+out:
+ update_xps(priv);
+
+ return 0;
+}
+
static const struct net_device_ops dpaa2_eth_ops = {
.ndo_open = dpaa2_eth_open,
.ndo_start_xmit = dpaa2_eth_tx,
@@ -1884,6 +1960,7 @@ static const struct net_device_ops dpaa2_eth_ops = {
.ndo_change_mtu = dpaa2_eth_change_mtu,
.ndo_bpf = dpaa2_eth_xdp,
.ndo_xdp_xmit = dpaa2_eth_xdp_xmit,
+ .ndo_setup_tc = dpaa2_eth_setup_tc,
};
static void cdan_cb(struct dpaa2_io_notification_ctx *ctx)
@@ -2138,10 +2215,9 @@ static struct dpaa2_eth_channel *get_affine_channel(struct dpaa2_eth_priv *priv,
static void set_fq_affinity(struct dpaa2_eth_priv *priv)
{
struct device *dev = priv->net_dev->dev.parent;
- struct cpumask xps_mask;
struct dpaa2_eth_fq *fq;
int rx_cpu, txc_cpu;
- int i, err;
+ int i;
/* For each FQ, pick one channel/CPU to deliver frames to.
* This may well change at runtime, either through irqbalance or
@@ -2160,17 +2236,6 @@ static void set_fq_affinity(struct dpaa2_eth_priv *priv)
break;
case DPAA2_TX_CONF_FQ:
fq->target_cpu = txc_cpu;
-
- /* Tell the stack to affine to txc_cpu the Tx queue
- * associated with the confirmation one
- */
- cpumask_clear(&xps_mask);
- cpumask_set_cpu(txc_cpu, &xps_mask);
- err = netif_set_xps_queue(priv->net_dev, &xps_mask,
- fq->flowid);
- if (err)
- dev_err(dev, "Error setting XPS queue\n");
-
txc_cpu = cpumask_next(txc_cpu, &priv->dpio_cpumask);
if (txc_cpu >= nr_cpu_ids)
txc_cpu = cpumask_first(&priv->dpio_cpumask);
@@ -2180,6 +2245,8 @@ static void set_fq_affinity(struct dpaa2_eth_priv *priv)
}
fq->channel = get_affine_channel(priv, fq->target_cpu);
}
+
+ update_xps(priv);
}
static void setup_fqs(struct dpaa2_eth_priv *priv)
@@ -2361,11 +2428,10 @@ static inline int dpaa2_eth_enqueue_qd(struct dpaa2_eth_priv *priv,
static inline int dpaa2_eth_enqueue_fq(struct dpaa2_eth_priv *priv,
struct dpaa2_eth_fq *fq,
- struct dpaa2_fd *fd,
- u8 prio __always_unused)
+ struct dpaa2_fd *fd, u8 prio)
{
return dpaa2_io_service_enqueue_fq(fq->channel->dpio,
- fq->tx_fqid, fd);
+ fq->tx_fqid[prio], fd);
}
static void set_enqueue_mode(struct dpaa2_eth_priv *priv)
@@ -2479,14 +2545,9 @@ static int setup_rx_flow(struct dpaa2_eth_priv *priv,
queue.destination.type = DPNI_DEST_DPCON;
queue.destination.priority = 1;
queue.user_context = (u64)(uintptr_t)fq;
- queue.flc.stash_control = 1;
- queue.flc.value &= 0xFFFFFFFFFFFFFFC0;
- /* 01 01 00 - data, annotation, flow context */
- queue.flc.value |= 0x14;
err = dpni_set_queue(priv->mc_io, 0, priv->mc_token,
DPNI_QUEUE_RX, 0, fq->flowid,
- DPNI_QUEUE_OPT_USER_CTX | DPNI_QUEUE_OPT_DEST |
- DPNI_QUEUE_OPT_FLC,
+ DPNI_QUEUE_OPT_USER_CTX | DPNI_QUEUE_OPT_DEST,
&queue);
if (err) {
dev_err(dev, "dpni_set_queue(RX) failed\n");
@@ -2526,17 +2587,21 @@ static int setup_tx_flow(struct dpaa2_eth_priv *priv,
struct device *dev = priv->net_dev->dev.parent;
struct dpni_queue queue;
struct dpni_queue_id qid;
- int err;
+ int i, err;
- err = dpni_get_queue(priv->mc_io, 0, priv->mc_token,
- DPNI_QUEUE_TX, 0, fq->flowid, &queue, &qid);
- if (err) {
- dev_err(dev, "dpni_get_queue(TX) failed\n");
- return err;
+ for (i = 0; i < dpaa2_eth_tc_count(priv); i++) {
+ err = dpni_get_queue(priv->mc_io, 0, priv->mc_token,
+ DPNI_QUEUE_TX, i, fq->flowid,
+ &queue, &qid);
+ if (err) {
+ dev_err(dev, "dpni_get_queue(TX) failed\n");
+ return err;
+ }
+ fq->tx_fqid[i] = qid.fqid;
}
+ /* All Tx queues belonging to the same flowid have the same qdbin */
fq->tx_qdbin = qid.qdbin;
- fq->tx_fqid = qid.fqid;
err = dpni_get_queue(priv->mc_io, 0, priv->mc_token,
DPNI_QUEUE_TX_CONFIRM, 0, fq->flowid,
@@ -3236,7 +3301,7 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev)
dev = &dpni_dev->dev;
/* Net device */
- net_dev = alloc_etherdev_mq(sizeof(*priv), DPAA2_ETH_MAX_TX_QUEUES);
+ net_dev = alloc_etherdev_mq(sizeof(*priv), DPAA2_ETH_MAX_NETDEV_QUEUES);
if (!net_dev) {
dev_err(dev, "alloc_etherdev_mq() failed\n");
return -ENOMEM;
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
index e180d5a68c98..9af18c24221f 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
@@ -282,10 +282,13 @@ struct dpaa2_eth_ch_stats {
};
/* Maximum number of queues associated with a DPNI */
+#define DPAA2_ETH_MAX_TCS 8
#define DPAA2_ETH_MAX_RX_QUEUES 16
#define DPAA2_ETH_MAX_TX_QUEUES 16
#define DPAA2_ETH_MAX_QUEUES (DPAA2_ETH_MAX_RX_QUEUES + \
DPAA2_ETH_MAX_TX_QUEUES)
+#define DPAA2_ETH_MAX_NETDEV_QUEUES \
+ (DPAA2_ETH_MAX_TX_QUEUES * DPAA2_ETH_MAX_TCS)
#define DPAA2_ETH_MAX_DPCONS 16
@@ -299,8 +302,9 @@ struct dpaa2_eth_priv;
struct dpaa2_eth_fq {
u32 fqid;
u32 tx_qdbin;
- u32 tx_fqid;
+ u32 tx_fqid[DPAA2_ETH_MAX_TCS];
u16 flowid;
+ u8 tc;
int target_cpu;
u32 dq_frames;
u32 dq_bytes;
@@ -448,6 +452,9 @@ static inline int dpaa2_eth_cmp_dpni_ver(struct dpaa2_eth_priv *priv,
#define dpaa2_eth_fs_count(priv) \
((priv)->dpni_attrs.fs_entries)
+#define dpaa2_eth_tc_count(priv) \
+ ((priv)->dpni_attrs.num_tcs)
+
/* We have exactly one {Rx, Tx conf} queue per channel */
#define dpaa2_eth_queue_count(priv) \
((priv)->num_channels)
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.c
index 9b150db3b510..a9503aea527f 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.c
@@ -5,114 +5,58 @@
*/
#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/ptp_clock_kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/msi.h>
#include <linux/fsl/mc.h>
+#include <linux/fsl/ptp_qoriq.h>
#include "dpaa2-ptp.h"
-struct ptp_dpaa2_priv {
- struct fsl_mc_device *ptp_mc_dev;
- struct ptp_clock *clock;
- struct ptp_clock_info caps;
- u32 freq_comp;
-};
-
-/* PTP clock operations */
-static int ptp_dpaa2_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
+static int dpaa2_ptp_enable(struct ptp_clock_info *ptp,
+ struct ptp_clock_request *rq, int on)
{
- struct ptp_dpaa2_priv *ptp_dpaa2 =
- container_of(ptp, struct ptp_dpaa2_priv, caps);
- struct fsl_mc_device *mc_dev = ptp_dpaa2->ptp_mc_dev;
- struct device *dev = &mc_dev->dev;
- u64 adj;
- u32 diff, tmr_add;
- int neg_adj = 0;
- int err = 0;
-
- if (ppb < 0) {
- neg_adj = 1;
- ppb = -ppb;
- }
-
- tmr_add = ptp_dpaa2->freq_comp;
- adj = tmr_add;
- adj *= ppb;
- diff = div_u64(adj, 1000000000ULL);
-
- tmr_add = neg_adj ? tmr_add - diff : tmr_add + diff;
+ struct ptp_qoriq *ptp_qoriq = container_of(ptp, struct ptp_qoriq, caps);
+ struct fsl_mc_device *mc_dev;
+ struct device *dev;
+ u32 mask = 0;
+ u32 bit;
+ int err;
- err = dprtc_set_freq_compensation(mc_dev->mc_io, 0,
- mc_dev->mc_handle, tmr_add);
- if (err)
- dev_err(dev, "dprtc_set_freq_compensation err %d\n", err);
- return err;
-}
+ dev = ptp_qoriq->dev;
+ mc_dev = to_fsl_mc_device(dev);
-static int ptp_dpaa2_adjtime(struct ptp_clock_info *ptp, s64 delta)
-{
- struct ptp_dpaa2_priv *ptp_dpaa2 =
- container_of(ptp, struct ptp_dpaa2_priv, caps);
- struct fsl_mc_device *mc_dev = ptp_dpaa2->ptp_mc_dev;
- struct device *dev = &mc_dev->dev;
- s64 now;
- int err = 0;
+ switch (rq->type) {
+ case PTP_CLK_REQ_PPS:
+ bit = DPRTC_EVENT_PPS;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
- err = dprtc_get_time(mc_dev->mc_io, 0, mc_dev->mc_handle, &now);
- if (err) {
- dev_err(dev, "dprtc_get_time err %d\n", err);
+ err = dprtc_get_irq_mask(mc_dev->mc_io, 0, mc_dev->mc_handle,
+ DPRTC_IRQ_INDEX, &mask);
+ if (err < 0) {
+ dev_err(dev, "dprtc_get_irq_mask(): %d\n", err);
return err;
}
- now += delta;
+ if (on)
+ mask |= bit;
+ else
+ mask &= ~bit;
- err = dprtc_set_time(mc_dev->mc_io, 0, mc_dev->mc_handle, now);
- if (err)
- dev_err(dev, "dprtc_set_time err %d\n", err);
- return err;
-}
-
-static int ptp_dpaa2_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
-{
- struct ptp_dpaa2_priv *ptp_dpaa2 =
- container_of(ptp, struct ptp_dpaa2_priv, caps);
- struct fsl_mc_device *mc_dev = ptp_dpaa2->ptp_mc_dev;
- struct device *dev = &mc_dev->dev;
- u64 ns;
- u32 remainder;
- int err = 0;
-
- err = dprtc_get_time(mc_dev->mc_io, 0, mc_dev->mc_handle, &ns);
- if (err) {
- dev_err(dev, "dprtc_get_time err %d\n", err);
+ err = dprtc_set_irq_mask(mc_dev->mc_io, 0, mc_dev->mc_handle,
+ DPRTC_IRQ_INDEX, mask);
+ if (err < 0) {
+ dev_err(dev, "dprtc_set_irq_mask(): %d\n", err);
return err;
}
- ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder);
- ts->tv_nsec = remainder;
- return err;
-}
-
-static int ptp_dpaa2_settime(struct ptp_clock_info *ptp,
- const struct timespec64 *ts)
-{
- struct ptp_dpaa2_priv *ptp_dpaa2 =
- container_of(ptp, struct ptp_dpaa2_priv, caps);
- struct fsl_mc_device *mc_dev = ptp_dpaa2->ptp_mc_dev;
- struct device *dev = &mc_dev->dev;
- u64 ns;
- int err = 0;
-
- ns = ts->tv_sec * 1000000000ULL;
- ns += ts->tv_nsec;
-
- err = dprtc_set_time(mc_dev->mc_io, 0, mc_dev->mc_handle, ns);
- if (err)
- dev_err(dev, "dprtc_set_time err %d\n", err);
- return err;
+ return 0;
}
-static const struct ptp_clock_info ptp_dpaa2_caps = {
+static const struct ptp_clock_info dpaa2_ptp_caps = {
.owner = THIS_MODULE,
.name = "DPAA2 PTP Clock",
.max_adj = 512000,
@@ -121,21 +65,58 @@ static const struct ptp_clock_info ptp_dpaa2_caps = {
.n_per_out = 3,
.n_pins = 0,
.pps = 1,
- .adjfreq = ptp_dpaa2_adjfreq,
- .adjtime = ptp_dpaa2_adjtime,
- .gettime64 = ptp_dpaa2_gettime,
- .settime64 = ptp_dpaa2_settime,
+ .adjfine = ptp_qoriq_adjfine,
+ .adjtime = ptp_qoriq_adjtime,
+ .gettime64 = ptp_qoriq_gettime,
+ .settime64 = ptp_qoriq_settime,
+ .enable = dpaa2_ptp_enable,
};
+static irqreturn_t dpaa2_ptp_irq_handler_thread(int irq, void *priv)
+{
+ struct ptp_qoriq *ptp_qoriq = priv;
+ struct ptp_clock_event event;
+ struct fsl_mc_device *mc_dev;
+ struct device *dev;
+ u32 status = 0;
+ int err;
+
+ dev = ptp_qoriq->dev;
+ mc_dev = to_fsl_mc_device(dev);
+
+ err = dprtc_get_irq_status(mc_dev->mc_io, 0, mc_dev->mc_handle,
+ DPRTC_IRQ_INDEX, &status);
+ if (unlikely(err)) {
+ dev_err(dev, "dprtc_get_irq_status err %d\n", err);
+ return IRQ_NONE;
+ }
+
+ if (status & DPRTC_EVENT_PPS) {
+ event.type = PTP_CLOCK_PPS;
+ ptp_clock_event(ptp_qoriq->clock, &event);
+ }
+
+ err = dprtc_clear_irq_status(mc_dev->mc_io, 0, mc_dev->mc_handle,
+ DPRTC_IRQ_INDEX, status);
+ if (unlikely(err)) {
+ dev_err(dev, "dprtc_clear_irq_status err %d\n", err);
+ return IRQ_NONE;
+ }
+
+ return IRQ_HANDLED;
+}
+
static int dpaa2_ptp_probe(struct fsl_mc_device *mc_dev)
{
struct device *dev = &mc_dev->dev;
- struct ptp_dpaa2_priv *ptp_dpaa2;
- u32 tmr_add = 0;
+ struct fsl_mc_device_irq *irq;
+ struct ptp_qoriq *ptp_qoriq;
+ struct device_node *node;
+ void __iomem *base;
int err;
- ptp_dpaa2 = devm_kzalloc(dev, sizeof(*ptp_dpaa2), GFP_KERNEL);
- if (!ptp_dpaa2)
+ ptp_qoriq = devm_kzalloc(dev, sizeof(*ptp_qoriq), GFP_KERNEL);
+ if (!ptp_qoriq)
return -ENOMEM;
err = fsl_mc_portal_allocate(mc_dev, 0, &mc_dev->mc_io);
@@ -154,30 +135,60 @@ static int dpaa2_ptp_probe(struct fsl_mc_device *mc_dev)
goto err_free_mcp;
}
- ptp_dpaa2->ptp_mc_dev = mc_dev;
+ ptp_qoriq->dev = dev;
- err = dprtc_get_freq_compensation(mc_dev->mc_io, 0,
- mc_dev->mc_handle, &tmr_add);
- if (err) {
- dev_err(dev, "dprtc_get_freq_compensation err %d\n", err);
+ node = of_find_compatible_node(NULL, NULL, "fsl,dpaa2-ptp");
+ if (!node) {
+ err = -ENODEV;
goto err_close;
}
- ptp_dpaa2->freq_comp = tmr_add;
- ptp_dpaa2->caps = ptp_dpaa2_caps;
+ dev->of_node = node;
- ptp_dpaa2->clock = ptp_clock_register(&ptp_dpaa2->caps, dev);
- if (IS_ERR(ptp_dpaa2->clock)) {
- err = PTR_ERR(ptp_dpaa2->clock);
+ base = of_iomap(node, 0);
+ if (!base) {
+ err = -ENOMEM;
goto err_close;
}
- dpaa2_phc_index = ptp_clock_index(ptp_dpaa2->clock);
+ err = fsl_mc_allocate_irqs(mc_dev);
+ if (err) {
+ dev_err(dev, "MC irqs allocation failed\n");
+ goto err_unmap;
+ }
+
+ irq = mc_dev->irqs[0];
+ ptp_qoriq->irq = irq->msi_desc->irq;
- dev_set_drvdata(dev, ptp_dpaa2);
+ err = devm_request_threaded_irq(dev, ptp_qoriq->irq, NULL,
+ dpaa2_ptp_irq_handler_thread,
+ IRQF_NO_SUSPEND | IRQF_ONESHOT,
+ dev_name(dev), ptp_qoriq);
+ if (err < 0) {
+ dev_err(dev, "devm_request_threaded_irq(): %d\n", err);
+ goto err_free_mc_irq;
+ }
+
+ err = dprtc_set_irq_enable(mc_dev->mc_io, 0, mc_dev->mc_handle,
+ DPRTC_IRQ_INDEX, 1);
+ if (err < 0) {
+ dev_err(dev, "dprtc_set_irq_enable(): %d\n", err);
+ goto err_free_mc_irq;
+ }
+
+ err = ptp_qoriq_init(ptp_qoriq, base, &dpaa2_ptp_caps);
+ if (err)
+ goto err_free_mc_irq;
+
+ dpaa2_phc_index = ptp_qoriq->phc_index;
+ dev_set_drvdata(dev, ptp_qoriq);
return 0;
+err_free_mc_irq:
+ fsl_mc_free_irqs(mc_dev);
+err_unmap:
+ iounmap(base);
err_close:
dprtc_close(mc_dev->mc_io, 0, mc_dev->mc_handle);
err_free_mcp:
@@ -188,12 +199,15 @@ err_exit:
static int dpaa2_ptp_remove(struct fsl_mc_device *mc_dev)
{
- struct ptp_dpaa2_priv *ptp_dpaa2;
struct device *dev = &mc_dev->dev;
+ struct ptp_qoriq *ptp_qoriq;
+
+ ptp_qoriq = dev_get_drvdata(dev);
- ptp_dpaa2 = dev_get_drvdata(dev);
- ptp_clock_unregister(ptp_dpaa2->clock);
+ dpaa2_phc_index = -1;
+ ptp_qoriq_free(ptp_qoriq);
+ fsl_mc_free_irqs(mc_dev);
dprtc_close(mc_dev->mc_io, 0, mc_dev->mc_handle);
fsl_mc_portal_free(mc_dev->mc_io);
diff --git a/drivers/net/ethernet/freescale/dpaa2/dprtc-cmd.h b/drivers/net/ethernet/freescale/dpaa2/dprtc-cmd.h
index 9af4ac71f347..720cd50f5895 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dprtc-cmd.h
+++ b/drivers/net/ethernet/freescale/dpaa2/dprtc-cmd.h
@@ -17,22 +17,54 @@
#define DPRTC_CMDID_CLOSE DPRTC_CMD(0x800)
#define DPRTC_CMDID_OPEN DPRTC_CMD(0x810)
-#define DPRTC_CMDID_SET_FREQ_COMPENSATION DPRTC_CMD(0x1d1)
-#define DPRTC_CMDID_GET_FREQ_COMPENSATION DPRTC_CMD(0x1d2)
-#define DPRTC_CMDID_GET_TIME DPRTC_CMD(0x1d3)
-#define DPRTC_CMDID_SET_TIME DPRTC_CMD(0x1d4)
+#define DPRTC_CMDID_SET_IRQ_ENABLE DPRTC_CMD(0x012)
+#define DPRTC_CMDID_GET_IRQ_ENABLE DPRTC_CMD(0x013)
+#define DPRTC_CMDID_SET_IRQ_MASK DPRTC_CMD(0x014)
+#define DPRTC_CMDID_GET_IRQ_MASK DPRTC_CMD(0x015)
+#define DPRTC_CMDID_GET_IRQ_STATUS DPRTC_CMD(0x016)
+#define DPRTC_CMDID_CLEAR_IRQ_STATUS DPRTC_CMD(0x017)
#pragma pack(push, 1)
struct dprtc_cmd_open {
__le32 dprtc_id;
};
-struct dprtc_get_freq_compensation {
- __le32 freq_compensation;
+struct dprtc_cmd_get_irq {
+ __le32 pad;
+ u8 irq_index;
};
-struct dprtc_time {
- __le64 time;
+struct dprtc_cmd_set_irq_enable {
+ u8 en;
+ u8 pad[3];
+ u8 irq_index;
+};
+
+struct dprtc_rsp_get_irq_enable {
+ u8 en;
+};
+
+struct dprtc_cmd_set_irq_mask {
+ __le32 mask;
+ u8 irq_index;
+};
+
+struct dprtc_rsp_get_irq_mask {
+ __le32 mask;
+};
+
+struct dprtc_cmd_get_irq_status {
+ __le32 status;
+ u8 irq_index;
+};
+
+struct dprtc_rsp_get_irq_status {
+ __le32 status;
+};
+
+struct dprtc_cmd_clear_irq_status {
+ __le32 status;
+ u8 irq_index;
};
#pragma pack(pop)
diff --git a/drivers/net/ethernet/freescale/dpaa2/dprtc.c b/drivers/net/ethernet/freescale/dpaa2/dprtc.c
index c13e09bc7b9d..ed52a34fa6a1 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dprtc.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dprtc.c
@@ -74,121 +74,220 @@ int dprtc_close(struct fsl_mc_io *mc_io,
}
/**
- * dprtc_set_freq_compensation() - Sets a new frequency compensation value.
+ * dprtc_set_irq_enable() - Set overall interrupt state.
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPRTC object
+ * @irq_index: The interrupt index to configure
+ * @en: Interrupt state - enable = 1, disable = 0
*
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRTC object
- * @freq_compensation: The new frequency compensation value to set.
+ * Allows GPP software to control when interrupts are generated.
+ * Each interrupt can have up to 32 causes. The enable/disable control's the
+ * overall interrupt state. if the interrupt is disabled no causes will cause
+ * an interrupt.
*
* Return: '0' on Success; Error code otherwise.
*/
-int dprtc_set_freq_compensation(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u32 freq_compensation)
+int dprtc_set_irq_enable(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u8 irq_index,
+ u8 en)
{
- struct dprtc_get_freq_compensation *cmd_params;
+ struct dprtc_cmd_set_irq_enable *cmd_params;
struct fsl_mc_command cmd = { 0 };
- cmd.header = mc_encode_cmd_header(DPRTC_CMDID_SET_FREQ_COMPENSATION,
+ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_SET_IRQ_ENABLE,
cmd_flags,
token);
- cmd_params = (struct dprtc_get_freq_compensation *)cmd.params;
- cmd_params->freq_compensation = cpu_to_le32(freq_compensation);
+ cmd_params = (struct dprtc_cmd_set_irq_enable *)cmd.params;
+ cmd_params->irq_index = irq_index;
+ cmd_params->en = en;
return mc_send_command(mc_io, &cmd);
}
/**
- * dprtc_get_freq_compensation() - Retrieves the frequency compensation value
+ * dprtc_get_irq_enable() - Get overall interrupt state
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPRTC object
+ * @irq_index: The interrupt index to configure
+ * @en: Returned interrupt state - enable = 1, disable = 0
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dprtc_get_irq_enable(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u8 irq_index,
+ u8 *en)
+{
+ struct dprtc_rsp_get_irq_enable *rsp_params;
+ struct dprtc_cmd_get_irq *cmd_params;
+ struct fsl_mc_command cmd = { 0 };
+ int err;
+
+ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_IRQ_ENABLE,
+ cmd_flags,
+ token);
+ cmd_params = (struct dprtc_cmd_get_irq *)cmd.params;
+ cmd_params->irq_index = irq_index;
+
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ rsp_params = (struct dprtc_rsp_get_irq_enable *)cmd.params;
+ *en = rsp_params->en;
+
+ return 0;
+}
+
+/**
+ * dprtc_set_irq_mask() - Set interrupt mask.
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPRTC object
+ * @irq_index: The interrupt index to configure
+ * @mask: Event mask to trigger interrupt;
+ * each bit:
+ * 0 = ignore event
+ * 1 = consider event for asserting IRQ
+ *
+ * Every interrupt can have up to 32 causes and the interrupt model supports
+ * masking/unmasking each cause independently
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dprtc_set_irq_mask(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u8 irq_index,
+ u32 mask)
+{
+ struct dprtc_cmd_set_irq_mask *cmd_params;
+ struct fsl_mc_command cmd = { 0 };
+
+ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_SET_IRQ_MASK,
+ cmd_flags,
+ token);
+ cmd_params = (struct dprtc_cmd_set_irq_mask *)cmd.params;
+ cmd_params->mask = cpu_to_le32(mask);
+ cmd_params->irq_index = irq_index;
+
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dprtc_get_irq_mask() - Get interrupt mask.
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPRTC object
+ * @irq_index: The interrupt index to configure
+ * @mask: Returned event mask to trigger interrupt
*
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRTC object
- * @freq_compensation: Frequency compensation value
+ * Every interrupt can have up to 32 causes and the interrupt model supports
+ * masking/unmasking each cause independently
*
* Return: '0' on Success; Error code otherwise.
*/
-int dprtc_get_freq_compensation(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u32 *freq_compensation)
+int dprtc_get_irq_mask(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u8 irq_index,
+ u32 *mask)
{
- struct dprtc_get_freq_compensation *rsp_params;
+ struct dprtc_rsp_get_irq_mask *rsp_params;
+ struct dprtc_cmd_get_irq *cmd_params;
struct fsl_mc_command cmd = { 0 };
int err;
- cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_FREQ_COMPENSATION,
+ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_IRQ_MASK,
cmd_flags,
token);
+ cmd_params = (struct dprtc_cmd_get_irq *)cmd.params;
+ cmd_params->irq_index = irq_index;
err = mc_send_command(mc_io, &cmd);
if (err)
return err;
- rsp_params = (struct dprtc_get_freq_compensation *)cmd.params;
- *freq_compensation = le32_to_cpu(rsp_params->freq_compensation);
+ rsp_params = (struct dprtc_rsp_get_irq_mask *)cmd.params;
+ *mask = le32_to_cpu(rsp_params->mask);
return 0;
}
/**
- * dprtc_get_time() - Returns the current RTC time.
+ * dprtc_get_irq_status() - Get the current status of any pending interrupts.
*
* @mc_io: Pointer to MC portal's I/O object
* @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
* @token: Token of DPRTC object
- * @time: Current RTC time.
+ * @irq_index: The interrupt index to configure
+ * @status: Returned interrupts status - one bit per cause:
+ * 0 = no interrupt pending
+ * 1 = interrupt pending
*
* Return: '0' on Success; Error code otherwise.
*/
-int dprtc_get_time(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- uint64_t *time)
+int dprtc_get_irq_status(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u8 irq_index,
+ u32 *status)
{
- struct dprtc_time *rsp_params;
+ struct dprtc_cmd_get_irq_status *cmd_params;
+ struct dprtc_rsp_get_irq_status *rsp_params;
struct fsl_mc_command cmd = { 0 };
int err;
- cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_TIME,
+ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_IRQ_STATUS,
cmd_flags,
token);
+ cmd_params = (struct dprtc_cmd_get_irq_status *)cmd.params;
+ cmd_params->status = cpu_to_le32(*status);
+ cmd_params->irq_index = irq_index;
err = mc_send_command(mc_io, &cmd);
if (err)
return err;
- rsp_params = (struct dprtc_time *)cmd.params;
- *time = le64_to_cpu(rsp_params->time);
+ rsp_params = (struct dprtc_rsp_get_irq_status *)cmd.params;
+ *status = le32_to_cpu(rsp_params->status);
return 0;
}
/**
- * dprtc_set_time() - Updates current RTC time.
+ * dprtc_clear_irq_status() - Clear a pending interrupt's status
*
* @mc_io: Pointer to MC portal's I/O object
* @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
* @token: Token of DPRTC object
- * @time: New RTC time.
+ * @irq_index: The interrupt index to configure
+ * @status: Bits to clear (W1C) - one bit per cause:
+ * 0 = don't change
+ * 1 = clear status bit
*
* Return: '0' on Success; Error code otherwise.
*/
-int dprtc_set_time(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- uint64_t time)
+int dprtc_clear_irq_status(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u8 irq_index,
+ u32 status)
{
- struct dprtc_time *cmd_params;
+ struct dprtc_cmd_clear_irq_status *cmd_params;
struct fsl_mc_command cmd = { 0 };
- cmd.header = mc_encode_cmd_header(DPRTC_CMDID_SET_TIME,
+ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_CLEAR_IRQ_STATUS,
cmd_flags,
token);
- cmd_params = (struct dprtc_time *)cmd.params;
- cmd_params->time = cpu_to_le64(time);
+ cmd_params = (struct dprtc_cmd_clear_irq_status *)cmd.params;
+ cmd_params->irq_index = irq_index;
+ cmd_params->status = cpu_to_le32(status);
return mc_send_command(mc_io, &cmd);
}
diff --git a/drivers/net/ethernet/freescale/dpaa2/dprtc.h b/drivers/net/ethernet/freescale/dpaa2/dprtc.h
index fe19618d6cdf..be7914c1634d 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dprtc.h
+++ b/drivers/net/ethernet/freescale/dpaa2/dprtc.h
@@ -13,6 +13,14 @@
struct fsl_mc_io;
+/**
+ * Number of irq's
+ */
+#define DPRTC_MAX_IRQ_NUM 1
+#define DPRTC_IRQ_INDEX 0
+
+#define DPRTC_EVENT_PPS 0x08000000
+
int dprtc_open(struct fsl_mc_io *mc_io,
u32 cmd_flags,
int dprtc_id,
@@ -22,24 +30,40 @@ int dprtc_close(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token);
-int dprtc_set_freq_compensation(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u32 freq_compensation);
-
-int dprtc_get_freq_compensation(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u32 *freq_compensation);
-
-int dprtc_get_time(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- uint64_t *time);
-
-int dprtc_set_time(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- uint64_t time);
+int dprtc_set_irq_enable(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u8 irq_index,
+ u8 en);
+
+int dprtc_get_irq_enable(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u8 irq_index,
+ u8 *en);
+
+int dprtc_set_irq_mask(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u8 irq_index,
+ u32 mask);
+
+int dprtc_get_irq_mask(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u8 irq_index,
+ u32 *mask);
+
+int dprtc_get_irq_status(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u8 irq_index,
+ u32 *status);
+
+int dprtc_clear_irq_status(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u8 irq_index,
+ u32 status);
#endif /* __FSL_DPRTC_H */
diff --git a/drivers/net/ethernet/freescale/enetc/Kconfig b/drivers/net/ethernet/freescale/enetc/Kconfig
index 8429f5c1d810..ed0d010c7cf2 100644
--- a/drivers/net/ethernet/freescale/enetc/Kconfig
+++ b/drivers/net/ethernet/freescale/enetc/Kconfig
@@ -29,3 +29,13 @@ config FSL_ENETC_PTP_CLOCK
packets using the SO_TIMESTAMPING API.
If compiled as module (M), the module name is fsl-enetc-ptp.
+
+config FSL_ENETC_HW_TIMESTAMPING
+ bool "ENETC hardware timestamping support"
+ depends on FSL_ENETC || FSL_ENETC_VF
+ help
+ Enable hardware timestamping support on the Ethernet packets
+ using the SO_TIMESTAMPING API. Because the RX BD ring dynamic
+ allocation has not been supported and it is too expensive to use
+ extended RX BDs if timestamping is not used, this option enables
+ extended RX BDs in order to support hardware timestamping.
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
index 491475d87736..223709443ea4 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
@@ -13,7 +13,8 @@
#define ENETC_MAX_SKB_FRAGS 13
#define ENETC_TXBDS_MAX_NEEDED ENETC_TXBDS_NEEDED(ENETC_MAX_SKB_FRAGS + 1)
-static int enetc_map_tx_buffs(struct enetc_bdr *tx_ring, struct sk_buff *skb);
+static int enetc_map_tx_buffs(struct enetc_bdr *tx_ring, struct sk_buff *skb,
+ int active_offloads);
netdev_tx_t enetc_xmit(struct sk_buff *skb, struct net_device *ndev)
{
@@ -33,7 +34,7 @@ netdev_tx_t enetc_xmit(struct sk_buff *skb, struct net_device *ndev)
return NETDEV_TX_BUSY;
}
- count = enetc_map_tx_buffs(tx_ring, skb);
+ count = enetc_map_tx_buffs(tx_ring, skb, priv->active_offloads);
if (unlikely(!count))
goto drop_packet_err;
@@ -105,7 +106,8 @@ static void enetc_free_tx_skb(struct enetc_bdr *tx_ring,
}
}
-static int enetc_map_tx_buffs(struct enetc_bdr *tx_ring, struct sk_buff *skb)
+static int enetc_map_tx_buffs(struct enetc_bdr *tx_ring, struct sk_buff *skb,
+ int active_offloads)
{
struct enetc_tx_swbd *tx_swbd;
struct skb_frag_struct *frag;
@@ -137,7 +139,10 @@ static int enetc_map_tx_buffs(struct enetc_bdr *tx_ring, struct sk_buff *skb)
count++;
do_vlan = skb_vlan_tag_present(skb);
- do_tstamp = skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP;
+ do_tstamp = (active_offloads & ENETC_F_TX_TSTAMP) &&
+ (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP);
+ tx_swbd->do_tstamp = do_tstamp;
+ tx_swbd->check_wb = tx_swbd->do_tstamp;
if (do_vlan || do_tstamp)
flags |= ENETC_TXBD_FLAGS_EX;
@@ -299,24 +304,70 @@ static int enetc_bd_ready_count(struct enetc_bdr *tx_ring, int ci)
return pi >= ci ? pi - ci : tx_ring->bd_count - ci + pi;
}
+static void enetc_get_tx_tstamp(struct enetc_hw *hw, union enetc_tx_bd *txbd,
+ u64 *tstamp)
+{
+ u32 lo, hi, tstamp_lo;
+
+ lo = enetc_rd(hw, ENETC_SICTR0);
+ hi = enetc_rd(hw, ENETC_SICTR1);
+ tstamp_lo = le32_to_cpu(txbd->wb.tstamp);
+ if (lo <= tstamp_lo)
+ hi -= 1;
+ *tstamp = (u64)hi << 32 | tstamp_lo;
+}
+
+static void enetc_tstamp_tx(struct sk_buff *skb, u64 tstamp)
+{
+ struct skb_shared_hwtstamps shhwtstamps;
+
+ if (skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS) {
+ memset(&shhwtstamps, 0, sizeof(shhwtstamps));
+ shhwtstamps.hwtstamp = ns_to_ktime(tstamp);
+ skb_tstamp_tx(skb, &shhwtstamps);
+ }
+}
+
static bool enetc_clean_tx_ring(struct enetc_bdr *tx_ring, int napi_budget)
{
struct net_device *ndev = tx_ring->ndev;
int tx_frm_cnt = 0, tx_byte_cnt = 0;
struct enetc_tx_swbd *tx_swbd;
int i, bds_to_clean;
+ bool do_tstamp;
+ u64 tstamp = 0;
i = tx_ring->next_to_clean;
tx_swbd = &tx_ring->tx_swbd[i];
bds_to_clean = enetc_bd_ready_count(tx_ring, i);
+ do_tstamp = false;
+
while (bds_to_clean && tx_frm_cnt < ENETC_DEFAULT_TX_WORK) {
bool is_eof = !!tx_swbd->skb;
+ if (unlikely(tx_swbd->check_wb)) {
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ union enetc_tx_bd *txbd;
+
+ txbd = ENETC_TXBD(*tx_ring, i);
+
+ if (txbd->flags & ENETC_TXBD_FLAGS_W &&
+ tx_swbd->do_tstamp) {
+ enetc_get_tx_tstamp(&priv->si->hw, txbd,
+ &tstamp);
+ do_tstamp = true;
+ }
+ }
+
if (likely(tx_swbd->dma))
enetc_unmap_tx_buff(tx_ring, tx_swbd);
if (is_eof) {
+ if (unlikely(do_tstamp)) {
+ enetc_tstamp_tx(tx_swbd->skb, tstamp);
+ do_tstamp = false;
+ }
napi_consume_skb(tx_swbd->skb, napi_budget);
tx_swbd->skb = NULL;
}
@@ -425,10 +476,38 @@ static int enetc_refill_rx_ring(struct enetc_bdr *rx_ring, const int buff_cnt)
return j;
}
+#ifdef CONFIG_FSL_ENETC_HW_TIMESTAMPING
+static void enetc_get_rx_tstamp(struct net_device *ndev,
+ union enetc_rx_bd *rxbd,
+ struct sk_buff *skb)
+{
+ struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ struct enetc_hw *hw = &priv->si->hw;
+ u32 lo, hi, tstamp_lo;
+ u64 tstamp;
+
+ if (le16_to_cpu(rxbd->r.flags) & ENETC_RXBD_FLAG_TSTMP) {
+ lo = enetc_rd(hw, ENETC_SICTR0);
+ hi = enetc_rd(hw, ENETC_SICTR1);
+ tstamp_lo = le32_to_cpu(rxbd->r.tstamp);
+ if (lo <= tstamp_lo)
+ hi -= 1;
+
+ tstamp = (u64)hi << 32 | tstamp_lo;
+ memset(shhwtstamps, 0, sizeof(*shhwtstamps));
+ shhwtstamps->hwtstamp = ns_to_ktime(tstamp);
+ }
+}
+#endif
+
static void enetc_get_offloads(struct enetc_bdr *rx_ring,
union enetc_rx_bd *rxbd, struct sk_buff *skb)
{
- /* TODO: add tstamp, hashing */
+#ifdef CONFIG_FSL_ENETC_HW_TIMESTAMPING
+ struct enetc_ndev_priv *priv = netdev_priv(rx_ring->ndev);
+#endif
+ /* TODO: hashing */
if (rx_ring->ndev->features & NETIF_F_RXCSUM) {
u16 inet_csum = le16_to_cpu(rxbd->r.inet_csum);
@@ -442,6 +521,10 @@ static void enetc_get_offloads(struct enetc_bdr *rx_ring,
if (le16_to_cpu(rxbd->r.flags) & ENETC_RXBD_FLAG_VLAN)
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
le16_to_cpu(rxbd->r.vlan_opt));
+#ifdef CONFIG_FSL_ENETC_HW_TIMESTAMPING
+ if (priv->active_offloads & ENETC_F_RX_TSTAMP)
+ enetc_get_rx_tstamp(rx_ring->ndev, rxbd, skb);
+#endif
}
static void enetc_process_skb(struct enetc_bdr *rx_ring,
@@ -1074,6 +1157,9 @@ static void enetc_setup_rxbdr(struct enetc_hw *hw, struct enetc_bdr *rx_ring)
enetc_rxbdr_wr(hw, idx, ENETC_RBICIR0, ENETC_RBICIR0_ICEN | 0x1);
rbmr = ENETC_RBMR_EN;
+#ifdef CONFIG_FSL_ENETC_HW_TIMESTAMPING
+ rbmr |= ENETC_RBMR_BDS;
+#endif
if (rx_ring->ndev->features & NETIF_F_HW_VLAN_CTAG_RX)
rbmr |= ENETC_RBMR_VTE;
@@ -1341,6 +1427,62 @@ int enetc_close(struct net_device *ndev)
return 0;
}
+int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
+ void *type_data)
+{
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ struct tc_mqprio_qopt *mqprio = type_data;
+ struct enetc_bdr *tx_ring;
+ u8 num_tc;
+ int i;
+
+ if (type != TC_SETUP_QDISC_MQPRIO)
+ return -EOPNOTSUPP;
+
+ mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
+ num_tc = mqprio->num_tc;
+
+ if (!num_tc) {
+ netdev_reset_tc(ndev);
+ netif_set_real_num_tx_queues(ndev, priv->num_tx_rings);
+
+ /* Reset all ring priorities to 0 */
+ for (i = 0; i < priv->num_tx_rings; i++) {
+ tx_ring = priv->tx_ring[i];
+ enetc_set_bdr_prio(&priv->si->hw, tx_ring->index, 0);
+ }
+
+ return 0;
+ }
+
+ /* Check if we have enough BD rings available to accommodate all TCs */
+ if (num_tc > priv->num_tx_rings) {
+ netdev_err(ndev, "Max %d traffic classes supported\n",
+ priv->num_tx_rings);
+ return -EINVAL;
+ }
+
+ /* For the moment, we use only one BD ring per TC.
+ *
+ * Configure num_tc BD rings with increasing priorities.
+ */
+ for (i = 0; i < num_tc; i++) {
+ tx_ring = priv->tx_ring[i];
+ enetc_set_bdr_prio(&priv->si->hw, tx_ring->index, i);
+ }
+
+ /* Reset the number of netdev queues based on the TC count */
+ netif_set_real_num_tx_queues(ndev, num_tc);
+
+ netdev_set_num_tc(ndev, num_tc);
+
+ /* Each TC is associated with one netdev queue */
+ for (i = 0; i < num_tc; i++)
+ netdev_set_tc_queue(ndev, i, 1, i);
+
+ return 0;
+}
+
struct net_device_stats *enetc_get_stats(struct net_device *ndev)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
@@ -1396,6 +1538,70 @@ int enetc_set_features(struct net_device *ndev,
return 0;
}
+#ifdef CONFIG_FSL_ENETC_HW_TIMESTAMPING
+static int enetc_hwtstamp_set(struct net_device *ndev, struct ifreq *ifr)
+{
+ struct enetc_ndev_priv *priv = 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:
+ priv->active_offloads &= ~ENETC_F_TX_TSTAMP;
+ break;
+ case HWTSTAMP_TX_ON:
+ priv->active_offloads |= ENETC_F_TX_TSTAMP;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ switch (config.rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ priv->active_offloads &= ~ENETC_F_RX_TSTAMP;
+ break;
+ default:
+ priv->active_offloads |= ENETC_F_RX_TSTAMP;
+ config.rx_filter = HWTSTAMP_FILTER_ALL;
+ }
+
+ return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
+ -EFAULT : 0;
+}
+
+static int enetc_hwtstamp_get(struct net_device *ndev, struct ifreq *ifr)
+{
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ struct hwtstamp_config config;
+
+ config.flags = 0;
+
+ if (priv->active_offloads & ENETC_F_TX_TSTAMP)
+ config.tx_type = HWTSTAMP_TX_ON;
+ else
+ config.tx_type = HWTSTAMP_TX_OFF;
+
+ config.rx_filter = (priv->active_offloads & ENETC_F_RX_TSTAMP) ?
+ HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE;
+
+ return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
+ -EFAULT : 0;
+}
+#endif
+
+int enetc_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
+{
+#ifdef CONFIG_FSL_ENETC_HW_TIMESTAMPING
+ if (cmd == SIOCSHWTSTAMP)
+ return enetc_hwtstamp_set(ndev, rq);
+ if (cmd == SIOCGHWTSTAMP)
+ return enetc_hwtstamp_get(ndev, rq);
+#endif
+ return -EINVAL;
+}
+
int enetc_alloc_msix(struct enetc_ndev_priv *priv)
{
struct pci_dev *pdev = priv->si->pdev;
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index b274135c5103..541b4e2073fe 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -21,7 +21,9 @@ struct enetc_tx_swbd {
struct sk_buff *skb;
dma_addr_t dma;
u16 len;
- u16 is_dma_page;
+ u8 is_dma_page:1;
+ u8 check_wb:1;
+ u8 do_tstamp:1;
};
#define ENETC_RX_MAXFRM_SIZE ENETC_MAC_MAXFRM_SIZE
@@ -167,6 +169,12 @@ struct enetc_cls_rule {
#define ENETC_MAX_BDR_INT 2 /* fixed to max # of available cpus */
+/* TODO: more hardware offloads */
+enum enetc_active_offloads {
+ ENETC_F_RX_TSTAMP = BIT(0),
+ ENETC_F_TX_TSTAMP = BIT(1),
+};
+
struct enetc_ndev_priv {
struct net_device *ndev;
struct device *dev; /* dma-mapping device */
@@ -178,6 +186,7 @@ struct enetc_ndev_priv {
u16 rx_bd_count, tx_bd_count;
u16 msg_enable;
+ int active_offloads;
struct enetc_bdr *tx_ring[16];
struct enetc_bdr *rx_ring[16];
@@ -200,6 +209,9 @@ struct enetc_msg_cmd_set_primary_mac {
#define ENETC_CBDR_TIMEOUT 1000 /* usecs */
+/* PTP driver exports */
+extern int enetc_phc_index;
+
/* SI common */
int enetc_pci_probe(struct pci_dev *pdev, const char *name, int sizeof_priv);
void enetc_pci_remove(struct pci_dev *pdev);
@@ -216,6 +228,10 @@ netdev_tx_t enetc_xmit(struct sk_buff *skb, struct net_device *ndev);
struct net_device_stats *enetc_get_stats(struct net_device *ndev);
int enetc_set_features(struct net_device *ndev,
netdev_features_t features);
+int enetc_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd);
+int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
+ void *type_data);
+
/* ethtool */
void enetc_set_ethtool_ops(struct net_device *ndev);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
index b9519b6ad727..fcb52efec075 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
@@ -555,6 +555,35 @@ static void enetc_get_ringparam(struct net_device *ndev,
}
}
+static int enetc_get_ts_info(struct net_device *ndev,
+ struct ethtool_ts_info *info)
+{
+ int *phc_idx;
+
+ phc_idx = symbol_get(enetc_phc_index);
+ if (phc_idx) {
+ info->phc_index = *phc_idx;
+ symbol_put(enetc_phc_index);
+ } else {
+ info->phc_index = -1;
+ }
+
+#ifdef CONFIG_FSL_ENETC_HW_TIMESTAMPING
+ info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE;
+
+ info->tx_types = (1 << HWTSTAMP_TX_OFF) |
+ (1 << HWTSTAMP_TX_ON);
+ info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
+ (1 << HWTSTAMP_FILTER_ALL);
+#else
+ info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE |
+ SOF_TIMESTAMPING_SOFTWARE;
+#endif
+ return 0;
+}
+
static const struct ethtool_ops enetc_pf_ethtool_ops = {
.get_regs_len = enetc_get_reglen,
.get_regs = enetc_get_regs,
@@ -571,6 +600,7 @@ static const struct ethtool_ops enetc_pf_ethtool_ops = {
.get_link_ksettings = phy_ethtool_get_link_ksettings,
.set_link_ksettings = phy_ethtool_set_link_ksettings,
.get_link = ethtool_op_get_link,
+ .get_ts_info = enetc_get_ts_info,
};
static const struct ethtool_ops enetc_vf_ethtool_ops = {
@@ -586,6 +616,7 @@ static const struct ethtool_ops enetc_vf_ethtool_ops = {
.set_rxfh = enetc_set_rxfh,
.get_ringparam = enetc_get_ringparam,
.get_link = ethtool_op_get_link,
+ .get_ts_info = enetc_get_ts_info,
};
void enetc_set_ethtool_ops(struct net_device *ndev)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
index df8eb8882d92..88276299f447 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
@@ -127,7 +127,7 @@ enum enetc_bdr_type {TX, RX};
#define ENETC_TBSR_BUSY BIT(0)
#define ENETC_TBMR_VIH BIT(9)
#define ENETC_TBMR_PRIO_MASK GENMASK(2, 0)
-#define ENETC_TBMR_PRIO_SET(val) val
+#define ENETC_TBMR_SET_PRIO(val) ((val) & ENETC_TBMR_PRIO_MASK)
#define ENETC_TBMR_EN BIT(31)
#define ENETC_TBSR 0x4
#define ENETC_TBBAR0 0x10
@@ -361,6 +361,12 @@ union enetc_tx_bd {
u8 e_flags;
u8 flags;
} ext; /* Tx BD extension */
+ struct {
+ __le32 tstamp;
+ u8 reserved[10];
+ u8 status;
+ u8 flags;
+ } wb; /* writeback descriptor */
};
#define ENETC_TXBD_FLAGS_L4CS BIT(0)
@@ -399,6 +405,9 @@ union enetc_rx_bd {
struct {
__le64 addr;
u8 reserved[8];
+#ifdef CONFIG_FSL_ENETC_HW_TIMESTAMPING
+ u8 reserved1[16];
+#endif
} w;
struct {
__le16 inet_csum;
@@ -413,6 +422,10 @@ union enetc_rx_bd {
};
__le32 lstatus;
};
+#ifdef CONFIG_FSL_ENETC_HW_TIMESTAMPING
+ __le32 tstamp;
+ u8 reserved[12];
+#endif
} r;
};
@@ -531,3 +544,13 @@ static inline void enetc_enable_txvlan(struct enetc_hw *hw, int si_idx,
val = (val & ~ENETC_TBMR_VIH) | (en ? ENETC_TBMR_VIH : 0);
enetc_txbdr_wr(hw, si_idx, ENETC_TBMR, val);
}
+
+static inline void enetc_set_bdr_prio(struct enetc_hw *hw, int bdr_idx,
+ int prio)
+{
+ u32 val = enetc_txbdr_rd(hw, bdr_idx, ENETC_TBMR);
+
+ val &= ~ENETC_TBMR_PRIO_MASK;
+ val |= ENETC_TBMR_SET_PRIO(prio);
+ enetc_txbdr_wr(hw, bdr_idx, ENETC_TBMR, val);
+}
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
index 78287c517095..258b3cb38a6f 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -702,6 +702,8 @@ static const struct net_device_ops enetc_ndev_ops = {
.ndo_set_vf_vlan = enetc_pf_set_vf_vlan,
.ndo_set_vf_spoofchk = enetc_pf_set_vf_spoofchk,
.ndo_set_features = enetc_pf_set_features,
+ .ndo_do_ioctl = enetc_ioctl,
+ .ndo_setup_tc = enetc_setup_tc,
};
static void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ptp.c b/drivers/net/ethernet/freescale/enetc/enetc_ptp.c
index 8c1497e7d9c5..2fd2586e42bf 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_ptp.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_ptp.c
@@ -7,6 +7,9 @@
#include "enetc.h"
+int enetc_phc_index = -1;
+EXPORT_SYMBOL(enetc_phc_index);
+
static struct ptp_clock_info enetc_ptp_caps = {
.owner = THIS_MODULE,
.name = "ENETC PTP clock",
@@ -96,6 +99,7 @@ static int enetc_ptp_probe(struct pci_dev *pdev,
if (err)
goto err_no_clock;
+ enetc_phc_index = ptp_qoriq->phc_index;
pci_set_drvdata(pdev, ptp_qoriq);
return 0;
@@ -119,6 +123,7 @@ static void enetc_ptp_remove(struct pci_dev *pdev)
{
struct ptp_qoriq *ptp_qoriq = pci_get_drvdata(pdev);
+ enetc_phc_index = -1;
ptp_qoriq_free(ptp_qoriq);
kfree(ptp_qoriq);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_vf.c b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
index 72c3ea887bcf..ebd21bf4cfa1 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_vf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
@@ -111,6 +111,8 @@ static const struct net_device_ops enetc_ndev_ops = {
.ndo_get_stats = enetc_get_stats,
.ndo_set_mac_address = enetc_vf_set_mac_addr,
.ndo_set_features = enetc_vf_set_features,
+ .ndo_do_ioctl = enetc_ioctl,
+ .ndo_setup_tc = enetc_setup_tc,
};
static void enetc_vf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 38f10f7dcbc3..e5610a4da539 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1689,10 +1689,10 @@ static void fec_get_mac(struct net_device *ndev)
*/
if (!is_valid_ether_addr(iap)) {
/* Report it and use a random ethernet address instead */
- netdev_err(ndev, "Invalid MAC address: %pM\n", iap);
+ dev_err(&fep->pdev->dev, "Invalid MAC address: %pM\n", iap);
eth_hw_addr_random(ndev);
- netdev_info(ndev, "Using random MAC address: %pM\n",
- ndev->dev_addr);
+ dev_info(&fep->pdev->dev, "Using random MAC address: %pM\n",
+ ndev->dev_addr);
return;
}
@@ -2446,30 +2446,31 @@ static int
fec_enet_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *ec)
{
struct fec_enet_private *fep = netdev_priv(ndev);
+ struct device *dev = &fep->pdev->dev;
unsigned int cycle;
if (!(fep->quirks & FEC_QUIRK_HAS_COALESCE))
return -EOPNOTSUPP;
if (ec->rx_max_coalesced_frames > 255) {
- pr_err("Rx coalesced frames exceed hardware limitation\n");
+ dev_err(dev, "Rx coalesced frames exceed hardware limitation\n");
return -EINVAL;
}
if (ec->tx_max_coalesced_frames > 255) {
- pr_err("Tx coalesced frame exceed hardware limitation\n");
+ dev_err(dev, "Tx coalesced frame exceed hardware limitation\n");
return -EINVAL;
}
cycle = fec_enet_us_to_itr_clock(ndev, fep->rx_time_itr);
if (cycle > 0xFFFF) {
- pr_err("Rx coalesced usec exceed hardware limitation\n");
+ dev_err(dev, "Rx coalesced usec exceed hardware limitation\n");
return -EINVAL;
}
cycle = fec_enet_us_to_itr_clock(ndev, fep->tx_time_itr);
if (cycle > 0xFFFF) {
- pr_err("Rx coalesced usec exceed hardware limitation\n");
+ dev_err(dev, "Rx coalesced usec exceed hardware limitation\n");
return -EINVAL;
}
@@ -3143,8 +3144,6 @@ static int fec_enet_init(struct net_device *ndev)
return -ENOMEM;
}
- memset(cbd_base, 0, bd_size);
-
/* Get the Ethernet address */
fec_get_mac(ndev);
/* make sure MAC we just acquired is programmed into the hw */
@@ -3473,7 +3472,6 @@ fec_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev,
"Failed to enable phy regulator: %d\n", ret);
- clk_disable_unprepare(fep->clk_ipg);
goto failed_regulator;
}
} else {
diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c
index 7e892b1cbd3d..19e2365be7d8 100644
--- a/drivers/net/ethernet/freescale/fec_ptp.c
+++ b/drivers/net/ethernet/freescale/fec_ptp.c
@@ -617,7 +617,7 @@ void fec_ptp_init(struct platform_device *pdev, int irq_idx)
fep->ptp_clock = ptp_clock_register(&fep->ptp_caps, &pdev->dev);
if (IS_ERR(fep->ptp_clock)) {
fep->ptp_clock = NULL;
- pr_err("ptp_clock_register failed\n");
+ dev_err(&pdev->dev, "ptp_clock_register failed\n");
}
schedule_delayed_work(&fep->time_keep, HZ);
diff --git a/drivers/net/ethernet/freescale/fman/fman_keygen.c b/drivers/net/ethernet/freescale/fman/fman_keygen.c
index f54da3c684d0..e1bdfed16134 100644
--- a/drivers/net/ethernet/freescale/fman/fman_keygen.c
+++ b/drivers/net/ethernet/freescale/fman/fman_keygen.c
@@ -144,7 +144,8 @@
/* Hash Key extraction fields: */
#define DEFAULT_HASH_KEY_EXTRACT_FIELDS \
(KG_SCH_KN_IPSRC1 | KG_SCH_KN_IPDST1 | \
- KG_SCH_KN_L4PSRC | KG_SCH_KN_L4PDST)
+ KG_SCH_KN_L4PSRC | KG_SCH_KN_L4PDST | \
+ KG_SCH_KN_IPSEC_SPI)
/* Default values to be used as hash key in case IPv4 or L4 (TCP, UDP)
* don't exist in the frame
diff --git a/drivers/net/ethernet/google/Kconfig b/drivers/net/ethernet/google/Kconfig
new file mode 100644
index 000000000000..b8f04d052fda
--- /dev/null
+++ b/drivers/net/ethernet/google/Kconfig
@@ -0,0 +1,27 @@
+#
+# Google network device configuration
+#
+
+config NET_VENDOR_GOOGLE
+ bool "Google Devices"
+ default y
+ help
+ If you have a network (Ethernet) device belonging to this class, say Y.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Google devices. If you say Y, you will be asked
+ for your specific device in the following questions.
+
+if NET_VENDOR_GOOGLE
+
+config GVE
+ tristate "Google Virtual NIC (gVNIC) support"
+ depends on PCI_MSI
+ help
+ This driver supports Google Virtual NIC (gVNIC)"
+
+ To compile this driver as a module, choose M here.
+ The module will be called gve.
+
+endif #NET_VENDOR_GOOGLE
diff --git a/drivers/net/ethernet/google/Makefile b/drivers/net/ethernet/google/Makefile
new file mode 100644
index 000000000000..402cc3ba1639
--- /dev/null
+++ b/drivers/net/ethernet/google/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Google network device drivers.
+#
+
+obj-$(CONFIG_GVE) += gve/
diff --git a/drivers/net/ethernet/google/gve/Makefile b/drivers/net/ethernet/google/gve/Makefile
new file mode 100644
index 000000000000..3354ce40eb97
--- /dev/null
+++ b/drivers/net/ethernet/google/gve/Makefile
@@ -0,0 +1,4 @@
+# Makefile for the Google virtual Ethernet (gve) driver
+
+obj-$(CONFIG_GVE) += gve.o
+gve-objs := gve_main.o gve_tx.o gve_rx.o gve_ethtool.o gve_adminq.o
diff --git a/drivers/net/ethernet/google/gve/gve.h b/drivers/net/ethernet/google/gve/gve.h
new file mode 100644
index 000000000000..92372dc43be8
--- /dev/null
+++ b/drivers/net/ethernet/google/gve/gve.h
@@ -0,0 +1,459 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
+ * Google virtual Ethernet (gve) driver
+ *
+ * Copyright (C) 2015-2019 Google, Inc.
+ */
+
+#ifndef _GVE_H_
+#define _GVE_H_
+
+#include <linux/dma-mapping.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/u64_stats_sync.h>
+#include "gve_desc.h"
+
+#ifndef PCI_VENDOR_ID_GOOGLE
+#define PCI_VENDOR_ID_GOOGLE 0x1ae0
+#endif
+
+#define PCI_DEV_ID_GVNIC 0x0042
+
+#define GVE_REGISTER_BAR 0
+#define GVE_DOORBELL_BAR 2
+
+/* Driver can alloc up to 2 segments for the header and 2 for the payload. */
+#define GVE_TX_MAX_IOVEC 4
+/* 1 for management, 1 for rx, 1 for tx */
+#define GVE_MIN_MSIX 3
+
+/* 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 */
+ dma_addr_t bus; /* the bus for the desc_ring */
+ u32 cnt; /* free-running total number of completed packets */
+ u32 fill_cnt; /* free-running total number of descriptors posted */
+ u32 mask; /* masks the cnt to the size of the ring */
+ u8 seqno; /* the next expected seqno for this desc*/
+};
+
+/* The page info for a single slot in the RX data queue */
+struct gve_rx_slot_page_info {
+ struct page *page;
+ void *page_address;
+ u32 page_offset; /* offset to write to in page */
+};
+
+/* A list of pages registered with the device during setup and used by a queue
+ * as buffers
+ */
+struct gve_queue_page_list {
+ u32 id; /* unique id */
+ u32 num_entries;
+ struct page **pages; /* list of num_entries pages */
+ dma_addr_t *page_buses; /* the dma addrs of the pages */
+};
+
+/* Each slot in the data ring has a 1:1 mapping to a slot in the desc ring */
+struct gve_rx_data_queue {
+ struct gve_rx_data_slot *data_ring; /* read by NIC */
+ dma_addr_t data_bus; /* dma mapping of the slots */
+ struct gve_rx_slot_page_info *page_info; /* page info of the buffers */
+ struct gve_queue_page_list *qpl; /* qpl assigned to this queue */
+ u32 mask; /* masks the cnt to the size of the ring */
+ u32 cnt; /* free-running total number of completed packets */
+};
+
+struct gve_priv;
+
+/* An RX ring that contains a power-of-two sized desc and data ring. */
+struct gve_rx_ring {
+ struct gve_priv *gve;
+ struct gve_rx_desc_queue desc;
+ struct gve_rx_data_queue data;
+ u64 rbytes; /* free-running bytes received */
+ u64 rpackets; /* free-running packets received */
+ u32 q_num; /* queue index */
+ u32 ntfy_id; /* notification block index */
+ struct gve_queue_resources *q_resources; /* head and tail pointer idx */
+ dma_addr_t q_resources_bus; /* dma address for the queue resources */
+ struct u64_stats_sync statss; /* sync stats for 32bit archs */
+};
+
+/* A TX desc ring entry */
+union gve_tx_desc {
+ struct gve_tx_pkt_desc pkt; /* first desc for a packet */
+ struct gve_tx_seg_desc seg; /* subsequent descs for a packet */
+};
+
+/* Tracks the memory in the fifo occupied by a segment of a packet */
+struct gve_tx_iovec {
+ u32 iov_offset; /* offset into this segment */
+ u32 iov_len; /* length */
+ u32 iov_padding; /* padding associated with this segment */
+};
+
+/* Tracks the memory in the fifo occupied by the skb. Mapped 1:1 to a desc
+ * ring entry but only used for a pkt_desc not a seg_desc
+ */
+struct gve_tx_buffer_state {
+ struct sk_buff *skb; /* skb for this pkt */
+ struct gve_tx_iovec iov[GVE_TX_MAX_IOVEC]; /* segments of this pkt */
+};
+
+/* A TX buffer - each queue has one */
+struct gve_tx_fifo {
+ void *base; /* address of base of FIFO */
+ u32 size; /* total size */
+ atomic_t available; /* how much space is still available */
+ u32 head; /* offset to write at */
+ struct gve_queue_page_list *qpl; /* QPL mapped into this FIFO */
+};
+
+/* A TX ring that contains a power-of-two sized desc ring and a FIFO buffer */
+struct gve_tx_ring {
+ /* Cacheline 0 -- Accessed & dirtied during transmit */
+ struct gve_tx_fifo tx_fifo;
+ u32 req; /* driver tracked head pointer */
+ u32 done; /* driver tracked tail pointer */
+
+ /* Cacheline 1 -- Accessed & dirtied during gve_clean_tx_done */
+ __be32 last_nic_done ____cacheline_aligned; /* NIC tail pointer */
+ u64 pkt_done; /* free-running - total packets completed */
+ u64 bytes_done; /* free-running - total bytes completed */
+
+ /* Cacheline 2 -- Read-mostly fields */
+ union gve_tx_desc *desc ____cacheline_aligned;
+ struct gve_tx_buffer_state *info; /* Maps 1:1 to a desc */
+ struct netdev_queue *netdev_txq;
+ struct gve_queue_resources *q_resources; /* head and tail pointer idx */
+ u32 mask; /* masks req and done down to queue size */
+
+ /* Slow-path fields */
+ u32 q_num ____cacheline_aligned; /* queue idx */
+ u32 stop_queue; /* count of queue stops */
+ u32 wake_queue; /* count of queue wakes */
+ u32 ntfy_id; /* notification block index */
+ dma_addr_t bus; /* dma address of the descr ring */
+ dma_addr_t q_resources_bus; /* dma address of the queue resources */
+ struct u64_stats_sync statss; /* sync stats for 32bit archs */
+} ____cacheline_aligned;
+
+/* Wraps the info for one irq including the napi struct and the queues
+ * associated with that irq.
+ */
+struct gve_notify_block {
+ __be32 irq_db_index; /* idx into Bar2 - set by device, must be 1st */
+ char name[IFNAMSIZ + 16]; /* name registered with the kernel */
+ struct napi_struct napi; /* kernel napi struct for this block */
+ struct gve_priv *priv;
+ struct gve_tx_ring *tx; /* tx rings on this block */
+ struct gve_rx_ring *rx; /* rx rings on this block */
+} ____cacheline_aligned;
+
+/* Tracks allowed and current queue settings */
+struct gve_queue_config {
+ u16 max_queues;
+ u16 num_queues; /* current */
+};
+
+/* Tracks the available and used qpl IDs */
+struct gve_qpl_config {
+ u32 qpl_map_size; /* map memory size */
+ unsigned long *qpl_id_map; /* bitmap of used qpl ids */
+};
+
+struct gve_priv {
+ struct net_device *dev;
+ struct gve_tx_ring *tx; /* array of tx_cfg.num_queues */
+ struct gve_rx_ring *rx; /* array of rx_cfg.num_queues */
+ struct gve_queue_page_list *qpls; /* array of num qpls */
+ struct gve_notify_block *ntfy_blocks; /* array of num_ntfy_blks */
+ dma_addr_t ntfy_block_bus;
+ struct msix_entry *msix_vectors; /* array of num_ntfy_blks + 1 */
+ char mgmt_msix_name[IFNAMSIZ + 16];
+ u32 mgmt_msix_idx;
+ __be32 *counter_array; /* array of num_event_counters */
+ dma_addr_t counter_array_bus;
+
+ 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 rx_pages_per_qpl; /* rx buffer length */
+ u64 max_registered_pages;
+ u64 num_registered_pages; /* num pages registered with NIC */
+ u32 rx_copybreak; /* copy packets smaller than this */
+ u16 default_num_queues; /* default num queues to set up */
+
+ struct gve_queue_config tx_cfg;
+ struct gve_queue_config rx_cfg;
+ struct gve_qpl_config qpl_cfg; /* map used QPL ids */
+ u32 num_ntfy_blks; /* spilt between TX and RX so must be even */
+
+ struct gve_registers __iomem *reg_bar0; /* see gve_register.h */
+ __be32 __iomem *db_bar2; /* "array" of doorbells */
+ u32 msg_enable; /* level for netif* netdev print macros */
+ struct pci_dev *pdev;
+
+ /* metrics */
+ u32 tx_timeo_cnt;
+
+ /* Admin queue - see gve_adminq.h*/
+ union gve_adminq_command *adminq;
+ dma_addr_t adminq_bus_addr;
+ u32 adminq_mask; /* masks prod_cnt to adminq size */
+ u32 adminq_prod_cnt; /* free-running count of AQ cmds executed */
+
+ struct workqueue_struct *gve_wq;
+ struct work_struct service_task;
+ unsigned long service_task_flags;
+ unsigned long state_flags;
+};
+
+enum gve_service_task_flags {
+ GVE_PRIV_FLAGS_DO_RESET = BIT(1),
+ GVE_PRIV_FLAGS_RESET_IN_PROGRESS = BIT(2),
+ GVE_PRIV_FLAGS_PROBE_IN_PROGRESS = BIT(3),
+};
+
+enum gve_state_flags {
+ GVE_PRIV_FLAGS_ADMIN_QUEUE_OK = BIT(1),
+ GVE_PRIV_FLAGS_DEVICE_RESOURCES_OK = BIT(2),
+ GVE_PRIV_FLAGS_DEVICE_RINGS_OK = BIT(3),
+ GVE_PRIV_FLAGS_NAPI_ENABLED = BIT(4),
+};
+
+static inline bool gve_get_do_reset(struct gve_priv *priv)
+{
+ return test_bit(GVE_PRIV_FLAGS_DO_RESET, &priv->service_task_flags);
+}
+
+static inline void gve_set_do_reset(struct gve_priv *priv)
+{
+ set_bit(GVE_PRIV_FLAGS_DO_RESET, &priv->service_task_flags);
+}
+
+static inline void gve_clear_do_reset(struct gve_priv *priv)
+{
+ clear_bit(GVE_PRIV_FLAGS_DO_RESET, &priv->service_task_flags);
+}
+
+static inline bool gve_get_reset_in_progress(struct gve_priv *priv)
+{
+ return test_bit(GVE_PRIV_FLAGS_RESET_IN_PROGRESS,
+ &priv->service_task_flags);
+}
+
+static inline void gve_set_reset_in_progress(struct gve_priv *priv)
+{
+ set_bit(GVE_PRIV_FLAGS_RESET_IN_PROGRESS, &priv->service_task_flags);
+}
+
+static inline void gve_clear_reset_in_progress(struct gve_priv *priv)
+{
+ clear_bit(GVE_PRIV_FLAGS_RESET_IN_PROGRESS, &priv->service_task_flags);
+}
+
+static inline bool gve_get_probe_in_progress(struct gve_priv *priv)
+{
+ return test_bit(GVE_PRIV_FLAGS_PROBE_IN_PROGRESS,
+ &priv->service_task_flags);
+}
+
+static inline void gve_set_probe_in_progress(struct gve_priv *priv)
+{
+ set_bit(GVE_PRIV_FLAGS_PROBE_IN_PROGRESS, &priv->service_task_flags);
+}
+
+static inline void gve_clear_probe_in_progress(struct gve_priv *priv)
+{
+ clear_bit(GVE_PRIV_FLAGS_PROBE_IN_PROGRESS, &priv->service_task_flags);
+}
+
+static inline bool gve_get_admin_queue_ok(struct gve_priv *priv)
+{
+ return test_bit(GVE_PRIV_FLAGS_ADMIN_QUEUE_OK, &priv->state_flags);
+}
+
+static inline void gve_set_admin_queue_ok(struct gve_priv *priv)
+{
+ set_bit(GVE_PRIV_FLAGS_ADMIN_QUEUE_OK, &priv->state_flags);
+}
+
+static inline void gve_clear_admin_queue_ok(struct gve_priv *priv)
+{
+ clear_bit(GVE_PRIV_FLAGS_ADMIN_QUEUE_OK, &priv->state_flags);
+}
+
+static inline bool gve_get_device_resources_ok(struct gve_priv *priv)
+{
+ return test_bit(GVE_PRIV_FLAGS_DEVICE_RESOURCES_OK, &priv->state_flags);
+}
+
+static inline void gve_set_device_resources_ok(struct gve_priv *priv)
+{
+ set_bit(GVE_PRIV_FLAGS_DEVICE_RESOURCES_OK, &priv->state_flags);
+}
+
+static inline void gve_clear_device_resources_ok(struct gve_priv *priv)
+{
+ clear_bit(GVE_PRIV_FLAGS_DEVICE_RESOURCES_OK, &priv->state_flags);
+}
+
+static inline bool gve_get_device_rings_ok(struct gve_priv *priv)
+{
+ return test_bit(GVE_PRIV_FLAGS_DEVICE_RINGS_OK, &priv->state_flags);
+}
+
+static inline void gve_set_device_rings_ok(struct gve_priv *priv)
+{
+ set_bit(GVE_PRIV_FLAGS_DEVICE_RINGS_OK, &priv->state_flags);
+}
+
+static inline void gve_clear_device_rings_ok(struct gve_priv *priv)
+{
+ clear_bit(GVE_PRIV_FLAGS_DEVICE_RINGS_OK, &priv->state_flags);
+}
+
+static inline bool gve_get_napi_enabled(struct gve_priv *priv)
+{
+ return test_bit(GVE_PRIV_FLAGS_NAPI_ENABLED, &priv->state_flags);
+}
+
+static inline void gve_set_napi_enabled(struct gve_priv *priv)
+{
+ set_bit(GVE_PRIV_FLAGS_NAPI_ENABLED, &priv->state_flags);
+}
+
+static inline void gve_clear_napi_enabled(struct gve_priv *priv)
+{
+ clear_bit(GVE_PRIV_FLAGS_NAPI_ENABLED, &priv->state_flags);
+}
+
+/* Returns the address of the ntfy_blocks irq doorbell
+ */
+static inline __be32 __iomem *gve_irq_doorbell(struct gve_priv *priv,
+ struct gve_notify_block *block)
+{
+ return &priv->db_bar2[be32_to_cpu(block->irq_db_index)];
+}
+
+/* Returns the index into ntfy_blocks of the given tx ring's block
+ */
+static inline u32 gve_tx_idx_to_ntfy(struct gve_priv *priv, u32 queue_idx)
+{
+ return queue_idx;
+}
+
+/* Returns the index into ntfy_blocks of the given rx ring's block
+ */
+static inline u32 gve_rx_idx_to_ntfy(struct gve_priv *priv, u32 queue_idx)
+{
+ return (priv->num_ntfy_blks / 2) + queue_idx;
+}
+
+/* Returns the number of tx queue page lists
+ */
+static inline u32 gve_num_tx_qpls(struct gve_priv *priv)
+{
+ return priv->tx_cfg.num_queues;
+}
+
+/* Returns the number of rx queue page lists
+ */
+static inline u32 gve_num_rx_qpls(struct gve_priv *priv)
+{
+ return priv->rx_cfg.num_queues;
+}
+
+/* Returns a pointer to the next available tx qpl in the list of qpls
+ */
+static inline
+struct gve_queue_page_list *gve_assign_tx_qpl(struct gve_priv *priv)
+{
+ int id = find_first_zero_bit(priv->qpl_cfg.qpl_id_map,
+ priv->qpl_cfg.qpl_map_size);
+
+ /* we are out of tx qpls */
+ if (id >= gve_num_tx_qpls(priv))
+ return NULL;
+
+ set_bit(id, priv->qpl_cfg.qpl_id_map);
+ return &priv->qpls[id];
+}
+
+/* Returns a pointer to the next available rx qpl in the list of qpls
+ */
+static inline
+struct gve_queue_page_list *gve_assign_rx_qpl(struct gve_priv *priv)
+{
+ int id = find_next_zero_bit(priv->qpl_cfg.qpl_id_map,
+ priv->qpl_cfg.qpl_map_size,
+ gve_num_tx_qpls(priv));
+
+ /* we are out of rx qpls */
+ if (id == priv->qpl_cfg.qpl_map_size)
+ return NULL;
+
+ set_bit(id, priv->qpl_cfg.qpl_id_map);
+ return &priv->qpls[id];
+}
+
+/* Unassigns the qpl with the given id
+ */
+static inline void gve_unassign_qpl(struct gve_priv *priv, int id)
+{
+ clear_bit(id, priv->qpl_cfg.qpl_id_map);
+}
+
+/* Returns the correct dma direction for tx and rx qpls
+ */
+static inline enum dma_data_direction gve_qpl_dma_dir(struct gve_priv *priv,
+ int id)
+{
+ if (id < gve_num_tx_qpls(priv))
+ return DMA_TO_DEVICE;
+ else
+ return DMA_FROM_DEVICE;
+}
+
+/* Returns true if the max mtu allows page recycling */
+static inline bool gve_can_recycle_pages(struct net_device *dev)
+{
+ /* We can't recycle the pages if we can't fit a packet into half a
+ * page.
+ */
+ return dev->max_mtu <= PAGE_SIZE / 2;
+}
+
+/* buffers */
+int gve_alloc_page(struct device *dev, struct page **page, dma_addr_t *dma,
+ enum dma_data_direction);
+void gve_free_page(struct device *dev, struct page *page, dma_addr_t dma,
+ enum dma_data_direction);
+/* tx handling */
+netdev_tx_t gve_tx(struct sk_buff *skb, struct net_device *dev);
+bool gve_tx_poll(struct gve_notify_block *block, int budget);
+int gve_tx_alloc_rings(struct gve_priv *priv);
+void gve_tx_free_rings(struct gve_priv *priv);
+__be32 gve_tx_load_event_counter(struct gve_priv *priv,
+ struct gve_tx_ring *tx);
+/* rx handling */
+void gve_rx_write_doorbell(struct gve_priv *priv, struct gve_rx_ring *rx);
+bool gve_rx_poll(struct gve_notify_block *block, int budget);
+int gve_rx_alloc_rings(struct gve_priv *priv);
+void gve_rx_free_rings(struct gve_priv *priv);
+bool gve_clean_rx_done(struct gve_rx_ring *rx, int budget,
+ netdev_features_t feat);
+/* Reset */
+void gve_schedule_reset(struct gve_priv *priv);
+int gve_reset(struct gve_priv *priv, bool attempt_teardown);
+int gve_adjust_queues(struct gve_priv *priv,
+ struct gve_queue_config new_rx_config,
+ struct gve_queue_config new_tx_config);
+/* exported by ethtool.c */
+extern const struct ethtool_ops gve_ethtool_ops;
+/* needed by ethtool */
+extern const char gve_version_str[];
+#endif /* _GVE_H_ */
diff --git a/drivers/net/ethernet/google/gve/gve_adminq.c b/drivers/net/ethernet/google/gve/gve_adminq.c
new file mode 100644
index 000000000000..c3ba7baf0107
--- /dev/null
+++ b/drivers/net/ethernet/google/gve/gve_adminq.c
@@ -0,0 +1,387 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Google virtual Ethernet (gve) driver
+ *
+ * Copyright (C) 2015-2019 Google, Inc.
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/pci.h>
+#include "gve.h"
+#include "gve_adminq.h"
+#include "gve_register.h"
+
+#define GVE_MAX_ADMINQ_RELEASE_CHECK 500
+#define GVE_ADMINQ_SLEEP_LEN 20
+#define GVE_MAX_ADMINQ_EVENT_COUNTER_CHECK 100
+
+int gve_adminq_alloc(struct device *dev, struct gve_priv *priv)
+{
+ priv->adminq = dma_alloc_coherent(dev, PAGE_SIZE,
+ &priv->adminq_bus_addr, GFP_KERNEL);
+ if (unlikely(!priv->adminq))
+ return -ENOMEM;
+
+ priv->adminq_mask = (PAGE_SIZE / sizeof(union gve_adminq_command)) - 1;
+ priv->adminq_prod_cnt = 0;
+
+ /* Setup Admin queue with the device */
+ iowrite32be(priv->adminq_bus_addr / PAGE_SIZE,
+ &priv->reg_bar0->adminq_pfn);
+
+ gve_set_admin_queue_ok(priv);
+ return 0;
+}
+
+void gve_adminq_release(struct gve_priv *priv)
+{
+ int i = 0;
+
+ /* Tell the device the adminq is leaving */
+ iowrite32be(0x0, &priv->reg_bar0->adminq_pfn);
+ while (ioread32be(&priv->reg_bar0->adminq_pfn)) {
+ /* If this is reached the device is unrecoverable and still
+ * holding memory. Continue looping to avoid memory corruption,
+ * but WARN so it is visible what is going on.
+ */
+ if (i == GVE_MAX_ADMINQ_RELEASE_CHECK)
+ WARN(1, "Unrecoverable platform error!");
+ i++;
+ msleep(GVE_ADMINQ_SLEEP_LEN);
+ }
+ gve_clear_device_rings_ok(priv);
+ gve_clear_device_resources_ok(priv);
+ gve_clear_admin_queue_ok(priv);
+}
+
+void gve_adminq_free(struct device *dev, struct gve_priv *priv)
+{
+ if (!gve_get_admin_queue_ok(priv))
+ return;
+ gve_adminq_release(priv);
+ dma_free_coherent(dev, PAGE_SIZE, priv->adminq, priv->adminq_bus_addr);
+ gve_clear_admin_queue_ok(priv);
+}
+
+static void gve_adminq_kick_cmd(struct gve_priv *priv, u32 prod_cnt)
+{
+ iowrite32be(prod_cnt, &priv->reg_bar0->adminq_doorbell);
+}
+
+static bool gve_adminq_wait_for_cmd(struct gve_priv *priv, u32 prod_cnt)
+{
+ int i;
+
+ for (i = 0; i < GVE_MAX_ADMINQ_EVENT_COUNTER_CHECK; i++) {
+ if (ioread32be(&priv->reg_bar0->adminq_event_counter)
+ == prod_cnt)
+ return true;
+ msleep(GVE_ADMINQ_SLEEP_LEN);
+ }
+
+ return false;
+}
+
+static int gve_adminq_parse_err(struct device *dev, u32 status)
+{
+ if (status != GVE_ADMINQ_COMMAND_PASSED &&
+ status != GVE_ADMINQ_COMMAND_UNSET)
+ dev_err(dev, "AQ command failed with status %d\n", status);
+
+ switch (status) {
+ case GVE_ADMINQ_COMMAND_PASSED:
+ return 0;
+ case GVE_ADMINQ_COMMAND_UNSET:
+ dev_err(dev, "parse_aq_err: err and status both unset, this should not be possible.\n");
+ return -EINVAL;
+ case GVE_ADMINQ_COMMAND_ERROR_ABORTED:
+ case GVE_ADMINQ_COMMAND_ERROR_CANCELLED:
+ case GVE_ADMINQ_COMMAND_ERROR_DATALOSS:
+ case GVE_ADMINQ_COMMAND_ERROR_FAILED_PRECONDITION:
+ case GVE_ADMINQ_COMMAND_ERROR_UNAVAILABLE:
+ return -EAGAIN;
+ case GVE_ADMINQ_COMMAND_ERROR_ALREADY_EXISTS:
+ case GVE_ADMINQ_COMMAND_ERROR_INTERNAL_ERROR:
+ case GVE_ADMINQ_COMMAND_ERROR_INVALID_ARGUMENT:
+ case GVE_ADMINQ_COMMAND_ERROR_NOT_FOUND:
+ case GVE_ADMINQ_COMMAND_ERROR_OUT_OF_RANGE:
+ case GVE_ADMINQ_COMMAND_ERROR_UNKNOWN_ERROR:
+ return -EINVAL;
+ case GVE_ADMINQ_COMMAND_ERROR_DEADLINE_EXCEEDED:
+ return -ETIME;
+ case GVE_ADMINQ_COMMAND_ERROR_PERMISSION_DENIED:
+ case GVE_ADMINQ_COMMAND_ERROR_UNAUTHENTICATED:
+ return -EACCES;
+ case GVE_ADMINQ_COMMAND_ERROR_RESOURCE_EXHAUSTED:
+ return -ENOMEM;
+ case GVE_ADMINQ_COMMAND_ERROR_UNIMPLEMENTED:
+ return -ENOTSUPP;
+ default:
+ dev_err(dev, "parse_aq_err: unknown status code %d\n", status);
+ return -EINVAL;
+ }
+}
+
+/* This function is not threadsafe - the caller is responsible for any
+ * necessary locks.
+ */
+int gve_adminq_execute_cmd(struct gve_priv *priv,
+ union gve_adminq_command *cmd_orig)
+{
+ union gve_adminq_command *cmd;
+ u32 status = 0;
+ u32 prod_cnt;
+
+ cmd = &priv->adminq[priv->adminq_prod_cnt & priv->adminq_mask];
+ priv->adminq_prod_cnt++;
+ prod_cnt = priv->adminq_prod_cnt;
+
+ memcpy(cmd, cmd_orig, sizeof(*cmd_orig));
+
+ gve_adminq_kick_cmd(priv, prod_cnt);
+ if (!gve_adminq_wait_for_cmd(priv, prod_cnt)) {
+ dev_err(&priv->pdev->dev, "AQ command timed out, need to reset AQ\n");
+ return -ENOTRECOVERABLE;
+ }
+
+ memcpy(cmd_orig, cmd, sizeof(*cmd));
+ status = be32_to_cpu(READ_ONCE(cmd->status));
+ return gve_adminq_parse_err(&priv->pdev->dev, status);
+}
+
+/* The device specifies that the management vector can either be the first irq
+ * or the last irq. ntfy_blk_msix_base_idx indicates the first irq assigned to
+ * the ntfy blks. It if is 0 then the management vector is last, if it is 1 then
+ * the management vector is first.
+ *
+ * gve arranges the msix vectors so that the management vector is last.
+ */
+#define GVE_NTFY_BLK_BASE_MSIX_IDX 0
+int gve_adminq_configure_device_resources(struct gve_priv *priv,
+ dma_addr_t counter_array_bus_addr,
+ u32 num_counters,
+ dma_addr_t db_array_bus_addr,
+ u32 num_ntfy_blks)
+{
+ union gve_adminq_command cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.opcode = cpu_to_be32(GVE_ADMINQ_CONFIGURE_DEVICE_RESOURCES);
+ cmd.configure_device_resources =
+ (struct gve_adminq_configure_device_resources) {
+ .counter_array = cpu_to_be64(counter_array_bus_addr),
+ .num_counters = cpu_to_be32(num_counters),
+ .irq_db_addr = cpu_to_be64(db_array_bus_addr),
+ .num_irq_dbs = cpu_to_be32(num_ntfy_blks),
+ .irq_db_stride = cpu_to_be32(sizeof(priv->ntfy_blocks[0])),
+ .ntfy_blk_msix_base_idx =
+ cpu_to_be32(GVE_NTFY_BLK_BASE_MSIX_IDX),
+ };
+
+ return gve_adminq_execute_cmd(priv, &cmd);
+}
+
+int gve_adminq_deconfigure_device_resources(struct gve_priv *priv)
+{
+ union gve_adminq_command cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.opcode = cpu_to_be32(GVE_ADMINQ_DECONFIGURE_DEVICE_RESOURCES);
+
+ return gve_adminq_execute_cmd(priv, &cmd);
+}
+
+int gve_adminq_create_tx_queue(struct gve_priv *priv, u32 queue_index)
+{
+ struct gve_tx_ring *tx = &priv->tx[queue_index];
+ union gve_adminq_command cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.opcode = cpu_to_be32(GVE_ADMINQ_CREATE_TX_QUEUE);
+ cmd.create_tx_queue = (struct gve_adminq_create_tx_queue) {
+ .queue_id = cpu_to_be32(queue_index),
+ .reserved = 0,
+ .queue_resources_addr = cpu_to_be64(tx->q_resources_bus),
+ .tx_ring_addr = cpu_to_be64(tx->bus),
+ .queue_page_list_id = cpu_to_be32(tx->tx_fifo.qpl->id),
+ .ntfy_id = cpu_to_be32(tx->ntfy_id),
+ };
+
+ return gve_adminq_execute_cmd(priv, &cmd);
+}
+
+int gve_adminq_create_rx_queue(struct gve_priv *priv, u32 queue_index)
+{
+ struct gve_rx_ring *rx = &priv->rx[queue_index];
+ union gve_adminq_command cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.opcode = cpu_to_be32(GVE_ADMINQ_CREATE_RX_QUEUE);
+ cmd.create_rx_queue = (struct gve_adminq_create_rx_queue) {
+ .queue_id = cpu_to_be32(queue_index),
+ .index = cpu_to_be32(queue_index),
+ .reserved = 0,
+ .ntfy_id = cpu_to_be32(rx->ntfy_id),
+ .queue_resources_addr = cpu_to_be64(rx->q_resources_bus),
+ .rx_desc_ring_addr = cpu_to_be64(rx->desc.bus),
+ .rx_data_ring_addr = cpu_to_be64(rx->data.data_bus),
+ .queue_page_list_id = cpu_to_be32(rx->data.qpl->id),
+ };
+
+ return gve_adminq_execute_cmd(priv, &cmd);
+}
+
+int gve_adminq_destroy_tx_queue(struct gve_priv *priv, u32 queue_index)
+{
+ union gve_adminq_command cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.opcode = cpu_to_be32(GVE_ADMINQ_DESTROY_TX_QUEUE);
+ cmd.destroy_tx_queue = (struct gve_adminq_destroy_tx_queue) {
+ .queue_id = cpu_to_be32(queue_index),
+ };
+
+ return gve_adminq_execute_cmd(priv, &cmd);
+}
+
+int gve_adminq_destroy_rx_queue(struct gve_priv *priv, u32 queue_index)
+{
+ union gve_adminq_command cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.opcode = cpu_to_be32(GVE_ADMINQ_DESTROY_RX_QUEUE);
+ cmd.destroy_rx_queue = (struct gve_adminq_destroy_rx_queue) {
+ .queue_id = cpu_to_be32(queue_index),
+ };
+
+ return gve_adminq_execute_cmd(priv, &cmd);
+}
+
+int gve_adminq_describe_device(struct gve_priv *priv)
+{
+ struct gve_device_descriptor *descriptor;
+ union gve_adminq_command cmd;
+ dma_addr_t descriptor_bus;
+ int err = 0;
+ u8 *mac;
+ u16 mtu;
+
+ memset(&cmd, 0, sizeof(cmd));
+ descriptor = dma_alloc_coherent(&priv->pdev->dev, PAGE_SIZE,
+ &descriptor_bus, GFP_KERNEL);
+ if (!descriptor)
+ return -ENOMEM;
+ cmd.opcode = cpu_to_be32(GVE_ADMINQ_DESCRIBE_DEVICE);
+ cmd.describe_device.device_descriptor_addr =
+ cpu_to_be64(descriptor_bus);
+ cmd.describe_device.device_descriptor_version =
+ cpu_to_be32(GVE_ADMINQ_DEVICE_DESCRIPTOR_VERSION);
+ cmd.describe_device.available_length = cpu_to_be32(PAGE_SIZE);
+
+ err = gve_adminq_execute_cmd(priv, &cmd);
+ if (err)
+ goto free_device_descriptor;
+
+ priv->tx_desc_cnt = be16_to_cpu(descriptor->tx_queue_entries);
+ if (priv->tx_desc_cnt * sizeof(priv->tx->desc[0]) < PAGE_SIZE) {
+ netif_err(priv, drv, priv->dev, "Tx desc count %d too low\n",
+ priv->tx_desc_cnt);
+ err = -EINVAL;
+ goto free_device_descriptor;
+ }
+ priv->rx_desc_cnt = be16_to_cpu(descriptor->rx_queue_entries);
+ if (priv->rx_desc_cnt * sizeof(priv->rx->desc.desc_ring[0])
+ < PAGE_SIZE ||
+ priv->rx_desc_cnt * sizeof(priv->rx->data.data_ring[0])
+ < PAGE_SIZE) {
+ netif_err(priv, drv, priv->dev, "Rx desc count %d too low\n",
+ priv->rx_desc_cnt);
+ err = -EINVAL;
+ goto free_device_descriptor;
+ }
+ priv->max_registered_pages =
+ be64_to_cpu(descriptor->max_registered_pages);
+ mtu = be16_to_cpu(descriptor->mtu);
+ if (mtu < ETH_MIN_MTU) {
+ netif_err(priv, drv, priv->dev, "MTU %d below minimum MTU\n",
+ mtu);
+ err = -EINVAL;
+ goto free_device_descriptor;
+ }
+ priv->dev->max_mtu = mtu;
+ priv->num_event_counters = be16_to_cpu(descriptor->counters);
+ ether_addr_copy(priv->dev->dev_addr, descriptor->mac);
+ mac = descriptor->mac;
+ netif_info(priv, drv, priv->dev, "MAC addr: %pM\n", mac);
+ priv->tx_pages_per_qpl = be16_to_cpu(descriptor->tx_pages_per_qpl);
+ priv->rx_pages_per_qpl = be16_to_cpu(descriptor->rx_pages_per_qpl);
+ if (priv->rx_pages_per_qpl < priv->rx_desc_cnt) {
+ netif_err(priv, drv, priv->dev, "rx_pages_per_qpl cannot be smaller than rx_desc_cnt, setting rx_desc_cnt down to %d.\n",
+ priv->rx_pages_per_qpl);
+ priv->rx_desc_cnt = priv->rx_pages_per_qpl;
+ }
+ priv->default_num_queues = be16_to_cpu(descriptor->default_num_queues);
+
+free_device_descriptor:
+ dma_free_coherent(&priv->pdev->dev, sizeof(*descriptor), descriptor,
+ descriptor_bus);
+ return err;
+}
+
+int gve_adminq_register_page_list(struct gve_priv *priv,
+ struct gve_queue_page_list *qpl)
+{
+ struct device *hdev = &priv->pdev->dev;
+ u32 num_entries = qpl->num_entries;
+ u32 size = num_entries * sizeof(qpl->page_buses[0]);
+ union gve_adminq_command cmd;
+ dma_addr_t page_list_bus;
+ __be64 *page_list;
+ int err;
+ int i;
+
+ memset(&cmd, 0, sizeof(cmd));
+ page_list = dma_alloc_coherent(hdev, size, &page_list_bus, GFP_KERNEL);
+ if (!page_list)
+ return -ENOMEM;
+
+ for (i = 0; i < num_entries; i++)
+ page_list[i] = cpu_to_be64(qpl->page_buses[i]);
+
+ cmd.opcode = cpu_to_be32(GVE_ADMINQ_REGISTER_PAGE_LIST);
+ cmd.reg_page_list = (struct gve_adminq_register_page_list) {
+ .page_list_id = cpu_to_be32(qpl->id),
+ .num_pages = cpu_to_be32(num_entries),
+ .page_address_list_addr = cpu_to_be64(page_list_bus),
+ };
+
+ err = gve_adminq_execute_cmd(priv, &cmd);
+ dma_free_coherent(hdev, size, page_list, page_list_bus);
+ return err;
+}
+
+int gve_adminq_unregister_page_list(struct gve_priv *priv, u32 page_list_id)
+{
+ union gve_adminq_command cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.opcode = cpu_to_be32(GVE_ADMINQ_UNREGISTER_PAGE_LIST);
+ cmd.unreg_page_list = (struct gve_adminq_unregister_page_list) {
+ .page_list_id = cpu_to_be32(page_list_id),
+ };
+
+ return gve_adminq_execute_cmd(priv, &cmd);
+}
+
+int gve_adminq_set_mtu(struct gve_priv *priv, u64 mtu)
+{
+ union gve_adminq_command cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.opcode = cpu_to_be32(GVE_ADMINQ_SET_DRIVER_PARAMETER);
+ cmd.set_driver_param = (struct gve_adminq_set_driver_parameter) {
+ .parameter_type = cpu_to_be32(GVE_SET_PARAM_MTU),
+ .parameter_value = cpu_to_be64(mtu),
+ };
+
+ return gve_adminq_execute_cmd(priv, &cmd);
+}
diff --git a/drivers/net/ethernet/google/gve/gve_adminq.h b/drivers/net/ethernet/google/gve/gve_adminq.h
new file mode 100644
index 000000000000..4dfa06edc0f8
--- /dev/null
+++ b/drivers/net/ethernet/google/gve/gve_adminq.h
@@ -0,0 +1,217 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
+ * Google virtual Ethernet (gve) driver
+ *
+ * Copyright (C) 2015-2019 Google, Inc.
+ */
+
+#ifndef _GVE_ADMINQ_H
+#define _GVE_ADMINQ_H
+
+#include <linux/build_bug.h>
+
+/* Admin queue opcodes */
+enum gve_adminq_opcodes {
+ GVE_ADMINQ_DESCRIBE_DEVICE = 0x1,
+ GVE_ADMINQ_CONFIGURE_DEVICE_RESOURCES = 0x2,
+ GVE_ADMINQ_REGISTER_PAGE_LIST = 0x3,
+ GVE_ADMINQ_UNREGISTER_PAGE_LIST = 0x4,
+ GVE_ADMINQ_CREATE_TX_QUEUE = 0x5,
+ GVE_ADMINQ_CREATE_RX_QUEUE = 0x6,
+ GVE_ADMINQ_DESTROY_TX_QUEUE = 0x7,
+ GVE_ADMINQ_DESTROY_RX_QUEUE = 0x8,
+ GVE_ADMINQ_DECONFIGURE_DEVICE_RESOURCES = 0x9,
+ GVE_ADMINQ_SET_DRIVER_PARAMETER = 0xB,
+};
+
+/* Admin queue status codes */
+enum gve_adminq_statuses {
+ GVE_ADMINQ_COMMAND_UNSET = 0x0,
+ GVE_ADMINQ_COMMAND_PASSED = 0x1,
+ GVE_ADMINQ_COMMAND_ERROR_ABORTED = 0xFFFFFFF0,
+ GVE_ADMINQ_COMMAND_ERROR_ALREADY_EXISTS = 0xFFFFFFF1,
+ GVE_ADMINQ_COMMAND_ERROR_CANCELLED = 0xFFFFFFF2,
+ GVE_ADMINQ_COMMAND_ERROR_DATALOSS = 0xFFFFFFF3,
+ GVE_ADMINQ_COMMAND_ERROR_DEADLINE_EXCEEDED = 0xFFFFFFF4,
+ GVE_ADMINQ_COMMAND_ERROR_FAILED_PRECONDITION = 0xFFFFFFF5,
+ GVE_ADMINQ_COMMAND_ERROR_INTERNAL_ERROR = 0xFFFFFFF6,
+ GVE_ADMINQ_COMMAND_ERROR_INVALID_ARGUMENT = 0xFFFFFFF7,
+ GVE_ADMINQ_COMMAND_ERROR_NOT_FOUND = 0xFFFFFFF8,
+ GVE_ADMINQ_COMMAND_ERROR_OUT_OF_RANGE = 0xFFFFFFF9,
+ GVE_ADMINQ_COMMAND_ERROR_PERMISSION_DENIED = 0xFFFFFFFA,
+ GVE_ADMINQ_COMMAND_ERROR_UNAUTHENTICATED = 0xFFFFFFFB,
+ GVE_ADMINQ_COMMAND_ERROR_RESOURCE_EXHAUSTED = 0xFFFFFFFC,
+ GVE_ADMINQ_COMMAND_ERROR_UNAVAILABLE = 0xFFFFFFFD,
+ GVE_ADMINQ_COMMAND_ERROR_UNIMPLEMENTED = 0xFFFFFFFE,
+ GVE_ADMINQ_COMMAND_ERROR_UNKNOWN_ERROR = 0xFFFFFFFF,
+};
+
+#define GVE_ADMINQ_DEVICE_DESCRIPTOR_VERSION 1
+
+/* All AdminQ command structs should be naturally packed. The static_assert
+ * calls make sure this is the case at compile time.
+ */
+
+struct gve_adminq_describe_device {
+ __be64 device_descriptor_addr;
+ __be32 device_descriptor_version;
+ __be32 available_length;
+};
+
+static_assert(sizeof(struct gve_adminq_describe_device) == 16);
+
+struct gve_device_descriptor {
+ __be64 max_registered_pages;
+ __be16 reserved1;
+ __be16 tx_queue_entries;
+ __be16 rx_queue_entries;
+ __be16 default_num_queues;
+ __be16 mtu;
+ __be16 counters;
+ __be16 tx_pages_per_qpl;
+ __be16 rx_pages_per_qpl;
+ u8 mac[ETH_ALEN];
+ __be16 num_device_options;
+ __be16 total_length;
+ u8 reserved2[6];
+};
+
+static_assert(sizeof(struct gve_device_descriptor) == 40);
+
+struct device_option {
+ __be32 option_id;
+ __be32 option_length;
+};
+
+static_assert(sizeof(struct device_option) == 8);
+
+struct gve_adminq_configure_device_resources {
+ __be64 counter_array;
+ __be64 irq_db_addr;
+ __be32 num_counters;
+ __be32 num_irq_dbs;
+ __be32 irq_db_stride;
+ __be32 ntfy_blk_msix_base_idx;
+};
+
+static_assert(sizeof(struct gve_adminq_configure_device_resources) == 32);
+
+struct gve_adminq_register_page_list {
+ __be32 page_list_id;
+ __be32 num_pages;
+ __be64 page_address_list_addr;
+};
+
+static_assert(sizeof(struct gve_adminq_register_page_list) == 16);
+
+struct gve_adminq_unregister_page_list {
+ __be32 page_list_id;
+};
+
+static_assert(sizeof(struct gve_adminq_unregister_page_list) == 4);
+
+struct gve_adminq_create_tx_queue {
+ __be32 queue_id;
+ __be32 reserved;
+ __be64 queue_resources_addr;
+ __be64 tx_ring_addr;
+ __be32 queue_page_list_id;
+ __be32 ntfy_id;
+};
+
+static_assert(sizeof(struct gve_adminq_create_tx_queue) == 32);
+
+struct gve_adminq_create_rx_queue {
+ __be32 queue_id;
+ __be32 index;
+ __be32 reserved;
+ __be32 ntfy_id;
+ __be64 queue_resources_addr;
+ __be64 rx_desc_ring_addr;
+ __be64 rx_data_ring_addr;
+ __be32 queue_page_list_id;
+ u8 padding[4];
+};
+
+static_assert(sizeof(struct gve_adminq_create_rx_queue) == 48);
+
+/* Queue resources that are shared with the device */
+struct gve_queue_resources {
+ union {
+ struct {
+ __be32 db_index; /* Device -> Guest */
+ __be32 counter_index; /* Device -> Guest */
+ };
+ u8 reserved[64];
+ };
+};
+
+static_assert(sizeof(struct gve_queue_resources) == 64);
+
+struct gve_adminq_destroy_tx_queue {
+ __be32 queue_id;
+};
+
+static_assert(sizeof(struct gve_adminq_destroy_tx_queue) == 4);
+
+struct gve_adminq_destroy_rx_queue {
+ __be32 queue_id;
+};
+
+static_assert(sizeof(struct gve_adminq_destroy_rx_queue) == 4);
+
+/* GVE Set Driver Parameter Types */
+enum gve_set_driver_param_types {
+ GVE_SET_PARAM_MTU = 0x1,
+};
+
+struct gve_adminq_set_driver_parameter {
+ __be32 parameter_type;
+ u8 reserved[4];
+ __be64 parameter_value;
+};
+
+static_assert(sizeof(struct gve_adminq_set_driver_parameter) == 16);
+
+union gve_adminq_command {
+ struct {
+ __be32 opcode;
+ __be32 status;
+ union {
+ struct gve_adminq_configure_device_resources
+ configure_device_resources;
+ struct gve_adminq_create_tx_queue create_tx_queue;
+ struct gve_adminq_create_rx_queue create_rx_queue;
+ struct gve_adminq_destroy_tx_queue destroy_tx_queue;
+ struct gve_adminq_destroy_rx_queue destroy_rx_queue;
+ struct gve_adminq_describe_device describe_device;
+ struct gve_adminq_register_page_list reg_page_list;
+ struct gve_adminq_unregister_page_list unreg_page_list;
+ struct gve_adminq_set_driver_parameter set_driver_param;
+ };
+ };
+ u8 reserved[64];
+};
+
+static_assert(sizeof(union gve_adminq_command) == 64);
+
+int gve_adminq_alloc(struct device *dev, struct gve_priv *priv);
+void gve_adminq_free(struct device *dev, struct gve_priv *priv);
+void gve_adminq_release(struct gve_priv *priv);
+int gve_adminq_execute_cmd(struct gve_priv *priv,
+ union gve_adminq_command *cmd_orig);
+int gve_adminq_describe_device(struct gve_priv *priv);
+int gve_adminq_configure_device_resources(struct gve_priv *priv,
+ dma_addr_t counter_array_bus_addr,
+ u32 num_counters,
+ dma_addr_t db_array_bus_addr,
+ u32 num_ntfy_blks);
+int gve_adminq_deconfigure_device_resources(struct gve_priv *priv);
+int gve_adminq_create_tx_queue(struct gve_priv *priv, u32 queue_id);
+int gve_adminq_destroy_tx_queue(struct gve_priv *priv, u32 queue_id);
+int gve_adminq_create_rx_queue(struct gve_priv *priv, u32 queue_id);
+int gve_adminq_destroy_rx_queue(struct gve_priv *priv, u32 queue_id);
+int gve_adminq_register_page_list(struct gve_priv *priv,
+ struct gve_queue_page_list *qpl);
+int gve_adminq_unregister_page_list(struct gve_priv *priv, u32 page_list_id);
+int gve_adminq_set_mtu(struct gve_priv *priv, u64 mtu);
+#endif /* _GVE_ADMINQ_H */
diff --git a/drivers/net/ethernet/google/gve/gve_desc.h b/drivers/net/ethernet/google/gve/gve_desc.h
new file mode 100644
index 000000000000..54779871d52e
--- /dev/null
+++ b/drivers/net/ethernet/google/gve/gve_desc.h
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
+ * Google virtual Ethernet (gve) driver
+ *
+ * Copyright (C) 2015-2019 Google, Inc.
+ */
+
+/* GVE Transmit Descriptor formats */
+
+#ifndef _GVE_DESC_H_
+#define _GVE_DESC_H_
+
+#include <linux/build_bug.h>
+
+/* A note on seg_addrs
+ *
+ * Base addresses encoded in seg_addr are not assumed to be physical
+ * addresses. The ring format assumes these come from some linear address
+ * space. This could be physical memory, kernel virtual memory, user virtual
+ * memory. gVNIC uses lists of registered pages. Each queue is assumed
+ * to be associated with a single such linear address space to ensure a
+ * consistent meaning for seg_addrs posted to its rings.
+ */
+
+struct gve_tx_pkt_desc {
+ u8 type_flags; /* desc type is lower 4 bits, flags upper */
+ u8 l4_csum_offset; /* relative offset of L4 csum word */
+ u8 l4_hdr_offset; /* Offset of start of L4 headers in packet */
+ u8 desc_cnt; /* Total descriptors for this packet */
+ __be16 len; /* Total length of this packet (in bytes) */
+ __be16 seg_len; /* Length of this descriptor's segment */
+ __be64 seg_addr; /* Base address (see note) of this segment */
+} __packed;
+
+struct gve_tx_seg_desc {
+ u8 type_flags; /* type is lower 4 bits, flags upper */
+ u8 l3_offset; /* TSO: 2 byte units to start of IPH */
+ __be16 reserved;
+ __be16 mss; /* TSO MSS */
+ __be16 seg_len;
+ __be64 seg_addr;
+} __packed;
+
+/* GVE Transmit Descriptor Types */
+#define GVE_TXD_STD (0x0 << 4) /* Std with Host Address */
+#define GVE_TXD_TSO (0x1 << 4) /* TSO with Host Address */
+#define GVE_TXD_SEG (0x2 << 4) /* Seg with Host Address */
+
+/* GVE Transmit Descriptor Flags for Std Pkts */
+#define GVE_TXF_L4CSUM BIT(0) /* Need csum offload */
+#define GVE_TXF_TSTAMP BIT(2) /* Timestamp required */
+
+/* GVE Transmit Descriptor Flags for TSO Segs */
+#define GVE_TXSF_IPV6 BIT(1) /* IPv6 TSO */
+
+/* GVE Receive Packet Descriptor */
+/* The start of an ethernet packet comes 2 bytes into the rx buffer.
+ * gVNIC adds this padding so that both the DMA and the L3/4 protocol header
+ * access is aligned.
+ */
+#define GVE_RX_PAD 2
+
+struct gve_rx_desc {
+ u8 padding[48];
+ __be32 rss_hash; /* Receive-side scaling hash (Toeplitz for gVNIC) */
+ __be16 mss;
+ __be16 reserved; /* Reserved to zero */
+ u8 hdr_len; /* Header length (L2-L4) including padding */
+ u8 hdr_off; /* 64-byte-scaled offset into RX_DATA entry */
+ __sum16 csum; /* 1's-complement partial checksum of L3+ bytes */
+ __be16 len; /* Length of the received packet */
+ __be16 flags_seq; /* Flags [15:3] and sequence number [2:0] (1-7) */
+} __packed;
+static_assert(sizeof(struct gve_rx_desc) == 64);
+
+/* As with the Tx ring format, the qpl_offset entries below are offsets into an
+ * ordered list of registered pages.
+ */
+struct gve_rx_data_slot {
+ /* byte offset into the rx registered segment of this slot */
+ __be64 qpl_offset;
+};
+
+/* GVE Recive Packet Descriptor Seq No */
+#define GVE_SEQNO(x) (be16_to_cpu(x) & 0x7)
+
+/* GVE Recive 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 */
+#define GVE_RXF_IPV6 GVE_RXFLG(5) /* IPv6 */
+#define GVE_RXF_TCP GVE_RXFLG(6) /* TCP Packet */
+#define GVE_RXF_UDP GVE_RXFLG(7) /* UDP Packet */
+#define GVE_RXF_ERR GVE_RXFLG(8) /* Packet Error Detected */
+
+/* GVE IRQ */
+#define GVE_IRQ_ACK BIT(31)
+#define GVE_IRQ_MASK BIT(30)
+#define GVE_IRQ_EVENT BIT(29)
+
+static inline bool gve_needs_rss(__be16 flag)
+{
+ if (flag & GVE_RXF_FRAG)
+ return false;
+ if (flag & (GVE_RXF_IPV4 | GVE_RXF_IPV6))
+ return true;
+ return false;
+}
+
+static inline u8 gve_next_seqno(u8 seq)
+{
+ return (seq + 1) == 8 ? 1 : seq + 1;
+}
+#endif /* _GVE_DESC_H_ */
diff --git a/drivers/net/ethernet/google/gve/gve_ethtool.c b/drivers/net/ethernet/google/gve/gve_ethtool.c
new file mode 100644
index 000000000000..26540b856541
--- /dev/null
+++ b/drivers/net/ethernet/google/gve/gve_ethtool.c
@@ -0,0 +1,245 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Google virtual Ethernet (gve) driver
+ *
+ * Copyright (C) 2015-2019 Google, Inc.
+ */
+
+#include <linux/rtnetlink.h>
+#include "gve.h"
+
+static void gve_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *info)
+{
+ struct gve_priv *priv = netdev_priv(netdev);
+
+ strlcpy(info->driver, "gve", sizeof(info->driver));
+ strlcpy(info->version, gve_version_str, sizeof(info->version));
+ strlcpy(info->bus_info, pci_name(priv->pdev), sizeof(info->bus_info));
+}
+
+static void gve_set_msglevel(struct net_device *netdev, u32 value)
+{
+ struct gve_priv *priv = netdev_priv(netdev);
+
+ priv->msg_enable = value;
+}
+
+static u32 gve_get_msglevel(struct net_device *netdev)
+{
+ struct gve_priv *priv = netdev_priv(netdev);
+
+ return priv->msg_enable;
+}
+
+static const char gve_gstrings_main_stats[][ETH_GSTRING_LEN] = {
+ "rx_packets", "tx_packets", "rx_bytes", "tx_bytes",
+ "rx_dropped", "tx_dropped", "tx_timeouts",
+};
+
+#define GVE_MAIN_STATS_LEN ARRAY_SIZE(gve_gstrings_main_stats)
+#define NUM_GVE_TX_CNTS 5
+#define NUM_GVE_RX_CNTS 2
+
+static void gve_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
+{
+ struct gve_priv *priv = netdev_priv(netdev);
+ char *s = (char *)data;
+ int i;
+
+ if (stringset != ETH_SS_STATS)
+ return;
+
+ memcpy(s, *gve_gstrings_main_stats,
+ sizeof(gve_gstrings_main_stats));
+ s += sizeof(gve_gstrings_main_stats);
+ for (i = 0; i < priv->rx_cfg.num_queues; i++) {
+ snprintf(s, ETH_GSTRING_LEN, "rx_desc_cnt[%u]", i);
+ s += ETH_GSTRING_LEN;
+ snprintf(s, ETH_GSTRING_LEN, "rx_desc_fill_cnt[%u]", i);
+ s += ETH_GSTRING_LEN;
+ }
+ for (i = 0; i < priv->tx_cfg.num_queues; i++) {
+ snprintf(s, ETH_GSTRING_LEN, "tx_req[%u]", i);
+ s += ETH_GSTRING_LEN;
+ snprintf(s, ETH_GSTRING_LEN, "tx_done[%u]", i);
+ s += ETH_GSTRING_LEN;
+ snprintf(s, ETH_GSTRING_LEN, "tx_wake[%u]", i);
+ s += ETH_GSTRING_LEN;
+ snprintf(s, ETH_GSTRING_LEN, "tx_stop[%u]", i);
+ s += ETH_GSTRING_LEN;
+ snprintf(s, ETH_GSTRING_LEN, "tx_event_counter[%u]", i);
+ s += ETH_GSTRING_LEN;
+ }
+}
+
+static int gve_get_sset_count(struct net_device *netdev, int sset)
+{
+ struct gve_priv *priv = netdev_priv(netdev);
+
+ switch (sset) {
+ case ETH_SS_STATS:
+ return GVE_MAIN_STATS_LEN +
+ (priv->rx_cfg.num_queues * NUM_GVE_RX_CNTS) +
+ (priv->tx_cfg.num_queues * NUM_GVE_TX_CNTS);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void
+gve_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct gve_priv *priv = netdev_priv(netdev);
+ u64 rx_pkts, rx_bytes, tx_pkts, tx_bytes;
+ unsigned int start;
+ int ring;
+ int i;
+
+ ASSERT_RTNL();
+
+ for (rx_pkts = 0, rx_bytes = 0, ring = 0;
+ ring < priv->rx_cfg.num_queues; ring++) {
+ if (priv->rx) {
+ do {
+ start =
+ u64_stats_fetch_begin(&priv->rx[ring].statss);
+ rx_pkts += priv->rx[ring].rpackets;
+ rx_bytes += priv->rx[ring].rbytes;
+ } while (u64_stats_fetch_retry(&priv->rx[ring].statss,
+ start));
+ }
+ }
+ for (tx_pkts = 0, tx_bytes = 0, ring = 0;
+ ring < priv->tx_cfg.num_queues; ring++) {
+ if (priv->tx) {
+ do {
+ start =
+ u64_stats_fetch_begin(&priv->tx[ring].statss);
+ tx_pkts += priv->tx[ring].pkt_done;
+ tx_bytes += priv->tx[ring].bytes_done;
+ } while (u64_stats_fetch_retry(&priv->tx[ring].statss,
+ start));
+ }
+ }
+
+ i = 0;
+ data[i++] = rx_pkts;
+ data[i++] = tx_pkts;
+ data[i++] = rx_bytes;
+ data[i++] = tx_bytes;
+ /* Skip rx_dropped and tx_dropped */
+ i += 2;
+ data[i++] = priv->tx_timeo_cnt;
+ i = GVE_MAIN_STATS_LEN;
+
+ /* walk RX rings */
+ if (priv->rx) {
+ for (ring = 0; ring < priv->rx_cfg.num_queues; ring++) {
+ struct gve_rx_ring *rx = &priv->rx[ring];
+
+ data[i++] = rx->desc.cnt;
+ data[i++] = rx->desc.fill_cnt;
+ }
+ } else {
+ i += priv->rx_cfg.num_queues * NUM_GVE_RX_CNTS;
+ }
+ /* walk TX rings */
+ if (priv->tx) {
+ for (ring = 0; ring < priv->tx_cfg.num_queues; ring++) {
+ struct gve_tx_ring *tx = &priv->tx[ring];
+
+ data[i++] = tx->req;
+ data[i++] = tx->done;
+ data[i++] = tx->wake_queue;
+ data[i++] = tx->stop_queue;
+ data[i++] = be32_to_cpu(gve_tx_load_event_counter(priv,
+ tx));
+ }
+ } else {
+ i += priv->tx_cfg.num_queues * NUM_GVE_TX_CNTS;
+ }
+}
+
+static void gve_get_channels(struct net_device *netdev,
+ struct ethtool_channels *cmd)
+{
+ struct gve_priv *priv = netdev_priv(netdev);
+
+ cmd->max_rx = priv->rx_cfg.max_queues;
+ cmd->max_tx = priv->tx_cfg.max_queues;
+ cmd->max_other = 0;
+ cmd->max_combined = 0;
+ cmd->rx_count = priv->rx_cfg.num_queues;
+ cmd->tx_count = priv->tx_cfg.num_queues;
+ cmd->other_count = 0;
+ cmd->combined_count = 0;
+}
+
+static int gve_set_channels(struct net_device *netdev,
+ struct ethtool_channels *cmd)
+{
+ struct gve_priv *priv = netdev_priv(netdev);
+ struct gve_queue_config new_tx_cfg = priv->tx_cfg;
+ struct gve_queue_config new_rx_cfg = priv->rx_cfg;
+ struct ethtool_channels old_settings;
+ int new_tx = cmd->tx_count;
+ int new_rx = cmd->rx_count;
+
+ gve_get_channels(netdev, &old_settings);
+
+ /* Changing combined is not allowed allowed */
+ if (cmd->combined_count != old_settings.combined_count)
+ return -EINVAL;
+
+ if (!new_rx || !new_tx)
+ return -EINVAL;
+
+ if (!netif_carrier_ok(netdev)) {
+ priv->tx_cfg.num_queues = new_tx;
+ priv->rx_cfg.num_queues = new_rx;
+ return 0;
+ }
+
+ new_tx_cfg.num_queues = new_tx;
+ new_rx_cfg.num_queues = new_rx;
+
+ return gve_adjust_queues(priv, new_rx_cfg, new_tx_cfg);
+}
+
+static void gve_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *cmd)
+{
+ struct gve_priv *priv = netdev_priv(netdev);
+
+ cmd->rx_max_pending = priv->rx_desc_cnt;
+ cmd->tx_max_pending = priv->tx_desc_cnt;
+ cmd->rx_pending = priv->rx_desc_cnt;
+ cmd->tx_pending = priv->tx_desc_cnt;
+}
+
+static int gve_user_reset(struct net_device *netdev, u32 *flags)
+{
+ struct gve_priv *priv = netdev_priv(netdev);
+
+ if (*flags == ETH_RESET_ALL) {
+ *flags = 0;
+ return gve_reset(priv, true);
+ }
+
+ return -EOPNOTSUPP;
+}
+
+const struct ethtool_ops gve_ethtool_ops = {
+ .get_drvinfo = gve_get_drvinfo,
+ .get_strings = gve_get_strings,
+ .get_sset_count = gve_get_sset_count,
+ .get_ethtool_stats = gve_get_ethtool_stats,
+ .set_msglevel = gve_set_msglevel,
+ .get_msglevel = gve_get_msglevel,
+ .set_channels = gve_set_channels,
+ .get_channels = gve_get_channels,
+ .get_link = ethtool_op_get_link,
+ .get_ringparam = gve_get_ringparam,
+ .reset = gve_user_reset,
+};
diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c
new file mode 100644
index 000000000000..497298752381
--- /dev/null
+++ b/drivers/net/ethernet/google/gve/gve_main.c
@@ -0,0 +1,1231 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Google virtual Ethernet (gve) driver
+ *
+ * Copyright (C) 2015-2019 Google, Inc.
+ */
+
+#include <linux/cpumask.h>
+#include <linux/etherdevice.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+#include <net/sch_generic.h>
+#include "gve.h"
+#include "gve_adminq.h"
+#include "gve_register.h"
+
+#define GVE_DEFAULT_RX_COPYBREAK (256)
+
+#define DEFAULT_MSG_LEVEL (NETIF_MSG_DRV | NETIF_MSG_LINK)
+#define GVE_VERSION "1.0.0"
+#define GVE_VERSION_PREFIX "GVE-"
+
+const char gve_version_str[] = GVE_VERSION;
+static const char gve_version_prefix[] = GVE_VERSION_PREFIX;
+
+static void gve_get_stats(struct net_device *dev, struct rtnl_link_stats64 *s)
+{
+ struct gve_priv *priv = netdev_priv(dev);
+ unsigned int start;
+ int ring;
+
+ if (priv->rx) {
+ for (ring = 0; ring < priv->rx_cfg.num_queues; ring++) {
+ do {
+ start =
+ u64_stats_fetch_begin(&priv->rx[ring].statss);
+ s->rx_packets += priv->rx[ring].rpackets;
+ s->rx_bytes += priv->rx[ring].rbytes;
+ } while (u64_stats_fetch_retry(&priv->rx[ring].statss,
+ start));
+ }
+ }
+ if (priv->tx) {
+ for (ring = 0; ring < priv->tx_cfg.num_queues; ring++) {
+ do {
+ start =
+ u64_stats_fetch_begin(&priv->tx[ring].statss);
+ s->tx_packets += priv->tx[ring].pkt_done;
+ s->tx_bytes += priv->tx[ring].bytes_done;
+ } while (u64_stats_fetch_retry(&priv->rx[ring].statss,
+ start));
+ }
+ }
+}
+
+static int gve_alloc_counter_array(struct gve_priv *priv)
+{
+ priv->counter_array =
+ dma_alloc_coherent(&priv->pdev->dev,
+ priv->num_event_counters *
+ sizeof(*priv->counter_array),
+ &priv->counter_array_bus, GFP_KERNEL);
+ if (!priv->counter_array)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void gve_free_counter_array(struct gve_priv *priv)
+{
+ dma_free_coherent(&priv->pdev->dev,
+ priv->num_event_counters *
+ sizeof(*priv->counter_array),
+ priv->counter_array, priv->counter_array_bus);
+ priv->counter_array = NULL;
+}
+
+static irqreturn_t gve_mgmnt_intr(int irq, void *arg)
+{
+ struct gve_priv *priv = arg;
+
+ queue_work(priv->gve_wq, &priv->service_task);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t gve_intr(int irq, void *arg)
+{
+ struct gve_notify_block *block = arg;
+ struct gve_priv *priv = block->priv;
+
+ iowrite32be(GVE_IRQ_MASK, gve_irq_doorbell(priv, block));
+ napi_schedule_irqoff(&block->napi);
+ return IRQ_HANDLED;
+}
+
+static int gve_napi_poll(struct napi_struct *napi, int budget)
+{
+ struct gve_notify_block *block;
+ __be32 __iomem *irq_doorbell;
+ bool reschedule = false;
+ struct gve_priv *priv;
+
+ block = container_of(napi, struct gve_notify_block, napi);
+ priv = block->priv;
+
+ if (block->tx)
+ reschedule |= gve_tx_poll(block, budget);
+ if (block->rx)
+ reschedule |= gve_rx_poll(block, budget);
+
+ if (reschedule)
+ return budget;
+
+ napi_complete(napi);
+ irq_doorbell = gve_irq_doorbell(priv, block);
+ iowrite32be(GVE_IRQ_ACK | GVE_IRQ_EVENT, irq_doorbell);
+
+ /* Double check we have no extra work.
+ * Ensure unmask synchronizes with checking for work.
+ */
+ dma_rmb();
+ if (block->tx)
+ reschedule |= gve_tx_poll(block, -1);
+ if (block->rx)
+ reschedule |= gve_rx_poll(block, -1);
+ if (reschedule && napi_reschedule(napi))
+ iowrite32be(GVE_IRQ_MASK, irq_doorbell);
+
+ return 0;
+}
+
+static int gve_alloc_notify_blocks(struct gve_priv *priv)
+{
+ int num_vecs_requested = priv->num_ntfy_blks + 1;
+ char *name = priv->dev->name;
+ unsigned int active_cpus;
+ int vecs_enabled;
+ int i, j;
+ int err;
+
+ priv->msix_vectors = kvzalloc(num_vecs_requested *
+ sizeof(*priv->msix_vectors), GFP_KERNEL);
+ if (!priv->msix_vectors)
+ return -ENOMEM;
+ for (i = 0; i < num_vecs_requested; i++)
+ priv->msix_vectors[i].entry = i;
+ vecs_enabled = pci_enable_msix_range(priv->pdev, priv->msix_vectors,
+ GVE_MIN_MSIX, num_vecs_requested);
+ if (vecs_enabled < 0) {
+ dev_err(&priv->pdev->dev, "Could not enable min msix %d/%d\n",
+ GVE_MIN_MSIX, vecs_enabled);
+ err = vecs_enabled;
+ goto abort_with_msix_vectors;
+ }
+ if (vecs_enabled != num_vecs_requested) {
+ int new_num_ntfy_blks = (vecs_enabled - 1) & ~0x1;
+ int vecs_per_type = new_num_ntfy_blks / 2;
+ int vecs_left = new_num_ntfy_blks % 2;
+
+ priv->num_ntfy_blks = new_num_ntfy_blks;
+ priv->tx_cfg.max_queues = min_t(int, priv->tx_cfg.max_queues,
+ vecs_per_type);
+ priv->rx_cfg.max_queues = min_t(int, priv->rx_cfg.max_queues,
+ vecs_per_type + vecs_left);
+ dev_err(&priv->pdev->dev,
+ "Could not enable desired msix, only enabled %d, adjusting tx max queues to %d, and rx max queues to %d\n",
+ vecs_enabled, priv->tx_cfg.max_queues,
+ priv->rx_cfg.max_queues);
+ if (priv->tx_cfg.num_queues > priv->tx_cfg.max_queues)
+ priv->tx_cfg.num_queues = priv->tx_cfg.max_queues;
+ if (priv->rx_cfg.num_queues > priv->rx_cfg.max_queues)
+ priv->rx_cfg.num_queues = priv->rx_cfg.max_queues;
+ }
+ /* Half the notification blocks go to TX and half to RX */
+ active_cpus = min_t(int, priv->num_ntfy_blks / 2, num_online_cpus());
+
+ /* Setup Management Vector - the last vector */
+ snprintf(priv->mgmt_msix_name, sizeof(priv->mgmt_msix_name), "%s-mgmnt",
+ name);
+ err = request_irq(priv->msix_vectors[priv->mgmt_msix_idx].vector,
+ gve_mgmnt_intr, 0, priv->mgmt_msix_name, priv);
+ if (err) {
+ dev_err(&priv->pdev->dev, "Did not receive management vector.\n");
+ goto abort_with_msix_enabled;
+ }
+ priv->ntfy_blocks =
+ dma_alloc_coherent(&priv->pdev->dev,
+ priv->num_ntfy_blks *
+ sizeof(*priv->ntfy_blocks),
+ &priv->ntfy_block_bus, GFP_KERNEL);
+ if (!priv->ntfy_blocks) {
+ err = -ENOMEM;
+ goto abort_with_mgmt_vector;
+ }
+ /* Setup the other blocks - the first n-1 vectors */
+ for (i = 0; i < priv->num_ntfy_blks; i++) {
+ struct gve_notify_block *block = &priv->ntfy_blocks[i];
+ int msix_idx = i;
+
+ snprintf(block->name, sizeof(block->name), "%s-ntfy-block.%d",
+ name, i);
+ block->priv = priv;
+ err = request_irq(priv->msix_vectors[msix_idx].vector,
+ gve_intr, 0, block->name, block);
+ if (err) {
+ dev_err(&priv->pdev->dev,
+ "Failed to receive msix vector %d\n", i);
+ goto abort_with_some_ntfy_blocks;
+ }
+ irq_set_affinity_hint(priv->msix_vectors[msix_idx].vector,
+ get_cpu_mask(i % active_cpus));
+ }
+ return 0;
+abort_with_some_ntfy_blocks:
+ for (j = 0; j < i; j++) {
+ struct gve_notify_block *block = &priv->ntfy_blocks[j];
+ int msix_idx = j;
+
+ irq_set_affinity_hint(priv->msix_vectors[msix_idx].vector,
+ NULL);
+ free_irq(priv->msix_vectors[msix_idx].vector, block);
+ }
+ dma_free_coherent(&priv->pdev->dev, priv->num_ntfy_blks *
+ sizeof(*priv->ntfy_blocks),
+ priv->ntfy_blocks, priv->ntfy_block_bus);
+ priv->ntfy_blocks = NULL;
+abort_with_mgmt_vector:
+ free_irq(priv->msix_vectors[priv->mgmt_msix_idx].vector, priv);
+abort_with_msix_enabled:
+ pci_disable_msix(priv->pdev);
+abort_with_msix_vectors:
+ kvfree(priv->msix_vectors);
+ priv->msix_vectors = NULL;
+ return err;
+}
+
+static void gve_free_notify_blocks(struct gve_priv *priv)
+{
+ int i;
+
+ /* Free the irqs */
+ for (i = 0; i < priv->num_ntfy_blks; i++) {
+ struct gve_notify_block *block = &priv->ntfy_blocks[i];
+ int msix_idx = i;
+
+ irq_set_affinity_hint(priv->msix_vectors[msix_idx].vector,
+ NULL);
+ free_irq(priv->msix_vectors[msix_idx].vector, block);
+ }
+ dma_free_coherent(&priv->pdev->dev,
+ priv->num_ntfy_blks * sizeof(*priv->ntfy_blocks),
+ priv->ntfy_blocks, priv->ntfy_block_bus);
+ priv->ntfy_blocks = NULL;
+ free_irq(priv->msix_vectors[priv->mgmt_msix_idx].vector, priv);
+ pci_disable_msix(priv->pdev);
+ kvfree(priv->msix_vectors);
+ priv->msix_vectors = NULL;
+}
+
+static int gve_setup_device_resources(struct gve_priv *priv)
+{
+ int err;
+
+ err = gve_alloc_counter_array(priv);
+ if (err)
+ return err;
+ err = gve_alloc_notify_blocks(priv);
+ if (err)
+ goto abort_with_counter;
+ err = gve_adminq_configure_device_resources(priv,
+ priv->counter_array_bus,
+ priv->num_event_counters,
+ priv->ntfy_block_bus,
+ priv->num_ntfy_blks);
+ if (unlikely(err)) {
+ dev_err(&priv->pdev->dev,
+ "could not setup device_resources: err=%d\n", err);
+ err = -ENXIO;
+ goto abort_with_ntfy_blocks;
+ }
+ gve_set_device_resources_ok(priv);
+ return 0;
+abort_with_ntfy_blocks:
+ gve_free_notify_blocks(priv);
+abort_with_counter:
+ gve_free_counter_array(priv);
+ return err;
+}
+
+static void gve_trigger_reset(struct gve_priv *priv);
+
+static void gve_teardown_device_resources(struct gve_priv *priv)
+{
+ int err;
+
+ /* Tell device its resources are being freed */
+ if (gve_get_device_resources_ok(priv)) {
+ err = gve_adminq_deconfigure_device_resources(priv);
+ if (err) {
+ dev_err(&priv->pdev->dev,
+ "Could not deconfigure device resources: err=%d\n",
+ err);
+ gve_trigger_reset(priv);
+ }
+ }
+ gve_free_counter_array(priv);
+ gve_free_notify_blocks(priv);
+ gve_clear_device_resources_ok(priv);
+}
+
+static void gve_add_napi(struct gve_priv *priv, int ntfy_idx)
+{
+ struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
+
+ netif_napi_add(priv->dev, &block->napi, gve_napi_poll,
+ NAPI_POLL_WEIGHT);
+}
+
+static void gve_remove_napi(struct gve_priv *priv, int ntfy_idx)
+{
+ struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
+
+ netif_napi_del(&block->napi);
+}
+
+static int gve_register_qpls(struct gve_priv *priv)
+{
+ int num_qpls = gve_num_tx_qpls(priv) + gve_num_rx_qpls(priv);
+ int err;
+ int i;
+
+ for (i = 0; i < num_qpls; i++) {
+ err = gve_adminq_register_page_list(priv, &priv->qpls[i]);
+ if (err) {
+ netif_err(priv, drv, priv->dev,
+ "failed to register queue page list %d\n",
+ priv->qpls[i].id);
+ /* This failure will trigger a reset - no need to clean
+ * up
+ */
+ return err;
+ }
+ }
+ return 0;
+}
+
+static int gve_unregister_qpls(struct gve_priv *priv)
+{
+ int num_qpls = gve_num_tx_qpls(priv) + gve_num_rx_qpls(priv);
+ int err;
+ int i;
+
+ for (i = 0; i < num_qpls; i++) {
+ err = gve_adminq_unregister_page_list(priv, priv->qpls[i].id);
+ /* This failure will trigger a reset - no need to clean up */
+ if (err) {
+ netif_err(priv, drv, priv->dev,
+ "Failed to unregister queue page list %d\n",
+ priv->qpls[i].id);
+ return err;
+ }
+ }
+ return 0;
+}
+
+static int gve_create_rings(struct gve_priv *priv)
+{
+ int err;
+ int i;
+
+ for (i = 0; i < priv->tx_cfg.num_queues; i++) {
+ err = gve_adminq_create_tx_queue(priv, i);
+ if (err) {
+ netif_err(priv, drv, priv->dev, "failed to create tx queue %d\n",
+ i);
+ /* This failure will trigger a reset - no need to clean
+ * up
+ */
+ return err;
+ }
+ netif_dbg(priv, drv, priv->dev, "created tx queue %d\n", i);
+ }
+ for (i = 0; i < priv->rx_cfg.num_queues; i++) {
+ err = gve_adminq_create_rx_queue(priv, i);
+ if (err) {
+ netif_err(priv, drv, priv->dev, "failed to create rx queue %d\n",
+ i);
+ /* This failure will trigger a reset - no need to clean
+ * up
+ */
+ return err;
+ }
+ /* Rx data ring has been prefilled with packet buffers at
+ * queue allocation time.
+ * Write the doorbell to provide descriptor slots and packet
+ * buffers to the NIC.
+ */
+ gve_rx_write_doorbell(priv, &priv->rx[i]);
+ netif_dbg(priv, drv, priv->dev, "created rx queue %d\n", i);
+ }
+
+ return 0;
+}
+
+static int gve_alloc_rings(struct gve_priv *priv)
+{
+ int ntfy_idx;
+ int err;
+ int i;
+
+ /* Setup tx rings */
+ priv->tx = kvzalloc(priv->tx_cfg.num_queues * sizeof(*priv->tx),
+ GFP_KERNEL);
+ if (!priv->tx)
+ return -ENOMEM;
+ err = gve_tx_alloc_rings(priv);
+ if (err)
+ goto free_tx;
+ /* Setup rx rings */
+ priv->rx = kvzalloc(priv->rx_cfg.num_queues * sizeof(*priv->rx),
+ GFP_KERNEL);
+ if (!priv->rx) {
+ err = -ENOMEM;
+ goto free_tx_queue;
+ }
+ err = gve_rx_alloc_rings(priv);
+ if (err)
+ goto free_rx;
+ /* Add tx napi & init sync stats*/
+ for (i = 0; i < priv->tx_cfg.num_queues; i++) {
+ u64_stats_init(&priv->tx[i].statss);
+ ntfy_idx = gve_tx_idx_to_ntfy(priv, i);
+ gve_add_napi(priv, ntfy_idx);
+ }
+ /* Add rx napi & init sync stats*/
+ for (i = 0; i < priv->rx_cfg.num_queues; i++) {
+ u64_stats_init(&priv->rx[i].statss);
+ ntfy_idx = gve_rx_idx_to_ntfy(priv, i);
+ gve_add_napi(priv, ntfy_idx);
+ }
+
+ return 0;
+
+free_rx:
+ kvfree(priv->rx);
+ priv->rx = NULL;
+free_tx_queue:
+ gve_tx_free_rings(priv);
+free_tx:
+ kvfree(priv->tx);
+ priv->tx = NULL;
+ return err;
+}
+
+static int gve_destroy_rings(struct gve_priv *priv)
+{
+ int err;
+ int i;
+
+ for (i = 0; i < priv->tx_cfg.num_queues; i++) {
+ err = gve_adminq_destroy_tx_queue(priv, i);
+ if (err) {
+ netif_err(priv, drv, priv->dev,
+ "failed to destroy tx queue %d\n",
+ i);
+ /* This failure will trigger a reset - no need to clean
+ * up
+ */
+ return err;
+ }
+ netif_dbg(priv, drv, priv->dev, "destroyed tx queue %d\n", i);
+ }
+ for (i = 0; i < priv->rx_cfg.num_queues; i++) {
+ err = gve_adminq_destroy_rx_queue(priv, i);
+ if (err) {
+ netif_err(priv, drv, priv->dev,
+ "failed to destroy rx queue %d\n",
+ i);
+ /* This failure will trigger a reset - no need to clean
+ * up
+ */
+ return err;
+ }
+ netif_dbg(priv, drv, priv->dev, "destroyed rx queue %d\n", i);
+ }
+ return 0;
+}
+
+static void gve_free_rings(struct gve_priv *priv)
+{
+ int ntfy_idx;
+ int i;
+
+ if (priv->tx) {
+ for (i = 0; i < priv->tx_cfg.num_queues; i++) {
+ ntfy_idx = gve_tx_idx_to_ntfy(priv, i);
+ gve_remove_napi(priv, ntfy_idx);
+ }
+ gve_tx_free_rings(priv);
+ kvfree(priv->tx);
+ priv->tx = NULL;
+ }
+ if (priv->rx) {
+ for (i = 0; i < priv->rx_cfg.num_queues; i++) {
+ ntfy_idx = gve_rx_idx_to_ntfy(priv, i);
+ gve_remove_napi(priv, ntfy_idx);
+ }
+ gve_rx_free_rings(priv);
+ kvfree(priv->rx);
+ priv->rx = NULL;
+ }
+}
+
+int gve_alloc_page(struct device *dev, struct page **page, dma_addr_t *dma,
+ enum dma_data_direction dir)
+{
+ *page = alloc_page(GFP_KERNEL);
+ if (!*page)
+ return -ENOMEM;
+ *dma = dma_map_page(dev, *page, 0, PAGE_SIZE, dir);
+ if (dma_mapping_error(dev, *dma)) {
+ put_page(*page);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static int gve_alloc_queue_page_list(struct gve_priv *priv, u32 id,
+ int pages)
+{
+ struct gve_queue_page_list *qpl = &priv->qpls[id];
+ int err;
+ int i;
+
+ if (pages + priv->num_registered_pages > priv->max_registered_pages) {
+ netif_err(priv, drv, priv->dev,
+ "Reached max number of registered pages %llu > %llu\n",
+ pages + priv->num_registered_pages,
+ priv->max_registered_pages);
+ return -EINVAL;
+ }
+
+ qpl->id = id;
+ qpl->num_entries = pages;
+ qpl->pages = kvzalloc(pages * sizeof(*qpl->pages), GFP_KERNEL);
+ /* caller handles clean up */
+ if (!qpl->pages)
+ return -ENOMEM;
+ qpl->page_buses = kvzalloc(pages * sizeof(*qpl->page_buses),
+ GFP_KERNEL);
+ /* caller handles clean up */
+ if (!qpl->page_buses)
+ return -ENOMEM;
+
+ for (i = 0; i < pages; i++) {
+ err = gve_alloc_page(&priv->pdev->dev, &qpl->pages[i],
+ &qpl->page_buses[i],
+ gve_qpl_dma_dir(priv, id));
+ /* caller handles clean up */
+ if (err)
+ return -ENOMEM;
+ }
+ priv->num_registered_pages += pages;
+
+ return 0;
+}
+
+void gve_free_page(struct device *dev, struct page *page, dma_addr_t dma,
+ enum dma_data_direction dir)
+{
+ if (!dma_mapping_error(dev, dma))
+ dma_unmap_page(dev, dma, PAGE_SIZE, dir);
+ if (page)
+ put_page(page);
+}
+
+static void gve_free_queue_page_list(struct gve_priv *priv,
+ int id)
+{
+ struct gve_queue_page_list *qpl = &priv->qpls[id];
+ int i;
+
+ if (!qpl->pages)
+ return;
+ if (!qpl->page_buses)
+ goto free_pages;
+
+ for (i = 0; i < qpl->num_entries; i++)
+ gve_free_page(&priv->pdev->dev, qpl->pages[i],
+ qpl->page_buses[i], gve_qpl_dma_dir(priv, id));
+
+ kvfree(qpl->page_buses);
+free_pages:
+ kvfree(qpl->pages);
+ priv->num_registered_pages -= qpl->num_entries;
+}
+
+static int gve_alloc_qpls(struct gve_priv *priv)
+{
+ int num_qpls = gve_num_tx_qpls(priv) + gve_num_rx_qpls(priv);
+ int i, j;
+ int err;
+
+ priv->qpls = kvzalloc(num_qpls * sizeof(*priv->qpls), GFP_KERNEL);
+ if (!priv->qpls)
+ return -ENOMEM;
+
+ for (i = 0; i < gve_num_tx_qpls(priv); i++) {
+ err = gve_alloc_queue_page_list(priv, i,
+ priv->tx_pages_per_qpl);
+ if (err)
+ goto free_qpls;
+ }
+ for (; i < num_qpls; i++) {
+ err = gve_alloc_queue_page_list(priv, i,
+ priv->rx_pages_per_qpl);
+ if (err)
+ goto free_qpls;
+ }
+
+ priv->qpl_cfg.qpl_map_size = BITS_TO_LONGS(num_qpls) *
+ sizeof(unsigned long) * BITS_PER_BYTE;
+ priv->qpl_cfg.qpl_id_map = kvzalloc(BITS_TO_LONGS(num_qpls) *
+ sizeof(unsigned long), GFP_KERNEL);
+ if (!priv->qpl_cfg.qpl_id_map) {
+ err = -ENOMEM;
+ goto free_qpls;
+ }
+
+ return 0;
+
+free_qpls:
+ for (j = 0; j <= i; j++)
+ gve_free_queue_page_list(priv, j);
+ kvfree(priv->qpls);
+ return err;
+}
+
+static void gve_free_qpls(struct gve_priv *priv)
+{
+ int num_qpls = gve_num_tx_qpls(priv) + gve_num_rx_qpls(priv);
+ int i;
+
+ kvfree(priv->qpl_cfg.qpl_id_map);
+
+ for (i = 0; i < num_qpls; i++)
+ gve_free_queue_page_list(priv, i);
+
+ kvfree(priv->qpls);
+}
+
+/* Use this to schedule a reset when the device is capable of continuing
+ * to handle other requests in its current state. If it is not, do a reset
+ * in thread instead.
+ */
+void gve_schedule_reset(struct gve_priv *priv)
+{
+ gve_set_do_reset(priv);
+ queue_work(priv->gve_wq, &priv->service_task);
+}
+
+static void gve_reset_and_teardown(struct gve_priv *priv, bool was_up);
+static int gve_reset_recovery(struct gve_priv *priv, bool was_up);
+static void gve_turndown(struct gve_priv *priv);
+static void gve_turnup(struct gve_priv *priv);
+
+static int gve_open(struct net_device *dev)
+{
+ struct gve_priv *priv = netdev_priv(dev);
+ int err;
+
+ err = gve_alloc_qpls(priv);
+ if (err)
+ return err;
+ err = gve_alloc_rings(priv);
+ if (err)
+ goto free_qpls;
+
+ err = netif_set_real_num_tx_queues(dev, priv->tx_cfg.num_queues);
+ if (err)
+ goto free_rings;
+ err = netif_set_real_num_rx_queues(dev, priv->rx_cfg.num_queues);
+ if (err)
+ goto free_rings;
+
+ err = gve_register_qpls(priv);
+ if (err)
+ goto reset;
+ err = gve_create_rings(priv);
+ if (err)
+ goto reset;
+ gve_set_device_rings_ok(priv);
+
+ gve_turnup(priv);
+ netif_carrier_on(dev);
+ return 0;
+
+free_rings:
+ gve_free_rings(priv);
+free_qpls:
+ gve_free_qpls(priv);
+ return err;
+
+reset:
+ /* This must have been called from a reset due to the rtnl lock
+ * so just return at this point.
+ */
+ if (gve_get_reset_in_progress(priv))
+ return err;
+ /* Otherwise reset before returning */
+ gve_reset_and_teardown(priv, true);
+ /* if this fails there is nothing we can do so just ignore the return */
+ gve_reset_recovery(priv, false);
+ /* return the original error */
+ return err;
+}
+
+static int gve_close(struct net_device *dev)
+{
+ struct gve_priv *priv = netdev_priv(dev);
+ int err;
+
+ netif_carrier_off(dev);
+ if (gve_get_device_rings_ok(priv)) {
+ gve_turndown(priv);
+ err = gve_destroy_rings(priv);
+ if (err)
+ goto err;
+ err = gve_unregister_qpls(priv);
+ if (err)
+ goto err;
+ gve_clear_device_rings_ok(priv);
+ }
+
+ gve_free_rings(priv);
+ gve_free_qpls(priv);
+ return 0;
+
+err:
+ /* This must have been called from a reset due to the rtnl lock
+ * so just return at this point.
+ */
+ if (gve_get_reset_in_progress(priv))
+ return err;
+ /* Otherwise reset before returning */
+ gve_reset_and_teardown(priv, true);
+ return gve_reset_recovery(priv, false);
+}
+
+int gve_adjust_queues(struct gve_priv *priv,
+ struct gve_queue_config new_rx_config,
+ struct gve_queue_config new_tx_config)
+{
+ int err;
+
+ if (netif_carrier_ok(priv->dev)) {
+ /* To make this process as simple as possible we teardown the
+ * device, set the new configuration, and then bring the device
+ * up again.
+ */
+ err = gve_close(priv->dev);
+ /* we have already tried to reset in close,
+ * just fail at this point
+ */
+ if (err)
+ return err;
+ priv->tx_cfg = new_tx_config;
+ priv->rx_cfg = new_rx_config;
+
+ err = gve_open(priv->dev);
+ if (err)
+ goto err;
+
+ return 0;
+ }
+ /* Set the config for the next up. */
+ priv->tx_cfg = new_tx_config;
+ priv->rx_cfg = new_rx_config;
+
+ return 0;
+err:
+ netif_err(priv, drv, priv->dev,
+ "Adjust queues failed! !!! DISABLING ALL QUEUES !!!\n");
+ gve_turndown(priv);
+ return err;
+}
+
+static void gve_turndown(struct gve_priv *priv)
+{
+ int idx;
+
+ if (netif_carrier_ok(priv->dev))
+ netif_carrier_off(priv->dev);
+
+ if (!gve_get_napi_enabled(priv))
+ return;
+
+ /* Disable napi to prevent more work from coming in */
+ for (idx = 0; idx < priv->tx_cfg.num_queues; idx++) {
+ int ntfy_idx = gve_tx_idx_to_ntfy(priv, idx);
+ struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
+
+ napi_disable(&block->napi);
+ }
+ for (idx = 0; idx < priv->rx_cfg.num_queues; idx++) {
+ int ntfy_idx = gve_rx_idx_to_ntfy(priv, idx);
+ struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
+
+ napi_disable(&block->napi);
+ }
+
+ /* Stop tx queues */
+ netif_tx_disable(priv->dev);
+
+ gve_clear_napi_enabled(priv);
+}
+
+static void gve_turnup(struct gve_priv *priv)
+{
+ int idx;
+
+ /* Start the tx queues */
+ netif_tx_start_all_queues(priv->dev);
+
+ /* Enable napi and unmask interrupts for all queues */
+ for (idx = 0; idx < priv->tx_cfg.num_queues; idx++) {
+ int ntfy_idx = gve_tx_idx_to_ntfy(priv, idx);
+ struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
+
+ napi_enable(&block->napi);
+ iowrite32be(0, gve_irq_doorbell(priv, block));
+ }
+ for (idx = 0; idx < priv->rx_cfg.num_queues; idx++) {
+ int ntfy_idx = gve_rx_idx_to_ntfy(priv, idx);
+ struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
+
+ napi_enable(&block->napi);
+ iowrite32be(0, gve_irq_doorbell(priv, block));
+ }
+
+ gve_set_napi_enabled(priv);
+}
+
+static void gve_tx_timeout(struct net_device *dev)
+{
+ struct gve_priv *priv = netdev_priv(dev);
+
+ gve_schedule_reset(priv);
+ priv->tx_timeo_cnt++;
+}
+
+static const struct net_device_ops gve_netdev_ops = {
+ .ndo_start_xmit = gve_tx,
+ .ndo_open = gve_open,
+ .ndo_stop = gve_close,
+ .ndo_get_stats64 = gve_get_stats,
+ .ndo_tx_timeout = gve_tx_timeout,
+};
+
+static void gve_handle_status(struct gve_priv *priv, u32 status)
+{
+ if (GVE_DEVICE_STATUS_RESET_MASK & status) {
+ dev_info(&priv->pdev->dev, "Device requested reset.\n");
+ gve_set_do_reset(priv);
+ }
+}
+
+static void gve_handle_reset(struct gve_priv *priv)
+{
+ /* A service task will be scheduled at the end of probe to catch any
+ * resets that need to happen, and we don't want to reset until
+ * probe is done.
+ */
+ if (gve_get_probe_in_progress(priv))
+ return;
+
+ if (gve_get_do_reset(priv)) {
+ rtnl_lock();
+ gve_reset(priv, false);
+ rtnl_unlock();
+ }
+}
+
+/* Handle NIC status register changes and reset requests */
+static void gve_service_task(struct work_struct *work)
+{
+ struct gve_priv *priv = container_of(work, struct gve_priv,
+ service_task);
+
+ gve_handle_status(priv,
+ ioread32be(&priv->reg_bar0->device_status));
+
+ gve_handle_reset(priv);
+}
+
+static int gve_init_priv(struct gve_priv *priv, bool skip_describe_device)
+{
+ int num_ntfy;
+ int err;
+
+ /* Set up the adminq */
+ err = gve_adminq_alloc(&priv->pdev->dev, priv);
+ if (err) {
+ dev_err(&priv->pdev->dev,
+ "Failed to alloc admin queue: err=%d\n", err);
+ return err;
+ }
+
+ if (skip_describe_device)
+ goto setup_device;
+
+ /* Get the initial information we need from the device */
+ err = gve_adminq_describe_device(priv);
+ if (err) {
+ dev_err(&priv->pdev->dev,
+ "Could not get device information: err=%d\n", err);
+ goto err;
+ }
+ if (priv->dev->max_mtu > PAGE_SIZE) {
+ priv->dev->max_mtu = PAGE_SIZE;
+ err = gve_adminq_set_mtu(priv, priv->dev->mtu);
+ if (err) {
+ netif_err(priv, drv, priv->dev, "Could not set mtu");
+ goto err;
+ }
+ }
+ priv->dev->mtu = priv->dev->max_mtu;
+ num_ntfy = pci_msix_vec_count(priv->pdev);
+ if (num_ntfy <= 0) {
+ dev_err(&priv->pdev->dev,
+ "could not count MSI-x vectors: err=%d\n", num_ntfy);
+ err = num_ntfy;
+ goto err;
+ } else if (num_ntfy < GVE_MIN_MSIX) {
+ dev_err(&priv->pdev->dev, "gve needs at least %d MSI-x vectors, but only has %d\n",
+ GVE_MIN_MSIX, num_ntfy);
+ err = -EINVAL;
+ goto err;
+ }
+
+ priv->num_registered_pages = 0;
+ priv->rx_copybreak = GVE_DEFAULT_RX_COPYBREAK;
+ /* gvnic has one Notification Block per MSI-x vector, except for the
+ * management vector
+ */
+ priv->num_ntfy_blks = (num_ntfy - 1) & ~0x1;
+ priv->mgmt_msix_idx = priv->num_ntfy_blks;
+
+ priv->tx_cfg.max_queues =
+ min_t(int, priv->tx_cfg.max_queues, priv->num_ntfy_blks / 2);
+ priv->rx_cfg.max_queues =
+ min_t(int, priv->rx_cfg.max_queues, priv->num_ntfy_blks / 2);
+
+ priv->tx_cfg.num_queues = priv->tx_cfg.max_queues;
+ priv->rx_cfg.num_queues = priv->rx_cfg.max_queues;
+ if (priv->default_num_queues > 0) {
+ priv->tx_cfg.num_queues = min_t(int, priv->default_num_queues,
+ priv->tx_cfg.num_queues);
+ priv->rx_cfg.num_queues = min_t(int, priv->default_num_queues,
+ priv->rx_cfg.num_queues);
+ }
+
+ netif_info(priv, drv, priv->dev, "TX queues %d, RX queues %d\n",
+ priv->tx_cfg.num_queues, priv->rx_cfg.num_queues);
+ netif_info(priv, drv, priv->dev, "Max TX queues %d, Max RX queues %d\n",
+ priv->tx_cfg.max_queues, priv->rx_cfg.max_queues);
+
+setup_device:
+ err = gve_setup_device_resources(priv);
+ if (!err)
+ return 0;
+err:
+ gve_adminq_free(&priv->pdev->dev, priv);
+ return err;
+}
+
+static void gve_teardown_priv_resources(struct gve_priv *priv)
+{
+ gve_teardown_device_resources(priv);
+ gve_adminq_free(&priv->pdev->dev, priv);
+}
+
+static void gve_trigger_reset(struct gve_priv *priv)
+{
+ /* Reset the device by releasing the AQ */
+ gve_adminq_release(priv);
+}
+
+static void gve_reset_and_teardown(struct gve_priv *priv, bool was_up)
+{
+ gve_trigger_reset(priv);
+ /* With the reset having already happened, close cannot fail */
+ if (was_up)
+ gve_close(priv->dev);
+ gve_teardown_priv_resources(priv);
+}
+
+static int gve_reset_recovery(struct gve_priv *priv, bool was_up)
+{
+ int err;
+
+ err = gve_init_priv(priv, true);
+ if (err)
+ goto err;
+ if (was_up) {
+ err = gve_open(priv->dev);
+ if (err)
+ goto err;
+ }
+ return 0;
+err:
+ dev_err(&priv->pdev->dev, "Reset failed! !!! DISABLING ALL QUEUES !!!\n");
+ gve_turndown(priv);
+ return err;
+}
+
+int gve_reset(struct gve_priv *priv, bool attempt_teardown)
+{
+ bool was_up = netif_carrier_ok(priv->dev);
+ int err;
+
+ dev_info(&priv->pdev->dev, "Performing reset\n");
+ gve_clear_do_reset(priv);
+ gve_set_reset_in_progress(priv);
+ /* If we aren't attempting to teardown normally, just go turndown and
+ * reset right away.
+ */
+ if (!attempt_teardown) {
+ gve_turndown(priv);
+ gve_reset_and_teardown(priv, was_up);
+ } else {
+ /* Otherwise attempt to close normally */
+ if (was_up) {
+ err = gve_close(priv->dev);
+ /* If that fails reset as we did above */
+ if (err)
+ gve_reset_and_teardown(priv, was_up);
+ }
+ /* Clean up any remaining resources */
+ gve_teardown_priv_resources(priv);
+ }
+
+ /* Set it all back up */
+ err = gve_reset_recovery(priv, was_up);
+ gve_clear_reset_in_progress(priv);
+ return err;
+}
+
+static void gve_write_version(u8 __iomem *driver_version_register)
+{
+ const char *c = gve_version_prefix;
+
+ while (*c) {
+ writeb(*c, driver_version_register);
+ c++;
+ }
+
+ c = gve_version_str;
+ while (*c) {
+ writeb(*c, driver_version_register);
+ c++;
+ }
+ writeb('\n', driver_version_register);
+}
+
+static int gve_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int max_tx_queues, max_rx_queues;
+ struct net_device *dev;
+ __be32 __iomem *db_bar;
+ struct gve_registers __iomem *reg_bar;
+ struct gve_priv *priv;
+ int err;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ return -ENXIO;
+
+ err = pci_request_regions(pdev, "gvnic-cfg");
+ if (err)
+ goto abort_with_enabled;
+
+ pci_set_master(pdev);
+
+ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+ if (err) {
+ dev_err(&pdev->dev, "Failed to set dma mask: err=%d\n", err);
+ goto abort_with_pci_region;
+ }
+
+ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+ if (err) {
+ dev_err(&pdev->dev,
+ "Failed to set consistent dma mask: err=%d\n", err);
+ goto abort_with_pci_region;
+ }
+
+ reg_bar = pci_iomap(pdev, GVE_REGISTER_BAR, 0);
+ if (!reg_bar) {
+ dev_err(&pdev->dev, "Failed to map pci bar!\n");
+ err = -ENOMEM;
+ goto abort_with_pci_region;
+ }
+
+ db_bar = pci_iomap(pdev, GVE_DOORBELL_BAR, 0);
+ if (!db_bar) {
+ dev_err(&pdev->dev, "Failed to map doorbell bar!\n");
+ err = -ENOMEM;
+ goto abort_with_reg_bar;
+ }
+
+ gve_write_version(&reg_bar->driver_version);
+ /* Get max queues to alloc etherdev */
+ max_rx_queues = ioread32be(&reg_bar->max_tx_queues);
+ max_tx_queues = ioread32be(&reg_bar->max_rx_queues);
+ /* Alloc and setup the netdev and priv */
+ dev = alloc_etherdev_mqs(sizeof(*priv), max_tx_queues, max_rx_queues);
+ if (!dev) {
+ dev_err(&pdev->dev, "could not allocate netdev\n");
+ goto abort_with_db_bar;
+ }
+ SET_NETDEV_DEV(dev, &pdev->dev);
+ pci_set_drvdata(pdev, dev);
+ dev->ethtool_ops = &gve_ethtool_ops;
+ dev->netdev_ops = &gve_netdev_ops;
+ /* advertise features */
+ dev->hw_features = NETIF_F_HIGHDMA;
+ dev->hw_features |= NETIF_F_SG;
+ dev->hw_features |= NETIF_F_HW_CSUM;
+ dev->hw_features |= NETIF_F_TSO;
+ dev->hw_features |= NETIF_F_TSO6;
+ dev->hw_features |= NETIF_F_TSO_ECN;
+ dev->hw_features |= NETIF_F_RXCSUM;
+ dev->hw_features |= NETIF_F_RXHASH;
+ dev->features = dev->hw_features;
+ dev->watchdog_timeo = 5 * HZ;
+ dev->min_mtu = ETH_MIN_MTU;
+ netif_carrier_off(dev);
+
+ priv = netdev_priv(dev);
+ priv->dev = dev;
+ priv->pdev = pdev;
+ priv->msg_enable = DEFAULT_MSG_LEVEL;
+ priv->reg_bar0 = reg_bar;
+ priv->db_bar2 = db_bar;
+ priv->service_task_flags = 0x0;
+ priv->state_flags = 0x0;
+
+ gve_set_probe_in_progress(priv);
+ priv->gve_wq = alloc_ordered_workqueue("gve", 0);
+ if (!priv->gve_wq) {
+ dev_err(&pdev->dev, "Could not allocate workqueue");
+ err = -ENOMEM;
+ goto abort_with_netdev;
+ }
+ INIT_WORK(&priv->service_task, gve_service_task);
+ priv->tx_cfg.max_queues = max_tx_queues;
+ priv->rx_cfg.max_queues = max_rx_queues;
+
+ err = gve_init_priv(priv, false);
+ if (err)
+ goto abort_with_wq;
+
+ err = register_netdev(dev);
+ if (err)
+ goto abort_with_wq;
+
+ dev_info(&pdev->dev, "GVE version %s\n", gve_version_str);
+ gve_clear_probe_in_progress(priv);
+ queue_work(priv->gve_wq, &priv->service_task);
+ return 0;
+
+abort_with_wq:
+ destroy_workqueue(priv->gve_wq);
+
+abort_with_netdev:
+ free_netdev(dev);
+
+abort_with_db_bar:
+ pci_iounmap(pdev, db_bar);
+
+abort_with_reg_bar:
+ pci_iounmap(pdev, reg_bar);
+
+abort_with_pci_region:
+ pci_release_regions(pdev);
+
+abort_with_enabled:
+ pci_disable_device(pdev);
+ return -ENXIO;
+}
+
+static void gve_remove(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct gve_priv *priv = netdev_priv(netdev);
+ __be32 __iomem *db_bar = priv->db_bar2;
+ void __iomem *reg_bar = priv->reg_bar0;
+
+ unregister_netdev(netdev);
+ gve_teardown_priv_resources(priv);
+ destroy_workqueue(priv->gve_wq);
+ free_netdev(netdev);
+ pci_iounmap(pdev, db_bar);
+ pci_iounmap(pdev, reg_bar);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+}
+
+static const struct pci_device_id gve_id_table[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_GOOGLE, PCI_DEV_ID_GVNIC) },
+ { }
+};
+
+static struct pci_driver gvnic_driver = {
+ .name = "gvnic",
+ .id_table = gve_id_table,
+ .probe = gve_probe,
+ .remove = gve_remove,
+};
+
+module_pci_driver(gvnic_driver);
+
+MODULE_DEVICE_TABLE(pci, gve_id_table);
+MODULE_AUTHOR("Google, Inc.");
+MODULE_DESCRIPTION("gVNIC Driver");
+MODULE_LICENSE("Dual MIT/GPL");
+MODULE_VERSION(GVE_VERSION);
diff --git a/drivers/net/ethernet/google/gve/gve_register.h b/drivers/net/ethernet/google/gve/gve_register.h
new file mode 100644
index 000000000000..84ab8893aadd
--- /dev/null
+++ b/drivers/net/ethernet/google/gve/gve_register.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
+ * Google virtual Ethernet (gve) driver
+ *
+ * Copyright (C) 2015-2019 Google, Inc.
+ */
+
+#ifndef _GVE_REGISTER_H_
+#define _GVE_REGISTER_H_
+
+/* Fixed Configuration Registers */
+struct gve_registers {
+ __be32 device_status;
+ __be32 driver_status;
+ __be32 max_tx_queues;
+ __be32 max_rx_queues;
+ __be32 adminq_pfn;
+ __be32 adminq_doorbell;
+ __be32 adminq_event_counter;
+ u8 reserved[3];
+ u8 driver_version;
+};
+
+enum gve_device_status_flags {
+ GVE_DEVICE_STATUS_RESET_MASK = BIT(1),
+ GVE_DEVICE_STATUS_LINK_STATUS_MASK = BIT(2),
+};
+#endif /* _GVE_REGISTER_H_ */
diff --git a/drivers/net/ethernet/google/gve/gve_rx.c b/drivers/net/ethernet/google/gve/gve_rx.c
new file mode 100644
index 000000000000..1914b8350da7
--- /dev/null
+++ b/drivers/net/ethernet/google/gve/gve_rx.c
@@ -0,0 +1,446 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Google virtual Ethernet (gve) driver
+ *
+ * Copyright (C) 2015-2019 Google, Inc.
+ */
+
+#include "gve.h"
+#include "gve_adminq.h"
+#include <linux/etherdevice.h>
+
+static void gve_rx_remove_from_block(struct gve_priv *priv, int queue_idx)
+{
+ struct gve_notify_block *block =
+ &priv->ntfy_blocks[gve_rx_idx_to_ntfy(priv, queue_idx)];
+
+ block->rx = NULL;
+}
+
+static void gve_rx_free_ring(struct gve_priv *priv, int idx)
+{
+ struct gve_rx_ring *rx = &priv->rx[idx];
+ struct device *dev = &priv->pdev->dev;
+ size_t bytes;
+ u32 slots;
+
+ gve_rx_remove_from_block(priv, idx);
+
+ bytes = sizeof(struct gve_rx_desc) * priv->rx_desc_cnt;
+ dma_free_coherent(dev, bytes, rx->desc.desc_ring, rx->desc.bus);
+ rx->desc.desc_ring = NULL;
+
+ dma_free_coherent(dev, sizeof(*rx->q_resources),
+ rx->q_resources, rx->q_resources_bus);
+ rx->q_resources = NULL;
+
+ gve_unassign_qpl(priv, rx->data.qpl->id);
+ rx->data.qpl = NULL;
+ kvfree(rx->data.page_info);
+
+ slots = rx->data.mask + 1;
+ bytes = sizeof(*rx->data.data_ring) * slots;
+ dma_free_coherent(dev, bytes, rx->data.data_ring,
+ rx->data.data_bus);
+ rx->data.data_ring = NULL;
+ netif_dbg(priv, drv, priv->dev, "freed rx ring %d\n", idx);
+}
+
+static void gve_setup_rx_buffer(struct gve_rx_slot_page_info *page_info,
+ struct gve_rx_data_slot *slot,
+ dma_addr_t addr, struct page *page)
+{
+ page_info->page = page;
+ page_info->page_offset = 0;
+ page_info->page_address = page_address(page);
+ slot->qpl_offset = cpu_to_be64(addr);
+}
+
+static int gve_prefill_rx_pages(struct gve_rx_ring *rx)
+{
+ struct gve_priv *priv = rx->gve;
+ u32 slots;
+ int i;
+
+ /* Allocate one page per Rx queue slot. Each page is split into two
+ * packet buffers, when possible we "page flip" between the two.
+ */
+ slots = rx->data.mask + 1;
+
+ rx->data.page_info = kvzalloc(slots *
+ sizeof(*rx->data.page_info), GFP_KERNEL);
+ if (!rx->data.page_info)
+ return -ENOMEM;
+
+ rx->data.qpl = gve_assign_rx_qpl(priv);
+
+ for (i = 0; i < slots; i++) {
+ struct page *page = rx->data.qpl->pages[i];
+ dma_addr_t addr = i * PAGE_SIZE;
+
+ gve_setup_rx_buffer(&rx->data.page_info[i],
+ &rx->data.data_ring[i], addr, page);
+ }
+
+ return slots;
+}
+
+static void gve_rx_add_to_block(struct gve_priv *priv, int queue_idx)
+{
+ u32 ntfy_idx = gve_rx_idx_to_ntfy(priv, queue_idx);
+ struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
+ struct gve_rx_ring *rx = &priv->rx[queue_idx];
+
+ block->rx = rx;
+ rx->ntfy_id = ntfy_idx;
+}
+
+static int gve_rx_alloc_ring(struct gve_priv *priv, int idx)
+{
+ struct gve_rx_ring *rx = &priv->rx[idx];
+ struct device *hdev = &priv->pdev->dev;
+ u32 slots, npages;
+ int filled_pages;
+ size_t bytes;
+ int err;
+
+ netif_dbg(priv, drv, priv->dev, "allocating rx ring\n");
+ /* Make sure everything is zeroed to start with */
+ memset(rx, 0, sizeof(*rx));
+
+ rx->gve = priv;
+ rx->q_num = idx;
+
+ slots = priv->rx_pages_per_qpl;
+ rx->data.mask = slots - 1;
+
+ /* alloc rx data ring */
+ bytes = sizeof(*rx->data.data_ring) * slots;
+ rx->data.data_ring = dma_alloc_coherent(hdev, bytes,
+ &rx->data.data_bus,
+ GFP_KERNEL);
+ if (!rx->data.data_ring)
+ return -ENOMEM;
+ filled_pages = gve_prefill_rx_pages(rx);
+ if (filled_pages < 0) {
+ err = -ENOMEM;
+ goto abort_with_slots;
+ }
+ rx->desc.fill_cnt = filled_pages;
+ /* Ensure data ring slots (packet buffers) are visible. */
+ dma_wmb();
+
+ /* Alloc gve_queue_resources */
+ rx->q_resources =
+ dma_alloc_coherent(hdev,
+ sizeof(*rx->q_resources),
+ &rx->q_resources_bus,
+ GFP_KERNEL);
+ if (!rx->q_resources) {
+ err = -ENOMEM;
+ goto abort_filled;
+ }
+ netif_dbg(priv, drv, priv->dev, "rx[%d]->data.data_bus=%lx\n", idx,
+ (unsigned long)rx->data.data_bus);
+
+ /* alloc rx desc ring */
+ bytes = sizeof(struct gve_rx_desc) * priv->rx_desc_cnt;
+ npages = bytes / PAGE_SIZE;
+ if (npages * PAGE_SIZE != bytes) {
+ err = -EIO;
+ goto abort_with_q_resources;
+ }
+
+ rx->desc.desc_ring = dma_alloc_coherent(hdev, bytes, &rx->desc.bus,
+ GFP_KERNEL);
+ if (!rx->desc.desc_ring) {
+ err = -ENOMEM;
+ goto abort_with_q_resources;
+ }
+ rx->desc.mask = slots - 1;
+ rx->desc.cnt = 0;
+ rx->desc.seqno = 1;
+ gve_rx_add_to_block(priv, idx);
+
+ return 0;
+
+abort_with_q_resources:
+ dma_free_coherent(hdev, sizeof(*rx->q_resources),
+ rx->q_resources, rx->q_resources_bus);
+ rx->q_resources = NULL;
+abort_filled:
+ kvfree(rx->data.page_info);
+abort_with_slots:
+ bytes = sizeof(*rx->data.data_ring) * slots;
+ dma_free_coherent(hdev, bytes, rx->data.data_ring, rx->data.data_bus);
+ rx->data.data_ring = NULL;
+
+ return err;
+}
+
+int gve_rx_alloc_rings(struct gve_priv *priv)
+{
+ int err = 0;
+ int i;
+
+ for (i = 0; i < priv->rx_cfg.num_queues; i++) {
+ err = gve_rx_alloc_ring(priv, i);
+ if (err) {
+ netif_err(priv, drv, priv->dev,
+ "Failed to alloc rx ring=%d: err=%d\n",
+ i, err);
+ break;
+ }
+ }
+ /* Unallocate if there was an error */
+ if (err) {
+ int j;
+
+ for (j = 0; j < i; j++)
+ gve_rx_free_ring(priv, j);
+ }
+ return err;
+}
+
+void gve_rx_free_rings(struct gve_priv *priv)
+{
+ int i;
+
+ for (i = 0; i < priv->rx_cfg.num_queues; i++)
+ gve_rx_free_ring(priv, i);
+}
+
+void gve_rx_write_doorbell(struct gve_priv *priv, struct gve_rx_ring *rx)
+{
+ u32 db_idx = be32_to_cpu(rx->q_resources->db_index);
+
+ iowrite32be(rx->desc.fill_cnt, &priv->db_bar2[db_idx]);
+}
+
+static enum pkt_hash_types gve_rss_type(__be16 pkt_flags)
+{
+ if (likely(pkt_flags & (GVE_RXF_TCP | GVE_RXF_UDP)))
+ return PKT_HASH_TYPE_L4;
+ if (pkt_flags & (GVE_RXF_IPV4 | GVE_RXF_IPV6))
+ return PKT_HASH_TYPE_L3;
+ return PKT_HASH_TYPE_L2;
+}
+
+static struct sk_buff *gve_rx_copy(struct net_device *dev,
+ struct napi_struct *napi,
+ struct gve_rx_slot_page_info *page_info,
+ u16 len)
+{
+ struct sk_buff *skb = napi_alloc_skb(napi, len);
+ void *va = page_info->page_address + GVE_RX_PAD +
+ page_info->page_offset;
+
+ if (unlikely(!skb))
+ return NULL;
+
+ __skb_put(skb, len);
+
+ skb_copy_to_linear_data(skb, va, len);
+
+ skb->protocol = eth_type_trans(skb, dev);
+ return skb;
+}
+
+static struct sk_buff *gve_rx_add_frags(struct net_device *dev,
+ struct napi_struct *napi,
+ struct gve_rx_slot_page_info *page_info,
+ u16 len)
+{
+ struct sk_buff *skb = napi_get_frags(napi);
+
+ if (unlikely(!skb))
+ return NULL;
+
+ skb_add_rx_frag(skb, 0, page_info->page,
+ page_info->page_offset +
+ GVE_RX_PAD, len, PAGE_SIZE / 2);
+
+ return skb;
+}
+
+static void gve_rx_flip_buff(struct gve_rx_slot_page_info *page_info,
+ struct gve_rx_data_slot *data_ring)
+{
+ u64 addr = be64_to_cpu(data_ring->qpl_offset);
+
+ page_info->page_offset ^= PAGE_SIZE / 2;
+ addr ^= PAGE_SIZE / 2;
+ data_ring->qpl_offset = cpu_to_be64(addr);
+}
+
+static bool gve_rx(struct gve_rx_ring *rx, struct gve_rx_desc *rx_desc,
+ netdev_features_t feat)
+{
+ struct gve_rx_slot_page_info *page_info;
+ struct gve_priv *priv = rx->gve;
+ struct napi_struct *napi = &priv->ntfy_blocks[rx->ntfy_id].napi;
+ struct net_device *dev = priv->dev;
+ struct sk_buff *skb;
+ int pagecount;
+ u16 len;
+ u32 idx;
+
+ /* drop this packet */
+ if (unlikely(rx_desc->flags_seq & GVE_RXF_ERR))
+ return true;
+
+ len = be16_to_cpu(rx_desc->len) - GVE_RX_PAD;
+ idx = rx->data.cnt & rx->data.mask;
+ page_info = &rx->data.page_info[idx];
+
+ /* gvnic can only receive into registered segments. If the buffer
+ * can't be recycled, our only choice is to copy the data out of
+ * it so that we can return it to the device.
+ */
+
+ if (PAGE_SIZE == 4096) {
+ if (len <= priv->rx_copybreak) {
+ /* Just copy small packets */
+ skb = gve_rx_copy(dev, napi, page_info, len);
+ goto have_skb;
+ }
+ if (unlikely(!gve_can_recycle_pages(dev))) {
+ skb = gve_rx_copy(dev, napi, page_info, len);
+ goto have_skb;
+ }
+ pagecount = page_count(page_info->page);
+ if (pagecount == 1) {
+ /* No part of this page is used by any SKBs; we attach
+ * the page fragment to a new SKB and pass it up the
+ * stack.
+ */
+ skb = gve_rx_add_frags(dev, napi, page_info, len);
+ if (!skb)
+ return true;
+ /* Make sure the kernel stack can't release the page */
+ get_page(page_info->page);
+ /* "flip" to other packet buffer on this page */
+ gve_rx_flip_buff(page_info, &rx->data.data_ring[idx]);
+ } else if (pagecount >= 2) {
+ /* We have previously passed the other half of this
+ * page up the stack, but it has not yet been freed.
+ */
+ skb = gve_rx_copy(dev, napi, page_info, len);
+ } else {
+ WARN(pagecount < 1, "Pagecount should never be < 1");
+ return false;
+ }
+ } else {
+ skb = gve_rx_copy(dev, napi, page_info, len);
+ }
+
+have_skb:
+ /* We didn't manage to allocate an skb but we haven't had any
+ * reset worthy failures.
+ */
+ if (!skb)
+ return true;
+
+ rx->data.cnt++;
+
+ if (likely(feat & NETIF_F_RXCSUM)) {
+ /* NIC passes up the partial sum */
+ if (rx_desc->csum)
+ skb->ip_summed = CHECKSUM_COMPLETE;
+ else
+ skb->ip_summed = CHECKSUM_NONE;
+ skb->csum = csum_unfold(rx_desc->csum);
+ }
+
+ /* parse flags & pass relevant info up */
+ if (likely(feat & NETIF_F_RXHASH) &&
+ gve_needs_rss(rx_desc->flags_seq))
+ skb_set_hash(skb, be32_to_cpu(rx_desc->rss_hash),
+ gve_rss_type(rx_desc->flags_seq));
+
+ if (skb_is_nonlinear(skb))
+ napi_gro_frags(napi);
+ else
+ napi_gro_receive(napi, skb);
+ return true;
+}
+
+static bool gve_rx_work_pending(struct gve_rx_ring *rx)
+{
+ struct gve_rx_desc *desc;
+ __be16 flags_seq;
+ u32 next_idx;
+
+ next_idx = rx->desc.cnt & rx->desc.mask;
+ desc = rx->desc.desc_ring + next_idx;
+
+ flags_seq = desc->flags_seq;
+ /* Make sure we have synchronized the seq no with the device */
+ smp_rmb();
+
+ return (GVE_SEQNO(flags_seq) == rx->desc.seqno);
+}
+
+bool gve_clean_rx_done(struct gve_rx_ring *rx, int budget,
+ netdev_features_t feat)
+{
+ struct gve_priv *priv = rx->gve;
+ struct gve_rx_desc *desc;
+ u32 cnt = rx->desc.cnt;
+ u32 idx = cnt & rx->desc.mask;
+ u32 work_done = 0;
+ u64 bytes = 0;
+
+ desc = rx->desc.desc_ring + idx;
+ while ((GVE_SEQNO(desc->flags_seq) == rx->desc.seqno) &&
+ work_done < budget) {
+ netif_info(priv, rx_status, priv->dev,
+ "[%d] idx=%d desc=%p desc->flags_seq=0x%x\n",
+ rx->q_num, idx, desc, desc->flags_seq);
+ netif_info(priv, rx_status, priv->dev,
+ "[%d] seqno=%d rx->desc.seqno=%d\n",
+ rx->q_num, GVE_SEQNO(desc->flags_seq),
+ rx->desc.seqno);
+ bytes += be16_to_cpu(desc->len) - GVE_RX_PAD;
+ if (!gve_rx(rx, desc, feat))
+ gve_schedule_reset(priv);
+ cnt++;
+ idx = cnt & rx->desc.mask;
+ desc = rx->desc.desc_ring + idx;
+ rx->desc.seqno = gve_next_seqno(rx->desc.seqno);
+ work_done++;
+ }
+
+ if (!work_done)
+ return false;
+
+ u64_stats_update_begin(&rx->statss);
+ rx->rpackets += work_done;
+ rx->rbytes += bytes;
+ u64_stats_update_end(&rx->statss);
+ rx->desc.cnt = cnt;
+ rx->desc.fill_cnt += work_done;
+
+ /* restock desc ring slots */
+ dma_wmb(); /* Ensure descs are visible before ringing doorbell */
+ gve_rx_write_doorbell(priv, rx);
+ return gve_rx_work_pending(rx);
+}
+
+bool gve_rx_poll(struct gve_notify_block *block, int budget)
+{
+ struct gve_rx_ring *rx = block->rx;
+ netdev_features_t feat;
+ bool repoll = false;
+
+ feat = block->napi.dev->features;
+
+ /* If budget is 0, do all the work */
+ if (budget == 0)
+ budget = INT_MAX;
+
+ if (budget > 0)
+ repoll |= gve_clean_rx_done(rx, budget, feat);
+ else
+ repoll |= gve_rx_work_pending(rx);
+ return repoll;
+}
diff --git a/drivers/net/ethernet/google/gve/gve_tx.c b/drivers/net/ethernet/google/gve/gve_tx.c
new file mode 100644
index 000000000000..778b87b5a06c
--- /dev/null
+++ b/drivers/net/ethernet/google/gve/gve_tx.c
@@ -0,0 +1,584 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Google virtual Ethernet (gve) driver
+ *
+ * Copyright (C) 2015-2019 Google, Inc.
+ */
+
+#include "gve.h"
+#include "gve_adminq.h"
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/vmalloc.h>
+#include <linux/skbuff.h>
+
+static inline void gve_tx_put_doorbell(struct gve_priv *priv,
+ struct gve_queue_resources *q_resources,
+ u32 val)
+{
+ iowrite32be(val, &priv->db_bar2[be32_to_cpu(q_resources->db_index)]);
+}
+
+/* gvnic can only transmit from a Registered Segment.
+ * We copy skb payloads into the registered segment before writing Tx
+ * descriptors and ringing the Tx doorbell.
+ *
+ * gve_tx_fifo_* manages the Registered Segment as a FIFO - clients must
+ * free allocations in the order they were allocated.
+ */
+
+static int gve_tx_fifo_init(struct gve_priv *priv, struct gve_tx_fifo *fifo)
+{
+ fifo->base = vmap(fifo->qpl->pages, fifo->qpl->num_entries, VM_MAP,
+ PAGE_KERNEL);
+ if (unlikely(!fifo->base)) {
+ netif_err(priv, drv, priv->dev, "Failed to vmap fifo, qpl_id = %d\n",
+ fifo->qpl->id);
+ return -ENOMEM;
+ }
+
+ fifo->size = fifo->qpl->num_entries * PAGE_SIZE;
+ atomic_set(&fifo->available, fifo->size);
+ fifo->head = 0;
+ return 0;
+}
+
+static void gve_tx_fifo_release(struct gve_priv *priv, struct gve_tx_fifo *fifo)
+{
+ WARN(atomic_read(&fifo->available) != fifo->size,
+ "Releasing non-empty fifo");
+
+ vunmap(fifo->base);
+}
+
+static int gve_tx_fifo_pad_alloc_one_frag(struct gve_tx_fifo *fifo,
+ size_t bytes)
+{
+ return (fifo->head + bytes < fifo->size) ? 0 : fifo->size - fifo->head;
+}
+
+static bool gve_tx_fifo_can_alloc(struct gve_tx_fifo *fifo, size_t bytes)
+{
+ return (atomic_read(&fifo->available) <= bytes) ? false : true;
+}
+
+/* gve_tx_alloc_fifo - Allocate fragment(s) from Tx FIFO
+ * @fifo: FIFO to allocate from
+ * @bytes: Allocation size
+ * @iov: Scatter-gather elements to fill with allocation fragment base/len
+ *
+ * Returns number of valid elements in iov[] or negative on error.
+ *
+ * Allocations from a given FIFO must be externally synchronized but concurrent
+ * allocation and frees are allowed.
+ */
+static int gve_tx_alloc_fifo(struct gve_tx_fifo *fifo, size_t bytes,
+ struct gve_tx_iovec iov[2])
+{
+ size_t overflow, padding;
+ u32 aligned_head;
+ int nfrags = 0;
+
+ if (!bytes)
+ return 0;
+
+ /* This check happens before we know how much padding is needed to
+ * align to a cacheline boundary for the payload, but that is fine,
+ * because the FIFO head always start aligned, and the FIFO's boundaries
+ * are aligned, so if there is space for the data, there is space for
+ * the padding to the next alignment.
+ */
+ WARN(!gve_tx_fifo_can_alloc(fifo, bytes),
+ "Reached %s when there's not enough space in the fifo", __func__);
+
+ nfrags++;
+
+ iov[0].iov_offset = fifo->head;
+ iov[0].iov_len = bytes;
+ fifo->head += bytes;
+
+ if (fifo->head > fifo->size) {
+ /* If the allocation did not fit in the tail fragment of the
+ * FIFO, also use the head fragment.
+ */
+ nfrags++;
+ overflow = fifo->head - fifo->size;
+ iov[0].iov_len -= overflow;
+ iov[1].iov_offset = 0; /* Start of fifo*/
+ iov[1].iov_len = overflow;
+
+ fifo->head = overflow;
+ }
+
+ /* Re-align to a cacheline boundary */
+ aligned_head = L1_CACHE_ALIGN(fifo->head);
+ padding = aligned_head - fifo->head;
+ iov[nfrags - 1].iov_padding = padding;
+ atomic_sub(bytes + padding, &fifo->available);
+ fifo->head = aligned_head;
+
+ if (fifo->head == fifo->size)
+ fifo->head = 0;
+
+ return nfrags;
+}
+
+/* gve_tx_free_fifo - Return space to Tx FIFO
+ * @fifo: FIFO to return fragments to
+ * @bytes: Bytes to free
+ */
+static void gve_tx_free_fifo(struct gve_tx_fifo *fifo, size_t bytes)
+{
+ atomic_add(bytes, &fifo->available);
+}
+
+static void gve_tx_remove_from_block(struct gve_priv *priv, int queue_idx)
+{
+ struct gve_notify_block *block =
+ &priv->ntfy_blocks[gve_tx_idx_to_ntfy(priv, queue_idx)];
+
+ block->tx = NULL;
+}
+
+static int gve_clean_tx_done(struct gve_priv *priv, struct gve_tx_ring *tx,
+ u32 to_do, bool try_to_wake);
+
+static void gve_tx_free_ring(struct gve_priv *priv, int idx)
+{
+ struct gve_tx_ring *tx = &priv->tx[idx];
+ struct device *hdev = &priv->pdev->dev;
+ size_t bytes;
+ u32 slots;
+
+ gve_tx_remove_from_block(priv, idx);
+ slots = tx->mask + 1;
+ gve_clean_tx_done(priv, tx, tx->req, false);
+ netdev_tx_reset_queue(tx->netdev_txq);
+
+ dma_free_coherent(hdev, sizeof(*tx->q_resources),
+ tx->q_resources, tx->q_resources_bus);
+ tx->q_resources = NULL;
+
+ gve_tx_fifo_release(priv, &tx->tx_fifo);
+ gve_unassign_qpl(priv, tx->tx_fifo.qpl->id);
+ tx->tx_fifo.qpl = NULL;
+
+ bytes = sizeof(*tx->desc) * slots;
+ dma_free_coherent(hdev, bytes, tx->desc, tx->bus);
+ tx->desc = NULL;
+
+ vfree(tx->info);
+ tx->info = NULL;
+
+ netif_dbg(priv, drv, priv->dev, "freed tx queue %d\n", idx);
+}
+
+static void gve_tx_add_to_block(struct gve_priv *priv, int queue_idx)
+{
+ int ntfy_idx = gve_tx_idx_to_ntfy(priv, queue_idx);
+ struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
+ struct gve_tx_ring *tx = &priv->tx[queue_idx];
+
+ block->tx = tx;
+ tx->ntfy_id = ntfy_idx;
+}
+
+static int gve_tx_alloc_ring(struct gve_priv *priv, int idx)
+{
+ struct gve_tx_ring *tx = &priv->tx[idx];
+ struct device *hdev = &priv->pdev->dev;
+ u32 slots = priv->tx_desc_cnt;
+ size_t bytes;
+
+ /* Make sure everything is zeroed to start */
+ memset(tx, 0, sizeof(*tx));
+ tx->q_num = idx;
+
+ tx->mask = slots - 1;
+
+ /* alloc metadata */
+ tx->info = vzalloc(sizeof(*tx->info) * slots);
+ if (!tx->info)
+ return -ENOMEM;
+
+ /* alloc tx queue */
+ bytes = sizeof(*tx->desc) * slots;
+ tx->desc = dma_alloc_coherent(hdev, bytes, &tx->bus, GFP_KERNEL);
+ if (!tx->desc)
+ goto abort_with_info;
+
+ tx->tx_fifo.qpl = gve_assign_tx_qpl(priv);
+
+ /* map Tx FIFO */
+ if (gve_tx_fifo_init(priv, &tx->tx_fifo))
+ goto abort_with_desc;
+
+ tx->q_resources =
+ dma_alloc_coherent(hdev,
+ sizeof(*tx->q_resources),
+ &tx->q_resources_bus,
+ GFP_KERNEL);
+ if (!tx->q_resources)
+ goto abort_with_fifo;
+
+ netif_dbg(priv, drv, priv->dev, "tx[%d]->bus=%lx\n", idx,
+ (unsigned long)tx->bus);
+ tx->netdev_txq = netdev_get_tx_queue(priv->dev, idx);
+ gve_tx_add_to_block(priv, idx);
+
+ return 0;
+
+abort_with_fifo:
+ gve_tx_fifo_release(priv, &tx->tx_fifo);
+abort_with_desc:
+ dma_free_coherent(hdev, bytes, tx->desc, tx->bus);
+ tx->desc = NULL;
+abort_with_info:
+ vfree(tx->info);
+ tx->info = NULL;
+ return -ENOMEM;
+}
+
+int gve_tx_alloc_rings(struct gve_priv *priv)
+{
+ int err = 0;
+ int i;
+
+ for (i = 0; i < priv->tx_cfg.num_queues; i++) {
+ err = gve_tx_alloc_ring(priv, i);
+ if (err) {
+ netif_err(priv, drv, priv->dev,
+ "Failed to alloc tx ring=%d: err=%d\n",
+ i, err);
+ break;
+ }
+ }
+ /* Unallocate if there was an error */
+ if (err) {
+ int j;
+
+ for (j = 0; j < i; j++)
+ gve_tx_free_ring(priv, j);
+ }
+ return err;
+}
+
+void gve_tx_free_rings(struct gve_priv *priv)
+{
+ int i;
+
+ for (i = 0; i < priv->tx_cfg.num_queues; i++)
+ gve_tx_free_ring(priv, i);
+}
+
+/* gve_tx_avail - Calculates the number of slots available in the ring
+ * @tx: tx ring to check
+ *
+ * Returns the number of slots available
+ *
+ * The capacity of the queue is mask + 1. We don't need to reserve an entry.
+ **/
+static inline u32 gve_tx_avail(struct gve_tx_ring *tx)
+{
+ return tx->mask + 1 - (tx->req - tx->done);
+}
+
+static inline int gve_skb_fifo_bytes_required(struct gve_tx_ring *tx,
+ struct sk_buff *skb)
+{
+ int pad_bytes, align_hdr_pad;
+ int bytes;
+ int hlen;
+
+ hlen = skb_is_gso(skb) ? skb_checksum_start_offset(skb) +
+ tcp_hdrlen(skb) : skb_headlen(skb);
+
+ pad_bytes = gve_tx_fifo_pad_alloc_one_frag(&tx->tx_fifo,
+ hlen);
+ /* We need to take into account the header alignment padding. */
+ align_hdr_pad = L1_CACHE_ALIGN(hlen) - hlen;
+ bytes = align_hdr_pad + pad_bytes + skb->len;
+
+ return bytes;
+}
+
+/* The most descriptors we could need are 3 - 1 for the headers, 1 for
+ * the beginning of the payload at the end of the FIFO, and 1 if the
+ * payload wraps to the beginning of the FIFO.
+ */
+#define MAX_TX_DESC_NEEDED 3
+
+/* Check if sufficient resources (descriptor ring space, FIFO space) are
+ * available to transmit the given number of bytes.
+ */
+static inline bool gve_can_tx(struct gve_tx_ring *tx, int bytes_required)
+{
+ return (gve_tx_avail(tx) >= MAX_TX_DESC_NEEDED &&
+ gve_tx_fifo_can_alloc(&tx->tx_fifo, bytes_required));
+}
+
+/* Stops the queue if the skb cannot be transmitted. */
+static int gve_maybe_stop_tx(struct gve_tx_ring *tx, struct sk_buff *skb)
+{
+ int bytes_required;
+
+ bytes_required = gve_skb_fifo_bytes_required(tx, skb);
+ if (likely(gve_can_tx(tx, bytes_required)))
+ return 0;
+
+ /* No space, so stop the queue */
+ tx->stop_queue++;
+ netif_tx_stop_queue(tx->netdev_txq);
+ smp_mb(); /* sync with restarting queue in gve_clean_tx_done() */
+
+ /* Now check for resources again, in case gve_clean_tx_done() freed
+ * resources after we checked and we stopped the queue after
+ * gve_clean_tx_done() checked.
+ *
+ * gve_maybe_stop_tx() gve_clean_tx_done()
+ * nsegs/can_alloc test failed
+ * gve_tx_free_fifo()
+ * if (tx queue stopped)
+ * netif_tx_queue_wake()
+ * netif_tx_stop_queue()
+ * Need to check again for space here!
+ */
+ if (likely(!gve_can_tx(tx, bytes_required)))
+ return -EBUSY;
+
+ netif_tx_start_queue(tx->netdev_txq);
+ tx->wake_queue++;
+ return 0;
+}
+
+static void gve_tx_fill_pkt_desc(union gve_tx_desc *pkt_desc,
+ struct sk_buff *skb, bool is_gso,
+ int l4_hdr_offset, u32 desc_cnt,
+ u16 hlen, u64 addr)
+{
+ /* l4_hdr_offset and csum_offset are in units of 16-bit words */
+ if (is_gso) {
+ pkt_desc->pkt.type_flags = GVE_TXD_TSO | GVE_TXF_L4CSUM;
+ pkt_desc->pkt.l4_csum_offset = skb->csum_offset >> 1;
+ pkt_desc->pkt.l4_hdr_offset = l4_hdr_offset >> 1;
+ } else if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
+ pkt_desc->pkt.type_flags = GVE_TXD_STD | GVE_TXF_L4CSUM;
+ pkt_desc->pkt.l4_csum_offset = skb->csum_offset >> 1;
+ pkt_desc->pkt.l4_hdr_offset = l4_hdr_offset >> 1;
+ } else {
+ pkt_desc->pkt.type_flags = GVE_TXD_STD;
+ pkt_desc->pkt.l4_csum_offset = 0;
+ pkt_desc->pkt.l4_hdr_offset = 0;
+ }
+ pkt_desc->pkt.desc_cnt = desc_cnt;
+ pkt_desc->pkt.len = cpu_to_be16(skb->len);
+ pkt_desc->pkt.seg_len = cpu_to_be16(hlen);
+ pkt_desc->pkt.seg_addr = cpu_to_be64(addr);
+}
+
+static void gve_tx_fill_seg_desc(union gve_tx_desc *seg_desc,
+ struct sk_buff *skb, bool is_gso,
+ u16 len, u64 addr)
+{
+ seg_desc->seg.type_flags = GVE_TXD_SEG;
+ if (is_gso) {
+ if (skb_is_gso_v6(skb))
+ seg_desc->seg.type_flags |= GVE_TXSF_IPV6;
+ seg_desc->seg.l3_offset = skb_network_offset(skb) >> 1;
+ seg_desc->seg.mss = cpu_to_be16(skb_shinfo(skb)->gso_size);
+ }
+ seg_desc->seg.seg_len = cpu_to_be16(len);
+ seg_desc->seg.seg_addr = cpu_to_be64(addr);
+}
+
+static int gve_tx_add_skb(struct gve_tx_ring *tx, struct sk_buff *skb)
+{
+ int pad_bytes, hlen, hdr_nfrags, payload_nfrags, l4_hdr_offset;
+ union gve_tx_desc *pkt_desc, *seg_desc;
+ struct gve_tx_buffer_state *info;
+ bool is_gso = skb_is_gso(skb);
+ u32 idx = tx->req & tx->mask;
+ int payload_iov = 2;
+ int copy_offset;
+ u32 next_idx;
+ int i;
+
+ info = &tx->info[idx];
+ pkt_desc = &tx->desc[idx];
+
+ l4_hdr_offset = skb_checksum_start_offset(skb);
+ /* If the skb is gso, then we want the tcp header in the first segment
+ * otherwise we want the linear portion of the skb (which will contain
+ * the checksum because skb->csum_start and skb->csum_offset are given
+ * relative to skb->head) in the first segment.
+ */
+ hlen = is_gso ? l4_hdr_offset + tcp_hdrlen(skb) :
+ skb_headlen(skb);
+
+ info->skb = skb;
+ /* We don't want to split the header, so if necessary, pad to the end
+ * of the fifo and then put the header at the beginning of the fifo.
+ */
+ pad_bytes = gve_tx_fifo_pad_alloc_one_frag(&tx->tx_fifo, hlen);
+ hdr_nfrags = gve_tx_alloc_fifo(&tx->tx_fifo, hlen + pad_bytes,
+ &info->iov[0]);
+ WARN(!hdr_nfrags, "hdr_nfrags should never be 0!");
+ payload_nfrags = gve_tx_alloc_fifo(&tx->tx_fifo, skb->len - hlen,
+ &info->iov[payload_iov]);
+
+ gve_tx_fill_pkt_desc(pkt_desc, skb, is_gso, l4_hdr_offset,
+ 1 + payload_nfrags, hlen,
+ info->iov[hdr_nfrags - 1].iov_offset);
+
+ skb_copy_bits(skb, 0,
+ tx->tx_fifo.base + info->iov[hdr_nfrags - 1].iov_offset,
+ hlen);
+ copy_offset = hlen;
+
+ for (i = payload_iov; i < payload_nfrags + payload_iov; i++) {
+ next_idx = (tx->req + 1 + i - payload_iov) & tx->mask;
+ seg_desc = &tx->desc[next_idx];
+
+ gve_tx_fill_seg_desc(seg_desc, skb, is_gso,
+ info->iov[i].iov_len,
+ info->iov[i].iov_offset);
+
+ skb_copy_bits(skb, copy_offset,
+ tx->tx_fifo.base + info->iov[i].iov_offset,
+ info->iov[i].iov_len);
+ copy_offset += info->iov[i].iov_len;
+ }
+
+ return 1 + payload_nfrags;
+}
+
+netdev_tx_t gve_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ struct gve_priv *priv = netdev_priv(dev);
+ struct gve_tx_ring *tx;
+ int nsegs;
+
+ WARN(skb_get_queue_mapping(skb) > priv->tx_cfg.num_queues,
+ "skb queue index out of range");
+ tx = &priv->tx[skb_get_queue_mapping(skb)];
+ if (unlikely(gve_maybe_stop_tx(tx, skb))) {
+ /* We need to ring the txq doorbell -- we have stopped the Tx
+ * queue for want of resources, but prior calls to gve_tx()
+ * may have added descriptors without ringing the doorbell.
+ */
+
+ /* Ensure tx descs from a prior gve_tx are visible before
+ * ringing doorbell.
+ */
+ dma_wmb();
+ gve_tx_put_doorbell(priv, tx->q_resources, tx->req);
+ return NETDEV_TX_BUSY;
+ }
+ nsegs = gve_tx_add_skb(tx, skb);
+
+ netdev_tx_sent_queue(tx->netdev_txq, skb->len);
+ skb_tx_timestamp(skb);
+
+ /* give packets to NIC */
+ tx->req += nsegs;
+
+ if (!netif_xmit_stopped(tx->netdev_txq) && netdev_xmit_more())
+ return NETDEV_TX_OK;
+
+ /* Ensure tx descs are visible before ringing doorbell */
+ dma_wmb();
+ gve_tx_put_doorbell(priv, tx->q_resources, tx->req);
+ return NETDEV_TX_OK;
+}
+
+#define GVE_TX_START_THRESH PAGE_SIZE
+
+static int gve_clean_tx_done(struct gve_priv *priv, struct gve_tx_ring *tx,
+ u32 to_do, bool try_to_wake)
+{
+ struct gve_tx_buffer_state *info;
+ u64 pkts = 0, bytes = 0;
+ size_t space_freed = 0;
+ struct sk_buff *skb;
+ int i, j;
+ u32 idx;
+
+ for (j = 0; j < to_do; j++) {
+ idx = tx->done & tx->mask;
+ netif_info(priv, tx_done, priv->dev,
+ "[%d] %s: idx=%d (req=%u done=%u)\n",
+ tx->q_num, __func__, idx, tx->req, tx->done);
+ info = &tx->info[idx];
+ skb = info->skb;
+
+ /* Mark as free */
+ if (skb) {
+ info->skb = NULL;
+ bytes += skb->len;
+ pkts++;
+ dev_consume_skb_any(skb);
+ /* FIFO free */
+ for (i = 0; i < ARRAY_SIZE(info->iov); i++) {
+ space_freed += info->iov[i].iov_len +
+ info->iov[i].iov_padding;
+ info->iov[i].iov_len = 0;
+ info->iov[i].iov_padding = 0;
+ }
+ }
+ tx->done++;
+ }
+
+ gve_tx_free_fifo(&tx->tx_fifo, space_freed);
+ u64_stats_update_begin(&tx->statss);
+ tx->bytes_done += bytes;
+ tx->pkt_done += pkts;
+ u64_stats_update_end(&tx->statss);
+ netdev_tx_completed_queue(tx->netdev_txq, pkts, bytes);
+
+ /* start the queue if we've stopped it */
+#ifndef CONFIG_BQL
+ /* Make sure that the doorbells are synced */
+ smp_mb();
+#endif
+ if (try_to_wake && netif_tx_queue_stopped(tx->netdev_txq) &&
+ likely(gve_can_tx(tx, GVE_TX_START_THRESH))) {
+ tx->wake_queue++;
+ netif_tx_wake_queue(tx->netdev_txq);
+ }
+
+ return pkts;
+}
+
+__be32 gve_tx_load_event_counter(struct gve_priv *priv,
+ struct gve_tx_ring *tx)
+{
+ u32 counter_index = be32_to_cpu((tx->q_resources->counter_index));
+
+ return READ_ONCE(priv->counter_array[counter_index]);
+}
+
+bool gve_tx_poll(struct gve_notify_block *block, int budget)
+{
+ struct gve_priv *priv = block->priv;
+ struct gve_tx_ring *tx = block->tx;
+ bool repoll = false;
+ u32 nic_done;
+ u32 to_do;
+
+ /* If budget is 0, do all the work */
+ if (budget == 0)
+ budget = INT_MAX;
+
+ /* Find out how much work there is to be done */
+ tx->last_nic_done = gve_tx_load_event_counter(priv, tx);
+ nic_done = be32_to_cpu(tx->last_nic_done);
+ if (budget > 0) {
+ /* Do as much work as we have that the budget will
+ * allow
+ */
+ to_do = min_t(u32, (nic_done - tx->done), budget);
+ gve_clean_tx_done(priv, tx, to_do, true);
+ }
+ /* If we still have work we want to repoll */
+ repoll |= (nic_done != tx->done);
+ return repoll;
+}
diff --git a/drivers/net/ethernet/hisilicon/Kconfig b/drivers/net/ethernet/hisilicon/Kconfig
index a0d780c14e60..3892a2062404 100644
--- a/drivers/net/ethernet/hisilicon/Kconfig
+++ b/drivers/net/ethernet/hisilicon/Kconfig
@@ -46,6 +46,16 @@ config HIP04_ETH
If you wish to compile a kernel for a hardware with hisilicon p04 SoC and
want to use the internal ethernet then you should answer Y to this.
+config HI13X1_GMAC
+ bool "Hisilicon HI13X1 Network Device Support"
+ depends on HIP04_ETH
+ help
+ If you wish to compile a kernel for a hardware with hisilicon hi13x1_gamc
+ then you should answer Y to this. This makes this driver suitable for use
+ on certain boards such as the HI13X1.
+
+ If you are unsure, say N.
+
config HNS_MDIO
tristate
select PHYLIB
diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c
index e1f2978506fd..d60452845539 100644
--- a/drivers/net/ethernet/hisilicon/hip04_eth.c
+++ b/drivers/net/ethernet/hisilicon/hip04_eth.c
@@ -16,6 +16,8 @@
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
+#define SC_PPE_RESET_DREQ 0x026C
+
#define PPE_CFG_RX_ADDR 0x100
#define PPE_CFG_POOL_GRP 0x300
#define PPE_CFG_RX_BUF_SIZE 0x400
@@ -33,10 +35,23 @@
#define GE_MODE_CHANGE_REG 0x1b4
#define GE_RECV_CONTROL_REG 0x1e0
#define GE_STATION_MAC_ADDRESS 0x210
-#define PPE_CFG_CPU_ADD_ADDR 0x580
-#define PPE_CFG_MAX_FRAME_LEN_REG 0x408
+
#define PPE_CFG_BUS_CTRL_REG 0x424
#define PPE_CFG_RX_CTRL_REG 0x428
+
+#if defined(CONFIG_HI13X1_GMAC)
+#define PPE_CFG_CPU_ADD_ADDR 0x6D0
+#define PPE_CFG_MAX_FRAME_LEN_REG 0x500
+#define PPE_CFG_RX_PKT_MODE_REG 0x504
+#define PPE_CFG_QOS_VMID_GEN 0x520
+#define PPE_CFG_RX_PKT_INT 0x740
+#define PPE_INTEN 0x700
+#define PPE_INTSTS 0x708
+#define PPE_RINT 0x704
+#define PPE_CFG_STS_MODE 0x880
+#else
+#define PPE_CFG_CPU_ADD_ADDR 0x580
+#define PPE_CFG_MAX_FRAME_LEN_REG 0x408
#define PPE_CFG_RX_PKT_MODE_REG 0x438
#define PPE_CFG_QOS_VMID_GEN 0x500
#define PPE_CFG_RX_PKT_INT 0x538
@@ -44,8 +59,12 @@
#define PPE_INTSTS 0x608
#define PPE_RINT 0x604
#define PPE_CFG_STS_MODE 0x700
+#endif /* CONFIG_HI13X1_GMAC */
+
#define PPE_HIS_RX_PKT_CNT 0x804
+#define RESET_DREQ_ALL 0xffffffff
+
/* REG_INTERRUPT */
#define RCV_INT BIT(10)
#define RCV_NOBUF BIT(8)
@@ -57,8 +76,15 @@
/* TX descriptor config */
#define TX_FREE_MEM BIT(0)
#define TX_READ_ALLOC_L3 BIT(1)
-#define TX_FINISH_CACHE_INV BIT(2)
+#if defined(CONFIG_HI13X1_GMAC)
+#define TX_CLEAR_WB BIT(7)
+#define TX_RELEASE_TO_PPE BIT(4)
+#define TX_FINISH_CACHE_INV BIT(6)
+#define TX_POOL_SHIFT 16
+#else
#define TX_CLEAR_WB BIT(4)
+#define TX_FINISH_CACHE_INV BIT(2)
+#endif
#define TX_L3_CHECKSUM BIT(5)
#define TX_LOOP_BACK BIT(11)
@@ -93,18 +119,35 @@
#define GE_RX_PORT_EN BIT(1)
#define GE_TX_PORT_EN BIT(2)
-#define PPE_CFG_STS_RX_PKT_CNT_RC BIT(12)
-
#define PPE_CFG_RX_PKT_ALIGN BIT(18)
-#define PPE_CFG_QOS_VMID_MODE BIT(14)
+
+#if defined(CONFIG_HI13X1_GMAC)
+#define PPE_CFG_QOS_VMID_GRP_SHIFT 4
+#define PPE_CFG_RX_CTRL_ALIGN_SHIFT 7
+#define PPE_CFG_STS_RX_PKT_CNT_RC BIT(0)
+#define PPE_CFG_QOS_VMID_MODE BIT(15)
+#define PPE_CFG_BUS_LOCAL_REL (BIT(9) | BIT(15) | BIT(19) | BIT(23))
+
+/* buf unit size is cache_line_size, which is 64, so the shift is 6 */
+#define PPE_BUF_SIZE_SHIFT 6
+#define PPE_TX_BUF_HOLD BIT(31)
+#define CACHE_LINE_MASK 0x3F
+#else
#define PPE_CFG_QOS_VMID_GRP_SHIFT 8
+#define PPE_CFG_RX_CTRL_ALIGN_SHIFT 11
+#define PPE_CFG_STS_RX_PKT_CNT_RC BIT(12)
+#define PPE_CFG_QOS_VMID_MODE BIT(14)
+#define PPE_CFG_BUS_LOCAL_REL BIT(14)
+
+/* buf unit size is 1, so the shift is 6 */
+#define PPE_BUF_SIZE_SHIFT 0
+#define PPE_TX_BUF_HOLD 0
+#endif /* CONFIG_HI13X1_GMAC */
#define PPE_CFG_RX_FIFO_FSFU BIT(11)
#define PPE_CFG_RX_DEPTH_SHIFT 16
#define PPE_CFG_RX_START_SHIFT 0
-#define PPE_CFG_RX_CTRL_ALIGN_SHIFT 11
-#define PPE_CFG_BUS_LOCAL_REL BIT(14)
#define PPE_CFG_BUS_BIG_ENDIEN BIT(0)
#define RX_DESC_NUM 128
@@ -128,26 +171,50 @@
#define HIP04_MIN_TX_COALESCE_FRAMES 100
struct tx_desc {
+#if defined(CONFIG_HI13X1_GMAC)
+ u32 reserved1[2];
+ u32 send_addr;
+ u16 send_size;
+ u16 data_offset;
+ u32 reserved2[7];
+ u32 cfg;
+ u32 wb_addr;
+ u32 reserved3[3];
+#else
u32 send_addr;
u32 send_size;
u32 next_addr;
u32 cfg;
u32 wb_addr;
+#endif
} __aligned(64);
struct rx_desc {
+#if defined(CONFIG_HI13X1_GMAC)
+ u32 reserved1[3];
+ u16 pkt_len;
+ u16 reserved_16;
+ u32 reserved2[6];
+ u32 pkt_err;
+ u32 reserved3[5];
+#else
u16 reserved_16;
u16 pkt_len;
u32 reserve1[3];
u32 pkt_err;
u32 reserve2[4];
+#endif
};
struct hip04_priv {
void __iomem *base;
+#if defined(CONFIG_HI13X1_GMAC)
+ void __iomem *sysctrl_base;
+#endif
int phy_mode;
int chan;
unsigned int port;
+ unsigned int group;
unsigned int speed;
unsigned int duplex;
unsigned int reg_inten;
@@ -221,6 +288,13 @@ static void hip04_config_port(struct net_device *ndev, u32 speed, u32 duplex)
writel_relaxed(val, priv->base + GE_MODE_CHANGE_REG);
}
+static void hip04_reset_dreq(struct hip04_priv *priv)
+{
+#if defined(CONFIG_HI13X1_GMAC)
+ writel_relaxed(RESET_DREQ_ALL, priv->sysctrl_base + SC_PPE_RESET_DREQ);
+#endif
+}
+
static void hip04_reset_ppe(struct hip04_priv *priv)
{
u32 val, tmp, timeout = 0;
@@ -241,14 +315,14 @@ static void hip04_config_fifo(struct hip04_priv *priv)
val |= PPE_CFG_STS_RX_PKT_CNT_RC;
writel_relaxed(val, priv->base + PPE_CFG_STS_MODE);
- val = BIT(priv->port);
+ val = BIT(priv->group);
regmap_write(priv->map, priv->port * 4 + PPE_CFG_POOL_GRP, val);
- val = priv->port << PPE_CFG_QOS_VMID_GRP_SHIFT;
+ val = priv->group << PPE_CFG_QOS_VMID_GRP_SHIFT;
val |= PPE_CFG_QOS_VMID_MODE;
writel_relaxed(val, priv->base + PPE_CFG_QOS_VMID_GEN);
- val = RX_BUF_SIZE;
+ val = RX_BUF_SIZE >> PPE_BUF_SIZE_SHIFT;
regmap_write(priv->map, priv->port * 4 + PPE_CFG_RX_BUF_SIZE, val);
val = RX_DESC_NUM << PPE_CFG_RX_DEPTH_SHIFT;
@@ -285,8 +359,10 @@ static void hip04_config_fifo(struct hip04_priv *priv)
val |= GE_RX_STRIP_PAD | GE_RX_PAD_EN;
writel_relaxed(val, priv->base + GE_RECV_CONTROL_REG);
+#ifndef CONFIG_HI13X1_GMAC
val = GE_AUTO_NEG_CTL;
writel_relaxed(val, priv->base + GE_TX_LOCAL_PAGE_REG);
+#endif
}
static void hip04_mac_enable(struct net_device *ndev)
@@ -329,12 +405,18 @@ static void hip04_mac_disable(struct net_device *ndev)
static void hip04_set_xmit_desc(struct hip04_priv *priv, dma_addr_t phys)
{
- writel(phys, priv->base + PPE_CFG_CPU_ADD_ADDR);
+ u32 val;
+
+ val = phys >> PPE_BUF_SIZE_SHIFT | PPE_TX_BUF_HOLD;
+ writel(val, priv->base + PPE_CFG_CPU_ADD_ADDR);
}
static void hip04_set_recv_desc(struct hip04_priv *priv, dma_addr_t phys)
{
- regmap_write(priv->map, priv->port * 4 + PPE_CFG_RX_ADDR, phys);
+ u32 val;
+
+ val = phys >> PPE_BUF_SIZE_SHIFT;
+ regmap_write(priv->map, priv->port * 4 + PPE_CFG_RX_ADDR, val);
}
static u32 hip04_recv_cnt(struct hip04_priv *priv)
@@ -442,11 +524,20 @@ hip04_mac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
priv->tx_skb[tx_head] = skb;
priv->tx_phys[tx_head] = phys;
- desc->send_addr = cpu_to_be32(phys);
- desc->send_size = cpu_to_be32(skb->len);
- desc->cfg = cpu_to_be32(TX_CLEAR_WB | TX_FINISH_CACHE_INV);
+
+ desc->send_size = (__force u32)cpu_to_be32(skb->len);
+#if defined(CONFIG_HI13X1_GMAC)
+ desc->cfg = (__force u32)cpu_to_be32(TX_CLEAR_WB | TX_FINISH_CACHE_INV
+ | TX_RELEASE_TO_PPE | priv->port << TX_POOL_SHIFT);
+ desc->data_offset = (__force u32)cpu_to_be32(phys & CACHE_LINE_MASK);
+ desc->send_addr = (__force u32)cpu_to_be32(phys & ~CACHE_LINE_MASK);
+#else
+ desc->cfg = (__force u32)cpu_to_be32(TX_CLEAR_WB | TX_FINISH_CACHE_INV);
+ desc->send_addr = (__force u32)cpu_to_be32(phys);
+#endif
phys = priv->tx_desc_dma + tx_head * sizeof(struct tx_desc);
- desc->wb_addr = cpu_to_be32(phys);
+ desc->wb_addr = (__force u32)cpu_to_be32(phys +
+ offsetof(struct tx_desc, send_addr));
skb_tx_timestamp(skb);
hip04_set_xmit_desc(priv, phys);
@@ -507,8 +598,8 @@ static int hip04_rx_poll(struct napi_struct *napi, int budget)
priv->rx_phys[priv->rx_head] = 0;
desc = (struct rx_desc *)skb->data;
- len = be16_to_cpu(desc->pkt_len);
- err = be32_to_cpu(desc->pkt_err);
+ len = be16_to_cpu((__force __be16)desc->pkt_len);
+ err = be32_to_cpu((__force __be32)desc->pkt_err);
if (0 == len) {
dev_kfree_skb_any(skb);
@@ -808,7 +899,6 @@ static int hip04_mac_probe(struct platform_device *pdev)
struct of_phandle_args arg;
struct net_device *ndev;
struct hip04_priv *priv;
- struct resource *res;
int irq;
int ret;
@@ -821,14 +911,21 @@ static int hip04_mac_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ndev);
SET_NETDEV_DEV(ndev, &pdev->dev);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- priv->base = devm_ioremap_resource(d, res);
+ priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base)) {
ret = PTR_ERR(priv->base);
goto init_fail;
}
- ret = of_parse_phandle_with_fixed_args(node, "port-handle", 2, 0, &arg);
+#if defined(CONFIG_HI13X1_GMAC)
+ priv->sysctrl_base = devm_platform_ioremap_resource(pdev, 1);
+ if (IS_ERR(priv->sysctrl_base)) {
+ ret = PTR_ERR(priv->sysctrl_base);
+ goto init_fail;
+ }
+#endif
+
+ ret = of_parse_phandle_with_fixed_args(node, "port-handle", 3, 0, &arg);
if (ret < 0) {
dev_warn(d, "no port-handle\n");
goto init_fail;
@@ -836,6 +933,7 @@ static int hip04_mac_probe(struct platform_device *pdev)
priv->port = arg.args[0];
priv->chan = arg.args[1] * RX_DESC_NUM;
+ priv->group = arg.args[2];
hrtimer_init(&priv->tx_coalesce_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
@@ -896,6 +994,7 @@ static int hip04_mac_probe(struct platform_device *pdev)
ndev->irq = irq;
netif_napi_add(ndev, &priv->napi, hip04_rx_poll, NAPI_POLL_WEIGHT);
+ hip04_reset_dreq(priv);
hip04_reset_ppe(priv);
if (priv->phy_mode == PHY_INTERFACE_MODE_MII)
hip04_config_port(ndev, SPEED_100, DUPLEX_FULL);
diff --git a/drivers/net/ethernet/hisilicon/hisi_femac.c b/drivers/net/ethernet/hisilicon/hisi_femac.c
index d2e019d89a6f..689f18e3100f 100644
--- a/drivers/net/ethernet/hisilicon/hisi_femac.c
+++ b/drivers/net/ethernet/hisilicon/hisi_femac.c
@@ -781,7 +781,6 @@ static int hisi_femac_drv_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
- struct resource *res;
struct net_device *ndev;
struct hisi_femac_priv *priv;
struct phy_device *phy;
@@ -799,15 +798,13 @@ static int hisi_femac_drv_probe(struct platform_device *pdev)
priv->dev = dev;
priv->ndev = ndev;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- priv->port_base = devm_ioremap_resource(dev, res);
+ priv->port_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->port_base)) {
ret = PTR_ERR(priv->port_base);
goto out_free_netdev;
}
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- priv->glb_base = devm_ioremap_resource(dev, res);
+ priv->glb_base = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(priv->glb_base)) {
ret = PTR_ERR(priv->glb_base);
goto out_free_netdev;
diff --git a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
index 89ef764e1c4b..349970557c52 100644
--- a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
+++ b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
@@ -1097,7 +1097,6 @@ static int hix5hd2_dev_probe(struct platform_device *pdev)
const struct of_device_id *of_id = NULL;
struct net_device *ndev;
struct hix5hd2_priv *priv;
- struct resource *res;
struct mii_bus *bus;
const char *mac_addr;
int ret;
@@ -1119,15 +1118,13 @@ static int hix5hd2_dev_probe(struct platform_device *pdev)
}
priv->hw_cap = (unsigned long)of_id->data;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- priv->base = devm_ioremap_resource(dev, res);
+ priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base)) {
ret = PTR_ERR(priv->base);
goto out_free_netdev;
}
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- priv->ctrl_base = devm_ioremap_resource(dev, res);
+ priv->ctrl_base = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(priv->ctrl_base)) {
ret = PTR_ERR(priv->ctrl_base);
goto out_free_netdev;
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
index 09c16d88172e..bb6586d0e5af 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
@@ -754,7 +754,7 @@ struct dsaf_misc_op *hns_misc_op_get(struct dsaf_device *dsaf_dev)
return (void *)misc_op;
}
-static int hns_dsaf_dev_match(struct device *dev, void *fwnode)
+static int hns_dsaf_dev_match(struct device *dev, const void *fwnode)
{
return dev->fwnode == fwnode;
}
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
index fe879c07ae3c..2235dd55fab2 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
@@ -2370,6 +2370,7 @@ static int hns_nic_dev_probe(struct platform_device *pdev)
ndev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO |
NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6;
+ ndev->vlan_features |= NETIF_F_TSO | NETIF_F_TSO6;
ndev->max_mtu = MAC_MAX_MTU_V2 -
(ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN);
break;
diff --git a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h
index 83e19c6b974e..8ad5292eebbe 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h
@@ -69,7 +69,7 @@ enum hclge_mbx_vlan_cfg_subcode {
};
#define HCLGE_MBX_MAX_MSG_SIZE 16
-#define HCLGE_MBX_MAX_RESP_DATA_SIZE 16
+#define HCLGE_MBX_MAX_RESP_DATA_SIZE 8
#define HCLGE_MBX_RING_MAP_BASIC_MSG_NUM 3
#define HCLGE_MBX_RING_NODE_VARIABLE_NUM 3
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.c b/drivers/net/ethernet/hisilicon/hns3/hnae3.c
index fa8b8506b120..908d4f45c06a 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hnae3.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.c
@@ -16,21 +16,18 @@ static LIST_HEAD(hnae3_ae_dev_list);
*/
static DEFINE_MUTEX(hnae3_common_lock);
-static bool hnae3_client_match(enum hnae3_client_type client_type,
- enum hnae3_dev_type dev_type)
+static bool hnae3_client_match(enum hnae3_client_type client_type)
{
- if ((dev_type == HNAE3_DEV_KNIC) && (client_type == HNAE3_CLIENT_KNIC ||
- client_type == HNAE3_CLIENT_ROCE))
- return true;
-
- if (dev_type == HNAE3_DEV_UNIC && client_type == HNAE3_CLIENT_UNIC)
+ if (client_type == HNAE3_CLIENT_KNIC ||
+ client_type == HNAE3_CLIENT_ROCE)
return true;
return false;
}
void hnae3_set_client_init_flag(struct hnae3_client *client,
- struct hnae3_ae_dev *ae_dev, int inited)
+ struct hnae3_ae_dev *ae_dev,
+ unsigned int inited)
{
if (!client || !ae_dev)
return;
@@ -39,9 +36,6 @@ void hnae3_set_client_init_flag(struct hnae3_client *client,
case HNAE3_CLIENT_KNIC:
hnae3_set_bit(ae_dev->flag, HNAE3_KNIC_CLIENT_INITED_B, inited);
break;
- case HNAE3_CLIENT_UNIC:
- hnae3_set_bit(ae_dev->flag, HNAE3_UNIC_CLIENT_INITED_B, inited);
- break;
case HNAE3_CLIENT_ROCE:
hnae3_set_bit(ae_dev->flag, HNAE3_ROCE_CLIENT_INITED_B, inited);
break;
@@ -61,10 +55,6 @@ static int hnae3_get_client_init_flag(struct hnae3_client *client,
inited = hnae3_get_bit(ae_dev->flag,
HNAE3_KNIC_CLIENT_INITED_B);
break;
- case HNAE3_CLIENT_UNIC:
- inited = hnae3_get_bit(ae_dev->flag,
- HNAE3_UNIC_CLIENT_INITED_B);
- break;
case HNAE3_CLIENT_ROCE:
inited = hnae3_get_bit(ae_dev->flag,
HNAE3_ROCE_CLIENT_INITED_B);
@@ -82,7 +72,7 @@ static int hnae3_init_client_instance(struct hnae3_client *client,
int ret;
/* check if this client matches the type of ae_dev */
- if (!(hnae3_client_match(client->type, ae_dev->dev_type) &&
+ if (!(hnae3_client_match(client->type) &&
hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))) {
return 0;
}
@@ -99,7 +89,7 @@ static void hnae3_uninit_client_instance(struct hnae3_client *client,
struct hnae3_ae_dev *ae_dev)
{
/* check if this client matches the type of ae_dev */
- if (!(hnae3_client_match(client->type, ae_dev->dev_type) &&
+ if (!(hnae3_client_match(client->type) &&
hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B)))
return;
@@ -251,6 +241,7 @@ void hnae3_unregister_ae_algo(struct hnae3_ae_algo *ae_algo)
ae_algo->ops->uninit_ae_dev(ae_dev);
hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 0);
+ ae_dev->ops = NULL;
}
list_del(&ae_algo->node);
@@ -351,6 +342,7 @@ void hnae3_unregister_ae_dev(struct hnae3_ae_dev *ae_dev)
ae_algo->ops->uninit_ae_dev(ae_dev);
hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 0);
+ ae_dev->ops = NULL;
}
list_del(&ae_dev->node);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
index ad21b0ef1946..48c7b70fc2c4 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
@@ -102,15 +102,9 @@ enum hnae3_loop {
enum hnae3_client_type {
HNAE3_CLIENT_KNIC,
- HNAE3_CLIENT_UNIC,
HNAE3_CLIENT_ROCE,
};
-enum hnae3_dev_type {
- HNAE3_DEV_KNIC,
- HNAE3_DEV_UNIC,
-};
-
/* mac media type */
enum hnae3_media_type {
HNAE3_MEDIA_TYPE_UNKNOWN,
@@ -154,7 +148,6 @@ enum hnae3_reset_type {
HNAE3_VF_FULL_RESET,
HNAE3_FLR_RESET,
HNAE3_FUNC_RESET,
- HNAE3_CORE_RESET,
HNAE3_GLOBAL_RESET,
HNAE3_IMP_RESET,
HNAE3_UNKNOWN_RESET,
@@ -220,8 +213,7 @@ struct hnae3_ae_dev {
const struct hnae3_ae_ops *ops;
struct list_head node;
u32 flag;
- u8 override_pci_need_reset; /* fix to stop multiple reset happening */
- enum hnae3_dev_type dev_type;
+ unsigned long hw_err_reset_req;
enum hnae3_reset_type reset_type;
void *priv;
};
@@ -271,6 +263,8 @@ struct hnae3_ae_dev {
* get auto autonegotiation of pause frame use
* restart_autoneg()
* restart autonegotiation
+ * halt_autoneg()
+ * halt/resume autonegotiation when autonegotiation on
* get_coalesce_usecs()
* get usecs to delay a TX interrupt after a packet is sent
* get_rx_max_coalesced_frames()
@@ -339,10 +333,14 @@ struct hnae3_ae_dev {
* Set vlan filter config of Ports
* set_vf_vlan_filter()
* Set vlan filter config of vf
+ * restore_vlan_table()
+ * Restore vlan filter entries after reset
* enable_hw_strip_rxvtag()
* Enable/disable hardware strip vlan tag of packets received
* set_gro_en
* Enable/disable HW GRO
+ * add_arfs_entry
+ * Check the 5-tuples of flow, and create flow director rule
*/
struct hnae3_ae_ops {
int (*init_ae_dev)(struct hnae3_ae_dev *ae_dev);
@@ -386,6 +384,7 @@ struct hnae3_ae_ops {
int (*set_autoneg)(struct hnae3_handle *handle, bool enable);
int (*get_autoneg)(struct hnae3_handle *handle);
int (*restart_autoneg)(struct hnae3_handle *handle);
+ int (*halt_autoneg)(struct hnae3_handle *handle, bool halt);
void (*get_coalesce_usecs)(struct hnae3_handle *handle,
u32 *tx_usecs, u32 *rx_usecs);
@@ -463,6 +462,8 @@ struct hnae3_ae_ops {
u16 vlan, u8 qos, __be16 proto);
int (*enable_hw_strip_rxvtag)(struct hnae3_handle *handle, bool enable);
void (*reset_event)(struct pci_dev *pdev, struct hnae3_handle *handle);
+ enum hnae3_reset_type (*get_reset_level)(struct hnae3_ae_dev *ae_dev,
+ unsigned long *addr);
void (*set_default_reset_request)(struct hnae3_ae_dev *ae_dev,
enum hnae3_reset_type rst_type);
void (*get_channels)(struct hnae3_handle *handle,
@@ -492,7 +493,9 @@ struct hnae3_ae_ops {
struct ethtool_rxnfc *cmd, u32 *rule_locs);
int (*restore_fd_rules)(struct hnae3_handle *handle);
void (*enable_fd)(struct hnae3_handle *handle, bool enable);
- int (*dbg_run_cmd)(struct hnae3_handle *handle, char *cmd_buf);
+ int (*add_arfs_entry)(struct hnae3_handle *handle, u16 queue_id,
+ u16 flow_id, struct flow_keys *fkeys);
+ int (*dbg_run_cmd)(struct hnae3_handle *handle, const char *cmd_buf);
pci_ers_result_t (*handle_hw_ras_error)(struct hnae3_ae_dev *ae_dev);
bool (*get_hw_reset_stat)(struct hnae3_handle *handle);
bool (*ae_dev_resetting)(struct hnae3_handle *handle);
@@ -502,6 +505,7 @@ struct hnae3_ae_ops {
void (*set_timer_task)(struct hnae3_handle *handle, bool enable);
int (*mac_connect_phy)(struct hnae3_handle *handle);
void (*mac_disconnect_phy)(struct hnae3_handle *handle);
+ void (*restore_vlan_table)(struct hnae3_handle *handle);
};
struct hnae3_dcb_ops {
@@ -643,5 +647,6 @@ void hnae3_unregister_client(struct hnae3_client *client);
int hnae3_register_client(struct hnae3_client *client);
void hnae3_set_client_init_flag(struct hnae3_client *client,
- struct hnae3_ae_dev *ae_dev, int inited);
+ struct hnae3_ae_dev *ae_dev,
+ unsigned int inited);
#endif
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_dcbnl.c b/drivers/net/ethernet/hisilicon/hns3/hns3_dcbnl.c
index b6fabbbdfd5b..d2ec4c573bf8 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_dcbnl.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_dcbnl.c
@@ -4,8 +4,7 @@
#include "hnae3.h"
#include "hns3_enet.h"
-static
-int hns3_dcbnl_ieee_getets(struct net_device *ndev, struct ieee_ets *ets)
+static int hns3_dcbnl_ieee_getets(struct net_device *ndev, struct ieee_ets *ets)
{
struct hnae3_handle *h = hns3_get_handle(ndev);
@@ -18,8 +17,7 @@ int hns3_dcbnl_ieee_getets(struct net_device *ndev, struct ieee_ets *ets)
return -EOPNOTSUPP;
}
-static
-int hns3_dcbnl_ieee_setets(struct net_device *ndev, struct ieee_ets *ets)
+static int hns3_dcbnl_ieee_setets(struct net_device *ndev, struct ieee_ets *ets)
{
struct hnae3_handle *h = hns3_get_handle(ndev);
@@ -32,8 +30,7 @@ int hns3_dcbnl_ieee_setets(struct net_device *ndev, struct ieee_ets *ets)
return -EOPNOTSUPP;
}
-static
-int hns3_dcbnl_ieee_getpfc(struct net_device *ndev, struct ieee_pfc *pfc)
+static int hns3_dcbnl_ieee_getpfc(struct net_device *ndev, struct ieee_pfc *pfc)
{
struct hnae3_handle *h = hns3_get_handle(ndev);
@@ -46,8 +43,7 @@ int hns3_dcbnl_ieee_getpfc(struct net_device *ndev, struct ieee_pfc *pfc)
return -EOPNOTSUPP;
}
-static
-int hns3_dcbnl_ieee_setpfc(struct net_device *ndev, struct ieee_pfc *pfc)
+static int hns3_dcbnl_ieee_setpfc(struct net_device *ndev, struct ieee_pfc *pfc)
{
struct hnae3_handle *h = hns3_get_handle(ndev);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c
index fc4917ac44be..a4b937286f55 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c
@@ -11,7 +11,8 @@
static struct dentry *hns3_dbgfs_root;
-static int hns3_dbg_queue_info(struct hnae3_handle *h, char *cmd_buf)
+static int hns3_dbg_queue_info(struct hnae3_handle *h,
+ const char *cmd_buf)
{
struct hns3_nic_priv *priv = h->priv;
struct hns3_nic_ring_data *ring_data;
@@ -155,7 +156,7 @@ static int hns3_dbg_queue_map(struct hnae3_handle *h)
return 0;
}
-static int hns3_dbg_bd_info(struct hnae3_handle *h, char *cmd_buf)
+static int hns3_dbg_bd_info(struct hnae3_handle *h, const char *cmd_buf)
{
struct hns3_nic_priv *priv = h->priv;
struct hns3_nic_ring_data *ring_data;
@@ -252,6 +253,7 @@ static void hns3_dbg_help(struct hnae3_handle *h)
dev_info(&h->pdev->dev, "dump qos buf cfg\n");
dev_info(&h->pdev->dev, "dump mng tbl\n");
dev_info(&h->pdev->dev, "dump reset info\n");
+ dev_info(&h->pdev->dev, "dump m7 info\n");
dev_info(&h->pdev->dev, "dump ncl_config <offset> <length>(in hex)\n");
dev_info(&h->pdev->dev, "dump mac tnl status\n");
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
index 196a3d780dcf..310afa708831 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
@@ -4,6 +4,9 @@
#include <linux/dma-mapping.h>
#include <linux/etherdevice.h>
#include <linux/interrupt.h>
+#ifdef CONFIG_RFS_ACCEL
+#include <linux/cpu_rmap.h>
+#endif
#include <linux/if_vlan.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
@@ -14,6 +17,7 @@
#include <linux/sctp.h>
#include <linux/vermagic.h>
#include <net/gre.h>
+#include <net/ip6_checksum.h>
#include <net/pkt_cls.h>
#include <net/tcp.h>
#include <net/vxlan.h>
@@ -24,8 +28,7 @@
#define hns3_set_field(origin, shift, val) ((origin) |= ((val) << (shift)))
#define hns3_tx_bd_count(S) DIV_ROUND_UP(S, HNS3_MAX_BD_SIZE)
-static void hns3_clear_all_ring(struct hnae3_handle *h);
-static void hns3_force_clear_all_rx_ring(struct hnae3_handle *h);
+static void hns3_clear_all_ring(struct hnae3_handle *h, bool force);
static void hns3_remove_hw_addr(struct net_device *netdev);
static const char hns3_driver_name[] = "hns3";
@@ -79,23 +82,6 @@ static irqreturn_t hns3_irq_handle(int irq, void *vector)
return IRQ_HANDLED;
}
-/* This callback function is used to set affinity changes to the irq affinity
- * masks when the irq_set_affinity_notifier function is used.
- */
-static void hns3_nic_irq_affinity_notify(struct irq_affinity_notify *notify,
- const cpumask_t *mask)
-{
- struct hns3_enet_tqp_vector *tqp_vectors =
- container_of(notify, struct hns3_enet_tqp_vector,
- affinity_notify);
-
- tqp_vectors->affinity_mask = *mask;
-}
-
-static void hns3_nic_irq_affinity_release(struct kref *ref)
-{
-}
-
static void hns3_nic_uninit_irq(struct hns3_nic_priv *priv)
{
struct hns3_enet_tqp_vector *tqp_vectors;
@@ -107,8 +93,7 @@ static void hns3_nic_uninit_irq(struct hns3_nic_priv *priv)
if (tqp_vectors->irq_init_flag != HNS3_VECTOR_INITED)
continue;
- /* clear the affinity notifier and affinity mask */
- irq_set_affinity_notifier(tqp_vectors->vector_irq, NULL);
+ /* clear the affinity mask */
irq_set_affinity_hint(tqp_vectors->vector_irq, NULL);
/* release the irq resource */
@@ -153,20 +138,14 @@ static int hns3_nic_init_irq(struct hns3_nic_priv *priv)
tqp_vectors->name[HNAE3_INT_NAME_LEN - 1] = '\0';
ret = request_irq(tqp_vectors->vector_irq, hns3_irq_handle, 0,
- tqp_vectors->name,
- tqp_vectors);
+ tqp_vectors->name, tqp_vectors);
if (ret) {
netdev_err(priv->netdev, "request irq(%d) fail\n",
tqp_vectors->vector_irq);
+ hns3_nic_uninit_irq(priv);
return ret;
}
- tqp_vectors->affinity_notify.notify =
- hns3_nic_irq_affinity_notify;
- tqp_vectors->affinity_notify.release =
- hns3_nic_irq_affinity_release;
- irq_set_affinity_notifier(tqp_vectors->vector_irq,
- &tqp_vectors->affinity_notify);
irq_set_affinity_hint(tqp_vectors->vector_irq,
&tqp_vectors->affinity_mask);
@@ -297,8 +276,7 @@ static int hns3_nic_set_real_num_queue(struct net_device *netdev)
ret = netif_set_real_num_tx_queues(netdev, queue_size);
if (ret) {
netdev_err(netdev,
- "netif_set_real_num_tx_queues fail, ret=%d!\n",
- ret);
+ "netif_set_real_num_tx_queues fail, ret=%d!\n", ret);
return ret;
}
@@ -340,6 +318,40 @@ static void hns3_tqp_disable(struct hnae3_queue *tqp)
hns3_write_dev(tqp, HNS3_RING_EN_REG, rcb_reg);
}
+static void hns3_free_rx_cpu_rmap(struct net_device *netdev)
+{
+#ifdef CONFIG_RFS_ACCEL
+ free_irq_cpu_rmap(netdev->rx_cpu_rmap);
+ netdev->rx_cpu_rmap = NULL;
+#endif
+}
+
+static int hns3_set_rx_cpu_rmap(struct net_device *netdev)
+{
+#ifdef CONFIG_RFS_ACCEL
+ struct hns3_nic_priv *priv = netdev_priv(netdev);
+ struct hns3_enet_tqp_vector *tqp_vector;
+ int i, ret;
+
+ if (!netdev->rx_cpu_rmap) {
+ netdev->rx_cpu_rmap = alloc_irq_cpu_rmap(priv->vector_num);
+ if (!netdev->rx_cpu_rmap)
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < priv->vector_num; i++) {
+ tqp_vector = &priv->tqp_vector[i];
+ ret = irq_cpu_rmap_add(netdev->rx_cpu_rmap,
+ tqp_vector->vector_irq);
+ if (ret) {
+ hns3_free_rx_cpu_rmap(netdev);
+ return ret;
+ }
+ }
+#endif
+ return 0;
+}
+
static int hns3_nic_net_up(struct net_device *netdev)
{
struct hns3_nic_priv *priv = netdev_priv(netdev);
@@ -351,11 +363,16 @@ static int hns3_nic_net_up(struct net_device *netdev)
if (ret)
return ret;
+ /* the device can work without cpu rmap, only aRFS needs it */
+ ret = hns3_set_rx_cpu_rmap(netdev);
+ if (ret)
+ netdev_warn(netdev, "set rx cpu rmap fail, ret=%d!\n", ret);
+
/* get irq resource for all vectors */
ret = hns3_nic_init_irq(priv);
if (ret) {
- netdev_err(netdev, "hns init irq failed! ret=%d\n", ret);
- return ret;
+ netdev_err(netdev, "init irq failed! ret=%d\n", ret);
+ goto free_rmap;
}
clear_bit(HNS3_NIC_STATE_DOWN, &priv->state);
@@ -384,7 +401,8 @@ out_start_err:
hns3_vector_disable(&priv->tqp_vector[j]);
hns3_nic_uninit_irq(priv);
-
+free_rmap:
+ hns3_free_rx_cpu_rmap(netdev);
return ret;
}
@@ -429,16 +447,13 @@ static int hns3_nic_net_open(struct net_device *netdev)
ret = hns3_nic_net_up(netdev);
if (ret) {
- netdev_err(netdev,
- "hns net up fail, ret=%d!\n", ret);
+ netdev_err(netdev, "net up fail, ret=%d!\n", ret);
return ret;
}
kinfo = &h->kinfo;
- for (i = 0; i < HNAE3_MAX_USER_PRIO; i++) {
- netdev_set_prio_tc_map(netdev, i,
- kinfo->prio_tc[i]);
- }
+ for (i = 0; i < HNAE3_MAX_USER_PRIO; i++)
+ netdev_set_prio_tc_map(netdev, i, kinfo->prio_tc[i]);
if (h->ae_algo->ops->set_timer_task)
h->ae_algo->ops->set_timer_task(priv->ae_handle, true);
@@ -447,6 +462,20 @@ static int hns3_nic_net_open(struct net_device *netdev)
return 0;
}
+static void hns3_reset_tx_queue(struct hnae3_handle *h)
+{
+ struct net_device *ndev = h->kinfo.netdev;
+ struct hns3_nic_priv *priv = netdev_priv(ndev);
+ struct netdev_queue *dev_queue;
+ u32 i;
+
+ for (i = 0; i < h->kinfo.num_tqps; i++) {
+ dev_queue = netdev_get_tx_queue(ndev,
+ priv->ring_data[i].queue_index);
+ netdev_tx_reset_queue(dev_queue);
+ }
+}
+
static void hns3_nic_net_down(struct net_device *netdev)
{
struct hns3_nic_priv *priv = netdev_priv(netdev);
@@ -467,10 +496,19 @@ static void hns3_nic_net_down(struct net_device *netdev)
if (ops->stop)
ops->stop(priv->ae_handle);
+ hns3_free_rx_cpu_rmap(netdev);
+
/* free irq resources */
hns3_nic_uninit_irq(priv);
- hns3_clear_all_ring(priv->ae_handle);
+ /* delay ring buffer clearing to hns3_reset_notify_uninit_enet
+ * during reset process, because driver may not be able
+ * to disable the ring through firmware when downing the netdev.
+ */
+ if (!hns3_nic_resetting(netdev))
+ hns3_clear_all_ring(priv->ae_handle, false);
+
+ hns3_reset_tx_queue(priv->ae_handle);
}
static int hns3_nic_net_stop(struct net_device *netdev)
@@ -641,7 +679,7 @@ static int hns3_set_tso(struct sk_buff *skb, u32 *paylen,
if (l3.v4->version == 4)
l3.v4->check = 0;
- /* tunnel packet.*/
+ /* tunnel packet */
if (skb_shinfo(skb)->gso_type & (SKB_GSO_GRE |
SKB_GSO_GRE_CSUM |
SKB_GSO_UDP_TUNNEL |
@@ -666,11 +704,11 @@ static int hns3_set_tso(struct sk_buff *skb, u32 *paylen,
l3.v4->check = 0;
}
- /* normal or tunnel packet*/
+ /* normal or tunnel packet */
l4_offset = l4.hdr - skb->data;
hdr_len = (l4.tcp->doff << 2) + l4_offset;
- /* remove payload length from inner pseudo checksum when tso*/
+ /* remove payload length from inner pseudo checksum when tso */
l4_paylen = skb->len - l4_offset;
csum_replace_by_diff(&l4.tcp->check,
(__force __wsum)htonl(l4_paylen));
@@ -778,7 +816,7 @@ static void hns3_set_outer_l2l3l4(struct sk_buff *skb, u8 ol4_proto,
hns3_set_field(*ol_type_vlan_len_msec, HNS3_TXD_L3LEN_S, l3_len >> 2);
il2_hdr = skb_inner_mac_header(skb);
- /* compute OL4 header size, defined in 4 Bytes. */
+ /* compute OL4 header size, defined in 4 Bytes */
l4_len = il2_hdr - l4.hdr;
hns3_set_field(*ol_type_vlan_len_msec, HNS3_TXD_L4LEN_S, l4_len >> 2);
@@ -913,8 +951,9 @@ static int hns3_set_l2l3l4(struct sk_buff *skb, u8 ol4_proto,
static void hns3_set_txbd_baseinfo(u16 *bdtp_fe_sc_vld_ra_ri, int frag_end)
{
/* Config bd buffer end */
- hns3_set_field(*bdtp_fe_sc_vld_ra_ri, HNS3_TXD_FE_B, !!frag_end);
- hns3_set_field(*bdtp_fe_sc_vld_ra_ri, HNS3_TXD_VLD_B, 1);
+ if (!!frag_end)
+ hns3_set_field(*bdtp_fe_sc_vld_ra_ri, HNS3_TXD_FE_B, 1U);
+ hns3_set_field(*bdtp_fe_sc_vld_ra_ri, HNS3_TXD_VLD_B, 1U);
}
static int hns3_fill_desc_vtags(struct sk_buff *skb,
@@ -988,7 +1027,8 @@ static int hns3_fill_desc_vtags(struct sk_buff *skb,
}
static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv,
- int size, int frag_end, enum hns_desc_type type)
+ unsigned int size, int frag_end,
+ enum hns_desc_type type)
{
struct hns3_desc_cb *desc_cb = &ring->desc_cb[ring->next_to_use];
struct hns3_desc *desc = &ring->desc[ring->next_to_use];
@@ -1038,8 +1078,7 @@ static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv,
/* Set txbd */
desc->tx.ol_type_vlan_len_msec =
cpu_to_le32(ol_type_vlan_len_msec);
- desc->tx.type_cs_vlan_tso_len =
- cpu_to_le32(type_cs_vlan_tso);
+ desc->tx.type_cs_vlan_tso_len = cpu_to_le32(type_cs_vlan_tso);
desc->tx.paylen = cpu_to_le32(paylen);
desc->tx.mss = cpu_to_le16(mss);
desc->tx.vlan_tag = cpu_to_le16(inner_vtag);
@@ -1086,19 +1125,19 @@ static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv,
desc_cb->priv = priv;
desc_cb->dma = dma + HNS3_MAX_BD_SIZE * k;
desc_cb->type = (type == DESC_TYPE_SKB && !k) ?
- DESC_TYPE_SKB : DESC_TYPE_PAGE;
+ DESC_TYPE_SKB : DESC_TYPE_PAGE;
/* now, fill the descriptor */
desc->addr = cpu_to_le64(dma + HNS3_MAX_BD_SIZE * k);
desc->tx.send_size = cpu_to_le16((k == frag_buf_num - 1) ?
- (u16)sizeoflast : (u16)HNS3_MAX_BD_SIZE);
+ (u16)sizeoflast : (u16)HNS3_MAX_BD_SIZE);
hns3_set_txbd_baseinfo(&bdtp_fe_sc_vld_ra_ri,
frag_end && (k == frag_buf_num - 1) ?
1 : 0);
desc->tx.bdtp_fe_sc_vld_ra_ri =
cpu_to_le16(bdtp_fe_sc_vld_ra_ri);
- /* move ring pointer to next.*/
+ /* move ring pointer to next */
ring_ptr_move_fw(ring, next_to_use);
desc_cb = &ring->desc_cb[ring->next_to_use];
@@ -1452,12 +1491,10 @@ static void hns3_nic_get_stats64(struct net_device *netdev,
start = u64_stats_fetch_begin_irq(&ring->syncp);
rx_bytes += ring->stats.rx_bytes;
rx_pkts += ring->stats.rx_pkts;
- rx_drop += ring->stats.non_vld_descs;
rx_drop += ring->stats.l2_err;
- rx_errors += ring->stats.non_vld_descs;
rx_errors += ring->stats.l2_err;
+ rx_errors += ring->stats.l3l4_csum_err;
rx_crc_errors += ring->stats.l2_err;
- rx_crc_errors += ring->stats.l3l4_csum_err;
rx_multicast += ring->stats.rx_multicast;
rx_length_errors += ring->stats.err_pkt_len;
} while (u64_stats_fetch_retry_irq(&ring->syncp, start));
@@ -1493,12 +1530,12 @@ static void hns3_nic_get_stats64(struct net_device *netdev,
static int hns3_setup_tc(struct net_device *netdev, void *type_data)
{
struct tc_mqprio_qopt_offload *mqprio_qopt = type_data;
- struct hnae3_handle *h = hns3_get_handle(netdev);
- struct hnae3_knic_private_info *kinfo = &h->kinfo;
u8 *prio_tc = mqprio_qopt->qopt.prio_tc_map;
+ struct hnae3_knic_private_info *kinfo;
u8 tc = mqprio_qopt->qopt.num_tc;
u16 mode = mqprio_qopt->mode;
u8 hw = mqprio_qopt->qopt.hw;
+ struct hnae3_handle *h;
if (!((hw == TC_MQPRIO_HW_OFFLOAD_TCS &&
mode == TC_MQPRIO_MODE_CHANNEL) || (!hw && tc == 0)))
@@ -1510,6 +1547,9 @@ static int hns3_setup_tc(struct net_device *netdev, void *type_data)
if (!netdev)
return -EINVAL;
+ h = hns3_get_handle(netdev);
+ kinfo = &h->kinfo;
+
return (kinfo->dcb_ops && kinfo->dcb_ops->setup_tc) ?
kinfo->dcb_ops->setup_tc(h, tc, prio_tc) : -EOPNOTSUPP;
}
@@ -1527,15 +1567,11 @@ static int hns3_vlan_rx_add_vid(struct net_device *netdev,
__be16 proto, u16 vid)
{
struct hnae3_handle *h = hns3_get_handle(netdev);
- struct hns3_nic_priv *priv = netdev_priv(netdev);
int ret = -EIO;
if (h->ae_algo->ops->set_vlan_filter)
ret = h->ae_algo->ops->set_vlan_filter(h, proto, vid, false);
- if (!ret)
- set_bit(vid, priv->active_vlans);
-
return ret;
}
@@ -1543,33 +1579,11 @@ static int hns3_vlan_rx_kill_vid(struct net_device *netdev,
__be16 proto, u16 vid)
{
struct hnae3_handle *h = hns3_get_handle(netdev);
- struct hns3_nic_priv *priv = netdev_priv(netdev);
int ret = -EIO;
if (h->ae_algo->ops->set_vlan_filter)
ret = h->ae_algo->ops->set_vlan_filter(h, proto, vid, true);
- if (!ret)
- clear_bit(vid, priv->active_vlans);
-
- return ret;
-}
-
-static int hns3_restore_vlan(struct net_device *netdev)
-{
- struct hns3_nic_priv *priv = netdev_priv(netdev);
- int ret = 0;
- u16 vid;
-
- for_each_set_bit(vid, priv->active_vlans, VLAN_N_VID) {
- ret = hns3_vlan_rx_add_vid(netdev, htons(ETH_P_8021Q), vid);
- if (ret) {
- netdev_err(netdev, "Restore vlan: %d filter, ret:%d\n",
- vid, ret);
- return ret;
- }
- }
-
return ret;
}
@@ -1581,7 +1595,7 @@ static int hns3_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan,
if (h->ae_algo->ops->set_vf_vlan_filter)
ret = h->ae_algo->ops->set_vf_vlan_filter(h, vf, vlan,
- qos, vlan_proto);
+ qos, vlan_proto);
return ret;
}
@@ -1722,6 +1736,32 @@ static void hns3_nic_net_timeout(struct net_device *ndev)
h->ae_algo->ops->reset_event(h->pdev, h);
}
+#ifdef CONFIG_RFS_ACCEL
+static int hns3_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
+ u16 rxq_index, u32 flow_id)
+{
+ struct hnae3_handle *h = hns3_get_handle(dev);
+ struct flow_keys fkeys;
+
+ if (!h->ae_algo->ops->add_arfs_entry)
+ return -EOPNOTSUPP;
+
+ if (skb->encapsulation)
+ return -EPROTONOSUPPORT;
+
+ if (!skb_flow_dissect_flow_keys(skb, &fkeys, 0))
+ return -EPROTONOSUPPORT;
+
+ if ((fkeys.basic.n_proto != htons(ETH_P_IP) &&
+ fkeys.basic.n_proto != htons(ETH_P_IPV6)) ||
+ (fkeys.basic.ip_proto != IPPROTO_TCP &&
+ fkeys.basic.ip_proto != IPPROTO_UDP))
+ return -EPROTONOSUPPORT;
+
+ return h->ae_algo->ops->add_arfs_entry(h, rxq_index, flow_id, &fkeys);
+}
+#endif
+
static const struct net_device_ops hns3_nic_netdev_ops = {
.ndo_open = hns3_nic_net_open,
.ndo_stop = hns3_nic_net_stop,
@@ -1737,6 +1777,10 @@ static const struct net_device_ops hns3_nic_netdev_ops = {
.ndo_vlan_rx_add_vid = hns3_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = hns3_vlan_rx_kill_vid,
.ndo_set_vf_vlan = hns3_ndo_set_vf_vlan,
+#ifdef CONFIG_RFS_ACCEL
+ .ndo_rx_flow_steer = hns3_rx_flow_steer,
+#endif
+
};
bool hns3_is_phys_func(struct pci_dev *pdev)
@@ -1802,8 +1846,7 @@ static int hns3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
struct hnae3_ae_dev *ae_dev;
int ret;
- ae_dev = devm_kzalloc(&pdev->dev, sizeof(*ae_dev),
- GFP_KERNEL);
+ ae_dev = devm_kzalloc(&pdev->dev, sizeof(*ae_dev), GFP_KERNEL);
if (!ae_dev) {
ret = -ENOMEM;
return ret;
@@ -1811,7 +1854,6 @@ static int hns3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ae_dev->pdev = pdev;
ae_dev->flag = ent->driver_data;
- ae_dev->dev_type = HNAE3_DEV_KNIC;
ae_dev->reset_type = HNAE3_NONE_RESET;
hns3_get_dev_capability(pdev, ae_dev);
pci_set_drvdata(pdev, ae_dev);
@@ -1895,9 +1937,9 @@ static pci_ers_result_t hns3_error_detected(struct pci_dev *pdev,
if (state == pci_channel_io_perm_failure)
return PCI_ERS_RESULT_DISCONNECT;
- if (!ae_dev) {
+ if (!ae_dev || !ae_dev->ops) {
dev_err(&pdev->dev,
- "Can't recover - error happened during device init\n");
+ "Can't recover - error happened before device initialized\n");
return PCI_ERS_RESULT_NONE;
}
@@ -1912,14 +1954,23 @@ static pci_ers_result_t hns3_error_detected(struct pci_dev *pdev,
static pci_ers_result_t hns3_slot_reset(struct pci_dev *pdev)
{
struct hnae3_ae_dev *ae_dev = pci_get_drvdata(pdev);
+ const struct hnae3_ae_ops *ops;
+ enum hnae3_reset_type reset_type;
struct device *dev = &pdev->dev;
- dev_info(dev, "requesting reset due to PCI error\n");
+ if (!ae_dev || !ae_dev->ops)
+ return PCI_ERS_RESULT_NONE;
+ ops = ae_dev->ops;
/* request the reset */
- if (ae_dev->ops->reset_event) {
- if (!ae_dev->override_pci_need_reset)
- ae_dev->ops->reset_event(pdev, NULL);
+ if (ops->reset_event) {
+ if (ae_dev->hw_err_reset_req) {
+ reset_type = ops->get_reset_level(ae_dev,
+ &ae_dev->hw_err_reset_req);
+ ops->set_default_reset_request(ae_dev, reset_type);
+ dev_info(dev, "requesting reset due to PCI error\n");
+ ops->reset_event(pdev, NULL);
+ }
return PCI_ERS_RESULT_RECOVERED;
}
@@ -2168,7 +2219,7 @@ out_buffer_fail:
return ret;
}
-/* detach a in-used buffer and replace with a reserved one */
+/* detach a in-used buffer and replace with a reserved one */
static void hns3_replace_buffer(struct hns3_enet_ring *ring, int i,
struct hns3_desc_cb *res_cb)
{
@@ -2181,8 +2232,8 @@ static void hns3_replace_buffer(struct hns3_enet_ring *ring, int i,
static void hns3_reuse_buffer(struct hns3_enet_ring *ring, int i)
{
ring->desc_cb[i].reuse_flag = 0;
- ring->desc[i].addr = cpu_to_le64(ring->desc_cb[i].dma
- + ring->desc_cb[i].page_offset);
+ ring->desc[i].addr = cpu_to_le64(ring->desc_cb[i].dma +
+ ring->desc_cb[i].page_offset);
ring->desc[i].rx.bd_base_info = 0;
}
@@ -2284,8 +2335,8 @@ static int hns3_desc_unused(struct hns3_enet_ring *ring)
return ((ntc >= ntu) ? 0 : ring->desc_num) + ntc - ntu;
}
-static void
-hns3_nic_alloc_rx_buffers(struct hns3_enet_ring *ring, int cleand_count)
+static void hns3_nic_alloc_rx_buffers(struct hns3_enet_ring *ring,
+ int cleand_count)
{
struct hns3_desc_cb *desc_cb;
struct hns3_desc_cb res_cbs;
@@ -2338,7 +2389,7 @@ static void hns3_nic_reuse_page(struct sk_buff *skb, int i,
/* Avoid re-using remote pages, or the stack is still using the page
* when page_offset rollback to zero, flag default unreuse
*/
- if (unlikely(page_to_nid(desc_cb->priv) != numa_node_id()) ||
+ if (unlikely(page_to_nid(desc_cb->priv) != numa_mem_id()) ||
(!desc_cb->page_offset && page_count(desc_cb->priv) > 1))
return;
@@ -2347,7 +2398,7 @@ static void hns3_nic_reuse_page(struct sk_buff *skb, int i,
if (desc_cb->page_offset + truesize <= hnae3_page_size(ring)) {
desc_cb->reuse_flag = 1;
- /* Bump ref count on page before it is given*/
+ /* Bump ref count on page before it is given */
get_page(desc_cb->priv);
} else if (page_count(desc_cb->priv) == 1) {
desc_cb->reuse_flag = 1;
@@ -2356,13 +2407,13 @@ static void hns3_nic_reuse_page(struct sk_buff *skb, int i,
}
}
-static int hns3_gro_complete(struct sk_buff *skb)
+static int hns3_gro_complete(struct sk_buff *skb, u32 l234info)
{
__be16 type = skb->protocol;
struct tcphdr *th;
int depth = 0;
- while (type == htons(ETH_P_8021Q)) {
+ while (eth_type_vlan(type)) {
struct vlan_hdr *vh;
if ((depth + VLAN_HLEN) > skb_headlen(skb))
@@ -2373,10 +2424,24 @@ static int hns3_gro_complete(struct sk_buff *skb)
depth += VLAN_HLEN;
}
+ skb_set_network_header(skb, depth);
+
if (type == htons(ETH_P_IP)) {
+ const struct iphdr *iph = ip_hdr(skb);
+
depth += sizeof(struct iphdr);
+ skb_set_transport_header(skb, depth);
+ th = tcp_hdr(skb);
+ th->check = ~tcp_v4_check(skb->len - depth, iph->saddr,
+ iph->daddr, 0);
} else if (type == htons(ETH_P_IPV6)) {
+ const struct ipv6hdr *iph = ipv6_hdr(skb);
+
depth += sizeof(struct ipv6hdr);
+ skb_set_transport_header(skb, depth);
+ th = tcp_hdr(skb);
+ th->check = ~tcp_v6_check(skb->len - depth, &iph->saddr,
+ &iph->daddr, 0);
} else {
netdev_err(skb->dev,
"Error: FW GRO supports only IPv4/IPv6, not 0x%04x, depth: %d\n",
@@ -2384,13 +2449,16 @@ static int hns3_gro_complete(struct sk_buff *skb)
return -EFAULT;
}
- th = (struct tcphdr *)(skb->data + depth);
skb_shinfo(skb)->gso_segs = NAPI_GRO_CB(skb)->count;
if (th->cwr)
skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN;
- skb->ip_summed = CHECKSUM_UNNECESSARY;
+ if (l234info & BIT(HNS3_RXD_GRO_FIXID_B))
+ skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_FIXEDID;
+ skb->csum_start = (unsigned char *)th - skb->head;
+ skb->csum_offset = offsetof(struct tcphdr, check);
+ skb->ip_summed = CHECKSUM_PARTIAL;
return 0;
}
@@ -2508,7 +2576,7 @@ static bool hns3_parse_vlan_tag(struct hns3_enet_ring *ring,
}
}
-static int hns3_alloc_skb(struct hns3_enet_ring *ring, int length,
+static int hns3_alloc_skb(struct hns3_enet_ring *ring, unsigned int length,
unsigned char *va)
{
#define HNS3_NEED_ADD_FRAG 1
@@ -2537,7 +2605,7 @@ static int hns3_alloc_skb(struct hns3_enet_ring *ring, int length,
memcpy(__skb_put(skb, length), va, ALIGN(length, sizeof(long)));
/* We can reuse buffer as-is, just make sure it is local */
- if (likely(page_to_nid(desc_cb->priv) == numa_node_id()))
+ if (likely(page_to_nid(desc_cb->priv) == numa_mem_id()))
desc_cb->reuse_flag = 1;
else /* This page cannot be reused so discard it */
put_page(desc_cb->priv);
@@ -2574,7 +2642,7 @@ static int hns3_add_frag(struct hns3_enet_ring *ring, struct hns3_desc *desc,
*/
if (pending) {
pre_bd = (ring->next_to_clean - 1 + ring->desc_num) %
- ring->desc_num;
+ ring->desc_num;
pre_desc = &ring->desc[pre_bd];
bd_base_info = le32_to_cpu(pre_desc->rx.bd_base_info);
} else {
@@ -2628,21 +2696,22 @@ static int hns3_set_gro_and_checksum(struct hns3_enet_ring *ring,
struct sk_buff *skb, u32 l234info,
u32 bd_base_info, u32 ol_info)
{
- u16 gro_count;
u32 l3_type;
- gro_count = hnae3_get_field(l234info, HNS3_RXD_GRO_COUNT_M,
- HNS3_RXD_GRO_COUNT_S);
+ skb_shinfo(skb)->gso_size = hnae3_get_field(bd_base_info,
+ HNS3_RXD_GRO_SIZE_M,
+ HNS3_RXD_GRO_SIZE_S);
/* if there is no HW GRO, do not set gro params */
- if (!gro_count) {
+ if (!skb_shinfo(skb)->gso_size) {
hns3_rx_checksum(ring, skb, l234info, bd_base_info, ol_info);
return 0;
}
- NAPI_GRO_CB(skb)->count = gro_count;
+ NAPI_GRO_CB(skb)->count = hnae3_get_field(l234info,
+ HNS3_RXD_GRO_COUNT_M,
+ HNS3_RXD_GRO_COUNT_S);
- l3_type = hnae3_get_field(l234info, HNS3_RXD_L3ID_M,
- HNS3_RXD_L3ID_S);
+ l3_type = hnae3_get_field(l234info, HNS3_RXD_L3ID_M, HNS3_RXD_L3ID_S);
if (l3_type == HNS3_L3_TYPE_IPV4)
skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
else if (l3_type == HNS3_L3_TYPE_IPV6)
@@ -2650,11 +2719,7 @@ static int hns3_set_gro_and_checksum(struct hns3_enet_ring *ring,
else
return -EFAULT;
- skb_shinfo(skb)->gso_size = hnae3_get_field(bd_base_info,
- HNS3_RXD_GRO_SIZE_M,
- HNS3_RXD_GRO_SIZE_S);
-
- return hns3_gro_complete(skb);
+ return hns3_gro_complete(skb, l234info);
}
static void hns3_set_rx_skb_rss_type(struct hns3_enet_ring *ring,
@@ -2703,14 +2768,6 @@ static int hns3_handle_bdinfo(struct hns3_enet_ring *ring, struct sk_buff *skb)
vlan_tag);
}
- if (unlikely(!(bd_base_info & BIT(HNS3_RXD_VLD_B)))) {
- u64_stats_update_begin(&ring->syncp);
- ring->stats.non_vld_descs++;
- u64_stats_update_end(&ring->syncp);
-
- return -EINVAL;
- }
-
if (unlikely(!desc->rx.pkt_len || (l234info & (BIT(HNS3_RXD_TRUNCAT_B) |
BIT(HNS3_RXD_L2E_B))))) {
u64_stats_update_begin(&ring->syncp);
@@ -2762,8 +2819,8 @@ static int hns3_handle_rx_bd(struct hns3_enet_ring *ring,
struct sk_buff *skb = ring->skb;
struct hns3_desc_cb *desc_cb;
struct hns3_desc *desc;
+ unsigned int length;
u32 bd_base_info;
- int length;
int ret;
desc = &ring->desc[ring->next_to_clean];
@@ -2828,14 +2885,14 @@ static int hns3_handle_rx_bd(struct hns3_enet_ring *ring,
return ret;
}
+ skb_record_rx_queue(skb, ring->tqp->tqp_index);
*out_skb = skb;
return 0;
}
-int hns3_clean_rx_ring(
- struct hns3_enet_ring *ring, int budget,
- void (*rx_fn)(struct hns3_enet_ring *, struct sk_buff *))
+int hns3_clean_rx_ring(struct hns3_enet_ring *ring, int budget,
+ void (*rx_fn)(struct hns3_enet_ring *, struct sk_buff *))
{
#define RCB_NOF_ALLOC_RX_BUFF_ONCE 16
int recv_pkts, recv_bds, clean_count, err;
@@ -2887,42 +2944,25 @@ int hns3_clean_rx_ring(
out:
/* Make all data has been write before submit */
if (clean_count + unused_count > 0)
- hns3_nic_alloc_rx_buffers(ring,
- clean_count + unused_count);
+ hns3_nic_alloc_rx_buffers(ring, clean_count + unused_count);
return recv_pkts;
}
-static bool hns3_get_new_int_gl(struct hns3_enet_ring_group *ring_group)
+static bool hns3_get_new_flow_lvl(struct hns3_enet_ring_group *ring_group)
{
- struct hns3_enet_tqp_vector *tqp_vector =
- ring_group->ring->tqp_vector;
+#define HNS3_RX_LOW_BYTE_RATE 10000
+#define HNS3_RX_MID_BYTE_RATE 20000
+#define HNS3_RX_ULTRA_PACKET_RATE 40
+
enum hns3_flow_level_range new_flow_level;
- int packets_per_msecs;
- int bytes_per_msecs;
+ struct hns3_enet_tqp_vector *tqp_vector;
+ int packets_per_msecs, bytes_per_msecs;
u32 time_passed_ms;
- u16 new_int_gl;
-
- if (!tqp_vector->last_jiffies)
- return false;
-
- if (ring_group->total_packets == 0) {
- ring_group->coal.int_gl = HNS3_INT_GL_50K;
- ring_group->coal.flow_level = HNS3_FLOW_LOW;
- return true;
- }
- /* Simple throttlerate management
- * 0-10MB/s lower (50000 ints/s)
- * 10-20MB/s middle (20000 ints/s)
- * 20-1249MB/s high (18000 ints/s)
- * > 40000pps ultra (8000 ints/s)
- */
- new_flow_level = ring_group->coal.flow_level;
- new_int_gl = ring_group->coal.int_gl;
+ tqp_vector = ring_group->ring->tqp_vector;
time_passed_ms =
jiffies_to_msecs(jiffies - tqp_vector->last_jiffies);
-
if (!time_passed_ms)
return false;
@@ -2932,9 +2972,14 @@ static bool hns3_get_new_int_gl(struct hns3_enet_ring_group *ring_group)
do_div(ring_group->total_bytes, time_passed_ms);
bytes_per_msecs = ring_group->total_bytes;
-#define HNS3_RX_LOW_BYTE_RATE 10000
-#define HNS3_RX_MID_BYTE_RATE 20000
+ new_flow_level = ring_group->coal.flow_level;
+ /* Simple throttlerate management
+ * 0-10MB/s lower (50000 ints/s)
+ * 10-20MB/s middle (20000 ints/s)
+ * 20-1249MB/s high (18000 ints/s)
+ * > 40000pps ultra (8000 ints/s)
+ */
switch (new_flow_level) {
case HNS3_FLOW_LOW:
if (bytes_per_msecs > HNS3_RX_LOW_BYTE_RATE)
@@ -2954,13 +2999,40 @@ static bool hns3_get_new_int_gl(struct hns3_enet_ring_group *ring_group)
break;
}
-#define HNS3_RX_ULTRA_PACKET_RATE 40
-
if (packets_per_msecs > HNS3_RX_ULTRA_PACKET_RATE &&
&tqp_vector->rx_group == ring_group)
new_flow_level = HNS3_FLOW_ULTRA;
- switch (new_flow_level) {
+ ring_group->total_bytes = 0;
+ ring_group->total_packets = 0;
+ ring_group->coal.flow_level = new_flow_level;
+
+ return true;
+}
+
+static bool hns3_get_new_int_gl(struct hns3_enet_ring_group *ring_group)
+{
+ struct hns3_enet_tqp_vector *tqp_vector;
+ u16 new_int_gl;
+
+ if (!ring_group->ring)
+ return false;
+
+ tqp_vector = ring_group->ring->tqp_vector;
+ if (!tqp_vector->last_jiffies)
+ return false;
+
+ if (ring_group->total_packets == 0) {
+ ring_group->coal.int_gl = HNS3_INT_GL_50K;
+ ring_group->coal.flow_level = HNS3_FLOW_LOW;
+ return true;
+ }
+
+ if (!hns3_get_new_flow_lvl(ring_group))
+ return false;
+
+ new_int_gl = ring_group->coal.int_gl;
+ switch (ring_group->coal.flow_level) {
case HNS3_FLOW_LOW:
new_int_gl = HNS3_INT_GL_50K;
break;
@@ -2977,9 +3049,6 @@ static bool hns3_get_new_int_gl(struct hns3_enet_ring_group *ring_group)
break;
}
- ring_group->total_bytes = 0;
- ring_group->total_packets = 0;
- ring_group->coal.flow_level = new_flow_level;
if (new_int_gl != ring_group->coal.int_gl) {
ring_group->coal.int_gl = new_int_gl;
return true;
@@ -3280,6 +3349,7 @@ static int hns3_nic_alloc_vector_data(struct hns3_nic_priv *priv)
if (!vector)
return -ENOMEM;
+ /* save the actual available vector number */
vector_num = h->ae_algo->ops->get_vector(h, vector_num, vector);
priv->vector_num = vector_num;
@@ -3331,8 +3401,6 @@ static void hns3_nic_uninit_vector_data(struct hns3_nic_priv *priv)
hns3_free_vector_ring_chain(tqp_vector, &vector_ring_chain);
if (tqp_vector->irq_init_flag == HNS3_VECTOR_INITED) {
- irq_set_affinity_notifier(tqp_vector->vector_irq,
- NULL);
irq_set_affinity_hint(tqp_vector->vector_irq, NULL);
free_irq(tqp_vector->vector_irq, tqp_vector);
tqp_vector->irq_init_flag = HNS3_VECTOR_NOT_INITED;
@@ -3364,7 +3432,7 @@ static int hns3_nic_dealloc_vector_data(struct hns3_nic_priv *priv)
}
static int hns3_ring_get_cfg(struct hnae3_queue *q, struct hns3_nic_priv *priv,
- int ring_type)
+ unsigned int ring_type)
{
struct hns3_nic_ring_data *ring_data = priv->ring_data;
int queue_num = priv->ae_handle->kinfo.num_tqps;
@@ -3550,8 +3618,7 @@ static void hns3_init_ring_hw(struct hns3_enet_ring *ring)
struct hnae3_queue *q = ring->tqp;
if (!HNAE3_IS_TX_RING(ring)) {
- hns3_write_dev(q, HNS3_RING_RX_RING_BASEADDR_L_REG,
- (u32)dma);
+ hns3_write_dev(q, HNS3_RING_RX_RING_BASEADDR_L_REG, (u32)dma);
hns3_write_dev(q, HNS3_RING_RX_RING_BASEADDR_H_REG,
(u32)((dma >> 31) >> 1));
@@ -3803,7 +3870,7 @@ static int hns3_client_init(struct hnae3_handle *handle)
ret = hns3_client_start(handle);
if (ret) {
dev_err(priv->dev, "hns3_client_start fail! ret=%d\n", ret);
- goto out_client_start;
+ goto out_client_start;
}
hns3_dcbnl_setup(handle);
@@ -3851,6 +3918,8 @@ static void hns3_client_uninit(struct hnae3_handle *handle, bool reset)
hns3_client_stop(handle);
+ hns3_uninit_phy(netdev);
+
if (!test_and_clear_bit(HNS3_NIC_STATE_INITED, &priv->state)) {
netdev_warn(netdev, "already uninitialized\n");
goto out_netdev_free;
@@ -3858,9 +3927,7 @@ static void hns3_client_uninit(struct hnae3_handle *handle, bool reset)
hns3_del_all_fd_rules(netdev, true);
- hns3_force_clear_all_rx_ring(handle);
-
- hns3_uninit_phy(netdev);
+ hns3_clear_all_ring(handle, true);
hns3_nic_uninit_vector_data(priv);
@@ -3997,8 +4064,7 @@ static int hns3_clear_rx_ring(struct hns3_enet_ring *ring)
ret);
return ret;
}
- hns3_replace_buffer(ring, ring->next_to_use,
- &res_cbs);
+ hns3_replace_buffer(ring, ring->next_to_use, &res_cbs);
}
ring_ptr_move_fw(ring, next_to_use);
}
@@ -4030,40 +4096,26 @@ static void hns3_force_clear_rx_ring(struct hns3_enet_ring *ring)
}
}
-static void hns3_force_clear_all_rx_ring(struct hnae3_handle *h)
+static void hns3_clear_all_ring(struct hnae3_handle *h, bool force)
{
struct net_device *ndev = h->kinfo.netdev;
struct hns3_nic_priv *priv = netdev_priv(ndev);
- struct hns3_enet_ring *ring;
u32 i;
for (i = 0; i < h->kinfo.num_tqps; i++) {
- ring = priv->ring_data[i + h->kinfo.num_tqps].ring;
- hns3_force_clear_rx_ring(ring);
- }
-}
-
-static void hns3_clear_all_ring(struct hnae3_handle *h)
-{
- struct net_device *ndev = h->kinfo.netdev;
- struct hns3_nic_priv *priv = netdev_priv(ndev);
- u32 i;
-
- for (i = 0; i < h->kinfo.num_tqps; i++) {
- struct netdev_queue *dev_queue;
struct hns3_enet_ring *ring;
ring = priv->ring_data[i].ring;
hns3_clear_tx_ring(ring);
- dev_queue = netdev_get_tx_queue(ndev,
- priv->ring_data[i].queue_index);
- netdev_tx_reset_queue(dev_queue);
ring = priv->ring_data[i + h->kinfo.num_tqps].ring;
/* Continue to clear other rings even if clearing some
* rings failed.
*/
- hns3_clear_rx_ring(ring);
+ if (force)
+ hns3_force_clear_rx_ring(ring);
+ else
+ hns3_clear_rx_ring(ring);
}
}
@@ -4173,7 +4225,7 @@ static int hns3_reset_notify_up_enet(struct hnae3_handle *handle)
if (ret) {
set_bit(HNS3_NIC_STATE_RESETTING, &priv->state);
netdev_err(kinfo->netdev,
- "hns net up fail, ret=%d!\n", ret);
+ "net up fail, ret=%d!\n", ret);
return ret;
}
}
@@ -4251,12 +4303,8 @@ static int hns3_reset_notify_restore_enet(struct hnae3_handle *handle)
vlan_filter_enable = netdev->flags & IFF_PROMISC ? false : true;
hns3_enable_vlan_filter(netdev, vlan_filter_enable);
- /* Hardware table is only clear when pf resets */
- if (!(handle->flags & HNAE3_SUPPORT_VF)) {
- ret = hns3_restore_vlan(netdev);
- if (ret)
- return ret;
- }
+ if (handle->ae_algo->ops->restore_vlan_table)
+ handle->ae_algo->ops->restore_vlan_table(handle);
return hns3_restore_fd_rules(netdev);
}
@@ -4272,7 +4320,8 @@ static int hns3_reset_notify_uninit_enet(struct hnae3_handle *handle)
return 0;
}
- hns3_force_clear_all_rx_ring(handle);
+ hns3_clear_all_ring(handle, true);
+ hns3_reset_tx_queue(priv->ae_handle);
hns3_nic_uninit_vector_data(priv);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
index c14480f9b625..848b866761df 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
@@ -145,7 +145,7 @@ enum hns3_nic_state {
#define HNS3_RXD_TSIND_M (0x7 << HNS3_RXD_TSIND_S)
#define HNS3_RXD_LKBK_B 15
#define HNS3_RXD_GRO_SIZE_S 16
-#define HNS3_RXD_GRO_SIZE_M (0x3ff << HNS3_RXD_GRO_SIZE_S)
+#define HNS3_RXD_GRO_SIZE_M (0x3fff << HNS3_RXD_GRO_SIZE_S)
#define HNS3_TXD_L3T_S 0
#define HNS3_TXD_L3T_M (0x3 << HNS3_TXD_L3T_S)
@@ -384,7 +384,6 @@ struct ring_stats {
u64 rx_err_cnt;
u64 reuse_pg_cnt;
u64 err_pkt_len;
- u64 non_vld_descs;
u64 err_bd_num;
u64 l2_err;
u64 l3l4_csum_err;
@@ -417,7 +416,7 @@ struct hns3_enet_ring {
*/
int next_to_clean;
- int pull_len; /* head length for current packet */
+ u32 pull_len; /* head length for current packet */
u32 frag_num;
unsigned char *va; /* first buffer address for current packet */
@@ -446,25 +445,6 @@ enum hns3_flow_level_range {
HNS3_FLOW_ULTRA = 3,
};
-enum hns3_link_mode_bits {
- HNS3_LM_FIBRE_BIT = BIT(0),
- HNS3_LM_AUTONEG_BIT = BIT(1),
- HNS3_LM_TP_BIT = BIT(2),
- HNS3_LM_PAUSE_BIT = BIT(3),
- HNS3_LM_BACKPLANE_BIT = BIT(4),
- HNS3_LM_10BASET_HALF_BIT = BIT(5),
- HNS3_LM_10BASET_FULL_BIT = BIT(6),
- HNS3_LM_100BASET_HALF_BIT = BIT(7),
- HNS3_LM_100BASET_FULL_BIT = BIT(8),
- HNS3_LM_1000BASET_FULL_BIT = BIT(9),
- HNS3_LM_10000BASEKR_FULL_BIT = BIT(10),
- HNS3_LM_25000BASEKR_FULL_BIT = BIT(11),
- HNS3_LM_40000BASELR4_FULL_BIT = BIT(12),
- HNS3_LM_50000BASEKR2_FULL_BIT = BIT(13),
- HNS3_LM_100000BASEKR4_FULL_BIT = BIT(14),
- HNS3_LM_COUNT = 15
-};
-
#define HNS3_INT_GL_MAX 0x1FE0
#define HNS3_INT_GL_50K 0x0014
#define HNS3_INT_GL_20K 0x0032
@@ -550,7 +530,6 @@ struct hns3_nic_priv {
struct notifier_block notifier_block;
/* Vxlan/Geneve information */
struct hns3_udp_tunnel udp_tnl[HNS3_UDP_TNL_MAX];
- unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
struct hns3_enet_coalesce tx_coal;
struct hns3_enet_coalesce rx_coal;
};
@@ -631,7 +610,7 @@ static inline bool hns3_nic_resetting(struct net_device *netdev)
#define hnae3_buf_size(_ring) ((_ring)->buf_size)
#define hnae3_page_order(_ring) (get_order(hnae3_buf_size(_ring)))
-#define hnae3_page_size(_ring) (PAGE_SIZE << hnae3_page_order(_ring))
+#define hnae3_page_size(_ring) (PAGE_SIZE << (u32)hnae3_page_order(_ring))
/* iterator for handling rings in ring group */
#define hns3_for_each_ring(pos, head) \
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
index d1588ea6132c..5bff98a9b0dc 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
@@ -44,7 +44,6 @@ static const struct hns3_stats hns3_rxq_stats[] = {
HNS3_TQP_STAT("errors", rx_err_cnt),
HNS3_TQP_STAT("reuse_pg_cnt", reuse_pg_cnt),
HNS3_TQP_STAT("err_pkt_len", err_pkt_len),
- HNS3_TQP_STAT("non_vld_descs", non_vld_descs),
HNS3_TQP_STAT("err_bd_num", err_bd_num),
HNS3_TQP_STAT("l2_err", l2_err),
HNS3_TQP_STAT("l3l4_csum_err", l3l4_csum_err),
@@ -60,6 +59,7 @@ static const struct hns3_stats hns3_rxq_stats[] = {
#define HNS3_NIC_LB_TEST_PKT_NUM 1
#define HNS3_NIC_LB_TEST_RING_ID 0
#define HNS3_NIC_LB_TEST_PACKET_SIZE 128
+#define HNS3_NIC_LB_SETUP_USEC 10000
/* Nic loopback test err */
#define HNS3_NIC_LB_TEST_NO_MEM_ERR 1
@@ -117,7 +117,7 @@ static int hns3_lp_up(struct net_device *ndev, enum hnae3_loop loop_mode)
return ret;
ret = hns3_lp_setup(ndev, loop_mode, true);
- usleep_range(10000, 20000);
+ usleep_range(HNS3_NIC_LB_SETUP_USEC, HNS3_NIC_LB_SETUP_USEC * 2);
return ret;
}
@@ -132,7 +132,7 @@ static int hns3_lp_down(struct net_device *ndev, enum hnae3_loop loop_mode)
return ret;
}
- usleep_range(10000, 20000);
+ usleep_range(HNS3_NIC_LB_SETUP_USEC, HNS3_NIC_LB_SETUP_USEC * 2);
return 0;
}
@@ -149,6 +149,12 @@ static void hns3_lp_setup_skb(struct sk_buff *skb)
packet = skb_put(skb, HNS3_NIC_LB_TEST_PACKET_SIZE);
memcpy(ethh->h_dest, ndev->dev_addr, ETH_ALEN);
+
+ /* The dst mac addr of loopback packet is the same as the host'
+ * mac addr, the SSU component may loop back the packet to host
+ * before the packet reaches mac or serdes, which will defect
+ * the purpose of mac or serdes selftest.
+ */
ethh->h_dest[5] += 0x1f;
eth_zero_addr(ethh->h_source);
ethh->h_proto = htons(ETH_P_ARP);
@@ -243,11 +249,13 @@ static int hns3_lp_run_test(struct net_device *ndev, enum hnae3_loop mode)
skb_get(skb);
tx_ret = hns3_nic_net_xmit(skb, ndev);
- if (tx_ret == NETDEV_TX_OK)
+ if (tx_ret == NETDEV_TX_OK) {
good_cnt++;
- else
+ } else {
+ kfree_skb(skb);
netdev_err(ndev, "hns3_lb_run_test xmit failed: %d\n",
tx_ret);
+ }
}
if (good_cnt != HNS3_NIC_LB_TEST_PKT_NUM) {
ret_val = HNS3_NIC_LB_TEST_TX_CNT_ERR;
@@ -327,6 +335,13 @@ static void hns3_self_test(struct net_device *ndev,
h->ae_algo->ops->enable_vlan_filter(h, false);
#endif
+ /* Tell firmware to stop mac autoneg before loopback test start,
+ * otherwise loopback test may be failed when the port is still
+ * negotiating.
+ */
+ if (h->ae_algo->ops->halt_autoneg)
+ h->ae_algo->ops->halt_autoneg(h, true);
+
set_bit(HNS3_NIC_STATE_TESTING, &priv->state);
for (i = 0; i < HNS3_SELF_TEST_TYPE_NUM; i++) {
@@ -349,6 +364,9 @@ static void hns3_self_test(struct net_device *ndev,
clear_bit(HNS3_NIC_STATE_TESTING, &priv->state);
+ if (h->ae_algo->ops->halt_autoneg)
+ h->ae_algo->ops->halt_autoneg(h, false);
+
#if IS_ENABLED(CONFIG_VLAN_8021Q)
if (dis_vlan_filter)
h->ae_algo->ops->enable_vlan_filter(h, true);
@@ -435,7 +453,7 @@ static void hns3_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
switch (stringset) {
case ETH_SS_STATS:
buff = hns3_get_strings_tqps(h, buff);
- h->ae_algo->ops->get_strings(h, stringset, (u8 *)buff);
+ ops->get_strings(h, stringset, (u8 *)buff);
break;
case ETH_SS_TEST:
ops->get_strings(h, stringset, data);
@@ -510,6 +528,11 @@ static void hns3_get_drvinfo(struct net_device *netdev,
struct hns3_nic_priv *priv = netdev_priv(netdev);
struct hnae3_handle *h = priv->ae_handle;
+ if (!h->ae_algo->ops->get_fw_version) {
+ netdev_err(netdev, "could not get fw version!\n");
+ return;
+ }
+
strncpy(drvinfo->version, hns3_driver_version,
sizeof(drvinfo->version));
drvinfo->version[sizeof(drvinfo->version) - 1] = '\0';
@@ -530,7 +553,7 @@ static u32 hns3_get_link(struct net_device *netdev)
{
struct hnae3_handle *h = hns3_get_handle(netdev);
- if (h->ae_algo && h->ae_algo->ops && h->ae_algo->ops->get_status)
+ if (h->ae_algo->ops->get_status)
return h->ae_algo->ops->get_status(h);
else
return 0;
@@ -560,7 +583,7 @@ static void hns3_get_pauseparam(struct net_device *netdev,
{
struct hnae3_handle *h = hns3_get_handle(netdev);
- if (h->ae_algo && h->ae_algo->ops && h->ae_algo->ops->get_pauseparam)
+ if (h->ae_algo->ops->get_pauseparam)
h->ae_algo->ops->get_pauseparam(h, &param->autoneg,
&param->rx_pause, &param->tx_pause);
}
@@ -610,9 +633,6 @@ static int hns3_get_link_ksettings(struct net_device *netdev,
u8 media_type;
u8 link_stat;
- if (!h->ae_algo || !h->ae_algo->ops)
- return -EOPNOTSUPP;
-
ops = h->ae_algo->ops;
if (ops->get_media_type)
ops->get_media_type(h, &media_type, &module_type);
@@ -740,8 +760,7 @@ static u32 hns3_get_rss_key_size(struct net_device *netdev)
{
struct hnae3_handle *h = hns3_get_handle(netdev);
- if (!h->ae_algo || !h->ae_algo->ops ||
- !h->ae_algo->ops->get_rss_key_size)
+ if (!h->ae_algo->ops->get_rss_key_size)
return 0;
return h->ae_algo->ops->get_rss_key_size(h);
@@ -751,8 +770,7 @@ static u32 hns3_get_rss_indir_size(struct net_device *netdev)
{
struct hnae3_handle *h = hns3_get_handle(netdev);
- if (!h->ae_algo || !h->ae_algo->ops ||
- !h->ae_algo->ops->get_rss_indir_size)
+ if (!h->ae_algo->ops->get_rss_indir_size)
return 0;
return h->ae_algo->ops->get_rss_indir_size(h);
@@ -763,7 +781,7 @@ static int hns3_get_rss(struct net_device *netdev, u32 *indir, u8 *key,
{
struct hnae3_handle *h = hns3_get_handle(netdev);
- if (!h->ae_algo || !h->ae_algo->ops || !h->ae_algo->ops->get_rss)
+ if (!h->ae_algo->ops->get_rss)
return -EOPNOTSUPP;
return h->ae_algo->ops->get_rss(h, indir, key, hfunc);
@@ -774,7 +792,7 @@ static int hns3_set_rss(struct net_device *netdev, const u32 *indir,
{
struct hnae3_handle *h = hns3_get_handle(netdev);
- if (!h->ae_algo || !h->ae_algo->ops || !h->ae_algo->ops->set_rss)
+ if (!h->ae_algo->ops->set_rss)
return -EOPNOTSUPP;
if ((h->pdev->revision == 0x20 &&
@@ -799,9 +817,6 @@ static int hns3_get_rxnfc(struct net_device *netdev,
{
struct hnae3_handle *h = hns3_get_handle(netdev);
- if (!h->ae_algo || !h->ae_algo->ops)
- return -EOPNOTSUPP;
-
switch (cmd->cmd) {
case ETHTOOL_GRXRINGS:
cmd->data = h->kinfo.num_tqps;
@@ -915,9 +930,6 @@ static int hns3_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
{
struct hnae3_handle *h = hns3_get_handle(netdev);
- if (!h->ae_algo || !h->ae_algo->ops)
- return -EOPNOTSUPP;
-
switch (cmd->cmd) {
case ETHTOOL_SRXFH:
if (h->ae_algo->ops->set_rss_tuple)
@@ -1193,7 +1205,7 @@ static int hns3_set_phys_id(struct net_device *netdev,
{
struct hnae3_handle *h = hns3_get_handle(netdev);
- if (!h->ae_algo || !h->ae_algo->ops || !h->ae_algo->ops->set_led_id)
+ if (!h->ae_algo->ops->set_led_id)
return -EOPNOTSUPP;
return h->ae_algo->ops->set_led_id(h, state);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c
index fbd904e3077c..22f6acd45d9a 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c
@@ -110,8 +110,7 @@ static void hclge_cmd_config_regs(struct hclge_cmq_ring *ring)
hclge_write_dev(hw, HCLGE_NIC_CSQ_BASEADDR_H_REG,
upper_32_bits(dma));
hclge_write_dev(hw, HCLGE_NIC_CSQ_DEPTH_REG,
- (ring->desc_num >> HCLGE_NIC_CMQ_DESC_NUM_S) |
- HCLGE_NIC_CMQ_ENABLE);
+ ring->desc_num >> HCLGE_NIC_CMQ_DESC_NUM_S);
hclge_write_dev(hw, HCLGE_NIC_CSQ_HEAD_REG, 0);
hclge_write_dev(hw, HCLGE_NIC_CSQ_TAIL_REG, 0);
} else {
@@ -120,8 +119,7 @@ static void hclge_cmd_config_regs(struct hclge_cmq_ring *ring)
hclge_write_dev(hw, HCLGE_NIC_CRQ_BASEADDR_H_REG,
upper_32_bits(dma));
hclge_write_dev(hw, HCLGE_NIC_CRQ_DEPTH_REG,
- (ring->desc_num >> HCLGE_NIC_CMQ_DESC_NUM_S) |
- HCLGE_NIC_CMQ_ENABLE);
+ ring->desc_num >> HCLGE_NIC_CMQ_DESC_NUM_S);
hclge_write_dev(hw, HCLGE_NIC_CRQ_HEAD_REG, 0);
hclge_write_dev(hw, HCLGE_NIC_CRQ_TAIL_REG, 0);
}
@@ -175,7 +173,11 @@ static bool hclge_is_special_opcode(u16 opcode)
HCLGE_OPC_STATS_MAC,
HCLGE_OPC_STATS_MAC_ALL,
HCLGE_OPC_QUERY_32_BIT_REG,
- HCLGE_OPC_QUERY_64_BIT_REG};
+ HCLGE_OPC_QUERY_64_BIT_REG,
+ HCLGE_QUERY_CLEAR_MPF_RAS_INT,
+ HCLGE_QUERY_CLEAR_PF_RAS_INT,
+ HCLGE_QUERY_CLEAR_ALL_MPF_MSIX_INT,
+ HCLGE_QUERY_CLEAR_ALL_PF_MSIX_INT};
int i;
for (i = 0; i < ARRAY_SIZE(spec_opcode); i++) {
@@ -186,12 +188,43 @@ static bool hclge_is_special_opcode(u16 opcode)
return false;
}
+static int hclge_cmd_convert_err_code(u16 desc_ret)
+{
+ switch (desc_ret) {
+ case HCLGE_CMD_EXEC_SUCCESS:
+ return 0;
+ case HCLGE_CMD_NO_AUTH:
+ return -EPERM;
+ case HCLGE_CMD_NOT_SUPPORTED:
+ return -EOPNOTSUPP;
+ case HCLGE_CMD_QUEUE_FULL:
+ return -EXFULL;
+ case HCLGE_CMD_NEXT_ERR:
+ return -ENOSR;
+ case HCLGE_CMD_UNEXE_ERR:
+ return -ENOTBLK;
+ case HCLGE_CMD_PARA_ERR:
+ return -EINVAL;
+ case HCLGE_CMD_RESULT_ERR:
+ return -ERANGE;
+ case HCLGE_CMD_TIMEOUT:
+ return -ETIME;
+ case HCLGE_CMD_HILINK_ERR:
+ return -ENOLINK;
+ case HCLGE_CMD_QUEUE_ILLEGAL:
+ return -ENXIO;
+ case HCLGE_CMD_INVALID:
+ return -EBADR;
+ default:
+ return -EIO;
+ }
+}
+
static int hclge_cmd_check_retval(struct hclge_hw *hw, struct hclge_desc *desc,
int num, int ntc)
{
u16 opcode, desc_ret;
int handle;
- int retval;
opcode = le16_to_cpu(desc[0].opcode);
for (handle = 0; handle < num; handle++) {
@@ -205,17 +238,9 @@ static int hclge_cmd_check_retval(struct hclge_hw *hw, struct hclge_desc *desc,
else
desc_ret = le16_to_cpu(desc[0].retval);
- if (desc_ret == HCLGE_CMD_EXEC_SUCCESS)
- retval = 0;
- else if (desc_ret == HCLGE_CMD_NO_AUTH)
- retval = -EPERM;
- else if (desc_ret == HCLGE_CMD_NOT_SUPPORTED)
- retval = -EOPNOTSUPP;
- else
- retval = -EIO;
hw->cmq.last_status = desc_ret;
- return retval;
+ return hclge_cmd_convert_err_code(desc_ret);
}
/**
@@ -230,6 +255,7 @@ static int hclge_cmd_check_retval(struct hclge_hw *hw, struct hclge_desc *desc,
int hclge_cmd_send(struct hclge_hw *hw, struct hclge_desc *desc, int num)
{
struct hclge_dev *hdev = container_of(hw, struct hclge_dev, hw);
+ struct hclge_cmq_ring *csq = &hw->cmq.csq;
struct hclge_desc *desc_to_use;
bool complete = false;
u32 timeout = 0;
@@ -239,8 +265,16 @@ int hclge_cmd_send(struct hclge_hw *hw, struct hclge_desc *desc, int num)
spin_lock_bh(&hw->cmq.csq.lock);
- if (num > hclge_ring_space(&hw->cmq.csq) ||
- test_bit(HCLGE_STATE_CMD_DISABLE, &hdev->state)) {
+ if (test_bit(HCLGE_STATE_CMD_DISABLE, &hdev->state)) {
+ spin_unlock_bh(&hw->cmq.csq.lock);
+ return -EBUSY;
+ }
+
+ if (num > hclge_ring_space(&hw->cmq.csq)) {
+ /* If CMDQ ring is full, SW HEAD and HW HEAD may be different,
+ * need update the SW HEAD pointer csq->next_to_clean
+ */
+ csq->next_to_clean = hclge_read_dev(hw, HCLGE_NIC_CSQ_HEAD_REG);
spin_unlock_bh(&hw->cmq.csq.lock);
return -EBUSY;
}
@@ -278,7 +312,7 @@ int hclge_cmd_send(struct hclge_hw *hw, struct hclge_desc *desc, int num)
}
if (!complete) {
- retval = -EAGAIN;
+ retval = -EBADE;
} else {
retval = hclge_cmd_check_retval(hw, desc, num, ntc);
}
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
index d79a209b80f6..96840d8f3e24 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
@@ -41,6 +41,14 @@ enum hclge_cmd_return_status {
HCLGE_CMD_NO_AUTH = 1,
HCLGE_CMD_NOT_SUPPORTED = 2,
HCLGE_CMD_QUEUE_FULL = 3,
+ HCLGE_CMD_NEXT_ERR = 4,
+ HCLGE_CMD_UNEXE_ERR = 5,
+ HCLGE_CMD_PARA_ERR = 6,
+ HCLGE_CMD_RESULT_ERR = 7,
+ HCLGE_CMD_TIMEOUT = 8,
+ HCLGE_CMD_HILINK_ERR = 9,
+ HCLGE_CMD_QUEUE_ILLEGAL = 10,
+ HCLGE_CMD_INVALID = 11,
};
enum hclge_cmd_status {
@@ -180,6 +188,9 @@ enum hclge_opcode_type {
HCLGE_OPC_CFG_COM_TQP_QUEUE = 0x0B20,
HCLGE_OPC_RESET_TQP_QUEUE = 0x0B22,
+ /* PPU commands */
+ HCLGE_OPC_PPU_PF_OTHER_INT_DFX = 0x0B4A,
+
/* TSO command */
HCLGE_OPC_TSO_GENERIC_CONFIG = 0x0C01,
HCLGE_OPC_GRO_GENERIC_CONFIG = 0x0C10,
@@ -243,6 +254,9 @@ enum hclge_opcode_type {
/* NCL config command */
HCLGE_OPC_QUERY_NCL_CONFIG = 0x7011,
+ /* M7 stats command */
+ HCLGE_OPC_M7_STATS_BD = 0x7012,
+ HCLGE_OPC_M7_STATS_INFO = 0x7013,
/* SFP command */
HCLGE_OPC_GET_SFP_INFO = 0x7104,
@@ -265,6 +279,8 @@ enum hclge_opcode_type {
HCLGE_CONFIG_ROCEE_RAS_INT_EN = 0x1580,
HCLGE_QUERY_CLEAR_ROCEE_RAS_INT = 0x1581,
HCLGE_ROCEE_PF_RAS_INT_CMD = 0x1584,
+ HCLGE_QUERY_ROCEE_ECC_RAS_INFO_CMD = 0x1585,
+ HCLGE_QUERY_ROCEE_AXI_RAS_INFO_CMD = 0x1586,
HCLGE_IGU_EGU_TNL_INT_EN = 0x1803,
HCLGE_IGU_COMMON_INT_EN = 0x1806,
HCLGE_TM_QCN_MEM_INT_CFG = 0x1A14,
@@ -641,6 +657,11 @@ enum hclge_mac_vlan_tbl_opcode {
HCLGE_MAC_VLAN_LKUP, /* Lookup a entry through mac_vlan key */
};
+enum hclge_mac_vlan_add_resp_code {
+ HCLGE_ADD_UC_OVERFLOW = 2, /* ADD failed for UC overflow */
+ HCLGE_ADD_MC_OVERFLOW, /* ADD failed for MC overflow */
+};
+
#define HCLGE_MAC_VLAN_BIT0_EN_B 0
#define HCLGE_MAC_VLAN_BIT1_EN_B 1
#define HCLGE_MAC_EPORT_SW_EN_B 12
@@ -674,7 +695,6 @@ struct hclge_umv_spc_alc_cmd {
#define HCLGE_MAC_MGR_MASK_VLAN_B BIT(0)
#define HCLGE_MAC_MGR_MASK_MAC_B BIT(1)
#define HCLGE_MAC_MGR_MASK_ETHERTYPE_B BIT(2)
-#define HCLGE_MAC_ETHERTYPE_LLDP 0x88cc
struct hclge_mac_mgr_tbl_entry_cmd {
u8 flags;
@@ -872,7 +892,7 @@ struct hclge_serdes_lb_cmd {
#define HCLGE_TOTAL_PKT_BUF 0x108000 /* 1.03125M bytes */
#define HCLGE_DEFAULT_DV 0xA000 /* 40k byte */
#define HCLGE_DEFAULT_NON_DCB_DV 0x7800 /* 30K byte */
-#define HCLGE_NON_DCB_ADDITIONAL_BUF 0x200 /* 512 byte */
+#define HCLGE_NON_DCB_ADDITIONAL_BUF 0x1400 /* 5120 byte */
#define HCLGE_TYPE_CRQ 0
#define HCLGE_TYPE_CSQ 1
@@ -970,6 +990,25 @@ struct hclge_fd_ad_config_cmd {
u8 rsv2[8];
};
+struct hclge_get_m7_bd_cmd {
+ __le32 bd_num;
+ u8 rsv[20];
+};
+
+struct hclge_query_ppu_pf_other_int_dfx_cmd {
+ __le16 over_8bd_no_fe_qid;
+ __le16 over_8bd_no_fe_vf_id;
+ __le16 tso_mss_cmp_min_err_qid;
+ __le16 tso_mss_cmp_min_err_vf_id;
+ __le16 tso_mss_cmp_max_err_qid;
+ __le16 tso_mss_cmp_max_err_vf_id;
+ __le16 tx_rd_fbd_poison_qid;
+ __le16 tx_rd_fbd_poison_vf_id;
+ __le16 rx_rd_fbd_poison_qid;
+ __le16 rx_rd_fbd_poison_vf_id;
+ u8 rsv[4];
+};
+
int hclge_cmd_init(struct hclge_dev *hdev);
static inline void hclge_write_reg(void __iomem *base, u32 reg, u32 value)
{
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c
index 1161361a973b..bac4ce13f6ae 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c
@@ -325,6 +325,8 @@ static int hclge_ieee_setpfc(struct hnae3_handle *h, struct ieee_pfc *pfc)
hdev->tm_info.hw_pfc_map = pfc_map;
hdev->tm_info.pfc_en = pfc->pfc_en;
+ hclge_tm_pfc_info_update(hdev);
+
return hclge_pause_setup_hw(hdev, false);
}
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c
index a9ffb57c4607..ab625c757a95 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c
@@ -61,9 +61,11 @@ static int hclge_dbg_cmd_send(struct hclge_dev *hdev,
static void hclge_dbg_dump_reg_common(struct hclge_dev *hdev,
struct hclge_dbg_dfx_message *dfx_message,
- char *cmd_buf, int msg_num, int offset,
- enum hclge_opcode_type cmd)
+ const char *cmd_buf, int msg_num,
+ int offset, enum hclge_opcode_type cmd)
{
+#define BD_DATA_NUM 6
+
struct hclge_desc *desc_src;
struct hclge_desc *desc;
int bd_num, buf_len;
@@ -92,14 +94,16 @@ static void hclge_dbg_dump_reg_common(struct hclge_dev *hdev,
return;
}
- max = (bd_num * 6) <= msg_num ? (bd_num * 6) : msg_num;
+ max = (bd_num * BD_DATA_NUM) <= msg_num ?
+ (bd_num * BD_DATA_NUM) : msg_num;
desc = desc_src;
for (i = 0; i < max; i++) {
- (((i / 6) > 0) && ((i % 6) == 0)) ? desc++ : desc;
+ ((i > 0) && ((i % BD_DATA_NUM) == 0)) ? desc++ : desc;
if (dfx_message->flag)
dev_info(&hdev->pdev->dev, "%s: 0x%x\n",
- dfx_message->message, desc->data[i % 6]);
+ dfx_message->message,
+ desc->data[i % BD_DATA_NUM]);
dfx_message++;
}
@@ -107,7 +111,7 @@ static void hclge_dbg_dump_reg_common(struct hclge_dev *hdev,
kfree(desc_src);
}
-static void hclge_dbg_dump_dcb(struct hclge_dev *hdev, char *cmd_buf)
+static void hclge_dbg_dump_dcb(struct hclge_dev *hdev, const char *cmd_buf)
{
struct device *dev = &hdev->pdev->dev;
struct hclge_dbg_bitmap_cmd *bitmap;
@@ -207,7 +211,7 @@ static void hclge_dbg_dump_dcb(struct hclge_dev *hdev, char *cmd_buf)
dev_info(dev, "IGU_TX_PRI_MAP_TC_CFG: 0x%x\n", desc[0].data[5]);
}
-static void hclge_dbg_dump_reg_cmd(struct hclge_dev *hdev, char *cmd_buf)
+static void hclge_dbg_dump_reg_cmd(struct hclge_dev *hdev, const char *cmd_buf)
{
int msg_num;
@@ -395,7 +399,7 @@ static void hclge_dbg_dump_tm_pg(struct hclge_dev *hdev)
if (ret)
goto err_tm_pg_cmd_send;
- dev_info(&hdev->pdev->dev, "PRI_SCH pg_id: %u\n", desc.data[0]);
+ dev_info(&hdev->pdev->dev, "PRI_SCH pri_id: %u\n", desc.data[0]);
cmd = HCLGE_OPC_TM_QS_SCH_MODE_CFG;
hclge_cmd_setup_basic_desc(&desc, cmd, true);
@@ -403,7 +407,7 @@ static void hclge_dbg_dump_tm_pg(struct hclge_dev *hdev)
if (ret)
goto err_tm_pg_cmd_send;
- dev_info(&hdev->pdev->dev, "QS_SCH pg_id: %u\n", desc.data[0]);
+ dev_info(&hdev->pdev->dev, "QS_SCH qs_id: %u\n", desc.data[0]);
cmd = HCLGE_OPC_TM_BP_TO_QSET_MAPPING;
hclge_cmd_setup_basic_desc(&desc, cmd, true);
@@ -412,9 +416,9 @@ static void hclge_dbg_dump_tm_pg(struct hclge_dev *hdev)
goto err_tm_pg_cmd_send;
bp_to_qs_map_cmd = (struct hclge_bp_to_qs_map_cmd *)desc.data;
- dev_info(&hdev->pdev->dev, "BP_TO_QSET pg_id: %u\n",
+ dev_info(&hdev->pdev->dev, "BP_TO_QSET tc_id: %u\n",
bp_to_qs_map_cmd->tc_id);
- dev_info(&hdev->pdev->dev, "BP_TO_QSET pg_shapping: 0x%x\n",
+ dev_info(&hdev->pdev->dev, "BP_TO_QSET qs_group_id: 0x%x\n",
bp_to_qs_map_cmd->qs_group_id);
dev_info(&hdev->pdev->dev, "BP_TO_QSET qs_bit_map: 0x%x\n",
bp_to_qs_map_cmd->qs_bit_map);
@@ -473,7 +477,7 @@ static void hclge_dbg_dump_tm(struct hclge_dev *hdev)
nq_to_qs_map = (struct hclge_nq_to_qs_link_cmd *)desc.data;
dev_info(&hdev->pdev->dev, "NQ_TO_QS nq_id: %u\n", nq_to_qs_map->nq_id);
- dev_info(&hdev->pdev->dev, "NQ_TO_QS qset_id: %u\n",
+ dev_info(&hdev->pdev->dev, "NQ_TO_QS qset_id: 0x%x\n",
nq_to_qs_map->qset_id);
cmd = HCLGE_OPC_TM_PG_WEIGHT;
@@ -537,7 +541,8 @@ err_tm_cmd_send:
cmd, ret);
}
-static void hclge_dbg_dump_tm_map(struct hclge_dev *hdev, char *cmd_buf)
+static void hclge_dbg_dump_tm_map(struct hclge_dev *hdev,
+ const char *cmd_buf)
{
struct hclge_bp_to_qs_map_cmd *bp_to_qs_map_cmd;
struct hclge_nq_to_qs_link_cmd *nq_to_qs_map;
@@ -921,11 +926,67 @@ static void hclge_dbg_dump_rst_info(struct hclge_dev *hdev)
hdev->rst_stats.reset_cnt);
}
+void hclge_dbg_get_m7_stats_info(struct hclge_dev *hdev)
+{
+ struct hclge_desc *desc_src, *desc_tmp;
+ struct hclge_get_m7_bd_cmd *req;
+ struct hclge_desc desc;
+ u32 bd_num, buf_len;
+ int ret, i;
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_M7_STATS_BD, true);
+
+ req = (struct hclge_get_m7_bd_cmd *)desc.data;
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "get firmware statistics bd number failed, ret=%d\n",
+ ret);
+ return;
+ }
+
+ bd_num = le32_to_cpu(req->bd_num);
+
+ buf_len = sizeof(struct hclge_desc) * bd_num;
+ desc_src = kzalloc(buf_len, GFP_KERNEL);
+ if (!desc_src) {
+ dev_err(&hdev->pdev->dev,
+ "allocate desc for get_m7_stats failed\n");
+ return;
+ }
+
+ desc_tmp = desc_src;
+ ret = hclge_dbg_cmd_send(hdev, desc_tmp, 0, bd_num,
+ HCLGE_OPC_M7_STATS_INFO);
+ if (ret) {
+ kfree(desc_src);
+ dev_err(&hdev->pdev->dev,
+ "get firmware statistics failed, ret=%d\n", ret);
+ return;
+ }
+
+ for (i = 0; i < bd_num; i++) {
+ dev_info(&hdev->pdev->dev, "0x%08x 0x%08x 0x%08x\n",
+ le32_to_cpu(desc_tmp->data[0]),
+ le32_to_cpu(desc_tmp->data[1]),
+ le32_to_cpu(desc_tmp->data[2]));
+ dev_info(&hdev->pdev->dev, "0x%08x 0x%08x 0x%08x\n",
+ le32_to_cpu(desc_tmp->data[3]),
+ le32_to_cpu(desc_tmp->data[4]),
+ le32_to_cpu(desc_tmp->data[5]));
+
+ desc_tmp++;
+ }
+
+ kfree(desc_src);
+}
+
/* hclge_dbg_dump_ncl_config: print specified range of NCL_CONFIG file
* @hdev: pointer to struct hclge_dev
* @cmd_buf: string that contains offset and length
*/
-static void hclge_dbg_dump_ncl_config(struct hclge_dev *hdev, char *cmd_buf)
+static void hclge_dbg_dump_ncl_config(struct hclge_dev *hdev,
+ const char *cmd_buf)
{
#define HCLGE_MAX_NCL_CONFIG_OFFSET 4096
#define HCLGE_MAX_NCL_CONFIG_LENGTH (20 + 24 * 4)
@@ -998,13 +1059,13 @@ static void hclge_dbg_dump_mac_tnl_status(struct hclge_dev *hdev)
while (kfifo_get(&hdev->mac_tnl_log, &stats)) {
rem_nsec = do_div(stats.time, HCLGE_BILLION_NANO_SECONDS);
- dev_info(&hdev->pdev->dev, "[%07lu.%03lu]status = 0x%x\n",
+ dev_info(&hdev->pdev->dev, "[%07lu.%03lu] status = 0x%x\n",
(unsigned long)stats.time, rem_nsec / 1000,
stats.status);
}
}
-int hclge_dbg_run_cmd(struct hnae3_handle *handle, char *cmd_buf)
+int hclge_dbg_run_cmd(struct hnae3_handle *handle, const char *cmd_buf)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
@@ -1029,6 +1090,8 @@ int hclge_dbg_run_cmd(struct hnae3_handle *handle, char *cmd_buf)
hclge_dbg_dump_reg_cmd(hdev, cmd_buf);
} else if (strncmp(cmd_buf, "dump reset info", 15) == 0) {
hclge_dbg_dump_rst_info(hdev);
+ } else if (strncmp(cmd_buf, "dump m7 info", 12) == 0) {
+ hclge_dbg_get_m7_stats_info(hdev);
} else if (strncmp(cmd_buf, "dump ncl_config", 15) == 0) {
hclge_dbg_dump_ncl_config(hdev,
&cmd_buf[sizeof("dump ncl_config")]);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c
index 4ac80634c984..0a7243825e7b 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c
@@ -87,25 +87,25 @@ static const struct hclge_hw_error hclge_msix_sram_ecc_int[] = {
static const struct hclge_hw_error hclge_igu_int[] = {
{ .int_msk = BIT(0), .msg = "igu_rx_buf0_ecc_mbit_err",
- .reset_level = HNAE3_CORE_RESET },
+ .reset_level = HNAE3_GLOBAL_RESET },
{ .int_msk = BIT(2), .msg = "igu_rx_buf1_ecc_mbit_err",
- .reset_level = HNAE3_CORE_RESET },
+ .reset_level = HNAE3_GLOBAL_RESET },
{ /* sentinel */ }
};
static const struct hclge_hw_error hclge_igu_egu_tnl_int[] = {
{ .int_msk = BIT(0), .msg = "rx_buf_overflow",
- .reset_level = HNAE3_CORE_RESET },
+ .reset_level = HNAE3_GLOBAL_RESET },
{ .int_msk = BIT(1), .msg = "rx_stp_fifo_overflow",
- .reset_level = HNAE3_CORE_RESET },
+ .reset_level = HNAE3_GLOBAL_RESET },
{ .int_msk = BIT(2), .msg = "rx_stp_fifo_undeflow",
- .reset_level = HNAE3_CORE_RESET },
+ .reset_level = HNAE3_GLOBAL_RESET },
{ .int_msk = BIT(3), .msg = "tx_buf_overflow",
- .reset_level = HNAE3_CORE_RESET },
+ .reset_level = HNAE3_GLOBAL_RESET },
{ .int_msk = BIT(4), .msg = "tx_buf_underrun",
- .reset_level = HNAE3_CORE_RESET },
+ .reset_level = HNAE3_GLOBAL_RESET },
{ .int_msk = BIT(5), .msg = "rx_stp_buf_overflow",
- .reset_level = HNAE3_CORE_RESET },
+ .reset_level = HNAE3_GLOBAL_RESET },
{ /* sentinel */ }
};
@@ -413,13 +413,13 @@ static const struct hclge_hw_error hclge_ppu_mpf_abnormal_int_st2[] = {
static const struct hclge_hw_error hclge_ppu_mpf_abnormal_int_st3[] = {
{ .int_msk = BIT(4), .msg = "gro_bd_ecc_mbit_err",
- .reset_level = HNAE3_CORE_RESET },
+ .reset_level = HNAE3_GLOBAL_RESET },
{ .int_msk = BIT(5), .msg = "gro_context_ecc_mbit_err",
- .reset_level = HNAE3_CORE_RESET },
+ .reset_level = HNAE3_GLOBAL_RESET },
{ .int_msk = BIT(6), .msg = "rx_stash_cfg_ecc_mbit_err",
- .reset_level = HNAE3_CORE_RESET },
+ .reset_level = HNAE3_GLOBAL_RESET },
{ .int_msk = BIT(7), .msg = "axi_rd_fbd_ecc_mbit_err",
- .reset_level = HNAE3_CORE_RESET },
+ .reset_level = HNAE3_GLOBAL_RESET },
{ /* sentinel */ }
};
@@ -631,29 +631,20 @@ static const struct hclge_hw_error hclge_rocee_qmm_ovf_err_int[] = {
{ /* sentinel */ }
};
-static enum hnae3_reset_type hclge_log_error(struct device *dev, char *reg,
- const struct hclge_hw_error *err,
- u32 err_sts)
+static void hclge_log_error(struct device *dev, char *reg,
+ const struct hclge_hw_error *err,
+ u32 err_sts, unsigned long *reset_requests)
{
- enum hnae3_reset_type reset_level = HNAE3_FUNC_RESET;
- bool need_reset = false;
-
while (err->msg) {
if (err->int_msk & err_sts) {
dev_warn(dev, "%s %s found [error status=0x%x]\n",
reg, err->msg, err_sts);
- if (err->reset_level != HNAE3_NONE_RESET &&
- err->reset_level >= reset_level) {
- reset_level = err->reset_level;
- need_reset = true;
- }
+ if (err->reset_level &&
+ err->reset_level != HNAE3_NONE_RESET)
+ set_bit(err->reset_level, reset_requests);
}
err++;
}
- if (need_reset)
- return reset_level;
- else
- return HNAE3_NONE_RESET;
}
/* hclge_cmd_query_error: read the error information
@@ -673,19 +664,19 @@ static int hclge_cmd_query_error(struct hclge_dev *hdev,
enum hclge_err_int_type int_type)
{
struct device *dev = &hdev->pdev->dev;
- int num = 1;
+ int desc_num = 1;
int ret;
hclge_cmd_setup_basic_desc(&desc[0], cmd, true);
if (flag) {
desc[0].flag |= cpu_to_le16(flag);
hclge_cmd_setup_basic_desc(&desc[1], cmd, true);
- num = 2;
+ desc_num = 2;
}
if (w_num)
desc[0].data[w_num] = cpu_to_le32(int_type);
- ret = hclge_cmd_send(&hdev->hw, &desc[0], num);
+ ret = hclge_cmd_send(&hdev->hw, &desc[0], desc_num);
if (ret)
dev_err(dev, "query error cmd failed (%d)\n", ret);
@@ -941,7 +932,7 @@ static int hclge_config_ppu_error_interrupts(struct hclge_dev *hdev, u32 cmd,
{
struct device *dev = &hdev->pdev->dev;
struct hclge_desc desc[2];
- int num = 1;
+ int desc_num = 1;
int ret;
/* configure PPU error interrupts */
@@ -960,7 +951,7 @@ static int hclge_config_ppu_error_interrupts(struct hclge_dev *hdev, u32 cmd,
desc[1].data[1] = HCLGE_PPU_MPF_ABNORMAL_INT1_EN_MASK;
desc[1].data[2] = HCLGE_PPU_MPF_ABNORMAL_INT2_EN_MASK;
desc[1].data[3] |= HCLGE_PPU_MPF_ABNORMAL_INT3_EN_MASK;
- num = 2;
+ desc_num = 2;
} else if (cmd == HCLGE_PPU_MPF_OTHER_INT_CMD) {
hclge_cmd_setup_basic_desc(&desc[0], cmd, false);
if (en)
@@ -978,7 +969,7 @@ static int hclge_config_ppu_error_interrupts(struct hclge_dev *hdev, u32 cmd,
return -EINVAL;
}
- ret = hclge_cmd_send(&hdev->hw, &desc[0], num);
+ ret = hclge_cmd_send(&hdev->hw, &desc[0], desc_num);
return ret;
}
@@ -1069,12 +1060,51 @@ static int hclge_config_ssu_hw_err_int(struct hclge_dev *hdev, bool en)
return ret;
}
-#define HCLGE_SET_DEFAULT_RESET_REQUEST(reset_type) \
- do { \
- if (ae_dev->ops->set_default_reset_request) \
- ae_dev->ops->set_default_reset_request(ae_dev, \
- reset_type); \
- } while (0)
+/* hclge_query_bd_num: query number of buffer descriptors
+ * @hdev: pointer to struct hclge_dev
+ * @is_ras: true for ras, false for msix
+ * @mpf_bd_num: number of main PF interrupt buffer descriptors
+ * @pf_bd_num: number of not main PF interrupt buffer descriptors
+ *
+ * This function querys number of mpf and pf buffer descriptors.
+ */
+static int hclge_query_bd_num(struct hclge_dev *hdev, bool is_ras,
+ int *mpf_bd_num, int *pf_bd_num)
+{
+ struct device *dev = &hdev->pdev->dev;
+ u32 mpf_min_bd_num, pf_min_bd_num;
+ enum hclge_opcode_type opcode;
+ struct hclge_desc desc_bd;
+ int ret;
+
+ if (is_ras) {
+ opcode = HCLGE_QUERY_RAS_INT_STS_BD_NUM;
+ mpf_min_bd_num = HCLGE_MPF_RAS_INT_MIN_BD_NUM;
+ pf_min_bd_num = HCLGE_PF_RAS_INT_MIN_BD_NUM;
+ } else {
+ opcode = HCLGE_QUERY_MSIX_INT_STS_BD_NUM;
+ mpf_min_bd_num = HCLGE_MPF_MSIX_INT_MIN_BD_NUM;
+ pf_min_bd_num = HCLGE_PF_MSIX_INT_MIN_BD_NUM;
+ }
+
+ hclge_cmd_setup_basic_desc(&desc_bd, opcode, true);
+ ret = hclge_cmd_send(&hdev->hw, &desc_bd, 1);
+ if (ret) {
+ dev_err(dev, "fail(%d) to query msix int status bd num\n",
+ ret);
+ return ret;
+ }
+
+ *mpf_bd_num = le32_to_cpu(desc_bd.data[0]);
+ *pf_bd_num = le32_to_cpu(desc_bd.data[1]);
+ if (*mpf_bd_num < mpf_min_bd_num || *pf_bd_num < pf_min_bd_num) {
+ dev_err(dev, "Invalid bd num: mpf(%d), pf(%d)\n",
+ *mpf_bd_num, *pf_bd_num);
+ return -EINVAL;
+ }
+
+ return 0;
+}
/* hclge_handle_mpf_ras_error: handle all main PF RAS errors
* @hdev: pointer to struct hclge_dev
@@ -1089,7 +1119,6 @@ static int hclge_handle_mpf_ras_error(struct hclge_dev *hdev,
int num)
{
struct hnae3_ae_dev *ae_dev = hdev->ae_dev;
- enum hnae3_reset_type reset_level;
struct device *dev = &hdev->pdev->dev;
__le32 *desc_data;
u32 status;
@@ -1098,8 +1127,6 @@ static int hclge_handle_mpf_ras_error(struct hclge_dev *hdev,
/* query all main PF RAS errors */
hclge_cmd_setup_basic_desc(&desc[0], HCLGE_QUERY_CLEAR_MPF_RAS_INT,
true);
- desc[0].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
-
ret = hclge_cmd_send(&hdev->hw, &desc[0], num);
if (ret) {
dev_err(dev, "query all mpf ras int cmd failed (%d)\n", ret);
@@ -1108,95 +1135,74 @@ static int hclge_handle_mpf_ras_error(struct hclge_dev *hdev,
/* log HNS common errors */
status = le32_to_cpu(desc[0].data[0]);
- if (status) {
- reset_level = hclge_log_error(dev, "IMP_TCM_ECC_INT_STS",
- &hclge_imp_tcm_ecc_int[0],
- status);
- HCLGE_SET_DEFAULT_RESET_REQUEST(reset_level);
- }
+ if (status)
+ hclge_log_error(dev, "IMP_TCM_ECC_INT_STS",
+ &hclge_imp_tcm_ecc_int[0], status,
+ &ae_dev->hw_err_reset_req);
status = le32_to_cpu(desc[0].data[1]);
- if (status) {
- reset_level = hclge_log_error(dev, "CMDQ_MEM_ECC_INT_STS",
- &hclge_cmdq_nic_mem_ecc_int[0],
- status);
- HCLGE_SET_DEFAULT_RESET_REQUEST(reset_level);
- }
+ if (status)
+ hclge_log_error(dev, "CMDQ_MEM_ECC_INT_STS",
+ &hclge_cmdq_nic_mem_ecc_int[0], status,
+ &ae_dev->hw_err_reset_req);
- if ((le32_to_cpu(desc[0].data[2])) & BIT(0)) {
+ if ((le32_to_cpu(desc[0].data[2])) & BIT(0))
dev_warn(dev, "imp_rd_data_poison_err found\n");
- HCLGE_SET_DEFAULT_RESET_REQUEST(HNAE3_NONE_RESET);
- }
status = le32_to_cpu(desc[0].data[3]);
- if (status) {
- reset_level = hclge_log_error(dev, "TQP_INT_ECC_INT_STS",
- &hclge_tqp_int_ecc_int[0],
- status);
- HCLGE_SET_DEFAULT_RESET_REQUEST(reset_level);
- }
+ if (status)
+ hclge_log_error(dev, "TQP_INT_ECC_INT_STS",
+ &hclge_tqp_int_ecc_int[0], status,
+ &ae_dev->hw_err_reset_req);
status = le32_to_cpu(desc[0].data[4]);
- if (status) {
- reset_level = hclge_log_error(dev, "MSIX_ECC_INT_STS",
- &hclge_msix_sram_ecc_int[0],
- status);
- HCLGE_SET_DEFAULT_RESET_REQUEST(reset_level);
- }
+ if (status)
+ hclge_log_error(dev, "MSIX_ECC_INT_STS",
+ &hclge_msix_sram_ecc_int[0], status,
+ &ae_dev->hw_err_reset_req);
/* log SSU(Storage Switch Unit) errors */
desc_data = (__le32 *)&desc[2];
status = le32_to_cpu(*(desc_data + 2));
- if (status) {
- reset_level = hclge_log_error(dev, "SSU_ECC_MULTI_BIT_INT_0",
- &hclge_ssu_mem_ecc_err_int[0],
- status);
- HCLGE_SET_DEFAULT_RESET_REQUEST(reset_level);
- }
+ if (status)
+ hclge_log_error(dev, "SSU_ECC_MULTI_BIT_INT_0",
+ &hclge_ssu_mem_ecc_err_int[0], status,
+ &ae_dev->hw_err_reset_req);
status = le32_to_cpu(*(desc_data + 3)) & BIT(0);
if (status) {
dev_warn(dev, "SSU_ECC_MULTI_BIT_INT_1 ssu_mem32_ecc_mbit_err found [error status=0x%x]\n",
status);
- HCLGE_SET_DEFAULT_RESET_REQUEST(HNAE3_GLOBAL_RESET);
+ set_bit(HNAE3_GLOBAL_RESET, &ae_dev->hw_err_reset_req);
}
status = le32_to_cpu(*(desc_data + 4)) & HCLGE_SSU_COMMON_ERR_INT_MASK;
- if (status) {
- reset_level = hclge_log_error(dev, "SSU_COMMON_ERR_INT",
- &hclge_ssu_com_err_int[0],
- status);
- HCLGE_SET_DEFAULT_RESET_REQUEST(reset_level);
- }
+ if (status)
+ hclge_log_error(dev, "SSU_COMMON_ERR_INT",
+ &hclge_ssu_com_err_int[0], status,
+ &ae_dev->hw_err_reset_req);
/* log IGU(Ingress Unit) errors */
desc_data = (__le32 *)&desc[3];
status = le32_to_cpu(*desc_data) & HCLGE_IGU_INT_MASK;
- if (status) {
- reset_level = hclge_log_error(dev, "IGU_INT_STS",
- &hclge_igu_int[0], status);
- HCLGE_SET_DEFAULT_RESET_REQUEST(reset_level);
- }
+ if (status)
+ hclge_log_error(dev, "IGU_INT_STS",
+ &hclge_igu_int[0], status,
+ &ae_dev->hw_err_reset_req);
/* log PPP(Programmable Packet Process) errors */
desc_data = (__le32 *)&desc[4];
status = le32_to_cpu(*(desc_data + 1));
- if (status) {
- reset_level =
- hclge_log_error(dev, "PPP_MPF_ABNORMAL_INT_ST1",
- &hclge_ppp_mpf_abnormal_int_st1[0],
- status);
- HCLGE_SET_DEFAULT_RESET_REQUEST(reset_level);
- }
+ if (status)
+ hclge_log_error(dev, "PPP_MPF_ABNORMAL_INT_ST1",
+ &hclge_ppp_mpf_abnormal_int_st1[0], status,
+ &ae_dev->hw_err_reset_req);
status = le32_to_cpu(*(desc_data + 3)) & HCLGE_PPP_MPF_INT_ST3_MASK;
- if (status) {
- reset_level =
- hclge_log_error(dev, "PPP_MPF_ABNORMAL_INT_ST3",
- &hclge_ppp_mpf_abnormal_int_st3[0],
- status);
- HCLGE_SET_DEFAULT_RESET_REQUEST(reset_level);
- }
+ if (status)
+ hclge_log_error(dev, "PPP_MPF_ABNORMAL_INT_ST3",
+ &hclge_ppp_mpf_abnormal_int_st3[0], status,
+ &ae_dev->hw_err_reset_req);
/* log PPU(RCB) errors */
desc_data = (__le32 *)&desc[5];
@@ -1204,66 +1210,53 @@ static int hclge_handle_mpf_ras_error(struct hclge_dev *hdev,
if (status) {
dev_warn(dev, "PPU_MPF_ABNORMAL_INT_ST1 %s found\n",
"rpu_rx_pkt_ecc_mbit_err");
- HCLGE_SET_DEFAULT_RESET_REQUEST(HNAE3_GLOBAL_RESET);
+ set_bit(HNAE3_GLOBAL_RESET, &ae_dev->hw_err_reset_req);
}
status = le32_to_cpu(*(desc_data + 2));
- if (status) {
- reset_level =
- hclge_log_error(dev, "PPU_MPF_ABNORMAL_INT_ST2",
- &hclge_ppu_mpf_abnormal_int_st2[0],
- status);
- HCLGE_SET_DEFAULT_RESET_REQUEST(reset_level);
- }
+ if (status)
+ hclge_log_error(dev, "PPU_MPF_ABNORMAL_INT_ST2",
+ &hclge_ppu_mpf_abnormal_int_st2[0], status,
+ &ae_dev->hw_err_reset_req);
status = le32_to_cpu(*(desc_data + 3)) & HCLGE_PPU_MPF_INT_ST3_MASK;
- if (status) {
- reset_level =
- hclge_log_error(dev, "PPU_MPF_ABNORMAL_INT_ST3",
- &hclge_ppu_mpf_abnormal_int_st3[0],
- status);
- HCLGE_SET_DEFAULT_RESET_REQUEST(reset_level);
- }
+ if (status)
+ hclge_log_error(dev, "PPU_MPF_ABNORMAL_INT_ST3",
+ &hclge_ppu_mpf_abnormal_int_st3[0], status,
+ &ae_dev->hw_err_reset_req);
/* log TM(Traffic Manager) errors */
desc_data = (__le32 *)&desc[6];
status = le32_to_cpu(*desc_data);
- if (status) {
- reset_level = hclge_log_error(dev, "TM_SCH_RINT",
- &hclge_tm_sch_rint[0], status);
- HCLGE_SET_DEFAULT_RESET_REQUEST(reset_level);
- }
+ if (status)
+ hclge_log_error(dev, "TM_SCH_RINT",
+ &hclge_tm_sch_rint[0], status,
+ &ae_dev->hw_err_reset_req);
/* log QCN(Quantized Congestion Control) errors */
desc_data = (__le32 *)&desc[7];
status = le32_to_cpu(*desc_data) & HCLGE_QCN_FIFO_INT_MASK;
- if (status) {
- reset_level = hclge_log_error(dev, "QCN_FIFO_RINT",
- &hclge_qcn_fifo_rint[0], status);
- HCLGE_SET_DEFAULT_RESET_REQUEST(reset_level);
- }
+ if (status)
+ hclge_log_error(dev, "QCN_FIFO_RINT",
+ &hclge_qcn_fifo_rint[0], status,
+ &ae_dev->hw_err_reset_req);
status = le32_to_cpu(*(desc_data + 1)) & HCLGE_QCN_ECC_INT_MASK;
- if (status) {
- reset_level = hclge_log_error(dev, "QCN_ECC_RINT",
- &hclge_qcn_ecc_rint[0],
- status);
- HCLGE_SET_DEFAULT_RESET_REQUEST(reset_level);
- }
+ if (status)
+ hclge_log_error(dev, "QCN_ECC_RINT",
+ &hclge_qcn_ecc_rint[0], status,
+ &ae_dev->hw_err_reset_req);
/* log NCSI errors */
desc_data = (__le32 *)&desc[9];
status = le32_to_cpu(*desc_data) & HCLGE_NCSI_ECC_INT_MASK;
- if (status) {
- reset_level = hclge_log_error(dev, "NCSI_ECC_INT_RPT",
- &hclge_ncsi_err_int[0], status);
- HCLGE_SET_DEFAULT_RESET_REQUEST(reset_level);
- }
+ if (status)
+ hclge_log_error(dev, "NCSI_ECC_INT_RPT",
+ &hclge_ncsi_err_int[0], status,
+ &ae_dev->hw_err_reset_req);
/* clear all main PF RAS errors */
hclge_cmd_reuse_desc(&desc[0], false);
- desc[0].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
-
ret = hclge_cmd_send(&hdev->hw, &desc[0], num);
if (ret)
dev_err(dev, "clear all mpf ras int cmd failed (%d)\n", ret);
@@ -1285,7 +1278,6 @@ static int hclge_handle_pf_ras_error(struct hclge_dev *hdev,
{
struct hnae3_ae_dev *ae_dev = hdev->ae_dev;
struct device *dev = &hdev->pdev->dev;
- enum hnae3_reset_type reset_level;
__le32 *desc_data;
u32 status;
int ret;
@@ -1293,8 +1285,6 @@ static int hclge_handle_pf_ras_error(struct hclge_dev *hdev,
/* query all PF RAS errors */
hclge_cmd_setup_basic_desc(&desc[0], HCLGE_QUERY_CLEAR_PF_RAS_INT,
true);
- desc[0].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
-
ret = hclge_cmd_send(&hdev->hw, &desc[0], num);
if (ret) {
dev_err(dev, "query all pf ras int cmd failed (%d)\n", ret);
@@ -1303,53 +1293,41 @@ static int hclge_handle_pf_ras_error(struct hclge_dev *hdev,
/* log SSU(Storage Switch Unit) errors */
status = le32_to_cpu(desc[0].data[0]);
- if (status) {
- reset_level = hclge_log_error(dev, "SSU_PORT_BASED_ERR_INT",
- &hclge_ssu_port_based_err_int[0],
- status);
- HCLGE_SET_DEFAULT_RESET_REQUEST(reset_level);
- }
+ if (status)
+ hclge_log_error(dev, "SSU_PORT_BASED_ERR_INT",
+ &hclge_ssu_port_based_err_int[0], status,
+ &ae_dev->hw_err_reset_req);
status = le32_to_cpu(desc[0].data[1]);
- if (status) {
- reset_level = hclge_log_error(dev, "SSU_FIFO_OVERFLOW_INT",
- &hclge_ssu_fifo_overflow_int[0],
- status);
- HCLGE_SET_DEFAULT_RESET_REQUEST(reset_level);
- }
+ if (status)
+ hclge_log_error(dev, "SSU_FIFO_OVERFLOW_INT",
+ &hclge_ssu_fifo_overflow_int[0], status,
+ &ae_dev->hw_err_reset_req);
status = le32_to_cpu(desc[0].data[2]);
- if (status) {
- reset_level = hclge_log_error(dev, "SSU_ETS_TCG_INT",
- &hclge_ssu_ets_tcg_int[0],
- status);
- HCLGE_SET_DEFAULT_RESET_REQUEST(reset_level);
- }
+ if (status)
+ hclge_log_error(dev, "SSU_ETS_TCG_INT",
+ &hclge_ssu_ets_tcg_int[0], status,
+ &ae_dev->hw_err_reset_req);
/* log IGU(Ingress Unit) EGU(Egress Unit) TNL errors */
desc_data = (__le32 *)&desc[1];
status = le32_to_cpu(*desc_data) & HCLGE_IGU_EGU_TNL_INT_MASK;
- if (status) {
- reset_level = hclge_log_error(dev, "IGU_EGU_TNL_INT_STS",
- &hclge_igu_egu_tnl_int[0],
- status);
- HCLGE_SET_DEFAULT_RESET_REQUEST(reset_level);
- }
+ if (status)
+ hclge_log_error(dev, "IGU_EGU_TNL_INT_STS",
+ &hclge_igu_egu_tnl_int[0], status,
+ &ae_dev->hw_err_reset_req);
/* log PPU(RCB) errors */
desc_data = (__le32 *)&desc[3];
status = le32_to_cpu(*desc_data) & HCLGE_PPU_PF_INT_RAS_MASK;
- if (status) {
- reset_level = hclge_log_error(dev, "PPU_PF_ABNORMAL_INT_ST0",
- &hclge_ppu_pf_abnormal_int[0],
- status);
- HCLGE_SET_DEFAULT_RESET_REQUEST(reset_level);
- }
+ if (status)
+ hclge_log_error(dev, "PPU_PF_ABNORMAL_INT_ST0",
+ &hclge_ppu_pf_abnormal_int[0], status,
+ &ae_dev->hw_err_reset_req);
/* clear all PF RAS errors */
hclge_cmd_reuse_desc(&desc[0], false);
- desc[0].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
-
ret = hclge_cmd_send(&hdev->hw, &desc[0], num);
if (ret)
dev_err(dev, "clear all pf ras int cmd failed (%d)\n", ret);
@@ -1359,24 +1337,16 @@ static int hclge_handle_pf_ras_error(struct hclge_dev *hdev,
static int hclge_handle_all_ras_errors(struct hclge_dev *hdev)
{
- struct device *dev = &hdev->pdev->dev;
u32 mpf_bd_num, pf_bd_num, bd_num;
- struct hclge_desc desc_bd;
struct hclge_desc *desc;
int ret;
/* query the number of registers in the RAS int status */
- hclge_cmd_setup_basic_desc(&desc_bd, HCLGE_QUERY_RAS_INT_STS_BD_NUM,
- true);
- ret = hclge_cmd_send(&hdev->hw, &desc_bd, 1);
- if (ret) {
- dev_err(dev, "fail(%d) to query ras int status bd num\n", ret);
+ ret = hclge_query_bd_num(hdev, true, &mpf_bd_num, &pf_bd_num);
+ if (ret)
return ret;
- }
- mpf_bd_num = le32_to_cpu(desc_bd.data[0]);
- pf_bd_num = le32_to_cpu(desc_bd.data[1]);
- bd_num = max_t(u32, mpf_bd_num, pf_bd_num);
+ bd_num = max_t(u32, mpf_bd_num, pf_bd_num);
desc = kcalloc(bd_num, sizeof(struct hclge_desc), GFP_KERNEL);
if (!desc)
return -ENOMEM;
@@ -1396,6 +1366,66 @@ static int hclge_handle_all_ras_errors(struct hclge_dev *hdev)
return ret;
}
+static int hclge_log_rocee_axi_error(struct hclge_dev *hdev)
+{
+ struct device *dev = &hdev->pdev->dev;
+ struct hclge_desc desc[3];
+ int ret;
+
+ hclge_cmd_setup_basic_desc(&desc[0], HCLGE_QUERY_ROCEE_AXI_RAS_INFO_CMD,
+ true);
+ hclge_cmd_setup_basic_desc(&desc[1], HCLGE_QUERY_ROCEE_AXI_RAS_INFO_CMD,
+ true);
+ hclge_cmd_setup_basic_desc(&desc[2], HCLGE_QUERY_ROCEE_AXI_RAS_INFO_CMD,
+ true);
+ desc[0].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
+ desc[1].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
+
+ ret = hclge_cmd_send(&hdev->hw, &desc[0], 3);
+ if (ret) {
+ dev_err(dev, "failed(%d) to query ROCEE AXI error sts\n", ret);
+ return ret;
+ }
+
+ dev_info(dev, "AXI1: %08X %08X %08X %08X %08X %08X\n",
+ le32_to_cpu(desc[0].data[0]), le32_to_cpu(desc[0].data[1]),
+ le32_to_cpu(desc[0].data[2]), le32_to_cpu(desc[0].data[3]),
+ le32_to_cpu(desc[0].data[4]), le32_to_cpu(desc[0].data[5]));
+ dev_info(dev, "AXI2: %08X %08X %08X %08X %08X %08X\n",
+ le32_to_cpu(desc[1].data[0]), le32_to_cpu(desc[1].data[1]),
+ le32_to_cpu(desc[1].data[2]), le32_to_cpu(desc[1].data[3]),
+ le32_to_cpu(desc[1].data[4]), le32_to_cpu(desc[1].data[5]));
+ dev_info(dev, "AXI3: %08X %08X %08X %08X\n",
+ le32_to_cpu(desc[2].data[0]), le32_to_cpu(desc[2].data[1]),
+ le32_to_cpu(desc[2].data[2]), le32_to_cpu(desc[2].data[3]));
+
+ return 0;
+}
+
+static int hclge_log_rocee_ecc_error(struct hclge_dev *hdev)
+{
+ struct device *dev = &hdev->pdev->dev;
+ struct hclge_desc desc[2];
+ int ret;
+
+ ret = hclge_cmd_query_error(hdev, &desc[0],
+ HCLGE_QUERY_ROCEE_ECC_RAS_INFO_CMD,
+ HCLGE_CMD_FLAG_NEXT, 0, 0);
+ if (ret) {
+ dev_err(dev, "failed(%d) to query ROCEE ECC error sts\n", ret);
+ return ret;
+ }
+
+ dev_info(dev, "ECC1: %08X %08X %08X %08X %08X %08X\n",
+ le32_to_cpu(desc[0].data[0]), le32_to_cpu(desc[0].data[1]),
+ le32_to_cpu(desc[0].data[2]), le32_to_cpu(desc[0].data[3]),
+ le32_to_cpu(desc[0].data[4]), le32_to_cpu(desc[0].data[5]));
+ dev_info(dev, "ECC2: %08X %08X %08X\n", le32_to_cpu(desc[1].data[0]),
+ le32_to_cpu(desc[1].data[1]), le32_to_cpu(desc[1].data[2]));
+
+ return 0;
+}
+
static int hclge_log_rocee_ovf_error(struct hclge_dev *hdev)
{
struct device *dev = &hdev->pdev->dev;
@@ -1403,8 +1433,7 @@ static int hclge_log_rocee_ovf_error(struct hclge_dev *hdev)
int ret;
/* read overflow error status */
- ret = hclge_cmd_query_error(hdev, &desc[0],
- HCLGE_ROCEE_PF_RAS_INT_CMD,
+ ret = hclge_cmd_query_error(hdev, &desc[0], HCLGE_ROCEE_PF_RAS_INT_CMD,
0, 0, 0);
if (ret) {
dev_err(dev, "failed(%d) to query ROCEE OVF error sts\n", ret);
@@ -1464,19 +1493,27 @@ hclge_log_and_clear_rocee_ras_error(struct hclge_dev *hdev)
status = le32_to_cpu(desc[0].data[0]);
- if (status & HCLGE_ROCEE_RERR_INT_MASK) {
- dev_warn(dev, "ROCEE RAS AXI rresp error\n");
- reset_type = HNAE3_FUNC_RESET;
- }
+ if (status & HCLGE_ROCEE_AXI_ERR_INT_MASK) {
+ if (status & HCLGE_ROCEE_RERR_INT_MASK)
+ dev_warn(dev, "ROCEE RAS AXI rresp error\n");
+
+ if (status & HCLGE_ROCEE_BERR_INT_MASK)
+ dev_warn(dev, "ROCEE RAS AXI bresp error\n");
- if (status & HCLGE_ROCEE_BERR_INT_MASK) {
- dev_warn(dev, "ROCEE RAS AXI bresp error\n");
reset_type = HNAE3_FUNC_RESET;
+
+ ret = hclge_log_rocee_axi_error(hdev);
+ if (ret)
+ return HNAE3_GLOBAL_RESET;
}
if (status & HCLGE_ROCEE_ECC_INT_MASK) {
dev_warn(dev, "ROCEE RAS 2bit ECC error\n");
reset_type = HNAE3_GLOBAL_RESET;
+
+ ret = hclge_log_rocee_ecc_error(hdev);
+ if (ret)
+ return HNAE3_GLOBAL_RESET;
}
if (status & HCLGE_ROCEE_OVF_INT_MASK) {
@@ -1486,7 +1523,6 @@ hclge_log_and_clear_rocee_ras_error(struct hclge_dev *hdev)
/* reset everything for now */
return HNAE3_GLOBAL_RESET;
}
- reset_type = HNAE3_FUNC_RESET;
}
/* clear error status */
@@ -1501,7 +1537,7 @@ hclge_log_and_clear_rocee_ras_error(struct hclge_dev *hdev)
return reset_type;
}
-static int hclge_config_rocee_ras_interrupt(struct hclge_dev *hdev, bool en)
+int hclge_config_rocee_ras_interrupt(struct hclge_dev *hdev, bool en)
{
struct device *dev = &hdev->pdev->dev;
struct hclge_desc desc;
@@ -1539,7 +1575,7 @@ static void hclge_handle_rocee_ras_error(struct hnae3_ae_dev *ae_dev)
reset_type = hclge_log_and_clear_rocee_ras_error(hdev);
if (reset_type != HNAE3_NONE_RESET)
- HCLGE_SET_DEFAULT_RESET_REQUEST(reset_type);
+ set_bit(reset_type, &ae_dev->hw_err_reset_req);
}
static const struct hclge_hw_blk hw_blk[] = {
@@ -1574,10 +1610,9 @@ static const struct hclge_hw_blk hw_blk[] = {
{ /* sentinel */ }
};
-int hclge_hw_error_set_state(struct hclge_dev *hdev, bool state)
+int hclge_config_nic_hw_error(struct hclge_dev *hdev, bool state)
{
const struct hclge_hw_blk *module = hw_blk;
- struct device *dev = &hdev->pdev->dev;
int ret = 0;
while (module->name) {
@@ -1589,10 +1624,6 @@ int hclge_hw_error_set_state(struct hclge_dev *hdev, bool state)
module++;
}
- ret = hclge_config_rocee_ras_interrupt(hdev, state);
- if (ret)
- dev_err(dev, "fail(%d) to configure ROCEE err int\n", ret);
-
return ret;
}
@@ -1602,165 +1633,281 @@ pci_ers_result_t hclge_handle_hw_ras_error(struct hnae3_ae_dev *ae_dev)
struct device *dev = &hdev->pdev->dev;
u32 status;
+ if (!test_bit(HCLGE_STATE_SERVICE_INITED, &hdev->state)) {
+ dev_err(dev,
+ "Can't recover - RAS error reported during dev init\n");
+ return PCI_ERS_RESULT_NONE;
+ }
+
status = hclge_read_dev(&hdev->hw, HCLGE_RAS_PF_OTHER_INT_STS_REG);
+ if (status & HCLGE_RAS_REG_NFE_MASK ||
+ status & HCLGE_RAS_REG_ROCEE_ERR_MASK)
+ ae_dev->hw_err_reset_req = 0;
+ else
+ goto out;
+
/* Handling Non-fatal HNS RAS errors */
if (status & HCLGE_RAS_REG_NFE_MASK) {
dev_warn(dev,
"HNS Non-Fatal RAS error(status=0x%x) identified\n",
status);
hclge_handle_all_ras_errors(hdev);
- } else {
- if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state) ||
- hdev->pdev->revision < 0x21) {
- ae_dev->override_pci_need_reset = 1;
- return PCI_ERS_RESULT_RECOVERED;
- }
}
- if (status & HCLGE_RAS_REG_ROCEE_ERR_MASK) {
- dev_warn(dev, "ROCEE uncorrected RAS error identified\n");
+ /* Handling Non-fatal Rocee RAS errors */
+ if (hdev->pdev->revision >= 0x21 &&
+ status & HCLGE_RAS_REG_ROCEE_ERR_MASK) {
+ dev_warn(dev, "ROCEE Non-Fatal RAS error identified\n");
hclge_handle_rocee_ras_error(ae_dev);
}
- if (status & HCLGE_RAS_REG_NFE_MASK ||
- status & HCLGE_RAS_REG_ROCEE_ERR_MASK) {
- ae_dev->override_pci_need_reset = 0;
+ if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state))
+ goto out;
+
+ if (ae_dev->hw_err_reset_req)
return PCI_ERS_RESULT_NEED_RESET;
- }
- ae_dev->override_pci_need_reset = 1;
+out:
return PCI_ERS_RESULT_RECOVERED;
}
-int hclge_handle_hw_msix_error(struct hclge_dev *hdev,
- unsigned long *reset_requests)
+static int hclge_clear_hw_msix_error(struct hclge_dev *hdev,
+ struct hclge_desc *desc, bool is_mpf,
+ u32 bd_num)
+{
+ if (is_mpf)
+ desc[0].opcode =
+ cpu_to_le16(HCLGE_QUERY_CLEAR_ALL_MPF_MSIX_INT);
+ else
+ desc[0].opcode = cpu_to_le16(HCLGE_QUERY_CLEAR_ALL_PF_MSIX_INT);
+
+ desc[0].flag = cpu_to_le16(HCLGE_CMD_FLAG_NO_INTR | HCLGE_CMD_FLAG_IN);
+
+ return hclge_cmd_send(&hdev->hw, &desc[0], bd_num);
+}
+
+/* hclge_query_8bd_info: query information about over_8bd_nfe_err
+ * @hdev: pointer to struct hclge_dev
+ * @vf_id: Index of the virtual function with error
+ * @q_id: Physical index of the queue with error
+ *
+ * This function get specific index of queue and function which causes
+ * over_8bd_nfe_err by using command. If vf_id is 0, it means error is
+ * caused by PF instead of VF.
+ */
+static int hclge_query_over_8bd_err_info(struct hclge_dev *hdev, u16 *vf_id,
+ u16 *q_id)
+{
+ struct hclge_query_ppu_pf_other_int_dfx_cmd *req;
+ struct hclge_desc desc;
+ int ret;
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_PPU_PF_OTHER_INT_DFX, true);
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret)
+ return ret;
+
+ req = (struct hclge_query_ppu_pf_other_int_dfx_cmd *)desc.data;
+ *vf_id = le16_to_cpu(req->over_8bd_no_fe_vf_id);
+ *q_id = le16_to_cpu(req->over_8bd_no_fe_qid);
+
+ return 0;
+}
+
+/* hclge_handle_over_8bd_err: handle MSI-X error named over_8bd_nfe_err
+ * @hdev: pointer to struct hclge_dev
+ * @reset_requests: reset level that we need to trigger later
+ *
+ * over_8bd_nfe_err is a special MSI-X because it may caused by a VF, in
+ * that case, we need to trigger VF reset. Otherwise, a PF reset is needed.
+ */
+static void hclge_handle_over_8bd_err(struct hclge_dev *hdev,
+ unsigned long *reset_requests)
{
- struct hclge_mac_tnl_stats mac_tnl_stats;
struct device *dev = &hdev->pdev->dev;
- u32 mpf_bd_num, pf_bd_num, bd_num;
- enum hnae3_reset_type reset_level;
- struct hclge_desc desc_bd;
- struct hclge_desc *desc;
- __le32 *desc_data;
- u32 status;
+ u16 vf_id;
+ u16 q_id;
int ret;
- /* query the number of bds for the MSIx int status */
- hclge_cmd_setup_basic_desc(&desc_bd, HCLGE_QUERY_MSIX_INT_STS_BD_NUM,
- true);
- ret = hclge_cmd_send(&hdev->hw, &desc_bd, 1);
+ ret = hclge_query_over_8bd_err_info(hdev, &vf_id, &q_id);
if (ret) {
- dev_err(dev, "fail(%d) to query msix int status bd num\n",
+ dev_err(dev, "fail(%d) to query over_8bd_no_fe info\n",
ret);
- return ret;
+ return;
}
- mpf_bd_num = le32_to_cpu(desc_bd.data[0]);
- pf_bd_num = le32_to_cpu(desc_bd.data[1]);
- bd_num = max_t(u32, mpf_bd_num, pf_bd_num);
+ dev_warn(dev, "PPU_PF_ABNORMAL_INT_ST over_8bd_no_fe found, vf_id(%d), queue_id(%d)\n",
+ vf_id, q_id);
- desc = kcalloc(bd_num, sizeof(struct hclge_desc), GFP_KERNEL);
- if (!desc)
- goto out;
+ if (vf_id) {
+ if (vf_id >= hdev->num_alloc_vport) {
+ dev_err(dev, "invalid vf id(%d)\n", vf_id);
+ return;
+ }
+
+ /* If we need to trigger other reset whose level is higher
+ * than HNAE3_VF_FUNC_RESET, no need to trigger a VF reset
+ * here.
+ */
+ if (*reset_requests != 0)
+ return;
+ ret = hclge_inform_reset_assert_to_vf(&hdev->vport[vf_id]);
+ if (ret)
+ dev_warn(dev, "inform reset to vf(%d) failed %d!\n",
+ hdev->vport->vport_id, ret);
+ } else {
+ set_bit(HNAE3_FUNC_RESET, reset_requests);
+ }
+}
+
+/* hclge_handle_mpf_msix_error: handle all main PF MSI-X errors
+ * @hdev: pointer to struct hclge_dev
+ * @desc: descriptor for describing the command
+ * @mpf_bd_num: number of extended command structures
+ * @reset_requests: record of the reset level that we need
+ *
+ * This function handles all the main PF MSI-X errors in the hw register/s
+ * using command.
+ */
+static int hclge_handle_mpf_msix_error(struct hclge_dev *hdev,
+ struct hclge_desc *desc,
+ int mpf_bd_num,
+ unsigned long *reset_requests)
+{
+ struct device *dev = &hdev->pdev->dev;
+ __le32 *desc_data;
+ u32 status;
+ int ret;
/* query all main PF MSIx errors */
hclge_cmd_setup_basic_desc(&desc[0], HCLGE_QUERY_CLEAR_ALL_MPF_MSIX_INT,
true);
- desc[0].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
-
ret = hclge_cmd_send(&hdev->hw, &desc[0], mpf_bd_num);
if (ret) {
- dev_err(dev, "query all mpf msix int cmd failed (%d)\n",
- ret);
- goto msi_error;
+ dev_err(dev, "query all mpf msix int cmd failed (%d)\n", ret);
+ return ret;
}
/* log MAC errors */
desc_data = (__le32 *)&desc[1];
status = le32_to_cpu(*desc_data);
- if (status) {
- reset_level = hclge_log_error(dev, "MAC_AFIFO_TNL_INT_R",
- &hclge_mac_afifo_tnl_int[0],
- status);
- set_bit(reset_level, reset_requests);
- }
+ if (status)
+ hclge_log_error(dev, "MAC_AFIFO_TNL_INT_R",
+ &hclge_mac_afifo_tnl_int[0], status,
+ reset_requests);
/* log PPU(RCB) MPF errors */
desc_data = (__le32 *)&desc[5];
status = le32_to_cpu(*(desc_data + 2)) &
HCLGE_PPU_MPF_INT_ST2_MSIX_MASK;
- if (status) {
- reset_level =
- hclge_log_error(dev, "PPU_MPF_ABNORMAL_INT_ST2",
- &hclge_ppu_mpf_abnormal_int_st2[0],
- status);
- set_bit(reset_level, reset_requests);
- }
+ if (status)
+ dev_warn(dev, "PPU_MPF_ABNORMAL_INT_ST2 rx_q_search_miss found [dfx status=0x%x\n]",
+ status);
/* clear all main PF MSIx errors */
- hclge_cmd_reuse_desc(&desc[0], false);
- desc[0].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
+ ret = hclge_clear_hw_msix_error(hdev, desc, true, mpf_bd_num);
+ if (ret)
+ dev_err(dev, "clear all mpf msix int cmd failed (%d)\n", ret);
- ret = hclge_cmd_send(&hdev->hw, &desc[0], mpf_bd_num);
- if (ret) {
- dev_err(dev, "clear all mpf msix int cmd failed (%d)\n",
- ret);
- goto msi_error;
- }
+ return ret;
+}
+
+/* hclge_handle_pf_msix_error: handle all PF MSI-X errors
+ * @hdev: pointer to struct hclge_dev
+ * @desc: descriptor for describing the command
+ * @mpf_bd_num: number of extended command structures
+ * @reset_requests: record of the reset level that we need
+ *
+ * This function handles all the PF MSI-X errors in the hw register/s using
+ * command.
+ */
+static int hclge_handle_pf_msix_error(struct hclge_dev *hdev,
+ struct hclge_desc *desc,
+ int pf_bd_num,
+ unsigned long *reset_requests)
+{
+ struct device *dev = &hdev->pdev->dev;
+ __le32 *desc_data;
+ u32 status;
+ int ret;
/* query all PF MSIx errors */
- memset(desc, 0, bd_num * sizeof(struct hclge_desc));
hclge_cmd_setup_basic_desc(&desc[0], HCLGE_QUERY_CLEAR_ALL_PF_MSIX_INT,
true);
- desc[0].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
-
ret = hclge_cmd_send(&hdev->hw, &desc[0], pf_bd_num);
if (ret) {
- dev_err(dev, "query all pf msix int cmd failed (%d)\n",
- ret);
- goto msi_error;
+ dev_err(dev, "query all pf msix int cmd failed (%d)\n", ret);
+ return ret;
}
/* log SSU PF errors */
status = le32_to_cpu(desc[0].data[0]) & HCLGE_SSU_PORT_INT_MSIX_MASK;
- if (status) {
- reset_level = hclge_log_error(dev, "SSU_PORT_BASED_ERR_INT",
- &hclge_ssu_port_based_pf_int[0],
- status);
- set_bit(reset_level, reset_requests);
- }
+ if (status)
+ hclge_log_error(dev, "SSU_PORT_BASED_ERR_INT",
+ &hclge_ssu_port_based_pf_int[0],
+ status, reset_requests);
/* read and log PPP PF errors */
desc_data = (__le32 *)&desc[2];
status = le32_to_cpu(*desc_data);
- if (status) {
- reset_level = hclge_log_error(dev, "PPP_PF_ABNORMAL_INT_ST0",
- &hclge_ppp_pf_abnormal_int[0],
- status);
- set_bit(reset_level, reset_requests);
- }
+ if (status)
+ hclge_log_error(dev, "PPP_PF_ABNORMAL_INT_ST0",
+ &hclge_ppp_pf_abnormal_int[0],
+ status, reset_requests);
/* log PPU(RCB) PF errors */
desc_data = (__le32 *)&desc[3];
status = le32_to_cpu(*desc_data) & HCLGE_PPU_PF_INT_MSIX_MASK;
- if (status) {
- reset_level = hclge_log_error(dev, "PPU_PF_ABNORMAL_INT_ST",
- &hclge_ppu_pf_abnormal_int[0],
- status);
- set_bit(reset_level, reset_requests);
- }
+ if (status)
+ hclge_log_error(dev, "PPU_PF_ABNORMAL_INT_ST",
+ &hclge_ppu_pf_abnormal_int[0],
+ status, reset_requests);
+
+ status = le32_to_cpu(*desc_data) & HCLGE_PPU_PF_OVER_8BD_ERR_MASK;
+ if (status)
+ hclge_handle_over_8bd_err(hdev, reset_requests);
/* clear all PF MSIx errors */
- hclge_cmd_reuse_desc(&desc[0], false);
- desc[0].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
+ ret = hclge_clear_hw_msix_error(hdev, desc, false, pf_bd_num);
+ if (ret)
+ dev_err(dev, "clear all pf msix int cmd failed (%d)\n", ret);
- ret = hclge_cmd_send(&hdev->hw, &desc[0], pf_bd_num);
- if (ret) {
- dev_err(dev, "clear all pf msix int cmd failed (%d)\n",
- ret);
+ return ret;
+}
+
+static int hclge_handle_all_hw_msix_error(struct hclge_dev *hdev,
+ unsigned long *reset_requests)
+{
+ struct hclge_mac_tnl_stats mac_tnl_stats;
+ struct device *dev = &hdev->pdev->dev;
+ u32 mpf_bd_num, pf_bd_num, bd_num;
+ struct hclge_desc *desc;
+ u32 status;
+ int ret;
+
+ /* query the number of bds for the MSIx int status */
+ ret = hclge_query_bd_num(hdev, false, &mpf_bd_num, &pf_bd_num);
+ if (ret)
+ goto out;
+
+ bd_num = max_t(u32, mpf_bd_num, pf_bd_num);
+ desc = kcalloc(bd_num, sizeof(struct hclge_desc), GFP_KERNEL);
+ if (!desc) {
+ ret = -ENOMEM;
+ goto out;
}
+ ret = hclge_handle_mpf_msix_error(hdev, desc, mpf_bd_num,
+ reset_requests);
+ if (ret)
+ goto msi_error;
+
+ memset(desc, 0, bd_num * sizeof(struct hclge_desc));
+ ret = hclge_handle_pf_msix_error(hdev, desc, pf_bd_num, reset_requests);
+ if (ret)
+ goto msi_error;
+
/* query and clear mac tnl interruptions */
hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_QUERY_MAC_TNL_INT,
true);
@@ -1783,7 +1930,6 @@ int hclge_handle_hw_msix_error(struct hclge_dev *hdev,
ret = hclge_clear_mac_tnl_int(hdev);
if (ret)
dev_err(dev, "clear mac tnl int failed (%d)\n", ret);
- set_bit(HNAE3_NONE_RESET, reset_requests);
}
msi_error:
@@ -1791,3 +1937,70 @@ msi_error:
out:
return ret;
}
+
+int hclge_handle_hw_msix_error(struct hclge_dev *hdev,
+ unsigned long *reset_requests)
+{
+ struct device *dev = &hdev->pdev->dev;
+
+ if (!test_bit(HCLGE_STATE_SERVICE_INITED, &hdev->state)) {
+ dev_err(dev,
+ "Can't handle - MSIx error reported during dev init\n");
+ return 0;
+ }
+
+ return hclge_handle_all_hw_msix_error(hdev, reset_requests);
+}
+
+void hclge_handle_all_hns_hw_errors(struct hnae3_ae_dev *ae_dev)
+{
+#define HCLGE_DESC_NO_DATA_LEN 8
+
+ struct hclge_dev *hdev = ae_dev->priv;
+ struct device *dev = &hdev->pdev->dev;
+ u32 mpf_bd_num, pf_bd_num, bd_num;
+ struct hclge_desc *desc;
+ u32 status;
+ int ret;
+
+ ae_dev->hw_err_reset_req = 0;
+ status = hclge_read_dev(&hdev->hw, HCLGE_RAS_PF_OTHER_INT_STS_REG);
+
+ /* query the number of bds for the MSIx int status */
+ ret = hclge_query_bd_num(hdev, false, &mpf_bd_num, &pf_bd_num);
+ if (ret)
+ return;
+
+ bd_num = max_t(u32, mpf_bd_num, pf_bd_num);
+ desc = kcalloc(bd_num, sizeof(struct hclge_desc), GFP_KERNEL);
+ if (!desc)
+ return;
+
+ /* Clear HNS hw errors reported through msix */
+ memset(&desc[0].data[0], 0xFF, mpf_bd_num * sizeof(struct hclge_desc) -
+ HCLGE_DESC_NO_DATA_LEN);
+ ret = hclge_clear_hw_msix_error(hdev, desc, true, mpf_bd_num);
+ if (ret) {
+ dev_err(dev, "fail(%d) to clear mpf msix int during init\n",
+ ret);
+ goto msi_error;
+ }
+
+ memset(&desc[0].data[0], 0xFF, pf_bd_num * sizeof(struct hclge_desc) -
+ HCLGE_DESC_NO_DATA_LEN);
+ ret = hclge_clear_hw_msix_error(hdev, desc, false, pf_bd_num);
+ if (ret) {
+ dev_err(dev, "fail(%d) to clear pf msix int during init\n",
+ ret);
+ goto msi_error;
+ }
+
+ /* Handle Non-fatal HNS RAS errors */
+ if (status & HCLGE_RAS_REG_NFE_MASK) {
+ dev_warn(dev, "HNS hw error(RAS) identified during init\n");
+ hclge_handle_all_ras_errors(hdev);
+ }
+
+msi_error:
+ kfree(desc);
+}
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h
index 9645590c9294..7ea8bb28a0cb 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h
@@ -6,6 +6,11 @@
#include "hclge_main.h"
+#define HCLGE_MPF_RAS_INT_MIN_BD_NUM 10
+#define HCLGE_PF_RAS_INT_MIN_BD_NUM 4
+#define HCLGE_MPF_MSIX_INT_MIN_BD_NUM 10
+#define HCLGE_PF_MSIX_INT_MIN_BD_NUM 4
+
#define HCLGE_RAS_PF_OTHER_INT_STS_REG 0x20B00
#define HCLGE_RAS_REG_NFE_MASK 0xFF00
#define HCLGE_RAS_REG_ROCEE_ERR_MASK 0x3000000
@@ -47,9 +52,9 @@
#define HCLGE_NCSI_ERR_INT_TYPE 0x9
#define HCLGE_MAC_COMMON_ERR_INT_EN 0x107FF
#define HCLGE_MAC_COMMON_ERR_INT_EN_MASK 0x107FF
-#define HCLGE_MAC_TNL_INT_EN GENMASK(7, 0)
-#define HCLGE_MAC_TNL_INT_EN_MASK GENMASK(7, 0)
-#define HCLGE_MAC_TNL_INT_CLR GENMASK(7, 0)
+#define HCLGE_MAC_TNL_INT_EN GENMASK(9, 0)
+#define HCLGE_MAC_TNL_INT_EN_MASK GENMASK(9, 0)
+#define HCLGE_MAC_TNL_INT_CLR GENMASK(9, 0)
#define HCLGE_PPU_MPF_ABNORMAL_INT0_EN GENMASK(31, 0)
#define HCLGE_PPU_MPF_ABNORMAL_INT0_EN_MASK GENMASK(31, 0)
#define HCLGE_PPU_MPF_ABNORMAL_INT1_EN GENMASK(31, 0)
@@ -81,9 +86,10 @@
#define HCLGE_IGU_EGU_TNL_INT_MASK GENMASK(5, 0)
#define HCLGE_PPP_MPF_INT_ST3_MASK GENMASK(5, 0)
#define HCLGE_PPU_MPF_INT_ST3_MASK GENMASK(7, 0)
-#define HCLGE_PPU_MPF_INT_ST2_MSIX_MASK GENMASK(29, 28)
+#define HCLGE_PPU_MPF_INT_ST2_MSIX_MASK BIT(29)
#define HCLGE_PPU_PF_INT_RAS_MASK 0x18
-#define HCLGE_PPU_PF_INT_MSIX_MASK 0x27
+#define HCLGE_PPU_PF_INT_MSIX_MASK 0x26
+#define HCLGE_PPU_PF_OVER_8BD_ERR_MASK 0x01
#define HCLGE_QCN_FIFO_INT_MASK GENMASK(17, 0)
#define HCLGE_QCN_ECC_INT_MASK GENMASK(21, 0)
#define HCLGE_NCSI_ECC_INT_MASK GENMASK(1, 0)
@@ -94,6 +100,7 @@
#define HCLGE_ROCEE_RAS_CE_INT_EN_MASK 0x1
#define HCLGE_ROCEE_RERR_INT_MASK BIT(0)
#define HCLGE_ROCEE_BERR_INT_MASK BIT(1)
+#define HCLGE_ROCEE_AXI_ERR_INT_MASK GENMASK(1, 0)
#define HCLGE_ROCEE_ECC_INT_MASK BIT(2)
#define HCLGE_ROCEE_OVF_INT_MASK BIT(3)
#define HCLGE_ROCEE_OVF_ERR_INT_MASK 0x10000
@@ -119,7 +126,9 @@ struct hclge_hw_error {
};
int hclge_config_mac_tnl_int(struct hclge_dev *hdev, bool en);
-int hclge_hw_error_set_state(struct hclge_dev *hdev, bool state);
+int hclge_config_nic_hw_error(struct hclge_dev *hdev, bool state);
+int hclge_config_rocee_ras_interrupt(struct hclge_dev *hdev, bool en);
+void hclge_handle_all_hns_hw_errors(struct hnae3_ae_dev *ae_dev);
pci_ers_result_t hclge_handle_hw_ras_error(struct hnae3_ae_dev *ae_dev);
int hclge_handle_hw_msix_error(struct hclge_dev *hdev,
unsigned long *reset_requests);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
index d3b1f8cb1155..3fde5471e1c0 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
@@ -27,14 +27,26 @@
#define HCLGE_STATS_READ(p, offset) (*((u64 *)((u8 *)(p) + (offset))))
#define HCLGE_MAC_STATS_FIELD_OFF(f) (offsetof(struct hclge_mac_stats, f))
-#define HCLGE_BUF_SIZE_UNIT 256
+#define HCLGE_BUF_SIZE_UNIT 256U
+#define HCLGE_BUF_MUL_BY 2
+#define HCLGE_BUF_DIV_BY 2
+#define NEED_RESERVE_TC_NUM 2
+#define BUF_MAX_PERCENT 100
+#define BUF_RESERVE_PERCENT 90
+
+#define HCLGE_RESET_MAX_FAIL_CNT 5
static int hclge_set_mac_mtu(struct hclge_dev *hdev, int new_mps);
static int hclge_init_vlan_config(struct hclge_dev *hdev);
+static void hclge_sync_vlan_filter(struct hclge_dev *hdev);
static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev);
static bool hclge_get_hw_reset_stat(struct hnae3_handle *handle);
static int hclge_set_umv_space(struct hclge_dev *hdev, u16 space_size,
u16 *allocated_size, bool is_alloc);
+static void hclge_rfs_filter_expire(struct hclge_dev *hdev);
+static void hclge_clear_arfs_rules(struct hnae3_handle *handle);
+static enum hnae3_reset_type hclge_get_reset_level(struct hnae3_ae_dev *ae_dev,
+ unsigned long *addr);
static struct hnae3_ae_algo ae_algo;
@@ -290,7 +302,7 @@ static const struct hclge_comm_stats_str g_mac_stats_string[] = {
static const struct hclge_mac_mgr_tbl_entry_cmd hclge_mgr_table[] = {
{
.flags = HCLGE_MAC_MGR_MASK_VLAN_B,
- .ethter_type = cpu_to_le16(HCLGE_MAC_ETHERTYPE_LLDP),
+ .ethter_type = cpu_to_le16(ETH_P_LLDP),
.mac_addr_hi32 = cpu_to_le32(htonl(0x0180C200)),
.mac_addr_lo16 = cpu_to_le16(htons(0x000E)),
.i_port_bitmap = 0x1,
@@ -437,8 +449,7 @@ static int hclge_tqps_update_stats(struct hnae3_handle *handle)
queue = handle->kinfo.tqp[i];
tqp = container_of(queue, struct hclge_tqp, q);
/* command : HCLGE_OPC_QUERY_IGU_STAT */
- hclge_cmd_setup_basic_desc(&desc[0],
- HCLGE_OPC_QUERY_RX_STATUS,
+ hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_QUERY_RX_STATUS,
true);
desc[0].data[0] = cpu_to_le32((tqp->index & 0x1ff));
@@ -446,7 +457,7 @@ static int hclge_tqps_update_stats(struct hnae3_handle *handle)
if (ret) {
dev_err(&hdev->pdev->dev,
"Query tqp stat fail, status = %d,queue = %d\n",
- ret, i);
+ ret, i);
return ret;
}
tqp->tqp_stats.rcb_rx_ring_pktnum_rcd +=
@@ -500,6 +511,7 @@ static int hclge_tqps_get_sset_count(struct hnae3_handle *handle, int stringset)
{
struct hnae3_knic_private_info *kinfo = &handle->kinfo;
+ /* each tqp has TX & RX two queues */
return kinfo->num_tqps * (2);
}
@@ -528,7 +540,7 @@ static u8 *hclge_tqps_get_strings(struct hnae3_handle *handle, u8 *data)
return buff;
}
-static u64 *hclge_comm_get_stats(void *comm_stats,
+static u64 *hclge_comm_get_stats(const void *comm_stats,
const struct hclge_comm_stats_str strs[],
int size, u64 *data)
{
@@ -552,8 +564,7 @@ static u8 *hclge_comm_get_strings(u32 stringset,
return buff;
for (i = 0; i < size; i++) {
- snprintf(buff, ETH_GSTRING_LEN,
- strs[i].desc);
+ snprintf(buff, ETH_GSTRING_LEN, "%s", strs[i].desc);
buff = buff + ETH_GSTRING_LEN;
}
@@ -644,8 +655,7 @@ static int hclge_get_sset_count(struct hnae3_handle *handle, int stringset)
return count;
}
-static void hclge_get_strings(struct hnae3_handle *handle,
- u32 stringset,
+static void hclge_get_strings(struct hnae3_handle *handle, u32 stringset,
u8 *data)
{
u8 *p = (char *)data;
@@ -653,21 +663,17 @@ static void hclge_get_strings(struct hnae3_handle *handle,
if (stringset == ETH_SS_STATS) {
size = ARRAY_SIZE(g_mac_stats_string);
- p = hclge_comm_get_strings(stringset,
- g_mac_stats_string,
- size,
- p);
+ p = hclge_comm_get_strings(stringset, g_mac_stats_string,
+ size, p);
p = hclge_tqps_get_strings(handle, p);
} else if (stringset == ETH_SS_TEST) {
if (handle->flags & HNAE3_SUPPORT_APP_LOOPBACK) {
- memcpy(p,
- hns3_nic_test_strs[HNAE3_LOOP_APP],
+ memcpy(p, hns3_nic_test_strs[HNAE3_LOOP_APP],
ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN;
}
if (handle->flags & HNAE3_SUPPORT_SERDES_SERIAL_LOOPBACK) {
- memcpy(p,
- hns3_nic_test_strs[HNAE3_LOOP_SERIAL_SERDES],
+ memcpy(p, hns3_nic_test_strs[HNAE3_LOOP_SERIAL_SERDES],
ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN;
}
@@ -678,8 +684,7 @@ static void hclge_get_strings(struct hnae3_handle *handle,
p += ETH_GSTRING_LEN;
}
if (handle->flags & HNAE3_SUPPORT_PHY_LOOPBACK) {
- memcpy(p,
- hns3_nic_test_strs[HNAE3_LOOP_PHY],
+ memcpy(p, hns3_nic_test_strs[HNAE3_LOOP_PHY],
ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN;
}
@@ -692,10 +697,8 @@ static void hclge_get_stats(struct hnae3_handle *handle, u64 *data)
struct hclge_dev *hdev = vport->back;
u64 *p;
- p = hclge_comm_get_stats(&hdev->hw_stats.mac_stats,
- g_mac_stats_string,
- ARRAY_SIZE(g_mac_stats_string),
- data);
+ p = hclge_comm_get_stats(&hdev->hw_stats.mac_stats, g_mac_stats_string,
+ ARRAY_SIZE(g_mac_stats_string), data);
p = hclge_tqps_get_stats(handle, p);
}
@@ -726,6 +729,8 @@ static int hclge_parse_func_status(struct hclge_dev *hdev,
static int hclge_query_function_status(struct hclge_dev *hdev)
{
+#define HCLGE_QUERY_MAX_CNT 5
+
struct hclge_func_status_cmd *req;
struct hclge_desc desc;
int timeout = 0;
@@ -738,9 +743,7 @@ static int hclge_query_function_status(struct hclge_dev *hdev)
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
- "query function status failed %d.\n",
- ret);
-
+ "query function status failed %d.\n", ret);
return ret;
}
@@ -748,7 +751,7 @@ static int hclge_query_function_status(struct hclge_dev *hdev)
if (req->pf_state)
break;
usleep_range(1000, 2000);
- } while (timeout++ < 5);
+ } while (timeout++ < HCLGE_QUERY_MAX_CNT);
ret = hclge_parse_func_status(hdev, req);
@@ -800,7 +803,7 @@ static int hclge_query_pf_resource(struct hclge_dev *hdev)
/* PF should have NIC vectors and Roce vectors,
* NIC vectors are queued before Roce vectors.
*/
- hdev->num_msi = hdev->num_roce_msi +
+ hdev->num_msi = hdev->num_roce_msi +
hdev->roce_base_msix_offset;
} else {
hdev->num_msi =
@@ -1058,6 +1061,7 @@ static void hclge_parse_copper_link_mode(struct hclge_dev *hdev,
linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, supported);
linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT, supported);
linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, supported);
+ linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, supported);
}
static void hclge_parse_link_mode(struct hclge_dev *hdev, u8 speed_ability)
@@ -1076,7 +1080,7 @@ static void hclge_parse_cfg(struct hclge_cfg *cfg, struct hclge_desc *desc)
struct hclge_cfg_param_cmd *req;
u64 mac_addr_tmp_high;
u64 mac_addr_tmp;
- int i;
+ unsigned int i;
req = (struct hclge_cfg_param_cmd *)desc[0].data;
@@ -1138,7 +1142,8 @@ static int hclge_get_cfg(struct hclge_dev *hdev, struct hclge_cfg *hcfg)
{
struct hclge_desc desc[HCLGE_PF_CFG_DESC_NUM];
struct hclge_cfg_param_cmd *req;
- int i, ret;
+ unsigned int i;
+ int ret;
for (i = 0; i < HCLGE_PF_CFG_DESC_NUM; i++) {
u32 offset = 0;
@@ -1204,7 +1209,8 @@ static void hclge_init_kdump_kernel_config(struct hclge_dev *hdev)
static int hclge_configure(struct hclge_dev *hdev)
{
struct hclge_cfg cfg;
- int ret, i;
+ unsigned int i;
+ int ret;
ret = hclge_get_cfg(hdev, &cfg);
if (ret) {
@@ -1226,8 +1232,10 @@ static int hclge_configure(struct hclge_dev *hdev)
hdev->tm_info.hw_pfc_map = 0;
hdev->wanted_umv_size = cfg.umv_space;
- if (hnae3_dev_fd_supported(hdev))
+ if (hnae3_dev_fd_supported(hdev)) {
hdev->fd_en = true;
+ hdev->fd_active_type = HCLGE_FD_RULE_NONE;
+ }
ret = hclge_parse_speed(cfg.default_speed, &hdev->hw.mac.speed);
if (ret) {
@@ -1265,8 +1273,8 @@ static int hclge_configure(struct hclge_dev *hdev)
return ret;
}
-static int hclge_config_tso(struct hclge_dev *hdev, int tso_mss_min,
- int tso_mss_max)
+static int hclge_config_tso(struct hclge_dev *hdev, unsigned int tso_mss_min,
+ unsigned int tso_mss_max)
{
struct hclge_cfg_tso_status_cmd *req;
struct hclge_desc desc;
@@ -1352,8 +1360,9 @@ static int hclge_map_tqps_to_func(struct hclge_dev *hdev, u16 func_id,
req = (struct hclge_tqp_map_cmd *)desc.data;
req->tqp_id = cpu_to_le16(tqp_pid);
req->tqp_vf = func_id;
- req->tqp_flag = !is_pf << HCLGE_TQP_MAP_TYPE_B |
- 1 << HCLGE_TQP_MAP_EN_B;
+ req->tqp_flag = 1U << HCLGE_TQP_MAP_EN_B;
+ if (!is_pf)
+ req->tqp_flag |= 1U << HCLGE_TQP_MAP_TYPE_B;
req->tqp_vid = cpu_to_le16(tqp_vid);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
@@ -1457,11 +1466,6 @@ static int hclge_map_tqp(struct hclge_dev *hdev)
return 0;
}
-static void hclge_unic_setup(struct hclge_vport *vport, u16 num_tqps)
-{
- /* this would be initialized later */
-}
-
static int hclge_vport_setup(struct hclge_vport *vport, u16 num_tqps)
{
struct hnae3_handle *nic = &vport->nic;
@@ -1472,20 +1476,12 @@ static int hclge_vport_setup(struct hclge_vport *vport, u16 num_tqps)
nic->ae_algo = &ae_algo;
nic->numa_node_mask = hdev->numa_node_mask;
- if (hdev->ae_dev->dev_type == HNAE3_DEV_KNIC) {
- ret = hclge_knic_setup(vport, num_tqps,
- hdev->num_tx_desc, hdev->num_rx_desc);
-
- if (ret) {
- dev_err(&hdev->pdev->dev, "knic setup failed %d\n",
- ret);
- return ret;
- }
- } else {
- hclge_unic_setup(vport, num_tqps);
- }
+ ret = hclge_knic_setup(vport, num_tqps,
+ hdev->num_tx_desc, hdev->num_rx_desc);
+ if (ret)
+ dev_err(&hdev->pdev->dev, "knic setup failed %d\n", ret);
- return 0;
+ return ret;
}
static int hclge_alloc_vport(struct hclge_dev *hdev)
@@ -1591,7 +1587,8 @@ static int hclge_tx_buffer_alloc(struct hclge_dev *hdev,
static u32 hclge_get_tc_num(struct hclge_dev *hdev)
{
- int i, cnt = 0;
+ unsigned int i;
+ u32 cnt = 0;
for (i = 0; i < HCLGE_MAX_TC_NUM; i++)
if (hdev->hw_tc_map & BIT(i))
@@ -1604,7 +1601,8 @@ static int hclge_get_pfc_priv_num(struct hclge_dev *hdev,
struct hclge_pkt_buf_alloc *buf_alloc)
{
struct hclge_priv_buf *priv;
- int i, cnt = 0;
+ unsigned int i;
+ int cnt = 0;
for (i = 0; i < HCLGE_MAX_TC_NUM; i++) {
priv = &buf_alloc->priv_buf[i];
@@ -1621,7 +1619,8 @@ static int hclge_get_no_pfc_priv_num(struct hclge_dev *hdev,
struct hclge_pkt_buf_alloc *buf_alloc)
{
struct hclge_priv_buf *priv;
- int i, cnt = 0;
+ unsigned int i;
+ int cnt = 0;
for (i = 0; i < HCLGE_MAX_TC_NUM; i++) {
priv = &buf_alloc->priv_buf[i];
@@ -1671,7 +1670,8 @@ static bool hclge_is_rx_buf_ok(struct hclge_dev *hdev,
aligned_mps = roundup(hdev->mps, HCLGE_BUF_SIZE_UNIT);
if (hnae3_dev_dcb_supported(hdev))
- shared_buf_min = 2 * aligned_mps + hdev->dv_buf_size;
+ shared_buf_min = HCLGE_BUF_MUL_BY * aligned_mps +
+ hdev->dv_buf_size;
else
shared_buf_min = aligned_mps + HCLGE_NON_DCB_ADDITIONAL_BUF
+ hdev->dv_buf_size;
@@ -1689,7 +1689,8 @@ static bool hclge_is_rx_buf_ok(struct hclge_dev *hdev,
if (hnae3_dev_dcb_supported(hdev)) {
buf_alloc->s_buf.self.high = shared_buf - hdev->dv_buf_size;
buf_alloc->s_buf.self.low = buf_alloc->s_buf.self.high
- - roundup(aligned_mps / 2, HCLGE_BUF_SIZE_UNIT);
+ - roundup(aligned_mps / HCLGE_BUF_DIV_BY,
+ HCLGE_BUF_SIZE_UNIT);
} else {
buf_alloc->s_buf.self.high = aligned_mps +
HCLGE_NON_DCB_ADDITIONAL_BUF;
@@ -1697,14 +1698,18 @@ static bool hclge_is_rx_buf_ok(struct hclge_dev *hdev,
}
if (hnae3_dev_dcb_supported(hdev)) {
+ hi_thrd = shared_buf - hdev->dv_buf_size;
+
+ if (tc_num <= NEED_RESERVE_TC_NUM)
+ hi_thrd = hi_thrd * BUF_RESERVE_PERCENT
+ / BUF_MAX_PERCENT;
+
if (tc_num)
- hi_thrd = (shared_buf - hdev->dv_buf_size) / tc_num;
- else
- hi_thrd = shared_buf - hdev->dv_buf_size;
+ hi_thrd = hi_thrd / tc_num;
- hi_thrd = max_t(u32, hi_thrd, 2 * aligned_mps);
+ hi_thrd = max_t(u32, hi_thrd, HCLGE_BUF_MUL_BY * aligned_mps);
hi_thrd = rounddown(hi_thrd, HCLGE_BUF_SIZE_UNIT);
- lo_thrd = hi_thrd - aligned_mps / 2;
+ lo_thrd = hi_thrd - aligned_mps / HCLGE_BUF_DIV_BY;
} else {
hi_thrd = aligned_mps + HCLGE_NON_DCB_ADDITIONAL_BUF;
lo_thrd = aligned_mps;
@@ -1749,7 +1754,7 @@ static bool hclge_rx_buf_calc_all(struct hclge_dev *hdev, bool max,
{
u32 rx_all = hdev->pkt_buf_size - hclge_get_tx_buff_alloced(buf_alloc);
u32 aligned_mps = round_up(hdev->mps, HCLGE_BUF_SIZE_UNIT);
- int i;
+ unsigned int i;
for (i = 0; i < HCLGE_MAX_TC_NUM; i++) {
struct hclge_priv_buf *priv = &buf_alloc->priv_buf[i];
@@ -1765,12 +1770,13 @@ static bool hclge_rx_buf_calc_all(struct hclge_dev *hdev, bool max,
priv->enable = 1;
if (hdev->tm_info.hw_pfc_map & BIT(i)) {
- priv->wl.low = max ? aligned_mps : 256;
+ priv->wl.low = max ? aligned_mps : HCLGE_BUF_SIZE_UNIT;
priv->wl.high = roundup(priv->wl.low + aligned_mps,
HCLGE_BUF_SIZE_UNIT);
} else {
priv->wl.low = 0;
- priv->wl.high = max ? (aligned_mps * 2) : aligned_mps;
+ priv->wl.high = max ? (aligned_mps * HCLGE_BUF_MUL_BY) :
+ aligned_mps;
}
priv->buf_size = priv->wl.high + hdev->dv_buf_size;
@@ -1789,9 +1795,10 @@ static bool hclge_drop_nopfc_buf_till_fit(struct hclge_dev *hdev,
/* let the last to be cleared first */
for (i = HCLGE_MAX_TC_NUM - 1; i >= 0; i--) {
struct hclge_priv_buf *priv = &buf_alloc->priv_buf[i];
+ unsigned int mask = BIT((unsigned int)i);
- if (hdev->hw_tc_map & BIT(i) &&
- !(hdev->tm_info.hw_pfc_map & BIT(i))) {
+ if (hdev->hw_tc_map & mask &&
+ !(hdev->tm_info.hw_pfc_map & mask)) {
/* Clear the no pfc TC private buffer */
priv->wl.low = 0;
priv->wl.high = 0;
@@ -1818,9 +1825,10 @@ static bool hclge_drop_pfc_buf_till_fit(struct hclge_dev *hdev,
/* let the last to be cleared first */
for (i = HCLGE_MAX_TC_NUM - 1; i >= 0; i--) {
struct hclge_priv_buf *priv = &buf_alloc->priv_buf[i];
+ unsigned int mask = BIT((unsigned int)i);
- if (hdev->hw_tc_map & BIT(i) &&
- hdev->tm_info.hw_pfc_map & BIT(i)) {
+ if (hdev->hw_tc_map & mask &&
+ hdev->tm_info.hw_pfc_map & mask) {
/* Reduce the number of pfc TC with private buffer */
priv->wl.low = 0;
priv->enable = 0;
@@ -1837,6 +1845,55 @@ static bool hclge_drop_pfc_buf_till_fit(struct hclge_dev *hdev,
return hclge_is_rx_buf_ok(hdev, buf_alloc, rx_all);
}
+static int hclge_only_alloc_priv_buff(struct hclge_dev *hdev,
+ struct hclge_pkt_buf_alloc *buf_alloc)
+{
+#define COMPENSATE_BUFFER 0x3C00
+#define COMPENSATE_HALF_MPS_NUM 5
+#define PRIV_WL_GAP 0x1800
+
+ u32 rx_priv = hdev->pkt_buf_size - hclge_get_tx_buff_alloced(buf_alloc);
+ u32 tc_num = hclge_get_tc_num(hdev);
+ u32 half_mps = hdev->mps >> 1;
+ u32 min_rx_priv;
+ unsigned int i;
+
+ if (tc_num)
+ rx_priv = rx_priv / tc_num;
+
+ if (tc_num <= NEED_RESERVE_TC_NUM)
+ rx_priv = rx_priv * BUF_RESERVE_PERCENT / BUF_MAX_PERCENT;
+
+ min_rx_priv = hdev->dv_buf_size + COMPENSATE_BUFFER +
+ COMPENSATE_HALF_MPS_NUM * half_mps;
+ min_rx_priv = round_up(min_rx_priv, HCLGE_BUF_SIZE_UNIT);
+ rx_priv = round_down(rx_priv, HCLGE_BUF_SIZE_UNIT);
+
+ if (rx_priv < min_rx_priv)
+ return false;
+
+ for (i = 0; i < HCLGE_MAX_TC_NUM; i++) {
+ struct hclge_priv_buf *priv = &buf_alloc->priv_buf[i];
+
+ priv->enable = 0;
+ priv->wl.low = 0;
+ priv->wl.high = 0;
+ priv->buf_size = 0;
+
+ if (!(hdev->hw_tc_map & BIT(i)))
+ continue;
+
+ priv->enable = 1;
+ priv->buf_size = rx_priv;
+ priv->wl.high = rx_priv - hdev->dv_buf_size;
+ priv->wl.low = priv->wl.high - PRIV_WL_GAP;
+ }
+
+ buf_alloc->s_buf.buf_size = 0;
+
+ return true;
+}
+
/* hclge_rx_buffer_calc: calculate the rx private buffer size for all TCs
* @hdev: pointer to struct hclge_dev
* @buf_alloc: pointer to buffer calculation data
@@ -1856,6 +1913,9 @@ static int hclge_rx_buffer_calc(struct hclge_dev *hdev,
return 0;
}
+ if (hclge_only_alloc_priv_buff(hdev, buf_alloc))
+ return 0;
+
if (hclge_rx_buf_calc_all(hdev, true, buf_alloc))
return 0;
@@ -2153,7 +2213,6 @@ static int hclge_init_msi(struct hclge_dev *hdev)
static u8 hclge_check_speed_dup(u8 duplex, int speed)
{
-
if (!(speed == HCLGE_MAC_SPEED_10M || speed == HCLGE_MAC_SPEED_100M))
duplex = HCLGE_MAC_FULL;
@@ -2171,7 +2230,8 @@ static int hclge_cfg_mac_speed_dup_hw(struct hclge_dev *hdev, int speed,
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CONFIG_SPEED_DUP, false);
- hnae3_set_bit(req->speed_dup, HCLGE_CFG_DUPLEX_B, !!duplex);
+ if (duplex)
+ hnae3_set_bit(req->speed_dup, HCLGE_CFG_DUPLEX_B, 1);
switch (speed) {
case HCLGE_MAC_SPEED_10M:
@@ -2261,7 +2321,8 @@ static int hclge_set_autoneg_en(struct hclge_dev *hdev, bool enable)
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CONFIG_AN_MODE, false);
req = (struct hclge_config_auto_neg_cmd *)desc.data;
- hnae3_set_bit(flag, HCLGE_MAC_CFG_AN_EN_B, !!enable);
+ if (enable)
+ hnae3_set_bit(flag, HCLGE_MAC_CFG_AN_EN_B, 1U);
req->cfg_an_cmd_flag = cpu_to_le32(flag);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
@@ -2316,6 +2377,17 @@ static int hclge_restart_autoneg(struct hnae3_handle *handle)
return hclge_notify_client(hdev, HNAE3_UP_CLIENT);
}
+static int hclge_halt_autoneg(struct hnae3_handle *handle, bool halt)
+{
+ struct hclge_vport *vport = hclge_get_vport(handle);
+ struct hclge_dev *hdev = vport->back;
+
+ if (hdev->hw.mac.support_autoneg && hdev->hw.mac.autoneg)
+ return hclge_set_autoneg_en(hdev, !halt);
+
+ return 0;
+}
+
static int hclge_set_fec_hw(struct hclge_dev *hdev, u32 fec_mode)
{
struct hclge_config_fec_cmd *req;
@@ -2389,6 +2461,15 @@ static int hclge_mac_init(struct hclge_dev *hdev)
return ret;
}
+ if (hdev->hw.mac.support_autoneg) {
+ ret = hclge_set_autoneg_en(hdev, hdev->hw.mac.autoneg);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "Config mac autoneg fail ret=%d\n", ret);
+ return ret;
+ }
+ }
+
mac->link = 0;
if (mac->user_fec_mode & BIT(HNAE3_FEC_USER_DEF)) {
@@ -2423,7 +2504,8 @@ static void hclge_mbx_task_schedule(struct hclge_dev *hdev)
static void hclge_reset_task_schedule(struct hclge_dev *hdev)
{
- if (!test_and_set_bit(HCLGE_STATE_RST_SERVICE_SCHED, &hdev->state))
+ if (!test_bit(HCLGE_STATE_REMOVING, &hdev->state) &&
+ !test_and_set_bit(HCLGE_STATE_RST_SERVICE_SCHED, &hdev->state))
schedule_work(&hdev->rst_service_task);
}
@@ -2458,7 +2540,7 @@ static int hclge_get_mac_link_status(struct hclge_dev *hdev)
static int hclge_get_mac_phy_link(struct hclge_dev *hdev)
{
- int mac_state;
+ unsigned int mac_state;
int link_stat;
if (test_bit(HCLGE_STATE_DOWN, &hdev->state))
@@ -2508,6 +2590,9 @@ static void hclge_update_link_status(struct hclge_dev *hdev)
static void hclge_update_port_capability(struct hclge_mac *mac)
{
+ /* update fec ability by speed */
+ hclge_convert_setting_fec(mac);
+
/* firmware can not identify back plane type, the media type
* read from configuration can help deal it
*/
@@ -2529,7 +2614,7 @@ static void hclge_update_port_capability(struct hclge_mac *mac)
static int hclge_get_sfp_speed(struct hclge_dev *hdev, u32 *speed)
{
- struct hclge_sfp_info_cmd *resp = NULL;
+ struct hclge_sfp_info_cmd *resp;
struct hclge_desc desc;
int ret;
@@ -2580,6 +2665,11 @@ static int hclge_get_sfp_info(struct hclge_dev *hdev, struct hclge_mac *mac)
mac->speed_ability = le32_to_cpu(resp->speed_ability);
mac->autoneg = resp->autoneg;
mac->support_autoneg = resp->autoneg_ability;
+ mac->speed_type = QUERY_ACTIVE_SPEED;
+ if (!resp->active_fec)
+ mac->fec_mode = 0;
+ else
+ mac->fec_mode = BIT(resp->active_fec);
} else {
mac->speed_type = QUERY_SFP_SPEED;
}
@@ -2645,6 +2735,7 @@ static void hclge_service_timer(struct timer_list *t)
mod_timer(&hdev->service_timer, jiffies + HZ);
hdev->hw_stats.stats_timer++;
+ hdev->fd_arfs_expire_timer++;
hclge_task_schedule(hdev);
}
@@ -2693,19 +2784,11 @@ static u32 hclge_check_event_cause(struct hclge_dev *hdev, u32 *clearval)
return HCLGE_VECTOR0_EVENT_RST;
}
- if (BIT(HCLGE_VECTOR0_CORERESET_INT_B) & rst_src_reg) {
- dev_info(&hdev->pdev->dev, "core reset interrupt\n");
- set_bit(HCLGE_STATE_CMD_DISABLE, &hdev->state);
- set_bit(HNAE3_CORE_RESET, &hdev->reset_pending);
- *clearval = BIT(HCLGE_VECTOR0_CORERESET_INT_B);
- hdev->rst_stats.core_rst_cnt++;
- return HCLGE_VECTOR0_EVENT_RST;
- }
-
/* check for vector0 msix event source */
if (msix_src_reg & HCLGE_VECTOR0_REG_MSIX_MASK) {
- dev_dbg(&hdev->pdev->dev, "received event 0x%x\n",
- msix_src_reg);
+ dev_info(&hdev->pdev->dev, "received event 0x%x\n",
+ msix_src_reg);
+ *clearval = msix_src_reg;
return HCLGE_VECTOR0_EVENT_ERR;
}
@@ -2717,8 +2800,11 @@ static u32 hclge_check_event_cause(struct hclge_dev *hdev, u32 *clearval)
}
/* print other vector0 event source */
- dev_dbg(&hdev->pdev->dev, "cmdq_src_reg:0x%x, msix_src_reg:0x%x\n",
- cmdq_src_reg, msix_src_reg);
+ dev_info(&hdev->pdev->dev,
+ "CMDQ INT status:0x%x, other INT status:0x%x\n",
+ cmdq_src_reg, msix_src_reg);
+ *clearval = msix_src_reg;
+
return HCLGE_VECTOR0_EVENT_OTHER;
}
@@ -2754,8 +2840,8 @@ static void hclge_enable_vector(struct hclge_misc_vector *vector, bool enable)
static irqreturn_t hclge_misc_irq_handle(int irq, void *data)
{
struct hclge_dev *hdev = data;
+ u32 clearval = 0;
u32 event_cause;
- u32 clearval;
hclge_enable_vector(&hdev->misc_vector, false);
event_cause = hclge_check_event_cause(hdev, &clearval);
@@ -2797,7 +2883,8 @@ static irqreturn_t hclge_misc_irq_handle(int irq, void *data)
}
/* clear the source of interrupt if it is not cause by reset */
- if (event_cause == HCLGE_VECTOR0_EVENT_MBX) {
+ if (!clearval ||
+ event_cause == HCLGE_VECTOR0_EVENT_MBX) {
hclge_clear_event_cause(hdev, event_cause, clearval);
hclge_enable_vector(&hdev->misc_vector, true);
}
@@ -2861,6 +2948,9 @@ int hclge_notify_client(struct hclge_dev *hdev,
struct hnae3_client *client = hdev->nic_client;
u16 i;
+ if (!test_bit(HCLGE_STATE_NIC_REGISTERED, &hdev->state) || !client)
+ return 0;
+
if (!client->ops->reset_notify)
return -EOPNOTSUPP;
@@ -2886,7 +2976,7 @@ static int hclge_notify_roce_client(struct hclge_dev *hdev,
int ret = 0;
u16 i;
- if (!client)
+ if (!test_bit(HCLGE_STATE_ROCE_REGISTERED, &hdev->state) || !client)
return 0;
if (!client->ops->reset_notify)
@@ -2923,10 +3013,6 @@ static int hclge_reset_wait(struct hclge_dev *hdev)
reg = HCLGE_GLOBAL_RESET_REG;
reg_bit = HCLGE_GLOBAL_RESET_BIT;
break;
- case HNAE3_CORE_RESET:
- reg = HCLGE_GLOBAL_RESET_REG;
- reg_bit = HCLGE_CORE_RESET_BIT;
- break;
case HNAE3_FUNC_RESET:
reg = HCLGE_FUN_RST_ING;
reg_bit = HCLGE_FUN_RST_ING_B;
@@ -3058,12 +3144,6 @@ static void hclge_do_reset(struct hclge_dev *hdev)
hclge_write_dev(&hdev->hw, HCLGE_GLOBAL_RESET_REG, val);
dev_info(&pdev->dev, "Global Reset requested\n");
break;
- case HNAE3_CORE_RESET:
- val = hclge_read_dev(&hdev->hw, HCLGE_GLOBAL_RESET_REG);
- hnae3_set_bit(val, HCLGE_CORE_RESET_BIT, 1);
- hclge_write_dev(&hdev->hw, HCLGE_GLOBAL_RESET_REG, val);
- dev_info(&pdev->dev, "Core Reset requested\n");
- break;
case HNAE3_FUNC_RESET:
dev_info(&pdev->dev, "PF Reset requested\n");
/* schedule again to check later */
@@ -3083,10 +3163,11 @@ static void hclge_do_reset(struct hclge_dev *hdev)
}
}
-static enum hnae3_reset_type hclge_get_reset_level(struct hclge_dev *hdev,
+static enum hnae3_reset_type hclge_get_reset_level(struct hnae3_ae_dev *ae_dev,
unsigned long *addr)
{
enum hnae3_reset_type rst_level = HNAE3_NONE_RESET;
+ struct hclge_dev *hdev = ae_dev->priv;
/* first, resolve any unknown reset type to the known type(s) */
if (test_bit(HNAE3_UNKNOWN_RESET, addr)) {
@@ -3110,16 +3191,10 @@ static enum hnae3_reset_type hclge_get_reset_level(struct hclge_dev *hdev,
rst_level = HNAE3_IMP_RESET;
clear_bit(HNAE3_IMP_RESET, addr);
clear_bit(HNAE3_GLOBAL_RESET, addr);
- clear_bit(HNAE3_CORE_RESET, addr);
clear_bit(HNAE3_FUNC_RESET, addr);
} else if (test_bit(HNAE3_GLOBAL_RESET, addr)) {
rst_level = HNAE3_GLOBAL_RESET;
clear_bit(HNAE3_GLOBAL_RESET, addr);
- clear_bit(HNAE3_CORE_RESET, addr);
- clear_bit(HNAE3_FUNC_RESET, addr);
- } else if (test_bit(HNAE3_CORE_RESET, addr)) {
- rst_level = HNAE3_CORE_RESET;
- clear_bit(HNAE3_CORE_RESET, addr);
clear_bit(HNAE3_FUNC_RESET, addr);
} else if (test_bit(HNAE3_FUNC_RESET, addr)) {
rst_level = HNAE3_FUNC_RESET;
@@ -3147,9 +3222,6 @@ static void hclge_clear_reset_cause(struct hclge_dev *hdev)
case HNAE3_GLOBAL_RESET:
clearval = BIT(HCLGE_VECTOR0_GLOBALRESET_INT_B);
break;
- case HNAE3_CORE_RESET:
- clearval = BIT(HCLGE_VECTOR0_CORERESET_INT_B);
- break;
default:
break;
}
@@ -3180,6 +3252,8 @@ static int hclge_reset_prepare_down(struct hclge_dev *hdev)
static int hclge_reset_prepare_wait(struct hclge_dev *hdev)
{
+#define HCLGE_RESET_SYNC_TIME 100
+
u32 reg_val;
int ret = 0;
@@ -3188,7 +3262,7 @@ static int hclge_reset_prepare_wait(struct hclge_dev *hdev)
/* There is no mechanism for PF to know if VF has stopped IO
* for now, just wait 100 ms for VF to stop IO
*/
- msleep(100);
+ msleep(HCLGE_RESET_SYNC_TIME);
ret = hclge_func_reset_cmd(hdev, 0);
if (ret) {
dev_err(&hdev->pdev->dev,
@@ -3208,7 +3282,7 @@ static int hclge_reset_prepare_wait(struct hclge_dev *hdev)
/* There is no mechanism for PF to know if VF has stopped IO
* for now, just wait 100 ms for VF to stop IO
*/
- msleep(100);
+ msleep(HCLGE_RESET_SYNC_TIME);
set_bit(HCLGE_STATE_CMD_DISABLE, &hdev->state);
set_bit(HNAE3_FLR_DOWN, &hdev->flr_state);
hdev->rst_stats.flr_rst_cnt++;
@@ -3222,6 +3296,10 @@ static int hclge_reset_prepare_wait(struct hclge_dev *hdev)
break;
}
+ /* inform hardware that preparatory work is done */
+ msleep(HCLGE_RESET_SYNC_TIME);
+ hclge_write_dev(&hdev->hw, HCLGE_NIC_CSQ_DEPTH_REG,
+ HCLGE_NIC_CMQ_ENABLE);
dev_info(&hdev->pdev->dev, "prepare wait ok\n");
return ret;
@@ -3230,7 +3308,6 @@ static int hclge_reset_prepare_wait(struct hclge_dev *hdev)
static bool hclge_reset_err_handle(struct hclge_dev *hdev, bool is_timeout)
{
#define MAX_RESET_FAIL_CNT 5
-#define RESET_UPGRADE_DELAY_SEC 10
if (hdev->reset_pending) {
dev_info(&hdev->pdev->dev, "Reset pending %lu\n",
@@ -3254,8 +3331,9 @@ static bool hclge_reset_err_handle(struct hclge_dev *hdev, bool is_timeout)
dev_info(&hdev->pdev->dev, "Upgrade reset level\n");
hclge_clear_reset_cause(hdev);
+ set_bit(HNAE3_GLOBAL_RESET, &hdev->default_reset_request);
mod_timer(&hdev->reset_timer,
- jiffies + RESET_UPGRADE_DELAY_SEC * HZ);
+ jiffies + HCLGE_RESET_INTERVAL);
return false;
}
@@ -3282,6 +3360,25 @@ static int hclge_reset_prepare_up(struct hclge_dev *hdev)
return ret;
}
+static int hclge_reset_stack(struct hclge_dev *hdev)
+{
+ int ret;
+
+ ret = hclge_notify_client(hdev, HNAE3_UNINIT_CLIENT);
+ if (ret)
+ return ret;
+
+ ret = hclge_reset_ae_dev(hdev->ae_dev);
+ if (ret)
+ return ret;
+
+ ret = hclge_notify_client(hdev, HNAE3_INIT_CLIENT);
+ if (ret)
+ return ret;
+
+ return hclge_notify_client(hdev, HNAE3_RESTORE_CLIENT);
+}
+
static void hclge_reset(struct hclge_dev *hdev)
{
struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev);
@@ -3325,19 +3422,8 @@ static void hclge_reset(struct hclge_dev *hdev)
goto err_reset;
rtnl_lock();
- ret = hclge_notify_client(hdev, HNAE3_UNINIT_CLIENT);
- if (ret)
- goto err_reset_lock;
- ret = hclge_reset_ae_dev(hdev->ae_dev);
- if (ret)
- goto err_reset_lock;
-
- ret = hclge_notify_client(hdev, HNAE3_INIT_CLIENT);
- if (ret)
- goto err_reset_lock;
-
- ret = hclge_notify_client(hdev, HNAE3_RESTORE_CLIENT);
+ ret = hclge_reset_stack(hdev);
if (ret)
goto err_reset_lock;
@@ -3347,16 +3433,23 @@ static void hclge_reset(struct hclge_dev *hdev)
if (ret)
goto err_reset_lock;
+ rtnl_unlock();
+
+ ret = hclge_notify_roce_client(hdev, HNAE3_INIT_CLIENT);
+ /* ignore RoCE notify error if it fails HCLGE_RESET_MAX_FAIL_CNT - 1
+ * times
+ */
+ if (ret && hdev->reset_fail_cnt < HCLGE_RESET_MAX_FAIL_CNT - 1)
+ goto err_reset;
+
+ rtnl_lock();
+
ret = hclge_notify_client(hdev, HNAE3_UP_CLIENT);
if (ret)
goto err_reset_lock;
rtnl_unlock();
- ret = hclge_notify_roce_client(hdev, HNAE3_INIT_CLIENT);
- if (ret)
- goto err_reset;
-
ret = hclge_notify_roce_client(hdev, HNAE3_UP_CLIENT);
if (ret)
goto err_reset;
@@ -3399,11 +3492,12 @@ static void hclge_reset_event(struct pci_dev *pdev, struct hnae3_handle *handle)
if (!handle)
handle = &hdev->vport[0].nic;
- if (time_before(jiffies, (hdev->last_reset_time + 3 * HZ)))
+ if (time_before(jiffies, (hdev->last_reset_time +
+ HCLGE_RESET_INTERVAL)))
return;
else if (hdev->default_reset_request)
hdev->reset_level =
- hclge_get_reset_level(hdev,
+ hclge_get_reset_level(ae_dev,
&hdev->default_reset_request);
else if (time_after(jiffies, (hdev->last_reset_time + 4 * 5 * HZ)))
hdev->reset_level = HNAE3_FUNC_RESET;
@@ -3432,13 +3526,14 @@ static void hclge_reset_timer(struct timer_list *t)
struct hclge_dev *hdev = from_timer(hdev, t, reset_timer);
dev_info(&hdev->pdev->dev,
- "triggering global reset in reset timer\n");
- set_bit(HNAE3_GLOBAL_RESET, &hdev->default_reset_request);
+ "triggering reset in reset timer\n");
hclge_reset_event(hdev->pdev, NULL);
}
static void hclge_reset_subtask(struct hclge_dev *hdev)
{
+ struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev);
+
/* check if there is any ongoing reset in the hardware. This status can
* be checked from reset_pending. If there is then, we need to wait for
* hardware to complete reset.
@@ -3449,12 +3544,12 @@ static void hclge_reset_subtask(struct hclge_dev *hdev)
* now.
*/
hdev->last_reset_time = jiffies;
- hdev->reset_type = hclge_get_reset_level(hdev, &hdev->reset_pending);
+ hdev->reset_type = hclge_get_reset_level(ae_dev, &hdev->reset_pending);
if (hdev->reset_type != HNAE3_NONE_RESET)
hclge_reset(hdev);
/* check if we got any *new* reset requests to be honored */
- hdev->reset_type = hclge_get_reset_level(hdev, &hdev->reset_request);
+ hdev->reset_type = hclge_get_reset_level(ae_dev, &hdev->reset_request);
if (hdev->reset_type != HNAE3_NONE_RESET)
hclge_do_reset(hdev);
@@ -3521,6 +3616,11 @@ static void hclge_service_task(struct work_struct *work)
hclge_update_port_info(hdev);
hclge_update_link_status(hdev);
hclge_update_vport_alive(hdev);
+ hclge_sync_vlan_filter(hdev);
+ if (hdev->fd_arfs_expire_timer >= HCLGE_FD_ARFS_EXPIRE_TIMER_INTERVAL) {
+ hclge_rfs_filter_expire(hdev);
+ hdev->fd_arfs_expire_timer = 0;
+ }
hclge_service_complete(hdev);
}
@@ -3614,29 +3714,28 @@ static int hclge_set_rss_algo_key(struct hclge_dev *hdev,
const u8 hfunc, const u8 *key)
{
struct hclge_rss_config_cmd *req;
+ unsigned int key_offset = 0;
struct hclge_desc desc;
- int key_offset;
+ int key_counts;
int key_size;
int ret;
+ key_counts = HCLGE_RSS_KEY_SIZE;
req = (struct hclge_rss_config_cmd *)desc.data;
- for (key_offset = 0; key_offset < 3; key_offset++) {
+ while (key_counts) {
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_RSS_GENERIC_CONFIG,
false);
req->hash_config |= (hfunc & HCLGE_RSS_HASH_ALGO_MASK);
req->hash_config |= (key_offset << HCLGE_RSS_HASH_KEY_OFFSET_B);
- if (key_offset == 2)
- key_size =
- HCLGE_RSS_KEY_SIZE - HCLGE_RSS_HASH_KEY_NUM * 2;
- else
- key_size = HCLGE_RSS_HASH_KEY_NUM;
-
+ key_size = min(HCLGE_RSS_HASH_KEY_NUM, key_counts);
memcpy(req->hash_key,
key + key_offset * HCLGE_RSS_HASH_KEY_NUM, key_size);
+ key_counts -= key_size;
+ key_offset++;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
@@ -3995,13 +4094,14 @@ int hclge_rss_init_hw(struct hclge_dev *hdev)
struct hclge_vport *vport = hdev->vport;
u8 *rss_indir = vport[0].rss_indirection_tbl;
u16 rss_size = vport[0].alloc_rss_size;
+ u16 tc_offset[HCLGE_MAX_TC_NUM] = {0};
+ u16 tc_size[HCLGE_MAX_TC_NUM] = {0};
u8 *key = vport[0].rss_hash_key;
u8 hfunc = vport[0].rss_algo;
- u16 tc_offset[HCLGE_MAX_TC_NUM];
u16 tc_valid[HCLGE_MAX_TC_NUM];
- u16 tc_size[HCLGE_MAX_TC_NUM];
u16 roundup_size;
- int i, ret;
+ unsigned int i;
+ int ret;
ret = hclge_set_rss_indir_table(hdev, rss_indir);
if (ret)
@@ -4156,8 +4256,7 @@ int hclge_bind_ring_with_vector(struct hclge_vport *vport,
return 0;
}
-static int hclge_map_ring_to_vector(struct hnae3_handle *handle,
- int vector,
+static int hclge_map_ring_to_vector(struct hnae3_handle *handle, int vector,
struct hnae3_ring_chain_node *ring_chain)
{
struct hclge_vport *vport = hclge_get_vport(handle);
@@ -4174,8 +4273,7 @@ static int hclge_map_ring_to_vector(struct hnae3_handle *handle,
return hclge_bind_ring_with_vector(vport, vector_id, true, ring_chain);
}
-static int hclge_unmap_ring_frm_vector(struct hnae3_handle *handle,
- int vector,
+static int hclge_unmap_ring_frm_vector(struct hnae3_handle *handle, int vector,
struct hnae3_ring_chain_node *ring_chain)
{
struct hclge_vport *vport = hclge_get_vport(handle);
@@ -4196,8 +4294,7 @@ static int hclge_unmap_ring_frm_vector(struct hnae3_handle *handle,
if (ret)
dev_err(&handle->pdev->dev,
"Unmap ring from vector fail. vectorid=%d, ret =%d\n",
- vector_id,
- ret);
+ vector_id, ret);
return ret;
}
@@ -4503,19 +4600,19 @@ static bool hclge_fd_convert_tuple(u32 tuple_bit, u8 *key_x, u8 *key_y,
case 0:
return false;
case BIT(INNER_DST_MAC):
- for (i = 0; i < 6; i++) {
- calc_x(key_x[5 - i], rule->tuples.dst_mac[i],
+ for (i = 0; i < ETH_ALEN; i++) {
+ calc_x(key_x[ETH_ALEN - 1 - i], rule->tuples.dst_mac[i],
rule->tuples_mask.dst_mac[i]);
- calc_y(key_y[5 - i], rule->tuples.dst_mac[i],
+ calc_y(key_y[ETH_ALEN - 1 - i], rule->tuples.dst_mac[i],
rule->tuples_mask.dst_mac[i]);
}
return true;
case BIT(INNER_SRC_MAC):
- for (i = 0; i < 6; i++) {
- calc_x(key_x[5 - i], rule->tuples.src_mac[i],
+ for (i = 0; i < ETH_ALEN; i++) {
+ calc_x(key_x[ETH_ALEN - 1 - i], rule->tuples.src_mac[i],
rule->tuples.src_mac[i]);
- calc_y(key_y[5 - i], rule->tuples.src_mac[i],
+ calc_y(key_y[ETH_ALEN - 1 - i], rule->tuples.src_mac[i],
rule->tuples.src_mac[i]);
}
@@ -4551,19 +4648,19 @@ static bool hclge_fd_convert_tuple(u32 tuple_bit, u8 *key_x, u8 *key_y,
return true;
case BIT(INNER_SRC_IP):
- calc_x(tmp_x_l, rule->tuples.src_ip[3],
- rule->tuples_mask.src_ip[3]);
- calc_y(tmp_y_l, rule->tuples.src_ip[3],
- rule->tuples_mask.src_ip[3]);
+ calc_x(tmp_x_l, rule->tuples.src_ip[IPV4_INDEX],
+ rule->tuples_mask.src_ip[IPV4_INDEX]);
+ calc_y(tmp_y_l, rule->tuples.src_ip[IPV4_INDEX],
+ rule->tuples_mask.src_ip[IPV4_INDEX]);
*(__le32 *)key_x = cpu_to_le32(tmp_x_l);
*(__le32 *)key_y = cpu_to_le32(tmp_y_l);
return true;
case BIT(INNER_DST_IP):
- calc_x(tmp_x_l, rule->tuples.dst_ip[3],
- rule->tuples_mask.dst_ip[3]);
- calc_y(tmp_y_l, rule->tuples.dst_ip[3],
- rule->tuples_mask.dst_ip[3]);
+ calc_x(tmp_x_l, rule->tuples.dst_ip[IPV4_INDEX],
+ rule->tuples_mask.dst_ip[IPV4_INDEX]);
+ calc_y(tmp_y_l, rule->tuples.dst_ip[IPV4_INDEX],
+ rule->tuples_mask.dst_ip[IPV4_INDEX]);
*(__le32 *)key_x = cpu_to_le32(tmp_x_l);
*(__le32 *)key_y = cpu_to_le32(tmp_y_l);
@@ -4617,7 +4714,7 @@ static void hclge_fd_convert_meta_data(struct hclge_fd_key_cfg *key_cfg,
{
u32 tuple_bit, meta_data = 0, tmp_x, tmp_y, port_number;
u8 cur_pos = 0, tuple_size, shift_bits;
- int i;
+ unsigned int i;
for (i = 0; i < MAX_META_DATA; i++) {
tuple_size = meta_data_key_info[i].key_length;
@@ -4659,7 +4756,8 @@ static int hclge_config_key(struct hclge_dev *hdev, u8 stage,
struct hclge_fd_key_cfg *key_cfg = &hdev->fd_cfg.key_cfg[stage];
u8 key_x[MAX_KEY_BYTES], key_y[MAX_KEY_BYTES];
u8 *cur_key_x, *cur_key_y;
- int i, ret, tuple_size;
+ unsigned int i;
+ int ret, tuple_size;
u8 meta_data_region;
memset(key_x, 0, sizeof(key_x));
@@ -4812,6 +4910,7 @@ static int hclge_fd_check_spec(struct hclge_dev *hdev,
*unused |= BIT(INNER_SRC_MAC) | BIT(INNER_DST_MAC) |
BIT(INNER_IP_TOS);
+ /* check whether src/dst ip address used */
if (!tcp_ip6_spec->ip6src[0] && !tcp_ip6_spec->ip6src[1] &&
!tcp_ip6_spec->ip6src[2] && !tcp_ip6_spec->ip6src[3])
*unused |= BIT(INNER_SRC_IP);
@@ -4836,6 +4935,7 @@ static int hclge_fd_check_spec(struct hclge_dev *hdev,
BIT(INNER_IP_TOS) | BIT(INNER_SRC_PORT) |
BIT(INNER_DST_PORT);
+ /* check whether src/dst ip address used */
if (!usr_ip6_spec->ip6src[0] && !usr_ip6_spec->ip6src[1] &&
!usr_ip6_spec->ip6src[2] && !usr_ip6_spec->ip6src[3])
*unused |= BIT(INNER_SRC_IP);
@@ -4906,14 +5006,18 @@ static bool hclge_fd_rule_exist(struct hclge_dev *hdev, u16 location)
struct hclge_fd_rule *rule = NULL;
struct hlist_node *node2;
+ spin_lock_bh(&hdev->fd_rule_lock);
hlist_for_each_entry_safe(rule, node2, &hdev->fd_rule_list, rule_node) {
if (rule->location >= location)
break;
}
+ spin_unlock_bh(&hdev->fd_rule_lock);
+
return rule && rule->location == location;
}
+/* make sure being called after lock up with fd_rule_lock */
static int hclge_fd_update_rule_list(struct hclge_dev *hdev,
struct hclge_fd_rule *new_rule,
u16 location,
@@ -4937,9 +5041,13 @@ static int hclge_fd_update_rule_list(struct hclge_dev *hdev,
kfree(rule);
hdev->hclge_fd_rule_num--;
- if (!is_add)
- return 0;
+ if (!is_add) {
+ if (!hdev->hclge_fd_rule_num)
+ hdev->fd_active_type = HCLGE_FD_RULE_NONE;
+ clear_bit(location, hdev->fd_bmap);
+ return 0;
+ }
} else if (!is_add) {
dev_err(&hdev->pdev->dev,
"delete fail, rule %d is inexistent\n",
@@ -4954,7 +5062,9 @@ static int hclge_fd_update_rule_list(struct hclge_dev *hdev,
else
hlist_add_head(&new_rule->rule_node, &hdev->fd_rule_list);
+ set_bit(location, hdev->fd_bmap);
hdev->hclge_fd_rule_num++;
+ hdev->fd_active_type = new_rule->rule_type;
return 0;
}
@@ -4969,14 +5079,14 @@ static int hclge_fd_get_tuple(struct hclge_dev *hdev,
case SCTP_V4_FLOW:
case TCP_V4_FLOW:
case UDP_V4_FLOW:
- rule->tuples.src_ip[3] =
+ rule->tuples.src_ip[IPV4_INDEX] =
be32_to_cpu(fs->h_u.tcp_ip4_spec.ip4src);
- rule->tuples_mask.src_ip[3] =
+ rule->tuples_mask.src_ip[IPV4_INDEX] =
be32_to_cpu(fs->m_u.tcp_ip4_spec.ip4src);
- rule->tuples.dst_ip[3] =
+ rule->tuples.dst_ip[IPV4_INDEX] =
be32_to_cpu(fs->h_u.tcp_ip4_spec.ip4dst);
- rule->tuples_mask.dst_ip[3] =
+ rule->tuples_mask.dst_ip[IPV4_INDEX] =
be32_to_cpu(fs->m_u.tcp_ip4_spec.ip4dst);
rule->tuples.src_port = be16_to_cpu(fs->h_u.tcp_ip4_spec.psrc);
@@ -4995,14 +5105,14 @@ static int hclge_fd_get_tuple(struct hclge_dev *hdev,
break;
case IP_USER_FLOW:
- rule->tuples.src_ip[3] =
+ rule->tuples.src_ip[IPV4_INDEX] =
be32_to_cpu(fs->h_u.usr_ip4_spec.ip4src);
- rule->tuples_mask.src_ip[3] =
+ rule->tuples_mask.src_ip[IPV4_INDEX] =
be32_to_cpu(fs->m_u.usr_ip4_spec.ip4src);
- rule->tuples.dst_ip[3] =
+ rule->tuples.dst_ip[IPV4_INDEX] =
be32_to_cpu(fs->h_u.usr_ip4_spec.ip4dst);
- rule->tuples_mask.dst_ip[3] =
+ rule->tuples_mask.dst_ip[IPV4_INDEX] =
be32_to_cpu(fs->m_u.usr_ip4_spec.ip4dst);
rule->tuples.ip_tos = fs->h_u.usr_ip4_spec.tos;
@@ -5019,14 +5129,14 @@ static int hclge_fd_get_tuple(struct hclge_dev *hdev,
case TCP_V6_FLOW:
case UDP_V6_FLOW:
be32_to_cpu_array(rule->tuples.src_ip,
- fs->h_u.tcp_ip6_spec.ip6src, 4);
+ fs->h_u.tcp_ip6_spec.ip6src, IPV6_SIZE);
be32_to_cpu_array(rule->tuples_mask.src_ip,
- fs->m_u.tcp_ip6_spec.ip6src, 4);
+ fs->m_u.tcp_ip6_spec.ip6src, IPV6_SIZE);
be32_to_cpu_array(rule->tuples.dst_ip,
- fs->h_u.tcp_ip6_spec.ip6dst, 4);
+ fs->h_u.tcp_ip6_spec.ip6dst, IPV6_SIZE);
be32_to_cpu_array(rule->tuples_mask.dst_ip,
- fs->m_u.tcp_ip6_spec.ip6dst, 4);
+ fs->m_u.tcp_ip6_spec.ip6dst, IPV6_SIZE);
rule->tuples.src_port = be16_to_cpu(fs->h_u.tcp_ip6_spec.psrc);
rule->tuples_mask.src_port =
@@ -5042,14 +5152,14 @@ static int hclge_fd_get_tuple(struct hclge_dev *hdev,
break;
case IPV6_USER_FLOW:
be32_to_cpu_array(rule->tuples.src_ip,
- fs->h_u.usr_ip6_spec.ip6src, 4);
+ fs->h_u.usr_ip6_spec.ip6src, IPV6_SIZE);
be32_to_cpu_array(rule->tuples_mask.src_ip,
- fs->m_u.usr_ip6_spec.ip6src, 4);
+ fs->m_u.usr_ip6_spec.ip6src, IPV6_SIZE);
be32_to_cpu_array(rule->tuples.dst_ip,
- fs->h_u.usr_ip6_spec.ip6dst, 4);
+ fs->h_u.usr_ip6_spec.ip6dst, IPV6_SIZE);
be32_to_cpu_array(rule->tuples_mask.dst_ip,
- fs->m_u.usr_ip6_spec.ip6dst, 4);
+ fs->m_u.usr_ip6_spec.ip6dst, IPV6_SIZE);
rule->tuples.ip_proto = fs->h_u.usr_ip6_spec.l4_proto;
rule->tuples_mask.ip_proto = fs->m_u.usr_ip6_spec.l4_proto;
@@ -5112,6 +5222,36 @@ static int hclge_fd_get_tuple(struct hclge_dev *hdev,
return 0;
}
+/* make sure being called after lock up with fd_rule_lock */
+static int hclge_fd_config_rule(struct hclge_dev *hdev,
+ struct hclge_fd_rule *rule)
+{
+ int ret;
+
+ if (!rule) {
+ dev_err(&hdev->pdev->dev,
+ "The flow director rule is NULL\n");
+ return -EINVAL;
+ }
+
+ /* it will never fail here, so needn't to check return value */
+ hclge_fd_update_rule_list(hdev, rule, rule->location, true);
+
+ ret = hclge_config_action(hdev, HCLGE_FD_STAGE_1, rule);
+ if (ret)
+ goto clear_rule;
+
+ ret = hclge_config_key(hdev, HCLGE_FD_STAGE_1, rule);
+ if (ret)
+ goto clear_rule;
+
+ return 0;
+
+clear_rule:
+ hclge_fd_update_rule_list(hdev, rule, rule->location, false);
+ return ret;
+}
+
static int hclge_add_fd_entry(struct hnae3_handle *handle,
struct ethtool_rxnfc *cmd)
{
@@ -5174,8 +5314,10 @@ static int hclge_add_fd_entry(struct hnae3_handle *handle,
return -ENOMEM;
ret = hclge_fd_get_tuple(hdev, fs, rule);
- if (ret)
- goto free_rule;
+ if (ret) {
+ kfree(rule);
+ return ret;
+ }
rule->flow_type = fs->flow_type;
@@ -5184,24 +5326,19 @@ static int hclge_add_fd_entry(struct hnae3_handle *handle,
rule->vf_id = dst_vport_id;
rule->queue_id = q_index;
rule->action = action;
+ rule->rule_type = HCLGE_FD_EP_ACTIVE;
- ret = hclge_config_action(hdev, HCLGE_FD_STAGE_1, rule);
- if (ret)
- goto free_rule;
+ /* to avoid rule conflict, when user configure rule by ethtool,
+ * we need to clear all arfs rules
+ */
+ hclge_clear_arfs_rules(handle);
- ret = hclge_config_key(hdev, HCLGE_FD_STAGE_1, rule);
- if (ret)
- goto free_rule;
+ spin_lock_bh(&hdev->fd_rule_lock);
+ ret = hclge_fd_config_rule(hdev, rule);
- ret = hclge_fd_update_rule_list(hdev, rule, fs->location, true);
- if (ret)
- goto free_rule;
+ spin_unlock_bh(&hdev->fd_rule_lock);
return ret;
-
-free_rule:
- kfree(rule);
- return ret;
}
static int hclge_del_fd_entry(struct hnae3_handle *handle,
@@ -5222,18 +5359,21 @@ static int hclge_del_fd_entry(struct hnae3_handle *handle,
if (!hclge_fd_rule_exist(hdev, fs->location)) {
dev_err(&hdev->pdev->dev,
- "Delete fail, rule %d is inexistent\n",
- fs->location);
+ "Delete fail, rule %d is inexistent\n", fs->location);
return -ENOENT;
}
- ret = hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true,
- fs->location, NULL, false);
+ ret = hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true, fs->location,
+ NULL, false);
if (ret)
return ret;
- return hclge_fd_update_rule_list(hdev, NULL, fs->location,
- false);
+ spin_lock_bh(&hdev->fd_rule_lock);
+ ret = hclge_fd_update_rule_list(hdev, NULL, fs->location, false);
+
+ spin_unlock_bh(&hdev->fd_rule_lock);
+
+ return ret;
}
static void hclge_del_all_fd_entries(struct hnae3_handle *handle,
@@ -5243,25 +5383,30 @@ static void hclge_del_all_fd_entries(struct hnae3_handle *handle,
struct hclge_dev *hdev = vport->back;
struct hclge_fd_rule *rule;
struct hlist_node *node;
+ u16 location;
if (!hnae3_dev_fd_supported(hdev))
return;
+ spin_lock_bh(&hdev->fd_rule_lock);
+ for_each_set_bit(location, hdev->fd_bmap,
+ hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1])
+ hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true, location,
+ NULL, false);
+
if (clear_list) {
hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list,
rule_node) {
- hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true,
- rule->location, NULL, false);
hlist_del(&rule->rule_node);
kfree(rule);
- hdev->hclge_fd_rule_num--;
}
- } else {
- hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list,
- rule_node)
- hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true,
- rule->location, NULL, false);
+ hdev->fd_active_type = HCLGE_FD_RULE_NONE;
+ hdev->hclge_fd_rule_num = 0;
+ bitmap_zero(hdev->fd_bmap,
+ hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1]);
}
+
+ spin_unlock_bh(&hdev->fd_rule_lock);
}
static int hclge_restore_fd_entries(struct hnae3_handle *handle)
@@ -5283,6 +5428,7 @@ static int hclge_restore_fd_entries(struct hnae3_handle *handle)
if (!hdev->fd_en)
return 0;
+ spin_lock_bh(&hdev->fd_rule_lock);
hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list, rule_node) {
ret = hclge_config_action(hdev, HCLGE_FD_STAGE_1, rule);
if (!ret)
@@ -5292,11 +5438,18 @@ static int hclge_restore_fd_entries(struct hnae3_handle *handle)
dev_warn(&hdev->pdev->dev,
"Restore rule %d failed, remove it\n",
rule->location);
+ clear_bit(rule->location, hdev->fd_bmap);
hlist_del(&rule->rule_node);
kfree(rule);
hdev->hclge_fd_rule_num--;
}
}
+
+ if (hdev->hclge_fd_rule_num)
+ hdev->fd_active_type = HCLGE_FD_EP_ACTIVE;
+
+ spin_unlock_bh(&hdev->fd_rule_lock);
+
return 0;
}
@@ -5329,13 +5482,18 @@ static int hclge_get_fd_rule_info(struct hnae3_handle *handle,
fs = (struct ethtool_rx_flow_spec *)&cmd->fs;
+ spin_lock_bh(&hdev->fd_rule_lock);
+
hlist_for_each_entry_safe(rule, node2, &hdev->fd_rule_list, rule_node) {
if (rule->location >= fs->location)
break;
}
- if (!rule || fs->location != rule->location)
+ if (!rule || fs->location != rule->location) {
+ spin_unlock_bh(&hdev->fd_rule_lock);
+
return -ENOENT;
+ }
fs->flow_type = rule->flow_type;
switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) {
@@ -5343,16 +5501,16 @@ static int hclge_get_fd_rule_info(struct hnae3_handle *handle,
case TCP_V4_FLOW:
case UDP_V4_FLOW:
fs->h_u.tcp_ip4_spec.ip4src =
- cpu_to_be32(rule->tuples.src_ip[3]);
+ cpu_to_be32(rule->tuples.src_ip[IPV4_INDEX]);
fs->m_u.tcp_ip4_spec.ip4src =
- rule->unused_tuple & BIT(INNER_SRC_IP) ?
- 0 : cpu_to_be32(rule->tuples_mask.src_ip[3]);
+ rule->unused_tuple & BIT(INNER_SRC_IP) ?
+ 0 : cpu_to_be32(rule->tuples_mask.src_ip[IPV4_INDEX]);
fs->h_u.tcp_ip4_spec.ip4dst =
- cpu_to_be32(rule->tuples.dst_ip[3]);
+ cpu_to_be32(rule->tuples.dst_ip[IPV4_INDEX]);
fs->m_u.tcp_ip4_spec.ip4dst =
- rule->unused_tuple & BIT(INNER_DST_IP) ?
- 0 : cpu_to_be32(rule->tuples_mask.dst_ip[3]);
+ rule->unused_tuple & BIT(INNER_DST_IP) ?
+ 0 : cpu_to_be32(rule->tuples_mask.dst_ip[IPV4_INDEX]);
fs->h_u.tcp_ip4_spec.psrc = cpu_to_be16(rule->tuples.src_port);
fs->m_u.tcp_ip4_spec.psrc =
@@ -5372,16 +5530,16 @@ static int hclge_get_fd_rule_info(struct hnae3_handle *handle,
break;
case IP_USER_FLOW:
fs->h_u.usr_ip4_spec.ip4src =
- cpu_to_be32(rule->tuples.src_ip[3]);
+ cpu_to_be32(rule->tuples.src_ip[IPV4_INDEX]);
fs->m_u.tcp_ip4_spec.ip4src =
- rule->unused_tuple & BIT(INNER_SRC_IP) ?
- 0 : cpu_to_be32(rule->tuples_mask.src_ip[3]);
+ rule->unused_tuple & BIT(INNER_SRC_IP) ?
+ 0 : cpu_to_be32(rule->tuples_mask.src_ip[IPV4_INDEX]);
fs->h_u.usr_ip4_spec.ip4dst =
- cpu_to_be32(rule->tuples.dst_ip[3]);
+ cpu_to_be32(rule->tuples.dst_ip[IPV4_INDEX]);
fs->m_u.usr_ip4_spec.ip4dst =
- rule->unused_tuple & BIT(INNER_DST_IP) ?
- 0 : cpu_to_be32(rule->tuples_mask.dst_ip[3]);
+ rule->unused_tuple & BIT(INNER_DST_IP) ?
+ 0 : cpu_to_be32(rule->tuples_mask.dst_ip[IPV4_INDEX]);
fs->h_u.usr_ip4_spec.tos = rule->tuples.ip_tos;
fs->m_u.usr_ip4_spec.tos =
@@ -5400,20 +5558,22 @@ static int hclge_get_fd_rule_info(struct hnae3_handle *handle,
case TCP_V6_FLOW:
case UDP_V6_FLOW:
cpu_to_be32_array(fs->h_u.tcp_ip6_spec.ip6src,
- rule->tuples.src_ip, 4);
+ rule->tuples.src_ip, IPV6_SIZE);
if (rule->unused_tuple & BIT(INNER_SRC_IP))
- memset(fs->m_u.tcp_ip6_spec.ip6src, 0, sizeof(int) * 4);
+ memset(fs->m_u.tcp_ip6_spec.ip6src, 0,
+ sizeof(int) * IPV6_SIZE);
else
cpu_to_be32_array(fs->m_u.tcp_ip6_spec.ip6src,
- rule->tuples_mask.src_ip, 4);
+ rule->tuples_mask.src_ip, IPV6_SIZE);
cpu_to_be32_array(fs->h_u.tcp_ip6_spec.ip6dst,
- rule->tuples.dst_ip, 4);
+ rule->tuples.dst_ip, IPV6_SIZE);
if (rule->unused_tuple & BIT(INNER_DST_IP))
- memset(fs->m_u.tcp_ip6_spec.ip6dst, 0, sizeof(int) * 4);
+ memset(fs->m_u.tcp_ip6_spec.ip6dst, 0,
+ sizeof(int) * IPV6_SIZE);
else
cpu_to_be32_array(fs->m_u.tcp_ip6_spec.ip6dst,
- rule->tuples_mask.dst_ip, 4);
+ rule->tuples_mask.dst_ip, IPV6_SIZE);
fs->h_u.tcp_ip6_spec.psrc = cpu_to_be16(rule->tuples.src_port);
fs->m_u.tcp_ip6_spec.psrc =
@@ -5428,20 +5588,22 @@ static int hclge_get_fd_rule_info(struct hnae3_handle *handle,
break;
case IPV6_USER_FLOW:
cpu_to_be32_array(fs->h_u.usr_ip6_spec.ip6src,
- rule->tuples.src_ip, 4);
+ rule->tuples.src_ip, IPV6_SIZE);
if (rule->unused_tuple & BIT(INNER_SRC_IP))
- memset(fs->m_u.usr_ip6_spec.ip6src, 0, sizeof(int) * 4);
+ memset(fs->m_u.usr_ip6_spec.ip6src, 0,
+ sizeof(int) * IPV6_SIZE);
else
cpu_to_be32_array(fs->m_u.usr_ip6_spec.ip6src,
- rule->tuples_mask.src_ip, 4);
+ rule->tuples_mask.src_ip, IPV6_SIZE);
cpu_to_be32_array(fs->h_u.usr_ip6_spec.ip6dst,
- rule->tuples.dst_ip, 4);
+ rule->tuples.dst_ip, IPV6_SIZE);
if (rule->unused_tuple & BIT(INNER_DST_IP))
- memset(fs->m_u.usr_ip6_spec.ip6dst, 0, sizeof(int) * 4);
+ memset(fs->m_u.usr_ip6_spec.ip6dst, 0,
+ sizeof(int) * IPV6_SIZE);
else
cpu_to_be32_array(fs->m_u.usr_ip6_spec.ip6dst,
- rule->tuples_mask.dst_ip, 4);
+ rule->tuples_mask.dst_ip, IPV6_SIZE);
fs->h_u.usr_ip6_spec.l4_proto = rule->tuples.ip_proto;
fs->m_u.usr_ip6_spec.l4_proto =
@@ -5474,6 +5636,7 @@ static int hclge_get_fd_rule_info(struct hnae3_handle *handle,
break;
default:
+ spin_unlock_bh(&hdev->fd_rule_lock);
return -EOPNOTSUPP;
}
@@ -5505,6 +5668,8 @@ static int hclge_get_fd_rule_info(struct hnae3_handle *handle,
fs->ring_cookie |= vf_id;
}
+ spin_unlock_bh(&hdev->fd_rule_lock);
+
return 0;
}
@@ -5522,20 +5687,208 @@ static int hclge_get_all_rules(struct hnae3_handle *handle,
cmd->data = hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1];
+ spin_lock_bh(&hdev->fd_rule_lock);
hlist_for_each_entry_safe(rule, node2,
&hdev->fd_rule_list, rule_node) {
- if (cnt == cmd->rule_cnt)
+ if (cnt == cmd->rule_cnt) {
+ spin_unlock_bh(&hdev->fd_rule_lock);
return -EMSGSIZE;
+ }
rule_locs[cnt] = rule->location;
cnt++;
}
+ spin_unlock_bh(&hdev->fd_rule_lock);
+
cmd->rule_cnt = cnt;
return 0;
}
+static void hclge_fd_get_flow_tuples(const struct flow_keys *fkeys,
+ struct hclge_fd_rule_tuples *tuples)
+{
+ tuples->ether_proto = be16_to_cpu(fkeys->basic.n_proto);
+ tuples->ip_proto = fkeys->basic.ip_proto;
+ tuples->dst_port = be16_to_cpu(fkeys->ports.dst);
+
+ if (fkeys->basic.n_proto == htons(ETH_P_IP)) {
+ tuples->src_ip[3] = be32_to_cpu(fkeys->addrs.v4addrs.src);
+ tuples->dst_ip[3] = be32_to_cpu(fkeys->addrs.v4addrs.dst);
+ } else {
+ memcpy(tuples->src_ip,
+ fkeys->addrs.v6addrs.src.in6_u.u6_addr32,
+ sizeof(tuples->src_ip));
+ memcpy(tuples->dst_ip,
+ fkeys->addrs.v6addrs.dst.in6_u.u6_addr32,
+ sizeof(tuples->dst_ip));
+ }
+}
+
+/* traverse all rules, check whether an existed rule has the same tuples */
+static struct hclge_fd_rule *
+hclge_fd_search_flow_keys(struct hclge_dev *hdev,
+ const struct hclge_fd_rule_tuples *tuples)
+{
+ struct hclge_fd_rule *rule = NULL;
+ struct hlist_node *node;
+
+ hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list, rule_node) {
+ if (!memcmp(tuples, &rule->tuples, sizeof(*tuples)))
+ return rule;
+ }
+
+ return NULL;
+}
+
+static void hclge_fd_build_arfs_rule(const struct hclge_fd_rule_tuples *tuples,
+ struct hclge_fd_rule *rule)
+{
+ rule->unused_tuple = BIT(INNER_SRC_MAC) | BIT(INNER_DST_MAC) |
+ BIT(INNER_VLAN_TAG_FST) | BIT(INNER_IP_TOS) |
+ BIT(INNER_SRC_PORT);
+ rule->action = 0;
+ rule->vf_id = 0;
+ rule->rule_type = HCLGE_FD_ARFS_ACTIVE;
+ if (tuples->ether_proto == ETH_P_IP) {
+ if (tuples->ip_proto == IPPROTO_TCP)
+ rule->flow_type = TCP_V4_FLOW;
+ else
+ rule->flow_type = UDP_V4_FLOW;
+ } else {
+ if (tuples->ip_proto == IPPROTO_TCP)
+ rule->flow_type = TCP_V6_FLOW;
+ else
+ rule->flow_type = UDP_V6_FLOW;
+ }
+ memcpy(&rule->tuples, tuples, sizeof(rule->tuples));
+ memset(&rule->tuples_mask, 0xFF, sizeof(rule->tuples_mask));
+}
+
+static int hclge_add_fd_entry_by_arfs(struct hnae3_handle *handle, u16 queue_id,
+ u16 flow_id, struct flow_keys *fkeys)
+{
+ struct hclge_vport *vport = hclge_get_vport(handle);
+ struct hclge_fd_rule_tuples new_tuples;
+ struct hclge_dev *hdev = vport->back;
+ struct hclge_fd_rule *rule;
+ u16 tmp_queue_id;
+ u16 bit_id;
+ int ret;
+
+ if (!hnae3_dev_fd_supported(hdev))
+ return -EOPNOTSUPP;
+
+ memset(&new_tuples, 0, sizeof(new_tuples));
+ hclge_fd_get_flow_tuples(fkeys, &new_tuples);
+
+ spin_lock_bh(&hdev->fd_rule_lock);
+
+ /* when there is already fd rule existed add by user,
+ * arfs should not work
+ */
+ if (hdev->fd_active_type == HCLGE_FD_EP_ACTIVE) {
+ spin_unlock_bh(&hdev->fd_rule_lock);
+
+ return -EOPNOTSUPP;
+ }
+
+ /* check is there flow director filter existed for this flow,
+ * if not, create a new filter for it;
+ * if filter exist with different queue id, modify the filter;
+ * if filter exist with same queue id, do nothing
+ */
+ rule = hclge_fd_search_flow_keys(hdev, &new_tuples);
+ if (!rule) {
+ bit_id = find_first_zero_bit(hdev->fd_bmap, MAX_FD_FILTER_NUM);
+ if (bit_id >= hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1]) {
+ spin_unlock_bh(&hdev->fd_rule_lock);
+
+ return -ENOSPC;
+ }
+
+ rule = kzalloc(sizeof(*rule), GFP_KERNEL);
+ if (!rule) {
+ spin_unlock_bh(&hdev->fd_rule_lock);
+
+ return -ENOMEM;
+ }
+
+ set_bit(bit_id, hdev->fd_bmap);
+ rule->location = bit_id;
+ rule->flow_id = flow_id;
+ rule->queue_id = queue_id;
+ hclge_fd_build_arfs_rule(&new_tuples, rule);
+ ret = hclge_fd_config_rule(hdev, rule);
+
+ spin_unlock_bh(&hdev->fd_rule_lock);
+
+ if (ret)
+ return ret;
+
+ return rule->location;
+ }
+
+ spin_unlock_bh(&hdev->fd_rule_lock);
+
+ if (rule->queue_id == queue_id)
+ return rule->location;
+
+ tmp_queue_id = rule->queue_id;
+ rule->queue_id = queue_id;
+ ret = hclge_config_action(hdev, HCLGE_FD_STAGE_1, rule);
+ if (ret) {
+ rule->queue_id = tmp_queue_id;
+ return ret;
+ }
+
+ return rule->location;
+}
+
+static void hclge_rfs_filter_expire(struct hclge_dev *hdev)
+{
+#ifdef CONFIG_RFS_ACCEL
+ struct hnae3_handle *handle = &hdev->vport[0].nic;
+ struct hclge_fd_rule *rule;
+ struct hlist_node *node;
+ HLIST_HEAD(del_list);
+
+ spin_lock_bh(&hdev->fd_rule_lock);
+ if (hdev->fd_active_type != HCLGE_FD_ARFS_ACTIVE) {
+ spin_unlock_bh(&hdev->fd_rule_lock);
+ return;
+ }
+ hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list, rule_node) {
+ if (rps_may_expire_flow(handle->netdev, rule->queue_id,
+ rule->flow_id, rule->location)) {
+ hlist_del_init(&rule->rule_node);
+ hlist_add_head(&rule->rule_node, &del_list);
+ hdev->hclge_fd_rule_num--;
+ clear_bit(rule->location, hdev->fd_bmap);
+ }
+ }
+ spin_unlock_bh(&hdev->fd_rule_lock);
+
+ hlist_for_each_entry_safe(rule, node, &del_list, rule_node) {
+ hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true,
+ rule->location, NULL, false);
+ kfree(rule);
+ }
+#endif
+}
+
+static void hclge_clear_arfs_rules(struct hnae3_handle *handle)
+{
+#ifdef CONFIG_RFS_ACCEL
+ struct hclge_vport *vport = hclge_get_vport(handle);
+ struct hclge_dev *hdev = vport->back;
+
+ if (hdev->fd_active_type == HCLGE_FD_ARFS_ACTIVE)
+ hclge_del_all_fd_entries(handle, true);
+#endif
+}
+
static bool hclge_get_hw_reset_stat(struct hnae3_handle *handle)
{
struct hclge_vport *vport = hclge_get_vport(handle);
@@ -5565,10 +5918,12 @@ static void hclge_enable_fd(struct hnae3_handle *handle, bool enable)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
+ bool clear;
hdev->fd_en = enable;
+ clear = hdev->fd_active_type == HCLGE_FD_ARFS_ACTIVE ? true : false;
if (!enable)
- hclge_del_all_fd_entries(handle, false);
+ hclge_del_all_fd_entries(handle, clear);
else
hclge_restore_fd_entries(handle);
}
@@ -5582,20 +5937,20 @@ static void hclge_cfg_mac_mode(struct hclge_dev *hdev, bool enable)
int ret;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CONFIG_MAC_MODE, false);
- hnae3_set_bit(loop_en, HCLGE_MAC_TX_EN_B, enable);
- hnae3_set_bit(loop_en, HCLGE_MAC_RX_EN_B, enable);
- hnae3_set_bit(loop_en, HCLGE_MAC_PAD_TX_B, enable);
- hnae3_set_bit(loop_en, HCLGE_MAC_PAD_RX_B, enable);
- hnae3_set_bit(loop_en, HCLGE_MAC_1588_TX_B, 0);
- hnae3_set_bit(loop_en, HCLGE_MAC_1588_RX_B, 0);
- hnae3_set_bit(loop_en, HCLGE_MAC_APP_LP_B, 0);
- hnae3_set_bit(loop_en, HCLGE_MAC_LINE_LP_B, 0);
- hnae3_set_bit(loop_en, HCLGE_MAC_FCS_TX_B, enable);
- hnae3_set_bit(loop_en, HCLGE_MAC_RX_FCS_B, enable);
- hnae3_set_bit(loop_en, HCLGE_MAC_RX_FCS_STRIP_B, enable);
- hnae3_set_bit(loop_en, HCLGE_MAC_TX_OVERSIZE_TRUNCATE_B, enable);
- hnae3_set_bit(loop_en, HCLGE_MAC_RX_OVERSIZE_TRUNCATE_B, enable);
- hnae3_set_bit(loop_en, HCLGE_MAC_TX_UNDER_MIN_ERR_B, enable);
+
+ if (enable) {
+ hnae3_set_bit(loop_en, HCLGE_MAC_TX_EN_B, 1U);
+ hnae3_set_bit(loop_en, HCLGE_MAC_RX_EN_B, 1U);
+ hnae3_set_bit(loop_en, HCLGE_MAC_PAD_TX_B, 1U);
+ hnae3_set_bit(loop_en, HCLGE_MAC_PAD_RX_B, 1U);
+ hnae3_set_bit(loop_en, HCLGE_MAC_FCS_TX_B, 1U);
+ hnae3_set_bit(loop_en, HCLGE_MAC_RX_FCS_B, 1U);
+ hnae3_set_bit(loop_en, HCLGE_MAC_RX_FCS_STRIP_B, 1U);
+ hnae3_set_bit(loop_en, HCLGE_MAC_TX_OVERSIZE_TRUNCATE_B, 1U);
+ hnae3_set_bit(loop_en, HCLGE_MAC_RX_OVERSIZE_TRUNCATE_B, 1U);
+ hnae3_set_bit(loop_en, HCLGE_MAC_TX_UNDER_MIN_ERR_B, 1U);
+ }
+
req->txrx_pad_fcs_loop_en = cpu_to_le32(loop_en);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
@@ -5726,7 +6081,7 @@ static int hclge_set_serdes_loopback(struct hclge_dev *hdev, bool en,
return -EBUSY;
}
-static int hclge_tqp_enable(struct hclge_dev *hdev, int tqp_id,
+static int hclge_tqp_enable(struct hclge_dev *hdev, unsigned int tqp_id,
int stream_id, bool enable)
{
struct hclge_desc desc;
@@ -5737,7 +6092,8 @@ static int hclge_tqp_enable(struct hclge_dev *hdev, int tqp_id,
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CFG_COM_TQP_QUEUE, false);
req->tqp_id = cpu_to_le16(tqp_id & HCLGE_RING_ID_MASK);
req->stream_id = cpu_to_le16(stream_id);
- req->enable |= enable << HCLGE_TQP_ENABLE_B;
+ if (enable)
+ req->enable |= 1U << HCLGE_TQP_ENABLE_B;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret)
@@ -5838,6 +6194,8 @@ static void hclge_ae_stop(struct hnae3_handle *handle)
set_bit(HCLGE_STATE_DOWN, &hdev->state);
+ hclge_clear_arfs_rules(handle);
+
/* If it is not PF reset, the firmware will disable the MAC,
* so it only need to stop phy here.
*/
@@ -5903,11 +6261,11 @@ static int hclge_get_mac_vlan_cmd_status(struct hclge_vport *vport,
if (op == HCLGE_MAC_VLAN_ADD) {
if ((!resp_code) || (resp_code == 1)) {
return_status = 0;
- } else if (resp_code == 2) {
+ } else if (resp_code == HCLGE_ADD_UC_OVERFLOW) {
return_status = -ENOSPC;
dev_err(&hdev->pdev->dev,
"add mac addr failed for uc_overflow.\n");
- } else if (resp_code == 3) {
+ } else if (resp_code == HCLGE_ADD_MC_OVERFLOW) {
return_status = -ENOSPC;
dev_err(&hdev->pdev->dev,
"add mac addr failed for mc_overflow.\n");
@@ -5952,13 +6310,15 @@ static int hclge_get_mac_vlan_cmd_status(struct hclge_vport *vport,
static int hclge_update_desc_vfid(struct hclge_desc *desc, int vfid, bool clr)
{
- int word_num;
- int bit_num;
+#define HCLGE_VF_NUM_IN_FIRST_DESC 192
+
+ unsigned int word_num;
+ unsigned int bit_num;
if (vfid > 255 || vfid < 0)
return -EIO;
- if (vfid >= 0 && vfid <= 191) {
+ if (vfid >= 0 && vfid < HCLGE_VF_NUM_IN_FIRST_DESC) {
word_num = vfid / 32;
bit_num = vfid % 32;
if (clr)
@@ -5966,7 +6326,7 @@ static int hclge_update_desc_vfid(struct hclge_desc *desc, int vfid, bool clr)
else
desc[1].data[word_num] |= cpu_to_le32(1 << bit_num);
} else {
- word_num = (vfid - 192) / 32;
+ word_num = (vfid - HCLGE_VF_NUM_IN_FIRST_DESC) / 32;
bit_num = vfid % 32;
if (clr)
desc[2].data[word_num] &= cpu_to_le32(~(1 << bit_num));
@@ -6149,6 +6509,10 @@ static int hclge_init_umv_space(struct hclge_dev *hdev)
mutex_init(&hdev->umv_mutex);
hdev->max_umv_size = allocated_size;
+ /* divide max_umv_size by (hdev->num_req_vfs + 2), in order to
+ * preserve some unicast mac vlan table entries shared by pf
+ * and its vfs.
+ */
hdev->priv_umv_size = hdev->max_umv_size / (hdev->num_req_vfs + 2);
hdev->share_umv_size = hdev->priv_umv_size +
hdev->max_umv_size % (hdev->num_req_vfs + 2);
@@ -6181,7 +6545,9 @@ static int hclge_set_umv_space(struct hclge_dev *hdev, u16 space_size,
req = (struct hclge_umv_spc_alc_cmd *)desc.data;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MAC_VLAN_ALLOCATE, false);
- hnae3_set_bit(req->allocate, HCLGE_UMV_SPC_ALC_B, !is_alloc);
+ if (!is_alloc)
+ hnae3_set_bit(req->allocate, HCLGE_UMV_SPC_ALC_B, 1);
+
req->space_size = cpu_to_le32(space_size);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
@@ -6270,8 +6636,7 @@ int hclge_add_uc_addr_common(struct hclge_vport *vport,
is_multicast_ether_addr(addr)) {
dev_err(&hdev->pdev->dev,
"Set_uc mac err! invalid mac:%pM. is_zero:%d,is_br=%d,is_mul=%d\n",
- addr,
- is_zero_ether_addr(addr),
+ addr, is_zero_ether_addr(addr),
is_broadcast_ether_addr(addr),
is_multicast_ether_addr(addr));
return -EINVAL;
@@ -6338,9 +6703,8 @@ int hclge_rm_uc_addr_common(struct hclge_vport *vport,
if (is_zero_ether_addr(addr) ||
is_broadcast_ether_addr(addr) ||
is_multicast_ether_addr(addr)) {
- dev_dbg(&hdev->pdev->dev,
- "Remove mac err! invalid mac:%pM.\n",
- addr);
+ dev_dbg(&hdev->pdev->dev, "Remove mac err! invalid mac:%pM.\n",
+ addr);
return -EINVAL;
}
@@ -6381,18 +6745,16 @@ int hclge_add_mc_addr_common(struct hclge_vport *vport,
hnae3_set_bit(req.entry_type, HCLGE_MAC_VLAN_BIT0_EN_B, 0);
hclge_prepare_mac_addr(&req, addr, true);
status = hclge_lookup_mac_vlan_tbl(vport, &req, desc, true);
- if (!status) {
- /* This mac addr exist, update VFID for it */
- hclge_update_desc_vfid(desc, vport->vport_id, false);
- status = hclge_add_mac_vlan_tbl(vport, &req, desc);
- } else {
+ if (status) {
/* This mac addr do not exist, add new entry for it */
memset(desc[0].data, 0, sizeof(desc[0].data));
memset(desc[1].data, 0, sizeof(desc[0].data));
memset(desc[2].data, 0, sizeof(desc[0].data));
- hclge_update_desc_vfid(desc, vport->vport_id, false);
- status = hclge_add_mac_vlan_tbl(vport, &req, desc);
}
+ status = hclge_update_desc_vfid(desc, vport->vport_id, false);
+ if (status)
+ return status;
+ status = hclge_add_mac_vlan_tbl(vport, &req, desc);
if (status == -ENOSPC)
dev_err(&hdev->pdev->dev, "mc mac vlan table is full\n");
@@ -6430,7 +6792,9 @@ int hclge_rm_mc_addr_common(struct hclge_vport *vport,
status = hclge_lookup_mac_vlan_tbl(vport, &req, desc, true);
if (!status) {
/* This mac addr exist, remove this handle's VFID for it */
- hclge_update_desc_vfid(desc, vport->vport_id, true);
+ status = hclge_update_desc_vfid(desc, vport->vport_id, true);
+ if (status)
+ return status;
if (hclge_is_all_function_id_zero(desc))
/* All the vfid is zero, so need to delete this entry */
@@ -6759,7 +7123,7 @@ static void hclge_enable_vlan_filter(struct hnae3_handle *handle, bool enable)
handle->netdev_flags &= ~HNAE3_VLAN_FLTR;
}
-static int hclge_set_vf_vlan_common(struct hclge_dev *hdev, int vfid,
+static int hclge_set_vf_vlan_common(struct hclge_dev *hdev, u16 vfid,
bool is_kill, u16 vlan, u8 qos,
__be16 proto)
{
@@ -6771,6 +7135,12 @@ static int hclge_set_vf_vlan_common(struct hclge_dev *hdev, int vfid,
u8 vf_byte_off;
int ret;
+ /* if vf vlan table is full, firmware will close vf vlan filter, it
+ * is unable and unnecessary to add new vlan id to vf vlan filter
+ */
+ if (test_bit(vfid, hdev->vf_vlan_full) && !is_kill)
+ return 0;
+
hclge_cmd_setup_basic_desc(&desc[0],
HCLGE_OPC_VLAN_FILTER_VF_CFG, false);
hclge_cmd_setup_basic_desc(&desc[1],
@@ -6806,6 +7176,7 @@ static int hclge_set_vf_vlan_common(struct hclge_dev *hdev, int vfid,
return 0;
if (req0->resp_code == HCLGE_VF_VLAN_NO_ENTRY) {
+ set_bit(vfid, hdev->vf_vlan_full);
dev_warn(&hdev->pdev->dev,
"vf vlan table is full, vf vlan filter is disabled\n");
return 0;
@@ -6819,12 +7190,13 @@ static int hclge_set_vf_vlan_common(struct hclge_dev *hdev, int vfid,
if (!req0->resp_code)
return 0;
- if (req0->resp_code == HCLGE_VF_VLAN_DEL_NO_FOUND) {
- dev_warn(&hdev->pdev->dev,
- "vlan %d filter is not in vf vlan table\n",
- vlan);
+ /* vf vlan filter is disabled when vf vlan table is full,
+ * then new vlan id will not be added into vf vlan table.
+ * Just return 0 without warning, avoid massive verbose
+ * print logs when unload.
+ */
+ if (req0->resp_code == HCLGE_VF_VLAN_DEL_NO_FOUND)
return 0;
- }
dev_err(&hdev->pdev->dev,
"Kill vf vlan filter fail, ret =%d.\n",
@@ -7140,10 +7512,6 @@ static void hclge_add_vport_vlan_table(struct hclge_vport *vport, u16 vlan_id,
{
struct hclge_vport_vlan_cfg *vlan;
- /* vlan 0 is reserved */
- if (!vlan_id)
- return;
-
vlan = kzalloc(sizeof(*vlan), GFP_KERNEL);
if (!vlan)
return;
@@ -7238,6 +7606,43 @@ void hclge_uninit_vport_vlan_table(struct hclge_dev *hdev)
mutex_unlock(&hdev->vport_cfg_mutex);
}
+static void hclge_restore_vlan_table(struct hnae3_handle *handle)
+{
+ struct hclge_vport *vport = hclge_get_vport(handle);
+ struct hclge_vport_vlan_cfg *vlan, *tmp;
+ struct hclge_dev *hdev = vport->back;
+ u16 vlan_proto, qos;
+ u16 state, vlan_id;
+ int i;
+
+ mutex_lock(&hdev->vport_cfg_mutex);
+ for (i = 0; i < hdev->num_alloc_vport; i++) {
+ vport = &hdev->vport[i];
+ vlan_proto = vport->port_base_vlan_cfg.vlan_info.vlan_proto;
+ vlan_id = vport->port_base_vlan_cfg.vlan_info.vlan_tag;
+ qos = vport->port_base_vlan_cfg.vlan_info.qos;
+ state = vport->port_base_vlan_cfg.state;
+
+ if (state != HNAE3_PORT_BASE_VLAN_DISABLE) {
+ hclge_set_vlan_filter_hw(hdev, htons(vlan_proto),
+ vport->vport_id, vlan_id, qos,
+ false);
+ continue;
+ }
+
+ list_for_each_entry_safe(vlan, tmp, &vport->vlan_list, node) {
+ if (vlan->hd_tbl_status)
+ hclge_set_vlan_filter_hw(hdev,
+ htons(ETH_P_8021Q),
+ vport->vport_id,
+ vlan->vlan_id, 0,
+ false);
+ }
+ }
+
+ mutex_unlock(&hdev->vport_cfg_mutex);
+}
+
int hclge_en_hw_strip_rxvtag(struct hnae3_handle *handle, bool enable)
{
struct hclge_vport *vport = hclge_get_vport(handle);
@@ -7415,11 +7820,20 @@ int hclge_set_vlan_filter(struct hnae3_handle *handle, __be16 proto,
bool writen_to_tbl = false;
int ret = 0;
- /* when port based VLAN enabled, we use port based VLAN as the VLAN
- * filter entry. In this case, we don't update VLAN filter table
- * when user add new VLAN or remove exist VLAN, just update the vport
- * VLAN list. The VLAN id in VLAN list won't be writen in VLAN filter
- * table until port based VLAN disabled
+ /* When device is resetting, firmware is unable to handle
+ * mailbox. Just record the vlan id, and remove it after
+ * reset finished.
+ */
+ if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state) && is_kill) {
+ set_bit(vlan_id, vport->vlan_del_fail_bmap);
+ return -EBUSY;
+ }
+
+ /* When port base vlan enabled, we use port base vlan as the vlan
+ * filter entry. In this case, we don't update vlan filter table
+ * when user add new vlan or remove exist vlan, just update the vport
+ * vlan list. The vlan id in vlan list will be writen in vlan filter
+ * table until port base vlan disabled
*/
if (handle->port_base_vlan_state == HNAE3_PORT_BASE_VLAN_DISABLE) {
ret = hclge_set_vlan_filter_hw(hdev, proto, vport->vport_id,
@@ -7427,16 +7841,53 @@ int hclge_set_vlan_filter(struct hnae3_handle *handle, __be16 proto,
writen_to_tbl = true;
}
- if (ret)
- return ret;
+ if (!ret) {
+ if (is_kill)
+ hclge_rm_vport_vlan_table(vport, vlan_id, false);
+ else
+ hclge_add_vport_vlan_table(vport, vlan_id,
+ writen_to_tbl);
+ } else if (is_kill) {
+ /* When remove hw vlan filter failed, record the vlan id,
+ * and try to remove it from hw later, to be consistence
+ * with stack
+ */
+ set_bit(vlan_id, vport->vlan_del_fail_bmap);
+ }
+ return ret;
+}
- if (is_kill)
- hclge_rm_vport_vlan_table(vport, vlan_id, false);
- else
- hclge_add_vport_vlan_table(vport, vlan_id,
- writen_to_tbl);
+static void hclge_sync_vlan_filter(struct hclge_dev *hdev)
+{
+#define HCLGE_MAX_SYNC_COUNT 60
- return 0;
+ int i, ret, sync_cnt = 0;
+ u16 vlan_id;
+
+ /* start from vport 1 for PF is always alive */
+ for (i = 0; i < hdev->num_alloc_vport; i++) {
+ struct hclge_vport *vport = &hdev->vport[i];
+
+ vlan_id = find_first_bit(vport->vlan_del_fail_bmap,
+ VLAN_N_VID);
+ while (vlan_id != VLAN_N_VID) {
+ ret = hclge_set_vlan_filter_hw(hdev, htons(ETH_P_8021Q),
+ vport->vport_id, vlan_id,
+ 0, true);
+ if (ret && ret != -EINVAL)
+ return;
+
+ clear_bit(vlan_id, vport->vlan_del_fail_bmap);
+ hclge_rm_vport_vlan_table(vport, vlan_id, false);
+
+ sync_cnt++;
+ if (sync_cnt >= HCLGE_MAX_SYNC_COUNT)
+ return;
+
+ vlan_id = find_first_bit(vport->vlan_del_fail_bmap,
+ VLAN_N_VID);
+ }
+ }
}
static int hclge_set_mac_mtu(struct hclge_dev *hdev, int new_mps)
@@ -7463,7 +7914,7 @@ static int hclge_set_mtu(struct hnae3_handle *handle, int new_mtu)
int hclge_set_vport_mtu(struct hclge_vport *vport, int new_mtu)
{
struct hclge_dev *hdev = vport->back;
- int i, max_frm_size, ret = 0;
+ int i, max_frm_size, ret;
max_frm_size = new_mtu + ETH_HLEN + ETH_FCS_LEN + 2 * VLAN_HLEN;
if (max_frm_size < HCLGE_MAC_MIN_FRAME ||
@@ -7523,7 +7974,8 @@ static int hclge_send_reset_tqp_cmd(struct hclge_dev *hdev, u16 queue_id,
req = (struct hclge_reset_tqp_queue_cmd *)desc.data;
req->tqp_id = cpu_to_le16(queue_id & HCLGE_RING_ID_MASK);
- hnae3_set_bit(req->reset_req, HCLGE_TQP_RESET_B, enable);
+ if (enable)
+ hnae3_set_bit(req->reset_req, HCLGE_TQP_RESET_B, 1U);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
@@ -7574,7 +8026,7 @@ int hclge_reset_tqp(struct hnae3_handle *handle, u16 queue_id)
int reset_try_times = 0;
int reset_status;
u16 queue_gid;
- int ret = 0;
+ int ret;
queue_gid = hclge_covert_handle_qid_global(handle, queue_id);
@@ -7591,7 +8043,6 @@ int hclge_reset_tqp(struct hnae3_handle *handle, u16 queue_id)
return ret;
}
- reset_try_times = 0;
while (reset_try_times++ < HCLGE_TQP_RESET_TRY_TIMES) {
/* Wait for tqp hw reset */
msleep(20);
@@ -7630,7 +8081,6 @@ void hclge_reset_vf_queue(struct hclge_vport *vport, u16 queue_id)
return;
}
- reset_try_times = 0;
while (reset_try_times++ < HCLGE_TQP_RESET_TRY_TIMES) {
/* Wait for tqp hw reset */
msleep(20);
@@ -7700,7 +8150,7 @@ int hclge_cfg_flowctrl(struct hclge_dev *hdev)
{
struct phy_device *phydev = hdev->hw.mac.phydev;
u16 remote_advertising = 0;
- u16 local_advertising = 0;
+ u16 local_advertising;
u32 rx_pause, tx_pause;
u8 flowctl;
@@ -7733,8 +8183,9 @@ static void hclge_get_pauseparam(struct hnae3_handle *handle, u32 *auto_neg,
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
+ struct phy_device *phydev = hdev->hw.mac.phydev;
- *auto_neg = hclge_get_autoneg(handle);
+ *auto_neg = phydev ? hclge_get_autoneg(handle) : 0;
if (hdev->tm_info.fc_mode == HCLGE_FC_PFC) {
*rx_en = 0;
@@ -7765,11 +8216,13 @@ static int hclge_set_pauseparam(struct hnae3_handle *handle, u32 auto_neg,
struct phy_device *phydev = hdev->hw.mac.phydev;
u32 fc_autoneg;
- fc_autoneg = hclge_get_autoneg(handle);
- if (auto_neg != fc_autoneg) {
- dev_info(&hdev->pdev->dev,
- "To change autoneg please use: ethtool -s <dev> autoneg <on|off>\n");
- return -EOPNOTSUPP;
+ if (phydev) {
+ fc_autoneg = hclge_get_autoneg(handle);
+ if (auto_neg != fc_autoneg) {
+ dev_info(&hdev->pdev->dev,
+ "To change autoneg please use: ethtool -s <dev> autoneg <on|off>\n");
+ return -EOPNOTSUPP;
+ }
}
if (hdev->tm_info.fc_mode == HCLGE_FC_PFC) {
@@ -7780,16 +8233,13 @@ static int hclge_set_pauseparam(struct hnae3_handle *handle, u32 auto_neg,
hclge_set_flowctrl_adv(hdev, rx_en, tx_en);
- if (!fc_autoneg)
+ if (!auto_neg)
return hclge_cfg_pauseparam(hdev, rx_en, tx_en);
if (phydev)
return phy_start_aneg(phydev);
- if (hdev->pdev->revision == 0x20)
- return -EOPNOTSUPP;
-
- return hclge_restart_autoneg(handle);
+ return -EOPNOTSUPP;
}
static void hclge_get_ksettings_an_result(struct hnae3_handle *handle,
@@ -7825,7 +8275,8 @@ static void hclge_get_mdix_mode(struct hnae3_handle *handle,
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
struct phy_device *phydev = hdev->hw.mac.phydev;
- int mdix_ctrl, mdix, retval, is_resolved;
+ int mdix_ctrl, mdix, is_resolved;
+ unsigned int retval;
if (!phydev) {
*tp_mdix_ctrl = ETH_TP_MDI_INVALID;
@@ -7894,6 +8345,102 @@ static void hclge_info_show(struct hclge_dev *hdev)
dev_info(dev, "PF info end.\n");
}
+static int hclge_init_nic_client_instance(struct hnae3_ae_dev *ae_dev,
+ struct hclge_vport *vport)
+{
+ struct hnae3_client *client = vport->nic.client;
+ struct hclge_dev *hdev = ae_dev->priv;
+ int rst_cnt;
+ int ret;
+
+ rst_cnt = hdev->rst_stats.reset_cnt;
+ ret = client->ops->init_instance(&vport->nic);
+ if (ret)
+ return ret;
+
+ set_bit(HCLGE_STATE_NIC_REGISTERED, &hdev->state);
+ if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state) ||
+ rst_cnt != hdev->rst_stats.reset_cnt) {
+ ret = -EBUSY;
+ goto init_nic_err;
+ }
+
+ /* Enable nic hw error interrupts */
+ ret = hclge_config_nic_hw_error(hdev, true);
+ if (ret) {
+ dev_err(&ae_dev->pdev->dev,
+ "fail(%d) to enable hw error interrupts\n", ret);
+ goto init_nic_err;
+ }
+
+ hnae3_set_client_init_flag(client, ae_dev, 1);
+
+ if (netif_msg_drv(&hdev->vport->nic))
+ hclge_info_show(hdev);
+
+ return ret;
+
+init_nic_err:
+ clear_bit(HCLGE_STATE_NIC_REGISTERED, &hdev->state);
+ while (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state))
+ msleep(HCLGE_WAIT_RESET_DONE);
+
+ client->ops->uninit_instance(&vport->nic, 0);
+
+ return ret;
+}
+
+static int hclge_init_roce_client_instance(struct hnae3_ae_dev *ae_dev,
+ struct hclge_vport *vport)
+{
+ struct hnae3_client *client = vport->roce.client;
+ struct hclge_dev *hdev = ae_dev->priv;
+ int rst_cnt;
+ int ret;
+
+ if (!hnae3_dev_roce_supported(hdev) || !hdev->roce_client ||
+ !hdev->nic_client)
+ return 0;
+
+ client = hdev->roce_client;
+ ret = hclge_init_roce_base_info(vport);
+ if (ret)
+ return ret;
+
+ rst_cnt = hdev->rst_stats.reset_cnt;
+ ret = client->ops->init_instance(&vport->roce);
+ if (ret)
+ return ret;
+
+ set_bit(HCLGE_STATE_ROCE_REGISTERED, &hdev->state);
+ if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state) ||
+ rst_cnt != hdev->rst_stats.reset_cnt) {
+ ret = -EBUSY;
+ goto init_roce_err;
+ }
+
+ /* Enable roce ras interrupts */
+ ret = hclge_config_rocee_ras_interrupt(hdev, true);
+ if (ret) {
+ dev_err(&ae_dev->pdev->dev,
+ "fail(%d) to enable roce ras interrupts\n", ret);
+ goto init_roce_err;
+ }
+
+ hnae3_set_client_init_flag(client, ae_dev, 1);
+
+ return 0;
+
+init_roce_err:
+ clear_bit(HCLGE_STATE_ROCE_REGISTERED, &hdev->state);
+ while (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state))
+ msleep(HCLGE_WAIT_RESET_DONE);
+
+ hdev->roce_client->ops->uninit_instance(&vport->roce, 0);
+
+ return ret;
+}
+
static int hclge_init_client_instance(struct hnae3_client *client,
struct hnae3_ae_dev *ae_dev)
{
@@ -7909,41 +8456,13 @@ static int hclge_init_client_instance(struct hnae3_client *client,
hdev->nic_client = client;
vport->nic.client = client;
- ret = client->ops->init_instance(&vport->nic);
+ ret = hclge_init_nic_client_instance(ae_dev, vport);
if (ret)
goto clear_nic;
- hnae3_set_client_init_flag(client, ae_dev, 1);
-
- if (netif_msg_drv(&hdev->vport->nic))
- hclge_info_show(hdev);
-
- if (hdev->roce_client &&
- hnae3_dev_roce_supported(hdev)) {
- struct hnae3_client *rc = hdev->roce_client;
-
- ret = hclge_init_roce_base_info(vport);
- if (ret)
- goto clear_roce;
-
- ret = rc->ops->init_instance(&vport->roce);
- if (ret)
- goto clear_roce;
-
- hnae3_set_client_init_flag(hdev->roce_client,
- ae_dev, 1);
- }
-
- break;
- case HNAE3_CLIENT_UNIC:
- hdev->nic_client = client;
- vport->nic.client = client;
-
- ret = client->ops->init_instance(&vport->nic);
+ ret = hclge_init_roce_client_instance(ae_dev, vport);
if (ret)
- goto clear_nic;
-
- hnae3_set_client_init_flag(client, ae_dev, 1);
+ goto clear_roce;
break;
case HNAE3_CLIENT_ROCE:
@@ -7952,17 +8471,9 @@ static int hclge_init_client_instance(struct hnae3_client *client,
vport->roce.client = client;
}
- if (hdev->roce_client && hdev->nic_client) {
- ret = hclge_init_roce_base_info(vport);
- if (ret)
- goto clear_roce;
-
- ret = client->ops->init_instance(&vport->roce);
- if (ret)
- goto clear_roce;
-
- hnae3_set_client_init_flag(client, ae_dev, 1);
- }
+ ret = hclge_init_roce_client_instance(ae_dev, vport);
+ if (ret)
+ goto clear_roce;
break;
default:
@@ -7970,7 +8481,7 @@ static int hclge_init_client_instance(struct hnae3_client *client,
}
}
- return 0;
+ return ret;
clear_nic:
hdev->nic_client = NULL;
@@ -7992,6 +8503,10 @@ static void hclge_uninit_client_instance(struct hnae3_client *client,
for (i = 0; i < hdev->num_vmdq_vport + 1; i++) {
vport = &hdev->vport[i];
if (hdev->roce_client) {
+ clear_bit(HCLGE_STATE_ROCE_REGISTERED, &hdev->state);
+ while (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state))
+ msleep(HCLGE_WAIT_RESET_DONE);
+
hdev->roce_client->ops->uninit_instance(&vport->roce,
0);
hdev->roce_client = NULL;
@@ -8000,6 +8515,10 @@ static void hclge_uninit_client_instance(struct hnae3_client *client,
if (client->type == HNAE3_CLIENT_ROCE)
return;
if (hdev->nic_client && client->ops->uninit_instance) {
+ clear_bit(HCLGE_STATE_NIC_REGISTERED, &hdev->state);
+ while (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state))
+ msleep(HCLGE_WAIT_RESET_DONE);
+
client->ops->uninit_instance(&vport->nic, 0);
hdev->nic_client = NULL;
vport->nic.client = NULL;
@@ -8081,6 +8600,7 @@ static void hclge_state_init(struct hclge_dev *hdev)
static void hclge_state_uninit(struct hclge_dev *hdev)
{
set_bit(HCLGE_STATE_DOWN, &hdev->state);
+ set_bit(HCLGE_STATE_REMOVING, &hdev->state);
if (hdev->service_timer.function)
del_timer_sync(&hdev->service_timer);
@@ -8122,6 +8642,23 @@ static void hclge_flr_done(struct hnae3_ae_dev *ae_dev)
set_bit(HNAE3_FLR_DONE, &hdev->flr_state);
}
+static void hclge_clear_resetting_state(struct hclge_dev *hdev)
+{
+ u16 i;
+
+ for (i = 0; i < hdev->num_alloc_vport; i++) {
+ struct hclge_vport *vport = &hdev->vport[i];
+ int ret;
+
+ /* Send cmd to clear VF's FUNC_RST_ING */
+ ret = hclge_set_vf_rst(hdev, vport->vport_id, false);
+ if (ret)
+ dev_warn(&hdev->pdev->dev,
+ "clear vf(%d) rst failed %d!\n",
+ vport->vport_id, ret);
+ }
+}
+
static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
{
struct pci_dev *pdev = ae_dev->pdev;
@@ -8143,6 +8680,7 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
mutex_init(&hdev->vport_lock);
mutex_init(&hdev->vport_cfg_mutex);
+ spin_lock_init(&hdev->fd_rule_lock);
ret = hclge_pci_init(hdev);
if (ret) {
@@ -8270,13 +8808,6 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
goto err_mdiobus_unreg;
}
- ret = hclge_hw_error_set_state(hdev, true);
- if (ret) {
- dev_err(&pdev->dev,
- "fail(%d) to enable hw error interrupts\n", ret);
- goto err_mdiobus_unreg;
- }
-
INIT_KFIFO(hdev->mac_tnl_log);
hclge_dcb_ops_set(hdev);
@@ -8288,6 +8819,22 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
INIT_WORK(&hdev->mbx_service_task, hclge_mailbox_service_task);
hclge_clear_all_event_cause(hdev);
+ hclge_clear_resetting_state(hdev);
+
+ /* Log and clear the hw errors those already occurred */
+ hclge_handle_all_hns_hw_errors(ae_dev);
+
+ /* request delayed reset for the error recovery because an immediate
+ * global reset on a PF affecting pending initialization of other PFs
+ */
+ if (ae_dev->hw_err_reset_req) {
+ enum hnae3_reset_type reset_level;
+
+ reset_level = hclge_get_reset_level(ae_dev,
+ &ae_dev->hw_err_reset_req);
+ hclge_set_def_reset_request(ae_dev, reset_level);
+ mod_timer(&hdev->reset_timer, jiffies + HCLGE_RESET_INTERVAL);
+ }
/* Enable MISC vector(vector0) */
hclge_enable_vector(&hdev->misc_vector, true);
@@ -8342,6 +8889,7 @@ static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev)
hclge_stats_clear(hdev);
memset(hdev->vlan_table, 0, sizeof(hdev->vlan_table));
+ memset(hdev->vf_vlan_full, 0, sizeof(hdev->vf_vlan_full));
ret = hclge_cmd_init(hdev);
if (ret) {
@@ -8393,21 +8941,31 @@ static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev)
ret = hclge_init_fd_config(hdev);
if (ret) {
- dev_err(&pdev->dev,
- "fd table init fail, ret=%d\n", ret);
+ dev_err(&pdev->dev, "fd table init fail, ret=%d\n", ret);
return ret;
}
/* Re-enable the hw error interrupts because
- * the interrupts get disabled on core/global reset.
+ * the interrupts get disabled on global reset.
*/
- ret = hclge_hw_error_set_state(hdev, true);
+ ret = hclge_config_nic_hw_error(hdev, true);
if (ret) {
dev_err(&pdev->dev,
- "fail(%d) to re-enable HNS hw error interrupts\n", ret);
+ "fail(%d) to re-enable NIC hw error interrupts\n",
+ ret);
return ret;
}
+ if (hdev->roce_client) {
+ ret = hclge_config_rocee_ras_interrupt(hdev, true);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "fail(%d) to re-enable roce ras interrupts\n",
+ ret);
+ return ret;
+ }
+ }
+
hclge_reset_vport_state(hdev);
dev_info(&pdev->dev, "Reset done, %s driver initialization finished.\n",
@@ -8432,8 +8990,11 @@ static void hclge_uninit_ae_dev(struct hnae3_ae_dev *ae_dev)
hclge_enable_vector(&hdev->misc_vector, false);
synchronize_irq(hdev->misc_vector.vector_irq);
+ /* Disable all hw interrupts */
hclge_config_mac_tnl_int(hdev, false);
- hclge_hw_error_set_state(hdev, false);
+ hclge_config_nic_hw_error(hdev, false);
+ hclge_config_rocee_ras_interrupt(hdev, false);
+
hclge_cmd_uninit(hdev);
hclge_misc_irq_uninit(hdev);
hclge_pci_uninit(hdev);
@@ -8478,15 +9039,16 @@ static int hclge_set_channels(struct hnae3_handle *handle, u32 new_tqps_num,
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hnae3_knic_private_info *kinfo = &vport->nic.kinfo;
+ u16 tc_offset[HCLGE_MAX_TC_NUM] = {0};
struct hclge_dev *hdev = vport->back;
+ u16 tc_size[HCLGE_MAX_TC_NUM] = {0};
int cur_rss_size = kinfo->rss_size;
int cur_tqps = kinfo->num_tqps;
- u16 tc_offset[HCLGE_MAX_TC_NUM];
u16 tc_valid[HCLGE_MAX_TC_NUM];
- u16 tc_size[HCLGE_MAX_TC_NUM];
u16 roundup_size;
u32 *rss_indir;
- int ret, i;
+ unsigned int i;
+ int ret;
kinfo->req_rss_size = new_tqps_num;
@@ -8571,10 +9133,12 @@ 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;
@@ -8582,7 +9146,9 @@ static int hclge_get_32_bit_regs(struct hclge_dev *hdev, u32 regs_num,
if (regs_num == 0)
return 0;
- cmd_num = DIV_ROUND_UP(regs_num + 2, HCLGE_32_BIT_REG_RTN_DATANUM);
+ 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;
@@ -8599,7 +9165,7 @@ static int hclge_get_32_bit_regs(struct hclge_dev *hdev, u32 regs_num,
for (i = 0; i < cmd_num; i++) {
if (i == 0) {
desc_data = (__le32 *)(&desc[i].data[0]);
- n = HCLGE_32_BIT_REG_RTN_DATANUM - 2;
+ n = HCLGE_32_BIT_REG_RTN_DATANUM - nodata_num;
} else {
desc_data = (__le32 *)(&desc[i]);
n = HCLGE_32_BIT_REG_RTN_DATANUM;
@@ -8621,10 +9187,12 @@ 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;
@@ -8632,7 +9200,9 @@ static int hclge_get_64_bit_regs(struct hclge_dev *hdev, u32 regs_num,
if (regs_num == 0)
return 0;
- cmd_num = DIV_ROUND_UP(regs_num + 1, HCLGE_64_BIT_REG_RTN_DATANUM);
+ 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;
@@ -8649,7 +9219,7 @@ static int hclge_get_64_bit_regs(struct hclge_dev *hdev, u32 regs_num,
for (i = 0; i < cmd_num; i++) {
if (i == 0) {
desc_data = (__le64 *)(&desc[i].data[0]);
- n = HCLGE_64_BIT_REG_RTN_DATANUM - 1;
+ n = HCLGE_64_BIT_REG_RTN_DATANUM - nodata_len;
} else {
desc_data = (__le64 *)(&desc[i]);
n = HCLGE_64_BIT_REG_RTN_DATANUM;
@@ -8876,6 +9446,7 @@ static const struct hnae3_ae_ops hclge_ops = {
.set_autoneg = hclge_set_autoneg,
.get_autoneg = hclge_get_autoneg,
.restart_autoneg = hclge_restart_autoneg,
+ .halt_autoneg = hclge_halt_autoneg,
.get_pauseparam = hclge_get_pauseparam,
.set_pauseparam = hclge_set_pauseparam,
.set_mtu = hclge_set_mtu,
@@ -8892,6 +9463,7 @@ static const struct hnae3_ae_ops hclge_ops = {
.set_vf_vlan_filter = hclge_set_vf_vlan_filter,
.enable_hw_strip_rxvtag = hclge_en_hw_strip_rxvtag,
.reset_event = hclge_reset_event,
+ .get_reset_level = hclge_get_reset_level,
.set_default_reset_request = hclge_set_def_reset_request,
.get_tqps_and_rss_info = hclge_get_tqps_and_rss_info,
.set_channels = hclge_set_channels,
@@ -8908,6 +9480,7 @@ static const struct hnae3_ae_ops hclge_ops = {
.get_fd_all_rules = hclge_get_all_rules,
.restore_fd_rules = hclge_restore_fd_entries,
.enable_fd = hclge_enable_fd,
+ .add_arfs_entry = hclge_add_fd_entry_by_arfs,
.dbg_run_cmd = hclge_dbg_run_cmd,
.handle_hw_ras_error = hclge_handle_hw_ras_error,
.get_hw_reset_stat = hclge_get_hw_reset_stat,
@@ -8918,6 +9491,7 @@ static const struct hnae3_ae_ops hclge_ops = {
.set_timer_task = hclge_set_timer_task,
.mac_connect_phy = hclge_mac_connect_phy,
.mac_disconnect_phy = hclge_mac_disconnect_phy,
+ .restore_vlan_table = hclge_restore_vlan_table,
};
static struct hnae3_ae_algo ae_algo = {
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
index dd06b11187b0..6a12285f4c76 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
@@ -201,6 +201,8 @@ enum HCLGE_DEV_STATE {
HCLGE_STATE_DOWN,
HCLGE_STATE_DISABLED,
HCLGE_STATE_REMOVING,
+ HCLGE_STATE_NIC_REGISTERED,
+ HCLGE_STATE_ROCE_REGISTERED,
HCLGE_STATE_SERVICE_INITED,
HCLGE_STATE_SERVICE_SCHED,
HCLGE_STATE_RST_SERVICE_SCHED,
@@ -472,6 +474,7 @@ enum HCLGE_FD_KEY_TYPE {
enum HCLGE_FD_STAGE {
HCLGE_FD_STAGE_1,
HCLGE_FD_STAGE_2,
+ MAX_STAGE_NUM,
};
/* OUTER_XXX indicates tuples in tunnel header of tunnel packet
@@ -526,7 +529,7 @@ enum HCLGE_FD_META_DATA {
struct key_info {
u8 key_type;
- u8 key_length;
+ u8 key_length; /* use bit as unit */
};
static const struct key_info meta_data_key_info[] = {
@@ -578,6 +581,16 @@ static const struct key_info tuple_key_info[] = {
#define MAX_KEY_BYTES (MAX_KEY_DWORDS * 4)
#define MAX_META_DATA_LENGTH 32
+/* assigned by firmware, the real filter number for each pf may be less */
+#define MAX_FD_FILTER_NUM 4096
+#define HCLGE_FD_ARFS_EXPIRE_TIMER_INTERVAL 5
+
+enum HCLGE_FD_ACTIVE_RULE_TYPE {
+ HCLGE_FD_RULE_NONE,
+ HCLGE_FD_ARFS_ACTIVE,
+ HCLGE_FD_EP_ACTIVE,
+};
+
enum HCLGE_FD_PACKET_TYPE {
NIC_PACKET,
ROCE_PACKET,
@@ -600,18 +613,23 @@ struct hclge_fd_key_cfg {
struct hclge_fd_cfg {
u8 fd_mode;
- u16 max_key_length;
+ u16 max_key_length; /* use bit as unit */
u32 proto_support;
- u32 rule_num[2]; /* rule entry number */
- u16 cnt_num[2]; /* rule hit counter number */
- struct hclge_fd_key_cfg key_cfg[2];
+ u32 rule_num[MAX_STAGE_NUM]; /* rule entry number */
+ u16 cnt_num[MAX_STAGE_NUM]; /* rule hit counter number */
+ struct hclge_fd_key_cfg key_cfg[MAX_STAGE_NUM];
};
+#define IPV4_INDEX 3
+#define IPV6_SIZE 4
struct hclge_fd_rule_tuples {
- u8 src_mac[6];
- u8 dst_mac[6];
- u32 src_ip[4];
- u32 dst_ip[4];
+ u8 src_mac[ETH_ALEN];
+ u8 dst_mac[ETH_ALEN];
+ /* Be compatible for ip address of both ipv4 and ipv6.
+ * For ipv4 address, we store it in src/dst_ip[3].
+ */
+ u32 src_ip[IPV6_SIZE];
+ u32 dst_ip[IPV6_SIZE];
u16 src_port;
u16 dst_port;
u16 vlan_tag1;
@@ -630,6 +648,8 @@ struct hclge_fd_rule {
u16 vf_id;
u16 queue_id;
u16 location;
+ u16 flow_id; /* only used for arfs */
+ enum HCLGE_FD_ACTIVE_RULE_TYPE rule_type;
};
struct hclge_fd_ad_data {
@@ -679,6 +699,20 @@ struct hclge_mac_tnl_stats {
u32 status;
};
+#define HCLGE_RESET_INTERVAL (10 * HZ)
+#define HCLGE_WAIT_RESET_DONE 100
+
+#pragma pack(1)
+struct hclge_vf_vlan_cfg {
+ u8 mbx_cmd;
+ u8 subcode;
+ u8 is_kill;
+ u16 vlan;
+ u16 proto;
+};
+
+#pragma pack()
+
/* For each bit of TCAM entry, it uses a pair of 'x' and
* 'y' to indicate which value to match, like below:
* ----------------------------------
@@ -806,10 +840,15 @@ struct hclge_dev {
struct hclge_vlan_type_cfg vlan_type_cfg;
unsigned long vlan_table[VLAN_N_VID][BITS_TO_LONGS(HCLGE_VPORT_NUM)];
+ unsigned long vf_vlan_full[BITS_TO_LONGS(HCLGE_VPORT_NUM)];
struct hclge_fd_cfg fd_cfg;
struct hlist_head fd_rule_list;
+ spinlock_t fd_rule_lock; /* protect fd_rule_list and fd_bmap */
u16 hclge_fd_rule_num;
+ u16 fd_arfs_expire_timer;
+ unsigned long fd_bmap[BITS_TO_LONGS(MAX_FD_FILTER_NUM)];
+ enum HCLGE_FD_ACTIVE_RULE_TYPE fd_active_type;
u8 fd_en;
u16 wanted_umv_size;
@@ -891,13 +930,14 @@ struct hclge_vport {
u32 bw_limit; /* VSI BW Limit (0 = disabled) */
u8 dwrr;
+ unsigned long vlan_del_fail_bmap[BITS_TO_LONGS(VLAN_N_VID)];
struct hclge_port_base_vlan_config port_base_vlan_cfg;
struct hclge_tx_vtag_cfg txvlan_cfg;
struct hclge_rx_vtag_cfg rxvlan_cfg;
u16 used_umv_num;
- int vport_id;
+ u16 vport_id;
struct hclge_dev *back; /* Back reference to associated dev */
struct hnae3_handle nic;
struct hnae3_handle roce;
@@ -959,7 +999,7 @@ int hclge_func_reset_cmd(struct hclge_dev *hdev, int func_id);
int hclge_vport_start(struct hclge_vport *vport);
void hclge_vport_stop(struct hclge_vport *vport);
int hclge_set_vport_mtu(struct hclge_vport *vport, int new_mtu);
-int hclge_dbg_run_cmd(struct hnae3_handle *handle, char *cmd_buf);
+int hclge_dbg_run_cmd(struct hnae3_handle *handle, const char *cmd_buf);
u16 hclge_covert_handle_qid_global(struct hnae3_handle *handle, u16 queue_id);
int hclge_notify_client(struct hclge_dev *hdev,
enum hnae3_reset_notify_type type);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c
index 0e04e63f2a94..a38ac7cfe16b 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c
@@ -29,6 +29,10 @@ static int hclge_gen_resp_to_vf(struct hclge_vport *vport,
"PF fail to gen resp to VF len %d exceeds max len %d\n",
resp_data_len,
HCLGE_MBX_MAX_RESP_DATA_SIZE);
+ /* If resp_data_len is too long, set the value to max length
+ * and return the msg to VF
+ */
+ resp_data_len = HCLGE_MBX_MAX_RESP_DATA_SIZE;
}
hclge_cmd_setup_basic_desc(&desc, HCLGEVF_OPC_MBX_PF_TO_VF, false);
@@ -93,7 +97,7 @@ int hclge_inform_reset_assert_to_vf(struct hclge_vport *vport)
else if (hdev->reset_type == HNAE3_FLR_RESET)
reset_type = HNAE3_VF_FULL_RESET;
else
- return -EINVAL;
+ reset_type = HNAE3_VF_FUNC_RESET;
memcpy(&msg_data[0], &reset_type, sizeof(u16));
@@ -192,12 +196,10 @@ static int hclge_map_unmap_ring_to_vf_vector(struct hclge_vport *vport, bool en,
return ret;
ret = hclge_bind_ring_with_vector(vport, vector_id, en, &ring_chain);
- if (ret)
- return ret;
hclge_free_vector_ring_chain(&ring_chain);
- return 0;
+ return ret;
}
static int hclge_set_vf_promisc_mode(struct hclge_vport *vport,
@@ -308,21 +310,23 @@ int hclge_push_vf_port_base_vlan_info(struct hclge_vport *vport, u8 vfid,
static int hclge_set_vf_vlan_cfg(struct hclge_vport *vport,
struct hclge_mbx_vf_to_pf_cmd *mbx_req)
{
+ struct hclge_vf_vlan_cfg *msg_cmd;
int status = 0;
- if (mbx_req->msg[1] == HCLGE_MBX_VLAN_FILTER) {
+ msg_cmd = (struct hclge_vf_vlan_cfg *)mbx_req->msg;
+ if (msg_cmd->subcode == HCLGE_MBX_VLAN_FILTER) {
struct hnae3_handle *handle = &vport->nic;
u16 vlan, proto;
bool is_kill;
- is_kill = !!mbx_req->msg[2];
- memcpy(&vlan, &mbx_req->msg[3], sizeof(vlan));
- memcpy(&proto, &mbx_req->msg[5], sizeof(proto));
+ is_kill = !!msg_cmd->is_kill;
+ vlan = msg_cmd->vlan;
+ proto = msg_cmd->proto;
status = hclge_set_vlan_filter(handle, cpu_to_be16(proto),
vlan, is_kill);
- } else if (mbx_req->msg[1] == HCLGE_MBX_VLAN_RX_OFF_CFG) {
+ } else if (msg_cmd->subcode == HCLGE_MBX_VLAN_RX_OFF_CFG) {
struct hnae3_handle *handle = &vport->nic;
- bool en = mbx_req->msg[2] ? true : false;
+ bool en = msg_cmd->is_kill ? true : false;
status = hclge_en_hw_strip_rxvtag(handle, en);
} else if (mbx_req->msg[1] == HCLGE_MBX_PORT_BASE_VLAN_CFG) {
@@ -365,13 +369,14 @@ static int hclge_get_vf_tcinfo(struct hclge_vport *vport,
{
struct hnae3_knic_private_info *kinfo = &vport->nic.kinfo;
u8 vf_tc_map = 0;
- int i, ret;
+ unsigned int i;
+ int ret;
for (i = 0; i < kinfo->num_tc; i++)
vf_tc_map |= BIT(i);
ret = hclge_gen_resp_to_vf(vport, mbx_req, 0, &vf_tc_map,
- sizeof(u8));
+ sizeof(vf_tc_map));
return ret;
}
@@ -553,7 +558,8 @@ void hclge_mbx_handler(struct hclge_dev *hdev)
struct hclge_mbx_vf_to_pf_cmd *req;
struct hclge_vport *vport;
struct hclge_desc *desc;
- int ret, flag;
+ unsigned int flag;
+ int ret;
/* handle all the mailbox requests in the queue */
while (!hclge_cmd_crq_empty(&hdev->hw)) {
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c
index 1e8134892d77..abb1b438564e 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c
@@ -55,9 +55,9 @@ static int hclge_mdio_write(struct mii_bus *bus, int phyid, int regnum,
mdio_cmd = (struct hclge_mdio_cfg_cmd *)desc.data;
hnae3_set_field(mdio_cmd->phyid, HCLGE_MDIO_PHYID_M,
- HCLGE_MDIO_PHYID_S, phyid);
+ HCLGE_MDIO_PHYID_S, (u32)phyid);
hnae3_set_field(mdio_cmd->phyad, HCLGE_MDIO_PHYREG_M,
- HCLGE_MDIO_PHYREG_S, regnum);
+ HCLGE_MDIO_PHYREG_S, (u32)regnum);
hnae3_set_bit(mdio_cmd->ctrl_bit, HCLGE_MDIO_CTRL_START_B, 1);
hnae3_set_field(mdio_cmd->ctrl_bit, HCLGE_MDIO_CTRL_ST_M,
@@ -93,9 +93,9 @@ static int hclge_mdio_read(struct mii_bus *bus, int phyid, int regnum)
mdio_cmd = (struct hclge_mdio_cfg_cmd *)desc.data;
hnae3_set_field(mdio_cmd->phyid, HCLGE_MDIO_PHYID_M,
- HCLGE_MDIO_PHYID_S, phyid);
+ HCLGE_MDIO_PHYID_S, (u32)phyid);
hnae3_set_field(mdio_cmd->phyad, HCLGE_MDIO_PHYREG_M,
- HCLGE_MDIO_PHYREG_S, regnum);
+ HCLGE_MDIO_PHYREG_S, (u32)regnum);
hnae3_set_bit(mdio_cmd->ctrl_bit, HCLGE_MDIO_CTRL_START_B, 1);
hnae3_set_field(mdio_cmd->ctrl_bit, HCLGE_MDIO_CTRL_ST_M,
@@ -224,6 +224,13 @@ int hclge_mac_connect_phy(struct hnae3_handle *handle)
linkmode_and(phydev->supported, phydev->supported, mask);
linkmode_copy(phydev->advertising, phydev->supported);
+ /* supported flag is Pause and Asym Pause, but default advertising
+ * should be rx on, tx on, so need clear Asym Pause in advertising
+ * flag
+ */
+ linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
+ phydev->advertising);
+
return 0;
}
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c
index a7bbb6d3091a..3f41fa2bc414 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c
@@ -43,18 +43,23 @@ enum hclge_shaper_level {
static int hclge_shaper_para_calc(u32 ir, u8 shaper_level,
u8 *ir_b, u8 *ir_u, u8 *ir_s)
{
+#define DIVISOR_CLK (1000 * 8)
+#define DIVISOR_IR_B_126 (126 * DIVISOR_CLK)
+
const u16 tick_array[HCLGE_SHAPER_LVL_CNT] = {
6 * 256, /* Prioriy level */
6 * 32, /* Prioriy group level */
6 * 8, /* Port level */
6 * 256 /* Qset level */
};
- u8 ir_u_calc = 0, ir_s_calc = 0;
+ u8 ir_u_calc = 0;
+ u8 ir_s_calc = 0;
u32 ir_calc;
u32 tick;
/* Calc tick */
- if (shaper_level >= HCLGE_SHAPER_LVL_CNT)
+ if (shaper_level >= HCLGE_SHAPER_LVL_CNT ||
+ ir > HCLGE_ETHER_MAX_RATE)
return -EINVAL;
tick = tick_array[shaper_level];
@@ -66,7 +71,7 @@ static int hclge_shaper_para_calc(u32 ir, u8 shaper_level,
* ir_calc = ---------------- * 1000
* tick * 1
*/
- ir_calc = (1008000 + (tick >> 1) - 1) / tick;
+ ir_calc = (DIVISOR_IR_B_126 + (tick >> 1) - 1) / tick;
if (ir_calc == ir) {
*ir_b = 126;
@@ -78,27 +83,28 @@ static int hclge_shaper_para_calc(u32 ir, u8 shaper_level,
/* Increasing the denominator to select ir_s value */
while (ir_calc > ir) {
ir_s_calc++;
- ir_calc = 1008000 / (tick * (1 << ir_s_calc));
+ ir_calc = DIVISOR_IR_B_126 / (tick * (1 << ir_s_calc));
}
if (ir_calc == ir)
*ir_b = 126;
else
- *ir_b = (ir * tick * (1 << ir_s_calc) + 4000) / 8000;
+ *ir_b = (ir * tick * (1 << ir_s_calc) +
+ (DIVISOR_CLK >> 1)) / DIVISOR_CLK;
} else {
/* Increasing the numerator to select ir_u value */
u32 numerator;
while (ir_calc < ir) {
ir_u_calc++;
- numerator = 1008000 * (1 << ir_u_calc);
+ numerator = DIVISOR_IR_B_126 * (1 << ir_u_calc);
ir_calc = (numerator + (tick >> 1)) / tick;
}
if (ir_calc == ir) {
*ir_b = 126;
} else {
- u32 denominator = (8000 * (1 << --ir_u_calc));
+ u32 denominator = (DIVISOR_CLK * (1 << --ir_u_calc));
*ir_b = (ir * tick + (denominator >> 1)) / denominator;
}
}
@@ -119,14 +125,13 @@ static int hclge_pfc_stats_get(struct hclge_dev *hdev,
opcode == HCLGE_OPC_QUERY_PFC_TX_PKT_CNT))
return -EINVAL;
- for (i = 0; i < HCLGE_TM_PFC_PKT_GET_CMD_NUM; i++) {
+ for (i = 0; i < HCLGE_TM_PFC_PKT_GET_CMD_NUM - 1; i++) {
hclge_cmd_setup_basic_desc(&desc[i], opcode, true);
- if (i != (HCLGE_TM_PFC_PKT_GET_CMD_NUM - 1))
- desc[i].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
- else
- desc[i].flag &= ~cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
+ desc[i].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
}
+ hclge_cmd_setup_basic_desc(&desc[i], opcode, true);
+
ret = hclge_cmd_send(&hdev->hw, desc, HCLGE_TM_PFC_PKT_GET_CMD_NUM);
if (ret)
return ret;
@@ -219,8 +224,7 @@ int hclge_pause_addr_cfg(struct hclge_dev *hdev, const u8 *mac_addr)
trans_gap = pause_param->pause_trans_gap;
trans_time = le16_to_cpu(pause_param->pause_trans_time);
- return hclge_pause_param_cfg(hdev, mac_addr, trans_gap,
- trans_time);
+ return hclge_pause_param_cfg(hdev, mac_addr, trans_gap, trans_time);
}
static int hclge_fill_pri_array(struct hclge_dev *hdev, u8 *pri, u8 pri_id)
@@ -361,29 +365,36 @@ static int hclge_tm_qs_weight_cfg(struct hclge_dev *hdev, u16 qs_id,
return hclge_cmd_send(&hdev->hw, &desc, 1);
}
+static u32 hclge_tm_get_shapping_para(u8 ir_b, u8 ir_u, u8 ir_s,
+ u8 bs_b, u8 bs_s)
+{
+ u32 shapping_para = 0;
+
+ hclge_tm_set_field(shapping_para, IR_B, ir_b);
+ hclge_tm_set_field(shapping_para, IR_U, ir_u);
+ hclge_tm_set_field(shapping_para, IR_S, ir_s);
+ hclge_tm_set_field(shapping_para, BS_B, bs_b);
+ hclge_tm_set_field(shapping_para, BS_S, bs_s);
+
+ return shapping_para;
+}
+
static int hclge_tm_pg_shapping_cfg(struct hclge_dev *hdev,
enum hclge_shap_bucket bucket, u8 pg_id,
- u8 ir_b, u8 ir_u, u8 ir_s, u8 bs_b, u8 bs_s)
+ u32 shapping_para)
{
struct hclge_pg_shapping_cmd *shap_cfg_cmd;
enum hclge_opcode_type opcode;
struct hclge_desc desc;
- u32 shapping_para = 0;
opcode = bucket ? HCLGE_OPC_TM_PG_P_SHAPPING :
- HCLGE_OPC_TM_PG_C_SHAPPING;
+ HCLGE_OPC_TM_PG_C_SHAPPING;
hclge_cmd_setup_basic_desc(&desc, opcode, false);
shap_cfg_cmd = (struct hclge_pg_shapping_cmd *)desc.data;
shap_cfg_cmd->pg_id = pg_id;
- hclge_tm_set_field(shapping_para, IR_B, ir_b);
- hclge_tm_set_field(shapping_para, IR_U, ir_u);
- hclge_tm_set_field(shapping_para, IR_S, ir_s);
- hclge_tm_set_field(shapping_para, BS_B, bs_b);
- hclge_tm_set_field(shapping_para, BS_S, bs_s);
-
shap_cfg_cmd->pg_shapping_para = cpu_to_le32(shapping_para);
return hclge_cmd_send(&hdev->hw, &desc, 1);
@@ -397,7 +408,7 @@ static int hclge_tm_port_shaper_cfg(struct hclge_dev *hdev)
u8 ir_u, ir_b, ir_s;
int ret;
- ret = hclge_shaper_para_calc(HCLGE_ETHER_MAX_RATE,
+ ret = hclge_shaper_para_calc(hdev->hw.mac.speed,
HCLGE_SHAPER_LVL_PORT,
&ir_b, &ir_u, &ir_s);
if (ret)
@@ -406,11 +417,9 @@ static int hclge_tm_port_shaper_cfg(struct hclge_dev *hdev)
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_PORT_SHAPPING, false);
shap_cfg_cmd = (struct hclge_port_shapping_cmd *)desc.data;
- hclge_tm_set_field(shapping_para, IR_B, ir_b);
- hclge_tm_set_field(shapping_para, IR_U, ir_u);
- hclge_tm_set_field(shapping_para, IR_S, ir_s);
- hclge_tm_set_field(shapping_para, BS_B, HCLGE_SHAPER_BS_U_DEF);
- hclge_tm_set_field(shapping_para, BS_S, HCLGE_SHAPER_BS_S_DEF);
+ shapping_para = hclge_tm_get_shapping_para(ir_b, ir_u, ir_s,
+ HCLGE_SHAPER_BS_U_DEF,
+ HCLGE_SHAPER_BS_S_DEF);
shap_cfg_cmd->port_shapping_para = cpu_to_le32(shapping_para);
@@ -419,16 +428,14 @@ static int hclge_tm_port_shaper_cfg(struct hclge_dev *hdev)
static int hclge_tm_pri_shapping_cfg(struct hclge_dev *hdev,
enum hclge_shap_bucket bucket, u8 pri_id,
- u8 ir_b, u8 ir_u, u8 ir_s,
- u8 bs_b, u8 bs_s)
+ u32 shapping_para)
{
struct hclge_pri_shapping_cmd *shap_cfg_cmd;
enum hclge_opcode_type opcode;
struct hclge_desc desc;
- u32 shapping_para = 0;
opcode = bucket ? HCLGE_OPC_TM_PRI_P_SHAPPING :
- HCLGE_OPC_TM_PRI_C_SHAPPING;
+ HCLGE_OPC_TM_PRI_C_SHAPPING;
hclge_cmd_setup_basic_desc(&desc, opcode, false);
@@ -436,12 +443,6 @@ static int hclge_tm_pri_shapping_cfg(struct hclge_dev *hdev,
shap_cfg_cmd->pri_id = pri_id;
- hclge_tm_set_field(shapping_para, IR_B, ir_b);
- hclge_tm_set_field(shapping_para, IR_U, ir_u);
- hclge_tm_set_field(shapping_para, IR_S, ir_s);
- hclge_tm_set_field(shapping_para, BS_B, bs_b);
- hclge_tm_set_field(shapping_para, BS_S, bs_s);
-
shap_cfg_cmd->pri_shapping_para = cpu_to_le32(shapping_para);
return hclge_cmd_send(&hdev->hw, &desc, 1);
@@ -531,6 +532,7 @@ static void hclge_tm_vport_tc_info_update(struct hclge_vport *vport)
max_rss_size = min_t(u16, hdev->rss_size_max,
vport->alloc_tqps / kinfo->num_tc);
+ /* Set to user value, no larger than max_rss_size. */
if (kinfo->req_rss_size != kinfo->rss_size && kinfo->req_rss_size &&
kinfo->req_rss_size <= max_rss_size) {
dev_info(&hdev->pdev->dev, "rss changes from %d to %d\n",
@@ -538,6 +540,7 @@ static void hclge_tm_vport_tc_info_update(struct hclge_vport *vport)
kinfo->rss_size = kinfo->req_rss_size;
} else if (kinfo->rss_size > max_rss_size ||
(!kinfo->req_rss_size && kinfo->rss_size < max_rss_size)) {
+ /* Set to the maximum specification value (max_rss_size). */
dev_info(&hdev->pdev->dev, "rss changes from %d to %d\n",
kinfo->rss_size, max_rss_size);
kinfo->rss_size = max_rss_size;
@@ -595,8 +598,10 @@ static void hclge_tm_tc_info_init(struct hclge_dev *hdev)
hdev->tm_info.prio_tc[i] =
(i >= hdev->tm_info.num_tc) ? 0 : i;
- /* DCB is enabled if we have more than 1 TC */
- if (hdev->tm_info.num_tc > 1)
+ /* DCB is enabled if we have more than 1 TC or pfc_en is
+ * non-zero.
+ */
+ if (hdev->tm_info.num_tc > 1 || hdev->tm_info.pfc_en)
hdev->flag |= HCLGE_FLAG_DCB_ENABLE;
else
hdev->flag &= ~HCLGE_FLAG_DCB_ENABLE;
@@ -604,12 +609,14 @@ static void hclge_tm_tc_info_init(struct hclge_dev *hdev)
static void hclge_tm_pg_info_init(struct hclge_dev *hdev)
{
+#define BW_PERCENT 100
+
u8 i;
for (i = 0; i < hdev->tm_info.num_pg; i++) {
int k;
- hdev->tm_info.pg_dwrr[i] = i ? 0 : 100;
+ hdev->tm_info.pg_dwrr[i] = i ? 0 : BW_PERCENT;
hdev->tm_info.pg_info[i].pg_id = i;
hdev->tm_info.pg_info[i].pg_sch_mode = HCLGE_SCH_MODE_DWRR;
@@ -621,7 +628,7 @@ static void hclge_tm_pg_info_init(struct hclge_dev *hdev)
hdev->tm_info.pg_info[i].tc_bit_map = hdev->hw_tc_map;
for (k = 0; k < hdev->tm_info.num_tc; k++)
- hdev->tm_info.pg_info[i].tc_dwrr[k] = 100;
+ hdev->tm_info.pg_info[i].tc_dwrr[k] = BW_PERCENT;
}
}
@@ -682,6 +689,7 @@ static int hclge_tm_pg_to_pri_map(struct hclge_dev *hdev)
static int hclge_tm_pg_shaper_cfg(struct hclge_dev *hdev)
{
u8 ir_u, ir_b, ir_s;
+ u32 shaper_para;
int ret;
u32 i;
@@ -699,18 +707,21 @@ static int hclge_tm_pg_shaper_cfg(struct hclge_dev *hdev)
if (ret)
return ret;
+ shaper_para = hclge_tm_get_shapping_para(0, 0, 0,
+ HCLGE_SHAPER_BS_U_DEF,
+ HCLGE_SHAPER_BS_S_DEF);
ret = hclge_tm_pg_shapping_cfg(hdev,
HCLGE_TM_SHAP_C_BUCKET, i,
- 0, 0, 0, HCLGE_SHAPER_BS_U_DEF,
- HCLGE_SHAPER_BS_S_DEF);
+ shaper_para);
if (ret)
return ret;
+ shaper_para = hclge_tm_get_shapping_para(ir_b, ir_u, ir_s,
+ HCLGE_SHAPER_BS_U_DEF,
+ HCLGE_SHAPER_BS_S_DEF);
ret = hclge_tm_pg_shapping_cfg(hdev,
HCLGE_TM_SHAP_P_BUCKET, i,
- ir_b, ir_u, ir_s,
- HCLGE_SHAPER_BS_U_DEF,
- HCLGE_SHAPER_BS_S_DEF);
+ shaper_para);
if (ret)
return ret;
}
@@ -730,8 +741,7 @@ static int hclge_tm_pg_dwrr_cfg(struct hclge_dev *hdev)
/* pg to prio */
for (i = 0; i < hdev->tm_info.num_pg; i++) {
/* Cfg dwrr */
- ret = hclge_tm_pg_weight_cfg(hdev, i,
- hdev->tm_info.pg_dwrr[i]);
+ ret = hclge_tm_pg_weight_cfg(hdev, i, hdev->tm_info.pg_dwrr[i]);
if (ret)
return ret;
}
@@ -811,6 +821,7 @@ static int hclge_tm_pri_q_qs_cfg(struct hclge_dev *hdev)
static int hclge_tm_pri_tc_base_shaper_cfg(struct hclge_dev *hdev)
{
u8 ir_u, ir_b, ir_s;
+ u32 shaper_para;
int ret;
u32 i;
@@ -822,17 +833,19 @@ static int hclge_tm_pri_tc_base_shaper_cfg(struct hclge_dev *hdev)
if (ret)
return ret;
- ret = hclge_tm_pri_shapping_cfg(
- hdev, HCLGE_TM_SHAP_C_BUCKET, i,
- 0, 0, 0, HCLGE_SHAPER_BS_U_DEF,
- HCLGE_SHAPER_BS_S_DEF);
+ shaper_para = hclge_tm_get_shapping_para(0, 0, 0,
+ HCLGE_SHAPER_BS_U_DEF,
+ HCLGE_SHAPER_BS_S_DEF);
+ ret = hclge_tm_pri_shapping_cfg(hdev, HCLGE_TM_SHAP_C_BUCKET, i,
+ shaper_para);
if (ret)
return ret;
- ret = hclge_tm_pri_shapping_cfg(
- hdev, HCLGE_TM_SHAP_P_BUCKET, i,
- ir_b, ir_u, ir_s, HCLGE_SHAPER_BS_U_DEF,
- HCLGE_SHAPER_BS_S_DEF);
+ shaper_para = hclge_tm_get_shapping_para(ir_b, ir_u, ir_s,
+ HCLGE_SHAPER_BS_U_DEF,
+ HCLGE_SHAPER_BS_S_DEF);
+ ret = hclge_tm_pri_shapping_cfg(hdev, HCLGE_TM_SHAP_P_BUCKET, i,
+ shaper_para);
if (ret)
return ret;
}
@@ -844,6 +857,7 @@ static int hclge_tm_pri_vnet_base_shaper_pri_cfg(struct hclge_vport *vport)
{
struct hclge_dev *hdev = vport->back;
u8 ir_u, ir_b, ir_s;
+ u32 shaper_para;
int ret;
ret = hclge_shaper_para_calc(vport->bw_limit, HCLGE_SHAPER_LVL_VF,
@@ -851,18 +865,19 @@ static int hclge_tm_pri_vnet_base_shaper_pri_cfg(struct hclge_vport *vport)
if (ret)
return ret;
+ shaper_para = hclge_tm_get_shapping_para(0, 0, 0,
+ HCLGE_SHAPER_BS_U_DEF,
+ HCLGE_SHAPER_BS_S_DEF);
ret = hclge_tm_pri_shapping_cfg(hdev, HCLGE_TM_SHAP_C_BUCKET,
- vport->vport_id,
- 0, 0, 0, HCLGE_SHAPER_BS_U_DEF,
- HCLGE_SHAPER_BS_S_DEF);
+ vport->vport_id, shaper_para);
if (ret)
return ret;
+ shaper_para = hclge_tm_get_shapping_para(ir_b, ir_u, ir_s,
+ HCLGE_SHAPER_BS_U_DEF,
+ HCLGE_SHAPER_BS_S_DEF);
ret = hclge_tm_pri_shapping_cfg(hdev, HCLGE_TM_SHAP_P_BUCKET,
- vport->vport_id,
- ir_b, ir_u, ir_s,
- HCLGE_SHAPER_BS_U_DEF,
- HCLGE_SHAPER_BS_S_DEF);
+ vport->vport_id, shaper_para);
if (ret)
return ret;
@@ -964,7 +979,7 @@ static int hclge_tm_ets_tc_dwrr_cfg(struct hclge_dev *hdev)
struct hclge_ets_tc_weight_cmd *ets_weight;
struct hclge_desc desc;
- int i;
+ unsigned int i;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_ETS_TC_WEIGHT, false);
ets_weight = (struct hclge_ets_tc_weight_cmd *)desc.data;
@@ -1124,6 +1139,9 @@ static int hclge_tm_schd_mode_vnet_base_cfg(struct hclge_vport *vport)
int ret;
u8 i;
+ if (vport->vport_id >= HNAE3_MAX_TC)
+ return -EINVAL;
+
ret = hclge_tm_pri_schd_mode_cfg(hdev, vport->vport_id);
if (ret)
return ret;
@@ -1212,8 +1230,8 @@ static int hclge_pause_param_setup_hw(struct hclge_dev *hdev)
struct hclge_mac *mac = &hdev->hw.mac;
return hclge_pause_param_cfg(hdev, mac->mac_addr,
- HCLGE_DEFAULT_PAUSE_TRANS_GAP,
- HCLGE_DEFAULT_PAUSE_TRANS_TIME);
+ HCLGE_DEFAULT_PAUSE_TRANS_GAP,
+ HCLGE_DEFAULT_PAUSE_TRANS_TIME);
}
static int hclge_pfc_setup_hw(struct hclge_dev *hdev)
@@ -1358,7 +1376,8 @@ void hclge_tm_prio_tc_info_update(struct hclge_dev *hdev, u8 *prio_tc)
void hclge_tm_schd_info_update(struct hclge_dev *hdev, u8 num_tc)
{
- u8 i, bit_map = 0;
+ u8 bit_map = 0;
+ u8 i;
hdev->tm_info.num_tc = num_tc;
@@ -1375,6 +1394,19 @@ void hclge_tm_schd_info_update(struct hclge_dev *hdev, u8 num_tc)
hclge_tm_schd_info_init(hdev);
}
+void hclge_tm_pfc_info_update(struct hclge_dev *hdev)
+{
+ /* DCB is enabled if we have more than 1 TC or pfc_en is
+ * non-zero.
+ */
+ if (hdev->tm_info.num_tc > 1 || hdev->tm_info.pfc_en)
+ hdev->flag |= HCLGE_FLAG_DCB_ENABLE;
+ else
+ hdev->flag &= ~HCLGE_FLAG_DCB_ENABLE;
+
+ hclge_pfc_info_init(hdev);
+}
+
int hclge_tm_init_hw(struct hclge_dev *hdev, bool init)
{
int ret;
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h
index f60e540c7a62..818610988d34 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h
@@ -12,7 +12,7 @@
#define HCLGE_TM_PORT_BASE_MODE_MSK BIT(0)
-#define HCLGE_DEFAULT_PAUSE_TRANS_GAP 0xFF
+#define HCLGE_DEFAULT_PAUSE_TRANS_GAP 0x7F
#define HCLGE_DEFAULT_PAUSE_TRANS_TIME 0xFFFF
/* SP or DWRR */
@@ -147,6 +147,7 @@ int hclge_pause_setup_hw(struct hclge_dev *hdev, bool init);
int hclge_tm_schd_setup_hw(struct hclge_dev *hdev);
void hclge_tm_prio_tc_info_update(struct hclge_dev *hdev, u8 *prio_tc);
void hclge_tm_schd_info_update(struct hclge_dev *hdev, u8 num_tc);
+void hclge_tm_pfc_info_update(struct hclge_dev *hdev);
int hclge_tm_dwrr_cfg(struct hclge_dev *hdev);
int hclge_tm_init_hw(struct hclge_dev *hdev, bool init);
int hclge_mac_pause_en_cfg(struct hclge_dev *hdev, bool tx, bool rx);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/Makefile b/drivers/net/ethernet/hisilicon/hns3/hns3vf/Makefile
index 6193f8fa7cf3..53804d95ea90 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/Makefile
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/Makefile
@@ -6,4 +6,4 @@
ccflags-y := -I $(srctree)/drivers/net/ethernet/hisilicon/hns3
obj-$(CONFIG_HNS3_HCLGEVF) += hclgevf.o
-hclgevf-objs = hclgevf_main.o hclgevf_cmd.o hclgevf_mbx.o \ No newline at end of file
+hclgevf-objs = hclgevf_main.o hclgevf_cmd.o hclgevf_mbx.o
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c
index 71f356fc2446..652b796044e3 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c
@@ -98,7 +98,6 @@ static void hclgevf_cmd_config_regs(struct hclgevf_cmq_ring *ring)
hclgevf_write_dev(hw, HCLGEVF_NIC_CSQ_BASEADDR_H_REG, reg_val);
reg_val = (ring->desc_num >> HCLGEVF_NIC_CMQ_DESC_NUM_S);
- reg_val |= HCLGEVF_NIC_CMQ_ENABLE;
hclgevf_write_dev(hw, HCLGEVF_NIC_CSQ_DEPTH_REG, reg_val);
hclgevf_write_dev(hw, HCLGEVF_NIC_CSQ_HEAD_REG, 0);
@@ -110,7 +109,6 @@ static void hclgevf_cmd_config_regs(struct hclgevf_cmq_ring *ring)
hclgevf_write_dev(hw, HCLGEVF_NIC_CRQ_BASEADDR_H_REG, reg_val);
reg_val = (ring->desc_num >> HCLGEVF_NIC_CMQ_DESC_NUM_S);
- reg_val |= HCLGEVF_NIC_CMQ_ENABLE;
hclgevf_write_dev(hw, HCLGEVF_NIC_CRQ_DEPTH_REG, reg_val);
hclgevf_write_dev(hw, HCLGEVF_NIC_CRQ_HEAD_REG, 0);
@@ -179,6 +177,38 @@ void hclgevf_cmd_setup_basic_desc(struct hclgevf_desc *desc,
desc->flag &= cpu_to_le16(~HCLGEVF_CMD_FLAG_WR);
}
+static int hclgevf_cmd_convert_err_code(u16 desc_ret)
+{
+ switch (desc_ret) {
+ case HCLGEVF_CMD_EXEC_SUCCESS:
+ return 0;
+ case HCLGEVF_CMD_NO_AUTH:
+ return -EPERM;
+ case HCLGEVF_CMD_NOT_SUPPORTED:
+ return -EOPNOTSUPP;
+ case HCLGEVF_CMD_QUEUE_FULL:
+ return -EXFULL;
+ case HCLGEVF_CMD_NEXT_ERR:
+ return -ENOSR;
+ case HCLGEVF_CMD_UNEXE_ERR:
+ return -ENOTBLK;
+ case HCLGEVF_CMD_PARA_ERR:
+ return -EINVAL;
+ case HCLGEVF_CMD_RESULT_ERR:
+ return -ERANGE;
+ case HCLGEVF_CMD_TIMEOUT:
+ return -ETIME;
+ case HCLGEVF_CMD_HILINK_ERR:
+ return -ENOLINK;
+ case HCLGEVF_CMD_QUEUE_ILLEGAL:
+ return -ENXIO;
+ case HCLGEVF_CMD_INVALID:
+ return -EBADR;
+ default:
+ return -EIO;
+ }
+}
+
/* hclgevf_cmd_send - send command to command queue
* @hw: pointer to the hw struct
* @desc: prefilled descriptor for describing the command
@@ -190,6 +220,7 @@ void hclgevf_cmd_setup_basic_desc(struct hclgevf_desc *desc,
int hclgevf_cmd_send(struct hclgevf_hw *hw, struct hclgevf_desc *desc, int num)
{
struct hclgevf_dev *hdev = (struct hclgevf_dev *)hw->hdev;
+ struct hclgevf_cmq_ring *csq = &hw->cmq.csq;
struct hclgevf_desc *desc_to_use;
bool complete = false;
u32 timeout = 0;
@@ -201,8 +232,17 @@ int hclgevf_cmd_send(struct hclgevf_hw *hw, struct hclgevf_desc *desc, int num)
spin_lock_bh(&hw->cmq.csq.lock);
- if (num > hclgevf_ring_space(&hw->cmq.csq) ||
- test_bit(HCLGEVF_STATE_CMD_DISABLE, &hdev->state)) {
+ if (test_bit(HCLGEVF_STATE_CMD_DISABLE, &hdev->state)) {
+ spin_unlock_bh(&hw->cmq.csq.lock);
+ return -EBUSY;
+ }
+
+ if (num > hclgevf_ring_space(&hw->cmq.csq)) {
+ /* If CMDQ ring is full, SW HEAD and HW HEAD may be different,
+ * need update the SW HEAD pointer csq->next_to_clean
+ */
+ csq->next_to_clean = hclgevf_read_dev(hw,
+ HCLGEVF_NIC_CSQ_HEAD_REG);
spin_unlock_bh(&hw->cmq.csq.lock);
return -EBUSY;
}
@@ -251,11 +291,7 @@ int hclgevf_cmd_send(struct hclgevf_hw *hw, struct hclgevf_desc *desc, int num)
else
retval = le16_to_cpu(desc[0].retval);
- if ((enum hclgevf_cmd_return_status)retval ==
- HCLGEVF_CMD_EXEC_SUCCESS)
- status = 0;
- else
- status = -EIO;
+ status = hclgevf_cmd_convert_err_code(retval);
hw->cmq.last_status = (enum hclgevf_cmd_status)retval;
ntc++;
handle++;
@@ -265,14 +301,13 @@ int hclgevf_cmd_send(struct hclgevf_hw *hw, struct hclgevf_desc *desc, int num)
}
if (!complete)
- status = -EAGAIN;
+ status = -EBADE;
/* Clean the command send queue */
handle = hclgevf_cmd_csq_clean(hw);
- if (handle != num) {
+ if (handle != num)
dev_warn(&hdev->pdev->dev,
"cleaned %d, need to clean %d\n", handle, num);
- }
spin_unlock_bh(&hw->cmq.csq.lock);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h
index 47030b42341f..127a434a56f3 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h
@@ -46,9 +46,17 @@ struct hclgevf_cmq_ring {
enum hclgevf_cmd_return_status {
HCLGEVF_CMD_EXEC_SUCCESS = 0,
- HCLGEVF_CMD_NO_AUTH = 1,
- HCLGEVF_CMD_NOT_EXEC = 2,
- HCLGEVF_CMD_QUEUE_FULL = 3,
+ HCLGEVF_CMD_NO_AUTH = 1,
+ HCLGEVF_CMD_NOT_SUPPORTED = 2,
+ HCLGEVF_CMD_QUEUE_FULL = 3,
+ HCLGEVF_CMD_NEXT_ERR = 4,
+ HCLGEVF_CMD_UNEXE_ERR = 5,
+ HCLGEVF_CMD_PARA_ERR = 6,
+ HCLGEVF_CMD_RESULT_ERR = 7,
+ HCLGEVF_CMD_TIMEOUT = 8,
+ HCLGEVF_CMD_HILINK_ERR = 9,
+ HCLGEVF_CMD_QUEUE_ILLEGAL = 10,
+ HCLGEVF_CMD_INVALID = 11,
};
enum hclgevf_cmd_status {
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
index 5d53467ee2d2..a13a0e101c3b 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
@@ -11,6 +11,8 @@
#define HCLGEVF_NAME "hclgevf"
+#define HCLGEVF_RESET_MAX_FAIL_CNT 5
+
static int hclgevf_reset_hdev(struct hclgevf_dev *hdev);
static struct hnae3_ae_algo ae_algovf;
@@ -83,8 +85,7 @@ static const u32 tqp_intr_reg_addr_list[] = {HCLGEVF_TQP_INTR_CTRL_REG,
HCLGEVF_TQP_INTR_GL2_REG,
HCLGEVF_TQP_INTR_RL_REG};
-static inline struct hclgevf_dev *hclgevf_ae_get_hdev(
- struct hnae3_handle *handle)
+static struct hclgevf_dev *hclgevf_ae_get_hdev(struct hnae3_handle *handle)
{
if (!handle->client)
return container_of(handle, struct hclgevf_dev, nic);
@@ -232,7 +233,7 @@ static int hclgevf_get_tc_info(struct hclgevf_dev *hdev)
int status;
status = hclgevf_send_mbx_msg(hdev, HCLGE_MBX_GET_TCINFO, 0, NULL, 0,
- true, &resp_msg, sizeof(u8));
+ true, &resp_msg, sizeof(resp_msg));
if (status) {
dev_err(&hdev->pdev->dev,
"VF request to get TC info from PF failed %d",
@@ -321,7 +322,8 @@ static u16 hclgevf_get_qid_global(struct hnae3_handle *handle, u16 queue_id)
memcpy(&msg_data[0], &queue_id, sizeof(queue_id));
ret = hclgevf_send_mbx_msg(hdev, HCLGE_MBX_GET_QID_IN_PF, 0, msg_data,
- 2, true, resp_data, 2);
+ sizeof(msg_data), true, resp_data,
+ sizeof(resp_data));
if (!ret)
qid_in_pf = *(u16 *)resp_data;
@@ -382,7 +384,7 @@ static int hclgevf_knic_setup(struct hclgevf_dev *hdev)
struct hnae3_handle *nic = &hdev->nic;
struct hnae3_knic_private_info *kinfo;
u16 new_tqps = hdev->num_tqps;
- int i;
+ unsigned int i;
kinfo = &nic->kinfo;
kinfo->num_tc = 0;
@@ -418,7 +420,7 @@ static void hclgevf_request_link_info(struct hclgevf_dev *hdev)
u8 resp_msg;
status = hclgevf_send_mbx_msg(hdev, HCLGE_MBX_GET_LINK_STATUS, 0, NULL,
- 0, false, &resp_msg, sizeof(u8));
+ 0, false, &resp_msg, sizeof(resp_msg));
if (status)
dev_err(&hdev->pdev->dev,
"VF failed to fetch link status(%d) from PF", status);
@@ -453,11 +455,13 @@ static void hclgevf_update_link_mode(struct hclgevf_dev *hdev)
u8 resp_msg;
send_msg = HCLGEVF_ADVERTISING;
- hclgevf_send_mbx_msg(hdev, HCLGE_MBX_GET_LINK_MODE, 0, &send_msg,
- sizeof(u8), false, &resp_msg, sizeof(u8));
+ hclgevf_send_mbx_msg(hdev, HCLGE_MBX_GET_LINK_MODE, 0,
+ &send_msg, sizeof(send_msg), false,
+ &resp_msg, sizeof(resp_msg));
send_msg = HCLGEVF_SUPPORTED;
- hclgevf_send_mbx_msg(hdev, HCLGE_MBX_GET_LINK_MODE, 0, &send_msg,
- sizeof(u8), false, &resp_msg, sizeof(u8));
+ hclgevf_send_mbx_msg(hdev, HCLGE_MBX_GET_LINK_MODE, 0,
+ &send_msg, sizeof(send_msg), false,
+ &resp_msg, sizeof(resp_msg));
}
static int hclgevf_set_handle_info(struct hclgevf_dev *hdev)
@@ -470,12 +474,6 @@ static int hclgevf_set_handle_info(struct hclgevf_dev *hdev)
nic->numa_node_mask = hdev->numa_node_mask;
nic->flags |= HNAE3_SUPPORT_VF;
- if (hdev->ae_dev->dev_type != HNAE3_DEV_KNIC) {
- dev_err(&hdev->pdev->dev, "unsupported device type %d\n",
- hdev->ae_dev->dev_type);
- return -EINVAL;
- }
-
ret = hclgevf_knic_setup(hdev);
if (ret)
dev_err(&hdev->pdev->dev, "VF knic setup failed %d\n",
@@ -544,14 +542,16 @@ static int hclgevf_set_rss_algo_key(struct hclgevf_dev *hdev,
const u8 hfunc, const u8 *key)
{
struct hclgevf_rss_config_cmd *req;
+ unsigned int key_offset = 0;
struct hclgevf_desc desc;
- int key_offset;
+ int key_counts;
int key_size;
int ret;
+ key_counts = HCLGEVF_RSS_KEY_SIZE;
req = (struct hclgevf_rss_config_cmd *)desc.data;
- for (key_offset = 0; key_offset < 3; key_offset++) {
+ while (key_counts) {
hclgevf_cmd_setup_basic_desc(&desc,
HCLGEVF_OPC_RSS_GENERIC_CONFIG,
false);
@@ -560,15 +560,12 @@ static int hclgevf_set_rss_algo_key(struct hclgevf_dev *hdev,
req->hash_config |=
(key_offset << HCLGEVF_RSS_HASH_KEY_OFFSET_B);
- if (key_offset == 2)
- key_size =
- HCLGEVF_RSS_KEY_SIZE - HCLGEVF_RSS_HASH_KEY_NUM * 2;
- else
- key_size = HCLGEVF_RSS_HASH_KEY_NUM;
-
+ key_size = min(HCLGEVF_RSS_HASH_KEY_NUM, key_counts);
memcpy(req->hash_key,
key + key_offset * HCLGEVF_RSS_HASH_KEY_NUM, key_size);
+ key_counts -= key_size;
+ key_offset++;
ret = hclgevf_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
@@ -631,7 +628,7 @@ static int hclgevf_set_rss_tc_mode(struct hclgevf_dev *hdev, u16 rss_size)
struct hclgevf_desc desc;
u16 roundup_size;
int status;
- int i;
+ unsigned int i;
req = (struct hclgevf_rss_tc_mode_cmd *)desc.data;
@@ -997,6 +994,8 @@ static int hclgevf_bind_ring_to_vector(struct hnae3_handle *handle, bool en,
u8 type;
req = (struct hclge_mbx_vf_to_pf_cmd *)desc.data;
+ type = en ? HCLGE_MBX_MAP_RING_TO_VECTOR :
+ HCLGE_MBX_UNMAP_RING_TO_VECTOR;
for (node = ring_chain; node; node = node->next) {
int idx_offset = HCLGE_MBX_RING_MAP_BASIC_MSG_NUM +
@@ -1006,9 +1005,6 @@ static int hclgevf_bind_ring_to_vector(struct hnae3_handle *handle, bool en,
hclgevf_cmd_setup_basic_desc(&desc,
HCLGEVF_OPC_MBX_VF_TO_PF,
false);
- type = en ?
- HCLGE_MBX_MAP_RING_TO_VECTOR :
- HCLGE_MBX_UNMAP_RING_TO_VECTOR;
req->msg[0] = type;
req->msg[1] = vector_id;
}
@@ -1134,7 +1130,7 @@ static int hclgevf_set_promisc_mode(struct hclgevf_dev *hdev, bool en_bc_pmc)
return hclgevf_cmd_set_promisc_mode(hdev, en_bc_pmc);
}
-static int hclgevf_tqp_enable(struct hclgevf_dev *hdev, int tqp_id,
+static int hclgevf_tqp_enable(struct hclgevf_dev *hdev, unsigned int tqp_id,
int stream_id, bool enable)
{
struct hclgevf_cfg_com_tqp_queue_cmd *req;
@@ -1147,7 +1143,8 @@ static int hclgevf_tqp_enable(struct hclgevf_dev *hdev, int tqp_id,
false);
req->tqp_id = cpu_to_le16(tqp_id & HCLGEVF_RING_ID_MASK);
req->stream_id = cpu_to_le16(stream_id);
- req->enable |= enable << HCLGEVF_TQP_ENABLE_B;
+ if (enable)
+ req->enable |= 1U << HCLGEVF_TQP_ENABLE_B;
status = hclgevf_cmd_send(&hdev->hw, &desc, 1);
if (status)
@@ -1193,7 +1190,7 @@ static int hclgevf_set_mac_addr(struct hnae3_handle *handle, void *p,
HCLGE_MBX_MAC_VLAN_UC_MODIFY;
status = hclgevf_send_mbx_msg(hdev, HCLGE_MBX_SET_UNICAST,
- subcode, msg_data, ETH_ALEN * 2,
+ subcode, msg_data, sizeof(msg_data),
true, NULL, 0);
if (!status)
ether_addr_copy(hdev->hw.mac.mac_addr, new_mac_addr);
@@ -1248,19 +1245,61 @@ static int hclgevf_set_vlan_filter(struct hnae3_handle *handle,
#define HCLGEVF_VLAN_MBX_MSG_LEN 5
struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
u8 msg_data[HCLGEVF_VLAN_MBX_MSG_LEN];
+ int ret;
- if (vlan_id > 4095)
+ if (vlan_id > HCLGEVF_MAX_VLAN_ID)
return -EINVAL;
if (proto != htons(ETH_P_8021Q))
return -EPROTONOSUPPORT;
+ /* When device is resetting, firmware is unable to handle
+ * mailbox. Just record the vlan id, and remove it after
+ * reset finished.
+ */
+ if (test_bit(HCLGEVF_STATE_RST_HANDLING, &hdev->state) && is_kill) {
+ set_bit(vlan_id, hdev->vlan_del_fail_bmap);
+ return -EBUSY;
+ }
+
msg_data[0] = is_kill;
memcpy(&msg_data[1], &vlan_id, sizeof(vlan_id));
memcpy(&msg_data[3], &proto, sizeof(proto));
- return hclgevf_send_mbx_msg(hdev, HCLGE_MBX_SET_VLAN,
- HCLGE_MBX_VLAN_FILTER, msg_data,
- HCLGEVF_VLAN_MBX_MSG_LEN, false, NULL, 0);
+ ret = hclgevf_send_mbx_msg(hdev, HCLGE_MBX_SET_VLAN,
+ HCLGE_MBX_VLAN_FILTER, msg_data,
+ HCLGEVF_VLAN_MBX_MSG_LEN, false, NULL, 0);
+
+ /* When remove hw vlan filter failed, record the vlan id,
+ * and try to remove it from hw later, to be consistence
+ * with stack.
+ */
+ if (is_kill && ret)
+ set_bit(vlan_id, hdev->vlan_del_fail_bmap);
+
+ return ret;
+}
+
+static void hclgevf_sync_vlan_filter(struct hclgevf_dev *hdev)
+{
+#define HCLGEVF_MAX_SYNC_COUNT 60
+ struct hnae3_handle *handle = &hdev->nic;
+ int ret, sync_cnt = 0;
+ u16 vlan_id;
+
+ vlan_id = find_first_bit(hdev->vlan_del_fail_bmap, VLAN_N_VID);
+ while (vlan_id != VLAN_N_VID) {
+ ret = hclgevf_set_vlan_filter(handle, htons(ETH_P_8021Q),
+ vlan_id, true);
+ if (ret)
+ return;
+
+ clear_bit(vlan_id, hdev->vlan_del_fail_bmap);
+ sync_cnt++;
+ if (sync_cnt >= HCLGEVF_MAX_SYNC_COUNT)
+ return;
+
+ vlan_id = find_first_bit(hdev->vlan_del_fail_bmap, VLAN_N_VID);
+ }
}
static int hclgevf_en_hw_strip_rxvtag(struct hnae3_handle *handle, bool enable)
@@ -1280,7 +1319,7 @@ static int hclgevf_reset_tqp(struct hnae3_handle *handle, u16 queue_id)
u8 msg_data[2];
int ret;
- memcpy(&msg_data[0], &queue_id, sizeof(queue_id));
+ memcpy(msg_data, &queue_id, sizeof(queue_id));
/* disable vf queue before send queue reset msg to PF */
ret = hclgevf_tqp_enable(hdev, queue_id, 0, false);
@@ -1288,7 +1327,7 @@ static int hclgevf_reset_tqp(struct hnae3_handle *handle, u16 queue_id)
return ret;
return hclgevf_send_mbx_msg(hdev, HCLGE_MBX_QUEUE_RESET, 0, msg_data,
- 2, true, NULL, 0);
+ sizeof(msg_data), true, NULL, 0);
}
static int hclgevf_set_mtu(struct hnae3_handle *handle, int new_mtu)
@@ -1306,6 +1345,10 @@ static int hclgevf_notify_client(struct hclgevf_dev *hdev,
struct hnae3_handle *handle = &hdev->nic;
int ret;
+ if (!test_bit(HCLGEVF_STATE_NIC_REGISTERED, &hdev->state) ||
+ !client)
+ return 0;
+
if (!client->ops->reset_notify)
return -EOPNOTSUPP;
@@ -1410,6 +1453,8 @@ static int hclgevf_reset_stack(struct hclgevf_dev *hdev)
static int hclgevf_reset_prepare_wait(struct hclgevf_dev *hdev)
{
+#define HCLGEVF_RESET_SYNC_TIME 100
+
int ret = 0;
switch (hdev->reset_type) {
@@ -1427,13 +1472,34 @@ static int hclgevf_reset_prepare_wait(struct hclgevf_dev *hdev)
}
set_bit(HCLGEVF_STATE_CMD_DISABLE, &hdev->state);
-
+ /* inform hardware that preparatory work is done */
+ msleep(HCLGEVF_RESET_SYNC_TIME);
+ hclgevf_write_dev(&hdev->hw, HCLGEVF_NIC_CSQ_DEPTH_REG,
+ HCLGEVF_NIC_CMQ_ENABLE);
dev_info(&hdev->pdev->dev, "prepare reset(%d) wait done, ret:%d\n",
hdev->reset_type, ret);
return ret;
}
+static void hclgevf_reset_err_handle(struct hclgevf_dev *hdev)
+{
+ hdev->rst_stats.rst_fail_cnt++;
+ dev_err(&hdev->pdev->dev, "failed to reset VF(%d)\n",
+ hdev->rst_stats.rst_fail_cnt);
+
+ if (hdev->rst_stats.rst_fail_cnt < HCLGEVF_RESET_MAX_FAIL_CNT)
+ set_bit(hdev->reset_type, &hdev->reset_pending);
+
+ if (hclgevf_is_reset_pending(hdev)) {
+ set_bit(HCLGEVF_RESET_PENDING, &hdev->reset_state);
+ hclgevf_reset_task_schedule(hdev);
+ } else {
+ hclgevf_write_dev(&hdev->hw, HCLGEVF_NIC_CSQ_DEPTH_REG,
+ HCLGEVF_NIC_CMQ_ENABLE);
+ }
+}
+
static int hclgevf_reset(struct hclgevf_dev *hdev)
{
struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev);
@@ -1490,19 +1556,13 @@ static int hclgevf_reset(struct hclgevf_dev *hdev)
hdev->last_reset_time = jiffies;
ae_dev->reset_type = HNAE3_NONE_RESET;
hdev->rst_stats.rst_done_cnt++;
+ hdev->rst_stats.rst_fail_cnt = 0;
return ret;
err_reset_lock:
rtnl_unlock();
err_reset:
- /* When VF reset failed, only the higher level reset asserted by PF
- * can restore it, so re-initialize the command queue to receive
- * this higher reset event.
- */
- hclgevf_cmd_init(hdev);
- dev_err(&hdev->pdev->dev, "failed to reset VF\n");
- if (hclgevf_is_reset_pending(hdev))
- hclgevf_reset_task_schedule(hdev);
+ hclgevf_reset_err_handle(hdev);
return ret;
}
@@ -1612,7 +1672,8 @@ static void hclgevf_get_misc_vector(struct hclgevf_dev *hdev)
void hclgevf_reset_task_schedule(struct hclgevf_dev *hdev)
{
- if (!test_bit(HCLGEVF_STATE_RST_SERVICE_SCHED, &hdev->state)) {
+ if (!test_bit(HCLGEVF_STATE_RST_SERVICE_SCHED, &hdev->state) &&
+ !test_bit(HCLGEVF_STATE_REMOVING, &hdev->state)) {
set_bit(HCLGEVF_STATE_RST_SERVICE_SCHED, &hdev->state);
schedule_work(&hdev->rst_service_task);
}
@@ -1648,7 +1709,8 @@ static void hclgevf_service_timer(struct timer_list *t)
{
struct hclgevf_dev *hdev = from_timer(hdev, t, service_timer);
- mod_timer(&hdev->service_timer, jiffies + 5 * HZ);
+ mod_timer(&hdev->service_timer, jiffies +
+ HCLGEVF_GENERAL_TASK_INTERVAL * HZ);
hdev->stats_timer++;
hclgevf_task_schedule(hdev);
@@ -1668,9 +1730,9 @@ static void hclgevf_reset_service_task(struct work_struct *work)
if (test_and_clear_bit(HCLGEVF_RESET_PENDING,
&hdev->reset_state)) {
/* PF has initmated that it is about to reset the hardware.
- * We now have to poll & check if harware has actually completed
- * the reset sequence. On hardware reset completion, VF needs to
- * reset the client and ae device.
+ * We now have to poll & check if hardware has actually
+ * completed the reset sequence. On hardware reset completion,
+ * VF needs to reset the client and ae device.
*/
hdev->reset_attempts = 0;
@@ -1686,7 +1748,7 @@ static void hclgevf_reset_service_task(struct work_struct *work)
} else if (test_and_clear_bit(HCLGEVF_RESET_REQUESTED,
&hdev->reset_state)) {
/* we could be here when either of below happens:
- * 1. reset was initiated due to watchdog timeout due to
+ * 1. reset was initiated due to watchdog timeout caused by
* a. IMP was earlier reset and our TX got choked down and
* which resulted in watchdog reacting and inducing VF
* reset. This also means our cmdq would be unreliable.
@@ -1748,7 +1810,8 @@ static void hclgevf_keep_alive_timer(struct timer_list *t)
struct hclgevf_dev *hdev = from_timer(hdev, t, keep_alive_timer);
schedule_work(&hdev->keep_alive_task);
- mod_timer(&hdev->keep_alive_timer, jiffies + 2 * HZ);
+ mod_timer(&hdev->keep_alive_timer, jiffies +
+ HCLGEVF_KEEP_ALIVE_TASK_INTERVAL * HZ);
}
static void hclgevf_keep_alive_task(struct work_struct *work)
@@ -1763,7 +1826,7 @@ static void hclgevf_keep_alive_task(struct work_struct *work)
return;
ret = hclgevf_send_mbx_msg(hdev, HCLGE_MBX_KEEP_ALIVE, 0, NULL,
- 0, false, &respmsg, sizeof(u8));
+ 0, false, &respmsg, sizeof(respmsg));
if (ret)
dev_err(&hdev->pdev->dev,
"VF sends keep alive cmd failed(=%d)\n", ret);
@@ -1789,6 +1852,8 @@ static void hclgevf_service_task(struct work_struct *work)
hclgevf_update_link_mode(hdev);
+ hclgevf_sync_vlan_filter(hdev);
+
hclgevf_deferred_task_schedule(hdev);
clear_bit(HCLGEVF_STATE_SERVICE_SCHED, &hdev->state);
@@ -1995,7 +2060,7 @@ static int hclgevf_rss_init_hw(struct hclgevf_dev *hdev)
}
- /* Initialize RSS indirect table for each vport */
+ /* Initialize RSS indirect table */
for (i = 0; i < HCLGEVF_RSS_IND_TBL_SIZE; i++)
rss_cfg->rss_indirection_tbl[i] = i % hdev->rss_size_max;
@@ -2008,9 +2073,6 @@ static int hclgevf_rss_init_hw(struct hclgevf_dev *hdev)
static int hclgevf_init_vlan_config(struct hclgevf_dev *hdev)
{
- /* other vlan config(like, VLAN TX/RX offload) would also be added
- * here later
- */
return hclgevf_set_vlan_filter(&hdev->nic, htons(ETH_P_8021Q), 0,
false);
}
@@ -2032,7 +2094,6 @@ static int hclgevf_ae_start(struct hnae3_handle *handle)
{
struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
- /* reset tqp stats */
hclgevf_reset_tqp_stats(handle);
hclgevf_request_link_info(hdev);
@@ -2056,7 +2117,6 @@ static void hclgevf_ae_stop(struct hnae3_handle *handle)
if (hclgevf_reset_tqp(handle, i))
break;
- /* reset tqp stats */
hclgevf_reset_tqp_stats(handle);
hclgevf_update_link_status(hdev, 0);
}
@@ -2080,7 +2140,8 @@ static int hclgevf_client_start(struct hnae3_handle *handle)
if (ret)
return ret;
- mod_timer(&hdev->keep_alive_timer, jiffies + 2 * HZ);
+ mod_timer(&hdev->keep_alive_timer, jiffies +
+ HCLGEVF_KEEP_ALIVE_TASK_INTERVAL * HZ);
return 0;
}
@@ -2123,6 +2184,7 @@ static void hclgevf_state_init(struct hclgevf_dev *hdev)
static void hclgevf_state_uninit(struct hclgevf_dev *hdev)
{
set_bit(HCLGEVF_STATE_DOWN, &hdev->state);
+ set_bit(HCLGEVF_STATE_REMOVING, &hdev->state);
if (hdev->keep_alive_timer.function)
del_timer_sync(&hdev->keep_alive_timer);
@@ -2249,49 +2311,68 @@ static void hclgevf_info_show(struct hclgevf_dev *hdev)
dev_info(dev, "VF info end.\n");
}
-static int hclgevf_init_client_instance(struct hnae3_client *client,
- struct hnae3_ae_dev *ae_dev)
+static int hclgevf_init_nic_client_instance(struct hnae3_ae_dev *ae_dev,
+ struct hnae3_client *client)
{
struct hclgevf_dev *hdev = ae_dev->priv;
int ret;
- switch (client->type) {
- case HNAE3_CLIENT_KNIC:
- hdev->nic_client = client;
- hdev->nic.client = client;
+ ret = client->ops->init_instance(&hdev->nic);
+ if (ret)
+ return ret;
- ret = client->ops->init_instance(&hdev->nic);
- if (ret)
- goto clear_nic;
+ set_bit(HCLGEVF_STATE_NIC_REGISTERED, &hdev->state);
+ hnae3_set_client_init_flag(client, ae_dev, 1);
- hnae3_set_client_init_flag(client, ae_dev, 1);
+ if (netif_msg_drv(&hdev->nic))
+ hclgevf_info_show(hdev);
- if (netif_msg_drv(&hdev->nic))
- hclgevf_info_show(hdev);
+ return 0;
+}
- if (hdev->roce_client && hnae3_dev_roce_supported(hdev)) {
- struct hnae3_client *rc = hdev->roce_client;
+static int hclgevf_init_roce_client_instance(struct hnae3_ae_dev *ae_dev,
+ struct hnae3_client *client)
+{
+ struct hclgevf_dev *hdev = ae_dev->priv;
+ int ret;
- ret = hclgevf_init_roce_base_info(hdev);
- if (ret)
- goto clear_roce;
- ret = rc->ops->init_instance(&hdev->roce);
- if (ret)
- goto clear_roce;
+ if (!hnae3_dev_roce_supported(hdev) || !hdev->roce_client ||
+ !hdev->nic_client)
+ return 0;
- hnae3_set_client_init_flag(hdev->roce_client, ae_dev,
- 1);
- }
- break;
- case HNAE3_CLIENT_UNIC:
+ ret = hclgevf_init_roce_base_info(hdev);
+ if (ret)
+ return ret;
+
+ ret = client->ops->init_instance(&hdev->roce);
+ if (ret)
+ return ret;
+
+ hnae3_set_client_init_flag(client, ae_dev, 1);
+
+ return 0;
+}
+
+static int hclgevf_init_client_instance(struct hnae3_client *client,
+ struct hnae3_ae_dev *ae_dev)
+{
+ struct hclgevf_dev *hdev = ae_dev->priv;
+ int ret;
+
+ switch (client->type) {
+ case HNAE3_CLIENT_KNIC:
hdev->nic_client = client;
hdev->nic.client = client;
- ret = client->ops->init_instance(&hdev->nic);
+ ret = hclgevf_init_nic_client_instance(ae_dev, client);
if (ret)
goto clear_nic;
- hnae3_set_client_init_flag(client, ae_dev, 1);
+ ret = hclgevf_init_roce_client_instance(ae_dev,
+ hdev->roce_client);
+ if (ret)
+ goto clear_roce;
+
break;
case HNAE3_CLIENT_ROCE:
if (hnae3_dev_roce_supported(hdev)) {
@@ -2299,17 +2380,10 @@ static int hclgevf_init_client_instance(struct hnae3_client *client,
hdev->roce.client = client;
}
- if (hdev->roce_client && hdev->nic_client) {
- ret = hclgevf_init_roce_base_info(hdev);
- if (ret)
- goto clear_roce;
-
- ret = client->ops->init_instance(&hdev->roce);
- if (ret)
- goto clear_roce;
- }
+ ret = hclgevf_init_roce_client_instance(ae_dev, client);
+ if (ret)
+ goto clear_roce;
- hnae3_set_client_init_flag(client, ae_dev, 1);
break;
default:
return -EINVAL;
@@ -2342,6 +2416,8 @@ static void hclgevf_uninit_client_instance(struct hnae3_client *client,
/* un-init nic/unic, if this was not called by roce client */
if (client->ops->uninit_instance && hdev->nic_client &&
client->type != HNAE3_CLIENT_ROCE) {
+ clear_bit(HCLGEVF_STATE_NIC_REGISTERED, &hdev->state);
+
client->ops->uninit_instance(&hdev->nic, 0);
hdev->nic_client = NULL;
hdev->nic.client = NULL;
@@ -2512,6 +2588,12 @@ static int hclgevf_reset_hdev(struct hclgevf_dev *hdev)
return ret;
}
+ if (pdev->revision >= 0x21) {
+ ret = hclgevf_set_promisc_mode(hdev, true);
+ if (ret)
+ return ret;
+ }
+
dev_info(&hdev->pdev->dev, "Reset done\n");
return 0;
@@ -2591,9 +2673,11 @@ static int hclgevf_init_hdev(struct hclgevf_dev *hdev)
* firmware makes sure broadcast packets can be accepted.
* For revision 0x21, default to enable broadcast promisc mode.
*/
- ret = hclgevf_set_promisc_mode(hdev, true);
- if (ret)
- goto err_config;
+ if (pdev->revision >= 0x21) {
+ ret = hclgevf_set_promisc_mode(hdev, true);
+ if (ret)
+ goto err_config;
+ }
/* Initialize RSS for this VF */
ret = hclgevf_rss_init_hw(hdev);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h
index cc52f54f8c08..5a9e30998a8f 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h
@@ -4,6 +4,7 @@
#ifndef __HCLGEVF_MAIN_H
#define __HCLGEVF_MAIN_H
#include <linux/fs.h>
+#include <linux/if_vlan.h>
#include <linux/types.h>
#include "hclge_mbx.h"
#include "hclgevf_cmd.h"
@@ -12,9 +13,12 @@
#define HCLGEVF_MOD_VERSION "1.0"
#define HCLGEVF_DRIVER_NAME "hclgevf"
+#define HCLGEVF_MAX_VLAN_ID 4095
#define HCLGEVF_MISC_VECTOR_NUM 0
#define HCLGEVF_INVALID_VPORT 0xffff
+#define HCLGEVF_GENERAL_TASK_INTERVAL 5
+#define HCLGEVF_KEEP_ALIVE_TASK_INTERVAL 2
/* This number in actual depends upon the total number of VFs
* created by physical function. But the maximum number of
@@ -130,6 +134,8 @@ enum hclgevf_states {
HCLGEVF_STATE_DOWN,
HCLGEVF_STATE_DISABLED,
HCLGEVF_STATE_IRQ_INITED,
+ HCLGEVF_STATE_REMOVING,
+ HCLGEVF_STATE_NIC_REGISTERED,
/* task states */
HCLGEVF_STATE_SERVICE_SCHED,
HCLGEVF_STATE_RST_SERVICE_SCHED,
@@ -220,6 +226,7 @@ struct hclgevf_rst_stats {
u32 vf_rst_cnt; /* the number of VF reset */
u32 rst_done_cnt; /* the number of reset completed */
u32 hw_rst_done_cnt; /* the number of HW reset completed */
+ u32 rst_fail_cnt; /* the number of VF reset fail */
};
struct hclgevf_dev {
@@ -265,6 +272,8 @@ struct hclgevf_dev {
u16 *vector_status;
int *vector_irq;
+ unsigned long vlan_del_fail_bmap[BITS_TO_LONGS(VLAN_N_VID)];
+
bool mbx_event_pending;
struct hclgevf_mbx_resp_status mbx_resp; /* mailbox response */
struct hclgevf_mbx_arq_ring arq; /* mailbox async rx queue */
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c
index 30f2e9352cf3..f60b80bd605e 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c
@@ -102,7 +102,8 @@ int hclgevf_send_mbx_msg(struct hclgevf_dev *hdev, u16 code, u16 subcode,
~HCLGE_MBX_NEED_RESP_BIT;
req->msg[0] = code;
req->msg[1] = subcode;
- memcpy(&req->msg[2], msg_data, msg_len);
+ if (msg_data)
+ memcpy(&req->msg[2], msg_data, msg_len);
/* synchronous send */
if (need_resp) {
diff --git a/drivers/net/ethernet/hisilicon/hns_mdio.c b/drivers/net/ethernet/hisilicon/hns_mdio.c
index 918cab1c61cd..3e863a71c513 100644
--- a/drivers/net/ethernet/hisilicon/hns_mdio.c
+++ b/drivers/net/ethernet/hisilicon/hns_mdio.c
@@ -417,7 +417,6 @@ static int hns_mdio_probe(struct platform_device *pdev)
{
struct hns_mdio_device *mdio_dev;
struct mii_bus *new_bus;
- struct resource *res;
int ret = -ENODEV;
if (!pdev) {
@@ -442,8 +441,7 @@ static int hns_mdio_probe(struct platform_device *pdev)
new_bus->priv = mdio_dev;
new_bus->parent = &pdev->dev;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- mdio_dev->vbase = devm_ioremap_resource(&pdev->dev, res);
+ mdio_dev->vbase = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(mdio_dev->vbase)) {
ret = PTR_ERR(mdio_dev->vbase);
return ret;
diff --git a/drivers/net/ethernet/huawei/hinic/Makefile b/drivers/net/ethernet/huawei/hinic/Makefile
index 99de5b6607d5..fe88ab88cacc 100644
--- a/drivers/net/ethernet/huawei/hinic/Makefile
+++ b/drivers/net/ethernet/huawei/hinic/Makefile
@@ -4,4 +4,4 @@ obj-$(CONFIG_HINIC) += hinic.o
hinic-y := hinic_main.o hinic_tx.o hinic_rx.o hinic_port.o hinic_hw_dev.o \
hinic_hw_io.o hinic_hw_qp.o hinic_hw_cmdq.o hinic_hw_wq.o \
hinic_hw_mgmt.o hinic_hw_api_cmd.o hinic_hw_eqs.o hinic_hw_if.o \
- hinic_common.o
+ hinic_common.o hinic_ethtool.o
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_dev.h b/drivers/net/ethernet/huawei/hinic/hinic_dev.h
index 353276fdcaed..a209b14160cc 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_dev.h
+++ b/drivers/net/ethernet/huawei/hinic/hinic_dev.h
@@ -22,6 +22,7 @@
enum hinic_flags {
HINIC_LINK_UP = BIT(0),
HINIC_INTF_UP = BIT(1),
+ HINIC_RSS_ENABLE = BIT(2),
};
struct hinic_rx_mode_work {
@@ -29,6 +30,23 @@ struct hinic_rx_mode_work {
u32 rx_mode;
};
+struct hinic_rss_type {
+ u8 tcp_ipv6_ext;
+ u8 ipv6_ext;
+ u8 tcp_ipv6;
+ u8 ipv6;
+ u8 tcp_ipv4;
+ u8 ipv4;
+ u8 udp_ipv6;
+ u8 udp_ipv4;
+};
+
+enum hinic_rss_hash_type {
+ HINIC_RSS_HASH_ENGINE_TYPE_XOR,
+ HINIC_RSS_HASH_ENGINE_TYPE_TOEP,
+ HINIC_RSS_HASH_ENGINE_TYPE_MAX,
+};
+
struct hinic_dev {
struct net_device *netdev;
struct hinic_hwdev *hwdev;
@@ -36,6 +54,8 @@ struct hinic_dev {
u32 msg_enable;
unsigned int tx_weight;
unsigned int rx_weight;
+ u16 num_qps;
+ u16 max_qps;
unsigned int flags;
@@ -50,6 +70,14 @@ struct hinic_dev {
struct hinic_txq_stats tx_stats;
struct hinic_rxq_stats rx_stats;
+
+ u8 rss_tmpl_idx;
+ u8 rss_hash_engine;
+ u16 num_rss;
+ u16 rss_limit;
+ struct hinic_rss_type rss_type;
+ u8 *rss_hkey_user;
+ s32 *rss_indir_user;
};
#endif
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c b/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c
new file mode 100644
index 000000000000..60ec48fe4144
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c
@@ -0,0 +1,762 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Huawei HiNIC PCI Express Linux driver
+ * Copyright(c) 2017 Huawei Technologies Co., Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/etherdevice.h>
+#include <linux/netdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/ethtool.h>
+#include <linux/vmalloc.h>
+
+#include "hinic_hw_qp.h"
+#include "hinic_hw_dev.h"
+#include "hinic_port.h"
+#include "hinic_tx.h"
+#include "hinic_rx.h"
+#include "hinic_dev.h"
+
+static void set_link_speed(struct ethtool_link_ksettings *link_ksettings,
+ enum hinic_speed speed)
+{
+ switch (speed) {
+ case HINIC_SPEED_10MB_LINK:
+ link_ksettings->base.speed = SPEED_10;
+ break;
+
+ case HINIC_SPEED_100MB_LINK:
+ link_ksettings->base.speed = SPEED_100;
+ break;
+
+ case HINIC_SPEED_1000MB_LINK:
+ link_ksettings->base.speed = SPEED_1000;
+ break;
+
+ case HINIC_SPEED_10GB_LINK:
+ link_ksettings->base.speed = SPEED_10000;
+ break;
+
+ case HINIC_SPEED_25GB_LINK:
+ link_ksettings->base.speed = SPEED_25000;
+ break;
+
+ case HINIC_SPEED_40GB_LINK:
+ link_ksettings->base.speed = SPEED_40000;
+ break;
+
+ case HINIC_SPEED_100GB_LINK:
+ link_ksettings->base.speed = SPEED_100000;
+ break;
+
+ default:
+ link_ksettings->base.speed = SPEED_UNKNOWN;
+ break;
+ }
+}
+
+static int hinic_get_link_ksettings(struct net_device *netdev,
+ struct ethtool_link_ksettings
+ *link_ksettings)
+{
+ struct hinic_dev *nic_dev = netdev_priv(netdev);
+ enum hinic_port_link_state link_state;
+ struct hinic_port_cap port_cap;
+ int err;
+
+ ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising);
+ ethtool_link_ksettings_add_link_mode(link_ksettings, supported,
+ Autoneg);
+
+ link_ksettings->base.speed = SPEED_UNKNOWN;
+ link_ksettings->base.autoneg = AUTONEG_DISABLE;
+ link_ksettings->base.duplex = DUPLEX_UNKNOWN;
+
+ err = hinic_port_get_cap(nic_dev, &port_cap);
+ if (err)
+ return err;
+
+ err = hinic_port_link_state(nic_dev, &link_state);
+ if (err)
+ return err;
+
+ if (link_state != HINIC_LINK_STATE_UP)
+ return err;
+
+ set_link_speed(link_ksettings, port_cap.speed);
+
+ if (!!(port_cap.autoneg_cap & HINIC_AUTONEG_SUPPORTED))
+ ethtool_link_ksettings_add_link_mode(link_ksettings,
+ advertising, Autoneg);
+
+ if (port_cap.autoneg_state == HINIC_AUTONEG_ACTIVE)
+ link_ksettings->base.autoneg = AUTONEG_ENABLE;
+
+ link_ksettings->base.duplex = (port_cap.duplex == HINIC_DUPLEX_FULL) ?
+ DUPLEX_FULL : DUPLEX_HALF;
+ return 0;
+}
+
+static void hinic_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *info)
+{
+ struct hinic_dev *nic_dev = netdev_priv(netdev);
+ u8 mgmt_ver[HINIC_MGMT_VERSION_MAX_LEN] = {0};
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic_hwif *hwif = hwdev->hwif;
+ int err;
+
+ strlcpy(info->driver, HINIC_DRV_NAME, sizeof(info->driver));
+ strlcpy(info->bus_info, pci_name(hwif->pdev), sizeof(info->bus_info));
+
+ err = hinic_get_mgmt_version(nic_dev, mgmt_ver);
+ if (err)
+ return;
+
+ snprintf(info->fw_version, sizeof(info->fw_version), "%s", mgmt_ver);
+}
+
+static void hinic_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ ring->rx_max_pending = HINIC_RQ_DEPTH;
+ ring->tx_max_pending = HINIC_SQ_DEPTH;
+ ring->rx_pending = HINIC_RQ_DEPTH;
+ ring->tx_pending = HINIC_SQ_DEPTH;
+}
+
+static void hinic_get_channels(struct net_device *netdev,
+ struct ethtool_channels *channels)
+{
+ struct hinic_dev *nic_dev = netdev_priv(netdev);
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+
+ channels->max_rx = hwdev->nic_cap.max_qps;
+ channels->max_tx = hwdev->nic_cap.max_qps;
+ channels->max_other = 0;
+ channels->max_combined = 0;
+ channels->rx_count = hinic_hwdev_num_qps(hwdev);
+ channels->tx_count = hinic_hwdev_num_qps(hwdev);
+ channels->other_count = 0;
+ channels->combined_count = 0;
+}
+
+static int hinic_get_rss_hash_opts(struct hinic_dev *nic_dev,
+ struct ethtool_rxnfc *cmd)
+{
+ struct hinic_rss_type rss_type = { 0 };
+ int err;
+
+ cmd->data = 0;
+
+ if (!(nic_dev->flags & HINIC_RSS_ENABLE))
+ return 0;
+
+ err = hinic_get_rss_type(nic_dev, nic_dev->rss_tmpl_idx,
+ &rss_type);
+ if (err)
+ return err;
+
+ cmd->data = RXH_IP_SRC | RXH_IP_DST;
+ switch (cmd->flow_type) {
+ case TCP_V4_FLOW:
+ if (rss_type.tcp_ipv4)
+ cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ break;
+ case TCP_V6_FLOW:
+ if (rss_type.tcp_ipv6)
+ cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ break;
+ case UDP_V4_FLOW:
+ if (rss_type.udp_ipv4)
+ cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ break;
+ case UDP_V6_FLOW:
+ if (rss_type.udp_ipv6)
+ cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ break;
+ case IPV4_FLOW:
+ case IPV6_FLOW:
+ break;
+ default:
+ cmd->data = 0;
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int set_l4_rss_hash_ops(struct ethtool_rxnfc *cmd,
+ struct hinic_rss_type *rss_type)
+{
+ u8 rss_l4_en = 0;
+
+ switch (cmd->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
+ case 0:
+ rss_l4_en = 0;
+ break;
+ case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
+ rss_l4_en = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (cmd->flow_type) {
+ case TCP_V4_FLOW:
+ rss_type->tcp_ipv4 = rss_l4_en;
+ break;
+ case TCP_V6_FLOW:
+ rss_type->tcp_ipv6 = rss_l4_en;
+ break;
+ case UDP_V4_FLOW:
+ rss_type->udp_ipv4 = rss_l4_en;
+ break;
+ case UDP_V6_FLOW:
+ rss_type->udp_ipv6 = rss_l4_en;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int hinic_set_rss_hash_opts(struct hinic_dev *nic_dev,
+ struct ethtool_rxnfc *cmd)
+{
+ struct hinic_rss_type *rss_type = &nic_dev->rss_type;
+ int err;
+
+ if (!(nic_dev->flags & HINIC_RSS_ENABLE)) {
+ cmd->data = 0;
+ return -EOPNOTSUPP;
+ }
+
+ /* RSS does not support anything other than hashing
+ * to queues on src and dst IPs and ports
+ */
+ if (cmd->data & ~(RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 |
+ RXH_L4_B_2_3))
+ return -EINVAL;
+
+ /* We need at least the IP SRC and DEST fields for hashing */
+ if (!(cmd->data & RXH_IP_SRC) || !(cmd->data & RXH_IP_DST))
+ return -EINVAL;
+
+ err = hinic_get_rss_type(nic_dev,
+ nic_dev->rss_tmpl_idx, rss_type);
+ if (err)
+ return -EFAULT;
+
+ switch (cmd->flow_type) {
+ case TCP_V4_FLOW:
+ case TCP_V6_FLOW:
+ case UDP_V4_FLOW:
+ case UDP_V6_FLOW:
+ err = set_l4_rss_hash_ops(cmd, rss_type);
+ if (err)
+ return err;
+ break;
+ case IPV4_FLOW:
+ rss_type->ipv4 = 1;
+ break;
+ case IPV6_FLOW:
+ rss_type->ipv6 = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ err = hinic_set_rss_type(nic_dev, nic_dev->rss_tmpl_idx,
+ *rss_type);
+ if (err)
+ return -EFAULT;
+
+ return 0;
+}
+
+static int __set_rss_rxfh(struct net_device *netdev,
+ const u32 *indir, const u8 *key)
+{
+ struct hinic_dev *nic_dev = netdev_priv(netdev);
+ int err;
+
+ if (indir) {
+ if (!nic_dev->rss_indir_user) {
+ nic_dev->rss_indir_user =
+ kzalloc(sizeof(u32) * HINIC_RSS_INDIR_SIZE,
+ GFP_KERNEL);
+ if (!nic_dev->rss_indir_user)
+ return -ENOMEM;
+ }
+
+ memcpy(nic_dev->rss_indir_user, indir,
+ sizeof(u32) * HINIC_RSS_INDIR_SIZE);
+
+ err = hinic_rss_set_indir_tbl(nic_dev,
+ nic_dev->rss_tmpl_idx, indir);
+ if (err)
+ return -EFAULT;
+ }
+
+ if (key) {
+ if (!nic_dev->rss_hkey_user) {
+ nic_dev->rss_hkey_user =
+ kzalloc(HINIC_RSS_KEY_SIZE * 2, GFP_KERNEL);
+
+ if (!nic_dev->rss_hkey_user)
+ return -ENOMEM;
+ }
+
+ memcpy(nic_dev->rss_hkey_user, key, HINIC_RSS_KEY_SIZE);
+
+ err = hinic_rss_set_template_tbl(nic_dev,
+ nic_dev->rss_tmpl_idx, key);
+ if (err)
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int hinic_get_rxnfc(struct net_device *netdev,
+ struct ethtool_rxnfc *cmd, u32 *rule_locs)
+{
+ struct hinic_dev *nic_dev = netdev_priv(netdev);
+ int err = 0;
+
+ switch (cmd->cmd) {
+ case ETHTOOL_GRXRINGS:
+ cmd->data = nic_dev->num_qps;
+ break;
+ case ETHTOOL_GRXFH:
+ err = hinic_get_rss_hash_opts(nic_dev, cmd);
+ break;
+ default:
+ err = -EOPNOTSUPP;
+ break;
+ }
+
+ return err;
+}
+
+static int hinic_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
+{
+ struct hinic_dev *nic_dev = netdev_priv(netdev);
+ int err = 0;
+
+ switch (cmd->cmd) {
+ case ETHTOOL_SRXFH:
+ err = hinic_set_rss_hash_opts(nic_dev, cmd);
+ break;
+ default:
+ err = -EOPNOTSUPP;
+ break;
+ }
+
+ return err;
+}
+
+static int hinic_get_rxfh(struct net_device *netdev,
+ u32 *indir, u8 *key, u8 *hfunc)
+{
+ struct hinic_dev *nic_dev = netdev_priv(netdev);
+ u8 hash_engine_type = 0;
+ int err = 0;
+
+ if (!(nic_dev->flags & HINIC_RSS_ENABLE))
+ return -EOPNOTSUPP;
+
+ if (hfunc) {
+ err = hinic_rss_get_hash_engine(nic_dev,
+ nic_dev->rss_tmpl_idx,
+ &hash_engine_type);
+ if (err)
+ return -EFAULT;
+
+ *hfunc = hash_engine_type ? ETH_RSS_HASH_TOP : ETH_RSS_HASH_XOR;
+ }
+
+ if (indir) {
+ err = hinic_rss_get_indir_tbl(nic_dev,
+ nic_dev->rss_tmpl_idx, indir);
+ if (err)
+ return -EFAULT;
+ }
+
+ if (key)
+ err = hinic_rss_get_template_tbl(nic_dev,
+ nic_dev->rss_tmpl_idx, key);
+
+ return err;
+}
+
+static int hinic_set_rxfh(struct net_device *netdev, const u32 *indir,
+ const u8 *key, const u8 hfunc)
+{
+ struct hinic_dev *nic_dev = netdev_priv(netdev);
+ int err = 0;
+
+ if (!(nic_dev->flags & HINIC_RSS_ENABLE))
+ return -EOPNOTSUPP;
+
+ if (hfunc != ETH_RSS_HASH_NO_CHANGE) {
+ if (hfunc != ETH_RSS_HASH_TOP && hfunc != ETH_RSS_HASH_XOR)
+ return -EOPNOTSUPP;
+
+ nic_dev->rss_hash_engine = (hfunc == ETH_RSS_HASH_XOR) ?
+ HINIC_RSS_HASH_ENGINE_TYPE_XOR :
+ HINIC_RSS_HASH_ENGINE_TYPE_TOEP;
+ err = hinic_rss_set_hash_engine
+ (nic_dev, nic_dev->rss_tmpl_idx,
+ nic_dev->rss_hash_engine);
+ if (err)
+ return -EFAULT;
+ }
+
+ err = __set_rss_rxfh(netdev, indir, key);
+
+ return err;
+}
+
+static u32 hinic_get_rxfh_key_size(struct net_device *netdev)
+{
+ return HINIC_RSS_KEY_SIZE;
+}
+
+static u32 hinic_get_rxfh_indir_size(struct net_device *netdev)
+{
+ return HINIC_RSS_INDIR_SIZE;
+}
+
+#define ARRAY_LEN(arr) ((int)((int)sizeof(arr) / (int)sizeof(arr[0])))
+
+#define HINIC_FUNC_STAT(_stat_item) { \
+ .name = #_stat_item, \
+ .size = FIELD_SIZEOF(struct hinic_vport_stats, _stat_item), \
+ .offset = offsetof(struct hinic_vport_stats, _stat_item) \
+}
+
+static struct hinic_stats hinic_function_stats[] = {
+ HINIC_FUNC_STAT(tx_unicast_pkts_vport),
+ HINIC_FUNC_STAT(tx_unicast_bytes_vport),
+ HINIC_FUNC_STAT(tx_multicast_pkts_vport),
+ HINIC_FUNC_STAT(tx_multicast_bytes_vport),
+ HINIC_FUNC_STAT(tx_broadcast_pkts_vport),
+ HINIC_FUNC_STAT(tx_broadcast_bytes_vport),
+
+ HINIC_FUNC_STAT(rx_unicast_pkts_vport),
+ HINIC_FUNC_STAT(rx_unicast_bytes_vport),
+ HINIC_FUNC_STAT(rx_multicast_pkts_vport),
+ HINIC_FUNC_STAT(rx_multicast_bytes_vport),
+ HINIC_FUNC_STAT(rx_broadcast_pkts_vport),
+ HINIC_FUNC_STAT(rx_broadcast_bytes_vport),
+
+ HINIC_FUNC_STAT(tx_discard_vport),
+ HINIC_FUNC_STAT(rx_discard_vport),
+ HINIC_FUNC_STAT(tx_err_vport),
+ HINIC_FUNC_STAT(rx_err_vport),
+};
+
+#define HINIC_PORT_STAT(_stat_item) { \
+ .name = #_stat_item, \
+ .size = FIELD_SIZEOF(struct hinic_phy_port_stats, _stat_item), \
+ .offset = offsetof(struct hinic_phy_port_stats, _stat_item) \
+}
+
+static struct hinic_stats hinic_port_stats[] = {
+ HINIC_PORT_STAT(mac_rx_total_pkt_num),
+ HINIC_PORT_STAT(mac_rx_total_oct_num),
+ HINIC_PORT_STAT(mac_rx_bad_pkt_num),
+ HINIC_PORT_STAT(mac_rx_bad_oct_num),
+ HINIC_PORT_STAT(mac_rx_good_pkt_num),
+ HINIC_PORT_STAT(mac_rx_good_oct_num),
+ HINIC_PORT_STAT(mac_rx_uni_pkt_num),
+ HINIC_PORT_STAT(mac_rx_multi_pkt_num),
+ HINIC_PORT_STAT(mac_rx_broad_pkt_num),
+ HINIC_PORT_STAT(mac_tx_total_pkt_num),
+ HINIC_PORT_STAT(mac_tx_total_oct_num),
+ HINIC_PORT_STAT(mac_tx_bad_pkt_num),
+ HINIC_PORT_STAT(mac_tx_bad_oct_num),
+ HINIC_PORT_STAT(mac_tx_good_pkt_num),
+ HINIC_PORT_STAT(mac_tx_good_oct_num),
+ HINIC_PORT_STAT(mac_tx_uni_pkt_num),
+ HINIC_PORT_STAT(mac_tx_multi_pkt_num),
+ HINIC_PORT_STAT(mac_tx_broad_pkt_num),
+ HINIC_PORT_STAT(mac_rx_fragment_pkt_num),
+ HINIC_PORT_STAT(mac_rx_undersize_pkt_num),
+ HINIC_PORT_STAT(mac_rx_undermin_pkt_num),
+ HINIC_PORT_STAT(mac_rx_64_oct_pkt_num),
+ HINIC_PORT_STAT(mac_rx_65_127_oct_pkt_num),
+ HINIC_PORT_STAT(mac_rx_128_255_oct_pkt_num),
+ HINIC_PORT_STAT(mac_rx_256_511_oct_pkt_num),
+ HINIC_PORT_STAT(mac_rx_512_1023_oct_pkt_num),
+ HINIC_PORT_STAT(mac_rx_1024_1518_oct_pkt_num),
+ HINIC_PORT_STAT(mac_rx_1519_2047_oct_pkt_num),
+ HINIC_PORT_STAT(mac_rx_2048_4095_oct_pkt_num),
+ HINIC_PORT_STAT(mac_rx_4096_8191_oct_pkt_num),
+ HINIC_PORT_STAT(mac_rx_8192_9216_oct_pkt_num),
+ HINIC_PORT_STAT(mac_rx_9217_12287_oct_pkt_num),
+ HINIC_PORT_STAT(mac_rx_12288_16383_oct_pkt_num),
+ HINIC_PORT_STAT(mac_rx_1519_max_good_pkt_num),
+ HINIC_PORT_STAT(mac_rx_1519_max_bad_pkt_num),
+ HINIC_PORT_STAT(mac_rx_oversize_pkt_num),
+ HINIC_PORT_STAT(mac_rx_jabber_pkt_num),
+ HINIC_PORT_STAT(mac_rx_pause_num),
+ HINIC_PORT_STAT(mac_rx_pfc_pkt_num),
+ HINIC_PORT_STAT(mac_rx_pfc_pri0_pkt_num),
+ HINIC_PORT_STAT(mac_rx_pfc_pri1_pkt_num),
+ HINIC_PORT_STAT(mac_rx_pfc_pri2_pkt_num),
+ HINIC_PORT_STAT(mac_rx_pfc_pri3_pkt_num),
+ HINIC_PORT_STAT(mac_rx_pfc_pri4_pkt_num),
+ HINIC_PORT_STAT(mac_rx_pfc_pri5_pkt_num),
+ HINIC_PORT_STAT(mac_rx_pfc_pri6_pkt_num),
+ HINIC_PORT_STAT(mac_rx_pfc_pri7_pkt_num),
+ HINIC_PORT_STAT(mac_rx_control_pkt_num),
+ HINIC_PORT_STAT(mac_rx_sym_err_pkt_num),
+ HINIC_PORT_STAT(mac_rx_fcs_err_pkt_num),
+ HINIC_PORT_STAT(mac_rx_send_app_good_pkt_num),
+ HINIC_PORT_STAT(mac_rx_send_app_bad_pkt_num),
+ HINIC_PORT_STAT(mac_tx_fragment_pkt_num),
+ HINIC_PORT_STAT(mac_tx_undersize_pkt_num),
+ HINIC_PORT_STAT(mac_tx_undermin_pkt_num),
+ HINIC_PORT_STAT(mac_tx_64_oct_pkt_num),
+ HINIC_PORT_STAT(mac_tx_65_127_oct_pkt_num),
+ HINIC_PORT_STAT(mac_tx_128_255_oct_pkt_num),
+ HINIC_PORT_STAT(mac_tx_256_511_oct_pkt_num),
+ HINIC_PORT_STAT(mac_tx_512_1023_oct_pkt_num),
+ HINIC_PORT_STAT(mac_tx_1024_1518_oct_pkt_num),
+ HINIC_PORT_STAT(mac_tx_1519_2047_oct_pkt_num),
+ HINIC_PORT_STAT(mac_tx_2048_4095_oct_pkt_num),
+ HINIC_PORT_STAT(mac_tx_4096_8191_oct_pkt_num),
+ HINIC_PORT_STAT(mac_tx_8192_9216_oct_pkt_num),
+ HINIC_PORT_STAT(mac_tx_9217_12287_oct_pkt_num),
+ HINIC_PORT_STAT(mac_tx_12288_16383_oct_pkt_num),
+ HINIC_PORT_STAT(mac_tx_1519_max_good_pkt_num),
+ HINIC_PORT_STAT(mac_tx_1519_max_bad_pkt_num),
+ HINIC_PORT_STAT(mac_tx_oversize_pkt_num),
+ HINIC_PORT_STAT(mac_tx_jabber_pkt_num),
+ HINIC_PORT_STAT(mac_tx_pause_num),
+ HINIC_PORT_STAT(mac_tx_pfc_pkt_num),
+ HINIC_PORT_STAT(mac_tx_pfc_pri0_pkt_num),
+ HINIC_PORT_STAT(mac_tx_pfc_pri1_pkt_num),
+ HINIC_PORT_STAT(mac_tx_pfc_pri2_pkt_num),
+ HINIC_PORT_STAT(mac_tx_pfc_pri3_pkt_num),
+ HINIC_PORT_STAT(mac_tx_pfc_pri4_pkt_num),
+ HINIC_PORT_STAT(mac_tx_pfc_pri5_pkt_num),
+ HINIC_PORT_STAT(mac_tx_pfc_pri6_pkt_num),
+ HINIC_PORT_STAT(mac_tx_pfc_pri7_pkt_num),
+ HINIC_PORT_STAT(mac_tx_control_pkt_num),
+ HINIC_PORT_STAT(mac_tx_err_all_pkt_num),
+ HINIC_PORT_STAT(mac_tx_from_app_good_pkt_num),
+ HINIC_PORT_STAT(mac_tx_from_app_bad_pkt_num),
+};
+
+#define HINIC_TXQ_STAT(_stat_item) { \
+ .name = "txq%d_"#_stat_item, \
+ .size = FIELD_SIZEOF(struct hinic_txq_stats, _stat_item), \
+ .offset = offsetof(struct hinic_txq_stats, _stat_item) \
+}
+
+static struct hinic_stats hinic_tx_queue_stats[] = {
+ HINIC_TXQ_STAT(pkts),
+ HINIC_TXQ_STAT(bytes),
+ HINIC_TXQ_STAT(tx_busy),
+ HINIC_TXQ_STAT(tx_wake),
+ HINIC_TXQ_STAT(tx_dropped),
+ HINIC_TXQ_STAT(big_frags_pkts),
+};
+
+#define HINIC_RXQ_STAT(_stat_item) { \
+ .name = "rxq%d_"#_stat_item, \
+ .size = FIELD_SIZEOF(struct hinic_rxq_stats, _stat_item), \
+ .offset = offsetof(struct hinic_rxq_stats, _stat_item) \
+}
+
+static struct hinic_stats hinic_rx_queue_stats[] = {
+ HINIC_RXQ_STAT(pkts),
+ HINIC_RXQ_STAT(bytes),
+ HINIC_RXQ_STAT(errors),
+ HINIC_RXQ_STAT(csum_errors),
+ HINIC_RXQ_STAT(other_errors),
+};
+
+static void get_drv_queue_stats(struct hinic_dev *nic_dev, u64 *data)
+{
+ struct hinic_txq_stats txq_stats;
+ struct hinic_rxq_stats rxq_stats;
+ u16 i = 0, j = 0, qid = 0;
+ char *p;
+
+ for (qid = 0; qid < nic_dev->num_qps; qid++) {
+ if (!nic_dev->txqs)
+ break;
+
+ hinic_txq_get_stats(&nic_dev->txqs[qid], &txq_stats);
+ for (j = 0; j < ARRAY_LEN(hinic_tx_queue_stats); j++, i++) {
+ p = (char *)&txq_stats +
+ hinic_tx_queue_stats[j].offset;
+ data[i] = (hinic_tx_queue_stats[j].size ==
+ sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+ }
+ }
+
+ for (qid = 0; qid < nic_dev->num_qps; qid++) {
+ if (!nic_dev->rxqs)
+ break;
+
+ hinic_rxq_get_stats(&nic_dev->rxqs[qid], &rxq_stats);
+ for (j = 0; j < ARRAY_LEN(hinic_rx_queue_stats); j++, i++) {
+ p = (char *)&rxq_stats +
+ hinic_rx_queue_stats[j].offset;
+ data[i] = (hinic_rx_queue_stats[j].size ==
+ sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+ }
+ }
+}
+
+static void hinic_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct hinic_dev *nic_dev = netdev_priv(netdev);
+ struct hinic_vport_stats vport_stats = {0};
+ struct hinic_phy_port_stats *port_stats;
+ u16 i = 0, j = 0;
+ char *p;
+ int err;
+
+ err = hinic_get_vport_stats(nic_dev, &vport_stats);
+ if (err)
+ netif_err(nic_dev, drv, netdev,
+ "Failed to get vport stats from firmware\n");
+
+ for (j = 0; j < ARRAY_LEN(hinic_function_stats); j++, i++) {
+ p = (char *)&vport_stats + hinic_function_stats[j].offset;
+ data[i] = (hinic_function_stats[j].size ==
+ sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+ }
+
+ port_stats = kzalloc(sizeof(*port_stats), GFP_KERNEL);
+ if (!port_stats) {
+ memset(&data[i], 0,
+ ARRAY_LEN(hinic_port_stats) * sizeof(*data));
+ i += ARRAY_LEN(hinic_port_stats);
+ goto get_drv_stats;
+ }
+
+ err = hinic_get_phy_port_stats(nic_dev, port_stats);
+ if (err)
+ netif_err(nic_dev, drv, netdev,
+ "Failed to get port stats from firmware\n");
+
+ for (j = 0; j < ARRAY_LEN(hinic_port_stats); j++, i++) {
+ p = (char *)port_stats + hinic_port_stats[j].offset;
+ data[i] = (hinic_port_stats[j].size ==
+ sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+ }
+
+ kfree(port_stats);
+
+get_drv_stats:
+ get_drv_queue_stats(nic_dev, data + i);
+}
+
+static int hinic_get_sset_count(struct net_device *netdev, int sset)
+{
+ struct hinic_dev *nic_dev = netdev_priv(netdev);
+ int count, q_num;
+
+ switch (sset) {
+ case ETH_SS_STATS:
+ q_num = nic_dev->num_qps;
+ count = ARRAY_LEN(hinic_function_stats) +
+ (ARRAY_LEN(hinic_tx_queue_stats) +
+ ARRAY_LEN(hinic_rx_queue_stats)) * q_num;
+
+ count += ARRAY_LEN(hinic_port_stats);
+
+ return count;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void hinic_get_strings(struct net_device *netdev,
+ u32 stringset, u8 *data)
+{
+ struct hinic_dev *nic_dev = netdev_priv(netdev);
+ char *p = (char *)data;
+ u16 i, j;
+
+ switch (stringset) {
+ case ETH_SS_STATS:
+ for (i = 0; i < ARRAY_LEN(hinic_function_stats); i++) {
+ memcpy(p, hinic_function_stats[i].name,
+ ETH_GSTRING_LEN);
+ p += ETH_GSTRING_LEN;
+ }
+
+ for (i = 0; i < ARRAY_LEN(hinic_port_stats); i++) {
+ memcpy(p, hinic_port_stats[i].name,
+ ETH_GSTRING_LEN);
+ p += ETH_GSTRING_LEN;
+ }
+
+ for (i = 0; i < nic_dev->num_qps; i++) {
+ for (j = 0; j < ARRAY_LEN(hinic_tx_queue_stats); j++) {
+ sprintf(p, hinic_tx_queue_stats[j].name, i);
+ p += ETH_GSTRING_LEN;
+ }
+ }
+
+ for (i = 0; i < nic_dev->num_qps; i++) {
+ for (j = 0; j < ARRAY_LEN(hinic_rx_queue_stats); j++) {
+ sprintf(p, hinic_rx_queue_stats[j].name, i);
+ p += ETH_GSTRING_LEN;
+ }
+ }
+
+ return;
+ default:
+ return;
+ }
+}
+
+static const struct ethtool_ops hinic_ethtool_ops = {
+ .get_link_ksettings = hinic_get_link_ksettings,
+ .get_drvinfo = hinic_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ .get_ringparam = hinic_get_ringparam,
+ .get_channels = hinic_get_channels,
+ .get_rxnfc = hinic_get_rxnfc,
+ .set_rxnfc = hinic_set_rxnfc,
+ .get_rxfh_key_size = hinic_get_rxfh_key_size,
+ .get_rxfh_indir_size = hinic_get_rxfh_indir_size,
+ .get_rxfh = hinic_get_rxfh,
+ .set_rxfh = hinic_set_rxfh,
+ .get_sset_count = hinic_get_sset_count,
+ .get_ethtool_stats = hinic_get_ethtool_stats,
+ .get_strings = hinic_get_strings,
+};
+
+void hinic_set_ethtool_ops(struct net_device *netdev)
+{
+ netdev->ethtool_ops = &hinic_ethtool_ops;
+}
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c
index 408705687de6..6f2cf569a283 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c
@@ -89,9 +89,6 @@ static int get_capability(struct hinic_hwdev *hwdev,
if (nic_cap->num_qps > HINIC_Q_CTXT_MAX)
nic_cap->num_qps = HINIC_Q_CTXT_MAX;
- /* num_qps must be power of 2 */
- nic_cap->num_qps = BIT(fls(nic_cap->num_qps) - 1);
-
nic_cap->max_qps = dev_cap->max_sqs + 1;
if (nic_cap->max_qps != (dev_cap->max_rqs + 1))
return -EFAULT;
@@ -304,6 +301,8 @@ static int set_hw_ioctxt(struct hinic_hwdev *hwdev, unsigned int rq_depth,
hw_ioctxt.set_cmdq_depth = HW_IOCTXT_SET_CMDQ_DEPTH_DEFAULT;
hw_ioctxt.cmdq_depth = 0;
+ hw_ioctxt.lro_en = 1;
+
hw_ioctxt.rq_depth = ilog2(rq_depth);
hw_ioctxt.rx_buf_sz_idx = HINIC_RX_BUF_SZ_IDX;
@@ -872,6 +871,13 @@ void hinic_free_hwdev(struct hinic_hwdev *hwdev)
hinic_free_hwif(hwdev->hwif);
}
+int hinic_hwdev_max_num_qps(struct hinic_hwdev *hwdev)
+{
+ struct hinic_cap *nic_cap = &hwdev->nic_cap;
+
+ return nic_cap->max_qps;
+}
+
/**
* hinic_hwdev_num_qps - return the number QPs available for use
* @hwdev: the NIC HW device
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h
index a0a5b7434ad7..b069045de416 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h
@@ -41,21 +41,73 @@ enum hinic_port_cmd {
HINIC_PORT_CMD_GET_LINK_STATE = 24,
+ HINIC_PORT_CMD_SET_LRO = 25,
+
HINIC_PORT_CMD_SET_RX_CSUM = 26,
+ HINIC_PORT_CMD_SET_RX_VLAN_OFFLOAD = 27,
+
+ HINIC_PORT_CMD_GET_PORT_STATISTICS = 28,
+
+ HINIC_PORT_CMD_CLEAR_PORT_STATISTICS = 29,
+
+ HINIC_PORT_CMD_GET_VPORT_STAT = 30,
+
+ HINIC_PORT_CMD_CLEAN_VPORT_STAT = 31,
+
+ HINIC_PORT_CMD_GET_RSS_TEMPLATE_INDIR_TBL = 37,
+
HINIC_PORT_CMD_SET_PORT_STATE = 41,
+ HINIC_PORT_CMD_SET_RSS_TEMPLATE_TBL = 43,
+
+ HINIC_PORT_CMD_GET_RSS_TEMPLATE_TBL = 44,
+
+ HINIC_PORT_CMD_SET_RSS_HASH_ENGINE = 45,
+
+ HINIC_PORT_CMD_GET_RSS_HASH_ENGINE = 46,
+
+ HINIC_PORT_CMD_GET_RSS_CTX_TBL = 47,
+
+ HINIC_PORT_CMD_SET_RSS_CTX_TBL = 48,
+
+ HINIC_PORT_CMD_RSS_TEMP_MGR = 49,
+
+ HINIC_PORT_CMD_RSS_CFG = 66,
+
HINIC_PORT_CMD_FWCTXT_INIT = 69,
+ HINIC_PORT_CMD_GET_MGMT_VERSION = 88,
+
HINIC_PORT_CMD_SET_FUNC_STATE = 93,
HINIC_PORT_CMD_GET_GLOBAL_QPN = 102,
HINIC_PORT_CMD_SET_TSO = 112,
+ HINIC_PORT_CMD_SET_RQ_IQ_MAP = 115,
+
HINIC_PORT_CMD_GET_CAP = 170,
+
+ HINIC_PORT_CMD_SET_LRO_TIMER = 244,
};
+enum hinic_ucode_cmd {
+ HINIC_UCODE_CMD_MODIFY_QUEUE_CONTEXT = 0,
+ HINIC_UCODE_CMD_CLEAN_QUEUE_CONTEXT,
+ HINIC_UCODE_CMD_ARM_SQ,
+ HINIC_UCODE_CMD_ARM_RQ,
+ HINIC_UCODE_CMD_SET_RSS_INDIR_TABLE,
+ HINIC_UCODE_CMD_SET_RSS_CONTEXT_TABLE,
+ HINIC_UCODE_CMD_GET_RSS_INDIR_TABLE,
+ HINIC_UCODE_CMD_GET_RSS_CONTEXT_TABLE,
+ HINIC_UCODE_CMD_SET_IQ_ENABLE,
+ HINIC_UCODE_CMD_SET_RQ_FLUSH = 10
+};
+
+#define NIC_RSS_CMD_TEMP_ALLOC 0x01
+#define NIC_RSS_CMD_TEMP_FREE 0x02
+
enum hinic_mgmt_msg_cmd {
HINIC_MGMT_MSG_CMD_BASE = 160,
@@ -97,7 +149,7 @@ struct hinic_cmd_hw_ioctxt {
u8 set_cmdq_depth;
u8 cmdq_depth;
- u8 rsvd2;
+ u8 lro_en;
u8 rsvd3;
u8 rsvd4;
u8 rsvd5;
@@ -215,6 +267,8 @@ struct hinic_hwdev *hinic_init_hwdev(struct pci_dev *pdev);
void hinic_free_hwdev(struct hinic_hwdev *hwdev);
+int hinic_hwdev_max_num_qps(struct hinic_hwdev *hwdev);
+
int hinic_hwdev_num_qps(struct hinic_hwdev *hwdev);
struct hinic_sq *hinic_hwdev_get_sq(struct hinic_hwdev *hwdev, int i);
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_io.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_io.c
index 2d07bdd17432..d66f86fa3f46 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_io.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_io.c
@@ -36,6 +36,7 @@
enum io_cmd {
IO_CMD_MODIFY_QUEUE_CTXT = 0,
+ IO_CMD_CLEAN_QUEUE_CTXT,
};
static void init_db_area_idx(struct hinic_free_db_area *free_db_area)
@@ -201,6 +202,59 @@ static int write_qp_ctxts(struct hinic_func_to_io *func_to_io, u16 base_qpn,
write_rq_ctxts(func_to_io, base_qpn, num_qps));
}
+static int hinic_clean_queue_offload_ctxt(struct hinic_func_to_io *func_to_io,
+ enum hinic_qp_ctxt_type ctxt_type)
+{
+ struct hinic_hwif *hwif = func_to_io->hwif;
+ struct hinic_clean_queue_ctxt *ctxt_block;
+ struct pci_dev *pdev = hwif->pdev;
+ struct hinic_cmdq_buf cmdq_buf;
+ u64 out_param = 0;
+ int err;
+
+ err = hinic_alloc_cmdq_buf(&func_to_io->cmdqs, &cmdq_buf);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to allocate cmdq buf\n");
+ return err;
+ }
+
+ ctxt_block = cmdq_buf.buf;
+ ctxt_block->cmdq_hdr.num_queues = func_to_io->max_qps;
+ ctxt_block->cmdq_hdr.queue_type = ctxt_type;
+ ctxt_block->cmdq_hdr.addr_offset = 0;
+
+ /* TSO/LRO ctxt size: 0x0:0B; 0x1:160B; 0x2:200B; 0x3:240B */
+ ctxt_block->ctxt_size = 0x3;
+
+ hinic_cpu_to_be32(ctxt_block, sizeof(*ctxt_block));
+
+ cmdq_buf.size = sizeof(*ctxt_block);
+
+ err = hinic_cmdq_direct_resp(&func_to_io->cmdqs, HINIC_MOD_L2NIC,
+ IO_CMD_CLEAN_QUEUE_CTXT,
+ &cmdq_buf, &out_param);
+
+ if (err || out_param) {
+ dev_err(&pdev->dev, "Failed to clean offload ctxts, err: %d, out_param: 0x%llx\n",
+ err, out_param);
+
+ err = -EFAULT;
+ }
+
+ hinic_free_cmdq_buf(&func_to_io->cmdqs, &cmdq_buf);
+
+ return err;
+}
+
+static int hinic_clean_qp_offload_ctxt(struct hinic_func_to_io *func_to_io)
+{
+ /* clean LRO/TSO context space */
+ return (hinic_clean_queue_offload_ctxt(func_to_io,
+ HINIC_QP_CTXT_TYPE_SQ) ||
+ hinic_clean_queue_offload_ctxt(func_to_io,
+ HINIC_QP_CTXT_TYPE_RQ));
+}
+
/**
* init_qp - Initialize a Queue Pair
* @func_to_io: func to io channel that holds the IO components
@@ -372,6 +426,12 @@ int hinic_io_create_qps(struct hinic_func_to_io *func_to_io,
goto err_write_qp_ctxts;
}
+ err = hinic_clean_qp_offload_ctxt(func_to_io);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to clean QP contexts space\n");
+ goto err_write_qp_ctxts;
+ }
+
return 0;
err_write_qp_ctxts:
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_qp_ctxt.h b/drivers/net/ethernet/huawei/hinic/hinic_hw_qp_ctxt.h
index 1856fdcc1e32..00900a6640ad 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_qp_ctxt.h
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_qp_ctxt.h
@@ -192,6 +192,11 @@ struct hinic_rq_ctxt {
u32 wq_block_lo_pfn;
};
+struct hinic_clean_queue_ctxt {
+ struct hinic_qp_ctxt_header cmdq_hdr;
+ u32 ctxt_size;
+};
+
struct hinic_sq_ctxt_block {
struct hinic_qp_ctxt_header hdr;
struct hinic_sq_ctxt sq_ctxt[HINIC_Q_CTXT_MAX];
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_wqe.h b/drivers/net/ethernet/huawei/hinic/hinic_hw_wqe.h
index 8991c9a5ef04..f4b6d2c1061f 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_wqe.h
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_wqe.h
@@ -210,6 +210,57 @@
#define HINIC_MSS_DEFAULT 0x3E00
#define HINIC_MSS_MIN 0x50
+#define RQ_CQE_STATUS_NUM_LRO_SHIFT 16
+#define RQ_CQE_STATUS_NUM_LRO_MASK 0xFFU
+
+#define RQ_CQE_STATUS_GET(val, member) (((val) >> \
+ RQ_CQE_STATUS_##member##_SHIFT) & \
+ RQ_CQE_STATUS_##member##_MASK)
+
+#define HINIC_GET_RX_NUM_LRO(status) \
+ RQ_CQE_STATUS_GET(status, NUM_LRO)
+
+#define RQ_CQE_OFFOLAD_TYPE_PKT_TYPE_SHIFT 0
+#define RQ_CQE_OFFOLAD_TYPE_PKT_TYPE_MASK 0xFFFU
+#define RQ_CQE_OFFOLAD_TYPE_VLAN_EN_SHIFT 21
+#define RQ_CQE_OFFOLAD_TYPE_VLAN_EN_MASK 0x1U
+
+#define RQ_CQE_OFFOLAD_TYPE_GET(val, member) (((val) >> \
+ RQ_CQE_OFFOLAD_TYPE_##member##_SHIFT) & \
+ RQ_CQE_OFFOLAD_TYPE_##member##_MASK)
+
+#define HINIC_GET_RX_PKT_TYPE(offload_type) \
+ RQ_CQE_OFFOLAD_TYPE_GET(offload_type, PKT_TYPE)
+
+#define HINIC_GET_RX_VLAN_OFFLOAD_EN(offload_type) \
+ RQ_CQE_OFFOLAD_TYPE_GET(offload_type, VLAN_EN)
+
+#define RQ_CQE_SGE_VLAN_MASK 0xFFFFU
+#define RQ_CQE_SGE_VLAN_SHIFT 0
+
+#define RQ_CQE_SGE_GET(val, member) (((val) >> \
+ RQ_CQE_SGE_##member##_SHIFT) & \
+ RQ_CQE_SGE_##member##_MASK)
+
+#define HINIC_GET_RX_VLAN_TAG(vlan_len) \
+ RQ_CQE_SGE_GET(vlan_len, VLAN)
+
+#define HINIC_RSS_TYPE_VALID_SHIFT 23
+#define HINIC_RSS_TYPE_TCP_IPV6_EXT_SHIFT 24
+#define HINIC_RSS_TYPE_IPV6_EXT_SHIFT 25
+#define HINIC_RSS_TYPE_TCP_IPV6_SHIFT 26
+#define HINIC_RSS_TYPE_IPV6_SHIFT 27
+#define HINIC_RSS_TYPE_TCP_IPV4_SHIFT 28
+#define HINIC_RSS_TYPE_IPV4_SHIFT 29
+#define HINIC_RSS_TYPE_UDP_IPV6_SHIFT 30
+#define HINIC_RSS_TYPE_UDP_IPV4_SHIFT 31
+
+#define HINIC_RSS_TYPE_SET(val, member) \
+ (((u32)(val) & 0x1) << HINIC_RSS_TYPE_##member##_SHIFT)
+
+#define HINIC_RSS_TYPE_GET(val, member) \
+ (((u32)(val) >> HINIC_RSS_TYPE_##member##_SHIFT) & 0x1)
+
enum hinic_l4offload_type {
HINIC_L4_OFF_DISABLE = 0,
HINIC_TCP_OFFLOAD_ENABLE = 1,
@@ -363,7 +414,7 @@ struct hinic_rq_cqe {
u32 status;
u32 len;
- u32 rsvd2;
+ u32 offload_type;
u32 rsvd3;
u32 rsvd4;
u32 rsvd5;
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_main.c b/drivers/net/ethernet/huawei/hinic/hinic_main.c
index b695d29d364c..2411ad270c98 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_main.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_main.c
@@ -53,6 +53,10 @@ MODULE_PARM_DESC(rx_weight, "Number Rx packets for NAPI budget (default=64)");
NETIF_MSG_IFUP | \
NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR)
+#define HINIC_LRO_MAX_WQE_NUM_DEFAULT 8
+
+#define HINIC_LRO_RX_TIMER_DEFAULT 16
+
#define VLAN_BITMAP_SIZE(nic_dev) (ALIGN(VLAN_N_VID, 8) / 8)
#define work_to_rx_mode_work(work) \
@@ -63,137 +67,9 @@ MODULE_PARM_DESC(rx_weight, "Number Rx packets for NAPI budget (default=64)");
static int change_mac_addr(struct net_device *netdev, const u8 *addr);
-static void set_link_speed(struct ethtool_link_ksettings *link_ksettings,
- enum hinic_speed speed)
-{
- switch (speed) {
- case HINIC_SPEED_10MB_LINK:
- link_ksettings->base.speed = SPEED_10;
- break;
-
- case HINIC_SPEED_100MB_LINK:
- link_ksettings->base.speed = SPEED_100;
- break;
-
- case HINIC_SPEED_1000MB_LINK:
- link_ksettings->base.speed = SPEED_1000;
- break;
-
- case HINIC_SPEED_10GB_LINK:
- link_ksettings->base.speed = SPEED_10000;
- break;
-
- case HINIC_SPEED_25GB_LINK:
- link_ksettings->base.speed = SPEED_25000;
- break;
-
- case HINIC_SPEED_40GB_LINK:
- link_ksettings->base.speed = SPEED_40000;
- break;
-
- case HINIC_SPEED_100GB_LINK:
- link_ksettings->base.speed = SPEED_100000;
- break;
-
- default:
- link_ksettings->base.speed = SPEED_UNKNOWN;
- break;
- }
-}
-
-static int hinic_get_link_ksettings(struct net_device *netdev,
- struct ethtool_link_ksettings
- *link_ksettings)
-{
- struct hinic_dev *nic_dev = netdev_priv(netdev);
- enum hinic_port_link_state link_state;
- struct hinic_port_cap port_cap;
- int err;
-
- ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising);
- ethtool_link_ksettings_add_link_mode(link_ksettings, supported,
- Autoneg);
-
- link_ksettings->base.speed = SPEED_UNKNOWN;
- link_ksettings->base.autoneg = AUTONEG_DISABLE;
- link_ksettings->base.duplex = DUPLEX_UNKNOWN;
-
- err = hinic_port_get_cap(nic_dev, &port_cap);
- if (err) {
- netif_err(nic_dev, drv, netdev,
- "Failed to get port capabilities\n");
- return err;
- }
-
- err = hinic_port_link_state(nic_dev, &link_state);
- if (err) {
- netif_err(nic_dev, drv, netdev,
- "Failed to get port link state\n");
- return err;
- }
-
- if (link_state != HINIC_LINK_STATE_UP) {
- netif_info(nic_dev, drv, netdev, "No link\n");
- return err;
- }
-
- set_link_speed(link_ksettings, port_cap.speed);
-
- if (!!(port_cap.autoneg_cap & HINIC_AUTONEG_SUPPORTED))
- ethtool_link_ksettings_add_link_mode(link_ksettings,
- advertising, Autoneg);
-
- if (port_cap.autoneg_state == HINIC_AUTONEG_ACTIVE)
- link_ksettings->base.autoneg = AUTONEG_ENABLE;
-
- link_ksettings->base.duplex = (port_cap.duplex == HINIC_DUPLEX_FULL) ?
- DUPLEX_FULL : DUPLEX_HALF;
- return 0;
-}
-
-static void hinic_get_drvinfo(struct net_device *netdev,
- struct ethtool_drvinfo *info)
-{
- struct hinic_dev *nic_dev = netdev_priv(netdev);
- struct hinic_hwdev *hwdev = nic_dev->hwdev;
- struct hinic_hwif *hwif = hwdev->hwif;
-
- strlcpy(info->driver, HINIC_DRV_NAME, sizeof(info->driver));
- strlcpy(info->bus_info, pci_name(hwif->pdev), sizeof(info->bus_info));
-}
-
-static void hinic_get_ringparam(struct net_device *netdev,
- struct ethtool_ringparam *ring)
-{
- ring->rx_max_pending = HINIC_RQ_DEPTH;
- ring->tx_max_pending = HINIC_SQ_DEPTH;
- ring->rx_pending = HINIC_RQ_DEPTH;
- ring->tx_pending = HINIC_SQ_DEPTH;
-}
-
-static void hinic_get_channels(struct net_device *netdev,
- struct ethtool_channels *channels)
-{
- struct hinic_dev *nic_dev = netdev_priv(netdev);
- struct hinic_hwdev *hwdev = nic_dev->hwdev;
-
- channels->max_rx = hwdev->nic_cap.max_qps;
- channels->max_tx = hwdev->nic_cap.max_qps;
- channels->max_other = 0;
- channels->max_combined = 0;
- channels->rx_count = hinic_hwdev_num_qps(hwdev);
- channels->tx_count = hinic_hwdev_num_qps(hwdev);
- channels->other_count = 0;
- channels->combined_count = 0;
-}
-
-static const struct ethtool_ops hinic_ethtool_ops = {
- .get_link_ksettings = hinic_get_link_ksettings,
- .get_drvinfo = hinic_get_drvinfo,
- .get_link = ethtool_op_get_link,
- .get_ringparam = hinic_get_ringparam,
- .get_channels = hinic_get_channels,
-};
+static int set_features(struct hinic_dev *nic_dev,
+ netdev_features_t pre_features,
+ netdev_features_t features, bool force_change);
static void update_rx_stats(struct hinic_dev *nic_dev, struct hinic_rxq *rxq)
{
@@ -207,6 +83,9 @@ static void update_rx_stats(struct hinic_dev *nic_dev, struct hinic_rxq *rxq)
u64_stats_update_begin(&nic_rx_stats->syncp);
nic_rx_stats->bytes += rx_stats.bytes;
nic_rx_stats->pkts += rx_stats.pkts;
+ nic_rx_stats->errors += rx_stats.errors;
+ nic_rx_stats->csum_errors += rx_stats.csum_errors;
+ nic_rx_stats->other_errors += rx_stats.other_errors;
u64_stats_update_end(&nic_rx_stats->syncp);
hinic_rxq_clean_stats(rxq);
@@ -227,6 +106,7 @@ static void update_tx_stats(struct hinic_dev *nic_dev, struct hinic_txq *txq)
nic_tx_stats->tx_busy += tx_stats.tx_busy;
nic_tx_stats->tx_wake += tx_stats.tx_wake;
nic_tx_stats->tx_dropped += tx_stats.tx_dropped;
+ nic_tx_stats->big_frags_pkts += tx_stats.big_frags_pkts;
u64_stats_update_end(&nic_tx_stats->syncp);
hinic_txq_clean_stats(txq);
@@ -363,11 +243,135 @@ static void free_rxqs(struct hinic_dev *nic_dev)
nic_dev->rxqs = NULL;
}
+static int hinic_configure_max_qnum(struct hinic_dev *nic_dev)
+{
+ int err;
+
+ err = hinic_set_max_qnum(nic_dev, nic_dev->hwdev->nic_cap.max_qps);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int hinic_rss_init(struct hinic_dev *nic_dev)
+{
+ u8 default_rss_key[HINIC_RSS_KEY_SIZE];
+ u8 tmpl_idx = nic_dev->rss_tmpl_idx;
+ u32 *indir_tbl;
+ int err, i;
+
+ indir_tbl = kcalloc(HINIC_RSS_INDIR_SIZE, sizeof(u32), GFP_KERNEL);
+ if (!indir_tbl)
+ return -ENOMEM;
+
+ netdev_rss_key_fill(default_rss_key, sizeof(default_rss_key));
+ for (i = 0; i < HINIC_RSS_INDIR_SIZE; i++)
+ indir_tbl[i] = ethtool_rxfh_indir_default(i, nic_dev->num_rss);
+
+ err = hinic_rss_set_template_tbl(nic_dev, tmpl_idx, default_rss_key);
+ if (err)
+ goto out;
+
+ err = hinic_rss_set_indir_tbl(nic_dev, tmpl_idx, indir_tbl);
+ if (err)
+ goto out;
+
+ err = hinic_set_rss_type(nic_dev, tmpl_idx, nic_dev->rss_type);
+ if (err)
+ goto out;
+
+ err = hinic_rss_set_hash_engine(nic_dev, tmpl_idx,
+ nic_dev->rss_hash_engine);
+ if (err)
+ goto out;
+
+ err = hinic_rss_cfg(nic_dev, 1, tmpl_idx);
+ if (err)
+ goto out;
+
+out:
+ kfree(indir_tbl);
+ return err;
+}
+
+static void hinic_rss_deinit(struct hinic_dev *nic_dev)
+{
+ hinic_rss_cfg(nic_dev, 0, nic_dev->rss_tmpl_idx);
+}
+
+static void hinic_init_rss_parameters(struct hinic_dev *nic_dev)
+{
+ nic_dev->rss_hash_engine = HINIC_RSS_HASH_ENGINE_TYPE_XOR;
+ nic_dev->rss_type.tcp_ipv6_ext = 1;
+ nic_dev->rss_type.ipv6_ext = 1;
+ nic_dev->rss_type.tcp_ipv6 = 1;
+ nic_dev->rss_type.ipv6 = 1;
+ nic_dev->rss_type.tcp_ipv4 = 1;
+ nic_dev->rss_type.ipv4 = 1;
+ nic_dev->rss_type.udp_ipv6 = 1;
+ nic_dev->rss_type.udp_ipv4 = 1;
+}
+
+static void hinic_enable_rss(struct hinic_dev *nic_dev)
+{
+ struct net_device *netdev = nic_dev->netdev;
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic_hwif *hwif = hwdev->hwif;
+ struct pci_dev *pdev = hwif->pdev;
+ int i, node, err = 0;
+ u16 num_cpus = 0;
+
+ nic_dev->max_qps = hinic_hwdev_max_num_qps(hwdev);
+ if (nic_dev->max_qps <= 1) {
+ nic_dev->flags &= ~HINIC_RSS_ENABLE;
+ nic_dev->rss_limit = nic_dev->max_qps;
+ nic_dev->num_qps = nic_dev->max_qps;
+ nic_dev->num_rss = nic_dev->max_qps;
+
+ return;
+ }
+
+ err = hinic_rss_template_alloc(nic_dev, &nic_dev->rss_tmpl_idx);
+ if (err) {
+ netif_err(nic_dev, drv, netdev,
+ "Failed to alloc tmpl_idx for rss, can't enable rss for this function\n");
+ nic_dev->flags &= ~HINIC_RSS_ENABLE;
+ nic_dev->max_qps = 1;
+ nic_dev->rss_limit = nic_dev->max_qps;
+ nic_dev->num_qps = nic_dev->max_qps;
+ nic_dev->num_rss = nic_dev->max_qps;
+
+ return;
+ }
+
+ nic_dev->flags |= HINIC_RSS_ENABLE;
+
+ for (i = 0; i < num_online_cpus(); i++) {
+ node = cpu_to_node(i);
+ if (node == dev_to_node(&pdev->dev))
+ num_cpus++;
+ }
+
+ if (!num_cpus)
+ num_cpus = num_online_cpus();
+
+ nic_dev->num_qps = min_t(u16, nic_dev->max_qps, num_cpus);
+
+ nic_dev->rss_limit = nic_dev->num_qps;
+ nic_dev->num_rss = nic_dev->num_qps;
+
+ hinic_init_rss_parameters(nic_dev);
+ err = hinic_rss_init(nic_dev);
+ if (err)
+ netif_err(nic_dev, drv, netdev, "Failed to init rss\n");
+}
+
static int hinic_open(struct net_device *netdev)
{
struct hinic_dev *nic_dev = netdev_priv(netdev);
enum hinic_port_link_state link_state;
- int err, ret, num_qps;
+ int err, ret;
if (!(nic_dev->flags & HINIC_INTF_UP)) {
err = hinic_hwdev_ifup(nic_dev->hwdev);
@@ -392,9 +396,17 @@ static int hinic_open(struct net_device *netdev)
goto err_create_rxqs;
}
- num_qps = hinic_hwdev_num_qps(nic_dev->hwdev);
- netif_set_real_num_tx_queues(netdev, num_qps);
- netif_set_real_num_rx_queues(netdev, num_qps);
+ hinic_enable_rss(nic_dev);
+
+ err = hinic_configure_max_qnum(nic_dev);
+ if (err) {
+ netif_err(nic_dev, drv, nic_dev->netdev,
+ "Failed to configure the maximum number of queues\n");
+ goto err_port_state;
+ }
+
+ netif_set_real_num_tx_queues(netdev, nic_dev->num_qps);
+ netif_set_real_num_rx_queues(netdev, nic_dev->num_qps);
err = hinic_port_set_state(nic_dev, HINIC_PORT_ENABLE);
if (err) {
@@ -450,9 +462,12 @@ err_func_port_state:
if (ret)
netif_warn(nic_dev, drv, netdev,
"Failed to revert port state\n");
-
err_port_state:
free_rxqs(nic_dev);
+ if (nic_dev->flags & HINIC_RSS_ENABLE) {
+ hinic_rss_deinit(nic_dev);
+ hinic_rss_template_free(nic_dev, nic_dev->rss_tmpl_idx);
+ }
err_create_rxqs:
free_txqs(nic_dev);
@@ -496,6 +511,11 @@ static int hinic_close(struct net_device *netdev)
return err;
}
+ if (nic_dev->flags & HINIC_RSS_ENABLE) {
+ hinic_rss_deinit(nic_dev);
+ hinic_rss_template_free(nic_dev, nic_dev->rss_tmpl_idx);
+ }
+
free_rxqs(nic_dev);
free_txqs(nic_dev);
@@ -715,7 +735,6 @@ static void set_rx_mode(struct work_struct *work)
{
struct hinic_rx_mode_work *rx_mode_work = work_to_rx_mode_work(work);
struct hinic_dev *nic_dev = rx_mode_work_to_nic_dev(rx_mode_work);
- struct netdev_hw_addr *ha;
netif_info(nic_dev, drv, nic_dev->netdev, "set rx mode work\n");
@@ -723,9 +742,6 @@ static void set_rx_mode(struct work_struct *work)
__dev_uc_sync(nic_dev->netdev, add_mac_addr, remove_mac_addr);
__dev_mc_sync(nic_dev->netdev, add_mac_addr, remove_mac_addr);
-
- netdev_for_each_mc_addr(ha, nic_dev->netdev)
- add_mac_addr(nic_dev->netdev, ha->addr);
}
static void hinic_set_rx_mode(struct net_device *netdev)
@@ -776,12 +792,36 @@ static void hinic_get_stats64(struct net_device *netdev,
stats->rx_bytes = nic_rx_stats->bytes;
stats->rx_packets = nic_rx_stats->pkts;
+ stats->rx_errors = nic_rx_stats->errors;
stats->tx_bytes = nic_tx_stats->bytes;
stats->tx_packets = nic_tx_stats->pkts;
stats->tx_errors = nic_tx_stats->tx_dropped;
}
+static int hinic_set_features(struct net_device *netdev,
+ netdev_features_t features)
+{
+ struct hinic_dev *nic_dev = netdev_priv(netdev);
+
+ return set_features(nic_dev, nic_dev->netdev->features,
+ features, false);
+}
+
+static netdev_features_t hinic_fix_features(struct net_device *netdev,
+ netdev_features_t features)
+{
+ struct hinic_dev *nic_dev = netdev_priv(netdev);
+
+ /* If Rx checksum is disabled, then LRO should also be disabled */
+ if (!(features & NETIF_F_RXCSUM)) {
+ netif_info(nic_dev, drv, netdev, "disabling LRO as RXCSUM is off\n");
+ features &= ~NETIF_F_LRO;
+ }
+
+ return features;
+}
+
static const struct net_device_ops hinic_netdev_ops = {
.ndo_open = hinic_open,
.ndo_stop = hinic_close,
@@ -794,13 +834,16 @@ static const struct net_device_ops hinic_netdev_ops = {
.ndo_start_xmit = hinic_xmit_frame,
.ndo_tx_timeout = hinic_tx_timeout,
.ndo_get_stats64 = hinic_get_stats64,
+ .ndo_fix_features = hinic_fix_features,
+ .ndo_set_features = hinic_set_features,
};
static void netdev_features_init(struct net_device *netdev)
{
netdev->hw_features = NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_IP_CSUM |
NETIF_F_IPV6_CSUM | NETIF_F_TSO | NETIF_F_TSO6 |
- NETIF_F_RXCSUM;
+ NETIF_F_RXCSUM | NETIF_F_LRO |
+ NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
netdev->vlan_features = netdev->hw_features;
@@ -873,6 +916,18 @@ static int set_features(struct hinic_dev *nic_dev,
if (changed & NETIF_F_RXCSUM)
err = hinic_set_rx_csum_offload(nic_dev, csum_en);
+ if (changed & NETIF_F_LRO) {
+ err = hinic_set_rx_lro_state(nic_dev,
+ !!(features & NETIF_F_LRO),
+ HINIC_LRO_RX_TIMER_DEFAULT,
+ HINIC_LRO_MAX_WQE_NUM_DEFAULT);
+ }
+
+ if (changed & NETIF_F_HW_VLAN_CTAG_RX)
+ err = hinic_set_rx_vlan_offload(nic_dev,
+ !!(features &
+ NETIF_F_HW_VLAN_CTAG_RX));
+
return err;
}
@@ -912,8 +967,8 @@ static int nic_dev_init(struct pci_dev *pdev)
goto err_alloc_etherdev;
}
+ hinic_set_ethtool_ops(netdev);
netdev->netdev_ops = &hinic_netdev_ops;
- netdev->ethtool_ops = &hinic_ethtool_ops;
netdev->max_mtu = ETH_MAX_MTU;
nic_dev = netdev_priv(netdev);
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_port.c b/drivers/net/ethernet/huawei/hinic/hinic_port.c
index 4b3b7d39e437..1e389a004e50 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_port.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_port.c
@@ -430,3 +430,641 @@ int hinic_set_rx_csum_offload(struct hinic_dev *nic_dev, u32 en)
return 0;
}
+
+int hinic_set_rx_vlan_offload(struct hinic_dev *nic_dev, u8 en)
+{
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic_vlan_cfg vlan_cfg;
+ struct hinic_hwif *hwif;
+ struct pci_dev *pdev;
+ u16 out_size;
+ int err;
+
+ if (!hwdev)
+ return -EINVAL;
+
+ hwif = hwdev->hwif;
+ pdev = hwif->pdev;
+ vlan_cfg.func_id = HINIC_HWIF_FUNC_IDX(hwif);
+ vlan_cfg.vlan_rx_offload = en;
+
+ err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_SET_RX_VLAN_OFFLOAD,
+ &vlan_cfg, sizeof(vlan_cfg),
+ &vlan_cfg, &out_size);
+ if (err || !out_size || vlan_cfg.status) {
+ dev_err(&pdev->dev,
+ "Failed to set rx vlan offload, err: %d, status: 0x%x, out size: 0x%x\n",
+ err, vlan_cfg.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int hinic_set_max_qnum(struct hinic_dev *nic_dev, u8 num_rqs)
+{
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic_hwif *hwif = hwdev->hwif;
+ struct pci_dev *pdev = hwif->pdev;
+ struct hinic_rq_num rq_num = { 0 };
+ u16 out_size = sizeof(rq_num);
+ int err;
+
+ rq_num.func_id = HINIC_HWIF_FUNC_IDX(hwif);
+ rq_num.num_rqs = num_rqs;
+ rq_num.rq_depth = ilog2(HINIC_SQ_DEPTH);
+
+ err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_SET_RQ_IQ_MAP,
+ &rq_num, sizeof(rq_num),
+ &rq_num, &out_size);
+ if (err || !out_size || rq_num.status) {
+ dev_err(&pdev->dev,
+ "Failed to rxq number, ret = %d\n",
+ rq_num.status);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int hinic_set_rx_lro(struct hinic_dev *nic_dev, u8 ipv4_en, u8 ipv6_en,
+ u8 max_wqe_num)
+{
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic_hwif *hwif = hwdev->hwif;
+ struct hinic_lro_config lro_cfg = { 0 };
+ struct pci_dev *pdev = hwif->pdev;
+ u16 out_size = sizeof(lro_cfg);
+ int err;
+
+ lro_cfg.func_id = HINIC_HWIF_FUNC_IDX(hwif);
+ lro_cfg.lro_ipv4_en = ipv4_en;
+ lro_cfg.lro_ipv6_en = ipv6_en;
+ lro_cfg.lro_max_wqe_num = max_wqe_num;
+
+ err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_SET_LRO,
+ &lro_cfg, sizeof(lro_cfg),
+ &lro_cfg, &out_size);
+ if (err || !out_size || lro_cfg.status) {
+ dev_err(&pdev->dev,
+ "Failed to set lro offload, ret = %d\n",
+ lro_cfg.status);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int hinic_set_rx_lro_timer(struct hinic_dev *nic_dev, u32 timer_value)
+{
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic_lro_timer lro_timer = { 0 };
+ struct hinic_hwif *hwif = hwdev->hwif;
+ struct pci_dev *pdev = hwif->pdev;
+ u16 out_size = sizeof(lro_timer);
+ int err;
+
+ lro_timer.status = 0;
+ lro_timer.type = 0;
+ lro_timer.enable = 1;
+ lro_timer.timer = timer_value;
+
+ err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_SET_LRO_TIMER,
+ &lro_timer, sizeof(lro_timer),
+ &lro_timer, &out_size);
+ if (lro_timer.status == 0xFF) {
+ /* For this case, we think status (0xFF) is OK */
+ lro_timer.status = 0;
+ dev_dbg(&pdev->dev,
+ "Set lro timer not supported by the current FW version, it will be 1ms default\n");
+ }
+
+ if (err || !out_size || lro_timer.status) {
+ dev_err(&pdev->dev,
+ "Failed to set lro timer, ret = %d\n",
+ lro_timer.status);
+
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int hinic_set_rx_lro_state(struct hinic_dev *nic_dev, u8 lro_en,
+ u32 lro_timer, u32 wqe_num)
+{
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ u8 ipv4_en;
+ u8 ipv6_en;
+ int err;
+
+ if (!hwdev)
+ return -EINVAL;
+
+ ipv4_en = lro_en ? 1 : 0;
+ ipv6_en = lro_en ? 1 : 0;
+
+ err = hinic_set_rx_lro(nic_dev, ipv4_en, ipv6_en, (u8)wqe_num);
+ if (err)
+ return err;
+
+ err = hinic_set_rx_lro_timer(nic_dev, lro_timer);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+int hinic_rss_set_indir_tbl(struct hinic_dev *nic_dev, u32 tmpl_idx,
+ const u32 *indir_table)
+{
+ struct hinic_rss_indirect_tbl *indir_tbl;
+ struct hinic_func_to_io *func_to_io;
+ struct hinic_cmdq_buf cmd_buf;
+ struct hinic_hwdev *hwdev;
+ struct hinic_hwif *hwif;
+ struct pci_dev *pdev;
+ u32 indir_size;
+ u64 out_param;
+ int err, i;
+ u32 *temp;
+
+ hwdev = nic_dev->hwdev;
+ func_to_io = &hwdev->func_to_io;
+ hwif = hwdev->hwif;
+ pdev = hwif->pdev;
+
+ err = hinic_alloc_cmdq_buf(&func_to_io->cmdqs, &cmd_buf);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to allocate cmdq buf\n");
+ return err;
+ }
+
+ cmd_buf.size = sizeof(*indir_tbl);
+
+ indir_tbl = cmd_buf.buf;
+ indir_tbl->group_index = cpu_to_be32(tmpl_idx);
+
+ for (i = 0; i < HINIC_RSS_INDIR_SIZE; i++) {
+ indir_tbl->entry[i] = indir_table[i];
+
+ if (0x3 == (i & 0x3)) {
+ temp = (u32 *)&indir_tbl->entry[i - 3];
+ *temp = cpu_to_be32(*temp);
+ }
+ }
+
+ /* cfg the rss indirect table by command queue */
+ indir_size = HINIC_RSS_INDIR_SIZE / 2;
+ indir_tbl->offset = 0;
+ indir_tbl->size = cpu_to_be32(indir_size);
+
+ err = hinic_cmdq_direct_resp(&func_to_io->cmdqs, HINIC_MOD_L2NIC,
+ HINIC_UCODE_CMD_SET_RSS_INDIR_TABLE,
+ &cmd_buf, &out_param);
+ if (err || out_param != 0) {
+ dev_err(&pdev->dev, "Failed to set rss indir table\n");
+ err = -EFAULT;
+ goto free_buf;
+ }
+
+ indir_tbl->offset = cpu_to_be32(indir_size);
+ indir_tbl->size = cpu_to_be32(indir_size);
+ memcpy(&indir_tbl->entry[0], &indir_tbl->entry[indir_size], indir_size);
+
+ err = hinic_cmdq_direct_resp(&func_to_io->cmdqs, HINIC_MOD_L2NIC,
+ HINIC_UCODE_CMD_SET_RSS_INDIR_TABLE,
+ &cmd_buf, &out_param);
+ if (err || out_param != 0) {
+ dev_err(&pdev->dev, "Failed to set rss indir table\n");
+ err = -EFAULT;
+ }
+
+free_buf:
+ hinic_free_cmdq_buf(&func_to_io->cmdqs, &cmd_buf);
+
+ return err;
+}
+
+int hinic_rss_get_indir_tbl(struct hinic_dev *nic_dev, u32 tmpl_idx,
+ u32 *indir_table)
+{
+ struct hinic_rss_indir_table rss_cfg = { 0 };
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic_hwif *hwif = hwdev->hwif;
+ struct pci_dev *pdev = hwif->pdev;
+ u16 out_size = sizeof(rss_cfg);
+ int err = 0, i;
+
+ rss_cfg.func_id = HINIC_HWIF_FUNC_IDX(hwif);
+ rss_cfg.template_id = tmpl_idx;
+
+ err = hinic_port_msg_cmd(hwdev,
+ HINIC_PORT_CMD_GET_RSS_TEMPLATE_INDIR_TBL,
+ &rss_cfg, sizeof(rss_cfg), &rss_cfg,
+ &out_size);
+ if (err || !out_size || rss_cfg.status) {
+ dev_err(&pdev->dev, "Failed to get indir table, err: %d, status: 0x%x, out size: 0x%x\n",
+ err, rss_cfg.status, out_size);
+ return -EINVAL;
+ }
+
+ hinic_be32_to_cpu(rss_cfg.indir, HINIC_RSS_INDIR_SIZE);
+ for (i = 0; i < HINIC_RSS_INDIR_SIZE; i++)
+ indir_table[i] = rss_cfg.indir[i];
+
+ return 0;
+}
+
+int hinic_set_rss_type(struct hinic_dev *nic_dev, u32 tmpl_idx,
+ struct hinic_rss_type rss_type)
+{
+ struct hinic_rss_context_tbl *ctx_tbl;
+ struct hinic_func_to_io *func_to_io;
+ struct hinic_cmdq_buf cmd_buf;
+ struct hinic_hwdev *hwdev;
+ struct hinic_hwif *hwif;
+ struct pci_dev *pdev;
+ u64 out_param;
+ u32 ctx = 0;
+ int err;
+
+ hwdev = nic_dev->hwdev;
+ func_to_io = &hwdev->func_to_io;
+ hwif = hwdev->hwif;
+ pdev = hwif->pdev;
+
+ err = hinic_alloc_cmdq_buf(&func_to_io->cmdqs, &cmd_buf);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to allocate cmd buf\n");
+ return -ENOMEM;
+ }
+
+ ctx |= HINIC_RSS_TYPE_SET(1, VALID) |
+ HINIC_RSS_TYPE_SET(rss_type.ipv4, IPV4) |
+ HINIC_RSS_TYPE_SET(rss_type.ipv6, IPV6) |
+ HINIC_RSS_TYPE_SET(rss_type.ipv6_ext, IPV6_EXT) |
+ HINIC_RSS_TYPE_SET(rss_type.tcp_ipv4, TCP_IPV4) |
+ HINIC_RSS_TYPE_SET(rss_type.tcp_ipv6, TCP_IPV6) |
+ HINIC_RSS_TYPE_SET(rss_type.tcp_ipv6_ext, TCP_IPV6_EXT) |
+ HINIC_RSS_TYPE_SET(rss_type.udp_ipv4, UDP_IPV4) |
+ HINIC_RSS_TYPE_SET(rss_type.udp_ipv6, UDP_IPV6);
+
+ cmd_buf.size = sizeof(struct hinic_rss_context_tbl);
+
+ ctx_tbl = (struct hinic_rss_context_tbl *)cmd_buf.buf;
+ ctx_tbl->group_index = cpu_to_be32(tmpl_idx);
+ ctx_tbl->offset = 0;
+ ctx_tbl->size = sizeof(u32);
+ ctx_tbl->size = cpu_to_be32(ctx_tbl->size);
+ ctx_tbl->rsvd = 0;
+ ctx_tbl->ctx = cpu_to_be32(ctx);
+
+ /* cfg the rss context table by command queue */
+ err = hinic_cmdq_direct_resp(&func_to_io->cmdqs, HINIC_MOD_L2NIC,
+ HINIC_UCODE_CMD_SET_RSS_CONTEXT_TABLE,
+ &cmd_buf, &out_param);
+
+ hinic_free_cmdq_buf(&func_to_io->cmdqs, &cmd_buf);
+
+ if (err || out_param != 0) {
+ dev_err(&pdev->dev, "Failed to set rss context table, err: %d\n",
+ err);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int hinic_get_rss_type(struct hinic_dev *nic_dev, u32 tmpl_idx,
+ struct hinic_rss_type *rss_type)
+{
+ struct hinic_rss_context_table ctx_tbl = { 0 };
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic_hwif *hwif;
+ struct pci_dev *pdev;
+ u16 out_size = sizeof(ctx_tbl);
+ int err;
+
+ if (!hwdev || !rss_type)
+ return -EINVAL;
+
+ hwif = hwdev->hwif;
+ pdev = hwif->pdev;
+
+ ctx_tbl.func_id = HINIC_HWIF_FUNC_IDX(hwif);
+ ctx_tbl.template_id = tmpl_idx;
+
+ err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_GET_RSS_CTX_TBL,
+ &ctx_tbl, sizeof(ctx_tbl),
+ &ctx_tbl, &out_size);
+ if (err || !out_size || ctx_tbl.status) {
+ dev_err(&pdev->dev, "Failed to get hash type, err: %d, status: 0x%x, out size: 0x%x\n",
+ err, ctx_tbl.status, out_size);
+ return -EINVAL;
+ }
+
+ rss_type->ipv4 = HINIC_RSS_TYPE_GET(ctx_tbl.context, IPV4);
+ rss_type->ipv6 = HINIC_RSS_TYPE_GET(ctx_tbl.context, IPV6);
+ rss_type->ipv6_ext = HINIC_RSS_TYPE_GET(ctx_tbl.context, IPV6_EXT);
+ rss_type->tcp_ipv4 = HINIC_RSS_TYPE_GET(ctx_tbl.context, TCP_IPV4);
+ rss_type->tcp_ipv6 = HINIC_RSS_TYPE_GET(ctx_tbl.context, TCP_IPV6);
+ rss_type->tcp_ipv6_ext = HINIC_RSS_TYPE_GET(ctx_tbl.context,
+ TCP_IPV6_EXT);
+ rss_type->udp_ipv4 = HINIC_RSS_TYPE_GET(ctx_tbl.context, UDP_IPV4);
+ rss_type->udp_ipv6 = HINIC_RSS_TYPE_GET(ctx_tbl.context, UDP_IPV6);
+
+ return 0;
+}
+
+int hinic_rss_set_template_tbl(struct hinic_dev *nic_dev, u32 template_id,
+ const u8 *temp)
+{
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic_hwif *hwif = hwdev->hwif;
+ struct hinic_rss_key rss_key = { 0 };
+ struct pci_dev *pdev = hwif->pdev;
+ u16 out_size;
+ int err;
+
+ rss_key.func_id = HINIC_HWIF_FUNC_IDX(hwif);
+ rss_key.template_id = template_id;
+ memcpy(rss_key.key, temp, HINIC_RSS_KEY_SIZE);
+
+ err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_SET_RSS_TEMPLATE_TBL,
+ &rss_key, sizeof(rss_key),
+ &rss_key, &out_size);
+ if (err || !out_size || rss_key.status) {
+ dev_err(&pdev->dev,
+ "Failed to set rss hash key, err: %d, status: 0x%x, out size: 0x%x\n",
+ err, rss_key.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int hinic_rss_get_template_tbl(struct hinic_dev *nic_dev, u32 tmpl_idx,
+ u8 *temp)
+{
+ struct hinic_rss_template_key temp_key = { 0 };
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic_hwif *hwif;
+ struct pci_dev *pdev;
+ u16 out_size = sizeof(temp_key);
+ int err;
+
+ if (!hwdev || !temp)
+ return -EINVAL;
+
+ hwif = hwdev->hwif;
+ pdev = hwif->pdev;
+
+ temp_key.func_id = HINIC_HWIF_FUNC_IDX(hwif);
+ temp_key.template_id = tmpl_idx;
+
+ err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_GET_RSS_TEMPLATE_TBL,
+ &temp_key, sizeof(temp_key),
+ &temp_key, &out_size);
+ if (err || !out_size || temp_key.status) {
+ dev_err(&pdev->dev, "Failed to set hash key, err: %d, status: 0x%x, out size: 0x%x\n",
+ err, temp_key.status, out_size);
+ return -EINVAL;
+ }
+
+ memcpy(temp, temp_key.key, HINIC_RSS_KEY_SIZE);
+
+ return 0;
+}
+
+int hinic_rss_set_hash_engine(struct hinic_dev *nic_dev, u8 template_id,
+ u8 type)
+{
+ struct hinic_rss_engine_type rss_engine = { 0 };
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic_hwif *hwif = hwdev->hwif;
+ struct pci_dev *pdev = hwif->pdev;
+ u16 out_size;
+ int err;
+
+ rss_engine.func_id = HINIC_HWIF_FUNC_IDX(hwif);
+ rss_engine.hash_engine = type;
+ rss_engine.template_id = template_id;
+
+ err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_SET_RSS_HASH_ENGINE,
+ &rss_engine, sizeof(rss_engine),
+ &rss_engine, &out_size);
+ if (err || !out_size || rss_engine.status) {
+ dev_err(&pdev->dev,
+ "Failed to set hash engine, err: %d, status: 0x%x, out size: 0x%x\n",
+ err, rss_engine.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int hinic_rss_get_hash_engine(struct hinic_dev *nic_dev, u8 tmpl_idx, u8 *type)
+{
+ struct hinic_rss_engine_type hash_type = { 0 };
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic_hwif *hwif;
+ struct pci_dev *pdev;
+ u16 out_size = sizeof(hash_type);
+ int err;
+
+ if (!hwdev || !type)
+ return -EINVAL;
+
+ hwif = hwdev->hwif;
+ pdev = hwif->pdev;
+
+ hash_type.func_id = HINIC_HWIF_FUNC_IDX(hwif);
+ hash_type.template_id = tmpl_idx;
+
+ err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_GET_RSS_HASH_ENGINE,
+ &hash_type, sizeof(hash_type),
+ &hash_type, &out_size);
+ if (err || !out_size || hash_type.status) {
+ dev_err(&pdev->dev, "Failed to get hash engine, err: %d, status: 0x%x, out size: 0x%x\n",
+ err, hash_type.status, out_size);
+ return -EINVAL;
+ }
+
+ *type = hash_type.hash_engine;
+ return 0;
+}
+
+int hinic_rss_cfg(struct hinic_dev *nic_dev, u8 rss_en, u8 template_id)
+{
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic_rss_config rss_cfg = { 0 };
+ struct hinic_hwif *hwif = hwdev->hwif;
+ struct pci_dev *pdev = hwif->pdev;
+ u16 out_size;
+ int err;
+
+ rss_cfg.func_id = HINIC_HWIF_FUNC_IDX(hwif);
+ rss_cfg.rss_en = rss_en;
+ rss_cfg.template_id = template_id;
+ rss_cfg.rq_priority_number = 0;
+
+ err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_RSS_CFG,
+ &rss_cfg, sizeof(rss_cfg),
+ &rss_cfg, &out_size);
+ if (err || !out_size || rss_cfg.status) {
+ dev_err(&pdev->dev,
+ "Failed to set rss cfg, err: %d, status: 0x%x, out size: 0x%x\n",
+ err, rss_cfg.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int hinic_rss_template_alloc(struct hinic_dev *nic_dev, u8 *tmpl_idx)
+{
+ struct hinic_rss_template_mgmt template_mgmt = { 0 };
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic_hwif *hwif = hwdev->hwif;
+ struct pci_dev *pdev = hwif->pdev;
+ u16 out_size;
+ int err;
+
+ template_mgmt.func_id = HINIC_HWIF_FUNC_IDX(hwif);
+ template_mgmt.cmd = NIC_RSS_CMD_TEMP_ALLOC;
+
+ err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_RSS_TEMP_MGR,
+ &template_mgmt, sizeof(template_mgmt),
+ &template_mgmt, &out_size);
+ if (err || !out_size || template_mgmt.status) {
+ dev_err(&pdev->dev, "Failed to alloc rss template, err: %d, status: 0x%x, out size: 0x%x\n",
+ err, template_mgmt.status, out_size);
+ return -EINVAL;
+ }
+
+ *tmpl_idx = template_mgmt.template_id;
+
+ return 0;
+}
+
+int hinic_rss_template_free(struct hinic_dev *nic_dev, u8 tmpl_idx)
+{
+ struct hinic_rss_template_mgmt template_mgmt = { 0 };
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic_hwif *hwif = hwdev->hwif;
+ struct pci_dev *pdev = hwif->pdev;
+ u16 out_size;
+ int err;
+
+ template_mgmt.func_id = HINIC_HWIF_FUNC_IDX(hwif);
+ template_mgmt.template_id = tmpl_idx;
+ template_mgmt.cmd = NIC_RSS_CMD_TEMP_FREE;
+
+ err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_RSS_TEMP_MGR,
+ &template_mgmt, sizeof(template_mgmt),
+ &template_mgmt, &out_size);
+ if (err || !out_size || template_mgmt.status) {
+ dev_err(&pdev->dev, "Failed to free rss template, err: %d, status: 0x%x, out size: 0x%x\n",
+ err, template_mgmt.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int hinic_get_vport_stats(struct hinic_dev *nic_dev,
+ struct hinic_vport_stats *stats)
+{
+ struct hinic_cmd_vport_stats vport_stats = { 0 };
+ struct hinic_port_stats_info stats_info = { 0 };
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic_hwif *hwif = hwdev->hwif;
+ u16 out_size = sizeof(vport_stats);
+ struct pci_dev *pdev = hwif->pdev;
+ int err;
+
+ stats_info.stats_version = HINIC_PORT_STATS_VERSION;
+ stats_info.func_id = HINIC_HWIF_FUNC_IDX(hwif);
+ stats_info.stats_size = sizeof(vport_stats);
+
+ err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_GET_VPORT_STAT,
+ &stats_info, sizeof(stats_info),
+ &vport_stats, &out_size);
+ if (err || !out_size || vport_stats.status) {
+ dev_err(&pdev->dev,
+ "Failed to get function statistics, err: %d, status: 0x%x, out size: 0x%x\n",
+ err, vport_stats.status, out_size);
+ return -EFAULT;
+ }
+
+ memcpy(stats, &vport_stats.stats, sizeof(*stats));
+ return 0;
+}
+
+int hinic_get_phy_port_stats(struct hinic_dev *nic_dev,
+ struct hinic_phy_port_stats *stats)
+{
+ struct hinic_port_stats_info stats_info = { 0 };
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic_hwif *hwif = hwdev->hwif;
+ struct hinic_port_stats *port_stats;
+ u16 out_size = sizeof(*port_stats);
+ struct pci_dev *pdev = hwif->pdev;
+ int err;
+
+ port_stats = kzalloc(sizeof(*port_stats), GFP_KERNEL);
+ if (!port_stats)
+ return -ENOMEM;
+
+ stats_info.stats_version = HINIC_PORT_STATS_VERSION;
+ stats_info.stats_size = sizeof(*port_stats);
+
+ err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_GET_PORT_STATISTICS,
+ &stats_info, sizeof(stats_info),
+ port_stats, &out_size);
+ if (err || !out_size || port_stats->status) {
+ dev_err(&pdev->dev,
+ "Failed to get port statistics, err: %d, status: 0x%x, out size: 0x%x\n",
+ err, port_stats->status, out_size);
+ err = -EINVAL;
+ goto out;
+ }
+
+ memcpy(stats, &port_stats->stats, sizeof(*stats));
+
+out:
+ kfree(port_stats);
+
+ return err;
+}
+
+int hinic_get_mgmt_version(struct hinic_dev *nic_dev, u8 *mgmt_ver)
+{
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic_version_info up_ver = {0};
+ struct hinic_hwif *hwif;
+ struct pci_dev *pdev;
+ u16 out_size;
+ int err;
+
+ if (!hwdev)
+ return -EINVAL;
+
+ hwif = hwdev->hwif;
+ pdev = hwif->pdev;
+
+ err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_GET_MGMT_VERSION,
+ &up_ver, sizeof(up_ver), &up_ver,
+ &out_size);
+ if (err || !out_size || up_ver.status) {
+ dev_err(&pdev->dev,
+ "Failed to get mgmt version, err: %d, status: 0x%x, out size: 0x%x\n",
+ err, up_ver.status, out_size);
+ return -EINVAL;
+ }
+
+ snprintf(mgmt_ver, HINIC_MGMT_VERSION_MAX_LEN, "%s", up_ver.ver);
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_port.h b/drivers/net/ethernet/huawei/hinic/hinic_port.h
index c562afd206be..44772fd47fc1 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_port.h
+++ b/drivers/net/ethernet/huawei/hinic/hinic_port.h
@@ -13,6 +13,22 @@
#include "hinic_dev.h"
+#define HINIC_RSS_KEY_SIZE 40
+#define HINIC_RSS_INDIR_SIZE 256
+#define HINIC_PORT_STATS_VERSION 0
+#define HINIC_FW_VERSION_NAME 16
+#define HINIC_COMPILE_TIME_LEN 20
+#define HINIC_MGMT_VERSION_MAX_LEN 32
+
+struct hinic_version_info {
+ u8 status;
+ u8 version;
+ u8 rsvd[6];
+
+ u8 ver[HINIC_FW_VERSION_NAME];
+ u8 time[HINIC_COMPILE_TIME_LEN];
+};
+
enum hinic_rx_mode {
HINIC_RX_MODE_UC = BIT(0),
HINIC_RX_MODE_MC = BIT(1),
@@ -183,6 +199,313 @@ struct hinic_checksum_offload {
u16 rsvd1;
u32 rx_csum_offload;
};
+
+struct hinic_rq_num {
+ u8 status;
+ u8 version;
+ u8 rsvd0[6];
+
+ u16 func_id;
+ u16 rsvd1[33];
+ u32 num_rqs;
+ u32 rq_depth;
+};
+
+struct hinic_lro_config {
+ u8 status;
+ u8 version;
+ u8 rsvd0[6];
+
+ u16 func_id;
+ u16 rsvd1;
+ u8 lro_ipv4_en;
+ u8 lro_ipv6_en;
+ u8 lro_max_wqe_num;
+ u8 resv2[13];
+};
+
+struct hinic_lro_timer {
+ u8 status;
+ u8 version;
+ u8 rsvd0[6];
+
+ u8 type; /* 0: set timer value, 1: get timer value */
+ u8 enable; /* when set lro time, enable should be 1 */
+ u16 rsvd1;
+ u32 timer;
+};
+
+struct hinic_vlan_cfg {
+ u8 status;
+ u8 version;
+ u8 rsvd0[6];
+
+ u16 func_id;
+ u8 vlan_rx_offload;
+ u8 rsvd1[5];
+};
+
+struct hinic_rss_template_mgmt {
+ u8 status;
+ u8 version;
+ u8 rsvd0[6];
+
+ u16 func_id;
+ u8 cmd;
+ u8 template_id;
+ u8 rsvd1[4];
+};
+
+struct hinic_rss_template_key {
+ u8 status;
+ u8 version;
+ u8 rsvd0[6];
+
+ u16 func_id;
+ u8 template_id;
+ u8 rsvd1;
+ u8 key[HINIC_RSS_KEY_SIZE];
+};
+
+struct hinic_rss_context_tbl {
+ u32 group_index;
+ u32 offset;
+ u32 size;
+ u32 rsvd;
+ u32 ctx;
+};
+
+struct hinic_rss_context_table {
+ u8 status;
+ u8 version;
+ u8 rsvd0[6];
+
+ u16 func_id;
+ u8 template_id;
+ u8 rsvd1;
+ u32 context;
+};
+
+struct hinic_rss_indirect_tbl {
+ u32 group_index;
+ u32 offset;
+ u32 size;
+ u32 rsvd;
+ u8 entry[HINIC_RSS_INDIR_SIZE];
+};
+
+struct hinic_rss_indir_table {
+ u8 status;
+ u8 version;
+ u8 rsvd0[6];
+
+ u16 func_id;
+ u8 template_id;
+ u8 rsvd1;
+ u8 indir[HINIC_RSS_INDIR_SIZE];
+};
+
+struct hinic_rss_key {
+ u8 status;
+ u8 version;
+ u8 rsvd0[6];
+
+ u16 func_id;
+ u8 template_id;
+ u8 rsvd1;
+ u8 key[HINIC_RSS_KEY_SIZE];
+};
+
+struct hinic_rss_engine_type {
+ u8 status;
+ u8 version;
+ u8 rsvd0[6];
+
+ u16 func_id;
+ u8 template_id;
+ u8 hash_engine;
+ u8 rsvd1[4];
+};
+
+struct hinic_rss_config {
+ u8 status;
+ u8 version;
+ u8 rsvd0[6];
+
+ u16 func_id;
+ u8 rss_en;
+ u8 template_id;
+ u8 rq_priority_number;
+ u8 rsvd1[11];
+};
+
+struct hinic_stats {
+ char name[ETH_GSTRING_LEN];
+ u32 size;
+ int offset;
+};
+
+struct hinic_vport_stats {
+ u64 tx_unicast_pkts_vport;
+ u64 tx_unicast_bytes_vport;
+ u64 tx_multicast_pkts_vport;
+ u64 tx_multicast_bytes_vport;
+ u64 tx_broadcast_pkts_vport;
+ u64 tx_broadcast_bytes_vport;
+
+ u64 rx_unicast_pkts_vport;
+ u64 rx_unicast_bytes_vport;
+ u64 rx_multicast_pkts_vport;
+ u64 rx_multicast_bytes_vport;
+ u64 rx_broadcast_pkts_vport;
+ u64 rx_broadcast_bytes_vport;
+
+ u64 tx_discard_vport;
+ u64 rx_discard_vport;
+ u64 tx_err_vport;
+ u64 rx_err_vport;
+};
+
+struct hinic_phy_port_stats {
+ u64 mac_rx_total_pkt_num;
+ u64 mac_rx_total_oct_num;
+ u64 mac_rx_bad_pkt_num;
+ u64 mac_rx_bad_oct_num;
+ u64 mac_rx_good_pkt_num;
+ u64 mac_rx_good_oct_num;
+ u64 mac_rx_uni_pkt_num;
+ u64 mac_rx_multi_pkt_num;
+ u64 mac_rx_broad_pkt_num;
+
+ u64 mac_tx_total_pkt_num;
+ u64 mac_tx_total_oct_num;
+ u64 mac_tx_bad_pkt_num;
+ u64 mac_tx_bad_oct_num;
+ u64 mac_tx_good_pkt_num;
+ u64 mac_tx_good_oct_num;
+ u64 mac_tx_uni_pkt_num;
+ u64 mac_tx_multi_pkt_num;
+ u64 mac_tx_broad_pkt_num;
+
+ u64 mac_rx_fragment_pkt_num;
+ u64 mac_rx_undersize_pkt_num;
+ u64 mac_rx_undermin_pkt_num;
+ u64 mac_rx_64_oct_pkt_num;
+ u64 mac_rx_65_127_oct_pkt_num;
+ u64 mac_rx_128_255_oct_pkt_num;
+ u64 mac_rx_256_511_oct_pkt_num;
+ u64 mac_rx_512_1023_oct_pkt_num;
+ u64 mac_rx_1024_1518_oct_pkt_num;
+ u64 mac_rx_1519_2047_oct_pkt_num;
+ u64 mac_rx_2048_4095_oct_pkt_num;
+ u64 mac_rx_4096_8191_oct_pkt_num;
+ u64 mac_rx_8192_9216_oct_pkt_num;
+ u64 mac_rx_9217_12287_oct_pkt_num;
+ u64 mac_rx_12288_16383_oct_pkt_num;
+ u64 mac_rx_1519_max_bad_pkt_num;
+ u64 mac_rx_1519_max_good_pkt_num;
+ u64 mac_rx_oversize_pkt_num;
+ u64 mac_rx_jabber_pkt_num;
+
+ u64 mac_rx_pause_num;
+ u64 mac_rx_pfc_pkt_num;
+ u64 mac_rx_pfc_pri0_pkt_num;
+ u64 mac_rx_pfc_pri1_pkt_num;
+ u64 mac_rx_pfc_pri2_pkt_num;
+ u64 mac_rx_pfc_pri3_pkt_num;
+ u64 mac_rx_pfc_pri4_pkt_num;
+ u64 mac_rx_pfc_pri5_pkt_num;
+ u64 mac_rx_pfc_pri6_pkt_num;
+ u64 mac_rx_pfc_pri7_pkt_num;
+ u64 mac_rx_control_pkt_num;
+ u64 mac_rx_y1731_pkt_num;
+ u64 mac_rx_sym_err_pkt_num;
+ u64 mac_rx_fcs_err_pkt_num;
+ u64 mac_rx_send_app_good_pkt_num;
+ u64 mac_rx_send_app_bad_pkt_num;
+
+ u64 mac_tx_fragment_pkt_num;
+ u64 mac_tx_undersize_pkt_num;
+ u64 mac_tx_undermin_pkt_num;
+ u64 mac_tx_64_oct_pkt_num;
+ u64 mac_tx_65_127_oct_pkt_num;
+ u64 mac_tx_128_255_oct_pkt_num;
+ u64 mac_tx_256_511_oct_pkt_num;
+ u64 mac_tx_512_1023_oct_pkt_num;
+ u64 mac_tx_1024_1518_oct_pkt_num;
+ u64 mac_tx_1519_2047_oct_pkt_num;
+ u64 mac_tx_2048_4095_oct_pkt_num;
+ u64 mac_tx_4096_8191_oct_pkt_num;
+ u64 mac_tx_8192_9216_oct_pkt_num;
+ u64 mac_tx_9217_12287_oct_pkt_num;
+ u64 mac_tx_12288_16383_oct_pkt_num;
+ u64 mac_tx_1519_max_bad_pkt_num;
+ u64 mac_tx_1519_max_good_pkt_num;
+ u64 mac_tx_oversize_pkt_num;
+ u64 mac_tx_jabber_pkt_num;
+
+ u64 mac_tx_pause_num;
+ u64 mac_tx_pfc_pkt_num;
+ u64 mac_tx_pfc_pri0_pkt_num;
+ u64 mac_tx_pfc_pri1_pkt_num;
+ u64 mac_tx_pfc_pri2_pkt_num;
+ u64 mac_tx_pfc_pri3_pkt_num;
+ u64 mac_tx_pfc_pri4_pkt_num;
+ u64 mac_tx_pfc_pri5_pkt_num;
+ u64 mac_tx_pfc_pri6_pkt_num;
+ u64 mac_tx_pfc_pri7_pkt_num;
+ u64 mac_tx_control_pkt_num;
+ u64 mac_tx_y1731_pkt_num;
+ u64 mac_tx_1588_pkt_num;
+ u64 mac_tx_err_all_pkt_num;
+ u64 mac_tx_from_app_good_pkt_num;
+ u64 mac_tx_from_app_bad_pkt_num;
+
+ u64 mac_rx_higig2_ext_pkt_num;
+ u64 mac_rx_higig2_message_pkt_num;
+ u64 mac_rx_higig2_error_pkt_num;
+ u64 mac_rx_higig2_cpu_ctrl_pkt_num;
+ u64 mac_rx_higig2_unicast_pkt_num;
+ u64 mac_rx_higig2_broadcast_pkt_num;
+ u64 mac_rx_higig2_l2_multicast_pkt_num;
+ u64 mac_rx_higig2_l3_multicast_pkt_num;
+
+ u64 mac_tx_higig2_message_pkt_num;
+ u64 mac_tx_higig2_ext_pkt_num;
+ u64 mac_tx_higig2_cpu_ctrl_pkt_num;
+ u64 mac_tx_higig2_unicast_pkt_num;
+ u64 mac_tx_higig2_broadcast_pkt_num;
+ u64 mac_tx_higig2_l2_multicast_pkt_num;
+ u64 mac_tx_higig2_l3_multicast_pkt_num;
+};
+
+struct hinic_port_stats_info {
+ u8 status;
+ u8 version;
+ u8 rsvd0[6];
+
+ u16 func_id;
+ u16 rsvd1;
+ u32 stats_version;
+ u32 stats_size;
+};
+
+struct hinic_port_stats {
+ u8 status;
+ u8 version;
+ u8 rsvd[6];
+
+ struct hinic_phy_port_stats stats;
+};
+
+struct hinic_cmd_vport_stats {
+ u8 status;
+ u8 version;
+ u8 rsvd0[6];
+
+ struct hinic_vport_stats stats;
+};
+
int hinic_port_add_mac(struct hinic_dev *nic_dev, const u8 *addr,
u16 vlan_id);
@@ -211,7 +534,55 @@ int hinic_port_set_func_state(struct hinic_dev *nic_dev,
int hinic_port_get_cap(struct hinic_dev *nic_dev,
struct hinic_port_cap *port_cap);
+int hinic_set_max_qnum(struct hinic_dev *nic_dev, u8 num_rqs);
+
int hinic_port_set_tso(struct hinic_dev *nic_dev, enum hinic_tso_state state);
int hinic_set_rx_csum_offload(struct hinic_dev *nic_dev, u32 en);
+
+int hinic_set_rx_lro_state(struct hinic_dev *nic_dev, u8 lro_en,
+ u32 lro_timer, u32 wqe_num);
+
+int hinic_set_rss_type(struct hinic_dev *nic_dev, u32 tmpl_idx,
+ struct hinic_rss_type rss_type);
+
+int hinic_rss_set_indir_tbl(struct hinic_dev *nic_dev, u32 tmpl_idx,
+ const u32 *indir_table);
+
+int hinic_rss_set_template_tbl(struct hinic_dev *nic_dev, u32 template_id,
+ const u8 *temp);
+
+int hinic_rss_set_hash_engine(struct hinic_dev *nic_dev, u8 template_id,
+ u8 type);
+
+int hinic_rss_cfg(struct hinic_dev *nic_dev, u8 rss_en, u8 template_id);
+
+int hinic_rss_template_alloc(struct hinic_dev *nic_dev, u8 *tmpl_idx);
+
+int hinic_rss_template_free(struct hinic_dev *nic_dev, u8 tmpl_idx);
+
+void hinic_set_ethtool_ops(struct net_device *netdev);
+
+int hinic_get_rss_type(struct hinic_dev *nic_dev, u32 tmpl_idx,
+ struct hinic_rss_type *rss_type);
+
+int hinic_rss_get_indir_tbl(struct hinic_dev *nic_dev, u32 tmpl_idx,
+ u32 *indir_table);
+
+int hinic_rss_get_template_tbl(struct hinic_dev *nic_dev, u32 tmpl_idx,
+ u8 *temp);
+
+int hinic_rss_get_hash_engine(struct hinic_dev *nic_dev, u8 tmpl_idx,
+ u8 *type);
+
+int hinic_get_phy_port_stats(struct hinic_dev *nic_dev,
+ struct hinic_phy_port_stats *stats);
+
+int hinic_get_vport_stats(struct hinic_dev *nic_dev,
+ struct hinic_vport_stats *stats);
+
+int hinic_set_rx_vlan_offload(struct hinic_dev *nic_dev, u8 en);
+
+int hinic_get_mgmt_version(struct hinic_dev *nic_dev, u8 *mgmt_ver);
+
#endif
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_rx.c b/drivers/net/ethernet/huawei/hinic/hinic_rx.c
index 0850ea83d6c1..56ea6d692f1c 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_rx.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_rx.c
@@ -18,6 +18,7 @@
#include <linux/dma-mapping.h>
#include <linux/prefetch.h>
#include <linux/cpumask.h>
+#include <linux/if_vlan.h>
#include <asm/barrier.h>
#include "hinic_common.h"
@@ -36,6 +37,15 @@
#define RX_IRQ_NO_RESEND_TIMER 0
#define HINIC_RX_BUFFER_WRITE 16
+#define HINIC_RX_IPV6_PKT 7
+#define LRO_PKT_HDR_LEN_IPV4 66
+#define LRO_PKT_HDR_LEN_IPV6 86
+#define LRO_REPLENISH_THLD 256
+
+#define LRO_PKT_HDR_LEN(cqe) \
+ (HINIC_GET_RX_PKT_TYPE(be32_to_cpu((cqe)->offload_type)) == \
+ HINIC_RX_IPV6_PKT ? LRO_PKT_HDR_LEN_IPV6 : LRO_PKT_HDR_LEN_IPV4)
+
/**
* hinic_rxq_clean_stats - Clean the statistics of specific queue
* @rxq: Logical Rx Queue
@@ -47,6 +57,9 @@ void hinic_rxq_clean_stats(struct hinic_rxq *rxq)
u64_stats_update_begin(&rxq_stats->syncp);
rxq_stats->pkts = 0;
rxq_stats->bytes = 0;
+ rxq_stats->errors = 0;
+ rxq_stats->csum_errors = 0;
+ rxq_stats->other_errors = 0;
u64_stats_update_end(&rxq_stats->syncp);
}
@@ -65,6 +78,10 @@ void hinic_rxq_get_stats(struct hinic_rxq *rxq, struct hinic_rxq_stats *stats)
start = u64_stats_fetch_begin(&rxq_stats->syncp);
stats->pkts = rxq_stats->pkts;
stats->bytes = rxq_stats->bytes;
+ stats->errors = rxq_stats->csum_errors +
+ rxq_stats->other_errors;
+ stats->csum_errors = rxq_stats->csum_errors;
+ stats->other_errors = rxq_stats->other_errors;
} while (u64_stats_fetch_retry(&rxq_stats->syncp, start));
u64_stats_update_end(&stats->syncp);
}
@@ -81,27 +98,25 @@ static void rxq_stats_init(struct hinic_rxq *rxq)
hinic_rxq_clean_stats(rxq);
}
-static void rx_csum(struct hinic_rxq *rxq, u16 cons_idx,
+static void rx_csum(struct hinic_rxq *rxq, u32 status,
struct sk_buff *skb)
{
struct net_device *netdev = rxq->netdev;
- struct hinic_rq_cqe *cqe;
- struct hinic_rq *rq;
u32 csum_err;
- u32 status;
- rq = rxq->rq;
- cqe = rq->cqe[cons_idx];
- status = be32_to_cpu(cqe->status);
csum_err = HINIC_RQ_CQE_STATUS_GET(status, CSUM_ERR);
if (!(netdev->features & NETIF_F_RXCSUM))
return;
- if (!csum_err)
+ if (!csum_err) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
- else
+ } else {
+ if (!(csum_err & (HINIC_RX_CSUM_HW_CHECK_NONE |
+ HINIC_RX_CSUM_IPSU_OTHER_ERR)))
+ rxq->rxq_stats.csum_errors++;
skb->ip_summed = CHECKSUM_NONE;
+ }
}
/**
* rx_alloc_skb - allocate skb and map it to dma address
@@ -311,13 +326,21 @@ static int rx_recv_jumbo_pkt(struct hinic_rxq *rxq, struct sk_buff *head_skb,
static int rxq_recv(struct hinic_rxq *rxq, int budget)
{
struct hinic_qp *qp = container_of(rxq->rq, struct hinic_qp, rq);
+ struct net_device *netdev = rxq->netdev;
u64 pkt_len = 0, rx_bytes = 0;
+ struct hinic_rq *rq = rxq->rq;
struct hinic_rq_wqe *rq_wqe;
unsigned int free_wqebbs;
+ struct hinic_rq_cqe *cqe;
int num_wqes, pkts = 0;
struct hinic_sge sge;
+ unsigned int status;
struct sk_buff *skb;
- u16 ci;
+ u32 offload_type;
+ u16 ci, num_lro;
+ u16 num_wqe = 0;
+ u32 vlan_len;
+ u16 vid;
while (pkts < budget) {
num_wqes = 0;
@@ -327,11 +350,13 @@ static int rxq_recv(struct hinic_rxq *rxq, int budget)
if (!rq_wqe)
break;
+ cqe = rq->cqe[ci];
+ status = be32_to_cpu(cqe->status);
hinic_rq_get_sge(rxq->rq, rq_wqe, ci, &sge);
rx_unmap_skb(rxq, hinic_sge_to_dma(&sge));
- rx_csum(rxq, ci, skb);
+ rx_csum(rxq, status, skb);
prefetch(skb->data);
@@ -345,9 +370,17 @@ static int rxq_recv(struct hinic_rxq *rxq, int budget)
HINIC_RX_BUF_SZ, ci);
}
- hinic_rq_put_wqe(rxq->rq, ci,
+ hinic_rq_put_wqe(rq, ci,
(num_wqes + 1) * HINIC_RQ_WQE_SIZE);
+ offload_type = be32_to_cpu(cqe->offload_type);
+ vlan_len = be32_to_cpu(cqe->len);
+ if ((netdev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
+ HINIC_GET_RX_VLAN_OFFLOAD_EN(offload_type)) {
+ vid = HINIC_GET_RX_VLAN_TAG(vlan_len);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
+ }
+
skb_record_rx_queue(skb, qp->q_id);
skb->protocol = eth_type_trans(skb, rxq->netdev);
@@ -355,6 +388,21 @@ static int rxq_recv(struct hinic_rxq *rxq, int budget)
pkts++;
rx_bytes += pkt_len;
+
+ num_lro = HINIC_GET_RX_NUM_LRO(status);
+ if (num_lro) {
+ rx_bytes += ((num_lro - 1) *
+ LRO_PKT_HDR_LEN(cqe));
+
+ num_wqe +=
+ (u16)(pkt_len >> rxq->rx_buff_shift) +
+ ((pkt_len & (rxq->buf_len - 1)) ? 1 : 0);
+ }
+
+ cqe->status = 0;
+
+ if (num_wqe >= LRO_REPLENISH_THLD)
+ break;
}
free_wqebbs = hinic_get_rq_free_wqebbs(rxq->rq);
@@ -469,20 +517,20 @@ int hinic_init_rxq(struct hinic_rxq *rxq, struct hinic_rq *rq,
struct net_device *netdev)
{
struct hinic_qp *qp = container_of(rq, struct hinic_qp, rq);
- int err, pkts, irqname_len;
+ int err, pkts;
rxq->netdev = netdev;
rxq->rq = rq;
+ rxq->buf_len = HINIC_RX_BUF_SZ;
+ rxq->rx_buff_shift = ilog2(HINIC_RX_BUF_SZ);
rxq_stats_init(rxq);
- irqname_len = snprintf(NULL, 0, "hinic_rxq%d", qp->q_id) + 1;
- rxq->irq_name = devm_kzalloc(&netdev->dev, irqname_len, GFP_KERNEL);
+ rxq->irq_name = devm_kasprintf(&netdev->dev, GFP_KERNEL,
+ "hinic_rxq%d", qp->q_id);
if (!rxq->irq_name)
return -ENOMEM;
- sprintf(rxq->irq_name, "hinic_rxq%d", qp->q_id);
-
pkts = rx_alloc_pkts(rxq);
if (!pkts) {
err = -ENOMEM;
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_rx.h b/drivers/net/ethernet/huawei/hinic/hinic_rx.h
index bc797498a87f..507dcbae9085 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_rx.h
+++ b/drivers/net/ethernet/huawei/hinic/hinic_rx.h
@@ -21,7 +21,10 @@
struct hinic_rxq_stats {
u64 pkts;
u64 bytes;
-
+ u64 errors;
+ u64 csum_errors;
+ u64 other_errors;
+ u64 alloc_skb_err;
struct u64_stats_sync syncp;
};
@@ -32,6 +35,8 @@ struct hinic_rxq {
struct hinic_rxq_stats rxq_stats;
char *irq_name;
+ u16 buf_len;
+ u32 rx_buff_shift;
struct napi_struct napi;
};
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_tx.c b/drivers/net/ethernet/huawei/hinic/hinic_tx.c
index b9fd8d720349..9c78251f9c39 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_tx.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_tx.c
@@ -83,6 +83,7 @@ void hinic_txq_clean_stats(struct hinic_txq *txq)
txq_stats->tx_busy = 0;
txq_stats->tx_wake = 0;
txq_stats->tx_dropped = 0;
+ txq_stats->big_frags_pkts = 0;
u64_stats_update_end(&txq_stats->syncp);
}
@@ -104,6 +105,7 @@ void hinic_txq_get_stats(struct hinic_txq *txq, struct hinic_txq_stats *stats)
stats->tx_busy = txq_stats->tx_busy;
stats->tx_wake = txq_stats->tx_wake;
stats->tx_dropped = txq_stats->tx_dropped;
+ stats->big_frags_pkts = txq_stats->big_frags_pkts;
} while (u64_stats_fetch_retry(&txq_stats->syncp, start));
u64_stats_update_end(&stats->syncp);
}
@@ -405,10 +407,20 @@ static int offload_csum(struct hinic_sq_task *task, u32 *queue_info,
return 1;
}
+static void offload_vlan(struct hinic_sq_task *task, u32 *queue_info,
+ u16 vlan_tag, u16 vlan_pri)
+{
+ task->pkt_info0 |= HINIC_SQ_TASK_INFO0_SET(vlan_tag, VLAN_TAG) |
+ HINIC_SQ_TASK_INFO0_SET(1U, VLAN_OFFLOAD);
+
+ *queue_info |= HINIC_SQ_CTRL_SET(vlan_pri, QUEUE_INFO_PRI);
+}
+
static int hinic_tx_offload(struct sk_buff *skb, struct hinic_sq_task *task,
u32 *queue_info)
{
enum hinic_offload_type offload = 0;
+ u16 vlan_tag;
int enabled;
enabled = offload_tso(task, queue_info, skb);
@@ -422,6 +434,13 @@ static int hinic_tx_offload(struct sk_buff *skb, struct hinic_sq_task *task,
return -EPROTONOSUPPORT;
}
+ if (unlikely(skb_vlan_tag_present(skb))) {
+ vlan_tag = skb_vlan_tag_get(skb);
+ offload_vlan(task, queue_info, vlan_tag,
+ vlan_tag >> VLAN_PRIO_SHIFT);
+ offload |= TX_OFFLOAD_VLAN;
+ }
+
if (offload)
hinic_task_set_l2hdr(task, skb_network_offset(skb));
@@ -464,6 +483,12 @@ netdev_tx_t hinic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
}
nr_sges = skb_shinfo(skb)->nr_frags + 1;
+ if (nr_sges > 17) {
+ u64_stats_update_begin(&txq->txq_stats.syncp);
+ txq->txq_stats.big_frags_pkts++;
+ u64_stats_update_end(&txq->txq_stats.syncp);
+ }
+
if (nr_sges > txq->max_sges) {
netdev_err(netdev, "Too many Tx sges\n");
goto skb_error;
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_tx.h b/drivers/net/ethernet/huawei/hinic/hinic_tx.h
index ca5f537fc383..f158b7db7fb8 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_tx.h
+++ b/drivers/net/ethernet/huawei/hinic/hinic_tx.h
@@ -21,6 +21,7 @@ struct hinic_txq_stats {
u64 tx_busy;
u64 tx_wake;
u64 tx_dropped;
+ u64 big_frags_pkts;
struct u64_stats_sync syncp;
};
diff --git a/drivers/net/ethernet/i825xx/ether1.c b/drivers/net/ethernet/i825xx/ether1.c
index 35f6291a3672..bb3b8adbe4f0 100644
--- a/drivers/net/ethernet/i825xx/ether1.c
+++ b/drivers/net/ethernet/i825xx/ether1.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/acorn/net/ether1.c
*
* Copyright (C) 1996-2000 Russell King
*
- * 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.
- *
* Acorn ether1 driver (82586 chip) for Acorn machines
*
* We basically keep two queues in the cards memory - one for transmit
diff --git a/drivers/net/ethernet/i825xx/ether1.h b/drivers/net/ethernet/i825xx/ether1.h
index 3a5830ab3dc7..3926e042fe2e 100644
--- a/drivers/net/ethernet/i825xx/ether1.h
+++ b/drivers/net/ethernet/i825xx/ether1.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/drivers/acorn/net/ether1.h
*
* Copyright (C) 1996 Russell King
*
- * 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.
- *
* Network driver for Acorn Ether1 cards.
*/
diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
index 3da392bfd659..3da680073265 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.c
+++ b/drivers/net/ethernet/ibm/ibmvnic.c
@@ -428,9 +428,10 @@ static int reset_rx_pools(struct ibmvnic_adapter *adapter)
if (rx_pool->buff_size != be64_to_cpu(size_array[i])) {
free_long_term_buff(adapter, &rx_pool->long_term_buff);
rx_pool->buff_size = be64_to_cpu(size_array[i]);
- alloc_long_term_buff(adapter, &rx_pool->long_term_buff,
- rx_pool->size *
- rx_pool->buff_size);
+ rc = alloc_long_term_buff(adapter,
+ &rx_pool->long_term_buff,
+ rx_pool->size *
+ rx_pool->buff_size);
} else {
rc = reset_long_term_buff(adapter,
&rx_pool->long_term_buff);
@@ -696,9 +697,9 @@ static int init_tx_pools(struct net_device *netdev)
return rc;
}
- init_one_tx_pool(netdev, &adapter->tso_pool[i],
- IBMVNIC_TSO_BUFS,
- IBMVNIC_TSO_BUF_SZ);
+ rc = init_one_tx_pool(netdev, &adapter->tso_pool[i],
+ IBMVNIC_TSO_BUFS,
+ IBMVNIC_TSO_BUF_SZ);
if (rc) {
release_tx_pools(adapter);
return rc;
@@ -1745,7 +1746,8 @@ static int do_reset(struct ibmvnic_adapter *adapter,
ibmvnic_cleanup(netdev);
- if (adapter->reset_reason != VNIC_RESET_MOBILITY &&
+ if (reset_state == VNIC_OPEN &&
+ adapter->reset_reason != VNIC_RESET_MOBILITY &&
adapter->reset_reason != VNIC_RESET_FAILOVER) {
rc = __ibmvnic_close(netdev);
if (rc)
@@ -1844,6 +1846,9 @@ static int do_reset(struct ibmvnic_adapter *adapter,
return 0;
}
+ /* refresh device's multicast list */
+ ibmvnic_set_multi(netdev);
+
/* kick napi */
for (i = 0; i < adapter->req_rx_queues; i++)
napi_schedule(&adapter->napi[i]);
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
index 551de8c2fef2..f703fa58458e 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -3019,7 +3019,7 @@ static void e1000_tx_queue(struct e1000_adapter *adapter,
* applicable for weak-ordered memory model archs,
* such as IA-64).
*/
- wmb();
+ dma_wmb();
tx_ring->next_to_use = i;
}
@@ -4540,7 +4540,7 @@ e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter,
* applicable for weak-ordered memory model archs,
* such as IA-64).
*/
- wmb();
+ dma_wmb();
writel(i, adapter->hw.hw_addr + rx_ring->rdt);
}
}
@@ -4655,7 +4655,7 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
* applicable for weak-ordered memory model archs,
* such as IA-64).
*/
- wmb();
+ dma_wmb();
writel(i, hw->hw_addr + rx_ring->rdt);
}
}
diff --git a/drivers/net/ethernet/intel/e1000e/80003es2lan.c b/drivers/net/ethernet/intel/e1000e/80003es2lan.c
index f86d55657959..4b103cca8a39 100644
--- a/drivers/net/ethernet/intel/e1000e/80003es2lan.c
+++ b/drivers/net/ethernet/intel/e1000e/80003es2lan.c
@@ -680,7 +680,7 @@ static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw)
ew32(TCTL, E1000_TCTL_PSP);
e1e_flush();
- usleep_range(10000, 20000);
+ usleep_range(10000, 11000);
ctrl = er32(CTRL);
diff --git a/drivers/net/ethernet/intel/e1000e/82571.c b/drivers/net/ethernet/intel/e1000e/82571.c
index b9309302c29e..2c1bab377b2a 100644
--- a/drivers/net/ethernet/intel/e1000e/82571.c
+++ b/drivers/net/ethernet/intel/e1000e/82571.c
@@ -959,7 +959,7 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
ew32(TCTL, tctl);
e1e_flush();
- usleep_range(10000, 20000);
+ usleep_range(10000, 11000);
/* Must acquire the MDIO ownership before MAC reset.
* Ownership defaults to firmware after a reset.
diff --git a/drivers/net/ethernet/intel/e1000e/defines.h b/drivers/net/ethernet/intel/e1000e/defines.h
index fd550dee4982..63c3c79380a1 100644
--- a/drivers/net/ethernet/intel/e1000e/defines.h
+++ b/drivers/net/ethernet/intel/e1000e/defines.h
@@ -222,6 +222,9 @@
#define E1000_STATUS_PHYRA 0x00000400 /* PHY Reset Asserted */
#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Master Req status */
+/* PCIm function state */
+#define E1000_STATUS_PCIM_STATE 0x40000000
+
#define HALF_DUPLEX 1
#define FULL_DUPLEX 2
diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h
index be13227f1697..34cd67951aec 100644
--- a/drivers/net/ethernet/intel/e1000e/e1000.h
+++ b/drivers/net/ethernet/intel/e1000e/e1000.h
@@ -186,12 +186,13 @@ struct e1000_phy_regs {
/* board specific private data structure */
struct e1000_adapter {
- struct timer_list watchdog_timer;
struct timer_list phy_info_timer;
struct timer_list blink_timer;
struct work_struct reset_task;
- struct work_struct watchdog_task;
+ struct delayed_work watchdog_task;
+
+ struct workqueue_struct *e1000_workqueue;
const struct e1000_info *ei;
diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c
index 02ebf208f48b..08342698386d 100644
--- a/drivers/net/ethernet/intel/e1000e/ethtool.c
+++ b/drivers/net/ethernet/intel/e1000e/ethtool.c
@@ -1014,7 +1014,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
/* Disable all the interrupts */
ew32(IMC, 0xFFFFFFFF);
e1e_flush();
- usleep_range(10000, 20000);
+ usleep_range(10000, 11000);
/* Test each interrupt */
for (i = 0; i < 10; i++) {
@@ -1046,7 +1046,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
ew32(IMC, mask);
ew32(ICS, mask);
e1e_flush();
- usleep_range(10000, 20000);
+ usleep_range(10000, 11000);
if (adapter->test_icr & mask) {
*data = 3;
@@ -1064,7 +1064,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
ew32(IMS, mask);
ew32(ICS, mask);
e1e_flush();
- usleep_range(10000, 20000);
+ usleep_range(10000, 11000);
if (!(adapter->test_icr & mask)) {
*data = 4;
@@ -1082,7 +1082,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
ew32(IMC, ~mask & 0x00007FFF);
ew32(ICS, ~mask & 0x00007FFF);
e1e_flush();
- usleep_range(10000, 20000);
+ usleep_range(10000, 11000);
if (adapter->test_icr) {
*data = 5;
@@ -1094,7 +1094,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
/* Disable all the interrupts */
ew32(IMC, 0xFFFFFFFF);
e1e_flush();
- usleep_range(10000, 20000);
+ usleep_range(10000, 11000);
/* Unhook test interrupt handler */
free_irq(irq, netdev);
@@ -1470,7 +1470,7 @@ static int e1000_set_82571_fiber_loopback(struct e1000_adapter *adapter)
*/
ew32(SCTL, E1000_SCTL_ENABLE_SERDES_LOOPBACK);
e1e_flush();
- usleep_range(10000, 20000);
+ usleep_range(10000, 11000);
return 0;
}
@@ -1584,7 +1584,7 @@ static void e1000_loopback_cleanup(struct e1000_adapter *adapter)
hw->phy.media_type == e1000_media_type_internal_serdes) {
ew32(SCTL, E1000_SCTL_DISABLE_SERDES_LOOPBACK);
e1e_flush();
- usleep_range(10000, 20000);
+ usleep_range(10000, 11000);
break;
}
/* Fall Through */
diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c
index cdae0efde8e6..395b05701480 100644
--- a/drivers/net/ethernet/intel/e1000e/ich8lan.c
+++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c
@@ -271,7 +271,7 @@ static void e1000_toggle_lanphypc_pch_lpt(struct e1000_hw *hw)
u16 count = 20;
do {
- usleep_range(5000, 10000);
+ usleep_range(5000, 6000);
} while (!(er32(CTRL_EXT) & E1000_CTRL_EXT_LPCD) && count--);
msleep(30);
@@ -405,7 +405,7 @@ out:
/* Ungate automatic PHY configuration on non-managed 82579 */
if ((hw->mac.type == e1000_pch2lan) &&
!(fwsm & E1000_ICH_FWSM_FW_VALID)) {
- usleep_range(10000, 20000);
+ usleep_range(10000, 11000);
e1000_gate_hw_phy_config_ich8lan(hw, false);
}
@@ -531,7 +531,7 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw)
phy->id = 0;
while ((e1000_phy_unknown == e1000e_get_phy_type_from_id(phy->id)) &&
(i++ < 100)) {
- usleep_range(1000, 2000);
+ usleep_range(1000, 1100);
ret_val = e1000e_get_phy_id(hw);
if (ret_val)
return ret_val;
@@ -1244,7 +1244,7 @@ static s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force)
goto out;
}
- usleep_range(10000, 20000);
+ usleep_range(10000, 11000);
}
e_dbg("ULP_CONFIG_DONE cleared after %dmsec\n", i * 10);
@@ -1999,7 +1999,7 @@ static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw)
while ((blocked = !(er32(FWSM) & E1000_ICH_FWSM_RSPCIPHY)) &&
(i++ < 30))
- usleep_range(10000, 20000);
+ usleep_range(10000, 11000);
return blocked ? E1000_BLK_PHY_RESET : 0;
}
@@ -2818,7 +2818,7 @@ static s32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw)
return 0;
/* Allow time for h/w to get to quiescent state after reset */
- usleep_range(10000, 20000);
+ usleep_range(10000, 11000);
/* Perform any necessary post-reset workarounds */
switch (hw->mac.type) {
@@ -2854,7 +2854,7 @@ static s32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw)
if (hw->mac.type == e1000_pch2lan) {
/* Ungate automatic PHY configuration on non-managed 82579 */
if (!(er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) {
- usleep_range(10000, 20000);
+ usleep_range(10000, 11000);
e1000_gate_hw_phy_config_ich8lan(hw, false);
}
@@ -3875,7 +3875,7 @@ release:
*/
if (!ret_val) {
nvm->ops.reload(hw);
- usleep_range(10000, 20000);
+ usleep_range(10000, 11000);
}
out:
@@ -4026,7 +4026,7 @@ release:
*/
if (!ret_val) {
nvm->ops.reload(hw);
- usleep_range(10000, 20000);
+ usleep_range(10000, 11000);
}
out:
@@ -4650,7 +4650,7 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
ew32(TCTL, E1000_TCTL_PSP);
e1e_flush();
- usleep_range(10000, 20000);
+ usleep_range(10000, 11000);
/* Workaround for ICH8 bit corruption issue in FIFO memory */
if (hw->mac.type == e1000_ich8lan) {
diff --git a/drivers/net/ethernet/intel/e1000e/mac.c b/drivers/net/ethernet/intel/e1000e/mac.c
index 4abd55d646c5..e531976f8a67 100644
--- a/drivers/net/ethernet/intel/e1000e/mac.c
+++ b/drivers/net/ethernet/intel/e1000e/mac.c
@@ -797,7 +797,7 @@ static s32 e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw)
* milliseconds even if the other end is doing it in SW).
*/
for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) {
- usleep_range(10000, 20000);
+ usleep_range(10000, 11000);
status = er32(STATUS);
if (status & E1000_STATUS_LU)
break;
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 0e09bede42a2..e4baa13b3cda 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -1780,7 +1780,8 @@ static irqreturn_t e1000_intr_msi(int __always_unused irq, void *data)
}
/* guard against interrupt when we're going down */
if (!test_bit(__E1000_DOWN, &adapter->state))
- mod_timer(&adapter->watchdog_timer, jiffies + 1);
+ queue_delayed_work(adapter->e1000_workqueue,
+ &adapter->watchdog_task, 1);
}
/* Reset on uncorrectable ECC error */
@@ -1860,7 +1861,8 @@ static irqreturn_t e1000_intr(int __always_unused irq, void *data)
}
/* guard against interrupt when we're going down */
if (!test_bit(__E1000_DOWN, &adapter->state))
- mod_timer(&adapter->watchdog_timer, jiffies + 1);
+ queue_delayed_work(adapter->e1000_workqueue,
+ &adapter->watchdog_task, 1);
}
/* Reset on uncorrectable ECC error */
@@ -1905,7 +1907,8 @@ static irqreturn_t e1000_msix_other(int __always_unused irq, void *data)
hw->mac.get_link_status = true;
/* guard against interrupt when we're going down */
if (!test_bit(__E1000_DOWN, &adapter->state))
- mod_timer(&adapter->watchdog_timer, jiffies + 1);
+ queue_delayed_work(adapter->e1000_workqueue,
+ &adapter->watchdog_task, 1);
}
if (!test_bit(__E1000_DOWN, &adapter->state))
@@ -3208,7 +3211,7 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
if (!(adapter->flags2 & FLAG2_NO_DISABLE_RX))
ew32(RCTL, rctl & ~E1000_RCTL_EN);
e1e_flush();
- usleep_range(10000, 20000);
+ usleep_range(10000, 11000);
if (adapter->flags2 & FLAG2_DMA_BURST) {
/* set the writeback threshold (only takes effect if the RDTR
@@ -4046,12 +4049,12 @@ void e1000e_reset(struct e1000_adapter *adapter)
case e1000_pch_lpt:
case e1000_pch_spt:
case e1000_pch_cnp:
- fc->refresh_time = 0x0400;
+ fc->refresh_time = 0xFFFF;
+ fc->pause_time = 0xFFFF;
if (adapter->netdev->mtu <= ETH_DATA_LEN) {
fc->high_water = 0x05C20;
fc->low_water = 0x05048;
- fc->pause_time = 0x0650;
break;
}
@@ -4208,7 +4211,7 @@ void e1000e_up(struct e1000_adapter *adapter)
e1000_configure_msix(adapter);
e1000_irq_enable(adapter);
- netif_start_queue(adapter->netdev);
+ /* Tx queue started by watchdog timer when link is up */
e1000e_trigger_lsc(adapter);
}
@@ -4272,13 +4275,12 @@ void e1000e_down(struct e1000_adapter *adapter, bool reset)
/* flush both disables and wait for them to finish */
e1e_flush();
- usleep_range(10000, 20000);
+ usleep_range(10000, 11000);
e1000_irq_disable(adapter);
napi_synchronize(&adapter->napi);
- del_timer_sync(&adapter->watchdog_timer);
del_timer_sync(&adapter->phy_info_timer);
spin_lock(&adapter->stats64_lock);
@@ -4310,7 +4312,7 @@ void e1000e_reinit_locked(struct e1000_adapter *adapter)
{
might_sleep();
while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
- usleep_range(1000, 2000);
+ usleep_range(1000, 1100);
e1000e_down(adapter, true);
e1000e_up(adapter);
clear_bit(__E1000_RESETTING, &adapter->state);
@@ -4606,6 +4608,7 @@ int e1000e_open(struct net_device *netdev)
pm_runtime_get_sync(&pdev->dev);
netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
/* allocate transmit descriptors */
err = e1000e_setup_tx_resources(adapter->tx_ring);
@@ -4666,7 +4669,6 @@ int e1000e_open(struct net_device *netdev)
e1000_irq_enable(adapter);
adapter->tx_hang_recheck = false;
- netif_start_queue(netdev);
hw->mac.get_link_status = true;
pm_runtime_put(&pdev->dev);
@@ -4707,7 +4709,7 @@ int e1000e_close(struct net_device *netdev)
int count = E1000_CHECK_RESET_COUNT;
while (test_bit(__E1000_RESETTING, &adapter->state) && count--)
- usleep_range(10000, 20000);
+ usleep_range(10000, 11000);
WARN_ON(test_bit(__E1000_RESETTING, &adapter->state));
@@ -5150,31 +5152,18 @@ static void e1000e_check_82574_phy_workaround(struct e1000_adapter *adapter)
}
}
-/**
- * e1000_watchdog - Timer Call-back
- * @data: pointer to adapter cast into an unsigned long
- **/
-static void e1000_watchdog(struct timer_list *t)
-{
- struct e1000_adapter *adapter = from_timer(adapter, t, watchdog_timer);
-
- /* Do the rest outside of interrupt context */
- schedule_work(&adapter->watchdog_task);
-
- /* TODO: make this use queue_delayed_work() */
-}
-
static void e1000_watchdog_task(struct work_struct *work)
{
struct e1000_adapter *adapter = container_of(work,
struct e1000_adapter,
- watchdog_task);
+ watchdog_task.work);
struct net_device *netdev = adapter->netdev;
struct e1000_mac_info *mac = &adapter->hw.mac;
struct e1000_phy_info *phy = &adapter->hw.phy;
struct e1000_ring *tx_ring = adapter->tx_ring;
+ u32 dmoff_exit_timeout = 100, tries = 0;
struct e1000_hw *hw = &adapter->hw;
- u32 link, tctl;
+ u32 link, tctl, pcim_state;
if (test_bit(__E1000_DOWN, &adapter->state))
return;
@@ -5199,6 +5188,21 @@ static void e1000_watchdog_task(struct work_struct *work)
/* Cancel scheduled suspend requests. */
pm_runtime_resume(netdev->dev.parent);
+ /* Checking if MAC is in DMoff state*/
+ pcim_state = er32(STATUS);
+ while (pcim_state & E1000_STATUS_PCIM_STATE) {
+ if (tries++ == dmoff_exit_timeout) {
+ e_dbg("Error in exiting dmoff\n");
+ break;
+ }
+ usleep_range(10000, 20000);
+ pcim_state = er32(STATUS);
+
+ /* Checking if MAC exited DMoff state */
+ if (!(pcim_state & E1000_STATUS_PCIM_STATE))
+ e1000_phy_hw_reset(&adapter->hw);
+ }
+
/* update snapshot of PHY registers on LSC */
e1000_phy_read_status(adapter);
mac->ops.get_link_up_info(&adapter->hw,
@@ -5288,6 +5292,7 @@ static void e1000_watchdog_task(struct work_struct *work)
if (phy->ops.cfg_on_link_up)
phy->ops.cfg_on_link_up(hw);
+ netif_wake_queue(netdev);
netif_carrier_on(netdev);
if (!test_bit(__E1000_DOWN, &adapter->state))
@@ -5301,6 +5306,7 @@ static void e1000_watchdog_task(struct work_struct *work)
/* Link status message must follow this format */
pr_info("%s NIC Link is Down\n", adapter->netdev->name);
netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
if (!test_bit(__E1000_DOWN, &adapter->state))
mod_timer(&adapter->phy_info_timer,
round_jiffies(jiffies + 2 * HZ));
@@ -5308,13 +5314,8 @@ static void e1000_watchdog_task(struct work_struct *work)
/* 8000ES2LAN requires a Rx packet buffer work-around
* on link down event; reset the controller to flush
* the Rx packet buffer.
- *
- * If the link is lost the controller stops DMA, but
- * if there is queued Tx work it cannot be done. So
- * reset the controller to flush the Tx packet buffers.
*/
- if ((adapter->flags & FLAG_RX_NEEDS_RESTART) ||
- e1000_desc_unused(tx_ring) + 1 < tx_ring->count)
+ if (adapter->flags & FLAG_RX_NEEDS_RESTART)
adapter->flags |= FLAG_RESTART_NOW;
else
pm_schedule_suspend(netdev->dev.parent,
@@ -5337,6 +5338,14 @@ link_up:
adapter->gotc_old = adapter->stats.gotc;
spin_unlock(&adapter->stats64_lock);
+ /* If the link is lost the controller stops DMA, but
+ * if there is queued Tx work it cannot be done. So
+ * reset the controller to flush the Tx packet buffers.
+ */
+ if (!netif_carrier_ok(netdev) &&
+ (e1000_desc_unused(tx_ring) + 1 < tx_ring->count))
+ adapter->flags |= FLAG_RESTART_NOW;
+
/* If reset is necessary, do it outside of interrupt context. */
if (adapter->flags & FLAG_RESTART_NOW) {
schedule_work(&adapter->reset_task);
@@ -5395,8 +5404,9 @@ link_up:
/* Reset the timer */
if (!test_bit(__E1000_DOWN, &adapter->state))
- mod_timer(&adapter->watchdog_timer,
- round_jiffies(jiffies + 2 * HZ));
+ queue_delayed_work(adapter->e1000_workqueue,
+ &adapter->watchdog_task,
+ round_jiffies(2 * HZ));
}
#define E1000_TX_FLAGS_CSUM 0x00000001
@@ -6016,7 +6026,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
}
while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
- usleep_range(1000, 2000);
+ usleep_range(1000, 1100);
/* e1000e_down -> e1000e_reset dependent on max_frame_size & mtu */
adapter->max_frame_size = max_frame;
e_info("changing MTU from %d to %d\n", netdev->mtu, new_mtu);
@@ -6296,7 +6306,7 @@ static int e1000e_pm_freeze(struct device *dev)
int count = E1000_CHECK_RESET_COUNT;
while (test_bit(__E1000_RESETTING, &adapter->state) && count--)
- usleep_range(10000, 20000);
+ usleep_range(10000, 11000);
WARN_ON(test_bit(__E1000_RESETTING, &adapter->state));
@@ -6711,7 +6721,7 @@ static int e1000e_pm_runtime_suspend(struct device *dev)
int count = E1000_CHECK_RESET_COUNT;
while (test_bit(__E1000_RESETTING, &adapter->state) && count--)
- usleep_range(10000, 20000);
+ usleep_range(10000, 11000);
WARN_ON(test_bit(__E1000_RESETTING, &adapter->state));
@@ -7251,11 +7261,21 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_eeprom;
}
- timer_setup(&adapter->watchdog_timer, e1000_watchdog, 0);
+ adapter->e1000_workqueue = alloc_workqueue("%s", WQ_MEM_RECLAIM, 0,
+ e1000e_driver_name);
+
+ if (!adapter->e1000_workqueue) {
+ err = -ENOMEM;
+ goto err_workqueue;
+ }
+
+ INIT_DELAYED_WORK(&adapter->watchdog_task, e1000_watchdog_task);
+ queue_delayed_work(adapter->e1000_workqueue, &adapter->watchdog_task,
+ 0);
+
timer_setup(&adapter->phy_info_timer, e1000_update_phy_info, 0);
INIT_WORK(&adapter->reset_task, e1000_reset_task);
- INIT_WORK(&adapter->watchdog_task, e1000_watchdog_task);
INIT_WORK(&adapter->downshift_task, e1000e_downshift_workaround);
INIT_WORK(&adapter->update_phy_task, e1000e_update_phy_task);
INIT_WORK(&adapter->print_hang_task, e1000_print_hw_hang);
@@ -7349,6 +7369,9 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return 0;
err_register:
+ flush_workqueue(adapter->e1000_workqueue);
+ destroy_workqueue(adapter->e1000_workqueue);
+err_workqueue:
if (!(adapter->flags & FLAG_HAS_AMT))
e1000e_release_hw_control(adapter);
err_eeprom:
@@ -7395,15 +7418,17 @@ static void e1000_remove(struct pci_dev *pdev)
*/
if (!down)
set_bit(__E1000_DOWN, &adapter->state);
- del_timer_sync(&adapter->watchdog_timer);
del_timer_sync(&adapter->phy_info_timer);
cancel_work_sync(&adapter->reset_task);
- cancel_work_sync(&adapter->watchdog_task);
cancel_work_sync(&adapter->downshift_task);
cancel_work_sync(&adapter->update_phy_task);
cancel_work_sync(&adapter->print_hang_task);
+ cancel_delayed_work(&adapter->watchdog_task);
+ flush_workqueue(adapter->e1000_workqueue);
+ destroy_workqueue(adapter->e1000_workqueue);
+
if (adapter->flags & FLAG_HAS_HW_TIMESTAMP) {
cancel_work_sync(&adapter->tx_hwtstamp_work);
if (adapter->tx_hwtstamp_skb) {
diff --git a/drivers/net/ethernet/intel/e1000e/nvm.c b/drivers/net/ethernet/intel/e1000e/nvm.c
index 937f9af22d26..e609f4df86f4 100644
--- a/drivers/net/ethernet/intel/e1000e/nvm.c
+++ b/drivers/net/ethernet/intel/e1000e/nvm.c
@@ -392,7 +392,7 @@ s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
break;
}
}
- usleep_range(10000, 20000);
+ usleep_range(10000, 11000);
nvm->ops.release(hw);
}
diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h
index 7ce42040b851..84bd06901014 100644
--- a/drivers/net/ethernet/intel/i40e/i40e.h
+++ b/drivers/net/ethernet/intel/i40e/i40e.h
@@ -27,6 +27,7 @@
#include <net/ip6_checksum.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
+#include <linux/if_macvlan.h>
#include <linux/if_bridge.h>
#include <linux/clocksource.h>
#include <linux/net_tstamp.h>
@@ -295,8 +296,6 @@ struct i40e_cloud_filter {
u8 tunnel_type;
};
-#define I40E_ETH_P_LLDP 0x88cc
-
#define I40E_DCB_PRIO_TYPE_STRICT 0
#define I40E_DCB_PRIO_TYPE_ETS 1
#define I40E_DCB_STRICT_PRIO_CREDITS 127
@@ -414,6 +413,11 @@ struct i40e_flex_pit {
u8 pit_index;
};
+struct i40e_fwd_adapter {
+ struct net_device *netdev;
+ int bit_no;
+};
+
struct i40e_channel {
struct list_head list;
bool initialized;
@@ -428,11 +432,25 @@ struct i40e_channel {
struct i40e_aqc_vsi_properties_data info;
u64 max_tx_rate;
+ struct i40e_fwd_adapter *fwd;
/* track this channel belongs to which VSI */
struct i40e_vsi *parent_vsi;
};
+static inline bool i40e_is_channel_macvlan(struct i40e_channel *ch)
+{
+ return !!ch->fwd;
+}
+
+static inline u8 *i40e_channel_mac(struct i40e_channel *ch)
+{
+ if (i40e_is_channel_macvlan(ch))
+ return ch->fwd->netdev->dev_addr;
+ else
+ return NULL;
+}
+
/* struct that defines the Ethernet device */
struct i40e_pf {
struct pci_dev *pdev;
@@ -777,7 +795,8 @@ struct i40e_vsi {
u16 alloc_queue_pairs; /* Allocated Tx/Rx queues */
u16 req_queue_pairs; /* User requested queue pairs */
u16 num_queue_pairs; /* Used tx and rx pairs */
- u16 num_desc;
+ u16 num_tx_desc;
+ u16 num_rx_desc;
enum i40e_vsi_type type; /* VSI type, e.g., LAN, FCoE, etc */
s16 vf_id; /* Virtual function ID for SRIOV VSIs */
@@ -814,6 +833,13 @@ struct i40e_vsi {
struct list_head ch_list;
u16 tc_seid_map[I40E_MAX_TRAFFIC_CLASS];
+ /* macvlan fields */
+#define I40E_MAX_MACVLANS 128 /* Max HW vectors - 1 on FVL */
+#define I40E_MIN_MACVLAN_VECTORS 2 /* Min vectors to enable macvlans */
+ DECLARE_BITMAP(fwd_bitmask, I40E_MAX_MACVLANS);
+ struct list_head macvlan_list;
+ int macvlan_cnt;
+
void *priv; /* client driver data reference. */
/* VSI specific handlers */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c
index 243dcd4bec19..814acbe79ffd 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c
@@ -675,7 +675,7 @@ static u16 i40e_clean_asq(struct i40e_hw *hw)
desc = I40E_ADMINQ_DESC(*asq, ntc);
details = I40E_ADMINQ_DETAILS(*asq, ntc);
while (rd32(hw, hw->aq.asq.head) != ntc) {
- i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE,
+ i40e_debug(hw, I40E_DEBUG_AQ_COMMAND,
"ntc %d head %d.\n", ntc, rd32(hw, hw->aq.asq.head));
if (details->callback) {
@@ -835,7 +835,7 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw,
}
/* bump the tail */
- i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: desc and buffer:\n");
+ i40e_debug(hw, I40E_DEBUG_AQ_COMMAND, "AQTX: desc and buffer:\n");
i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc_on_ring,
buff, buff_size);
(hw->aq.asq.next_to_use)++;
@@ -886,7 +886,7 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw,
hw->aq.asq_last_status = (enum i40e_admin_queue_err)retval;
}
- i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE,
+ i40e_debug(hw, I40E_DEBUG_AQ_COMMAND,
"AQTX: desc and buffer writeback:\n");
i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, buff, buff_size);
@@ -995,7 +995,7 @@ i40e_status i40e_clean_arq_element(struct i40e_hw *hw,
memcpy(e->msg_buf, hw->aq.arq.r.arq_bi[desc_idx].va,
e->msg_len);
- i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQRX: desc and buffer:\n");
+ i40e_debug(hw, I40E_DEBUG_AQ_COMMAND, "AQRX: desc and buffer:\n");
i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, e->msg_buf,
hw->aq.arq_buf_size);
diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c
index ecb1adaa54ec..906cf68d3453 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_common.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_common.c
@@ -281,47 +281,49 @@ void i40e_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, void *desc,
void *buffer, u16 buf_len)
{
struct i40e_aq_desc *aq_desc = (struct i40e_aq_desc *)desc;
+ u32 effective_mask = hw->debug_mask & mask;
+ char prefix[27];
u16 len;
u8 *buf = (u8 *)buffer;
- if ((!(mask & hw->debug_mask)) || (desc == NULL))
+ if (!effective_mask || !desc)
return;
len = le16_to_cpu(aq_desc->datalen);
- i40e_debug(hw, mask,
+ i40e_debug(hw, mask & I40E_DEBUG_AQ_DESCRIPTOR,
"AQ CMD: opcode 0x%04X, flags 0x%04X, datalen 0x%04X, retval 0x%04X\n",
le16_to_cpu(aq_desc->opcode),
le16_to_cpu(aq_desc->flags),
le16_to_cpu(aq_desc->datalen),
le16_to_cpu(aq_desc->retval));
- i40e_debug(hw, mask, "\tcookie (h,l) 0x%08X 0x%08X\n",
+ i40e_debug(hw, mask & I40E_DEBUG_AQ_DESCRIPTOR,
+ "\tcookie (h,l) 0x%08X 0x%08X\n",
le32_to_cpu(aq_desc->cookie_high),
le32_to_cpu(aq_desc->cookie_low));
- i40e_debug(hw, mask, "\tparam (0,1) 0x%08X 0x%08X\n",
+ i40e_debug(hw, mask & I40E_DEBUG_AQ_DESCRIPTOR,
+ "\tparam (0,1) 0x%08X 0x%08X\n",
le32_to_cpu(aq_desc->params.internal.param0),
le32_to_cpu(aq_desc->params.internal.param1));
- i40e_debug(hw, mask, "\taddr (h,l) 0x%08X 0x%08X\n",
+ i40e_debug(hw, mask & I40E_DEBUG_AQ_DESCRIPTOR,
+ "\taddr (h,l) 0x%08X 0x%08X\n",
le32_to_cpu(aq_desc->params.external.addr_high),
le32_to_cpu(aq_desc->params.external.addr_low));
- if ((buffer != NULL) && (aq_desc->datalen != 0)) {
+ if (buffer && buf_len != 0 && len != 0 &&
+ (effective_mask & I40E_DEBUG_AQ_DESC_BUFFER)) {
i40e_debug(hw, mask, "AQ CMD Buffer:\n");
if (buf_len < len)
len = buf_len;
- /* write the full 16-byte chunks */
- if (hw->debug_mask & mask) {
- char prefix[27];
-
- snprintf(prefix, sizeof(prefix),
- "i40e %02x:%02x.%x: \t0x",
- hw->bus.bus_id,
- hw->bus.device,
- hw->bus.func);
-
- print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_OFFSET,
- 16, 1, buf, len, false);
- }
+
+ snprintf(prefix, sizeof(prefix),
+ "i40e %02x:%02x.%x: \t0x",
+ hw->bus.bus_id,
+ hw->bus.device,
+ hw->bus.func);
+
+ print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_OFFSET,
+ 16, 1, buf, len, false);
}
}
@@ -1859,8 +1861,7 @@ i40e_status i40e_aq_get_link_info(struct i40e_hw *hw,
hw->aq.fw_min_ver < 40)) && hw_link_info->phy_type == 0xE)
hw_link_info->phy_type = I40E_PHY_TYPE_10GBASE_SFPP_CU;
- if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
- hw->aq.api_min_ver >= 7) {
+ if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) {
__le32 tmp;
memcpy(&tmp, resp->link_type, sizeof(tmp));
diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
index 7ea4f09229e4..55d20acfcf70 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
@@ -333,8 +333,9 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
" seid = %d, id = %d, uplink_seid = %d\n",
vsi->seid, vsi->id, vsi->uplink_seid);
dev_info(&pf->pdev->dev,
- " base_queue = %d, num_queue_pairs = %d, num_desc = %d\n",
- vsi->base_queue, vsi->num_queue_pairs, vsi->num_desc);
+ " base_queue = %d, num_queue_pairs = %d, num_tx_desc = %d, num_rx_desc = %d\n",
+ vsi->base_queue, vsi->num_queue_pairs, vsi->num_tx_desc,
+ vsi->num_rx_desc);
dev_info(&pf->pdev->dev, " type = %i\n", vsi->type);
if (vsi->type == I40E_VSI_SRIOV)
dev_info(&pf->pdev->dev, " VF ID = %i\n", vsi->vf_id);
@@ -1330,7 +1331,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
}
ret = i40e_aq_add_rem_control_packet_filter(&pf->hw,
pf->hw.mac.addr,
- I40E_ETH_P_LLDP, 0,
+ ETH_P_LLDP, 0,
pf->vsi[pf->lan_vsi]->seid,
0, true, NULL, NULL);
if (ret) {
@@ -1348,7 +1349,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
ret = i40e_aq_add_rem_control_packet_filter(&pf->hw,
pf->hw.mac.addr,
- I40E_ETH_P_LLDP, 0,
+ ETH_P_LLDP, 0,
pf->vsi[pf->lan_vsi]->seid,
0, false, NULL, NULL);
if (ret) {
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
index 7545b21bee3c..527eb52c5401 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
@@ -1982,6 +1982,8 @@ static int i40e_set_ringparam(struct net_device *netdev,
if (i40e_enabled_xdp_vsi(vsi))
vsi->xdp_rings[i]->count = new_tx_count;
}
+ vsi->num_tx_desc = new_tx_count;
+ vsi->num_rx_desc = new_rx_count;
goto done;
}
@@ -2118,6 +2120,8 @@ rx_unwind:
rx_rings = NULL;
}
+ vsi->num_tx_desc = new_tx_count;
+ vsi->num_rx_desc = new_rx_count;
i40e_up(vsi);
free_tx:
@@ -4852,9 +4856,12 @@ static u32 i40e_get_priv_flags(struct net_device *dev)
static int i40e_set_priv_flags(struct net_device *dev, u32 flags)
{
struct i40e_netdev_priv *np = netdev_priv(dev);
+ u64 orig_flags, new_flags, changed_flags;
+ enum i40e_admin_queue_err adq_err;
struct i40e_vsi *vsi = np->vsi;
struct i40e_pf *pf = vsi->back;
- u64 orig_flags, new_flags, changed_flags;
+ bool is_reset_needed;
+ i40e_status status;
u32 i, j;
orig_flags = READ_ONCE(pf->flags);
@@ -4898,6 +4905,10 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags)
flags_complete:
changed_flags = orig_flags ^ new_flags;
+ is_reset_needed = !!(changed_flags & (I40E_FLAG_VEB_STATS_ENABLED |
+ I40E_FLAG_LEGACY_RX | I40E_FLAG_SOURCE_PRUNING_DISABLED |
+ I40E_FLAG_DISABLE_FW_LLDP));
+
/* Before we finalize any flag changes, we need to perform some
* checks to ensure that the changes are supported and safe.
*/
@@ -4932,13 +4943,6 @@ flags_complete:
return -EOPNOTSUPP;
}
- /* Now that we've checked to ensure that the new flags are valid, load
- * them into place. Since we only modify flags either (a) during
- * initialization or (b) while holding the RTNL lock, we don't need
- * anything fancy here.
- */
- pf->flags = new_flags;
-
/* Process any additional changes needed as a result of flag changes.
* The changed_flags value reflects the list of bits that were
* changed in the code above.
@@ -4946,7 +4950,7 @@ flags_complete:
/* Flush current ATR settings if ATR was disabled */
if ((changed_flags & I40E_FLAG_FD_ATR_ENABLED) &&
- !(pf->flags & I40E_FLAG_FD_ATR_ENABLED)) {
+ !(new_flags & I40E_FLAG_FD_ATR_ENABLED)) {
set_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state);
set_bit(__I40E_FD_FLUSH_REQUESTED, pf->state);
}
@@ -4955,7 +4959,7 @@ flags_complete:
u16 sw_flags = 0, valid_flags = 0;
int ret;
- if (!(pf->flags & I40E_FLAG_TRUE_PROMISC_SUPPORT))
+ if (!(new_flags & I40E_FLAG_TRUE_PROMISC_SUPPORT))
sw_flags = I40E_AQ_SET_SWITCH_CFG_PROMISC;
valid_flags = I40E_AQ_SET_SWITCH_CFG_PROMISC;
ret = i40e_aq_set_switch_config(&pf->hw, sw_flags, valid_flags,
@@ -4974,13 +4978,13 @@ flags_complete:
(changed_flags & I40E_FLAG_BASE_R_FEC)) {
u8 fec_cfg = 0;
- if (pf->flags & I40E_FLAG_RS_FEC &&
- pf->flags & I40E_FLAG_BASE_R_FEC) {
+ if (new_flags & I40E_FLAG_RS_FEC &&
+ new_flags & I40E_FLAG_BASE_R_FEC) {
fec_cfg = I40E_AQ_SET_FEC_AUTO;
- } else if (pf->flags & I40E_FLAG_RS_FEC) {
+ } else if (new_flags & I40E_FLAG_RS_FEC) {
fec_cfg = (I40E_AQ_SET_FEC_REQUEST_RS |
I40E_AQ_SET_FEC_ABILITY_RS);
- } else if (pf->flags & I40E_FLAG_BASE_R_FEC) {
+ } else if (new_flags & I40E_FLAG_BASE_R_FEC) {
fec_cfg = (I40E_AQ_SET_FEC_REQUEST_KR |
I40E_AQ_SET_FEC_ABILITY_KR);
}
@@ -4988,14 +4992,14 @@ flags_complete:
dev_warn(&pf->pdev->dev, "Cannot change FEC config\n");
}
- if ((changed_flags & pf->flags &
+ if ((changed_flags & new_flags &
I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED) &&
- (pf->flags & I40E_FLAG_MFP_ENABLED))
+ (new_flags & I40E_FLAG_MFP_ENABLED))
dev_warn(&pf->pdev->dev,
"Turning on link-down-on-close flag may affect other partitions\n");
if (changed_flags & I40E_FLAG_DISABLE_FW_LLDP) {
- if (pf->flags & I40E_FLAG_DISABLE_FW_LLDP) {
+ if (new_flags & I40E_FLAG_DISABLE_FW_LLDP) {
struct i40e_dcbx_config *dcbcfg;
i40e_aq_stop_lldp(&pf->hw, true, false, NULL);
@@ -5013,17 +5017,43 @@ flags_complete:
dcbcfg->pfc.willing = 1;
dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;
} else {
- i40e_aq_start_lldp(&pf->hw, false, NULL);
+ status = i40e_aq_start_lldp(&pf->hw, false, NULL);
+ if (status) {
+ adq_err = pf->hw.aq.asq_last_status;
+ switch (adq_err) {
+ case I40E_AQ_RC_EEXIST:
+ dev_warn(&pf->pdev->dev,
+ "FW LLDP agent is already running\n");
+ is_reset_needed = false;
+ break;
+ case I40E_AQ_RC_EPERM:
+ dev_warn(&pf->pdev->dev,
+ "Device configuration forbids SW from starting the LLDP agent.\n");
+ return -EINVAL;
+ default:
+ dev_warn(&pf->pdev->dev,
+ "Starting FW LLDP agent failed: error: %s, %s\n",
+ i40e_stat_str(&pf->hw,
+ status),
+ i40e_aq_str(&pf->hw,
+ adq_err));
+ return -EINVAL;
+ }
+ }
}
}
+ /* Now that we've checked to ensure that the new flags are valid, load
+ * them into place. Since we only modify flags either (a) during
+ * initialization or (b) while holding the RTNL lock, we don't need
+ * anything fancy here.
+ */
+ pf->flags = new_flags;
+
/* Issue reset to cause things to take effect, as additional bits
* are added we will need to create a mask of bits requiring reset
*/
- if (changed_flags & (I40E_FLAG_VEB_STATS_ENABLED |
- I40E_FLAG_LEGACY_RX |
- I40E_FLAG_SOURCE_PRUNING_DISABLED |
- I40E_FLAG_DISABLE_FW_LLDP))
+ if (is_reset_needed)
i40e_do_reset(pf, BIT(__I40E_PF_RESET_REQUESTED), true);
return 0;
@@ -5181,6 +5211,16 @@ static int i40e_get_module_eeprom(struct net_device *netdev,
return 0;
}
+static int i40e_get_eee(struct net_device *netdev, struct ethtool_eee *edata)
+{
+ return -EOPNOTSUPP;
+}
+
+static int i40e_set_eee(struct net_device *netdev, struct ethtool_eee *edata)
+{
+ return -EOPNOTSUPP;
+}
+
static const struct ethtool_ops i40e_ethtool_recovery_mode_ops = {
.set_eeprom = i40e_set_eeprom,
.get_eeprom_len = i40e_get_eeprom_len,
@@ -5208,6 +5248,8 @@ static const struct ethtool_ops i40e_ethtool_ops = {
.set_rxnfc = i40e_set_rxnfc,
.self_test = i40e_diag_test,
.get_strings = i40e_get_strings,
+ .get_eee = i40e_get_eee,
+ .set_eee = i40e_set_eee,
.set_phys_id = i40e_set_phys_id,
.get_sset_count = i40e_get_sset_count,
.get_ethtool_stats = i40e_get_ethtool_stats,
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index 320562b39686..9ebbe3da61bb 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -32,7 +32,7 @@ static const char i40e_driver_string[] =
__stringify(DRV_VERSION_MINOR) "." \
__stringify(DRV_VERSION_BUILD) DRV_KERN
const char i40e_driver_version_str[] = DRV_VERSION;
-static const char i40e_copyright[] = "Copyright (c) 2013 - 2014 Intel Corporation.";
+static const char i40e_copyright[] = "Copyright (c) 2013 - 2019 Intel Corporation.";
/* a bit of forward declarations */
static void i40e_vsi_reinit_locked(struct i40e_vsi *vsi);
@@ -636,9 +636,6 @@ void i40e_update_eth_stats(struct i40e_vsi *vsi)
i40e_stat_update32(hw, I40E_GLV_RUPP(stat_idx),
vsi->stat_offsets_loaded,
&oes->rx_unknown_protocol, &es->rx_unknown_protocol);
- i40e_stat_update32(hw, I40E_GLV_TEPC(stat_idx),
- vsi->stat_offsets_loaded,
- &oes->tx_errors, &es->tx_errors);
i40e_stat_update48(hw, I40E_GLV_GORCH(stat_idx),
I40E_GLV_GORCL(stat_idx),
@@ -5864,8 +5861,10 @@ static int i40e_add_channel(struct i40e_pf *pf, u16 uplink_seid,
return -ENOENT;
}
- /* Success, update channel */
- ch->enabled_tc = enabled_tc;
+ /* Success, update channel, set enabled_tc only if the channel
+ * is not a macvlan
+ */
+ ch->enabled_tc = !i40e_is_channel_macvlan(ch) && enabled_tc;
ch->seid = ctxt.seid;
ch->vsi_number = ctxt.vsi_number;
ch->stat_counter_idx = cpu_to_le16(ctxt.info.stat_counter_idx);
@@ -6413,6 +6412,50 @@ static int i40e_resume_port_tx(struct i40e_pf *pf)
}
/**
+ * i40e_update_dcb_config
+ * @hw: pointer to the HW struct
+ * @enable_mib_change: enable MIB change event
+ *
+ * Update DCB configuration from the firmware
+ **/
+static enum i40e_status_code
+i40e_update_dcb_config(struct i40e_hw *hw, bool enable_mib_change)
+{
+ struct i40e_lldp_variables lldp_cfg;
+ i40e_status ret;
+
+ if (!hw->func_caps.dcb)
+ return I40E_NOT_SUPPORTED;
+
+ /* Read LLDP NVM area */
+ ret = i40e_read_lldp_cfg(hw, &lldp_cfg);
+ if (ret)
+ return I40E_ERR_NOT_READY;
+
+ /* Get DCBX status */
+ ret = i40e_get_dcbx_status(hw, &hw->dcbx_status);
+ if (ret)
+ return ret;
+
+ /* Check the DCBX Status */
+ if (hw->dcbx_status == I40E_DCBX_STATUS_DONE ||
+ hw->dcbx_status == I40E_DCBX_STATUS_IN_PROGRESS) {
+ /* Get current DCBX configuration */
+ ret = i40e_get_dcb_config(hw);
+ if (ret)
+ return ret;
+ } else if (hw->dcbx_status == I40E_DCBX_STATUS_DISABLED) {
+ return I40E_ERR_NOT_READY;
+ }
+
+ /* Configure the LLDP MIB change event */
+ if (enable_mib_change)
+ ret = i40e_aq_cfg_lldp_mib_change_event(hw, true, NULL);
+
+ return ret;
+}
+
+/**
* i40e_init_pf_dcb - Initialize DCB configuration
* @pf: PF being configured
*
@@ -6428,11 +6471,13 @@ static int i40e_init_pf_dcb(struct i40e_pf *pf)
* Also do not enable DCBx if FW LLDP agent is disabled
*/
if ((pf->hw_features & I40E_HW_NO_DCB_SUPPORT) ||
- (pf->flags & I40E_FLAG_DISABLE_FW_LLDP))
+ (pf->flags & I40E_FLAG_DISABLE_FW_LLDP)) {
+ dev_info(&pf->pdev->dev, "DCB is not supported or FW LLDP is disabled\n");
+ err = I40E_NOT_SUPPORTED;
goto out;
+ }
- /* Get the initial DCB configuration */
- err = i40e_init_dcb(hw, true);
+ err = i40e_update_dcb_config(hw, true);
if (!err) {
/* Device/Function is not DCBX capable */
if ((!hw->func_caps.dcb) ||
@@ -6869,6 +6914,489 @@ static void i40e_vsi_set_default_tc_config(struct i40e_vsi *vsi)
}
/**
+ * i40e_del_macvlan_filter
+ * @hw: pointer to the HW structure
+ * @seid: seid of the channel VSI
+ * @macaddr: the mac address to apply as a filter
+ * @aq_err: store the admin Q error
+ *
+ * This function deletes a mac filter on the channel VSI which serves as the
+ * macvlan. Returns 0 on success.
+ **/
+static i40e_status i40e_del_macvlan_filter(struct i40e_hw *hw, u16 seid,
+ const u8 *macaddr, int *aq_err)
+{
+ struct i40e_aqc_remove_macvlan_element_data element;
+ i40e_status status;
+
+ memset(&element, 0, sizeof(element));
+ ether_addr_copy(element.mac_addr, macaddr);
+ element.vlan_tag = 0;
+ element.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH;
+ status = i40e_aq_remove_macvlan(hw, seid, &element, 1, NULL);
+ *aq_err = hw->aq.asq_last_status;
+
+ return status;
+}
+
+/**
+ * i40e_add_macvlan_filter
+ * @hw: pointer to the HW structure
+ * @seid: seid of the channel VSI
+ * @macaddr: the mac address to apply as a filter
+ * @aq_err: store the admin Q error
+ *
+ * This function adds a mac filter on the channel VSI which serves as the
+ * macvlan. Returns 0 on success.
+ **/
+static i40e_status i40e_add_macvlan_filter(struct i40e_hw *hw, u16 seid,
+ const u8 *macaddr, int *aq_err)
+{
+ struct i40e_aqc_add_macvlan_element_data element;
+ i40e_status status;
+ u16 cmd_flags = 0;
+
+ ether_addr_copy(element.mac_addr, macaddr);
+ element.vlan_tag = 0;
+ element.queue_number = 0;
+ element.match_method = I40E_AQC_MM_ERR_NO_RES;
+ cmd_flags |= I40E_AQC_MACVLAN_ADD_PERFECT_MATCH;
+ element.flags = cpu_to_le16(cmd_flags);
+ status = i40e_aq_add_macvlan(hw, seid, &element, 1, NULL);
+ *aq_err = hw->aq.asq_last_status;
+
+ return status;
+}
+
+/**
+ * i40e_reset_ch_rings - Reset the queue contexts in a channel
+ * @vsi: the VSI we want to access
+ * @ch: the channel we want to access
+ */
+static void i40e_reset_ch_rings(struct i40e_vsi *vsi, struct i40e_channel *ch)
+{
+ struct i40e_ring *tx_ring, *rx_ring;
+ u16 pf_q;
+ int i;
+
+ for (i = 0; i < ch->num_queue_pairs; i++) {
+ pf_q = ch->base_queue + i;
+ tx_ring = vsi->tx_rings[pf_q];
+ tx_ring->ch = NULL;
+ rx_ring = vsi->rx_rings[pf_q];
+ rx_ring->ch = NULL;
+ }
+}
+
+/**
+ * i40e_free_macvlan_channels
+ * @vsi: the VSI we want to access
+ *
+ * This function frees the Qs of the channel VSI from
+ * the stack and also deletes the channel VSIs which
+ * serve as macvlans.
+ */
+static void i40e_free_macvlan_channels(struct i40e_vsi *vsi)
+{
+ struct i40e_channel *ch, *ch_tmp;
+ int ret;
+
+ if (list_empty(&vsi->macvlan_list))
+ return;
+
+ list_for_each_entry_safe(ch, ch_tmp, &vsi->macvlan_list, list) {
+ struct i40e_vsi *parent_vsi;
+
+ if (i40e_is_channel_macvlan(ch)) {
+ i40e_reset_ch_rings(vsi, ch);
+ clear_bit(ch->fwd->bit_no, vsi->fwd_bitmask);
+ netdev_unbind_sb_channel(vsi->netdev, ch->fwd->netdev);
+ netdev_set_sb_channel(ch->fwd->netdev, 0);
+ kfree(ch->fwd);
+ ch->fwd = NULL;
+ }
+
+ list_del(&ch->list);
+ parent_vsi = ch->parent_vsi;
+ if (!parent_vsi || !ch->initialized) {
+ kfree(ch);
+ continue;
+ }
+
+ /* remove the VSI */
+ ret = i40e_aq_delete_element(&vsi->back->hw, ch->seid,
+ NULL);
+ if (ret)
+ dev_err(&vsi->back->pdev->dev,
+ "unable to remove channel (%d) for parent VSI(%d)\n",
+ ch->seid, parent_vsi->seid);
+ kfree(ch);
+ }
+ vsi->macvlan_cnt = 0;
+}
+
+/**
+ * i40e_fwd_ring_up - bring the macvlan device up
+ * @vsi: the VSI we want to access
+ * @vdev: macvlan netdevice
+ * @fwd: the private fwd structure
+ */
+static int i40e_fwd_ring_up(struct i40e_vsi *vsi, struct net_device *vdev,
+ struct i40e_fwd_adapter *fwd)
+{
+ int ret = 0, num_tc = 1, i, aq_err;
+ struct i40e_channel *ch, *ch_tmp;
+ struct i40e_pf *pf = vsi->back;
+ struct i40e_hw *hw = &pf->hw;
+
+ if (list_empty(&vsi->macvlan_list))
+ return -EINVAL;
+
+ /* Go through the list and find an available channel */
+ list_for_each_entry_safe(ch, ch_tmp, &vsi->macvlan_list, list) {
+ if (!i40e_is_channel_macvlan(ch)) {
+ ch->fwd = fwd;
+ /* record configuration for macvlan interface in vdev */
+ for (i = 0; i < num_tc; i++)
+ netdev_bind_sb_channel_queue(vsi->netdev, vdev,
+ i,
+ ch->num_queue_pairs,
+ ch->base_queue);
+ for (i = 0; i < ch->num_queue_pairs; i++) {
+ struct i40e_ring *tx_ring, *rx_ring;
+ u16 pf_q;
+
+ pf_q = ch->base_queue + i;
+
+ /* Get to TX ring ptr */
+ tx_ring = vsi->tx_rings[pf_q];
+ tx_ring->ch = ch;
+
+ /* Get the RX ring ptr */
+ rx_ring = vsi->rx_rings[pf_q];
+ rx_ring->ch = ch;
+ }
+ break;
+ }
+ }
+
+ /* Guarantee all rings are updated before we update the
+ * MAC address filter.
+ */
+ wmb();
+
+ /* Add a mac filter */
+ ret = i40e_add_macvlan_filter(hw, ch->seid, vdev->dev_addr, &aq_err);
+ if (ret) {
+ /* if we cannot add the MAC rule then disable the offload */
+ macvlan_release_l2fw_offload(vdev);
+ for (i = 0; i < ch->num_queue_pairs; i++) {
+ struct i40e_ring *rx_ring;
+ u16 pf_q;
+
+ pf_q = ch->base_queue + i;
+ rx_ring = vsi->rx_rings[pf_q];
+ rx_ring->netdev = NULL;
+ }
+ dev_info(&pf->pdev->dev,
+ "Error adding mac filter on macvlan err %s, aq_err %s\n",
+ i40e_stat_str(hw, ret),
+ i40e_aq_str(hw, aq_err));
+ netdev_err(vdev, "L2fwd offload disabled to L2 filter error\n");
+ }
+
+ return ret;
+}
+
+/**
+ * i40e_setup_macvlans - create the channels which will be macvlans
+ * @vsi: the VSI we want to access
+ * @macvlan_cnt: no. of macvlans to be setup
+ * @qcnt: no. of Qs per macvlan
+ * @vdev: macvlan netdevice
+ */
+static int i40e_setup_macvlans(struct i40e_vsi *vsi, u16 macvlan_cnt, u16 qcnt,
+ struct net_device *vdev)
+{
+ struct i40e_pf *pf = vsi->back;
+ struct i40e_hw *hw = &pf->hw;
+ struct i40e_vsi_context ctxt;
+ u16 sections, qmap, num_qps;
+ struct i40e_channel *ch;
+ int i, pow, ret = 0;
+ u8 offset = 0;
+
+ if (vsi->type != I40E_VSI_MAIN || !macvlan_cnt)
+ return -EINVAL;
+
+ num_qps = vsi->num_queue_pairs - (macvlan_cnt * qcnt);
+
+ /* find the next higher power-of-2 of num queue pairs */
+ pow = fls(roundup_pow_of_two(num_qps) - 1);
+
+ qmap = (offset << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) |
+ (pow << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT);
+
+ /* Setup context bits for the main VSI */
+ sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID;
+ sections |= I40E_AQ_VSI_PROP_SCHED_VALID;
+ memset(&ctxt, 0, sizeof(ctxt));
+ ctxt.seid = vsi->seid;
+ ctxt.pf_num = vsi->back->hw.pf_id;
+ ctxt.vf_num = 0;
+ ctxt.uplink_seid = vsi->uplink_seid;
+ ctxt.info = vsi->info;
+ ctxt.info.tc_mapping[0] = cpu_to_le16(qmap);
+ ctxt.info.mapping_flags |= cpu_to_le16(I40E_AQ_VSI_QUE_MAP_CONTIG);
+ ctxt.info.queue_mapping[0] = cpu_to_le16(vsi->base_queue);
+ ctxt.info.valid_sections |= cpu_to_le16(sections);
+
+ /* Reconfigure RSS for main VSI with new max queue count */
+ vsi->rss_size = max_t(u16, num_qps, qcnt);
+ ret = i40e_vsi_config_rss(vsi);
+ if (ret) {
+ dev_info(&pf->pdev->dev,
+ "Failed to reconfig RSS for num_queues (%u)\n",
+ vsi->rss_size);
+ return ret;
+ }
+ vsi->reconfig_rss = true;
+ dev_dbg(&vsi->back->pdev->dev,
+ "Reconfigured RSS with num_queues (%u)\n", vsi->rss_size);
+ vsi->next_base_queue = num_qps;
+ vsi->cnt_q_avail = vsi->num_queue_pairs - num_qps;
+
+ /* Update the VSI after updating the VSI queue-mapping
+ * information
+ */
+ ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
+ if (ret) {
+ dev_info(&pf->pdev->dev,
+ "Update vsi tc config failed, err %s aq_err %s\n",
+ i40e_stat_str(hw, ret),
+ i40e_aq_str(hw, hw->aq.asq_last_status));
+ return ret;
+ }
+ /* update the local VSI info with updated queue map */
+ i40e_vsi_update_queue_map(vsi, &ctxt);
+ vsi->info.valid_sections = 0;
+
+ /* Create channels for macvlans */
+ INIT_LIST_HEAD(&vsi->macvlan_list);
+ for (i = 0; i < macvlan_cnt; i++) {
+ ch = kzalloc(sizeof(*ch), GFP_KERNEL);
+ if (!ch) {
+ ret = -ENOMEM;
+ goto err_free;
+ }
+ INIT_LIST_HEAD(&ch->list);
+ ch->num_queue_pairs = qcnt;
+ if (!i40e_setup_channel(pf, vsi, ch)) {
+ ret = -EINVAL;
+ goto err_free;
+ }
+ ch->parent_vsi = vsi;
+ vsi->cnt_q_avail -= ch->num_queue_pairs;
+ vsi->macvlan_cnt++;
+ list_add_tail(&ch->list, &vsi->macvlan_list);
+ }
+
+ return ret;
+
+err_free:
+ dev_info(&pf->pdev->dev, "Failed to setup macvlans\n");
+ i40e_free_macvlan_channels(vsi);
+
+ return ret;
+}
+
+/**
+ * i40e_fwd_add - configure macvlans
+ * @netdev: net device to configure
+ * @vdev: macvlan netdevice
+ **/
+static void *i40e_fwd_add(struct net_device *netdev, struct net_device *vdev)
+{
+ struct i40e_netdev_priv *np = netdev_priv(netdev);
+ u16 q_per_macvlan = 0, macvlan_cnt = 0, vectors;
+ struct i40e_vsi *vsi = np->vsi;
+ struct i40e_pf *pf = vsi->back;
+ struct i40e_fwd_adapter *fwd;
+ int avail_macvlan, ret;
+
+ if ((pf->flags & I40E_FLAG_DCB_ENABLED)) {
+ netdev_info(netdev, "Macvlans are not supported when DCB is enabled\n");
+ return ERR_PTR(-EINVAL);
+ }
+ if ((pf->flags & I40E_FLAG_TC_MQPRIO)) {
+ netdev_info(netdev, "Macvlans are not supported when HW TC offload is on\n");
+ return ERR_PTR(-EINVAL);
+ }
+ if (pf->num_lan_msix < I40E_MIN_MACVLAN_VECTORS) {
+ netdev_info(netdev, "Not enough vectors available to support macvlans\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ /* The macvlan device has to be a single Q device so that the
+ * tc_to_txq field can be reused to pick the tx queue.
+ */
+ if (netif_is_multiqueue(vdev))
+ return ERR_PTR(-ERANGE);
+
+ if (!vsi->macvlan_cnt) {
+ /* reserve bit 0 for the pf device */
+ set_bit(0, vsi->fwd_bitmask);
+
+ /* Try to reserve as many queues as possible for macvlans. First
+ * reserve 3/4th of max vectors, then half, then quarter and
+ * calculate Qs per macvlan as you go
+ */
+ vectors = pf->num_lan_msix;
+ if (vectors <= I40E_MAX_MACVLANS && vectors > 64) {
+ /* allocate 4 Qs per macvlan and 32 Qs to the PF*/
+ q_per_macvlan = 4;
+ macvlan_cnt = (vectors - 32) / 4;
+ } else if (vectors <= 64 && vectors > 32) {
+ /* allocate 2 Qs per macvlan and 16 Qs to the PF*/
+ q_per_macvlan = 2;
+ macvlan_cnt = (vectors - 16) / 2;
+ } else if (vectors <= 32 && vectors > 16) {
+ /* allocate 1 Q per macvlan and 16 Qs to the PF*/
+ q_per_macvlan = 1;
+ macvlan_cnt = vectors - 16;
+ } else if (vectors <= 16 && vectors > 8) {
+ /* allocate 1 Q per macvlan and 8 Qs to the PF */
+ q_per_macvlan = 1;
+ macvlan_cnt = vectors - 8;
+ } else {
+ /* allocate 1 Q per macvlan and 1 Q to the PF */
+ q_per_macvlan = 1;
+ macvlan_cnt = vectors - 1;
+ }
+
+ if (macvlan_cnt == 0)
+ return ERR_PTR(-EBUSY);
+
+ /* Quiesce VSI queues */
+ i40e_quiesce_vsi(vsi);
+
+ /* sets up the macvlans but does not "enable" them */
+ ret = i40e_setup_macvlans(vsi, macvlan_cnt, q_per_macvlan,
+ vdev);
+ if (ret)
+ return ERR_PTR(ret);
+
+ /* Unquiesce VSI */
+ i40e_unquiesce_vsi(vsi);
+ }
+ avail_macvlan = find_first_zero_bit(vsi->fwd_bitmask,
+ vsi->macvlan_cnt);
+ if (avail_macvlan >= I40E_MAX_MACVLANS)
+ return ERR_PTR(-EBUSY);
+
+ /* create the fwd struct */
+ fwd = kzalloc(sizeof(*fwd), GFP_KERNEL);
+ if (!fwd)
+ return ERR_PTR(-ENOMEM);
+
+ set_bit(avail_macvlan, vsi->fwd_bitmask);
+ fwd->bit_no = avail_macvlan;
+ netdev_set_sb_channel(vdev, avail_macvlan);
+ fwd->netdev = vdev;
+
+ if (!netif_running(netdev))
+ return fwd;
+
+ /* Set fwd ring up */
+ ret = i40e_fwd_ring_up(vsi, vdev, fwd);
+ if (ret) {
+ /* unbind the queues and drop the subordinate channel config */
+ netdev_unbind_sb_channel(netdev, vdev);
+ netdev_set_sb_channel(vdev, 0);
+
+ kfree(fwd);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return fwd;
+}
+
+/**
+ * i40e_del_all_macvlans - Delete all the mac filters on the channels
+ * @vsi: the VSI we want to access
+ */
+static void i40e_del_all_macvlans(struct i40e_vsi *vsi)
+{
+ struct i40e_channel *ch, *ch_tmp;
+ struct i40e_pf *pf = vsi->back;
+ struct i40e_hw *hw = &pf->hw;
+ int aq_err, ret = 0;
+
+ if (list_empty(&vsi->macvlan_list))
+ return;
+
+ list_for_each_entry_safe(ch, ch_tmp, &vsi->macvlan_list, list) {
+ if (i40e_is_channel_macvlan(ch)) {
+ ret = i40e_del_macvlan_filter(hw, ch->seid,
+ i40e_channel_mac(ch),
+ &aq_err);
+ if (!ret) {
+ /* Reset queue contexts */
+ i40e_reset_ch_rings(vsi, ch);
+ clear_bit(ch->fwd->bit_no, vsi->fwd_bitmask);
+ netdev_unbind_sb_channel(vsi->netdev,
+ ch->fwd->netdev);
+ netdev_set_sb_channel(ch->fwd->netdev, 0);
+ kfree(ch->fwd);
+ ch->fwd = NULL;
+ }
+ }
+ }
+}
+
+/**
+ * i40e_fwd_del - delete macvlan interfaces
+ * @netdev: net device to configure
+ * @vdev: macvlan netdevice
+ */
+static void i40e_fwd_del(struct net_device *netdev, void *vdev)
+{
+ struct i40e_netdev_priv *np = netdev_priv(netdev);
+ struct i40e_fwd_adapter *fwd = vdev;
+ struct i40e_channel *ch, *ch_tmp;
+ struct i40e_vsi *vsi = np->vsi;
+ struct i40e_pf *pf = vsi->back;
+ struct i40e_hw *hw = &pf->hw;
+ int aq_err, ret = 0;
+
+ /* Find the channel associated with the macvlan and del mac filter */
+ list_for_each_entry_safe(ch, ch_tmp, &vsi->macvlan_list, list) {
+ if (i40e_is_channel_macvlan(ch) &&
+ ether_addr_equal(i40e_channel_mac(ch),
+ fwd->netdev->dev_addr)) {
+ ret = i40e_del_macvlan_filter(hw, ch->seid,
+ i40e_channel_mac(ch),
+ &aq_err);
+ if (!ret) {
+ /* Reset queue contexts */
+ i40e_reset_ch_rings(vsi, ch);
+ clear_bit(ch->fwd->bit_no, vsi->fwd_bitmask);
+ netdev_unbind_sb_channel(netdev, fwd->netdev);
+ netdev_set_sb_channel(fwd->netdev, 0);
+ kfree(ch->fwd);
+ ch->fwd = NULL;
+ } else {
+ dev_info(&pf->pdev->dev,
+ "Error deleting mac filter on macvlan err %s, aq_err %s\n",
+ i40e_stat_str(hw, ret),
+ i40e_aq_str(hw, aq_err));
+ }
+ break;
+ }
+ }
+}
+
+/**
* i40e_setup_tc - configure multiple traffic classes
* @netdev: net device to configure
* @type_data: tc offload data
@@ -6963,6 +7491,10 @@ config_tc:
vsi->seid);
need_reset = true;
goto exit;
+ } else {
+ dev_info(&vsi->back->pdev->dev,
+ "Setup channel (id:%u) utilizing num_queues %d\n",
+ vsi->seid, vsi->tc_config.tc_info[0].qcount);
}
if (pf->flags & I40E_FLAG_TC_MQPRIO) {
@@ -7227,15 +7759,15 @@ int i40e_add_del_cloud_filter_big_buf(struct i40e_vsi *vsi,
/**
* i40e_parse_cls_flower - Parse tc flower filters provided by kernel
* @vsi: Pointer to VSI
- * @cls_flower: Pointer to struct tc_cls_flower_offload
+ * @cls_flower: Pointer to struct flow_cls_offload
* @filter: Pointer to cloud filter structure
*
**/
static int i40e_parse_cls_flower(struct i40e_vsi *vsi,
- struct tc_cls_flower_offload *f,
+ struct flow_cls_offload *f,
struct i40e_cloud_filter *filter)
{
- struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
+ struct flow_rule *rule = flow_cls_offload_flow_rule(f);
struct flow_dissector *dissector = rule->match.dissector;
u16 n_proto_mask = 0, n_proto_key = 0, addr_type = 0;
struct i40e_pf *pf = vsi->back;
@@ -7469,11 +8001,11 @@ static int i40e_handle_tclass(struct i40e_vsi *vsi, u32 tc,
/**
* i40e_configure_clsflower - Configure tc flower filters
* @vsi: Pointer to VSI
- * @cls_flower: Pointer to struct tc_cls_flower_offload
+ * @cls_flower: Pointer to struct flow_cls_offload
*
**/
static int i40e_configure_clsflower(struct i40e_vsi *vsi,
- struct tc_cls_flower_offload *cls_flower)
+ struct flow_cls_offload *cls_flower)
{
int tc = tc_classid_to_hwtc(vsi->netdev, cls_flower->classid);
struct i40e_cloud_filter *filter = NULL;
@@ -7565,11 +8097,11 @@ static struct i40e_cloud_filter *i40e_find_cloud_filter(struct i40e_vsi *vsi,
/**
* i40e_delete_clsflower - Remove tc flower filters
* @vsi: Pointer to VSI
- * @cls_flower: Pointer to struct tc_cls_flower_offload
+ * @cls_flower: Pointer to struct flow_cls_offload
*
**/
static int i40e_delete_clsflower(struct i40e_vsi *vsi,
- struct tc_cls_flower_offload *cls_flower)
+ struct flow_cls_offload *cls_flower)
{
struct i40e_cloud_filter *filter = NULL;
struct i40e_pf *pf = vsi->back;
@@ -7612,16 +8144,16 @@ static int i40e_delete_clsflower(struct i40e_vsi *vsi,
* @type_data: offload data
**/
static int i40e_setup_tc_cls_flower(struct i40e_netdev_priv *np,
- struct tc_cls_flower_offload *cls_flower)
+ struct flow_cls_offload *cls_flower)
{
struct i40e_vsi *vsi = np->vsi;
switch (cls_flower->command) {
- case TC_CLSFLOWER_REPLACE:
+ case FLOW_CLS_REPLACE:
return i40e_configure_clsflower(vsi, cls_flower);
- case TC_CLSFLOWER_DESTROY:
+ case FLOW_CLS_DESTROY:
return i40e_delete_clsflower(vsi, cls_flower);
- case TC_CLSFLOWER_STATS:
+ case FLOW_CLS_STATS:
return -EOPNOTSUPP;
default:
return -EOPNOTSUPP;
@@ -7645,34 +8177,21 @@ static int i40e_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
}
}
-static int i40e_setup_tc_block(struct net_device *dev,
- struct tc_block_offload *f)
-{
- struct i40e_netdev_priv *np = netdev_priv(dev);
-
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
- return -EOPNOTSUPP;
-
- switch (f->command) {
- case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block, i40e_setup_tc_block_cb,
- np, np, f->extack);
- case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block, i40e_setup_tc_block_cb, np);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-}
+static LIST_HEAD(i40e_block_cb_list);
static int __i40e_setup_tc(struct net_device *netdev, enum tc_setup_type type,
void *type_data)
{
+ struct i40e_netdev_priv *np = netdev_priv(netdev);
+
switch (type) {
case TC_SETUP_QDISC_MQPRIO:
return i40e_setup_tc(netdev, type_data);
case TC_SETUP_BLOCK:
- return i40e_setup_tc_block(netdev, type_data);
+ return flow_block_cb_setup_simple(type_data,
+ &i40e_block_cb_list,
+ i40e_setup_tc_block_cb,
+ np, np, true);
default:
return -EOPNOTSUPP;
}
@@ -8570,7 +9089,7 @@ static void i40e_link_event(struct i40e_pf *pf)
/* Notify the base of the switch tree connected to
* the link. Floating VEBs are not notified.
*/
- if (pf->lan_veb != I40E_NO_VEB && pf->veb[pf->lan_veb])
+ if (pf->lan_veb < I40E_MAX_VEB && pf->veb[pf->lan_veb])
i40e_veb_link_event(pf->veb[pf->lan_veb], new_link);
else
i40e_vsi_link_event(vsi, new_link);
@@ -10031,8 +10550,12 @@ static int i40e_set_num_rings_in_vsi(struct i40e_vsi *vsi)
switch (vsi->type) {
case I40E_VSI_MAIN:
vsi->alloc_queue_pairs = pf->num_lan_qps;
- vsi->num_desc = ALIGN(I40E_DEFAULT_NUM_DESCRIPTORS,
- I40E_REQ_DESCRIPTOR_MULTIPLE);
+ if (!vsi->num_tx_desc)
+ vsi->num_tx_desc = ALIGN(I40E_DEFAULT_NUM_DESCRIPTORS,
+ I40E_REQ_DESCRIPTOR_MULTIPLE);
+ if (!vsi->num_rx_desc)
+ vsi->num_rx_desc = ALIGN(I40E_DEFAULT_NUM_DESCRIPTORS,
+ I40E_REQ_DESCRIPTOR_MULTIPLE);
if (pf->flags & I40E_FLAG_MSIX_ENABLED)
vsi->num_q_vectors = pf->num_lan_msix;
else
@@ -10042,22 +10565,32 @@ static int i40e_set_num_rings_in_vsi(struct i40e_vsi *vsi)
case I40E_VSI_FDIR:
vsi->alloc_queue_pairs = 1;
- vsi->num_desc = ALIGN(I40E_FDIR_RING_COUNT,
- I40E_REQ_DESCRIPTOR_MULTIPLE);
+ vsi->num_tx_desc = ALIGN(I40E_FDIR_RING_COUNT,
+ I40E_REQ_DESCRIPTOR_MULTIPLE);
+ vsi->num_rx_desc = ALIGN(I40E_FDIR_RING_COUNT,
+ I40E_REQ_DESCRIPTOR_MULTIPLE);
vsi->num_q_vectors = pf->num_fdsb_msix;
break;
case I40E_VSI_VMDQ2:
vsi->alloc_queue_pairs = pf->num_vmdq_qps;
- vsi->num_desc = ALIGN(I40E_DEFAULT_NUM_DESCRIPTORS,
- I40E_REQ_DESCRIPTOR_MULTIPLE);
+ if (!vsi->num_tx_desc)
+ vsi->num_tx_desc = ALIGN(I40E_DEFAULT_NUM_DESCRIPTORS,
+ I40E_REQ_DESCRIPTOR_MULTIPLE);
+ if (!vsi->num_rx_desc)
+ vsi->num_rx_desc = ALIGN(I40E_DEFAULT_NUM_DESCRIPTORS,
+ I40E_REQ_DESCRIPTOR_MULTIPLE);
vsi->num_q_vectors = pf->num_vmdq_msix;
break;
case I40E_VSI_SRIOV:
vsi->alloc_queue_pairs = pf->num_vf_qps;
- vsi->num_desc = ALIGN(I40E_DEFAULT_NUM_DESCRIPTORS,
- I40E_REQ_DESCRIPTOR_MULTIPLE);
+ if (!vsi->num_tx_desc)
+ vsi->num_tx_desc = ALIGN(I40E_DEFAULT_NUM_DESCRIPTORS,
+ I40E_REQ_DESCRIPTOR_MULTIPLE);
+ if (!vsi->num_rx_desc)
+ vsi->num_rx_desc = ALIGN(I40E_DEFAULT_NUM_DESCRIPTORS,
+ I40E_REQ_DESCRIPTOR_MULTIPLE);
break;
default:
@@ -10333,7 +10866,7 @@ static int i40e_alloc_rings(struct i40e_vsi *vsi)
ring->vsi = vsi;
ring->netdev = vsi->netdev;
ring->dev = &pf->pdev->dev;
- ring->count = vsi->num_desc;
+ ring->count = vsi->num_tx_desc;
ring->size = 0;
ring->dcb_tc = 0;
if (vsi->back->hw_features & I40E_HW_WB_ON_ITR_CAPABLE)
@@ -10350,7 +10883,7 @@ static int i40e_alloc_rings(struct i40e_vsi *vsi)
ring->vsi = vsi;
ring->netdev = NULL;
ring->dev = &pf->pdev->dev;
- ring->count = vsi->num_desc;
+ ring->count = vsi->num_tx_desc;
ring->size = 0;
ring->dcb_tc = 0;
if (vsi->back->hw_features & I40E_HW_WB_ON_ITR_CAPABLE)
@@ -10366,7 +10899,7 @@ setup_rx:
ring->vsi = vsi;
ring->netdev = vsi->netdev;
ring->dev = &pf->pdev->dev;
- ring->count = vsi->num_desc;
+ ring->count = vsi->num_rx_desc;
ring->size = 0;
ring->dcb_tc = 0;
ring->itr_setting = pf->rx_itr_default;
@@ -11604,6 +12137,9 @@ static int i40e_set_features(struct net_device *netdev,
return -EINVAL;
}
+ if (!(features & NETIF_F_HW_L2FW_DOFFLOAD) && vsi->macvlan_cnt)
+ i40e_del_all_macvlans(vsi);
+
need_reset = i40e_set_ntuple(pf, features);
if (need_reset)
@@ -12348,6 +12884,8 @@ static const struct net_device_ops i40e_netdev_ops = {
.ndo_bpf = i40e_xdp,
.ndo_xdp_xmit = i40e_xdp_xmit,
.ndo_xsk_async_xmit = i40e_xsk_async_xmit,
+ .ndo_dfwd_add_station = i40e_fwd_add,
+ .ndo_dfwd_del_station = i40e_fwd_del,
};
/**
@@ -12407,6 +12945,9 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
/* record features VLANs can make use of */
netdev->vlan_features |= hw_enc_features | NETIF_F_TSO_MANGLEID;
+ /* enable macvlan offloads */
+ netdev->hw_features |= NETIF_F_HW_L2FW_DOFFLOAD;
+
hw_features = hw_enc_features |
NETIF_F_HW_VLAN_CTAG_TX |
NETIF_F_HW_VLAN_CTAG_RX;
@@ -12519,7 +13060,7 @@ int i40e_is_vsi_uplink_mode_veb(struct i40e_vsi *vsi)
struct i40e_pf *pf = vsi->back;
/* Uplink is not a bridge so default to VEB */
- if (vsi->veb_idx == I40E_NO_VEB)
+ if (vsi->veb_idx >= I40E_MAX_VEB)
return 1;
veb = pf->veb[vsi->veb_idx];
@@ -13577,7 +14118,7 @@ static void i40e_setup_pf_switch_element(struct i40e_pf *pf,
/* Main VEB? */
if (uplink_seid != pf->mac_seid)
break;
- if (pf->lan_veb == I40E_NO_VEB) {
+ if (pf->lan_veb >= I40E_MAX_VEB) {
int v;
/* find existing or else empty VEB */
@@ -13587,13 +14128,15 @@ static void i40e_setup_pf_switch_element(struct i40e_pf *pf,
break;
}
}
- if (pf->lan_veb == I40E_NO_VEB) {
+ if (pf->lan_veb >= I40E_MAX_VEB) {
v = i40e_veb_mem_alloc(pf);
if (v < 0)
break;
pf->lan_veb = v;
}
}
+ if (pf->lan_veb >= I40E_MAX_VEB)
+ break;
pf->veb[pf->lan_veb]->seid = seid;
pf->veb[pf->lan_veb]->uplink_seid = pf->mac_seid;
@@ -13747,7 +14290,7 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit)
/* Set up the PF VSI associated with the PF's main VSI
* that is already in the HW switch
*/
- if (pf->lan_veb != I40E_NO_VEB && pf->veb[pf->lan_veb])
+ if (pf->lan_veb < I40E_MAX_VEB && pf->veb[pf->lan_veb])
uplink_seid = pf->veb[pf->lan_veb]->seid;
else
uplink_seid = pf->mac_seid;
@@ -14203,7 +14746,17 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pf->ioremap_len = min_t(int, pci_resource_len(pdev, 0),
I40E_MAX_CSR_SPACE);
-
+ /* We believe that the highest register to read is
+ * I40E_GLGEN_STAT_CLEAR, so we check if the BAR size
+ * is not less than that before mapping to prevent a
+ * kernel panic.
+ */
+ if (pf->ioremap_len < I40E_GLGEN_STAT_CLEAR) {
+ dev_err(&pdev->dev, "Cannot map registers, bar size 0x%X too small, aborting\n",
+ pf->ioremap_len);
+ err = -ENOMEM;
+ goto err_ioremap;
+ }
hw->hw_addr = ioremap(pci_resource_start(pdev, 0), pf->ioremap_len);
if (!hw->hw_addr) {
err = -EIO;
@@ -14388,6 +14941,11 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_drvdata(pdev, pf);
pci_save_state(pdev);
+ dev_info(&pdev->dev,
+ (pf->flags & I40E_FLAG_DISABLE_FW_LLDP) ?
+ "FW LLDP is disabled\n" :
+ "FW LLDP is enabled\n");
+
/* Enable FW to write default DCB config on link-up */
i40e_aq_set_dcb_parameters(hw, true, NULL);
diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
index 882627073dce..eac88bcc6c06 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
@@ -350,6 +350,10 @@ i40e_virtchnl_link_speed(enum i40e_aq_link_speed link_speed)
return VIRTCHNL_LINK_SPEED_100MB;
case I40E_LINK_SPEED_1GB:
return VIRTCHNL_LINK_SPEED_1GB;
+ case I40E_LINK_SPEED_2_5GB:
+ return VIRTCHNL_LINK_SPEED_2_5GB;
+ case I40E_LINK_SPEED_5GB:
+ return VIRTCHNL_LINK_SPEED_5GB;
case I40E_LINK_SPEED_10GB:
return VIRTCHNL_LINK_SPEED_10GB;
case I40E_LINK_SPEED_40GB:
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c
index 439c35f0c581..11394a52e21c 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c
@@ -140,8 +140,7 @@ static int i40e_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
* @ptp: The PTP clock structure
* @delta: Offset in nanoseconds to adjust the PHC time by
*
- * Adjust the frequency of the PHC by the indicated parts per billion from the
- * base frequency.
+ * Adjust the current clock time by a delta specified in nanoseconds.
**/
static int i40e_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
{
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
index 20a283702c9f..2a2fe3ec7926 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
@@ -774,7 +774,7 @@ void i40e_detect_recover_hung(struct i40e_vsi *vsi)
static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
struct i40e_ring *tx_ring, int napi_budget)
{
- u16 i = tx_ring->next_to_clean;
+ int i = tx_ring->next_to_clean;
struct i40e_tx_buffer *tx_buf;
struct i40e_tx_desc *tx_head;
struct i40e_tx_desc *tx_desc;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
index 479bc60c8f71..02b09a8ad54c 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
@@ -440,7 +440,7 @@ static int i40e_config_iwarp_qvlist(struct i40e_vf *vf,
struct virtchnl_iwarp_qv_info *qv_info;
u32 v_idx, i, reg_idx, reg;
u32 next_q_idx, next_q_type;
- u32 msix_vf, size;
+ u32 msix_vf;
int ret = 0;
msix_vf = pf->hw.func_caps.num_msix_vectors_vf;
@@ -454,11 +454,10 @@ static int i40e_config_iwarp_qvlist(struct i40e_vf *vf,
goto err_out;
}
- size = sizeof(struct virtchnl_iwarp_qvlist_info) +
- (sizeof(struct virtchnl_iwarp_qv_info) *
- (qvlist_info->num_vectors - 1));
kfree(vf->qvlist_info);
- vf->qvlist_info = kzalloc(size, GFP_KERNEL);
+ vf->qvlist_info = kzalloc(struct_size(vf->qvlist_info, qv_info,
+ qvlist_info->num_vectors - 1),
+ GFP_KERNEL);
if (!vf->qvlist_info) {
ret = -ENOMEM;
goto err_out;
@@ -470,14 +469,15 @@ static int i40e_config_iwarp_qvlist(struct i40e_vf *vf,
qv_info = &qvlist_info->qv_info[i];
if (!qv_info)
continue;
- v_idx = qv_info->v_idx;
/* Validate vector id belongs to this vf */
- if (!i40e_vc_isvalid_vector_id(vf, v_idx)) {
+ if (!i40e_vc_isvalid_vector_id(vf, qv_info->v_idx)) {
ret = -EINVAL;
goto err_free;
}
+ v_idx = qv_info->v_idx;
+
vf->qvlist_info->qv_info[i] = *qv_info;
reg_idx = ((msix_vf - 1) * vf->vf_id) + (v_idx - 1);
@@ -1845,7 +1845,7 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg)
i40e_status aq_ret = 0;
struct i40e_vsi *vsi;
int num_vsis = 1;
- int len = 0;
+ size_t len = 0;
int ret;
if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) {
@@ -1853,9 +1853,7 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg)
goto err;
}
- len = (sizeof(struct virtchnl_vf_resource) +
- sizeof(struct virtchnl_vsi_resource) * num_vsis);
-
+ len = struct_size(vfres, vsi_res, num_vsis);
vfres = kzalloc(len, GFP_KERNEL);
if (!vfres) {
aq_ret = I40E_ERR_NO_MEMORY;
@@ -2135,8 +2133,13 @@ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg)
}
}
- if (vf->adq_enabled)
+ if (vf->adq_enabled) {
+ if (idx >= ARRAY_SIZE(vf->ch)) {
+ aq_ret = I40E_ERR_NO_AVAILABLE_VSI;
+ goto error_param;
+ }
vsi_id = vf->ch[idx].vsi_id;
+ }
if (i40e_config_vsi_rx_queue(vf, vsi_id, vsi_queue_id,
&qpi->rxq) ||
@@ -2152,6 +2155,10 @@ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg)
* to its appropriate VSIs based on TC mapping
**/
if (vf->adq_enabled) {
+ if (idx >= ARRAY_SIZE(vf->ch)) {
+ aq_ret = I40E_ERR_NO_AVAILABLE_VSI;
+ goto error_param;
+ }
if (j == (vf->ch[idx].num_qps - 1)) {
idx++;
j = 0; /* resetting the queue count */
@@ -2318,7 +2325,6 @@ static int i40e_vc_enable_queues_msg(struct i40e_vf *vf, u8 *msg)
struct virtchnl_queue_select *vqs =
(struct virtchnl_queue_select *)msg;
struct i40e_pf *pf = vf->pf;
- u16 vsi_id = vqs->vsi_id;
i40e_status aq_ret = 0;
int i;
@@ -2327,7 +2333,7 @@ static int i40e_vc_enable_queues_msg(struct i40e_vf *vf, u8 *msg)
goto error_param;
}
- if (!i40e_vc_isvalid_vsi_id(vf, vsi_id)) {
+ if (!i40e_vc_isvalid_vsi_id(vf, vqs->vsi_id)) {
aq_ret = I40E_ERR_PARAM;
goto error_param;
}
@@ -2427,18 +2433,14 @@ static int i40e_vc_request_queues_msg(struct i40e_vf *vf, u8 *msg)
{
struct virtchnl_vf_res_request *vfres =
(struct virtchnl_vf_res_request *)msg;
- int req_pairs = vfres->num_queue_pairs;
- int cur_pairs = vf->num_queue_pairs;
+ u16 req_pairs = vfres->num_queue_pairs;
+ u8 cur_pairs = vf->num_queue_pairs;
struct i40e_pf *pf = vf->pf;
if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states))
return -EINVAL;
- if (req_pairs <= 0) {
- dev_err(&pf->pdev->dev,
- "VF %d tried to request %d queues. Ignoring.\n",
- vf->vf_id, req_pairs);
- } else if (req_pairs > I40E_MAX_VF_QUEUES) {
+ if (req_pairs > I40E_MAX_VF_QUEUES) {
dev_err(&pf->pdev->dev,
"VF %d tried to request more than %d queues.\n",
vf->vf_id,
@@ -2509,7 +2511,7 @@ error_param:
* MAC filters: 16 for multicast, 1 for MAC, 1 for broadcast
*/
#define I40E_VC_MAX_MAC_ADDR_PER_VF (16 + 1 + 1)
-#define I40E_VC_MAX_VLAN_PER_VF 8
+#define I40E_VC_MAX_VLAN_PER_VF 16
/**
* i40e_check_vf_permission
@@ -2587,12 +2589,11 @@ static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg)
(struct virtchnl_ether_addr_list *)msg;
struct i40e_pf *pf = vf->pf;
struct i40e_vsi *vsi = NULL;
- u16 vsi_id = al->vsi_id;
i40e_status ret = 0;
int i;
if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
- !i40e_vc_isvalid_vsi_id(vf, vsi_id)) {
+ !i40e_vc_isvalid_vsi_id(vf, al->vsi_id)) {
ret = I40E_ERR_PARAM;
goto error_param;
}
@@ -2657,12 +2658,11 @@ static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg)
(struct virtchnl_ether_addr_list *)msg;
struct i40e_pf *pf = vf->pf;
struct i40e_vsi *vsi = NULL;
- u16 vsi_id = al->vsi_id;
i40e_status ret = 0;
int i;
if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
- !i40e_vc_isvalid_vsi_id(vf, vsi_id)) {
+ !i40e_vc_isvalid_vsi_id(vf, al->vsi_id)) {
ret = I40E_ERR_PARAM;
goto error_param;
}
@@ -2726,7 +2726,6 @@ static int i40e_vc_add_vlan_msg(struct i40e_vf *vf, u8 *msg)
(struct virtchnl_vlan_filter_list *)msg;
struct i40e_pf *pf = vf->pf;
struct i40e_vsi *vsi = NULL;
- u16 vsi_id = vfl->vsi_id;
i40e_status aq_ret = 0;
int i;
@@ -2737,7 +2736,7 @@ static int i40e_vc_add_vlan_msg(struct i40e_vf *vf, u8 *msg)
goto error_param;
}
if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
- !i40e_vc_isvalid_vsi_id(vf, vsi_id)) {
+ !i40e_vc_isvalid_vsi_id(vf, vfl->vsi_id)) {
aq_ret = I40E_ERR_PARAM;
goto error_param;
}
@@ -2798,12 +2797,11 @@ static int i40e_vc_remove_vlan_msg(struct i40e_vf *vf, u8 *msg)
(struct virtchnl_vlan_filter_list *)msg;
struct i40e_pf *pf = vf->pf;
struct i40e_vsi *vsi = NULL;
- u16 vsi_id = vfl->vsi_id;
i40e_status aq_ret = 0;
int i;
if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
- !i40e_vc_isvalid_vsi_id(vf, vsi_id)) {
+ !i40e_vc_isvalid_vsi_id(vf, vfl->vsi_id)) {
aq_ret = I40E_ERR_PARAM;
goto error_param;
}
@@ -2920,11 +2918,10 @@ static int i40e_vc_config_rss_key(struct i40e_vf *vf, u8 *msg)
(struct virtchnl_rss_key *)msg;
struct i40e_pf *pf = vf->pf;
struct i40e_vsi *vsi = NULL;
- u16 vsi_id = vrk->vsi_id;
i40e_status aq_ret = 0;
if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
- !i40e_vc_isvalid_vsi_id(vf, vsi_id) ||
+ !i40e_vc_isvalid_vsi_id(vf, vrk->vsi_id) ||
(vrk->key_len != I40E_HKEY_ARRAY_SIZE)) {
aq_ret = I40E_ERR_PARAM;
goto err;
@@ -2951,16 +2948,22 @@ static int i40e_vc_config_rss_lut(struct i40e_vf *vf, u8 *msg)
(struct virtchnl_rss_lut *)msg;
struct i40e_pf *pf = vf->pf;
struct i40e_vsi *vsi = NULL;
- u16 vsi_id = vrl->vsi_id;
i40e_status aq_ret = 0;
+ u16 i;
if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
- !i40e_vc_isvalid_vsi_id(vf, vsi_id) ||
+ !i40e_vc_isvalid_vsi_id(vf, vrl->vsi_id) ||
(vrl->lut_entries != I40E_VF_HLUT_ARRAY_SIZE)) {
aq_ret = I40E_ERR_PARAM;
goto err;
}
+ for (i = 0; i < vrl->lut_entries; i++)
+ if (vrl->lut[i] >= vf->num_queue_pairs) {
+ aq_ret = I40E_ERR_PARAM;
+ goto err;
+ }
+
vsi = pf->vsi[vf->lan_vsi_idx];
aq_ret = i40e_config_rss(vsi, NULL, vrl->lut, I40E_VF_HLUT_ARRAY_SIZE);
/* send the response to the VF */
@@ -3041,14 +3044,15 @@ err:
**/
static int i40e_vc_enable_vlan_stripping(struct i40e_vf *vf, u8 *msg)
{
- struct i40e_vsi *vsi = vf->pf->vsi[vf->lan_vsi_idx];
i40e_status aq_ret = 0;
+ struct i40e_vsi *vsi;
if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
aq_ret = I40E_ERR_PARAM;
goto err;
}
+ vsi = vf->pf->vsi[vf->lan_vsi_idx];
i40e_vlan_stripping_enable(vsi);
/* send the response to the VF */
@@ -3066,14 +3070,15 @@ err:
**/
static int i40e_vc_disable_vlan_stripping(struct i40e_vf *vf, u8 *msg)
{
- struct i40e_vsi *vsi = vf->pf->vsi[vf->lan_vsi_idx];
i40e_status aq_ret = 0;
+ struct i40e_vsi *vsi;
if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
aq_ret = I40E_ERR_PARAM;
goto err;
}
+ vsi = vf->pf->vsi[vf->lan_vsi_idx];
i40e_vlan_stripping_disable(vsi);
/* send the response to the VF */
@@ -3531,8 +3536,9 @@ static int i40e_vc_add_qch_msg(struct i40e_vf *vf, u8 *msg)
(struct virtchnl_tc_info *)msg;
struct i40e_pf *pf = vf->pf;
struct i40e_link_status *ls = &pf->hw.phy.link_info;
- int i, adq_request_qps = 0, speed = 0;
+ int i, adq_request_qps = 0;
i40e_status aq_ret = 0;
+ u64 speed = 0;
if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
aq_ret = I40E_ERR_PARAM;
@@ -3558,8 +3564,8 @@ static int i40e_vc_add_qch_msg(struct i40e_vf *vf, u8 *msg)
/* max number of traffic classes for VF currently capped at 4 */
if (!tci->num_tc || tci->num_tc > I40E_MAX_VF_VSI) {
dev_err(&pf->pdev->dev,
- "VF %d trying to set %u TCs, valid range 1-4 TCs per VF\n",
- vf->vf_id, tci->num_tc);
+ "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;
goto err;
}
@@ -3569,8 +3575,9 @@ static int i40e_vc_add_qch_msg(struct i40e_vf *vf, u8 *msg)
if (!tci->list[i].count ||
tci->list[i].count > I40E_DEFAULT_QUEUES_PER_VF) {
dev_err(&pf->pdev->dev,
- "VF %d: TC %d trying to set %u queues, valid range 1-4 queues per TC\n",
- vf->vf_id, i, tci->list[i].count);
+ "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;
goto err;
}
@@ -3730,19 +3737,6 @@ int i40e_vc_process_vf_msg(struct i40e_pf *pf, s16 vf_id, u32 v_opcode,
/* perform basic checks on the msg */
ret = virtchnl_vc_validate_vf_msg(&vf->vf_ver, v_opcode, msg, msglen);
- /* perform additional checks specific to this driver */
- if (v_opcode == VIRTCHNL_OP_CONFIG_RSS_KEY) {
- struct virtchnl_rss_key *vrk = (struct virtchnl_rss_key *)msg;
-
- if (vrk->key_len != I40E_HKEY_ARRAY_SIZE)
- ret = -EINVAL;
- } else if (v_opcode == VIRTCHNL_OP_CONFIG_RSS_LUT) {
- struct virtchnl_rss_lut *vrl = (struct virtchnl_rss_lut *)msg;
-
- if (vrl->lut_entries != I40E_VF_HLUT_ARRAY_SIZE)
- ret = -EINVAL;
- }
-
if (ret) {
i40e_vc_send_resp_to_vf(vf, v_opcode, I40E_ERR_PARAM);
dev_err(&pf->pdev->dev, "Invalid message from VF %d, opcode %d, len %d\n",
@@ -3943,6 +3937,11 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
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");
+ return -EAGAIN;
+ }
+
/* validate the request */
ret = i40e_validate_vf(pf, vf_id);
if (ret)
@@ -3967,11 +3966,6 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
goto error_param;
}
- 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");
- return -EAGAIN;
- }
-
if (is_multicast_ether_addr(mac)) {
dev_err(&pf->pdev->dev,
"Invalid Ethernet address %pM for VF %d\n", mac, vf_id);
@@ -4302,10 +4296,8 @@ int i40e_ndo_get_vf_config(struct net_device *netdev,
vf = &pf->vf[vf_id];
/* first vsi is always the LAN vsi */
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);
- ret = -EAGAIN;
+ if (!vsi) {
+ ret = -ENOENT;
goto error_param;
}
diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.c b/drivers/net/ethernet/intel/i40e/i40e_xsk.c
index 1b17486543ac..32bad014d76c 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_xsk.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.c
@@ -215,6 +215,7 @@ static int i40e_run_xdp_zc(struct i40e_ring *rx_ring, struct xdp_buff *xdp)
break;
default:
bpf_warn_invalid_xdp_action(act);
+ /* fall through */
case XDP_ABORTED:
trace_xdp_exception(rx_ring->netdev, xdp_prog, act);
/* fallthrough -- handle aborts by dropping packet */
@@ -640,8 +641,8 @@ static bool i40e_xmit_zc(struct i40e_ring *xdp_ring, unsigned int budget)
struct i40e_tx_desc *tx_desc = NULL;
struct i40e_tx_buffer *tx_bi;
bool work_done = true;
+ struct xdp_desc desc;
dma_addr_t dma;
- u32 len;
while (budget-- > 0) {
if (!unlikely(I40E_DESC_UNUSED(xdp_ring))) {
@@ -650,21 +651,23 @@ static bool i40e_xmit_zc(struct i40e_ring *xdp_ring, unsigned int budget)
break;
}
- if (!xsk_umem_consume_tx(xdp_ring->xsk_umem, &dma, &len))
+ if (!xsk_umem_consume_tx(xdp_ring->xsk_umem, &desc))
break;
- dma_sync_single_for_device(xdp_ring->dev, dma, len,
+ dma = xdp_umem_get_dma(xdp_ring->xsk_umem, desc.addr);
+
+ dma_sync_single_for_device(xdp_ring->dev, dma, desc.len,
DMA_BIDIRECTIONAL);
tx_bi = &xdp_ring->tx_bi[xdp_ring->next_to_use];
- tx_bi->bytecount = len;
+ tx_bi->bytecount = desc.len;
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, len, 0);
+ 0, desc.len, 0);
xdp_ring->next_to_use++;
if (xdp_ring->next_to_use == xdp_ring->count)
diff --git a/drivers/net/ethernet/intel/iavf/Makefile b/drivers/net/ethernet/intel/iavf/Makefile
index 9cbb5743ed12..c997063ed728 100644
--- a/drivers/net/ethernet/intel/iavf/Makefile
+++ b/drivers/net/ethernet/intel/iavf/Makefile
@@ -12,4 +12,4 @@ subdir-ccflags-y += -I$(src)
obj-$(CONFIG_IAVF) += iavf.o
iavf-objs := iavf_main.o iavf_ethtool.o iavf_virtchnl.o \
- iavf_txrx.o iavf_common.o i40e_adminq.o iavf_client.o
+ iavf_txrx.o iavf_common.o iavf_adminq.o iavf_client.o
diff --git a/drivers/net/ethernet/intel/iavf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/iavf/i40e_adminq_cmd.h
deleted file mode 100644
index e5ae4a1c0cff..000000000000
--- a/drivers/net/ethernet/intel/iavf/i40e_adminq_cmd.h
+++ /dev/null
@@ -1,530 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* Copyright(c) 2013 - 2018 Intel Corporation. */
-
-#ifndef _I40E_ADMINQ_CMD_H_
-#define _I40E_ADMINQ_CMD_H_
-
-/* This header file defines the i40e Admin Queue commands and is shared between
- * i40e Firmware and Software. Do not change the names in this file to IAVF
- * because this file should be diff-able against the i40e version, even
- * though many parts have been removed in this VF version.
- *
- * This file needs to comply with the Linux Kernel coding style.
- */
-
-#define I40E_FW_API_VERSION_MAJOR 0x0001
-#define I40E_FW_API_VERSION_MINOR_X722 0x0005
-#define I40E_FW_API_VERSION_MINOR_X710 0x0008
-
-#define I40E_FW_MINOR_VERSION(_h) ((_h)->mac.type == I40E_MAC_XL710 ? \
- I40E_FW_API_VERSION_MINOR_X710 : \
- I40E_FW_API_VERSION_MINOR_X722)
-
-/* API version 1.7 implements additional link and PHY-specific APIs */
-#define I40E_MINOR_VER_GET_LINK_INFO_XL710 0x0007
-
-struct i40e_aq_desc {
- __le16 flags;
- __le16 opcode;
- __le16 datalen;
- __le16 retval;
- __le32 cookie_high;
- __le32 cookie_low;
- union {
- struct {
- __le32 param0;
- __le32 param1;
- __le32 param2;
- __le32 param3;
- } internal;
- struct {
- __le32 param0;
- __le32 param1;
- __le32 addr_high;
- __le32 addr_low;
- } external;
- u8 raw[16];
- } params;
-};
-
-/* Flags sub-structure
- * |0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |10 |11 |12 |13 |14 |15 |
- * |DD |CMP|ERR|VFE| * * RESERVED * * |LB |RD |VFC|BUF|SI |EI |FE |
- */
-
-/* command flags and offsets*/
-#define I40E_AQ_FLAG_DD_SHIFT 0
-#define I40E_AQ_FLAG_CMP_SHIFT 1
-#define I40E_AQ_FLAG_ERR_SHIFT 2
-#define I40E_AQ_FLAG_VFE_SHIFT 3
-#define I40E_AQ_FLAG_LB_SHIFT 9
-#define I40E_AQ_FLAG_RD_SHIFT 10
-#define I40E_AQ_FLAG_VFC_SHIFT 11
-#define I40E_AQ_FLAG_BUF_SHIFT 12
-#define I40E_AQ_FLAG_SI_SHIFT 13
-#define I40E_AQ_FLAG_EI_SHIFT 14
-#define I40E_AQ_FLAG_FE_SHIFT 15
-
-#define I40E_AQ_FLAG_DD BIT(I40E_AQ_FLAG_DD_SHIFT) /* 0x1 */
-#define I40E_AQ_FLAG_CMP BIT(I40E_AQ_FLAG_CMP_SHIFT) /* 0x2 */
-#define I40E_AQ_FLAG_ERR BIT(I40E_AQ_FLAG_ERR_SHIFT) /* 0x4 */
-#define I40E_AQ_FLAG_VFE BIT(I40E_AQ_FLAG_VFE_SHIFT) /* 0x8 */
-#define I40E_AQ_FLAG_LB BIT(I40E_AQ_FLAG_LB_SHIFT) /* 0x200 */
-#define I40E_AQ_FLAG_RD BIT(I40E_AQ_FLAG_RD_SHIFT) /* 0x400 */
-#define I40E_AQ_FLAG_VFC BIT(I40E_AQ_FLAG_VFC_SHIFT) /* 0x800 */
-#define I40E_AQ_FLAG_BUF BIT(I40E_AQ_FLAG_BUF_SHIFT) /* 0x1000 */
-#define I40E_AQ_FLAG_SI BIT(I40E_AQ_FLAG_SI_SHIFT) /* 0x2000 */
-#define I40E_AQ_FLAG_EI BIT(I40E_AQ_FLAG_EI_SHIFT) /* 0x4000 */
-#define I40E_AQ_FLAG_FE BIT(I40E_AQ_FLAG_FE_SHIFT) /* 0x8000 */
-
-/* error codes */
-enum i40e_admin_queue_err {
- I40E_AQ_RC_OK = 0, /* success */
- I40E_AQ_RC_EPERM = 1, /* Operation not permitted */
- I40E_AQ_RC_ENOENT = 2, /* No such element */
- I40E_AQ_RC_ESRCH = 3, /* Bad opcode */
- I40E_AQ_RC_EINTR = 4, /* operation interrupted */
- I40E_AQ_RC_EIO = 5, /* I/O error */
- I40E_AQ_RC_ENXIO = 6, /* No such resource */
- I40E_AQ_RC_E2BIG = 7, /* Arg too long */
- I40E_AQ_RC_EAGAIN = 8, /* Try again */
- I40E_AQ_RC_ENOMEM = 9, /* Out of memory */
- I40E_AQ_RC_EACCES = 10, /* Permission denied */
- I40E_AQ_RC_EFAULT = 11, /* Bad address */
- I40E_AQ_RC_EBUSY = 12, /* Device or resource busy */
- I40E_AQ_RC_EEXIST = 13, /* object already exists */
- I40E_AQ_RC_EINVAL = 14, /* Invalid argument */
- I40E_AQ_RC_ENOTTY = 15, /* Not a typewriter */
- I40E_AQ_RC_ENOSPC = 16, /* No space left or alloc failure */
- I40E_AQ_RC_ENOSYS = 17, /* Function not implemented */
- I40E_AQ_RC_ERANGE = 18, /* Parameter out of range */
- I40E_AQ_RC_EFLUSHED = 19, /* Cmd flushed due to prev cmd error */
- I40E_AQ_RC_BAD_ADDR = 20, /* Descriptor contains a bad pointer */
- I40E_AQ_RC_EMODE = 21, /* Op not allowed in current dev mode */
- I40E_AQ_RC_EFBIG = 22, /* File too large */
-};
-
-/* Admin Queue command opcodes */
-enum i40e_admin_queue_opc {
- /* aq commands */
- i40e_aqc_opc_get_version = 0x0001,
- i40e_aqc_opc_driver_version = 0x0002,
- i40e_aqc_opc_queue_shutdown = 0x0003,
- i40e_aqc_opc_set_pf_context = 0x0004,
-
- /* resource ownership */
- i40e_aqc_opc_request_resource = 0x0008,
- i40e_aqc_opc_release_resource = 0x0009,
-
- i40e_aqc_opc_list_func_capabilities = 0x000A,
- i40e_aqc_opc_list_dev_capabilities = 0x000B,
-
- /* Proxy commands */
- i40e_aqc_opc_set_proxy_config = 0x0104,
- i40e_aqc_opc_set_ns_proxy_table_entry = 0x0105,
-
- /* LAA */
- i40e_aqc_opc_mac_address_read = 0x0107,
- i40e_aqc_opc_mac_address_write = 0x0108,
-
- /* PXE */
- i40e_aqc_opc_clear_pxe_mode = 0x0110,
-
- /* WoL commands */
- i40e_aqc_opc_set_wol_filter = 0x0120,
- i40e_aqc_opc_get_wake_reason = 0x0121,
-
- /* internal switch commands */
- i40e_aqc_opc_get_switch_config = 0x0200,
- i40e_aqc_opc_add_statistics = 0x0201,
- i40e_aqc_opc_remove_statistics = 0x0202,
- i40e_aqc_opc_set_port_parameters = 0x0203,
- i40e_aqc_opc_get_switch_resource_alloc = 0x0204,
- i40e_aqc_opc_set_switch_config = 0x0205,
- i40e_aqc_opc_rx_ctl_reg_read = 0x0206,
- i40e_aqc_opc_rx_ctl_reg_write = 0x0207,
-
- i40e_aqc_opc_add_vsi = 0x0210,
- i40e_aqc_opc_update_vsi_parameters = 0x0211,
- i40e_aqc_opc_get_vsi_parameters = 0x0212,
-
- i40e_aqc_opc_add_pv = 0x0220,
- i40e_aqc_opc_update_pv_parameters = 0x0221,
- i40e_aqc_opc_get_pv_parameters = 0x0222,
-
- i40e_aqc_opc_add_veb = 0x0230,
- i40e_aqc_opc_update_veb_parameters = 0x0231,
- i40e_aqc_opc_get_veb_parameters = 0x0232,
-
- i40e_aqc_opc_delete_element = 0x0243,
-
- i40e_aqc_opc_add_macvlan = 0x0250,
- i40e_aqc_opc_remove_macvlan = 0x0251,
- i40e_aqc_opc_add_vlan = 0x0252,
- i40e_aqc_opc_remove_vlan = 0x0253,
- i40e_aqc_opc_set_vsi_promiscuous_modes = 0x0254,
- i40e_aqc_opc_add_tag = 0x0255,
- i40e_aqc_opc_remove_tag = 0x0256,
- i40e_aqc_opc_add_multicast_etag = 0x0257,
- i40e_aqc_opc_remove_multicast_etag = 0x0258,
- i40e_aqc_opc_update_tag = 0x0259,
- i40e_aqc_opc_add_control_packet_filter = 0x025A,
- i40e_aqc_opc_remove_control_packet_filter = 0x025B,
- i40e_aqc_opc_add_cloud_filters = 0x025C,
- i40e_aqc_opc_remove_cloud_filters = 0x025D,
- i40e_aqc_opc_clear_wol_switch_filters = 0x025E,
-
- i40e_aqc_opc_add_mirror_rule = 0x0260,
- i40e_aqc_opc_delete_mirror_rule = 0x0261,
-
- /* Dynamic Device Personalization */
- i40e_aqc_opc_write_personalization_profile = 0x0270,
- i40e_aqc_opc_get_personalization_profile_list = 0x0271,
-
- /* DCB commands */
- i40e_aqc_opc_dcb_ignore_pfc = 0x0301,
- i40e_aqc_opc_dcb_updated = 0x0302,
- i40e_aqc_opc_set_dcb_parameters = 0x0303,
-
- /* TX scheduler */
- i40e_aqc_opc_configure_vsi_bw_limit = 0x0400,
- i40e_aqc_opc_configure_vsi_ets_sla_bw_limit = 0x0406,
- i40e_aqc_opc_configure_vsi_tc_bw = 0x0407,
- i40e_aqc_opc_query_vsi_bw_config = 0x0408,
- i40e_aqc_opc_query_vsi_ets_sla_config = 0x040A,
- i40e_aqc_opc_configure_switching_comp_bw_limit = 0x0410,
-
- i40e_aqc_opc_enable_switching_comp_ets = 0x0413,
- i40e_aqc_opc_modify_switching_comp_ets = 0x0414,
- i40e_aqc_opc_disable_switching_comp_ets = 0x0415,
- i40e_aqc_opc_configure_switching_comp_ets_bw_limit = 0x0416,
- i40e_aqc_opc_configure_switching_comp_bw_config = 0x0417,
- i40e_aqc_opc_query_switching_comp_ets_config = 0x0418,
- i40e_aqc_opc_query_port_ets_config = 0x0419,
- i40e_aqc_opc_query_switching_comp_bw_config = 0x041A,
- i40e_aqc_opc_suspend_port_tx = 0x041B,
- i40e_aqc_opc_resume_port_tx = 0x041C,
- i40e_aqc_opc_configure_partition_bw = 0x041D,
- /* hmc */
- i40e_aqc_opc_query_hmc_resource_profile = 0x0500,
- i40e_aqc_opc_set_hmc_resource_profile = 0x0501,
-
- /* phy commands*/
- i40e_aqc_opc_get_phy_abilities = 0x0600,
- i40e_aqc_opc_set_phy_config = 0x0601,
- i40e_aqc_opc_set_mac_config = 0x0603,
- i40e_aqc_opc_set_link_restart_an = 0x0605,
- i40e_aqc_opc_get_link_status = 0x0607,
- i40e_aqc_opc_set_phy_int_mask = 0x0613,
- i40e_aqc_opc_get_local_advt_reg = 0x0614,
- i40e_aqc_opc_set_local_advt_reg = 0x0615,
- i40e_aqc_opc_get_partner_advt = 0x0616,
- i40e_aqc_opc_set_lb_modes = 0x0618,
- i40e_aqc_opc_get_phy_wol_caps = 0x0621,
- i40e_aqc_opc_set_phy_debug = 0x0622,
- i40e_aqc_opc_upload_ext_phy_fm = 0x0625,
- i40e_aqc_opc_run_phy_activity = 0x0626,
- i40e_aqc_opc_set_phy_register = 0x0628,
- i40e_aqc_opc_get_phy_register = 0x0629,
-
- /* NVM commands */
- i40e_aqc_opc_nvm_read = 0x0701,
- i40e_aqc_opc_nvm_erase = 0x0702,
- i40e_aqc_opc_nvm_update = 0x0703,
- i40e_aqc_opc_nvm_config_read = 0x0704,
- i40e_aqc_opc_nvm_config_write = 0x0705,
- i40e_aqc_opc_oem_post_update = 0x0720,
- i40e_aqc_opc_thermal_sensor = 0x0721,
-
- /* virtualization commands */
- i40e_aqc_opc_send_msg_to_pf = 0x0801,
- i40e_aqc_opc_send_msg_to_vf = 0x0802,
- i40e_aqc_opc_send_msg_to_peer = 0x0803,
-
- /* alternate structure */
- i40e_aqc_opc_alternate_write = 0x0900,
- i40e_aqc_opc_alternate_write_indirect = 0x0901,
- i40e_aqc_opc_alternate_read = 0x0902,
- i40e_aqc_opc_alternate_read_indirect = 0x0903,
- i40e_aqc_opc_alternate_write_done = 0x0904,
- i40e_aqc_opc_alternate_set_mode = 0x0905,
- i40e_aqc_opc_alternate_clear_port = 0x0906,
-
- /* LLDP commands */
- i40e_aqc_opc_lldp_get_mib = 0x0A00,
- i40e_aqc_opc_lldp_update_mib = 0x0A01,
- i40e_aqc_opc_lldp_add_tlv = 0x0A02,
- i40e_aqc_opc_lldp_update_tlv = 0x0A03,
- i40e_aqc_opc_lldp_delete_tlv = 0x0A04,
- i40e_aqc_opc_lldp_stop = 0x0A05,
- i40e_aqc_opc_lldp_start = 0x0A06,
-
- /* Tunnel commands */
- i40e_aqc_opc_add_udp_tunnel = 0x0B00,
- i40e_aqc_opc_del_udp_tunnel = 0x0B01,
- i40e_aqc_opc_set_rss_key = 0x0B02,
- i40e_aqc_opc_set_rss_lut = 0x0B03,
- i40e_aqc_opc_get_rss_key = 0x0B04,
- i40e_aqc_opc_get_rss_lut = 0x0B05,
-
- /* Async Events */
- i40e_aqc_opc_event_lan_overflow = 0x1001,
-
- /* OEM commands */
- i40e_aqc_opc_oem_parameter_change = 0xFE00,
- i40e_aqc_opc_oem_device_status_change = 0xFE01,
- i40e_aqc_opc_oem_ocsd_initialize = 0xFE02,
- i40e_aqc_opc_oem_ocbb_initialize = 0xFE03,
-
- /* debug commands */
- i40e_aqc_opc_debug_read_reg = 0xFF03,
- i40e_aqc_opc_debug_write_reg = 0xFF04,
- i40e_aqc_opc_debug_modify_reg = 0xFF07,
- i40e_aqc_opc_debug_dump_internals = 0xFF08,
-};
-
-/* command structures and indirect data structures */
-
-/* Structure naming conventions:
- * - no suffix for direct command descriptor structures
- * - _data for indirect sent data
- * - _resp for indirect return data (data which is both will use _data)
- * - _completion for direct return data
- * - _element_ for repeated elements (may also be _data or _resp)
- *
- * Command structures are expected to overlay the params.raw member of the basic
- * descriptor, and as such cannot exceed 16 bytes in length.
- */
-
-/* This macro is used to generate a compilation error if a structure
- * is not exactly the correct length. It gives a divide by zero error if the
- * structure is not of the correct size, otherwise it creates an enum that is
- * never used.
- */
-#define I40E_CHECK_STRUCT_LEN(n, X) enum i40e_static_assert_enum_##X \
- { i40e_static_assert_##X = (n)/((sizeof(struct X) == (n)) ? 1 : 0) }
-
-/* This macro is used extensively to ensure that command structures are 16
- * bytes in length as they have to map to the raw array of that size.
- */
-#define I40E_CHECK_CMD_LENGTH(X) I40E_CHECK_STRUCT_LEN(16, X)
-
-/* Queue Shutdown (direct 0x0003) */
-struct i40e_aqc_queue_shutdown {
- __le32 driver_unloading;
-#define I40E_AQ_DRIVER_UNLOADING 0x1
- u8 reserved[12];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_queue_shutdown);
-
-struct i40e_aqc_vsi_properties_data {
- /* first 96 byte are written by SW */
- __le16 valid_sections;
-#define I40E_AQ_VSI_PROP_SWITCH_VALID 0x0001
-#define I40E_AQ_VSI_PROP_SECURITY_VALID 0x0002
-#define I40E_AQ_VSI_PROP_VLAN_VALID 0x0004
-#define I40E_AQ_VSI_PROP_CAS_PV_VALID 0x0008
-#define I40E_AQ_VSI_PROP_INGRESS_UP_VALID 0x0010
-#define I40E_AQ_VSI_PROP_EGRESS_UP_VALID 0x0020
-#define I40E_AQ_VSI_PROP_QUEUE_MAP_VALID 0x0040
-#define I40E_AQ_VSI_PROP_QUEUE_OPT_VALID 0x0080
-#define I40E_AQ_VSI_PROP_OUTER_UP_VALID 0x0100
-#define I40E_AQ_VSI_PROP_SCHED_VALID 0x0200
- /* switch section */
- __le16 switch_id; /* 12bit id combined with flags below */
-#define I40E_AQ_VSI_SW_ID_SHIFT 0x0000
-#define I40E_AQ_VSI_SW_ID_MASK (0xFFF << I40E_AQ_VSI_SW_ID_SHIFT)
-#define I40E_AQ_VSI_SW_ID_FLAG_NOT_STAG 0x1000
-#define I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB 0x2000
-#define I40E_AQ_VSI_SW_ID_FLAG_LOCAL_LB 0x4000
- u8 sw_reserved[2];
- /* security section */
- u8 sec_flags;
-#define I40E_AQ_VSI_SEC_FLAG_ALLOW_DEST_OVRD 0x01
-#define I40E_AQ_VSI_SEC_FLAG_ENABLE_VLAN_CHK 0x02
-#define I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK 0x04
- u8 sec_reserved;
- /* VLAN section */
- __le16 pvid; /* VLANS include priority bits */
- __le16 fcoe_pvid;
- u8 port_vlan_flags;
-#define I40E_AQ_VSI_PVLAN_MODE_SHIFT 0x00
-#define I40E_AQ_VSI_PVLAN_MODE_MASK (0x03 << \
- I40E_AQ_VSI_PVLAN_MODE_SHIFT)
-#define I40E_AQ_VSI_PVLAN_MODE_TAGGED 0x01
-#define I40E_AQ_VSI_PVLAN_MODE_UNTAGGED 0x02
-#define I40E_AQ_VSI_PVLAN_MODE_ALL 0x03
-#define I40E_AQ_VSI_PVLAN_INSERT_PVID 0x04
-#define I40E_AQ_VSI_PVLAN_EMOD_SHIFT 0x03
-#define I40E_AQ_VSI_PVLAN_EMOD_MASK (0x3 << \
- I40E_AQ_VSI_PVLAN_EMOD_SHIFT)
-#define I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH 0x0
-#define I40E_AQ_VSI_PVLAN_EMOD_STR_UP 0x08
-#define I40E_AQ_VSI_PVLAN_EMOD_STR 0x10
-#define I40E_AQ_VSI_PVLAN_EMOD_NOTHING 0x18
- u8 pvlan_reserved[3];
- /* ingress egress up sections */
- __le32 ingress_table; /* bitmap, 3 bits per up */
-#define I40E_AQ_VSI_UP_TABLE_UP0_SHIFT 0
-#define I40E_AQ_VSI_UP_TABLE_UP0_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP0_SHIFT)
-#define I40E_AQ_VSI_UP_TABLE_UP1_SHIFT 3
-#define I40E_AQ_VSI_UP_TABLE_UP1_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP1_SHIFT)
-#define I40E_AQ_VSI_UP_TABLE_UP2_SHIFT 6
-#define I40E_AQ_VSI_UP_TABLE_UP2_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP2_SHIFT)
-#define I40E_AQ_VSI_UP_TABLE_UP3_SHIFT 9
-#define I40E_AQ_VSI_UP_TABLE_UP3_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP3_SHIFT)
-#define I40E_AQ_VSI_UP_TABLE_UP4_SHIFT 12
-#define I40E_AQ_VSI_UP_TABLE_UP4_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP4_SHIFT)
-#define I40E_AQ_VSI_UP_TABLE_UP5_SHIFT 15
-#define I40E_AQ_VSI_UP_TABLE_UP5_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP5_SHIFT)
-#define I40E_AQ_VSI_UP_TABLE_UP6_SHIFT 18
-#define I40E_AQ_VSI_UP_TABLE_UP6_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP6_SHIFT)
-#define I40E_AQ_VSI_UP_TABLE_UP7_SHIFT 21
-#define I40E_AQ_VSI_UP_TABLE_UP7_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP7_SHIFT)
- __le32 egress_table; /* same defines as for ingress table */
- /* cascaded PV section */
- __le16 cas_pv_tag;
- u8 cas_pv_flags;
-#define I40E_AQ_VSI_CAS_PV_TAGX_SHIFT 0x00
-#define I40E_AQ_VSI_CAS_PV_TAGX_MASK (0x03 << \
- I40E_AQ_VSI_CAS_PV_TAGX_SHIFT)
-#define I40E_AQ_VSI_CAS_PV_TAGX_LEAVE 0x00
-#define I40E_AQ_VSI_CAS_PV_TAGX_REMOVE 0x01
-#define I40E_AQ_VSI_CAS_PV_TAGX_COPY 0x02
-#define I40E_AQ_VSI_CAS_PV_INSERT_TAG 0x10
-#define I40E_AQ_VSI_CAS_PV_ETAG_PRUNE 0x20
-#define I40E_AQ_VSI_CAS_PV_ACCEPT_HOST_TAG 0x40
- u8 cas_pv_reserved;
- /* queue mapping section */
- __le16 mapping_flags;
-#define I40E_AQ_VSI_QUE_MAP_CONTIG 0x0
-#define I40E_AQ_VSI_QUE_MAP_NONCONTIG 0x1
- __le16 queue_mapping[16];
-#define I40E_AQ_VSI_QUEUE_SHIFT 0x0
-#define I40E_AQ_VSI_QUEUE_MASK (0x7FF << I40E_AQ_VSI_QUEUE_SHIFT)
- __le16 tc_mapping[8];
-#define I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT 0
-#define I40E_AQ_VSI_TC_QUE_OFFSET_MASK (0x1FF << \
- I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT)
-#define I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT 9
-#define I40E_AQ_VSI_TC_QUE_NUMBER_MASK (0x7 << \
- I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT)
- /* queueing option section */
- u8 queueing_opt_flags;
-#define I40E_AQ_VSI_QUE_OPT_MULTICAST_UDP_ENA 0x04
-#define I40E_AQ_VSI_QUE_OPT_UNICAST_UDP_ENA 0x08
-#define I40E_AQ_VSI_QUE_OPT_TCP_ENA 0x10
-#define I40E_AQ_VSI_QUE_OPT_FCOE_ENA 0x20
-#define I40E_AQ_VSI_QUE_OPT_RSS_LUT_PF 0x00
-#define I40E_AQ_VSI_QUE_OPT_RSS_LUT_VSI 0x40
- u8 queueing_opt_reserved[3];
- /* scheduler section */
- u8 up_enable_bits;
- u8 sched_reserved;
- /* outer up section */
- __le32 outer_up_table; /* same structure and defines as ingress tbl */
- u8 cmd_reserved[8];
- /* last 32 bytes are written by FW */
- __le16 qs_handle[8];
-#define I40E_AQ_VSI_QS_HANDLE_INVALID 0xFFFF
- __le16 stat_counter_idx;
- __le16 sched_id;
- u8 resp_reserved[12];
-};
-
-I40E_CHECK_STRUCT_LEN(128, i40e_aqc_vsi_properties_data);
-
-/* Get VEB Parameters (direct 0x0232)
- * uses i40e_aqc_switch_seid for the descriptor
- */
-struct i40e_aqc_get_veb_parameters_completion {
- __le16 seid;
- __le16 switch_id;
- __le16 veb_flags; /* only the first/last flags from 0x0230 is valid */
- __le16 statistic_index;
- __le16 vebs_used;
- __le16 vebs_free;
- u8 reserved[4];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_get_veb_parameters_completion);
-
-#define I40E_LINK_SPEED_100MB_SHIFT 0x1
-#define I40E_LINK_SPEED_1000MB_SHIFT 0x2
-#define I40E_LINK_SPEED_10GB_SHIFT 0x3
-#define I40E_LINK_SPEED_40GB_SHIFT 0x4
-#define I40E_LINK_SPEED_20GB_SHIFT 0x5
-#define I40E_LINK_SPEED_25GB_SHIFT 0x6
-
-enum i40e_aq_link_speed {
- I40E_LINK_SPEED_UNKNOWN = 0,
- I40E_LINK_SPEED_100MB = BIT(I40E_LINK_SPEED_100MB_SHIFT),
- I40E_LINK_SPEED_1GB = BIT(I40E_LINK_SPEED_1000MB_SHIFT),
- I40E_LINK_SPEED_10GB = BIT(I40E_LINK_SPEED_10GB_SHIFT),
- I40E_LINK_SPEED_40GB = BIT(I40E_LINK_SPEED_40GB_SHIFT),
- I40E_LINK_SPEED_20GB = BIT(I40E_LINK_SPEED_20GB_SHIFT),
- I40E_LINK_SPEED_25GB = BIT(I40E_LINK_SPEED_25GB_SHIFT),
-};
-
-/* Send to PF command (indirect 0x0801) id is only used by PF
- * Send to VF command (indirect 0x0802) id is only used by PF
- * Send to Peer PF command (indirect 0x0803)
- */
-struct i40e_aqc_pf_vf_message {
- __le32 id;
- u8 reserved[4];
- __le32 addr_high;
- __le32 addr_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_pf_vf_message);
-
-struct i40e_aqc_get_set_rss_key {
-#define I40E_AQC_SET_RSS_KEY_VSI_VALID BIT(15)
-#define I40E_AQC_SET_RSS_KEY_VSI_ID_SHIFT 0
-#define I40E_AQC_SET_RSS_KEY_VSI_ID_MASK (0x3FF << \
- I40E_AQC_SET_RSS_KEY_VSI_ID_SHIFT)
- __le16 vsi_id;
- u8 reserved[6];
- __le32 addr_high;
- __le32 addr_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_get_set_rss_key);
-
-struct i40e_aqc_get_set_rss_key_data {
- u8 standard_rss_key[0x28];
- u8 extended_hash_key[0xc];
-};
-
-I40E_CHECK_STRUCT_LEN(0x34, i40e_aqc_get_set_rss_key_data);
-
-struct i40e_aqc_get_set_rss_lut {
-#define I40E_AQC_SET_RSS_LUT_VSI_VALID BIT(15)
-#define I40E_AQC_SET_RSS_LUT_VSI_ID_SHIFT 0
-#define I40E_AQC_SET_RSS_LUT_VSI_ID_MASK (0x3FF << \
- I40E_AQC_SET_RSS_LUT_VSI_ID_SHIFT)
- __le16 vsi_id;
-#define I40E_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT 0
-#define I40E_AQC_SET_RSS_LUT_TABLE_TYPE_MASK \
- BIT(I40E_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT)
-
-#define I40E_AQC_SET_RSS_LUT_TABLE_TYPE_VSI 0
-#define I40E_AQC_SET_RSS_LUT_TABLE_TYPE_PF 1
- __le16 flags;
- u8 reserved[4];
- __le32 addr_high;
- __le32 addr_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_get_set_rss_lut);
-#endif /* _I40E_ADMINQ_CMD_H_ */
diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h
index 272d76b733aa..9fc635d816d2 100644
--- a/drivers/net/ethernet/intel/iavf/iavf.h
+++ b/drivers/net/ethernet/intel/iavf/iavf.h
@@ -109,7 +109,7 @@ struct iavf_q_vector {
/* Helper macros to switch between ints/sec and what the register uses.
* And yes, it's the same math going both ways. The lowest value
- * supported by all of the i40e hardware is 8.
+ * supported by all of the iavf hardware is 8.
*/
#define EITR_INTS_PER_SEC_TO_REG(_eitr) \
((_eitr) ? (1000000000 / ((_eitr) * 256)) : 8)
@@ -171,6 +171,7 @@ enum iavf_state_t {
__IAVF_INIT_GET_RESOURCES, /* aq msg sent, awaiting reply */
__IAVF_INIT_SW, /* got resources, setting up structs */
__IAVF_RESETTING, /* in reset */
+ __IAVF_COMM_FAILED, /* communication with PF failed */
/* Below here, watchdog is running */
__IAVF_DOWN, /* ready, can be opened */
__IAVF_DOWN_PENDING, /* descending, waiting for watchdog */
@@ -216,7 +217,6 @@ struct iavf_cloud_filter {
/* board specific private data structure */
struct iavf_adapter {
- struct timer_list watchdog_timer;
struct work_struct reset_task;
struct work_struct adminq_task;
struct delayed_work client_task;
@@ -244,7 +244,7 @@ struct iavf_adapter {
int num_iwarp_msix;
int iwarp_base_vector;
u32 client_pending;
- struct i40e_client_instance *cinst;
+ struct iavf_client_instance *cinst;
struct msix_entry *msix_entries;
u32 flags;
@@ -303,7 +303,7 @@ struct iavf_adapter {
enum iavf_state_t state;
unsigned long crit_section;
- struct work_struct watchdog_task;
+ struct delayed_work watchdog_task;
bool netdev_registered;
bool link_up;
enum virtchnl_link_speed link_speed;
@@ -351,7 +351,7 @@ struct iavf_adapter {
/* Ethtool Private Flags */
/* lan device, used by client interface */
-struct i40e_device {
+struct iavf_device {
struct list_head list;
struct iavf_adapter *vf;
};
@@ -359,6 +359,7 @@ struct i40e_device {
/* needed by iavf_ethtool.c */
extern char iavf_driver_name[];
extern const char iavf_driver_version[];
+extern struct workqueue_struct *iavf_wq;
int iavf_up(struct iavf_adapter *adapter);
void iavf_down(struct iavf_adapter *adapter);
@@ -402,7 +403,7 @@ void iavf_enable_vlan_stripping(struct iavf_adapter *adapter);
void iavf_disable_vlan_stripping(struct iavf_adapter *adapter);
void iavf_virtchnl_completion(struct iavf_adapter *adapter,
enum virtchnl_ops v_opcode,
- iavf_status v_retval, u8 *msg, u16 msglen);
+ enum iavf_status v_retval, u8 *msg, u16 msglen);
int iavf_config_rss(struct iavf_adapter *adapter);
int iavf_lan_add_device(struct iavf_adapter *adapter);
int iavf_lan_del_device(struct iavf_adapter *adapter);
diff --git a/drivers/net/ethernet/intel/iavf/i40e_adminq.c b/drivers/net/ethernet/intel/iavf/iavf_adminq.c
index fca1ecfd9f71..9fa3fa99b4c2 100644
--- a/drivers/net/ethernet/intel/iavf/i40e_adminq.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_adminq.c
@@ -4,16 +4,16 @@
#include "iavf_status.h"
#include "iavf_type.h"
#include "iavf_register.h"
-#include "i40e_adminq.h"
+#include "iavf_adminq.h"
#include "iavf_prototype.h"
/**
- * i40e_adminq_init_regs - Initialize AdminQ registers
+ * iavf_adminq_init_regs - Initialize AdminQ registers
* @hw: pointer to the hardware structure
*
* This assumes the alloc_asq and alloc_arq functions have already been called
**/
-static void i40e_adminq_init_regs(struct iavf_hw *hw)
+static void iavf_adminq_init_regs(struct iavf_hw *hw)
{
/* set head and tail registers in our local struct */
hw->aq.asq.tail = IAVF_VF_ATQT1;
@@ -29,24 +29,24 @@ static void i40e_adminq_init_regs(struct iavf_hw *hw)
}
/**
- * i40e_alloc_adminq_asq_ring - Allocate Admin Queue send rings
+ * iavf_alloc_adminq_asq_ring - Allocate Admin Queue send rings
* @hw: pointer to the hardware structure
**/
-static iavf_status i40e_alloc_adminq_asq_ring(struct iavf_hw *hw)
+static enum iavf_status iavf_alloc_adminq_asq_ring(struct iavf_hw *hw)
{
- iavf_status ret_code;
+ enum iavf_status ret_code;
ret_code = iavf_allocate_dma_mem(hw, &hw->aq.asq.desc_buf,
- i40e_mem_atq_ring,
+ iavf_mem_atq_ring,
(hw->aq.num_asq_entries *
- sizeof(struct i40e_aq_desc)),
+ sizeof(struct iavf_aq_desc)),
IAVF_ADMINQ_DESC_ALIGNMENT);
if (ret_code)
return ret_code;
ret_code = iavf_allocate_virt_mem(hw, &hw->aq.asq.cmd_buf,
(hw->aq.num_asq_entries *
- sizeof(struct i40e_asq_cmd_details)));
+ sizeof(struct iavf_asq_cmd_details)));
if (ret_code) {
iavf_free_dma_mem(hw, &hw->aq.asq.desc_buf);
return ret_code;
@@ -56,55 +56,55 @@ static iavf_status i40e_alloc_adminq_asq_ring(struct iavf_hw *hw)
}
/**
- * i40e_alloc_adminq_arq_ring - Allocate Admin Queue receive rings
+ * iavf_alloc_adminq_arq_ring - Allocate Admin Queue receive rings
* @hw: pointer to the hardware structure
**/
-static iavf_status i40e_alloc_adminq_arq_ring(struct iavf_hw *hw)
+static enum iavf_status iavf_alloc_adminq_arq_ring(struct iavf_hw *hw)
{
- iavf_status ret_code;
+ enum iavf_status ret_code;
ret_code = iavf_allocate_dma_mem(hw, &hw->aq.arq.desc_buf,
- i40e_mem_arq_ring,
+ iavf_mem_arq_ring,
(hw->aq.num_arq_entries *
- sizeof(struct i40e_aq_desc)),
+ sizeof(struct iavf_aq_desc)),
IAVF_ADMINQ_DESC_ALIGNMENT);
return ret_code;
}
/**
- * i40e_free_adminq_asq - Free Admin Queue send rings
+ * iavf_free_adminq_asq - Free Admin Queue send rings
* @hw: pointer to the hardware structure
*
* This assumes the posted send buffers have already been cleaned
* and de-allocated
**/
-static void i40e_free_adminq_asq(struct iavf_hw *hw)
+static void iavf_free_adminq_asq(struct iavf_hw *hw)
{
iavf_free_dma_mem(hw, &hw->aq.asq.desc_buf);
}
/**
- * i40e_free_adminq_arq - Free Admin Queue receive rings
+ * iavf_free_adminq_arq - Free Admin Queue receive rings
* @hw: pointer to the hardware structure
*
* This assumes the posted receive buffers have already been cleaned
* and de-allocated
**/
-static void i40e_free_adminq_arq(struct iavf_hw *hw)
+static void iavf_free_adminq_arq(struct iavf_hw *hw)
{
iavf_free_dma_mem(hw, &hw->aq.arq.desc_buf);
}
/**
- * i40e_alloc_arq_bufs - Allocate pre-posted buffers for the receive queue
+ * iavf_alloc_arq_bufs - Allocate pre-posted buffers for the receive queue
* @hw: pointer to the hardware structure
**/
-static iavf_status i40e_alloc_arq_bufs(struct iavf_hw *hw)
+static enum iavf_status iavf_alloc_arq_bufs(struct iavf_hw *hw)
{
- struct i40e_aq_desc *desc;
+ struct iavf_aq_desc *desc;
struct iavf_dma_mem *bi;
- iavf_status ret_code;
+ enum iavf_status ret_code;
int i;
/* We'll be allocating the buffer info memory first, then we can
@@ -123,7 +123,7 @@ static iavf_status i40e_alloc_arq_bufs(struct iavf_hw *hw)
for (i = 0; i < hw->aq.num_arq_entries; i++) {
bi = &hw->aq.arq.r.arq_bi[i];
ret_code = iavf_allocate_dma_mem(hw, bi,
- i40e_mem_arq_buf,
+ iavf_mem_arq_buf,
hw->aq.arq_buf_size,
IAVF_ADMINQ_DESC_ALIGNMENT);
if (ret_code)
@@ -132,9 +132,9 @@ static iavf_status i40e_alloc_arq_bufs(struct iavf_hw *hw)
/* now configure the descriptors for use */
desc = IAVF_ADMINQ_DESC(hw->aq.arq, i);
- desc->flags = cpu_to_le16(I40E_AQ_FLAG_BUF);
- if (hw->aq.arq_buf_size > I40E_AQ_LARGE_BUF)
- desc->flags |= cpu_to_le16(I40E_AQ_FLAG_LB);
+ desc->flags = cpu_to_le16(IAVF_AQ_FLAG_BUF);
+ if (hw->aq.arq_buf_size > IAVF_AQ_LARGE_BUF)
+ desc->flags |= cpu_to_le16(IAVF_AQ_FLAG_LB);
desc->opcode = 0;
/* This is in accordance with Admin queue design, there is no
* register for buffer size configuration
@@ -165,13 +165,13 @@ unwind_alloc_arq_bufs:
}
/**
- * i40e_alloc_asq_bufs - Allocate empty buffer structs for the send queue
+ * iavf_alloc_asq_bufs - Allocate empty buffer structs for the send queue
* @hw: pointer to the hardware structure
**/
-static iavf_status i40e_alloc_asq_bufs(struct iavf_hw *hw)
+static enum iavf_status iavf_alloc_asq_bufs(struct iavf_hw *hw)
{
struct iavf_dma_mem *bi;
- iavf_status ret_code;
+ enum iavf_status ret_code;
int i;
/* No mapped memory needed yet, just the buffer info structures */
@@ -186,7 +186,7 @@ static iavf_status i40e_alloc_asq_bufs(struct iavf_hw *hw)
for (i = 0; i < hw->aq.num_asq_entries; i++) {
bi = &hw->aq.asq.r.asq_bi[i];
ret_code = iavf_allocate_dma_mem(hw, bi,
- i40e_mem_asq_buf,
+ iavf_mem_asq_buf,
hw->aq.asq_buf_size,
IAVF_ADMINQ_DESC_ALIGNMENT);
if (ret_code)
@@ -206,10 +206,10 @@ unwind_alloc_asq_bufs:
}
/**
- * i40e_free_arq_bufs - Free receive queue buffer info elements
+ * iavf_free_arq_bufs - Free receive queue buffer info elements
* @hw: pointer to the hardware structure
**/
-static void i40e_free_arq_bufs(struct iavf_hw *hw)
+static void iavf_free_arq_bufs(struct iavf_hw *hw)
{
int i;
@@ -225,10 +225,10 @@ static void i40e_free_arq_bufs(struct iavf_hw *hw)
}
/**
- * i40e_free_asq_bufs - Free send queue buffer info elements
+ * iavf_free_asq_bufs - Free send queue buffer info elements
* @hw: pointer to the hardware structure
**/
-static void i40e_free_asq_bufs(struct iavf_hw *hw)
+static void iavf_free_asq_bufs(struct iavf_hw *hw)
{
int i;
@@ -248,14 +248,14 @@ static void i40e_free_asq_bufs(struct iavf_hw *hw)
}
/**
- * i40e_config_asq_regs - configure ASQ registers
+ * iavf_config_asq_regs - configure ASQ registers
* @hw: pointer to the hardware structure
*
* Configure base address and length registers for the transmit queue
**/
-static iavf_status i40e_config_asq_regs(struct iavf_hw *hw)
+static enum iavf_status iavf_config_asq_regs(struct iavf_hw *hw)
{
- iavf_status ret_code = 0;
+ enum iavf_status ret_code = 0;
u32 reg = 0;
/* Clear Head and Tail */
@@ -271,20 +271,20 @@ static iavf_status i40e_config_asq_regs(struct iavf_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 = IAVF_ERR_ADMIN_QUEUE_ERROR;
return ret_code;
}
/**
- * i40e_config_arq_regs - ARQ register configuration
+ * iavf_config_arq_regs - ARQ register configuration
* @hw: pointer to the hardware structure
*
* Configure base address and length registers for the receive (event queue)
**/
-static iavf_status i40e_config_arq_regs(struct iavf_hw *hw)
+static enum iavf_status iavf_config_arq_regs(struct iavf_hw *hw)
{
- iavf_status ret_code = 0;
+ enum iavf_status ret_code = 0;
u32 reg = 0;
/* Clear Head and Tail */
@@ -303,13 +303,13 @@ static iavf_status i40e_config_arq_regs(struct iavf_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 = IAVF_ERR_ADMIN_QUEUE_ERROR;
return ret_code;
}
/**
- * i40e_init_asq - main initialization routine for ASQ
+ * iavf_init_asq - main initialization routine for ASQ
* @hw: pointer to the hardware structure
*
* This is the main initialization routine for the Admin Send Queue
@@ -321,20 +321,20 @@ static iavf_status i40e_config_arq_regs(struct iavf_hw *hw)
* Do *NOT* hold the lock when calling this as the memory allocation routines
* called are not going to be atomic context safe
**/
-static iavf_status i40e_init_asq(struct iavf_hw *hw)
+static enum iavf_status iavf_init_asq(struct iavf_hw *hw)
{
- iavf_status ret_code = 0;
+ enum iavf_status ret_code = 0;
if (hw->aq.asq.count > 0) {
/* queue already initialized */
- ret_code = I40E_ERR_NOT_READY;
+ ret_code = IAVF_ERR_NOT_READY;
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 = IAVF_ERR_CONFIG;
goto init_adminq_exit;
}
@@ -342,17 +342,17 @@ static iavf_status i40e_init_asq(struct iavf_hw *hw)
hw->aq.asq.next_to_clean = 0;
/* allocate the ring memory */
- ret_code = i40e_alloc_adminq_asq_ring(hw);
+ ret_code = iavf_alloc_adminq_asq_ring(hw);
if (ret_code)
goto init_adminq_exit;
/* allocate buffers in the rings */
- ret_code = i40e_alloc_asq_bufs(hw);
+ ret_code = iavf_alloc_asq_bufs(hw);
if (ret_code)
goto init_adminq_free_rings;
/* initialize base registers */
- ret_code = i40e_config_asq_regs(hw);
+ ret_code = iavf_config_asq_regs(hw);
if (ret_code)
goto init_adminq_free_rings;
@@ -361,14 +361,14 @@ static iavf_status i40e_init_asq(struct iavf_hw *hw)
goto init_adminq_exit;
init_adminq_free_rings:
- i40e_free_adminq_asq(hw);
+ iavf_free_adminq_asq(hw);
init_adminq_exit:
return ret_code;
}
/**
- * i40e_init_arq - initialize ARQ
+ * iavf_init_arq - initialize ARQ
* @hw: pointer to the hardware structure
*
* The main initialization routine for the Admin Receive (Event) Queue.
@@ -380,20 +380,20 @@ init_adminq_exit:
* Do *NOT* hold the lock when calling this as the memory allocation routines
* called are not going to be atomic context safe
**/
-static iavf_status i40e_init_arq(struct iavf_hw *hw)
+static enum iavf_status iavf_init_arq(struct iavf_hw *hw)
{
- iavf_status ret_code = 0;
+ enum iavf_status ret_code = 0;
if (hw->aq.arq.count > 0) {
/* queue already initialized */
- ret_code = I40E_ERR_NOT_READY;
+ ret_code = IAVF_ERR_NOT_READY;
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 = IAVF_ERR_CONFIG;
goto init_adminq_exit;
}
@@ -401,17 +401,17 @@ static iavf_status i40e_init_arq(struct iavf_hw *hw)
hw->aq.arq.next_to_clean = 0;
/* allocate the ring memory */
- ret_code = i40e_alloc_adminq_arq_ring(hw);
+ ret_code = iavf_alloc_adminq_arq_ring(hw);
if (ret_code)
goto init_adminq_exit;
/* allocate buffers in the rings */
- ret_code = i40e_alloc_arq_bufs(hw);
+ ret_code = iavf_alloc_arq_bufs(hw);
if (ret_code)
goto init_adminq_free_rings;
/* initialize base registers */
- ret_code = i40e_config_arq_regs(hw);
+ ret_code = iavf_config_arq_regs(hw);
if (ret_code)
goto init_adminq_free_rings;
@@ -420,26 +420,26 @@ static iavf_status i40e_init_arq(struct iavf_hw *hw)
goto init_adminq_exit;
init_adminq_free_rings:
- i40e_free_adminq_arq(hw);
+ iavf_free_adminq_arq(hw);
init_adminq_exit:
return ret_code;
}
/**
- * i40e_shutdown_asq - shutdown the ASQ
+ * iavf_shutdown_asq - shutdown the ASQ
* @hw: pointer to the hardware structure
*
* The main shutdown routine for the Admin Send Queue
**/
-static iavf_status i40e_shutdown_asq(struct iavf_hw *hw)
+static enum iavf_status iavf_shutdown_asq(struct iavf_hw *hw)
{
- iavf_status ret_code = 0;
+ enum iavf_status ret_code = 0;
mutex_lock(&hw->aq.asq_mutex);
if (hw->aq.asq.count == 0) {
- ret_code = I40E_ERR_NOT_READY;
+ ret_code = IAVF_ERR_NOT_READY;
goto shutdown_asq_out;
}
@@ -453,7 +453,7 @@ static iavf_status i40e_shutdown_asq(struct iavf_hw *hw)
hw->aq.asq.count = 0; /* to indicate uninitialized queue */
/* free ring buffers */
- i40e_free_asq_bufs(hw);
+ iavf_free_asq_bufs(hw);
shutdown_asq_out:
mutex_unlock(&hw->aq.asq_mutex);
@@ -461,19 +461,19 @@ shutdown_asq_out:
}
/**
- * i40e_shutdown_arq - shutdown ARQ
+ * iavf_shutdown_arq - shutdown ARQ
* @hw: pointer to the hardware structure
*
* The main shutdown routine for the Admin Receive Queue
**/
-static iavf_status i40e_shutdown_arq(struct iavf_hw *hw)
+static enum iavf_status iavf_shutdown_arq(struct iavf_hw *hw)
{
- iavf_status ret_code = 0;
+ enum iavf_status ret_code = 0;
mutex_lock(&hw->aq.arq_mutex);
if (hw->aq.arq.count == 0) {
- ret_code = I40E_ERR_NOT_READY;
+ ret_code = IAVF_ERR_NOT_READY;
goto shutdown_arq_out;
}
@@ -487,7 +487,7 @@ static iavf_status i40e_shutdown_arq(struct iavf_hw *hw)
hw->aq.arq.count = 0; /* to indicate uninitialized queue */
/* free ring buffers */
- i40e_free_arq_bufs(hw);
+ iavf_free_arq_bufs(hw);
shutdown_arq_out:
mutex_unlock(&hw->aq.arq_mutex);
@@ -505,32 +505,32 @@ shutdown_arq_out:
* - hw->aq.arq_buf_size
* - hw->aq.asq_buf_size
**/
-iavf_status iavf_init_adminq(struct iavf_hw *hw)
+enum iavf_status iavf_init_adminq(struct iavf_hw *hw)
{
- iavf_status ret_code;
+ enum iavf_status ret_code;
/* verify input for valid configuration */
if ((hw->aq.num_arq_entries == 0) ||
(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 = IAVF_ERR_CONFIG;
goto init_adminq_exit;
}
/* Set up register offsets */
- i40e_adminq_init_regs(hw);
+ iavf_adminq_init_regs(hw);
/* setup ASQ command write back timeout */
- hw->aq.asq_cmd_timeout = I40E_ASQ_CMD_TIMEOUT;
+ hw->aq.asq_cmd_timeout = IAVF_ASQ_CMD_TIMEOUT;
/* allocate the ASQ */
- ret_code = i40e_init_asq(hw);
+ ret_code = iavf_init_asq(hw);
if (ret_code)
goto init_adminq_destroy_locks;
/* allocate the ARQ */
- ret_code = i40e_init_arq(hw);
+ ret_code = iavf_init_arq(hw);
if (ret_code)
goto init_adminq_free_asq;
@@ -538,7 +538,7 @@ iavf_status iavf_init_adminq(struct iavf_hw *hw)
goto init_adminq_exit;
init_adminq_free_asq:
- i40e_shutdown_asq(hw);
+ iavf_shutdown_asq(hw);
init_adminq_destroy_locks:
init_adminq_exit:
@@ -549,53 +549,53 @@ init_adminq_exit:
* iavf_shutdown_adminq - shutdown routine for the Admin Queue
* @hw: pointer to the hardware structure
**/
-iavf_status iavf_shutdown_adminq(struct iavf_hw *hw)
+enum iavf_status iavf_shutdown_adminq(struct iavf_hw *hw)
{
- iavf_status ret_code = 0;
+ enum iavf_status ret_code = 0;
if (iavf_check_asq_alive(hw))
iavf_aq_queue_shutdown(hw, true);
- i40e_shutdown_asq(hw);
- i40e_shutdown_arq(hw);
+ iavf_shutdown_asq(hw);
+ iavf_shutdown_arq(hw);
return ret_code;
}
/**
- * i40e_clean_asq - cleans Admin send queue
+ * iavf_clean_asq - cleans Admin send queue
* @hw: pointer to the hardware structure
*
* returns the number of free desc
**/
-static u16 i40e_clean_asq(struct iavf_hw *hw)
+static u16 iavf_clean_asq(struct iavf_hw *hw)
{
struct iavf_adminq_ring *asq = &hw->aq.asq;
- struct i40e_asq_cmd_details *details;
+ struct iavf_asq_cmd_details *details;
u16 ntc = asq->next_to_clean;
- struct i40e_aq_desc desc_cb;
- struct i40e_aq_desc *desc;
+ struct iavf_aq_desc desc_cb;
+ struct iavf_aq_desc *desc;
desc = IAVF_ADMINQ_DESC(*asq, ntc);
- details = I40E_ADMINQ_DETAILS(*asq, ntc);
+ details = IAVF_ADMINQ_DETAILS(*asq, ntc);
while (rd32(hw, hw->aq.asq.head) != ntc) {
iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE,
"ntc %d head %d.\n", ntc, rd32(hw, hw->aq.asq.head));
if (details->callback) {
- I40E_ADMINQ_CALLBACK cb_func =
- (I40E_ADMINQ_CALLBACK)details->callback;
+ IAVF_ADMINQ_CALLBACK cb_func =
+ (IAVF_ADMINQ_CALLBACK)details->callback;
desc_cb = *desc;
cb_func(hw, &desc_cb);
}
- memset((void *)desc, 0, sizeof(struct i40e_aq_desc));
+ memset((void *)desc, 0, sizeof(struct iavf_aq_desc));
memset((void *)details, 0,
- sizeof(struct i40e_asq_cmd_details));
+ sizeof(struct iavf_asq_cmd_details));
ntc++;
if (ntc == asq->count)
ntc = 0;
desc = IAVF_ADMINQ_DESC(*asq, ntc);
- details = I40E_ADMINQ_DETAILS(*asq, ntc);
+ details = IAVF_ADMINQ_DETAILS(*asq, ntc);
}
asq->next_to_clean = ntc;
@@ -629,16 +629,17 @@ bool iavf_asq_done(struct iavf_hw *hw)
* This is the main send command driver routine for the Admin Queue send
* queue. It runs the queue, cleans the queue, etc
**/
-iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc,
- void *buff, /* can be NULL */
- u16 buff_size,
- struct i40e_asq_cmd_details *cmd_details)
+enum iavf_status iavf_asq_send_command(struct iavf_hw *hw,
+ struct iavf_aq_desc *desc,
+ void *buff, /* can be NULL */
+ u16 buff_size,
+ struct iavf_asq_cmd_details *cmd_details)
{
struct iavf_dma_mem *dma_buff = NULL;
- struct i40e_asq_cmd_details *details;
- struct i40e_aq_desc *desc_on_ring;
+ struct iavf_asq_cmd_details *details;
+ struct iavf_aq_desc *desc_on_ring;
bool cmd_completed = false;
- iavf_status status = 0;
+ enum iavf_status status = 0;
u16 retval = 0;
u32 val = 0;
@@ -647,21 +648,21 @@ iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc,
if (hw->aq.asq.count == 0) {
iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE,
"AQTX: Admin queue not initialized.\n");
- status = I40E_ERR_QUEUE_EMPTY;
+ status = IAVF_ERR_QUEUE_EMPTY;
goto asq_send_command_error;
}
- hw->aq.asq_last_status = I40E_AQ_RC_OK;
+ hw->aq.asq_last_status = IAVF_AQ_RC_OK;
val = rd32(hw, hw->aq.asq.head);
if (val >= hw->aq.num_asq_entries) {
iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE,
"AQTX: head overrun at %d\n", val);
- status = I40E_ERR_QUEUE_EMPTY;
+ status = IAVF_ERR_QUEUE_EMPTY;
goto asq_send_command_error;
}
- details = I40E_ADMINQ_DETAILS(hw->aq.asq, hw->aq.asq.next_to_use);
+ details = IAVF_ADMINQ_DETAILS(hw->aq.asq, hw->aq.asq.next_to_use);
if (cmd_details) {
*details = *cmd_details;
@@ -676,7 +677,7 @@ iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc,
cpu_to_le32(lower_32_bits(details->cookie));
}
} else {
- memset(details, 0, sizeof(struct i40e_asq_cmd_details));
+ memset(details, 0, sizeof(struct iavf_asq_cmd_details));
}
/* clear requested flags and then set additional flags if defined */
@@ -688,7 +689,7 @@ iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc,
IAVF_DEBUG_AQ_MESSAGE,
"AQTX: Invalid buffer size: %d.\n",
buff_size);
- status = I40E_ERR_INVALID_SIZE;
+ status = IAVF_ERR_INVALID_SIZE;
goto asq_send_command_error;
}
@@ -696,7 +697,7 @@ iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc,
iavf_debug(hw,
IAVF_DEBUG_AQ_MESSAGE,
"AQTX: Async flag not set along with postpone flag");
- status = I40E_ERR_PARAM;
+ status = IAVF_ERR_PARAM;
goto asq_send_command_error;
}
@@ -707,11 +708,11 @@ iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc,
/* the clean function called here could be called in a separate thread
* in case of asynchronous completions
*/
- if (i40e_clean_asq(hw) == 0) {
+ if (iavf_clean_asq(hw) == 0) {
iavf_debug(hw,
IAVF_DEBUG_AQ_MESSAGE,
"AQTX: Error queue is full.\n");
- status = I40E_ERR_ADMIN_QUEUE_FULL;
+ status = IAVF_ERR_ADMIN_QUEUE_FULL;
goto asq_send_command_error;
}
@@ -780,13 +781,13 @@ iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc,
retval &= 0xff;
}
cmd_completed = true;
- if ((enum i40e_admin_queue_err)retval == I40E_AQ_RC_OK)
+ if ((enum iavf_admin_queue_err)retval == IAVF_AQ_RC_OK)
status = 0;
- else if ((enum i40e_admin_queue_err)retval == I40E_AQ_RC_EBUSY)
- status = I40E_ERR_NOT_READY;
+ else if ((enum iavf_admin_queue_err)retval == IAVF_AQ_RC_EBUSY)
+ status = IAVF_ERR_NOT_READY;
else
- status = I40E_ERR_ADMIN_QUEUE_ERROR;
- hw->aq.asq_last_status = (enum i40e_admin_queue_err)retval;
+ status = IAVF_ERR_ADMIN_QUEUE_ERROR;
+ hw->aq.asq_last_status = (enum iavf_admin_queue_err)retval;
}
iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE,
@@ -803,11 +804,11 @@ iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc,
if (rd32(hw, hw->aq.asq.len) & IAVF_VF_ATQLEN1_ATQCRIT_MASK) {
iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE,
"AQTX: AQ Critical error.\n");
- status = I40E_ERR_ADMIN_QUEUE_CRITICAL_ERROR;
+ status = IAVF_ERR_ADMIN_QUEUE_CRITICAL_ERROR;
} else {
iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE,
"AQTX: Writeback timeout.\n");
- status = I40E_ERR_ADMIN_QUEUE_TIMEOUT;
+ status = IAVF_ERR_ADMIN_QUEUE_TIMEOUT;
}
}
@@ -823,12 +824,12 @@ asq_send_command_error:
*
* Fill the desc with default values
**/
-void iavf_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc, u16 opcode)
+void iavf_fill_default_direct_cmd_desc(struct iavf_aq_desc *desc, u16 opcode)
{
/* zero out the desc */
- memset((void *)desc, 0, sizeof(struct i40e_aq_desc));
+ memset((void *)desc, 0, sizeof(struct iavf_aq_desc));
desc->opcode = cpu_to_le16(opcode);
- desc->flags = cpu_to_le16(I40E_AQ_FLAG_SI);
+ desc->flags = cpu_to_le16(IAVF_AQ_FLAG_SI);
}
/**
@@ -841,13 +842,13 @@ void iavf_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc, u16 opcode)
* the contents through e. It can also return how many events are
* left to process through 'pending'
**/
-iavf_status iavf_clean_arq_element(struct iavf_hw *hw,
- struct i40e_arq_event_info *e,
- u16 *pending)
+enum iavf_status iavf_clean_arq_element(struct iavf_hw *hw,
+ struct iavf_arq_event_info *e,
+ u16 *pending)
{
u16 ntc = hw->aq.arq.next_to_clean;
- struct i40e_aq_desc *desc;
- iavf_status ret_code = 0;
+ struct iavf_aq_desc *desc;
+ enum iavf_status ret_code = 0;
struct iavf_dma_mem *bi;
u16 desc_idx;
u16 datalen;
@@ -863,7 +864,7 @@ iavf_status iavf_clean_arq_element(struct iavf_hw *hw,
if (hw->aq.arq.count == 0) {
iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE,
"AQRX: Admin queue not initialized.\n");
- ret_code = I40E_ERR_QUEUE_EMPTY;
+ ret_code = IAVF_ERR_QUEUE_EMPTY;
goto clean_arq_element_err;
}
@@ -871,7 +872,7 @@ iavf_status iavf_clean_arq_element(struct iavf_hw *hw,
ntu = rd32(hw, hw->aq.arq.head) & IAVF_VF_ARQH1_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 = IAVF_ERR_ADMIN_QUEUE_NO_WORK;
goto clean_arq_element_out;
}
@@ -880,10 +881,10 @@ iavf_status iavf_clean_arq_element(struct iavf_hw *hw,
desc_idx = ntc;
hw->aq.arq_last_status =
- (enum i40e_admin_queue_err)le16_to_cpu(desc->retval);
+ (enum iavf_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;
+ if (flags & IAVF_AQ_FLAG_ERR) {
+ ret_code = IAVF_ERR_ADMIN_QUEUE_ERROR;
iavf_debug(hw,
IAVF_DEBUG_AQ_MESSAGE,
"AQRX: Event received with error 0x%X.\n",
@@ -906,11 +907,11 @@ iavf_status iavf_clean_arq_element(struct iavf_hw *hw,
* size
*/
bi = &hw->aq.arq.r.arq_bi[ntc];
- memset((void *)desc, 0, sizeof(struct i40e_aq_desc));
+ memset((void *)desc, 0, sizeof(struct iavf_aq_desc));
- desc->flags = cpu_to_le16(I40E_AQ_FLAG_BUF);
- if (hw->aq.arq_buf_size > I40E_AQ_LARGE_BUF)
- desc->flags |= cpu_to_le16(I40E_AQ_FLAG_LB);
+ desc->flags = cpu_to_le16(IAVF_AQ_FLAG_BUF);
+ if (hw->aq.arq_buf_size > IAVF_AQ_LARGE_BUF)
+ desc->flags |= cpu_to_le16(IAVF_AQ_FLAG_LB);
desc->datalen = cpu_to_le16((u16)bi->size);
desc->params.external.addr_high = cpu_to_le32(upper_32_bits(bi->pa));
desc->params.external.addr_low = cpu_to_le32(lower_32_bits(bi->pa));
diff --git a/drivers/net/ethernet/intel/iavf/i40e_adminq.h b/drivers/net/ethernet/intel/iavf/iavf_adminq.h
index ee983889eab0..baf2fe26f302 100644
--- a/drivers/net/ethernet/intel/iavf/i40e_adminq.h
+++ b/drivers/net/ethernet/intel/iavf/iavf_adminq.h
@@ -6,10 +6,10 @@
#include "iavf_osdep.h"
#include "iavf_status.h"
-#include "i40e_adminq_cmd.h"
+#include "iavf_adminq_cmd.h"
#define IAVF_ADMINQ_DESC(R, i) \
- (&(((struct i40e_aq_desc *)((R).desc_buf.va))[i]))
+ (&(((struct iavf_aq_desc *)((R).desc_buf.va))[i]))
#define IAVF_ADMINQ_DESC_ALIGNMENT 4096
@@ -39,22 +39,22 @@ struct iavf_adminq_ring {
};
/* ASQ transaction details */
-struct i40e_asq_cmd_details {
- void *callback; /* cast from type I40E_ADMINQ_CALLBACK */
+struct iavf_asq_cmd_details {
+ void *callback; /* cast from type IAVF_ADMINQ_CALLBACK */
u64 cookie;
u16 flags_ena;
u16 flags_dis;
bool async;
bool postpone;
- struct i40e_aq_desc *wb_desc;
+ struct iavf_aq_desc *wb_desc;
};
-#define I40E_ADMINQ_DETAILS(R, i) \
- (&(((struct i40e_asq_cmd_details *)((R).cmd_buf.va))[i]))
+#define IAVF_ADMINQ_DETAILS(R, i) \
+ (&(((struct iavf_asq_cmd_details *)((R).cmd_buf.va))[i]))
/* ARQ event information */
-struct i40e_arq_event_info {
- struct i40e_aq_desc desc;
+struct iavf_arq_event_info {
+ struct iavf_aq_desc desc;
u16 msg_len;
u16 buf_len;
u8 *msg_buf;
@@ -79,45 +79,45 @@ struct iavf_adminq_info {
struct mutex arq_mutex; /* Receive queue lock */
/* last status values on send and receive queues */
- enum i40e_admin_queue_err asq_last_status;
- enum i40e_admin_queue_err arq_last_status;
+ enum iavf_admin_queue_err asq_last_status;
+ enum iavf_admin_queue_err arq_last_status;
};
/**
- * i40e_aq_rc_to_posix - convert errors to user-land codes
+ * iavf_aq_rc_to_posix - convert errors to user-land codes
* aq_ret: AdminQ handler error code can override aq_rc
* aq_rc: AdminQ firmware error code to convert
**/
-static inline int i40e_aq_rc_to_posix(int aq_ret, int aq_rc)
+static inline int iavf_aq_rc_to_posix(int aq_ret, int aq_rc)
{
int aq_to_posix[] = {
- 0, /* I40E_AQ_RC_OK */
- -EPERM, /* I40E_AQ_RC_EPERM */
- -ENOENT, /* I40E_AQ_RC_ENOENT */
- -ESRCH, /* I40E_AQ_RC_ESRCH */
- -EINTR, /* I40E_AQ_RC_EINTR */
- -EIO, /* I40E_AQ_RC_EIO */
- -ENXIO, /* I40E_AQ_RC_ENXIO */
- -E2BIG, /* I40E_AQ_RC_E2BIG */
- -EAGAIN, /* I40E_AQ_RC_EAGAIN */
- -ENOMEM, /* I40E_AQ_RC_ENOMEM */
- -EACCES, /* I40E_AQ_RC_EACCES */
- -EFAULT, /* I40E_AQ_RC_EFAULT */
- -EBUSY, /* I40E_AQ_RC_EBUSY */
- -EEXIST, /* I40E_AQ_RC_EEXIST */
- -EINVAL, /* I40E_AQ_RC_EINVAL */
- -ENOTTY, /* I40E_AQ_RC_ENOTTY */
- -ENOSPC, /* I40E_AQ_RC_ENOSPC */
- -ENOSYS, /* I40E_AQ_RC_ENOSYS */
- -ERANGE, /* I40E_AQ_RC_ERANGE */
- -EPIPE, /* I40E_AQ_RC_EFLUSHED */
- -ESPIPE, /* I40E_AQ_RC_BAD_ADDR */
- -EROFS, /* I40E_AQ_RC_EMODE */
- -EFBIG, /* I40E_AQ_RC_EFBIG */
+ 0, /* IAVF_AQ_RC_OK */
+ -EPERM, /* IAVF_AQ_RC_EPERM */
+ -ENOENT, /* IAVF_AQ_RC_ENOENT */
+ -ESRCH, /* IAVF_AQ_RC_ESRCH */
+ -EINTR, /* IAVF_AQ_RC_EINTR */
+ -EIO, /* IAVF_AQ_RC_EIO */
+ -ENXIO, /* IAVF_AQ_RC_ENXIO */
+ -E2BIG, /* IAVF_AQ_RC_E2BIG */
+ -EAGAIN, /* IAVF_AQ_RC_EAGAIN */
+ -ENOMEM, /* IAVF_AQ_RC_ENOMEM */
+ -EACCES, /* IAVF_AQ_RC_EACCES */
+ -EFAULT, /* IAVF_AQ_RC_EFAULT */
+ -EBUSY, /* IAVF_AQ_RC_EBUSY */
+ -EEXIST, /* IAVF_AQ_RC_EEXIST */
+ -EINVAL, /* IAVF_AQ_RC_EINVAL */
+ -ENOTTY, /* IAVF_AQ_RC_ENOTTY */
+ -ENOSPC, /* IAVF_AQ_RC_ENOSPC */
+ -ENOSYS, /* IAVF_AQ_RC_ENOSYS */
+ -ERANGE, /* IAVF_AQ_RC_ERANGE */
+ -EPIPE, /* IAVF_AQ_RC_EFLUSHED */
+ -ESPIPE, /* IAVF_AQ_RC_BAD_ADDR */
+ -EROFS, /* IAVF_AQ_RC_EMODE */
+ -EFBIG, /* IAVF_AQ_RC_EFBIG */
};
/* aq_rc is invalid if AQ timed out */
- if (aq_ret == I40E_ERR_ADMIN_QUEUE_TIMEOUT)
+ if (aq_ret == IAVF_ERR_ADMIN_QUEUE_TIMEOUT)
return -EAGAIN;
if (!((u32)aq_rc < (sizeof(aq_to_posix) / sizeof((aq_to_posix)[0]))))
@@ -127,9 +127,9 @@ static inline int i40e_aq_rc_to_posix(int aq_ret, int aq_rc)
}
/* general information */
-#define I40E_AQ_LARGE_BUF 512
-#define I40E_ASQ_CMD_TIMEOUT 250000 /* usecs */
+#define IAVF_AQ_LARGE_BUF 512
+#define IAVF_ASQ_CMD_TIMEOUT 250000 /* usecs */
-void iavf_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc, u16 opcode);
+void iavf_fill_default_direct_cmd_desc(struct iavf_aq_desc *desc, u16 opcode);
#endif /* _IAVF_ADMINQ_H_ */
diff --git a/drivers/net/ethernet/intel/iavf/iavf_adminq_cmd.h b/drivers/net/ethernet/intel/iavf/iavf_adminq_cmd.h
new file mode 100644
index 000000000000..bc512308557b
--- /dev/null
+++ b/drivers/net/ethernet/intel/iavf/iavf_adminq_cmd.h
@@ -0,0 +1,528 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
+
+#ifndef _IAVF_ADMINQ_CMD_H_
+#define _IAVF_ADMINQ_CMD_H_
+
+/* This header file defines the iavf Admin Queue commands and is shared between
+ * iavf Firmware and Software.
+ *
+ * This file needs to comply with the Linux Kernel coding style.
+ */
+
+#define IAVF_FW_API_VERSION_MAJOR 0x0001
+#define IAVF_FW_API_VERSION_MINOR_X722 0x0005
+#define IAVF_FW_API_VERSION_MINOR_X710 0x0008
+
+#define IAVF_FW_MINOR_VERSION(_h) ((_h)->mac.type == IAVF_MAC_XL710 ? \
+ IAVF_FW_API_VERSION_MINOR_X710 : \
+ IAVF_FW_API_VERSION_MINOR_X722)
+
+/* API version 1.7 implements additional link and PHY-specific APIs */
+#define IAVF_MINOR_VER_GET_LINK_INFO_XL710 0x0007
+
+struct iavf_aq_desc {
+ __le16 flags;
+ __le16 opcode;
+ __le16 datalen;
+ __le16 retval;
+ __le32 cookie_high;
+ __le32 cookie_low;
+ union {
+ struct {
+ __le32 param0;
+ __le32 param1;
+ __le32 param2;
+ __le32 param3;
+ } internal;
+ struct {
+ __le32 param0;
+ __le32 param1;
+ __le32 addr_high;
+ __le32 addr_low;
+ } external;
+ u8 raw[16];
+ } params;
+};
+
+/* Flags sub-structure
+ * |0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |10 |11 |12 |13 |14 |15 |
+ * |DD |CMP|ERR|VFE| * * RESERVED * * |LB |RD |VFC|BUF|SI |EI |FE |
+ */
+
+/* command flags and offsets*/
+#define IAVF_AQ_FLAG_DD_SHIFT 0
+#define IAVF_AQ_FLAG_CMP_SHIFT 1
+#define IAVF_AQ_FLAG_ERR_SHIFT 2
+#define IAVF_AQ_FLAG_VFE_SHIFT 3
+#define IAVF_AQ_FLAG_LB_SHIFT 9
+#define IAVF_AQ_FLAG_RD_SHIFT 10
+#define IAVF_AQ_FLAG_VFC_SHIFT 11
+#define IAVF_AQ_FLAG_BUF_SHIFT 12
+#define IAVF_AQ_FLAG_SI_SHIFT 13
+#define IAVF_AQ_FLAG_EI_SHIFT 14
+#define IAVF_AQ_FLAG_FE_SHIFT 15
+
+#define IAVF_AQ_FLAG_DD BIT(IAVF_AQ_FLAG_DD_SHIFT) /* 0x1 */
+#define IAVF_AQ_FLAG_CMP BIT(IAVF_AQ_FLAG_CMP_SHIFT) /* 0x2 */
+#define IAVF_AQ_FLAG_ERR BIT(IAVF_AQ_FLAG_ERR_SHIFT) /* 0x4 */
+#define IAVF_AQ_FLAG_VFE BIT(IAVF_AQ_FLAG_VFE_SHIFT) /* 0x8 */
+#define IAVF_AQ_FLAG_LB BIT(IAVF_AQ_FLAG_LB_SHIFT) /* 0x200 */
+#define IAVF_AQ_FLAG_RD BIT(IAVF_AQ_FLAG_RD_SHIFT) /* 0x400 */
+#define IAVF_AQ_FLAG_VFC BIT(IAVF_AQ_FLAG_VFC_SHIFT) /* 0x800 */
+#define IAVF_AQ_FLAG_BUF BIT(IAVF_AQ_FLAG_BUF_SHIFT) /* 0x1000 */
+#define IAVF_AQ_FLAG_SI BIT(IAVF_AQ_FLAG_SI_SHIFT) /* 0x2000 */
+#define IAVF_AQ_FLAG_EI BIT(IAVF_AQ_FLAG_EI_SHIFT) /* 0x4000 */
+#define IAVF_AQ_FLAG_FE BIT(IAVF_AQ_FLAG_FE_SHIFT) /* 0x8000 */
+
+/* error codes */
+enum iavf_admin_queue_err {
+ IAVF_AQ_RC_OK = 0, /* success */
+ IAVF_AQ_RC_EPERM = 1, /* Operation not permitted */
+ IAVF_AQ_RC_ENOENT = 2, /* No such element */
+ IAVF_AQ_RC_ESRCH = 3, /* Bad opcode */
+ IAVF_AQ_RC_EINTR = 4, /* operation interrupted */
+ IAVF_AQ_RC_EIO = 5, /* I/O error */
+ IAVF_AQ_RC_ENXIO = 6, /* No such resource */
+ IAVF_AQ_RC_E2BIG = 7, /* Arg too long */
+ IAVF_AQ_RC_EAGAIN = 8, /* Try again */
+ IAVF_AQ_RC_ENOMEM = 9, /* Out of memory */
+ IAVF_AQ_RC_EACCES = 10, /* Permission denied */
+ IAVF_AQ_RC_EFAULT = 11, /* Bad address */
+ IAVF_AQ_RC_EBUSY = 12, /* Device or resource busy */
+ IAVF_AQ_RC_EEXIST = 13, /* object already exists */
+ IAVF_AQ_RC_EINVAL = 14, /* Invalid argument */
+ IAVF_AQ_RC_ENOTTY = 15, /* Not a typewriter */
+ IAVF_AQ_RC_ENOSPC = 16, /* No space left or alloc failure */
+ IAVF_AQ_RC_ENOSYS = 17, /* Function not implemented */
+ IAVF_AQ_RC_ERANGE = 18, /* Parameter out of range */
+ IAVF_AQ_RC_EFLUSHED = 19, /* Cmd flushed due to prev cmd error */
+ IAVF_AQ_RC_BAD_ADDR = 20, /* Descriptor contains a bad pointer */
+ IAVF_AQ_RC_EMODE = 21, /* Op not allowed in current dev mode */
+ IAVF_AQ_RC_EFBIG = 22, /* File too large */
+};
+
+/* Admin Queue command opcodes */
+enum iavf_admin_queue_opc {
+ /* aq commands */
+ iavf_aqc_opc_get_version = 0x0001,
+ iavf_aqc_opc_driver_version = 0x0002,
+ iavf_aqc_opc_queue_shutdown = 0x0003,
+ iavf_aqc_opc_set_pf_context = 0x0004,
+
+ /* resource ownership */
+ iavf_aqc_opc_request_resource = 0x0008,
+ iavf_aqc_opc_release_resource = 0x0009,
+
+ iavf_aqc_opc_list_func_capabilities = 0x000A,
+ iavf_aqc_opc_list_dev_capabilities = 0x000B,
+
+ /* Proxy commands */
+ iavf_aqc_opc_set_proxy_config = 0x0104,
+ iavf_aqc_opc_set_ns_proxy_table_entry = 0x0105,
+
+ /* LAA */
+ iavf_aqc_opc_mac_address_read = 0x0107,
+ iavf_aqc_opc_mac_address_write = 0x0108,
+
+ /* PXE */
+ iavf_aqc_opc_clear_pxe_mode = 0x0110,
+
+ /* WoL commands */
+ iavf_aqc_opc_set_wol_filter = 0x0120,
+ iavf_aqc_opc_get_wake_reason = 0x0121,
+
+ /* internal switch commands */
+ iavf_aqc_opc_get_switch_config = 0x0200,
+ iavf_aqc_opc_add_statistics = 0x0201,
+ iavf_aqc_opc_remove_statistics = 0x0202,
+ iavf_aqc_opc_set_port_parameters = 0x0203,
+ iavf_aqc_opc_get_switch_resource_alloc = 0x0204,
+ iavf_aqc_opc_set_switch_config = 0x0205,
+ iavf_aqc_opc_rx_ctl_reg_read = 0x0206,
+ iavf_aqc_opc_rx_ctl_reg_write = 0x0207,
+
+ iavf_aqc_opc_add_vsi = 0x0210,
+ iavf_aqc_opc_update_vsi_parameters = 0x0211,
+ iavf_aqc_opc_get_vsi_parameters = 0x0212,
+
+ iavf_aqc_opc_add_pv = 0x0220,
+ iavf_aqc_opc_update_pv_parameters = 0x0221,
+ iavf_aqc_opc_get_pv_parameters = 0x0222,
+
+ iavf_aqc_opc_add_veb = 0x0230,
+ iavf_aqc_opc_update_veb_parameters = 0x0231,
+ iavf_aqc_opc_get_veb_parameters = 0x0232,
+
+ iavf_aqc_opc_delete_element = 0x0243,
+
+ iavf_aqc_opc_add_macvlan = 0x0250,
+ iavf_aqc_opc_remove_macvlan = 0x0251,
+ iavf_aqc_opc_add_vlan = 0x0252,
+ iavf_aqc_opc_remove_vlan = 0x0253,
+ iavf_aqc_opc_set_vsi_promiscuous_modes = 0x0254,
+ iavf_aqc_opc_add_tag = 0x0255,
+ iavf_aqc_opc_remove_tag = 0x0256,
+ iavf_aqc_opc_add_multicast_etag = 0x0257,
+ iavf_aqc_opc_remove_multicast_etag = 0x0258,
+ iavf_aqc_opc_update_tag = 0x0259,
+ iavf_aqc_opc_add_control_packet_filter = 0x025A,
+ iavf_aqc_opc_remove_control_packet_filter = 0x025B,
+ iavf_aqc_opc_add_cloud_filters = 0x025C,
+ iavf_aqc_opc_remove_cloud_filters = 0x025D,
+ iavf_aqc_opc_clear_wol_switch_filters = 0x025E,
+
+ iavf_aqc_opc_add_mirror_rule = 0x0260,
+ iavf_aqc_opc_delete_mirror_rule = 0x0261,
+
+ /* Dynamic Device Personalization */
+ iavf_aqc_opc_write_personalization_profile = 0x0270,
+ iavf_aqc_opc_get_personalization_profile_list = 0x0271,
+
+ /* DCB commands */
+ iavf_aqc_opc_dcb_ignore_pfc = 0x0301,
+ iavf_aqc_opc_dcb_updated = 0x0302,
+ iavf_aqc_opc_set_dcb_parameters = 0x0303,
+
+ /* TX scheduler */
+ iavf_aqc_opc_configure_vsi_bw_limit = 0x0400,
+ iavf_aqc_opc_configure_vsi_ets_sla_bw_limit = 0x0406,
+ iavf_aqc_opc_configure_vsi_tc_bw = 0x0407,
+ iavf_aqc_opc_query_vsi_bw_config = 0x0408,
+ iavf_aqc_opc_query_vsi_ets_sla_config = 0x040A,
+ iavf_aqc_opc_configure_switching_comp_bw_limit = 0x0410,
+
+ iavf_aqc_opc_enable_switching_comp_ets = 0x0413,
+ iavf_aqc_opc_modify_switching_comp_ets = 0x0414,
+ iavf_aqc_opc_disable_switching_comp_ets = 0x0415,
+ iavf_aqc_opc_configure_switching_comp_ets_bw_limit = 0x0416,
+ iavf_aqc_opc_configure_switching_comp_bw_config = 0x0417,
+ iavf_aqc_opc_query_switching_comp_ets_config = 0x0418,
+ iavf_aqc_opc_query_port_ets_config = 0x0419,
+ iavf_aqc_opc_query_switching_comp_bw_config = 0x041A,
+ iavf_aqc_opc_suspend_port_tx = 0x041B,
+ iavf_aqc_opc_resume_port_tx = 0x041C,
+ iavf_aqc_opc_configure_partition_bw = 0x041D,
+ /* hmc */
+ iavf_aqc_opc_query_hmc_resource_profile = 0x0500,
+ iavf_aqc_opc_set_hmc_resource_profile = 0x0501,
+
+ /* phy commands*/
+ iavf_aqc_opc_get_phy_abilities = 0x0600,
+ iavf_aqc_opc_set_phy_config = 0x0601,
+ iavf_aqc_opc_set_mac_config = 0x0603,
+ iavf_aqc_opc_set_link_restart_an = 0x0605,
+ iavf_aqc_opc_get_link_status = 0x0607,
+ iavf_aqc_opc_set_phy_int_mask = 0x0613,
+ iavf_aqc_opc_get_local_advt_reg = 0x0614,
+ iavf_aqc_opc_set_local_advt_reg = 0x0615,
+ iavf_aqc_opc_get_partner_advt = 0x0616,
+ iavf_aqc_opc_set_lb_modes = 0x0618,
+ iavf_aqc_opc_get_phy_wol_caps = 0x0621,
+ iavf_aqc_opc_set_phy_debug = 0x0622,
+ iavf_aqc_opc_upload_ext_phy_fm = 0x0625,
+ iavf_aqc_opc_run_phy_activity = 0x0626,
+ iavf_aqc_opc_set_phy_register = 0x0628,
+ iavf_aqc_opc_get_phy_register = 0x0629,
+
+ /* NVM commands */
+ iavf_aqc_opc_nvm_read = 0x0701,
+ iavf_aqc_opc_nvm_erase = 0x0702,
+ iavf_aqc_opc_nvm_update = 0x0703,
+ iavf_aqc_opc_nvm_config_read = 0x0704,
+ iavf_aqc_opc_nvm_config_write = 0x0705,
+ iavf_aqc_opc_oem_post_update = 0x0720,
+ iavf_aqc_opc_thermal_sensor = 0x0721,
+
+ /* virtualization commands */
+ iavf_aqc_opc_send_msg_to_pf = 0x0801,
+ iavf_aqc_opc_send_msg_to_vf = 0x0802,
+ iavf_aqc_opc_send_msg_to_peer = 0x0803,
+
+ /* alternate structure */
+ iavf_aqc_opc_alternate_write = 0x0900,
+ iavf_aqc_opc_alternate_write_indirect = 0x0901,
+ iavf_aqc_opc_alternate_read = 0x0902,
+ iavf_aqc_opc_alternate_read_indirect = 0x0903,
+ iavf_aqc_opc_alternate_write_done = 0x0904,
+ iavf_aqc_opc_alternate_set_mode = 0x0905,
+ iavf_aqc_opc_alternate_clear_port = 0x0906,
+
+ /* LLDP commands */
+ iavf_aqc_opc_lldp_get_mib = 0x0A00,
+ iavf_aqc_opc_lldp_update_mib = 0x0A01,
+ iavf_aqc_opc_lldp_add_tlv = 0x0A02,
+ iavf_aqc_opc_lldp_update_tlv = 0x0A03,
+ iavf_aqc_opc_lldp_delete_tlv = 0x0A04,
+ iavf_aqc_opc_lldp_stop = 0x0A05,
+ iavf_aqc_opc_lldp_start = 0x0A06,
+
+ /* Tunnel commands */
+ iavf_aqc_opc_add_udp_tunnel = 0x0B00,
+ iavf_aqc_opc_del_udp_tunnel = 0x0B01,
+ iavf_aqc_opc_set_rss_key = 0x0B02,
+ iavf_aqc_opc_set_rss_lut = 0x0B03,
+ iavf_aqc_opc_get_rss_key = 0x0B04,
+ iavf_aqc_opc_get_rss_lut = 0x0B05,
+
+ /* Async Events */
+ iavf_aqc_opc_event_lan_overflow = 0x1001,
+
+ /* OEM commands */
+ iavf_aqc_opc_oem_parameter_change = 0xFE00,
+ iavf_aqc_opc_oem_device_status_change = 0xFE01,
+ iavf_aqc_opc_oem_ocsd_initialize = 0xFE02,
+ iavf_aqc_opc_oem_ocbb_initialize = 0xFE03,
+
+ /* debug commands */
+ iavf_aqc_opc_debug_read_reg = 0xFF03,
+ iavf_aqc_opc_debug_write_reg = 0xFF04,
+ iavf_aqc_opc_debug_modify_reg = 0xFF07,
+ iavf_aqc_opc_debug_dump_internals = 0xFF08,
+};
+
+/* command structures and indirect data structures */
+
+/* Structure naming conventions:
+ * - no suffix for direct command descriptor structures
+ * - _data for indirect sent data
+ * - _resp for indirect return data (data which is both will use _data)
+ * - _completion for direct return data
+ * - _element_ for repeated elements (may also be _data or _resp)
+ *
+ * Command structures are expected to overlay the params.raw member of the basic
+ * descriptor, and as such cannot exceed 16 bytes in length.
+ */
+
+/* This macro is used to generate a compilation error if a structure
+ * is not exactly the correct length. It gives a divide by zero error if the
+ * structure is not of the correct size, otherwise it creates an enum that is
+ * never used.
+ */
+#define IAVF_CHECK_STRUCT_LEN(n, X) enum iavf_static_assert_enum_##X \
+ { iavf_static_assert_##X = (n) / ((sizeof(struct X) == (n)) ? 1 : 0) }
+
+/* This macro is used extensively to ensure that command structures are 16
+ * bytes in length as they have to map to the raw array of that size.
+ */
+#define IAVF_CHECK_CMD_LENGTH(X) IAVF_CHECK_STRUCT_LEN(16, X)
+
+/* Queue Shutdown (direct 0x0003) */
+struct iavf_aqc_queue_shutdown {
+ __le32 driver_unloading;
+#define IAVF_AQ_DRIVER_UNLOADING 0x1
+ u8 reserved[12];
+};
+
+IAVF_CHECK_CMD_LENGTH(iavf_aqc_queue_shutdown);
+
+struct iavf_aqc_vsi_properties_data {
+ /* first 96 byte are written by SW */
+ __le16 valid_sections;
+#define IAVF_AQ_VSI_PROP_SWITCH_VALID 0x0001
+#define IAVF_AQ_VSI_PROP_SECURITY_VALID 0x0002
+#define IAVF_AQ_VSI_PROP_VLAN_VALID 0x0004
+#define IAVF_AQ_VSI_PROP_CAS_PV_VALID 0x0008
+#define IAVF_AQ_VSI_PROP_INGRESS_UP_VALID 0x0010
+#define IAVF_AQ_VSI_PROP_EGRESS_UP_VALID 0x0020
+#define IAVF_AQ_VSI_PROP_QUEUE_MAP_VALID 0x0040
+#define IAVF_AQ_VSI_PROP_QUEUE_OPT_VALID 0x0080
+#define IAVF_AQ_VSI_PROP_OUTER_UP_VALID 0x0100
+#define IAVF_AQ_VSI_PROP_SCHED_VALID 0x0200
+ /* switch section */
+ __le16 switch_id; /* 12bit id combined with flags below */
+#define IAVF_AQ_VSI_SW_ID_SHIFT 0x0000
+#define IAVF_AQ_VSI_SW_ID_MASK (0xFFF << IAVF_AQ_VSI_SW_ID_SHIFT)
+#define IAVF_AQ_VSI_SW_ID_FLAG_NOT_STAG 0x1000
+#define IAVF_AQ_VSI_SW_ID_FLAG_ALLOW_LB 0x2000
+#define IAVF_AQ_VSI_SW_ID_FLAG_LOCAL_LB 0x4000
+ u8 sw_reserved[2];
+ /* security section */
+ u8 sec_flags;
+#define IAVF_AQ_VSI_SEC_FLAG_ALLOW_DEST_OVRD 0x01
+#define IAVF_AQ_VSI_SEC_FLAG_ENABLE_VLAN_CHK 0x02
+#define IAVF_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK 0x04
+ u8 sec_reserved;
+ /* VLAN section */
+ __le16 pvid; /* VLANS include priority bits */
+ __le16 fcoe_pvid;
+ u8 port_vlan_flags;
+#define IAVF_AQ_VSI_PVLAN_MODE_SHIFT 0x00
+#define IAVF_AQ_VSI_PVLAN_MODE_MASK (0x03 << \
+ IAVF_AQ_VSI_PVLAN_MODE_SHIFT)
+#define IAVF_AQ_VSI_PVLAN_MODE_TAGGED 0x01
+#define IAVF_AQ_VSI_PVLAN_MODE_UNTAGGED 0x02
+#define IAVF_AQ_VSI_PVLAN_MODE_ALL 0x03
+#define IAVF_AQ_VSI_PVLAN_INSERT_PVID 0x04
+#define IAVF_AQ_VSI_PVLAN_EMOD_SHIFT 0x03
+#define IAVF_AQ_VSI_PVLAN_EMOD_MASK (0x3 << \
+ IAVF_AQ_VSI_PVLAN_EMOD_SHIFT)
+#define IAVF_AQ_VSI_PVLAN_EMOD_STR_BOTH 0x0
+#define IAVF_AQ_VSI_PVLAN_EMOD_STR_UP 0x08
+#define IAVF_AQ_VSI_PVLAN_EMOD_STR 0x10
+#define IAVF_AQ_VSI_PVLAN_EMOD_NOTHING 0x18
+ u8 pvlan_reserved[3];
+ /* ingress egress up sections */
+ __le32 ingress_table; /* bitmap, 3 bits per up */
+#define IAVF_AQ_VSI_UP_TABLE_UP0_SHIFT 0
+#define IAVF_AQ_VSI_UP_TABLE_UP0_MASK (0x7 << \
+ IAVF_AQ_VSI_UP_TABLE_UP0_SHIFT)
+#define IAVF_AQ_VSI_UP_TABLE_UP1_SHIFT 3
+#define IAVF_AQ_VSI_UP_TABLE_UP1_MASK (0x7 << \
+ IAVF_AQ_VSI_UP_TABLE_UP1_SHIFT)
+#define IAVF_AQ_VSI_UP_TABLE_UP2_SHIFT 6
+#define IAVF_AQ_VSI_UP_TABLE_UP2_MASK (0x7 << \
+ IAVF_AQ_VSI_UP_TABLE_UP2_SHIFT)
+#define IAVF_AQ_VSI_UP_TABLE_UP3_SHIFT 9
+#define IAVF_AQ_VSI_UP_TABLE_UP3_MASK (0x7 << \
+ IAVF_AQ_VSI_UP_TABLE_UP3_SHIFT)
+#define IAVF_AQ_VSI_UP_TABLE_UP4_SHIFT 12
+#define IAVF_AQ_VSI_UP_TABLE_UP4_MASK (0x7 << \
+ IAVF_AQ_VSI_UP_TABLE_UP4_SHIFT)
+#define IAVF_AQ_VSI_UP_TABLE_UP5_SHIFT 15
+#define IAVF_AQ_VSI_UP_TABLE_UP5_MASK (0x7 << \
+ IAVF_AQ_VSI_UP_TABLE_UP5_SHIFT)
+#define IAVF_AQ_VSI_UP_TABLE_UP6_SHIFT 18
+#define IAVF_AQ_VSI_UP_TABLE_UP6_MASK (0x7 << \
+ IAVF_AQ_VSI_UP_TABLE_UP6_SHIFT)
+#define IAVF_AQ_VSI_UP_TABLE_UP7_SHIFT 21
+#define IAVF_AQ_VSI_UP_TABLE_UP7_MASK (0x7 << \
+ IAVF_AQ_VSI_UP_TABLE_UP7_SHIFT)
+ __le32 egress_table; /* same defines as for ingress table */
+ /* cascaded PV section */
+ __le16 cas_pv_tag;
+ u8 cas_pv_flags;
+#define IAVF_AQ_VSI_CAS_PV_TAGX_SHIFT 0x00
+#define IAVF_AQ_VSI_CAS_PV_TAGX_MASK (0x03 << \
+ IAVF_AQ_VSI_CAS_PV_TAGX_SHIFT)
+#define IAVF_AQ_VSI_CAS_PV_TAGX_LEAVE 0x00
+#define IAVF_AQ_VSI_CAS_PV_TAGX_REMOVE 0x01
+#define IAVF_AQ_VSI_CAS_PV_TAGX_COPY 0x02
+#define IAVF_AQ_VSI_CAS_PV_INSERT_TAG 0x10
+#define IAVF_AQ_VSI_CAS_PV_ETAG_PRUNE 0x20
+#define IAVF_AQ_VSI_CAS_PV_ACCEPT_HOST_TAG 0x40
+ u8 cas_pv_reserved;
+ /* queue mapping section */
+ __le16 mapping_flags;
+#define IAVF_AQ_VSI_QUE_MAP_CONTIG 0x0
+#define IAVF_AQ_VSI_QUE_MAP_NONCONTIG 0x1
+ __le16 queue_mapping[16];
+#define IAVF_AQ_VSI_QUEUE_SHIFT 0x0
+#define IAVF_AQ_VSI_QUEUE_MASK (0x7FF << IAVF_AQ_VSI_QUEUE_SHIFT)
+ __le16 tc_mapping[8];
+#define IAVF_AQ_VSI_TC_QUE_OFFSET_SHIFT 0
+#define IAVF_AQ_VSI_TC_QUE_OFFSET_MASK (0x1FF << \
+ IAVF_AQ_VSI_TC_QUE_OFFSET_SHIFT)
+#define IAVF_AQ_VSI_TC_QUE_NUMBER_SHIFT 9
+#define IAVF_AQ_VSI_TC_QUE_NUMBER_MASK (0x7 << \
+ IAVF_AQ_VSI_TC_QUE_NUMBER_SHIFT)
+ /* queueing option section */
+ u8 queueing_opt_flags;
+#define IAVF_AQ_VSI_QUE_OPT_MULTICAST_UDP_ENA 0x04
+#define IAVF_AQ_VSI_QUE_OPT_UNICAST_UDP_ENA 0x08
+#define IAVF_AQ_VSI_QUE_OPT_TCP_ENA 0x10
+#define IAVF_AQ_VSI_QUE_OPT_FCOE_ENA 0x20
+#define IAVF_AQ_VSI_QUE_OPT_RSS_LUT_PF 0x00
+#define IAVF_AQ_VSI_QUE_OPT_RSS_LUT_VSI 0x40
+ u8 queueing_opt_reserved[3];
+ /* scheduler section */
+ u8 up_enable_bits;
+ u8 sched_reserved;
+ /* outer up section */
+ __le32 outer_up_table; /* same structure and defines as ingress tbl */
+ u8 cmd_reserved[8];
+ /* last 32 bytes are written by FW */
+ __le16 qs_handle[8];
+#define IAVF_AQ_VSI_QS_HANDLE_INVALID 0xFFFF
+ __le16 stat_counter_idx;
+ __le16 sched_id;
+ u8 resp_reserved[12];
+};
+
+IAVF_CHECK_STRUCT_LEN(128, iavf_aqc_vsi_properties_data);
+
+/* Get VEB Parameters (direct 0x0232)
+ * uses iavf_aqc_switch_seid for the descriptor
+ */
+struct iavf_aqc_get_veb_parameters_completion {
+ __le16 seid;
+ __le16 switch_id;
+ __le16 veb_flags; /* only the first/last flags from 0x0230 is valid */
+ __le16 statistic_index;
+ __le16 vebs_used;
+ __le16 vebs_free;
+ u8 reserved[4];
+};
+
+IAVF_CHECK_CMD_LENGTH(iavf_aqc_get_veb_parameters_completion);
+
+#define IAVF_LINK_SPEED_100MB_SHIFT 0x1
+#define IAVF_LINK_SPEED_1000MB_SHIFT 0x2
+#define IAVF_LINK_SPEED_10GB_SHIFT 0x3
+#define IAVF_LINK_SPEED_40GB_SHIFT 0x4
+#define IAVF_LINK_SPEED_20GB_SHIFT 0x5
+#define IAVF_LINK_SPEED_25GB_SHIFT 0x6
+
+enum iavf_aq_link_speed {
+ IAVF_LINK_SPEED_UNKNOWN = 0,
+ IAVF_LINK_SPEED_100MB = BIT(IAVF_LINK_SPEED_100MB_SHIFT),
+ IAVF_LINK_SPEED_1GB = BIT(IAVF_LINK_SPEED_1000MB_SHIFT),
+ IAVF_LINK_SPEED_10GB = BIT(IAVF_LINK_SPEED_10GB_SHIFT),
+ IAVF_LINK_SPEED_40GB = BIT(IAVF_LINK_SPEED_40GB_SHIFT),
+ IAVF_LINK_SPEED_20GB = BIT(IAVF_LINK_SPEED_20GB_SHIFT),
+ IAVF_LINK_SPEED_25GB = BIT(IAVF_LINK_SPEED_25GB_SHIFT),
+};
+
+/* Send to PF command (indirect 0x0801) id is only used by PF
+ * Send to VF command (indirect 0x0802) id is only used by PF
+ * Send to Peer PF command (indirect 0x0803)
+ */
+struct iavf_aqc_pf_vf_message {
+ __le32 id;
+ u8 reserved[4];
+ __le32 addr_high;
+ __le32 addr_low;
+};
+
+IAVF_CHECK_CMD_LENGTH(iavf_aqc_pf_vf_message);
+
+struct iavf_aqc_get_set_rss_key {
+#define IAVF_AQC_SET_RSS_KEY_VSI_VALID BIT(15)
+#define IAVF_AQC_SET_RSS_KEY_VSI_ID_SHIFT 0
+#define IAVF_AQC_SET_RSS_KEY_VSI_ID_MASK (0x3FF << \
+ IAVF_AQC_SET_RSS_KEY_VSI_ID_SHIFT)
+ __le16 vsi_id;
+ u8 reserved[6];
+ __le32 addr_high;
+ __le32 addr_low;
+};
+
+IAVF_CHECK_CMD_LENGTH(iavf_aqc_get_set_rss_key);
+
+struct iavf_aqc_get_set_rss_key_data {
+ u8 standard_rss_key[0x28];
+ u8 extended_hash_key[0xc];
+};
+
+IAVF_CHECK_STRUCT_LEN(0x34, iavf_aqc_get_set_rss_key_data);
+
+struct iavf_aqc_get_set_rss_lut {
+#define IAVF_AQC_SET_RSS_LUT_VSI_VALID BIT(15)
+#define IAVF_AQC_SET_RSS_LUT_VSI_ID_SHIFT 0
+#define IAVF_AQC_SET_RSS_LUT_VSI_ID_MASK (0x3FF << \
+ IAVF_AQC_SET_RSS_LUT_VSI_ID_SHIFT)
+ __le16 vsi_id;
+#define IAVF_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT 0
+#define IAVF_AQC_SET_RSS_LUT_TABLE_TYPE_MASK \
+ BIT(IAVF_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT)
+
+#define IAVF_AQC_SET_RSS_LUT_TABLE_TYPE_VSI 0
+#define IAVF_AQC_SET_RSS_LUT_TABLE_TYPE_PF 1
+ __le16 flags;
+ u8 reserved[4];
+ __le32 addr_high;
+ __le32 addr_low;
+};
+
+IAVF_CHECK_CMD_LENGTH(iavf_aqc_get_set_rss_lut);
+#endif /* _IAVF_ADMINQ_CMD_H_ */
diff --git a/drivers/net/ethernet/intel/iavf/iavf_alloc.h b/drivers/net/ethernet/intel/iavf/iavf_alloc.h
index bf2753146f30..2711573c14ec 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_alloc.h
+++ b/drivers/net/ethernet/intel/iavf/iavf_alloc.h
@@ -20,12 +20,15 @@ enum iavf_memory_type {
};
/* prototype for functions used for dynamic memory allocation */
-iavf_status iavf_allocate_dma_mem(struct iavf_hw *hw, struct iavf_dma_mem *mem,
- enum iavf_memory_type type,
- u64 size, u32 alignment);
-iavf_status iavf_free_dma_mem(struct iavf_hw *hw, struct iavf_dma_mem *mem);
-iavf_status iavf_allocate_virt_mem(struct iavf_hw *hw,
- struct iavf_virt_mem *mem, u32 size);
-iavf_status iavf_free_virt_mem(struct iavf_hw *hw, struct iavf_virt_mem *mem);
+enum iavf_status iavf_allocate_dma_mem(struct iavf_hw *hw,
+ struct iavf_dma_mem *mem,
+ enum iavf_memory_type type,
+ u64 size, u32 alignment);
+enum iavf_status iavf_free_dma_mem(struct iavf_hw *hw,
+ struct iavf_dma_mem *mem);
+enum iavf_status iavf_allocate_virt_mem(struct iavf_hw *hw,
+ struct iavf_virt_mem *mem, u32 size);
+enum iavf_status iavf_free_virt_mem(struct iavf_hw *hw,
+ struct iavf_virt_mem *mem);
#endif /* _IAVF_ALLOC_H_ */
diff --git a/drivers/net/ethernet/intel/iavf/iavf_client.c b/drivers/net/ethernet/intel/iavf/iavf_client.c
index aea45364fd1c..0c77e4171808 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_client.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_client.c
@@ -10,19 +10,19 @@
static
const char iavf_client_interface_version_str[] = IAVF_CLIENT_VERSION_STR;
-static struct i40e_client *vf_registered_client;
-static LIST_HEAD(i40e_devices);
+static struct iavf_client *vf_registered_client;
+static LIST_HEAD(iavf_devices);
static DEFINE_MUTEX(iavf_device_mutex);
-static u32 iavf_client_virtchnl_send(struct i40e_info *ldev,
- struct i40e_client *client,
+static u32 iavf_client_virtchnl_send(struct iavf_info *ldev,
+ struct iavf_client *client,
u8 *msg, u16 len);
-static int iavf_client_setup_qvlist(struct i40e_info *ldev,
- struct i40e_client *client,
- struct i40e_qvlist_info *qvlist_info);
+static int iavf_client_setup_qvlist(struct iavf_info *ldev,
+ struct iavf_client *client,
+ struct iavf_qvlist_info *qvlist_info);
-static struct i40e_ops iavf_lan_ops = {
+static struct iavf_ops iavf_lan_ops = {
.virtchnl_send = iavf_client_virtchnl_send,
.setup_qvlist = iavf_client_setup_qvlist,
};
@@ -33,11 +33,11 @@ static struct i40e_ops iavf_lan_ops = {
* @params: client param struct
**/
static
-void iavf_client_get_params(struct iavf_vsi *vsi, struct i40e_params *params)
+void iavf_client_get_params(struct iavf_vsi *vsi, struct iavf_params *params)
{
int i;
- memset(params, 0, sizeof(struct i40e_params));
+ memset(params, 0, sizeof(struct iavf_params));
params->mtu = vsi->netdev->mtu;
params->link_up = vsi->back->link_up;
@@ -57,7 +57,7 @@ void iavf_client_get_params(struct iavf_vsi *vsi, struct i40e_params *params)
**/
void iavf_notify_client_message(struct iavf_vsi *vsi, u8 *msg, u16 len)
{
- struct i40e_client_instance *cinst;
+ struct iavf_client_instance *cinst;
if (!vsi)
return;
@@ -81,8 +81,8 @@ void iavf_notify_client_message(struct iavf_vsi *vsi, u8 *msg, u16 len)
**/
void iavf_notify_client_l2_params(struct iavf_vsi *vsi)
{
- struct i40e_client_instance *cinst;
- struct i40e_params params;
+ struct iavf_client_instance *cinst;
+ struct iavf_params params;
if (!vsi)
return;
@@ -110,7 +110,7 @@ void iavf_notify_client_l2_params(struct iavf_vsi *vsi)
void iavf_notify_client_open(struct iavf_vsi *vsi)
{
struct iavf_adapter *adapter = vsi->back;
- struct i40e_client_instance *cinst = adapter->cinst;
+ struct iavf_client_instance *cinst = adapter->cinst;
int ret;
if (!cinst || !cinst->client || !cinst->client->ops ||
@@ -119,10 +119,10 @@ void iavf_notify_client_open(struct iavf_vsi *vsi)
"Cannot locate client instance open function\n");
return;
}
- if (!(test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cinst->state))) {
+ if (!(test_bit(__IAVF_CLIENT_INSTANCE_OPENED, &cinst->state))) {
ret = cinst->client->ops->open(&cinst->lan_info, cinst->client);
if (!ret)
- set_bit(__I40E_CLIENT_INSTANCE_OPENED, &cinst->state);
+ set_bit(__IAVF_CLIENT_INSTANCE_OPENED, &cinst->state);
}
}
@@ -132,17 +132,17 @@ void iavf_notify_client_open(struct iavf_vsi *vsi)
*
* Return 0 on success or < 0 on error
**/
-static int iavf_client_release_qvlist(struct i40e_info *ldev)
+static int iavf_client_release_qvlist(struct iavf_info *ldev)
{
struct iavf_adapter *adapter = ldev->vf;
- iavf_status err;
+ enum iavf_status err;
if (adapter->aq_required)
return -EAGAIN;
err = iavf_aq_send_msg_to_pf(&adapter->hw,
VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP,
- I40E_SUCCESS, NULL, 0, NULL);
+ IAVF_SUCCESS, NULL, 0, NULL);
if (err)
dev_err(&adapter->pdev->dev,
@@ -162,7 +162,7 @@ static int iavf_client_release_qvlist(struct i40e_info *ldev)
void iavf_notify_client_close(struct iavf_vsi *vsi, bool reset)
{
struct iavf_adapter *adapter = vsi->back;
- struct i40e_client_instance *cinst = adapter->cinst;
+ struct iavf_client_instance *cinst = adapter->cinst;
if (!cinst || !cinst->client || !cinst->client->ops ||
!cinst->client->ops->close) {
@@ -172,7 +172,7 @@ void iavf_notify_client_close(struct iavf_vsi *vsi, bool reset)
}
cinst->client->ops->close(&cinst->lan_info, cinst->client, reset);
iavf_client_release_qvlist(&cinst->lan_info);
- clear_bit(__I40E_CLIENT_INSTANCE_OPENED, &cinst->state);
+ clear_bit(__IAVF_CLIENT_INSTANCE_OPENED, &cinst->state);
}
/**
@@ -181,13 +181,13 @@ void iavf_notify_client_close(struct iavf_vsi *vsi, bool reset)
*
* Returns cinst ptr on success, NULL on failure
**/
-static struct i40e_client_instance *
+static struct iavf_client_instance *
iavf_client_add_instance(struct iavf_adapter *adapter)
{
- struct i40e_client_instance *cinst = NULL;
+ struct iavf_client_instance *cinst = NULL;
struct iavf_vsi *vsi = &adapter->vsi;
struct netdev_hw_addr *mac = NULL;
- struct i40e_params params;
+ struct iavf_params params;
if (!vf_registered_client)
goto out;
@@ -205,7 +205,7 @@ iavf_client_add_instance(struct iavf_adapter *adapter)
cinst->lan_info.netdev = vsi->netdev;
cinst->lan_info.pcidev = adapter->pdev;
cinst->lan_info.fid = 0;
- cinst->lan_info.ftype = I40E_CLIENT_FTYPE_VF;
+ cinst->lan_info.ftype = IAVF_CLIENT_FTYPE_VF;
cinst->lan_info.hw_addr = adapter->hw.hw_addr;
cinst->lan_info.ops = &iavf_lan_ops;
cinst->lan_info.version.major = IAVF_CLIENT_VERSION_MAJOR;
@@ -213,7 +213,7 @@ iavf_client_add_instance(struct iavf_adapter *adapter)
cinst->lan_info.version.build = IAVF_CLIENT_VERSION_BUILD;
iavf_client_get_params(vsi, &params);
cinst->lan_info.params = params;
- set_bit(__I40E_CLIENT_INSTANCE_NONE, &cinst->state);
+ set_bit(__IAVF_CLIENT_INSTANCE_NONE, &cinst->state);
cinst->lan_info.msix_count = adapter->num_iwarp_msix;
cinst->lan_info.msix_entries =
@@ -250,8 +250,8 @@ void iavf_client_del_instance(struct iavf_adapter *adapter)
**/
void iavf_client_subtask(struct iavf_adapter *adapter)
{
- struct i40e_client *client = vf_registered_client;
- struct i40e_client_instance *cinst;
+ struct iavf_client *client = vf_registered_client;
+ struct iavf_client_instance *cinst;
int ret = 0;
if (adapter->state < __IAVF_DOWN)
@@ -269,13 +269,13 @@ void iavf_client_subtask(struct iavf_adapter *adapter)
dev_info(&adapter->pdev->dev, "Added instance of Client %s\n",
client->name);
- if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cinst->state)) {
+ if (!test_bit(__IAVF_CLIENT_INSTANCE_OPENED, &cinst->state)) {
/* Send an Open request to the client */
if (client->ops && client->ops->open)
ret = client->ops->open(&cinst->lan_info, client);
if (!ret)
- set_bit(__I40E_CLIENT_INSTANCE_OPENED,
+ set_bit(__IAVF_CLIENT_INSTANCE_OPENED,
&cinst->state);
else
/* remove client instance */
@@ -291,11 +291,11 @@ void iavf_client_subtask(struct iavf_adapter *adapter)
**/
int iavf_lan_add_device(struct iavf_adapter *adapter)
{
- struct i40e_device *ldev;
+ struct iavf_device *ldev;
int ret = 0;
mutex_lock(&iavf_device_mutex);
- list_for_each_entry(ldev, &i40e_devices, list) {
+ list_for_each_entry(ldev, &iavf_devices, list) {
if (ldev->vf == adapter) {
ret = -EEXIST;
goto out;
@@ -308,7 +308,7 @@ int iavf_lan_add_device(struct iavf_adapter *adapter)
}
ldev->vf = adapter;
INIT_LIST_HEAD(&ldev->list);
- list_add(&ldev->list, &i40e_devices);
+ list_add(&ldev->list, &iavf_devices);
dev_info(&adapter->pdev->dev, "Added LAN device bus=0x%02x dev=0x%02x func=0x%02x\n",
adapter->hw.bus.bus_id, adapter->hw.bus.device,
adapter->hw.bus.func);
@@ -331,11 +331,11 @@ out:
**/
int iavf_lan_del_device(struct iavf_adapter *adapter)
{
- struct i40e_device *ldev, *tmp;
+ struct iavf_device *ldev, *tmp;
int ret = -ENODEV;
mutex_lock(&iavf_device_mutex);
- list_for_each_entry_safe(ldev, tmp, &i40e_devices, list) {
+ list_for_each_entry_safe(ldev, tmp, &iavf_devices, list) {
if (ldev->vf == adapter) {
dev_info(&adapter->pdev->dev,
"Deleted LAN device bus=0x%02x dev=0x%02x func=0x%02x\n",
@@ -357,24 +357,24 @@ int iavf_lan_del_device(struct iavf_adapter *adapter)
* @client: pointer to the registered client
*
**/
-static void iavf_client_release(struct i40e_client *client)
+static void iavf_client_release(struct iavf_client *client)
{
- struct i40e_client_instance *cinst;
- struct i40e_device *ldev;
+ struct iavf_client_instance *cinst;
+ struct iavf_device *ldev;
struct iavf_adapter *adapter;
mutex_lock(&iavf_device_mutex);
- list_for_each_entry(ldev, &i40e_devices, list) {
+ list_for_each_entry(ldev, &iavf_devices, list) {
adapter = ldev->vf;
cinst = adapter->cinst;
if (!cinst)
continue;
- if (test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cinst->state)) {
+ if (test_bit(__IAVF_CLIENT_INSTANCE_OPENED, &cinst->state)) {
if (client->ops && client->ops->close)
client->ops->close(&cinst->lan_info, client,
false);
iavf_client_release_qvlist(&cinst->lan_info);
- clear_bit(__I40E_CLIENT_INSTANCE_OPENED, &cinst->state);
+ clear_bit(__IAVF_CLIENT_INSTANCE_OPENED, &cinst->state);
dev_warn(&adapter->pdev->dev,
"Client %s instance closed\n", client->name);
@@ -392,13 +392,13 @@ static void iavf_client_release(struct i40e_client *client)
* @client: pointer to the registered client
*
**/
-static void iavf_client_prepare(struct i40e_client *client)
+static void iavf_client_prepare(struct iavf_client *client)
{
- struct i40e_device *ldev;
+ struct iavf_device *ldev;
struct iavf_adapter *adapter;
mutex_lock(&iavf_device_mutex);
- list_for_each_entry(ldev, &i40e_devices, list) {
+ list_for_each_entry(ldev, &iavf_devices, list) {
adapter = ldev->vf;
/* Signal the watchdog to service the client */
adapter->flags |= IAVF_FLAG_SERVICE_CLIENT_REQUESTED;
@@ -415,18 +415,18 @@ static void iavf_client_prepare(struct i40e_client *client)
*
* Return 0 on success or < 0 on error
**/
-static u32 iavf_client_virtchnl_send(struct i40e_info *ldev,
- struct i40e_client *client,
+static u32 iavf_client_virtchnl_send(struct iavf_info *ldev,
+ struct iavf_client *client,
u8 *msg, u16 len)
{
struct iavf_adapter *adapter = ldev->vf;
- iavf_status err;
+ enum iavf_status err;
if (adapter->aq_required)
return -EAGAIN;
err = iavf_aq_send_msg_to_pf(&adapter->hw, VIRTCHNL_OP_IWARP,
- I40E_SUCCESS, msg, len, NULL);
+ IAVF_SUCCESS, msg, len, NULL);
if (err)
dev_err(&adapter->pdev->dev, "Unable to send iWarp message to PF, error %d, aq status %d\n",
err, adapter->hw.aq.asq_last_status);
@@ -442,16 +442,16 @@ static u32 iavf_client_virtchnl_send(struct i40e_info *ldev,
*
* Return 0 on success or < 0 on error
**/
-static int iavf_client_setup_qvlist(struct i40e_info *ldev,
- struct i40e_client *client,
- struct i40e_qvlist_info *qvlist_info)
+static int iavf_client_setup_qvlist(struct iavf_info *ldev,
+ struct iavf_client *client,
+ struct iavf_qvlist_info *qvlist_info)
{
struct virtchnl_iwarp_qvlist_info *v_qvlist_info;
struct iavf_adapter *adapter = ldev->vf;
- struct i40e_qv_info *qv_info;
- iavf_status err;
+ struct iavf_qv_info *qv_info;
+ enum iavf_status err;
u32 v_idx, i;
- u32 msg_size;
+ size_t msg_size;
if (adapter->aq_required)
return -EAGAIN;
@@ -469,13 +469,12 @@ static int iavf_client_setup_qvlist(struct i40e_info *ldev,
}
v_qvlist_info = (struct virtchnl_iwarp_qvlist_info *)qvlist_info;
- msg_size = sizeof(struct virtchnl_iwarp_qvlist_info) +
- (sizeof(struct virtchnl_iwarp_qv_info) *
- (v_qvlist_info->num_vectors - 1));
+ msg_size = struct_size(v_qvlist_info, qv_info,
+ v_qvlist_info->num_vectors - 1);
adapter->client_pending |= BIT(VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP);
err = iavf_aq_send_msg_to_pf(&adapter->hw,
- VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP, I40E_SUCCESS,
+ VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP, IAVF_SUCCESS,
(u8 *)v_qvlist_info, msg_size, NULL);
if (err) {
@@ -499,12 +498,12 @@ out:
}
/**
- * iavf_register_client - Register a i40e client driver with the L2 driver
- * @client: pointer to the i40e_client struct
+ * iavf_register_client - Register a iavf client driver with the L2 driver
+ * @client: pointer to the iavf_client struct
*
* Returns 0 on success or non-0 on error
**/
-int iavf_register_client(struct i40e_client *client)
+int iavf_register_client(struct iavf_client *client)
{
int ret = 0;
@@ -550,12 +549,12 @@ out:
EXPORT_SYMBOL(iavf_register_client);
/**
- * iavf_unregister_client - Unregister a i40e client driver with the L2 driver
- * @client: pointer to the i40e_client struct
+ * iavf_unregister_client - Unregister a iavf client driver with the L2 driver
+ * @client: pointer to the iavf_client struct
*
* Returns 0 on success or non-0 on error
**/
-int iavf_unregister_client(struct i40e_client *client)
+int iavf_unregister_client(struct iavf_client *client)
{
int ret = 0;
diff --git a/drivers/net/ethernet/intel/iavf/iavf_client.h b/drivers/net/ethernet/intel/iavf/iavf_client.h
index e216fc9dfd81..9a7cf39ea75a 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_client.h
+++ b/drivers/net/ethernet/intel/iavf/iavf_client.h
@@ -17,86 +17,86 @@
__stringify(IAVF_CLIENT_VERSION_MINOR) "." \
__stringify(IAVF_CLIENT_VERSION_BUILD)
-struct i40e_client_version {
+struct iavf_client_version {
u8 major;
u8 minor;
u8 build;
u8 rsvd;
};
-enum i40e_client_state {
- __I40E_CLIENT_NULL,
- __I40E_CLIENT_REGISTERED
+enum iavf_client_state {
+ __IAVF_CLIENT_NULL,
+ __IAVF_CLIENT_REGISTERED
};
-enum i40e_client_instance_state {
- __I40E_CLIENT_INSTANCE_NONE,
- __I40E_CLIENT_INSTANCE_OPENED,
+enum iavf_client_instance_state {
+ __IAVF_CLIENT_INSTANCE_NONE,
+ __IAVF_CLIENT_INSTANCE_OPENED,
};
-struct i40e_ops;
-struct i40e_client;
+struct iavf_ops;
+struct iavf_client;
/* HW does not define a type value for AEQ; only for RX/TX and CEQ.
* In order for us to keep the interface simple, SW will define a
* unique type value for AEQ.
*/
-#define I40E_QUEUE_TYPE_PE_AEQ 0x80
-#define I40E_QUEUE_INVALID_IDX 0xFFFF
+#define IAVF_QUEUE_TYPE_PE_AEQ 0x80
+#define IAVF_QUEUE_INVALID_IDX 0xFFFF
-struct i40e_qv_info {
+struct iavf_qv_info {
u32 v_idx; /* msix_vector */
u16 ceq_idx;
u16 aeq_idx;
u8 itr_idx;
};
-struct i40e_qvlist_info {
+struct iavf_qvlist_info {
u32 num_vectors;
- struct i40e_qv_info qv_info[1];
+ struct iavf_qv_info qv_info[1];
};
-#define I40E_CLIENT_MSIX_ALL 0xFFFFFFFF
+#define IAVF_CLIENT_MSIX_ALL 0xFFFFFFFF
/* set of LAN parameters useful for clients managed by LAN */
/* Struct to hold per priority info */
-struct i40e_prio_qos_params {
+struct iavf_prio_qos_params {
u16 qs_handle; /* qs handle for prio */
u8 tc; /* TC mapped to prio */
u8 reserved;
};
-#define I40E_CLIENT_MAX_USER_PRIORITY 8
+#define IAVF_CLIENT_MAX_USER_PRIORITY 8
/* Struct to hold Client QoS */
-struct i40e_qos_params {
- struct i40e_prio_qos_params prio_qos[I40E_CLIENT_MAX_USER_PRIORITY];
+struct iavf_qos_params {
+ struct iavf_prio_qos_params prio_qos[IAVF_CLIENT_MAX_USER_PRIORITY];
};
-struct i40e_params {
- struct i40e_qos_params qos;
+struct iavf_params {
+ struct iavf_qos_params qos;
u16 mtu;
u16 link_up; /* boolean */
};
/* Structure to hold LAN device info for a client device */
-struct i40e_info {
- struct i40e_client_version version;
+struct iavf_info {
+ struct iavf_client_version version;
u8 lanmac[6];
struct net_device *netdev;
struct pci_dev *pcidev;
u8 __iomem *hw_addr;
u8 fid; /* function id, PF id or VF id */
-#define I40E_CLIENT_FTYPE_PF 0
-#define I40E_CLIENT_FTYPE_VF 1
+#define IAVF_CLIENT_FTYPE_PF 0
+#define IAVF_CLIENT_FTYPE_VF 1
u8 ftype; /* function type, PF or VF */
void *vf; /* cast to iavf_adapter */
/* All L2 params that could change during the life span of the device
* and needs to be communicated to the client when they change
*/
- struct i40e_params params;
- struct i40e_ops *ops;
+ struct iavf_params params;
+ struct iavf_ops *ops;
u16 msix_count; /* number of msix vectors*/
/* Array down below will be dynamically allocated based on msix_count */
@@ -104,66 +104,66 @@ struct i40e_info {
u16 itr_index; /* Which ITR index the PE driver is suppose to use */
};
-struct i40e_ops {
+struct iavf_ops {
/* setup_q_vector_list enables queues with a particular vector */
- int (*setup_qvlist)(struct i40e_info *ldev, struct i40e_client *client,
- struct i40e_qvlist_info *qv_info);
+ int (*setup_qvlist)(struct iavf_info *ldev, struct iavf_client *client,
+ struct iavf_qvlist_info *qv_info);
- u32 (*virtchnl_send)(struct i40e_info *ldev, struct i40e_client *client,
+ u32 (*virtchnl_send)(struct iavf_info *ldev, struct iavf_client *client,
u8 *msg, u16 len);
/* If the PE Engine is unresponsive, RDMA driver can request a reset.*/
- void (*request_reset)(struct i40e_info *ldev,
- struct i40e_client *client);
+ void (*request_reset)(struct iavf_info *ldev,
+ struct iavf_client *client);
};
-struct i40e_client_ops {
+struct iavf_client_ops {
/* Should be called from register_client() or whenever the driver is
* ready to create a specific client instance.
*/
- int (*open)(struct i40e_info *ldev, struct i40e_client *client);
+ int (*open)(struct iavf_info *ldev, struct iavf_client *client);
/* Should be closed when netdev is unavailable or when unregister
* call comes in. If the close happens due to a reset, set the reset
* bit to true.
*/
- void (*close)(struct i40e_info *ldev, struct i40e_client *client,
+ void (*close)(struct iavf_info *ldev, struct iavf_client *client,
bool reset);
/* called when some l2 managed parameters changes - mss */
- void (*l2_param_change)(struct i40e_info *ldev,
- struct i40e_client *client,
- struct i40e_params *params);
+ void (*l2_param_change)(struct iavf_info *ldev,
+ struct iavf_client *client,
+ struct iavf_params *params);
/* called when a message is received from the PF */
- int (*virtchnl_receive)(struct i40e_info *ldev,
- struct i40e_client *client,
+ int (*virtchnl_receive)(struct iavf_info *ldev,
+ struct iavf_client *client,
u8 *msg, u16 len);
};
/* Client device */
-struct i40e_client_instance {
+struct iavf_client_instance {
struct list_head list;
- struct i40e_info lan_info;
- struct i40e_client *client;
+ struct iavf_info lan_info;
+ struct iavf_client *client;
unsigned long state;
};
-struct i40e_client {
+struct iavf_client {
struct list_head list; /* list of registered clients */
char name[IAVF_CLIENT_STR_LENGTH];
- struct i40e_client_version version;
+ struct iavf_client_version version;
unsigned long state; /* client state */
atomic_t ref_cnt; /* Count of all the client devices of this kind */
u32 flags;
-#define I40E_CLIENT_FLAGS_LAUNCH_ON_PROBE BIT(0)
-#define I40E_TX_FLAGS_NOTIFY_OTHER_EVENTS BIT(2)
+#define IAVF_CLIENT_FLAGS_LAUNCH_ON_PROBE BIT(0)
+#define IAVF_TX_FLAGS_NOTIFY_OTHER_EVENTS BIT(2)
u8 type;
-#define I40E_CLIENT_IWARP 0
- struct i40e_client_ops *ops; /* client ops provided by the client */
+#define IAVF_CLIENT_IWARP 0
+ struct iavf_client_ops *ops; /* client ops provided by the client */
};
/* used by clients */
-int iavf_register_client(struct i40e_client *client);
-int iavf_unregister_client(struct i40e_client *client);
+int iavf_register_client(struct iavf_client *client);
+int iavf_unregister_client(struct iavf_client *client);
#endif /* _IAVF_CLIENT_H_ */
diff --git a/drivers/net/ethernet/intel/iavf/iavf_common.c b/drivers/net/ethernet/intel/iavf/iavf_common.c
index 768369c89e77..8547fc8fdfd6 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_common.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_common.c
@@ -2,7 +2,7 @@
/* Copyright(c) 2013 - 2018 Intel Corporation. */
#include "iavf_type.h"
-#include "i40e_adminq.h"
+#include "iavf_adminq.h"
#include "iavf_prototype.h"
#include <linux/avf/virtchnl.h>
@@ -13,9 +13,9 @@
* This function sets the mac type of the adapter based on the
* vendor ID and device ID stored in the hw structure.
**/
-iavf_status iavf_set_mac_type(struct iavf_hw *hw)
+enum iavf_status iavf_set_mac_type(struct iavf_hw *hw)
{
- iavf_status status = 0;
+ enum iavf_status status = 0;
if (hw->vendor_id == PCI_VENDOR_ID_INTEL) {
switch (hw->device_id) {
@@ -32,7 +32,7 @@ iavf_status iavf_set_mac_type(struct iavf_hw *hw)
break;
}
} else {
- status = I40E_ERR_DEVICE_NOT_SUPPORTED;
+ status = IAVF_ERR_DEVICE_NOT_SUPPORTED;
}
hw_dbg(hw, "found mac: %d, returns: %d\n", hw->mac.type, status);
@@ -44,55 +44,55 @@ iavf_status iavf_set_mac_type(struct iavf_hw *hw)
* @hw: pointer to the HW structure
* @aq_err: the AQ error code to convert
**/
-const char *iavf_aq_str(struct iavf_hw *hw, enum i40e_admin_queue_err aq_err)
+const char *iavf_aq_str(struct iavf_hw *hw, enum iavf_admin_queue_err aq_err)
{
switch (aq_err) {
- case I40E_AQ_RC_OK:
+ case IAVF_AQ_RC_OK:
return "OK";
- case I40E_AQ_RC_EPERM:
- return "I40E_AQ_RC_EPERM";
- case I40E_AQ_RC_ENOENT:
- return "I40E_AQ_RC_ENOENT";
- case I40E_AQ_RC_ESRCH:
- return "I40E_AQ_RC_ESRCH";
- case I40E_AQ_RC_EINTR:
- return "I40E_AQ_RC_EINTR";
- case I40E_AQ_RC_EIO:
- return "I40E_AQ_RC_EIO";
- case I40E_AQ_RC_ENXIO:
- return "I40E_AQ_RC_ENXIO";
- case I40E_AQ_RC_E2BIG:
- return "I40E_AQ_RC_E2BIG";
- case I40E_AQ_RC_EAGAIN:
- return "I40E_AQ_RC_EAGAIN";
- case I40E_AQ_RC_ENOMEM:
- return "I40E_AQ_RC_ENOMEM";
- case I40E_AQ_RC_EACCES:
- return "I40E_AQ_RC_EACCES";
- case I40E_AQ_RC_EFAULT:
- return "I40E_AQ_RC_EFAULT";
- case I40E_AQ_RC_EBUSY:
- return "I40E_AQ_RC_EBUSY";
- case I40E_AQ_RC_EEXIST:
- return "I40E_AQ_RC_EEXIST";
- case I40E_AQ_RC_EINVAL:
- return "I40E_AQ_RC_EINVAL";
- case I40E_AQ_RC_ENOTTY:
- return "I40E_AQ_RC_ENOTTY";
- case I40E_AQ_RC_ENOSPC:
- return "I40E_AQ_RC_ENOSPC";
- case I40E_AQ_RC_ENOSYS:
- return "I40E_AQ_RC_ENOSYS";
- case I40E_AQ_RC_ERANGE:
- return "I40E_AQ_RC_ERANGE";
- case I40E_AQ_RC_EFLUSHED:
- return "I40E_AQ_RC_EFLUSHED";
- case I40E_AQ_RC_BAD_ADDR:
- return "I40E_AQ_RC_BAD_ADDR";
- case I40E_AQ_RC_EMODE:
- return "I40E_AQ_RC_EMODE";
- case I40E_AQ_RC_EFBIG:
- return "I40E_AQ_RC_EFBIG";
+ case IAVF_AQ_RC_EPERM:
+ return "IAVF_AQ_RC_EPERM";
+ case IAVF_AQ_RC_ENOENT:
+ return "IAVF_AQ_RC_ENOENT";
+ case IAVF_AQ_RC_ESRCH:
+ return "IAVF_AQ_RC_ESRCH";
+ case IAVF_AQ_RC_EINTR:
+ return "IAVF_AQ_RC_EINTR";
+ case IAVF_AQ_RC_EIO:
+ return "IAVF_AQ_RC_EIO";
+ case IAVF_AQ_RC_ENXIO:
+ return "IAVF_AQ_RC_ENXIO";
+ case IAVF_AQ_RC_E2BIG:
+ return "IAVF_AQ_RC_E2BIG";
+ case IAVF_AQ_RC_EAGAIN:
+ return "IAVF_AQ_RC_EAGAIN";
+ case IAVF_AQ_RC_ENOMEM:
+ return "IAVF_AQ_RC_ENOMEM";
+ case IAVF_AQ_RC_EACCES:
+ return "IAVF_AQ_RC_EACCES";
+ case IAVF_AQ_RC_EFAULT:
+ return "IAVF_AQ_RC_EFAULT";
+ case IAVF_AQ_RC_EBUSY:
+ return "IAVF_AQ_RC_EBUSY";
+ case IAVF_AQ_RC_EEXIST:
+ return "IAVF_AQ_RC_EEXIST";
+ case IAVF_AQ_RC_EINVAL:
+ return "IAVF_AQ_RC_EINVAL";
+ case IAVF_AQ_RC_ENOTTY:
+ return "IAVF_AQ_RC_ENOTTY";
+ case IAVF_AQ_RC_ENOSPC:
+ return "IAVF_AQ_RC_ENOSPC";
+ case IAVF_AQ_RC_ENOSYS:
+ return "IAVF_AQ_RC_ENOSYS";
+ case IAVF_AQ_RC_ERANGE:
+ return "IAVF_AQ_RC_ERANGE";
+ case IAVF_AQ_RC_EFLUSHED:
+ return "IAVF_AQ_RC_EFLUSHED";
+ case IAVF_AQ_RC_BAD_ADDR:
+ return "IAVF_AQ_RC_BAD_ADDR";
+ case IAVF_AQ_RC_EMODE:
+ return "IAVF_AQ_RC_EMODE";
+ case IAVF_AQ_RC_EFBIG:
+ return "IAVF_AQ_RC_EFBIG";
}
snprintf(hw->err_str, sizeof(hw->err_str), "%d", aq_err);
@@ -104,143 +104,143 @@ const char *iavf_aq_str(struct iavf_hw *hw, enum i40e_admin_queue_err aq_err)
* @hw: pointer to the HW structure
* @stat_err: the status error code to convert
**/
-const char *iavf_stat_str(struct iavf_hw *hw, iavf_status stat_err)
+const char *iavf_stat_str(struct iavf_hw *hw, enum iavf_status stat_err)
{
switch (stat_err) {
case 0:
return "OK";
- case I40E_ERR_NVM:
- return "I40E_ERR_NVM";
- case I40E_ERR_NVM_CHECKSUM:
- return "I40E_ERR_NVM_CHECKSUM";
- case I40E_ERR_PHY:
- return "I40E_ERR_PHY";
- case I40E_ERR_CONFIG:
- return "I40E_ERR_CONFIG";
- case I40E_ERR_PARAM:
- return "I40E_ERR_PARAM";
- case I40E_ERR_MAC_TYPE:
- return "I40E_ERR_MAC_TYPE";
- case I40E_ERR_UNKNOWN_PHY:
- return "I40E_ERR_UNKNOWN_PHY";
- case I40E_ERR_LINK_SETUP:
- return "I40E_ERR_LINK_SETUP";
- case I40E_ERR_ADAPTER_STOPPED:
- return "I40E_ERR_ADAPTER_STOPPED";
- case I40E_ERR_INVALID_MAC_ADDR:
- return "I40E_ERR_INVALID_MAC_ADDR";
- case I40E_ERR_DEVICE_NOT_SUPPORTED:
- return "I40E_ERR_DEVICE_NOT_SUPPORTED";
- case I40E_ERR_MASTER_REQUESTS_PENDING:
- return "I40E_ERR_MASTER_REQUESTS_PENDING";
- case I40E_ERR_INVALID_LINK_SETTINGS:
- return "I40E_ERR_INVALID_LINK_SETTINGS";
- case I40E_ERR_AUTONEG_NOT_COMPLETE:
- return "I40E_ERR_AUTONEG_NOT_COMPLETE";
- case I40E_ERR_RESET_FAILED:
- return "I40E_ERR_RESET_FAILED";
- case I40E_ERR_SWFW_SYNC:
- return "I40E_ERR_SWFW_SYNC";
- case I40E_ERR_NO_AVAILABLE_VSI:
- return "I40E_ERR_NO_AVAILABLE_VSI";
- case I40E_ERR_NO_MEMORY:
- return "I40E_ERR_NO_MEMORY";
- case I40E_ERR_BAD_PTR:
- return "I40E_ERR_BAD_PTR";
- case I40E_ERR_RING_FULL:
- return "I40E_ERR_RING_FULL";
- case I40E_ERR_INVALID_PD_ID:
- return "I40E_ERR_INVALID_PD_ID";
- case I40E_ERR_INVALID_QP_ID:
- return "I40E_ERR_INVALID_QP_ID";
- case I40E_ERR_INVALID_CQ_ID:
- return "I40E_ERR_INVALID_CQ_ID";
- case I40E_ERR_INVALID_CEQ_ID:
- return "I40E_ERR_INVALID_CEQ_ID";
- case I40E_ERR_INVALID_AEQ_ID:
- return "I40E_ERR_INVALID_AEQ_ID";
- case I40E_ERR_INVALID_SIZE:
- return "I40E_ERR_INVALID_SIZE";
- case I40E_ERR_INVALID_ARP_INDEX:
- return "I40E_ERR_INVALID_ARP_INDEX";
- case I40E_ERR_INVALID_FPM_FUNC_ID:
- return "I40E_ERR_INVALID_FPM_FUNC_ID";
- case I40E_ERR_QP_INVALID_MSG_SIZE:
- return "I40E_ERR_QP_INVALID_MSG_SIZE";
- case I40E_ERR_QP_TOOMANY_WRS_POSTED:
- return "I40E_ERR_QP_TOOMANY_WRS_POSTED";
- case I40E_ERR_INVALID_FRAG_COUNT:
- return "I40E_ERR_INVALID_FRAG_COUNT";
- case I40E_ERR_QUEUE_EMPTY:
- return "I40E_ERR_QUEUE_EMPTY";
- case I40E_ERR_INVALID_ALIGNMENT:
- return "I40E_ERR_INVALID_ALIGNMENT";
- case I40E_ERR_FLUSHED_QUEUE:
- return "I40E_ERR_FLUSHED_QUEUE";
- case I40E_ERR_INVALID_PUSH_PAGE_INDEX:
- return "I40E_ERR_INVALID_PUSH_PAGE_INDEX";
- case I40E_ERR_INVALID_IMM_DATA_SIZE:
- return "I40E_ERR_INVALID_IMM_DATA_SIZE";
- case I40E_ERR_TIMEOUT:
- return "I40E_ERR_TIMEOUT";
- case I40E_ERR_OPCODE_MISMATCH:
- return "I40E_ERR_OPCODE_MISMATCH";
- case I40E_ERR_CQP_COMPL_ERROR:
- return "I40E_ERR_CQP_COMPL_ERROR";
- case I40E_ERR_INVALID_VF_ID:
- return "I40E_ERR_INVALID_VF_ID";
- case I40E_ERR_INVALID_HMCFN_ID:
- return "I40E_ERR_INVALID_HMCFN_ID";
- case I40E_ERR_BACKING_PAGE_ERROR:
- return "I40E_ERR_BACKING_PAGE_ERROR";
- case I40E_ERR_NO_PBLCHUNKS_AVAILABLE:
- return "I40E_ERR_NO_PBLCHUNKS_AVAILABLE";
- case I40E_ERR_INVALID_PBLE_INDEX:
- return "I40E_ERR_INVALID_PBLE_INDEX";
- case I40E_ERR_INVALID_SD_INDEX:
- return "I40E_ERR_INVALID_SD_INDEX";
- case I40E_ERR_INVALID_PAGE_DESC_INDEX:
- return "I40E_ERR_INVALID_PAGE_DESC_INDEX";
- case I40E_ERR_INVALID_SD_TYPE:
- return "I40E_ERR_INVALID_SD_TYPE";
- case I40E_ERR_MEMCPY_FAILED:
- return "I40E_ERR_MEMCPY_FAILED";
- case I40E_ERR_INVALID_HMC_OBJ_INDEX:
- return "I40E_ERR_INVALID_HMC_OBJ_INDEX";
- case I40E_ERR_INVALID_HMC_OBJ_COUNT:
- return "I40E_ERR_INVALID_HMC_OBJ_COUNT";
- case I40E_ERR_INVALID_SRQ_ARM_LIMIT:
- return "I40E_ERR_INVALID_SRQ_ARM_LIMIT";
- case I40E_ERR_SRQ_ENABLED:
- return "I40E_ERR_SRQ_ENABLED";
- case I40E_ERR_ADMIN_QUEUE_ERROR:
- return "I40E_ERR_ADMIN_QUEUE_ERROR";
- case I40E_ERR_ADMIN_QUEUE_TIMEOUT:
- return "I40E_ERR_ADMIN_QUEUE_TIMEOUT";
- case I40E_ERR_BUF_TOO_SHORT:
- return "I40E_ERR_BUF_TOO_SHORT";
- case I40E_ERR_ADMIN_QUEUE_FULL:
- return "I40E_ERR_ADMIN_QUEUE_FULL";
- case I40E_ERR_ADMIN_QUEUE_NO_WORK:
- return "I40E_ERR_ADMIN_QUEUE_NO_WORK";
- case I40E_ERR_BAD_IWARP_CQE:
- return "I40E_ERR_BAD_IWARP_CQE";
- case I40E_ERR_NVM_BLANK_MODE:
- return "I40E_ERR_NVM_BLANK_MODE";
- case I40E_ERR_NOT_IMPLEMENTED:
- return "I40E_ERR_NOT_IMPLEMENTED";
- case I40E_ERR_PE_DOORBELL_NOT_ENABLED:
- return "I40E_ERR_PE_DOORBELL_NOT_ENABLED";
- case I40E_ERR_DIAG_TEST_FAILED:
- return "I40E_ERR_DIAG_TEST_FAILED";
- case I40E_ERR_NOT_READY:
- return "I40E_ERR_NOT_READY";
- case I40E_NOT_SUPPORTED:
- return "I40E_NOT_SUPPORTED";
- case I40E_ERR_FIRMWARE_API_VERSION:
- return "I40E_ERR_FIRMWARE_API_VERSION";
- case I40E_ERR_ADMIN_QUEUE_CRITICAL_ERROR:
- return "I40E_ERR_ADMIN_QUEUE_CRITICAL_ERROR";
+ case IAVF_ERR_NVM:
+ return "IAVF_ERR_NVM";
+ case IAVF_ERR_NVM_CHECKSUM:
+ return "IAVF_ERR_NVM_CHECKSUM";
+ case IAVF_ERR_PHY:
+ return "IAVF_ERR_PHY";
+ case IAVF_ERR_CONFIG:
+ return "IAVF_ERR_CONFIG";
+ case IAVF_ERR_PARAM:
+ return "IAVF_ERR_PARAM";
+ case IAVF_ERR_MAC_TYPE:
+ return "IAVF_ERR_MAC_TYPE";
+ case IAVF_ERR_UNKNOWN_PHY:
+ return "IAVF_ERR_UNKNOWN_PHY";
+ case IAVF_ERR_LINK_SETUP:
+ return "IAVF_ERR_LINK_SETUP";
+ case IAVF_ERR_ADAPTER_STOPPED:
+ return "IAVF_ERR_ADAPTER_STOPPED";
+ case IAVF_ERR_INVALID_MAC_ADDR:
+ return "IAVF_ERR_INVALID_MAC_ADDR";
+ case IAVF_ERR_DEVICE_NOT_SUPPORTED:
+ return "IAVF_ERR_DEVICE_NOT_SUPPORTED";
+ case IAVF_ERR_MASTER_REQUESTS_PENDING:
+ return "IAVF_ERR_MASTER_REQUESTS_PENDING";
+ case IAVF_ERR_INVALID_LINK_SETTINGS:
+ return "IAVF_ERR_INVALID_LINK_SETTINGS";
+ case IAVF_ERR_AUTONEG_NOT_COMPLETE:
+ return "IAVF_ERR_AUTONEG_NOT_COMPLETE";
+ case IAVF_ERR_RESET_FAILED:
+ return "IAVF_ERR_RESET_FAILED";
+ case IAVF_ERR_SWFW_SYNC:
+ return "IAVF_ERR_SWFW_SYNC";
+ case IAVF_ERR_NO_AVAILABLE_VSI:
+ return "IAVF_ERR_NO_AVAILABLE_VSI";
+ case IAVF_ERR_NO_MEMORY:
+ return "IAVF_ERR_NO_MEMORY";
+ case IAVF_ERR_BAD_PTR:
+ return "IAVF_ERR_BAD_PTR";
+ case IAVF_ERR_RING_FULL:
+ return "IAVF_ERR_RING_FULL";
+ case IAVF_ERR_INVALID_PD_ID:
+ return "IAVF_ERR_INVALID_PD_ID";
+ case IAVF_ERR_INVALID_QP_ID:
+ return "IAVF_ERR_INVALID_QP_ID";
+ case IAVF_ERR_INVALID_CQ_ID:
+ return "IAVF_ERR_INVALID_CQ_ID";
+ case IAVF_ERR_INVALID_CEQ_ID:
+ return "IAVF_ERR_INVALID_CEQ_ID";
+ case IAVF_ERR_INVALID_AEQ_ID:
+ return "IAVF_ERR_INVALID_AEQ_ID";
+ case IAVF_ERR_INVALID_SIZE:
+ return "IAVF_ERR_INVALID_SIZE";
+ case IAVF_ERR_INVALID_ARP_INDEX:
+ return "IAVF_ERR_INVALID_ARP_INDEX";
+ case IAVF_ERR_INVALID_FPM_FUNC_ID:
+ return "IAVF_ERR_INVALID_FPM_FUNC_ID";
+ case IAVF_ERR_QP_INVALID_MSG_SIZE:
+ return "IAVF_ERR_QP_INVALID_MSG_SIZE";
+ case IAVF_ERR_QP_TOOMANY_WRS_POSTED:
+ return "IAVF_ERR_QP_TOOMANY_WRS_POSTED";
+ case IAVF_ERR_INVALID_FRAG_COUNT:
+ return "IAVF_ERR_INVALID_FRAG_COUNT";
+ case IAVF_ERR_QUEUE_EMPTY:
+ return "IAVF_ERR_QUEUE_EMPTY";
+ case IAVF_ERR_INVALID_ALIGNMENT:
+ return "IAVF_ERR_INVALID_ALIGNMENT";
+ case IAVF_ERR_FLUSHED_QUEUE:
+ return "IAVF_ERR_FLUSHED_QUEUE";
+ case IAVF_ERR_INVALID_PUSH_PAGE_INDEX:
+ return "IAVF_ERR_INVALID_PUSH_PAGE_INDEX";
+ case IAVF_ERR_INVALID_IMM_DATA_SIZE:
+ return "IAVF_ERR_INVALID_IMM_DATA_SIZE";
+ case IAVF_ERR_TIMEOUT:
+ return "IAVF_ERR_TIMEOUT";
+ case IAVF_ERR_OPCODE_MISMATCH:
+ return "IAVF_ERR_OPCODE_MISMATCH";
+ case IAVF_ERR_CQP_COMPL_ERROR:
+ return "IAVF_ERR_CQP_COMPL_ERROR";
+ case IAVF_ERR_INVALID_VF_ID:
+ return "IAVF_ERR_INVALID_VF_ID";
+ case IAVF_ERR_INVALID_HMCFN_ID:
+ return "IAVF_ERR_INVALID_HMCFN_ID";
+ case IAVF_ERR_BACKING_PAGE_ERROR:
+ return "IAVF_ERR_BACKING_PAGE_ERROR";
+ case IAVF_ERR_NO_PBLCHUNKS_AVAILABLE:
+ return "IAVF_ERR_NO_PBLCHUNKS_AVAILABLE";
+ case IAVF_ERR_INVALID_PBLE_INDEX:
+ return "IAVF_ERR_INVALID_PBLE_INDEX";
+ case IAVF_ERR_INVALID_SD_INDEX:
+ return "IAVF_ERR_INVALID_SD_INDEX";
+ case IAVF_ERR_INVALID_PAGE_DESC_INDEX:
+ return "IAVF_ERR_INVALID_PAGE_DESC_INDEX";
+ case IAVF_ERR_INVALID_SD_TYPE:
+ return "IAVF_ERR_INVALID_SD_TYPE";
+ case IAVF_ERR_MEMCPY_FAILED:
+ return "IAVF_ERR_MEMCPY_FAILED";
+ case IAVF_ERR_INVALID_HMC_OBJ_INDEX:
+ return "IAVF_ERR_INVALID_HMC_OBJ_INDEX";
+ case IAVF_ERR_INVALID_HMC_OBJ_COUNT:
+ return "IAVF_ERR_INVALID_HMC_OBJ_COUNT";
+ case IAVF_ERR_INVALID_SRQ_ARM_LIMIT:
+ return "IAVF_ERR_INVALID_SRQ_ARM_LIMIT";
+ case IAVF_ERR_SRQ_ENABLED:
+ return "IAVF_ERR_SRQ_ENABLED";
+ case IAVF_ERR_ADMIN_QUEUE_ERROR:
+ return "IAVF_ERR_ADMIN_QUEUE_ERROR";
+ case IAVF_ERR_ADMIN_QUEUE_TIMEOUT:
+ return "IAVF_ERR_ADMIN_QUEUE_TIMEOUT";
+ case IAVF_ERR_BUF_TOO_SHORT:
+ return "IAVF_ERR_BUF_TOO_SHORT";
+ case IAVF_ERR_ADMIN_QUEUE_FULL:
+ return "IAVF_ERR_ADMIN_QUEUE_FULL";
+ case IAVF_ERR_ADMIN_QUEUE_NO_WORK:
+ return "IAVF_ERR_ADMIN_QUEUE_NO_WORK";
+ case IAVF_ERR_BAD_IWARP_CQE:
+ return "IAVF_ERR_BAD_IWARP_CQE";
+ case IAVF_ERR_NVM_BLANK_MODE:
+ return "IAVF_ERR_NVM_BLANK_MODE";
+ case IAVF_ERR_NOT_IMPLEMENTED:
+ return "IAVF_ERR_NOT_IMPLEMENTED";
+ case IAVF_ERR_PE_DOORBELL_NOT_ENABLED:
+ return "IAVF_ERR_PE_DOORBELL_NOT_ENABLED";
+ case IAVF_ERR_DIAG_TEST_FAILED:
+ return "IAVF_ERR_DIAG_TEST_FAILED";
+ case IAVF_ERR_NOT_READY:
+ return "IAVF_ERR_NOT_READY";
+ case IAVF_NOT_SUPPORTED:
+ return "IAVF_NOT_SUPPORTED";
+ case IAVF_ERR_FIRMWARE_API_VERSION:
+ return "IAVF_ERR_FIRMWARE_API_VERSION";
+ case IAVF_ERR_ADMIN_QUEUE_CRITICAL_ERROR:
+ return "IAVF_ERR_ADMIN_QUEUE_CRITICAL_ERROR";
}
snprintf(hw->err_str, sizeof(hw->err_str), "%d", stat_err);
@@ -260,7 +260,7 @@ const char *iavf_stat_str(struct iavf_hw *hw, iavf_status stat_err)
void iavf_debug_aq(struct iavf_hw *hw, enum iavf_debug_mask mask, void *desc,
void *buffer, u16 buf_len)
{
- struct i40e_aq_desc *aq_desc = (struct i40e_aq_desc *)desc;
+ struct iavf_aq_desc *aq_desc = (struct iavf_aq_desc *)desc;
u8 *buf = (u8 *)buffer;
if ((!(mask & hw->debug_mask)) || !desc)
@@ -327,17 +327,17 @@ bool iavf_check_asq_alive(struct iavf_hw *hw)
* Tell the Firmware that we're shutting down the AdminQ and whether
* or not the driver is unloading as well.
**/
-iavf_status iavf_aq_queue_shutdown(struct iavf_hw *hw, bool unloading)
+enum iavf_status iavf_aq_queue_shutdown(struct iavf_hw *hw, bool unloading)
{
- struct i40e_aq_desc desc;
- struct i40e_aqc_queue_shutdown *cmd =
- (struct i40e_aqc_queue_shutdown *)&desc.params.raw;
- iavf_status status;
+ struct iavf_aq_desc desc;
+ struct iavf_aqc_queue_shutdown *cmd =
+ (struct iavf_aqc_queue_shutdown *)&desc.params.raw;
+ enum iavf_status status;
- iavf_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_queue_shutdown);
+ iavf_fill_default_direct_cmd_desc(&desc, iavf_aqc_opc_queue_shutdown);
if (unloading)
- cmd->driver_unloading = cpu_to_le32(I40E_AQ_DRIVER_UNLOADING);
+ cmd->driver_unloading = cpu_to_le32(IAVF_AQ_DRIVER_UNLOADING);
status = iavf_asq_send_command(hw, &desc, NULL, 0, NULL);
return status;
@@ -354,43 +354,43 @@ iavf_status iavf_aq_queue_shutdown(struct iavf_hw *hw, bool unloading)
*
* Internal function to get or set RSS look up table
**/
-static iavf_status iavf_aq_get_set_rss_lut(struct iavf_hw *hw,
- u16 vsi_id, bool pf_lut,
- u8 *lut, u16 lut_size,
- bool set)
+static enum iavf_status iavf_aq_get_set_rss_lut(struct iavf_hw *hw,
+ u16 vsi_id, bool pf_lut,
+ u8 *lut, u16 lut_size,
+ bool set)
{
- iavf_status status;
- struct i40e_aq_desc desc;
- struct i40e_aqc_get_set_rss_lut *cmd_resp =
- (struct i40e_aqc_get_set_rss_lut *)&desc.params.raw;
+ enum iavf_status status;
+ struct iavf_aq_desc desc;
+ struct iavf_aqc_get_set_rss_lut *cmd_resp =
+ (struct iavf_aqc_get_set_rss_lut *)&desc.params.raw;
if (set)
iavf_fill_default_direct_cmd_desc(&desc,
- i40e_aqc_opc_set_rss_lut);
+ iavf_aqc_opc_set_rss_lut);
else
iavf_fill_default_direct_cmd_desc(&desc,
- i40e_aqc_opc_get_rss_lut);
+ iavf_aqc_opc_get_rss_lut);
/* Indirect command */
- desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF);
- desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_RD);
+ desc.flags |= cpu_to_le16((u16)IAVF_AQ_FLAG_BUF);
+ desc.flags |= cpu_to_le16((u16)IAVF_AQ_FLAG_RD);
cmd_resp->vsi_id =
cpu_to_le16((u16)((vsi_id <<
- I40E_AQC_SET_RSS_LUT_VSI_ID_SHIFT) &
- I40E_AQC_SET_RSS_LUT_VSI_ID_MASK));
- cmd_resp->vsi_id |= cpu_to_le16((u16)I40E_AQC_SET_RSS_LUT_VSI_VALID);
+ IAVF_AQC_SET_RSS_LUT_VSI_ID_SHIFT) &
+ IAVF_AQC_SET_RSS_LUT_VSI_ID_MASK));
+ cmd_resp->vsi_id |= cpu_to_le16((u16)IAVF_AQC_SET_RSS_LUT_VSI_VALID);
if (pf_lut)
cmd_resp->flags |= cpu_to_le16((u16)
- ((I40E_AQC_SET_RSS_LUT_TABLE_TYPE_PF <<
- I40E_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT) &
- I40E_AQC_SET_RSS_LUT_TABLE_TYPE_MASK));
+ ((IAVF_AQC_SET_RSS_LUT_TABLE_TYPE_PF <<
+ IAVF_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT) &
+ IAVF_AQC_SET_RSS_LUT_TABLE_TYPE_MASK));
else
cmd_resp->flags |= cpu_to_le16((u16)
- ((I40E_AQC_SET_RSS_LUT_TABLE_TYPE_VSI <<
- I40E_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT) &
- I40E_AQC_SET_RSS_LUT_TABLE_TYPE_MASK));
+ ((IAVF_AQC_SET_RSS_LUT_TABLE_TYPE_VSI <<
+ IAVF_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT) &
+ IAVF_AQC_SET_RSS_LUT_TABLE_TYPE_MASK));
status = iavf_asq_send_command(hw, &desc, lut, lut_size, NULL);
@@ -407,8 +407,8 @@ static iavf_status iavf_aq_get_set_rss_lut(struct iavf_hw *hw,
*
* get the RSS lookup table, PF or VSI type
**/
-iavf_status iavf_aq_get_rss_lut(struct iavf_hw *hw, u16 vsi_id,
- bool pf_lut, u8 *lut, u16 lut_size)
+enum iavf_status iavf_aq_get_rss_lut(struct iavf_hw *hw, u16 vsi_id,
+ bool pf_lut, u8 *lut, u16 lut_size)
{
return iavf_aq_get_set_rss_lut(hw, vsi_id, pf_lut, lut, lut_size,
false);
@@ -424,8 +424,8 @@ iavf_status iavf_aq_get_rss_lut(struct iavf_hw *hw, u16 vsi_id,
*
* set the RSS lookup table, PF or VSI type
**/
-iavf_status iavf_aq_set_rss_lut(struct iavf_hw *hw, u16 vsi_id,
- bool pf_lut, u8 *lut, u16 lut_size)
+enum iavf_status iavf_aq_set_rss_lut(struct iavf_hw *hw, u16 vsi_id,
+ bool pf_lut, u8 *lut, u16 lut_size)
{
return iavf_aq_get_set_rss_lut(hw, vsi_id, pf_lut, lut, lut_size, true);
}
@@ -439,33 +439,33 @@ iavf_status iavf_aq_set_rss_lut(struct iavf_hw *hw, u16 vsi_id,
*
* get the RSS key per VSI
**/
-static
+static enum
iavf_status iavf_aq_get_set_rss_key(struct iavf_hw *hw, u16 vsi_id,
- struct i40e_aqc_get_set_rss_key_data *key,
+ struct iavf_aqc_get_set_rss_key_data *key,
bool set)
{
- iavf_status status;
- struct i40e_aq_desc desc;
- struct i40e_aqc_get_set_rss_key *cmd_resp =
- (struct i40e_aqc_get_set_rss_key *)&desc.params.raw;
- u16 key_size = sizeof(struct i40e_aqc_get_set_rss_key_data);
+ enum iavf_status status;
+ struct iavf_aq_desc desc;
+ struct iavf_aqc_get_set_rss_key *cmd_resp =
+ (struct iavf_aqc_get_set_rss_key *)&desc.params.raw;
+ u16 key_size = sizeof(struct iavf_aqc_get_set_rss_key_data);
if (set)
iavf_fill_default_direct_cmd_desc(&desc,
- i40e_aqc_opc_set_rss_key);
+ iavf_aqc_opc_set_rss_key);
else
iavf_fill_default_direct_cmd_desc(&desc,
- i40e_aqc_opc_get_rss_key);
+ iavf_aqc_opc_get_rss_key);
/* Indirect command */
- desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF);
- desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_RD);
+ desc.flags |= cpu_to_le16((u16)IAVF_AQ_FLAG_BUF);
+ desc.flags |= cpu_to_le16((u16)IAVF_AQ_FLAG_RD);
cmd_resp->vsi_id =
cpu_to_le16((u16)((vsi_id <<
- I40E_AQC_SET_RSS_KEY_VSI_ID_SHIFT) &
- I40E_AQC_SET_RSS_KEY_VSI_ID_MASK));
- cmd_resp->vsi_id |= cpu_to_le16((u16)I40E_AQC_SET_RSS_KEY_VSI_VALID);
+ IAVF_AQC_SET_RSS_KEY_VSI_ID_SHIFT) &
+ IAVF_AQC_SET_RSS_KEY_VSI_ID_MASK));
+ cmd_resp->vsi_id |= cpu_to_le16((u16)IAVF_AQC_SET_RSS_KEY_VSI_VALID);
status = iavf_asq_send_command(hw, &desc, key, key_size, NULL);
@@ -479,8 +479,8 @@ iavf_status iavf_aq_get_set_rss_key(struct iavf_hw *hw, u16 vsi_id,
* @key: pointer to key info struct
*
**/
-iavf_status iavf_aq_get_rss_key(struct iavf_hw *hw, u16 vsi_id,
- struct i40e_aqc_get_set_rss_key_data *key)
+enum iavf_status iavf_aq_get_rss_key(struct iavf_hw *hw, u16 vsi_id,
+ struct iavf_aqc_get_set_rss_key_data *key)
{
return iavf_aq_get_set_rss_key(hw, vsi_id, key, false);
}
@@ -493,8 +493,8 @@ iavf_status iavf_aq_get_rss_key(struct iavf_hw *hw, u16 vsi_id,
*
* set the RSS key per VSI
**/
-iavf_status iavf_aq_set_rss_key(struct iavf_hw *hw, u16 vsi_id,
- struct i40e_aqc_get_set_rss_key_data *key)
+enum iavf_status iavf_aq_set_rss_key(struct iavf_hw *hw, u16 vsi_id,
+ struct iavf_aqc_get_set_rss_key_data *key)
{
return iavf_aq_get_set_rss_key(hw, vsi_id, key, true);
}
@@ -515,7 +515,7 @@ iavf_status iavf_aq_set_rss_key(struct iavf_hw *hw, u16 vsi_id,
* IF NOT iavf_ptype_lookup[ptype].known
* THEN
* Packet is unknown
- * ELSE IF iavf_ptype_lookup[ptype].outer_ip == I40E_RX_PTYPE_OUTER_IP
+ * ELSE IF iavf_ptype_lookup[ptype].outer_ip == IAVF_RX_PTYPE_OUTER_IP
* Use the rest of the fields to look at the tunnels, inner protocols, etc
* ELSE
* Use the enum iavf_rx_l2_ptype to decode the packet type
@@ -877,24 +877,25 @@ struct iavf_rx_ptype_decoded iavf_ptype_lookup[] = {
* is sent asynchronously, i.e. iavf_asq_send_command() does not wait for
* completion before returning.
**/
-iavf_status iavf_aq_send_msg_to_pf(struct iavf_hw *hw,
- enum virtchnl_ops v_opcode,
- iavf_status v_retval, u8 *msg, u16 msglen,
- struct i40e_asq_cmd_details *cmd_details)
+enum iavf_status iavf_aq_send_msg_to_pf(struct iavf_hw *hw,
+ enum virtchnl_ops v_opcode,
+ enum iavf_status v_retval,
+ u8 *msg, u16 msglen,
+ struct iavf_asq_cmd_details *cmd_details)
{
- struct i40e_asq_cmd_details details;
- struct i40e_aq_desc desc;
- iavf_status status;
+ struct iavf_asq_cmd_details details;
+ struct iavf_aq_desc desc;
+ enum iavf_status status;
- iavf_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_send_msg_to_pf);
- desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_SI);
+ iavf_fill_default_direct_cmd_desc(&desc, iavf_aqc_opc_send_msg_to_pf);
+ desc.flags |= cpu_to_le16((u16)IAVF_AQ_FLAG_SI);
desc.cookie_high = cpu_to_le32(v_opcode);
desc.cookie_low = cpu_to_le32(v_retval);
if (msglen) {
- desc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF
- | I40E_AQ_FLAG_RD));
- if (msglen > I40E_AQ_LARGE_BUF)
- desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);
+ desc.flags |= cpu_to_le16((u16)(IAVF_AQ_FLAG_BUF
+ | IAVF_AQ_FLAG_RD));
+ if (msglen > IAVF_AQ_LARGE_BUF)
+ desc.flags |= cpu_to_le16((u16)IAVF_AQ_FLAG_LB);
desc.datalen = cpu_to_le16(msglen);
}
if (!cmd_details) {
@@ -948,7 +949,7 @@ void iavf_vf_parse_hw_config(struct iavf_hw *hw,
* as none will be forthcoming. Immediately after calling this function,
* the admin queue should be shut down and (optionally) reinitialized.
**/
-iavf_status iavf_vf_reset(struct iavf_hw *hw)
+enum iavf_status iavf_vf_reset(struct iavf_hw *hw)
{
return iavf_aq_send_msg_to_pf(hw, VIRTCHNL_OP_RESET_VF,
0, NULL, 0, NULL);
diff --git a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
index 9f87304109fe..dad3eec8ccd8 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
@@ -280,10 +280,10 @@ static int iavf_get_link_ksettings(struct net_device *netdev,
cmd->base.port = PORT_NONE;
/* Set speed and duplex */
switch (adapter->link_speed) {
- case I40E_LINK_SPEED_40GB:
+ case IAVF_LINK_SPEED_40GB:
cmd->base.speed = SPEED_40000;
break;
- case I40E_LINK_SPEED_25GB:
+ case IAVF_LINK_SPEED_25GB:
#ifdef SPEED_25000
cmd->base.speed = SPEED_25000;
#else
@@ -291,16 +291,16 @@ static int iavf_get_link_ksettings(struct net_device *netdev,
"Speed is 25G, display not supported by this version of ethtool.\n");
#endif
break;
- case I40E_LINK_SPEED_20GB:
+ case IAVF_LINK_SPEED_20GB:
cmd->base.speed = SPEED_20000;
break;
- case I40E_LINK_SPEED_10GB:
+ case IAVF_LINK_SPEED_10GB:
cmd->base.speed = SPEED_10000;
break;
- case I40E_LINK_SPEED_1GB:
+ case IAVF_LINK_SPEED_1GB:
cmd->base.speed = SPEED_1000;
break;
- case I40E_LINK_SPEED_100MB:
+ case IAVF_LINK_SPEED_100MB:
cmd->base.speed = SPEED_100;
break;
default:
@@ -510,7 +510,7 @@ static int iavf_set_priv_flags(struct net_device *netdev, u32 flags)
if (changed_flags & IAVF_FLAG_LEGACY_RX) {
if (netif_running(netdev)) {
adapter->flags |= IAVF_FLAG_RESET_NEEDED;
- schedule_work(&adapter->reset_task);
+ queue_work(iavf_wq, &adapter->reset_task);
}
}
@@ -622,7 +622,7 @@ static int iavf_set_ringparam(struct net_device *netdev,
if (netif_running(netdev)) {
adapter->flags |= IAVF_FLAG_RESET_NEEDED;
- schedule_work(&adapter->reset_task);
+ queue_work(iavf_wq, &adapter->reset_task);
}
return 0;
diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c
index 4569d69a2b55..9d2b50964a08 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_main.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
@@ -14,6 +14,8 @@
static int iavf_setup_all_tx_resources(struct iavf_adapter *adapter);
static int iavf_setup_all_rx_resources(struct iavf_adapter *adapter);
static int iavf_close(struct net_device *netdev);
+static int iavf_init_get_resources(struct iavf_adapter *adapter);
+static int iavf_check_reset_complete(struct iavf_hw *hw);
char iavf_driver_name[] = "iavf";
static const char iavf_driver_string[] =
@@ -57,7 +59,8 @@ MODULE_DESCRIPTION("Intel(R) Ethernet Adaptive Virtual Function Network Driver")
MODULE_LICENSE("GPL v2");
MODULE_VERSION(DRV_VERSION);
-static struct workqueue_struct *iavf_wq;
+static const struct net_device_ops iavf_netdev_ops;
+struct workqueue_struct *iavf_wq;
/**
* iavf_allocate_dma_mem_d - OS specific memory alloc for shared code
@@ -66,14 +69,14 @@ static struct workqueue_struct *iavf_wq;
* @size: size of memory requested
* @alignment: what to align the allocation to
**/
-iavf_status iavf_allocate_dma_mem_d(struct iavf_hw *hw,
- struct iavf_dma_mem *mem,
- u64 size, u32 alignment)
+enum iavf_status iavf_allocate_dma_mem_d(struct iavf_hw *hw,
+ struct iavf_dma_mem *mem,
+ u64 size, u32 alignment)
{
struct iavf_adapter *adapter = (struct iavf_adapter *)hw->back;
if (!mem)
- return I40E_ERR_PARAM;
+ return IAVF_ERR_PARAM;
mem->size = ALIGN(size, alignment);
mem->va = dma_alloc_coherent(&adapter->pdev->dev, mem->size,
@@ -81,7 +84,7 @@ iavf_status iavf_allocate_dma_mem_d(struct iavf_hw *hw,
if (mem->va)
return 0;
else
- return I40E_ERR_NO_MEMORY;
+ return IAVF_ERR_NO_MEMORY;
}
/**
@@ -89,12 +92,13 @@ iavf_status iavf_allocate_dma_mem_d(struct iavf_hw *hw,
* @hw: pointer to the HW structure
* @mem: ptr to mem struct to free
**/
-iavf_status iavf_free_dma_mem_d(struct iavf_hw *hw, struct iavf_dma_mem *mem)
+enum iavf_status iavf_free_dma_mem_d(struct iavf_hw *hw,
+ struct iavf_dma_mem *mem)
{
struct iavf_adapter *adapter = (struct iavf_adapter *)hw->back;
if (!mem || !mem->va)
- return I40E_ERR_PARAM;
+ return IAVF_ERR_PARAM;
dma_free_coherent(&adapter->pdev->dev, mem->size,
mem->va, (dma_addr_t)mem->pa);
return 0;
@@ -106,11 +110,11 @@ iavf_status iavf_free_dma_mem_d(struct iavf_hw *hw, struct iavf_dma_mem *mem)
* @mem: ptr to mem struct to fill out
* @size: size of memory requested
**/
-iavf_status iavf_allocate_virt_mem_d(struct iavf_hw *hw,
- struct iavf_virt_mem *mem, u32 size)
+enum iavf_status iavf_allocate_virt_mem_d(struct iavf_hw *hw,
+ struct iavf_virt_mem *mem, u32 size)
{
if (!mem)
- return I40E_ERR_PARAM;
+ return IAVF_ERR_PARAM;
mem->size = size;
mem->va = kzalloc(size, GFP_KERNEL);
@@ -118,7 +122,7 @@ iavf_status iavf_allocate_virt_mem_d(struct iavf_hw *hw,
if (mem->va)
return 0;
else
- return I40E_ERR_NO_MEMORY;
+ return IAVF_ERR_NO_MEMORY;
}
/**
@@ -126,10 +130,11 @@ iavf_status iavf_allocate_virt_mem_d(struct iavf_hw *hw,
* @hw: pointer to the HW structure
* @mem: ptr to mem struct to free
**/
-iavf_status iavf_free_virt_mem_d(struct iavf_hw *hw, struct iavf_virt_mem *mem)
+enum iavf_status iavf_free_virt_mem_d(struct iavf_hw *hw,
+ struct iavf_virt_mem *mem)
{
if (!mem)
- return I40E_ERR_PARAM;
+ return IAVF_ERR_PARAM;
/* it's ok to kfree a NULL pointer */
kfree(mem->va);
@@ -168,7 +173,7 @@ void iavf_schedule_reset(struct iavf_adapter *adapter)
if (!(adapter->flags &
(IAVF_FLAG_RESET_PENDING | IAVF_FLAG_RESET_NEEDED))) {
adapter->flags |= IAVF_FLAG_RESET_NEEDED;
- schedule_work(&adapter->reset_task);
+ queue_work(iavf_wq, &adapter->reset_task);
}
}
@@ -287,7 +292,7 @@ static irqreturn_t iavf_msix_aq(int irq, void *data)
rd32(hw, IAVF_VFINT_ICR0_ENA1);
/* schedule work on the private workqueue */
- schedule_work(&adapter->adminq_task);
+ queue_work(iavf_wq, &adapter->adminq_task);
return IRQ_HANDLED;
}
@@ -657,14 +662,13 @@ iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter, u16 vlan)
f = iavf_find_vlan(adapter, vlan);
if (!f) {
- f = kzalloc(sizeof(*f), GFP_KERNEL);
+ f = kzalloc(sizeof(*f), GFP_ATOMIC);
if (!f)
goto clearout;
f->vlan = vlan;
- INIT_LIST_HEAD(&f->list);
- list_add(&f->list, &adapter->vlan_filter_list);
+ list_add_tail(&f->list, &adapter->vlan_filter_list);
f->add = true;
adapter->aq_required |= IAVF_FLAG_AQ_ADD_VLAN_FILTER;
}
@@ -979,7 +983,7 @@ static void iavf_up_complete(struct iavf_adapter *adapter)
adapter->aq_required |= IAVF_FLAG_AQ_ENABLE_QUEUES;
if (CLIENT_ENABLED(adapter))
adapter->flags |= IAVF_FLAG_CLIENT_NEEDS_OPEN;
- mod_timer_pending(&adapter->watchdog_timer, jiffies + 1);
+ mod_delayed_work(iavf_wq, &adapter->watchdog_task, 0);
}
/**
@@ -1043,7 +1047,7 @@ void iavf_down(struct iavf_adapter *adapter)
adapter->aq_required |= IAVF_FLAG_AQ_DISABLE_QUEUES;
}
- mod_timer_pending(&adapter->watchdog_timer, jiffies + 1);
+ mod_delayed_work(iavf_wq, &adapter->watchdog_task, 0);
}
/**
@@ -1227,8 +1231,8 @@ out:
**/
static int iavf_config_rss_aq(struct iavf_adapter *adapter)
{
- struct i40e_aqc_get_set_rss_key_data *rss_key =
- (struct i40e_aqc_get_set_rss_key_data *)adapter->rss_key;
+ struct iavf_aqc_get_set_rss_key_data *rss_key =
+ (struct iavf_aqc_get_set_rss_key_data *)adapter->rss_key;
struct iavf_hw *hw = &adapter->hw;
int ret = 0;
@@ -1532,136 +1536,66 @@ err:
}
/**
- * iavf_watchdog_timer - Periodic call-back timer
- * @data: pointer to adapter disguised as unsigned long
- **/
-static void iavf_watchdog_timer(struct timer_list *t)
-{
- struct iavf_adapter *adapter = from_timer(adapter, t,
- watchdog_timer);
-
- schedule_work(&adapter->watchdog_task);
- /* timer will be rescheduled in watchdog task */
-}
-
-/**
- * iavf_watchdog_task - Periodic call-back task
- * @work: pointer to work_struct
+ * iavf_process_aq_command - process aq_required flags
+ * and sends aq command
+ * @adapter: pointer to iavf adapter structure
+ *
+ * Returns 0 on success
+ * Returns error code if no command was sent
+ * or error code if the command failed.
**/
-static void iavf_watchdog_task(struct work_struct *work)
+static int iavf_process_aq_command(struct iavf_adapter *adapter)
{
- struct iavf_adapter *adapter = container_of(work,
- struct iavf_adapter,
- watchdog_task);
- struct iavf_hw *hw = &adapter->hw;
- u32 reg_val;
-
- if (test_and_set_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section))
- goto restart_watchdog;
-
- if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED) {
- reg_val = rd32(hw, IAVF_VFGEN_RSTAT) &
- IAVF_VFGEN_RSTAT_VFR_STATE_MASK;
- if ((reg_val == VIRTCHNL_VFR_VFACTIVE) ||
- (reg_val == VIRTCHNL_VFR_COMPLETED)) {
- /* A chance for redemption! */
- dev_err(&adapter->pdev->dev, "Hardware came out of reset. Attempting reinit.\n");
- adapter->state = __IAVF_STARTUP;
- adapter->flags &= ~IAVF_FLAG_PF_COMMS_FAILED;
- schedule_delayed_work(&adapter->init_task, 10);
- clear_bit(__IAVF_IN_CRITICAL_TASK,
- &adapter->crit_section);
- /* Don't reschedule the watchdog, since we've restarted
- * the init task. When init_task contacts the PF and
- * gets everything set up again, it'll restart the
- * watchdog for us. Down, boy. Sit. Stay. Woof.
- */
- return;
- }
- adapter->aq_required = 0;
- adapter->current_op = VIRTCHNL_OP_UNKNOWN;
- goto watchdog_done;
- }
-
- if ((adapter->state < __IAVF_DOWN) ||
- (adapter->flags & IAVF_FLAG_RESET_PENDING))
- goto watchdog_done;
-
- /* check for reset */
- reg_val = rd32(hw, IAVF_VF_ARQLEN1) & IAVF_VF_ARQLEN1_ARQENABLE_MASK;
- if (!(adapter->flags & IAVF_FLAG_RESET_PENDING) && !reg_val) {
- adapter->state = __IAVF_RESETTING;
- adapter->flags |= IAVF_FLAG_RESET_PENDING;
- dev_err(&adapter->pdev->dev, "Hardware reset detected\n");
- schedule_work(&adapter->reset_task);
- adapter->aq_required = 0;
- adapter->current_op = VIRTCHNL_OP_UNKNOWN;
- goto watchdog_done;
- }
-
- /* Process admin queue tasks. After init, everything gets done
- * here so we don't race on the admin queue.
- */
- if (adapter->current_op) {
- if (!iavf_asq_done(hw)) {
- dev_dbg(&adapter->pdev->dev, "Admin queue timeout\n");
- iavf_send_api_ver(adapter);
- }
- goto watchdog_done;
- }
- if (adapter->aq_required & IAVF_FLAG_AQ_GET_CONFIG) {
- iavf_send_vf_config_msg(adapter);
- goto watchdog_done;
- }
-
+ if (adapter->aq_required & IAVF_FLAG_AQ_GET_CONFIG)
+ return iavf_send_vf_config_msg(adapter);
if (adapter->aq_required & IAVF_FLAG_AQ_DISABLE_QUEUES) {
iavf_disable_queues(adapter);
- goto watchdog_done;
+ return 0;
}
if (adapter->aq_required & IAVF_FLAG_AQ_MAP_VECTORS) {
iavf_map_queues(adapter);
- goto watchdog_done;
+ return 0;
}
if (adapter->aq_required & IAVF_FLAG_AQ_ADD_MAC_FILTER) {
iavf_add_ether_addrs(adapter);
- goto watchdog_done;
+ return 0;
}
if (adapter->aq_required & IAVF_FLAG_AQ_ADD_VLAN_FILTER) {
iavf_add_vlans(adapter);
- goto watchdog_done;
+ return 0;
}
if (adapter->aq_required & IAVF_FLAG_AQ_DEL_MAC_FILTER) {
iavf_del_ether_addrs(adapter);
- goto watchdog_done;
+ return 0;
}
if (adapter->aq_required & IAVF_FLAG_AQ_DEL_VLAN_FILTER) {
iavf_del_vlans(adapter);
- goto watchdog_done;
+ return 0;
}
if (adapter->aq_required & IAVF_FLAG_AQ_ENABLE_VLAN_STRIPPING) {
iavf_enable_vlan_stripping(adapter);
- goto watchdog_done;
+ return 0;
}
if (adapter->aq_required & IAVF_FLAG_AQ_DISABLE_VLAN_STRIPPING) {
iavf_disable_vlan_stripping(adapter);
- goto watchdog_done;
+ return 0;
}
if (adapter->aq_required & IAVF_FLAG_AQ_CONFIGURE_QUEUES) {
iavf_configure_queues(adapter);
- goto watchdog_done;
+ return 0;
}
if (adapter->aq_required & IAVF_FLAG_AQ_ENABLE_QUEUES) {
iavf_enable_queues(adapter);
- goto watchdog_done;
+ return 0;
}
if (adapter->aq_required & IAVF_FLAG_AQ_CONFIGURE_RSS) {
@@ -1669,81 +1603,414 @@ static void iavf_watchdog_task(struct work_struct *work)
* PF, so we don't have to set current_op as we will
* not get a response through the ARQ.
*/
- iavf_init_rss(adapter);
adapter->aq_required &= ~IAVF_FLAG_AQ_CONFIGURE_RSS;
- goto watchdog_done;
+ return 0;
}
if (adapter->aq_required & IAVF_FLAG_AQ_GET_HENA) {
iavf_get_hena(adapter);
- goto watchdog_done;
+ return 0;
}
if (adapter->aq_required & IAVF_FLAG_AQ_SET_HENA) {
iavf_set_hena(adapter);
- goto watchdog_done;
+ return 0;
}
if (adapter->aq_required & IAVF_FLAG_AQ_SET_RSS_KEY) {
iavf_set_rss_key(adapter);
- goto watchdog_done;
+ return 0;
}
if (adapter->aq_required & IAVF_FLAG_AQ_SET_RSS_LUT) {
iavf_set_rss_lut(adapter);
- goto watchdog_done;
+ return 0;
}
if (adapter->aq_required & IAVF_FLAG_AQ_REQUEST_PROMISC) {
iavf_set_promiscuous(adapter, FLAG_VF_UNICAST_PROMISC |
FLAG_VF_MULTICAST_PROMISC);
- goto watchdog_done;
+ return 0;
}
if (adapter->aq_required & IAVF_FLAG_AQ_REQUEST_ALLMULTI) {
iavf_set_promiscuous(adapter, FLAG_VF_MULTICAST_PROMISC);
- goto watchdog_done;
+ return 0;
}
if ((adapter->aq_required & IAVF_FLAG_AQ_RELEASE_PROMISC) &&
(adapter->aq_required & IAVF_FLAG_AQ_RELEASE_ALLMULTI)) {
iavf_set_promiscuous(adapter, 0);
- goto watchdog_done;
+ return 0;
}
if (adapter->aq_required & IAVF_FLAG_AQ_ENABLE_CHANNELS) {
iavf_enable_channels(adapter);
- goto watchdog_done;
+ return 0;
}
if (adapter->aq_required & IAVF_FLAG_AQ_DISABLE_CHANNELS) {
iavf_disable_channels(adapter);
- goto watchdog_done;
+ return 0;
}
-
if (adapter->aq_required & IAVF_FLAG_AQ_ADD_CLOUD_FILTER) {
iavf_add_cloud_filter(adapter);
- goto watchdog_done;
+ return 0;
}
if (adapter->aq_required & IAVF_FLAG_AQ_DEL_CLOUD_FILTER) {
iavf_del_cloud_filter(adapter);
+ return 0;
+ }
+ if (adapter->aq_required & IAVF_FLAG_AQ_DEL_CLOUD_FILTER) {
+ iavf_del_cloud_filter(adapter);
+ return 0;
+ }
+ if (adapter->aq_required & IAVF_FLAG_AQ_ADD_CLOUD_FILTER) {
+ iavf_add_cloud_filter(adapter);
+ return 0;
+ }
+ return -EAGAIN;
+}
+
+/**
+ * iavf_startup - first step of driver startup
+ * @adapter: board private structure
+ *
+ * Function process __IAVF_STARTUP driver state.
+ * When success the state is changed to __IAVF_INIT_VERSION_CHECK
+ * when fails it returns -EAGAIN
+ **/
+static int iavf_startup(struct iavf_adapter *adapter)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ struct iavf_hw *hw = &adapter->hw;
+ int err;
+
+ WARN_ON(adapter->state != __IAVF_STARTUP);
+
+ /* driver loaded, probe complete */
+ adapter->flags &= ~IAVF_FLAG_PF_COMMS_FAILED;
+ adapter->flags &= ~IAVF_FLAG_RESET_PENDING;
+ err = iavf_set_mac_type(hw);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to set MAC type (%d)\n", err);
+ goto err;
+ }
+
+ err = iavf_check_reset_complete(hw);
+ if (err) {
+ dev_info(&pdev->dev, "Device is still in reset (%d), retrying\n",
+ err);
+ goto err;
+ }
+ hw->aq.num_arq_entries = IAVF_AQ_LEN;
+ hw->aq.num_asq_entries = IAVF_AQ_LEN;
+ hw->aq.arq_buf_size = IAVF_MAX_AQ_BUF_SIZE;
+ hw->aq.asq_buf_size = IAVF_MAX_AQ_BUF_SIZE;
+
+ err = iavf_init_adminq(hw);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to init Admin Queue (%d)\n", err);
+ goto err;
+ }
+ err = iavf_send_api_ver(adapter);
+ if (err) {
+ dev_err(&pdev->dev, "Unable to send to PF (%d)\n", err);
+ iavf_shutdown_adminq(hw);
+ goto err;
+ }
+ adapter->state = __IAVF_INIT_VERSION_CHECK;
+err:
+ return err;
+}
+
+/**
+ * iavf_init_version_check - second step of driver startup
+ * @adapter: board private structure
+ *
+ * Function process __IAVF_INIT_VERSION_CHECK driver state.
+ * When success the state is changed to __IAVF_INIT_GET_RESOURCES
+ * when fails it returns -EAGAIN
+ **/
+static int iavf_init_version_check(struct iavf_adapter *adapter)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ struct iavf_hw *hw = &adapter->hw;
+ int err = -EAGAIN;
+
+ WARN_ON(adapter->state != __IAVF_INIT_VERSION_CHECK);
+
+ if (!iavf_asq_done(hw)) {
+ dev_err(&pdev->dev, "Admin queue command never completed\n");
+ iavf_shutdown_adminq(hw);
+ adapter->state = __IAVF_STARTUP;
+ goto err;
+ }
+
+ /* aq msg sent, awaiting reply */
+ err = iavf_verify_api_ver(adapter);
+ if (err) {
+ if (err == IAVF_ERR_ADMIN_QUEUE_NO_WORK)
+ err = iavf_send_api_ver(adapter);
+ else
+ dev_err(&pdev->dev, "Unsupported PF API version %d.%d, expected %d.%d\n",
+ adapter->pf_version.major,
+ adapter->pf_version.minor,
+ VIRTCHNL_VERSION_MAJOR,
+ VIRTCHNL_VERSION_MINOR);
+ goto err;
+ }
+ err = iavf_send_vf_config_msg(adapter);
+ if (err) {
+ dev_err(&pdev->dev, "Unable to send config request (%d)\n",
+ err);
+ goto err;
+ }
+ adapter->state = __IAVF_INIT_GET_RESOURCES;
+
+err:
+ return err;
+}
+
+/**
+ * iavf_init_get_resources - third step of driver startup
+ * @adapter: board private structure
+ *
+ * Function process __IAVF_INIT_GET_RESOURCES driver state and
+ * finishes driver initialization procedure.
+ * When success the state is changed to __IAVF_DOWN
+ * when fails it returns -EAGAIN
+ **/
+static int iavf_init_get_resources(struct iavf_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+ struct iavf_hw *hw = &adapter->hw;
+ int err = 0, bufsz;
+
+ WARN_ON(adapter->state != __IAVF_INIT_GET_RESOURCES);
+ /* aq msg sent, awaiting reply */
+ if (!adapter->vf_res) {
+ bufsz = sizeof(struct virtchnl_vf_resource) +
+ (IAVF_MAX_VF_VSI *
+ sizeof(struct virtchnl_vsi_resource));
+ adapter->vf_res = kzalloc(bufsz, GFP_KERNEL);
+ if (!adapter->vf_res)
+ goto err;
+ }
+ err = iavf_get_vf_config(adapter);
+ if (err == IAVF_ERR_ADMIN_QUEUE_NO_WORK) {
+ err = iavf_send_vf_config_msg(adapter);
+ goto err;
+ } else if (err == IAVF_ERR_PARAM) {
+ /* We only get ERR_PARAM if the device is in a very bad
+ * state or if we've been disabled for previous bad
+ * behavior. Either way, we're done now.
+ */
+ iavf_shutdown_adminq(hw);
+ dev_err(&pdev->dev, "Unable to get VF config due to PF error condition, not retrying\n");
+ return 0;
+ }
+ if (err) {
+ dev_err(&pdev->dev, "Unable to get VF config (%d)\n", err);
+ goto err_alloc;
+ }
+
+ if (iavf_process_config(adapter))
+ goto err_alloc;
+ adapter->current_op = VIRTCHNL_OP_UNKNOWN;
+
+ adapter->flags |= IAVF_FLAG_RX_CSUM_ENABLED;
+
+ netdev->netdev_ops = &iavf_netdev_ops;
+ iavf_set_ethtool_ops(netdev);
+ netdev->watchdog_timeo = 5 * HZ;
+
+ /* MTU range: 68 - 9710 */
+ netdev->min_mtu = ETH_MIN_MTU;
+ netdev->max_mtu = IAVF_MAX_RXBUFFER - IAVF_PACKET_HDR_PAD;
+
+ if (!is_valid_ether_addr(adapter->hw.mac.addr)) {
+ dev_info(&pdev->dev, "Invalid MAC address %pM, using random\n",
+ adapter->hw.mac.addr);
+ eth_hw_addr_random(netdev);
+ ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr);
+ } else {
+ adapter->flags |= IAVF_FLAG_ADDR_SET_BY_PF;
+ ether_addr_copy(netdev->dev_addr, adapter->hw.mac.addr);
+ ether_addr_copy(netdev->perm_addr, adapter->hw.mac.addr);
+ }
+
+ adapter->tx_desc_count = IAVF_DEFAULT_TXD;
+ adapter->rx_desc_count = IAVF_DEFAULT_RXD;
+ err = iavf_init_interrupt_scheme(adapter);
+ if (err)
+ goto err_sw_init;
+ iavf_map_rings_to_vectors(adapter);
+ if (adapter->vf_res->vf_cap_flags &
+ VIRTCHNL_VF_OFFLOAD_WB_ON_ITR)
+ adapter->flags |= IAVF_FLAG_WB_ON_ITR_CAPABLE;
+
+ err = iavf_request_misc_irq(adapter);
+ if (err)
+ goto err_sw_init;
+
+ netif_carrier_off(netdev);
+ adapter->link_up = false;
+
+ /* set the semaphore to prevent any callbacks after device registration
+ * up to time when state of driver will be set to __IAVF_DOWN
+ */
+ rtnl_lock();
+ if (!adapter->netdev_registered) {
+ err = register_netdevice(netdev);
+ if (err) {
+ rtnl_unlock();
+ goto err_register;
+ }
+ }
+
+ adapter->netdev_registered = true;
+
+ netif_tx_stop_all_queues(netdev);
+ if (CLIENT_ALLOWED(adapter)) {
+ err = iavf_lan_add_device(adapter);
+ if (err) {
+ rtnl_unlock();
+ dev_info(&pdev->dev, "Failed to add VF to client API service list: %d\n",
+ err);
+ }
+ }
+ dev_info(&pdev->dev, "MAC address: %pM\n", adapter->hw.mac.addr);
+ if (netdev->features & NETIF_F_GRO)
+ dev_info(&pdev->dev, "GRO is enabled\n");
+
+ adapter->state = __IAVF_DOWN;
+ set_bit(__IAVF_VSI_DOWN, adapter->vsi.state);
+ rtnl_unlock();
+
+ iavf_misc_irq_enable(adapter);
+ wake_up(&adapter->down_waitqueue);
+
+ adapter->rss_key = kzalloc(adapter->rss_key_size, GFP_KERNEL);
+ adapter->rss_lut = kzalloc(adapter->rss_lut_size, GFP_KERNEL);
+ if (!adapter->rss_key || !adapter->rss_lut)
+ goto err_mem;
+ if (RSS_AQ(adapter))
+ adapter->aq_required |= IAVF_FLAG_AQ_CONFIGURE_RSS;
+ else
+ iavf_init_rss(adapter);
+
+ return err;
+err_mem:
+ iavf_free_rss(adapter);
+err_register:
+ iavf_free_misc_irq(adapter);
+err_sw_init:
+ iavf_reset_interrupt_capability(adapter);
+err_alloc:
+ kfree(adapter->vf_res);
+ adapter->vf_res = NULL;
+err:
+ return err;
+}
+
+/**
+ * iavf_watchdog_task - Periodic call-back task
+ * @work: pointer to work_struct
+ **/
+static void iavf_watchdog_task(struct work_struct *work)
+{
+ struct iavf_adapter *adapter = container_of(work,
+ struct iavf_adapter,
+ watchdog_task.work);
+ struct iavf_hw *hw = &adapter->hw;
+ u32 reg_val;
+
+ if (test_and_set_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section))
+ goto restart_watchdog;
+
+ if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED)
+ adapter->state = __IAVF_COMM_FAILED;
+
+ switch (adapter->state) {
+ case __IAVF_COMM_FAILED:
+ reg_val = rd32(hw, IAVF_VFGEN_RSTAT) &
+ IAVF_VFGEN_RSTAT_VFR_STATE_MASK;
+ if (reg_val == VIRTCHNL_VFR_VFACTIVE ||
+ reg_val == VIRTCHNL_VFR_COMPLETED) {
+ /* A chance for redemption! */
+ dev_err(&adapter->pdev->dev,
+ "Hardware came out of reset. Attempting reinit.\n");
+ adapter->state = __IAVF_STARTUP;
+ adapter->flags &= ~IAVF_FLAG_PF_COMMS_FAILED;
+ queue_delayed_work(iavf_wq, &adapter->init_task, 10);
+ clear_bit(__IAVF_IN_CRITICAL_TASK,
+ &adapter->crit_section);
+ /* Don't reschedule the watchdog, since we've restarted
+ * the init task. When init_task contacts the PF and
+ * gets everything set up again, it'll restart the
+ * watchdog for us. Down, boy. Sit. Stay. Woof.
+ */
+ return;
+ }
+ adapter->aq_required = 0;
+ adapter->current_op = VIRTCHNL_OP_UNKNOWN;
+ clear_bit(__IAVF_IN_CRITICAL_TASK,
+ &adapter->crit_section);
+ queue_delayed_work(iavf_wq,
+ &adapter->watchdog_task,
+ msecs_to_jiffies(10));
goto watchdog_done;
+ case __IAVF_RESETTING:
+ clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section);
+ queue_delayed_work(iavf_wq, &adapter->watchdog_task, HZ * 2);
+ return;
+ case __IAVF_DOWN:
+ case __IAVF_DOWN_PENDING:
+ case __IAVF_TESTING:
+ case __IAVF_RUNNING:
+ if (adapter->current_op) {
+ if (!iavf_asq_done(hw)) {
+ dev_dbg(&adapter->pdev->dev,
+ "Admin queue timeout\n");
+ iavf_send_api_ver(adapter);
+ }
+ } else {
+ if (!iavf_process_aq_command(adapter) &&
+ adapter->state == __IAVF_RUNNING)
+ iavf_request_stats(adapter);
+ }
+ break;
+ case __IAVF_REMOVE:
+ clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section);
+ return;
+ default:
+ goto restart_watchdog;
}
- schedule_delayed_work(&adapter->client_task, msecs_to_jiffies(5));
+ /* check for hw reset */
+ reg_val = rd32(hw, IAVF_VF_ARQLEN1) & IAVF_VF_ARQLEN1_ARQENABLE_MASK;
+ if (!reg_val) {
+ adapter->state = __IAVF_RESETTING;
+ adapter->flags |= IAVF_FLAG_RESET_PENDING;
+ adapter->aq_required = 0;
+ adapter->current_op = VIRTCHNL_OP_UNKNOWN;
+ dev_err(&adapter->pdev->dev, "Hardware reset detected\n");
+ queue_work(iavf_wq, &adapter->reset_task);
+ goto watchdog_done;
+ }
- if (adapter->state == __IAVF_RUNNING)
- iavf_request_stats(adapter);
+ schedule_delayed_work(&adapter->client_task, msecs_to_jiffies(5));
watchdog_done:
- if (adapter->state == __IAVF_RUNNING)
+ if (adapter->state == __IAVF_RUNNING ||
+ adapter->state == __IAVF_COMM_FAILED)
iavf_detect_recover_hung(&adapter->vsi);
clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section);
restart_watchdog:
- if (adapter->state == __IAVF_REMOVE)
- return;
if (adapter->aq_required)
- mod_timer(&adapter->watchdog_timer,
- jiffies + msecs_to_jiffies(20));
+ queue_delayed_work(iavf_wq, &adapter->watchdog_task,
+ msecs_to_jiffies(20));
else
- mod_timer(&adapter->watchdog_timer, jiffies + (HZ * 2));
- schedule_work(&adapter->adminq_task);
+ queue_delayed_work(iavf_wq, &adapter->watchdog_task, HZ * 2);
+ queue_work(iavf_wq, &adapter->adminq_task);
}
static void iavf_disable_vf(struct iavf_adapter *adapter)
@@ -1967,7 +2234,7 @@ continue_reset:
adapter->aq_required |= IAVF_FLAG_AQ_ADD_CLOUD_FILTER;
iavf_misc_irq_enable(adapter);
- mod_timer(&adapter->watchdog_timer, jiffies + 2);
+ mod_delayed_work(iavf_wq, &adapter->watchdog_task, 2);
/* We were running when the reset started, so we need to restore some
* state here.
@@ -2020,9 +2287,9 @@ static void iavf_adminq_task(struct work_struct *work)
struct iavf_adapter *adapter =
container_of(work, struct iavf_adapter, adminq_task);
struct iavf_hw *hw = &adapter->hw;
- struct i40e_arq_event_info event;
+ struct iavf_arq_event_info event;
enum virtchnl_ops v_op;
- iavf_status ret, v_ret;
+ enum iavf_status ret, v_ret;
u32 val, oldval;
u16 pending;
@@ -2037,7 +2304,7 @@ static void iavf_adminq_task(struct work_struct *work)
do {
ret = iavf_clean_arq_element(hw, &event, &pending);
v_op = (enum virtchnl_ops)le32_to_cpu(event.desc.cookie_high);
- v_ret = (iavf_status)le32_to_cpu(event.desc.cookie_low);
+ v_ret = (enum iavf_status)le32_to_cpu(event.desc.cookie_low);
if (ret || !v_op)
break; /* No event to process or error cleaning ARQ */
@@ -2239,22 +2506,22 @@ static int iavf_validate_tx_bandwidth(struct iavf_adapter *adapter,
int speed = 0, ret = 0;
switch (adapter->link_speed) {
- case I40E_LINK_SPEED_40GB:
+ case IAVF_LINK_SPEED_40GB:
speed = 40000;
break;
- case I40E_LINK_SPEED_25GB:
+ case IAVF_LINK_SPEED_25GB:
speed = 25000;
break;
- case I40E_LINK_SPEED_20GB:
+ case IAVF_LINK_SPEED_20GB:
speed = 20000;
break;
- case I40E_LINK_SPEED_10GB:
+ case IAVF_LINK_SPEED_10GB:
speed = 10000;
break;
- case I40E_LINK_SPEED_1GB:
+ case IAVF_LINK_SPEED_1GB:
speed = 1000;
break;
- case I40E_LINK_SPEED_100MB:
+ case IAVF_LINK_SPEED_100MB:
speed = 100;
break;
default:
@@ -2432,14 +2699,14 @@ exit:
/**
* iavf_parse_cls_flower - Parse tc flower filters provided by kernel
* @adapter: board private structure
- * @cls_flower: pointer to struct tc_cls_flower_offload
+ * @cls_flower: pointer to struct flow_cls_offload
* @filter: pointer to cloud filter structure
*/
static int iavf_parse_cls_flower(struct iavf_adapter *adapter,
- struct tc_cls_flower_offload *f,
+ struct flow_cls_offload *f,
struct iavf_cloud_filter *filter)
{
- struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
+ struct flow_rule *rule = flow_cls_offload_flow_rule(f);
struct flow_dissector *dissector = rule->match.dissector;
u16 n_proto_mask = 0;
u16 n_proto_key = 0;
@@ -2508,7 +2775,7 @@ static int iavf_parse_cls_flower(struct iavf_adapter *adapter,
} else {
dev_err(&adapter->pdev->dev, "Bad ether dest mask %pM\n",
match.mask->dst);
- return I40E_ERR_CONFIG;
+ return IAVF_ERR_CONFIG;
}
}
@@ -2518,7 +2785,7 @@ static int iavf_parse_cls_flower(struct iavf_adapter *adapter,
} else {
dev_err(&adapter->pdev->dev, "Bad ether src mask %pM\n",
match.mask->src);
- return I40E_ERR_CONFIG;
+ return IAVF_ERR_CONFIG;
}
}
@@ -2553,7 +2820,7 @@ static int iavf_parse_cls_flower(struct iavf_adapter *adapter,
} else {
dev_err(&adapter->pdev->dev, "Bad vlan mask %u\n",
match.mask->vlan_id);
- return I40E_ERR_CONFIG;
+ return IAVF_ERR_CONFIG;
}
}
vf->mask.tcp_spec.vlan_id |= cpu_to_be16(0xffff);
@@ -2577,7 +2844,7 @@ static int iavf_parse_cls_flower(struct iavf_adapter *adapter,
} else {
dev_err(&adapter->pdev->dev, "Bad ip dst mask 0x%08x\n",
be32_to_cpu(match.mask->dst));
- return I40E_ERR_CONFIG;
+ return IAVF_ERR_CONFIG;
}
}
@@ -2587,13 +2854,13 @@ static int iavf_parse_cls_flower(struct iavf_adapter *adapter,
} else {
dev_err(&adapter->pdev->dev, "Bad ip src mask 0x%08x\n",
be32_to_cpu(match.mask->dst));
- return I40E_ERR_CONFIG;
+ return IAVF_ERR_CONFIG;
}
}
if (field_flags & IAVF_CLOUD_FIELD_TEN_ID) {
dev_info(&adapter->pdev->dev, "Tenant id not allowed for ip filter\n");
- return I40E_ERR_CONFIG;
+ return IAVF_ERR_CONFIG;
}
if (match.key->dst) {
vf->mask.tcp_spec.dst_ip[0] |= cpu_to_be32(0xffffffff);
@@ -2614,7 +2881,7 @@ static int iavf_parse_cls_flower(struct iavf_adapter *adapter,
if (ipv6_addr_any(&match.mask->dst)) {
dev_err(&adapter->pdev->dev, "Bad ipv6 dst mask 0x%02x\n",
IPV6_ADDR_ANY);
- return I40E_ERR_CONFIG;
+ return IAVF_ERR_CONFIG;
}
/* src and dest IPv6 address should not be LOOPBACK
@@ -2624,7 +2891,7 @@ static int iavf_parse_cls_flower(struct iavf_adapter *adapter,
ipv6_addr_loopback(&match.key->src)) {
dev_err(&adapter->pdev->dev,
"ipv6 addr should not be loopback\n");
- return I40E_ERR_CONFIG;
+ return IAVF_ERR_CONFIG;
}
if (!ipv6_addr_any(&match.mask->dst) ||
!ipv6_addr_any(&match.mask->src))
@@ -2649,7 +2916,7 @@ static int iavf_parse_cls_flower(struct iavf_adapter *adapter,
} else {
dev_err(&adapter->pdev->dev, "Bad src port mask %u\n",
be16_to_cpu(match.mask->src));
- return I40E_ERR_CONFIG;
+ return IAVF_ERR_CONFIG;
}
}
@@ -2659,7 +2926,7 @@ static int iavf_parse_cls_flower(struct iavf_adapter *adapter,
} else {
dev_err(&adapter->pdev->dev, "Bad dst port mask %u\n",
be16_to_cpu(match.mask->dst));
- return I40E_ERR_CONFIG;
+ return IAVF_ERR_CONFIG;
}
}
if (match.key->dst) {
@@ -2704,10 +2971,10 @@ static int iavf_handle_tclass(struct iavf_adapter *adapter, u32 tc,
/**
* iavf_configure_clsflower - Add tc flower filters
* @adapter: board private structure
- * @cls_flower: Pointer to struct tc_cls_flower_offload
+ * @cls_flower: Pointer to struct flow_cls_offload
*/
static int iavf_configure_clsflower(struct iavf_adapter *adapter,
- struct tc_cls_flower_offload *cls_flower)
+ struct flow_cls_offload *cls_flower)
{
int tc = tc_classid_to_hwtc(adapter->netdev, cls_flower->classid);
struct iavf_cloud_filter *filter = NULL;
@@ -2783,10 +3050,10 @@ static struct iavf_cloud_filter *iavf_find_cf(struct iavf_adapter *adapter,
/**
* iavf_delete_clsflower - Remove tc flower filters
* @adapter: board private structure
- * @cls_flower: Pointer to struct tc_cls_flower_offload
+ * @cls_flower: Pointer to struct flow_cls_offload
*/
static int iavf_delete_clsflower(struct iavf_adapter *adapter,
- struct tc_cls_flower_offload *cls_flower)
+ struct flow_cls_offload *cls_flower)
{
struct iavf_cloud_filter *filter = NULL;
int err = 0;
@@ -2810,17 +3077,17 @@ static int iavf_delete_clsflower(struct iavf_adapter *adapter,
* @type_data: offload data
*/
static int iavf_setup_tc_cls_flower(struct iavf_adapter *adapter,
- struct tc_cls_flower_offload *cls_flower)
+ struct flow_cls_offload *cls_flower)
{
if (cls_flower->common.chain_index)
return -EOPNOTSUPP;
switch (cls_flower->command) {
- case TC_CLSFLOWER_REPLACE:
+ case FLOW_CLS_REPLACE:
return iavf_configure_clsflower(adapter, cls_flower);
- case TC_CLSFLOWER_DESTROY:
+ case FLOW_CLS_DESTROY:
return iavf_delete_clsflower(adapter, cls_flower);
- case TC_CLSFLOWER_STATS:
+ case FLOW_CLS_STATS:
return -EOPNOTSUPP;
default:
return -EOPNOTSUPP;
@@ -2846,34 +3113,7 @@ static int iavf_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
}
}
-/**
- * iavf_setup_tc_block - register callbacks for tc
- * @netdev: network interface device structure
- * @f: tc offload data
- *
- * This function registers block callbacks for tc
- * offloads
- **/
-static int iavf_setup_tc_block(struct net_device *dev,
- struct tc_block_offload *f)
-{
- struct iavf_adapter *adapter = netdev_priv(dev);
-
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
- return -EOPNOTSUPP;
-
- switch (f->command) {
- case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block, iavf_setup_tc_block_cb,
- adapter, adapter, f->extack);
- case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block, iavf_setup_tc_block_cb,
- adapter);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-}
+static LIST_HEAD(iavf_block_cb_list);
/**
* iavf_setup_tc - configure multiple traffic classes
@@ -2889,11 +3129,16 @@ static int iavf_setup_tc_block(struct net_device *dev,
static int iavf_setup_tc(struct net_device *netdev, enum tc_setup_type type,
void *type_data)
{
+ struct iavf_adapter *adapter = netdev_priv(netdev);
+
switch (type) {
case TC_SETUP_QDISC_MQPRIO:
return __iavf_setup_tc(netdev, type_data);
case TC_SETUP_BLOCK:
- return iavf_setup_tc_block(netdev, type_data);
+ return flow_block_cb_setup_simple(type_data,
+ &iavf_block_cb_list,
+ iavf_setup_tc_block_cb,
+ adapter, adapter, true);
default:
return -EOPNOTSUPP;
}
@@ -2908,7 +3153,7 @@ static int iavf_setup_tc(struct net_device *netdev, enum tc_setup_type type,
* The open entry point is called when a network interface is made
* active by the system (IFF_UP). At this point all resources needed
* for transmit and receive operations are allocated, the interrupt
- * handler is registered with the OS, the watchdog timer is started,
+ * handler is registered with the OS, the watchdog is started,
* and the stack is notified that the interface is ready.
**/
static int iavf_open(struct net_device *netdev)
@@ -3020,7 +3265,7 @@ static int iavf_close(struct net_device *netdev)
status = wait_event_timeout(adapter->down_waitqueue,
adapter->state == __IAVF_DOWN,
- msecs_to_jiffies(200));
+ msecs_to_jiffies(500));
if (!status)
netdev_warn(netdev, "Device resources not yet released\n");
return 0;
@@ -3043,7 +3288,7 @@ static int iavf_change_mtu(struct net_device *netdev, int new_mtu)
adapter->flags |= IAVF_FLAG_SERVICE_CLIENT_REQUESTED;
}
adapter->flags |= IAVF_FLAG_RESET_NEEDED;
- schedule_work(&adapter->reset_task);
+ queue_work(iavf_wq, &adapter->reset_task);
return 0;
}
@@ -3348,217 +3593,41 @@ int iavf_process_config(struct iavf_adapter *adapter)
static void iavf_init_task(struct work_struct *work)
{
struct iavf_adapter *adapter = container_of(work,
- struct iavf_adapter,
- init_task.work);
- struct net_device *netdev = adapter->netdev;
+ struct iavf_adapter,
+ init_task.work);
struct iavf_hw *hw = &adapter->hw;
- struct pci_dev *pdev = adapter->pdev;
- int err, bufsz;
switch (adapter->state) {
case __IAVF_STARTUP:
- /* driver loaded, probe complete */
- adapter->flags &= ~IAVF_FLAG_PF_COMMS_FAILED;
- adapter->flags &= ~IAVF_FLAG_RESET_PENDING;
- err = iavf_set_mac_type(hw);
- if (err) {
- dev_err(&pdev->dev, "Failed to set MAC type (%d)\n",
- err);
- goto err;
- }
- err = iavf_check_reset_complete(hw);
- if (err) {
- dev_info(&pdev->dev, "Device is still in reset (%d), retrying\n",
- err);
- goto err;
- }
- hw->aq.num_arq_entries = IAVF_AQ_LEN;
- hw->aq.num_asq_entries = IAVF_AQ_LEN;
- hw->aq.arq_buf_size = IAVF_MAX_AQ_BUF_SIZE;
- hw->aq.asq_buf_size = IAVF_MAX_AQ_BUF_SIZE;
-
- err = iavf_init_adminq(hw);
- if (err) {
- dev_err(&pdev->dev, "Failed to init Admin Queue (%d)\n",
- err);
- goto err;
- }
- err = iavf_send_api_ver(adapter);
- if (err) {
- dev_err(&pdev->dev, "Unable to send to PF (%d)\n", err);
- iavf_shutdown_adminq(hw);
- goto err;
- }
- adapter->state = __IAVF_INIT_VERSION_CHECK;
- goto restart;
+ if (iavf_startup(adapter) < 0)
+ goto init_failed;
+ break;
case __IAVF_INIT_VERSION_CHECK:
- if (!iavf_asq_done(hw)) {
- dev_err(&pdev->dev, "Admin queue command never completed\n");
- iavf_shutdown_adminq(hw);
- adapter->state = __IAVF_STARTUP;
- goto err;
- }
-
- /* aq msg sent, awaiting reply */
- err = iavf_verify_api_ver(adapter);
- if (err) {
- if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK)
- err = iavf_send_api_ver(adapter);
- else
- dev_err(&pdev->dev, "Unsupported PF API version %d.%d, expected %d.%d\n",
- adapter->pf_version.major,
- adapter->pf_version.minor,
- VIRTCHNL_VERSION_MAJOR,
- VIRTCHNL_VERSION_MINOR);
- goto err;
- }
- err = iavf_send_vf_config_msg(adapter);
- if (err) {
- dev_err(&pdev->dev, "Unable to send config request (%d)\n",
- err);
- goto err;
- }
- adapter->state = __IAVF_INIT_GET_RESOURCES;
- goto restart;
- case __IAVF_INIT_GET_RESOURCES:
- /* aq msg sent, awaiting reply */
- if (!adapter->vf_res) {
- bufsz = sizeof(struct virtchnl_vf_resource) +
- (IAVF_MAX_VF_VSI *
- sizeof(struct virtchnl_vsi_resource));
- adapter->vf_res = kzalloc(bufsz, GFP_KERNEL);
- if (!adapter->vf_res)
- goto err;
- }
- err = iavf_get_vf_config(adapter);
- if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK) {
- err = iavf_send_vf_config_msg(adapter);
- goto err;
- } else if (err == I40E_ERR_PARAM) {
- /* We only get ERR_PARAM if the device is in a very bad
- * state or if we've been disabled for previous bad
- * behavior. Either way, we're done now.
- */
- iavf_shutdown_adminq(hw);
- dev_err(&pdev->dev, "Unable to get VF config due to PF error condition, not retrying\n");
- return;
- }
- if (err) {
- dev_err(&pdev->dev, "Unable to get VF config (%d)\n",
- err);
- goto err_alloc;
- }
- adapter->state = __IAVF_INIT_SW;
+ if (iavf_init_version_check(adapter) < 0)
+ goto init_failed;
break;
+ case __IAVF_INIT_GET_RESOURCES:
+ if (iavf_init_get_resources(adapter) < 0)
+ goto init_failed;
+ return;
default:
- goto err_alloc;
- }
-
- if (iavf_process_config(adapter))
- goto err_alloc;
- adapter->current_op = VIRTCHNL_OP_UNKNOWN;
-
- adapter->flags |= IAVF_FLAG_RX_CSUM_ENABLED;
-
- netdev->netdev_ops = &iavf_netdev_ops;
- iavf_set_ethtool_ops(netdev);
- netdev->watchdog_timeo = 5 * HZ;
-
- /* MTU range: 68 - 9710 */
- netdev->min_mtu = ETH_MIN_MTU;
- netdev->max_mtu = IAVF_MAX_RXBUFFER - IAVF_PACKET_HDR_PAD;
-
- if (!is_valid_ether_addr(adapter->hw.mac.addr)) {
- dev_info(&pdev->dev, "Invalid MAC address %pM, using random\n",
- adapter->hw.mac.addr);
- eth_hw_addr_random(netdev);
- ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr);
- } else {
- adapter->flags |= IAVF_FLAG_ADDR_SET_BY_PF;
- ether_addr_copy(netdev->dev_addr, adapter->hw.mac.addr);
- ether_addr_copy(netdev->perm_addr, adapter->hw.mac.addr);
- }
-
- timer_setup(&adapter->watchdog_timer, iavf_watchdog_timer, 0);
- mod_timer(&adapter->watchdog_timer, jiffies + 1);
-
- adapter->tx_desc_count = IAVF_DEFAULT_TXD;
- adapter->rx_desc_count = IAVF_DEFAULT_RXD;
- err = iavf_init_interrupt_scheme(adapter);
- if (err)
- goto err_sw_init;
- iavf_map_rings_to_vectors(adapter);
- if (adapter->vf_res->vf_cap_flags &
- VIRTCHNL_VF_OFFLOAD_WB_ON_ITR)
- adapter->flags |= IAVF_FLAG_WB_ON_ITR_CAPABLE;
-
- err = iavf_request_misc_irq(adapter);
- if (err)
- goto err_sw_init;
-
- netif_carrier_off(netdev);
- adapter->link_up = false;
-
- if (!adapter->netdev_registered) {
- err = register_netdev(netdev);
- if (err)
- goto err_register;
- }
-
- adapter->netdev_registered = true;
-
- netif_tx_stop_all_queues(netdev);
- if (CLIENT_ALLOWED(adapter)) {
- err = iavf_lan_add_device(adapter);
- if (err)
- dev_info(&pdev->dev, "Failed to add VF to client API service list: %d\n",
- err);
+ goto init_failed;
}
- dev_info(&pdev->dev, "MAC address: %pM\n", adapter->hw.mac.addr);
- if (netdev->features & NETIF_F_GRO)
- dev_info(&pdev->dev, "GRO is enabled\n");
-
- adapter->state = __IAVF_DOWN;
- set_bit(__IAVF_VSI_DOWN, adapter->vsi.state);
- iavf_misc_irq_enable(adapter);
- wake_up(&adapter->down_waitqueue);
-
- adapter->rss_key = kzalloc(adapter->rss_key_size, GFP_KERNEL);
- adapter->rss_lut = kzalloc(adapter->rss_lut_size, GFP_KERNEL);
- if (!adapter->rss_key || !adapter->rss_lut)
- goto err_mem;
-
- if (RSS_AQ(adapter)) {
- adapter->aq_required |= IAVF_FLAG_AQ_CONFIGURE_RSS;
- mod_timer_pending(&adapter->watchdog_timer, jiffies + 1);
- } else {
- iavf_init_rss(adapter);
- }
- return;
-restart:
- schedule_delayed_work(&adapter->init_task, msecs_to_jiffies(30));
+ queue_delayed_work(iavf_wq, &adapter->init_task,
+ msecs_to_jiffies(30));
return;
-err_mem:
- iavf_free_rss(adapter);
-err_register:
- iavf_free_misc_irq(adapter);
-err_sw_init:
- iavf_reset_interrupt_capability(adapter);
-err_alloc:
- kfree(adapter->vf_res);
- adapter->vf_res = NULL;
-err:
- /* Things went into the weeds, so try again later */
+init_failed:
if (++adapter->aq_wait_count > IAVF_AQ_MAX_ERR) {
- dev_err(&pdev->dev, "Failed to communicate with PF; waiting before retry\n");
+ dev_err(&adapter->pdev->dev,
+ "Failed to communicate with PF; waiting before retry\n");
adapter->flags |= IAVF_FLAG_PF_COMMS_FAILED;
iavf_shutdown_adminq(hw);
adapter->state = __IAVF_STARTUP;
- schedule_delayed_work(&adapter->init_task, HZ * 5);
+ queue_delayed_work(iavf_wq, &adapter->init_task, HZ * 5);
return;
}
- schedule_delayed_work(&adapter->init_task, HZ);
+ queue_delayed_work(iavf_wq, &adapter->init_task, HZ);
}
/**
@@ -3683,11 +3752,11 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
INIT_WORK(&adapter->reset_task, iavf_reset_task);
INIT_WORK(&adapter->adminq_task, iavf_adminq_task);
- INIT_WORK(&adapter->watchdog_task, iavf_watchdog_task);
+ INIT_DELAYED_WORK(&adapter->watchdog_task, iavf_watchdog_task);
INIT_DELAYED_WORK(&adapter->client_task, iavf_client_task);
INIT_DELAYED_WORK(&adapter->init_task, iavf_init_task);
- schedule_delayed_work(&adapter->init_task,
- msecs_to_jiffies(5 * (pdev->devfn & 0x07)));
+ queue_delayed_work(iavf_wq, &adapter->init_task,
+ msecs_to_jiffies(5 * (pdev->devfn & 0x07)));
/* Setup the wait queue for indicating transition to down status */
init_waitqueue_head(&adapter->down_waitqueue);
@@ -3783,7 +3852,7 @@ static int iavf_resume(struct pci_dev *pdev)
return err;
}
- schedule_work(&adapter->reset_task);
+ queue_work(iavf_wq, &adapter->reset_task);
netif_device_attach(netdev);
@@ -3843,8 +3912,7 @@ static void iavf_remove(struct pci_dev *pdev)
iavf_reset_interrupt_capability(adapter);
iavf_free_q_vectors(adapter);
- if (adapter->watchdog_timer.function)
- del_timer_sync(&adapter->watchdog_timer);
+ cancel_delayed_work_sync(&adapter->watchdog_task);
cancel_work_sync(&adapter->adminq_task);
diff --git a/drivers/net/ethernet/intel/iavf/iavf_osdep.h b/drivers/net/ethernet/intel/iavf/iavf_osdep.h
index e6e0b0328706..a452ce90679a 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_osdep.h
+++ b/drivers/net/ethernet/intel/iavf/iavf_osdep.h
@@ -44,9 +44,12 @@ struct iavf_virt_mem {
#define iavf_allocate_virt_mem(h, m, s) iavf_allocate_virt_mem_d(h, m, s)
#define iavf_free_virt_mem(h, m) iavf_free_virt_mem_d(h, m)
-#define iavf_debug(h, m, s, ...) iavf_debug_d(h, m, s, ##__VA_ARGS__)
-extern void iavf_debug_d(void *hw, u32 mask, char *fmt_str, ...)
- __attribute__ ((format(gnu_printf, 3, 4)));
+#define iavf_debug(h, m, s, ...) \
+do { \
+ if (((m) & (h)->debug_mask)) \
+ pr_info("iavf %02x:%02x.%x " s, \
+ (h)->bus.bus_id, (h)->bus.device, \
+ (h)->bus.func, ##__VA_ARGS__); \
+} while (0)
-typedef enum iavf_status_code iavf_status;
#endif /* _IAVF_OSDEP_H_ */
diff --git a/drivers/net/ethernet/intel/iavf/iavf_prototype.h b/drivers/net/ethernet/intel/iavf/iavf_prototype.h
index d6685103af39..edebfbbcffdc 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_prototype.h
+++ b/drivers/net/ethernet/intel/iavf/iavf_prototype.h
@@ -16,39 +16,40 @@
*/
/* adminq functions */
-iavf_status iavf_init_adminq(struct iavf_hw *hw);
-iavf_status iavf_shutdown_adminq(struct iavf_hw *hw);
-void i40e_adminq_init_ring_data(struct iavf_hw *hw);
-iavf_status iavf_clean_arq_element(struct iavf_hw *hw,
- struct i40e_arq_event_info *e,
- u16 *events_pending);
-iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc,
- void *buff, /* can be NULL */
- u16 buff_size,
- struct i40e_asq_cmd_details *cmd_details);
+enum iavf_status iavf_init_adminq(struct iavf_hw *hw);
+enum iavf_status iavf_shutdown_adminq(struct iavf_hw *hw);
+void iavf_adminq_init_ring_data(struct iavf_hw *hw);
+enum iavf_status iavf_clean_arq_element(struct iavf_hw *hw,
+ struct iavf_arq_event_info *e,
+ u16 *events_pending);
+enum iavf_status iavf_asq_send_command(struct iavf_hw *hw,
+ struct iavf_aq_desc *desc,
+ void *buff, /* can be NULL */
+ u16 buff_size,
+ struct iavf_asq_cmd_details *cmd_details);
bool iavf_asq_done(struct iavf_hw *hw);
/* debug function for adminq */
void iavf_debug_aq(struct iavf_hw *hw, enum iavf_debug_mask mask,
void *desc, void *buffer, u16 buf_len);
-void i40e_idle_aq(struct iavf_hw *hw);
+void iavf_idle_aq(struct iavf_hw *hw);
void iavf_resume_aq(struct iavf_hw *hw);
bool iavf_check_asq_alive(struct iavf_hw *hw);
-iavf_status iavf_aq_queue_shutdown(struct iavf_hw *hw, bool unloading);
-const char *iavf_aq_str(struct iavf_hw *hw, enum i40e_admin_queue_err aq_err);
-const char *iavf_stat_str(struct iavf_hw *hw, iavf_status stat_err);
+enum iavf_status iavf_aq_queue_shutdown(struct iavf_hw *hw, bool unloading);
+const char *iavf_aq_str(struct iavf_hw *hw, enum iavf_admin_queue_err aq_err);
+const char *iavf_stat_str(struct iavf_hw *hw, enum iavf_status stat_err);
-iavf_status iavf_aq_get_rss_lut(struct iavf_hw *hw, u16 seid,
- bool pf_lut, u8 *lut, u16 lut_size);
-iavf_status iavf_aq_set_rss_lut(struct iavf_hw *hw, u16 seid,
- bool pf_lut, u8 *lut, u16 lut_size);
-iavf_status iavf_aq_get_rss_key(struct iavf_hw *hw, u16 seid,
- struct i40e_aqc_get_set_rss_key_data *key);
-iavf_status iavf_aq_set_rss_key(struct iavf_hw *hw, u16 seid,
- struct i40e_aqc_get_set_rss_key_data *key);
+enum iavf_status iavf_aq_get_rss_lut(struct iavf_hw *hw, u16 seid,
+ bool pf_lut, u8 *lut, u16 lut_size);
+enum iavf_status iavf_aq_set_rss_lut(struct iavf_hw *hw, u16 seid,
+ bool pf_lut, u8 *lut, u16 lut_size);
+enum iavf_status iavf_aq_get_rss_key(struct iavf_hw *hw, u16 seid,
+ struct iavf_aqc_get_set_rss_key_data *key);
+enum iavf_status iavf_aq_set_rss_key(struct iavf_hw *hw, u16 seid,
+ struct iavf_aqc_get_set_rss_key_data *key);
-iavf_status iavf_set_mac_type(struct iavf_hw *hw);
+enum iavf_status iavf_set_mac_type(struct iavf_hw *hw);
extern struct iavf_rx_ptype_decoded iavf_ptype_lookup[];
@@ -59,9 +60,10 @@ static inline struct iavf_rx_ptype_decoded decode_rx_desc_ptype(u8 ptype)
void iavf_vf_parse_hw_config(struct iavf_hw *hw,
struct virtchnl_vf_resource *msg);
-iavf_status iavf_vf_reset(struct iavf_hw *hw);
-iavf_status iavf_aq_send_msg_to_pf(struct iavf_hw *hw,
- enum virtchnl_ops v_opcode,
- iavf_status v_retval, u8 *msg, u16 msglen,
- struct i40e_asq_cmd_details *cmd_details);
+enum iavf_status iavf_vf_reset(struct iavf_hw *hw);
+enum iavf_status iavf_aq_send_msg_to_pf(struct iavf_hw *hw,
+ enum virtchnl_ops v_opcode,
+ enum iavf_status v_retval,
+ u8 *msg, u16 msglen,
+ struct iavf_asq_cmd_details *cmd_details);
#endif /* _IAVF_PROTOTYPE_H_ */
diff --git a/drivers/net/ethernet/intel/iavf/iavf_status.h b/drivers/net/ethernet/intel/iavf/iavf_status.h
index 46742fab7b8c..46e3d1f6b604 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_status.h
+++ b/drivers/net/ethernet/intel/iavf/iavf_status.h
@@ -5,74 +5,74 @@
#define _IAVF_STATUS_H_
/* Error Codes */
-enum iavf_status_code {
- I40E_SUCCESS = 0,
- I40E_ERR_NVM = -1,
- I40E_ERR_NVM_CHECKSUM = -2,
- I40E_ERR_PHY = -3,
- I40E_ERR_CONFIG = -4,
- I40E_ERR_PARAM = -5,
- I40E_ERR_MAC_TYPE = -6,
- I40E_ERR_UNKNOWN_PHY = -7,
- I40E_ERR_LINK_SETUP = -8,
- I40E_ERR_ADAPTER_STOPPED = -9,
- I40E_ERR_INVALID_MAC_ADDR = -10,
- I40E_ERR_DEVICE_NOT_SUPPORTED = -11,
- I40E_ERR_MASTER_REQUESTS_PENDING = -12,
- I40E_ERR_INVALID_LINK_SETTINGS = -13,
- I40E_ERR_AUTONEG_NOT_COMPLETE = -14,
- I40E_ERR_RESET_FAILED = -15,
- I40E_ERR_SWFW_SYNC = -16,
- I40E_ERR_NO_AVAILABLE_VSI = -17,
- I40E_ERR_NO_MEMORY = -18,
- I40E_ERR_BAD_PTR = -19,
- I40E_ERR_RING_FULL = -20,
- I40E_ERR_INVALID_PD_ID = -21,
- I40E_ERR_INVALID_QP_ID = -22,
- I40E_ERR_INVALID_CQ_ID = -23,
- I40E_ERR_INVALID_CEQ_ID = -24,
- I40E_ERR_INVALID_AEQ_ID = -25,
- I40E_ERR_INVALID_SIZE = -26,
- I40E_ERR_INVALID_ARP_INDEX = -27,
- I40E_ERR_INVALID_FPM_FUNC_ID = -28,
- I40E_ERR_QP_INVALID_MSG_SIZE = -29,
- I40E_ERR_QP_TOOMANY_WRS_POSTED = -30,
- I40E_ERR_INVALID_FRAG_COUNT = -31,
- I40E_ERR_QUEUE_EMPTY = -32,
- I40E_ERR_INVALID_ALIGNMENT = -33,
- I40E_ERR_FLUSHED_QUEUE = -34,
- I40E_ERR_INVALID_PUSH_PAGE_INDEX = -35,
- I40E_ERR_INVALID_IMM_DATA_SIZE = -36,
- I40E_ERR_TIMEOUT = -37,
- I40E_ERR_OPCODE_MISMATCH = -38,
- I40E_ERR_CQP_COMPL_ERROR = -39,
- I40E_ERR_INVALID_VF_ID = -40,
- I40E_ERR_INVALID_HMCFN_ID = -41,
- I40E_ERR_BACKING_PAGE_ERROR = -42,
- I40E_ERR_NO_PBLCHUNKS_AVAILABLE = -43,
- I40E_ERR_INVALID_PBLE_INDEX = -44,
- I40E_ERR_INVALID_SD_INDEX = -45,
- I40E_ERR_INVALID_PAGE_DESC_INDEX = -46,
- I40E_ERR_INVALID_SD_TYPE = -47,
- I40E_ERR_MEMCPY_FAILED = -48,
- I40E_ERR_INVALID_HMC_OBJ_INDEX = -49,
- I40E_ERR_INVALID_HMC_OBJ_COUNT = -50,
- I40E_ERR_INVALID_SRQ_ARM_LIMIT = -51,
- I40E_ERR_SRQ_ENABLED = -52,
- 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_BAD_IWARP_CQE = -58,
- I40E_ERR_NVM_BLANK_MODE = -59,
- I40E_ERR_NOT_IMPLEMENTED = -60,
- I40E_ERR_PE_DOORBELL_NOT_ENABLED = -61,
- 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,
+enum iavf_status {
+ IAVF_SUCCESS = 0,
+ IAVF_ERR_NVM = -1,
+ IAVF_ERR_NVM_CHECKSUM = -2,
+ IAVF_ERR_PHY = -3,
+ IAVF_ERR_CONFIG = -4,
+ IAVF_ERR_PARAM = -5,
+ IAVF_ERR_MAC_TYPE = -6,
+ IAVF_ERR_UNKNOWN_PHY = -7,
+ IAVF_ERR_LINK_SETUP = -8,
+ IAVF_ERR_ADAPTER_STOPPED = -9,
+ IAVF_ERR_INVALID_MAC_ADDR = -10,
+ IAVF_ERR_DEVICE_NOT_SUPPORTED = -11,
+ IAVF_ERR_MASTER_REQUESTS_PENDING = -12,
+ IAVF_ERR_INVALID_LINK_SETTINGS = -13,
+ IAVF_ERR_AUTONEG_NOT_COMPLETE = -14,
+ IAVF_ERR_RESET_FAILED = -15,
+ IAVF_ERR_SWFW_SYNC = -16,
+ IAVF_ERR_NO_AVAILABLE_VSI = -17,
+ IAVF_ERR_NO_MEMORY = -18,
+ IAVF_ERR_BAD_PTR = -19,
+ IAVF_ERR_RING_FULL = -20,
+ IAVF_ERR_INVALID_PD_ID = -21,
+ IAVF_ERR_INVALID_QP_ID = -22,
+ IAVF_ERR_INVALID_CQ_ID = -23,
+ IAVF_ERR_INVALID_CEQ_ID = -24,
+ IAVF_ERR_INVALID_AEQ_ID = -25,
+ IAVF_ERR_INVALID_SIZE = -26,
+ IAVF_ERR_INVALID_ARP_INDEX = -27,
+ IAVF_ERR_INVALID_FPM_FUNC_ID = -28,
+ IAVF_ERR_QP_INVALID_MSG_SIZE = -29,
+ IAVF_ERR_QP_TOOMANY_WRS_POSTED = -30,
+ IAVF_ERR_INVALID_FRAG_COUNT = -31,
+ IAVF_ERR_QUEUE_EMPTY = -32,
+ IAVF_ERR_INVALID_ALIGNMENT = -33,
+ IAVF_ERR_FLUSHED_QUEUE = -34,
+ IAVF_ERR_INVALID_PUSH_PAGE_INDEX = -35,
+ IAVF_ERR_INVALID_IMM_DATA_SIZE = -36,
+ IAVF_ERR_TIMEOUT = -37,
+ IAVF_ERR_OPCODE_MISMATCH = -38,
+ IAVF_ERR_CQP_COMPL_ERROR = -39,
+ IAVF_ERR_INVALID_VF_ID = -40,
+ IAVF_ERR_INVALID_HMCFN_ID = -41,
+ IAVF_ERR_BACKING_PAGE_ERROR = -42,
+ IAVF_ERR_NO_PBLCHUNKS_AVAILABLE = -43,
+ IAVF_ERR_INVALID_PBLE_INDEX = -44,
+ IAVF_ERR_INVALID_SD_INDEX = -45,
+ IAVF_ERR_INVALID_PAGE_DESC_INDEX = -46,
+ IAVF_ERR_INVALID_SD_TYPE = -47,
+ IAVF_ERR_MEMCPY_FAILED = -48,
+ IAVF_ERR_INVALID_HMC_OBJ_INDEX = -49,
+ IAVF_ERR_INVALID_HMC_OBJ_COUNT = -50,
+ IAVF_ERR_INVALID_SRQ_ARM_LIMIT = -51,
+ IAVF_ERR_SRQ_ENABLED = -52,
+ IAVF_ERR_ADMIN_QUEUE_ERROR = -53,
+ IAVF_ERR_ADMIN_QUEUE_TIMEOUT = -54,
+ IAVF_ERR_BUF_TOO_SHORT = -55,
+ IAVF_ERR_ADMIN_QUEUE_FULL = -56,
+ IAVF_ERR_ADMIN_QUEUE_NO_WORK = -57,
+ IAVF_ERR_BAD_IWARP_CQE = -58,
+ IAVF_ERR_NVM_BLANK_MODE = -59,
+ IAVF_ERR_NOT_IMPLEMENTED = -60,
+ IAVF_ERR_PE_DOORBELL_NOT_ENABLED = -61,
+ IAVF_ERR_DIAG_TEST_FAILED = -62,
+ IAVF_ERR_NOT_READY = -63,
+ IAVF_NOT_SUPPORTED = -64,
+ IAVF_ERR_FIRMWARE_API_VERSION = -65,
+ IAVF_ERR_ADMIN_QUEUE_CRITICAL_ERROR = -66,
};
#endif /* _IAVF_STATUS_H_ */
diff --git a/drivers/net/ethernet/intel/iavf/iavf_trace.h b/drivers/net/ethernet/intel/iavf/iavf_trace.h
index 1474f5539751..1058e68a02b4 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_trace.h
+++ b/drivers/net/ethernet/intel/iavf/iavf_trace.h
@@ -17,8 +17,8 @@
/* See trace-events-sample.h for a detailed description of why this
* guard clause is different from most normal include files.
*/
-#if !defined(_I40E_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
-#define _I40E_TRACE_H_
+#if !defined(_IAVF_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _IAVF_TRACE_H_
#include <linux/tracepoint.h>
diff --git a/drivers/net/ethernet/intel/iavf/iavf_txrx.c b/drivers/net/ethernet/intel/iavf/iavf_txrx.c
index 06d1509d57f7..0cca1b589b56 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_txrx.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_txrx.c
@@ -190,7 +190,7 @@ void iavf_detect_recover_hung(struct iavf_vsi *vsi)
static bool iavf_clean_tx_irq(struct iavf_vsi *vsi,
struct iavf_ring *tx_ring, int napi_budget)
{
- u16 i = tx_ring->next_to_clean;
+ int i = tx_ring->next_to_clean;
struct iavf_tx_buffer *tx_buf;
struct iavf_tx_desc *tx_desc;
unsigned int total_bytes = 0, total_packets = 0;
@@ -379,19 +379,19 @@ static inline unsigned int iavf_itr_divisor(struct iavf_q_vector *q_vector)
unsigned int divisor;
switch (q_vector->adapter->link_speed) {
- case I40E_LINK_SPEED_40GB:
+ case IAVF_LINK_SPEED_40GB:
divisor = IAVF_ITR_ADAPTIVE_MIN_INC * 1024;
break;
- case I40E_LINK_SPEED_25GB:
- case I40E_LINK_SPEED_20GB:
+ case IAVF_LINK_SPEED_25GB:
+ case IAVF_LINK_SPEED_20GB:
divisor = IAVF_ITR_ADAPTIVE_MIN_INC * 512;
break;
default:
- case I40E_LINK_SPEED_10GB:
+ case IAVF_LINK_SPEED_10GB:
divisor = IAVF_ITR_ADAPTIVE_MIN_INC * 256;
break;
- case I40E_LINK_SPEED_1GB:
- case I40E_LINK_SPEED_100MB:
+ case IAVF_LINK_SPEED_1GB:
+ case IAVF_LINK_SPEED_100MB:
divisor = IAVF_ITR_ADAPTIVE_MIN_INC * 32;
break;
}
@@ -1236,6 +1236,9 @@ static void iavf_add_rx_frag(struct iavf_ring *rx_ring,
unsigned int truesize = SKB_DATA_ALIGN(size + iavf_rx_offset(rx_ring));
#endif
+ if (!size)
+ return;
+
skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, rx_buffer->page,
rx_buffer->page_offset, size, truesize);
@@ -1260,6 +1263,9 @@ static struct iavf_rx_buffer *iavf_get_rx_buffer(struct iavf_ring *rx_ring,
{
struct iavf_rx_buffer *rx_buffer;
+ if (!size)
+ return NULL;
+
rx_buffer = &rx_ring->rx_bi[rx_ring->next_to_clean];
prefetchw(rx_buffer->page);
@@ -1290,7 +1296,7 @@ static struct sk_buff *iavf_construct_skb(struct iavf_ring *rx_ring,
struct iavf_rx_buffer *rx_buffer,
unsigned int size)
{
- void *va = page_address(rx_buffer->page) + rx_buffer->page_offset;
+ void *va;
#if (PAGE_SIZE < 8192)
unsigned int truesize = iavf_rx_pg_size(rx_ring) / 2;
#else
@@ -1299,7 +1305,10 @@ static struct sk_buff *iavf_construct_skb(struct iavf_ring *rx_ring,
unsigned int headlen;
struct sk_buff *skb;
+ if (!rx_buffer)
+ return NULL;
/* prefetch first cache line of first page */
+ va = page_address(rx_buffer->page) + rx_buffer->page_offset;
prefetch(va);
#if L1_CACHE_BYTES < 128
prefetch(va + L1_CACHE_BYTES);
@@ -1354,7 +1363,7 @@ static struct sk_buff *iavf_build_skb(struct iavf_ring *rx_ring,
struct iavf_rx_buffer *rx_buffer,
unsigned int size)
{
- void *va = page_address(rx_buffer->page) + rx_buffer->page_offset;
+ void *va;
#if (PAGE_SIZE < 8192)
unsigned int truesize = iavf_rx_pg_size(rx_ring) / 2;
#else
@@ -1363,7 +1372,10 @@ static struct sk_buff *iavf_build_skb(struct iavf_ring *rx_ring,
#endif
struct sk_buff *skb;
+ if (!rx_buffer)
+ return NULL;
/* prefetch first cache line of first page */
+ va = page_address(rx_buffer->page) + rx_buffer->page_offset;
prefetch(va);
#if L1_CACHE_BYTES < 128
prefetch(va + L1_CACHE_BYTES);
@@ -1398,6 +1410,9 @@ static struct sk_buff *iavf_build_skb(struct iavf_ring *rx_ring,
static void iavf_put_rx_buffer(struct iavf_ring *rx_ring,
struct iavf_rx_buffer *rx_buffer)
{
+ if (!rx_buffer)
+ return;
+
if (iavf_can_reuse_rx_page(rx_buffer)) {
/* hand second half of page back to the ring */
iavf_reuse_rx_page(rx_ring, rx_buffer);
@@ -1496,11 +1511,12 @@ static int iavf_clean_rx_irq(struct iavf_ring *rx_ring, int budget)
* verified the descriptor has been written back.
*/
dma_rmb();
+#define IAVF_RXD_DD BIT(IAVF_RX_DESC_STATUS_DD_SHIFT)
+ if (!iavf_test_staterr(rx_desc, IAVF_RXD_DD))
+ break;
size = (qword & IAVF_RXD_QW1_LENGTH_PBUF_MASK) >>
IAVF_RXD_QW1_LENGTH_PBUF_SHIFT;
- if (!size)
- break;
iavf_trace(clean_rx_irq, rx_ring, rx_desc, skb);
rx_buffer = iavf_get_rx_buffer(rx_ring, size);
@@ -1516,7 +1532,8 @@ static int iavf_clean_rx_irq(struct iavf_ring *rx_ring, int budget)
/* exit if we failed to retrieve a buffer */
if (!skb) {
rx_ring->rx_stats.alloc_buff_failed++;
- rx_buffer->pagecnt_bias++;
+ if (rx_buffer)
+ rx_buffer->pagecnt_bias++;
break;
}
diff --git a/drivers/net/ethernet/intel/iavf/iavf_type.h b/drivers/net/ethernet/intel/iavf/iavf_type.h
index ca89583613fb..7190a40c540c 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_type.h
+++ b/drivers/net/ethernet/intel/iavf/iavf_type.h
@@ -7,7 +7,7 @@
#include "iavf_status.h"
#include "iavf_osdep.h"
#include "iavf_register.h"
-#include "i40e_adminq.h"
+#include "iavf_adminq.h"
#include "iavf_devids.h"
#define IAVF_RXQ_CTX_DBUFF_SHIFT 7
@@ -21,7 +21,7 @@
/* forward declaration */
struct iavf_hw;
-typedef void (*I40E_ADMINQ_CALLBACK)(struct iavf_hw *, struct i40e_aq_desc *);
+typedef void (*IAVF_ADMINQ_CALLBACK)(struct iavf_hw *, struct iavf_aq_desc *);
/* Data type manipulation macros. */
diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
index e64751da0921..d49d58a6de80 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
@@ -22,7 +22,7 @@ static int iavf_send_pf_msg(struct iavf_adapter *adapter,
enum virtchnl_ops op, u8 *msg, u16 len)
{
struct iavf_hw *hw = &adapter->hw;
- iavf_status err;
+ enum iavf_status err;
if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED)
return 0; /* nothing to see here, move along */
@@ -41,7 +41,7 @@ static int iavf_send_pf_msg(struct iavf_adapter *adapter,
*
* Send API version admin queue message to the PF. The reply is not checked
* in this function. Returns 0 if the message was successfully
- * sent, or one of the I40E_ADMIN_QUEUE_ERROR_ statuses if not.
+ * sent, or one of the IAVF_ADMIN_QUEUE_ERROR_ statuses if not.
**/
int iavf_send_api_ver(struct iavf_adapter *adapter)
{
@@ -60,16 +60,16 @@ int iavf_send_api_ver(struct iavf_adapter *adapter)
*
* Compare API versions with the PF. Must be called after admin queue is
* initialized. Returns 0 if API versions match, -EIO if they do not,
- * I40E_ERR_ADMIN_QUEUE_NO_WORK if the admin queue is empty, and any errors
+ * IAVF_ERR_ADMIN_QUEUE_NO_WORK if the admin queue is empty, and any errors
* from the firmware are propagated.
**/
int iavf_verify_api_ver(struct iavf_adapter *adapter)
{
struct virtchnl_version_info *pf_vvi;
struct iavf_hw *hw = &adapter->hw;
- struct i40e_arq_event_info event;
+ struct iavf_arq_event_info event;
enum virtchnl_ops op;
- iavf_status err;
+ enum iavf_status err;
event.buf_len = IAVF_MAX_AQ_BUF_SIZE;
event.msg_buf = kzalloc(event.buf_len, GFP_KERNEL);
@@ -92,7 +92,7 @@ int iavf_verify_api_ver(struct iavf_adapter *adapter)
}
- err = (iavf_status)le32_to_cpu(event.desc.cookie_low);
+ err = (enum iavf_status)le32_to_cpu(event.desc.cookie_low);
if (err)
goto out_alloc;
@@ -123,7 +123,7 @@ out:
*
* Send VF configuration request admin queue message to the PF. The reply
* is not checked in this function. Returns 0 if the message was
- * successfully sent, or one of the I40E_ADMIN_QUEUE_ERROR_ statuses if not.
+ * successfully sent, or one of the IAVF_ADMIN_QUEUE_ERROR_ statuses if not.
**/
int iavf_send_vf_config_msg(struct iavf_adapter *adapter)
{
@@ -189,9 +189,9 @@ static void iavf_validate_num_queues(struct iavf_adapter *adapter)
int iavf_get_vf_config(struct iavf_adapter *adapter)
{
struct iavf_hw *hw = &adapter->hw;
- struct i40e_arq_event_info event;
+ struct iavf_arq_event_info event;
enum virtchnl_ops op;
- iavf_status err;
+ enum iavf_status err;
u16 len;
len = sizeof(struct virtchnl_vf_resource) +
@@ -216,7 +216,7 @@ int iavf_get_vf_config(struct iavf_adapter *adapter)
break;
}
- err = (iavf_status)le32_to_cpu(event.desc.cookie_low);
+ err = (enum iavf_status)le32_to_cpu(event.desc.cookie_low);
memcpy(adapter->vf_res, event.msg_buf, min(event.msg_len, len));
/* some PFs send more queues than we should have so validate that
@@ -242,7 +242,8 @@ void iavf_configure_queues(struct iavf_adapter *adapter)
struct virtchnl_vsi_queue_config_info *vqci;
struct virtchnl_queue_pair_info *vqpi;
int pairs = adapter->num_active_queues;
- int i, len, max_frame = IAVF_MAX_RXBUFFER;
+ int i, max_frame = IAVF_MAX_RXBUFFER;
+ size_t len;
if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
/* bail because we already have a command pending */
@@ -251,8 +252,7 @@ void iavf_configure_queues(struct iavf_adapter *adapter)
return;
}
adapter->current_op = VIRTCHNL_OP_CONFIG_VSI_QUEUES;
- len = sizeof(struct virtchnl_vsi_queue_config_info) +
- (sizeof(struct virtchnl_queue_pair_info) * pairs);
+ len = struct_size(vqci, qpair, pairs);
vqci = kzalloc(len, GFP_KERNEL);
if (!vqci)
return;
@@ -351,8 +351,9 @@ void iavf_map_queues(struct iavf_adapter *adapter)
{
struct virtchnl_irq_map_info *vimi;
struct virtchnl_vector_map *vecmap;
- int v_idx, q_vectors, len;
struct iavf_q_vector *q_vector;
+ int v_idx, q_vectors;
+ size_t len;
if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
/* bail because we already have a command pending */
@@ -364,9 +365,7 @@ void iavf_map_queues(struct iavf_adapter *adapter)
q_vectors = adapter->num_msix_vectors - NONQ_VECS;
- len = sizeof(struct virtchnl_irq_map_info) +
- (adapter->num_msix_vectors *
- sizeof(struct virtchnl_vector_map));
+ len = struct_size(vimi, vecmap, adapter->num_msix_vectors);
vimi = kzalloc(len, GFP_KERNEL);
if (!vimi)
return;
@@ -416,7 +415,7 @@ int iavf_request_queues(struct iavf_adapter *adapter, int num)
return -EBUSY;
}
- vfres.num_queue_pairs = num;
+ vfres.num_queue_pairs = min_t(int, num, num_online_cpus());
adapter->current_op = VIRTCHNL_OP_REQUEST_QUEUES;
adapter->flags |= IAVF_FLAG_REINIT_ITR_NEEDED;
@@ -433,9 +432,10 @@ int iavf_request_queues(struct iavf_adapter *adapter, int num)
void iavf_add_ether_addrs(struct iavf_adapter *adapter)
{
struct virtchnl_ether_addr_list *veal;
- int len, i = 0, count = 0;
struct iavf_mac_filter *f;
+ int i = 0, count = 0;
bool more = false;
+ size_t len;
if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
/* bail because we already have a command pending */
@@ -457,15 +457,13 @@ void iavf_add_ether_addrs(struct iavf_adapter *adapter)
}
adapter->current_op = VIRTCHNL_OP_ADD_ETH_ADDR;
- len = sizeof(struct virtchnl_ether_addr_list) +
- (count * sizeof(struct virtchnl_ether_addr));
+ len = 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 = sizeof(struct virtchnl_ether_addr_list) +
- (count * sizeof(struct virtchnl_ether_addr));
+ len = struct_size(veal, list, count);
more = true;
}
@@ -505,8 +503,9 @@ void iavf_del_ether_addrs(struct iavf_adapter *adapter)
{
struct virtchnl_ether_addr_list *veal;
struct iavf_mac_filter *f, *ftmp;
- int len, i = 0, count = 0;
+ int i = 0, count = 0;
bool more = false;
+ size_t len;
if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
/* bail because we already have a command pending */
@@ -528,15 +527,13 @@ void iavf_del_ether_addrs(struct iavf_adapter *adapter)
}
adapter->current_op = VIRTCHNL_OP_DEL_ETH_ADDR;
- len = sizeof(struct virtchnl_ether_addr_list) +
- (count * sizeof(struct virtchnl_ether_addr));
+ len = 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 = sizeof(struct virtchnl_ether_addr_list) +
- (count * sizeof(struct virtchnl_ether_addr));
+ len = struct_size(veal, list, count);
more = true;
}
veal = kzalloc(len, GFP_ATOMIC);
@@ -938,22 +935,22 @@ static void iavf_print_link_message(struct iavf_adapter *adapter)
}
switch (adapter->link_speed) {
- case I40E_LINK_SPEED_40GB:
+ case IAVF_LINK_SPEED_40GB:
speed = "40 G";
break;
- case I40E_LINK_SPEED_25GB:
+ case IAVF_LINK_SPEED_25GB:
speed = "25 G";
break;
- case I40E_LINK_SPEED_20GB:
+ case IAVF_LINK_SPEED_20GB:
speed = "20 G";
break;
- case I40E_LINK_SPEED_10GB:
+ case IAVF_LINK_SPEED_10GB:
speed = "10 G";
break;
- case I40E_LINK_SPEED_1GB:
+ case IAVF_LINK_SPEED_1GB:
speed = "1000 M";
break;
- case I40E_LINK_SPEED_100MB:
+ case IAVF_LINK_SPEED_100MB:
speed = "100 M";
break;
default:
@@ -973,7 +970,7 @@ static void iavf_print_link_message(struct iavf_adapter *adapter)
void iavf_enable_channels(struct iavf_adapter *adapter)
{
struct virtchnl_tc_info *vti = NULL;
- u16 len;
+ size_t len;
int i;
if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
@@ -983,9 +980,7 @@ void iavf_enable_channels(struct iavf_adapter *adapter)
return;
}
- len = (adapter->num_tc * sizeof(struct virtchnl_channel_info)) +
- sizeof(struct virtchnl_tc_info);
-
+ len = struct_size(vti, list, adapter->num_tc - 1);
vti = kzalloc(len, GFP_KERNEL);
if (!vti)
return;
@@ -1184,8 +1179,8 @@ void iavf_request_reset(struct iavf_adapter *adapter)
* This function handles the reply messages.
**/
void iavf_virtchnl_completion(struct iavf_adapter *adapter,
- enum virtchnl_ops v_opcode, iavf_status v_retval,
- u8 *msg, u16 msglen)
+ enum virtchnl_ops v_opcode,
+ enum iavf_status v_retval, u8 *msg, u16 msglen)
{
struct net_device *netdev = adapter->netdev;
@@ -1238,7 +1233,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
if (!(adapter->flags & IAVF_FLAG_RESET_PENDING)) {
adapter->flags |= IAVF_FLAG_RESET_PENDING;
dev_info(&adapter->pdev->dev, "Scheduling reset task\n");
- schedule_work(&adapter->reset_task);
+ queue_work(iavf_wq, &adapter->reset_task);
}
break;
default:
diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
index 792e6e42030e..9ee6b55553c0 100644
--- a/drivers/net/ethernet/intel/ice/ice.h
+++ b/drivers/net/ethernet/intel/ice/ice.h
@@ -44,15 +44,22 @@
extern const char ice_drv_ver[];
#define ICE_BAR0 0
#define ICE_REQ_DESC_MULTIPLE 32
-#define ICE_MIN_NUM_DESC ICE_REQ_DESC_MULTIPLE
+#define ICE_MIN_NUM_DESC 64
#define ICE_MAX_NUM_DESC 8160
-/* set default number of Rx/Tx descriptors to the minimum between
- * ICE_MAX_NUM_DESC and the number of descriptors to fill up an entire page
+#define ICE_DFLT_MIN_RX_DESC 512
+/* if the default number of Rx descriptors between ICE_MAX_NUM_DESC and the
+ * number of descriptors to fill up an entire page is greater than or equal to
+ * ICE_DFLT_MIN_RX_DESC set it based on page size, otherwise set it to
+ * ICE_DFLT_MIN_RX_DESC
+ */
+#define ICE_DFLT_NUM_RX_DESC \
+ min_t(u16, ICE_MAX_NUM_DESC, \
+ max_t(u16, ALIGN(PAGE_SIZE / sizeof(union ice_32byte_rx_desc), \
+ ICE_REQ_DESC_MULTIPLE), \
+ ICE_DFLT_MIN_RX_DESC))
+/* set default number of Tx descriptors to the minimum between ICE_MAX_NUM_DESC
+ * and the number of descriptors to fill up an entire page
*/
-#define ICE_DFLT_NUM_RX_DESC min_t(u16, ICE_MAX_NUM_DESC, \
- ALIGN(PAGE_SIZE / \
- sizeof(union ice_32byte_rx_desc), \
- ICE_REQ_DESC_MULTIPLE))
#define ICE_DFLT_NUM_TX_DESC min_t(u16, ICE_MAX_NUM_DESC, \
ALIGN(PAGE_SIZE / \
sizeof(struct ice_tx_desc), \
@@ -160,7 +167,7 @@ struct ice_tc_cfg {
struct ice_res_tracker {
u16 num_entries;
- u16 search_hint;
+ u16 end;
u16 list[1];
};
@@ -182,6 +189,7 @@ struct ice_sw {
};
enum ice_state {
+ __ICE_TESTING,
__ICE_DOWN,
__ICE_NEEDS_RESTART,
__ICE_PREPARED_FOR_RESET, /* set by driver when prepared */
@@ -244,8 +252,7 @@ struct ice_vsi {
u32 rx_buf_failed;
u32 rx_page_failed;
int num_q_vectors;
- int sw_base_vector; /* Irq base for OS reserved vectors */
- int hw_base_vector; /* HW (absolute) index of a vector */
+ int base_vector; /* IRQ base for OS reserved vectors */
enum ice_vsi_type type;
u16 vsi_num; /* HW (absolute) index of this VSI */
u16 idx; /* software index in pf->vsi[] */
@@ -277,10 +284,10 @@ struct ice_vsi {
struct list_head tmp_sync_list; /* MAC filters to be synced */
struct list_head tmp_unsync_list; /* MAC filters to be unsynced */
- u8 irqs_ready;
- u8 current_isup; /* Sync 'link up' logging */
- u8 stat_offsets_loaded;
- u8 vlan_ena;
+ u8 irqs_ready:1;
+ u8 current_isup:1; /* Sync 'link up' logging */
+ u8 stat_offsets_loaded:1;
+ u8 vlan_ena:1;
/* queue information */
u8 tx_mapping_mode; /* ICE_MAP_MODE_[CONTIG|SCATTER] */
@@ -330,7 +337,7 @@ enum ice_pf_flags {
ICE_FLAG_DCB_CAPABLE,
ICE_FLAG_DCB_ENA,
ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA,
- ICE_FLAG_DISABLE_FW_LLDP,
+ ICE_FLAG_ENABLE_FW_LLDP,
ICE_FLAG_ETHTOOL_CTXT, /* set when ethtool holds RTNL lock */
ICE_PF_FLAGS_NBITS /* must be last */
};
@@ -340,10 +347,12 @@ struct ice_pf {
/* OS reserved IRQ details */
struct msix_entry *msix_entries;
- struct ice_res_tracker *sw_irq_tracker;
-
- /* HW reserved Interrupts for this PF */
- struct ice_res_tracker *hw_irq_tracker;
+ struct ice_res_tracker *irq_tracker;
+ /* First MSIX vector used by SR-IOV VFs. Calculated by subtracting the
+ * number of MSIX vectors needed for all SR-IOV VFs from the number of
+ * MSIX vectors allowed on this PF.
+ */
+ u16 sriov_base_vector;
struct ice_vsi **vsi; /* VSIs created by the driver */
struct ice_sw *first_sw; /* first switch created by firmware */
@@ -365,10 +374,8 @@ struct ice_pf {
struct mutex sw_mutex; /* lock for protecting VSI alloc flow */
u32 msg_enable;
u32 hw_csum_rx_error;
- u32 sw_oicr_idx; /* Other interrupt cause SW vector index */
+ u32 oicr_idx; /* Other interrupt cause MSIX vector index */
u32 num_avail_sw_msix; /* remaining MSIX SW vectors left unclaimed */
- u32 hw_oicr_idx; /* Other interrupt cause vector HW index */
- u32 num_avail_hw_msix; /* remaining HW MSIX vectors left unclaimed */
u32 num_lan_msix; /* Total MSIX vectors for base driver */
u16 num_lan_tx; /* num LAN Tx queues setup */
u16 num_lan_rx; /* num LAN Rx queues setup */
@@ -384,7 +391,7 @@ struct ice_pf {
struct ice_hw_port_stats stats;
struct ice_hw_port_stats stats_prev;
struct ice_hw hw;
- u8 stat_prev_loaded; /* has previous stats been loaded */
+ u8 stat_prev_loaded:1; /* has previous stats been loaded */
#ifdef CONFIG_DCB
u16 dcbx_cap;
#endif /* CONFIG_DCB */
@@ -392,6 +399,7 @@ struct ice_pf {
unsigned long tx_timeout_last_recovery;
u32 tx_timeout_recovery_level;
char int_name[ICE_INT_NAME_STR_LEN];
+ u32 sw_int_count;
};
struct ice_netdev_priv {
@@ -409,7 +417,7 @@ ice_irq_dynamic_ena(struct ice_hw *hw, struct ice_vsi *vsi,
struct ice_q_vector *q_vector)
{
u32 vector = (vsi && q_vector) ? q_vector->reg_idx :
- ((struct ice_pf *)hw->back)->hw_oicr_idx;
+ ((struct ice_pf *)hw->back)->oicr_idx;
int itr = ICE_ITR_NONE;
u32 val;
@@ -444,17 +452,22 @@ ice_find_vsi_by_type(struct ice_pf *pf, enum ice_vsi_type type)
return NULL;
}
+int ice_vsi_setup_tx_rings(struct ice_vsi *vsi);
+int ice_vsi_setup_rx_rings(struct ice_vsi *vsi);
void ice_set_ethtool_ops(struct net_device *netdev);
int ice_up(struct ice_vsi *vsi);
int ice_down(struct ice_vsi *vsi);
+int ice_vsi_cfg(struct ice_vsi *vsi);
+struct ice_vsi *ice_lb_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi);
int ice_set_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size);
int ice_get_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size);
void ice_fill_rss_lut(u8 *lut, u16 rss_table_size, u16 rss_size);
void ice_print_link_msg(struct ice_vsi *vsi, bool isup);
-void ice_napi_del(struct ice_vsi *vsi);
#ifdef CONFIG_DCB
int ice_pf_ena_all_vsi(struct ice_pf *pf, bool locked);
void ice_pf_dis_all_vsi(struct ice_pf *pf, bool locked);
#endif /* CONFIG_DCB */
+int ice_open(struct net_device *netdev);
+int ice_stop(struct net_device *netdev);
#endif /* _ICE_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
index 6ef083002f5b..765e3c2ed045 100644
--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
@@ -35,8 +35,8 @@ struct ice_aqc_get_ver {
/* Queue Shutdown (direct 0x0003) */
struct ice_aqc_q_shutdown {
-#define ICE_AQC_DRIVER_UNLOADING BIT(0)
__le32 driver_unloading;
+#define ICE_AQC_DRIVER_UNLOADING BIT(0)
u8 reserved[12];
};
@@ -120,11 +120,9 @@ struct ice_aqc_manage_mac_read {
#define ICE_AQC_MAN_MAC_WOL_ADDR_VALID BIT(7)
#define ICE_AQC_MAN_MAC_READ_S 4
#define ICE_AQC_MAN_MAC_READ_M (0xF << ICE_AQC_MAN_MAC_READ_S)
- u8 lport_num;
- u8 lport_num_valid;
-#define ICE_AQC_MAN_MAC_PORT_NUM_IS_VALID BIT(0)
+ u8 rsvd[2];
u8 num_addr; /* Used in response */
- u8 reserved[3];
+ u8 rsvd1[3];
__le32 addr_high;
__le32 addr_low;
};
@@ -140,7 +138,7 @@ struct ice_aqc_manage_mac_read_resp {
/* Manage MAC address, write command - direct (0x0108) */
struct ice_aqc_manage_mac_write {
- u8 port_num;
+ u8 rsvd;
u8 flags;
#define ICE_AQC_MAN_MAC_WR_MC_MAG_EN BIT(0)
#define ICE_AQC_MAN_MAC_WR_WOL_LAA_PFR_KEEP BIT(1)
@@ -920,6 +918,8 @@ struct ice_aqc_get_phy_caps_data {
#define ICE_AQC_PHY_EN_LINK BIT(3)
#define ICE_AQC_PHY_AN_MODE BIT(4)
#define ICE_AQC_GET_PHY_EN_MOD_QUAL BIT(5)
+#define ICE_AQC_PHY_EN_AUTO_FEC BIT(7)
+#define ICE_AQC_PHY_CAPS_MASK ICE_M(0xff, 0)
u8 low_power_ctrl;
#define ICE_AQC_PHY_EN_D3COLD_LOW_POWER_AUTONEG BIT(0)
__le16 eee_cap;
@@ -932,6 +932,7 @@ struct ice_aqc_get_phy_caps_data {
#define ICE_AQC_PHY_EEE_EN_40GBASE_KR4 BIT(6)
__le16 eeer_value;
u8 phy_id_oui[4]; /* PHY/Module ID connected on the port */
+ u8 phy_fw_ver[8];
u8 link_fec_options;
#define ICE_AQC_PHY_FEC_10G_KR_40G_KR4_EN BIT(0)
#define ICE_AQC_PHY_FEC_10G_KR_40G_KR4_REQ BIT(1)
@@ -940,6 +941,8 @@ struct ice_aqc_get_phy_caps_data {
#define ICE_AQC_PHY_FEC_25G_RS_544_REQ BIT(4)
#define ICE_AQC_PHY_FEC_25G_RS_CLAUSE91_EN BIT(6)
#define ICE_AQC_PHY_FEC_25G_KR_CLAUSE74_EN BIT(7)
+#define ICE_AQC_PHY_FEC_MASK ICE_M(0xdf, 0)
+ u8 rsvd1; /* Byte 35 reserved */
u8 extended_compliance_code;
#define ICE_MODULE_TYPE_TOTAL_BYTE 3
u8 module_type[ICE_MODULE_TYPE_TOTAL_BYTE];
@@ -954,13 +957,14 @@ struct ice_aqc_get_phy_caps_data {
#define ICE_AQC_MOD_TYPE_BYTE2_SFP_PLUS 0xA0
#define ICE_AQC_MOD_TYPE_BYTE2_QSFP_PLUS 0x86
u8 qualified_module_count;
+ u8 rsvd2[7]; /* Bytes 47:41 reserved */
#define ICE_AQC_QUAL_MOD_COUNT_MAX 16
struct {
u8 v_oui[3];
- u8 rsvd1;
+ u8 rsvd3;
u8 v_part[16];
__le32 v_rev;
- __le64 rsvd8;
+ __le64 rsvd4;
} qual_modules[ICE_AQC_QUAL_MOD_COUNT_MAX];
};
@@ -1062,6 +1066,7 @@ struct ice_aqc_get_link_status_data {
#define ICE_AQ_LINK_25G_KR_FEC_EN BIT(0)
#define ICE_AQ_LINK_25G_RS_528_FEC_EN BIT(1)
#define ICE_AQ_LINK_25G_RS_544_FEC_EN BIT(2)
+#define ICE_AQ_FEC_MASK ICE_M(0x7, 0)
/* Pacing Config */
#define ICE_AQ_CFG_PACING_S 3
#define ICE_AQ_CFG_PACING_M (0xF << ICE_AQ_CFG_PACING_S)
@@ -1112,6 +1117,14 @@ struct ice_aqc_set_event_mask {
u8 reserved1[6];
};
+/* Set MAC Loopback command (direct 0x0620) */
+struct ice_aqc_set_mac_lb {
+ u8 lb_mode;
+#define ICE_AQ_MAC_LB_EN BIT(0)
+#define ICE_AQ_MAC_LB_OSC_CLK BIT(1)
+ u8 reserved[15];
+};
+
/* Set Port Identification LED (direct, 0x06E9) */
struct ice_aqc_set_port_id_led {
u8 lport_num;
@@ -1145,6 +1158,17 @@ struct ice_aqc_nvm {
__le32 addr_low;
};
+/* NVM Checksum Command (direct, 0x0706) */
+struct ice_aqc_nvm_checksum {
+ u8 flags;
+#define ICE_AQC_NVM_CHECKSUM_VERIFY BIT(0)
+#define ICE_AQC_NVM_CHECKSUM_RECALC BIT(1)
+ u8 rsvd;
+ __le16 checksum; /* Used only by response */
+#define ICE_AQC_NVM_CHECKSUM_CORRECT 0xBABA
+ u8 rsvd2[12];
+};
+
/**
* Send to PF command (indirect 0x0801) ID is only used by PF
*
@@ -1249,7 +1273,7 @@ struct ice_aqc_get_cee_dcb_cfg_resp {
};
/* Set Local LLDP MIB (indirect 0x0A08)
- * Used to replace the local MIB of a given LLDP agent. e.g. DCBx
+ * Used to replace the local MIB of a given LLDP agent. e.g. DCBX
*/
struct ice_aqc_lldp_set_local_mib {
u8 type;
@@ -1266,7 +1290,7 @@ struct ice_aqc_lldp_set_local_mib {
};
/* Stop/Start LLDP Agent (direct 0x0A09)
- * Used for stopping/starting specific LLDP agent. e.g. DCBx.
+ * Used for stopping/starting specific LLDP agent. e.g. DCBX.
* The same structure is used for the response, with the command field
* being used as the status field.
*/
@@ -1539,6 +1563,7 @@ struct ice_aq_desc {
struct ice_aqc_query_txsched_res query_sched_res;
struct ice_aqc_query_port_ets port_ets;
struct ice_aqc_nvm nvm;
+ struct ice_aqc_nvm_checksum nvm_checksum;
struct ice_aqc_pf_vf_msg virt;
struct ice_aqc_lldp_get_mib lldp_get_mib;
struct ice_aqc_lldp_set_mib_change lldp_set_event;
@@ -1554,6 +1579,7 @@ struct ice_aq_desc {
struct ice_aqc_add_update_free_vsi_resp add_update_free_vsi_res;
struct ice_aqc_fw_logging fw_logging;
struct ice_aqc_get_clear_fw_log get_clear_fw_log;
+ struct ice_aqc_set_mac_lb set_mac_lb;
struct ice_aqc_alloc_free_res_cmd sw_res_ctrl;
struct ice_aqc_set_event_mask set_event_mask;
struct ice_aqc_get_link_status get_link_status;
@@ -1642,10 +1668,12 @@ enum ice_adminq_opc {
ice_aqc_opc_restart_an = 0x0605,
ice_aqc_opc_get_link_status = 0x0607,
ice_aqc_opc_set_event_mask = 0x0613,
+ ice_aqc_opc_set_mac_lb = 0x0620,
ice_aqc_opc_set_port_id_led = 0x06E9,
/* NVM commands */
ice_aqc_opc_nvm_read = 0x0701,
+ ice_aqc_opc_nvm_checksum = 0x0706,
/* PF/VF mailbox commands */
ice_mbx_opc_send_msg_to_pf = 0x0801,
@@ -1671,6 +1699,7 @@ enum ice_adminq_opc {
/* debug commands */
ice_aqc_opc_fw_logging = 0xFF09,
+ ice_aqc_opc_fw_logging_info = 0xFF10,
};
#endif /* _ICE_ADMINQ_CMD_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c
index da7878529929..2e0731c1e1a3 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.c
+++ b/drivers/net/ethernet/intel/ice/ice_common.c
@@ -51,9 +51,6 @@ static enum ice_status ice_set_mac_type(struct ice_hw *hw)
*/
void ice_dev_onetime_setup(struct ice_hw *hw)
{
- /* configure Rx - set non pxe mode */
- wr32(hw, GLLAN_RCTL_0, 0x1);
-
#define MBX_PF_VT_PFALLOC 0x00231E80
/* set VFs per PF */
wr32(hw, MBX_PF_VT_PFALLOC, rd32(hw, PF_VT_PFALLOC_HIF));
@@ -307,6 +304,8 @@ ice_aq_get_link_info(struct ice_port_info *pi, bool ena_lse,
hw_link_info->an_info = link_data.an_info;
hw_link_info->ext_info = link_data.ext_info;
hw_link_info->max_frame_size = le16_to_cpu(link_data.max_frame_size);
+ hw_link_info->fec_info = link_data.cfg & ICE_AQ_FEC_MASK;
+ hw_link_info->topo_media_conflict = link_data.topo_media_conflict;
hw_link_info->pacing = link_data.cfg & ICE_AQ_CFG_PACING_M;
/* update fc info */
@@ -476,6 +475,49 @@ static void ice_cleanup_fltr_mgmt_struct(struct ice_hw *hw)
ICE_FW_LOG_DESC_SIZE(ICE_AQC_FW_LOG_ID_MAX)
/**
+ * ice_get_fw_log_cfg - get FW logging configuration
+ * @hw: pointer to the HW struct
+ */
+static enum ice_status ice_get_fw_log_cfg(struct ice_hw *hw)
+{
+ struct ice_aqc_fw_logging_data *config;
+ struct ice_aq_desc desc;
+ enum ice_status status;
+ u16 size;
+
+ size = ICE_FW_LOG_DESC_SIZE_MAX;
+ config = devm_kzalloc(ice_hw_to_dev(hw), size, GFP_KERNEL);
+ if (!config)
+ return ICE_ERR_NO_MEMORY;
+
+ ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_fw_logging_info);
+
+ desc.flags |= cpu_to_le16(ICE_AQ_FLAG_BUF);
+ desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
+
+ status = ice_aq_send_cmd(hw, &desc, config, size, NULL);
+ if (!status) {
+ u16 i;
+
+ /* Save FW logging information into the HW structure */
+ for (i = 0; i < ICE_AQC_FW_LOG_ID_MAX; i++) {
+ u16 v, m, flgs;
+
+ v = le16_to_cpu(config->entry[i]);
+ m = (v & ICE_AQC_FW_LOG_ID_M) >> ICE_AQC_FW_LOG_ID_S;
+ flgs = (v & ICE_AQC_FW_LOG_EN_M) >> ICE_AQC_FW_LOG_EN_S;
+
+ if (m < ICE_AQC_FW_LOG_ID_MAX)
+ hw->fw_log.evnts[m].cur = flgs;
+ }
+ }
+
+ devm_kfree(ice_hw_to_dev(hw), config);
+
+ return status;
+}
+
+/**
* ice_cfg_fw_log - configure FW logging
* @hw: pointer to the HW struct
* @enable: enable certain FW logging events if true, disable all if false
@@ -529,6 +571,11 @@ static enum ice_status ice_cfg_fw_log(struct ice_hw *hw, bool enable)
(!hw->fw_log.actv_evnts || !ice_check_sq_alive(hw, &hw->adminq)))
return 0;
+ /* Get current FW log settings */
+ status = ice_get_fw_log_cfg(hw);
+ if (status)
+ return status;
+
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_fw_logging);
cmd = &desc.params.fw_logging;
@@ -634,17 +681,17 @@ out:
*/
void ice_output_fw_log(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf)
{
- ice_debug(hw, ICE_DBG_AQ_MSG, "[ FW Log Msg Start ]\n");
- ice_debug_array(hw, ICE_DBG_AQ_MSG, 16, 1, (u8 *)buf,
+ ice_debug(hw, ICE_DBG_FW_LOG, "[ FW Log Msg Start ]\n");
+ ice_debug_array(hw, ICE_DBG_FW_LOG, 16, 1, (u8 *)buf,
le16_to_cpu(desc->datalen));
- ice_debug(hw, ICE_DBG_AQ_MSG, "[ FW Log Msg End ]\n");
+ ice_debug(hw, ICE_DBG_FW_LOG, "[ FW Log Msg End ]\n");
}
/**
* ice_get_itr_intrl_gran - determine int/intrl granularity
* @hw: pointer to the HW struct
*
- * Determines the itr/intrl granularities based on the maximum aggregate
+ * Determines the ITR/intrl granularities based on the maximum aggregate
* bandwidth according to the device's configuration during power-on.
*/
static void ice_get_itr_intrl_gran(struct ice_hw *hw)
@@ -815,6 +862,10 @@ err_unroll_cqinit:
/**
* ice_deinit_hw - unroll initialization operations done by ice_init_hw
* @hw: pointer to the hardware structure
+ *
+ * This should be called only during nominal operation, not as a result of
+ * ice_init_hw() failing since ice_init_hw() will take care of unrolling
+ * applicable initializations if it fails for any reason.
*/
void ice_deinit_hw(struct ice_hw *hw)
{
@@ -1447,6 +1498,7 @@ ice_parse_caps(struct ice_hw *hw, void *buf, u32 cap_count,
struct ice_hw_func_caps *func_p = NULL;
struct ice_hw_dev_caps *dev_p = NULL;
struct ice_hw_common_caps *caps;
+ char const *prefix;
u32 i;
if (!buf)
@@ -1457,9 +1509,11 @@ ice_parse_caps(struct ice_hw *hw, void *buf, u32 cap_count,
if (opc == ice_aqc_opc_list_dev_caps) {
dev_p = &hw->dev_caps;
caps = &dev_p->common_cap;
+ prefix = "dev cap";
} else if (opc == ice_aqc_opc_list_func_caps) {
func_p = &hw->func_caps;
caps = &func_p->common_cap;
+ prefix = "func cap";
} else {
ice_debug(hw, ICE_DBG_INIT, "wrong opcode\n");
return;
@@ -1475,28 +1529,29 @@ ice_parse_caps(struct ice_hw *hw, void *buf, u32 cap_count,
case ICE_AQC_CAPS_VALID_FUNCTIONS:
caps->valid_functions = number;
ice_debug(hw, ICE_DBG_INIT,
- "HW caps: Valid Functions = %d\n",
+ "%s: valid functions = %d\n", prefix,
caps->valid_functions);
break;
case ICE_AQC_CAPS_SRIOV:
caps->sr_iov_1_1 = (number == 1);
ice_debug(hw, ICE_DBG_INIT,
- "HW caps: SR-IOV = %d\n", caps->sr_iov_1_1);
+ "%s: SR-IOV = %d\n", prefix,
+ caps->sr_iov_1_1);
break;
case ICE_AQC_CAPS_VF:
if (dev_p) {
dev_p->num_vfs_exposed = number;
ice_debug(hw, ICE_DBG_INIT,
- "HW caps: VFs exposed = %d\n",
+ "%s: VFs exposed = %d\n", prefix,
dev_p->num_vfs_exposed);
} else if (func_p) {
func_p->num_allocd_vfs = number;
func_p->vf_base_id = logical_id;
ice_debug(hw, ICE_DBG_INIT,
- "HW caps: VFs allocated = %d\n",
+ "%s: VFs allocated = %d\n", prefix,
func_p->num_allocd_vfs);
ice_debug(hw, ICE_DBG_INIT,
- "HW caps: VF base_id = %d\n",
+ "%s: VF base_id = %d\n", prefix,
func_p->vf_base_id);
}
break;
@@ -1504,69 +1559,69 @@ ice_parse_caps(struct ice_hw *hw, void *buf, u32 cap_count,
if (dev_p) {
dev_p->num_vsi_allocd_to_host = number;
ice_debug(hw, ICE_DBG_INIT,
- "HW caps: Dev.VSI cnt = %d\n",
+ "%s: num VSI alloc to host = %d\n",
+ prefix,
dev_p->num_vsi_allocd_to_host);
} else if (func_p) {
func_p->guar_num_vsi =
ice_get_num_per_func(hw, ICE_MAX_VSI);
ice_debug(hw, ICE_DBG_INIT,
- "HW caps: Func.VSI cnt = %d\n",
- number);
+ "%s: num guaranteed VSI (fw) = %d\n",
+ prefix, number);
+ ice_debug(hw, ICE_DBG_INIT,
+ "%s: num guaranteed VSI = %d\n",
+ prefix, func_p->guar_num_vsi);
}
break;
case ICE_AQC_CAPS_RSS:
caps->rss_table_size = number;
caps->rss_table_entry_width = logical_id;
ice_debug(hw, ICE_DBG_INIT,
- "HW caps: RSS table size = %d\n",
+ "%s: RSS table size = %d\n", prefix,
caps->rss_table_size);
ice_debug(hw, ICE_DBG_INIT,
- "HW caps: RSS table width = %d\n",
+ "%s: RSS table width = %d\n", prefix,
caps->rss_table_entry_width);
break;
case ICE_AQC_CAPS_RXQS:
caps->num_rxq = number;
caps->rxq_first_id = phys_id;
ice_debug(hw, ICE_DBG_INIT,
- "HW caps: Num Rx Qs = %d\n", caps->num_rxq);
+ "%s: num Rx queues = %d\n", prefix,
+ caps->num_rxq);
ice_debug(hw, ICE_DBG_INIT,
- "HW caps: Rx first queue ID = %d\n",
+ "%s: Rx first queue ID = %d\n", prefix,
caps->rxq_first_id);
break;
case ICE_AQC_CAPS_TXQS:
caps->num_txq = number;
caps->txq_first_id = phys_id;
ice_debug(hw, ICE_DBG_INIT,
- "HW caps: Num Tx Qs = %d\n", caps->num_txq);
+ "%s: num Tx queues = %d\n", prefix,
+ caps->num_txq);
ice_debug(hw, ICE_DBG_INIT,
- "HW caps: Tx first queue ID = %d\n",
+ "%s: Tx first queue ID = %d\n", prefix,
caps->txq_first_id);
break;
case ICE_AQC_CAPS_MSIX:
caps->num_msix_vectors = number;
caps->msix_vector_first_id = phys_id;
ice_debug(hw, ICE_DBG_INIT,
- "HW caps: MSIX vector count = %d\n",
+ "%s: MSIX vector count = %d\n", prefix,
caps->num_msix_vectors);
ice_debug(hw, ICE_DBG_INIT,
- "HW caps: MSIX first vector index = %d\n",
+ "%s: MSIX first vector index = %d\n", prefix,
caps->msix_vector_first_id);
break;
case ICE_AQC_CAPS_MAX_MTU:
caps->max_mtu = number;
- if (dev_p)
- ice_debug(hw, ICE_DBG_INIT,
- "HW caps: Dev.MaxMTU = %d\n",
- caps->max_mtu);
- else if (func_p)
- ice_debug(hw, ICE_DBG_INIT,
- "HW caps: func.MaxMTU = %d\n",
- caps->max_mtu);
+ ice_debug(hw, ICE_DBG_INIT, "%s: max MTU = %d\n",
+ prefix, caps->max_mtu);
break;
default:
ice_debug(hw, ICE_DBG_INIT,
- "HW caps: Unknown capability[%d]: 0x%x\n", i,
- cap);
+ "%s: unknown capability[%d]: 0x%x\n", prefix,
+ i, cap);
break;
}
}
@@ -1947,36 +2002,37 @@ ice_aq_set_phy_cfg(struct ice_hw *hw, u8 lport,
*/
enum ice_status ice_update_link_info(struct ice_port_info *pi)
{
- struct ice_aqc_get_phy_caps_data *pcaps;
- struct ice_phy_info *phy_info;
+ struct ice_link_status *li;
enum ice_status status;
- struct ice_hw *hw;
if (!pi)
return ICE_ERR_PARAM;
- hw = pi->hw;
-
- pcaps = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*pcaps), GFP_KERNEL);
- if (!pcaps)
- return ICE_ERR_NO_MEMORY;
+ li = &pi->phy.link_info;
- phy_info = &pi->phy;
status = ice_aq_get_link_info(pi, true, NULL, NULL);
if (status)
- goto out;
+ return status;
+
+ if (li->link_info & ICE_AQ_MEDIA_AVAILABLE) {
+ struct ice_aqc_get_phy_caps_data *pcaps;
+ struct ice_hw *hw;
+
+ hw = pi->hw;
+ pcaps = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*pcaps),
+ GFP_KERNEL);
+ if (!pcaps)
+ return ICE_ERR_NO_MEMORY;
- if (phy_info->link_info.link_info & ICE_AQ_MEDIA_AVAILABLE) {
status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_SW_CFG,
pcaps, NULL);
- if (status)
- goto out;
+ if (!status)
+ memcpy(li->module_type, &pcaps->module_type,
+ sizeof(li->module_type));
- memcpy(phy_info->link_info.module_type, &pcaps->module_type,
- sizeof(phy_info->link_info.module_type));
+ devm_kfree(ice_hw_to_dev(hw), pcaps);
}
-out:
- devm_kfree(ice_hw_to_dev(hw), pcaps);
+
return status;
}
@@ -2081,6 +2137,74 @@ out:
}
/**
+ * ice_copy_phy_caps_to_cfg - Copy PHY ability data to configuration data
+ * @caps: PHY ability structure to copy date from
+ * @cfg: PHY configuration structure to copy data to
+ *
+ * Helper function to copy AQC PHY get ability data to PHY set configuration
+ * data structure
+ */
+void
+ice_copy_phy_caps_to_cfg(struct ice_aqc_get_phy_caps_data *caps,
+ struct ice_aqc_set_phy_cfg_data *cfg)
+{
+ if (!caps || !cfg)
+ return;
+
+ cfg->phy_type_low = caps->phy_type_low;
+ cfg->phy_type_high = caps->phy_type_high;
+ cfg->caps = caps->caps;
+ cfg->low_power_ctrl = caps->low_power_ctrl;
+ cfg->eee_cap = caps->eee_cap;
+ cfg->eeer_value = caps->eeer_value;
+ cfg->link_fec_opt = caps->link_fec_options;
+}
+
+/**
+ * ice_cfg_phy_fec - Configure PHY FEC data based on FEC mode
+ * @cfg: PHY configuration data to set FEC mode
+ * @fec: FEC mode to configure
+ *
+ * Caller should copy ice_aqc_get_phy_caps_data.caps ICE_AQC_PHY_EN_AUTO_FEC
+ * (bit 7) and ice_aqc_get_phy_caps_data.link_fec_options to cfg.caps
+ * ICE_AQ_PHY_ENA_AUTO_FEC (bit 7) and cfg.link_fec_options before calling.
+ */
+void
+ice_cfg_phy_fec(struct ice_aqc_set_phy_cfg_data *cfg, enum ice_fec_mode fec)
+{
+ switch (fec) {
+ case ICE_FEC_BASER:
+ /* Clear auto FEC and RS bits, and AND BASE-R ability
+ * bits and OR request bits.
+ */
+ cfg->caps &= ~ICE_AQC_PHY_EN_AUTO_FEC;
+ cfg->link_fec_opt &= ICE_AQC_PHY_FEC_10G_KR_40G_KR4_EN |
+ ICE_AQC_PHY_FEC_25G_KR_CLAUSE74_EN;
+ cfg->link_fec_opt |= ICE_AQC_PHY_FEC_10G_KR_40G_KR4_REQ |
+ ICE_AQC_PHY_FEC_25G_KR_REQ;
+ break;
+ case ICE_FEC_RS:
+ /* Clear auto FEC and BASE-R bits, and AND RS ability
+ * bits and OR request bits.
+ */
+ cfg->caps &= ~ICE_AQC_PHY_EN_AUTO_FEC;
+ cfg->link_fec_opt &= ICE_AQC_PHY_FEC_25G_RS_CLAUSE91_EN;
+ cfg->link_fec_opt |= ICE_AQC_PHY_FEC_25G_RS_528_REQ |
+ ICE_AQC_PHY_FEC_25G_RS_544_REQ;
+ break;
+ case ICE_FEC_NONE:
+ /* Clear auto FEC and all FEC option bits. */
+ cfg->caps &= ~ICE_AQC_PHY_EN_AUTO_FEC;
+ cfg->link_fec_opt &= ~ICE_AQC_PHY_FEC_MASK;
+ break;
+ case ICE_FEC_AUTO:
+ /* AND auto FEC bit, and all caps bits. */
+ cfg->caps &= ICE_AQC_PHY_CAPS_MASK;
+ break;
+ }
+}
+
+/**
* ice_get_link_status - get status of the HW network link
* @pi: port information structure
* @link_up: pointer to bool (true/false = linkup/linkdown)
@@ -2169,6 +2293,29 @@ ice_aq_set_event_mask(struct ice_hw *hw, u8 port_num, u16 mask,
}
/**
+ * ice_aq_set_mac_loopback
+ * @hw: pointer to the HW struct
+ * @ena_lpbk: Enable or Disable loopback
+ * @cd: pointer to command details structure or NULL
+ *
+ * Enable/disable loopback on a given port
+ */
+enum ice_status
+ice_aq_set_mac_loopback(struct ice_hw *hw, bool ena_lpbk, struct ice_sq_cd *cd)
+{
+ struct ice_aqc_set_mac_lb *cmd;
+ struct ice_aq_desc desc;
+
+ cmd = &desc.params.set_mac_lb;
+
+ ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_mac_lb);
+ if (ena_lpbk)
+ cmd->lb_mode = ICE_AQ_MAC_LB_EN;
+
+ return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
+}
+
+/**
* ice_aq_set_port_id_led
* @pi: pointer to the port information
* @is_orig_mode: is this LED set to original mode (by the net-list)
@@ -2552,7 +2699,7 @@ do_aq:
ice_debug(hw, ICE_DBG_SCHED, "VM%d disable failed %d\n",
vmvf_num, hw->adminq.sq_last_status);
else
- ice_debug(hw, ICE_DBG_SCHED, "disable Q %d failed %d\n",
+ ice_debug(hw, ICE_DBG_SCHED, "disable queue %d failed %d\n",
le16_to_cpu(qg_list[0].q_id[0]),
hw->adminq.sq_last_status);
}
@@ -2924,7 +3071,6 @@ ice_dis_vsi_txq(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u8 num_queues,
if (!pi || pi->port_state != ICE_SCHED_PORT_STATE_READY)
return ICE_ERR_CFG;
-
if (!num_queues) {
/* if queue is disabled already yet the disable queue command
* has to be sent to complete the VF reset, then call
diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h
index f1ddebf45231..d1f8353fe6bb 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.h
+++ b/drivers/net/ethernet/intel/ice/ice_common.h
@@ -9,6 +9,8 @@
#include "ice_switch.h"
#include <linux/avf/virtchnl.h>
+enum ice_status ice_nvm_validate_checksum(struct ice_hw *hw);
+
void
ice_debug_cq(struct ice_hw *hw, u32 mask, void *desc, void *buf, u16 buf_len);
enum ice_status ice_init_hw(struct ice_hw *hw);
@@ -84,7 +86,11 @@ ice_aq_set_phy_cfg(struct ice_hw *hw, u8 lport,
enum ice_status
ice_set_fc(struct ice_port_info *pi, u8 *aq_failures,
bool ena_auto_link_update);
-
+void
+ice_cfg_phy_fec(struct ice_aqc_set_phy_cfg_data *cfg, enum ice_fec_mode fec);
+void
+ice_copy_phy_caps_to_cfg(struct ice_aqc_get_phy_caps_data *caps,
+ struct ice_aqc_set_phy_cfg_data *cfg);
enum ice_status
ice_aq_set_link_restart_an(struct ice_port_info *pi, bool ena_link,
struct ice_sq_cd *cd);
@@ -95,6 +101,9 @@ enum ice_status
ice_aq_set_event_mask(struct ice_hw *hw, u8 port_num, u16 mask,
struct ice_sq_cd *cd);
enum ice_status
+ice_aq_set_mac_loopback(struct ice_hw *hw, bool ena_lpbk, struct ice_sq_cd *cd);
+
+enum ice_status
ice_aq_set_port_id_led(struct ice_port_info *pi, bool is_orig_mode,
struct ice_sq_cd *cd);
diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.c b/drivers/net/ethernet/intel/ice/ice_controlq.c
index cc8cb5fdcdc1..e91ac4df0242 100644
--- a/drivers/net/ethernet/intel/ice/ice_controlq.c
+++ b/drivers/net/ethernet/intel/ice/ice_controlq.c
@@ -439,7 +439,7 @@ do { \
/* free the buffer info list */ \
if ((qi)->ring.cmd_buf) \
devm_kfree(ice_hw_to_dev(hw), (qi)->ring.cmd_buf); \
- /* free dma head */ \
+ /* free DMA head */ \
devm_kfree(ice_hw_to_dev(hw), (qi)->ring.dma_head); \
} while (0)
diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.h b/drivers/net/ethernet/intel/ice/ice_controlq.h
index e0585394d984..44945c2165d8 100644
--- a/drivers/net/ethernet/intel/ice/ice_controlq.h
+++ b/drivers/net/ethernet/intel/ice/ice_controlq.h
@@ -35,7 +35,7 @@ enum ice_ctl_q {
#define ICE_CTL_Q_SQ_CMD_TIMEOUT 250 /* msecs */
struct ice_ctl_q_ring {
- void *dma_head; /* Virtual address to dma head */
+ void *dma_head; /* Virtual address to DMA head */
struct ice_dma_mem desc_buf; /* descriptor ring memory */
void *cmd_buf; /* command buffer memory */
diff --git a/drivers/net/ethernet/intel/ice/ice_dcb.c b/drivers/net/ethernet/intel/ice/ice_dcb.c
index 8bbf48e04a1c..c2002ded65f6 100644
--- a/drivers/net/ethernet/intel/ice/ice_dcb.c
+++ b/drivers/net/ethernet/intel/ice/ice_dcb.c
@@ -82,12 +82,14 @@ ice_aq_cfg_lldp_mib_change(struct ice_hw *hw, bool ena_update,
* @hw: pointer to the HW struct
* @shutdown_lldp_agent: True if LLDP Agent needs to be Shutdown
* False if LLDP Agent needs to be Stopped
+ * @persist: True if Stop/Shutdown of LLDP Agent needs to be persistent across
+ * reboots
* @cd: pointer to command details structure or NULL
*
* Stop or Shutdown the embedded LLDP Agent (0x0A05)
*/
enum ice_status
-ice_aq_stop_lldp(struct ice_hw *hw, bool shutdown_lldp_agent,
+ice_aq_stop_lldp(struct ice_hw *hw, bool shutdown_lldp_agent, bool persist,
struct ice_sq_cd *cd)
{
struct ice_aqc_lldp_stop *cmd;
@@ -100,17 +102,22 @@ ice_aq_stop_lldp(struct ice_hw *hw, bool shutdown_lldp_agent,
if (shutdown_lldp_agent)
cmd->command |= ICE_AQ_LLDP_AGENT_SHUTDOWN;
+ if (persist)
+ cmd->command |= ICE_AQ_LLDP_AGENT_PERSIST_DIS;
+
return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
}
/**
* ice_aq_start_lldp
* @hw: pointer to the HW struct
+ * @persist: True if Start of LLDP Agent needs to be persistent across reboots
* @cd: pointer to command details structure or NULL
*
* Start the embedded LLDP Agent on all ports. (0x0A06)
*/
-enum ice_status ice_aq_start_lldp(struct ice_hw *hw, struct ice_sq_cd *cd)
+enum ice_status
+ice_aq_start_lldp(struct ice_hw *hw, bool persist, struct ice_sq_cd *cd)
{
struct ice_aqc_lldp_start *cmd;
struct ice_aq_desc desc;
@@ -121,6 +128,9 @@ enum ice_status ice_aq_start_lldp(struct ice_hw *hw, struct ice_sq_cd *cd)
cmd->command = ICE_AQ_LLDP_AGENT_START;
+ if (persist)
+ cmd->command |= ICE_AQ_LLDP_AGENT_PERSIST_ENA;
+
return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
}
@@ -163,7 +173,7 @@ ice_aq_set_lldp_mib(struct ice_hw *hw, u8 mib_type, void *buf, u16 buf_size,
*
* Get the DCBX status from the Firmware
*/
-u8 ice_get_dcbx_status(struct ice_hw *hw)
+static u8 ice_get_dcbx_status(struct ice_hw *hw)
{
u32 reg;
@@ -614,7 +624,8 @@ ice_parse_org_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
*
* Parse DCB configuration from the LLDPDU
*/
-enum ice_status ice_lldp_to_dcb_cfg(u8 *lldpmib, struct ice_dcbx_cfg *dcbcfg)
+static enum ice_status
+ice_lldp_to_dcb_cfg(u8 *lldpmib, struct ice_dcbx_cfg *dcbcfg)
{
struct ice_lldp_org_tlv *tlv;
enum ice_status ret = 0;
@@ -658,13 +669,13 @@ enum ice_status ice_lldp_to_dcb_cfg(u8 *lldpmib, struct ice_dcbx_cfg *dcbcfg)
/**
* ice_aq_get_dcb_cfg
* @hw: pointer to the HW struct
- * @mib_type: mib type for the query
+ * @mib_type: MIB type for the query
* @bridgetype: bridge type for the query (remote)
* @dcbcfg: store for LLDPDU data
*
* Query DCB configuration from the firmware
*/
-static enum ice_status
+enum ice_status
ice_aq_get_dcb_cfg(struct ice_hw *hw, u8 mib_type, u8 bridgetype,
struct ice_dcbx_cfg *dcbcfg)
{
@@ -689,13 +700,13 @@ ice_aq_get_dcb_cfg(struct ice_hw *hw, u8 mib_type, u8 bridgetype,
}
/**
- * ice_aq_start_stop_dcbx - Start/Stop DCBx service in FW
+ * ice_aq_start_stop_dcbx - Start/Stop DCBX service in FW
* @hw: pointer to the HW struct
- * @start_dcbx_agent: True if DCBx Agent needs to be started
- * False if DCBx Agent needs to be stopped
- * @dcbx_agent_status: FW indicates back the DCBx agent status
- * True if DCBx Agent is active
- * False if DCBx Agent is stopped
+ * @start_dcbx_agent: True if DCBX Agent needs to be started
+ * False if DCBX Agent needs to be stopped
+ * @dcbx_agent_status: FW indicates back the DCBX agent status
+ * True if DCBX Agent is active
+ * False if DCBX Agent is stopped
* @cd: pointer to command details structure or NULL
*
* Start/Stop the embedded dcbx Agent. In case that this wrapper function
diff --git a/drivers/net/ethernet/intel/ice/ice_dcb.h b/drivers/net/ethernet/intel/ice/ice_dcb.h
index e7d4416e3a66..522e1452abe2 100644
--- a/drivers/net/ethernet/intel/ice/ice_dcb.h
+++ b/drivers/net/ethernet/intel/ice/ice_dcb.h
@@ -120,8 +120,9 @@ struct ice_cee_app_prio {
u8 prio_map;
} __packed;
-u8 ice_get_dcbx_status(struct ice_hw *hw);
-enum ice_status ice_lldp_to_dcb_cfg(u8 *lldpmib, struct ice_dcbx_cfg *dcbcfg);
+enum ice_status
+ice_aq_get_dcb_cfg(struct ice_hw *hw, u8 mib_type, u8 bridgetype,
+ struct ice_dcbx_cfg *dcbcfg);
enum ice_status ice_get_dcb_cfg(struct ice_port_info *pi);
enum ice_status ice_set_dcb_cfg(struct ice_port_info *pi);
enum ice_status ice_init_dcb(struct ice_hw *hw);
@@ -131,9 +132,10 @@ ice_query_port_ets(struct ice_port_info *pi,
struct ice_sq_cd *cmd_details);
#ifdef CONFIG_DCB
enum ice_status
-ice_aq_stop_lldp(struct ice_hw *hw, bool shutdown_lldp_agent,
+ice_aq_stop_lldp(struct ice_hw *hw, bool shutdown_lldp_agent, bool persist,
struct ice_sq_cd *cd);
-enum ice_status ice_aq_start_lldp(struct ice_hw *hw, struct ice_sq_cd *cd);
+enum ice_status
+ice_aq_start_lldp(struct ice_hw *hw, bool persist, struct ice_sq_cd *cd);
enum ice_status
ice_aq_start_stop_dcbx(struct ice_hw *hw, bool start_dcbx_agent,
bool *dcbx_agent_status, struct ice_sq_cd *cd);
@@ -144,6 +146,7 @@ ice_aq_cfg_lldp_mib_change(struct ice_hw *hw, bool ena_update,
static inline enum ice_status
ice_aq_stop_lldp(struct ice_hw __always_unused *hw,
bool __always_unused shutdown_lldp_agent,
+ bool __always_unused persist,
struct ice_sq_cd __always_unused *cd)
{
return 0;
@@ -151,6 +154,7 @@ ice_aq_stop_lldp(struct ice_hw __always_unused *hw,
static inline enum ice_status
ice_aq_start_lldp(struct ice_hw __always_unused *hw,
+ bool __always_unused persist,
struct ice_sq_cd __always_unused *cd)
{
return 0;
diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c
index 3e81af1884fc..fe88b127ca42 100644
--- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c
@@ -120,12 +120,14 @@ static void ice_pf_dcb_recfg(struct ice_pf *pf)
tc_map = ICE_DFLT_TRAFFIC_CLASS;
ret = ice_vsi_cfg_tc(pf->vsi[v], tc_map);
- if (ret)
+ if (ret) {
dev_err(&pf->pdev->dev,
"Failed to config TC for VSI index: %d\n",
pf->vsi[v]->idx);
- else
- ice_vsi_map_rings_to_vectors(pf->vsi[v]);
+ continue;
+ }
+
+ ice_vsi_map_rings_to_vectors(pf->vsi[v]);
}
}
@@ -133,8 +135,10 @@ static void ice_pf_dcb_recfg(struct ice_pf *pf)
* ice_pf_dcb_cfg - Apply new DCB configuration
* @pf: pointer to the PF struct
* @new_cfg: DCBX config to apply
+ * @locked: is the RTNL held
*/
-static int ice_pf_dcb_cfg(struct ice_pf *pf, struct ice_dcbx_cfg *new_cfg)
+static
+int ice_pf_dcb_cfg(struct ice_pf *pf, struct ice_dcbx_cfg *new_cfg, bool locked)
{
struct ice_dcbx_cfg *old_cfg, *curr_cfg;
struct ice_aqc_port_ets_elem buf = { 0 };
@@ -163,7 +167,8 @@ static int ice_pf_dcb_cfg(struct ice_pf *pf, struct ice_dcbx_cfg *new_cfg)
/* avoid race conditions by holding the lock while disabling and
* re-enabling the VSI
*/
- rtnl_lock();
+ if (!locked)
+ rtnl_lock();
ice_pf_dis_all_vsi(pf, true);
memcpy(curr_cfg, new_cfg, sizeof(*curr_cfg));
@@ -192,7 +197,8 @@ static int ice_pf_dcb_cfg(struct ice_pf *pf, struct ice_dcbx_cfg *new_cfg)
out:
ice_pf_ena_all_vsi(pf, true);
- rtnl_unlock();
+ if (!locked)
+ rtnl_unlock();
devm_kfree(&pf->pdev->dev, old_cfg);
return ret;
}
@@ -271,15 +277,16 @@ dcb_error:
prev_cfg->etscfg.tcbwtable[0] = ICE_TC_MAX_BW;
prev_cfg->etscfg.tsatable[0] = ICE_IEEE_TSA_ETS;
memcpy(&prev_cfg->etsrec, &prev_cfg->etscfg, sizeof(prev_cfg->etsrec));
- ice_pf_dcb_cfg(pf, prev_cfg);
+ ice_pf_dcb_cfg(pf, prev_cfg, false);
devm_kfree(&pf->pdev->dev, prev_cfg);
}
/**
* ice_dcb_init_cfg - set the initial DCB config in SW
- * @pf: pf to apply config to
+ * @pf: PF to apply config to
+ * @locked: Is the RTNL held
*/
-static int ice_dcb_init_cfg(struct ice_pf *pf)
+static int ice_dcb_init_cfg(struct ice_pf *pf, bool locked)
{
struct ice_dcbx_cfg *newcfg;
struct ice_port_info *pi;
@@ -294,7 +301,7 @@ static int ice_dcb_init_cfg(struct ice_pf *pf)
memset(&pi->local_dcbx_cfg, 0, sizeof(*newcfg));
dev_info(&pf->pdev->dev, "Configuring initial DCB values\n");
- if (ice_pf_dcb_cfg(pf, newcfg))
+ if (ice_pf_dcb_cfg(pf, newcfg, locked))
ret = -EINVAL;
devm_kfree(&pf->pdev->dev, newcfg);
@@ -304,9 +311,10 @@ static int ice_dcb_init_cfg(struct ice_pf *pf)
/**
* ice_dcb_sw_default_config - Apply a default DCB config
- * @pf: pf to apply config to
+ * @pf: PF to apply config to
+ * @locked: was this function called with RTNL held
*/
-static int ice_dcb_sw_dflt_cfg(struct ice_pf *pf)
+static int ice_dcb_sw_dflt_cfg(struct ice_pf *pf, bool locked)
{
struct ice_aqc_port_ets_elem buf = { 0 };
struct ice_dcbx_cfg *dcbcfg;
@@ -338,7 +346,7 @@ static int ice_dcb_sw_dflt_cfg(struct ice_pf *pf)
dcbcfg->app[0].priority = 3;
dcbcfg->app[0].prot_id = ICE_APP_PROT_ID_FCOE;
- ret = ice_pf_dcb_cfg(pf, dcbcfg);
+ ret = ice_pf_dcb_cfg(pf, dcbcfg, locked);
devm_kfree(&pf->pdev->dev, dcbcfg);
if (ret)
return ret;
@@ -348,9 +356,10 @@ static int ice_dcb_sw_dflt_cfg(struct ice_pf *pf)
/**
* ice_init_pf_dcb - initialize DCB for a PF
- * @pf: pf to initiialize DCB for
+ * @pf: PF to initialize DCB for
+ * @locked: Was function called with RTNL held
*/
-int ice_init_pf_dcb(struct ice_pf *pf)
+int ice_init_pf_dcb(struct ice_pf *pf, bool locked)
{
struct device *dev = &pf->pdev->dev;
struct ice_port_info *port_info;
@@ -360,33 +369,10 @@ int ice_init_pf_dcb(struct ice_pf *pf)
port_info = hw->port_info;
- /* check if device is DCB capable */
- if (!hw->func_caps.common_cap.dcb) {
- dev_dbg(dev, "DCB not supported\n");
- return -EOPNOTSUPP;
- }
-
- /* Best effort to put DCBx and LLDP into a good state */
- port_info->dcbx_status = ice_get_dcbx_status(hw);
- if (port_info->dcbx_status != ICE_DCBX_STATUS_DONE &&
- port_info->dcbx_status != ICE_DCBX_STATUS_IN_PROGRESS) {
- bool dcbx_status;
-
- /* Attempt to start LLDP engine. Ignore errors
- * as this will error if it is already started
- */
- ice_aq_start_lldp(hw, NULL);
-
- /* Attempt to start DCBX. Ignore errors as this
- * will error if it is already started
- */
- ice_aq_start_stop_dcbx(hw, true, &dcbx_status, NULL);
- }
-
err = ice_init_dcb(hw);
if (err) {
- /* FW LLDP not in usable state, default to SW DCBx/LLDP */
- dev_info(&pf->pdev->dev, "FW LLDP not in usable state\n");
+ /* FW LLDP is not active, default to SW DCBX/LLDP */
+ dev_info(&pf->pdev->dev, "FW LLDP is not active\n");
hw->port_info->dcbx_status = ICE_DCBX_STATUS_NOT_STARTED;
hw->port_info->is_sw_lldp = true;
}
@@ -398,15 +384,16 @@ int ice_init_pf_dcb(struct ice_pf *pf)
if (port_info->is_sw_lldp) {
sw_default = 1;
dev_info(&pf->pdev->dev, "DCBx/LLDP in SW mode.\n");
+ clear_bit(ICE_FLAG_ENABLE_FW_LLDP, pf->flags);
+ } else {
+ set_bit(ICE_FLAG_ENABLE_FW_LLDP, pf->flags);
}
- if (port_info->dcbx_status == ICE_DCBX_STATUS_NOT_STARTED) {
- sw_default = 1;
+ if (port_info->dcbx_status == ICE_DCBX_STATUS_NOT_STARTED)
dev_info(&pf->pdev->dev, "DCBX not started\n");
- }
if (sw_default) {
- err = ice_dcb_sw_dflt_cfg(pf);
+ err = ice_dcb_sw_dflt_cfg(pf, locked);
if (err) {
dev_err(&pf->pdev->dev,
"Failed to set local DCB config %d\n", err);
@@ -425,7 +412,7 @@ int ice_init_pf_dcb(struct ice_pf *pf)
set_bit(ICE_FLAG_DCB_CAPABLE, pf->flags);
- err = ice_dcb_init_cfg(pf);
+ err = ice_dcb_init_cfg(pf, locked);
if (err)
goto dcb_init_err;
@@ -515,6 +502,55 @@ ice_tx_prepare_vlan_flags_dcb(struct ice_ring *tx_ring,
}
/**
+ * ice_dcb_need_recfg - Check if DCB needs reconfig
+ * @pf: board private structure
+ * @old_cfg: current DCB config
+ * @new_cfg: new DCB config
+ */
+static bool ice_dcb_need_recfg(struct ice_pf *pf, struct ice_dcbx_cfg *old_cfg,
+ struct ice_dcbx_cfg *new_cfg)
+{
+ bool need_reconfig = false;
+
+ /* Check if ETS configuration has changed */
+ if (memcmp(&new_cfg->etscfg, &old_cfg->etscfg,
+ sizeof(new_cfg->etscfg))) {
+ /* If Priority Table has changed reconfig is needed */
+ if (memcmp(&new_cfg->etscfg.prio_table,
+ &old_cfg->etscfg.prio_table,
+ sizeof(new_cfg->etscfg.prio_table))) {
+ need_reconfig = true;
+ dev_dbg(&pf->pdev->dev, "ETS UP2TC changed.\n");
+ }
+
+ if (memcmp(&new_cfg->etscfg.tcbwtable,
+ &old_cfg->etscfg.tcbwtable,
+ sizeof(new_cfg->etscfg.tcbwtable)))
+ dev_dbg(&pf->pdev->dev, "ETS TC BW Table changed.\n");
+
+ if (memcmp(&new_cfg->etscfg.tsatable,
+ &old_cfg->etscfg.tsatable,
+ sizeof(new_cfg->etscfg.tsatable)))
+ dev_dbg(&pf->pdev->dev, "ETS TSA Table changed.\n");
+ }
+
+ /* Check if PFC configuration has changed */
+ if (memcmp(&new_cfg->pfc, &old_cfg->pfc, sizeof(new_cfg->pfc))) {
+ need_reconfig = true;
+ dev_dbg(&pf->pdev->dev, "PFC config change detected.\n");
+ }
+
+ /* Check if APP Table has changed */
+ if (memcmp(&new_cfg->app, &old_cfg->app, sizeof(new_cfg->app))) {
+ need_reconfig = true;
+ dev_dbg(&pf->pdev->dev, "APP Table change detected.\n");
+ }
+
+ dev_dbg(&pf->pdev->dev, "dcb need_reconfig=%d\n", need_reconfig);
+ return need_reconfig;
+}
+
+/**
* ice_dcb_process_lldp_set_mib_change - Process MIB change
* @pf: ptr to ice_pf
* @event: pointer to the admin queue receive event
@@ -523,29 +559,95 @@ void
ice_dcb_process_lldp_set_mib_change(struct ice_pf *pf,
struct ice_rq_event_info *event)
{
- if (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) {
- struct ice_dcbx_cfg *dcbcfg, *prev_cfg;
- int err;
-
- prev_cfg = &pf->hw.port_info->local_dcbx_cfg;
- dcbcfg = devm_kmemdup(&pf->pdev->dev, prev_cfg,
- sizeof(*dcbcfg), GFP_KERNEL);
- if (!dcbcfg)
+ struct ice_aqc_port_ets_elem buf = { 0 };
+ struct ice_aqc_lldp_get_mib *mib;
+ struct ice_dcbx_cfg tmp_dcbx_cfg;
+ bool need_reconfig = false;
+ struct ice_port_info *pi;
+ u8 type;
+ int ret;
+
+ /* Not DCB capable or capability disabled */
+ if (!(test_bit(ICE_FLAG_DCB_CAPABLE, pf->flags)))
+ return;
+
+ if (pf->dcbx_cap & DCB_CAP_DCBX_HOST) {
+ dev_dbg(&pf->pdev->dev,
+ "MIB Change Event in HOST mode\n");
+ return;
+ }
+
+ pi = pf->hw.port_info;
+ mib = (struct ice_aqc_lldp_get_mib *)&event->desc.params.raw;
+ /* Ignore if event is not for Nearest Bridge */
+ type = ((mib->type >> ICE_AQ_LLDP_BRID_TYPE_S) &
+ ICE_AQ_LLDP_BRID_TYPE_M);
+ dev_dbg(&pf->pdev->dev, "LLDP event MIB bridge type 0x%x\n", type);
+ if (type != ICE_AQ_LLDP_BRID_TYPE_NEAREST_BRID)
+ return;
+
+ /* Check MIB Type and return if event for Remote MIB update */
+ type = mib->type & ICE_AQ_LLDP_MIB_TYPE_M;
+ dev_dbg(&pf->pdev->dev,
+ "LLDP event mib type %s\n", type ? "remote" : "local");
+ if (type == ICE_AQ_LLDP_MIB_REMOTE) {
+ /* Update the remote cached instance and return */
+ ret = ice_aq_get_dcb_cfg(pi->hw, ICE_AQ_LLDP_MIB_REMOTE,
+ ICE_AQ_LLDP_BRID_TYPE_NEAREST_BRID,
+ &pi->remote_dcbx_cfg);
+ if (ret) {
+ dev_err(&pf->pdev->dev, "Failed to get remote DCB config\n");
return;
+ }
+ }
- err = ice_lldp_to_dcb_cfg(event->msg_buf, dcbcfg);
- if (!err)
- ice_pf_dcb_cfg(pf, dcbcfg);
+ /* store the old configuration */
+ tmp_dcbx_cfg = pf->hw.port_info->local_dcbx_cfg;
- devm_kfree(&pf->pdev->dev, dcbcfg);
+ /* Reset the old DCBX configuration data */
+ memset(&pi->local_dcbx_cfg, 0, sizeof(pi->local_dcbx_cfg));
- /* Get updated DCBx data from firmware */
- err = ice_get_dcb_cfg(pf->hw.port_info);
- if (err)
- dev_err(&pf->pdev->dev,
- "Failed to get DCB config\n");
- } else {
+ /* Get updated DCBX data from firmware */
+ ret = ice_get_dcb_cfg(pf->hw.port_info);
+ if (ret) {
+ dev_err(&pf->pdev->dev, "Failed to get DCB config\n");
+ return;
+ }
+
+ /* No change detected in DCBX configs */
+ if (!memcmp(&tmp_dcbx_cfg, &pi->local_dcbx_cfg, sizeof(tmp_dcbx_cfg))) {
dev_dbg(&pf->pdev->dev,
- "MIB Change Event in HOST mode\n");
+ "No change detected in DCBX configuration.\n");
+ return;
+ }
+
+ need_reconfig = ice_dcb_need_recfg(pf, &tmp_dcbx_cfg,
+ &pi->local_dcbx_cfg);
+ if (!need_reconfig)
+ return;
+
+ /* Enable DCB tagging only when more than one TC */
+ if (ice_dcb_get_num_tc(&pi->local_dcbx_cfg) > 1) {
+ dev_dbg(&pf->pdev->dev, "DCB tagging enabled (num TC > 1)\n");
+ set_bit(ICE_FLAG_DCB_ENA, pf->flags);
+ } else {
+ dev_dbg(&pf->pdev->dev, "DCB tagging disabled (num TC = 1)\n");
+ clear_bit(ICE_FLAG_DCB_ENA, pf->flags);
}
+
+ rtnl_lock();
+ ice_pf_dis_all_vsi(pf, true);
+
+ ret = ice_query_port_ets(pf->hw.port_info, &buf, sizeof(buf), NULL);
+ if (ret) {
+ dev_err(&pf->pdev->dev, "Query Port ETS failed\n");
+ rtnl_unlock();
+ return;
+ }
+
+ /* changes in configuration update VSI */
+ ice_pf_dcb_recfg(pf);
+
+ ice_pf_ena_all_vsi(pf, true);
+ rtnl_unlock();
}
diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.h b/drivers/net/ethernet/intel/ice/ice_dcb_lib.h
index ca7b76faa03c..819081053ff5 100644
--- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.h
+++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.h
@@ -14,7 +14,7 @@ void ice_dcb_rebuild(struct ice_pf *pf);
u8 ice_dcb_get_ena_tc(struct ice_dcbx_cfg *dcbcfg);
u8 ice_dcb_get_num_tc(struct ice_dcbx_cfg *dcbcfg);
void ice_vsi_cfg_dcb_rings(struct ice_vsi *vsi);
-int ice_init_pf_dcb(struct ice_pf *pf);
+int ice_init_pf_dcb(struct ice_pf *pf, bool locked);
void ice_update_dcb_stats(struct ice_pf *pf);
int
ice_tx_prepare_vlan_flags_dcb(struct ice_ring *tx_ring,
@@ -40,7 +40,8 @@ static inline u8 ice_dcb_get_num_tc(struct ice_dcbx_cfg __always_unused *dcbcfg)
return 1;
}
-static inline int ice_init_pf_dcb(struct ice_pf *pf)
+static inline int
+ice_init_pf_dcb(struct ice_pf *pf, bool __always_unused locked)
{
dev_dbg(&pf->pdev->dev, "DCB not supported\n");
return -EOPNOTSUPP;
diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c
index 1341fde8d53f..52083a63dee6 100644
--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c
+++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c
@@ -45,22 +45,40 @@ static int ice_q_stats_len(struct net_device *netdev)
ICE_VSI_STATS_LEN + ice_q_stats_len(n))
static const struct ice_stats ice_gstrings_vsi_stats[] = {
- ICE_VSI_STAT("tx_unicast", eth_stats.tx_unicast),
ICE_VSI_STAT("rx_unicast", eth_stats.rx_unicast),
- ICE_VSI_STAT("tx_multicast", eth_stats.tx_multicast),
+ ICE_VSI_STAT("tx_unicast", eth_stats.tx_unicast),
ICE_VSI_STAT("rx_multicast", eth_stats.rx_multicast),
- ICE_VSI_STAT("tx_broadcast", eth_stats.tx_broadcast),
+ ICE_VSI_STAT("tx_multicast", eth_stats.tx_multicast),
ICE_VSI_STAT("rx_broadcast", eth_stats.rx_broadcast),
- ICE_VSI_STAT("tx_bytes", eth_stats.tx_bytes),
+ ICE_VSI_STAT("tx_broadcast", eth_stats.tx_broadcast),
ICE_VSI_STAT("rx_bytes", eth_stats.rx_bytes),
- ICE_VSI_STAT("rx_discards", eth_stats.rx_discards),
- ICE_VSI_STAT("tx_errors", eth_stats.tx_errors),
- ICE_VSI_STAT("tx_linearize", tx_linearize),
+ ICE_VSI_STAT("tx_bytes", eth_stats.tx_bytes),
+ ICE_VSI_STAT("rx_dropped", eth_stats.rx_discards),
ICE_VSI_STAT("rx_unknown_protocol", eth_stats.rx_unknown_protocol),
ICE_VSI_STAT("rx_alloc_fail", rx_buf_failed),
ICE_VSI_STAT("rx_pg_alloc_fail", rx_page_failed),
+ ICE_VSI_STAT("tx_errors", eth_stats.tx_errors),
+ ICE_VSI_STAT("tx_linearize", tx_linearize),
+};
+
+enum ice_ethtool_test_id {
+ ICE_ETH_TEST_REG = 0,
+ ICE_ETH_TEST_EEPROM,
+ ICE_ETH_TEST_INTR,
+ ICE_ETH_TEST_LOOP,
+ ICE_ETH_TEST_LINK,
};
+static const char ice_gstrings_test[][ETH_GSTRING_LEN] = {
+ "Register test (offline)",
+ "EEPROM test (offline)",
+ "Interrupt test (offline)",
+ "Loopback test (offline)",
+ "Link test (on/offline)",
+};
+
+#define ICE_TEST_LEN (sizeof(ice_gstrings_test) / ETH_GSTRING_LEN)
+
/* These PF_STATs might look like duplicates of some NETDEV_STATs,
* but they aren't. This device is capable of supporting multiple
* VSIs/netdevs on a single PF. The NETDEV_STATs are for individual
@@ -71,45 +89,45 @@ static const struct ice_stats ice_gstrings_vsi_stats[] = {
* is queried on the base PF netdev.
*/
static const struct ice_stats ice_gstrings_pf_stats[] = {
- ICE_PF_STAT("port.tx_bytes", stats.eth.tx_bytes),
- ICE_PF_STAT("port.rx_bytes", stats.eth.rx_bytes),
- ICE_PF_STAT("port.tx_unicast", stats.eth.tx_unicast),
- ICE_PF_STAT("port.rx_unicast", stats.eth.rx_unicast),
- ICE_PF_STAT("port.tx_multicast", stats.eth.tx_multicast),
- ICE_PF_STAT("port.rx_multicast", stats.eth.rx_multicast),
- ICE_PF_STAT("port.tx_broadcast", stats.eth.tx_broadcast),
- ICE_PF_STAT("port.rx_broadcast", stats.eth.rx_broadcast),
- ICE_PF_STAT("port.tx_errors", stats.eth.tx_errors),
- ICE_PF_STAT("port.tx_size_64", stats.tx_size_64),
- ICE_PF_STAT("port.rx_size_64", stats.rx_size_64),
- ICE_PF_STAT("port.tx_size_127", stats.tx_size_127),
- ICE_PF_STAT("port.rx_size_127", stats.rx_size_127),
- ICE_PF_STAT("port.tx_size_255", stats.tx_size_255),
- ICE_PF_STAT("port.rx_size_255", stats.rx_size_255),
- ICE_PF_STAT("port.tx_size_511", stats.tx_size_511),
- ICE_PF_STAT("port.rx_size_511", stats.rx_size_511),
- ICE_PF_STAT("port.tx_size_1023", stats.tx_size_1023),
- ICE_PF_STAT("port.rx_size_1023", stats.rx_size_1023),
- ICE_PF_STAT("port.tx_size_1522", stats.tx_size_1522),
- ICE_PF_STAT("port.rx_size_1522", stats.rx_size_1522),
- ICE_PF_STAT("port.tx_size_big", stats.tx_size_big),
- ICE_PF_STAT("port.rx_size_big", stats.rx_size_big),
- ICE_PF_STAT("port.link_xon_tx", stats.link_xon_tx),
- ICE_PF_STAT("port.link_xon_rx", stats.link_xon_rx),
- ICE_PF_STAT("port.link_xoff_tx", stats.link_xoff_tx),
- ICE_PF_STAT("port.link_xoff_rx", stats.link_xoff_rx),
- ICE_PF_STAT("port.tx_dropped_link_down", stats.tx_dropped_link_down),
- ICE_PF_STAT("port.rx_undersize", stats.rx_undersize),
- ICE_PF_STAT("port.rx_fragments", stats.rx_fragments),
- ICE_PF_STAT("port.rx_oversize", stats.rx_oversize),
- ICE_PF_STAT("port.rx_jabber", stats.rx_jabber),
- ICE_PF_STAT("port.rx_csum_bad", hw_csum_rx_error),
- ICE_PF_STAT("port.rx_length_errors", stats.rx_len_errors),
- ICE_PF_STAT("port.rx_dropped", stats.eth.rx_discards),
- ICE_PF_STAT("port.rx_crc_errors", stats.crc_errors),
- ICE_PF_STAT("port.illegal_bytes", stats.illegal_bytes),
- ICE_PF_STAT("port.mac_local_faults", stats.mac_local_faults),
- ICE_PF_STAT("port.mac_remote_faults", stats.mac_remote_faults),
+ ICE_PF_STAT("rx_bytes.nic", stats.eth.rx_bytes),
+ ICE_PF_STAT("tx_bytes.nic", stats.eth.tx_bytes),
+ ICE_PF_STAT("rx_unicast.nic", stats.eth.rx_unicast),
+ ICE_PF_STAT("tx_unicast.nic", stats.eth.tx_unicast),
+ ICE_PF_STAT("rx_multicast.nic", stats.eth.rx_multicast),
+ ICE_PF_STAT("tx_multicast.nic", stats.eth.tx_multicast),
+ ICE_PF_STAT("rx_broadcast.nic", stats.eth.rx_broadcast),
+ ICE_PF_STAT("tx_broadcast.nic", stats.eth.tx_broadcast),
+ ICE_PF_STAT("tx_errors.nic", stats.eth.tx_errors),
+ ICE_PF_STAT("rx_size_64.nic", stats.rx_size_64),
+ ICE_PF_STAT("tx_size_64.nic", stats.tx_size_64),
+ ICE_PF_STAT("rx_size_127.nic", stats.rx_size_127),
+ ICE_PF_STAT("tx_size_127.nic", stats.tx_size_127),
+ ICE_PF_STAT("rx_size_255.nic", stats.rx_size_255),
+ ICE_PF_STAT("tx_size_255.nic", stats.tx_size_255),
+ ICE_PF_STAT("rx_size_511.nic", stats.rx_size_511),
+ ICE_PF_STAT("tx_size_511.nic", stats.tx_size_511),
+ ICE_PF_STAT("rx_size_1023.nic", stats.rx_size_1023),
+ ICE_PF_STAT("tx_size_1023.nic", stats.tx_size_1023),
+ ICE_PF_STAT("rx_size_1522.nic", stats.rx_size_1522),
+ ICE_PF_STAT("tx_size_1522.nic", stats.tx_size_1522),
+ ICE_PF_STAT("rx_size_big.nic", stats.rx_size_big),
+ ICE_PF_STAT("tx_size_big.nic", stats.tx_size_big),
+ ICE_PF_STAT("link_xon_rx.nic", stats.link_xon_rx),
+ ICE_PF_STAT("link_xon_tx.nic", stats.link_xon_tx),
+ ICE_PF_STAT("link_xoff_rx.nic", stats.link_xoff_rx),
+ ICE_PF_STAT("link_xoff_tx.nic", stats.link_xoff_tx),
+ ICE_PF_STAT("tx_dropped_link_down.nic", stats.tx_dropped_link_down),
+ ICE_PF_STAT("rx_undersize.nic", stats.rx_undersize),
+ ICE_PF_STAT("rx_fragments.nic", stats.rx_fragments),
+ ICE_PF_STAT("rx_oversize.nic", stats.rx_oversize),
+ ICE_PF_STAT("rx_jabber.nic", stats.rx_jabber),
+ ICE_PF_STAT("rx_csum_bad.nic", hw_csum_rx_error),
+ ICE_PF_STAT("rx_length_errors.nic", stats.rx_len_errors),
+ ICE_PF_STAT("rx_dropped.nic", stats.eth.rx_discards),
+ ICE_PF_STAT("rx_crc_errors.nic", stats.crc_errors),
+ ICE_PF_STAT("illegal_bytes.nic", stats.illegal_bytes),
+ ICE_PF_STAT("mac_local_faults.nic", stats.mac_local_faults),
+ ICE_PF_STAT("mac_remote_faults.nic", stats.mac_remote_faults),
};
static const u32 ice_regs_dump_list[] = {
@@ -120,6 +138,9 @@ static const u32 ice_regs_dump_list[] = {
QINT_RQCTL(0),
PFINT_OICR_ENA,
QRX_ITR(0),
+ PF0INT_ITR_0(0),
+ PF0INT_ITR_1(0),
+ PF0INT_ITR_2(0),
};
struct ice_priv_flag {
@@ -134,7 +155,7 @@ struct ice_priv_flag {
static const struct ice_priv_flag ice_gstrings_priv_flags[] = {
ICE_PRIV_FLAG("link-down-on-close", ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA),
- ICE_PRIV_FLAG("disable-fw-lldp", ICE_FLAG_DISABLE_FW_LLDP),
+ ICE_PRIV_FLAG("enable-fw-lldp", ICE_FLAG_ENABLE_FW_LLDP),
};
#define ICE_PRIV_FLAG_ARRAY_SIZE ARRAY_SIZE(ice_gstrings_priv_flags)
@@ -278,6 +299,571 @@ out:
return ret;
}
+/**
+ * ice_active_vfs - check if there are any active VFs
+ * @pf: board private structure
+ *
+ * Returns true if an active VF is found, otherwise returns false
+ */
+static bool ice_active_vfs(struct ice_pf *pf)
+{
+ struct ice_vf *vf = pf->vf;
+ int i;
+
+ for (i = 0; i < pf->num_alloc_vfs; i++, vf++)
+ if (test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states))
+ return true;
+ return false;
+}
+
+/**
+ * ice_link_test - perform a link test on a given net_device
+ * @netdev: network interface device structure
+ *
+ * This function performs one of the self-tests required by ethtool.
+ * Returns 0 on success, non-zero on failure.
+ */
+static u64 ice_link_test(struct net_device *netdev)
+{
+ struct ice_netdev_priv *np = netdev_priv(netdev);
+ enum ice_status status;
+ bool link_up = false;
+
+ netdev_info(netdev, "link test\n");
+ status = ice_get_link_status(np->vsi->port_info, &link_up);
+ if (status) {
+ netdev_err(netdev, "link query error, status = %d\n", status);
+ return 1;
+ }
+
+ if (!link_up)
+ return 2;
+
+ return 0;
+}
+
+/**
+ * ice_eeprom_test - perform an EEPROM test on a given net_device
+ * @netdev: network interface device structure
+ *
+ * This function performs one of the self-tests required by ethtool.
+ * Returns 0 on success, non-zero on failure.
+ */
+static u64 ice_eeprom_test(struct net_device *netdev)
+{
+ struct ice_netdev_priv *np = netdev_priv(netdev);
+ struct ice_pf *pf = np->vsi->back;
+
+ netdev_info(netdev, "EEPROM test\n");
+ return !!(ice_nvm_validate_checksum(&pf->hw));
+}
+
+/**
+ * ice_reg_pattern_test
+ * @hw: pointer to the HW struct
+ * @reg: reg to be tested
+ * @mask: bits to be touched
+ */
+static int ice_reg_pattern_test(struct ice_hw *hw, u32 reg, u32 mask)
+{
+ struct ice_pf *pf = (struct ice_pf *)hw->back;
+ static const u32 patterns[] = {
+ 0x5A5A5A5A, 0xA5A5A5A5,
+ 0x00000000, 0xFFFFFFFF
+ };
+ u32 val, orig_val;
+ int i;
+
+ orig_val = rd32(hw, reg);
+ for (i = 0; i < ARRAY_SIZE(patterns); ++i) {
+ u32 pattern = patterns[i] & mask;
+
+ wr32(hw, reg, pattern);
+ val = rd32(hw, reg);
+ if (val == pattern)
+ continue;
+ dev_err(&pf->pdev->dev,
+ "%s: reg pattern test failed - reg 0x%08x pat 0x%08x val 0x%08x\n"
+ , __func__, reg, pattern, val);
+ return 1;
+ }
+
+ wr32(hw, reg, orig_val);
+ val = rd32(hw, reg);
+ if (val != orig_val) {
+ dev_err(&pf->pdev->dev,
+ "%s: reg restore test failed - reg 0x%08x orig 0x%08x val 0x%08x\n"
+ , __func__, reg, orig_val, val);
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * ice_reg_test - perform a register test on a given net_device
+ * @netdev: network interface device structure
+ *
+ * This function performs one of the self-tests required by ethtool.
+ * Returns 0 on success, non-zero on failure.
+ */
+static u64 ice_reg_test(struct net_device *netdev)
+{
+ struct ice_netdev_priv *np = netdev_priv(netdev);
+ struct ice_hw *hw = np->vsi->port_info->hw;
+ u32 int_elements = hw->func_caps.common_cap.num_msix_vectors ?
+ hw->func_caps.common_cap.num_msix_vectors - 1 : 1;
+ struct ice_diag_reg_test_info {
+ u32 address;
+ u32 mask;
+ u32 elem_num;
+ u32 elem_size;
+ } ice_reg_list[] = {
+ {GLINT_ITR(0, 0), 0x00000fff, int_elements,
+ GLINT_ITR(0, 1) - GLINT_ITR(0, 0)},
+ {GLINT_ITR(1, 0), 0x00000fff, int_elements,
+ GLINT_ITR(1, 1) - GLINT_ITR(1, 0)},
+ {GLINT_ITR(0, 0), 0x00000fff, int_elements,
+ GLINT_ITR(2, 1) - GLINT_ITR(2, 0)},
+ {GLINT_CTL, 0xffff0001, 1, 0}
+ };
+ int i;
+
+ netdev_dbg(netdev, "Register test\n");
+ for (i = 0; i < ARRAY_SIZE(ice_reg_list); ++i) {
+ u32 j;
+
+ for (j = 0; j < ice_reg_list[i].elem_num; ++j) {
+ u32 mask = ice_reg_list[i].mask;
+ u32 reg = ice_reg_list[i].address +
+ (j * ice_reg_list[i].elem_size);
+
+ /* bail on failure (non-zero return) */
+ if (ice_reg_pattern_test(hw, reg, mask))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * ice_lbtest_prepare_rings - configure Tx/Rx test rings
+ * @vsi: pointer to the VSI structure
+ *
+ * Function configures rings of a VSI for loopback test without
+ * enabling interrupts or informing the kernel about new queues.
+ *
+ * Returns 0 on success, negative on failure.
+ */
+static int ice_lbtest_prepare_rings(struct ice_vsi *vsi)
+{
+ int status;
+
+ status = ice_vsi_setup_tx_rings(vsi);
+ if (status)
+ goto err_setup_tx_ring;
+
+ status = ice_vsi_setup_rx_rings(vsi);
+ if (status)
+ goto err_setup_rx_ring;
+
+ status = ice_vsi_cfg(vsi);
+ if (status)
+ goto err_setup_rx_ring;
+
+ status = ice_vsi_start_rx_rings(vsi);
+ if (status)
+ goto err_start_rx_ring;
+
+ return status;
+
+err_start_rx_ring:
+ ice_vsi_free_rx_rings(vsi);
+err_setup_rx_ring:
+ ice_vsi_stop_lan_tx_rings(vsi, ICE_NO_RESET, 0);
+err_setup_tx_ring:
+ ice_vsi_free_tx_rings(vsi);
+
+ return status;
+}
+
+/**
+ * ice_lbtest_disable_rings - disable Tx/Rx test rings after loopback test
+ * @vsi: pointer to the VSI structure
+ *
+ * Function stops and frees VSI rings after a loopback test.
+ * Returns 0 on success, negative on failure.
+ */
+static int ice_lbtest_disable_rings(struct ice_vsi *vsi)
+{
+ int status;
+
+ status = ice_vsi_stop_lan_tx_rings(vsi, ICE_NO_RESET, 0);
+ if (status)
+ netdev_err(vsi->netdev, "Failed to stop Tx rings, VSI %d error %d\n",
+ vsi->vsi_num, status);
+
+ status = ice_vsi_stop_rx_rings(vsi);
+ if (status)
+ netdev_err(vsi->netdev, "Failed to stop Rx rings, VSI %d error %d\n",
+ vsi->vsi_num, status);
+
+ ice_vsi_free_tx_rings(vsi);
+ ice_vsi_free_rx_rings(vsi);
+
+ return status;
+}
+
+/**
+ * ice_lbtest_create_frame - create test packet
+ * @pf: pointer to the PF structure
+ * @ret_data: allocated frame buffer
+ * @size: size of the packet data
+ *
+ * Function allocates a frame with a test pattern on specific offsets.
+ * Returns 0 on success, non-zero on failure.
+ */
+static int ice_lbtest_create_frame(struct ice_pf *pf, u8 **ret_data, u16 size)
+{
+ u8 *data;
+
+ if (!pf)
+ return -EINVAL;
+
+ data = devm_kzalloc(&pf->pdev->dev, size, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ /* Since the ethernet test frame should always be at least
+ * 64 bytes long, fill some octets in the payload with test data.
+ */
+ memset(data, 0xFF, size);
+ data[32] = 0xDE;
+ data[42] = 0xAD;
+ data[44] = 0xBE;
+ data[46] = 0xEF;
+
+ *ret_data = data;
+
+ return 0;
+}
+
+/**
+ * ice_lbtest_check_frame - verify received loopback frame
+ * @frame: pointer to the raw packet data
+ *
+ * Function verifies received test frame with a pattern.
+ * Returns true if frame matches the pattern, false otherwise.
+ */
+static bool ice_lbtest_check_frame(u8 *frame)
+{
+ /* Validate bytes of a frame under offsets chosen earlier */
+ if (frame[32] == 0xDE &&
+ frame[42] == 0xAD &&
+ frame[44] == 0xBE &&
+ frame[46] == 0xEF &&
+ frame[48] == 0xFF)
+ return true;
+
+ return false;
+}
+
+/**
+ * ice_diag_send - send test frames to the test ring
+ * @tx_ring: pointer to the transmit ring
+ * @data: pointer to the raw packet data
+ * @size: size of the packet to send
+ *
+ * Function sends loopback packets on a test Tx ring.
+ */
+static int ice_diag_send(struct ice_ring *tx_ring, u8 *data, u16 size)
+{
+ struct ice_tx_desc *tx_desc;
+ struct ice_tx_buf *tx_buf;
+ dma_addr_t dma;
+ u64 td_cmd;
+
+ tx_desc = ICE_TX_DESC(tx_ring, tx_ring->next_to_use);
+ tx_buf = &tx_ring->tx_buf[tx_ring->next_to_use];
+
+ dma = dma_map_single(tx_ring->dev, data, size, DMA_TO_DEVICE);
+ if (dma_mapping_error(tx_ring->dev, dma))
+ return -EINVAL;
+
+ tx_desc->buf_addr = cpu_to_le64(dma);
+
+ /* These flags are required for a descriptor to be pushed out */
+ td_cmd = (u64)(ICE_TX_DESC_CMD_EOP | ICE_TX_DESC_CMD_RS);
+ tx_desc->cmd_type_offset_bsz =
+ cpu_to_le64(ICE_TX_DESC_DTYPE_DATA |
+ (td_cmd << ICE_TXD_QW1_CMD_S) |
+ ((u64)0 << ICE_TXD_QW1_OFFSET_S) |
+ ((u64)size << ICE_TXD_QW1_TX_BUF_SZ_S) |
+ ((u64)0 << ICE_TXD_QW1_L2TAG1_S));
+
+ tx_buf->next_to_watch = tx_desc;
+
+ /* Force memory write to complete before letting h/w know
+ * there are new descriptors to fetch.
+ */
+ wmb();
+
+ tx_ring->next_to_use++;
+ if (tx_ring->next_to_use >= tx_ring->count)
+ tx_ring->next_to_use = 0;
+
+ writel_relaxed(tx_ring->next_to_use, tx_ring->tail);
+
+ /* Wait until the packets get transmitted to the receive queue. */
+ usleep_range(1000, 2000);
+ dma_unmap_single(tx_ring->dev, dma, size, DMA_TO_DEVICE);
+
+ return 0;
+}
+
+#define ICE_LB_FRAME_SIZE 64
+/**
+ * ice_lbtest_receive_frames - receive and verify test frames
+ * @rx_ring: pointer to the receive ring
+ *
+ * Function receives loopback packets and verify their correctness.
+ * Returns number of received valid frames.
+ */
+static int ice_lbtest_receive_frames(struct ice_ring *rx_ring)
+{
+ struct ice_rx_buf *rx_buf;
+ int valid_frames, i;
+ u8 *received_buf;
+
+ valid_frames = 0;
+
+ for (i = 0; i < rx_ring->count; i++) {
+ union ice_32b_rx_flex_desc *rx_desc;
+
+ rx_desc = ICE_RX_DESC(rx_ring, i);
+
+ if (!(rx_desc->wb.status_error0 &
+ cpu_to_le16(ICE_TX_DESC_CMD_EOP | ICE_TX_DESC_CMD_RS)))
+ continue;
+
+ rx_buf = &rx_ring->rx_buf[i];
+ received_buf = page_address(rx_buf->page);
+
+ if (ice_lbtest_check_frame(received_buf))
+ valid_frames++;
+ }
+
+ return valid_frames;
+}
+
+/**
+ * ice_loopback_test - perform a loopback test on a given net_device
+ * @netdev: network interface device structure
+ *
+ * This function performs one of the self-tests required by ethtool.
+ * Returns 0 on success, non-zero on failure.
+ */
+static u64 ice_loopback_test(struct net_device *netdev)
+{
+ struct ice_netdev_priv *np = netdev_priv(netdev);
+ struct ice_vsi *orig_vsi = np->vsi, *test_vsi;
+ struct ice_pf *pf = orig_vsi->back;
+ struct ice_ring *tx_ring, *rx_ring;
+ u8 broadcast[ETH_ALEN], ret = 0;
+ int num_frames, valid_frames;
+ LIST_HEAD(tmp_list);
+ u8 *tx_frame;
+ int i;
+
+ netdev_info(netdev, "loopback test\n");
+
+ test_vsi = ice_lb_vsi_setup(pf, pf->hw.port_info);
+ if (!test_vsi) {
+ netdev_err(netdev, "Failed to create a VSI for the loopback test");
+ return 1;
+ }
+
+ test_vsi->netdev = netdev;
+ tx_ring = test_vsi->tx_rings[0];
+ rx_ring = test_vsi->rx_rings[0];
+
+ if (ice_lbtest_prepare_rings(test_vsi)) {
+ ret = 2;
+ goto lbtest_vsi_close;
+ }
+
+ if (ice_alloc_rx_bufs(rx_ring, rx_ring->count)) {
+ ret = 3;
+ goto lbtest_rings_dis;
+ }
+
+ /* Enable MAC loopback in firmware */
+ if (ice_aq_set_mac_loopback(&pf->hw, true, NULL)) {
+ ret = 4;
+ goto lbtest_mac_dis;
+ }
+
+ /* Test VSI needs to receive broadcast packets */
+ eth_broadcast_addr(broadcast);
+ if (ice_add_mac_to_list(test_vsi, &tmp_list, broadcast)) {
+ ret = 5;
+ goto lbtest_mac_dis;
+ }
+
+ if (ice_add_mac(&pf->hw, &tmp_list)) {
+ ret = 6;
+ goto free_mac_list;
+ }
+
+ if (ice_lbtest_create_frame(pf, &tx_frame, ICE_LB_FRAME_SIZE)) {
+ ret = 7;
+ goto remove_mac_filters;
+ }
+
+ num_frames = min_t(int, tx_ring->count, 32);
+ for (i = 0; i < num_frames; i++) {
+ if (ice_diag_send(tx_ring, tx_frame, ICE_LB_FRAME_SIZE)) {
+ ret = 8;
+ goto lbtest_free_frame;
+ }
+ }
+
+ valid_frames = ice_lbtest_receive_frames(rx_ring);
+ if (!valid_frames)
+ ret = 9;
+ else if (valid_frames != num_frames)
+ ret = 10;
+
+lbtest_free_frame:
+ devm_kfree(&pf->pdev->dev, tx_frame);
+remove_mac_filters:
+ if (ice_remove_mac(&pf->hw, &tmp_list))
+ netdev_err(netdev, "Could not remove MAC filter for the test VSI");
+free_mac_list:
+ ice_free_fltr_list(&pf->pdev->dev, &tmp_list);
+lbtest_mac_dis:
+ /* Disable MAC loopback after the test is completed. */
+ if (ice_aq_set_mac_loopback(&pf->hw, false, NULL))
+ netdev_err(netdev, "Could not disable MAC loopback\n");
+lbtest_rings_dis:
+ if (ice_lbtest_disable_rings(test_vsi))
+ netdev_err(netdev, "Could not disable test rings\n");
+lbtest_vsi_close:
+ test_vsi->netdev = NULL;
+ if (ice_vsi_release(test_vsi))
+ netdev_err(netdev, "Failed to remove the test VSI");
+
+ return ret;
+}
+
+/**
+ * ice_intr_test - perform an interrupt test on a given net_device
+ * @netdev: network interface device structure
+ *
+ * This function performs one of the self-tests required by ethtool.
+ * Returns 0 on success, non-zero on failure.
+ */
+static u64 ice_intr_test(struct net_device *netdev)
+{
+ struct ice_netdev_priv *np = netdev_priv(netdev);
+ struct ice_pf *pf = np->vsi->back;
+ u16 swic_old = pf->sw_int_count;
+
+ netdev_info(netdev, "interrupt test\n");
+
+ wr32(&pf->hw, GLINT_DYN_CTL(pf->oicr_idx),
+ GLINT_DYN_CTL_SW_ITR_INDX_M |
+ GLINT_DYN_CTL_INTENA_MSK_M |
+ GLINT_DYN_CTL_SWINT_TRIG_M);
+
+ usleep_range(1000, 2000);
+ return (swic_old == pf->sw_int_count);
+}
+
+/**
+ * ice_self_test - handler function for performing a self-test by ethtool
+ * @netdev: network interface device structure
+ * @eth_test: ethtool_test structure
+ * @data: required by ethtool.self_test
+ *
+ * This function is called after invoking 'ethtool -t devname' command where
+ * devname is the name of the network device on which ethtool should operate.
+ * It performs a set of self-tests to check if a device works properly.
+ */
+static void
+ice_self_test(struct net_device *netdev, struct ethtool_test *eth_test,
+ u64 *data)
+{
+ struct ice_netdev_priv *np = netdev_priv(netdev);
+ bool if_running = netif_running(netdev);
+ struct ice_pf *pf = np->vsi->back;
+
+ if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
+ netdev_info(netdev, "offline testing starting\n");
+
+ set_bit(__ICE_TESTING, pf->state);
+
+ if (ice_active_vfs(pf)) {
+ dev_warn(&pf->pdev->dev,
+ "Please take active VFs and Netqueues offline and restart the adapter before running NIC diagnostics\n");
+ data[ICE_ETH_TEST_REG] = 1;
+ data[ICE_ETH_TEST_EEPROM] = 1;
+ data[ICE_ETH_TEST_INTR] = 1;
+ data[ICE_ETH_TEST_LOOP] = 1;
+ data[ICE_ETH_TEST_LINK] = 1;
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+ clear_bit(__ICE_TESTING, pf->state);
+ goto skip_ol_tests;
+ }
+ /* If the device is online then take it offline */
+ if (if_running)
+ /* indicate we're in test mode */
+ ice_stop(netdev);
+
+ data[ICE_ETH_TEST_LINK] = ice_link_test(netdev);
+ data[ICE_ETH_TEST_EEPROM] = ice_eeprom_test(netdev);
+ data[ICE_ETH_TEST_INTR] = ice_intr_test(netdev);
+ data[ICE_ETH_TEST_LOOP] = ice_loopback_test(netdev);
+ data[ICE_ETH_TEST_REG] = ice_reg_test(netdev);
+
+ if (data[ICE_ETH_TEST_LINK] ||
+ data[ICE_ETH_TEST_EEPROM] ||
+ data[ICE_ETH_TEST_LOOP] ||
+ data[ICE_ETH_TEST_INTR] ||
+ data[ICE_ETH_TEST_REG])
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ clear_bit(__ICE_TESTING, pf->state);
+
+ if (if_running) {
+ int status = ice_open(netdev);
+
+ if (status) {
+ dev_err(&pf->pdev->dev,
+ "Could not open device %s, err %d",
+ pf->int_name, status);
+ }
+ }
+ } else {
+ /* Online tests */
+ netdev_info(netdev, "online testing starting\n");
+
+ data[ICE_ETH_TEST_LINK] = ice_link_test(netdev);
+ if (data[ICE_ETH_TEST_LINK])
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ /* Offline only tests, not run in online; pass by default */
+ data[ICE_ETH_TEST_REG] = 0;
+ data[ICE_ETH_TEST_EEPROM] = 0;
+ data[ICE_ETH_TEST_INTR] = 0;
+ data[ICE_ETH_TEST_LOOP] = 0;
+ }
+
+skip_ol_tests:
+ netdev_info(netdev, "testing finished\n");
+}
+
static void ice_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
{
struct ice_netdev_priv *np = netdev_priv(netdev);
@@ -295,17 +881,17 @@ static void ice_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
ice_for_each_alloc_txq(vsi, i) {
snprintf(p, ETH_GSTRING_LEN,
- "tx-queue-%u.tx_packets", i);
+ "tx_queue_%u_packets", i);
p += ETH_GSTRING_LEN;
- snprintf(p, ETH_GSTRING_LEN, "tx-queue-%u.tx_bytes", i);
+ snprintf(p, ETH_GSTRING_LEN, "tx_queue_%u_bytes", i);
p += ETH_GSTRING_LEN;
}
ice_for_each_alloc_rxq(vsi, i) {
snprintf(p, ETH_GSTRING_LEN,
- "rx-queue-%u.rx_packets", i);
+ "rx_queue_%u_packets", i);
p += ETH_GSTRING_LEN;
- snprintf(p, ETH_GSTRING_LEN, "rx-queue-%u.rx_bytes", i);
+ snprintf(p, ETH_GSTRING_LEN, "rx_queue_%u_bytes", i);
p += ETH_GSTRING_LEN;
}
@@ -320,21 +906,24 @@ static void ice_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
for (i = 0; i < ICE_MAX_USER_PRIORITY; i++) {
snprintf(p, ETH_GSTRING_LEN,
- "port.tx-priority-%u-xon", i);
+ "tx_priority_%u_xon.nic", i);
p += ETH_GSTRING_LEN;
snprintf(p, ETH_GSTRING_LEN,
- "port.tx-priority-%u-xoff", i);
+ "tx_priority_%u_xoff.nic", i);
p += ETH_GSTRING_LEN;
}
for (i = 0; i < ICE_MAX_USER_PRIORITY; i++) {
snprintf(p, ETH_GSTRING_LEN,
- "port.rx-priority-%u-xon", i);
+ "rx_priority_%u_xon.nic", i);
p += ETH_GSTRING_LEN;
snprintf(p, ETH_GSTRING_LEN,
- "port.rx-priority-%u-xoff", i);
+ "rx_priority_%u_xoff.nic", i);
p += ETH_GSTRING_LEN;
}
break;
+ case ETH_SS_TEST:
+ memcpy(data, ice_gstrings_test, ICE_TEST_LEN * ETH_GSTRING_LEN);
+ break;
case ETH_SS_PRIV_FLAGS:
for (i = 0; i < ICE_PRIV_FLAG_ARRAY_SIZE; i++) {
snprintf(p, ETH_GSTRING_LEN, "%s",
@@ -371,6 +960,185 @@ ice_set_phys_id(struct net_device *netdev, enum ethtool_phys_id_state state)
}
/**
+ * ice_set_fec_cfg - Set link FEC options
+ * @netdev: network interface device structure
+ * @req_fec: FEC mode to configure
+ */
+static int ice_set_fec_cfg(struct net_device *netdev, enum ice_fec_mode req_fec)
+{
+ struct ice_netdev_priv *np = netdev_priv(netdev);
+ struct ice_aqc_set_phy_cfg_data config = { 0 };
+ struct ice_aqc_get_phy_caps_data *caps;
+ struct ice_vsi *vsi = np->vsi;
+ u8 sw_cfg_caps, sw_cfg_fec;
+ struct ice_port_info *pi;
+ enum ice_status status;
+ int err = 0;
+
+ pi = vsi->port_info;
+ if (!pi)
+ return -EOPNOTSUPP;
+
+ /* Changing the FEC parameters is not supported if not the PF VSI */
+ if (vsi->type != ICE_VSI_PF) {
+ netdev_info(netdev, "Changing FEC parameters only supported for PF VSI\n");
+ return -EOPNOTSUPP;
+ }
+
+ /* Get last SW configuration */
+ caps = devm_kzalloc(&vsi->back->pdev->dev, sizeof(*caps), GFP_KERNEL);
+ if (!caps)
+ return -ENOMEM;
+
+ status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_SW_CFG,
+ caps, NULL);
+ if (status) {
+ err = -EAGAIN;
+ goto done;
+ }
+
+ /* Copy SW configuration returned from PHY caps to PHY config */
+ ice_copy_phy_caps_to_cfg(caps, &config);
+ sw_cfg_caps = caps->caps;
+ sw_cfg_fec = caps->link_fec_options;
+
+ /* Get toloplogy caps, then copy PHY FEC topoloy caps to PHY config */
+ memset(caps, 0, sizeof(*caps));
+
+ status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_TOPO_CAP,
+ caps, NULL);
+ if (status) {
+ err = -EAGAIN;
+ goto done;
+ }
+
+ config.caps |= (caps->caps & ICE_AQC_PHY_EN_AUTO_FEC);
+ config.link_fec_opt = caps->link_fec_options;
+
+ ice_cfg_phy_fec(&config, req_fec);
+
+ /* If FEC mode has changed, then set PHY configuration and enable AN. */
+ if ((config.caps & ICE_AQ_PHY_ENA_AUTO_FEC) !=
+ (sw_cfg_caps & ICE_AQC_PHY_EN_AUTO_FEC) ||
+ config.link_fec_opt != sw_cfg_fec) {
+ if (caps->caps & ICE_AQC_PHY_AN_MODE)
+ config.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
+
+ status = ice_aq_set_phy_cfg(pi->hw, pi->lport, &config, NULL);
+
+ if (status)
+ err = -EAGAIN;
+ }
+
+done:
+ devm_kfree(&vsi->back->pdev->dev, caps);
+ return err;
+}
+
+/**
+ * ice_set_fecparam - Set FEC link options
+ * @netdev: network interface device structure
+ * @fecparam: Ethtool structure to retrieve FEC parameters
+ */
+static int
+ice_set_fecparam(struct net_device *netdev, struct ethtool_fecparam *fecparam)
+{
+ struct ice_netdev_priv *np = netdev_priv(netdev);
+ struct ice_vsi *vsi = np->vsi;
+ enum ice_fec_mode fec;
+
+ switch (fecparam->fec) {
+ case ETHTOOL_FEC_AUTO:
+ fec = ICE_FEC_AUTO;
+ break;
+ case ETHTOOL_FEC_RS:
+ fec = ICE_FEC_RS;
+ break;
+ case ETHTOOL_FEC_BASER:
+ fec = ICE_FEC_BASER;
+ break;
+ case ETHTOOL_FEC_OFF:
+ case ETHTOOL_FEC_NONE:
+ fec = ICE_FEC_NONE;
+ break;
+ default:
+ dev_warn(&vsi->back->pdev->dev, "Unsupported FEC mode: %d\n",
+ fecparam->fec);
+ return -EINVAL;
+ }
+
+ return ice_set_fec_cfg(netdev, fec);
+}
+
+/**
+ * ice_get_fecparam - Get link FEC options
+ * @netdev: network interface device structure
+ * @fecparam: Ethtool structure to retrieve FEC parameters
+ */
+static int
+ice_get_fecparam(struct net_device *netdev, struct ethtool_fecparam *fecparam)
+{
+ struct ice_netdev_priv *np = netdev_priv(netdev);
+ struct ice_aqc_get_phy_caps_data *caps;
+ struct ice_link_status *link_info;
+ struct ice_vsi *vsi = np->vsi;
+ struct ice_port_info *pi;
+ enum ice_status status;
+ int err = 0;
+
+ pi = vsi->port_info;
+
+ if (!pi)
+ return -EOPNOTSUPP;
+ link_info = &pi->phy.link_info;
+
+ /* Set FEC mode based on negotiated link info */
+ switch (link_info->fec_info) {
+ case ICE_AQ_LINK_25G_KR_FEC_EN:
+ fecparam->active_fec = ETHTOOL_FEC_BASER;
+ break;
+ case ICE_AQ_LINK_25G_RS_528_FEC_EN:
+ /* fall through */
+ case ICE_AQ_LINK_25G_RS_544_FEC_EN:
+ fecparam->active_fec = ETHTOOL_FEC_RS;
+ break;
+ default:
+ fecparam->active_fec = ETHTOOL_FEC_OFF;
+ break;
+ }
+
+ caps = devm_kzalloc(&vsi->back->pdev->dev, sizeof(*caps), GFP_KERNEL);
+ if (!caps)
+ return -ENOMEM;
+
+ status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_TOPO_CAP,
+ caps, NULL);
+ if (status) {
+ err = -EAGAIN;
+ goto done;
+ }
+
+ /* Set supported/configured FEC modes based on PHY capability */
+ if (caps->caps & ICE_AQC_PHY_EN_AUTO_FEC)
+ fecparam->fec |= ETHTOOL_FEC_AUTO;
+ if (caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_EN ||
+ caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_REQ ||
+ caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_CLAUSE74_EN ||
+ caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_REQ)
+ fecparam->fec |= ETHTOOL_FEC_BASER;
+ if (caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_528_REQ ||
+ caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_544_REQ ||
+ caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_CLAUSE91_EN)
+ fecparam->fec |= ETHTOOL_FEC_RS;
+ if (caps->link_fec_options == 0)
+ fecparam->fec |= ETHTOOL_FEC_OFF;
+
+done:
+ devm_kfree(&vsi->back->pdev->dev, caps);
+ return err;
+}
+
+/**
* ice_get_priv_flags - report device private flags
* @netdev: network interface device structure
*
@@ -433,10 +1201,11 @@ static int ice_set_priv_flags(struct net_device *netdev, u32 flags)
bitmap_xor(change_flags, pf->flags, orig_flags, ICE_PF_FLAGS_NBITS);
- if (test_bit(ICE_FLAG_DISABLE_FW_LLDP, change_flags)) {
- if (test_bit(ICE_FLAG_DISABLE_FW_LLDP, pf->flags)) {
+ if (test_bit(ICE_FLAG_ENABLE_FW_LLDP, change_flags)) {
+ if (!test_bit(ICE_FLAG_ENABLE_FW_LLDP, pf->flags)) {
enum ice_status status;
+ /* Disable FW LLDP engine */
status = ice_aq_cfg_lldp_mib_change(&pf->hw, false,
NULL);
/* If unregistering for LLDP events fails, this is
@@ -450,7 +1219,7 @@ static int ice_set_priv_flags(struct net_device *netdev, u32 flags)
/* The AQ call to stop the FW LLDP agent will generate
* an error if the agent is already stopped.
*/
- status = ice_aq_stop_lldp(&pf->hw, true, NULL);
+ status = ice_aq_stop_lldp(&pf->hw, true, true, NULL);
if (status)
dev_warn(&pf->pdev->dev,
"Fail to stop LLDP agent\n");
@@ -458,9 +1227,14 @@ static int ice_set_priv_flags(struct net_device *netdev, u32 flags)
* will likely not need DCB, so failure to init is
* not a concern of ethtool
*/
- status = ice_init_pf_dcb(pf);
+ status = ice_init_pf_dcb(pf, true);
if (status)
dev_warn(&pf->pdev->dev, "Fail to init DCB\n");
+
+ /* Forward LLDP packets to default VSI so that they
+ * are passed up the stack
+ */
+ ice_cfg_sw_lldp(vsi, false, true);
} else {
enum ice_status status;
bool dcbx_agent_status;
@@ -468,12 +1242,12 @@ static int ice_set_priv_flags(struct net_device *netdev, u32 flags)
/* AQ command to start FW LLDP agent will return an
* error if the agent is already started
*/
- status = ice_aq_start_lldp(&pf->hw, NULL);
+ status = ice_aq_start_lldp(&pf->hw, true, NULL);
if (status)
dev_warn(&pf->pdev->dev,
"Fail to start LLDP Agent\n");
- /* AQ command to start FW DCBx agent will fail if
+ /* AQ command to start FW DCBX agent will fail if
* the agent is already started
*/
status = ice_aq_start_stop_dcbx(&pf->hw, true,
@@ -491,15 +1265,14 @@ static int ice_set_priv_flags(struct net_device *netdev, u32 flags)
* registration/init failed but do not return error
* state to ethtool
*/
- status = ice_aq_cfg_lldp_mib_change(&pf->hw, false,
- NULL);
- if (status)
- dev_dbg(&pf->pdev->dev,
- "Fail to reg for MIB change\n");
-
- status = ice_init_pf_dcb(pf);
+ status = ice_init_pf_dcb(pf, true);
if (status)
dev_dbg(&pf->pdev->dev, "Fail to init DCB\n");
+
+ /* Remove rule to direct LLDP packets to default VSI.
+ * The FW LLDP engine will now be consuming them.
+ */
+ ice_cfg_sw_lldp(vsi, false, false);
}
}
clear_bit(ICE_FLAG_ETHTOOL_CTXT, pf->flags);
@@ -529,6 +1302,8 @@ static int ice_get_sset_count(struct net_device *netdev, int sset)
* not safe.
*/
return ICE_ALL_STATS_LEN(netdev);
+ case ETH_SS_TEST:
+ return ICE_TEST_LEN;
case ETH_SS_PRIV_FLAGS:
return ICE_PRIV_FLAG_ARRAY_SIZE;
default:
@@ -628,7 +1403,8 @@ ice_phy_type_to_ethtool(struct net_device *netdev,
phy_types_low & ICE_PHY_TYPE_LOW_100M_SGMII) {
ethtool_link_ksettings_add_link_mode(ks, supported,
100baseT_Full);
- if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_100MB)
+ if (!hw_link_info->req_speeds ||
+ hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_100MB)
ethtool_link_ksettings_add_link_mode(ks, advertising,
100baseT_Full);
}
@@ -636,14 +1412,16 @@ ice_phy_type_to_ethtool(struct net_device *netdev,
phy_types_low & ICE_PHY_TYPE_LOW_1G_SGMII) {
ethtool_link_ksettings_add_link_mode(ks, supported,
1000baseT_Full);
- if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_1000MB)
+ if (!hw_link_info->req_speeds ||
+ hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_1000MB)
ethtool_link_ksettings_add_link_mode(ks, advertising,
1000baseT_Full);
}
if (phy_types_low & ICE_PHY_TYPE_LOW_1000BASE_KX) {
ethtool_link_ksettings_add_link_mode(ks, supported,
1000baseKX_Full);
- if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_1000MB)
+ if (!hw_link_info->req_speeds ||
+ hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_1000MB)
ethtool_link_ksettings_add_link_mode(ks, advertising,
1000baseKX_Full);
}
@@ -651,14 +1429,16 @@ ice_phy_type_to_ethtool(struct net_device *netdev,
phy_types_low & ICE_PHY_TYPE_LOW_1000BASE_LX) {
ethtool_link_ksettings_add_link_mode(ks, supported,
1000baseX_Full);
- if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_1000MB)
+ if (!hw_link_info->req_speeds ||
+ hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_1000MB)
ethtool_link_ksettings_add_link_mode(ks, advertising,
1000baseX_Full);
}
if (phy_types_low & ICE_PHY_TYPE_LOW_2500BASE_T) {
ethtool_link_ksettings_add_link_mode(ks, supported,
2500baseT_Full);
- if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_2500MB)
+ if (!hw_link_info->req_speeds ||
+ hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_2500MB)
ethtool_link_ksettings_add_link_mode(ks, advertising,
2500baseT_Full);
}
@@ -666,7 +1446,8 @@ ice_phy_type_to_ethtool(struct net_device *netdev,
phy_types_low & ICE_PHY_TYPE_LOW_2500BASE_KX) {
ethtool_link_ksettings_add_link_mode(ks, supported,
2500baseX_Full);
- if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_2500MB)
+ if (!hw_link_info->req_speeds ||
+ hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_2500MB)
ethtool_link_ksettings_add_link_mode(ks, advertising,
2500baseX_Full);
}
@@ -674,7 +1455,8 @@ ice_phy_type_to_ethtool(struct net_device *netdev,
phy_types_low & ICE_PHY_TYPE_LOW_5GBASE_KR) {
ethtool_link_ksettings_add_link_mode(ks, supported,
5000baseT_Full);
- if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_5GB)
+ if (!hw_link_info->req_speeds ||
+ hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_5GB)
ethtool_link_ksettings_add_link_mode(ks, advertising,
5000baseT_Full);
}
@@ -684,28 +1466,32 @@ ice_phy_type_to_ethtool(struct net_device *netdev,
phy_types_low & ICE_PHY_TYPE_LOW_10G_SFI_C2C) {
ethtool_link_ksettings_add_link_mode(ks, supported,
10000baseT_Full);
- if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_10GB)
+ if (!hw_link_info->req_speeds ||
+ hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_10GB)
ethtool_link_ksettings_add_link_mode(ks, advertising,
10000baseT_Full);
}
if (phy_types_low & ICE_PHY_TYPE_LOW_10GBASE_KR_CR1) {
ethtool_link_ksettings_add_link_mode(ks, supported,
10000baseKR_Full);
- if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_10GB)
+ if (!hw_link_info->req_speeds ||
+ hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_10GB)
ethtool_link_ksettings_add_link_mode(ks, advertising,
10000baseKR_Full);
}
if (phy_types_low & ICE_PHY_TYPE_LOW_10GBASE_SR) {
ethtool_link_ksettings_add_link_mode(ks, supported,
10000baseSR_Full);
- if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_10GB)
+ if (!hw_link_info->req_speeds ||
+ hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_10GB)
ethtool_link_ksettings_add_link_mode(ks, advertising,
10000baseSR_Full);
}
if (phy_types_low & ICE_PHY_TYPE_LOW_10GBASE_LR) {
ethtool_link_ksettings_add_link_mode(ks, supported,
10000baseLR_Full);
- if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_10GB)
+ if (!hw_link_info->req_speeds ||
+ hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_10GB)
ethtool_link_ksettings_add_link_mode(ks, advertising,
10000baseLR_Full);
}
@@ -717,7 +1503,8 @@ ice_phy_type_to_ethtool(struct net_device *netdev,
phy_types_low & ICE_PHY_TYPE_LOW_25G_AUI_C2C) {
ethtool_link_ksettings_add_link_mode(ks, supported,
25000baseCR_Full);
- if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_25GB)
+ if (!hw_link_info->req_speeds ||
+ hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_25GB)
ethtool_link_ksettings_add_link_mode(ks, advertising,
25000baseCR_Full);
}
@@ -725,7 +1512,8 @@ ice_phy_type_to_ethtool(struct net_device *netdev,
phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_LR) {
ethtool_link_ksettings_add_link_mode(ks, supported,
25000baseSR_Full);
- if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_25GB)
+ if (!hw_link_info->req_speeds ||
+ hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_25GB)
ethtool_link_ksettings_add_link_mode(ks, advertising,
25000baseSR_Full);
}
@@ -734,14 +1522,16 @@ ice_phy_type_to_ethtool(struct net_device *netdev,
phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_KR1) {
ethtool_link_ksettings_add_link_mode(ks, supported,
25000baseKR_Full);
- if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_25GB)
+ if (!hw_link_info->req_speeds ||
+ hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_25GB)
ethtool_link_ksettings_add_link_mode(ks, advertising,
25000baseKR_Full);
}
if (phy_types_low & ICE_PHY_TYPE_LOW_40GBASE_KR4) {
ethtool_link_ksettings_add_link_mode(ks, supported,
40000baseKR4_Full);
- if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_40GB)
+ if (!hw_link_info->req_speeds ||
+ hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_40GB)
ethtool_link_ksettings_add_link_mode(ks, advertising,
40000baseKR4_Full);
}
@@ -750,21 +1540,24 @@ ice_phy_type_to_ethtool(struct net_device *netdev,
phy_types_low & ICE_PHY_TYPE_LOW_40G_XLAUI) {
ethtool_link_ksettings_add_link_mode(ks, supported,
40000baseCR4_Full);
- if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_40GB)
+ if (!hw_link_info->req_speeds ||
+ hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_40GB)
ethtool_link_ksettings_add_link_mode(ks, advertising,
40000baseCR4_Full);
}
if (phy_types_low & ICE_PHY_TYPE_LOW_40GBASE_SR4) {
ethtool_link_ksettings_add_link_mode(ks, supported,
40000baseSR4_Full);
- if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_40GB)
+ if (!hw_link_info->req_speeds ||
+ hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_40GB)
ethtool_link_ksettings_add_link_mode(ks, advertising,
40000baseSR4_Full);
}
if (phy_types_low & ICE_PHY_TYPE_LOW_40GBASE_LR4) {
ethtool_link_ksettings_add_link_mode(ks, supported,
40000baseLR4_Full);
- if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_40GB)
+ if (!hw_link_info->req_speeds ||
+ hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_40GB)
ethtool_link_ksettings_add_link_mode(ks, advertising,
40000baseLR4_Full);
}
@@ -779,7 +1572,8 @@ ice_phy_type_to_ethtool(struct net_device *netdev,
phy_types_low & ICE_PHY_TYPE_LOW_50G_AUI1) {
ethtool_link_ksettings_add_link_mode(ks, supported,
50000baseCR2_Full);
- if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_50GB)
+ if (!hw_link_info->req_speeds ||
+ hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_50GB)
ethtool_link_ksettings_add_link_mode(ks, advertising,
50000baseCR2_Full);
}
@@ -787,7 +1581,8 @@ ice_phy_type_to_ethtool(struct net_device *netdev,
phy_types_low & ICE_PHY_TYPE_LOW_50GBASE_KR_PAM4) {
ethtool_link_ksettings_add_link_mode(ks, supported,
50000baseKR2_Full);
- if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_50GB)
+ if (!hw_link_info->req_speeds ||
+ hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_50GB)
ethtool_link_ksettings_add_link_mode(ks, advertising,
50000baseKR2_Full);
}
@@ -797,7 +1592,8 @@ ice_phy_type_to_ethtool(struct net_device *netdev,
phy_types_low & ICE_PHY_TYPE_LOW_50GBASE_LR) {
ethtool_link_ksettings_add_link_mode(ks, supported,
50000baseSR2_Full);
- if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_50GB)
+ if (!hw_link_info->req_speeds ||
+ hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_50GB)
ethtool_link_ksettings_add_link_mode(ks, advertising,
50000baseSR2_Full);
}
@@ -814,7 +1610,8 @@ ice_phy_type_to_ethtool(struct net_device *netdev,
phy_types_high & ICE_PHY_TYPE_HIGH_100G_AUI2) {
ethtool_link_ksettings_add_link_mode(ks, supported,
100000baseCR4_Full);
- if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_100GB)
+ if (!hw_link_info->req_speeds ||
+ hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_100GB)
need_add_adv_mode = true;
}
if (need_add_adv_mode) {
@@ -826,7 +1623,8 @@ ice_phy_type_to_ethtool(struct net_device *netdev,
phy_types_low & ICE_PHY_TYPE_LOW_100GBASE_SR2) {
ethtool_link_ksettings_add_link_mode(ks, supported,
100000baseSR4_Full);
- if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_100GB)
+ if (!hw_link_info->req_speeds ||
+ hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_100GB)
need_add_adv_mode = true;
}
if (need_add_adv_mode) {
@@ -838,7 +1636,8 @@ ice_phy_type_to_ethtool(struct net_device *netdev,
phy_types_low & ICE_PHY_TYPE_LOW_100GBASE_DR) {
ethtool_link_ksettings_add_link_mode(ks, supported,
100000baseLR4_ER4_Full);
- if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_100GB)
+ if (!hw_link_info->req_speeds ||
+ hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_100GB)
need_add_adv_mode = true;
}
if (need_add_adv_mode) {
@@ -851,7 +1650,8 @@ ice_phy_type_to_ethtool(struct net_device *netdev,
phy_types_high & ICE_PHY_TYPE_HIGH_100GBASE_KR2_PAM4) {
ethtool_link_ksettings_add_link_mode(ks, supported,
100000baseKR4_Full);
- if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_100GB)
+ if (!hw_link_info->req_speeds ||
+ hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_100GB)
need_add_adv_mode = true;
}
if (need_add_adv_mode)
@@ -1275,6 +2075,7 @@ ice_get_link_ksettings(struct net_device *netdev,
struct ethtool_link_ksettings *ks)
{
struct ice_netdev_priv *np = netdev_priv(netdev);
+ struct ice_aqc_get_phy_caps_data *caps;
struct ice_link_status *hw_link_info;
struct ice_vsi *vsi = np->vsi;
@@ -1345,6 +2146,40 @@ ice_get_link_ksettings(struct net_device *netdev,
break;
}
+ caps = devm_kzalloc(&vsi->back->pdev->dev, sizeof(*caps), GFP_KERNEL);
+ if (!caps)
+ goto done;
+
+ if (ice_aq_get_phy_caps(vsi->port_info, false, ICE_AQC_REPORT_TOPO_CAP,
+ caps, NULL))
+ netdev_info(netdev, "Get phy capability failed.\n");
+
+ /* Set supported FEC modes based on PHY capability */
+ ethtool_link_ksettings_add_link_mode(ks, supported, FEC_NONE);
+
+ if (caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_EN ||
+ caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_CLAUSE74_EN)
+ ethtool_link_ksettings_add_link_mode(ks, supported, FEC_BASER);
+ if (caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_CLAUSE91_EN)
+ ethtool_link_ksettings_add_link_mode(ks, supported, FEC_RS);
+
+ if (ice_aq_get_phy_caps(vsi->port_info, false, ICE_AQC_REPORT_SW_CFG,
+ caps, NULL))
+ netdev_info(netdev, "Get phy capability failed.\n");
+
+ /* Set advertised FEC modes based on PHY capability */
+ ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_NONE);
+
+ if (caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_REQ ||
+ caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_REQ)
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ FEC_BASER);
+ if (caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_528_REQ ||
+ caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_544_REQ)
+ ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_RS);
+
+done:
+ devm_kfree(&vsi->back->pdev->dev, caps);
return 0;
}
@@ -2371,8 +3206,7 @@ ice_set_rc_coalesce(enum ice_container_type c_type, struct ethtool_coalesce *ec,
if (ec->rx_coalesce_usecs_high != rc->ring->q_vector->intrl) {
rc->ring->q_vector->intrl = ec->rx_coalesce_usecs_high;
- wr32(&pf->hw, GLINT_RATE(vsi->hw_base_vector +
- rc->ring->q_vector->v_idx),
+ wr32(&pf->hw, GLINT_RATE(rc->ring->q_vector->reg_idx),
ice_intrl_usec_to_reg(ec->rx_coalesce_usecs_high,
pf->hw.intrl_gran));
}
@@ -2533,6 +3367,7 @@ static const struct ethtool_ops ice_ethtool_ops = {
.get_regs = ice_get_regs,
.get_msglevel = ice_get_msglevel,
.set_msglevel = ice_set_msglevel,
+ .self_test = ice_self_test,
.get_link = ethtool_op_get_link,
.get_eeprom_len = ice_get_eeprom_len,
.get_eeprom = ice_get_eeprom,
@@ -2557,6 +3392,8 @@ static const struct ethtool_ops ice_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
.get_per_queue_coalesce = ice_get_per_q_coalesce,
.set_per_queue_coalesce = ice_set_per_q_coalesce,
+ .get_fecparam = ice_get_fecparam,
+ .set_fecparam = ice_set_fecparam,
};
/**
diff --git a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h
index ec25f26069b0..6c5ce05742b1 100644
--- a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h
+++ b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h
@@ -6,6 +6,9 @@
#ifndef _ICE_HW_AUTOGEN_H_
#define _ICE_HW_AUTOGEN_H_
+#define PF0INT_ITR_0(_i) (0x03000004 + ((_i) * 4096))
+#define PF0INT_ITR_1(_i) (0x03000008 + ((_i) * 4096))
+#define PF0INT_ITR_2(_i) (0x0300000C + ((_i) * 4096))
#define QTX_COMM_DBELL(_DBQM) (0x002C0000 + ((_DBQM) * 4))
#define QTX_COMM_HEAD(_DBQM) (0x000E0000 + ((_DBQM) * 4))
#define QTX_COMM_HEAD_HEAD_S 0
@@ -155,6 +158,7 @@
#define PFINT_OICR_HMC_ERR_M BIT(26)
#define PFINT_OICR_PE_CRITERR_M BIT(28)
#define PFINT_OICR_VFLR_M BIT(29)
+#define PFINT_OICR_SWINT_M BIT(31)
#define PFINT_OICR_CTL 0x0016CA80
#define PFINT_OICR_CTL_MSIX_INDX_M ICE_M(0x7FF, 0)
#define PFINT_OICR_CTL_ITR_INDX_S 11
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index fbf1eba0cc2a..a19f5920733b 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -137,6 +137,8 @@ ice_setup_tx_ctx(struct ice_ring *ring, struct ice_tlan_ctx *tlan_ctx, u16 pf_q)
* for PF or EMP this field should be set to zero
*/
switch (vsi->type) {
+ case ICE_VSI_LB:
+ /* fall through */
case ICE_VSI_PF:
tlan_ctx->vmvf_type = ICE_TLAN_CTX_VMVF_TYPE_PF;
break;
@@ -251,6 +253,10 @@ static int ice_vsi_alloc_arrays(struct ice_vsi *vsi)
if (!vsi->rx_rings)
goto err_rxrings;
+ /* There is no need to allocate q_vectors for a loopback VSI. */
+ if (vsi->type == ICE_VSI_LB)
+ return 0;
+
/* allocate memory for q_vector pointers */
vsi->q_vectors = devm_kcalloc(&pf->pdev->dev, vsi->num_q_vectors,
sizeof(*vsi->q_vectors), GFP_KERNEL);
@@ -275,6 +281,8 @@ static void ice_vsi_set_num_desc(struct ice_vsi *vsi)
{
switch (vsi->type) {
case ICE_VSI_PF:
+ /* fall through */
+ case ICE_VSI_LB:
vsi->num_rx_desc = ICE_DFLT_NUM_RX_DESC;
vsi->num_tx_desc = ICE_DFLT_NUM_TX_DESC;
break;
@@ -313,10 +321,14 @@ static void ice_vsi_set_num_qs(struct ice_vsi *vsi, u16 vf_id)
vsi->alloc_rxq = vf->num_vf_qs;
/* pf->num_vf_msix includes (VF miscellaneous vector +
* data queue interrupts). Since vsi->num_q_vectors is number
- * of queues vectors, subtract 1 from the original vector
- * count
+ * of queues vectors, subtract 1 (ICE_NONQ_VECS_VF) from the
+ * original vector count
*/
- vsi->num_q_vectors = pf->num_vf_msix - 1;
+ vsi->num_q_vectors = pf->num_vf_msix - ICE_NONQ_VECS_VF;
+ break;
+ case ICE_VSI_LB:
+ vsi->alloc_txq = 1;
+ vsi->alloc_rxq = 1;
break;
default:
dev_warn(&pf->pdev->dev, "Unknown VSI type %d\n", vsi->type);
@@ -516,6 +528,10 @@ ice_vsi_alloc(struct ice_pf *pf, enum ice_vsi_type type, u16 vf_id)
if (ice_vsi_alloc_arrays(vsi))
goto err_rings;
break;
+ case ICE_VSI_LB:
+ if (ice_vsi_alloc_arrays(vsi))
+ goto err_rings;
+ break;
default:
dev_warn(&pf->pdev->dev, "Unknown VSI type %d\n", vsi->type);
goto unlock_pf;
@@ -732,6 +748,8 @@ static void ice_vsi_set_rss_params(struct ice_vsi *vsi)
BIT(cap->rss_table_entry_width));
vsi->rss_lut_type = ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_VSI;
break;
+ case ICE_VSI_LB:
+ break;
default:
dev_warn(&pf->pdev->dev, "Unknown VSI type %d\n",
vsi->type);
@@ -924,6 +942,9 @@ static void ice_set_rss_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi)
lut_type = ICE_AQ_VSI_Q_OPT_RSS_LUT_VSI;
hash_type = ICE_AQ_VSI_Q_OPT_RSS_TPLZ;
break;
+ case ICE_VSI_LB:
+ dev_dbg(&pf->pdev->dev, "Unsupported VSI type %d\n", vsi->type);
+ return;
default:
dev_warn(&pf->pdev->dev, "Unknown VSI type %d\n", vsi->type);
return;
@@ -955,6 +976,8 @@ static int ice_vsi_init(struct ice_vsi *vsi)
ctxt->info = vsi->info;
switch (vsi->type) {
+ case ICE_VSI_LB:
+ /* fall through */
case ICE_VSI_PF:
ctxt->flags = ICE_AQ_VSI_TYPE_PF;
break;
@@ -1145,61 +1168,32 @@ err_out:
static int ice_vsi_setup_vector_base(struct ice_vsi *vsi)
{
struct ice_pf *pf = vsi->back;
- int num_q_vectors = 0;
+ u16 num_q_vectors;
+
+ /* SRIOV doesn't grab irq_tracker entries for each VSI */
+ if (vsi->type == ICE_VSI_VF)
+ return 0;
- if (vsi->sw_base_vector || vsi->hw_base_vector) {
- dev_dbg(&pf->pdev->dev, "VSI %d has non-zero HW base vector %d or SW base vector %d\n",
- vsi->vsi_num, vsi->hw_base_vector, vsi->sw_base_vector);
+ if (vsi->base_vector) {
+ dev_dbg(&pf->pdev->dev, "VSI %d has non-zero base vector %d\n",
+ vsi->vsi_num, vsi->base_vector);
return -EEXIST;
}
if (!test_bit(ICE_FLAG_MSIX_ENA, pf->flags))
return -ENOENT;
- switch (vsi->type) {
- case ICE_VSI_PF:
- num_q_vectors = vsi->num_q_vectors;
- /* reserve slots from OS requested IRQs */
- vsi->sw_base_vector = ice_get_res(pf, pf->sw_irq_tracker,
- num_q_vectors, vsi->idx);
- if (vsi->sw_base_vector < 0) {
- dev_err(&pf->pdev->dev,
- "Failed to get tracking for %d SW vectors for VSI %d, err=%d\n",
- num_q_vectors, vsi->vsi_num,
- vsi->sw_base_vector);
- return -ENOENT;
- }
- pf->num_avail_sw_msix -= num_q_vectors;
-
- /* reserve slots from HW interrupts */
- vsi->hw_base_vector = ice_get_res(pf, pf->hw_irq_tracker,
- num_q_vectors, vsi->idx);
- break;
- case ICE_VSI_VF:
- /* take VF misc vector and data vectors into account */
- num_q_vectors = pf->num_vf_msix;
- /* For VF VSI, reserve slots only from HW interrupts */
- vsi->hw_base_vector = ice_get_res(pf, pf->hw_irq_tracker,
- num_q_vectors, vsi->idx);
- break;
- default:
- dev_warn(&pf->pdev->dev, "Unknown VSI type %d\n", vsi->type);
- break;
- }
-
- if (vsi->hw_base_vector < 0) {
+ num_q_vectors = vsi->num_q_vectors;
+ /* reserve slots from OS requested IRQs */
+ vsi->base_vector = ice_get_res(pf, pf->irq_tracker, num_q_vectors,
+ vsi->idx);
+ if (vsi->base_vector < 0) {
dev_err(&pf->pdev->dev,
- "Failed to get tracking for %d HW vectors for VSI %d, err=%d\n",
- num_q_vectors, vsi->vsi_num, vsi->hw_base_vector);
- if (vsi->type != ICE_VSI_VF) {
- ice_free_res(pf->sw_irq_tracker,
- vsi->sw_base_vector, vsi->idx);
- pf->num_avail_sw_msix += num_q_vectors;
- }
+ "Failed to get tracking for %d vectors for VSI %d, err=%d\n",
+ num_q_vectors, vsi->vsi_num, vsi->base_vector);
return -ENOENT;
}
-
- pf->num_avail_hw_msix -= num_q_vectors;
+ pf->num_avail_sw_msix -= num_q_vectors;
return 0;
}
@@ -1842,8 +1836,73 @@ ice_cfg_itr(struct ice_hw *hw, struct ice_q_vector *q_vector)
}
/**
+ * ice_cfg_txq_interrupt - configure interrupt on Tx queue
+ * @vsi: the VSI being configured
+ * @txq: Tx queue being mapped to MSI-X vector
+ * @msix_idx: MSI-X vector index within the function
+ * @itr_idx: ITR index of the interrupt cause
+ *
+ * Configure interrupt on Tx queue by associating Tx queue to MSI-X vector
+ * within the function space.
+ */
+#ifdef CONFIG_PCI_IOV
+void
+ice_cfg_txq_interrupt(struct ice_vsi *vsi, u16 txq, u16 msix_idx, u16 itr_idx)
+#else
+static void
+ice_cfg_txq_interrupt(struct ice_vsi *vsi, u16 txq, u16 msix_idx, u16 itr_idx)
+#endif /* CONFIG_PCI_IOV */
+{
+ struct ice_pf *pf = vsi->back;
+ struct ice_hw *hw = &pf->hw;
+ u32 val;
+
+ itr_idx = (itr_idx << QINT_TQCTL_ITR_INDX_S) & QINT_TQCTL_ITR_INDX_M;
+
+ val = QINT_TQCTL_CAUSE_ENA_M | itr_idx |
+ ((msix_idx << QINT_TQCTL_MSIX_INDX_S) & QINT_TQCTL_MSIX_INDX_M);
+
+ wr32(hw, QINT_TQCTL(vsi->txq_map[txq]), val);
+}
+
+/**
+ * ice_cfg_rxq_interrupt - configure interrupt on Rx queue
+ * @vsi: the VSI being configured
+ * @rxq: Rx queue being mapped to MSI-X vector
+ * @msix_idx: MSI-X vector index within the function
+ * @itr_idx: ITR index of the interrupt cause
+ *
+ * Configure interrupt on Rx queue by associating Rx queue to MSI-X vector
+ * within the function space.
+ */
+#ifdef CONFIG_PCI_IOV
+void
+ice_cfg_rxq_interrupt(struct ice_vsi *vsi, u16 rxq, u16 msix_idx, u16 itr_idx)
+#else
+static void
+ice_cfg_rxq_interrupt(struct ice_vsi *vsi, u16 rxq, u16 msix_idx, u16 itr_idx)
+#endif /* CONFIG_PCI_IOV */
+{
+ struct ice_pf *pf = vsi->back;
+ struct ice_hw *hw = &pf->hw;
+ u32 val;
+
+ itr_idx = (itr_idx << QINT_RQCTL_ITR_INDX_S) & QINT_RQCTL_ITR_INDX_M;
+
+ val = QINT_RQCTL_CAUSE_ENA_M | itr_idx |
+ ((msix_idx << QINT_RQCTL_MSIX_INDX_S) & QINT_RQCTL_MSIX_INDX_M);
+
+ wr32(hw, QINT_RQCTL(vsi->rxq_map[rxq]), val);
+
+ ice_flush(hw);
+}
+
+/**
* ice_vsi_cfg_msix - MSIX mode Interrupt Config in the HW
* @vsi: the VSI being configured
+ *
+ * This configures MSIX mode interrupts for the PF VSI, and should not be used
+ * for the VF VSI.
*/
void ice_vsi_cfg_msix(struct ice_vsi *vsi)
{
@@ -1873,43 +1932,17 @@ void ice_vsi_cfg_msix(struct ice_vsi *vsi)
* tracked for this PF.
*/
for (q = 0; q < q_vector->num_ring_tx; q++) {
- int itr_idx = (q_vector->tx.itr_idx <<
- QINT_TQCTL_ITR_INDX_S) &
- QINT_TQCTL_ITR_INDX_M;
- u32 val;
-
- if (vsi->type == ICE_VSI_VF)
- val = QINT_TQCTL_CAUSE_ENA_M | itr_idx |
- (((i + 1) << QINT_TQCTL_MSIX_INDX_S) &
- QINT_TQCTL_MSIX_INDX_M);
- else
- val = QINT_TQCTL_CAUSE_ENA_M | itr_idx |
- ((reg_idx << QINT_TQCTL_MSIX_INDX_S) &
- QINT_TQCTL_MSIX_INDX_M);
- wr32(hw, QINT_TQCTL(vsi->txq_map[txq]), val);
+ ice_cfg_txq_interrupt(vsi, txq, reg_idx,
+ q_vector->tx.itr_idx);
txq++;
}
for (q = 0; q < q_vector->num_ring_rx; q++) {
- int itr_idx = (q_vector->rx.itr_idx <<
- QINT_RQCTL_ITR_INDX_S) &
- QINT_RQCTL_ITR_INDX_M;
- u32 val;
-
- if (vsi->type == ICE_VSI_VF)
- val = QINT_RQCTL_CAUSE_ENA_M | itr_idx |
- (((i + 1) << QINT_RQCTL_MSIX_INDX_S) &
- QINT_RQCTL_MSIX_INDX_M);
- else
- val = QINT_RQCTL_CAUSE_ENA_M | itr_idx |
- ((reg_idx << QINT_RQCTL_MSIX_INDX_S) &
- QINT_RQCTL_MSIX_INDX_M);
- wr32(hw, QINT_RQCTL(vsi->rxq_map[rxq]), val);
+ ice_cfg_rxq_interrupt(vsi, rxq, reg_idx,
+ q_vector->rx.itr_idx);
rxq++;
}
}
-
- ice_flush(hw);
}
/**
@@ -2024,6 +2057,19 @@ int ice_vsi_stop_rx_rings(struct ice_vsi *vsi)
}
/**
+ * ice_trigger_sw_intr - trigger a software interrupt
+ * @hw: pointer to the HW structure
+ * @q_vector: interrupt vector to trigger the software interrupt for
+ */
+void ice_trigger_sw_intr(struct ice_hw *hw, struct ice_q_vector *q_vector)
+{
+ wr32(hw, GLINT_DYN_CTL(q_vector->reg_idx),
+ (ICE_ITR_NONE << GLINT_DYN_CTL_ITR_INDX_S) |
+ GLINT_DYN_CTL_SWINT_TRIG_M |
+ GLINT_DYN_CTL_INTENA_M);
+}
+
+/**
* ice_vsi_stop_tx_rings - Disable Tx rings
* @vsi: the VSI being configured
* @rst_src: reset source
@@ -2070,8 +2116,9 @@ ice_vsi_stop_tx_rings(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src,
break;
for (i = 0; i < vsi->tc_cfg.tc_info[tc].qcount_tx; i++) {
- if (!rings || !rings[q_idx] ||
- !rings[q_idx]->q_vector) {
+ struct ice_q_vector *q_vector;
+
+ if (!rings || !rings[q_idx]) {
err = -EINVAL;
goto err_out;
}
@@ -2091,9 +2138,10 @@ ice_vsi_stop_tx_rings(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src,
/* trigger a software interrupt for the vector
* associated to the queue to schedule NAPI handler
*/
- wr32(hw, GLINT_DYN_CTL(rings[i]->q_vector->reg_idx),
- GLINT_DYN_CTL_SWINT_TRIG_M |
- GLINT_DYN_CTL_INTENA_MSK_M);
+ q_vector = rings[i]->q_vector;
+ if (q_vector)
+ ice_trigger_sw_intr(hw, q_vector);
+
q_idx++;
}
status = ice_dis_vsi_txq(vsi->port_info, vsi->idx, tc,
@@ -2234,7 +2282,14 @@ ice_vsi_set_q_vectors_reg_idx(struct ice_vsi *vsi)
goto clear_reg_idx;
}
- q_vector->reg_idx = q_vector->v_idx + vsi->hw_base_vector;
+ if (vsi->type == ICE_VSI_VF) {
+ struct ice_vf *vf = &vsi->back->vf[vsi->vf_id];
+
+ q_vector->reg_idx = ice_calc_vf_reg_idx(vf, q_vector);
+ } else {
+ q_vector->reg_idx =
+ q_vector->v_idx + vsi->base_vector;
+ }
}
return 0;
@@ -2291,6 +2346,54 @@ ice_vsi_add_rem_eth_mac(struct ice_vsi *vsi, bool add_rule)
}
/**
+ * ice_cfg_sw_lldp - Config switch rules for LLDP packet handling
+ * @vsi: the VSI being configured
+ * @tx: bool to determine Tx or Rx rule
+ * @create: bool to determine create or remove Rule
+ */
+void ice_cfg_sw_lldp(struct ice_vsi *vsi, bool tx, bool create)
+{
+ struct ice_fltr_list_entry *list;
+ struct ice_pf *pf = vsi->back;
+ LIST_HEAD(tmp_add_list);
+ enum ice_status status;
+
+ list = devm_kzalloc(&pf->pdev->dev, sizeof(*list), GFP_KERNEL);
+ if (!list)
+ return;
+
+ list->fltr_info.lkup_type = ICE_SW_LKUP_ETHERTYPE;
+ list->fltr_info.vsi_handle = vsi->idx;
+ list->fltr_info.l_data.ethertype_mac.ethertype = ETH_P_LLDP;
+
+ if (tx) {
+ list->fltr_info.fltr_act = ICE_DROP_PACKET;
+ list->fltr_info.flag = ICE_FLTR_TX;
+ list->fltr_info.src_id = ICE_SRC_ID_VSI;
+ } else {
+ list->fltr_info.fltr_act = ICE_FWD_TO_VSI;
+ list->fltr_info.flag = ICE_FLTR_RX;
+ list->fltr_info.src_id = ICE_SRC_ID_LPORT;
+ }
+
+ INIT_LIST_HEAD(&list->list_entry);
+ list_add(&list->list_entry, &tmp_add_list);
+
+ if (create)
+ status = ice_add_eth_mac(&pf->hw, &tmp_add_list);
+ else
+ status = ice_remove_eth_mac(&pf->hw, &tmp_add_list);
+
+ if (status)
+ dev_err(&pf->pdev->dev,
+ "Fail %s %s LLDP rule on VSI %i error: %d\n",
+ create ? "adding" : "removing", tx ? "TX" : "RX",
+ vsi->vsi_num, status);
+
+ ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list);
+}
+
+/**
* ice_vsi_setup - Set up a VSI by a given type
* @pf: board private structure
* @pi: pointer to the port_info instance
@@ -2310,6 +2413,7 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,
{
u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 };
struct device *dev = &pf->pdev->dev;
+ enum ice_status status;
struct ice_vsi *vsi;
int ret, i;
@@ -2389,23 +2493,24 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,
if (ret)
goto unroll_alloc_q_vector;
- /* Setup Vector base only during VF init phase or when VF asks
- * for more vectors than assigned number. In all other cases,
- * assign hw_base_vector to the value given earlier.
- */
- if (test_bit(ICE_VF_STATE_CFG_INTR, pf->vf[vf_id].vf_states)) {
- ret = ice_vsi_setup_vector_base(vsi);
- if (ret)
- goto unroll_vector_base;
- } else {
- vsi->hw_base_vector = pf->vf[vf_id].first_vector_idx;
- }
ret = ice_vsi_set_q_vectors_reg_idx(vsi);
if (ret)
goto unroll_vector_base;
pf->q_left_tx -= vsi->alloc_txq;
pf->q_left_rx -= vsi->alloc_rxq;
+
+ /* Do not exit if configuring RSS had an issue, at least
+ * receive traffic on first queue. Hence no need to capture
+ * return value
+ */
+ if (test_bit(ICE_FLAG_RSS_ENA, pf->flags))
+ ice_vsi_cfg_rss_lut_key(vsi);
+ break;
+ case ICE_VSI_LB:
+ ret = ice_vsi_alloc_rings(vsi);
+ if (ret)
+ goto unroll_vsi_init;
break;
default:
/* clean up the resources and exit */
@@ -2416,12 +2521,12 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,
for (i = 0; i < vsi->tc_cfg.numtc; i++)
max_txqs[i] = pf->num_lan_tx;
- ret = ice_cfg_vsi_lan(vsi->port_info, vsi->idx, vsi->tc_cfg.ena_tc,
- max_txqs);
- if (ret) {
+ status = ice_cfg_vsi_lan(vsi->port_info, vsi->idx, vsi->tc_cfg.ena_tc,
+ max_txqs);
+ if (status) {
dev_err(&pf->pdev->dev,
"VSI %d failed lan queue config, error %d\n",
- vsi->vsi_num, ret);
+ vsi->vsi_num, status);
goto unroll_vector_base;
}
@@ -2430,19 +2535,28 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,
* out PAUSE or PFC frames. If enabled, FW can still send FC frames.
* The rule is added once for PF VSI in order to create appropriate
* recipe, since VSI/VSI list is ignored with drop action...
+ * Also add rules to handle LLDP Tx and Rx packets. Tx LLDP packets
+ * need to be dropped so that VFs cannot send LLDP packets to reconfig
+ * DCB settings in the HW. Also, if the FW DCBX engine is not running
+ * then Rx LLDP packets need to be redirected up the stack.
*/
- if (vsi->type == ICE_VSI_PF)
+ if (vsi->type == ICE_VSI_PF) {
ice_vsi_add_rem_eth_mac(vsi, true);
+ /* Tx LLDP packets */
+ ice_cfg_sw_lldp(vsi, true, true);
+
+ /* Rx LLDP packets */
+ if (!test_bit(ICE_FLAG_ENABLE_FW_LLDP, pf->flags))
+ ice_cfg_sw_lldp(vsi, false, true);
+ }
+
return vsi;
unroll_vector_base:
/* reclaim SW interrupts back to the common pool */
- ice_free_res(pf->sw_irq_tracker, vsi->sw_base_vector, vsi->idx);
+ ice_free_res(pf->irq_tracker, vsi->base_vector, vsi->idx);
pf->num_avail_sw_msix += vsi->num_q_vectors;
- /* reclaim HW interrupt back to the common pool */
- ice_free_res(pf->hw_irq_tracker, vsi->hw_base_vector, vsi->idx);
- pf->num_avail_hw_msix += vsi->num_q_vectors;
unroll_alloc_q_vector:
ice_vsi_free_q_vectors(vsi);
unroll_vsi_init:
@@ -2463,17 +2577,17 @@ unroll_get_qs:
static void ice_vsi_release_msix(struct ice_vsi *vsi)
{
struct ice_pf *pf = vsi->back;
- u16 vector = vsi->hw_base_vector;
struct ice_hw *hw = &pf->hw;
u32 txq = 0;
u32 rxq = 0;
int i, q;
- for (i = 0; i < vsi->num_q_vectors; i++, vector++) {
+ for (i = 0; i < vsi->num_q_vectors; i++) {
struct ice_q_vector *q_vector = vsi->q_vectors[i];
+ u16 reg_idx = q_vector->reg_idx;
- wr32(hw, GLINT_ITR(ICE_IDX_ITR0, vector), 0);
- wr32(hw, GLINT_ITR(ICE_IDX_ITR1, vector), 0);
+ wr32(hw, GLINT_ITR(ICE_IDX_ITR0, reg_idx), 0);
+ wr32(hw, GLINT_ITR(ICE_IDX_ITR1, reg_idx), 0);
for (q = 0; q < q_vector->num_ring_tx; q++) {
wr32(hw, QINT_TQCTL(vsi->txq_map[txq]), 0);
txq++;
@@ -2495,7 +2609,7 @@ static void ice_vsi_release_msix(struct ice_vsi *vsi)
void ice_vsi_free_irq(struct ice_vsi *vsi)
{
struct ice_pf *pf = vsi->back;
- int base = vsi->sw_base_vector;
+ int base = vsi->base_vector;
if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) {
int i;
@@ -2591,11 +2705,11 @@ int ice_free_res(struct ice_res_tracker *res, u16 index, u16 id)
int count = 0;
int i;
- if (!res || index >= res->num_entries)
+ if (!res || index >= res->end)
return -EINVAL;
id |= ICE_RES_VALID_BIT;
- for (i = index; i < res->num_entries && res->list[i] == id; i++) {
+ for (i = index; i < res->end && res->list[i] == id; i++) {
res->list[i] = 0;
count++;
}
@@ -2613,10 +2727,9 @@ int ice_free_res(struct ice_res_tracker *res, u16 index, u16 id)
*/
static int ice_search_res(struct ice_res_tracker *res, u16 needed, u16 id)
{
- int start = res->search_hint;
- int end = start;
+ int start = 0, end = 0;
- if ((start + needed) > res->num_entries)
+ if (needed > res->end)
return -ENOMEM;
id |= ICE_RES_VALID_BIT;
@@ -2625,7 +2738,7 @@ static int ice_search_res(struct ice_res_tracker *res, u16 needed, u16 id)
/* skip already allocated entries */
if (res->list[end++] & ICE_RES_VALID_BIT) {
start = end;
- if ((start + needed) > res->num_entries)
+ if ((start + needed) > res->end)
break;
}
@@ -2636,13 +2749,9 @@ static int ice_search_res(struct ice_res_tracker *res, u16 needed, u16 id)
while (i != end)
res->list[i++] = id;
- if (end == res->num_entries)
- end = 0;
-
- res->search_hint = end;
return start;
}
- } while (1);
+ } while (end < res->end);
return -ENOMEM;
}
@@ -2654,16 +2763,11 @@ static int ice_search_res(struct ice_res_tracker *res, u16 needed, u16 id)
* @needed: size of the block needed
* @id: identifier to track owner
*
- * Returns the base item index of the block, or -ENOMEM for error
- * The search_hint trick and lack of advanced fit-finding only works
- * because we're highly likely to have all the same sized requests.
- * Linear search time and any fragmentation should be minimal.
+ * Returns the base item index of the block, or negative for error
*/
int
ice_get_res(struct ice_pf *pf, struct ice_res_tracker *res, u16 needed, u16 id)
{
- int ret;
-
if (!res || !pf)
return -EINVAL;
@@ -2674,16 +2778,7 @@ ice_get_res(struct ice_pf *pf, struct ice_res_tracker *res, u16 needed, u16 id)
return -EINVAL;
}
- /* search based on search_hint */
- ret = ice_search_res(res, needed, id);
-
- if (ret < 0) {
- /* previous search failed. Reset search hint and try again */
- res->search_hint = 0;
- ret = ice_search_res(res, needed, id);
- }
-
- return ret;
+ return ice_search_res(res, needed, id);
}
/**
@@ -2692,7 +2787,7 @@ ice_get_res(struct ice_pf *pf, struct ice_res_tracker *res, u16 needed, u16 id)
*/
void ice_vsi_dis_irq(struct ice_vsi *vsi)
{
- int base = vsi->sw_base_vector;
+ int base = vsi->base_vector;
struct ice_pf *pf = vsi->back;
struct ice_hw *hw = &pf->hw;
u32 val;
@@ -2738,6 +2833,21 @@ 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
*
@@ -2745,60 +2855,61 @@ void ice_vsi_dis_irq(struct ice_vsi *vsi)
*/
int ice_vsi_release(struct ice_vsi *vsi)
{
- struct ice_vf *vf = NULL;
struct ice_pf *pf;
if (!vsi->back)
return -ENODEV;
pf = vsi->back;
- if (vsi->type == ICE_VSI_VF)
- vf = &pf->vf[vsi->vf_id];
- /* do not unregister and free netdevs while driver is in the reset
- * recovery pending state. Since reset/rebuild happens through PF
- * service task workqueue, its not a good idea to unregister netdev
- * that is associated to the PF that is running the work queue items
- * currently. This is done to avoid check_flush_dependency() warning
- * on this wq
+ /* do not unregister while driver is in the reset recovery pending
+ * state. Since reset/rebuild happens through PF service task workqueue,
+ * it's not a good idea to unregister netdev that is associated to the
+ * PF that is running the work queue items currently. This is done to
+ * avoid check_flush_dependency() warning on this wq
*/
- if (vsi->netdev && !ice_is_reset_in_progress(pf->state)) {
- ice_napi_del(vsi);
+ if (vsi->netdev && !ice_is_reset_in_progress(pf->state))
unregister_netdev(vsi->netdev);
- free_netdev(vsi->netdev);
- vsi->netdev = NULL;
- }
if (test_bit(ICE_FLAG_RSS_ENA, pf->flags))
ice_rss_clean(vsi);
/* Disable VSI and free resources */
- ice_vsi_dis_irq(vsi);
+ if (vsi->type != ICE_VSI_LB)
+ ice_vsi_dis_irq(vsi);
ice_vsi_close(vsi);
- /* reclaim interrupt vectors back to PF */
+ /* SR-IOV determines needed MSIX resources all at once instead of per
+ * VSI since when VFs are spawned we know how many VFs there are and how
+ * many interrupts each VF needs. SR-IOV MSIX resources are also
+ * cleared in the same manner.
+ */
if (vsi->type != ICE_VSI_VF) {
/* reclaim SW interrupts back to the common pool */
- ice_free_res(pf->sw_irq_tracker, vsi->sw_base_vector, vsi->idx);
+ ice_free_res(pf->irq_tracker, vsi->base_vector, vsi->idx);
pf->num_avail_sw_msix += vsi->num_q_vectors;
- /* reclaim HW interrupts back to the common pool */
- ice_free_res(pf->hw_irq_tracker, vsi->hw_base_vector, vsi->idx);
- pf->num_avail_hw_msix += vsi->num_q_vectors;
- } else if (test_bit(ICE_VF_STATE_CFG_INTR, vf->vf_states)) {
- /* Reclaim VF resources back only while freeing all VFs or
- * vector reassignment is requested
- */
- ice_free_res(pf->hw_irq_tracker, vf->first_vector_idx,
- vsi->idx);
- pf->num_avail_hw_msix += pf->num_vf_msix;
}
- if (vsi->type == ICE_VSI_PF)
+ if (vsi->type == ICE_VSI_PF) {
ice_vsi_add_rem_eth_mac(vsi, false);
+ ice_cfg_sw_lldp(vsi, true, false);
+ /* The Rx rule will only exist to remove if the LLDP FW
+ * engine is currently stopped
+ */
+ if (!test_bit(ICE_FLAG_ENABLE_FW_LLDP, pf->flags))
+ ice_cfg_sw_lldp(vsi, false, false);
+ }
ice_remove_vsi_fltr(&pf->hw, vsi->idx);
ice_rm_vsi_lan_cfg(vsi->port_info, vsi->idx);
ice_vsi_delete(vsi);
ice_vsi_free_q_vectors(vsi);
+
+ /* make sure unregister_netdev() was called by checking __ICE_DOWN */
+ if (vsi->netdev && test_bit(__ICE_DOWN, vsi->state)) {
+ free_netdev(vsi->netdev);
+ vsi->netdev = NULL;
+ }
+
ice_vsi_clear_rings(vsi);
ice_vsi_put_qs(vsi);
@@ -2825,6 +2936,7 @@ int ice_vsi_rebuild(struct ice_vsi *vsi)
{
u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 };
struct ice_vf *vf = NULL;
+ enum ice_status status;
struct ice_pf *pf;
int ret, i;
@@ -2838,24 +2950,17 @@ int ice_vsi_rebuild(struct ice_vsi *vsi)
ice_rm_vsi_lan_cfg(vsi->port_info, vsi->idx);
ice_vsi_free_q_vectors(vsi);
+ /* SR-IOV determines needed MSIX resources all at once instead of per
+ * VSI since when VFs are spawned we know how many VFs there are and how
+ * many interrupts each VF needs. SR-IOV MSIX resources are also
+ * cleared in the same manner.
+ */
if (vsi->type != ICE_VSI_VF) {
/* reclaim SW interrupts back to the common pool */
- ice_free_res(pf->sw_irq_tracker, vsi->sw_base_vector, vsi->idx);
+ ice_free_res(pf->irq_tracker, vsi->base_vector, vsi->idx);
pf->num_avail_sw_msix += vsi->num_q_vectors;
- vsi->sw_base_vector = 0;
- /* reclaim HW interrupts back to the common pool */
- ice_free_res(pf->hw_irq_tracker, vsi->hw_base_vector,
- vsi->idx);
- pf->num_avail_hw_msix += vsi->num_q_vectors;
- } else {
- /* Reclaim VF resources back to the common pool for reset and
- * and rebuild, with vector reassignment
- */
- ice_free_res(pf->hw_irq_tracker, vf->first_vector_idx,
- vsi->idx);
- pf->num_avail_hw_msix += pf->num_vf_msix;
+ vsi->base_vector = 0;
}
- vsi->hw_base_vector = 0;
ice_vsi_clear_rings(vsi);
ice_vsi_free_arrays(vsi);
@@ -2881,10 +2986,6 @@ int ice_vsi_rebuild(struct ice_vsi *vsi)
if (ret)
goto err_rings;
- ret = ice_vsi_setup_vector_base(vsi);
- if (ret)
- goto err_vectors;
-
ret = ice_vsi_set_q_vectors_reg_idx(vsi);
if (ret)
goto err_vectors;
@@ -2929,12 +3030,12 @@ int ice_vsi_rebuild(struct ice_vsi *vsi)
for (i = 0; i < vsi->tc_cfg.numtc; i++)
max_txqs[i] = pf->num_lan_tx;
- ret = ice_cfg_vsi_lan(vsi->port_info, vsi->idx, vsi->tc_cfg.ena_tc,
- max_txqs);
- if (ret) {
+ status = ice_cfg_vsi_lan(vsi->port_info, vsi->idx, vsi->tc_cfg.ena_tc,
+ max_txqs);
+ if (status) {
dev_err(&pf->pdev->dev,
"VSI %d failed lan queue config, error %d\n",
- vsi->vsi_num, ret);
+ vsi->vsi_num, status);
goto err_vectors;
}
return 0;
@@ -2956,7 +3057,7 @@ err_vsi:
/**
* ice_is_reset_in_progress - check for a reset in progress
- * @state: pf state field
+ * @state: PF state field
*/
bool ice_is_reset_in_progress(unsigned long *state)
{
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h
index a91d3553cc89..6e43ef03bfc3 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.h
+++ b/drivers/net/ethernet/intel/ice/ice_lib.h
@@ -19,6 +19,14 @@ int ice_vsi_cfg_lan_txqs(struct ice_vsi *vsi);
void ice_vsi_cfg_msix(struct ice_vsi *vsi);
+#ifdef CONFIG_PCI_IOV
+void
+ice_cfg_txq_interrupt(struct ice_vsi *vsi, u16 txq, u16 msix_idx, u16 itr_idx);
+
+void
+ice_cfg_rxq_interrupt(struct ice_vsi *vsi, u16 rxq, u16 msix_idx, u16 itr_idx);
+#endif /* CONFIG_PCI_IOV */
+
int ice_vsi_add_vlan(struct ice_vsi *vsi, u16 vid);
int ice_vsi_kill_vlan(struct ice_vsi *vsi, u16 vid);
@@ -37,6 +45,8 @@ ice_vsi_stop_lan_tx_rings(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src,
int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena, bool vlan_promisc);
+void ice_cfg_sw_lldp(struct ice_vsi *vsi, bool tx, bool create);
+
void ice_vsi_delete(struct ice_vsi *vsi);
int ice_vsi_clear(struct ice_vsi *vsi);
@@ -49,6 +59,8 @@ struct ice_vsi *
ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,
enum ice_vsi_type type, u16 vf_id);
+void ice_napi_del(struct ice_vsi *vsi);
+
int ice_vsi_release(struct ice_vsi *vsi);
void ice_vsi_close(struct ice_vsi *vsi);
@@ -64,6 +76,8 @@ bool ice_is_reset_in_progress(unsigned long *state);
void ice_vsi_free_q_vectors(struct ice_vsi *vsi);
+void ice_trigger_sw_intr(struct ice_hw *hw, struct ice_q_vector *q_vector);
+
void ice_vsi_put_qs(struct ice_vsi *vsi);
#ifdef CONFIG_DCB
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index 7843abf4d44d..63db08d9bafa 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -61,9 +61,10 @@ static u32 ice_get_tx_pending(struct ice_ring *ring)
static void ice_check_for_hang_subtask(struct ice_pf *pf)
{
struct ice_vsi *vsi = NULL;
+ struct ice_hw *hw;
unsigned int i;
- u32 v, v_idx;
int packets;
+ u32 v;
ice_for_each_vsi(pf, v)
if (pf->vsi[v] && pf->vsi[v]->type == ICE_VSI_PF) {
@@ -77,12 +78,12 @@ static void ice_check_for_hang_subtask(struct ice_pf *pf)
if (!(vsi->netdev && netif_carrier_ok(vsi->netdev)))
return;
+ hw = &vsi->back->hw;
+
for (i = 0; i < vsi->num_txq; i++) {
struct ice_ring *tx_ring = vsi->tx_rings[i];
if (tx_ring && tx_ring->desc) {
- int itr = ICE_ITR_NONE;
-
/* If packet counter has not changed the queue is
* likely stalled, so force an interrupt for this
* queue.
@@ -93,12 +94,7 @@ static void ice_check_for_hang_subtask(struct ice_pf *pf)
packets = tx_ring->stats.pkts & INT_MAX;
if (tx_ring->tx_stats.prev_pkt == packets) {
/* Trigger sw interrupt to revive the queue */
- v_idx = tx_ring->q_vector->v_idx;
- wr32(&vsi->back->hw,
- GLINT_DYN_CTL(vsi->hw_base_vector + v_idx),
- (itr << GLINT_DYN_CTL_ITR_INDX_S) |
- GLINT_DYN_CTL_SWINT_TRIG_M |
- GLINT_DYN_CTL_INTENA_MSK_M);
+ ice_trigger_sw_intr(hw, tx_ring->q_vector);
continue;
}
@@ -113,6 +109,67 @@ static void ice_check_for_hang_subtask(struct ice_pf *pf)
}
/**
+ * ice_init_mac_fltr - Set initial MAC filters
+ * @pf: board private structure
+ *
+ * Set initial set of MAC filters for PF VSI; configure filters for permanent
+ * address and broadcast address. If an error is encountered, netdevice will be
+ * unregistered.
+ */
+static int ice_init_mac_fltr(struct ice_pf *pf)
+{
+ LIST_HEAD(tmp_add_list);
+ u8 broadcast[ETH_ALEN];
+ struct ice_vsi *vsi;
+ int status;
+
+ vsi = ice_find_vsi_by_type(pf, ICE_VSI_PF);
+ if (!vsi)
+ return -EINVAL;
+
+ /* To add a MAC filter, first add the MAC to a list and then
+ * pass the list to ice_add_mac.
+ */
+
+ /* Add a unicast MAC filter so the VSI can get its packets */
+ status = ice_add_mac_to_list(vsi, &tmp_add_list,
+ vsi->port_info->mac.perm_addr);
+ if (status)
+ goto unregister;
+
+ /* VSI needs to receive broadcast traffic, so add the broadcast
+ * MAC address to the list as well.
+ */
+ eth_broadcast_addr(broadcast);
+ status = ice_add_mac_to_list(vsi, &tmp_add_list, broadcast);
+ if (status)
+ goto free_mac_list;
+
+ /* Program MAC filters for entries in tmp_add_list */
+ status = ice_add_mac(&pf->hw, &tmp_add_list);
+ if (status)
+ status = -ENOMEM;
+
+free_mac_list:
+ ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list);
+
+unregister:
+ /* We aren't useful with no MAC filters, so unregister if we
+ * had an error
+ */
+ if (status && vsi->netdev->reg_state == NETREG_REGISTERED) {
+ dev_err(&pf->pdev->dev,
+ "Could not add MAC filters error %d. Unregistering device\n",
+ status);
+ unregister_netdev(vsi->netdev);
+ free_netdev(vsi->netdev);
+ vsi->netdev = NULL;
+ }
+
+ return status;
+}
+
+/**
* ice_add_mac_to_sync_list - creates list of MAC addresses to be synced
* @netdev: the net device on which the sync is happening
* @addr: MAC address to sync
@@ -567,7 +624,11 @@ static void ice_reset_subtask(struct ice_pf *pf)
*/
void ice_print_link_msg(struct ice_vsi *vsi, bool isup)
{
+ struct ice_aqc_get_phy_caps_data *caps;
+ enum ice_status status;
+ const char *fec_req;
const char *speed;
+ const char *fec;
const char *fc;
if (!vsi)
@@ -584,6 +645,12 @@ void ice_print_link_msg(struct ice_vsi *vsi, bool isup)
}
switch (vsi->port_info->phy.link_info.link_speed) {
+ case ICE_AQ_LINK_SPEED_100GB:
+ speed = "100 G";
+ break;
+ case ICE_AQ_LINK_SPEED_50GB:
+ speed = "50 G";
+ break;
case ICE_AQ_LINK_SPEED_40GB:
speed = "40 G";
break;
@@ -615,13 +682,13 @@ void ice_print_link_msg(struct ice_vsi *vsi, bool isup)
switch (vsi->port_info->fc.current_mode) {
case ICE_FC_FULL:
- fc = "RX/TX";
+ fc = "Rx/Tx";
break;
case ICE_FC_TX_PAUSE:
- fc = "TX";
+ fc = "Tx";
break;
case ICE_FC_RX_PAUSE:
- fc = "RX";
+ fc = "Rx";
break;
case ICE_FC_NONE:
fc = "None";
@@ -631,8 +698,47 @@ void ice_print_link_msg(struct ice_vsi *vsi, bool isup)
break;
}
- netdev_info(vsi->netdev, "NIC Link is up %sbps, Flow Control: %s\n",
- speed, fc);
+ /* Get FEC mode based on negotiated link info */
+ switch (vsi->port_info->phy.link_info.fec_info) {
+ case ICE_AQ_LINK_25G_RS_528_FEC_EN:
+ /* fall through */
+ case ICE_AQ_LINK_25G_RS_544_FEC_EN:
+ fec = "RS-FEC";
+ break;
+ case ICE_AQ_LINK_25G_KR_FEC_EN:
+ fec = "FC-FEC/BASE-R";
+ break;
+ default:
+ fec = "NONE";
+ break;
+ }
+
+ /* Get FEC mode requested based on PHY caps last SW configuration */
+ caps = devm_kzalloc(&vsi->back->pdev->dev, sizeof(*caps), GFP_KERNEL);
+ if (!caps) {
+ fec_req = "Unknown";
+ goto done;
+ }
+
+ status = ice_aq_get_phy_caps(vsi->port_info, false,
+ ICE_AQC_REPORT_SW_CFG, caps, NULL);
+ if (status)
+ netdev_info(vsi->netdev, "Get phy capability failed.\n");
+
+ if (caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_528_REQ ||
+ caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_544_REQ)
+ fec_req = "RS-FEC";
+ else if (caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_REQ ||
+ caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_REQ)
+ fec_req = "FC-FEC/BASE-R";
+ else
+ fec_req = "NONE";
+
+ devm_kfree(&vsi->back->pdev->dev, caps);
+
+done:
+ netdev_info(vsi->netdev, "NIC Link is up %sbps, Requested FEC: %s, FEC: %s, Flow Control: %s\n",
+ speed, fec_req, fec, fc);
}
/**
@@ -664,7 +770,7 @@ static void ice_vsi_link_event(struct ice_vsi *vsi, bool link_up)
/**
* ice_link_event - process the link event
- * @pf: pf that the link event is associated with
+ * @pf: PF that the link event is associated with
* @pi: port_info for the port that the link event is associated with
* @link_up: true if the physical link is up and false if it is down
* @link_speed: current link speed received from the link event
@@ -774,7 +880,7 @@ static int ice_init_link_events(struct ice_port_info *pi)
/**
* ice_handle_link_event - handle link event via ARQ
- * @pf: pf that the link event is associated with
+ * @pf: PF that the link event is associated with
* @event: event structure containing link status info
*/
static int
@@ -1161,16 +1267,16 @@ static void ice_handle_mdd_event(struct ice_pf *pf)
}
}
- /* see if one of the VFs needs to be reset */
- for (i = 0; i < pf->num_alloc_vfs && mdd_detected; i++) {
+ /* check to see if one of the VFs caused the MDD */
+ for (i = 0; i < pf->num_alloc_vfs; i++) {
struct ice_vf *vf = &pf->vf[i];
- mdd_detected = false;
+ bool vf_mdd_detected = false;
reg = rd32(hw, VP_MDET_TX_PQM(i));
if (reg & VP_MDET_TX_PQM_VALID_M) {
wr32(hw, VP_MDET_TX_PQM(i), 0xFFFF);
- mdd_detected = true;
+ vf_mdd_detected = true;
dev_info(&pf->pdev->dev, "TX driver issue detected on VF %d\n",
i);
}
@@ -1178,7 +1284,7 @@ static void ice_handle_mdd_event(struct ice_pf *pf)
reg = rd32(hw, VP_MDET_TX_TCLAN(i));
if (reg & VP_MDET_TX_TCLAN_VALID_M) {
wr32(hw, VP_MDET_TX_TCLAN(i), 0xFFFF);
- mdd_detected = true;
+ vf_mdd_detected = true;
dev_info(&pf->pdev->dev, "TX driver issue detected on VF %d\n",
i);
}
@@ -1186,7 +1292,7 @@ static void ice_handle_mdd_event(struct ice_pf *pf)
reg = rd32(hw, VP_MDET_TX_TDPU(i));
if (reg & VP_MDET_TX_TDPU_VALID_M) {
wr32(hw, VP_MDET_TX_TDPU(i), 0xFFFF);
- mdd_detected = true;
+ vf_mdd_detected = true;
dev_info(&pf->pdev->dev, "TX driver issue detected on VF %d\n",
i);
}
@@ -1194,19 +1300,18 @@ static void ice_handle_mdd_event(struct ice_pf *pf)
reg = rd32(hw, VP_MDET_RX(i));
if (reg & VP_MDET_RX_VALID_M) {
wr32(hw, VP_MDET_RX(i), 0xFFFF);
- mdd_detected = true;
+ vf_mdd_detected = true;
dev_info(&pf->pdev->dev, "RX driver issue detected on VF %d\n",
i);
}
- if (mdd_detected) {
+ if (vf_mdd_detected) {
vf->num_mdd_events++;
- dev_info(&pf->pdev->dev,
- "Use PF Control I/F to re-enable the VF\n");
- set_bit(ICE_VF_STATE_DIS, vf->vf_states);
+ if (vf->num_mdd_events > 1)
+ dev_info(&pf->pdev->dev, "VF %d has had %llu MDD events since last boot\n",
+ i, vf->num_mdd_events);
}
}
-
}
/**
@@ -1327,7 +1432,7 @@ static int ice_vsi_req_irq_msix(struct ice_vsi *vsi, char *basename)
{
int q_vectors = vsi->num_q_vectors;
struct ice_pf *pf = vsi->back;
- int base = vsi->sw_base_vector;
+ int base = vsi->base_vector;
int rx_int_idx = 0;
int tx_int_idx = 0;
int vector, err;
@@ -1408,7 +1513,7 @@ static void ice_ena_misc_vector(struct ice_pf *pf)
wr32(hw, PFINT_OICR_ENA, val);
/* SW_ITR_IDX = 0, but don't change INTENA */
- wr32(hw, GLINT_DYN_CTL(pf->hw_oicr_idx),
+ wr32(hw, GLINT_DYN_CTL(pf->oicr_idx),
GLINT_DYN_CTL_SW_ITR_INDX_M | GLINT_DYN_CTL_INTENA_MSK_M);
}
@@ -1430,6 +1535,11 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
oicr = rd32(hw, PFINT_OICR);
ena_mask = rd32(hw, PFINT_OICR_ENA);
+ if (oicr & PFINT_OICR_SWINT_M) {
+ ena_mask &= ~PFINT_OICR_SWINT_M;
+ pf->sw_int_count++;
+ }
+
if (oicr & PFINT_OICR_MAL_DETECT_M) {
ena_mask &= ~PFINT_OICR_MAL_DETECT_M;
set_bit(__ICE_MDD_EVENT_PENDING, pf->state);
@@ -1556,15 +1666,13 @@ static void ice_free_irq_msix_misc(struct ice_pf *pf)
ice_flush(hw);
if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags) && pf->msix_entries) {
- synchronize_irq(pf->msix_entries[pf->sw_oicr_idx].vector);
+ synchronize_irq(pf->msix_entries[pf->oicr_idx].vector);
devm_free_irq(&pf->pdev->dev,
- pf->msix_entries[pf->sw_oicr_idx].vector, pf);
+ pf->msix_entries[pf->oicr_idx].vector, pf);
}
pf->num_avail_sw_msix += 1;
- ice_free_res(pf->sw_irq_tracker, pf->sw_oicr_idx, ICE_RES_MISC_VEC_ID);
- pf->num_avail_hw_msix += 1;
- ice_free_res(pf->hw_irq_tracker, pf->hw_oicr_idx, ICE_RES_MISC_VEC_ID);
+ ice_free_res(pf->irq_tracker, pf->oicr_idx, ICE_RES_MISC_VEC_ID);
}
/**
@@ -1618,43 +1726,31 @@ static int ice_req_irq_msix_misc(struct ice_pf *pf)
if (ice_is_reset_in_progress(pf->state))
goto skip_req_irq;
- /* reserve one vector in sw_irq_tracker for misc interrupts */
- oicr_idx = ice_get_res(pf, pf->sw_irq_tracker, 1, ICE_RES_MISC_VEC_ID);
+ /* reserve one vector in irq_tracker for misc interrupts */
+ oicr_idx = ice_get_res(pf, pf->irq_tracker, 1, ICE_RES_MISC_VEC_ID);
if (oicr_idx < 0)
return oicr_idx;
pf->num_avail_sw_msix -= 1;
- pf->sw_oicr_idx = oicr_idx;
-
- /* reserve one vector in hw_irq_tracker for misc interrupts */
- oicr_idx = ice_get_res(pf, pf->hw_irq_tracker, 1, ICE_RES_MISC_VEC_ID);
- if (oicr_idx < 0) {
- ice_free_res(pf->sw_irq_tracker, 1, ICE_RES_MISC_VEC_ID);
- pf->num_avail_sw_msix += 1;
- return oicr_idx;
- }
- pf->num_avail_hw_msix -= 1;
- pf->hw_oicr_idx = oicr_idx;
+ pf->oicr_idx = oicr_idx;
err = devm_request_irq(&pf->pdev->dev,
- pf->msix_entries[pf->sw_oicr_idx].vector,
+ pf->msix_entries[pf->oicr_idx].vector,
ice_misc_intr, 0, pf->int_name, pf);
if (err) {
dev_err(&pf->pdev->dev,
"devm_request_irq for %s failed: %d\n",
pf->int_name, err);
- ice_free_res(pf->sw_irq_tracker, 1, ICE_RES_MISC_VEC_ID);
+ ice_free_res(pf->irq_tracker, 1, ICE_RES_MISC_VEC_ID);
pf->num_avail_sw_msix += 1;
- ice_free_res(pf->hw_irq_tracker, 1, ICE_RES_MISC_VEC_ID);
- pf->num_avail_hw_msix += 1;
return err;
}
skip_req_irq:
ice_ena_misc_vector(pf);
- ice_ena_ctrlq_interrupts(hw, pf->hw_oicr_idx);
- wr32(hw, GLINT_ITR(ICE_RX_ITR, pf->hw_oicr_idx),
+ ice_ena_ctrlq_interrupts(hw, pf->oicr_idx);
+ wr32(hw, GLINT_ITR(ICE_RX_ITR, pf->oicr_idx),
ITR_REG_ALIGN(ICE_ITR_8K) >> ICE_ITR_GRAN_S);
ice_flush(hw);
@@ -1664,21 +1760,6 @@ skip_req_irq:
}
/**
- * 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_napi_add - register NAPI handler for the VSI
* @vsi: VSI for which NAPI handler is to be registered
*
@@ -1803,8 +1884,8 @@ void ice_fill_rss_lut(u8 *lut, u16 rss_table_size, u16 rss_size)
* @pf: board private structure
* @pi: pointer to the port_info instance
*
- * Returns pointer to the successfully allocated VSI sw struct on success,
- * otherwise returns NULL on failure.
+ * Returns pointer to the successfully allocated VSI software struct
+ * on success, otherwise returns NULL on failure.
*/
static struct ice_vsi *
ice_pf_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi)
@@ -1813,6 +1894,20 @@ ice_pf_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi)
}
/**
+ * ice_lb_vsi_setup - Set up a loopback VSI
+ * @pf: board private structure
+ * @pi: pointer to the port_info instance
+ *
+ * Returns pointer to the successfully allocated VSI software struct
+ * on success, otherwise returns NULL on failure.
+ */
+struct ice_vsi *
+ice_lb_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi)
+{
+ return ice_vsi_setup(pf, pi, ICE_VSI_LB, ICE_INVAL_VFID);
+}
+
+/**
* ice_vlan_rx_add_vid - Add a VLAN ID filter to HW offload
* @netdev: network interface to be adjusted
* @proto: unused protocol
@@ -1900,8 +1995,6 @@ ice_vlan_rx_kill_vid(struct net_device *netdev, __always_unused __be16 proto,
*/
static int ice_setup_pf_sw(struct ice_pf *pf)
{
- LIST_HEAD(tmp_add_list);
- u8 broadcast[ETH_ALEN];
struct ice_vsi *vsi;
int status = 0;
@@ -1926,38 +2019,12 @@ static int ice_setup_pf_sw(struct ice_pf *pf)
*/
ice_napi_add(vsi);
- /* To add a MAC filter, first add the MAC to a list and then
- * pass the list to ice_add_mac.
- */
-
- /* Add a unicast MAC filter so the VSI can get its packets */
- status = ice_add_mac_to_list(vsi, &tmp_add_list,
- vsi->port_info->mac.perm_addr);
+ status = ice_init_mac_fltr(pf);
if (status)
goto unroll_napi_add;
- /* VSI needs to receive broadcast traffic, so add the broadcast
- * MAC address to the list as well.
- */
- eth_broadcast_addr(broadcast);
- status = ice_add_mac_to_list(vsi, &tmp_add_list, broadcast);
- if (status)
- goto free_mac_list;
-
- /* program MAC filters for entries in tmp_add_list */
- status = ice_add_mac(&pf->hw, &tmp_add_list);
- if (status) {
- dev_err(&pf->pdev->dev, "Could not add MAC filters\n");
- status = -ENOMEM;
- goto free_mac_list;
- }
-
- ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list);
return status;
-free_mac_list:
- ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list);
-
unroll_napi_add:
if (vsi) {
ice_napi_del(vsi);
@@ -2149,14 +2216,9 @@ static void ice_clear_interrupt_scheme(struct ice_pf *pf)
if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags))
ice_dis_msix(pf);
- if (pf->sw_irq_tracker) {
- devm_kfree(&pf->pdev->dev, pf->sw_irq_tracker);
- pf->sw_irq_tracker = NULL;
- }
-
- if (pf->hw_irq_tracker) {
- devm_kfree(&pf->pdev->dev, pf->hw_irq_tracker);
- pf->hw_irq_tracker = NULL;
+ if (pf->irq_tracker) {
+ devm_kfree(&pf->pdev->dev, pf->irq_tracker);
+ pf->irq_tracker = NULL;
}
}
@@ -2166,7 +2228,7 @@ static void ice_clear_interrupt_scheme(struct ice_pf *pf)
*/
static int ice_init_interrupt_scheme(struct ice_pf *pf)
{
- int vectors = 0, hw_vectors = 0;
+ int vectors;
if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags))
vectors = ice_ena_msix_range(pf);
@@ -2177,31 +2239,18 @@ static int ice_init_interrupt_scheme(struct ice_pf *pf)
return vectors;
/* set up vector assignment tracking */
- pf->sw_irq_tracker =
- devm_kzalloc(&pf->pdev->dev, sizeof(*pf->sw_irq_tracker) +
+ pf->irq_tracker =
+ devm_kzalloc(&pf->pdev->dev, sizeof(*pf->irq_tracker) +
(sizeof(u16) * vectors), GFP_KERNEL);
- if (!pf->sw_irq_tracker) {
+ if (!pf->irq_tracker) {
ice_dis_msix(pf);
return -ENOMEM;
}
/* populate SW interrupts pool with number of OS granted IRQs. */
pf->num_avail_sw_msix = vectors;
- pf->sw_irq_tracker->num_entries = vectors;
-
- /* set up HW vector assignment tracking */
- hw_vectors = pf->hw.func_caps.common_cap.num_msix_vectors;
- pf->hw_irq_tracker =
- devm_kzalloc(&pf->pdev->dev, sizeof(*pf->hw_irq_tracker) +
- (sizeof(u16) * hw_vectors), GFP_KERNEL);
- if (!pf->hw_irq_tracker) {
- ice_clear_interrupt_scheme(pf);
- return -ENOMEM;
- }
-
- /* populate HW interrupts pool with number of HW supported irqs. */
- pf->num_avail_hw_msix = hw_vectors;
- pf->hw_irq_tracker->num_entries = hw_vectors;
+ pf->irq_tracker->num_entries = vectors;
+ pf->irq_tracker->end = pf->irq_tracker->num_entries;
return 0;
}
@@ -2237,7 +2286,7 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
struct ice_hw *hw;
int err;
- /* this driver uses devres, see Documentation/driver-model/devres.txt */
+ /* this driver uses devres, see Documentation/driver-api/driver-model/devres.rst */
err = pcim_enable_device(pdev);
if (err)
return err;
@@ -2252,7 +2301,7 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
if (!pf)
return -ENOMEM;
- /* set up for high or low dma */
+ /* set up for high or low DMA */
err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
if (err)
err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
@@ -2302,7 +2351,7 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
ice_init_pf(pf);
- err = ice_init_pf_dcb(pf);
+ err = ice_init_pf_dcb(pf, false);
if (err) {
clear_bit(ICE_FLAG_DCB_CAPABLE, pf->flags);
clear_bit(ICE_FLAG_DCB_ENA, pf->flags);
@@ -2368,7 +2417,7 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
err = ice_setup_pf_sw(pf);
if (err) {
- dev_err(dev, "probe failed due to setup pf switch:%d\n", err);
+ dev_err(dev, "probe failed due to setup PF switch:%d\n", err);
goto err_alloc_sw_unroll;
}
@@ -2625,7 +2674,7 @@ static int __init ice_module_init(void)
status = pci_register_driver(&ice_driver);
if (status) {
- pr_err("failed to register pci driver, err %d\n", status);
+ pr_err("failed to register PCI driver, err %d\n", status);
destroy_workqueue(ice_wq);
}
@@ -2725,21 +2774,21 @@ free_lists:
ice_free_fltr_list(&pf->pdev->dev, &a_mac_list);
if (err) {
- netdev_err(netdev, "can't set mac %pM. filter update failed\n",
+ netdev_err(netdev, "can't set MAC %pM. filter update failed\n",
mac);
return err;
}
/* change the netdev's MAC address */
memcpy(netdev->dev_addr, mac, netdev->addr_len);
- netdev_dbg(vsi->netdev, "updated mac address to %pM\n",
+ netdev_dbg(vsi->netdev, "updated MAC address to %pM\n",
netdev->dev_addr);
/* write new MAC address to the firmware */
flags = ICE_AQC_MAN_MAC_UPDATE_LAA_WOL;
status = ice_aq_manage_mac_write(hw, mac, flags, NULL);
if (status) {
- netdev_err(netdev, "can't set mac %pM. write to firmware failed.\n",
+ netdev_err(netdev, "can't set MAC %pM. write to firmware failed.\n",
mac);
}
return 0;
@@ -2876,6 +2925,13 @@ ice_set_features(struct net_device *netdev, netdev_features_t features)
(netdev->features & NETIF_F_HW_VLAN_CTAG_TX))
ret = ice_vsi_manage_vlan_insertion(vsi);
+ if ((features & NETIF_F_HW_VLAN_CTAG_FILTER) &&
+ !(netdev->features & NETIF_F_HW_VLAN_CTAG_FILTER))
+ ret = ice_cfg_vlan_pruning(vsi, true, false);
+ else if (!(features & NETIF_F_HW_VLAN_CTAG_FILTER) &&
+ (netdev->features & NETIF_F_HW_VLAN_CTAG_FILTER))
+ ret = ice_cfg_vlan_pruning(vsi, false, false);
+
return ret;
}
@@ -2901,7 +2957,7 @@ static int ice_vsi_vlan_setup(struct ice_vsi *vsi)
*
* Return 0 on success and negative value on error
*/
-static int ice_vsi_cfg(struct ice_vsi *vsi)
+int ice_vsi_cfg(struct ice_vsi *vsi)
{
int err;
@@ -2933,7 +2989,7 @@ static void ice_napi_enable_all(struct ice_vsi *vsi)
if (!vsi->netdev)
return;
- ice_for_each_q_vector(vsi, q_idx) {
+ ice_for_each_q_vector(vsi, q_idx) {
struct ice_q_vector *q_vector = vsi->q_vectors[q_idx];
if (q_vector->rx.ring || q_vector->tx.ring)
@@ -3456,7 +3512,7 @@ int ice_down(struct ice_vsi *vsi)
*
* Return 0 on success, negative on failure
*/
-static int ice_vsi_setup_tx_rings(struct ice_vsi *vsi)
+int ice_vsi_setup_tx_rings(struct ice_vsi *vsi)
{
int i, err = 0;
@@ -3482,7 +3538,7 @@ static int ice_vsi_setup_tx_rings(struct ice_vsi *vsi)
*
* Return 0 on success, negative on failure
*/
-static int ice_vsi_setup_rx_rings(struct ice_vsi *vsi)
+int ice_vsi_setup_rx_rings(struct ice_vsi *vsi)
{
int i, err = 0;
@@ -3658,7 +3714,7 @@ static int ice_pf_ena_all_vsi(struct ice_pf *pf, bool locked)
}
/**
- * ice_vsi_rebuild_all - rebuild all VSIs in pf
+ * ice_vsi_rebuild_all - rebuild all VSIs in PF
* @pf: the PF
*/
static int ice_vsi_rebuild_all(struct ice_pf *pf)
@@ -3728,7 +3784,7 @@ static int ice_vsi_replay_all(struct ice_pf *pf)
/**
* ice_rebuild - rebuild after reset
- * @pf: pf to rebuild
+ * @pf: PF to rebuild
*/
static void ice_rebuild(struct ice_pf *pf)
{
@@ -3740,7 +3796,7 @@ static void ice_rebuild(struct ice_pf *pf)
if (test_bit(__ICE_DOWN, pf->state))
goto clear_recovery;
- dev_dbg(dev, "rebuilding pf\n");
+ dev_dbg(dev, "rebuilding PF\n");
ret = ice_init_all_ctrlq(hw);
if (ret) {
@@ -3768,12 +3824,6 @@ static void ice_rebuild(struct ice_pf *pf)
ice_dcb_rebuild(pf);
- /* reset search_hint of irq_trackers to 0 since interrupts are
- * reclaimed and could be allocated from beginning during VSI rebuild
- */
- pf->sw_irq_tracker->search_hint = 0;
- pf->hw_irq_tracker->search_hint = 0;
-
err = ice_vsi_rebuild_all(pf);
if (err) {
dev_err(dev, "ice_vsi_rebuild_all failed\n");
@@ -3857,16 +3907,16 @@ static int ice_change_mtu(struct net_device *netdev, int new_mtu)
u8 count = 0;
if (new_mtu == netdev->mtu) {
- netdev_warn(netdev, "mtu is already %u\n", netdev->mtu);
+ netdev_warn(netdev, "MTU is already %u\n", netdev->mtu);
return 0;
}
if (new_mtu < netdev->min_mtu) {
- netdev_err(netdev, "new mtu invalid. min_mtu is %d\n",
+ netdev_err(netdev, "new MTU invalid. min_mtu is %d\n",
netdev->min_mtu);
return -EINVAL;
} else if (new_mtu > netdev->max_mtu) {
- netdev_err(netdev, "new mtu invalid. max_mtu is %d\n",
+ netdev_err(netdev, "new MTU invalid. max_mtu is %d\n",
netdev->min_mtu);
return -EINVAL;
}
@@ -3882,7 +3932,7 @@ static int ice_change_mtu(struct net_device *netdev, int new_mtu)
} while (count < 100);
if (count == 100) {
- netdev_err(netdev, "can't change mtu. Device is busy\n");
+ netdev_err(netdev, "can't change MTU. Device is busy\n");
return -EBUSY;
}
@@ -3894,18 +3944,18 @@ static int ice_change_mtu(struct net_device *netdev, int new_mtu)
err = ice_down(vsi);
if (err) {
- netdev_err(netdev, "change mtu if_up err %d\n", err);
+ netdev_err(netdev, "change MTU if_up err %d\n", err);
return err;
}
err = ice_up(vsi);
if (err) {
- netdev_err(netdev, "change mtu if_up err %d\n", err);
+ netdev_err(netdev, "change MTU if_up err %d\n", err);
return err;
}
}
- netdev_dbg(netdev, "changed mtu to %d\n", new_mtu);
+ netdev_info(netdev, "changed MTU to %d\n", new_mtu);
return 0;
}
@@ -4241,7 +4291,7 @@ static void ice_tx_timeout(struct net_device *netdev)
*
* Returns 0 on success, negative value on failure
*/
-static int ice_open(struct net_device *netdev)
+int ice_open(struct net_device *netdev)
{
struct ice_netdev_priv *np = netdev_priv(netdev);
struct ice_vsi *vsi = np->vsi;
@@ -4278,7 +4328,7 @@ static int ice_open(struct net_device *netdev)
*
* Returns success only - not allowed to fail
*/
-static int ice_stop(struct net_device *netdev)
+int ice_stop(struct net_device *netdev)
{
struct ice_netdev_priv *np = netdev_priv(netdev);
struct ice_vsi *vsi = np->vsi;
diff --git a/drivers/net/ethernet/intel/ice/ice_nvm.c b/drivers/net/ethernet/intel/ice/ice_nvm.c
index 62571d33d0d6..bcb431f1bd92 100644
--- a/drivers/net/ethernet/intel/ice/ice_nvm.c
+++ b/drivers/net/ethernet/intel/ice/ice_nvm.c
@@ -119,7 +119,7 @@ ice_read_sr_word_aq(struct ice_hw *hw, u16 offset, u16 *data)
status = ice_read_sr_aq(hw, offset, 1, data, true);
if (!status)
- *data = le16_to_cpu(*(__le16 *)data);
+ *data = le16_to_cpu(*(__force __le16 *)data);
return status;
}
@@ -174,7 +174,7 @@ ice_read_sr_buf_aq(struct ice_hw *hw, u16 offset, u16 *words, u16 *data)
} while (words_read < *words);
for (i = 0; i < *words; i++)
- data[i] = le16_to_cpu(((__le16 *)data)[i]);
+ data[i] = le16_to_cpu(((__force __le16 *)data)[i]);
read_nvm_buf_aq_exit:
*words = words_read;
@@ -316,3 +316,34 @@ ice_read_sr_buf(struct ice_hw *hw, u16 offset, u16 *words, u16 *data)
return status;
}
+
+/**
+ * ice_nvm_validate_checksum
+ * @hw: pointer to the HW struct
+ *
+ * Verify NVM PFA checksum validity (0x0706)
+ */
+enum ice_status ice_nvm_validate_checksum(struct ice_hw *hw)
+{
+ struct ice_aqc_nvm_checksum *cmd;
+ struct ice_aq_desc desc;
+ enum ice_status status;
+
+ status = ice_acquire_nvm(hw, ICE_RES_READ);
+ if (status)
+ return status;
+
+ cmd = &desc.params.nvm_checksum;
+
+ ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_checksum);
+ cmd->flags = ICE_AQC_NVM_CHECKSUM_VERIFY;
+
+ status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
+ ice_release_nvm(hw);
+
+ if (!status)
+ if (le16_to_cpu(cmd->checksum) != ICE_AQC_NVM_CHECKSUM_CORRECT)
+ status = ICE_ERR_NVM_CHECKSUM;
+
+ return status;
+}
diff --git a/drivers/net/ethernet/intel/ice/ice_sched.c b/drivers/net/ethernet/intel/ice/ice_sched.c
index 8d49f83be7a5..2a232504379d 100644
--- a/drivers/net/ethernet/intel/ice/ice_sched.c
+++ b/drivers/net/ethernet/intel/ice/ice_sched.c
@@ -683,10 +683,10 @@ ice_sched_add_elems(struct ice_port_info *pi, struct ice_sched_node *tc_node,
u16 i, num_groups_added = 0;
enum ice_status status = 0;
struct ice_hw *hw = pi->hw;
- u16 buf_size;
+ size_t buf_size;
u32 teid;
- buf_size = sizeof(*buf) + sizeof(*buf->generic) * (num_nodes - 1);
+ buf_size = struct_size(buf, generic, num_nodes - 1);
buf = devm_kzalloc(ice_hw_to_dev(hw), buf_size, GFP_KERNEL);
if (!buf)
return ICE_ERR_NO_MEMORY;
diff --git a/drivers/net/ethernet/intel/ice/ice_status.h b/drivers/net/ethernet/intel/ice/ice_status.h
index 17afe6acb18a..c01597885629 100644
--- a/drivers/net/ethernet/intel/ice/ice_status.h
+++ b/drivers/net/ethernet/intel/ice/ice_status.h
@@ -26,6 +26,7 @@ enum ice_status {
ICE_ERR_IN_USE = -16,
ICE_ERR_MAX_LIMIT = -17,
ICE_ERR_RESET_ONGOING = -18,
+ ICE_ERR_NVM_CHECKSUM = -51,
ICE_ERR_BUF_TOO_SHORT = -52,
ICE_ERR_NVM_BLANK_MODE = -53,
ICE_ERR_AQ_ERROR = -100,
diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c
index 9f1f595ae7e6..8271fd651725 100644
--- a/drivers/net/ethernet/intel/ice/ice_switch.c
+++ b/drivers/net/ethernet/intel/ice/ice_switch.c
@@ -799,7 +799,7 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info,
daddr = f_info->l_data.ethertype_mac.mac_addr;
/* fall-through */
case ICE_SW_LKUP_ETHERTYPE:
- off = (__be16 *)(eth_hdr + ICE_ETH_ETHTYPE_OFFSET);
+ off = (__force __be16 *)(eth_hdr + ICE_ETH_ETHTYPE_OFFSET);
*off = cpu_to_be16(f_info->l_data.ethertype_mac.ethertype);
break;
case ICE_SW_LKUP_MAC_VLAN:
@@ -829,7 +829,7 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info,
ether_addr_copy(eth_hdr + ICE_ETH_DA_OFFSET, daddr);
if (!(vlan_id > ICE_MAX_VLAN_ID)) {
- off = (__be16 *)(eth_hdr + ICE_ETH_VLAN_TCI_OFFSET);
+ off = (__force __be16 *)(eth_hdr + ICE_ETH_VLAN_TCI_OFFSET);
*off = cpu_to_be16(vlan_id);
}
@@ -1973,6 +1973,10 @@ ice_add_vlan(struct ice_hw *hw, struct list_head *v_list)
* ice_add_eth_mac - Add ethertype and MAC based filter rule
* @hw: pointer to the hardware structure
* @em_list: list of ether type MAC filter, MAC is optional
+ *
+ * This function requires the caller to populate the entries in
+ * the filter list with the necessary fields (including flags to
+ * indicate Tx or Rx rules).
*/
enum ice_status
ice_add_eth_mac(struct ice_hw *hw, struct list_head *em_list)
@@ -1990,7 +1994,6 @@ ice_add_eth_mac(struct ice_hw *hw, struct list_head *em_list)
l_type != ICE_SW_LKUP_ETHERTYPE)
return ICE_ERR_PARAM;
- em_list_itr->fltr_info.flag = ICE_FLTR_TX;
em_list_itr->status = ice_add_rule_internal(hw, l_type,
em_list_itr);
if (em_list_itr->status)
diff --git a/drivers/net/ethernet/intel/ice/ice_switch.h b/drivers/net/ethernet/intel/ice/ice_switch.h
index 732b0b9b2e15..cb123fbe30be 100644
--- a/drivers/net/ethernet/intel/ice/ice_switch.h
+++ b/drivers/net/ethernet/intel/ice/ice_switch.h
@@ -8,9 +8,11 @@
#define ICE_SW_CFG_MAX_BUF_LEN 2048
#define ICE_DFLT_VSI_INVAL 0xff
+#define ICE_FLTR_RX BIT(0)
+#define ICE_FLTR_TX BIT(1)
+#define ICE_FLTR_TX_RX (ICE_FLTR_RX | ICE_FLTR_TX)
#define ICE_VSI_INVAL_ID 0xffff
#define ICE_INVAL_Q_HANDLE 0xFFFF
-#define ICE_INVAL_Q_HANDLE 0xFFFF
/* VSI queue context structure */
struct ice_q_ctx {
@@ -69,9 +71,6 @@ struct ice_fltr_info {
/* rule ID returned by firmware once filter rule is created */
u16 fltr_rule_id;
u16 flag;
-#define ICE_FLTR_RX BIT(0)
-#define ICE_FLTR_TX BIT(1)
-#define ICE_FLTR_TX_RX (ICE_FLTR_RX | ICE_FLTR_TX)
/* Source VSI for LOOKUP_TX or source port for LOOKUP_RX */
u16 src;
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c
index 2364eaf33d23..3c83230434b6 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.c
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.c
@@ -55,7 +55,7 @@ void ice_clean_tx_ring(struct ice_ring *tx_ring)
if (!tx_ring->tx_buf)
return;
- /* Free all the Tx ring sk_bufss */
+ /* Free all the Tx ring sk_buffs */
for (i = 0; i < tx_ring->count; i++)
ice_unmap_and_free_tx_buf(tx_ring, &tx_ring->tx_buf[i]);
@@ -1101,7 +1101,7 @@ static int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget)
* ice_adjust_itr_by_size_and_speed - Adjust ITR based on current traffic
* @port_info: port_info structure containing the current link speed
* @avg_pkt_size: average size of Tx or Rx packets based on clean routine
- * @itr: itr value to update
+ * @itr: ITR value to update
*
* Calculate how big of an increment should be applied to the ITR value passed
* in based on wmem_default, SKB overhead, Ethernet overhead, and the current
@@ -1316,7 +1316,7 @@ clear_counts:
*/
static u32 ice_buildreg_itr(u16 itr_idx, u16 itr)
{
- /* The itr value is reported in microseconds, and the register value is
+ /* The ITR value is reported in microseconds, and the register value is
* recorded in 2 microsecond units. For this reason we only need to
* shift by the GLINT_DYN_CTL_INTERVAL_S - ICE_ITR_GRAN_S to apply this
* granularity as a shift instead of division. The mask makes sure the
@@ -1645,7 +1645,7 @@ ice_tx_map(struct ice_ring *tx_ring, struct ice_tx_buf *first,
return;
dma_error:
- /* clear dma mappings for failed tx_buf map */
+ /* clear DMA mappings for failed tx_buf map */
for (;;) {
tx_buf = &tx_ring->tx_buf[i];
ice_unmap_and_free_tx_buf(tx_ring, tx_buf);
@@ -1874,10 +1874,10 @@ int ice_tso(struct ice_tx_buf *first, struct ice_tx_offload_params *off)
cd_mss = skb_shinfo(skb)->gso_size;
/* record cdesc_qw1 with TSO parameters */
- off->cd_qw1 |= ICE_TX_DESC_DTYPE_CTX |
- (ICE_TX_CTX_DESC_TSO << ICE_TXD_CTX_QW1_CMD_S) |
- (cd_tso_len << ICE_TXD_CTX_QW1_TSO_LEN_S) |
- (cd_mss << ICE_TXD_CTX_QW1_MSS_S);
+ off->cd_qw1 |= (u64)(ICE_TX_DESC_DTYPE_CTX |
+ (ICE_TX_CTX_DESC_TSO << ICE_TXD_CTX_QW1_CMD_S) |
+ (cd_tso_len << ICE_TXD_CTX_QW1_TSO_LEN_S) |
+ (cd_mss << ICE_TXD_CTX_QW1_MSS_S));
first->tx_flags |= ICE_TX_FLAGS_TSO;
return 1;
}
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h
index 66e05032ee56..ec76aba347b9 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.h
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.h
@@ -58,19 +58,19 @@ struct ice_tx_buf {
unsigned int bytecount;
unsigned short gso_segs;
u32 tx_flags;
- DEFINE_DMA_UNMAP_ADDR(dma);
DEFINE_DMA_UNMAP_LEN(len);
+ DEFINE_DMA_UNMAP_ADDR(dma);
};
struct ice_tx_offload_params {
- u8 header_len;
+ u64 cd_qw1;
+ struct ice_ring *tx_ring;
u32 td_cmd;
u32 td_offset;
u32 td_l2tag1;
- u16 cd_l2tag2;
u32 cd_tunnel_params;
- u64 cd_qw1;
- struct ice_ring *tx_ring;
+ u16 cd_l2tag2;
+ u8 header_len;
};
struct ice_rx_buf {
@@ -150,6 +150,7 @@ enum ice_rx_dtype {
/* descriptor ring, associated with a VSI */
struct ice_ring {
+ /* CL1 - 1st cacheline starts here */
struct ice_ring *next; /* pointer to next ring in q_vector */
void *desc; /* Descriptor ring memory */
struct device *dev; /* Used for DMA mapping */
@@ -161,11 +162,11 @@ struct ice_ring {
struct ice_tx_buf *tx_buf;
struct ice_rx_buf *rx_buf;
};
+ /* CL2 - 2nd cacheline starts here */
u16 q_index; /* Queue number of ring */
- u32 txq_teid; /* Added Tx queue TEID */
-#ifdef CONFIG_DCB
- u8 dcb_tc; /* Traffic class of ring */
-#endif /* CONFIG_DCB */
+ u16 q_handle; /* Queue handle per TC */
+
+ u8 ring_active:1; /* is ring online or not */
u16 count; /* Number of descriptors */
u16 reg_idx; /* HW register index of the ring */
@@ -173,8 +174,7 @@ struct ice_ring {
/* used in interrupt processing */
u16 next_to_use;
u16 next_to_clean;
-
- u8 ring_active; /* is ring online or not */
+ u16 next_to_alloc;
/* stats structs */
struct ice_q_stats stats;
@@ -184,10 +184,17 @@ struct ice_ring {
struct ice_rxq_stats rx_stats;
};
- unsigned int size; /* length of descriptor ring in bytes */
- dma_addr_t dma; /* physical address of ring */
struct rcu_head rcu; /* to avoid race on free */
- u16 next_to_alloc;
+ /* CLX - the below items are only accessed infrequently and should be
+ * in their own cache line if possible
+ */
+ dma_addr_t dma; /* physical address of ring */
+ unsigned int size; /* length of descriptor ring in bytes */
+ u32 txq_teid; /* Added Tx queue TEID */
+ u16 rx_buf_len;
+#ifdef CONFIG_DCB
+ u8 dcb_tc; /* Traffic class of ring */
+#endif /* CONFIG_DCB */
} ____cacheline_internodealigned_in_smp;
struct ice_ring_container {
diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h
index a862af4cbf78..24bbef8bbe69 100644
--- a/drivers/net/ethernet/intel/ice/ice_type.h
+++ b/drivers/net/ethernet/intel/ice/ice_type.h
@@ -23,6 +23,7 @@ static inline bool ice_is_tc_ena(u8 bitmap, u8 tc)
/* debug masks - set these bits in hw->debug_mask to control output */
#define ICE_DBG_INIT BIT_ULL(1)
+#define ICE_DBG_FW_LOG BIT_ULL(3)
#define ICE_DBG_LINK BIT_ULL(4)
#define ICE_DBG_PHY BIT_ULL(5)
#define ICE_DBG_QCTX BIT_ULL(6)
@@ -61,6 +62,13 @@ enum ice_fc_mode {
ICE_FC_DFLT
};
+enum ice_fec_mode {
+ ICE_FEC_NONE = 0,
+ ICE_FEC_RS,
+ ICE_FEC_BASER,
+ ICE_FEC_AUTO
+};
+
enum ice_set_fc_aq_failures {
ICE_SET_FC_AQ_FAIL_NONE = 0,
ICE_SET_FC_AQ_FAIL_GET,
@@ -86,12 +94,14 @@ enum ice_media_type {
enum ice_vsi_type {
ICE_VSI_PF = 0,
ICE_VSI_VF,
+ ICE_VSI_LB = 6,
};
struct ice_link_status {
/* Refer to ice_aq_phy_type for bits definition */
u64 phy_type_low;
u64 phy_type_high;
+ u8 topo_media_conflict;
u16 max_frame_size;
u16 link_speed;
u16 req_speeds;
@@ -99,6 +109,7 @@ struct ice_link_status {
u8 link_info;
u8 an_info;
u8 ext_info;
+ u8 fec_info;
u8 pacing;
/* Refer to #define from module_type[ICE_MODULE_TYPE_TOTAL_BYTE] of
* ice_aqc_get_phy_caps structure
@@ -423,7 +434,7 @@ struct ice_hw {
struct ice_fw_log_cfg fw_log;
/* Device max aggregate bandwidths corresponding to the GL_PWR_MODE_CTL
- * register. Used for determining the itr/intrl granularity during
+ * register. Used for determining the ITR/intrl granularity during
* initialization.
*/
#define ICE_MAX_AGG_BW_200G 0x0
diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c
index a805cbdd69be..5d24b539648f 100644
--- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c
+++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c
@@ -103,7 +103,7 @@ ice_set_pfe_link_forced(struct ice_vf *vf, struct virtchnl_pf_event *pfe,
u16 link_speed;
if (link_up)
- link_speed = ICE_AQ_LINK_SPEED_40GB;
+ link_speed = ICE_AQ_LINK_SPEED_100GB;
else
link_speed = ICE_AQ_LINK_SPEED_UNKNOWN;
@@ -141,32 +141,20 @@ static void ice_vc_notify_vf_link_state(struct ice_vf *vf)
}
/**
- * ice_get_vf_vector - get VF interrupt vector register offset
- * @vf_msix: number of MSIx vector per VF on a PF
- * @vf_id: VF identifier
- * @i: index of MSIx vector
- */
-static u32 ice_get_vf_vector(int vf_msix, int vf_id, int i)
-{
- return ((i == 0) ? VFINT_DYN_CTLN(vf_id) :
- VFINT_DYN_CTLN(((vf_msix - 1) * (vf_id)) + (i - 1)));
-}
-
-/**
* ice_free_vf_res - Free a VF's resources
* @vf: pointer to the VF info
*/
static void ice_free_vf_res(struct ice_vf *vf)
{
struct ice_pf *pf = vf->pf;
- int i, pf_vf_msix;
+ int i, last_vector_idx;
/* First, disable VF's configuration API to prevent OS from
* accessing the VF's VSI after it's freed or invalidated.
*/
clear_bit(ICE_VF_STATE_INIT, vf->vf_states);
- /* free vsi & disconnect it from the parent uplink */
+ /* free VSI and disconnect it from the parent uplink */
if (vf->lan_vsi_idx) {
ice_vsi_release(pf->vsi[vf->lan_vsi_idx]);
vf->lan_vsi_idx = 0;
@@ -174,13 +162,10 @@ static void ice_free_vf_res(struct ice_vf *vf)
vf->num_mac = 0;
}
- pf_vf_msix = pf->num_vf_msix;
+ last_vector_idx = vf->first_vector_idx + pf->num_vf_msix - 1;
/* Disable interrupts so that VF starts in a known state */
- for (i = 0; i < pf_vf_msix; i++) {
- u32 reg_idx;
-
- reg_idx = ice_get_vf_vector(pf_vf_msix, vf->vf_id, i);
- wr32(&pf->hw, reg_idx, VFINT_DYN_CTLN_CLEARPBA_M);
+ for (i = vf->first_vector_idx; i <= last_vector_idx; i++) {
+ wr32(&pf->hw, GLINT_DYN_CTL(i), GLINT_DYN_CTL_CLEARPBA_M);
ice_flush(&pf->hw);
}
/* reset some of the state variables keeping track of the resources */
@@ -205,8 +190,7 @@ static void ice_dis_vf_mappings(struct ice_vf *vf)
wr32(hw, VPINT_ALLOC(vf->vf_id), 0);
wr32(hw, VPINT_ALLOC_PCI(vf->vf_id), 0);
- first = vf->first_vector_idx +
- hw->func_caps.common_cap.msix_vector_first_id;
+ first = vf->first_vector_idx;
last = first + pf->num_vf_msix - 1;
for (v = first; v <= last; v++) {
u32 reg;
@@ -232,6 +216,42 @@ static void ice_dis_vf_mappings(struct ice_vf *vf)
}
/**
+ * ice_sriov_free_msix_res - Reset/free any used MSIX resources
+ * @pf: pointer to the PF structure
+ *
+ * If MSIX entries from the pf->irq_tracker were needed then we need to
+ * reset the irq_tracker->end and give back the entries we needed to
+ * num_avail_sw_msix.
+ *
+ * If no MSIX entries were taken from the pf->irq_tracker then just clear
+ * the pf->sriov_base_vector.
+ *
+ * Returns 0 on success, and -EINVAL on error.
+ */
+static int ice_sriov_free_msix_res(struct ice_pf *pf)
+{
+ struct ice_res_tracker *res;
+
+ if (!pf)
+ return -EINVAL;
+
+ res = pf->irq_tracker;
+ if (!res)
+ return -EINVAL;
+
+ /* give back irq_tracker resources used */
+ if (pf->sriov_base_vector < res->num_entries) {
+ res->end = res->num_entries;
+ pf->num_avail_sw_msix +=
+ res->num_entries - pf->sriov_base_vector;
+ }
+
+ pf->sriov_base_vector = 0;
+
+ return 0;
+}
+
+/**
* ice_free_vfs - Free all VFs
* @pf: pointer to the PF structure
*/
@@ -246,15 +266,6 @@ void ice_free_vfs(struct ice_pf *pf)
while (test_and_set_bit(__ICE_VF_DIS, pf->state))
usleep_range(1000, 2000);
- /* Disable IOV before freeing resources. This lets any VF drivers
- * running in the host get themselves cleaned up before we yank
- * the carpet out from underneath their feet.
- */
- if (!pci_vfs_assigned(pf->pdev))
- pci_disable_sriov(pf->pdev);
- else
- dev_warn(&pf->pdev->dev, "VFs are assigned - not disabling SR-IOV\n");
-
/* Avoid wait time by stopping all VFs at the same time */
for (i = 0; i < pf->num_alloc_vfs; i++) {
struct ice_vsi *vsi;
@@ -270,6 +281,15 @@ void ice_free_vfs(struct ice_pf *pf)
clear_bit(ICE_VF_STATE_ENA, pf->vf[i].vf_states);
}
+ /* Disable IOV before freeing resources. This lets any VF drivers
+ * running in the host get themselves cleaned up before we yank
+ * the carpet out from underneath their feet.
+ */
+ if (!pci_vfs_assigned(pf->pdev))
+ pci_disable_sriov(pf->pdev);
+ else
+ dev_warn(&pf->pdev->dev, "VFs are assigned - not disabling SR-IOV\n");
+
tmp = pf->num_alloc_vfs;
pf->num_vf_qps = 0;
pf->num_alloc_vfs = 0;
@@ -288,6 +308,10 @@ void ice_free_vfs(struct ice_pf *pf)
}
}
+ if (ice_sriov_free_msix_res(pf))
+ dev_err(&pf->pdev->dev,
+ "Failed to free MSIX resources used by SR-IOV\n");
+
devm_kfree(&pf->pdev->dev, pf->vf);
pf->vf = NULL;
@@ -457,6 +481,22 @@ ice_vf_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi, u16 vf_id)
}
/**
+ * ice_calc_vf_first_vector_idx - Calculate absolute MSIX vector index in HW
+ * @pf: pointer to PF structure
+ * @vf: pointer to VF that the first MSIX vector index is being calculated for
+ *
+ * This returns the first MSIX vector index in HW that is used by this VF and
+ * this will always be the OICR index in the AVF driver so any functionality
+ * using vf->first_vector_idx for queue configuration will have to increment by
+ * 1 to avoid meddling with the OICR index.
+ */
+static int ice_calc_vf_first_vector_idx(struct ice_pf *pf, struct ice_vf *vf)
+{
+ return pf->hw.func_caps.common_cap.msix_vector_first_id +
+ pf->sriov_base_vector + vf->vf_id * pf->num_vf_msix;
+}
+
+/**
* ice_alloc_vsi_res - Setup VF VSI and its resources
* @vf: pointer to the VF structure
*
@@ -470,8 +510,10 @@ static int ice_alloc_vsi_res(struct ice_vf *vf)
struct ice_vsi *vsi;
int status = 0;
- vsi = ice_vf_vsi_setup(pf, pf->hw.port_info, vf->vf_id);
+ /* first vector index is the VFs OICR index */
+ vf->first_vector_idx = ice_calc_vf_first_vector_idx(pf, vf);
+ vsi = ice_vf_vsi_setup(pf, pf->hw.port_info, vf->vf_id);
if (!vsi) {
dev_err(&pf->pdev->dev, "Failed to create VF VSI\n");
return -ENOMEM;
@@ -480,14 +522,6 @@ static int ice_alloc_vsi_res(struct ice_vf *vf)
vf->lan_vsi_idx = vsi->idx;
vf->lan_vsi_num = vsi->vsi_num;
- /* first vector index is the VFs OICR index */
- vf->first_vector_idx = vsi->hw_base_vector;
- /* Since hw_base_vector holds the vector where data queue interrupts
- * starts, increment by 1 since VFs allocated vectors include OICR intr
- * as well.
- */
- vsi->hw_base_vector += 1;
-
/* Check if port VLAN exist before, and restore it accordingly */
if (vf->port_vlan_id) {
ice_vsi_manage_pvid(vsi, vf->port_vlan_id, true);
@@ -580,8 +614,7 @@ static void ice_ena_vf_mappings(struct ice_vf *vf)
hw = &pf->hw;
vsi = pf->vsi[vf->lan_vsi_idx];
- first = vf->first_vector_idx +
- hw->func_caps.common_cap.msix_vector_first_id;
+ first = vf->first_vector_idx;
last = (first + pf->num_vf_msix) - 1;
abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id;
@@ -687,6 +720,97 @@ ice_determine_res(struct ice_pf *pf, u16 avail_res, u16 max_res, u16 min_res)
}
/**
+ * ice_calc_vf_reg_idx - Calculate the VF's register index in the PF space
+ * @vf: VF to calculate the register index for
+ * @q_vector: a q_vector associated to the VF
+ */
+int ice_calc_vf_reg_idx(struct ice_vf *vf, struct ice_q_vector *q_vector)
+{
+ struct ice_pf *pf;
+
+ if (!vf || !q_vector)
+ return -EINVAL;
+
+ pf = vf->pf;
+
+ /* always add one to account for the OICR being the first MSIX */
+ return pf->sriov_base_vector + pf->num_vf_msix * vf->vf_id +
+ q_vector->v_idx + 1;
+}
+
+/**
+ * ice_get_max_valid_res_idx - Get the max valid resource index
+ * @res: pointer to the resource to find the max valid index for
+ *
+ * Start from the end of the ice_res_tracker and return right when we find the
+ * first res->list entry with the ICE_RES_VALID_BIT set. This function is only
+ * valid for SR-IOV because it is the only consumer that manipulates the
+ * res->end and this is always called when res->end is set to res->num_entries.
+ */
+static int ice_get_max_valid_res_idx(struct ice_res_tracker *res)
+{
+ int i;
+
+ if (!res)
+ return -EINVAL;
+
+ for (i = res->num_entries - 1; i >= 0; i--)
+ if (res->list[i] & ICE_RES_VALID_BIT)
+ return i;
+
+ return 0;
+}
+
+/**
+ * ice_sriov_set_msix_res - Set any used MSIX resources
+ * @pf: pointer to PF structure
+ * @num_msix_needed: number of MSIX vectors needed for all SR-IOV VFs
+ *
+ * This function allows SR-IOV resources to be taken from the end of the PF's
+ * allowed HW MSIX vectors so in many cases the irq_tracker will not
+ * be needed. In these cases we just set the pf->sriov_base_vector and return
+ * success.
+ *
+ * If SR-IOV needs to use any pf->irq_tracker entries it updates the
+ * irq_tracker->end based on the first entry needed for SR-IOV. This makes it
+ * so any calls to ice_get_res() using the irq_tracker will not try to use
+ * resources at or beyond the newly set value.
+ *
+ * Return 0 on success, and -EINVAL when there are not enough MSIX vectors in
+ * in the PF's space available for SR-IOV.
+ */
+static int ice_sriov_set_msix_res(struct ice_pf *pf, u16 num_msix_needed)
+{
+ int max_valid_res_idx = ice_get_max_valid_res_idx(pf->irq_tracker);
+ u16 pf_total_msix_vectors =
+ pf->hw.func_caps.common_cap.num_msix_vectors;
+ struct ice_res_tracker *res = pf->irq_tracker;
+ int sriov_base_vector;
+
+ if (max_valid_res_idx < 0)
+ return max_valid_res_idx;
+
+ sriov_base_vector = pf_total_msix_vectors - num_msix_needed;
+
+ /* make sure we only grab irq_tracker entries from the list end and
+ * that we have enough available MSIX vectors
+ */
+ if (sriov_base_vector <= max_valid_res_idx)
+ return -EINVAL;
+
+ pf->sriov_base_vector = sriov_base_vector;
+
+ /* dip into irq_tracker entries and update used resources */
+ if (num_msix_needed > (pf_total_msix_vectors - res->num_entries)) {
+ pf->num_avail_sw_msix -=
+ res->num_entries - pf->sriov_base_vector;
+ res->end = pf->sriov_base_vector;
+ }
+
+ return 0;
+}
+
+/**
* ice_check_avail_res - check if vectors and queues are available
* @pf: pointer to the PF structure
*
@@ -696,11 +820,16 @@ ice_determine_res(struct ice_pf *pf, u16 avail_res, u16 max_res, u16 min_res)
*/
static int ice_check_avail_res(struct ice_pf *pf)
{
- u16 num_msix, num_txq, num_rxq;
+ int max_valid_res_idx = ice_get_max_valid_res_idx(pf->irq_tracker);
+ u16 num_msix, num_txq, num_rxq, num_avail_msix;
- if (!pf->num_alloc_vfs)
+ if (!pf->num_alloc_vfs || max_valid_res_idx < 0)
return -EINVAL;
+ /* add 1 to max_valid_res_idx to account for it being 0-based */
+ num_avail_msix = pf->hw.func_caps.common_cap.num_msix_vectors -
+ (max_valid_res_idx + 1);
+
/* Grab from HW interrupts common pool
* Note: By the time the user decides it needs more vectors in a VF
* its already too late since one must decide this prior to creating the
@@ -717,11 +846,11 @@ static int ice_check_avail_res(struct ice_pf *pf)
* grab default interrupt vectors (5 as supported by AVF driver).
*/
if (pf->num_alloc_vfs <= 16) {
- num_msix = ice_determine_res(pf, pf->num_avail_hw_msix,
+ num_msix = ice_determine_res(pf, num_avail_msix,
ICE_MAX_INTR_PER_VF,
ICE_MIN_INTR_PER_VF);
} else if (pf->num_alloc_vfs <= ICE_MAX_VF_COUNT) {
- num_msix = ice_determine_res(pf, pf->num_avail_hw_msix,
+ num_msix = ice_determine_res(pf, num_avail_msix,
ICE_DFLT_INTR_PER_VF,
ICE_MIN_INTR_PER_VF);
} else {
@@ -750,6 +879,9 @@ static int ice_check_avail_res(struct ice_pf *pf)
if (!num_txq || !num_rxq)
return -EIO;
+ if (ice_sriov_set_msix_res(pf, num_msix * pf->num_alloc_vfs))
+ return -EINVAL;
+
/* since AVF driver works with only queue pairs which means, it expects
* to have equal number of Rx and Tx queues, so take the minimum of
* available Tx or Rx queues
@@ -938,6 +1070,10 @@ bool ice_reset_all_vfs(struct ice_pf *pf, bool is_vflr)
vf->num_vf_qs = 0;
}
+ if (ice_sriov_free_msix_res(pf))
+ dev_err(&pf->pdev->dev,
+ "Failed to free MSIX resources used by SR-IOV\n");
+
if (ice_check_avail_res(pf)) {
dev_err(&pf->pdev->dev,
"Cannot allocate VF resources, try with fewer number of VFs\n");
@@ -1119,7 +1255,7 @@ static int ice_alloc_vfs(struct ice_pf *pf, u16 num_alloc_vfs)
int i, ret;
/* Disable global interrupt 0 so we don't try to handle the VFLR. */
- wr32(hw, GLINT_DYN_CTL(pf->hw_oicr_idx),
+ wr32(hw, GLINT_DYN_CTL(pf->oicr_idx),
ICE_ITR_NONE << GLINT_DYN_CTL_ITR_INDX_S);
ice_flush(hw);
@@ -1134,7 +1270,7 @@ static int ice_alloc_vfs(struct ice_pf *pf, u16 num_alloc_vfs)
GFP_KERNEL);
if (!vfs) {
ret = -ENOMEM;
- goto err_unroll_sriov;
+ goto err_pci_disable_sriov;
}
pf->vf = vfs;
@@ -1154,12 +1290,19 @@ static int ice_alloc_vfs(struct ice_pf *pf, u16 num_alloc_vfs)
pf->num_alloc_vfs = num_alloc_vfs;
/* VF resources get allocated during reset */
- if (!ice_reset_all_vfs(pf, true))
+ if (!ice_reset_all_vfs(pf, true)) {
+ ret = -EIO;
goto err_unroll_sriov;
+ }
goto err_unroll_intr;
err_unroll_sriov:
+ pf->vf = NULL;
+ devm_kfree(&pf->pdev->dev, vfs);
+ vfs = NULL;
+ pf->num_alloc_vfs = 0;
+err_pci_disable_sriov:
pci_disable_sriov(pf->pdev);
err_unroll_intr:
/* rearm interrupts here */
@@ -1168,8 +1311,8 @@ err_unroll_intr:
}
/**
- * ice_pf_state_is_nominal - checks the pf for nominal state
- * @pf: pointer to pf to check
+ * ice_pf_state_is_nominal - checks the PF for nominal state
+ * @pf: pointer to PF to check
*
* Check the PF's state for a collection of bits that would indicate
* the PF is in a state that would inhibit normal operation for
@@ -1496,7 +1639,7 @@ static void ice_vc_reset_vf_msg(struct ice_vf *vf)
/**
* ice_find_vsi_from_id
- * @pf: the pf structure to search for the VSI
+ * @pf: the PF structure to search for the VSI
* @id: ID of the VSI it is searching for
*
* searches for the VSI with the given ID
@@ -1807,28 +1950,37 @@ error_param:
static int ice_vc_cfg_irq_map_msg(struct ice_vf *vf, u8 *msg)
{
enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
- struct virtchnl_irq_map_info *irqmap_info =
- (struct virtchnl_irq_map_info *)msg;
+ struct virtchnl_irq_map_info *irqmap_info;
u16 vsi_id, vsi_q_id, vector_id;
struct virtchnl_vector_map *map;
- struct ice_vsi *vsi = NULL;
struct ice_pf *pf = vf->pf;
+ u16 num_q_vectors_mapped;
+ struct ice_vsi *vsi;
unsigned long qmap;
- u16 num_q_vectors;
int i;
- num_q_vectors = irqmap_info->num_vectors - ICE_NONQ_VECS_VF;
+ irqmap_info = (struct virtchnl_irq_map_info *)msg;
+ num_q_vectors_mapped = irqmap_info->num_vectors;
+
vsi = pf->vsi[vf->lan_vsi_idx];
+ if (!vsi) {
+ v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+ goto error_param;
+ }
+ /* Check to make sure number of VF vectors mapped is not greater than
+ * number of VF vectors originally allocated, and check that
+ * there is actually at least a single VF queue vector mapped
+ */
if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states) ||
- !vsi || vsi->num_q_vectors < num_q_vectors ||
- irqmap_info->num_vectors == 0) {
+ pf->num_vf_msix < num_q_vectors_mapped ||
+ !irqmap_info->num_vectors) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
- for (i = 0; i < num_q_vectors; i++) {
- struct ice_q_vector *q_vector = vsi->q_vectors[i];
+ for (i = 0; i < num_q_vectors_mapped; i++) {
+ struct ice_q_vector *q_vector;
map = &irqmap_info->vecmap[i];
@@ -1836,7 +1988,21 @@ static int ice_vc_cfg_irq_map_msg(struct ice_vf *vf, u8 *msg)
vsi_id = map->vsi_id;
/* validate msg params */
if (!(vector_id < pf->hw.func_caps.common_cap
- .num_msix_vectors) || !ice_vc_isvalid_vsi_id(vf, vsi_id)) {
+ .num_msix_vectors) || !ice_vc_isvalid_vsi_id(vf, vsi_id) ||
+ (!vector_id && (map->rxq_map || map->txq_map))) {
+ v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+ goto error_param;
+ }
+
+ /* No need to map VF miscellaneous or rogue vector */
+ if (!vector_id)
+ continue;
+
+ /* Subtract non queue vector from vector_id passed by VF
+ * to get actual number of VSI queue vector array index
+ */
+ q_vector = vsi->q_vectors[vector_id - ICE_NONQ_VECS_VF];
+ if (!q_vector) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
@@ -1852,6 +2018,8 @@ static int ice_vc_cfg_irq_map_msg(struct ice_vf *vf, u8 *msg)
q_vector->num_ring_rx++;
q_vector->rx.itr_idx = map->rxitr_idx;
vsi->rx_rings[vsi_q_id]->q_vector = q_vector;
+ ice_cfg_rxq_interrupt(vsi, vsi_q_id, vector_id,
+ q_vector->rx.itr_idx);
}
qmap = map->txq_map;
@@ -1864,11 +2032,11 @@ static int ice_vc_cfg_irq_map_msg(struct ice_vf *vf, u8 *msg)
q_vector->num_ring_tx++;
q_vector->tx.itr_idx = map->txitr_idx;
vsi->tx_rings[vsi_q_id]->q_vector = q_vector;
+ ice_cfg_txq_interrupt(vsi, vsi_q_id, vector_id,
+ q_vector->tx.itr_idx);
}
}
- if (vsi)
- ice_vsi_cfg_msix(vsi);
error_param:
/* send the response to the VF */
return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_IRQ_MAP, v_ret,
@@ -1903,9 +2071,8 @@ static int ice_vc_cfg_qs_msg(struct ice_vf *vf, u8 *msg)
}
vsi = pf->vsi[vf->lan_vsi_idx];
- if (!vsi) {
+ if (!vsi)
goto error_param;
- }
if (qci->num_queue_pairs > ICE_MAX_BASE_QS_PER_VF) {
dev_err(&pf->pdev->dev,
diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h
index 3725aea16840..c3ca522c245a 100644
--- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h
+++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h
@@ -49,29 +49,34 @@ struct ice_vf {
struct ice_pf *pf;
s16 vf_id; /* VF ID in the PF space */
- u32 driver_caps; /* reported by VF driver */
+ u16 lan_vsi_idx; /* index into PF struct */
int first_vector_idx; /* first vector index of this VF */
struct ice_sw *vf_sw_id; /* switch ID the VF VSIs connect to */
struct virtchnl_version_info vf_ver;
+ u32 driver_caps; /* reported by VF driver */
struct virtchnl_ether_addr dflt_lan_addr;
u16 port_vlan_id;
- u8 pf_set_mac; /* VF MAC address set by VMM admin */
- u8 trusted;
- u16 lan_vsi_idx; /* index into PF struct */
+ u8 pf_set_mac:1; /* VF MAC address set by VMM admin */
+ u8 trusted:1;
+ u8 spoofchk:1;
+ u8 link_forced:1;
+ u8 link_up:1; /* only valid if VF link is forced */
+ /* VSI indices - actual VSI pointers are maintained in the PF structure
+ * When assigned, these will be non-zero, because VSI 0 is always
+ * the main LAN VSI for the PF.
+ */
u16 lan_vsi_num; /* ID as used by firmware */
+ unsigned int tx_rate; /* Tx bandwidth limit in Mbps */
+ DECLARE_BITMAP(vf_states, ICE_VF_STATES_NBITS); /* VF runtime states */
+
u64 num_mdd_events; /* number of MDD events detected */
u64 num_inval_msgs; /* number of continuous invalid msgs */
u64 num_valid_msgs; /* number of valid msgs detected */
unsigned long vf_caps; /* VF's adv. capabilities */
- DECLARE_BITMAP(vf_states, ICE_VF_STATES_NBITS); /* VF runtime states */
- unsigned int tx_rate; /* Tx bandwidth limit in Mbps */
- u8 link_forced;
- u8 link_up; /* only valid if VF link is forced */
- u8 spoofchk;
+ u8 num_req_qs; /* num of queue pairs requested by VF */
u16 num_mac;
u16 num_vlan;
u16 num_vf_qs; /* num of queue configured per VF */
- u8 num_req_qs; /* num of queue pairs requested by VF */
};
#ifdef CONFIG_PCI_IOV
@@ -96,6 +101,8 @@ int ice_set_vf_trust(struct net_device *netdev, int vf_id, bool trusted);
int ice_set_vf_link_state(struct net_device *netdev, int vf_id, int link_state);
int ice_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool ena);
+
+int ice_calc_vf_reg_idx(struct ice_vf *vf, struct ice_q_vector *q_vector);
#else /* CONFIG_PCI_IOV */
#define ice_process_vflr_event(pf) do {} while (0)
#define ice_free_vfs(pf) do {} while (0)
@@ -161,5 +168,11 @@ ice_set_vf_link_state(struct net_device __always_unused *netdev,
return -EOPNOTSUPP;
}
+static inline int
+ice_calc_vf_reg_idx(struct ice_vf __always_unused *vf,
+ struct ice_q_vector __always_unused *q_vector)
+{
+ return 0;
+}
#endif /* CONFIG_PCI_IOV */
#endif /* _ICE_VIRTCHNL_PF_H_ */
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c
index bafdcf70a353..3ec2ce0725d5 100644
--- a/drivers/net/ethernet/intel/igb/e1000_82575.c
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.c
@@ -638,7 +638,7 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
dev_spec->sgmii_active = true;
break;
}
- /* fall through for I2C based SGMII */
+ /* fall through - for I2C based SGMII */
case E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES:
/* read media type from SFP EEPROM */
ret_val = igb_set_sfp_media_type_82575(hw);
diff --git a/drivers/net/ethernet/intel/igb/e1000_regs.h b/drivers/net/ethernet/intel/igb/e1000_regs.h
index 0ad737d2f289..9cb49980ec2d 100644
--- a/drivers/net/ethernet/intel/igb/e1000_regs.h
+++ b/drivers/net/ethernet/intel/igb/e1000_regs.h
@@ -409,6 +409,8 @@ do { \
#define E1000_I210_TQAVCC(_n) (0x3004 + ((_n) * 0x40))
#define E1000_I210_TQAVHC(_n) (0x300C + ((_n) * 0x40))
+#define E1000_I210_RR2DCDELAY 0x5BF4
+
#define E1000_INVM_DATA_REG(_n) (0x12120 + 4*(_n))
#define E1000_INVM_SIZE 64 /* Number of INVM Data Registers */
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
index c645d9e648e0..3182b059bf55 100644
--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c
+++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -448,7 +448,7 @@ static void igb_set_msglevel(struct net_device *netdev, u32 data)
static int igb_get_regs_len(struct net_device *netdev)
{
-#define IGB_REGS_LEN 739
+#define IGB_REGS_LEN 740
return IGB_REGS_LEN * sizeof(u32);
}
@@ -675,41 +675,44 @@ static void igb_get_regs(struct net_device *netdev,
regs_buff[554] = adapter->stats.b2ogprc;
}
- if (hw->mac.type != e1000_82576)
- return;
- for (i = 0; i < 12; i++)
- regs_buff[555 + i] = rd32(E1000_SRRCTL(i + 4));
- for (i = 0; i < 4; i++)
- regs_buff[567 + i] = rd32(E1000_PSRTYPE(i + 4));
- for (i = 0; i < 12; i++)
- regs_buff[571 + i] = rd32(E1000_RDBAL(i + 4));
- for (i = 0; i < 12; i++)
- regs_buff[583 + i] = rd32(E1000_RDBAH(i + 4));
- for (i = 0; i < 12; i++)
- regs_buff[595 + i] = rd32(E1000_RDLEN(i + 4));
- for (i = 0; i < 12; i++)
- regs_buff[607 + i] = rd32(E1000_RDH(i + 4));
- for (i = 0; i < 12; i++)
- regs_buff[619 + i] = rd32(E1000_RDT(i + 4));
- for (i = 0; i < 12; i++)
- regs_buff[631 + i] = rd32(E1000_RXDCTL(i + 4));
-
- for (i = 0; i < 12; i++)
- regs_buff[643 + i] = rd32(E1000_TDBAL(i + 4));
- for (i = 0; i < 12; i++)
- regs_buff[655 + i] = rd32(E1000_TDBAH(i + 4));
- for (i = 0; i < 12; i++)
- regs_buff[667 + i] = rd32(E1000_TDLEN(i + 4));
- for (i = 0; i < 12; i++)
- regs_buff[679 + i] = rd32(E1000_TDH(i + 4));
- for (i = 0; i < 12; i++)
- regs_buff[691 + i] = rd32(E1000_TDT(i + 4));
- for (i = 0; i < 12; i++)
- regs_buff[703 + i] = rd32(E1000_TXDCTL(i + 4));
- for (i = 0; i < 12; i++)
- regs_buff[715 + i] = rd32(E1000_TDWBAL(i + 4));
- for (i = 0; i < 12; i++)
- regs_buff[727 + i] = rd32(E1000_TDWBAH(i + 4));
+ if (hw->mac.type == e1000_82576) {
+ for (i = 0; i < 12; i++)
+ regs_buff[555 + i] = rd32(E1000_SRRCTL(i + 4));
+ for (i = 0; i < 4; i++)
+ regs_buff[567 + i] = rd32(E1000_PSRTYPE(i + 4));
+ for (i = 0; i < 12; i++)
+ regs_buff[571 + i] = rd32(E1000_RDBAL(i + 4));
+ for (i = 0; i < 12; i++)
+ regs_buff[583 + i] = rd32(E1000_RDBAH(i + 4));
+ for (i = 0; i < 12; i++)
+ regs_buff[595 + i] = rd32(E1000_RDLEN(i + 4));
+ for (i = 0; i < 12; i++)
+ regs_buff[607 + i] = rd32(E1000_RDH(i + 4));
+ for (i = 0; i < 12; i++)
+ regs_buff[619 + i] = rd32(E1000_RDT(i + 4));
+ for (i = 0; i < 12; i++)
+ regs_buff[631 + i] = rd32(E1000_RXDCTL(i + 4));
+
+ for (i = 0; i < 12; i++)
+ regs_buff[643 + i] = rd32(E1000_TDBAL(i + 4));
+ for (i = 0; i < 12; i++)
+ regs_buff[655 + i] = rd32(E1000_TDBAH(i + 4));
+ for (i = 0; i < 12; i++)
+ regs_buff[667 + i] = rd32(E1000_TDLEN(i + 4));
+ for (i = 0; i < 12; i++)
+ regs_buff[679 + i] = rd32(E1000_TDH(i + 4));
+ for (i = 0; i < 12; i++)
+ regs_buff[691 + i] = rd32(E1000_TDT(i + 4));
+ for (i = 0; i < 12; i++)
+ regs_buff[703 + i] = rd32(E1000_TXDCTL(i + 4));
+ for (i = 0; i < 12; i++)
+ regs_buff[715 + i] = rd32(E1000_TDWBAL(i + 4));
+ for (i = 0; i < 12; i++)
+ regs_buff[727 + i] = rd32(E1000_TDWBAH(i + 4));
+ }
+
+ if (hw->mac.type == e1000_i210 || hw->mac.type == e1000_i211)
+ regs_buff[739] = rd32(E1000_I210_RR2DCDELAY);
}
static int igb_get_eeprom_len(struct net_device *netdev)
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 39f33afc479c..b4df3e319467 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -753,6 +753,7 @@ u32 igb_rd32(struct e1000_hw *hw, u32 reg)
struct net_device *netdev = igb->netdev;
hw->hw_addr = NULL;
netdev_err(netdev, "PCIe link lost\n");
+ WARN(1, "igb: Failed to read reg 0x%x!\n", reg);
}
return value;
@@ -2577,11 +2578,11 @@ static int igb_offload_cbs(struct igb_adapter *adapter,
#define VLAN_PRIO_FULL_MASK (0x07)
static int igb_parse_cls_flower(struct igb_adapter *adapter,
- struct tc_cls_flower_offload *f,
+ struct flow_cls_offload *f,
int traffic_class,
struct igb_nfc_filter *input)
{
- struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
+ struct flow_rule *rule = flow_cls_offload_flow_rule(f);
struct flow_dissector *dissector = rule->match.dissector;
struct netlink_ext_ack *extack = f->common.extack;
@@ -2659,7 +2660,7 @@ static int igb_parse_cls_flower(struct igb_adapter *adapter,
}
static int igb_configure_clsflower(struct igb_adapter *adapter,
- struct tc_cls_flower_offload *cls_flower)
+ struct flow_cls_offload *cls_flower)
{
struct netlink_ext_ack *extack = cls_flower->common.extack;
struct igb_nfc_filter *filter, *f;
@@ -2721,7 +2722,7 @@ err_parse:
}
static int igb_delete_clsflower(struct igb_adapter *adapter,
- struct tc_cls_flower_offload *cls_flower)
+ struct flow_cls_offload *cls_flower)
{
struct igb_nfc_filter *filter;
int err;
@@ -2751,14 +2752,14 @@ out:
}
static int igb_setup_tc_cls_flower(struct igb_adapter *adapter,
- struct tc_cls_flower_offload *cls_flower)
+ struct flow_cls_offload *cls_flower)
{
switch (cls_flower->command) {
- case TC_CLSFLOWER_REPLACE:
+ case FLOW_CLS_REPLACE:
return igb_configure_clsflower(adapter, cls_flower);
- case TC_CLSFLOWER_DESTROY:
+ case FLOW_CLS_DESTROY:
return igb_delete_clsflower(adapter, cls_flower);
- case TC_CLSFLOWER_STATS:
+ case FLOW_CLS_STATS:
return -EOPNOTSUPP;
default:
return -EOPNOTSUPP;
@@ -2782,25 +2783,6 @@ static int igb_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
}
}
-static int igb_setup_tc_block(struct igb_adapter *adapter,
- struct tc_block_offload *f)
-{
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
- return -EOPNOTSUPP;
-
- switch (f->command) {
- case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block, igb_setup_tc_block_cb,
- adapter, adapter, f->extack);
- case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block, igb_setup_tc_block_cb,
- adapter);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-}
-
static int igb_offload_txtime(struct igb_adapter *adapter,
struct tc_etf_qopt_offload *qopt)
{
@@ -2824,6 +2806,8 @@ static int igb_offload_txtime(struct igb_adapter *adapter,
return 0;
}
+static LIST_HEAD(igb_block_cb_list);
+
static int igb_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data)
{
@@ -2833,7 +2817,11 @@ static int igb_setup_tc(struct net_device *dev, enum tc_setup_type type,
case TC_SETUP_QDISC_CBS:
return igb_offload_cbs(adapter, type_data);
case TC_SETUP_BLOCK:
- return igb_setup_tc_block(adapter, type_data);
+ return flow_block_cb_setup_simple(type_data,
+ &igb_block_cb_list,
+ igb_setup_tc_block_cb,
+ adapter, adapter, true);
+
case TC_SETUP_QDISC_ETF:
return igb_offload_txtime(adapter, type_data);
@@ -5687,6 +5675,7 @@ static void igb_tx_ctxtdesc(struct igb_ring *tx_ring,
*/
if (tx_ring->launchtime_enable) {
ts = ns_to_timespec64(first->skb->tstamp);
+ first->skb->tstamp = 0;
context_desc->seqnum_seed = cpu_to_le32(ts.tv_nsec / 32);
} else {
context_desc->seqnum_seed = 0;
@@ -6695,7 +6684,7 @@ static int __igb_notify_dca(struct device *dev, void *data)
igb_setup_dca(adapter);
break;
}
- /* Fall Through since DCA is disabled. */
+ /* Fall Through - since DCA is disabled. */
case DCA_PROVIDER_REMOVE:
if (adapter->flags & IGB_FLAG_DCA_ENABLED) {
/* without this a class_device is left
diff --git a/drivers/net/ethernet/intel/igc/igc_base.c b/drivers/net/ethernet/intel/igc/igc_base.c
index 51a8b8769c67..59258d791106 100644
--- a/drivers/net/ethernet/intel/igc/igc_base.c
+++ b/drivers/net/ethernet/intel/igc/igc_base.c
@@ -10,50 +10,6 @@
#include "igc.h"
/**
- * igc_set_pcie_completion_timeout - set pci-e completion timeout
- * @hw: pointer to the HW structure
- */
-static s32 igc_set_pcie_completion_timeout(struct igc_hw *hw)
-{
- u32 gcr = rd32(IGC_GCR);
- u16 pcie_devctl2;
- s32 ret_val = 0;
-
- /* only take action if timeout value is defaulted to 0 */
- if (gcr & IGC_GCR_CMPL_TMOUT_MASK)
- goto out;
-
- /* if capabilities version is type 1 we can write the
- * timeout of 10ms to 200ms through the GCR register
- */
- if (!(gcr & IGC_GCR_CAP_VER2)) {
- gcr |= IGC_GCR_CMPL_TMOUT_10ms;
- goto out;
- }
-
- /* for version 2 capabilities we need to write the config space
- * directly in order to set the completion timeout value for
- * 16ms to 55ms
- */
- ret_val = igc_read_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2,
- &pcie_devctl2);
- if (ret_val)
- goto out;
-
- pcie_devctl2 |= PCIE_DEVICE_CONTROL2_16ms;
-
- ret_val = igc_write_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2,
- &pcie_devctl2);
-out:
- /* disable completion timeout resend */
- gcr &= ~IGC_GCR_CMPL_TMOUT_RESEND;
-
- wr32(IGC_GCR, gcr);
-
- return ret_val;
-}
-
-/**
* igc_reset_hw_base - Reset hardware
* @hw: pointer to the HW structure
*
@@ -72,11 +28,6 @@ static s32 igc_reset_hw_base(struct igc_hw *hw)
if (ret_val)
hw_dbg("PCI-E Master disable polling has failed.\n");
- /* set the completion timeout for interface */
- ret_val = igc_set_pcie_completion_timeout(hw);
- if (ret_val)
- hw_dbg("PCI-E Set completion timeout has failed.\n");
-
hw_dbg("Masking off all interrupts\n");
wr32(IGC_IMC, 0xffffffff);
diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h
index a9a30268de59..fc0ccfe38a20 100644
--- a/drivers/net/ethernet/intel/igc/igc_defines.h
+++ b/drivers/net/ethernet/intel/igc/igc_defines.h
@@ -5,8 +5,8 @@
#define _IGC_DEFINES_H_
/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
-#define REQ_TX_DESCRIPTOR_MULTIPLE 8
-#define REQ_RX_DESCRIPTOR_MULTIPLE 8
+#define REQ_TX_DESCRIPTOR_MULTIPLE 8
+#define REQ_RX_DESCRIPTOR_MULTIPLE 8
#define IGC_CTRL_EXT_DRV_LOAD 0x10000000 /* Drv loaded bit for FW */
@@ -29,12 +29,6 @@
/* Status of Master requests. */
#define IGC_STATUS_GIO_MASTER_ENABLE 0x00080000
-/* PCI Express Control */
-#define IGC_GCR_CMPL_TMOUT_MASK 0x0000F000
-#define IGC_GCR_CMPL_TMOUT_10ms 0x00001000
-#define IGC_GCR_CMPL_TMOUT_RESEND 0x00010000
-#define IGC_GCR_CAP_VER2 0x00040000
-
/* Receive Address
* Number of high/low register pairs in the RAR. The RAR (Receive Address
* Registers) holds the directed and multicast addresses that we monitor.
@@ -72,6 +66,9 @@
#define IGC_CONNSW_AUTOSENSE_EN 0x1
+/* As per the EAS the maximum supported size is 9.5KB (9728 bytes) */
+#define MAX_JUMBO_FRAME_SIZE 0x2600
+
/* PBA constants */
#define IGC_PBA_34K 0x0022
@@ -264,9 +261,6 @@
#define IGC_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */
#define IGC_TCTL_MULR 0x10000000 /* Multiple request support */
-#define IGC_CT_SHIFT 4
-#define IGC_COLLISION_THRESHOLD 15
-
/* Flow Control Constants */
#define FLOW_CONTROL_ADDRESS_LOW 0x00C28001
#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
@@ -398,7 +392,7 @@
#define IGC_MDIC_ERROR 0x40000000
#define IGC_MDIC_DEST 0x80000000
-#define IGC_N0_QUEUE -1
+#define IGC_N0_QUEUE -1
#define IGC_MAX_MAC_HDR_LEN 127
#define IGC_MAX_NETWORK_HDR_LEN 511
diff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ethernet/intel/igc/igc_hw.h
index 7c88b7bd4799..1039a224ac80 100644
--- a/drivers/net/ethernet/intel/igc/igc_hw.h
+++ b/drivers/net/ethernet/intel/igc/igc_hw.h
@@ -114,11 +114,8 @@ struct igc_nvm_operations {
struct igc_phy_operations {
s32 (*acquire)(struct igc_hw *hw);
- s32 (*check_polarity)(struct igc_hw *hw);
s32 (*check_reset_block)(struct igc_hw *hw);
s32 (*force_speed_duplex)(struct igc_hw *hw);
- s32 (*get_cfg_done)(struct igc_hw *hw);
- s32 (*get_cable_length)(struct igc_hw *hw);
s32 (*get_phy_info)(struct igc_hw *hw);
s32 (*read_reg)(struct igc_hw *hw, u32 address, u16 *data);
void (*release)(struct igc_hw *hw);
diff --git a/drivers/net/ethernet/intel/igc/igc_mac.c b/drivers/net/ethernet/intel/igc/igc_mac.c
index f7683d3ae47c..ba4646737288 100644
--- a/drivers/net/ethernet/intel/igc/igc_mac.c
+++ b/drivers/net/ethernet/intel/igc/igc_mac.c
@@ -8,7 +8,6 @@
#include "igc_hw.h"
/* forward declaration */
-static s32 igc_set_default_fc(struct igc_hw *hw);
static s32 igc_set_fc_watermarks(struct igc_hw *hw);
/**
@@ -96,13 +95,10 @@ s32 igc_setup_link(struct igc_hw *hw)
goto out;
/* If requested flow control is set to default, set flow control
- * based on the EEPROM flow control settings.
+ * to the both 'rx' and 'tx' pause frames.
*/
- if (hw->fc.requested_mode == igc_fc_default) {
- ret_val = igc_set_default_fc(hw);
- if (ret_val)
- goto out;
- }
+ if (hw->fc.requested_mode == igc_fc_default)
+ hw->fc.requested_mode = igc_fc_full;
/* We want to save off the original Flow Control configuration just
* in case we get disconnected and then reconnected into a different
@@ -136,19 +132,6 @@ out:
}
/**
- * igc_set_default_fc - Set flow control default values
- * @hw: pointer to the HW structure
- *
- * Read the EEPROM for the default values for flow control and store the
- * values.
- */
-static s32 igc_set_default_fc(struct igc_hw *hw)
-{
- hw->fc.requested_mode = igc_fc_full;
- return 0;
-}
-
-/**
* igc_force_mac_fc - Force the MAC's flow control settings
* @hw: pointer to the HW structure
*
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index 34fa0e60a780..93f3b4e6185b 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -72,6 +72,27 @@ void igc_reset(struct igc_adapter *adapter)
{
struct pci_dev *pdev = adapter->pdev;
struct igc_hw *hw = &adapter->hw;
+ struct igc_fc_info *fc = &hw->fc;
+ u32 pba, hwm;
+
+ /* Repartition PBA for greater than 9k MTU if required */
+ pba = IGC_PBA_34K;
+
+ /* flow control settings
+ * The high water mark must be low enough to fit one full frame
+ * after transmitting the pause frame. As such we must have enough
+ * space to allow for us to complete our current transmit and then
+ * receive the frame that is in progress from the link partner.
+ * Set it to:
+ * - the full Rx FIFO size minus one full Tx plus one full Rx frame
+ */
+ hwm = (pba << 10) - (adapter->max_frame_size + MAX_JUMBO_FRAME_SIZE);
+
+ fc->high_water = hwm & 0xFFFFFFF0; /* 16-byte granularity */
+ fc->low_water = fc->high_water - 16;
+ fc->pause_time = 0xFFFF;
+ fc->send_xon = 1;
+ fc->current_mode = fc->requested_mode;
hw->mac.ops.reset_hw(hw);
@@ -3934,6 +3955,7 @@ u32 igc_rd32(struct igc_hw *hw, u32 reg)
hw->hw_addr = NULL;
netif_device_detach(netdev);
netdev_err(netdev, "PCIe link lost, device now detached\n");
+ WARN(1, "igc: Failed to read reg 0x%x!\n", reg);
}
return value;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index 08d85e336bd4..39e73ad60352 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -50,8 +50,6 @@
#define IXGBE_MAX_RXD 4096
#define IXGBE_MIN_RXD 64
-#define IXGBE_ETH_P_LLDP 0x88CC
-
/* flow control */
#define IXGBE_MIN_FCRTL 0x40
#define IXGBE_MAX_FCRTL 0x7FF80
@@ -635,6 +633,7 @@ struct ixgbe_adapter {
/* XDP */
int num_xdp_queues;
struct ixgbe_ring *xdp_ring[MAX_XDP_QUEUES];
+ unsigned long *af_xdp_zc_qps; /* tracks AF_XDP ZC enabled rings */
/* TX */
struct ixgbe_ring *tx_ring[MAX_TX_QUEUES] ____cacheline_aligned_in_smp;
@@ -774,11 +773,6 @@ struct ixgbe_adapter {
#ifdef CONFIG_IXGBE_IPSEC
struct ixgbe_ipsec *ipsec;
#endif /* CONFIG_IXGBE_IPSEC */
-
- /* AF_XDP zero-copy */
- struct xdp_umem **xsk_umems;
- u16 num_xsk_umems_used;
- u16 num_xsk_umems;
};
static inline u8 ixgbe_max_rss_indices(struct ixgbe_adapter *adapter)
@@ -1039,4 +1033,10 @@ static inline int ixgbe_ipsec_vf_add_sa(struct ixgbe_adapter *adapter,
static inline int ixgbe_ipsec_vf_del_sa(struct ixgbe_adapter *adapter,
u32 *mbuf, u32 vf) { return -EACCES; }
#endif /* CONFIG_IXGBE_IPSEC */
+
+static inline bool ixgbe_enabled_xdp_adapter(struct ixgbe_adapter *adapter)
+{
+ return !!adapter->xdp_prog;
+}
+
#endif /* _IXGBE_H_ */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
index acba067cc15a..7c52ae8ac005 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
@@ -3226,7 +3226,8 @@ static int ixgbe_get_module_info(struct net_device *dev,
page_swap = true;
}
- if (sff8472_rev == IXGBE_SFF_SFF_8472_UNSUP || page_swap) {
+ if (sff8472_rev == IXGBE_SFF_SFF_8472_UNSUP || page_swap ||
+ !(addr_mode & IXGBE_SFF_DDM_IMPLEMENTED)) {
/* We have a SFP, but it does not support SFF-8472 */
modinfo->type = ETH_MODULE_SFF_8079;
modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c
index ff85ce5791a3..31629fc7e820 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c
@@ -842,6 +842,9 @@ void ixgbe_ipsec_vf_clear(struct ixgbe_adapter *adapter, u32 vf)
struct ixgbe_ipsec *ipsec = adapter->ipsec;
int i;
+ if (!ipsec)
+ return;
+
/* search rx sa table */
for (i = 0; i < IXGBE_IPSEC_MAX_SA_COUNT && ipsec->num_rx_sa; i++) {
if (!ipsec->rx_tbl[i].used)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 57fd9ee6de66..cbaf712d6529 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -6288,6 +6288,10 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter,
if (ixgbe_init_rss_key(adapter))
return -ENOMEM;
+ adapter->af_xdp_zc_qps = bitmap_zalloc(MAX_XDP_QUEUES, GFP_KERNEL);
+ if (!adapter->af_xdp_zc_qps)
+ return -ENOMEM;
+
/* Set MAC specific capability flags and exceptions */
switch (hw->mac.type) {
case ixgbe_mac_82598EB:
@@ -9603,27 +9607,6 @@ static int ixgbe_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
}
}
-static int ixgbe_setup_tc_block(struct net_device *dev,
- struct tc_block_offload *f)
-{
- struct ixgbe_adapter *adapter = netdev_priv(dev);
-
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
- return -EOPNOTSUPP;
-
- switch (f->command) {
- case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block, ixgbe_setup_tc_block_cb,
- adapter, adapter, f->extack);
- case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block, ixgbe_setup_tc_block_cb,
- adapter);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-}
-
static int ixgbe_setup_tc_mqprio(struct net_device *dev,
struct tc_mqprio_qopt *mqprio)
{
@@ -9631,12 +9614,19 @@ static int ixgbe_setup_tc_mqprio(struct net_device *dev,
return ixgbe_setup_tc(dev, mqprio->num_tc);
}
+static LIST_HEAD(ixgbe_block_cb_list);
+
static int __ixgbe_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data)
{
+ struct ixgbe_adapter *adapter = netdev_priv(dev);
+
switch (type) {
case TC_SETUP_BLOCK:
- return ixgbe_setup_tc_block(dev, type_data);
+ return flow_block_cb_setup_simple(type_data,
+ &ixgbe_block_cb_list,
+ ixgbe_setup_tc_block_cb,
+ adapter, adapter, true);
case TC_SETUP_QDISC_MQPRIO:
return ixgbe_setup_tc_mqprio(dev, type_data);
default:
@@ -11161,6 +11151,7 @@ err_sw_init:
kfree(adapter->jump_tables[0]);
kfree(adapter->mac_table);
kfree(adapter->rss_key);
+ bitmap_free(adapter->af_xdp_zc_qps);
err_ioremap:
disable_dev = !test_and_set_bit(__IXGBE_DISABLED, &adapter->state);
free_netdev(netdev);
@@ -11249,6 +11240,7 @@ static void ixgbe_remove(struct pci_dev *pdev)
kfree(adapter->mac_table);
kfree(adapter->rss_key);
+ bitmap_free(adapter->af_xdp_zc_qps);
disable_dev = !test_and_set_bit(__IXGBE_DISABLED, &adapter->state);
free_netdev(netdev);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
index 214b01085718..6544c4539c0d 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
@@ -45,6 +45,7 @@
#define IXGBE_SFF_SOFT_RS_SELECT_10G 0x8
#define IXGBE_SFF_SOFT_RS_SELECT_1G 0x0
#define IXGBE_SFF_ADDRESSING_MODE 0x4
+#define IXGBE_SFF_DDM_IMPLEMENTED 0x40
#define IXGBE_SFF_QSFP_DA_ACTIVE_CABLE 0x1
#define IXGBE_SFF_QSFP_DA_PASSIVE_CABLE 0x8
#define IXGBE_SFF_QSFP_CONNECTOR_NOT_SEPARABLE 0x23
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
index d81a50dc9535..0be13a90ff79 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
@@ -72,13 +72,13 @@
#define IXGBE_INCPER_SHIFT_82599 24
#define IXGBE_OVERFLOW_PERIOD (HZ * 30)
-#define IXGBE_PTP_TX_TIMEOUT (HZ * 15)
+#define IXGBE_PTP_TX_TIMEOUT (HZ)
-/* half of a one second clock period, for use with PPS signal. We have to use
- * this instead of something pre-defined like IXGBE_PTP_PPS_HALF_SECOND, in
- * order to force at least 64bits of precision for shifting
+/* We use our own definitions instead of NSEC_PER_SEC because we want to mark
+ * the value as a ULL to force precision when bit shifting.
*/
-#define IXGBE_PTP_PPS_HALF_SECOND 500000000ULL
+#define NS_PER_SEC 1000000000ULL
+#define NS_PER_HALF_SEC 500000000ULL
/* In contrast, the X550 controller has two registers, SYSTIMEH and SYSTIMEL
* which contain measurements of seconds and nanoseconds respectively. This
@@ -141,23 +141,26 @@
#define MAX_TIMADJ 0x7FFFFFFF
/**
- * ixgbe_ptp_setup_sdp_x540
+ * ixgbe_ptp_setup_sdp_X540
* @adapter: private adapter structure
*
* this function enables or disables the clock out feature on SDP0 for
- * the X540 device. It will create a 1second periodic output that can
+ * the X540 device. It will create a 1 second periodic output that can
* be used as the PPS (via an interrupt).
*
- * It calculates when the systime will be on an exact second, and then
- * aligns the start of the PPS signal to that value. The shift is
- * necessary because it can change based on the link speed.
+ * It calculates when the system time will be on an exact second, and then
+ * aligns the start of the PPS signal to that value.
+ *
+ * This works by using the cycle counter shift and mult values in reverse, and
+ * assumes that the values we're shifting will not overflow.
*/
-static void ixgbe_ptp_setup_sdp_x540(struct ixgbe_adapter *adapter)
+static void ixgbe_ptp_setup_sdp_X540(struct ixgbe_adapter *adapter)
{
+ struct cyclecounter *cc = &adapter->hw_cc;
struct ixgbe_hw *hw = &adapter->hw;
- int shift = adapter->hw_cc.shift;
u32 esdp, tsauxc, clktiml, clktimh, trgttiml, trgttimh, rem;
- u64 ns = 0, clock_edge = 0;
+ u64 ns = 0, clock_edge = 0, clock_period;
+ unsigned long flags;
/* disable the pin first */
IXGBE_WRITE_REG(hw, IXGBE_TSAUXC, 0x0);
@@ -177,26 +180,33 @@ static void ixgbe_ptp_setup_sdp_x540(struct ixgbe_adapter *adapter)
/* enable the Clock Out feature on SDP0, and allow
* interrupts to occur when the pin changes
*/
- tsauxc = IXGBE_TSAUXC_EN_CLK |
- IXGBE_TSAUXC_SYNCLK |
- IXGBE_TSAUXC_SDP0_INT;
+ tsauxc = (IXGBE_TSAUXC_EN_CLK |
+ IXGBE_TSAUXC_SYNCLK |
+ IXGBE_TSAUXC_SDP0_INT);
- /* clock period (or pulse length) */
- clktiml = (u32)(IXGBE_PTP_PPS_HALF_SECOND << shift);
- clktimh = (u32)((IXGBE_PTP_PPS_HALF_SECOND << shift) >> 32);
-
- /* Account for the cyclecounter wrap-around value by
- * using the converted ns value of the current time to
- * check for when the next aligned second would occur.
+ /* Determine the clock time period to use. This assumes that the
+ * cycle counter shift is small enough to avoid overflow.
*/
- clock_edge |= (u64)IXGBE_READ_REG(hw, IXGBE_SYSTIML);
- clock_edge |= (u64)IXGBE_READ_REG(hw, IXGBE_SYSTIMH) << 32;
- ns = timecounter_cyc2time(&adapter->hw_tc, clock_edge);
+ clock_period = div_u64((NS_PER_HALF_SEC << cc->shift), cc->mult);
+ clktiml = (u32)(clock_period);
+ clktimh = (u32)(clock_period >> 32);
- div_u64_rem(ns, IXGBE_PTP_PPS_HALF_SECOND, &rem);
- clock_edge += ((IXGBE_PTP_PPS_HALF_SECOND - (u64)rem) << shift);
+ /* Read the current clock time, and save the cycle counter value */
+ spin_lock_irqsave(&adapter->tmreg_lock, flags);
+ ns = timecounter_read(&adapter->hw_tc);
+ clock_edge = adapter->hw_tc.cycle_last;
+ spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
+
+ /* Figure out how many seconds to add in order to round up */
+ div_u64_rem(ns, NS_PER_SEC, &rem);
+
+ /* Figure out how many nanoseconds to add to round the clock edge up
+ * to the next full second
+ */
+ rem = (NS_PER_SEC - rem);
- /* specify the initial clock start time */
+ /* Adjust the clock edge to align with the next full second. */
+ clock_edge += div_u64(((u64)rem << cc->shift), cc->mult);
trgttiml = (u32)clock_edge;
trgttimh = (u32)(clock_edge >> 32);
@@ -212,8 +222,100 @@ static void ixgbe_ptp_setup_sdp_x540(struct ixgbe_adapter *adapter)
}
/**
+ * ixgbe_ptp_setup_sdp_X550
+ * @adapter: private adapter structure
+ *
+ * Enable or disable a clock output signal on SDP 0 for X550 hardware.
+ *
+ * Use the target time feature to align the output signal on the next full
+ * second.
+ *
+ * This works by using the cycle counter shift and mult values in reverse, and
+ * assumes that the values we're shifting will not overflow.
+ */
+static void ixgbe_ptp_setup_sdp_X550(struct ixgbe_adapter *adapter)
+{
+ u32 esdp, tsauxc, freqout, trgttiml, trgttimh, rem, tssdp;
+ struct cyclecounter *cc = &adapter->hw_cc;
+ struct ixgbe_hw *hw = &adapter->hw;
+ u64 ns = 0, clock_edge = 0;
+ struct timespec64 ts;
+ unsigned long flags;
+
+ /* disable the pin first */
+ IXGBE_WRITE_REG(hw, IXGBE_TSAUXC, 0x0);
+ IXGBE_WRITE_FLUSH(hw);
+
+ if (!(adapter->flags2 & IXGBE_FLAG2_PTP_PPS_ENABLED))
+ return;
+
+ esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
+
+ /* enable the SDP0 pin as output, and connected to the
+ * native function for Timesync (ClockOut)
+ */
+ esdp |= IXGBE_ESDP_SDP0_DIR |
+ IXGBE_ESDP_SDP0_NATIVE;
+
+ /* enable the Clock Out feature on SDP0, and use Target Time 0 to
+ * enable generation of interrupts on the clock change.
+ */
+#define IXGBE_TSAUXC_DIS_TS_CLEAR 0x40000000
+ tsauxc = (IXGBE_TSAUXC_EN_CLK | IXGBE_TSAUXC_ST0 |
+ IXGBE_TSAUXC_EN_TT0 | IXGBE_TSAUXC_SDP0_INT |
+ IXGBE_TSAUXC_DIS_TS_CLEAR);
+
+ tssdp = (IXGBE_TSSDP_TS_SDP0_EN |
+ IXGBE_TSSDP_TS_SDP0_CLK0);
+
+ /* Determine the clock time period to use. This assumes that the
+ * cycle counter shift is small enough to avoid overflowing a 32bit
+ * value.
+ */
+ freqout = div_u64(NS_PER_HALF_SEC << cc->shift, cc->mult);
+
+ /* Read the current clock time, and save the cycle counter value */
+ spin_lock_irqsave(&adapter->tmreg_lock, flags);
+ ns = timecounter_read(&adapter->hw_tc);
+ clock_edge = adapter->hw_tc.cycle_last;
+ spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
+
+ /* Figure out how far past the next second we are */
+ div_u64_rem(ns, NS_PER_SEC, &rem);
+
+ /* Figure out how many nanoseconds to add to round the clock edge up
+ * to the next full second
+ */
+ rem = (NS_PER_SEC - rem);
+
+ /* Adjust the clock edge to align with the next full second. */
+ clock_edge += div_u64(((u64)rem << cc->shift), cc->mult);
+
+ /* X550 hardware stores the time in 32bits of 'billions of cycles' and
+ * 32bits of 'cycles'. There's no guarantee that cycles represents
+ * nanoseconds. However, we can use the math from a timespec64 to
+ * convert into the hardware representation.
+ *
+ * See ixgbe_ptp_read_X550() for more details.
+ */
+ ts = ns_to_timespec64(clock_edge);
+ trgttiml = (u32)ts.tv_nsec;
+ trgttimh = (u32)ts.tv_sec;
+
+ IXGBE_WRITE_REG(hw, IXGBE_FREQOUT0, freqout);
+ IXGBE_WRITE_REG(hw, IXGBE_TRGTTIML0, trgttiml);
+ IXGBE_WRITE_REG(hw, IXGBE_TRGTTIMH0, trgttimh);
+
+ IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
+ IXGBE_WRITE_REG(hw, IXGBE_TSSDP, tssdp);
+ IXGBE_WRITE_REG(hw, IXGBE_TSAUXC, tsauxc);
+
+ IXGBE_WRITE_FLUSH(hw);
+}
+
+/**
* ixgbe_ptp_read_X550 - read cycle counter value
- * @hw_cc: cyclecounter structure
+ * @cc: cyclecounter structure
*
* This function reads SYSTIME registers. It is called by the cyclecounter
* structure to convert from internal representation into nanoseconds. We need
@@ -221,10 +323,10 @@ static void ixgbe_ptp_setup_sdp_x540(struct ixgbe_adapter *adapter)
* result of SYSTIME is 32bits of "billions of cycles" and 32 bits of
* "cycles", rather than seconds and nanoseconds.
*/
-static u64 ixgbe_ptp_read_X550(const struct cyclecounter *hw_cc)
+static u64 ixgbe_ptp_read_X550(const struct cyclecounter *cc)
{
struct ixgbe_adapter *adapter =
- container_of(hw_cc, struct ixgbe_adapter, hw_cc);
+ container_of(cc, struct ixgbe_adapter, hw_cc);
struct ixgbe_hw *hw = &adapter->hw;
struct timespec64 ts;
@@ -838,6 +940,15 @@ void ixgbe_ptp_rx_rgtstamp(struct ixgbe_q_vector *q_vector,
ixgbe_ptp_convert_to_hwtstamp(adapter, skb_hwtstamps(skb), regval);
}
+/**
+ * ixgbe_ptp_get_ts_config - get current hardware timestamping configuration
+ * @adapter: pointer to adapter structure
+ * @ifr: ioctl data
+ *
+ * This function returns the current timestamping settings. Rather than
+ * attempt to deconstruct registers to fill in the values, simply keep a copy
+ * of the old settings around, and return a copy when requested.
+ */
int ixgbe_ptp_get_ts_config(struct ixgbe_adapter *adapter, struct ifreq *ifr)
{
struct hwtstamp_config *config = &adapter->tstamp_config;
@@ -1253,7 +1364,7 @@ static long ixgbe_ptp_create_clock(struct ixgbe_adapter *adapter)
adapter->ptp_caps.gettimex64 = ixgbe_ptp_gettimex;
adapter->ptp_caps.settime64 = ixgbe_ptp_settime;
adapter->ptp_caps.enable = ixgbe_ptp_feature_enable;
- adapter->ptp_setup_sdp = ixgbe_ptp_setup_sdp_x540;
+ adapter->ptp_setup_sdp = ixgbe_ptp_setup_sdp_X540;
break;
case ixgbe_mac_82599EB:
snprintf(adapter->ptp_caps.name,
@@ -1280,13 +1391,13 @@ static long ixgbe_ptp_create_clock(struct ixgbe_adapter *adapter)
adapter->ptp_caps.n_alarm = 0;
adapter->ptp_caps.n_ext_ts = 0;
adapter->ptp_caps.n_per_out = 0;
- adapter->ptp_caps.pps = 0;
+ adapter->ptp_caps.pps = 1;
adapter->ptp_caps.adjfreq = ixgbe_ptp_adjfreq_X550;
adapter->ptp_caps.adjtime = ixgbe_ptp_adjtime;
adapter->ptp_caps.gettimex64 = ixgbe_ptp_gettimex;
adapter->ptp_caps.settime64 = ixgbe_ptp_settime;
adapter->ptp_caps.enable = ixgbe_ptp_feature_enable;
- adapter->ptp_setup_sdp = NULL;
+ adapter->ptp_setup_sdp = ixgbe_ptp_setup_sdp_X550;
break;
default:
adapter->ptp_clock = NULL;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
index 345701af7749..537dfff585e0 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
@@ -1645,7 +1645,7 @@ int ixgbe_ndo_set_vf_spoofchk(struct net_device *netdev, int vf, bool setting)
IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_LLDP),
(IXGBE_ETQF_FILTER_EN |
IXGBE_ETQF_TX_ANTISPOOF |
- IXGBE_ETH_P_LLDP));
+ ETH_P_LLDP));
IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_FC),
(IXGBE_ETQF_FILTER_EN |
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
index 84f2dba39e36..2be1c4c72435 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
@@ -1067,6 +1067,7 @@ struct ixgbe_nvm_version {
#define IXGBE_AUXSTMPL1 0x08C44 /* Auxiliary Time Stamp 1 register Low - RO */
#define IXGBE_AUXSTMPH1 0x08C48 /* Auxiliary Time Stamp 1 register High - RO */
#define IXGBE_TSIM 0x08C68 /* TimeSync Interrupt Mask Register - RW */
+#define IXGBE_TSSDP 0x0003C /* TimeSync SDP Configuration Register - RW */
/* Diagnostic Registers */
#define IXGBE_RDSTATCTL 0x02C20
@@ -2240,11 +2241,18 @@ enum {
#define IXGBE_RXDCTL_RLPML_EN 0x00008000
#define IXGBE_RXDCTL_VME 0x40000000 /* VLAN mode enable */
-#define IXGBE_TSAUXC_EN_CLK 0x00000004
-#define IXGBE_TSAUXC_SYNCLK 0x00000008
-#define IXGBE_TSAUXC_SDP0_INT 0x00000040
+#define IXGBE_TSAUXC_EN_CLK 0x00000004
+#define IXGBE_TSAUXC_SYNCLK 0x00000008
+#define IXGBE_TSAUXC_SDP0_INT 0x00000040
+#define IXGBE_TSAUXC_EN_TT0 0x00000001
+#define IXGBE_TSAUXC_EN_TT1 0x00000002
+#define IXGBE_TSAUXC_ST0 0x00000010
#define IXGBE_TSAUXC_DISABLE_SYSTIME 0x80000000
+#define IXGBE_TSSDP_TS_SDP0_SEL_MASK 0x000000C0
+#define IXGBE_TSSDP_TS_SDP0_CLK0 0x00000080
+#define IXGBE_TSSDP_TS_SDP0_EN 0x00000100
+
#define IXGBE_TSYNCTXCTL_VALID 0x00000001 /* Tx timestamp valid */
#define IXGBE_TSYNCTXCTL_ENABLED 0x00000010 /* Tx timestamping enabled */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c
index bfe95ce0bd7f..6b609553329f 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c
@@ -14,57 +14,10 @@ struct xdp_umem *ixgbe_xsk_umem(struct ixgbe_adapter *adapter,
bool xdp_on = READ_ONCE(adapter->xdp_prog);
int qid = ring->ring_idx;
- if (!adapter->xsk_umems || !adapter->xsk_umems[qid] ||
- qid >= adapter->num_xsk_umems || !xdp_on)
+ if (!xdp_on || !test_bit(qid, adapter->af_xdp_zc_qps))
return NULL;
- return adapter->xsk_umems[qid];
-}
-
-static int ixgbe_alloc_xsk_umems(struct ixgbe_adapter *adapter)
-{
- if (adapter->xsk_umems)
- return 0;
-
- adapter->num_xsk_umems_used = 0;
- adapter->num_xsk_umems = adapter->num_rx_queues;
- adapter->xsk_umems = kcalloc(adapter->num_xsk_umems,
- sizeof(*adapter->xsk_umems),
- GFP_KERNEL);
- if (!adapter->xsk_umems) {
- adapter->num_xsk_umems = 0;
- return -ENOMEM;
- }
-
- return 0;
-}
-
-static int ixgbe_add_xsk_umem(struct ixgbe_adapter *adapter,
- struct xdp_umem *umem,
- u16 qid)
-{
- int err;
-
- err = ixgbe_alloc_xsk_umems(adapter);
- if (err)
- return err;
-
- adapter->xsk_umems[qid] = umem;
- adapter->num_xsk_umems_used++;
-
- return 0;
-}
-
-static void ixgbe_remove_xsk_umem(struct ixgbe_adapter *adapter, u16 qid)
-{
- adapter->xsk_umems[qid] = NULL;
- adapter->num_xsk_umems_used--;
-
- if (adapter->num_xsk_umems == 0) {
- kfree(adapter->xsk_umems);
- adapter->xsk_umems = NULL;
- adapter->num_xsk_umems = 0;
- }
+ return xdp_get_umem_from_qid(adapter->netdev, qid);
}
static int ixgbe_xsk_umem_dma_map(struct ixgbe_adapter *adapter,
@@ -113,6 +66,7 @@ static int ixgbe_xsk_umem_enable(struct ixgbe_adapter *adapter,
struct xdp_umem *umem,
u16 qid)
{
+ struct net_device *netdev = adapter->netdev;
struct xdp_umem_fq_reuse *reuseq;
bool if_running;
int err;
@@ -120,12 +74,9 @@ static int ixgbe_xsk_umem_enable(struct ixgbe_adapter *adapter,
if (qid >= adapter->num_rx_queues)
return -EINVAL;
- if (adapter->xsk_umems) {
- if (qid >= adapter->num_xsk_umems)
- return -EINVAL;
- if (adapter->xsk_umems[qid])
- return -EBUSY;
- }
+ if (qid >= netdev->real_num_rx_queues ||
+ qid >= netdev->real_num_tx_queues)
+ return -EINVAL;
reuseq = xsk_reuseq_prepare(adapter->rx_ring[0]->count);
if (!reuseq)
@@ -138,14 +89,12 @@ static int ixgbe_xsk_umem_enable(struct ixgbe_adapter *adapter,
return err;
if_running = netif_running(adapter->netdev) &&
- READ_ONCE(adapter->xdp_prog);
+ ixgbe_enabled_xdp_adapter(adapter);
if (if_running)
ixgbe_txrx_ring_disable(adapter, qid);
- err = ixgbe_add_xsk_umem(adapter, umem, qid);
- if (err)
- return err;
+ set_bit(qid, adapter->af_xdp_zc_qps);
if (if_running) {
ixgbe_txrx_ring_enable(adapter, qid);
@@ -161,20 +110,21 @@ static int ixgbe_xsk_umem_enable(struct ixgbe_adapter *adapter,
static int ixgbe_xsk_umem_disable(struct ixgbe_adapter *adapter, u16 qid)
{
+ struct xdp_umem *umem;
bool if_running;
- if (!adapter->xsk_umems || qid >= adapter->num_xsk_umems ||
- !adapter->xsk_umems[qid])
+ umem = xdp_get_umem_from_qid(adapter->netdev, qid);
+ if (!umem)
return -EINVAL;
if_running = netif_running(adapter->netdev) &&
- READ_ONCE(adapter->xdp_prog);
+ ixgbe_enabled_xdp_adapter(adapter);
if (if_running)
ixgbe_txrx_ring_disable(adapter, qid);
- ixgbe_xsk_umem_dma_unmap(adapter, adapter->xsk_umems[qid]);
- ixgbe_remove_xsk_umem(adapter, qid);
+ clear_bit(qid, adapter->af_xdp_zc_qps);
+ ixgbe_xsk_umem_dma_unmap(adapter, umem);
if (if_running)
ixgbe_txrx_ring_enable(adapter, qid);
@@ -621,8 +571,9 @@ static bool ixgbe_xmit_zc(struct ixgbe_ring *xdp_ring, unsigned int budget)
union ixgbe_adv_tx_desc *tx_desc = NULL;
struct ixgbe_tx_buffer *tx_bi;
bool work_done = true;
- u32 len, cmd_type;
+ struct xdp_desc desc;
dma_addr_t dma;
+ u32 cmd_type;
while (budget-- > 0) {
if (unlikely(!ixgbe_desc_unused(xdp_ring)) ||
@@ -631,15 +582,18 @@ static bool ixgbe_xmit_zc(struct ixgbe_ring *xdp_ring, unsigned int budget)
break;
}
- if (!xsk_umem_consume_tx(xdp_ring->xsk_umem, &dma, &len))
+ if (!xsk_umem_consume_tx(xdp_ring->xsk_umem, &desc))
break;
- dma_sync_single_for_device(xdp_ring->dev, dma, len,
+ dma = xdp_umem_get_dma(xdp_ring->xsk_umem, desc.addr);
+
+ dma_sync_single_for_device(xdp_ring->dev, dma, desc.len,
DMA_BIDIRECTIONAL);
tx_bi = &xdp_ring->tx_buffer_info[xdp_ring->next_to_use];
- tx_bi->bytecount = len;
+ tx_bi->bytecount = desc.len;
tx_bi->xdpf = NULL;
+ tx_bi->gso_segs = 1;
tx_desc = IXGBE_TX_DESC(xdp_ring, xdp_ring->next_to_use);
tx_desc->read.buffer_addr = cpu_to_le64(dma);
@@ -648,10 +602,10 @@ static bool ixgbe_xmit_zc(struct ixgbe_ring *xdp_ring, unsigned int budget)
cmd_type = IXGBE_ADVTXD_DTYP_DATA |
IXGBE_ADVTXD_DCMD_DEXT |
IXGBE_ADVTXD_DCMD_IFCS;
- cmd_type |= len | IXGBE_TXD_CMD;
+ cmd_type |= desc.len | IXGBE_TXD_CMD;
tx_desc->read.cmd_type_len = cpu_to_le32(cmd_type);
tx_desc->read.olinfo_status =
- cpu_to_le32(len << IXGBE_ADVTXD_PAYLEN_SHIFT);
+ cpu_to_le32(desc.len << IXGBE_ADVTXD_PAYLEN_SHIFT);
xdp_ring->next_to_use++;
if (xdp_ring->next_to_use == xdp_ring->count)
@@ -704,7 +658,6 @@ bool ixgbe_clean_xdp_tx_irq(struct ixgbe_q_vector *q_vector,
xsk_frames++;
tx_bi->xdpf = NULL;
- total_bytes += tx_bi->bytecount;
tx_bi++;
tx_desc++;
@@ -753,7 +706,7 @@ int ixgbe_xsk_async_xmit(struct net_device *dev, u32 qid)
if (qid >= adapter->num_xdp_queues)
return -ENXIO;
- if (!adapter->xsk_umems || !adapter->xsk_umems[qid])
+ if (!adapter->xdp_ring[qid]->xsk_umem)
return -ENXIO;
ring = adapter->xdp_ring[qid];
diff --git a/drivers/net/ethernet/intel/ixgbevf/ethtool.c b/drivers/net/ethernet/intel/ixgbevf/ethtool.c
index 5399787e07af..54459b69c948 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ethtool.c
+++ b/drivers/net/ethernet/intel/ixgbevf/ethtool.c
@@ -85,22 +85,16 @@ static int ixgbevf_get_link_ksettings(struct net_device *netdev,
struct ethtool_link_ksettings *cmd)
{
struct ixgbevf_adapter *adapter = netdev_priv(netdev);
- struct ixgbe_hw *hw = &adapter->hw;
- u32 link_speed = 0;
- bool link_up;
ethtool_link_ksettings_zero_link_mode(cmd, supported);
ethtool_link_ksettings_add_link_mode(cmd, supported, 10000baseT_Full);
cmd->base.autoneg = AUTONEG_DISABLE;
cmd->base.port = -1;
- hw->mac.get_link_status = 1;
- hw->mac.ops.check_link(hw, &link_speed, &link_up, false);
-
- if (link_up) {
+ if (adapter->link_up) {
__u32 speed = SPEED_10000;
- switch (link_speed) {
+ switch (adapter->link_speed) {
case IXGBE_LINK_SPEED_10GB_FULL:
speed = SPEED_10000;
break;
diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
index d189ed247665..d2b41f9f87f8 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
+++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
@@ -1423,6 +1423,9 @@ static void ixgbevf_update_itr(struct ixgbevf_q_vector *q_vector,
*/
/* what was last interrupt timeslice? */
timepassed_us = q_vector->itr >> 2;
+ if (timepassed_us == 0)
+ return;
+
bytes_perint = bytes / timepassed_us; /* bytes/usec */
switch (itr_setting) {
diff --git a/drivers/net/ethernet/intel/ixgbevf/vf.c b/drivers/net/ethernet/intel/ixgbevf/vf.c
index cd3b81300cc7..d5ce49636548 100644
--- a/drivers/net/ethernet/intel/ixgbevf/vf.c
+++ b/drivers/net/ethernet/intel/ixgbevf/vf.c
@@ -508,9 +508,8 @@ static s32 ixgbevf_update_mc_addr_list_vf(struct ixgbe_hw *hw,
vector_list[i++] = ixgbevf_mta_vector(hw, ha->addr);
}
- ixgbevf_write_msg_read_ack(hw, msgbuf, msgbuf, IXGBE_VFMAILBOX_SIZE);
-
- return 0;
+ return ixgbevf_write_msg_read_ack(hw, msgbuf, msgbuf,
+ IXGBE_VFMAILBOX_SIZE);
}
/**
diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c
index 76b7b7b85e35..0b668357db4d 100644
--- a/drivers/net/ethernet/jme.c
+++ b/drivers/net/ethernet/jme.c
@@ -582,11 +582,6 @@ jme_setup_tx_resources(struct jme_adapter *jme)
if (unlikely(!(txring->bufinf)))
goto err_free_txring;
- /*
- * Initialize Transmit Descriptors
- */
- memset(txring->alloc, 0, TX_RING_ALLOC_SIZE(jme->tx_ring_size));
-
return 0;
err_free_txring:
diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c
index f9bb890733b5..6e73ffe6f928 100644
--- a/drivers/net/ethernet/lantiq_etop.c
+++ b/drivers/net/ethernet/lantiq_etop.c
@@ -1,15 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* Copyright (C) 2011 John Crispin <blogic@openwrt.org>
*/
diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c
index c5dac6bd2be4..f660cc2b8258 100644
--- a/drivers/net/ethernet/marvell/mvmdio.c
+++ b/drivers/net/ethernet/marvell/mvmdio.c
@@ -64,7 +64,7 @@
struct orion_mdio_dev {
void __iomem *regs;
- struct clk *clk[3];
+ struct clk *clk[4];
/*
* If we have access to the error interrupt pin (which is
* somewhat misnamed as it not only reflects internal errors
@@ -321,11 +321,19 @@ static int orion_mdio_probe(struct platform_device *pdev)
for (i = 0; i < ARRAY_SIZE(dev->clk); i++) {
dev->clk[i] = of_clk_get(pdev->dev.of_node, i);
+ if (PTR_ERR(dev->clk[i]) == -EPROBE_DEFER) {
+ ret = -EPROBE_DEFER;
+ goto out_clk;
+ }
if (IS_ERR(dev->clk[i]))
break;
clk_prepare_enable(dev->clk[i]);
}
+ if (!IS_ERR(of_clk_get(pdev->dev.of_node, ARRAY_SIZE(dev->clk))))
+ dev_warn(&pdev->dev, "unsupported number of clocks, limiting to the first "
+ __stringify(ARRAY_SIZE(dev->clk)) "\n");
+
dev->err_interrupt = platform_get_irq(pdev, 0);
if (dev->err_interrupt > 0 &&
resource_size(r) < MVMDIO_ERR_INT_MASK + 4) {
@@ -362,6 +370,7 @@ out_mdio:
if (dev->err_interrupt > 0)
writel(0, dev->regs + MVMDIO_ERR_INT_MASK);
+out_clk:
for (i = 0; i < ARRAY_SIZE(dev->clk); i++) {
if (IS_ERR(dev->clk[i]))
break;
diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index 269bd73be1a0..895bfed26a8a 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -437,6 +437,7 @@ struct mvneta_port {
struct device_node *dn;
unsigned int tx_csum_limit;
struct phylink *phylink;
+ struct phylink_config phylink_config;
struct phy *comphy;
struct mvneta_bm *bm_priv;
@@ -1118,7 +1119,7 @@ static void mvneta_bm_update_mtu(struct mvneta_port *pp, int mtu)
SKB_DATA_ALIGN(MVNETA_RX_BUF_SIZE(bm_pool->pkt_size));
/* Fill entire long pool */
- num = hwbm_pool_add(hwbm_pool, hwbm_pool->size, GFP_ATOMIC);
+ num = hwbm_pool_add(hwbm_pool, hwbm_pool->size);
if (num != hwbm_pool->size) {
WARN(1, "pool %d: %d of %d allocated\n",
bm_pool->id, num, hwbm_pool->size);
@@ -3356,9 +3357,11 @@ static int mvneta_set_mac_addr(struct net_device *dev, void *addr)
return 0;
}
-static void mvneta_validate(struct net_device *ndev, unsigned long *supported,
+static void mvneta_validate(struct phylink_config *config,
+ unsigned long *supported,
struct phylink_link_state *state)
{
+ struct net_device *ndev = to_net_dev(config->dev);
struct mvneta_port *pp = netdev_priv(ndev);
__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
@@ -3408,9 +3411,10 @@ static void mvneta_validate(struct net_device *ndev, unsigned long *supported,
phylink_helper_basex_speed(state);
}
-static int mvneta_mac_link_state(struct net_device *ndev,
+static int mvneta_mac_link_state(struct phylink_config *config,
struct phylink_link_state *state)
{
+ struct net_device *ndev = to_net_dev(config->dev);
struct mvneta_port *pp = netdev_priv(ndev);
u32 gmac_stat;
@@ -3438,8 +3442,9 @@ static int mvneta_mac_link_state(struct net_device *ndev,
return 1;
}
-static void mvneta_mac_an_restart(struct net_device *ndev)
+static void mvneta_mac_an_restart(struct phylink_config *config)
{
+ struct net_device *ndev = to_net_dev(config->dev);
struct mvneta_port *pp = netdev_priv(ndev);
u32 gmac_an = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
@@ -3449,9 +3454,10 @@ static void mvneta_mac_an_restart(struct net_device *ndev)
gmac_an & ~MVNETA_GMAC_INBAND_RESTART_AN);
}
-static void mvneta_mac_config(struct net_device *ndev, unsigned int mode,
- const struct phylink_link_state *state)
+static void mvneta_mac_config(struct phylink_config *config, unsigned int mode,
+ const struct phylink_link_state *state)
{
+ struct net_device *ndev = to_net_dev(config->dev);
struct mvneta_port *pp = netdev_priv(ndev);
u32 new_ctrl0, gmac_ctrl0 = mvreg_read(pp, MVNETA_GMAC_CTRL_0);
u32 new_ctrl2, gmac_ctrl2 = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
@@ -3581,9 +3587,10 @@ static void mvneta_set_eee(struct mvneta_port *pp, bool enable)
mvreg_write(pp, MVNETA_LPI_CTRL_1, lpi_ctl1);
}
-static void mvneta_mac_link_down(struct net_device *ndev, unsigned int mode,
- phy_interface_t interface)
+static void mvneta_mac_link_down(struct phylink_config *config,
+ unsigned int mode, phy_interface_t interface)
{
+ struct net_device *ndev = to_net_dev(config->dev);
struct mvneta_port *pp = netdev_priv(ndev);
u32 val;
@@ -3600,10 +3607,11 @@ static void mvneta_mac_link_down(struct net_device *ndev, unsigned int mode,
mvneta_set_eee(pp, false);
}
-static void mvneta_mac_link_up(struct net_device *ndev, unsigned int mode,
+static void mvneta_mac_link_up(struct phylink_config *config, unsigned int mode,
phy_interface_t interface,
struct phy_device *phy)
{
+ struct net_device *ndev = to_net_dev(config->dev);
struct mvneta_port *pp = netdev_priv(ndev);
u32 val;
@@ -4500,8 +4508,14 @@ static int mvneta_probe(struct platform_device *pdev)
comphy = NULL;
}
- phylink = phylink_create(dev, pdev->dev.fwnode, phy_mode,
- &mvneta_phylink_ops);
+ pp = netdev_priv(dev);
+ spin_lock_init(&pp->lock);
+
+ pp->phylink_config.dev = &dev->dev;
+ pp->phylink_config.type = PHYLINK_NETDEV;
+
+ phylink = phylink_create(&pp->phylink_config, pdev->dev.fwnode,
+ phy_mode, &mvneta_phylink_ops);
if (IS_ERR(phylink)) {
err = PTR_ERR(phylink);
goto err_free_irq;
@@ -4513,8 +4527,6 @@ static int mvneta_probe(struct platform_device *pdev)
dev->ethtool_ops = &mvneta_eth_tool_ops;
- pp = netdev_priv(dev);
- spin_lock_init(&pp->lock);
pp->phylink = phylink;
pp->comphy = comphy;
pp->phy_interface = phy_mode;
diff --git a/drivers/net/ethernet/marvell/mvneta_bm.c b/drivers/net/ethernet/marvell/mvneta_bm.c
index de468e1bdba9..82ee2bcca6fd 100644
--- a/drivers/net/ethernet/marvell/mvneta_bm.c
+++ b/drivers/net/ethernet/marvell/mvneta_bm.c
@@ -190,7 +190,7 @@ struct mvneta_bm_pool *mvneta_bm_pool_use(struct mvneta_bm *priv, u8 pool_id,
SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
hwbm_pool->construct = mvneta_bm_construct;
hwbm_pool->priv = new_pool;
- spin_lock_init(&hwbm_pool->lock);
+ mutex_init(&hwbm_pool->buf_lock);
/* Create new pool */
err = mvneta_bm_pool_create(priv, new_pool);
@@ -201,7 +201,7 @@ struct mvneta_bm_pool *mvneta_bm_pool_use(struct mvneta_bm *priv, u8 pool_id,
}
/* Allocate buffers for this pool */
- num = hwbm_pool_add(hwbm_pool, hwbm_pool->size, GFP_ATOMIC);
+ num = hwbm_pool_add(hwbm_pool, hwbm_pool->size);
if (num != hwbm_pool->size) {
WARN(1, "pool %d: %d of %d allocated\n",
new_pool->id, num, hwbm_pool->size);
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h
index 6171270a016c..4d9564ba68f6 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h
@@ -148,6 +148,8 @@
#define MVPP22_CLS_C2_ATTR2 0x1b6c
#define MVPP22_CLS_C2_ATTR2_RSS_EN BIT(30)
#define MVPP22_CLS_C2_ATTR3 0x1b70
+#define MVPP22_CLS_C2_TCAM_CTRL 0x1b90
+#define MVPP22_CLS_C2_TCAM_BYPASS_FIFO BIT(0)
/* Descriptor Manager Top Registers */
#define MVPP2_RXQ_NUM_REG 0x2040
@@ -327,8 +329,26 @@
#define MVPP22_BM_ADDR_HIGH_VIRT_RLS_MASK 0xff00
#define MVPP22_BM_ADDR_HIGH_VIRT_RLS_SHIFT 8
+/* Packet Processor per-port counters */
+#define MVPP2_OVERRUN_ETH_DROP 0x7000
+#define MVPP2_CLS_ETH_DROP 0x7020
+
/* Hit counters registers */
#define MVPP2_CTRS_IDX 0x7040
+#define MVPP22_CTRS_TX_CTR(port, txq) ((txq) | ((port) << 3) | BIT(7))
+#define MVPP2_TX_DESC_ENQ_CTR 0x7100
+#define MVPP2_TX_DESC_ENQ_TO_DDR_CTR 0x7104
+#define MVPP2_TX_BUFF_ENQ_TO_DDR_CTR 0x7108
+#define MVPP2_TX_DESC_ENQ_HW_FWD_CTR 0x710c
+#define MVPP2_RX_DESC_ENQ_CTR 0x7120
+#define MVPP2_TX_PKTS_DEQ_CTR 0x7130
+#define MVPP2_TX_PKTS_FULL_QUEUE_DROP_CTR 0x7200
+#define MVPP2_TX_PKTS_EARLY_DROP_CTR 0x7204
+#define MVPP2_TX_PKTS_BM_DROP_CTR 0x7208
+#define MVPP2_TX_PKTS_BM_MC_DROP_CTR 0x720c
+#define MVPP2_RX_PKTS_FULL_QUEUE_DROP_CTR 0x7220
+#define MVPP2_RX_PKTS_EARLY_DROP_CTR 0x7224
+#define MVPP2_RX_PKTS_BM_DROP_CTR 0x7228
#define MVPP2_CLS_DEC_TBL_HIT_CTR 0x7700
#define MVPP2_CLS_FLOW_TBL_HIT_CTR 0x7704
@@ -624,6 +644,7 @@
#define MVPP2_N_RFS_RULES (MVPP2_N_RFS_ENTRIES_PER_FLOW * 7)
/* RSS constants */
+#define MVPP22_N_RSS_TABLES 8
#define MVPP22_RSS_TABLE_ENTRIES 32
/* IPv6 max L3 address size */
@@ -725,6 +746,10 @@ enum mvpp2_prs_l3_cast {
/* Definitions */
struct mvpp2_dbgfs_entries;
+struct mvpp2_rss_table {
+ u32 indir[MVPP22_RSS_TABLE_ENTRIES];
+};
+
/* Shared Packet Processor resources */
struct mvpp2 {
/* Shared registers' base addresses */
@@ -788,6 +813,9 @@ struct mvpp2 {
/* Debugfs entries private data */
struct mvpp2_dbgfs_entries *dbgfs_entries;
+
+ /* RSS Indirection tables */
+ struct mvpp2_rss_table *rss_tables[MVPP22_N_RSS_TABLES];
};
struct mvpp2_pcpu_stats {
@@ -905,6 +933,7 @@ struct mvpp2_port {
phy_interface_t phy_interface;
struct phylink *phylink;
+ struct phylink_config phylink_config;
struct phy *comphy;
struct mvpp2_bm_pool *pool_long;
@@ -919,12 +948,14 @@ struct mvpp2_port {
u32 tx_time_coal;
- /* RSS indirection table */
- u32 indir[MVPP22_RSS_TABLE_ENTRIES];
-
/* List of steering rules active on that port */
- struct mvpp2_ethtool_fs *rfs_rules[MVPP2_N_RFS_RULES];
+ struct mvpp2_ethtool_fs *rfs_rules[MVPP2_N_RFS_ENTRIES_PER_FLOW];
int n_rfs_rules;
+
+ /* Each port has its own view of the rss contexts, so that it can number
+ * them from 0
+ */
+ int rss_ctx[MVPP22_N_RSS_TABLES];
};
/* The mvpp2_tx_desc and mvpp2_rx_desc structures describe the
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c
index a57d17ab91f0..35478cba2aa5 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c
@@ -44,17 +44,17 @@ static const struct mvpp2_cls_flow cls_flows[MVPP2_N_PRS_FLOWS] = {
/* TCP over IPv4 flows, Not fragmented, with vlan tag */
MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_NF_TAG,
- MVPP22_CLS_HEK_IP4_5T | MVPP22_CLS_HEK_OPT_VLAN,
+ MVPP22_CLS_HEK_IP4_5T | MVPP22_CLS_HEK_TAGGED,
MVPP2_PRS_RI_L3_IP4 | MVPP2_PRS_RI_L4_TCP,
MVPP2_PRS_IP_MASK),
MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_NF_TAG,
- MVPP22_CLS_HEK_IP4_5T | MVPP22_CLS_HEK_OPT_VLAN,
+ MVPP22_CLS_HEK_IP4_5T | MVPP22_CLS_HEK_TAGGED,
MVPP2_PRS_RI_L3_IP4_OPT | MVPP2_PRS_RI_L4_TCP,
MVPP2_PRS_IP_MASK),
MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_NF_TAG,
- MVPP22_CLS_HEK_IP4_5T | MVPP22_CLS_HEK_OPT_VLAN,
+ MVPP22_CLS_HEK_IP4_5T | MVPP22_CLS_HEK_TAGGED,
MVPP2_PRS_RI_L3_IP4_OTHER | MVPP2_PRS_RI_L4_TCP,
MVPP2_PRS_IP_MASK),
@@ -79,17 +79,17 @@ static const struct mvpp2_cls_flow cls_flows[MVPP2_N_PRS_FLOWS] = {
/* TCP over IPv4 flows, fragmented, with vlan tag */
MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_TAG,
- MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_OPT_VLAN,
+ MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
MVPP2_PRS_RI_L3_IP4 | MVPP2_PRS_RI_L4_TCP,
MVPP2_PRS_IP_MASK),
MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_TAG,
- MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_OPT_VLAN,
+ MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
MVPP2_PRS_RI_L3_IP4_OPT | MVPP2_PRS_RI_L4_TCP,
MVPP2_PRS_IP_MASK),
MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_TAG,
- MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_OPT_VLAN,
+ MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
MVPP2_PRS_RI_L3_IP4_OTHER | MVPP2_PRS_RI_L4_TCP,
MVPP2_PRS_IP_MASK),
@@ -114,17 +114,17 @@ static const struct mvpp2_cls_flow cls_flows[MVPP2_N_PRS_FLOWS] = {
/* UDP over IPv4 flows, Not fragmented, with vlan tag */
MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_NF_TAG,
- MVPP22_CLS_HEK_IP4_5T | MVPP22_CLS_HEK_OPT_VLAN,
+ MVPP22_CLS_HEK_IP4_5T | MVPP22_CLS_HEK_TAGGED,
MVPP2_PRS_RI_L3_IP4 | MVPP2_PRS_RI_L4_UDP,
MVPP2_PRS_IP_MASK),
MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_NF_TAG,
- MVPP22_CLS_HEK_IP4_5T | MVPP22_CLS_HEK_OPT_VLAN,
+ MVPP22_CLS_HEK_IP4_5T | MVPP22_CLS_HEK_TAGGED,
MVPP2_PRS_RI_L3_IP4_OPT | MVPP2_PRS_RI_L4_UDP,
MVPP2_PRS_IP_MASK),
MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_NF_TAG,
- MVPP22_CLS_HEK_IP4_5T | MVPP22_CLS_HEK_OPT_VLAN,
+ MVPP22_CLS_HEK_IP4_5T | MVPP22_CLS_HEK_TAGGED,
MVPP2_PRS_RI_L3_IP4_OTHER | MVPP2_PRS_RI_L4_UDP,
MVPP2_PRS_IP_MASK),
@@ -149,17 +149,17 @@ static const struct mvpp2_cls_flow cls_flows[MVPP2_N_PRS_FLOWS] = {
/* UDP over IPv4 flows, fragmented, with vlan tag */
MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_TAG,
- MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_OPT_VLAN,
+ MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
MVPP2_PRS_RI_L3_IP4 | MVPP2_PRS_RI_L4_UDP,
MVPP2_PRS_IP_MASK),
MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_TAG,
- MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_OPT_VLAN,
+ MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
MVPP2_PRS_RI_L3_IP4_OPT | MVPP2_PRS_RI_L4_UDP,
MVPP2_PRS_IP_MASK),
MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_TAG,
- MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_OPT_VLAN,
+ MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
MVPP2_PRS_RI_L3_IP4_OTHER | MVPP2_PRS_RI_L4_UDP,
MVPP2_PRS_IP_MASK),
@@ -178,12 +178,12 @@ static const struct mvpp2_cls_flow cls_flows[MVPP2_N_PRS_FLOWS] = {
/* TCP over IPv6 flows, not fragmented, with vlan tag */
MVPP2_DEF_FLOW(MVPP22_FLOW_TCP6, MVPP2_FL_IP6_TCP_NF_TAG,
- MVPP22_CLS_HEK_IP6_5T | MVPP22_CLS_HEK_OPT_VLAN,
+ MVPP22_CLS_HEK_IP6_5T | MVPP22_CLS_HEK_TAGGED,
MVPP2_PRS_RI_L3_IP6 | MVPP2_PRS_RI_L4_TCP,
MVPP2_PRS_IP_MASK),
MVPP2_DEF_FLOW(MVPP22_FLOW_TCP6, MVPP2_FL_IP6_TCP_NF_TAG,
- MVPP22_CLS_HEK_IP6_5T | MVPP22_CLS_HEK_OPT_VLAN,
+ MVPP22_CLS_HEK_IP6_5T | MVPP22_CLS_HEK_TAGGED,
MVPP2_PRS_RI_L3_IP6_EXT | MVPP2_PRS_RI_L4_TCP,
MVPP2_PRS_IP_MASK),
@@ -202,13 +202,13 @@ static const struct mvpp2_cls_flow cls_flows[MVPP2_N_PRS_FLOWS] = {
/* TCP over IPv6 flows, fragmented, with vlan tag */
MVPP2_DEF_FLOW(MVPP22_FLOW_TCP6, MVPP2_FL_IP6_TCP_FRAG_TAG,
- MVPP22_CLS_HEK_IP6_2T | MVPP22_CLS_HEK_OPT_VLAN,
+ MVPP22_CLS_HEK_IP6_2T | MVPP22_CLS_HEK_TAGGED,
MVPP2_PRS_RI_L3_IP6 | MVPP2_PRS_RI_IP_FRAG_TRUE |
MVPP2_PRS_RI_L4_TCP,
MVPP2_PRS_IP_MASK),
MVPP2_DEF_FLOW(MVPP22_FLOW_TCP6, MVPP2_FL_IP6_TCP_FRAG_TAG,
- MVPP22_CLS_HEK_IP6_2T | MVPP22_CLS_HEK_OPT_VLAN,
+ MVPP22_CLS_HEK_IP6_2T | MVPP22_CLS_HEK_TAGGED,
MVPP2_PRS_RI_L3_IP6_EXT | MVPP2_PRS_RI_IP_FRAG_TRUE |
MVPP2_PRS_RI_L4_TCP,
MVPP2_PRS_IP_MASK),
@@ -228,12 +228,12 @@ static const struct mvpp2_cls_flow cls_flows[MVPP2_N_PRS_FLOWS] = {
/* UDP over IPv6 flows, not fragmented, with vlan tag */
MVPP2_DEF_FLOW(MVPP22_FLOW_UDP6, MVPP2_FL_IP6_UDP_NF_TAG,
- MVPP22_CLS_HEK_IP6_5T | MVPP22_CLS_HEK_OPT_VLAN,
+ MVPP22_CLS_HEK_IP6_5T | MVPP22_CLS_HEK_TAGGED,
MVPP2_PRS_RI_L3_IP6 | MVPP2_PRS_RI_L4_UDP,
MVPP2_PRS_IP_MASK),
MVPP2_DEF_FLOW(MVPP22_FLOW_UDP6, MVPP2_FL_IP6_UDP_NF_TAG,
- MVPP22_CLS_HEK_IP6_5T | MVPP22_CLS_HEK_OPT_VLAN,
+ MVPP22_CLS_HEK_IP6_5T | MVPP22_CLS_HEK_TAGGED,
MVPP2_PRS_RI_L3_IP6_EXT | MVPP2_PRS_RI_L4_UDP,
MVPP2_PRS_IP_MASK),
@@ -252,13 +252,13 @@ static const struct mvpp2_cls_flow cls_flows[MVPP2_N_PRS_FLOWS] = {
/* UDP over IPv6 flows, fragmented, with vlan tag */
MVPP2_DEF_FLOW(MVPP22_FLOW_UDP6, MVPP2_FL_IP6_UDP_FRAG_TAG,
- MVPP22_CLS_HEK_IP6_2T | MVPP22_CLS_HEK_OPT_VLAN,
+ MVPP22_CLS_HEK_IP6_2T | MVPP22_CLS_HEK_TAGGED,
MVPP2_PRS_RI_L3_IP6 | MVPP2_PRS_RI_IP_FRAG_TRUE |
MVPP2_PRS_RI_L4_UDP,
MVPP2_PRS_IP_MASK),
MVPP2_DEF_FLOW(MVPP22_FLOW_UDP6, MVPP2_FL_IP6_UDP_FRAG_TAG,
- MVPP22_CLS_HEK_IP6_2T | MVPP22_CLS_HEK_OPT_VLAN,
+ MVPP22_CLS_HEK_IP6_2T | MVPP22_CLS_HEK_TAGGED,
MVPP2_PRS_RI_L3_IP6_EXT | MVPP2_PRS_RI_IP_FRAG_TRUE |
MVPP2_PRS_RI_L4_UDP,
MVPP2_PRS_IP_MASK),
@@ -279,15 +279,15 @@ static const struct mvpp2_cls_flow cls_flows[MVPP2_N_PRS_FLOWS] = {
/* IPv4 flows, with vlan tag */
MVPP2_DEF_FLOW(MVPP22_FLOW_IP4, MVPP2_FL_IP4_TAG,
- MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_OPT_VLAN,
+ MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
MVPP2_PRS_RI_L3_IP4,
MVPP2_PRS_RI_L3_PROTO_MASK),
MVPP2_DEF_FLOW(MVPP22_FLOW_IP4, MVPP2_FL_IP4_TAG,
- MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_OPT_VLAN,
+ MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
MVPP2_PRS_RI_L3_IP4_OPT,
MVPP2_PRS_RI_L3_PROTO_MASK),
MVPP2_DEF_FLOW(MVPP22_FLOW_IP4, MVPP2_FL_IP4_TAG,
- MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_OPT_VLAN,
+ MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
MVPP2_PRS_RI_L3_IP4_OTHER,
MVPP2_PRS_RI_L3_PROTO_MASK),
@@ -303,11 +303,11 @@ static const struct mvpp2_cls_flow cls_flows[MVPP2_N_PRS_FLOWS] = {
/* IPv6 flows, with vlan tag */
MVPP2_DEF_FLOW(MVPP22_FLOW_IP6, MVPP2_FL_IP6_TAG,
- MVPP22_CLS_HEK_IP6_2T | MVPP22_CLS_HEK_OPT_VLAN,
+ MVPP22_CLS_HEK_IP6_2T | MVPP22_CLS_HEK_TAGGED,
MVPP2_PRS_RI_L3_IP6,
MVPP2_PRS_RI_L3_PROTO_MASK),
MVPP2_DEF_FLOW(MVPP22_FLOW_IP6, MVPP2_FL_IP6_TAG,
- MVPP22_CLS_HEK_IP6_2T | MVPP22_CLS_HEK_OPT_VLAN,
+ MVPP22_CLS_HEK_IP6_2T | MVPP22_CLS_HEK_TAGGED,
MVPP2_PRS_RI_L3_IP6,
MVPP2_PRS_RI_L3_PROTO_MASK),
@@ -548,6 +548,8 @@ void mvpp2_cls_c2_read(struct mvpp2 *priv, int index,
static int mvpp2_cls_ethtool_flow_to_type(int flow_type)
{
switch (flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS)) {
+ case ETHER_FLOW:
+ return MVPP22_FLOW_ETHERNET;
case TCP_V4_FLOW:
return MVPP22_FLOW_TCP4;
case TCP_V6_FLOW:
@@ -596,7 +598,7 @@ static void mvpp2_cls_flow_init(struct mvpp2 *priv,
mvpp2_cls_flow_eng_set(&fe, MVPP22_CLS_ENGINE_C2);
mvpp2_cls_flow_port_id_sel(&fe, true);
- mvpp2_cls_flow_lu_type_set(&fe, MVPP22_FLOW_ETHERNET);
+ mvpp2_cls_flow_lu_type_set(&fe, MVPP22_CLS_LU_TYPE_ALL);
/* Add all ports */
for (i = 0; i < MVPP2_MAX_PORTS; i++)
@@ -655,6 +657,9 @@ static int mvpp2_flow_set_hek_fields(struct mvpp2_cls_flow_entry *fe,
case MVPP22_CLS_HEK_OPT_VLAN:
field_id = MVPP22_CLS_FIELD_VLAN;
break;
+ case MVPP22_CLS_HEK_OPT_VLAN_PRI:
+ field_id = MVPP22_CLS_FIELD_VLAN_PRI;
+ break;
case MVPP22_CLS_HEK_OPT_IP4SA:
field_id = MVPP22_CLS_FIELD_IP4SA;
break;
@@ -689,6 +694,10 @@ static int mvpp2_cls_hek_field_size(u32 field)
switch (field) {
case MVPP22_CLS_HEK_OPT_MAC_DA:
return 48;
+ case MVPP22_CLS_HEK_OPT_VLAN:
+ return 12;
+ case MVPP22_CLS_HEK_OPT_VLAN_PRI:
+ return 3;
case MVPP22_CLS_HEK_OPT_IP4SA:
case MVPP22_CLS_HEK_OPT_IP4DA:
return 32;
@@ -777,6 +786,9 @@ u16 mvpp2_flow_get_hek_fields(struct mvpp2_cls_flow_entry *fe)
case MVPP22_CLS_FIELD_VLAN:
hash_opts |= MVPP22_CLS_HEK_OPT_VLAN;
break;
+ case MVPP22_CLS_FIELD_VLAN_PRI:
+ hash_opts |= MVPP22_CLS_HEK_OPT_VLAN_PRI;
+ break;
case MVPP22_CLS_FIELD_L3_PROTO:
hash_opts |= MVPP22_CLS_HEK_OPT_L3_PROTO;
break;
@@ -861,7 +873,7 @@ static void mvpp2_port_c2_cls_init(struct mvpp2_port *port)
/* Match on Lookup Type */
c2.tcam[4] |= MVPP22_CLS_C2_TCAM_EN(MVPP22_CLS_C2_LU_TYPE(MVPP2_CLS_LU_TYPE_MASK));
- c2.tcam[4] |= MVPP22_CLS_C2_LU_TYPE(MVPP22_FLOW_ETHERNET);
+ c2.tcam[4] |= MVPP22_CLS_C2_LU_TYPE(MVPP22_CLS_LU_TYPE_ALL);
/* Update RSS status after matching this entry */
c2.act = MVPP22_CLS_C2_ACT_RSS_EN(MVPP22_C2_UPD_LOCK);
@@ -923,6 +935,12 @@ void mvpp2_cls_init(struct mvpp2 *priv)
mvpp2_cls_c2_write(priv, &c2);
}
+ /* Disable the FIFO stages in C2 engine, which are only used in BIST
+ * mode
+ */
+ mvpp2_write(priv, MVPP22_CLS_C2_TCAM_CTRL,
+ MVPP22_CLS_C2_TCAM_BYPASS_FIFO);
+
mvpp2_cls_port_init_flows(priv);
}
@@ -963,12 +981,22 @@ u32 mvpp2_cls_c2_hit_count(struct mvpp2 *priv, int c2_index)
return mvpp2_read(priv, MVPP22_CLS_C2_HIT_CTR);
}
-static void mvpp2_rss_port_c2_enable(struct mvpp2_port *port)
+static void mvpp2_rss_port_c2_enable(struct mvpp2_port *port, u32 ctx)
{
struct mvpp2_cls_c2_entry c2;
+ u8 qh, ql;
mvpp2_cls_c2_read(port->priv, MVPP22_CLS_C2_RSS_ENTRY(port->id), &c2);
+ /* The RxQ number is used to select the RSS table. It that case, we set
+ * it to be the ctx number.
+ */
+ qh = (ctx >> 3) & MVPP22_CLS_C2_ATTR0_QHIGH_MASK;
+ ql = ctx & MVPP22_CLS_C2_ATTR0_QLOW_MASK;
+
+ c2.attr[0] = MVPP22_CLS_C2_ATTR0_QHIGH(qh) |
+ MVPP22_CLS_C2_ATTR0_QLOW(ql);
+
c2.attr[2] |= MVPP22_CLS_C2_ATTR2_RSS_EN;
mvpp2_cls_c2_write(port->priv, &c2);
@@ -977,22 +1005,45 @@ static void mvpp2_rss_port_c2_enable(struct mvpp2_port *port)
static void mvpp2_rss_port_c2_disable(struct mvpp2_port *port)
{
struct mvpp2_cls_c2_entry c2;
+ u8 qh, ql;
mvpp2_cls_c2_read(port->priv, MVPP22_CLS_C2_RSS_ENTRY(port->id), &c2);
+ /* Reset the default destination RxQ to the port's first rx queue. */
+ qh = (port->first_rxq >> 3) & MVPP22_CLS_C2_ATTR0_QHIGH_MASK;
+ ql = port->first_rxq & MVPP22_CLS_C2_ATTR0_QLOW_MASK;
+
+ c2.attr[0] = MVPP22_CLS_C2_ATTR0_QHIGH(qh) |
+ MVPP22_CLS_C2_ATTR0_QLOW(ql);
+
c2.attr[2] &= ~MVPP22_CLS_C2_ATTR2_RSS_EN;
mvpp2_cls_c2_write(port->priv, &c2);
}
-void mvpp22_port_rss_enable(struct mvpp2_port *port)
+static inline int mvpp22_rss_ctx(struct mvpp2_port *port, int port_rss_ctx)
+{
+ return port->rss_ctx[port_rss_ctx];
+}
+
+int mvpp22_port_rss_enable(struct mvpp2_port *port)
{
- mvpp2_rss_port_c2_enable(port);
+ if (mvpp22_rss_ctx(port, 0) < 0)
+ return -EINVAL;
+
+ mvpp2_rss_port_c2_enable(port, mvpp22_rss_ctx(port, 0));
+
+ return 0;
}
-void mvpp22_port_rss_disable(struct mvpp2_port *port)
+int mvpp22_port_rss_disable(struct mvpp2_port *port)
{
+ if (mvpp22_rss_ctx(port, 0) < 0)
+ return -EINVAL;
+
mvpp2_rss_port_c2_disable(port);
+
+ return 0;
}
static void mvpp22_port_c2_lookup_disable(struct mvpp2_port *port, int entry)
@@ -1029,7 +1080,7 @@ static int mvpp2_port_c2_tcam_rule_add(struct mvpp2_port *port,
struct flow_action_entry *act;
struct mvpp2_cls_c2_entry c2;
u8 qh, ql, pmap;
- int index;
+ int index, ctx;
memset(&c2, 0, sizeof(c2));
@@ -1042,13 +1093,13 @@ static int mvpp2_port_c2_tcam_rule_add(struct mvpp2_port *port,
rule->c2_index = c2.index;
- c2.tcam[0] = (rule->c2_tcam & 0xffff) |
+ c2.tcam[3] = (rule->c2_tcam & 0xffff) |
((rule->c2_tcam_mask & 0xffff) << 16);
- c2.tcam[1] = ((rule->c2_tcam >> 16) & 0xffff) |
+ c2.tcam[2] = ((rule->c2_tcam >> 16) & 0xffff) |
(((rule->c2_tcam_mask >> 16) & 0xffff) << 16);
- c2.tcam[2] = ((rule->c2_tcam >> 32) & 0xffff) |
+ c2.tcam[1] = ((rule->c2_tcam >> 32) & 0xffff) |
(((rule->c2_tcam_mask >> 32) & 0xffff) << 16);
- c2.tcam[3] = ((rule->c2_tcam >> 48) & 0xffff) |
+ c2.tcam[0] = ((rule->c2_tcam >> 48) & 0xffff) |
(((rule->c2_tcam_mask >> 48) & 0xffff) << 16);
pmap = BIT(port->id);
@@ -1069,14 +1120,36 @@ static int mvpp2_port_c2_tcam_rule_add(struct mvpp2_port *port,
*/
c2.act = MVPP22_CLS_C2_ACT_COLOR(MVPP22_C2_COL_NO_UPD_LOCK);
+ /* Update RSS status after matching this entry */
+ if (act->queue.ctx)
+ c2.attr[2] |= MVPP22_CLS_C2_ATTR2_RSS_EN;
+
+ /* Always lock the RSS_EN decision. We might have high prio
+ * rules steering to an RXQ, and a lower one steering to RSS,
+ * we don't want the low prio RSS rule overwriting this flag.
+ */
+ c2.act = MVPP22_CLS_C2_ACT_RSS_EN(MVPP22_C2_UPD_LOCK);
+
/* Mark packet as "forwarded to software", needed for RSS */
c2.act |= MVPP22_CLS_C2_ACT_FWD(MVPP22_C2_FWD_SW_LOCK);
c2.act |= MVPP22_CLS_C2_ACT_QHIGH(MVPP22_C2_UPD_LOCK) |
MVPP22_CLS_C2_ACT_QLOW(MVPP22_C2_UPD_LOCK);
- qh = ((act->queue.index + port->first_rxq) >> 3) & MVPP22_CLS_C2_ATTR0_QHIGH_MASK;
- ql = (act->queue.index + port->first_rxq) & MVPP22_CLS_C2_ATTR0_QLOW_MASK;
+ if (act->queue.ctx) {
+ /* Get the global ctx number */
+ ctx = mvpp22_rss_ctx(port, act->queue.ctx);
+ if (ctx < 0)
+ return -EINVAL;
+
+ qh = (ctx >> 3) & MVPP22_CLS_C2_ATTR0_QHIGH_MASK;
+ ql = ctx & MVPP22_CLS_C2_ATTR0_QLOW_MASK;
+ } else {
+ qh = ((act->queue.index + port->first_rxq) >> 3) &
+ MVPP22_CLS_C2_ATTR0_QHIGH_MASK;
+ ql = (act->queue.index + port->first_rxq) &
+ MVPP22_CLS_C2_ATTR0_QLOW_MASK;
+ }
c2.attr[0] = MVPP22_CLS_C2_ATTR0_QHIGH(qh) |
MVPP22_CLS_C2_ATTR0_QLOW(ql);
@@ -1140,6 +1213,9 @@ static int mvpp2_port_flt_rfs_rule_insert(struct mvpp2_port *port,
if (!flow)
return 0;
+ if ((rule->hek_fields & flow->supported_hash_opts) != rule->hek_fields)
+ continue;
+
index = MVPP2_CLS_FLT_C2_RFS(port->id, flow->flow_id, rule->loc);
mvpp2_cls_flow_read(priv, index, &fe);
@@ -1158,7 +1234,44 @@ static int mvpp2_port_flt_rfs_rule_insert(struct mvpp2_port *port,
static int mvpp2_cls_c2_build_match(struct mvpp2_rfs_rule *rule)
{
struct flow_rule *flow = rule->flow;
- int offs = 64;
+ int offs = 0;
+
+ /* The order of insertion in C2 tcam must match the order in which
+ * the fields are found in the header
+ */
+ if (flow_rule_match_key(flow, FLOW_DISSECTOR_KEY_VLAN)) {
+ struct flow_match_vlan match;
+
+ flow_rule_match_vlan(flow, &match);
+ if (match.mask->vlan_id) {
+ rule->hek_fields |= MVPP22_CLS_HEK_OPT_VLAN;
+
+ rule->c2_tcam |= ((u64)match.key->vlan_id) << offs;
+ rule->c2_tcam_mask |= ((u64)match.mask->vlan_id) << offs;
+
+ /* Don't update the offset yet */
+ }
+
+ if (match.mask->vlan_priority) {
+ rule->hek_fields |= MVPP22_CLS_HEK_OPT_VLAN_PRI;
+
+ /* VLAN pri is always at offset 13 relative to the
+ * current offset
+ */
+ rule->c2_tcam |= ((u64)match.key->vlan_priority) <<
+ (offs + 13);
+ rule->c2_tcam_mask |= ((u64)match.mask->vlan_priority) <<
+ (offs + 13);
+ }
+
+ if (match.mask->vlan_dei)
+ return -EOPNOTSUPP;
+
+ /* vlan id and prio always seem to take a full 16-bit slot in
+ * the Header Extracted Key.
+ */
+ offs += 16;
+ }
if (flow_rule_match_key(flow, FLOW_DISSECTOR_KEY_PORTS)) {
struct flow_match_ports match;
@@ -1166,18 +1279,18 @@ static int mvpp2_cls_c2_build_match(struct mvpp2_rfs_rule *rule)
flow_rule_match_ports(flow, &match);
if (match.mask->src) {
rule->hek_fields |= MVPP22_CLS_HEK_OPT_L4SIP;
- offs -= mvpp2_cls_hek_field_size(MVPP22_CLS_HEK_OPT_L4SIP);
rule->c2_tcam |= ((u64)ntohs(match.key->src)) << offs;
rule->c2_tcam_mask |= ((u64)ntohs(match.mask->src)) << offs;
+ offs += mvpp2_cls_hek_field_size(MVPP22_CLS_HEK_OPT_L4SIP);
}
if (match.mask->dst) {
rule->hek_fields |= MVPP22_CLS_HEK_OPT_L4DIP;
- offs -= mvpp2_cls_hek_field_size(MVPP22_CLS_HEK_OPT_L4DIP);
rule->c2_tcam |= ((u64)ntohs(match.key->dst)) << offs;
rule->c2_tcam_mask |= ((u64)ntohs(match.mask->dst)) << offs;
+ offs += mvpp2_cls_hek_field_size(MVPP22_CLS_HEK_OPT_L4DIP);
}
}
@@ -1196,6 +1309,13 @@ static int mvpp2_cls_rfs_parse_rule(struct mvpp2_rfs_rule *rule)
if (act->id != FLOW_ACTION_QUEUE && act->id != FLOW_ACTION_DROP)
return -EOPNOTSUPP;
+ /* When both an RSS context and an queue index are set, the index
+ * is considered as an offset to be added to the indirection table
+ * entries. We don't support this, so reject this rule.
+ */
+ if (act->queue.ctx && act->queue.index)
+ return -EOPNOTSUPP;
+
/* For now, only use the C2 engine which has a HEK size limited to 64
* bits for TCAM matching.
*/
@@ -1212,7 +1332,7 @@ int mvpp2_ethtool_cls_rule_get(struct mvpp2_port *port,
{
struct mvpp2_ethtool_fs *efs;
- if (rxnfc->fs.location >= MVPP2_N_RFS_RULES)
+ if (rxnfc->fs.location >= MVPP2_N_RFS_ENTRIES_PER_FLOW)
return -EINVAL;
efs = port->rfs_rules[rxnfc->fs.location];
@@ -1232,8 +1352,7 @@ int mvpp2_ethtool_cls_rule_ins(struct mvpp2_port *port,
struct mvpp2_ethtool_fs *efs, *old_efs;
int ret = 0;
- if (info->fs.location >= 4 ||
- info->fs.location < 0)
+ if (info->fs.location >= MVPP2_N_RFS_ENTRIES_PER_FLOW)
return -EINVAL;
efs = kzalloc(sizeof(*efs), GFP_KERNEL);
@@ -1242,6 +1361,12 @@ int mvpp2_ethtool_cls_rule_ins(struct mvpp2_port *port,
input.fs = &info->fs;
+ /* We need to manually set the rss_ctx, since this info isn't present
+ * in info->fs
+ */
+ if (info->fs.flow_type & FLOW_RSS)
+ input.rss_ctx = info->rss_context;
+
ethtool_rule = ethtool_rx_flow_rule_create(&input);
if (IS_ERR(ethtool_rule)) {
ret = PTR_ERR(ethtool_rule);
@@ -1250,6 +1375,10 @@ int mvpp2_ethtool_cls_rule_ins(struct mvpp2_port *port,
efs->rule.flow = ethtool_rule->rule;
efs->rule.flow_type = mvpp2_cls_ethtool_flow_to_type(info->fs.flow_type);
+ if (efs->rule.flow_type < 0) {
+ ret = efs->rule.flow_type;
+ goto clean_rule;
+ }
ret = mvpp2_cls_rfs_parse_rule(&efs->rule);
if (ret)
@@ -1328,19 +1457,160 @@ static inline u32 mvpp22_rxfh_indir(struct mvpp2_port *port, u32 rxq)
return port->first_rxq + ((rxq * nrxqs + rxq / cpus) % port->nrxqs);
}
-void mvpp22_rss_fill_table(struct mvpp2_port *port, u32 table)
+static void mvpp22_rss_fill_table(struct mvpp2_port *port,
+ struct mvpp2_rss_table *table,
+ u32 rss_ctx)
{
struct mvpp2 *priv = port->priv;
int i;
for (i = 0; i < MVPP22_RSS_TABLE_ENTRIES; i++) {
- u32 sel = MVPP22_RSS_INDEX_TABLE(table) |
+ u32 sel = MVPP22_RSS_INDEX_TABLE(rss_ctx) |
MVPP22_RSS_INDEX_TABLE_ENTRY(i);
mvpp2_write(priv, MVPP22_RSS_INDEX, sel);
mvpp2_write(priv, MVPP22_RSS_TABLE_ENTRY,
- mvpp22_rxfh_indir(port, port->indir[i]));
+ mvpp22_rxfh_indir(port, table->indir[i]));
+ }
+}
+
+static int mvpp22_rss_context_create(struct mvpp2_port *port, u32 *rss_ctx)
+{
+ struct mvpp2 *priv = port->priv;
+ u32 ctx;
+
+ /* Find the first free RSS table */
+ for (ctx = 0; ctx < MVPP22_N_RSS_TABLES; ctx++) {
+ if (!priv->rss_tables[ctx])
+ break;
+ }
+
+ if (ctx == MVPP22_N_RSS_TABLES)
+ return -EINVAL;
+
+ priv->rss_tables[ctx] = kzalloc(sizeof(*priv->rss_tables[ctx]),
+ GFP_KERNEL);
+ if (!priv->rss_tables[ctx])
+ return -ENOMEM;
+
+ *rss_ctx = ctx;
+
+ /* Set the table width: replace the whole classifier Rx queue number
+ * with the ones configured in RSS table entries.
+ */
+ mvpp2_write(priv, MVPP22_RSS_INDEX, MVPP22_RSS_INDEX_TABLE(ctx));
+ mvpp2_write(priv, MVPP22_RSS_WIDTH, 8);
+
+ mvpp2_write(priv, MVPP22_RSS_INDEX, MVPP22_RSS_INDEX_QUEUE(ctx));
+ mvpp2_write(priv, MVPP22_RXQ2RSS_TABLE, MVPP22_RSS_TABLE_POINTER(ctx));
+
+ return 0;
+}
+
+int mvpp22_port_rss_ctx_create(struct mvpp2_port *port, u32 *port_ctx)
+{
+ u32 rss_ctx;
+ int ret, i;
+
+ ret = mvpp22_rss_context_create(port, &rss_ctx);
+ if (ret)
+ return ret;
+
+ /* Find the first available context number in the port, starting from 1.
+ * Context 0 on each port is reserved for the default context.
+ */
+ for (i = 1; i < MVPP22_N_RSS_TABLES; i++) {
+ if (port->rss_ctx[i] < 0)
+ break;
+ }
+
+ if (i == MVPP22_N_RSS_TABLES)
+ return -EINVAL;
+
+ port->rss_ctx[i] = rss_ctx;
+ *port_ctx = i;
+
+ return 0;
+}
+
+static struct mvpp2_rss_table *mvpp22_rss_table_get(struct mvpp2 *priv,
+ int rss_ctx)
+{
+ if (rss_ctx < 0 || rss_ctx >= MVPP22_N_RSS_TABLES)
+ return NULL;
+
+ return priv->rss_tables[rss_ctx];
+}
+
+int mvpp22_port_rss_ctx_delete(struct mvpp2_port *port, u32 port_ctx)
+{
+ struct mvpp2 *priv = port->priv;
+ struct ethtool_rxnfc *rxnfc;
+ int i, rss_ctx, ret;
+
+ rss_ctx = mvpp22_rss_ctx(port, port_ctx);
+
+ if (rss_ctx < 0 || rss_ctx >= MVPP22_N_RSS_TABLES)
+ return -EINVAL;
+
+ /* Invalidate any active classification rule that use this context */
+ for (i = 0; i < MVPP2_N_RFS_ENTRIES_PER_FLOW; i++) {
+ if (!port->rfs_rules[i])
+ continue;
+
+ rxnfc = &port->rfs_rules[i]->rxnfc;
+ if (!(rxnfc->fs.flow_type & FLOW_RSS) ||
+ rxnfc->rss_context != port_ctx)
+ continue;
+
+ ret = mvpp2_ethtool_cls_rule_del(port, rxnfc);
+ if (ret) {
+ netdev_warn(port->dev,
+ "couldn't remove classification rule %d associated to this context",
+ rxnfc->fs.location);
+ }
}
+
+ kfree(priv->rss_tables[rss_ctx]);
+
+ priv->rss_tables[rss_ctx] = NULL;
+ port->rss_ctx[port_ctx] = -1;
+
+ return 0;
+}
+
+int mvpp22_port_rss_ctx_indir_set(struct mvpp2_port *port, u32 port_ctx,
+ const u32 *indir)
+{
+ int rss_ctx = mvpp22_rss_ctx(port, port_ctx);
+ struct mvpp2_rss_table *rss_table = mvpp22_rss_table_get(port->priv,
+ rss_ctx);
+
+ if (!rss_table)
+ return -EINVAL;
+
+ memcpy(rss_table->indir, indir,
+ MVPP22_RSS_TABLE_ENTRIES * sizeof(rss_table->indir[0]));
+
+ mvpp22_rss_fill_table(port, rss_table, rss_ctx);
+
+ return 0;
+}
+
+int mvpp22_port_rss_ctx_indir_get(struct mvpp2_port *port, u32 port_ctx,
+ u32 *indir)
+{
+ int rss_ctx = mvpp22_rss_ctx(port, port_ctx);
+ struct mvpp2_rss_table *rss_table = mvpp22_rss_table_get(port->priv,
+ rss_ctx);
+
+ if (!rss_table)
+ return -EINVAL;
+
+ memcpy(indir, rss_table->indir,
+ MVPP22_RSS_TABLE_ENTRIES * sizeof(rss_table->indir[0]));
+
+ return 0;
}
int mvpp2_ethtool_rxfh_set(struct mvpp2_port *port, struct ethtool_rxnfc *info)
@@ -1424,32 +1694,32 @@ int mvpp2_ethtool_rxfh_get(struct mvpp2_port *port, struct ethtool_rxnfc *info)
return 0;
}
-void mvpp22_port_rss_init(struct mvpp2_port *port)
+int mvpp22_port_rss_init(struct mvpp2_port *port)
{
- struct mvpp2 *priv = port->priv;
- int i;
+ struct mvpp2_rss_table *table;
+ u32 context = 0;
+ int i, ret;
- /* Set the table width: replace the whole classifier Rx queue number
- * with the ones configured in RSS table entries.
- */
- mvpp2_write(priv, MVPP22_RSS_INDEX, MVPP22_RSS_INDEX_TABLE(port->id));
- mvpp2_write(priv, MVPP22_RSS_WIDTH, 8);
+ for (i = 0; i < MVPP22_N_RSS_TABLES; i++)
+ port->rss_ctx[i] = -1;
- /* The default RxQ is used as a key to select the RSS table to use.
- * We use one RSS table per port.
- */
- mvpp2_write(priv, MVPP22_RSS_INDEX,
- MVPP22_RSS_INDEX_QUEUE(port->first_rxq));
- mvpp2_write(priv, MVPP22_RXQ2RSS_TABLE,
- MVPP22_RSS_TABLE_POINTER(port->id));
+ ret = mvpp22_rss_context_create(port, &context);
+ if (ret)
+ return ret;
+
+ table = mvpp22_rss_table_get(port->priv, context);
+ if (!table)
+ return -EINVAL;
+
+ port->rss_ctx[0] = context;
/* Configure the first table to evenly distribute the packets across
* real Rx Queues. The table entries map a hash to a port Rx Queue.
*/
for (i = 0; i < MVPP22_RSS_TABLE_ENTRIES; i++)
- port->indir[i] = ethtool_rxfh_indir_default(i, port->nrxqs);
+ table->indir[i] = ethtool_rxfh_indir_default(i, port->nrxqs);
- mvpp22_rss_fill_table(port, port->id);
+ mvpp22_rss_fill_table(port, table, mvpp22_rss_ctx(port, 0));
/* Configure default flows */
mvpp2_port_rss_hash_opts_set(port, MVPP22_FLOW_IP4, MVPP22_CLS_HEK_IP4_2T);
@@ -1458,4 +1728,6 @@ void mvpp22_port_rss_init(struct mvpp2_port *port)
mvpp2_port_rss_hash_opts_set(port, MVPP22_FLOW_TCP6, MVPP22_CLS_HEK_IP6_5T);
mvpp2_port_rss_hash_opts_set(port, MVPP22_FLOW_UDP4, MVPP22_CLS_HEK_IP4_5T);
mvpp2_port_rss_hash_opts_set(port, MVPP22_FLOW_UDP6, MVPP22_CLS_HEK_IP6_5T);
+
+ return 0;
}
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.h b/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.h
index 56b617375a65..8867f25afab4 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.h
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.h
@@ -33,15 +33,16 @@ enum mvpp2_cls_engine {
};
#define MVPP22_CLS_HEK_OPT_MAC_DA BIT(0)
-#define MVPP22_CLS_HEK_OPT_VLAN BIT(1)
-#define MVPP22_CLS_HEK_OPT_L3_PROTO BIT(2)
-#define MVPP22_CLS_HEK_OPT_IP4SA BIT(3)
-#define MVPP22_CLS_HEK_OPT_IP4DA BIT(4)
-#define MVPP22_CLS_HEK_OPT_IP6SA BIT(5)
-#define MVPP22_CLS_HEK_OPT_IP6DA BIT(6)
-#define MVPP22_CLS_HEK_OPT_L4SIP BIT(7)
-#define MVPP22_CLS_HEK_OPT_L4DIP BIT(8)
-#define MVPP22_CLS_HEK_N_FIELDS 9
+#define MVPP22_CLS_HEK_OPT_VLAN_PRI BIT(1)
+#define MVPP22_CLS_HEK_OPT_VLAN BIT(2)
+#define MVPP22_CLS_HEK_OPT_L3_PROTO BIT(3)
+#define MVPP22_CLS_HEK_OPT_IP4SA BIT(4)
+#define MVPP22_CLS_HEK_OPT_IP4DA BIT(5)
+#define MVPP22_CLS_HEK_OPT_IP6SA BIT(6)
+#define MVPP22_CLS_HEK_OPT_IP6DA BIT(7)
+#define MVPP22_CLS_HEK_OPT_L4SIP BIT(8)
+#define MVPP22_CLS_HEK_OPT_L4DIP BIT(9)
+#define MVPP22_CLS_HEK_N_FIELDS 10
#define MVPP22_CLS_HEK_L4_OPTS (MVPP22_CLS_HEK_OPT_L4SIP | \
MVPP22_CLS_HEK_OPT_L4DIP)
@@ -59,8 +60,12 @@ enum mvpp2_cls_engine {
#define MVPP22_CLS_HEK_IP6_5T (MVPP22_CLS_HEK_IP6_2T | \
MVPP22_CLS_HEK_L4_OPTS)
+#define MVPP22_CLS_HEK_TAGGED (MVPP22_CLS_HEK_OPT_VLAN | \
+ MVPP22_CLS_HEK_OPT_VLAN_PRI)
+
enum mvpp2_cls_field_id {
MVPP22_CLS_FIELD_MAC_DA = 0x03,
+ MVPP22_CLS_FIELD_VLAN_PRI = 0x05,
MVPP22_CLS_FIELD_VLAN = 0x06,
MVPP22_CLS_FIELD_L3_PROTO = 0x0f,
MVPP22_CLS_FIELD_IP4SA = 0x10,
@@ -180,6 +185,11 @@ enum mvpp2_prs_flow {
/* LU Type defined for all engines, and specified in the flow table */
#define MVPP2_CLS_LU_TYPE_MASK 0x3f
+enum mvpp2_cls_lu_type {
+ /* rule->loc is used as a lu-type for the entries 0 - 62. */
+ MVPP22_CLS_LU_TYPE_ALL = 63,
+};
+
#define MVPP2_N_FLOWS (MVPP2_FL_LAST - MVPP2_FL_START)
struct mvpp2_cls_flow {
@@ -249,11 +259,18 @@ struct mvpp2_cls_lookup_entry {
u32 data;
};
-void mvpp22_rss_fill_table(struct mvpp2_port *port, u32 table);
-void mvpp22_port_rss_init(struct mvpp2_port *port);
+int mvpp22_port_rss_init(struct mvpp2_port *port);
+
+int mvpp22_port_rss_enable(struct mvpp2_port *port);
+int mvpp22_port_rss_disable(struct mvpp2_port *port);
+
+int mvpp22_port_rss_ctx_create(struct mvpp2_port *port, u32 *rss_ctx);
+int mvpp22_port_rss_ctx_delete(struct mvpp2_port *port, u32 rss_ctx);
-void mvpp22_port_rss_enable(struct mvpp2_port *port);
-void mvpp22_port_rss_disable(struct mvpp2_port *port);
+int mvpp22_port_rss_ctx_indir_set(struct mvpp2_port *port, u32 rss_ctx,
+ const u32 *indir);
+int mvpp22_port_rss_ctx_indir_get(struct mvpp2_port *port, u32 rss_ctx,
+ u32 *indir);
int mvpp2_ethtool_rxfh_get(struct mvpp2_port *port, struct ethtool_rxnfc *info);
int mvpp2_ethtool_rxfh_set(struct mvpp2_port *port, struct ethtool_rxnfc *info);
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_debugfs.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_debugfs.c
index 0ee39ea47b6b..274fb07362cb 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_debugfs.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_debugfs.c
@@ -566,6 +566,9 @@ static int mvpp2_dbgfs_prs_entry_init(struct dentry *parent,
debugfs_create_file("hits", 0444, prs_entry_dir, entry,
&mvpp2_dbgfs_prs_hits_fops);
+ debugfs_create_file("pmap", 0444, prs_entry_dir, entry,
+ &mvpp2_dbgfs_prs_pmap_fops);
+
return 0;
}
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
index d8e5241097a9..c51f1d5b550b 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
@@ -56,9 +56,9 @@ static struct {
/* The prototype is added here to be used in start_dev when using ACPI. This
* will be removed once phylink is used for all modes (dt+ACPI).
*/
-static void mvpp2_mac_config(struct net_device *dev, unsigned int mode,
+static void mvpp2_mac_config(struct phylink_config *config, unsigned int mode,
const struct phylink_link_state *state);
-static void mvpp2_mac_link_up(struct net_device *dev, unsigned int mode,
+static void mvpp2_mac_link_up(struct phylink_config *config, unsigned int mode,
phy_interface_t interface, struct phy_device *phy);
/* Queue modes */
@@ -1258,6 +1258,17 @@ static u64 mvpp2_read_count(struct mvpp2_port *port,
return val;
}
+/* Some counters are accessed indirectly by first writing an index to
+ * MVPP2_CTRS_IDX. The index can represent various resources depending on the
+ * register we access, it can be a hit counter for some classification tables,
+ * a counter specific to a rxq, a txq or a buffer pool.
+ */
+static u32 mvpp2_read_index(struct mvpp2 *priv, u32 index, u32 reg)
+{
+ mvpp2_write(priv, MVPP2_CTRS_IDX, index);
+ return mvpp2_read(priv, reg);
+}
+
/* Due to the fact that software statistics and hardware statistics are, by
* design, incremented at different moments in the chain of packet processing,
* it is very likely that incoming packets could have been dropped after being
@@ -1267,7 +1278,7 @@ static u64 mvpp2_read_count(struct mvpp2_port *port,
* Hence, statistics gathered from userspace with ifconfig (software) and
* ethtool (hardware) cannot be compared.
*/
-static const struct mvpp2_ethtool_counter mvpp2_ethtool_regs[] = {
+static const struct mvpp2_ethtool_counter mvpp2_ethtool_mib_regs[] = {
{ MVPP2_MIB_GOOD_OCTETS_RCVD, "good_octets_received", true },
{ MVPP2_MIB_BAD_OCTETS_RCVD, "bad_octets_received" },
{ MVPP2_MIB_CRC_ERRORS_SENT, "crc_errors_sent" },
@@ -1297,31 +1308,114 @@ static const struct mvpp2_ethtool_counter mvpp2_ethtool_regs[] = {
{ MVPP2_MIB_LATE_COLLISION, "late_collision" },
};
+static const struct mvpp2_ethtool_counter mvpp2_ethtool_port_regs[] = {
+ { MVPP2_OVERRUN_ETH_DROP, "rx_fifo_or_parser_overrun_drops" },
+ { MVPP2_CLS_ETH_DROP, "rx_classifier_drops" },
+};
+
+static const struct mvpp2_ethtool_counter mvpp2_ethtool_txq_regs[] = {
+ { MVPP2_TX_DESC_ENQ_CTR, "txq_%d_desc_enqueue" },
+ { MVPP2_TX_DESC_ENQ_TO_DDR_CTR, "txq_%d_desc_enqueue_to_ddr" },
+ { MVPP2_TX_BUFF_ENQ_TO_DDR_CTR, "txq_%d_buff_euqueue_to_ddr" },
+ { MVPP2_TX_DESC_ENQ_HW_FWD_CTR, "txq_%d_desc_hardware_forwarded" },
+ { MVPP2_TX_PKTS_DEQ_CTR, "txq_%d_packets_dequeued" },
+ { MVPP2_TX_PKTS_FULL_QUEUE_DROP_CTR, "txq_%d_queue_full_drops" },
+ { MVPP2_TX_PKTS_EARLY_DROP_CTR, "txq_%d_packets_early_drops" },
+ { MVPP2_TX_PKTS_BM_DROP_CTR, "txq_%d_packets_bm_drops" },
+ { MVPP2_TX_PKTS_BM_MC_DROP_CTR, "txq_%d_packets_rep_bm_drops" },
+};
+
+static const struct mvpp2_ethtool_counter mvpp2_ethtool_rxq_regs[] = {
+ { MVPP2_RX_DESC_ENQ_CTR, "rxq_%d_desc_enqueue" },
+ { MVPP2_RX_PKTS_FULL_QUEUE_DROP_CTR, "rxq_%d_queue_full_drops" },
+ { MVPP2_RX_PKTS_EARLY_DROP_CTR, "rxq_%d_packets_early_drops" },
+ { MVPP2_RX_PKTS_BM_DROP_CTR, "rxq_%d_packets_bm_drops" },
+};
+
+#define MVPP2_N_ETHTOOL_STATS(ntxqs, nrxqs) (ARRAY_SIZE(mvpp2_ethtool_mib_regs) + \
+ ARRAY_SIZE(mvpp2_ethtool_port_regs) + \
+ (ARRAY_SIZE(mvpp2_ethtool_txq_regs) * (ntxqs)) + \
+ (ARRAY_SIZE(mvpp2_ethtool_rxq_regs) * (nrxqs)))
+
static void mvpp2_ethtool_get_strings(struct net_device *netdev, u32 sset,
u8 *data)
{
- if (sset == ETH_SS_STATS) {
- int i;
+ struct mvpp2_port *port = netdev_priv(netdev);
+ int i, q;
- for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_regs); i++)
- strscpy(data + i * ETH_GSTRING_LEN,
- mvpp2_ethtool_regs[i].string, ETH_GSTRING_LEN);
+ if (sset != ETH_SS_STATS)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_mib_regs); i++) {
+ strscpy(data, mvpp2_ethtool_mib_regs[i].string,
+ ETH_GSTRING_LEN);
+ data += ETH_GSTRING_LEN;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_port_regs); i++) {
+ strscpy(data, mvpp2_ethtool_port_regs[i].string,
+ ETH_GSTRING_LEN);
+ data += ETH_GSTRING_LEN;
+ }
+
+ for (q = 0; q < port->ntxqs; q++) {
+ for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_txq_regs); i++) {
+ snprintf(data, ETH_GSTRING_LEN,
+ mvpp2_ethtool_txq_regs[i].string, q);
+ data += ETH_GSTRING_LEN;
+ }
+ }
+
+ for (q = 0; q < port->nrxqs; q++) {
+ for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_rxq_regs); i++) {
+ snprintf(data, ETH_GSTRING_LEN,
+ mvpp2_ethtool_rxq_regs[i].string,
+ q);
+ data += ETH_GSTRING_LEN;
+ }
}
}
+static void mvpp2_read_stats(struct mvpp2_port *port)
+{
+ u64 *pstats;
+ int i, q;
+
+ pstats = port->ethtool_stats;
+
+ for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_mib_regs); i++)
+ *pstats++ += mvpp2_read_count(port, &mvpp2_ethtool_mib_regs[i]);
+
+ for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_port_regs); i++)
+ *pstats++ += mvpp2_read(port->priv,
+ mvpp2_ethtool_port_regs[i].offset +
+ 4 * port->id);
+
+ for (q = 0; q < port->ntxqs; q++)
+ for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_txq_regs); i++)
+ *pstats++ += mvpp2_read_index(port->priv,
+ MVPP22_CTRS_TX_CTR(port->id, i),
+ mvpp2_ethtool_txq_regs[i].offset);
+
+ /* Rxqs are numbered from 0 from the user standpoint, but not from the
+ * driver's. We need to add the port->first_rxq offset.
+ */
+ for (q = 0; q < port->nrxqs; q++)
+ for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_rxq_regs); i++)
+ *pstats++ += mvpp2_read_index(port->priv,
+ port->first_rxq + i,
+ mvpp2_ethtool_rxq_regs[i].offset);
+}
+
static void mvpp2_gather_hw_statistics(struct work_struct *work)
{
struct delayed_work *del_work = to_delayed_work(work);
struct mvpp2_port *port = container_of(del_work, struct mvpp2_port,
stats_work);
- u64 *pstats;
- int i;
mutex_lock(&port->gather_stats_lock);
- pstats = port->ethtool_stats;
- for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_regs); i++)
- *pstats++ += mvpp2_read_count(port, &mvpp2_ethtool_regs[i]);
+ mvpp2_read_stats(port);
/* No need to read again the counters right after this function if it
* was called asynchronously by the user (ie. use of ethtool).
@@ -1345,27 +1439,24 @@ static void mvpp2_ethtool_get_stats(struct net_device *dev,
mutex_lock(&port->gather_stats_lock);
memcpy(data, port->ethtool_stats,
- sizeof(u64) * ARRAY_SIZE(mvpp2_ethtool_regs));
+ sizeof(u64) * MVPP2_N_ETHTOOL_STATS(port->ntxqs, port->nrxqs));
mutex_unlock(&port->gather_stats_lock);
}
static int mvpp2_ethtool_get_sset_count(struct net_device *dev, int sset)
{
+ struct mvpp2_port *port = netdev_priv(dev);
+
if (sset == ETH_SS_STATS)
- return ARRAY_SIZE(mvpp2_ethtool_regs);
+ return MVPP2_N_ETHTOOL_STATS(port->ntxqs, port->nrxqs);
return -EOPNOTSUPP;
}
static void mvpp2_mac_reset_assert(struct mvpp2_port *port)
{
- unsigned int i;
u32 val;
- /* Read the GOP statistics to reset the hardware counters */
- for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_regs); i++)
- mvpp2_read_count(port, &mvpp2_ethtool_regs[i]);
-
val = readl(port->base + MVPP2_GMAC_CTRL_2_REG) |
MVPP2_GMAC_PORT_RESET_MASK;
writel(val, port->base + MVPP2_GMAC_CTRL_2_REG);
@@ -3237,9 +3328,9 @@ static void mvpp2_start_dev(struct mvpp2_port *port)
struct phylink_link_state state = {
.interface = port->phy_interface,
};
- mvpp2_mac_config(port->dev, MLO_AN_INBAND, &state);
- mvpp2_mac_link_up(port->dev, MLO_AN_INBAND, port->phy_interface,
- NULL);
+ mvpp2_mac_config(&port->phylink_config, MLO_AN_INBAND, &state);
+ mvpp2_mac_link_up(&port->phylink_config, MLO_AN_INBAND,
+ port->phy_interface, NULL);
}
netif_tx_start_all_queues(port->dev);
@@ -3954,7 +4045,7 @@ static int mvpp2_ethtool_get_rxnfc(struct net_device *dev,
ret = mvpp2_ethtool_cls_rule_get(port, info);
break;
case ETHTOOL_GRXCLSRLALL:
- for (i = 0; i < MVPP2_N_RFS_RULES; i++) {
+ for (i = 0; i < MVPP2_N_RFS_ENTRIES_PER_FLOW; i++) {
if (port->rfs_rules[i])
rules[loc++] = i;
}
@@ -4000,24 +4091,25 @@ static int mvpp2_ethtool_get_rxfh(struct net_device *dev, u32 *indir, u8 *key,
u8 *hfunc)
{
struct mvpp2_port *port = netdev_priv(dev);
+ int ret = 0;
if (!mvpp22_rss_is_supported())
return -EOPNOTSUPP;
if (indir)
- memcpy(indir, port->indir,
- ARRAY_SIZE(port->indir) * sizeof(port->indir[0]));
+ ret = mvpp22_port_rss_ctx_indir_get(port, 0, indir);
if (hfunc)
*hfunc = ETH_RSS_HASH_CRC32;
- return 0;
+ return ret;
}
static int mvpp2_ethtool_set_rxfh(struct net_device *dev, const u32 *indir,
const u8 *key, const u8 hfunc)
{
struct mvpp2_port *port = netdev_priv(dev);
+ int ret = 0;
if (!mvpp22_rss_is_supported())
return -EOPNOTSUPP;
@@ -4028,15 +4120,58 @@ static int mvpp2_ethtool_set_rxfh(struct net_device *dev, const u32 *indir,
if (key)
return -EOPNOTSUPP;
- if (indir) {
- memcpy(port->indir, indir,
- ARRAY_SIZE(port->indir) * sizeof(port->indir[0]));
- mvpp22_rss_fill_table(port, port->id);
- }
+ if (indir)
+ ret = mvpp22_port_rss_ctx_indir_set(port, 0, indir);
- return 0;
+ return ret;
+}
+
+static int mvpp2_ethtool_get_rxfh_context(struct net_device *dev, u32 *indir,
+ u8 *key, u8 *hfunc, u32 rss_context)
+{
+ struct mvpp2_port *port = netdev_priv(dev);
+ int ret = 0;
+
+ if (!mvpp22_rss_is_supported())
+ return -EOPNOTSUPP;
+
+ if (hfunc)
+ *hfunc = ETH_RSS_HASH_CRC32;
+
+ if (indir)
+ ret = mvpp22_port_rss_ctx_indir_get(port, rss_context, indir);
+
+ return ret;
}
+static int mvpp2_ethtool_set_rxfh_context(struct net_device *dev,
+ const u32 *indir, const u8 *key,
+ const u8 hfunc, u32 *rss_context,
+ bool delete)
+{
+ struct mvpp2_port *port = netdev_priv(dev);
+ int ret;
+
+ if (!mvpp22_rss_is_supported())
+ return -EOPNOTSUPP;
+
+ if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_CRC32)
+ return -EOPNOTSUPP;
+
+ if (key)
+ return -EOPNOTSUPP;
+
+ if (delete)
+ return mvpp22_port_rss_ctx_delete(port, *rss_context);
+
+ if (*rss_context == ETH_RXFH_CONTEXT_ALLOC) {
+ ret = mvpp22_port_rss_ctx_create(port, rss_context);
+ if (ret)
+ return ret;
+ }
+
+ return mvpp22_port_rss_ctx_indir_set(port, *rss_context, indir);
+}
/* Device ops */
static const struct net_device_ops mvpp2_netdev_ops = {
@@ -4073,7 +4208,8 @@ static const struct ethtool_ops mvpp2_eth_tool_ops = {
.get_rxfh_indir_size = mvpp2_ethtool_get_rxfh_indir_size,
.get_rxfh = mvpp2_ethtool_get_rxfh,
.set_rxfh = mvpp2_ethtool_set_rxfh,
-
+ .get_rxfh_context = mvpp2_ethtool_get_rxfh_context,
+ .set_rxfh_context = mvpp2_ethtool_set_rxfh_context,
};
/* Used for PPv2.1, or PPv2.2 with the old Device Tree binding that
@@ -4327,6 +4463,11 @@ static int mvpp2_port_init(struct mvpp2_port *port)
if (err)
goto err_free_percpu;
+ /* Clear all port stats */
+ mvpp2_read_stats(port);
+ memset(port->ethtool_stats, 0,
+ MVPP2_N_ETHTOOL_STATS(port->ntxqs, port->nrxqs) * sizeof(u64));
+
return 0;
err_free_percpu:
@@ -4416,11 +4557,12 @@ static void mvpp2_port_copy_mac_addr(struct net_device *dev, struct mvpp2 *priv,
eth_hw_addr_random(dev);
}
-static void mvpp2_phylink_validate(struct net_device *dev,
+static void mvpp2_phylink_validate(struct phylink_config *config,
unsigned long *supported,
struct phylink_link_state *state)
{
- struct mvpp2_port *port = netdev_priv(dev);
+ struct mvpp2_port *port = container_of(config, struct mvpp2_port,
+ phylink_config);
__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
/* Invalid combinations */
@@ -4544,10 +4686,11 @@ static void mvpp2_gmac_link_state(struct mvpp2_port *port,
state->pause |= MLO_PAUSE_TX;
}
-static int mvpp2_phylink_mac_link_state(struct net_device *dev,
+static int mvpp2_phylink_mac_link_state(struct phylink_config *config,
struct phylink_link_state *state)
{
- struct mvpp2_port *port = netdev_priv(dev);
+ struct mvpp2_port *port = container_of(config, struct mvpp2_port,
+ phylink_config);
if (port->priv->hw_version == MVPP22 && port->gop_id == 0) {
u32 mode = readl(port->base + MVPP22_XLG_CTRL3_REG);
@@ -4563,9 +4706,10 @@ static int mvpp2_phylink_mac_link_state(struct net_device *dev,
return 1;
}
-static void mvpp2_mac_an_restart(struct net_device *dev)
+static void mvpp2_mac_an_restart(struct phylink_config *config)
{
- struct mvpp2_port *port = netdev_priv(dev);
+ struct mvpp2_port *port = container_of(config, struct mvpp2_port,
+ phylink_config);
u32 val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
writel(val | MVPP2_GMAC_IN_BAND_RESTART_AN,
@@ -4750,9 +4894,10 @@ static void mvpp2_gmac_config(struct mvpp2_port *port, unsigned int mode,
}
}
-static void mvpp2_mac_config(struct net_device *dev, unsigned int mode,
+static void mvpp2_mac_config(struct phylink_config *config, unsigned int mode,
const struct phylink_link_state *state)
{
+ struct net_device *dev = to_net_dev(config->dev);
struct mvpp2_port *port = netdev_priv(dev);
bool change_interface = port->phy_interface != state->interface;
@@ -4792,9 +4937,10 @@ static void mvpp2_mac_config(struct net_device *dev, unsigned int mode,
mvpp2_port_enable(port);
}
-static void mvpp2_mac_link_up(struct net_device *dev, unsigned int mode,
+static void mvpp2_mac_link_up(struct phylink_config *config, unsigned int mode,
phy_interface_t interface, struct phy_device *phy)
{
+ struct net_device *dev = to_net_dev(config->dev);
struct mvpp2_port *port = netdev_priv(dev);
u32 val;
@@ -4819,9 +4965,10 @@ static void mvpp2_mac_link_up(struct net_device *dev, unsigned int mode,
netif_tx_wake_all_queues(dev);
}
-static void mvpp2_mac_link_down(struct net_device *dev, unsigned int mode,
- phy_interface_t interface)
+static void mvpp2_mac_link_down(struct phylink_config *config,
+ unsigned int mode, phy_interface_t interface)
{
+ struct net_device *dev = to_net_dev(config->dev);
struct mvpp2_port *port = netdev_priv(dev);
u32 val;
@@ -5002,7 +5149,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
}
port->ethtool_stats = devm_kcalloc(&pdev->dev,
- ARRAY_SIZE(mvpp2_ethtool_regs),
+ MVPP2_N_ETHTOOL_STATS(ntxqs, nrxqs),
sizeof(u64), GFP_KERNEL);
if (!port->ethtool_stats) {
err = -ENOMEM;
@@ -5078,8 +5225,11 @@ static int mvpp2_port_probe(struct platform_device *pdev,
/* Phylink isn't used w/ ACPI as of now */
if (port_node) {
- phylink = phylink_create(dev, port_fwnode, phy_mode,
- &mvpp2_phylink_ops);
+ port->phylink_config.dev = &dev->dev;
+ port->phylink_config.type = PHYLINK_NETDEV;
+
+ phylink = phylink_create(&port->phylink_config, port_fwnode,
+ phy_mode, &mvpp2_phylink_ops);
if (IS_ERR(phylink)) {
err = PTR_ERR(phylink);
goto err_free_port_pcpu;
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c
index 392fd895f278..5692c6087bbb 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c
@@ -312,7 +312,8 @@ static void mvpp2_prs_sram_shift_set(struct mvpp2_prs_entry *pe, int shift,
}
/* Set value */
- pe->sram[MVPP2_BIT_TO_WORD(MVPP2_PRS_SRAM_SHIFT_OFFS)] = shift & MVPP2_PRS_SRAM_SHIFT_MASK;
+ pe->sram[MVPP2_BIT_TO_WORD(MVPP2_PRS_SRAM_SHIFT_OFFS)] |=
+ shift & MVPP2_PRS_SRAM_SHIFT_MASK;
/* Reset and set operation */
mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_SHIFT_OFFS,
@@ -1905,8 +1906,7 @@ static int mvpp2_prs_ip6_init(struct mvpp2 *priv)
}
/* Find tcam entry with matched pair <vid,port> */
-static int mvpp2_prs_vid_range_find(struct mvpp2 *priv, int pmap, u16 vid,
- u16 mask)
+static int mvpp2_prs_vid_range_find(struct mvpp2_port *port, u16 vid, u16 mask)
{
unsigned char byte[2], enable[2];
struct mvpp2_prs_entry pe;
@@ -1914,13 +1914,13 @@ static int mvpp2_prs_vid_range_find(struct mvpp2 *priv, int pmap, u16 vid,
int tid;
/* Go through the all entries with MVPP2_PRS_LU_VID */
- for (tid = MVPP2_PE_VID_FILT_RANGE_START;
- tid <= MVPP2_PE_VID_FILT_RANGE_END; tid++) {
- if (!priv->prs_shadow[tid].valid ||
- priv->prs_shadow[tid].lu != MVPP2_PRS_LU_VID)
+ for (tid = MVPP2_PRS_VID_PORT_FIRST(port->id);
+ tid <= MVPP2_PRS_VID_PORT_LAST(port->id); tid++) {
+ if (!port->priv->prs_shadow[tid].valid ||
+ port->priv->prs_shadow[tid].lu != MVPP2_PRS_LU_VID)
continue;
- mvpp2_prs_init_from_hw(priv, &pe, tid);
+ mvpp2_prs_init_from_hw(port->priv, &pe, tid);
mvpp2_prs_tcam_data_byte_get(&pe, 2, &byte[0], &enable[0]);
mvpp2_prs_tcam_data_byte_get(&pe, 3, &byte[1], &enable[1]);
@@ -1950,7 +1950,7 @@ int mvpp2_prs_vid_entry_add(struct mvpp2_port *port, u16 vid)
memset(&pe, 0, sizeof(pe));
/* Scan TCAM and see if entry with this <vid,port> already exist */
- tid = mvpp2_prs_vid_range_find(priv, (1 << port->id), vid, mask);
+ tid = mvpp2_prs_vid_range_find(port, vid, mask);
reg_val = mvpp2_read(priv, MVPP2_MH_REG(port->id));
if (reg_val & MVPP2_DSA_EXTENDED)
@@ -2008,7 +2008,7 @@ void mvpp2_prs_vid_entry_remove(struct mvpp2_port *port, u16 vid)
int tid;
/* Scan TCAM and see if entry with this <vid,port> already exist */
- tid = mvpp2_prs_vid_range_find(priv, (1 << port->id), vid, 0xfff);
+ tid = mvpp2_prs_vid_range_find(port, vid, 0xfff);
/* No such entry */
if (tid < 0)
@@ -2026,8 +2026,10 @@ void mvpp2_prs_vid_remove_all(struct mvpp2_port *port)
for (tid = MVPP2_PRS_VID_PORT_FIRST(port->id);
tid <= MVPP2_PRS_VID_PORT_LAST(port->id); tid++) {
- if (priv->prs_shadow[tid].valid)
- mvpp2_prs_vid_entry_remove(port, tid);
+ if (priv->prs_shadow[tid].valid) {
+ mvpp2_prs_hw_inv(priv, tid);
+ priv->prs_shadow[tid].valid = false;
+ }
}
}
diff --git a/drivers/net/ethernet/marvell/skge.c b/drivers/net/ethernet/marvell/skge.c
index 35a92fd2cf39..9ac854c2b371 100644
--- a/drivers/net/ethernet/marvell/skge.c
+++ b/drivers/net/ethernet/marvell/skge.c
@@ -2558,8 +2558,6 @@ static int skge_up(struct net_device *dev)
goto free_pci_mem;
}
- memset(skge->mem, 0, skge->mem_size);
-
err = skge_ring_alloc(&skge->rx_ring, skge->mem, skge->dma);
if (err)
goto free_pci_mem;
diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c
index fe518c854d1f..f518312ffe69 100644
--- a/drivers/net/ethernet/marvell/sky2.c
+++ b/drivers/net/ethernet/marvell/sky2.c
@@ -4917,6 +4917,13 @@ static const struct dmi_system_id msi_blacklist[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "P-79"),
},
},
+ {
+ .ident = "ASUS P5W DH Deluxe",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTEK COMPUTER INC"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "P5W DH Deluxe"),
+ },
+ },
{}
};
diff --git a/drivers/net/ethernet/mediatek/Makefile b/drivers/net/ethernet/mediatek/Makefile
index d41a2414c575..2d8362f9341b 100644
--- a/drivers/net/ethernet/mediatek/Makefile
+++ b/drivers/net/ethernet/mediatek/Makefile
@@ -3,4 +3,5 @@
# Makefile for the Mediatek SoCs built-in ethernet macs
#
-obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth_soc.o
+obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth.o
+mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_eth_path.o
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_path.c b/drivers/net/ethernet/mediatek/mtk_eth_path.c
new file mode 100644
index 000000000000..7f05880cf9ef
--- /dev/null
+++ b/drivers/net/ethernet/mediatek/mtk_eth_path.c
@@ -0,0 +1,352 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018-2019 MediaTek Inc.
+
+/* A library for configuring path from GMAC/GDM to target PHY
+ *
+ * Author: Sean Wang <sean.wang@mediatek.com>
+ *
+ */
+
+#include <linux/phy.h>
+#include <linux/regmap.h>
+
+#include "mtk_eth_soc.h"
+
+struct mtk_eth_muxc {
+ const char *name;
+ int cap_bit;
+ int (*set_path)(struct mtk_eth *eth, int path);
+};
+
+static const char *mtk_eth_path_name(int path)
+{
+ switch (path) {
+ case MTK_ETH_PATH_GMAC1_RGMII:
+ return "gmac1_rgmii";
+ case MTK_ETH_PATH_GMAC1_TRGMII:
+ return "gmac1_trgmii";
+ case MTK_ETH_PATH_GMAC1_SGMII:
+ return "gmac1_sgmii";
+ case MTK_ETH_PATH_GMAC2_RGMII:
+ return "gmac2_rgmii";
+ case MTK_ETH_PATH_GMAC2_SGMII:
+ return "gmac2_sgmii";
+ case MTK_ETH_PATH_GMAC2_GEPHY:
+ return "gmac2_gephy";
+ case MTK_ETH_PATH_GDM1_ESW:
+ return "gdm1_esw";
+ default:
+ return "unknown path";
+ }
+}
+
+static int set_mux_gdm1_to_gmac1_esw(struct mtk_eth *eth, int path)
+{
+ bool updated = true;
+ u32 val, mask, set;
+
+ switch (path) {
+ case MTK_ETH_PATH_GMAC1_SGMII:
+ mask = ~(u32)MTK_MUX_TO_ESW;
+ set = 0;
+ break;
+ case MTK_ETH_PATH_GDM1_ESW:
+ mask = ~(u32)MTK_MUX_TO_ESW;
+ set = MTK_MUX_TO_ESW;
+ break;
+ default:
+ updated = false;
+ break;
+ };
+
+ if (updated) {
+ val = mtk_r32(eth, MTK_MAC_MISC);
+ val = (val & mask) | set;
+ mtk_w32(eth, val, MTK_MAC_MISC);
+ }
+
+ dev_dbg(eth->dev, "path %s in %s updated = %d\n",
+ mtk_eth_path_name(path), __func__, updated);
+
+ return 0;
+}
+
+static int set_mux_gmac2_gmac0_to_gephy(struct mtk_eth *eth, int path)
+{
+ unsigned int val = 0;
+ bool updated = true;
+
+ switch (path) {
+ case MTK_ETH_PATH_GMAC2_GEPHY:
+ val = ~(u32)GEPHY_MAC_SEL;
+ break;
+ default:
+ updated = false;
+ break;
+ }
+
+ if (updated)
+ regmap_update_bits(eth->infra, INFRA_MISC2, GEPHY_MAC_SEL, val);
+
+ dev_dbg(eth->dev, "path %s in %s updated = %d\n",
+ mtk_eth_path_name(path), __func__, updated);
+
+ return 0;
+}
+
+static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, int path)
+{
+ unsigned int val = 0;
+ bool updated = true;
+
+ switch (path) {
+ case MTK_ETH_PATH_GMAC2_SGMII:
+ val = CO_QPHY_SEL;
+ break;
+ default:
+ updated = false;
+ break;
+ }
+
+ if (updated)
+ regmap_update_bits(eth->infra, INFRA_MISC2, CO_QPHY_SEL, val);
+
+ dev_dbg(eth->dev, "path %s in %s updated = %d\n",
+ mtk_eth_path_name(path), __func__, updated);
+
+ return 0;
+}
+
+static int set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth *eth, int path)
+{
+ unsigned int val = 0;
+ bool updated = true;
+
+ switch (path) {
+ case MTK_ETH_PATH_GMAC1_SGMII:
+ val = SYSCFG0_SGMII_GMAC1;
+ break;
+ case MTK_ETH_PATH_GMAC2_SGMII:
+ val = SYSCFG0_SGMII_GMAC2;
+ break;
+ case MTK_ETH_PATH_GMAC1_RGMII:
+ case MTK_ETH_PATH_GMAC2_RGMII:
+ regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
+ val &= SYSCFG0_SGMII_MASK;
+
+ if ((path == MTK_GMAC1_RGMII && val == SYSCFG0_SGMII_GMAC1) ||
+ (path == MTK_GMAC2_RGMII && val == SYSCFG0_SGMII_GMAC2))
+ val = 0;
+ else
+ updated = false;
+ break;
+ default:
+ updated = false;
+ break;
+ };
+
+ if (updated)
+ regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
+ SYSCFG0_SGMII_MASK, val);
+
+ dev_dbg(eth->dev, "path %s in %s updated = %d\n",
+ mtk_eth_path_name(path), __func__, updated);
+
+ return 0;
+}
+
+static int set_mux_gmac12_to_gephy_sgmii(struct mtk_eth *eth, int path)
+{
+ unsigned int val = 0;
+ bool updated = true;
+
+ regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
+
+ switch (path) {
+ case MTK_ETH_PATH_GMAC1_SGMII:
+ val |= SYSCFG0_SGMII_GMAC1_V2;
+ break;
+ case MTK_ETH_PATH_GMAC2_GEPHY:
+ val &= ~(u32)SYSCFG0_SGMII_GMAC2_V2;
+ break;
+ case MTK_ETH_PATH_GMAC2_SGMII:
+ val |= SYSCFG0_SGMII_GMAC2_V2;
+ break;
+ default:
+ updated = false;
+ };
+
+ if (updated)
+ regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
+ SYSCFG0_SGMII_MASK, val);
+
+ dev_dbg(eth->dev, "path %s in %s updated = %d\n",
+ mtk_eth_path_name(path), __func__, updated);
+
+ return 0;
+}
+
+static const struct mtk_eth_muxc mtk_eth_muxc[] = {
+ {
+ .name = "mux_gdm1_to_gmac1_esw",
+ .cap_bit = MTK_ETH_MUX_GDM1_TO_GMAC1_ESW,
+ .set_path = set_mux_gdm1_to_gmac1_esw,
+ }, {
+ .name = "mux_gmac2_gmac0_to_gephy",
+ .cap_bit = MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY,
+ .set_path = set_mux_gmac2_gmac0_to_gephy,
+ }, {
+ .name = "mux_u3_gmac2_to_qphy",
+ .cap_bit = MTK_ETH_MUX_U3_GMAC2_TO_QPHY,
+ .set_path = set_mux_u3_gmac2_to_qphy,
+ }, {
+ .name = "mux_gmac1_gmac2_to_sgmii_rgmii",
+ .cap_bit = MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII,
+ .set_path = set_mux_gmac1_gmac2_to_sgmii_rgmii,
+ }, {
+ .name = "mux_gmac12_to_gephy_sgmii",
+ .cap_bit = MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII,
+ .set_path = set_mux_gmac12_to_gephy_sgmii,
+ },
+};
+
+static int mtk_eth_mux_setup(struct mtk_eth *eth, int path)
+{
+ int i, err = 0;
+
+ if (!MTK_HAS_CAPS(eth->soc->caps, path)) {
+ dev_err(eth->dev, "path %s isn't support on the SoC\n",
+ mtk_eth_path_name(path));
+ return -EINVAL;
+ }
+
+ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_MUX))
+ return 0;
+
+ /* Setup MUX in path fabric */
+ for (i = 0; i < ARRAY_SIZE(mtk_eth_muxc); i++) {
+ if (MTK_HAS_CAPS(eth->soc->caps, mtk_eth_muxc[i].cap_bit)) {
+ err = mtk_eth_muxc[i].set_path(eth, path);
+ if (err)
+ goto out;
+ } else {
+ dev_dbg(eth->dev, "mux %s isn't present on the SoC\n",
+ mtk_eth_muxc[i].name);
+ }
+ }
+
+out:
+ return err;
+}
+
+static int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id)
+{
+ unsigned int val = 0;
+ int sid, err, path;
+
+ path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_SGMII :
+ MTK_ETH_PATH_GMAC2_SGMII;
+
+ /* Setup proper MUXes along the path */
+ err = mtk_eth_mux_setup(eth, path);
+ if (err)
+ return err;
+
+ /* The path GMAC to SGMII will be enabled once the SGMIISYS is being
+ * setup done.
+ */
+ regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
+
+ regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
+ SYSCFG0_SGMII_MASK, ~(u32)SYSCFG0_SGMII_MASK);
+
+ /* Decide how GMAC and SGMIISYS be mapped */
+ sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ? 0 : mac_id;
+
+ /* Setup SGMIISYS with the determined property */
+ if (MTK_HAS_FLAGS(eth->sgmii->flags[sid], MTK_SGMII_PHYSPEED_AN))
+ err = mtk_sgmii_setup_mode_an(eth->sgmii, sid);
+ else
+ err = mtk_sgmii_setup_mode_force(eth->sgmii, sid);
+
+ if (err)
+ return err;
+
+ regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
+ SYSCFG0_SGMII_MASK, val);
+
+ return 0;
+}
+
+static int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id)
+{
+ int err, path = 0;
+
+ if (mac_id == 1)
+ path = MTK_ETH_PATH_GMAC2_GEPHY;
+
+ if (!path)
+ return -EINVAL;
+
+ /* Setup proper MUXes along the path */
+ err = mtk_eth_mux_setup(eth, path);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id)
+{
+ int err, path;
+
+ path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_RGMII :
+ MTK_ETH_PATH_GMAC2_RGMII;
+
+ /* Setup proper MUXes along the path */
+ err = mtk_eth_mux_setup(eth, path);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+int mtk_setup_hw_path(struct mtk_eth *eth, int mac_id, int phymode)
+{
+ int err;
+
+ switch (phymode) {
+ case PHY_INTERFACE_MODE_TRGMII:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_MII:
+ case PHY_INTERFACE_MODE_REVMII:
+ case PHY_INTERFACE_MODE_RMII:
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_RGMII)) {
+ err = mtk_gmac_rgmii_path_setup(eth, mac_id);
+ if (err)
+ return err;
+ }
+ break;
+ case PHY_INTERFACE_MODE_SGMII:
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) {
+ err = mtk_gmac_sgmii_path_setup(eth, mac_id);
+ if (err)
+ return err;
+ }
+ break;
+ case PHY_INTERFACE_MODE_GMII:
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_GEPHY)) {
+ err = mtk_gmac_gephy_path_setup(eth, mac_id);
+ if (err)
+ return err;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 6cfffb64cd51..c39d7f4ab1d4 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -48,8 +48,10 @@ static const struct mtk_ethtool_stats {
};
static const char * const mtk_clks_source_name[] = {
- "ethif", "esw", "gp0", "gp1", "gp2", "trgpll", "sgmii_tx250m",
- "sgmii_rx250m", "sgmii_cdr_ref", "sgmii_cdr_fb", "sgmii_ck", "eth2pll"
+ "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",
};
void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg)
@@ -132,6 +134,31 @@ static int mtk_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg)
return _mtk_mdio_read(eth, phy_addr, phy_reg);
}
+static int mt7621_gmac0_rgmii_adjust(struct mtk_eth *eth,
+ phy_interface_t interface)
+{
+ u32 val;
+
+ /* Check DDR memory type.
+ * Currently TRGMII mode with DDR2 memory is not supported.
+ */
+ regmap_read(eth->ethsys, ETHSYS_SYSCFG, &val);
+ if (interface == PHY_INTERFACE_MODE_TRGMII &&
+ val & SYSCFG_DRAM_TYPE_DDR2) {
+ dev_err(eth->dev,
+ "TRGMII mode with DDR2 memory is not supported!\n");
+ return -EOPNOTSUPP;
+ }
+
+ val = (interface == PHY_INTERFACE_MODE_TRGMII) ?
+ ETHSYS_TRGMII_MT7621_DDR_PLL : 0;
+
+ regmap_update_bits(eth->ethsys, ETHSYS_CLKCFG0,
+ ETHSYS_TRGMII_MT7621_MASK, val);
+
+ return 0;
+}
+
static void mtk_gmac0_rgmii_adjust(struct mtk_eth *eth, int speed)
{
u32 val;
@@ -159,47 +186,6 @@ static void mtk_gmac0_rgmii_adjust(struct mtk_eth *eth, int speed)
mtk_w32(eth, val, TRGMII_TCK_CTRL);
}
-static void mtk_gmac_sgmii_hw_setup(struct mtk_eth *eth, int mac_id)
-{
- u32 val;
-
- /* Setup the link timer and QPHY power up inside SGMIISYS */
- regmap_write(eth->sgmiisys, SGMSYS_PCS_LINK_TIMER,
- SGMII_LINK_TIMER_DEFAULT);
-
- regmap_read(eth->sgmiisys, SGMSYS_SGMII_MODE, &val);
- val |= SGMII_REMOTE_FAULT_DIS;
- regmap_write(eth->sgmiisys, SGMSYS_SGMII_MODE, val);
-
- regmap_read(eth->sgmiisys, SGMSYS_PCS_CONTROL_1, &val);
- val |= SGMII_AN_RESTART;
- regmap_write(eth->sgmiisys, SGMSYS_PCS_CONTROL_1, val);
-
- regmap_read(eth->sgmiisys, SGMSYS_QPHY_PWR_STATE_CTRL, &val);
- val &= ~SGMII_PHYA_PWD;
- regmap_write(eth->sgmiisys, SGMSYS_QPHY_PWR_STATE_CTRL, val);
-
- /* Determine MUX for which GMAC uses the SGMII interface */
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_DUAL_GMAC_SHARED_SGMII)) {
- regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
- val &= ~SYSCFG0_SGMII_MASK;
- val |= !mac_id ? SYSCFG0_SGMII_GMAC1 : SYSCFG0_SGMII_GMAC2;
- regmap_write(eth->ethsys, ETHSYS_SYSCFG0, val);
-
- dev_info(eth->dev, "setup shared sgmii for gmac=%d\n",
- mac_id);
- }
-
- /* Setup the GMAC1 going through SGMII path when SoC also support
- * ESW on GMAC1
- */
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_GMAC1_ESW | MTK_GMAC1_SGMII) &&
- !mac_id) {
- mtk_w32(eth, 0, MTK_MAC_MISC);
- dev_info(eth->dev, "setup gmac1 going through sgmii");
- }
-}
-
static void mtk_phy_link_adjust(struct net_device *dev)
{
struct mtk_mac *mac = netdev_priv(dev);
@@ -222,9 +208,17 @@ static void mtk_phy_link_adjust(struct net_device *dev)
break;
}
- if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_GMAC1_TRGMII) &&
- !mac->id && !mac->trgmii)
- mtk_gmac0_rgmii_adjust(mac->hw, dev->phydev->speed);
+ if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_GMAC1_TRGMII) && !mac->id) {
+ if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_TRGMII_MT7621_CLK)) {
+ if (mt7621_gmac0_rgmii_adjust(mac->hw,
+ dev->phydev->interface))
+ return;
+ } else {
+ if (!mac->trgmii)
+ mtk_gmac0_rgmii_adjust(mac->hw,
+ dev->phydev->speed);
+ }
+ }
if (dev->phydev->link)
mcr |= MAC_MCR_FORCE_LINK;
@@ -289,6 +283,7 @@ static int mtk_phy_connect(struct net_device *dev)
struct mtk_eth *eth;
struct device_node *np;
u32 val;
+ int err;
eth = mac->hw;
np = of_parse_phandle(mac->of_node, "phy-handle", 0);
@@ -298,6 +293,10 @@ static int mtk_phy_connect(struct net_device *dev)
if (!np)
return -ENODEV;
+ err = mtk_setup_hw_path(eth, mac->id, of_get_phy_mode(np));
+ if (err)
+ goto err_phy;
+
mac->ge_mode = 0;
switch (of_get_phy_mode(np)) {
case PHY_INTERFACE_MODE_TRGMII:
@@ -306,12 +305,10 @@ static int mtk_phy_connect(struct net_device *dev)
case PHY_INTERFACE_MODE_RGMII_RXID:
case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII:
- break;
case PHY_INTERFACE_MODE_SGMII:
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII))
- mtk_gmac_sgmii_hw_setup(eth, mac->id);
break;
case PHY_INTERFACE_MODE_MII:
+ case PHY_INTERFACE_MODE_GMII:
mac->ge_mode = 1;
break;
case PHY_INTERFACE_MODE_REVMII:
@@ -2477,16 +2474,28 @@ static int mtk_probe(struct platform_device *pdev)
return PTR_ERR(eth->ethsys);
}
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) {
- eth->sgmiisys =
- syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
- "mediatek,sgmiisys");
- if (IS_ERR(eth->sgmiisys)) {
- dev_err(&pdev->dev, "no sgmiisys regmap found\n");
- return PTR_ERR(eth->sgmiisys);
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_INFRA)) {
+ eth->infra = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "mediatek,infracfg");
+ if (IS_ERR(eth->infra)) {
+ dev_err(&pdev->dev, "no infracfg regmap found\n");
+ return PTR_ERR(eth->infra);
}
}
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) {
+ eth->sgmii = devm_kzalloc(eth->dev, sizeof(*eth->sgmii),
+ GFP_KERNEL);
+ if (!eth->sgmii)
+ return -ENOMEM;
+
+ err = mtk_sgmii_init(eth->sgmii, pdev->dev.of_node,
+ eth->soc->ana_rgc3);
+
+ if (err)
+ return err;
+ }
+
if (eth->soc->required_pctl) {
eth->pctl = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
"mediatek,pctl");
@@ -2539,8 +2548,10 @@ static int mtk_probe(struct platform_device *pdev)
continue;
err = mtk_add_mac(eth, mac_np);
- if (err)
+ if (err) {
+ of_node_put(mac_np);
goto err_deinit_hw;
+ }
}
if (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT)) {
@@ -2625,34 +2636,43 @@ static int mtk_remove(struct platform_device *pdev)
}
static const struct mtk_soc_data mt2701_data = {
- .caps = MTK_GMAC1_TRGMII | MTK_HWLRO,
+ .caps = MT7623_CAPS | MTK_HWLRO,
.required_clks = MT7623_CLKS_BITMAP,
.required_pctl = true,
};
static const struct mtk_soc_data mt7621_data = {
- .caps = MTK_SHARED_INT,
+ .caps = MT7621_CAPS,
.required_clks = MT7621_CLKS_BITMAP,
.required_pctl = false,
};
static const struct mtk_soc_data mt7622_data = {
- .caps = MTK_DUAL_GMAC_SHARED_SGMII | MTK_GMAC1_ESW | MTK_HWLRO,
+ .ana_rgc3 = 0x2028,
+ .caps = MT7622_CAPS | MTK_HWLRO,
.required_clks = MT7622_CLKS_BITMAP,
.required_pctl = false,
};
static const struct mtk_soc_data mt7623_data = {
- .caps = MTK_GMAC1_TRGMII | MTK_HWLRO,
+ .caps = MT7623_CAPS | MTK_HWLRO,
.required_clks = MT7623_CLKS_BITMAP,
.required_pctl = true,
};
+static const struct mtk_soc_data mt7629_data = {
+ .ana_rgc3 = 0x128,
+ .caps = MT7629_CAPS | MTK_HWLRO,
+ .required_clks = MT7629_CLKS_BITMAP,
+ .required_pctl = false,
+};
+
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},
{},
};
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 baa85d5601e7..bab94f763e2c 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -9,6 +9,10 @@
#ifndef MTK_ETH_H
#define MTK_ETH_H
+#include <linux/dma-mapping.h>
+#include <linux/netdevice.h>
+#include <linux/of_net.h>
+#include <linux/u64_stats_sync.h>
#include <linux/refcount.h>
#define MTK_QDMA_PAGE_SIZE 2048
@@ -359,17 +363,27 @@
#define MT7622_ETH 7622
#define MT7621_ETH 7621
+/* ethernet system control register */
+#define ETHSYS_SYSCFG 0x10
+#define SYSCFG_DRAM_TYPE_DDR2 BIT(4)
+
/* ethernet subsystem config register */
#define ETHSYS_SYSCFG0 0x14
#define SYSCFG0_GE_MASK 0x3
#define SYSCFG0_GE_MODE(x, y) (x << (12 + (y * 2)))
-#define SYSCFG0_SGMII_MASK (3 << 8)
-#define SYSCFG0_SGMII_GMAC1 ((2 << 8) & GENMASK(9, 8))
-#define SYSCFG0_SGMII_GMAC2 ((3 << 8) & GENMASK(9, 8))
+#define SYSCFG0_SGMII_MASK GENMASK(9, 8)
+#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)
+#define SYSCFG0_SGMII_GMAC2_V2 BIT(8)
+
/* ethernet subsystem clock register */
#define ETHSYS_CLKCFG0 0x2c
#define ETHSYS_TRGMII_CLK_SEL362_5 BIT(11)
+#define ETHSYS_TRGMII_MT7621_MASK (BIT(5) | BIT(6))
+#define ETHSYS_TRGMII_MT7621_APLL BIT(6)
+#define ETHSYS_TRGMII_MT7621_DDR_PLL BIT(5)
/* ethernet reset control register */
#define ETHSYS_RSTCTRL 0x34
@@ -393,6 +407,11 @@
#define SGMSYS_QPHY_PWR_STATE_CTRL 0xe8
#define SGMII_PHYA_PWD BIT(4)
+/* Infrasys subsystem config registers */
+#define INFRA_MISC2 0x70c
+#define CO_QPHY_SEL BIT(0)
+#define GEPHY_MAC_SEL BIT(1)
+
struct mtk_rx_dma {
unsigned int rxd1;
unsigned int rxd2;
@@ -457,15 +476,21 @@ enum mtk_tx_flags {
*/
enum mtk_clks_map {
MTK_CLK_ETHIF,
+ MTK_CLK_SGMIITOP,
MTK_CLK_ESW,
MTK_CLK_GP0,
MTK_CLK_GP1,
MTK_CLK_GP2,
+ MTK_CLK_FE,
MTK_CLK_TRGPLL,
MTK_CLK_SGMII_TX_250M,
MTK_CLK_SGMII_RX_250M,
MTK_CLK_SGMII_CDR_REF,
MTK_CLK_SGMII_CDR_FB,
+ MTK_CLK_SGMII2_TX_250M,
+ MTK_CLK_SGMII2_RX_250M,
+ MTK_CLK_SGMII2_CDR_REF,
+ MTK_CLK_SGMII2_CDR_FB,
MTK_CLK_SGMII_CK,
MTK_CLK_ETH2PLL,
MTK_CLK_MAX
@@ -484,6 +509,19 @@ enum mtk_clks_map {
BIT(MTK_CLK_SGMII_CK) | \
BIT(MTK_CLK_ETH2PLL))
#define MT7621_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))
enum mtk_dev_state {
MTK_HW_INIT,
@@ -554,21 +592,120 @@ struct mtk_rx_ring {
u32 crx_idx_reg;
};
-#define MTK_TRGMII BIT(0)
-#define MTK_GMAC1_TRGMII (BIT(1) | MTK_TRGMII)
-#define MTK_ESW BIT(4)
-#define MTK_GMAC1_ESW (BIT(5) | MTK_ESW)
-#define MTK_SGMII BIT(8)
-#define MTK_GMAC1_SGMII (BIT(9) | MTK_SGMII)
-#define MTK_GMAC2_SGMII (BIT(10) | MTK_SGMII)
-#define MTK_DUAL_GMAC_SHARED_SGMII (BIT(11) | MTK_GMAC1_SGMII | \
- MTK_GMAC2_SGMII)
-#define MTK_HWLRO BIT(12)
-#define MTK_SHARED_INT BIT(13)
+enum mkt_eth_capabilities {
+ MTK_RGMII_BIT = 0,
+ MTK_TRGMII_BIT,
+ MTK_SGMII_BIT,
+ MTK_ESW_BIT,
+ MTK_GEPHY_BIT,
+ MTK_MUX_BIT,
+ MTK_INFRA_BIT,
+ MTK_SHARED_SGMII_BIT,
+ MTK_HWLRO_BIT,
+ MTK_SHARED_INT_BIT,
+ MTK_TRGMII_MT7621_CLK_BIT,
+
+ /* MUX BITS*/
+ MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT,
+ MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY_BIT,
+ MTK_ETH_MUX_U3_GMAC2_TO_QPHY_BIT,
+ MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII_BIT,
+ MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII_BIT,
+
+ /* PATH BITS */
+ MTK_ETH_PATH_GMAC1_RGMII_BIT,
+ MTK_ETH_PATH_GMAC1_TRGMII_BIT,
+ MTK_ETH_PATH_GMAC1_SGMII_BIT,
+ MTK_ETH_PATH_GMAC2_RGMII_BIT,
+ MTK_ETH_PATH_GMAC2_SGMII_BIT,
+ MTK_ETH_PATH_GMAC2_GEPHY_BIT,
+ MTK_ETH_PATH_GDM1_ESW_BIT,
+};
+
+/* 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_ETH_MUX_GDM1_TO_GMAC1_ESW \
+ BIT(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)
+#define MTK_ETH_MUX_U3_GMAC2_TO_QPHY \
+ BIT(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)
+#define MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII \
+ BIT(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_GMAC1_RGMII (MTK_ETH_PATH_GMAC1_RGMII | MTK_RGMII)
+#define MTK_GMAC1_TRGMII (MTK_ETH_PATH_GMAC1_TRGMII | MTK_TRGMII)
+#define MTK_GMAC1_SGMII (MTK_ETH_PATH_GMAC1_SGMII | MTK_SGMII)
+#define MTK_GMAC2_RGMII (MTK_ETH_PATH_GMAC2_RGMII | MTK_RGMII)
+#define MTK_GMAC2_SGMII (MTK_ETH_PATH_GMAC2_SGMII | MTK_SGMII)
+#define MTK_GMAC2_GEPHY (MTK_ETH_PATH_GMAC2_GEPHY | MTK_GEPHY)
+#define MTK_GDM1_ESW (MTK_ETH_PATH_GDM1_ESW | MTK_ESW)
+
+/* MUXes present on SoCs */
+/* 0: GDM1 -> GMAC1, 1: GDM1 -> ESW */
+#define MTK_MUX_GDM1_TO_GMAC1_ESW (MTK_ETH_MUX_GDM1_TO_GMAC1_ESW | MTK_MUX)
+
+/* 0: GMAC2 -> GEPHY, 1: GMAC0 -> GePHY */
+#define MTK_MUX_GMAC2_GMAC0_TO_GEPHY \
+ (MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY | MTK_MUX | MTK_INFRA)
+
+/* 0: U3 -> QPHY, 1: GMAC2 -> QPHY */
+#define MTK_MUX_U3_GMAC2_TO_QPHY \
+ (MTK_ETH_MUX_U3_GMAC2_TO_QPHY | MTK_MUX | MTK_INFRA)
+
+/* 2: GMAC1 -> SGMII, 3: GMAC2 -> SGMII */
+#define MTK_MUX_GMAC1_GMAC2_TO_SGMII_RGMII \
+ (MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII | MTK_MUX | \
+ MTK_SHARED_SGMII)
+
+/* 0: GMACx -> GEPHY, 1: GMACx -> SGMII where x is 1 or 2 */
+#define MTK_MUX_GMAC12_TO_GEPHY_SGMII \
+ (MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII | MTK_MUX)
+
#define MTK_HAS_CAPS(caps, _x) (((caps) & (_x)) == (_x))
+#define MT7621_CAPS (MTK_GMAC1_RGMII | MTK_GMAC1_TRGMII | \
+ MTK_GMAC2_RGMII | MTK_SHARED_INT | MTK_TRGMII_MT7621_CLK)
+
+#define MT7622_CAPS (MTK_GMAC1_RGMII | MTK_GMAC1_SGMII | MTK_GMAC2_RGMII | \
+ MTK_GMAC2_SGMII | MTK_GDM1_ESW | \
+ MTK_MUX_GDM1_TO_GMAC1_ESW | \
+ MTK_MUX_GMAC1_GMAC2_TO_SGMII_RGMII)
+
+#define MT7623_CAPS (MTK_GMAC1_RGMII | MTK_GMAC1_TRGMII | MTK_GMAC2_RGMII)
+
+#define MT7629_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | MTK_GMAC2_GEPHY | \
+ MTK_GDM1_ESW | MTK_MUX_GDM1_TO_GMAC1_ESW | \
+ MTK_MUX_GMAC2_GMAC0_TO_GEPHY | \
+ MTK_MUX_U3_GMAC2_TO_QPHY | \
+ MTK_MUX_GMAC12_TO_GEPHY_SGMII)
+
/* struct mtk_eth_data - This is the structure holding all differences
* among various plaforms
+ * @ana_rgc3: The offset for register ANA_RGC3 related to
+ * sgmiisys syscon
* @caps Flags shown the extra capability for the SoC
* @required_clks Flags shown the bitmap for required clocks on
* the target SoC
@@ -576,6 +713,7 @@ struct mtk_rx_ring {
* the extra setup for those pins used by GMAC.
*/
struct mtk_soc_data {
+ u32 ana_rgc3;
u32 caps;
u32 required_clks;
bool required_pctl;
@@ -584,6 +722,26 @@ struct mtk_soc_data {
/* currently no SoC has more than 2 macs */
#define MTK_MAX_DEVS 2
+#define MTK_SGMII_PHYSPEED_AN BIT(31)
+#define MTK_SGMII_PHYSPEED_MASK GENMASK(2, 0)
+#define MTK_SGMII_PHYSPEED_1000 BIT(0)
+#define MTK_SGMII_PHYSPEED_2500 BIT(1)
+#define MTK_HAS_FLAGS(flags, _x) (((flags) & (_x)) == (_x))
+
+/* struct mtk_sgmii - This is the structure holding sgmii regmap and its
+ * characteristics
+ * @regmap: The register map pointing at the range used to setup
+ * SGMII modes
+ * @flags: The enum refers to which mode the sgmii wants to run on
+ * @ana_rgc3: The offset refers to register ANA_RGC3 related to regmap
+ */
+
+struct mtk_sgmii {
+ struct regmap *regmap[MTK_MAX_DEVS];
+ u32 flags[MTK_MAX_DEVS];
+ u32 ana_rgc3;
+};
+
/* struct mtk_eth - This is the main datasructure for holding the state
* of the driver
* @dev: The device pointer
@@ -599,8 +757,8 @@ struct mtk_soc_data {
* @msg_enable: Ethtool msg level
* @ethsys: The register map pointing at the range used to setup
* MII modes
- * @sgmiisys: The register map pointing at the range used to setup
- * SGMII modes
+ * @infra: The register map pointing at the range used to setup
+ * SGMII and GePHY path
* @pctl: The register map pointing at the range used to setup
* GMAC port drive/slew values
* @dma_refcnt: track how many netdevs are using the DMA engine
@@ -632,7 +790,8 @@ struct mtk_eth {
u32 msg_enable;
unsigned long sysclk;
struct regmap *ethsys;
- struct regmap *sgmiisys;
+ struct regmap *infra;
+ struct mtk_sgmii *sgmii;
struct regmap *pctl;
bool hwlro;
refcount_t dma_refcnt;
@@ -683,4 +842,10 @@ 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);
+int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *np,
+ u32 ana_rgc3);
+int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id);
+int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id);
+int mtk_setup_hw_path(struct mtk_eth *eth, int mac_id, int phymode);
+
#endif /* MTK_ETH_H */
diff --git a/drivers/net/ethernet/mediatek/mtk_sgmii.c b/drivers/net/ethernet/mediatek/mtk_sgmii.c
new file mode 100644
index 000000000000..ff509d42d818
--- /dev/null
+++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018-2019 MediaTek Inc.
+
+/* A library for MediaTek SGMII circuit
+ *
+ * Author: Sean Wang <sean.wang@mediatek.com>
+ *
+ */
+
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+
+#include "mtk_eth_soc.h"
+
+int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *r, u32 ana_rgc3)
+{
+ struct device_node *np;
+ const char *str;
+ int i, err;
+
+ ss->ana_rgc3 = ana_rgc3;
+
+ for (i = 0; i < MTK_MAX_DEVS; i++) {
+ np = of_parse_phandle(r, "mediatek,sgmiisys", i);
+ if (!np)
+ break;
+
+ ss->regmap[i] = syscon_node_to_regmap(np);
+ if (IS_ERR(ss->regmap[i]))
+ return PTR_ERR(ss->regmap[i]);
+
+ err = of_property_read_string(np, "mediatek,physpeed", &str);
+ if (err)
+ return err;
+
+ if (!strcmp(str, "2500"))
+ ss->flags[i] |= MTK_SGMII_PHYSPEED_2500;
+ else if (!strcmp(str, "1000"))
+ ss->flags[i] |= MTK_SGMII_PHYSPEED_1000;
+ else if (!strcmp(str, "auto"))
+ ss->flags[i] |= MTK_SGMII_PHYSPEED_AN;
+ else
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id)
+{
+ unsigned int val;
+
+ if (!ss->regmap[id])
+ return -EINVAL;
+
+ /* Setup the link timer and QPHY power up inside SGMIISYS */
+ regmap_write(ss->regmap[id], SGMSYS_PCS_LINK_TIMER,
+ SGMII_LINK_TIMER_DEFAULT);
+
+ regmap_read(ss->regmap[id], SGMSYS_SGMII_MODE, &val);
+ val |= SGMII_REMOTE_FAULT_DIS;
+ regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val);
+
+ regmap_read(ss->regmap[id], SGMSYS_PCS_CONTROL_1, &val);
+ val |= SGMII_AN_RESTART;
+ regmap_write(ss->regmap[id], SGMSYS_PCS_CONTROL_1, val);
+
+ regmap_read(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, &val);
+ val &= ~SGMII_PHYA_PWD;
+ regmap_write(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, val);
+
+ return 0;
+}
+
+int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id)
+{
+ unsigned int val;
+ int mode;
+
+ if (!ss->regmap[id])
+ return -EINVAL;
+
+ regmap_read(ss->regmap[id], ss->ana_rgc3, &val);
+ val &= ~GENMASK(3, 2);
+ mode = ss->flags[id] & MTK_SGMII_PHYSPEED_MASK;
+ val |= (mode == MTK_SGMII_PHYSPEED_1000) ? 0 : BIT(2);
+ regmap_write(ss->regmap[id], ss->ana_rgc3, val);
+
+ /* Disable SGMII AN */
+ regmap_read(ss->regmap[id], SGMSYS_PCS_CONTROL_1, &val);
+ val &= ~BIT(12);
+ regmap_write(ss->regmap[id], SGMSYS_PCS_CONTROL_1, val);
+
+ /* SGMII force mode setting */
+ val = 0x31120019;
+ regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val);
+
+ /* Release PHYA power down state */
+ regmap_read(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, &val);
+ val &= ~SGMII_PHYA_PWD;
+ regmap_write(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, val);
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c
index a5be27772b8e..c790a5fcea73 100644
--- a/drivers/net/ethernet/mellanox/mlx4/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/eq.c
@@ -1013,8 +1013,6 @@ static int mlx4_create_eq(struct mlx4_dev *dev, int nent,
dma_list[i] = t;
eq->page_list[i].map = t;
-
- memset(eq->page_list[i].buf, 0, PAGE_SIZE);
}
eq->eqn = mlx4_bitmap_alloc(&priv->eq_table.bitmap);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig
index 2391e3cfb56b..37fef8cd25e3 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig
+++ b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig
@@ -34,6 +34,7 @@ config MLX5_CORE_EN
depends on NETDEVICES && ETHERNET && INET && PCI && MLX5_CORE
depends on IPV6=y || IPV6=n || MLX5_CORE=m
select PAGE_POOL
+ select DIMLIB
default n
---help---
Ethernet support in Mellanox Technologies ConnectX-4 NIC.
@@ -96,26 +97,60 @@ config MLX5_CORE_IPOIB
---help---
MLX5 IPoIB offloads & acceleration support.
+config MLX5_FPGA_IPSEC
+ bool "Mellanox Technologies IPsec Innova support"
+ depends on MLX5_CORE
+ depends on MLX5_FPGA
+ default n
+ help
+ Build IPsec support for the Innova family of network cards by Mellanox
+ Technologies. Innova network cards are comprised of a ConnectX chip
+ and an FPGA chip on one board. If you select this option, the
+ mlx5_core driver will include the Innova FPGA core and allow building
+ sandbox-specific client drivers.
+
config MLX5_EN_IPSEC
bool "IPSec XFRM cryptography-offload accelaration"
- depends on MLX5_ACCEL
depends on MLX5_CORE_EN
depends on XFRM_OFFLOAD
depends on INET_ESP_OFFLOAD || INET6_ESP_OFFLOAD
+ depends on MLX5_FPGA_IPSEC
default n
- ---help---
+ help
Build support for IPsec cryptography-offload accelaration in the NIC.
Note: Support for hardware with this capability needs to be selected
for this option to become available.
-config MLX5_EN_TLS
- bool "TLS cryptography-offload accelaration"
+config MLX5_FPGA_TLS
+ bool "Mellanox Technologies TLS Innova support"
+ depends on TLS_DEVICE
+ depends on TLS=y || MLX5_CORE=m
+ depends on MLX5_FPGA
+ default n
+ help
+ Build TLS support for the Innova family of network cards by Mellanox
+ Technologies. Innova network cards are comprised of a ConnectX chip
+ and an FPGA chip on one board. If you select this option, the
+ mlx5_core driver will include the Innova FPGA core and allow building
+ sandbox-specific client drivers.
+
+config MLX5_TLS
+ bool "Mellanox Technologies TLS Connect-X support"
depends on MLX5_CORE_EN
depends on TLS_DEVICE
depends on TLS=y || MLX5_CORE=m
- depends on MLX5_ACCEL
+ select MLX5_ACCEL
default n
- ---help---
- Build support for TLS cryptography-offload accelaration in the NIC.
- Note: Support for hardware with this capability needs to be selected
- for this option to become available.
+ help
+ Build TLS support for the Connect-X family of network cards by Mellanox
+ Technologies.
+
+config MLX5_EN_TLS
+ bool "TLS cryptography-offload accelaration"
+ depends on MLX5_CORE_EN
+ depends on MLX5_FPGA_TLS || MLX5_TLS
+ default y
+ help
+ Build support for TLS cryptography-offload accelaration in the NIC.
+ Note: Support for hardware with this capability needs to be selected
+ for this option to become available.
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
index 243368dc23db..57d2cc666fe3 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
@@ -13,9 +13,10 @@ obj-$(CONFIG_MLX5_CORE) += mlx5_core.o
#
mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
health.o mcg.o cq.o alloc.o qp.o port.o mr.o pd.o \
- transobj.o vport.o sriov.o fs_cmd.o fs_core.o \
+ transobj.o vport.o sriov.o fs_cmd.o fs_core.o pci_irq.o \
fs_counters.o rl.o lag.o dev.o events.o wq.o lib/gid.o \
- lib/devcom.o diag/fs_tracepoint.o diag/fw_tracer.o
+ lib/devcom.o lib/pci_vsc.o diag/fs_tracepoint.o \
+ diag/fw_tracer.o diag/crdump.o devlink.o
#
# Netdev basic
@@ -23,7 +24,7 @@ mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
mlx5_core-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
en_tx.o en_rx.o en_dim.o en_txrx.o en/xdp.o en_stats.o \
en_selftest.o en/port.o en/monitor_stats.o en/reporter_tx.o \
- en/params.o
+ en/params.o en/xsk/umem.o en/xsk/setup.o en/xsk/rx.o en/xsk/tx.o
#
# Netdev extra
@@ -31,12 +32,15 @@ mlx5_core-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
mlx5_core-$(CONFIG_MLX5_EN_ARFS) += en_arfs.o
mlx5_core-$(CONFIG_MLX5_EN_RXNFC) += en_fs_ethtool.o
mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o en/port_buffer.o
-mlx5_core-$(CONFIG_MLX5_ESWITCH) += en_rep.o en_tc.o en/tc_tun.o lib/port_tun.o lag_mp.o
+mlx5_core-$(CONFIG_MLX5_ESWITCH) += en_rep.o en_tc.o en/tc_tun.o lib/port_tun.o lag_mp.o \
+ lib/geneve.o en/tc_tun_vxlan.o en/tc_tun_gre.o \
+ en/tc_tun_geneve.o
#
# Core extra
#
-mlx5_core-$(CONFIG_MLX5_ESWITCH) += eswitch.o eswitch_offloads.o ecpf.o rdma.o
+mlx5_core-$(CONFIG_MLX5_ESWITCH) += eswitch.o eswitch_offloads.o eswitch_offloads_termtbl.o \
+ ecpf.o rdma.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
@@ -49,12 +53,14 @@ mlx5_core-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o ipoib/ipoib
#
# Accelerations & FPGA
#
-mlx5_core-$(CONFIG_MLX5_ACCEL) += accel/ipsec.o accel/tls.o
+mlx5_core-$(CONFIG_MLX5_FPGA_IPSEC) += fpga/ipsec.o
+mlx5_core-$(CONFIG_MLX5_FPGA_TLS) += fpga/tls.o
+mlx5_core-$(CONFIG_MLX5_ACCEL) += lib/crypto.o accel/tls.o accel/ipsec.o
-mlx5_core-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o \
- fpga/ipsec.o fpga/tls.o
+mlx5_core-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o
mlx5_core-$(CONFIG_MLX5_EN_IPSEC) += en_accel/ipsec.o en_accel/ipsec_rxtx.o \
en_accel/ipsec_stats.o
-mlx5_core-$(CONFIG_MLX5_EN_TLS) += en_accel/tls.o en_accel/tls_rxtx.o en_accel/tls_stats.o
+mlx5_core-$(CONFIG_MLX5_EN_TLS) += en_accel/tls.o en_accel/tls_rxtx.o en_accel/tls_stats.o \
+ en_accel/ktls.o en_accel/ktls_tx.o
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/accel/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/accel/ipsec.c
index 9f1b1939716a..eddc34e4a762 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/accel/ipsec.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/accel/ipsec.c
@@ -31,6 +31,8 @@
*
*/
+#ifdef CONFIG_MLX5_FPGA_IPSEC
+
#include <linux/mlx5/device.h>
#include "accel/ipsec.h"
@@ -74,6 +76,11 @@ int mlx5_accel_ipsec_init(struct mlx5_core_dev *mdev)
return mlx5_fpga_ipsec_init(mdev);
}
+void mlx5_accel_ipsec_build_fs_cmds(void)
+{
+ mlx5_fpga_ipsec_build_fs_cmds();
+}
+
void mlx5_accel_ipsec_cleanup(struct mlx5_core_dev *mdev)
{
mlx5_fpga_ipsec_cleanup(mdev);
@@ -107,3 +114,5 @@ int mlx5_accel_esp_modify_xfrm(struct mlx5_accel_esp_xfrm *xfrm,
return mlx5_fpga_esp_modify_xfrm(xfrm, attrs);
}
EXPORT_SYMBOL_GPL(mlx5_accel_esp_modify_xfrm);
+
+#endif
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/accel/ipsec.h b/drivers/net/ethernet/mellanox/mlx5/core/accel/ipsec.h
index 024dbd22a89b..530e428d46ab 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/accel/ipsec.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/accel/ipsec.h
@@ -37,7 +37,7 @@
#include <linux/mlx5/driver.h>
#include <linux/mlx5/accel.h>
-#ifdef CONFIG_MLX5_ACCEL
+#ifdef CONFIG_MLX5_FPGA_IPSEC
#define MLX5_IPSEC_DEV(mdev) (mlx5_accel_ipsec_device_caps(mdev) & \
MLX5_ACCEL_IPSEC_CAP_DEVICE)
@@ -54,6 +54,7 @@ void *mlx5_accel_esp_create_hw_context(struct mlx5_core_dev *mdev,
void mlx5_accel_esp_free_hw_context(void *context);
int mlx5_accel_ipsec_init(struct mlx5_core_dev *mdev);
+void mlx5_accel_ipsec_build_fs_cmds(void);
void mlx5_accel_ipsec_cleanup(struct mlx5_core_dev *mdev);
#else
@@ -79,6 +80,10 @@ static inline int mlx5_accel_ipsec_init(struct mlx5_core_dev *mdev)
return 0;
}
+static inline void mlx5_accel_ipsec_build_fs_cmds(void)
+{
+}
+
static inline void mlx5_accel_ipsec_cleanup(struct mlx5_core_dev *mdev)
{
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/accel/tls.c b/drivers/net/ethernet/mellanox/mlx5/core/accel/tls.c
index da7bd26368f9..cab708af3422 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/accel/tls.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/accel/tls.c
@@ -35,6 +35,9 @@
#include "accel/tls.h"
#include "mlx5_core.h"
+#include "lib/mlx5.h"
+
+#ifdef CONFIG_MLX5_FPGA_TLS
#include "fpga/tls.h"
int mlx5_accel_tls_add_flow(struct mlx5_core_dev *mdev, void *flow,
@@ -61,7 +64,8 @@ int mlx5_accel_tls_resync_rx(struct mlx5_core_dev *mdev, u32 handle, u32 seq,
bool mlx5_accel_is_tls_device(struct mlx5_core_dev *mdev)
{
- return mlx5_fpga_is_tls_device(mdev);
+ return mlx5_fpga_is_tls_device(mdev) ||
+ mlx5_accel_is_ktls_device(mdev);
}
u32 mlx5_accel_tls_device_caps(struct mlx5_core_dev *mdev)
@@ -78,3 +82,42 @@ void mlx5_accel_tls_cleanup(struct mlx5_core_dev *mdev)
{
mlx5_fpga_tls_cleanup(mdev);
}
+#endif
+
+#ifdef CONFIG_MLX5_TLS
+int mlx5_ktls_create_key(struct mlx5_core_dev *mdev,
+ struct tls_crypto_info *crypto_info,
+ u32 *p_key_id)
+{
+ u32 sz_bytes;
+ void *key;
+
+ switch (crypto_info->cipher_type) {
+ case TLS_CIPHER_AES_GCM_128: {
+ struct tls12_crypto_info_aes_gcm_128 *info =
+ (struct tls12_crypto_info_aes_gcm_128 *)crypto_info;
+
+ key = info->key;
+ sz_bytes = sizeof(info->key);
+ break;
+ }
+ case TLS_CIPHER_AES_GCM_256: {
+ struct tls12_crypto_info_aes_gcm_256 *info =
+ (struct tls12_crypto_info_aes_gcm_256 *)crypto_info;
+
+ key = info->key;
+ sz_bytes = sizeof(info->key);
+ break;
+ }
+ default:
+ return -EINVAL;
+ }
+
+ return mlx5_create_encryption_key(mdev, key, sz_bytes, p_key_id);
+}
+
+void mlx5_ktls_destroy_key(struct mlx5_core_dev *mdev, u32 key_id)
+{
+ mlx5_destroy_encryption_key(mdev, key_id);
+}
+#endif
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/accel/tls.h b/drivers/net/ethernet/mellanox/mlx5/core/accel/tls.h
index def4093ebfae..d787bc0a4155 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/accel/tls.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/accel/tls.h
@@ -37,7 +37,49 @@
#include <linux/mlx5/driver.h>
#include <linux/tls.h>
-#ifdef CONFIG_MLX5_ACCEL
+#ifdef CONFIG_MLX5_TLS
+int mlx5_ktls_create_key(struct mlx5_core_dev *mdev,
+ struct tls_crypto_info *crypto_info,
+ u32 *p_key_id);
+void mlx5_ktls_destroy_key(struct mlx5_core_dev *mdev, u32 key_id);
+
+static inline bool mlx5_accel_is_ktls_device(struct mlx5_core_dev *mdev)
+{
+ if (!MLX5_CAP_GEN(mdev, tls))
+ return false;
+
+ if (!MLX5_CAP_GEN(mdev, log_max_dek))
+ return false;
+
+ return MLX5_CAP_TLS(mdev, tls_1_2_aes_gcm_128);
+}
+
+static inline bool mlx5e_ktls_type_check(struct mlx5_core_dev *mdev,
+ struct tls_crypto_info *crypto_info)
+{
+ switch (crypto_info->cipher_type) {
+ case TLS_CIPHER_AES_GCM_128:
+ if (crypto_info->version == TLS_1_2_VERSION)
+ return MLX5_CAP_TLS(mdev, tls_1_2_aes_gcm_128);
+ break;
+ }
+
+ return false;
+}
+#else
+static inline int
+mlx5_ktls_create_key(struct mlx5_core_dev *mdev,
+ struct tls_crypto_info *crypto_info,
+ u32 *p_key_id) { return -ENOTSUPP; }
+static inline void
+mlx5_ktls_destroy_key(struct mlx5_core_dev *mdev, u32 key_id) {}
+
+static inline bool
+mlx5_accel_is_ktls_device(struct mlx5_core_dev *mdev) { return false; }
+static inline bool
+mlx5e_ktls_type_check(struct mlx5_core_dev *mdev,
+ struct tls_crypto_info *crypto_info) { return false; }
+#endif
enum {
MLX5_ACCEL_TLS_TX = BIT(0),
@@ -60,6 +102,7 @@ struct mlx5_ifc_tls_flow_bits {
u8 reserved_at_2[0x1e];
};
+#ifdef CONFIG_MLX5_FPGA_TLS
int mlx5_accel_tls_add_flow(struct mlx5_core_dev *mdev, void *flow,
struct tls_crypto_info *crypto_info,
u32 start_offload_tcp_sn, u32 *p_swid,
@@ -84,11 +127,13 @@ static inline void mlx5_accel_tls_del_flow(struct mlx5_core_dev *mdev, u32 swid,
bool direction_sx) { }
static inline int mlx5_accel_tls_resync_rx(struct mlx5_core_dev *mdev, u32 handle,
u32 seq, u64 rcd_sn) { return 0; }
-static inline bool mlx5_accel_is_tls_device(struct mlx5_core_dev *mdev) { return false; }
+static inline bool mlx5_accel_is_tls_device(struct mlx5_core_dev *mdev)
+{
+ return mlx5_accel_is_ktls_device(mdev);
+}
static inline u32 mlx5_accel_tls_device_caps(struct mlx5_core_dev *mdev) { return 0; }
static inline int mlx5_accel_tls_init(struct mlx5_core_dev *mdev) { return 0; }
static inline void mlx5_accel_tls_cleanup(struct mlx5_core_dev *mdev) { }
-
#endif
#endif /* __MLX5_ACCEL_TLS_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
index d2ab8cd8ad9f..8cdd7e66f8df 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
@@ -316,7 +316,7 @@ static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op,
case MLX5_CMD_OP_DESTROY_GENERAL_OBJECT:
case MLX5_CMD_OP_DEALLOC_MEMIC:
case MLX5_CMD_OP_PAGE_FAULT_RESUME:
- case MLX5_CMD_OP_QUERY_HOST_PARAMS:
+ case MLX5_CMD_OP_QUERY_ESW_FUNCTIONS:
return MLX5_CMD_STAT_OK;
case MLX5_CMD_OP_QUERY_HCA_CAP:
@@ -441,6 +441,10 @@ static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op,
case MLX5_CMD_OP_CREATE_GENERAL_OBJECT:
case MLX5_CMD_OP_MODIFY_GENERAL_OBJECT:
case MLX5_CMD_OP_QUERY_GENERAL_OBJECT:
+ case MLX5_CMD_OP_CREATE_UCTX:
+ case MLX5_CMD_OP_DESTROY_UCTX:
+ case MLX5_CMD_OP_CREATE_UMEM:
+ case MLX5_CMD_OP_DESTROY_UMEM:
case MLX5_CMD_OP_ALLOC_MEMIC:
*status = MLX5_DRIVER_STATUS_ABORTED;
*synd = MLX5_DRIVER_SYND;
@@ -628,7 +632,11 @@ const char *mlx5_command_str(int command)
MLX5_COMMAND_STR_CASE(QUERY_MODIFY_HEADER_CONTEXT);
MLX5_COMMAND_STR_CASE(ALLOC_MEMIC);
MLX5_COMMAND_STR_CASE(DEALLOC_MEMIC);
- MLX5_COMMAND_STR_CASE(QUERY_HOST_PARAMS);
+ MLX5_COMMAND_STR_CASE(QUERY_ESW_FUNCTIONS);
+ MLX5_COMMAND_STR_CASE(CREATE_UCTX);
+ MLX5_COMMAND_STR_CASE(DESTROY_UCTX);
+ MLX5_COMMAND_STR_CASE(CREATE_UMEM);
+ MLX5_COMMAND_STR_CASE(DESTROY_UMEM);
default: return "unknown command opcode";
}
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cq.c b/drivers/net/ethernet/mellanox/mlx5/core/cq.c
index 713a17ee3751..818edc63e428 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/cq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/cq.c
@@ -58,7 +58,7 @@ void mlx5_cq_tasklet_cb(unsigned long data)
list_for_each_entry_safe(mcq, temp, &ctx->process_list,
tasklet_ctx.list) {
list_del_init(&mcq->tasklet_ctx.list);
- mcq->tasklet_ctx.comp(mcq);
+ mcq->tasklet_ctx.comp(mcq, NULL);
mlx5_cq_put(mcq);
if (time_after(jiffies, end))
break;
@@ -68,7 +68,8 @@ void mlx5_cq_tasklet_cb(unsigned long data)
tasklet_schedule(&ctx->task);
}
-static void mlx5_add_cq_to_tasklet(struct mlx5_core_cq *cq)
+static void mlx5_add_cq_to_tasklet(struct mlx5_core_cq *cq,
+ struct mlx5_eqe *eqe)
{
unsigned long flags;
struct mlx5_eq_tasklet *tasklet_ctx = cq->tasklet_ctx.priv;
@@ -87,11 +88,10 @@ static void mlx5_add_cq_to_tasklet(struct mlx5_core_cq *cq)
}
int mlx5_core_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
- u32 *in, int inlen)
+ u32 *in, int inlen, u32 *out, int outlen)
{
int eqn = MLX5_GET(cqc, MLX5_ADDR_OF(create_cq_in, in, cq_context), c_eqn);
u32 dout[MLX5_ST_SZ_DW(destroy_cq_out)];
- u32 out[MLX5_ST_SZ_DW(create_cq_out)];
u32 din[MLX5_ST_SZ_DW(destroy_cq_in)];
struct mlx5_eq_comp *eq;
int err;
@@ -100,9 +100,9 @@ int mlx5_core_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
if (IS_ERR(eq))
return PTR_ERR(eq);
- memset(out, 0, sizeof(out));
+ memset(out, 0, outlen);
MLX5_SET(create_cq_in, in, opcode, MLX5_CMD_OP_CREATE_CQ);
- err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
+ err = mlx5_cmd_exec(dev, in, inlen, out, outlen);
if (err)
return err;
@@ -158,13 +158,8 @@ int mlx5_core_destroy_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq)
u32 in[MLX5_ST_SZ_DW(destroy_cq_in)] = {0};
int err;
- err = mlx5_eq_del_cq(mlx5_get_async_eq(dev), cq);
- if (err)
- return err;
-
- err = mlx5_eq_del_cq(&cq->eq->core, cq);
- if (err)
- return err;
+ mlx5_eq_del_cq(mlx5_get_async_eq(dev), cq);
+ mlx5_eq_del_cq(&cq->eq->core, cq);
MLX5_SET(destroy_cq_in, in, opcode, MLX5_CMD_OP_DESTROY_CQ);
MLX5_SET(destroy_cq_in, in, cqn, cq->cqn);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dev.c b/drivers/net/ethernet/mellanox/mlx5/core/dev.c
index ebc046fa97d3..5bb6a26ea267 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/dev.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/dev.c
@@ -248,11 +248,32 @@ void mlx5_unregister_interface(struct mlx5_interface *intf)
}
EXPORT_SYMBOL(mlx5_unregister_interface);
+/* Must be called with intf_mutex held */
+static bool mlx5_has_added_dev_by_protocol(struct mlx5_core_dev *mdev, int protocol)
+{
+ struct mlx5_device_context *dev_ctx;
+ struct mlx5_interface *intf;
+ bool found = false;
+
+ list_for_each_entry(intf, &intf_list, list) {
+ if (intf->protocol == protocol) {
+ dev_ctx = mlx5_get_device(intf, &mdev->priv);
+ if (dev_ctx && test_bit(MLX5_INTERFACE_ADDED, &dev_ctx->state))
+ found = true;
+ break;
+ }
+ }
+
+ return found;
+}
+
void mlx5_reload_interface(struct mlx5_core_dev *mdev, int protocol)
{
mutex_lock(&mlx5_intf_mutex);
- mlx5_remove_dev_by_protocol(mdev, protocol);
- mlx5_add_dev_by_protocol(mdev, protocol);
+ if (mlx5_has_added_dev_by_protocol(mdev, protocol)) {
+ mlx5_remove_dev_by_protocol(mdev, protocol);
+ mlx5_add_dev_by_protocol(mdev, protocol);
+ }
mutex_unlock(&mlx5_intf_mutex);
}
@@ -290,13 +311,20 @@ static u32 mlx5_gen_pci_id(struct mlx5_core_dev *dev)
/* Must be called with intf_mutex held */
struct mlx5_core_dev *mlx5_get_next_phys_dev(struct mlx5_core_dev *dev)
{
- u32 pci_id = mlx5_gen_pci_id(dev);
struct mlx5_core_dev *res = NULL;
struct mlx5_core_dev *tmp_dev;
struct mlx5_priv *priv;
+ u32 pci_id;
+ if (!mlx5_core_is_pf(dev))
+ return NULL;
+
+ pci_id = mlx5_gen_pci_id(dev);
list_for_each_entry(priv, &mlx5_dev_list, dev_list) {
tmp_dev = container_of(priv, struct mlx5_core_dev, priv);
+ if (!mlx5_core_is_pf(tmp_dev))
+ continue;
+
if ((dev != tmp_dev) && (mlx5_gen_pci_id(tmp_dev) == pci_id)) {
res = tmp_dev;
break;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
new file mode 100644
index 000000000000..a400f4430c28
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/* Copyright (c) 2019 Mellanox Technologies */
+
+#include <devlink.h>
+
+#include "mlx5_core.h"
+#include "eswitch.h"
+
+static int mlx5_devlink_flash_update(struct devlink *devlink,
+ const char *file_name,
+ const char *component,
+ struct netlink_ext_ack *extack)
+{
+ struct mlx5_core_dev *dev = devlink_priv(devlink);
+ const struct firmware *fw;
+ int err;
+
+ if (component)
+ return -EOPNOTSUPP;
+
+ err = request_firmware_direct(&fw, file_name, &dev->pdev->dev);
+ if (err)
+ return err;
+
+ return mlx5_firmware_flash(dev, fw, extack);
+}
+
+static u8 mlx5_fw_ver_major(u32 version)
+{
+ return (version >> 24) & 0xff;
+}
+
+static u8 mlx5_fw_ver_minor(u32 version)
+{
+ return (version >> 16) & 0xff;
+}
+
+static u16 mlx5_fw_ver_subminor(u32 version)
+{
+ return version & 0xffff;
+}
+
+#define DEVLINK_FW_STRING_LEN 32
+
+static int
+mlx5_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
+ struct netlink_ext_ack *extack)
+{
+ struct mlx5_core_dev *dev = devlink_priv(devlink);
+ char version_str[DEVLINK_FW_STRING_LEN];
+ u32 running_fw, stored_fw;
+ int err;
+
+ err = devlink_info_driver_name_put(req, DRIVER_NAME);
+ if (err)
+ return err;
+
+ err = devlink_info_version_fixed_put(req, "fw.psid", dev->board_id);
+ if (err)
+ return err;
+
+ err = mlx5_fw_version_query(dev, &running_fw, &stored_fw);
+ if (err)
+ return err;
+
+ snprintf(version_str, sizeof(version_str), "%d.%d.%04d",
+ mlx5_fw_ver_major(running_fw), mlx5_fw_ver_minor(running_fw),
+ mlx5_fw_ver_subminor(running_fw));
+ err = devlink_info_version_running_put(req, "fw.version", version_str);
+ if (err)
+ return err;
+
+ /* no pending version, return running (stored) version */
+ if (stored_fw == 0)
+ stored_fw = running_fw;
+
+ snprintf(version_str, sizeof(version_str), "%d.%d.%04d",
+ mlx5_fw_ver_major(stored_fw), mlx5_fw_ver_minor(stored_fw),
+ mlx5_fw_ver_subminor(stored_fw));
+ err = devlink_info_version_stored_put(req, "fw.version", version_str);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static const struct devlink_ops mlx5_devlink_ops = {
+#ifdef CONFIG_MLX5_ESWITCH
+ .eswitch_mode_set = mlx5_devlink_eswitch_mode_set,
+ .eswitch_mode_get = mlx5_devlink_eswitch_mode_get,
+ .eswitch_inline_mode_set = mlx5_devlink_eswitch_inline_mode_set,
+ .eswitch_inline_mode_get = mlx5_devlink_eswitch_inline_mode_get,
+ .eswitch_encap_mode_set = mlx5_devlink_eswitch_encap_mode_set,
+ .eswitch_encap_mode_get = mlx5_devlink_eswitch_encap_mode_get,
+#endif
+ .flash_update = mlx5_devlink_flash_update,
+ .info_get = mlx5_devlink_info_get,
+};
+
+struct devlink *mlx5_devlink_alloc(void)
+{
+ return devlink_alloc(&mlx5_devlink_ops, sizeof(struct mlx5_core_dev));
+}
+
+void mlx5_devlink_free(struct devlink *devlink)
+{
+ devlink_free(devlink);
+}
+
+int mlx5_devlink_register(struct devlink *devlink, struct device *dev)
+{
+ return devlink_register(devlink, dev);
+}
+
+void mlx5_devlink_unregister(struct devlink *devlink)
+{
+ devlink_unregister(devlink);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.h b/drivers/net/ethernet/mellanox/mlx5/core/devlink.h
new file mode 100644
index 000000000000..d0ba03774ddf
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2019, Mellanox Technologies */
+
+#ifndef __MLX5_DEVLINK_H__
+#define __MLX5_DEVLINK_H__
+
+#include <net/devlink.h>
+
+struct devlink *mlx5_devlink_alloc(void);
+void mlx5_devlink_free(struct devlink *devlink);
+int mlx5_devlink_register(struct devlink *devlink, struct device *dev);
+void mlx5_devlink_unregister(struct devlink *devlink);
+
+#endif /* __MLX5_DEVLINK_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/crdump.c b/drivers/net/ethernet/mellanox/mlx5/core/diag/crdump.c
new file mode 100644
index 000000000000..28d02749d3c4
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/crdump.c
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/* Copyright (c) 2019 Mellanox Technologies */
+
+#include <linux/mlx5/driver.h>
+#include "mlx5_core.h"
+#include "lib/pci_vsc.h"
+#include "lib/mlx5.h"
+
+#define BAD_ACCESS 0xBADACCE5
+#define MLX5_PROTECTED_CR_SCAN_CRSPACE 0x7
+
+static bool mlx5_crdump_enabled(struct mlx5_core_dev *dev)
+{
+ return !!dev->priv.health.crdump_size;
+}
+
+static int mlx5_crdump_fill(struct mlx5_core_dev *dev, u32 *cr_data)
+{
+ u32 crdump_size = dev->priv.health.crdump_size;
+ int i, ret;
+
+ for (i = 0; i < (crdump_size / 4); i++)
+ cr_data[i] = BAD_ACCESS;
+
+ ret = mlx5_vsc_gw_read_block_fast(dev, cr_data, crdump_size);
+ if (ret <= 0) {
+ if (ret == 0)
+ return -EIO;
+ return ret;
+ }
+
+ if (crdump_size != ret) {
+ mlx5_core_warn(dev, "failed to read full dump, read %d out of %u\n",
+ ret, crdump_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int mlx5_crdump_collect(struct mlx5_core_dev *dev, u32 *cr_data)
+{
+ int ret;
+
+ if (!mlx5_crdump_enabled(dev))
+ return -ENODEV;
+
+ ret = mlx5_vsc_gw_lock(dev);
+ if (ret) {
+ mlx5_core_warn(dev, "crdump: failed to lock vsc gw err %d\n",
+ ret);
+ return ret;
+ }
+ /* Verify no other PF is running cr-dump or sw reset */
+ ret = mlx5_vsc_sem_set_space(dev, MLX5_SEMAPHORE_SW_RESET,
+ MLX5_VSC_LOCK);
+ if (ret) {
+ mlx5_core_warn(dev, "Failed to lock SW reset semaphore\n");
+ goto unlock_gw;
+ }
+
+ ret = mlx5_vsc_gw_set_space(dev, MLX5_VSC_SPACE_SCAN_CRSPACE, NULL);
+ if (ret)
+ goto unlock_sem;
+
+ ret = mlx5_crdump_fill(dev, cr_data);
+
+unlock_sem:
+ mlx5_vsc_sem_set_space(dev, MLX5_SEMAPHORE_SW_RESET, MLX5_VSC_UNLOCK);
+unlock_gw:
+ mlx5_vsc_gw_unlock(dev);
+ return ret;
+}
+
+int mlx5_crdump_enable(struct mlx5_core_dev *dev)
+{
+ struct mlx5_priv *priv = &dev->priv;
+ u32 space_size;
+ int ret;
+
+ if (!mlx5_core_is_pf(dev) || !mlx5_vsc_accessible(dev) ||
+ mlx5_crdump_enabled(dev))
+ return 0;
+
+ ret = mlx5_vsc_gw_lock(dev);
+ if (ret)
+ return ret;
+
+ /* Check if space is supported and get space size */
+ ret = mlx5_vsc_gw_set_space(dev, MLX5_VSC_SPACE_SCAN_CRSPACE,
+ &space_size);
+ if (ret) {
+ /* Unlock and mask error since space is not supported */
+ mlx5_vsc_gw_unlock(dev);
+ return 0;
+ }
+
+ if (!space_size) {
+ mlx5_core_warn(dev, "Invalid Crspace size, zero\n");
+ mlx5_vsc_gw_unlock(dev);
+ return -EINVAL;
+ }
+
+ ret = mlx5_vsc_gw_unlock(dev);
+ if (ret)
+ return ret;
+
+ priv->health.crdump_size = space_size;
+ return 0;
+}
+
+void mlx5_crdump_disable(struct mlx5_core_dev *dev)
+{
+ dev->priv.health.crdump_size = 0;
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/fs_tracepoint.h b/drivers/net/ethernet/mellanox/mlx5/core/diag/fs_tracepoint.h
index a4cf123e3f17..ddf1b87f1bc0 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/diag/fs_tracepoint.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/fs_tracepoint.h
@@ -187,6 +187,7 @@ TRACE_EVENT(mlx5_fs_set_fte,
__field(u32, index)
__field(u32, action)
__field(u32, flow_tag)
+ __field(u32, flow_source)
__field(u8, mask_enable)
__field(int, new_fte)
__array(u32, mask_outer, MLX5_ST_SZ_DW(fte_match_set_lyr_2_4))
@@ -204,7 +205,8 @@ TRACE_EVENT(mlx5_fs_set_fte,
__entry->index = fte->index;
__entry->action = fte->action.action;
__entry->mask_enable = __entry->fg->mask.match_criteria_enable;
- __entry->flow_tag = fte->action.flow_tag;
+ __entry->flow_tag = fte->flow_context.flow_tag;
+ __entry->flow_source = fte->flow_context.flow_source;
memcpy(__entry->mask_outer,
MLX5_ADDR_OF(fte_match_param,
&__entry->fg->mask.match_criteria,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
index 6999f4486e9e..8a4930c8bf62 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
@@ -243,6 +243,19 @@ free_strings_db:
return -ENOMEM;
}
+static void
+mlx5_fw_tracer_init_saved_traces_array(struct mlx5_fw_tracer *tracer)
+{
+ tracer->st_arr.saved_traces_index = 0;
+ mutex_init(&tracer->st_arr.lock);
+}
+
+static void
+mlx5_fw_tracer_clean_saved_traces_array(struct mlx5_fw_tracer *tracer)
+{
+ mutex_destroy(&tracer->st_arr.lock);
+}
+
static void mlx5_tracer_read_strings_db(struct work_struct *work)
{
struct mlx5_fw_tracer *tracer = container_of(work, struct mlx5_fw_tracer,
@@ -522,6 +535,24 @@ static void mlx5_fw_tracer_clean_ready_list(struct mlx5_fw_tracer *tracer)
list_del(&str_frmt->list);
}
+static void mlx5_fw_tracer_save_trace(struct mlx5_fw_tracer *tracer,
+ u64 timestamp, bool lost,
+ u8 event_id, char *msg)
+{
+ struct mlx5_fw_trace_data *trace_data;
+
+ mutex_lock(&tracer->st_arr.lock);
+ trace_data = &tracer->st_arr.straces[tracer->st_arr.saved_traces_index];
+ trace_data->timestamp = timestamp;
+ trace_data->lost = lost;
+ trace_data->event_id = event_id;
+ strncpy(trace_data->msg, msg, TRACE_STR_MSG);
+
+ tracer->st_arr.saved_traces_index =
+ (tracer->st_arr.saved_traces_index + 1) & (SAVED_TRACES_NUM - 1);
+ mutex_unlock(&tracer->st_arr.lock);
+}
+
static void mlx5_tracer_print_trace(struct tracer_string_format *str_frmt,
struct mlx5_core_dev *dev,
u64 trace_timestamp)
@@ -540,6 +571,9 @@ static void mlx5_tracer_print_trace(struct tracer_string_format *str_frmt,
trace_mlx5_fw(dev->tracer, trace_timestamp, str_frmt->lost,
str_frmt->event_id, tmp);
+ mlx5_fw_tracer_save_trace(dev->tracer, trace_timestamp,
+ str_frmt->lost, str_frmt->event_id, tmp);
+
/* remove it from hash */
mlx5_tracer_clean_message(str_frmt);
}
@@ -786,6 +820,109 @@ static void mlx5_fw_tracer_ownership_change(struct work_struct *work)
mlx5_fw_tracer_start(tracer);
}
+static int mlx5_fw_tracer_set_core_dump_reg(struct mlx5_core_dev *dev,
+ u32 *in, int size_in)
+{
+ u32 out[MLX5_ST_SZ_DW(core_dump_reg)] = {};
+
+ if (!MLX5_CAP_DEBUG(dev, core_dump_general) &&
+ !MLX5_CAP_DEBUG(dev, core_dump_qp))
+ return -EOPNOTSUPP;
+
+ return mlx5_core_access_reg(dev, in, size_in, out, sizeof(out),
+ MLX5_REG_CORE_DUMP, 0, 1);
+}
+
+int mlx5_fw_tracer_trigger_core_dump_general(struct mlx5_core_dev *dev)
+{
+ struct mlx5_fw_tracer *tracer = dev->tracer;
+ u32 in[MLX5_ST_SZ_DW(core_dump_reg)] = {};
+ int err;
+
+ if (!MLX5_CAP_DEBUG(dev, core_dump_general) || !tracer)
+ return -EOPNOTSUPP;
+ if (!tracer->owner)
+ return -EPERM;
+
+ MLX5_SET(core_dump_reg, in, core_dump_type, 0x0);
+
+ err = mlx5_fw_tracer_set_core_dump_reg(dev, in, sizeof(in));
+ if (err)
+ return err;
+ queue_work(tracer->work_queue, &tracer->handle_traces_work);
+ flush_workqueue(tracer->work_queue);
+ return 0;
+}
+
+static int
+mlx5_devlink_fmsg_fill_trace(struct devlink_fmsg *fmsg,
+ struct mlx5_fw_trace_data *trace_data)
+{
+ int err;
+
+ err = devlink_fmsg_obj_nest_start(fmsg);
+ if (err)
+ return err;
+
+ err = devlink_fmsg_u64_pair_put(fmsg, "timestamp", trace_data->timestamp);
+ if (err)
+ return err;
+
+ err = devlink_fmsg_bool_pair_put(fmsg, "lost", trace_data->lost);
+ if (err)
+ return err;
+
+ err = devlink_fmsg_u8_pair_put(fmsg, "event_id", trace_data->event_id);
+ if (err)
+ return err;
+
+ err = devlink_fmsg_string_pair_put(fmsg, "msg", trace_data->msg);
+ if (err)
+ return err;
+
+ err = devlink_fmsg_obj_nest_end(fmsg);
+ if (err)
+ return err;
+ return 0;
+}
+
+int mlx5_fw_tracer_get_saved_traces_objects(struct mlx5_fw_tracer *tracer,
+ struct devlink_fmsg *fmsg)
+{
+ struct mlx5_fw_trace_data *straces = tracer->st_arr.straces;
+ u32 index, start_index, end_index;
+ u32 saved_traces_index;
+ int err;
+
+ if (!straces[0].timestamp)
+ return -ENOMSG;
+
+ mutex_lock(&tracer->st_arr.lock);
+ saved_traces_index = tracer->st_arr.saved_traces_index;
+ if (straces[saved_traces_index].timestamp)
+ start_index = saved_traces_index;
+ else
+ start_index = 0;
+ end_index = (saved_traces_index - 1) & (SAVED_TRACES_NUM - 1);
+
+ err = devlink_fmsg_arr_pair_nest_start(fmsg, "dump fw traces");
+ if (err)
+ goto unlock;
+ index = start_index;
+ while (index != end_index) {
+ err = mlx5_devlink_fmsg_fill_trace(fmsg, &straces[index]);
+ if (err)
+ goto unlock;
+
+ index = (index + 1) & (SAVED_TRACES_NUM - 1);
+ }
+
+ err = devlink_fmsg_arr_pair_nest_end(fmsg);
+unlock:
+ mutex_unlock(&tracer->st_arr.lock);
+ return err;
+}
+
/* Create software resources (Buffers, etc ..) */
struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev)
{
@@ -833,6 +970,7 @@ struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev)
goto free_log_buf;
}
+ mlx5_fw_tracer_init_saved_traces_array(tracer);
mlx5_core_dbg(dev, "FWTracer: Tracer created\n");
return tracer;
@@ -917,6 +1055,7 @@ void mlx5_fw_tracer_destroy(struct mlx5_fw_tracer *tracer)
cancel_work_sync(&tracer->read_fw_strings_work);
mlx5_fw_tracer_clean_ready_list(tracer);
mlx5_fw_tracer_clean_print_hash(tracer);
+ mlx5_fw_tracer_clean_saved_traces_array(tracer);
mlx5_fw_tracer_free_strings_db(tracer);
mlx5_fw_tracer_destroy_log_buf(tracer);
flush_workqueue(tracer->work_queue);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.h b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.h
index a8b8747f2b61..40601fba80ba 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.h
@@ -46,6 +46,9 @@
#define TRACER_BLOCK_SIZE_BYTE 256
#define TRACES_PER_BLOCK 32
+#define TRACE_STR_MSG 256
+#define SAVED_TRACES_NUM 8192
+
#define TRACER_MAX_PARAMS 7
#define MESSAGE_HASH_BITS 6
#define MESSAGE_HASH_SIZE BIT(MESSAGE_HASH_BITS)
@@ -53,6 +56,13 @@
#define MASK_52_7 (0x1FFFFFFFFFFF80)
#define MASK_6_0 (0x7F)
+struct mlx5_fw_trace_data {
+ u64 timestamp;
+ bool lost;
+ u8 event_id;
+ char msg[TRACE_STR_MSG];
+};
+
struct mlx5_fw_tracer {
struct mlx5_core_dev *dev;
struct mlx5_nb nb;
@@ -83,6 +93,13 @@ struct mlx5_fw_tracer {
u32 consumer_index;
} buff;
+ /* Saved Traces Array */
+ struct {
+ struct mlx5_fw_trace_data straces[SAVED_TRACES_NUM];
+ u32 saved_traces_index;
+ struct mutex lock; /* Protect st_arr access */
+ } st_arr;
+
u64 last_timestamp;
struct work_struct handle_traces_work;
struct hlist_head hash[MESSAGE_HASH_SIZE];
@@ -171,5 +188,8 @@ struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev);
int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer);
void mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer *tracer);
void mlx5_fw_tracer_destroy(struct mlx5_fw_tracer *tracer);
+int mlx5_fw_tracer_trigger_core_dump_general(struct mlx5_core_dev *dev);
+int mlx5_fw_tracer_get_saved_traces_objects(struct mlx5_fw_tracer *tracer,
+ struct devlink_fmsg *fmsg);
#endif
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ecpf.c b/drivers/net/ethernet/mellanox/mlx5/core/ecpf.c
index 0ccd6d40baf7..d2228e37450f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/ecpf.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/ecpf.c
@@ -83,30 +83,3 @@ void mlx5_ec_cleanup(struct mlx5_core_dev *dev)
mlx5_peer_pf_cleanup(dev);
}
-
-static int mlx5_query_host_params_context(struct mlx5_core_dev *dev,
- u32 *out, int outlen)
-{
- u32 in[MLX5_ST_SZ_DW(query_host_params_in)] = {};
-
- MLX5_SET(query_host_params_in, in, opcode,
- MLX5_CMD_OP_QUERY_HOST_PARAMS);
-
- return mlx5_cmd_exec(dev, in, sizeof(in), out, outlen);
-}
-
-int mlx5_query_host_params_num_vfs(struct mlx5_core_dev *dev, int *num_vf)
-{
- u32 out[MLX5_ST_SZ_DW(query_host_params_out)] = {};
- int err;
-
- err = mlx5_query_host_params_context(dev, out, sizeof(out));
- if (err)
- return err;
-
- *num_vf = MLX5_GET(query_host_params_out, out,
- host_params_context.host_num_of_vfs);
- mlx5_core_dbg(dev, "host_num_of_vfs %d\n", *num_vf);
-
- return 0;
-}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ecpf.h b/drivers/net/ethernet/mellanox/mlx5/core/ecpf.h
index 346372df218f..d3d7a00a02ac 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/ecpf.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/ecpf.h
@@ -16,7 +16,6 @@ enum {
bool mlx5_read_embedded_cpu(struct mlx5_core_dev *dev);
int mlx5_ec_init(struct mlx5_core_dev *dev);
void mlx5_ec_cleanup(struct mlx5_core_dev *dev);
-int mlx5_query_host_params_num_vfs(struct mlx5_core_dev *dev, int *num_vf);
#else /* CONFIG_MLX5_ESWITCH */
@@ -24,9 +23,6 @@ static inline bool
mlx5_read_embedded_cpu(struct mlx5_core_dev *dev) { return false; }
static inline int mlx5_ec_init(struct mlx5_core_dev *dev) { return 0; }
static inline void mlx5_ec_cleanup(struct mlx5_core_dev *dev) {}
-static inline int
-mlx5_query_host_params_num_vfs(struct mlx5_core_dev *dev, int *num_vf)
-{ return -EOPNOTSUPP; }
#endif /* CONFIG_MLX5_ESWITCH */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
index 3a183d690e23..79d93d6c7d7a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
@@ -48,7 +48,7 @@
#include <linux/rhashtable.h>
#include <net/switchdev.h>
#include <net/xdp.h>
-#include <linux/net_dim.h>
+#include <linux/dim.h>
#include <linux/bits.h>
#include "wq.h"
#include "mlx5_core.h"
@@ -137,6 +137,7 @@ struct page_pool;
#define MLX5E_MAX_NUM_CHANNELS (MLX5E_INDIR_RQT_SIZE >> 1)
#define MLX5E_MAX_NUM_SQS (MLX5E_MAX_NUM_CHANNELS * MLX5E_MAX_NUM_TC)
#define MLX5E_TX_CQ_POLL_BUDGET 128
+#define MLX5E_TX_XSK_POLL_BUDGET 64
#define MLX5E_SQ_RECOVER_MIN_INTERVAL 500 /* msecs */
#define MLX5E_UMR_WQE_INLINE_SZ \
@@ -155,6 +156,11 @@ do { \
##__VA_ARGS__); \
} while (0)
+enum mlx5e_rq_group {
+ MLX5E_RQ_GROUP_REGULAR,
+ MLX5E_RQ_GROUP_XSK,
+ MLX5E_NUM_RQ_GROUPS /* Keep last. */
+};
static inline u16 mlx5_min_rx_wqes(int wq_type, u32 wq_size)
{
@@ -179,7 +185,8 @@ static inline int mlx5e_get_max_num_channels(struct mlx5_core_dev *mdev)
/* Use this function to get max num channels after netdev was created */
static inline int mlx5e_get_netdev_max_channels(struct net_device *netdev)
{
- return min_t(unsigned int, netdev->num_rx_queues,
+ return min_t(unsigned int,
+ netdev->num_rx_queues / MLX5E_NUM_RQ_GROUPS,
netdev->num_tx_queues);
}
@@ -202,7 +209,10 @@ struct mlx5e_umr_wqe {
struct mlx5_wqe_ctrl_seg ctrl;
struct mlx5_wqe_umr_ctrl_seg uctrl;
struct mlx5_mkey_seg mkc;
- struct mlx5_mtt inline_mtts[0];
+ union {
+ struct mlx5_mtt inline_mtts[0];
+ u8 tls_static_params_ctx[0];
+ };
};
extern const char mlx5e_self_tests[][ETH_GSTRING_LEN];
@@ -238,9 +248,9 @@ struct mlx5e_params {
u16 num_channels;
u8 num_tc;
bool rx_cqe_compress_def;
- struct net_dim_cq_moder rx_cq_moderation;
- struct net_dim_cq_moder tx_cq_moderation;
bool tunneled_offload_en;
+ struct dim_cq_moder rx_cq_moderation;
+ struct dim_cq_moder tx_cq_moderation;
bool lro_en;
u8 tx_min_inline_mode;
bool vlan_strip_disable;
@@ -250,6 +260,7 @@ struct mlx5e_params {
u32 lro_timeout;
u32 pflags;
struct bpf_prog *xdp_prog;
+ struct mlx5e_xsk *xsk;
unsigned int sw_mtu;
int hard_mtu;
};
@@ -294,6 +305,7 @@ enum {
MLX5E_RQ_STATE_ENABLED,
MLX5E_RQ_STATE_AM,
MLX5E_RQ_STATE_NO_CSUM_COMPLETE,
+ MLX5E_RQ_STATE_CSUM_FULL, /* cqe_csum_full hw bit is set */
};
struct mlx5e_cq {
@@ -325,6 +337,9 @@ struct mlx5e_tx_wqe_info {
u32 num_bytes;
u8 num_wqebbs;
u8 num_dma;
+#ifdef CONFIG_MLX5_EN_TLS
+ skb_frag_t *resync_dump_frag;
+#endif
};
enum mlx5e_dma_map_type {
@@ -348,6 +363,13 @@ enum {
struct mlx5e_sq_wqe_info {
u8 opcode;
+
+ /* Auxiliary data for different opcodes. */
+ union {
+ struct {
+ struct mlx5e_rq *rq;
+ } umr;
+ };
};
struct mlx5e_txqsq {
@@ -356,7 +378,7 @@ struct mlx5e_txqsq {
/* dirtied @completion */
u16 cc;
u32 dma_fifo_cc;
- struct net_dim dim; /* Adaptive Moderation */
+ struct dim dim; /* Adaptive Moderation */
/* dirtied @xmit */
u16 pc ____cacheline_aligned_in_smp;
@@ -375,6 +397,7 @@ struct mlx5e_txqsq {
void __iomem *uar_map;
struct netdev_queue *txq;
u32 sqn;
+ u16 stop_room;
u8 min_inline_mode;
struct device *pdev;
__be32 mkey_be;
@@ -385,20 +408,62 @@ struct mlx5e_txqsq {
/* control path */
struct mlx5_wq_ctrl wq_ctrl;
struct mlx5e_channel *channel;
+ int ch_ix;
int txq_ix;
u32 rate_limit;
struct work_struct recover_work;
} ____cacheline_aligned_in_smp;
struct mlx5e_dma_info {
- struct page *page;
- dma_addr_t addr;
+ dma_addr_t addr;
+ union {
+ struct page *page;
+ struct {
+ u64 handle;
+ void *data;
+ } xsk;
+ };
+};
+
+/* XDP packets can be transmitted in different ways. On completion, we need to
+ * distinguish between them to clean up things in a proper way.
+ */
+enum mlx5e_xdp_xmit_mode {
+ /* An xdp_frame was transmitted due to either XDP_REDIRECT from another
+ * device or XDP_TX from an XSK RQ. The frame has to be unmapped and
+ * returned.
+ */
+ MLX5E_XDP_XMIT_MODE_FRAME,
+
+ /* The xdp_frame was created in place as a result of XDP_TX from a
+ * regular RQ. No DMA remapping happened, and the page belongs to us.
+ */
+ MLX5E_XDP_XMIT_MODE_PAGE,
+
+ /* No xdp_frame was created at all, the transmit happened from a UMEM
+ * page. The UMEM Completion Ring producer pointer has to be increased.
+ */
+ MLX5E_XDP_XMIT_MODE_XSK,
};
struct mlx5e_xdp_info {
- struct xdp_frame *xdpf;
- dma_addr_t dma_addr;
- struct mlx5e_dma_info di;
+ enum mlx5e_xdp_xmit_mode mode;
+ union {
+ struct {
+ struct xdp_frame *xdpf;
+ dma_addr_t dma_addr;
+ } frame;
+ struct {
+ struct mlx5e_rq *rq;
+ struct mlx5e_dma_info di;
+ } page;
+ };
+};
+
+struct mlx5e_xdp_xmit_data {
+ dma_addr_t dma_addr;
+ void *data;
+ u32 len;
};
struct mlx5e_xdp_info_fifo {
@@ -424,8 +489,12 @@ struct mlx5e_xdp_mpwqe {
};
struct mlx5e_xdpsq;
-typedef bool (*mlx5e_fp_xmit_xdp_frame)(struct mlx5e_xdpsq*,
- struct mlx5e_xdp_info*);
+typedef int (*mlx5e_fp_xmit_xdp_frame_check)(struct mlx5e_xdpsq *);
+typedef bool (*mlx5e_fp_xmit_xdp_frame)(struct mlx5e_xdpsq *,
+ struct mlx5e_xdp_xmit_data *,
+ struct mlx5e_xdp_info *,
+ int);
+
struct mlx5e_xdpsq {
/* data path */
@@ -442,8 +511,10 @@ struct mlx5e_xdpsq {
struct mlx5e_cq cq;
/* read only */
+ struct xdp_umem *umem;
struct mlx5_wq_cyc wq;
struct mlx5e_xdpsq_stats *stats;
+ mlx5e_fp_xmit_xdp_frame_check xmit_xdp_frame_check;
mlx5e_fp_xmit_xdp_frame xmit_xdp_frame;
struct {
struct mlx5e_xdp_wqe_info *wqe_info;
@@ -486,12 +557,6 @@ struct mlx5e_icosq {
struct mlx5e_channel *channel;
} ____cacheline_aligned_in_smp;
-static inline bool
-mlx5e_wqc_has_room_for(struct mlx5_wq_cyc *wq, u16 cc, u16 pc, u16 n)
-{
- return (mlx5_wq_cyc_ctr2ix(wq, cc - pc) >= n) || (cc == pc);
-}
-
struct mlx5e_wqe_frag_info {
struct mlx5e_dma_info *di;
u32 offset;
@@ -570,9 +635,11 @@ struct mlx5e_rq {
u8 log_stride_sz;
u8 umr_in_progress;
u8 umr_last_bulk;
+ u8 umr_completed;
} mpwqe;
};
struct {
+ u16 umem_headroom;
u16 headroom;
u8 map_dir; /* dma map direction */
} buff;
@@ -595,14 +662,18 @@ struct mlx5e_rq {
int ix;
unsigned int hw_mtu;
- struct net_dim dim; /* Dynamic Interrupt Moderation */
+ struct dim dim; /* Dynamic Interrupt Moderation */
/* XDP */
struct bpf_prog *xdp_prog;
- struct mlx5e_xdpsq xdpsq;
+ struct mlx5e_xdpsq *xdpsq;
DECLARE_BITMAP(flags, 8);
struct page_pool *page_pool;
+ /* AF_XDP zero-copy */
+ struct zero_copy_allocator zca;
+ struct xdp_umem *umem;
+
/* control */
struct mlx5_wq_ctrl wq_ctrl;
__be32 mkey_be;
@@ -615,9 +686,15 @@ struct mlx5e_rq {
struct xdp_rxq_info xdp_rxq;
} ____cacheline_aligned_in_smp;
+enum mlx5e_channel_state {
+ MLX5E_CHANNEL_STATE_XSK,
+ MLX5E_CHANNEL_NUM_STATES
+};
+
struct mlx5e_channel {
/* data path */
struct mlx5e_rq rq;
+ struct mlx5e_xdpsq rq_xdpsq;
struct mlx5e_txqsq sq[MLX5E_MAX_NUM_TC];
struct mlx5e_icosq icosq; /* internal control operations */
bool xdp;
@@ -630,6 +707,13 @@ struct mlx5e_channel {
/* XDP_REDIRECT */
struct mlx5e_xdpsq xdpsq;
+ /* AF_XDP zero-copy */
+ struct mlx5e_rq xskrq;
+ struct mlx5e_xdpsq xsksq;
+ struct mlx5e_icosq xskicosq;
+ /* xskicosq can be accessed from any CPU - the spinlock protects it. */
+ spinlock_t xskicosq_lock;
+
/* data path - accessed per napi poll */
struct irq_desc *irq_desc;
struct mlx5e_ch_stats *stats;
@@ -638,6 +722,7 @@ struct mlx5e_channel {
struct mlx5e_priv *priv;
struct mlx5_core_dev *mdev;
struct hwtstamp_config *tstamp;
+ DECLARE_BITMAP(state, MLX5E_CHANNEL_NUM_STATES);
int ix;
int cpu;
cpumask_var_t xps_cpumask;
@@ -653,14 +738,17 @@ struct mlx5e_channel_stats {
struct mlx5e_ch_stats ch;
struct mlx5e_sq_stats sq[MLX5E_MAX_NUM_TC];
struct mlx5e_rq_stats rq;
+ struct mlx5e_rq_stats xskrq;
struct mlx5e_xdpsq_stats rq_xdpsq;
struct mlx5e_xdpsq_stats xdpsq;
+ struct mlx5e_xdpsq_stats xsksq;
} ____cacheline_aligned_in_smp;
enum {
MLX5E_STATE_OPENED,
MLX5E_STATE_DESTROYING,
MLX5E_STATE_XDP_TX_ENABLED,
+ MLX5E_STATE_XDP_OPEN,
};
struct mlx5e_rqt {
@@ -693,6 +781,17 @@ struct mlx5e_modify_sq_param {
int rl_index;
};
+struct mlx5e_xsk {
+ /* UMEMs are stored separately from channels, because we don't want to
+ * lose them when channels are recreated. The kernel also stores UMEMs,
+ * but it doesn't distinguish between zero-copy and non-zero-copy UMEMs,
+ * so rely on our mechanism.
+ */
+ struct xdp_umem **umems;
+ u16 refcnt;
+ bool ever_used;
+};
+
struct mlx5e_priv {
/* priv data path fields - start */
struct mlx5e_txqsq *txq2sq[MLX5E_MAX_NUM_CHANNELS * MLX5E_MAX_NUM_TC];
@@ -713,6 +812,7 @@ struct mlx5e_priv {
struct mlx5e_tir indir_tir[MLX5E_NUM_INDIR_TIRS];
struct mlx5e_tir inner_indir_tir[MLX5E_NUM_INDIR_TIRS];
struct mlx5e_tir direct_tir[MLX5E_MAX_NUM_CHANNELS];
+ struct mlx5e_tir xsk_tir[MLX5E_MAX_NUM_CHANNELS];
struct mlx5e_rss_params rss_params;
u32 tx_rates[MLX5E_MAX_NUM_SQS];
@@ -749,6 +849,7 @@ struct mlx5e_priv {
struct mlx5e_tls *tls;
#endif
struct devlink_health_reporter *tx_reporter;
+ struct mlx5e_xsk xsk;
};
struct mlx5e_profile {
@@ -762,6 +863,7 @@ struct mlx5e_profile {
void (*cleanup_tx)(struct mlx5e_priv *priv);
void (*enable)(struct mlx5e_priv *priv);
void (*disable)(struct mlx5e_priv *priv);
+ int (*update_rx)(struct mlx5e_priv *priv);
void (*update_stats)(struct mlx5e_priv *priv);
void (*update_carrier)(struct mlx5e_priv *priv);
struct {
@@ -780,7 +882,7 @@ netdev_tx_t mlx5e_sq_xmit(struct mlx5e_txqsq *sq, struct sk_buff *skb,
struct mlx5e_tx_wqe *wqe, u16 pi, bool xmit_more);
void mlx5e_trigger_irq(struct mlx5e_icosq *sq);
-void mlx5e_completion_event(struct mlx5_core_cq *mcq);
+void mlx5e_completion_event(struct mlx5_core_cq *mcq, struct mlx5_eqe *eqe);
void mlx5e_cq_error_event(struct mlx5_core_cq *mcq, enum mlx5_event event);
int mlx5e_napi_poll(struct napi_struct *napi, int budget);
bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget);
@@ -792,11 +894,13 @@ bool mlx5e_striding_rq_possible(struct mlx5_core_dev *mdev,
struct mlx5e_params *params);
void mlx5e_page_dma_unmap(struct mlx5e_rq *rq, struct mlx5e_dma_info *dma_info);
-void mlx5e_page_release(struct mlx5e_rq *rq, struct mlx5e_dma_info *dma_info,
- bool recycle);
+void mlx5e_page_release_dynamic(struct mlx5e_rq *rq,
+ struct mlx5e_dma_info *dma_info,
+ bool recycle);
void mlx5e_handle_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe);
void mlx5e_handle_rx_cqe_mpwrq(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe);
bool mlx5e_post_rx_wqes(struct mlx5e_rq *rq);
+void mlx5e_poll_ico_cq(struct mlx5e_cq *cq);
bool mlx5e_post_rx_mpwqes(struct mlx5e_rq *rq);
void mlx5e_dealloc_rx_wqe(struct mlx5e_rq *rq, u16 ix);
void mlx5e_dealloc_rx_mpwqe(struct mlx5e_rq *rq, u16 ix);
@@ -852,6 +956,30 @@ void mlx5e_build_indir_tir_ctx_hash(struct mlx5e_rss_params *rss_params,
void mlx5e_modify_tirs_hash(struct mlx5e_priv *priv, void *in, int inlen);
struct mlx5e_tirc_config mlx5e_tirc_get_default_config(enum mlx5e_traffic_types tt);
+struct mlx5e_xsk_param;
+
+struct mlx5e_rq_param;
+int mlx5e_open_rq(struct mlx5e_channel *c, struct mlx5e_params *params,
+ struct mlx5e_rq_param *param, struct mlx5e_xsk_param *xsk,
+ struct xdp_umem *umem, struct mlx5e_rq *rq);
+int mlx5e_wait_for_min_rx_wqes(struct mlx5e_rq *rq, int wait_time);
+void mlx5e_deactivate_rq(struct mlx5e_rq *rq);
+void mlx5e_close_rq(struct mlx5e_rq *rq);
+
+struct mlx5e_sq_param;
+int mlx5e_open_icosq(struct mlx5e_channel *c, struct mlx5e_params *params,
+ struct mlx5e_sq_param *param, struct mlx5e_icosq *sq);
+void mlx5e_close_icosq(struct mlx5e_icosq *sq);
+int mlx5e_open_xdpsq(struct mlx5e_channel *c, struct mlx5e_params *params,
+ struct mlx5e_sq_param *param, struct xdp_umem *umem,
+ struct mlx5e_xdpsq *sq, bool is_redirect);
+void mlx5e_close_xdpsq(struct mlx5e_xdpsq *sq);
+
+struct mlx5e_cq_param;
+int mlx5e_open_cq(struct mlx5e_channel *c, struct dim_cq_moder moder,
+ struct mlx5e_cq_param *param, struct mlx5e_cq *cq);
+void mlx5e_close_cq(struct mlx5e_cq *cq);
+
int mlx5e_open_locked(struct net_device *netdev);
int mlx5e_close_locked(struct net_device *netdev);
@@ -897,102 +1025,6 @@ static inline bool mlx5_tx_swp_supported(struct mlx5_core_dev *mdev)
MLX5_CAP_ETH(mdev, swp_csum) && MLX5_CAP_ETH(mdev, swp_lso);
}
-struct mlx5e_swp_spec {
- __be16 l3_proto;
- u8 l4_proto;
- u8 is_tun;
- __be16 tun_l3_proto;
- u8 tun_l4_proto;
-};
-
-static inline void
-mlx5e_set_eseg_swp(struct sk_buff *skb, struct mlx5_wqe_eth_seg *eseg,
- struct mlx5e_swp_spec *swp_spec)
-{
- /* SWP offsets are in 2-bytes words */
- eseg->swp_outer_l3_offset = skb_network_offset(skb) / 2;
- if (swp_spec->l3_proto == htons(ETH_P_IPV6))
- eseg->swp_flags |= MLX5_ETH_WQE_SWP_OUTER_L3_IPV6;
- if (swp_spec->l4_proto) {
- eseg->swp_outer_l4_offset = skb_transport_offset(skb) / 2;
- if (swp_spec->l4_proto == IPPROTO_UDP)
- eseg->swp_flags |= MLX5_ETH_WQE_SWP_OUTER_L4_UDP;
- }
-
- if (swp_spec->is_tun) {
- eseg->swp_inner_l3_offset = skb_inner_network_offset(skb) / 2;
- if (swp_spec->tun_l3_proto == htons(ETH_P_IPV6))
- eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L3_IPV6;
- } else { /* typically for ipsec when xfrm mode != XFRM_MODE_TUNNEL */
- eseg->swp_inner_l3_offset = skb_network_offset(skb) / 2;
- if (swp_spec->l3_proto == htons(ETH_P_IPV6))
- eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L3_IPV6;
- }
- switch (swp_spec->tun_l4_proto) {
- case IPPROTO_UDP:
- eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L4_UDP;
- /* fall through */
- case IPPROTO_TCP:
- eseg->swp_inner_l4_offset = skb_inner_transport_offset(skb) / 2;
- break;
- }
-}
-
-static inline void mlx5e_sq_fetch_wqe(struct mlx5e_txqsq *sq,
- struct mlx5e_tx_wqe **wqe,
- u16 *pi)
-{
- struct mlx5_wq_cyc *wq = &sq->wq;
-
- *pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
- *wqe = mlx5_wq_cyc_get_wqe(wq, *pi);
- memset(*wqe, 0, sizeof(**wqe));
-}
-
-static inline
-struct mlx5e_tx_wqe *mlx5e_post_nop(struct mlx5_wq_cyc *wq, u32 sqn, u16 *pc)
-{
- u16 pi = mlx5_wq_cyc_ctr2ix(wq, *pc);
- struct mlx5e_tx_wqe *wqe = mlx5_wq_cyc_get_wqe(wq, pi);
- struct mlx5_wqe_ctrl_seg *cseg = &wqe->ctrl;
-
- memset(cseg, 0, sizeof(*cseg));
-
- cseg->opmod_idx_opcode = cpu_to_be32((*pc << 8) | MLX5_OPCODE_NOP);
- cseg->qpn_ds = cpu_to_be32((sqn << 8) | 0x01);
-
- (*pc)++;
-
- return wqe;
-}
-
-static inline
-void mlx5e_notify_hw(struct mlx5_wq_cyc *wq, u16 pc,
- void __iomem *uar_map,
- struct mlx5_wqe_ctrl_seg *ctrl)
-{
- ctrl->fm_ce_se = MLX5_WQE_CTRL_CQ_UPDATE;
- /* ensure wqe is visible to device before updating doorbell record */
- dma_wmb();
-
- *wq->db = cpu_to_be32(pc);
-
- /* ensure doorbell record is visible to device before ringing the
- * doorbell
- */
- wmb();
-
- mlx5_write64((__be32 *)ctrl, uar_map);
-}
-
-static inline void mlx5e_cq_arm(struct mlx5e_cq *cq)
-{
- struct mlx5_core_cq *mcq;
-
- mcq = &cq->mcq;
- mlx5_cq_arm(mcq, MLX5_CQ_DB_REQ_NOT, mcq->uar->map, cq->wq.cc);
-}
-
extern const struct ethtool_ops mlx5e_ethtool_ops;
#ifdef CONFIG_MLX5_CORE_EN_DCB
extern const struct dcbnl_rtnl_ops mlx5e_dcbnl_ops;
@@ -1022,17 +1054,17 @@ int mlx5e_create_indirect_rqt(struct mlx5e_priv *priv);
int mlx5e_create_indirect_tirs(struct mlx5e_priv *priv, bool inner_ttc);
void mlx5e_destroy_indirect_tirs(struct mlx5e_priv *priv, bool inner_ttc);
-int mlx5e_create_direct_rqts(struct mlx5e_priv *priv);
-void mlx5e_destroy_direct_rqts(struct mlx5e_priv *priv);
-int mlx5e_create_direct_tirs(struct mlx5e_priv *priv);
-void mlx5e_destroy_direct_tirs(struct mlx5e_priv *priv);
+int mlx5e_create_direct_rqts(struct mlx5e_priv *priv, struct mlx5e_tir *tirs);
+void mlx5e_destroy_direct_rqts(struct mlx5e_priv *priv, struct mlx5e_tir *tirs);
+int mlx5e_create_direct_tirs(struct mlx5e_priv *priv, struct mlx5e_tir *tirs);
+void mlx5e_destroy_direct_tirs(struct mlx5e_priv *priv, struct mlx5e_tir *tirs);
void mlx5e_destroy_rqt(struct mlx5e_priv *priv, struct mlx5e_rqt *rqt);
-int mlx5e_create_tis(struct mlx5_core_dev *mdev, int tc,
- u32 underlay_qpn, u32 *tisn);
+int mlx5e_create_tis(struct mlx5_core_dev *mdev, void *in, u32 *tisn);
void mlx5e_destroy_tis(struct mlx5_core_dev *mdev, u32 tisn);
int mlx5e_create_tises(struct mlx5e_priv *priv);
+int mlx5e_update_nic_rx(struct mlx5e_priv *priv);
void mlx5e_update_carrier(struct mlx5e_priv *priv);
int mlx5e_close(struct net_device *netdev);
int mlx5e_open(struct net_device *netdev);
@@ -1074,8 +1106,6 @@ 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,
struct ethtool_ts_info *info);
-int mlx5e_ethtool_flash_device(struct mlx5e_priv *priv,
- struct ethtool_flash *flash);
void mlx5e_ethtool_get_pauseparam(struct mlx5e_priv *priv,
struct ethtool_pauseparam *pauseparam);
int mlx5e_ethtool_set_pauseparam(struct mlx5e_priv *priv,
@@ -1096,6 +1126,7 @@ void mlx5e_detach_netdev(struct mlx5e_priv *priv);
void mlx5e_destroy_netdev(struct mlx5e_priv *priv);
void mlx5e_set_netdev_mtu_boundaries(struct mlx5e_priv *priv);
void mlx5e_build_nic_params(struct mlx5_core_dev *mdev,
+ struct mlx5e_xsk *xsk,
struct mlx5e_rss_params *rss_params,
struct mlx5e_params *params,
u16 max_channels, u16 mtu);
@@ -1112,6 +1143,7 @@ void mlx5e_del_vxlan_port(struct net_device *netdev, struct udp_tunnel_info *ti)
netdev_features_t mlx5e_features_check(struct sk_buff *skb,
struct net_device *netdev,
netdev_features_t features);
+int mlx5e_set_features(struct net_device *netdev, netdev_features_t features);
#ifdef CONFIG_MLX5_ESWITCH
int mlx5e_set_vf_mac(struct net_device *dev, int vf, u8 *mac);
int mlx5e_set_vf_rate(struct net_device *dev, int vf, int min_tx_rate, int max_tx_rate);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/params.c b/drivers/net/ethernet/mellanox/mlx5/core/en/params.c
index d3744bffbae3..79301d116667 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/params.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/params.c
@@ -3,65 +3,102 @@
#include "en/params.h"
-u32 mlx5e_rx_get_linear_frag_sz(struct mlx5e_params *params)
+static inline bool mlx5e_rx_is_xdp(struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk)
{
- u16 hw_mtu = MLX5E_SW2HW_MTU(params, params->sw_mtu);
- u16 linear_rq_headroom = params->xdp_prog ?
- XDP_PACKET_HEADROOM : MLX5_RX_HEADROOM;
- u32 frag_sz;
+ return params->xdp_prog || xsk;
+}
+
+u16 mlx5e_get_linear_rq_headroom(struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk)
+{
+ u16 headroom = NET_IP_ALIGN;
+
+ if (mlx5e_rx_is_xdp(params, xsk)) {
+ headroom += XDP_PACKET_HEADROOM;
+ if (xsk)
+ headroom += xsk->headroom;
+ } else {
+ headroom += MLX5_RX_HEADROOM;
+ }
+
+ return headroom;
+}
+
+u32 mlx5e_rx_get_linear_frag_sz(struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk)
+{
+ u32 hw_mtu = MLX5E_SW2HW_MTU(params, params->sw_mtu);
+ u16 linear_rq_headroom = mlx5e_get_linear_rq_headroom(params, xsk);
+ u32 frag_sz = linear_rq_headroom + hw_mtu;
- linear_rq_headroom += NET_IP_ALIGN;
+ /* AF_XDP doesn't build SKBs in place. */
+ if (!xsk)
+ frag_sz = MLX5_SKB_FRAG_SZ(frag_sz);
- frag_sz = MLX5_SKB_FRAG_SZ(linear_rq_headroom + hw_mtu);
+ /* XDP in mlx5e doesn't support multiple packets per page. */
+ if (mlx5e_rx_is_xdp(params, xsk))
+ frag_sz = max_t(u32, frag_sz, PAGE_SIZE);
- if (params->xdp_prog && frag_sz < PAGE_SIZE)
- frag_sz = PAGE_SIZE;
+ /* Even if we can go with a smaller fragment size, we must not put
+ * multiple packets into a single frame.
+ */
+ if (xsk)
+ frag_sz = max_t(u32, frag_sz, xsk->chunk_size);
return frag_sz;
}
-u8 mlx5e_mpwqe_log_pkts_per_wqe(struct mlx5e_params *params)
+u8 mlx5e_mpwqe_log_pkts_per_wqe(struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk)
{
- u32 linear_frag_sz = mlx5e_rx_get_linear_frag_sz(params);
+ u32 linear_frag_sz = mlx5e_rx_get_linear_frag_sz(params, xsk);
return MLX5_MPWRQ_LOG_WQE_SZ - order_base_2(linear_frag_sz);
}
-bool mlx5e_rx_is_linear_skb(struct mlx5e_params *params)
+bool mlx5e_rx_is_linear_skb(struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk)
{
- u32 frag_sz = mlx5e_rx_get_linear_frag_sz(params);
+ /* AF_XDP allocates SKBs on XDP_PASS - ensure they don't occupy more
+ * than one page. For this, check both with and without xsk.
+ */
+ u32 linear_frag_sz = max(mlx5e_rx_get_linear_frag_sz(params, xsk),
+ mlx5e_rx_get_linear_frag_sz(params, NULL));
- return !params->lro_en && frag_sz <= PAGE_SIZE;
+ return !params->lro_en && linear_frag_sz <= PAGE_SIZE;
}
#define MLX5_MAX_MPWQE_LOG_WQE_STRIDE_SZ ((BIT(__mlx5_bit_sz(wq, log_wqe_stride_size)) - 1) + \
MLX5_MPWQE_LOG_STRIDE_SZ_BASE)
bool mlx5e_rx_mpwqe_is_linear_skb(struct mlx5_core_dev *mdev,
- struct mlx5e_params *params)
+ struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk)
{
- u32 frag_sz = mlx5e_rx_get_linear_frag_sz(params);
+ u32 linear_frag_sz = mlx5e_rx_get_linear_frag_sz(params, xsk);
s8 signed_log_num_strides_param;
u8 log_num_strides;
- if (!mlx5e_rx_is_linear_skb(params))
+ if (!mlx5e_rx_is_linear_skb(params, xsk))
return false;
- if (order_base_2(frag_sz) > MLX5_MAX_MPWQE_LOG_WQE_STRIDE_SZ)
+ if (order_base_2(linear_frag_sz) > MLX5_MAX_MPWQE_LOG_WQE_STRIDE_SZ)
return false;
if (MLX5_CAP_GEN(mdev, ext_stride_num_range))
return true;
- log_num_strides = MLX5_MPWRQ_LOG_WQE_SZ - order_base_2(frag_sz);
+ log_num_strides = MLX5_MPWRQ_LOG_WQE_SZ - order_base_2(linear_frag_sz);
signed_log_num_strides_param =
(s8)log_num_strides - MLX5_MPWQE_LOG_NUM_STRIDES_BASE;
return signed_log_num_strides_param >= 0;
}
-u8 mlx5e_mpwqe_get_log_rq_size(struct mlx5e_params *params)
+u8 mlx5e_mpwqe_get_log_rq_size(struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk)
{
- u8 log_pkts_per_wqe = mlx5e_mpwqe_log_pkts_per_wqe(params);
+ u8 log_pkts_per_wqe = mlx5e_mpwqe_log_pkts_per_wqe(params, xsk);
/* Numbers are unsigned, don't subtract to avoid underflow. */
if (params->log_rq_mtu_frames <
@@ -72,33 +109,30 @@ u8 mlx5e_mpwqe_get_log_rq_size(struct mlx5e_params *params)
}
u8 mlx5e_mpwqe_get_log_stride_size(struct mlx5_core_dev *mdev,
- struct mlx5e_params *params)
+ struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk)
{
- if (mlx5e_rx_mpwqe_is_linear_skb(mdev, params))
- return order_base_2(mlx5e_rx_get_linear_frag_sz(params));
+ if (mlx5e_rx_mpwqe_is_linear_skb(mdev, params, xsk))
+ return order_base_2(mlx5e_rx_get_linear_frag_sz(params, xsk));
return MLX5_MPWRQ_DEF_LOG_STRIDE_SZ(mdev);
}
u8 mlx5e_mpwqe_get_log_num_strides(struct mlx5_core_dev *mdev,
- struct mlx5e_params *params)
+ struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk)
{
return MLX5_MPWRQ_LOG_WQE_SZ -
- mlx5e_mpwqe_get_log_stride_size(mdev, params);
+ mlx5e_mpwqe_get_log_stride_size(mdev, params, xsk);
}
u16 mlx5e_get_rq_headroom(struct mlx5_core_dev *mdev,
- struct mlx5e_params *params)
+ struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk)
{
- u16 linear_rq_headroom = params->xdp_prog ?
- XDP_PACKET_HEADROOM : MLX5_RX_HEADROOM;
- bool is_linear_skb;
-
- linear_rq_headroom += NET_IP_ALIGN;
-
- is_linear_skb = (params->rq_wq_type == MLX5_WQ_TYPE_CYCLIC) ?
- mlx5e_rx_is_linear_skb(params) :
- mlx5e_rx_mpwqe_is_linear_skb(mdev, params);
+ bool is_linear_skb = (params->rq_wq_type == MLX5_WQ_TYPE_CYCLIC) ?
+ mlx5e_rx_is_linear_skb(params, xsk) :
+ mlx5e_rx_mpwqe_is_linear_skb(mdev, params, xsk);
- return is_linear_skb ? linear_rq_headroom : 0;
+ return is_linear_skb ? mlx5e_get_linear_rq_headroom(params, xsk) : 0;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/params.h b/drivers/net/ethernet/mellanox/mlx5/core/en/params.h
index b106a0236f36..bd882b5ee9a7 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/params.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/params.h
@@ -6,17 +6,119 @@
#include "en.h"
-u32 mlx5e_rx_get_linear_frag_sz(struct mlx5e_params *params);
-u8 mlx5e_mpwqe_log_pkts_per_wqe(struct mlx5e_params *params);
-bool mlx5e_rx_is_linear_skb(struct mlx5e_params *params);
+struct mlx5e_xsk_param {
+ u16 headroom;
+ u16 chunk_size;
+};
+
+struct mlx5e_rq_param {
+ u32 rqc[MLX5_ST_SZ_DW(rqc)];
+ struct mlx5_wq_param wq;
+ struct mlx5e_rq_frags_info frags_info;
+};
+
+struct mlx5e_sq_param {
+ u32 sqc[MLX5_ST_SZ_DW(sqc)];
+ struct mlx5_wq_param wq;
+ bool is_mpw;
+};
+
+struct mlx5e_cq_param {
+ u32 cqc[MLX5_ST_SZ_DW(cqc)];
+ struct mlx5_wq_param wq;
+ u16 eq_ix;
+ u8 cq_period_mode;
+};
+
+struct mlx5e_channel_param {
+ struct mlx5e_rq_param rq;
+ struct mlx5e_sq_param sq;
+ struct mlx5e_sq_param xdp_sq;
+ struct mlx5e_sq_param icosq;
+ struct mlx5e_cq_param rx_cq;
+ struct mlx5e_cq_param tx_cq;
+ struct mlx5e_cq_param icosq_cq;
+};
+
+static inline bool mlx5e_qid_get_ch_if_in_group(struct mlx5e_params *params,
+ u16 qid,
+ enum mlx5e_rq_group group,
+ u16 *ix)
+{
+ int nch = params->num_channels;
+ int ch = qid - nch * group;
+
+ if (ch < 0 || ch >= nch)
+ return false;
+
+ *ix = ch;
+ return true;
+}
+
+static inline void mlx5e_qid_get_ch_and_group(struct mlx5e_params *params,
+ u16 qid,
+ u16 *ix,
+ enum mlx5e_rq_group *group)
+{
+ u16 nch = params->num_channels;
+
+ *ix = qid % nch;
+ *group = qid / nch;
+}
+
+static inline bool mlx5e_qid_validate(struct mlx5e_params *params, u64 qid)
+{
+ return qid < params->num_channels * MLX5E_NUM_RQ_GROUPS;
+}
+
+/* Parameter calculations */
+
+u16 mlx5e_get_linear_rq_headroom(struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk);
+u32 mlx5e_rx_get_linear_frag_sz(struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk);
+u8 mlx5e_mpwqe_log_pkts_per_wqe(struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk);
+bool mlx5e_rx_is_linear_skb(struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk);
bool mlx5e_rx_mpwqe_is_linear_skb(struct mlx5_core_dev *mdev,
- struct mlx5e_params *params);
-u8 mlx5e_mpwqe_get_log_rq_size(struct mlx5e_params *params);
+ struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk);
+u8 mlx5e_mpwqe_get_log_rq_size(struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk);
u8 mlx5e_mpwqe_get_log_stride_size(struct mlx5_core_dev *mdev,
- struct mlx5e_params *params);
+ struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk);
u8 mlx5e_mpwqe_get_log_num_strides(struct mlx5_core_dev *mdev,
- struct mlx5e_params *params);
+ struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk);
u16 mlx5e_get_rq_headroom(struct mlx5_core_dev *mdev,
- struct mlx5e_params *params);
+ struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk);
+
+/* Build queue parameters */
+
+void mlx5e_build_rq_param(struct mlx5e_priv *priv,
+ struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk,
+ struct mlx5e_rq_param *param);
+void mlx5e_build_sq_param_common(struct mlx5e_priv *priv,
+ struct mlx5e_sq_param *param);
+void mlx5e_build_rx_cq_param(struct mlx5e_priv *priv,
+ struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk,
+ struct mlx5e_cq_param *param);
+void mlx5e_build_tx_cq_param(struct mlx5e_priv *priv,
+ struct mlx5e_params *params,
+ struct mlx5e_cq_param *param);
+void mlx5e_build_ico_cq_param(struct mlx5e_priv *priv,
+ u8 log_wq_size,
+ struct mlx5e_cq_param *param);
+void mlx5e_build_icosq_param(struct mlx5e_priv *priv,
+ u8 log_wq_size,
+ struct mlx5e_sq_param *param);
+void mlx5e_build_xdpsq_param(struct mlx5e_priv *priv,
+ struct mlx5e_params *params,
+ struct mlx5e_sq_param *param);
#endif /* __MLX5_EN_PARAMS_H__ */
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 476dd97f7f2f..f3d98748b211 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
@@ -142,22 +142,20 @@ static int mlx5e_tx_reporter_timeout_recover(struct mlx5e_txqsq *sq)
{
struct mlx5_eq_comp *eq = sq->cq.mcq.eq;
u32 eqe_count;
- int ret;
netdev_err(sq->channel->netdev, "EQ 0x%x: Cons = 0x%x, irqn = 0x%x\n",
eq->core.eqn, eq->core.cons_index, eq->core.irqn);
eqe_count = mlx5_eq_poll_irq_disabled(eq);
- ret = eqe_count ? false : true;
if (!eqe_count) {
clear_bit(MLX5E_SQ_STATE_ENABLED, &sq->state);
- return ret;
+ return -EIO;
}
netdev_err(sq->channel->netdev, "Recover %d eqes on EQ 0x%x\n",
eqe_count, eq->core.eqn);
sq->channel->stats->eq_rearm++;
- return ret;
+ return 0;
}
int mlx5e_tx_reporter_timeout(struct mlx5e_txqsq *sq)
@@ -264,13 +262,13 @@ static int mlx5e_tx_reporter_diagnose(struct devlink_health_reporter *reporter,
err = mlx5_core_query_sq_state(priv->mdev, sq->sqn, &state);
if (err)
- break;
+ goto unlock;
err = mlx5e_tx_reporter_build_diagnose_output(fmsg, sq->sqn,
state,
netif_xmit_stopped(sq->txq));
if (err)
- break;
+ goto unlock;
}
err = devlink_fmsg_arr_pair_nest_end(fmsg);
if (err)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c
index fe5d4d7f15ed..a6a52806be45 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c
@@ -3,37 +3,53 @@
#include <net/vxlan.h>
#include <net/gre.h>
-#include "lib/vxlan.h"
+#include <net/geneve.h>
#include "en/tc_tun.h"
+#include "en_tc.h"
+
+struct mlx5e_tc_tunnel *mlx5e_get_tc_tun(struct net_device *tunnel_dev)
+{
+ if (netif_is_vxlan(tunnel_dev))
+ return &vxlan_tunnel;
+ else if (netif_is_geneve(tunnel_dev))
+ return &geneve_tunnel;
+ else if (netif_is_gretap(tunnel_dev) ||
+ netif_is_ip6gretap(tunnel_dev))
+ return &gre_tunnel;
+ else
+ return NULL;
+}
static int get_route_and_out_devs(struct mlx5e_priv *priv,
struct net_device *dev,
struct net_device **route_dev,
struct net_device **out_dev)
{
+ struct net_device *uplink_dev, *uplink_upper, *real_dev;
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
- struct net_device *uplink_dev, *uplink_upper;
bool dst_is_lag_dev;
+ real_dev = is_vlan_dev(dev) ? vlan_dev_real_dev(dev) : dev;
uplink_dev = mlx5_eswitch_uplink_get_proto_dev(esw, REP_ETH);
uplink_upper = netdev_master_upper_dev_get(uplink_dev);
dst_is_lag_dev = (uplink_upper &&
netif_is_lag_master(uplink_upper) &&
- dev == uplink_upper &&
+ real_dev == uplink_upper &&
mlx5_lag_is_sriov(priv->mdev));
/* if the egress device isn't on the same HW e-switch or
* it's a LAG device, use the uplink
*/
- if (!netdev_port_same_parent_id(priv->netdev, dev) ||
+ if (!netdev_port_same_parent_id(priv->netdev, real_dev) ||
dst_is_lag_dev) {
- *route_dev = uplink_dev;
- *out_dev = *route_dev;
+ *route_dev = dev;
+ *out_dev = uplink_dev;
} else {
*route_dev = dev;
if (is_vlan_dev(*route_dev))
*out_dev = uplink_dev;
- else if (mlx5e_eswitch_rep(dev))
+ else if (mlx5e_eswitch_rep(dev) &&
+ mlx5e_is_valid_eswitch_fwd_dev(priv, dev))
*out_dev = *route_dev;
else
return -EOPNOTSUPP;
@@ -141,63 +157,15 @@ static int mlx5e_route_lookup_ipv6(struct mlx5e_priv *priv,
return 0;
}
-static int mlx5e_gen_vxlan_header(char buf[], struct ip_tunnel_key *tun_key)
-{
- __be32 tun_id = tunnel_id_to_key32(tun_key->tun_id);
- struct udphdr *udp = (struct udphdr *)(buf);
- struct vxlanhdr *vxh = (struct vxlanhdr *)
- ((char *)udp + sizeof(struct udphdr));
-
- udp->dest = tun_key->tp_dst;
- vxh->vx_flags = VXLAN_HF_VNI;
- vxh->vx_vni = vxlan_vni_field(tun_id);
-
- return 0;
-}
-
-static int mlx5e_gen_gre_header(char buf[], struct ip_tunnel_key *tun_key)
-{
- __be32 tun_id = tunnel_id_to_key32(tun_key->tun_id);
- int hdr_len;
- struct gre_base_hdr *greh = (struct gre_base_hdr *)(buf);
-
- /* the HW does not calculate GRE csum or sequences */
- if (tun_key->tun_flags & (TUNNEL_CSUM | TUNNEL_SEQ))
- return -EOPNOTSUPP;
-
- greh->protocol = htons(ETH_P_TEB);
-
- /* GRE key */
- hdr_len = gre_calc_hlen(tun_key->tun_flags);
- greh->flags = gre_tnl_flags_to_gre_flags(tun_key->tun_flags);
- if (tun_key->tun_flags & TUNNEL_KEY) {
- __be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4);
-
- *ptr = tun_id;
- }
-
- return 0;
-}
-
static int mlx5e_gen_ip_tunnel_header(char buf[], __u8 *ip_proto,
struct mlx5e_encap_entry *e)
{
- int err = 0;
- struct ip_tunnel_key *key = &e->tun_info.key;
-
- if (e->tunnel_type == MLX5E_TC_TUNNEL_TYPE_VXLAN) {
- *ip_proto = IPPROTO_UDP;
- err = mlx5e_gen_vxlan_header(buf, key);
- } else if (e->tunnel_type == MLX5E_TC_TUNNEL_TYPE_GRETAP) {
- *ip_proto = IPPROTO_GRE;
- err = mlx5e_gen_gre_header(buf, key);
- } else {
- pr_warn("mlx5: Cannot generate tunnel header for tunnel type (%d)\n"
- , e->tunnel_type);
- err = -EOPNOTSUPP;
+ if (!e->tunnel) {
+ pr_warn("mlx5: Cannot generate tunnel header for this tunnel\n");
+ return -EOPNOTSUPP;
}
- return err;
+ return e->tunnel->generate_ip_tun_hdr(buf, ip_proto, e);
}
static char *gen_eth_tnl_hdr(char *buf, struct net_device *dev,
@@ -229,7 +197,7 @@ int mlx5e_tc_tun_create_header_ipv4(struct mlx5e_priv *priv,
struct mlx5e_encap_entry *e)
{
int max_encap_size = MLX5_CAP_ESW(priv->mdev, max_encap_header_size);
- struct ip_tunnel_key *tun_key = &e->tun_info.key;
+ const struct ip_tunnel_key *tun_key = &e->tun_info->key;
struct net_device *out_dev, *route_dev;
struct neighbour *n = NULL;
struct flowi4 fl4 = {};
@@ -253,7 +221,7 @@ int mlx5e_tc_tun_create_header_ipv4(struct mlx5e_priv *priv,
ipv4_encap_size =
(is_vlan_dev(route_dev) ? VLAN_ETH_HLEN : ETH_HLEN) +
sizeof(struct iphdr) +
- e->tunnel_hlen;
+ e->tunnel->calc_hlen(e);
if (max_encap_size < ipv4_encap_size) {
mlx5_core_warn(priv->mdev, "encap size %d too big, max supported is %d\n",
@@ -345,7 +313,7 @@ int mlx5e_tc_tun_create_header_ipv6(struct mlx5e_priv *priv,
struct mlx5e_encap_entry *e)
{
int max_encap_size = MLX5_CAP_ESW(priv->mdev, max_encap_header_size);
- struct ip_tunnel_key *tun_key = &e->tun_info.key;
+ const struct ip_tunnel_key *tun_key = &e->tun_info->key;
struct net_device *out_dev, *route_dev;
struct neighbour *n = NULL;
struct flowi6 fl6 = {};
@@ -369,7 +337,7 @@ int mlx5e_tc_tun_create_header_ipv6(struct mlx5e_priv *priv,
ipv6_encap_size =
(is_vlan_dev(route_dev) ? VLAN_ETH_HLEN : ETH_HLEN) +
sizeof(struct ipv6hdr) +
- e->tunnel_hlen;
+ e->tunnel->calc_hlen(e);
if (max_encap_size < ipv6_encap_size) {
mlx5_core_warn(priv->mdev, "encap size %d too big, max supported is %d\n",
@@ -455,27 +423,12 @@ out:
return err;
}
-int mlx5e_tc_tun_get_type(struct net_device *tunnel_dev)
-{
- if (netif_is_vxlan(tunnel_dev))
- return MLX5E_TC_TUNNEL_TYPE_VXLAN;
- else if (netif_is_gretap(tunnel_dev) ||
- netif_is_ip6gretap(tunnel_dev))
- return MLX5E_TC_TUNNEL_TYPE_GRETAP;
- else
- return MLX5E_TC_TUNNEL_TYPE_UNKNOWN;
-}
-
bool mlx5e_tc_tun_device_to_offload(struct mlx5e_priv *priv,
struct net_device *netdev)
{
- int tunnel_type = mlx5e_tc_tun_get_type(netdev);
+ struct mlx5e_tc_tunnel *tunnel = mlx5e_get_tc_tun(netdev);
- if (tunnel_type == MLX5E_TC_TUNNEL_TYPE_VXLAN &&
- MLX5_CAP_ESW(priv->mdev, vxlan_encap_decap))
- return true;
- else if (tunnel_type == MLX5E_TC_TUNNEL_TYPE_GRETAP &&
- MLX5_CAP_ESW(priv->mdev, nvgre_encap_decap))
+ if (tunnel && tunnel->can_offload(priv))
return true;
else
return false;
@@ -486,71 +439,87 @@ int mlx5e_tc_tun_init_encap_attr(struct net_device *tunnel_dev,
struct mlx5e_encap_entry *e,
struct netlink_ext_ack *extack)
{
- e->tunnel_type = mlx5e_tc_tun_get_type(tunnel_dev);
-
- if (e->tunnel_type == MLX5E_TC_TUNNEL_TYPE_VXLAN) {
- int dst_port = be16_to_cpu(e->tun_info.key.tp_dst);
+ struct mlx5e_tc_tunnel *tunnel = mlx5e_get_tc_tun(tunnel_dev);
- if (!mlx5_vxlan_lookup_port(priv->mdev->vxlan, dst_port)) {
- NL_SET_ERR_MSG_MOD(extack,
- "vxlan udp dport was not registered with the HW");
- netdev_warn(priv->netdev,
- "%d isn't an offloaded vxlan udp dport\n",
- dst_port);
- return -EOPNOTSUPP;
- }
- e->reformat_type = MLX5_REFORMAT_TYPE_L2_TO_VXLAN;
- e->tunnel_hlen = VXLAN_HLEN;
- } else if (e->tunnel_type == MLX5E_TC_TUNNEL_TYPE_GRETAP) {
- e->reformat_type = MLX5_REFORMAT_TYPE_L2_TO_NVGRE;
- e->tunnel_hlen = gre_calc_hlen(e->tun_info.key.tun_flags);
- } else {
+ if (!tunnel) {
e->reformat_type = -1;
- e->tunnel_hlen = -1;
return -EOPNOTSUPP;
}
- return 0;
+
+ return tunnel->init_encap_attr(tunnel_dev, priv, e, extack);
+}
+
+int mlx5e_tc_tun_parse(struct net_device *filter_dev,
+ struct mlx5e_priv *priv,
+ struct mlx5_flow_spec *spec,
+ struct flow_cls_offload *f,
+ void *headers_c,
+ void *headers_v, u8 *match_level)
+{
+ struct mlx5e_tc_tunnel *tunnel = mlx5e_get_tc_tun(filter_dev);
+ int err = 0;
+
+ if (!tunnel) {
+ netdev_warn(priv->netdev,
+ "decapsulation offload is not supported for %s net device\n",
+ mlx5e_netdev_kind(filter_dev));
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ *match_level = tunnel->match_level;
+
+ if (tunnel->parse_udp_ports) {
+ err = tunnel->parse_udp_ports(priv, spec, f,
+ headers_c, headers_v);
+ if (err)
+ goto out;
+ }
+
+ if (tunnel->parse_tunnel) {
+ err = tunnel->parse_tunnel(priv, spec, f,
+ headers_c, headers_v);
+ if (err)
+ goto out;
+ }
+
+out:
+ return err;
}
-static int mlx5e_tc_tun_parse_vxlan(struct mlx5e_priv *priv,
- struct mlx5_flow_spec *spec,
- struct tc_cls_flower_offload *f,
- void *headers_c,
- void *headers_v)
+int mlx5e_tc_tun_parse_udp_ports(struct mlx5e_priv *priv,
+ struct mlx5_flow_spec *spec,
+ struct flow_cls_offload *f,
+ void *headers_c,
+ void *headers_v)
{
- struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
+ struct flow_rule *rule = flow_cls_offload_flow_rule(f);
struct netlink_ext_ack *extack = f->common.extack;
- void *misc_c = MLX5_ADDR_OF(fte_match_param,
- spec->match_criteria,
- misc_parameters);
- void *misc_v = MLX5_ADDR_OF(fte_match_param,
- spec->match_value,
- misc_parameters);
struct flow_match_ports enc_ports;
- flow_rule_match_enc_ports(rule, &enc_ports);
-
/* Full udp dst port must be given */
- if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_PORTS) ||
- memchr_inv(&enc_ports.mask->dst, 0xff, sizeof(enc_ports.mask->dst))) {
+
+ if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_PORTS)) {
NL_SET_ERR_MSG_MOD(extack,
- "VXLAN decap filter must include enc_dst_port condition");
+ "UDP tunnel decap filter must include enc_dst_port condition");
netdev_warn(priv->netdev,
- "VXLAN decap filter must include enc_dst_port condition\n");
+ "UDP tunnel decap filter must include enc_dst_port condition\n");
return -EOPNOTSUPP;
}
- /* udp dst port must be knonwn as a VXLAN port */
- if (!mlx5_vxlan_lookup_port(priv->mdev->vxlan, be16_to_cpu(enc_ports.key->dst))) {
+ flow_rule_match_enc_ports(rule, &enc_ports);
+
+ if (memchr_inv(&enc_ports.mask->dst, 0xff,
+ sizeof(enc_ports.mask->dst))) {
NL_SET_ERR_MSG_MOD(extack,
- "Matched UDP port is not registered as a VXLAN port");
+ "UDP tunnel decap filter must match enc_dst_port fully");
netdev_warn(priv->netdev,
- "UDP port %d is not registered as a VXLAN port\n",
- be16_to_cpu(enc_ports.key->dst));
+ "UDP tunnel decap filter must match enc_dst_port fully\n");
return -EOPNOTSUPP;
}
- /* dst UDP port is valid here */
+ /* match on UDP protocol and dst port number */
+
MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ip_protocol);
MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_UDP);
@@ -559,92 +528,15 @@ static int mlx5e_tc_tun_parse_vxlan(struct mlx5e_priv *priv,
MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport,
ntohs(enc_ports.key->dst));
+ /* UDP src port on outer header is generated by HW,
+ * so it is probably a bad idea to request matching it.
+ * Nonetheless, it is allowed.
+ */
+
MLX5_SET(fte_match_set_lyr_2_4, headers_c, udp_sport,
ntohs(enc_ports.mask->src));
MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_sport,
ntohs(enc_ports.key->src));
- /* match on VNI */
- if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
- struct flow_match_enc_keyid enc_keyid;
-
- flow_rule_match_enc_keyid(rule, &enc_keyid);
-
- MLX5_SET(fte_match_set_misc, misc_c, vxlan_vni,
- be32_to_cpu(enc_keyid.mask->keyid));
- MLX5_SET(fte_match_set_misc, misc_v, vxlan_vni,
- be32_to_cpu(enc_keyid.key->keyid));
- }
return 0;
}
-
-static int mlx5e_tc_tun_parse_gretap(struct mlx5e_priv *priv,
- struct mlx5_flow_spec *spec,
- struct tc_cls_flower_offload *f,
- void *outer_headers_c,
- void *outer_headers_v)
-{
- void *misc_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
- misc_parameters);
- void *misc_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
- misc_parameters);
- struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
-
- if (!MLX5_CAP_ESW(priv->mdev, nvgre_encap_decap)) {
- NL_SET_ERR_MSG_MOD(f->common.extack,
- "GRE HW offloading is not supported");
- netdev_warn(priv->netdev, "GRE HW offloading is not supported\n");
- return -EOPNOTSUPP;
- }
-
- MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, ip_protocol);
- MLX5_SET(fte_match_set_lyr_2_4, outer_headers_v,
- ip_protocol, IPPROTO_GRE);
-
- /* gre protocol*/
- MLX5_SET_TO_ONES(fte_match_set_misc, misc_c, gre_protocol);
- MLX5_SET(fte_match_set_misc, misc_v, gre_protocol, ETH_P_TEB);
-
- /* gre key */
- if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
- struct flow_match_enc_keyid enc_keyid;
-
- flow_rule_match_enc_keyid(rule, &enc_keyid);
- MLX5_SET(fte_match_set_misc, misc_c,
- gre_key.key, be32_to_cpu(enc_keyid.mask->keyid));
- MLX5_SET(fte_match_set_misc, misc_v,
- gre_key.key, be32_to_cpu(enc_keyid.key->keyid));
- }
-
- return 0;
-}
-
-int mlx5e_tc_tun_parse(struct net_device *filter_dev,
- struct mlx5e_priv *priv,
- struct mlx5_flow_spec *spec,
- struct tc_cls_flower_offload *f,
- void *headers_c,
- void *headers_v, u8 *match_level)
-{
- int tunnel_type;
- int err = 0;
-
- tunnel_type = mlx5e_tc_tun_get_type(filter_dev);
- if (tunnel_type == MLX5E_TC_TUNNEL_TYPE_VXLAN) {
- *match_level = MLX5_MATCH_L4;
- err = mlx5e_tc_tun_parse_vxlan(priv, spec, f,
- headers_c, headers_v);
- } else if (tunnel_type == MLX5E_TC_TUNNEL_TYPE_GRETAP) {
- *match_level = MLX5_MATCH_L3;
- err = mlx5e_tc_tun_parse_gretap(priv, spec, f,
- headers_c, headers_v);
- } else {
- netdev_warn(priv->netdev,
- "decapsulation offload is not supported for %s (kind: \"%s\")\n",
- netdev_name(filter_dev),
- mlx5e_netdev_kind(filter_dev));
-
- return -EOPNOTSUPP;
- }
- return err;
-}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.h b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.h
index b63f15de899d..c362b9225dc2 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.h
@@ -14,9 +14,41 @@
enum {
MLX5E_TC_TUNNEL_TYPE_UNKNOWN,
MLX5E_TC_TUNNEL_TYPE_VXLAN,
- MLX5E_TC_TUNNEL_TYPE_GRETAP
+ MLX5E_TC_TUNNEL_TYPE_GENEVE,
+ MLX5E_TC_TUNNEL_TYPE_GRETAP,
};
+struct mlx5e_tc_tunnel {
+ int tunnel_type;
+ enum mlx5_flow_match_level match_level;
+
+ bool (*can_offload)(struct mlx5e_priv *priv);
+ int (*calc_hlen)(struct mlx5e_encap_entry *e);
+ int (*init_encap_attr)(struct net_device *tunnel_dev,
+ struct mlx5e_priv *priv,
+ struct mlx5e_encap_entry *e,
+ struct netlink_ext_ack *extack);
+ int (*generate_ip_tun_hdr)(char buf[],
+ __u8 *ip_proto,
+ struct mlx5e_encap_entry *e);
+ int (*parse_udp_ports)(struct mlx5e_priv *priv,
+ struct mlx5_flow_spec *spec,
+ struct flow_cls_offload *f,
+ void *headers_c,
+ void *headers_v);
+ int (*parse_tunnel)(struct mlx5e_priv *priv,
+ struct mlx5_flow_spec *spec,
+ struct flow_cls_offload *f,
+ void *headers_c,
+ void *headers_v);
+};
+
+extern struct mlx5e_tc_tunnel vxlan_tunnel;
+extern struct mlx5e_tc_tunnel geneve_tunnel;
+extern struct mlx5e_tc_tunnel gre_tunnel;
+
+struct mlx5e_tc_tunnel *mlx5e_get_tc_tun(struct net_device *tunnel_dev);
+
int mlx5e_tc_tun_init_encap_attr(struct net_device *tunnel_dev,
struct mlx5e_priv *priv,
struct mlx5e_encap_entry *e,
@@ -30,15 +62,20 @@ int mlx5e_tc_tun_create_header_ipv6(struct mlx5e_priv *priv,
struct net_device *mirred_dev,
struct mlx5e_encap_entry *e);
-int mlx5e_tc_tun_get_type(struct net_device *tunnel_dev);
bool mlx5e_tc_tun_device_to_offload(struct mlx5e_priv *priv,
struct net_device *netdev);
int mlx5e_tc_tun_parse(struct net_device *filter_dev,
struct mlx5e_priv *priv,
struct mlx5_flow_spec *spec,
- struct tc_cls_flower_offload *f,
+ struct flow_cls_offload *f,
void *headers_c,
void *headers_v, u8 *match_level);
+int mlx5e_tc_tun_parse_udp_ports(struct mlx5e_priv *priv,
+ struct mlx5_flow_spec *spec,
+ struct flow_cls_offload *f,
+ void *headers_c,
+ void *headers_v);
+
#endif //__MLX5_EN_TC_TUNNEL_H__
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_geneve.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_geneve.c
new file mode 100644
index 000000000000..951ea26d96bc
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_geneve.c
@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/* Copyright (c) 2018 Mellanox Technologies. */
+
+#include <net/geneve.h>
+#include "lib/geneve.h"
+#include "en/tc_tun.h"
+
+#define MLX5E_GENEVE_VER 0
+
+static bool mlx5e_tc_tun_can_offload_geneve(struct mlx5e_priv *priv)
+{
+ return !!(MLX5_CAP_GEN(priv->mdev, flex_parser_protocols) & MLX5_FLEX_PROTO_GENEVE);
+}
+
+static int mlx5e_tc_tun_calc_hlen_geneve(struct mlx5e_encap_entry *e)
+{
+ return sizeof(struct udphdr) +
+ sizeof(struct genevehdr) +
+ e->tun_info->options_len;
+}
+
+static int mlx5e_tc_tun_check_udp_dport_geneve(struct mlx5e_priv *priv,
+ struct flow_cls_offload *f)
+{
+ struct flow_rule *rule = flow_cls_offload_flow_rule(f);
+ struct netlink_ext_ack *extack = f->common.extack;
+ struct flow_match_ports enc_ports;
+
+ if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_PORTS))
+ return -EOPNOTSUPP;
+
+ flow_rule_match_enc_ports(rule, &enc_ports);
+
+ /* Currently we support only default GENEVE
+ * port, so udp dst port must match.
+ */
+ if (be16_to_cpu(enc_ports.key->dst) != GENEVE_UDP_PORT) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Matched UDP dst port is not registered as a GENEVE port");
+ netdev_warn(priv->netdev,
+ "UDP port %d is not registered as a GENEVE port\n",
+ be16_to_cpu(enc_ports.key->dst));
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int mlx5e_tc_tun_parse_udp_ports_geneve(struct mlx5e_priv *priv,
+ struct mlx5_flow_spec *spec,
+ struct flow_cls_offload *f,
+ void *headers_c,
+ void *headers_v)
+{
+ int err;
+
+ err = mlx5e_tc_tun_parse_udp_ports(priv, spec, f, headers_c, headers_v);
+ if (err)
+ return err;
+
+ return mlx5e_tc_tun_check_udp_dport_geneve(priv, f);
+}
+
+static int mlx5e_tc_tun_init_encap_attr_geneve(struct net_device *tunnel_dev,
+ struct mlx5e_priv *priv,
+ struct mlx5e_encap_entry *e,
+ struct netlink_ext_ack *extack)
+{
+ e->tunnel = &geneve_tunnel;
+
+ /* Reformat type for GENEVE encap is similar to VXLAN:
+ * in both cases the HW adds in the same place a
+ * defined encapsulation header that the SW provides.
+ */
+ e->reformat_type = MLX5_REFORMAT_TYPE_L2_TO_VXLAN;
+ return 0;
+}
+
+static void mlx5e_tunnel_id_to_vni(__be64 tun_id, __u8 *vni)
+{
+#ifdef __BIG_ENDIAN
+ vni[0] = (__force __u8)(tun_id >> 16);
+ vni[1] = (__force __u8)(tun_id >> 8);
+ vni[2] = (__force __u8)tun_id;
+#else
+ vni[0] = (__force __u8)((__force u64)tun_id >> 40);
+ vni[1] = (__force __u8)((__force u64)tun_id >> 48);
+ vni[2] = (__force __u8)((__force u64)tun_id >> 56);
+#endif
+}
+
+static int mlx5e_gen_ip_tunnel_header_geneve(char buf[],
+ __u8 *ip_proto,
+ struct mlx5e_encap_entry *e)
+{
+ const struct ip_tunnel_info *tun_info = e->tun_info;
+ struct udphdr *udp = (struct udphdr *)(buf);
+ struct genevehdr *geneveh;
+
+ geneveh = (struct genevehdr *)((char *)udp + sizeof(struct udphdr));
+
+ *ip_proto = IPPROTO_UDP;
+
+ udp->dest = tun_info->key.tp_dst;
+
+ memset(geneveh, 0, sizeof(*geneveh));
+ geneveh->ver = MLX5E_GENEVE_VER;
+ geneveh->opt_len = tun_info->options_len / 4;
+ geneveh->oam = !!(tun_info->key.tun_flags & TUNNEL_OAM);
+ geneveh->critical = !!(tun_info->key.tun_flags & TUNNEL_CRIT_OPT);
+ mlx5e_tunnel_id_to_vni(tun_info->key.tun_id, geneveh->vni);
+ geneveh->proto_type = htons(ETH_P_TEB);
+
+ if (tun_info->key.tun_flags & TUNNEL_GENEVE_OPT) {
+ if (!geneveh->opt_len)
+ return -EOPNOTSUPP;
+ ip_tunnel_info_opts_get(geneveh->options, tun_info);
+ }
+
+ return 0;
+}
+
+static int mlx5e_tc_tun_parse_geneve_vni(struct mlx5e_priv *priv,
+ struct mlx5_flow_spec *spec,
+ struct flow_cls_offload *f)
+{
+ struct flow_rule *rule = flow_cls_offload_flow_rule(f);
+ struct netlink_ext_ack *extack = f->common.extack;
+ struct flow_match_enc_keyid enc_keyid;
+ void *misc_c, *misc_v;
+
+ misc_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
+ misc_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
+
+ if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID))
+ return 0;
+
+ flow_rule_match_enc_keyid(rule, &enc_keyid);
+
+ if (!enc_keyid.mask->keyid)
+ return 0;
+
+ if (!MLX5_CAP_ESW_FLOWTABLE_FDB(priv->mdev, ft_field_support.outer_geneve_vni)) {
+ NL_SET_ERR_MSG_MOD(extack, "Matching on GENEVE VNI is not supported");
+ netdev_warn(priv->netdev, "Matching on GENEVE VNI is not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ MLX5_SET(fte_match_set_misc, misc_c, geneve_vni, be32_to_cpu(enc_keyid.mask->keyid));
+ MLX5_SET(fte_match_set_misc, misc_v, geneve_vni, be32_to_cpu(enc_keyid.key->keyid));
+
+ return 0;
+}
+
+static int mlx5e_tc_tun_parse_geneve_options(struct mlx5e_priv *priv,
+ struct mlx5_flow_spec *spec,
+ struct flow_cls_offload *f)
+{
+ u8 max_tlv_option_data_len = MLX5_CAP_GEN(priv->mdev, max_geneve_tlv_option_data_len);
+ u8 max_tlv_options = MLX5_CAP_GEN(priv->mdev, max_geneve_tlv_options);
+ struct flow_rule *rule = flow_cls_offload_flow_rule(f);
+ struct netlink_ext_ack *extack = f->common.extack;
+ void *misc_c, *misc_v, *misc_3_c, *misc_3_v;
+ struct geneve_opt *option_key, *option_mask;
+ __be32 opt_data_key = 0, opt_data_mask = 0;
+ struct flow_match_enc_opts enc_opts;
+ int res = 0;
+
+ misc_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
+ misc_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
+ misc_3_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters_3);
+ misc_3_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters_3);
+
+ if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_OPTS))
+ return 0;
+
+ flow_rule_match_enc_opts(rule, &enc_opts);
+
+ if (memchr_inv(&enc_opts.mask->data, 0, sizeof(enc_opts.mask->data)) &&
+ !MLX5_CAP_ESW_FLOWTABLE_FDB(priv->mdev,
+ ft_field_support.geneve_tlv_option_0_data)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Matching on GENEVE options is not supported");
+ netdev_warn(priv->netdev,
+ "Matching on GENEVE options is not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ /* make sure that we're talking about GENEVE options */
+
+ if (enc_opts.key->dst_opt_type != TUNNEL_GENEVE_OPT) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Matching on GENEVE options: option type is not GENEVE");
+ netdev_warn(priv->netdev,
+ "Matching on GENEVE options: option type is not GENEVE\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (enc_opts.mask->len &&
+ !MLX5_CAP_ESW_FLOWTABLE_FDB(priv->mdev,
+ ft_field_support.outer_geneve_opt_len)) {
+ NL_SET_ERR_MSG_MOD(extack, "Matching on GENEVE options len is not supported");
+ netdev_warn(priv->netdev,
+ "Matching on GENEVE options len is not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ /* max_geneve_tlv_option_data_len comes in multiples of 4 bytes, and it
+ * doesn't include the TLV option header. 'geneve_opt_len' is a total
+ * len of all the options, including the headers, also multiples of 4
+ * bytes. Len that comes from the dissector is in bytes.
+ */
+
+ if ((enc_opts.key->len / 4) > ((max_tlv_option_data_len + 1) * max_tlv_options)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Matching on GENEVE options: unsupported options len");
+ netdev_warn(priv->netdev,
+ "Matching on GENEVE options: unsupported options len (len=%d)\n",
+ enc_opts.key->len);
+ return -EOPNOTSUPP;
+ }
+
+ MLX5_SET(fte_match_set_misc, misc_c, geneve_opt_len, enc_opts.mask->len / 4);
+ MLX5_SET(fte_match_set_misc, misc_v, geneve_opt_len, enc_opts.key->len / 4);
+
+ /* we support matching on one option only, so just get it */
+ option_key = (struct geneve_opt *)&enc_opts.key->data[0];
+ option_mask = (struct geneve_opt *)&enc_opts.mask->data[0];
+
+ if (option_key->length > max_tlv_option_data_len) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Matching on GENEVE options: unsupported option len");
+ netdev_warn(priv->netdev,
+ "Matching on GENEVE options: unsupported option len (key=%d, mask=%d)\n",
+ option_key->length, option_mask->length);
+ return -EOPNOTSUPP;
+ }
+
+ /* data can't be all 0 - fail to offload such rule */
+ if (!memchr_inv(option_key->opt_data, 0, option_key->length * 4)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Matching on GENEVE options: can't match on 0 data field");
+ netdev_warn(priv->netdev,
+ "Matching on GENEVE options: can't match on 0 data field\n");
+ return -EOPNOTSUPP;
+ }
+
+ /* add new GENEVE TLV options object */
+ res = mlx5_geneve_tlv_option_add(priv->mdev->geneve, option_key);
+ if (res) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Matching on GENEVE options: failed creating TLV opt object");
+ netdev_warn(priv->netdev,
+ "Matching on GENEVE options: failed creating TLV opt object (class:type:len = 0x%x:0x%x:%d)\n",
+ be16_to_cpu(option_key->opt_class),
+ option_key->type, option_key->length);
+ return res;
+ }
+
+ /* In general, after creating the object, need to query it
+ * in order to check which option data to set in misc3.
+ * But we support only geneve_tlv_option_0_data, so no
+ * point querying at this stage.
+ */
+
+ memcpy(&opt_data_key, option_key->opt_data, option_key->length * 4);
+ memcpy(&opt_data_mask, option_mask->opt_data, option_mask->length * 4);
+ MLX5_SET(fte_match_set_misc3, misc_3_v,
+ geneve_tlv_option_0_data, be32_to_cpu(opt_data_key));
+ MLX5_SET(fte_match_set_misc3, misc_3_c,
+ geneve_tlv_option_0_data, be32_to_cpu(opt_data_mask));
+
+ spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_3;
+
+ return 0;
+}
+
+static int mlx5e_tc_tun_parse_geneve_params(struct mlx5e_priv *priv,
+ struct mlx5_flow_spec *spec,
+ struct flow_cls_offload *f)
+{
+ void *misc_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
+ void *misc_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
+ struct netlink_ext_ack *extack = f->common.extack;
+
+ /* match on OAM - packets with OAM bit on should NOT be offloaded */
+
+ if (!MLX5_CAP_ESW_FLOWTABLE_FDB(priv->mdev, ft_field_support.outer_geneve_oam)) {
+ NL_SET_ERR_MSG_MOD(extack, "Matching on GENEVE OAM is not supported");
+ netdev_warn(priv->netdev, "Matching on GENEVE OAM is not supported\n");
+ return -EOPNOTSUPP;
+ }
+ MLX5_SET_TO_ONES(fte_match_set_misc, misc_c, geneve_oam);
+ MLX5_SET(fte_match_set_misc, misc_v, geneve_oam, 0);
+
+ /* Match on GENEVE protocol. We support only Transparent Eth Bridge. */
+
+ if (MLX5_CAP_ESW_FLOWTABLE_FDB(priv->mdev,
+ ft_field_support.outer_geneve_protocol_type)) {
+ MLX5_SET_TO_ONES(fte_match_set_misc, misc_c, geneve_protocol_type);
+ MLX5_SET(fte_match_set_misc, misc_v, geneve_protocol_type, ETH_P_TEB);
+ }
+
+ return 0;
+}
+
+static int mlx5e_tc_tun_parse_geneve(struct mlx5e_priv *priv,
+ struct mlx5_flow_spec *spec,
+ struct flow_cls_offload *f,
+ void *headers_c,
+ void *headers_v)
+{
+ int err;
+
+ err = mlx5e_tc_tun_parse_geneve_params(priv, spec, f);
+ if (err)
+ return err;
+
+ err = mlx5e_tc_tun_parse_geneve_vni(priv, spec, f);
+ if (err)
+ return err;
+
+ return mlx5e_tc_tun_parse_geneve_options(priv, spec, f);
+}
+
+struct mlx5e_tc_tunnel geneve_tunnel = {
+ .tunnel_type = MLX5E_TC_TUNNEL_TYPE_GENEVE,
+ .match_level = MLX5_MATCH_L4,
+ .can_offload = mlx5e_tc_tun_can_offload_geneve,
+ .calc_hlen = mlx5e_tc_tun_calc_hlen_geneve,
+ .init_encap_attr = mlx5e_tc_tun_init_encap_attr_geneve,
+ .generate_ip_tun_hdr = mlx5e_gen_ip_tunnel_header_geneve,
+ .parse_udp_ports = mlx5e_tc_tun_parse_udp_ports_geneve,
+ .parse_tunnel = mlx5e_tc_tun_parse_geneve,
+};
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_gre.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_gre.c
new file mode 100644
index 000000000000..58b13192df23
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_gre.c
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/* Copyright (c) 2018 Mellanox Technologies. */
+
+#include <net/gre.h>
+#include "en/tc_tun.h"
+
+static bool mlx5e_tc_tun_can_offload_gretap(struct mlx5e_priv *priv)
+{
+ return !!MLX5_CAP_ESW(priv->mdev, nvgre_encap_decap);
+}
+
+static int mlx5e_tc_tun_calc_hlen_gretap(struct mlx5e_encap_entry *e)
+{
+ return gre_calc_hlen(e->tun_info->key.tun_flags);
+}
+
+static int mlx5e_tc_tun_init_encap_attr_gretap(struct net_device *tunnel_dev,
+ struct mlx5e_priv *priv,
+ struct mlx5e_encap_entry *e,
+ struct netlink_ext_ack *extack)
+{
+ e->tunnel = &gre_tunnel;
+ e->reformat_type = MLX5_REFORMAT_TYPE_L2_TO_NVGRE;
+ return 0;
+}
+
+static int mlx5e_gen_ip_tunnel_header_gretap(char buf[],
+ __u8 *ip_proto,
+ struct mlx5e_encap_entry *e)
+{
+ const struct ip_tunnel_key *tun_key = &e->tun_info->key;
+ struct gre_base_hdr *greh = (struct gre_base_hdr *)(buf);
+ __be32 tun_id = tunnel_id_to_key32(tun_key->tun_id);
+ int hdr_len;
+
+ *ip_proto = IPPROTO_GRE;
+
+ /* the HW does not calculate GRE csum or sequences */
+ if (tun_key->tun_flags & (TUNNEL_CSUM | TUNNEL_SEQ))
+ return -EOPNOTSUPP;
+
+ greh->protocol = htons(ETH_P_TEB);
+
+ /* GRE key */
+ hdr_len = mlx5e_tc_tun_calc_hlen_gretap(e);
+ greh->flags = gre_tnl_flags_to_gre_flags(tun_key->tun_flags);
+ if (tun_key->tun_flags & TUNNEL_KEY) {
+ __be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4);
+ *ptr = tun_id;
+ }
+
+ return 0;
+}
+
+static int mlx5e_tc_tun_parse_gretap(struct mlx5e_priv *priv,
+ struct mlx5_flow_spec *spec,
+ struct flow_cls_offload *f,
+ void *headers_c,
+ void *headers_v)
+{
+ void *misc_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
+ void *misc_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
+ struct flow_rule *rule = flow_cls_offload_flow_rule(f);
+
+ MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ip_protocol);
+ MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_GRE);
+
+ /* gre protocol */
+ MLX5_SET_TO_ONES(fte_match_set_misc, misc_c, gre_protocol);
+ MLX5_SET(fte_match_set_misc, misc_v, gre_protocol, ETH_P_TEB);
+
+ /* gre key */
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
+ struct flow_match_enc_keyid enc_keyid;
+
+ flow_rule_match_enc_keyid(rule, &enc_keyid);
+ MLX5_SET(fte_match_set_misc, misc_c,
+ gre_key.key, be32_to_cpu(enc_keyid.mask->keyid));
+ MLX5_SET(fte_match_set_misc, misc_v,
+ gre_key.key, be32_to_cpu(enc_keyid.key->keyid));
+ }
+
+ return 0;
+}
+
+struct mlx5e_tc_tunnel gre_tunnel = {
+ .tunnel_type = MLX5E_TC_TUNNEL_TYPE_GRETAP,
+ .match_level = MLX5_MATCH_L3,
+ .can_offload = mlx5e_tc_tun_can_offload_gretap,
+ .calc_hlen = mlx5e_tc_tun_calc_hlen_gretap,
+ .init_encap_attr = mlx5e_tc_tun_init_encap_attr_gretap,
+ .generate_ip_tun_hdr = mlx5e_gen_ip_tunnel_header_gretap,
+ .parse_udp_ports = NULL,
+ .parse_tunnel = mlx5e_tc_tun_parse_gretap,
+};
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_vxlan.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_vxlan.c
new file mode 100644
index 000000000000..37b176801bcc
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_vxlan.c
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/* Copyright (c) 2018 Mellanox Technologies. */
+
+#include <net/vxlan.h>
+#include "lib/vxlan.h"
+#include "en/tc_tun.h"
+
+static bool mlx5e_tc_tun_can_offload_vxlan(struct mlx5e_priv *priv)
+{
+ return !!MLX5_CAP_ESW(priv->mdev, vxlan_encap_decap);
+}
+
+static int mlx5e_tc_tun_calc_hlen_vxlan(struct mlx5e_encap_entry *e)
+{
+ return VXLAN_HLEN;
+}
+
+static int mlx5e_tc_tun_check_udp_dport_vxlan(struct mlx5e_priv *priv,
+ struct flow_cls_offload *f)
+{
+ struct flow_rule *rule = flow_cls_offload_flow_rule(f);
+ struct netlink_ext_ack *extack = f->common.extack;
+ struct flow_match_ports enc_ports;
+
+ if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_PORTS))
+ return -EOPNOTSUPP;
+
+ flow_rule_match_enc_ports(rule, &enc_ports);
+
+ /* check the UDP destination port validity */
+
+ if (!mlx5_vxlan_lookup_port(priv->mdev->vxlan,
+ be16_to_cpu(enc_ports.key->dst))) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Matched UDP dst port is not registered as a VXLAN port");
+ netdev_warn(priv->netdev,
+ "UDP port %d is not registered as a VXLAN port\n",
+ be16_to_cpu(enc_ports.key->dst));
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int mlx5e_tc_tun_parse_udp_ports_vxlan(struct mlx5e_priv *priv,
+ struct mlx5_flow_spec *spec,
+ struct flow_cls_offload *f,
+ void *headers_c,
+ void *headers_v)
+{
+ int err = 0;
+
+ err = mlx5e_tc_tun_parse_udp_ports(priv, spec, f, headers_c, headers_v);
+ if (err)
+ return err;
+
+ return mlx5e_tc_tun_check_udp_dport_vxlan(priv, f);
+}
+
+static int mlx5e_tc_tun_init_encap_attr_vxlan(struct net_device *tunnel_dev,
+ struct mlx5e_priv *priv,
+ struct mlx5e_encap_entry *e,
+ struct netlink_ext_ack *extack)
+{
+ int dst_port = be16_to_cpu(e->tun_info->key.tp_dst);
+
+ e->tunnel = &vxlan_tunnel;
+
+ if (!mlx5_vxlan_lookup_port(priv->mdev->vxlan, dst_port)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "vxlan udp dport was not registered with the HW");
+ netdev_warn(priv->netdev,
+ "%d isn't an offloaded vxlan udp dport\n",
+ dst_port);
+ return -EOPNOTSUPP;
+ }
+
+ e->reformat_type = MLX5_REFORMAT_TYPE_L2_TO_VXLAN;
+ return 0;
+}
+
+static int mlx5e_gen_ip_tunnel_header_vxlan(char buf[],
+ __u8 *ip_proto,
+ struct mlx5e_encap_entry *e)
+{
+ const struct ip_tunnel_key *tun_key = &e->tun_info->key;
+ __be32 tun_id = tunnel_id_to_key32(tun_key->tun_id);
+ struct udphdr *udp = (struct udphdr *)(buf);
+ struct vxlanhdr *vxh;
+
+ vxh = (struct vxlanhdr *)((char *)udp + sizeof(struct udphdr));
+ *ip_proto = IPPROTO_UDP;
+
+ udp->dest = tun_key->tp_dst;
+ vxh->vx_flags = VXLAN_HF_VNI;
+ vxh->vx_vni = vxlan_vni_field(tun_id);
+
+ return 0;
+}
+
+static int mlx5e_tc_tun_parse_vxlan(struct mlx5e_priv *priv,
+ struct mlx5_flow_spec *spec,
+ struct flow_cls_offload *f,
+ void *headers_c,
+ void *headers_v)
+{
+ struct flow_rule *rule = flow_cls_offload_flow_rule(f);
+ struct netlink_ext_ack *extack = f->common.extack;
+ struct flow_match_enc_keyid enc_keyid;
+ void *misc_c, *misc_v;
+
+ misc_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
+ misc_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
+
+ if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID))
+ return 0;
+
+ flow_rule_match_enc_keyid(rule, &enc_keyid);
+
+ if (!enc_keyid.mask->keyid)
+ return 0;
+
+ /* match on VNI is required */
+
+ if (!MLX5_CAP_ESW_FLOWTABLE_FDB(priv->mdev,
+ ft_field_support.outer_vxlan_vni)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Matching on VXLAN VNI is not supported");
+ netdev_warn(priv->netdev,
+ "Matching on VXLAN VNI is not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ MLX5_SET(fte_match_set_misc, misc_c, vxlan_vni,
+ be32_to_cpu(enc_keyid.mask->keyid));
+ MLX5_SET(fte_match_set_misc, misc_v, vxlan_vni,
+ be32_to_cpu(enc_keyid.key->keyid));
+
+ return 0;
+}
+
+struct mlx5e_tc_tunnel vxlan_tunnel = {
+ .tunnel_type = MLX5E_TC_TUNNEL_TYPE_VXLAN,
+ .match_level = MLX5_MATCH_L4,
+ .can_offload = mlx5e_tc_tun_can_offload_vxlan,
+ .calc_hlen = mlx5e_tc_tun_calc_hlen_vxlan,
+ .init_encap_attr = mlx5e_tc_tun_init_encap_attr_vxlan,
+ .generate_ip_tun_hdr = mlx5e_gen_ip_tunnel_header_vxlan,
+ .parse_udp_ports = mlx5e_tc_tun_parse_udp_ports_vxlan,
+ .parse_tunnel = mlx5e_tc_tun_parse_vxlan,
+};
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h b/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
new file mode 100644
index 000000000000..ddfe19adb3d9
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
@@ -0,0 +1,208 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2019 Mellanox Technologies. */
+
+#ifndef __MLX5_EN_TXRX_H___
+#define __MLX5_EN_TXRX_H___
+
+#include "en.h"
+
+#define MLX5E_SQ_NOPS_ROOM MLX5_SEND_WQE_MAX_WQEBBS
+#define MLX5E_SQ_STOP_ROOM (MLX5_SEND_WQE_MAX_WQEBBS +\
+ MLX5E_SQ_NOPS_ROOM)
+
+#ifndef CONFIG_MLX5_EN_TLS
+#define MLX5E_SQ_TLS_ROOM (0)
+#else
+/* TLS offload requires additional stop_room for:
+ * - a resync SKB.
+ * kTLS offload requires additional stop_room for:
+ * - static params WQE,
+ * - progress params WQE, and
+ * - resync DUMP per frag.
+ */
+#define MLX5E_SQ_TLS_ROOM \
+ (MLX5_SEND_WQE_MAX_WQEBBS + \
+ MLX5E_KTLS_STATIC_WQEBBS + MLX5E_KTLS_PROGRESS_WQEBBS + \
+ MAX_SKB_FRAGS * MLX5E_KTLS_MAX_DUMP_WQEBBS)
+#endif
+
+#define INL_HDR_START_SZ (sizeof(((struct mlx5_wqe_eth_seg *)NULL)->inline_hdr.start))
+
+static inline bool
+mlx5e_wqc_has_room_for(struct mlx5_wq_cyc *wq, u16 cc, u16 pc, u16 n)
+{
+ return (mlx5_wq_cyc_ctr2ix(wq, cc - pc) >= n) || (cc == pc);
+}
+
+static inline void *
+mlx5e_sq_fetch_wqe(struct mlx5e_txqsq *sq, size_t size, u16 *pi)
+{
+ struct mlx5_wq_cyc *wq = &sq->wq;
+ void *wqe;
+
+ *pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
+ wqe = mlx5_wq_cyc_get_wqe(wq, *pi);
+ memset(wqe, 0, size);
+
+ return wqe;
+}
+
+static inline struct mlx5e_tx_wqe *
+mlx5e_post_nop(struct mlx5_wq_cyc *wq, u32 sqn, u16 *pc)
+{
+ u16 pi = mlx5_wq_cyc_ctr2ix(wq, *pc);
+ struct mlx5e_tx_wqe *wqe = mlx5_wq_cyc_get_wqe(wq, pi);
+ struct mlx5_wqe_ctrl_seg *cseg = &wqe->ctrl;
+
+ memset(cseg, 0, sizeof(*cseg));
+
+ cseg->opmod_idx_opcode = cpu_to_be32((*pc << 8) | MLX5_OPCODE_NOP);
+ cseg->qpn_ds = cpu_to_be32((sqn << 8) | 0x01);
+
+ (*pc)++;
+
+ return wqe;
+}
+
+static inline struct mlx5e_tx_wqe *
+mlx5e_post_nop_fence(struct mlx5_wq_cyc *wq, u32 sqn, u16 *pc)
+{
+ u16 pi = mlx5_wq_cyc_ctr2ix(wq, *pc);
+ struct mlx5e_tx_wqe *wqe = mlx5_wq_cyc_get_wqe(wq, pi);
+ struct mlx5_wqe_ctrl_seg *cseg = &wqe->ctrl;
+
+ memset(cseg, 0, sizeof(*cseg));
+
+ cseg->opmod_idx_opcode = cpu_to_be32((*pc << 8) | MLX5_OPCODE_NOP);
+ cseg->qpn_ds = cpu_to_be32((sqn << 8) | 0x01);
+ cseg->fm_ce_se = MLX5_FENCE_MODE_INITIATOR_SMALL;
+
+ (*pc)++;
+
+ return wqe;
+}
+
+static inline void
+mlx5e_fill_sq_frag_edge(struct mlx5e_txqsq *sq, struct mlx5_wq_cyc *wq,
+ u16 pi, u16 nnops)
+{
+ struct mlx5e_tx_wqe_info *edge_wi, *wi = &sq->db.wqe_info[pi];
+
+ edge_wi = wi + nnops;
+
+ /* fill sq frag edge with nops to avoid wqe wrapping two pages */
+ for (; wi < edge_wi; wi++) {
+ wi->skb = NULL;
+ wi->num_wqebbs = 1;
+ mlx5e_post_nop(wq, sq->sqn, &sq->pc);
+ }
+ sq->stats->nop += nnops;
+}
+
+static inline void
+mlx5e_notify_hw(struct mlx5_wq_cyc *wq, u16 pc, void __iomem *uar_map,
+ struct mlx5_wqe_ctrl_seg *ctrl)
+{
+ ctrl->fm_ce_se = MLX5_WQE_CTRL_CQ_UPDATE;
+ /* ensure wqe is visible to device before updating doorbell record */
+ dma_wmb();
+
+ *wq->db = cpu_to_be32(pc);
+
+ /* ensure doorbell record is visible to device before ringing the
+ * doorbell
+ */
+ wmb();
+
+ mlx5_write64((__be32 *)ctrl, uar_map);
+}
+
+static inline bool mlx5e_transport_inline_tx_wqe(struct mlx5e_tx_wqe *wqe)
+{
+ return !!wqe->ctrl.tisn;
+}
+
+static inline void mlx5e_cq_arm(struct mlx5e_cq *cq)
+{
+ struct mlx5_core_cq *mcq;
+
+ mcq = &cq->mcq;
+ mlx5_cq_arm(mcq, MLX5_CQ_DB_REQ_NOT, mcq->uar->map, cq->wq.cc);
+}
+
+static inline struct mlx5e_sq_dma *
+mlx5e_dma_get(struct mlx5e_txqsq *sq, u32 i)
+{
+ return &sq->db.dma_fifo[i & sq->dma_fifo_mask];
+}
+
+static inline void
+mlx5e_dma_push(struct mlx5e_txqsq *sq, dma_addr_t addr, u32 size,
+ enum mlx5e_dma_map_type map_type)
+{
+ struct mlx5e_sq_dma *dma = mlx5e_dma_get(sq, sq->dma_fifo_pc++);
+
+ dma->addr = addr;
+ dma->size = size;
+ dma->type = map_type;
+}
+
+static inline void
+mlx5e_tx_dma_unmap(struct device *pdev, struct mlx5e_sq_dma *dma)
+{
+ switch (dma->type) {
+ case MLX5E_DMA_MAP_SINGLE:
+ dma_unmap_single(pdev, dma->addr, dma->size, DMA_TO_DEVICE);
+ break;
+ case MLX5E_DMA_MAP_PAGE:
+ dma_unmap_page(pdev, dma->addr, dma->size, DMA_TO_DEVICE);
+ break;
+ default:
+ WARN_ONCE(true, "mlx5e_tx_dma_unmap unknown DMA type!\n");
+ }
+}
+
+/* SW parser related functions */
+
+struct mlx5e_swp_spec {
+ __be16 l3_proto;
+ u8 l4_proto;
+ u8 is_tun;
+ __be16 tun_l3_proto;
+ u8 tun_l4_proto;
+};
+
+static inline void
+mlx5e_set_eseg_swp(struct sk_buff *skb, struct mlx5_wqe_eth_seg *eseg,
+ struct mlx5e_swp_spec *swp_spec)
+{
+ /* SWP offsets are in 2-bytes words */
+ eseg->swp_outer_l3_offset = skb_network_offset(skb) / 2;
+ if (swp_spec->l3_proto == htons(ETH_P_IPV6))
+ eseg->swp_flags |= MLX5_ETH_WQE_SWP_OUTER_L3_IPV6;
+ if (swp_spec->l4_proto) {
+ eseg->swp_outer_l4_offset = skb_transport_offset(skb) / 2;
+ if (swp_spec->l4_proto == IPPROTO_UDP)
+ eseg->swp_flags |= MLX5_ETH_WQE_SWP_OUTER_L4_UDP;
+ }
+
+ if (swp_spec->is_tun) {
+ eseg->swp_inner_l3_offset = skb_inner_network_offset(skb) / 2;
+ if (swp_spec->tun_l3_proto == htons(ETH_P_IPV6))
+ eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L3_IPV6;
+ } else { /* typically for ipsec when xfrm mode != XFRM_MODE_TUNNEL */
+ eseg->swp_inner_l3_offset = skb_network_offset(skb) / 2;
+ if (swp_spec->l3_proto == htons(ETH_P_IPV6))
+ eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L3_IPV6;
+ }
+ switch (swp_spec->tun_l4_proto) {
+ case IPPROTO_UDP:
+ eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L4_UDP;
+ /* fall through */
+ case IPPROTO_TCP:
+ eseg->swp_inner_l4_offset = skb_inner_transport_offset(skb) / 2;
+ break;
+ }
+}
+
+#endif
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
index eb8ef78e5626..b0b982cf69bb 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
@@ -31,11 +31,13 @@
*/
#include <linux/bpf_trace.h>
+#include <net/xdp_sock.h>
#include "en/xdp.h"
+#include "en/params.h"
-int mlx5e_xdp_max_mtu(struct mlx5e_params *params)
+int mlx5e_xdp_max_mtu(struct mlx5e_params *params, struct mlx5e_xsk_param *xsk)
{
- int hr = NET_IP_ALIGN + XDP_PACKET_HEADROOM;
+ int hr = mlx5e_get_linear_rq_headroom(params, xsk);
/* Let S := SKB_DATA_ALIGN(sizeof(struct skb_shared_info)).
* The condition checked in mlx5e_rx_is_linear_skb is:
@@ -54,25 +56,70 @@ int mlx5e_xdp_max_mtu(struct mlx5e_params *params)
}
static inline bool
-mlx5e_xmit_xdp_buff(struct mlx5e_xdpsq *sq, struct mlx5e_dma_info *di,
- struct xdp_buff *xdp)
+mlx5e_xmit_xdp_buff(struct mlx5e_xdpsq *sq, struct mlx5e_rq *rq,
+ struct mlx5e_dma_info *di, struct xdp_buff *xdp)
{
+ struct mlx5e_xdp_xmit_data xdptxd;
struct mlx5e_xdp_info xdpi;
+ struct xdp_frame *xdpf;
+ dma_addr_t dma_addr;
- xdpi.xdpf = convert_to_xdp_frame(xdp);
- if (unlikely(!xdpi.xdpf))
+ xdpf = convert_to_xdp_frame(xdp);
+ if (unlikely(!xdpf))
return false;
- xdpi.dma_addr = di->addr + (xdpi.xdpf->data - (void *)xdpi.xdpf);
- dma_sync_single_for_device(sq->pdev, xdpi.dma_addr,
- xdpi.xdpf->len, PCI_DMA_TODEVICE);
- xdpi.di = *di;
- return sq->xmit_xdp_frame(sq, &xdpi);
+ xdptxd.data = xdpf->data;
+ xdptxd.len = xdpf->len;
+
+ if (xdp->rxq->mem.type == MEM_TYPE_ZERO_COPY) {
+ /* The xdp_buff was in the UMEM and was copied into a newly
+ * allocated page. The UMEM page was returned via the ZCA, and
+ * this new page has to be mapped at this point and has to be
+ * unmapped and returned via xdp_return_frame on completion.
+ */
+
+ /* Prevent double recycling of the UMEM page. Even in case this
+ * function returns false, the xdp_buff shouldn't be recycled,
+ * as it was already done in xdp_convert_zc_to_xdp_frame.
+ */
+ __set_bit(MLX5E_RQ_FLAG_XDP_XMIT, rq->flags); /* non-atomic */
+
+ xdpi.mode = MLX5E_XDP_XMIT_MODE_FRAME;
+
+ dma_addr = dma_map_single(sq->pdev, xdptxd.data, xdptxd.len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(sq->pdev, dma_addr)) {
+ xdp_return_frame(xdpf);
+ return false;
+ }
+
+ xdptxd.dma_addr = dma_addr;
+ xdpi.frame.xdpf = xdpf;
+ xdpi.frame.dma_addr = dma_addr;
+ } else {
+ /* Driver assumes that convert_to_xdp_frame returns an xdp_frame
+ * that points to the same memory region as the original
+ * xdp_buff. It allows to map the memory only once and to use
+ * the DMA_BIDIRECTIONAL mode.
+ */
+
+ xdpi.mode = MLX5E_XDP_XMIT_MODE_PAGE;
+
+ dma_addr = di->addr + (xdpf->data - (void *)xdpf);
+ dma_sync_single_for_device(sq->pdev, dma_addr, xdptxd.len,
+ DMA_TO_DEVICE);
+
+ xdptxd.dma_addr = dma_addr;
+ xdpi.page.rq = rq;
+ xdpi.page.di = *di;
+ }
+
+ return sq->xmit_xdp_frame(sq, &xdptxd, &xdpi, 0);
}
/* returns true if packet was consumed by xdp */
bool mlx5e_xdp_handle(struct mlx5e_rq *rq, struct mlx5e_dma_info *di,
- void *va, u16 *rx_headroom, u32 *len)
+ void *va, u16 *rx_headroom, u32 *len, bool xsk)
{
struct bpf_prog *prog = READ_ONCE(rq->xdp_prog);
struct xdp_buff xdp;
@@ -86,16 +133,20 @@ bool mlx5e_xdp_handle(struct mlx5e_rq *rq, struct mlx5e_dma_info *di,
xdp_set_data_meta_invalid(&xdp);
xdp.data_end = xdp.data + *len;
xdp.data_hard_start = va;
+ if (xsk)
+ xdp.handle = di->xsk.handle;
xdp.rxq = &rq->xdp_rxq;
act = bpf_prog_run_xdp(prog, &xdp);
+ if (xsk)
+ xdp.handle += xdp.data - xdp.data_hard_start;
switch (act) {
case XDP_PASS:
*rx_headroom = xdp.data - xdp.data_hard_start;
*len = xdp.data_end - xdp.data;
return false;
case XDP_TX:
- if (unlikely(!mlx5e_xmit_xdp_buff(&rq->xdpsq, di, &xdp)))
+ if (unlikely(!mlx5e_xmit_xdp_buff(rq->xdpsq, rq, di, &xdp)))
goto xdp_abort;
__set_bit(MLX5E_RQ_FLAG_XDP_XMIT, rq->flags); /* non-atomic */
return true;
@@ -106,7 +157,8 @@ bool mlx5e_xdp_handle(struct mlx5e_rq *rq, struct mlx5e_dma_info *di,
goto xdp_abort;
__set_bit(MLX5E_RQ_FLAG_XDP_XMIT, rq->flags);
__set_bit(MLX5E_RQ_FLAG_XDP_REDIRECT, rq->flags);
- mlx5e_page_dma_unmap(rq, di);
+ if (!xsk)
+ mlx5e_page_dma_unmap(rq, di);
rq->stats->xdp_redirect++;
return true;
default:
@@ -160,7 +212,7 @@ static void mlx5e_xdp_mpwqe_session_start(struct mlx5e_xdpsq *sq)
stats->mpwqe++;
}
-static void mlx5e_xdp_mpwqe_complete(struct mlx5e_xdpsq *sq)
+void mlx5e_xdp_mpwqe_complete(struct mlx5e_xdpsq *sq)
{
struct mlx5_wq_cyc *wq = &sq->wq;
struct mlx5e_xdp_mpwqe *session = &sq->mpwqe;
@@ -183,32 +235,55 @@ static void mlx5e_xdp_mpwqe_complete(struct mlx5e_xdpsq *sq)
session->wqe = NULL; /* Close session */
}
+enum {
+ MLX5E_XDP_CHECK_OK = 1,
+ MLX5E_XDP_CHECK_START_MPWQE = 2,
+};
+
+static int mlx5e_xmit_xdp_frame_check_mpwqe(struct mlx5e_xdpsq *sq)
+{
+ if (unlikely(!sq->mpwqe.wqe)) {
+ if (unlikely(!mlx5e_wqc_has_room_for(&sq->wq, sq->cc, sq->pc,
+ MLX5_SEND_WQE_MAX_WQEBBS))) {
+ /* SQ is full, ring doorbell */
+ mlx5e_xmit_xdp_doorbell(sq);
+ sq->stats->full++;
+ return -EBUSY;
+ }
+
+ return MLX5E_XDP_CHECK_START_MPWQE;
+ }
+
+ return MLX5E_XDP_CHECK_OK;
+}
+
static bool mlx5e_xmit_xdp_frame_mpwqe(struct mlx5e_xdpsq *sq,
- struct mlx5e_xdp_info *xdpi)
+ struct mlx5e_xdp_xmit_data *xdptxd,
+ struct mlx5e_xdp_info *xdpi,
+ int check_result)
{
struct mlx5e_xdp_mpwqe *session = &sq->mpwqe;
struct mlx5e_xdpsq_stats *stats = sq->stats;
- struct xdp_frame *xdpf = xdpi->xdpf;
-
- if (unlikely(sq->hw_mtu < xdpf->len)) {
+ if (unlikely(xdptxd->len > sq->hw_mtu)) {
stats->err++;
return false;
}
- if (unlikely(!session->wqe)) {
- if (unlikely(!mlx5e_wqc_has_room_for(&sq->wq, sq->cc, sq->pc,
- MLX5_SEND_WQE_MAX_WQEBBS))) {
- /* SQ is full, ring doorbell */
- mlx5e_xmit_xdp_doorbell(sq);
- stats->full++;
- return false;
- }
+ if (!check_result)
+ check_result = mlx5e_xmit_xdp_frame_check_mpwqe(sq);
+ if (unlikely(check_result < 0))
+ return false;
+ if (check_result == MLX5E_XDP_CHECK_START_MPWQE) {
+ /* Start the session when nothing can fail, so it's guaranteed
+ * that if there is an active session, it has at least one dseg,
+ * and it's safe to complete it at any time.
+ */
mlx5e_xdp_mpwqe_session_start(sq);
}
- mlx5e_xdp_mpwqe_add_dseg(sq, xdpi, stats);
+ mlx5e_xdp_mpwqe_add_dseg(sq, xdptxd, stats);
if (unlikely(session->complete ||
session->ds_count == session->max_ds_count))
@@ -219,7 +294,22 @@ static bool mlx5e_xmit_xdp_frame_mpwqe(struct mlx5e_xdpsq *sq,
return true;
}
-static bool mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xdp_info *xdpi)
+static int mlx5e_xmit_xdp_frame_check(struct mlx5e_xdpsq *sq)
+{
+ if (unlikely(!mlx5e_wqc_has_room_for(&sq->wq, sq->cc, sq->pc, 1))) {
+ /* SQ is full, ring doorbell */
+ mlx5e_xmit_xdp_doorbell(sq);
+ sq->stats->full++;
+ return -EBUSY;
+ }
+
+ return MLX5E_XDP_CHECK_OK;
+}
+
+static bool mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq,
+ struct mlx5e_xdp_xmit_data *xdptxd,
+ struct mlx5e_xdp_info *xdpi,
+ int check_result)
{
struct mlx5_wq_cyc *wq = &sq->wq;
u16 pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
@@ -229,9 +319,8 @@ static bool mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xdp_info *
struct mlx5_wqe_eth_seg *eseg = &wqe->eth;
struct mlx5_wqe_data_seg *dseg = wqe->data;
- struct xdp_frame *xdpf = xdpi->xdpf;
- dma_addr_t dma_addr = xdpi->dma_addr;
- unsigned int dma_len = xdpf->len;
+ dma_addr_t dma_addr = xdptxd->dma_addr;
+ u32 dma_len = xdptxd->len;
struct mlx5e_xdpsq_stats *stats = sq->stats;
@@ -242,18 +331,16 @@ static bool mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xdp_info *
return false;
}
- if (unlikely(!mlx5e_wqc_has_room_for(wq, sq->cc, sq->pc, 1))) {
- /* SQ is full, ring doorbell */
- mlx5e_xmit_xdp_doorbell(sq);
- stats->full++;
+ if (!check_result)
+ check_result = mlx5e_xmit_xdp_frame_check(sq);
+ if (unlikely(check_result < 0))
return false;
- }
cseg->fm_ce_se = 0;
/* copy the inline part if required */
if (sq->min_inline_mode != MLX5_INLINE_MODE_NONE) {
- memcpy(eseg->inline_hdr.start, xdpf->data, MLX5E_XDP_MIN_INLINE);
+ memcpy(eseg->inline_hdr.start, xdptxd->data, MLX5E_XDP_MIN_INLINE);
eseg->inline_hdr.sz = cpu_to_be16(MLX5E_XDP_MIN_INLINE);
dma_len -= MLX5E_XDP_MIN_INLINE;
dma_addr += MLX5E_XDP_MIN_INLINE;
@@ -277,7 +364,7 @@ static bool mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xdp_info *
static void mlx5e_free_xdpsq_desc(struct mlx5e_xdpsq *sq,
struct mlx5e_xdp_wqe_info *wi,
- struct mlx5e_rq *rq,
+ u32 *xsk_frames,
bool recycle)
{
struct mlx5e_xdp_info_fifo *xdpi_fifo = &sq->db.xdpi_fifo;
@@ -286,22 +373,32 @@ static void mlx5e_free_xdpsq_desc(struct mlx5e_xdpsq *sq,
for (i = 0; i < wi->num_pkts; i++) {
struct mlx5e_xdp_info xdpi = mlx5e_xdpi_fifo_pop(xdpi_fifo);
- if (rq) {
- /* XDP_TX */
- mlx5e_page_release(rq, &xdpi.di, recycle);
- } else {
- /* XDP_REDIRECT */
- dma_unmap_single(sq->pdev, xdpi.dma_addr,
- xdpi.xdpf->len, DMA_TO_DEVICE);
- xdp_return_frame(xdpi.xdpf);
+ switch (xdpi.mode) {
+ case MLX5E_XDP_XMIT_MODE_FRAME:
+ /* XDP_TX from the XSK RQ and XDP_REDIRECT */
+ dma_unmap_single(sq->pdev, xdpi.frame.dma_addr,
+ xdpi.frame.xdpf->len, DMA_TO_DEVICE);
+ xdp_return_frame(xdpi.frame.xdpf);
+ break;
+ case MLX5E_XDP_XMIT_MODE_PAGE:
+ /* XDP_TX from the regular RQ */
+ mlx5e_page_release_dynamic(xdpi.page.rq, &xdpi.page.di, recycle);
+ break;
+ case MLX5E_XDP_XMIT_MODE_XSK:
+ /* AF_XDP send */
+ (*xsk_frames)++;
+ break;
+ default:
+ WARN_ON_ONCE(true);
}
}
}
-bool mlx5e_poll_xdpsq_cq(struct mlx5e_cq *cq, struct mlx5e_rq *rq)
+bool mlx5e_poll_xdpsq_cq(struct mlx5e_cq *cq)
{
struct mlx5e_xdpsq *sq;
struct mlx5_cqe64 *cqe;
+ u32 xsk_frames = 0;
u16 sqcc;
int i;
@@ -343,10 +440,13 @@ bool mlx5e_poll_xdpsq_cq(struct mlx5e_cq *cq, struct mlx5e_rq *rq)
sqcc += wi->num_wqebbs;
- mlx5e_free_xdpsq_desc(sq, wi, rq, true);
+ mlx5e_free_xdpsq_desc(sq, wi, &xsk_frames, true);
} while (!last_wqe);
} while ((++i < MLX5E_TX_CQ_POLL_BUDGET) && (cqe = mlx5_cqwq_get_cqe(&cq->wq)));
+ if (xsk_frames)
+ xsk_umem_complete_tx(sq->umem, xsk_frames);
+
sq->stats->cqes += i;
mlx5_cqwq_update_db_record(&cq->wq);
@@ -358,8 +458,10 @@ bool mlx5e_poll_xdpsq_cq(struct mlx5e_cq *cq, struct mlx5e_rq *rq)
return (i == MLX5E_TX_CQ_POLL_BUDGET);
}
-void mlx5e_free_xdpsq_descs(struct mlx5e_xdpsq *sq, struct mlx5e_rq *rq)
+void mlx5e_free_xdpsq_descs(struct mlx5e_xdpsq *sq)
{
+ u32 xsk_frames = 0;
+
while (sq->cc != sq->pc) {
struct mlx5e_xdp_wqe_info *wi;
u16 ci;
@@ -369,8 +471,11 @@ void mlx5e_free_xdpsq_descs(struct mlx5e_xdpsq *sq, struct mlx5e_rq *rq)
sq->cc += wi->num_wqebbs;
- mlx5e_free_xdpsq_desc(sq, wi, rq, false);
+ mlx5e_free_xdpsq_desc(sq, wi, &xsk_frames, false);
}
+
+ if (xsk_frames)
+ xsk_umem_complete_tx(sq->umem, xsk_frames);
}
int mlx5e_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames,
@@ -398,21 +503,27 @@ int mlx5e_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames,
for (i = 0; i < n; i++) {
struct xdp_frame *xdpf = frames[i];
+ struct mlx5e_xdp_xmit_data xdptxd;
struct mlx5e_xdp_info xdpi;
- xdpi.dma_addr = dma_map_single(sq->pdev, xdpf->data, xdpf->len,
- DMA_TO_DEVICE);
- if (unlikely(dma_mapping_error(sq->pdev, xdpi.dma_addr))) {
+ xdptxd.data = xdpf->data;
+ xdptxd.len = xdpf->len;
+ xdptxd.dma_addr = dma_map_single(sq->pdev, xdptxd.data,
+ xdptxd.len, DMA_TO_DEVICE);
+
+ if (unlikely(dma_mapping_error(sq->pdev, xdptxd.dma_addr))) {
xdp_return_frame_rx_napi(xdpf);
drops++;
continue;
}
- xdpi.xdpf = xdpf;
+ xdpi.mode = MLX5E_XDP_XMIT_MODE_FRAME;
+ xdpi.frame.xdpf = xdpf;
+ xdpi.frame.dma_addr = xdptxd.dma_addr;
- if (unlikely(!sq->xmit_xdp_frame(sq, &xdpi))) {
- dma_unmap_single(sq->pdev, xdpi.dma_addr,
- xdpf->len, DMA_TO_DEVICE);
+ if (unlikely(!sq->xmit_xdp_frame(sq, &xdptxd, &xdpi, 0))) {
+ dma_unmap_single(sq->pdev, xdptxd.dma_addr,
+ xdptxd.len, DMA_TO_DEVICE);
xdp_return_frame_rx_napi(xdpf);
drops++;
}
@@ -429,7 +540,7 @@ int mlx5e_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames,
void mlx5e_xdp_rx_poll_complete(struct mlx5e_rq *rq)
{
- struct mlx5e_xdpsq *xdpsq = &rq->xdpsq;
+ struct mlx5e_xdpsq *xdpsq = rq->xdpsq;
if (xdpsq->mpwqe.wqe)
mlx5e_xdp_mpwqe_complete(xdpsq);
@@ -444,6 +555,8 @@ void mlx5e_xdp_rx_poll_complete(struct mlx5e_rq *rq)
void mlx5e_set_xmit_fp(struct mlx5e_xdpsq *sq, bool is_mpw)
{
+ sq->xmit_xdp_frame_check = is_mpw ?
+ mlx5e_xmit_xdp_frame_check_mpwqe : mlx5e_xmit_xdp_frame_check;
sq->xmit_xdp_frame = is_mpw ?
mlx5e_xmit_xdp_frame_mpwqe : mlx5e_xmit_xdp_frame;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h
index 8b537a4b0840..b90923932668 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h
@@ -33,17 +33,20 @@
#define __MLX5_EN_XDP_H__
#include "en.h"
+#include "en/txrx.h"
#define MLX5E_XDP_MIN_INLINE (ETH_HLEN + VLAN_HLEN)
#define MLX5E_XDP_TX_EMPTY_DS_COUNT \
(sizeof(struct mlx5e_tx_wqe) / MLX5_SEND_WQE_DS)
#define MLX5E_XDP_TX_DS_COUNT (MLX5E_XDP_TX_EMPTY_DS_COUNT + 1 /* SG DS */)
-int mlx5e_xdp_max_mtu(struct mlx5e_params *params);
+struct mlx5e_xsk_param;
+int mlx5e_xdp_max_mtu(struct mlx5e_params *params, struct mlx5e_xsk_param *xsk);
bool mlx5e_xdp_handle(struct mlx5e_rq *rq, struct mlx5e_dma_info *di,
- void *va, u16 *rx_headroom, u32 *len);
-bool mlx5e_poll_xdpsq_cq(struct mlx5e_cq *cq, struct mlx5e_rq *rq);
-void mlx5e_free_xdpsq_descs(struct mlx5e_xdpsq *sq, struct mlx5e_rq *rq);
+ void *va, u16 *rx_headroom, u32 *len, bool xsk);
+void mlx5e_xdp_mpwqe_complete(struct mlx5e_xdpsq *sq);
+bool mlx5e_poll_xdpsq_cq(struct mlx5e_cq *cq);
+void mlx5e_free_xdpsq_descs(struct mlx5e_xdpsq *sq);
void mlx5e_set_xmit_fp(struct mlx5e_xdpsq *sq, bool is_mpw);
void mlx5e_xdp_rx_poll_complete(struct mlx5e_rq *rq);
int mlx5e_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames,
@@ -66,6 +69,21 @@ static inline bool mlx5e_xdp_tx_is_enabled(struct mlx5e_priv *priv)
return test_bit(MLX5E_STATE_XDP_TX_ENABLED, &priv->state);
}
+static inline void mlx5e_xdp_set_open(struct mlx5e_priv *priv)
+{
+ set_bit(MLX5E_STATE_XDP_OPEN, &priv->state);
+}
+
+static inline void mlx5e_xdp_set_closed(struct mlx5e_priv *priv)
+{
+ clear_bit(MLX5E_STATE_XDP_OPEN, &priv->state);
+}
+
+static inline bool mlx5e_xdp_is_open(struct mlx5e_priv *priv)
+{
+ return test_bit(MLX5E_STATE_XDP_OPEN, &priv->state);
+}
+
static inline void mlx5e_xmit_xdp_doorbell(struct mlx5e_xdpsq *sq)
{
if (sq->doorbell_cseg) {
@@ -97,15 +115,14 @@ static inline void mlx5e_xdp_update_inline_state(struct mlx5e_xdpsq *sq)
}
static inline void
-mlx5e_xdp_mpwqe_add_dseg(struct mlx5e_xdpsq *sq, struct mlx5e_xdp_info *xdpi,
+mlx5e_xdp_mpwqe_add_dseg(struct mlx5e_xdpsq *sq,
+ struct mlx5e_xdp_xmit_data *xdptxd,
struct mlx5e_xdpsq_stats *stats)
{
struct mlx5e_xdp_mpwqe *session = &sq->mpwqe;
- dma_addr_t dma_addr = xdpi->dma_addr;
- struct xdp_frame *xdpf = xdpi->xdpf;
struct mlx5_wqe_data_seg *dseg =
(struct mlx5_wqe_data_seg *)session->wqe + session->ds_count;
- u16 dma_len = xdpf->len;
+ u32 dma_len = xdptxd->len;
session->pkt_count++;
@@ -124,7 +141,7 @@ mlx5e_xdp_mpwqe_add_dseg(struct mlx5e_xdpsq *sq, struct mlx5e_xdp_info *xdpi,
}
inline_dseg->byte_count = cpu_to_be32(dma_len | MLX5_INLINE_SEG);
- memcpy(inline_dseg->data, xdpf->data, dma_len);
+ memcpy(inline_dseg->data, xdptxd->data, dma_len);
session->ds_count += ds_cnt;
stats->inlnw++;
@@ -132,7 +149,7 @@ mlx5e_xdp_mpwqe_add_dseg(struct mlx5e_xdpsq *sq, struct mlx5e_xdp_info *xdpi,
}
no_inline:
- dseg->addr = cpu_to_be64(dma_addr);
+ dseg->addr = cpu_to_be64(xdptxd->dma_addr);
dseg->byte_count = cpu_to_be32(dma_len);
dseg->lkey = sq->mkey_be;
session->ds_count++;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/Makefile
new file mode 100644
index 000000000000..5ee42991900a
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/Makefile
@@ -0,0 +1 @@
+subdir-ccflags-y += -I$(src)/../..
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.c
new file mode 100644
index 000000000000..6a55573ec8f2
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.c
@@ -0,0 +1,192 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/* Copyright (c) 2019 Mellanox Technologies. */
+
+#include "rx.h"
+#include "en/xdp.h"
+#include <net/xdp_sock.h>
+
+/* RX data path */
+
+bool mlx5e_xsk_pages_enough_umem(struct mlx5e_rq *rq, int count)
+{
+ /* Check in advance that we have enough frames, instead of allocating
+ * one-by-one, failing and moving frames to the Reuse Ring.
+ */
+ return xsk_umem_has_addrs_rq(rq->umem, count);
+}
+
+int mlx5e_xsk_page_alloc_umem(struct mlx5e_rq *rq,
+ struct mlx5e_dma_info *dma_info)
+{
+ struct xdp_umem *umem = rq->umem;
+ u64 handle;
+
+ if (!xsk_umem_peek_addr_rq(umem, &handle))
+ return -ENOMEM;
+
+ dma_info->xsk.handle = handle + rq->buff.umem_headroom;
+ dma_info->xsk.data = xdp_umem_get_data(umem, dma_info->xsk.handle);
+
+ /* No need to add headroom to the DMA address. In striding RQ case, we
+ * just provide pages for UMR, and headroom is counted at the setup
+ * stage when creating a WQE. In non-striding RQ case, headroom is
+ * accounted in mlx5e_alloc_rx_wqe.
+ */
+ dma_info->addr = xdp_umem_get_dma(umem, handle);
+
+ xsk_umem_discard_addr_rq(umem);
+
+ dma_sync_single_for_device(rq->pdev, dma_info->addr, PAGE_SIZE,
+ DMA_BIDIRECTIONAL);
+
+ return 0;
+}
+
+static inline void mlx5e_xsk_recycle_frame(struct mlx5e_rq *rq, u64 handle)
+{
+ xsk_umem_fq_reuse(rq->umem, handle & rq->umem->chunk_mask);
+}
+
+/* XSKRQ uses pages from UMEM, they must not be released. They are returned to
+ * the userspace if possible, and if not, this function is called to reuse them
+ * in the driver.
+ */
+void mlx5e_xsk_page_release(struct mlx5e_rq *rq,
+ struct mlx5e_dma_info *dma_info)
+{
+ mlx5e_xsk_recycle_frame(rq, dma_info->xsk.handle);
+}
+
+/* Return a frame back to the hardware to fill in again. It is used by XDP when
+ * the XDP program returns XDP_TX or XDP_REDIRECT not to an XSKMAP.
+ */
+void mlx5e_xsk_zca_free(struct zero_copy_allocator *zca, unsigned long handle)
+{
+ struct mlx5e_rq *rq = container_of(zca, struct mlx5e_rq, zca);
+
+ mlx5e_xsk_recycle_frame(rq, handle);
+}
+
+static struct sk_buff *mlx5e_xsk_construct_skb(struct mlx5e_rq *rq, void *data,
+ u32 cqe_bcnt)
+{
+ struct sk_buff *skb;
+
+ skb = napi_alloc_skb(rq->cq.napi, cqe_bcnt);
+ if (unlikely(!skb)) {
+ rq->stats->buff_alloc_err++;
+ return NULL;
+ }
+
+ skb_put_data(skb, data, cqe_bcnt);
+
+ return skb;
+}
+
+struct sk_buff *mlx5e_xsk_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq,
+ struct mlx5e_mpw_info *wi,
+ u16 cqe_bcnt,
+ u32 head_offset,
+ u32 page_idx)
+{
+ struct mlx5e_dma_info *di = &wi->umr.dma_info[page_idx];
+ u16 rx_headroom = rq->buff.headroom - rq->buff.umem_headroom;
+ u32 cqe_bcnt32 = cqe_bcnt;
+ void *va, *data;
+ u32 frag_size;
+ bool consumed;
+
+ /* Check packet size. Note LRO doesn't use linear SKB */
+ if (unlikely(cqe_bcnt > rq->hw_mtu)) {
+ rq->stats->oversize_pkts_sw_drop++;
+ return NULL;
+ }
+
+ /* head_offset is not used in this function, because di->xsk.data and
+ * di->addr point directly to the necessary place. Furthermore, in the
+ * current implementation, one page = one packet = one frame, so
+ * head_offset should always be 0.
+ */
+ WARN_ON_ONCE(head_offset);
+
+ va = di->xsk.data;
+ data = va + rx_headroom;
+ frag_size = rq->buff.headroom + cqe_bcnt32;
+
+ dma_sync_single_for_cpu(rq->pdev, di->addr, frag_size, DMA_BIDIRECTIONAL);
+ prefetch(data);
+
+ rcu_read_lock();
+ consumed = mlx5e_xdp_handle(rq, di, va, &rx_headroom, &cqe_bcnt32, true);
+ rcu_read_unlock();
+
+ /* Possible flows:
+ * - XDP_REDIRECT to XSKMAP:
+ * The page is owned by the userspace from now.
+ * - XDP_TX and other XDP_REDIRECTs:
+ * The page was returned by ZCA and recycled.
+ * - XDP_DROP:
+ * Recycle the page.
+ * - XDP_PASS:
+ * Allocate an SKB, copy the data and recycle the page.
+ *
+ * Pages to be recycled go to the Reuse Ring on MPWQE deallocation. Its
+ * size is the same as the Driver RX Ring's size, and pages for WQEs are
+ * allocated first from the Reuse Ring, so it has enough space.
+ */
+
+ if (likely(consumed)) {
+ if (likely(__test_and_clear_bit(MLX5E_RQ_FLAG_XDP_XMIT, rq->flags)))
+ __set_bit(page_idx, wi->xdp_xmit_bitmap); /* non-atomic */
+ return NULL; /* page/packet was consumed by XDP */
+ }
+
+ /* XDP_PASS: copy the data from the UMEM to a new SKB and reuse the
+ * frame. On SKB allocation failure, NULL is returned.
+ */
+ return mlx5e_xsk_construct_skb(rq, data, cqe_bcnt32);
+}
+
+struct sk_buff *mlx5e_xsk_skb_from_cqe_linear(struct mlx5e_rq *rq,
+ struct mlx5_cqe64 *cqe,
+ struct mlx5e_wqe_frag_info *wi,
+ u32 cqe_bcnt)
+{
+ struct mlx5e_dma_info *di = wi->di;
+ u16 rx_headroom = rq->buff.headroom - rq->buff.umem_headroom;
+ void *va, *data;
+ bool consumed;
+ u32 frag_size;
+
+ /* wi->offset is not used in this function, because di->xsk.data and
+ * di->addr point directly to the necessary place. Furthermore, in the
+ * current implementation, one page = one packet = one frame, so
+ * wi->offset should always be 0.
+ */
+ WARN_ON_ONCE(wi->offset);
+
+ va = di->xsk.data;
+ data = va + rx_headroom;
+ frag_size = rq->buff.headroom + cqe_bcnt;
+
+ dma_sync_single_for_cpu(rq->pdev, di->addr, frag_size, DMA_BIDIRECTIONAL);
+ prefetch(data);
+
+ if (unlikely(get_cqe_opcode(cqe) != MLX5_CQE_RESP_SEND)) {
+ rq->stats->wqe_err++;
+ return NULL;
+ }
+
+ rcu_read_lock();
+ consumed = mlx5e_xdp_handle(rq, di, va, &rx_headroom, &cqe_bcnt, true);
+ rcu_read_unlock();
+
+ if (likely(consumed))
+ return NULL; /* page/packet was consumed by XDP */
+
+ /* XDP_PASS: copy the data from the UMEM to a new SKB. The frame reuse
+ * will be handled by mlx5e_put_rx_frag.
+ * On SKB allocation failure, NULL is returned.
+ */
+ return mlx5e_xsk_construct_skb(rq, data, cqe_bcnt);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.h b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.h
new file mode 100644
index 000000000000..307b923a1361
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2019 Mellanox Technologies. */
+
+#ifndef __MLX5_EN_XSK_RX_H__
+#define __MLX5_EN_XSK_RX_H__
+
+#include "en.h"
+
+/* RX data path */
+
+bool mlx5e_xsk_pages_enough_umem(struct mlx5e_rq *rq, int count);
+int mlx5e_xsk_page_alloc_umem(struct mlx5e_rq *rq,
+ struct mlx5e_dma_info *dma_info);
+void mlx5e_xsk_page_release(struct mlx5e_rq *rq,
+ struct mlx5e_dma_info *dma_info);
+void mlx5e_xsk_zca_free(struct zero_copy_allocator *zca, unsigned long handle);
+struct sk_buff *mlx5e_xsk_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq,
+ struct mlx5e_mpw_info *wi,
+ u16 cqe_bcnt,
+ u32 head_offset,
+ u32 page_idx);
+struct sk_buff *mlx5e_xsk_skb_from_cqe_linear(struct mlx5e_rq *rq,
+ struct mlx5_cqe64 *cqe,
+ struct mlx5e_wqe_frag_info *wi,
+ u32 cqe_bcnt);
+
+#endif /* __MLX5_EN_XSK_RX_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/setup.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/setup.c
new file mode 100644
index 000000000000..aaffa6f68dc0
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/setup.c
@@ -0,0 +1,223 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/* Copyright (c) 2019 Mellanox Technologies. */
+
+#include "setup.h"
+#include "en/params.h"
+
+bool mlx5e_validate_xsk_param(struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk,
+ struct mlx5_core_dev *mdev)
+{
+ /* AF_XDP doesn't support frames larger than PAGE_SIZE, and the current
+ * mlx5e XDP implementation doesn't support multiple packets per page.
+ */
+ if (xsk->chunk_size != PAGE_SIZE)
+ return false;
+
+ /* Current MTU and XSK headroom don't allow packets to fit the frames. */
+ if (mlx5e_rx_get_linear_frag_sz(params, xsk) > xsk->chunk_size)
+ return false;
+
+ /* frag_sz is different for regular and XSK RQs, so ensure that linear
+ * SKB mode is possible.
+ */
+ switch (params->rq_wq_type) {
+ case MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ:
+ return mlx5e_rx_mpwqe_is_linear_skb(mdev, params, xsk);
+ default: /* MLX5_WQ_TYPE_CYCLIC */
+ return mlx5e_rx_is_linear_skb(params, xsk);
+ }
+}
+
+static void mlx5e_build_xskicosq_param(struct mlx5e_priv *priv,
+ u8 log_wq_size,
+ struct mlx5e_sq_param *param)
+{
+ void *sqc = param->sqc;
+ void *wq = MLX5_ADDR_OF(sqc, sqc, wq);
+
+ mlx5e_build_sq_param_common(priv, param);
+
+ MLX5_SET(wq, wq, log_wq_sz, log_wq_size);
+}
+
+static void mlx5e_build_xsk_cparam(struct mlx5e_priv *priv,
+ struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk,
+ struct mlx5e_channel_param *cparam)
+{
+ const u8 xskicosq_size = MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE;
+
+ mlx5e_build_rq_param(priv, params, xsk, &cparam->rq);
+ mlx5e_build_xdpsq_param(priv, params, &cparam->xdp_sq);
+ mlx5e_build_xskicosq_param(priv, xskicosq_size, &cparam->icosq);
+ mlx5e_build_rx_cq_param(priv, params, xsk, &cparam->rx_cq);
+ mlx5e_build_tx_cq_param(priv, params, &cparam->tx_cq);
+ mlx5e_build_ico_cq_param(priv, xskicosq_size, &cparam->icosq_cq);
+}
+
+int mlx5e_open_xsk(struct mlx5e_priv *priv, struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk, struct xdp_umem *umem,
+ struct mlx5e_channel *c)
+{
+ struct mlx5e_channel_param cparam = {};
+ struct dim_cq_moder icocq_moder = {};
+ int err;
+
+ if (!mlx5e_validate_xsk_param(params, xsk, priv->mdev))
+ return -EINVAL;
+
+ mlx5e_build_xsk_cparam(priv, params, xsk, &cparam);
+
+ err = mlx5e_open_cq(c, params->rx_cq_moderation, &cparam.rx_cq, &c->xskrq.cq);
+ if (unlikely(err))
+ return err;
+
+ err = mlx5e_open_rq(c, params, &cparam.rq, xsk, umem, &c->xskrq);
+ if (unlikely(err))
+ goto err_close_rx_cq;
+
+ err = mlx5e_open_cq(c, params->tx_cq_moderation, &cparam.tx_cq, &c->xsksq.cq);
+ if (unlikely(err))
+ goto err_close_rq;
+
+ /* Create a separate SQ, so that when the UMEM is disabled, we could
+ * close this SQ safely and stop receiving CQEs. In other case, e.g., if
+ * the XDPSQ was used instead, we might run into trouble when the UMEM
+ * is disabled and then reenabled, but the SQ continues receiving CQEs
+ * from the old UMEM.
+ */
+ err = mlx5e_open_xdpsq(c, params, &cparam.xdp_sq, umem, &c->xsksq, true);
+ if (unlikely(err))
+ goto err_close_tx_cq;
+
+ err = mlx5e_open_cq(c, icocq_moder, &cparam.icosq_cq, &c->xskicosq.cq);
+ if (unlikely(err))
+ goto err_close_sq;
+
+ /* Create a dedicated SQ for posting NOPs whenever we need an IRQ to be
+ * triggered and NAPI to be called on the correct CPU.
+ */
+ err = mlx5e_open_icosq(c, params, &cparam.icosq, &c->xskicosq);
+ if (unlikely(err))
+ goto err_close_icocq;
+
+ spin_lock_init(&c->xskicosq_lock);
+
+ set_bit(MLX5E_CHANNEL_STATE_XSK, c->state);
+
+ return 0;
+
+err_close_icocq:
+ mlx5e_close_cq(&c->xskicosq.cq);
+
+err_close_sq:
+ mlx5e_close_xdpsq(&c->xsksq);
+
+err_close_tx_cq:
+ mlx5e_close_cq(&c->xsksq.cq);
+
+err_close_rq:
+ mlx5e_close_rq(&c->xskrq);
+
+err_close_rx_cq:
+ mlx5e_close_cq(&c->xskrq.cq);
+
+ return err;
+}
+
+void mlx5e_close_xsk(struct mlx5e_channel *c)
+{
+ clear_bit(MLX5E_CHANNEL_STATE_XSK, c->state);
+ napi_synchronize(&c->napi);
+
+ mlx5e_close_rq(&c->xskrq);
+ mlx5e_close_cq(&c->xskrq.cq);
+ mlx5e_close_icosq(&c->xskicosq);
+ mlx5e_close_cq(&c->xskicosq.cq);
+ mlx5e_close_xdpsq(&c->xsksq);
+ mlx5e_close_cq(&c->xsksq.cq);
+}
+
+void mlx5e_activate_xsk(struct mlx5e_channel *c)
+{
+ set_bit(MLX5E_RQ_STATE_ENABLED, &c->xskrq.state);
+ /* TX queue is created active. */
+ mlx5e_trigger_irq(&c->xskicosq);
+}
+
+void mlx5e_deactivate_xsk(struct mlx5e_channel *c)
+{
+ mlx5e_deactivate_rq(&c->xskrq);
+ /* TX queue is disabled on close. */
+}
+
+static int mlx5e_redirect_xsk_rqt(struct mlx5e_priv *priv, u16 ix, u32 rqn)
+{
+ struct mlx5e_redirect_rqt_param direct_rrp = {
+ .is_rss = false,
+ {
+ .rqn = rqn,
+ },
+ };
+
+ u32 rqtn = priv->xsk_tir[ix].rqt.rqtn;
+
+ return mlx5e_redirect_rqt(priv, rqtn, 1, direct_rrp);
+}
+
+int mlx5e_xsk_redirect_rqt_to_channel(struct mlx5e_priv *priv, struct mlx5e_channel *c)
+{
+ return mlx5e_redirect_xsk_rqt(priv, c->ix, c->xskrq.rqn);
+}
+
+int mlx5e_xsk_redirect_rqt_to_drop(struct mlx5e_priv *priv, u16 ix)
+{
+ return mlx5e_redirect_xsk_rqt(priv, ix, priv->drop_rq.rqn);
+}
+
+int mlx5e_xsk_redirect_rqts_to_channels(struct mlx5e_priv *priv, struct mlx5e_channels *chs)
+{
+ int err, i;
+
+ if (!priv->xsk.refcnt)
+ return 0;
+
+ for (i = 0; i < chs->num; i++) {
+ struct mlx5e_channel *c = chs->c[i];
+
+ if (!test_bit(MLX5E_CHANNEL_STATE_XSK, c->state))
+ continue;
+
+ err = mlx5e_xsk_redirect_rqt_to_channel(priv, c);
+ if (unlikely(err))
+ goto err_stop;
+ }
+
+ return 0;
+
+err_stop:
+ for (i--; i >= 0; i--) {
+ if (!test_bit(MLX5E_CHANNEL_STATE_XSK, chs->c[i]->state))
+ continue;
+
+ mlx5e_xsk_redirect_rqt_to_drop(priv, i);
+ }
+
+ return err;
+}
+
+void mlx5e_xsk_redirect_rqts_to_drop(struct mlx5e_priv *priv, struct mlx5e_channels *chs)
+{
+ int i;
+
+ if (!priv->xsk.refcnt)
+ return;
+
+ for (i = 0; i < chs->num; i++) {
+ if (!test_bit(MLX5E_CHANNEL_STATE_XSK, chs->c[i]->state))
+ continue;
+
+ mlx5e_xsk_redirect_rqt_to_drop(priv, i);
+ }
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/setup.h b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/setup.h
new file mode 100644
index 000000000000..0dd11b81c046
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/setup.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2019 Mellanox Technologies. */
+
+#ifndef __MLX5_EN_XSK_SETUP_H__
+#define __MLX5_EN_XSK_SETUP_H__
+
+#include "en.h"
+
+struct mlx5e_xsk_param;
+
+bool mlx5e_validate_xsk_param(struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk,
+ struct mlx5_core_dev *mdev);
+int mlx5e_open_xsk(struct mlx5e_priv *priv, struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk, struct xdp_umem *umem,
+ struct mlx5e_channel *c);
+void mlx5e_close_xsk(struct mlx5e_channel *c);
+void mlx5e_activate_xsk(struct mlx5e_channel *c);
+void mlx5e_deactivate_xsk(struct mlx5e_channel *c);
+int mlx5e_xsk_redirect_rqt_to_channel(struct mlx5e_priv *priv, struct mlx5e_channel *c);
+int mlx5e_xsk_redirect_rqt_to_drop(struct mlx5e_priv *priv, u16 ix);
+int mlx5e_xsk_redirect_rqts_to_channels(struct mlx5e_priv *priv, struct mlx5e_channels *chs);
+void mlx5e_xsk_redirect_rqts_to_drop(struct mlx5e_priv *priv, struct mlx5e_channels *chs);
+
+#endif /* __MLX5_EN_XSK_SETUP_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c
new file mode 100644
index 000000000000..35e188cf4ea4
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/* Copyright (c) 2019 Mellanox Technologies. */
+
+#include "tx.h"
+#include "umem.h"
+#include "en/xdp.h"
+#include "en/params.h"
+#include <net/xdp_sock.h>
+
+int mlx5e_xsk_async_xmit(struct net_device *dev, u32 qid)
+{
+ struct mlx5e_priv *priv = netdev_priv(dev);
+ struct mlx5e_params *params = &priv->channels.params;
+ struct mlx5e_channel *c;
+ u16 ix;
+
+ if (unlikely(!mlx5e_xdp_is_open(priv)))
+ return -ENETDOWN;
+
+ if (unlikely(!mlx5e_qid_get_ch_if_in_group(params, qid, MLX5E_RQ_GROUP_XSK, &ix)))
+ return -EINVAL;
+
+ c = priv->channels.c[ix];
+
+ if (unlikely(!test_bit(MLX5E_CHANNEL_STATE_XSK, c->state)))
+ return -ENXIO;
+
+ if (!napi_if_scheduled_mark_missed(&c->napi)) {
+ spin_lock(&c->xskicosq_lock);
+ mlx5e_trigger_irq(&c->xskicosq);
+ spin_unlock(&c->xskicosq_lock);
+ }
+
+ return 0;
+}
+
+/* When TX fails (because of the size of the packet), we need to get completions
+ * in order, so post a NOP to get a CQE. Since AF_XDP doesn't distinguish
+ * between successful TX and errors, handling in mlx5e_poll_xdpsq_cq is the
+ * same.
+ */
+static void mlx5e_xsk_tx_post_err(struct mlx5e_xdpsq *sq,
+ struct mlx5e_xdp_info *xdpi)
+{
+ u16 pi = mlx5_wq_cyc_ctr2ix(&sq->wq, sq->pc);
+ struct mlx5e_xdp_wqe_info *wi = &sq->db.wqe_info[pi];
+ struct mlx5e_tx_wqe *nopwqe;
+
+ wi->num_wqebbs = 1;
+ wi->num_pkts = 1;
+
+ nopwqe = mlx5e_post_nop(&sq->wq, sq->sqn, &sq->pc);
+ mlx5e_xdpi_fifo_push(&sq->db.xdpi_fifo, xdpi);
+ sq->doorbell_cseg = &nopwqe->ctrl;
+}
+
+bool mlx5e_xsk_tx(struct mlx5e_xdpsq *sq, unsigned int budget)
+{
+ struct xdp_umem *umem = sq->umem;
+ struct mlx5e_xdp_info xdpi;
+ struct mlx5e_xdp_xmit_data xdptxd;
+ bool work_done = true;
+ bool flush = false;
+
+ xdpi.mode = MLX5E_XDP_XMIT_MODE_XSK;
+
+ for (; budget; budget--) {
+ int check_result = sq->xmit_xdp_frame_check(sq);
+ struct xdp_desc desc;
+
+ if (unlikely(check_result < 0)) {
+ work_done = false;
+ break;
+ }
+
+ if (!xsk_umem_consume_tx(umem, &desc)) {
+ /* TX will get stuck until something wakes it up by
+ * triggering NAPI. Currently it's expected that the
+ * application calls sendto() if there are consumed, but
+ * not completed frames.
+ */
+ break;
+ }
+
+ xdptxd.dma_addr = xdp_umem_get_dma(umem, desc.addr);
+ xdptxd.data = xdp_umem_get_data(umem, desc.addr);
+ xdptxd.len = desc.len;
+
+ dma_sync_single_for_device(sq->pdev, xdptxd.dma_addr,
+ xdptxd.len, DMA_BIDIRECTIONAL);
+
+ if (unlikely(!sq->xmit_xdp_frame(sq, &xdptxd, &xdpi, check_result))) {
+ if (sq->mpwqe.wqe)
+ mlx5e_xdp_mpwqe_complete(sq);
+
+ mlx5e_xsk_tx_post_err(sq, &xdpi);
+ }
+
+ flush = true;
+ }
+
+ if (flush) {
+ if (sq->mpwqe.wqe)
+ mlx5e_xdp_mpwqe_complete(sq);
+ mlx5e_xmit_xdp_doorbell(sq);
+
+ xsk_umem_consume_tx_done(umem);
+ }
+
+ return !(budget && work_done);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.h b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.h
new file mode 100644
index 000000000000..7add18bf78d8
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2019 Mellanox Technologies. */
+
+#ifndef __MLX5_EN_XSK_TX_H__
+#define __MLX5_EN_XSK_TX_H__
+
+#include "en.h"
+
+/* TX data path */
+
+int mlx5e_xsk_async_xmit(struct net_device *dev, u32 qid);
+
+bool mlx5e_xsk_tx(struct mlx5e_xdpsq *sq, unsigned int budget);
+
+#endif /* __MLX5_EN_XSK_TX_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/umem.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/umem.c
new file mode 100644
index 000000000000..4baaa5788320
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/umem.c
@@ -0,0 +1,267 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/* Copyright (c) 2019 Mellanox Technologies. */
+
+#include <net/xdp_sock.h>
+#include "umem.h"
+#include "setup.h"
+#include "en/params.h"
+
+static int mlx5e_xsk_map_umem(struct mlx5e_priv *priv,
+ struct xdp_umem *umem)
+{
+ struct device *dev = priv->mdev->device;
+ u32 i;
+
+ for (i = 0; i < umem->npgs; i++) {
+ dma_addr_t dma = dma_map_page(dev, umem->pgs[i], 0, PAGE_SIZE,
+ DMA_BIDIRECTIONAL);
+
+ if (unlikely(dma_mapping_error(dev, dma)))
+ goto err_unmap;
+ umem->pages[i].dma = dma;
+ }
+
+ return 0;
+
+err_unmap:
+ while (i--) {
+ dma_unmap_page(dev, umem->pages[i].dma, PAGE_SIZE,
+ DMA_BIDIRECTIONAL);
+ umem->pages[i].dma = 0;
+ }
+
+ return -ENOMEM;
+}
+
+static void mlx5e_xsk_unmap_umem(struct mlx5e_priv *priv,
+ struct xdp_umem *umem)
+{
+ struct device *dev = priv->mdev->device;
+ u32 i;
+
+ for (i = 0; i < umem->npgs; i++) {
+ dma_unmap_page(dev, umem->pages[i].dma, PAGE_SIZE,
+ DMA_BIDIRECTIONAL);
+ umem->pages[i].dma = 0;
+ }
+}
+
+static int mlx5e_xsk_get_umems(struct mlx5e_xsk *xsk)
+{
+ if (!xsk->umems) {
+ xsk->umems = kcalloc(MLX5E_MAX_NUM_CHANNELS,
+ sizeof(*xsk->umems), GFP_KERNEL);
+ if (unlikely(!xsk->umems))
+ return -ENOMEM;
+ }
+
+ xsk->refcnt++;
+ xsk->ever_used = true;
+
+ return 0;
+}
+
+static void mlx5e_xsk_put_umems(struct mlx5e_xsk *xsk)
+{
+ if (!--xsk->refcnt) {
+ kfree(xsk->umems);
+ xsk->umems = NULL;
+ }
+}
+
+static int mlx5e_xsk_add_umem(struct mlx5e_xsk *xsk, struct xdp_umem *umem, u16 ix)
+{
+ int err;
+
+ err = mlx5e_xsk_get_umems(xsk);
+ if (unlikely(err))
+ return err;
+
+ xsk->umems[ix] = umem;
+ return 0;
+}
+
+static void mlx5e_xsk_remove_umem(struct mlx5e_xsk *xsk, u16 ix)
+{
+ xsk->umems[ix] = NULL;
+
+ mlx5e_xsk_put_umems(xsk);
+}
+
+static bool mlx5e_xsk_is_umem_sane(struct xdp_umem *umem)
+{
+ return umem->headroom <= 0xffff && umem->chunk_size_nohr <= 0xffff;
+}
+
+void mlx5e_build_xsk_param(struct xdp_umem *umem, struct mlx5e_xsk_param *xsk)
+{
+ xsk->headroom = umem->headroom;
+ xsk->chunk_size = umem->chunk_size_nohr + umem->headroom;
+}
+
+static int mlx5e_xsk_enable_locked(struct mlx5e_priv *priv,
+ struct xdp_umem *umem, u16 ix)
+{
+ struct mlx5e_params *params = &priv->channels.params;
+ struct mlx5e_xsk_param xsk;
+ struct mlx5e_channel *c;
+ int err;
+
+ if (unlikely(mlx5e_xsk_get_umem(&priv->channels.params, &priv->xsk, ix)))
+ return -EBUSY;
+
+ if (unlikely(!mlx5e_xsk_is_umem_sane(umem)))
+ return -EINVAL;
+
+ err = mlx5e_xsk_map_umem(priv, umem);
+ if (unlikely(err))
+ return err;
+
+ err = mlx5e_xsk_add_umem(&priv->xsk, umem, ix);
+ if (unlikely(err))
+ goto err_unmap_umem;
+
+ mlx5e_build_xsk_param(umem, &xsk);
+
+ if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) {
+ /* XSK objects will be created on open. */
+ goto validate_closed;
+ }
+
+ if (!params->xdp_prog) {
+ /* XSK objects will be created when an XDP program is set,
+ * and the channels are reopened.
+ */
+ goto validate_closed;
+ }
+
+ c = priv->channels.c[ix];
+
+ err = mlx5e_open_xsk(priv, params, &xsk, umem, c);
+ if (unlikely(err))
+ goto err_remove_umem;
+
+ mlx5e_activate_xsk(c);
+
+ /* Don't wait for WQEs, because the newer xdpsock sample doesn't provide
+ * any Fill Ring entries at the setup stage.
+ */
+
+ err = mlx5e_xsk_redirect_rqt_to_channel(priv, priv->channels.c[ix]);
+ if (unlikely(err))
+ goto err_deactivate;
+
+ return 0;
+
+err_deactivate:
+ mlx5e_deactivate_xsk(c);
+ mlx5e_close_xsk(c);
+
+err_remove_umem:
+ mlx5e_xsk_remove_umem(&priv->xsk, ix);
+
+err_unmap_umem:
+ mlx5e_xsk_unmap_umem(priv, umem);
+
+ return err;
+
+validate_closed:
+ /* Check the configuration in advance, rather than fail at a later stage
+ * (in mlx5e_xdp_set or on open) and end up with no channels.
+ */
+ if (!mlx5e_validate_xsk_param(params, &xsk, priv->mdev)) {
+ err = -EINVAL;
+ goto err_remove_umem;
+ }
+
+ return 0;
+}
+
+static int mlx5e_xsk_disable_locked(struct mlx5e_priv *priv, u16 ix)
+{
+ struct xdp_umem *umem = mlx5e_xsk_get_umem(&priv->channels.params,
+ &priv->xsk, ix);
+ struct mlx5e_channel *c;
+
+ if (unlikely(!umem))
+ return -EINVAL;
+
+ if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
+ goto remove_umem;
+
+ /* XSK RQ and SQ are only created if XDP program is set. */
+ if (!priv->channels.params.xdp_prog)
+ goto remove_umem;
+
+ c = priv->channels.c[ix];
+ mlx5e_xsk_redirect_rqt_to_drop(priv, ix);
+ mlx5e_deactivate_xsk(c);
+ mlx5e_close_xsk(c);
+
+remove_umem:
+ mlx5e_xsk_remove_umem(&priv->xsk, ix);
+ mlx5e_xsk_unmap_umem(priv, umem);
+
+ return 0;
+}
+
+static int mlx5e_xsk_enable_umem(struct mlx5e_priv *priv, struct xdp_umem *umem,
+ u16 ix)
+{
+ int err;
+
+ mutex_lock(&priv->state_lock);
+ err = mlx5e_xsk_enable_locked(priv, umem, ix);
+ mutex_unlock(&priv->state_lock);
+
+ return err;
+}
+
+static int mlx5e_xsk_disable_umem(struct mlx5e_priv *priv, u16 ix)
+{
+ int err;
+
+ mutex_lock(&priv->state_lock);
+ err = mlx5e_xsk_disable_locked(priv, ix);
+ mutex_unlock(&priv->state_lock);
+
+ return err;
+}
+
+int mlx5e_xsk_setup_umem(struct net_device *dev, struct xdp_umem *umem, u16 qid)
+{
+ struct mlx5e_priv *priv = netdev_priv(dev);
+ struct mlx5e_params *params = &priv->channels.params;
+ u16 ix;
+
+ if (unlikely(!mlx5e_qid_get_ch_if_in_group(params, qid, MLX5E_RQ_GROUP_XSK, &ix)))
+ return -EINVAL;
+
+ return umem ? mlx5e_xsk_enable_umem(priv, umem, ix) :
+ mlx5e_xsk_disable_umem(priv, ix);
+}
+
+int mlx5e_xsk_resize_reuseq(struct xdp_umem *umem, u32 nentries)
+{
+ struct xdp_umem_fq_reuse *reuseq;
+
+ reuseq = xsk_reuseq_prepare(nentries);
+ if (unlikely(!reuseq))
+ return -ENOMEM;
+ xsk_reuseq_free(xsk_reuseq_swap(umem, reuseq));
+
+ return 0;
+}
+
+u16 mlx5e_xsk_first_unused_channel(struct mlx5e_params *params, struct mlx5e_xsk *xsk)
+{
+ u16 res = xsk->refcnt ? params->num_channels : 0;
+
+ while (res) {
+ if (mlx5e_xsk_get_umem(params, xsk, res - 1))
+ break;
+ --res;
+ }
+
+ return res;
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/umem.h b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/umem.h
new file mode 100644
index 000000000000..25b4cbe58b54
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/umem.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2019 Mellanox Technologies. */
+
+#ifndef __MLX5_EN_XSK_UMEM_H__
+#define __MLX5_EN_XSK_UMEM_H__
+
+#include "en.h"
+
+static inline struct xdp_umem *mlx5e_xsk_get_umem(struct mlx5e_params *params,
+ struct mlx5e_xsk *xsk, u16 ix)
+{
+ if (!xsk || !xsk->umems)
+ return NULL;
+
+ if (unlikely(ix >= params->num_channels))
+ return NULL;
+
+ return xsk->umems[ix];
+}
+
+struct mlx5e_xsk_param;
+void mlx5e_build_xsk_param(struct xdp_umem *umem, struct mlx5e_xsk_param *xsk);
+
+/* .ndo_bpf callback. */
+int mlx5e_xsk_setup_umem(struct net_device *dev, struct xdp_umem *umem, u16 qid);
+
+int mlx5e_xsk_resize_reuseq(struct xdp_umem *umem, u32 nentries);
+
+u16 mlx5e_xsk_first_unused_channel(struct mlx5e_params *params, struct mlx5e_xsk *xsk);
+
+#endif /* __MLX5_EN_XSK_UMEM_H__ */
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 6da7c88742dc..3022463f2284 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
@@ -39,6 +39,7 @@
#include "en_accel/ipsec_rxtx.h"
#include "en_accel/tls_rxtx.h"
#include "en.h"
+#include "en/txrx.h"
#if IS_ENABLED(CONFIG_GENEVE)
static inline bool mlx5_geneve_tx_allowed(struct mlx5_core_dev *mdev)
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 ca47c0540904..db84500b024f 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
@@ -39,6 +39,7 @@
#include <linux/skbuff.h>
#include <net/xfrm.h>
#include "en.h"
+#include "en/txrx.h"
struct sk_buff *mlx5e_ipsec_handle_rx_skb(struct net_device *netdev,
struct sk_buff *skb, u32 *cqe_bcnt);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.c
new file mode 100644
index 000000000000..d2ff74d52720
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+// Copyright (c) 2019 Mellanox Technologies.
+
+#include "en.h"
+#include "en_accel/ktls.h"
+
+static int mlx5e_ktls_create_tis(struct mlx5_core_dev *mdev, u32 *tisn)
+{
+ u32 in[MLX5_ST_SZ_DW(create_tis_in)] = {};
+ void *tisc;
+
+ tisc = MLX5_ADDR_OF(create_tis_in, in, ctx);
+
+ MLX5_SET(tisc, tisc, tls_en, 1);
+
+ return mlx5e_create_tis(mdev, in, tisn);
+}
+
+static int mlx5e_ktls_add(struct net_device *netdev, struct sock *sk,
+ enum tls_offload_ctx_dir direction,
+ struct tls_crypto_info *crypto_info,
+ u32 start_offload_tcp_sn)
+{
+ struct mlx5e_priv *priv = netdev_priv(netdev);
+ struct mlx5e_ktls_offload_context_tx *tx_priv;
+ struct tls_context *tls_ctx = tls_get_ctx(sk);
+ struct mlx5_core_dev *mdev = priv->mdev;
+ int err;
+
+ if (WARN_ON(direction != TLS_OFFLOAD_CTX_DIR_TX))
+ return -EINVAL;
+
+ if (WARN_ON(!mlx5e_ktls_type_check(mdev, crypto_info)))
+ return -EOPNOTSUPP;
+
+ tx_priv = kvzalloc(sizeof(*tx_priv), GFP_KERNEL);
+ if (!tx_priv)
+ return -ENOMEM;
+
+ tx_priv->expected_seq = start_offload_tcp_sn;
+ tx_priv->crypto_info = crypto_info;
+ mlx5e_set_ktls_tx_priv_ctx(tls_ctx, tx_priv);
+
+ /* tc and underlay_qpn values are not in use for tls tis */
+ err = mlx5e_ktls_create_tis(mdev, &tx_priv->tisn);
+ if (err)
+ goto create_tis_fail;
+
+ err = mlx5_ktls_create_key(mdev, crypto_info, &tx_priv->key_id);
+ if (err)
+ goto encryption_key_create_fail;
+
+ mlx5e_ktls_tx_offload_set_pending(tx_priv);
+
+ return 0;
+
+encryption_key_create_fail:
+ mlx5e_destroy_tis(priv->mdev, tx_priv->tisn);
+create_tis_fail:
+ kvfree(tx_priv);
+ return err;
+}
+
+static void mlx5e_ktls_del(struct net_device *netdev,
+ struct tls_context *tls_ctx,
+ enum tls_offload_ctx_dir direction)
+{
+ struct mlx5e_priv *priv = netdev_priv(netdev);
+ struct mlx5e_ktls_offload_context_tx *tx_priv =
+ mlx5e_get_ktls_tx_priv_ctx(tls_ctx);
+
+ mlx5_ktls_destroy_key(priv->mdev, tx_priv->key_id);
+ mlx5e_destroy_tis(priv->mdev, tx_priv->tisn);
+ kvfree(tx_priv);
+}
+
+static const struct tlsdev_ops mlx5e_ktls_ops = {
+ .tls_dev_add = mlx5e_ktls_add,
+ .tls_dev_del = mlx5e_ktls_del,
+};
+
+void mlx5e_ktls_build_netdev(struct mlx5e_priv *priv)
+{
+ struct net_device *netdev = priv->netdev;
+
+ if (!mlx5_accel_is_ktls_device(priv->mdev))
+ return;
+
+ netdev->hw_features |= NETIF_F_HW_TLS_TX;
+ netdev->features |= NETIF_F_HW_TLS_TX;
+
+ netdev->tlsdev_ops = &mlx5e_ktls_ops;
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.h
new file mode 100644
index 000000000000..407da83474ef
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.h
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2019 Mellanox Technologies. */
+
+#ifndef __MLX5E_KTLS_H__
+#define __MLX5E_KTLS_H__
+
+#include "en.h"
+
+#ifdef CONFIG_MLX5_EN_TLS
+#include <net/tls.h>
+#include "accel/tls.h"
+
+#define MLX5E_KTLS_STATIC_UMR_WQE_SZ \
+ (sizeof(struct mlx5e_umr_wqe) + MLX5_ST_SZ_BYTES(tls_static_params))
+#define MLX5E_KTLS_STATIC_WQEBBS \
+ (DIV_ROUND_UP(MLX5E_KTLS_STATIC_UMR_WQE_SZ, MLX5_SEND_WQE_BB))
+
+#define MLX5E_KTLS_PROGRESS_WQE_SZ \
+ (sizeof(struct mlx5e_tx_wqe) + MLX5_ST_SZ_BYTES(tls_progress_params))
+#define MLX5E_KTLS_PROGRESS_WQEBBS \
+ (DIV_ROUND_UP(MLX5E_KTLS_PROGRESS_WQE_SZ, MLX5_SEND_WQE_BB))
+#define MLX5E_KTLS_MAX_DUMP_WQEBBS 2
+
+enum {
+ MLX5E_TLS_PROGRESS_PARAMS_AUTH_STATE_NO_OFFLOAD = 0,
+ MLX5E_TLS_PROGRESS_PARAMS_AUTH_STATE_OFFLOAD = 1,
+ MLX5E_TLS_PROGRESS_PARAMS_AUTH_STATE_AUTHENTICATION = 2,
+};
+
+enum {
+ MLX5E_TLS_PROGRESS_PARAMS_RECORD_TRACKER_STATE_START = 0,
+ MLX5E_TLS_PROGRESS_PARAMS_RECORD_TRACKER_STATE_SEARCHING = 1,
+ MLX5E_TLS_PROGRESS_PARAMS_RECORD_TRACKER_STATE_TRACKING = 2,
+};
+
+struct mlx5e_ktls_offload_context_tx {
+ struct tls_offload_context_tx *tx_ctx;
+ struct tls_crypto_info *crypto_info;
+ u32 expected_seq;
+ u32 tisn;
+ u32 key_id;
+ bool ctx_post_pending;
+};
+
+struct mlx5e_ktls_offload_context_tx_shadow {
+ struct tls_offload_context_tx tx_ctx;
+ struct mlx5e_ktls_offload_context_tx *priv_tx;
+};
+
+static inline void
+mlx5e_set_ktls_tx_priv_ctx(struct tls_context *tls_ctx,
+ struct mlx5e_ktls_offload_context_tx *priv_tx)
+{
+ struct tls_offload_context_tx *tx_ctx = tls_offload_ctx_tx(tls_ctx);
+ struct mlx5e_ktls_offload_context_tx_shadow *shadow;
+
+ BUILD_BUG_ON(sizeof(*shadow) > TLS_OFFLOAD_CONTEXT_SIZE_TX);
+
+ shadow = (struct mlx5e_ktls_offload_context_tx_shadow *)tx_ctx;
+
+ shadow->priv_tx = priv_tx;
+ priv_tx->tx_ctx = tx_ctx;
+}
+
+static inline struct mlx5e_ktls_offload_context_tx *
+mlx5e_get_ktls_tx_priv_ctx(struct tls_context *tls_ctx)
+{
+ struct tls_offload_context_tx *tx_ctx = tls_offload_ctx_tx(tls_ctx);
+ struct mlx5e_ktls_offload_context_tx_shadow *shadow;
+
+ BUILD_BUG_ON(sizeof(*shadow) > TLS_OFFLOAD_CONTEXT_SIZE_TX);
+
+ shadow = (struct mlx5e_ktls_offload_context_tx_shadow *)tx_ctx;
+
+ return shadow->priv_tx;
+}
+
+void mlx5e_ktls_build_netdev(struct mlx5e_priv *priv);
+void mlx5e_ktls_tx_offload_set_pending(struct mlx5e_ktls_offload_context_tx *priv_tx);
+
+struct sk_buff *mlx5e_ktls_handle_tx_skb(struct net_device *netdev,
+ struct mlx5e_txqsq *sq,
+ struct sk_buff *skb,
+ struct mlx5e_tx_wqe **wqe, u16 *pi);
+void mlx5e_ktls_tx_handle_resync_dump_comp(struct mlx5e_txqsq *sq,
+ struct mlx5e_tx_wqe_info *wi,
+ struct mlx5e_sq_dma *dma);
+
+#else
+
+static inline void mlx5e_ktls_build_netdev(struct mlx5e_priv *priv)
+{
+}
+
+#endif
+
+#endif /* __MLX5E_TLS_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c
new file mode 100644
index 000000000000..ea032f54197e
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c
@@ -0,0 +1,448 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+// Copyright (c) 2019 Mellanox Technologies.
+
+#include <linux/tls.h>
+#include "en.h"
+#include "en/txrx.h"
+#include "en_accel/ktls.h"
+
+enum {
+ MLX5E_STATIC_PARAMS_CONTEXT_TLS_1_2 = 0x2,
+};
+
+enum {
+ MLX5E_ENCRYPTION_STANDARD_TLS = 0x1,
+};
+
+#define EXTRACT_INFO_FIELDS do { \
+ salt = info->salt; \
+ rec_seq = info->rec_seq; \
+ salt_sz = sizeof(info->salt); \
+ rec_seq_sz = sizeof(info->rec_seq); \
+} while (0)
+
+static void
+fill_static_params_ctx(void *ctx, struct mlx5e_ktls_offload_context_tx *priv_tx)
+{
+ struct tls_crypto_info *crypto_info = priv_tx->crypto_info;
+ struct tls12_crypto_info_aes_gcm_128 *info;
+ char *initial_rn, *gcm_iv;
+ u16 salt_sz, rec_seq_sz;
+ char *salt, *rec_seq;
+ u8 tls_version;
+
+ if (WARN_ON(crypto_info->cipher_type != TLS_CIPHER_AES_GCM_128))
+ return;
+
+ info = (struct tls12_crypto_info_aes_gcm_128 *)crypto_info;
+ EXTRACT_INFO_FIELDS;
+
+ gcm_iv = MLX5_ADDR_OF(tls_static_params, ctx, gcm_iv);
+ initial_rn = MLX5_ADDR_OF(tls_static_params, ctx, initial_record_number);
+
+ memcpy(gcm_iv, salt, salt_sz);
+ memcpy(initial_rn, rec_seq, rec_seq_sz);
+
+ tls_version = MLX5E_STATIC_PARAMS_CONTEXT_TLS_1_2;
+
+ MLX5_SET(tls_static_params, ctx, tls_version, tls_version);
+ MLX5_SET(tls_static_params, ctx, const_1, 1);
+ MLX5_SET(tls_static_params, ctx, const_2, 2);
+ MLX5_SET(tls_static_params, ctx, encryption_standard,
+ MLX5E_ENCRYPTION_STANDARD_TLS);
+ MLX5_SET(tls_static_params, ctx, dek_index, priv_tx->key_id);
+}
+
+static void
+build_static_params(struct mlx5e_umr_wqe *wqe, u16 pc, u32 sqn,
+ struct mlx5e_ktls_offload_context_tx *priv_tx,
+ bool fence)
+{
+ struct mlx5_wqe_ctrl_seg *cseg = &wqe->ctrl;
+ struct mlx5_wqe_umr_ctrl_seg *ucseg = &wqe->uctrl;
+
+#define STATIC_PARAMS_DS_CNT \
+ DIV_ROUND_UP(MLX5E_KTLS_STATIC_UMR_WQE_SZ, MLX5_SEND_WQE_DS)
+
+ cseg->opmod_idx_opcode = cpu_to_be32((pc << 8) | MLX5_OPCODE_UMR |
+ (MLX5_OPC_MOD_TLS_TIS_STATIC_PARAMS << 24));
+ cseg->qpn_ds = cpu_to_be32((sqn << MLX5_WQE_CTRL_QPN_SHIFT) |
+ STATIC_PARAMS_DS_CNT);
+ cseg->fm_ce_se = fence ? MLX5_FENCE_MODE_INITIATOR_SMALL : 0;
+ cseg->imm = cpu_to_be32(priv_tx->tisn);
+
+ ucseg->flags = MLX5_UMR_INLINE;
+ ucseg->bsf_octowords = cpu_to_be16(MLX5_ST_SZ_BYTES(tls_static_params) / 16);
+
+ fill_static_params_ctx(wqe->tls_static_params_ctx, priv_tx);
+}
+
+static void
+fill_progress_params_ctx(void *ctx, struct mlx5e_ktls_offload_context_tx *priv_tx)
+{
+ MLX5_SET(tls_progress_params, ctx, pd, priv_tx->tisn);
+ MLX5_SET(tls_progress_params, ctx, record_tracker_state,
+ MLX5E_TLS_PROGRESS_PARAMS_RECORD_TRACKER_STATE_START);
+ MLX5_SET(tls_progress_params, ctx, auth_state,
+ MLX5E_TLS_PROGRESS_PARAMS_AUTH_STATE_NO_OFFLOAD);
+}
+
+static void
+build_progress_params(struct mlx5e_tx_wqe *wqe, u16 pc, u32 sqn,
+ struct mlx5e_ktls_offload_context_tx *priv_tx,
+ bool fence)
+{
+ struct mlx5_wqe_ctrl_seg *cseg = &wqe->ctrl;
+
+#define PROGRESS_PARAMS_DS_CNT \
+ DIV_ROUND_UP(MLX5E_KTLS_PROGRESS_WQE_SZ, MLX5_SEND_WQE_DS)
+
+ cseg->opmod_idx_opcode =
+ cpu_to_be32((pc << 8) | MLX5_OPCODE_SET_PSV |
+ (MLX5_OPC_MOD_TLS_TIS_PROGRESS_PARAMS << 24));
+ cseg->qpn_ds = cpu_to_be32((sqn << MLX5_WQE_CTRL_QPN_SHIFT) |
+ PROGRESS_PARAMS_DS_CNT);
+ cseg->fm_ce_se = fence ? MLX5_FENCE_MODE_INITIATOR_SMALL : 0;
+
+ fill_progress_params_ctx(wqe->data, priv_tx);
+}
+
+static void tx_fill_wi(struct mlx5e_txqsq *sq,
+ u16 pi, u8 num_wqebbs,
+ skb_frag_t *resync_dump_frag)
+{
+ struct mlx5e_tx_wqe_info *wi = &sq->db.wqe_info[pi];
+
+ wi->skb = NULL;
+ wi->num_wqebbs = num_wqebbs;
+ wi->resync_dump_frag = resync_dump_frag;
+}
+
+void mlx5e_ktls_tx_offload_set_pending(struct mlx5e_ktls_offload_context_tx *priv_tx)
+{
+ priv_tx->ctx_post_pending = true;
+}
+
+static bool
+mlx5e_ktls_tx_offload_test_and_clear_pending(struct mlx5e_ktls_offload_context_tx *priv_tx)
+{
+ bool ret = priv_tx->ctx_post_pending;
+
+ priv_tx->ctx_post_pending = false;
+
+ return ret;
+}
+
+static void
+post_static_params(struct mlx5e_txqsq *sq,
+ struct mlx5e_ktls_offload_context_tx *priv_tx,
+ bool fence)
+{
+ struct mlx5e_umr_wqe *umr_wqe;
+ u16 pi;
+
+ umr_wqe = mlx5e_sq_fetch_wqe(sq, MLX5E_KTLS_STATIC_UMR_WQE_SZ, &pi);
+ build_static_params(umr_wqe, sq->pc, sq->sqn, priv_tx, fence);
+ tx_fill_wi(sq, pi, MLX5E_KTLS_STATIC_WQEBBS, NULL);
+ sq->pc += MLX5E_KTLS_STATIC_WQEBBS;
+}
+
+static void
+post_progress_params(struct mlx5e_txqsq *sq,
+ struct mlx5e_ktls_offload_context_tx *priv_tx,
+ bool fence)
+{
+ struct mlx5e_tx_wqe *wqe;
+ u16 pi;
+
+ wqe = mlx5e_sq_fetch_wqe(sq, MLX5E_KTLS_PROGRESS_WQE_SZ, &pi);
+ build_progress_params(wqe, sq->pc, sq->sqn, priv_tx, fence);
+ tx_fill_wi(sq, pi, MLX5E_KTLS_PROGRESS_WQEBBS, NULL);
+ sq->pc += MLX5E_KTLS_PROGRESS_WQEBBS;
+}
+
+static void
+mlx5e_ktls_tx_post_param_wqes(struct mlx5e_txqsq *sq,
+ struct mlx5e_ktls_offload_context_tx *priv_tx,
+ bool skip_static_post, bool fence_first_post)
+{
+ bool progress_fence = skip_static_post || !fence_first_post;
+
+ if (!skip_static_post)
+ post_static_params(sq, priv_tx, fence_first_post);
+
+ post_progress_params(sq, priv_tx, progress_fence);
+}
+
+struct tx_sync_info {
+ u64 rcd_sn;
+ s32 sync_len;
+ int nr_frags;
+ skb_frag_t *frags[MAX_SKB_FRAGS];
+};
+
+static bool tx_sync_info_get(struct mlx5e_ktls_offload_context_tx *priv_tx,
+ u32 tcp_seq, struct tx_sync_info *info)
+{
+ struct tls_offload_context_tx *tx_ctx = priv_tx->tx_ctx;
+ struct tls_record_info *record;
+ int remaining, i = 0;
+ unsigned long flags;
+ bool ret = true;
+
+ spin_lock_irqsave(&tx_ctx->lock, flags);
+ record = tls_get_record(tx_ctx, tcp_seq, &info->rcd_sn);
+
+ if (unlikely(!record)) {
+ ret = false;
+ goto out;
+ }
+
+ if (unlikely(tcp_seq < tls_record_start_seq(record))) {
+ if (!tls_record_is_start_marker(record))
+ ret = false;
+ goto out;
+ }
+
+ info->sync_len = tcp_seq - tls_record_start_seq(record);
+ remaining = info->sync_len;
+ while (remaining > 0) {
+ skb_frag_t *frag = &record->frags[i];
+
+ __skb_frag_ref(frag);
+ remaining -= skb_frag_size(frag);
+ info->frags[i++] = frag;
+ }
+ /* reduce the part which will be sent with the original SKB */
+ if (remaining < 0)
+ skb_frag_size_add(info->frags[i - 1], remaining);
+ info->nr_frags = i;
+out:
+ spin_unlock_irqrestore(&tx_ctx->lock, flags);
+ return ret;
+}
+
+static void
+tx_post_resync_params(struct mlx5e_txqsq *sq,
+ struct mlx5e_ktls_offload_context_tx *priv_tx,
+ u64 rcd_sn)
+{
+ struct tls_crypto_info *crypto_info = priv_tx->crypto_info;
+ struct tls12_crypto_info_aes_gcm_128 *info;
+ __be64 rn_be = cpu_to_be64(rcd_sn);
+ bool skip_static_post;
+ u16 rec_seq_sz;
+ char *rec_seq;
+
+ if (WARN_ON(crypto_info->cipher_type != TLS_CIPHER_AES_GCM_128))
+ return;
+
+ info = (struct tls12_crypto_info_aes_gcm_128 *)crypto_info;
+ rec_seq = info->rec_seq;
+ rec_seq_sz = sizeof(info->rec_seq);
+
+ skip_static_post = !memcmp(rec_seq, &rn_be, rec_seq_sz);
+ if (!skip_static_post)
+ memcpy(rec_seq, &rn_be, rec_seq_sz);
+
+ mlx5e_ktls_tx_post_param_wqes(sq, priv_tx, skip_static_post, true);
+}
+
+static int
+tx_post_resync_dump(struct mlx5e_txqsq *sq, struct sk_buff *skb,
+ skb_frag_t *frag, u32 tisn, bool first)
+{
+ struct mlx5_wqe_ctrl_seg *cseg;
+ struct mlx5_wqe_eth_seg *eseg;
+ struct mlx5_wqe_data_seg *dseg;
+ struct mlx5e_tx_wqe *wqe;
+ dma_addr_t dma_addr = 0;
+ u16 ds_cnt, ds_cnt_inl;
+ u8 num_wqebbs;
+ u16 pi, ihs;
+ int fsz;
+
+ ds_cnt = sizeof(*wqe) / MLX5_SEND_WQE_DS;
+ ihs = eth_get_headlen(skb->dev, skb->data, skb_headlen(skb));
+ ds_cnt_inl = DIV_ROUND_UP(ihs - INL_HDR_START_SZ, MLX5_SEND_WQE_DS);
+ ds_cnt += ds_cnt_inl;
+ ds_cnt += 1; /* one frag */
+
+ wqe = mlx5e_sq_fetch_wqe(sq, sizeof(*wqe), &pi);
+
+ num_wqebbs = DIV_ROUND_UP(ds_cnt, MLX5_SEND_WQEBB_NUM_DS);
+
+ cseg = &wqe->ctrl;
+ eseg = &wqe->eth;
+ dseg = wqe->data;
+
+ cseg->opmod_idx_opcode = cpu_to_be32((sq->pc << 8) | MLX5_OPCODE_DUMP);
+ cseg->qpn_ds = cpu_to_be32((sq->sqn << 8) | ds_cnt);
+ cseg->imm = cpu_to_be32(tisn);
+ cseg->fm_ce_se = first ? MLX5_FENCE_MODE_INITIATOR_SMALL : 0;
+
+ eseg->inline_hdr.sz = cpu_to_be16(ihs);
+ memcpy(eseg->inline_hdr.start, skb->data, ihs);
+ dseg += ds_cnt_inl;
+
+ fsz = skb_frag_size(frag);
+ dma_addr = skb_frag_dma_map(sq->pdev, frag, 0, fsz,
+ DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(sq->pdev, dma_addr)))
+ return -ENOMEM;
+
+ dseg->addr = cpu_to_be64(dma_addr);
+ dseg->lkey = sq->mkey_be;
+ dseg->byte_count = cpu_to_be32(fsz);
+ mlx5e_dma_push(sq, dma_addr, fsz, MLX5E_DMA_MAP_PAGE);
+
+ tx_fill_wi(sq, pi, num_wqebbs, frag);
+ sq->pc += num_wqebbs;
+
+ WARN(num_wqebbs > MLX5E_KTLS_MAX_DUMP_WQEBBS,
+ "unexpected DUMP num_wqebbs, %d > %d",
+ num_wqebbs, MLX5E_KTLS_MAX_DUMP_WQEBBS);
+
+ return 0;
+}
+
+void mlx5e_ktls_tx_handle_resync_dump_comp(struct mlx5e_txqsq *sq,
+ struct mlx5e_tx_wqe_info *wi,
+ struct mlx5e_sq_dma *dma)
+{
+ struct mlx5e_sq_stats *stats = sq->stats;
+
+ mlx5e_tx_dma_unmap(sq->pdev, dma);
+ __skb_frag_unref(wi->resync_dump_frag);
+ stats->tls_dump_packets++;
+ stats->tls_dump_bytes += wi->num_bytes;
+}
+
+static void tx_post_fence_nop(struct mlx5e_txqsq *sq)
+{
+ struct mlx5_wq_cyc *wq = &sq->wq;
+ u16 pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
+
+ tx_fill_wi(sq, pi, 1, NULL);
+
+ mlx5e_post_nop_fence(wq, sq->sqn, &sq->pc);
+}
+
+static struct sk_buff *
+mlx5e_ktls_tx_handle_ooo(struct mlx5e_ktls_offload_context_tx *priv_tx,
+ struct mlx5e_txqsq *sq,
+ struct sk_buff *skb,
+ u32 seq)
+{
+ struct mlx5e_sq_stats *stats = sq->stats;
+ struct mlx5_wq_cyc *wq = &sq->wq;
+ struct tx_sync_info info = {};
+ u16 contig_wqebbs_room, pi;
+ u8 num_wqebbs;
+ int i;
+
+ if (!tx_sync_info_get(priv_tx, seq, &info)) {
+ /* We might get here if a retransmission reaches the driver
+ * after the relevant record is acked.
+ * It should be safe to drop the packet in this case
+ */
+ stats->tls_drop_no_sync_data++;
+ goto err_out;
+ }
+
+ if (unlikely(info.sync_len < 0)) {
+ u32 payload;
+ int headln;
+
+ headln = skb_transport_offset(skb) + tcp_hdrlen(skb);
+ payload = skb->len - headln;
+ if (likely(payload <= -info.sync_len))
+ return skb;
+
+ stats->tls_drop_bypass_req++;
+ goto err_out;
+ }
+
+ stats->tls_ooo++;
+
+ num_wqebbs = MLX5E_KTLS_STATIC_WQEBBS + MLX5E_KTLS_PROGRESS_WQEBBS +
+ (info.nr_frags ? info.nr_frags * MLX5E_KTLS_MAX_DUMP_WQEBBS : 1);
+ pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
+ contig_wqebbs_room = mlx5_wq_cyc_get_contig_wqebbs(wq, pi);
+ if (unlikely(contig_wqebbs_room < num_wqebbs))
+ mlx5e_fill_sq_frag_edge(sq, wq, pi, contig_wqebbs_room);
+
+ tx_post_resync_params(sq, priv_tx, info.rcd_sn);
+
+ for (i = 0; i < info.nr_frags; i++)
+ if (tx_post_resync_dump(sq, skb, info.frags[i],
+ priv_tx->tisn, !i))
+ goto err_out;
+
+ /* If no dump WQE was sent, we need to have a fence NOP WQE before the
+ * actual data xmit.
+ */
+ if (!info.nr_frags)
+ tx_post_fence_nop(sq);
+
+ return skb;
+
+err_out:
+ dev_kfree_skb_any(skb);
+ return NULL;
+}
+
+struct sk_buff *mlx5e_ktls_handle_tx_skb(struct net_device *netdev,
+ struct mlx5e_txqsq *sq,
+ struct sk_buff *skb,
+ struct mlx5e_tx_wqe **wqe, u16 *pi)
+{
+ struct mlx5e_ktls_offload_context_tx *priv_tx;
+ struct mlx5e_sq_stats *stats = sq->stats;
+ struct mlx5_wqe_ctrl_seg *cseg;
+ struct tls_context *tls_ctx;
+ int datalen;
+ u32 seq;
+
+ if (!skb->sk || !tls_is_sk_tx_device_offloaded(skb->sk))
+ goto out;
+
+ datalen = skb->len - (skb_transport_offset(skb) + tcp_hdrlen(skb));
+ if (!datalen)
+ goto out;
+
+ tls_ctx = tls_get_ctx(skb->sk);
+ if (unlikely(tls_ctx->netdev != netdev))
+ goto err_out;
+
+ priv_tx = mlx5e_get_ktls_tx_priv_ctx(tls_ctx);
+
+ if (unlikely(mlx5e_ktls_tx_offload_test_and_clear_pending(priv_tx))) {
+ mlx5e_ktls_tx_post_param_wqes(sq, priv_tx, false, false);
+ *wqe = mlx5e_sq_fetch_wqe(sq, sizeof(**wqe), pi);
+ stats->tls_ctx++;
+ }
+
+ seq = ntohl(tcp_hdr(skb)->seq);
+ if (unlikely(priv_tx->expected_seq != seq)) {
+ skb = mlx5e_ktls_tx_handle_ooo(priv_tx, sq, skb, seq);
+ if (unlikely(!skb))
+ goto out;
+ *wqe = mlx5e_sq_fetch_wqe(sq, sizeof(**wqe), pi);
+ }
+
+ priv_tx->expected_seq = seq + datalen;
+
+ cseg = &(*wqe)->ctrl;
+ cseg->imm = cpu_to_be32(priv_tx->tisn);
+
+ stats->tls_encrypted_packets += skb_is_gso(skb) ? skb_shinfo(skb)->gso_segs : 1;
+ stats->tls_encrypted_bytes += datalen;
+
+out:
+ return skb;
+
+err_out:
+ dev_kfree_skb_any(skb);
+ return NULL;
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls.c
index e88340e196f7..fba561ffe1d4 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls.c
@@ -160,25 +160,31 @@ static void mlx5e_tls_del(struct net_device *netdev,
direction == TLS_OFFLOAD_CTX_DIR_TX);
}
-static void mlx5e_tls_resync_rx(struct net_device *netdev, struct sock *sk,
- u32 seq, u64 rcd_sn)
+static int mlx5e_tls_resync(struct net_device *netdev, struct sock *sk,
+ u32 seq, u8 *rcd_sn_data,
+ enum tls_offload_ctx_dir direction)
{
struct tls_context *tls_ctx = tls_get_ctx(sk);
struct mlx5e_priv *priv = netdev_priv(netdev);
struct mlx5e_tls_offload_context_rx *rx_ctx;
+ u64 rcd_sn = *(u64 *)rcd_sn_data;
+ if (WARN_ON_ONCE(direction != TLS_OFFLOAD_CTX_DIR_RX))
+ return -EINVAL;
rx_ctx = mlx5e_get_tls_rx_context(tls_ctx);
netdev_info(netdev, "resyncing seq %d rcd %lld\n", seq,
be64_to_cpu(rcd_sn));
mlx5_accel_tls_resync_rx(priv->mdev, rx_ctx->handle, seq, rcd_sn);
atomic64_inc(&priv->tls->sw_stats.rx_tls_resync_reply);
+
+ return 0;
}
static const struct tlsdev_ops mlx5e_tls_ops = {
.tls_dev_add = mlx5e_tls_add,
.tls_dev_del = mlx5e_tls_del,
- .tls_dev_resync_rx = mlx5e_tls_resync_rx,
+ .tls_dev_resync = mlx5e_tls_resync,
};
void mlx5e_tls_build_netdev(struct mlx5e_priv *priv)
@@ -186,6 +192,11 @@ void mlx5e_tls_build_netdev(struct mlx5e_priv *priv)
struct net_device *netdev = priv->netdev;
u32 caps;
+ if (mlx5_accel_is_ktls_device(priv->mdev)) {
+ mlx5e_ktls_build_netdev(priv);
+ return;
+ }
+
if (!mlx5_accel_is_tls_device(priv->mdev))
return;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls.h
index 3f5d72163b56..9015f3f7792d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls.h
@@ -33,8 +33,10 @@
#ifndef __MLX5E_TLS_H__
#define __MLX5E_TLS_H__
-#ifdef CONFIG_MLX5_EN_TLS
+#include "accel/tls.h"
+#include "en_accel/ktls.h"
+#ifdef CONFIG_MLX5_EN_TLS
#include <net/tls.h>
#include "en.h"
@@ -94,7 +96,12 @@ int mlx5e_tls_get_stats(struct mlx5e_priv *priv, u64 *data);
#else
-static inline void mlx5e_tls_build_netdev(struct mlx5e_priv *priv) { }
+static inline void mlx5e_tls_build_netdev(struct mlx5e_priv *priv)
+{
+ if (mlx5_accel_is_ktls_device(priv->mdev))
+ mlx5e_ktls_build_netdev(priv);
+}
+
static inline int mlx5e_tls_init(struct mlx5e_priv *priv) { return 0; }
static inline void mlx5e_tls_cleanup(struct mlx5e_priv *priv) { }
static inline int mlx5e_tls_get_count(struct mlx5e_priv *priv) { return 0; }
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls_rxtx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls_rxtx.c
index 439bf5953885..71384ad1a443 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls_rxtx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls_rxtx.c
@@ -248,7 +248,7 @@ mlx5e_tls_handle_ooo(struct mlx5e_tls_offload_context_tx *context,
mlx5e_tls_complete_sync_skb(skb, nskb, tcp_seq, headln,
cpu_to_be64(info.rcd_sn));
mlx5e_sq_xmit(sq, nskb, *wqe, *pi, true);
- mlx5e_sq_fetch_wqe(sq, wqe, pi);
+ *wqe = mlx5e_sq_fetch_wqe(sq, sizeof(**wqe), pi);
return skb;
err_out:
@@ -269,6 +269,11 @@ struct sk_buff *mlx5e_tls_handle_tx_skb(struct net_device *netdev,
int datalen;
u32 skb_seq;
+ if (MLX5_CAP_GEN(sq->channel->mdev, tls)) {
+ skb = mlx5e_ktls_handle_tx_skb(netdev, sq, skb, wqe, pi);
+ goto out;
+ }
+
if (!skb->sk || !tls_is_sk_tx_device_offloaded(skb->sk))
goto out;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls_rxtx.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls_rxtx.h
index 311667ec71b8..90bc1f2384c8 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls_rxtx.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls_rxtx.h
@@ -38,6 +38,7 @@
#include <linux/skbuff.h>
#include "en.h"
+#include "en/txrx.h"
struct sk_buff *mlx5e_tls_handle_tx_skb(struct net_device *netdev,
struct mlx5e_txqsq *sq,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c b/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c
index 554672edf8c3..8dd31b5c740c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c
@@ -680,7 +680,7 @@ static void mlx5e_dcbnl_getpermhwaddr(struct net_device *netdev,
memset(perm_addr, 0xff, MAX_ADDR_LEN);
- mlx5_query_nic_vport_mac_address(priv->mdev, 0, perm_addr);
+ mlx5_query_mac_address(priv->mdev, perm_addr);
}
static void mlx5e_dcbnl_setpgtccfgtx(struct net_device *netdev,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_dim.c b/drivers/net/ethernet/mellanox/mlx5/core/en_dim.c
index d67adf70a97b..ca9cfbf57d8f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_dim.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_dim.c
@@ -30,22 +30,22 @@
* SOFTWARE.
*/
-#include <linux/net_dim.h>
+#include <linux/dim.h>
#include "en.h"
static void
-mlx5e_complete_dim_work(struct net_dim *dim, struct net_dim_cq_moder moder,
+mlx5e_complete_dim_work(struct dim *dim, struct dim_cq_moder moder,
struct mlx5_core_dev *mdev, struct mlx5_core_cq *mcq)
{
mlx5_core_modify_cq_moderation(mdev, mcq, moder.usec, moder.pkts);
- dim->state = NET_DIM_START_MEASURE;
+ dim->state = DIM_START_MEASURE;
}
void mlx5e_rx_dim_work(struct work_struct *work)
{
- struct net_dim *dim = container_of(work, struct net_dim, work);
+ struct dim *dim = container_of(work, struct dim, work);
struct mlx5e_rq *rq = container_of(dim, struct mlx5e_rq, dim);
- struct net_dim_cq_moder cur_moder =
+ struct dim_cq_moder cur_moder =
net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
mlx5e_complete_dim_work(dim, cur_moder, rq->mdev, &rq->cq.mcq);
@@ -53,9 +53,9 @@ void mlx5e_rx_dim_work(struct work_struct *work)
void mlx5e_tx_dim_work(struct work_struct *work)
{
- struct net_dim *dim = container_of(work, struct net_dim, work);
+ struct dim *dim = container_of(work, struct dim, work);
struct mlx5e_txqsq *sq = container_of(dim, struct mlx5e_txqsq, dim);
- struct net_dim_cq_moder cur_moder =
+ struct dim_cq_moder cur_moder =
net_dim_get_tx_moderation(dim->mode, dim->profile_ix);
mlx5e_complete_dim_work(dim, cur_moder, sq->cq.mdev, &sq->cq.mcq);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
index dd764e0471f2..126ec4181286 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
@@ -32,6 +32,7 @@
#include "en.h"
#include "en/port.h"
+#include "en/xsk/umem.h"
#include "lib/clock.h"
void mlx5e_ethtool_get_drvinfo(struct mlx5e_priv *priv,
@@ -46,7 +47,7 @@ void mlx5e_ethtool_get_drvinfo(struct mlx5e_priv *priv,
"%d.%d.%04d (%.16s)",
fw_rev_maj(mdev), fw_rev_min(mdev), fw_rev_sub(mdev),
mdev->board_id);
- strlcpy(drvinfo->bus_info, pci_name(mdev->pdev),
+ strlcpy(drvinfo->bus_info, dev_name(mdev->device),
sizeof(drvinfo->bus_info));
}
@@ -388,8 +389,17 @@ static int mlx5e_set_ringparam(struct net_device *dev,
void mlx5e_ethtool_get_channels(struct mlx5e_priv *priv,
struct ethtool_channels *ch)
{
+ mutex_lock(&priv->state_lock);
+
ch->max_combined = mlx5e_get_netdev_max_channels(priv->netdev);
ch->combined_count = priv->channels.params.num_channels;
+ if (priv->xsk.refcnt) {
+ /* The upper half are XSK queues. */
+ ch->max_combined *= 2;
+ ch->combined_count *= 2;
+ }
+
+ mutex_unlock(&priv->state_lock);
}
static void mlx5e_get_channels(struct net_device *dev,
@@ -403,6 +413,7 @@ static void mlx5e_get_channels(struct net_device *dev,
int mlx5e_ethtool_set_channels(struct mlx5e_priv *priv,
struct ethtool_channels *ch)
{
+ struct mlx5e_params *cur_params = &priv->channels.params;
unsigned int count = ch->combined_count;
struct mlx5e_channels new_channels = {};
bool arfs_enabled;
@@ -414,16 +425,26 @@ int mlx5e_ethtool_set_channels(struct mlx5e_priv *priv,
return -EINVAL;
}
- if (priv->channels.params.num_channels == count)
+ if (cur_params->num_channels == count)
return 0;
mutex_lock(&priv->state_lock);
+ /* Don't allow changing the number of channels if there is an active
+ * XSK, because the numeration of the XSK and regular RQs will change.
+ */
+ if (priv->xsk.refcnt) {
+ err = -EINVAL;
+ netdev_err(priv->netdev, "%s: AF_XDP is active, cannot change the number of channels\n",
+ __func__);
+ goto out;
+ }
+
new_channels.params = priv->channels.params;
new_channels.params.num_channels = count;
if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) {
- priv->channels.params = new_channels.params;
+ *cur_params = new_channels.params;
if (!netif_is_rxfh_configured(priv->netdev))
mlx5e_build_default_indir_rqt(priv->rss_params.indirection_rqt,
MLX5E_INDIR_RQT_SIZE, count);
@@ -466,7 +487,7 @@ static int mlx5e_set_channels(struct net_device *dev,
int mlx5e_ethtool_get_coalesce(struct mlx5e_priv *priv,
struct ethtool_coalesce *coal)
{
- struct net_dim_cq_moder *rx_moder, *tx_moder;
+ struct dim_cq_moder *rx_moder, *tx_moder;
if (!MLX5_CAP_GEN(priv->mdev, cq_moderation))
return -EOPNOTSUPP;
@@ -521,7 +542,7 @@ mlx5e_set_priv_channels_coalesce(struct mlx5e_priv *priv, struct ethtool_coalesc
int mlx5e_ethtool_set_coalesce(struct mlx5e_priv *priv,
struct ethtool_coalesce *coal)
{
- struct net_dim_cq_moder *rx_moder, *tx_moder;
+ struct dim_cq_moder *rx_moder, *tx_moder;
struct mlx5_core_dev *mdev = priv->mdev;
struct mlx5e_channels new_channels = {};
int err = 0;
@@ -1867,40 +1888,6 @@ static u32 mlx5e_get_priv_flags(struct net_device *netdev)
return priv->channels.params.pflags;
}
-int mlx5e_ethtool_flash_device(struct mlx5e_priv *priv,
- struct ethtool_flash *flash)
-{
- struct mlx5_core_dev *mdev = priv->mdev;
- struct net_device *dev = priv->netdev;
- const struct firmware *fw;
- int err;
-
- if (flash->region != ETHTOOL_FLASH_ALL_REGIONS)
- return -EOPNOTSUPP;
-
- err = request_firmware_direct(&fw, flash->data, &dev->dev);
- if (err)
- return err;
-
- dev_hold(dev);
- rtnl_unlock();
-
- err = mlx5_firmware_flash(mdev, fw);
- release_firmware(fw);
-
- rtnl_lock();
- dev_put(dev);
- return err;
-}
-
-static int mlx5e_flash_device(struct net_device *dev,
- struct ethtool_flash *flash)
-{
- struct mlx5e_priv *priv = netdev_priv(dev);
-
- return mlx5e_ethtool_flash_device(priv, flash);
-}
-
#ifndef CONFIG_MLX5_EN_RXNFC
/* When CONFIG_MLX5_EN_RXNFC=n we only support ETHTOOL_GRXRINGS
* otherwise this function will be defined from en_fs_ethtool.c
@@ -1939,7 +1926,6 @@ const struct ethtool_ops mlx5e_ethtool_ops = {
#ifdef CONFIG_MLX5_EN_RXNFC
.set_rxnfc = mlx5e_set_rxnfc,
#endif
- .flash_device = mlx5e_flash_device,
.get_tunable = mlx5e_get_tunable,
.set_tunable = mlx5e_set_tunable,
.get_pauseparam = mlx5e_get_pauseparam,
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 4421c10f58ae..ea3a490b569a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c
@@ -32,6 +32,8 @@
#include <linux/mlx5/fs.h>
#include "en.h"
+#include "en/params.h"
+#include "en/xsk/umem.h"
struct mlx5e_ethtool_rule {
struct list_head list;
@@ -414,6 +416,14 @@ add_ethtool_flow_rule(struct mlx5e_priv *priv,
if (fs->ring_cookie == RX_CLS_FLOW_DISC) {
flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP;
} else {
+ struct mlx5e_params *params = &priv->channels.params;
+ enum mlx5e_rq_group group;
+ struct mlx5e_tir *tir;
+ u16 ix;
+
+ mlx5e_qid_get_ch_and_group(params, fs->ring_cookie, &ix, &group);
+ tir = group == MLX5E_RQ_GROUP_XSK ? priv->xsk_tir : priv->direct_tir;
+
dst = kzalloc(sizeof(*dst), GFP_KERNEL);
if (!dst) {
err = -ENOMEM;
@@ -421,12 +431,12 @@ add_ethtool_flow_rule(struct mlx5e_priv *priv,
}
dst->type = MLX5_FLOW_DESTINATION_TYPE_TIR;
- dst->tir_num = priv->direct_tir[fs->ring_cookie].tirn;
+ dst->tir_num = tir[ix].tirn;
flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
}
spec->match_criteria_enable = (!outer_header_zero(spec->match_criteria));
- flow_act.flow_tag = MLX5_FS_DEFAULT_FLOW_TAG;
+ spec->flow_context.flow_tag = MLX5_FS_DEFAULT_FLOW_TAG;
rule = mlx5_add_flow_rules(ft, spec, &flow_act, dst, dst ? 1 : 0);
if (IS_ERR(rule)) {
err = PTR_ERR(rule);
@@ -600,9 +610,9 @@ static int validate_flow(struct mlx5e_priv *priv,
if (fs->location >= MAX_NUM_OF_ETHTOOL_RULES)
return -ENOSPC;
- if (fs->ring_cookie >= priv->channels.params.num_channels &&
- fs->ring_cookie != RX_CLS_FLOW_DISC)
- return -EINVAL;
+ if (fs->ring_cookie != RX_CLS_FLOW_DISC)
+ if (!mlx5e_qid_validate(&priv->channels.params, fs->ring_cookie))
+ return -EINVAL;
switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) {
case ETHER_FLOW:
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index c65cefd84eda..47eea6b3a1c3 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -38,8 +38,10 @@
#include <linux/bpf.h>
#include <linux/if_bridge.h>
#include <net/page_pool.h>
+#include <net/xdp_sock.h>
#include "eswitch.h"
#include "en.h"
+#include "en/txrx.h"
#include "en_tc.h"
#include "en_rep.h"
#include "en_accel/ipsec.h"
@@ -56,35 +58,11 @@
#include "en/monitor_stats.h"
#include "en/reporter.h"
#include "en/params.h"
+#include "en/xsk/umem.h"
+#include "en/xsk/setup.h"
+#include "en/xsk/rx.h"
+#include "en/xsk/tx.h"
-struct mlx5e_rq_param {
- u32 rqc[MLX5_ST_SZ_DW(rqc)];
- struct mlx5_wq_param wq;
- struct mlx5e_rq_frags_info frags_info;
-};
-
-struct mlx5e_sq_param {
- u32 sqc[MLX5_ST_SZ_DW(sqc)];
- struct mlx5_wq_param wq;
- bool is_mpw;
-};
-
-struct mlx5e_cq_param {
- u32 cqc[MLX5_ST_SZ_DW(cqc)];
- struct mlx5_wq_param wq;
- u16 eq_ix;
- u8 cq_period_mode;
-};
-
-struct mlx5e_channel_param {
- struct mlx5e_rq_param rq;
- struct mlx5e_sq_param sq;
- struct mlx5e_sq_param xdp_sq;
- struct mlx5e_sq_param icosq;
- struct mlx5e_cq_param rx_cq;
- struct mlx5e_cq_param tx_cq;
- struct mlx5e_cq_param icosq_cq;
-};
bool mlx5e_check_fragmented_striding_rq_cap(struct mlx5_core_dev *mdev)
{
@@ -114,18 +92,31 @@ void mlx5e_init_rq_type_params(struct mlx5_core_dev *mdev,
mlx5_core_info(mdev, "MLX5E: StrdRq(%d) RqSz(%ld) StrdSz(%ld) RxCqeCmprss(%d)\n",
params->rq_wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ,
params->rq_wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ ?
- BIT(mlx5e_mpwqe_get_log_rq_size(params)) :
+ BIT(mlx5e_mpwqe_get_log_rq_size(params, NULL)) :
BIT(params->log_rq_mtu_frames),
- BIT(mlx5e_mpwqe_get_log_stride_size(mdev, params)),
+ BIT(mlx5e_mpwqe_get_log_stride_size(mdev, params, NULL)),
MLX5E_GET_PFLAG(params, MLX5E_PFLAG_RX_CQE_COMPRESS));
}
bool mlx5e_striding_rq_possible(struct mlx5_core_dev *mdev,
struct mlx5e_params *params)
{
- return mlx5e_check_fragmented_striding_rq_cap(mdev) &&
- !MLX5_IPSEC_DEV(mdev) &&
- !(params->xdp_prog && !mlx5e_rx_mpwqe_is_linear_skb(mdev, params));
+ if (!mlx5e_check_fragmented_striding_rq_cap(mdev))
+ return false;
+
+ if (MLX5_IPSEC_DEV(mdev))
+ return false;
+
+ if (params->xdp_prog) {
+ /* XSK params are not considered here. If striding RQ is in use,
+ * and an XSK is being opened, mlx5e_rx_mpwqe_is_linear_skb will
+ * be called with the known XSK params.
+ */
+ if (!mlx5e_rx_mpwqe_is_linear_skb(mdev, params, NULL))
+ return false;
+ }
+
+ return true;
}
void mlx5e_set_rq_type(struct mlx5_core_dev *mdev, struct mlx5e_params *params)
@@ -394,6 +385,8 @@ static void mlx5e_free_di_list(struct mlx5e_rq *rq)
static int mlx5e_alloc_rq(struct mlx5e_channel *c,
struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk,
+ struct xdp_umem *umem,
struct mlx5e_rq_param *rqp,
struct mlx5e_rq *rq)
{
@@ -401,6 +394,8 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
struct mlx5_core_dev *mdev = c->mdev;
void *rqc = rqp->rqc;
void *rqc_wq = MLX5_ADDR_OF(rqc, rqc, wq);
+ u32 num_xsk_frames = 0;
+ u32 rq_xdp_ix;
u32 pool_size;
int wq_sz;
int err;
@@ -417,7 +412,13 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
rq->ix = c->ix;
rq->mdev = mdev;
rq->hw_mtu = MLX5E_SW2HW_MTU(params, params->sw_mtu);
- rq->stats = &c->priv->channel_stats[c->ix].rq;
+ rq->xdpsq = &c->rq_xdpsq;
+ rq->umem = umem;
+
+ if (rq->umem)
+ rq->stats = &c->priv->channel_stats[c->ix].xskrq;
+ else
+ rq->stats = &c->priv->channel_stats[c->ix].rq;
rq->xdp_prog = params->xdp_prog ? bpf_prog_inc(params->xdp_prog) : NULL;
if (IS_ERR(rq->xdp_prog)) {
@@ -426,12 +427,16 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
goto err_rq_wq_destroy;
}
- err = xdp_rxq_info_reg(&rq->xdp_rxq, rq->netdev, rq->ix);
+ rq_xdp_ix = rq->ix;
+ if (xsk)
+ rq_xdp_ix += params->num_channels * MLX5E_RQ_GROUP_XSK;
+ err = xdp_rxq_info_reg(&rq->xdp_rxq, rq->netdev, rq_xdp_ix);
if (err < 0)
goto err_rq_wq_destroy;
rq->buff.map_dir = rq->xdp_prog ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE;
- rq->buff.headroom = mlx5e_get_rq_headroom(mdev, params);
+ rq->buff.headroom = mlx5e_get_rq_headroom(mdev, params, xsk);
+ rq->buff.umem_headroom = xsk ? xsk->headroom : 0;
pool_size = 1 << params->log_rq_mtu_frames;
switch (rq->wq_type) {
@@ -445,7 +450,12 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
wq_sz = mlx5_wq_ll_get_size(&rq->mpwqe.wq);
- pool_size = MLX5_MPWRQ_PAGES_PER_WQE << mlx5e_mpwqe_get_log_rq_size(params);
+ if (xsk)
+ num_xsk_frames = wq_sz <<
+ mlx5e_mpwqe_get_log_num_strides(mdev, params, xsk);
+
+ pool_size = MLX5_MPWRQ_PAGES_PER_WQE <<
+ mlx5e_mpwqe_get_log_rq_size(params, xsk);
rq->post_wqes = mlx5e_post_rx_mpwqes;
rq->dealloc_wqe = mlx5e_dealloc_rx_mpwqe;
@@ -464,12 +474,15 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
goto err_rq_wq_destroy;
}
- rq->mpwqe.skb_from_cqe_mpwrq =
- mlx5e_rx_mpwqe_is_linear_skb(mdev, params) ?
- mlx5e_skb_from_cqe_mpwrq_linear :
- mlx5e_skb_from_cqe_mpwrq_nonlinear;
- rq->mpwqe.log_stride_sz = mlx5e_mpwqe_get_log_stride_size(mdev, params);
- rq->mpwqe.num_strides = BIT(mlx5e_mpwqe_get_log_num_strides(mdev, params));
+ rq->mpwqe.skb_from_cqe_mpwrq = xsk ?
+ mlx5e_xsk_skb_from_cqe_mpwrq_linear :
+ mlx5e_rx_mpwqe_is_linear_skb(mdev, params, NULL) ?
+ mlx5e_skb_from_cqe_mpwrq_linear :
+ mlx5e_skb_from_cqe_mpwrq_nonlinear;
+
+ rq->mpwqe.log_stride_sz = mlx5e_mpwqe_get_log_stride_size(mdev, params, xsk);
+ rq->mpwqe.num_strides =
+ BIT(mlx5e_mpwqe_get_log_num_strides(mdev, params, xsk));
err = mlx5e_create_rq_umr_mkey(mdev, rq);
if (err)
@@ -490,6 +503,9 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
wq_sz = mlx5_wq_cyc_get_size(&rq->wqe.wq);
+ if (xsk)
+ num_xsk_frames = wq_sz << rq->wqe.info.log_num_frags;
+
rq->wqe.info = rqp->frags_info;
rq->wqe.frags =
kvzalloc_node(array_size(sizeof(*rq->wqe.frags),
@@ -503,6 +519,7 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
err = mlx5e_init_di_list(rq, wq_sz, c->cpu);
if (err)
goto err_free;
+
rq->post_wqes = mlx5e_post_rx_wqes;
rq->dealloc_wqe = mlx5e_dealloc_rx_wqe;
@@ -518,33 +535,49 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
goto err_free;
}
- rq->wqe.skb_from_cqe = mlx5e_rx_is_linear_skb(params) ?
- mlx5e_skb_from_cqe_linear :
- mlx5e_skb_from_cqe_nonlinear;
+ rq->wqe.skb_from_cqe = xsk ?
+ mlx5e_xsk_skb_from_cqe_linear :
+ mlx5e_rx_is_linear_skb(params, NULL) ?
+ mlx5e_skb_from_cqe_linear :
+ mlx5e_skb_from_cqe_nonlinear;
rq->mkey_be = c->mkey_be;
}
- /* Create a page_pool and register it with rxq */
- pp_params.order = 0;
- pp_params.flags = 0; /* No-internal DMA mapping in page_pool */
- pp_params.pool_size = pool_size;
- pp_params.nid = cpu_to_node(c->cpu);
- pp_params.dev = c->pdev;
- pp_params.dma_dir = rq->buff.map_dir;
-
- /* page_pool can be used even when there is no rq->xdp_prog,
- * given page_pool does not handle DMA mapping there is no
- * required state to clear. And page_pool gracefully handle
- * elevated refcnt.
- */
- rq->page_pool = page_pool_create(&pp_params);
- if (IS_ERR(rq->page_pool)) {
- err = PTR_ERR(rq->page_pool);
- rq->page_pool = NULL;
- goto err_free;
+ if (xsk) {
+ err = mlx5e_xsk_resize_reuseq(umem, num_xsk_frames);
+ if (unlikely(err)) {
+ mlx5_core_err(mdev, "Unable to allocate the Reuse Ring for %u frames\n",
+ num_xsk_frames);
+ goto err_free;
+ }
+
+ rq->zca.free = mlx5e_xsk_zca_free;
+ err = xdp_rxq_info_reg_mem_model(&rq->xdp_rxq,
+ MEM_TYPE_ZERO_COPY,
+ &rq->zca);
+ } else {
+ /* Create a page_pool and register it with rxq */
+ pp_params.order = 0;
+ pp_params.flags = 0; /* No-internal DMA mapping in page_pool */
+ pp_params.pool_size = pool_size;
+ pp_params.nid = cpu_to_node(c->cpu);
+ pp_params.dev = c->pdev;
+ pp_params.dma_dir = rq->buff.map_dir;
+
+ /* page_pool can be used even when there is no rq->xdp_prog,
+ * given page_pool does not handle DMA mapping there is no
+ * required state to clear. And page_pool gracefully handle
+ * elevated refcnt.
+ */
+ rq->page_pool = page_pool_create(&pp_params);
+ if (IS_ERR(rq->page_pool)) {
+ err = PTR_ERR(rq->page_pool);
+ rq->page_pool = NULL;
+ goto err_free;
+ }
+ err = xdp_rxq_info_reg_mem_model(&rq->xdp_rxq,
+ MEM_TYPE_PAGE_POOL, rq->page_pool);
}
- err = xdp_rxq_info_reg_mem_model(&rq->xdp_rxq,
- MEM_TYPE_PAGE_POOL, rq->page_pool);
if (err)
goto err_free;
@@ -584,11 +617,11 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
switch (params->rx_cq_moderation.cq_period_mode) {
case MLX5_CQ_PERIOD_MODE_START_FROM_CQE:
- rq->dim.mode = NET_DIM_CQ_PERIOD_MODE_START_FROM_CQE;
+ rq->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_CQE;
break;
case MLX5_CQ_PERIOD_MODE_START_FROM_EQE:
default:
- rq->dim.mode = NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE;
+ rq->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
}
rq->page_cache.head = 0;
@@ -611,8 +644,7 @@ err_rq_wq_destroy:
if (rq->xdp_prog)
bpf_prog_put(rq->xdp_prog);
xdp_rxq_info_unreg(&rq->xdp_rxq);
- if (rq->page_pool)
- page_pool_destroy(rq->page_pool);
+ page_pool_destroy(rq->page_pool);
mlx5_wq_destroy(&rq->wq_ctrl);
return err;
@@ -625,10 +657,6 @@ static void mlx5e_free_rq(struct mlx5e_rq *rq)
if (rq->xdp_prog)
bpf_prog_put(rq->xdp_prog);
- xdp_rxq_info_unreg(&rq->xdp_rxq);
- if (rq->page_pool)
- page_pool_destroy(rq->page_pool);
-
switch (rq->wq_type) {
case MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ:
kvfree(rq->mpwqe.info);
@@ -643,8 +671,15 @@ static void mlx5e_free_rq(struct mlx5e_rq *rq)
i = (i + 1) & (MLX5E_CACHE_SIZE - 1)) {
struct mlx5e_dma_info *dma_info = &rq->page_cache.page_cache[i];
- mlx5e_page_release(rq, dma_info, false);
+ /* With AF_XDP, page_cache is not used, so this loop is not
+ * entered, and it's safe to call mlx5e_page_release_dynamic
+ * directly.
+ */
+ mlx5e_page_release_dynamic(rq, dma_info, false);
}
+
+ xdp_rxq_info_unreg(&rq->xdp_rxq);
+ page_pool_destroy(rq->page_pool);
mlx5_wq_destroy(&rq->wq_ctrl);
}
@@ -778,7 +813,7 @@ static void mlx5e_destroy_rq(struct mlx5e_rq *rq)
mlx5_core_destroy_rq(rq->mdev, rq->rqn);
}
-static int mlx5e_wait_for_min_rx_wqes(struct mlx5e_rq *rq, int wait_time)
+int mlx5e_wait_for_min_rx_wqes(struct mlx5e_rq *rq, int wait_time)
{
unsigned long exp_time = jiffies + msecs_to_jiffies(wait_time);
struct mlx5e_channel *c = rq->channel;
@@ -836,14 +871,13 @@ static void mlx5e_free_rx_descs(struct mlx5e_rq *rq)
}
-static int mlx5e_open_rq(struct mlx5e_channel *c,
- struct mlx5e_params *params,
- struct mlx5e_rq_param *param,
- struct mlx5e_rq *rq)
+int mlx5e_open_rq(struct mlx5e_channel *c, struct mlx5e_params *params,
+ struct mlx5e_rq_param *param, struct mlx5e_xsk_param *xsk,
+ struct xdp_umem *umem, struct mlx5e_rq *rq)
{
int err;
- err = mlx5e_alloc_rq(c, params, param, rq);
+ err = mlx5e_alloc_rq(c, params, xsk, umem, param, rq);
if (err)
return err;
@@ -855,6 +889,9 @@ static int mlx5e_open_rq(struct mlx5e_channel *c,
if (err)
goto err_destroy_rq;
+ if (MLX5_CAP_ETH(c->mdev, cqe_checksum_full))
+ __set_bit(MLX5E_RQ_STATE_CSUM_FULL, &c->rq.state);
+
if (params->rx_dim_enabled)
__set_bit(MLX5E_RQ_STATE_AM, &c->rq.state);
@@ -881,13 +918,13 @@ static void mlx5e_activate_rq(struct mlx5e_rq *rq)
mlx5e_trigger_irq(&rq->channel->icosq);
}
-static void mlx5e_deactivate_rq(struct mlx5e_rq *rq)
+void mlx5e_deactivate_rq(struct mlx5e_rq *rq)
{
clear_bit(MLX5E_RQ_STATE_ENABLED, &rq->state);
napi_synchronize(&rq->channel->napi); /* prevent mlx5e_post_rx_wqes */
}
-static void mlx5e_close_rq(struct mlx5e_rq *rq)
+void mlx5e_close_rq(struct mlx5e_rq *rq)
{
cancel_work_sync(&rq->dim.work);
mlx5e_destroy_rq(rq);
@@ -940,6 +977,7 @@ static int mlx5e_alloc_xdpsq_db(struct mlx5e_xdpsq *sq, int numa)
static int mlx5e_alloc_xdpsq(struct mlx5e_channel *c,
struct mlx5e_params *params,
+ struct xdp_umem *umem,
struct mlx5e_sq_param *param,
struct mlx5e_xdpsq *sq,
bool is_redirect)
@@ -955,9 +993,13 @@ static int mlx5e_alloc_xdpsq(struct mlx5e_channel *c,
sq->uar_map = mdev->mlx5e_res.bfreg.map;
sq->min_inline_mode = params->tx_min_inline_mode;
sq->hw_mtu = MLX5E_SW2HW_MTU(params, params->sw_mtu);
- sq->stats = is_redirect ?
- &c->priv->channel_stats[c->ix].xdpsq :
- &c->priv->channel_stats[c->ix].rq_xdpsq;
+ sq->umem = umem;
+
+ sq->stats = sq->umem ?
+ &c->priv->channel_stats[c->ix].xsksq :
+ is_redirect ?
+ &c->priv->channel_stats[c->ix].xdpsq :
+ &c->priv->channel_stats[c->ix].rq_xdpsq;
param->wq.db_numa_node = cpu_to_node(c->cpu);
err = mlx5_wq_cyc_create(mdev, &param->wq, sqc_wq, wq, &sq->wq_ctrl);
@@ -1082,15 +1124,19 @@ static int mlx5e_alloc_txqsq(struct mlx5e_channel *c,
sq->clock = &mdev->clock;
sq->mkey_be = c->mkey_be;
sq->channel = c;
+ sq->ch_ix = c->ix;
sq->txq_ix = txq_ix;
sq->uar_map = mdev->mlx5e_res.bfreg.map;
sq->min_inline_mode = params->tx_min_inline_mode;
sq->stats = &c->priv->channel_stats[c->ix].sq[tc];
+ sq->stop_room = MLX5E_SQ_STOP_ROOM;
INIT_WORK(&sq->recover_work, mlx5e_tx_err_cqe_work);
if (MLX5_IPSEC_DEV(c->priv->mdev))
set_bit(MLX5E_SQ_STATE_IPSEC, &sq->state);
- if (mlx5_accel_is_tls_device(c->priv->mdev))
+ if (mlx5_accel_is_tls_device(c->priv->mdev)) {
set_bit(MLX5E_SQ_STATE_TLS, &sq->state);
+ sq->stop_room += MLX5E_SQ_TLS_ROOM;
+ }
param->wq.db_numa_node = cpu_to_node(c->cpu);
err = mlx5_wq_cyc_create(mdev, &param->wq, sqc_wq, wq, &sq->wq_ctrl);
@@ -1336,10 +1382,8 @@ static void mlx5e_tx_err_cqe_work(struct work_struct *recover_work)
mlx5e_tx_reporter_err_cqe(sq);
}
-static int mlx5e_open_icosq(struct mlx5e_channel *c,
- struct mlx5e_params *params,
- struct mlx5e_sq_param *param,
- struct mlx5e_icosq *sq)
+int mlx5e_open_icosq(struct mlx5e_channel *c, struct mlx5e_params *params,
+ struct mlx5e_sq_param *param, struct mlx5e_icosq *sq)
{
struct mlx5e_create_sq_param csp = {};
int err;
@@ -1365,7 +1409,7 @@ err_free_icosq:
return err;
}
-static void mlx5e_close_icosq(struct mlx5e_icosq *sq)
+void mlx5e_close_icosq(struct mlx5e_icosq *sq)
{
struct mlx5e_channel *c = sq->channel;
@@ -1376,16 +1420,14 @@ static void mlx5e_close_icosq(struct mlx5e_icosq *sq)
mlx5e_free_icosq(sq);
}
-static int mlx5e_open_xdpsq(struct mlx5e_channel *c,
- struct mlx5e_params *params,
- struct mlx5e_sq_param *param,
- struct mlx5e_xdpsq *sq,
- bool is_redirect)
+int mlx5e_open_xdpsq(struct mlx5e_channel *c, struct mlx5e_params *params,
+ struct mlx5e_sq_param *param, struct xdp_umem *umem,
+ struct mlx5e_xdpsq *sq, bool is_redirect)
{
struct mlx5e_create_sq_param csp = {};
int err;
- err = mlx5e_alloc_xdpsq(c, params, param, sq, is_redirect);
+ err = mlx5e_alloc_xdpsq(c, params, umem, param, sq, is_redirect);
if (err)
return err;
@@ -1439,7 +1481,7 @@ err_free_xdpsq:
return err;
}
-static void mlx5e_close_xdpsq(struct mlx5e_xdpsq *sq, struct mlx5e_rq *rq)
+void mlx5e_close_xdpsq(struct mlx5e_xdpsq *sq)
{
struct mlx5e_channel *c = sq->channel;
@@ -1447,7 +1489,7 @@ static void mlx5e_close_xdpsq(struct mlx5e_xdpsq *sq, struct mlx5e_rq *rq)
napi_synchronize(&c->napi);
mlx5e_destroy_sq(c->mdev, sq->sqn);
- mlx5e_free_xdpsq_descs(sq, rq);
+ mlx5e_free_xdpsq_descs(sq);
mlx5e_free_xdpsq(sq);
}
@@ -1517,6 +1559,7 @@ static void mlx5e_free_cq(struct mlx5e_cq *cq)
static int mlx5e_create_cq(struct mlx5e_cq *cq, struct mlx5e_cq_param *param)
{
+ u32 out[MLX5_ST_SZ_DW(create_cq_out)];
struct mlx5_core_dev *mdev = cq->mdev;
struct mlx5_core_cq *mcq = &cq->mcq;
@@ -1551,7 +1594,7 @@ static int mlx5e_create_cq(struct mlx5e_cq *cq, struct mlx5e_cq_param *param)
MLX5_ADAPTER_PAGE_SHIFT);
MLX5_SET64(cqc, cqc, dbr_addr, cq->wq_ctrl.db.dma);
- err = mlx5_core_create_cq(mdev, mcq, in, inlen);
+ err = mlx5_core_create_cq(mdev, mcq, in, inlen, out, sizeof(out));
kvfree(in);
@@ -1568,10 +1611,8 @@ static void mlx5e_destroy_cq(struct mlx5e_cq *cq)
mlx5_core_destroy_cq(cq->mdev, &cq->mcq);
}
-static int mlx5e_open_cq(struct mlx5e_channel *c,
- struct net_dim_cq_moder moder,
- struct mlx5e_cq_param *param,
- struct mlx5e_cq *cq)
+int mlx5e_open_cq(struct mlx5e_channel *c, struct dim_cq_moder moder,
+ struct mlx5e_cq_param *param, struct mlx5e_cq *cq)
{
struct mlx5_core_dev *mdev = c->mdev;
int err;
@@ -1594,7 +1635,7 @@ err_free_cq:
return err;
}
-static void mlx5e_close_cq(struct mlx5e_cq *cq)
+void mlx5e_close_cq(struct mlx5e_cq *cq)
{
mlx5e_destroy_cq(cq);
mlx5e_free_cq(cq);
@@ -1768,49 +1809,16 @@ static void mlx5e_free_xps_cpumask(struct mlx5e_channel *c)
free_cpumask_var(c->xps_cpumask);
}
-static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix,
- struct mlx5e_params *params,
- struct mlx5e_channel_param *cparam,
- struct mlx5e_channel **cp)
+static int mlx5e_open_queues(struct mlx5e_channel *c,
+ struct mlx5e_params *params,
+ struct mlx5e_channel_param *cparam)
{
- int cpu = cpumask_first(mlx5_comp_irq_get_affinity_mask(priv->mdev, ix));
- struct net_dim_cq_moder icocq_moder = {0, 0};
- struct net_device *netdev = priv->netdev;
- struct mlx5e_channel *c;
- unsigned int irq;
+ struct dim_cq_moder icocq_moder = {0, 0};
int err;
- int eqn;
-
- err = mlx5_vector2eqn(priv->mdev, ix, &eqn, &irq);
- if (err)
- return err;
-
- c = kvzalloc_node(sizeof(*c), GFP_KERNEL, cpu_to_node(cpu));
- if (!c)
- return -ENOMEM;
-
- c->priv = priv;
- c->mdev = priv->mdev;
- c->tstamp = &priv->tstamp;
- c->ix = ix;
- c->cpu = cpu;
- c->pdev = priv->mdev->device;
- c->netdev = priv->netdev;
- c->mkey_be = cpu_to_be32(priv->mdev->mlx5e_res.mkey.key);
- c->num_tc = params->num_tc;
- c->xdp = !!params->xdp_prog;
- c->stats = &priv->channel_stats[ix].ch;
- c->irq_desc = irq_to_desc(irq);
-
- err = mlx5e_alloc_xps_cpumask(c, params);
- if (err)
- goto err_free_channel;
-
- netif_napi_add(netdev, &c->napi, mlx5e_napi_poll, 64);
err = mlx5e_open_cq(c, icocq_moder, &cparam->icosq_cq, &c->icosq.cq);
if (err)
- goto err_napi_del;
+ return err;
err = mlx5e_open_tx_cqs(c, params, cparam);
if (err)
@@ -1826,7 +1834,7 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix,
/* XDP SQ CQ params are same as normal TXQ sq CQ params */
err = c->xdp ? mlx5e_open_cq(c, params->tx_cq_moderation,
- &cparam->tx_cq, &c->rq.xdpsq.cq) : 0;
+ &cparam->tx_cq, &c->rq_xdpsq.cq) : 0;
if (err)
goto err_close_rx_cq;
@@ -1840,20 +1848,21 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix,
if (err)
goto err_close_icosq;
- err = c->xdp ? mlx5e_open_xdpsq(c, params, &cparam->xdp_sq, &c->rq.xdpsq, false) : 0;
- if (err)
- goto err_close_sqs;
+ if (c->xdp) {
+ err = mlx5e_open_xdpsq(c, params, &cparam->xdp_sq, NULL,
+ &c->rq_xdpsq, false);
+ if (err)
+ goto err_close_sqs;
+ }
- err = mlx5e_open_rq(c, params, &cparam->rq, &c->rq);
+ err = mlx5e_open_rq(c, params, &cparam->rq, NULL, NULL, &c->rq);
if (err)
goto err_close_xdp_sq;
- err = mlx5e_open_xdpsq(c, params, &cparam->xdp_sq, &c->xdpsq, true);
+ err = mlx5e_open_xdpsq(c, params, &cparam->xdp_sq, NULL, &c->xdpsq, true);
if (err)
goto err_close_rq;
- *cp = c;
-
return 0;
err_close_rq:
@@ -1861,7 +1870,7 @@ err_close_rq:
err_close_xdp_sq:
if (c->xdp)
- mlx5e_close_xdpsq(&c->rq.xdpsq, &c->rq);
+ mlx5e_close_xdpsq(&c->rq_xdpsq);
err_close_sqs:
mlx5e_close_sqs(c);
@@ -1871,8 +1880,9 @@ err_close_icosq:
err_disable_napi:
napi_disable(&c->napi);
+
if (c->xdp)
- mlx5e_close_cq(&c->rq.xdpsq.cq);
+ mlx5e_close_cq(&c->rq_xdpsq.cq);
err_close_rx_cq:
mlx5e_close_cq(&c->rq.cq);
@@ -1886,6 +1896,85 @@ err_close_tx_cqs:
err_close_icosq_cq:
mlx5e_close_cq(&c->icosq.cq);
+ return err;
+}
+
+static void mlx5e_close_queues(struct mlx5e_channel *c)
+{
+ mlx5e_close_xdpsq(&c->xdpsq);
+ mlx5e_close_rq(&c->rq);
+ if (c->xdp)
+ mlx5e_close_xdpsq(&c->rq_xdpsq);
+ mlx5e_close_sqs(c);
+ mlx5e_close_icosq(&c->icosq);
+ napi_disable(&c->napi);
+ if (c->xdp)
+ mlx5e_close_cq(&c->rq_xdpsq.cq);
+ mlx5e_close_cq(&c->rq.cq);
+ mlx5e_close_cq(&c->xdpsq.cq);
+ mlx5e_close_tx_cqs(c);
+ mlx5e_close_cq(&c->icosq.cq);
+}
+
+static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix,
+ struct mlx5e_params *params,
+ struct mlx5e_channel_param *cparam,
+ struct xdp_umem *umem,
+ struct mlx5e_channel **cp)
+{
+ int cpu = cpumask_first(mlx5_comp_irq_get_affinity_mask(priv->mdev, ix));
+ struct net_device *netdev = priv->netdev;
+ struct mlx5e_xsk_param xsk;
+ struct mlx5e_channel *c;
+ unsigned int irq;
+ int err;
+ int eqn;
+
+ err = mlx5_vector2eqn(priv->mdev, ix, &eqn, &irq);
+ if (err)
+ return err;
+
+ c = kvzalloc_node(sizeof(*c), GFP_KERNEL, cpu_to_node(cpu));
+ if (!c)
+ return -ENOMEM;
+
+ c->priv = priv;
+ c->mdev = priv->mdev;
+ c->tstamp = &priv->tstamp;
+ c->ix = ix;
+ c->cpu = cpu;
+ c->pdev = priv->mdev->device;
+ c->netdev = priv->netdev;
+ c->mkey_be = cpu_to_be32(priv->mdev->mlx5e_res.mkey.key);
+ c->num_tc = params->num_tc;
+ c->xdp = !!params->xdp_prog;
+ c->stats = &priv->channel_stats[ix].ch;
+ c->irq_desc = irq_to_desc(irq);
+
+ err = mlx5e_alloc_xps_cpumask(c, params);
+ if (err)
+ goto err_free_channel;
+
+ netif_napi_add(netdev, &c->napi, mlx5e_napi_poll, 64);
+
+ err = mlx5e_open_queues(c, params, cparam);
+ if (unlikely(err))
+ goto err_napi_del;
+
+ if (umem) {
+ mlx5e_build_xsk_param(umem, &xsk);
+ err = mlx5e_open_xsk(priv, params, &xsk, umem, c);
+ if (unlikely(err))
+ goto err_close_queues;
+ }
+
+ *cp = c;
+
+ return 0;
+
+err_close_queues:
+ mlx5e_close_queues(c);
+
err_napi_del:
netif_napi_del(&c->napi);
mlx5e_free_xps_cpumask(c);
@@ -1904,12 +1993,18 @@ static void mlx5e_activate_channel(struct mlx5e_channel *c)
mlx5e_activate_txqsq(&c->sq[tc]);
mlx5e_activate_rq(&c->rq);
netif_set_xps_queue(c->netdev, c->xps_cpumask, c->ix);
+
+ if (test_bit(MLX5E_CHANNEL_STATE_XSK, c->state))
+ mlx5e_activate_xsk(c);
}
static void mlx5e_deactivate_channel(struct mlx5e_channel *c)
{
int tc;
+ if (test_bit(MLX5E_CHANNEL_STATE_XSK, c->state))
+ mlx5e_deactivate_xsk(c);
+
mlx5e_deactivate_rq(&c->rq);
for (tc = 0; tc < c->num_tc; tc++)
mlx5e_deactivate_txqsq(&c->sq[tc]);
@@ -1917,19 +2012,9 @@ static void mlx5e_deactivate_channel(struct mlx5e_channel *c)
static void mlx5e_close_channel(struct mlx5e_channel *c)
{
- mlx5e_close_xdpsq(&c->xdpsq, NULL);
- mlx5e_close_rq(&c->rq);
- if (c->xdp)
- mlx5e_close_xdpsq(&c->rq.xdpsq, &c->rq);
- mlx5e_close_sqs(c);
- mlx5e_close_icosq(&c->icosq);
- napi_disable(&c->napi);
- if (c->xdp)
- mlx5e_close_cq(&c->rq.xdpsq.cq);
- mlx5e_close_cq(&c->rq.cq);
- mlx5e_close_cq(&c->xdpsq.cq);
- mlx5e_close_tx_cqs(c);
- mlx5e_close_cq(&c->icosq.cq);
+ if (test_bit(MLX5E_CHANNEL_STATE_XSK, c->state))
+ mlx5e_close_xsk(c);
+ mlx5e_close_queues(c);
netif_napi_del(&c->napi);
mlx5e_free_xps_cpumask(c);
@@ -1940,6 +2025,7 @@ static void mlx5e_close_channel(struct mlx5e_channel *c)
static void mlx5e_build_rq_frags_info(struct mlx5_core_dev *mdev,
struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk,
struct mlx5e_rq_frags_info *info)
{
u32 byte_count = MLX5E_SW2HW_MTU(params, params->sw_mtu);
@@ -1952,10 +2038,10 @@ static void mlx5e_build_rq_frags_info(struct mlx5_core_dev *mdev,
byte_count += MLX5E_METADATA_ETHER_LEN;
#endif
- if (mlx5e_rx_is_linear_skb(params)) {
+ if (mlx5e_rx_is_linear_skb(params, xsk)) {
int frag_stride;
- frag_stride = mlx5e_rx_get_linear_frag_sz(params);
+ frag_stride = mlx5e_rx_get_linear_frag_sz(params, xsk);
frag_stride = roundup_pow_of_two(frag_stride);
info->arr[0].frag_size = byte_count;
@@ -2013,9 +2099,10 @@ static u8 mlx5e_get_rq_log_wq_sz(void *rqc)
return MLX5_GET(wq, wq, log_wq_sz);
}
-static void mlx5e_build_rq_param(struct mlx5e_priv *priv,
- struct mlx5e_params *params,
- struct mlx5e_rq_param *param)
+void mlx5e_build_rq_param(struct mlx5e_priv *priv,
+ struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk,
+ struct mlx5e_rq_param *param)
{
struct mlx5_core_dev *mdev = priv->mdev;
void *rqc = param->rqc;
@@ -2025,16 +2112,16 @@ static void mlx5e_build_rq_param(struct mlx5e_priv *priv,
switch (params->rq_wq_type) {
case MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ:
MLX5_SET(wq, wq, log_wqe_num_of_strides,
- mlx5e_mpwqe_get_log_num_strides(mdev, params) -
+ mlx5e_mpwqe_get_log_num_strides(mdev, params, xsk) -
MLX5_MPWQE_LOG_NUM_STRIDES_BASE);
MLX5_SET(wq, wq, log_wqe_stride_size,
- mlx5e_mpwqe_get_log_stride_size(mdev, params) -
+ mlx5e_mpwqe_get_log_stride_size(mdev, params, xsk) -
MLX5_MPWQE_LOG_STRIDE_SZ_BASE);
- MLX5_SET(wq, wq, log_wq_sz, mlx5e_mpwqe_get_log_rq_size(params));
+ MLX5_SET(wq, wq, log_wq_sz, mlx5e_mpwqe_get_log_rq_size(params, xsk));
break;
default: /* MLX5_WQ_TYPE_CYCLIC */
MLX5_SET(wq, wq, log_wq_sz, params->log_rq_mtu_frames);
- mlx5e_build_rq_frags_info(mdev, params, &param->frags_info);
+ mlx5e_build_rq_frags_info(mdev, params, xsk, &param->frags_info);
ndsegs = param->frags_info.num_frags;
}
@@ -2065,8 +2152,8 @@ static void mlx5e_build_drop_rq_param(struct mlx5e_priv *priv,
param->wq.buf_numa_node = dev_to_node(mdev->device);
}
-static void mlx5e_build_sq_param_common(struct mlx5e_priv *priv,
- struct mlx5e_sq_param *param)
+void mlx5e_build_sq_param_common(struct mlx5e_priv *priv,
+ struct mlx5e_sq_param *param)
{
void *sqc = param->sqc;
void *wq = MLX5_ADDR_OF(sqc, sqc, wq);
@@ -2102,9 +2189,10 @@ static void mlx5e_build_common_cq_param(struct mlx5e_priv *priv,
MLX5_SET(cqc, cqc, cqe_sz, CQE_STRIDE_128_PAD);
}
-static void mlx5e_build_rx_cq_param(struct mlx5e_priv *priv,
- struct mlx5e_params *params,
- struct mlx5e_cq_param *param)
+void mlx5e_build_rx_cq_param(struct mlx5e_priv *priv,
+ struct mlx5e_params *params,
+ struct mlx5e_xsk_param *xsk,
+ struct mlx5e_cq_param *param)
{
struct mlx5_core_dev *mdev = priv->mdev;
void *cqc = param->cqc;
@@ -2112,8 +2200,8 @@ static void mlx5e_build_rx_cq_param(struct mlx5e_priv *priv,
switch (params->rq_wq_type) {
case MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ:
- log_cq_size = mlx5e_mpwqe_get_log_rq_size(params) +
- mlx5e_mpwqe_get_log_num_strides(mdev, params);
+ log_cq_size = mlx5e_mpwqe_get_log_rq_size(params, xsk) +
+ mlx5e_mpwqe_get_log_num_strides(mdev, params, xsk);
break;
default: /* MLX5_WQ_TYPE_CYCLIC */
log_cq_size = params->log_rq_mtu_frames;
@@ -2129,9 +2217,9 @@ static void mlx5e_build_rx_cq_param(struct mlx5e_priv *priv,
param->cq_period_mode = params->rx_cq_moderation.cq_period_mode;
}
-static void mlx5e_build_tx_cq_param(struct mlx5e_priv *priv,
- struct mlx5e_params *params,
- struct mlx5e_cq_param *param)
+void mlx5e_build_tx_cq_param(struct mlx5e_priv *priv,
+ struct mlx5e_params *params,
+ struct mlx5e_cq_param *param)
{
void *cqc = param->cqc;
@@ -2141,9 +2229,9 @@ static void mlx5e_build_tx_cq_param(struct mlx5e_priv *priv,
param->cq_period_mode = params->tx_cq_moderation.cq_period_mode;
}
-static void mlx5e_build_ico_cq_param(struct mlx5e_priv *priv,
- u8 log_wq_size,
- struct mlx5e_cq_param *param)
+void mlx5e_build_ico_cq_param(struct mlx5e_priv *priv,
+ u8 log_wq_size,
+ struct mlx5e_cq_param *param)
{
void *cqc = param->cqc;
@@ -2151,12 +2239,12 @@ static void mlx5e_build_ico_cq_param(struct mlx5e_priv *priv,
mlx5e_build_common_cq_param(priv, param);
- param->cq_period_mode = NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE;
+ param->cq_period_mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
}
-static void mlx5e_build_icosq_param(struct mlx5e_priv *priv,
- u8 log_wq_size,
- struct mlx5e_sq_param *param)
+void mlx5e_build_icosq_param(struct mlx5e_priv *priv,
+ u8 log_wq_size,
+ struct mlx5e_sq_param *param)
{
void *sqc = param->sqc;
void *wq = MLX5_ADDR_OF(sqc, sqc, wq);
@@ -2167,9 +2255,9 @@ static void mlx5e_build_icosq_param(struct mlx5e_priv *priv,
MLX5_SET(sqc, sqc, reg_umr, MLX5_CAP_ETH(priv->mdev, reg_umr_sq));
}
-static void mlx5e_build_xdpsq_param(struct mlx5e_priv *priv,
- struct mlx5e_params *params,
- struct mlx5e_sq_param *param)
+void mlx5e_build_xdpsq_param(struct mlx5e_priv *priv,
+ struct mlx5e_params *params,
+ struct mlx5e_sq_param *param)
{
void *sqc = param->sqc;
void *wq = MLX5_ADDR_OF(sqc, sqc, wq);
@@ -2197,14 +2285,14 @@ static void mlx5e_build_channel_param(struct mlx5e_priv *priv,
{
u8 icosq_log_wq_sz;
- mlx5e_build_rq_param(priv, params, &cparam->rq);
+ mlx5e_build_rq_param(priv, params, NULL, &cparam->rq);
icosq_log_wq_sz = mlx5e_build_icosq_log_wq_sz(params, &cparam->rq);
mlx5e_build_sq_param(priv, params, &cparam->sq);
mlx5e_build_xdpsq_param(priv, params, &cparam->xdp_sq);
mlx5e_build_icosq_param(priv, icosq_log_wq_sz, &cparam->icosq);
- mlx5e_build_rx_cq_param(priv, params, &cparam->rx_cq);
+ mlx5e_build_rx_cq_param(priv, params, NULL, &cparam->rx_cq);
mlx5e_build_tx_cq_param(priv, params, &cparam->tx_cq);
mlx5e_build_ico_cq_param(priv, icosq_log_wq_sz, &cparam->icosq_cq);
}
@@ -2225,7 +2313,12 @@ int mlx5e_open_channels(struct mlx5e_priv *priv,
mlx5e_build_channel_param(priv, &chs->params, cparam);
for (i = 0; i < chs->num; i++) {
- err = mlx5e_open_channel(priv, i, &chs->params, cparam, &chs->c[i]);
+ struct xdp_umem *umem = NULL;
+
+ if (chs->params.xdp_prog)
+ umem = mlx5e_xsk_get_umem(&chs->params, chs->params.xsk, i);
+
+ err = mlx5e_open_channel(priv, i, &chs->params, cparam, umem, &chs->c[i]);
if (err)
goto err_close_channels;
}
@@ -2267,6 +2360,10 @@ static int mlx5e_wait_channels_min_rx_wqes(struct mlx5e_channels *chs)
int timeout = err ? 0 : MLX5E_RQ_WQES_TIMEOUT;
err |= mlx5e_wait_for_min_rx_wqes(&chs->c[i]->rq, timeout);
+
+ /* Don't wait on the XSK RQ, because the newer xdpsock sample
+ * doesn't provide any Fill Ring entries at the setup stage.
+ */
}
return err ? -ETIMEDOUT : 0;
@@ -2339,35 +2436,35 @@ int mlx5e_create_indirect_rqt(struct mlx5e_priv *priv)
return err;
}
-int mlx5e_create_direct_rqts(struct mlx5e_priv *priv)
+int mlx5e_create_direct_rqts(struct mlx5e_priv *priv, struct mlx5e_tir *tirs)
{
- struct mlx5e_rqt *rqt;
+ const int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
int err;
int ix;
- for (ix = 0; ix < mlx5e_get_netdev_max_channels(priv->netdev); ix++) {
- rqt = &priv->direct_tir[ix].rqt;
- err = mlx5e_create_rqt(priv, 1 /*size */, rqt);
- if (err)
+ for (ix = 0; ix < max_nch; ix++) {
+ err = mlx5e_create_rqt(priv, 1 /*size */, &tirs[ix].rqt);
+ if (unlikely(err))
goto err_destroy_rqts;
}
return 0;
err_destroy_rqts:
- mlx5_core_warn(priv->mdev, "create direct rqts failed, %d\n", err);
+ mlx5_core_warn(priv->mdev, "create rqts failed, %d\n", err);
for (ix--; ix >= 0; ix--)
- mlx5e_destroy_rqt(priv, &priv->direct_tir[ix].rqt);
+ mlx5e_destroy_rqt(priv, &tirs[ix].rqt);
return err;
}
-void mlx5e_destroy_direct_rqts(struct mlx5e_priv *priv)
+void mlx5e_destroy_direct_rqts(struct mlx5e_priv *priv, struct mlx5e_tir *tirs)
{
+ const int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
int i;
- for (i = 0; i < mlx5e_get_netdev_max_channels(priv->netdev); i++)
- mlx5e_destroy_rqt(priv, &priv->direct_tir[i].rqt);
+ for (i = 0; i < max_nch; i++)
+ mlx5e_destroy_rqt(priv, &tirs[i].rqt);
}
static int mlx5e_rx_hash_fn(int hfunc)
@@ -2787,11 +2884,12 @@ static void mlx5e_build_tx2sq_maps(struct mlx5e_priv *priv)
void mlx5e_activate_priv_channels(struct mlx5e_priv *priv)
{
int num_txqs = priv->channels.num * priv->channels.params.num_tc;
+ int num_rxqs = priv->channels.num * MLX5E_NUM_RQ_GROUPS;
struct net_device *netdev = priv->netdev;
mlx5e_netdev_set_tcs(netdev);
netif_set_real_num_tx_queues(netdev, num_txqs);
- netif_set_real_num_rx_queues(netdev, priv->channels.num);
+ netif_set_real_num_rx_queues(netdev, num_rxqs);
mlx5e_build_tx2sq_maps(priv);
mlx5e_activate_channels(&priv->channels);
@@ -2803,10 +2901,14 @@ void mlx5e_activate_priv_channels(struct mlx5e_priv *priv)
mlx5e_wait_channels_min_rx_wqes(&priv->channels);
mlx5e_redirect_rqts_to_channels(priv, &priv->channels);
+
+ mlx5e_xsk_redirect_rqts_to_channels(priv, &priv->channels);
}
void mlx5e_deactivate_priv_channels(struct mlx5e_priv *priv)
{
+ mlx5e_xsk_redirect_rqts_to_drop(priv, &priv->channels);
+
mlx5e_redirect_rqts_to_drop(priv);
if (mlx5e_is_vport_rep(priv))
@@ -2846,7 +2948,7 @@ static void mlx5e_switch_priv_channels(struct mlx5e_priv *priv,
if (hw_modify)
hw_modify(priv);
- mlx5e_refresh_tirs(priv, false);
+ priv->profile->update_rx(priv);
mlx5e_activate_priv_channels(priv);
/* return carrier back if needed */
@@ -2885,15 +2987,18 @@ void mlx5e_timestamp_init(struct mlx5e_priv *priv)
int mlx5e_open_locked(struct net_device *netdev)
{
struct mlx5e_priv *priv = netdev_priv(netdev);
+ bool is_xdp = priv->channels.params.xdp_prog;
int err;
set_bit(MLX5E_STATE_OPENED, &priv->state);
+ if (is_xdp)
+ mlx5e_xdp_set_open(priv);
err = mlx5e_open_channels(priv, &priv->channels);
if (err)
goto err_clear_state_opened_flag;
- mlx5e_refresh_tirs(priv, false);
+ priv->profile->update_rx(priv);
mlx5e_activate_priv_channels(priv);
if (priv->profile->update_carrier)
priv->profile->update_carrier(priv);
@@ -2902,6 +3007,8 @@ int mlx5e_open_locked(struct net_device *netdev)
return 0;
err_clear_state_opened_flag:
+ if (is_xdp)
+ mlx5e_xdp_set_closed(priv);
clear_bit(MLX5E_STATE_OPENED, &priv->state);
return err;
}
@@ -2933,6 +3040,8 @@ int mlx5e_close_locked(struct net_device *netdev)
if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
return 0;
+ if (priv->channels.params.xdp_prog)
+ mlx5e_xdp_set_closed(priv);
clear_bit(MLX5E_STATE_OPENED, &priv->state);
netif_carrier_off(priv->netdev);
@@ -3044,20 +3153,19 @@ void mlx5e_close_drop_rq(struct mlx5e_rq *drop_rq)
mlx5e_free_cq(&drop_rq->cq);
}
-int mlx5e_create_tis(struct mlx5_core_dev *mdev, int tc,
- u32 underlay_qpn, u32 *tisn)
+int mlx5e_create_tis(struct mlx5_core_dev *mdev, void *in, u32 *tisn)
{
- u32 in[MLX5_ST_SZ_DW(create_tis_in)] = {0};
void *tisc = MLX5_ADDR_OF(create_tis_in, in, ctx);
- MLX5_SET(tisc, tisc, prio, tc << 1);
- MLX5_SET(tisc, tisc, underlay_qpn, underlay_qpn);
MLX5_SET(tisc, tisc, transport_domain, mdev->mlx5e_res.td.tdn);
+ if (MLX5_GET(tisc, tisc, tls_en))
+ MLX5_SET(tisc, tisc, pd, mdev->mlx5e_res.pdn);
+
if (mlx5_lag_is_lacp_owner(mdev))
MLX5_SET(tisc, tisc, strict_lag_tx_port_affinity, 1);
- return mlx5_core_create_tis(mdev, in, sizeof(in), tisn);
+ return mlx5_core_create_tis(mdev, in, MLX5_ST_SZ_BYTES(create_tis_in), tisn);
}
void mlx5e_destroy_tis(struct mlx5_core_dev *mdev, u32 tisn)
@@ -3071,7 +3179,14 @@ int mlx5e_create_tises(struct mlx5e_priv *priv)
int tc;
for (tc = 0; tc < priv->profile->max_tc; tc++) {
- err = mlx5e_create_tis(priv->mdev, tc, 0, &priv->tisn[tc]);
+ u32 in[MLX5_ST_SZ_DW(create_tis_in)] = {};
+ void *tisc;
+
+ tisc = MLX5_ADDR_OF(create_tis_in, in, ctx);
+
+ MLX5_SET(tisc, tisc, prio, tc << 1);
+
+ err = mlx5e_create_tis(priv->mdev, in, &priv->tisn[tc]);
if (err)
goto err_close_tises;
}
@@ -3189,13 +3304,13 @@ err_destroy_inner_tirs:
return err;
}
-int mlx5e_create_direct_tirs(struct mlx5e_priv *priv)
+int mlx5e_create_direct_tirs(struct mlx5e_priv *priv, struct mlx5e_tir *tirs)
{
- int nch = mlx5e_get_netdev_max_channels(priv->netdev);
+ const int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
struct mlx5e_tir *tir;
void *tirc;
int inlen;
- int err;
+ int err = 0;
u32 *in;
int ix;
@@ -3204,25 +3319,24 @@ int mlx5e_create_direct_tirs(struct mlx5e_priv *priv)
if (!in)
return -ENOMEM;
- for (ix = 0; ix < nch; ix++) {
+ for (ix = 0; ix < max_nch; ix++) {
memset(in, 0, inlen);
- tir = &priv->direct_tir[ix];
+ tir = &tirs[ix];
tirc = MLX5_ADDR_OF(create_tir_in, in, ctx);
- mlx5e_build_direct_tir_ctx(priv, priv->direct_tir[ix].rqt.rqtn, tirc);
+ mlx5e_build_direct_tir_ctx(priv, tir->rqt.rqtn, tirc);
err = mlx5e_create_tir(priv->mdev, tir, in, inlen);
- if (err)
+ if (unlikely(err))
goto err_destroy_ch_tirs;
}
- kvfree(in);
-
- return 0;
+ goto out;
err_destroy_ch_tirs:
- mlx5_core_warn(priv->mdev, "create direct tirs failed, %d\n", err);
+ mlx5_core_warn(priv->mdev, "create tirs failed, %d\n", err);
for (ix--; ix >= 0; ix--)
- mlx5e_destroy_tir(priv->mdev, &priv->direct_tir[ix]);
+ mlx5e_destroy_tir(priv->mdev, &tirs[ix]);
+out:
kvfree(in);
return err;
@@ -3242,13 +3356,13 @@ void mlx5e_destroy_indirect_tirs(struct mlx5e_priv *priv, bool inner_ttc)
mlx5e_destroy_tir(priv->mdev, &priv->inner_indir_tir[i]);
}
-void mlx5e_destroy_direct_tirs(struct mlx5e_priv *priv)
+void mlx5e_destroy_direct_tirs(struct mlx5e_priv *priv, struct mlx5e_tir *tirs)
{
- int nch = mlx5e_get_netdev_max_channels(priv->netdev);
+ const int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
int i;
- for (i = 0; i < nch; i++)
- mlx5e_destroy_tir(priv->mdev, &priv->direct_tir[i]);
+ for (i = 0; i < max_nch; i++)
+ mlx5e_destroy_tir(priv->mdev, &tirs[i]);
}
static int mlx5e_modify_channels_scatter_fcs(struct mlx5e_channels *chs, bool enable)
@@ -3279,10 +3393,9 @@ static int mlx5e_modify_channels_vsd(struct mlx5e_channels *chs, bool vsd)
return 0;
}
-static int mlx5e_setup_tc_mqprio(struct net_device *netdev,
+static int mlx5e_setup_tc_mqprio(struct mlx5e_priv *priv,
struct tc_mqprio_qopt *mqprio)
{
- struct mlx5e_priv *priv = netdev_priv(netdev);
struct mlx5e_channels new_channels = {};
u8 tc = mqprio->num_tc;
int err = 0;
@@ -3315,17 +3428,17 @@ out:
#ifdef CONFIG_MLX5_ESWITCH
static int mlx5e_setup_tc_cls_flower(struct mlx5e_priv *priv,
- struct tc_cls_flower_offload *cls_flower,
+ struct flow_cls_offload *cls_flower,
int flags)
{
switch (cls_flower->command) {
- case TC_CLSFLOWER_REPLACE:
+ case FLOW_CLS_REPLACE:
return mlx5e_configure_flower(priv->netdev, priv, cls_flower,
flags);
- case TC_CLSFLOWER_DESTROY:
+ case FLOW_CLS_DESTROY:
return mlx5e_delete_flower(priv->netdev, priv, cls_flower,
flags);
- case TC_CLSFLOWER_STATS:
+ case FLOW_CLS_STATS:
return mlx5e_stats_flower(priv->netdev, priv, cls_flower,
flags);
default:
@@ -3346,39 +3459,25 @@ static int mlx5e_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
return -EOPNOTSUPP;
}
}
-
-static int mlx5e_setup_tc_block(struct net_device *dev,
- struct tc_block_offload *f)
-{
- struct mlx5e_priv *priv = netdev_priv(dev);
-
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
- return -EOPNOTSUPP;
-
- switch (f->command) {
- case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block, mlx5e_setup_tc_block_cb,
- priv, priv, f->extack);
- case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block, mlx5e_setup_tc_block_cb,
- priv);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-}
#endif
+static LIST_HEAD(mlx5e_block_cb_list);
+
static int mlx5e_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data)
{
+ struct mlx5e_priv *priv = netdev_priv(dev);
+
switch (type) {
#ifdef CONFIG_MLX5_ESWITCH
case TC_SETUP_BLOCK:
- return mlx5e_setup_tc_block(dev, type_data);
+ return flow_block_cb_setup_simple(type_data,
+ &mlx5e_block_cb_list,
+ mlx5e_setup_tc_block_cb,
+ priv, priv, true);
#endif
case TC_SETUP_QDISC_MQPRIO:
- return mlx5e_setup_tc_mqprio(dev, type_data);
+ return mlx5e_setup_tc_mqprio(priv, type_data);
default:
return -EOPNOTSUPP;
}
@@ -3390,11 +3489,12 @@ void mlx5e_fold_sw_stats64(struct mlx5e_priv *priv, struct rtnl_link_stats64 *s)
for (i = 0; i < mlx5e_get_netdev_max_channels(priv->netdev); i++) {
struct mlx5e_channel_stats *channel_stats = &priv->channel_stats[i];
+ struct mlx5e_rq_stats *xskrq_stats = &channel_stats->xskrq;
struct mlx5e_rq_stats *rq_stats = &channel_stats->rq;
int j;
- s->rx_packets += rq_stats->packets;
- s->rx_bytes += rq_stats->bytes;
+ s->rx_packets += rq_stats->packets + xskrq_stats->packets;
+ s->rx_bytes += rq_stats->bytes + xskrq_stats->bytes;
for (j = 0; j < priv->max_opened_tc; j++) {
struct mlx5e_sq_stats *sq_stats = &channel_stats->sq[j];
@@ -3493,6 +3593,13 @@ static int set_feature_lro(struct net_device *netdev, bool enable)
mutex_lock(&priv->state_lock);
+ if (enable && priv->xsk.refcnt) {
+ netdev_warn(netdev, "LRO is incompatible with AF_XDP (%hu XSKs are active)\n",
+ priv->xsk.refcnt);
+ err = -EINVAL;
+ goto out;
+ }
+
old_params = &priv->channels.params;
if (enable && !MLX5E_GET_PFLAG(old_params, MLX5E_PFLAG_RX_STRIDING_RQ)) {
netdev_warn(netdev, "can't set LRO with legacy RQ\n");
@@ -3506,8 +3613,8 @@ static int set_feature_lro(struct net_device *netdev, bool enable)
new_channels.params.lro_en = enable;
if (old_params->rq_wq_type != MLX5_WQ_TYPE_CYCLIC) {
- if (mlx5e_rx_mpwqe_is_linear_skb(mdev, old_params) ==
- mlx5e_rx_mpwqe_is_linear_skb(mdev, &new_channels.params))
+ if (mlx5e_rx_mpwqe_is_linear_skb(mdev, old_params, NULL) ==
+ mlx5e_rx_mpwqe_is_linear_skb(mdev, &new_channels.params, NULL))
reset = false;
}
@@ -3635,8 +3742,7 @@ static int mlx5e_handle_feature(struct net_device *netdev,
return 0;
}
-static int mlx5e_set_features(struct net_device *netdev,
- netdev_features_t features)
+int mlx5e_set_features(struct net_device *netdev, netdev_features_t features)
{
netdev_features_t oper_features = netdev->features;
int err = 0;
@@ -3698,6 +3804,43 @@ static netdev_features_t mlx5e_fix_features(struct net_device *netdev,
return features;
}
+static bool mlx5e_xsk_validate_mtu(struct net_device *netdev,
+ struct mlx5e_channels *chs,
+ struct mlx5e_params *new_params,
+ struct mlx5_core_dev *mdev)
+{
+ u16 ix;
+
+ for (ix = 0; ix < chs->params.num_channels; ix++) {
+ struct xdp_umem *umem = mlx5e_xsk_get_umem(&chs->params, chs->params.xsk, ix);
+ struct mlx5e_xsk_param xsk;
+
+ if (!umem)
+ continue;
+
+ mlx5e_build_xsk_param(umem, &xsk);
+
+ if (!mlx5e_validate_xsk_param(new_params, &xsk, mdev)) {
+ u32 hr = mlx5e_get_linear_rq_headroom(new_params, &xsk);
+ int max_mtu_frame, max_mtu_page, max_mtu;
+
+ /* Two criteria must be met:
+ * 1. HW MTU + all headrooms <= XSK frame size.
+ * 2. Size of SKBs allocated on XDP_PASS <= PAGE_SIZE.
+ */
+ max_mtu_frame = MLX5E_HW2SW_MTU(new_params, xsk.chunk_size - hr);
+ max_mtu_page = mlx5e_xdp_max_mtu(new_params, &xsk);
+ max_mtu = min(max_mtu_frame, max_mtu_page);
+
+ netdev_err(netdev, "MTU %d is too big for an XSK running on channel %hu. Try MTU <= %d\n",
+ new_params->sw_mtu, ix, max_mtu);
+ return false;
+ }
+ }
+
+ return true;
+}
+
int mlx5e_change_mtu(struct net_device *netdev, int new_mtu,
change_hw_mtu_cb set_mtu_cb)
{
@@ -3718,18 +3861,31 @@ int mlx5e_change_mtu(struct net_device *netdev, int new_mtu,
new_channels.params.sw_mtu = new_mtu;
if (params->xdp_prog &&
- !mlx5e_rx_is_linear_skb(&new_channels.params)) {
+ !mlx5e_rx_is_linear_skb(&new_channels.params, NULL)) {
netdev_err(netdev, "MTU(%d) > %d is not allowed while XDP enabled\n",
- new_mtu, mlx5e_xdp_max_mtu(params));
+ new_mtu, mlx5e_xdp_max_mtu(params, NULL));
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (priv->xsk.refcnt &&
+ !mlx5e_xsk_validate_mtu(netdev, &priv->channels,
+ &new_channels.params, priv->mdev)) {
err = -EINVAL;
goto out;
}
if (params->rq_wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ) {
- bool is_linear = mlx5e_rx_mpwqe_is_linear_skb(priv->mdev, &new_channels.params);
- u8 ppw_old = mlx5e_mpwqe_log_pkts_per_wqe(params);
- u8 ppw_new = mlx5e_mpwqe_log_pkts_per_wqe(&new_channels.params);
+ bool is_linear = mlx5e_rx_mpwqe_is_linear_skb(priv->mdev,
+ &new_channels.params,
+ NULL);
+ u8 ppw_old = mlx5e_mpwqe_log_pkts_per_wqe(params, NULL);
+ u8 ppw_new = mlx5e_mpwqe_log_pkts_per_wqe(&new_channels.params, NULL);
+
+ /* If XSK is active, XSK RQs are linear. */
+ is_linear |= priv->xsk.refcnt;
+ /* Always reset in linear mode - hw_mtu is used in data path. */
reset = reset && (is_linear || (ppw_old != ppw_new));
}
@@ -4162,16 +4318,29 @@ static int mlx5e_xdp_allowed(struct mlx5e_priv *priv, struct bpf_prog *prog)
new_channels.params = priv->channels.params;
new_channels.params.xdp_prog = prog;
- if (!mlx5e_rx_is_linear_skb(&new_channels.params)) {
+ /* No XSK params: AF_XDP can't be enabled yet at the point of setting
+ * the XDP program.
+ */
+ if (!mlx5e_rx_is_linear_skb(&new_channels.params, NULL)) {
netdev_warn(netdev, "XDP is not allowed with MTU(%d) > %d\n",
new_channels.params.sw_mtu,
- mlx5e_xdp_max_mtu(&new_channels.params));
+ mlx5e_xdp_max_mtu(&new_channels.params, NULL));
return -EINVAL;
}
return 0;
}
+static int mlx5e_xdp_update_state(struct mlx5e_priv *priv)
+{
+ if (priv->channels.params.xdp_prog)
+ mlx5e_xdp_set_open(priv);
+ else
+ mlx5e_xdp_set_closed(priv);
+
+ return 0;
+}
+
static int mlx5e_xdp_set(struct net_device *netdev, struct bpf_prog *prog)
{
struct mlx5e_priv *priv = netdev_priv(netdev);
@@ -4192,8 +4361,6 @@ static int mlx5e_xdp_set(struct net_device *netdev, struct bpf_prog *prog)
/* no need for full reset when exchanging programs */
reset = (!priv->channels.params.xdp_prog || !prog);
- if (was_opened && reset)
- mlx5e_close_locked(netdev);
if (was_opened && !reset) {
/* num_channels is invariant here, so we can take the
* batched reference right upfront.
@@ -4205,20 +4372,31 @@ static int mlx5e_xdp_set(struct net_device *netdev, struct bpf_prog *prog)
}
}
- /* exchange programs, extra prog reference we got from caller
- * as long as we don't fail from this point onwards.
- */
- old_prog = xchg(&priv->channels.params.xdp_prog, prog);
+ if (was_opened && reset) {
+ struct mlx5e_channels new_channels = {};
+
+ new_channels.params = priv->channels.params;
+ new_channels.params.xdp_prog = prog;
+ mlx5e_set_rq_type(priv->mdev, &new_channels.params);
+ old_prog = priv->channels.params.xdp_prog;
+
+ err = mlx5e_safe_switch_channels(priv, &new_channels, mlx5e_xdp_update_state);
+ if (err)
+ goto unlock;
+ } else {
+ /* exchange programs, extra prog reference we got from caller
+ * as long as we don't fail from this point onwards.
+ */
+ old_prog = xchg(&priv->channels.params.xdp_prog, prog);
+ }
+
if (old_prog)
bpf_prog_put(old_prog);
- if (reset) /* change RQ type according to priv->xdp_prog */
+ if (!was_opened && reset) /* change RQ type according to priv->xdp_prog */
mlx5e_set_rq_type(priv->mdev, &priv->channels.params);
- if (was_opened && reset)
- err = mlx5e_open_locked(netdev);
-
- if (!test_bit(MLX5E_STATE_OPENED, &priv->state) || reset)
+ if (!was_opened || reset)
goto unlock;
/* exchanging programs w/o reset, we update ref counts on behalf
@@ -4226,19 +4404,29 @@ static int mlx5e_xdp_set(struct net_device *netdev, struct bpf_prog *prog)
*/
for (i = 0; i < priv->channels.num; i++) {
struct mlx5e_channel *c = priv->channels.c[i];
+ bool xsk_open = test_bit(MLX5E_CHANNEL_STATE_XSK, c->state);
clear_bit(MLX5E_RQ_STATE_ENABLED, &c->rq.state);
+ if (xsk_open)
+ clear_bit(MLX5E_RQ_STATE_ENABLED, &c->xskrq.state);
napi_synchronize(&c->napi);
/* prevent mlx5e_poll_rx_cq from accessing rq->xdp_prog */
old_prog = xchg(&c->rq.xdp_prog, prog);
+ if (old_prog)
+ bpf_prog_put(old_prog);
+
+ if (xsk_open) {
+ old_prog = xchg(&c->xskrq.xdp_prog, prog);
+ if (old_prog)
+ bpf_prog_put(old_prog);
+ }
set_bit(MLX5E_RQ_STATE_ENABLED, &c->rq.state);
+ if (xsk_open)
+ set_bit(MLX5E_RQ_STATE_ENABLED, &c->xskrq.state);
/* napi_schedule in case we have missed anything */
napi_schedule(&c->napi);
-
- if (old_prog)
- bpf_prog_put(old_prog);
}
unlock:
@@ -4269,6 +4457,9 @@ static int mlx5e_xdp(struct net_device *dev, struct netdev_bpf *xdp)
case XDP_QUERY_PROG:
xdp->prog_id = mlx5e_xdp_query(dev);
return 0;
+ case XDP_SETUP_XSK_UMEM:
+ return mlx5e_xsk_setup_umem(dev, xdp->xsk.umem,
+ xdp->xsk.queue_id);
default:
return -EINVAL;
}
@@ -4351,6 +4542,7 @@ const struct net_device_ops mlx5e_netdev_ops = {
.ndo_tx_timeout = mlx5e_tx_timeout,
.ndo_bpf = mlx5e_xdp,
.ndo_xdp_xmit = mlx5e_xdp_xmit,
+ .ndo_xsk_async_xmit = mlx5e_xsk_async_xmit,
#ifdef CONFIG_MLX5_EN_ARFS
.ndo_rx_flow_steer = mlx5e_rx_flow_steer,
#endif
@@ -4420,9 +4612,9 @@ static bool slow_pci_heuristic(struct mlx5_core_dev *mdev)
link_speed > MLX5E_SLOW_PCI_RATIO * pci_bw;
}
-static struct net_dim_cq_moder mlx5e_get_def_tx_moderation(u8 cq_period_mode)
+static struct dim_cq_moder mlx5e_get_def_tx_moderation(u8 cq_period_mode)
{
- struct net_dim_cq_moder moder;
+ struct dim_cq_moder moder;
moder.cq_period_mode = cq_period_mode;
moder.pkts = MLX5E_PARAMS_DEFAULT_TX_CQ_MODERATION_PKTS;
@@ -4433,9 +4625,9 @@ static struct net_dim_cq_moder mlx5e_get_def_tx_moderation(u8 cq_period_mode)
return moder;
}
-static struct net_dim_cq_moder mlx5e_get_def_rx_moderation(u8 cq_period_mode)
+static struct dim_cq_moder mlx5e_get_def_rx_moderation(u8 cq_period_mode)
{
- struct net_dim_cq_moder moder;
+ struct dim_cq_moder moder;
moder.cq_period_mode = cq_period_mode;
moder.pkts = MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_PKTS;
@@ -4449,8 +4641,8 @@ static struct net_dim_cq_moder mlx5e_get_def_rx_moderation(u8 cq_period_mode)
static u8 mlx5_to_net_dim_cq_period_mode(u8 cq_period_mode)
{
return cq_period_mode == MLX5_CQ_PERIOD_MODE_START_FROM_CQE ?
- NET_DIM_CQ_PERIOD_MODE_START_FROM_CQE :
- NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE;
+ DIM_CQ_PERIOD_MODE_START_FROM_CQE :
+ DIM_CQ_PERIOD_MODE_START_FROM_EQE;
}
void mlx5e_set_tx_cq_mode_params(struct mlx5e_params *params, u8 cq_period_mode)
@@ -4502,11 +4694,13 @@ void mlx5e_build_rq_params(struct mlx5_core_dev *mdev,
* - Striding RQ configuration is not possible/supported.
* - Slow PCI heuristic.
* - Legacy RQ would use linear SKB while Striding RQ would use non-linear.
+ *
+ * No XSK params: checking the availability of striding RQ in general.
*/
if (!slow_pci_heuristic(mdev) &&
mlx5e_striding_rq_possible(mdev, params) &&
- (mlx5e_rx_mpwqe_is_linear_skb(mdev, params) ||
- !mlx5e_rx_is_linear_skb(params)))
+ (mlx5e_rx_mpwqe_is_linear_skb(mdev, params, NULL) ||
+ !mlx5e_rx_is_linear_skb(params, NULL)))
MLX5E_SET_PFLAG(params, MLX5E_PFLAG_RX_STRIDING_RQ, true);
mlx5e_set_rq_type(mdev, params);
mlx5e_init_rq_type_params(mdev, params);
@@ -4528,6 +4722,7 @@ void mlx5e_build_rss_params(struct mlx5e_rss_params *rss_params,
}
void mlx5e_build_nic_params(struct mlx5_core_dev *mdev,
+ struct mlx5e_xsk *xsk,
struct mlx5e_rss_params *rss_params,
struct mlx5e_params *params,
u16 max_channels, u16 mtu)
@@ -4563,9 +4758,11 @@ void mlx5e_build_nic_params(struct mlx5_core_dev *mdev,
/* HW LRO */
/* TODO: && MLX5_CAP_ETH(mdev, lro_cap) */
- if (params->rq_wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ)
- if (!mlx5e_rx_mpwqe_is_linear_skb(mdev, params))
+ if (params->rq_wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ) {
+ /* No XSK params: checking the availability of striding RQ in general. */
+ if (!mlx5e_rx_mpwqe_is_linear_skb(mdev, params, NULL))
params->lro_en = !slow_pci_heuristic(mdev);
+ }
params->lro_timeout = mlx5e_choose_lro_timeout(mdev, MLX5E_DEFAULT_LRO_TIMEOUT);
/* CQ moderation params */
@@ -4584,13 +4781,16 @@ void mlx5e_build_nic_params(struct mlx5_core_dev *mdev,
mlx5e_build_rss_params(rss_params, params->num_channels);
params->tunneled_offload_en =
mlx5e_tunnel_inner_ft_supported(mdev);
+
+ /* AF_XDP */
+ params->xsk = xsk;
}
static void mlx5e_set_netdev_dev_addr(struct net_device *netdev)
{
struct mlx5e_priv *priv = netdev_priv(netdev);
- mlx5_query_nic_vport_mac_address(priv->mdev, 0, netdev->dev_addr);
+ mlx5_query_mac_address(priv->mdev, netdev->dev_addr);
if (is_zero_ether_addr(netdev->dev_addr) &&
!MLX5_CAP_GEN(priv->mdev, vport_group_manager)) {
eth_hw_addr_random(netdev);
@@ -4619,14 +4819,18 @@ static void mlx5e_build_nic_netdev(struct net_device *netdev)
netdev->ethtool_ops = &mlx5e_ethtool_ops;
netdev->vlan_features |= NETIF_F_SG;
- netdev->vlan_features |= NETIF_F_IP_CSUM;
- netdev->vlan_features |= NETIF_F_IPV6_CSUM;
+ netdev->vlan_features |= NETIF_F_HW_CSUM;
netdev->vlan_features |= NETIF_F_GRO;
netdev->vlan_features |= NETIF_F_TSO;
netdev->vlan_features |= NETIF_F_TSO6;
netdev->vlan_features |= NETIF_F_RXCSUM;
netdev->vlan_features |= NETIF_F_RXHASH;
+ netdev->mpls_features |= NETIF_F_SG;
+ netdev->mpls_features |= NETIF_F_HW_CSUM;
+ netdev->mpls_features |= NETIF_F_TSO;
+ netdev->mpls_features |= NETIF_F_TSO6;
+
netdev->hw_enc_features |= NETIF_F_HW_VLAN_CTAG_TX;
netdev->hw_enc_features |= NETIF_F_HW_VLAN_CTAG_RX;
@@ -4642,8 +4846,7 @@ static void mlx5e_build_nic_netdev(struct net_device *netdev)
if (mlx5_vxlan_allowed(mdev->vxlan) || mlx5_geneve_tx_allowed(mdev) ||
MLX5_CAP_ETH(mdev, tunnel_stateless_gre)) {
- netdev->hw_enc_features |= NETIF_F_IP_CSUM;
- netdev->hw_enc_features |= NETIF_F_IPV6_CSUM;
+ netdev->hw_enc_features |= NETIF_F_HW_CSUM;
netdev->hw_enc_features |= NETIF_F_TSO;
netdev->hw_enc_features |= NETIF_F_TSO6;
netdev->hw_enc_features |= NETIF_F_GSO_PARTIAL;
@@ -4756,7 +4959,7 @@ static int mlx5e_nic_init(struct mlx5_core_dev *mdev,
if (err)
return err;
- mlx5e_build_nic_params(mdev, rss, &priv->channels.params,
+ mlx5e_build_nic_params(mdev, &priv->xsk, rss, &priv->channels.params,
mlx5e_get_netdev_max_channels(netdev),
netdev->mtu);
@@ -4798,7 +5001,7 @@ static int mlx5e_init_nic_rx(struct mlx5e_priv *priv)
if (err)
goto err_close_drop_rq;
- err = mlx5e_create_direct_rqts(priv);
+ err = mlx5e_create_direct_rqts(priv, priv->direct_tir);
if (err)
goto err_destroy_indirect_rqts;
@@ -4806,14 +5009,22 @@ static int mlx5e_init_nic_rx(struct mlx5e_priv *priv)
if (err)
goto err_destroy_direct_rqts;
- err = mlx5e_create_direct_tirs(priv);
+ err = mlx5e_create_direct_tirs(priv, priv->direct_tir);
if (err)
goto err_destroy_indirect_tirs;
+ err = mlx5e_create_direct_rqts(priv, priv->xsk_tir);
+ if (unlikely(err))
+ goto err_destroy_direct_tirs;
+
+ err = mlx5e_create_direct_tirs(priv, priv->xsk_tir);
+ if (unlikely(err))
+ goto err_destroy_xsk_rqts;
+
err = mlx5e_create_flow_steering(priv);
if (err) {
mlx5_core_warn(mdev, "create flow steering failed, %d\n", err);
- goto err_destroy_direct_tirs;
+ goto err_destroy_xsk_tirs;
}
err = mlx5e_tc_nic_init(priv);
@@ -4824,12 +5035,16 @@ static int mlx5e_init_nic_rx(struct mlx5e_priv *priv)
err_destroy_flow_steering:
mlx5e_destroy_flow_steering(priv);
+err_destroy_xsk_tirs:
+ mlx5e_destroy_direct_tirs(priv, priv->xsk_tir);
+err_destroy_xsk_rqts:
+ mlx5e_destroy_direct_rqts(priv, priv->xsk_tir);
err_destroy_direct_tirs:
- mlx5e_destroy_direct_tirs(priv);
+ mlx5e_destroy_direct_tirs(priv, priv->direct_tir);
err_destroy_indirect_tirs:
mlx5e_destroy_indirect_tirs(priv, true);
err_destroy_direct_rqts:
- mlx5e_destroy_direct_rqts(priv);
+ mlx5e_destroy_direct_rqts(priv, priv->direct_tir);
err_destroy_indirect_rqts:
mlx5e_destroy_rqt(priv, &priv->indir_rqt);
err_close_drop_rq:
@@ -4843,9 +5058,11 @@ static void mlx5e_cleanup_nic_rx(struct mlx5e_priv *priv)
{
mlx5e_tc_nic_cleanup(priv);
mlx5e_destroy_flow_steering(priv);
- mlx5e_destroy_direct_tirs(priv);
+ mlx5e_destroy_direct_tirs(priv, priv->xsk_tir);
+ mlx5e_destroy_direct_rqts(priv, priv->xsk_tir);
+ mlx5e_destroy_direct_tirs(priv, priv->direct_tir);
mlx5e_destroy_indirect_tirs(priv, true);
- mlx5e_destroy_direct_rqts(priv);
+ mlx5e_destroy_direct_rqts(priv, priv->direct_tir);
mlx5e_destroy_rqt(priv, &priv->indir_rqt);
mlx5e_close_drop_rq(&priv->drop_rq);
mlx5e_destroy_q_counters(priv);
@@ -4927,6 +5144,11 @@ static void mlx5e_nic_disable(struct mlx5e_priv *priv)
mlx5_lag_remove(mdev);
}
+int mlx5e_update_nic_rx(struct mlx5e_priv *priv)
+{
+ return mlx5e_refresh_tirs(priv, false);
+}
+
static const struct mlx5e_profile mlx5e_nic_profile = {
.init = mlx5e_nic_init,
.cleanup = mlx5e_nic_cleanup,
@@ -4936,6 +5158,7 @@ static const struct mlx5e_profile mlx5e_nic_profile = {
.cleanup_tx = mlx5e_cleanup_nic_tx,
.enable = mlx5e_nic_enable,
.disable = mlx5e_nic_disable,
+ .update_rx = mlx5e_update_nic_rx,
.update_stats = mlx5e_update_ndo_stats,
.update_carrier = mlx5e_update_carrier,
.rx_handlers.handle_rx_cqe = mlx5e_handle_rx_cqe,
@@ -4995,7 +5218,7 @@ struct net_device *mlx5e_create_netdev(struct mlx5_core_dev *mdev,
netdev = alloc_etherdev_mqs(sizeof(struct mlx5e_priv),
nch * profile->max_tc,
- nch);
+ nch * MLX5E_NUM_RQ_GROUPS);
if (!netdev) {
mlx5_core_err(mdev, "alloc_etherdev_mqs() failed\n");
return NULL;
@@ -5108,6 +5331,11 @@ static void mlx5e_detach(struct mlx5_core_dev *mdev, void *vpriv)
struct mlx5e_priv *priv = vpriv;
struct net_device *netdev = priv->netdev;
+#ifdef CONFIG_MLX5_ESWITCH
+ if (MLX5_ESWITCH_MANAGER(mdev) && vpriv == mdev)
+ return;
+#endif
+
if (!netif_device_present(netdev))
return;
@@ -5128,7 +5356,7 @@ static void *mlx5e_add(struct mlx5_core_dev *mdev)
#ifdef CONFIG_MLX5_ESWITCH
if (MLX5_ESWITCH_MANAGER(mdev) &&
- mlx5_eswitch_mode(mdev->priv.eswitch) == SRIOV_OFFLOADS) {
+ mlx5_eswitch_mode(mdev->priv.eswitch) == MLX5_ESWITCH_OFFLOADS) {
mlx5e_rep_register_vport_reps(mdev);
return mdev;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
index 9aea9c5b2ce8..7245d287633d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
@@ -37,6 +37,7 @@
#include <net/act_api.h>
#include <net/netevent.h>
#include <net/arp.h>
+#include <net/devlink.h>
#include "eswitch.h"
#include "en.h"
@@ -128,7 +129,7 @@ static void mlx5e_rep_get_strings(struct net_device *dev,
}
}
-static void mlx5e_vf_rep_update_hw_counters(struct mlx5e_priv *priv)
+static void mlx5e_rep_update_hw_counters(struct mlx5e_priv *priv)
{
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
struct mlx5e_rep_priv *rpriv = priv->ppriv;
@@ -166,17 +167,6 @@ static void mlx5e_uplink_rep_update_hw_counters(struct mlx5e_priv *priv)
vport_stats->tx_bytes = PPORT_802_3_GET(pstats, a_octets_transmitted_ok);
}
-static void mlx5e_rep_update_hw_counters(struct mlx5e_priv *priv)
-{
- struct mlx5e_rep_priv *rpriv = priv->ppriv;
- struct mlx5_eswitch_rep *rep = rpriv->rep;
-
- if (rep->vport == MLX5_VPORT_UPLINK)
- mlx5e_uplink_rep_update_hw_counters(priv);
- else
- mlx5e_vf_rep_update_hw_counters(priv);
-}
-
static void mlx5e_rep_update_sw_counters(struct mlx5e_priv *priv)
{
struct mlx5e_sw_stats *s = &priv->stats.sw;
@@ -203,7 +193,7 @@ static void mlx5e_rep_get_ethtool_stats(struct net_device *dev,
mutex_lock(&priv->state_lock);
mlx5e_rep_update_sw_counters(priv);
- mlx5e_rep_update_hw_counters(priv);
+ priv->profile->update_stats(priv);
mutex_unlock(&priv->state_lock);
for (i = 0; i < NUM_VPORT_REP_SW_COUNTERS; i++)
@@ -363,7 +353,7 @@ static int mlx5e_uplink_rep_set_link_ksettings(struct net_device *netdev,
return mlx5e_ethtool_set_link_ksettings(priv, link_ksettings);
}
-static const struct ethtool_ops mlx5e_vf_rep_ethtool_ops = {
+static const struct ethtool_ops mlx5e_rep_ethtool_ops = {
.get_drvinfo = mlx5e_rep_get_drvinfo,
.get_link = ethtool_op_get_link,
.get_strings = mlx5e_rep_get_strings,
@@ -402,30 +392,19 @@ static const struct ethtool_ops mlx5e_uplink_rep_ethtool_ops = {
static int mlx5e_rep_get_port_parent_id(struct net_device *dev,
struct netdev_phys_item_id *ppid)
{
- struct mlx5e_priv *priv = netdev_priv(dev);
- struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
- struct net_device *uplink_upper = NULL;
- struct mlx5e_priv *uplink_priv = NULL;
- struct net_device *uplink_dev;
-
- if (esw->mode == SRIOV_NONE)
- return -EOPNOTSUPP;
+ struct mlx5_eswitch *esw;
+ struct mlx5e_priv *priv;
+ u64 parent_id;
- uplink_dev = mlx5_eswitch_uplink_get_proto_dev(esw, REP_ETH);
- if (uplink_dev) {
- uplink_upper = netdev_master_upper_dev_get(uplink_dev);
- uplink_priv = netdev_priv(uplink_dev);
- }
+ priv = netdev_priv(dev);
+ esw = priv->mdev->priv.eswitch;
- ppid->id_len = ETH_ALEN;
- if (uplink_upper && mlx5_lag_is_sriov(uplink_priv->mdev)) {
- ether_addr_copy(ppid->id, uplink_upper->dev_addr);
- } else {
- struct mlx5e_rep_priv *rpriv = priv->ppriv;
- struct mlx5_eswitch_rep *rep = rpriv->rep;
+ if (esw->mode == MLX5_ESWITCH_NONE)
+ return -EOPNOTSUPP;
- ether_addr_copy(ppid->id, rep->hw_id);
- }
+ parent_id = mlx5_query_nic_system_image_guid(priv->mdev);
+ ppid->id_len = sizeof(parent_id);
+ memcpy(ppid->id, &parent_id, sizeof(parent_id));
return 0;
}
@@ -436,7 +415,7 @@ static void mlx5e_sqs2vport_stop(struct mlx5_eswitch *esw,
struct mlx5e_rep_sq *rep_sq, *tmp;
struct mlx5e_rep_priv *rpriv;
- if (esw->mode != SRIOV_OFFLOADS)
+ if (esw->mode != MLX5_ESWITCH_OFFLOADS)
return;
rpriv = mlx5e_rep_to_rep_priv(rep);
@@ -457,7 +436,7 @@ static int mlx5e_sqs2vport_start(struct mlx5_eswitch *esw,
int err;
int i;
- if (esw->mode != SRIOV_OFFLOADS)
+ if (esw->mode != MLX5_ESWITCH_OFFLOADS)
return 0;
rpriv = mlx5e_rep_to_rep_priv(rep);
@@ -677,7 +656,7 @@ static void mlx5e_rep_indr_clean_block_privs(struct mlx5e_rep_priv *rpriv)
static int
mlx5e_rep_indr_offload(struct net_device *netdev,
- struct tc_cls_flower_offload *flower,
+ struct flow_cls_offload *flower,
struct mlx5e_rep_indr_block_priv *indr_priv)
{
struct mlx5e_priv *priv = netdev_priv(indr_priv->rpriv->netdev);
@@ -685,13 +664,13 @@ mlx5e_rep_indr_offload(struct net_device *netdev,
int err = 0;
switch (flower->command) {
- case TC_CLSFLOWER_REPLACE:
+ case FLOW_CLS_REPLACE:
err = mlx5e_configure_flower(netdev, priv, flower, flags);
break;
- case TC_CLSFLOWER_DESTROY:
+ case FLOW_CLS_DESTROY:
err = mlx5e_delete_flower(netdev, priv, flower, flags);
break;
- case TC_CLSFLOWER_STATS:
+ case FLOW_CLS_STATS:
err = mlx5e_stats_flower(netdev, priv, flower, flags);
break;
default:
@@ -714,23 +693,39 @@ static int mlx5e_rep_indr_setup_block_cb(enum tc_setup_type type,
}
}
+static void mlx5e_rep_indr_tc_block_unbind(void *cb_priv)
+{
+ struct mlx5e_rep_indr_block_priv *indr_priv = cb_priv;
+
+ list_del(&indr_priv->list);
+ kfree(indr_priv);
+}
+
+static LIST_HEAD(mlx5e_block_cb_list);
+
static int
mlx5e_rep_indr_setup_tc_block(struct net_device *netdev,
struct mlx5e_rep_priv *rpriv,
- struct tc_block_offload *f)
+ struct flow_block_offload *f)
{
struct mlx5e_rep_indr_block_priv *indr_priv;
- int err = 0;
+ struct flow_block_cb *block_cb;
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
+ if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
return -EOPNOTSUPP;
+ f->driver_block_list = &mlx5e_block_cb_list;
+
switch (f->command) {
- case TC_BLOCK_BIND:
+ case FLOW_BLOCK_BIND:
indr_priv = mlx5e_rep_indr_block_priv_lookup(rpriv, netdev);
if (indr_priv)
return -EEXIST;
+ if (flow_block_cb_is_busy(mlx5e_rep_indr_setup_block_cb,
+ indr_priv, &mlx5e_block_cb_list))
+ return -EBUSY;
+
indr_priv = kmalloc(sizeof(*indr_priv), GFP_KERNEL);
if (!indr_priv)
return -ENOMEM;
@@ -740,26 +735,32 @@ mlx5e_rep_indr_setup_tc_block(struct net_device *netdev,
list_add(&indr_priv->list,
&rpriv->uplink_priv.tc_indr_block_priv_list);
- err = tcf_block_cb_register(f->block,
- mlx5e_rep_indr_setup_block_cb,
- indr_priv, indr_priv, f->extack);
- if (err) {
+ block_cb = flow_block_cb_alloc(f->net,
+ mlx5e_rep_indr_setup_block_cb,
+ indr_priv, indr_priv,
+ mlx5e_rep_indr_tc_block_unbind);
+ if (IS_ERR(block_cb)) {
list_del(&indr_priv->list);
kfree(indr_priv);
+ return PTR_ERR(block_cb);
}
+ flow_block_cb_add(block_cb, f);
+ list_add_tail(&block_cb->driver_list, &mlx5e_block_cb_list);
- return err;
- case TC_BLOCK_UNBIND:
+ return 0;
+ case FLOW_BLOCK_UNBIND:
indr_priv = mlx5e_rep_indr_block_priv_lookup(rpriv, netdev);
if (!indr_priv)
return -ENOENT;
- tcf_block_cb_unregister(f->block,
- mlx5e_rep_indr_setup_block_cb,
- indr_priv);
- list_del(&indr_priv->list);
- kfree(indr_priv);
+ block_cb = flow_block_cb_lookup(f,
+ mlx5e_rep_indr_setup_block_cb,
+ indr_priv);
+ if (!block_cb)
+ return -ENOENT;
+ flow_block_cb_remove(block_cb, f);
+ list_del(&block_cb->driver_list);
return 0;
default:
return -EOPNOTSUPP;
@@ -1101,7 +1102,7 @@ void mlx5e_rep_encap_entry_detach(struct mlx5e_priv *priv,
mlx5_tun_entropy_refcount_dec(tun_entropy, e->reformat_type);
}
-static int mlx5e_vf_rep_open(struct net_device *dev)
+static int mlx5e_rep_open(struct net_device *dev)
{
struct mlx5e_priv *priv = netdev_priv(dev);
struct mlx5e_rep_priv *rpriv = priv->ppriv;
@@ -1124,7 +1125,7 @@ unlock:
return err;
}
-static int mlx5e_vf_rep_close(struct net_device *dev)
+static int mlx5e_rep_close(struct net_device *dev)
{
struct mlx5e_priv *priv = netdev_priv(dev);
struct mlx5e_rep_priv *rpriv = priv->ppriv;
@@ -1141,42 +1142,18 @@ static int mlx5e_vf_rep_close(struct net_device *dev)
return ret;
}
-static int mlx5e_rep_get_phys_port_name(struct net_device *dev,
- char *buf, size_t len)
-{
- struct mlx5e_priv *priv = netdev_priv(dev);
- struct mlx5e_rep_priv *rpriv = priv->ppriv;
- struct mlx5_eswitch_rep *rep = rpriv->rep;
- unsigned int fn;
- int ret;
-
- fn = PCI_FUNC(priv->mdev->pdev->devfn);
- if (fn >= MLX5_MAX_PORTS)
- return -EOPNOTSUPP;
-
- if (rep->vport == MLX5_VPORT_UPLINK)
- ret = snprintf(buf, len, "p%d", fn);
- else
- ret = snprintf(buf, len, "pf%dvf%d", fn, rep->vport - 1);
-
- if (ret >= len)
- return -EOPNOTSUPP;
-
- return 0;
-}
-
static int
mlx5e_rep_setup_tc_cls_flower(struct mlx5e_priv *priv,
- struct tc_cls_flower_offload *cls_flower, int flags)
+ struct flow_cls_offload *cls_flower, int flags)
{
switch (cls_flower->command) {
- case TC_CLSFLOWER_REPLACE:
+ case FLOW_CLS_REPLACE:
return mlx5e_configure_flower(priv->netdev, priv, cls_flower,
flags);
- case TC_CLSFLOWER_DESTROY:
+ case FLOW_CLS_DESTROY:
return mlx5e_delete_flower(priv->netdev, priv, cls_flower,
flags);
- case TC_CLSFLOWER_STATS:
+ case FLOW_CLS_STATS:
return mlx5e_stats_flower(priv->netdev, priv, cls_flower,
flags);
default:
@@ -1198,32 +1175,19 @@ static int mlx5e_rep_setup_tc_cb(enum tc_setup_type type, void *type_data,
}
}
-static int mlx5e_rep_setup_tc_block(struct net_device *dev,
- struct tc_block_offload *f)
-{
- struct mlx5e_priv *priv = netdev_priv(dev);
-
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
- return -EOPNOTSUPP;
-
- switch (f->command) {
- case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block, mlx5e_rep_setup_tc_cb,
- priv, priv, f->extack);
- case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block, mlx5e_rep_setup_tc_cb, priv);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-}
+static LIST_HEAD(mlx5e_rep_block_cb_list);
static int mlx5e_rep_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data)
{
+ struct mlx5e_priv *priv = netdev_priv(dev);
+
switch (type) {
case TC_SETUP_BLOCK:
- return mlx5e_rep_setup_tc_block(dev, type_data);
+ return flow_block_cb_setup_simple(type_data,
+ &mlx5e_rep_block_cb_list,
+ mlx5e_rep_setup_tc_cb,
+ priv, priv, true);
default:
return -EOPNOTSUPP;
}
@@ -1276,7 +1240,7 @@ static int mlx5e_rep_get_offload_stats(int attr_id, const struct net_device *dev
}
static void
-mlx5e_vf_rep_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats)
+mlx5e_rep_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats)
{
struct mlx5e_priv *priv = netdev_priv(dev);
@@ -1285,7 +1249,7 @@ mlx5e_vf_rep_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats)
memcpy(stats, &priv->stats.vf_vport, sizeof(*stats));
}
-static int mlx5e_vf_rep_change_mtu(struct net_device *netdev, int new_mtu)
+static int mlx5e_rep_change_mtu(struct net_device *netdev, int new_mtu)
{
return mlx5e_change_mtu(netdev, new_mtu, NULL);
}
@@ -1318,17 +1282,24 @@ static int mlx5e_uplink_rep_set_vf_vlan(struct net_device *dev, int vf, u16 vlan
return 0;
}
-static const struct net_device_ops mlx5e_netdev_ops_vf_rep = {
- .ndo_open = mlx5e_vf_rep_open,
- .ndo_stop = mlx5e_vf_rep_close,
+static struct devlink_port *mlx5e_get_devlink_port(struct net_device *dev)
+{
+ struct mlx5e_priv *priv = netdev_priv(dev);
+ struct mlx5e_rep_priv *rpriv = priv->ppriv;
+
+ return &rpriv->dl_port;
+}
+
+static const struct net_device_ops mlx5e_netdev_ops_rep = {
+ .ndo_open = mlx5e_rep_open,
+ .ndo_stop = mlx5e_rep_close,
.ndo_start_xmit = mlx5e_xmit,
- .ndo_get_phys_port_name = mlx5e_rep_get_phys_port_name,
.ndo_setup_tc = mlx5e_rep_setup_tc,
- .ndo_get_stats64 = mlx5e_vf_rep_get_stats,
+ .ndo_get_devlink_port = mlx5e_get_devlink_port,
+ .ndo_get_stats64 = mlx5e_rep_get_stats,
.ndo_has_offload_stats = mlx5e_rep_has_offload_stats,
.ndo_get_offload_stats = mlx5e_rep_get_offload_stats,
- .ndo_change_mtu = mlx5e_vf_rep_change_mtu,
- .ndo_get_port_parent_id = mlx5e_rep_get_port_parent_id,
+ .ndo_change_mtu = mlx5e_rep_change_mtu,
};
static const struct net_device_ops mlx5e_netdev_ops_uplink_rep = {
@@ -1336,8 +1307,8 @@ static const struct net_device_ops mlx5e_netdev_ops_uplink_rep = {
.ndo_stop = mlx5e_close,
.ndo_start_xmit = mlx5e_xmit,
.ndo_set_mac_address = mlx5e_uplink_rep_set_mac,
- .ndo_get_phys_port_name = mlx5e_rep_get_phys_port_name,
.ndo_setup_tc = mlx5e_rep_setup_tc,
+ .ndo_get_devlink_port = mlx5e_get_devlink_port,
.ndo_get_stats64 = mlx5e_get_stats,
.ndo_has_offload_stats = mlx5e_rep_has_offload_stats,
.ndo_get_offload_stats = mlx5e_rep_get_offload_stats,
@@ -1350,12 +1321,12 @@ static const struct net_device_ops mlx5e_netdev_ops_uplink_rep = {
.ndo_get_vf_config = mlx5e_get_vf_config,
.ndo_get_vf_stats = mlx5e_get_vf_stats,
.ndo_set_vf_vlan = mlx5e_uplink_rep_set_vf_vlan,
- .ndo_get_port_parent_id = mlx5e_rep_get_port_parent_id,
+ .ndo_set_features = mlx5e_set_features,
};
bool mlx5e_eswitch_rep(struct net_device *netdev)
{
- if (netdev->netdev_ops == &mlx5e_netdev_ops_vf_rep ||
+ if (netdev->netdev_ops == &mlx5e_netdev_ops_rep ||
netdev->netdev_ops == &mlx5e_netdev_ops_uplink_rep)
return true;
@@ -1411,24 +1382,23 @@ static void mlx5e_build_rep_netdev(struct net_device *netdev)
SET_NETDEV_DEV(netdev, mdev->device);
netdev->netdev_ops = &mlx5e_netdev_ops_uplink_rep;
/* we want a persistent mac for the uplink rep */
- mlx5_query_nic_vport_mac_address(mdev, 0, netdev->dev_addr);
+ mlx5_query_mac_address(mdev, netdev->dev_addr);
netdev->ethtool_ops = &mlx5e_uplink_rep_ethtool_ops;
#ifdef CONFIG_MLX5_CORE_EN_DCB
if (MLX5_CAP_GEN(mdev, qos))
netdev->dcbnl_ops = &mlx5e_dcbnl_ops;
#endif
} else {
- netdev->netdev_ops = &mlx5e_netdev_ops_vf_rep;
+ netdev->netdev_ops = &mlx5e_netdev_ops_rep;
eth_hw_addr_random(netdev);
- netdev->ethtool_ops = &mlx5e_vf_rep_ethtool_ops;
+ netdev->ethtool_ops = &mlx5e_rep_ethtool_ops;
}
netdev->watchdog_timeo = 15 * HZ;
+ netdev->features |= NETIF_F_NETNS_LOCAL;
- netdev->features |= NETIF_F_HW_TC | NETIF_F_NETNS_LOCAL;
- netdev->hw_features |= NETIF_F_HW_TC;
-
+ netdev->hw_features |= NETIF_F_HW_TC;
netdev->hw_features |= NETIF_F_SG;
netdev->hw_features |= NETIF_F_IP_CSUM;
netdev->hw_features |= NETIF_F_IPV6_CSUM;
@@ -1437,7 +1407,9 @@ static void mlx5e_build_rep_netdev(struct net_device *netdev)
netdev->hw_features |= NETIF_F_TSO6;
netdev->hw_features |= NETIF_F_RXCSUM;
- if (rep->vport != MLX5_VPORT_UPLINK)
+ if (rep->vport == MLX5_VPORT_UPLINK)
+ netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX;
+ else
netdev->features |= NETIF_F_VLAN_CHALLENGED;
netdev->features |= netdev->hw_features;
@@ -1528,7 +1500,7 @@ static int mlx5e_init_rep_rx(struct mlx5e_priv *priv)
if (err)
goto err_close_drop_rq;
- err = mlx5e_create_direct_rqts(priv);
+ err = mlx5e_create_direct_rqts(priv, priv->direct_tir);
if (err)
goto err_destroy_indirect_rqts;
@@ -1536,7 +1508,7 @@ static int mlx5e_init_rep_rx(struct mlx5e_priv *priv)
if (err)
goto err_destroy_direct_rqts;
- err = mlx5e_create_direct_tirs(priv);
+ err = mlx5e_create_direct_tirs(priv, priv->direct_tir);
if (err)
goto err_destroy_indirect_tirs;
@@ -1553,11 +1525,11 @@ static int mlx5e_init_rep_rx(struct mlx5e_priv *priv)
err_destroy_ttc_table:
mlx5e_destroy_ttc_table(priv, &priv->fs.ttc);
err_destroy_direct_tirs:
- mlx5e_destroy_direct_tirs(priv);
+ mlx5e_destroy_direct_tirs(priv, priv->direct_tir);
err_destroy_indirect_tirs:
mlx5e_destroy_indirect_tirs(priv, false);
err_destroy_direct_rqts:
- mlx5e_destroy_direct_rqts(priv);
+ mlx5e_destroy_direct_rqts(priv, priv->direct_tir);
err_destroy_indirect_rqts:
mlx5e_destroy_rqt(priv, &priv->indir_rqt);
err_close_drop_rq:
@@ -1571,9 +1543,9 @@ static void mlx5e_cleanup_rep_rx(struct mlx5e_priv *priv)
mlx5_del_flow_rules(rpriv->vport_rx_rule);
mlx5e_destroy_ttc_table(priv, &priv->fs.ttc);
- mlx5e_destroy_direct_tirs(priv);
+ mlx5e_destroy_direct_tirs(priv, priv->direct_tir);
mlx5e_destroy_indirect_tirs(priv, false);
- mlx5e_destroy_direct_rqts(priv);
+ mlx5e_destroy_direct_rqts(priv, priv->direct_tir);
mlx5e_destroy_rqt(priv, &priv->indir_rqt);
mlx5e_close_drop_rq(&priv->drop_rq);
}
@@ -1640,11 +1612,16 @@ static void mlx5e_cleanup_rep_tx(struct mlx5e_priv *priv)
}
}
-static void mlx5e_vf_rep_enable(struct mlx5e_priv *priv)
+static void mlx5e_rep_enable(struct mlx5e_priv *priv)
{
mlx5e_set_netdev_mtu_boundaries(priv);
}
+static int mlx5e_update_rep_rx(struct mlx5e_priv *priv)
+{
+ return 0;
+}
+
static int uplink_rep_async_event(struct notifier_block *nb, unsigned long event, void *data)
{
struct mlx5e_priv *priv = container_of(nb, struct mlx5e_priv, events_nb);
@@ -1712,15 +1689,16 @@ static void mlx5e_uplink_rep_disable(struct mlx5e_priv *priv)
mlx5_lag_remove(mdev);
}
-static const struct mlx5e_profile mlx5e_vf_rep_profile = {
+static const struct mlx5e_profile mlx5e_rep_profile = {
.init = mlx5e_init_rep,
.cleanup = mlx5e_cleanup_rep,
.init_rx = mlx5e_init_rep_rx,
.cleanup_rx = mlx5e_cleanup_rep_rx,
.init_tx = mlx5e_init_rep_tx,
.cleanup_tx = mlx5e_cleanup_rep_tx,
- .enable = mlx5e_vf_rep_enable,
- .update_stats = mlx5e_vf_rep_update_hw_counters,
+ .enable = mlx5e_rep_enable,
+ .update_rx = mlx5e_update_rep_rx,
+ .update_stats = mlx5e_rep_update_hw_counters,
.rx_handlers.handle_rx_cqe = mlx5e_handle_rx_cqe_rep,
.rx_handlers.handle_rx_cqe_mpwqe = mlx5e_handle_rx_cqe_mpwrq,
.max_tc = 1,
@@ -1735,6 +1713,7 @@ static const struct mlx5e_profile mlx5e_uplink_rep_profile = {
.cleanup_tx = mlx5e_cleanup_rep_tx,
.enable = mlx5e_uplink_rep_enable,
.disable = mlx5e_uplink_rep_disable,
+ .update_rx = mlx5e_update_rep_rx,
.update_stats = mlx5e_uplink_rep_update_hw_counters,
.update_carrier = mlx5e_update_carrier,
.rx_handlers.handle_rx_cqe = mlx5e_handle_rx_cqe_rep,
@@ -1742,6 +1721,55 @@ static const struct mlx5e_profile mlx5e_uplink_rep_profile = {
.max_tc = MLX5E_MAX_NUM_TC,
};
+static bool
+is_devlink_port_supported(const struct mlx5_core_dev *dev,
+ const struct mlx5e_rep_priv *rpriv)
+{
+ return rpriv->rep->vport == MLX5_VPORT_UPLINK ||
+ rpriv->rep->vport == MLX5_VPORT_PF ||
+ mlx5_eswitch_is_vf_vport(dev->priv.eswitch, rpriv->rep->vport);
+}
+
+static int register_devlink_port(struct mlx5_core_dev *dev,
+ struct mlx5e_rep_priv *rpriv)
+{
+ struct devlink *devlink = priv_to_devlink(dev);
+ struct mlx5_eswitch_rep *rep = rpriv->rep;
+ struct netdev_phys_item_id ppid = {};
+ int ret;
+
+ if (!is_devlink_port_supported(dev, rpriv))
+ return 0;
+
+ ret = mlx5e_rep_get_port_parent_id(rpriv->netdev, &ppid);
+ if (ret)
+ return ret;
+
+ if (rep->vport == MLX5_VPORT_UPLINK)
+ devlink_port_attrs_set(&rpriv->dl_port,
+ DEVLINK_PORT_FLAVOUR_PHYSICAL,
+ PCI_FUNC(dev->pdev->devfn), false, 0,
+ &ppid.id[0], ppid.id_len);
+ else if (rep->vport == MLX5_VPORT_PF)
+ devlink_port_attrs_pci_pf_set(&rpriv->dl_port,
+ &ppid.id[0], ppid.id_len,
+ dev->pdev->devfn);
+ else if (mlx5_eswitch_is_vf_vport(dev->priv.eswitch, rpriv->rep->vport))
+ devlink_port_attrs_pci_vf_set(&rpriv->dl_port,
+ &ppid.id[0], ppid.id_len,
+ dev->pdev->devfn,
+ rep->vport - 1);
+
+ return devlink_port_register(devlink, &rpriv->dl_port, rep->vport);
+}
+
+static void unregister_devlink_port(struct mlx5_core_dev *dev,
+ struct mlx5e_rep_priv *rpriv)
+{
+ if (is_devlink_port_supported(dev, rpriv))
+ devlink_port_unregister(&rpriv->dl_port);
+}
+
/* e-Switch vport representors */
static int
mlx5e_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
@@ -1759,7 +1787,8 @@ mlx5e_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
rpriv->rep = rep;
nch = mlx5e_get_max_num_channels(dev);
- profile = (rep->vport == MLX5_VPORT_UPLINK) ? &mlx5e_uplink_rep_profile : &mlx5e_vf_rep_profile;
+ profile = (rep->vport == MLX5_VPORT_UPLINK) ?
+ &mlx5e_uplink_rep_profile : &mlx5e_rep_profile;
netdev = mlx5e_create_netdev(dev, profile, nch, rpriv);
if (!netdev) {
pr_warn("Failed to create representor netdev for vport %d\n",
@@ -1769,7 +1798,7 @@ mlx5e_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
}
rpriv->netdev = netdev;
- rep->rep_if[REP_ETH].priv = rpriv;
+ rep->rep_data[REP_ETH].priv = rpriv;
INIT_LIST_HEAD(&rpriv->vport_sqs_list);
if (rep->vport == MLX5_VPORT_UPLINK) {
@@ -1792,15 +1821,27 @@ mlx5e_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
goto err_detach_netdev;
}
+ err = register_devlink_port(dev, rpriv);
+ if (err) {
+ esw_warn(dev, "Failed to register devlink port %d\n",
+ rep->vport);
+ goto err_neigh_cleanup;
+ }
+
err = register_netdev(netdev);
if (err) {
pr_warn("Failed to register representor netdev for vport %d\n",
rep->vport);
- goto err_neigh_cleanup;
+ goto err_devlink_cleanup;
}
+ if (is_devlink_port_supported(dev, rpriv))
+ devlink_port_type_eth_set(&rpriv->dl_port, netdev);
return 0;
+err_devlink_cleanup:
+ unregister_devlink_port(dev, rpriv);
+
err_neigh_cleanup:
mlx5e_rep_neigh_cleanup(rpriv);
@@ -1823,9 +1864,13 @@ mlx5e_vport_rep_unload(struct mlx5_eswitch_rep *rep)
struct mlx5e_rep_priv *rpriv = mlx5e_rep_to_rep_priv(rep);
struct net_device *netdev = rpriv->netdev;
struct mlx5e_priv *priv = netdev_priv(netdev);
+ struct mlx5_core_dev *dev = priv->mdev;
void *ppriv = priv->ppriv;
+ if (is_devlink_port_supported(dev, rpriv))
+ devlink_port_type_clear(&rpriv->dl_port);
unregister_netdev(netdev);
+ unregister_devlink_port(dev, rpriv);
mlx5e_rep_neigh_cleanup(rpriv);
mlx5e_detach_netdev(priv);
if (rep->vport == MLX5_VPORT_UPLINK)
@@ -1843,16 +1888,17 @@ static void *mlx5e_vport_rep_get_proto_dev(struct mlx5_eswitch_rep *rep)
return rpriv->netdev;
}
+static const struct mlx5_eswitch_rep_ops rep_ops = {
+ .load = mlx5e_vport_rep_load,
+ .unload = mlx5e_vport_rep_unload,
+ .get_proto_dev = mlx5e_vport_rep_get_proto_dev
+};
+
void mlx5e_rep_register_vport_reps(struct mlx5_core_dev *mdev)
{
struct mlx5_eswitch *esw = mdev->priv.eswitch;
- struct mlx5_eswitch_rep_if rep_if = {};
-
- rep_if.load = mlx5e_vport_rep_load;
- rep_if.unload = mlx5e_vport_rep_unload;
- rep_if.get_proto_dev = mlx5e_vport_rep_get_proto_dev;
- mlx5_eswitch_register_vport_reps(esw, &rep_if, REP_ETH);
+ mlx5_eswitch_register_vport_reps(esw, &rep_ops, REP_ETH);
}
void mlx5e_rep_unregister_vport_reps(struct mlx5_core_dev *mdev)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h
index 83b573b1abac..c56e6ee4350c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h
@@ -86,12 +86,13 @@ struct mlx5e_rep_priv {
struct mlx5_flow_handle *vport_rx_rule;
struct list_head vport_sqs_list;
struct mlx5_rep_uplink_priv uplink_priv; /* valid for uplink rep */
+ struct devlink_port dl_port;
};
static inline
struct mlx5e_rep_priv *mlx5e_rep_to_rep_priv(struct mlx5_eswitch_rep *rep)
{
- return (struct mlx5e_rep_priv *)rep->rep_if[REP_ETH].priv;
+ return rep->rep_data[REP_ETH].priv;
}
struct mlx5e_neigh {
@@ -150,13 +151,12 @@ struct mlx5e_encap_entry {
struct hlist_node encap_hlist;
struct list_head flows;
u32 encap_id;
- struct ip_tunnel_info tun_info;
+ const struct ip_tunnel_info *tun_info;
unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
struct net_device *out_dev;
struct net_device *route_dev;
- int tunnel_type;
- int tunnel_hlen;
+ struct mlx5e_tc_tunnel *tunnel;
int reformat_type;
u8 flags;
char *encap_header;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
index 13133e7f088e..ac6e586d403d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -34,6 +34,7 @@
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/tcp.h>
+#include <linux/indirect_call_wrapper.h>
#include <net/ip6_checksum.h>
#include <net/page_pool.h>
#include <net/inet_ecn.h>
@@ -46,6 +47,7 @@
#include "en_accel/tls_rxtx.h"
#include "lib/clock.h"
#include "en/xdp.h"
+#include "en/xsk/rx.h"
static inline bool mlx5e_rx_hw_stamp(struct hwtstamp_config *config)
{
@@ -234,8 +236,8 @@ static inline bool mlx5e_rx_cache_get(struct mlx5e_rq *rq,
return true;
}
-static inline int mlx5e_page_alloc_mapped(struct mlx5e_rq *rq,
- struct mlx5e_dma_info *dma_info)
+static inline int mlx5e_page_alloc_pool(struct mlx5e_rq *rq,
+ struct mlx5e_dma_info *dma_info)
{
if (mlx5e_rx_cache_get(rq, dma_info))
return 0;
@@ -247,7 +249,7 @@ static inline int mlx5e_page_alloc_mapped(struct mlx5e_rq *rq,
dma_info->addr = dma_map_page(rq->pdev, dma_info->page, 0,
PAGE_SIZE, rq->buff.map_dir);
if (unlikely(dma_mapping_error(rq->pdev, dma_info->addr))) {
- put_page(dma_info->page);
+ page_pool_recycle_direct(rq->page_pool, dma_info->page);
dma_info->page = NULL;
return -ENOMEM;
}
@@ -255,13 +257,23 @@ static inline int mlx5e_page_alloc_mapped(struct mlx5e_rq *rq,
return 0;
}
+static inline int mlx5e_page_alloc(struct mlx5e_rq *rq,
+ struct mlx5e_dma_info *dma_info)
+{
+ if (rq->umem)
+ return mlx5e_xsk_page_alloc_umem(rq, dma_info);
+ else
+ return mlx5e_page_alloc_pool(rq, dma_info);
+}
+
void mlx5e_page_dma_unmap(struct mlx5e_rq *rq, struct mlx5e_dma_info *dma_info)
{
dma_unmap_page(rq->pdev, dma_info->addr, PAGE_SIZE, rq->buff.map_dir);
}
-void mlx5e_page_release(struct mlx5e_rq *rq, struct mlx5e_dma_info *dma_info,
- bool recycle)
+void mlx5e_page_release_dynamic(struct mlx5e_rq *rq,
+ struct mlx5e_dma_info *dma_info,
+ bool recycle)
{
if (likely(recycle)) {
if (mlx5e_rx_cache_put(rq, dma_info))
@@ -271,10 +283,25 @@ void mlx5e_page_release(struct mlx5e_rq *rq, struct mlx5e_dma_info *dma_info,
page_pool_recycle_direct(rq->page_pool, dma_info->page);
} else {
mlx5e_page_dma_unmap(rq, dma_info);
+ page_pool_release_page(rq->page_pool, dma_info->page);
put_page(dma_info->page);
}
}
+static inline void mlx5e_page_release(struct mlx5e_rq *rq,
+ struct mlx5e_dma_info *dma_info,
+ bool recycle)
+{
+ if (rq->umem)
+ /* The `recycle` parameter is ignored, and the page is always
+ * put into the Reuse Ring, because there is no way to return
+ * the page to the userspace when the interface goes down.
+ */
+ mlx5e_xsk_page_release(rq, dma_info);
+ else
+ mlx5e_page_release_dynamic(rq, dma_info, recycle);
+}
+
static inline int mlx5e_get_rx_frag(struct mlx5e_rq *rq,
struct mlx5e_wqe_frag_info *frag)
{
@@ -286,7 +313,7 @@ static inline int mlx5e_get_rx_frag(struct mlx5e_rq *rq,
* offset) should just use the new one without replenishing again
* by themselves.
*/
- err = mlx5e_page_alloc_mapped(rq, frag->di);
+ err = mlx5e_page_alloc(rq, frag->di);
return err;
}
@@ -352,6 +379,13 @@ static int mlx5e_alloc_rx_wqes(struct mlx5e_rq *rq, u16 ix, u8 wqe_bulk)
int err;
int i;
+ if (rq->umem) {
+ int pages_desired = wqe_bulk << rq->wqe.info.log_num_frags;
+
+ if (unlikely(!mlx5e_xsk_pages_enough_umem(rq, pages_desired)))
+ return -ENOMEM;
+ }
+
for (i = 0; i < wqe_bulk; i++) {
struct mlx5e_rx_wqe_cyc *wqe = mlx5_wq_cyc_get_wqe(wq, ix + i);
@@ -399,11 +433,17 @@ mlx5e_copy_skb_header(struct device *pdev, struct sk_buff *skb,
static void
mlx5e_free_rx_mpwqe(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi, bool recycle)
{
- const bool no_xdp_xmit =
- bitmap_empty(wi->xdp_xmit_bitmap, MLX5_MPWRQ_PAGES_PER_WQE);
+ bool no_xdp_xmit;
struct mlx5e_dma_info *dma_info = wi->umr.dma_info;
int i;
+ /* A common case for AF_XDP. */
+ if (bitmap_full(wi->xdp_xmit_bitmap, MLX5_MPWRQ_PAGES_PER_WQE))
+ return;
+
+ no_xdp_xmit = bitmap_empty(wi->xdp_xmit_bitmap,
+ MLX5_MPWRQ_PAGES_PER_WQE);
+
for (i = 0; i < MLX5_MPWRQ_PAGES_PER_WQE; i++)
if (no_xdp_xmit || !test_bit(i, wi->xdp_xmit_bitmap))
mlx5e_page_release(rq, &dma_info[i], recycle);
@@ -425,11 +465,6 @@ static void mlx5e_post_rx_mpwqe(struct mlx5e_rq *rq, u8 n)
mlx5_wq_ll_update_db_record(wq);
}
-static inline u16 mlx5e_icosq_wrap_cnt(struct mlx5e_icosq *sq)
-{
- return mlx5_wq_cyc_get_ctr_wrap_cnt(&sq->wq, sq->pc);
-}
-
static inline void mlx5e_fill_icosq_frag_edge(struct mlx5e_icosq *sq,
struct mlx5_wq_cyc *wq,
u16 pi, u16 nnops)
@@ -457,6 +492,12 @@ static int mlx5e_alloc_rx_mpwqe(struct mlx5e_rq *rq, u16 ix)
int err;
int i;
+ if (rq->umem &&
+ unlikely(!mlx5e_xsk_pages_enough_umem(rq, MLX5_MPWRQ_PAGES_PER_WQE))) {
+ err = -ENOMEM;
+ goto err;
+ }
+
pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
contig_wqebbs_room = mlx5_wq_cyc_get_contig_wqebbs(wq, pi);
if (unlikely(contig_wqebbs_room < MLX5E_UMR_WQEBBS)) {
@@ -465,12 +506,10 @@ static int mlx5e_alloc_rx_mpwqe(struct mlx5e_rq *rq, u16 ix)
}
umr_wqe = mlx5_wq_cyc_get_wqe(wq, pi);
- if (unlikely(mlx5e_icosq_wrap_cnt(sq) < 2))
- memcpy(umr_wqe, &rq->mpwqe.umr_wqe,
- offsetof(struct mlx5e_umr_wqe, inline_mtts));
+ memcpy(umr_wqe, &rq->mpwqe.umr_wqe, offsetof(struct mlx5e_umr_wqe, inline_mtts));
for (i = 0; i < MLX5_MPWRQ_PAGES_PER_WQE; i++, dma_info++) {
- err = mlx5e_page_alloc_mapped(rq, dma_info);
+ err = mlx5e_page_alloc(rq, dma_info);
if (unlikely(err))
goto err_unmap;
umr_wqe->inline_mtts[i].ptag = cpu_to_be64(dma_info->addr | MLX5_EN_WR);
@@ -485,6 +524,7 @@ static int mlx5e_alloc_rx_mpwqe(struct mlx5e_rq *rq, u16 ix)
umr_wqe->uctrl.xlt_offset = cpu_to_be16(xlt_offset);
sq->db.ico_wqe[pi].opcode = MLX5_OPCODE_UMR;
+ sq->db.ico_wqe[pi].umr.rq = rq;
sq->pc += MLX5E_UMR_WQEBBS;
sq->doorbell_cseg = &umr_wqe->ctrl;
@@ -496,6 +536,8 @@ err_unmap:
dma_info--;
mlx5e_page_release(rq, dma_info, true);
}
+
+err:
rq->stats->buff_alloc_err++;
return err;
@@ -542,11 +584,10 @@ bool mlx5e_post_rx_wqes(struct mlx5e_rq *rq)
return !!err;
}
-static void mlx5e_poll_ico_cq(struct mlx5e_cq *cq, struct mlx5e_rq *rq)
+void mlx5e_poll_ico_cq(struct mlx5e_cq *cq)
{
struct mlx5e_icosq *sq = container_of(cq, struct mlx5e_icosq, cq);
struct mlx5_cqe64 *cqe;
- u8 completed_umr = 0;
u16 sqcc;
int i;
@@ -587,7 +628,7 @@ static void mlx5e_poll_ico_cq(struct mlx5e_cq *cq, struct mlx5e_rq *rq)
if (likely(wi->opcode == MLX5_OPCODE_UMR)) {
sqcc += MLX5E_UMR_WQEBBS;
- completed_umr++;
+ wi->umr.rq->mpwqe.umr_completed++;
} else if (likely(wi->opcode == MLX5_OPCODE_NOP)) {
sqcc++;
} else {
@@ -603,24 +644,25 @@ static void mlx5e_poll_ico_cq(struct mlx5e_cq *cq, struct mlx5e_rq *rq)
sq->cc = sqcc;
mlx5_cqwq_update_db_record(&cq->wq);
-
- if (likely(completed_umr)) {
- mlx5e_post_rx_mpwqe(rq, completed_umr);
- rq->mpwqe.umr_in_progress -= completed_umr;
- }
}
bool mlx5e_post_rx_mpwqes(struct mlx5e_rq *rq)
{
struct mlx5e_icosq *sq = &rq->channel->icosq;
struct mlx5_wq_ll *wq = &rq->mpwqe.wq;
+ u8 umr_completed = rq->mpwqe.umr_completed;
+ int alloc_err = 0;
u8 missing, i;
u16 head;
if (unlikely(!test_bit(MLX5E_RQ_STATE_ENABLED, &rq->state)))
return false;
- mlx5e_poll_ico_cq(&sq->cq, rq);
+ if (umr_completed) {
+ mlx5e_post_rx_mpwqe(rq, umr_completed);
+ rq->mpwqe.umr_in_progress -= umr_completed;
+ rq->mpwqe.umr_completed = 0;
+ }
missing = mlx5_wq_ll_missing(wq) - rq->mpwqe.umr_in_progress;
@@ -634,7 +676,9 @@ bool mlx5e_post_rx_mpwqes(struct mlx5e_rq *rq)
head = rq->mpwqe.actual_wq_head;
i = missing;
do {
- if (unlikely(mlx5e_alloc_rx_mpwqe(rq, head)))
+ alloc_err = mlx5e_alloc_rx_mpwqe(rq, head);
+
+ if (unlikely(alloc_err))
break;
head = mlx5_wq_ll_get_wqe_next_ix(wq, head);
} while (--i);
@@ -648,6 +692,12 @@ bool mlx5e_post_rx_mpwqes(struct mlx5e_rq *rq)
rq->mpwqe.umr_in_progress += rq->mpwqe.umr_last_bulk;
rq->mpwqe.actual_wq_head = head;
+ /* If XSK Fill Ring doesn't have enough frames, busy poll by
+ * rescheduling the NAPI poll.
+ */
+ if (unlikely(alloc_err == -ENOMEM && rq->umem))
+ return true;
+
return false;
}
@@ -873,8 +923,14 @@ static inline void mlx5e_handle_csum(struct net_device *netdev,
if (unlikely(get_ip_proto(skb, network_depth, proto) == IPPROTO_SCTP))
goto csum_unnecessary;
+ stats->csum_complete++;
skb->ip_summed = CHECKSUM_COMPLETE;
skb->csum = csum_unfold((__force __sum16)cqe->check_sum);
+
+ if (test_bit(MLX5E_RQ_STATE_CSUM_FULL, &rq->state))
+ return; /* CQE csum covers all received bytes */
+
+ /* csum might need some fixups ...*/
if (network_depth > ETH_HLEN)
/* CQE csum is calculated from the IP header and does
* not cover VLAN headers (if present). This will add
@@ -885,7 +941,6 @@ static inline void mlx5e_handle_csum(struct net_device *netdev,
skb->csum);
mlx5e_skb_padding_csum(skb, network_depth, proto, stats);
- stats->csum_complete++;
return;
}
@@ -1016,7 +1071,7 @@ mlx5e_skb_from_cqe_linear(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe,
}
rcu_read_lock();
- consumed = mlx5e_xdp_handle(rq, di, va, &rx_headroom, &cqe_bcnt);
+ consumed = mlx5e_xdp_handle(rq, di, va, &rx_headroom, &cqe_bcnt, false);
rcu_read_unlock();
if (consumed)
return NULL; /* page/packet was consumed by XDP */
@@ -1092,7 +1147,10 @@ void mlx5e_handle_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe)
wi = get_frag(rq, ci);
cqe_bcnt = be32_to_cpu(cqe->byte_cnt);
- skb = rq->wqe.skb_from_cqe(rq, cqe, wi, cqe_bcnt);
+ skb = INDIRECT_CALL_2(rq->wqe.skb_from_cqe,
+ mlx5e_skb_from_cqe_linear,
+ mlx5e_skb_from_cqe_nonlinear,
+ rq, cqe, wi, cqe_bcnt);
if (!skb) {
/* probably for XDP */
if (__test_and_clear_bit(MLX5E_RQ_FLAG_XDP_XMIT, rq->flags)) {
@@ -1230,7 +1288,7 @@ mlx5e_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
prefetch(data);
rcu_read_lock();
- consumed = mlx5e_xdp_handle(rq, di, va, &rx_headroom, &cqe_bcnt32);
+ consumed = mlx5e_xdp_handle(rq, di, va, &rx_headroom, &cqe_bcnt32, false);
rcu_read_unlock();
if (consumed) {
if (__test_and_clear_bit(MLX5E_RQ_FLAG_XDP_XMIT, rq->flags))
@@ -1279,8 +1337,10 @@ void mlx5e_handle_rx_cqe_mpwrq(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe)
cqe_bcnt = mpwrq_get_cqe_byte_cnt(cqe);
- skb = rq->mpwqe.skb_from_cqe_mpwrq(rq, wi, cqe_bcnt, head_offset,
- page_idx);
+ skb = INDIRECT_CALL_2(rq->mpwqe.skb_from_cqe_mpwrq,
+ mlx5e_skb_from_cqe_mpwrq_linear,
+ mlx5e_skb_from_cqe_mpwrq_nonlinear,
+ rq, wi, cqe_bcnt, head_offset, page_idx);
if (!skb)
goto mpwrq_cqe_out;
@@ -1327,7 +1387,8 @@ int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget)
mlx5_cqwq_pop(cqwq);
- rq->handle_rx_cqe(rq, cqe);
+ INDIRECT_CALL_2(rq->handle_rx_cqe, mlx5e_handle_rx_cqe_mpwrq,
+ mlx5e_handle_rx_cqe, rq, cqe);
} while ((++work_done < budget) && (cqe = mlx5_cqwq_get_cqe(cqwq)));
out:
@@ -1437,7 +1498,10 @@ void mlx5i_handle_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe)
wi = get_frag(rq, ci);
cqe_bcnt = be32_to_cpu(cqe->byte_cnt);
- skb = rq->wqe.skb_from_cqe(rq, cqe, wi, cqe_bcnt);
+ skb = INDIRECT_CALL_2(rq->wqe.skb_from_cqe,
+ mlx5e_skb_from_cqe_linear,
+ mlx5e_skb_from_cqe_nonlinear,
+ rq, cqe, wi, cqe_bcnt);
if (!skb)
goto wq_free_wqe;
@@ -1469,7 +1533,10 @@ void mlx5e_ipsec_handle_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe)
wi = get_frag(rq, ci);
cqe_bcnt = be32_to_cpu(cqe->byte_cnt);
- skb = rq->wqe.skb_from_cqe(rq, cqe, wi, cqe_bcnt);
+ skb = INDIRECT_CALL_2(rq->wqe.skb_from_cqe,
+ mlx5e_skb_from_cqe_linear,
+ mlx5e_skb_from_cqe_nonlinear,
+ rq, cqe, wi, cqe_bcnt);
if (unlikely(!skb)) {
/* a DROP, save the page-reuse checks */
mlx5e_free_rx_wqe(rq, wi, true);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c b/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c
index 4382ef85488c..840ec945ccba 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c
@@ -64,7 +64,7 @@ static int mlx5e_test_health_info(struct mlx5e_priv *priv)
{
struct mlx5_core_health *health = &priv->mdev->priv.health;
- return health->sick ? 1 : 0;
+ return health->fatal_error ? 1 : 0;
}
static int mlx5e_test_link_state(struct mlx5e_priv *priv)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
index 483d321d2151..539b4d3656da 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
@@ -48,8 +48,15 @@ static const struct counter_desc sw_stats_desc[] = {
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_nop) },
#ifdef CONFIG_MLX5_EN_TLS
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tls_encrypted_packets) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tls_encrypted_bytes) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tls_ctx) },
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tls_ooo) },
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tls_resync_bytes) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tls_drop_no_sync_data) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tls_drop_bypass_req) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tls_dump_packets) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tls_dump_bytes) },
#endif
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_lro_packets) },
@@ -104,7 +111,33 @@ static const struct counter_desc sw_stats_desc[] = {
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, ch_poll) },
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, ch_arm) },
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, ch_aff_change) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, ch_force_irq) },
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, ch_eq_rearm) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_packets) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_bytes) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_csum_complete) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_csum_unnecessary) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_csum_unnecessary_inner) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_csum_none) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_ecn_mark) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_removed_vlan_packets) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_xdp_drop) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_xdp_redirect) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_wqe_err) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_mpwqe_filler_cqes) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_mpwqe_filler_strides) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_oversize_pkts_sw_drop) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_buff_alloc_err) },
+ { 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) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_xsk_full) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_xsk_err) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_xsk_cqes) },
};
#define NUM_SW_COUNTERS ARRAY_SIZE(sw_stats_desc)
@@ -144,6 +177,8 @@ static void mlx5e_grp_sw_update_stats(struct mlx5e_priv *priv)
&priv->channel_stats[i];
struct mlx5e_xdpsq_stats *xdpsq_red_stats = &channel_stats->xdpsq;
struct mlx5e_xdpsq_stats *xdpsq_stats = &channel_stats->rq_xdpsq;
+ struct mlx5e_xdpsq_stats *xsksq_stats = &channel_stats->xsksq;
+ struct mlx5e_rq_stats *xskrq_stats = &channel_stats->xskrq;
struct mlx5e_rq_stats *rq_stats = &channel_stats->rq;
struct mlx5e_ch_stats *ch_stats = &channel_stats->ch;
int j;
@@ -186,6 +221,7 @@ static void mlx5e_grp_sw_update_stats(struct mlx5e_priv *priv)
s->ch_poll += ch_stats->poll;
s->ch_arm += ch_stats->arm;
s->ch_aff_change += ch_stats->aff_change;
+ s->ch_force_irq += ch_stats->force_irq;
s->ch_eq_rearm += ch_stats->eq_rearm;
/* xdp redirect */
s->tx_xdp_xmit += xdpsq_red_stats->xmit;
@@ -194,6 +230,32 @@ static void mlx5e_grp_sw_update_stats(struct mlx5e_priv *priv)
s->tx_xdp_full += xdpsq_red_stats->full;
s->tx_xdp_err += xdpsq_red_stats->err;
s->tx_xdp_cqes += xdpsq_red_stats->cqes;
+ /* AF_XDP zero-copy */
+ s->rx_xsk_packets += xskrq_stats->packets;
+ s->rx_xsk_bytes += xskrq_stats->bytes;
+ s->rx_xsk_csum_complete += xskrq_stats->csum_complete;
+ s->rx_xsk_csum_unnecessary += xskrq_stats->csum_unnecessary;
+ s->rx_xsk_csum_unnecessary_inner += xskrq_stats->csum_unnecessary_inner;
+ s->rx_xsk_csum_none += xskrq_stats->csum_none;
+ s->rx_xsk_ecn_mark += xskrq_stats->ecn_mark;
+ s->rx_xsk_removed_vlan_packets += xskrq_stats->removed_vlan_packets;
+ s->rx_xsk_xdp_drop += xskrq_stats->xdp_drop;
+ s->rx_xsk_xdp_redirect += xskrq_stats->xdp_redirect;
+ s->rx_xsk_wqe_err += xskrq_stats->wqe_err;
+ s->rx_xsk_mpwqe_filler_cqes += xskrq_stats->mpwqe_filler_cqes;
+ s->rx_xsk_mpwqe_filler_strides += xskrq_stats->mpwqe_filler_strides;
+ s->rx_xsk_oversize_pkts_sw_drop += xskrq_stats->oversize_pkts_sw_drop;
+ s->rx_xsk_buff_alloc_err += xskrq_stats->buff_alloc_err;
+ 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;
+ s->tx_xsk_xmit += xsksq_stats->xmit;
+ s->tx_xsk_mpwqe += xsksq_stats->mpwqe;
+ s->tx_xsk_inlnw += xsksq_stats->inlnw;
+ s->tx_xsk_full += xsksq_stats->full;
+ s->tx_xsk_err += xsksq_stats->err;
+ s->tx_xsk_cqes += xsksq_stats->cqes;
for (j = 0; j < priv->max_opened_tc; j++) {
struct mlx5e_sq_stats *sq_stats = &channel_stats->sq[j];
@@ -216,8 +278,15 @@ static void mlx5e_grp_sw_update_stats(struct mlx5e_priv *priv)
s->tx_csum_none += sq_stats->csum_none;
s->tx_csum_partial += sq_stats->csum_partial;
#ifdef CONFIG_MLX5_EN_TLS
- s->tx_tls_ooo += sq_stats->tls_ooo;
- s->tx_tls_resync_bytes += sq_stats->tls_resync_bytes;
+ s->tx_tls_encrypted_packets += sq_stats->tls_encrypted_packets;
+ s->tx_tls_encrypted_bytes += sq_stats->tls_encrypted_bytes;
+ s->tx_tls_ctx += sq_stats->tls_ctx;
+ s->tx_tls_ooo += sq_stats->tls_ooo;
+ s->tx_tls_resync_bytes += sq_stats->tls_resync_bytes;
+ s->tx_tls_drop_no_sync_data += sq_stats->tls_drop_no_sync_data;
+ s->tx_tls_drop_bypass_req += sq_stats->tls_drop_bypass_req;
+ s->tx_tls_dump_bytes += sq_stats->tls_dump_bytes;
+ s->tx_tls_dump_packets += sq_stats->tls_dump_packets;
#endif
s->tx_cqes += sq_stats->cqes;
}
@@ -1238,6 +1307,16 @@ static const struct counter_desc sq_stats_desc[] = {
{ MLX5E_DECLARE_TX_STAT(struct mlx5e_sq_stats, csum_partial_inner) },
{ MLX5E_DECLARE_TX_STAT(struct mlx5e_sq_stats, added_vlan_packets) },
{ MLX5E_DECLARE_TX_STAT(struct mlx5e_sq_stats, nop) },
+#ifdef CONFIG_MLX5_EN_TLS
+ { MLX5E_DECLARE_TX_STAT(struct mlx5e_sq_stats, tls_encrypted_packets) },
+ { MLX5E_DECLARE_TX_STAT(struct mlx5e_sq_stats, tls_encrypted_bytes) },
+ { MLX5E_DECLARE_TX_STAT(struct mlx5e_sq_stats, tls_ctx) },
+ { MLX5E_DECLARE_TX_STAT(struct mlx5e_sq_stats, tls_ooo) },
+ { MLX5E_DECLARE_TX_STAT(struct mlx5e_sq_stats, tls_drop_no_sync_data) },
+ { MLX5E_DECLARE_TX_STAT(struct mlx5e_sq_stats, tls_drop_bypass_req) },
+ { MLX5E_DECLARE_TX_STAT(struct mlx5e_sq_stats, tls_dump_packets) },
+ { MLX5E_DECLARE_TX_STAT(struct mlx5e_sq_stats, tls_dump_bytes) },
+#endif
{ MLX5E_DECLARE_TX_STAT(struct mlx5e_sq_stats, csum_none) },
{ MLX5E_DECLARE_TX_STAT(struct mlx5e_sq_stats, stopped) },
{ MLX5E_DECLARE_TX_STAT(struct mlx5e_sq_stats, dropped) },
@@ -1266,11 +1345,43 @@ static const struct counter_desc xdpsq_stats_desc[] = {
{ MLX5E_DECLARE_XDPSQ_STAT(struct mlx5e_xdpsq_stats, cqes) },
};
+static const struct counter_desc xskrq_stats_desc[] = {
+ { MLX5E_DECLARE_XSKRQ_STAT(struct mlx5e_rq_stats, packets) },
+ { MLX5E_DECLARE_XSKRQ_STAT(struct mlx5e_rq_stats, bytes) },
+ { MLX5E_DECLARE_XSKRQ_STAT(struct mlx5e_rq_stats, csum_complete) },
+ { MLX5E_DECLARE_XSKRQ_STAT(struct mlx5e_rq_stats, csum_unnecessary) },
+ { MLX5E_DECLARE_XSKRQ_STAT(struct mlx5e_rq_stats, csum_unnecessary_inner) },
+ { MLX5E_DECLARE_XSKRQ_STAT(struct mlx5e_rq_stats, csum_none) },
+ { MLX5E_DECLARE_XSKRQ_STAT(struct mlx5e_rq_stats, ecn_mark) },
+ { MLX5E_DECLARE_XSKRQ_STAT(struct mlx5e_rq_stats, removed_vlan_packets) },
+ { MLX5E_DECLARE_XSKRQ_STAT(struct mlx5e_rq_stats, xdp_drop) },
+ { MLX5E_DECLARE_XSKRQ_STAT(struct mlx5e_rq_stats, xdp_redirect) },
+ { MLX5E_DECLARE_XSKRQ_STAT(struct mlx5e_rq_stats, wqe_err) },
+ { MLX5E_DECLARE_XSKRQ_STAT(struct mlx5e_rq_stats, mpwqe_filler_cqes) },
+ { MLX5E_DECLARE_XSKRQ_STAT(struct mlx5e_rq_stats, mpwqe_filler_strides) },
+ { MLX5E_DECLARE_XSKRQ_STAT(struct mlx5e_rq_stats, oversize_pkts_sw_drop) },
+ { MLX5E_DECLARE_XSKRQ_STAT(struct mlx5e_rq_stats, buff_alloc_err) },
+ { 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[] = {
+ { MLX5E_DECLARE_XSKSQ_STAT(struct mlx5e_xdpsq_stats, xmit) },
+ { MLX5E_DECLARE_XSKSQ_STAT(struct mlx5e_xdpsq_stats, mpwqe) },
+ { MLX5E_DECLARE_XSKSQ_STAT(struct mlx5e_xdpsq_stats, inlnw) },
+ { MLX5E_DECLARE_XSKSQ_STAT(struct mlx5e_xdpsq_stats, full) },
+ { MLX5E_DECLARE_XSKSQ_STAT(struct mlx5e_xdpsq_stats, err) },
+ { MLX5E_DECLARE_XSKSQ_STAT(struct mlx5e_xdpsq_stats, cqes) },
+};
+
static const struct counter_desc ch_stats_desc[] = {
{ MLX5E_DECLARE_CH_STAT(struct mlx5e_ch_stats, events) },
{ MLX5E_DECLARE_CH_STAT(struct mlx5e_ch_stats, poll) },
{ MLX5E_DECLARE_CH_STAT(struct mlx5e_ch_stats, arm) },
{ MLX5E_DECLARE_CH_STAT(struct mlx5e_ch_stats, aff_change) },
+ { MLX5E_DECLARE_CH_STAT(struct mlx5e_ch_stats, force_irq) },
{ MLX5E_DECLARE_CH_STAT(struct mlx5e_ch_stats, eq_rearm) },
};
@@ -1278,6 +1389,8 @@ static const struct counter_desc ch_stats_desc[] = {
#define NUM_SQ_STATS ARRAY_SIZE(sq_stats_desc)
#define NUM_XDPSQ_STATS ARRAY_SIZE(xdpsq_stats_desc)
#define NUM_RQ_XDPSQ_STATS ARRAY_SIZE(rq_xdpsq_stats_desc)
+#define NUM_XSKRQ_STATS ARRAY_SIZE(xskrq_stats_desc)
+#define NUM_XSKSQ_STATS ARRAY_SIZE(xsksq_stats_desc)
#define NUM_CH_STATS ARRAY_SIZE(ch_stats_desc)
static int mlx5e_grp_channels_get_num_stats(struct mlx5e_priv *priv)
@@ -1288,13 +1401,16 @@ static int mlx5e_grp_channels_get_num_stats(struct mlx5e_priv *priv)
(NUM_CH_STATS * max_nch) +
(NUM_SQ_STATS * max_nch * priv->max_opened_tc) +
(NUM_RQ_XDPSQ_STATS * max_nch) +
- (NUM_XDPSQ_STATS * max_nch);
+ (NUM_XDPSQ_STATS * max_nch) +
+ (NUM_XSKRQ_STATS * max_nch * priv->xsk.ever_used) +
+ (NUM_XSKSQ_STATS * max_nch * priv->xsk.ever_used);
}
static int mlx5e_grp_channels_fill_strings(struct mlx5e_priv *priv, u8 *data,
int idx)
{
int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
+ bool is_xsk = priv->xsk.ever_used;
int i, j, tc;
for (i = 0; i < max_nch; i++)
@@ -1306,6 +1422,9 @@ static int mlx5e_grp_channels_fill_strings(struct mlx5e_priv *priv, u8 *data,
for (j = 0; j < NUM_RQ_STATS; j++)
sprintf(data + (idx++) * ETH_GSTRING_LEN,
rq_stats_desc[j].format, i);
+ for (j = 0; j < NUM_XSKRQ_STATS * is_xsk; j++)
+ sprintf(data + (idx++) * ETH_GSTRING_LEN,
+ xskrq_stats_desc[j].format, i);
for (j = 0; j < NUM_RQ_XDPSQ_STATS; j++)
sprintf(data + (idx++) * ETH_GSTRING_LEN,
rq_xdpsq_stats_desc[j].format, i);
@@ -1318,10 +1437,14 @@ static int mlx5e_grp_channels_fill_strings(struct mlx5e_priv *priv, u8 *data,
sq_stats_desc[j].format,
priv->channel_tc2txq[i][tc]);
- for (i = 0; i < max_nch; i++)
+ for (i = 0; i < max_nch; i++) {
+ for (j = 0; j < NUM_XSKSQ_STATS * is_xsk; j++)
+ sprintf(data + (idx++) * ETH_GSTRING_LEN,
+ xsksq_stats_desc[j].format, i);
for (j = 0; j < NUM_XDPSQ_STATS; j++)
sprintf(data + (idx++) * ETH_GSTRING_LEN,
xdpsq_stats_desc[j].format, i);
+ }
return idx;
}
@@ -1330,6 +1453,7 @@ static int mlx5e_grp_channels_fill_stats(struct mlx5e_priv *priv, u64 *data,
int idx)
{
int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
+ bool is_xsk = priv->xsk.ever_used;
int i, j, tc;
for (i = 0; i < max_nch; i++)
@@ -1343,6 +1467,10 @@ static int mlx5e_grp_channels_fill_stats(struct mlx5e_priv *priv, u64 *data,
data[idx++] =
MLX5E_READ_CTR64_CPU(&priv->channel_stats[i].rq,
rq_stats_desc, j);
+ for (j = 0; j < NUM_XSKRQ_STATS * is_xsk; j++)
+ data[idx++] =
+ MLX5E_READ_CTR64_CPU(&priv->channel_stats[i].xskrq,
+ xskrq_stats_desc, j);
for (j = 0; j < NUM_RQ_XDPSQ_STATS; j++)
data[idx++] =
MLX5E_READ_CTR64_CPU(&priv->channel_stats[i].rq_xdpsq,
@@ -1356,11 +1484,16 @@ static int mlx5e_grp_channels_fill_stats(struct mlx5e_priv *priv, u64 *data,
MLX5E_READ_CTR64_CPU(&priv->channel_stats[i].sq[tc],
sq_stats_desc, j);
- for (i = 0; i < max_nch; i++)
+ for (i = 0; i < max_nch; i++) {
+ for (j = 0; j < NUM_XSKSQ_STATS * is_xsk; j++)
+ data[idx++] =
+ MLX5E_READ_CTR64_CPU(&priv->channel_stats[i].xsksq,
+ xsksq_stats_desc, j);
for (j = 0; j < NUM_XDPSQ_STATS; j++)
data[idx++] =
MLX5E_READ_CTR64_CPU(&priv->channel_stats[i].xdpsq,
xdpsq_stats_desc, j);
+ }
return idx;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
index cdddcc46971b..76ac111e14d0 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
@@ -46,6 +46,8 @@
#define MLX5E_DECLARE_TX_STAT(type, fld) "tx%d_"#fld, offsetof(type, fld)
#define MLX5E_DECLARE_XDPSQ_STAT(type, fld) "tx%d_xdp_"#fld, offsetof(type, fld)
#define MLX5E_DECLARE_RQ_XDPSQ_STAT(type, fld) "rx%d_xdp_tx_"#fld, offsetof(type, fld)
+#define MLX5E_DECLARE_XSKRQ_STAT(type, fld) "rx%d_xsk_"#fld, offsetof(type, fld)
+#define MLX5E_DECLARE_XSKSQ_STAT(type, fld) "tx%d_xsk_"#fld, offsetof(type, fld)
#define MLX5E_DECLARE_CH_STAT(type, fld) "ch%d_"#fld, offsetof(type, fld)
struct counter_desc {
@@ -116,12 +118,46 @@ struct mlx5e_sw_stats {
u64 ch_poll;
u64 ch_arm;
u64 ch_aff_change;
+ u64 ch_force_irq;
u64 ch_eq_rearm;
#ifdef CONFIG_MLX5_EN_TLS
+ u64 tx_tls_encrypted_packets;
+ u64 tx_tls_encrypted_bytes;
+ u64 tx_tls_ctx;
u64 tx_tls_ooo;
u64 tx_tls_resync_bytes;
+ u64 tx_tls_drop_no_sync_data;
+ u64 tx_tls_drop_bypass_req;
+ u64 tx_tls_dump_packets;
+ u64 tx_tls_dump_bytes;
#endif
+
+ u64 rx_xsk_packets;
+ u64 rx_xsk_bytes;
+ u64 rx_xsk_csum_complete;
+ u64 rx_xsk_csum_unnecessary;
+ u64 rx_xsk_csum_unnecessary_inner;
+ u64 rx_xsk_csum_none;
+ u64 rx_xsk_ecn_mark;
+ u64 rx_xsk_removed_vlan_packets;
+ u64 rx_xsk_xdp_drop;
+ u64 rx_xsk_xdp_redirect;
+ u64 rx_xsk_wqe_err;
+ u64 rx_xsk_mpwqe_filler_cqes;
+ u64 rx_xsk_mpwqe_filler_strides;
+ u64 rx_xsk_oversize_pkts_sw_drop;
+ u64 rx_xsk_buff_alloc_err;
+ 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;
+ u64 tx_xsk_full;
+ u64 tx_xsk_err;
+ u64 tx_xsk_cqes;
};
struct mlx5e_qcounter_stats {
@@ -227,8 +263,15 @@ struct mlx5e_sq_stats {
u64 added_vlan_packets;
u64 nop;
#ifdef CONFIG_MLX5_EN_TLS
+ u64 tls_encrypted_packets;
+ u64 tls_encrypted_bytes;
+ u64 tls_ctx;
u64 tls_ooo;
u64 tls_resync_bytes;
+ u64 tls_drop_no_sync_data;
+ u64 tls_drop_bypass_req;
+ u64 tls_dump_packets;
+ u64 tls_dump_bytes;
#endif
/* less likely accessed in data path */
u64 csum_none;
@@ -256,6 +299,7 @@ struct mlx5e_ch_stats {
u64 poll;
u64 arm;
u64 aff_change;
+ u64 force_irq;
u64 eq_rearm;
};
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index 31cd02f11499..cc096f6011d9 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -53,6 +53,7 @@
#include "en/port.h"
#include "en/tc_tun.h"
#include "lib/devcom.h"
+#include "lib/geneve.h"
struct mlx5_nic_flow_attr {
u32 action;
@@ -126,7 +127,7 @@ struct mlx5e_tc_flow {
};
struct mlx5e_tc_flow_parse_attr {
- struct ip_tunnel_info tun_info[MLX5_MAX_FLOW_FWD_VPORTS];
+ const struct ip_tunnel_info *tun_info[MLX5_MAX_FLOW_FWD_VPORTS];
struct net_device *filter_dev;
struct mlx5_flow_spec spec;
int num_mod_hdr_actions;
@@ -716,19 +717,22 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
struct mlx5e_tc_flow *flow,
struct netlink_ext_ack *extack)
{
+ struct mlx5_flow_context *flow_context = &parse_attr->spec.flow_context;
struct mlx5_nic_flow_attr *attr = flow->nic_attr;
struct mlx5_core_dev *dev = priv->mdev;
struct mlx5_flow_destination dest[2] = {};
struct mlx5_flow_act flow_act = {
.action = attr->action,
- .flow_tag = attr->flow_tag,
.reformat_id = 0,
- .flags = FLOW_ACT_HAS_TAG | FLOW_ACT_NO_APPEND,
+ .flags = FLOW_ACT_NO_APPEND,
};
struct mlx5_fc *counter = NULL;
bool table_created = false;
int err, dest_ix = 0;
+ flow_context->flags |= FLOW_CONTEXT_HAS_TAG;
+ flow_context->flow_tag = attr->flow_tag;
+
if (flow->flags & MLX5E_TC_FLOW_HAIRPIN) {
err = mlx5e_hairpin_flow_add(priv, flow, parse_attr, extack);
if (err) {
@@ -799,7 +803,7 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
}
if (attr->match_level != MLX5_MATCH_NONE)
- parse_attr->spec.match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
+ parse_attr->spec.match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
flow->rule[0] = mlx5_add_flow_rules(priv->fs.tc.t, &parse_attr->spec,
&flow_act, dest, dest_ix);
@@ -1063,6 +1067,19 @@ err_max_prio_chain:
return err;
}
+static bool mlx5_flow_has_geneve_opt(struct mlx5e_tc_flow *flow)
+{
+ struct mlx5_flow_spec *spec = &flow->esw_attr->parse_attr->spec;
+ void *headers_v = MLX5_ADDR_OF(fte_match_param,
+ spec->match_value,
+ misc_parameters_3);
+ u32 geneve_tlv_opt_0_data = MLX5_GET(fte_match_set_misc3,
+ headers_v,
+ geneve_tlv_option_0_data);
+
+ return !!geneve_tlv_opt_0_data;
+}
+
static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv,
struct mlx5e_tc_flow *flow)
{
@@ -1084,6 +1101,9 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv,
mlx5e_tc_unoffload_fdb_rules(esw, flow, attr);
}
+ if (mlx5_flow_has_geneve_opt(flow))
+ mlx5_geneve_tlv_option_del(priv->mdev->geneve);
+
mlx5_eswitch_del_vlan_action(esw, attr);
for (out_index = 0; out_index < MLX5_MAX_FLOW_FWD_VPORTS; out_index++)
@@ -1330,7 +1350,7 @@ static void mlx5e_tc_del_flow(struct mlx5e_priv *priv,
static int parse_tunnel_attr(struct mlx5e_priv *priv,
struct mlx5_flow_spec *spec,
- struct tc_cls_flower_offload *f,
+ struct flow_cls_offload *f,
struct net_device *filter_dev, u8 *match_level)
{
struct netlink_ext_ack *extack = f->common.extack;
@@ -1338,8 +1358,7 @@ static int parse_tunnel_attr(struct mlx5e_priv *priv,
outer_headers);
void *headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
outer_headers);
- struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
- struct flow_match_control enc_control;
+ struct flow_rule *rule = flow_cls_offload_flow_rule(f);
int err;
err = mlx5e_tc_tun_parse(filter_dev, priv, spec, f,
@@ -1350,9 +1369,7 @@ static int parse_tunnel_attr(struct mlx5e_priv *priv,
return err;
}
- flow_rule_match_enc_control(rule, &enc_control);
-
- if (enc_control.key->addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS)) {
struct flow_match_ipv4_addrs match;
flow_rule_match_enc_ipv4_addrs(rule, &match);
@@ -1372,7 +1389,7 @@ static int parse_tunnel_attr(struct mlx5e_priv *priv,
MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ethertype);
MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, ETH_P_IP);
- } else if (enc_control.key->addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {
+ } else if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS)) {
struct flow_match_ipv6_addrs match;
flow_rule_match_enc_ipv6_addrs(rule, &match);
@@ -1461,7 +1478,7 @@ static void *get_match_headers_value(u32 flags,
static int __parse_cls_flower(struct mlx5e_priv *priv,
struct mlx5_flow_spec *spec,
- struct tc_cls_flower_offload *f,
+ struct flow_cls_offload *f,
struct net_device *filter_dev,
u8 *match_level, u8 *tunnel_match_level)
{
@@ -1474,7 +1491,7 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
misc_parameters);
void *misc_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
misc_parameters);
- struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
+ struct flow_rule *rule = flow_cls_offload_flow_rule(f);
struct flow_dissector *dissector = rule->match.dissector;
u16 addr_type = 0;
u8 ip_proto = 0;
@@ -1482,7 +1499,8 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
*match_level = MLX5_MATCH_NONE;
if (dissector->used_keys &
- ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
+ ~(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) |
@@ -1497,29 +1515,17 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL) |
BIT(FLOW_DISSECTOR_KEY_TCP) |
BIT(FLOW_DISSECTOR_KEY_IP) |
- BIT(FLOW_DISSECTOR_KEY_ENC_IP))) {
+ BIT(FLOW_DISSECTOR_KEY_ENC_IP) |
+ BIT(FLOW_DISSECTOR_KEY_ENC_OPTS))) {
NL_SET_ERR_MSG_MOD(extack, "Unsupported key");
netdev_warn(priv->netdev, "Unsupported key used: 0x%x\n",
dissector->used_keys);
return -EOPNOTSUPP;
}
- if ((flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) ||
- flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID) ||
- flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_PORTS)) &&
- flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_CONTROL)) {
- struct flow_match_control match;
-
- flow_rule_match_enc_control(rule, &match);
- switch (match.key->addr_type) {
- case FLOW_DISSECTOR_KEY_IPV4_ADDRS:
- case FLOW_DISSECTOR_KEY_IPV6_ADDRS:
- if (parse_tunnel_attr(priv, spec, f, filter_dev, tunnel_match_level))
- return -EOPNOTSUPP;
- break;
- default:
+ if (mlx5e_get_tc_tun(filter_dev)) {
+ if (parse_tunnel_attr(priv, spec, f, filter_dev, tunnel_match_level))
return -EOPNOTSUPP;
- }
/* In decap flow, header pointers should point to the inner
* headers, outer header were already set by parse_tunnel_attr
@@ -1822,7 +1828,7 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
static int parse_cls_flower(struct mlx5e_priv *priv,
struct mlx5e_tc_flow *flow,
struct mlx5_flow_spec *spec,
- struct tc_cls_flower_offload *f,
+ struct flow_cls_offload *f,
struct net_device *filter_dev)
{
struct netlink_ext_ack *extack = f->common.extack;
@@ -2581,21 +2587,21 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv,
}
struct encap_key {
- struct ip_tunnel_key *ip_tun_key;
- int tunnel_type;
+ const struct ip_tunnel_key *ip_tun_key;
+ struct mlx5e_tc_tunnel *tc_tunnel;
};
static inline int cmp_encap_info(struct encap_key *a,
struct encap_key *b)
{
return memcmp(a->ip_tun_key, b->ip_tun_key, sizeof(*a->ip_tun_key)) ||
- a->tunnel_type != b->tunnel_type;
+ a->tc_tunnel->tunnel_type != b->tc_tunnel->tunnel_type;
}
static inline int hash_encap_info(struct encap_key *key)
{
return jhash(key->ip_tun_key, sizeof(*key->ip_tun_key),
- key->tunnel_type);
+ key->tc_tunnel->tunnel_type);
}
@@ -2625,7 +2631,7 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv,
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
struct mlx5_esw_flow_attr *attr = flow->esw_attr;
struct mlx5e_tc_flow_parse_attr *parse_attr;
- struct ip_tunnel_info *tun_info;
+ const struct ip_tunnel_info *tun_info;
struct encap_key key, e_key;
struct mlx5e_encap_entry *e;
unsigned short family;
@@ -2634,17 +2640,21 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv,
int err = 0;
parse_attr = attr->parse_attr;
- tun_info = &parse_attr->tun_info[out_index];
+ tun_info = parse_attr->tun_info[out_index];
family = ip_tunnel_info_af(tun_info);
key.ip_tun_key = &tun_info->key;
- key.tunnel_type = mlx5e_tc_tun_get_type(mirred_dev);
+ key.tc_tunnel = mlx5e_get_tc_tun(mirred_dev);
+ if (!key.tc_tunnel) {
+ NL_SET_ERR_MSG_MOD(extack, "Unsupported tunnel");
+ return -EOPNOTSUPP;
+ }
hash_key = hash_encap_info(&key);
hash_for_each_possible_rcu(esw->offloads.encap_tbl, e,
encap_hlist, hash_key) {
- e_key.ip_tun_key = &e->tun_info.key;
- e_key.tunnel_type = e->tunnel_type;
+ e_key.ip_tun_key = &e->tun_info->key;
+ e_key.tc_tunnel = e->tunnel;
if (!cmp_encap_info(&e_key, &key)) {
found = true;
break;
@@ -2659,7 +2669,7 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv,
if (!e)
return -ENOMEM;
- e->tun_info = *tun_info;
+ e->tun_info = tun_info;
err = mlx5e_tc_tun_init_encap_attr(mirred_dev, priv, e, extack);
if (err)
goto out_err;
@@ -2793,6 +2803,16 @@ static int add_vlan_pop_action(struct mlx5e_priv *priv,
return err;
}
+bool mlx5e_is_valid_eswitch_fwd_dev(struct mlx5e_priv *priv,
+ struct net_device *out_dev)
+{
+ if (is_merged_eswitch_dev(priv, out_dev))
+ return true;
+
+ return mlx5e_eswitch_rep(out_dev) &&
+ same_hw_devs(priv, netdev_priv(out_dev));
+}
+
static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
struct flow_action *flow_action,
struct mlx5e_tc_flow *flow,
@@ -2812,9 +2832,6 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
if (!flow_action_has_entries(flow_action))
return -EINVAL;
- attr->in_rep = rpriv->rep;
- attr->in_mdev = priv->mdev;
-
flow_action_for_each(i, act, flow_action) {
switch (act->id) {
case FLOW_ACTION_DROP:
@@ -2861,9 +2878,7 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
MLX5_FLOW_CONTEXT_ACTION_COUNT;
- if (netdev_port_same_parent_id(priv->netdev,
- out_dev) ||
- is_merged_eswitch_dev(priv, out_dev)) {
+ if (netdev_port_same_parent_id(priv->netdev, out_dev)) {
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
struct net_device *uplink_dev = mlx5_eswitch_uplink_get_proto_dev(esw, REP_ETH);
struct net_device *uplink_upper = netdev_master_upper_dev_get(uplink_dev);
@@ -2880,6 +2895,7 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
if (err)
return err;
}
+
if (is_vlan_dev(parse_attr->filter_dev)) {
err = add_vlan_pop_action(priv, attr,
&action);
@@ -2887,8 +2903,13 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
return err;
}
- if (!mlx5e_eswitch_rep(out_dev))
+ if (!mlx5e_is_valid_eswitch_fwd_dev(priv, out_dev)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "devices are not on same switch HW, can't offload forwarding");
+ pr_err("devices %s %s not on same switch HW, can't offload forwarding\n",
+ priv->netdev->name, out_dev->name);
return -EOPNOTSUPP;
+ }
out_priv = netdev_priv(out_dev);
rpriv = out_priv->ppriv;
@@ -2898,7 +2919,7 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
} else if (encap) {
parse_attr->mirred_ifindex[attr->out_count] =
out_dev->ifindex;
- parse_attr->tun_info[attr->out_count] = *info;
+ parse_attr->tun_info[attr->out_count] = info;
encap = false;
attr->dests[attr->out_count].flags |=
MLX5_ESW_DEST_ENCAP;
@@ -3095,7 +3116,7 @@ static bool is_peer_flow_needed(struct mlx5e_tc_flow *flow)
static int
mlx5e_alloc_flow(struct mlx5e_priv *priv, int attr_size,
- struct tc_cls_flower_offload *f, u16 flow_flags,
+ struct flow_cls_offload *f, u16 flow_flags,
struct mlx5e_tc_flow_parse_attr **__parse_attr,
struct mlx5e_tc_flow **__flow)
{
@@ -3129,7 +3150,7 @@ static void
mlx5e_flow_esw_attr_init(struct mlx5_esw_flow_attr *esw_attr,
struct mlx5e_priv *priv,
struct mlx5e_tc_flow_parse_attr *parse_attr,
- struct tc_cls_flower_offload *f,
+ struct flow_cls_offload *f,
struct mlx5_eswitch_rep *in_rep,
struct mlx5_core_dev *in_mdev)
{
@@ -3151,13 +3172,13 @@ mlx5e_flow_esw_attr_init(struct mlx5_esw_flow_attr *esw_attr,
static struct mlx5e_tc_flow *
__mlx5e_add_fdb_flow(struct mlx5e_priv *priv,
- struct tc_cls_flower_offload *f,
+ struct flow_cls_offload *f,
u16 flow_flags,
struct net_device *filter_dev,
struct mlx5_eswitch_rep *in_rep,
struct mlx5_core_dev *in_mdev)
{
- struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
+ struct flow_rule *rule = flow_cls_offload_flow_rule(f);
struct netlink_ext_ack *extack = f->common.extack;
struct mlx5e_tc_flow_parse_attr *parse_attr;
struct mlx5e_tc_flow *flow;
@@ -3201,7 +3222,7 @@ out:
return ERR_PTR(err);
}
-static int mlx5e_tc_add_fdb_peer_flow(struct tc_cls_flower_offload *f,
+static int mlx5e_tc_add_fdb_peer_flow(struct flow_cls_offload *f,
struct mlx5e_tc_flow *flow,
u16 flow_flags)
{
@@ -3253,7 +3274,7 @@ out:
static int
mlx5e_add_fdb_flow(struct mlx5e_priv *priv,
- struct tc_cls_flower_offload *f,
+ struct flow_cls_offload *f,
u16 flow_flags,
struct net_device *filter_dev,
struct mlx5e_tc_flow **__flow)
@@ -3287,12 +3308,12 @@ out:
static int
mlx5e_add_nic_flow(struct mlx5e_priv *priv,
- struct tc_cls_flower_offload *f,
+ struct flow_cls_offload *f,
u16 flow_flags,
struct net_device *filter_dev,
struct mlx5e_tc_flow **__flow)
{
- struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
+ struct flow_rule *rule = flow_cls_offload_flow_rule(f);
struct netlink_ext_ack *extack = f->common.extack;
struct mlx5e_tc_flow_parse_attr *parse_attr;
struct mlx5e_tc_flow *flow;
@@ -3338,7 +3359,7 @@ out:
static int
mlx5e_tc_add_flow(struct mlx5e_priv *priv,
- struct tc_cls_flower_offload *f,
+ struct flow_cls_offload *f,
int flags,
struct net_device *filter_dev,
struct mlx5e_tc_flow **flow)
@@ -3352,7 +3373,7 @@ mlx5e_tc_add_flow(struct mlx5e_priv *priv,
if (!tc_can_offload_extack(priv->netdev, f->common.extack))
return -EOPNOTSUPP;
- if (esw && esw->mode == SRIOV_OFFLOADS)
+ if (esw && esw->mode == MLX5_ESWITCH_OFFLOADS)
err = mlx5e_add_fdb_flow(priv, f, flow_flags,
filter_dev, flow);
else
@@ -3363,7 +3384,7 @@ mlx5e_tc_add_flow(struct mlx5e_priv *priv,
}
int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv,
- struct tc_cls_flower_offload *f, int flags)
+ struct flow_cls_offload *f, int flags)
{
struct netlink_ext_ack *extack = f->common.extack;
struct rhashtable *tc_ht = get_tc_ht(priv, flags);
@@ -3410,7 +3431,7 @@ static bool same_flow_direction(struct mlx5e_tc_flow *flow, int flags)
}
int mlx5e_delete_flower(struct net_device *dev, struct mlx5e_priv *priv,
- struct tc_cls_flower_offload *f, int flags)
+ struct flow_cls_offload *f, int flags)
{
struct rhashtable *tc_ht = get_tc_ht(priv, flags);
struct mlx5e_tc_flow *flow;
@@ -3429,7 +3450,7 @@ int mlx5e_delete_flower(struct net_device *dev, struct mlx5e_priv *priv,
}
int mlx5e_stats_flower(struct net_device *dev, struct mlx5e_priv *priv,
- struct tc_cls_flower_offload *f, int flags)
+ struct flow_cls_offload *f, int flags)
{
struct mlx5_devcom *devcom = priv->mdev->priv.devcom;
struct rhashtable *tc_ht = get_tc_ht(priv, flags);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h
index f62e81902d27..3ab39275ca7d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h
@@ -54,12 +54,12 @@ int mlx5e_tc_esw_init(struct rhashtable *tc_ht);
void mlx5e_tc_esw_cleanup(struct rhashtable *tc_ht);
int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv,
- struct tc_cls_flower_offload *f, int flags);
+ struct flow_cls_offload *f, int flags);
int mlx5e_delete_flower(struct net_device *dev, struct mlx5e_priv *priv,
- struct tc_cls_flower_offload *f, int flags);
+ struct flow_cls_offload *f, int flags);
int mlx5e_stats_flower(struct net_device *dev, struct mlx5e_priv *priv,
- struct tc_cls_flower_offload *f, int flags);
+ struct flow_cls_offload *f, int flags);
struct mlx5e_encap_entry;
void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv,
@@ -74,6 +74,9 @@ int mlx5e_tc_num_filters(struct mlx5e_priv *priv, int flags);
void mlx5e_tc_reoffload_flows_work(struct work_struct *work);
+bool mlx5e_is_valid_eswitch_fwd_dev(struct mlx5e_priv *priv,
+ struct net_device *out_dev);
+
#else /* CONFIG_MLX5_ESWITCH */
static inline int mlx5e_tc_nic_init(struct mlx5e_priv *priv) { return 0; }
static inline void mlx5e_tc_nic_cleanup(struct mlx5e_priv *priv) {}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
index 195a7d903cec..600e92cb629a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
@@ -35,55 +35,12 @@
#include <net/geneve.h>
#include <net/dsfield.h>
#include "en.h"
+#include "en/txrx.h"
#include "ipoib/ipoib.h"
#include "en_accel/en_accel.h"
+#include "en_accel/ktls.h"
#include "lib/clock.h"
-#define MLX5E_SQ_NOPS_ROOM MLX5_SEND_WQE_MAX_WQEBBS
-
-#ifndef CONFIG_MLX5_EN_TLS
-#define MLX5E_SQ_STOP_ROOM (MLX5_SEND_WQE_MAX_WQEBBS +\
- MLX5E_SQ_NOPS_ROOM)
-#else
-/* TLS offload requires MLX5E_SQ_STOP_ROOM to have
- * enough room for a resync SKB, a normal SKB and a NOP
- */
-#define MLX5E_SQ_STOP_ROOM (2 * MLX5_SEND_WQE_MAX_WQEBBS +\
- MLX5E_SQ_NOPS_ROOM)
-#endif
-
-static inline void mlx5e_tx_dma_unmap(struct device *pdev,
- struct mlx5e_sq_dma *dma)
-{
- switch (dma->type) {
- case MLX5E_DMA_MAP_SINGLE:
- dma_unmap_single(pdev, dma->addr, dma->size, DMA_TO_DEVICE);
- break;
- case MLX5E_DMA_MAP_PAGE:
- dma_unmap_page(pdev, dma->addr, dma->size, DMA_TO_DEVICE);
- break;
- default:
- WARN_ONCE(true, "mlx5e_tx_dma_unmap unknown DMA type!\n");
- }
-}
-
-static inline struct mlx5e_sq_dma *mlx5e_dma_get(struct mlx5e_txqsq *sq, u32 i)
-{
- return &sq->db.dma_fifo[i & sq->dma_fifo_mask];
-}
-
-static inline void mlx5e_dma_push(struct mlx5e_txqsq *sq,
- dma_addr_t addr,
- u32 size,
- enum mlx5e_dma_map_type map_type)
-{
- struct mlx5e_sq_dma *dma = mlx5e_dma_get(sq, sq->dma_fifo_pc++);
-
- dma->addr = addr;
- dma->size = size;
- dma->type = map_type;
-}
-
static void mlx5e_dma_unmap_wqe_err(struct mlx5e_txqsq *sq, u8 num_dma)
{
int i;
@@ -113,13 +70,13 @@ static inline int mlx5e_get_dscp_up(struct mlx5e_priv *priv, struct sk_buff *skb
u16 mlx5e_select_queue(struct net_device *dev, struct sk_buff *skb,
struct net_device *sb_dev)
{
- int channel_ix = netdev_pick_tx(dev, skb, NULL);
+ int txq_ix = netdev_pick_tx(dev, skb, NULL);
struct mlx5e_priv *priv = netdev_priv(dev);
u16 num_channels;
int up = 0;
if (!netdev_get_num_tc(dev))
- return channel_ix;
+ return txq_ix;
#ifdef CONFIG_MLX5_CORE_EN_DCB
if (priv->dcbx_dp.trust_state == MLX5_QPTS_TRUST_DSCP)
@@ -129,14 +86,14 @@ u16 mlx5e_select_queue(struct net_device *dev, struct sk_buff *skb,
if (skb_vlan_tag_present(skb))
up = skb_vlan_tag_get_prio(skb);
- /* channel_ix can be larger than num_channels since
+ /* txq_ix can be larger than num_channels since
* dev->num_real_tx_queues = num_channels * num_tc
*/
num_channels = priv->channels.params.num_channels;
- if (channel_ix >= num_channels)
- channel_ix = reciprocal_scale(channel_ix, num_channels);
+ if (txq_ix >= num_channels)
+ txq_ix = priv->txq2sq[txq_ix]->ch_ix;
- return priv->channel_tc2txq[channel_ix][up];
+ return priv->channel_tc2txq[txq_ix][up];
}
static inline int mlx5e_skb_l2_header_offset(struct sk_buff *skb)
@@ -277,23 +234,6 @@ dma_unmap_wqe_err:
return -ENOMEM;
}
-static inline void mlx5e_fill_sq_frag_edge(struct mlx5e_txqsq *sq,
- struct mlx5_wq_cyc *wq,
- u16 pi, u16 nnops)
-{
- struct mlx5e_tx_wqe_info *edge_wi, *wi = &sq->db.wqe_info[pi];
-
- edge_wi = wi + nnops;
-
- /* fill sq frag edge with nops to avoid wqe wrapping two pages */
- for (; wi < edge_wi; wi++) {
- wi->skb = NULL;
- wi->num_wqebbs = 1;
- mlx5e_post_nop(wq, sq->sqn, &sq->pc);
- }
- sq->stats->nop += nnops;
-}
-
static inline void
mlx5e_txwqe_complete(struct mlx5e_txqsq *sq, struct sk_buff *skb,
u8 opcode, u16 ds_cnt, u8 num_wqebbs, u32 num_bytes, u8 num_dma,
@@ -301,6 +241,7 @@ mlx5e_txwqe_complete(struct mlx5e_txqsq *sq, struct sk_buff *skb,
bool xmit_more)
{
struct mlx5_wq_cyc *wq = &sq->wq;
+ bool send_doorbell;
wi->num_bytes = num_bytes;
wi->num_dma = num_dma;
@@ -310,23 +251,21 @@ mlx5e_txwqe_complete(struct mlx5e_txqsq *sq, struct sk_buff *skb,
cseg->opmod_idx_opcode = cpu_to_be32((sq->pc << 8) | opcode);
cseg->qpn_ds = cpu_to_be32((sq->sqn << 8) | ds_cnt);
- netdev_tx_sent_queue(sq->txq, num_bytes);
-
if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
sq->pc += wi->num_wqebbs;
- if (unlikely(!mlx5e_wqc_has_room_for(wq, sq->cc, sq->pc, MLX5E_SQ_STOP_ROOM))) {
+ if (unlikely(!mlx5e_wqc_has_room_for(wq, sq->cc, sq->pc, sq->stop_room))) {
netif_tx_stop_queue(sq->txq);
sq->stats->stopped++;
}
- if (!xmit_more || netif_xmit_stopped(sq->txq))
+ send_doorbell = __netdev_tx_sent_queue(sq->txq, num_bytes,
+ xmit_more);
+ if (send_doorbell)
mlx5e_notify_hw(wq, sq->pc, sq->uar_map, cseg);
}
-#define INL_HDR_START_SZ (sizeof(((struct mlx5_wqe_eth_seg *)NULL)->inline_hdr.start))
-
netdev_tx_t mlx5e_sq_xmit(struct mlx5e_txqsq *sq, struct sk_buff *skb,
struct mlx5e_tx_wqe *wqe, u16 pi, bool xmit_more)
{
@@ -353,9 +292,12 @@ netdev_tx_t mlx5e_sq_xmit(struct mlx5e_txqsq *sq, struct sk_buff *skb,
num_bytes = skb->len + (skb_shinfo(skb)->gso_segs - 1) * ihs;
stats->packets += skb_shinfo(skb)->gso_segs;
} else {
+ u8 mode = mlx5e_transport_inline_tx_wqe(wqe) ?
+ MLX5_INLINE_MODE_TCP_UDP : sq->min_inline_mode;
+
opcode = MLX5_OPCODE_SEND;
mss = 0;
- ihs = mlx5e_calc_min_inline(sq->min_inline_mode, skb);
+ ihs = mlx5e_calc_min_inline(mode, skb);
num_bytes = max_t(unsigned int, skb->len, ETH_ZLEN);
stats->packets++;
}
@@ -380,11 +322,17 @@ netdev_tx_t mlx5e_sq_xmit(struct mlx5e_txqsq *sq, struct sk_buff *skb,
#ifdef CONFIG_MLX5_EN_IPSEC
struct mlx5_wqe_eth_seg cur_eth = wqe->eth;
#endif
+#ifdef CONFIG_MLX5_EN_TLS
+ struct mlx5_wqe_ctrl_seg cur_ctrl = wqe->ctrl;
+#endif
mlx5e_fill_sq_frag_edge(sq, wq, pi, contig_wqebbs_room);
- mlx5e_sq_fetch_wqe(sq, &wqe, &pi);
+ wqe = mlx5e_sq_fetch_wqe(sq, sizeof(*wqe), &pi);
#ifdef CONFIG_MLX5_EN_IPSEC
wqe->eth = cur_eth;
#endif
+#ifdef CONFIG_MLX5_EN_TLS
+ wqe->ctrl = cur_ctrl;
+#endif
}
/* fill wqe */
@@ -443,7 +391,7 @@ netdev_tx_t mlx5e_xmit(struct sk_buff *skb, struct net_device *dev)
u16 pi;
sq = priv->txq2sq[skb_get_queue_mapping(skb)];
- mlx5e_sq_fetch_wqe(sq, &wqe, &pi);
+ wqe = mlx5e_sq_fetch_wqe(sq, sizeof(*wqe), &pi);
/* might send skbs and update wqe and pi */
skb = mlx5e_accel_handle_tx(skb, sq, dev, &wqe, &pi);
@@ -531,8 +479,16 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget)
wi = &sq->db.wqe_info[ci];
skb = wi->skb;
- if (unlikely(!skb)) { /* nop */
- sqcc++;
+ if (unlikely(!skb)) {
+#ifdef CONFIG_MLX5_EN_TLS
+ if (wi->resync_dump_frag) {
+ struct mlx5e_sq_dma *dma =
+ mlx5e_dma_get(sq, dma_fifo_cc++);
+
+ mlx5e_ktls_tx_handle_resync_dump_comp(sq, wi, dma);
+ }
+#endif
+ sqcc += wi->num_wqebbs;
continue;
}
@@ -574,8 +530,7 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget)
netdev_tx_completed_queue(sq->txq, npkts, nbytes);
if (netif_tx_queue_stopped(sq->txq) &&
- mlx5e_wqc_has_room_for(&sq->wq, sq->cc, sq->pc,
- MLX5E_SQ_STOP_ROOM) &&
+ mlx5e_wqc_has_room_for(&sq->wq, sq->cc, sq->pc, sq->stop_room) &&
!test_bit(MLX5E_SQ_STATE_RECOVERING, &sq->state)) {
netif_tx_wake_queue(sq->txq);
stats->wake++;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c
index f9862bf75491..c50b6f0769c8 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c
@@ -33,6 +33,7 @@
#include <linux/irq.h>
#include "en.h"
#include "en/xdp.h"
+#include "en/xsk/tx.h"
static inline bool mlx5e_channel_no_affinity_change(struct mlx5e_channel *c)
{
@@ -48,26 +49,24 @@ static inline bool mlx5e_channel_no_affinity_change(struct mlx5e_channel *c)
static void mlx5e_handle_tx_dim(struct mlx5e_txqsq *sq)
{
struct mlx5e_sq_stats *stats = sq->stats;
- struct net_dim_sample dim_sample;
+ struct dim_sample dim_sample;
if (unlikely(!test_bit(MLX5E_SQ_STATE_AM, &sq->state)))
return;
- net_dim_sample(sq->cq.event_ctr, stats->packets, stats->bytes,
- &dim_sample);
+ dim_update_sample(sq->cq.event_ctr, stats->packets, stats->bytes, &dim_sample);
net_dim(&sq->dim, dim_sample);
}
static void mlx5e_handle_rx_dim(struct mlx5e_rq *rq)
{
struct mlx5e_rq_stats *stats = rq->stats;
- struct net_dim_sample dim_sample;
+ struct dim_sample dim_sample;
if (unlikely(!test_bit(MLX5E_RQ_STATE_AM, &rq->state)))
return;
- net_dim_sample(rq->cq.event_ctr, stats->packets, stats->bytes,
- &dim_sample);
+ dim_update_sample(rq->cq.event_ctr, stats->packets, stats->bytes, &dim_sample);
net_dim(&rq->dim, dim_sample);
}
@@ -87,7 +86,12 @@ int mlx5e_napi_poll(struct napi_struct *napi, int budget)
struct mlx5e_channel *c = container_of(napi, struct mlx5e_channel,
napi);
struct mlx5e_ch_stats *ch_stats = c->stats;
+ struct mlx5e_xdpsq *xsksq = &c->xsksq;
+ struct mlx5e_rq *xskrq = &c->xskrq;
struct mlx5e_rq *rq = &c->rq;
+ bool xsk_open = test_bit(MLX5E_CHANNEL_STATE_XSK, c->state);
+ bool aff_change = false;
+ bool busy_xsk = false;
bool busy = false;
int work_done = 0;
int i;
@@ -97,22 +101,38 @@ int mlx5e_napi_poll(struct napi_struct *napi, int budget)
for (i = 0; i < c->num_tc; i++)
busy |= mlx5e_poll_tx_cq(&c->sq[i].cq, budget);
- busy |= mlx5e_poll_xdpsq_cq(&c->xdpsq.cq, NULL);
+ busy |= mlx5e_poll_xdpsq_cq(&c->xdpsq.cq);
if (c->xdp)
- busy |= mlx5e_poll_xdpsq_cq(&rq->xdpsq.cq, rq);
+ busy |= mlx5e_poll_xdpsq_cq(&c->rq_xdpsq.cq);
if (likely(budget)) { /* budget=0 means: don't poll rx rings */
- work_done = mlx5e_poll_rx_cq(&rq->cq, budget);
+ if (xsk_open)
+ work_done = mlx5e_poll_rx_cq(&xskrq->cq, budget);
+
+ if (likely(budget - work_done))
+ work_done += mlx5e_poll_rx_cq(&rq->cq, budget - work_done);
+
busy |= work_done == budget;
}
- busy |= c->rq.post_wqes(rq);
+ mlx5e_poll_ico_cq(&c->icosq.cq);
+
+ busy |= rq->post_wqes(rq);
+ if (xsk_open) {
+ mlx5e_poll_ico_cq(&c->xskicosq.cq);
+ busy |= mlx5e_poll_xdpsq_cq(&xsksq->cq);
+ busy_xsk |= mlx5e_xsk_tx(xsksq, MLX5E_TX_XSK_POLL_BUDGET);
+ busy_xsk |= xskrq->post_wqes(xskrq);
+ }
+
+ busy |= busy_xsk;
if (busy) {
if (likely(mlx5e_channel_no_affinity_change(c)))
return budget;
ch_stats->aff_change++;
+ aff_change = true;
if (budget && work_done == budget)
work_done--;
}
@@ -133,10 +153,22 @@ int mlx5e_napi_poll(struct napi_struct *napi, int budget)
mlx5e_cq_arm(&c->icosq.cq);
mlx5e_cq_arm(&c->xdpsq.cq);
+ if (xsk_open) {
+ mlx5e_handle_rx_dim(xskrq);
+ mlx5e_cq_arm(&c->xskicosq.cq);
+ mlx5e_cq_arm(&xsksq->cq);
+ mlx5e_cq_arm(&xskrq->cq);
+ }
+
+ if (unlikely(aff_change && busy_xsk)) {
+ mlx5e_trigger_irq(&c->icosq);
+ ch_stats->force_irq++;
+ }
+
return work_done;
}
-void mlx5e_completion_event(struct mlx5_core_cq *mcq)
+void mlx5e_completion_event(struct mlx5_core_cq *mcq, struct mlx5_eqe *eqe)
{
struct mlx5e_cq *cq = container_of(mcq, struct mlx5e_cq, mcq);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
index 23883d1fa22f..41f25ea2e8d9 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
@@ -61,17 +61,21 @@ enum {
MLX5_EQ_DOORBEL_OFFSET = 0x40,
};
-struct mlx5_irq_info {
- cpumask_var_t mask;
- char name[MLX5_MAX_IRQ_NAME];
- void *context; /* dev_id provided to request_irq */
+/* budget must be smaller than MLX5_NUM_SPARE_EQE to guarantee that we update
+ * the ci before we polled all the entries in the EQ. MLX5_NUM_SPARE_EQE is
+ * used to set the EQ size, budget must be smaller than the EQ size.
+ */
+enum {
+ MLX5_EQ_POLLING_BUDGET = 128,
};
+static_assert(MLX5_EQ_POLLING_BUDGET <= MLX5_NUM_SPARE_EQE);
+
struct mlx5_eq_table {
struct list_head comp_eqs_list;
- struct mlx5_eq pages_eq;
- struct mlx5_eq cmd_eq;
- struct mlx5_eq async_eq;
+ struct mlx5_eq_async pages_eq;
+ struct mlx5_eq_async cmd_eq;
+ struct mlx5_eq_async async_eq;
struct atomic_notifier_head nh[MLX5_EVENT_TYPE_MAX];
@@ -79,11 +83,8 @@ struct mlx5_eq_table {
struct mlx5_nb cq_err_nb;
struct mutex lock; /* sync async eqs creations */
- int num_comp_vectors;
- struct mlx5_irq_info *irq_info;
-#ifdef CONFIG_RFS_ACCEL
- struct cpu_rmap *rmap;
-#endif
+ int num_comp_eqs;
+ struct mlx5_irq_table *irq_table;
};
#define MLX5_ASYNC_EVENT_MASK ((1ull << MLX5_EVENT_TYPE_PATH_MIG) | \
@@ -124,16 +125,24 @@ static struct mlx5_core_cq *mlx5_eq_cq_get(struct mlx5_eq *eq, u32 cqn)
return cq;
}
-static irqreturn_t mlx5_eq_comp_int(int irq, void *eq_ptr)
+static int mlx5_eq_comp_int(struct notifier_block *nb,
+ __always_unused unsigned long action,
+ __always_unused void *data)
{
- struct mlx5_eq_comp *eq_comp = eq_ptr;
- struct mlx5_eq *eq = eq_ptr;
+ struct mlx5_eq_comp *eq_comp =
+ container_of(nb, struct mlx5_eq_comp, irq_nb);
+ struct mlx5_eq *eq = &eq_comp->core;
struct mlx5_eqe *eqe;
- int set_ci = 0;
+ int num_eqes = 0;
u32 cqn = -1;
- while ((eqe = next_eqe_sw(eq))) {
+ eqe = next_eqe_sw(eq);
+ if (!eqe)
+ goto out;
+
+ do {
struct mlx5_core_cq *cq;
+
/* Make sure we read EQ entry contents after we've
* checked the ownership bit.
*/
@@ -144,33 +153,23 @@ static irqreturn_t mlx5_eq_comp_int(int irq, void *eq_ptr)
cq = mlx5_eq_cq_get(eq, cqn);
if (likely(cq)) {
++cq->arm_sn;
- cq->comp(cq);
+ cq->comp(cq, eqe);
mlx5_cq_put(cq);
} else {
mlx5_core_warn(eq->dev, "Completion event for bogus CQ 0x%x\n", cqn);
}
++eq->cons_index;
- ++set_ci;
- /* The HCA will think the queue has overflowed if we
- * don't tell it we've been processing events. We
- * create our EQs with MLX5_NUM_SPARE_EQE extra
- * entries, so we must update our consumer index at
- * least that often.
- */
- if (unlikely(set_ci >= MLX5_NUM_SPARE_EQE)) {
- eq_update_ci(eq, 0);
- set_ci = 0;
- }
- }
+ } while ((++num_eqes < MLX5_EQ_POLLING_BUDGET) && (eqe = next_eqe_sw(eq)));
+out:
eq_update_ci(eq, 1);
if (cqn != -1)
tasklet_schedule(&eq_comp->tasklet_ctx.task);
- return IRQ_HANDLED;
+ return 0;
}
/* Some architectures don't latch interrupts when they are disabled, so using
@@ -184,25 +183,32 @@ u32 mlx5_eq_poll_irq_disabled(struct mlx5_eq_comp *eq)
disable_irq(eq->core.irqn);
count_eqe = eq->core.cons_index;
- mlx5_eq_comp_int(eq->core.irqn, eq);
+ mlx5_eq_comp_int(&eq->irq_nb, 0, NULL);
count_eqe = eq->core.cons_index - count_eqe;
enable_irq(eq->core.irqn);
return count_eqe;
}
-static irqreturn_t mlx5_eq_async_int(int irq, void *eq_ptr)
+static int mlx5_eq_async_int(struct notifier_block *nb,
+ unsigned long action, void *data)
{
- struct mlx5_eq *eq = eq_ptr;
+ struct mlx5_eq_async *eq_async =
+ container_of(nb, struct mlx5_eq_async, irq_nb);
+ struct mlx5_eq *eq = &eq_async->core;
struct mlx5_eq_table *eqt;
struct mlx5_core_dev *dev;
struct mlx5_eqe *eqe;
- int set_ci = 0;
+ int num_eqes = 0;
dev = eq->dev;
eqt = dev->priv.eq_table;
- while ((eqe = next_eqe_sw(eq))) {
+ eqe = next_eqe_sw(eq);
+ if (!eqe)
+ goto out;
+
+ do {
/*
* Make sure we read EQ entry contents after we've
* checked the ownership bit.
@@ -217,23 +223,13 @@ static irqreturn_t mlx5_eq_async_int(int irq, void *eq_ptr)
atomic_notifier_call_chain(&eqt->nh[MLX5_EVENT_TYPE_NOTIFY_ANY], eqe->type, eqe);
++eq->cons_index;
- ++set_ci;
- /* The HCA will think the queue has overflowed if we
- * don't tell it we've been processing events. We
- * create our EQs with MLX5_NUM_SPARE_EQE extra
- * entries, so we must update our consumer index at
- * least that often.
- */
- if (unlikely(set_ci >= MLX5_NUM_SPARE_EQE)) {
- eq_update_ci(eq, 0);
- set_ci = 0;
- }
- }
+ } while ((++num_eqes < MLX5_EQ_POLLING_BUDGET) && (eqe = next_eqe_sw(eq)));
+out:
eq_update_ci(eq, 1);
- return IRQ_HANDLED;
+ return 0;
}
static void init_eq_buf(struct mlx5_eq *eq)
@@ -248,22 +244,19 @@ static void init_eq_buf(struct mlx5_eq *eq)
}
static int
-create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq, const char *name,
+create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq,
struct mlx5_eq_param *param)
{
- struct mlx5_eq_table *eq_table = dev->priv.eq_table;
struct mlx5_cq_table *cq_table = &eq->cq_table;
u32 out[MLX5_ST_SZ_DW(create_eq_out)] = {0};
struct mlx5_priv *priv = &dev->priv;
- u8 vecidx = param->index;
+ u8 vecidx = param->irq_index;
__be64 *pas;
void *eqc;
int inlen;
u32 *in;
int err;
-
- if (eq_table->irq_info[vecidx].context)
- return -EEXIST;
+ int i;
/* Init CQ table */
memset(cq_table, 0, sizeof(*cq_table));
@@ -291,10 +284,12 @@ create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq, const char *name,
mlx5_fill_page_array(&eq->buf, pas);
MLX5_SET(create_eq_in, in, opcode, MLX5_CMD_OP_CREATE_EQ);
- if (!param->mask && MLX5_CAP_GEN(dev, log_max_uctx))
+ if (!param->mask[0] && MLX5_CAP_GEN(dev, log_max_uctx))
MLX5_SET(create_eq_in, in, uid, MLX5_SHARED_RESOURCE_UID);
- MLX5_SET64(create_eq_in, in, event_bitmask, param->mask);
+ for (i = 0; i < 4; i++)
+ MLX5_ARRAY_SET64(create_eq_in, in, event_bitmask, i,
+ param->mask[i]);
eqc = MLX5_ADDR_OF(create_eq_in, in, eq_context_entry);
MLX5_SET(eqc, eqc, log_eq_size, ilog2(eq->nent));
@@ -307,34 +302,19 @@ create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq, const char *name,
if (err)
goto err_in;
- snprintf(eq_table->irq_info[vecidx].name, MLX5_MAX_IRQ_NAME, "%s@pci:%s",
- name, pci_name(dev->pdev));
- eq_table->irq_info[vecidx].context = param->context;
-
eq->vecidx = vecidx;
eq->eqn = MLX5_GET(create_eq_out, out, eq_number);
eq->irqn = pci_irq_vector(dev->pdev, vecidx);
eq->dev = dev;
eq->doorbell = priv->uar->map + MLX5_EQ_DOORBEL_OFFSET;
- err = request_irq(eq->irqn, param->handler, 0,
- eq_table->irq_info[vecidx].name, param->context);
- if (err)
- goto err_eq;
err = mlx5_debug_eq_add(dev, eq);
if (err)
- goto err_irq;
-
- /* EQs are created in ARMED state
- */
- eq_update_ci(eq, 1);
+ goto err_eq;
kvfree(in);
return 0;
-err_irq:
- free_irq(eq->irqn, eq);
-
err_eq:
mlx5_cmd_destroy_eq(dev, eq->eqn);
@@ -346,18 +326,48 @@ err_buf:
return err;
}
-static int destroy_unmap_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq)
+/**
+ * mlx5_eq_enable - Enable EQ for receiving EQEs
+ * @dev - Device which owns the eq
+ * @eq - EQ to enable
+ * @nb - notifier call block
+ * mlx5_eq_enable - must be called after EQ is created in device.
+ */
+int mlx5_eq_enable(struct mlx5_core_dev *dev, struct mlx5_eq *eq,
+ struct notifier_block *nb)
{
struct mlx5_eq_table *eq_table = dev->priv.eq_table;
- struct mlx5_irq_info *irq_info;
int err;
- irq_info = &eq_table->irq_info[eq->vecidx];
+ err = mlx5_irq_attach_nb(eq_table->irq_table, eq->vecidx, nb);
+ if (!err)
+ eq_update_ci(eq, 1);
- mlx5_debug_eq_remove(dev, eq);
+ return err;
+}
+EXPORT_SYMBOL(mlx5_eq_enable);
+
+/**
+ * mlx5_eq_disable - Enable EQ for receiving EQEs
+ * @dev - Device which owns the eq
+ * @eq - EQ to disable
+ * @nb - notifier call block
+ * mlx5_eq_disable - must be called before EQ is destroyed.
+ */
+void mlx5_eq_disable(struct mlx5_core_dev *dev, struct mlx5_eq *eq,
+ struct notifier_block *nb)
+{
+ struct mlx5_eq_table *eq_table = dev->priv.eq_table;
+
+ mlx5_irq_detach_nb(eq_table->irq_table, eq->vecidx, nb);
+}
+EXPORT_SYMBOL(mlx5_eq_disable);
+
+static int destroy_unmap_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq)
+{
+ int err;
- free_irq(eq->irqn, irq_info->context);
- irq_info->context = NULL;
+ mlx5_debug_eq_remove(dev, eq);
err = mlx5_cmd_destroy_eq(dev, eq->eqn);
if (err)
@@ -382,7 +392,7 @@ int mlx5_eq_add_cq(struct mlx5_eq *eq, struct mlx5_core_cq *cq)
return err;
}
-int mlx5_eq_del_cq(struct mlx5_eq *eq, struct mlx5_core_cq *cq)
+void mlx5_eq_del_cq(struct mlx5_eq *eq, struct mlx5_core_cq *cq)
{
struct mlx5_cq_table *table = &eq->cq_table;
struct mlx5_core_cq *tmp;
@@ -392,16 +402,14 @@ int mlx5_eq_del_cq(struct mlx5_eq *eq, struct mlx5_core_cq *cq)
spin_unlock(&table->lock);
if (!tmp) {
- mlx5_core_warn(eq->dev, "cq 0x%x not found in eq 0x%x tree\n", eq->eqn, cq->cqn);
- return -ENOENT;
- }
-
- if (tmp != cq) {
- mlx5_core_warn(eq->dev, "corruption on cqn 0x%x in eq 0x%x\n", eq->eqn, cq->cqn);
- return -EINVAL;
+ mlx5_core_dbg(eq->dev, "cq 0x%x not found in eq 0x%x tree\n",
+ eq->eqn, cq->cqn);
+ return;
}
- return 0;
+ if (tmp != cq)
+ mlx5_core_dbg(eq->dev, "corruption on cqn 0x%x in eq 0x%x\n",
+ eq->eqn, cq->cqn);
}
int mlx5_eq_table_init(struct mlx5_core_dev *dev)
@@ -423,6 +431,7 @@ int mlx5_eq_table_init(struct mlx5_core_dev *dev)
for (i = 0; i < MLX5_EVENT_TYPE_MAX; i++)
ATOMIC_INIT_NOTIFIER_HEAD(&eq_table->nh[i]);
+ eq_table->irq_table = dev->priv.irq_table;
return 0;
kvfree_eq_table:
@@ -439,19 +448,20 @@ void mlx5_eq_table_cleanup(struct mlx5_core_dev *dev)
/* Async EQs */
-static int create_async_eq(struct mlx5_core_dev *dev, const char *name,
+static int create_async_eq(struct mlx5_core_dev *dev,
struct mlx5_eq *eq, struct mlx5_eq_param *param)
{
struct mlx5_eq_table *eq_table = dev->priv.eq_table;
int err;
mutex_lock(&eq_table->lock);
- if (param->index >= MLX5_EQ_MAX_ASYNC_EQS) {
- err = -ENOSPC;
+ /* Async EQs must share irq index 0 */
+ if (param->irq_index != 0) {
+ err = -EINVAL;
goto unlock;
}
- err = create_map_eq(dev, eq, name, param);
+ err = create_map_eq(dev, eq, param);
unlock:
mutex_unlock(&eq_table->lock);
return err;
@@ -480,7 +490,7 @@ static int cq_err_event_notifier(struct notifier_block *nb,
/* type == MLX5_EVENT_TYPE_CQ_ERROR */
eqt = mlx5_nb_cof(nb, struct mlx5_eq_table, cq_err_nb);
- eq = &eqt->async_eq;
+ eq = &eqt->async_eq.core;
eqe = data;
cqn = be32_to_cpu(eqe->data.cq_err.cqn) & 0xffffff;
@@ -493,14 +503,31 @@ static int cq_err_event_notifier(struct notifier_block *nb,
return NOTIFY_OK;
}
- cq->event(cq, type);
+ if (cq->event)
+ cq->event(cq, type);
mlx5_cq_put(cq);
return NOTIFY_OK;
}
-static u64 gather_async_events_mask(struct mlx5_core_dev *dev)
+static void gather_user_async_events(struct mlx5_core_dev *dev, u64 mask[4])
+{
+ __be64 *user_unaffiliated_events;
+ __be64 *user_affiliated_events;
+ int i;
+
+ user_affiliated_events =
+ MLX5_CAP_DEV_EVENT(dev, user_affiliated_events);
+ user_unaffiliated_events =
+ MLX5_CAP_DEV_EVENT(dev, user_unaffiliated_events);
+
+ for (i = 0; i < 4; i++)
+ mask[i] |= be64_to_cpu(user_affiliated_events[i] |
+ user_unaffiliated_events[i]);
+}
+
+static void gather_async_events_mask(struct mlx5_core_dev *dev, u64 mask[4])
{
u64 async_event_mask = MLX5_ASYNC_EVENT_MASK;
@@ -533,10 +560,14 @@ static u64 gather_async_events_mask(struct mlx5_core_dev *dev)
if (MLX5_CAP_GEN(dev, max_num_of_monitor_counters))
async_event_mask |= (1ull << MLX5_EVENT_TYPE_MONITOR_COUNTER);
- if (mlx5_core_is_ecpf_esw_manager(dev))
- async_event_mask |= (1ull << MLX5_EVENT_TYPE_HOST_PARAMS_CHANGE);
+ if (mlx5_eswitch_is_funcs_handler(dev))
+ async_event_mask |=
+ (1ull << MLX5_EVENT_TYPE_ESW_FUNCTIONS_CHANGED);
- return async_event_mask;
+ mask[0] = async_event_mask;
+
+ if (MLX5_CAP_GEN(dev, event_cap))
+ gather_user_async_events(dev, mask);
}
static int create_async_eqs(struct mlx5_core_dev *dev)
@@ -548,55 +579,76 @@ static int create_async_eqs(struct mlx5_core_dev *dev)
MLX5_NB_INIT(&table->cq_err_nb, cq_err_event_notifier, CQ_ERROR);
mlx5_eq_notifier_register(dev, &table->cq_err_nb);
+ table->cmd_eq.irq_nb.notifier_call = mlx5_eq_async_int;
param = (struct mlx5_eq_param) {
- .index = MLX5_EQ_CMD_IDX,
- .mask = 1ull << MLX5_EVENT_TYPE_CMD,
+ .irq_index = 0,
.nent = MLX5_NUM_CMD_EQE,
- .context = &table->cmd_eq,
- .handler = mlx5_eq_async_int,
};
- err = create_async_eq(dev, "mlx5_cmd_eq", &table->cmd_eq, &param);
+
+ param.mask[0] = 1ull << MLX5_EVENT_TYPE_CMD;
+ err = create_async_eq(dev, &table->cmd_eq.core, &param);
if (err) {
mlx5_core_warn(dev, "failed to create cmd EQ %d\n", err);
goto err0;
}
-
+ err = mlx5_eq_enable(dev, &table->cmd_eq.core, &table->cmd_eq.irq_nb);
+ if (err) {
+ mlx5_core_warn(dev, "failed to enable cmd EQ %d\n", err);
+ goto err1;
+ }
mlx5_cmd_use_events(dev);
+ table->async_eq.irq_nb.notifier_call = mlx5_eq_async_int;
param = (struct mlx5_eq_param) {
- .index = MLX5_EQ_ASYNC_IDX,
- .mask = gather_async_events_mask(dev),
+ .irq_index = 0,
.nent = MLX5_NUM_ASYNC_EQE,
- .context = &table->async_eq,
- .handler = mlx5_eq_async_int,
};
- err = create_async_eq(dev, "mlx5_async_eq", &table->async_eq, &param);
+
+ gather_async_events_mask(dev, param.mask);
+ err = create_async_eq(dev, &table->async_eq.core, &param);
if (err) {
mlx5_core_warn(dev, "failed to create async EQ %d\n", err);
- goto err1;
+ goto err2;
+ }
+ err = mlx5_eq_enable(dev, &table->async_eq.core,
+ &table->async_eq.irq_nb);
+ if (err) {
+ mlx5_core_warn(dev, "failed to enable async EQ %d\n", err);
+ goto err3;
}
+ table->pages_eq.irq_nb.notifier_call = mlx5_eq_async_int;
param = (struct mlx5_eq_param) {
- .index = MLX5_EQ_PAGEREQ_IDX,
- .mask = 1 << MLX5_EVENT_TYPE_PAGE_REQUEST,
+ .irq_index = 0,
.nent = /* TODO: sriov max_vf + */ 1,
- .context = &table->pages_eq,
- .handler = mlx5_eq_async_int,
};
- err = create_async_eq(dev, "mlx5_pages_eq", &table->pages_eq, &param);
+
+ param.mask[0] = 1ull << MLX5_EVENT_TYPE_PAGE_REQUEST;
+ err = create_async_eq(dev, &table->pages_eq.core, &param);
if (err) {
mlx5_core_warn(dev, "failed to create pages EQ %d\n", err);
- goto err2;
+ goto err4;
+ }
+ err = mlx5_eq_enable(dev, &table->pages_eq.core,
+ &table->pages_eq.irq_nb);
+ if (err) {
+ mlx5_core_warn(dev, "failed to enable pages EQ %d\n", err);
+ goto err5;
}
return err;
+err5:
+ destroy_async_eq(dev, &table->pages_eq.core);
+err4:
+ mlx5_eq_disable(dev, &table->async_eq.core, &table->async_eq.irq_nb);
+err3:
+ destroy_async_eq(dev, &table->async_eq.core);
err2:
- destroy_async_eq(dev, &table->async_eq);
-
-err1:
mlx5_cmd_use_polling(dev);
- destroy_async_eq(dev, &table->cmd_eq);
+ mlx5_eq_disable(dev, &table->cmd_eq.core, &table->cmd_eq.irq_nb);
+err1:
+ destroy_async_eq(dev, &table->cmd_eq.core);
err0:
mlx5_eq_notifier_unregister(dev, &table->cq_err_nb);
return err;
@@ -607,19 +659,22 @@ static void destroy_async_eqs(struct mlx5_core_dev *dev)
struct mlx5_eq_table *table = dev->priv.eq_table;
int err;
- err = destroy_async_eq(dev, &table->pages_eq);
+ mlx5_eq_disable(dev, &table->pages_eq.core, &table->pages_eq.irq_nb);
+ err = destroy_async_eq(dev, &table->pages_eq.core);
if (err)
mlx5_core_err(dev, "failed to destroy pages eq, err(%d)\n",
err);
- err = destroy_async_eq(dev, &table->async_eq);
+ mlx5_eq_disable(dev, &table->async_eq.core, &table->async_eq.irq_nb);
+ err = destroy_async_eq(dev, &table->async_eq.core);
if (err)
mlx5_core_err(dev, "failed to destroy async eq, err(%d)\n",
err);
mlx5_cmd_use_polling(dev);
- err = destroy_async_eq(dev, &table->cmd_eq);
+ mlx5_eq_disable(dev, &table->cmd_eq.core, &table->cmd_eq.irq_nb);
+ err = destroy_async_eq(dev, &table->cmd_eq.core);
if (err)
mlx5_core_err(dev, "failed to destroy command eq, err(%d)\n",
err);
@@ -629,24 +684,24 @@ static void destroy_async_eqs(struct mlx5_core_dev *dev)
struct mlx5_eq *mlx5_get_async_eq(struct mlx5_core_dev *dev)
{
- return &dev->priv.eq_table->async_eq;
+ return &dev->priv.eq_table->async_eq.core;
}
void mlx5_eq_synchronize_async_irq(struct mlx5_core_dev *dev)
{
- synchronize_irq(dev->priv.eq_table->async_eq.irqn);
+ synchronize_irq(dev->priv.eq_table->async_eq.core.irqn);
}
void mlx5_eq_synchronize_cmd_irq(struct mlx5_core_dev *dev)
{
- synchronize_irq(dev->priv.eq_table->cmd_eq.irqn);
+ synchronize_irq(dev->priv.eq_table->cmd_eq.core.irqn);
}
/* Generic EQ API for mlx5_core consumers
* Needed For RDMA ODP EQ for now
*/
struct mlx5_eq *
-mlx5_eq_create_generic(struct mlx5_core_dev *dev, const char *name,
+mlx5_eq_create_generic(struct mlx5_core_dev *dev,
struct mlx5_eq_param *param)
{
struct mlx5_eq *eq = kvzalloc(sizeof(*eq), GFP_KERNEL);
@@ -655,7 +710,7 @@ mlx5_eq_create_generic(struct mlx5_core_dev *dev, const char *name,
if (!eq)
return ERR_PTR(-ENOMEM);
- err = create_async_eq(dev, name, eq, param);
+ err = create_async_eq(dev, eq, param);
if (err) {
kvfree(eq);
eq = ERR_PTR(err);
@@ -713,84 +768,14 @@ void mlx5_eq_update_ci(struct mlx5_eq *eq, u32 cc, bool arm)
}
EXPORT_SYMBOL(mlx5_eq_update_ci);
-/* Completion EQs */
-
-static int set_comp_irq_affinity_hint(struct mlx5_core_dev *mdev, int i)
-{
- struct mlx5_priv *priv = &mdev->priv;
- int vecidx = MLX5_EQ_VEC_COMP_BASE + i;
- int irq = pci_irq_vector(mdev->pdev, vecidx);
- struct mlx5_irq_info *irq_info = &priv->eq_table->irq_info[vecidx];
-
- if (!zalloc_cpumask_var(&irq_info->mask, GFP_KERNEL)) {
- mlx5_core_warn(mdev, "zalloc_cpumask_var failed");
- return -ENOMEM;
- }
-
- cpumask_set_cpu(cpumask_local_spread(i, priv->numa_node),
- irq_info->mask);
-
- if (IS_ENABLED(CONFIG_SMP) &&
- irq_set_affinity_hint(irq, irq_info->mask))
- mlx5_core_warn(mdev, "irq_set_affinity_hint failed, irq 0x%.4x", irq);
-
- return 0;
-}
-
-static void clear_comp_irq_affinity_hint(struct mlx5_core_dev *mdev, int i)
-{
- int vecidx = MLX5_EQ_VEC_COMP_BASE + i;
- struct mlx5_priv *priv = &mdev->priv;
- int irq = pci_irq_vector(mdev->pdev, vecidx);
- struct mlx5_irq_info *irq_info = &priv->eq_table->irq_info[vecidx];
-
- irq_set_affinity_hint(irq, NULL);
- free_cpumask_var(irq_info->mask);
-}
-
-static int set_comp_irq_affinity_hints(struct mlx5_core_dev *mdev)
-{
- int err;
- int i;
-
- for (i = 0; i < mdev->priv.eq_table->num_comp_vectors; i++) {
- err = set_comp_irq_affinity_hint(mdev, i);
- if (err)
- goto err_out;
- }
-
- return 0;
-
-err_out:
- for (i--; i >= 0; i--)
- clear_comp_irq_affinity_hint(mdev, i);
-
- return err;
-}
-
-static void clear_comp_irqs_affinity_hints(struct mlx5_core_dev *mdev)
-{
- int i;
-
- for (i = 0; i < mdev->priv.eq_table->num_comp_vectors; i++)
- clear_comp_irq_affinity_hint(mdev, i);
-}
-
static void destroy_comp_eqs(struct mlx5_core_dev *dev)
{
struct mlx5_eq_table *table = dev->priv.eq_table;
struct mlx5_eq_comp *eq, *n;
- clear_comp_irqs_affinity_hints(dev);
-
-#ifdef CONFIG_RFS_ACCEL
- if (table->rmap) {
- free_irq_cpu_rmap(table->rmap);
- table->rmap = NULL;
- }
-#endif
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);
@@ -802,23 +787,17 @@ static void destroy_comp_eqs(struct mlx5_core_dev *dev)
static int create_comp_eqs(struct mlx5_core_dev *dev)
{
struct mlx5_eq_table *table = dev->priv.eq_table;
- char name[MLX5_MAX_IRQ_NAME];
struct mlx5_eq_comp *eq;
- int ncomp_vec;
+ int ncomp_eqs;
int nent;
int err;
int i;
INIT_LIST_HEAD(&table->comp_eqs_list);
- ncomp_vec = table->num_comp_vectors;
+ ncomp_eqs = table->num_comp_eqs;
nent = MLX5_COMP_EQ_SIZE;
-#ifdef CONFIG_RFS_ACCEL
- table->rmap = alloc_irq_cpu_rmap(ncomp_vec);
- if (!table->rmap)
- return -ENOMEM;
-#endif
- for (i = 0; i < ncomp_vec; i++) {
- int vecidx = i + MLX5_EQ_VEC_COMP_BASE;
+ for (i = 0; i < ncomp_eqs; i++) {
+ int vecidx = i + MLX5_IRQ_VEC_COMP_BASE;
struct mlx5_eq_param param = {};
eq = kzalloc(sizeof(*eq), GFP_KERNEL);
@@ -833,33 +812,28 @@ static int create_comp_eqs(struct mlx5_core_dev *dev)
tasklet_init(&eq->tasklet_ctx.task, mlx5_cq_tasklet_cb,
(unsigned long)&eq->tasklet_ctx);
-#ifdef CONFIG_RFS_ACCEL
- irq_cpu_rmap_add(table->rmap, pci_irq_vector(dev->pdev, vecidx));
-#endif
- snprintf(name, MLX5_MAX_IRQ_NAME, "mlx5_comp%d", i);
+ eq->irq_nb.notifier_call = mlx5_eq_comp_int;
param = (struct mlx5_eq_param) {
- .index = vecidx,
- .mask = 0,
+ .irq_index = vecidx,
.nent = nent,
- .context = &eq->core,
- .handler = mlx5_eq_comp_int
};
- err = create_map_eq(dev, &eq->core, name, &param);
+ err = create_map_eq(dev, &eq->core, &param);
+ if (err) {
+ kfree(eq);
+ goto clean;
+ }
+ err = mlx5_eq_enable(dev, &eq->core, &eq->irq_nb);
if (err) {
+ destroy_unmap_eq(dev, &eq->core);
kfree(eq);
goto clean;
}
+
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 = set_comp_irq_affinity_hints(dev);
- if (err) {
- mlx5_core_err(dev, "Failed to alloc affinity hint cpumask\n");
- goto clean;
- }
-
return 0;
clean:
@@ -890,22 +864,24 @@ EXPORT_SYMBOL(mlx5_vector2eqn);
unsigned int mlx5_comp_vectors_count(struct mlx5_core_dev *dev)
{
- return dev->priv.eq_table->num_comp_vectors;
+ return dev->priv.eq_table->num_comp_eqs;
}
EXPORT_SYMBOL(mlx5_comp_vectors_count);
struct cpumask *
mlx5_comp_irq_get_affinity_mask(struct mlx5_core_dev *dev, int vector)
{
- /* TODO: consider irq_get_affinity_mask(irq) */
- return dev->priv.eq_table->irq_info[vector + MLX5_EQ_VEC_COMP_BASE].mask;
+ int vecidx = vector + MLX5_IRQ_VEC_COMP_BASE;
+
+ return mlx5_irq_get_affinity_mask(dev->priv.eq_table->irq_table,
+ vecidx);
}
EXPORT_SYMBOL(mlx5_comp_irq_get_affinity_mask);
#ifdef CONFIG_RFS_ACCEL
struct cpu_rmap *mlx5_eq_table_get_rmap(struct mlx5_core_dev *dev)
{
- return dev->priv.eq_table->rmap;
+ return mlx5_irq_get_rmap(dev->priv.eq_table->irq_table);
}
#endif
@@ -926,82 +902,19 @@ struct mlx5_eq_comp *mlx5_eqn2comp_eq(struct mlx5_core_dev *dev, int eqn)
void mlx5_core_eq_free_irqs(struct mlx5_core_dev *dev)
{
struct mlx5_eq_table *table = dev->priv.eq_table;
- int i, max_eqs;
-
- clear_comp_irqs_affinity_hints(dev);
-
-#ifdef CONFIG_RFS_ACCEL
- if (table->rmap) {
- free_irq_cpu_rmap(table->rmap);
- table->rmap = NULL;
- }
-#endif
mutex_lock(&table->lock); /* sync with create/destroy_async_eq */
- max_eqs = table->num_comp_vectors + MLX5_EQ_VEC_COMP_BASE;
- for (i = max_eqs - 1; i >= 0; i--) {
- if (!table->irq_info[i].context)
- continue;
- free_irq(pci_irq_vector(dev->pdev, i), table->irq_info[i].context);
- table->irq_info[i].context = NULL;
- }
+ mlx5_irq_table_destroy(dev);
mutex_unlock(&table->lock);
- pci_free_irq_vectors(dev->pdev);
-}
-
-static int alloc_irq_vectors(struct mlx5_core_dev *dev)
-{
- struct mlx5_priv *priv = &dev->priv;
- struct mlx5_eq_table *table = priv->eq_table;
- int num_eqs = MLX5_CAP_GEN(dev, max_num_eqs) ?
- MLX5_CAP_GEN(dev, max_num_eqs) :
- 1 << MLX5_CAP_GEN(dev, log_max_eq);
- int nvec;
- int err;
-
- nvec = MLX5_CAP_GEN(dev, num_ports) * num_online_cpus() +
- MLX5_EQ_VEC_COMP_BASE;
- nvec = min_t(int, nvec, num_eqs);
- if (nvec <= MLX5_EQ_VEC_COMP_BASE)
- return -ENOMEM;
-
- table->irq_info = kcalloc(nvec, sizeof(*table->irq_info), GFP_KERNEL);
- if (!table->irq_info)
- return -ENOMEM;
-
- nvec = pci_alloc_irq_vectors(dev->pdev, MLX5_EQ_VEC_COMP_BASE + 1,
- nvec, PCI_IRQ_MSIX);
- if (nvec < 0) {
- err = nvec;
- goto err_free_irq_info;
- }
-
- table->num_comp_vectors = nvec - MLX5_EQ_VEC_COMP_BASE;
-
- return 0;
-
-err_free_irq_info:
- kfree(table->irq_info);
- return err;
-}
-
-static void free_irq_vectors(struct mlx5_core_dev *dev)
-{
- struct mlx5_priv *priv = &dev->priv;
-
- pci_free_irq_vectors(dev->pdev);
- kfree(priv->eq_table->irq_info);
}
int mlx5_eq_table_create(struct mlx5_core_dev *dev)
{
+ struct mlx5_eq_table *eq_table = dev->priv.eq_table;
int err;
- err = alloc_irq_vectors(dev);
- if (err) {
- mlx5_core_err(dev, "alloc irq vectors failed\n");
- return err;
- }
+ eq_table->num_comp_eqs =
+ mlx5_irq_get_num_comp(eq_table->irq_table);
err = create_async_eqs(dev);
if (err) {
@@ -1019,7 +932,6 @@ int mlx5_eq_table_create(struct mlx5_core_dev *dev)
err_comp_eqs:
destroy_async_eqs(dev);
err_async_eqs:
- free_irq_vectors(dev);
return err;
}
@@ -1027,7 +939,6 @@ void mlx5_eq_table_destroy(struct mlx5_core_dev *dev)
{
destroy_comp_eqs(dev);
destroy_async_eqs(dev);
- free_irq_vectors(dev);
}
int mlx5_eq_notifier_register(struct mlx5_core_dev *dev, struct mlx5_nb *nb)
@@ -1039,6 +950,7 @@ int mlx5_eq_notifier_register(struct mlx5_core_dev *dev, struct mlx5_nb *nb)
return atomic_notifier_chain_register(&eqt->nh[nb->event_type], &nb->nb);
}
+EXPORT_SYMBOL(mlx5_eq_notifier_register);
int mlx5_eq_notifier_unregister(struct mlx5_core_dev *dev, struct mlx5_nb *nb)
{
@@ -1049,3 +961,4 @@ int mlx5_eq_notifier_unregister(struct mlx5_core_dev *dev, struct mlx5_nb *nb)
return atomic_notifier_chain_unregister(&eqt->nh[nb->event_type], &nb->nb);
}
+EXPORT_SYMBOL(mlx5_eq_notifier_unregister);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
index 6a921e24cd5e..1f3891fde2eb 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
@@ -134,6 +134,30 @@ static int modify_esw_vport_context_cmd(struct mlx5_core_dev *dev, u16 vport,
return mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
}
+int mlx5_eswitch_modify_esw_vport_context(struct mlx5_eswitch *esw, u16 vport,
+ void *in, int inlen)
+{
+ return modify_esw_vport_context_cmd(esw->dev, vport, in, inlen);
+}
+
+static int query_esw_vport_context_cmd(struct mlx5_core_dev *dev, u16 vport,
+ void *out, int outlen)
+{
+ u32 in[MLX5_ST_SZ_DW(query_esw_vport_context_in)] = {};
+
+ MLX5_SET(query_esw_vport_context_in, in, opcode,
+ MLX5_CMD_OP_QUERY_ESW_VPORT_CONTEXT);
+ MLX5_SET(modify_esw_vport_context_in, in, vport_number, vport);
+ MLX5_SET(modify_esw_vport_context_in, in, other_vport, 1);
+ return mlx5_cmd_exec(dev, in, sizeof(in), out, outlen);
+}
+
+int mlx5_eswitch_query_esw_vport_context(struct mlx5_eswitch *esw, u16 vport,
+ void *out, int outlen)
+{
+ return query_esw_vport_context_cmd(esw->dev, vport, out, outlen);
+}
+
static int modify_esw_vport_cvlan(struct mlx5_core_dev *dev, u16 vport,
u16 vlan, u8 qos, u8 set_flags)
{
@@ -473,7 +497,7 @@ static int esw_add_uc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)
fdb_add:
/* SRIOV is enabled: Forward UC MAC to vport */
- if (esw->fdb_table.legacy.fdb && esw->mode == SRIOV_LEGACY)
+ if (esw->fdb_table.legacy.fdb && esw->mode == MLX5_ESWITCH_LEGACY)
vaddr->flow_rule = esw_fdb_set_vport_rule(esw, mac, vport);
esw_debug(esw->dev, "\tADDED UC MAC: vport[%d] %pM fr(%p)\n",
@@ -873,7 +897,7 @@ static void esw_vport_change_handle_locked(struct mlx5_vport *vport)
struct mlx5_eswitch *esw = dev->priv.eswitch;
u8 mac[ETH_ALEN];
- mlx5_query_nic_vport_mac_address(dev, vport->vport, mac);
+ mlx5_query_nic_vport_mac_address(dev, vport->vport, true, mac);
esw_debug(dev, "vport[%d] Context Changed: perm mac: %pM\n",
vport->vport, mac);
@@ -939,7 +963,7 @@ int esw_vport_enable_egress_acl(struct mlx5_eswitch *esw,
vport->vport, MLX5_CAP_ESW_EGRESS_ACL(dev, log_max_ft_size));
root_ns = mlx5_get_flow_vport_acl_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_EGRESS,
- vport->vport);
+ mlx5_eswitch_vport_num_to_index(esw, vport->vport));
if (!root_ns) {
esw_warn(dev, "Failed to get E-Switch egress flow namespace for vport (%d)\n", vport->vport);
return -EOPNOTSUPP;
@@ -1057,7 +1081,7 @@ int esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw,
vport->vport, MLX5_CAP_ESW_INGRESS_ACL(dev, log_max_ft_size));
root_ns = mlx5_get_flow_vport_acl_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_INGRESS,
- vport->vport);
+ mlx5_eswitch_vport_num_to_index(esw, vport->vport));
if (!root_ns) {
esw_warn(dev, "Failed to get E-Switch ingress flow namespace for vport (%d)\n", vport->vport);
return -EOPNOTSUPP;
@@ -1168,6 +1192,8 @@ void esw_vport_cleanup_ingress_rules(struct mlx5_eswitch *esw,
vport->ingress.drop_rule = NULL;
vport->ingress.allow_rule = NULL;
+
+ esw_vport_del_ingress_acl_modify_metadata(esw, vport);
}
void esw_vport_disable_ingress_acl(struct mlx5_eswitch *esw,
@@ -1527,6 +1553,7 @@ static void esw_apply_vport_conf(struct mlx5_eswitch *esw,
struct mlx5_vport *vport)
{
u16 vport_num = vport->vport;
+ int flags;
if (esw->manager_vport == vport_num)
return;
@@ -1544,11 +1571,13 @@ static void esw_apply_vport_conf(struct mlx5_eswitch *esw,
vport->info.node_guid);
}
+ flags = (vport->info.vlan || vport->info.qos) ?
+ SET_VLAN_STRIP | SET_VLAN_INSERT : 0;
modify_esw_vport_cvlan(esw->dev, vport_num, vport->info.vlan, vport->info.qos,
- (vport->info.vlan || vport->info.qos));
+ flags);
/* Only legacy mode needs ACLs */
- if (esw->mode == SRIOV_LEGACY) {
+ if (esw->mode == MLX5_ESWITCH_LEGACY) {
esw_vport_ingress_config(esw, vport);
esw_vport_egress_config(esw, vport);
}
@@ -1600,7 +1629,7 @@ static void esw_enable_vport(struct mlx5_eswitch *esw, struct mlx5_vport *vport,
esw_debug(esw->dev, "Enabling VPORT(%d)\n", vport_num);
/* Create steering drop counters for ingress and egress ACLs */
- if (vport_num && esw->mode == SRIOV_LEGACY)
+ if (vport_num && esw->mode == MLX5_ESWITCH_LEGACY)
esw_vport_create_drop_counters(vport);
/* Restore old vport configuration */
@@ -1654,7 +1683,7 @@ static void esw_disable_vport(struct mlx5_eswitch *esw,
vport->enabled_events = 0;
esw_vport_disable_qos(esw, vport);
if (esw->manager_vport != vport_num &&
- esw->mode == SRIOV_LEGACY) {
+ esw->mode == MLX5_ESWITCH_LEGACY) {
mlx5_modify_vport_admin_state(esw->dev,
MLX5_VPORT_STATE_OP_MOD_ESW_VPORT,
vport_num, 1,
@@ -1686,54 +1715,91 @@ static int eswitch_vport_event(struct notifier_block *nb,
return NOTIFY_OK;
}
+/**
+ * mlx5_esw_query_functions - Returns raw output about functions state
+ * @dev: Pointer to device to query
+ *
+ * mlx5_esw_query_functions() allocates and returns functions changed
+ * raw output memory pointer from device on success. Otherwise returns ERR_PTR.
+ * Caller must free the memory using kvfree() when valid pointer is returned.
+ */
+const u32 *mlx5_esw_query_functions(struct mlx5_core_dev *dev)
+{
+ int outlen = MLX5_ST_SZ_BYTES(query_esw_functions_out);
+ u32 in[MLX5_ST_SZ_DW(query_esw_functions_in)] = {};
+ u32 *out;
+ int err;
+
+ out = kvzalloc(outlen, GFP_KERNEL);
+ if (!out)
+ return ERR_PTR(-ENOMEM);
+
+ MLX5_SET(query_esw_functions_in, in, opcode,
+ MLX5_CMD_OP_QUERY_ESW_FUNCTIONS);
+
+ err = mlx5_cmd_exec(dev, in, sizeof(in), out, outlen);
+ if (!err)
+ return out;
+
+ kvfree(out);
+ return ERR_PTR(err);
+}
+
+static void mlx5_eswitch_event_handlers_register(struct mlx5_eswitch *esw)
+{
+ MLX5_NB_INIT(&esw->nb, eswitch_vport_event, NIC_VPORT_CHANGE);
+ mlx5_eq_notifier_register(esw->dev, &esw->nb);
+
+ if (esw->mode == MLX5_ESWITCH_OFFLOADS && mlx5_eswitch_is_funcs_handler(esw->dev)) {
+ MLX5_NB_INIT(&esw->esw_funcs.nb, mlx5_esw_funcs_changed_handler,
+ ESW_FUNCTIONS_CHANGED);
+ mlx5_eq_notifier_register(esw->dev, &esw->esw_funcs.nb);
+ }
+}
+
+static void mlx5_eswitch_event_handlers_unregister(struct mlx5_eswitch *esw)
+{
+ if (esw->mode == MLX5_ESWITCH_OFFLOADS && mlx5_eswitch_is_funcs_handler(esw->dev))
+ mlx5_eq_notifier_unregister(esw->dev, &esw->esw_funcs.nb);
+
+ mlx5_eq_notifier_unregister(esw->dev, &esw->nb);
+
+ flush_workqueue(esw->work_queue);
+}
+
/* Public E-Switch API */
#define ESW_ALLOWED(esw) ((esw) && MLX5_ESWITCH_MANAGER((esw)->dev))
-int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs, int mode)
+int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int mode)
{
- int vf_nvports = 0, total_nvports = 0;
struct mlx5_vport *vport;
int err;
int i, enabled_events;
if (!ESW_ALLOWED(esw) ||
!MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, ft_support)) {
- esw_warn(esw->dev, "E-Switch FDB is not supported, aborting ...\n");
+ esw_warn(esw->dev, "FDB is not supported, aborting ...\n");
return -EOPNOTSUPP;
}
if (!MLX5_CAP_ESW_INGRESS_ACL(esw->dev, ft_support))
- esw_warn(esw->dev, "E-Switch ingress ACL is not supported by FW\n");
+ esw_warn(esw->dev, "ingress ACL is not supported by FW\n");
if (!MLX5_CAP_ESW_EGRESS_ACL(esw->dev, ft_support))
- esw_warn(esw->dev, "E-Switch engress ACL is not supported by FW\n");
-
- esw_info(esw->dev, "E-Switch enable SRIOV: nvfs(%d) mode (%d)\n", nvfs, mode);
-
- if (mode == SRIOV_OFFLOADS) {
- if (mlx5_core_is_ecpf_esw_manager(esw->dev)) {
- err = mlx5_query_host_params_num_vfs(esw->dev, &vf_nvports);
- if (err)
- return err;
- total_nvports = esw->total_vports;
- } else {
- vf_nvports = nvfs;
- total_nvports = nvfs + MLX5_SPECIAL_VPORTS(esw->dev);
- }
- }
+ esw_warn(esw->dev, "engress ACL is not supported by FW\n");
esw->mode = mode;
mlx5_lag_update(esw->dev);
- if (mode == SRIOV_LEGACY) {
+ if (mode == MLX5_ESWITCH_LEGACY) {
err = esw_create_legacy_table(esw);
if (err)
goto abort;
} else {
mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_ETH);
mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
- err = esw_offloads_init(esw, vf_nvports, total_nvports);
+ err = esw_offloads_init(esw);
}
if (err)
@@ -1743,11 +1809,8 @@ int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs, int mode)
if (err)
esw_warn(esw->dev, "Failed to create eswitch TSAR");
- /* Don't enable vport events when in SRIOV_OFFLOADS mode, since:
- * 1. L2 table (MPFS) is programmed by PF/VF representors netdevs set_rx_mode
- * 2. FDB/Eswitch is programmed by user space tools
- */
- enabled_events = (mode == SRIOV_LEGACY) ? SRIOV_VPORT_EVENTS : 0;
+ enabled_events = (mode == MLX5_ESWITCH_LEGACY) ? SRIOV_VPORT_EVENTS :
+ UC_ADDR_CHANGE;
/* Enable PF vport */
vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_PF);
@@ -1760,22 +1823,21 @@ int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs, int mode)
}
/* Enable VF vports */
- mlx5_esw_for_each_vf_vport(esw, i, vport, nvfs)
+ mlx5_esw_for_each_vf_vport(esw, i, vport, esw->esw_funcs.num_vfs)
esw_enable_vport(esw, vport, enabled_events);
- if (mode == SRIOV_LEGACY) {
- MLX5_NB_INIT(&esw->nb, eswitch_vport_event, NIC_VPORT_CHANGE);
- mlx5_eq_notifier_register(esw->dev, &esw->nb);
- }
+ mlx5_eswitch_event_handlers_register(esw);
+
+ esw_info(esw->dev, "Enable: mode(%s), nvfs(%d), active vports(%d)\n",
+ mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS",
+ esw->esw_funcs.num_vfs, esw->enabled_vports);
- esw_info(esw->dev, "SRIOV enabled: active vports(%d)\n",
- esw->enabled_vports);
return 0;
abort:
- esw->mode = SRIOV_NONE;
+ esw->mode = MLX5_ESWITCH_NONE;
- if (mode == SRIOV_OFFLOADS) {
+ if (mode == MLX5_ESWITCH_OFFLOADS) {
mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_ETH);
}
@@ -1783,23 +1845,22 @@ abort:
return err;
}
-void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw)
+void mlx5_eswitch_disable(struct mlx5_eswitch *esw)
{
struct esw_mc_addr *mc_promisc;
struct mlx5_vport *vport;
int old_mode;
int i;
- if (!ESW_ALLOWED(esw) || esw->mode == SRIOV_NONE)
+ if (!ESW_ALLOWED(esw) || esw->mode == MLX5_ESWITCH_NONE)
return;
- esw_info(esw->dev, "disable SRIOV: active vports(%d) mode(%d)\n",
- esw->enabled_vports, esw->mode);
+ esw_info(esw->dev, "Disable: mode(%s), nvfs(%d), active vports(%d)\n",
+ esw->mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS",
+ esw->esw_funcs.num_vfs, esw->enabled_vports);
mc_promisc = &esw->mc_promisc;
-
- if (esw->mode == SRIOV_LEGACY)
- mlx5_eq_notifier_unregister(esw->dev, &esw->nb);
+ mlx5_eswitch_event_handlers_unregister(esw);
mlx5_esw_for_all_vports(esw, i, vport)
esw_disable_vport(esw, vport);
@@ -1809,17 +1870,17 @@ void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw)
esw_destroy_tsar(esw);
- if (esw->mode == SRIOV_LEGACY)
+ if (esw->mode == MLX5_ESWITCH_LEGACY)
esw_destroy_legacy_table(esw);
- else if (esw->mode == SRIOV_OFFLOADS)
+ else if (esw->mode == MLX5_ESWITCH_OFFLOADS)
esw_offloads_cleanup(esw);
old_mode = esw->mode;
- esw->mode = SRIOV_NONE;
+ esw->mode = MLX5_ESWITCH_NONE;
mlx5_lag_update(esw->dev);
- if (old_mode == SRIOV_OFFLOADS) {
+ if (old_mode == MLX5_ESWITCH_OFFLOADS) {
mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_ETH);
}
@@ -1827,14 +1888,16 @@ void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw)
int mlx5_eswitch_init(struct mlx5_core_dev *dev)
{
- int total_vports = MLX5_TOTAL_VPORTS(dev);
struct mlx5_eswitch *esw;
struct mlx5_vport *vport;
+ int total_vports;
int err, i;
if (!MLX5_VPORT_MANAGER(dev))
return 0;
+ total_vports = mlx5_eswitch_get_total_vports(dev);
+
esw_info(dev,
"Total vports %d, per vport: max uc(%d) max mc(%d)\n",
total_vports,
@@ -1847,6 +1910,7 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev)
esw->dev = dev;
esw->manager_vport = mlx5_eswitch_manager_vport(dev);
+ esw->first_host_vport = mlx5_eswitch_first_host_vport_num(dev);
esw->work_queue = create_singlethread_workqueue("mlx5_esw_wq");
if (!esw->work_queue) {
@@ -1880,13 +1944,8 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev)
}
esw->enabled_vports = 0;
- esw->mode = SRIOV_NONE;
+ esw->mode = MLX5_ESWITCH_NONE;
esw->offloads.inline_mode = MLX5_INLINE_MODE_NONE;
- if (MLX5_CAP_ESW_FLOWTABLE_FDB(dev, reformat) &&
- MLX5_CAP_ESW_FLOWTABLE_FDB(dev, decap))
- esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_BASIC;
- else
- esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_NONE;
dev->priv.eswitch = esw;
return 0;
@@ -1950,7 +2009,7 @@ int mlx5_eswitch_set_vport_mac(struct mlx5_eswitch *esw,
ether_addr_copy(evport->info.mac, mac);
evport->info.node_guid = node_guid;
- if (evport->enabled && esw->mode == SRIOV_LEGACY)
+ if (evport->enabled && esw->mode == MLX5_ESWITCH_LEGACY)
err = esw_vport_ingress_config(esw, evport);
unlock:
@@ -2034,7 +2093,7 @@ int __mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch *esw,
evport->info.vlan = vlan;
evport->info.qos = qos;
- if (evport->enabled && esw->mode == SRIOV_LEGACY) {
+ if (evport->enabled && esw->mode == MLX5_ESWITCH_LEGACY) {
err = esw_vport_ingress_config(esw, evport);
if (err)
goto unlock;
@@ -2076,7 +2135,7 @@ int mlx5_eswitch_set_vport_spoofchk(struct mlx5_eswitch *esw,
mlx5_core_warn(esw->dev,
"Spoofchk in set while MAC is invalid, vport(%d)\n",
evport->vport);
- if (evport->enabled && esw->mode == SRIOV_LEGACY)
+ if (evport->enabled && esw->mode == MLX5_ESWITCH_LEGACY)
err = esw_vport_ingress_config(esw, evport);
if (err)
evport->info.spoofchk = pschk;
@@ -2172,7 +2231,7 @@ int mlx5_eswitch_set_vepa(struct mlx5_eswitch *esw, u8 setting)
return -EPERM;
mutex_lock(&esw->state_lock);
- if (esw->mode != SRIOV_LEGACY) {
+ if (esw->mode != MLX5_ESWITCH_LEGACY) {
err = -EOPNOTSUPP;
goto out;
}
@@ -2195,7 +2254,7 @@ int mlx5_eswitch_get_vepa(struct mlx5_eswitch *esw, u8 *setting)
return -EPERM;
mutex_lock(&esw->state_lock);
- if (esw->mode != SRIOV_LEGACY) {
+ if (esw->mode != MLX5_ESWITCH_LEGACY) {
err = -EOPNOTSUPP;
goto out;
}
@@ -2338,7 +2397,7 @@ static int mlx5_eswitch_query_vport_drop_stats(struct mlx5_core_dev *dev,
u64 bytes = 0;
int err = 0;
- if (!vport->enabled || esw->mode != SRIOV_LEGACY)
+ if (!vport->enabled || esw->mode != MLX5_ESWITCH_LEGACY)
return 0;
if (vport->egress.drop_counter)
@@ -2391,7 +2450,6 @@ int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw,
MLX5_SET(query_vport_counter_in, in, vport_number, vport->vport);
MLX5_SET(query_vport_counter_in, in, other_vport, 1);
- memset(out, 0, outlen);
err = mlx5_cmd_exec(esw->dev, in, sizeof(in), out, outlen);
if (err)
goto free_out;
@@ -2448,16 +2506,27 @@ free_out:
u8 mlx5_eswitch_mode(struct mlx5_eswitch *esw)
{
- return ESW_ALLOWED(esw) ? esw->mode : SRIOV_NONE;
+ return ESW_ALLOWED(esw) ? esw->mode : MLX5_ESWITCH_NONE;
}
EXPORT_SYMBOL_GPL(mlx5_eswitch_mode);
+enum devlink_eswitch_encap_mode
+mlx5_eswitch_get_encap_mode(const struct mlx5_core_dev *dev)
+{
+ struct mlx5_eswitch *esw;
+
+ esw = dev->priv.eswitch;
+ return ESW_ALLOWED(esw) ? esw->offloads.encap :
+ DEVLINK_ESWITCH_ENCAP_MODE_NONE;
+}
+EXPORT_SYMBOL(mlx5_eswitch_get_encap_mode);
+
bool mlx5_esw_lag_prereq(struct mlx5_core_dev *dev0, struct mlx5_core_dev *dev1)
{
- if ((dev0->priv.eswitch->mode == SRIOV_NONE &&
- dev1->priv.eswitch->mode == SRIOV_NONE) ||
- (dev0->priv.eswitch->mode == SRIOV_OFFLOADS &&
- dev1->priv.eswitch->mode == SRIOV_OFFLOADS))
+ if ((dev0->priv.eswitch->mode == MLX5_ESWITCH_NONE &&
+ dev1->priv.eswitch->mode == MLX5_ESWITCH_NONE) ||
+ (dev0->priv.eswitch->mode == MLX5_ESWITCH_OFFLOADS &&
+ dev1->priv.eswitch->mode == MLX5_ESWITCH_OFFLOADS))
return true;
return false;
@@ -2466,6 +2535,26 @@ bool mlx5_esw_lag_prereq(struct mlx5_core_dev *dev0, struct mlx5_core_dev *dev1)
bool mlx5_esw_multipath_prereq(struct mlx5_core_dev *dev0,
struct mlx5_core_dev *dev1)
{
- return (dev0->priv.eswitch->mode == SRIOV_OFFLOADS &&
- dev1->priv.eswitch->mode == SRIOV_OFFLOADS);
+ return (dev0->priv.eswitch->mode == MLX5_ESWITCH_OFFLOADS &&
+ dev1->priv.eswitch->mode == MLX5_ESWITCH_OFFLOADS);
+}
+
+void mlx5_eswitch_update_num_of_vfs(struct mlx5_eswitch *esw, const int num_vfs)
+{
+ const u32 *out;
+
+ WARN_ON_ONCE(esw->mode != MLX5_ESWITCH_NONE);
+
+ if (!mlx5_core_is_ecpf_esw_manager(esw->dev)) {
+ esw->esw_funcs.num_vfs = num_vfs;
+ return;
+ }
+
+ out = mlx5_esw_query_functions(esw->dev);
+ if (IS_ERR(out))
+ return;
+
+ esw->esw_funcs.num_vfs = MLX5_GET(query_esw_functions_out, out,
+ host_params_context.host_num_of_vfs);
+ kvfree(out);
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
index d043d6f9797d..a38e8a3c7c9a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
@@ -68,6 +68,8 @@ struct vport_ingress {
struct mlx5_flow_group *allow_spoofchk_only_grp;
struct mlx5_flow_group *allow_untagged_only_grp;
struct mlx5_flow_group *drop_grp;
+ int modify_metadata_id;
+ struct mlx5_flow_handle *modify_metadata_rule;
struct mlx5_flow_handle *allow_rule;
struct mlx5_flow_handle *drop_rule;
struct mlx5_fc *drop_counter;
@@ -173,9 +175,12 @@ struct mlx5_esw_offload {
struct mutex peer_mutex;
DECLARE_HASHTABLE(encap_tbl, 8);
DECLARE_HASHTABLE(mod_hdr_tbl, 8);
+ DECLARE_HASHTABLE(termtbl_tbl, 8);
+ struct mutex termtbl_mutex; /* protects termtbl hash */
+ const struct mlx5_eswitch_rep_ops *rep_ops[NUM_REP_TYPES];
u8 inline_mode;
u64 num_flows;
- u8 encap;
+ enum devlink_eswitch_encap_mode encap;
};
/* E-Switch MC FDB table hash node */
@@ -190,11 +195,15 @@ struct mlx5_host_work {
struct mlx5_eswitch *esw;
};
-struct mlx5_host_info {
+struct mlx5_esw_functions {
struct mlx5_nb nb;
u16 num_vfs;
};
+enum {
+ MLX5_ESWITCH_VPORT_MATCH_METADATA = BIT(0),
+};
+
struct mlx5_eswitch {
struct mlx5_core_dev *dev;
struct mlx5_nb nb;
@@ -202,6 +211,7 @@ struct mlx5_eswitch {
struct hlist_head mc_table[MLX5_L2_ADDR_HASH_SIZE];
struct workqueue_struct *work_queue;
struct mlx5_vport *vports;
+ u32 flags;
int total_vports;
int enabled_vports;
/* Synchronize between vport change events
@@ -219,12 +229,12 @@ struct mlx5_eswitch {
int mode;
int nvports;
u16 manager_vport;
- struct mlx5_host_info host_info;
+ u16 first_host_vport;
+ struct mlx5_esw_functions esw_funcs;
};
void esw_offloads_cleanup(struct mlx5_eswitch *esw);
-int esw_offloads_init(struct mlx5_eswitch *esw, int vf_nvports,
- int total_nvports);
+int esw_offloads_init(struct mlx5_eswitch *esw);
void esw_offloads_cleanup_reps(struct mlx5_eswitch *esw);
int esw_offloads_init_reps(struct mlx5_eswitch *esw);
void esw_vport_cleanup_ingress_rules(struct mlx5_eswitch *esw,
@@ -239,12 +249,14 @@ void esw_vport_disable_egress_acl(struct mlx5_eswitch *esw,
struct mlx5_vport *vport);
void esw_vport_disable_ingress_acl(struct mlx5_eswitch *esw,
struct mlx5_vport *vport);
+void esw_vport_del_ingress_acl_modify_metadata(struct mlx5_eswitch *esw,
+ struct mlx5_vport *vport);
/* E-Switch API */
int mlx5_eswitch_init(struct mlx5_core_dev *dev);
void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw);
-int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs, int mode);
-void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw);
+int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int mode);
+void mlx5_eswitch_disable(struct mlx5_eswitch *esw);
int mlx5_eswitch_set_vport_mac(struct mlx5_eswitch *esw,
u16 vport, u8 mac[ETH_ALEN]);
int mlx5_eswitch_set_vport_state(struct mlx5_eswitch *esw,
@@ -266,8 +278,32 @@ int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw,
struct ifla_vf_stats *vf_stats);
void mlx5_eswitch_del_send_to_vport_rule(struct mlx5_flow_handle *rule);
+int mlx5_eswitch_modify_esw_vport_context(struct mlx5_eswitch *esw, u16 vport,
+ void *in, int inlen);
+int mlx5_eswitch_query_esw_vport_context(struct mlx5_eswitch *esw, u16 vport,
+ void *out, int outlen);
+
struct mlx5_flow_spec;
struct mlx5_esw_flow_attr;
+struct mlx5_termtbl_handle;
+
+bool
+mlx5_eswitch_termtbl_required(struct mlx5_eswitch *esw,
+ struct mlx5_flow_act *flow_act,
+ struct mlx5_flow_spec *spec);
+
+struct mlx5_flow_handle *
+mlx5_eswitch_add_termtbl_rule(struct mlx5_eswitch *esw,
+ struct mlx5_flow_table *ft,
+ struct mlx5_flow_spec *spec,
+ struct mlx5_esw_flow_attr *attr,
+ struct mlx5_flow_act *flow_act,
+ struct mlx5_flow_destination *dest,
+ int num_dest);
+
+void
+mlx5_eswitch_termtbl_put(struct mlx5_eswitch *esw,
+ struct mlx5_termtbl_handle *tt);
struct mlx5_flow_handle *
mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
@@ -338,6 +374,7 @@ struct mlx5_esw_flow_attr {
struct mlx5_eswitch_rep *rep;
struct mlx5_core_dev *mdev;
u32 encap_id;
+ struct mlx5_termtbl_handle *termtbl;
} dests[MLX5_MAX_FLOW_FWD_VPORTS];
u32 mod_hdr_id;
u8 match_level;
@@ -355,10 +392,12 @@ int mlx5_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode);
int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode,
struct netlink_ext_ack *extack);
int mlx5_devlink_eswitch_inline_mode_get(struct devlink *devlink, u8 *mode);
-int mlx5_eswitch_inline_mode_get(struct mlx5_eswitch *esw, int nvfs, u8 *mode);
-int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, u8 encap,
+int mlx5_eswitch_inline_mode_get(struct mlx5_eswitch *esw, u8 *mode);
+int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink,
+ enum devlink_eswitch_encap_mode encap,
struct netlink_ext_ack *extack);
-int mlx5_devlink_eswitch_encap_mode_get(struct devlink *devlink, u8 *encap);
+int mlx5_devlink_eswitch_encap_mode_get(struct devlink *devlink,
+ enum devlink_eswitch_encap_mode *encap);
void *mlx5_eswitch_get_uplink_priv(struct mlx5_eswitch *esw, u8 rep_type);
int mlx5_eswitch_add_vlan_action(struct mlx5_eswitch *esw,
@@ -386,6 +425,8 @@ bool mlx5_esw_lag_prereq(struct mlx5_core_dev *dev0,
bool mlx5_esw_multipath_prereq(struct mlx5_core_dev *dev0,
struct mlx5_core_dev *dev1);
+const u32 *mlx5_esw_query_functions(struct mlx5_core_dev *dev);
+
#define MLX5_DEBUG_ESWITCH_MASK BIT(3)
#define esw_info(__dev, format, ...) \
@@ -404,6 +445,24 @@ static inline u16 mlx5_eswitch_manager_vport(struct mlx5_core_dev *dev)
MLX5_VPORT_ECPF : MLX5_VPORT_PF;
}
+static inline u16 mlx5_eswitch_first_host_vport_num(struct mlx5_core_dev *dev)
+{
+ return mlx5_core_is_ecpf_esw_manager(dev) ?
+ MLX5_VPORT_PF : MLX5_VPORT_FIRST_VF;
+}
+
+static inline bool mlx5_eswitch_is_funcs_handler(struct mlx5_core_dev *dev)
+{
+ /* Ideally device should have the functions changed supported
+ * capability regardless of it being ECPF or PF wherever such
+ * event should be processed such as on eswitch manager device.
+ * However, some ECPF based device might not have this capability
+ * set. Hence OR for ECPF check to cover such device.
+ */
+ return MLX5_CAP_ESW(dev, esw_functions_changed) ||
+ mlx5_core_is_ecpf_esw_manager(dev);
+}
+
static inline int mlx5_eswitch_uplink_idx(struct mlx5_eswitch *esw)
{
/* Uplink always locate at the last element of the array.*/
@@ -488,16 +547,47 @@ void mlx5e_tc_clean_fdb_peer_flows(struct mlx5_eswitch *esw);
#define mlx5_esw_for_each_vf_vport_num_reverse(esw, vport, nvfs) \
for ((vport) = (nvfs); (vport) >= MLX5_VPORT_FIRST_VF; (vport)--)
+/* Includes host PF (vport 0) if it's not esw manager. */
+#define mlx5_esw_for_each_host_func_rep(esw, i, rep, nvfs) \
+ for ((i) = (esw)->first_host_vport; \
+ (rep) = &(esw)->offloads.vport_reps[i], \
+ (i) <= (nvfs); (i)++)
+
+#define mlx5_esw_for_each_host_func_rep_reverse(esw, i, rep, nvfs) \
+ for ((i) = (nvfs); \
+ (rep) = &(esw)->offloads.vport_reps[i], \
+ (i) >= (esw)->first_host_vport; (i)--)
+
+#define mlx5_esw_for_each_host_func_vport(esw, vport, nvfs) \
+ for ((vport) = (esw)->first_host_vport; \
+ (vport) <= (nvfs); (vport)++)
+
+#define mlx5_esw_for_each_host_func_vport_reverse(esw, vport, nvfs) \
+ for ((vport) = (nvfs); \
+ (vport) >= (esw)->first_host_vport; (vport)--)
+
struct mlx5_vport *__must_check
mlx5_eswitch_get_vport(struct mlx5_eswitch *esw, u16 vport_num);
+bool mlx5_eswitch_is_vf_vport(const struct mlx5_eswitch *esw, u16 vport_num);
+
+void mlx5_eswitch_update_num_of_vfs(struct mlx5_eswitch *esw, const int num_vfs);
+int mlx5_esw_funcs_changed_handler(struct notifier_block *nb, unsigned long type, void *data);
+
#else /* CONFIG_MLX5_ESWITCH */
/* eswitch API stubs */
static inline int mlx5_eswitch_init(struct mlx5_core_dev *dev) { return 0; }
static inline void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw) {}
-static inline int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs, int mode) { return 0; }
-static inline void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw) {}
+static inline int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int mode) { return 0; }
+static inline void mlx5_eswitch_disable(struct mlx5_eswitch *esw) {}
static inline bool mlx5_esw_lag_prereq(struct mlx5_core_dev *dev0, struct mlx5_core_dev *dev1) { return true; }
+static inline bool mlx5_eswitch_is_funcs_handler(struct mlx5_core_dev *dev) { return false; }
+static inline const u32 *mlx5_esw_query_functions(struct mlx5_core_dev *dev)
+{
+ return ERR_PTR(-EOPNOTSUPP);
+}
+
+static inline void mlx5_eswitch_update_num_of_vfs(struct mlx5_eswitch *esw, const int num_vfs) {}
#define FDB_MAX_CHAIN 1
#define FDB_SLOW_PATH_CHAIN (FDB_MAX_CHAIN + 1)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
index 47b446d30f71..089ae4d48a82 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
@@ -41,7 +41,6 @@
#include "en.h"
#include "fs_core.h"
#include "lib/devcom.h"
-#include "ecpf.h"
#include "lib/eq.h"
/* There are two match-all miss flows, one for unicast dst mac and
@@ -89,6 +88,53 @@ u16 mlx5_eswitch_get_prio_range(struct mlx5_eswitch *esw)
return 1;
}
+static void
+mlx5_eswitch_set_rule_source_port(struct mlx5_eswitch *esw,
+ struct mlx5_flow_spec *spec,
+ struct mlx5_esw_flow_attr *attr)
+{
+ void *misc2;
+ void *misc;
+
+ /* Use metadata matching because vport is not represented by single
+ * VHCA in dual-port RoCE mode, and matching on source vport may fail.
+ */
+ if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
+ misc2 = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters_2);
+ MLX5_SET(fte_match_set_misc2, misc2, metadata_reg_c_0,
+ mlx5_eswitch_get_vport_metadata_for_match(attr->in_mdev->priv.eswitch,
+ attr->in_rep->vport));
+
+ misc2 = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters_2);
+ MLX5_SET_TO_ONES(fte_match_set_misc2, misc2, metadata_reg_c_0);
+
+ spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2;
+ misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
+ if (memchr_inv(misc, 0, MLX5_ST_SZ_BYTES(fte_match_set_misc)))
+ spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS;
+ } else {
+ misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
+ MLX5_SET(fte_match_set_misc, misc, source_port, attr->in_rep->vport);
+
+ if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
+ MLX5_SET(fte_match_set_misc, misc,
+ source_eswitch_owner_vhca_id,
+ MLX5_CAP_GEN(attr->in_mdev, vhca_id));
+
+ misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
+ MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
+ if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
+ MLX5_SET_TO_ONES(fte_match_set_misc, misc,
+ source_eswitch_owner_vhca_id);
+
+ spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS;
+ }
+
+ if (MLX5_CAP_ESW_FLOWTABLE(esw->dev, flow_source) &&
+ attr->in_rep->vport == MLX5_VPORT_UPLINK)
+ spec->flow_context.flow_source = MLX5_FLOW_CONTEXT_FLOW_SOURCE_UPLINK;
+}
+
struct mlx5_flow_handle *
mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
struct mlx5_flow_spec *spec,
@@ -100,9 +146,8 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
struct mlx5_flow_handle *rule;
struct mlx5_flow_table *fdb;
int j, i = 0;
- void *misc;
- if (esw->mode != SRIOV_OFFLOADS)
+ if (esw->mode != MLX5_ESWITCH_OFFLOADS)
return ERR_PTR(-EOPNOTSUPP);
flow_act.action = attr->action;
@@ -160,21 +205,8 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
i++;
}
- misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
- MLX5_SET(fte_match_set_misc, misc, source_port, attr->in_rep->vport);
-
- if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
- MLX5_SET(fte_match_set_misc, misc,
- source_eswitch_owner_vhca_id,
- MLX5_CAP_GEN(attr->in_mdev, vhca_id));
+ mlx5_eswitch_set_rule_source_port(esw, spec, attr);
- misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
- MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
- if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
- MLX5_SET_TO_ONES(fte_match_set_misc, misc,
- source_eswitch_owner_vhca_id);
-
- spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_DECAP) {
if (attr->tunnel_match_level != MLX5_MATCH_NONE)
spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
@@ -193,7 +225,11 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
goto err_esw_get;
}
- rule = mlx5_add_flow_rules(fdb, spec, &flow_act, dest, i);
+ if (mlx5_eswitch_termtbl_required(esw, &flow_act, spec))
+ rule = mlx5_eswitch_add_termtbl_rule(esw, fdb, spec, attr,
+ &flow_act, dest, i);
+ else
+ rule = mlx5_add_flow_rules(fdb, spec, &flow_act, dest, i);
if (IS_ERR(rule))
goto err_add_rule;
else
@@ -220,7 +256,6 @@ mlx5_eswitch_add_fwd_rule(struct mlx5_eswitch *esw,
struct mlx5_flow_table *fast_fdb;
struct mlx5_flow_table *fwd_fdb;
struct mlx5_flow_handle *rule;
- void *misc;
int i;
fast_fdb = esw_get_prio_table(esw, attr->chain, attr->prio, 0);
@@ -252,25 +287,11 @@ mlx5_eswitch_add_fwd_rule(struct mlx5_eswitch *esw,
dest[i].ft = fwd_fdb,
i++;
- misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
- MLX5_SET(fte_match_set_misc, misc, source_port, attr->in_rep->vport);
-
- if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
- MLX5_SET(fte_match_set_misc, misc,
- source_eswitch_owner_vhca_id,
- MLX5_CAP_GEN(attr->in_mdev, vhca_id));
+ mlx5_eswitch_set_rule_source_port(esw, spec, attr);
- misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
- MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
- if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
- MLX5_SET_TO_ONES(fte_match_set_misc, misc,
- source_eswitch_owner_vhca_id);
-
- if (attr->match_level == MLX5_MATCH_NONE)
- spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
- else
- spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS |
- MLX5_MATCH_MISC_PARAMETERS;
+ spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS;
+ if (attr->match_level != MLX5_MATCH_NONE)
+ spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
rule = mlx5_add_flow_rules(fast_fdb, spec, &flow_act, dest, i);
@@ -295,8 +316,16 @@ __mlx5_eswitch_del_rule(struct mlx5_eswitch *esw,
bool fwd_rule)
{
bool split = (attr->split_count > 0);
+ int i;
mlx5_del_flow_rules(rule);
+
+ /* unref the term table */
+ for (i = 0; i < MLX5_MAX_FLOW_FWD_VPORTS; i++) {
+ if (attr->dests[i].termtbl)
+ mlx5_eswitch_termtbl_put(esw, attr->dests[i].termtbl);
+ }
+
esw->offloads.num_flows--;
if (fwd_rule) {
@@ -328,12 +357,11 @@ mlx5_eswitch_del_fwd_rule(struct mlx5_eswitch *esw,
static int esw_set_global_vlan_pop(struct mlx5_eswitch *esw, u8 val)
{
struct mlx5_eswitch_rep *rep;
- int vf_vport, err = 0;
+ int i, err = 0;
esw_debug(esw->dev, "%s applying global %s policy\n", __func__, val ? "pop" : "none");
- for (vf_vport = 1; vf_vport < esw->enabled_vports; vf_vport++) {
- rep = &esw->offloads.vport_reps[vf_vport];
- if (atomic_read(&rep->rep_if[REP_ETH].state) != REP_LOADED)
+ mlx5_esw_for_each_host_func_rep(esw, i, rep, esw->esw_funcs.num_vfs) {
+ if (atomic_read(&rep->rep_data[REP_ETH].state) != REP_LOADED)
continue;
err = __mlx5_eswitch_set_vport_vlan(esw, rep->vport, 0, 0, val);
@@ -559,23 +587,87 @@ void mlx5_eswitch_del_send_to_vport_rule(struct mlx5_flow_handle *rule)
mlx5_del_flow_rules(rule);
}
-static void peer_miss_rules_setup(struct mlx5_core_dev *peer_dev,
+static int mlx5_eswitch_enable_passing_vport_metadata(struct mlx5_eswitch *esw)
+{
+ u32 out[MLX5_ST_SZ_DW(query_esw_vport_context_out)] = {};
+ u32 in[MLX5_ST_SZ_DW(modify_esw_vport_context_in)] = {};
+ u8 fdb_to_vport_reg_c_id;
+ int err;
+
+ err = mlx5_eswitch_query_esw_vport_context(esw, esw->manager_vport,
+ out, sizeof(out));
+ if (err)
+ return err;
+
+ fdb_to_vport_reg_c_id = MLX5_GET(query_esw_vport_context_out, out,
+ esw_vport_context.fdb_to_vport_reg_c_id);
+
+ fdb_to_vport_reg_c_id |= MLX5_FDB_TO_VPORT_REG_C_0;
+ MLX5_SET(modify_esw_vport_context_in, in,
+ esw_vport_context.fdb_to_vport_reg_c_id, fdb_to_vport_reg_c_id);
+
+ MLX5_SET(modify_esw_vport_context_in, in,
+ field_select.fdb_to_vport_reg_c_id, 1);
+
+ return mlx5_eswitch_modify_esw_vport_context(esw, esw->manager_vport,
+ in, sizeof(in));
+}
+
+static int mlx5_eswitch_disable_passing_vport_metadata(struct mlx5_eswitch *esw)
+{
+ u32 out[MLX5_ST_SZ_DW(query_esw_vport_context_out)] = {};
+ u32 in[MLX5_ST_SZ_DW(modify_esw_vport_context_in)] = {};
+ u8 fdb_to_vport_reg_c_id;
+ int err;
+
+ err = mlx5_eswitch_query_esw_vport_context(esw, esw->manager_vport,
+ out, sizeof(out));
+ if (err)
+ return err;
+
+ fdb_to_vport_reg_c_id = MLX5_GET(query_esw_vport_context_out, out,
+ esw_vport_context.fdb_to_vport_reg_c_id);
+
+ fdb_to_vport_reg_c_id &= ~MLX5_FDB_TO_VPORT_REG_C_0;
+
+ MLX5_SET(modify_esw_vport_context_in, in,
+ esw_vport_context.fdb_to_vport_reg_c_id, fdb_to_vport_reg_c_id);
+
+ MLX5_SET(modify_esw_vport_context_in, in,
+ field_select.fdb_to_vport_reg_c_id, 1);
+
+ return mlx5_eswitch_modify_esw_vport_context(esw, esw->manager_vport,
+ in, sizeof(in));
+}
+
+static void peer_miss_rules_setup(struct mlx5_eswitch *esw,
+ struct mlx5_core_dev *peer_dev,
struct mlx5_flow_spec *spec,
struct mlx5_flow_destination *dest)
{
- void *misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
- misc_parameters);
+ void *misc;
- MLX5_SET(fte_match_set_misc, misc, source_eswitch_owner_vhca_id,
- MLX5_CAP_GEN(peer_dev, vhca_id));
+ if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
+ misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
+ misc_parameters_2);
+ MLX5_SET_TO_ONES(fte_match_set_misc2, misc, metadata_reg_c_0);
- spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
+ spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS_2;
+ } else {
+ misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
+ misc_parameters);
- misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
- misc_parameters);
- MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
- MLX5_SET_TO_ONES(fte_match_set_misc, misc,
- source_eswitch_owner_vhca_id);
+ MLX5_SET(fte_match_set_misc, misc, source_eswitch_owner_vhca_id,
+ MLX5_CAP_GEN(peer_dev, vhca_id));
+
+ spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
+
+ misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
+ misc_parameters);
+ MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
+ MLX5_SET_TO_ONES(fte_match_set_misc, misc,
+ source_eswitch_owner_vhca_id);
+ }
dest->type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
dest->vport.num = peer_dev->priv.eswitch->manager_vport;
@@ -583,6 +675,26 @@ static void peer_miss_rules_setup(struct mlx5_core_dev *peer_dev,
dest->vport.flags |= MLX5_FLOW_DEST_VPORT_VHCA_ID;
}
+static void esw_set_peer_miss_rule_source_port(struct mlx5_eswitch *esw,
+ struct mlx5_eswitch *peer_esw,
+ struct mlx5_flow_spec *spec,
+ u16 vport)
+{
+ void *misc;
+
+ if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
+ misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
+ misc_parameters_2);
+ MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0,
+ mlx5_eswitch_get_vport_metadata_for_match(peer_esw,
+ vport));
+ } else {
+ misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
+ misc_parameters);
+ MLX5_SET(fte_match_set_misc, misc, source_port, vport);
+ }
+}
+
static int esw_add_fdb_peer_miss_rules(struct mlx5_eswitch *esw,
struct mlx5_core_dev *peer_dev)
{
@@ -600,7 +712,7 @@ static int esw_add_fdb_peer_miss_rules(struct mlx5_eswitch *esw,
if (!spec)
return -ENOMEM;
- peer_miss_rules_setup(peer_dev, spec, &dest);
+ peer_miss_rules_setup(esw, peer_dev, spec, &dest);
flows = kvzalloc(nvports * sizeof(*flows), GFP_KERNEL);
if (!flows) {
@@ -613,7 +725,9 @@ static int esw_add_fdb_peer_miss_rules(struct mlx5_eswitch *esw,
misc_parameters);
if (mlx5_core_is_ecpf_esw_manager(esw->dev)) {
- MLX5_SET(fte_match_set_misc, misc, source_port, MLX5_VPORT_PF);
+ esw_set_peer_miss_rule_source_port(esw, peer_dev->priv.eswitch,
+ spec, MLX5_VPORT_PF);
+
flow = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb,
spec, &flow_act, &dest, 1);
if (IS_ERR(flow)) {
@@ -635,7 +749,10 @@ static int esw_add_fdb_peer_miss_rules(struct mlx5_eswitch *esw,
}
mlx5_esw_for_each_vf_vport_num(esw, i, mlx5_core_max_vfs(esw->dev)) {
- MLX5_SET(fte_match_set_misc, misc, source_port, i);
+ esw_set_peer_miss_rule_source_port(esw,
+ peer_dev->priv.eswitch,
+ spec, i);
+
flow = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb,
spec, &flow_act, &dest, 1);
if (IS_ERR(flow)) {
@@ -919,6 +1036,30 @@ static void esw_destroy_offloads_fast_fdb_tables(struct mlx5_eswitch *esw)
#define MAX_PF_SQ 256
#define MAX_SQ_NVPORTS 32
+static void esw_set_flow_group_source_port(struct mlx5_eswitch *esw,
+ u32 *flow_group_in)
+{
+ void *match_criteria = MLX5_ADDR_OF(create_flow_group_in,
+ flow_group_in,
+ match_criteria);
+
+ if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
+ MLX5_SET(create_flow_group_in, flow_group_in,
+ match_criteria_enable,
+ MLX5_MATCH_MISC_PARAMETERS_2);
+
+ MLX5_SET_TO_ONES(fte_match_param, match_criteria,
+ misc_parameters_2.metadata_reg_c_0);
+ } else {
+ MLX5_SET(create_flow_group_in, flow_group_in,
+ match_criteria_enable,
+ MLX5_MATCH_MISC_PARAMETERS);
+
+ MLX5_SET_TO_ONES(fte_match_param, match_criteria,
+ misc_parameters.source_port);
+ }
+}
+
static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw, int nvports)
{
int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
@@ -993,7 +1134,6 @@ static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw, int nvports)
}
/* create send-to-vport group */
- memset(flow_group_in, 0, inlen);
MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
MLX5_MATCH_MISC_PARAMETERS);
@@ -1016,19 +1156,21 @@ static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw, int nvports)
/* create peer esw miss group */
memset(flow_group_in, 0, inlen);
- MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
- MLX5_MATCH_MISC_PARAMETERS);
- match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in,
- match_criteria);
+ esw_set_flow_group_source_port(esw, flow_group_in);
+
+ if (!mlx5_eswitch_vport_match_metadata_enabled(esw)) {
+ match_criteria = MLX5_ADDR_OF(create_flow_group_in,
+ flow_group_in,
+ match_criteria);
- MLX5_SET_TO_ONES(fte_match_param, match_criteria,
- misc_parameters.source_port);
- MLX5_SET_TO_ONES(fte_match_param, match_criteria,
- misc_parameters.source_eswitch_owner_vhca_id);
+ MLX5_SET_TO_ONES(fte_match_param, match_criteria,
+ misc_parameters.source_eswitch_owner_vhca_id);
+
+ MLX5_SET(create_flow_group_in, flow_group_in,
+ source_eswitch_owner_vhca_id_valid, 1);
+ }
- MLX5_SET(create_flow_group_in, flow_group_in,
- source_eswitch_owner_vhca_id_valid, 1);
MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, ix);
MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index,
ix + esw->total_vports - 1);
@@ -1142,7 +1284,6 @@ static int esw_create_vport_rx_group(struct mlx5_eswitch *esw, int nvports)
int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
struct mlx5_flow_group *g;
u32 *flow_group_in;
- void *match_criteria, *misc;
int err = 0;
nvports = nvports + MLX5_ESW_MISS_FLOWS;
@@ -1151,13 +1292,7 @@ static int esw_create_vport_rx_group(struct mlx5_eswitch *esw, int nvports)
return -ENOMEM;
/* create vport rx group */
- memset(flow_group_in, 0, inlen);
- MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
- MLX5_MATCH_MISC_PARAMETERS);
-
- match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
- misc = MLX5_ADDR_OF(fte_match_param, match_criteria, misc_parameters);
- MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
+ esw_set_flow_group_source_port(esw, flow_group_in);
MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, nvports - 1);
@@ -1196,13 +1331,24 @@ mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, u16 vport,
goto out;
}
- misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
- MLX5_SET(fte_match_set_misc, misc, source_port, vport);
+ if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
+ misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters_2);
+ MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0,
+ mlx5_eswitch_get_vport_metadata_for_match(esw, vport));
- misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
- MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
+ misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters_2);
+ MLX5_SET_TO_ONES(fte_match_set_misc2, misc, metadata_reg_c_0);
- spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
+ spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS_2;
+ } else {
+ misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
+ MLX5_SET(fte_match_set_misc, misc, source_port, vport);
+
+ misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
+ MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
+
+ spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
+ }
flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
flow_rule = mlx5_add_flow_rules(esw->offloads.ft_offloads, spec,
@@ -1220,21 +1366,22 @@ out:
static int esw_offloads_start(struct mlx5_eswitch *esw,
struct netlink_ext_ack *extack)
{
- int err, err1, num_vfs = esw->dev->priv.sriov.num_vfs;
+ int err, err1;
- if (esw->mode != SRIOV_LEGACY &&
+ if (esw->mode != MLX5_ESWITCH_LEGACY &&
!mlx5_core_is_ecpf_esw_manager(esw->dev)) {
NL_SET_ERR_MSG_MOD(extack,
"Can't set offloads mode, SRIOV legacy not enabled");
return -EINVAL;
}
- mlx5_eswitch_disable_sriov(esw);
- err = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_OFFLOADS);
+ mlx5_eswitch_disable(esw);
+ mlx5_eswitch_update_num_of_vfs(esw, esw->dev->priv.sriov.num_vfs);
+ err = mlx5_eswitch_enable(esw, MLX5_ESWITCH_OFFLOADS);
if (err) {
NL_SET_ERR_MSG_MOD(extack,
"Failed setting eswitch to offloads");
- err1 = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY);
+ err1 = mlx5_eswitch_enable(esw, MLX5_ESWITCH_LEGACY);
if (err1) {
NL_SET_ERR_MSG_MOD(extack,
"Failed setting eswitch back to legacy");
@@ -1242,7 +1389,6 @@ static int esw_offloads_start(struct mlx5_eswitch *esw,
}
if (esw->offloads.inline_mode == MLX5_INLINE_MODE_NONE) {
if (mlx5_eswitch_inline_mode_get(esw,
- num_vfs,
&esw->offloads.inline_mode)) {
esw->offloads.inline_mode = MLX5_INLINE_MODE_L2;
NL_SET_ERR_MSG_MOD(extack,
@@ -1259,11 +1405,11 @@ void esw_offloads_cleanup_reps(struct mlx5_eswitch *esw)
int esw_offloads_init_reps(struct mlx5_eswitch *esw)
{
- int total_vports = MLX5_TOTAL_VPORTS(esw->dev);
+ int total_vports = esw->total_vports;
struct mlx5_core_dev *dev = esw->dev;
struct mlx5_eswitch_rep *rep;
u8 hw_id[ETH_ALEN], rep_type;
- int vport;
+ int vport_index;
esw->offloads.vport_reps = kcalloc(total_vports,
sizeof(struct mlx5_eswitch_rep),
@@ -1271,14 +1417,15 @@ int esw_offloads_init_reps(struct mlx5_eswitch *esw)
if (!esw->offloads.vport_reps)
return -ENOMEM;
- mlx5_query_nic_vport_mac_address(dev, 0, hw_id);
+ mlx5_query_mac_address(dev, hw_id);
- mlx5_esw_for_all_reps(esw, vport, rep) {
- rep->vport = mlx5_eswitch_index_to_vport_num(esw, vport);
+ mlx5_esw_for_all_reps(esw, vport_index, rep) {
+ rep->vport = mlx5_eswitch_index_to_vport_num(esw, vport_index);
+ rep->vport_index = vport_index;
ether_addr_copy(rep->hw_id, hw_id);
for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++)
- atomic_set(&rep->rep_if[rep_type].state,
+ atomic_set(&rep->rep_data[rep_type].state,
REP_UNREGISTERED);
}
@@ -1288,9 +1435,9 @@ int esw_offloads_init_reps(struct mlx5_eswitch *esw)
static void __esw_offloads_unload_rep(struct mlx5_eswitch *esw,
struct mlx5_eswitch_rep *rep, u8 rep_type)
{
- if (atomic_cmpxchg(&rep->rep_if[rep_type].state,
+ if (atomic_cmpxchg(&rep->rep_data[rep_type].state,
REP_LOADED, REP_REGISTERED) == REP_LOADED)
- rep->rep_if[rep_type].unload(rep);
+ esw->offloads.rep_ops[rep_type]->unload(rep);
}
static void __unload_reps_special_vport(struct mlx5_eswitch *esw, u8 rep_type)
@@ -1329,21 +1476,20 @@ static void esw_offloads_unload_vf_reps(struct mlx5_eswitch *esw, int nvports)
__unload_reps_vf_vport(esw, nvports, rep_type);
}
-static void __unload_reps_all_vport(struct mlx5_eswitch *esw, int nvports,
- u8 rep_type)
+static void __unload_reps_all_vport(struct mlx5_eswitch *esw, u8 rep_type)
{
- __unload_reps_vf_vport(esw, nvports, rep_type);
+ __unload_reps_vf_vport(esw, esw->esw_funcs.num_vfs, rep_type);
/* Special vports must be the last to unload. */
__unload_reps_special_vport(esw, rep_type);
}
-static void esw_offloads_unload_all_reps(struct mlx5_eswitch *esw, int nvports)
+static void esw_offloads_unload_all_reps(struct mlx5_eswitch *esw)
{
u8 rep_type = NUM_REP_TYPES;
while (rep_type-- > 0)
- __unload_reps_all_vport(esw, nvports, rep_type);
+ __unload_reps_all_vport(esw, rep_type);
}
static int __esw_offloads_load_rep(struct mlx5_eswitch *esw,
@@ -1351,11 +1497,11 @@ static int __esw_offloads_load_rep(struct mlx5_eswitch *esw,
{
int err = 0;
- if (atomic_cmpxchg(&rep->rep_if[rep_type].state,
+ if (atomic_cmpxchg(&rep->rep_data[rep_type].state,
REP_REGISTERED, REP_LOADED) == REP_REGISTERED) {
- err = rep->rep_if[rep_type].load(esw->dev, rep);
+ err = esw->offloads.rep_ops[rep_type]->load(esw->dev, rep);
if (err)
- atomic_set(&rep->rep_if[rep_type].state,
+ atomic_set(&rep->rep_data[rep_type].state,
REP_REGISTERED);
}
@@ -1419,6 +1565,26 @@ err_vf:
return err;
}
+static int __load_reps_all_vport(struct mlx5_eswitch *esw, u8 rep_type)
+{
+ int err;
+
+ /* Special vports must be loaded first, uplink rep creates mdev resource. */
+ err = __load_reps_special_vport(esw, rep_type);
+ if (err)
+ return err;
+
+ err = __load_reps_vf_vport(esw, esw->esw_funcs.num_vfs, rep_type);
+ if (err)
+ goto err_vfs;
+
+ return 0;
+
+err_vfs:
+ __unload_reps_special_vport(esw, rep_type);
+ return err;
+}
+
static int esw_offloads_load_vf_reps(struct mlx5_eswitch *esw, int nvports)
{
u8 rep_type = 0;
@@ -1438,34 +1604,13 @@ err_reps:
return err;
}
-static int __load_reps_all_vport(struct mlx5_eswitch *esw, int nvports,
- u8 rep_type)
-{
- int err;
-
- /* Special vports must be loaded first. */
- err = __load_reps_special_vport(esw, rep_type);
- if (err)
- return err;
-
- err = __load_reps_vf_vport(esw, nvports, rep_type);
- if (err)
- goto err_vfs;
-
- return 0;
-
-err_vfs:
- __unload_reps_special_vport(esw, rep_type);
- return err;
-}
-
-static int esw_offloads_load_all_reps(struct mlx5_eswitch *esw, int nvports)
+static int esw_offloads_load_all_reps(struct mlx5_eswitch *esw)
{
u8 rep_type = 0;
int err;
for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++) {
- err = __load_reps_all_vport(esw, nvports, rep_type);
+ err = __load_reps_all_vport(esw, rep_type);
if (err)
goto err_reps;
}
@@ -1474,7 +1619,7 @@ static int esw_offloads_load_all_reps(struct mlx5_eswitch *esw, int nvports)
err_reps:
while (rep_type-- > 0)
- __unload_reps_all_vport(esw, nvports, rep_type);
+ __unload_reps_all_vport(esw, rep_type);
return err;
}
@@ -1510,6 +1655,10 @@ static int mlx5_esw_offloads_devcom_event(int event,
switch (event) {
case ESW_OFFLOADS_DEVCOM_PAIR:
+ if (mlx5_eswitch_vport_match_metadata_enabled(esw) !=
+ mlx5_eswitch_vport_match_metadata_enabled(peer_esw))
+ break;
+
err = mlx5_esw_offloads_pair(esw, peer_esw);
if (err)
goto err_out;
@@ -1578,32 +1727,16 @@ static void esw_offloads_devcom_cleanup(struct mlx5_eswitch *esw)
static int esw_vport_ingress_prio_tag_config(struct mlx5_eswitch *esw,
struct mlx5_vport *vport)
{
- struct mlx5_core_dev *dev = esw->dev;
struct mlx5_flow_act flow_act = {0};
struct mlx5_flow_spec *spec;
int err = 0;
/* For prio tag mode, there is only 1 FTEs:
- * 1) Untagged packets - push prio tag VLAN, allow
+ * 1) Untagged packets - push prio tag VLAN and modify metadata if
+ * required, allow
* Unmatched traffic is allowed by default
*/
- if (!MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support))
- return -EOPNOTSUPP;
-
- esw_vport_cleanup_ingress_rules(esw, vport);
-
- err = esw_vport_enable_ingress_acl(esw, vport);
- if (err) {
- mlx5_core_warn(esw->dev,
- "failed to enable prio tag ingress acl (%d) on vport[%d]\n",
- err, vport->vport);
- return err;
- }
-
- esw_debug(esw->dev,
- "vport[%d] configure ingress rules\n", vport->vport);
-
spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
if (!spec) {
err = -ENOMEM;
@@ -1619,6 +1752,12 @@ static int esw_vport_ingress_prio_tag_config(struct mlx5_eswitch *esw,
flow_act.vlan[0].ethtype = ETH_P_8021Q;
flow_act.vlan[0].vid = 0;
flow_act.vlan[0].prio = 0;
+
+ if (vport->ingress.modify_metadata_rule) {
+ flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
+ flow_act.modify_id = vport->ingress.modify_metadata_id;
+ }
+
vport->ingress.allow_rule =
mlx5_add_flow_rules(vport->ingress.acl, spec,
&flow_act, NULL, 0);
@@ -1639,6 +1778,58 @@ out_no_mem:
return err;
}
+static int esw_vport_add_ingress_acl_modify_metadata(struct mlx5_eswitch *esw,
+ struct mlx5_vport *vport)
+{
+ u8 action[MLX5_UN_SZ_BYTES(set_action_in_add_action_in_auto)] = {};
+ static const struct mlx5_flow_spec spec = {};
+ struct mlx5_flow_act flow_act = {};
+ int err = 0;
+
+ 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_0);
+ MLX5_SET(set_action_in, action, data,
+ mlx5_eswitch_get_vport_metadata_for_match(esw, vport->vport));
+
+ err = mlx5_modify_header_alloc(esw->dev, MLX5_FLOW_NAMESPACE_ESW_INGRESS,
+ 1, action, &vport->ingress.modify_metadata_id);
+ if (err) {
+ esw_warn(esw->dev,
+ "failed to alloc modify header for vport %d ingress acl (%d)\n",
+ vport->vport, err);
+ return err;
+ }
+
+ flow_act.action = MLX5_FLOW_CONTEXT_ACTION_MOD_HDR | MLX5_FLOW_CONTEXT_ACTION_ALLOW;
+ flow_act.modify_id = vport->ingress.modify_metadata_id;
+ vport->ingress.modify_metadata_rule = mlx5_add_flow_rules(vport->ingress.acl,
+ &spec, &flow_act, NULL, 0);
+ if (IS_ERR(vport->ingress.modify_metadata_rule)) {
+ err = PTR_ERR(vport->ingress.modify_metadata_rule);
+ esw_warn(esw->dev,
+ "failed to add setting metadata rule for vport %d ingress acl, err(%d)\n",
+ vport->vport, err);
+ vport->ingress.modify_metadata_rule = NULL;
+ goto out;
+ }
+
+out:
+ if (err)
+ mlx5_modify_header_dealloc(esw->dev, vport->ingress.modify_metadata_id);
+ return err;
+}
+
+void esw_vport_del_ingress_acl_modify_metadata(struct mlx5_eswitch *esw,
+ struct mlx5_vport *vport)
+{
+ if (vport->ingress.modify_metadata_rule) {
+ mlx5_del_flow_rules(vport->ingress.modify_metadata_rule);
+ mlx5_modify_header_dealloc(esw->dev, vport->ingress.modify_metadata_id);
+
+ vport->ingress.modify_metadata_rule = NULL;
+ }
+}
+
static int esw_vport_egress_prio_tag_config(struct mlx5_eswitch *esw,
struct mlx5_vport *vport)
{
@@ -1646,6 +1837,9 @@ static int esw_vport_egress_prio_tag_config(struct mlx5_eswitch *esw,
struct mlx5_flow_spec *spec;
int err = 0;
+ if (!MLX5_CAP_GEN(esw->dev, prio_tag_required))
+ return 0;
+
/* For prio tag mode, there is only 1 FTEs:
* 1) prio tag packets - pop the prio tag VLAN, allow
* Unmatched traffic is allowed by default
@@ -1699,27 +1893,98 @@ out_no_mem:
return err;
}
-static int esw_prio_tag_acls_config(struct mlx5_eswitch *esw, int nvports)
+static int esw_vport_ingress_common_config(struct mlx5_eswitch *esw,
+ struct mlx5_vport *vport)
{
- struct mlx5_vport *vport = NULL;
- int i, j;
int err;
- mlx5_esw_for_each_vf_vport(esw, i, vport, nvports) {
+ if (!mlx5_eswitch_vport_match_metadata_enabled(esw) &&
+ !MLX5_CAP_GEN(esw->dev, prio_tag_required))
+ return 0;
+
+ esw_vport_cleanup_ingress_rules(esw, vport);
+
+ err = esw_vport_enable_ingress_acl(esw, vport);
+ if (err) {
+ esw_warn(esw->dev,
+ "failed to enable ingress acl (%d) on vport[%d]\n",
+ err, vport->vport);
+ return err;
+ }
+
+ esw_debug(esw->dev,
+ "vport[%d] configure ingress rules\n", vport->vport);
+
+ if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
+ err = esw_vport_add_ingress_acl_modify_metadata(esw, vport);
+ if (err)
+ goto out;
+ }
+
+ if (MLX5_CAP_GEN(esw->dev, prio_tag_required) &&
+ mlx5_eswitch_is_vf_vport(esw, vport->vport)) {
err = esw_vport_ingress_prio_tag_config(esw, vport);
if (err)
- goto err_ingress;
- err = esw_vport_egress_prio_tag_config(esw, vport);
+ goto out;
+ }
+
+out:
+ if (err)
+ esw_vport_disable_ingress_acl(esw, vport);
+ return err;
+}
+
+static bool
+esw_check_vport_match_metadata_supported(const struct mlx5_eswitch *esw)
+{
+ if (!MLX5_CAP_ESW(esw->dev, esw_uplink_ingress_acl))
+ return false;
+
+ if (!(MLX5_CAP_ESW_FLOWTABLE(esw->dev, fdb_to_vport_reg_c_id) &
+ MLX5_FDB_TO_VPORT_REG_C_0))
+ return false;
+
+ if (!MLX5_CAP_ESW_FLOWTABLE(esw->dev, flow_source))
+ return false;
+
+ if (mlx5_core_is_ecpf_esw_manager(esw->dev) ||
+ mlx5_ecpf_vport_exists(esw->dev))
+ return false;
+
+ return true;
+}
+
+static int esw_create_offloads_acl_tables(struct mlx5_eswitch *esw)
+{
+ struct mlx5_vport *vport;
+ int i, j;
+ int err;
+
+ if (esw_check_vport_match_metadata_supported(esw))
+ esw->flags |= MLX5_ESWITCH_VPORT_MATCH_METADATA;
+
+ mlx5_esw_for_all_vports(esw, i, vport) {
+ err = esw_vport_ingress_common_config(esw, vport);
if (err)
- goto err_egress;
+ goto err_ingress;
+
+ if (mlx5_eswitch_is_vf_vport(esw, vport->vport)) {
+ err = esw_vport_egress_prio_tag_config(esw, vport);
+ if (err)
+ goto err_egress;
+ }
}
+ if (mlx5_eswitch_vport_match_metadata_enabled(esw))
+ esw_info(esw->dev, "Use metadata reg_c as source vport to match\n");
+
return 0;
err_egress:
esw_vport_disable_ingress_acl(esw, vport);
err_ingress:
- mlx5_esw_for_each_vf_vport_reverse(esw, j, vport, i - 1) {
+ for (j = MLX5_VPORT_PF; j < i; j++) {
+ vport = &esw->vports[j];
esw_vport_disable_egress_acl(esw, vport);
esw_vport_disable_ingress_acl(esw, vport);
}
@@ -1727,40 +1992,46 @@ err_ingress:
return err;
}
-static void esw_prio_tag_acls_cleanup(struct mlx5_eswitch *esw)
+static void esw_destroy_offloads_acl_tables(struct mlx5_eswitch *esw)
{
struct mlx5_vport *vport;
int i;
- mlx5_esw_for_each_vf_vport(esw, i, vport, esw->dev->priv.sriov.num_vfs) {
+ mlx5_esw_for_all_vports(esw, i, vport) {
esw_vport_disable_egress_acl(esw, vport);
esw_vport_disable_ingress_acl(esw, vport);
}
+
+ esw->flags &= ~MLX5_ESWITCH_VPORT_MATCH_METADATA;
}
-static int esw_offloads_steering_init(struct mlx5_eswitch *esw, int vf_nvports,
- int nvports)
+static int esw_offloads_steering_init(struct mlx5_eswitch *esw)
{
+ int num_vfs = esw->esw_funcs.num_vfs;
+ int total_vports;
int err;
+ if (mlx5_core_is_ecpf_esw_manager(esw->dev))
+ total_vports = esw->total_vports;
+ else
+ total_vports = num_vfs + MLX5_SPECIAL_VPORTS(esw->dev);
+
memset(&esw->fdb_table.offloads, 0, sizeof(struct offloads_fdb));
mutex_init(&esw->fdb_table.offloads.fdb_prio_lock);
- if (MLX5_CAP_GEN(esw->dev, prio_tag_required)) {
- err = esw_prio_tag_acls_config(esw, vf_nvports);
- if (err)
- return err;
- }
-
- err = esw_create_offloads_fdb_tables(esw, nvports);
+ err = esw_create_offloads_acl_tables(esw);
if (err)
return err;
- err = esw_create_offloads_table(esw, nvports);
+ err = esw_create_offloads_fdb_tables(esw, total_vports);
+ if (err)
+ goto create_fdb_err;
+
+ err = esw_create_offloads_table(esw, total_vports);
if (err)
goto create_ft_err;
- err = esw_create_vport_rx_group(esw, nvports);
+ err = esw_create_vport_rx_group(esw, total_vports);
if (err)
goto create_fg_err;
@@ -1772,6 +2043,9 @@ create_fg_err:
create_ft_err:
esw_destroy_offloads_fdb_tables(esw);
+create_fdb_err:
+ esw_destroy_offloads_acl_tables(esw);
+
return err;
}
@@ -1780,88 +2054,111 @@ static void esw_offloads_steering_cleanup(struct mlx5_eswitch *esw)
esw_destroy_vport_rx_group(esw);
esw_destroy_offloads_table(esw);
esw_destroy_offloads_fdb_tables(esw);
- if (MLX5_CAP_GEN(esw->dev, prio_tag_required))
- esw_prio_tag_acls_cleanup(esw);
+ esw_destroy_offloads_acl_tables(esw);
}
-static void esw_host_params_event_handler(struct work_struct *work)
+static void
+esw_vfs_changed_event_handler(struct mlx5_eswitch *esw, const u32 *out)
{
- struct mlx5_host_work *host_work;
- struct mlx5_eswitch *esw;
- int err, num_vf = 0;
+ bool host_pf_disabled;
+ u16 new_num_vfs;
- host_work = container_of(work, struct mlx5_host_work, work);
- esw = host_work->esw;
+ new_num_vfs = MLX5_GET(query_esw_functions_out, out,
+ host_params_context.host_num_of_vfs);
+ host_pf_disabled = MLX5_GET(query_esw_functions_out, out,
+ host_params_context.host_pf_disabled);
- err = mlx5_query_host_params_num_vfs(esw->dev, &num_vf);
- if (err || num_vf == esw->host_info.num_vfs)
- goto out;
+ if (new_num_vfs == esw->esw_funcs.num_vfs || host_pf_disabled)
+ return;
/* Number of VFs can only change from "0 to x" or "x to 0". */
- if (esw->host_info.num_vfs > 0) {
- esw_offloads_unload_vf_reps(esw, esw->host_info.num_vfs);
+ if (esw->esw_funcs.num_vfs > 0) {
+ esw_offloads_unload_vf_reps(esw, esw->esw_funcs.num_vfs);
} else {
- err = esw_offloads_load_vf_reps(esw, num_vf);
+ int err;
+ err = esw_offloads_load_vf_reps(esw, new_num_vfs);
if (err)
- goto out;
+ return;
}
+ esw->esw_funcs.num_vfs = new_num_vfs;
+}
+
+static void esw_functions_changed_event_handler(struct work_struct *work)
+{
+ struct mlx5_host_work *host_work;
+ struct mlx5_eswitch *esw;
+ const u32 *out;
- esw->host_info.num_vfs = num_vf;
+ host_work = container_of(work, struct mlx5_host_work, work);
+ esw = host_work->esw;
+ out = mlx5_esw_query_functions(esw->dev);
+ if (IS_ERR(out))
+ goto out;
+
+ esw_vfs_changed_event_handler(esw, out);
+ kvfree(out);
out:
kfree(host_work);
}
-static int esw_host_params_event(struct notifier_block *nb,
- unsigned long type, void *data)
+int mlx5_esw_funcs_changed_handler(struct notifier_block *nb, unsigned long type, void *data)
{
+ struct mlx5_esw_functions *esw_funcs;
struct mlx5_host_work *host_work;
- struct mlx5_host_info *host_info;
struct mlx5_eswitch *esw;
host_work = kzalloc(sizeof(*host_work), GFP_ATOMIC);
if (!host_work)
return NOTIFY_DONE;
- host_info = mlx5_nb_cof(nb, struct mlx5_host_info, nb);
- esw = container_of(host_info, struct mlx5_eswitch, host_info);
+ esw_funcs = mlx5_nb_cof(nb, struct mlx5_esw_functions, nb);
+ esw = container_of(esw_funcs, struct mlx5_eswitch, esw_funcs);
host_work->esw = esw;
- INIT_WORK(&host_work->work, esw_host_params_event_handler);
+ INIT_WORK(&host_work->work, esw_functions_changed_event_handler);
queue_work(esw->work_queue, &host_work->work);
return NOTIFY_OK;
}
-int esw_offloads_init(struct mlx5_eswitch *esw, int vf_nvports,
- int total_nvports)
+int esw_offloads_init(struct mlx5_eswitch *esw)
{
int err;
- err = esw_offloads_steering_init(esw, vf_nvports, total_nvports);
+ if (MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, reformat) &&
+ MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, decap))
+ esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_BASIC;
+ else
+ esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_NONE;
+
+ err = esw_offloads_steering_init(esw);
if (err)
return err;
- err = esw_offloads_load_all_reps(esw, vf_nvports);
+ if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
+ err = mlx5_eswitch_enable_passing_vport_metadata(esw);
+ if (err)
+ goto err_vport_metadata;
+ }
+
+ err = esw_offloads_load_all_reps(esw);
if (err)
goto err_reps;
esw_offloads_devcom_init(esw);
-
- if (mlx5_core_is_ecpf_esw_manager(esw->dev)) {
- MLX5_NB_INIT(&esw->host_info.nb, esw_host_params_event,
- HOST_PARAMS_CHANGE);
- mlx5_eq_notifier_register(esw->dev, &esw->host_info.nb);
- esw->host_info.num_vfs = vf_nvports;
- }
+ mutex_init(&esw->offloads.termtbl_mutex);
mlx5_rdma_enable_roce(esw->dev);
return 0;
err_reps:
+ if (mlx5_eswitch_vport_match_metadata_enabled(esw))
+ mlx5_eswitch_disable_passing_vport_metadata(esw);
+err_vport_metadata:
esw_offloads_steering_cleanup(esw);
return err;
}
@@ -1869,13 +2166,13 @@ err_reps:
static int esw_offloads_stop(struct mlx5_eswitch *esw,
struct netlink_ext_ack *extack)
{
- int err, err1, num_vfs = esw->dev->priv.sriov.num_vfs;
+ int err, err1;
- mlx5_eswitch_disable_sriov(esw);
- err = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY);
+ mlx5_eswitch_disable(esw);
+ err = mlx5_eswitch_enable(esw, MLX5_ESWITCH_LEGACY);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Failed setting eswitch to legacy");
- err1 = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_OFFLOADS);
+ err1 = mlx5_eswitch_enable(esw, MLX5_ESWITCH_OFFLOADS);
if (err1) {
NL_SET_ERR_MSG_MOD(extack,
"Failed setting eswitch back to offloads");
@@ -1887,30 +2184,23 @@ static int esw_offloads_stop(struct mlx5_eswitch *esw,
void esw_offloads_cleanup(struct mlx5_eswitch *esw)
{
- u16 num_vfs;
-
- if (mlx5_core_is_ecpf_esw_manager(esw->dev)) {
- mlx5_eq_notifier_unregister(esw->dev, &esw->host_info.nb);
- flush_workqueue(esw->work_queue);
- num_vfs = esw->host_info.num_vfs;
- } else {
- num_vfs = esw->dev->priv.sriov.num_vfs;
- }
-
mlx5_rdma_disable_roce(esw->dev);
esw_offloads_devcom_cleanup(esw);
- esw_offloads_unload_all_reps(esw, num_vfs);
+ esw_offloads_unload_all_reps(esw);
+ if (mlx5_eswitch_vport_match_metadata_enabled(esw))
+ mlx5_eswitch_disable_passing_vport_metadata(esw);
esw_offloads_steering_cleanup(esw);
+ esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_NONE;
}
static int esw_mode_from_devlink(u16 mode, u16 *mlx5_mode)
{
switch (mode) {
case DEVLINK_ESWITCH_MODE_LEGACY:
- *mlx5_mode = SRIOV_LEGACY;
+ *mlx5_mode = MLX5_ESWITCH_LEGACY;
break;
case DEVLINK_ESWITCH_MODE_SWITCHDEV:
- *mlx5_mode = SRIOV_OFFLOADS;
+ *mlx5_mode = MLX5_ESWITCH_OFFLOADS;
break;
default:
return -EINVAL;
@@ -1922,10 +2212,10 @@ static int esw_mode_from_devlink(u16 mode, u16 *mlx5_mode)
static int esw_mode_to_devlink(u16 mlx5_mode, u16 *mode)
{
switch (mlx5_mode) {
- case SRIOV_LEGACY:
+ case MLX5_ESWITCH_LEGACY:
*mode = DEVLINK_ESWITCH_MODE_LEGACY;
break;
- case SRIOV_OFFLOADS:
+ case MLX5_ESWITCH_OFFLOADS:
*mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
break;
default:
@@ -1989,7 +2279,7 @@ static int mlx5_devlink_eswitch_check(struct devlink *devlink)
if(!MLX5_ESWITCH_MANAGER(dev))
return -EPERM;
- if (dev->priv.eswitch->mode == SRIOV_NONE &&
+ if (dev->priv.eswitch->mode == MLX5_ESWITCH_NONE &&
!mlx5_core_is_ecpf_esw_manager(dev))
return -EOPNOTSUPP;
@@ -2040,7 +2330,7 @@ int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode,
{
struct mlx5_core_dev *dev = devlink_priv(devlink);
struct mlx5_eswitch *esw = dev->priv.eswitch;
- int err, vport;
+ int err, vport, num_vport;
u8 mlx5_mode;
err = mlx5_devlink_eswitch_check(devlink);
@@ -2069,7 +2359,7 @@ int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode,
if (err)
goto out;
- for (vport = 1; vport < esw->enabled_vports; vport++) {
+ mlx5_esw_for_each_host_func_vport(esw, vport, esw->esw_funcs.num_vfs) {
err = mlx5_modify_nic_vport_min_inline(dev, vport, mlx5_mode);
if (err) {
NL_SET_ERR_MSG_MOD(extack,
@@ -2082,7 +2372,8 @@ int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode,
return 0;
revert_inline_mode:
- while (--vport > 0)
+ num_vport = --vport;
+ mlx5_esw_for_each_host_func_vport_reverse(esw, vport, num_vport)
mlx5_modify_nic_vport_min_inline(dev,
vport,
esw->offloads.inline_mode);
@@ -2103,7 +2394,7 @@ int mlx5_devlink_eswitch_inline_mode_get(struct devlink *devlink, u8 *mode)
return esw_inline_mode_to_devlink(esw->offloads.inline_mode, mode);
}
-int mlx5_eswitch_inline_mode_get(struct mlx5_eswitch *esw, int nvfs, u8 *mode)
+int mlx5_eswitch_inline_mode_get(struct mlx5_eswitch *esw, u8 *mode)
{
u8 prev_mlx5_mode, mlx5_mode = MLX5_INLINE_MODE_L2;
struct mlx5_core_dev *dev = esw->dev;
@@ -2112,7 +2403,7 @@ int mlx5_eswitch_inline_mode_get(struct mlx5_eswitch *esw, int nvfs, u8 *mode)
if (!MLX5_CAP_GEN(dev, vport_group_manager))
return -EOPNOTSUPP;
- if (esw->mode == SRIOV_NONE)
+ if (esw->mode == MLX5_ESWITCH_NONE)
return -EOPNOTSUPP;
switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
@@ -2127,9 +2418,10 @@ int mlx5_eswitch_inline_mode_get(struct mlx5_eswitch *esw, int nvfs, u8 *mode)
}
query_vports:
- for (vport = 1; vport <= nvfs; vport++) {
+ mlx5_query_nic_vport_min_inline(dev, esw->first_host_vport, &prev_mlx5_mode);
+ mlx5_esw_for_each_host_func_vport(esw, vport, esw->esw_funcs.num_vfs) {
mlx5_query_nic_vport_min_inline(dev, vport, &mlx5_mode);
- if (vport > 1 && prev_mlx5_mode != mlx5_mode)
+ if (prev_mlx5_mode != mlx5_mode)
return -EINVAL;
prev_mlx5_mode = mlx5_mode;
}
@@ -2139,7 +2431,8 @@ out:
return 0;
}
-int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, u8 encap,
+int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink,
+ enum devlink_eswitch_encap_mode encap,
struct netlink_ext_ack *extack)
{
struct mlx5_core_dev *dev = devlink_priv(devlink);
@@ -2158,7 +2451,7 @@ int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, u8 encap,
if (encap && encap != DEVLINK_ESWITCH_ENCAP_MODE_BASIC)
return -EOPNOTSUPP;
- if (esw->mode == SRIOV_LEGACY) {
+ if (esw->mode == MLX5_ESWITCH_LEGACY) {
esw->offloads.encap = encap;
return 0;
}
@@ -2188,7 +2481,8 @@ int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, u8 encap,
return err;
}
-int mlx5_devlink_eswitch_encap_mode_get(struct devlink *devlink, u8 *encap)
+int mlx5_devlink_eswitch_encap_mode_get(struct devlink *devlink,
+ enum devlink_eswitch_encap_mode *encap)
{
struct mlx5_core_dev *dev = devlink_priv(devlink);
struct mlx5_eswitch *esw = dev->priv.eswitch;
@@ -2203,36 +2497,31 @@ int mlx5_devlink_eswitch_encap_mode_get(struct devlink *devlink, u8 *encap)
}
void mlx5_eswitch_register_vport_reps(struct mlx5_eswitch *esw,
- struct mlx5_eswitch_rep_if *__rep_if,
+ const struct mlx5_eswitch_rep_ops *ops,
u8 rep_type)
{
- struct mlx5_eswitch_rep_if *rep_if;
+ struct mlx5_eswitch_rep_data *rep_data;
struct mlx5_eswitch_rep *rep;
int i;
+ esw->offloads.rep_ops[rep_type] = ops;
mlx5_esw_for_all_reps(esw, i, rep) {
- rep_if = &rep->rep_if[rep_type];
- rep_if->load = __rep_if->load;
- rep_if->unload = __rep_if->unload;
- rep_if->get_proto_dev = __rep_if->get_proto_dev;
- rep_if->priv = __rep_if->priv;
-
- atomic_set(&rep_if->state, REP_REGISTERED);
+ rep_data = &rep->rep_data[rep_type];
+ atomic_set(&rep_data->state, REP_REGISTERED);
}
}
EXPORT_SYMBOL(mlx5_eswitch_register_vport_reps);
void mlx5_eswitch_unregister_vport_reps(struct mlx5_eswitch *esw, u8 rep_type)
{
- u16 max_vf = mlx5_core_max_vfs(esw->dev);
struct mlx5_eswitch_rep *rep;
int i;
- if (esw->mode == SRIOV_OFFLOADS)
- __unload_reps_all_vport(esw, max_vf, rep_type);
+ if (esw->mode == MLX5_ESWITCH_OFFLOADS)
+ __unload_reps_all_vport(esw, rep_type);
mlx5_esw_for_all_reps(esw, i, rep)
- atomic_set(&rep->rep_if[rep_type].state, REP_UNREGISTERED);
+ atomic_set(&rep->rep_data[rep_type].state, REP_UNREGISTERED);
}
EXPORT_SYMBOL(mlx5_eswitch_unregister_vport_reps);
@@ -2241,7 +2530,7 @@ void *mlx5_eswitch_get_uplink_priv(struct mlx5_eswitch *esw, u8 rep_type)
struct mlx5_eswitch_rep *rep;
rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_UPLINK);
- return rep->rep_if[rep_type].priv;
+ return rep->rep_data[rep_type].priv;
}
void *mlx5_eswitch_get_proto_dev(struct mlx5_eswitch *esw,
@@ -2252,9 +2541,9 @@ void *mlx5_eswitch_get_proto_dev(struct mlx5_eswitch *esw,
rep = mlx5_eswitch_get_rep(esw, vport);
- if (atomic_read(&rep->rep_if[rep_type].state) == REP_LOADED &&
- rep->rep_if[rep_type].get_proto_dev)
- return rep->rep_if[rep_type].get_proto_dev(rep);
+ if (atomic_read(&rep->rep_data[rep_type].state) == REP_LOADED &&
+ esw->offloads.rep_ops[rep_type]->get_proto_dev)
+ return esw->offloads.rep_ops[rep_type]->get_proto_dev(rep);
return NULL;
}
EXPORT_SYMBOL(mlx5_eswitch_get_proto_dev);
@@ -2271,3 +2560,22 @@ struct mlx5_eswitch_rep *mlx5_eswitch_vport_rep(struct mlx5_eswitch *esw,
return mlx5_eswitch_get_rep(esw, vport);
}
EXPORT_SYMBOL(mlx5_eswitch_vport_rep);
+
+bool mlx5_eswitch_is_vf_vport(const struct mlx5_eswitch *esw, u16 vport_num)
+{
+ return vport_num >= MLX5_VPORT_FIRST_VF &&
+ vport_num <= esw->dev->priv.sriov.max_vfs;
+}
+
+bool mlx5_eswitch_vport_match_metadata_enabled(const struct mlx5_eswitch *esw)
+{
+ return !!(esw->flags & MLX5_ESWITCH_VPORT_MATCH_METADATA);
+}
+EXPORT_SYMBOL(mlx5_eswitch_vport_match_metadata_enabled);
+
+u32 mlx5_eswitch_get_vport_metadata_for_match(const struct mlx5_eswitch *esw,
+ u16 vport_num)
+{
+ return ((MLX5_CAP_GEN(esw->dev, vhca_id) & 0xffff) << 16) | vport_num;
+}
+EXPORT_SYMBOL(mlx5_eswitch_get_vport_metadata_for_match);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_termtbl.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_termtbl.c
new file mode 100644
index 000000000000..1d55a324a17e
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_termtbl.c
@@ -0,0 +1,277 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+// Copyright (c) 2019 Mellanox Technologies.
+
+#include <linux/mlx5/fs.h>
+#include "eswitch.h"
+
+struct mlx5_termtbl_handle {
+ struct hlist_node termtbl_hlist;
+
+ struct mlx5_flow_table *termtbl;
+ struct mlx5_flow_act flow_act;
+ struct mlx5_flow_destination dest;
+
+ struct mlx5_flow_handle *rule;
+ int ref_count;
+};
+
+static u32
+mlx5_eswitch_termtbl_hash(struct mlx5_flow_act *flow_act,
+ struct mlx5_flow_destination *dest)
+{
+ u32 hash;
+
+ hash = jhash_1word(flow_act->action, 0);
+ hash = jhash((const void *)&flow_act->vlan,
+ sizeof(flow_act->vlan), hash);
+ hash = jhash((const void *)&dest->vport.num,
+ sizeof(dest->vport.num), hash);
+ hash = jhash((const void *)&dest->vport.vhca_id,
+ sizeof(dest->vport.num), hash);
+ return hash;
+}
+
+static int
+mlx5_eswitch_termtbl_cmp(struct mlx5_flow_act *flow_act1,
+ struct mlx5_flow_destination *dest1,
+ struct mlx5_flow_act *flow_act2,
+ struct mlx5_flow_destination *dest2)
+{
+ return flow_act1->action != flow_act2->action ||
+ dest1->vport.num != dest2->vport.num ||
+ dest1->vport.vhca_id != dest2->vport.vhca_id ||
+ memcmp(&flow_act1->vlan, &flow_act2->vlan,
+ sizeof(flow_act1->vlan));
+}
+
+static int
+mlx5_eswitch_termtbl_create(struct mlx5_core_dev *dev,
+ struct mlx5_termtbl_handle *tt,
+ struct mlx5_flow_act *flow_act)
+{
+ static const struct mlx5_flow_spec spec = {};
+ struct mlx5_flow_namespace *root_ns;
+ int prio, flags;
+ int err;
+
+ root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
+ if (!root_ns) {
+ esw_warn(dev, "Failed to get FDB flow namespace\n");
+ return -EOPNOTSUPP;
+ }
+
+ /* As this is the terminating action then the termination table is the
+ * same prio as the slow path
+ */
+ prio = FDB_SLOW_PATH;
+ flags = MLX5_FLOW_TABLE_TERMINATION;
+ tt->termtbl = mlx5_create_auto_grouped_flow_table(root_ns, prio, 1, 1,
+ 0, flags);
+ if (IS_ERR(tt->termtbl)) {
+ esw_warn(dev, "Failed to create termination table\n");
+ return -EOPNOTSUPP;
+ }
+
+ tt->rule = mlx5_add_flow_rules(tt->termtbl, &spec, flow_act,
+ &tt->dest, 1);
+
+ if (IS_ERR(tt->rule)) {
+ esw_warn(dev, "Failed to create termination table rule\n");
+ goto add_flow_err;
+ }
+ return 0;
+
+add_flow_err:
+ err = mlx5_destroy_flow_table(tt->termtbl);
+ if (err)
+ esw_warn(dev, "Failed to destroy termination table\n");
+
+ return -EOPNOTSUPP;
+}
+
+static struct mlx5_termtbl_handle *
+mlx5_eswitch_termtbl_get_create(struct mlx5_eswitch *esw,
+ struct mlx5_flow_act *flow_act,
+ struct mlx5_flow_destination *dest)
+{
+ struct mlx5_termtbl_handle *tt;
+ bool found = false;
+ u32 hash_key;
+ int err;
+
+ mutex_lock(&esw->offloads.termtbl_mutex);
+
+ hash_key = mlx5_eswitch_termtbl_hash(flow_act, dest);
+ hash_for_each_possible(esw->offloads.termtbl_tbl, tt,
+ termtbl_hlist, hash_key) {
+ if (!mlx5_eswitch_termtbl_cmp(&tt->flow_act, &tt->dest,
+ flow_act, dest)) {
+ found = true;
+ break;
+ }
+ }
+ if (found)
+ goto tt_add_ref;
+
+ tt = kzalloc(sizeof(*tt), GFP_KERNEL);
+ if (!tt) {
+ err = -ENOMEM;
+ goto tt_create_err;
+ }
+
+ tt->dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
+ tt->dest.vport.num = dest->vport.num;
+ tt->dest.vport.vhca_id = dest->vport.vhca_id;
+ memcpy(&tt->flow_act, flow_act, sizeof(*flow_act));
+
+ err = mlx5_eswitch_termtbl_create(esw->dev, tt, flow_act);
+ if (err) {
+ esw_warn(esw->dev, "Failed to create termination table\n");
+ goto tt_create_err;
+ }
+ hash_add(esw->offloads.termtbl_tbl, &tt->termtbl_hlist, hash_key);
+tt_add_ref:
+ tt->ref_count++;
+ mutex_unlock(&esw->offloads.termtbl_mutex);
+ return tt;
+tt_create_err:
+ kfree(tt);
+ mutex_unlock(&esw->offloads.termtbl_mutex);
+ return ERR_PTR(err);
+}
+
+void
+mlx5_eswitch_termtbl_put(struct mlx5_eswitch *esw,
+ struct mlx5_termtbl_handle *tt)
+{
+ mutex_lock(&esw->offloads.termtbl_mutex);
+ if (--tt->ref_count == 0)
+ hash_del(&tt->termtbl_hlist);
+ mutex_unlock(&esw->offloads.termtbl_mutex);
+
+ if (!tt->ref_count) {
+ mlx5_del_flow_rules(tt->rule);
+ mlx5_destroy_flow_table(tt->termtbl);
+ kfree(tt);
+ }
+}
+
+static void
+mlx5_eswitch_termtbl_actions_move(struct mlx5_flow_act *src,
+ struct mlx5_flow_act *dst)
+{
+ if (!(src->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH))
+ return;
+
+ src->action &= ~MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH;
+ dst->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH;
+ memcpy(&dst->vlan[0], &src->vlan[0], sizeof(src->vlan[0]));
+ memset(&src->vlan[0], 0, sizeof(src->vlan[0]));
+
+ if (!(src->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2))
+ return;
+
+ src->action &= ~MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2;
+ dst->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2;
+ memcpy(&dst->vlan[1], &src->vlan[1], sizeof(src->vlan[1]));
+ memset(&src->vlan[1], 0, sizeof(src->vlan[1]));
+}
+
+bool
+mlx5_eswitch_termtbl_required(struct mlx5_eswitch *esw,
+ struct mlx5_flow_act *flow_act,
+ struct mlx5_flow_spec *spec)
+{
+ u32 port_mask = MLX5_GET(fte_match_param, spec->match_criteria,
+ misc_parameters.source_port);
+ u32 port_value = MLX5_GET(fte_match_param, spec->match_value,
+ misc_parameters.source_port);
+
+ if (!MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, termination_table))
+ return false;
+
+ /* push vlan on RX */
+ return (flow_act->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH) &&
+ ((port_mask & port_value) == MLX5_VPORT_UPLINK);
+}
+
+struct mlx5_flow_handle *
+mlx5_eswitch_add_termtbl_rule(struct mlx5_eswitch *esw,
+ struct mlx5_flow_table *fdb,
+ struct mlx5_flow_spec *spec,
+ struct mlx5_esw_flow_attr *attr,
+ struct mlx5_flow_act *flow_act,
+ struct mlx5_flow_destination *dest,
+ int num_dest)
+{
+ struct mlx5_flow_act term_tbl_act = {};
+ struct mlx5_flow_handle *rule = NULL;
+ bool term_table_created = false;
+ int num_vport_dests = 0;
+ int i, curr_dest;
+
+ mlx5_eswitch_termtbl_actions_move(flow_act, &term_tbl_act);
+ term_tbl_act.action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
+
+ for (i = 0; i < num_dest; i++) {
+ struct mlx5_termtbl_handle *tt;
+
+ /* only vport destinations can be terminated */
+ if (dest[i].type != MLX5_FLOW_DESTINATION_TYPE_VPORT)
+ continue;
+
+ /* get the terminating table for the action list */
+ tt = mlx5_eswitch_termtbl_get_create(esw, &term_tbl_act,
+ &dest[i]);
+ if (IS_ERR(tt)) {
+ esw_warn(esw->dev, "Failed to create termination table\n");
+ goto revert_changes;
+ }
+ attr->dests[num_vport_dests].termtbl = tt;
+ num_vport_dests++;
+
+ /* link the destination with the termination table */
+ dest[i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
+ dest[i].ft = tt->termtbl;
+ term_table_created = true;
+ }
+
+ /* at least one destination should reference a termination table */
+ if (!term_table_created)
+ goto revert_changes;
+
+ /* create the FTE */
+ rule = mlx5_add_flow_rules(fdb, spec, flow_act, dest, num_dest);
+ if (IS_ERR(rule))
+ goto revert_changes;
+
+ goto out;
+
+revert_changes:
+ /* revert the changes that were made to the original flow_act
+ * and fall-back to the original rule actions
+ */
+ mlx5_eswitch_termtbl_actions_move(&term_tbl_act, flow_act);
+
+ for (curr_dest = 0; curr_dest < num_vport_dests; curr_dest++) {
+ struct mlx5_termtbl_handle *tt = attr->dests[curr_dest].termtbl;
+
+ /* search for the destination associated with the
+ * current term table
+ */
+ for (i = 0; i < num_dest; i++) {
+ if (dest[i].ft != tt->termtbl)
+ continue;
+
+ memset(&dest[i], 0, sizeof(dest[i]));
+ dest[i].type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
+ dest[i].vport.num = tt->dest.vport.num;
+ dest[i].vport.vhca_id = tt->dest.vport.vhca_id;
+ mlx5_eswitch_termtbl_put(esw, tt);
+ break;
+ }
+ }
+ rule = mlx5_add_flow_rules(fdb, spec, flow_act, dest, num_dest);
+out:
+ return rule;
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/events.c b/drivers/net/ethernet/mellanox/mlx5/core/events.c
index a81e8d2168d8..8bcf3426b9c6 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/events.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/events.c
@@ -108,8 +108,8 @@ static const char *eqe_type_str(u8 type)
return "MLX5_EVENT_TYPE_STALL_EVENT";
case MLX5_EVENT_TYPE_CMD:
return "MLX5_EVENT_TYPE_CMD";
- case MLX5_EVENT_TYPE_HOST_PARAMS_CHANGE:
- return "MLX5_EVENT_TYPE_HOST_PARAMS_CHANGE";
+ case MLX5_EVENT_TYPE_ESW_FUNCTIONS_CHANGED:
+ return "MLX5_EVENT_TYPE_ESW_FUNCTIONS_CHANGED";
case MLX5_EVENT_TYPE_PAGE_REQUEST:
return "MLX5_EVENT_TYPE_PAGE_REQUEST";
case MLX5_EVENT_TYPE_PAGE_FAULT:
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c
index ca2296a2f9ee..4c50efe4e7f1 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c
@@ -414,7 +414,8 @@ static void mlx5_fpga_conn_cq_tasklet(unsigned long data)
mlx5_fpga_conn_cqes(conn, MLX5_FPGA_CQ_BUDGET);
}
-static void mlx5_fpga_conn_cq_complete(struct mlx5_core_cq *mcq)
+static void mlx5_fpga_conn_cq_complete(struct mlx5_core_cq *mcq,
+ struct mlx5_eqe *eqe)
{
struct mlx5_fpga_conn *conn;
@@ -429,6 +430,7 @@ static int mlx5_fpga_conn_create_cq(struct mlx5_fpga_conn *conn, int cq_size)
struct mlx5_fpga_device *fdev = conn->fdev;
struct mlx5_core_dev *mdev = fdev->mdev;
u32 temp_cqc[MLX5_ST_SZ_DW(cqc)] = {0};
+ u32 out[MLX5_ST_SZ_DW(create_cq_out)];
struct mlx5_wq_param wqp;
struct mlx5_cqe64 *cqe;
int inlen, err, eqn;
@@ -476,7 +478,7 @@ static int mlx5_fpga_conn_create_cq(struct mlx5_fpga_conn *conn, int cq_size)
pas = (__be64 *)MLX5_ADDR_OF(create_cq_in, in, pas);
mlx5_fill_page_frag_array(&conn->cq.wq_ctrl.buf, pas);
- err = mlx5_core_create_cq(mdev, &conn->cq.mcq, in, inlen);
+ err = mlx5_core_create_cq(mdev, &conn->cq.mcq, in, inlen, out, sizeof(out));
kvfree(in);
if (err)
@@ -867,7 +869,7 @@ struct mlx5_fpga_conn *mlx5_fpga_conn_create(struct mlx5_fpga_device *fdev,
conn->cb_arg = attr->cb_arg;
remote_mac = MLX5_ADDR_OF(fpga_qpc, conn->fpga_qpc, remote_mac_47_32);
- err = mlx5_query_nic_vport_mac_address(fdev->mdev, 0, remote_mac);
+ err = mlx5_query_mac_address(fdev->mdev, remote_mac);
if (err) {
mlx5_fpga_err(fdev, "Failed to query local MAC: %d\n", err);
ret = ERR_PTR(err);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c
index 52c47d3dd5a5..c76da309506b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c
@@ -636,7 +636,8 @@ static bool mlx5_is_fpga_egress_ipsec_rule(struct mlx5_core_dev *dev,
u8 match_criteria_enable,
const u32 *match_c,
const u32 *match_v,
- struct mlx5_flow_act *flow_act)
+ struct mlx5_flow_act *flow_act,
+ struct mlx5_flow_context *flow_context)
{
const void *outer_c = MLX5_ADDR_OF(fte_match_param, match_c,
outer_headers);
@@ -655,7 +656,7 @@ static bool mlx5_is_fpga_egress_ipsec_rule(struct mlx5_core_dev *dev,
(match_criteria_enable &
~(MLX5_MATCH_OUTER_HEADERS | MLX5_MATCH_MISC_PARAMETERS)) ||
(flow_act->action & ~(MLX5_FLOW_CONTEXT_ACTION_ENCRYPT | MLX5_FLOW_CONTEXT_ACTION_ALLOW)) ||
- (flow_act->flags & FLOW_ACT_HAS_TAG))
+ (flow_context->flags & FLOW_CONTEXT_HAS_TAG))
return false;
return true;
@@ -767,7 +768,8 @@ mlx5_fpga_ipsec_fs_create_sa_ctx(struct mlx5_core_dev *mdev,
fg->mask.match_criteria_enable,
fg->mask.match_criteria,
fte->val,
- &fte->action))
+ &fte->action,
+ &fte->flow_context))
return ERR_PTR(-EINVAL);
else if (!mlx5_is_fpga_ipsec_rule(mdev,
fg->mask.match_criteria_enable,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.h b/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.h
index 2b5e63b0d4d6..382985e65b48 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.h
@@ -37,8 +37,6 @@
#include "accel/ipsec.h"
#include "fs_cmd.h"
-#ifdef CONFIG_MLX5_FPGA
-
u32 mlx5_fpga_ipsec_device_caps(struct mlx5_core_dev *mdev);
unsigned int mlx5_fpga_ipsec_counters_count(struct mlx5_core_dev *mdev);
int mlx5_fpga_ipsec_counters_read(struct mlx5_core_dev *mdev, u64 *counters,
@@ -66,77 +64,4 @@ int mlx5_fpga_esp_modify_xfrm(struct mlx5_accel_esp_xfrm *xfrm,
const struct mlx5_flow_cmds *
mlx5_fs_cmd_get_default_ipsec_fpga_cmds(enum fs_flow_table_type type);
-#else
-
-static inline u32 mlx5_fpga_ipsec_device_caps(struct mlx5_core_dev *mdev)
-{
- return 0;
-}
-
-static inline unsigned int
-mlx5_fpga_ipsec_counters_count(struct mlx5_core_dev *mdev)
-{
- return 0;
-}
-
-static inline int mlx5_fpga_ipsec_counters_read(struct mlx5_core_dev *mdev,
- u64 *counters)
-{
- return 0;
-}
-
-static inline void *
-mlx5_fpga_ipsec_create_sa_ctx(struct mlx5_core_dev *mdev,
- struct mlx5_accel_esp_xfrm *accel_xfrm,
- const __be32 saddr[4],
- const __be32 daddr[4],
- const __be32 spi, bool is_ipv6)
-{
- return NULL;
-}
-
-static inline void mlx5_fpga_ipsec_delete_sa_ctx(void *context)
-{
-}
-
-static inline int mlx5_fpga_ipsec_init(struct mlx5_core_dev *mdev)
-{
- return 0;
-}
-
-static inline void mlx5_fpga_ipsec_cleanup(struct mlx5_core_dev *mdev)
-{
-}
-
-static inline void mlx5_fpga_ipsec_build_fs_cmds(void)
-{
-}
-
-static inline struct mlx5_accel_esp_xfrm *
-mlx5_fpga_esp_create_xfrm(struct mlx5_core_dev *mdev,
- const struct mlx5_accel_esp_xfrm_attrs *attrs,
- u32 flags)
-{
- return ERR_PTR(-EOPNOTSUPP);
-}
-
-static inline void mlx5_fpga_esp_destroy_xfrm(struct mlx5_accel_esp_xfrm *xfrm)
-{
-}
-
-static inline int
-mlx5_fpga_esp_modify_xfrm(struct mlx5_accel_esp_xfrm *xfrm,
- const struct mlx5_accel_esp_xfrm_attrs *attrs)
-{
- return -EOPNOTSUPP;
-}
-
-static inline const struct mlx5_flow_cmds *
-mlx5_fs_cmd_get_default_ipsec_fpga_cmds(enum fs_flow_table_type type)
-{
- return mlx5_fs_cmd_get_default(type);
-}
-
-#endif /* CONFIG_MLX5_FPGA */
-
#endif /* __MLX5_FPGA_SADB_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c
index 013b1ca4a791..7ac1249eadc3 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c
@@ -147,6 +147,7 @@ static int mlx5_cmd_create_flow_table(struct mlx5_flow_root_namespace *ns,
{
int en_encap = !!(ft->flags & MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT);
int en_decap = !!(ft->flags & MLX5_FLOW_TABLE_TUNNEL_EN_DECAP);
+ int term = !!(ft->flags & MLX5_FLOW_TABLE_TERMINATION);
u32 out[MLX5_ST_SZ_DW(create_flow_table_out)] = {0};
u32 in[MLX5_ST_SZ_DW(create_flow_table_in)] = {0};
struct mlx5_core_dev *dev = ns->dev;
@@ -167,6 +168,8 @@ static int mlx5_cmd_create_flow_table(struct mlx5_flow_root_namespace *ns,
en_decap);
MLX5_SET(create_flow_table_in, in, flow_table_context.reformat_en,
en_encap);
+ MLX5_SET(create_flow_table_in, in, flow_table_context.termination_table,
+ term);
switch (ft->op_mod) {
case FS_FT_OP_MOD_NORMAL:
@@ -393,7 +396,11 @@ static int mlx5_cmd_set_fte(struct mlx5_core_dev *dev,
in_flow_context = MLX5_ADDR_OF(set_fte_in, in, flow_context);
MLX5_SET(flow_context, in_flow_context, group_id, group_id);
- MLX5_SET(flow_context, in_flow_context, flow_tag, fte->action.flow_tag);
+ MLX5_SET(flow_context, in_flow_context, flow_tag,
+ fte->flow_context.flow_tag);
+ MLX5_SET(flow_context, in_flow_context, flow_source,
+ fte->flow_context.flow_source);
+
MLX5_SET(flow_context, in_flow_context, extended_destination,
extended_dest);
if (extended_dest) {
@@ -768,6 +775,10 @@ int mlx5_modify_header_alloc(struct mlx5_core_dev *dev,
max_actions = MLX5_CAP_FLOWTABLE_NIC_TX(dev, max_modify_header_actions);
table_type = FS_FT_NIC_TX;
break;
+ case MLX5_FLOW_NAMESPACE_ESW_INGRESS:
+ max_actions = MLX5_CAP_ESW_INGRESS_ACL(dev, max_modify_header_actions);
+ table_type = FS_FT_ESW_INGRESS_ACL;
+ break;
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
index fe76c6fd6d80..3e99799bdb40 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
@@ -584,7 +584,7 @@ err_ida_remove:
}
static struct fs_fte *alloc_fte(struct mlx5_flow_table *ft,
- u32 *match_value,
+ const struct mlx5_flow_spec *spec,
struct mlx5_flow_act *flow_act)
{
struct mlx5_flow_steering *steering = get_steering(&ft->node);
@@ -594,9 +594,10 @@ static struct fs_fte *alloc_fte(struct mlx5_flow_table *ft,
if (!fte)
return ERR_PTR(-ENOMEM);
- memcpy(fte->val, match_value, sizeof(fte->val));
+ memcpy(fte->val, &spec->match_value, sizeof(fte->val));
fte->node.type = FS_TYPE_FLOW_ENTRY;
fte->action = *flow_act;
+ fte->flow_context = spec->flow_context;
tree_init_node(&fte->node, NULL, del_sw_fte);
@@ -612,7 +613,7 @@ static void dealloc_flow_group(struct mlx5_flow_steering *steering,
static struct mlx5_flow_group *alloc_flow_group(struct mlx5_flow_steering *steering,
u8 match_criteria_enable,
- void *match_criteria,
+ const void *match_criteria,
int start_index,
int end_index)
{
@@ -642,7 +643,7 @@ static struct mlx5_flow_group *alloc_flow_group(struct mlx5_flow_steering *steer
static struct mlx5_flow_group *alloc_insert_flow_group(struct mlx5_flow_table *ft,
u8 match_criteria_enable,
- void *match_criteria,
+ const void *match_criteria,
int start_index,
int end_index,
struct list_head *prev)
@@ -1285,7 +1286,7 @@ free_handle:
}
static struct mlx5_flow_group *alloc_auto_flow_group(struct mlx5_flow_table *ft,
- struct mlx5_flow_spec *spec)
+ const struct mlx5_flow_spec *spec)
{
struct list_head *prev = &ft->node.children;
struct mlx5_flow_group *fg;
@@ -1430,7 +1431,9 @@ static bool check_conflicting_actions(u32 action1, u32 action2)
return false;
}
-static int check_conflicting_ftes(struct fs_fte *fte, const struct mlx5_flow_act *flow_act)
+static int check_conflicting_ftes(struct fs_fte *fte,
+ const struct mlx5_flow_context *flow_context,
+ const struct mlx5_flow_act *flow_act)
{
if (check_conflicting_actions(flow_act->action, fte->action.action)) {
mlx5_core_warn(get_dev(&fte->node),
@@ -1438,12 +1441,12 @@ static int check_conflicting_ftes(struct fs_fte *fte, const struct mlx5_flow_act
return -EEXIST;
}
- if ((flow_act->flags & FLOW_ACT_HAS_TAG) &&
- fte->action.flow_tag != flow_act->flow_tag) {
+ if ((flow_context->flags & FLOW_CONTEXT_HAS_TAG) &&
+ fte->flow_context.flow_tag != flow_context->flow_tag) {
mlx5_core_warn(get_dev(&fte->node),
"FTE flow tag %u already exists with different flow tag %u\n",
- fte->action.flow_tag,
- flow_act->flow_tag);
+ fte->flow_context.flow_tag,
+ flow_context->flow_tag);
return -EEXIST;
}
@@ -1451,7 +1454,7 @@ static int check_conflicting_ftes(struct fs_fte *fte, const struct mlx5_flow_act
}
static struct mlx5_flow_handle *add_rule_fg(struct mlx5_flow_group *fg,
- u32 *match_value,
+ const struct mlx5_flow_spec *spec,
struct mlx5_flow_act *flow_act,
struct mlx5_flow_destination *dest,
int dest_num,
@@ -1462,7 +1465,7 @@ static struct mlx5_flow_handle *add_rule_fg(struct mlx5_flow_group *fg,
int i;
int ret;
- ret = check_conflicting_ftes(fte, flow_act);
+ ret = check_conflicting_ftes(fte, &spec->flow_context, flow_act);
if (ret)
return ERR_PTR(ret);
@@ -1536,7 +1539,7 @@ static void free_match_list(struct match_list_head *head)
static int build_match_list(struct match_list_head *match_head,
struct mlx5_flow_table *ft,
- struct mlx5_flow_spec *spec)
+ const struct mlx5_flow_spec *spec)
{
struct rhlist_head *tmp, *list;
struct mlx5_flow_group *g;
@@ -1589,7 +1592,7 @@ static u64 matched_fgs_get_version(struct list_head *match_head)
static struct fs_fte *
lookup_fte_locked(struct mlx5_flow_group *g,
- u32 *match_value,
+ const u32 *match_value,
bool take_write)
{
struct fs_fte *fte_tmp;
@@ -1622,7 +1625,7 @@ out:
static struct mlx5_flow_handle *
try_add_to_existing_fg(struct mlx5_flow_table *ft,
struct list_head *match_head,
- struct mlx5_flow_spec *spec,
+ const struct mlx5_flow_spec *spec,
struct mlx5_flow_act *flow_act,
struct mlx5_flow_destination *dest,
int dest_num,
@@ -1637,7 +1640,7 @@ try_add_to_existing_fg(struct mlx5_flow_table *ft,
u64 version;
int err;
- fte = alloc_fte(ft, spec->match_value, flow_act);
+ fte = alloc_fte(ft, spec, flow_act);
if (IS_ERR(fte))
return ERR_PTR(-ENOMEM);
@@ -1653,8 +1656,7 @@ search_again_locked:
fte_tmp = lookup_fte_locked(g, spec->match_value, take_write);
if (!fte_tmp)
continue;
- rule = add_rule_fg(g, spec->match_value,
- flow_act, dest, dest_num, fte_tmp);
+ rule = add_rule_fg(g, spec, flow_act, dest, dest_num, fte_tmp);
up_write_ref_node(&fte_tmp->node, false);
tree_put_node(&fte_tmp->node, false);
kmem_cache_free(steering->ftes_cache, fte);
@@ -1701,8 +1703,7 @@ skip_search:
nested_down_write_ref_node(&fte->node, FS_LOCK_CHILD);
up_write_ref_node(&g->node, false);
- rule = add_rule_fg(g, spec->match_value,
- flow_act, dest, dest_num, fte);
+ rule = add_rule_fg(g, spec, flow_act, dest, dest_num, fte);
up_write_ref_node(&fte->node, false);
tree_put_node(&fte->node, false);
return rule;
@@ -1715,7 +1716,7 @@ out:
static struct mlx5_flow_handle *
_mlx5_add_flow_rules(struct mlx5_flow_table *ft,
- struct mlx5_flow_spec *spec,
+ const struct mlx5_flow_spec *spec,
struct mlx5_flow_act *flow_act,
struct mlx5_flow_destination *dest,
int dest_num)
@@ -1788,7 +1789,7 @@ search_again_locked:
if (err)
goto err_release_fg;
- fte = alloc_fte(ft, spec->match_value, flow_act);
+ fte = alloc_fte(ft, spec, flow_act);
if (IS_ERR(fte)) {
err = PTR_ERR(fte);
goto err_release_fg;
@@ -1802,8 +1803,7 @@ search_again_locked:
nested_down_write_ref_node(&fte->node, FS_LOCK_CHILD);
up_write_ref_node(&g->node, false);
- rule = add_rule_fg(g, spec->match_value, flow_act, dest,
- dest_num, fte);
+ rule = add_rule_fg(g, spec, flow_act, dest, dest_num, fte);
up_write_ref_node(&fte->node, false);
tree_put_node(&fte->node, false);
tree_put_node(&g->node, false);
@@ -1823,7 +1823,7 @@ static bool fwd_next_prio_supported(struct mlx5_flow_table *ft)
struct mlx5_flow_handle *
mlx5_add_flow_rules(struct mlx5_flow_table *ft,
- struct mlx5_flow_spec *spec,
+ const struct mlx5_flow_spec *spec,
struct mlx5_flow_act *flow_act,
struct mlx5_flow_destination *dest,
int num_dest)
@@ -2092,7 +2092,7 @@ struct mlx5_flow_namespace *mlx5_get_flow_vport_acl_namespace(struct mlx5_core_d
{
struct mlx5_flow_steering *steering = dev->priv.steering;
- if (!steering || vport >= MLX5_TOTAL_VPORTS(dev))
+ if (!steering || vport >= mlx5_eswitch_get_total_vports(dev))
return NULL;
switch (type) {
@@ -2423,7 +2423,7 @@ static void cleanup_egress_acls_root_ns(struct mlx5_core_dev *dev)
if (!steering->esw_egress_root_ns)
return;
- for (i = 0; i < MLX5_TOTAL_VPORTS(dev); i++)
+ for (i = 0; i < mlx5_eswitch_get_total_vports(dev); i++)
cleanup_root_ns(steering->esw_egress_root_ns[i]);
kfree(steering->esw_egress_root_ns);
@@ -2438,7 +2438,7 @@ static void cleanup_ingress_acls_root_ns(struct mlx5_core_dev *dev)
if (!steering->esw_ingress_root_ns)
return;
- for (i = 0; i < MLX5_TOTAL_VPORTS(dev); i++)
+ for (i = 0; i < mlx5_eswitch_get_total_vports(dev); i++)
cleanup_root_ns(steering->esw_ingress_root_ns[i]);
kfree(steering->esw_ingress_root_ns);
@@ -2606,16 +2606,18 @@ static int init_ingress_acl_root_ns(struct mlx5_flow_steering *steering, int vpo
static int init_egress_acls_root_ns(struct mlx5_core_dev *dev)
{
struct mlx5_flow_steering *steering = dev->priv.steering;
+ int total_vports = mlx5_eswitch_get_total_vports(dev);
int err;
int i;
- steering->esw_egress_root_ns = kcalloc(MLX5_TOTAL_VPORTS(dev),
- sizeof(*steering->esw_egress_root_ns),
- GFP_KERNEL);
+ steering->esw_egress_root_ns =
+ kcalloc(total_vports,
+ sizeof(*steering->esw_egress_root_ns),
+ GFP_KERNEL);
if (!steering->esw_egress_root_ns)
return -ENOMEM;
- for (i = 0; i < MLX5_TOTAL_VPORTS(dev); i++) {
+ for (i = 0; i < total_vports; i++) {
err = init_egress_acl_root_ns(steering, i);
if (err)
goto cleanup_root_ns;
@@ -2634,16 +2636,18 @@ cleanup_root_ns:
static int init_ingress_acls_root_ns(struct mlx5_core_dev *dev)
{
struct mlx5_flow_steering *steering = dev->priv.steering;
+ int total_vports = mlx5_eswitch_get_total_vports(dev);
int err;
int i;
- steering->esw_ingress_root_ns = kcalloc(MLX5_TOTAL_VPORTS(dev),
- sizeof(*steering->esw_ingress_root_ns),
- GFP_KERNEL);
+ steering->esw_ingress_root_ns =
+ kcalloc(total_vports,
+ sizeof(*steering->esw_ingress_root_ns),
+ GFP_KERNEL);
if (!steering->esw_ingress_root_ns)
return -ENOMEM;
- for (i = 0; i < MLX5_TOTAL_VPORTS(dev); i++) {
+ for (i = 0; i < total_vports; i++) {
err = init_ingress_acl_root_ns(steering, i);
if (err)
goto cleanup_root_ns;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h
index a08c3d09a50f..c48c382f926f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h
@@ -170,6 +170,7 @@ struct fs_fte {
u32 val[MLX5_ST_SZ_DW_MATCH_PARAM];
u32 dests_size;
u32 index;
+ struct mlx5_flow_context flow_context;
struct mlx5_flow_act action;
enum fs_fte_status status;
struct mlx5_fc *counter;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
index c6c28f56aa29..b3762123a69c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
@@ -102,13 +102,15 @@ static struct list_head *mlx5_fc_counters_lookup_next(struct mlx5_core_dev *dev,
struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats;
unsigned long next_id = (unsigned long)id + 1;
struct mlx5_fc *counter;
+ unsigned long tmp;
rcu_read_lock();
/* skip counters that are in idr, but not yet in counters list */
- while ((counter = idr_get_next_ul(&fc_stats->counters_idr,
- &next_id)) != NULL &&
- list_empty(&counter->list))
- next_id++;
+ idr_for_each_entry_continue_ul(&fc_stats->counters_idr,
+ counter, tmp, next_id) {
+ if (!list_empty(&counter->list))
+ break;
+ }
rcu_read_unlock();
return counter ? &counter->list : &fc_stats->counters;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
index 1ab6f7e3bec6..a19790dee7b2 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
@@ -37,6 +37,37 @@
#include "mlx5_core.h"
#include "../../mlxfw/mlxfw.h"
+enum {
+ MCQS_IDENTIFIER_BOOT_IMG = 0x1,
+ MCQS_IDENTIFIER_OEM_NVCONFIG = 0x4,
+ MCQS_IDENTIFIER_MLNX_NVCONFIG = 0x5,
+ MCQS_IDENTIFIER_CS_TOKEN = 0x6,
+ MCQS_IDENTIFIER_DBG_TOKEN = 0x7,
+ MCQS_IDENTIFIER_GEARBOX = 0xA,
+};
+
+enum {
+ MCQS_UPDATE_STATE_IDLE,
+ MCQS_UPDATE_STATE_IN_PROGRESS,
+ MCQS_UPDATE_STATE_APPLIED,
+ MCQS_UPDATE_STATE_ACTIVE,
+ MCQS_UPDATE_STATE_ACTIVE_PENDING_RESET,
+ MCQS_UPDATE_STATE_FAILED,
+ MCQS_UPDATE_STATE_CANCELED,
+ MCQS_UPDATE_STATE_BUSY,
+};
+
+enum {
+ MCQI_INFO_TYPE_CAPABILITIES = 0x0,
+ MCQI_INFO_TYPE_VERSION = 0x1,
+ MCQI_INFO_TYPE_ACTIVATION_METHOD = 0x5,
+};
+
+enum {
+ MCQI_FW_RUNNING_VERSION = 0,
+ MCQI_FW_STORED_VERSION = 1,
+};
+
static int mlx5_cmd_query_adapter(struct mlx5_core_dev *dev, u32 *out,
int outlen)
{
@@ -202,6 +233,18 @@ int mlx5_query_hca_caps(struct mlx5_core_dev *dev)
return err;
}
+ if (MLX5_CAP_GEN(dev, event_cap)) {
+ err = mlx5_core_get_caps(dev, MLX5_CAP_DEV_EVENT);
+ if (err)
+ return err;
+ }
+
+ if (MLX5_CAP_GEN(dev, tls)) {
+ err = mlx5_core_get_caps(dev, MLX5_CAP_TLS);
+ if (err)
+ return err;
+ }
+
return 0;
}
@@ -392,33 +435,49 @@ static int mlx5_reg_mcda_set(struct mlx5_core_dev *dev,
}
static int mlx5_reg_mcqi_query(struct mlx5_core_dev *dev,
- u16 component_index,
- u32 *max_component_size,
- u8 *log_mcda_word_size,
- u16 *mcda_max_write_size)
+ u16 component_index, bool read_pending,
+ u8 info_type, u16 data_size, void *mcqi_data)
{
- u32 out[MLX5_ST_SZ_DW(mcqi_reg) + MLX5_ST_SZ_DW(mcqi_cap)];
- int offset = MLX5_ST_SZ_DW(mcqi_reg);
- u32 in[MLX5_ST_SZ_DW(mcqi_reg)];
+ u32 out[MLX5_ST_SZ_DW(mcqi_reg) + MLX5_UN_SZ_DW(mcqi_reg_data)] = {};
+ u32 in[MLX5_ST_SZ_DW(mcqi_reg)] = {};
+ void *data;
int err;
- memset(in, 0, sizeof(in));
- memset(out, 0, sizeof(out));
-
MLX5_SET(mcqi_reg, in, component_index, component_index);
- MLX5_SET(mcqi_reg, in, data_size, MLX5_ST_SZ_BYTES(mcqi_cap));
+ MLX5_SET(mcqi_reg, in, read_pending_component, read_pending);
+ MLX5_SET(mcqi_reg, in, info_type, info_type);
+ MLX5_SET(mcqi_reg, in, data_size, data_size);
err = mlx5_core_access_reg(dev, in, sizeof(in), out,
- sizeof(out), MLX5_REG_MCQI, 0, 0);
+ MLX5_ST_SZ_BYTES(mcqi_reg) + data_size,
+ MLX5_REG_MCQI, 0, 0);
if (err)
- goto out;
+ return err;
- *max_component_size = MLX5_GET(mcqi_cap, out + offset, max_component_size);
- *log_mcda_word_size = MLX5_GET(mcqi_cap, out + offset, log_mcda_word_size);
- *mcda_max_write_size = MLX5_GET(mcqi_cap, out + offset, mcda_max_write_size);
+ data = MLX5_ADDR_OF(mcqi_reg, out, data);
+ memcpy(mcqi_data, data, data_size);
-out:
- return err;
+ return 0;
+}
+
+static int mlx5_reg_mcqi_caps_query(struct mlx5_core_dev *dev, u16 component_index,
+ u32 *max_component_size, u8 *log_mcda_word_size,
+ u16 *mcda_max_write_size)
+{
+ u32 mcqi_reg[MLX5_ST_SZ_DW(mcqi_cap)] = {};
+ int err;
+
+ err = mlx5_reg_mcqi_query(dev, component_index, 0,
+ MCQI_INFO_TYPE_CAPABILITIES,
+ MLX5_ST_SZ_BYTES(mcqi_cap), mcqi_reg);
+ if (err)
+ return err;
+
+ *max_component_size = MLX5_GET(mcqi_cap, mcqi_reg, max_component_size);
+ *log_mcda_word_size = MLX5_GET(mcqi_cap, mcqi_reg, log_mcda_word_size);
+ *mcda_max_write_size = MLX5_GET(mcqi_cap, mcqi_reg, mcda_max_write_size);
+
+ return 0;
}
struct mlx5_mlxfw_dev {
@@ -434,8 +493,13 @@ static int mlx5_component_query(struct mlxfw_dev *mlxfw_dev,
container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
- return mlx5_reg_mcqi_query(dev, component_index, p_max_size,
- p_align_bits, p_max_write_size);
+ if (!MLX5_CAP_GEN(dev, mcam_reg) || !MLX5_CAP_MCAM_REG(dev, mcqi)) {
+ mlx5_core_warn(dev, "caps query isn't supported by running FW\n");
+ return -EOPNOTSUPP;
+ }
+
+ return mlx5_reg_mcqi_caps_query(dev, component_index, p_max_size,
+ p_align_bits, p_max_write_size);
}
static int mlx5_fsm_lock(struct mlxfw_dev *mlxfw_dev, u32 *fwhandle)
@@ -552,7 +616,8 @@ static const struct mlxfw_dev_ops mlx5_mlxfw_dev_ops = {
};
int mlx5_firmware_flash(struct mlx5_core_dev *dev,
- const struct firmware *firmware)
+ const struct firmware *firmware,
+ struct netlink_ext_ack *extack)
{
struct mlx5_mlxfw_dev mlx5_mlxfw_dev = {
.mlxfw_dev = {
@@ -571,5 +636,133 @@ int mlx5_firmware_flash(struct mlx5_core_dev *dev,
return -EOPNOTSUPP;
}
- return mlxfw_firmware_flash(&mlx5_mlxfw_dev.mlxfw_dev, firmware);
+ return mlxfw_firmware_flash(&mlx5_mlxfw_dev.mlxfw_dev,
+ firmware, extack);
+}
+
+static int mlx5_reg_mcqi_version_query(struct mlx5_core_dev *dev,
+ u16 component_index, bool read_pending,
+ u32 *mcqi_version_out)
+{
+ return mlx5_reg_mcqi_query(dev, component_index, read_pending,
+ MCQI_INFO_TYPE_VERSION,
+ MLX5_ST_SZ_BYTES(mcqi_version),
+ mcqi_version_out);
+}
+
+static int mlx5_reg_mcqs_query(struct mlx5_core_dev *dev, u32 *out,
+ u16 component_index)
+{
+ u8 out_sz = MLX5_ST_SZ_BYTES(mcqs_reg);
+ u32 in[MLX5_ST_SZ_DW(mcqs_reg)] = {};
+ int err;
+
+ memset(out, 0, out_sz);
+
+ MLX5_SET(mcqs_reg, in, component_index, component_index);
+
+ err = mlx5_core_access_reg(dev, in, sizeof(in), out,
+ out_sz, MLX5_REG_MCQS, 0, 0);
+ return err;
+}
+
+/* scans component index sequentially, to find the boot img index */
+static int mlx5_get_boot_img_component_index(struct mlx5_core_dev *dev)
+{
+ u32 out[MLX5_ST_SZ_DW(mcqs_reg)] = {};
+ u16 identifier, component_idx = 0;
+ bool quit;
+ int err;
+
+ do {
+ err = mlx5_reg_mcqs_query(dev, out, component_idx);
+ if (err)
+ return err;
+
+ identifier = MLX5_GET(mcqs_reg, out, identifier);
+ quit = !!MLX5_GET(mcqs_reg, out, last_index_flag);
+ quit |= identifier == MCQS_IDENTIFIER_BOOT_IMG;
+ } while (!quit && ++component_idx);
+
+ if (identifier != MCQS_IDENTIFIER_BOOT_IMG) {
+ mlx5_core_warn(dev, "mcqs: can't find boot_img component ix, last scanned idx %d\n",
+ component_idx);
+ return -EOPNOTSUPP;
+ }
+
+ return component_idx;
+}
+
+static int
+mlx5_fw_image_pending(struct mlx5_core_dev *dev,
+ int component_index,
+ bool *pending_version_exists)
+{
+ u32 out[MLX5_ST_SZ_DW(mcqs_reg)];
+ u8 component_update_state;
+ int err;
+
+ err = mlx5_reg_mcqs_query(dev, out, component_index);
+ if (err)
+ return err;
+
+ component_update_state = MLX5_GET(mcqs_reg, out, component_update_state);
+
+ if (component_update_state == MCQS_UPDATE_STATE_IDLE) {
+ *pending_version_exists = false;
+ } else if (component_update_state == MCQS_UPDATE_STATE_ACTIVE_PENDING_RESET) {
+ *pending_version_exists = true;
+ } else {
+ mlx5_core_warn(dev,
+ "mcqs: can't read pending fw version while fw state is %d\n",
+ component_update_state);
+ return -ENODATA;
+ }
+ return 0;
+}
+
+int mlx5_fw_version_query(struct mlx5_core_dev *dev,
+ u32 *running_ver, u32 *pending_ver)
+{
+ u32 reg_mcqi_version[MLX5_ST_SZ_DW(mcqi_version)] = {};
+ bool pending_version_exists;
+ int component_index;
+ int err;
+
+ if (!MLX5_CAP_GEN(dev, mcam_reg) || !MLX5_CAP_MCAM_REG(dev, mcqi) ||
+ !MLX5_CAP_MCAM_REG(dev, mcqs)) {
+ mlx5_core_warn(dev, "fw query isn't supported by the FW\n");
+ return -EOPNOTSUPP;
+ }
+
+ component_index = mlx5_get_boot_img_component_index(dev);
+ if (component_index < 0)
+ return component_index;
+
+ err = mlx5_reg_mcqi_version_query(dev, component_index,
+ MCQI_FW_RUNNING_VERSION,
+ reg_mcqi_version);
+ if (err)
+ return err;
+
+ *running_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version);
+
+ err = mlx5_fw_image_pending(dev, component_index, &pending_version_exists);
+ if (err)
+ return err;
+
+ if (!pending_version_exists) {
+ *pending_ver = 0;
+ return 0;
+ }
+
+ err = mlx5_reg_mcqi_version_query(dev, component_index,
+ MCQI_FW_STORED_VERSION,
+ reg_mcqi_version);
+ if (err)
+ return err;
+
+ *pending_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version);
+
+ return 0;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c
index a2656f4008d9..9314777d99e3 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/health.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c
@@ -40,6 +40,8 @@
#include "mlx5_core.h"
#include "lib/eq.h"
#include "lib/mlx5.h"
+#include "lib/pci_vsc.h"
+#include "diag/fw_tracer.h"
enum {
MLX5_HEALTH_POLL_INTERVAL = 2 * HZ,
@@ -62,12 +64,20 @@ enum {
enum {
MLX5_DROP_NEW_HEALTH_WORK,
- MLX5_DROP_NEW_RECOVERY_WORK,
+};
+
+enum {
+ MLX5_SENSOR_NO_ERR = 0,
+ MLX5_SENSOR_PCI_COMM_ERR = 1,
+ MLX5_SENSOR_PCI_ERR = 2,
+ MLX5_SENSOR_NIC_DISABLED = 3,
+ MLX5_SENSOR_NIC_SW_RESET = 4,
+ MLX5_SENSOR_FW_SYND_RFR = 5,
};
u8 mlx5_get_nic_state(struct mlx5_core_dev *dev)
{
- return (ioread32be(&dev->iseg->cmdq_addr_l_sz) >> 8) & 3;
+ return (ioread32be(&dev->iseg->cmdq_addr_l_sz) >> 8) & 7;
}
void mlx5_set_nic_state(struct mlx5_core_dev *dev, u8 state)
@@ -80,18 +90,105 @@ void mlx5_set_nic_state(struct mlx5_core_dev *dev, u8 state)
&dev->iseg->cmdq_addr_l_sz);
}
-static int in_fatal(struct mlx5_core_dev *dev)
+static bool sensor_pci_not_working(struct mlx5_core_dev *dev)
{
struct mlx5_core_health *health = &dev->priv.health;
struct health_buffer __iomem *h = health->health;
+ /* Offline PCI reads return 0xffffffff */
+ return (ioread32be(&h->fw_ver) == 0xffffffff);
+}
+
+static bool sensor_fw_synd_rfr(struct mlx5_core_dev *dev)
+{
+ struct mlx5_core_health *health = &dev->priv.health;
+ struct health_buffer __iomem *h = health->health;
+ u32 rfr = ioread32be(&h->rfr) >> MLX5_RFR_OFFSET;
+ u8 synd = ioread8(&h->synd);
+
+ if (rfr && synd)
+ mlx5_core_dbg(dev, "FW requests reset, synd: %d\n", synd);
+ return rfr && synd;
+}
+
+static u32 check_fatal_sensors(struct mlx5_core_dev *dev)
+{
+ if (sensor_pci_not_working(dev))
+ return MLX5_SENSOR_PCI_COMM_ERR;
+ if (pci_channel_offline(dev->pdev))
+ return MLX5_SENSOR_PCI_ERR;
if (mlx5_get_nic_state(dev) == MLX5_NIC_IFC_DISABLED)
- return 1;
+ return MLX5_SENSOR_NIC_DISABLED;
+ if (mlx5_get_nic_state(dev) == MLX5_NIC_IFC_SW_RESET)
+ return MLX5_SENSOR_NIC_SW_RESET;
+ if (sensor_fw_synd_rfr(dev))
+ return MLX5_SENSOR_FW_SYND_RFR;
- if (ioread32be(&h->fw_ver) == 0xffffffff)
- return 1;
+ return MLX5_SENSOR_NO_ERR;
+}
- return 0;
+static int lock_sem_sw_reset(struct mlx5_core_dev *dev, bool lock)
+{
+ enum mlx5_vsc_state state;
+ int ret;
+
+ if (!mlx5_core_is_pf(dev))
+ return -EBUSY;
+
+ /* Try to lock GW access, this stage doesn't return
+ * EBUSY because locked GW does not mean that other PF
+ * already started the reset.
+ */
+ ret = mlx5_vsc_gw_lock(dev);
+ if (ret == -EBUSY)
+ return -EINVAL;
+ if (ret)
+ return ret;
+
+ state = lock ? MLX5_VSC_LOCK : MLX5_VSC_UNLOCK;
+ /* At this stage, if the return status == EBUSY, then we know
+ * for sure that another PF started the reset, so don't allow
+ * another reset.
+ */
+ ret = mlx5_vsc_sem_set_space(dev, MLX5_SEMAPHORE_SW_RESET, state);
+ if (ret)
+ mlx5_core_warn(dev, "Failed to lock SW reset semaphore\n");
+
+ /* Unlock GW access */
+ mlx5_vsc_gw_unlock(dev);
+
+ return ret;
+}
+
+static bool reset_fw_if_needed(struct mlx5_core_dev *dev)
+{
+ bool supported = (ioread32be(&dev->iseg->initializing) >>
+ MLX5_FW_RESET_SUPPORTED_OFFSET) & 1;
+ u32 fatal_error;
+
+ if (!supported)
+ return false;
+
+ /* The reset only needs to be issued by one PF. The health buffer is
+ * shared between all functions, and will be cleared during a reset.
+ * Check again to avoid a redundant 2nd reset. If the fatal erros was
+ * PCI related a reset won't help.
+ */
+ fatal_error = check_fatal_sensors(dev);
+ if (fatal_error == MLX5_SENSOR_PCI_COMM_ERR ||
+ fatal_error == MLX5_SENSOR_NIC_DISABLED ||
+ fatal_error == MLX5_SENSOR_NIC_SW_RESET) {
+ mlx5_core_warn(dev, "Not issuing FW reset. Either it's already done or won't help.");
+ return false;
+ }
+
+ mlx5_core_warn(dev, "Issuing FW Reset\n");
+ /* Write the NIC interface field to initiate the reset, the command
+ * interface address also resides here, don't overwrite it.
+ */
+ mlx5_set_nic_state(dev, MLX5_NIC_IFC_SW_RESET);
+
+ return true;
}
void mlx5_enter_error_state(struct mlx5_core_dev *dev, bool force)
@@ -99,14 +196,65 @@ void mlx5_enter_error_state(struct mlx5_core_dev *dev, bool force)
mutex_lock(&dev->intf_state_mutex);
if (dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR)
goto unlock;
+ if (dev->state == MLX5_DEVICE_STATE_UNINITIALIZED) {
+ dev->state = MLX5_DEVICE_STATE_INTERNAL_ERROR;
+ goto unlock;
+ }
- mlx5_core_err(dev, "start\n");
- if (pci_channel_offline(dev->pdev) || in_fatal(dev) || force) {
+ if (check_fatal_sensors(dev) || force) {
dev->state = MLX5_DEVICE_STATE_INTERNAL_ERROR;
mlx5_cmd_flush(dev);
}
mlx5_notifier_call_chain(dev->priv.events, MLX5_DEV_EVENT_SYS_ERROR, (void *)1);
+unlock:
+ mutex_unlock(&dev->intf_state_mutex);
+}
+
+#define MLX5_CRDUMP_WAIT_MS 60000
+#define MLX5_FW_RESET_WAIT_MS 1000
+void mlx5_error_sw_reset(struct mlx5_core_dev *dev)
+{
+ unsigned long end, delay_ms = MLX5_FW_RESET_WAIT_MS;
+ int lock = -EBUSY;
+
+ mutex_lock(&dev->intf_state_mutex);
+ if (dev->state != MLX5_DEVICE_STATE_INTERNAL_ERROR)
+ goto unlock;
+
+ mlx5_core_err(dev, "start\n");
+
+ if (check_fatal_sensors(dev) == MLX5_SENSOR_FW_SYND_RFR) {
+ /* Get cr-dump and reset FW semaphore */
+ lock = lock_sem_sw_reset(dev, true);
+
+ if (lock == -EBUSY) {
+ delay_ms = MLX5_CRDUMP_WAIT_MS;
+ goto recover_from_sw_reset;
+ }
+ /* Execute SW reset */
+ reset_fw_if_needed(dev);
+ }
+
+recover_from_sw_reset:
+ /* Recover from SW reset */
+ end = jiffies + msecs_to_jiffies(delay_ms);
+ do {
+ if (mlx5_get_nic_state(dev) == MLX5_NIC_IFC_DISABLED)
+ break;
+
+ cond_resched();
+ } while (!time_after(jiffies, end));
+
+ if (mlx5_get_nic_state(dev) != MLX5_NIC_IFC_DISABLED) {
+ dev_err(&dev->pdev->dev, "NIC IFC still %d after %lums.\n",
+ mlx5_get_nic_state(dev), delay_ms);
+ }
+
+ /* Release FW semaphore if you are the lock owner */
+ if (!lock)
+ lock_sem_sw_reset(dev, false);
+
mlx5_core_err(dev, "end\n");
unlock:
@@ -129,6 +277,20 @@ static void mlx5_handle_bad_state(struct mlx5_core_dev *dev)
case MLX5_NIC_IFC_NO_DRAM_NIC:
mlx5_core_warn(dev, "Expected to see disabled NIC but it is no dram nic\n");
break;
+
+ case MLX5_NIC_IFC_SW_RESET:
+ /* The IFC mode field is 3 bits, so it will read 0x7 in 2 cases:
+ * 1. PCI has been disabled (ie. PCI-AER, PF driver unloaded
+ * and this is a VF), this is not recoverable by SW reset.
+ * Logging of this is handled elsewhere.
+ * 2. FW reset has been issued by another function, driver can
+ * be reloaded to recover after the mode switches to
+ * MLX5_NIC_IFC_DISABLED.
+ */
+ if (dev->priv.health.fatal_error != MLX5_SENSOR_PCI_COMM_ERR)
+ mlx5_core_warn(dev, "NIC SW reset in progress\n");
+ break;
+
default:
mlx5_core_warn(dev, "Expected to see disabled NIC but it is has invalid value %d\n",
nic_interface);
@@ -137,52 +299,32 @@ static void mlx5_handle_bad_state(struct mlx5_core_dev *dev)
mlx5_disable_device(dev);
}
-static void health_recover(struct work_struct *work)
-{
- struct mlx5_core_health *health;
- struct delayed_work *dwork;
- struct mlx5_core_dev *dev;
- struct mlx5_priv *priv;
- u8 nic_state;
-
- dwork = container_of(work, struct delayed_work, work);
- health = container_of(dwork, struct mlx5_core_health, recover_work);
- priv = container_of(health, struct mlx5_priv, health);
- dev = container_of(priv, struct mlx5_core_dev, priv);
-
- nic_state = mlx5_get_nic_state(dev);
- if (nic_state == MLX5_NIC_IFC_INVALID) {
- mlx5_core_err(dev, "health recovery flow aborted since the nic state is invalid\n");
- return;
- }
-
- mlx5_core_err(dev, "starting health recovery flow\n");
- mlx5_recover_device(dev);
-}
-
/* How much time to wait until health resetting the driver (in msecs) */
-#define MLX5_RECOVERY_DELAY_MSECS 60000
-static void health_care(struct work_struct *work)
+#define MLX5_RECOVERY_WAIT_MSECS 60000
+static int mlx5_health_try_recover(struct mlx5_core_dev *dev)
{
- unsigned long recover_delay = msecs_to_jiffies(MLX5_RECOVERY_DELAY_MSECS);
- struct mlx5_core_health *health;
- struct mlx5_core_dev *dev;
- struct mlx5_priv *priv;
- unsigned long flags;
+ unsigned long end;
- health = container_of(work, struct mlx5_core_health, work);
- priv = container_of(health, struct mlx5_priv, health);
- dev = container_of(priv, struct mlx5_core_dev, priv);
mlx5_core_warn(dev, "handling bad device here\n");
mlx5_handle_bad_state(dev);
+ end = jiffies + msecs_to_jiffies(MLX5_RECOVERY_WAIT_MSECS);
+ while (sensor_pci_not_working(dev)) {
+ if (time_after(jiffies, end)) {
+ mlx5_core_err(dev,
+ "health recovery flow aborted, PCI reads still not working\n");
+ return -EIO;
+ }
+ msleep(100);
+ }
- spin_lock_irqsave(&health->wq_lock, flags);
- if (!test_bit(MLX5_DROP_NEW_RECOVERY_WORK, &health->flags))
- schedule_delayed_work(&health->recover_work, recover_delay);
- else
- mlx5_core_err(dev,
- "new health works are not permitted at this stage\n");
- spin_unlock_irqrestore(&health->wq_lock, flags);
+ mlx5_core_err(dev, "starting health recovery flow\n");
+ mlx5_recover_device(dev);
+ if (!test_bit(MLX5_INTERFACE_STATE_UP, &dev->intf_state) ||
+ check_fatal_sensors(dev)) {
+ mlx5_core_err(dev, "health recovery failed\n");
+ return -EIO;
+ }
+ return 0;
}
static const char *hsynd_str(u8 synd)
@@ -246,6 +388,282 @@ static void print_health_info(struct mlx5_core_dev *dev)
mlx5_core_err(dev, "raw fw_ver 0x%08x\n", fw);
}
+static int
+mlx5_fw_reporter_diagnose(struct devlink_health_reporter *reporter,
+ struct devlink_fmsg *fmsg)
+{
+ struct mlx5_core_dev *dev = devlink_health_reporter_priv(reporter);
+ struct mlx5_core_health *health = &dev->priv.health;
+ struct health_buffer __iomem *h = health->health;
+ u8 synd;
+ int err;
+
+ synd = ioread8(&h->synd);
+ err = devlink_fmsg_u8_pair_put(fmsg, "Syndrome", synd);
+ if (err || !synd)
+ return err;
+ return devlink_fmsg_string_pair_put(fmsg, "Description", hsynd_str(synd));
+}
+
+struct mlx5_fw_reporter_ctx {
+ u8 err_synd;
+ int miss_counter;
+};
+
+static int
+mlx5_fw_reporter_ctx_pairs_put(struct devlink_fmsg *fmsg,
+ struct mlx5_fw_reporter_ctx *fw_reporter_ctx)
+{
+ int err;
+
+ err = devlink_fmsg_u8_pair_put(fmsg, "syndrome",
+ fw_reporter_ctx->err_synd);
+ if (err)
+ return err;
+ err = devlink_fmsg_u32_pair_put(fmsg, "fw_miss_counter",
+ fw_reporter_ctx->miss_counter);
+ if (err)
+ return err;
+ return 0;
+}
+
+static int
+mlx5_fw_reporter_heath_buffer_data_put(struct mlx5_core_dev *dev,
+ struct devlink_fmsg *fmsg)
+{
+ struct mlx5_core_health *health = &dev->priv.health;
+ struct health_buffer __iomem *h = health->health;
+ int err;
+ int i;
+
+ if (!ioread8(&h->synd))
+ return 0;
+
+ err = devlink_fmsg_pair_nest_start(fmsg, "health buffer");
+ if (err)
+ return err;
+ err = devlink_fmsg_obj_nest_start(fmsg);
+ if (err)
+ return err;
+ err = devlink_fmsg_arr_pair_nest_start(fmsg, "assert_var");
+ if (err)
+ return err;
+
+ for (i = 0; i < ARRAY_SIZE(h->assert_var); i++) {
+ err = devlink_fmsg_u32_put(fmsg, ioread32be(h->assert_var + i));
+ if (err)
+ return err;
+ }
+ err = devlink_fmsg_arr_pair_nest_end(fmsg);
+ if (err)
+ return err;
+ err = devlink_fmsg_u32_pair_put(fmsg, "assert_exit_ptr",
+ ioread32be(&h->assert_exit_ptr));
+ if (err)
+ return err;
+ err = devlink_fmsg_u32_pair_put(fmsg, "assert_callra",
+ ioread32be(&h->assert_callra));
+ if (err)
+ return err;
+ err = devlink_fmsg_u32_pair_put(fmsg, "hw_id", ioread32be(&h->hw_id));
+ if (err)
+ return err;
+ err = devlink_fmsg_u8_pair_put(fmsg, "irisc_index",
+ ioread8(&h->irisc_index));
+ if (err)
+ return err;
+ err = devlink_fmsg_u8_pair_put(fmsg, "synd", ioread8(&h->synd));
+ if (err)
+ return err;
+ err = devlink_fmsg_u32_pair_put(fmsg, "ext_synd",
+ ioread16be(&h->ext_synd));
+ if (err)
+ return err;
+ err = devlink_fmsg_u32_pair_put(fmsg, "raw_fw_ver",
+ ioread32be(&h->fw_ver));
+ if (err)
+ return err;
+ err = devlink_fmsg_obj_nest_end(fmsg);
+ if (err)
+ return err;
+ return devlink_fmsg_pair_nest_end(fmsg);
+}
+
+static int
+mlx5_fw_reporter_dump(struct devlink_health_reporter *reporter,
+ struct devlink_fmsg *fmsg, void *priv_ctx)
+{
+ struct mlx5_core_dev *dev = devlink_health_reporter_priv(reporter);
+ int err;
+
+ err = mlx5_fw_tracer_trigger_core_dump_general(dev);
+ if (err)
+ return err;
+
+ if (priv_ctx) {
+ struct mlx5_fw_reporter_ctx *fw_reporter_ctx = priv_ctx;
+
+ err = mlx5_fw_reporter_ctx_pairs_put(fmsg, fw_reporter_ctx);
+ if (err)
+ return err;
+ }
+
+ err = mlx5_fw_reporter_heath_buffer_data_put(dev, fmsg);
+ if (err)
+ return err;
+ return mlx5_fw_tracer_get_saved_traces_objects(dev->tracer, fmsg);
+}
+
+static void mlx5_fw_reporter_err_work(struct work_struct *work)
+{
+ struct mlx5_fw_reporter_ctx fw_reporter_ctx;
+ struct mlx5_core_health *health;
+
+ health = container_of(work, struct mlx5_core_health, report_work);
+
+ if (IS_ERR_OR_NULL(health->fw_reporter))
+ return;
+
+ fw_reporter_ctx.err_synd = health->synd;
+ fw_reporter_ctx.miss_counter = health->miss_counter;
+ if (fw_reporter_ctx.err_synd) {
+ devlink_health_report(health->fw_reporter,
+ "FW syndrom reported", &fw_reporter_ctx);
+ return;
+ }
+ if (fw_reporter_ctx.miss_counter)
+ devlink_health_report(health->fw_reporter,
+ "FW miss counter reported",
+ &fw_reporter_ctx);
+}
+
+static const struct devlink_health_reporter_ops mlx5_fw_reporter_ops = {
+ .name = "fw",
+ .diagnose = mlx5_fw_reporter_diagnose,
+ .dump = mlx5_fw_reporter_dump,
+};
+
+static int
+mlx5_fw_fatal_reporter_recover(struct devlink_health_reporter *reporter,
+ void *priv_ctx)
+{
+ struct mlx5_core_dev *dev = devlink_health_reporter_priv(reporter);
+
+ return mlx5_health_try_recover(dev);
+}
+
+#define MLX5_CR_DUMP_CHUNK_SIZE 256
+static int
+mlx5_fw_fatal_reporter_dump(struct devlink_health_reporter *reporter,
+ struct devlink_fmsg *fmsg, void *priv_ctx)
+{
+ struct mlx5_core_dev *dev = devlink_health_reporter_priv(reporter);
+ u32 crdump_size = dev->priv.health.crdump_size;
+ u32 *cr_data;
+ u32 data_size;
+ u32 offset;
+ int err;
+
+ if (!mlx5_core_is_pf(dev))
+ return -EPERM;
+
+ cr_data = kvmalloc(crdump_size, GFP_KERNEL);
+ if (!cr_data)
+ return -ENOMEM;
+ err = mlx5_crdump_collect(dev, cr_data);
+ if (err)
+ return err;
+
+ if (priv_ctx) {
+ struct mlx5_fw_reporter_ctx *fw_reporter_ctx = priv_ctx;
+
+ err = mlx5_fw_reporter_ctx_pairs_put(fmsg, fw_reporter_ctx);
+ if (err)
+ goto free_data;
+ }
+
+ err = devlink_fmsg_arr_pair_nest_start(fmsg, "crdump_data");
+ if (err)
+ goto free_data;
+ for (offset = 0; offset < crdump_size; offset += data_size) {
+ if (crdump_size - offset < MLX5_CR_DUMP_CHUNK_SIZE)
+ data_size = crdump_size - offset;
+ else
+ data_size = MLX5_CR_DUMP_CHUNK_SIZE;
+ err = devlink_fmsg_binary_put(fmsg, cr_data, data_size);
+ if (err)
+ goto free_data;
+ }
+ err = devlink_fmsg_arr_pair_nest_end(fmsg);
+
+free_data:
+ kvfree(cr_data);
+ return err;
+}
+
+static void mlx5_fw_fatal_reporter_err_work(struct work_struct *work)
+{
+ struct mlx5_fw_reporter_ctx fw_reporter_ctx;
+ struct mlx5_core_health *health;
+ struct mlx5_core_dev *dev;
+ struct mlx5_priv *priv;
+
+ health = container_of(work, struct mlx5_core_health, fatal_report_work);
+ priv = container_of(health, struct mlx5_priv, health);
+ dev = container_of(priv, struct mlx5_core_dev, priv);
+
+ mlx5_enter_error_state(dev, false);
+ if (IS_ERR_OR_NULL(health->fw_fatal_reporter)) {
+ if (mlx5_health_try_recover(dev))
+ mlx5_core_err(dev, "health recovery failed\n");
+ return;
+ }
+ fw_reporter_ctx.err_synd = health->synd;
+ fw_reporter_ctx.miss_counter = health->miss_counter;
+ devlink_health_report(health->fw_fatal_reporter,
+ "FW fatal error reported", &fw_reporter_ctx);
+}
+
+static const struct devlink_health_reporter_ops mlx5_fw_fatal_reporter_ops = {
+ .name = "fw_fatal",
+ .recover = mlx5_fw_fatal_reporter_recover,
+ .dump = mlx5_fw_fatal_reporter_dump,
+};
+
+#define MLX5_REPORTER_FW_GRACEFUL_PERIOD 1200000
+static void mlx5_fw_reporters_create(struct mlx5_core_dev *dev)
+{
+ struct mlx5_core_health *health = &dev->priv.health;
+ struct devlink *devlink = priv_to_devlink(dev);
+
+ health->fw_reporter =
+ devlink_health_reporter_create(devlink, &mlx5_fw_reporter_ops,
+ 0, false, dev);
+ if (IS_ERR(health->fw_reporter))
+ mlx5_core_warn(dev, "Failed to create fw reporter, err = %ld\n",
+ PTR_ERR(health->fw_reporter));
+
+ health->fw_fatal_reporter =
+ devlink_health_reporter_create(devlink,
+ &mlx5_fw_fatal_reporter_ops,
+ MLX5_REPORTER_FW_GRACEFUL_PERIOD,
+ true, dev);
+ if (IS_ERR(health->fw_fatal_reporter))
+ mlx5_core_warn(dev, "Failed to create fw fatal reporter, err = %ld\n",
+ PTR_ERR(health->fw_fatal_reporter));
+}
+
+static void mlx5_fw_reporters_destroy(struct mlx5_core_dev *dev)
+{
+ struct mlx5_core_health *health = &dev->priv.health;
+
+ if (!IS_ERR_OR_NULL(health->fw_reporter))
+ devlink_health_reporter_destroy(health->fw_reporter);
+
+ if (!IS_ERR_OR_NULL(health->fw_fatal_reporter))
+ devlink_health_reporter_destroy(health->fw_fatal_reporter);
+}
+
static unsigned long get_next_poll_jiffies(void)
{
unsigned long next;
@@ -264,7 +682,7 @@ void mlx5_trigger_health_work(struct mlx5_core_dev *dev)
spin_lock_irqsave(&health->wq_lock, flags);
if (!test_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags))
- queue_work(health->wq, &health->work);
+ queue_work(health->wq, &health->fatal_report_work);
else
mlx5_core_err(dev, "new health works are not permitted at this stage\n");
spin_unlock_irqrestore(&health->wq_lock, flags);
@@ -274,6 +692,9 @@ static void poll_health(struct timer_list *t)
{
struct mlx5_core_dev *dev = from_timer(dev, t, priv.health.timer);
struct mlx5_core_health *health = &dev->priv.health;
+ struct health_buffer __iomem *h = health->health;
+ u32 fatal_error;
+ u8 prev_synd;
u32 count;
if (dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR)
@@ -289,10 +710,19 @@ static void poll_health(struct timer_list *t)
if (health->miss_counter == MAX_MISSES) {
mlx5_core_err(dev, "device's health compromised - reached miss count\n");
print_health_info(dev);
+ queue_work(health->wq, &health->report_work);
}
- if (in_fatal(dev) && !health->sick) {
- health->sick = true;
+ prev_synd = health->synd;
+ health->synd = ioread8(&h->synd);
+ if (health->synd && health->synd != prev_synd)
+ queue_work(health->wq, &health->report_work);
+
+ fatal_error = check_fatal_sensors(dev);
+
+ if (fatal_error && !health->fatal_error) {
+ mlx5_core_err(dev, "Fatal error %u detected\n", fatal_error);
+ dev->priv.health.fatal_error = fatal_error;
print_health_info(dev);
mlx5_trigger_health_work(dev);
}
@@ -306,9 +736,8 @@ void mlx5_start_health_poll(struct mlx5_core_dev *dev)
struct mlx5_core_health *health = &dev->priv.health;
timer_setup(&health->timer, poll_health, 0);
- health->sick = 0;
+ health->fatal_error = MLX5_SENSOR_NO_ERR;
clear_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags);
- clear_bit(MLX5_DROP_NEW_RECOVERY_WORK, &health->flags);
health->health = &dev->iseg->health;
health->health_counter = &dev->iseg->health_counter;
@@ -324,7 +753,6 @@ void mlx5_stop_health_poll(struct mlx5_core_dev *dev, bool disable_health)
if (disable_health) {
spin_lock_irqsave(&health->wq_lock, flags);
set_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags);
- set_bit(MLX5_DROP_NEW_RECOVERY_WORK, &health->flags);
spin_unlock_irqrestore(&health->wq_lock, flags);
}
@@ -338,21 +766,9 @@ void mlx5_drain_health_wq(struct mlx5_core_dev *dev)
spin_lock_irqsave(&health->wq_lock, flags);
set_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags);
- set_bit(MLX5_DROP_NEW_RECOVERY_WORK, &health->flags);
spin_unlock_irqrestore(&health->wq_lock, flags);
- cancel_delayed_work_sync(&health->recover_work);
- cancel_work_sync(&health->work);
-}
-
-void mlx5_drain_health_recovery(struct mlx5_core_dev *dev)
-{
- struct mlx5_core_health *health = &dev->priv.health;
- unsigned long flags;
-
- spin_lock_irqsave(&health->wq_lock, flags);
- set_bit(MLX5_DROP_NEW_RECOVERY_WORK, &health->flags);
- spin_unlock_irqrestore(&health->wq_lock, flags);
- cancel_delayed_work_sync(&dev->priv.health.recover_work);
+ cancel_work_sync(&health->report_work);
+ cancel_work_sync(&health->fatal_report_work);
}
void mlx5_health_flush(struct mlx5_core_dev *dev)
@@ -367,6 +783,7 @@ void mlx5_health_cleanup(struct mlx5_core_dev *dev)
struct mlx5_core_health *health = &dev->priv.health;
destroy_workqueue(health->wq);
+ mlx5_fw_reporters_destroy(dev);
}
int mlx5_health_init(struct mlx5_core_dev *dev)
@@ -374,20 +791,26 @@ int mlx5_health_init(struct mlx5_core_dev *dev)
struct mlx5_core_health *health;
char *name;
+ mlx5_fw_reporters_create(dev);
+
health = &dev->priv.health;
name = kmalloc(64, GFP_KERNEL);
if (!name)
- return -ENOMEM;
+ goto out_err;
strcpy(name, "mlx5_health");
strcat(name, dev_name(dev->device));
health->wq = create_singlethread_workqueue(name);
kfree(name);
if (!health->wq)
- return -ENOMEM;
+ goto out_err;
spin_lock_init(&health->wq_lock);
- INIT_WORK(&health->work, health_care);
- INIT_DELAYED_WORK(&health->recover_work, health_recover);
+ INIT_WORK(&health->fatal_report_work, mlx5_fw_fatal_reporter_err_work);
+ INIT_WORK(&health->report_work, mlx5_fw_reporter_err_work);
return 0;
+
+out_err:
+ mlx5_fw_reporters_destroy(dev);
+ return -ENOMEM;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c
index 90cb50fe17fd..ebd81f6b556e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c
@@ -122,14 +122,6 @@ static int mlx5i_get_ts_info(struct net_device *netdev,
return mlx5e_ethtool_get_ts_info(priv, info);
}
-static int mlx5i_flash_device(struct net_device *netdev,
- struct ethtool_flash *flash)
-{
- struct mlx5e_priv *priv = mlx5i_epriv(netdev);
-
- return mlx5e_ethtool_flash_device(priv, flash);
-}
-
enum mlx5_ptys_width {
MLX5_PTYS_WIDTH_1X = 1 << 0,
MLX5_PTYS_WIDTH_2X = 1 << 1,
@@ -241,7 +233,6 @@ const struct ethtool_ops mlx5i_ethtool_ops = {
.get_ethtool_stats = mlx5i_get_ethtool_stats,
.get_ringparam = mlx5i_get_ringparam,
.set_ringparam = mlx5i_set_ringparam,
- .flash_device = mlx5i_flash_device,
.get_channels = mlx5i_get_channels,
.set_channels = mlx5i_set_channels,
.get_coalesce = mlx5i_get_coalesce,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
index 9ca492b430d8..6bfaaab362dc 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
@@ -87,7 +87,7 @@ int mlx5i_init(struct mlx5_core_dev *mdev,
mlx5e_set_netdev_mtu_boundaries(priv);
netdev->mtu = netdev->max_mtu;
- mlx5e_build_nic_params(mdev, &priv->rss_params, &priv->channels.params,
+ mlx5e_build_nic_params(mdev, NULL, &priv->rss_params, &priv->channels.params,
mlx5e_get_netdev_max_channels(netdev),
netdev->mtu);
mlx5i_build_nic_params(mdev, &priv->channels.params);
@@ -258,6 +258,18 @@ void mlx5i_destroy_underlay_qp(struct mlx5_core_dev *mdev, struct mlx5_core_qp *
mlx5_core_destroy_qp(mdev, qp);
}
+int mlx5i_create_tis(struct mlx5_core_dev *mdev, u32 underlay_qpn, u32 *tisn)
+{
+ u32 in[MLX5_ST_SZ_DW(create_tis_in)] = {};
+ void *tisc;
+
+ tisc = MLX5_ADDR_OF(create_tis_in, in, ctx);
+
+ MLX5_SET(tisc, tisc, underlay_qpn, underlay_qpn);
+
+ return mlx5e_create_tis(mdev, in, tisn);
+}
+
static int mlx5i_init_tx(struct mlx5e_priv *priv)
{
struct mlx5i_priv *ipriv = priv->ppriv;
@@ -269,7 +281,7 @@ static int mlx5i_init_tx(struct mlx5e_priv *priv)
return err;
}
- err = mlx5e_create_tis(priv->mdev, 0 /* tc */, ipriv->qp.qpn, &priv->tisn[0]);
+ err = mlx5i_create_tis(priv->mdev, ipriv->qp.qpn, &priv->tisn[0]);
if (err) {
mlx5_core_warn(priv->mdev, "create tis failed, %d\n", err);
goto err_destroy_underlay_qp;
@@ -365,7 +377,7 @@ static int mlx5i_init_rx(struct mlx5e_priv *priv)
if (err)
goto err_close_drop_rq;
- err = mlx5e_create_direct_rqts(priv);
+ err = mlx5e_create_direct_rqts(priv, priv->direct_tir);
if (err)
goto err_destroy_indirect_rqts;
@@ -373,7 +385,7 @@ static int mlx5i_init_rx(struct mlx5e_priv *priv)
if (err)
goto err_destroy_direct_rqts;
- err = mlx5e_create_direct_tirs(priv);
+ err = mlx5e_create_direct_tirs(priv, priv->direct_tir);
if (err)
goto err_destroy_indirect_tirs;
@@ -384,11 +396,11 @@ static int mlx5i_init_rx(struct mlx5e_priv *priv)
return 0;
err_destroy_direct_tirs:
- mlx5e_destroy_direct_tirs(priv);
+ mlx5e_destroy_direct_tirs(priv, priv->direct_tir);
err_destroy_indirect_tirs:
mlx5e_destroy_indirect_tirs(priv, true);
err_destroy_direct_rqts:
- mlx5e_destroy_direct_rqts(priv);
+ mlx5e_destroy_direct_rqts(priv, priv->direct_tir);
err_destroy_indirect_rqts:
mlx5e_destroy_rqt(priv, &priv->indir_rqt);
err_close_drop_rq:
@@ -401,9 +413,9 @@ err_destroy_q_counters:
static void mlx5i_cleanup_rx(struct mlx5e_priv *priv)
{
mlx5i_destroy_flow_steering(priv);
- mlx5e_destroy_direct_tirs(priv);
+ mlx5e_destroy_direct_tirs(priv, priv->direct_tir);
mlx5e_destroy_indirect_tirs(priv, true);
- mlx5e_destroy_direct_rqts(priv);
+ mlx5e_destroy_direct_rqts(priv, priv->direct_tir);
mlx5e_destroy_rqt(priv, &priv->indir_rqt);
mlx5e_close_drop_rq(&priv->drop_rq);
mlx5e_destroy_q_counters(priv);
@@ -418,6 +430,7 @@ static const struct mlx5e_profile mlx5i_nic_profile = {
.cleanup_rx = mlx5i_cleanup_rx,
.enable = NULL, /* mlx5i_enable */
.disable = NULL, /* mlx5i_disable */
+ .update_rx = mlx5e_update_nic_rx,
.update_stats = NULL, /* mlx5i_update_stats */
.update_carrier = NULL, /* no HW update in IB link */
.rx_handlers.handle_rx_cqe = mlx5i_handle_rx_cqe,
@@ -526,7 +539,7 @@ static int mlx5i_open(struct net_device *netdev)
if (err)
goto err_remove_fs_underlay_qp;
- mlx5e_refresh_tirs(epriv, false);
+ epriv->profile->update_rx(epriv);
mlx5e_activate_priv_channels(epriv);
mutex_unlock(&epriv->state_lock);
@@ -698,7 +711,9 @@ static int mlx5_rdma_setup_rn(struct ib_device *ibdev, u8 port_num,
prof->init(mdev, netdev, prof, ipriv);
- mlx5e_attach_netdev(epriv);
+ err = mlx5e_attach_netdev(epriv);
+ if (err)
+ goto detach;
netif_carrier_off(netdev);
/* set rdma_netdev func pointers */
@@ -714,6 +729,11 @@ static int mlx5_rdma_setup_rn(struct ib_device *ibdev, u8 port_num,
return 0;
+detach:
+ prof->cleanup(epriv);
+ if (ipriv->sub_interface)
+ return err;
+ mlx5e_destroy_mdev_resources(mdev);
destroy_ht:
mlx5i_pkey_qpn_ht_cleanup(netdev);
return err;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h
index e19ba3fcd1b7..c87962cab921 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h
@@ -59,6 +59,8 @@ struct mlx5i_priv {
char *mlx5e_priv[0];
};
+int mlx5i_create_tis(struct mlx5_core_dev *mdev, u32 underlay_qpn, u32 *tisn);
+
/* Underlay QP create/destroy functions */
int mlx5i_create_underlay_qp(struct mlx5_core_dev *mdev, struct mlx5_core_qp *qp);
void mlx5i_destroy_underlay_qp(struct mlx5_core_dev *mdev, struct mlx5_core_qp *qp);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c
index b491b8f5fd6b..6e56fa769d2e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c
@@ -210,7 +210,7 @@ static int mlx5i_pkey_open(struct net_device *netdev)
goto err_unint_underlay_qp;
}
- err = mlx5e_create_tis(mdev, 0 /* tc */, ipriv->qp.qpn, &epriv->tisn[0]);
+ err = mlx5i_create_tis(mdev, ipriv->qp.qpn, &epriv->tisn[0]);
if (err) {
mlx5_core_warn(mdev, "create child tis failed, %d\n", err);
goto err_remove_rx_uderlay_qp;
@@ -221,7 +221,7 @@ static int mlx5i_pkey_open(struct net_device *netdev)
mlx5_core_warn(mdev, "opening child channels failed, %d\n", err);
goto err_clear_state_opened_flag;
}
- mlx5e_refresh_tirs(epriv, false);
+ epriv->profile->update_rx(epriv);
mlx5e_activate_priv_channels(epriv);
mutex_unlock(&epriv->state_lock);
@@ -350,6 +350,7 @@ static const struct mlx5e_profile mlx5i_pkey_nic_profile = {
.cleanup_rx = mlx5i_pkey_cleanup_rx,
.enable = NULL,
.disable = NULL,
+ .update_rx = mlx5e_update_nic_rx,
.update_stats = NULL,
.rx_handlers.handle_rx_cqe = mlx5i_handle_rx_cqe,
.rx_handlers.handle_rx_cqe_mpwqe = NULL, /* Not supported */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag.c
index 959605559858..c5ef2ff26465 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag.c
@@ -305,8 +305,8 @@ static void mlx5_do_bond(struct mlx5_lag *ldev)
!mlx5_sriov_is_enabled(dev1);
#ifdef CONFIG_MLX5_ESWITCH
- roce_lag &= dev0->priv.eswitch->mode == SRIOV_NONE &&
- dev1->priv.eswitch->mode == SRIOV_NONE;
+ roce_lag &= dev0->priv.eswitch->mode == MLX5_ESWITCH_NONE &&
+ dev1->priv.eswitch->mode == MLX5_ESWITCH_NONE;
#endif
if (roce_lag)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c b/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c
index 8212bfd05733..e69766393990 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c
@@ -2,6 +2,7 @@
/* Copyright (c) 2019 Mellanox Technologies. */
#include <linux/netdevice.h>
+#include <net/nexthop.h>
#include "lag.h"
#include "lag_mp.h"
#include "mlx5_core.h"
@@ -110,6 +111,8 @@ static void mlx5_lag_fib_route_event(struct mlx5_lag *ldev,
struct fib_info *fi)
{
struct lag_mp *mp = &ldev->lag_mp;
+ struct fib_nh *fib_nh0, *fib_nh1;
+ unsigned int nhs;
/* Handle delete event */
if (event == FIB_EVENT_ENTRY_DEL) {
@@ -120,9 +123,11 @@ static void mlx5_lag_fib_route_event(struct mlx5_lag *ldev,
}
/* Handle add/replace event */
- if (fi->fib_nhs == 1) {
+ nhs = fib_info_num_path(fi);
+ if (nhs == 1) {
if (__mlx5_lag_is_active(ldev)) {
- struct net_device *nh_dev = fi->fib_nh[0].fib_nh_dev;
+ struct fib_nh *nh = fib_info_nh(fi, 0);
+ struct net_device *nh_dev = nh->fib_nh_dev;
int i = mlx5_lag_dev_get_netdev_idx(ldev, nh_dev);
mlx5_lag_set_port_affinity(ldev, ++i);
@@ -130,14 +135,16 @@ static void mlx5_lag_fib_route_event(struct mlx5_lag *ldev,
return;
}
- if (fi->fib_nhs != 2)
+ if (nhs != 2)
return;
/* Verify next hops are ports of the same hca */
- if (!(fi->fib_nh[0].fib_nh_dev == ldev->pf[0].netdev &&
- fi->fib_nh[1].fib_nh_dev == ldev->pf[1].netdev) &&
- !(fi->fib_nh[0].fib_nh_dev == ldev->pf[1].netdev &&
- fi->fib_nh[1].fib_nh_dev == ldev->pf[0].netdev)) {
+ fib_nh0 = fib_info_nh(fi, 0);
+ fib_nh1 = fib_info_nh(fi, 1);
+ if (!(fib_nh0->fib_nh_dev == ldev->pf[0].netdev &&
+ fib_nh1->fib_nh_dev == ldev->pf[1].netdev) &&
+ !(fib_nh0->fib_nh_dev == ldev->pf[1].netdev &&
+ fib_nh1->fib_nh_dev == ldev->pf[0].netdev)) {
mlx5_core_warn(ldev->pf[0].dev, "Multipath offload require two ports of the same HCA\n");
return;
}
@@ -174,7 +181,7 @@ static void mlx5_lag_fib_nexthop_event(struct mlx5_lag *ldev,
mlx5_lag_set_port_affinity(ldev, i);
}
} else if (event == FIB_EVENT_NH_ADD &&
- fi->fib_nhs == 2) {
+ fib_info_num_path(fi) == 2) {
mlx5_lag_set_port_affinity(ldev, 0);
}
}
@@ -238,6 +245,7 @@ static int mlx5_lag_fib_event(struct notifier_block *nb,
struct mlx5_fib_event_work *fib_work;
struct fib_entry_notifier_info *fen_info;
struct fib_nh_notifier_info *fnh_info;
+ struct net_device *fib_dev;
struct fib_info *fi;
if (info->family != AF_INET)
@@ -254,8 +262,13 @@ static int mlx5_lag_fib_event(struct notifier_block *nb,
fen_info = container_of(info, struct fib_entry_notifier_info,
info);
fi = fen_info->fi;
- if (fi->fib_dev != ldev->pf[0].netdev &&
- fi->fib_dev != ldev->pf[1].netdev) {
+ if (fi->nh) {
+ NL_SET_ERR_MSG_MOD(info->extack, "IPv4 route with nexthop objects is not supported");
+ return notifier_from_errno(-EINVAL);
+ }
+ fib_dev = fib_info_nh(fen_info->fi, 0)->fib_nh_dev;
+ if (fib_dev != ldev->pf[0].netdev &&
+ fib_dev != ldev->pf[1].netdev) {
return NOTIFY_DONE;
}
fib_work = mlx5_lag_init_fib_work(ldev, event);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/crypto.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/crypto.c
new file mode 100644
index 000000000000..ea9ee88491e5
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/crypto.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+// Copyright (c) 2019 Mellanox Technologies.
+
+#include "mlx5_core.h"
+
+int mlx5_create_encryption_key(struct mlx5_core_dev *mdev,
+ void *key, u32 sz_bytes,
+ u32 *p_key_id)
+{
+ u32 in[MLX5_ST_SZ_DW(create_encryption_key_in)] = {};
+ u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)];
+ u32 sz_bits = sz_bytes * BITS_PER_BYTE;
+ u8 general_obj_key_size;
+ u64 general_obj_types;
+ void *obj, *key_p;
+ int err;
+
+ obj = MLX5_ADDR_OF(create_encryption_key_in, in, encryption_key_object);
+ key_p = MLX5_ADDR_OF(encryption_key_obj, obj, key);
+
+ general_obj_types = MLX5_CAP_GEN_64(mdev, general_obj_types);
+ if (!(general_obj_types &
+ MLX5_HCA_CAP_GENERAL_OBJECT_TYPES_ENCRYPTION_KEY))
+ return -EINVAL;
+
+ switch (sz_bits) {
+ case 128:
+ general_obj_key_size =
+ MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_KEY_SIZE_128;
+ break;
+ case 256:
+ general_obj_key_size =
+ MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_KEY_SIZE_256;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ memcpy(key_p, key, sz_bytes);
+
+ MLX5_SET(encryption_key_obj, obj, key_size, general_obj_key_size);
+ MLX5_SET(encryption_key_obj, obj, key_type,
+ MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_TYPE_DEK);
+ MLX5_SET(general_obj_in_cmd_hdr, in, opcode,
+ MLX5_CMD_OP_CREATE_GENERAL_OBJECT);
+ MLX5_SET(general_obj_in_cmd_hdr, in, obj_type,
+ MLX5_GENERAL_OBJECT_TYPES_ENCRYPTION_KEY);
+ MLX5_SET(encryption_key_obj, obj, pd, mdev->mlx5e_res.pdn);
+
+ err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
+ if (!err)
+ *p_key_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id);
+
+ /* avoid leaking key on the stack */
+ memzero_explicit(in, sizeof(in));
+
+ return err;
+}
+
+void mlx5_destroy_encryption_key(struct mlx5_core_dev *mdev, u32 key_id)
+{
+ u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {};
+ u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)];
+
+ MLX5_SET(general_obj_in_cmd_hdr, in, opcode,
+ MLX5_CMD_OP_DESTROY_GENERAL_OBJECT);
+ MLX5_SET(general_obj_in_cmd_hdr, in, obj_type,
+ MLX5_GENERAL_OBJECT_TYPES_ENCRYPTION_KEY);
+ MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, key_id);
+
+ mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h
index c0fb6d72b695..3dfab91ae5f2 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h
@@ -7,7 +7,6 @@
#include <linux/mlx5/eq.h>
#include <linux/mlx5/cq.h>
-#define MLX5_MAX_IRQ_NAME (32)
#define MLX5_EQE_SIZE (sizeof(struct mlx5_eqe))
struct mlx5_eq_tasklet {
@@ -36,8 +35,14 @@ struct mlx5_eq {
struct mlx5_rsc_debug *dbg;
};
+struct mlx5_eq_async {
+ struct mlx5_eq core;
+ struct notifier_block irq_nb;
+};
+
struct mlx5_eq_comp {
- struct mlx5_eq core; /* Must be first */
+ struct mlx5_eq core;
+ struct notifier_block irq_nb;
struct mlx5_eq_tasklet tasklet_ctx;
struct list_head list;
};
@@ -70,7 +75,7 @@ int mlx5_eq_table_create(struct mlx5_core_dev *dev);
void mlx5_eq_table_destroy(struct mlx5_core_dev *dev);
int mlx5_eq_add_cq(struct mlx5_eq *eq, struct mlx5_core_cq *cq);
-int mlx5_eq_del_cq(struct mlx5_eq *eq, struct mlx5_core_cq *cq);
+void mlx5_eq_del_cq(struct mlx5_eq *eq, struct mlx5_core_cq *cq);
struct mlx5_eq_comp *mlx5_eqn2comp_eq(struct mlx5_core_dev *dev, int eqn);
struct mlx5_eq *mlx5_get_async_eq(struct mlx5_core_dev *dev);
void mlx5_cq_tasklet_cb(unsigned long data);
@@ -92,7 +97,4 @@ 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_eq_notifier_register(struct mlx5_core_dev *dev, struct mlx5_nb *nb);
-int mlx5_eq_notifier_unregister(struct mlx5_core_dev *dev, struct mlx5_nb *nb);
-
#endif
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/geneve.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/geneve.c
new file mode 100644
index 000000000000..23361a9ae4fa
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/geneve.c
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/* Copyright (c) 2019 Mellanox Technologies. */
+
+#include <linux/kernel.h>
+#include "mlx5_core.h"
+#include "geneve.h"
+
+struct mlx5_geneve {
+ struct mlx5_core_dev *mdev;
+ __be16 opt_class;
+ u8 opt_type;
+ u32 obj_id;
+ struct mutex sync_lock; /* protect GENEVE obj operations */
+ u32 refcount;
+};
+
+static int mlx5_geneve_tlv_option_create(struct mlx5_core_dev *mdev,
+ __be16 class,
+ u8 type,
+ u8 len)
+{
+ u32 in[MLX5_ST_SZ_DW(create_geneve_tlv_option_in)] = {};
+ u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {};
+ u64 general_obj_types;
+ void *hdr, *opt;
+ u16 obj_id;
+ int err;
+
+ general_obj_types = MLX5_CAP_GEN_64(mdev, general_obj_types);
+ if (!(general_obj_types & MLX5_GENERAL_OBJ_TYPES_CAP_GENEVE_TLV_OPT))
+ return -EINVAL;
+
+ hdr = MLX5_ADDR_OF(create_geneve_tlv_option_in, in, hdr);
+ opt = MLX5_ADDR_OF(create_geneve_tlv_option_in, in, geneve_tlv_opt);
+
+ MLX5_SET(general_obj_in_cmd_hdr, hdr, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT);
+ MLX5_SET(general_obj_in_cmd_hdr, hdr, obj_type, MLX5_OBJ_TYPE_GENEVE_TLV_OPT);
+
+ MLX5_SET(geneve_tlv_option, opt, option_class, be16_to_cpu(class));
+ MLX5_SET(geneve_tlv_option, opt, option_type, type);
+ MLX5_SET(geneve_tlv_option, opt, option_data_length, len);
+
+ err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
+ if (err)
+ return err;
+
+ obj_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id);
+ return obj_id;
+}
+
+static void mlx5_geneve_tlv_option_destroy(struct mlx5_core_dev *mdev, u16 obj_id)
+{
+ u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {};
+ u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {};
+
+ MLX5_SET(general_obj_in_cmd_hdr, in, opcode, MLX5_CMD_OP_DESTROY_GENERAL_OBJECT);
+ MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, MLX5_OBJ_TYPE_GENEVE_TLV_OPT);
+ MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, obj_id);
+
+ mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
+}
+
+int mlx5_geneve_tlv_option_add(struct mlx5_geneve *geneve, struct geneve_opt *opt)
+{
+ int res = 0;
+
+ if (IS_ERR_OR_NULL(geneve))
+ return -EOPNOTSUPP;
+
+ mutex_lock(&geneve->sync_lock);
+
+ if (geneve->refcount) {
+ if (geneve->opt_class == opt->opt_class &&
+ geneve->opt_type == opt->type) {
+ /* We already have TLV options obj allocated */
+ geneve->refcount++;
+ } else {
+ /* TLV options obj allocated, but its params
+ * do not match the new request.
+ * We support only one such object.
+ */
+ mlx5_core_warn(geneve->mdev,
+ "Won't create Geneve TLV opt object with class:type:len = 0x%x:0x%x:%d (another class:type already exists)\n",
+ be16_to_cpu(opt->opt_class),
+ opt->type,
+ opt->length);
+ res = -EOPNOTSUPP;
+ goto unlock;
+ }
+ } else {
+ /* We don't have any TLV options obj allocated */
+
+ res = mlx5_geneve_tlv_option_create(geneve->mdev,
+ opt->opt_class,
+ opt->type,
+ opt->length);
+ if (res < 0) {
+ mlx5_core_warn(geneve->mdev,
+ "Failed creating Geneve TLV opt object class:type:len = 0x%x:0x%x:%d (err=%d)\n",
+ be16_to_cpu(opt->opt_class),
+ opt->type, opt->length, res);
+ goto unlock;
+ }
+ geneve->opt_class = opt->opt_class;
+ geneve->opt_type = opt->type;
+ geneve->obj_id = res;
+ geneve->refcount++;
+ }
+
+unlock:
+ mutex_unlock(&geneve->sync_lock);
+ return res;
+}
+
+void mlx5_geneve_tlv_option_del(struct mlx5_geneve *geneve)
+{
+ if (IS_ERR_OR_NULL(geneve))
+ return;
+
+ mutex_lock(&geneve->sync_lock);
+ if (--geneve->refcount == 0) {
+ /* We've just removed the last user of Geneve option.
+ * Now delete the object in FW.
+ */
+ mlx5_geneve_tlv_option_destroy(geneve->mdev, geneve->obj_id);
+
+ geneve->opt_class = 0;
+ geneve->opt_type = 0;
+ geneve->obj_id = 0;
+ }
+ mutex_unlock(&geneve->sync_lock);
+}
+
+struct mlx5_geneve *mlx5_geneve_create(struct mlx5_core_dev *mdev)
+{
+ struct mlx5_geneve *geneve =
+ kzalloc(sizeof(*geneve), GFP_KERNEL);
+
+ if (!geneve)
+ return ERR_PTR(-ENOMEM);
+ geneve->mdev = mdev;
+ mutex_init(&geneve->sync_lock);
+
+ return geneve;
+}
+
+void mlx5_geneve_destroy(struct mlx5_geneve *geneve)
+{
+ if (IS_ERR_OR_NULL(geneve))
+ return;
+
+ /* Lockless since we are unloading */
+ if (geneve->refcount)
+ mlx5_geneve_tlv_option_destroy(geneve->mdev, geneve->obj_id);
+
+ kfree(geneve);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/geneve.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/geneve.h
new file mode 100644
index 000000000000..adee0cbba19c
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/geneve.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2019 Mellanox Technologies. */
+
+#ifndef __MLX5_GENEVE_H__
+#define __MLX5_GENEVE_H__
+
+#include <net/geneve.h>
+#include <linux/mlx5/driver.h>
+
+struct mlx5_geneve;
+
+#ifdef CONFIG_MLX5_ESWITCH
+
+struct mlx5_geneve *mlx5_geneve_create(struct mlx5_core_dev *mdev);
+void mlx5_geneve_destroy(struct mlx5_geneve *geneve);
+
+int mlx5_geneve_tlv_option_add(struct mlx5_geneve *geneve, struct geneve_opt *opt);
+void mlx5_geneve_tlv_option_del(struct mlx5_geneve *geneve);
+
+#else /* CONFIG_MLX5_ESWITCH */
+
+static inline struct mlx5_geneve
+*mlx5_geneve_create(struct mlx5_core_dev *mdev) { return NULL; }
+static inline void
+mlx5_geneve_destroy(struct mlx5_geneve *geneve) {}
+static inline int
+mlx5_geneve_tlv_option_add(struct mlx5_geneve *geneve, struct geneve_opt *opt) { return 0; }
+static inline void
+mlx5_geneve_tlv_option_del(struct mlx5_geneve *geneve) {}
+
+#endif /* CONFIG_MLX5_ESWITCH */
+
+#endif /* __MLX5_GENEVE_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h
index 397a2847867a..b99d469e4e64 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h
@@ -41,6 +41,9 @@ int mlx5_core_reserve_gids(struct mlx5_core_dev *dev, unsigned int count);
void mlx5_core_unreserve_gids(struct mlx5_core_dev *dev, unsigned int count);
int mlx5_core_reserved_gid_alloc(struct mlx5_core_dev *dev, int *gid_index);
void mlx5_core_reserved_gid_free(struct mlx5_core_dev *dev, int gid_index);
+int mlx5_crdump_enable(struct mlx5_core_dev *dev);
+void mlx5_crdump_disable(struct mlx5_core_dev *dev);
+int mlx5_crdump_collect(struct mlx5_core_dev *dev, u32 *cr_data);
/* TODO move to lib/events.h */
@@ -76,4 +79,9 @@ struct mlx5_pme_stats {
void mlx5_get_pme_stats(struct mlx5_core_dev *dev, struct mlx5_pme_stats *stats);
int mlx5_notifier_call_chain(struct mlx5_events *events, unsigned int event, void *data);
+/* Crypto */
+int mlx5_create_encryption_key(struct mlx5_core_dev *mdev,
+ void *key, u32 sz_bytes, u32 *p_key_id);
+void mlx5_destroy_encryption_key(struct mlx5_core_dev *mdev, u32 key_id);
+
#endif
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c
index a71d5b9c7ab2..3118e8d66407 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c
@@ -67,6 +67,7 @@ static int del_l2table_entry_cmd(struct mlx5_core_dev *dev, u32 index)
struct l2table_node {
struct l2addr_node node;
u32 index; /* index in HW l2 table */
+ int ref_count;
};
struct mlx5_mpfs {
@@ -134,8 +135,8 @@ int mlx5_mpfs_add_mac(struct mlx5_core_dev *dev, u8 *mac)
{
struct mlx5_mpfs *mpfs = dev->priv.mpfs;
struct l2table_node *l2addr;
+ int err = 0;
u32 index;
- int err;
if (!MLX5_ESWITCH_MANAGER(dev))
return 0;
@@ -144,30 +145,35 @@ int mlx5_mpfs_add_mac(struct mlx5_core_dev *dev, u8 *mac)
l2addr = l2addr_hash_find(mpfs->hash, mac, struct l2table_node);
if (l2addr) {
- err = -EEXIST;
- goto abort;
+ l2addr->ref_count++;
+ goto out;
}
err = alloc_l2table_index(mpfs, &index);
if (err)
- goto abort;
+ goto out;
l2addr = l2addr_hash_add(mpfs->hash, mac, struct l2table_node, GFP_KERNEL);
if (!l2addr) {
- free_l2table_index(mpfs, index);
err = -ENOMEM;
- goto abort;
+ goto hash_add_err;
}
- l2addr->index = index;
err = set_l2table_entry_cmd(dev, index, mac);
- if (err) {
- l2addr_hash_del(l2addr);
- free_l2table_index(mpfs, index);
- }
+ if (err)
+ goto set_table_entry_err;
+
+ l2addr->index = index;
+ l2addr->ref_count = 1;
mlx5_core_dbg(dev, "MPFS mac added %pM, index (%d)\n", mac, index);
-abort:
+ goto out;
+
+set_table_entry_err:
+ l2addr_hash_del(l2addr);
+hash_add_err:
+ free_l2table_index(mpfs, index);
+out:
mutex_unlock(&mpfs->lock);
return err;
}
@@ -190,6 +196,9 @@ int mlx5_mpfs_del_mac(struct mlx5_core_dev *dev, u8 *mac)
goto unlock;
}
+ if (--l2addr->ref_count > 0)
+ goto unlock;
+
index = l2addr->index;
del_l2table_entry_cmd(dev, index);
l2addr_hash_del(l2addr);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/pci_vsc.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/pci_vsc.c
new file mode 100644
index 000000000000..6b774e0c2766
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/pci_vsc.c
@@ -0,0 +1,316 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/* Copyright (c) 2019 Mellanox Technologies */
+
+#include <linux/pci.h>
+#include "mlx5_core.h"
+#include "pci_vsc.h"
+
+#define MLX5_EXTRACT_C(source, offset, size) \
+ ((((u32)(source)) >> (offset)) & MLX5_ONES32(size))
+#define MLX5_EXTRACT(src, start, len) \
+ (((len) == 32) ? (src) : MLX5_EXTRACT_C(src, start, len))
+#define MLX5_ONES32(size) \
+ ((size) ? (0xffffffff >> (32 - (size))) : 0)
+#define MLX5_MASK32(offset, size) \
+ (MLX5_ONES32(size) << (offset))
+#define MLX5_MERGE_C(rsrc1, rsrc2, start, len) \
+ ((((rsrc2) << (start)) & (MLX5_MASK32((start), (len)))) | \
+ ((rsrc1) & (~MLX5_MASK32((start), (len)))))
+#define MLX5_MERGE(rsrc1, rsrc2, start, len) \
+ (((len) == 32) ? (rsrc2) : MLX5_MERGE_C(rsrc1, rsrc2, start, len))
+#define vsc_read(dev, offset, val) \
+ pci_read_config_dword((dev)->pdev, (dev)->vsc_addr + (offset), (val))
+#define vsc_write(dev, offset, val) \
+ pci_write_config_dword((dev)->pdev, (dev)->vsc_addr + (offset), (val))
+#define VSC_MAX_RETRIES 2048
+
+enum {
+ VSC_CTRL_OFFSET = 0x4,
+ VSC_COUNTER_OFFSET = 0x8,
+ VSC_SEMAPHORE_OFFSET = 0xc,
+ VSC_ADDR_OFFSET = 0x10,
+ VSC_DATA_OFFSET = 0x14,
+
+ VSC_FLAG_BIT_OFFS = 31,
+ VSC_FLAG_BIT_LEN = 1,
+
+ VSC_SYND_BIT_OFFS = 30,
+ VSC_SYND_BIT_LEN = 1,
+
+ VSC_ADDR_BIT_OFFS = 0,
+ VSC_ADDR_BIT_LEN = 30,
+
+ VSC_SPACE_BIT_OFFS = 0,
+ VSC_SPACE_BIT_LEN = 16,
+
+ VSC_SIZE_VLD_BIT_OFFS = 28,
+ VSC_SIZE_VLD_BIT_LEN = 1,
+
+ VSC_STATUS_BIT_OFFS = 29,
+ VSC_STATUS_BIT_LEN = 3,
+};
+
+void mlx5_pci_vsc_init(struct mlx5_core_dev *dev)
+{
+ if (!mlx5_core_is_pf(dev))
+ return;
+
+ dev->vsc_addr = pci_find_capability(dev->pdev,
+ PCI_CAP_ID_VNDR);
+ if (!dev->vsc_addr)
+ mlx5_core_warn(dev, "Failed to get valid vendor specific ID\n");
+}
+
+int mlx5_vsc_gw_lock(struct mlx5_core_dev *dev)
+{
+ u32 counter = 0;
+ int retries = 0;
+ u32 lock_val;
+ int ret;
+
+ pci_cfg_access_lock(dev->pdev);
+ do {
+ if (retries > VSC_MAX_RETRIES) {
+ ret = -EBUSY;
+ goto pci_unlock;
+ }
+
+ /* Check if semaphore is already locked */
+ ret = vsc_read(dev, VSC_SEMAPHORE_OFFSET, &lock_val);
+ if (ret)
+ goto pci_unlock;
+
+ if (lock_val) {
+ retries++;
+ usleep_range(1000, 2000);
+ continue;
+ }
+
+ /* Read and write counter value, if written value is
+ * the same, semaphore was acquired successfully.
+ */
+ ret = vsc_read(dev, VSC_COUNTER_OFFSET, &counter);
+ if (ret)
+ goto pci_unlock;
+
+ ret = vsc_write(dev, VSC_SEMAPHORE_OFFSET, counter);
+ if (ret)
+ goto pci_unlock;
+
+ ret = vsc_read(dev, VSC_SEMAPHORE_OFFSET, &lock_val);
+ if (ret)
+ goto pci_unlock;
+
+ retries++;
+ } while (counter != lock_val);
+
+ return 0;
+
+pci_unlock:
+ pci_cfg_access_unlock(dev->pdev);
+ return ret;
+}
+
+int mlx5_vsc_gw_unlock(struct mlx5_core_dev *dev)
+{
+ int ret;
+
+ ret = vsc_write(dev, VSC_SEMAPHORE_OFFSET, MLX5_VSC_UNLOCK);
+ pci_cfg_access_unlock(dev->pdev);
+ return ret;
+}
+
+int mlx5_vsc_gw_set_space(struct mlx5_core_dev *dev, u16 space,
+ u32 *ret_space_size)
+{
+ int ret;
+ u32 val = 0;
+
+ if (!mlx5_vsc_accessible(dev))
+ return -EINVAL;
+
+ if (ret_space_size)
+ *ret_space_size = 0;
+
+ /* Get a unique val */
+ ret = vsc_read(dev, VSC_CTRL_OFFSET, &val);
+ if (ret)
+ goto out;
+
+ /* Try to modify the lock */
+ val = MLX5_MERGE(val, space, VSC_SPACE_BIT_OFFS, VSC_SPACE_BIT_LEN);
+ ret = vsc_write(dev, VSC_CTRL_OFFSET, val);
+ if (ret)
+ goto out;
+
+ /* Verify lock was modified */
+ ret = vsc_read(dev, VSC_CTRL_OFFSET, &val);
+ if (ret)
+ goto out;
+
+ if (MLX5_EXTRACT(val, VSC_STATUS_BIT_OFFS, VSC_STATUS_BIT_LEN) == 0)
+ return -EINVAL;
+
+ /* Get space max address if indicated by size valid bit */
+ if (ret_space_size &&
+ MLX5_EXTRACT(val, VSC_SIZE_VLD_BIT_OFFS, VSC_SIZE_VLD_BIT_LEN)) {
+ ret = vsc_read(dev, VSC_ADDR_OFFSET, &val);
+ if (ret) {
+ mlx5_core_warn(dev, "Failed to get max space size\n");
+ goto out;
+ }
+ *ret_space_size = MLX5_EXTRACT(val, VSC_ADDR_BIT_OFFS,
+ VSC_ADDR_BIT_LEN);
+ }
+ return 0;
+
+out:
+ return ret;
+}
+
+static int mlx5_vsc_wait_on_flag(struct mlx5_core_dev *dev, u8 expected_val)
+{
+ int retries = 0;
+ u32 flag;
+ int ret;
+
+ do {
+ if (retries > VSC_MAX_RETRIES)
+ return -EBUSY;
+
+ ret = vsc_read(dev, VSC_ADDR_OFFSET, &flag);
+ if (ret)
+ return ret;
+ flag = MLX5_EXTRACT(flag, VSC_FLAG_BIT_OFFS, VSC_FLAG_BIT_LEN);
+ retries++;
+
+ if ((retries & 0xf) == 0)
+ usleep_range(1000, 2000);
+
+ } while (flag != expected_val);
+
+ return 0;
+}
+
+static int mlx5_vsc_gw_write(struct mlx5_core_dev *dev, unsigned int address,
+ u32 data)
+{
+ int ret;
+
+ if (MLX5_EXTRACT(address, VSC_SYND_BIT_OFFS,
+ VSC_FLAG_BIT_LEN + VSC_SYND_BIT_LEN))
+ return -EINVAL;
+
+ /* Set flag to 0x1 */
+ address = MLX5_MERGE(address, 1, VSC_FLAG_BIT_OFFS, 1);
+ ret = vsc_write(dev, VSC_DATA_OFFSET, data);
+ if (ret)
+ goto out;
+
+ ret = vsc_write(dev, VSC_ADDR_OFFSET, address);
+ if (ret)
+ goto out;
+
+ /* Wait for the flag to be cleared */
+ ret = mlx5_vsc_wait_on_flag(dev, 0);
+
+out:
+ return ret;
+}
+
+static int mlx5_vsc_gw_read(struct mlx5_core_dev *dev, unsigned int address,
+ u32 *data)
+{
+ int ret;
+
+ if (MLX5_EXTRACT(address, VSC_SYND_BIT_OFFS,
+ VSC_FLAG_BIT_LEN + VSC_SYND_BIT_LEN))
+ return -EINVAL;
+
+ ret = vsc_write(dev, VSC_ADDR_OFFSET, address);
+ if (ret)
+ goto out;
+
+ ret = mlx5_vsc_wait_on_flag(dev, 1);
+ if (ret)
+ goto out;
+
+ ret = vsc_read(dev, VSC_DATA_OFFSET, data);
+out:
+ return ret;
+}
+
+static int mlx5_vsc_gw_read_fast(struct mlx5_core_dev *dev,
+ unsigned int read_addr,
+ unsigned int *next_read_addr,
+ u32 *data)
+{
+ int ret;
+
+ ret = mlx5_vsc_gw_read(dev, read_addr, data);
+ if (ret)
+ goto out;
+
+ ret = vsc_read(dev, VSC_ADDR_OFFSET, next_read_addr);
+ if (ret)
+ goto out;
+
+ *next_read_addr = MLX5_EXTRACT(*next_read_addr, VSC_ADDR_BIT_OFFS,
+ VSC_ADDR_BIT_LEN);
+
+ if (*next_read_addr <= read_addr)
+ ret = -EINVAL;
+out:
+ return ret;
+}
+
+int mlx5_vsc_gw_read_block_fast(struct mlx5_core_dev *dev, u32 *data,
+ int length)
+{
+ unsigned int next_read_addr = 0;
+ unsigned int read_addr = 0;
+
+ while (read_addr < length) {
+ if (mlx5_vsc_gw_read_fast(dev, read_addr, &next_read_addr,
+ &data[(read_addr >> 2)]))
+ return read_addr;
+
+ read_addr = next_read_addr;
+ }
+ return length;
+}
+
+int mlx5_vsc_sem_set_space(struct mlx5_core_dev *dev, u16 space,
+ enum mlx5_vsc_state state)
+{
+ u32 data, id = 0;
+ int ret;
+
+ ret = mlx5_vsc_gw_set_space(dev, MLX5_SEMAPHORE_SPACE_DOMAIN, NULL);
+ if (ret) {
+ mlx5_core_warn(dev, "Failed to set gw space %d\n", ret);
+ return ret;
+ }
+
+ if (state == MLX5_VSC_LOCK) {
+ /* Get a unique ID based on the counter */
+ ret = vsc_read(dev, VSC_COUNTER_OFFSET, &id);
+ if (ret)
+ return ret;
+ }
+
+ /* Try to modify lock */
+ ret = mlx5_vsc_gw_write(dev, space, id);
+ if (ret)
+ return ret;
+
+ /* Verify lock was modified */
+ ret = mlx5_vsc_gw_read(dev, space, &data);
+ if (ret)
+ return -EINVAL;
+
+ if (data != id)
+ return -EBUSY;
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/pci_vsc.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/pci_vsc.h
new file mode 100644
index 000000000000..64272a6d7754
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/pci_vsc.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2019 Mellanox Technologies */
+
+#ifndef __MLX5_PCI_VSC_H__
+#define __MLX5_PCI_VSC_H__
+
+enum mlx5_vsc_state {
+ MLX5_VSC_UNLOCK,
+ MLX5_VSC_LOCK,
+};
+
+enum {
+ MLX5_VSC_SPACE_SCAN_CRSPACE = 0x7,
+};
+
+void mlx5_pci_vsc_init(struct mlx5_core_dev *dev);
+int mlx5_vsc_gw_lock(struct mlx5_core_dev *dev);
+int mlx5_vsc_gw_unlock(struct mlx5_core_dev *dev);
+int mlx5_vsc_gw_set_space(struct mlx5_core_dev *dev, u16 space,
+ u32 *ret_space_size);
+int mlx5_vsc_gw_read_block_fast(struct mlx5_core_dev *dev, u32 *data,
+ int length);
+
+static inline bool mlx5_vsc_accessible(struct mlx5_core_dev *dev)
+{
+ return !!dev->vsc_addr;
+}
+
+int mlx5_vsc_sem_set_space(struct mlx5_core_dev *dev, u16 space,
+ enum mlx5_vsc_state state);
+
+#endif /* __MLX5_PCI_VSC_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/port_tun.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/port_tun.c
index be69c1d7941a..48b5c847b642 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/port_tun.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/port_tun.c
@@ -98,27 +98,12 @@ static int mlx5_set_entropy(struct mlx5_tun_entropy *tun_entropy,
*/
if (entropy_flags.gre_calc_supported &&
reformat_type == MLX5_REFORMAT_TYPE_L2_TO_NVGRE) {
- /* Other applications may change the global FW entropy
- * calculations settings. Check that the current entropy value
- * is the negative of the updated value.
- */
- if (entropy_flags.force_enabled &&
- enable == entropy_flags.gre_calc_enabled) {
- mlx5_core_warn(tun_entropy->mdev,
- "Unexpected GRE entropy calc setting - expected %d",
- !entropy_flags.gre_calc_enabled);
- return -EOPNOTSUPP;
- }
- err = mlx5_set_port_gre_tun_entropy_calc(tun_entropy->mdev, enable,
- entropy_flags.force_supported);
+ if (!entropy_flags.force_supported)
+ return 0;
+ err = mlx5_set_port_gre_tun_entropy_calc(tun_entropy->mdev,
+ enable, !enable);
if (err)
return err;
- /* if we turn on the entropy we don't need to force it anymore */
- if (entropy_flags.force_supported && enable) {
- err = mlx5_set_port_gre_tun_entropy_calc(tun_entropy->mdev, 1, 0);
- if (err)
- return err;
- }
} else if (entropy_flags.calc_supported) {
/* Other applications may change the global FW entropy
* calculations settings. Check that the current entropy value
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index 23d53163ce15..b15b27a497fc 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -56,6 +56,7 @@
#include "fs_core.h"
#include "lib/mpfs.h"
#include "eswitch.h"
+#include "devlink.h"
#include "lib/mlx5.h"
#include "fpga/core.h"
#include "fpga/ipsec.h"
@@ -63,7 +64,9 @@
#include "accel/tls.h"
#include "lib/clock.h"
#include "lib/vxlan.h"
+#include "lib/geneve.h"
#include "lib/devcom.h"
+#include "lib/pci_vsc.h"
#include "diag/fw_tracer.h"
#include "ecpf.h"
@@ -169,18 +172,28 @@ static struct mlx5_profile profile[] = {
#define FW_INIT_TIMEOUT_MILI 2000
#define FW_INIT_WAIT_MS 2
-#define FW_PRE_INIT_TIMEOUT_MILI 10000
+#define FW_PRE_INIT_TIMEOUT_MILI 120000
+#define FW_INIT_WARN_MESSAGE_INTERVAL 20000
-static int wait_fw_init(struct mlx5_core_dev *dev, u32 max_wait_mili)
+static int wait_fw_init(struct mlx5_core_dev *dev, u32 max_wait_mili,
+ u32 warn_time_mili)
{
+ unsigned long warn = jiffies + msecs_to_jiffies(warn_time_mili);
unsigned long end = jiffies + msecs_to_jiffies(max_wait_mili);
int err = 0;
+ BUILD_BUG_ON(FW_PRE_INIT_TIMEOUT_MILI < FW_INIT_WARN_MESSAGE_INTERVAL);
+
while (fw_initializing(dev)) {
if (time_after(jiffies, end)) {
err = -EBUSY;
break;
}
+ if (warn_time_mili && time_after(jiffies, warn)) {
+ mlx5_core_warn(dev, "Waiting for FW initialization, timeout abort in %ds\n",
+ jiffies_to_msecs(end - warn) / 1000);
+ warn = jiffies + msecs_to_jiffies(warn_time_mili);
+ }
msleep(FW_INIT_WAIT_MS);
}
@@ -721,8 +734,7 @@ static int mlx5_pci_init(struct mlx5_core_dev *dev, struct pci_dev *pdev,
struct mlx5_priv *priv = &dev->priv;
int err = 0;
- priv->pci_dev_data = id->driver_data;
-
+ mutex_init(&dev->pci_status_mutex);
pci_set_drvdata(dev->pdev, dev);
dev->bar_addr = pci_resource_start(pdev, 0);
@@ -761,6 +773,8 @@ static int mlx5_pci_init(struct mlx5_core_dev *dev, struct pci_dev *pdev,
goto err_clr_master;
}
+ mlx5_pci_vsc_init(dev);
+
return 0;
err_clr_master:
@@ -794,10 +808,16 @@ static int mlx5_init_once(struct mlx5_core_dev *dev)
goto err_devcom;
}
+ err = mlx5_irq_table_init(dev);
+ if (err) {
+ mlx5_core_err(dev, "failed to initialize irq table\n");
+ goto err_devcom;
+ }
+
err = mlx5_eq_table_init(dev);
if (err) {
mlx5_core_err(dev, "failed to initialize eq\n");
- goto err_devcom;
+ goto err_irq_cleanup;
}
err = mlx5_events_init(dev);
@@ -821,6 +841,7 @@ static int mlx5_init_once(struct mlx5_core_dev *dev)
mlx5_init_clock(dev);
dev->vxlan = mlx5_vxlan_create(dev);
+ dev->geneve = mlx5_geneve_create(dev);
err = mlx5_init_rl_table(dev);
if (err) {
@@ -834,37 +855,38 @@ static int mlx5_init_once(struct mlx5_core_dev *dev)
goto err_rl_cleanup;
}
- err = mlx5_eswitch_init(dev);
+ err = mlx5_sriov_init(dev);
if (err) {
- mlx5_core_err(dev, "Failed to init eswitch %d\n", err);
+ mlx5_core_err(dev, "Failed to init sriov %d\n", err);
goto err_mpfs_cleanup;
}
- err = mlx5_sriov_init(dev);
+ err = mlx5_eswitch_init(dev);
if (err) {
- mlx5_core_err(dev, "Failed to init sriov %d\n", err);
- goto err_eswitch_cleanup;
+ mlx5_core_err(dev, "Failed to init eswitch %d\n", err);
+ goto err_sriov_cleanup;
}
err = mlx5_fpga_init(dev);
if (err) {
mlx5_core_err(dev, "Failed to init fpga device %d\n", err);
- goto err_sriov_cleanup;
+ goto err_eswitch_cleanup;
}
dev->tracer = mlx5_fw_tracer_create(dev);
return 0;
-err_sriov_cleanup:
- mlx5_sriov_cleanup(dev);
err_eswitch_cleanup:
mlx5_eswitch_cleanup(dev->priv.eswitch);
+err_sriov_cleanup:
+ mlx5_sriov_cleanup(dev);
err_mpfs_cleanup:
mlx5_mpfs_cleanup(dev);
err_rl_cleanup:
mlx5_cleanup_rl_table(dev);
err_tables_cleanup:
+ mlx5_geneve_destroy(dev->geneve);
mlx5_vxlan_destroy(dev->vxlan);
mlx5_cleanup_mkey_table(dev);
mlx5_cleanup_qp_table(dev);
@@ -873,6 +895,8 @@ err_events_cleanup:
mlx5_events_cleanup(dev);
err_eq_cleanup:
mlx5_eq_table_cleanup(dev);
+err_irq_cleanup:
+ mlx5_irq_table_cleanup(dev);
err_devcom:
mlx5_devcom_unregister_device(dev->priv.devcom);
@@ -883,10 +907,11 @@ static void mlx5_cleanup_once(struct mlx5_core_dev *dev)
{
mlx5_fw_tracer_destroy(dev->tracer);
mlx5_fpga_cleanup(dev);
- mlx5_sriov_cleanup(dev);
mlx5_eswitch_cleanup(dev->priv.eswitch);
+ mlx5_sriov_cleanup(dev);
mlx5_mpfs_cleanup(dev);
mlx5_cleanup_rl_table(dev);
+ mlx5_geneve_destroy(dev->geneve);
mlx5_vxlan_destroy(dev->vxlan);
mlx5_cleanup_clock(dev);
mlx5_cleanup_reserved_gids(dev);
@@ -895,6 +920,7 @@ static void mlx5_cleanup_once(struct mlx5_core_dev *dev)
mlx5_cq_debugfs_cleanup(dev);
mlx5_events_cleanup(dev);
mlx5_eq_table_cleanup(dev);
+ mlx5_irq_table_cleanup(dev);
mlx5_devcom_unregister_device(dev->priv.devcom);
}
@@ -911,7 +937,7 @@ static int mlx5_function_setup(struct mlx5_core_dev *dev, bool boot)
/* wait for firmware to accept initialization segments configurations
*/
- err = wait_fw_init(dev, FW_PRE_INIT_TIMEOUT_MILI);
+ err = wait_fw_init(dev, FW_PRE_INIT_TIMEOUT_MILI, FW_INIT_WARN_MESSAGE_INTERVAL);
if (err) {
mlx5_core_err(dev, "Firmware over %d MS in pre-initializing state, aborting\n",
FW_PRE_INIT_TIMEOUT_MILI);
@@ -924,7 +950,7 @@ static int mlx5_function_setup(struct mlx5_core_dev *dev, bool boot)
return err;
}
- err = wait_fw_init(dev, FW_INIT_TIMEOUT_MILI);
+ err = wait_fw_init(dev, FW_INIT_TIMEOUT_MILI, 0);
if (err) {
mlx5_core_err(dev, "Firmware over %d MS in initializing state, aborting\n",
FW_INIT_TIMEOUT_MILI);
@@ -1028,6 +1054,12 @@ static int mlx5_load(struct mlx5_core_dev *dev)
mlx5_events_start(dev);
mlx5_pagealloc_start(dev);
+ err = mlx5_irq_table_create(dev);
+ if (err) {
+ mlx5_core_err(dev, "Failed to alloc IRQs\n");
+ goto err_irq_table;
+ }
+
err = mlx5_eq_table_create(dev);
if (err) {
mlx5_core_err(dev, "Failed to create EQs\n");
@@ -1099,6 +1131,8 @@ err_fpga_start:
err_fw_tracer:
mlx5_eq_table_destroy(dev);
err_eq_table:
+ mlx5_irq_table_destroy(dev);
+err_irq_table:
mlx5_pagealloc_stop(dev);
mlx5_events_stop(dev);
mlx5_put_uars_page(dev, dev->priv.uar);
@@ -1115,6 +1149,7 @@ static void mlx5_unload(struct mlx5_core_dev *dev)
mlx5_fpga_device_stop(dev);
mlx5_fw_tracer_cleanup(dev->tracer);
mlx5_eq_table_destroy(dev);
+ mlx5_irq_table_destroy(dev);
mlx5_pagealloc_stop(dev);
mlx5_events_stop(dev);
mlx5_put_uars_page(dev, dev->priv.uar);
@@ -1183,7 +1218,7 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, bool cleanup)
int err = 0;
if (cleanup)
- mlx5_drain_health_recovery(dev);
+ mlx5_drain_health_wq(dev);
mutex_lock(&dev->intf_state_mutex);
if (!test_bit(MLX5_INTERFACE_STATE_UP, &dev->intf_state)) {
@@ -1210,17 +1245,6 @@ out:
return err;
}
-static const struct devlink_ops mlx5_devlink_ops = {
-#ifdef CONFIG_MLX5_ESWITCH
- .eswitch_mode_set = mlx5_devlink_eswitch_mode_set,
- .eswitch_mode_get = mlx5_devlink_eswitch_mode_get,
- .eswitch_inline_mode_set = mlx5_devlink_eswitch_inline_mode_set,
- .eswitch_inline_mode_get = mlx5_devlink_eswitch_inline_mode_get,
- .eswitch_encap_mode_set = mlx5_devlink_eswitch_encap_mode_set,
- .eswitch_encap_mode_get = mlx5_devlink_eswitch_encap_mode_get,
-#endif
-};
-
static int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx)
{
struct mlx5_priv *priv = &dev->priv;
@@ -1230,7 +1254,6 @@ static int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx)
INIT_LIST_HEAD(&priv->ctx_list);
spin_lock_init(&priv->ctx_lock);
- mutex_init(&dev->pci_status_mutex);
mutex_init(&dev->intf_state_mutex);
mutex_init(&priv->bfregs.reg_head.lock);
@@ -1282,9 +1305,9 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *id)
struct devlink *devlink;
int err;
- devlink = devlink_alloc(&mlx5_devlink_ops, sizeof(*dev));
+ devlink = mlx5_devlink_alloc();
if (!devlink) {
- dev_err(&pdev->dev, "kzalloc failed\n");
+ dev_err(&pdev->dev, "devlink alloc failed\n");
return -ENOMEM;
}
@@ -1292,6 +1315,9 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *id)
dev->device = &pdev->dev;
dev->pdev = pdev;
+ dev->coredev_type = id->driver_data & MLX5_PCI_DEV_IS_VF ?
+ MLX5_COREDEV_VF : MLX5_COREDEV_PF;
+
err = mlx5_mdev_init(dev, prof_sel);
if (err)
goto mdev_init_err;
@@ -1312,10 +1338,14 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *id)
request_module_nowait(MLX5_IB_MOD);
- err = devlink_register(devlink, &pdev->dev);
+ err = mlx5_devlink_register(devlink, &pdev->dev);
if (err)
goto clean_load;
+ err = mlx5_crdump_enable(dev);
+ if (err)
+ dev_err(&pdev->dev, "mlx5_crdump_enable failed with error code %d\n", err);
+
pci_save_state(pdev);
return 0;
@@ -1327,7 +1357,7 @@ err_load_one:
pci_init_err:
mlx5_mdev_uninit(dev);
mdev_init_err:
- devlink_free(devlink);
+ mlx5_devlink_free(devlink);
return err;
}
@@ -1337,7 +1367,8 @@ static void remove_one(struct pci_dev *pdev)
struct mlx5_core_dev *dev = pci_get_drvdata(pdev);
struct devlink *devlink = priv_to_devlink(dev);
- devlink_unregister(devlink);
+ mlx5_crdump_disable(dev);
+ mlx5_devlink_unregister(devlink);
mlx5_unregister_device(dev);
if (mlx5_unload_one(dev, true)) {
@@ -1348,7 +1379,7 @@ static void remove_one(struct pci_dev *pdev)
mlx5_pci_close(dev);
mlx5_mdev_uninit(dev);
- devlink_free(devlink);
+ mlx5_devlink_free(devlink);
}
static pci_ers_result_t mlx5_pci_err_detected(struct pci_dev *pdev,
@@ -1359,12 +1390,10 @@ static pci_ers_result_t mlx5_pci_err_detected(struct pci_dev *pdev,
mlx5_core_info(dev, "%s was called\n", __func__);
mlx5_enter_error_state(dev, false);
+ mlx5_error_sw_reset(dev);
mlx5_unload_one(dev, false);
- /* In case of kernel call drain the health wq */
- if (state) {
- mlx5_drain_health_wq(dev);
- mlx5_pci_disable_device(dev);
- }
+ mlx5_drain_health_wq(dev);
+ mlx5_pci_disable_device(dev);
return state == pci_channel_io_perm_failure ?
PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET;
@@ -1532,7 +1561,8 @@ MODULE_DEVICE_TABLE(pci, mlx5_core_pci_table);
void mlx5_disable_device(struct mlx5_core_dev *dev)
{
- mlx5_pci_err_detected(dev->pdev, 0);
+ mlx5_error_sw_reset(dev);
+ mlx5_unload_one(dev, false);
}
void mlx5_recover_device(struct mlx5_core_dev *dev)
@@ -1570,7 +1600,7 @@ static int __init init(void)
get_random_bytes(&sw_owner_id, sizeof(sw_owner_id));
mlx5_core_verify_params();
- mlx5_fpga_ipsec_build_fs_cmds();
+ mlx5_accel_ipsec_build_fs_cmds();
mlx5_register_debugfs();
err = pci_register_driver(&mlx5_core_driver);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
index 22e69d4813e4..471bbc48bc1f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
@@ -111,6 +111,11 @@ enum {
MLX5_DRIVER_SYND = 0xbadd00de,
};
+enum mlx5_semaphore_space_address {
+ MLX5_SEMAPHORE_SPACE_DOMAIN = 0xA,
+ MLX5_SEMAPHORE_SW_RESET = 0x20,
+};
+
int mlx5_query_hca_caps(struct mlx5_core_dev *dev);
int mlx5_query_board_id(struct mlx5_core_dev *dev);
int mlx5_cmd_init_hca(struct mlx5_core_dev *dev, uint32_t *sw_owner_id);
@@ -118,6 +123,7 @@ int mlx5_cmd_teardown_hca(struct mlx5_core_dev *dev);
int mlx5_cmd_force_teardown_hca(struct mlx5_core_dev *dev);
int mlx5_cmd_fast_teardown_hca(struct mlx5_core_dev *dev);
void mlx5_enter_error_state(struct mlx5_core_dev *dev, bool force);
+void mlx5_error_sw_reset(struct mlx5_core_dev *dev);
void mlx5_disable_device(struct mlx5_core_dev *dev);
void mlx5_recover_device(struct mlx5_core_dev *dev);
int mlx5_sriov_init(struct mlx5_core_dev *dev);
@@ -153,6 +159,19 @@ int mlx5_query_qcam_reg(struct mlx5_core_dev *mdev, u32 *qcam,
void mlx5_lag_add(struct mlx5_core_dev *dev, struct net_device *netdev);
void mlx5_lag_remove(struct mlx5_core_dev *dev);
+int mlx5_irq_table_init(struct mlx5_core_dev *dev);
+void mlx5_irq_table_cleanup(struct mlx5_core_dev *dev);
+int mlx5_irq_table_create(struct mlx5_core_dev *dev);
+void mlx5_irq_table_destroy(struct mlx5_core_dev *dev);
+int mlx5_irq_attach_nb(struct mlx5_irq_table *irq_table, int vecidx,
+ struct notifier_block *nb);
+int mlx5_irq_detach_nb(struct mlx5_irq_table *irq_table, int vecidx,
+ struct notifier_block *nb);
+struct cpumask *
+mlx5_irq_get_affinity_mask(struct mlx5_irq_table *irq_table, int vecidx);
+struct cpu_rmap *mlx5_irq_get_rmap(struct mlx5_irq_table *table);
+int mlx5_irq_get_num_comp(struct mlx5_irq_table *table);
+
int mlx5_events_init(struct mlx5_core_dev *dev);
void mlx5_events_cleanup(struct mlx5_core_dev *dev);
void mlx5_events_start(struct mlx5_core_dev *dev);
@@ -184,7 +203,10 @@ int mlx5_set_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 arm, u8 mode);
MLX5_CAP_MCAM_FEATURE((mdev), mtpps_fs) && \
MLX5_CAP_MCAM_FEATURE((mdev), mtpps_enh_out_per_adj))
-int mlx5_firmware_flash(struct mlx5_core_dev *dev, const struct firmware *fw);
+int mlx5_firmware_flash(struct mlx5_core_dev *dev, const struct firmware *fw,
+ struct netlink_ext_ack *extack);
+int mlx5_fw_version_query(struct mlx5_core_dev *dev,
+ u32 *running_ver, u32 *stored_ver);
void mlx5e_init(void);
void mlx5e_cleanup(void);
@@ -213,7 +235,7 @@ enum {
MLX5_NIC_IFC_FULL = 0,
MLX5_NIC_IFC_DISABLED = 1,
MLX5_NIC_IFC_NO_DRAM_NIC = 2,
- MLX5_NIC_IFC_INVALID = 3
+ MLX5_NIC_IFC_SW_RESET = 7
};
u8 mlx5_get_nic_state(struct mlx5_core_dev *dev);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mr.c b/drivers/net/ethernet/mellanox/mlx5/core/mr.c
index ea744d8466ea..9231b39d18b2 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/mr.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/mr.c
@@ -38,15 +38,12 @@
void mlx5_init_mkey_table(struct mlx5_core_dev *dev)
{
- struct mlx5_mkey_table *table = &dev->priv.mkey_table;
-
- memset(table, 0, sizeof(*table));
- rwlock_init(&table->lock);
- INIT_RADIX_TREE(&table->tree, GFP_ATOMIC);
+ xa_init_flags(&dev->priv.mkey_table, XA_FLAGS_LOCK_IRQ);
}
void mlx5_cleanup_mkey_table(struct mlx5_core_dev *dev)
{
+ WARN_ON(!xa_empty(&dev->priv.mkey_table));
}
int mlx5_core_create_mkey_cb(struct mlx5_core_dev *dev,
@@ -56,8 +53,8 @@ int mlx5_core_create_mkey_cb(struct mlx5_core_dev *dev,
mlx5_async_cbk_t callback,
struct mlx5_async_work *context)
{
- struct mlx5_mkey_table *table = &dev->priv.mkey_table;
u32 lout[MLX5_ST_SZ_DW(create_mkey_out)] = {0};
+ struct xarray *mkeys = &dev->priv.mkey_table;
u32 mkey_index;
void *mkc;
int err;
@@ -88,12 +85,10 @@ int mlx5_core_create_mkey_cb(struct mlx5_core_dev *dev,
mlx5_core_dbg(dev, "out 0x%x, key 0x%x, mkey 0x%x\n",
mkey_index, key, mkey->key);
- /* connect to mkey tree */
- write_lock_irq(&table->lock);
- err = radix_tree_insert(&table->tree, mlx5_base_mkey(mkey->key), mkey);
- write_unlock_irq(&table->lock);
+ err = xa_err(xa_store_irq(mkeys, mlx5_base_mkey(mkey->key), mkey,
+ GFP_KERNEL));
if (err) {
- mlx5_core_warn(dev, "failed radix tree insert of mkey 0x%x, %d\n",
+ mlx5_core_warn(dev, "failed xarray insert of mkey 0x%x, %d\n",
mlx5_base_mkey(mkey->key), err);
mlx5_core_destroy_mkey(dev, mkey);
}
@@ -114,17 +109,17 @@ EXPORT_SYMBOL(mlx5_core_create_mkey);
int mlx5_core_destroy_mkey(struct mlx5_core_dev *dev,
struct mlx5_core_mkey *mkey)
{
- struct mlx5_mkey_table *table = &dev->priv.mkey_table;
u32 out[MLX5_ST_SZ_DW(destroy_mkey_out)] = {0};
u32 in[MLX5_ST_SZ_DW(destroy_mkey_in)] = {0};
+ struct xarray *mkeys = &dev->priv.mkey_table;
struct mlx5_core_mkey *deleted_mkey;
unsigned long flags;
- write_lock_irqsave(&table->lock, flags);
- deleted_mkey = radix_tree_delete(&table->tree, mlx5_base_mkey(mkey->key));
- write_unlock_irqrestore(&table->lock, flags);
+ xa_lock_irqsave(mkeys, flags);
+ deleted_mkey = __xa_erase(mkeys, mlx5_base_mkey(mkey->key));
+ xa_unlock_irqrestore(mkeys, flags);
if (!deleted_mkey) {
- mlx5_core_dbg(dev, "failed radix tree delete of mkey 0x%x\n",
+ mlx5_core_dbg(dev, "failed xarray delete of mkey 0x%x\n",
mlx5_base_mkey(mkey->key));
return -ENOENT;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c b/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c
new file mode 100644
index 000000000000..373981a659c7
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c
@@ -0,0 +1,334 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/* Copyright (c) 2019 Mellanox Technologies. */
+
+#include <linux/interrupt.h>
+#include <linux/notifier.h>
+#include <linux/module.h>
+#include <linux/mlx5/driver.h>
+#include "mlx5_core.h"
+#ifdef CONFIG_RFS_ACCEL
+#include <linux/cpu_rmap.h>
+#endif
+
+#define MLX5_MAX_IRQ_NAME (32)
+
+struct mlx5_irq {
+ struct atomic_notifier_head nh;
+ cpumask_var_t mask;
+ char name[MLX5_MAX_IRQ_NAME];
+};
+
+struct mlx5_irq_table {
+ struct mlx5_irq *irq;
+ int nvec;
+#ifdef CONFIG_RFS_ACCEL
+ struct cpu_rmap *rmap;
+#endif
+};
+
+int mlx5_irq_table_init(struct mlx5_core_dev *dev)
+{
+ struct mlx5_irq_table *irq_table;
+
+ irq_table = kvzalloc(sizeof(*irq_table), GFP_KERNEL);
+ if (!irq_table)
+ return -ENOMEM;
+
+ dev->priv.irq_table = irq_table;
+ return 0;
+}
+
+void mlx5_irq_table_cleanup(struct mlx5_core_dev *dev)
+{
+ kvfree(dev->priv.irq_table);
+}
+
+int mlx5_irq_get_num_comp(struct mlx5_irq_table *table)
+{
+ return table->nvec - MLX5_IRQ_VEC_COMP_BASE;
+}
+
+static struct mlx5_irq *mlx5_irq_get(struct mlx5_core_dev *dev, int vecidx)
+{
+ struct mlx5_irq_table *irq_table = dev->priv.irq_table;
+
+ return &irq_table->irq[vecidx];
+}
+
+int mlx5_irq_attach_nb(struct mlx5_irq_table *irq_table, int vecidx,
+ struct notifier_block *nb)
+{
+ struct mlx5_irq *irq;
+
+ irq = &irq_table->irq[vecidx];
+ return atomic_notifier_chain_register(&irq->nh, nb);
+}
+
+int mlx5_irq_detach_nb(struct mlx5_irq_table *irq_table, int vecidx,
+ struct notifier_block *nb)
+{
+ struct mlx5_irq *irq;
+
+ irq = &irq_table->irq[vecidx];
+ return atomic_notifier_chain_unregister(&irq->nh, nb);
+}
+
+static irqreturn_t mlx5_irq_int_handler(int irq, void *nh)
+{
+ atomic_notifier_call_chain(nh, 0, NULL);
+ return IRQ_HANDLED;
+}
+
+static void irq_set_name(char *name, int vecidx)
+{
+ if (vecidx == 0) {
+ snprintf(name, MLX5_MAX_IRQ_NAME, "mlx5_async");
+ return;
+ }
+
+ snprintf(name, MLX5_MAX_IRQ_NAME, "mlx5_comp%d",
+ vecidx - MLX5_IRQ_VEC_COMP_BASE);
+ return;
+}
+
+static int request_irqs(struct mlx5_core_dev *dev, int nvec)
+{
+ char name[MLX5_MAX_IRQ_NAME];
+ int err;
+ int i;
+
+ for (i = 0; i < nvec; i++) {
+ struct mlx5_irq *irq = mlx5_irq_get(dev, i);
+ int irqn = pci_irq_vector(dev->pdev, i);
+
+ irq_set_name(name, i);
+ ATOMIC_INIT_NOTIFIER_HEAD(&irq->nh);
+ snprintf(irq->name, MLX5_MAX_IRQ_NAME,
+ "%s@pci:%s", name, pci_name(dev->pdev));
+ err = request_irq(irqn, mlx5_irq_int_handler, 0, irq->name,
+ &irq->nh);
+ if (err) {
+ mlx5_core_err(dev, "Failed to request irq\n");
+ goto err_request_irq;
+ }
+ }
+ return 0;
+
+err_request_irq:
+ for (; i >= 0; i--) {
+ struct mlx5_irq *irq = mlx5_irq_get(dev, i);
+ int irqn = pci_irq_vector(dev->pdev, i);
+
+ free_irq(irqn, &irq->nh);
+ }
+ return err;
+}
+
+static void irq_clear_rmap(struct mlx5_core_dev *dev)
+{
+#ifdef CONFIG_RFS_ACCEL
+ struct mlx5_irq_table *irq_table = dev->priv.irq_table;
+
+ free_irq_cpu_rmap(irq_table->rmap);
+#endif
+}
+
+static int irq_set_rmap(struct mlx5_core_dev *mdev)
+{
+ int err = 0;
+#ifdef CONFIG_RFS_ACCEL
+ struct mlx5_irq_table *irq_table = mdev->priv.irq_table;
+ int num_affinity_vec;
+ int vecidx;
+
+ num_affinity_vec = mlx5_irq_get_num_comp(irq_table);
+ irq_table->rmap = alloc_irq_cpu_rmap(num_affinity_vec);
+ if (!irq_table->rmap) {
+ err = -ENOMEM;
+ mlx5_core_err(mdev, "Failed to allocate cpu_rmap. err %d", err);
+ goto err_out;
+ }
+
+ vecidx = MLX5_IRQ_VEC_COMP_BASE;
+ for (; vecidx < irq_table->nvec; vecidx++) {
+ err = irq_cpu_rmap_add(irq_table->rmap,
+ pci_irq_vector(mdev->pdev, vecidx));
+ if (err) {
+ mlx5_core_err(mdev, "irq_cpu_rmap_add failed. err %d",
+ err);
+ goto err_irq_cpu_rmap_add;
+ }
+ }
+ return 0;
+
+err_irq_cpu_rmap_add:
+ irq_clear_rmap(mdev);
+err_out:
+#endif
+ return err;
+}
+
+/* Completion IRQ vectors */
+
+static int set_comp_irq_affinity_hint(struct mlx5_core_dev *mdev, int i)
+{
+ int vecidx = MLX5_IRQ_VEC_COMP_BASE + i;
+ struct mlx5_irq *irq;
+ int irqn;
+
+ irq = mlx5_irq_get(mdev, vecidx);
+ irqn = pci_irq_vector(mdev->pdev, vecidx);
+ if (!zalloc_cpumask_var(&irq->mask, GFP_KERNEL)) {
+ mlx5_core_warn(mdev, "zalloc_cpumask_var failed");
+ return -ENOMEM;
+ }
+
+ cpumask_set_cpu(cpumask_local_spread(i, mdev->priv.numa_node),
+ irq->mask);
+ if (IS_ENABLED(CONFIG_SMP) &&
+ irq_set_affinity_hint(irqn, irq->mask))
+ mlx5_core_warn(mdev, "irq_set_affinity_hint failed, irq 0x%.4x",
+ irqn);
+
+ return 0;
+}
+
+static void clear_comp_irq_affinity_hint(struct mlx5_core_dev *mdev, int i)
+{
+ int vecidx = MLX5_IRQ_VEC_COMP_BASE + i;
+ struct mlx5_irq *irq;
+ int irqn;
+
+ irq = mlx5_irq_get(mdev, vecidx);
+ irqn = pci_irq_vector(mdev->pdev, vecidx);
+ irq_set_affinity_hint(irqn, NULL);
+ free_cpumask_var(irq->mask);
+}
+
+static int set_comp_irq_affinity_hints(struct mlx5_core_dev *mdev)
+{
+ int nvec = mlx5_irq_get_num_comp(mdev->priv.irq_table);
+ int err;
+ int i;
+
+ for (i = 0; i < nvec; i++) {
+ err = set_comp_irq_affinity_hint(mdev, i);
+ if (err)
+ goto err_out;
+ }
+
+ return 0;
+
+err_out:
+ for (i--; i >= 0; i--)
+ clear_comp_irq_affinity_hint(mdev, i);
+
+ return err;
+}
+
+static void clear_comp_irqs_affinity_hints(struct mlx5_core_dev *mdev)
+{
+ int nvec = mlx5_irq_get_num_comp(mdev->priv.irq_table);
+ int i;
+
+ for (i = 0; i < nvec; i++)
+ clear_comp_irq_affinity_hint(mdev, i);
+}
+
+struct cpumask *
+mlx5_irq_get_affinity_mask(struct mlx5_irq_table *irq_table, int vecidx)
+{
+ return irq_table->irq[vecidx].mask;
+}
+
+#ifdef CONFIG_RFS_ACCEL
+struct cpu_rmap *mlx5_irq_get_rmap(struct mlx5_irq_table *irq_table)
+{
+ return irq_table->rmap;
+}
+#endif
+
+static void unrequest_irqs(struct mlx5_core_dev *dev)
+{
+ struct mlx5_irq_table *table = dev->priv.irq_table;
+ int i;
+
+ for (i = 0; i < table->nvec; i++)
+ free_irq(pci_irq_vector(dev->pdev, i),
+ &mlx5_irq_get(dev, i)->nh);
+}
+
+int mlx5_irq_table_create(struct mlx5_core_dev *dev)
+{
+ struct mlx5_priv *priv = &dev->priv;
+ struct mlx5_irq_table *table = priv->irq_table;
+ int num_eqs = MLX5_CAP_GEN(dev, max_num_eqs) ?
+ MLX5_CAP_GEN(dev, max_num_eqs) :
+ 1 << MLX5_CAP_GEN(dev, log_max_eq);
+ int nvec;
+ int err;
+
+ nvec = MLX5_CAP_GEN(dev, num_ports) * num_online_cpus() +
+ MLX5_IRQ_VEC_COMP_BASE;
+ nvec = min_t(int, nvec, num_eqs);
+ if (nvec <= MLX5_IRQ_VEC_COMP_BASE)
+ return -ENOMEM;
+
+ table->irq = kcalloc(nvec, sizeof(*table->irq), GFP_KERNEL);
+ if (!table->irq)
+ return -ENOMEM;
+
+ nvec = pci_alloc_irq_vectors(dev->pdev, MLX5_IRQ_VEC_COMP_BASE + 1,
+ nvec, PCI_IRQ_MSIX);
+ if (nvec < 0) {
+ err = nvec;
+ goto err_free_irq;
+ }
+
+ table->nvec = nvec;
+
+ err = irq_set_rmap(dev);
+ if (err)
+ goto err_set_rmap;
+
+ err = request_irqs(dev, nvec);
+ if (err)
+ goto err_request_irqs;
+
+ err = set_comp_irq_affinity_hints(dev);
+ if (err) {
+ mlx5_core_err(dev, "Failed to alloc affinity hint cpumask\n");
+ goto err_set_affinity;
+ }
+
+ return 0;
+
+err_set_affinity:
+ unrequest_irqs(dev);
+err_request_irqs:
+ irq_clear_rmap(dev);
+err_set_rmap:
+ pci_free_irq_vectors(dev->pdev);
+err_free_irq:
+ kfree(table->irq);
+ return err;
+}
+
+void mlx5_irq_table_destroy(struct mlx5_core_dev *dev)
+{
+ struct mlx5_irq_table *table = dev->priv.irq_table;
+ int i;
+
+ /* free_irq requires that affinity and rmap will be cleared
+ * before calling it. This is why there is asymmetry with set_rmap
+ * which should be called after alloc_irq but before request_irq.
+ */
+ irq_clear_rmap(dev);
+ clear_comp_irqs_affinity_hints(dev);
+ for (i = 0; i < table->nvec; i++)
+ free_irq(pci_irq_vector(dev->pdev, i),
+ &mlx5_irq_get(dev, i)->nh);
+ pci_free_irq_vectors(dev->pdev);
+ kfree(table->irq);
+}
+
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/rdma.c b/drivers/net/ethernet/mellanox/mlx5/core/rdma.c
index 86f77456f873..17ce9dd56b13 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/rdma.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/rdma.c
@@ -106,10 +106,10 @@ static int mlx5_rdma_enable_roce_steering(struct mlx5_core_dev *dev)
return 0;
-destroy_flow_table:
- mlx5_destroy_flow_table(ft);
destroy_flow_group:
mlx5_destroy_flow_group(fg);
+destroy_flow_table:
+ mlx5_destroy_flow_table(ft);
free:
kvfree(spec);
kvfree(flow_group_in);
@@ -126,7 +126,7 @@ static void mlx5_rdma_make_default_gid(struct mlx5_core_dev *dev, union ib_gid *
{
u8 hw_id[ETH_ALEN];
- mlx5_query_nic_vport_mac_address(dev, 0, hw_id);
+ mlx5_query_mac_address(dev, hw_id);
gid->global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL);
addrconf_addr_eui48(&gid->raw[8], hw_id);
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c
index a249b3c3843d..61fcfd8b39b4 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c
@@ -74,17 +74,11 @@ static int mlx5_device_enable_sriov(struct mlx5_core_dev *dev, int num_vfs)
int err;
int vf;
- if (sriov->enabled_vfs) {
- mlx5_core_warn(dev,
- "failed to enable SRIOV on device, already enabled with %d vfs\n",
- sriov->enabled_vfs);
- return -EBUSY;
- }
-
if (!MLX5_ESWITCH_MANAGER(dev))
goto enable_vfs_hca;
- err = mlx5_eswitch_enable_sriov(dev->priv.eswitch, num_vfs, SRIOV_LEGACY);
+ mlx5_eswitch_update_num_of_vfs(dev->priv.eswitch, num_vfs);
+ err = mlx5_eswitch_enable(dev->priv.eswitch, MLX5_ESWITCH_LEGACY);
if (err) {
mlx5_core_warn(dev,
"failed to enable eswitch SRIOV (%d)\n", err);
@@ -99,7 +93,6 @@ enable_vfs_hca:
continue;
}
sriov->vfs_ctx[vf].enabled = 1;
- sriov->enabled_vfs++;
if (MLX5_CAP_GEN(dev, port_type) == MLX5_CAP_PORT_TYPE_IB) {
err = sriov_restore_guids(dev, vf);
if (err) {
@@ -118,13 +111,11 @@ enable_vfs_hca:
static void mlx5_device_disable_sriov(struct mlx5_core_dev *dev)
{
struct mlx5_core_sriov *sriov = &dev->priv.sriov;
+ int num_vfs = pci_num_vf(dev->pdev);
int err;
int vf;
- if (!sriov->enabled_vfs)
- goto out;
-
- for (vf = 0; vf < sriov->num_vfs; vf++) {
+ for (vf = num_vfs - 1; vf >= 0; vf--) {
if (!sriov->vfs_ctx[vf].enabled)
continue;
err = mlx5_core_disable_hca(dev, vf + 1);
@@ -133,12 +124,10 @@ static void mlx5_device_disable_sriov(struct mlx5_core_dev *dev)
continue;
}
sriov->vfs_ctx[vf].enabled = 0;
- sriov->enabled_vfs--;
}
-out:
if (MLX5_ESWITCH_MANAGER(dev))
- mlx5_eswitch_disable_sriov(dev->priv.eswitch);
+ mlx5_eswitch_disable(dev->priv.eswitch);
if (mlx5_wait_for_pages(dev, &dev->priv.vfs_pages))
mlx5_core_warn(dev, "timeout reclaiming VFs pages\n");
@@ -191,13 +180,11 @@ int mlx5_core_sriov_configure(struct pci_dev *pdev, int num_vfs)
int mlx5_sriov_attach(struct mlx5_core_dev *dev)
{
- struct mlx5_core_sriov *sriov = &dev->priv.sriov;
-
- if (!mlx5_core_is_pf(dev) || !sriov->num_vfs)
+ if (!mlx5_core_is_pf(dev) || !pci_num_vf(dev->pdev))
return 0;
/* If sriov VFs exist in PCI level, enable them in device level */
- return mlx5_device_enable_sriov(dev, sriov->num_vfs);
+ return mlx5_device_enable_sriov(dev, pci_num_vf(dev->pdev));
}
void mlx5_sriov_detach(struct mlx5_core_dev *dev)
@@ -208,6 +195,30 @@ void mlx5_sriov_detach(struct mlx5_core_dev *dev)
mlx5_device_disable_sriov(dev);
}
+static u16 mlx5_get_max_vfs(struct mlx5_core_dev *dev)
+{
+ u16 host_total_vfs;
+ const u32 *out;
+
+ if (mlx5_core_is_ecpf_esw_manager(dev)) {
+ out = mlx5_esw_query_functions(dev);
+
+ /* Old FW doesn't support getting total_vfs from esw func
+ * but supports getting it from pci_sriov.
+ */
+ if (IS_ERR(out))
+ goto done;
+ host_total_vfs = MLX5_GET(query_esw_functions_out, out,
+ host_params_context.host_total_vfs);
+ kvfree(out);
+ if (host_total_vfs)
+ return host_total_vfs;
+ }
+
+done:
+ return pci_sriov_get_totalvfs(dev->pdev);
+}
+
int mlx5_sriov_init(struct mlx5_core_dev *dev)
{
struct mlx5_core_sriov *sriov = &dev->priv.sriov;
@@ -218,6 +229,7 @@ int mlx5_sriov_init(struct mlx5_core_dev *dev)
return 0;
total_vfs = pci_sriov_get_totalvfs(pdev);
+ sriov->max_vfs = mlx5_get_max_vfs(dev);
sriov->num_vfs = pci_num_vf(pdev);
sriov->vfs_ctx = kcalloc(total_vfs, sizeof(*sriov->vfs_ctx), GFP_KERNEL);
if (!sriov->vfs_ctx)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c
index 95cdc8cbcba4..c912d82ca64b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c
@@ -34,6 +34,7 @@
#include <linux/etherdevice.h>
#include <linux/mlx5/driver.h>
#include <linux/mlx5/vport.h>
+#include <linux/mlx5/eswitch.h>
#include "mlx5_core.h"
/* Mutex to hold while enabling or disabling RoCE */
@@ -155,11 +156,12 @@ int mlx5_modify_nic_vport_min_inline(struct mlx5_core_dev *mdev,
}
int mlx5_query_nic_vport_mac_address(struct mlx5_core_dev *mdev,
- u16 vport, u8 *addr)
+ u16 vport, bool other, u8 *addr)
{
- u32 *out;
int outlen = MLX5_ST_SZ_BYTES(query_nic_vport_context_out);
+ u32 in[MLX5_ST_SZ_DW(query_nic_vport_context_in)] = {};
u8 *out_addr;
+ u32 *out;
int err;
out = kvzalloc(outlen, GFP_KERNEL);
@@ -169,7 +171,12 @@ int mlx5_query_nic_vport_mac_address(struct mlx5_core_dev *mdev,
out_addr = MLX5_ADDR_OF(query_nic_vport_context_out, out,
nic_vport_context.permanent_address);
- err = mlx5_query_nic_vport_context(mdev, vport, out, outlen);
+ MLX5_SET(query_nic_vport_context_in, in, opcode,
+ MLX5_CMD_OP_QUERY_NIC_VPORT_CONTEXT);
+ MLX5_SET(query_nic_vport_context_in, in, vport_number, vport);
+ MLX5_SET(query_nic_vport_context_in, in, other_vport, other);
+
+ err = mlx5_cmd_exec(mdev, in, sizeof(in), out, outlen);
if (!err)
ether_addr_copy(addr, &out_addr[2]);
@@ -178,6 +185,12 @@ int mlx5_query_nic_vport_mac_address(struct mlx5_core_dev *mdev,
}
EXPORT_SYMBOL_GPL(mlx5_query_nic_vport_mac_address);
+int mlx5_query_mac_address(struct mlx5_core_dev *mdev, u8 *addr)
+{
+ return mlx5_query_nic_vport_mac_address(mdev, 0, false, addr);
+}
+EXPORT_SYMBOL_GPL(mlx5_query_mac_address);
+
int mlx5_modify_nic_vport_mac_address(struct mlx5_core_dev *mdev,
u16 vport, u8 *addr)
{
@@ -194,9 +207,7 @@ int mlx5_modify_nic_vport_mac_address(struct mlx5_core_dev *mdev,
MLX5_SET(modify_nic_vport_context_in, in,
field_select.permanent_address, 1);
MLX5_SET(modify_nic_vport_context_in, in, vport_number, vport);
-
- if (vport)
- MLX5_SET(modify_nic_vport_context_in, in, other_vport, 1);
+ MLX5_SET(modify_nic_vport_context_in, in, other_vport, 1);
nic_vport_ctx = MLX5_ADDR_OF(modify_nic_vport_context_in,
in, nic_vport_context);
@@ -291,9 +302,7 @@ int mlx5_query_nic_vport_mac_list(struct mlx5_core_dev *dev,
MLX5_CMD_OP_QUERY_NIC_VPORT_CONTEXT);
MLX5_SET(query_nic_vport_context_in, in, allowed_list_type, list_type);
MLX5_SET(query_nic_vport_context_in, in, vport_number, vport);
-
- if (vport)
- MLX5_SET(query_nic_vport_context_in, in, other_vport, 1);
+ MLX5_SET(query_nic_vport_context_in, in, other_vport, 1);
err = mlx5_cmd_exec(dev, in, sizeof(in), out, out_sz);
if (err)
@@ -483,7 +492,7 @@ int mlx5_modify_nic_vport_node_guid(struct mlx5_core_dev *mdev,
MLX5_SET(modify_nic_vport_context_in, in,
field_select.node_guid, 1);
MLX5_SET(modify_nic_vport_context_in, in, vport_number, vport);
- MLX5_SET(modify_nic_vport_context_in, in, other_vport, !!vport);
+ MLX5_SET(modify_nic_vport_context_in, in, other_vport, 1);
nic_vport_context = MLX5_ADDR_OF(modify_nic_vport_context_in,
in, nic_vport_context);
@@ -1157,3 +1166,17 @@ u64 mlx5_query_nic_system_image_guid(struct mlx5_core_dev *mdev)
return tmp;
}
EXPORT_SYMBOL_GPL(mlx5_query_nic_system_image_guid);
+
+/**
+ * mlx5_eswitch_get_total_vports - Get total vports of the eswitch
+ *
+ * @dev: Pointer to core device
+ *
+ * mlx5_eswitch_get_total_vports returns total number of vports for
+ * the eswitch.
+ */
+u16 mlx5_eswitch_get_total_vports(const struct mlx5_core_dev *dev)
+{
+ return MLX5_SPECIAL_VPORTS(dev) + mlx5_core_max_vfs(dev);
+}
+EXPORT_SYMBOL(mlx5_eswitch_get_total_vports);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/wq.h b/drivers/net/ethernet/mellanox/mlx5/core/wq.h
index 1f87cce421e0..f1ec58c9e9e3 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/wq.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/wq.h
@@ -134,11 +134,6 @@ static inline void mlx5_wq_cyc_update_db_record(struct mlx5_wq_cyc *wq)
*wq->db = cpu_to_be32(wq->wqe_ctr);
}
-static inline u16 mlx5_wq_cyc_get_ctr_wrap_cnt(struct mlx5_wq_cyc *wq, u16 ctr)
-{
- return ctr >> wq->fbc.log_sz;
-}
-
static inline u16 mlx5_wq_cyc_ctr2ix(struct mlx5_wq_cyc *wq, u16 ctr)
{
return ctr & wq->fbc.sz_m1;
diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h b/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h
index 14c0c62f8e73..c50e74ab02c4 100644
--- a/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h
+++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h
@@ -5,6 +5,7 @@
#define _MLXFW_H
#include <linux/firmware.h>
+#include <linux/netlink.h>
enum mlxfw_fsm_state {
MLXFW_FSM_STATE_IDLE,
@@ -57,6 +58,10 @@ struct mlxfw_dev_ops {
void (*fsm_cancel)(struct mlxfw_dev *mlxfw_dev, u32 fwhandle);
void (*fsm_release)(struct mlxfw_dev *mlxfw_dev, u32 fwhandle);
+
+ void (*status_notify)(struct mlxfw_dev *mlxfw_dev,
+ const char *msg, const char *comp_name,
+ u32 done_bytes, u32 total_bytes);
};
struct mlxfw_dev {
@@ -67,11 +72,13 @@ struct mlxfw_dev {
#if IS_REACHABLE(CONFIG_MLXFW)
int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev,
- const struct firmware *firmware);
+ const struct firmware *firmware,
+ struct netlink_ext_ack *extack);
#else
static inline
int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev,
- const struct firmware *firmware)
+ const struct firmware *firmware,
+ struct netlink_ext_ack *extack)
{
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c
index 240c027e5f07..67990406cba2 100644
--- a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c
+++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c
@@ -39,8 +39,19 @@ static const char * const mlxfw_fsm_state_err_str[] = {
"unknown error"
};
+static void mlxfw_status_notify(struct mlxfw_dev *mlxfw_dev,
+ const char *msg, const char *comp_name,
+ u32 done_bytes, u32 total_bytes)
+{
+ if (!mlxfw_dev->ops->status_notify)
+ return;
+ mlxfw_dev->ops->status_notify(mlxfw_dev, msg, comp_name,
+ done_bytes, total_bytes);
+}
+
static int mlxfw_fsm_state_wait(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
- enum mlxfw_fsm_state fsm_state)
+ enum mlxfw_fsm_state fsm_state,
+ struct netlink_ext_ack *extack)
{
enum mlxfw_fsm_state_err fsm_state_err;
enum mlxfw_fsm_state curr_fsm_state;
@@ -57,11 +68,13 @@ retry:
if (fsm_state_err != MLXFW_FSM_STATE_ERR_OK) {
pr_err("Firmware flash failed: %s\n",
mlxfw_fsm_state_err_str[fsm_state_err]);
+ NL_SET_ERR_MSG_MOD(extack, "Firmware flash failed");
return -EINVAL;
}
if (curr_fsm_state != fsm_state) {
if (--times == 0) {
pr_err("Timeout reached on FSM state change");
+ NL_SET_ERR_MSG_MOD(extack, "Timeout reached on FSM state change");
return -ETIMEDOUT;
}
msleep(MLXFW_FSM_STATE_WAIT_CYCLE_MS);
@@ -76,16 +89,20 @@ retry:
static int mlxfw_flash_component(struct mlxfw_dev *mlxfw_dev,
u32 fwhandle,
- struct mlxfw_mfa2_component *comp)
+ struct mlxfw_mfa2_component *comp,
+ struct netlink_ext_ack *extack)
{
u16 comp_max_write_size;
u8 comp_align_bits;
u32 comp_max_size;
+ char comp_name[8];
u16 block_size;
u8 *block_ptr;
u32 offset;
int err;
+ sprintf(comp_name, "%u", comp->index);
+
err = mlxfw_dev->ops->component_query(mlxfw_dev, comp->index,
&comp_max_size, &comp_align_bits,
&comp_max_write_size);
@@ -96,6 +113,7 @@ static int mlxfw_flash_component(struct mlxfw_dev *mlxfw_dev,
if (comp->data_size > comp_max_size) {
pr_err("Component %d is of size %d which is bigger than limit %d\n",
comp->index, comp->data_size, comp_max_size);
+ NL_SET_ERR_MSG_MOD(extack, "Component is bigger than limit");
return -EINVAL;
}
@@ -103,6 +121,7 @@ static int mlxfw_flash_component(struct mlxfw_dev *mlxfw_dev,
comp_align_bits);
pr_debug("Component update\n");
+ mlxfw_status_notify(mlxfw_dev, "Updating component", comp_name, 0, 0);
err = mlxfw_dev->ops->fsm_component_update(mlxfw_dev, fwhandle,
comp->index,
comp->data_size);
@@ -110,11 +129,13 @@ static int mlxfw_flash_component(struct mlxfw_dev *mlxfw_dev,
return err;
err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
- MLXFW_FSM_STATE_DOWNLOAD);
+ MLXFW_FSM_STATE_DOWNLOAD, extack);
if (err)
goto err_out;
pr_debug("Component download\n");
+ mlxfw_status_notify(mlxfw_dev, "Downloading component",
+ comp_name, 0, comp->data_size);
for (offset = 0;
offset < MLXFW_ALIGN_UP(comp->data_size, comp_align_bits);
offset += comp_max_write_size) {
@@ -126,15 +147,20 @@ static int mlxfw_flash_component(struct mlxfw_dev *mlxfw_dev,
offset);
if (err)
goto err_out;
+ mlxfw_status_notify(mlxfw_dev, "Downloading component",
+ comp_name, offset + block_size,
+ comp->data_size);
}
pr_debug("Component verify\n");
+ mlxfw_status_notify(mlxfw_dev, "Verifying component", comp_name, 0, 0);
err = mlxfw_dev->ops->fsm_component_verify(mlxfw_dev, fwhandle,
comp->index);
if (err)
goto err_out;
- err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle, MLXFW_FSM_STATE_LOCKED);
+ err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
+ MLXFW_FSM_STATE_LOCKED, extack);
if (err)
goto err_out;
return 0;
@@ -145,7 +171,8 @@ err_out:
}
static int mlxfw_flash_components(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
- struct mlxfw_mfa2_file *mfa2_file)
+ struct mlxfw_mfa2_file *mfa2_file,
+ struct netlink_ext_ack *extack)
{
u32 component_count;
int err;
@@ -156,6 +183,7 @@ static int mlxfw_flash_components(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
&component_count);
if (err) {
pr_err("Could not find device PSID in MFA2 file\n");
+ NL_SET_ERR_MSG_MOD(extack, "Could not find device PSID in MFA2 file");
return err;
}
@@ -168,7 +196,7 @@ static int mlxfw_flash_components(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
return PTR_ERR(comp);
pr_info("Flashing component type %d\n", comp->index);
- err = mlxfw_flash_component(mlxfw_dev, fwhandle, comp);
+ err = mlxfw_flash_component(mlxfw_dev, fwhandle, comp, extack);
mlxfw_mfa2_file_component_put(comp);
if (err)
return err;
@@ -177,7 +205,8 @@ static int mlxfw_flash_components(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
}
int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev,
- const struct firmware *firmware)
+ const struct firmware *firmware,
+ struct netlink_ext_ack *extack)
{
struct mlxfw_mfa2_file *mfa2_file;
u32 fwhandle;
@@ -185,6 +214,7 @@ int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev,
if (!mlxfw_mfa2_check(firmware)) {
pr_err("Firmware file is not MFA2\n");
+ NL_SET_ERR_MSG_MOD(extack, "Firmware file is not MFA2");
return -EINVAL;
}
@@ -193,29 +223,35 @@ int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev,
return PTR_ERR(mfa2_file);
pr_info("Initialize firmware flash process\n");
+ mlxfw_status_notify(mlxfw_dev, "Initializing firmware flash process",
+ NULL, 0, 0);
err = mlxfw_dev->ops->fsm_lock(mlxfw_dev, &fwhandle);
if (err) {
pr_err("Could not lock the firmware FSM\n");
+ NL_SET_ERR_MSG_MOD(extack, "Could not lock the firmware FSM");
goto err_fsm_lock;
}
err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
- MLXFW_FSM_STATE_LOCKED);
+ MLXFW_FSM_STATE_LOCKED, extack);
if (err)
goto err_state_wait_idle_to_locked;
- err = mlxfw_flash_components(mlxfw_dev, fwhandle, mfa2_file);
+ err = mlxfw_flash_components(mlxfw_dev, fwhandle, mfa2_file, extack);
if (err)
goto err_flash_components;
pr_debug("Activate image\n");
+ mlxfw_status_notify(mlxfw_dev, "Activating image", NULL, 0, 0);
err = mlxfw_dev->ops->fsm_activate(mlxfw_dev, fwhandle);
if (err) {
pr_err("Could not activate the downloaded image\n");
+ NL_SET_ERR_MSG_MOD(extack, "Could not activate the downloaded image");
goto err_fsm_activate;
}
- err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle, MLXFW_FSM_STATE_LOCKED);
+ err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
+ MLXFW_FSM_STATE_LOCKED, extack);
if (err)
goto err_state_wait_activate_to_locked;
@@ -223,6 +259,7 @@ int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev,
mlxfw_dev->ops->fsm_release(mlxfw_dev, fwhandle);
pr_info("Firmware flash done.\n");
+ mlxfw_status_notify(mlxfw_dev, "Firmware flash done", NULL, 0, 0);
mlxfw_mfa2_file_fini(mfa2_file);
return 0;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/Kconfig b/drivers/net/ethernet/mellanox/mlxsw/Kconfig
index 11ded0bc7d98..06c80343d9ed 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/Kconfig
+++ b/drivers/net/ethernet/mellanox/mlxsw/Kconfig
@@ -83,6 +83,8 @@ config MLXSW_SPECTRUM
select PARMAN
select OBJAGG
select MLXFW
+ imply PTP_1588_CLOCK
+ select NET_PTP_CLASSIFY if PTP_1588_CLOCK
default m
---help---
This driver supports Mellanox Technologies Spectrum Ethernet
diff --git a/drivers/net/ethernet/mellanox/mlxsw/Makefile b/drivers/net/ethernet/mellanox/mlxsw/Makefile
index c4dc72e1ce63..171b36bd8a4e 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/Makefile
+++ b/drivers/net/ethernet/mellanox/mlxsw/Makefile
@@ -31,5 +31,6 @@ mlxsw_spectrum-objs := spectrum.o spectrum_buffers.o \
spectrum_nve.o spectrum_nve_vxlan.o \
spectrum_dpipe.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
mlxsw_minimal-objs := minimal.o
diff --git a/drivers/net/ethernet/mellanox/mlxsw/cmd.h b/drivers/net/ethernet/mellanox/mlxsw/cmd.h
index 0772e4339b33..5ffdfb532cb7 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/cmd.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/cmd.h
@@ -317,6 +317,18 @@ MLXSW_ITEM64(cmd_mbox, query_fw, doorbell_page_offset, 0x40, 0, 64);
*/
MLXSW_ITEM32(cmd_mbox, query_fw, doorbell_page_bar, 0x48, 30, 2);
+/* cmd_mbox_query_fw_free_running_clock_offset
+ * The offset of the free running clock page
+ */
+MLXSW_ITEM64(cmd_mbox, query_fw, free_running_clock_offset, 0x50, 0, 64);
+
+/* cmd_mbox_query_fw_fr_rn_clk_bar
+ * PCI base address register (BAR) of the free running clock page
+ * 0: BAR 0
+ * 1: 64 bit BAR
+ */
+MLXSW_ITEM32(cmd_mbox, query_fw, fr_rn_clk_bar, 0x58, 30, 2);
+
/* QUERY_BOARDINFO - Query Board Information
* -----------------------------------------
* OpMod == 0 (N/A), INMmod == 0 (N/A)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c
index 6ee6de7f0160..17ceac7505e5 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core.c
@@ -1003,6 +1003,20 @@ static int mlxsw_devlink_core_bus_device_reload(struct devlink *devlink,
return err;
}
+static int mlxsw_devlink_flash_update(struct devlink *devlink,
+ const char *file_name,
+ const char *component,
+ struct netlink_ext_ack *extack)
+{
+ struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
+ struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
+
+ if (!mlxsw_driver->flash_update)
+ return -EOPNOTSUPP;
+ return mlxsw_driver->flash_update(mlxsw_core, file_name,
+ component, extack);
+}
+
static const struct devlink_ops mlxsw_devlink_ops = {
.reload = mlxsw_devlink_core_bus_device_reload,
.port_type_set = mlxsw_devlink_port_type_set,
@@ -1019,6 +1033,7 @@ static const struct devlink_ops mlxsw_devlink_ops = {
.sb_occ_port_pool_get = mlxsw_devlink_sb_occ_port_pool_get,
.sb_occ_tc_port_bind_get = mlxsw_devlink_sb_occ_tc_port_bind_get,
.info_get = mlxsw_devlink_info_get,
+ .flash_update = mlxsw_devlink_flash_update,
};
static int
@@ -1098,6 +1113,12 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
goto err_register_params;
}
+ if (mlxsw_driver->init) {
+ err = mlxsw_driver->init(mlxsw_core, mlxsw_bus_info);
+ if (err)
+ goto err_driver_init;
+ }
+
err = mlxsw_hwmon_init(mlxsw_core, mlxsw_bus_info, &mlxsw_core->hwmon);
if (err)
goto err_hwmon_init;
@@ -1107,22 +1128,17 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
if (err)
goto err_thermal_init;
- if (mlxsw_driver->init) {
- err = mlxsw_driver->init(mlxsw_core, mlxsw_bus_info);
- if (err)
- goto err_driver_init;
- }
-
if (mlxsw_driver->params_register && !reload)
devlink_params_publish(devlink);
return 0;
-err_driver_init:
- mlxsw_thermal_fini(mlxsw_core->thermal);
err_thermal_init:
mlxsw_hwmon_fini(mlxsw_core->hwmon);
err_hwmon_init:
+ if (mlxsw_core->driver->fini)
+ mlxsw_core->driver->fini(mlxsw_core);
+err_driver_init:
if (mlxsw_driver->params_unregister && !reload)
mlxsw_driver->params_unregister(mlxsw_core);
err_register_params:
@@ -1187,10 +1203,10 @@ void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core,
if (mlxsw_core->driver->params_unregister && !reload)
devlink_params_unpublish(devlink);
- if (mlxsw_core->driver->fini)
- mlxsw_core->driver->fini(mlxsw_core);
mlxsw_thermal_fini(mlxsw_core->thermal);
mlxsw_hwmon_fini(mlxsw_core->hwmon);
+ if (mlxsw_core->driver->fini)
+ mlxsw_core->driver->fini(mlxsw_core);
if (mlxsw_core->driver->params_unregister && !reload)
mlxsw_core->driver->params_unregister(mlxsw_core);
if (!reload)
@@ -1229,6 +1245,15 @@ int mlxsw_core_skb_transmit(struct mlxsw_core *mlxsw_core, struct sk_buff *skb,
}
EXPORT_SYMBOL(mlxsw_core_skb_transmit);
+void mlxsw_core_ptp_transmitted(struct mlxsw_core *mlxsw_core,
+ struct sk_buff *skb, u8 local_port)
+{
+ if (mlxsw_core->driver->ptp_transmitted)
+ mlxsw_core->driver->ptp_transmitted(mlxsw_core, skb,
+ local_port);
+}
+EXPORT_SYMBOL(mlxsw_core_ptp_transmitted);
+
static bool __is_rx_listener_equal(const struct mlxsw_rx_listener *rxl_a,
const struct mlxsw_rx_listener *rxl_b)
{
@@ -2010,6 +2035,18 @@ int mlxsw_core_resources_query(struct mlxsw_core *mlxsw_core, char *mbox,
}
EXPORT_SYMBOL(mlxsw_core_resources_query);
+u32 mlxsw_core_read_frc_h(struct mlxsw_core *mlxsw_core)
+{
+ return mlxsw_core->bus->read_frc_h(mlxsw_core->bus_priv);
+}
+EXPORT_SYMBOL(mlxsw_core_read_frc_h);
+
+u32 mlxsw_core_read_frc_l(struct mlxsw_core *mlxsw_core)
+{
+ return mlxsw_core->bus->read_frc_l(mlxsw_core->bus_priv);
+}
+EXPORT_SYMBOL(mlxsw_core_read_frc_l);
+
static int __init mlxsw_core_module_init(void)
{
int err;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h
index e3832cb5bdda..8efcff4b59cb 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/core.h
@@ -48,6 +48,8 @@ bool mlxsw_core_skb_transmit_busy(struct mlxsw_core *mlxsw_core,
const struct mlxsw_tx_info *tx_info);
int mlxsw_core_skb_transmit(struct mlxsw_core *mlxsw_core, struct sk_buff *skb,
const struct mlxsw_tx_info *tx_info);
+void mlxsw_core_ptp_transmitted(struct mlxsw_core *mlxsw_core,
+ struct sk_buff *skb, u8 local_port);
struct mlxsw_rx_listener {
void (*func)(struct sk_buff *skb, u8 local_port, void *priv);
@@ -284,6 +286,9 @@ struct mlxsw_driver {
unsigned int sb_index, u16 tc_index,
enum devlink_sb_pool_type pool_type,
u32 *p_cur, u32 *p_max);
+ int (*flash_update)(struct mlxsw_core *mlxsw_core,
+ const char *file_name, const char *component,
+ struct netlink_ext_ack *extack);
void (*txhdr_construct)(struct sk_buff *skb,
const struct mlxsw_tx_info *tx_info);
int (*resources_register)(struct mlxsw_core *mlxsw_core);
@@ -293,6 +298,13 @@ struct mlxsw_driver {
u64 *p_linear_size);
int (*params_register)(struct mlxsw_core *mlxsw_core);
void (*params_unregister)(struct mlxsw_core *mlxsw_core);
+
+ /* Notify a driver that a timestamped packet was transmitted. Driver
+ * is responsible for freeing the passed-in SKB.
+ */
+ void (*ptp_transmitted)(struct mlxsw_core *mlxsw_core,
+ struct sk_buff *skb, u8 local_port);
+
u8 txhdr_len;
const struct mlxsw_config_profile *profile;
bool res_query_enabled;
@@ -306,6 +318,9 @@ int mlxsw_core_kvd_sizes_get(struct mlxsw_core *mlxsw_core,
void mlxsw_core_fw_flash_start(struct mlxsw_core *mlxsw_core);
void mlxsw_core_fw_flash_end(struct mlxsw_core *mlxsw_core);
+u32 mlxsw_core_read_frc_h(struct mlxsw_core *mlxsw_core);
+u32 mlxsw_core_read_frc_l(struct mlxsw_core *mlxsw_core);
+
bool mlxsw_core_res_valid(struct mlxsw_core *mlxsw_core,
enum mlxsw_res_id res_id);
@@ -336,6 +351,8 @@ struct mlxsw_bus {
char *in_mbox, size_t in_mbox_size,
char *out_mbox, size_t out_mbox_size,
u8 *p_status);
+ u32 (*read_frc_h)(void *bus_priv);
+ u32 (*read_frc_l)(void *bus_priv);
u8 features;
};
@@ -353,7 +370,8 @@ struct mlxsw_bus_info {
struct mlxsw_fw_rev fw_rev;
u8 vsd[MLXSW_CMD_BOARDINFO_VSD_LEN];
u8 psid[MLXSW_CMD_BOARDINFO_PSID_LEN];
- u8 low_frequency;
+ u8 low_frequency:1,
+ read_frc_capable:1;
};
struct mlxsw_hwmon;
@@ -409,4 +427,14 @@ enum mlxsw_devlink_param_id {
MLXSW_DEVLINK_PARAM_ID_ACL_REGION_REHASH_INTERVAL,
};
+struct mlxsw_skb_cb {
+ struct mlxsw_tx_info tx_info;
+};
+
+static inline struct mlxsw_skb_cb *mlxsw_skb_cb(struct sk_buff *skb)
+{
+ BUILD_BUG_ON(sizeof(mlxsw_skb_cb) > sizeof(skb->cb));
+ return (struct mlxsw_skb_cb *) skb->cb;
+}
+
#endif
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 cb3e663b1d37..feb4672a5ac0 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c
@@ -30,8 +30,9 @@ static bool mlxsw_afk_blocks_check(struct mlxsw_afk *mlxsw_afk)
elinst = &block->instances[j];
if (elinst->type != elinst->info->type ||
- elinst->item.size.bits !=
- elinst->info->item.size.bits)
+ (!elinst->avoid_size_check &&
+ elinst->item.size.bits !=
+ elinst->info->item.size.bits))
return false;
}
}
@@ -385,12 +386,12 @@ EXPORT_SYMBOL(mlxsw_afk_values_add_buf);
static void mlxsw_sp_afk_encode_u32(const struct mlxsw_item *storage_item,
const struct mlxsw_item *output_item,
- char *storage, char *output)
+ char *storage, char *output, int diff)
{
u32 value;
value = __mlxsw_item_get32(storage, storage_item, 0);
- __mlxsw_item_set32(output, output_item, 0, value);
+ __mlxsw_item_set32(output, output_item, 0, value + diff);
}
static void mlxsw_sp_afk_encode_buf(const struct mlxsw_item *storage_item,
@@ -406,14 +407,14 @@ static void mlxsw_sp_afk_encode_buf(const struct mlxsw_item *storage_item,
static void
mlxsw_sp_afk_encode_one(const struct mlxsw_afk_element_inst *elinst,
- char *output, char *storage)
+ char *output, char *storage, int u32_diff)
{
const struct mlxsw_item *storage_item = &elinst->info->item;
const struct mlxsw_item *output_item = &elinst->item;
if (elinst->type == MLXSW_AFK_ELEMENT_TYPE_U32)
mlxsw_sp_afk_encode_u32(storage_item, output_item,
- storage, output);
+ storage, output, u32_diff);
else if (elinst->type == MLXSW_AFK_ELEMENT_TYPE_BUF)
mlxsw_sp_afk_encode_buf(storage_item, output_item,
storage, output);
@@ -446,9 +447,10 @@ void mlxsw_afk_encode(struct mlxsw_afk *mlxsw_afk,
continue;
mlxsw_sp_afk_encode_one(elinst, block_key,
- values->storage.key);
+ values->storage.key,
+ elinst->u32_key_diff);
mlxsw_sp_afk_encode_one(elinst, block_mask,
- values->storage.mask);
+ values->storage.mask, 0);
}
mlxsw_afk->ops->encode_block(key, i, block_key);
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 4a625cdf3e7c..cb229b55ecc4 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h
@@ -74,7 +74,7 @@ struct mlxsw_afk_element_info {
* define an internal storage geometry.
*/
static const struct mlxsw_afk_element_info mlxsw_afk_element_infos[] = {
- MLXSW_AFK_ELEMENT_INFO_U32(SRC_SYS_PORT, 0x00, 16, 8),
+ MLXSW_AFK_ELEMENT_INFO_U32(SRC_SYS_PORT, 0x00, 16, 16),
MLXSW_AFK_ELEMENT_INFO_BUF(DMAC_32_47, 0x04, 2),
MLXSW_AFK_ELEMENT_INFO_BUF(DMAC_0_31, 0x06, 4),
MLXSW_AFK_ELEMENT_INFO_BUF(SMAC_32_47, 0x0A, 2),
@@ -107,9 +107,14 @@ struct mlxsw_afk_element_inst { /* element instance in actual block */
const struct mlxsw_afk_element_info *info;
enum mlxsw_afk_element_type type;
struct mlxsw_item item; /* element geometry in block */
+ int u32_key_diff; /* in case value needs to be adjusted before write
+ * this diff is here to handle that
+ */
+ bool avoid_size_check;
};
-#define MLXSW_AFK_ELEMENT_INST(_type, _element, _offset, _shift, _size) \
+#define MLXSW_AFK_ELEMENT_INST(_type, _element, _offset, \
+ _shift, _size, _u32_key_diff, _avoid_size_check) \
{ \
.info = &mlxsw_afk_element_infos[MLXSW_AFK_ELEMENT_##_element], \
.type = _type, \
@@ -119,15 +124,24 @@ struct mlxsw_afk_element_inst { /* element instance in actual block */
.size = {.bits = _size}, \
.name = #_element, \
}, \
+ .u32_key_diff = _u32_key_diff, \
+ .avoid_size_check = _avoid_size_check, \
}
#define MLXSW_AFK_ELEMENT_INST_U32(_element, _offset, _shift, _size) \
MLXSW_AFK_ELEMENT_INST(MLXSW_AFK_ELEMENT_TYPE_U32, \
- _element, _offset, _shift, _size)
+ _element, _offset, _shift, _size, 0, false)
+
+#define MLXSW_AFK_ELEMENT_INST_EXT_U32(_element, _offset, \
+ _shift, _size, _key_diff, \
+ _avoid_size_check) \
+ MLXSW_AFK_ELEMENT_INST(MLXSW_AFK_ELEMENT_TYPE_U32, \
+ _element, _offset, _shift, _size, \
+ _key_diff, _avoid_size_check)
#define MLXSW_AFK_ELEMENT_INST_BUF(_element, _offset, _size) \
MLXSW_AFK_ELEMENT_INST(MLXSW_AFK_ELEMENT_TYPE_BUF, \
- _element, _offset, 0, _size)
+ _element, _offset, 0, _size, 0, false)
struct mlxsw_afk_block {
u16 encoding; /* block ID */
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c
index 72539a9a3847..d2c7ce67c300 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c
@@ -92,33 +92,20 @@ int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module,
u16 temp;
} temp_thresh;
char mcia_pl[MLXSW_REG_MCIA_LEN] = {0};
- char mtbr_pl[MLXSW_REG_MTBR_LEN] = {0};
- u16 module_temp;
+ char mtmp_pl[MLXSW_REG_MTMP_LEN];
+ unsigned int module_temp;
bool qsfp;
int err;
- mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module,
- 1);
- err = mlxsw_reg_query(core, MLXSW_REG(mtbr), mtbr_pl);
+ mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTMP_MODULE_INDEX_MIN + module,
+ false, false);
+ err = mlxsw_reg_query(core, MLXSW_REG(mtmp), mtmp_pl);
if (err)
return err;
-
- /* Don't read temperature thresholds for module with no valid info. */
- mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &module_temp, NULL);
- switch (module_temp) {
- case MLXSW_REG_MTBR_BAD_SENS_INFO: /* fall-through */
- case MLXSW_REG_MTBR_NO_CONN: /* fall-through */
- case MLXSW_REG_MTBR_NO_TEMP_SENS: /* fall-through */
- case MLXSW_REG_MTBR_INDEX_NA:
+ mlxsw_reg_mtmp_unpack(mtmp_pl, &module_temp, NULL, NULL);
+ if (!module_temp) {
*temp = 0;
return 0;
- default:
- /* Do not consider thresholds for zero temperature. */
- if (MLXSW_REG_MTMP_TEMP_TO_MC(module_temp) == 0) {
- *temp = 0;
- return 0;
- }
- break;
}
/* Read Free Side Device Temperature Thresholds from page 03h
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c
index 496dc904c5ed..5b00726c4346 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c
@@ -23,6 +23,14 @@ struct mlxsw_hwmon_attr {
char name[32];
};
+static int mlxsw_hwmon_get_attr_index(int index, int count)
+{
+ if (index >= count)
+ return index % count + MLXSW_REG_MTMP_GBOX_INDEX_MIN;
+
+ return index;
+}
+
struct mlxsw_hwmon {
struct mlxsw_core *core;
const struct mlxsw_bus_info *bus_info;
@@ -33,6 +41,7 @@ struct mlxsw_hwmon {
struct mlxsw_hwmon_attr hwmon_attrs[MLXSW_HWMON_ATTR_COUNT];
unsigned int attrs_count;
u8 sensor_count;
+ u8 module_sensor_count;
};
static ssize_t mlxsw_hwmon_temp_show(struct device *dev,
@@ -43,18 +52,19 @@ static ssize_t mlxsw_hwmon_temp_show(struct device *dev,
container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
char mtmp_pl[MLXSW_REG_MTMP_LEN];
- unsigned int temp;
+ int temp, index;
int err;
- mlxsw_reg_mtmp_pack(mtmp_pl, mlwsw_hwmon_attr->type_index,
- false, false);
+ index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index,
+ mlxsw_hwmon->module_sensor_count);
+ mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false);
err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl);
if (err) {
dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query temp sensor\n");
return err;
}
mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL);
- return sprintf(buf, "%u\n", temp);
+ return sprintf(buf, "%d\n", temp);
}
static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev,
@@ -65,18 +75,19 @@ static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev,
container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
char mtmp_pl[MLXSW_REG_MTMP_LEN];
- unsigned int temp_max;
+ int temp_max, index;
int err;
- mlxsw_reg_mtmp_pack(mtmp_pl, mlwsw_hwmon_attr->type_index,
- false, false);
+ index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index,
+ mlxsw_hwmon->module_sensor_count);
+ mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false);
err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl);
if (err) {
dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query temp sensor\n");
return err;
}
mlxsw_reg_mtmp_unpack(mtmp_pl, NULL, &temp_max, NULL);
- return sprintf(buf, "%u\n", temp_max);
+ return sprintf(buf, "%d\n", temp_max);
}
static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev,
@@ -88,6 +99,7 @@ static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev,
struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
char mtmp_pl[MLXSW_REG_MTMP_LEN];
unsigned long val;
+ int index;
int err;
err = kstrtoul(buf, 10, &val);
@@ -96,7 +108,9 @@ static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev,
if (val != 1)
return -EINVAL;
- mlxsw_reg_mtmp_pack(mtmp_pl, mlwsw_hwmon_attr->type_index, true, true);
+ index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index,
+ mlxsw_hwmon->module_sensor_count);
+ mlxsw_reg_mtmp_pack(mtmp_pl, index, true, true);
err = mlxsw_reg_write(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl);
if (err) {
dev_err(mlxsw_hwmon->bus_info->dev, "Failed to reset temp sensor history\n");
@@ -198,40 +212,20 @@ static ssize_t mlxsw_hwmon_module_temp_show(struct device *dev,
struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
- char mtbr_pl[MLXSW_REG_MTBR_LEN] = {0};
- u16 temp;
+ char mtmp_pl[MLXSW_REG_MTMP_LEN];
u8 module;
+ int temp;
int err;
module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count;
- mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module,
- 1);
- err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtbr), mtbr_pl);
- if (err) {
- dev_err(dev, "Failed to query module temperature sensor\n");
+ mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTMP_MODULE_INDEX_MIN + module,
+ false, false);
+ err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl);
+ if (err)
return err;
- }
-
- mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL);
- /* Update status and temperature cache. */
- switch (temp) {
- case MLXSW_REG_MTBR_NO_CONN: /* fall-through */
- case MLXSW_REG_MTBR_NO_TEMP_SENS: /* fall-through */
- case MLXSW_REG_MTBR_INDEX_NA:
- temp = 0;
- break;
- case MLXSW_REG_MTBR_BAD_SENS_INFO:
- /* Untrusted cable is connected. Reading temperature from its
- * sensor is faulty.
- */
- temp = 0;
- break;
- default:
- temp = MLXSW_REG_MTMP_TEMP_TO_MC(temp);
- break;
- }
+ mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL);
- return sprintf(buf, "%u\n", temp);
+ return sprintf(buf, "%d\n", temp);
}
static ssize_t mlxsw_hwmon_module_temp_fault_show(struct device *dev,
@@ -333,6 +327,20 @@ mlxsw_hwmon_module_temp_label_show(struct device *dev,
mlwsw_hwmon_attr->type_index);
}
+static ssize_t
+mlxsw_hwmon_gbox_temp_label_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
+ container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
+ struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
+ int index = mlwsw_hwmon_attr->type_index -
+ mlxsw_hwmon->module_sensor_count + 1;
+
+ return sprintf(buf, "gearbox %03u\n", index);
+}
+
enum mlxsw_hwmon_attr_type {
MLXSW_HWMON_ATTR_TYPE_TEMP,
MLXSW_HWMON_ATTR_TYPE_TEMP_MAX,
@@ -345,6 +353,7 @@ enum mlxsw_hwmon_attr_type {
MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT,
MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG,
MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_LABEL,
+ MLXSW_HWMON_ATTR_TYPE_TEMP_GBOX_LABEL,
};
static void mlxsw_hwmon_attr_add(struct mlxsw_hwmon *mlxsw_hwmon,
@@ -428,6 +437,13 @@ static void mlxsw_hwmon_attr_add(struct mlxsw_hwmon *mlxsw_hwmon,
snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
"temp%u_label", num + 1);
break;
+ case MLXSW_HWMON_ATTR_TYPE_TEMP_GBOX_LABEL:
+ mlxsw_hwmon_attr->dev_attr.show =
+ mlxsw_hwmon_gbox_temp_label_show;
+ mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
+ snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
+ "temp%u_label", num + 1);
+ break;
default:
WARN_ON(1);
}
@@ -556,6 +572,54 @@ static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon)
index, index);
index++;
}
+ mlxsw_hwmon->module_sensor_count = index;
+
+ return 0;
+}
+
+static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon)
+{
+ int index, max_index, sensor_index;
+ char mgpir_pl[MLXSW_REG_MGPIR_LEN];
+ char mtmp_pl[MLXSW_REG_MTMP_LEN];
+ u8 gbox_num;
+ int err;
+
+ mlxsw_reg_mgpir_pack(mgpir_pl);
+ err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mgpir), mgpir_pl);
+ if (err)
+ return err;
+
+ mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, NULL, NULL);
+ if (!gbox_num)
+ return 0;
+
+ index = mlxsw_hwmon->module_sensor_count;
+ max_index = mlxsw_hwmon->module_sensor_count + gbox_num;
+ while (index < max_index) {
+ sensor_index = index % mlxsw_hwmon->module_sensor_count +
+ MLXSW_REG_MTMP_GBOX_INDEX_MIN;
+ mlxsw_reg_mtmp_pack(mtmp_pl, sensor_index, true, true);
+ err = mlxsw_reg_write(mlxsw_hwmon->core,
+ MLXSW_REG(mtmp), mtmp_pl);
+ if (err) {
+ dev_err(mlxsw_hwmon->bus_info->dev, "Failed to setup temp sensor number %d\n",
+ sensor_index);
+ return err;
+ }
+ mlxsw_hwmon_attr_add(mlxsw_hwmon, MLXSW_HWMON_ATTR_TYPE_TEMP,
+ index, index);
+ mlxsw_hwmon_attr_add(mlxsw_hwmon,
+ MLXSW_HWMON_ATTR_TYPE_TEMP_MAX, index,
+ index);
+ mlxsw_hwmon_attr_add(mlxsw_hwmon,
+ MLXSW_HWMON_ATTR_TYPE_TEMP_RST, index,
+ index);
+ mlxsw_hwmon_attr_add(mlxsw_hwmon,
+ MLXSW_HWMON_ATTR_TYPE_TEMP_GBOX_LABEL,
+ index, index);
+ index++;
+ }
return 0;
}
@@ -586,6 +650,10 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core,
if (err)
goto err_temp_module_init;
+ err = mlxsw_hwmon_gearbox_init(mlxsw_hwmon);
+ if (err)
+ goto err_temp_gearbox_init;
+
mlxsw_hwmon->groups[0] = &mlxsw_hwmon->group;
mlxsw_hwmon->group.attrs = mlxsw_hwmon->attrs;
@@ -602,6 +670,7 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core,
return 0;
err_hwmon_register:
+err_temp_gearbox_init:
err_temp_module_init:
err_fans_init:
err_temp_init:
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
index d3e851e7ca72..35a1dc89c28a 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
@@ -23,6 +23,7 @@
#define MLXSW_THERMAL_HYSTERESIS_TEMP 5000 /* 5C */
#define MLXSW_THERMAL_MODULE_TEMP_SHIFT (MLXSW_THERMAL_HYSTERESIS_TEMP * 2)
#define MLXSW_THERMAL_ZONE_MAX_NAME 16
+#define MLXSW_THERMAL_TEMP_SCORE_MAX GENMASK(31, 0)
#define MLXSW_THERMAL_MAX_STATE 10
#define MLXSW_THERMAL_MAX_DUTY 255
/* Minimum and maximum fan allowed speed in percent: from 20% to 100%. Values
@@ -98,7 +99,7 @@ struct mlxsw_thermal_module {
struct thermal_zone_device *tzdev;
struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
enum thermal_device_mode mode;
- int module;
+ int module; /* Module or gearbox number */
};
struct mlxsw_thermal {
@@ -111,6 +112,10 @@ struct mlxsw_thermal {
struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
enum thermal_device_mode mode;
struct mlxsw_thermal_module *tz_module_arr;
+ struct mlxsw_thermal_module *tz_gearbox_arr;
+ u8 tz_gearbox_num;
+ unsigned int tz_highest_score;
+ struct thermal_zone_device *tz_highest_dev;
};
static inline u8 mlxsw_state_to_duty(int state)
@@ -195,6 +200,34 @@ mlxsw_thermal_module_trips_update(struct device *dev, struct mlxsw_core *core,
return 0;
}
+static void mlxsw_thermal_tz_score_update(struct mlxsw_thermal *thermal,
+ struct thermal_zone_device *tzdev,
+ struct mlxsw_thermal_trip *trips,
+ int temp)
+{
+ struct mlxsw_thermal_trip *trip = trips;
+ unsigned int score, delta, i, shift = 1;
+
+ /* Calculate thermal zone score, if temperature is above the critical
+ * threshold score is set to MLXSW_THERMAL_TEMP_SCORE_MAX.
+ */
+ score = MLXSW_THERMAL_TEMP_SCORE_MAX;
+ for (i = MLXSW_THERMAL_TEMP_TRIP_NORM; i < MLXSW_THERMAL_NUM_TRIPS;
+ i++, trip++) {
+ if (temp < trip->temp) {
+ delta = DIV_ROUND_CLOSEST(temp, trip->temp - temp);
+ score = delta * shift;
+ break;
+ }
+ shift *= 256;
+ }
+
+ if (score > thermal->tz_highest_score) {
+ thermal->tz_highest_score = score;
+ thermal->tz_highest_dev = tzdev;
+ }
+}
+
static int mlxsw_thermal_bind(struct thermal_zone_device *tzdev,
struct thermal_cooling_device *cdev)
{
@@ -279,7 +312,7 @@ static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev,
struct mlxsw_thermal *thermal = tzdev->devdata;
struct device *dev = thermal->bus_info->dev;
char mtmp_pl[MLXSW_REG_MTMP_LEN];
- unsigned int temp;
+ int temp;
int err;
mlxsw_reg_mtmp_pack(mtmp_pl, 0, false, false);
@@ -290,8 +323,11 @@ static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev,
return err;
}
mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL);
+ if (temp > 0)
+ mlxsw_thermal_tz_score_update(thermal, tzdev, thermal->trips,
+ temp);
- *p_temp = (int) temp;
+ *p_temp = temp;
return 0;
}
@@ -351,6 +387,22 @@ static int mlxsw_thermal_set_trip_hyst(struct thermal_zone_device *tzdev,
return 0;
}
+static int mlxsw_thermal_trend_get(struct thermal_zone_device *tzdev,
+ int trip, enum thermal_trend *trend)
+{
+ struct mlxsw_thermal_module *tz = tzdev->devdata;
+ struct mlxsw_thermal *thermal = tz->parent;
+
+ if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS)
+ return -EINVAL;
+
+ if (tzdev == thermal->tz_highest_dev)
+ return 1;
+
+ *trend = THERMAL_TREND_STABLE;
+ return 0;
+}
+
static struct thermal_zone_device_ops mlxsw_thermal_ops = {
.bind = mlxsw_thermal_bind,
.unbind = mlxsw_thermal_unbind,
@@ -362,6 +414,7 @@ static struct thermal_zone_device_ops mlxsw_thermal_ops = {
.set_trip_temp = mlxsw_thermal_set_trip_temp,
.get_trip_hyst = mlxsw_thermal_get_trip_hyst,
.set_trip_hyst = mlxsw_thermal_set_trip_hyst,
+ .get_trend = mlxsw_thermal_trend_get,
};
static int mlxsw_thermal_module_bind(struct thermal_zone_device *tzdev,
@@ -449,39 +502,33 @@ static int mlxsw_thermal_module_temp_get(struct thermal_zone_device *tzdev,
struct mlxsw_thermal_module *tz = tzdev->devdata;
struct mlxsw_thermal *thermal = tz->parent;
struct device *dev = thermal->bus_info->dev;
- char mtbr_pl[MLXSW_REG_MTBR_LEN];
- u16 temp;
+ char mtmp_pl[MLXSW_REG_MTMP_LEN];
+ int temp;
int err;
/* Read module temperature. */
- mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX +
- tz->module, 1);
- err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtbr), mtbr_pl);
- if (err)
- return err;
-
- mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL);
- /* Update temperature. */
- switch (temp) {
- case MLXSW_REG_MTBR_NO_CONN: /* fall-through */
- case MLXSW_REG_MTBR_NO_TEMP_SENS: /* fall-through */
- case MLXSW_REG_MTBR_INDEX_NA: /* fall-through */
- case MLXSW_REG_MTBR_BAD_SENS_INFO:
+ mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTMP_MODULE_INDEX_MIN +
+ tz->module, false, false);
+ err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl);
+ if (err) {
+ /* Do not return error - in case of broken module's sensor
+ * it will cause error message flooding.
+ */
temp = 0;
- break;
- default:
- temp = MLXSW_REG_MTMP_TEMP_TO_MC(temp);
- /* Reset all trip point. */
- mlxsw_thermal_module_trips_reset(tz);
- /* Update trip points. */
- err = mlxsw_thermal_module_trips_update(dev, thermal->core,
- tz);
- if (err)
- return err;
- break;
+ *p_temp = (int) temp;
+ return 0;
}
+ mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL);
+ *p_temp = temp;
+
+ if (!temp)
+ return 0;
+
+ /* Update trip points. */
+ err = mlxsw_thermal_module_trips_update(dev, thermal->core, tz);
+ if (!err && temp > 0)
+ mlxsw_thermal_tz_score_update(thermal, tzdev, tz->trips, temp);
- *p_temp = (int) temp;
return 0;
}
@@ -545,10 +592,6 @@ mlxsw_thermal_module_trip_hyst_set(struct thermal_zone_device *tzdev, int trip,
return 0;
}
-static struct thermal_zone_params mlxsw_thermal_module_params = {
- .governor_name = "user_space",
-};
-
static struct thermal_zone_device_ops mlxsw_thermal_module_ops = {
.bind = mlxsw_thermal_module_bind,
.unbind = mlxsw_thermal_module_unbind,
@@ -560,6 +603,46 @@ static struct thermal_zone_device_ops mlxsw_thermal_module_ops = {
.set_trip_temp = mlxsw_thermal_module_trip_temp_set,
.get_trip_hyst = mlxsw_thermal_module_trip_hyst_get,
.set_trip_hyst = mlxsw_thermal_module_trip_hyst_set,
+ .get_trend = mlxsw_thermal_trend_get,
+};
+
+static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev,
+ int *p_temp)
+{
+ struct mlxsw_thermal_module *tz = tzdev->devdata;
+ struct mlxsw_thermal *thermal = tz->parent;
+ char mtmp_pl[MLXSW_REG_MTMP_LEN];
+ u16 index;
+ int temp;
+ int err;
+
+ index = MLXSW_REG_MTMP_GBOX_INDEX_MIN + tz->module;
+ mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false);
+
+ err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl);
+ if (err)
+ return err;
+
+ mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL);
+ if (temp > 0)
+ mlxsw_thermal_tz_score_update(thermal, tzdev, tz->trips, temp);
+
+ *p_temp = temp;
+ return 0;
+}
+
+static struct thermal_zone_device_ops mlxsw_thermal_gearbox_ops = {
+ .bind = mlxsw_thermal_module_bind,
+ .unbind = mlxsw_thermal_module_unbind,
+ .get_mode = mlxsw_thermal_module_mode_get,
+ .set_mode = mlxsw_thermal_module_mode_set,
+ .get_temp = mlxsw_thermal_gearbox_temp_get,
+ .get_trip_type = mlxsw_thermal_module_trip_type_get,
+ .get_trip_temp = mlxsw_thermal_module_trip_temp_get,
+ .set_trip_temp = mlxsw_thermal_module_trip_temp_set,
+ .get_trip_hyst = mlxsw_thermal_module_trip_hyst_get,
+ .set_trip_hyst = mlxsw_thermal_module_trip_hyst_set,
+ .get_trend = mlxsw_thermal_trend_get,
};
static int mlxsw_thermal_get_max_state(struct thermal_cooling_device *cdev,
@@ -675,13 +758,13 @@ mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz)
MLXSW_THERMAL_TRIP_MASK,
module_tz,
&mlxsw_thermal_module_ops,
- &mlxsw_thermal_module_params,
- 0, 0);
+ NULL, 0, 0);
if (IS_ERR(module_tz->tzdev)) {
err = PTR_ERR(module_tz->tzdev);
return err;
}
+ module_tz->mode = THERMAL_DEVICE_ENABLED;
return 0;
}
@@ -787,6 +870,92 @@ mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal)
kfree(thermal->tz_module_arr);
}
+static int
+mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz)
+{
+ char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME];
+
+ snprintf(tz_name, sizeof(tz_name), "mlxsw-gearbox%d",
+ gearbox_tz->module + 1);
+ gearbox_tz->tzdev = thermal_zone_device_register(tz_name,
+ MLXSW_THERMAL_NUM_TRIPS,
+ MLXSW_THERMAL_TRIP_MASK,
+ gearbox_tz,
+ &mlxsw_thermal_gearbox_ops,
+ NULL, 0, 0);
+ if (IS_ERR(gearbox_tz->tzdev))
+ return PTR_ERR(gearbox_tz->tzdev);
+
+ gearbox_tz->mode = THERMAL_DEVICE_ENABLED;
+ return 0;
+}
+
+static void
+mlxsw_thermal_gearbox_tz_fini(struct mlxsw_thermal_module *gearbox_tz)
+{
+ thermal_zone_device_unregister(gearbox_tz->tzdev);
+}
+
+static int
+mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core,
+ struct mlxsw_thermal *thermal)
+{
+ struct mlxsw_thermal_module *gearbox_tz;
+ char mgpir_pl[MLXSW_REG_MGPIR_LEN];
+ int i;
+ int err;
+
+ if (!mlxsw_core_res_query_enabled(core))
+ return 0;
+
+ mlxsw_reg_mgpir_pack(mgpir_pl);
+ err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl);
+ if (err)
+ return err;
+
+ mlxsw_reg_mgpir_unpack(mgpir_pl, &thermal->tz_gearbox_num, NULL, NULL);
+ if (!thermal->tz_gearbox_num)
+ return 0;
+
+ thermal->tz_gearbox_arr = kcalloc(thermal->tz_gearbox_num,
+ sizeof(*thermal->tz_gearbox_arr),
+ GFP_KERNEL);
+ if (!thermal->tz_gearbox_arr)
+ return -ENOMEM;
+
+ for (i = 0; i < thermal->tz_gearbox_num; i++) {
+ gearbox_tz = &thermal->tz_gearbox_arr[i];
+ memcpy(gearbox_tz->trips, default_thermal_trips,
+ sizeof(thermal->trips));
+ gearbox_tz->module = i;
+ gearbox_tz->parent = thermal;
+ err = mlxsw_thermal_gearbox_tz_init(gearbox_tz);
+ if (err)
+ goto err_unreg_tz_gearbox;
+ }
+
+ return 0;
+
+err_unreg_tz_gearbox:
+ for (i--; i >= 0; i--)
+ mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]);
+ kfree(thermal->tz_gearbox_arr);
+ return err;
+}
+
+static void
+mlxsw_thermal_gearboxes_fini(struct mlxsw_thermal *thermal)
+{
+ int i;
+
+ if (!mlxsw_core_res_query_enabled(thermal->core))
+ return;
+
+ for (i = thermal->tz_gearbox_num - 1; i >= 0; i--)
+ mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]);
+ kfree(thermal->tz_gearbox_arr);
+}
+
int mlxsw_thermal_init(struct mlxsw_core *core,
const struct mlxsw_bus_info *bus_info,
struct mlxsw_thermal **p_thermal)
@@ -877,10 +1046,16 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
if (err)
goto err_unreg_tzdev;
+ err = mlxsw_thermal_gearboxes_init(dev, core, thermal);
+ if (err)
+ goto err_unreg_modules_tzdev;
+
thermal->mode = THERMAL_DEVICE_ENABLED;
*p_thermal = thermal;
return 0;
+err_unreg_modules_tzdev:
+ mlxsw_thermal_modules_fini(thermal);
err_unreg_tzdev:
if (thermal->tzdev) {
thermal_zone_device_unregister(thermal->tzdev);
@@ -899,6 +1074,7 @@ void mlxsw_thermal_fini(struct mlxsw_thermal *thermal)
{
int i;
+ mlxsw_thermal_gearboxes_fini(thermal);
mlxsw_thermal_modules_fini(thermal);
if (thermal->tzdev) {
thermal_zone_device_unregister(thermal->tzdev);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/i2c.c b/drivers/net/ethernet/mellanox/mlxsw/i2c.c
index 06aea1999518..95f408d0e103 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/i2c.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/i2c.c
@@ -43,11 +43,10 @@
#define MLXSW_I2C_PREP_SIZE (MLXSW_I2C_ADDR_WIDTH + 28)
#define MLXSW_I2C_MBOX_SIZE 20
#define MLXSW_I2C_MBOX_OUT_PARAM_OFF 12
-#define MLXSW_I2C_MAX_BUFF_SIZE 32
#define MLXSW_I2C_MBOX_OFFSET_BITS 20
#define MLXSW_I2C_MBOX_SIZE_BITS 12
#define MLXSW_I2C_ADDR_BUF_SIZE 4
-#define MLXSW_I2C_BLK_MAX 32
+#define MLXSW_I2C_BLK_DEF 32
#define MLXSW_I2C_RETRY 5
#define MLXSW_I2C_TIMEOUT_MSECS 5000
#define MLXSW_I2C_MAX_DATA_SIZE 256
@@ -62,6 +61,7 @@
* @dev: I2C device;
* @core: switch core pointer;
* @bus_info: bus info block;
+ * @block_size: maximum block size allowed to pass to under layer;
*/
struct mlxsw_i2c {
struct {
@@ -74,6 +74,7 @@ struct mlxsw_i2c {
struct device *dev;
struct mlxsw_core *core;
struct mlxsw_bus_info bus_info;
+ u16 block_size;
};
#define MLXSW_I2C_READ_MSG(_client, _addr_buf, _buf, _len) { \
@@ -315,20 +316,26 @@ mlxsw_i2c_write(struct device *dev, size_t in_mbox_size, u8 *in_mbox, int num,
struct i2c_client *client = to_i2c_client(dev);
struct mlxsw_i2c *mlxsw_i2c = i2c_get_clientdata(client);
unsigned long timeout = msecs_to_jiffies(MLXSW_I2C_TIMEOUT_MSECS);
- u8 tran_buf[MLXSW_I2C_MAX_BUFF_SIZE + MLXSW_I2C_ADDR_BUF_SIZE];
int off = mlxsw_i2c->cmd.mb_off_in, chunk_size, i, j;
unsigned long end;
+ u8 *tran_buf;
struct i2c_msg write_tran =
- MLXSW_I2C_WRITE_MSG(client, tran_buf, MLXSW_I2C_PUSH_CMD_SIZE);
+ MLXSW_I2C_WRITE_MSG(client, NULL, MLXSW_I2C_PUSH_CMD_SIZE);
int err;
+ tran_buf = kmalloc(mlxsw_i2c->block_size + MLXSW_I2C_ADDR_BUF_SIZE,
+ GFP_KERNEL);
+ if (!tran_buf)
+ return -ENOMEM;
+
+ write_tran.buf = tran_buf;
for (i = 0; i < num; i++) {
- chunk_size = (in_mbox_size > MLXSW_I2C_BLK_MAX) ?
- MLXSW_I2C_BLK_MAX : in_mbox_size;
+ chunk_size = (in_mbox_size > mlxsw_i2c->block_size) ?
+ mlxsw_i2c->block_size : in_mbox_size;
write_tran.len = MLXSW_I2C_ADDR_WIDTH + chunk_size;
mlxsw_i2c_set_slave_addr(tran_buf, off);
memcpy(&tran_buf[MLXSW_I2C_ADDR_BUF_SIZE], in_mbox +
- MLXSW_I2C_BLK_MAX * i, chunk_size);
+ mlxsw_i2c->block_size * i, chunk_size);
j = 0;
end = jiffies + timeout;
@@ -342,9 +349,10 @@ mlxsw_i2c_write(struct device *dev, size_t in_mbox_size, u8 *in_mbox, int num,
(j++ < MLXSW_I2C_RETRY));
if (err != 1) {
- if (!err)
+ if (!err) {
err = -EIO;
- return err;
+ goto mlxsw_i2c_write_exit;
+ }
}
off += chunk_size;
@@ -355,24 +363,27 @@ mlxsw_i2c_write(struct device *dev, size_t in_mbox_size, u8 *in_mbox, int num,
err = mlxsw_i2c_write_cmd(client, mlxsw_i2c, 0);
if (err) {
dev_err(&client->dev, "Could not start transaction");
- return -EIO;
+ err = -EIO;
+ goto mlxsw_i2c_write_exit;
}
/* Wait until go bit is cleared. */
err = mlxsw_i2c_wait_go_bit(client, mlxsw_i2c, p_status);
if (err) {
dev_err(&client->dev, "HW semaphore is not released");
- return err;
+ goto mlxsw_i2c_write_exit;
}
/* Validate transaction completion status. */
if (*p_status) {
dev_err(&client->dev, "Bad transaction completion status %x\n",
*p_status);
- return -EIO;
+ err = -EIO;
}
- return 0;
+mlxsw_i2c_write_exit:
+ kfree(tran_buf);
+ return err;
}
/* Routine executes I2C command. */
@@ -395,8 +406,8 @@ mlxsw_i2c_cmd(struct device *dev, u16 opcode, u32 in_mod, size_t in_mbox_size,
if (in_mbox) {
reg_size = mlxsw_i2c_get_reg_size(in_mbox);
- num = reg_size / MLXSW_I2C_BLK_MAX;
- if (reg_size % MLXSW_I2C_BLK_MAX)
+ num = reg_size / mlxsw_i2c->block_size;
+ if (reg_size % mlxsw_i2c->block_size)
num++;
if (mutex_lock_interruptible(&mlxsw_i2c->cmd.lock) < 0) {
@@ -416,7 +427,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_BLK_MAX;
+ num = reg_size / mlxsw_i2c->block_size;
if (mutex_lock_interruptible(&mlxsw_i2c->cmd.lock) < 0) {
dev_err(&client->dev, "Could not acquire lock");
@@ -432,8 +443,8 @@ mlxsw_i2c_cmd(struct device *dev, u16 opcode, u32 in_mod, size_t in_mbox_size,
/* Send read transaction to get output mailbox content. */
read_tran[1].buf = out_mbox;
for (i = 0; i < num; i++) {
- chunk_size = (reg_size > MLXSW_I2C_BLK_MAX) ?
- MLXSW_I2C_BLK_MAX : reg_size;
+ chunk_size = (reg_size > mlxsw_i2c->block_size) ?
+ mlxsw_i2c->block_size : reg_size;
read_tran[1].len = chunk_size;
mlxsw_i2c_set_slave_addr(tran_buf, off);
@@ -509,8 +520,20 @@ mlxsw_i2c_init(void *bus_priv, struct mlxsw_core *mlxsw_core,
if (!mbox)
return -ENOMEM;
+ err = mlxsw_cmd_query_fw(mlxsw_core, mbox);
+ if (err)
+ goto mbox_put;
+
+ mlxsw_i2c->bus_info.fw_rev.major =
+ mlxsw_cmd_mbox_query_fw_fw_rev_major_get(mbox);
+ mlxsw_i2c->bus_info.fw_rev.minor =
+ mlxsw_cmd_mbox_query_fw_fw_rev_minor_get(mbox);
+ mlxsw_i2c->bus_info.fw_rev.subminor =
+ mlxsw_cmd_mbox_query_fw_fw_rev_subminor_get(mbox);
+
err = mlxsw_core_resources_query(mlxsw_core, mbox, res);
+mbox_put:
mlxsw_cmd_mbox_free(mbox);
return err;
}
@@ -534,6 +557,7 @@ static const struct mlxsw_bus mlxsw_i2c_bus = {
static int mlxsw_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
+ const struct i2c_adapter_quirks *quirks = client->adapter->quirks;
struct mlxsw_i2c *mlxsw_i2c;
u8 status;
int err;
@@ -542,6 +566,22 @@ static int mlxsw_i2c_probe(struct i2c_client *client,
if (!mlxsw_i2c)
return -ENOMEM;
+ if (quirks) {
+ if ((quirks->max_read_len &&
+ quirks->max_read_len < MLXSW_I2C_BLK_DEF) ||
+ (quirks->max_write_len &&
+ quirks->max_write_len < MLXSW_I2C_BLK_DEF)) {
+ dev_err(&client->dev, "Insufficient transaction buffer length\n");
+ return -EOPNOTSUPP;
+ }
+
+ mlxsw_i2c->block_size = max_t(u16, MLXSW_I2C_BLK_DEF,
+ min_t(u16, quirks->max_read_len,
+ quirks->max_write_len));
+ } else {
+ mlxsw_i2c->block_size = MLXSW_I2C_BLK_DEF;
+ }
+
i2c_set_clientdata(client, mlxsw_i2c);
mutex_init(&mlxsw_i2c->cmd.lock);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c
index cf2114273b72..471b0ca6d69a 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c
@@ -67,6 +67,23 @@ static const struct net_device_ops mlxsw_m_port_netdev_ops = {
.ndo_get_devlink_port = mlxsw_m_port_get_devlink_port,
};
+static void mlxsw_m_module_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ struct mlxsw_m_port *mlxsw_m_port = netdev_priv(dev);
+ struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m;
+
+ strlcpy(drvinfo->driver, mlxsw_m->bus_info->device_kind,
+ sizeof(drvinfo->driver));
+ snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+ "%d.%d.%d",
+ mlxsw_m->bus_info->fw_rev.major,
+ mlxsw_m->bus_info->fw_rev.minor,
+ mlxsw_m->bus_info->fw_rev.subminor);
+ strlcpy(drvinfo->bus_info, mlxsw_m->bus_info->device_name,
+ sizeof(drvinfo->bus_info));
+}
+
static int mlxsw_m_get_module_info(struct net_device *netdev,
struct ethtool_modinfo *modinfo)
{
@@ -88,6 +105,7 @@ mlxsw_m_get_module_eeprom(struct net_device *netdev, struct ethtool_eeprom *ee,
}
static const struct ethtool_ops mlxsw_m_port_ethtool_ops = {
+ .get_drvinfo = mlxsw_m_module_get_drvinfo,
.get_module_info = mlxsw_m_get_module_info,
.get_module_eeprom = mlxsw_m_get_module_eeprom,
};
diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c
index b40455f8293d..615455a21567 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/pci.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c
@@ -102,6 +102,7 @@ struct mlxsw_pci_queue_type_group {
struct mlxsw_pci {
struct pci_dev *pdev;
u8 __iomem *hw_addr;
+ u64 free_running_clock_offset;
struct mlxsw_pci_queue_type_group queues[MLXSW_PCI_QUEUE_TYPE_COUNT];
u32 doorbell_offset;
struct mlxsw_core *core;
@@ -507,17 +508,28 @@ static void mlxsw_pci_cqe_sdq_handle(struct mlxsw_pci *mlxsw_pci,
{
struct pci_dev *pdev = mlxsw_pci->pdev;
struct mlxsw_pci_queue_elem_info *elem_info;
+ struct mlxsw_tx_info tx_info;
char *wqe;
struct sk_buff *skb;
int i;
spin_lock(&q->lock);
elem_info = mlxsw_pci_queue_elem_info_consumer_get(q);
+ tx_info = mlxsw_skb_cb(elem_info->u.sdq.skb)->tx_info;
skb = elem_info->u.sdq.skb;
wqe = elem_info->elem;
for (i = 0; i < MLXSW_PCI_WQE_SG_ENTRIES; i++)
mlxsw_pci_wqe_frag_unmap(mlxsw_pci, wqe, i, DMA_TO_DEVICE);
- dev_kfree_skb_any(skb);
+
+ if (unlikely(!tx_info.is_emad &&
+ skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
+ mlxsw_core_ptp_transmitted(mlxsw_pci->core, skb,
+ tx_info.local_port);
+ skb = NULL;
+ }
+
+ if (skb)
+ dev_kfree_skb_any(skb);
elem_info->u.sdq.skb = NULL;
if (q->consumer_counter++ != consumer_counter_limit)
@@ -835,7 +847,6 @@ static int mlxsw_pci_queue_init(struct mlxsw_pci *mlxsw_pci, char *mbox,
&mem_item->mapaddr);
if (!mem_item->buf)
return -ENOMEM;
- memset(mem_item->buf, 0, mem_item->size);
q->elem_info = kcalloc(q->count, sizeof(*q->elem_info), GFP_KERNEL);
if (!q->elem_info) {
@@ -1414,6 +1425,15 @@ static int mlxsw_pci_init(void *bus_priv, struct mlxsw_core *mlxsw_core,
mlxsw_pci->doorbell_offset =
mlxsw_cmd_mbox_query_fw_doorbell_page_offset_get(mbox);
+ if (mlxsw_cmd_mbox_query_fw_fr_rn_clk_bar_get(mbox) != 0) {
+ dev_err(&pdev->dev, "Unsupported free running clock BAR queried from hw\n");
+ err = -EINVAL;
+ goto err_fr_rn_clk_bar;
+ }
+
+ mlxsw_pci->free_running_clock_offset =
+ mlxsw_cmd_mbox_query_fw_free_running_clock_offset_get(mbox);
+
num_pages = mlxsw_cmd_mbox_query_fw_fw_pages_get(mbox);
err = mlxsw_pci_fw_area_init(mlxsw_pci, mbox, num_pages);
if (err)
@@ -1469,6 +1489,7 @@ err_query_resources:
err_boardinfo:
mlxsw_pci_fw_area_fini(mlxsw_pci);
err_fw_area_init:
+err_fr_rn_clk_bar:
err_doorbell_page_bar:
err_iface_rev:
err_query_fw:
@@ -1537,6 +1558,7 @@ static int mlxsw_pci_skb_transmit(void *bus_priv, struct sk_buff *skb,
err = -EAGAIN;
goto unlock;
}
+ mlxsw_skb_cb(skb)->tx_info = *tx_info;
elem_info->u.sdq.skb = skb;
wqe = elem_info->elem;
@@ -1560,6 +1582,9 @@ static int mlxsw_pci_skb_transmit(void *bus_priv, struct sk_buff *skb,
goto unmap_frags;
}
+ if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+
/* Set unused sq entries byte count to zero. */
for (i++; i < MLXSW_PCI_WQE_SG_ENTRIES; i++)
mlxsw_pci_wqe_byte_count_set(wqe, i, 0);
@@ -1672,6 +1697,24 @@ static int mlxsw_pci_cmd_exec(void *bus_priv, u16 opcode, u8 opcode_mod,
return err;
}
+static u32 mlxsw_pci_read_frc_h(void *bus_priv)
+{
+ struct mlxsw_pci *mlxsw_pci = bus_priv;
+ u64 frc_offset;
+
+ frc_offset = mlxsw_pci->free_running_clock_offset;
+ return mlxsw_pci_read32(mlxsw_pci, FREE_RUNNING_CLOCK_H(frc_offset));
+}
+
+static u32 mlxsw_pci_read_frc_l(void *bus_priv)
+{
+ struct mlxsw_pci *mlxsw_pci = bus_priv;
+ u64 frc_offset;
+
+ frc_offset = mlxsw_pci->free_running_clock_offset;
+ return mlxsw_pci_read32(mlxsw_pci, FREE_RUNNING_CLOCK_L(frc_offset));
+}
+
static const struct mlxsw_bus mlxsw_pci_bus = {
.kind = "pci",
.init = mlxsw_pci_init,
@@ -1679,6 +1722,8 @@ static const struct mlxsw_bus mlxsw_pci_bus = {
.skb_transmit_busy = mlxsw_pci_skb_transmit_busy,
.skb_transmit = mlxsw_pci_skb_transmit,
.cmd_exec = mlxsw_pci_cmd_exec,
+ .read_frc_h = mlxsw_pci_read_frc_h,
+ .read_frc_l = mlxsw_pci_read_frc_l,
.features = MLXSW_BUS_F_TXRX | MLXSW_BUS_F_RESET,
};
@@ -1740,6 +1785,7 @@ static int mlxsw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
mlxsw_pci->bus_info.device_kind = driver_name;
mlxsw_pci->bus_info.device_name = pci_name(mlxsw_pci->pdev);
mlxsw_pci->bus_info.dev = &pdev->dev;
+ mlxsw_pci->bus_info.read_frc_capable = true;
mlxsw_pci->id = id;
err = mlxsw_core_bus_device_register(&mlxsw_pci->bus_info,
diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h b/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h
index 8648ca171254..e57e42e2d2b2 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h
@@ -43,6 +43,9 @@
#define MLXSW_PCI_DOORBELL(offset, type_offset, num) \
((offset) + (type_offset) + (num) * 4)
+#define MLXSW_PCI_FREE_RUNNING_CLOCK_H(offset) (offset)
+#define MLXSW_PCI_FREE_RUNNING_CLOCK_L(offset) ((offset) + 4)
+
#define MLXSW_PCI_CQS_MAX 96
#define MLXSW_PCI_EQS_COUNT 2
#define MLXSW_PCI_EQ_ASYNC_NUM 0
diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h
index e8002bfc1e8f..ead36702549a 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h
@@ -997,7 +997,7 @@ static inline void mlxsw_reg_spaft_pack(char *payload, u8 local_port,
MLXSW_REG_ZERO(spaft, payload);
mlxsw_reg_spaft_local_port_set(payload, local_port);
mlxsw_reg_spaft_allow_untagged_set(payload, allow_untagged);
- mlxsw_reg_spaft_allow_prio_tagged_set(payload, true);
+ mlxsw_reg_spaft_allow_prio_tagged_set(payload, allow_untagged);
mlxsw_reg_spaft_allow_tagged_set(payload, true);
}
@@ -3515,6 +3515,18 @@ MLXSW_ITEM32(reg, qeec, next_element_index, 0x08, 0, 8);
*/
MLXSW_ITEM32(reg, qeec, mise, 0x0C, 31, 1);
+/* reg_qeec_ptps
+ * PTP shaper
+ * 0: regular shaper mode
+ * 1: PTP oriented shaper
+ * Allowed only for hierarchy 0
+ * Not supported for CPU port
+ * Note that ptps mode may affect the shaper rates of all hierarchies
+ * Supported only on Spectrum-1
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, qeec, ptps, 0x0C, 29, 1);
+
enum {
MLXSW_REG_QEEC_BYTES_MODE,
MLXSW_REG_QEEC_PACKETS_MODE,
@@ -3601,6 +3613,16 @@ static inline void mlxsw_reg_qeec_pack(char *payload, u8 local_port,
mlxsw_reg_qeec_next_element_index_set(payload, next_index);
}
+static inline void mlxsw_reg_qeec_ptps_pack(char *payload, u8 local_port,
+ bool ptps)
+{
+ MLXSW_REG_ZERO(qeec, payload);
+ mlxsw_reg_qeec_local_port_set(payload, local_port);
+ mlxsw_reg_qeec_element_hierarchy_set(payload,
+ MLXSW_REG_QEEC_HIERARCY_PORT);
+ mlxsw_reg_qeec_ptps_set(payload, ptps);
+}
+
/* QRWE - QoS ReWrite Enable
* -------------------------
* This register configures the rewrite enable per receive port.
@@ -3814,6 +3836,112 @@ mlxsw_reg_qtctm_pack(char *payload, u8 local_port, bool mc)
mlxsw_reg_qtctm_mc_set(payload, mc);
}
+/* QPSC - QoS PTP Shaper Configuration Register
+ * --------------------------------------------
+ * The QPSC allows advanced configuration of the shapers when QEEC.ptps=1.
+ * Supported only on Spectrum-1.
+ */
+#define MLXSW_REG_QPSC_ID 0x401B
+#define MLXSW_REG_QPSC_LEN 0x28
+
+MLXSW_REG_DEFINE(qpsc, MLXSW_REG_QPSC_ID, MLXSW_REG_QPSC_LEN);
+
+enum mlxsw_reg_qpsc_port_speed {
+ MLXSW_REG_QPSC_PORT_SPEED_100M,
+ MLXSW_REG_QPSC_PORT_SPEED_1G,
+ MLXSW_REG_QPSC_PORT_SPEED_10G,
+ MLXSW_REG_QPSC_PORT_SPEED_25G,
+};
+
+/* reg_qpsc_port_speed
+ * Port speed.
+ * Access: Index
+ */
+MLXSW_ITEM32(reg, qpsc, port_speed, 0x00, 0, 4);
+
+/* reg_qpsc_shaper_time_exp
+ * The base-time-interval for updating the shapers tokens (for all hierarchies).
+ * shaper_update_rate = 2 ^ shaper_time_exp * (1 + shaper_time_mantissa) * 32nSec
+ * shaper_rate = 64bit * shaper_inc / shaper_update_rate
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, qpsc, shaper_time_exp, 0x04, 16, 4);
+
+/* reg_qpsc_shaper_time_mantissa
+ * The base-time-interval for updating the shapers tokens (for all hierarchies).
+ * shaper_update_rate = 2 ^ shaper_time_exp * (1 + shaper_time_mantissa) * 32nSec
+ * shaper_rate = 64bit * shaper_inc / shaper_update_rate
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, qpsc, shaper_time_mantissa, 0x04, 0, 5);
+
+/* reg_qpsc_shaper_inc
+ * Number of tokens added to shaper on each update.
+ * Units of 8B.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, qpsc, shaper_inc, 0x08, 0, 5);
+
+/* reg_qpsc_shaper_bs
+ * Max shaper Burst size.
+ * Burst size is 2 ^ max_shaper_bs * 512 [bits]
+ * Range is: 5..25 (from 2KB..2GB)
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, qpsc, shaper_bs, 0x0C, 0, 6);
+
+/* reg_qpsc_ptsc_we
+ * Write enable to port_to_shaper_credits.
+ * Access: WO
+ */
+MLXSW_ITEM32(reg, qpsc, ptsc_we, 0x10, 31, 1);
+
+/* reg_qpsc_port_to_shaper_credits
+ * For split ports: range 1..57
+ * For non-split ports: range 1..112
+ * Written only when ptsc_we is set.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, qpsc, port_to_shaper_credits, 0x10, 0, 8);
+
+/* reg_qpsc_ing_timestamp_inc
+ * Ingress timestamp increment.
+ * 2's complement.
+ * The timestamp of MTPPTR at ingress will be incremented by this value. Global
+ * value for all ports.
+ * Same units as used by MTPPTR.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, qpsc, ing_timestamp_inc, 0x20, 0, 32);
+
+/* reg_qpsc_egr_timestamp_inc
+ * Egress timestamp increment.
+ * 2's complement.
+ * The timestamp of MTPPTR at egress will be incremented by this value. Global
+ * value for all ports.
+ * Same units as used by MTPPTR.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, qpsc, egr_timestamp_inc, 0x24, 0, 32);
+
+static inline void
+mlxsw_reg_qpsc_pack(char *payload, enum mlxsw_reg_qpsc_port_speed port_speed,
+ u8 shaper_time_exp, u8 shaper_time_mantissa, u8 shaper_inc,
+ u8 shaper_bs, u8 port_to_shaper_credits,
+ int ing_timestamp_inc, int egr_timestamp_inc)
+{
+ MLXSW_REG_ZERO(qpsc, payload);
+ mlxsw_reg_qpsc_port_speed_set(payload, port_speed);
+ mlxsw_reg_qpsc_shaper_time_exp_set(payload, shaper_time_exp);
+ mlxsw_reg_qpsc_shaper_time_mantissa_set(payload, shaper_time_mantissa);
+ mlxsw_reg_qpsc_shaper_inc_set(payload, shaper_inc);
+ mlxsw_reg_qpsc_shaper_bs_set(payload, shaper_bs);
+ mlxsw_reg_qpsc_ptsc_we_set(payload, true);
+ mlxsw_reg_qpsc_port_to_shaper_credits_set(payload, port_to_shaper_credits);
+ mlxsw_reg_qpsc_ing_timestamp_inc_set(payload, ing_timestamp_inc);
+ mlxsw_reg_qpsc_egr_timestamp_inc_set(payload, egr_timestamp_inc);
+}
+
/* PMLP - Ports Module to Local Port Register
* ------------------------------------------
* Configures the assignment of modules to local ports.
@@ -5292,6 +5420,8 @@ enum mlxsw_reg_htgt_trap_group {
MLXSW_REG_HTGT_TRAP_GROUP_SP_IPV6_MLD,
MLXSW_REG_HTGT_TRAP_GROUP_SP_IPV6_ND,
MLXSW_REG_HTGT_TRAP_GROUP_SP_LBERROR,
+ MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP0,
+ MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP1,
};
/* reg_htgt_trap_group
@@ -8039,16 +8169,21 @@ MLXSW_ITEM32(reg, mtcap, sensor_count, 0x00, 0, 7);
MLXSW_REG_DEFINE(mtmp, MLXSW_REG_MTMP_ID, MLXSW_REG_MTMP_LEN);
+#define MLXSW_REG_MTMP_MODULE_INDEX_MIN 64
+#define MLXSW_REG_MTMP_GBOX_INDEX_MIN 256
/* reg_mtmp_sensor_index
* Sensors index to access.
* 64-127 of sensor_index are mapped to the SFP+/QSFP modules sequentially
* (module 0 is mapped to sensor_index 64).
* Access: Index
*/
-MLXSW_ITEM32(reg, mtmp, sensor_index, 0x00, 0, 7);
+MLXSW_ITEM32(reg, mtmp, sensor_index, 0x00, 0, 12);
/* Convert to milli degrees Celsius */
-#define MLXSW_REG_MTMP_TEMP_TO_MC(val) (val * 125)
+#define MLXSW_REG_MTMP_TEMP_TO_MC(val) ({ typeof(val) v_ = (val); \
+ ((v_) >= 0) ? ((v_) * 125) : \
+ ((s16)((GENMASK(15, 0) + (v_) + 1) \
+ * 125)); })
/* reg_mtmp_temperature
* Temperature reading from the sensor. Reading is in 0.125 Celsius
@@ -8107,7 +8242,7 @@ MLXSW_ITEM32(reg, mtmp, temperature_threshold_lo, 0x10, 0, 16);
*/
MLXSW_ITEM_BUF(reg, mtmp, sensor_name, 0x18, MLXSW_REG_MTMP_SENSOR_NAME_SIZE);
-static inline void mlxsw_reg_mtmp_pack(char *payload, u8 sensor_index,
+static inline void mlxsw_reg_mtmp_pack(char *payload, u16 sensor_index,
bool max_temp_enable,
bool max_temp_reset)
{
@@ -8119,11 +8254,10 @@ static inline void mlxsw_reg_mtmp_pack(char *payload, u8 sensor_index,
MLXSW_REG_MTMP_THRESH_HI);
}
-static inline void mlxsw_reg_mtmp_unpack(char *payload, unsigned int *p_temp,
- unsigned int *p_max_temp,
- char *sensor_name)
+static inline void mlxsw_reg_mtmp_unpack(char *payload, int *p_temp,
+ int *p_max_temp, char *sensor_name)
{
- u16 temp;
+ s16 temp;
if (p_temp) {
temp = mlxsw_reg_mtmp_temperature_get(payload);
@@ -8156,7 +8290,7 @@ MLXSW_REG_DEFINE(mtbr, MLXSW_REG_MTBR_ID, MLXSW_REG_MTBR_LEN);
* 64-127 are mapped to the SFP+/QSFP modules sequentially).
* Access: Index
*/
-MLXSW_ITEM32(reg, mtbr, base_sensor_index, 0x00, 0, 7);
+MLXSW_ITEM32(reg, mtbr, base_sensor_index, 0x00, 0, 12);
/* reg_mtbr_num_rec
* Request: Number of records to read
@@ -8183,7 +8317,7 @@ MLXSW_ITEM32_INDEXED(reg, mtbr, rec_max_temp, MLXSW_REG_MTBR_BASE_LEN, 16,
MLXSW_ITEM32_INDEXED(reg, mtbr, rec_temp, MLXSW_REG_MTBR_BASE_LEN, 0, 16,
MLXSW_REG_MTBR_REC_LEN, 0x00, false);
-static inline void mlxsw_reg_mtbr_pack(char *payload, u8 base_sensor_index,
+static inline void mlxsw_reg_mtbr_pack(char *payload, u16 base_sensor_index,
u8 num_rec)
{
MLXSW_REG_ZERO(mtbr, payload);
@@ -8689,6 +8823,107 @@ static inline void mlxsw_reg_mlcr_pack(char *payload, u8 local_port,
MLXSW_REG_MLCR_DURATION_MAX : 0);
}
+/* MTPPS - Management Pulse Per Second Register
+ * --------------------------------------------
+ * This register provides the device PPS capabilities, configure the PPS in and
+ * out modules and holds the PPS in time stamp.
+ */
+#define MLXSW_REG_MTPPS_ID 0x9053
+#define MLXSW_REG_MTPPS_LEN 0x3C
+
+MLXSW_REG_DEFINE(mtpps, MLXSW_REG_MTPPS_ID, MLXSW_REG_MTPPS_LEN);
+
+/* reg_mtpps_enable
+ * Enables the PPS functionality the specific pin.
+ * A boolean variable.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, mtpps, enable, 0x20, 31, 1);
+
+enum mlxsw_reg_mtpps_pin_mode {
+ MLXSW_REG_MTPPS_PIN_MODE_VIRTUAL_PIN = 0x2,
+};
+
+/* reg_mtpps_pin_mode
+ * Pin mode to be used. The mode must comply with the supported modes of the
+ * requested pin.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, mtpps, pin_mode, 0x20, 8, 4);
+
+#define MLXSW_REG_MTPPS_PIN_SP_VIRTUAL_PIN 7
+
+/* reg_mtpps_pin
+ * Pin to be configured or queried out of the supported pins.
+ * Access: Index
+ */
+MLXSW_ITEM32(reg, mtpps, pin, 0x20, 0, 8);
+
+/* reg_mtpps_time_stamp
+ * When pin_mode = pps_in, the latched device time when it was triggered from
+ * the external GPIO pin.
+ * When pin_mode = pps_out or virtual_pin or pps_out_and_virtual_pin, the target
+ * time to generate next output signal.
+ * Time is in units of device clock.
+ * Access: RW
+ */
+MLXSW_ITEM64(reg, mtpps, time_stamp, 0x28, 0, 64);
+
+static inline void
+mlxsw_reg_mtpps_vpin_pack(char *payload, u64 time_stamp)
+{
+ MLXSW_REG_ZERO(mtpps, payload);
+ mlxsw_reg_mtpps_pin_set(payload, MLXSW_REG_MTPPS_PIN_SP_VIRTUAL_PIN);
+ mlxsw_reg_mtpps_pin_mode_set(payload,
+ MLXSW_REG_MTPPS_PIN_MODE_VIRTUAL_PIN);
+ mlxsw_reg_mtpps_enable_set(payload, true);
+ mlxsw_reg_mtpps_time_stamp_set(payload, time_stamp);
+}
+
+/* MTUTC - Management UTC Register
+ * -------------------------------
+ * Configures the HW UTC counter.
+ */
+#define MLXSW_REG_MTUTC_ID 0x9055
+#define MLXSW_REG_MTUTC_LEN 0x1C
+
+MLXSW_REG_DEFINE(mtutc, MLXSW_REG_MTUTC_ID, MLXSW_REG_MTUTC_LEN);
+
+enum mlxsw_reg_mtutc_operation {
+ MLXSW_REG_MTUTC_OPERATION_SET_TIME_AT_NEXT_SEC = 0,
+ MLXSW_REG_MTUTC_OPERATION_ADJUST_FREQ = 3,
+};
+
+/* reg_mtutc_operation
+ * Operation.
+ * Access: OP
+ */
+MLXSW_ITEM32(reg, mtutc, operation, 0x00, 0, 4);
+
+/* reg_mtutc_freq_adjustment
+ * Frequency adjustment: Every PPS the HW frequency will be
+ * adjusted by this value. Units of HW clock, where HW counts
+ * 10^9 HW clocks for 1 HW second.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, mtutc, freq_adjustment, 0x04, 0, 32);
+
+/* reg_mtutc_utc_sec
+ * UTC seconds.
+ * Access: WO
+ */
+MLXSW_ITEM32(reg, mtutc, utc_sec, 0x10, 0, 32);
+
+static inline void
+mlxsw_reg_mtutc_pack(char *payload, enum mlxsw_reg_mtutc_operation oper,
+ u32 freq_adj, u32 utc_sec)
+{
+ MLXSW_REG_ZERO(mtutc, payload);
+ mlxsw_reg_mtutc_operation_set(payload, oper);
+ mlxsw_reg_mtutc_freq_adjustment_set(payload, freq_adj);
+ mlxsw_reg_mtutc_utc_sec_set(payload, utc_sec);
+}
+
/* MCQI - Management Component Query Information
* ---------------------------------------------
* This register allows querying information about firmware components.
@@ -9043,6 +9278,267 @@ static inline void mlxsw_reg_mprs_pack(char *payload, u16 parsing_depth,
mlxsw_reg_mprs_vxlan_udp_dport_set(payload, vxlan_udp_dport);
}
+/* MOGCR - Monitoring Global Configuration Register
+ * ------------------------------------------------
+ */
+#define MLXSW_REG_MOGCR_ID 0x9086
+#define MLXSW_REG_MOGCR_LEN 0x20
+
+MLXSW_REG_DEFINE(mogcr, MLXSW_REG_MOGCR_ID, MLXSW_REG_MOGCR_LEN);
+
+/* reg_mogcr_ptp_iftc
+ * PTP Ingress FIFO Trap Clear
+ * The PTP_ING_FIFO trap provides MTPPTR with clr according
+ * to this value. Default 0.
+ * Reserved when IB switches and when SwitchX/-2, Spectrum-2
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, mogcr, ptp_iftc, 0x00, 1, 1);
+
+/* reg_mogcr_ptp_eftc
+ * PTP Egress FIFO Trap Clear
+ * The PTP_EGR_FIFO trap provides MTPPTR with clr according
+ * to this value. Default 0.
+ * Reserved when IB switches and when SwitchX/-2, Spectrum-2
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, mogcr, ptp_eftc, 0x00, 0, 1);
+
+/* MTPPPC - Time Precision Packet Port Configuration
+ * -------------------------------------------------
+ * This register serves for configuration of which PTP messages should be
+ * timestamped. This is a global configuration, despite the register name.
+ *
+ * Reserved when Spectrum-2.
+ */
+#define MLXSW_REG_MTPPPC_ID 0x9090
+#define MLXSW_REG_MTPPPC_LEN 0x28
+
+MLXSW_REG_DEFINE(mtpppc, MLXSW_REG_MTPPPC_ID, MLXSW_REG_MTPPPC_LEN);
+
+/* reg_mtpppc_ing_timestamp_message_type
+ * Bitwise vector of PTP message types to timestamp at ingress.
+ * MessageType field as defined by IEEE 1588
+ * Each bit corresponds to a value (e.g. Bit0: Sync, Bit1: Delay_Req)
+ * Default all 0
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, mtpppc, ing_timestamp_message_type, 0x08, 0, 16);
+
+/* reg_mtpppc_egr_timestamp_message_type
+ * Bitwise vector of PTP message types to timestamp at egress.
+ * MessageType field as defined by IEEE 1588
+ * Each bit corresponds to a value (e.g. Bit0: Sync, Bit1: Delay_Req)
+ * Default all 0
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, mtpppc, egr_timestamp_message_type, 0x0C, 0, 16);
+
+static inline void mlxsw_reg_mtpppc_pack(char *payload, u16 ing, u16 egr)
+{
+ MLXSW_REG_ZERO(mtpppc, payload);
+ mlxsw_reg_mtpppc_ing_timestamp_message_type_set(payload, ing);
+ mlxsw_reg_mtpppc_egr_timestamp_message_type_set(payload, egr);
+}
+
+/* MTPPTR - Time Precision Packet Timestamping Reading
+ * ---------------------------------------------------
+ * The MTPPTR is used for reading the per port PTP timestamp FIFO.
+ * There is a trap for packets which are latched to the timestamp FIFO, thus the
+ * SW knows which FIFO to read. Note that packets enter the FIFO before been
+ * trapped. The sequence number is used to synchronize the timestamp FIFO
+ * entries and the trapped packets.
+ * Reserved when Spectrum-2.
+ */
+
+#define MLXSW_REG_MTPPTR_ID 0x9091
+#define MLXSW_REG_MTPPTR_BASE_LEN 0x10 /* base length, without records */
+#define MLXSW_REG_MTPPTR_REC_LEN 0x10 /* record length */
+#define MLXSW_REG_MTPPTR_REC_MAX_COUNT 4
+#define MLXSW_REG_MTPPTR_LEN (MLXSW_REG_MTPPTR_BASE_LEN + \
+ MLXSW_REG_MTPPTR_REC_LEN * MLXSW_REG_MTPPTR_REC_MAX_COUNT)
+
+MLXSW_REG_DEFINE(mtpptr, MLXSW_REG_MTPPTR_ID, MLXSW_REG_MTPPTR_LEN);
+
+/* reg_mtpptr_local_port
+ * Not supported for CPU port.
+ * Access: Index
+ */
+MLXSW_ITEM32(reg, mtpptr, local_port, 0x00, 16, 8);
+
+enum mlxsw_reg_mtpptr_dir {
+ MLXSW_REG_MTPPTR_DIR_INGRESS,
+ MLXSW_REG_MTPPTR_DIR_EGRESS,
+};
+
+/* reg_mtpptr_dir
+ * Direction.
+ * Access: Index
+ */
+MLXSW_ITEM32(reg, mtpptr, dir, 0x00, 0, 1);
+
+/* reg_mtpptr_clr
+ * Clear the records.
+ * Access: OP
+ */
+MLXSW_ITEM32(reg, mtpptr, clr, 0x04, 31, 1);
+
+/* reg_mtpptr_num_rec
+ * Number of valid records in the response
+ * Range 0.. cap_ptp_timestamp_fifo
+ * Access: RO
+ */
+MLXSW_ITEM32(reg, mtpptr, num_rec, 0x08, 0, 4);
+
+/* reg_mtpptr_rec_message_type
+ * MessageType field as defined by IEEE 1588 Each bit corresponds to a value
+ * (e.g. Bit0: Sync, Bit1: Delay_Req)
+ * Access: RO
+ */
+MLXSW_ITEM32_INDEXED(reg, mtpptr, rec_message_type,
+ MLXSW_REG_MTPPTR_BASE_LEN, 8, 4,
+ MLXSW_REG_MTPPTR_REC_LEN, 0, false);
+
+/* reg_mtpptr_rec_domain_number
+ * DomainNumber field as defined by IEEE 1588
+ * Access: RO
+ */
+MLXSW_ITEM32_INDEXED(reg, mtpptr, rec_domain_number,
+ MLXSW_REG_MTPPTR_BASE_LEN, 0, 8,
+ MLXSW_REG_MTPPTR_REC_LEN, 0, false);
+
+/* reg_mtpptr_rec_sequence_id
+ * SequenceId field as defined by IEEE 1588
+ * Access: RO
+ */
+MLXSW_ITEM32_INDEXED(reg, mtpptr, rec_sequence_id,
+ MLXSW_REG_MTPPTR_BASE_LEN, 0, 16,
+ MLXSW_REG_MTPPTR_REC_LEN, 0x4, false);
+
+/* reg_mtpptr_rec_timestamp_high
+ * Timestamp of when the PTP packet has passed through the port Units of PLL
+ * clock time.
+ * For Spectrum-1 the PLL clock is 156.25Mhz and PLL clock time is 6.4nSec.
+ * Access: RO
+ */
+MLXSW_ITEM32_INDEXED(reg, mtpptr, rec_timestamp_high,
+ MLXSW_REG_MTPPTR_BASE_LEN, 0, 32,
+ MLXSW_REG_MTPPTR_REC_LEN, 0x8, false);
+
+/* reg_mtpptr_rec_timestamp_low
+ * See rec_timestamp_high.
+ * Access: RO
+ */
+MLXSW_ITEM32_INDEXED(reg, mtpptr, rec_timestamp_low,
+ MLXSW_REG_MTPPTR_BASE_LEN, 0, 32,
+ MLXSW_REG_MTPPTR_REC_LEN, 0xC, false);
+
+static inline void mlxsw_reg_mtpptr_unpack(const char *payload,
+ unsigned int rec,
+ u8 *p_message_type,
+ u8 *p_domain_number,
+ u16 *p_sequence_id,
+ u64 *p_timestamp)
+{
+ u32 timestamp_high, timestamp_low;
+
+ *p_message_type = mlxsw_reg_mtpptr_rec_message_type_get(payload, rec);
+ *p_domain_number = mlxsw_reg_mtpptr_rec_domain_number_get(payload, rec);
+ *p_sequence_id = mlxsw_reg_mtpptr_rec_sequence_id_get(payload, rec);
+ timestamp_high = mlxsw_reg_mtpptr_rec_timestamp_high_get(payload, rec);
+ timestamp_low = mlxsw_reg_mtpptr_rec_timestamp_low_get(payload, rec);
+ *p_timestamp = (u64)timestamp_high << 32 | timestamp_low;
+}
+
+/* MTPTPT - Monitoring Precision Time Protocol Trap Register
+ * ---------------------------------------------------------
+ * This register is used for configuring under which trap to deliver PTP
+ * packets depending on type of the packet.
+ */
+#define MLXSW_REG_MTPTPT_ID 0x9092
+#define MLXSW_REG_MTPTPT_LEN 0x08
+
+MLXSW_REG_DEFINE(mtptpt, MLXSW_REG_MTPTPT_ID, MLXSW_REG_MTPTPT_LEN);
+
+enum mlxsw_reg_mtptpt_trap_id {
+ MLXSW_REG_MTPTPT_TRAP_ID_PTP0,
+ MLXSW_REG_MTPTPT_TRAP_ID_PTP1,
+};
+
+/* reg_mtptpt_trap_id
+ * Trap id.
+ * Access: Index
+ */
+MLXSW_ITEM32(reg, mtptpt, trap_id, 0x00, 0, 4);
+
+/* reg_mtptpt_message_type
+ * Bitwise vector of PTP message types to trap. This is a necessary but
+ * non-sufficient condition since need to enable also per port. See MTPPPC.
+ * Message types are defined by IEEE 1588 Each bit corresponds to a value (e.g.
+ * Bit0: Sync, Bit1: Delay_Req)
+ */
+MLXSW_ITEM32(reg, mtptpt, message_type, 0x04, 0, 16);
+
+static inline void mlxsw_reg_mtptptp_pack(char *payload,
+ enum mlxsw_reg_mtptpt_trap_id trap_id,
+ u16 message_type)
+{
+ MLXSW_REG_ZERO(mtptpt, payload);
+ mlxsw_reg_mtptpt_trap_id_set(payload, trap_id);
+ mlxsw_reg_mtptpt_message_type_set(payload, message_type);
+}
+
+/* MGPIR - Management General Peripheral Information Register
+ * ----------------------------------------------------------
+ * MGPIR register allows software to query the hardware and
+ * firmware general information of peripheral entities.
+ */
+#define MLXSW_REG_MGPIR_ID 0x9100
+#define MLXSW_REG_MGPIR_LEN 0xA0
+
+MLXSW_REG_DEFINE(mgpir, MLXSW_REG_MGPIR_ID, MLXSW_REG_MGPIR_LEN);
+
+enum mlxsw_reg_mgpir_device_type {
+ MLXSW_REG_MGPIR_DEVICE_TYPE_NONE,
+ MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE,
+};
+
+/* device_type
+ * Access: RO
+ */
+MLXSW_ITEM32(reg, mgpir, device_type, 0x00, 24, 4);
+
+/* devices_per_flash
+ * Number of devices of device_type per flash (can be shared by few devices).
+ * Access: RO
+ */
+MLXSW_ITEM32(reg, mgpir, devices_per_flash, 0x00, 16, 8);
+
+/* num_of_devices
+ * Number of devices of device_type.
+ * Access: RO
+ */
+MLXSW_ITEM32(reg, mgpir, num_of_devices, 0x00, 0, 8);
+
+static inline void mlxsw_reg_mgpir_pack(char *payload)
+{
+ MLXSW_REG_ZERO(mgpir, payload);
+}
+
+static inline void
+mlxsw_reg_mgpir_unpack(char *payload, u8 *num_of_devices,
+ enum mlxsw_reg_mgpir_device_type *device_type,
+ u8 *devices_per_flash)
+{
+ if (num_of_devices)
+ *num_of_devices = mlxsw_reg_mgpir_num_of_devices_get(payload);
+ if (device_type)
+ *device_type = mlxsw_reg_mgpir_device_type_get(payload);
+ if (devices_per_flash)
+ *devices_per_flash =
+ mlxsw_reg_mgpir_devices_per_flash_get(payload);
+}
+
/* TNGCR - Tunneling NVE General Configuration Register
* ----------------------------------------------------
* The TNGCR register is used for setting up the NVE Tunneling configuration.
@@ -10006,6 +10502,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = {
MLXSW_REG(qpdsm),
MLXSW_REG(qpdpm),
MLXSW_REG(qtctm),
+ MLXSW_REG(qpsc),
MLXSW_REG(pmlp),
MLXSW_REG(pmtu),
MLXSW_REG(ptys),
@@ -10052,12 +10549,19 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = {
MLXSW_REG(mgir),
MLXSW_REG(mrsr),
MLXSW_REG(mlcr),
+ MLXSW_REG(mtpps),
+ MLXSW_REG(mtutc),
MLXSW_REG(mpsc),
MLXSW_REG(mcqi),
MLXSW_REG(mcc),
MLXSW_REG(mcda),
MLXSW_REG(mgpc),
MLXSW_REG(mprs),
+ MLXSW_REG(mogcr),
+ MLXSW_REG(mtpppc),
+ MLXSW_REG(mtpptr),
+ MLXSW_REG(mtptpt),
+ MLXSW_REG(mgpir),
MLXSW_REG(tngcr),
MLXSW_REG(tnumt),
MLXSW_REG(tnqcr),
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index dfe6b44baf63..4d34d42b3b0e 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -41,6 +41,7 @@
#include "spectrum_dpipe.h"
#include "spectrum_acl_flex_actions.h"
#include "spectrum_span.h"
+#include "spectrum_ptp.h"
#include "../mlxfw/mlxfw.h"
#define MLXSW_SP_FWREV_MINOR_TO_BRANCH(minor) ((minor) / 100)
@@ -146,6 +147,35 @@ struct mlxsw_sp_mlxfw_dev {
struct mlxsw_sp *mlxsw_sp;
};
+struct mlxsw_sp_ptp_ops {
+ struct mlxsw_sp_ptp_clock *
+ (*clock_init)(struct mlxsw_sp *mlxsw_sp, struct device *dev);
+ void (*clock_fini)(struct mlxsw_sp_ptp_clock *clock);
+
+ struct mlxsw_sp_ptp_state *(*init)(struct mlxsw_sp *mlxsw_sp);
+ void (*fini)(struct mlxsw_sp_ptp_state *ptp_state);
+
+ /* Notify a driver that a packet that might be PTP was received. Driver
+ * is responsible for freeing the passed-in SKB.
+ */
+ void (*receive)(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb,
+ u8 local_port);
+
+ /* Notify a driver that a timestamped packet was transmitted. Driver
+ * is responsible for freeing the passed-in SKB.
+ */
+ void (*transmitted)(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb,
+ u8 local_port);
+
+ int (*hwtstamp_get)(struct mlxsw_sp_port *mlxsw_sp_port,
+ struct hwtstamp_config *config);
+ int (*hwtstamp_set)(struct mlxsw_sp_port *mlxsw_sp_port,
+ struct hwtstamp_config *config);
+ void (*shaper_work)(struct work_struct *work);
+ int (*get_ts_info)(struct mlxsw_sp *mlxsw_sp,
+ struct ethtool_ts_info *info);
+};
+
static int mlxsw_sp_component_query(struct mlxfw_dev *mlxfw_dev,
u16 component_index, u32 *p_max_size,
u8 *p_align_bits, u16 *p_max_write_size)
@@ -294,6 +324,19 @@ static void mlxsw_sp_fsm_release(struct mlxfw_dev *mlxfw_dev, u32 fwhandle)
mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mcc), mcc_pl);
}
+static void mlxsw_sp_status_notify(struct mlxfw_dev *mlxfw_dev,
+ const char *msg, const char *comp_name,
+ u32 done_bytes, u32 total_bytes)
+{
+ struct mlxsw_sp_mlxfw_dev *mlxsw_sp_mlxfw_dev =
+ container_of(mlxfw_dev, struct mlxsw_sp_mlxfw_dev, mlxfw_dev);
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_mlxfw_dev->mlxsw_sp;
+
+ devlink_flash_update_status_notify(priv_to_devlink(mlxsw_sp->core),
+ msg, comp_name,
+ done_bytes, total_bytes);
+}
+
static const struct mlxfw_dev_ops mlxsw_sp_mlxfw_dev_ops = {
.component_query = mlxsw_sp_component_query,
.fsm_lock = mlxsw_sp_fsm_lock,
@@ -303,11 +346,13 @@ static const struct mlxfw_dev_ops mlxsw_sp_mlxfw_dev_ops = {
.fsm_activate = mlxsw_sp_fsm_activate,
.fsm_query_state = mlxsw_sp_fsm_query_state,
.fsm_cancel = mlxsw_sp_fsm_cancel,
- .fsm_release = mlxsw_sp_fsm_release
+ .fsm_release = mlxsw_sp_fsm_release,
+ .status_notify = mlxsw_sp_status_notify,
};
static int mlxsw_sp_firmware_flash(struct mlxsw_sp *mlxsw_sp,
- const struct firmware *firmware)
+ const struct firmware *firmware,
+ struct netlink_ext_ack *extack)
{
struct mlxsw_sp_mlxfw_dev mlxsw_sp_mlxfw_dev = {
.mlxfw_dev = {
@@ -320,7 +365,10 @@ static int mlxsw_sp_firmware_flash(struct mlxsw_sp *mlxsw_sp,
int err;
mlxsw_core_fw_flash_start(mlxsw_sp->core);
- err = mlxfw_firmware_flash(&mlxsw_sp_mlxfw_dev.mlxfw_dev, firmware);
+ devlink_flash_update_begin_notify(priv_to_devlink(mlxsw_sp->core));
+ err = mlxfw_firmware_flash(&mlxsw_sp_mlxfw_dev.mlxfw_dev,
+ firmware, extack);
+ devlink_flash_update_end_notify(priv_to_devlink(mlxsw_sp->core));
mlxsw_core_fw_flash_end(mlxsw_sp->core);
return err;
@@ -374,7 +422,7 @@ static int mlxsw_sp_fw_rev_validate(struct mlxsw_sp *mlxsw_sp)
return err;
}
- err = mlxsw_sp_firmware_flash(mlxsw_sp, firmware);
+ err = mlxsw_sp_firmware_flash(mlxsw_sp, firmware, NULL);
release_firmware(firmware);
if (err)
dev_err(mlxsw_sp->bus_info->dev, "Could not upgrade firmware\n");
@@ -388,6 +436,27 @@ static int mlxsw_sp_fw_rev_validate(struct mlxsw_sp *mlxsw_sp)
return 0;
}
+static int mlxsw_sp_flash_update(struct mlxsw_core *mlxsw_core,
+ const char *file_name, const char *component,
+ struct netlink_ext_ack *extack)
+{
+ struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
+ const struct firmware *firmware;
+ int err;
+
+ if (component)
+ return -EOPNOTSUPP;
+
+ err = request_firmware_direct(&firmware, file_name,
+ mlxsw_sp->bus_info->dev);
+ if (err)
+ return err;
+ err = mlxsw_sp_firmware_flash(mlxsw_sp, firmware, extack);
+ release_firmware(firmware);
+
+ return err;
+}
+
int mlxsw_sp_flow_counter_get(struct mlxsw_sp *mlxsw_sp,
unsigned int counter_index, u64 *packets,
u64 *bytes)
@@ -738,6 +807,8 @@ static netdev_tx_t mlxsw_sp_port_xmit(struct sk_buff *skb,
u64 len;
int err;
+ memset(skb->cb, 0, sizeof(struct mlxsw_skb_cb));
+
if (mlxsw_core_skb_transmit_busy(mlxsw_sp->core, &tx_info))
return NETDEV_TX_BUSY;
@@ -1437,21 +1508,21 @@ static int mlxsw_sp_setup_tc_cls_matchall(struct mlxsw_sp_port *mlxsw_sp_port,
static int
mlxsw_sp_setup_tc_cls_flower(struct mlxsw_sp_acl_block *acl_block,
- struct tc_cls_flower_offload *f)
+ struct flow_cls_offload *f)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_acl_block_mlxsw_sp(acl_block);
switch (f->command) {
- case TC_CLSFLOWER_REPLACE:
+ case FLOW_CLS_REPLACE:
return mlxsw_sp_flower_replace(mlxsw_sp, acl_block, f);
- case TC_CLSFLOWER_DESTROY:
+ case FLOW_CLS_DESTROY:
mlxsw_sp_flower_destroy(mlxsw_sp, acl_block, f);
return 0;
- case TC_CLSFLOWER_STATS:
+ case FLOW_CLS_STATS:
return mlxsw_sp_flower_stats(mlxsw_sp, acl_block, f);
- case TC_CLSFLOWER_TMPLT_CREATE:
+ case FLOW_CLS_TMPLT_CREATE:
return mlxsw_sp_flower_tmplt_create(mlxsw_sp, acl_block, f);
- case TC_CLSFLOWER_TMPLT_DESTROY:
+ case FLOW_CLS_TMPLT_DESTROY:
mlxsw_sp_flower_tmplt_destroy(mlxsw_sp, acl_block, f);
return 0;
default:
@@ -1514,33 +1585,45 @@ static int mlxsw_sp_setup_tc_block_cb_flower(enum tc_setup_type type,
}
}
+static void mlxsw_sp_tc_block_flower_release(void *cb_priv)
+{
+ struct mlxsw_sp_acl_block *acl_block = cb_priv;
+
+ mlxsw_sp_acl_block_destroy(acl_block);
+}
+
+static LIST_HEAD(mlxsw_sp_block_cb_list);
+
static int
mlxsw_sp_setup_tc_block_flower_bind(struct mlxsw_sp_port *mlxsw_sp_port,
- struct tcf_block *block, bool ingress,
- struct netlink_ext_ack *extack)
+ struct flow_block_offload *f, bool ingress)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
struct mlxsw_sp_acl_block *acl_block;
- struct tcf_block_cb *block_cb;
+ struct flow_block_cb *block_cb;
+ bool register_block = false;
int err;
- block_cb = tcf_block_cb_lookup(block, mlxsw_sp_setup_tc_block_cb_flower,
- mlxsw_sp);
+ block_cb = flow_block_cb_lookup(f, mlxsw_sp_setup_tc_block_cb_flower,
+ mlxsw_sp);
if (!block_cb) {
- acl_block = mlxsw_sp_acl_block_create(mlxsw_sp, block->net);
+ acl_block = mlxsw_sp_acl_block_create(mlxsw_sp, f->net);
if (!acl_block)
return -ENOMEM;
- block_cb = __tcf_block_cb_register(block,
- mlxsw_sp_setup_tc_block_cb_flower,
- mlxsw_sp, acl_block, extack);
+ block_cb = flow_block_cb_alloc(f->net,
+ mlxsw_sp_setup_tc_block_cb_flower,
+ mlxsw_sp, acl_block,
+ mlxsw_sp_tc_block_flower_release);
if (IS_ERR(block_cb)) {
+ mlxsw_sp_acl_block_destroy(acl_block);
err = PTR_ERR(block_cb);
goto err_cb_register;
}
+ register_block = true;
} else {
- acl_block = tcf_block_cb_priv(block_cb);
+ acl_block = flow_block_cb_priv(block_cb);
}
- tcf_block_cb_incref(block_cb);
+ flow_block_cb_incref(block_cb);
err = mlxsw_sp_acl_block_bind(mlxsw_sp, acl_block,
mlxsw_sp_port, ingress);
if (err)
@@ -1551,28 +1634,31 @@ mlxsw_sp_setup_tc_block_flower_bind(struct mlxsw_sp_port *mlxsw_sp_port,
else
mlxsw_sp_port->eg_acl_block = acl_block;
+ if (register_block) {
+ flow_block_cb_add(block_cb, f);
+ list_add_tail(&block_cb->driver_list, &mlxsw_sp_block_cb_list);
+ }
+
return 0;
err_block_bind:
- if (!tcf_block_cb_decref(block_cb)) {
- __tcf_block_cb_unregister(block, block_cb);
+ if (!flow_block_cb_decref(block_cb))
+ flow_block_cb_free(block_cb);
err_cb_register:
- mlxsw_sp_acl_block_destroy(acl_block);
- }
return err;
}
static void
mlxsw_sp_setup_tc_block_flower_unbind(struct mlxsw_sp_port *mlxsw_sp_port,
- struct tcf_block *block, bool ingress)
+ struct flow_block_offload *f, bool ingress)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
struct mlxsw_sp_acl_block *acl_block;
- struct tcf_block_cb *block_cb;
+ struct flow_block_cb *block_cb;
int err;
- block_cb = tcf_block_cb_lookup(block, mlxsw_sp_setup_tc_block_cb_flower,
- mlxsw_sp);
+ block_cb = flow_block_cb_lookup(f, mlxsw_sp_setup_tc_block_cb_flower,
+ mlxsw_sp);
if (!block_cb)
return;
@@ -1581,50 +1667,63 @@ mlxsw_sp_setup_tc_block_flower_unbind(struct mlxsw_sp_port *mlxsw_sp_port,
else
mlxsw_sp_port->eg_acl_block = NULL;
- acl_block = tcf_block_cb_priv(block_cb);
+ acl_block = flow_block_cb_priv(block_cb);
err = mlxsw_sp_acl_block_unbind(mlxsw_sp, acl_block,
mlxsw_sp_port, ingress);
- if (!err && !tcf_block_cb_decref(block_cb)) {
- __tcf_block_cb_unregister(block, block_cb);
- mlxsw_sp_acl_block_destroy(acl_block);
+ if (!err && !flow_block_cb_decref(block_cb)) {
+ flow_block_cb_remove(block_cb, f);
+ list_del(&block_cb->driver_list);
}
}
static int mlxsw_sp_setup_tc_block(struct mlxsw_sp_port *mlxsw_sp_port,
- struct tc_block_offload *f)
+ struct flow_block_offload *f)
{
+ struct flow_block_cb *block_cb;
tc_setup_cb_t *cb;
bool ingress;
int err;
- if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS) {
+ if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) {
cb = mlxsw_sp_setup_tc_block_cb_matchall_ig;
ingress = true;
- } else if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS) {
+ } else if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) {
cb = mlxsw_sp_setup_tc_block_cb_matchall_eg;
ingress = false;
} else {
return -EOPNOTSUPP;
}
+ f->driver_block_list = &mlxsw_sp_block_cb_list;
+
switch (f->command) {
- case TC_BLOCK_BIND:
- err = tcf_block_cb_register(f->block, cb, mlxsw_sp_port,
- mlxsw_sp_port, f->extack);
- if (err)
- return err;
- err = mlxsw_sp_setup_tc_block_flower_bind(mlxsw_sp_port,
- f->block, ingress,
- f->extack);
+ case FLOW_BLOCK_BIND:
+ if (flow_block_cb_is_busy(cb, mlxsw_sp_port,
+ &mlxsw_sp_block_cb_list))
+ return -EBUSY;
+
+ block_cb = flow_block_cb_alloc(f->net, cb, mlxsw_sp_port,
+ mlxsw_sp_port, NULL);
+ if (IS_ERR(block_cb))
+ return PTR_ERR(block_cb);
+ err = mlxsw_sp_setup_tc_block_flower_bind(mlxsw_sp_port, f,
+ ingress);
if (err) {
- tcf_block_cb_unregister(f->block, cb, mlxsw_sp_port);
+ flow_block_cb_free(block_cb);
return err;
}
+ flow_block_cb_add(block_cb, f);
+ list_add_tail(&block_cb->driver_list, &mlxsw_sp_block_cb_list);
return 0;
- case TC_BLOCK_UNBIND:
+ case FLOW_BLOCK_UNBIND:
mlxsw_sp_setup_tc_block_flower_unbind(mlxsw_sp_port,
- f->block, ingress);
- tcf_block_cb_unregister(f->block, cb, mlxsw_sp_port);
+ f, ingress);
+ block_cb = flow_block_cb_lookup(f, cb, mlxsw_sp_port);
+ if (!block_cb)
+ return -ENOENT;
+
+ flow_block_cb_remove(block_cb, f);
+ list_del(&block_cb->driver_list);
return 0;
default:
return -EOPNOTSUPP;
@@ -1745,6 +1844,65 @@ mlxsw_sp_port_get_devlink_port(struct net_device *dev)
mlxsw_sp_port->local_port);
}
+static int mlxsw_sp_port_hwtstamp_set(struct mlxsw_sp_port *mlxsw_sp_port,
+ struct ifreq *ifr)
+{
+ struct hwtstamp_config config;
+ int err;
+
+ if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
+ return -EFAULT;
+
+ err = mlxsw_sp_port->mlxsw_sp->ptp_ops->hwtstamp_set(mlxsw_sp_port,
+ &config);
+ if (err)
+ return err;
+
+ if (copy_to_user(ifr->ifr_data, &config, sizeof(config)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int mlxsw_sp_port_hwtstamp_get(struct mlxsw_sp_port *mlxsw_sp_port,
+ struct ifreq *ifr)
+{
+ struct hwtstamp_config config;
+ int err;
+
+ err = mlxsw_sp_port->mlxsw_sp->ptp_ops->hwtstamp_get(mlxsw_sp_port,
+ &config);
+ if (err)
+ return err;
+
+ if (copy_to_user(ifr->ifr_data, &config, sizeof(config)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static inline void mlxsw_sp_port_ptp_clear(struct mlxsw_sp_port *mlxsw_sp_port)
+{
+ struct hwtstamp_config config = {0};
+
+ mlxsw_sp_port->mlxsw_sp->ptp_ops->hwtstamp_set(mlxsw_sp_port, &config);
+}
+
+static int
+mlxsw_sp_port_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
+
+ switch (cmd) {
+ case SIOCSHWTSTAMP:
+ return mlxsw_sp_port_hwtstamp_set(mlxsw_sp_port, ifr);
+ case SIOCGHWTSTAMP:
+ return mlxsw_sp_port_hwtstamp_get(mlxsw_sp_port, ifr);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
static const struct net_device_ops mlxsw_sp_port_netdev_ops = {
.ndo_open = mlxsw_sp_port_open,
.ndo_stop = mlxsw_sp_port_stop,
@@ -1760,6 +1918,7 @@ static const struct net_device_ops mlxsw_sp_port_netdev_ops = {
.ndo_vlan_rx_kill_vid = mlxsw_sp_port_kill_vid,
.ndo_set_features = mlxsw_sp_set_features,
.ndo_get_devlink_port = mlxsw_sp_port_get_devlink_port,
+ .ndo_do_ioctl = mlxsw_sp_port_ioctl,
};
static void mlxsw_sp_port_get_drvinfo(struct net_device *dev,
@@ -2525,28 +2684,33 @@ mlxsw_sp1_from_ptys_link(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto,
}
}
+static u32
+mlxsw_sp1_from_ptys_speed(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto)
+{
+ int i;
+
+ for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
+ if (ptys_eth_proto & mlxsw_sp1_port_link_mode[i].mask)
+ return mlxsw_sp1_port_link_mode[i].speed;
+ }
+
+ return SPEED_UNKNOWN;
+}
+
static void
mlxsw_sp1_from_ptys_speed_duplex(struct mlxsw_sp *mlxsw_sp, bool carrier_ok,
u32 ptys_eth_proto,
struct ethtool_link_ksettings *cmd)
{
- u32 speed = SPEED_UNKNOWN;
- u8 duplex = DUPLEX_UNKNOWN;
- int i;
+ cmd->base.speed = SPEED_UNKNOWN;
+ cmd->base.duplex = DUPLEX_UNKNOWN;
if (!carrier_ok)
- goto out;
+ return;
- for (i = 0; i < MLXSW_SP1_PORT_LINK_MODE_LEN; i++) {
- if (ptys_eth_proto & mlxsw_sp1_port_link_mode[i].mask) {
- speed = mlxsw_sp1_port_link_mode[i].speed;
- duplex = DUPLEX_FULL;
- break;
- }
- }
-out:
- cmd->base.speed = speed;
- cmd->base.duplex = duplex;
+ cmd->base.speed = mlxsw_sp1_from_ptys_speed(mlxsw_sp, ptys_eth_proto);
+ if (cmd->base.speed != SPEED_UNKNOWN)
+ cmd->base.duplex = DUPLEX_FULL;
}
static u32
@@ -2617,6 +2781,7 @@ static const struct mlxsw_sp_port_type_speed_ops
mlxsw_sp1_port_type_speed_ops = {
.from_ptys_supported_port = mlxsw_sp1_from_ptys_supported_port,
.from_ptys_link = mlxsw_sp1_from_ptys_link,
+ .from_ptys_speed = mlxsw_sp1_from_ptys_speed,
.from_ptys_speed_duplex = mlxsw_sp1_from_ptys_speed_duplex,
.to_ptys_advert_link = mlxsw_sp1_to_ptys_advert_link,
.to_ptys_speed = mlxsw_sp1_to_ptys_speed,
@@ -2867,28 +3032,33 @@ mlxsw_sp2_from_ptys_link(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto,
}
}
+static u32
+mlxsw_sp2_from_ptys_speed(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto)
+{
+ int i;
+
+ for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
+ if (ptys_eth_proto & mlxsw_sp2_port_link_mode[i].mask)
+ return mlxsw_sp2_port_link_mode[i].speed;
+ }
+
+ return SPEED_UNKNOWN;
+}
+
static void
mlxsw_sp2_from_ptys_speed_duplex(struct mlxsw_sp *mlxsw_sp, bool carrier_ok,
u32 ptys_eth_proto,
struct ethtool_link_ksettings *cmd)
{
- u32 speed = SPEED_UNKNOWN;
- u8 duplex = DUPLEX_UNKNOWN;
- int i;
+ cmd->base.speed = SPEED_UNKNOWN;
+ cmd->base.duplex = DUPLEX_UNKNOWN;
if (!carrier_ok)
- goto out;
+ return;
- for (i = 0; i < MLXSW_SP2_PORT_LINK_MODE_LEN; i++) {
- if (ptys_eth_proto & mlxsw_sp2_port_link_mode[i].mask) {
- speed = mlxsw_sp2_port_link_mode[i].speed;
- duplex = DUPLEX_FULL;
- break;
- }
- }
-out:
- cmd->base.speed = speed;
- cmd->base.duplex = duplex;
+ cmd->base.speed = mlxsw_sp2_from_ptys_speed(mlxsw_sp, ptys_eth_proto);
+ if (cmd->base.speed != SPEED_UNKNOWN)
+ cmd->base.duplex = DUPLEX_FULL;
}
static bool
@@ -2999,6 +3169,7 @@ static const struct mlxsw_sp_port_type_speed_ops
mlxsw_sp2_port_type_speed_ops = {
.from_ptys_supported_port = mlxsw_sp2_from_ptys_supported_port,
.from_ptys_link = mlxsw_sp2_from_ptys_link,
+ .from_ptys_speed = mlxsw_sp2_from_ptys_speed,
.from_ptys_speed_duplex = mlxsw_sp2_from_ptys_speed_duplex,
.to_ptys_advert_link = mlxsw_sp2_to_ptys_advert_link,
.to_ptys_speed = mlxsw_sp2_to_ptys_speed,
@@ -3159,31 +3330,6 @@ mlxsw_sp_port_set_link_ksettings(struct net_device *dev,
return 0;
}
-static int mlxsw_sp_flash_device(struct net_device *dev,
- struct ethtool_flash *flash)
-{
- struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
- struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
- const struct firmware *firmware;
- int err;
-
- if (flash->region != ETHTOOL_FLASH_ALL_REGIONS)
- return -EOPNOTSUPP;
-
- dev_hold(dev);
- rtnl_unlock();
-
- err = request_firmware_direct(&firmware, flash->data, &dev->dev);
- if (err)
- goto out;
- err = mlxsw_sp_firmware_flash(mlxsw_sp, firmware);
- release_firmware(firmware);
-out:
- rtnl_lock();
- dev_put(dev);
- return err;
-}
-
static int mlxsw_sp_get_module_info(struct net_device *netdev,
struct ethtool_modinfo *modinfo)
{
@@ -3213,6 +3359,15 @@ static int mlxsw_sp_get_module_eeprom(struct net_device *netdev,
return err;
}
+static int
+mlxsw_sp_get_ts_info(struct net_device *netdev, struct ethtool_ts_info *info)
+{
+ struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(netdev);
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+
+ return mlxsw_sp->ptp_ops->get_ts_info(mlxsw_sp, info);
+}
+
static const struct ethtool_ops mlxsw_sp_port_ethtool_ops = {
.get_drvinfo = mlxsw_sp_port_get_drvinfo,
.get_link = ethtool_op_get_link,
@@ -3224,9 +3379,9 @@ static const struct ethtool_ops mlxsw_sp_port_ethtool_ops = {
.get_sset_count = mlxsw_sp_port_get_sset_count,
.get_link_ksettings = mlxsw_sp_port_get_link_ksettings,
.set_link_ksettings = mlxsw_sp_port_set_link_ksettings,
- .flash_device = mlxsw_sp_flash_device,
.get_module_info = mlxsw_sp_get_module_info,
.get_module_eeprom = mlxsw_sp_get_module_eeprom,
+ .get_ts_info = mlxsw_sp_get_ts_info,
};
static int
@@ -3343,8 +3498,9 @@ static int mlxsw_sp_port_ets_init(struct mlxsw_sp_port *mlxsw_sp_port)
return err;
}
- /* Make sure the max shaper is disabled in all hierarchies that
- * support it.
+ /* Make sure the max shaper is disabled in all hierarchies that support
+ * it. Note that this disables ptps (PTP shaper), but that is intended
+ * for the initial configuration.
*/
err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port,
MLXSW_REG_QEEC_HIERARCY_PORT, 0, 0,
@@ -3589,6 +3745,9 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
}
mlxsw_sp_port->default_vlan = mlxsw_sp_port_vlan;
+ INIT_DELAYED_WORK(&mlxsw_sp_port->ptp.shaper_dw,
+ mlxsw_sp->ptp_ops->shaper_work);
+
mlxsw_sp->ports[local_port] = mlxsw_sp_port;
err = register_netdev(dev);
if (err) {
@@ -3643,6 +3802,8 @@ static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port)
struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp->ports[local_port];
cancel_delayed_work_sync(&mlxsw_sp_port->periodic_hw_stats.update_dw);
+ cancel_delayed_work_sync(&mlxsw_sp_port->ptp.shaper_dw);
+ mlxsw_sp_port_ptp_clear(mlxsw_sp_port);
mlxsw_core_port_clear(mlxsw_sp->core, local_port, mlxsw_sp);
unregister_netdev(mlxsw_sp_port->dev); /* This calls ndo_stop */
mlxsw_sp->ports[local_port] = NULL;
@@ -3927,14 +4088,55 @@ static void mlxsw_sp_pude_event_func(const struct mlxsw_reg_info *reg,
if (status == MLXSW_PORT_OPER_STATUS_UP) {
netdev_info(mlxsw_sp_port->dev, "link up\n");
netif_carrier_on(mlxsw_sp_port->dev);
+ mlxsw_core_schedule_dw(&mlxsw_sp_port->ptp.shaper_dw, 0);
} else {
netdev_info(mlxsw_sp_port->dev, "link down\n");
netif_carrier_off(mlxsw_sp_port->dev);
}
}
-static void mlxsw_sp_rx_listener_no_mark_func(struct sk_buff *skb,
- u8 local_port, void *priv)
+static void mlxsw_sp1_ptp_fifo_event_func(struct mlxsw_sp *mlxsw_sp,
+ char *mtpptr_pl, bool ingress)
+{
+ u8 local_port;
+ u8 num_rec;
+ int i;
+
+ local_port = mlxsw_reg_mtpptr_local_port_get(mtpptr_pl);
+ num_rec = mlxsw_reg_mtpptr_num_rec_get(mtpptr_pl);
+ for (i = 0; i < num_rec; i++) {
+ u8 domain_number;
+ u8 message_type;
+ u16 sequence_id;
+ u64 timestamp;
+
+ mlxsw_reg_mtpptr_unpack(mtpptr_pl, i, &message_type,
+ &domain_number, &sequence_id,
+ &timestamp);
+ mlxsw_sp1_ptp_got_timestamp(mlxsw_sp, ingress, local_port,
+ message_type, domain_number,
+ sequence_id, timestamp);
+ }
+}
+
+static void mlxsw_sp1_ptp_ing_fifo_event_func(const struct mlxsw_reg_info *reg,
+ char *mtpptr_pl, void *priv)
+{
+ struct mlxsw_sp *mlxsw_sp = priv;
+
+ mlxsw_sp1_ptp_fifo_event_func(mlxsw_sp, mtpptr_pl, true);
+}
+
+static void mlxsw_sp1_ptp_egr_fifo_event_func(const struct mlxsw_reg_info *reg,
+ char *mtpptr_pl, void *priv)
+{
+ struct mlxsw_sp *mlxsw_sp = priv;
+
+ mlxsw_sp1_ptp_fifo_event_func(mlxsw_sp, mtpptr_pl, false);
+}
+
+void mlxsw_sp_rx_listener_no_mark_func(struct sk_buff *skb,
+ u8 local_port, void *priv)
{
struct mlxsw_sp *mlxsw_sp = priv;
struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp->ports[local_port];
@@ -4008,6 +4210,14 @@ out:
consume_skb(skb);
}
+static void mlxsw_sp_rx_listener_ptp(struct sk_buff *skb, u8 local_port,
+ void *priv)
+{
+ struct mlxsw_sp *mlxsw_sp = priv;
+
+ mlxsw_sp->ptp_ops->receive(mlxsw_sp, skb, local_port);
+}
+
#define MLXSW_SP_RXL_NO_MARK(_trap_id, _action, _trap_group, _is_ctrl) \
MLXSW_RXL(mlxsw_sp_rx_listener_no_mark_func, _trap_id, _action, \
_is_ctrl, SP_##_trap_group, DISCARD)
@@ -4029,7 +4239,8 @@ static const struct mlxsw_listener mlxsw_sp_listener[] = {
/* L2 traps */
MLXSW_SP_RXL_NO_MARK(STP, TRAP_TO_CPU, STP, true),
MLXSW_SP_RXL_NO_MARK(LACP, TRAP_TO_CPU, LACP, true),
- MLXSW_SP_RXL_NO_MARK(LLDP, TRAP_TO_CPU, LLDP, true),
+ MLXSW_RXL(mlxsw_sp_rx_listener_ptp, LLDP, TRAP_TO_CPU,
+ false, SP_LLDP, DISCARD),
MLXSW_SP_RXL_MARK(DHCP, MIRROR_TO_CPU, DHCP, false),
MLXSW_SP_RXL_MARK(IGMP_QUERY, MIRROR_TO_CPU, IGMP, false),
MLXSW_SP_RXL_NO_MARK(IGMP_V1_REPORT, TRAP_TO_CPU, IGMP, false),
@@ -4098,6 +4309,16 @@ static const struct mlxsw_listener mlxsw_sp_listener[] = {
/* NVE traps */
MLXSW_SP_RXL_MARK(NVE_ENCAP_ARP, TRAP_TO_CPU, ARP, false),
MLXSW_SP_RXL_NO_MARK(NVE_DECAP_ARP, TRAP_TO_CPU, ARP, false),
+ /* PTP traps */
+ MLXSW_RXL(mlxsw_sp_rx_listener_ptp, PTP0, TRAP_TO_CPU,
+ false, SP_PTP0, DISCARD),
+ MLXSW_SP_RXL_NO_MARK(PTP1, TRAP_TO_CPU, PTP1, false),
+};
+
+static const struct mlxsw_listener mlxsw_sp1_listener[] = {
+ /* Events */
+ MLXSW_EVENTL(mlxsw_sp1_ptp_egr_fifo_event_func, PTP_EGR_FIFO, SP_PTP0),
+ MLXSW_EVENTL(mlxsw_sp1_ptp_ing_fifo_event_func, PTP_ING_FIFO, SP_PTP0),
};
static int mlxsw_sp_cpu_policers_set(struct mlxsw_core *mlxsw_core)
@@ -4149,6 +4370,14 @@ static int mlxsw_sp_cpu_policers_set(struct mlxsw_core *mlxsw_core)
rate = 1024;
burst_size = 7;
break;
+ case MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP0:
+ rate = 24 * 1024;
+ burst_size = 12;
+ break;
+ case MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP1:
+ rate = 19 * 1024;
+ burst_size = 12;
+ break;
default:
continue;
}
@@ -4187,6 +4416,7 @@ static int mlxsw_sp_trap_groups_set(struct mlxsw_core *mlxsw_core)
case MLXSW_REG_HTGT_TRAP_GROUP_SP_LLDP:
case MLXSW_REG_HTGT_TRAP_GROUP_SP_OSPF:
case MLXSW_REG_HTGT_TRAP_GROUP_SP_PIM:
+ case MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP0:
priority = 5;
tc = 5;
break;
@@ -4204,6 +4434,7 @@ static int mlxsw_sp_trap_groups_set(struct mlxsw_core *mlxsw_core)
case MLXSW_REG_HTGT_TRAP_GROUP_SP_ARP:
case MLXSW_REG_HTGT_TRAP_GROUP_SP_IPV6_ND:
case MLXSW_REG_HTGT_TRAP_GROUP_SP_RPF:
+ case MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP1:
priority = 2;
tc = 2;
break;
@@ -4237,22 +4468,16 @@ static int mlxsw_sp_trap_groups_set(struct mlxsw_core *mlxsw_core)
return 0;
}
-static int mlxsw_sp_traps_init(struct mlxsw_sp *mlxsw_sp)
+static int mlxsw_sp_traps_register(struct mlxsw_sp *mlxsw_sp,
+ const struct mlxsw_listener listeners[],
+ size_t listeners_count)
{
int i;
int err;
- err = mlxsw_sp_cpu_policers_set(mlxsw_sp->core);
- if (err)
- return err;
-
- err = mlxsw_sp_trap_groups_set(mlxsw_sp->core);
- if (err)
- return err;
-
- for (i = 0; i < ARRAY_SIZE(mlxsw_sp_listener); i++) {
+ for (i = 0; i < listeners_count; i++) {
err = mlxsw_core_trap_register(mlxsw_sp->core,
- &mlxsw_sp_listener[i],
+ &listeners[i],
mlxsw_sp);
if (err)
goto err_listener_register;
@@ -4263,30 +4488,73 @@ static int mlxsw_sp_traps_init(struct mlxsw_sp *mlxsw_sp)
err_listener_register:
for (i--; i >= 0; i--) {
mlxsw_core_trap_unregister(mlxsw_sp->core,
- &mlxsw_sp_listener[i],
+ &listeners[i],
mlxsw_sp);
}
return err;
}
-static void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp)
+static void mlxsw_sp_traps_unregister(struct mlxsw_sp *mlxsw_sp,
+ const struct mlxsw_listener listeners[],
+ size_t listeners_count)
{
int i;
- for (i = 0; i < ARRAY_SIZE(mlxsw_sp_listener); i++) {
+ for (i = 0; i < listeners_count; i++) {
mlxsw_core_trap_unregister(mlxsw_sp->core,
- &mlxsw_sp_listener[i],
+ &listeners[i],
mlxsw_sp);
}
}
+static int mlxsw_sp_traps_init(struct mlxsw_sp *mlxsw_sp)
+{
+ int err;
+
+ err = mlxsw_sp_cpu_policers_set(mlxsw_sp->core);
+ if (err)
+ return err;
+
+ err = mlxsw_sp_trap_groups_set(mlxsw_sp->core);
+ if (err)
+ return err;
+
+ err = mlxsw_sp_traps_register(mlxsw_sp, mlxsw_sp_listener,
+ ARRAY_SIZE(mlxsw_sp_listener));
+ if (err)
+ return err;
+
+ err = mlxsw_sp_traps_register(mlxsw_sp, mlxsw_sp->listeners,
+ mlxsw_sp->listeners_count);
+ if (err)
+ goto err_extra_traps_init;
+
+ return 0;
+
+err_extra_traps_init:
+ mlxsw_sp_traps_unregister(mlxsw_sp, mlxsw_sp_listener,
+ ARRAY_SIZE(mlxsw_sp_listener));
+ return err;
+}
+
+static void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp)
+{
+ mlxsw_sp_traps_unregister(mlxsw_sp, mlxsw_sp->listeners,
+ mlxsw_sp->listeners_count);
+ mlxsw_sp_traps_unregister(mlxsw_sp, mlxsw_sp_listener,
+ ARRAY_SIZE(mlxsw_sp_listener));
+}
+
+#define MLXSW_SP_LAG_SEED_INIT 0xcafecafe
+
static int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp)
{
char slcr_pl[MLXSW_REG_SLCR_LEN];
u32 seed;
int err;
- seed = jhash(mlxsw_sp->base_mac, sizeof(mlxsw_sp->base_mac), 0);
+ seed = jhash(mlxsw_sp->base_mac, sizeof(mlxsw_sp->base_mac),
+ MLXSW_SP_LAG_SEED_INIT);
mlxsw_reg_slcr_pack(slcr_pl, MLXSW_REG_SLCR_LAG_HASH_SMAC |
MLXSW_REG_SLCR_LAG_HASH_DMAC |
MLXSW_REG_SLCR_LAG_HASH_ETHERTYPE |
@@ -4329,6 +4597,32 @@ static int mlxsw_sp_basic_trap_groups_set(struct mlxsw_core *mlxsw_core)
return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl);
}
+static const struct mlxsw_sp_ptp_ops mlxsw_sp1_ptp_ops = {
+ .clock_init = mlxsw_sp1_ptp_clock_init,
+ .clock_fini = mlxsw_sp1_ptp_clock_fini,
+ .init = mlxsw_sp1_ptp_init,
+ .fini = mlxsw_sp1_ptp_fini,
+ .receive = mlxsw_sp1_ptp_receive,
+ .transmitted = mlxsw_sp1_ptp_transmitted,
+ .hwtstamp_get = mlxsw_sp1_ptp_hwtstamp_get,
+ .hwtstamp_set = mlxsw_sp1_ptp_hwtstamp_set,
+ .shaper_work = mlxsw_sp1_ptp_shaper_work,
+ .get_ts_info = mlxsw_sp1_ptp_get_ts_info,
+};
+
+static const struct mlxsw_sp_ptp_ops mlxsw_sp2_ptp_ops = {
+ .clock_init = mlxsw_sp2_ptp_clock_init,
+ .clock_fini = mlxsw_sp2_ptp_clock_fini,
+ .init = mlxsw_sp2_ptp_init,
+ .fini = mlxsw_sp2_ptp_fini,
+ .receive = mlxsw_sp2_ptp_receive,
+ .transmitted = mlxsw_sp2_ptp_transmitted,
+ .hwtstamp_get = mlxsw_sp2_ptp_hwtstamp_get,
+ .hwtstamp_set = mlxsw_sp2_ptp_hwtstamp_set,
+ .shaper_work = mlxsw_sp2_ptp_shaper_work,
+ .get_ts_info = mlxsw_sp2_ptp_get_ts_info,
+};
+
static int mlxsw_sp_netdevice_event(struct notifier_block *unused,
unsigned long event, void *ptr);
@@ -4426,6 +4720,28 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
goto err_router_init;
}
+ if (mlxsw_sp->bus_info->read_frc_capable) {
+ /* NULL is a valid return value from clock_init */
+ mlxsw_sp->clock =
+ mlxsw_sp->ptp_ops->clock_init(mlxsw_sp,
+ mlxsw_sp->bus_info->dev);
+ if (IS_ERR(mlxsw_sp->clock)) {
+ err = PTR_ERR(mlxsw_sp->clock);
+ dev_err(mlxsw_sp->bus_info->dev, "Failed to init ptp clock\n");
+ goto err_ptp_clock_init;
+ }
+ }
+
+ if (mlxsw_sp->clock) {
+ /* NULL is a valid return value from ptp_ops->init */
+ mlxsw_sp->ptp_state = mlxsw_sp->ptp_ops->init(mlxsw_sp);
+ if (IS_ERR(mlxsw_sp->ptp_state)) {
+ err = PTR_ERR(mlxsw_sp->ptp_state);
+ dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize PTP\n");
+ goto err_ptp_init;
+ }
+ }
+
/* Initialize netdevice notifier after router and SPAN is initialized,
* so that the event handler can use router structures and call SPAN
* respin.
@@ -4456,6 +4772,12 @@ err_ports_create:
err_dpipe_init:
unregister_netdevice_notifier(&mlxsw_sp->netdevice_nb);
err_netdev_notifier:
+ if (mlxsw_sp->clock)
+ mlxsw_sp->ptp_ops->fini(mlxsw_sp->ptp_state);
+err_ptp_init:
+ if (mlxsw_sp->clock)
+ mlxsw_sp->ptp_ops->clock_fini(mlxsw_sp->clock);
+err_ptp_clock_init:
mlxsw_sp_router_fini(mlxsw_sp);
err_router_init:
mlxsw_sp_acl_fini(mlxsw_sp);
@@ -4499,6 +4821,9 @@ static int mlxsw_sp1_init(struct mlxsw_core *mlxsw_core,
mlxsw_sp->rif_ops_arr = mlxsw_sp1_rif_ops_arr;
mlxsw_sp->sb_vals = &mlxsw_sp1_sb_vals;
mlxsw_sp->port_type_speed_ops = &mlxsw_sp1_port_type_speed_ops;
+ mlxsw_sp->ptp_ops = &mlxsw_sp1_ptp_ops;
+ mlxsw_sp->listeners = mlxsw_sp1_listener;
+ mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp1_listener);
return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info);
}
@@ -4518,6 +4843,7 @@ static int mlxsw_sp2_init(struct mlxsw_core *mlxsw_core,
mlxsw_sp->rif_ops_arr = mlxsw_sp2_rif_ops_arr;
mlxsw_sp->sb_vals = &mlxsw_sp2_sb_vals;
mlxsw_sp->port_type_speed_ops = &mlxsw_sp2_port_type_speed_ops;
+ mlxsw_sp->ptp_ops = &mlxsw_sp2_ptp_ops;
return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info);
}
@@ -4529,6 +4855,10 @@ static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core)
mlxsw_sp_ports_remove(mlxsw_sp);
mlxsw_sp_dpipe_fini(mlxsw_sp);
unregister_netdevice_notifier(&mlxsw_sp->netdevice_nb);
+ if (mlxsw_sp->clock) {
+ mlxsw_sp->ptp_ops->fini(mlxsw_sp->ptp_state);
+ mlxsw_sp->ptp_ops->clock_fini(mlxsw_sp->clock);
+ }
mlxsw_sp_router_fini(mlxsw_sp);
mlxsw_sp_acl_fini(mlxsw_sp);
mlxsw_sp_nve_fini(mlxsw_sp);
@@ -4871,6 +5201,15 @@ static void mlxsw_sp2_params_unregister(struct mlxsw_core *mlxsw_core)
mlxsw_sp_params_unregister(mlxsw_core);
}
+static void mlxsw_sp_ptp_transmitted(struct mlxsw_core *mlxsw_core,
+ struct sk_buff *skb, u8 local_port)
+{
+ struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
+
+ skb_pull(skb, MLXSW_TXHDR_LEN);
+ mlxsw_sp->ptp_ops->transmitted(mlxsw_sp, skb, local_port);
+}
+
static struct mlxsw_driver mlxsw_sp1_driver = {
.kind = mlxsw_sp1_driver_name,
.priv_size = sizeof(struct mlxsw_sp),
@@ -4889,11 +5228,13 @@ static struct mlxsw_driver mlxsw_sp1_driver = {
.sb_occ_max_clear = mlxsw_sp_sb_occ_max_clear,
.sb_occ_port_pool_get = mlxsw_sp_sb_occ_port_pool_get,
.sb_occ_tc_port_bind_get = mlxsw_sp_sb_occ_tc_port_bind_get,
+ .flash_update = mlxsw_sp_flash_update,
.txhdr_construct = mlxsw_sp_txhdr_construct,
.resources_register = mlxsw_sp1_resources_register,
.kvd_sizes_get = mlxsw_sp_kvd_sizes_get,
.params_register = mlxsw_sp_params_register,
.params_unregister = mlxsw_sp_params_unregister,
+ .ptp_transmitted = mlxsw_sp_ptp_transmitted,
.txhdr_len = MLXSW_TXHDR_LEN,
.profile = &mlxsw_sp1_config_profile,
.res_query_enabled = true,
@@ -4917,10 +5258,12 @@ static struct mlxsw_driver mlxsw_sp2_driver = {
.sb_occ_max_clear = mlxsw_sp_sb_occ_max_clear,
.sb_occ_port_pool_get = mlxsw_sp_sb_occ_port_pool_get,
.sb_occ_tc_port_bind_get = mlxsw_sp_sb_occ_tc_port_bind_get,
+ .flash_update = mlxsw_sp_flash_update,
.txhdr_construct = mlxsw_sp_txhdr_construct,
.resources_register = mlxsw_sp2_resources_register,
.params_register = mlxsw_sp2_params_register,
.params_unregister = mlxsw_sp2_params_unregister,
+ .ptp_transmitted = mlxsw_sp_ptp_transmitted,
.txhdr_len = MLXSW_TXHDR_LEN,
.profile = &mlxsw_sp2_config_profile,
.res_query_enabled = true,
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index 8601b3041acd..131f62ce9297 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -136,6 +136,8 @@ struct mlxsw_sp_acl_tcam_ops;
struct mlxsw_sp_nve_ops;
struct mlxsw_sp_sb_vals;
struct mlxsw_sp_port_type_speed_ops;
+struct mlxsw_sp_ptp_state;
+struct mlxsw_sp_ptp_ops;
struct mlxsw_sp {
struct mlxsw_sp_port **ports;
@@ -155,6 +157,8 @@ struct mlxsw_sp {
struct mlxsw_sp_kvdl *kvdl;
struct mlxsw_sp_nve *nve;
struct notifier_block netdevice_nb;
+ struct mlxsw_sp_ptp_clock *clock;
+ struct mlxsw_sp_ptp_state *ptp_state;
struct mlxsw_sp_counter_pool *counter_pool;
struct {
@@ -172,6 +176,9 @@ struct mlxsw_sp {
const struct mlxsw_sp_rif_ops **rif_ops_arr;
const struct mlxsw_sp_sb_vals *sb_vals;
const struct mlxsw_sp_port_type_speed_ops *port_type_speed_ops;
+ const struct mlxsw_sp_ptp_ops *ptp_ops;
+ const struct mlxsw_listener *listeners;
+ size_t listeners_count;
};
static inline struct mlxsw_sp_upper *
@@ -259,6 +266,12 @@ struct mlxsw_sp_port {
unsigned acl_rule_count;
struct mlxsw_sp_acl_block *ing_acl_block;
struct mlxsw_sp_acl_block *eg_acl_block;
+ struct {
+ struct delayed_work shaper_dw;
+ struct hwtstamp_config hwtstamp_config;
+ u16 ing_types;
+ u16 egr_types;
+ } ptp;
};
struct mlxsw_sp_port_type_speed_ops {
@@ -267,6 +280,7 @@ struct mlxsw_sp_port_type_speed_ops {
struct ethtool_link_ksettings *cmd);
void (*from_ptys_link)(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto,
unsigned long *mode);
+ u32 (*from_ptys_speed)(struct mlxsw_sp *mlxsw_sp, u32 ptys_eth_proto);
void (*from_ptys_speed_duplex)(struct mlxsw_sp *mlxsw_sp,
bool carrier_ok, u32 ptys_eth_proto,
struct ethtool_link_ksettings *cmd);
@@ -435,6 +449,8 @@ struct mlxsw_sp_fid *mlxsw_sp_bridge_fid_get(struct mlxsw_sp *mlxsw_sp,
extern struct notifier_block mlxsw_sp_switchdev_notifier;
/* spectrum.c */
+void mlxsw_sp_rx_listener_no_mark_func(struct sk_buff *skb,
+ u8 local_port, void *priv);
int mlxsw_sp_port_ets_set(struct mlxsw_sp_port *mlxsw_sp_port,
enum mlxsw_reg_qeec_hr hr, u8 index, u8 next_index,
bool dwrr, u8 dwrr_weight);
@@ -620,6 +636,15 @@ enum mlxsw_sp_acl_profile {
MLXSW_SP_ACL_PROFILE_MR,
};
+struct mlxsw_sp_acl_block {
+ struct list_head binding_list;
+ struct mlxsw_sp_acl_ruleset *ruleset_zero;
+ struct mlxsw_sp *mlxsw_sp;
+ unsigned int rule_count;
+ unsigned int disable_count;
+ struct net *net;
+};
+
struct mlxsw_afk *mlxsw_sp_acl_afk(struct mlxsw_sp_acl *acl);
struct mlxsw_sp *mlxsw_sp_acl_block_mlxsw_sp(struct mlxsw_sp_acl_block *block);
unsigned int mlxsw_sp_acl_block_rule_count(struct mlxsw_sp_acl_block *block);
@@ -782,19 +807,19 @@ extern const struct mlxsw_afk_ops mlxsw_sp2_afk_ops;
/* spectrum_flower.c */
int mlxsw_sp_flower_replace(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_block *block,
- struct tc_cls_flower_offload *f);
+ struct flow_cls_offload *f);
void mlxsw_sp_flower_destroy(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_block *block,
- struct tc_cls_flower_offload *f);
+ struct flow_cls_offload *f);
int mlxsw_sp_flower_stats(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_block *block,
- struct tc_cls_flower_offload *f);
+ struct flow_cls_offload *f);
int mlxsw_sp_flower_tmplt_create(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_block *block,
- struct tc_cls_flower_offload *f);
+ struct flow_cls_offload *f);
void mlxsw_sp_flower_tmplt_destroy(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_block *block,
- struct tc_cls_flower_offload *f);
+ struct flow_cls_offload *f);
/* spectrum_qdisc.c */
int mlxsw_sp_tc_qdisc_init(struct mlxsw_sp_port *mlxsw_sp_port);
@@ -805,6 +830,7 @@ int mlxsw_sp_setup_tc_prio(struct mlxsw_sp_port *mlxsw_sp_port,
struct tc_prio_qopt_offload *p);
/* spectrum_fid.c */
+bool mlxsw_sp_fid_is_dummy(struct mlxsw_sp *mlxsw_sp, u16 fid_index);
bool mlxsw_sp_fid_lag_vid_valid(const struct mlxsw_sp_fid *fid);
struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp *mlxsw_sp,
u16 fid_index);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
index a146a44634e9..e8ac90564dbe 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
@@ -45,14 +45,6 @@ struct mlxsw_sp_acl_block_binding {
bool ingress;
};
-struct mlxsw_sp_acl_block {
- struct list_head binding_list;
- struct mlxsw_sp_acl_ruleset *ruleset_zero;
- struct mlxsw_sp *mlxsw_sp;
- unsigned int rule_count;
- unsigned int disable_count;
-};
-
struct mlxsw_sp_acl_ruleset_ht_key {
struct mlxsw_sp_acl_block *block;
u32 chain_index;
@@ -221,6 +213,7 @@ struct mlxsw_sp_acl_block *mlxsw_sp_acl_block_create(struct mlxsw_sp *mlxsw_sp,
return NULL;
INIT_LIST_HEAD(&block->binding_list);
block->mlxsw_sp = mlxsw_sp;
+ block->net = net;
return block;
}
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 2a998dea4f39..279c241f76f0 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c
@@ -12,7 +12,7 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_dmac[] = {
MLXSW_AFK_ELEMENT_INST_BUF(DMAC_0_31, 0x02, 4),
MLXSW_AFK_ELEMENT_INST_U32(PCP, 0x08, 13, 3),
MLXSW_AFK_ELEMENT_INST_U32(VID, 0x08, 0, 12),
- MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x0C, 0, 8),
+ MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x0C, 0, 16),
};
static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_smac[] = {
@@ -20,7 +20,7 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_smac[] = {
MLXSW_AFK_ELEMENT_INST_BUF(SMAC_0_31, 0x02, 4),
MLXSW_AFK_ELEMENT_INST_U32(PCP, 0x08, 13, 3),
MLXSW_AFK_ELEMENT_INST_U32(VID, 0x08, 0, 12),
- MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x0C, 0, 8),
+ MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x0C, 0, 16),
};
static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_smac_ex[] = {
@@ -32,13 +32,13 @@ 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(IP_PROTO, 0x08, 0, 8),
- MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x0C, 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(IP_PROTO, 0x08, 0, 8),
- MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x0C, 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[] = {
@@ -149,7 +149,7 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_4[] = {
static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_5[] = {
MLXSW_AFK_ELEMENT_INST_U32(VID, 0x04, 16, 12),
- MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x04, 0, 8), /* RX_ACL_SYSTEM_PORT */
+ MLXSW_AFK_ELEMENT_INST_EXT_U32(SRC_SYS_PORT, 0x04, 0, 8, -1, true), /* RX_ACL_SYSTEM_PORT */
};
static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_0[] = {
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c
index 8512dd49e420..1537f70bc26d 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c
@@ -437,8 +437,8 @@ static const struct mlxsw_sp_sb_pr mlxsw_sp1_sb_prs[] = {
MLXSW_SP1_SB_PR_CPU_SIZE, true, false),
};
-#define MLXSW_SP2_SB_PR_INGRESS_SIZE 40960000
-#define MLXSW_SP2_SB_PR_EGRESS_SIZE 40960000
+#define MLXSW_SP2_SB_PR_INGRESS_SIZE 38128752
+#define MLXSW_SP2_SB_PR_EGRESS_SIZE 38128752
#define MLXSW_SP2_SB_PR_CPU_SIZE (256 * 1000)
/* Order according to mlxsw_sp2_sb_pool_dess */
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_dcb.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_dcb.c
index b25048c6c761..21296fa7f7fb 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_dcb.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_dcb.c
@@ -408,14 +408,6 @@ static int mlxsw_sp_port_dcb_app_update(struct mlxsw_sp_port *mlxsw_sp_port)
have_dscp = mlxsw_sp_port_dcb_app_prio_dscp_map(mlxsw_sp_port,
&prio_map);
- if (!have_dscp) {
- err = mlxsw_sp_port_dcb_toggle_trust(mlxsw_sp_port,
- MLXSW_REG_QPTS_TRUST_STATE_PCP);
- if (err)
- netdev_err(mlxsw_sp_port->dev, "Couldn't switch to trust L2\n");
- return err;
- }
-
mlxsw_sp_port_dcb_app_dscp_prio_map(mlxsw_sp_port, default_prio,
&dscp_map);
err = mlxsw_sp_port_dcb_app_update_qpdpm(mlxsw_sp_port,
@@ -432,6 +424,14 @@ static int mlxsw_sp_port_dcb_app_update(struct mlxsw_sp_port *mlxsw_sp_port)
return err;
}
+ if (!have_dscp) {
+ err = mlxsw_sp_port_dcb_toggle_trust(mlxsw_sp_port,
+ MLXSW_REG_QPTS_TRUST_STATE_PCP);
+ if (err)
+ netdev_err(mlxsw_sp_port->dev, "Couldn't switch to trust L2\n");
+ return err;
+ }
+
err = mlxsw_sp_port_dcb_toggle_trust(mlxsw_sp_port,
MLXSW_REG_QPTS_TRUST_STATE_DSCP);
if (err) {
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c
index 46baf3b44309..8df3cb21baa6 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c
@@ -126,6 +126,16 @@ 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;
+}
+
bool mlxsw_sp_fid_lag_vid_valid(const struct mlxsw_sp_fid *fid)
{
return fid->fid_family->lag_vid_valid;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
index 15f804453cd6..202e9a246019 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
@@ -120,8 +120,51 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp,
return 0;
}
+static int mlxsw_sp_flower_parse_meta(struct mlxsw_sp_acl_rule_info *rulei,
+ struct flow_cls_offload *f,
+ struct mlxsw_sp_acl_block *block)
+{
+ struct flow_rule *rule = flow_cls_offload_flow_rule(f);
+ struct mlxsw_sp_port *mlxsw_sp_port;
+ struct net_device *ingress_dev;
+ struct flow_match_meta match;
+
+ if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_META))
+ return 0;
+
+ flow_rule_match_meta(rule, &match);
+ if (match.mask->ingress_ifindex != 0xFFFFFFFF) {
+ NL_SET_ERR_MSG_MOD(f->common.extack, "Unsupported ingress ifindex mask");
+ return -EINVAL;
+ }
+
+ ingress_dev = __dev_get_by_index(block->net,
+ match.key->ingress_ifindex);
+ if (!ingress_dev) {
+ NL_SET_ERR_MSG_MOD(f->common.extack, "Can't find specified ingress port to match on");
+ return -EINVAL;
+ }
+
+ if (!mlxsw_sp_port_dev_check(ingress_dev)) {
+ NL_SET_ERR_MSG_MOD(f->common.extack, "Can't match on non-mlxsw ingress port");
+ return -EINVAL;
+ }
+
+ mlxsw_sp_port = netdev_priv(ingress_dev);
+ if (mlxsw_sp_port->mlxsw_sp != block->mlxsw_sp) {
+ NL_SET_ERR_MSG_MOD(f->common.extack, "Can't match on a port from different device");
+ return -EINVAL;
+ }
+
+ mlxsw_sp_acl_rulei_keymask_u32(rulei,
+ MLXSW_AFK_ELEMENT_SRC_SYS_PORT,
+ mlxsw_sp_port->local_port,
+ 0xFFFFFFFF);
+ return 0;
+}
+
static void mlxsw_sp_flower_parse_ipv4(struct mlxsw_sp_acl_rule_info *rulei,
- struct tc_cls_flower_offload *f)
+ struct flow_cls_offload *f)
{
struct flow_match_ipv4_addrs match;
@@ -136,7 +179,7 @@ static void mlxsw_sp_flower_parse_ipv4(struct mlxsw_sp_acl_rule_info *rulei,
}
static void mlxsw_sp_flower_parse_ipv6(struct mlxsw_sp_acl_rule_info *rulei,
- struct tc_cls_flower_offload *f)
+ struct flow_cls_offload *f)
{
struct flow_match_ipv6_addrs match;
@@ -170,10 +213,10 @@ static void mlxsw_sp_flower_parse_ipv6(struct mlxsw_sp_acl_rule_info *rulei,
static int mlxsw_sp_flower_parse_ports(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_rule_info *rulei,
- struct tc_cls_flower_offload *f,
+ struct flow_cls_offload *f,
u8 ip_proto)
{
- const struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
+ const struct flow_rule *rule = flow_cls_offload_flow_rule(f);
struct flow_match_ports match;
if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS))
@@ -197,10 +240,10 @@ static int mlxsw_sp_flower_parse_ports(struct mlxsw_sp *mlxsw_sp,
static int mlxsw_sp_flower_parse_tcp(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_rule_info *rulei,
- struct tc_cls_flower_offload *f,
+ struct flow_cls_offload *f,
u8 ip_proto)
{
- const struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
+ const struct flow_rule *rule = flow_cls_offload_flow_rule(f);
struct flow_match_tcp match;
if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_TCP))
@@ -222,10 +265,10 @@ static int mlxsw_sp_flower_parse_tcp(struct mlxsw_sp *mlxsw_sp,
static int mlxsw_sp_flower_parse_ip(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_rule_info *rulei,
- struct tc_cls_flower_offload *f,
+ struct flow_cls_offload *f,
u16 n_proto)
{
- const struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
+ const struct flow_rule *rule = flow_cls_offload_flow_rule(f);
struct flow_match_ip match;
if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IP))
@@ -247,8 +290,8 @@ static int mlxsw_sp_flower_parse_ip(struct mlxsw_sp *mlxsw_sp,
match.mask->tos & 0x3);
mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_IP_DSCP,
- match.key->tos >> 6,
- match.mask->tos >> 6);
+ match.key->tos >> 2,
+ match.mask->tos >> 2);
return 0;
}
@@ -256,9 +299,9 @@ static int mlxsw_sp_flower_parse_ip(struct mlxsw_sp *mlxsw_sp,
static int mlxsw_sp_flower_parse(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_block *block,
struct mlxsw_sp_acl_rule_info *rulei,
- struct tc_cls_flower_offload *f)
+ struct flow_cls_offload *f)
{
- struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
+ struct flow_rule *rule = flow_cls_offload_flow_rule(f);
struct flow_dissector *dissector = rule->match.dissector;
u16 n_proto_mask = 0;
u16 n_proto_key = 0;
@@ -267,7 +310,8 @@ static int mlxsw_sp_flower_parse(struct mlxsw_sp *mlxsw_sp,
int err;
if (dissector->used_keys &
- ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
+ ~(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) |
@@ -283,6 +327,10 @@ static int mlxsw_sp_flower_parse(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_acl_rulei_priority(rulei, f->common.prio);
+ err = mlxsw_sp_flower_parse_meta(rulei, f, block);
+ if (err)
+ return err;
+
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
struct flow_match_control match;
@@ -378,7 +426,7 @@ static int mlxsw_sp_flower_parse(struct mlxsw_sp *mlxsw_sp,
int mlxsw_sp_flower_replace(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_block *block,
- struct tc_cls_flower_offload *f)
+ struct flow_cls_offload *f)
{
struct mlxsw_sp_acl_rule_info *rulei;
struct mlxsw_sp_acl_ruleset *ruleset;
@@ -425,7 +473,7 @@ err_rule_create:
void mlxsw_sp_flower_destroy(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_block *block,
- struct tc_cls_flower_offload *f)
+ struct flow_cls_offload *f)
{
struct mlxsw_sp_acl_ruleset *ruleset;
struct mlxsw_sp_acl_rule *rule;
@@ -447,7 +495,7 @@ void mlxsw_sp_flower_destroy(struct mlxsw_sp *mlxsw_sp,
int mlxsw_sp_flower_stats(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_block *block,
- struct tc_cls_flower_offload *f)
+ struct flow_cls_offload *f)
{
struct mlxsw_sp_acl_ruleset *ruleset;
struct mlxsw_sp_acl_rule *rule;
@@ -483,7 +531,7 @@ err_rule_get_stats:
int mlxsw_sp_flower_tmplt_create(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_block *block,
- struct tc_cls_flower_offload *f)
+ struct flow_cls_offload *f)
{
struct mlxsw_sp_acl_ruleset *ruleset;
struct mlxsw_sp_acl_rule_info rulei;
@@ -504,7 +552,7 @@ int mlxsw_sp_flower_tmplt_create(struct mlxsw_sp *mlxsw_sp,
void mlxsw_sp_flower_tmplt_destroy(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_block *block,
- struct tc_cls_flower_offload *f)
+ struct flow_cls_offload *f)
{
struct mlxsw_sp_acl_ruleset *ruleset;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c
new file mode 100644
index 000000000000..bd9c2bc2d5d6
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c
@@ -0,0 +1,1111 @@
+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+/* Copyright (c) 2019 Mellanox Technologies. All rights reserved */
+
+#include <linux/ptp_clock_kernel.h>
+#include <linux/clocksource.h>
+#include <linux/timecounter.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/rhashtable.h>
+#include <linux/ptp_classify.h>
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+#include <linux/net_tstamp.h>
+
+#include "spectrum.h"
+#include "spectrum_ptp.h"
+#include "core.h"
+
+#define MLXSW_SP1_PTP_CLOCK_CYCLES_SHIFT 29
+#define MLXSW_SP1_PTP_CLOCK_FREQ_KHZ 156257 /* 6.4nSec */
+#define MLXSW_SP1_PTP_CLOCK_MASK 64
+
+#define MLXSW_SP1_PTP_HT_GC_INTERVAL 500 /* ms */
+
+/* How long, approximately, should the unmatched entries stay in the hash table
+ * before they are collected. Should be evenly divisible by the GC interval.
+ */
+#define MLXSW_SP1_PTP_HT_GC_TIMEOUT 1000 /* ms */
+
+struct mlxsw_sp_ptp_state {
+ struct mlxsw_sp *mlxsw_sp;
+ struct rhashtable unmatched_ht;
+ spinlock_t unmatched_lock; /* protects the HT */
+ struct delayed_work ht_gc_dw;
+ u32 gc_cycle;
+};
+
+struct mlxsw_sp1_ptp_key {
+ u8 local_port;
+ u8 message_type;
+ u16 sequence_id;
+ u8 domain_number;
+ bool ingress;
+};
+
+struct mlxsw_sp1_ptp_unmatched {
+ struct mlxsw_sp1_ptp_key key;
+ struct rhash_head ht_node;
+ struct rcu_head rcu;
+ struct sk_buff *skb;
+ u64 timestamp;
+ u32 gc_cycle;
+};
+
+static const struct rhashtable_params mlxsw_sp1_ptp_unmatched_ht_params = {
+ .key_len = sizeof_field(struct mlxsw_sp1_ptp_unmatched, key),
+ .key_offset = offsetof(struct mlxsw_sp1_ptp_unmatched, key),
+ .head_offset = offsetof(struct mlxsw_sp1_ptp_unmatched, ht_node),
+};
+
+struct mlxsw_sp_ptp_clock {
+ struct mlxsw_core *core;
+ spinlock_t lock; /* protect this structure */
+ struct cyclecounter cycles;
+ struct timecounter tc;
+ u32 nominal_c_mult;
+ struct ptp_clock *ptp;
+ struct ptp_clock_info ptp_info;
+ unsigned long overflow_period;
+ struct delayed_work overflow_work;
+};
+
+static u64 __mlxsw_sp1_ptp_read_frc(struct mlxsw_sp_ptp_clock *clock,
+ struct ptp_system_timestamp *sts)
+{
+ struct mlxsw_core *mlxsw_core = clock->core;
+ u32 frc_h1, frc_h2, frc_l;
+
+ frc_h1 = mlxsw_core_read_frc_h(mlxsw_core);
+ ptp_read_system_prets(sts);
+ frc_l = mlxsw_core_read_frc_l(mlxsw_core);
+ ptp_read_system_postts(sts);
+ frc_h2 = mlxsw_core_read_frc_h(mlxsw_core);
+
+ if (frc_h1 != frc_h2) {
+ /* wrap around */
+ ptp_read_system_prets(sts);
+ frc_l = mlxsw_core_read_frc_l(mlxsw_core);
+ ptp_read_system_postts(sts);
+ }
+
+ return (u64) frc_l | (u64) frc_h2 << 32;
+}
+
+static u64 mlxsw_sp1_ptp_read_frc(const struct cyclecounter *cc)
+{
+ struct mlxsw_sp_ptp_clock *clock =
+ container_of(cc, struct mlxsw_sp_ptp_clock, cycles);
+
+ return __mlxsw_sp1_ptp_read_frc(clock, NULL) & cc->mask;
+}
+
+static int
+mlxsw_sp1_ptp_phc_adjfreq(struct mlxsw_sp_ptp_clock *clock, int freq_adj)
+{
+ struct mlxsw_core *mlxsw_core = clock->core;
+ char mtutc_pl[MLXSW_REG_MTUTC_LEN];
+
+ mlxsw_reg_mtutc_pack(mtutc_pl, MLXSW_REG_MTUTC_OPERATION_ADJUST_FREQ,
+ freq_adj, 0);
+ return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mtutc), mtutc_pl);
+}
+
+static u64 mlxsw_sp1_ptp_ns2cycles(const struct timecounter *tc, u64 nsec)
+{
+ u64 cycles = (u64) nsec;
+
+ cycles <<= tc->cc->shift;
+ cycles = div_u64(cycles, tc->cc->mult);
+
+ return cycles;
+}
+
+static int
+mlxsw_sp1_ptp_phc_settime(struct mlxsw_sp_ptp_clock *clock, u64 nsec)
+{
+ struct mlxsw_core *mlxsw_core = clock->core;
+ u64 next_sec, next_sec_in_nsec, cycles;
+ char mtutc_pl[MLXSW_REG_MTUTC_LEN];
+ char mtpps_pl[MLXSW_REG_MTPPS_LEN];
+ int err;
+
+ next_sec = div_u64(nsec, NSEC_PER_SEC) + 1;
+ next_sec_in_nsec = next_sec * NSEC_PER_SEC;
+
+ spin_lock_bh(&clock->lock);
+ cycles = mlxsw_sp1_ptp_ns2cycles(&clock->tc, next_sec_in_nsec);
+ spin_unlock_bh(&clock->lock);
+
+ mlxsw_reg_mtpps_vpin_pack(mtpps_pl, cycles);
+ err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(mtpps), mtpps_pl);
+ if (err)
+ return err;
+
+ mlxsw_reg_mtutc_pack(mtutc_pl,
+ MLXSW_REG_MTUTC_OPERATION_SET_TIME_AT_NEXT_SEC,
+ 0, next_sec);
+ return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mtutc), mtutc_pl);
+}
+
+static int mlxsw_sp1_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
+{
+ struct mlxsw_sp_ptp_clock *clock =
+ container_of(ptp, struct mlxsw_sp_ptp_clock, ptp_info);
+ int neg_adj = 0;
+ u32 diff;
+ u64 adj;
+ s32 ppb;
+
+ ppb = scaled_ppm_to_ppb(scaled_ppm);
+
+ if (ppb < 0) {
+ neg_adj = 1;
+ ppb = -ppb;
+ }
+
+ adj = clock->nominal_c_mult;
+ adj *= ppb;
+ diff = div_u64(adj, NSEC_PER_SEC);
+
+ spin_lock_bh(&clock->lock);
+ timecounter_read(&clock->tc);
+ clock->cycles.mult = neg_adj ? clock->nominal_c_mult - diff :
+ clock->nominal_c_mult + diff;
+ spin_unlock_bh(&clock->lock);
+
+ return mlxsw_sp1_ptp_phc_adjfreq(clock, neg_adj ? -ppb : ppb);
+}
+
+static int mlxsw_sp1_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+ struct mlxsw_sp_ptp_clock *clock =
+ container_of(ptp, struct mlxsw_sp_ptp_clock, ptp_info);
+ u64 nsec;
+
+ spin_lock_bh(&clock->lock);
+ timecounter_adjtime(&clock->tc, delta);
+ nsec = timecounter_read(&clock->tc);
+ spin_unlock_bh(&clock->lock);
+
+ return mlxsw_sp1_ptp_phc_settime(clock, nsec);
+}
+
+static int mlxsw_sp1_ptp_gettimex(struct ptp_clock_info *ptp,
+ struct timespec64 *ts,
+ struct ptp_system_timestamp *sts)
+{
+ struct mlxsw_sp_ptp_clock *clock =
+ container_of(ptp, struct mlxsw_sp_ptp_clock, ptp_info);
+ u64 cycles, nsec;
+
+ spin_lock_bh(&clock->lock);
+ cycles = __mlxsw_sp1_ptp_read_frc(clock, sts);
+ nsec = timecounter_cyc2time(&clock->tc, cycles);
+ spin_unlock_bh(&clock->lock);
+
+ *ts = ns_to_timespec64(nsec);
+
+ return 0;
+}
+
+static int mlxsw_sp1_ptp_settime(struct ptp_clock_info *ptp,
+ const struct timespec64 *ts)
+{
+ struct mlxsw_sp_ptp_clock *clock =
+ container_of(ptp, struct mlxsw_sp_ptp_clock, ptp_info);
+ u64 nsec = timespec64_to_ns(ts);
+
+ spin_lock_bh(&clock->lock);
+ timecounter_init(&clock->tc, &clock->cycles, nsec);
+ nsec = timecounter_read(&clock->tc);
+ spin_unlock_bh(&clock->lock);
+
+ return mlxsw_sp1_ptp_phc_settime(clock, nsec);
+}
+
+static const struct ptp_clock_info mlxsw_sp1_ptp_clock_info = {
+ .owner = THIS_MODULE,
+ .name = "mlxsw_sp_clock",
+ .max_adj = 100000000,
+ .adjfine = mlxsw_sp1_ptp_adjfine,
+ .adjtime = mlxsw_sp1_ptp_adjtime,
+ .gettimex64 = mlxsw_sp1_ptp_gettimex,
+ .settime64 = mlxsw_sp1_ptp_settime,
+};
+
+static void mlxsw_sp1_ptp_clock_overflow(struct work_struct *work)
+{
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct mlxsw_sp_ptp_clock *clock;
+
+ clock = container_of(dwork, struct mlxsw_sp_ptp_clock, overflow_work);
+
+ spin_lock_bh(&clock->lock);
+ timecounter_read(&clock->tc);
+ spin_unlock_bh(&clock->lock);
+ mlxsw_core_schedule_dw(&clock->overflow_work, clock->overflow_period);
+}
+
+struct mlxsw_sp_ptp_clock *
+mlxsw_sp1_ptp_clock_init(struct mlxsw_sp *mlxsw_sp, struct device *dev)
+{
+ u64 overflow_cycles, nsec, frac = 0;
+ struct mlxsw_sp_ptp_clock *clock;
+ int err;
+
+ clock = kzalloc(sizeof(*clock), GFP_KERNEL);
+ if (!clock)
+ return ERR_PTR(-ENOMEM);
+
+ spin_lock_init(&clock->lock);
+ clock->cycles.read = mlxsw_sp1_ptp_read_frc;
+ clock->cycles.shift = MLXSW_SP1_PTP_CLOCK_CYCLES_SHIFT;
+ clock->cycles.mult = clocksource_khz2mult(MLXSW_SP1_PTP_CLOCK_FREQ_KHZ,
+ clock->cycles.shift);
+ clock->nominal_c_mult = clock->cycles.mult;
+ clock->cycles.mask = CLOCKSOURCE_MASK(MLXSW_SP1_PTP_CLOCK_MASK);
+ clock->core = mlxsw_sp->core;
+
+ timecounter_init(&clock->tc, &clock->cycles,
+ ktime_to_ns(ktime_get_real()));
+
+ /* Calculate period in seconds to call the overflow watchdog - to make
+ * sure counter is checked at least twice every wrap around.
+ * The period is calculated as the minimum between max HW cycles count
+ * (The clock source mask) and max amount of cycles that can be
+ * multiplied by clock multiplier where the result doesn't exceed
+ * 64bits.
+ */
+ overflow_cycles = div64_u64(~0ULL >> 1, clock->cycles.mult);
+ overflow_cycles = min(overflow_cycles, div_u64(clock->cycles.mask, 3));
+
+ nsec = cyclecounter_cyc2ns(&clock->cycles, overflow_cycles, 0, &frac);
+ clock->overflow_period = nsecs_to_jiffies(nsec);
+
+ INIT_DELAYED_WORK(&clock->overflow_work, mlxsw_sp1_ptp_clock_overflow);
+ mlxsw_core_schedule_dw(&clock->overflow_work, 0);
+
+ clock->ptp_info = mlxsw_sp1_ptp_clock_info;
+ clock->ptp = ptp_clock_register(&clock->ptp_info, dev);
+ if (IS_ERR(clock->ptp)) {
+ err = PTR_ERR(clock->ptp);
+ dev_err(dev, "ptp_clock_register failed %d\n", err);
+ goto err_ptp_clock_register;
+ }
+
+ return clock;
+
+err_ptp_clock_register:
+ cancel_delayed_work_sync(&clock->overflow_work);
+ kfree(clock);
+ return ERR_PTR(err);
+}
+
+void mlxsw_sp1_ptp_clock_fini(struct mlxsw_sp_ptp_clock *clock)
+{
+ ptp_clock_unregister(clock->ptp);
+ cancel_delayed_work_sync(&clock->overflow_work);
+ kfree(clock);
+}
+
+static int mlxsw_sp_ptp_parse(struct sk_buff *skb,
+ u8 *p_domain_number,
+ u8 *p_message_type,
+ u16 *p_sequence_id)
+{
+ unsigned int offset = 0;
+ unsigned int ptp_class;
+ u8 *data;
+
+ data = skb_mac_header(skb);
+ ptp_class = ptp_classify_raw(skb);
+
+ switch (ptp_class & PTP_CLASS_VMASK) {
+ case PTP_CLASS_V1:
+ case PTP_CLASS_V2:
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ if (ptp_class & PTP_CLASS_VLAN)
+ offset += VLAN_HLEN;
+
+ switch (ptp_class & PTP_CLASS_PMASK) {
+ case PTP_CLASS_IPV4:
+ offset += ETH_HLEN + IPV4_HLEN(data + offset) + UDP_HLEN;
+ break;
+ case PTP_CLASS_IPV6:
+ offset += ETH_HLEN + IP6_HLEN + UDP_HLEN;
+ break;
+ case PTP_CLASS_L2:
+ offset += ETH_HLEN;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ /* PTP header is 34 bytes. */
+ if (skb->len < offset + 34)
+ return -EINVAL;
+
+ *p_message_type = data[offset] & 0x0f;
+ *p_domain_number = data[offset + 4];
+ *p_sequence_id = (u16)(data[offset + 30]) << 8 | data[offset + 31];
+ return 0;
+}
+
+/* Returns NULL on successful insertion, a pointer on conflict, or an ERR_PTR on
+ * error.
+ */
+static struct mlxsw_sp1_ptp_unmatched *
+mlxsw_sp1_ptp_unmatched_save(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp1_ptp_key key,
+ struct sk_buff *skb,
+ u64 timestamp)
+{
+ int cycles = MLXSW_SP1_PTP_HT_GC_TIMEOUT / MLXSW_SP1_PTP_HT_GC_INTERVAL;
+ struct mlxsw_sp_ptp_state *ptp_state = mlxsw_sp->ptp_state;
+ struct mlxsw_sp1_ptp_unmatched *unmatched;
+ struct mlxsw_sp1_ptp_unmatched *conflict;
+
+ unmatched = kzalloc(sizeof(*unmatched), GFP_ATOMIC);
+ if (!unmatched)
+ return ERR_PTR(-ENOMEM);
+
+ unmatched->key = key;
+ unmatched->skb = skb;
+ unmatched->timestamp = timestamp;
+ unmatched->gc_cycle = mlxsw_sp->ptp_state->gc_cycle + cycles;
+
+ conflict = rhashtable_lookup_get_insert_fast(&ptp_state->unmatched_ht,
+ &unmatched->ht_node,
+ mlxsw_sp1_ptp_unmatched_ht_params);
+ if (conflict)
+ kfree(unmatched);
+
+ return conflict;
+}
+
+static struct mlxsw_sp1_ptp_unmatched *
+mlxsw_sp1_ptp_unmatched_lookup(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp1_ptp_key key)
+{
+ return rhashtable_lookup(&mlxsw_sp->ptp_state->unmatched_ht, &key,
+ mlxsw_sp1_ptp_unmatched_ht_params);
+}
+
+static int
+mlxsw_sp1_ptp_unmatched_remove(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp1_ptp_unmatched *unmatched)
+{
+ return rhashtable_remove_fast(&mlxsw_sp->ptp_state->unmatched_ht,
+ &unmatched->ht_node,
+ mlxsw_sp1_ptp_unmatched_ht_params);
+}
+
+/* This function is called in the following scenarios:
+ *
+ * 1) When a packet is matched with its timestamp.
+ * 2) In several situation when it is necessary to immediately pass on
+ * an SKB without a timestamp.
+ * 3) From GC indirectly through mlxsw_sp1_ptp_unmatched_finish().
+ * This case is similar to 2) above.
+ */
+static void mlxsw_sp1_ptp_packet_finish(struct mlxsw_sp *mlxsw_sp,
+ struct sk_buff *skb, u8 local_port,
+ bool ingress,
+ struct skb_shared_hwtstamps *hwtstamps)
+{
+ struct mlxsw_sp_port *mlxsw_sp_port;
+
+ /* Between capturing the packet and finishing it, there is a window of
+ * opportunity for the originating port to go away (e.g. due to a
+ * split). Also make sure the SKB device reference is still valid.
+ */
+ mlxsw_sp_port = mlxsw_sp->ports[local_port];
+ if (!(mlxsw_sp_port && (!skb->dev || skb->dev == mlxsw_sp_port->dev))) {
+ dev_kfree_skb_any(skb);
+ return;
+ }
+
+ if (ingress) {
+ if (hwtstamps)
+ *skb_hwtstamps(skb) = *hwtstamps;
+ mlxsw_sp_rx_listener_no_mark_func(skb, local_port, mlxsw_sp);
+ } else {
+ /* skb_tstamp_tx() allows hwtstamps to be NULL. */
+ skb_tstamp_tx(skb, hwtstamps);
+ dev_kfree_skb_any(skb);
+ }
+}
+
+static void mlxsw_sp1_packet_timestamp(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp1_ptp_key key,
+ struct sk_buff *skb,
+ u64 timestamp)
+{
+ struct skb_shared_hwtstamps hwtstamps;
+ u64 nsec;
+
+ spin_lock_bh(&mlxsw_sp->clock->lock);
+ nsec = timecounter_cyc2time(&mlxsw_sp->clock->tc, timestamp);
+ spin_unlock_bh(&mlxsw_sp->clock->lock);
+
+ hwtstamps.hwtstamp = ns_to_ktime(nsec);
+ mlxsw_sp1_ptp_packet_finish(mlxsw_sp, skb,
+ key.local_port, key.ingress, &hwtstamps);
+}
+
+static void
+mlxsw_sp1_ptp_unmatched_finish(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp1_ptp_unmatched *unmatched)
+{
+ if (unmatched->skb && unmatched->timestamp)
+ mlxsw_sp1_packet_timestamp(mlxsw_sp, unmatched->key,
+ unmatched->skb,
+ unmatched->timestamp);
+ else if (unmatched->skb)
+ mlxsw_sp1_ptp_packet_finish(mlxsw_sp, unmatched->skb,
+ unmatched->key.local_port,
+ unmatched->key.ingress, NULL);
+ kfree_rcu(unmatched, rcu);
+}
+
+static void mlxsw_sp1_ptp_unmatched_free_fn(void *ptr, void *arg)
+{
+ struct mlxsw_sp1_ptp_unmatched *unmatched = ptr;
+
+ /* This is invoked at a point where the ports are gone already. Nothing
+ * to do with whatever is left in the HT but to free it.
+ */
+ if (unmatched->skb)
+ dev_kfree_skb_any(unmatched->skb);
+ kfree_rcu(unmatched, rcu);
+}
+
+static void mlxsw_sp1_ptp_got_piece(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp1_ptp_key key,
+ struct sk_buff *skb, u64 timestamp)
+{
+ struct mlxsw_sp1_ptp_unmatched *unmatched, *conflict;
+ int err;
+
+ rcu_read_lock();
+
+ unmatched = mlxsw_sp1_ptp_unmatched_lookup(mlxsw_sp, key);
+
+ spin_lock(&mlxsw_sp->ptp_state->unmatched_lock);
+
+ if (unmatched) {
+ /* There was an unmatched entry when we looked, but it may have
+ * been removed before we took the lock.
+ */
+ err = mlxsw_sp1_ptp_unmatched_remove(mlxsw_sp, unmatched);
+ if (err)
+ unmatched = NULL;
+ }
+
+ if (!unmatched) {
+ /* We have no unmatched entry, but one may have been added after
+ * we looked, but before we took the lock.
+ */
+ unmatched = mlxsw_sp1_ptp_unmatched_save(mlxsw_sp, key,
+ skb, timestamp);
+ if (IS_ERR(unmatched)) {
+ if (skb)
+ mlxsw_sp1_ptp_packet_finish(mlxsw_sp, skb,
+ key.local_port,
+ key.ingress, NULL);
+ unmatched = NULL;
+ } else if (unmatched) {
+ /* Save just told us, under lock, that the entry is
+ * there, so this has to work.
+ */
+ err = mlxsw_sp1_ptp_unmatched_remove(mlxsw_sp,
+ unmatched);
+ WARN_ON_ONCE(err);
+ }
+ }
+
+ /* If unmatched is non-NULL here, it comes either from the lookup, or
+ * from the save attempt above. In either case the entry was removed
+ * from the hash table. If unmatched is NULL, a new unmatched entry was
+ * added to the hash table, and there was no conflict.
+ */
+
+ if (skb && unmatched && unmatched->timestamp) {
+ unmatched->skb = skb;
+ } else if (timestamp && unmatched && unmatched->skb) {
+ unmatched->timestamp = timestamp;
+ } else if (unmatched) {
+ /* unmatched holds an older entry of the same type: either an
+ * skb if we are handling skb, or a timestamp if we are handling
+ * timestamp. We can't match that up, so save what we have.
+ */
+ conflict = mlxsw_sp1_ptp_unmatched_save(mlxsw_sp, key,
+ skb, timestamp);
+ if (IS_ERR(conflict)) {
+ if (skb)
+ mlxsw_sp1_ptp_packet_finish(mlxsw_sp, skb,
+ key.local_port,
+ key.ingress, NULL);
+ } else {
+ /* Above, we removed an object with this key from the
+ * hash table, under lock, so conflict can not be a
+ * valid pointer.
+ */
+ WARN_ON_ONCE(conflict);
+ }
+ }
+
+ spin_unlock(&mlxsw_sp->ptp_state->unmatched_lock);
+
+ if (unmatched)
+ mlxsw_sp1_ptp_unmatched_finish(mlxsw_sp, unmatched);
+
+ rcu_read_unlock();
+}
+
+static void mlxsw_sp1_ptp_got_packet(struct mlxsw_sp *mlxsw_sp,
+ struct sk_buff *skb, u8 local_port,
+ bool ingress)
+{
+ struct mlxsw_sp_port *mlxsw_sp_port;
+ struct mlxsw_sp1_ptp_key key;
+ u8 types;
+ int err;
+
+ mlxsw_sp_port = mlxsw_sp->ports[local_port];
+ if (!mlxsw_sp_port)
+ goto immediate;
+
+ types = ingress ? mlxsw_sp_port->ptp.ing_types :
+ mlxsw_sp_port->ptp.egr_types;
+ if (!types)
+ goto immediate;
+
+ memset(&key, 0, sizeof(key));
+ key.local_port = local_port;
+ key.ingress = ingress;
+
+ err = mlxsw_sp_ptp_parse(skb, &key.domain_number, &key.message_type,
+ &key.sequence_id);
+ if (err)
+ goto immediate;
+
+ /* For packets whose timestamping was not enabled on this port, don't
+ * bother trying to match the timestamp.
+ */
+ if (!((1 << key.message_type) & types))
+ goto immediate;
+
+ mlxsw_sp1_ptp_got_piece(mlxsw_sp, key, skb, 0);
+ return;
+
+immediate:
+ mlxsw_sp1_ptp_packet_finish(mlxsw_sp, skb, local_port, ingress, NULL);
+}
+
+void mlxsw_sp1_ptp_got_timestamp(struct mlxsw_sp *mlxsw_sp, bool ingress,
+ u8 local_port, u8 message_type,
+ u8 domain_number, u16 sequence_id,
+ u64 timestamp)
+{
+ struct mlxsw_sp_port *mlxsw_sp_port;
+ struct mlxsw_sp1_ptp_key key;
+ u8 types;
+
+ mlxsw_sp_port = mlxsw_sp->ports[local_port];
+ if (!mlxsw_sp_port)
+ return;
+
+ types = ingress ? mlxsw_sp_port->ptp.ing_types :
+ mlxsw_sp_port->ptp.egr_types;
+
+ /* For message types whose timestamping was not enabled on this port,
+ * don't bother with the timestamp.
+ */
+ if (!((1 << message_type) & types))
+ return;
+
+ memset(&key, 0, sizeof(key));
+ key.local_port = local_port;
+ key.domain_number = domain_number;
+ key.message_type = message_type;
+ key.sequence_id = sequence_id;
+ key.ingress = ingress;
+
+ mlxsw_sp1_ptp_got_piece(mlxsw_sp, key, NULL, timestamp);
+}
+
+void mlxsw_sp1_ptp_receive(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb,
+ u8 local_port)
+{
+ skb_reset_mac_header(skb);
+ mlxsw_sp1_ptp_got_packet(mlxsw_sp, skb, local_port, true);
+}
+
+void mlxsw_sp1_ptp_transmitted(struct mlxsw_sp *mlxsw_sp,
+ struct sk_buff *skb, u8 local_port)
+{
+ mlxsw_sp1_ptp_got_packet(mlxsw_sp, skb, local_port, false);
+}
+
+static void
+mlxsw_sp1_ptp_ht_gc_collect(struct mlxsw_sp_ptp_state *ptp_state,
+ struct mlxsw_sp1_ptp_unmatched *unmatched)
+{
+ int err;
+
+ /* If an unmatched entry has an SKB, it has to be handed over to the
+ * networking stack. This is usually done from a trap handler, which is
+ * invoked in a softirq context. Here we are going to do it in process
+ * context. If that were to be interrupted by a softirq, it could cause
+ * a deadlock when an attempt is made to take an already-taken lock
+ * somewhere along the sending path. Disable softirqs to prevent this.
+ */
+ local_bh_disable();
+
+ spin_lock(&ptp_state->unmatched_lock);
+ err = rhashtable_remove_fast(&ptp_state->unmatched_ht,
+ &unmatched->ht_node,
+ mlxsw_sp1_ptp_unmatched_ht_params);
+ spin_unlock(&ptp_state->unmatched_lock);
+
+ if (err)
+ /* The packet was matched with timestamp during the walk. */
+ goto out;
+
+ /* mlxsw_sp1_ptp_unmatched_finish() invokes netif_receive_skb(). While
+ * the comment at that function states that it can only be called in
+ * soft IRQ context, this pattern of local_bh_disable() +
+ * netif_receive_skb(), in process context, is seen elsewhere in the
+ * kernel, notably in pktgen.
+ */
+ mlxsw_sp1_ptp_unmatched_finish(ptp_state->mlxsw_sp, unmatched);
+
+out:
+ local_bh_enable();
+}
+
+static void mlxsw_sp1_ptp_ht_gc(struct work_struct *work)
+{
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct mlxsw_sp1_ptp_unmatched *unmatched;
+ struct mlxsw_sp_ptp_state *ptp_state;
+ struct rhashtable_iter iter;
+ u32 gc_cycle;
+ void *obj;
+
+ ptp_state = container_of(dwork, struct mlxsw_sp_ptp_state, ht_gc_dw);
+ gc_cycle = ptp_state->gc_cycle++;
+
+ rhashtable_walk_enter(&ptp_state->unmatched_ht, &iter);
+ rhashtable_walk_start(&iter);
+ while ((obj = rhashtable_walk_next(&iter))) {
+ if (IS_ERR(obj))
+ continue;
+
+ unmatched = obj;
+ if (unmatched->gc_cycle <= gc_cycle)
+ mlxsw_sp1_ptp_ht_gc_collect(ptp_state, unmatched);
+ }
+ rhashtable_walk_stop(&iter);
+ rhashtable_walk_exit(&iter);
+
+ mlxsw_core_schedule_dw(&ptp_state->ht_gc_dw,
+ MLXSW_SP1_PTP_HT_GC_INTERVAL);
+}
+
+static int mlxsw_sp_ptp_mtptpt_set(struct mlxsw_sp *mlxsw_sp,
+ enum mlxsw_reg_mtptpt_trap_id trap_id,
+ u16 message_type)
+{
+ char mtptpt_pl[MLXSW_REG_MTPTPT_LEN];
+
+ mlxsw_reg_mtptptp_pack(mtptpt_pl, trap_id, message_type);
+ return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mtptpt), mtptpt_pl);
+}
+
+static int mlxsw_sp1_ptp_set_fifo_clr_on_trap(struct mlxsw_sp *mlxsw_sp,
+ bool clr)
+{
+ char mogcr_pl[MLXSW_REG_MOGCR_LEN] = {0};
+ int err;
+
+ err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(mogcr), mogcr_pl);
+ if (err)
+ return err;
+
+ mlxsw_reg_mogcr_ptp_iftc_set(mogcr_pl, clr);
+ mlxsw_reg_mogcr_ptp_eftc_set(mogcr_pl, clr);
+ return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mogcr), mogcr_pl);
+}
+
+static int mlxsw_sp1_ptp_mtpppc_set(struct mlxsw_sp *mlxsw_sp,
+ u16 ing_types, u16 egr_types)
+{
+ char mtpppc_pl[MLXSW_REG_MTPPPC_LEN];
+
+ mlxsw_reg_mtpppc_pack(mtpppc_pl, ing_types, egr_types);
+ return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mtpppc), mtpppc_pl);
+}
+
+struct mlxsw_sp1_ptp_shaper_params {
+ u32 ethtool_speed;
+ enum mlxsw_reg_qpsc_port_speed port_speed;
+ u8 shaper_time_exp;
+ u8 shaper_time_mantissa;
+ u8 shaper_inc;
+ u8 shaper_bs;
+ u8 port_to_shaper_credits;
+ int ing_timestamp_inc;
+ int egr_timestamp_inc;
+};
+
+static const struct mlxsw_sp1_ptp_shaper_params
+mlxsw_sp1_ptp_shaper_params[] = {
+ {
+ .ethtool_speed = SPEED_100,
+ .port_speed = MLXSW_REG_QPSC_PORT_SPEED_100M,
+ .shaper_time_exp = 4,
+ .shaper_time_mantissa = 12,
+ .shaper_inc = 9,
+ .shaper_bs = 1,
+ .port_to_shaper_credits = 1,
+ .ing_timestamp_inc = -313,
+ .egr_timestamp_inc = 313,
+ },
+ {
+ .ethtool_speed = SPEED_1000,
+ .port_speed = MLXSW_REG_QPSC_PORT_SPEED_1G,
+ .shaper_time_exp = 0,
+ .shaper_time_mantissa = 12,
+ .shaper_inc = 6,
+ .shaper_bs = 0,
+ .port_to_shaper_credits = 1,
+ .ing_timestamp_inc = -35,
+ .egr_timestamp_inc = 35,
+ },
+ {
+ .ethtool_speed = SPEED_10000,
+ .port_speed = MLXSW_REG_QPSC_PORT_SPEED_10G,
+ .shaper_time_exp = 0,
+ .shaper_time_mantissa = 2,
+ .shaper_inc = 14,
+ .shaper_bs = 1,
+ .port_to_shaper_credits = 1,
+ .ing_timestamp_inc = -11,
+ .egr_timestamp_inc = 11,
+ },
+ {
+ .ethtool_speed = SPEED_25000,
+ .port_speed = MLXSW_REG_QPSC_PORT_SPEED_25G,
+ .shaper_time_exp = 0,
+ .shaper_time_mantissa = 0,
+ .shaper_inc = 11,
+ .shaper_bs = 1,
+ .port_to_shaper_credits = 1,
+ .ing_timestamp_inc = -14,
+ .egr_timestamp_inc = 14,
+ },
+};
+
+#define MLXSW_SP1_PTP_SHAPER_PARAMS_LEN ARRAY_SIZE(mlxsw_sp1_ptp_shaper_params)
+
+static int mlxsw_sp1_ptp_shaper_params_set(struct mlxsw_sp *mlxsw_sp)
+{
+ const struct mlxsw_sp1_ptp_shaper_params *params;
+ char qpsc_pl[MLXSW_REG_QPSC_LEN];
+ int i, err;
+
+ for (i = 0; i < MLXSW_SP1_PTP_SHAPER_PARAMS_LEN; i++) {
+ params = &mlxsw_sp1_ptp_shaper_params[i];
+ mlxsw_reg_qpsc_pack(qpsc_pl, params->port_speed,
+ params->shaper_time_exp,
+ params->shaper_time_mantissa,
+ params->shaper_inc, params->shaper_bs,
+ params->port_to_shaper_credits,
+ params->ing_timestamp_inc,
+ params->egr_timestamp_inc);
+ err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpsc), qpsc_pl);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+struct mlxsw_sp_ptp_state *mlxsw_sp1_ptp_init(struct mlxsw_sp *mlxsw_sp)
+{
+ struct mlxsw_sp_ptp_state *ptp_state;
+ u16 message_type;
+ int err;
+
+ err = mlxsw_sp1_ptp_shaper_params_set(mlxsw_sp);
+ if (err)
+ return ERR_PTR(err);
+
+ ptp_state = kzalloc(sizeof(*ptp_state), GFP_KERNEL);
+ if (!ptp_state)
+ return ERR_PTR(-ENOMEM);
+ ptp_state->mlxsw_sp = mlxsw_sp;
+
+ spin_lock_init(&ptp_state->unmatched_lock);
+
+ err = rhashtable_init(&ptp_state->unmatched_ht,
+ &mlxsw_sp1_ptp_unmatched_ht_params);
+ if (err)
+ goto err_hashtable_init;
+
+ /* Delive these message types as PTP0. */
+ message_type = BIT(MLXSW_SP_PTP_MESSAGE_TYPE_SYNC) |
+ BIT(MLXSW_SP_PTP_MESSAGE_TYPE_DELAY_REQ) |
+ BIT(MLXSW_SP_PTP_MESSAGE_TYPE_PDELAY_REQ) |
+ BIT(MLXSW_SP_PTP_MESSAGE_TYPE_PDELAY_RESP);
+ err = mlxsw_sp_ptp_mtptpt_set(mlxsw_sp, MLXSW_REG_MTPTPT_TRAP_ID_PTP0,
+ message_type);
+ if (err)
+ goto err_mtptpt_set;
+
+ /* Everything else is PTP1. */
+ message_type = ~message_type;
+ err = mlxsw_sp_ptp_mtptpt_set(mlxsw_sp, MLXSW_REG_MTPTPT_TRAP_ID_PTP1,
+ message_type);
+ if (err)
+ goto err_mtptpt1_set;
+
+ err = mlxsw_sp1_ptp_set_fifo_clr_on_trap(mlxsw_sp, true);
+ if (err)
+ goto err_fifo_clr;
+
+ INIT_DELAYED_WORK(&ptp_state->ht_gc_dw, mlxsw_sp1_ptp_ht_gc);
+ mlxsw_core_schedule_dw(&ptp_state->ht_gc_dw,
+ MLXSW_SP1_PTP_HT_GC_INTERVAL);
+ return ptp_state;
+
+err_fifo_clr:
+ mlxsw_sp_ptp_mtptpt_set(mlxsw_sp, MLXSW_REG_MTPTPT_TRAP_ID_PTP1, 0);
+err_mtptpt1_set:
+ mlxsw_sp_ptp_mtptpt_set(mlxsw_sp, MLXSW_REG_MTPTPT_TRAP_ID_PTP0, 0);
+err_mtptpt_set:
+ rhashtable_destroy(&ptp_state->unmatched_ht);
+err_hashtable_init:
+ kfree(ptp_state);
+ return ERR_PTR(err);
+}
+
+void mlxsw_sp1_ptp_fini(struct mlxsw_sp_ptp_state *ptp_state)
+{
+ struct mlxsw_sp *mlxsw_sp = ptp_state->mlxsw_sp;
+
+ cancel_delayed_work_sync(&ptp_state->ht_gc_dw);
+ mlxsw_sp1_ptp_mtpppc_set(mlxsw_sp, 0, 0);
+ mlxsw_sp1_ptp_set_fifo_clr_on_trap(mlxsw_sp, false);
+ mlxsw_sp_ptp_mtptpt_set(mlxsw_sp, MLXSW_REG_MTPTPT_TRAP_ID_PTP1, 0);
+ mlxsw_sp_ptp_mtptpt_set(mlxsw_sp, MLXSW_REG_MTPTPT_TRAP_ID_PTP0, 0);
+ rhashtable_free_and_destroy(&ptp_state->unmatched_ht,
+ &mlxsw_sp1_ptp_unmatched_free_fn, NULL);
+ kfree(ptp_state);
+}
+
+int mlxsw_sp1_ptp_hwtstamp_get(struct mlxsw_sp_port *mlxsw_sp_port,
+ struct hwtstamp_config *config)
+{
+ *config = mlxsw_sp_port->ptp.hwtstamp_config;
+ return 0;
+}
+
+static int mlxsw_sp_ptp_get_message_types(const struct hwtstamp_config *config,
+ u16 *p_ing_types, u16 *p_egr_types,
+ enum hwtstamp_rx_filters *p_rx_filter)
+{
+ enum hwtstamp_rx_filters rx_filter = config->rx_filter;
+ enum hwtstamp_tx_types tx_type = config->tx_type;
+ u16 ing_types = 0x00;
+ u16 egr_types = 0x00;
+
+ switch (tx_type) {
+ case HWTSTAMP_TX_OFF:
+ egr_types = 0x00;
+ break;
+ case HWTSTAMP_TX_ON:
+ egr_types = 0xff;
+ break;
+ case HWTSTAMP_TX_ONESTEP_SYNC:
+ return -ERANGE;
+ }
+
+ switch (rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ ing_types = 0x00;
+ break;
+ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_SYNC:
+ ing_types = 0x01;
+ break;
+ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+ ing_types = 0x02;
+ break;
+ case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_EVENT:
+ ing_types = 0x0f;
+ break;
+ case HWTSTAMP_FILTER_ALL:
+ ing_types = 0xff;
+ break;
+ case HWTSTAMP_FILTER_SOME:
+ case HWTSTAMP_FILTER_NTP_ALL:
+ return -ERANGE;
+ }
+
+ *p_ing_types = ing_types;
+ *p_egr_types = egr_types;
+ *p_rx_filter = rx_filter;
+ return 0;
+}
+
+static int mlxsw_sp1_ptp_mtpppc_update(struct mlxsw_sp_port *mlxsw_sp_port,
+ u16 ing_types, u16 egr_types)
+{
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+ struct mlxsw_sp_port *tmp;
+ int i;
+
+ /* MTPPPC configures timestamping globally, not per port. Find the
+ * configuration that contains all configured timestamping requests.
+ */
+ for (i = 1; i < mlxsw_core_max_ports(mlxsw_sp->core); i++) {
+ tmp = mlxsw_sp->ports[i];
+ if (tmp && tmp != mlxsw_sp_port) {
+ ing_types |= tmp->ptp.ing_types;
+ egr_types |= tmp->ptp.egr_types;
+ }
+ }
+
+ return mlxsw_sp1_ptp_mtpppc_set(mlxsw_sp_port->mlxsw_sp,
+ ing_types, egr_types);
+}
+
+static bool mlxsw_sp1_ptp_hwtstamp_enabled(struct mlxsw_sp_port *mlxsw_sp_port)
+{
+ return mlxsw_sp_port->ptp.ing_types || mlxsw_sp_port->ptp.egr_types;
+}
+
+static int
+mlxsw_sp1_ptp_port_shaper_set(struct mlxsw_sp_port *mlxsw_sp_port, bool enable)
+{
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+ char qeec_pl[MLXSW_REG_QEEC_LEN];
+
+ mlxsw_reg_qeec_ptps_pack(qeec_pl, mlxsw_sp_port->local_port, enable);
+ return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qeec), qeec_pl);
+}
+
+static int mlxsw_sp1_ptp_port_shaper_check(struct mlxsw_sp_port *mlxsw_sp_port)
+{
+ const struct mlxsw_sp_port_type_speed_ops *port_type_speed_ops;
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+ char ptys_pl[MLXSW_REG_PTYS_LEN];
+ u32 eth_proto_oper, speed;
+ bool ptps = false;
+ int err, i;
+
+ if (!mlxsw_sp1_ptp_hwtstamp_enabled(mlxsw_sp_port))
+ return mlxsw_sp1_ptp_port_shaper_set(mlxsw_sp_port, false);
+
+ port_type_speed_ops = mlxsw_sp->port_type_speed_ops;
+ port_type_speed_ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl,
+ mlxsw_sp_port->local_port, 0,
+ false);
+ err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl);
+ if (err)
+ return err;
+ port_type_speed_ops->reg_ptys_eth_unpack(mlxsw_sp, ptys_pl, NULL, NULL,
+ &eth_proto_oper);
+
+ speed = port_type_speed_ops->from_ptys_speed(mlxsw_sp, eth_proto_oper);
+ for (i = 0; i < MLXSW_SP1_PTP_SHAPER_PARAMS_LEN; i++) {
+ if (mlxsw_sp1_ptp_shaper_params[i].ethtool_speed == speed) {
+ ptps = true;
+ break;
+ }
+ }
+
+ return mlxsw_sp1_ptp_port_shaper_set(mlxsw_sp_port, ptps);
+}
+
+void mlxsw_sp1_ptp_shaper_work(struct work_struct *work)
+{
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct mlxsw_sp_port *mlxsw_sp_port;
+ int err;
+
+ mlxsw_sp_port = container_of(dwork, struct mlxsw_sp_port,
+ ptp.shaper_dw);
+
+ if (!mlxsw_sp1_ptp_hwtstamp_enabled(mlxsw_sp_port))
+ return;
+
+ err = mlxsw_sp1_ptp_port_shaper_check(mlxsw_sp_port);
+ if (err)
+ netdev_err(mlxsw_sp_port->dev, "Failed to set up PTP shaper\n");
+}
+
+int mlxsw_sp1_ptp_hwtstamp_set(struct mlxsw_sp_port *mlxsw_sp_port,
+ struct hwtstamp_config *config)
+{
+ enum hwtstamp_rx_filters rx_filter;
+ u16 ing_types;
+ u16 egr_types;
+ int err;
+
+ err = mlxsw_sp_ptp_get_message_types(config, &ing_types, &egr_types,
+ &rx_filter);
+ if (err)
+ return err;
+
+ err = mlxsw_sp1_ptp_mtpppc_update(mlxsw_sp_port, ing_types, egr_types);
+ if (err)
+ return err;
+
+ mlxsw_sp_port->ptp.hwtstamp_config = *config;
+ mlxsw_sp_port->ptp.ing_types = ing_types;
+ mlxsw_sp_port->ptp.egr_types = egr_types;
+
+ err = mlxsw_sp1_ptp_port_shaper_check(mlxsw_sp_port);
+ if (err)
+ return err;
+
+ /* Notify the ioctl caller what we are actually timestamping. */
+ config->rx_filter = rx_filter;
+
+ return 0;
+}
+
+int mlxsw_sp1_ptp_get_ts_info(struct mlxsw_sp *mlxsw_sp,
+ struct ethtool_ts_info *info)
+{
+ info->phc_index = ptp_clock_index(mlxsw_sp->clock->ptp);
+
+ info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE;
+
+ info->tx_types = BIT(HWTSTAMP_TX_OFF) |
+ BIT(HWTSTAMP_TX_ON);
+
+ info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
+ BIT(HWTSTAMP_FILTER_ALL);
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.h
new file mode 100644
index 000000000000..72e55f6926b9
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.h
@@ -0,0 +1,186 @@
+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */
+/* Copyright (c) 2019 Mellanox Technologies. All rights reserved */
+
+#ifndef _MLXSW_SPECTRUM_PTP_H
+#define _MLXSW_SPECTRUM_PTP_H
+
+#include <linux/device.h>
+#include <linux/rhashtable.h>
+
+struct mlxsw_sp;
+struct mlxsw_sp_port;
+struct mlxsw_sp_ptp_clock;
+
+enum {
+ MLXSW_SP_PTP_MESSAGE_TYPE_SYNC,
+ MLXSW_SP_PTP_MESSAGE_TYPE_DELAY_REQ,
+ MLXSW_SP_PTP_MESSAGE_TYPE_PDELAY_REQ,
+ MLXSW_SP_PTP_MESSAGE_TYPE_PDELAY_RESP,
+};
+
+static inline int mlxsw_sp_ptp_get_ts_info_noptp(struct ethtool_ts_info *info)
+{
+ info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE |
+ SOF_TIMESTAMPING_SOFTWARE;
+ info->phc_index = -1;
+ return 0;
+}
+
+#if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
+
+struct mlxsw_sp_ptp_clock *
+mlxsw_sp1_ptp_clock_init(struct mlxsw_sp *mlxsw_sp, struct device *dev);
+
+void mlxsw_sp1_ptp_clock_fini(struct mlxsw_sp_ptp_clock *clock);
+
+struct mlxsw_sp_ptp_state *mlxsw_sp1_ptp_init(struct mlxsw_sp *mlxsw_sp);
+
+void mlxsw_sp1_ptp_fini(struct mlxsw_sp_ptp_state *ptp_state);
+
+void mlxsw_sp1_ptp_receive(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb,
+ u8 local_port);
+
+void mlxsw_sp1_ptp_transmitted(struct mlxsw_sp *mlxsw_sp,
+ struct sk_buff *skb, u8 local_port);
+
+void mlxsw_sp1_ptp_got_timestamp(struct mlxsw_sp *mlxsw_sp, bool ingress,
+ u8 local_port, u8 message_type,
+ u8 domain_number, u16 sequence_id,
+ u64 timestamp);
+
+int mlxsw_sp1_ptp_hwtstamp_get(struct mlxsw_sp_port *mlxsw_sp_port,
+ struct hwtstamp_config *config);
+
+int mlxsw_sp1_ptp_hwtstamp_set(struct mlxsw_sp_port *mlxsw_sp_port,
+ struct hwtstamp_config *config);
+
+void mlxsw_sp1_ptp_shaper_work(struct work_struct *work);
+
+int mlxsw_sp1_ptp_get_ts_info(struct mlxsw_sp *mlxsw_sp,
+ struct ethtool_ts_info *info);
+
+#else
+
+static inline struct mlxsw_sp_ptp_clock *
+mlxsw_sp1_ptp_clock_init(struct mlxsw_sp *mlxsw_sp, struct device *dev)
+{
+ return NULL;
+}
+
+static inline void mlxsw_sp1_ptp_clock_fini(struct mlxsw_sp_ptp_clock *clock)
+{
+}
+
+static inline struct mlxsw_sp_ptp_state *
+mlxsw_sp1_ptp_init(struct mlxsw_sp *mlxsw_sp)
+{
+ return NULL;
+}
+
+static inline void mlxsw_sp1_ptp_fini(struct mlxsw_sp_ptp_state *ptp_state)
+{
+}
+
+static inline void mlxsw_sp1_ptp_receive(struct mlxsw_sp *mlxsw_sp,
+ struct sk_buff *skb, u8 local_port)
+{
+ mlxsw_sp_rx_listener_no_mark_func(skb, local_port, mlxsw_sp);
+}
+
+static inline void mlxsw_sp1_ptp_transmitted(struct mlxsw_sp *mlxsw_sp,
+ struct sk_buff *skb, u8 local_port)
+{
+ dev_kfree_skb_any(skb);
+}
+
+static inline void
+mlxsw_sp1_ptp_got_timestamp(struct mlxsw_sp *mlxsw_sp, bool ingress,
+ u8 local_port, u8 message_type,
+ u8 domain_number,
+ u16 sequence_id, u64 timestamp)
+{
+}
+
+static inline int
+mlxsw_sp1_ptp_hwtstamp_get(struct mlxsw_sp_port *mlxsw_sp_port,
+ struct hwtstamp_config *config)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int
+mlxsw_sp1_ptp_hwtstamp_set(struct mlxsw_sp_port *mlxsw_sp_port,
+ struct hwtstamp_config *config)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline void mlxsw_sp1_ptp_shaper_work(struct work_struct *work)
+{
+}
+
+static inline int mlxsw_sp1_ptp_get_ts_info(struct mlxsw_sp *mlxsw_sp,
+ struct ethtool_ts_info *info)
+{
+ return mlxsw_sp_ptp_get_ts_info_noptp(info);
+}
+
+#endif
+
+static inline struct mlxsw_sp_ptp_clock *
+mlxsw_sp2_ptp_clock_init(struct mlxsw_sp *mlxsw_sp, struct device *dev)
+{
+ return NULL;
+}
+
+static inline void mlxsw_sp2_ptp_clock_fini(struct mlxsw_sp_ptp_clock *clock)
+{
+}
+
+static inline struct mlxsw_sp_ptp_state *
+mlxsw_sp2_ptp_init(struct mlxsw_sp *mlxsw_sp)
+{
+ return NULL;
+}
+
+static inline void mlxsw_sp2_ptp_fini(struct mlxsw_sp_ptp_state *ptp_state)
+{
+}
+
+static inline void mlxsw_sp2_ptp_receive(struct mlxsw_sp *mlxsw_sp,
+ struct sk_buff *skb, u8 local_port)
+{
+ mlxsw_sp_rx_listener_no_mark_func(skb, local_port, mlxsw_sp);
+}
+
+static inline void mlxsw_sp2_ptp_transmitted(struct mlxsw_sp *mlxsw_sp,
+ struct sk_buff *skb, u8 local_port)
+{
+ dev_kfree_skb_any(skb);
+}
+
+static inline int
+mlxsw_sp2_ptp_hwtstamp_get(struct mlxsw_sp_port *mlxsw_sp_port,
+ struct hwtstamp_config *config)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int
+mlxsw_sp2_ptp_hwtstamp_set(struct mlxsw_sp_port *mlxsw_sp_port,
+ struct hwtstamp_config *config)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline void mlxsw_sp2_ptp_shaper_work(struct work_struct *work)
+{
+}
+
+static inline int mlxsw_sp2_ptp_get_ts_info(struct mlxsw_sp *mlxsw_sp,
+ struct ethtool_ts_info *info)
+{
+ return mlxsw_sp_ptp_get_ts_info_noptp(info);
+}
+
+#endif
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index 1cda8a248b12..e618be7ce6c6 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -21,6 +21,7 @@
#include <net/arp.h>
#include <net/ip_fib.h>
#include <net/ip6_fib.h>
+#include <net/nexthop.h>
#include <net/fib_rules.h>
#include <net/ip_tunnels.h>
#include <net/l3mdev.h>
@@ -2363,7 +2364,7 @@ static void mlxsw_sp_router_probe_unresolved_nexthops(struct work_struct *work)
static void
mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_neigh_entry *neigh_entry,
- bool removing);
+ bool removing, bool dead);
static enum mlxsw_reg_rauht_op mlxsw_sp_rauht_op(bool adding)
{
@@ -2507,7 +2508,8 @@ static void mlxsw_sp_router_neigh_event_work(struct work_struct *work)
memcpy(neigh_entry->ha, ha, ETH_ALEN);
mlxsw_sp_neigh_entry_update(mlxsw_sp, neigh_entry, entry_connected);
- mlxsw_sp_nexthop_neigh_update(mlxsw_sp, neigh_entry, !entry_connected);
+ mlxsw_sp_nexthop_neigh_update(mlxsw_sp, neigh_entry, !entry_connected,
+ dead);
if (!neigh_entry->connected && list_empty(&neigh_entry->nexthop_list))
mlxsw_sp_neigh_entry_destroy(mlxsw_sp, neigh_entry);
@@ -2886,7 +2888,7 @@ mlxsw_sp_nexthop6_group_cmp(const struct mlxsw_sp_nexthop_group *nh_grp,
return false;
list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) {
- struct fib6_nh *fib6_nh = &mlxsw_sp_rt6->rt->fib6_nh;
+ struct fib6_nh *fib6_nh = mlxsw_sp_rt6->rt->fib6_nh;
struct in6_addr *gw;
int ifindex, weight;
@@ -2958,7 +2960,7 @@ mlxsw_sp_nexthop6_group_hash(struct mlxsw_sp_fib6_entry *fib6_entry, u32 seed)
struct net_device *dev;
list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) {
- dev = mlxsw_sp_rt6->rt->fib6_nh.fib_nh_dev;
+ dev = mlxsw_sp_rt6->rt->fib6_nh->fib_nh_dev;
val ^= dev->ifindex;
}
@@ -3472,13 +3474,79 @@ static void __mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp_nexthop *nh,
nh->update = 1;
}
+static int
+mlxsw_sp_nexthop_dead_neigh_replace(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_neigh_entry *neigh_entry)
+{
+ struct neighbour *n, *old_n = neigh_entry->key.n;
+ struct mlxsw_sp_nexthop *nh;
+ bool entry_connected;
+ u8 nud_state, dead;
+ int err;
+
+ nh = list_first_entry(&neigh_entry->nexthop_list,
+ struct mlxsw_sp_nexthop, neigh_list_node);
+
+ n = neigh_lookup(nh->nh_grp->neigh_tbl, &nh->gw_addr, nh->rif->dev);
+ if (!n) {
+ n = neigh_create(nh->nh_grp->neigh_tbl, &nh->gw_addr,
+ nh->rif->dev);
+ if (IS_ERR(n))
+ return PTR_ERR(n);
+ neigh_event_send(n, NULL);
+ }
+
+ mlxsw_sp_neigh_entry_remove(mlxsw_sp, neigh_entry);
+ neigh_entry->key.n = n;
+ err = mlxsw_sp_neigh_entry_insert(mlxsw_sp, neigh_entry);
+ if (err)
+ goto err_neigh_entry_insert;
+
+ read_lock_bh(&n->lock);
+ nud_state = n->nud_state;
+ dead = n->dead;
+ read_unlock_bh(&n->lock);
+ entry_connected = nud_state & NUD_VALID && !dead;
+
+ list_for_each_entry(nh, &neigh_entry->nexthop_list,
+ neigh_list_node) {
+ neigh_release(old_n);
+ neigh_clone(n);
+ __mlxsw_sp_nexthop_neigh_update(nh, !entry_connected);
+ mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh->nh_grp);
+ }
+
+ neigh_release(n);
+
+ return 0;
+
+err_neigh_entry_insert:
+ neigh_entry->key.n = old_n;
+ mlxsw_sp_neigh_entry_insert(mlxsw_sp, neigh_entry);
+ neigh_release(n);
+ return err;
+}
+
static void
mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_neigh_entry *neigh_entry,
- bool removing)
+ bool removing, bool dead)
{
struct mlxsw_sp_nexthop *nh;
+ if (list_empty(&neigh_entry->nexthop_list))
+ return;
+
+ if (dead) {
+ int err;
+
+ err = mlxsw_sp_nexthop_dead_neigh_replace(mlxsw_sp,
+ neigh_entry);
+ if (err)
+ dev_err(mlxsw_sp->bus_info->dev, "Failed to replace dead neigh\n");
+ return;
+ }
+
list_for_each_entry(nh, &neigh_entry->nexthop_list,
neigh_list_node) {
__mlxsw_sp_nexthop_neigh_update(nh, removing);
@@ -3816,23 +3884,25 @@ static void mlxsw_sp_nexthop_rif_gone_sync(struct mlxsw_sp *mlxsw_sp,
}
static bool mlxsw_sp_fi_is_gateway(const struct mlxsw_sp *mlxsw_sp,
- const struct fib_info *fi)
+ struct fib_info *fi)
{
- return fi->fib_nh->fib_nh_scope == RT_SCOPE_LINK ||
- mlxsw_sp_nexthop4_ipip_type(mlxsw_sp, fi->fib_nh, NULL);
+ const struct fib_nh *nh = fib_info_nh(fi, 0);
+
+ return nh->fib_nh_scope == RT_SCOPE_LINK ||
+ mlxsw_sp_nexthop4_ipip_type(mlxsw_sp, nh, NULL);
}
static struct mlxsw_sp_nexthop_group *
mlxsw_sp_nexthop4_group_create(struct mlxsw_sp *mlxsw_sp, struct fib_info *fi)
{
+ unsigned int nhs = fib_info_num_path(fi);
struct mlxsw_sp_nexthop_group *nh_grp;
struct mlxsw_sp_nexthop *nh;
struct fib_nh *fib_nh;
int i;
int err;
- nh_grp = kzalloc(struct_size(nh_grp, nexthops, fi->fib_nhs),
- GFP_KERNEL);
+ nh_grp = kzalloc(struct_size(nh_grp, nexthops, nhs), GFP_KERNEL);
if (!nh_grp)
return ERR_PTR(-ENOMEM);
nh_grp->priv = fi;
@@ -3840,11 +3910,11 @@ mlxsw_sp_nexthop4_group_create(struct mlxsw_sp *mlxsw_sp, struct fib_info *fi)
nh_grp->neigh_tbl = &arp_tbl;
nh_grp->gateway = mlxsw_sp_fi_is_gateway(mlxsw_sp, fi);
- nh_grp->count = fi->fib_nhs;
+ nh_grp->count = nhs;
fib_info_hold(fi);
for (i = 0; i < nh_grp->count; i++) {
nh = &nh_grp->nexthops[i];
- fib_nh = &fi->fib_nh[i];
+ fib_nh = fib_info_nh(fi, i);
err = mlxsw_sp_nexthop4_init(mlxsw_sp, nh_grp, nh, fib_nh);
if (err)
goto err_nexthop4_init;
@@ -3960,9 +4030,9 @@ mlxsw_sp_rt6_nexthop(struct mlxsw_sp_nexthop_group *nh_grp,
struct mlxsw_sp_nexthop *nh = &nh_grp->nexthops[i];
struct fib6_info *rt = mlxsw_sp_rt6->rt;
- if (nh->rif && nh->rif->dev == rt->fib6_nh.fib_nh_dev &&
+ if (nh->rif && nh->rif->dev == rt->fib6_nh->fib_nh_dev &&
ipv6_addr_equal((const struct in6_addr *) &nh->gw_addr,
- &rt->fib6_nh.fib_nh_gw6))
+ &rt->fib6_nh->fib_nh_gw6))
return nh;
continue;
}
@@ -4022,13 +4092,13 @@ mlxsw_sp_fib6_entry_offload_set(struct mlxsw_sp_fib_entry *fib_entry)
if (fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_LOCAL ||
fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE) {
list_first_entry(&fib6_entry->rt6_list, struct mlxsw_sp_rt6,
- list)->rt->fib6_nh.fib_nh_flags |= RTNH_F_OFFLOAD;
+ list)->rt->fib6_nh->fib_nh_flags |= RTNH_F_OFFLOAD;
return;
}
list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) {
struct mlxsw_sp_nexthop_group *nh_grp = fib_entry->nh_group;
- struct fib6_nh *fib6_nh = &mlxsw_sp_rt6->rt->fib6_nh;
+ struct fib6_nh *fib6_nh = mlxsw_sp_rt6->rt->fib6_nh;
struct mlxsw_sp_nexthop *nh;
nh = mlxsw_sp_rt6_nexthop(nh_grp, mlxsw_sp_rt6);
@@ -4050,7 +4120,7 @@ mlxsw_sp_fib6_entry_offload_unset(struct mlxsw_sp_fib_entry *fib_entry)
list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) {
struct fib6_info *rt = mlxsw_sp_rt6->rt;
- rt->fib6_nh.fib_nh_flags &= ~RTNH_F_OFFLOAD;
+ rt->fib6_nh->fib_nh_flags &= ~RTNH_F_OFFLOAD;
}
}
@@ -4282,9 +4352,9 @@ mlxsw_sp_fib4_entry_type_set(struct mlxsw_sp *mlxsw_sp,
const struct fib_entry_notifier_info *fen_info,
struct mlxsw_sp_fib_entry *fib_entry)
{
+ struct net_device *dev = fib_info_nh(fen_info->fi, 0)->fib_nh_dev;
union mlxsw_sp_l3addr dip = { .addr4 = htonl(fen_info->dst) };
u32 tb_id = mlxsw_sp_fix_tb_id(fen_info->tb_id);
- struct net_device *dev = fen_info->fi->fib_dev;
struct mlxsw_sp_ipip_entry *ipip_entry;
struct fib_info *fi = fen_info->fi;
@@ -4928,7 +4998,8 @@ static void mlxsw_sp_rt6_destroy(struct mlxsw_sp_rt6 *mlxsw_sp_rt6)
static bool mlxsw_sp_fib6_rt_can_mp(const struct fib6_info *rt)
{
/* RTF_CACHE routes are ignored */
- return !(rt->fib6_flags & RTF_ADDRCONF) && rt->fib6_nh.fib_nh_gw_family;
+ return !(rt->fib6_flags & RTF_ADDRCONF) &&
+ rt->fib6_nh->fib_nh_gw_family;
}
static struct fib6_info *
@@ -4987,8 +5058,8 @@ static bool mlxsw_sp_nexthop6_ipip_type(const struct mlxsw_sp *mlxsw_sp,
const struct fib6_info *rt,
enum mlxsw_sp_ipip_type *ret)
{
- return rt->fib6_nh.fib_nh_dev &&
- mlxsw_sp_netdev_ipip_type(mlxsw_sp, rt->fib6_nh.fib_nh_dev, ret);
+ return rt->fib6_nh->fib_nh_dev &&
+ mlxsw_sp_netdev_ipip_type(mlxsw_sp, rt->fib6_nh->fib_nh_dev, ret);
}
static int mlxsw_sp_nexthop6_type_init(struct mlxsw_sp *mlxsw_sp,
@@ -4998,7 +5069,7 @@ static int mlxsw_sp_nexthop6_type_init(struct mlxsw_sp *mlxsw_sp,
{
const struct mlxsw_sp_ipip_ops *ipip_ops;
struct mlxsw_sp_ipip_entry *ipip_entry;
- struct net_device *dev = rt->fib6_nh.fib_nh_dev;
+ struct net_device *dev = rt->fib6_nh->fib_nh_dev;
struct mlxsw_sp_rif *rif;
int err;
@@ -5041,11 +5112,11 @@ static int mlxsw_sp_nexthop6_init(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_nexthop *nh,
const struct fib6_info *rt)
{
- struct net_device *dev = rt->fib6_nh.fib_nh_dev;
+ struct net_device *dev = rt->fib6_nh->fib_nh_dev;
nh->nh_grp = nh_grp;
- nh->nh_weight = rt->fib6_nh.fib_nh_weight;
- memcpy(&nh->gw_addr, &rt->fib6_nh.fib_nh_gw6, sizeof(nh->gw_addr));
+ nh->nh_weight = rt->fib6_nh->fib_nh_weight;
+ memcpy(&nh->gw_addr, &rt->fib6_nh->fib_nh_gw6, sizeof(nh->gw_addr));
mlxsw_sp_nexthop_counter_alloc(mlxsw_sp, nh);
list_add_tail(&nh->router_list_node, &mlxsw_sp->router->nexthop_list);
@@ -5068,7 +5139,7 @@ static void mlxsw_sp_nexthop6_fini(struct mlxsw_sp *mlxsw_sp,
static bool mlxsw_sp_rt6_is_gateway(const struct mlxsw_sp *mlxsw_sp,
const struct fib6_info *rt)
{
- return rt->fib6_nh.fib_nh_gw_family ||
+ return rt->fib6_nh->fib_nh_gw_family ||
mlxsw_sp_nexthop6_ipip_type(mlxsw_sp, rt, NULL);
}
@@ -5207,17 +5278,21 @@ err_nexthop6_group_get:
static int
mlxsw_sp_fib6_entry_nexthop_add(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib6_entry *fib6_entry,
- struct fib6_info *rt)
+ struct fib6_info **rt_arr, unsigned int nrt6)
{
struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
- int err;
+ int err, i;
- mlxsw_sp_rt6 = mlxsw_sp_rt6_create(rt);
- if (IS_ERR(mlxsw_sp_rt6))
- return PTR_ERR(mlxsw_sp_rt6);
+ for (i = 0; i < nrt6; i++) {
+ mlxsw_sp_rt6 = mlxsw_sp_rt6_create(rt_arr[i]);
+ if (IS_ERR(mlxsw_sp_rt6)) {
+ err = PTR_ERR(mlxsw_sp_rt6);
+ goto err_rt6_create;
+ }
- list_add_tail(&mlxsw_sp_rt6->list, &fib6_entry->rt6_list);
- fib6_entry->nrt6++;
+ list_add_tail(&mlxsw_sp_rt6->list, &fib6_entry->rt6_list);
+ fib6_entry->nrt6++;
+ }
err = mlxsw_sp_nexthop6_group_update(mlxsw_sp, fib6_entry);
if (err)
@@ -5226,27 +5301,38 @@ mlxsw_sp_fib6_entry_nexthop_add(struct mlxsw_sp *mlxsw_sp,
return 0;
err_nexthop6_group_update:
- fib6_entry->nrt6--;
- list_del(&mlxsw_sp_rt6->list);
- mlxsw_sp_rt6_destroy(mlxsw_sp_rt6);
+ i = nrt6;
+err_rt6_create:
+ for (i--; i >= 0; i--) {
+ fib6_entry->nrt6--;
+ mlxsw_sp_rt6 = list_last_entry(&fib6_entry->rt6_list,
+ struct mlxsw_sp_rt6, list);
+ list_del(&mlxsw_sp_rt6->list);
+ mlxsw_sp_rt6_destroy(mlxsw_sp_rt6);
+ }
return err;
}
static void
mlxsw_sp_fib6_entry_nexthop_del(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib6_entry *fib6_entry,
- struct fib6_info *rt)
+ struct fib6_info **rt_arr, unsigned int nrt6)
{
struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
+ int i;
- mlxsw_sp_rt6 = mlxsw_sp_fib6_entry_rt_find(fib6_entry, rt);
- if (WARN_ON(!mlxsw_sp_rt6))
- return;
+ for (i = 0; i < nrt6; i++) {
+ mlxsw_sp_rt6 = mlxsw_sp_fib6_entry_rt_find(fib6_entry,
+ rt_arr[i]);
+ if (WARN_ON_ONCE(!mlxsw_sp_rt6))
+ continue;
+
+ fib6_entry->nrt6--;
+ list_del(&mlxsw_sp_rt6->list);
+ mlxsw_sp_rt6_destroy(mlxsw_sp_rt6);
+ }
- fib6_entry->nrt6--;
- list_del(&mlxsw_sp_rt6->list);
mlxsw_sp_nexthop6_group_update(mlxsw_sp, fib6_entry);
- mlxsw_sp_rt6_destroy(mlxsw_sp_rt6);
}
static void mlxsw_sp_fib6_entry_type_set(struct mlxsw_sp *mlxsw_sp,
@@ -5287,29 +5373,32 @@ mlxsw_sp_fib6_entry_rt_destroy_all(struct mlxsw_sp_fib6_entry *fib6_entry)
static struct mlxsw_sp_fib6_entry *
mlxsw_sp_fib6_entry_create(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_node *fib_node,
- struct fib6_info *rt)
+ struct fib6_info **rt_arr, unsigned int nrt6)
{
struct mlxsw_sp_fib6_entry *fib6_entry;
struct mlxsw_sp_fib_entry *fib_entry;
struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
- int err;
+ int err, i;
fib6_entry = kzalloc(sizeof(*fib6_entry), GFP_KERNEL);
if (!fib6_entry)
return ERR_PTR(-ENOMEM);
fib_entry = &fib6_entry->common;
- mlxsw_sp_rt6 = mlxsw_sp_rt6_create(rt);
- if (IS_ERR(mlxsw_sp_rt6)) {
- err = PTR_ERR(mlxsw_sp_rt6);
- goto err_rt6_create;
+ INIT_LIST_HEAD(&fib6_entry->rt6_list);
+
+ for (i = 0; i < nrt6; i++) {
+ mlxsw_sp_rt6 = mlxsw_sp_rt6_create(rt_arr[i]);
+ if (IS_ERR(mlxsw_sp_rt6)) {
+ err = PTR_ERR(mlxsw_sp_rt6);
+ goto err_rt6_create;
+ }
+ list_add_tail(&mlxsw_sp_rt6->list, &fib6_entry->rt6_list);
+ fib6_entry->nrt6++;
}
- mlxsw_sp_fib6_entry_type_set(mlxsw_sp, fib_entry, mlxsw_sp_rt6->rt);
+ mlxsw_sp_fib6_entry_type_set(mlxsw_sp, fib_entry, rt_arr[0]);
- INIT_LIST_HEAD(&fib6_entry->rt6_list);
- list_add_tail(&mlxsw_sp_rt6->list, &fib6_entry->rt6_list);
- fib6_entry->nrt6 = 1;
err = mlxsw_sp_nexthop6_group_get(mlxsw_sp, fib6_entry);
if (err)
goto err_nexthop6_group_get;
@@ -5319,9 +5408,15 @@ mlxsw_sp_fib6_entry_create(struct mlxsw_sp *mlxsw_sp,
return fib6_entry;
err_nexthop6_group_get:
- list_del(&mlxsw_sp_rt6->list);
- mlxsw_sp_rt6_destroy(mlxsw_sp_rt6);
+ i = nrt6;
err_rt6_create:
+ for (i--; i >= 0; i--) {
+ fib6_entry->nrt6--;
+ mlxsw_sp_rt6 = list_last_entry(&fib6_entry->rt6_list,
+ struct mlxsw_sp_rt6, list);
+ list_del(&mlxsw_sp_rt6->list);
+ mlxsw_sp_rt6_destroy(mlxsw_sp_rt6);
+ }
kfree(fib6_entry);
return ERR_PTR(err);
}
@@ -5364,16 +5459,16 @@ mlxsw_sp_fib6_node_entry_find(const struct mlxsw_sp_fib_node *fib_node,
static int
mlxsw_sp_fib6_node_list_insert(struct mlxsw_sp_fib6_entry *new6_entry,
- bool replace)
+ bool *p_replace)
{
struct mlxsw_sp_fib_node *fib_node = new6_entry->common.fib_node;
struct fib6_info *nrt = mlxsw_sp_fib6_entry_rt(new6_entry);
struct mlxsw_sp_fib6_entry *fib6_entry;
- fib6_entry = mlxsw_sp_fib6_node_entry_find(fib_node, nrt, replace);
+ fib6_entry = mlxsw_sp_fib6_node_entry_find(fib_node, nrt, *p_replace);
- if (replace && WARN_ON(!fib6_entry))
- return -EINVAL;
+ if (*p_replace && !fib6_entry)
+ *p_replace = false;
if (fib6_entry) {
list_add_tail(&new6_entry->common.list,
@@ -5408,11 +5503,11 @@ mlxsw_sp_fib6_node_list_remove(struct mlxsw_sp_fib6_entry *fib6_entry)
static int mlxsw_sp_fib6_node_entry_link(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib6_entry *fib6_entry,
- bool replace)
+ bool *p_replace)
{
int err;
- err = mlxsw_sp_fib6_node_list_insert(fib6_entry, replace);
+ err = mlxsw_sp_fib6_node_list_insert(fib6_entry, p_replace);
if (err)
return err;
@@ -5485,10 +5580,12 @@ static void mlxsw_sp_fib6_entry_replace(struct mlxsw_sp *mlxsw_sp,
}
static int mlxsw_sp_router_fib6_add(struct mlxsw_sp *mlxsw_sp,
- struct fib6_info *rt, bool replace)
+ struct fib6_info **rt_arr,
+ unsigned int nrt6, bool replace)
{
struct mlxsw_sp_fib6_entry *fib6_entry;
struct mlxsw_sp_fib_node *fib_node;
+ struct fib6_info *rt = rt_arr[0];
int err;
if (mlxsw_sp->router->aborted)
@@ -5513,19 +5610,21 @@ static int mlxsw_sp_router_fib6_add(struct mlxsw_sp *mlxsw_sp,
*/
fib6_entry = mlxsw_sp_fib6_node_mp_entry_find(fib_node, rt, replace);
if (fib6_entry) {
- err = mlxsw_sp_fib6_entry_nexthop_add(mlxsw_sp, fib6_entry, rt);
+ err = mlxsw_sp_fib6_entry_nexthop_add(mlxsw_sp, fib6_entry,
+ rt_arr, nrt6);
if (err)
goto err_fib6_entry_nexthop_add;
return 0;
}
- fib6_entry = mlxsw_sp_fib6_entry_create(mlxsw_sp, fib_node, rt);
+ fib6_entry = mlxsw_sp_fib6_entry_create(mlxsw_sp, fib_node, rt_arr,
+ nrt6);
if (IS_ERR(fib6_entry)) {
err = PTR_ERR(fib6_entry);
goto err_fib6_entry_create;
}
- err = mlxsw_sp_fib6_node_entry_link(mlxsw_sp, fib6_entry, replace);
+ err = mlxsw_sp_fib6_node_entry_link(mlxsw_sp, fib6_entry, &replace);
if (err)
goto err_fib6_node_entry_link;
@@ -5542,10 +5641,12 @@ err_fib6_entry_nexthop_add:
}
static void mlxsw_sp_router_fib6_del(struct mlxsw_sp *mlxsw_sp,
- struct fib6_info *rt)
+ struct fib6_info **rt_arr,
+ unsigned int nrt6)
{
struct mlxsw_sp_fib6_entry *fib6_entry;
struct mlxsw_sp_fib_node *fib_node;
+ struct fib6_info *rt = rt_arr[0];
if (mlxsw_sp->router->aborted)
return;
@@ -5557,11 +5658,12 @@ static void mlxsw_sp_router_fib6_del(struct mlxsw_sp *mlxsw_sp,
if (WARN_ON(!fib6_entry))
return;
- /* If route is part of a multipath entry, but not the last one
- * removed, then only reduce its nexthop group.
+ /* If not all the nexthops are deleted, then only reduce the nexthop
+ * group.
*/
- if (!list_is_singular(&fib6_entry->rt6_list)) {
- mlxsw_sp_fib6_entry_nexthop_del(mlxsw_sp, fib6_entry, rt);
+ if (nrt6 != fib6_entry->nrt6) {
+ mlxsw_sp_fib6_entry_nexthop_del(mlxsw_sp, fib6_entry, rt_arr,
+ nrt6);
return;
}
@@ -5822,10 +5924,15 @@ static void mlxsw_sp_router_fib_abort(struct mlxsw_sp *mlxsw_sp)
dev_warn(mlxsw_sp->bus_info->dev, "Failed to set abort trap.\n");
}
+struct mlxsw_sp_fib6_event_work {
+ struct fib6_info **rt_arr;
+ unsigned int nrt6;
+};
+
struct mlxsw_sp_fib_event_work {
struct work_struct work;
union {
- struct fib6_entry_notifier_info fen6_info;
+ struct mlxsw_sp_fib6_event_work fib6_work;
struct fib_entry_notifier_info fen_info;
struct fib_rule_notifier_info fr_info;
struct fib_nh_notifier_info fnh_info;
@@ -5836,6 +5943,54 @@ struct mlxsw_sp_fib_event_work {
unsigned long event;
};
+static int
+mlxsw_sp_router_fib6_work_init(struct mlxsw_sp_fib6_event_work *fib6_work,
+ struct fib6_entry_notifier_info *fen6_info)
+{
+ struct fib6_info *rt = fen6_info->rt;
+ struct fib6_info **rt_arr;
+ struct fib6_info *iter;
+ unsigned int nrt6;
+ int i = 0;
+
+ nrt6 = fen6_info->nsiblings + 1;
+
+ rt_arr = kcalloc(nrt6, sizeof(struct fib6_info *), GFP_ATOMIC);
+ if (!rt_arr)
+ return -ENOMEM;
+
+ fib6_work->rt_arr = rt_arr;
+ fib6_work->nrt6 = nrt6;
+
+ rt_arr[0] = rt;
+ fib6_info_hold(rt);
+
+ if (!fen6_info->nsiblings)
+ return 0;
+
+ list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) {
+ if (i == fen6_info->nsiblings)
+ break;
+
+ rt_arr[i + 1] = iter;
+ fib6_info_hold(iter);
+ i++;
+ }
+ WARN_ON_ONCE(i != fen6_info->nsiblings);
+
+ return 0;
+}
+
+static void
+mlxsw_sp_router_fib6_work_fini(struct mlxsw_sp_fib6_event_work *fib6_work)
+{
+ int i;
+
+ for (i = 0; i < fib6_work->nrt6; i++)
+ mlxsw_sp_rt6_release(fib6_work->rt_arr[i]);
+ kfree(fib6_work->rt_arr);
+}
+
static void mlxsw_sp_router_fib4_event_work(struct work_struct *work)
{
struct mlxsw_sp_fib_event_work *fib_work =
@@ -5894,18 +6049,21 @@ static void mlxsw_sp_router_fib6_event_work(struct work_struct *work)
switch (fib_work->event) {
case FIB_EVENT_ENTRY_REPLACE: /* fall through */
- case FIB_EVENT_ENTRY_APPEND: /* fall through */
case FIB_EVENT_ENTRY_ADD:
replace = fib_work->event == FIB_EVENT_ENTRY_REPLACE;
err = mlxsw_sp_router_fib6_add(mlxsw_sp,
- fib_work->fen6_info.rt, replace);
+ fib_work->fib6_work.rt_arr,
+ fib_work->fib6_work.nrt6,
+ replace);
if (err)
mlxsw_sp_router_fib_abort(mlxsw_sp);
- mlxsw_sp_rt6_release(fib_work->fen6_info.rt);
+ mlxsw_sp_router_fib6_work_fini(&fib_work->fib6_work);
break;
case FIB_EVENT_ENTRY_DEL:
- mlxsw_sp_router_fib6_del(mlxsw_sp, fib_work->fen6_info.rt);
- mlxsw_sp_rt6_release(fib_work->fen6_info.rt);
+ mlxsw_sp_router_fib6_del(mlxsw_sp,
+ fib_work->fib6_work.rt_arr,
+ fib_work->fib6_work.nrt6);
+ mlxsw_sp_router_fib6_work_fini(&fib_work->fib6_work);
break;
case FIB_EVENT_RULE_ADD:
/* if we get here, a rule was added that we do not support.
@@ -5994,22 +6152,26 @@ static void mlxsw_sp_router_fib4_event(struct mlxsw_sp_fib_event_work *fib_work,
}
}
-static void mlxsw_sp_router_fib6_event(struct mlxsw_sp_fib_event_work *fib_work,
- struct fib_notifier_info *info)
+static int mlxsw_sp_router_fib6_event(struct mlxsw_sp_fib_event_work *fib_work,
+ struct fib_notifier_info *info)
{
struct fib6_entry_notifier_info *fen6_info;
+ int err;
switch (fib_work->event) {
case FIB_EVENT_ENTRY_REPLACE: /* fall through */
- case FIB_EVENT_ENTRY_APPEND: /* fall through */
case FIB_EVENT_ENTRY_ADD: /* fall through */
case FIB_EVENT_ENTRY_DEL:
fen6_info = container_of(info, struct fib6_entry_notifier_info,
info);
- fib_work->fen6_info = *fen6_info;
- fib6_info_hold(fib_work->fen6_info.rt);
+ err = mlxsw_sp_router_fib6_work_init(&fib_work->fib6_work,
+ fen6_info);
+ if (err)
+ return err;
break;
}
+
+ return 0;
}
static void
@@ -6118,6 +6280,20 @@ static int mlxsw_sp_router_fib_event(struct notifier_block *nb,
NL_SET_ERR_MSG_MOD(info->extack, "IPv6 gateway with IPv4 route is not supported");
return notifier_from_errno(-EINVAL);
}
+ if (fen_info->fi->nh) {
+ NL_SET_ERR_MSG_MOD(info->extack, "IPv4 route with nexthop objects is not supported");
+ return notifier_from_errno(-EINVAL);
+ }
+ } else if (info->family == AF_INET6) {
+ struct fib6_entry_notifier_info *fen6_info;
+
+ fen6_info = container_of(info,
+ struct fib6_entry_notifier_info,
+ info);
+ if (fen6_info->rt->nh) {
+ NL_SET_ERR_MSG_MOD(info->extack, "IPv6 route with nexthop objects is not supported");
+ return notifier_from_errno(-EINVAL);
+ }
}
break;
}
@@ -6136,7 +6312,9 @@ static int mlxsw_sp_router_fib_event(struct notifier_block *nb,
break;
case AF_INET6:
INIT_WORK(&fib_work->work, mlxsw_sp_router_fib6_event_work);
- mlxsw_sp_router_fib6_event(fib_work, info);
+ err = mlxsw_sp_router_fib6_event(fib_work, info);
+ if (err)
+ goto err_fib_event;
break;
case RTNL_FAMILY_IP6MR:
case RTNL_FAMILY_IPMR:
@@ -6148,6 +6326,10 @@ static int mlxsw_sp_router_fib_event(struct notifier_block *nb,
mlxsw_core_schedule_work(&fib_work->work);
return NOTIFY_DONE;
+
+err_fib_event:
+ kfree(fib_work);
+ return NOTIFY_BAD;
}
struct mlxsw_sp_rif *
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
index 50111f228d77..5ecb45118400 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
@@ -2468,6 +2468,9 @@ 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");
@@ -2527,6 +2530,9 @@ 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");
diff --git a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c
index fc4f19167262..bdab96f5bc70 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c
@@ -299,6 +299,8 @@ static netdev_tx_t mlxsw_sx_port_xmit(struct sk_buff *skb,
u64 len;
int err;
+ memset(skb->cb, 0, sizeof(struct mlxsw_skb_cb));
+
if (mlxsw_core_skb_transmit_busy(mlxsw_sx->core, &tx_info))
return NETDEV_TX_BUSY;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/trap.h b/drivers/net/ethernet/mellanox/mlxsw/trap.h
index 451216dd7f6b..19202bdb5105 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/trap.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/trap.h
@@ -17,6 +17,8 @@ enum {
MLXSW_TRAP_ID_MVRP = 0x15,
MLXSW_TRAP_ID_RPVST = 0x16,
MLXSW_TRAP_ID_DHCP = 0x19,
+ MLXSW_TRAP_ID_PTP0 = 0x28,
+ MLXSW_TRAP_ID_PTP1 = 0x29,
MLXSW_TRAP_ID_IGMP_QUERY = 0x30,
MLXSW_TRAP_ID_IGMP_V1_REPORT = 0x31,
MLXSW_TRAP_ID_IGMP_V2_REPORT = 0x32,
@@ -76,6 +78,10 @@ enum {
enum mlxsw_event_trap_id {
/* Port Up/Down event generated by hardware */
MLXSW_TRAP_ID_PUDE = 0x8,
+ /* PTP Ingress FIFO has a new entry */
+ MLXSW_TRAP_ID_PTP_ING_FIFO = 0x2D,
+ /* PTP Egress FIFO has a new entry */
+ MLXSW_TRAP_ID_PTP_EGR_FIFO = 0x2E,
};
#endif /* _MLXSW_TRAP_H */
diff --git a/drivers/net/ethernet/micrel/ks8851.c b/drivers/net/ethernet/micrel/ks8851.c
index ba4fdf1b0dea..33305c9c5a62 100644
--- a/drivers/net/ethernet/micrel/ks8851.c
+++ b/drivers/net/ethernet/micrel/ks8851.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* drivers/net/ethernet/micrel/ks8851.c
*
* Copyright 2009 Simtec Electronics
* http://www.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/net/ethernet/micrel/ks8851.h b/drivers/net/ethernet/micrel/ks8851.h
index 23da1e3ee429..8f834aef8e32 100644
--- a/drivers/net/ethernet/micrel/ks8851.h
+++ b/drivers/net/ethernet/micrel/ks8851.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/* drivers/net/ethernet/micrel/ks8851.h
*
* Copyright 2009 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* KS8851 register definitions
- *
- * 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.
*/
#define KS_CCR 0x08
diff --git a/drivers/net/ethernet/microchip/encx24j600-regmap.c b/drivers/net/ethernet/microchip/encx24j600-regmap.c
index 44bb04d4d21b..1f496fac7033 100644
--- a/drivers/net/ethernet/microchip/encx24j600-regmap.c
+++ b/drivers/net/ethernet/microchip/encx24j600-regmap.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/**
* Register map access API - ENCX24J600 support
*
* Copyright 2015 Gridpoint
*
* Author: Jon Ringle <jringle@gridpoint.com>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/net/ethernet/mscc/Makefile b/drivers/net/ethernet/mscc/Makefile
index cb52a3b128ae..9a36c26095c8 100644
--- a/drivers/net/ethernet/mscc/Makefile
+++ b/drivers/net/ethernet/mscc/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: (GPL-2.0 OR MIT)
obj-$(CONFIG_MSCC_OCELOT_SWITCH) += mscc_ocelot_common.o
mscc_ocelot_common-y := ocelot.o ocelot_io.o
-mscc_ocelot_common-y += ocelot_regs.o
+mscc_ocelot_common-y += ocelot_regs.o ocelot_tc.o ocelot_police.o ocelot_ace.o ocelot_flower.o
obj-$(CONFIG_MSCC_OCELOT_SWITCH_OCELOT) += ocelot_board.o
diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
index 02ad11e0b0d8..b71e4ecbe469 100644
--- a/drivers/net/ethernet/mscc/ocelot.c
+++ b/drivers/net/ethernet/mscc/ocelot.c
@@ -22,6 +22,7 @@
#include <net/switchdev.h>
#include "ocelot.h"
+#include "ocelot_ace.h"
#define TABLE_UPDATE_SLEEP_US 10
#define TABLE_UPDATE_TIMEOUT_US 100000
@@ -130,6 +131,13 @@ static void ocelot_mact_init(struct ocelot *ocelot)
ocelot_write(ocelot, MACACCESS_CMD_INIT, ANA_TABLES_MACACCESS);
}
+static void ocelot_vcap_enable(struct ocelot *ocelot, struct ocelot_port *port)
+{
+ ocelot_write_gix(ocelot, ANA_PORT_VCAP_S2_CFG_S2_ENA |
+ ANA_PORT_VCAP_S2_CFG_S2_IP6_CFG(0xa),
+ ANA_PORT_VCAP_S2_CFG, port->chip_port);
+}
+
static inline u32 ocelot_vlant_read_vlanaccess(struct ocelot *ocelot)
{
return ocelot_read(ocelot, ANA_TABLES_VLANACCESS);
@@ -884,6 +892,13 @@ static int ocelot_set_features(struct net_device *dev,
struct ocelot_port *port = netdev_priv(dev);
netdev_features_t changed = dev->features ^ features;
+ if ((dev->features & NETIF_F_HW_TC) > (features & NETIF_F_HW_TC) &&
+ port->tc.offload_cnt) {
+ netdev_err(dev,
+ "Cannot disable HW TC offload while offloads active\n");
+ return -EBUSY;
+ }
+
if (changed & NETIF_F_HW_VLAN_CTAG_FILTER)
ocelot_vlan_mode(port, features);
@@ -917,6 +932,7 @@ static const struct net_device_ops ocelot_port_netdev_ops = {
.ndo_vlan_rx_kill_vid = ocelot_vlan_rx_kill_vid,
.ndo_set_features = ocelot_set_features,
.ndo_get_port_parent_id = ocelot_get_port_parent_id,
+ .ndo_setup_tc = ocelot_setup_tc,
};
static void ocelot_get_strings(struct net_device *netdev, u32 sset, u8 *data)
@@ -1636,8 +1652,9 @@ int ocelot_probe_port(struct ocelot *ocelot, u8 port,
dev->netdev_ops = &ocelot_port_netdev_ops;
dev->ethtool_ops = &ocelot_ethtool_ops;
- dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_RXFCS;
- dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
+ dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_RXFCS |
+ NETIF_F_HW_TC;
+ dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_TC;
memcpy(dev->dev_addr, ocelot->base_mac, ETH_ALEN);
dev->dev_addr[ETH_ALEN - 1] += port;
@@ -1653,6 +1670,9 @@ int ocelot_probe_port(struct ocelot *ocelot, u8 port,
/* Basic L2 initialization */
ocelot_vlan_port_apply(ocelot, ocelot_port);
+ /* Enable vcap lookups */
+ ocelot_vcap_enable(ocelot, ocelot_port);
+
return 0;
err_register_netdev:
@@ -1687,6 +1707,7 @@ int ocelot_init(struct ocelot *ocelot)
ocelot_mact_init(ocelot);
ocelot_vlan_init(ocelot);
+ ocelot_ace_init(ocelot);
for (port = 0; port < ocelot->num_phys_ports; port++) {
/* Clear all counters (5 groups) */
@@ -1799,6 +1820,7 @@ void ocelot_deinit(struct ocelot *ocelot)
{
destroy_workqueue(ocelot->stats_queue);
mutex_destroy(&ocelot->stats_lock);
+ ocelot_ace_deinit();
}
EXPORT_SYMBOL(ocelot_deinit);
diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h
index 541fe41e60b0..f7eeb4806897 100644
--- a/drivers/net/ethernet/mscc/ocelot.h
+++ b/drivers/net/ethernet/mscc/ocelot.h
@@ -22,6 +22,7 @@
#include "ocelot_rew.h"
#include "ocelot_sys.h"
#include "ocelot_qs.h"
+#include "ocelot_tc.h"
#define PGID_AGGR 64
#define PGID_SRC 80
@@ -68,6 +69,7 @@ enum ocelot_target {
QSYS,
REW,
SYS,
+ S2,
HSIO,
TARGET_MAX,
};
@@ -334,6 +336,13 @@ enum ocelot_reg {
SYS_CM_DATA_RD,
SYS_CM_OP,
SYS_CM_DATA,
+ S2_CORE_UPDATE_CTRL = S2 << TARGET_OFFSET,
+ S2_CORE_MV_CFG,
+ S2_CACHE_ENTRY_DAT,
+ S2_CACHE_MASK_DAT,
+ S2_CACHE_ACTION_DAT,
+ S2_CACHE_CNT_DAT,
+ S2_CACHE_TG_DAT,
};
enum ocelot_regfield {
@@ -454,6 +463,8 @@ struct ocelot_port {
phy_interface_t phy_mode;
struct phy *serdes;
+
+ struct ocelot_port_tc tc;
};
u32 __ocelot_read_ix(struct ocelot *ocelot, u32 reg, u32 offset);
diff --git a/drivers/net/ethernet/mscc/ocelot_ace.c b/drivers/net/ethernet/mscc/ocelot_ace.c
new file mode 100644
index 000000000000..39aca1ab4687
--- /dev/null
+++ b/drivers/net/ethernet/mscc/ocelot_ace.c
@@ -0,0 +1,782 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Microsemi Ocelot Switch driver
+ * Copyright (c) 2019 Microsemi Corporation
+ */
+
+#include <linux/iopoll.h>
+#include <linux/proc_fs.h>
+
+#include "ocelot_ace.h"
+#include "ocelot_vcap.h"
+#include "ocelot_s2.h"
+
+#define OCELOT_POLICER_DISCARD 0x17f
+
+static struct ocelot_acl_block *acl_block;
+
+struct vcap_props {
+ const char *name; /* Symbolic name */
+ u16 tg_width; /* Type-group width (in bits) */
+ u16 sw_count; /* Sub word count */
+ u16 entry_count; /* Entry count */
+ u16 entry_words; /* Number of entry words */
+ u16 entry_width; /* Entry width (in bits) */
+ u16 action_count; /* Action count */
+ u16 action_words; /* Number of action words */
+ u16 action_width; /* Action width (in bits) */
+ u16 action_type_width; /* Action type width (in bits) */
+ struct {
+ u16 width; /* Action type width (in bits) */
+ u16 count; /* Action type sub word count */
+ } action_table[2];
+ u16 counter_words; /* Number of counter words */
+ u16 counter_width; /* Counter width (in bits) */
+};
+
+#define ENTRY_WIDTH 32
+#define BITS_TO_32BIT(x) (1 + (((x) - 1) / ENTRY_WIDTH))
+
+static const struct vcap_props vcap_is2 = {
+ .name = "IS2",
+ .tg_width = 2,
+ .sw_count = 4,
+ .entry_count = VCAP_IS2_CNT,
+ .entry_words = BITS_TO_32BIT(VCAP_IS2_ENTRY_WIDTH),
+ .entry_width = VCAP_IS2_ENTRY_WIDTH,
+ .action_count = (VCAP_IS2_CNT + VCAP_PORT_CNT + 2),
+ .action_words = BITS_TO_32BIT(VCAP_IS2_ACTION_WIDTH),
+ .action_width = (VCAP_IS2_ACTION_WIDTH),
+ .action_type_width = 1,
+ .action_table = {
+ {
+ .width = (IS2_AO_ACL_ID + IS2_AL_ACL_ID),
+ .count = 2
+ },
+ {
+ .width = 6,
+ .count = 4
+ },
+ },
+ .counter_words = BITS_TO_32BIT(4 * ENTRY_WIDTH),
+ .counter_width = ENTRY_WIDTH,
+};
+
+enum vcap_sel {
+ VCAP_SEL_ENTRY = 0x1,
+ VCAP_SEL_ACTION = 0x2,
+ VCAP_SEL_COUNTER = 0x4,
+ VCAP_SEL_ALL = 0x7,
+};
+
+enum vcap_cmd {
+ VCAP_CMD_WRITE = 0, /* Copy from Cache to TCAM */
+ VCAP_CMD_READ = 1, /* Copy from TCAM to Cache */
+ VCAP_CMD_MOVE_UP = 2, /* Move <count> up */
+ VCAP_CMD_MOVE_DOWN = 3, /* Move <count> down */
+ VCAP_CMD_INITIALIZE = 4, /* Write all (from cache) */
+};
+
+#define VCAP_ENTRY_WIDTH 12 /* Max entry width (32bit words) */
+#define VCAP_COUNTER_WIDTH 4 /* Max counter width (32bit words) */
+
+struct vcap_data {
+ u32 entry[VCAP_ENTRY_WIDTH]; /* ENTRY_DAT */
+ u32 mask[VCAP_ENTRY_WIDTH]; /* MASK_DAT */
+ u32 action[VCAP_ENTRY_WIDTH]; /* ACTION_DAT */
+ u32 counter[VCAP_COUNTER_WIDTH]; /* CNT_DAT */
+ u32 tg; /* TG_DAT */
+ u32 type; /* Action type */
+ u32 tg_sw; /* Current type-group */
+ u32 cnt; /* Current counter */
+ u32 key_offset; /* Current entry offset */
+ u32 action_offset; /* Current action offset */
+ u32 counter_offset; /* Current counter offset */
+ u32 tg_value; /* Current type-group value */
+ u32 tg_mask; /* Current type-group mask */
+};
+
+static u32 vcap_s2_read_update_ctrl(struct ocelot *oc)
+{
+ return ocelot_read(oc, S2_CORE_UPDATE_CTRL);
+}
+
+static void vcap_cmd(struct ocelot *oc, u16 ix, int cmd, int sel)
+{
+ u32 value = (S2_CORE_UPDATE_CTRL_UPDATE_CMD(cmd) |
+ S2_CORE_UPDATE_CTRL_UPDATE_ADDR(ix) |
+ S2_CORE_UPDATE_CTRL_UPDATE_SHOT);
+
+ if ((sel & VCAP_SEL_ENTRY) && ix >= vcap_is2.entry_count)
+ return;
+
+ if (!(sel & VCAP_SEL_ENTRY))
+ value |= S2_CORE_UPDATE_CTRL_UPDATE_ENTRY_DIS;
+
+ if (!(sel & VCAP_SEL_ACTION))
+ value |= S2_CORE_UPDATE_CTRL_UPDATE_ACTION_DIS;
+
+ if (!(sel & VCAP_SEL_COUNTER))
+ value |= S2_CORE_UPDATE_CTRL_UPDATE_CNT_DIS;
+
+ ocelot_write(oc, value, S2_CORE_UPDATE_CTRL);
+ readx_poll_timeout(vcap_s2_read_update_ctrl, oc, value,
+ (value & S2_CORE_UPDATE_CTRL_UPDATE_SHOT) == 0,
+ 10, 100000);
+}
+
+/* Convert from 0-based row to VCAP entry row and run command */
+static void vcap_row_cmd(struct ocelot *oc, u32 row, int cmd, int sel)
+{
+ vcap_cmd(oc, vcap_is2.entry_count - row - 1, cmd, sel);
+}
+
+static void vcap_entry2cache(struct ocelot *oc, struct vcap_data *data)
+{
+ u32 i;
+
+ for (i = 0; i < vcap_is2.entry_words; i++) {
+ ocelot_write_rix(oc, data->entry[i], S2_CACHE_ENTRY_DAT, i);
+ ocelot_write_rix(oc, ~data->mask[i], S2_CACHE_MASK_DAT, i);
+ }
+ ocelot_write(oc, data->tg, S2_CACHE_TG_DAT);
+}
+
+static void vcap_cache2entry(struct ocelot *oc, struct vcap_data *data)
+{
+ u32 i;
+
+ for (i = 0; i < vcap_is2.entry_words; i++) {
+ data->entry[i] = ocelot_read_rix(oc, S2_CACHE_ENTRY_DAT, i);
+ // Invert mask
+ data->mask[i] = ~ocelot_read_rix(oc, S2_CACHE_MASK_DAT, i);
+ }
+ data->tg = ocelot_read(oc, S2_CACHE_TG_DAT);
+}
+
+static void vcap_action2cache(struct ocelot *oc, struct vcap_data *data)
+{
+ u32 i, width, mask;
+
+ /* Encode action type */
+ width = vcap_is2.action_type_width;
+ if (width) {
+ mask = GENMASK(width, 0);
+ data->action[0] = ((data->action[0] & ~mask) | data->type);
+ }
+
+ for (i = 0; i < vcap_is2.action_words; i++)
+ ocelot_write_rix(oc, data->action[i], S2_CACHE_ACTION_DAT, i);
+
+ for (i = 0; i < vcap_is2.counter_words; i++)
+ ocelot_write_rix(oc, data->counter[i], S2_CACHE_CNT_DAT, i);
+}
+
+static void vcap_cache2action(struct ocelot *oc, struct vcap_data *data)
+{
+ u32 i, width;
+
+ for (i = 0; i < vcap_is2.action_words; i++)
+ data->action[i] = ocelot_read_rix(oc, S2_CACHE_ACTION_DAT, i);
+
+ for (i = 0; i < vcap_is2.counter_words; i++)
+ data->counter[i] = ocelot_read_rix(oc, S2_CACHE_CNT_DAT, i);
+
+ /* Extract action type */
+ width = vcap_is2.action_type_width;
+ data->type = (width ? (data->action[0] & GENMASK(width, 0)) : 0);
+}
+
+/* Calculate offsets for entry */
+static void is2_data_get(struct vcap_data *data, int ix)
+{
+ u32 i, col, offset, count, cnt, base, width = vcap_is2.tg_width;
+
+ count = (data->tg_sw == VCAP_TG_HALF ? 2 : 4);
+ col = (ix % 2);
+ cnt = (vcap_is2.sw_count / count);
+ base = (vcap_is2.sw_count - col * cnt - cnt);
+ data->tg_value = 0;
+ data->tg_mask = 0;
+ for (i = 0; i < cnt; i++) {
+ offset = ((base + i) * width);
+ data->tg_value |= (data->tg_sw << offset);
+ data->tg_mask |= GENMASK(offset + width - 1, offset);
+ }
+
+ /* Calculate key/action/counter offsets */
+ col = (count - col - 1);
+ data->key_offset = (base * vcap_is2.entry_width) / vcap_is2.sw_count;
+ data->counter_offset = (cnt * col * vcap_is2.counter_width);
+ i = data->type;
+ width = vcap_is2.action_table[i].width;
+ cnt = vcap_is2.action_table[i].count;
+ data->action_offset =
+ (((cnt * col * width) / count) + vcap_is2.action_type_width);
+}
+
+static void vcap_data_set(u32 *data, u32 offset, u32 len, u32 value)
+{
+ u32 i, v, m;
+
+ for (i = 0; i < len; i++, offset++) {
+ v = data[offset / ENTRY_WIDTH];
+ m = (1 << (offset % ENTRY_WIDTH));
+ if (value & (1 << i))
+ v |= m;
+ else
+ v &= ~m;
+ data[offset / ENTRY_WIDTH] = v;
+ }
+}
+
+static u32 vcap_data_get(u32 *data, u32 offset, u32 len)
+{
+ u32 i, v, m, value = 0;
+
+ for (i = 0; i < len; i++, offset++) {
+ v = data[offset / ENTRY_WIDTH];
+ m = (1 << (offset % ENTRY_WIDTH));
+ if (v & m)
+ value |= (1 << i);
+ }
+ return value;
+}
+
+static void vcap_key_set(struct vcap_data *data, u32 offset, u32 width,
+ u32 value, u32 mask)
+{
+ vcap_data_set(data->entry, offset + data->key_offset, width, value);
+ vcap_data_set(data->mask, offset + data->key_offset, width, mask);
+}
+
+static void vcap_key_bytes_set(struct vcap_data *data, u32 offset, u8 *val,
+ u8 *msk, u32 count)
+{
+ u32 i, j, n = 0, value = 0, mask = 0;
+
+ /* Data wider than 32 bits are split up in chunks of maximum 32 bits.
+ * The 32 LSB of the data are written to the 32 MSB of the TCAM.
+ */
+ offset += (count * 8);
+ for (i = 0; i < count; i++) {
+ j = (count - i - 1);
+ value += (val[j] << n);
+ mask += (msk[j] << n);
+ n += 8;
+ if (n == ENTRY_WIDTH || (i + 1) == count) {
+ offset -= n;
+ vcap_key_set(data, offset, n, value, mask);
+ n = 0;
+ value = 0;
+ mask = 0;
+ }
+ }
+}
+
+static void vcap_key_l4_port_set(struct vcap_data *data, u32 offset,
+ struct ocelot_vcap_udp_tcp *port)
+{
+ vcap_key_set(data, offset, 16, port->value, port->mask);
+}
+
+static void vcap_key_bit_set(struct vcap_data *data, u32 offset,
+ enum ocelot_vcap_bit val)
+{
+ vcap_key_set(data, offset, 1, val == OCELOT_VCAP_BIT_1 ? 1 : 0,
+ val == OCELOT_VCAP_BIT_ANY ? 0 : 1);
+}
+
+#define VCAP_KEY_SET(fld, val, msk) \
+ vcap_key_set(&data, IS2_HKO_##fld, IS2_HKL_##fld, val, msk)
+#define VCAP_KEY_ANY_SET(fld) \
+ vcap_key_set(&data, IS2_HKO_##fld, IS2_HKL_##fld, 0, 0)
+#define VCAP_KEY_BIT_SET(fld, val) vcap_key_bit_set(&data, IS2_HKO_##fld, val)
+#define VCAP_KEY_BYTES_SET(fld, val, msk) \
+ vcap_key_bytes_set(&data, IS2_HKO_##fld, val, msk, IS2_HKL_##fld / 8)
+
+static void vcap_action_set(struct vcap_data *data, u32 offset, u32 width,
+ u32 value)
+{
+ vcap_data_set(data->action, offset + data->action_offset, width, value);
+}
+
+#define VCAP_ACT_SET(fld, val) \
+ vcap_action_set(data, IS2_AO_##fld, IS2_AL_##fld, val)
+
+static void is2_action_set(struct vcap_data *data,
+ enum ocelot_ace_action action)
+{
+ switch (action) {
+ case OCELOT_ACL_ACTION_DROP:
+ VCAP_ACT_SET(PORT_MASK, 0x0);
+ VCAP_ACT_SET(MASK_MODE, 0x1);
+ VCAP_ACT_SET(POLICE_ENA, 0x1);
+ VCAP_ACT_SET(POLICE_IDX, OCELOT_POLICER_DISCARD);
+ VCAP_ACT_SET(CPU_QU_NUM, 0x0);
+ VCAP_ACT_SET(CPU_COPY_ENA, 0x0);
+ break;
+ case OCELOT_ACL_ACTION_TRAP:
+ VCAP_ACT_SET(PORT_MASK, 0x0);
+ VCAP_ACT_SET(MASK_MODE, 0x0);
+ VCAP_ACT_SET(POLICE_ENA, 0x0);
+ VCAP_ACT_SET(POLICE_IDX, 0x0);
+ VCAP_ACT_SET(CPU_QU_NUM, 0x0);
+ VCAP_ACT_SET(CPU_COPY_ENA, 0x1);
+ break;
+ }
+}
+
+static void is2_entry_set(struct ocelot *ocelot, int ix,
+ struct ocelot_ace_rule *ace)
+{
+ u32 val, msk, type, type_mask = 0xf, i, count;
+ struct ocelot_ace_vlan *tag = &ace->vlan;
+ struct ocelot_vcap_u64 payload;
+ struct vcap_data data;
+ int row = (ix / 2);
+
+ memset(&payload, 0, sizeof(payload));
+ memset(&data, 0, sizeof(data));
+
+ /* Read row */
+ vcap_row_cmd(ocelot, row, VCAP_CMD_READ, VCAP_SEL_ALL);
+ vcap_cache2entry(ocelot, &data);
+ vcap_cache2action(ocelot, &data);
+
+ data.tg_sw = VCAP_TG_HALF;
+ is2_data_get(&data, ix);
+ data.tg = (data.tg & ~data.tg_mask);
+ if (ace->prio != 0)
+ data.tg |= data.tg_value;
+
+ data.type = IS2_ACTION_TYPE_NORMAL;
+
+ VCAP_KEY_ANY_SET(PAG);
+ VCAP_KEY_SET(IGR_PORT_MASK, 0, ~BIT(ace->chip_port));
+ VCAP_KEY_BIT_SET(FIRST, OCELOT_VCAP_BIT_1);
+ VCAP_KEY_BIT_SET(HOST_MATCH, OCELOT_VCAP_BIT_ANY);
+ VCAP_KEY_BIT_SET(L2_MC, ace->dmac_mc);
+ VCAP_KEY_BIT_SET(L2_BC, ace->dmac_bc);
+ VCAP_KEY_BIT_SET(VLAN_TAGGED, tag->tagged);
+ VCAP_KEY_SET(VID, tag->vid.value, tag->vid.mask);
+ VCAP_KEY_SET(PCP, tag->pcp.value[0], tag->pcp.mask[0]);
+ VCAP_KEY_BIT_SET(DEI, tag->dei);
+
+ switch (ace->type) {
+ case OCELOT_ACE_TYPE_ETYPE: {
+ struct ocelot_ace_frame_etype *etype = &ace->frame.etype;
+
+ type = IS2_TYPE_ETYPE;
+ VCAP_KEY_BYTES_SET(L2_DMAC, etype->dmac.value,
+ etype->dmac.mask);
+ VCAP_KEY_BYTES_SET(L2_SMAC, etype->smac.value,
+ etype->smac.mask);
+ VCAP_KEY_BYTES_SET(MAC_ETYPE_ETYPE, etype->etype.value,
+ etype->etype.mask);
+ VCAP_KEY_ANY_SET(MAC_ETYPE_L2_PAYLOAD); // Clear unused bits
+ vcap_key_bytes_set(&data, IS2_HKO_MAC_ETYPE_L2_PAYLOAD,
+ etype->data.value, etype->data.mask, 2);
+ break;
+ }
+ case OCELOT_ACE_TYPE_LLC: {
+ struct ocelot_ace_frame_llc *llc = &ace->frame.llc;
+
+ type = IS2_TYPE_LLC;
+ VCAP_KEY_BYTES_SET(L2_DMAC, llc->dmac.value, llc->dmac.mask);
+ VCAP_KEY_BYTES_SET(L2_SMAC, llc->smac.value, llc->smac.mask);
+ for (i = 0; i < 4; i++) {
+ payload.value[i] = llc->llc.value[i];
+ payload.mask[i] = llc->llc.mask[i];
+ }
+ VCAP_KEY_BYTES_SET(MAC_LLC_L2_LLC, payload.value, payload.mask);
+ break;
+ }
+ case OCELOT_ACE_TYPE_SNAP: {
+ struct ocelot_ace_frame_snap *snap = &ace->frame.snap;
+
+ type = IS2_TYPE_SNAP;
+ VCAP_KEY_BYTES_SET(L2_DMAC, snap->dmac.value, snap->dmac.mask);
+ VCAP_KEY_BYTES_SET(L2_SMAC, snap->smac.value, snap->smac.mask);
+ VCAP_KEY_BYTES_SET(MAC_SNAP_L2_SNAP,
+ ace->frame.snap.snap.value,
+ ace->frame.snap.snap.mask);
+ break;
+ }
+ case OCELOT_ACE_TYPE_ARP: {
+ struct ocelot_ace_frame_arp *arp = &ace->frame.arp;
+
+ type = IS2_TYPE_ARP;
+ VCAP_KEY_BYTES_SET(MAC_ARP_L2_SMAC, arp->smac.value,
+ arp->smac.mask);
+ VCAP_KEY_BIT_SET(MAC_ARP_ARP_ADDR_SPACE_OK, arp->ethernet);
+ VCAP_KEY_BIT_SET(MAC_ARP_ARP_PROTO_SPACE_OK, arp->ip);
+ VCAP_KEY_BIT_SET(MAC_ARP_ARP_LEN_OK, arp->length);
+ VCAP_KEY_BIT_SET(MAC_ARP_ARP_TGT_MATCH, arp->dmac_match);
+ VCAP_KEY_BIT_SET(MAC_ARP_ARP_SENDER_MATCH, arp->smac_match);
+ VCAP_KEY_BIT_SET(MAC_ARP_ARP_OPCODE_UNKNOWN, arp->unknown);
+
+ /* OPCODE is inverse, bit 0 is reply flag, bit 1 is RARP flag */
+ val = ((arp->req == OCELOT_VCAP_BIT_0 ? 1 : 0) |
+ (arp->arp == OCELOT_VCAP_BIT_0 ? 2 : 0));
+ msk = ((arp->req == OCELOT_VCAP_BIT_ANY ? 0 : 1) |
+ (arp->arp == OCELOT_VCAP_BIT_ANY ? 0 : 2));
+ VCAP_KEY_SET(MAC_ARP_ARP_OPCODE, val, msk);
+ vcap_key_bytes_set(&data, IS2_HKO_MAC_ARP_L3_IP4_DIP,
+ arp->dip.value.addr, arp->dip.mask.addr, 4);
+ vcap_key_bytes_set(&data, IS2_HKO_MAC_ARP_L3_IP4_SIP,
+ arp->sip.value.addr, arp->sip.mask.addr, 4);
+ VCAP_KEY_ANY_SET(MAC_ARP_DIP_EQ_SIP);
+ break;
+ }
+ case OCELOT_ACE_TYPE_IPV4:
+ case OCELOT_ACE_TYPE_IPV6: {
+ enum ocelot_vcap_bit sip_eq_dip, sport_eq_dport, seq_zero, tcp;
+ enum ocelot_vcap_bit ttl, fragment, options, tcp_ack, tcp_urg;
+ enum ocelot_vcap_bit tcp_fin, tcp_syn, tcp_rst, tcp_psh;
+ struct ocelot_ace_frame_ipv4 *ipv4 = NULL;
+ struct ocelot_ace_frame_ipv6 *ipv6 = NULL;
+ struct ocelot_vcap_udp_tcp *sport, *dport;
+ struct ocelot_vcap_ipv4 sip, dip;
+ struct ocelot_vcap_u8 proto, ds;
+ struct ocelot_vcap_u48 *ip_data;
+
+ if (ace->type == OCELOT_ACE_TYPE_IPV4) {
+ ipv4 = &ace->frame.ipv4;
+ ttl = ipv4->ttl;
+ fragment = ipv4->fragment;
+ options = ipv4->options;
+ proto = ipv4->proto;
+ ds = ipv4->ds;
+ ip_data = &ipv4->data;
+ sip = ipv4->sip;
+ dip = ipv4->dip;
+ sport = &ipv4->sport;
+ dport = &ipv4->dport;
+ tcp_fin = ipv4->tcp_fin;
+ tcp_syn = ipv4->tcp_syn;
+ tcp_rst = ipv4->tcp_rst;
+ tcp_psh = ipv4->tcp_psh;
+ tcp_ack = ipv4->tcp_ack;
+ tcp_urg = ipv4->tcp_urg;
+ sip_eq_dip = ipv4->sip_eq_dip;
+ sport_eq_dport = ipv4->sport_eq_dport;
+ seq_zero = ipv4->seq_zero;
+ } else {
+ ipv6 = &ace->frame.ipv6;
+ ttl = ipv6->ttl;
+ fragment = OCELOT_VCAP_BIT_ANY;
+ options = OCELOT_VCAP_BIT_ANY;
+ proto = ipv6->proto;
+ ds = ipv6->ds;
+ ip_data = &ipv6->data;
+ for (i = 0; i < 8; i++) {
+ val = ipv6->sip.value[i + 8];
+ msk = ipv6->sip.mask[i + 8];
+ if (i < 4) {
+ dip.value.addr[i] = val;
+ dip.mask.addr[i] = msk;
+ } else {
+ sip.value.addr[i - 4] = val;
+ sip.mask.addr[i - 4] = msk;
+ }
+ }
+ sport = &ipv6->sport;
+ dport = &ipv6->dport;
+ tcp_fin = ipv6->tcp_fin;
+ tcp_syn = ipv6->tcp_syn;
+ tcp_rst = ipv6->tcp_rst;
+ tcp_psh = ipv6->tcp_psh;
+ tcp_ack = ipv6->tcp_ack;
+ tcp_urg = ipv6->tcp_urg;
+ sip_eq_dip = ipv6->sip_eq_dip;
+ sport_eq_dport = ipv6->sport_eq_dport;
+ seq_zero = ipv6->seq_zero;
+ }
+
+ VCAP_KEY_BIT_SET(IP4,
+ ipv4 ? OCELOT_VCAP_BIT_1 : OCELOT_VCAP_BIT_0);
+ VCAP_KEY_BIT_SET(L3_FRAGMENT, fragment);
+ VCAP_KEY_ANY_SET(L3_FRAG_OFS_GT0);
+ VCAP_KEY_BIT_SET(L3_OPTIONS, options);
+ VCAP_KEY_BIT_SET(L3_TTL_GT0, ttl);
+ VCAP_KEY_BYTES_SET(L3_TOS, ds.value, ds.mask);
+ vcap_key_bytes_set(&data, IS2_HKO_L3_IP4_DIP, dip.value.addr,
+ dip.mask.addr, 4);
+ vcap_key_bytes_set(&data, IS2_HKO_L3_IP4_SIP, sip.value.addr,
+ sip.mask.addr, 4);
+ VCAP_KEY_BIT_SET(DIP_EQ_SIP, sip_eq_dip);
+ val = proto.value[0];
+ msk = proto.mask[0];
+ type = IS2_TYPE_IP_UDP_TCP;
+ if (msk == 0xff && (val == 6 || val == 17)) {
+ /* UDP/TCP protocol match */
+ tcp = (val == 6 ?
+ OCELOT_VCAP_BIT_1 : OCELOT_VCAP_BIT_0);
+ VCAP_KEY_BIT_SET(IP4_TCP_UDP_TCP, tcp);
+ vcap_key_l4_port_set(&data,
+ IS2_HKO_IP4_TCP_UDP_L4_DPORT,
+ dport);
+ vcap_key_l4_port_set(&data,
+ IS2_HKO_IP4_TCP_UDP_L4_SPORT,
+ sport);
+ VCAP_KEY_ANY_SET(IP4_TCP_UDP_L4_RNG);
+ VCAP_KEY_BIT_SET(IP4_TCP_UDP_SPORT_EQ_DPORT,
+ sport_eq_dport);
+ VCAP_KEY_BIT_SET(IP4_TCP_UDP_SEQUENCE_EQ0, seq_zero);
+ VCAP_KEY_BIT_SET(IP4_TCP_UDP_L4_FIN, tcp_fin);
+ VCAP_KEY_BIT_SET(IP4_TCP_UDP_L4_SYN, tcp_syn);
+ VCAP_KEY_BIT_SET(IP4_TCP_UDP_L4_RST, tcp_rst);
+ VCAP_KEY_BIT_SET(IP4_TCP_UDP_L4_PSH, tcp_psh);
+ VCAP_KEY_BIT_SET(IP4_TCP_UDP_L4_ACK, tcp_ack);
+ VCAP_KEY_BIT_SET(IP4_TCP_UDP_L4_URG, tcp_urg);
+ VCAP_KEY_ANY_SET(IP4_TCP_UDP_L4_1588_DOM);
+ VCAP_KEY_ANY_SET(IP4_TCP_UDP_L4_1588_VER);
+ } else {
+ if (msk == 0) {
+ /* Any IP protocol match */
+ type_mask = IS2_TYPE_MASK_IP_ANY;
+ } else {
+ /* Non-UDP/TCP protocol match */
+ type = IS2_TYPE_IP_OTHER;
+ for (i = 0; i < 6; i++) {
+ payload.value[i] = ip_data->value[i];
+ payload.mask[i] = ip_data->mask[i];
+ }
+ }
+ VCAP_KEY_BYTES_SET(IP4_OTHER_L3_PROTO, proto.value,
+ proto.mask);
+ VCAP_KEY_BYTES_SET(IP4_OTHER_L3_PAYLOAD, payload.value,
+ payload.mask);
+ }
+ break;
+ }
+ case OCELOT_ACE_TYPE_ANY:
+ default:
+ type = 0;
+ type_mask = 0;
+ count = (vcap_is2.entry_width / 2);
+ for (i = (IS2_HKO_PCP + IS2_HKL_PCP); i < count;
+ i += ENTRY_WIDTH) {
+ /* Clear entry data */
+ vcap_key_set(&data, i, min(32u, count - i), 0, 0);
+ }
+ break;
+ }
+
+ VCAP_KEY_SET(TYPE, type, type_mask);
+ is2_action_set(&data, ace->action);
+ vcap_data_set(data.counter, data.counter_offset, vcap_is2.counter_width,
+ ace->stats.pkts);
+
+ /* Write row */
+ vcap_entry2cache(ocelot, &data);
+ vcap_action2cache(ocelot, &data);
+ vcap_row_cmd(ocelot, row, VCAP_CMD_WRITE, VCAP_SEL_ALL);
+}
+
+static void is2_entry_get(struct ocelot_ace_rule *rule, int ix)
+{
+ struct ocelot *op = rule->port->ocelot;
+ struct vcap_data data;
+ int row = (ix / 2);
+ u32 cnt;
+
+ vcap_row_cmd(op, row, VCAP_CMD_READ, VCAP_SEL_COUNTER);
+ vcap_cache2action(op, &data);
+ data.tg_sw = VCAP_TG_HALF;
+ is2_data_get(&data, ix);
+ cnt = vcap_data_get(data.counter, data.counter_offset,
+ vcap_is2.counter_width);
+
+ rule->stats.pkts = cnt;
+}
+
+static void ocelot_ace_rule_add(struct ocelot_acl_block *block,
+ struct ocelot_ace_rule *rule)
+{
+ struct ocelot_ace_rule *tmp;
+ struct list_head *pos, *n;
+
+ block->count++;
+
+ if (list_empty(&block->rules)) {
+ list_add(&rule->list, &block->rules);
+ return;
+ }
+
+ list_for_each_safe(pos, n, &block->rules) {
+ tmp = list_entry(pos, struct ocelot_ace_rule, list);
+ if (rule->prio < tmp->prio)
+ break;
+ }
+ list_add(&rule->list, pos->prev);
+}
+
+static int ocelot_ace_rule_get_index_id(struct ocelot_acl_block *block,
+ struct ocelot_ace_rule *rule)
+{
+ struct ocelot_ace_rule *tmp;
+ int index = -1;
+
+ list_for_each_entry(tmp, &block->rules, list) {
+ ++index;
+ if (rule->id == tmp->id)
+ break;
+ }
+ return index;
+}
+
+static struct ocelot_ace_rule*
+ocelot_ace_rule_get_rule_index(struct ocelot_acl_block *block, int index)
+{
+ struct ocelot_ace_rule *tmp;
+ int i = 0;
+
+ list_for_each_entry(tmp, &block->rules, list) {
+ if (i == index)
+ return tmp;
+ ++i;
+ }
+
+ return NULL;
+}
+
+int ocelot_ace_rule_offload_add(struct ocelot_ace_rule *rule)
+{
+ struct ocelot_ace_rule *ace;
+ int i, index;
+
+ /* Add rule to the linked list */
+ ocelot_ace_rule_add(acl_block, rule);
+
+ /* Get the index of the inserted rule */
+ index = ocelot_ace_rule_get_index_id(acl_block, rule);
+
+ /* Move down the rules to make place for the new rule */
+ for (i = acl_block->count - 1; i > index; i--) {
+ ace = ocelot_ace_rule_get_rule_index(acl_block, i);
+ is2_entry_set(rule->port->ocelot, i, ace);
+ }
+
+ /* Now insert the new rule */
+ is2_entry_set(rule->port->ocelot, index, rule);
+ return 0;
+}
+
+static void ocelot_ace_rule_del(struct ocelot_acl_block *block,
+ struct ocelot_ace_rule *rule)
+{
+ struct ocelot_ace_rule *tmp;
+ struct list_head *pos, *q;
+
+ list_for_each_safe(pos, q, &block->rules) {
+ tmp = list_entry(pos, struct ocelot_ace_rule, list);
+ if (tmp->id == rule->id) {
+ list_del(pos);
+ kfree(tmp);
+ }
+ }
+
+ block->count--;
+}
+
+int ocelot_ace_rule_offload_del(struct ocelot_ace_rule *rule)
+{
+ struct ocelot_ace_rule del_ace;
+ struct ocelot_ace_rule *ace;
+ int i, index;
+
+ memset(&del_ace, 0, sizeof(del_ace));
+
+ /* Gets index of the rule */
+ index = ocelot_ace_rule_get_index_id(acl_block, rule);
+
+ /* Delete rule */
+ ocelot_ace_rule_del(acl_block, rule);
+
+ /* Move up all the blocks over the deleted rule */
+ for (i = index; i < acl_block->count; i++) {
+ ace = ocelot_ace_rule_get_rule_index(acl_block, i);
+ is2_entry_set(rule->port->ocelot, i, ace);
+ }
+
+ /* Now delete the last rule, because it is duplicated */
+ is2_entry_set(rule->port->ocelot, acl_block->count, &del_ace);
+
+ return 0;
+}
+
+int ocelot_ace_rule_stats_update(struct ocelot_ace_rule *rule)
+{
+ struct ocelot_ace_rule *tmp;
+ int index;
+
+ index = ocelot_ace_rule_get_index_id(acl_block, rule);
+ is2_entry_get(rule, index);
+
+ /* After we get the result we need to clear the counters */
+ tmp = ocelot_ace_rule_get_rule_index(acl_block, index);
+ tmp->stats.pkts = 0;
+ is2_entry_set(rule->port->ocelot, index, tmp);
+
+ return 0;
+}
+
+static struct ocelot_acl_block *ocelot_acl_block_create(struct ocelot *ocelot)
+{
+ struct ocelot_acl_block *block;
+
+ block = kzalloc(sizeof(*block), GFP_KERNEL);
+ if (!block)
+ return NULL;
+
+ INIT_LIST_HEAD(&block->rules);
+ block->count = 0;
+ block->ocelot = ocelot;
+
+ return block;
+}
+
+static void ocelot_acl_block_destroy(struct ocelot_acl_block *block)
+{
+ kfree(block);
+}
+
+int ocelot_ace_init(struct ocelot *ocelot)
+{
+ struct vcap_data data;
+
+ memset(&data, 0, sizeof(data));
+ vcap_entry2cache(ocelot, &data);
+ ocelot_write(ocelot, vcap_is2.entry_count, S2_CORE_MV_CFG);
+ vcap_cmd(ocelot, 0, VCAP_CMD_INITIALIZE, VCAP_SEL_ENTRY);
+
+ vcap_action2cache(ocelot, &data);
+ ocelot_write(ocelot, vcap_is2.action_count, S2_CORE_MV_CFG);
+ vcap_cmd(ocelot, 0, VCAP_CMD_INITIALIZE,
+ VCAP_SEL_ACTION | VCAP_SEL_COUNTER);
+
+ /* Create a policer that will drop the frames for the cpu.
+ * This policer will be used as action in the acl rules to drop
+ * frames.
+ */
+ ocelot_write_gix(ocelot, 0x299, ANA_POL_MODE_CFG,
+ OCELOT_POLICER_DISCARD);
+ ocelot_write_gix(ocelot, 0x1, ANA_POL_PIR_CFG,
+ OCELOT_POLICER_DISCARD);
+ ocelot_write_gix(ocelot, 0x3fffff, ANA_POL_PIR_STATE,
+ OCELOT_POLICER_DISCARD);
+ ocelot_write_gix(ocelot, 0x0, ANA_POL_CIR_CFG,
+ OCELOT_POLICER_DISCARD);
+ ocelot_write_gix(ocelot, 0x3fffff, ANA_POL_CIR_STATE,
+ OCELOT_POLICER_DISCARD);
+
+ acl_block = ocelot_acl_block_create(ocelot);
+
+ return 0;
+}
+
+void ocelot_ace_deinit(void)
+{
+ ocelot_acl_block_destroy(acl_block);
+}
diff --git a/drivers/net/ethernet/mscc/ocelot_ace.h b/drivers/net/ethernet/mscc/ocelot_ace.h
new file mode 100644
index 000000000000..e98944c87259
--- /dev/null
+++ b/drivers/net/ethernet/mscc/ocelot_ace.h
@@ -0,0 +1,232 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/* Microsemi Ocelot Switch driver
+ * Copyright (c) 2019 Microsemi Corporation
+ */
+
+#ifndef _MSCC_OCELOT_ACE_H_
+#define _MSCC_OCELOT_ACE_H_
+
+#include "ocelot.h"
+#include <net/sch_generic.h>
+#include <net/pkt_cls.h>
+
+struct ocelot_ipv4 {
+ u8 addr[4];
+};
+
+enum ocelot_vcap_bit {
+ OCELOT_VCAP_BIT_ANY,
+ OCELOT_VCAP_BIT_0,
+ OCELOT_VCAP_BIT_1
+};
+
+struct ocelot_vcap_u8 {
+ u8 value[1];
+ u8 mask[1];
+};
+
+struct ocelot_vcap_u16 {
+ u8 value[2];
+ u8 mask[2];
+};
+
+struct ocelot_vcap_u24 {
+ u8 value[3];
+ u8 mask[3];
+};
+
+struct ocelot_vcap_u32 {
+ u8 value[4];
+ u8 mask[4];
+};
+
+struct ocelot_vcap_u40 {
+ u8 value[5];
+ u8 mask[5];
+};
+
+struct ocelot_vcap_u48 {
+ u8 value[6];
+ u8 mask[6];
+};
+
+struct ocelot_vcap_u64 {
+ u8 value[8];
+ u8 mask[8];
+};
+
+struct ocelot_vcap_u128 {
+ u8 value[16];
+ u8 mask[16];
+};
+
+struct ocelot_vcap_vid {
+ u16 value;
+ u16 mask;
+};
+
+struct ocelot_vcap_ipv4 {
+ struct ocelot_ipv4 value;
+ struct ocelot_ipv4 mask;
+};
+
+struct ocelot_vcap_udp_tcp {
+ u16 value;
+ u16 mask;
+};
+
+enum ocelot_ace_type {
+ OCELOT_ACE_TYPE_ANY,
+ OCELOT_ACE_TYPE_ETYPE,
+ OCELOT_ACE_TYPE_LLC,
+ OCELOT_ACE_TYPE_SNAP,
+ OCELOT_ACE_TYPE_ARP,
+ OCELOT_ACE_TYPE_IPV4,
+ OCELOT_ACE_TYPE_IPV6
+};
+
+struct ocelot_ace_vlan {
+ struct ocelot_vcap_vid vid; /* VLAN ID (12 bit) */
+ struct ocelot_vcap_u8 pcp; /* PCP (3 bit) */
+ enum ocelot_vcap_bit dei; /* DEI */
+ enum ocelot_vcap_bit tagged; /* Tagged/untagged frame */
+};
+
+struct ocelot_ace_frame_etype {
+ struct ocelot_vcap_u48 dmac;
+ struct ocelot_vcap_u48 smac;
+ struct ocelot_vcap_u16 etype;
+ struct ocelot_vcap_u16 data; /* MAC data */
+};
+
+struct ocelot_ace_frame_llc {
+ struct ocelot_vcap_u48 dmac;
+ struct ocelot_vcap_u48 smac;
+
+ /* LLC header: DSAP at byte 0, SSAP at byte 1, Control at byte 2 */
+ struct ocelot_vcap_u32 llc;
+};
+
+struct ocelot_ace_frame_snap {
+ struct ocelot_vcap_u48 dmac;
+ struct ocelot_vcap_u48 smac;
+
+ /* SNAP header: Organization Code at byte 0, Type at byte 3 */
+ struct ocelot_vcap_u40 snap;
+};
+
+struct ocelot_ace_frame_arp {
+ struct ocelot_vcap_u48 smac;
+ enum ocelot_vcap_bit arp; /* Opcode ARP/RARP */
+ enum ocelot_vcap_bit req; /* Opcode request/reply */
+ enum ocelot_vcap_bit unknown; /* Opcode unknown */
+ enum ocelot_vcap_bit smac_match; /* Sender MAC matches SMAC */
+ enum ocelot_vcap_bit dmac_match; /* Target MAC matches DMAC */
+
+ /**< Protocol addr. length 4, hardware length 6 */
+ enum ocelot_vcap_bit length;
+
+ enum ocelot_vcap_bit ip; /* Protocol address type IP */
+ enum ocelot_vcap_bit ethernet; /* Hardware address type Ethernet */
+ struct ocelot_vcap_ipv4 sip; /* Sender IP address */
+ struct ocelot_vcap_ipv4 dip; /* Target IP address */
+};
+
+struct ocelot_ace_frame_ipv4 {
+ enum ocelot_vcap_bit ttl; /* TTL zero */
+ enum ocelot_vcap_bit fragment; /* Fragment */
+ enum ocelot_vcap_bit options; /* Header options */
+ struct ocelot_vcap_u8 ds;
+ struct ocelot_vcap_u8 proto; /* Protocol */
+ struct ocelot_vcap_ipv4 sip; /* Source IP address */
+ struct ocelot_vcap_ipv4 dip; /* Destination IP address */
+ struct ocelot_vcap_u48 data; /* Not UDP/TCP: IP data */
+ struct ocelot_vcap_udp_tcp sport; /* UDP/TCP: Source port */
+ struct ocelot_vcap_udp_tcp dport; /* UDP/TCP: Destination port */
+ enum ocelot_vcap_bit tcp_fin;
+ enum ocelot_vcap_bit tcp_syn;
+ enum ocelot_vcap_bit tcp_rst;
+ enum ocelot_vcap_bit tcp_psh;
+ enum ocelot_vcap_bit tcp_ack;
+ enum ocelot_vcap_bit tcp_urg;
+ enum ocelot_vcap_bit sip_eq_dip; /* SIP equals DIP */
+ enum ocelot_vcap_bit sport_eq_dport; /* SPORT equals DPORT */
+ enum ocelot_vcap_bit seq_zero; /* TCP sequence number is zero */
+};
+
+struct ocelot_ace_frame_ipv6 {
+ struct ocelot_vcap_u8 proto; /* IPv6 protocol */
+ struct ocelot_vcap_u128 sip; /* IPv6 source (byte 0-7 ignored) */
+ enum ocelot_vcap_bit ttl; /* TTL zero */
+ struct ocelot_vcap_u8 ds;
+ struct ocelot_vcap_u48 data; /* Not UDP/TCP: IP data */
+ struct ocelot_vcap_udp_tcp sport;
+ struct ocelot_vcap_udp_tcp dport;
+ enum ocelot_vcap_bit tcp_fin;
+ enum ocelot_vcap_bit tcp_syn;
+ enum ocelot_vcap_bit tcp_rst;
+ enum ocelot_vcap_bit tcp_psh;
+ enum ocelot_vcap_bit tcp_ack;
+ enum ocelot_vcap_bit tcp_urg;
+ enum ocelot_vcap_bit sip_eq_dip; /* SIP equals DIP */
+ enum ocelot_vcap_bit sport_eq_dport; /* SPORT equals DPORT */
+ enum ocelot_vcap_bit seq_zero; /* TCP sequence number is zero */
+};
+
+enum ocelot_ace_action {
+ OCELOT_ACL_ACTION_DROP,
+ OCELOT_ACL_ACTION_TRAP,
+};
+
+struct ocelot_ace_stats {
+ u64 bytes;
+ u64 pkts;
+ u64 used;
+};
+
+struct ocelot_ace_rule {
+ struct list_head list;
+ struct ocelot_port *port;
+
+ u16 prio;
+ u32 id;
+
+ enum ocelot_ace_action action;
+ struct ocelot_ace_stats stats;
+ int chip_port;
+
+ enum ocelot_vcap_bit dmac_mc;
+ enum ocelot_vcap_bit dmac_bc;
+ struct ocelot_ace_vlan vlan;
+
+ enum ocelot_ace_type type;
+ union {
+ /* ocelot_ACE_TYPE_ANY: No specific fields */
+ struct ocelot_ace_frame_etype etype;
+ struct ocelot_ace_frame_llc llc;
+ struct ocelot_ace_frame_snap snap;
+ struct ocelot_ace_frame_arp arp;
+ struct ocelot_ace_frame_ipv4 ipv4;
+ struct ocelot_ace_frame_ipv6 ipv6;
+ } frame;
+};
+
+struct ocelot_acl_block {
+ struct list_head rules;
+ struct ocelot *ocelot;
+ int count;
+};
+
+int ocelot_ace_rule_offload_add(struct ocelot_ace_rule *rule);
+int ocelot_ace_rule_offload_del(struct ocelot_ace_rule *rule);
+int ocelot_ace_rule_stats_update(struct ocelot_ace_rule *rule);
+
+int ocelot_ace_init(struct ocelot *ocelot);
+void ocelot_ace_deinit(void);
+
+int ocelot_setup_tc_block_flower_bind(struct ocelot_port *port,
+ struct flow_block_offload *f);
+void ocelot_setup_tc_block_flower_unbind(struct ocelot_port *port,
+ struct flow_block_offload *f);
+
+#endif /* _MSCC_OCELOT_ACE_H_ */
diff --git a/drivers/net/ethernet/mscc/ocelot_board.c b/drivers/net/ethernet/mscc/ocelot_board.c
index e7f90101d2e0..2451d4a96490 100644
--- a/drivers/net/ethernet/mscc/ocelot_board.c
+++ b/drivers/net/ethernet/mscc/ocelot_board.c
@@ -188,6 +188,7 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
{ QSYS, "qsys" },
{ ANA, "ana" },
{ QS, "qs" },
+ { S2, "s2" },
};
if (!np && !pdev->dev.platform_data)
@@ -290,8 +291,10 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
continue;
err = ocelot_probe_port(ocelot, port, regs, phy);
- if (err)
+ if (err) {
+ of_node_put(portnp);
return err;
+ }
phy_mode = of_get_phy_mode(portnp);
if (phy_mode < 0)
@@ -317,6 +320,7 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
dev_err(ocelot->dev,
"invalid phy mode for port%d, (Q)SGMII only\n",
port);
+ of_node_put(portnp);
return -EINVAL;
}
diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c
new file mode 100644
index 000000000000..7aaddc09c185
--- /dev/null
+++ b/drivers/net/ethernet/mscc/ocelot_flower.c
@@ -0,0 +1,363 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Microsemi Ocelot Switch driver
+ * Copyright (c) 2019 Microsemi Corporation
+ */
+
+#include <net/pkt_cls.h>
+#include <net/tc_act/tc_gact.h>
+
+#include "ocelot_ace.h"
+
+struct ocelot_port_block {
+ struct ocelot_acl_block *block;
+ struct ocelot_port *port;
+};
+
+static u16 get_prio(u32 prio)
+{
+ /* prio starts from 0x1000 while the ids starts from 0 */
+ return prio >> 16;
+}
+
+static int ocelot_flower_parse_action(struct flow_cls_offload *f,
+ struct ocelot_ace_rule *rule)
+{
+ const struct flow_action_entry *a;
+ int i;
+
+ if (f->rule->action.num_entries != 1)
+ return -EOPNOTSUPP;
+
+ flow_action_for_each(i, a, &f->rule->action) {
+ switch (a->id) {
+ case FLOW_ACTION_DROP:
+ rule->action = OCELOT_ACL_ACTION_DROP;
+ break;
+ case FLOW_ACTION_TRAP:
+ rule->action = OCELOT_ACL_ACTION_TRAP;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ }
+
+ return 0;
+}
+
+static int ocelot_flower_parse(struct flow_cls_offload *f,
+ struct ocelot_ace_rule *ocelot_rule)
+{
+ struct flow_rule *rule = flow_cls_offload_flow_rule(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_PORTS) |
+ BIT(FLOW_DISSECTOR_KEY_VLAN) |
+ BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
+ BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
+ BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
+ return -EOPNOTSUPP;
+ }
+
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
+ struct flow_match_control match;
+
+ flow_rule_match_control(rule, &match);
+ }
+
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
+ struct flow_match_eth_addrs match;
+ u16 proto = ntohs(f->common.protocol);
+
+ /* The hw support mac matches only for MAC_ETYPE key,
+ * therefore if other matches(port, tcp flags, etc) are added
+ * 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)))
+ return -EOPNOTSUPP;
+
+ if (proto == ETH_P_IP ||
+ proto == ETH_P_IPV6 ||
+ proto == ETH_P_ARP)
+ return -EOPNOTSUPP;
+
+ flow_rule_match_eth_addrs(rule, &match);
+ ocelot_rule->type = OCELOT_ACE_TYPE_ETYPE;
+ ether_addr_copy(ocelot_rule->frame.etype.dmac.value,
+ match.key->dst);
+ ether_addr_copy(ocelot_rule->frame.etype.smac.value,
+ match.key->src);
+ ether_addr_copy(ocelot_rule->frame.etype.dmac.mask,
+ match.mask->dst);
+ ether_addr_copy(ocelot_rule->frame.etype.smac.mask,
+ match.mask->src);
+ goto finished_key_parsing;
+ }
+
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
+ struct flow_match_basic match;
+
+ flow_rule_match_basic(rule, &match);
+ if (ntohs(match.key->n_proto) == ETH_P_IP) {
+ ocelot_rule->type = OCELOT_ACE_TYPE_IPV4;
+ ocelot_rule->frame.ipv4.proto.value[0] =
+ match.key->ip_proto;
+ ocelot_rule->frame.ipv4.proto.mask[0] =
+ match.mask->ip_proto;
+ }
+ if (ntohs(match.key->n_proto) == ETH_P_IPV6) {
+ ocelot_rule->type = OCELOT_ACE_TYPE_IPV6;
+ ocelot_rule->frame.ipv6.proto.value[0] =
+ match.key->ip_proto;
+ ocelot_rule->frame.ipv6.proto.mask[0] =
+ match.mask->ip_proto;
+ }
+ }
+
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) &&
+ ntohs(f->common.protocol) == ETH_P_IP) {
+ struct flow_match_ipv4_addrs match;
+ u8 *tmp;
+
+ flow_rule_match_ipv4_addrs(rule, &match);
+ tmp = &ocelot_rule->frame.ipv4.sip.value.addr[0];
+ memcpy(tmp, &match.key->src, 4);
+
+ tmp = &ocelot_rule->frame.ipv4.sip.mask.addr[0];
+ memcpy(tmp, &match.mask->src, 4);
+
+ tmp = &ocelot_rule->frame.ipv4.dip.value.addr[0];
+ memcpy(tmp, &match.key->dst, 4);
+
+ tmp = &ocelot_rule->frame.ipv4.dip.mask.addr[0];
+ memcpy(tmp, &match.mask->dst, 4);
+ }
+
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) &&
+ ntohs(f->common.protocol) == ETH_P_IPV6) {
+ return -EOPNOTSUPP;
+ }
+
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
+ struct flow_match_ports match;
+
+ flow_rule_match_ports(rule, &match);
+ ocelot_rule->frame.ipv4.sport.value = ntohs(match.key->src);
+ ocelot_rule->frame.ipv4.sport.mask = ntohs(match.mask->src);
+ ocelot_rule->frame.ipv4.dport.value = ntohs(match.key->dst);
+ ocelot_rule->frame.ipv4.dport.mask = ntohs(match.mask->dst);
+ }
+
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
+ struct flow_match_vlan match;
+
+ flow_rule_match_vlan(rule, &match);
+ ocelot_rule->type = OCELOT_ACE_TYPE_ANY;
+ ocelot_rule->vlan.vid.value = match.key->vlan_id;
+ ocelot_rule->vlan.vid.mask = match.mask->vlan_id;
+ ocelot_rule->vlan.pcp.value[0] = match.key->vlan_priority;
+ ocelot_rule->vlan.pcp.mask[0] = match.mask->vlan_priority;
+ }
+
+finished_key_parsing:
+ ocelot_rule->prio = get_prio(f->common.prio);
+ ocelot_rule->id = f->cookie;
+ return ocelot_flower_parse_action(f, ocelot_rule);
+}
+
+static
+struct ocelot_ace_rule *ocelot_ace_rule_create(struct flow_cls_offload *f,
+ struct ocelot_port_block *block)
+{
+ struct ocelot_ace_rule *rule;
+
+ rule = kzalloc(sizeof(*rule), GFP_KERNEL);
+ if (!rule)
+ return NULL;
+
+ rule->port = block->port;
+ rule->chip_port = block->port->chip_port;
+ return rule;
+}
+
+static int ocelot_flower_replace(struct flow_cls_offload *f,
+ struct ocelot_port_block *port_block)
+{
+ struct ocelot_ace_rule *rule;
+ int ret;
+
+ rule = ocelot_ace_rule_create(f, port_block);
+ if (!rule)
+ return -ENOMEM;
+
+ ret = ocelot_flower_parse(f, rule);
+ if (ret) {
+ kfree(rule);
+ return ret;
+ }
+
+ ret = ocelot_ace_rule_offload_add(rule);
+ if (ret)
+ return ret;
+
+ port_block->port->tc.offload_cnt++;
+ return 0;
+}
+
+static int ocelot_flower_destroy(struct flow_cls_offload *f,
+ struct ocelot_port_block *port_block)
+{
+ struct ocelot_ace_rule rule;
+ int ret;
+
+ rule.prio = get_prio(f->common.prio);
+ rule.port = port_block->port;
+ rule.id = f->cookie;
+
+ ret = ocelot_ace_rule_offload_del(&rule);
+ if (ret)
+ return ret;
+
+ port_block->port->tc.offload_cnt--;
+ return 0;
+}
+
+static int ocelot_flower_stats_update(struct flow_cls_offload *f,
+ struct ocelot_port_block *port_block)
+{
+ struct ocelot_ace_rule rule;
+ int ret;
+
+ rule.prio = get_prio(f->common.prio);
+ rule.port = port_block->port;
+ rule.id = f->cookie;
+ ret = ocelot_ace_rule_stats_update(&rule);
+ if (ret)
+ return ret;
+
+ flow_stats_update(&f->stats, 0x0, rule.stats.pkts, 0x0);
+ return 0;
+}
+
+static int ocelot_setup_tc_cls_flower(struct flow_cls_offload *f,
+ struct ocelot_port_block *port_block)
+{
+ switch (f->command) {
+ case FLOW_CLS_REPLACE:
+ return ocelot_flower_replace(f, port_block);
+ case FLOW_CLS_DESTROY:
+ return ocelot_flower_destroy(f, port_block);
+ case FLOW_CLS_STATS:
+ return ocelot_flower_stats_update(f, port_block);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int ocelot_setup_tc_block_cb_flower(enum tc_setup_type type,
+ void *type_data, void *cb_priv)
+{
+ struct ocelot_port_block *port_block = cb_priv;
+
+ if (!tc_cls_can_offload_and_chain0(port_block->port->dev, type_data))
+ return -EOPNOTSUPP;
+
+ switch (type) {
+ case TC_SETUP_CLSFLOWER:
+ return ocelot_setup_tc_cls_flower(type_data, cb_priv);
+ case TC_SETUP_CLSMATCHALL:
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static struct ocelot_port_block*
+ocelot_port_block_create(struct ocelot_port *port)
+{
+ struct ocelot_port_block *port_block;
+
+ port_block = kzalloc(sizeof(*port_block), GFP_KERNEL);
+ if (!port_block)
+ return NULL;
+
+ port_block->port = port;
+
+ return port_block;
+}
+
+static void ocelot_port_block_destroy(struct ocelot_port_block *block)
+{
+ kfree(block);
+}
+
+static void ocelot_tc_block_unbind(void *cb_priv)
+{
+ struct ocelot_port_block *port_block = cb_priv;
+
+ ocelot_port_block_destroy(port_block);
+}
+
+int ocelot_setup_tc_block_flower_bind(struct ocelot_port *port,
+ struct flow_block_offload *f)
+{
+ struct ocelot_port_block *port_block;
+ struct flow_block_cb *block_cb;
+ int ret;
+
+ if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
+ return -EOPNOTSUPP;
+
+ block_cb = flow_block_cb_lookup(f, ocelot_setup_tc_block_cb_flower,
+ port);
+ if (!block_cb) {
+ port_block = ocelot_port_block_create(port);
+ if (!port_block)
+ return -ENOMEM;
+
+ block_cb = flow_block_cb_alloc(f->net,
+ ocelot_setup_tc_block_cb_flower,
+ port, port_block,
+ ocelot_tc_block_unbind);
+ if (IS_ERR(block_cb)) {
+ ret = PTR_ERR(block_cb);
+ goto err_cb_register;
+ }
+ flow_block_cb_add(block_cb, f);
+ list_add_tail(&block_cb->driver_list, f->driver_block_list);
+ } else {
+ port_block = flow_block_cb_priv(block_cb);
+ }
+
+ flow_block_cb_incref(block_cb);
+ return 0;
+
+err_cb_register:
+ ocelot_port_block_destroy(port_block);
+
+ return ret;
+}
+
+void ocelot_setup_tc_block_flower_unbind(struct ocelot_port *port,
+ struct flow_block_offload *f)
+{
+ struct flow_block_cb *block_cb;
+
+ block_cb = flow_block_cb_lookup(f, ocelot_setup_tc_block_cb_flower,
+ port);
+ if (!block_cb)
+ return;
+
+ if (!flow_block_cb_decref(block_cb)) {
+ flow_block_cb_remove(block_cb, f);
+ list_del(&block_cb->driver_list);
+ }
+}
diff --git a/drivers/net/ethernet/mscc/ocelot_police.c b/drivers/net/ethernet/mscc/ocelot_police.c
new file mode 100644
index 000000000000..701e82dd749a
--- /dev/null
+++ b/drivers/net/ethernet/mscc/ocelot_police.c
@@ -0,0 +1,227 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Microsemi Ocelot Switch driver
+ *
+ * Copyright (c) 2019 Microsemi Corporation
+ */
+
+#include "ocelot_police.h"
+
+enum mscc_qos_rate_mode {
+ MSCC_QOS_RATE_MODE_DISABLED, /* Policer/shaper disabled */
+ MSCC_QOS_RATE_MODE_LINE, /* Measure line rate in kbps incl. IPG */
+ MSCC_QOS_RATE_MODE_DATA, /* Measures data rate in kbps excl. IPG */
+ MSCC_QOS_RATE_MODE_FRAME, /* Measures frame rate in fps */
+ __MSCC_QOS_RATE_MODE_END,
+ NUM_MSCC_QOS_RATE_MODE = __MSCC_QOS_RATE_MODE_END,
+ MSCC_QOS_RATE_MODE_MAX = __MSCC_QOS_RATE_MODE_END - 1,
+};
+
+/* Types for ANA:POL[0-192]:POL_MODE_CFG.FRM_MODE */
+#define POL_MODE_LINERATE 0 /* Incl IPG. Unit: 33 1/3 kbps, 4096 bytes */
+#define POL_MODE_DATARATE 1 /* Excl IPG. Unit: 33 1/3 kbps, 4096 bytes */
+#define POL_MODE_FRMRATE_HI 2 /* Unit: 33 1/3 fps, 32.8 frames */
+#define POL_MODE_FRMRATE_LO 3 /* Unit: 1/3 fps, 0.3 frames */
+
+/* Policer indexes */
+#define POL_IX_PORT 0 /* 0-11 : Port policers */
+#define POL_IX_QUEUE 32 /* 32-127 : Queue policers */
+
+/* Default policer order */
+#define POL_ORDER 0x1d3 /* Ocelot policer order: Serial (QoS -> Port -> VCAP) */
+
+struct qos_policer_conf {
+ enum mscc_qos_rate_mode mode;
+ bool dlb; /* Enable DLB (dual leaky bucket mode */
+ bool cf; /* Coupling flag (ignored in SLB mode) */
+ u32 cir; /* CIR in kbps/fps (ignored in SLB mode) */
+ u32 cbs; /* CBS in bytes/frames (ignored in SLB mode) */
+ u32 pir; /* PIR in kbps/fps */
+ u32 pbs; /* PBS in bytes/frames */
+ u8 ipg; /* Size of IPG when MSCC_QOS_RATE_MODE_LINE is chosen */
+};
+
+static int qos_policer_conf_set(struct ocelot_port *port, u32 pol_ix,
+ struct qos_policer_conf *conf)
+{
+ u32 cf = 0, cir_ena = 0, frm_mode = POL_MODE_LINERATE;
+ u32 cir = 0, cbs = 0, pir = 0, pbs = 0;
+ bool cir_discard = 0, pir_discard = 0;
+ struct ocelot *ocelot = port->ocelot;
+ u32 pbs_max = 0, cbs_max = 0;
+ u8 ipg = 20;
+ u32 value;
+
+ pir = conf->pir;
+ pbs = conf->pbs;
+
+ switch (conf->mode) {
+ case MSCC_QOS_RATE_MODE_LINE:
+ case MSCC_QOS_RATE_MODE_DATA:
+ if (conf->mode == MSCC_QOS_RATE_MODE_LINE) {
+ frm_mode = POL_MODE_LINERATE;
+ ipg = min_t(u8, GENMASK(4, 0), conf->ipg);
+ } else {
+ frm_mode = POL_MODE_DATARATE;
+ }
+ if (conf->dlb) {
+ cir_ena = 1;
+ cir = conf->cir;
+ cbs = conf->cbs;
+ if (cir == 0 && cbs == 0) {
+ /* Discard cir frames */
+ cir_discard = 1;
+ } else {
+ cir = DIV_ROUND_UP(cir, 100);
+ cir *= 3; /* 33 1/3 kbps */
+ cbs = DIV_ROUND_UP(cbs, 4096);
+ cbs = (cbs ? cbs : 1); /* No zero burst size */
+ cbs_max = 60; /* Limit burst size */
+ cf = conf->cf;
+ if (cf)
+ pir += conf->cir;
+ }
+ }
+ if (pir == 0 && pbs == 0) {
+ /* Discard PIR frames */
+ pir_discard = 1;
+ } else {
+ pir = DIV_ROUND_UP(pir, 100);
+ pir *= 3; /* 33 1/3 kbps */
+ pbs = DIV_ROUND_UP(pbs, 4096);
+ pbs = (pbs ? pbs : 1); /* No zero burst size */
+ pbs_max = 60; /* Limit burst size */
+ }
+ break;
+ case MSCC_QOS_RATE_MODE_FRAME:
+ if (pir >= 100) {
+ frm_mode = POL_MODE_FRMRATE_HI;
+ pir = DIV_ROUND_UP(pir, 100);
+ pir *= 3; /* 33 1/3 fps */
+ pbs = (pbs * 10) / 328; /* 32.8 frames */
+ pbs = (pbs ? pbs : 1); /* No zero burst size */
+ pbs_max = GENMASK(6, 0); /* Limit burst size */
+ } else {
+ frm_mode = POL_MODE_FRMRATE_LO;
+ if (pir == 0 && pbs == 0) {
+ /* Discard all frames */
+ pir_discard = 1;
+ cir_discard = 1;
+ } else {
+ pir *= 3; /* 1/3 fps */
+ pbs = (pbs * 10) / 3; /* 0.3 frames */
+ pbs = (pbs ? pbs : 1); /* No zero burst size */
+ pbs_max = 61; /* Limit burst size */
+ }
+ }
+ break;
+ default: /* MSCC_QOS_RATE_MODE_DISABLED */
+ /* Disable policer using maximum rate and zero burst */
+ pir = GENMASK(15, 0);
+ pbs = 0;
+ break;
+ }
+
+ /* Check limits */
+ if (pir > GENMASK(15, 0)) {
+ netdev_err(port->dev, "Invalid pir\n");
+ return -EINVAL;
+ }
+
+ if (cir > GENMASK(15, 0)) {
+ netdev_err(port->dev, "Invalid cir\n");
+ return -EINVAL;
+ }
+
+ if (pbs > pbs_max) {
+ netdev_err(port->dev, "Invalid pbs\n");
+ return -EINVAL;
+ }
+
+ if (cbs > cbs_max) {
+ netdev_err(port->dev, "Invalid cbs\n");
+ return -EINVAL;
+ }
+
+ value = (ANA_POL_MODE_CFG_IPG_SIZE(ipg) |
+ ANA_POL_MODE_CFG_FRM_MODE(frm_mode) |
+ (cf ? ANA_POL_MODE_CFG_DLB_COUPLED : 0) |
+ (cir_ena ? ANA_POL_MODE_CFG_CIR_ENA : 0) |
+ ANA_POL_MODE_CFG_OVERSHOOT_ENA);
+
+ ocelot_write_gix(ocelot, value, ANA_POL_MODE_CFG, pol_ix);
+
+ ocelot_write_gix(ocelot,
+ ANA_POL_PIR_CFG_PIR_RATE(pir) |
+ ANA_POL_PIR_CFG_PIR_BURST(pbs),
+ ANA_POL_PIR_CFG, pol_ix);
+
+ ocelot_write_gix(ocelot,
+ (pir_discard ? GENMASK(22, 0) : 0),
+ ANA_POL_PIR_STATE, pol_ix);
+
+ ocelot_write_gix(ocelot,
+ ANA_POL_CIR_CFG_CIR_RATE(cir) |
+ ANA_POL_CIR_CFG_CIR_BURST(cbs),
+ ANA_POL_CIR_CFG, pol_ix);
+
+ ocelot_write_gix(ocelot,
+ (cir_discard ? GENMASK(22, 0) : 0),
+ ANA_POL_CIR_STATE, pol_ix);
+
+ return 0;
+}
+
+int ocelot_port_policer_add(struct ocelot_port *port,
+ struct ocelot_policer *pol)
+{
+ struct ocelot *ocelot = port->ocelot;
+ struct qos_policer_conf pp = { 0 };
+ int err;
+
+ if (!pol)
+ return -EINVAL;
+
+ pp.mode = MSCC_QOS_RATE_MODE_DATA;
+ pp.pir = pol->rate;
+ pp.pbs = pol->burst;
+
+ netdev_dbg(port->dev,
+ "%s: port %u pir %u kbps, pbs %u bytes\n",
+ __func__, port->chip_port, pp.pir, pp.pbs);
+
+ err = qos_policer_conf_set(port, POL_IX_PORT + port->chip_port, &pp);
+ if (err)
+ return err;
+
+ ocelot_rmw_gix(ocelot,
+ ANA_PORT_POL_CFG_PORT_POL_ENA |
+ ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER),
+ ANA_PORT_POL_CFG_PORT_POL_ENA |
+ ANA_PORT_POL_CFG_POL_ORDER_M,
+ ANA_PORT_POL_CFG, port->chip_port);
+
+ return 0;
+}
+
+int ocelot_port_policer_del(struct ocelot_port *port)
+{
+ struct ocelot *ocelot = port->ocelot;
+ struct qos_policer_conf pp = { 0 };
+ int err;
+
+ netdev_dbg(port->dev, "%s: port %u\n", __func__, port->chip_port);
+
+ pp.mode = MSCC_QOS_RATE_MODE_DISABLED;
+
+ err = qos_policer_conf_set(port, POL_IX_PORT + port->chip_port, &pp);
+ if (err)
+ return err;
+
+ ocelot_rmw_gix(ocelot,
+ ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER),
+ ANA_PORT_POL_CFG_PORT_POL_ENA |
+ ANA_PORT_POL_CFG_POL_ORDER_M,
+ ANA_PORT_POL_CFG, port->chip_port);
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/mscc/ocelot_police.h b/drivers/net/ethernet/mscc/ocelot_police.h
new file mode 100644
index 000000000000..d1137f79efda
--- /dev/null
+++ b/drivers/net/ethernet/mscc/ocelot_police.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/* Microsemi Ocelot Switch driver
+ *
+ * Copyright (c) 2019 Microsemi Corporation
+ */
+
+#ifndef _MSCC_OCELOT_POLICE_H_
+#define _MSCC_OCELOT_POLICE_H_
+
+#include "ocelot.h"
+
+struct ocelot_policer {
+ u32 rate; /* kilobit per second */
+ u32 burst; /* bytes */
+};
+
+int ocelot_port_policer_add(struct ocelot_port *port,
+ struct ocelot_policer *pol);
+
+int ocelot_port_policer_del(struct ocelot_port *port);
+
+#endif /* _MSCC_OCELOT_POLICE_H_ */
diff --git a/drivers/net/ethernet/mscc/ocelot_regs.c b/drivers/net/ethernet/mscc/ocelot_regs.c
index 9271af18b93b..6c387f994ec5 100644
--- a/drivers/net/ethernet/mscc/ocelot_regs.c
+++ b/drivers/net/ethernet/mscc/ocelot_regs.c
@@ -224,12 +224,23 @@ static const u32 ocelot_sys_regmap[] = {
REG(SYS_PTP_CFG, 0x0006c4),
};
+static const u32 ocelot_s2_regmap[] = {
+ REG(S2_CORE_UPDATE_CTRL, 0x000000),
+ REG(S2_CORE_MV_CFG, 0x000004),
+ REG(S2_CACHE_ENTRY_DAT, 0x000008),
+ REG(S2_CACHE_MASK_DAT, 0x000108),
+ REG(S2_CACHE_ACTION_DAT, 0x000208),
+ REG(S2_CACHE_CNT_DAT, 0x000308),
+ REG(S2_CACHE_TG_DAT, 0x000388),
+};
+
static const u32 *ocelot_regmap[] = {
[ANA] = ocelot_ana_regmap,
[QS] = ocelot_qs_regmap,
[QSYS] = ocelot_qsys_regmap,
[REW] = ocelot_rew_regmap,
[SYS] = ocelot_sys_regmap,
+ [S2] = ocelot_s2_regmap,
};
static const struct reg_field ocelot_regfields[] = {
diff --git a/drivers/net/ethernet/mscc/ocelot_s2.h b/drivers/net/ethernet/mscc/ocelot_s2.h
new file mode 100644
index 000000000000..80107bec2e45
--- /dev/null
+++ b/drivers/net/ethernet/mscc/ocelot_s2.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/* Microsemi Ocelot Switch driver
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#ifndef _OCELOT_S2_CORE_H_
+#define _OCELOT_S2_CORE_H_
+
+#define S2_CORE_UPDATE_CTRL_UPDATE_CMD(x) (((x) << 22) & GENMASK(24, 22))
+#define S2_CORE_UPDATE_CTRL_UPDATE_CMD_M GENMASK(24, 22)
+#define S2_CORE_UPDATE_CTRL_UPDATE_CMD_X(x) (((x) & GENMASK(24, 22)) >> 22)
+#define S2_CORE_UPDATE_CTRL_UPDATE_ENTRY_DIS BIT(21)
+#define S2_CORE_UPDATE_CTRL_UPDATE_ACTION_DIS BIT(20)
+#define S2_CORE_UPDATE_CTRL_UPDATE_CNT_DIS BIT(19)
+#define S2_CORE_UPDATE_CTRL_UPDATE_ADDR(x) (((x) << 3) & GENMASK(18, 3))
+#define S2_CORE_UPDATE_CTRL_UPDATE_ADDR_M GENMASK(18, 3)
+#define S2_CORE_UPDATE_CTRL_UPDATE_ADDR_X(x) (((x) & GENMASK(18, 3)) >> 3)
+#define S2_CORE_UPDATE_CTRL_UPDATE_SHOT BIT(2)
+#define S2_CORE_UPDATE_CTRL_CLEAR_CACHE BIT(1)
+#define S2_CORE_UPDATE_CTRL_MV_TRAFFIC_IGN BIT(0)
+
+#define S2_CORE_MV_CFG_MV_NUM_POS(x) (((x) << 16) & GENMASK(31, 16))
+#define S2_CORE_MV_CFG_MV_NUM_POS_M GENMASK(31, 16)
+#define S2_CORE_MV_CFG_MV_NUM_POS_X(x) (((x) & GENMASK(31, 16)) >> 16)
+#define S2_CORE_MV_CFG_MV_SIZE(x) ((x) & GENMASK(15, 0))
+#define S2_CORE_MV_CFG_MV_SIZE_M GENMASK(15, 0)
+
+#define S2_CACHE_ENTRY_DAT_RSZ 0x4
+
+#define S2_CACHE_MASK_DAT_RSZ 0x4
+
+#define S2_CACHE_ACTION_DAT_RSZ 0x4
+
+#define S2_CACHE_CNT_DAT_RSZ 0x4
+
+#define S2_STICKY_VCAP_ROW_DELETED_STICKY BIT(0)
+
+#define S2_BIST_CTRL_TCAM_BIST BIT(1)
+#define S2_BIST_CTRL_TCAM_INIT BIT(0)
+
+#define S2_BIST_CFG_TCAM_BIST_SOE_ENA BIT(8)
+#define S2_BIST_CFG_TCAM_HCG_DIS BIT(7)
+#define S2_BIST_CFG_TCAM_CG_DIS BIT(6)
+#define S2_BIST_CFG_TCAM_BIAS(x) ((x) & GENMASK(5, 0))
+#define S2_BIST_CFG_TCAM_BIAS_M GENMASK(5, 0)
+
+#define S2_BIST_STAT_BIST_RT_ERR BIT(15)
+#define S2_BIST_STAT_BIST_PENC_ERR BIT(14)
+#define S2_BIST_STAT_BIST_COMP_ERR BIT(13)
+#define S2_BIST_STAT_BIST_ADDR_ERR BIT(12)
+#define S2_BIST_STAT_BIST_BL1E_ERR BIT(11)
+#define S2_BIST_STAT_BIST_BL1_ERR BIT(10)
+#define S2_BIST_STAT_BIST_BL0E_ERR BIT(9)
+#define S2_BIST_STAT_BIST_BL0_ERR BIT(8)
+#define S2_BIST_STAT_BIST_PH1_ERR BIT(7)
+#define S2_BIST_STAT_BIST_PH0_ERR BIT(6)
+#define S2_BIST_STAT_BIST_PV1_ERR BIT(5)
+#define S2_BIST_STAT_BIST_PV0_ERR BIT(4)
+#define S2_BIST_STAT_BIST_RUN BIT(3)
+#define S2_BIST_STAT_BIST_ERR BIT(2)
+#define S2_BIST_STAT_BIST_BUSY BIT(1)
+#define S2_BIST_STAT_TCAM_RDY BIT(0)
+
+#endif /* _OCELOT_S2_CORE_H_ */
diff --git a/drivers/net/ethernet/mscc/ocelot_tc.c b/drivers/net/ethernet/mscc/ocelot_tc.c
new file mode 100644
index 000000000000..9e6464ffae5d
--- /dev/null
+++ b/drivers/net/ethernet/mscc/ocelot_tc.c
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Microsemi Ocelot Switch TC driver
+ *
+ * Copyright (c) 2019 Microsemi Corporation
+ */
+
+#include "ocelot_tc.h"
+#include "ocelot_police.h"
+#include "ocelot_ace.h"
+#include <net/pkt_cls.h>
+
+static int ocelot_setup_tc_cls_matchall(struct ocelot_port *port,
+ struct tc_cls_matchall_offload *f,
+ bool ingress)
+{
+ struct netlink_ext_ack *extack = f->common.extack;
+ struct ocelot_policer pol = { 0 };
+ struct flow_action_entry *action;
+ int err;
+
+ netdev_dbg(port->dev, "%s: port %u command %d cookie %lu\n",
+ __func__, port->chip_port, f->command, f->cookie);
+
+ if (!ingress) {
+ NL_SET_ERR_MSG_MOD(extack, "Only ingress is supported");
+ return -EOPNOTSUPP;
+ }
+
+ switch (f->command) {
+ case TC_CLSMATCHALL_REPLACE:
+ if (!flow_offload_has_one_action(&f->rule->action)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Only one action is supported");
+ return -EOPNOTSUPP;
+ }
+
+ if (port->tc.block_shared) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Rate limit is not supported on shared blocks");
+ return -EOPNOTSUPP;
+ }
+
+ action = &f->rule->action.entries[0];
+
+ if (action->id != FLOW_ACTION_POLICE) {
+ NL_SET_ERR_MSG_MOD(extack, "Unsupported action");
+ return -EOPNOTSUPP;
+ }
+
+ if (port->tc.police_id && port->tc.police_id != f->cookie) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Only one policer per port is supported\n");
+ return -EEXIST;
+ }
+
+ pol.rate = (u32)div_u64(action->police.rate_bytes_ps, 1000) * 8;
+ pol.burst = (u32)div_u64(action->police.rate_bytes_ps *
+ PSCHED_NS2TICKS(action->police.burst),
+ PSCHED_TICKS_PER_SEC);
+
+ err = ocelot_port_policer_add(port, &pol);
+ if (err) {
+ NL_SET_ERR_MSG_MOD(extack, "Could not add policer\n");
+ return err;
+ }
+
+ port->tc.police_id = f->cookie;
+ port->tc.offload_cnt++;
+ return 0;
+ case TC_CLSMATCHALL_DESTROY:
+ if (port->tc.police_id != f->cookie)
+ return -ENOENT;
+
+ err = ocelot_port_policer_del(port);
+ if (err) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Could not delete policer\n");
+ return err;
+ }
+ port->tc.police_id = 0;
+ port->tc.offload_cnt--;
+ return 0;
+ case TC_CLSMATCHALL_STATS: /* fall through */
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int ocelot_setup_tc_block_cb(enum tc_setup_type type,
+ void *type_data,
+ void *cb_priv, bool ingress)
+{
+ struct ocelot_port *port = cb_priv;
+
+ if (!tc_cls_can_offload_and_chain0(port->dev, type_data))
+ return -EOPNOTSUPP;
+
+ switch (type) {
+ case TC_SETUP_CLSMATCHALL:
+ netdev_dbg(port->dev, "tc_block_cb: TC_SETUP_CLSMATCHALL %s\n",
+ ingress ? "ingress" : "egress");
+
+ return ocelot_setup_tc_cls_matchall(port, type_data, ingress);
+ case TC_SETUP_CLSFLOWER:
+ return 0;
+ default:
+ netdev_dbg(port->dev, "tc_block_cb: type %d %s\n",
+ type,
+ ingress ? "ingress" : "egress");
+
+ return -EOPNOTSUPP;
+ }
+}
+
+static int ocelot_setup_tc_block_cb_ig(enum tc_setup_type type,
+ void *type_data,
+ void *cb_priv)
+{
+ return ocelot_setup_tc_block_cb(type, type_data,
+ cb_priv, true);
+}
+
+static int ocelot_setup_tc_block_cb_eg(enum tc_setup_type type,
+ void *type_data,
+ void *cb_priv)
+{
+ return ocelot_setup_tc_block_cb(type, type_data,
+ cb_priv, false);
+}
+
+static LIST_HEAD(ocelot_block_cb_list);
+
+static int ocelot_setup_tc_block(struct ocelot_port *port,
+ struct flow_block_offload *f)
+{
+ struct flow_block_cb *block_cb;
+ tc_setup_cb_t *cb;
+ int err;
+
+ netdev_dbg(port->dev, "tc_block command %d, binder_type %d\n",
+ f->command, f->binder_type);
+
+ if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) {
+ cb = ocelot_setup_tc_block_cb_ig;
+ port->tc.block_shared = f->block_shared;
+ } else if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) {
+ cb = ocelot_setup_tc_block_cb_eg;
+ } else {
+ return -EOPNOTSUPP;
+ }
+
+ f->driver_block_list = &ocelot_block_cb_list;
+
+ switch (f->command) {
+ case FLOW_BLOCK_BIND:
+ if (flow_block_cb_is_busy(cb, port, &ocelot_block_cb_list))
+ return -EBUSY;
+
+ block_cb = flow_block_cb_alloc(f->net, cb, port, port, NULL);
+ if (IS_ERR(block_cb))
+ return PTR_ERR(block_cb);
+
+ err = ocelot_setup_tc_block_flower_bind(port, f);
+ if (err < 0) {
+ flow_block_cb_free(block_cb);
+ return err;
+ }
+ flow_block_cb_add(block_cb, f);
+ list_add_tail(&block_cb->driver_list, f->driver_block_list);
+ return 0;
+ case FLOW_BLOCK_UNBIND:
+ block_cb = flow_block_cb_lookup(f, cb, port);
+ if (!block_cb)
+ return -ENOENT;
+
+ ocelot_setup_tc_block_flower_unbind(port, f);
+ flow_block_cb_remove(block_cb, f);
+ list_del(&block_cb->driver_list);
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+int ocelot_setup_tc(struct net_device *dev, enum tc_setup_type type,
+ void *type_data)
+{
+ struct ocelot_port *port = netdev_priv(dev);
+
+ switch (type) {
+ case TC_SETUP_BLOCK:
+ return ocelot_setup_tc_block(port, type_data);
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
diff --git a/drivers/net/ethernet/mscc/ocelot_tc.h b/drivers/net/ethernet/mscc/ocelot_tc.h
new file mode 100644
index 000000000000..61757c2250a6
--- /dev/null
+++ b/drivers/net/ethernet/mscc/ocelot_tc.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/* Microsemi Ocelot Switch driver
+ *
+ * Copyright (c) 2019 Microsemi Corporation
+ */
+
+#ifndef _MSCC_OCELOT_TC_H_
+#define _MSCC_OCELOT_TC_H_
+
+#include <linux/netdevice.h>
+
+struct ocelot_port_tc {
+ bool block_shared;
+ unsigned long offload_cnt;
+
+ unsigned long police_id;
+};
+
+int ocelot_setup_tc(struct net_device *dev, enum tc_setup_type type,
+ void *type_data);
+
+#endif /* _MSCC_OCELOT_TC_H_ */
diff --git a/drivers/net/ethernet/mscc/ocelot_vcap.h b/drivers/net/ethernet/mscc/ocelot_vcap.h
new file mode 100644
index 000000000000..e22eac1da783
--- /dev/null
+++ b/drivers/net/ethernet/mscc/ocelot_vcap.h
@@ -0,0 +1,403 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
+ * Microsemi Ocelot Switch driver
+ * Copyright (c) 2019 Microsemi Corporation
+ */
+
+#ifndef _OCELOT_VCAP_H_
+#define _OCELOT_VCAP_H_
+
+/* =================================================================
+ * VCAP Common
+ * =================================================================
+ */
+
+/* VCAP Type-Group values */
+#define VCAP_TG_NONE 0 /* Entry is invalid */
+#define VCAP_TG_FULL 1 /* Full entry */
+#define VCAP_TG_HALF 2 /* Half entry */
+#define VCAP_TG_QUARTER 3 /* Quarter entry */
+
+/* =================================================================
+ * VCAP IS2
+ * =================================================================
+ */
+
+#define VCAP_IS2_CNT 64
+#define VCAP_IS2_ENTRY_WIDTH 376
+#define VCAP_IS2_ACTION_WIDTH 99
+#define VCAP_PORT_CNT 11
+
+/* IS2 half key types */
+#define IS2_TYPE_ETYPE 0
+#define IS2_TYPE_LLC 1
+#define IS2_TYPE_SNAP 2
+#define IS2_TYPE_ARP 3
+#define IS2_TYPE_IP_UDP_TCP 4
+#define IS2_TYPE_IP_OTHER 5
+#define IS2_TYPE_IPV6 6
+#define IS2_TYPE_OAM 7
+#define IS2_TYPE_SMAC_SIP6 8
+#define IS2_TYPE_ANY 100 /* Pseudo type */
+
+/* IS2 half key type mask for matching any IP */
+#define IS2_TYPE_MASK_IP_ANY 0xe
+
+/* IS2 action types */
+#define IS2_ACTION_TYPE_NORMAL 0
+#define IS2_ACTION_TYPE_SMAC_SIP 1
+
+/* IS2 MASK_MODE values */
+#define IS2_ACT_MASK_MODE_NONE 0
+#define IS2_ACT_MASK_MODE_FILTER 1
+#define IS2_ACT_MASK_MODE_POLICY 2
+#define IS2_ACT_MASK_MODE_REDIR 3
+
+/* IS2 REW_OP values */
+#define IS2_ACT_REW_OP_NONE 0
+#define IS2_ACT_REW_OP_PTP_ONE 2
+#define IS2_ACT_REW_OP_PTP_TWO 3
+#define IS2_ACT_REW_OP_SPECIAL 8
+#define IS2_ACT_REW_OP_PTP_ORG 9
+#define IS2_ACT_REW_OP_PTP_ONE_SUB_DELAY_1 (IS2_ACT_REW_OP_PTP_ONE | (1 << 3))
+#define IS2_ACT_REW_OP_PTP_ONE_SUB_DELAY_2 (IS2_ACT_REW_OP_PTP_ONE | (2 << 3))
+#define IS2_ACT_REW_OP_PTP_ONE_ADD_DELAY (IS2_ACT_REW_OP_PTP_ONE | (1 << 5))
+#define IS2_ACT_REW_OP_PTP_ONE_ADD_SUB BIT(7)
+
+#define VCAP_PORT_WIDTH 4
+
+/* IS2 quarter key - SMAC_SIP4 */
+#define IS2_QKO_IGR_PORT 0
+#define IS2_QKL_IGR_PORT VCAP_PORT_WIDTH
+#define IS2_QKO_L2_SMAC (IS2_QKO_IGR_PORT + IS2_QKL_IGR_PORT)
+#define IS2_QKL_L2_SMAC 48
+#define IS2_QKO_L3_IP4_SIP (IS2_QKO_L2_SMAC + IS2_QKL_L2_SMAC)
+#define IS2_QKL_L3_IP4_SIP 32
+
+/* IS2 half key - common */
+#define IS2_HKO_TYPE 0
+#define IS2_HKL_TYPE 4
+#define IS2_HKO_FIRST (IS2_HKO_TYPE + IS2_HKL_TYPE)
+#define IS2_HKL_FIRST 1
+#define IS2_HKO_PAG (IS2_HKO_FIRST + IS2_HKL_FIRST)
+#define IS2_HKL_PAG 8
+#define IS2_HKO_IGR_PORT_MASK (IS2_HKO_PAG + IS2_HKL_PAG)
+#define IS2_HKL_IGR_PORT_MASK (VCAP_PORT_CNT + 1)
+#define IS2_HKO_SERVICE_FRM (IS2_HKO_IGR_PORT_MASK + IS2_HKL_IGR_PORT_MASK)
+#define IS2_HKL_SERVICE_FRM 1
+#define IS2_HKO_HOST_MATCH (IS2_HKO_SERVICE_FRM + IS2_HKL_SERVICE_FRM)
+#define IS2_HKL_HOST_MATCH 1
+#define IS2_HKO_L2_MC (IS2_HKO_HOST_MATCH + IS2_HKL_HOST_MATCH)
+#define IS2_HKL_L2_MC 1
+#define IS2_HKO_L2_BC (IS2_HKO_L2_MC + IS2_HKL_L2_MC)
+#define IS2_HKL_L2_BC 1
+#define IS2_HKO_VLAN_TAGGED (IS2_HKO_L2_BC + IS2_HKL_L2_BC)
+#define IS2_HKL_VLAN_TAGGED 1
+#define IS2_HKO_VID (IS2_HKO_VLAN_TAGGED + IS2_HKL_VLAN_TAGGED)
+#define IS2_HKL_VID 12
+#define IS2_HKO_DEI (IS2_HKO_VID + IS2_HKL_VID)
+#define IS2_HKL_DEI 1
+#define IS2_HKO_PCP (IS2_HKO_DEI + IS2_HKL_DEI)
+#define IS2_HKL_PCP 3
+
+/* IS2 half key - MAC_ETYPE/MAC_LLC/MAC_SNAP/OAM common */
+#define IS2_HKO_L2_DMAC (IS2_HKO_PCP + IS2_HKL_PCP)
+#define IS2_HKL_L2_DMAC 48
+#define IS2_HKO_L2_SMAC (IS2_HKO_L2_DMAC + IS2_HKL_L2_DMAC)
+#define IS2_HKL_L2_SMAC 48
+
+/* IS2 half key - MAC_ETYPE */
+#define IS2_HKO_MAC_ETYPE_ETYPE (IS2_HKO_L2_SMAC + IS2_HKL_L2_SMAC)
+#define IS2_HKL_MAC_ETYPE_ETYPE 16
+#define IS2_HKO_MAC_ETYPE_L2_PAYLOAD \
+ (IS2_HKO_MAC_ETYPE_ETYPE + IS2_HKL_MAC_ETYPE_ETYPE)
+#define IS2_HKL_MAC_ETYPE_L2_PAYLOAD 27
+
+/* IS2 half key - MAC_LLC */
+#define IS2_HKO_MAC_LLC_L2_LLC IS2_HKO_MAC_ETYPE_ETYPE
+#define IS2_HKL_MAC_LLC_L2_LLC 40
+
+/* IS2 half key - MAC_SNAP */
+#define IS2_HKO_MAC_SNAP_L2_SNAP IS2_HKO_MAC_ETYPE_ETYPE
+#define IS2_HKL_MAC_SNAP_L2_SNAP 40
+
+/* IS2 half key - ARP */
+#define IS2_HKO_MAC_ARP_L2_SMAC IS2_HKO_L2_DMAC
+#define IS2_HKL_MAC_ARP_L2_SMAC 48
+#define IS2_HKO_MAC_ARP_ARP_ADDR_SPACE_OK \
+ (IS2_HKO_MAC_ARP_L2_SMAC + IS2_HKL_MAC_ARP_L2_SMAC)
+#define IS2_HKL_MAC_ARP_ARP_ADDR_SPACE_OK 1
+#define IS2_HKO_MAC_ARP_ARP_PROTO_SPACE_OK \
+ (IS2_HKO_MAC_ARP_ARP_ADDR_SPACE_OK + IS2_HKL_MAC_ARP_ARP_ADDR_SPACE_OK)
+#define IS2_HKL_MAC_ARP_ARP_PROTO_SPACE_OK 1
+#define IS2_HKO_MAC_ARP_ARP_LEN_OK \
+ (IS2_HKO_MAC_ARP_ARP_PROTO_SPACE_OK + \
+ IS2_HKL_MAC_ARP_ARP_PROTO_SPACE_OK)
+#define IS2_HKL_MAC_ARP_ARP_LEN_OK 1
+#define IS2_HKO_MAC_ARP_ARP_TGT_MATCH \
+ (IS2_HKO_MAC_ARP_ARP_LEN_OK + IS2_HKL_MAC_ARP_ARP_LEN_OK)
+#define IS2_HKL_MAC_ARP_ARP_TGT_MATCH 1
+#define IS2_HKO_MAC_ARP_ARP_SENDER_MATCH \
+ (IS2_HKO_MAC_ARP_ARP_TGT_MATCH + IS2_HKL_MAC_ARP_ARP_TGT_MATCH)
+#define IS2_HKL_MAC_ARP_ARP_SENDER_MATCH 1
+#define IS2_HKO_MAC_ARP_ARP_OPCODE_UNKNOWN \
+ (IS2_HKO_MAC_ARP_ARP_SENDER_MATCH + IS2_HKL_MAC_ARP_ARP_SENDER_MATCH)
+#define IS2_HKL_MAC_ARP_ARP_OPCODE_UNKNOWN 1
+#define IS2_HKO_MAC_ARP_ARP_OPCODE \
+ (IS2_HKO_MAC_ARP_ARP_OPCODE_UNKNOWN + \
+ IS2_HKL_MAC_ARP_ARP_OPCODE_UNKNOWN)
+#define IS2_HKL_MAC_ARP_ARP_OPCODE 2
+#define IS2_HKO_MAC_ARP_L3_IP4_DIP \
+ (IS2_HKO_MAC_ARP_ARP_OPCODE + IS2_HKL_MAC_ARP_ARP_OPCODE)
+#define IS2_HKL_MAC_ARP_L3_IP4_DIP 32
+#define IS2_HKO_MAC_ARP_L3_IP4_SIP \
+ (IS2_HKO_MAC_ARP_L3_IP4_DIP + IS2_HKL_MAC_ARP_L3_IP4_DIP)
+#define IS2_HKL_MAC_ARP_L3_IP4_SIP 32
+#define IS2_HKO_MAC_ARP_DIP_EQ_SIP \
+ (IS2_HKO_MAC_ARP_L3_IP4_SIP + IS2_HKL_MAC_ARP_L3_IP4_SIP)
+#define IS2_HKL_MAC_ARP_DIP_EQ_SIP 1
+
+/* IS2 half key - IP4_TCP_UDP/IP4_OTHER common */
+#define IS2_HKO_IP4 IS2_HKO_L2_DMAC
+#define IS2_HKL_IP4 1
+#define IS2_HKO_L3_FRAGMENT (IS2_HKO_IP4 + IS2_HKL_IP4)
+#define IS2_HKL_L3_FRAGMENT 1
+#define IS2_HKO_L3_FRAG_OFS_GT0 (IS2_HKO_L3_FRAGMENT + IS2_HKL_L3_FRAGMENT)
+#define IS2_HKL_L3_FRAG_OFS_GT0 1
+#define IS2_HKO_L3_OPTIONS (IS2_HKO_L3_FRAG_OFS_GT0 + IS2_HKL_L3_FRAG_OFS_GT0)
+#define IS2_HKL_L3_OPTIONS 1
+#define IS2_HKO_L3_TTL_GT0 (IS2_HKO_L3_OPTIONS + IS2_HKL_L3_OPTIONS)
+#define IS2_HKL_L3_TTL_GT0 1
+#define IS2_HKO_L3_TOS (IS2_HKO_L3_TTL_GT0 + IS2_HKL_L3_TTL_GT0)
+#define IS2_HKL_L3_TOS 8
+#define IS2_HKO_L3_IP4_DIP (IS2_HKO_L3_TOS + IS2_HKL_L3_TOS)
+#define IS2_HKL_L3_IP4_DIP 32
+#define IS2_HKO_L3_IP4_SIP (IS2_HKO_L3_IP4_DIP + IS2_HKL_L3_IP4_DIP)
+#define IS2_HKL_L3_IP4_SIP 32
+#define IS2_HKO_DIP_EQ_SIP (IS2_HKO_L3_IP4_SIP + IS2_HKL_L3_IP4_SIP)
+#define IS2_HKL_DIP_EQ_SIP 1
+
+/* IS2 half key - IP4_TCP_UDP */
+#define IS2_HKO_IP4_TCP_UDP_TCP (IS2_HKO_DIP_EQ_SIP + IS2_HKL_DIP_EQ_SIP)
+#define IS2_HKL_IP4_TCP_UDP_TCP 1
+#define IS2_HKO_IP4_TCP_UDP_L4_DPORT \
+ (IS2_HKO_IP4_TCP_UDP_TCP + IS2_HKL_IP4_TCP_UDP_TCP)
+#define IS2_HKL_IP4_TCP_UDP_L4_DPORT 16
+#define IS2_HKO_IP4_TCP_UDP_L4_SPORT \
+ (IS2_HKO_IP4_TCP_UDP_L4_DPORT + IS2_HKL_IP4_TCP_UDP_L4_DPORT)
+#define IS2_HKL_IP4_TCP_UDP_L4_SPORT 16
+#define IS2_HKO_IP4_TCP_UDP_L4_RNG \
+ (IS2_HKO_IP4_TCP_UDP_L4_SPORT + IS2_HKL_IP4_TCP_UDP_L4_SPORT)
+#define IS2_HKL_IP4_TCP_UDP_L4_RNG 8
+#define IS2_HKO_IP4_TCP_UDP_SPORT_EQ_DPORT \
+ (IS2_HKO_IP4_TCP_UDP_L4_RNG + IS2_HKL_IP4_TCP_UDP_L4_RNG)
+#define IS2_HKL_IP4_TCP_UDP_SPORT_EQ_DPORT 1
+#define IS2_HKO_IP4_TCP_UDP_SEQUENCE_EQ0 \
+ (IS2_HKO_IP4_TCP_UDP_SPORT_EQ_DPORT + \
+ IS2_HKL_IP4_TCP_UDP_SPORT_EQ_DPORT)
+#define IS2_HKL_IP4_TCP_UDP_SEQUENCE_EQ0 1
+#define IS2_HKO_IP4_TCP_UDP_L4_FIN \
+ (IS2_HKO_IP4_TCP_UDP_SEQUENCE_EQ0 + IS2_HKL_IP4_TCP_UDP_SEQUENCE_EQ0)
+#define IS2_HKL_IP4_TCP_UDP_L4_FIN 1
+#define IS2_HKO_IP4_TCP_UDP_L4_SYN \
+ (IS2_HKO_IP4_TCP_UDP_L4_FIN + IS2_HKL_IP4_TCP_UDP_L4_FIN)
+#define IS2_HKL_IP4_TCP_UDP_L4_SYN 1
+#define IS2_HKO_IP4_TCP_UDP_L4_RST \
+ (IS2_HKO_IP4_TCP_UDP_L4_SYN + IS2_HKL_IP4_TCP_UDP_L4_SYN)
+#define IS2_HKL_IP4_TCP_UDP_L4_RST 1
+#define IS2_HKO_IP4_TCP_UDP_L4_PSH \
+ (IS2_HKO_IP4_TCP_UDP_L4_RST + IS2_HKL_IP4_TCP_UDP_L4_RST)
+#define IS2_HKL_IP4_TCP_UDP_L4_PSH 1
+#define IS2_HKO_IP4_TCP_UDP_L4_ACK \
+ (IS2_HKO_IP4_TCP_UDP_L4_PSH + IS2_HKL_IP4_TCP_UDP_L4_PSH)
+#define IS2_HKL_IP4_TCP_UDP_L4_ACK 1
+#define IS2_HKO_IP4_TCP_UDP_L4_URG \
+ (IS2_HKO_IP4_TCP_UDP_L4_ACK + IS2_HKL_IP4_TCP_UDP_L4_ACK)
+#define IS2_HKL_IP4_TCP_UDP_L4_URG 1
+#define IS2_HKO_IP4_TCP_UDP_L4_1588_DOM \
+ (IS2_HKO_IP4_TCP_UDP_L4_URG + IS2_HKL_IP4_TCP_UDP_L4_URG)
+#define IS2_HKL_IP4_TCP_UDP_L4_1588_DOM 8
+#define IS2_HKO_IP4_TCP_UDP_L4_1588_VER \
+ (IS2_HKO_IP4_TCP_UDP_L4_1588_DOM + IS2_HKL_IP4_TCP_UDP_L4_1588_DOM)
+#define IS2_HKL_IP4_TCP_UDP_L4_1588_VER 4
+
+/* IS2 half key - IP4_OTHER */
+#define IS2_HKO_IP4_OTHER_L3_PROTO IS2_HKO_IP4_TCP_UDP_TCP
+#define IS2_HKL_IP4_OTHER_L3_PROTO 8
+#define IS2_HKO_IP4_OTHER_L3_PAYLOAD \
+ (IS2_HKO_IP4_OTHER_L3_PROTO + IS2_HKL_IP4_OTHER_L3_PROTO)
+#define IS2_HKL_IP4_OTHER_L3_PAYLOAD 56
+
+/* IS2 half key - IP6_STD */
+#define IS2_HKO_IP6_STD_L3_TTL_GT0 IS2_HKO_L2_DMAC
+#define IS2_HKL_IP6_STD_L3_TTL_GT0 1
+#define IS2_HKO_IP6_STD_L3_IP6_SIP \
+ (IS2_HKO_IP6_STD_L3_TTL_GT0 + IS2_HKL_IP6_STD_L3_TTL_GT0)
+#define IS2_HKL_IP6_STD_L3_IP6_SIP 128
+#define IS2_HKO_IP6_STD_L3_PROTO \
+ (IS2_HKO_IP6_STD_L3_IP6_SIP + IS2_HKL_IP6_STD_L3_IP6_SIP)
+#define IS2_HKL_IP6_STD_L3_PROTO 8
+
+/* IS2 half key - OAM */
+#define IS2_HKO_OAM_OAM_MEL_FLAGS IS2_HKO_MAC_ETYPE_ETYPE
+#define IS2_HKL_OAM_OAM_MEL_FLAGS 7
+#define IS2_HKO_OAM_OAM_VER \
+ (IS2_HKO_OAM_OAM_MEL_FLAGS + IS2_HKL_OAM_OAM_MEL_FLAGS)
+#define IS2_HKL_OAM_OAM_VER 5
+#define IS2_HKO_OAM_OAM_OPCODE (IS2_HKO_OAM_OAM_VER + IS2_HKL_OAM_OAM_VER)
+#define IS2_HKL_OAM_OAM_OPCODE 8
+#define IS2_HKO_OAM_OAM_FLAGS (IS2_HKO_OAM_OAM_OPCODE + IS2_HKL_OAM_OAM_OPCODE)
+#define IS2_HKL_OAM_OAM_FLAGS 8
+#define IS2_HKO_OAM_OAM_MEPID (IS2_HKO_OAM_OAM_FLAGS + IS2_HKL_OAM_OAM_FLAGS)
+#define IS2_HKL_OAM_OAM_MEPID 16
+#define IS2_HKO_OAM_OAM_CCM_CNTS_EQ0 \
+ (IS2_HKO_OAM_OAM_MEPID + IS2_HKL_OAM_OAM_MEPID)
+#define IS2_HKL_OAM_OAM_CCM_CNTS_EQ0 1
+
+/* IS2 half key - SMAC_SIP6 */
+#define IS2_HKO_SMAC_SIP6_IGR_PORT IS2_HKL_TYPE
+#define IS2_HKL_SMAC_SIP6_IGR_PORT VCAP_PORT_WIDTH
+#define IS2_HKO_SMAC_SIP6_L2_SMAC \
+ (IS2_HKO_SMAC_SIP6_IGR_PORT + IS2_HKL_SMAC_SIP6_IGR_PORT)
+#define IS2_HKL_SMAC_SIP6_L2_SMAC 48
+#define IS2_HKO_SMAC_SIP6_L3_IP6_SIP \
+ (IS2_HKO_SMAC_SIP6_L2_SMAC + IS2_HKL_SMAC_SIP6_L2_SMAC)
+#define IS2_HKL_SMAC_SIP6_L3_IP6_SIP 128
+
+/* IS2 full key - common */
+#define IS2_FKO_TYPE 0
+#define IS2_FKL_TYPE 2
+#define IS2_FKO_FIRST (IS2_FKO_TYPE + IS2_FKL_TYPE)
+#define IS2_FKL_FIRST 1
+#define IS2_FKO_PAG (IS2_FKO_FIRST + IS2_FKL_FIRST)
+#define IS2_FKL_PAG 8
+#define IS2_FKO_IGR_PORT_MASK (IS2_FKO_PAG + IS2_FKL_PAG)
+#define IS2_FKL_IGR_PORT_MASK (VCAP_PORT_CNT + 1)
+#define IS2_FKO_SERVICE_FRM (IS2_FKO_IGR_PORT_MASK + IS2_FKL_IGR_PORT_MASK)
+#define IS2_FKL_SERVICE_FRM 1
+#define IS2_FKO_HOST_MATCH (IS2_FKO_SERVICE_FRM + IS2_FKL_SERVICE_FRM)
+#define IS2_FKL_HOST_MATCH 1
+#define IS2_FKO_L2_MC (IS2_FKO_HOST_MATCH + IS2_FKL_HOST_MATCH)
+#define IS2_FKL_L2_MC 1
+#define IS2_FKO_L2_BC (IS2_FKO_L2_MC + IS2_FKL_L2_MC)
+#define IS2_FKL_L2_BC 1
+#define IS2_FKO_VLAN_TAGGED (IS2_FKO_L2_BC + IS2_FKL_L2_BC)
+#define IS2_FKL_VLAN_TAGGED 1
+#define IS2_FKO_VID (IS2_FKO_VLAN_TAGGED + IS2_FKL_VLAN_TAGGED)
+#define IS2_FKL_VID 12
+#define IS2_FKO_DEI (IS2_FKO_VID + IS2_FKL_VID)
+#define IS2_FKL_DEI 1
+#define IS2_FKO_PCP (IS2_FKO_DEI + IS2_FKL_DEI)
+#define IS2_FKL_PCP 3
+
+/* IS2 full key - IP6_TCP_UDP/IP6_OTHER common */
+#define IS2_FKO_L3_TTL_GT0 (IS2_FKO_PCP + IS2_FKL_PCP)
+#define IS2_FKL_L3_TTL_GT0 1
+#define IS2_FKO_L3_TOS (IS2_FKO_L3_TTL_GT0 + IS2_FKL_L3_TTL_GT0)
+#define IS2_FKL_L3_TOS 8
+#define IS2_FKO_L3_IP6_DIP (IS2_FKO_L3_TOS + IS2_FKL_L3_TOS)
+#define IS2_FKL_L3_IP6_DIP 128
+#define IS2_FKO_L3_IP6_SIP (IS2_FKO_L3_IP6_DIP + IS2_FKL_L3_IP6_DIP)
+#define IS2_FKL_L3_IP6_SIP 128
+#define IS2_FKO_DIP_EQ_SIP (IS2_FKO_L3_IP6_SIP + IS2_FKL_L3_IP6_SIP)
+#define IS2_FKL_DIP_EQ_SIP 1
+
+/* IS2 full key - IP6_TCP_UDP */
+#define IS2_FKO_IP6_TCP_UDP_TCP (IS2_FKO_DIP_EQ_SIP + IS2_FKL_DIP_EQ_SIP)
+#define IS2_FKL_IP6_TCP_UDP_TCP 1
+#define IS2_FKO_IP6_TCP_UDP_L4_DPORT \
+ (IS2_FKO_IP6_TCP_UDP_TCP + IS2_FKL_IP6_TCP_UDP_TCP)
+#define IS2_FKL_IP6_TCP_UDP_L4_DPORT 16
+#define IS2_FKO_IP6_TCP_UDP_L4_SPORT \
+ (IS2_FKO_IP6_TCP_UDP_L4_DPORT + IS2_FKL_IP6_TCP_UDP_L4_DPORT)
+#define IS2_FKL_IP6_TCP_UDP_L4_SPORT 16
+#define IS2_FKO_IP6_TCP_UDP_L4_RNG \
+ (IS2_FKO_IP6_TCP_UDP_L4_SPORT + IS2_FKL_IP6_TCP_UDP_L4_SPORT)
+#define IS2_FKL_IP6_TCP_UDP_L4_RNG 8
+#define IS2_FKO_IP6_TCP_UDP_SPORT_EQ_DPORT \
+ (IS2_FKO_IP6_TCP_UDP_L4_RNG + IS2_FKL_IP6_TCP_UDP_L4_RNG)
+#define IS2_FKL_IP6_TCP_UDP_SPORT_EQ_DPORT 1
+#define IS2_FKO_IP6_TCP_UDP_SEQUENCE_EQ0 \
+ (IS2_FKO_IP6_TCP_UDP_SPORT_EQ_DPORT + \
+ IS2_FKL_IP6_TCP_UDP_SPORT_EQ_DPORT)
+#define IS2_FKL_IP6_TCP_UDP_SEQUENCE_EQ0 1
+#define IS2_FKO_IP6_TCP_UDP_L4_FIN \
+ (IS2_FKO_IP6_TCP_UDP_SEQUENCE_EQ0 + IS2_FKL_IP6_TCP_UDP_SEQUENCE_EQ0)
+#define IS2_FKL_IP6_TCP_UDP_L4_FIN 1
+#define IS2_FKO_IP6_TCP_UDP_L4_SYN \
+ (IS2_FKO_IP6_TCP_UDP_L4_FIN + IS2_FKL_IP6_TCP_UDP_L4_FIN)
+#define IS2_FKL_IP6_TCP_UDP_L4_SYN 1
+#define IS2_FKO_IP6_TCP_UDP_L4_RST \
+ (IS2_FKO_IP6_TCP_UDP_L4_SYN + IS2_FKL_IP6_TCP_UDP_L4_SYN)
+#define IS2_FKL_IP6_TCP_UDP_L4_RST 1
+#define IS2_FKO_IP6_TCP_UDP_L4_PSH \
+ (IS2_FKO_IP6_TCP_UDP_L4_RST + IS2_FKL_IP6_TCP_UDP_L4_RST)
+#define IS2_FKL_IP6_TCP_UDP_L4_PSH 1
+#define IS2_FKO_IP6_TCP_UDP_L4_ACK \
+ (IS2_FKO_IP6_TCP_UDP_L4_PSH + IS2_FKL_IP6_TCP_UDP_L4_PSH)
+#define IS2_FKL_IP6_TCP_UDP_L4_ACK 1
+#define IS2_FKO_IP6_TCP_UDP_L4_URG \
+ (IS2_FKO_IP6_TCP_UDP_L4_ACK + IS2_FKL_IP6_TCP_UDP_L4_ACK)
+#define IS2_FKL_IP6_TCP_UDP_L4_URG 1
+#define IS2_FKO_IP6_TCP_UDP_L4_1588_DOM \
+ (IS2_FKO_IP6_TCP_UDP_L4_URG + IS2_FKL_IP6_TCP_UDP_L4_URG)
+#define IS2_FKL_IP6_TCP_UDP_L4_1588_DOM 8
+#define IS2_FKO_IP6_TCP_UDP_L4_1588_VER \
+ (IS2_FKO_IP6_TCP_UDP_L4_1588_DOM + IS2_FKL_IP6_TCP_UDP_L4_1588_DOM)
+#define IS2_FKL_IP6_TCP_UDP_L4_1588_VER 4
+
+/* IS2 full key - IP6_OTHER */
+#define IS2_FKO_IP6_OTHER_L3_PROTO IS2_FKO_IP6_TCP_UDP_TCP
+#define IS2_FKL_IP6_OTHER_L3_PROTO 8
+#define IS2_FKO_IP6_OTHER_L3_PAYLOAD \
+ (IS2_FKO_IP6_OTHER_L3_PROTO + IS2_FKL_IP6_OTHER_L3_PROTO)
+#define IS2_FKL_IP6_OTHER_L3_PAYLOAD 56
+
+/* IS2 full key - CUSTOM */
+#define IS2_FKO_CUSTOM_CUSTOM_TYPE IS2_FKO_L3_TTL_GT0
+#define IS2_FKL_CUSTOM_CUSTOM_TYPE 1
+#define IS2_FKO_CUSTOM_CUSTOM \
+ (IS2_FKO_CUSTOM_CUSTOM_TYPE + IS2_FKL_CUSTOM_CUSTOM_TYPE)
+#define IS2_FKL_CUSTOM_CUSTOM 320
+
+/* IS2 action - BASE_TYPE */
+#define IS2_AO_HIT_ME_ONCE 0
+#define IS2_AL_HIT_ME_ONCE 1
+#define IS2_AO_CPU_COPY_ENA (IS2_AO_HIT_ME_ONCE + IS2_AL_HIT_ME_ONCE)
+#define IS2_AL_CPU_COPY_ENA 1
+#define IS2_AO_CPU_QU_NUM (IS2_AO_CPU_COPY_ENA + IS2_AL_CPU_COPY_ENA)
+#define IS2_AL_CPU_QU_NUM 3
+#define IS2_AO_MASK_MODE (IS2_AO_CPU_QU_NUM + IS2_AL_CPU_QU_NUM)
+#define IS2_AL_MASK_MODE 2
+#define IS2_AO_MIRROR_ENA (IS2_AO_MASK_MODE + IS2_AL_MASK_MODE)
+#define IS2_AL_MIRROR_ENA 1
+#define IS2_AO_LRN_DIS (IS2_AO_MIRROR_ENA + IS2_AL_MIRROR_ENA)
+#define IS2_AL_LRN_DIS 1
+#define IS2_AO_POLICE_ENA (IS2_AO_LRN_DIS + IS2_AL_LRN_DIS)
+#define IS2_AL_POLICE_ENA 1
+#define IS2_AO_POLICE_IDX (IS2_AO_POLICE_ENA + IS2_AL_POLICE_ENA)
+#define IS2_AL_POLICE_IDX 9
+#define IS2_AO_POLICE_VCAP_ONLY (IS2_AO_POLICE_IDX + IS2_AL_POLICE_IDX)
+#define IS2_AL_POLICE_VCAP_ONLY 1
+#define IS2_AO_PORT_MASK (IS2_AO_POLICE_VCAP_ONLY + IS2_AL_POLICE_VCAP_ONLY)
+#define IS2_AL_PORT_MASK VCAP_PORT_CNT
+#define IS2_AO_REW_OP (IS2_AO_PORT_MASK + IS2_AL_PORT_MASK)
+#define IS2_AL_REW_OP 9
+#define IS2_AO_LM_CNT_DIS (IS2_AO_REW_OP + IS2_AL_REW_OP)
+#define IS2_AL_LM_CNT_DIS 1
+#define IS2_AO_ISDX_ENA \
+ (IS2_AO_LM_CNT_DIS + IS2_AL_LM_CNT_DIS + 1) /* Reserved bit */
+#define IS2_AL_ISDX_ENA 1
+#define IS2_AO_ACL_ID (IS2_AO_ISDX_ENA + IS2_AL_ISDX_ENA)
+#define IS2_AL_ACL_ID 6
+
+/* IS2 action - SMAC_SIP */
+#define IS2_AO_SMAC_SIP_CPU_COPY_ENA 0
+#define IS2_AL_SMAC_SIP_CPU_COPY_ENA 1
+#define IS2_AO_SMAC_SIP_CPU_QU_NUM 1
+#define IS2_AL_SMAC_SIP_CPU_QU_NUM 3
+#define IS2_AO_SMAC_SIP_FWD_KILL_ENA 4
+#define IS2_AL_SMAC_SIP_FWD_KILL_ENA 1
+#define IS2_AO_SMAC_SIP_HOST_MATCH 5
+#define IS2_AL_SMAC_SIP_HOST_MATCH 1
+
+#endif /* _OCELOT_VCAP_H_ */
diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c
index 3b2ae1a21678..e0b2bf327905 100644
--- a/drivers/net/ethernet/neterion/s2io.c
+++ b/drivers/net/ethernet/neterion/s2io.c
@@ -747,7 +747,6 @@ static int init_shared_mem(struct s2io_nic *nic)
return -ENOMEM;
}
mem_allocated += size;
- memset(tmp_v_addr, 0, size);
size = sizeof(struct rxd_info) *
rxd_count[nic->rxd_mode];
diff --git a/drivers/net/ethernet/netronome/Kconfig b/drivers/net/ethernet/netronome/Kconfig
index 4ad5109059e0..bac5be4d4f43 100644
--- a/drivers/net/ethernet/netronome/Kconfig
+++ b/drivers/net/ethernet/netronome/Kconfig
@@ -20,6 +20,7 @@ config NFP
tristate "Netronome(R) NFP4000/NFP6000 NIC driver"
depends on PCI && PCI_MSI
depends on VXLAN || VXLAN=n
+ depends on TLS && TLS_DEVICE || TLS_DEVICE=n
select NET_DEVLINK
---help---
This driver supports the Netronome(R) NFP4000/NFP6000 based
diff --git a/drivers/net/ethernet/netronome/nfp/Makefile b/drivers/net/ethernet/netronome/nfp/Makefile
index 87bf784f8e8f..2805641965f3 100644
--- a/drivers/net/ethernet/netronome/nfp/Makefile
+++ b/drivers/net/ethernet/netronome/nfp/Makefile
@@ -16,6 +16,7 @@ nfp-objs := \
nfpcore/nfp_rtsym.o \
nfpcore/nfp_target.o \
ccm.o \
+ ccm_mbox.o \
nfp_asm.o \
nfp_app.o \
nfp_app_nic.o \
@@ -34,6 +35,11 @@ nfp-objs := \
nfp_shared_buf.o \
nic/main.o
+ifeq ($(CONFIG_TLS_DEVICE),y)
+nfp-objs += \
+ crypto/tls.o
+endif
+
ifeq ($(CONFIG_NFP_APP_FLOWER),y)
nfp-objs += \
flower/action.o \
diff --git a/drivers/net/ethernet/netronome/nfp/abm/cls.c b/drivers/net/ethernet/netronome/nfp/abm/cls.c
index ff3913085665..23ebddfb9532 100644
--- a/drivers/net/ethernet/netronome/nfp/abm/cls.c
+++ b/drivers/net/ethernet/netronome/nfp/abm/cls.c
@@ -262,22 +262,12 @@ static int nfp_abm_setup_tc_block_cb(enum tc_setup_type type,
}
}
+static LIST_HEAD(nfp_abm_block_cb_list);
+
int nfp_abm_setup_cls_block(struct net_device *netdev, struct nfp_repr *repr,
- struct tc_block_offload *f)
+ struct flow_block_offload *f)
{
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
- return -EOPNOTSUPP;
-
- switch (f->command) {
- case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block,
- nfp_abm_setup_tc_block_cb,
- repr, repr, f->extack);
- case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block, nfp_abm_setup_tc_block_cb,
- repr);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
+ return flow_block_cb_setup_simple(f, &nfp_abm_block_cb_list,
+ nfp_abm_setup_tc_block_cb,
+ repr, repr, true);
}
diff --git a/drivers/net/ethernet/netronome/nfp/abm/main.h b/drivers/net/ethernet/netronome/nfp/abm/main.h
index 49749c60885e..48746c9c6224 100644
--- a/drivers/net/ethernet/netronome/nfp/abm/main.h
+++ b/drivers/net/ethernet/netronome/nfp/abm/main.h
@@ -247,7 +247,7 @@ int nfp_abm_setup_tc_mq(struct net_device *netdev, struct nfp_abm_link *alink,
int nfp_abm_setup_tc_gred(struct net_device *netdev, struct nfp_abm_link *alink,
struct tc_gred_qopt_offload *opt);
int nfp_abm_setup_cls_block(struct net_device *netdev, struct nfp_repr *repr,
- struct tc_block_offload *opt);
+ struct flow_block_offload *opt);
int nfp_abm_ctrl_read_params(struct nfp_abm_link *alink);
int nfp_abm_ctrl_find_addrs(struct nfp_abm *abm);
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/jit.c b/drivers/net/ethernet/netronome/nfp/bpf/jit.c
index d4bf0e694541..4054b70d7719 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/jit.c
+++ b/drivers/net/ethernet/netronome/nfp/bpf/jit.c
@@ -623,6 +623,13 @@ static void wrp_immed(struct nfp_prog *nfp_prog, swreg dst, u32 imm)
}
static void
+wrp_zext(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta, u8 dst)
+{
+ if (meta->flags & FLAG_INSN_DO_ZEXT)
+ wrp_immed(nfp_prog, reg_both(dst + 1), 0);
+}
+
+static void
wrp_immed_relo(struct nfp_prog *nfp_prog, swreg dst, u32 imm,
enum nfp_relo_type relo)
{
@@ -858,7 +865,8 @@ static int nfp_cpp_memcpy(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
}
static int
-data_ld(struct nfp_prog *nfp_prog, swreg offset, u8 dst_gpr, int size)
+data_ld(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta, swreg offset,
+ u8 dst_gpr, int size)
{
unsigned int i;
u16 shift, sz;
@@ -881,14 +889,15 @@ data_ld(struct nfp_prog *nfp_prog, swreg offset, u8 dst_gpr, int size)
wrp_mov(nfp_prog, reg_both(dst_gpr + i), reg_xfer(i));
if (i < 2)
- wrp_immed(nfp_prog, reg_both(dst_gpr + 1), 0);
+ wrp_zext(nfp_prog, meta, dst_gpr);
return 0;
}
static int
-data_ld_host_order(struct nfp_prog *nfp_prog, u8 dst_gpr,
- swreg lreg, swreg rreg, int size, enum cmd_mode mode)
+data_ld_host_order(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
+ u8 dst_gpr, swreg lreg, swreg rreg, int size,
+ enum cmd_mode mode)
{
unsigned int i;
u8 mask, sz;
@@ -911,33 +920,34 @@ data_ld_host_order(struct nfp_prog *nfp_prog, u8 dst_gpr,
wrp_mov(nfp_prog, reg_both(dst_gpr + i), reg_xfer(i));
if (i < 2)
- wrp_immed(nfp_prog, reg_both(dst_gpr + 1), 0);
+ wrp_zext(nfp_prog, meta, dst_gpr);
return 0;
}
static int
-data_ld_host_order_addr32(struct nfp_prog *nfp_prog, u8 src_gpr, swreg offset,
- u8 dst_gpr, u8 size)
+data_ld_host_order_addr32(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
+ u8 src_gpr, swreg offset, u8 dst_gpr, u8 size)
{
- return data_ld_host_order(nfp_prog, dst_gpr, reg_a(src_gpr), offset,
- size, CMD_MODE_32b);
+ return data_ld_host_order(nfp_prog, meta, dst_gpr, reg_a(src_gpr),
+ offset, size, CMD_MODE_32b);
}
static int
-data_ld_host_order_addr40(struct nfp_prog *nfp_prog, u8 src_gpr, swreg offset,
- u8 dst_gpr, u8 size)
+data_ld_host_order_addr40(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
+ u8 src_gpr, swreg offset, u8 dst_gpr, u8 size)
{
swreg rega, regb;
addr40_offset(nfp_prog, src_gpr, offset, &rega, &regb);
- return data_ld_host_order(nfp_prog, dst_gpr, rega, regb,
+ return data_ld_host_order(nfp_prog, meta, dst_gpr, rega, regb,
size, CMD_MODE_40b_BA);
}
static int
-construct_data_ind_ld(struct nfp_prog *nfp_prog, u16 offset, u16 src, u8 size)
+construct_data_ind_ld(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
+ u16 offset, u16 src, u8 size)
{
swreg tmp_reg;
@@ -953,10 +963,12 @@ construct_data_ind_ld(struct nfp_prog *nfp_prog, u16 offset, u16 src, u8 size)
emit_br_relo(nfp_prog, BR_BLO, BR_OFF_RELO, 0, RELO_BR_GO_ABORT);
/* Load data */
- return data_ld(nfp_prog, imm_b(nfp_prog), 0, size);
+ return data_ld(nfp_prog, meta, imm_b(nfp_prog), 0, size);
}
-static int construct_data_ld(struct nfp_prog *nfp_prog, u16 offset, u8 size)
+static int
+construct_data_ld(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
+ u16 offset, u8 size)
{
swreg tmp_reg;
@@ -967,7 +979,7 @@ static int construct_data_ld(struct nfp_prog *nfp_prog, u16 offset, u8 size)
/* Load data */
tmp_reg = re_load_imm_any(nfp_prog, offset, imm_b(nfp_prog));
- return data_ld(nfp_prog, tmp_reg, 0, size);
+ return data_ld(nfp_prog, meta, tmp_reg, 0, size);
}
static int
@@ -1204,7 +1216,7 @@ mem_op_stack(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
}
if (clr_gpr && size < 8)
- wrp_immed(nfp_prog, reg_both(gpr + 1), 0);
+ wrp_zext(nfp_prog, meta, gpr);
while (size) {
u32 slice_end;
@@ -1305,9 +1317,10 @@ wrp_alu32_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
enum alu_op alu_op)
{
const struct bpf_insn *insn = &meta->insn;
+ u8 dst = insn->dst_reg * 2;
- wrp_alu_imm(nfp_prog, insn->dst_reg * 2, alu_op, insn->imm);
- wrp_immed(nfp_prog, reg_both(insn->dst_reg * 2 + 1), 0);
+ wrp_alu_imm(nfp_prog, dst, alu_op, insn->imm);
+ wrp_zext(nfp_prog, meta, dst);
return 0;
}
@@ -1319,7 +1332,7 @@ wrp_alu32_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
u8 dst = meta->insn.dst_reg * 2, src = meta->insn.src_reg * 2;
emit_alu(nfp_prog, reg_both(dst), reg_a(dst), alu_op, reg_b(src));
- wrp_immed(nfp_prog, reg_both(meta->insn.dst_reg * 2 + 1), 0);
+ wrp_zext(nfp_prog, meta, dst);
return 0;
}
@@ -2396,12 +2409,14 @@ static int neg_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
u8 dst = meta->insn.dst_reg * 2;
emit_alu(nfp_prog, reg_both(dst), reg_imm(0), ALU_OP_SUB, reg_b(dst));
- wrp_immed(nfp_prog, reg_both(meta->insn.dst_reg * 2 + 1), 0);
+ wrp_zext(nfp_prog, meta, dst);
return 0;
}
-static int __ashr_imm(struct nfp_prog *nfp_prog, u8 dst, u8 shift_amt)
+static int
+__ashr_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta, u8 dst,
+ u8 shift_amt)
{
if (shift_amt) {
/* Set signedness bit (MSB of result). */
@@ -2410,7 +2425,7 @@ static int __ashr_imm(struct nfp_prog *nfp_prog, u8 dst, u8 shift_amt)
emit_shf(nfp_prog, reg_both(dst), reg_none(), SHF_OP_ASHR,
reg_b(dst), SHF_SC_R_SHF, shift_amt);
}
- wrp_immed(nfp_prog, reg_both(dst + 1), 0);
+ wrp_zext(nfp_prog, meta, dst);
return 0;
}
@@ -2425,7 +2440,7 @@ static int ashr_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
umin = meta->umin_src;
umax = meta->umax_src;
if (umin == umax)
- return __ashr_imm(nfp_prog, dst, umin);
+ return __ashr_imm(nfp_prog, meta, dst, umin);
src = insn->src_reg * 2;
/* NOTE: the first insn will set both indirect shift amount (source A)
@@ -2434,7 +2449,7 @@ static int ashr_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
emit_alu(nfp_prog, reg_none(), reg_a(src), ALU_OP_OR, reg_b(dst));
emit_shf_indir(nfp_prog, reg_both(dst), reg_none(), SHF_OP_ASHR,
reg_b(dst), SHF_SC_R_SHF);
- wrp_immed(nfp_prog, reg_both(dst + 1), 0);
+ wrp_zext(nfp_prog, meta, dst);
return 0;
}
@@ -2444,15 +2459,17 @@ static int ashr_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
const struct bpf_insn *insn = &meta->insn;
u8 dst = insn->dst_reg * 2;
- return __ashr_imm(nfp_prog, dst, insn->imm);
+ return __ashr_imm(nfp_prog, meta, dst, insn->imm);
}
-static int __shr_imm(struct nfp_prog *nfp_prog, u8 dst, u8 shift_amt)
+static int
+__shr_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta, u8 dst,
+ u8 shift_amt)
{
if (shift_amt)
emit_shf(nfp_prog, reg_both(dst), reg_none(), SHF_OP_NONE,
reg_b(dst), SHF_SC_R_SHF, shift_amt);
- wrp_immed(nfp_prog, reg_both(dst + 1), 0);
+ wrp_zext(nfp_prog, meta, dst);
return 0;
}
@@ -2461,7 +2478,7 @@ static int shr_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
const struct bpf_insn *insn = &meta->insn;
u8 dst = insn->dst_reg * 2;
- return __shr_imm(nfp_prog, dst, insn->imm);
+ return __shr_imm(nfp_prog, meta, dst, insn->imm);
}
static int shr_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
@@ -2474,22 +2491,24 @@ static int shr_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
umin = meta->umin_src;
umax = meta->umax_src;
if (umin == umax)
- return __shr_imm(nfp_prog, dst, umin);
+ return __shr_imm(nfp_prog, meta, dst, umin);
src = insn->src_reg * 2;
emit_alu(nfp_prog, reg_none(), reg_a(src), ALU_OP_OR, reg_imm(0));
emit_shf_indir(nfp_prog, reg_both(dst), reg_none(), SHF_OP_NONE,
reg_b(dst), SHF_SC_R_SHF);
- wrp_immed(nfp_prog, reg_both(dst + 1), 0);
+ wrp_zext(nfp_prog, meta, dst);
return 0;
}
-static int __shl_imm(struct nfp_prog *nfp_prog, u8 dst, u8 shift_amt)
+static int
+__shl_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta, u8 dst,
+ u8 shift_amt)
{
if (shift_amt)
emit_shf(nfp_prog, reg_both(dst), reg_none(), SHF_OP_NONE,
reg_b(dst), SHF_SC_L_SHF, shift_amt);
- wrp_immed(nfp_prog, reg_both(dst + 1), 0);
+ wrp_zext(nfp_prog, meta, dst);
return 0;
}
@@ -2498,7 +2517,7 @@ static int shl_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
const struct bpf_insn *insn = &meta->insn;
u8 dst = insn->dst_reg * 2;
- return __shl_imm(nfp_prog, dst, insn->imm);
+ return __shl_imm(nfp_prog, meta, dst, insn->imm);
}
static int shl_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
@@ -2511,11 +2530,11 @@ static int shl_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
umin = meta->umin_src;
umax = meta->umax_src;
if (umin == umax)
- return __shl_imm(nfp_prog, dst, umin);
+ return __shl_imm(nfp_prog, meta, dst, umin);
src = insn->src_reg * 2;
shl_reg64_lt32_low(nfp_prog, dst, src);
- wrp_immed(nfp_prog, reg_both(dst + 1), 0);
+ wrp_zext(nfp_prog, meta, dst);
return 0;
}
@@ -2577,34 +2596,34 @@ static int imm_ld8(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
static int data_ld1(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
{
- return construct_data_ld(nfp_prog, meta->insn.imm, 1);
+ return construct_data_ld(nfp_prog, meta, meta->insn.imm, 1);
}
static int data_ld2(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
{
- return construct_data_ld(nfp_prog, meta->insn.imm, 2);
+ return construct_data_ld(nfp_prog, meta, meta->insn.imm, 2);
}
static int data_ld4(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
{
- return construct_data_ld(nfp_prog, meta->insn.imm, 4);
+ return construct_data_ld(nfp_prog, meta, meta->insn.imm, 4);
}
static int data_ind_ld1(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
{
- return construct_data_ind_ld(nfp_prog, meta->insn.imm,
+ return construct_data_ind_ld(nfp_prog, meta, meta->insn.imm,
meta->insn.src_reg * 2, 1);
}
static int data_ind_ld2(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
{
- return construct_data_ind_ld(nfp_prog, meta->insn.imm,
+ return construct_data_ind_ld(nfp_prog, meta, meta->insn.imm,
meta->insn.src_reg * 2, 2);
}
static int data_ind_ld4(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
{
- return construct_data_ind_ld(nfp_prog, meta->insn.imm,
+ return construct_data_ind_ld(nfp_prog, meta, meta->insn.imm,
meta->insn.src_reg * 2, 4);
}
@@ -2682,7 +2701,7 @@ mem_ldx_data(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
tmp_reg = re_load_imm_any(nfp_prog, meta->insn.off, imm_b(nfp_prog));
- return data_ld_host_order_addr32(nfp_prog, meta->insn.src_reg * 2,
+ return data_ld_host_order_addr32(nfp_prog, meta, meta->insn.src_reg * 2,
tmp_reg, meta->insn.dst_reg * 2, size);
}
@@ -2694,7 +2713,7 @@ mem_ldx_emem(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
tmp_reg = re_load_imm_any(nfp_prog, meta->insn.off, imm_b(nfp_prog));
- return data_ld_host_order_addr40(nfp_prog, meta->insn.src_reg * 2,
+ return data_ld_host_order_addr40(nfp_prog, meta, meta->insn.src_reg * 2,
tmp_reg, meta->insn.dst_reg * 2, size);
}
@@ -2755,7 +2774,7 @@ mem_ldx_data_from_pktcache_unaligned(struct nfp_prog *nfp_prog,
wrp_reg_subpart(nfp_prog, dst_lo, src_lo, len_lo, off);
if (!len_mid) {
- wrp_immed(nfp_prog, dst_hi, 0);
+ wrp_zext(nfp_prog, meta, dst_gpr);
return 0;
}
@@ -2763,7 +2782,7 @@ mem_ldx_data_from_pktcache_unaligned(struct nfp_prog *nfp_prog,
if (size <= REG_WIDTH) {
wrp_reg_or_subpart(nfp_prog, dst_lo, src_mid, len_mid, len_lo);
- wrp_immed(nfp_prog, dst_hi, 0);
+ wrp_zext(nfp_prog, meta, dst_gpr);
} else {
swreg src_hi = reg_xfer(idx + 2);
@@ -2794,10 +2813,10 @@ mem_ldx_data_from_pktcache_aligned(struct nfp_prog *nfp_prog,
if (size < REG_WIDTH) {
wrp_reg_subpart(nfp_prog, dst_lo, src_lo, size, 0);
- wrp_immed(nfp_prog, dst_hi, 0);
+ wrp_zext(nfp_prog, meta, dst_gpr);
} else if (size == REG_WIDTH) {
wrp_mov(nfp_prog, dst_lo, src_lo);
- wrp_immed(nfp_prog, dst_hi, 0);
+ wrp_zext(nfp_prog, meta, dst_gpr);
} else {
swreg src_hi = reg_xfer(idx + 1);
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.c b/drivers/net/ethernet/netronome/nfp/bpf/main.c
index 9c136da25221..1c9fb11470df 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/main.c
+++ b/drivers/net/ethernet/netronome/nfp/bpf/main.c
@@ -160,35 +160,19 @@ static int nfp_bpf_setup_tc_block_cb(enum tc_setup_type type,
return 0;
}
-static int nfp_bpf_setup_tc_block(struct net_device *netdev,
- struct tc_block_offload *f)
-{
- struct nfp_net *nn = netdev_priv(netdev);
-
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
- return -EOPNOTSUPP;
-
- switch (f->command) {
- case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block,
- nfp_bpf_setup_tc_block_cb,
- nn, nn, f->extack);
- case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block,
- nfp_bpf_setup_tc_block_cb,
- nn);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-}
+static LIST_HEAD(nfp_bpf_block_cb_list);
static int nfp_bpf_setup_tc(struct nfp_app *app, struct net_device *netdev,
enum tc_setup_type type, void *type_data)
{
+ struct nfp_net *nn = netdev_priv(netdev);
+
switch (type) {
case TC_SETUP_BLOCK:
- return nfp_bpf_setup_tc_block(netdev, type_data);
+ return flow_block_cb_setup_simple(type_data,
+ &nfp_bpf_block_cb_list,
+ nfp_bpf_setup_tc_block_cb,
+ nn, nn, true);
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.h b/drivers/net/ethernet/netronome/nfp/bpf/main.h
index e54d1ac84df2..57d6ff51e980 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/main.h
+++ b/drivers/net/ethernet/netronome/nfp/bpf/main.h
@@ -238,6 +238,8 @@ struct nfp_bpf_reg_state {
#define FLAG_INSN_SKIP_PREC_DEPENDENT BIT(4)
/* Instruction is optimized by the verifier */
#define FLAG_INSN_SKIP_VERIFIER_OPT BIT(5)
+/* Instruction needs to zero extend to high 32-bit */
+#define FLAG_INSN_DO_ZEXT BIT(6)
#define FLAG_INSN_SKIP_MASK (FLAG_INSN_SKIP_NOOP | \
FLAG_INSN_SKIP_PREC_DEPENDENT | \
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c
index 36f56eb4cbe2..e92ee510fd52 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c
+++ b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c
@@ -744,6 +744,17 @@ continue_subprog:
goto continue_subprog;
}
+static void nfp_bpf_insn_flag_zext(struct nfp_prog *nfp_prog,
+ struct bpf_insn_aux_data *aux)
+{
+ struct nfp_insn_meta *meta;
+
+ list_for_each_entry(meta, &nfp_prog->insns, l) {
+ if (aux[meta->n].zext_dst)
+ meta->flags |= FLAG_INSN_DO_ZEXT;
+ }
+}
+
int nfp_bpf_finalize(struct bpf_verifier_env *env)
{
struct bpf_subprog_info *info;
@@ -784,6 +795,7 @@ int nfp_bpf_finalize(struct bpf_verifier_env *env)
return -EOPNOTSUPP;
}
+ nfp_bpf_insn_flag_zext(nfp_prog, env->insn_aux_data);
return 0;
}
diff --git a/drivers/net/ethernet/netronome/nfp/ccm.c b/drivers/net/ethernet/netronome/nfp/ccm.c
index 94476e41e261..71afd111bae3 100644
--- a/drivers/net/ethernet/netronome/nfp/ccm.c
+++ b/drivers/net/ethernet/netronome/nfp/ccm.c
@@ -7,9 +7,6 @@
#include "nfp_app.h"
#include "nfp_net.h"
-#define NFP_CCM_TYPE_REPLY_BIT 7
-#define __NFP_CCM_REPLY(req) (BIT(NFP_CCM_TYPE_REPLY_BIT) | (req))
-
#define ccm_warn(app, msg...) nn_dp_warn(&(app)->ctrl->dp, msg)
#define NFP_CCM_TAG_ALLOC_SPAN (U16_MAX / 4)
diff --git a/drivers/net/ethernet/netronome/nfp/ccm.h b/drivers/net/ethernet/netronome/nfp/ccm.h
index ac963b128203..a460c75522be 100644
--- a/drivers/net/ethernet/netronome/nfp/ccm.h
+++ b/drivers/net/ethernet/netronome/nfp/ccm.h
@@ -9,6 +9,7 @@
#include <linux/wait.h>
struct nfp_app;
+struct nfp_net;
/* Firmware ABI */
@@ -21,15 +22,27 @@ enum nfp_ccm_type {
NFP_CCM_TYPE_BPF_MAP_GETNEXT = 6,
NFP_CCM_TYPE_BPF_MAP_GETFIRST = 7,
NFP_CCM_TYPE_BPF_BPF_EVENT = 8,
+ NFP_CCM_TYPE_CRYPTO_RESET = 9,
+ NFP_CCM_TYPE_CRYPTO_ADD = 10,
+ NFP_CCM_TYPE_CRYPTO_DEL = 11,
+ NFP_CCM_TYPE_CRYPTO_UPDATE = 12,
__NFP_CCM_TYPE_MAX,
};
#define NFP_CCM_ABI_VERSION 1
+#define NFP_CCM_TYPE_REPLY_BIT 7
+#define __NFP_CCM_REPLY(req) (BIT(NFP_CCM_TYPE_REPLY_BIT) | (req))
+
struct nfp_ccm_hdr {
- u8 type;
- u8 ver;
- __be16 tag;
+ union {
+ struct {
+ u8 type;
+ u8 ver;
+ __be16 tag;
+ };
+ __be32 raw;
+ };
};
static inline u8 nfp_ccm_get_type(struct sk_buff *skb)
@@ -41,15 +54,31 @@ static inline u8 nfp_ccm_get_type(struct sk_buff *skb)
return hdr->type;
}
-static inline unsigned int nfp_ccm_get_tag(struct sk_buff *skb)
+static inline __be16 __nfp_ccm_get_tag(struct sk_buff *skb)
{
struct nfp_ccm_hdr *hdr;
hdr = (struct nfp_ccm_hdr *)skb->data;
- return be16_to_cpu(hdr->tag);
+ return hdr->tag;
+}
+
+static inline unsigned int nfp_ccm_get_tag(struct sk_buff *skb)
+{
+ return be16_to_cpu(__nfp_ccm_get_tag(skb));
}
+#define NFP_NET_MBOX_TLV_TYPE GENMASK(31, 16)
+#define NFP_NET_MBOX_TLV_LEN GENMASK(15, 0)
+
+enum nfp_ccm_mbox_tlv_type {
+ NFP_NET_MBOX_TLV_TYPE_UNKNOWN = 0,
+ NFP_NET_MBOX_TLV_TYPE_END = 1,
+ NFP_NET_MBOX_TLV_TYPE_MSG = 2,
+ NFP_NET_MBOX_TLV_TYPE_MSG_NOSUP = 3,
+ NFP_NET_MBOX_TLV_TYPE_RESV = 4,
+};
+
/* Implementation */
/**
@@ -71,7 +100,7 @@ struct nfp_ccm {
u16 tag_alloc_last;
struct sk_buff_head replies;
- struct wait_queue_head wq;
+ wait_queue_head_t wq;
};
int nfp_ccm_init(struct nfp_ccm *ccm, struct nfp_app *app);
@@ -80,4 +109,23 @@ void nfp_ccm_rx(struct nfp_ccm *ccm, struct sk_buff *skb);
struct sk_buff *
nfp_ccm_communicate(struct nfp_ccm *ccm, struct sk_buff *skb,
enum nfp_ccm_type type, unsigned int reply_size);
+
+int nfp_ccm_mbox_alloc(struct nfp_net *nn);
+void nfp_ccm_mbox_free(struct nfp_net *nn);
+int nfp_ccm_mbox_init(struct nfp_net *nn);
+void nfp_ccm_mbox_clean(struct nfp_net *nn);
+bool nfp_ccm_mbox_fits(struct nfp_net *nn, unsigned int size);
+struct sk_buff *
+nfp_ccm_mbox_msg_alloc(struct nfp_net *nn, unsigned int req_size,
+ unsigned int reply_size, gfp_t flags);
+int __nfp_ccm_mbox_communicate(struct nfp_net *nn, struct sk_buff *skb,
+ enum nfp_ccm_type type,
+ unsigned int reply_size,
+ unsigned int max_reply_size, bool critical);
+int nfp_ccm_mbox_communicate(struct nfp_net *nn, struct sk_buff *skb,
+ enum nfp_ccm_type type,
+ unsigned int reply_size,
+ unsigned int max_reply_size);
+int nfp_ccm_mbox_post(struct nfp_net *nn, struct sk_buff *skb,
+ enum nfp_ccm_type type, unsigned int max_reply_size);
#endif
diff --git a/drivers/net/ethernet/netronome/nfp/ccm_mbox.c b/drivers/net/ethernet/netronome/nfp/ccm_mbox.c
new file mode 100644
index 000000000000..f0783aa9e66e
--- /dev/null
+++ b/drivers/net/ethernet/netronome/nfp/ccm_mbox.c
@@ -0,0 +1,743 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2019 Netronome Systems, Inc. */
+
+#include <linux/bitfield.h>
+#include <linux/io.h>
+#include <linux/skbuff.h>
+
+#include "ccm.h"
+#include "nfp_net.h"
+
+/* CCM messages via the mailbox. CMSGs get wrapped into simple TLVs
+ * and copied into the mailbox. Multiple messages can be copied to
+ * form a batch. Threads come in with CMSG formed in an skb, then
+ * enqueue that skb onto the request queue. If threads skb is first
+ * in queue this thread will handle the mailbox operation. It copies
+ * up to 64 messages into the mailbox (making sure that both requests
+ * and replies will fit. After FW is done processing the batch it
+ * copies the data out and wakes waiting threads.
+ * If a thread is waiting it either gets its the message completed
+ * (response is copied into the same skb as the request, overwriting
+ * it), or becomes the first in queue.
+ * Completions and next-to-run are signaled via the control buffer
+ * to limit potential cache line bounces.
+ */
+
+#define NFP_CCM_MBOX_BATCH_LIMIT 64
+#define NFP_CCM_TIMEOUT (NFP_NET_POLL_TIMEOUT * 1000)
+#define NFP_CCM_MAX_QLEN 1024
+
+enum nfp_net_mbox_cmsg_state {
+ NFP_NET_MBOX_CMSG_STATE_QUEUED,
+ NFP_NET_MBOX_CMSG_STATE_NEXT,
+ NFP_NET_MBOX_CMSG_STATE_BUSY,
+ NFP_NET_MBOX_CMSG_STATE_REPLY_FOUND,
+ NFP_NET_MBOX_CMSG_STATE_DONE,
+};
+
+/**
+ * struct nfp_ccm_mbox_skb_cb - CCM mailbox specific info
+ * @state: processing state (/stage) of the message
+ * @err: error encountered during processing if any
+ * @max_len: max(request_len, reply_len)
+ * @exp_reply: expected reply length (0 means don't validate)
+ * @posted: the message was posted and nobody waits for the reply
+ */
+struct nfp_ccm_mbox_cmsg_cb {
+ enum nfp_net_mbox_cmsg_state state;
+ int err;
+ unsigned int max_len;
+ unsigned int exp_reply;
+ bool posted;
+};
+
+static u32 nfp_ccm_mbox_max_msg(struct nfp_net *nn)
+{
+ return round_down(nn->tlv_caps.mbox_len, 4) -
+ NFP_NET_CFG_MBOX_SIMPLE_VAL - /* common mbox command header */
+ 4 * 2; /* Msg TLV plus End TLV headers */
+}
+
+static void
+nfp_ccm_mbox_msg_init(struct sk_buff *skb, unsigned int exp_reply, int max_len)
+{
+ struct nfp_ccm_mbox_cmsg_cb *cb = (void *)skb->cb;
+
+ cb->state = NFP_NET_MBOX_CMSG_STATE_QUEUED;
+ cb->err = 0;
+ cb->max_len = max_len;
+ cb->exp_reply = exp_reply;
+ cb->posted = false;
+}
+
+static int nfp_ccm_mbox_maxlen(const struct sk_buff *skb)
+{
+ struct nfp_ccm_mbox_cmsg_cb *cb = (void *)skb->cb;
+
+ return cb->max_len;
+}
+
+static bool nfp_ccm_mbox_done(struct sk_buff *skb)
+{
+ struct nfp_ccm_mbox_cmsg_cb *cb = (void *)skb->cb;
+
+ return cb->state == NFP_NET_MBOX_CMSG_STATE_DONE;
+}
+
+static bool nfp_ccm_mbox_in_progress(struct sk_buff *skb)
+{
+ struct nfp_ccm_mbox_cmsg_cb *cb = (void *)skb->cb;
+
+ return cb->state != NFP_NET_MBOX_CMSG_STATE_QUEUED &&
+ cb->state != NFP_NET_MBOX_CMSG_STATE_NEXT;
+}
+
+static void nfp_ccm_mbox_set_busy(struct sk_buff *skb)
+{
+ struct nfp_ccm_mbox_cmsg_cb *cb = (void *)skb->cb;
+
+ cb->state = NFP_NET_MBOX_CMSG_STATE_BUSY;
+}
+
+static bool nfp_ccm_mbox_is_posted(struct sk_buff *skb)
+{
+ struct nfp_ccm_mbox_cmsg_cb *cb = (void *)skb->cb;
+
+ return cb->posted;
+}
+
+static void nfp_ccm_mbox_mark_posted(struct sk_buff *skb)
+{
+ struct nfp_ccm_mbox_cmsg_cb *cb = (void *)skb->cb;
+
+ cb->posted = true;
+}
+
+static bool nfp_ccm_mbox_is_first(struct nfp_net *nn, struct sk_buff *skb)
+{
+ return skb_queue_is_first(&nn->mbox_cmsg.queue, skb);
+}
+
+static bool nfp_ccm_mbox_should_run(struct nfp_net *nn, struct sk_buff *skb)
+{
+ struct nfp_ccm_mbox_cmsg_cb *cb = (void *)skb->cb;
+
+ return cb->state == NFP_NET_MBOX_CMSG_STATE_NEXT;
+}
+
+static void nfp_ccm_mbox_mark_next_runner(struct nfp_net *nn)
+{
+ struct nfp_ccm_mbox_cmsg_cb *cb;
+ struct sk_buff *skb;
+
+ skb = skb_peek(&nn->mbox_cmsg.queue);
+ if (!skb)
+ return;
+
+ cb = (void *)skb->cb;
+ cb->state = NFP_NET_MBOX_CMSG_STATE_NEXT;
+ if (cb->posted)
+ queue_work(nn->mbox_cmsg.workq, &nn->mbox_cmsg.runq_work);
+}
+
+static void
+nfp_ccm_mbox_write_tlv(struct nfp_net *nn, u32 off, u32 type, u32 len)
+{
+ nn_writel(nn, off,
+ FIELD_PREP(NFP_NET_MBOX_TLV_TYPE, type) |
+ FIELD_PREP(NFP_NET_MBOX_TLV_LEN, len));
+}
+
+static void nfp_ccm_mbox_copy_in(struct nfp_net *nn, struct sk_buff *last)
+{
+ struct sk_buff *skb;
+ int reserve, i, cnt;
+ __be32 *data;
+ u32 off, len;
+
+ off = nn->tlv_caps.mbox_off + NFP_NET_CFG_MBOX_SIMPLE_VAL;
+ skb = __skb_peek(&nn->mbox_cmsg.queue);
+ while (true) {
+ nfp_ccm_mbox_write_tlv(nn, off, NFP_NET_MBOX_TLV_TYPE_MSG,
+ skb->len);
+ off += 4;
+
+ /* Write data word by word, skb->data should be aligned */
+ data = (__be32 *)skb->data;
+ cnt = skb->len / 4;
+ for (i = 0 ; i < cnt; i++) {
+ nn_writel(nn, off, be32_to_cpu(data[i]));
+ off += 4;
+ }
+ if (skb->len & 3) {
+ __be32 tmp = 0;
+
+ memcpy(&tmp, &data[i], skb->len & 3);
+ nn_writel(nn, off, be32_to_cpu(tmp));
+ off += 4;
+ }
+
+ /* Reserve space if reply is bigger */
+ len = round_up(skb->len, 4);
+ reserve = nfp_ccm_mbox_maxlen(skb) - len;
+ if (reserve > 0) {
+ nfp_ccm_mbox_write_tlv(nn, off,
+ NFP_NET_MBOX_TLV_TYPE_RESV,
+ reserve);
+ off += 4 + reserve;
+ }
+
+ if (skb == last)
+ break;
+ skb = skb_queue_next(&nn->mbox_cmsg.queue, skb);
+ }
+
+ nfp_ccm_mbox_write_tlv(nn, off, NFP_NET_MBOX_TLV_TYPE_END, 0);
+}
+
+static struct sk_buff *
+nfp_ccm_mbox_find_req(struct nfp_net *nn, __be16 tag, struct sk_buff *last)
+{
+ struct sk_buff *skb;
+
+ skb = __skb_peek(&nn->mbox_cmsg.queue);
+ while (true) {
+ if (__nfp_ccm_get_tag(skb) == tag)
+ return skb;
+
+ if (skb == last)
+ return NULL;
+ skb = skb_queue_next(&nn->mbox_cmsg.queue, skb);
+ }
+}
+
+static void nfp_ccm_mbox_copy_out(struct nfp_net *nn, struct sk_buff *last)
+{
+ struct nfp_ccm_mbox_cmsg_cb *cb;
+ u8 __iomem *data, *end;
+ struct sk_buff *skb;
+
+ data = nn->dp.ctrl_bar + nn->tlv_caps.mbox_off +
+ NFP_NET_CFG_MBOX_SIMPLE_VAL;
+ end = data + nn->tlv_caps.mbox_len;
+
+ while (true) {
+ unsigned int length, offset, type;
+ struct nfp_ccm_hdr hdr;
+ u32 tlv_hdr;
+
+ tlv_hdr = readl(data);
+ type = FIELD_GET(NFP_NET_MBOX_TLV_TYPE, tlv_hdr);
+ length = FIELD_GET(NFP_NET_MBOX_TLV_LEN, tlv_hdr);
+ offset = data - nn->dp.ctrl_bar;
+
+ /* Advance past the header */
+ data += 4;
+
+ if (data + length > end) {
+ nn_dp_warn(&nn->dp, "mailbox oversized TLV type:%d offset:%u len:%u\n",
+ type, offset, length);
+ break;
+ }
+
+ if (type == NFP_NET_MBOX_TLV_TYPE_END)
+ break;
+ if (type == NFP_NET_MBOX_TLV_TYPE_RESV)
+ goto next_tlv;
+ if (type != NFP_NET_MBOX_TLV_TYPE_MSG &&
+ type != NFP_NET_MBOX_TLV_TYPE_MSG_NOSUP) {
+ nn_dp_warn(&nn->dp, "mailbox unknown TLV type:%d offset:%u len:%u\n",
+ type, offset, length);
+ break;
+ }
+
+ if (length < 4) {
+ nn_dp_warn(&nn->dp, "mailbox msg too short to contain header TLV type:%d offset:%u len:%u\n",
+ type, offset, length);
+ break;
+ }
+
+ hdr.raw = cpu_to_be32(readl(data));
+
+ skb = nfp_ccm_mbox_find_req(nn, hdr.tag, last);
+ if (!skb) {
+ nn_dp_warn(&nn->dp, "mailbox request not found:%u\n",
+ be16_to_cpu(hdr.tag));
+ break;
+ }
+ cb = (void *)skb->cb;
+
+ if (type == NFP_NET_MBOX_TLV_TYPE_MSG_NOSUP) {
+ nn_dp_warn(&nn->dp,
+ "mailbox msg not supported type:%d\n",
+ nfp_ccm_get_type(skb));
+ cb->err = -EIO;
+ goto next_tlv;
+ }
+
+ if (hdr.type != __NFP_CCM_REPLY(nfp_ccm_get_type(skb))) {
+ nn_dp_warn(&nn->dp, "mailbox msg reply wrong type:%u expected:%lu\n",
+ hdr.type,
+ __NFP_CCM_REPLY(nfp_ccm_get_type(skb)));
+ cb->err = -EIO;
+ goto next_tlv;
+ }
+ if (cb->exp_reply && length != cb->exp_reply) {
+ nn_dp_warn(&nn->dp, "mailbox msg reply wrong size type:%u expected:%u have:%u\n",
+ hdr.type, length, cb->exp_reply);
+ cb->err = -EIO;
+ goto next_tlv;
+ }
+ if (length > cb->max_len) {
+ nn_dp_warn(&nn->dp, "mailbox msg oversized reply type:%u max:%u have:%u\n",
+ hdr.type, cb->max_len, length);
+ cb->err = -EIO;
+ goto next_tlv;
+ }
+
+ if (!cb->posted) {
+ __be32 *skb_data;
+ int i, cnt;
+
+ if (length <= skb->len)
+ __skb_trim(skb, length);
+ else
+ skb_put(skb, length - skb->len);
+
+ /* We overcopy here slightly, but that's okay,
+ * the skb is large enough, and the garbage will
+ * be ignored (beyond skb->len).
+ */
+ skb_data = (__be32 *)skb->data;
+ memcpy(skb_data, &hdr, 4);
+
+ cnt = DIV_ROUND_UP(length, 4);
+ for (i = 1 ; i < cnt; i++)
+ skb_data[i] = cpu_to_be32(readl(data + i * 4));
+ }
+
+ cb->state = NFP_NET_MBOX_CMSG_STATE_REPLY_FOUND;
+next_tlv:
+ data += round_up(length, 4);
+ if (data + 4 > end) {
+ nn_dp_warn(&nn->dp,
+ "reached end of MBOX without END TLV\n");
+ break;
+ }
+ }
+
+ smp_wmb(); /* order the skb->data vs. cb->state */
+ spin_lock_bh(&nn->mbox_cmsg.queue.lock);
+ do {
+ skb = __skb_dequeue(&nn->mbox_cmsg.queue);
+ cb = (void *)skb->cb;
+
+ if (cb->state != NFP_NET_MBOX_CMSG_STATE_REPLY_FOUND) {
+ cb->err = -ENOENT;
+ smp_wmb(); /* order the cb->err vs. cb->state */
+ }
+ cb->state = NFP_NET_MBOX_CMSG_STATE_DONE;
+
+ if (cb->posted) {
+ if (cb->err)
+ nn_dp_warn(&nn->dp,
+ "mailbox posted msg failed type:%u err:%d\n",
+ nfp_ccm_get_type(skb), cb->err);
+ dev_consume_skb_any(skb);
+ }
+ } while (skb != last);
+
+ nfp_ccm_mbox_mark_next_runner(nn);
+ spin_unlock_bh(&nn->mbox_cmsg.queue.lock);
+}
+
+static void
+nfp_ccm_mbox_mark_all_err(struct nfp_net *nn, struct sk_buff *last, int err)
+{
+ struct nfp_ccm_mbox_cmsg_cb *cb;
+ struct sk_buff *skb;
+
+ spin_lock_bh(&nn->mbox_cmsg.queue.lock);
+ do {
+ skb = __skb_dequeue(&nn->mbox_cmsg.queue);
+ cb = (void *)skb->cb;
+
+ cb->err = err;
+ smp_wmb(); /* order the cb->err vs. cb->state */
+ cb->state = NFP_NET_MBOX_CMSG_STATE_DONE;
+ } while (skb != last);
+
+ nfp_ccm_mbox_mark_next_runner(nn);
+ spin_unlock_bh(&nn->mbox_cmsg.queue.lock);
+}
+
+static void nfp_ccm_mbox_run_queue_unlock(struct nfp_net *nn)
+ __releases(&nn->mbox_cmsg.queue.lock)
+{
+ int space = nn->tlv_caps.mbox_len - NFP_NET_CFG_MBOX_SIMPLE_VAL;
+ struct sk_buff *skb, *last;
+ int cnt, err;
+
+ space -= 4; /* for End TLV */
+
+ /* First skb must fit, because it's ours and we checked it fits */
+ cnt = 1;
+ last = skb = __skb_peek(&nn->mbox_cmsg.queue);
+ space -= 4 + nfp_ccm_mbox_maxlen(skb);
+
+ while (!skb_queue_is_last(&nn->mbox_cmsg.queue, last)) {
+ skb = skb_queue_next(&nn->mbox_cmsg.queue, last);
+ space -= 4 + nfp_ccm_mbox_maxlen(skb);
+ if (space < 0)
+ break;
+ last = skb;
+ nfp_ccm_mbox_set_busy(skb);
+ cnt++;
+ if (cnt == NFP_CCM_MBOX_BATCH_LIMIT)
+ break;
+ }
+ spin_unlock_bh(&nn->mbox_cmsg.queue.lock);
+
+ /* Now we own all skb's marked in progress, new requests may arrive
+ * at the end of the queue.
+ */
+
+ nn_ctrl_bar_lock(nn);
+
+ nfp_ccm_mbox_copy_in(nn, last);
+
+ err = nfp_net_mbox_reconfig(nn, NFP_NET_CFG_MBOX_CMD_TLV_CMSG);
+ if (!err)
+ nfp_ccm_mbox_copy_out(nn, last);
+ else
+ nfp_ccm_mbox_mark_all_err(nn, last, -EIO);
+
+ nn_ctrl_bar_unlock(nn);
+
+ wake_up_all(&nn->mbox_cmsg.wq);
+}
+
+static int nfp_ccm_mbox_skb_return(struct sk_buff *skb)
+{
+ struct nfp_ccm_mbox_cmsg_cb *cb = (void *)skb->cb;
+
+ if (cb->err)
+ dev_kfree_skb_any(skb);
+ return cb->err;
+}
+
+/* If wait timed out but the command is already in progress we have
+ * to wait until it finishes. Runners has ownership of the skbs marked
+ * as busy.
+ */
+static int
+nfp_ccm_mbox_unlink_unlock(struct nfp_net *nn, struct sk_buff *skb,
+ enum nfp_ccm_type type)
+ __releases(&nn->mbox_cmsg.queue.lock)
+{
+ bool was_first;
+
+ if (nfp_ccm_mbox_in_progress(skb)) {
+ spin_unlock_bh(&nn->mbox_cmsg.queue.lock);
+
+ wait_event(nn->mbox_cmsg.wq, nfp_ccm_mbox_done(skb));
+ smp_rmb(); /* pairs with smp_wmb() after data is written */
+ return nfp_ccm_mbox_skb_return(skb);
+ }
+
+ was_first = nfp_ccm_mbox_should_run(nn, skb);
+ __skb_unlink(skb, &nn->mbox_cmsg.queue);
+ if (was_first)
+ nfp_ccm_mbox_mark_next_runner(nn);
+
+ spin_unlock_bh(&nn->mbox_cmsg.queue.lock);
+
+ if (was_first)
+ wake_up_all(&nn->mbox_cmsg.wq);
+
+ nn_dp_warn(&nn->dp, "time out waiting for mbox response to 0x%02x\n",
+ type);
+ return -ETIMEDOUT;
+}
+
+static int
+nfp_ccm_mbox_msg_prepare(struct nfp_net *nn, struct sk_buff *skb,
+ enum nfp_ccm_type type,
+ unsigned int reply_size, unsigned int max_reply_size,
+ gfp_t flags)
+{
+ const unsigned int mbox_max = nfp_ccm_mbox_max_msg(nn);
+ unsigned int max_len;
+ ssize_t undersize;
+ int err;
+
+ if (unlikely(!(nn->tlv_caps.mbox_cmsg_types & BIT(type)))) {
+ nn_dp_warn(&nn->dp,
+ "message type %d not supported by mailbox\n", type);
+ return -EINVAL;
+ }
+
+ /* If the reply size is unknown assume it will take the entire
+ * mailbox, the callers should do their best for this to never
+ * happen.
+ */
+ if (!max_reply_size)
+ max_reply_size = mbox_max;
+ max_reply_size = round_up(max_reply_size, 4);
+
+ /* Make sure we can fit the entire reply into the skb,
+ * and that we don't have to slow down the mbox handler
+ * with allocations.
+ */
+ undersize = max_reply_size - (skb_end_pointer(skb) - skb->data);
+ if (undersize > 0) {
+ err = pskb_expand_head(skb, 0, undersize, flags);
+ if (err) {
+ nn_dp_warn(&nn->dp,
+ "can't allocate reply buffer for mailbox\n");
+ return err;
+ }
+ }
+
+ /* Make sure that request and response both fit into the mailbox */
+ max_len = max(max_reply_size, round_up(skb->len, 4));
+ if (max_len > mbox_max) {
+ nn_dp_warn(&nn->dp,
+ "message too big for tha mailbox: %u/%u vs %u\n",
+ skb->len, max_reply_size, mbox_max);
+ return -EMSGSIZE;
+ }
+
+ nfp_ccm_mbox_msg_init(skb, reply_size, max_len);
+
+ return 0;
+}
+
+static int
+nfp_ccm_mbox_msg_enqueue(struct nfp_net *nn, struct sk_buff *skb,
+ enum nfp_ccm_type type, bool critical)
+{
+ struct nfp_ccm_hdr *hdr;
+
+ assert_spin_locked(&nn->mbox_cmsg.queue.lock);
+
+ if (!critical && nn->mbox_cmsg.queue.qlen >= NFP_CCM_MAX_QLEN) {
+ nn_dp_warn(&nn->dp, "mailbox request queue too long\n");
+ return -EBUSY;
+ }
+
+ hdr = (void *)skb->data;
+ hdr->ver = NFP_CCM_ABI_VERSION;
+ hdr->type = type;
+ hdr->tag = cpu_to_be16(nn->mbox_cmsg.tag++);
+
+ __skb_queue_tail(&nn->mbox_cmsg.queue, skb);
+
+ return 0;
+}
+
+int __nfp_ccm_mbox_communicate(struct nfp_net *nn, struct sk_buff *skb,
+ enum nfp_ccm_type type,
+ unsigned int reply_size,
+ unsigned int max_reply_size, bool critical)
+{
+ int err;
+
+ err = nfp_ccm_mbox_msg_prepare(nn, skb, type, reply_size,
+ max_reply_size, GFP_KERNEL);
+ if (err)
+ goto err_free_skb;
+
+ spin_lock_bh(&nn->mbox_cmsg.queue.lock);
+
+ err = nfp_ccm_mbox_msg_enqueue(nn, skb, type, critical);
+ if (err)
+ goto err_unlock;
+
+ /* First in queue takes the mailbox lock and processes the batch */
+ if (!nfp_ccm_mbox_is_first(nn, skb)) {
+ bool to;
+
+ spin_unlock_bh(&nn->mbox_cmsg.queue.lock);
+
+ to = !wait_event_timeout(nn->mbox_cmsg.wq,
+ nfp_ccm_mbox_done(skb) ||
+ nfp_ccm_mbox_should_run(nn, skb),
+ msecs_to_jiffies(NFP_CCM_TIMEOUT));
+
+ /* fast path for those completed by another thread */
+ if (nfp_ccm_mbox_done(skb)) {
+ smp_rmb(); /* pairs with wmb after data is written */
+ return nfp_ccm_mbox_skb_return(skb);
+ }
+
+ spin_lock_bh(&nn->mbox_cmsg.queue.lock);
+
+ if (!nfp_ccm_mbox_is_first(nn, skb)) {
+ WARN_ON(!to);
+
+ err = nfp_ccm_mbox_unlink_unlock(nn, skb, type);
+ if (err)
+ goto err_free_skb;
+ return 0;
+ }
+ }
+
+ /* run queue expects the lock held */
+ nfp_ccm_mbox_run_queue_unlock(nn);
+ return nfp_ccm_mbox_skb_return(skb);
+
+err_unlock:
+ spin_unlock_bh(&nn->mbox_cmsg.queue.lock);
+err_free_skb:
+ dev_kfree_skb_any(skb);
+ return err;
+}
+
+int nfp_ccm_mbox_communicate(struct nfp_net *nn, struct sk_buff *skb,
+ enum nfp_ccm_type type,
+ unsigned int reply_size,
+ unsigned int max_reply_size)
+{
+ return __nfp_ccm_mbox_communicate(nn, skb, type, reply_size,
+ max_reply_size, false);
+}
+
+static void nfp_ccm_mbox_post_runq_work(struct work_struct *work)
+{
+ struct sk_buff *skb;
+ struct nfp_net *nn;
+
+ nn = container_of(work, struct nfp_net, mbox_cmsg.runq_work);
+
+ spin_lock_bh(&nn->mbox_cmsg.queue.lock);
+
+ skb = __skb_peek(&nn->mbox_cmsg.queue);
+ if (WARN_ON(!skb || !nfp_ccm_mbox_is_posted(skb) ||
+ !nfp_ccm_mbox_should_run(nn, skb))) {
+ spin_unlock_bh(&nn->mbox_cmsg.queue.lock);
+ return;
+ }
+
+ nfp_ccm_mbox_run_queue_unlock(nn);
+}
+
+static void nfp_ccm_mbox_post_wait_work(struct work_struct *work)
+{
+ struct sk_buff *skb;
+ struct nfp_net *nn;
+ int err;
+
+ nn = container_of(work, struct nfp_net, mbox_cmsg.wait_work);
+
+ skb = skb_peek(&nn->mbox_cmsg.queue);
+ if (WARN_ON(!skb || !nfp_ccm_mbox_is_posted(skb)))
+ /* Should never happen so it's unclear what to do here.. */
+ goto exit_unlock_wake;
+
+ err = nfp_net_mbox_reconfig_wait_posted(nn);
+ if (!err)
+ nfp_ccm_mbox_copy_out(nn, skb);
+ else
+ nfp_ccm_mbox_mark_all_err(nn, skb, -EIO);
+exit_unlock_wake:
+ nn_ctrl_bar_unlock(nn);
+ wake_up_all(&nn->mbox_cmsg.wq);
+}
+
+int nfp_ccm_mbox_post(struct nfp_net *nn, struct sk_buff *skb,
+ enum nfp_ccm_type type, unsigned int max_reply_size)
+{
+ int err;
+
+ err = nfp_ccm_mbox_msg_prepare(nn, skb, type, 0, max_reply_size,
+ GFP_ATOMIC);
+ if (err)
+ goto err_free_skb;
+
+ nfp_ccm_mbox_mark_posted(skb);
+
+ spin_lock_bh(&nn->mbox_cmsg.queue.lock);
+
+ err = nfp_ccm_mbox_msg_enqueue(nn, skb, type, false);
+ if (err)
+ goto err_unlock;
+
+ if (nfp_ccm_mbox_is_first(nn, skb)) {
+ if (nn_ctrl_bar_trylock(nn)) {
+ nfp_ccm_mbox_copy_in(nn, skb);
+ nfp_net_mbox_reconfig_post(nn,
+ NFP_NET_CFG_MBOX_CMD_TLV_CMSG);
+ queue_work(nn->mbox_cmsg.workq,
+ &nn->mbox_cmsg.wait_work);
+ } else {
+ nfp_ccm_mbox_mark_next_runner(nn);
+ }
+ }
+
+ spin_unlock_bh(&nn->mbox_cmsg.queue.lock);
+
+ return 0;
+
+err_unlock:
+ spin_unlock_bh(&nn->mbox_cmsg.queue.lock);
+err_free_skb:
+ dev_kfree_skb_any(skb);
+ return err;
+}
+
+struct sk_buff *
+nfp_ccm_mbox_msg_alloc(struct nfp_net *nn, unsigned int req_size,
+ unsigned int reply_size, gfp_t flags)
+{
+ unsigned int max_size;
+ struct sk_buff *skb;
+
+ if (!reply_size)
+ max_size = nfp_ccm_mbox_max_msg(nn);
+ else
+ max_size = max(req_size, reply_size);
+ max_size = round_up(max_size, 4);
+
+ skb = alloc_skb(max_size, flags);
+ if (!skb)
+ return NULL;
+
+ skb_put(skb, req_size);
+
+ return skb;
+}
+
+bool nfp_ccm_mbox_fits(struct nfp_net *nn, unsigned int size)
+{
+ return nfp_ccm_mbox_max_msg(nn) >= size;
+}
+
+int nfp_ccm_mbox_init(struct nfp_net *nn)
+{
+ return 0;
+}
+
+void nfp_ccm_mbox_clean(struct nfp_net *nn)
+{
+ drain_workqueue(nn->mbox_cmsg.workq);
+}
+
+int nfp_ccm_mbox_alloc(struct nfp_net *nn)
+{
+ skb_queue_head_init(&nn->mbox_cmsg.queue);
+ init_waitqueue_head(&nn->mbox_cmsg.wq);
+ INIT_WORK(&nn->mbox_cmsg.wait_work, nfp_ccm_mbox_post_wait_work);
+ INIT_WORK(&nn->mbox_cmsg.runq_work, nfp_ccm_mbox_post_runq_work);
+
+ nn->mbox_cmsg.workq = alloc_workqueue("nfp-ccm-mbox", WQ_UNBOUND, 0);
+ if (!nn->mbox_cmsg.workq)
+ return -ENOMEM;
+ return 0;
+}
+
+void nfp_ccm_mbox_free(struct nfp_net *nn)
+{
+ destroy_workqueue(nn->mbox_cmsg.workq);
+ WARN_ON(!skb_queue_empty(&nn->mbox_cmsg.queue));
+}
diff --git a/drivers/net/ethernet/netronome/nfp/crypto/crypto.h b/drivers/net/ethernet/netronome/nfp/crypto/crypto.h
new file mode 100644
index 000000000000..60372ddf69f0
--- /dev/null
+++ b/drivers/net/ethernet/netronome/nfp/crypto/crypto.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/* Copyright (C) 2019 Netronome Systems, Inc. */
+
+#ifndef NFP_CRYPTO_H
+#define NFP_CRYPTO_H 1
+
+struct nfp_net_tls_offload_ctx {
+ __be32 fw_handle[2];
+
+ u8 rx_end[0];
+ /* Tx only fields follow - Rx side does not have enough driver state
+ * to fit these
+ */
+
+ u32 next_seq;
+};
+
+#ifdef CONFIG_TLS_DEVICE
+int nfp_net_tls_init(struct nfp_net *nn);
+#else
+static inline int nfp_net_tls_init(struct nfp_net *nn)
+{
+ return 0;
+}
+#endif
+
+#endif
diff --git a/drivers/net/ethernet/netronome/nfp/crypto/fw.h b/drivers/net/ethernet/netronome/nfp/crypto/fw.h
new file mode 100644
index 000000000000..67413d946c4a
--- /dev/null
+++ b/drivers/net/ethernet/netronome/nfp/crypto/fw.h
@@ -0,0 +1,84 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/* Copyright (C) 2019 Netronome Systems, Inc. */
+
+#ifndef NFP_CRYPTO_FW_H
+#define NFP_CRYPTO_FW_H 1
+
+#include "../ccm.h"
+
+#define NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_ENC 0
+#define NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_DEC 1
+
+struct nfp_crypto_reply_simple {
+ struct nfp_ccm_hdr hdr;
+ __be32 error;
+};
+
+struct nfp_crypto_req_reset {
+ struct nfp_ccm_hdr hdr;
+ __be32 ep_id;
+};
+
+#define NFP_NET_TLS_IPVER GENMASK(15, 12)
+#define NFP_NET_TLS_VLAN GENMASK(11, 0)
+#define NFP_NET_TLS_VLAN_UNUSED 4095
+
+struct nfp_crypto_req_add_front {
+ struct nfp_ccm_hdr hdr;
+ __be32 ep_id;
+ u8 resv[3];
+ u8 opcode;
+ u8 key_len;
+ __be16 ipver_vlan __packed;
+ u8 l4_proto;
+#define NFP_NET_TLS_NON_ADDR_KEY_LEN 8
+ u8 l3_addrs[0];
+};
+
+struct nfp_crypto_req_add_back {
+ __be16 src_port;
+ __be16 dst_port;
+ __be32 key[8];
+ __be32 salt;
+ __be32 iv[2];
+ __be32 counter;
+ __be32 rec_no[2];
+ __be32 tcp_seq;
+};
+
+struct nfp_crypto_req_add_v4 {
+ struct nfp_crypto_req_add_front front;
+ __be32 src_ip;
+ __be32 dst_ip;
+ struct nfp_crypto_req_add_back back;
+};
+
+struct nfp_crypto_req_add_v6 {
+ struct nfp_crypto_req_add_front front;
+ __be32 src_ip[4];
+ __be32 dst_ip[4];
+ struct nfp_crypto_req_add_back back;
+};
+
+struct nfp_crypto_reply_add {
+ struct nfp_ccm_hdr hdr;
+ __be32 error;
+ __be32 handle[2];
+};
+
+struct nfp_crypto_req_del {
+ struct nfp_ccm_hdr hdr;
+ __be32 ep_id;
+ __be32 handle[2];
+};
+
+struct nfp_crypto_req_update {
+ struct nfp_ccm_hdr hdr;
+ __be32 ep_id;
+ u8 resv[3];
+ u8 opcode;
+ __be32 handle[2];
+ __be32 rec_no[2];
+ __be32 tcp_seq;
+};
+#endif
diff --git a/drivers/net/ethernet/netronome/nfp/crypto/tls.c b/drivers/net/ethernet/netronome/nfp/crypto/tls.c
new file mode 100644
index 000000000000..96a96b35c0ca
--- /dev/null
+++ b/drivers/net/ethernet/netronome/nfp/crypto/tls.c
@@ -0,0 +1,522 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2019 Netronome Systems, Inc. */
+
+#include <linux/bitfield.h>
+#include <linux/ipv6.h>
+#include <linux/skbuff.h>
+#include <linux/string.h>
+#include <net/tls.h>
+
+#include "../ccm.h"
+#include "../nfp_net.h"
+#include "crypto.h"
+#include "fw.h"
+
+#define NFP_NET_TLS_CCM_MBOX_OPS_MASK \
+ (BIT(NFP_CCM_TYPE_CRYPTO_RESET) | \
+ BIT(NFP_CCM_TYPE_CRYPTO_ADD) | \
+ BIT(NFP_CCM_TYPE_CRYPTO_DEL) | \
+ BIT(NFP_CCM_TYPE_CRYPTO_UPDATE))
+
+#define NFP_NET_TLS_OPCODE_MASK_RX \
+ BIT(NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_DEC)
+
+#define NFP_NET_TLS_OPCODE_MASK_TX \
+ BIT(NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_ENC)
+
+#define NFP_NET_TLS_OPCODE_MASK \
+ (NFP_NET_TLS_OPCODE_MASK_RX | NFP_NET_TLS_OPCODE_MASK_TX)
+
+static void nfp_net_crypto_set_op(struct nfp_net *nn, u8 opcode, bool on)
+{
+ u32 off, val;
+
+ off = nn->tlv_caps.crypto_enable_off + round_down(opcode / 8, 4);
+
+ val = nn_readl(nn, off);
+ if (on)
+ val |= BIT(opcode & 31);
+ else
+ val &= ~BIT(opcode & 31);
+ nn_writel(nn, off, val);
+}
+
+static bool
+__nfp_net_tls_conn_cnt_changed(struct nfp_net *nn, int add,
+ enum tls_offload_ctx_dir direction)
+{
+ u8 opcode;
+ int cnt;
+
+ if (direction == TLS_OFFLOAD_CTX_DIR_TX) {
+ opcode = NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_ENC;
+ nn->ktls_tx_conn_cnt += add;
+ cnt = nn->ktls_tx_conn_cnt;
+ nn->dp.ktls_tx = !!nn->ktls_tx_conn_cnt;
+ } else {
+ opcode = NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_DEC;
+ nn->ktls_rx_conn_cnt += add;
+ cnt = nn->ktls_rx_conn_cnt;
+ }
+
+ /* Care only about 0 -> 1 and 1 -> 0 transitions */
+ if (cnt > 1)
+ return false;
+
+ nfp_net_crypto_set_op(nn, opcode, cnt);
+ return true;
+}
+
+static int
+nfp_net_tls_conn_cnt_changed(struct nfp_net *nn, int add,
+ enum tls_offload_ctx_dir direction)
+{
+ int ret = 0;
+
+ /* Use the BAR lock to protect the connection counts */
+ nn_ctrl_bar_lock(nn);
+ if (__nfp_net_tls_conn_cnt_changed(nn, add, direction)) {
+ ret = __nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_CRYPTO);
+ /* Undo the cnt adjustment if failed */
+ if (ret)
+ __nfp_net_tls_conn_cnt_changed(nn, -add, direction);
+ }
+ nn_ctrl_bar_unlock(nn);
+
+ return ret;
+}
+
+static int
+nfp_net_tls_conn_add(struct nfp_net *nn, enum tls_offload_ctx_dir direction)
+{
+ return nfp_net_tls_conn_cnt_changed(nn, 1, direction);
+}
+
+static int
+nfp_net_tls_conn_remove(struct nfp_net *nn, enum tls_offload_ctx_dir direction)
+{
+ return nfp_net_tls_conn_cnt_changed(nn, -1, direction);
+}
+
+static struct sk_buff *
+nfp_net_tls_alloc_simple(struct nfp_net *nn, size_t req_sz, gfp_t flags)
+{
+ return nfp_ccm_mbox_msg_alloc(nn, req_sz,
+ sizeof(struct nfp_crypto_reply_simple),
+ flags);
+}
+
+static int
+nfp_net_tls_communicate_simple(struct nfp_net *nn, struct sk_buff *skb,
+ const char *name, enum nfp_ccm_type type)
+{
+ struct nfp_crypto_reply_simple *reply;
+ int err;
+
+ err = __nfp_ccm_mbox_communicate(nn, skb, type,
+ sizeof(*reply), sizeof(*reply),
+ type == NFP_CCM_TYPE_CRYPTO_DEL);
+ if (err) {
+ nn_dp_warn(&nn->dp, "failed to %s TLS: %d\n", name, err);
+ return err;
+ }
+
+ reply = (void *)skb->data;
+ err = -be32_to_cpu(reply->error);
+ if (err)
+ nn_dp_warn(&nn->dp, "failed to %s TLS, fw replied: %d\n",
+ name, err);
+ dev_consume_skb_any(skb);
+
+ return err;
+}
+
+static void nfp_net_tls_del_fw(struct nfp_net *nn, __be32 *fw_handle)
+{
+ struct nfp_crypto_req_del *req;
+ struct sk_buff *skb;
+
+ skb = nfp_net_tls_alloc_simple(nn, sizeof(*req), GFP_KERNEL);
+ if (!skb)
+ return;
+
+ req = (void *)skb->data;
+ req->ep_id = 0;
+ memcpy(req->handle, fw_handle, sizeof(req->handle));
+
+ nfp_net_tls_communicate_simple(nn, skb, "delete",
+ NFP_CCM_TYPE_CRYPTO_DEL);
+}
+
+static void
+nfp_net_tls_set_ipver_vlan(struct nfp_crypto_req_add_front *front, u8 ipver)
+{
+ front->ipver_vlan = cpu_to_be16(FIELD_PREP(NFP_NET_TLS_IPVER, ipver) |
+ FIELD_PREP(NFP_NET_TLS_VLAN,
+ NFP_NET_TLS_VLAN_UNUSED));
+}
+
+static void
+nfp_net_tls_assign_conn_id(struct nfp_net *nn,
+ struct nfp_crypto_req_add_front *front)
+{
+ u32 len;
+ u64 id;
+
+ id = atomic64_inc_return(&nn->ktls_conn_id_gen);
+ len = front->key_len - NFP_NET_TLS_NON_ADDR_KEY_LEN;
+
+ memcpy(front->l3_addrs, &id, sizeof(id));
+ memset(front->l3_addrs + sizeof(id), 0, len - sizeof(id));
+}
+
+static struct nfp_crypto_req_add_back *
+nfp_net_tls_set_ipv4(struct nfp_net *nn, struct nfp_crypto_req_add_v4 *req,
+ struct sock *sk, int direction)
+{
+ struct inet_sock *inet = inet_sk(sk);
+
+ req->front.key_len += sizeof(__be32) * 2;
+
+ if (direction == TLS_OFFLOAD_CTX_DIR_TX) {
+ nfp_net_tls_assign_conn_id(nn, &req->front);
+ } else {
+ req->src_ip = inet->inet_daddr;
+ req->dst_ip = inet->inet_saddr;
+ }
+
+ return &req->back;
+}
+
+static struct nfp_crypto_req_add_back *
+nfp_net_tls_set_ipv6(struct nfp_net *nn, struct nfp_crypto_req_add_v6 *req,
+ struct sock *sk, int direction)
+{
+#if IS_ENABLED(CONFIG_IPV6)
+ struct ipv6_pinfo *np = inet6_sk(sk);
+
+ req->front.key_len += sizeof(struct in6_addr) * 2;
+
+ if (direction == TLS_OFFLOAD_CTX_DIR_TX) {
+ nfp_net_tls_assign_conn_id(nn, &req->front);
+ } else {
+ memcpy(req->src_ip, &sk->sk_v6_daddr, sizeof(req->src_ip));
+ memcpy(req->dst_ip, &np->saddr, sizeof(req->dst_ip));
+ }
+
+#endif
+ return &req->back;
+}
+
+static void
+nfp_net_tls_set_l4(struct nfp_crypto_req_add_front *front,
+ struct nfp_crypto_req_add_back *back, struct sock *sk,
+ int direction)
+{
+ struct inet_sock *inet = inet_sk(sk);
+
+ front->l4_proto = IPPROTO_TCP;
+
+ if (direction == TLS_OFFLOAD_CTX_DIR_TX) {
+ back->src_port = 0;
+ back->dst_port = 0;
+ } else {
+ back->src_port = inet->inet_dport;
+ back->dst_port = inet->inet_sport;
+ }
+}
+
+static u8 nfp_tls_1_2_dir_to_opcode(enum tls_offload_ctx_dir direction)
+{
+ switch (direction) {
+ case TLS_OFFLOAD_CTX_DIR_TX:
+ return NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_ENC;
+ case TLS_OFFLOAD_CTX_DIR_RX:
+ return NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_DEC;
+ default:
+ WARN_ON_ONCE(1);
+ return 0;
+ }
+}
+
+static bool
+nfp_net_cipher_supported(struct nfp_net *nn, u16 cipher_type,
+ enum tls_offload_ctx_dir direction)
+{
+ u8 bit;
+
+ switch (cipher_type) {
+ case TLS_CIPHER_AES_GCM_128:
+ if (direction == TLS_OFFLOAD_CTX_DIR_TX)
+ bit = NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_ENC;
+ else
+ bit = NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_DEC;
+ break;
+ default:
+ return false;
+ }
+
+ return nn->tlv_caps.crypto_ops & BIT(bit);
+}
+
+static int
+nfp_net_tls_add(struct net_device *netdev, struct sock *sk,
+ enum tls_offload_ctx_dir direction,
+ struct tls_crypto_info *crypto_info,
+ u32 start_offload_tcp_sn)
+{
+ struct tls12_crypto_info_aes_gcm_128 *tls_ci;
+ struct nfp_net *nn = netdev_priv(netdev);
+ struct nfp_crypto_req_add_front *front;
+ struct nfp_net_tls_offload_ctx *ntls;
+ struct nfp_crypto_req_add_back *back;
+ struct nfp_crypto_reply_add *reply;
+ struct sk_buff *skb;
+ size_t req_sz;
+ void *req;
+ bool ipv6;
+ int err;
+
+ BUILD_BUG_ON(sizeof(struct nfp_net_tls_offload_ctx) >
+ TLS_DRIVER_STATE_SIZE_TX);
+ BUILD_BUG_ON(offsetof(struct nfp_net_tls_offload_ctx, rx_end) >
+ TLS_DRIVER_STATE_SIZE_RX);
+
+ if (!nfp_net_cipher_supported(nn, crypto_info->cipher_type, direction))
+ return -EOPNOTSUPP;
+
+ switch (sk->sk_family) {
+#if IS_ENABLED(CONFIG_IPV6)
+ case AF_INET6:
+ if (sk->sk_ipv6only ||
+ ipv6_addr_type(&sk->sk_v6_daddr) != IPV6_ADDR_MAPPED) {
+ req_sz = sizeof(struct nfp_crypto_req_add_v6);
+ ipv6 = true;
+ break;
+ }
+#endif
+ /* fall through */
+ case AF_INET:
+ req_sz = sizeof(struct nfp_crypto_req_add_v4);
+ ipv6 = false;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ err = nfp_net_tls_conn_add(nn, direction);
+ if (err)
+ return err;
+
+ skb = nfp_ccm_mbox_msg_alloc(nn, req_sz, sizeof(*reply), GFP_KERNEL);
+ if (!skb) {
+ err = -ENOMEM;
+ goto err_conn_remove;
+ }
+
+ front = (void *)skb->data;
+ front->ep_id = 0;
+ front->key_len = NFP_NET_TLS_NON_ADDR_KEY_LEN;
+ front->opcode = nfp_tls_1_2_dir_to_opcode(direction);
+ memset(front->resv, 0, sizeof(front->resv));
+
+ nfp_net_tls_set_ipver_vlan(front, ipv6 ? 6 : 4);
+
+ req = (void *)skb->data;
+ if (ipv6)
+ back = nfp_net_tls_set_ipv6(nn, req, sk, direction);
+ else
+ back = nfp_net_tls_set_ipv4(nn, req, sk, direction);
+
+ nfp_net_tls_set_l4(front, back, sk, direction);
+
+ back->counter = 0;
+ back->tcp_seq = cpu_to_be32(start_offload_tcp_sn);
+
+ tls_ci = (struct tls12_crypto_info_aes_gcm_128 *)crypto_info;
+ memcpy(back->key, tls_ci->key, TLS_CIPHER_AES_GCM_128_KEY_SIZE);
+ memset(&back->key[TLS_CIPHER_AES_GCM_128_KEY_SIZE / 4], 0,
+ sizeof(back->key) - TLS_CIPHER_AES_GCM_128_KEY_SIZE);
+ memcpy(back->iv, tls_ci->iv, TLS_CIPHER_AES_GCM_128_IV_SIZE);
+ memcpy(&back->salt, tls_ci->salt, TLS_CIPHER_AES_GCM_128_SALT_SIZE);
+ memcpy(back->rec_no, tls_ci->rec_seq, sizeof(tls_ci->rec_seq));
+
+ /* Get an extra ref on the skb so we can wipe the key after */
+ skb_get(skb);
+
+ err = nfp_ccm_mbox_communicate(nn, skb, NFP_CCM_TYPE_CRYPTO_ADD,
+ sizeof(*reply), sizeof(*reply));
+ reply = (void *)skb->data;
+
+ /* We depend on CCM MBOX code not reallocating skb we sent
+ * so we can clear the key material out of the memory.
+ */
+ if (!WARN_ON_ONCE((u8 *)back < skb->head ||
+ (u8 *)back > skb_end_pointer(skb)) &&
+ !WARN_ON_ONCE((u8 *)&reply[1] > (u8 *)back))
+ memzero_explicit(back, sizeof(*back));
+ dev_consume_skb_any(skb); /* the extra ref from skb_get() above */
+
+ if (err) {
+ nn_dp_warn(&nn->dp, "failed to add TLS: %d (%d)\n",
+ err, direction == TLS_OFFLOAD_CTX_DIR_TX);
+ /* communicate frees skb on error */
+ goto err_conn_remove;
+ }
+
+ err = -be32_to_cpu(reply->error);
+ if (err) {
+ if (err == -ENOSPC) {
+ if (!atomic_fetch_inc(&nn->ktls_no_space))
+ nn_info(nn, "HW TLS table full\n");
+ } else {
+ nn_dp_warn(&nn->dp,
+ "failed to add TLS, FW replied: %d\n", err);
+ }
+ goto err_free_skb;
+ }
+
+ if (!reply->handle[0] && !reply->handle[1]) {
+ nn_dp_warn(&nn->dp, "FW returned NULL handle\n");
+ err = -EINVAL;
+ goto err_fw_remove;
+ }
+
+ ntls = tls_driver_ctx(sk, direction);
+ memcpy(ntls->fw_handle, reply->handle, sizeof(ntls->fw_handle));
+ if (direction == TLS_OFFLOAD_CTX_DIR_TX)
+ ntls->next_seq = start_offload_tcp_sn;
+ dev_consume_skb_any(skb);
+
+ if (direction == TLS_OFFLOAD_CTX_DIR_TX)
+ return 0;
+
+ tls_offload_rx_resync_set_type(sk,
+ TLS_OFFLOAD_SYNC_TYPE_CORE_NEXT_HINT);
+ return 0;
+
+err_fw_remove:
+ nfp_net_tls_del_fw(nn, reply->handle);
+err_free_skb:
+ dev_consume_skb_any(skb);
+err_conn_remove:
+ nfp_net_tls_conn_remove(nn, direction);
+ return err;
+}
+
+static void
+nfp_net_tls_del(struct net_device *netdev, struct tls_context *tls_ctx,
+ enum tls_offload_ctx_dir direction)
+{
+ struct nfp_net *nn = netdev_priv(netdev);
+ struct nfp_net_tls_offload_ctx *ntls;
+
+ nfp_net_tls_conn_remove(nn, direction);
+
+ ntls = __tls_driver_ctx(tls_ctx, direction);
+ nfp_net_tls_del_fw(nn, ntls->fw_handle);
+}
+
+static int
+nfp_net_tls_resync(struct net_device *netdev, struct sock *sk, u32 seq,
+ u8 *rcd_sn, enum tls_offload_ctx_dir direction)
+{
+ struct nfp_net *nn = netdev_priv(netdev);
+ struct nfp_net_tls_offload_ctx *ntls;
+ struct nfp_crypto_req_update *req;
+ struct sk_buff *skb;
+ gfp_t flags;
+ int err;
+
+ flags = direction == TLS_OFFLOAD_CTX_DIR_TX ? GFP_KERNEL : GFP_ATOMIC;
+ skb = nfp_net_tls_alloc_simple(nn, sizeof(*req), flags);
+ if (!skb)
+ return -ENOMEM;
+
+ ntls = tls_driver_ctx(sk, direction);
+ req = (void *)skb->data;
+ req->ep_id = 0;
+ req->opcode = nfp_tls_1_2_dir_to_opcode(direction);
+ memset(req->resv, 0, sizeof(req->resv));
+ memcpy(req->handle, ntls->fw_handle, sizeof(ntls->fw_handle));
+ req->tcp_seq = cpu_to_be32(seq);
+ memcpy(req->rec_no, rcd_sn, sizeof(req->rec_no));
+
+ if (direction == TLS_OFFLOAD_CTX_DIR_TX) {
+ err = nfp_net_tls_communicate_simple(nn, skb, "sync",
+ NFP_CCM_TYPE_CRYPTO_UPDATE);
+ if (err)
+ return err;
+ ntls->next_seq = seq;
+ } else {
+ nfp_ccm_mbox_post(nn, skb, NFP_CCM_TYPE_CRYPTO_UPDATE,
+ sizeof(struct nfp_crypto_reply_simple));
+ }
+
+ return 0;
+}
+
+static const struct tlsdev_ops nfp_net_tls_ops = {
+ .tls_dev_add = nfp_net_tls_add,
+ .tls_dev_del = nfp_net_tls_del,
+ .tls_dev_resync = nfp_net_tls_resync,
+};
+
+static int nfp_net_tls_reset(struct nfp_net *nn)
+{
+ struct nfp_crypto_req_reset *req;
+ struct sk_buff *skb;
+
+ skb = nfp_net_tls_alloc_simple(nn, sizeof(*req), GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+
+ req = (void *)skb->data;
+ req->ep_id = 0;
+
+ return nfp_net_tls_communicate_simple(nn, skb, "reset",
+ NFP_CCM_TYPE_CRYPTO_RESET);
+}
+
+int nfp_net_tls_init(struct nfp_net *nn)
+{
+ struct net_device *netdev = nn->dp.netdev;
+ int err;
+
+ if (!(nn->tlv_caps.crypto_ops & NFP_NET_TLS_OPCODE_MASK))
+ return 0;
+
+ if ((nn->tlv_caps.mbox_cmsg_types & NFP_NET_TLS_CCM_MBOX_OPS_MASK) !=
+ NFP_NET_TLS_CCM_MBOX_OPS_MASK)
+ return 0;
+
+ if (!nfp_ccm_mbox_fits(nn, sizeof(struct nfp_crypto_req_add_v6))) {
+ nn_warn(nn, "disabling TLS offload - mbox too small: %d\n",
+ nn->tlv_caps.mbox_len);
+ return 0;
+ }
+
+ err = nfp_net_tls_reset(nn);
+ if (err)
+ return err;
+
+ nn_ctrl_bar_lock(nn);
+ nn_writel(nn, nn->tlv_caps.crypto_enable_off, 0);
+ err = __nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_CRYPTO);
+ nn_ctrl_bar_unlock(nn);
+ if (err)
+ return err;
+
+ if (nn->tlv_caps.crypto_ops & NFP_NET_TLS_OPCODE_MASK_RX) {
+ netdev->hw_features |= NETIF_F_HW_TLS_RX;
+ netdev->features |= NETIF_F_HW_TLS_RX;
+ }
+ if (nn->tlv_caps.crypto_ops & NFP_NET_TLS_OPCODE_MASK_TX) {
+ netdev->hw_features |= NETIF_F_HW_TLS_TX;
+ netdev->features |= NETIF_F_HW_TLS_TX;
+ }
+
+ netdev->tlsdev_ops = &nfp_net_tls_ops;
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/netronome/nfp/flower/action.c b/drivers/net/ethernet/netronome/nfp/flower/action.c
index c56e31d9f8a4..5a54fe848de4 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/action.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/action.c
@@ -54,7 +54,8 @@ nfp_fl_push_vlan(struct nfp_fl_push_vlan *push_vlan,
static int
nfp_fl_pre_lag(struct nfp_app *app, const struct flow_action_entry *act,
- struct nfp_fl_payload *nfp_flow, int act_len)
+ struct nfp_fl_payload *nfp_flow, int act_len,
+ struct netlink_ext_ack *extack)
{
size_t act_size = sizeof(struct nfp_fl_pre_lag);
struct nfp_fl_pre_lag *pre_lag;
@@ -65,8 +66,10 @@ nfp_fl_pre_lag(struct nfp_app *app, const struct flow_action_entry *act,
if (!out_dev || !netif_is_lag_master(out_dev))
return 0;
- if (act_len + act_size > NFP_FL_MAX_A_SIZ)
+ if (act_len + act_size > NFP_FL_MAX_A_SIZ) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: maximum allowed action list size exceeded at LAG action");
return -EOPNOTSUPP;
+ }
/* Pre_lag action must be first on action list.
* If other actions already exist they need pushed forward.
@@ -76,7 +79,7 @@ nfp_fl_pre_lag(struct nfp_app *app, const struct flow_action_entry *act,
nfp_flow->action_data, act_len);
pre_lag = (struct nfp_fl_pre_lag *)nfp_flow->action_data;
- err = nfp_flower_lag_populate_pre_action(app, out_dev, pre_lag);
+ err = nfp_flower_lag_populate_pre_action(app, out_dev, pre_lag, extack);
if (err)
return err;
@@ -93,7 +96,8 @@ nfp_fl_output(struct nfp_app *app, struct nfp_fl_output *output,
const struct flow_action_entry *act,
struct nfp_fl_payload *nfp_flow,
bool last, struct net_device *in_dev,
- enum nfp_flower_tun_type tun_type, int *tun_out_cnt)
+ enum nfp_flower_tun_type tun_type, int *tun_out_cnt,
+ struct netlink_ext_ack *extack)
{
size_t act_size = sizeof(struct nfp_fl_output);
struct nfp_flower_priv *priv = app->priv;
@@ -104,18 +108,24 @@ nfp_fl_output(struct nfp_app *app, struct nfp_fl_output *output,
output->head.len_lw = act_size >> NFP_FL_LW_SIZ;
out_dev = act->dev;
- if (!out_dev)
+ if (!out_dev) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: invalid egress interface for mirred action");
return -EOPNOTSUPP;
+ }
tmp_flags = last ? NFP_FL_OUT_FLAGS_LAST : 0;
if (tun_type) {
/* Verify the egress netdev matches the tunnel type. */
- if (!nfp_fl_netdev_is_tunnel_type(out_dev, tun_type))
+ if (!nfp_fl_netdev_is_tunnel_type(out_dev, tun_type)) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: egress interface does not match the required tunnel type");
return -EOPNOTSUPP;
+ }
- if (*tun_out_cnt)
+ if (*tun_out_cnt) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: cannot offload more than one tunnel mirred output per filter");
return -EOPNOTSUPP;
+ }
(*tun_out_cnt)++;
output->flags = cpu_to_be16(tmp_flags |
@@ -127,8 +137,10 @@ nfp_fl_output(struct nfp_app *app, struct nfp_fl_output *output,
output->flags = cpu_to_be16(tmp_flags);
gid = nfp_flower_lag_get_output_id(app, out_dev);
- if (gid < 0)
+ if (gid < 0) {
+ NL_SET_ERR_MSG_MOD(extack, "invalid entry: cannot find group id for LAG action");
return gid;
+ }
output->port = cpu_to_be32(NFP_FL_LAG_OUT | gid);
} else {
/* Set action output parameters. */
@@ -136,29 +148,58 @@ nfp_fl_output(struct nfp_app *app, struct nfp_fl_output *output,
if (nfp_netdev_is_nfp_repr(in_dev)) {
/* Confirm ingress and egress are on same device. */
- if (!netdev_port_same_parent_id(in_dev, out_dev))
+ if (!netdev_port_same_parent_id(in_dev, out_dev)) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: ingress and egress interfaces are on different devices");
return -EOPNOTSUPP;
+ }
}
- if (!nfp_netdev_is_nfp_repr(out_dev))
+ if (!nfp_netdev_is_nfp_repr(out_dev)) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: egress interface is not an nfp port");
return -EOPNOTSUPP;
+ }
output->port = cpu_to_be32(nfp_repr_get_port_id(out_dev));
- if (!output->port)
+ if (!output->port) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: invalid port id for egress interface");
return -EOPNOTSUPP;
+ }
}
nfp_flow->meta.shortcut = output->port;
return 0;
}
+static bool
+nfp_flower_tun_is_gre(struct flow_cls_offload *flow, int start_idx)
+{
+ struct flow_action_entry *act = flow->rule->action.entries;
+ int num_act = flow->rule->action.num_entries;
+ int act_idx;
+
+ /* Preparse action list for next mirred or redirect action */
+ for (act_idx = start_idx + 1; act_idx < num_act; act_idx++)
+ if (act[act_idx].id == FLOW_ACTION_REDIRECT ||
+ act[act_idx].id == FLOW_ACTION_MIRRED)
+ return netif_is_gretap(act[act_idx].dev);
+
+ return false;
+}
+
static enum nfp_flower_tun_type
-nfp_fl_get_tun_from_act_l4_port(struct nfp_app *app,
- const struct flow_action_entry *act)
+nfp_fl_get_tun_from_act(struct nfp_app *app,
+ struct flow_cls_offload *flow,
+ const struct flow_action_entry *act, int act_idx)
{
const struct ip_tunnel_info *tun = act->tunnel;
struct nfp_flower_priv *priv = app->priv;
+ /* Determine the tunnel type based on the egress netdev
+ * in the mirred action for tunnels without l4.
+ */
+ if (nfp_flower_tun_is_gre(flow, act_idx))
+ return NFP_FL_TUNNEL_GRE;
+
switch (tun->key.tp_dst) {
case htons(IANA_VXLAN_UDP_PORT):
return NFP_FL_TUNNEL_VXLAN;
@@ -194,7 +235,8 @@ static struct nfp_fl_pre_tunnel *nfp_fl_pre_tunnel(char *act_data, int act_len)
static int
nfp_fl_push_geneve_options(struct nfp_fl_payload *nfp_fl, int *list_len,
- const struct flow_action_entry *act)
+ const struct flow_action_entry *act,
+ struct netlink_ext_ack *extack)
{
struct ip_tunnel_info *ip_tun = (struct ip_tunnel_info *)act->tunnel;
int opt_len, opt_cnt, act_start, tot_push_len;
@@ -212,20 +254,26 @@ nfp_fl_push_geneve_options(struct nfp_fl_payload *nfp_fl, int *list_len,
struct geneve_opt *opt = (struct geneve_opt *)src;
opt_cnt++;
- if (opt_cnt > NFP_FL_MAX_GENEVE_OPT_CNT)
+ if (opt_cnt > NFP_FL_MAX_GENEVE_OPT_CNT) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: maximum allowed number of geneve options exceeded");
return -EOPNOTSUPP;
+ }
tot_push_len += sizeof(struct nfp_fl_push_geneve) +
opt->length * 4;
- if (tot_push_len > NFP_FL_MAX_GENEVE_OPT_ACT)
+ if (tot_push_len > NFP_FL_MAX_GENEVE_OPT_ACT) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: maximum allowed action list size exceeded at push geneve options");
return -EOPNOTSUPP;
+ }
opt_len -= sizeof(struct geneve_opt) + opt->length * 4;
src += sizeof(struct geneve_opt) + opt->length * 4;
}
- if (*list_len + tot_push_len > NFP_FL_MAX_A_SIZ)
+ if (*list_len + tot_push_len > NFP_FL_MAX_A_SIZ) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: maximum allowed action list size exceeded at push geneve options");
return -EOPNOTSUPP;
+ }
act_start = *list_len;
*list_len += tot_push_len;
@@ -256,14 +304,13 @@ nfp_fl_push_geneve_options(struct nfp_fl_payload *nfp_fl, int *list_len,
}
static int
-nfp_fl_set_ipv4_udp_tun(struct nfp_app *app,
- struct nfp_fl_set_ipv4_udp_tun *set_tun,
- const struct flow_action_entry *act,
- struct nfp_fl_pre_tunnel *pre_tun,
- enum nfp_flower_tun_type tun_type,
- struct net_device *netdev)
+nfp_fl_set_ipv4_tun(struct nfp_app *app, struct nfp_fl_set_ipv4_tun *set_tun,
+ const struct flow_action_entry *act,
+ struct nfp_fl_pre_tunnel *pre_tun,
+ enum nfp_flower_tun_type tun_type,
+ struct net_device *netdev, struct netlink_ext_ack *extack)
{
- size_t act_size = sizeof(struct nfp_fl_set_ipv4_udp_tun);
+ size_t act_size = sizeof(struct nfp_fl_set_ipv4_tun);
const struct ip_tunnel_info *ip_tun = act->tunnel;
struct nfp_flower_priv *priv = app->priv;
u32 tmp_set_ip_tun_type_index = 0;
@@ -275,8 +322,10 @@ nfp_fl_set_ipv4_udp_tun(struct nfp_app *app,
NFP_FL_TUNNEL_GENEVE_OPT != TUNNEL_GENEVE_OPT);
if (ip_tun->options_len &&
(tun_type != NFP_FL_TUNNEL_GENEVE ||
- !(priv->flower_ext_feats & NFP_FL_FEATS_GENEVE_OPT)))
+ !(priv->flower_ext_feats & NFP_FL_FEATS_GENEVE_OPT))) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: loaded firmware does not support geneve options offload");
return -EOPNOTSUPP;
+ }
set_tun->head.jump_id = NFP_FL_ACTION_OPCODE_SET_IPV4_TUNNEL;
set_tun->head.len_lw = act_size >> NFP_FL_LW_SIZ;
@@ -316,8 +365,10 @@ nfp_fl_set_ipv4_udp_tun(struct nfp_app *app,
set_tun->tos = ip_tun->key.tos;
if (!(ip_tun->key.tun_flags & NFP_FL_TUNNEL_KEY) ||
- ip_tun->key.tun_flags & ~NFP_FL_SUPPORTED_IPV4_UDP_TUN_FLAGS)
+ ip_tun->key.tun_flags & ~NFP_FL_SUPPORTED_IPV4_UDP_TUN_FLAGS) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: loaded firmware does not support tunnel flag offload");
return -EOPNOTSUPP;
+ }
set_tun->tun_flags = ip_tun->key.tun_flags;
if (tun_type == NFP_FL_TUNNEL_GENEVE) {
@@ -345,18 +396,22 @@ static void nfp_fl_set_helper32(u32 value, u32 mask, u8 *p_exact, u8 *p_mask)
static int
nfp_fl_set_eth(const struct flow_action_entry *act, u32 off,
- struct nfp_fl_set_eth *set_eth)
+ struct nfp_fl_set_eth *set_eth, struct netlink_ext_ack *extack)
{
u32 exact, mask;
- if (off + 4 > ETH_ALEN * 2)
+ if (off + 4 > ETH_ALEN * 2) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: invalid pedit ethernet action");
return -EOPNOTSUPP;
+ }
mask = ~act->mangle.mask;
exact = act->mangle.val;
- if (exact & ~mask)
+ if (exact & ~mask) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: invalid pedit ethernet action");
return -EOPNOTSUPP;
+ }
nfp_fl_set_helper32(exact, mask, &set_eth->eth_addr_val[off],
&set_eth->eth_addr_mask[off]);
@@ -377,7 +432,8 @@ struct ipv4_ttl_word {
static int
nfp_fl_set_ip4(const struct flow_action_entry *act, u32 off,
struct nfp_fl_set_ip4_addrs *set_ip_addr,
- struct nfp_fl_set_ip4_ttl_tos *set_ip_ttl_tos)
+ struct nfp_fl_set_ip4_ttl_tos *set_ip_ttl_tos,
+ struct netlink_ext_ack *extack)
{
struct ipv4_ttl_word *ttl_word_mask;
struct ipv4_ttl_word *ttl_word;
@@ -389,8 +445,10 @@ nfp_fl_set_ip4(const struct flow_action_entry *act, u32 off,
mask = (__force __be32)~act->mangle.mask;
exact = (__force __be32)act->mangle.val;
- if (exact & ~mask)
+ if (exact & ~mask) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: invalid pedit IPv4 action");
return -EOPNOTSUPP;
+ }
switch (off) {
case offsetof(struct iphdr, daddr):
@@ -413,8 +471,10 @@ nfp_fl_set_ip4(const struct flow_action_entry *act, u32 off,
ttl_word_mask = (struct ipv4_ttl_word *)&mask;
ttl_word = (struct ipv4_ttl_word *)&exact;
- if (ttl_word_mask->protocol || ttl_word_mask->check)
+ if (ttl_word_mask->protocol || ttl_word_mask->check) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: invalid pedit IPv4 ttl action");
return -EOPNOTSUPP;
+ }
set_ip_ttl_tos->ipv4_ttl_mask |= ttl_word_mask->ttl;
set_ip_ttl_tos->ipv4_ttl &= ~ttl_word_mask->ttl;
@@ -429,8 +489,10 @@ nfp_fl_set_ip4(const struct flow_action_entry *act, u32 off,
tos_word = (struct iphdr *)&exact;
if (tos_word_mask->version || tos_word_mask->ihl ||
- tos_word_mask->tot_len)
+ tos_word_mask->tot_len) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: invalid pedit IPv4 tos action");
return -EOPNOTSUPP;
+ }
set_ip_ttl_tos->ipv4_tos_mask |= tos_word_mask->tos;
set_ip_ttl_tos->ipv4_tos &= ~tos_word_mask->tos;
@@ -441,6 +503,7 @@ nfp_fl_set_ip4(const struct flow_action_entry *act, u32 off,
NFP_FL_LW_SIZ;
break;
default:
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: pedit on unsupported section of IPv4 header");
return -EOPNOTSUPP;
}
@@ -468,7 +531,8 @@ struct ipv6_hop_limit_word {
static int
nfp_fl_set_ip6_hop_limit_flow_label(u32 off, __be32 exact, __be32 mask,
- struct nfp_fl_set_ipv6_tc_hl_fl *ip_hl_fl)
+ struct nfp_fl_set_ipv6_tc_hl_fl *ip_hl_fl,
+ struct netlink_ext_ack *extack)
{
struct ipv6_hop_limit_word *fl_hl_mask;
struct ipv6_hop_limit_word *fl_hl;
@@ -478,8 +542,10 @@ nfp_fl_set_ip6_hop_limit_flow_label(u32 off, __be32 exact, __be32 mask,
fl_hl_mask = (struct ipv6_hop_limit_word *)&mask;
fl_hl = (struct ipv6_hop_limit_word *)&exact;
- if (fl_hl_mask->nexthdr || fl_hl_mask->payload_len)
+ if (fl_hl_mask->nexthdr || fl_hl_mask->payload_len) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: invalid pedit IPv6 hop limit action");
return -EOPNOTSUPP;
+ }
ip_hl_fl->ipv6_hop_limit_mask |= fl_hl_mask->hop_limit;
ip_hl_fl->ipv6_hop_limit &= ~fl_hl_mask->hop_limit;
@@ -488,8 +554,10 @@ nfp_fl_set_ip6_hop_limit_flow_label(u32 off, __be32 exact, __be32 mask,
break;
case round_down(offsetof(struct ipv6hdr, flow_lbl), 4):
if (mask & ~IPV6_FLOW_LABEL_MASK ||
- exact & ~IPV6_FLOW_LABEL_MASK)
+ exact & ~IPV6_FLOW_LABEL_MASK) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: invalid pedit IPv6 flow label action");
return -EOPNOTSUPP;
+ }
ip_hl_fl->ipv6_label_mask |= mask;
ip_hl_fl->ipv6_label &= ~mask;
@@ -507,7 +575,8 @@ static int
nfp_fl_set_ip6(const struct flow_action_entry *act, u32 off,
struct nfp_fl_set_ipv6_addr *ip_dst,
struct nfp_fl_set_ipv6_addr *ip_src,
- struct nfp_fl_set_ipv6_tc_hl_fl *ip_hl_fl)
+ struct nfp_fl_set_ipv6_tc_hl_fl *ip_hl_fl,
+ struct netlink_ext_ack *extack)
{
__be32 exact, mask;
int err = 0;
@@ -517,12 +586,14 @@ nfp_fl_set_ip6(const struct flow_action_entry *act, u32 off,
mask = (__force __be32)~act->mangle.mask;
exact = (__force __be32)act->mangle.val;
- if (exact & ~mask)
+ if (exact & ~mask) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: invalid pedit IPv6 action");
return -EOPNOTSUPP;
+ }
if (off < offsetof(struct ipv6hdr, saddr)) {
err = nfp_fl_set_ip6_hop_limit_flow_label(off, exact, mask,
- ip_hl_fl);
+ ip_hl_fl, extack);
} else if (off < offsetof(struct ipv6hdr, daddr)) {
word = (off - offsetof(struct ipv6hdr, saddr)) / sizeof(exact);
nfp_fl_set_ip6_helper(NFP_FL_ACTION_OPCODE_SET_IPV6_SRC, word,
@@ -533,6 +604,7 @@ nfp_fl_set_ip6(const struct flow_action_entry *act, u32 off,
nfp_fl_set_ip6_helper(NFP_FL_ACTION_OPCODE_SET_IPV6_DST, word,
exact, mask, ip_dst);
} else {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: pedit on unsupported section of IPv6 header");
return -EOPNOTSUPP;
}
@@ -541,18 +613,23 @@ nfp_fl_set_ip6(const struct flow_action_entry *act, u32 off,
static int
nfp_fl_set_tport(const struct flow_action_entry *act, u32 off,
- struct nfp_fl_set_tport *set_tport, int opcode)
+ struct nfp_fl_set_tport *set_tport, int opcode,
+ struct netlink_ext_ack *extack)
{
u32 exact, mask;
- if (off)
+ if (off) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: pedit on unsupported section of L4 header");
return -EOPNOTSUPP;
+ }
mask = ~act->mangle.mask;
exact = act->mangle.val;
- if (exact & ~mask)
+ if (exact & ~mask) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: invalid pedit L4 action");
return -EOPNOTSUPP;
+ }
nfp_fl_set_helper32(exact, mask, set_tport->tp_port_val,
set_tport->tp_port_mask);
@@ -592,11 +669,11 @@ struct nfp_flower_pedit_acts {
};
static int
-nfp_fl_commit_mangle(struct tc_cls_flower_offload *flow, char *nfp_action,
+nfp_fl_commit_mangle(struct flow_cls_offload *flow, char *nfp_action,
int *a_len, struct nfp_flower_pedit_acts *set_act,
u32 *csum_updated)
{
- struct flow_rule *rule = tc_cls_flower_offload_flow_rule(flow);
+ struct flow_rule *rule = flow_cls_offload_flow_rule(flow);
size_t act_size = 0;
u8 ip_proto = 0;
@@ -694,8 +771,9 @@ nfp_fl_commit_mangle(struct tc_cls_flower_offload *flow, char *nfp_action,
static int
nfp_fl_pedit(const struct flow_action_entry *act,
- struct tc_cls_flower_offload *flow, char *nfp_action, int *a_len,
- u32 *csum_updated, struct nfp_flower_pedit_acts *set_act)
+ struct flow_cls_offload *flow, char *nfp_action, int *a_len,
+ u32 *csum_updated, struct nfp_flower_pedit_acts *set_act,
+ struct netlink_ext_ack *extack)
{
enum flow_action_mangle_base htype;
u32 offset;
@@ -705,21 +783,22 @@ nfp_fl_pedit(const struct flow_action_entry *act,
switch (htype) {
case TCA_PEDIT_KEY_EX_HDR_TYPE_ETH:
- return nfp_fl_set_eth(act, offset, &set_act->set_eth);
+ return nfp_fl_set_eth(act, offset, &set_act->set_eth, extack);
case TCA_PEDIT_KEY_EX_HDR_TYPE_IP4:
return nfp_fl_set_ip4(act, offset, &set_act->set_ip_addr,
- &set_act->set_ip_ttl_tos);
+ &set_act->set_ip_ttl_tos, extack);
case TCA_PEDIT_KEY_EX_HDR_TYPE_IP6:
return nfp_fl_set_ip6(act, offset, &set_act->set_ip6_dst,
&set_act->set_ip6_src,
- &set_act->set_ip6_tc_hl_fl);
+ &set_act->set_ip6_tc_hl_fl, extack);
case TCA_PEDIT_KEY_EX_HDR_TYPE_TCP:
return nfp_fl_set_tport(act, offset, &set_act->set_tport,
- NFP_FL_ACTION_OPCODE_SET_TCP);
+ NFP_FL_ACTION_OPCODE_SET_TCP, extack);
case TCA_PEDIT_KEY_EX_HDR_TYPE_UDP:
return nfp_fl_set_tport(act, offset, &set_act->set_tport,
- NFP_FL_ACTION_OPCODE_SET_UDP);
+ NFP_FL_ACTION_OPCODE_SET_UDP, extack);
default:
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: pedit on unsupported header");
return -EOPNOTSUPP;
}
}
@@ -730,7 +809,8 @@ nfp_flower_output_action(struct nfp_app *app,
struct nfp_fl_payload *nfp_fl, int *a_len,
struct net_device *netdev, bool last,
enum nfp_flower_tun_type *tun_type, int *tun_out_cnt,
- int *out_cnt, u32 *csum_updated)
+ int *out_cnt, u32 *csum_updated,
+ struct netlink_ext_ack *extack)
{
struct nfp_flower_priv *priv = app->priv;
struct nfp_fl_output *output;
@@ -739,15 +819,19 @@ nfp_flower_output_action(struct nfp_app *app,
/* If csum_updated has not been reset by now, it means HW will
* incorrectly update csums when they are not requested.
*/
- if (*csum_updated)
+ if (*csum_updated) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: set actions without updating checksums are not supported");
return -EOPNOTSUPP;
+ }
- if (*a_len + sizeof(struct nfp_fl_output) > NFP_FL_MAX_A_SIZ)
+ if (*a_len + sizeof(struct nfp_fl_output) > NFP_FL_MAX_A_SIZ) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: mirred output increases action list size beyond the allowed maximum");
return -EOPNOTSUPP;
+ }
output = (struct nfp_fl_output *)&nfp_fl->action_data[*a_len];
err = nfp_fl_output(app, output, act, nfp_fl, last, netdev, *tun_type,
- tun_out_cnt);
+ tun_out_cnt, extack);
if (err)
return err;
@@ -757,11 +841,13 @@ nfp_flower_output_action(struct nfp_app *app,
/* nfp_fl_pre_lag returns -err or size of prelag action added.
* This will be 0 if it is not egressing to a lag dev.
*/
- prelag_size = nfp_fl_pre_lag(app, act, nfp_fl, *a_len);
- if (prelag_size < 0)
+ prelag_size = nfp_fl_pre_lag(app, act, nfp_fl, *a_len, extack);
+ if (prelag_size < 0) {
return prelag_size;
- else if (prelag_size > 0 && (!last || *out_cnt))
+ } else if (prelag_size > 0 && (!last || *out_cnt)) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: LAG action has to be last action in action list");
return -EOPNOTSUPP;
+ }
*a_len += prelag_size;
}
@@ -772,14 +858,15 @@ nfp_flower_output_action(struct nfp_app *app,
static int
nfp_flower_loop_action(struct nfp_app *app, const struct flow_action_entry *act,
- struct tc_cls_flower_offload *flow,
+ struct flow_cls_offload *flow,
struct nfp_fl_payload *nfp_fl, int *a_len,
struct net_device *netdev,
enum nfp_flower_tun_type *tun_type, int *tun_out_cnt,
int *out_cnt, u32 *csum_updated,
- struct nfp_flower_pedit_acts *set_act)
+ struct nfp_flower_pedit_acts *set_act,
+ struct netlink_ext_ack *extack, int act_idx)
{
- struct nfp_fl_set_ipv4_udp_tun *set_tun;
+ struct nfp_fl_set_ipv4_tun *set_tun;
struct nfp_fl_pre_tunnel *pre_tun;
struct nfp_fl_push_vlan *psh_v;
struct nfp_fl_pop_vlan *pop_v;
@@ -792,20 +879,23 @@ nfp_flower_loop_action(struct nfp_app *app, const struct flow_action_entry *act,
case FLOW_ACTION_REDIRECT:
err = nfp_flower_output_action(app, act, nfp_fl, a_len, netdev,
true, tun_type, tun_out_cnt,
- out_cnt, csum_updated);
+ out_cnt, csum_updated, extack);
if (err)
return err;
break;
case FLOW_ACTION_MIRRED:
err = nfp_flower_output_action(app, act, nfp_fl, a_len, netdev,
false, tun_type, tun_out_cnt,
- out_cnt, csum_updated);
+ out_cnt, csum_updated, extack);
if (err)
return err;
break;
case FLOW_ACTION_VLAN_POP:
- if (*a_len + sizeof(struct nfp_fl_pop_vlan) > NFP_FL_MAX_A_SIZ)
+ if (*a_len +
+ sizeof(struct nfp_fl_pop_vlan) > NFP_FL_MAX_A_SIZ) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: maximum allowed action list size exceeded at pop vlan");
return -EOPNOTSUPP;
+ }
pop_v = (struct nfp_fl_pop_vlan *)&nfp_fl->action_data[*a_len];
nfp_fl->meta.shortcut = cpu_to_be32(NFP_FL_SC_ACT_POPV);
@@ -814,8 +904,11 @@ nfp_flower_loop_action(struct nfp_app *app, const struct flow_action_entry *act,
*a_len += sizeof(struct nfp_fl_pop_vlan);
break;
case FLOW_ACTION_VLAN_PUSH:
- if (*a_len + sizeof(struct nfp_fl_push_vlan) > NFP_FL_MAX_A_SIZ)
+ if (*a_len +
+ sizeof(struct nfp_fl_push_vlan) > NFP_FL_MAX_A_SIZ) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: maximum allowed action list size exceeded at push vlan");
return -EOPNOTSUPP;
+ }
psh_v = (struct nfp_fl_push_vlan *)&nfp_fl->action_data[*a_len];
nfp_fl->meta.shortcut = cpu_to_be32(NFP_FL_SC_ACT_NULL);
@@ -826,35 +919,41 @@ nfp_flower_loop_action(struct nfp_app *app, const struct flow_action_entry *act,
case FLOW_ACTION_TUNNEL_ENCAP: {
const struct ip_tunnel_info *ip_tun = act->tunnel;
- *tun_type = nfp_fl_get_tun_from_act_l4_port(app, act);
- if (*tun_type == NFP_FL_TUNNEL_NONE)
+ *tun_type = nfp_fl_get_tun_from_act(app, flow, act, act_idx);
+ if (*tun_type == NFP_FL_TUNNEL_NONE) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: unsupported tunnel type in action list");
return -EOPNOTSUPP;
+ }
- if (ip_tun->mode & ~NFP_FL_SUPPORTED_TUNNEL_INFO_FLAGS)
+ if (ip_tun->mode & ~NFP_FL_SUPPORTED_TUNNEL_INFO_FLAGS) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: unsupported tunnel flags in action list");
return -EOPNOTSUPP;
+ }
/* Pre-tunnel action is required for tunnel encap.
* This checks for next hop entries on NFP.
* If none, the packet falls back before applying other actions.
*/
if (*a_len + sizeof(struct nfp_fl_pre_tunnel) +
- sizeof(struct nfp_fl_set_ipv4_udp_tun) > NFP_FL_MAX_A_SIZ)
+ sizeof(struct nfp_fl_set_ipv4_tun) > NFP_FL_MAX_A_SIZ) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: maximum allowed action list size exceeded at tunnel encap");
return -EOPNOTSUPP;
+ }
pre_tun = nfp_fl_pre_tunnel(nfp_fl->action_data, *a_len);
nfp_fl->meta.shortcut = cpu_to_be32(NFP_FL_SC_ACT_NULL);
*a_len += sizeof(struct nfp_fl_pre_tunnel);
- err = nfp_fl_push_geneve_options(nfp_fl, a_len, act);
+ err = nfp_fl_push_geneve_options(nfp_fl, a_len, act, extack);
if (err)
return err;
set_tun = (void *)&nfp_fl->action_data[*a_len];
- err = nfp_fl_set_ipv4_udp_tun(app, set_tun, act, pre_tun,
- *tun_type, netdev);
+ err = nfp_fl_set_ipv4_tun(app, set_tun, act, pre_tun,
+ *tun_type, netdev, extack);
if (err)
return err;
- *a_len += sizeof(struct nfp_fl_set_ipv4_udp_tun);
+ *a_len += sizeof(struct nfp_fl_set_ipv4_tun);
}
break;
case FLOW_ACTION_TUNNEL_DECAP:
@@ -862,13 +961,15 @@ nfp_flower_loop_action(struct nfp_app *app, const struct flow_action_entry *act,
return 0;
case FLOW_ACTION_MANGLE:
if (nfp_fl_pedit(act, flow, &nfp_fl->action_data[*a_len],
- a_len, csum_updated, set_act))
+ a_len, csum_updated, set_act, extack))
return -EOPNOTSUPP;
break;
case FLOW_ACTION_CSUM:
/* csum action requests recalc of something we have not fixed */
- if (act->csum_flags & ~*csum_updated)
+ if (act->csum_flags & ~*csum_updated) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: unsupported csum update action in action list");
return -EOPNOTSUPP;
+ }
/* If we will correctly fix the csum we can remove it from the
* csum update list. Which will later be used to check support.
*/
@@ -876,6 +977,7 @@ nfp_flower_loop_action(struct nfp_app *app, const struct flow_action_entry *act,
break;
default:
/* Currently we do not handle any other actions. */
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: unsupported action in action list");
return -EOPNOTSUPP;
}
@@ -919,9 +1021,10 @@ static bool nfp_fl_check_mangle_end(struct flow_action *flow_act,
}
int nfp_flower_compile_action(struct nfp_app *app,
- struct tc_cls_flower_offload *flow,
+ struct flow_cls_offload *flow,
struct net_device *netdev,
- struct nfp_fl_payload *nfp_flow)
+ struct nfp_fl_payload *nfp_flow,
+ struct netlink_ext_ack *extack)
{
int act_len, act_cnt, err, tun_out_cnt, out_cnt, i;
struct nfp_flower_pedit_acts set_act;
@@ -942,7 +1045,8 @@ int nfp_flower_compile_action(struct nfp_app *app,
memset(&set_act, 0, sizeof(set_act));
err = nfp_flower_loop_action(app, act, flow, nfp_flow, &act_len,
netdev, &tun_type, &tun_out_cnt,
- &out_cnt, &csum_updated, &set_act);
+ &out_cnt, &csum_updated,
+ &set_act, extack, i);
if (err)
return err;
act_cnt++;
diff --git a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h
index 537f7fc19584..0f1706ae5bfc 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h
+++ b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h
@@ -8,6 +8,7 @@
#include <linux/skbuff.h>
#include <linux/types.h>
#include <net/geneve.h>
+#include <net/gre.h>
#include <net/vxlan.h>
#include "../nfp_app.h"
@@ -22,6 +23,7 @@
#define NFP_FLOWER_LAYER_CT BIT(6)
#define NFP_FLOWER_LAYER_VXLAN BIT(7)
+#define NFP_FLOWER_LAYER2_GRE BIT(0)
#define NFP_FLOWER_LAYER2_GENEVE BIT(5)
#define NFP_FLOWER_LAYER2_GENEVE_OP BIT(6)
@@ -37,6 +39,9 @@
#define NFP_FL_IP_FRAG_FIRST BIT(7)
#define NFP_FL_IP_FRAGMENTED BIT(6)
+/* GRE Tunnel flags */
+#define NFP_FL_GRE_FLAG_KEY BIT(2)
+
/* Compressed HW representation of TCP Flags */
#define NFP_FL_TCP_FLAG_URG BIT(4)
#define NFP_FL_TCP_FLAG_PSH BIT(3)
@@ -107,6 +112,7 @@
enum nfp_flower_tun_type {
NFP_FL_TUNNEL_NONE = 0,
+ NFP_FL_TUNNEL_GRE = 1,
NFP_FL_TUNNEL_VXLAN = 2,
NFP_FL_TUNNEL_GENEVE = 4,
};
@@ -203,7 +209,7 @@ struct nfp_fl_pre_tunnel {
__be32 extra[3];
};
-struct nfp_fl_set_ipv4_udp_tun {
+struct nfp_fl_set_ipv4_tun {
struct nfp_fl_act_head head;
__be16 reserved;
__be64 tun_id __packed;
@@ -354,6 +360,16 @@ struct nfp_flower_ipv6 {
struct in6_addr ipv6_dst;
};
+struct nfp_flower_tun_ipv4 {
+ __be32 src;
+ __be32 dst;
+};
+
+struct nfp_flower_tun_ip_ext {
+ u8 tos;
+ u8 ttl;
+};
+
/* Flow Frame IPv4 UDP TUNNEL --> Tunnel details (4W/16B)
* -----------------------------------------------------------------
* 3 2 1
@@ -371,15 +387,42 @@ struct nfp_flower_ipv6 {
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
struct nfp_flower_ipv4_udp_tun {
- __be32 ip_src;
- __be32 ip_dst;
+ struct nfp_flower_tun_ipv4 ipv4;
__be16 reserved1;
- u8 tos;
- u8 ttl;
+ struct nfp_flower_tun_ip_ext ip_ext;
__be32 reserved2;
__be32 tun_id;
};
+/* Flow Frame GRE TUNNEL --> Tunnel details (6W/24B)
+ * -----------------------------------------------------------------
+ * 3 2 1
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | ipv4_addr_src |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | ipv4_addr_dst |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | tun_flags | tos | ttl |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Reserved | Ethertype |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Key |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Reserved |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+struct nfp_flower_ipv4_gre_tun {
+ struct nfp_flower_tun_ipv4 ipv4;
+ __be16 tun_flags;
+ struct nfp_flower_tun_ip_ext ip_ext;
+ __be16 reserved1;
+ __be16 ethertype;
+ __be32 tun_key;
+ __be32 reserved2;
+};
+
struct nfp_flower_geneve_options {
u8 data[NFP_FL_MAX_GENEVE_OPT_KEY];
};
@@ -530,6 +573,8 @@ nfp_fl_netdev_is_tunnel_type(struct net_device *netdev,
{
if (netif_is_vxlan(netdev))
return tun_type == NFP_FL_TUNNEL_VXLAN;
+ if (netif_is_gretap(netdev))
+ return tun_type == NFP_FL_TUNNEL_GRE;
if (netif_is_geneve(netdev))
return tun_type == NFP_FL_TUNNEL_GENEVE;
@@ -546,6 +591,8 @@ static inline bool nfp_fl_is_netdev_to_offload(struct net_device *netdev)
return true;
if (netif_is_geneve(netdev))
return true;
+ if (netif_is_gretap(netdev))
+ return true;
return false;
}
diff --git a/drivers/net/ethernet/netronome/nfp/flower/lag_conf.c b/drivers/net/ethernet/netronome/nfp/flower/lag_conf.c
index 5db838f45694..63907aeb3884 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/lag_conf.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/lag_conf.c
@@ -156,7 +156,8 @@ nfp_fl_lag_find_group_for_master_with_lag(struct nfp_fl_lag *lag,
int nfp_flower_lag_populate_pre_action(struct nfp_app *app,
struct net_device *master,
- struct nfp_fl_pre_lag *pre_act)
+ struct nfp_fl_pre_lag *pre_act,
+ struct netlink_ext_ack *extack)
{
struct nfp_flower_priv *priv = app->priv;
struct nfp_fl_lag_group *group = NULL;
@@ -167,6 +168,7 @@ int nfp_flower_lag_populate_pre_action(struct nfp_app *app,
master);
if (!group) {
mutex_unlock(&priv->nfp_lag.lock);
+ NL_SET_ERR_MSG_MOD(extack, "invalid entry: group does not exist for LAG action");
return -ENOENT;
}
diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.h b/drivers/net/ethernet/netronome/nfp/flower/main.h
index 40957a8dbfe6..af9441d5787f 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/main.h
+++ b/drivers/net/ethernet/netronome/nfp/flower/main.h
@@ -343,19 +343,22 @@ int nfp_flower_merge_offloaded_flows(struct nfp_app *app,
struct nfp_fl_payload *sub_flow1,
struct nfp_fl_payload *sub_flow2);
int nfp_flower_compile_flow_match(struct nfp_app *app,
- struct tc_cls_flower_offload *flow,
+ struct flow_cls_offload *flow,
struct nfp_fl_key_ls *key_ls,
struct net_device *netdev,
struct nfp_fl_payload *nfp_flow,
- enum nfp_flower_tun_type tun_type);
+ enum nfp_flower_tun_type tun_type,
+ struct netlink_ext_ack *extack);
int nfp_flower_compile_action(struct nfp_app *app,
- struct tc_cls_flower_offload *flow,
+ struct flow_cls_offload *flow,
struct net_device *netdev,
- struct nfp_fl_payload *nfp_flow);
+ struct nfp_fl_payload *nfp_flow,
+ struct netlink_ext_ack *extack);
int nfp_compile_flow_metadata(struct nfp_app *app,
- struct tc_cls_flower_offload *flow,
+ struct flow_cls_offload *flow,
struct nfp_fl_payload *nfp_flow,
- struct net_device *netdev);
+ struct net_device *netdev,
+ struct netlink_ext_ack *extack);
void __nfp_modify_flow_metadata(struct nfp_flower_priv *priv,
struct nfp_fl_payload *nfp_flow);
int nfp_modify_flow_metadata(struct nfp_app *app,
@@ -389,7 +392,8 @@ int nfp_flower_lag_netdev_event(struct nfp_flower_priv *priv,
bool nfp_flower_lag_unprocessed_msg(struct nfp_app *app, struct sk_buff *skb);
int nfp_flower_lag_populate_pre_action(struct nfp_app *app,
struct net_device *master,
- struct nfp_fl_pre_lag *pre_act);
+ struct nfp_fl_pre_lag *pre_act,
+ struct netlink_ext_ack *extack);
int nfp_flower_lag_get_output_id(struct nfp_app *app,
struct net_device *master);
void nfp_flower_qos_init(struct nfp_app *app);
diff --git a/drivers/net/ethernet/netronome/nfp/flower/match.c b/drivers/net/ethernet/netronome/nfp/flower/match.c
index bfa4bf34911d..9cc3ba17ff69 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/match.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/match.c
@@ -10,9 +10,9 @@
static void
nfp_flower_compile_meta_tci(struct nfp_flower_meta_tci *ext,
struct nfp_flower_meta_tci *msk,
- struct tc_cls_flower_offload *flow, u8 key_type)
+ struct flow_cls_offload *flow, u8 key_type)
{
- struct flow_rule *rule = tc_cls_flower_offload_flow_rule(flow);
+ struct flow_rule *rule = flow_cls_offload_flow_rule(flow);
u16 tmp_tci;
memset(ext, 0, sizeof(struct nfp_flower_meta_tci));
@@ -54,7 +54,8 @@ nfp_flower_compile_ext_meta(struct nfp_flower_ext_meta *frame, u32 key_ext)
static int
nfp_flower_compile_port(struct nfp_flower_in_port *frame, u32 cmsg_port,
- bool mask_version, enum nfp_flower_tun_type tun_type)
+ bool mask_version, enum nfp_flower_tun_type tun_type,
+ struct netlink_ext_ack *extack)
{
if (mask_version) {
frame->in_port = cpu_to_be32(~0);
@@ -64,8 +65,10 @@ nfp_flower_compile_port(struct nfp_flower_in_port *frame, u32 cmsg_port,
if (tun_type) {
frame->in_port = cpu_to_be32(NFP_FL_PORT_TYPE_TUN | tun_type);
} else {
- if (!cmsg_port)
+ if (!cmsg_port) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: invalid ingress interface for match offload");
return -EOPNOTSUPP;
+ }
frame->in_port = cpu_to_be32(cmsg_port);
}
@@ -75,9 +78,9 @@ nfp_flower_compile_port(struct nfp_flower_in_port *frame, u32 cmsg_port,
static void
nfp_flower_compile_mac(struct nfp_flower_mac_mpls *ext,
struct nfp_flower_mac_mpls *msk,
- struct tc_cls_flower_offload *flow)
+ struct flow_cls_offload *flow)
{
- struct flow_rule *rule = tc_cls_flower_offload_flow_rule(flow);
+ struct flow_rule *rule = flow_cls_offload_flow_rule(flow);
memset(ext, 0, sizeof(struct nfp_flower_mac_mpls));
memset(msk, 0, sizeof(struct nfp_flower_mac_mpls));
@@ -127,9 +130,9 @@ nfp_flower_compile_mac(struct nfp_flower_mac_mpls *ext,
static void
nfp_flower_compile_tport(struct nfp_flower_tp_ports *ext,
struct nfp_flower_tp_ports *msk,
- struct tc_cls_flower_offload *flow)
+ struct flow_cls_offload *flow)
{
- struct flow_rule *rule = tc_cls_flower_offload_flow_rule(flow);
+ struct flow_rule *rule = flow_cls_offload_flow_rule(flow);
memset(ext, 0, sizeof(struct nfp_flower_tp_ports));
memset(msk, 0, sizeof(struct nfp_flower_tp_ports));
@@ -148,9 +151,9 @@ nfp_flower_compile_tport(struct nfp_flower_tp_ports *ext,
static void
nfp_flower_compile_ip_ext(struct nfp_flower_ip_ext *ext,
struct nfp_flower_ip_ext *msk,
- struct tc_cls_flower_offload *flow)
+ struct flow_cls_offload *flow)
{
- struct flow_rule *rule = tc_cls_flower_offload_flow_rule(flow);
+ struct flow_rule *rule = flow_cls_offload_flow_rule(flow);
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
struct flow_match_basic match;
@@ -222,9 +225,9 @@ nfp_flower_compile_ip_ext(struct nfp_flower_ip_ext *ext,
static void
nfp_flower_compile_ipv4(struct nfp_flower_ipv4 *ext,
struct nfp_flower_ipv4 *msk,
- struct tc_cls_flower_offload *flow)
+ struct flow_cls_offload *flow)
{
- struct flow_rule *rule = tc_cls_flower_offload_flow_rule(flow);
+ struct flow_rule *rule = flow_cls_offload_flow_rule(flow);
struct flow_match_ipv4_addrs match;
memset(ext, 0, sizeof(struct nfp_flower_ipv4));
@@ -244,9 +247,9 @@ nfp_flower_compile_ipv4(struct nfp_flower_ipv4 *ext,
static void
nfp_flower_compile_ipv6(struct nfp_flower_ipv6 *ext,
struct nfp_flower_ipv6 *msk,
- struct tc_cls_flower_offload *flow)
+ struct flow_cls_offload *flow)
{
- struct flow_rule *rule = tc_cls_flower_offload_flow_rule(flow);
+ struct flow_rule *rule = flow_cls_offload_flow_rule(flow);
memset(ext, 0, sizeof(struct nfp_flower_ipv6));
memset(msk, 0, sizeof(struct nfp_flower_ipv6));
@@ -266,7 +269,7 @@ nfp_flower_compile_ipv6(struct nfp_flower_ipv6 *ext,
static int
nfp_flower_compile_geneve_opt(void *ext, void *msk,
- struct tc_cls_flower_offload *flow)
+ struct flow_cls_offload *flow)
{
struct flow_match_enc_opts match;
@@ -278,11 +281,76 @@ nfp_flower_compile_geneve_opt(void *ext, void *msk,
}
static void
+nfp_flower_compile_tun_ipv4_addrs(struct nfp_flower_tun_ipv4 *ext,
+ struct nfp_flower_tun_ipv4 *msk,
+ struct flow_cls_offload *flow)
+{
+ struct flow_rule *rule = flow_cls_offload_flow_rule(flow);
+
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS)) {
+ struct flow_match_ipv4_addrs match;
+
+ flow_rule_match_enc_ipv4_addrs(rule, &match);
+ ext->src = match.key->src;
+ ext->dst = match.key->dst;
+ msk->src = match.mask->src;
+ msk->dst = match.mask->dst;
+ }
+}
+
+static void
+nfp_flower_compile_tun_ip_ext(struct nfp_flower_tun_ip_ext *ext,
+ struct nfp_flower_tun_ip_ext *msk,
+ struct flow_cls_offload *flow)
+{
+ struct flow_rule *rule = flow_cls_offload_flow_rule(flow);
+
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_IP)) {
+ struct flow_match_ip match;
+
+ flow_rule_match_enc_ip(rule, &match);
+ ext->tos = match.key->tos;
+ ext->ttl = match.key->ttl;
+ msk->tos = match.mask->tos;
+ msk->ttl = match.mask->ttl;
+ }
+}
+
+static void
+nfp_flower_compile_ipv4_gre_tun(struct nfp_flower_ipv4_gre_tun *ext,
+ struct nfp_flower_ipv4_gre_tun *msk,
+ struct flow_cls_offload *flow)
+{
+ struct flow_rule *rule = flow_cls_offload_flow_rule(flow);
+
+ memset(ext, 0, sizeof(struct nfp_flower_ipv4_gre_tun));
+ memset(msk, 0, sizeof(struct nfp_flower_ipv4_gre_tun));
+
+ /* NVGRE is the only supported GRE tunnel type */
+ ext->ethertype = cpu_to_be16(ETH_P_TEB);
+ msk->ethertype = cpu_to_be16(~0);
+
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
+ struct flow_match_enc_keyid match;
+
+ flow_rule_match_enc_keyid(rule, &match);
+ ext->tun_key = match.key->keyid;
+ msk->tun_key = match.mask->keyid;
+
+ ext->tun_flags = cpu_to_be16(NFP_FL_GRE_FLAG_KEY);
+ msk->tun_flags = cpu_to_be16(NFP_FL_GRE_FLAG_KEY);
+ }
+
+ nfp_flower_compile_tun_ipv4_addrs(&ext->ipv4, &msk->ipv4, flow);
+ nfp_flower_compile_tun_ip_ext(&ext->ip_ext, &msk->ip_ext, flow);
+}
+
+static void
nfp_flower_compile_ipv4_udp_tun(struct nfp_flower_ipv4_udp_tun *ext,
struct nfp_flower_ipv4_udp_tun *msk,
- struct tc_cls_flower_offload *flow)
+ struct flow_cls_offload *flow)
{
- struct flow_rule *rule = tc_cls_flower_offload_flow_rule(flow);
+ struct flow_rule *rule = flow_cls_offload_flow_rule(flow);
memset(ext, 0, sizeof(struct nfp_flower_ipv4_udp_tun));
memset(msk, 0, sizeof(struct nfp_flower_ipv4_udp_tun));
@@ -298,33 +366,17 @@ nfp_flower_compile_ipv4_udp_tun(struct nfp_flower_ipv4_udp_tun *ext,
msk->tun_id = cpu_to_be32(temp_vni);
}
- if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS)) {
- struct flow_match_ipv4_addrs match;
-
- flow_rule_match_enc_ipv4_addrs(rule, &match);
- ext->ip_src = match.key->src;
- ext->ip_dst = match.key->dst;
- msk->ip_src = match.mask->src;
- msk->ip_dst = match.mask->dst;
- }
-
- if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_IP)) {
- struct flow_match_ip match;
-
- flow_rule_match_enc_ip(rule, &match);
- ext->tos = match.key->tos;
- ext->ttl = match.key->ttl;
- msk->tos = match.mask->tos;
- msk->ttl = match.mask->ttl;
- }
+ nfp_flower_compile_tun_ipv4_addrs(&ext->ipv4, &msk->ipv4, flow);
+ nfp_flower_compile_tun_ip_ext(&ext->ip_ext, &msk->ip_ext, flow);
}
int nfp_flower_compile_flow_match(struct nfp_app *app,
- struct tc_cls_flower_offload *flow,
+ struct flow_cls_offload *flow,
struct nfp_fl_key_ls *key_ls,
struct net_device *netdev,
struct nfp_fl_payload *nfp_flow,
- enum nfp_flower_tun_type tun_type)
+ enum nfp_flower_tun_type tun_type,
+ struct netlink_ext_ack *extack)
{
u32 port_id;
int err;
@@ -357,13 +409,13 @@ int nfp_flower_compile_flow_match(struct nfp_app *app,
/* Populate Exact Port data. */
err = nfp_flower_compile_port((struct nfp_flower_in_port *)ext,
- port_id, false, tun_type);
+ port_id, false, tun_type, extack);
if (err)
return err;
/* Populate Mask Port Data. */
err = nfp_flower_compile_port((struct nfp_flower_in_port *)msk,
- port_id, true, tun_type);
+ port_id, true, tun_type, extack);
if (err)
return err;
@@ -402,12 +454,27 @@ int nfp_flower_compile_flow_match(struct nfp_app *app,
msk += sizeof(struct nfp_flower_ipv6);
}
+ if (key_ls->key_layer_two & NFP_FLOWER_LAYER2_GRE) {
+ __be32 tun_dst;
+
+ nfp_flower_compile_ipv4_gre_tun((void *)ext, (void *)msk, flow);
+ tun_dst = ((struct nfp_flower_ipv4_gre_tun *)ext)->ipv4.dst;
+ ext += sizeof(struct nfp_flower_ipv4_gre_tun);
+ msk += sizeof(struct nfp_flower_ipv4_gre_tun);
+
+ /* Store the tunnel destination in the rule data.
+ * This must be present and be an exact match.
+ */
+ nfp_flow->nfp_tun_ipv4_addr = tun_dst;
+ nfp_tunnel_add_ipv4_off(app, tun_dst);
+ }
+
if (key_ls->key_layer & NFP_FLOWER_LAYER_VXLAN ||
key_ls->key_layer_two & NFP_FLOWER_LAYER2_GENEVE) {
__be32 tun_dst;
nfp_flower_compile_ipv4_udp_tun((void *)ext, (void *)msk, flow);
- tun_dst = ((struct nfp_flower_ipv4_udp_tun *)ext)->ip_dst;
+ tun_dst = ((struct nfp_flower_ipv4_udp_tun *)ext)->ipv4.dst;
ext += sizeof(struct nfp_flower_ipv4_udp_tun);
msk += sizeof(struct nfp_flower_ipv4_udp_tun);
diff --git a/drivers/net/ethernet/netronome/nfp/flower/metadata.c b/drivers/net/ethernet/netronome/nfp/flower/metadata.c
index 3d326efdc814..7c4a15e967df 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/metadata.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/metadata.c
@@ -290,9 +290,10 @@ nfp_check_mask_remove(struct nfp_app *app, char *mask_data, u32 mask_len,
}
int nfp_compile_flow_metadata(struct nfp_app *app,
- struct tc_cls_flower_offload *flow,
+ struct flow_cls_offload *flow,
struct nfp_fl_payload *nfp_flow,
- struct net_device *netdev)
+ struct net_device *netdev,
+ struct netlink_ext_ack *extack)
{
struct nfp_fl_stats_ctx_to_flow *ctx_entry;
struct nfp_flower_priv *priv = app->priv;
@@ -302,8 +303,10 @@ int nfp_compile_flow_metadata(struct nfp_app *app,
int err;
err = nfp_get_stats_entry(app, &stats_cxt);
- if (err)
+ if (err) {
+ NL_SET_ERR_MSG_MOD(extack, "invalid entry: cannot allocate new stats context");
return err;
+ }
nfp_flow->meta.host_ctx_id = cpu_to_be32(stats_cxt);
nfp_flow->meta.host_cookie = cpu_to_be64(flow->cookie);
@@ -328,6 +331,12 @@ int nfp_compile_flow_metadata(struct nfp_app *app,
if (!nfp_check_mask_add(app, nfp_flow->mask_data,
nfp_flow->meta.mask_len,
&nfp_flow->meta.flags, &new_mask_id)) {
+ NL_SET_ERR_MSG_MOD(extack, "invalid entry: cannot allocate a new mask id");
+ if (nfp_release_stats_entry(app, stats_cxt)) {
+ NL_SET_ERR_MSG_MOD(extack, "invalid entry: cannot release stats context");
+ err = -EINVAL;
+ goto err_remove_rhash;
+ }
err = -ENOENT;
goto err_remove_rhash;
}
@@ -343,6 +352,21 @@ int nfp_compile_flow_metadata(struct nfp_app *app,
check_entry = nfp_flower_search_fl_table(app, flow->cookie, netdev);
if (check_entry) {
+ NL_SET_ERR_MSG_MOD(extack, "invalid entry: cannot offload duplicate flow entry");
+ if (nfp_release_stats_entry(app, stats_cxt)) {
+ NL_SET_ERR_MSG_MOD(extack, "invalid entry: cannot release stats context");
+ err = -EINVAL;
+ goto err_remove_mask;
+ }
+
+ if (!nfp_check_mask_remove(app, nfp_flow->mask_data,
+ nfp_flow->meta.mask_len,
+ NULL, &new_mask_id)) {
+ NL_SET_ERR_MSG_MOD(extack, "invalid entry: cannot release mask id");
+ err = -EINVAL;
+ goto err_remove_mask;
+ }
+
err = -EEXIST;
goto err_remove_mask;
}
diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c
index 1fbfeb43c538..faa8ba012a37 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/offload.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c
@@ -52,8 +52,7 @@
#define NFP_FLOWER_WHITELIST_TUN_DISSECTOR_R \
(BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL) | \
- BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) | \
- BIT(FLOW_DISSECTOR_KEY_ENC_PORTS))
+ BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS))
#define NFP_FLOWER_MERGE_FIELDS \
(NFP_FLOWER_LAYER_PORT | \
@@ -122,9 +121,9 @@ nfp_flower_xmit_flow(struct nfp_app *app, struct nfp_fl_payload *nfp_flow,
return 0;
}
-static bool nfp_flower_check_higher_than_mac(struct tc_cls_flower_offload *f)
+static bool nfp_flower_check_higher_than_mac(struct flow_cls_offload *f)
{
- struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
+ struct flow_rule *rule = flow_cls_offload_flow_rule(f);
return flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) ||
flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) ||
@@ -132,14 +131,25 @@ static bool nfp_flower_check_higher_than_mac(struct tc_cls_flower_offload *f)
flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ICMP);
}
+static bool nfp_flower_check_higher_than_l3(struct flow_cls_offload *f)
+{
+ struct flow_rule *rule = flow_cls_offload_flow_rule(f);
+
+ return flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS) ||
+ flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ICMP);
+}
+
static int
-nfp_flower_calc_opt_layer(struct flow_match_enc_opts *enc_opts,
- u32 *key_layer_two, int *key_size)
+nfp_flower_calc_opt_layer(struct flow_dissector_key_enc_opts *enc_opts,
+ u32 *key_layer_two, int *key_size,
+ struct netlink_ext_ack *extack)
{
- if (enc_opts->key->len > NFP_FL_MAX_GENEVE_OPT_KEY)
+ if (enc_opts->len > NFP_FL_MAX_GENEVE_OPT_KEY) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: geneve options exceed maximum length");
return -EOPNOTSUPP;
+ }
- if (enc_opts->key->len > 0) {
+ if (enc_opts->len > 0) {
*key_layer_two |= NFP_FLOWER_LAYER2_GENEVE_OP;
*key_size += sizeof(struct nfp_flower_geneve_options);
}
@@ -148,13 +158,65 @@ nfp_flower_calc_opt_layer(struct flow_match_enc_opts *enc_opts,
}
static int
+nfp_flower_calc_udp_tun_layer(struct flow_dissector_key_ports *enc_ports,
+ struct flow_dissector_key_enc_opts *enc_op,
+ u32 *key_layer_two, u8 *key_layer, int *key_size,
+ struct nfp_flower_priv *priv,
+ enum nfp_flower_tun_type *tun_type,
+ struct netlink_ext_ack *extack)
+{
+ int err;
+
+ switch (enc_ports->dst) {
+ case htons(IANA_VXLAN_UDP_PORT):
+ *tun_type = NFP_FL_TUNNEL_VXLAN;
+ *key_layer |= NFP_FLOWER_LAYER_VXLAN;
+ *key_size += sizeof(struct nfp_flower_ipv4_udp_tun);
+
+ if (enc_op) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: encap options not supported on vxlan tunnels");
+ return -EOPNOTSUPP;
+ }
+ break;
+ case htons(GENEVE_UDP_PORT):
+ if (!(priv->flower_ext_feats & NFP_FL_FEATS_GENEVE)) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: loaded firmware does not support geneve offload");
+ return -EOPNOTSUPP;
+ }
+ *tun_type = NFP_FL_TUNNEL_GENEVE;
+ *key_layer |= NFP_FLOWER_LAYER_EXT_META;
+ *key_size += sizeof(struct nfp_flower_ext_meta);
+ *key_layer_two |= NFP_FLOWER_LAYER2_GENEVE;
+ *key_size += sizeof(struct nfp_flower_ipv4_udp_tun);
+
+ if (!enc_op)
+ break;
+ if (!(priv->flower_ext_feats & NFP_FL_FEATS_GENEVE_OPT)) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: loaded firmware does not support geneve option offload");
+ return -EOPNOTSUPP;
+ }
+ err = nfp_flower_calc_opt_layer(enc_op, key_layer_two,
+ key_size, extack);
+ if (err)
+ return err;
+ break;
+ default:
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: tunnel type unknown");
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int
nfp_flower_calculate_key_layers(struct nfp_app *app,
struct net_device *netdev,
struct nfp_fl_key_ls *ret_key_ls,
- struct tc_cls_flower_offload *flow,
- enum nfp_flower_tun_type *tun_type)
+ struct flow_cls_offload *flow,
+ enum nfp_flower_tun_type *tun_type,
+ struct netlink_ext_ack *extack)
{
- struct flow_rule *rule = tc_cls_flower_offload_flow_rule(flow);
+ struct flow_rule *rule = flow_cls_offload_flow_rule(flow);
struct flow_dissector *dissector = rule->match.dissector;
struct flow_match_basic basic = { NULL, NULL};
struct nfp_flower_priv *priv = app->priv;
@@ -163,14 +225,18 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
int key_size;
int err;
- if (dissector->used_keys & ~NFP_FLOWER_WHITELIST_DISSECTOR)
+ if (dissector->used_keys & ~NFP_FLOWER_WHITELIST_DISSECTOR) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: match not supported");
return -EOPNOTSUPP;
+ }
/* If any tun dissector is used then the required set must be used. */
if (dissector->used_keys & NFP_FLOWER_WHITELIST_TUN_DISSECTOR &&
(dissector->used_keys & NFP_FLOWER_WHITELIST_TUN_DISSECTOR_R)
- != NFP_FLOWER_WHITELIST_TUN_DISSECTOR_R)
+ != NFP_FLOWER_WHITELIST_TUN_DISSECTOR_R) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: tunnel match not supported");
return -EOPNOTSUPP;
+ }
key_layer_two = 0;
key_layer = NFP_FLOWER_LAYER_PORT;
@@ -188,8 +254,10 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
flow_rule_match_vlan(rule, &vlan);
if (!(priv->flower_ext_feats & NFP_FL_FEATS_VLAN_PCP) &&
- vlan.key->vlan_priority)
+ vlan.key->vlan_priority) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: loaded firmware does not support VLAN PCP offload");
return -EOPNOTSUPP;
+ }
}
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_CONTROL)) {
@@ -200,56 +268,68 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
flow_rule_match_enc_control(rule, &enc_ctl);
- if (enc_ctl.mask->addr_type != 0xffff ||
- enc_ctl.key->addr_type != FLOW_DISSECTOR_KEY_IPV4_ADDRS)
+ if (enc_ctl.mask->addr_type != 0xffff) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: wildcarded protocols on tunnels are not supported");
+ return -EOPNOTSUPP;
+ }
+ if (enc_ctl.key->addr_type != FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: only IPv4 tunnels are supported");
return -EOPNOTSUPP;
+ }
/* These fields are already verified as used. */
flow_rule_match_enc_ipv4_addrs(rule, &ipv4_addrs);
- if (ipv4_addrs.mask->dst != cpu_to_be32(~0))
- return -EOPNOTSUPP;
-
- flow_rule_match_enc_ports(rule, &enc_ports);
- if (enc_ports.mask->dst != cpu_to_be16(~0))
+ if (ipv4_addrs.mask->dst != cpu_to_be32(~0)) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: only an exact match IPv4 destination address is supported");
return -EOPNOTSUPP;
+ }
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_OPTS))
flow_rule_match_enc_opts(rule, &enc_op);
- switch (enc_ports.key->dst) {
- case htons(IANA_VXLAN_UDP_PORT):
- *tun_type = NFP_FL_TUNNEL_VXLAN;
- key_layer |= NFP_FLOWER_LAYER_VXLAN;
- key_size += sizeof(struct nfp_flower_ipv4_udp_tun);
- if (enc_op.key)
+ if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_PORTS)) {
+ /* check if GRE, which has no enc_ports */
+ if (netif_is_gretap(netdev)) {
+ *tun_type = NFP_FL_TUNNEL_GRE;
+ key_layer |= NFP_FLOWER_LAYER_EXT_META;
+ key_size += sizeof(struct nfp_flower_ext_meta);
+ key_layer_two |= NFP_FLOWER_LAYER2_GRE;
+ key_size +=
+ sizeof(struct nfp_flower_ipv4_gre_tun);
+
+ if (enc_op.key) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: encap options not supported on GRE tunnels");
+ return -EOPNOTSUPP;
+ }
+ } else {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: an exact match on L4 destination port is required for non-GRE tunnels");
return -EOPNOTSUPP;
- break;
- case htons(GENEVE_UDP_PORT):
- if (!(priv->flower_ext_feats & NFP_FL_FEATS_GENEVE))
+ }
+ } else {
+ flow_rule_match_enc_ports(rule, &enc_ports);
+ if (enc_ports.mask->dst != cpu_to_be16(~0)) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: only an exact match L4 destination port is supported");
return -EOPNOTSUPP;
- *tun_type = NFP_FL_TUNNEL_GENEVE;
- key_layer |= NFP_FLOWER_LAYER_EXT_META;
- key_size += sizeof(struct nfp_flower_ext_meta);
- key_layer_two |= NFP_FLOWER_LAYER2_GENEVE;
- key_size += sizeof(struct nfp_flower_ipv4_udp_tun);
+ }
- if (!enc_op.key)
- break;
- if (!(priv->flower_ext_feats & NFP_FL_FEATS_GENEVE_OPT))
- return -EOPNOTSUPP;
- err = nfp_flower_calc_opt_layer(&enc_op, &key_layer_two,
- &key_size);
+ err = nfp_flower_calc_udp_tun_layer(enc_ports.key,
+ enc_op.key,
+ &key_layer_two,
+ &key_layer,
+ &key_size, priv,
+ tun_type, extack);
if (err)
return err;
- break;
- default:
- return -EOPNOTSUPP;
- }
- /* Ensure the ingress netdev matches the expected tun type. */
- if (!nfp_fl_netdev_is_tunnel_type(netdev, *tun_type))
- return -EOPNOTSUPP;
+ /* Ensure the ingress netdev matches the expected
+ * tun type.
+ */
+ if (!nfp_fl_netdev_is_tunnel_type(netdev, *tun_type)) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: ingress netdev does not match the expected tunnel type");
+ return -EOPNOTSUPP;
+ }
+ }
}
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC))
@@ -272,6 +352,7 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
* because we rely on it to get to the host.
*/
case cpu_to_be16(ETH_P_ARP):
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: ARP not supported");
return -EOPNOTSUPP;
case cpu_to_be16(ETH_P_MPLS_UC):
@@ -287,17 +368,15 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
break;
default:
- /* Other ethtype - we need check the masks for the
- * remainder of the key to ensure we can offload.
- */
- if (nfp_flower_check_higher_than_mac(flow))
- return -EOPNOTSUPP;
- break;
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: match on given EtherType is not supported");
+ return -EOPNOTSUPP;
}
+ } else if (nfp_flower_check_higher_than_mac(flow)) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: cannot match above L2 without specified EtherType");
+ return -EOPNOTSUPP;
}
if (basic.mask && basic.mask->ip_proto) {
- /* Ethernet type is present in the key. */
switch (basic.key->ip_proto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
@@ -307,14 +386,15 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
key_layer |= NFP_FLOWER_LAYER_TP;
key_size += sizeof(struct nfp_flower_tp_ports);
break;
- default:
- /* Other ip proto - we need check the masks for the
- * remainder of the key to ensure we can offload.
- */
- return -EOPNOTSUPP;
}
}
+ if (!(key_layer & NFP_FLOWER_LAYER_TP) &&
+ nfp_flower_check_higher_than_l3(flow)) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: cannot match on L4 information without specified IP protocol type");
+ return -EOPNOTSUPP;
+ }
+
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_TCP)) {
struct flow_match_tcp tcp;
u32 tcp_flags;
@@ -322,22 +402,28 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
flow_rule_match_tcp(rule, &tcp);
tcp_flags = be16_to_cpu(tcp.key->flags);
- if (tcp_flags & ~NFP_FLOWER_SUPPORTED_TCPFLAGS)
+ if (tcp_flags & ~NFP_FLOWER_SUPPORTED_TCPFLAGS) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: no match support for selected TCP flags");
return -EOPNOTSUPP;
+ }
/* We only support PSH and URG flags when either
* FIN, SYN or RST is present as well.
*/
if ((tcp_flags & (TCPHDR_PSH | TCPHDR_URG)) &&
- !(tcp_flags & (TCPHDR_FIN | TCPHDR_SYN | TCPHDR_RST)))
+ !(tcp_flags & (TCPHDR_FIN | TCPHDR_SYN | TCPHDR_RST))) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: PSH and URG is only supported when used with FIN, SYN or RST");
return -EOPNOTSUPP;
+ }
/* We need to store TCP flags in the either the IPv4 or IPv6 key
* space, thus we need to ensure we include a IPv4/IPv6 key
* layer if we have not done so already.
*/
- if (!basic.key)
+ if (!basic.key) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: match on TCP flags requires a match on L3 protocol");
return -EOPNOTSUPP;
+ }
if (!(key_layer & NFP_FLOWER_LAYER_IPV4) &&
!(key_layer & NFP_FLOWER_LAYER_IPV6)) {
@@ -353,6 +439,7 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
break;
default:
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: match on TCP flags requires a match on IPv4/IPv6");
return -EOPNOTSUPP;
}
}
@@ -362,8 +449,10 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
struct flow_match_control ctl;
flow_rule_match_control(rule, &ctl);
- if (ctl.key->flags & ~NFP_FLOWER_SUPPORTED_CTLFLAGS)
+ if (ctl.key->flags & ~NFP_FLOWER_SUPPORTED_CTLFLAGS) {
+ NL_SET_ERR_MSG_MOD(extack, "unsupported offload: match on unknown control flag");
return -EOPNOTSUPP;
+ }
}
ret_key_ls->key_layer = key_layer;
@@ -771,14 +860,16 @@ int nfp_flower_merge_offloaded_flows(struct nfp_app *app,
struct nfp_fl_payload *sub_flow1,
struct nfp_fl_payload *sub_flow2)
{
- struct tc_cls_flower_offload merge_tc_off;
+ struct flow_cls_offload merge_tc_off;
struct nfp_flower_priv *priv = app->priv;
+ struct netlink_ext_ack *extack = NULL;
struct nfp_fl_payload *merge_flow;
struct nfp_fl_key_ls merge_key_ls;
int err;
ASSERT_RTNL();
+ extack = merge_tc_off.common.extack;
if (sub_flow1 == sub_flow2 ||
nfp_flower_is_merge_flow(sub_flow1) ||
nfp_flower_is_merge_flow(sub_flow2))
@@ -816,7 +907,7 @@ int nfp_flower_merge_offloaded_flows(struct nfp_app *app,
merge_tc_off.cookie = merge_flow->tc_flower_cookie;
err = nfp_compile_flow_metadata(app, &merge_tc_off, merge_flow,
- merge_flow->ingress_dev);
+ merge_flow->ingress_dev, extack);
if (err)
goto err_unlink_sub_flow2;
@@ -865,15 +956,17 @@ err_destroy_merge_flow:
*/
static int
nfp_flower_add_offload(struct nfp_app *app, struct net_device *netdev,
- struct tc_cls_flower_offload *flow)
+ struct flow_cls_offload *flow)
{
enum nfp_flower_tun_type tun_type = NFP_FL_TUNNEL_NONE;
struct nfp_flower_priv *priv = app->priv;
+ struct netlink_ext_ack *extack = NULL;
struct nfp_fl_payload *flow_pay;
struct nfp_fl_key_ls *key_layer;
struct nfp_port *port = NULL;
int err;
+ extack = flow->common.extack;
if (nfp_netdev_is_nfp_repr(netdev))
port = nfp_port_from_netdev(netdev);
@@ -882,7 +975,7 @@ nfp_flower_add_offload(struct nfp_app *app, struct net_device *netdev,
return -ENOMEM;
err = nfp_flower_calculate_key_layers(app, netdev, key_layer, flow,
- &tun_type);
+ &tun_type, extack);
if (err)
goto err_free_key_ls;
@@ -893,23 +986,25 @@ nfp_flower_add_offload(struct nfp_app *app, struct net_device *netdev,
}
err = nfp_flower_compile_flow_match(app, flow, key_layer, netdev,
- flow_pay, tun_type);
+ flow_pay, tun_type, extack);
if (err)
goto err_destroy_flow;
- err = nfp_flower_compile_action(app, flow, netdev, flow_pay);
+ err = nfp_flower_compile_action(app, flow, netdev, flow_pay, extack);
if (err)
goto err_destroy_flow;
- err = nfp_compile_flow_metadata(app, flow, flow_pay, netdev);
+ err = nfp_compile_flow_metadata(app, flow, flow_pay, netdev, extack);
if (err)
goto err_destroy_flow;
flow_pay->tc_flower_cookie = flow->cookie;
err = rhashtable_insert_fast(&priv->flow_table, &flow_pay->fl_node,
nfp_flower_table_params);
- if (err)
+ if (err) {
+ NL_SET_ERR_MSG_MOD(extack, "invalid entry: cannot insert flow into tables for offloads");
goto err_release_metadata;
+ }
err = nfp_flower_xmit_flow(app, flow_pay,
NFP_FLOWER_CMSG_TYPE_FLOW_ADD);
@@ -1024,19 +1119,23 @@ nfp_flower_del_linked_merge_flows(struct nfp_app *app,
*/
static int
nfp_flower_del_offload(struct nfp_app *app, struct net_device *netdev,
- struct tc_cls_flower_offload *flow)
+ struct flow_cls_offload *flow)
{
struct nfp_flower_priv *priv = app->priv;
+ struct netlink_ext_ack *extack = NULL;
struct nfp_fl_payload *nfp_flow;
struct nfp_port *port = NULL;
int err;
+ extack = flow->common.extack;
if (nfp_netdev_is_nfp_repr(netdev))
port = nfp_port_from_netdev(netdev);
nfp_flow = nfp_flower_search_fl_table(app, flow->cookie, netdev);
- if (!nfp_flow)
+ if (!nfp_flow) {
+ NL_SET_ERR_MSG_MOD(extack, "invalid entry: cannot remove flow that does not exist");
return -ENOENT;
+ }
err = nfp_modify_flow_metadata(app, nfp_flow);
if (err)
@@ -1127,15 +1226,19 @@ nfp_flower_update_merge_stats(struct nfp_app *app,
*/
static int
nfp_flower_get_stats(struct nfp_app *app, struct net_device *netdev,
- struct tc_cls_flower_offload *flow)
+ struct flow_cls_offload *flow)
{
struct nfp_flower_priv *priv = app->priv;
+ struct netlink_ext_ack *extack = NULL;
struct nfp_fl_payload *nfp_flow;
u32 ctx_id;
+ extack = flow->common.extack;
nfp_flow = nfp_flower_search_fl_table(app, flow->cookie, netdev);
- if (!nfp_flow)
+ if (!nfp_flow) {
+ NL_SET_ERR_MSG_MOD(extack, "invalid entry: cannot dump stats for flow that does not exist");
return -EINVAL;
+ }
ctx_id = be32_to_cpu(nfp_flow->meta.host_ctx_id);
@@ -1156,17 +1259,17 @@ nfp_flower_get_stats(struct nfp_app *app, struct net_device *netdev,
static int
nfp_flower_repr_offload(struct nfp_app *app, struct net_device *netdev,
- struct tc_cls_flower_offload *flower)
+ struct flow_cls_offload *flower)
{
if (!eth_proto_is_802_3(flower->common.protocol))
return -EOPNOTSUPP;
switch (flower->command) {
- case TC_CLSFLOWER_REPLACE:
+ case FLOW_CLS_REPLACE:
return nfp_flower_add_offload(app, netdev, flower);
- case TC_CLSFLOWER_DESTROY:
+ case FLOW_CLS_DESTROY:
return nfp_flower_del_offload(app, netdev, flower);
- case TC_CLSFLOWER_STATS:
+ case FLOW_CLS_STATS:
return nfp_flower_get_stats(app, netdev, flower);
default:
return -EOPNOTSUPP;
@@ -1193,27 +1296,45 @@ static int nfp_flower_setup_tc_block_cb(enum tc_setup_type type,
}
}
+static LIST_HEAD(nfp_block_cb_list);
+
static int nfp_flower_setup_tc_block(struct net_device *netdev,
- struct tc_block_offload *f)
+ struct flow_block_offload *f)
{
struct nfp_repr *repr = netdev_priv(netdev);
struct nfp_flower_repr_priv *repr_priv;
+ struct flow_block_cb *block_cb;
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
+ if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
return -EOPNOTSUPP;
repr_priv = repr->app_priv;
- repr_priv->block_shared = tcf_block_shared(f->block);
+ repr_priv->block_shared = f->block_shared;
+ f->driver_block_list = &nfp_block_cb_list;
switch (f->command) {
- case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block,
- nfp_flower_setup_tc_block_cb,
- repr, repr, f->extack);
- case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block,
- nfp_flower_setup_tc_block_cb,
- repr);
+ case FLOW_BLOCK_BIND:
+ if (flow_block_cb_is_busy(nfp_flower_setup_tc_block_cb, repr,
+ &nfp_block_cb_list))
+ return -EBUSY;
+
+ block_cb = flow_block_cb_alloc(f->net,
+ nfp_flower_setup_tc_block_cb,
+ repr, repr, NULL);
+ if (IS_ERR(block_cb))
+ return PTR_ERR(block_cb);
+
+ flow_block_cb_add(block_cb, f);
+ list_add_tail(&block_cb->driver_list, &nfp_block_cb_list);
+ return 0;
+ case FLOW_BLOCK_UNBIND:
+ block_cb = flow_block_cb_lookup(f, nfp_flower_setup_tc_block_cb,
+ repr);
+ if (!block_cb)
+ return -ENOENT;
+
+ flow_block_cb_remove(block_cb, f);
+ list_del(&block_cb->driver_list);
return 0;
default:
return -EOPNOTSUPP;
@@ -1258,7 +1379,7 @@ static int nfp_flower_setup_indr_block_cb(enum tc_setup_type type,
void *type_data, void *cb_priv)
{
struct nfp_flower_indr_block_cb_priv *priv = cb_priv;
- struct tc_cls_flower_offload *flower = type_data;
+ struct flow_cls_offload *flower = type_data;
if (flower->common.chain_index)
return -EOPNOTSUPP;
@@ -1272,21 +1393,29 @@ static int nfp_flower_setup_indr_block_cb(enum tc_setup_type type,
}
}
+static void nfp_flower_setup_indr_tc_release(void *cb_priv)
+{
+ struct nfp_flower_indr_block_cb_priv *priv = cb_priv;
+
+ list_del(&priv->list);
+ kfree(priv);
+}
+
static int
nfp_flower_setup_indr_tc_block(struct net_device *netdev, struct nfp_app *app,
- struct tc_block_offload *f)
+ struct flow_block_offload *f)
{
struct nfp_flower_indr_block_cb_priv *cb_priv;
struct nfp_flower_priv *priv = app->priv;
- int err;
+ struct flow_block_cb *block_cb;
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS &&
- !(f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS &&
+ if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS &&
+ !(f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS &&
nfp_flower_internal_port_can_offload(app, netdev)))
return -EOPNOTSUPP;
switch (f->command) {
- case TC_BLOCK_BIND:
+ case FLOW_BLOCK_BIND:
cb_priv = kmalloc(sizeof(*cb_priv), GFP_KERNEL);
if (!cb_priv)
return -ENOMEM;
@@ -1295,26 +1424,32 @@ nfp_flower_setup_indr_tc_block(struct net_device *netdev, struct nfp_app *app,
cb_priv->app = app;
list_add(&cb_priv->list, &priv->indr_block_cb_priv);
- err = tcf_block_cb_register(f->block,
- nfp_flower_setup_indr_block_cb,
- cb_priv, cb_priv, f->extack);
- if (err) {
+ block_cb = flow_block_cb_alloc(f->net,
+ nfp_flower_setup_indr_block_cb,
+ cb_priv, cb_priv,
+ nfp_flower_setup_indr_tc_release);
+ if (IS_ERR(block_cb)) {
list_del(&cb_priv->list);
kfree(cb_priv);
+ return PTR_ERR(block_cb);
}
- return err;
- case TC_BLOCK_UNBIND:
+ flow_block_cb_add(block_cb, f);
+ list_add_tail(&block_cb->driver_list, &nfp_block_cb_list);
+ return 0;
+ case FLOW_BLOCK_UNBIND:
cb_priv = nfp_flower_indr_block_cb_priv_lookup(app, netdev);
if (!cb_priv)
return -ENOENT;
- tcf_block_cb_unregister(f->block,
- nfp_flower_setup_indr_block_cb,
- cb_priv);
- list_del(&cb_priv->list);
- kfree(cb_priv);
+ block_cb = flow_block_cb_lookup(f,
+ nfp_flower_setup_indr_block_cb,
+ cb_priv);
+ if (!block_cb)
+ return -ENOENT;
+ flow_block_cb_remove(block_cb, f);
+ list_del(&block_cb->driver_list);
return 0;
default:
return -EOPNOTSUPP;
diff --git a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
index 8c67505865a4..a7a80f4b722a 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
@@ -162,8 +162,7 @@ void nfp_tunnel_keep_alive(struct nfp_app *app, struct sk_buff *skb)
}
pay_len = nfp_flower_cmsg_get_data_len(skb);
- if (pay_len != sizeof(struct nfp_tun_active_tuns) +
- sizeof(struct route_ip_info) * count) {
+ if (pay_len != struct_size(payload, tun_info, count)) {
nfp_flower_cmsg_warn(app, "Corruption in tunnel keep-alive message.\n");
return;
}
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c
index 948d1a4b4643..60e57f08de80 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_main.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c
@@ -596,6 +596,10 @@ static int nfp_pci_probe(struct pci_dev *pdev,
struct nfp_pf *pf;
int err;
+ if (pdev->vendor == PCI_VENDOR_ID_NETRONOME &&
+ pdev->device == PCI_DEVICE_ID_NETRONOME_NFP6000_VF)
+ dev_warn(&pdev->dev, "Binding NFP VF device to the NFP PF driver, the VF driver is called 'nfp_netvf'\n");
+
err = pci_enable_device(pdev);
if (err < 0)
return err;
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h
index df9aff2684ed..5d6c3738b494 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h
@@ -12,11 +12,14 @@
#ifndef _NFP_NET_H_
#define _NFP_NET_H_
+#include <linux/atomic.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/netdevice.h>
#include <linux/pci.h>
#include <linux/io-64-nonatomic-hi-lo.h>
+#include <linux/semaphore.h>
+#include <linux/workqueue.h>
#include <net/xdp.h>
#include "nfp_net_ctrl.h"
@@ -238,7 +241,7 @@ struct nfp_net_tx_ring {
#define PCIE_DESC_RX_I_TCP_CSUM_OK cpu_to_le16(BIT(11))
#define PCIE_DESC_RX_I_UDP_CSUM cpu_to_le16(BIT(10))
#define PCIE_DESC_RX_I_UDP_CSUM_OK cpu_to_le16(BIT(9))
-#define PCIE_DESC_RX_BPF cpu_to_le16(BIT(8))
+#define PCIE_DESC_RX_DECRYPTED cpu_to_le16(BIT(8))
#define PCIE_DESC_RX_EOP cpu_to_le16(BIT(7))
#define PCIE_DESC_RX_IP4_CSUM cpu_to_le16(BIT(6))
#define PCIE_DESC_RX_IP4_CSUM_OK cpu_to_le16(BIT(5))
@@ -365,6 +368,7 @@ struct nfp_net_rx_ring {
* @hw_csum_rx_inner_ok: Counter of packets where the inner HW checksum was OK
* @hw_csum_rx_complete: Counter of packets with CHECKSUM_COMPLETE reported
* @hw_csum_rx_error: Counter of packets with bad checksums
+ * @hw_tls_rx: Number of packets with TLS decrypted by hardware
* @tx_sync: Seqlock for atomic updates of TX stats
* @tx_pkts: Number of Transmitted packets
* @tx_bytes: Number of Transmitted bytes
@@ -372,6 +376,11 @@ struct nfp_net_rx_ring {
* @hw_csum_tx_inner: Counter of inner TX checksum offload requests
* @tx_gather: Counter of packets with Gather DMA
* @tx_lso: Counter of LSO packets sent
+ * @hw_tls_tx: Counter of TLS packets sent with crypto offloaded to HW
+ * @tls_tx_fallback: Counter of TLS packets sent which had to be encrypted
+ * by the fallback path because packets came out of order
+ * @tls_tx_no_fallback: Counter of TLS packets not sent because the fallback
+ * path could not encrypt them
* @tx_errors: How many TX errors were encountered
* @tx_busy: How often was TX busy (no space)?
* @rx_replace_buf_alloc_fail: Counter of RX buffer allocation failures
@@ -392,7 +401,7 @@ struct nfp_net_r_vector {
struct {
struct tasklet_struct tasklet;
struct sk_buff_head queue;
- struct spinlock lock;
+ spinlock_t lock;
};
};
@@ -408,22 +417,30 @@ struct nfp_net_r_vector {
u64 hw_csum_rx_ok;
u64 hw_csum_rx_inner_ok;
u64 hw_csum_rx_complete;
+ u64 hw_tls_rx;
+
+ u64 hw_csum_rx_error;
+ u64 rx_replace_buf_alloc_fail;
struct nfp_net_tx_ring *xdp_ring;
struct u64_stats_sync tx_sync;
u64 tx_pkts;
u64 tx_bytes;
- u64 hw_csum_tx;
+
+ u64 ____cacheline_aligned_in_smp hw_csum_tx;
u64 hw_csum_tx_inner;
u64 tx_gather;
u64 tx_lso;
+ u64 hw_tls_tx;
- u64 hw_csum_rx_error;
- u64 rx_replace_buf_alloc_fail;
+ u64 tls_tx_fallback;
+ u64 tls_tx_no_fallback;
u64 tx_errors;
u64 tx_busy;
+ /* Cold data follows */
+
u32 irq_vector;
irq_handler_t handler;
char name[IFNAMSIZ + 8];
@@ -458,6 +475,7 @@ struct nfp_stat_pair {
* @netdev: Backpointer to net_device structure
* @is_vf: Is the driver attached to a VF?
* @chained_metadata_format: Firemware will use new metadata format
+ * @ktls_tx: Is kTLS TX enabled?
* @rx_dma_dir: Mapping direction for RX buffers
* @rx_dma_off: Offset at which DMA packets (for XDP headroom)
* @rx_offset: Offset in the RX buffers where packet data starts
@@ -482,6 +500,7 @@ struct nfp_net_dp {
u8 is_vf:1;
u8 chained_metadata_format:1;
+ u8 ktls_tx:1;
u8 rx_dma_dir;
u8 rx_offset;
@@ -549,7 +568,7 @@ struct nfp_net_dp {
* @reconfig_timer: Timer for async reading of reconfig results
* @reconfig_in_progress_update: Update FW is processing now (debug only)
* @bar_lock: vNIC config BAR access lock, protects: update,
- * mailbox area
+ * mailbox area, crypto TLV
* @link_up: Is the link up?
* @link_status_lock: Protects @link_* and ensures atomicity with BAR reading
* @rx_coalesce_usecs: RX interrupt moderation usecs delay parameter
@@ -562,6 +581,18 @@ struct nfp_net_dp {
* @tx_bar: Pointer to mapped TX queues
* @rx_bar: Pointer to mapped FL/RX queues
* @tlv_caps: Parsed TLV capabilities
+ * @ktls_tx_conn_cnt: Number of offloaded kTLS TX connections
+ * @ktls_rx_conn_cnt: Number of offloaded kTLS RX connections
+ * @ktls_conn_id_gen: Trivial generator for kTLS connection ids (for TX)
+ * @ktls_no_space: Counter of firmware rejecting kTLS connection due to
+ * lack of space
+ * @mbox_cmsg: Common Control Message via vNIC mailbox state
+ * @mbox_cmsg.queue: CCM mbox queue of pending messages
+ * @mbox_cmsg.wq: CCM mbox wait queue of waiting processes
+ * @mbox_cmsg.workq: CCM mbox work queue for @wait_work and @runq_work
+ * @mbox_cmsg.wait_work: CCM mbox posted msg reconfig wait work
+ * @mbox_cmsg.runq_work: CCM mbox posted msg queue runner work
+ * @mbox_cmsg.tag: CCM mbox message tag allocator
* @debugfs_dir: Device directory in debugfs
* @vnic_list: Entry on device vNIC list
* @pdev: Backpointer to PCI device
@@ -620,7 +651,7 @@ struct nfp_net {
struct timer_list reconfig_timer;
u32 reconfig_in_progress_update;
- struct mutex bar_lock;
+ struct semaphore bar_lock;
u32 rx_coalesce_usecs;
u32 rx_coalesce_max_frames;
@@ -637,6 +668,22 @@ struct nfp_net {
struct nfp_net_tlv_caps tlv_caps;
+ unsigned int ktls_tx_conn_cnt;
+ unsigned int ktls_rx_conn_cnt;
+
+ atomic64_t ktls_conn_id_gen;
+
+ atomic_t ktls_no_space;
+
+ struct {
+ struct sk_buff_head queue;
+ wait_queue_head_t wq;
+ struct workqueue_struct *workq;
+ struct work_struct wait_work;
+ struct work_struct runq_work;
+ u16 tag;
+ } mbox_cmsg;
+
struct dentry *debugfs_dir;
struct list_head vnic_list;
@@ -848,12 +895,17 @@ static inline void nfp_ctrl_unlock(struct nfp_net *nn)
static inline void nn_ctrl_bar_lock(struct nfp_net *nn)
{
- mutex_lock(&nn->bar_lock);
+ down(&nn->bar_lock);
+}
+
+static inline bool nn_ctrl_bar_trylock(struct nfp_net *nn)
+{
+ return !down_trylock(&nn->bar_lock);
}
static inline void nn_ctrl_bar_unlock(struct nfp_net *nn)
{
- mutex_unlock(&nn->bar_lock);
+ up(&nn->bar_lock);
}
/* Globals */
@@ -883,6 +935,7 @@ void nfp_ctrl_close(struct nfp_net *nn);
void nfp_net_set_ethtool_ops(struct net_device *netdev);
void nfp_net_info(struct nfp_net *nn);
+int __nfp_net_reconfig(struct nfp_net *nn, u32 update);
int nfp_net_reconfig(struct nfp_net *nn, u32 update);
unsigned int nfp_net_rss_key_sz(struct nfp_net *nn);
void nfp_net_rss_write_itbl(struct nfp_net *nn);
@@ -891,6 +944,8 @@ void nfp_net_coalesce_write_cfg(struct nfp_net *nn);
int nfp_net_mbox_lock(struct nfp_net *nn, unsigned int data_size);
int nfp_net_mbox_reconfig(struct nfp_net *nn, u32 mbox_cmd);
int nfp_net_mbox_reconfig_and_unlock(struct nfp_net *nn, u32 mbox_cmd);
+void nfp_net_mbox_reconfig_post(struct nfp_net *nn, u32 update);
+int nfp_net_mbox_reconfig_wait_posted(struct nfp_net *nn);
unsigned int
nfp_net_irqs_alloc(struct pci_dev *pdev, struct msix_entry *irq_entries,
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
index b82b684f52ce..9903805717da 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
@@ -23,7 +23,6 @@
#include <linux/interrupt.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
-#include <linux/lockdep.h>
#include <linux/mm.h>
#include <linux/overflow.h>
#include <linux/page_ref.h>
@@ -37,14 +36,17 @@
#include <linux/vmalloc.h>
#include <linux/ktime.h>
+#include <net/tls.h>
#include <net/vxlan.h>
#include "nfpcore/nfp_nsp.h"
+#include "ccm.h"
#include "nfp_app.h"
#include "nfp_net_ctrl.h"
#include "nfp_net.h"
#include "nfp_net_sriov.h"
#include "nfp_port.h"
+#include "crypto/crypto.h"
/**
* nfp_net_get_fw_version() - Read and parse the FW version
@@ -228,6 +230,7 @@ static void nfp_net_reconfig_sync_enter(struct nfp_net *nn)
spin_lock_bh(&nn->reconfig_lock);
+ WARN_ON(nn->reconfig_sync_present);
nn->reconfig_sync_present = true;
if (nn->reconfig_timer_active) {
@@ -271,12 +274,10 @@ static void nfp_net_reconfig_wait_posted(struct nfp_net *nn)
*
* Return: Negative errno on error, 0 on success
*/
-static int __nfp_net_reconfig(struct nfp_net *nn, u32 update)
+int __nfp_net_reconfig(struct nfp_net *nn, u32 update)
{
int ret;
- lockdep_assert_held(&nn->bar_lock);
-
nfp_net_reconfig_sync_enter(nn);
nfp_net_reconfig_start(nn, update);
@@ -331,7 +332,6 @@ int nfp_net_mbox_reconfig(struct nfp_net *nn, u32 mbox_cmd)
u32 mbox = nn->tlv_caps.mbox_off;
int ret;
- lockdep_assert_held(&nn->bar_lock);
nn_writeq(nn, mbox + NFP_NET_CFG_MBOX_SIMPLE_CMD, mbox_cmd);
ret = __nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_MBOX);
@@ -343,6 +343,24 @@ int nfp_net_mbox_reconfig(struct nfp_net *nn, u32 mbox_cmd)
return -nn_readl(nn, mbox + NFP_NET_CFG_MBOX_SIMPLE_RET);
}
+void nfp_net_mbox_reconfig_post(struct nfp_net *nn, u32 mbox_cmd)
+{
+ u32 mbox = nn->tlv_caps.mbox_off;
+
+ nn_writeq(nn, mbox + NFP_NET_CFG_MBOX_SIMPLE_CMD, mbox_cmd);
+
+ nfp_net_reconfig_post(nn, NFP_NET_CFG_UPDATE_MBOX);
+}
+
+int nfp_net_mbox_reconfig_wait_posted(struct nfp_net *nn)
+{
+ u32 mbox = nn->tlv_caps.mbox_off;
+
+ nfp_net_reconfig_wait_posted(nn);
+
+ return -nn_readl(nn, mbox + NFP_NET_CFG_MBOX_SIMPLE_RET);
+}
+
int nfp_net_mbox_reconfig_and_unlock(struct nfp_net *nn, u32 mbox_cmd)
{
int ret;
@@ -804,6 +822,99 @@ static void nfp_net_tx_csum(struct nfp_net_dp *dp,
u64_stats_update_end(&r_vec->tx_sync);
}
+static struct sk_buff *
+nfp_net_tls_tx(struct nfp_net_dp *dp, struct nfp_net_r_vector *r_vec,
+ struct sk_buff *skb, u64 *tls_handle, int *nr_frags)
+{
+#ifdef CONFIG_TLS_DEVICE
+ struct nfp_net_tls_offload_ctx *ntls;
+ struct sk_buff *nskb;
+ bool resync_pending;
+ u32 datalen, seq;
+
+ if (likely(!dp->ktls_tx))
+ return skb;
+ if (!skb->sk || !tls_is_sk_tx_device_offloaded(skb->sk))
+ return skb;
+
+ datalen = skb->len - (skb_transport_offset(skb) + tcp_hdrlen(skb));
+ seq = ntohl(tcp_hdr(skb)->seq);
+ ntls = tls_driver_ctx(skb->sk, TLS_OFFLOAD_CTX_DIR_TX);
+ resync_pending = tls_offload_tx_resync_pending(skb->sk);
+ if (unlikely(resync_pending || ntls->next_seq != seq)) {
+ /* Pure ACK out of order already */
+ if (!datalen)
+ return skb;
+
+ u64_stats_update_begin(&r_vec->tx_sync);
+ r_vec->tls_tx_fallback++;
+ u64_stats_update_end(&r_vec->tx_sync);
+
+ nskb = tls_encrypt_skb(skb);
+ if (!nskb) {
+ u64_stats_update_begin(&r_vec->tx_sync);
+ r_vec->tls_tx_no_fallback++;
+ u64_stats_update_end(&r_vec->tx_sync);
+ return NULL;
+ }
+ /* encryption wasn't necessary */
+ if (nskb == skb)
+ return skb;
+ /* we don't re-check ring space */
+ if (unlikely(skb_is_nonlinear(nskb))) {
+ nn_dp_warn(dp, "tls_encrypt_skb() produced fragmented frame\n");
+ u64_stats_update_begin(&r_vec->tx_sync);
+ r_vec->tx_errors++;
+ u64_stats_update_end(&r_vec->tx_sync);
+ dev_kfree_skb_any(nskb);
+ return NULL;
+ }
+
+ /* jump forward, a TX may have gotten lost, need to sync TX */
+ if (!resync_pending && seq - ntls->next_seq < U32_MAX / 4)
+ tls_offload_tx_resync_request(nskb->sk);
+
+ *nr_frags = 0;
+ return nskb;
+ }
+
+ if (datalen) {
+ u64_stats_update_begin(&r_vec->tx_sync);
+ if (!skb_is_gso(skb))
+ r_vec->hw_tls_tx++;
+ else
+ r_vec->hw_tls_tx += skb_shinfo(skb)->gso_segs;
+ u64_stats_update_end(&r_vec->tx_sync);
+ }
+
+ memcpy(tls_handle, ntls->fw_handle, sizeof(ntls->fw_handle));
+ ntls->next_seq += datalen;
+#endif
+ return skb;
+}
+
+static void nfp_net_tls_tx_undo(struct sk_buff *skb, u64 tls_handle)
+{
+#ifdef CONFIG_TLS_DEVICE
+ struct nfp_net_tls_offload_ctx *ntls;
+ u32 datalen, seq;
+
+ if (!tls_handle)
+ return;
+ if (WARN_ON_ONCE(!skb->sk || !tls_is_sk_tx_device_offloaded(skb->sk)))
+ return;
+
+ datalen = skb->len - (skb_transport_offset(skb) + tcp_hdrlen(skb));
+ seq = ntohl(tcp_hdr(skb)->seq);
+
+ ntls = tls_driver_ctx(skb->sk, TLS_OFFLOAD_CTX_DIR_TX);
+ if (ntls->next_seq == seq + datalen)
+ ntls->next_seq = seq;
+ else
+ WARN_ON_ONCE(1);
+#endif
+}
+
static void nfp_net_tx_xmit_more_flush(struct nfp_net_tx_ring *tx_ring)
{
wmb();
@@ -811,24 +922,47 @@ static void nfp_net_tx_xmit_more_flush(struct nfp_net_tx_ring *tx_ring)
tx_ring->wr_ptr_add = 0;
}
-static int nfp_net_prep_port_id(struct sk_buff *skb)
+static int nfp_net_prep_tx_meta(struct sk_buff *skb, u64 tls_handle)
{
struct metadata_dst *md_dst = skb_metadata_dst(skb);
unsigned char *data;
+ u32 meta_id = 0;
+ int md_bytes;
- if (likely(!md_dst))
- return 0;
- if (unlikely(md_dst->type != METADATA_HW_PORT_MUX))
+ if (likely(!md_dst && !tls_handle))
return 0;
+ if (unlikely(md_dst && md_dst->type != METADATA_HW_PORT_MUX)) {
+ if (!tls_handle)
+ return 0;
+ md_dst = NULL;
+ }
+
+ md_bytes = 4 + !!md_dst * 4 + !!tls_handle * 8;
- if (unlikely(skb_cow_head(skb, 8)))
+ if (unlikely(skb_cow_head(skb, md_bytes)))
return -ENOMEM;
- data = skb_push(skb, 8);
- put_unaligned_be32(NFP_NET_META_PORTID, data);
- put_unaligned_be32(md_dst->u.port_info.port_id, data + 4);
+ meta_id = 0;
+ data = skb_push(skb, md_bytes) + md_bytes;
+ if (md_dst) {
+ data -= 4;
+ put_unaligned_be32(md_dst->u.port_info.port_id, data);
+ meta_id = NFP_NET_META_PORTID;
+ }
+ if (tls_handle) {
+ /* conn handle is opaque, we just use u64 to be able to quickly
+ * compare it to zero
+ */
+ data -= 8;
+ memcpy(data, &tls_handle, sizeof(tls_handle));
+ meta_id <<= NFP_NET_META_FIELD_SIZE;
+ meta_id |= NFP_NET_META_CONN_HANDLE;
+ }
+
+ data -= 4;
+ put_unaligned_be32(meta_id, data);
- return 8;
+ return md_bytes;
}
/**
@@ -851,6 +985,7 @@ static int nfp_net_tx(struct sk_buff *skb, struct net_device *netdev)
struct nfp_net_dp *dp;
dma_addr_t dma_addr;
unsigned int fsize;
+ u64 tls_handle = 0;
u16 qidx;
dp = &nn->dp;
@@ -872,18 +1007,21 @@ static int nfp_net_tx(struct sk_buff *skb, struct net_device *netdev)
return NETDEV_TX_BUSY;
}
- md_bytes = nfp_net_prep_port_id(skb);
- if (unlikely(md_bytes < 0)) {
+ skb = nfp_net_tls_tx(dp, r_vec, skb, &tls_handle, &nr_frags);
+ if (unlikely(!skb)) {
nfp_net_tx_xmit_more_flush(tx_ring);
- dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
+ md_bytes = nfp_net_prep_tx_meta(skb, tls_handle);
+ if (unlikely(md_bytes < 0))
+ goto err_flush;
+
/* Start with the head skbuf */
dma_addr = dma_map_single(dp->dev, skb->data, skb_headlen(skb),
DMA_TO_DEVICE);
if (dma_mapping_error(dp->dev, dma_addr))
- goto err_free;
+ goto err_dma_err;
wr_idx = D_IDX(tx_ring, tx_ring->wr_p);
@@ -979,12 +1117,14 @@ err_unmap:
tx_ring->txbufs[wr_idx].skb = NULL;
tx_ring->txbufs[wr_idx].dma_addr = 0;
tx_ring->txbufs[wr_idx].fidx = -2;
-err_free:
+err_dma_err:
nn_dp_warn(dp, "Failed to map DMA TX buffer\n");
+err_flush:
nfp_net_tx_xmit_more_flush(tx_ring);
u64_stats_update_begin(&r_vec->tx_sync);
r_vec->tx_errors++;
u64_stats_update_end(&r_vec->tx_sync);
+ nfp_net_tls_tx_undo(skb, tls_handle);
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -1857,6 +1997,15 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget)
nfp_net_rx_csum(dp, r_vec, rxd, &meta, skb);
+#ifdef CONFIG_TLS_DEVICE
+ if (rxd->rxd.flags & PCIE_DESC_RX_DECRYPTED) {
+ skb->decrypted = true;
+ u64_stats_update_begin(&r_vec->rx_sync);
+ r_vec->hw_tls_rx++;
+ u64_stats_update_end(&r_vec->rx_sync);
+ }
+#endif
+
if (rxd->rxd.flags & PCIE_DESC_RX_VLAN)
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
le16_to_cpu(rxd->rxd.vlan));
@@ -1867,6 +2016,7 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget)
napi_gro_receive(&rx_ring->r_vec->napi, skb);
} else {
skb->dev = netdev;
+ skb_reset_network_header(skb);
__skb_push(skb, ETH_HLEN);
dev_queue_xmit(skb);
}
@@ -3704,7 +3854,7 @@ nfp_net_alloc(struct pci_dev *pdev, void __iomem *ctrl_bar, bool needs_netdev,
nn->dp.txd_cnt = NFP_NET_TX_DESCS_DEFAULT;
nn->dp.rxd_cnt = NFP_NET_RX_DESCS_DEFAULT;
- mutex_init(&nn->bar_lock);
+ sema_init(&nn->bar_lock, 1);
spin_lock_init(&nn->reconfig_lock);
spin_lock_init(&nn->link_status_lock);
@@ -3716,6 +3866,10 @@ nfp_net_alloc(struct pci_dev *pdev, void __iomem *ctrl_bar, bool needs_netdev,
if (err)
goto err_free_nn;
+ err = nfp_ccm_mbox_alloc(nn);
+ if (err)
+ goto err_free_nn;
+
return nn;
err_free_nn:
@@ -3733,8 +3887,7 @@ err_free_nn:
void nfp_net_free(struct nfp_net *nn)
{
WARN_ON(timer_pending(&nn->reconfig_timer) || nn->reconfig_posted);
-
- mutex_destroy(&nn->bar_lock);
+ nfp_ccm_mbox_free(nn);
if (nn->dp.netdev)
free_netdev(nn->dp.netdev);
@@ -4009,14 +4162,27 @@ int nfp_net_init(struct nfp_net *nn)
if (err)
return err;
- if (nn->dp.netdev)
+ if (nn->dp.netdev) {
nfp_net_netdev_init(nn);
+ err = nfp_ccm_mbox_init(nn);
+ if (err)
+ return err;
+
+ err = nfp_net_tls_init(nn);
+ if (err)
+ goto err_clean_mbox;
+ }
+
nfp_net_vecs_init(nn);
if (!nn->dp.netdev)
return 0;
return register_netdev(nn->dp.netdev);
+
+err_clean_mbox:
+ nfp_ccm_mbox_clean(nn);
+ return err;
}
/**
@@ -4029,5 +4195,6 @@ void nfp_net_clean(struct nfp_net *nn)
return;
unregister_netdev(nn->dp.netdev);
+ nfp_ccm_mbox_clean(nn);
nfp_net_reconfig_wait_posted(nn);
}
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.c
index 6d5213b5bcb0..d835c14b7257 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.c
@@ -99,6 +99,21 @@ int nfp_net_tlv_caps_parse(struct device *dev, u8 __iomem *ctrl_mem,
caps->repr_cap = readl(data);
break;
+ case NFP_NET_CFG_TLV_TYPE_MBOX_CMSG_TYPES:
+ if (length >= 4)
+ caps->mbox_cmsg_types = readl(data);
+ break;
+ case NFP_NET_CFG_TLV_TYPE_CRYPTO_OPS:
+ if (length < 32) {
+ dev_err(dev,
+ "CRYPTO OPS TLV should be at least 32B, is %dB offset:%u\n",
+ length, offset);
+ return -EINVAL;
+ }
+
+ caps->crypto_ops = readl(data);
+ caps->crypto_enable_off = data - ctrl_mem + 16;
+ break;
default:
if (!FIELD_GET(NFP_NET_CFG_TLV_HEADER_REQUIRED, hdr))
break;
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h
index 25919e338071..ee6b24e4eacd 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h
@@ -44,6 +44,7 @@
#define NFP_NET_META_MARK 2
#define NFP_NET_META_PORTID 5
#define NFP_NET_META_CSUM 6 /* checksum complete type */
+#define NFP_NET_META_CONN_HANDLE 7
#define NFP_META_PORT_ID_CTRL ~0U
@@ -135,6 +136,7 @@
#define NFP_NET_CFG_UPDATE_MACADDR (0x1 << 11) /* MAC address change */
#define NFP_NET_CFG_UPDATE_MBOX (0x1 << 12) /* Mailbox update */
#define NFP_NET_CFG_UPDATE_VF (0x1 << 13) /* VF settings change */
+#define NFP_NET_CFG_UPDATE_CRYPTO (0x1 << 14) /* Crypto on/off */
#define NFP_NET_CFG_UPDATE_ERR (0x1 << 31) /* A error occurred */
#define NFP_NET_CFG_TXRS_ENABLE 0x0008
#define NFP_NET_CFG_RXRS_ENABLE 0x0010
@@ -394,6 +396,7 @@
#define NFP_NET_CFG_MBOX_CMD_CTAG_FILTER_KILL 2
#define NFP_NET_CFG_MBOX_CMD_PCI_DSCP_PRIOMAP_SET 5
+#define NFP_NET_CFG_MBOX_CMD_TLV_CMSG 6
/**
* VLAN filtering using general use mailbox
@@ -466,6 +469,16 @@
* %NFP_NET_CFG_TLV_TYPE_REPR_CAP:
* Single word, equivalent of %NFP_NET_CFG_CAP for representors, features which
* can be used on representors.
+ *
+ * %NFP_NET_CFG_TLV_TYPE_MBOX_CMSG_TYPES:
+ * Variable, bitmap of control message types supported by the mailbox handler.
+ * Bit 0 corresponds to message type 0, bit 1 to 1, etc. Control messages are
+ * encapsulated into simple TLVs, with an end TLV and written to the Mailbox.
+ *
+ * %NFP_NET_CFG_TLV_TYPE_CRYPTO_OPS:
+ * 8 words, bitmaps of supported and enabled crypto operations.
+ * First 16B (4 words) contains a bitmap of supported crypto operations,
+ * and next 16B contain the enabled operations.
*/
#define NFP_NET_CFG_TLV_TYPE_UNKNOWN 0
#define NFP_NET_CFG_TLV_TYPE_RESERVED 1
@@ -475,6 +488,8 @@
#define NFP_NET_CFG_TLV_TYPE_EXPERIMENTAL0 5
#define NFP_NET_CFG_TLV_TYPE_EXPERIMENTAL1 6
#define NFP_NET_CFG_TLV_TYPE_REPR_CAP 7
+#define NFP_NET_CFG_TLV_TYPE_MBOX_CMSG_TYPES 10
+#define NFP_NET_CFG_TLV_TYPE_CRYPTO_OPS 11 /* see crypto/fw.h */
struct device;
@@ -484,12 +499,18 @@ struct device;
* @mbox_off: vNIC mailbox area offset
* @mbox_len: vNIC mailbox area length
* @repr_cap: capabilities for representors
+ * @mbox_cmsg_types: cmsgs which can be passed through the mailbox
+ * @crypto_ops: supported crypto operations
+ * @crypto_enable_off: offset of crypto ops enable region
*/
struct nfp_net_tlv_caps {
u32 me_freq_mhz;
unsigned int mbox_off;
unsigned int mbox_len;
u32 repr_cap;
+ u32 mbox_cmsg_types;
+ u32 crypto_ops;
+ unsigned int crypto_enable_off;
};
int nfp_net_tlv_caps_parse(struct device *dev, u8 __iomem *ctrl_mem,
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
index 851e31e0ba8e..d9cbe84ac6ad 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
@@ -150,8 +150,9 @@ static const struct nfp_et_stat nfp_mac_et_stats[] = {
#define NN_ET_GLOBAL_STATS_LEN ARRAY_SIZE(nfp_net_et_stats)
#define NN_ET_SWITCH_STATS_LEN 9
-#define NN_RVEC_GATHER_STATS 9
+#define NN_RVEC_GATHER_STATS 13
#define NN_RVEC_PER_Q_STATS 3
+#define NN_CTRL_PATH_STATS 1
#define SFP_SFF_REV_COMPLIANCE 1
@@ -423,7 +424,8 @@ static unsigned int nfp_vnic_get_sw_stats_count(struct net_device *netdev)
{
struct nfp_net *nn = netdev_priv(netdev);
- return NN_RVEC_GATHER_STATS + nn->max_r_vecs * NN_RVEC_PER_Q_STATS;
+ return NN_RVEC_GATHER_STATS + nn->max_r_vecs * NN_RVEC_PER_Q_STATS +
+ NN_CTRL_PATH_STATS;
}
static u8 *nfp_vnic_get_sw_stats_strings(struct net_device *netdev, u8 *data)
@@ -442,10 +444,16 @@ static u8 *nfp_vnic_get_sw_stats_strings(struct net_device *netdev, u8 *data)
data = nfp_pr_et(data, "hw_rx_csum_complete");
data = nfp_pr_et(data, "hw_rx_csum_err");
data = nfp_pr_et(data, "rx_replace_buf_alloc_fail");
+ data = nfp_pr_et(data, "rx_tls_decrypted");
data = nfp_pr_et(data, "hw_tx_csum");
data = nfp_pr_et(data, "hw_tx_inner_csum");
data = nfp_pr_et(data, "tx_gather");
data = nfp_pr_et(data, "tx_lso");
+ data = nfp_pr_et(data, "tx_tls_encrypted");
+ data = nfp_pr_et(data, "tx_tls_ooo");
+ data = nfp_pr_et(data, "tx_tls_drop_no_sync_data");
+
+ data = nfp_pr_et(data, "hw_tls_no_space");
return data;
}
@@ -468,16 +476,20 @@ static u64 *nfp_vnic_get_sw_stats(struct net_device *netdev, u64 *data)
tmp[2] = nn->r_vecs[i].hw_csum_rx_complete;
tmp[3] = nn->r_vecs[i].hw_csum_rx_error;
tmp[4] = nn->r_vecs[i].rx_replace_buf_alloc_fail;
+ tmp[5] = nn->r_vecs[i].hw_tls_rx;
} while (u64_stats_fetch_retry(&nn->r_vecs[i].rx_sync, start));
do {
start = u64_stats_fetch_begin(&nn->r_vecs[i].tx_sync);
data[1] = nn->r_vecs[i].tx_pkts;
data[2] = nn->r_vecs[i].tx_busy;
- tmp[5] = nn->r_vecs[i].hw_csum_tx;
- tmp[6] = nn->r_vecs[i].hw_csum_tx_inner;
- tmp[7] = nn->r_vecs[i].tx_gather;
- tmp[8] = nn->r_vecs[i].tx_lso;
+ tmp[6] = nn->r_vecs[i].hw_csum_tx;
+ tmp[7] = nn->r_vecs[i].hw_csum_tx_inner;
+ tmp[8] = nn->r_vecs[i].tx_gather;
+ tmp[9] = nn->r_vecs[i].tx_lso;
+ tmp[10] = nn->r_vecs[i].hw_tls_tx;
+ tmp[11] = nn->r_vecs[i].tls_tx_fallback;
+ tmp[12] = nn->r_vecs[i].tls_tx_no_fallback;
} while (u64_stats_fetch_retry(&nn->r_vecs[i].tx_sync, start));
data += NN_RVEC_PER_Q_STATS;
@@ -489,6 +501,8 @@ static u64 *nfp_vnic_get_sw_stats(struct net_device *netdev, u64 *data)
for (j = 0; j < NN_RVEC_GATHER_STATS; j++)
*data++ = gathered_stats[j];
+ *data++ = atomic_read(&nn->ktls_no_space);
+
return data;
}
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c
index 42cf4fd875ea..9a08623c325d 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c
@@ -241,11 +241,16 @@ static int nfp_nsp_check(struct nfp_nsp *state)
state->ver.major = FIELD_GET(NSP_STATUS_MAJOR, reg);
state->ver.minor = FIELD_GET(NSP_STATUS_MINOR, reg);
- if (state->ver.major != NSP_MAJOR || state->ver.minor < NSP_MINOR) {
+ if (state->ver.major != NSP_MAJOR) {
nfp_err(cpp, "Unsupported ABI %hu.%hu\n",
state->ver.major, state->ver.minor);
return -EINVAL;
}
+ if (state->ver.minor < NSP_MINOR) {
+ nfp_err(cpp, "ABI too old to support NIC operation (%u.%hu < %u.%u), please update the management FW on the flash\n",
+ NSP_MAJOR, state->ver.minor, NSP_MAJOR, NSP_MINOR);
+ return -EINVAL;
+ }
if (reg & NSP_STATUS_BUSY) {
nfp_err(cpp, "Service processor busy!\n");
diff --git a/drivers/net/ethernet/netx-eth.c b/drivers/net/ethernet/netx-eth.c
index df4188cb43e0..cf6e7eb1b1e1 100644
--- a/drivers/net/ethernet/netx-eth.c
+++ b/drivers/net/ethernet/netx-eth.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/net/ethernet/netx-eth.c
*
* Copyright (c) 2005 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/init.h>
diff --git a/drivers/net/ethernet/ni/nixge.c b/drivers/net/ethernet/ni/nixge.c
index 96f7a9818294..0b384f97d2fd 100644
--- a/drivers/net/ethernet/ni/nixge.c
+++ b/drivers/net/ethernet/ni/nixge.c
@@ -990,7 +990,7 @@ static void nixge_ethtools_get_drvinfo(struct net_device *ndev,
struct ethtool_drvinfo *ed)
{
strlcpy(ed->driver, "nixge", sizeof(ed->driver));
- strlcpy(ed->bus_info, "platform", sizeof(ed->driver));
+ strlcpy(ed->bus_info, "platform", sizeof(ed->bus_info));
}
static int nixge_ethtools_get_coalesce(struct net_device *ndev,
diff --git a/drivers/net/ethernet/pasemi/pasemi_mac.c b/drivers/net/ethernet/pasemi/pasemi_mac.c
index 5ffaee9f53b1..be6660128b55 100644
--- a/drivers/net/ethernet/pasemi/pasemi_mac.c
+++ b/drivers/net/ethernet/pasemi/pasemi_mac.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2006-2007 PA Semi, Inc
*
* Driver for the PA Semi PWRficient onchip 1G/10G Ethernet MACs
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
@@ -1053,7 +1042,6 @@ static int pasemi_mac_phy_init(struct net_device *dev)
dn = pci_device_to_OF_node(mac->pdev);
phy_dn = of_parse_phandle(dn, "phy-handle", 0);
- of_node_put(phy_dn);
mac->link = 0;
mac->speed = 0;
@@ -1062,6 +1050,7 @@ static int pasemi_mac_phy_init(struct net_device *dev)
phydev = of_phy_connect(dev, phy_dn, &pasemi_adjust_link, 0,
PHY_INTERFACE_MODE_SGMII);
+ of_node_put(phy_dn);
if (!phydev) {
printk(KERN_ERR "%s: Could not attach to phy\n", dev->name);
return -ENODEV;
diff --git a/drivers/net/ethernet/pasemi/pasemi_mac.h b/drivers/net/ethernet/pasemi/pasemi_mac.h
index 7c47e263b8c1..d7d2068b6f1b 100644
--- a/drivers/net/ethernet/pasemi/pasemi_mac.h
+++ b/drivers/net/ethernet/pasemi/pasemi_mac.h
@@ -1,20 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2006 PA Semi, Inc
*
* Driver for the PA6T-1682M onchip 1G/10G Ethernet MACs, soft state and
* hardware register layouts.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PASEMI_MAC_H
diff --git a/drivers/net/ethernet/pasemi/pasemi_mac_ethtool.c b/drivers/net/ethernet/pasemi/pasemi_mac_ethtool.c
index d0afc2b8f8e3..e1a304886a3c 100644
--- a/drivers/net/ethernet/pasemi/pasemi_mac_ethtool.c
+++ b/drivers/net/ethernet/pasemi/pasemi_mac_ethtool.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2006-2008 PA Semi, Inc
*
* Ethtool hooks for the PA Semi PWRficient onchip 1G/10G Ethernet MACs
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
diff --git a/drivers/net/ethernet/qlogic/Kconfig b/drivers/net/ethernet/qlogic/Kconfig
index fdbb3ce00e20..a391cf6ee4b2 100644
--- a/drivers/net/ethernet/qlogic/Kconfig
+++ b/drivers/net/ethernet/qlogic/Kconfig
@@ -87,6 +87,7 @@ config QED
depends on PCI
select ZLIB_INFLATE
select CRC8
+ select NET_DEVLINK
---help---
This enables the support for ...
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c
index 433052f734ed..5e9f8ee99800 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c
@@ -442,10 +442,8 @@ nx_fw_cmd_create_tx_ctx(struct netxen_adapter *adapter)
goto out_free_rq;
}
- memset(rq_addr, 0, rq_size);
prq = rq_addr;
- memset(rsp_addr, 0, rsp_size);
prsp = rsp_addr;
prq->host_rsp_dma_addr = cpu_to_le64(rsp_phys_addr);
@@ -755,7 +753,6 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter)
return -ENOMEM;
}
- memset(addr, 0, sizeof(struct netxen_ring_ctx));
recv_ctx->hwctx = addr;
recv_ctx->hwctx->ctx_id = cpu_to_le32(port);
recv_ctx->hwctx->cmd_consumer_offset =
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
index 84cb62434556..58e2eaf77014 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
@@ -3248,6 +3248,7 @@ netxen_config_indev_addr(struct netxen_adapter *adapter,
struct net_device *dev, unsigned long event)
{
struct in_device *indev;
+ struct in_ifaddr *ifa;
if (!netxen_destip_supported(adapter))
return;
@@ -3256,7 +3257,8 @@ netxen_config_indev_addr(struct netxen_adapter *adapter,
if (!indev)
return;
- for_ifa(indev) {
+ rcu_read_lock();
+ in_dev_for_each_ifa_rcu(ifa, indev) {
switch (event) {
case NETDEV_UP:
netxen_list_config_ip(adapter, ifa, NX_IP_UP);
@@ -3267,8 +3269,8 @@ netxen_config_indev_addr(struct netxen_adapter *adapter,
default:
break;
}
- } endfor_ifa(indev);
-
+ }
+ rcu_read_unlock();
in_dev_put(indev);
}
diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h
index c5e96ce20f59..89fe091c958d 100644
--- a/drivers/net/ethernet/qlogic/qed/qed.h
+++ b/drivers/net/ethernet/qlogic/qed/qed.h
@@ -140,6 +140,7 @@ struct qed_cxt_mngr;
struct qed_sb_sp_info;
struct qed_ll2_info;
struct qed_mcp_info;
+struct qed_llh_info;
struct qed_rt_data {
u32 *init_val;
@@ -741,6 +742,7 @@ struct qed_dev {
#define QED_DEV_ID_MASK 0xff00
#define QED_DEV_ID_MASK_BB 0x1600
#define QED_DEV_ID_MASK_AH 0x8000
+#define QED_IS_E4(dev) (QED_IS_BB(dev) || QED_IS_AH(dev))
u16 chip_num;
#define CHIP_NUM_MASK 0xffff
@@ -801,6 +803,11 @@ struct qed_dev {
u8 num_hwfns;
struct qed_hwfn hwfns[MAX_HWFNS_PER_DEVICE];
+ /* Engine affinity */
+ u8 l2_affin_hint;
+ u8 fir_affin;
+ u8 iwarp_affin;
+
/* SRIOV */
struct qed_hw_sriov_info *p_iov_info;
#define IS_QED_SRIOV(cdev) (!!(cdev)->p_iov_info)
@@ -815,6 +822,10 @@ struct qed_dev {
/* Recovery */
bool recov_in_prog;
+ /* LLH info */
+ u8 ppfid_bitmap;
+ struct qed_llh_info *p_llh_info;
+
/* Linux specific here */
struct qede_dev *edev;
struct pci_dev *pdev;
@@ -852,6 +863,9 @@ struct qed_dev {
u32 rdma_max_inline;
u32 rdma_max_srq_sge;
u16 tunn_feature_mask;
+
+ struct devlink *dl;
+ bool iwarp_cmt;
};
#define NUM_OF_VFS(dev) (QED_IS_BB(dev) ? MAX_NUM_VFS_BB \
@@ -904,6 +918,14 @@ void qed_set_fw_mac_addr(__le16 *fw_msb,
__le16 *fw_mid, __le16 *fw_lsb, u8 *mac);
#define QED_LEADING_HWFN(dev) (&dev->hwfns[0])
+#define QED_IS_CMT(dev) ((dev)->num_hwfns > 1)
+/* Macros for getting the engine-affinitized hwfn (FIR: fcoe,iscsi,roce) */
+#define QED_FIR_AFFIN_HWFN(dev) (&(dev)->hwfns[dev->fir_affin])
+#define QED_IWARP_AFFIN_HWFN(dev) (&(dev)->hwfns[dev->iwarp_affin])
+#define QED_AFFIN_HWFN(dev) \
+ (QED_IS_IWARP_PERSONALITY(QED_LEADING_HWFN(dev)) ? \
+ QED_IWARP_AFFIN_HWFN(dev) : QED_FIR_AFFIN_HWFN(dev))
+#define QED_AFFIN_HWFN_IDX(dev) (IS_LEAD_HWFN(QED_AFFIN_HWFN(dev)) ? 0 : 1)
/* Flags for indication of required queues */
#define PQ_FLAGS_RLS (BIT(0))
@@ -923,8 +945,6 @@ u16 qed_get_cm_pq_idx_vf(struct qed_hwfn *p_hwfn, u16 vf);
u16 qed_get_cm_pq_idx_ofld_mtc(struct qed_hwfn *p_hwfn, u8 tc);
u16 qed_get_cm_pq_idx_llt_mtc(struct qed_hwfn *p_hwfn, u8 tc);
-#define QED_LEADING_HWFN(dev) (&dev->hwfns[0])
-
/* doorbell recovery mechanism */
void qed_db_recovery_dp(struct qed_hwfn *p_hwfn);
void qed_db_recovery_execute(struct qed_hwfn *p_hwfn);
diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
index e61d1d905415..8e1bdf58b9e7 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
@@ -2351,7 +2351,8 @@ qed_cxt_dynamic_ilt_alloc(struct qed_hwfn *p_hwfn,
/* Write via DMAE since the PSWRQ2_REG_ILT_MEMORY line is a wide-bus */
qed_dmae_host2grc(p_hwfn, p_ptt, (u64) (uintptr_t)&ilt_hw_entry,
- reg_offset, sizeof(ilt_hw_entry) / sizeof(u32), 0);
+ reg_offset, sizeof(ilt_hw_entry) / sizeof(u32),
+ NULL);
if (elem_type == QED_ELEM_CXT) {
u32 last_cid_allocated = (1 + (iid / elems_per_p)) *
@@ -2457,7 +2458,7 @@ qed_cxt_free_ilt_range(struct qed_hwfn *p_hwfn,
(u64) (uintptr_t) &ilt_hw_entry,
reg_offset,
sizeof(ilt_hw_entry) / sizeof(u32),
- 0);
+ NULL);
}
qed_ptt_release(p_hwfn, p_ptt);
diff --git a/drivers/net/ethernet/qlogic/qed/qed_debug.c b/drivers/net/ethernet/qlogic/qed/qed_debug.c
index ab8cacbdee3e..5ea6c4fc6050 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_debug.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_debug.c
@@ -2534,7 +2534,7 @@ static u32 qed_grc_dump_addr_range(struct qed_hwfn *p_hwfn,
(len >= s_platform_defs[dev_data->platform_id].dmae_thresh ||
wide_bus)) {
if (!qed_dmae_grc2host(p_hwfn, p_ptt, DWORDS_TO_BYTES(addr),
- (u64)(uintptr_t)(dump_buf), len, 0))
+ (u64)(uintptr_t)(dump_buf), len, NULL))
return len;
dev_data->use_dmae = 0;
DP_VERBOSE(p_hwfn,
diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c
index fccdb06fc5c5..a1ebc2b1ca0b 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_dev.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c
@@ -361,6 +361,927 @@ void qed_db_recovery_execute(struct qed_hwfn *p_hwfn)
/******************** Doorbell Recovery end ****************/
+/********************************** NIG LLH ***********************************/
+
+enum qed_llh_filter_type {
+ QED_LLH_FILTER_TYPE_MAC,
+ QED_LLH_FILTER_TYPE_PROTOCOL,
+};
+
+struct qed_llh_mac_filter {
+ u8 addr[ETH_ALEN];
+};
+
+struct qed_llh_protocol_filter {
+ enum qed_llh_prot_filter_type_t type;
+ u16 source_port_or_eth_type;
+ u16 dest_port;
+};
+
+union qed_llh_filter {
+ struct qed_llh_mac_filter mac;
+ struct qed_llh_protocol_filter protocol;
+};
+
+struct qed_llh_filter_info {
+ bool b_enabled;
+ u32 ref_cnt;
+ enum qed_llh_filter_type type;
+ union qed_llh_filter filter;
+};
+
+struct qed_llh_info {
+ /* Number of LLH filters banks */
+ u8 num_ppfid;
+
+#define MAX_NUM_PPFID 8
+ u8 ppfid_array[MAX_NUM_PPFID];
+
+ /* Array of filters arrays:
+ * "num_ppfid" elements of filters banks, where each is an array of
+ * "NIG_REG_LLH_FUNC_FILTER_EN_SIZE" filters.
+ */
+ struct qed_llh_filter_info **pp_filters;
+};
+
+static void qed_llh_free(struct qed_dev *cdev)
+{
+ struct qed_llh_info *p_llh_info = cdev->p_llh_info;
+ u32 i;
+
+ if (p_llh_info) {
+ if (p_llh_info->pp_filters)
+ for (i = 0; i < p_llh_info->num_ppfid; i++)
+ kfree(p_llh_info->pp_filters[i]);
+
+ kfree(p_llh_info->pp_filters);
+ }
+
+ kfree(p_llh_info);
+ cdev->p_llh_info = NULL;
+}
+
+static int qed_llh_alloc(struct qed_dev *cdev)
+{
+ struct qed_llh_info *p_llh_info;
+ u32 size, i;
+
+ p_llh_info = kzalloc(sizeof(*p_llh_info), GFP_KERNEL);
+ if (!p_llh_info)
+ return -ENOMEM;
+ cdev->p_llh_info = p_llh_info;
+
+ for (i = 0; i < MAX_NUM_PPFID; i++) {
+ if (!(cdev->ppfid_bitmap & (0x1 << i)))
+ continue;
+
+ p_llh_info->ppfid_array[p_llh_info->num_ppfid] = i;
+ DP_VERBOSE(cdev, QED_MSG_SP, "ppfid_array[%d] = %hhd\n",
+ p_llh_info->num_ppfid, i);
+ p_llh_info->num_ppfid++;
+ }
+
+ size = p_llh_info->num_ppfid * sizeof(*p_llh_info->pp_filters);
+ p_llh_info->pp_filters = kzalloc(size, GFP_KERNEL);
+ if (!p_llh_info->pp_filters)
+ return -ENOMEM;
+
+ size = NIG_REG_LLH_FUNC_FILTER_EN_SIZE *
+ sizeof(**p_llh_info->pp_filters);
+ for (i = 0; i < p_llh_info->num_ppfid; i++) {
+ p_llh_info->pp_filters[i] = kzalloc(size, GFP_KERNEL);
+ if (!p_llh_info->pp_filters[i])
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int qed_llh_shadow_sanity(struct qed_dev *cdev,
+ u8 ppfid, u8 filter_idx, const char *action)
+{
+ struct qed_llh_info *p_llh_info = cdev->p_llh_info;
+
+ if (ppfid >= p_llh_info->num_ppfid) {
+ DP_NOTICE(cdev,
+ "LLH shadow [%s]: using ppfid %d while only %d ppfids are available\n",
+ action, ppfid, p_llh_info->num_ppfid);
+ return -EINVAL;
+ }
+
+ if (filter_idx >= NIG_REG_LLH_FUNC_FILTER_EN_SIZE) {
+ DP_NOTICE(cdev,
+ "LLH shadow [%s]: using filter_idx %d while only %d filters are available\n",
+ action, filter_idx, NIG_REG_LLH_FUNC_FILTER_EN_SIZE);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+#define QED_LLH_INVALID_FILTER_IDX 0xff
+
+static int
+qed_llh_shadow_search_filter(struct qed_dev *cdev,
+ u8 ppfid,
+ union qed_llh_filter *p_filter, u8 *p_filter_idx)
+{
+ struct qed_llh_info *p_llh_info = cdev->p_llh_info;
+ struct qed_llh_filter_info *p_filters;
+ int rc;
+ u8 i;
+
+ rc = qed_llh_shadow_sanity(cdev, ppfid, 0, "search");
+ if (rc)
+ return rc;
+
+ *p_filter_idx = QED_LLH_INVALID_FILTER_IDX;
+
+ p_filters = p_llh_info->pp_filters[ppfid];
+ for (i = 0; i < NIG_REG_LLH_FUNC_FILTER_EN_SIZE; i++) {
+ if (!memcmp(p_filter, &p_filters[i].filter,
+ sizeof(*p_filter))) {
+ *p_filter_idx = i;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int
+qed_llh_shadow_get_free_idx(struct qed_dev *cdev, u8 ppfid, u8 *p_filter_idx)
+{
+ struct qed_llh_info *p_llh_info = cdev->p_llh_info;
+ struct qed_llh_filter_info *p_filters;
+ int rc;
+ u8 i;
+
+ rc = qed_llh_shadow_sanity(cdev, ppfid, 0, "get_free_idx");
+ if (rc)
+ return rc;
+
+ *p_filter_idx = QED_LLH_INVALID_FILTER_IDX;
+
+ p_filters = p_llh_info->pp_filters[ppfid];
+ for (i = 0; i < NIG_REG_LLH_FUNC_FILTER_EN_SIZE; i++) {
+ if (!p_filters[i].b_enabled) {
+ *p_filter_idx = i;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int
+__qed_llh_shadow_add_filter(struct qed_dev *cdev,
+ u8 ppfid,
+ u8 filter_idx,
+ enum qed_llh_filter_type type,
+ union qed_llh_filter *p_filter, u32 *p_ref_cnt)
+{
+ struct qed_llh_info *p_llh_info = cdev->p_llh_info;
+ struct qed_llh_filter_info *p_filters;
+ int rc;
+
+ rc = qed_llh_shadow_sanity(cdev, ppfid, filter_idx, "add");
+ if (rc)
+ return rc;
+
+ p_filters = p_llh_info->pp_filters[ppfid];
+ if (!p_filters[filter_idx].ref_cnt) {
+ p_filters[filter_idx].b_enabled = true;
+ p_filters[filter_idx].type = type;
+ memcpy(&p_filters[filter_idx].filter, p_filter,
+ sizeof(p_filters[filter_idx].filter));
+ }
+
+ *p_ref_cnt = ++p_filters[filter_idx].ref_cnt;
+
+ return 0;
+}
+
+static int
+qed_llh_shadow_add_filter(struct qed_dev *cdev,
+ u8 ppfid,
+ enum qed_llh_filter_type type,
+ union qed_llh_filter *p_filter,
+ u8 *p_filter_idx, u32 *p_ref_cnt)
+{
+ int rc;
+
+ /* Check if the same filter already exist */
+ rc = qed_llh_shadow_search_filter(cdev, ppfid, p_filter, p_filter_idx);
+ if (rc)
+ return rc;
+
+ /* Find a new entry in case of a new filter */
+ if (*p_filter_idx == QED_LLH_INVALID_FILTER_IDX) {
+ rc = qed_llh_shadow_get_free_idx(cdev, ppfid, p_filter_idx);
+ if (rc)
+ return rc;
+ }
+
+ /* No free entry was found */
+ if (*p_filter_idx == QED_LLH_INVALID_FILTER_IDX) {
+ DP_NOTICE(cdev,
+ "Failed to find an empty LLH filter to utilize [ppfid %d]\n",
+ ppfid);
+ return -EINVAL;
+ }
+
+ return __qed_llh_shadow_add_filter(cdev, ppfid, *p_filter_idx, type,
+ p_filter, p_ref_cnt);
+}
+
+static int
+__qed_llh_shadow_remove_filter(struct qed_dev *cdev,
+ u8 ppfid, u8 filter_idx, u32 *p_ref_cnt)
+{
+ struct qed_llh_info *p_llh_info = cdev->p_llh_info;
+ struct qed_llh_filter_info *p_filters;
+ int rc;
+
+ rc = qed_llh_shadow_sanity(cdev, ppfid, filter_idx, "remove");
+ if (rc)
+ return rc;
+
+ p_filters = p_llh_info->pp_filters[ppfid];
+ if (!p_filters[filter_idx].ref_cnt) {
+ DP_NOTICE(cdev,
+ "LLH shadow: trying to remove a filter with ref_cnt=0\n");
+ return -EINVAL;
+ }
+
+ *p_ref_cnt = --p_filters[filter_idx].ref_cnt;
+ if (!p_filters[filter_idx].ref_cnt)
+ memset(&p_filters[filter_idx],
+ 0, sizeof(p_filters[filter_idx]));
+
+ return 0;
+}
+
+static int
+qed_llh_shadow_remove_filter(struct qed_dev *cdev,
+ u8 ppfid,
+ union qed_llh_filter *p_filter,
+ u8 *p_filter_idx, u32 *p_ref_cnt)
+{
+ int rc;
+
+ rc = qed_llh_shadow_search_filter(cdev, ppfid, p_filter, p_filter_idx);
+ if (rc)
+ return rc;
+
+ /* No matching filter was found */
+ if (*p_filter_idx == QED_LLH_INVALID_FILTER_IDX) {
+ DP_NOTICE(cdev, "Failed to find a filter in the LLH shadow\n");
+ return -EINVAL;
+ }
+
+ return __qed_llh_shadow_remove_filter(cdev, ppfid, *p_filter_idx,
+ p_ref_cnt);
+}
+
+static int qed_llh_abs_ppfid(struct qed_dev *cdev, u8 ppfid, u8 *p_abs_ppfid)
+{
+ struct qed_llh_info *p_llh_info = cdev->p_llh_info;
+
+ if (ppfid >= p_llh_info->num_ppfid) {
+ DP_NOTICE(cdev,
+ "ppfid %d is not valid, available indices are 0..%hhd\n",
+ ppfid, p_llh_info->num_ppfid - 1);
+ *p_abs_ppfid = 0;
+ return -EINVAL;
+ }
+
+ *p_abs_ppfid = p_llh_info->ppfid_array[ppfid];
+
+ return 0;
+}
+
+static int
+qed_llh_set_engine_affin(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
+{
+ struct qed_dev *cdev = p_hwfn->cdev;
+ enum qed_eng eng;
+ u8 ppfid;
+ int rc;
+
+ rc = qed_mcp_get_engine_config(p_hwfn, p_ptt);
+ if (rc != 0 && rc != -EOPNOTSUPP) {
+ DP_NOTICE(p_hwfn,
+ "Failed to get the engine affinity configuration\n");
+ return rc;
+ }
+
+ /* RoCE PF is bound to a single engine */
+ if (QED_IS_ROCE_PERSONALITY(p_hwfn)) {
+ eng = cdev->fir_affin ? QED_ENG1 : QED_ENG0;
+ rc = qed_llh_set_roce_affinity(cdev, eng);
+ if (rc) {
+ DP_NOTICE(cdev,
+ "Failed to set the RoCE engine affinity\n");
+ return rc;
+ }
+
+ DP_VERBOSE(cdev,
+ QED_MSG_SP,
+ "LLH: Set the engine affinity of RoCE packets as %d\n",
+ eng);
+ }
+
+ /* Storage PF is bound to a single engine while L2 PF uses both */
+ if (QED_IS_FCOE_PERSONALITY(p_hwfn) || QED_IS_ISCSI_PERSONALITY(p_hwfn))
+ eng = cdev->fir_affin ? QED_ENG1 : QED_ENG0;
+ else /* L2_PERSONALITY */
+ eng = QED_BOTH_ENG;
+
+ for (ppfid = 0; ppfid < cdev->p_llh_info->num_ppfid; ppfid++) {
+ rc = qed_llh_set_ppfid_affinity(cdev, ppfid, eng);
+ if (rc) {
+ DP_NOTICE(cdev,
+ "Failed to set the engine affinity of ppfid %d\n",
+ ppfid);
+ return rc;
+ }
+ }
+
+ DP_VERBOSE(cdev, QED_MSG_SP,
+ "LLH: Set the engine affinity of non-RoCE packets as %d\n",
+ eng);
+
+ return 0;
+}
+
+static int qed_llh_hw_init_pf(struct qed_hwfn *p_hwfn,
+ struct qed_ptt *p_ptt)
+{
+ struct qed_dev *cdev = p_hwfn->cdev;
+ u8 ppfid, abs_ppfid;
+ int rc;
+
+ for (ppfid = 0; ppfid < cdev->p_llh_info->num_ppfid; ppfid++) {
+ u32 addr;
+
+ rc = qed_llh_abs_ppfid(cdev, ppfid, &abs_ppfid);
+ if (rc)
+ return rc;
+
+ addr = NIG_REG_LLH_PPFID2PFID_TBL_0 + abs_ppfid * 0x4;
+ qed_wr(p_hwfn, p_ptt, addr, p_hwfn->rel_pf_id);
+ }
+
+ if (test_bit(QED_MF_LLH_MAC_CLSS, &cdev->mf_bits) &&
+ !QED_IS_FCOE_PERSONALITY(p_hwfn)) {
+ rc = qed_llh_add_mac_filter(cdev, 0,
+ p_hwfn->hw_info.hw_mac_addr);
+ if (rc)
+ DP_NOTICE(cdev,
+ "Failed to add an LLH filter with the primary MAC\n");
+ }
+
+ if (QED_IS_CMT(cdev)) {
+ rc = qed_llh_set_engine_affin(p_hwfn, p_ptt);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+u8 qed_llh_get_num_ppfid(struct qed_dev *cdev)
+{
+ return cdev->p_llh_info->num_ppfid;
+}
+
+#define NIG_REG_PPF_TO_ENGINE_SEL_ROCE_MASK 0x3
+#define NIG_REG_PPF_TO_ENGINE_SEL_ROCE_SHIFT 0
+#define NIG_REG_PPF_TO_ENGINE_SEL_NON_ROCE_MASK 0x3
+#define NIG_REG_PPF_TO_ENGINE_SEL_NON_ROCE_SHIFT 2
+
+int qed_llh_set_ppfid_affinity(struct qed_dev *cdev, u8 ppfid, enum qed_eng eng)
+{
+ struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
+ struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn);
+ u32 addr, val, eng_sel;
+ u8 abs_ppfid;
+ int rc = 0;
+
+ if (!p_ptt)
+ return -EAGAIN;
+
+ if (!QED_IS_CMT(cdev))
+ goto out;
+
+ rc = qed_llh_abs_ppfid(cdev, ppfid, &abs_ppfid);
+ if (rc)
+ goto out;
+
+ switch (eng) {
+ case QED_ENG0:
+ eng_sel = 0;
+ break;
+ case QED_ENG1:
+ eng_sel = 1;
+ break;
+ case QED_BOTH_ENG:
+ eng_sel = 2;
+ break;
+ default:
+ DP_NOTICE(cdev, "Invalid affinity value for ppfid [%d]\n", eng);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ addr = NIG_REG_PPF_TO_ENGINE_SEL + abs_ppfid * 0x4;
+ val = qed_rd(p_hwfn, p_ptt, addr);
+ SET_FIELD(val, NIG_REG_PPF_TO_ENGINE_SEL_NON_ROCE, eng_sel);
+ qed_wr(p_hwfn, p_ptt, addr, val);
+
+ /* The iWARP affinity is set as the affinity of ppfid 0 */
+ if (!ppfid && QED_IS_IWARP_PERSONALITY(p_hwfn))
+ cdev->iwarp_affin = (eng == QED_ENG1) ? 1 : 0;
+out:
+ qed_ptt_release(p_hwfn, p_ptt);
+
+ return rc;
+}
+
+int qed_llh_set_roce_affinity(struct qed_dev *cdev, enum qed_eng eng)
+{
+ struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
+ struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn);
+ u32 addr, val, eng_sel;
+ u8 ppfid, abs_ppfid;
+ int rc = 0;
+
+ if (!p_ptt)
+ return -EAGAIN;
+
+ if (!QED_IS_CMT(cdev))
+ goto out;
+
+ switch (eng) {
+ case QED_ENG0:
+ eng_sel = 0;
+ break;
+ case QED_ENG1:
+ eng_sel = 1;
+ break;
+ case QED_BOTH_ENG:
+ eng_sel = 2;
+ qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_ENG_CLS_ROCE_QP_SEL,
+ 0xf); /* QP bit 15 */
+ break;
+ default:
+ DP_NOTICE(cdev, "Invalid affinity value for RoCE [%d]\n", eng);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ for (ppfid = 0; ppfid < cdev->p_llh_info->num_ppfid; ppfid++) {
+ rc = qed_llh_abs_ppfid(cdev, ppfid, &abs_ppfid);
+ if (rc)
+ goto out;
+
+ addr = NIG_REG_PPF_TO_ENGINE_SEL + abs_ppfid * 0x4;
+ val = qed_rd(p_hwfn, p_ptt, addr);
+ SET_FIELD(val, NIG_REG_PPF_TO_ENGINE_SEL_ROCE, eng_sel);
+ qed_wr(p_hwfn, p_ptt, addr, val);
+ }
+out:
+ qed_ptt_release(p_hwfn, p_ptt);
+
+ return rc;
+}
+
+struct qed_llh_filter_details {
+ u64 value;
+ u32 mode;
+ u32 protocol_type;
+ u32 hdr_sel;
+ u32 enable;
+};
+
+static int
+qed_llh_access_filter(struct qed_hwfn *p_hwfn,
+ struct qed_ptt *p_ptt,
+ u8 abs_ppfid,
+ u8 filter_idx,
+ struct qed_llh_filter_details *p_details)
+{
+ struct qed_dmae_params params = {0};
+ u32 addr;
+ u8 pfid;
+ int rc;
+
+ /* The NIG/LLH registers that are accessed in this function have only 16
+ * rows which are exposed to a PF. I.e. only the 16 filters of its
+ * default ppfid. Accessing filters of other ppfids requires pretending
+ * to another PFs.
+ * The calculation of PPFID->PFID in AH is based on the relative index
+ * of a PF on its port.
+ * For BB the pfid is actually the abs_ppfid.
+ */
+ if (QED_IS_BB(p_hwfn->cdev))
+ pfid = abs_ppfid;
+ else
+ pfid = abs_ppfid * p_hwfn->cdev->num_ports_in_engine +
+ MFW_PORT(p_hwfn);
+
+ /* Filter enable - should be done first when removing a filter */
+ if (!p_details->enable) {
+ qed_fid_pretend(p_hwfn, p_ptt,
+ pfid << PXP_PRETEND_CONCRETE_FID_PFID_SHIFT);
+
+ addr = NIG_REG_LLH_FUNC_FILTER_EN + filter_idx * 0x4;
+ qed_wr(p_hwfn, p_ptt, addr, p_details->enable);
+
+ qed_fid_pretend(p_hwfn, p_ptt,
+ p_hwfn->rel_pf_id <<
+ PXP_PRETEND_CONCRETE_FID_PFID_SHIFT);
+ }
+
+ /* Filter value */
+ addr = NIG_REG_LLH_FUNC_FILTER_VALUE + 2 * filter_idx * 0x4;
+
+ params.flags = QED_DMAE_FLAG_PF_DST;
+ params.dst_pfid = pfid;
+ rc = qed_dmae_host2grc(p_hwfn,
+ p_ptt,
+ (u64)(uintptr_t)&p_details->value,
+ addr, 2 /* size_in_dwords */,
+ &params);
+ if (rc)
+ return rc;
+
+ qed_fid_pretend(p_hwfn, p_ptt,
+ pfid << PXP_PRETEND_CONCRETE_FID_PFID_SHIFT);
+
+ /* Filter mode */
+ addr = NIG_REG_LLH_FUNC_FILTER_MODE + filter_idx * 0x4;
+ qed_wr(p_hwfn, p_ptt, addr, p_details->mode);
+
+ /* Filter protocol type */
+ addr = NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE + filter_idx * 0x4;
+ qed_wr(p_hwfn, p_ptt, addr, p_details->protocol_type);
+
+ /* Filter header select */
+ addr = NIG_REG_LLH_FUNC_FILTER_HDR_SEL + filter_idx * 0x4;
+ qed_wr(p_hwfn, p_ptt, addr, p_details->hdr_sel);
+
+ /* Filter enable - should be done last when adding a filter */
+ if (p_details->enable) {
+ addr = NIG_REG_LLH_FUNC_FILTER_EN + filter_idx * 0x4;
+ qed_wr(p_hwfn, p_ptt, addr, p_details->enable);
+ }
+
+ qed_fid_pretend(p_hwfn, p_ptt,
+ p_hwfn->rel_pf_id <<
+ PXP_PRETEND_CONCRETE_FID_PFID_SHIFT);
+
+ return 0;
+}
+
+static int
+qed_llh_add_filter(struct qed_hwfn *p_hwfn,
+ struct qed_ptt *p_ptt,
+ u8 abs_ppfid,
+ u8 filter_idx, u8 filter_prot_type, u32 high, u32 low)
+{
+ struct qed_llh_filter_details filter_details;
+
+ filter_details.enable = 1;
+ filter_details.value = ((u64)high << 32) | low;
+ filter_details.hdr_sel = 0;
+ filter_details.protocol_type = filter_prot_type;
+ /* Mode: 0: MAC-address classification 1: protocol classification */
+ filter_details.mode = filter_prot_type ? 1 : 0;
+
+ return qed_llh_access_filter(p_hwfn, p_ptt, abs_ppfid, filter_idx,
+ &filter_details);
+}
+
+static int
+qed_llh_remove_filter(struct qed_hwfn *p_hwfn,
+ struct qed_ptt *p_ptt, u8 abs_ppfid, u8 filter_idx)
+{
+ struct qed_llh_filter_details filter_details = {0};
+
+ return qed_llh_access_filter(p_hwfn, p_ptt, abs_ppfid, filter_idx,
+ &filter_details);
+}
+
+int qed_llh_add_mac_filter(struct qed_dev *cdev,
+ u8 ppfid, u8 mac_addr[ETH_ALEN])
+{
+ struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
+ struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn);
+ union qed_llh_filter filter = {};
+ u8 filter_idx, abs_ppfid;
+ u32 high, low, ref_cnt;
+ int rc = 0;
+
+ if (!p_ptt)
+ return -EAGAIN;
+
+ if (!test_bit(QED_MF_LLH_MAC_CLSS, &cdev->mf_bits))
+ goto out;
+
+ memcpy(filter.mac.addr, mac_addr, ETH_ALEN);
+ rc = qed_llh_shadow_add_filter(cdev, ppfid,
+ QED_LLH_FILTER_TYPE_MAC,
+ &filter, &filter_idx, &ref_cnt);
+ if (rc)
+ goto err;
+
+ /* Configure the LLH only in case of a new the filter */
+ if (ref_cnt == 1) {
+ rc = qed_llh_abs_ppfid(cdev, ppfid, &abs_ppfid);
+ if (rc)
+ goto err;
+
+ high = mac_addr[1] | (mac_addr[0] << 8);
+ low = mac_addr[5] | (mac_addr[4] << 8) | (mac_addr[3] << 16) |
+ (mac_addr[2] << 24);
+ rc = qed_llh_add_filter(p_hwfn, p_ptt, abs_ppfid, filter_idx,
+ 0, high, low);
+ if (rc)
+ goto err;
+ }
+
+ DP_VERBOSE(cdev,
+ QED_MSG_SP,
+ "LLH: Added MAC filter [%pM] to ppfid %hhd [abs %hhd] at idx %hhd [ref_cnt %d]\n",
+ mac_addr, ppfid, abs_ppfid, filter_idx, ref_cnt);
+
+ goto out;
+
+err: DP_NOTICE(cdev,
+ "LLH: Failed to add MAC filter [%pM] to ppfid %hhd\n",
+ mac_addr, ppfid);
+out:
+ qed_ptt_release(p_hwfn, p_ptt);
+
+ return rc;
+}
+
+static int
+qed_llh_protocol_filter_stringify(struct qed_dev *cdev,
+ enum qed_llh_prot_filter_type_t type,
+ u16 source_port_or_eth_type,
+ u16 dest_port, u8 *str, size_t str_len)
+{
+ switch (type) {
+ case QED_LLH_FILTER_ETHERTYPE:
+ snprintf(str, str_len, "Ethertype 0x%04x",
+ source_port_or_eth_type);
+ break;
+ case QED_LLH_FILTER_TCP_SRC_PORT:
+ snprintf(str, str_len, "TCP src port 0x%04x",
+ source_port_or_eth_type);
+ break;
+ case QED_LLH_FILTER_UDP_SRC_PORT:
+ snprintf(str, str_len, "UDP src port 0x%04x",
+ source_port_or_eth_type);
+ break;
+ case QED_LLH_FILTER_TCP_DEST_PORT:
+ snprintf(str, str_len, "TCP dst port 0x%04x", dest_port);
+ break;
+ case QED_LLH_FILTER_UDP_DEST_PORT:
+ snprintf(str, str_len, "UDP dst port 0x%04x", dest_port);
+ break;
+ case QED_LLH_FILTER_TCP_SRC_AND_DEST_PORT:
+ snprintf(str, str_len, "TCP src/dst ports 0x%04x/0x%04x",
+ source_port_or_eth_type, dest_port);
+ break;
+ case QED_LLH_FILTER_UDP_SRC_AND_DEST_PORT:
+ snprintf(str, str_len, "UDP src/dst ports 0x%04x/0x%04x",
+ source_port_or_eth_type, dest_port);
+ break;
+ default:
+ DP_NOTICE(cdev,
+ "Non valid LLH protocol filter type %d\n", type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+qed_llh_protocol_filter_to_hilo(struct qed_dev *cdev,
+ enum qed_llh_prot_filter_type_t type,
+ u16 source_port_or_eth_type,
+ u16 dest_port, u32 *p_high, u32 *p_low)
+{
+ *p_high = 0;
+ *p_low = 0;
+
+ switch (type) {
+ case QED_LLH_FILTER_ETHERTYPE:
+ *p_high = source_port_or_eth_type;
+ break;
+ case QED_LLH_FILTER_TCP_SRC_PORT:
+ case QED_LLH_FILTER_UDP_SRC_PORT:
+ *p_low = source_port_or_eth_type << 16;
+ break;
+ case QED_LLH_FILTER_TCP_DEST_PORT:
+ case QED_LLH_FILTER_UDP_DEST_PORT:
+ *p_low = dest_port;
+ break;
+ case QED_LLH_FILTER_TCP_SRC_AND_DEST_PORT:
+ case QED_LLH_FILTER_UDP_SRC_AND_DEST_PORT:
+ *p_low = (source_port_or_eth_type << 16) | dest_port;
+ break;
+ default:
+ DP_NOTICE(cdev,
+ "Non valid LLH protocol filter type %d\n", type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int
+qed_llh_add_protocol_filter(struct qed_dev *cdev,
+ u8 ppfid,
+ enum qed_llh_prot_filter_type_t type,
+ u16 source_port_or_eth_type, u16 dest_port)
+{
+ struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
+ struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn);
+ u8 filter_idx, abs_ppfid, str[32], type_bitmap;
+ union qed_llh_filter filter = {};
+ u32 high, low, ref_cnt;
+ int rc = 0;
+
+ if (!p_ptt)
+ return -EAGAIN;
+
+ if (!test_bit(QED_MF_LLH_PROTO_CLSS, &cdev->mf_bits))
+ goto out;
+
+ rc = qed_llh_protocol_filter_stringify(cdev, type,
+ source_port_or_eth_type,
+ dest_port, str, sizeof(str));
+ if (rc)
+ goto err;
+
+ filter.protocol.type = type;
+ filter.protocol.source_port_or_eth_type = source_port_or_eth_type;
+ filter.protocol.dest_port = dest_port;
+ rc = qed_llh_shadow_add_filter(cdev,
+ ppfid,
+ QED_LLH_FILTER_TYPE_PROTOCOL,
+ &filter, &filter_idx, &ref_cnt);
+ if (rc)
+ goto err;
+
+ rc = qed_llh_abs_ppfid(cdev, ppfid, &abs_ppfid);
+ if (rc)
+ goto err;
+
+ /* Configure the LLH only in case of a new the filter */
+ if (ref_cnt == 1) {
+ rc = qed_llh_protocol_filter_to_hilo(cdev, type,
+ source_port_or_eth_type,
+ dest_port, &high, &low);
+ if (rc)
+ goto err;
+
+ type_bitmap = 0x1 << type;
+ rc = qed_llh_add_filter(p_hwfn, p_ptt, abs_ppfid,
+ filter_idx, type_bitmap, high, low);
+ if (rc)
+ goto err;
+ }
+
+ DP_VERBOSE(cdev,
+ QED_MSG_SP,
+ "LLH: Added protocol filter [%s] to ppfid %hhd [abs %hhd] at idx %hhd [ref_cnt %d]\n",
+ str, ppfid, abs_ppfid, filter_idx, ref_cnt);
+
+ goto out;
+
+err: DP_NOTICE(p_hwfn,
+ "LLH: Failed to add protocol filter [%s] to ppfid %hhd\n",
+ str, ppfid);
+out:
+ qed_ptt_release(p_hwfn, p_ptt);
+
+ return rc;
+}
+
+void qed_llh_remove_mac_filter(struct qed_dev *cdev,
+ u8 ppfid, u8 mac_addr[ETH_ALEN])
+{
+ struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
+ struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn);
+ union qed_llh_filter filter = {};
+ u8 filter_idx, abs_ppfid;
+ int rc = 0;
+ u32 ref_cnt;
+
+ if (!p_ptt)
+ return;
+
+ if (!test_bit(QED_MF_LLH_MAC_CLSS, &cdev->mf_bits))
+ goto out;
+
+ ether_addr_copy(filter.mac.addr, mac_addr);
+ rc = qed_llh_shadow_remove_filter(cdev, ppfid, &filter, &filter_idx,
+ &ref_cnt);
+ if (rc)
+ goto err;
+
+ rc = qed_llh_abs_ppfid(cdev, ppfid, &abs_ppfid);
+ if (rc)
+ goto err;
+
+ /* Remove from the LLH in case the filter is not in use */
+ if (!ref_cnt) {
+ rc = qed_llh_remove_filter(p_hwfn, p_ptt, abs_ppfid,
+ filter_idx);
+ if (rc)
+ goto err;
+ }
+
+ DP_VERBOSE(cdev,
+ QED_MSG_SP,
+ "LLH: Removed MAC filter [%pM] from ppfid %hhd [abs %hhd] at idx %hhd [ref_cnt %d]\n",
+ mac_addr, ppfid, abs_ppfid, filter_idx, ref_cnt);
+
+ goto out;
+
+err: DP_NOTICE(cdev,
+ "LLH: Failed to remove MAC filter [%pM] from ppfid %hhd\n",
+ mac_addr, ppfid);
+out:
+ qed_ptt_release(p_hwfn, p_ptt);
+}
+
+void qed_llh_remove_protocol_filter(struct qed_dev *cdev,
+ u8 ppfid,
+ enum qed_llh_prot_filter_type_t type,
+ u16 source_port_or_eth_type, u16 dest_port)
+{
+ struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
+ struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn);
+ u8 filter_idx, abs_ppfid, str[32];
+ union qed_llh_filter filter = {};
+ int rc = 0;
+ u32 ref_cnt;
+
+ if (!p_ptt)
+ return;
+
+ if (!test_bit(QED_MF_LLH_PROTO_CLSS, &cdev->mf_bits))
+ goto out;
+
+ rc = qed_llh_protocol_filter_stringify(cdev, type,
+ source_port_or_eth_type,
+ dest_port, str, sizeof(str));
+ if (rc)
+ goto err;
+
+ filter.protocol.type = type;
+ filter.protocol.source_port_or_eth_type = source_port_or_eth_type;
+ filter.protocol.dest_port = dest_port;
+ rc = qed_llh_shadow_remove_filter(cdev, ppfid, &filter, &filter_idx,
+ &ref_cnt);
+ if (rc)
+ goto err;
+
+ rc = qed_llh_abs_ppfid(cdev, ppfid, &abs_ppfid);
+ if (rc)
+ goto err;
+
+ /* Remove from the LLH in case the filter is not in use */
+ if (!ref_cnt) {
+ rc = qed_llh_remove_filter(p_hwfn, p_ptt, abs_ppfid,
+ filter_idx);
+ if (rc)
+ goto err;
+ }
+
+ DP_VERBOSE(cdev,
+ QED_MSG_SP,
+ "LLH: Removed protocol filter [%s] from ppfid %hhd [abs %hhd] at idx %hhd [ref_cnt %d]\n",
+ str, ppfid, abs_ppfid, filter_idx, ref_cnt);
+
+ goto out;
+
+err: DP_NOTICE(cdev,
+ "LLH: Failed to remove protocol filter [%s] from ppfid %hhd\n",
+ str, ppfid);
+out:
+ qed_ptt_release(p_hwfn, p_ptt);
+}
+
+/******************************* NIG LLH - End ********************************/
+
#define QED_MIN_DPIS (4)
#define QED_MIN_PWM_REGION (QED_WID_SIZE * QED_MIN_DPIS)
@@ -461,6 +1382,8 @@ void qed_resc_free(struct qed_dev *cdev)
kfree(cdev->reset_stats);
cdev->reset_stats = NULL;
+ qed_llh_free(cdev);
+
for_each_hwfn(cdev, i) {
struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
@@ -1428,6 +2351,13 @@ int qed_resc_alloc(struct qed_dev *cdev)
goto alloc_err;
}
+ rc = qed_llh_alloc(cdev);
+ if (rc) {
+ DP_NOTICE(cdev,
+ "Failed to allocate memory for the llh_info structure\n");
+ goto alloc_err;
+ }
+
cdev->reset_stats = kzalloc(sizeof(*cdev->reset_stats), GFP_KERNEL);
if (!cdev->reset_stats)
goto alloc_no_mem;
@@ -1879,6 +2809,10 @@ static int qed_hw_init_port(struct qed_hwfn *p_hwfn,
{
int rc = 0;
+ /* In CMT the gate should be cleared by the 2nd hwfn */
+ if (!QED_IS_CMT(p_hwfn->cdev) || !IS_LEAD_HWFN(p_hwfn))
+ STORE_RT_REG(p_hwfn, NIG_REG_BRB_GATE_DNTFWD_PORT_RT_OFFSET, 0);
+
rc = qed_init_run(p_hwfn, p_ptt, PHASE_PORT, p_hwfn->port_id, hw_mode);
if (rc)
return rc;
@@ -1964,6 +2898,13 @@ static int qed_hw_init_pf(struct qed_hwfn *p_hwfn,
if (rc)
return rc;
+ /* Use the leading hwfn since in CMT only NIG #0 is operational */
+ if (IS_LEAD_HWFN(p_hwfn)) {
+ rc = qed_llh_hw_init_pf(p_hwfn, p_ptt);
+ if (rc)
+ return rc;
+ }
+
if (b_hw_start) {
/* enable interrupts */
qed_int_igu_enable(p_hwfn, p_ptt, int_mode);
@@ -2393,6 +3334,12 @@ int qed_hw_stop(struct qed_dev *cdev)
qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_DB_ENABLE, 0);
qed_wr(p_hwfn, p_ptt, QM_REG_PF_EN, 0);
+ if (IS_LEAD_HWFN(p_hwfn) &&
+ test_bit(QED_MF_LLH_MAC_CLSS, &cdev->mf_bits) &&
+ !QED_IS_FCOE_PERSONALITY(p_hwfn))
+ qed_llh_remove_mac_filter(cdev, 0,
+ p_hwfn->hw_info.hw_mac_addr);
+
if (!cdev->recov_in_prog) {
rc = qed_mcp_unload_done(p_hwfn, p_ptt);
if (rc) {
@@ -2868,6 +3815,36 @@ static int qed_hw_set_resc_info(struct qed_hwfn *p_hwfn)
return 0;
}
+static int qed_hw_get_ppfid_bitmap(struct qed_hwfn *p_hwfn,
+ struct qed_ptt *p_ptt)
+{
+ struct qed_dev *cdev = p_hwfn->cdev;
+ u8 native_ppfid_idx;
+ int rc;
+
+ /* Calculation of BB/AH is different for native_ppfid_idx */
+ if (QED_IS_BB(cdev))
+ native_ppfid_idx = p_hwfn->rel_pf_id;
+ else
+ native_ppfid_idx = p_hwfn->rel_pf_id /
+ cdev->num_ports_in_engine;
+
+ rc = qed_mcp_get_ppfid_bitmap(p_hwfn, p_ptt);
+ if (rc != 0 && rc != -EOPNOTSUPP)
+ return rc;
+ else if (rc == -EOPNOTSUPP)
+ cdev->ppfid_bitmap = 0x1 << native_ppfid_idx;
+
+ if (!(cdev->ppfid_bitmap & (0x1 << native_ppfid_idx))) {
+ DP_INFO(p_hwfn,
+ "Fix the PPFID bitmap to include the native PPFID [native_ppfid_idx %hhd, orig_bitmap 0x%hhx]\n",
+ native_ppfid_idx, cdev->ppfid_bitmap);
+ cdev->ppfid_bitmap = 0x1 << native_ppfid_idx;
+ }
+
+ return 0;
+}
+
static int qed_hw_get_resc(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
{
struct qed_resc_unlock_params resc_unlock_params;
@@ -2925,6 +3902,13 @@ static int qed_hw_get_resc(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
"Failed to release the resource lock for the resource allocation commands\n");
}
+ /* PPFID bitmap */
+ if (IS_LEAD_HWFN(p_hwfn)) {
+ rc = qed_hw_get_ppfid_bitmap(p_hwfn, p_ptt);
+ if (rc)
+ return rc;
+ }
+
/* Sanity for ILT */
if ((b_ah && (RESC_END(p_hwfn, QED_ILT) > PXP_NUM_ILT_RECORDS_K2)) ||
(!b_ah && (RESC_END(p_hwfn, QED_ILT) > PXP_NUM_ILT_RECORDS_BB))) {
@@ -3443,6 +4427,7 @@ static void qed_nvm_info_free(struct qed_hwfn *p_hwfn)
static int qed_hw_prepare_single(struct qed_hwfn *p_hwfn,
void __iomem *p_regview,
void __iomem *p_doorbells,
+ u64 db_phys_addr,
enum qed_pci_personality personality)
{
struct qed_dev *cdev = p_hwfn->cdev;
@@ -3451,6 +4436,7 @@ static int qed_hw_prepare_single(struct qed_hwfn *p_hwfn,
/* Split PCI bars evenly between hwfns */
p_hwfn->regview = p_regview;
p_hwfn->doorbells = p_doorbells;
+ p_hwfn->db_phys_addr = db_phys_addr;
if (IS_VF(p_hwfn->cdev))
return qed_vf_hw_prepare(p_hwfn);
@@ -3546,7 +4532,9 @@ int qed_hw_prepare(struct qed_dev *cdev,
/* Initialize the first hwfn - will learn number of hwfns */
rc = qed_hw_prepare_single(p_hwfn,
cdev->regview,
- cdev->doorbells, personality);
+ cdev->doorbells,
+ cdev->db_phys_addr,
+ personality);
if (rc)
return rc;
@@ -3555,22 +4543,25 @@ int qed_hw_prepare(struct qed_dev *cdev,
/* Initialize the rest of the hwfns */
if (cdev->num_hwfns > 1) {
void __iomem *p_regview, *p_doorbell;
- u8 __iomem *addr;
+ u64 db_phys_addr;
+ u32 offset;
/* adjust bar offset for second engine */
- addr = cdev->regview +
- qed_hw_bar_size(p_hwfn, p_hwfn->p_main_ptt,
- BAR_ID_0) / 2;
- p_regview = addr;
+ offset = qed_hw_bar_size(p_hwfn, p_hwfn->p_main_ptt,
+ BAR_ID_0) / 2;
+ p_regview = cdev->regview + offset;
+
+ offset = qed_hw_bar_size(p_hwfn, p_hwfn->p_main_ptt,
+ BAR_ID_1) / 2;
- addr = cdev->doorbells +
- qed_hw_bar_size(p_hwfn, p_hwfn->p_main_ptt,
- BAR_ID_1) / 2;
- p_doorbell = addr;
+ p_doorbell = cdev->doorbells + offset;
+
+ db_phys_addr = cdev->db_phys_addr + offset;
/* prepare second hw function */
rc = qed_hw_prepare_single(&cdev->hwfns[1], p_regview,
- p_doorbell, personality);
+ p_doorbell, db_phys_addr,
+ personality);
/* in case of error, need to free the previously
* initiliazed hwfn 0.
@@ -3951,269 +4942,6 @@ int qed_fw_rss_eng(struct qed_hwfn *p_hwfn, u8 src_id, u8 *dst_id)
return 0;
}
-static void qed_llh_mac_to_filter(u32 *p_high, u32 *p_low,
- u8 *p_filter)
-{
- *p_high = p_filter[1] | (p_filter[0] << 8);
- *p_low = p_filter[5] | (p_filter[4] << 8) |
- (p_filter[3] << 16) | (p_filter[2] << 24);
-}
-
-int qed_llh_add_mac_filter(struct qed_hwfn *p_hwfn,
- struct qed_ptt *p_ptt, u8 *p_filter)
-{
- u32 high = 0, low = 0, en;
- int i;
-
- if (!test_bit(QED_MF_LLH_MAC_CLSS, &p_hwfn->cdev->mf_bits))
- return 0;
-
- qed_llh_mac_to_filter(&high, &low, p_filter);
-
- /* Find a free entry and utilize it */
- for (i = 0; i < NIG_REG_LLH_FUNC_FILTER_EN_SIZE; i++) {
- en = qed_rd(p_hwfn, p_ptt,
- NIG_REG_LLH_FUNC_FILTER_EN + i * sizeof(u32));
- if (en)
- continue;
- qed_wr(p_hwfn, p_ptt,
- NIG_REG_LLH_FUNC_FILTER_VALUE +
- 2 * i * sizeof(u32), low);
- qed_wr(p_hwfn, p_ptt,
- NIG_REG_LLH_FUNC_FILTER_VALUE +
- (2 * i + 1) * sizeof(u32), high);
- qed_wr(p_hwfn, p_ptt,
- NIG_REG_LLH_FUNC_FILTER_MODE + i * sizeof(u32), 0);
- qed_wr(p_hwfn, p_ptt,
- NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE +
- i * sizeof(u32), 0);
- qed_wr(p_hwfn, p_ptt,
- NIG_REG_LLH_FUNC_FILTER_EN + i * sizeof(u32), 1);
- break;
- }
- if (i >= NIG_REG_LLH_FUNC_FILTER_EN_SIZE) {
- DP_NOTICE(p_hwfn,
- "Failed to find an empty LLH filter to utilize\n");
- return -EINVAL;
- }
-
- DP_VERBOSE(p_hwfn, NETIF_MSG_HW,
- "mac: %pM is added at %d\n",
- p_filter, i);
-
- return 0;
-}
-
-void qed_llh_remove_mac_filter(struct qed_hwfn *p_hwfn,
- struct qed_ptt *p_ptt, u8 *p_filter)
-{
- u32 high = 0, low = 0;
- int i;
-
- if (!test_bit(QED_MF_LLH_MAC_CLSS, &p_hwfn->cdev->mf_bits))
- return;
-
- qed_llh_mac_to_filter(&high, &low, p_filter);
-
- /* Find the entry and clean it */
- for (i = 0; i < NIG_REG_LLH_FUNC_FILTER_EN_SIZE; i++) {
- if (qed_rd(p_hwfn, p_ptt,
- NIG_REG_LLH_FUNC_FILTER_VALUE +
- 2 * i * sizeof(u32)) != low)
- continue;
- if (qed_rd(p_hwfn, p_ptt,
- NIG_REG_LLH_FUNC_FILTER_VALUE +
- (2 * i + 1) * sizeof(u32)) != high)
- continue;
-
- qed_wr(p_hwfn, p_ptt,
- NIG_REG_LLH_FUNC_FILTER_EN + i * sizeof(u32), 0);
- qed_wr(p_hwfn, p_ptt,
- NIG_REG_LLH_FUNC_FILTER_VALUE + 2 * i * sizeof(u32), 0);
- qed_wr(p_hwfn, p_ptt,
- NIG_REG_LLH_FUNC_FILTER_VALUE +
- (2 * i + 1) * sizeof(u32), 0);
-
- DP_VERBOSE(p_hwfn, NETIF_MSG_HW,
- "mac: %pM is removed from %d\n",
- p_filter, i);
- break;
- }
- if (i >= NIG_REG_LLH_FUNC_FILTER_EN_SIZE)
- DP_NOTICE(p_hwfn, "Tried to remove a non-configured filter\n");
-}
-
-int
-qed_llh_add_protocol_filter(struct qed_hwfn *p_hwfn,
- struct qed_ptt *p_ptt,
- u16 source_port_or_eth_type,
- u16 dest_port, enum qed_llh_port_filter_type_t type)
-{
- u32 high = 0, low = 0, en;
- int i;
-
- if (!test_bit(QED_MF_LLH_PROTO_CLSS, &p_hwfn->cdev->mf_bits))
- return 0;
-
- switch (type) {
- case QED_LLH_FILTER_ETHERTYPE:
- high = source_port_or_eth_type;
- break;
- case QED_LLH_FILTER_TCP_SRC_PORT:
- case QED_LLH_FILTER_UDP_SRC_PORT:
- low = source_port_or_eth_type << 16;
- break;
- case QED_LLH_FILTER_TCP_DEST_PORT:
- case QED_LLH_FILTER_UDP_DEST_PORT:
- low = dest_port;
- break;
- case QED_LLH_FILTER_TCP_SRC_AND_DEST_PORT:
- case QED_LLH_FILTER_UDP_SRC_AND_DEST_PORT:
- low = (source_port_or_eth_type << 16) | dest_port;
- break;
- default:
- DP_NOTICE(p_hwfn,
- "Non valid LLH protocol filter type %d\n", type);
- return -EINVAL;
- }
- /* Find a free entry and utilize it */
- for (i = 0; i < NIG_REG_LLH_FUNC_FILTER_EN_SIZE; i++) {
- en = qed_rd(p_hwfn, p_ptt,
- NIG_REG_LLH_FUNC_FILTER_EN + i * sizeof(u32));
- if (en)
- continue;
- qed_wr(p_hwfn, p_ptt,
- NIG_REG_LLH_FUNC_FILTER_VALUE +
- 2 * i * sizeof(u32), low);
- qed_wr(p_hwfn, p_ptt,
- NIG_REG_LLH_FUNC_FILTER_VALUE +
- (2 * i + 1) * sizeof(u32), high);
- qed_wr(p_hwfn, p_ptt,
- NIG_REG_LLH_FUNC_FILTER_MODE + i * sizeof(u32), 1);
- qed_wr(p_hwfn, p_ptt,
- NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE +
- i * sizeof(u32), 1 << type);
- qed_wr(p_hwfn, p_ptt,
- NIG_REG_LLH_FUNC_FILTER_EN + i * sizeof(u32), 1);
- break;
- }
- if (i >= NIG_REG_LLH_FUNC_FILTER_EN_SIZE) {
- DP_NOTICE(p_hwfn,
- "Failed to find an empty LLH filter to utilize\n");
- return -EINVAL;
- }
- switch (type) {
- case QED_LLH_FILTER_ETHERTYPE:
- DP_VERBOSE(p_hwfn, NETIF_MSG_HW,
- "ETH type %x is added at %d\n",
- source_port_or_eth_type, i);
- break;
- case QED_LLH_FILTER_TCP_SRC_PORT:
- DP_VERBOSE(p_hwfn, NETIF_MSG_HW,
- "TCP src port %x is added at %d\n",
- source_port_or_eth_type, i);
- break;
- case QED_LLH_FILTER_UDP_SRC_PORT:
- DP_VERBOSE(p_hwfn, NETIF_MSG_HW,
- "UDP src port %x is added at %d\n",
- source_port_or_eth_type, i);
- break;
- case QED_LLH_FILTER_TCP_DEST_PORT:
- DP_VERBOSE(p_hwfn, NETIF_MSG_HW,
- "TCP dst port %x is added at %d\n", dest_port, i);
- break;
- case QED_LLH_FILTER_UDP_DEST_PORT:
- DP_VERBOSE(p_hwfn, NETIF_MSG_HW,
- "UDP dst port %x is added at %d\n", dest_port, i);
- break;
- case QED_LLH_FILTER_TCP_SRC_AND_DEST_PORT:
- DP_VERBOSE(p_hwfn, NETIF_MSG_HW,
- "TCP src/dst ports %x/%x are added at %d\n",
- source_port_or_eth_type, dest_port, i);
- break;
- case QED_LLH_FILTER_UDP_SRC_AND_DEST_PORT:
- DP_VERBOSE(p_hwfn, NETIF_MSG_HW,
- "UDP src/dst ports %x/%x are added at %d\n",
- source_port_or_eth_type, dest_port, i);
- break;
- }
- return 0;
-}
-
-void
-qed_llh_remove_protocol_filter(struct qed_hwfn *p_hwfn,
- struct qed_ptt *p_ptt,
- u16 source_port_or_eth_type,
- u16 dest_port,
- enum qed_llh_port_filter_type_t type)
-{
- u32 high = 0, low = 0;
- int i;
-
- if (!test_bit(QED_MF_LLH_PROTO_CLSS, &p_hwfn->cdev->mf_bits))
- return;
-
- switch (type) {
- case QED_LLH_FILTER_ETHERTYPE:
- high = source_port_or_eth_type;
- break;
- case QED_LLH_FILTER_TCP_SRC_PORT:
- case QED_LLH_FILTER_UDP_SRC_PORT:
- low = source_port_or_eth_type << 16;
- break;
- case QED_LLH_FILTER_TCP_DEST_PORT:
- case QED_LLH_FILTER_UDP_DEST_PORT:
- low = dest_port;
- break;
- case QED_LLH_FILTER_TCP_SRC_AND_DEST_PORT:
- case QED_LLH_FILTER_UDP_SRC_AND_DEST_PORT:
- low = (source_port_or_eth_type << 16) | dest_port;
- break;
- default:
- DP_NOTICE(p_hwfn,
- "Non valid LLH protocol filter type %d\n", type);
- return;
- }
-
- for (i = 0; i < NIG_REG_LLH_FUNC_FILTER_EN_SIZE; i++) {
- if (!qed_rd(p_hwfn, p_ptt,
- NIG_REG_LLH_FUNC_FILTER_EN + i * sizeof(u32)))
- continue;
- if (!qed_rd(p_hwfn, p_ptt,
- NIG_REG_LLH_FUNC_FILTER_MODE + i * sizeof(u32)))
- continue;
- if (!(qed_rd(p_hwfn, p_ptt,
- NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE +
- i * sizeof(u32)) & BIT(type)))
- continue;
- if (qed_rd(p_hwfn, p_ptt,
- NIG_REG_LLH_FUNC_FILTER_VALUE +
- 2 * i * sizeof(u32)) != low)
- continue;
- if (qed_rd(p_hwfn, p_ptt,
- NIG_REG_LLH_FUNC_FILTER_VALUE +
- (2 * i + 1) * sizeof(u32)) != high)
- continue;
-
- qed_wr(p_hwfn, p_ptt,
- NIG_REG_LLH_FUNC_FILTER_EN + i * sizeof(u32), 0);
- qed_wr(p_hwfn, p_ptt,
- NIG_REG_LLH_FUNC_FILTER_MODE + i * sizeof(u32), 0);
- qed_wr(p_hwfn, p_ptt,
- NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE +
- i * sizeof(u32), 0);
- qed_wr(p_hwfn, p_ptt,
- NIG_REG_LLH_FUNC_FILTER_VALUE + 2 * i * sizeof(u32), 0);
- qed_wr(p_hwfn, p_ptt,
- NIG_REG_LLH_FUNC_FILTER_VALUE +
- (2 * i + 1) * sizeof(u32), 0);
- break;
- }
-
- if (i >= NIG_REG_LLH_FUNC_FILTER_EN_SIZE)
- DP_NOTICE(p_hwfn, "Tried to remove a non-configured filter\n");
-}
-
static int qed_set_coalesce(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
u32 hw_addr, void *p_eth_qzone,
size_t eth_qzone_size, u8 timeset)
diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev_api.h b/drivers/net/ethernet/qlogic/qed/qed_dev_api.h
index e4b4e3b78e8a..47376d4d071f 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_dev_api.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_dev_api.h
@@ -241,11 +241,17 @@ enum qed_dmae_address_type_t {
#define QED_DMAE_FLAG_VF_SRC 0x00000002
#define QED_DMAE_FLAG_VF_DST 0x00000004
#define QED_DMAE_FLAG_COMPLETION_DST 0x00000008
+#define QED_DMAE_FLAG_PORT 0x00000010
+#define QED_DMAE_FLAG_PF_SRC 0x00000020
+#define QED_DMAE_FLAG_PF_DST 0x00000040
struct qed_dmae_params {
u32 flags; /* consists of QED_DMAE_FLAG_* values */
u8 src_vfid;
u8 dst_vfid;
+ u8 port_id;
+ u8 src_pfid;
+ u8 dst_pfid;
};
/**
@@ -257,7 +263,7 @@ struct qed_dmae_params {
* @param source_addr
* @param grc_addr (dmae_data_offset)
* @param size_in_dwords
- * @param flags (one of the flags defined above)
+ * @param p_params (default parameters will be used in case of NULL)
*/
int
qed_dmae_host2grc(struct qed_hwfn *p_hwfn,
@@ -265,7 +271,7 @@ qed_dmae_host2grc(struct qed_hwfn *p_hwfn,
u64 source_addr,
u32 grc_addr,
u32 size_in_dwords,
- u32 flags);
+ struct qed_dmae_params *p_params);
/**
* @brief qed_dmae_grc2host - Read data from dmae data offset
@@ -275,11 +281,11 @@ qed_dmae_host2grc(struct qed_hwfn *p_hwfn,
* @param grc_addr (dmae_data_offset)
* @param dest_addr
* @param size_in_dwords
- * @param flags - one of the flags defined above
+ * @param p_params (default parameters will be used in case of NULL)
*/
int qed_dmae_grc2host(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
u32 grc_addr, dma_addr_t dest_addr, u32 size_in_dwords,
- u32 flags);
+ struct qed_dmae_params *p_params);
/**
* @brief qed_dmae_host2host - copy data from to source address
@@ -290,7 +296,7 @@ int qed_dmae_grc2host(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
* @param source_addr
* @param dest_addr
* @param size_in_dwords
- * @param params
+ * @param p_params (default parameters will be used in case of NULL)
*/
int qed_dmae_host2host(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
@@ -368,26 +374,66 @@ int qed_fw_rss_eng(struct qed_hwfn *p_hwfn,
u8 *dst_id);
/**
- * @brief qed_llh_add_mac_filter - configures a MAC filter in llh
+ * @brief qed_llh_get_num_ppfid - Return the allocated number of LLH filter
+ * banks that are allocated to the PF.
*
- * @param p_hwfn
- * @param p_ptt
- * @param p_filter - MAC to add
+ * @param cdev
+ *
+ * @return u8 - Number of LLH filter banks
*/
-int qed_llh_add_mac_filter(struct qed_hwfn *p_hwfn,
- struct qed_ptt *p_ptt, u8 *p_filter);
+u8 qed_llh_get_num_ppfid(struct qed_dev *cdev);
+
+enum qed_eng {
+ QED_ENG0,
+ QED_ENG1,
+ QED_BOTH_ENG,
+};
/**
- * @brief qed_llh_remove_mac_filter - removes a MAC filter from llh
+ * @brief qed_llh_set_ppfid_affinity - Set the engine affinity for the given
+ * LLH filter bank.
+ *
+ * @param cdev
+ * @param ppfid - relative within the allocated ppfids ('0' is the default one).
+ * @param eng
+ *
+ * @return int
+ */
+int qed_llh_set_ppfid_affinity(struct qed_dev *cdev,
+ u8 ppfid, enum qed_eng eng);
+
+/**
+ * @brief qed_llh_set_roce_affinity - Set the RoCE engine affinity
+ *
+ * @param cdev
+ * @param eng
+ *
+ * @return int
+ */
+int qed_llh_set_roce_affinity(struct qed_dev *cdev, enum qed_eng eng);
+
+/**
+ * @brief qed_llh_add_mac_filter - Add a LLH MAC filter into the given filter
+ * bank.
+ *
+ * @param cdev
+ * @param ppfid - relative within the allocated ppfids ('0' is the default one).
+ * @param mac_addr - MAC to add
+ */
+int qed_llh_add_mac_filter(struct qed_dev *cdev,
+ u8 ppfid, u8 mac_addr[ETH_ALEN]);
+
+/**
+ * @brief qed_llh_remove_mac_filter - Remove a LLH MAC filter from the given
+ * filter bank.
*
- * @param p_hwfn
* @param p_ptt
* @param p_filter - MAC to remove
*/
-void qed_llh_remove_mac_filter(struct qed_hwfn *p_hwfn,
- struct qed_ptt *p_ptt, u8 *p_filter);
+void qed_llh_remove_mac_filter(struct qed_dev *cdev,
+ u8 ppfid, u8 mac_addr[ETH_ALEN]);
-enum qed_llh_port_filter_type_t {
+enum qed_llh_prot_filter_type_t {
QED_LLH_FILTER_ETHERTYPE,
QED_LLH_FILTER_TCP_SRC_PORT,
QED_LLH_FILTER_TCP_DEST_PORT,
@@ -398,36 +444,37 @@ enum qed_llh_port_filter_type_t {
};
/**
- * @brief qed_llh_add_protocol_filter - configures a protocol filter in llh
+ * @brief qed_llh_add_protocol_filter - Add a LLH protocol filter into the
+ * given filter bank.
*
- * @param p_hwfn
- * @param p_ptt
+ * @param cdev
+ * @param ppfid - relative within the allocated ppfids ('0' is the default one).
+ * @param type - type of filters and comparing
* @param source_port_or_eth_type - source port or ethertype to add
* @param dest_port - destination port to add
* @param type - type of filters and comparing
*/
int
-qed_llh_add_protocol_filter(struct qed_hwfn *p_hwfn,
- struct qed_ptt *p_ptt,
- u16 source_port_or_eth_type,
- u16 dest_port,
- enum qed_llh_port_filter_type_t type);
+qed_llh_add_protocol_filter(struct qed_dev *cdev,
+ u8 ppfid,
+ enum qed_llh_prot_filter_type_t type,
+ u16 source_port_or_eth_type, u16 dest_port);
/**
- * @brief qed_llh_remove_protocol_filter - remove a protocol filter in llh
+ * @brief qed_llh_remove_protocol_filter - Remove a LLH protocol filter from
+ * the given filter bank.
*
- * @param p_hwfn
- * @param p_ptt
+ * @param cdev
+ * @param ppfid - relative within the allocated ppfids ('0' is the default one).
+ * @param type - type of filters and comparing
* @param source_port_or_eth_type - source port or ethertype to add
* @param dest_port - destination port to add
- * @param type - type of filters and comparing
*/
void
-qed_llh_remove_protocol_filter(struct qed_hwfn *p_hwfn,
- struct qed_ptt *p_ptt,
- u16 source_port_or_eth_type,
- u16 dest_port,
- enum qed_llh_port_filter_type_t type);
+qed_llh_remove_protocol_filter(struct qed_dev *cdev,
+ u8 ppfid,
+ enum qed_llh_prot_filter_type_t type,
+ u16 source_port_or_eth_type, u16 dest_port);
/**
* *@brief Cleanup of previous driver remains prior to load
diff --git a/drivers/net/ethernet/qlogic/qed/qed_fcoe.c b/drivers/net/ethernet/qlogic/qed/qed_fcoe.c
index 46dc93d3b9b5..de31a382f58e 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_fcoe.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_fcoe.c
@@ -745,7 +745,7 @@ struct qed_hash_fcoe_con {
static int qed_fill_fcoe_dev_info(struct qed_dev *cdev,
struct qed_dev_fcoe_info *info)
{
- struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
+ struct qed_hwfn *hwfn = QED_AFFIN_HWFN(cdev);
int rc;
memset(info, 0, sizeof(*info));
@@ -806,15 +806,15 @@ static int qed_fcoe_stop(struct qed_dev *cdev)
return -EINVAL;
}
- p_ptt = qed_ptt_acquire(QED_LEADING_HWFN(cdev));
+ p_ptt = qed_ptt_acquire(QED_AFFIN_HWFN(cdev));
if (!p_ptt)
return -EAGAIN;
/* Stop the fcoe */
- rc = qed_sp_fcoe_func_stop(QED_LEADING_HWFN(cdev), p_ptt,
+ rc = qed_sp_fcoe_func_stop(QED_AFFIN_HWFN(cdev), p_ptt,
QED_SPQ_MODE_EBLOCK, NULL);
cdev->flags &= ~QED_FLAG_STORAGE_STARTED;
- qed_ptt_release(QED_LEADING_HWFN(cdev), p_ptt);
+ qed_ptt_release(QED_AFFIN_HWFN(cdev), p_ptt);
return rc;
}
@@ -828,8 +828,8 @@ static int qed_fcoe_start(struct qed_dev *cdev, struct qed_fcoe_tid *tasks)
return 0;
}
- rc = qed_sp_fcoe_func_start(QED_LEADING_HWFN(cdev),
- QED_SPQ_MODE_EBLOCK, NULL);
+ rc = qed_sp_fcoe_func_start(QED_AFFIN_HWFN(cdev), QED_SPQ_MODE_EBLOCK,
+ NULL);
if (rc) {
DP_NOTICE(cdev, "Failed to start fcoe\n");
return rc;
@@ -849,7 +849,7 @@ static int qed_fcoe_start(struct qed_dev *cdev, struct qed_fcoe_tid *tasks)
return -ENOMEM;
}
- rc = qed_cxt_get_tid_mem_info(QED_LEADING_HWFN(cdev), tid_info);
+ rc = qed_cxt_get_tid_mem_info(QED_AFFIN_HWFN(cdev), tid_info);
if (rc) {
DP_NOTICE(cdev, "Failed to gather task information\n");
qed_fcoe_stop(cdev);
@@ -884,7 +884,7 @@ static int qed_fcoe_acquire_conn(struct qed_dev *cdev,
}
/* Acquire the connection */
- rc = qed_fcoe_acquire_connection(QED_LEADING_HWFN(cdev), NULL,
+ rc = qed_fcoe_acquire_connection(QED_AFFIN_HWFN(cdev), NULL,
&hash_con->con);
if (rc) {
DP_NOTICE(cdev, "Failed to acquire Connection\n");
@@ -898,7 +898,7 @@ static int qed_fcoe_acquire_conn(struct qed_dev *cdev,
hash_add(cdev->connections, &hash_con->node, *handle);
if (p_doorbell)
- *p_doorbell = qed_fcoe_get_db_addr(QED_LEADING_HWFN(cdev),
+ *p_doorbell = qed_fcoe_get_db_addr(QED_AFFIN_HWFN(cdev),
*handle);
return 0;
@@ -916,7 +916,7 @@ static int qed_fcoe_release_conn(struct qed_dev *cdev, u32 handle)
}
hlist_del(&hash_con->node);
- qed_fcoe_release_connection(QED_LEADING_HWFN(cdev), hash_con->con);
+ qed_fcoe_release_connection(QED_AFFIN_HWFN(cdev), hash_con->con);
kfree(hash_con);
return 0;
@@ -971,7 +971,7 @@ static int qed_fcoe_offload_conn(struct qed_dev *cdev,
con->d_id.addr_mid = conn_info->d_id.addr_mid;
con->d_id.addr_lo = conn_info->d_id.addr_lo;
- return qed_sp_fcoe_conn_offload(QED_LEADING_HWFN(cdev), con,
+ return qed_sp_fcoe_conn_offload(QED_AFFIN_HWFN(cdev), con,
QED_SPQ_MODE_EBLOCK, NULL);
}
@@ -992,13 +992,13 @@ static int qed_fcoe_destroy_conn(struct qed_dev *cdev,
con = hash_con->con;
con->terminate_params = terminate_params;
- return qed_sp_fcoe_conn_destroy(QED_LEADING_HWFN(cdev), con,
+ return qed_sp_fcoe_conn_destroy(QED_AFFIN_HWFN(cdev), con,
QED_SPQ_MODE_EBLOCK, NULL);
}
static int qed_fcoe_stats(struct qed_dev *cdev, struct qed_fcoe_stats *stats)
{
- return qed_fcoe_get_stats(QED_LEADING_HWFN(cdev), stats);
+ return qed_fcoe_get_stats(QED_AFFIN_HWFN(cdev), stats);
}
void qed_get_protocol_stats_fcoe(struct qed_dev *cdev,
diff --git a/drivers/net/ethernet/qlogic/qed/qed_hsi.h b/drivers/net/ethernet/qlogic/qed/qed_hsi.h
index 37edaa847512..e054f6c69e3a 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_hsi.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_hsi.h
@@ -12612,8 +12612,10 @@ struct public_drv_mb {
#define DRV_MSG_CODE_BIST_TEST 0x001e0000
#define DRV_MSG_CODE_SET_LED_MODE 0x00200000
-#define DRV_MSG_CODE_RESOURCE_CMD 0x00230000
+#define DRV_MSG_CODE_RESOURCE_CMD 0x00230000
#define DRV_MSG_CODE_GET_TLV_DONE 0x002f0000
+#define DRV_MSG_CODE_GET_ENGINE_CONFIG 0x00370000
+#define DRV_MSG_CODE_GET_PPFID_BITMAP 0x43000000
#define RESOURCE_CMD_REQ_RESC_MASK 0x0000001F
#define RESOURCE_CMD_REQ_RESC_SHIFT 0
@@ -12802,6 +12804,18 @@ struct public_drv_mb {
#define FW_MB_PARAM_LOAD_DONE_DID_EFUSE_ERROR (1 << 0)
+#define FW_MB_PARAM_ENG_CFG_FIR_AFFIN_VALID_MASK 0x00000001
+#define FW_MB_PARAM_ENG_CFG_FIR_AFFIN_VALID_SHIFT 0
+#define FW_MB_PARAM_ENG_CFG_FIR_AFFIN_VALUE_MASK 0x00000002
+#define FW_MB_PARAM_ENG_CFG_FIR_AFFIN_VALUE_SHIFT 1
+#define FW_MB_PARAM_ENG_CFG_L2_AFFIN_VALID_MASK 0x00000004
+#define FW_MB_PARAM_ENG_CFG_L2_AFFIN_VALID_SHIFT 2
+#define FW_MB_PARAM_ENG_CFG_L2_AFFIN_VALUE_MASK 0x00000008
+#define FW_MB_PARAM_ENG_CFG_L2_AFFIN_VALUE_SHIFT 3
+
+#define FW_MB_PARAM_PPFID_BITMAP_MASK 0xFF
+#define FW_MB_PARAM_PPFID_BITMAP_SHIFT 0
+
u32 drv_pulse_mb;
#define DRV_PULSE_SEQ_MASK 0x00007fff
#define DRV_PULSE_SYSTEM_TIME_MASK 0xffff0000
diff --git a/drivers/net/ethernet/qlogic/qed/qed_hw.c b/drivers/net/ethernet/qlogic/qed/qed_hw.c
index 72ec1c6bdf70..a4de9e3ef72c 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_hw.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_hw.c
@@ -392,11 +392,15 @@ u32 qed_vfid_to_concrete(struct qed_hwfn *p_hwfn, u8 vfid)
}
/* DMAE */
+#define QED_DMAE_FLAGS_IS_SET(params, flag) \
+ ((params) != NULL && ((params)->flags & QED_DMAE_FLAG_##flag))
+
static void qed_dmae_opcode(struct qed_hwfn *p_hwfn,
const u8 is_src_type_grc,
const u8 is_dst_type_grc,
struct qed_dmae_params *p_params)
{
+ u8 src_pfid, dst_pfid, port_id;
u16 opcode_b = 0;
u32 opcode = 0;
@@ -407,14 +411,18 @@ static void qed_dmae_opcode(struct qed_hwfn *p_hwfn,
opcode |= (is_src_type_grc ? DMAE_CMD_SRC_MASK_GRC
: DMAE_CMD_SRC_MASK_PCIE) <<
DMAE_CMD_SRC_SHIFT;
- opcode |= ((p_hwfn->rel_pf_id & DMAE_CMD_SRC_PF_ID_MASK) <<
+ src_pfid = QED_DMAE_FLAGS_IS_SET(p_params, PF_SRC) ?
+ p_params->src_pfid : p_hwfn->rel_pf_id;
+ opcode |= ((src_pfid & DMAE_CMD_SRC_PF_ID_MASK) <<
DMAE_CMD_SRC_PF_ID_SHIFT);
/* The destination of the DMA can be: 0-None 1-PCIe 2-GRC 3-None */
opcode |= (is_dst_type_grc ? DMAE_CMD_DST_MASK_GRC
: DMAE_CMD_DST_MASK_PCIE) <<
DMAE_CMD_DST_SHIFT;
- opcode |= ((p_hwfn->rel_pf_id & DMAE_CMD_DST_PF_ID_MASK) <<
+ dst_pfid = QED_DMAE_FLAGS_IS_SET(p_params, PF_DST) ?
+ p_params->dst_pfid : p_hwfn->rel_pf_id;
+ opcode |= ((dst_pfid & DMAE_CMD_DST_PF_ID_MASK) <<
DMAE_CMD_DST_PF_ID_SHIFT);
/* Whether to write a completion word to the completion destination:
@@ -425,12 +433,14 @@ static void qed_dmae_opcode(struct qed_hwfn *p_hwfn,
opcode |= (DMAE_CMD_SRC_ADDR_RESET_MASK <<
DMAE_CMD_SRC_ADDR_RESET_SHIFT);
- if (p_params->flags & QED_DMAE_FLAG_COMPLETION_DST)
+ if (QED_DMAE_FLAGS_IS_SET(p_params, COMPLETION_DST))
opcode |= (1 << DMAE_CMD_COMP_FUNC_SHIFT);
opcode |= (DMAE_CMD_ENDIANITY << DMAE_CMD_ENDIANITY_MODE_SHIFT);
- opcode |= ((p_hwfn->port_id) << DMAE_CMD_PORT_ID_SHIFT);
+ port_id = (QED_DMAE_FLAGS_IS_SET(p_params, PORT)) ?
+ p_params->port_id : p_hwfn->port_id;
+ opcode |= (port_id << DMAE_CMD_PORT_ID_SHIFT);
/* reset source address in next go */
opcode |= (DMAE_CMD_SRC_ADDR_RESET_MASK <<
@@ -441,7 +451,7 @@ static void qed_dmae_opcode(struct qed_hwfn *p_hwfn,
DMAE_CMD_DST_ADDR_RESET_SHIFT);
/* SRC/DST VFID: all 1's - pf, otherwise VF id */
- if (p_params->flags & QED_DMAE_FLAG_VF_SRC) {
+ if (QED_DMAE_FLAGS_IS_SET(p_params, VF_SRC)) {
opcode |= 1 << DMAE_CMD_SRC_VF_ID_VALID_SHIFT;
opcode_b |= p_params->src_vfid << DMAE_CMD_SRC_VF_ID_SHIFT;
} else {
@@ -449,7 +459,7 @@ static void qed_dmae_opcode(struct qed_hwfn *p_hwfn,
DMAE_CMD_SRC_VF_ID_SHIFT;
}
- if (p_params->flags & QED_DMAE_FLAG_VF_DST) {
+ if (QED_DMAE_FLAGS_IS_SET(p_params, VF_DST)) {
opcode |= 1 << DMAE_CMD_DST_VF_ID_VALID_SHIFT;
opcode_b |= p_params->dst_vfid << DMAE_CMD_DST_VF_ID_SHIFT;
} else {
@@ -733,7 +743,7 @@ static int qed_dmae_execute_command(struct qed_hwfn *p_hwfn,
for (i = 0; i <= cnt_split; i++) {
offset = length_limit * i;
- if (!(p_params->flags & QED_DMAE_FLAG_RW_REPL_SRC)) {
+ if (!QED_DMAE_FLAGS_IS_SET(p_params, RW_REPL_SRC)) {
if (src_type == QED_DMAE_ADDRESS_GRC)
src_addr_split = src_addr + offset;
else
@@ -771,14 +781,12 @@ static int qed_dmae_execute_command(struct qed_hwfn *p_hwfn,
int qed_dmae_host2grc(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
- u64 source_addr, u32 grc_addr, u32 size_in_dwords, u32 flags)
+ u64 source_addr, u32 grc_addr, u32 size_in_dwords,
+ struct qed_dmae_params *p_params)
{
u32 grc_addr_in_dw = grc_addr / sizeof(u32);
- struct qed_dmae_params params;
int rc;
- memset(&params, 0, sizeof(struct qed_dmae_params));
- params.flags = flags;
mutex_lock(&p_hwfn->dmae_info.mutex);
@@ -786,7 +794,7 @@ int qed_dmae_host2grc(struct qed_hwfn *p_hwfn,
grc_addr_in_dw,
QED_DMAE_ADDRESS_HOST_VIRT,
QED_DMAE_ADDRESS_GRC,
- size_in_dwords, &params);
+ size_in_dwords, p_params);
mutex_unlock(&p_hwfn->dmae_info.mutex);
@@ -796,21 +804,19 @@ int qed_dmae_host2grc(struct qed_hwfn *p_hwfn,
int qed_dmae_grc2host(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 grc_addr,
- dma_addr_t dest_addr, u32 size_in_dwords, u32 flags)
+ dma_addr_t dest_addr, u32 size_in_dwords,
+ struct qed_dmae_params *p_params)
{
u32 grc_addr_in_dw = grc_addr / sizeof(u32);
- struct qed_dmae_params params;
int rc;
- memset(&params, 0, sizeof(struct qed_dmae_params));
- params.flags = flags;
mutex_lock(&p_hwfn->dmae_info.mutex);
rc = qed_dmae_execute_command(p_hwfn, p_ptt, grc_addr_in_dw,
dest_addr, QED_DMAE_ADDRESS_GRC,
QED_DMAE_ADDRESS_HOST_VIRT,
- size_in_dwords, &params);
+ size_in_dwords, p_params);
mutex_unlock(&p_hwfn->dmae_info.mutex);
@@ -842,7 +848,6 @@ int qed_dmae_sanity(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt, const char *phase)
{
u32 size = PAGE_SIZE / 2, val;
- struct qed_dmae_params params;
int rc = 0;
dma_addr_t p_phys;
void *p_virt;
@@ -875,9 +880,8 @@ int qed_dmae_sanity(struct qed_hwfn *p_hwfn,
(u64)p_phys,
p_virt, (u64)(p_phys + size), (u8 *)p_virt + size, size);
- memset(&params, 0, sizeof(params));
rc = qed_dmae_host2host(p_hwfn, p_ptt, p_phys, p_phys + size,
- size / 4 /* size_in_dwords */, &params);
+ size / 4, NULL);
if (rc) {
DP_NOTICE(p_hwfn,
"DMAE sanity [%s]: qed_dmae_host2host() failed. rc = %d.\n",
diff --git a/drivers/net/ethernet/qlogic/qed/qed_init_ops.c b/drivers/net/ethernet/qlogic/qed/qed_init_ops.c
index 34193c2f1699..a868d7f88601 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_init_ops.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_init_ops.c
@@ -131,7 +131,7 @@ static int qed_init_rt(struct qed_hwfn *p_hwfn,
rc = qed_dmae_host2grc(p_hwfn, p_ptt,
(uintptr_t)(p_init_val + i),
- addr + (i << 2), segment, 0);
+ addr + (i << 2), segment, NULL);
if (rc)
return rc;
@@ -194,7 +194,7 @@ static int qed_init_array_dmae(struct qed_hwfn *p_hwfn,
} else {
rc = qed_dmae_host2grc(p_hwfn, p_ptt,
(uintptr_t)(buf + dmae_data_offset),
- addr, size, 0);
+ addr, size, NULL);
}
return rc;
@@ -205,6 +205,7 @@ static int qed_init_fill_dmae(struct qed_hwfn *p_hwfn,
u32 addr, u32 fill, u32 fill_count)
{
static u32 zero_buffer[DMAE_MAX_RW_SIZE];
+ struct qed_dmae_params params = {};
memset(zero_buffer, 0, sizeof(u32) * DMAE_MAX_RW_SIZE);
@@ -214,10 +215,10 @@ static int qed_init_fill_dmae(struct qed_hwfn *p_hwfn,
* 3. p_hwfb->temp_data,
* 4. fill_count
*/
-
+ params.flags = QED_DMAE_FLAG_RW_REPL_SRC;
return qed_dmae_host2grc(p_hwfn, p_ptt,
(uintptr_t)(&zero_buffer[0]),
- addr, fill_count, QED_DMAE_FLAG_RW_REPL_SRC);
+ addr, fill_count, &params);
}
static void qed_init_fill(struct qed_hwfn *p_hwfn,
diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.c b/drivers/net/ethernet/qlogic/qed/qed_int.c
index fdfedbc8e431..4e8118a08654 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_int.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_int.c
@@ -1508,10 +1508,10 @@ void qed_int_cau_conf_sb(struct qed_hwfn *p_hwfn,
qed_dmae_host2grc(p_hwfn, p_ptt, (u64)(uintptr_t)&phys_addr,
CAU_REG_SB_ADDR_MEMORY +
- igu_sb_id * sizeof(u64), 2, 0);
+ igu_sb_id * sizeof(u64), 2, NULL);
qed_dmae_host2grc(p_hwfn, p_ptt, (u64)(uintptr_t)&sb_entry,
CAU_REG_SB_VAR_MEMORY +
- igu_sb_id * sizeof(u64), 2, 0);
+ igu_sb_id * sizeof(u64), 2, NULL);
} else {
/* Initialize Status Block Address */
STORE_RT_REG_AGG(p_hwfn,
@@ -2362,7 +2362,7 @@ int qed_int_set_timer_res(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
rc = qed_dmae_grc2host(p_hwfn, p_ptt, CAU_REG_SB_VAR_MEMORY +
sb_id * sizeof(u64),
- (u64)(uintptr_t)&sb_entry, 2, 0);
+ (u64)(uintptr_t)&sb_entry, 2, NULL);
if (rc) {
DP_ERR(p_hwfn, "dmae_grc2host failed %d\n", rc);
return rc;
@@ -2376,7 +2376,7 @@ int qed_int_set_timer_res(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
rc = qed_dmae_host2grc(p_hwfn, p_ptt,
(u64)(uintptr_t)&sb_entry,
CAU_REG_SB_VAR_MEMORY +
- sb_id * sizeof(u64), 2, 0);
+ sb_id * sizeof(u64), 2, NULL);
if (rc) {
DP_ERR(p_hwfn, "dmae_host2grc failed %d\n", rc);
return rc;
diff --git a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c
index 4f8a685d1a55..5585c18053ec 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c
@@ -1082,7 +1082,7 @@ struct qed_hash_iscsi_con {
static int qed_fill_iscsi_dev_info(struct qed_dev *cdev,
struct qed_dev_iscsi_info *info)
{
- struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
+ struct qed_hwfn *hwfn = QED_AFFIN_HWFN(cdev);
int rc;
@@ -1141,8 +1141,8 @@ static int qed_iscsi_stop(struct qed_dev *cdev)
}
/* Stop the iscsi */
- rc = qed_sp_iscsi_func_stop(QED_LEADING_HWFN(cdev),
- QED_SPQ_MODE_EBLOCK, NULL);
+ rc = qed_sp_iscsi_func_stop(QED_AFFIN_HWFN(cdev), QED_SPQ_MODE_EBLOCK,
+ NULL);
cdev->flags &= ~QED_FLAG_STORAGE_STARTED;
return rc;
@@ -1161,9 +1161,8 @@ static int qed_iscsi_start(struct qed_dev *cdev,
return 0;
}
- rc = qed_sp_iscsi_func_start(QED_LEADING_HWFN(cdev),
- QED_SPQ_MODE_EBLOCK, NULL, event_context,
- async_event_cb);
+ rc = qed_sp_iscsi_func_start(QED_AFFIN_HWFN(cdev), QED_SPQ_MODE_EBLOCK,
+ NULL, event_context, async_event_cb);
if (rc) {
DP_NOTICE(cdev, "Failed to start iscsi\n");
return rc;
@@ -1182,8 +1181,7 @@ static int qed_iscsi_start(struct qed_dev *cdev,
return -ENOMEM;
}
- rc = qed_cxt_get_tid_mem_info(QED_LEADING_HWFN(cdev),
- tid_info);
+ rc = qed_cxt_get_tid_mem_info(QED_AFFIN_HWFN(cdev), tid_info);
if (rc) {
DP_NOTICE(cdev, "Failed to gather task information\n");
qed_iscsi_stop(cdev);
@@ -1215,7 +1213,7 @@ static int qed_iscsi_acquire_conn(struct qed_dev *cdev,
return -ENOMEM;
/* Acquire the connection */
- rc = qed_iscsi_acquire_connection(QED_LEADING_HWFN(cdev), NULL,
+ rc = qed_iscsi_acquire_connection(QED_AFFIN_HWFN(cdev), NULL,
&hash_con->con);
if (rc) {
DP_NOTICE(cdev, "Failed to acquire Connection\n");
@@ -1229,7 +1227,7 @@ static int qed_iscsi_acquire_conn(struct qed_dev *cdev,
hash_add(cdev->connections, &hash_con->node, *handle);
if (p_doorbell)
- *p_doorbell = qed_iscsi_get_db_addr(QED_LEADING_HWFN(cdev),
+ *p_doorbell = qed_iscsi_get_db_addr(QED_AFFIN_HWFN(cdev),
*handle);
return 0;
@@ -1247,7 +1245,7 @@ static int qed_iscsi_release_conn(struct qed_dev *cdev, u32 handle)
}
hlist_del(&hash_con->node);
- qed_iscsi_release_connection(QED_LEADING_HWFN(cdev), hash_con->con);
+ qed_iscsi_release_connection(QED_AFFIN_HWFN(cdev), hash_con->con);
kfree(hash_con);
return 0;
@@ -1324,7 +1322,7 @@ static int qed_iscsi_offload_conn(struct qed_dev *cdev,
/* Set default values on other connection fields */
con->offl_flags = 0x1;
- return qed_sp_iscsi_conn_offload(QED_LEADING_HWFN(cdev), con,
+ return qed_sp_iscsi_conn_offload(QED_AFFIN_HWFN(cdev), con,
QED_SPQ_MODE_EBLOCK, NULL);
}
@@ -1351,7 +1349,7 @@ static int qed_iscsi_update_conn(struct qed_dev *cdev,
con->first_seq_length = conn_info->first_seq_length;
con->exp_stat_sn = conn_info->exp_stat_sn;
- return qed_sp_iscsi_conn_update(QED_LEADING_HWFN(cdev), con,
+ return qed_sp_iscsi_conn_update(QED_AFFIN_HWFN(cdev), con,
QED_SPQ_MODE_EBLOCK, NULL);
}
@@ -1366,8 +1364,7 @@ static int qed_iscsi_clear_conn_sq(struct qed_dev *cdev, u32 handle)
return -EINVAL;
}
- return qed_sp_iscsi_conn_clear_sq(QED_LEADING_HWFN(cdev),
- hash_con->con,
+ return qed_sp_iscsi_conn_clear_sq(QED_AFFIN_HWFN(cdev), hash_con->con,
QED_SPQ_MODE_EBLOCK, NULL);
}
@@ -1385,14 +1382,13 @@ static int qed_iscsi_destroy_conn(struct qed_dev *cdev,
hash_con->con->abortive_dsconnect = abrt_conn;
- return qed_sp_iscsi_conn_terminate(QED_LEADING_HWFN(cdev),
- hash_con->con,
+ return qed_sp_iscsi_conn_terminate(QED_AFFIN_HWFN(cdev), hash_con->con,
QED_SPQ_MODE_EBLOCK, NULL);
}
static int qed_iscsi_stats(struct qed_dev *cdev, struct qed_iscsi_stats *stats)
{
- return qed_iscsi_get_stats(QED_LEADING_HWFN(cdev), stats);
+ return qed_iscsi_get_stats(QED_AFFIN_HWFN(cdev), stats);
}
static int qed_iscsi_change_mac(struct qed_dev *cdev,
@@ -1407,8 +1403,7 @@ static int qed_iscsi_change_mac(struct qed_dev *cdev,
return -EINVAL;
}
- return qed_sp_iscsi_mac_update(QED_LEADING_HWFN(cdev),
- hash_con->con,
+ return qed_sp_iscsi_mac_update(QED_AFFIN_HWFN(cdev), hash_con->con,
QED_SPQ_MODE_EBLOCK, NULL);
}
diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index ded556b7bab5..f380fae8799d 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -63,7 +63,12 @@ struct mpa_v2_hdr {
#define MPA_REV2(_mpa_rev) ((_mpa_rev) == MPA_NEGOTIATION_TYPE_ENHANCED)
#define QED_IWARP_INVALID_TCP_CID 0xffffffff
-#define QED_IWARP_RCV_WND_SIZE_DEF (256 * 1024)
+
+#define QED_IWARP_RCV_WND_SIZE_DEF_BB_2P (200 * 1024)
+#define QED_IWARP_RCV_WND_SIZE_DEF_BB_4P (100 * 1024)
+#define QED_IWARP_RCV_WND_SIZE_DEF_AH_2P (150 * 1024)
+#define QED_IWARP_RCV_WND_SIZE_DEF_AH_4P (90 * 1024)
+
#define QED_IWARP_RCV_WND_SIZE_MIN (0xffff)
#define TIMESTAMP_HEADER_SIZE (12)
#define QED_IWARP_MAX_FIN_RT_DEFAULT (2)
@@ -532,7 +537,8 @@ int qed_iwarp_destroy_qp(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp)
/* Make sure ep is closed before returning and freeing memory. */
if (ep) {
- while (ep->state != QED_IWARP_EP_CLOSED && wait_count++ < 200)
+ while (READ_ONCE(ep->state) != QED_IWARP_EP_CLOSED &&
+ wait_count++ < 200)
msleep(100);
if (ep->state != QED_IWARP_EP_CLOSED)
@@ -1022,8 +1028,6 @@ qed_iwarp_mpa_complete(struct qed_hwfn *p_hwfn,
params.ep_context = ep;
- ep->state = QED_IWARP_EP_CLOSED;
-
switch (fw_return_code) {
case RDMA_RETURN_OK:
ep->qp->max_rd_atomic_req = ep->cm_info.ord;
@@ -1083,6 +1087,10 @@ qed_iwarp_mpa_complete(struct qed_hwfn *p_hwfn,
break;
}
+ if (fw_return_code != RDMA_RETURN_OK)
+ /* paired with READ_ONCE in destroy_qp */
+ smp_store_release(&ep->state, QED_IWARP_EP_CLOSED);
+
ep->event_cb(ep->cb_context, &params);
/* on passive side, if there is no associated QP (REJECT) we need to
@@ -2528,7 +2536,7 @@ qed_iwarp_ll2_slowpath(void *cxt,
memset(fpdu, 0, sizeof(*fpdu));
}
-static int qed_iwarp_ll2_stop(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
+static int qed_iwarp_ll2_stop(struct qed_hwfn *p_hwfn)
{
struct qed_iwarp_info *iwarp_info = &p_hwfn->p_rdma_info->iwarp;
int rc = 0;
@@ -2563,8 +2571,9 @@ static int qed_iwarp_ll2_stop(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
iwarp_info->ll2_mpa_handle = QED_IWARP_HANDLE_INVAL;
}
- qed_llh_remove_mac_filter(p_hwfn,
- p_ptt, p_hwfn->p_rdma_info->iwarp.mac_addr);
+ qed_llh_remove_mac_filter(p_hwfn->cdev, 0,
+ p_hwfn->p_rdma_info->iwarp.mac_addr);
+
return rc;
}
@@ -2609,7 +2618,7 @@ qed_iwarp_ll2_alloc_buffers(struct qed_hwfn *p_hwfn,
static int
qed_iwarp_ll2_start(struct qed_hwfn *p_hwfn,
struct qed_rdma_start_in_params *params,
- struct qed_ptt *p_ptt)
+ u32 rcv_wnd_size)
{
struct qed_iwarp_info *iwarp_info;
struct qed_ll2_acquire_data data;
@@ -2628,7 +2637,7 @@ qed_iwarp_ll2_start(struct qed_hwfn *p_hwfn,
ether_addr_copy(p_hwfn->p_rdma_info->iwarp.mac_addr, params->mac_addr);
- rc = qed_llh_add_mac_filter(p_hwfn, p_ptt, params->mac_addr);
+ rc = qed_llh_add_mac_filter(p_hwfn->cdev, 0, params->mac_addr);
if (rc)
return rc;
@@ -2637,6 +2646,7 @@ qed_iwarp_ll2_start(struct qed_hwfn *p_hwfn,
cbs.rx_release_cb = qed_iwarp_ll2_rel_rx_pkt;
cbs.tx_comp_cb = qed_iwarp_ll2_comp_tx_pkt;
cbs.tx_release_cb = qed_iwarp_ll2_rel_tx_pkt;
+ cbs.slowpath_cb = NULL;
cbs.cookie = p_hwfn;
memset(&data, 0, sizeof(data));
@@ -2653,7 +2663,7 @@ qed_iwarp_ll2_start(struct qed_hwfn *p_hwfn,
rc = qed_ll2_acquire_connection(p_hwfn, &data);
if (rc) {
DP_NOTICE(p_hwfn, "Failed to acquire LL2 connection\n");
- qed_llh_remove_mac_filter(p_hwfn, p_ptt, params->mac_addr);
+ qed_llh_remove_mac_filter(p_hwfn->cdev, 0, params->mac_addr);
return rc;
}
@@ -2675,7 +2685,7 @@ qed_iwarp_ll2_start(struct qed_hwfn *p_hwfn,
data.input.conn_type = QED_LL2_TYPE_OOO;
data.input.mtu = params->max_mtu;
- n_ooo_bufs = (QED_IWARP_MAX_OOO * QED_IWARP_RCV_WND_SIZE_DEF) /
+ n_ooo_bufs = (QED_IWARP_MAX_OOO * rcv_wnd_size) /
iwarp_info->max_mtu;
n_ooo_bufs = min_t(u32, n_ooo_bufs, QED_IWARP_LL2_OOO_MAX_RX_SIZE);
@@ -2708,6 +2718,8 @@ qed_iwarp_ll2_start(struct qed_hwfn *p_hwfn,
data.input.rx_num_desc = n_ooo_bufs * 2;
data.input.tx_num_desc = data.input.rx_num_desc;
data.input.tx_max_bds_per_packet = QED_IWARP_MAX_BDS_PER_FPDU;
+ data.input.tx_tc = PKT_LB_TC;
+ data.input.tx_dest = QED_LL2_TX_DEST_LB;
data.p_connection_handle = &iwarp_info->ll2_mpa_handle;
data.input.secondary_queue = true;
data.cbs = &cbs;
@@ -2757,21 +2769,35 @@ qed_iwarp_ll2_start(struct qed_hwfn *p_hwfn,
&iwarp_info->mpa_buf_list);
return rc;
err:
- qed_iwarp_ll2_stop(p_hwfn, p_ptt);
+ qed_iwarp_ll2_stop(p_hwfn);
return rc;
}
-int qed_iwarp_setup(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
+static struct {
+ u32 two_ports;
+ u32 four_ports;
+} qed_iwarp_rcv_wnd_size[MAX_CHIP_IDS] = {
+ {QED_IWARP_RCV_WND_SIZE_DEF_BB_2P, QED_IWARP_RCV_WND_SIZE_DEF_BB_4P},
+ {QED_IWARP_RCV_WND_SIZE_DEF_AH_2P, QED_IWARP_RCV_WND_SIZE_DEF_AH_4P}
+};
+
+int qed_iwarp_setup(struct qed_hwfn *p_hwfn,
struct qed_rdma_start_in_params *params)
{
+ struct qed_dev *cdev = p_hwfn->cdev;
struct qed_iwarp_info *iwarp_info;
+ enum chip_ids chip_id;
u32 rcv_wnd_size;
iwarp_info = &p_hwfn->p_rdma_info->iwarp;
iwarp_info->tcp_flags = QED_IWARP_TS_EN;
- rcv_wnd_size = QED_IWARP_RCV_WND_SIZE_DEF;
+
+ chip_id = QED_IS_BB(cdev) ? CHIP_BB : CHIP_K2;
+ rcv_wnd_size = (qed_device_num_ports(cdev) == 4) ?
+ qed_iwarp_rcv_wnd_size[chip_id].four_ports :
+ qed_iwarp_rcv_wnd_size[chip_id].two_ports;
/* value 0 is used for ilog2(QED_IWARP_RCV_WND_SIZE_MIN) */
iwarp_info->rcv_wnd_scale = ilog2(rcv_wnd_size) -
@@ -2794,10 +2820,10 @@ int qed_iwarp_setup(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
qed_iwarp_async_event);
qed_ooo_setup(p_hwfn);
- return qed_iwarp_ll2_start(p_hwfn, params, p_ptt);
+ return qed_iwarp_ll2_start(p_hwfn, params, rcv_wnd_size);
}
-int qed_iwarp_stop(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
+int qed_iwarp_stop(struct qed_hwfn *p_hwfn)
{
int rc;
@@ -2808,7 +2834,7 @@ int qed_iwarp_stop(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
qed_spq_unregister_async_cb(p_hwfn, PROTOCOLID_IWARP);
- return qed_iwarp_ll2_stop(p_hwfn, p_ptt);
+ return qed_iwarp_ll2_stop(p_hwfn);
}
static void qed_iwarp_qp_in_error(struct qed_hwfn *p_hwfn,
@@ -2825,7 +2851,9 @@ static void qed_iwarp_qp_in_error(struct qed_hwfn *p_hwfn,
params.status = (fw_return_code == IWARP_QP_IN_ERROR_GOOD_CLOSE) ?
0 : -ECONNRESET;
- ep->state = QED_IWARP_EP_CLOSED;
+ /* paired with READ_ONCE in destroy_qp */
+ smp_store_release(&ep->state, QED_IWARP_EP_CLOSED);
+
spin_lock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock);
list_del(&ep->list_entry);
spin_unlock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock);
@@ -2914,7 +2942,8 @@ qed_iwarp_tcp_connect_unsuccessful(struct qed_hwfn *p_hwfn,
params.event = QED_IWARP_EVENT_ACTIVE_COMPLETE;
params.ep_context = ep;
params.cm_info = &ep->cm_info;
- ep->state = QED_IWARP_EP_CLOSED;
+ /* paired with READ_ONCE in destroy_qp */
+ smp_store_release(&ep->state, QED_IWARP_EP_CLOSED);
switch (fw_return_code) {
case IWARP_CONN_ERROR_TCP_CONNECT_INVALID_PACKET:
diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
index 7ac959038324..c1b2057d23b8 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
@@ -183,13 +183,13 @@ struct qed_iwarp_listener {
int qed_iwarp_alloc(struct qed_hwfn *p_hwfn);
-int qed_iwarp_setup(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
+int qed_iwarp_setup(struct qed_hwfn *p_hwfn,
struct qed_rdma_start_in_params *params);
void qed_iwarp_init_fw_ramrod(struct qed_hwfn *p_hwfn,
struct iwarp_init_func_ramrod_data *p_ramrod);
-int qed_iwarp_stop(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt);
+int qed_iwarp_stop(struct qed_hwfn *p_hwfn);
void qed_iwarp_resc_free(struct qed_hwfn *p_hwfn);
diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c
index 57641728df69..9f36e7948222 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_l2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c
@@ -2111,7 +2111,7 @@ int qed_get_rxq_coalesce(struct qed_hwfn *p_hwfn,
rc = qed_dmae_grc2host(p_hwfn, p_ptt, CAU_REG_SB_VAR_MEMORY +
p_cid->sb_igu_id * sizeof(u64),
- (u64)(uintptr_t)&sb_entry, 2, 0);
+ (u64)(uintptr_t)&sb_entry, 2, NULL);
if (rc) {
DP_ERR(p_hwfn, "dmae_grc2host failed %d\n", rc);
return rc;
@@ -2144,7 +2144,7 @@ int qed_get_txq_coalesce(struct qed_hwfn *p_hwfn,
rc = qed_dmae_grc2host(p_hwfn, p_ptt, CAU_REG_SB_VAR_MEMORY +
p_cid->sb_igu_id * sizeof(u64),
- (u64)(uintptr_t)&sb_entry, 2, 0);
+ (u64)(uintptr_t)&sb_entry, 2, NULL);
if (rc) {
DP_ERR(p_hwfn, "dmae_grc2host failed %d\n", rc);
return rc;
diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index b5f419b71287..19a1a58d60f8 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -239,9 +239,8 @@ out_post1:
buffer->phys_addr = new_phys_addr;
out_post:
- rc = qed_ll2_post_rx_buffer(QED_LEADING_HWFN(cdev), cdev->ll2->handle,
- buffer->phys_addr, 0, buffer, 1);
-
+ rc = qed_ll2_post_rx_buffer(p_hwfn, cdev->ll2->handle,
+ buffer->phys_addr, 0, buffer, 1);
if (rc)
qed_ll2_dealloc_buffer(cdev, buffer);
}
@@ -926,16 +925,15 @@ static int qed_ll2_lb_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie)
return 0;
}
-static void qed_ll2_stop_ooo(struct qed_dev *cdev)
+static void qed_ll2_stop_ooo(struct qed_hwfn *p_hwfn)
{
- struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
- u8 *handle = &hwfn->pf_params.iscsi_pf_params.ll2_ooo_queue_id;
+ u8 *handle = &p_hwfn->pf_params.iscsi_pf_params.ll2_ooo_queue_id;
- DP_VERBOSE(cdev, QED_MSG_STORAGE, "Stopping LL2 OOO queue [%02x]\n",
- *handle);
+ DP_VERBOSE(p_hwfn, (QED_MSG_STORAGE | QED_MSG_LL2),
+ "Stopping LL2 OOO queue [%02x]\n", *handle);
- qed_ll2_terminate_connection(hwfn, *handle);
- qed_ll2_release_connection(hwfn, *handle);
+ qed_ll2_terminate_connection(p_hwfn, *handle);
+ qed_ll2_release_connection(p_hwfn, *handle);
*handle = QED_LL2_UNUSED_HANDLE;
}
@@ -1574,12 +1572,12 @@ int qed_ll2_establish_connection(void *cxt, u8 connection_handle)
if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_FCOE) {
if (!test_bit(QED_MF_UFP_SPECIFIC, &p_hwfn->cdev->mf_bits))
- qed_llh_add_protocol_filter(p_hwfn, p_ptt,
- ETH_P_FCOE, 0,
- QED_LLH_FILTER_ETHERTYPE);
- qed_llh_add_protocol_filter(p_hwfn, p_ptt,
- ETH_P_FIP, 0,
- QED_LLH_FILTER_ETHERTYPE);
+ qed_llh_add_protocol_filter(p_hwfn->cdev, 0,
+ QED_LLH_FILTER_ETHERTYPE,
+ ETH_P_FCOE, 0);
+ qed_llh_add_protocol_filter(p_hwfn->cdev, 0,
+ QED_LLH_FILTER_ETHERTYPE,
+ ETH_P_FIP, 0);
}
out:
@@ -1980,12 +1978,12 @@ int qed_ll2_terminate_connection(void *cxt, u8 connection_handle)
if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_FCOE) {
if (!test_bit(QED_MF_UFP_SPECIFIC, &p_hwfn->cdev->mf_bits))
- qed_llh_remove_protocol_filter(p_hwfn, p_ptt,
- ETH_P_FCOE, 0,
- QED_LLH_FILTER_ETHERTYPE);
- qed_llh_remove_protocol_filter(p_hwfn, p_ptt,
- ETH_P_FIP, 0,
- QED_LLH_FILTER_ETHERTYPE);
+ qed_llh_remove_protocol_filter(p_hwfn->cdev, 0,
+ QED_LLH_FILTER_ETHERTYPE,
+ ETH_P_FCOE, 0);
+ qed_llh_remove_protocol_filter(p_hwfn->cdev, 0,
+ QED_LLH_FILTER_ETHERTYPE,
+ ETH_P_FIP, 0);
}
out:
@@ -2086,12 +2084,12 @@ static void _qed_ll2_get_port_stats(struct qed_hwfn *p_hwfn,
TSTORM_LL2_PORT_STAT_OFFSET(MFW_PORT(p_hwfn)),
sizeof(port_stats));
- p_stats->gsi_invalid_hdr = HILO_64_REGPAIR(port_stats.gsi_invalid_hdr);
- p_stats->gsi_invalid_pkt_length =
+ p_stats->gsi_invalid_hdr += HILO_64_REGPAIR(port_stats.gsi_invalid_hdr);
+ p_stats->gsi_invalid_pkt_length +=
HILO_64_REGPAIR(port_stats.gsi_invalid_pkt_length);
- p_stats->gsi_unsupported_pkt_typ =
+ p_stats->gsi_unsupported_pkt_typ +=
HILO_64_REGPAIR(port_stats.gsi_unsupported_pkt_typ);
- p_stats->gsi_crcchksm_error =
+ p_stats->gsi_crcchksm_error +=
HILO_64_REGPAIR(port_stats.gsi_crcchksm_error);
}
@@ -2109,9 +2107,9 @@ static void _qed_ll2_get_tstats(struct qed_hwfn *p_hwfn,
CORE_LL2_TSTORM_PER_QUEUE_STAT_OFFSET(qid);
qed_memcpy_from(p_hwfn, p_ptt, &tstats, tstats_addr, sizeof(tstats));
- p_stats->packet_too_big_discard =
+ p_stats->packet_too_big_discard +=
HILO_64_REGPAIR(tstats.packet_too_big_discard);
- p_stats->no_buff_discard = HILO_64_REGPAIR(tstats.no_buff_discard);
+ p_stats->no_buff_discard += HILO_64_REGPAIR(tstats.no_buff_discard);
}
static void _qed_ll2_get_ustats(struct qed_hwfn *p_hwfn,
@@ -2128,12 +2126,12 @@ static void _qed_ll2_get_ustats(struct qed_hwfn *p_hwfn,
CORE_LL2_USTORM_PER_QUEUE_STAT_OFFSET(qid);
qed_memcpy_from(p_hwfn, p_ptt, &ustats, ustats_addr, sizeof(ustats));
- p_stats->rcv_ucast_bytes = HILO_64_REGPAIR(ustats.rcv_ucast_bytes);
- p_stats->rcv_mcast_bytes = HILO_64_REGPAIR(ustats.rcv_mcast_bytes);
- p_stats->rcv_bcast_bytes = HILO_64_REGPAIR(ustats.rcv_bcast_bytes);
- p_stats->rcv_ucast_pkts = HILO_64_REGPAIR(ustats.rcv_ucast_pkts);
- p_stats->rcv_mcast_pkts = HILO_64_REGPAIR(ustats.rcv_mcast_pkts);
- p_stats->rcv_bcast_pkts = HILO_64_REGPAIR(ustats.rcv_bcast_pkts);
+ p_stats->rcv_ucast_bytes += HILO_64_REGPAIR(ustats.rcv_ucast_bytes);
+ p_stats->rcv_mcast_bytes += HILO_64_REGPAIR(ustats.rcv_mcast_bytes);
+ p_stats->rcv_bcast_bytes += HILO_64_REGPAIR(ustats.rcv_bcast_bytes);
+ p_stats->rcv_ucast_pkts += HILO_64_REGPAIR(ustats.rcv_ucast_pkts);
+ p_stats->rcv_mcast_pkts += HILO_64_REGPAIR(ustats.rcv_mcast_pkts);
+ p_stats->rcv_bcast_pkts += HILO_64_REGPAIR(ustats.rcv_bcast_pkts);
}
static void _qed_ll2_get_pstats(struct qed_hwfn *p_hwfn,
@@ -2150,23 +2148,21 @@ static void _qed_ll2_get_pstats(struct qed_hwfn *p_hwfn,
CORE_LL2_PSTORM_PER_QUEUE_STAT_OFFSET(stats_id);
qed_memcpy_from(p_hwfn, p_ptt, &pstats, pstats_addr, sizeof(pstats));
- p_stats->sent_ucast_bytes = HILO_64_REGPAIR(pstats.sent_ucast_bytes);
- p_stats->sent_mcast_bytes = HILO_64_REGPAIR(pstats.sent_mcast_bytes);
- p_stats->sent_bcast_bytes = HILO_64_REGPAIR(pstats.sent_bcast_bytes);
- p_stats->sent_ucast_pkts = HILO_64_REGPAIR(pstats.sent_ucast_pkts);
- p_stats->sent_mcast_pkts = HILO_64_REGPAIR(pstats.sent_mcast_pkts);
- p_stats->sent_bcast_pkts = HILO_64_REGPAIR(pstats.sent_bcast_pkts);
+ p_stats->sent_ucast_bytes += HILO_64_REGPAIR(pstats.sent_ucast_bytes);
+ p_stats->sent_mcast_bytes += HILO_64_REGPAIR(pstats.sent_mcast_bytes);
+ p_stats->sent_bcast_bytes += HILO_64_REGPAIR(pstats.sent_bcast_bytes);
+ p_stats->sent_ucast_pkts += HILO_64_REGPAIR(pstats.sent_ucast_pkts);
+ p_stats->sent_mcast_pkts += HILO_64_REGPAIR(pstats.sent_mcast_pkts);
+ p_stats->sent_bcast_pkts += HILO_64_REGPAIR(pstats.sent_bcast_pkts);
}
-int qed_ll2_get_stats(void *cxt,
- u8 connection_handle, struct qed_ll2_stats *p_stats)
+static int __qed_ll2_get_stats(void *cxt, u8 connection_handle,
+ struct qed_ll2_stats *p_stats)
{
struct qed_hwfn *p_hwfn = cxt;
struct qed_ll2_info *p_ll2_conn = NULL;
struct qed_ptt *p_ptt;
- memset(p_stats, 0, sizeof(*p_stats));
-
if ((connection_handle >= QED_MAX_NUM_OF_LL2_CONNECTIONS) ||
!p_hwfn->p_ll2_info)
return -EINVAL;
@@ -2181,15 +2177,26 @@ int qed_ll2_get_stats(void *cxt,
if (p_ll2_conn->input.gsi_enable)
_qed_ll2_get_port_stats(p_hwfn, p_ptt, p_stats);
+
_qed_ll2_get_tstats(p_hwfn, p_ptt, p_ll2_conn, p_stats);
+
_qed_ll2_get_ustats(p_hwfn, p_ptt, p_ll2_conn, p_stats);
+
if (p_ll2_conn->tx_stats_en)
_qed_ll2_get_pstats(p_hwfn, p_ptt, p_ll2_conn, p_stats);
qed_ptt_release(p_hwfn, p_ptt);
+
return 0;
}
+int qed_ll2_get_stats(void *cxt,
+ u8 connection_handle, struct qed_ll2_stats *p_stats)
+{
+ memset(p_stats, 0, sizeof(*p_stats));
+ return __qed_ll2_get_stats(cxt, connection_handle, p_stats);
+}
+
static void qed_ll2b_release_rx_packet(void *cxt,
u8 connection_handle,
void *cookie,
@@ -2216,7 +2223,7 @@ struct qed_ll2_cbs ll2_cbs = {
.tx_release_cb = &qed_ll2b_complete_tx_packet,
};
-static void qed_ll2_set_conn_data(struct qed_dev *cdev,
+static void qed_ll2_set_conn_data(struct qed_hwfn *p_hwfn,
struct qed_ll2_acquire_data *data,
struct qed_ll2_params *params,
enum qed_ll2_conn_type conn_type,
@@ -2232,7 +2239,7 @@ static void qed_ll2_set_conn_data(struct qed_dev *cdev,
data->input.tx_num_desc = QED_LL2_TX_SIZE;
data->p_connection_handle = handle;
data->cbs = &ll2_cbs;
- ll2_cbs.cookie = QED_LEADING_HWFN(cdev);
+ ll2_cbs.cookie = p_hwfn;
if (lb) {
data->input.tx_tc = PKT_LB_TC;
@@ -2243,74 +2250,102 @@ static void qed_ll2_set_conn_data(struct qed_dev *cdev,
}
}
-static int qed_ll2_start_ooo(struct qed_dev *cdev,
+static int qed_ll2_start_ooo(struct qed_hwfn *p_hwfn,
struct qed_ll2_params *params)
{
- struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
- u8 *handle = &hwfn->pf_params.iscsi_pf_params.ll2_ooo_queue_id;
+ u8 *handle = &p_hwfn->pf_params.iscsi_pf_params.ll2_ooo_queue_id;
struct qed_ll2_acquire_data data;
int rc;
- qed_ll2_set_conn_data(cdev, &data, params,
+ qed_ll2_set_conn_data(p_hwfn, &data, params,
QED_LL2_TYPE_OOO, handle, true);
- rc = qed_ll2_acquire_connection(hwfn, &data);
+ rc = qed_ll2_acquire_connection(p_hwfn, &data);
if (rc) {
- DP_INFO(cdev, "Failed to acquire LL2 OOO connection\n");
+ DP_INFO(p_hwfn, "Failed to acquire LL2 OOO connection\n");
goto out;
}
- rc = qed_ll2_establish_connection(hwfn, *handle);
+ rc = qed_ll2_establish_connection(p_hwfn, *handle);
if (rc) {
- DP_INFO(cdev, "Failed to establist LL2 OOO connection\n");
+ DP_INFO(p_hwfn, "Failed to establish LL2 OOO connection\n");
goto fail;
}
return 0;
fail:
- qed_ll2_release_connection(hwfn, *handle);
+ qed_ll2_release_connection(p_hwfn, *handle);
out:
*handle = QED_LL2_UNUSED_HANDLE;
return rc;
}
-static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params)
+static bool qed_ll2_is_storage_eng1(struct qed_dev *cdev)
{
- struct qed_ll2_buffer *buffer, *tmp_buffer;
- enum qed_ll2_conn_type conn_type;
- struct qed_ll2_acquire_data data;
- struct qed_ptt *p_ptt;
- int rc, i;
+ return (QED_IS_FCOE_PERSONALITY(QED_LEADING_HWFN(cdev)) ||
+ QED_IS_ISCSI_PERSONALITY(QED_LEADING_HWFN(cdev))) &&
+ (QED_AFFIN_HWFN(cdev) != QED_LEADING_HWFN(cdev));
+}
+static int __qed_ll2_stop(struct qed_hwfn *p_hwfn)
+{
+ struct qed_dev *cdev = p_hwfn->cdev;
+ int rc;
- /* Initialize LL2 locks & lists */
- INIT_LIST_HEAD(&cdev->ll2->list);
- spin_lock_init(&cdev->ll2->lock);
- cdev->ll2->rx_size = NET_SKB_PAD + ETH_HLEN +
- L1_CACHE_BYTES + params->mtu;
+ rc = qed_ll2_terminate_connection(p_hwfn, cdev->ll2->handle);
+ if (rc)
+ DP_INFO(cdev, "Failed to terminate LL2 connection\n");
- /*Allocate memory for LL2 */
- DP_INFO(cdev, "Allocating LL2 buffers of size %08x bytes\n",
- cdev->ll2->rx_size);
- for (i = 0; i < QED_LL2_RX_SIZE; i++) {
- buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
- if (!buffer) {
- DP_INFO(cdev, "Failed to allocate LL2 buffers\n");
- goto fail;
- }
+ qed_ll2_release_connection(p_hwfn, cdev->ll2->handle);
- rc = qed_ll2_alloc_buffer(cdev, (u8 **)&buffer->data,
- &buffer->phys_addr);
- if (rc) {
- kfree(buffer);
- goto fail;
- }
+ return rc;
+}
- list_add_tail(&buffer->list, &cdev->ll2->list);
+static int qed_ll2_stop(struct qed_dev *cdev)
+{
+ bool b_is_storage_eng1 = qed_ll2_is_storage_eng1(cdev);
+ struct qed_hwfn *p_hwfn = QED_AFFIN_HWFN(cdev);
+ int rc = 0, rc2 = 0;
+
+ if (cdev->ll2->handle == QED_LL2_UNUSED_HANDLE)
+ return 0;
+
+ qed_llh_remove_mac_filter(cdev, 0, cdev->ll2_mac_address);
+ eth_zero_addr(cdev->ll2_mac_address);
+
+ if (QED_IS_ISCSI_PERSONALITY(p_hwfn))
+ qed_ll2_stop_ooo(p_hwfn);
+
+ /* In CMT mode, LL2 is always started on engine 0 for a storage PF */
+ if (b_is_storage_eng1) {
+ rc2 = __qed_ll2_stop(QED_LEADING_HWFN(cdev));
+ if (rc2)
+ DP_NOTICE(QED_LEADING_HWFN(cdev),
+ "Failed to stop LL2 on engine 0\n");
}
- switch (QED_LEADING_HWFN(cdev)->hw_info.personality) {
+ rc = __qed_ll2_stop(p_hwfn);
+ if (rc)
+ DP_NOTICE(p_hwfn, "Failed to stop LL2\n");
+
+ qed_ll2_kill_buffers(cdev);
+
+ cdev->ll2->handle = QED_LL2_UNUSED_HANDLE;
+
+ return rc | rc2;
+}
+
+static int __qed_ll2_start(struct qed_hwfn *p_hwfn,
+ struct qed_ll2_params *params)
+{
+ struct qed_ll2_buffer *buffer, *tmp_buffer;
+ struct qed_dev *cdev = p_hwfn->cdev;
+ enum qed_ll2_conn_type conn_type;
+ struct qed_ll2_acquire_data data;
+ int rc, rx_cnt;
+
+ switch (p_hwfn->hw_info.personality) {
case QED_PCI_FCOE:
conn_type = QED_LL2_TYPE_FCOE;
break;
@@ -2321,33 +2356,34 @@ static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params)
conn_type = QED_LL2_TYPE_ROCE;
break;
default:
+
conn_type = QED_LL2_TYPE_TEST;
}
- qed_ll2_set_conn_data(cdev, &data, params, conn_type,
+ qed_ll2_set_conn_data(p_hwfn, &data, params, conn_type,
&cdev->ll2->handle, false);
- rc = qed_ll2_acquire_connection(QED_LEADING_HWFN(cdev), &data);
+ rc = qed_ll2_acquire_connection(p_hwfn, &data);
if (rc) {
- DP_INFO(cdev, "Failed to acquire LL2 connection\n");
- goto fail;
+ DP_INFO(p_hwfn, "Failed to acquire LL2 connection\n");
+ return rc;
}
- rc = qed_ll2_establish_connection(QED_LEADING_HWFN(cdev),
- cdev->ll2->handle);
+ rc = qed_ll2_establish_connection(p_hwfn, cdev->ll2->handle);
if (rc) {
- DP_INFO(cdev, "Failed to establish LL2 connection\n");
- goto release_fail;
+ DP_INFO(p_hwfn, "Failed to establish LL2 connection\n");
+ goto release_conn;
}
/* Post all Rx buffers to FW */
spin_lock_bh(&cdev->ll2->lock);
+ rx_cnt = cdev->ll2->rx_cnt;
list_for_each_entry_safe(buffer, tmp_buffer, &cdev->ll2->list, list) {
- rc = qed_ll2_post_rx_buffer(QED_LEADING_HWFN(cdev),
+ rc = qed_ll2_post_rx_buffer(p_hwfn,
cdev->ll2->handle,
buffer->phys_addr, 0, buffer, 1);
if (rc) {
- DP_INFO(cdev,
+ DP_INFO(p_hwfn,
"Failed to post an Rx buffer; Deleting it\n");
dma_unmap_single(&cdev->pdev->dev, buffer->phys_addr,
cdev->ll2->rx_size, DMA_FROM_DEVICE);
@@ -2355,100 +2391,127 @@ static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params)
list_del(&buffer->list);
kfree(buffer);
} else {
- cdev->ll2->rx_cnt++;
+ rx_cnt++;
}
}
spin_unlock_bh(&cdev->ll2->lock);
- if (!cdev->ll2->rx_cnt) {
- DP_INFO(cdev, "Failed passing even a single Rx buffer\n");
- goto release_terminate;
+ if (rx_cnt == cdev->ll2->rx_cnt) {
+ DP_NOTICE(p_hwfn, "Failed passing even a single Rx buffer\n");
+ goto terminate_conn;
}
+ cdev->ll2->rx_cnt = rx_cnt;
+
+ return 0;
+
+terminate_conn:
+ qed_ll2_terminate_connection(p_hwfn, cdev->ll2->handle);
+release_conn:
+ qed_ll2_release_connection(p_hwfn, cdev->ll2->handle);
+ return rc;
+}
+
+static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params)
+{
+ bool b_is_storage_eng1 = qed_ll2_is_storage_eng1(cdev);
+ struct qed_hwfn *p_hwfn = QED_AFFIN_HWFN(cdev);
+ struct qed_ll2_buffer *buffer;
+ int rx_num_desc, i, rc;
if (!is_valid_ether_addr(params->ll2_mac_address)) {
- DP_INFO(cdev, "Invalid Ethernet address\n");
- goto release_terminate;
+ DP_NOTICE(cdev, "Invalid Ethernet address\n");
+ return -EINVAL;
}
- if (QED_LEADING_HWFN(cdev)->hw_info.personality == QED_PCI_ISCSI) {
- DP_VERBOSE(cdev, QED_MSG_STORAGE, "Starting OOO LL2 queue\n");
- rc = qed_ll2_start_ooo(cdev, params);
+ WARN_ON(!cdev->ll2->cbs);
+
+ /* Initialize LL2 locks & lists */
+ INIT_LIST_HEAD(&cdev->ll2->list);
+ spin_lock_init(&cdev->ll2->lock);
+
+ cdev->ll2->rx_size = NET_SKB_PAD + ETH_HLEN +
+ L1_CACHE_BYTES + params->mtu;
+
+ /* Allocate memory for LL2.
+ * In CMT mode, in case of a storage PF which is affintized to engine 1,
+ * LL2 is started also on engine 0 and thus we need twofold buffers.
+ */
+ rx_num_desc = QED_LL2_RX_SIZE * (b_is_storage_eng1 ? 2 : 1);
+ DP_INFO(cdev, "Allocating %d LL2 buffers of size %08x bytes\n",
+ rx_num_desc, cdev->ll2->rx_size);
+ for (i = 0; i < rx_num_desc; i++) {
+ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
+ if (!buffer) {
+ DP_INFO(cdev, "Failed to allocate LL2 buffers\n");
+ rc = -ENOMEM;
+ goto err0;
+ }
+
+ rc = qed_ll2_alloc_buffer(cdev, (u8 **)&buffer->data,
+ &buffer->phys_addr);
if (rc) {
- DP_INFO(cdev,
- "Failed to initialize the OOO LL2 queue\n");
- goto release_terminate;
+ kfree(buffer);
+ goto err0;
}
- }
- p_ptt = qed_ptt_acquire(QED_LEADING_HWFN(cdev));
- if (!p_ptt) {
- DP_INFO(cdev, "Failed to acquire PTT\n");
- goto release_terminate;
+ list_add_tail(&buffer->list, &cdev->ll2->list);
}
- rc = qed_llh_add_mac_filter(QED_LEADING_HWFN(cdev), p_ptt,
- params->ll2_mac_address);
- qed_ptt_release(QED_LEADING_HWFN(cdev), p_ptt);
+ rc = __qed_ll2_start(p_hwfn, params);
if (rc) {
- DP_ERR(cdev, "Failed to allocate LLH filter\n");
- goto release_terminate_all;
+ DP_NOTICE(cdev, "Failed to start LL2\n");
+ goto err0;
}
- ether_addr_copy(cdev->ll2_mac_address, params->ll2_mac_address);
- return 0;
-
-release_terminate_all:
-
-release_terminate:
- qed_ll2_terminate_connection(QED_LEADING_HWFN(cdev), cdev->ll2->handle);
-release_fail:
- qed_ll2_release_connection(QED_LEADING_HWFN(cdev), cdev->ll2->handle);
-fail:
- qed_ll2_kill_buffers(cdev);
- cdev->ll2->handle = QED_LL2_UNUSED_HANDLE;
- return -EINVAL;
-}
-
-static int qed_ll2_stop(struct qed_dev *cdev)
-{
- struct qed_ptt *p_ptt;
- int rc;
-
- if (cdev->ll2->handle == QED_LL2_UNUSED_HANDLE)
- return 0;
+ /* In CMT mode, always need to start LL2 on engine 0 for a storage PF,
+ * since broadcast/mutlicast packets are routed to engine 0.
+ */
+ if (b_is_storage_eng1) {
+ rc = __qed_ll2_start(QED_LEADING_HWFN(cdev), params);
+ if (rc) {
+ DP_NOTICE(QED_LEADING_HWFN(cdev),
+ "Failed to start LL2 on engine 0\n");
+ goto err1;
+ }
+ }
- p_ptt = qed_ptt_acquire(QED_LEADING_HWFN(cdev));
- if (!p_ptt) {
- DP_INFO(cdev, "Failed to acquire PTT\n");
- goto fail;
+ if (QED_IS_ISCSI_PERSONALITY(p_hwfn)) {
+ DP_VERBOSE(cdev, QED_MSG_STORAGE, "Starting OOO LL2 queue\n");
+ rc = qed_ll2_start_ooo(p_hwfn, params);
+ if (rc) {
+ DP_NOTICE(cdev, "Failed to start OOO LL2\n");
+ goto err2;
+ }
}
- qed_llh_remove_mac_filter(QED_LEADING_HWFN(cdev), p_ptt,
- cdev->ll2_mac_address);
- qed_ptt_release(QED_LEADING_HWFN(cdev), p_ptt);
- eth_zero_addr(cdev->ll2_mac_address);
+ rc = qed_llh_add_mac_filter(cdev, 0, params->ll2_mac_address);
+ if (rc) {
+ DP_NOTICE(cdev, "Failed to add an LLH filter\n");
+ goto err3;
+ }
- if (QED_LEADING_HWFN(cdev)->hw_info.personality == QED_PCI_ISCSI)
- qed_ll2_stop_ooo(cdev);
+ ether_addr_copy(cdev->ll2_mac_address, params->ll2_mac_address);
- rc = qed_ll2_terminate_connection(QED_LEADING_HWFN(cdev),
- cdev->ll2->handle);
- if (rc)
- DP_INFO(cdev, "Failed to terminate LL2 connection\n");
+ return 0;
+err3:
+ if (QED_IS_ISCSI_PERSONALITY(p_hwfn))
+ qed_ll2_stop_ooo(p_hwfn);
+err2:
+ if (b_is_storage_eng1)
+ __qed_ll2_stop(QED_LEADING_HWFN(cdev));
+err1:
+ __qed_ll2_stop(p_hwfn);
+err0:
qed_ll2_kill_buffers(cdev);
-
- qed_ll2_release_connection(QED_LEADING_HWFN(cdev), cdev->ll2->handle);
cdev->ll2->handle = QED_LL2_UNUSED_HANDLE;
-
return rc;
-fail:
- return -EINVAL;
}
static int qed_ll2_start_xmit(struct qed_dev *cdev, struct sk_buff *skb,
unsigned long xmit_flags)
{
+ struct qed_hwfn *p_hwfn = QED_AFFIN_HWFN(cdev);
struct qed_ll2_tx_pkt_info pkt;
const skb_frag_t *frag;
u8 flags = 0, nr_frags;
@@ -2506,7 +2569,7 @@ static int qed_ll2_start_xmit(struct qed_dev *cdev, struct sk_buff *skb,
* routine may run and free the SKB, so no dereferencing the SKB
* beyond this point unless skb has any fragments.
*/
- rc = qed_ll2_prepare_tx_packet(&cdev->hwfns[0], cdev->ll2->handle,
+ rc = qed_ll2_prepare_tx_packet(p_hwfn, cdev->ll2->handle,
&pkt, 1);
if (rc)
goto err;
@@ -2524,13 +2587,13 @@ static int qed_ll2_start_xmit(struct qed_dev *cdev, struct sk_buff *skb,
goto err;
}
- rc = qed_ll2_set_fragment_of_tx_packet(QED_LEADING_HWFN(cdev),
+ rc = qed_ll2_set_fragment_of_tx_packet(p_hwfn,
cdev->ll2->handle,
mapping,
skb_frag_size(frag));
/* if failed not much to do here, partial packet has been posted
- * we can't free memory, will need to wait for completion.
+ * we can't free memory, will need to wait for completion
*/
if (rc)
goto err2;
@@ -2540,18 +2603,37 @@ static int qed_ll2_start_xmit(struct qed_dev *cdev, struct sk_buff *skb,
err:
dma_unmap_single(&cdev->pdev->dev, mapping, skb->len, DMA_TO_DEVICE);
-
err2:
return rc;
}
static int qed_ll2_stats(struct qed_dev *cdev, struct qed_ll2_stats *stats)
{
+ bool b_is_storage_eng1 = qed_ll2_is_storage_eng1(cdev);
+ struct qed_hwfn *p_hwfn = QED_AFFIN_HWFN(cdev);
+ int rc;
+
if (!cdev->ll2)
return -EINVAL;
- return qed_ll2_get_stats(QED_LEADING_HWFN(cdev),
- cdev->ll2->handle, stats);
+ rc = qed_ll2_get_stats(p_hwfn, cdev->ll2->handle, stats);
+ if (rc) {
+ DP_NOTICE(p_hwfn, "Failed to get LL2 stats\n");
+ return rc;
+ }
+
+ /* In CMT mode, LL2 is always started on engine 0 for a storage PF */
+ if (b_is_storage_eng1) {
+ rc = __qed_ll2_get_stats(QED_LEADING_HWFN(cdev),
+ cdev->ll2->handle, stats);
+ if (rc) {
+ DP_NOTICE(QED_LEADING_HWFN(cdev),
+ "Failed to get LL2 stats on engine 0\n");
+ return rc;
+ }
+ }
+
+ return 0;
}
const struct qed_ll2_ops qed_ll2_ops_pass = {
diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c
index 6de23b56b294..829dd60ab937 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_main.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_main.c
@@ -48,6 +48,7 @@
#include <linux/crc32.h>
#include <linux/qed/qed_if.h>
#include <linux/qed/qed_ll2_if.h>
+#include <net/devlink.h>
#include "qed.h"
#include "qed_sriov.h"
@@ -342,6 +343,107 @@ static int qed_set_power_state(struct qed_dev *cdev, pci_power_t state)
return 0;
}
+struct qed_devlink {
+ struct qed_dev *cdev;
+};
+
+enum qed_devlink_param_id {
+ QED_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
+ QED_DEVLINK_PARAM_ID_IWARP_CMT,
+};
+
+static int qed_dl_param_get(struct devlink *dl, u32 id,
+ struct devlink_param_gset_ctx *ctx)
+{
+ struct qed_devlink *qed_dl;
+ struct qed_dev *cdev;
+
+ qed_dl = devlink_priv(dl);
+ cdev = qed_dl->cdev;
+ ctx->val.vbool = cdev->iwarp_cmt;
+
+ return 0;
+}
+
+static int qed_dl_param_set(struct devlink *dl, u32 id,
+ struct devlink_param_gset_ctx *ctx)
+{
+ struct qed_devlink *qed_dl;
+ struct qed_dev *cdev;
+
+ qed_dl = devlink_priv(dl);
+ cdev = qed_dl->cdev;
+ cdev->iwarp_cmt = ctx->val.vbool;
+
+ return 0;
+}
+
+static const struct devlink_param qed_devlink_params[] = {
+ DEVLINK_PARAM_DRIVER(QED_DEVLINK_PARAM_ID_IWARP_CMT,
+ "iwarp_cmt", DEVLINK_PARAM_TYPE_BOOL,
+ BIT(DEVLINK_PARAM_CMODE_RUNTIME),
+ qed_dl_param_get, qed_dl_param_set, NULL),
+};
+
+static const struct devlink_ops qed_dl_ops;
+
+static int qed_devlink_register(struct qed_dev *cdev)
+{
+ union devlink_param_value value;
+ struct qed_devlink *qed_dl;
+ struct devlink *dl;
+ int rc;
+
+ dl = devlink_alloc(&qed_dl_ops, sizeof(*qed_dl));
+ if (!dl)
+ return -ENOMEM;
+
+ qed_dl = devlink_priv(dl);
+
+ cdev->dl = dl;
+ qed_dl->cdev = cdev;
+
+ rc = devlink_register(dl, &cdev->pdev->dev);
+ if (rc)
+ goto err_free;
+
+ rc = devlink_params_register(dl, qed_devlink_params,
+ ARRAY_SIZE(qed_devlink_params));
+ if (rc)
+ goto err_unregister;
+
+ value.vbool = false;
+ devlink_param_driverinit_value_set(dl,
+ QED_DEVLINK_PARAM_ID_IWARP_CMT,
+ value);
+
+ devlink_params_publish(dl);
+ cdev->iwarp_cmt = false;
+
+ return 0;
+
+err_unregister:
+ devlink_unregister(dl);
+
+err_free:
+ cdev->dl = NULL;
+ devlink_free(dl);
+
+ return rc;
+}
+
+static void qed_devlink_unregister(struct qed_dev *cdev)
+{
+ if (!cdev->dl)
+ return;
+
+ devlink_params_unregister(cdev->dl, qed_devlink_params,
+ ARRAY_SIZE(qed_devlink_params));
+
+ devlink_unregister(cdev->dl);
+ devlink_free(cdev->dl);
+}
+
/* probing */
static struct qed_dev *qed_probe(struct pci_dev *pdev,
struct qed_probe_params *params)
@@ -370,6 +472,12 @@ static struct qed_dev *qed_probe(struct pci_dev *pdev,
}
DP_INFO(cdev, "PCI init completed successfully\n");
+ rc = qed_devlink_register(cdev);
+ if (rc) {
+ DP_INFO(cdev, "Failed to register devlink.\n");
+ goto err2;
+ }
+
rc = qed_hw_prepare(cdev, QED_PCI_DEFAULT);
if (rc) {
DP_ERR(cdev, "hw prepare failed\n");
@@ -399,6 +507,8 @@ static void qed_remove(struct qed_dev *cdev)
qed_set_power_state(cdev, PCI_D3hot);
+ qed_devlink_unregister(cdev);
+
qed_free_cdev(cdev);
}
@@ -1301,26 +1411,21 @@ static u32 qed_sb_init(struct qed_dev *cdev,
{
struct qed_hwfn *p_hwfn;
struct qed_ptt *p_ptt;
- int hwfn_index;
u16 rel_sb_id;
- u8 n_hwfns;
u32 rc;
- /* RoCE uses single engine and CMT uses two engines. When using both
- * we force only a single engine. Storage uses only engine 0 too.
- */
- if (type == QED_SB_TYPE_L2_QUEUE)
- n_hwfns = cdev->num_hwfns;
- else
- n_hwfns = 1;
-
- hwfn_index = sb_id % n_hwfns;
- p_hwfn = &cdev->hwfns[hwfn_index];
- rel_sb_id = sb_id / n_hwfns;
+ /* RoCE/Storage use a single engine in CMT mode while L2 uses both */
+ if (type == QED_SB_TYPE_L2_QUEUE) {
+ p_hwfn = &cdev->hwfns[sb_id % cdev->num_hwfns];
+ rel_sb_id = sb_id / cdev->num_hwfns;
+ } else {
+ p_hwfn = QED_AFFIN_HWFN(cdev);
+ rel_sb_id = sb_id;
+ }
DP_VERBOSE(cdev, NETIF_MSG_INTR,
"hwfn [%d] <--[init]-- SB %04x [0x%04x upper]\n",
- hwfn_index, rel_sb_id, sb_id);
+ IS_LEAD_HWFN(p_hwfn) ? 0 : 1, rel_sb_id, sb_id);
if (IS_PF(p_hwfn->cdev)) {
p_ptt = qed_ptt_acquire(p_hwfn);
@@ -1339,20 +1444,26 @@ static u32 qed_sb_init(struct qed_dev *cdev,
}
static u32 qed_sb_release(struct qed_dev *cdev,
- struct qed_sb_info *sb_info, u16 sb_id)
+ struct qed_sb_info *sb_info,
+ u16 sb_id,
+ enum qed_sb_type type)
{
struct qed_hwfn *p_hwfn;
- int hwfn_index;
u16 rel_sb_id;
u32 rc;
- hwfn_index = sb_id % cdev->num_hwfns;
- p_hwfn = &cdev->hwfns[hwfn_index];
- rel_sb_id = sb_id / cdev->num_hwfns;
+ /* RoCE/Storage use a single engine in CMT mode while L2 uses both */
+ if (type == QED_SB_TYPE_L2_QUEUE) {
+ p_hwfn = &cdev->hwfns[sb_id % cdev->num_hwfns];
+ rel_sb_id = sb_id / cdev->num_hwfns;
+ } else {
+ p_hwfn = QED_AFFIN_HWFN(cdev);
+ rel_sb_id = sb_id;
+ }
DP_VERBOSE(cdev, NETIF_MSG_INTR,
"hwfn [%d] <--[init]-- SB %04x [0x%04x upper]\n",
- hwfn_index, rel_sb_id, sb_id);
+ IS_LEAD_HWFN(p_hwfn) ? 0 : 1, rel_sb_id, sb_id);
rc = qed_int_sb_release(p_hwfn, sb_info, rel_sb_id);
@@ -2372,6 +2483,11 @@ static int qed_read_module_eeprom(struct qed_dev *cdev, char *buf,
return rc;
}
+static u8 qed_get_affin_hwfn_idx(struct qed_dev *cdev)
+{
+ return QED_AFFIN_HWFN_IDX(cdev);
+}
+
static struct qed_selftest_ops qed_selftest_ops_pass = {
.selftest_memory = &qed_selftest_memory,
.selftest_interrupt = &qed_selftest_interrupt,
@@ -2419,6 +2535,7 @@ const struct qed_common_ops qed_common_ops_pass = {
.db_recovery_add = &qed_db_recovery_add,
.db_recovery_del = &qed_db_recovery_del,
.read_module_eeprom = &qed_read_module_eeprom,
+ .get_affin_hwfn_idx = &qed_get_affin_hwfn_idx,
};
void qed_get_protocol_stats(struct qed_dev *cdev,
diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c b/drivers/net/ethernet/qlogic/qed/qed_mcp.c
index cc27fd60d689..758702c1ce9c 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_mcp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c
@@ -3685,3 +3685,68 @@ int qed_mcp_set_capabilities(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
return qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_FEATURE_SUPPORT,
features, &mcp_resp, &mcp_param);
}
+
+int qed_mcp_get_engine_config(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
+{
+ struct qed_mcp_mb_params mb_params = {0};
+ struct qed_dev *cdev = p_hwfn->cdev;
+ u8 fir_valid, l2_valid;
+ int rc;
+
+ mb_params.cmd = DRV_MSG_CODE_GET_ENGINE_CONFIG;
+ rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params);
+ if (rc)
+ return rc;
+
+ if (mb_params.mcp_resp == FW_MSG_CODE_UNSUPPORTED) {
+ DP_INFO(p_hwfn,
+ "The get_engine_config command is unsupported by the MFW\n");
+ return -EOPNOTSUPP;
+ }
+
+ fir_valid = QED_MFW_GET_FIELD(mb_params.mcp_param,
+ FW_MB_PARAM_ENG_CFG_FIR_AFFIN_VALID);
+ if (fir_valid)
+ cdev->fir_affin =
+ QED_MFW_GET_FIELD(mb_params.mcp_param,
+ FW_MB_PARAM_ENG_CFG_FIR_AFFIN_VALUE);
+
+ l2_valid = QED_MFW_GET_FIELD(mb_params.mcp_param,
+ FW_MB_PARAM_ENG_CFG_L2_AFFIN_VALID);
+ if (l2_valid)
+ cdev->l2_affin_hint =
+ QED_MFW_GET_FIELD(mb_params.mcp_param,
+ FW_MB_PARAM_ENG_CFG_L2_AFFIN_VALUE);
+
+ DP_INFO(p_hwfn,
+ "Engine affinity config: FIR={valid %hhd, value %hhd}, L2_hint={valid %hhd, value %hhd}\n",
+ fir_valid, cdev->fir_affin, l2_valid, cdev->l2_affin_hint);
+
+ return 0;
+}
+
+int qed_mcp_get_ppfid_bitmap(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
+{
+ struct qed_mcp_mb_params mb_params = {0};
+ struct qed_dev *cdev = p_hwfn->cdev;
+ int rc;
+
+ mb_params.cmd = DRV_MSG_CODE_GET_PPFID_BITMAP;
+ rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params);
+ if (rc)
+ return rc;
+
+ if (mb_params.mcp_resp == FW_MSG_CODE_UNSUPPORTED) {
+ DP_INFO(p_hwfn,
+ "The get_ppfid_bitmap command is unsupported by the MFW\n");
+ return -EOPNOTSUPP;
+ }
+
+ cdev->ppfid_bitmap = QED_MFW_GET_FIELD(mb_params.mcp_param,
+ FW_MB_PARAM_PPFID_BITMAP);
+
+ DP_VERBOSE(p_hwfn, QED_MSG_SP, "PPFID bitmap 0x%hhx\n",
+ cdev->ppfid_bitmap);
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.h b/drivers/net/ethernet/qlogic/qed/qed_mcp.h
index 261c1a392e2c..e4f8fe4bd062 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_mcp.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.h
@@ -1186,4 +1186,20 @@ void qed_mcp_read_ufp_config(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt);
*/
int qed_mcp_nvm_info_populate(struct qed_hwfn *p_hwfn);
+/**
+ * @brief Get the engine affinity configuration.
+ *
+ * @param p_hwfn
+ * @param p_ptt
+ */
+int qed_mcp_get_engine_config(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt);
+
+/**
+ * @brief Get the PPFID bitmap.
+ *
+ * @param p_hwfn
+ * @param p_ptt
+ */
+int qed_mcp_get_ppfid_bitmap(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt);
+
#endif
diff --git a/drivers/net/ethernet/qlogic/qed/qed_ptp.c b/drivers/net/ethernet/qlogic/qed/qed_ptp.c
index 1302b308bd87..0dacf2c18c09 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ptp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ptp.c
@@ -44,6 +44,8 @@
/* Add/subtract the Adjustment_Value when making a Drift adjustment */
#define QED_DRIFT_CNTR_DIRECTION_SHIFT 31
#define QED_TIMESTAMP_MASK BIT(16)
+/* Param mask for Hardware to detect/timestamp the unicast PTP packets */
+#define QED_PTP_UCAST_PARAM_MASK 0xF
static enum qed_resc_lock qed_ptcdev_to_resc(struct qed_hwfn *p_hwfn)
{
@@ -157,7 +159,8 @@ static int qed_ptp_hw_read_tx_ts(struct qed_dev *cdev, u64 *timestamp)
*timestamp = 0;
val = qed_rd(p_hwfn, p_ptt, NIG_REG_TX_LLH_PTP_BUF_SEQID);
if (!(val & QED_TIMESTAMP_MASK)) {
- DP_INFO(p_hwfn, "Invalid Tx timestamp, buf_seqid = %d\n", val);
+ DP_VERBOSE(p_hwfn, QED_MSG_DEBUG,
+ "Invalid Tx timestamp, buf_seqid = %08x\n", val);
return -EINVAL;
}
@@ -242,7 +245,8 @@ static int qed_ptp_hw_cfg_filters(struct qed_dev *cdev,
return -EINVAL;
}
- qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_PTP_PARAM_MASK, 0);
+ qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_PTP_PARAM_MASK,
+ QED_PTP_UCAST_PARAM_MASK);
qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_PTP_RULE_MASK, rule_mask);
qed_wr(p_hwfn, p_ptt, NIG_REG_RX_PTP_EN, enable_cfg);
@@ -252,7 +256,8 @@ static int qed_ptp_hw_cfg_filters(struct qed_dev *cdev,
qed_wr(p_hwfn, p_ptt, NIG_REG_TX_LLH_PTP_RULE_MASK, 0x3FFF);
} else {
qed_wr(p_hwfn, p_ptt, NIG_REG_TX_PTP_EN, enable_cfg);
- qed_wr(p_hwfn, p_ptt, NIG_REG_TX_LLH_PTP_PARAM_MASK, 0);
+ qed_wr(p_hwfn, p_ptt, NIG_REG_TX_LLH_PTP_PARAM_MASK,
+ QED_PTP_UCAST_PARAM_MASK);
qed_wr(p_hwfn, p_ptt, NIG_REG_TX_LLH_PTP_RULE_MASK, rule_mask);
}
diff --git a/drivers/net/ethernet/qlogic/qed/qed_rdma.c b/drivers/net/ethernet/qlogic/qed/qed_rdma.c
index 7873d6dfd91f..f900fde448db 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_rdma.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_rdma.c
@@ -700,7 +700,7 @@ static int qed_rdma_setup(struct qed_hwfn *p_hwfn,
return rc;
if (QED_IS_IWARP_PERSONALITY(p_hwfn)) {
- rc = qed_iwarp_setup(p_hwfn, p_ptt, params);
+ rc = qed_iwarp_setup(p_hwfn, params);
if (rc)
return rc;
} else {
@@ -742,7 +742,7 @@ static int qed_rdma_stop(void *rdma_cxt)
(ll2_ethertype_en & 0xFFFE));
if (QED_IS_IWARP_PERSONALITY(p_hwfn)) {
- rc = qed_iwarp_stop(p_hwfn, p_ptt);
+ rc = qed_iwarp_stop(p_hwfn);
if (rc) {
qed_ptt_release(p_hwfn, p_ptt);
return rc;
@@ -803,7 +803,7 @@ static int qed_rdma_add_user(void *rdma_cxt,
dpi_start_offset +
((out_params->dpi) * p_hwfn->dpi_size));
- out_params->dpi_phys_addr = p_hwfn->cdev->db_phys_addr +
+ out_params->dpi_phys_addr = p_hwfn->db_phys_addr +
dpi_start_offset +
((out_params->dpi) * p_hwfn->dpi_size);
@@ -818,14 +818,17 @@ static struct qed_rdma_port *qed_rdma_query_port(void *rdma_cxt)
{
struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt;
struct qed_rdma_port *p_port = p_hwfn->p_rdma_info->port;
+ struct qed_mcp_link_state *p_link_output;
DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "RDMA Query port\n");
- /* Link may have changed */
- p_port->port_state = p_hwfn->mcp_info->link_output.link_up ?
- QED_RDMA_PORT_UP : QED_RDMA_PORT_DOWN;
+ /* The link state is saved only for the leading hwfn */
+ p_link_output = &QED_LEADING_HWFN(p_hwfn->cdev)->mcp_info->link_output;
- p_port->link_speed = p_hwfn->mcp_info->link_output.speed;
+ p_port->port_state = p_link_output->link_up ? QED_RDMA_PORT_UP
+ : QED_RDMA_PORT_DOWN;
+
+ p_port->link_speed = p_link_output->speed;
p_port->max_msg_size = RDMA_MAX_DATA_SIZE_IN_WQE;
@@ -870,7 +873,7 @@ static void qed_rdma_cnq_prod_update(void *rdma_cxt, u8 qz_offset, u16 prod)
static int qed_fill_rdma_dev_info(struct qed_dev *cdev,
struct qed_dev_rdma_info *info)
{
- struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
+ struct qed_hwfn *p_hwfn = QED_AFFIN_HWFN(cdev);
memset(info, 0, sizeof(*info));
@@ -889,9 +892,9 @@ static int qed_rdma_get_sb_start(struct qed_dev *cdev)
int feat_num;
if (cdev->num_hwfns > 1)
- feat_num = FEAT_NUM(QED_LEADING_HWFN(cdev), QED_PF_L2_QUE);
+ feat_num = FEAT_NUM(QED_AFFIN_HWFN(cdev), QED_PF_L2_QUE);
else
- feat_num = FEAT_NUM(QED_LEADING_HWFN(cdev), QED_PF_L2_QUE) *
+ feat_num = FEAT_NUM(QED_AFFIN_HWFN(cdev), QED_PF_L2_QUE) *
cdev->num_hwfns;
return feat_num;
@@ -899,7 +902,7 @@ static int qed_rdma_get_sb_start(struct qed_dev *cdev)
static int qed_rdma_get_min_cnq_msix(struct qed_dev *cdev)
{
- int n_cnq = FEAT_NUM(QED_LEADING_HWFN(cdev), QED_RDMA_CNQ);
+ int n_cnq = FEAT_NUM(QED_AFFIN_HWFN(cdev), QED_RDMA_CNQ);
int n_msix = cdev->int_params.rdma_msix_cnt;
return min_t(int, n_cnq, n_msix);
@@ -1653,7 +1656,7 @@ static int qed_rdma_deregister_tid(void *rdma_cxt, u32 itid)
static void *qed_rdma_get_rdma_ctx(struct qed_dev *cdev)
{
- return QED_LEADING_HWFN(cdev);
+ return QED_AFFIN_HWFN(cdev);
}
static int qed_rdma_modify_srq(void *rdma_cxt,
@@ -1881,7 +1884,7 @@ err:
static int qed_rdma_init(struct qed_dev *cdev,
struct qed_rdma_start_in_params *params)
{
- return qed_rdma_start(QED_LEADING_HWFN(cdev), params);
+ return qed_rdma_start(QED_AFFIN_HWFN(cdev), params);
}
static void qed_rdma_remove_user(void *rdma_cxt, u16 dpi)
@@ -1899,23 +1902,12 @@ static int qed_roce_ll2_set_mac_filter(struct qed_dev *cdev,
u8 *old_mac_address,
u8 *new_mac_address)
{
- struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
- struct qed_ptt *p_ptt;
int rc = 0;
- p_ptt = qed_ptt_acquire(p_hwfn);
- if (!p_ptt) {
- DP_ERR(cdev,
- "qed roce ll2 mac filter set: failed to acquire PTT\n");
- return -EINVAL;
- }
-
if (old_mac_address)
- qed_llh_remove_mac_filter(p_hwfn, p_ptt, old_mac_address);
+ qed_llh_remove_mac_filter(cdev, 0, old_mac_address);
if (new_mac_address)
- rc = qed_llh_add_mac_filter(p_hwfn, p_ptt, new_mac_address);
-
- qed_ptt_release(p_hwfn, p_ptt);
+ rc = qed_llh_add_mac_filter(cdev, 0, new_mac_address);
if (rc)
DP_ERR(cdev,
@@ -1924,6 +1916,36 @@ static int qed_roce_ll2_set_mac_filter(struct qed_dev *cdev,
return rc;
}
+static int qed_iwarp_set_engine_affin(struct qed_dev *cdev, bool b_reset)
+{
+ enum qed_eng eng;
+ u8 ppfid = 0;
+ int rc;
+
+ /* Make sure iwarp cmt mode is enabled before setting affinity */
+ if (!cdev->iwarp_cmt)
+ return -EINVAL;
+
+ if (b_reset)
+ eng = QED_BOTH_ENG;
+ else
+ eng = cdev->l2_affin_hint ? QED_ENG1 : QED_ENG0;
+
+ rc = qed_llh_set_ppfid_affinity(cdev, ppfid, eng);
+ if (rc) {
+ DP_NOTICE(cdev,
+ "Failed to set the engine affinity of ppfid %d\n",
+ ppfid);
+ return rc;
+ }
+
+ DP_VERBOSE(cdev, (QED_MSG_RDMA | QED_MSG_SP),
+ "LLH: Set the engine affinity of non-RoCE packets as %d\n",
+ eng);
+
+ return 0;
+}
+
static const struct qed_rdma_ops qed_rdma_ops_pass = {
.common = &qed_common_ops_pass,
.fill_dev_info = &qed_fill_rdma_dev_info,
@@ -1963,6 +1985,7 @@ static const struct qed_rdma_ops qed_rdma_ops_pass = {
.ll2_set_fragment_of_tx_packet = &qed_ll2_set_fragment_of_tx_packet,
.ll2_set_mac_filter = &qed_roce_ll2_set_mac_filter,
.ll2_get_stats = &qed_ll2_get_stats,
+ .iwarp_set_engine_affin = &qed_iwarp_set_engine_affin,
.iwarp_connect = &qed_iwarp_connect,
.iwarp_create_listen = &qed_iwarp_create_listen,
.iwarp_destroy_listen = &qed_iwarp_destroy_listen,
diff --git a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h
index 5ce825ca5f24..60f850c3bdd6 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h
@@ -254,6 +254,10 @@
0x500840UL
#define NIG_REG_LLH_TAGMAC_DEF_PF_VECTOR \
0x50196cUL
+#define NIG_REG_LLH_PPFID2PFID_TBL_0 \
+ 0x501970UL
+#define NIG_REG_LLH_ENG_CLS_ROCE_QP_SEL \
+ 0x50
#define NIG_REG_LLH_CLS_TYPE_DUALMODE \
0x501964UL
#define NIG_REG_LLH_FUNC_TAG_EN 0x5019b0UL
@@ -1626,6 +1630,8 @@
#define PHY_PCIE_REG_PHY1_K2_E5 \
0x624000UL
#define NIG_REG_ROCE_DUPLICATE_TO_HOST 0x5088f0UL
+#define NIG_REG_PPF_TO_ENGINE_SEL 0x508900UL
+#define NIG_REG_PPF_TO_ENGINE_SEL_SIZE 8
#define PRS_REG_LIGHT_L2_ETHERTYPE_EN 0x1f0968UL
#define NIG_REG_LLH_ENG_CLS_ENG_ID_TBL 0x501b90UL
#define DORQ_REG_PF_DPM_ENABLE 0x100510UL
diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c
index 5a495fda9e9d..7e0b795230b2 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c
@@ -588,7 +588,7 @@ int qed_sp_pf_update_stag(struct qed_hwfn *p_hwfn)
{
struct qed_spq_entry *p_ent = NULL;
struct qed_sp_init_data init_data;
- int rc = -EINVAL;
+ int rc;
/* Get SPQ entry */
memset(&init_data, 0, sizeof(init_data));
diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethernet/qlogic/qed/qed_sriov.c
index 2f318aaf2b05..78f77b712b10 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c
@@ -917,10 +917,11 @@ static u8 qed_iov_alloc_vf_igu_sbs(struct qed_hwfn *p_hwfn,
/* Configure igu sb in CAU which were marked valid */
qed_init_cau_sb_entry(p_hwfn, &sb_entry,
p_hwfn->rel_pf_id, vf->abs_vf_id, 1);
+
qed_dmae_host2grc(p_hwfn, p_ptt,
(u64)(uintptr_t)&sb_entry,
CAU_REG_SB_VAR_MEMORY +
- p_block->igu_sb_id * sizeof(u64), 2, 0);
+ p_block->igu_sb_id * sizeof(u64), 2, NULL);
}
vf->num_sbs = (u8) num_rx_queues;
diff --git a/drivers/net/ethernet/qlogic/qede/qede.h b/drivers/net/ethernet/qlogic/qede/qede.h
index 92fe226980fd..0e931c04fecf 100644
--- a/drivers/net/ethernet/qlogic/qede/qede.h
+++ b/drivers/net/ethernet/qlogic/qede/qede.h
@@ -92,6 +92,7 @@ struct qede_stats_common {
u64 non_coalesced_pkts;
u64 coalesced_bytes;
u64 link_change_count;
+ u64 ptp_skip_txts;
/* port */
u64 rx_64_byte_packets;
@@ -189,6 +190,7 @@ struct qede_dev {
const struct qed_eth_ops *ops;
struct qede_ptp *ptp;
+ u64 ptp_skip_txts;
struct qed_dev_eth_info dev_info;
#define QEDE_MAX_RSS_CNT(edev) ((edev)->dev_info.num_queues)
@@ -549,7 +551,7 @@ int qede_txq_has_work(struct qede_tx_queue *txq);
void qede_recycle_rx_bd_ring(struct qede_rx_queue *rxq, u8 count);
void qede_update_rx_prod(struct qede_dev *edev, struct qede_rx_queue *rxq);
int qede_add_tc_flower_fltr(struct qede_dev *edev, __be16 proto,
- struct tc_cls_flower_offload *f);
+ struct flow_cls_offload *f);
#define RX_RING_SIZE_POW 13
#define RX_RING_SIZE ((u16)BIT(RX_RING_SIZE_POW))
diff --git a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c
index 8911a97ab0ca..e85f9fef930c 100644
--- a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c
+++ b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c
@@ -174,6 +174,7 @@ static const struct {
QEDE_STAT(coalesced_bytes),
QEDE_STAT(link_change_count),
+ QEDE_STAT(ptp_skip_txts),
};
#define QEDE_NUM_STATS ARRAY_SIZE(qede_stats_arr)
diff --git a/drivers/net/ethernet/qlogic/qede/qede_filter.c b/drivers/net/ethernet/qlogic/qede/qede_filter.c
index add922b93d2c..9a6a9a008714 100644
--- a/drivers/net/ethernet/qlogic/qede/qede_filter.c
+++ b/drivers/net/ethernet/qlogic/qede/qede_filter.c
@@ -1943,7 +1943,7 @@ qede_parse_flow_attr(struct qede_dev *edev, __be16 proto,
}
int qede_add_tc_flower_fltr(struct qede_dev *edev, __be16 proto,
- struct tc_cls_flower_offload *f)
+ struct flow_cls_offload *f)
{
struct qede_arfs_fltr_node *n;
int min_hlen, rc = -EINVAL;
diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c
index 02a97c659e29..8d1c208f778f 100644
--- a/drivers/net/ethernet/qlogic/qede/qede_main.c
+++ b/drivers/net/ethernet/qlogic/qede/qede_main.c
@@ -390,6 +390,7 @@ void qede_fill_by_demand_stats(struct qede_dev *edev)
p_common->brb_discards = stats.common.brb_discards;
p_common->tx_mac_ctrl_frames = stats.common.tx_mac_ctrl_frames;
p_common->link_change_count = stats.common.link_change_count;
+ p_common->ptp_skip_txts = edev->ptp_skip_txts;
if (QEDE_IS_BB(edev)) {
struct qede_stats_bb *p_bb = &edev->stats.bb;
@@ -547,13 +548,13 @@ static int qede_setup_tc(struct net_device *ndev, u8 num_tc)
}
static int
-qede_set_flower(struct qede_dev *edev, struct tc_cls_flower_offload *f,
+qede_set_flower(struct qede_dev *edev, struct flow_cls_offload *f,
__be16 proto)
{
switch (f->command) {
- case TC_CLSFLOWER_REPLACE:
+ case FLOW_CLS_REPLACE:
return qede_add_tc_flower_fltr(edev, proto, f);
- case TC_CLSFLOWER_DESTROY:
+ case FLOW_CLS_DESTROY:
return qede_delete_flow_filter(edev, f->cookie);
default:
return -EOPNOTSUPP;
@@ -563,7 +564,7 @@ qede_set_flower(struct qede_dev *edev, struct tc_cls_flower_offload *f,
static int qede_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
void *cb_priv)
{
- struct tc_cls_flower_offload *f;
+ struct flow_cls_offload *f;
struct qede_dev *edev = cb_priv;
if (!tc_cls_can_offload_and_chain0(edev->ndev, type_data))
@@ -578,24 +579,7 @@ static int qede_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
}
}
-static int qede_setup_tc_block(struct qede_dev *edev,
- struct tc_block_offload *f)
-{
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
- return -EOPNOTSUPP;
-
- switch (f->command) {
- case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block,
- qede_setup_tc_block_cb,
- edev, edev, f->extack);
- case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block, qede_setup_tc_block_cb, edev);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-}
+static LIST_HEAD(qede_block_cb_list);
static int
qede_setup_tc_offload(struct net_device *dev, enum tc_setup_type type,
@@ -606,7 +590,10 @@ qede_setup_tc_offload(struct net_device *dev, enum tc_setup_type type,
switch (type) {
case TC_SETUP_BLOCK:
- return qede_setup_tc_block(edev, type_data);
+ return flow_block_cb_setup_simple(type_data,
+ &qede_block_cb_list,
+ qede_setup_tc_block_cb,
+ edev, edev, true);
case TC_SETUP_QDISC_MQPRIO:
mqprio = type_data;
@@ -959,13 +946,13 @@ void __qede_unlock(struct qede_dev *edev)
/* This version of the lock should be used when acquiring the RTNL lock is also
* needed in addition to the internal qede lock.
*/
-void qede_lock(struct qede_dev *edev)
+static void qede_lock(struct qede_dev *edev)
{
rtnl_lock();
__qede_lock(edev);
}
-void qede_unlock(struct qede_dev *edev)
+static void qede_unlock(struct qede_dev *edev)
{
__qede_unlock(edev);
rtnl_unlock();
@@ -1306,7 +1293,8 @@ static void qede_free_mem_sb(struct qede_dev *edev, struct qed_sb_info *sb_info,
u16 sb_id)
{
if (sb_info->sb_virt) {
- edev->ops->common->sb_release(edev->cdev, sb_info, sb_id);
+ edev->ops->common->sb_release(edev->cdev, sb_info, sb_id,
+ QED_SB_TYPE_L2_QUEUE);
dma_free_coherent(&edev->pdev->dev, sizeof(*sb_info->sb_virt),
(void *)sb_info->sb_virt, sb_info->sb_phys);
memset(sb_info, 0, sizeof(*sb_info));
@@ -2231,6 +2219,8 @@ out:
if (mode != QEDE_UNLOAD_RECOVERY)
DP_NOTICE(edev, "Link is down\n");
+ edev->ptp_skip_txts = 0;
+
DP_INFO(edev, "Ending qede unload\n");
}
diff --git a/drivers/net/ethernet/qlogic/qede/qede_ptp.c b/drivers/net/ethernet/qlogic/qede/qede_ptp.c
index bddb2b5982dc..f815435cf106 100644
--- a/drivers/net/ethernet/qlogic/qede/qede_ptp.c
+++ b/drivers/net/ethernet/qlogic/qede/qede_ptp.c
@@ -30,6 +30,7 @@
* SOFTWARE.
*/
#include "qede_ptp.h"
+#define QEDE_PTP_TX_TIMEOUT (2 * HZ)
struct qede_ptp {
const struct qed_eth_ptp_ops *ops;
@@ -38,6 +39,7 @@ struct qede_ptp {
struct timecounter tc;
struct ptp_clock *clock;
struct work_struct work;
+ unsigned long ptp_tx_start;
struct qede_dev *edev;
struct sk_buff *tx_skb;
@@ -160,18 +162,30 @@ static void qede_ptp_task(struct work_struct *work)
struct qede_dev *edev;
struct qede_ptp *ptp;
u64 timestamp, ns;
+ bool timedout;
int rc;
ptp = container_of(work, struct qede_ptp, work);
edev = ptp->edev;
+ timedout = time_is_before_jiffies(ptp->ptp_tx_start +
+ QEDE_PTP_TX_TIMEOUT);
/* Read Tx timestamp registers */
spin_lock_bh(&ptp->lock);
rc = ptp->ops->read_tx_ts(edev->cdev, &timestamp);
spin_unlock_bh(&ptp->lock);
if (rc) {
- /* Reschedule to keep checking for a valid timestamp value */
- schedule_work(&ptp->work);
+ if (unlikely(timedout)) {
+ DP_INFO(edev, "Tx timestamp is not recorded\n");
+ dev_kfree_skb_any(ptp->tx_skb);
+ ptp->tx_skb = NULL;
+ clear_bit_unlock(QEDE_FLAGS_PTP_TX_IN_PRORGESS,
+ &edev->flags);
+ edev->ptp_skip_txts++;
+ } else {
+ /* Reschedule to keep checking for a valid TS value */
+ schedule_work(&ptp->work);
+ }
return;
}
@@ -514,19 +528,28 @@ void qede_ptp_tx_ts(struct qede_dev *edev, struct sk_buff *skb)
if (!ptp)
return;
- if (test_and_set_bit_lock(QEDE_FLAGS_PTP_TX_IN_PRORGESS, &edev->flags))
+ if (test_and_set_bit_lock(QEDE_FLAGS_PTP_TX_IN_PRORGESS,
+ &edev->flags)) {
+ DP_ERR(edev, "Timestamping in progress\n");
+ edev->ptp_skip_txts++;
return;
+ }
if (unlikely(!test_bit(QEDE_FLAGS_TX_TIMESTAMPING_EN, &edev->flags))) {
- DP_NOTICE(edev,
- "Tx timestamping was not enabled, this packet will not be timestamped\n");
+ DP_ERR(edev,
+ "Tx timestamping was not enabled, this packet will not be timestamped\n");
+ clear_bit_unlock(QEDE_FLAGS_PTP_TX_IN_PRORGESS, &edev->flags);
+ edev->ptp_skip_txts++;
} else if (unlikely(ptp->tx_skb)) {
- DP_NOTICE(edev,
- "The device supports only a single outstanding packet to timestamp, this packet will not be timestamped\n");
+ DP_ERR(edev,
+ "The device supports only a single outstanding packet to timestamp, this packet will not be timestamped\n");
+ clear_bit_unlock(QEDE_FLAGS_PTP_TX_IN_PRORGESS, &edev->flags);
+ edev->ptp_skip_txts++;
} else {
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
/* schedule check for Tx timestamp */
ptp->tx_skb = skb_get(skb);
+ ptp->ptp_tx_start = jiffies;
schedule_work(&ptp->work);
}
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index 7a873002e626..c07438db30ba 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -4119,13 +4119,14 @@ static void
qlcnic_config_indev_addr(struct qlcnic_adapter *adapter,
struct net_device *dev, unsigned long event)
{
+ const struct in_ifaddr *ifa;
struct in_device *indev;
indev = in_dev_get(dev);
if (!indev)
return;
- for_ifa(indev) {
+ in_dev_for_each_ifa_rtnl(ifa, indev) {
switch (event) {
case NETDEV_UP:
qlcnic_config_ipaddr(adapter,
@@ -4138,7 +4139,7 @@ qlcnic_config_indev_addr(struct qlcnic_adapter *adapter,
default:
break;
}
- } endfor_ifa(indev);
+ }
in_dev_put(indev);
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
index af3b037fa442..5632da05145a 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
@@ -1066,7 +1066,7 @@ static int qlcnic_sriov_pf_cfg_ip_cmd(struct qlcnic_bc_trans *trans,
{
struct qlcnic_vf_info *vf = trans->vf;
struct qlcnic_adapter *adapter = vf->adapter;
- int err = -EIO;
+ int err;
cmd->req.arg[1] |= vf->vp->handle << 16;
cmd->req.arg[1] |= BIT_31;
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h
index 4bf20d0651c4..576501db2a0b 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h
@@ -4,6 +4,7 @@
#ifndef _RMNET_MAP_H_
#define _RMNET_MAP_H_
+#include <linux/if_rmnet.h>
struct rmnet_map_control_command {
u8 command_name;
@@ -31,30 +32,6 @@ enum rmnet_map_commands {
RMNET_MAP_COMMAND_ENUM_LENGTH
};
-struct rmnet_map_header {
- u8 pad_len:6;
- u8 reserved_bit:1;
- u8 cd_bit:1;
- u8 mux_id;
- __be16 pkt_len;
-} __aligned(1);
-
-struct rmnet_map_dl_csum_trailer {
- u8 reserved1;
- u8 valid:1;
- u8 reserved2:7;
- u16 csum_start_offset;
- u16 csum_length;
- __be16 csum_value;
-} __aligned(1);
-
-struct rmnet_map_ul_csum_header {
- __be16 csum_start_offset;
- u16 csum_insert_offset:14;
- u16 udp_ip4_ind:1;
- u16 csum_enabled:1;
-} __aligned(1);
-
#define RMNET_MAP_GET_MUX_ID(Y) (((struct rmnet_map_header *) \
(Y)->data)->mux_id)
#define RMNET_MAP_GET_CD_BIT(Y) (((struct rmnet_map_header *) \
diff --git a/drivers/net/ethernet/realtek/Makefile b/drivers/net/ethernet/realtek/Makefile
index 33be8c5ad0c9..d5304bad2372 100644
--- a/drivers/net/ethernet/realtek/Makefile
+++ b/drivers/net/ethernet/realtek/Makefile
@@ -6,4 +6,5 @@
obj-$(CONFIG_8139CP) += 8139cp.o
obj-$(CONFIG_8139TOO) += 8139too.o
obj-$(CONFIG_ATP) += atp.o
+r8169-objs += r8169_main.o r8169_firmware.o
obj-$(CONFIG_R8169) += r8169.o
diff --git a/drivers/net/ethernet/realtek/r8169_firmware.c b/drivers/net/ethernet/realtek/r8169_firmware.c
new file mode 100644
index 000000000000..8f54a2c832eb
--- /dev/null
+++ b/drivers/net/ethernet/realtek/r8169_firmware.c
@@ -0,0 +1,231 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* r8169_firmware.c: RealTek 8169/8168/8101 ethernet driver.
+ *
+ * Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
+ * Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
+ * Copyright (c) a lot of people too. Please respect their work.
+ *
+ * See MAINTAINERS file for support contact information.
+ */
+
+#include <linux/delay.h>
+#include <linux/firmware.h>
+
+#include "r8169_firmware.h"
+
+enum rtl_fw_opcode {
+ PHY_READ = 0x0,
+ PHY_DATA_OR = 0x1,
+ PHY_DATA_AND = 0x2,
+ PHY_BJMPN = 0x3,
+ PHY_MDIO_CHG = 0x4,
+ PHY_CLEAR_READCOUNT = 0x7,
+ PHY_WRITE = 0x8,
+ PHY_READCOUNT_EQ_SKIP = 0x9,
+ PHY_COMP_EQ_SKIPN = 0xa,
+ PHY_COMP_NEQ_SKIPN = 0xb,
+ PHY_WRITE_PREVIOUS = 0xc,
+ PHY_SKIPN = 0xd,
+ PHY_DELAY_MS = 0xe,
+};
+
+struct fw_info {
+ u32 magic;
+ char version[RTL_VER_SIZE];
+ __le32 fw_start;
+ __le32 fw_len;
+ u8 chksum;
+} __packed;
+
+#define FW_OPCODE_SIZE sizeof(typeof(*((struct rtl_fw_phy_action *)0)->code))
+
+static bool rtl_fw_format_ok(struct rtl_fw *rtl_fw)
+{
+ const struct firmware *fw = rtl_fw->fw;
+ struct fw_info *fw_info = (struct fw_info *)fw->data;
+ struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
+
+ if (fw->size < FW_OPCODE_SIZE)
+ return false;
+
+ if (!fw_info->magic) {
+ size_t i, size, start;
+ u8 checksum = 0;
+
+ if (fw->size < sizeof(*fw_info))
+ return false;
+
+ for (i = 0; i < fw->size; i++)
+ checksum += fw->data[i];
+ if (checksum != 0)
+ return false;
+
+ start = le32_to_cpu(fw_info->fw_start);
+ if (start > fw->size)
+ return false;
+
+ size = le32_to_cpu(fw_info->fw_len);
+ if (size > (fw->size - start) / FW_OPCODE_SIZE)
+ return false;
+
+ strscpy(rtl_fw->version, fw_info->version, RTL_VER_SIZE);
+
+ pa->code = (__le32 *)(fw->data + start);
+ pa->size = size;
+ } else {
+ if (fw->size % FW_OPCODE_SIZE)
+ return false;
+
+ strscpy(rtl_fw->version, rtl_fw->fw_name, RTL_VER_SIZE);
+
+ pa->code = (__le32 *)fw->data;
+ pa->size = fw->size / FW_OPCODE_SIZE;
+ }
+
+ return true;
+}
+
+static bool rtl_fw_data_ok(struct rtl_fw *rtl_fw)
+{
+ struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
+ size_t index;
+
+ for (index = 0; index < pa->size; index++) {
+ u32 action = le32_to_cpu(pa->code[index]);
+ u32 regno = (action & 0x0fff0000) >> 16;
+
+ switch (action >> 28) {
+ case PHY_READ:
+ case PHY_DATA_OR:
+ case PHY_DATA_AND:
+ case PHY_MDIO_CHG:
+ case PHY_CLEAR_READCOUNT:
+ case PHY_WRITE:
+ case PHY_WRITE_PREVIOUS:
+ case PHY_DELAY_MS:
+ break;
+
+ case PHY_BJMPN:
+ if (regno > index)
+ goto out;
+ break;
+ case PHY_READCOUNT_EQ_SKIP:
+ if (index + 2 >= pa->size)
+ goto out;
+ break;
+ case PHY_COMP_EQ_SKIPN:
+ case PHY_COMP_NEQ_SKIPN:
+ case PHY_SKIPN:
+ if (index + 1 + regno >= pa->size)
+ goto out;
+ break;
+
+ default:
+ dev_err(rtl_fw->dev, "Invalid action 0x%08x\n", action);
+ return false;
+ }
+ }
+
+ return true;
+out:
+ dev_err(rtl_fw->dev, "Out of range of firmware\n");
+ return false;
+}
+
+void rtl_fw_write_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
+{
+ struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
+ rtl_fw_write_t fw_write = rtl_fw->phy_write;
+ rtl_fw_read_t fw_read = rtl_fw->phy_read;
+ int predata = 0, count = 0;
+ size_t index;
+
+ for (index = 0; index < pa->size; index++) {
+ u32 action = le32_to_cpu(pa->code[index]);
+ u32 data = action & 0x0000ffff;
+ u32 regno = (action & 0x0fff0000) >> 16;
+ enum rtl_fw_opcode opcode = action >> 28;
+
+ if (!action)
+ break;
+
+ switch (opcode) {
+ case PHY_READ:
+ predata = fw_read(tp, regno);
+ count++;
+ break;
+ case PHY_DATA_OR:
+ predata |= data;
+ break;
+ case PHY_DATA_AND:
+ predata &= data;
+ break;
+ case PHY_BJMPN:
+ index -= (regno + 1);
+ break;
+ case PHY_MDIO_CHG:
+ if (data == 0) {
+ fw_write = rtl_fw->phy_write;
+ fw_read = rtl_fw->phy_read;
+ } else if (data == 1) {
+ fw_write = rtl_fw->mac_mcu_write;
+ fw_read = rtl_fw->mac_mcu_read;
+ }
+
+ break;
+ case PHY_CLEAR_READCOUNT:
+ count = 0;
+ break;
+ case PHY_WRITE:
+ fw_write(tp, regno, data);
+ break;
+ case PHY_READCOUNT_EQ_SKIP:
+ if (count == data)
+ index++;
+ break;
+ case PHY_COMP_EQ_SKIPN:
+ if (predata == data)
+ index += regno;
+ break;
+ case PHY_COMP_NEQ_SKIPN:
+ if (predata != data)
+ index += regno;
+ break;
+ case PHY_WRITE_PREVIOUS:
+ fw_write(tp, regno, predata);
+ break;
+ case PHY_SKIPN:
+ index += regno;
+ break;
+ case PHY_DELAY_MS:
+ mdelay(data);
+ break;
+ }
+ }
+}
+
+void rtl_fw_release_firmware(struct rtl_fw *rtl_fw)
+{
+ release_firmware(rtl_fw->fw);
+}
+
+int rtl_fw_request_firmware(struct rtl_fw *rtl_fw)
+{
+ int rc;
+
+ rc = request_firmware(&rtl_fw->fw, rtl_fw->fw_name, rtl_fw->dev);
+ if (rc < 0)
+ goto out;
+
+ if (!rtl_fw_format_ok(rtl_fw) || !rtl_fw_data_ok(rtl_fw)) {
+ release_firmware(rtl_fw->fw);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ return 0;
+out:
+ dev_err(rtl_fw->dev, "Unable to load firmware %s (%d)\n",
+ rtl_fw->fw_name, rc);
+ return rc;
+}
diff --git a/drivers/net/ethernet/realtek/r8169_firmware.h b/drivers/net/ethernet/realtek/r8169_firmware.h
new file mode 100644
index 000000000000..7dc348ed8345
--- /dev/null
+++ b/drivers/net/ethernet/realtek/r8169_firmware.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* r8169_firmware.h: RealTek 8169/8168/8101 ethernet driver.
+ *
+ * Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
+ * Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
+ * Copyright (c) a lot of people too. Please respect their work.
+ *
+ * See MAINTAINERS file for support contact information.
+ */
+
+#include <linux/device.h>
+#include <linux/firmware.h>
+
+struct rtl8169_private;
+typedef void (*rtl_fw_write_t)(struct rtl8169_private *tp, int reg, int val);
+typedef int (*rtl_fw_read_t)(struct rtl8169_private *tp, int reg);
+
+#define RTL_VER_SIZE 32
+
+struct rtl_fw {
+ rtl_fw_write_t phy_write;
+ rtl_fw_read_t phy_read;
+ rtl_fw_write_t mac_mcu_write;
+ rtl_fw_read_t mac_mcu_read;
+ const struct firmware *fw;
+ const char *fw_name;
+ struct device *dev;
+
+ char version[RTL_VER_SIZE];
+
+ struct rtl_fw_phy_action {
+ __le32 *code;
+ size_t size;
+ } phy_action;
+};
+
+int rtl_fw_request_firmware(struct rtl_fw *rtl_fw);
+void rtl_fw_release_firmware(struct rtl_fw *rtl_fw);
+void rtl_fw_write_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw);
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169_main.c
index d06a61f00e78..0637c6752a78 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -27,12 +27,13 @@
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/pm_runtime.h>
-#include <linux/firmware.h>
#include <linux/prefetch.h>
#include <linux/pci-aspm.h>
#include <linux/ipv6.h>
#include <net/ip6_checksum.h>
+#include "r8169_firmware.h"
+
#define MODULENAME "r8169"
#define FIRMWARE_8168D_1 "rtl_nic/rtl8168d-1.fw"
@@ -72,6 +73,8 @@ static const int multicast_filter_limit = 32;
#define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc))
#define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc))
+#define RTL_CFG_NO_GBIT 1
+
/* write/read MMIO register */
#define RTL_W8(tp, reg, val8) writeb((val8), tp->mmio_addr + (reg))
#define RTL_W16(tp, reg, val16) writew((val16), tp->mmio_addr + (reg))
@@ -81,7 +84,7 @@ static const int multicast_filter_limit = 32;
#define RTL_R32(tp, reg) readl(tp->mmio_addr + (reg))
enum mac_version {
- RTL_GIGA_MAC_VER_01 = 0,
+ /* support for ancient RTL_GIGA_MAC_VER_01 has been removed */
RTL_GIGA_MAC_VER_02,
RTL_GIGA_MAC_VER_03,
RTL_GIGA_MAC_VER_04,
@@ -132,7 +135,7 @@ enum mac_version {
RTL_GIGA_MAC_VER_49,
RTL_GIGA_MAC_VER_50,
RTL_GIGA_MAC_VER_51,
- RTL_GIGA_MAC_NONE = 0xff,
+ RTL_GIGA_MAC_NONE
};
#define JUMBO_1K ETH_DATA_LEN
@@ -146,7 +149,6 @@ static const struct {
const char *fw_name;
} rtl_chip_infos[] = {
/* PCI devices. */
- [RTL_GIGA_MAC_VER_01] = {"RTL8169" },
[RTL_GIGA_MAC_VER_02] = {"RTL8169s" },
[RTL_GIGA_MAC_VER_03] = {"RTL8110s" },
[RTL_GIGA_MAC_VER_04] = {"RTL8169sb/8110sb" },
@@ -155,7 +157,7 @@ static const struct {
/* PCI-E devices. */
[RTL_GIGA_MAC_VER_07] = {"RTL8102e" },
[RTL_GIGA_MAC_VER_08] = {"RTL8102e" },
- [RTL_GIGA_MAC_VER_09] = {"RTL8102e" },
+ [RTL_GIGA_MAC_VER_09] = {"RTL8102e/RTL8103e" },
[RTL_GIGA_MAC_VER_10] = {"RTL8101e" },
[RTL_GIGA_MAC_VER_11] = {"RTL8168b/8111b" },
[RTL_GIGA_MAC_VER_12] = {"RTL8168b/8111b" },
@@ -188,9 +190,9 @@ static const struct {
[RTL_GIGA_MAC_VER_39] = {"RTL8106e", FIRMWARE_8106E_1},
[RTL_GIGA_MAC_VER_40] = {"RTL8168g/8111g", FIRMWARE_8168G_2},
[RTL_GIGA_MAC_VER_41] = {"RTL8168g/8111g" },
- [RTL_GIGA_MAC_VER_42] = {"RTL8168g/8111g", FIRMWARE_8168G_3},
- [RTL_GIGA_MAC_VER_43] = {"RTL8106e", FIRMWARE_8106E_2},
- [RTL_GIGA_MAC_VER_44] = {"RTL8411", FIRMWARE_8411_2 },
+ [RTL_GIGA_MAC_VER_42] = {"RTL8168gu/8111gu", FIRMWARE_8168G_3},
+ [RTL_GIGA_MAC_VER_43] = {"RTL8106eus", FIRMWARE_8106E_2},
+ [RTL_GIGA_MAC_VER_44] = {"RTL8411b", FIRMWARE_8411_2 },
[RTL_GIGA_MAC_VER_45] = {"RTL8168h/8111h", FIRMWARE_8168H_1},
[RTL_GIGA_MAC_VER_46] = {"RTL8168h/8111h", FIRMWARE_8168H_2},
[RTL_GIGA_MAC_VER_47] = {"RTL8107e", FIRMWARE_8107E_1},
@@ -200,32 +202,24 @@ static const struct {
[RTL_GIGA_MAC_VER_51] = {"RTL8168ep/8111ep" },
};
-enum cfg_version {
- RTL_CFG_0 = 0x00,
- RTL_CFG_1,
- RTL_CFG_2
-};
-
static const struct pci_device_id rtl8169_pci_tbl[] = {
- { PCI_VDEVICE(REALTEK, 0x2502), RTL_CFG_1 },
- { PCI_VDEVICE(REALTEK, 0x2600), RTL_CFG_1 },
- { PCI_VDEVICE(REALTEK, 0x8129), RTL_CFG_0 },
- { PCI_VDEVICE(REALTEK, 0x8136), RTL_CFG_2 },
- { PCI_VDEVICE(REALTEK, 0x8161), RTL_CFG_1 },
- { PCI_VDEVICE(REALTEK, 0x8167), RTL_CFG_0 },
- { PCI_VDEVICE(REALTEK, 0x8168), RTL_CFG_1 },
- { PCI_VDEVICE(NCUBE, 0x8168), RTL_CFG_1 },
- { PCI_VDEVICE(REALTEK, 0x8169), RTL_CFG_0 },
+ { PCI_VDEVICE(REALTEK, 0x2502) },
+ { PCI_VDEVICE(REALTEK, 0x2600) },
+ { PCI_VDEVICE(REALTEK, 0x8129) },
+ { PCI_VDEVICE(REALTEK, 0x8136), RTL_CFG_NO_GBIT },
+ { PCI_VDEVICE(REALTEK, 0x8161) },
+ { PCI_VDEVICE(REALTEK, 0x8167) },
+ { PCI_VDEVICE(REALTEK, 0x8168) },
+ { PCI_VDEVICE(NCUBE, 0x8168) },
+ { PCI_VDEVICE(REALTEK, 0x8169) },
{ PCI_VENDOR_ID_DLINK, 0x4300,
- PCI_VENDOR_ID_DLINK, 0x4b10, 0, 0, RTL_CFG_1 },
- { PCI_VDEVICE(DLINK, 0x4300), RTL_CFG_0 },
- { PCI_VDEVICE(DLINK, 0x4302), RTL_CFG_0 },
- { PCI_VDEVICE(AT, 0xc107), RTL_CFG_0 },
- { PCI_VDEVICE(USR, 0x0116), RTL_CFG_0 },
- { PCI_VENDOR_ID_LINKSYS, 0x1032,
- PCI_ANY_ID, 0x0024, 0, 0, RTL_CFG_0 },
- { 0x0001, 0x8168,
- PCI_ANY_ID, 0x2410, 0, 0, RTL_CFG_2 },
+ PCI_VENDOR_ID_DLINK, 0x4b10, 0, 0 },
+ { PCI_VDEVICE(DLINK, 0x4300) },
+ { PCI_VDEVICE(DLINK, 0x4302) },
+ { PCI_VDEVICE(AT, 0xc107) },
+ { PCI_VDEVICE(USR, 0x0116) },
+ { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0024 },
+ { 0x0001, 0x8168, PCI_ANY_ID, 0x2410 },
{}
};
@@ -406,8 +400,6 @@ enum rtl_register_content {
RxOK = 0x0001,
/* RxStatusDesc */
- RxBOVF = (1 << 24),
- RxFOVF = (1 << 23),
RxRWT = (1 << 22),
RxRES = (1 << 21),
RxRUNT = (1 << 20),
@@ -492,6 +484,7 @@ enum rtl_register_content {
PCIDAC = (1 << 4),
PCIMulRW = (1 << 3),
#define INTT_MASK GENMASK(1, 0)
+#define CPCMD_MASK (Normal_mode | RxVlan | RxChkSum | INTT_MASK)
/* rtl8169_PHYstatus */
TBI_Enable = 0x80,
@@ -503,9 +496,6 @@ enum rtl_register_content {
LinkStatus = 0x02,
FullDup = 0x01,
- /* _TBICSRBit */
- TBILinkOK = 0x02000000,
-
/* ResetCounterCommand */
CounterReset = 0x1,
@@ -578,7 +568,6 @@ enum rtl_rx_desc_bit {
};
#define RsvdMask 0x3fffc000
-#define CPCMD_QUIRK_MASK (Normal_mode | RxVlan | RxChkSum | INTT_MASK)
struct TxDesc {
__le32 opts1;
@@ -639,7 +628,7 @@ struct rtl8169_private {
struct phy_device *phydev;
struct napi_struct napi;
u32 msg_enable;
- u16 mac_version;
+ enum mac_version mac_version;
u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
u32 dirty_tx;
@@ -652,24 +641,9 @@ struct rtl8169_private {
void *Rx_databuff[NUM_RX_DESC]; /* Rx data buffers */
struct ring_info tx_skb[NUM_TX_DESC]; /* Tx data buffers */
u16 cp_cmd;
-
u16 irq_mask;
- const struct rtl_coalesce_info *coalesce_info;
struct clk *clk;
- struct mdio_ops {
- void (*write)(struct rtl8169_private *, int, int);
- int (*read)(struct rtl8169_private *, int);
- } mdio_ops;
-
- struct jumbo_ops {
- void (*enable)(struct rtl8169_private *);
- void (*disable)(struct rtl8169_private *);
- } jumbo_ops;
-
- void (*hw_start)(struct rtl8169_private *tp);
- bool (*tso_csum)(struct rtl8169_private *, struct sk_buff *, u32 *);
-
struct {
DECLARE_BITMAP(flags, RTL_FLAG_MAX);
struct mutex mutex;
@@ -678,24 +652,14 @@ struct rtl8169_private {
unsigned irq_enabled:1;
unsigned supports_gmii:1;
+ unsigned aspm_manageable:1;
dma_addr_t counters_phys_addr;
struct rtl8169_counters *counters;
struct rtl8169_tc_offsets tc_offset;
u32 saved_wolopts;
const char *fw_name;
- struct rtl_fw {
- const struct firmware *fw;
-
-#define RTL_VER_SIZE 32
-
- char version[RTL_VER_SIZE];
-
- struct rtl_fw_phy_action {
- __le32 *code;
- size_t size;
- } phy_action;
- } *rtl_fw;
+ struct rtl_fw *rtl_fw;
u32 ocp_base;
};
@@ -759,6 +723,12 @@ static void rtl_tx_performance_tweak(struct rtl8169_private *tp, u16 force)
PCI_EXP_DEVCTL_READRQ, force);
}
+static bool rtl_is_8168evl_up(struct rtl8169_private *tp)
+{
+ return tp->mac_version >= RTL_GIGA_MAC_VER_34 &&
+ tp->mac_version != RTL_GIGA_MAC_VER_39;
+}
+
struct rtl_cond {
bool (*check)(struct rtl8169_private *);
const char *msg;
@@ -847,7 +817,7 @@ static void r8168_phy_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
rtl_udelay_loop_wait_low(tp, &rtl_ocp_gphy_cond, 25, 10);
}
-static u16 r8168_phy_ocp_read(struct rtl8169_private *tp, u32 reg)
+static int r8168_phy_ocp_read(struct rtl8169_private *tp, u32 reg)
{
if (rtl_ocp_reg_failure(tp, reg))
return 0;
@@ -855,7 +825,7 @@ static u16 r8168_phy_ocp_read(struct rtl8169_private *tp, u32 reg)
RTL_W32(tp, GPHY_OCP, reg << 15);
return rtl_udelay_loop_wait_high(tp, &rtl_ocp_gphy_cond, 25, 10) ?
- (RTL_R32(tp, GPHY_OCP) & 0xffff) : ~0;
+ (RTL_R32(tp, GPHY_OCP) & 0xffff) : -ETIMEDOUT;
}
static void r8168_mac_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
@@ -938,7 +908,7 @@ static int r8169_mdio_read(struct rtl8169_private *tp, int reg)
RTL_W32(tp, PHYAR, 0x0 | (reg & 0x1f) << 16);
value = rtl_udelay_loop_wait_high(tp, &rtl_phyar_cond, 25, 20) ?
- RTL_R32(tp, PHYAR) & 0xffff : ~0;
+ RTL_R32(tp, PHYAR) & 0xffff : -ETIMEDOUT;
/*
* According to hardware specs a 20us delay is required after read
@@ -978,7 +948,7 @@ static int r8168dp_1_mdio_read(struct rtl8169_private *tp, int reg)
RTL_W32(tp, EPHY_RXER_NUM, 0);
return rtl_udelay_loop_wait_high(tp, &rtl_ocpar_cond, 1000, 100) ?
- RTL_R32(tp, OCPDR) & OCPDR_DATA_MASK : ~0;
+ RTL_R32(tp, OCPDR) & OCPDR_DATA_MASK : -ETIMEDOUT;
}
#define R8168DP_1_MDIO_ACCESS_BIT 0x00020000
@@ -1015,14 +985,38 @@ static int r8168dp_2_mdio_read(struct rtl8169_private *tp, int reg)
return value;
}
-static void rtl_writephy(struct rtl8169_private *tp, int location, u32 val)
+static void rtl_writephy(struct rtl8169_private *tp, int location, int val)
{
- tp->mdio_ops.write(tp, location, val);
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_27:
+ r8168dp_1_mdio_write(tp, location, val);
+ break;
+ case RTL_GIGA_MAC_VER_28:
+ case RTL_GIGA_MAC_VER_31:
+ r8168dp_2_mdio_write(tp, location, val);
+ break;
+ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_51:
+ r8168g_mdio_write(tp, location, val);
+ break;
+ default:
+ r8169_mdio_write(tp, location, val);
+ break;
+ }
}
static int rtl_readphy(struct rtl8169_private *tp, int location)
{
- return tp->mdio_ops.read(tp, location);
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_27:
+ return r8168dp_1_mdio_read(tp, location);
+ case RTL_GIGA_MAC_VER_28:
+ case RTL_GIGA_MAC_VER_31:
+ return r8168dp_2_mdio_read(tp, location);
+ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_51:
+ return r8168g_mdio_read(tp, location);
+ default:
+ return r8169_mdio_read(tp, location);
+ }
}
static void rtl_patchphy(struct rtl8169_private *tp, int reg_addr, int value)
@@ -1400,9 +1394,7 @@ static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts)
rtl_unlock_config_regs(tp);
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_38:
- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_51:
+ if (rtl_is_8168evl_up(tp)) {
tmp = ARRAY_SIZE(cfg) - 1;
if (wolopts & WAKE_MAGIC)
rtl_eri_set_bits(tp, 0x0dc, ERIAR_MASK_0100,
@@ -1410,10 +1402,8 @@ static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts)
else
rtl_eri_clear_bits(tp, 0x0dc, ERIAR_MASK_0100,
MagicPacket_v2);
- break;
- default:
+ } else {
tmp = ARRAY_SIZE(cfg);
- break;
}
for (i = 0; i < tmp; i++) {
@@ -1424,7 +1414,7 @@ static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts)
}
switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_01 ... RTL_GIGA_MAC_VER_17:
+ case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_17:
options = RTL_R8(tp, Config1) & ~PMEnable;
if (wolopts)
options |= PMEnable;
@@ -1794,18 +1784,16 @@ static const struct rtl_coalesce_info rtl_coalesce_info_8168_8136[] = {
static const struct rtl_coalesce_info *rtl_coalesce_info(struct net_device *dev)
{
struct rtl8169_private *tp = netdev_priv(dev);
- struct ethtool_link_ksettings ecmd;
const struct rtl_coalesce_info *ci;
- int rc;
- rc = phy_ethtool_get_link_ksettings(dev, &ecmd);
- if (rc < 0)
- return ERR_PTR(rc);
+ if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
+ ci = rtl_coalesce_info_8169;
+ else
+ ci = rtl_coalesce_info_8168_8136;
- for (ci = tp->coalesce_info; ci->speed != 0; ci++) {
- if (ecmd.base.speed == ci->speed) {
+ for (; ci->speed; ci++) {
+ if (tp->phydev->speed == ci->speed)
return ci;
- }
}
return ERR_PTR(-ELNRNG);
@@ -1954,9 +1942,7 @@ static int rtl_get_eee_supp(struct rtl8169_private *tp)
ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE);
break;
case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_51:
- phy_write(phydev, 0x1f, 0x0a5c);
- ret = phy_read(phydev, 0x12);
- phy_write(phydev, 0x1f, 0x0000);
+ ret = phy_read_paged(phydev, 0x0a5c, 0x12);
break;
default:
ret = -EPROTONOSUPPORT;
@@ -1979,9 +1965,7 @@ static int rtl_get_eee_lpadv(struct rtl8169_private *tp)
ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_LPABLE);
break;
case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_51:
- phy_write(phydev, 0x1f, 0x0a5d);
- ret = phy_read(phydev, 0x11);
- phy_write(phydev, 0x1f, 0x0000);
+ ret = phy_read_paged(phydev, 0x0a5d, 0x11);
break;
default:
ret = -EPROTONOSUPPORT;
@@ -2004,9 +1988,7 @@ static int rtl_get_eee_adv(struct rtl8169_private *tp)
ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV);
break;
case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_51:
- phy_write(phydev, 0x1f, 0x0a5d);
- ret = phy_read(phydev, 0x10);
- phy_write(phydev, 0x1f, 0x0000);
+ ret = phy_read_paged(phydev, 0x0a5d, 0x10);
break;
default:
ret = -EPROTONOSUPPORT;
@@ -2029,9 +2011,7 @@ static int rtl_set_eee_adv(struct rtl8169_private *tp, int val)
ret = phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, val);
break;
case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_51:
- phy_write(phydev, 0x1f, 0x0a5d);
- phy_write(phydev, 0x10, val);
- phy_write(phydev, 0x1f, 0x0000);
+ phy_write_paged(phydev, 0x0a5d, 0x10, val);
break;
default:
ret = -EPROTONOSUPPORT;
@@ -2252,7 +2232,6 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp)
{ 0xfc8, 0x100, RTL_GIGA_MAC_VER_04 },
{ 0xfc8, 0x040, RTL_GIGA_MAC_VER_03 },
{ 0xfc8, 0x008, RTL_GIGA_MAC_VER_02 },
- { 0xfc8, 0x000, RTL_GIGA_MAC_VER_01 },
/* Catch-all */
{ 0x000, 0x000, RTL_GIGA_MAC_NONE }
@@ -2292,246 +2271,10 @@ static void __rtl_writephy_batch(struct rtl8169_private *tp,
#define rtl_writephy_batch(tp, a) __rtl_writephy_batch(tp, a, ARRAY_SIZE(a))
-#define PHY_READ 0x00000000
-#define PHY_DATA_OR 0x10000000
-#define PHY_DATA_AND 0x20000000
-#define PHY_BJMPN 0x30000000
-#define PHY_MDIO_CHG 0x40000000
-#define PHY_CLEAR_READCOUNT 0x70000000
-#define PHY_WRITE 0x80000000
-#define PHY_READCOUNT_EQ_SKIP 0x90000000
-#define PHY_COMP_EQ_SKIPN 0xa0000000
-#define PHY_COMP_NEQ_SKIPN 0xb0000000
-#define PHY_WRITE_PREVIOUS 0xc0000000
-#define PHY_SKIPN 0xd0000000
-#define PHY_DELAY_MS 0xe0000000
-
-struct fw_info {
- u32 magic;
- char version[RTL_VER_SIZE];
- __le32 fw_start;
- __le32 fw_len;
- u8 chksum;
-} __packed;
-
-#define FW_OPCODE_SIZE sizeof(typeof(*((struct rtl_fw_phy_action *)0)->code))
-
-static bool rtl_fw_format_ok(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
-{
- const struct firmware *fw = rtl_fw->fw;
- struct fw_info *fw_info = (struct fw_info *)fw->data;
- struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
- char *version = rtl_fw->version;
- bool rc = false;
-
- if (fw->size < FW_OPCODE_SIZE)
- goto out;
-
- if (!fw_info->magic) {
- size_t i, size, start;
- u8 checksum = 0;
-
- if (fw->size < sizeof(*fw_info))
- goto out;
-
- for (i = 0; i < fw->size; i++)
- checksum += fw->data[i];
- if (checksum != 0)
- goto out;
-
- start = le32_to_cpu(fw_info->fw_start);
- if (start > fw->size)
- goto out;
-
- size = le32_to_cpu(fw_info->fw_len);
- if (size > (fw->size - start) / FW_OPCODE_SIZE)
- goto out;
-
- memcpy(version, fw_info->version, RTL_VER_SIZE);
-
- pa->code = (__le32 *)(fw->data + start);
- pa->size = size;
- } else {
- if (fw->size % FW_OPCODE_SIZE)
- goto out;
-
- strlcpy(version, tp->fw_name, RTL_VER_SIZE);
-
- pa->code = (__le32 *)fw->data;
- pa->size = fw->size / FW_OPCODE_SIZE;
- }
- version[RTL_VER_SIZE - 1] = 0;
-
- rc = true;
-out:
- return rc;
-}
-
-static bool rtl_fw_data_ok(struct rtl8169_private *tp, struct net_device *dev,
- struct rtl_fw_phy_action *pa)
-{
- bool rc = false;
- size_t index;
-
- for (index = 0; index < pa->size; index++) {
- u32 action = le32_to_cpu(pa->code[index]);
- u32 regno = (action & 0x0fff0000) >> 16;
-
- switch(action & 0xf0000000) {
- case PHY_READ:
- case PHY_DATA_OR:
- case PHY_DATA_AND:
- case PHY_MDIO_CHG:
- case PHY_CLEAR_READCOUNT:
- case PHY_WRITE:
- case PHY_WRITE_PREVIOUS:
- case PHY_DELAY_MS:
- break;
-
- case PHY_BJMPN:
- if (regno > index) {
- netif_err(tp, ifup, tp->dev,
- "Out of range of firmware\n");
- goto out;
- }
- break;
- case PHY_READCOUNT_EQ_SKIP:
- if (index + 2 >= pa->size) {
- netif_err(tp, ifup, tp->dev,
- "Out of range of firmware\n");
- goto out;
- }
- break;
- case PHY_COMP_EQ_SKIPN:
- case PHY_COMP_NEQ_SKIPN:
- case PHY_SKIPN:
- if (index + 1 + regno >= pa->size) {
- netif_err(tp, ifup, tp->dev,
- "Out of range of firmware\n");
- goto out;
- }
- break;
-
- default:
- netif_err(tp, ifup, tp->dev,
- "Invalid action 0x%08x\n", action);
- goto out;
- }
- }
- rc = true;
-out:
- return rc;
-}
-
-static int rtl_check_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
-{
- struct net_device *dev = tp->dev;
- int rc = -EINVAL;
-
- if (!rtl_fw_format_ok(tp, rtl_fw)) {
- netif_err(tp, ifup, dev, "invalid firmware\n");
- goto out;
- }
-
- if (rtl_fw_data_ok(tp, dev, &rtl_fw->phy_action))
- rc = 0;
-out:
- return rc;
-}
-
-static void rtl_phy_write_fw(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
-{
- struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
- struct mdio_ops org, *ops = &tp->mdio_ops;
- u32 predata, count;
- size_t index;
-
- predata = count = 0;
- org.write = ops->write;
- org.read = ops->read;
-
- for (index = 0; index < pa->size; ) {
- u32 action = le32_to_cpu(pa->code[index]);
- u32 data = action & 0x0000ffff;
- u32 regno = (action & 0x0fff0000) >> 16;
-
- if (!action)
- break;
-
- switch(action & 0xf0000000) {
- case PHY_READ:
- predata = rtl_readphy(tp, regno);
- count++;
- index++;
- break;
- case PHY_DATA_OR:
- predata |= data;
- index++;
- break;
- case PHY_DATA_AND:
- predata &= data;
- index++;
- break;
- case PHY_BJMPN:
- index -= regno;
- break;
- case PHY_MDIO_CHG:
- if (data == 0) {
- ops->write = org.write;
- ops->read = org.read;
- } else if (data == 1) {
- ops->write = mac_mcu_write;
- ops->read = mac_mcu_read;
- }
-
- index++;
- break;
- case PHY_CLEAR_READCOUNT:
- count = 0;
- index++;
- break;
- case PHY_WRITE:
- rtl_writephy(tp, regno, data);
- index++;
- break;
- case PHY_READCOUNT_EQ_SKIP:
- index += (count == data) ? 2 : 1;
- break;
- case PHY_COMP_EQ_SKIPN:
- if (predata == data)
- index += regno;
- index++;
- break;
- case PHY_COMP_NEQ_SKIPN:
- if (predata != data)
- index += regno;
- index++;
- break;
- case PHY_WRITE_PREVIOUS:
- rtl_writephy(tp, regno, predata);
- index++;
- break;
- case PHY_SKIPN:
- index += regno + 1;
- break;
- case PHY_DELAY_MS:
- mdelay(data);
- index++;
- break;
-
- default:
- BUG();
- }
- }
-
- ops->write = org.write;
- ops->read = org.read;
-}
-
static void rtl_release_firmware(struct rtl8169_private *tp)
{
if (tp->rtl_fw) {
- release_firmware(tp->rtl_fw->fw);
+ rtl_fw_release_firmware(tp->rtl_fw);
kfree(tp->rtl_fw);
tp->rtl_fw = NULL;
}
@@ -2539,9 +2282,9 @@ static void rtl_release_firmware(struct rtl8169_private *tp)
static void rtl_apply_firmware(struct rtl8169_private *tp)
{
- /* TODO: release firmware once rtl_phy_write_fw signals failures. */
+ /* TODO: release firmware if rtl_fw_write_firmware signals failure. */
if (tp->rtl_fw)
- rtl_phy_write_fw(tp, tp->rtl_fw);
+ rtl_fw_write_firmware(tp, tp->rtl_fw);
}
static void rtl_apply_firmware_cond(struct rtl8169_private *tp, u8 reg, u16 val)
@@ -2578,9 +2321,7 @@ static void rtl8168f_config_eee_phy(struct rtl8169_private *tp)
static void rtl8168g_config_eee_phy(struct rtl8169_private *tp)
{
- phy_write(tp->phydev, 0x1f, 0x0a43);
- phy_set_bits(tp->phydev, 0x11, BIT(4));
- phy_write(tp->phydev, 0x1f, 0x0000);
+ phy_modify_paged(tp->phydev, 0x0a43, 0x11, 0, BIT(4));
}
static void rtl8169s_hw_phy_config(struct rtl8169_private *tp)
@@ -2910,50 +2651,59 @@ static void rtl8168c_4_hw_phy_config(struct rtl8169_private *tp)
rtl8168c_3_hw_phy_config(tp);
}
-static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp)
-{
- static const struct phy_reg phy_reg_init_0[] = {
- /* Channel Estimation */
- { 0x1f, 0x0001 },
- { 0x06, 0x4064 },
- { 0x07, 0x2863 },
- { 0x08, 0x059c },
- { 0x09, 0x26b4 },
- { 0x0a, 0x6a19 },
- { 0x0b, 0xdcc8 },
- { 0x10, 0xf06d },
- { 0x14, 0x7f68 },
- { 0x18, 0x7fd9 },
- { 0x1c, 0xf0ff },
- { 0x1d, 0x3d9c },
- { 0x1f, 0x0003 },
- { 0x12, 0xf49f },
- { 0x13, 0x070b },
- { 0x1a, 0x05ad },
- { 0x14, 0x94c0 },
+static const struct phy_reg rtl8168d_1_phy_reg_init_0[] = {
+ /* Channel Estimation */
+ { 0x1f, 0x0001 },
+ { 0x06, 0x4064 },
+ { 0x07, 0x2863 },
+ { 0x08, 0x059c },
+ { 0x09, 0x26b4 },
+ { 0x0a, 0x6a19 },
+ { 0x0b, 0xdcc8 },
+ { 0x10, 0xf06d },
+ { 0x14, 0x7f68 },
+ { 0x18, 0x7fd9 },
+ { 0x1c, 0xf0ff },
+ { 0x1d, 0x3d9c },
+ { 0x1f, 0x0003 },
+ { 0x12, 0xf49f },
+ { 0x13, 0x070b },
+ { 0x1a, 0x05ad },
+ { 0x14, 0x94c0 },
- /*
- * Tx Error Issue
- * Enhance line driver power
- */
- { 0x1f, 0x0002 },
- { 0x06, 0x5561 },
- { 0x1f, 0x0005 },
- { 0x05, 0x8332 },
- { 0x06, 0x5561 },
+ /*
+ * Tx Error Issue
+ * Enhance line driver power
+ */
+ { 0x1f, 0x0002 },
+ { 0x06, 0x5561 },
+ { 0x1f, 0x0005 },
+ { 0x05, 0x8332 },
+ { 0x06, 0x5561 },
- /*
- * Can not link to 1Gbps with bad cable
- * Decrease SNR threshold form 21.07dB to 19.04dB
- */
- { 0x1f, 0x0001 },
- { 0x17, 0x0cc0 },
+ /*
+ * Can not link to 1Gbps with bad cable
+ * Decrease SNR threshold form 21.07dB to 19.04dB
+ */
+ { 0x1f, 0x0001 },
+ { 0x17, 0x0cc0 },
- { 0x1f, 0x0000 },
- { 0x0d, 0xf880 }
- };
+ { 0x1f, 0x0000 },
+ { 0x0d, 0xf880 }
+};
+
+static const struct phy_reg rtl8168d_1_phy_reg_init_1[] = {
+ { 0x1f, 0x0002 },
+ { 0x05, 0x669a },
+ { 0x1f, 0x0005 },
+ { 0x05, 0x8330 },
+ { 0x06, 0x669a },
+ { 0x1f, 0x0002 }
+};
- rtl_writephy_batch(tp, phy_reg_init_0);
+static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp)
+{
+ rtl_writephy_batch(tp, rtl8168d_1_phy_reg_init_0);
/*
* Rx Error Issue
@@ -2964,17 +2714,9 @@ static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp)
rtl_w0w1_phy(tp, 0x0c, 0xa200, 0x5d00);
if (rtl8168d_efuse_read(tp, 0x01) == 0xb1) {
- static const struct phy_reg phy_reg_init[] = {
- { 0x1f, 0x0002 },
- { 0x05, 0x669a },
- { 0x1f, 0x0005 },
- { 0x05, 0x8330 },
- { 0x06, 0x669a },
- { 0x1f, 0x0002 }
- };
int val;
- rtl_writephy_batch(tp, phy_reg_init);
+ rtl_writephy_batch(tp, rtl8168d_1_phy_reg_init_1);
val = rtl_readphy(tp, 0x0d);
@@ -3023,62 +2765,12 @@ static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp)
static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp)
{
- static const struct phy_reg phy_reg_init_0[] = {
- /* Channel Estimation */
- { 0x1f, 0x0001 },
- { 0x06, 0x4064 },
- { 0x07, 0x2863 },
- { 0x08, 0x059c },
- { 0x09, 0x26b4 },
- { 0x0a, 0x6a19 },
- { 0x0b, 0xdcc8 },
- { 0x10, 0xf06d },
- { 0x14, 0x7f68 },
- { 0x18, 0x7fd9 },
- { 0x1c, 0xf0ff },
- { 0x1d, 0x3d9c },
- { 0x1f, 0x0003 },
- { 0x12, 0xf49f },
- { 0x13, 0x070b },
- { 0x1a, 0x05ad },
- { 0x14, 0x94c0 },
-
- /*
- * Tx Error Issue
- * Enhance line driver power
- */
- { 0x1f, 0x0002 },
- { 0x06, 0x5561 },
- { 0x1f, 0x0005 },
- { 0x05, 0x8332 },
- { 0x06, 0x5561 },
-
- /*
- * Can not link to 1Gbps with bad cable
- * Decrease SNR threshold form 21.07dB to 19.04dB
- */
- { 0x1f, 0x0001 },
- { 0x17, 0x0cc0 },
-
- { 0x1f, 0x0000 },
- { 0x0d, 0xf880 }
- };
-
- rtl_writephy_batch(tp, phy_reg_init_0);
+ rtl_writephy_batch(tp, rtl8168d_1_phy_reg_init_0);
if (rtl8168d_efuse_read(tp, 0x01) == 0xb1) {
- static const struct phy_reg phy_reg_init[] = {
- { 0x1f, 0x0002 },
- { 0x05, 0x669a },
- { 0x1f, 0x0005 },
- { 0x05, 0x8330 },
- { 0x06, 0x669a },
-
- { 0x1f, 0x0002 }
- };
int val;
- rtl_writephy_batch(tp, phy_reg_init);
+ rtl_writephy_batch(tp, rtl8168d_1_phy_reg_init_1);
val = rtl_readphy(tp, 0x0d);
if ((val & 0x00ff) != 0x006c) {
@@ -3528,20 +3220,15 @@ static void rtl8411_hw_phy_config(struct rtl8169_private *tp)
static void rtl8168g_disable_aldps(struct rtl8169_private *tp)
{
- phy_write(tp->phydev, 0x1f, 0x0a43);
- phy_clear_bits(tp->phydev, 0x10, BIT(2));
+ phy_modify_paged(tp->phydev, 0x0a43, 0x10, BIT(2), 0);
}
static void rtl8168g_phy_adjust_10m_aldps(struct rtl8169_private *tp)
{
struct phy_device *phydev = tp->phydev;
- phy_write(phydev, 0x1f, 0x0bcc);
- phy_clear_bits(phydev, 0x14, BIT(8));
-
- phy_write(phydev, 0x1f, 0x0a44);
- phy_set_bits(phydev, 0x11, BIT(7) | BIT(6));
-
+ phy_modify_paged(phydev, 0x0bcc, 0x14, BIT(8), 0);
+ phy_modify_paged(phydev, 0x0a44, 0x11, 0, BIT(7) | BIT(6));
phy_write(phydev, 0x1f, 0x0a43);
phy_write(phydev, 0x13, 0x8084);
phy_clear_bits(phydev, 0x14, BIT(14) | BIT(13));
@@ -3552,43 +3239,36 @@ static void rtl8168g_phy_adjust_10m_aldps(struct rtl8169_private *tp)
static void rtl8168g_1_hw_phy_config(struct rtl8169_private *tp)
{
+ int ret;
+
rtl_apply_firmware(tp);
- rtl_writephy(tp, 0x1f, 0x0a46);
- if (rtl_readphy(tp, 0x10) & 0x0100) {
- rtl_writephy(tp, 0x1f, 0x0bcc);
- rtl_w0w1_phy(tp, 0x12, 0x0000, 0x8000);
- } else {
- rtl_writephy(tp, 0x1f, 0x0bcc);
- rtl_w0w1_phy(tp, 0x12, 0x8000, 0x0000);
- }
+ ret = phy_read_paged(tp->phydev, 0x0a46, 0x10);
+ if (ret & BIT(8))
+ phy_modify_paged(tp->phydev, 0x0bcc, 0x12, BIT(15), 0);
+ else
+ phy_modify_paged(tp->phydev, 0x0bcc, 0x12, 0, BIT(15));
- rtl_writephy(tp, 0x1f, 0x0a46);
- if (rtl_readphy(tp, 0x13) & 0x0100) {
- rtl_writephy(tp, 0x1f, 0x0c41);
- rtl_w0w1_phy(tp, 0x15, 0x0002, 0x0000);
- } else {
- rtl_writephy(tp, 0x1f, 0x0c41);
- rtl_w0w1_phy(tp, 0x15, 0x0000, 0x0002);
- }
+ ret = phy_read_paged(tp->phydev, 0x0a46, 0x13);
+ if (ret & BIT(8))
+ phy_modify_paged(tp->phydev, 0x0c41, 0x12, 0, BIT(1));
+ else
+ phy_modify_paged(tp->phydev, 0x0c41, 0x12, BIT(1), 0);
/* Enable PHY auto speed down */
- rtl_writephy(tp, 0x1f, 0x0a44);
- rtl_w0w1_phy(tp, 0x11, 0x000c, 0x0000);
+ phy_modify_paged(tp->phydev, 0x0a44, 0x11, 0, BIT(3) | BIT(2));
rtl8168g_phy_adjust_10m_aldps(tp);
/* EEE auto-fallback function */
- rtl_writephy(tp, 0x1f, 0x0a4b);
- rtl_w0w1_phy(tp, 0x11, 0x0004, 0x0000);
+ phy_modify_paged(tp->phydev, 0x0a4b, 0x11, 0, BIT(2));
/* Enable UC LPF tune function */
rtl_writephy(tp, 0x1f, 0x0a43);
rtl_writephy(tp, 0x13, 0x8012);
rtl_w0w1_phy(tp, 0x14, 0x8000, 0x0000);
- rtl_writephy(tp, 0x1f, 0x0c42);
- rtl_w0w1_phy(tp, 0x11, 0x4000, 0x2000);
+ phy_modify_paged(tp->phydev, 0x0c42, 0x11, BIT(13), BIT(14));
/* Improve SWR Efficiency */
rtl_writephy(tp, 0x1f, 0x0bcd);
@@ -3600,6 +3280,7 @@ static void rtl8168g_1_hw_phy_config(struct rtl8169_private *tp)
rtl_writephy(tp, 0x14, 0x1065);
rtl_writephy(tp, 0x14, 0x9065);
rtl_writephy(tp, 0x14, 0x1065);
+ rtl_writephy(tp, 0x1f, 0x0000);
rtl8168g_disable_aldps(tp);
rtl8168g_config_eee_phy(tp);
@@ -3684,14 +3365,10 @@ static void rtl8168h_1_hw_phy_config(struct rtl8169_private *tp)
rtl_writephy(tp, 0x1f, 0x0000);
/* enable GPHY 10M */
- rtl_writephy(tp, 0x1f, 0x0a44);
- rtl_w0w1_phy(tp, 0x11, 0x0800, 0x0000);
- rtl_writephy(tp, 0x1f, 0x0000);
+ phy_modify_paged(tp->phydev, 0x0a44, 0x11, 0, BIT(11));
/* SAR ADC performance */
- rtl_writephy(tp, 0x1f, 0x0bca);
- rtl_w0w1_phy(tp, 0x17, 0x4000, 0x3000);
- rtl_writephy(tp, 0x1f, 0x0000);
+ phy_modify_paged(tp->phydev, 0x0bca, 0x17, BIT(12) | BIT(13), BIT(14));
rtl_writephy(tp, 0x1f, 0x0a43);
rtl_writephy(tp, 0x13, 0x803f);
@@ -3711,9 +3388,7 @@ static void rtl8168h_1_hw_phy_config(struct rtl8169_private *tp)
rtl_writephy(tp, 0x1f, 0x0000);
/* disable phy pfm mode */
- rtl_writephy(tp, 0x1f, 0x0a44);
- rtl_w0w1_phy(tp, 0x11, 0x0000, 0x0080);
- rtl_writephy(tp, 0x1f, 0x0000);
+ phy_modify_paged(tp->phydev, 0x0a44, 0x11, BIT(7), 0);
rtl8168g_disable_aldps(tp);
rtl8168g_config_eee_phy(tp);
@@ -3743,9 +3418,7 @@ static void rtl8168h_2_hw_phy_config(struct rtl8169_private *tp)
rtl_writephy(tp, 0x1f, 0x0000);
/* enable GPHY 10M */
- rtl_writephy(tp, 0x1f, 0x0a44);
- rtl_w0w1_phy(tp, 0x11, 0x0800, 0x0000);
- rtl_writephy(tp, 0x1f, 0x0000);
+ phy_modify_paged(tp->phydev, 0x0a44, 0x11, 0, BIT(11));
r8168_mac_ocp_write(tp, 0xdd02, 0x807d);
data = r8168_mac_ocp_read(tp, 0xdd02);
@@ -3781,9 +3454,7 @@ static void rtl8168h_2_hw_phy_config(struct rtl8169_private *tp)
rtl_writephy(tp, 0x1f, 0x0000);
/* disable phy pfm mode */
- rtl_writephy(tp, 0x1f, 0x0a44);
- rtl_w0w1_phy(tp, 0x11, 0x0000, 0x0080);
- rtl_writephy(tp, 0x1f, 0x0000);
+ phy_modify_paged(tp->phydev, 0x0a44, 0x11, BIT(7), 0);
rtl8168g_disable_aldps(tp);
rtl8168g_config_eee_phy(tp);
@@ -3793,16 +3464,12 @@ static void rtl8168h_2_hw_phy_config(struct rtl8169_private *tp)
static void rtl8168ep_1_hw_phy_config(struct rtl8169_private *tp)
{
/* Enable PHY auto speed down */
- rtl_writephy(tp, 0x1f, 0x0a44);
- rtl_w0w1_phy(tp, 0x11, 0x000c, 0x0000);
- rtl_writephy(tp, 0x1f, 0x0000);
+ phy_modify_paged(tp->phydev, 0x0a44, 0x11, 0, BIT(3) | BIT(2));
rtl8168g_phy_adjust_10m_aldps(tp);
/* Enable EEE auto-fallback function */
- rtl_writephy(tp, 0x1f, 0x0a4b);
- rtl_w0w1_phy(tp, 0x11, 0x0004, 0x0000);
- rtl_writephy(tp, 0x1f, 0x0000);
+ phy_modify_paged(tp->phydev, 0x0a4b, 0x11, 0, BIT(2));
/* Enable UC LPF tune function */
rtl_writephy(tp, 0x1f, 0x0a43);
@@ -3811,9 +3478,7 @@ static void rtl8168ep_1_hw_phy_config(struct rtl8169_private *tp)
rtl_writephy(tp, 0x1f, 0x0000);
/* set rg_sel_sdm_rate */
- rtl_writephy(tp, 0x1f, 0x0c42);
- rtl_w0w1_phy(tp, 0x11, 0x4000, 0x2000);
- rtl_writephy(tp, 0x1f, 0x0000);
+ phy_modify_paged(tp->phydev, 0x0c42, 0x11, BIT(13), BIT(14));
rtl8168g_disable_aldps(tp);
rtl8168g_config_eee_phy(tp);
@@ -3831,9 +3496,7 @@ static void rtl8168ep_2_hw_phy_config(struct rtl8169_private *tp)
rtl_writephy(tp, 0x1f, 0x0000);
/* Set rg_sel_sdm_rate */
- rtl_writephy(tp, 0x1f, 0x0c42);
- rtl_w0w1_phy(tp, 0x11, 0x4000, 0x2000);
- rtl_writephy(tp, 0x1f, 0x0000);
+ phy_modify_paged(tp->phydev, 0x0c42, 0x11, BIT(13), BIT(14));
/* Channel estimation parameters */
rtl_writephy(tp, 0x1f, 0x0a43);
@@ -3985,7 +3648,6 @@ static void rtl_hw_phy_config(struct net_device *dev)
{
static const rtl_generic_fct phy_configs[] = {
/* PCI devices. */
- [RTL_GIGA_MAC_VER_01] = NULL,
[RTL_GIGA_MAC_VER_02] = rtl8169s_hw_phy_config,
[RTL_GIGA_MAC_VER_03] = rtl8169s_hw_phy_config,
[RTL_GIGA_MAC_VER_04] = rtl8169sb_hw_phy_config,
@@ -4050,12 +3712,6 @@ static void rtl_schedule_task(struct rtl8169_private *tp, enum rtl_flag flag)
schedule_work(&tp->wk.work);
}
-static bool rtl_tbi_enabled(struct rtl8169_private *tp)
-{
- return (tp->mac_version == RTL_GIGA_MAC_VER_01) &&
- (RTL_R8(tp, PHYstatus) & TBI_Enable);
-}
-
static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
{
rtl_hw_phy_config(dev);
@@ -4124,31 +3780,6 @@ static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return phy_mii_ioctl(tp->phydev, ifr, cmd);
}
-static void rtl_init_mdio_ops(struct rtl8169_private *tp)
-{
- struct mdio_ops *ops = &tp->mdio_ops;
-
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_27:
- ops->write = r8168dp_1_mdio_write;
- ops->read = r8168dp_1_mdio_read;
- break;
- case RTL_GIGA_MAC_VER_28:
- case RTL_GIGA_MAC_VER_31:
- ops->write = r8168dp_2_mdio_write;
- ops->read = r8168dp_2_mdio_read;
- break;
- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_51:
- ops->write = r8168g_mdio_write;
- ops->read = r8168g_mdio_read;
- break;
- default:
- ops->write = r8169_mdio_write;
- ops->read = r8169_mdio_read;
- break;
- }
-}
-
static void rtl_wol_suspend_quirk(struct rtl8169_private *tp)
{
switch (tp->mac_version) {
@@ -4168,7 +3799,7 @@ static void rtl_wol_suspend_quirk(struct rtl8169_private *tp)
}
}
-static void r8168_pll_power_down(struct rtl8169_private *tp)
+static void rtl_pll_power_down(struct rtl8169_private *tp)
{
if (r8168_check_dash(tp))
return;
@@ -4203,10 +3834,12 @@ static void r8168_pll_power_down(struct rtl8169_private *tp)
rtl_eri_clear_bits(tp, 0x1a8, ERIAR_MASK_1111, 0xfc000000);
RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) & ~0x80);
break;
+ default:
+ break;
}
}
-static void r8168_pll_power_up(struct rtl8169_private *tp)
+static void rtl_pll_power_up(struct rtl8169_private *tp)
{
switch (tp->mac_version) {
case RTL_GIGA_MAC_VER_25 ... RTL_GIGA_MAC_VER_33:
@@ -4230,6 +3863,8 @@ static void r8168_pll_power_up(struct rtl8169_private *tp)
RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) | 0xc0);
rtl_eri_set_bits(tp, 0x1a8, ERIAR_MASK_1111, 0xfc000000);
break;
+ default:
+ break;
}
phy_resume(tp->phydev);
@@ -4237,32 +3872,10 @@ static void r8168_pll_power_up(struct rtl8169_private *tp)
msleep(20);
}
-static void rtl_pll_power_down(struct rtl8169_private *tp)
-{
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_01 ... RTL_GIGA_MAC_VER_06:
- case RTL_GIGA_MAC_VER_13 ... RTL_GIGA_MAC_VER_15:
- break;
- default:
- r8168_pll_power_down(tp);
- }
-}
-
-static void rtl_pll_power_up(struct rtl8169_private *tp)
-{
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_01 ... RTL_GIGA_MAC_VER_06:
- case RTL_GIGA_MAC_VER_13 ... RTL_GIGA_MAC_VER_15:
- break;
- default:
- r8168_pll_power_up(tp);
- }
-}
-
static void rtl_init_rxcfg(struct rtl8169_private *tp)
{
switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_01 ... RTL_GIGA_MAC_VER_06:
+ case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06:
case RTL_GIGA_MAC_VER_10 ... RTL_GIGA_MAC_VER_17:
RTL_W32(tp, RxConfig, RX_FIFO_THRESH | RX_DMA_BURST);
break;
@@ -4285,24 +3898,6 @@ static void rtl8169_init_ring_indexes(struct rtl8169_private *tp)
tp->dirty_tx = tp->cur_tx = tp->cur_rx = 0;
}
-static void rtl_hw_jumbo_enable(struct rtl8169_private *tp)
-{
- if (tp->jumbo_ops.enable) {
- rtl_unlock_config_regs(tp);
- tp->jumbo_ops.enable(tp);
- rtl_lock_config_regs(tp);
- }
-}
-
-static void rtl_hw_jumbo_disable(struct rtl8169_private *tp)
-{
- if (tp->jumbo_ops.disable) {
- rtl_unlock_config_regs(tp);
- tp->jumbo_ops.disable(tp);
- rtl_lock_config_regs(tp);
- }
-}
-
static void r8168c_hw_jumbo_enable(struct rtl8169_private *tp)
{
RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0);
@@ -4369,55 +3964,56 @@ static void r8168b_1_hw_jumbo_disable(struct rtl8169_private *tp)
RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~(1 << 0));
}
-static void rtl_init_jumbo_ops(struct rtl8169_private *tp)
+static void rtl_hw_jumbo_enable(struct rtl8169_private *tp)
{
- struct jumbo_ops *ops = &tp->jumbo_ops;
-
+ rtl_unlock_config_regs(tp);
switch (tp->mac_version) {
case RTL_GIGA_MAC_VER_11:
- ops->disable = r8168b_0_hw_jumbo_disable;
- ops->enable = r8168b_0_hw_jumbo_enable;
+ r8168b_0_hw_jumbo_enable(tp);
break;
case RTL_GIGA_MAC_VER_12:
case RTL_GIGA_MAC_VER_17:
- ops->disable = r8168b_1_hw_jumbo_disable;
- ops->enable = r8168b_1_hw_jumbo_enable;
+ r8168b_1_hw_jumbo_enable(tp);
break;
- case RTL_GIGA_MAC_VER_18: /* Wild guess. Needs info from Realtek. */
- case RTL_GIGA_MAC_VER_19:
- case RTL_GIGA_MAC_VER_20:
- case RTL_GIGA_MAC_VER_21: /* Wild guess. Needs info from Realtek. */
- case RTL_GIGA_MAC_VER_22:
- case RTL_GIGA_MAC_VER_23:
- case RTL_GIGA_MAC_VER_24:
- case RTL_GIGA_MAC_VER_25:
- case RTL_GIGA_MAC_VER_26:
- ops->disable = r8168c_hw_jumbo_disable;
- ops->enable = r8168c_hw_jumbo_enable;
+ case RTL_GIGA_MAC_VER_18 ... RTL_GIGA_MAC_VER_26:
+ r8168c_hw_jumbo_enable(tp);
break;
- case RTL_GIGA_MAC_VER_27:
- case RTL_GIGA_MAC_VER_28:
- ops->disable = r8168dp_hw_jumbo_disable;
- ops->enable = r8168dp_hw_jumbo_enable;
+ case RTL_GIGA_MAC_VER_27 ... RTL_GIGA_MAC_VER_28:
+ r8168dp_hw_jumbo_enable(tp);
break;
- case RTL_GIGA_MAC_VER_31: /* Wild guess. Needs info from Realtek. */
- case RTL_GIGA_MAC_VER_32:
- case RTL_GIGA_MAC_VER_33:
- case RTL_GIGA_MAC_VER_34:
- ops->disable = r8168e_hw_jumbo_disable;
- ops->enable = r8168e_hw_jumbo_enable;
+ case RTL_GIGA_MAC_VER_31 ... RTL_GIGA_MAC_VER_34:
+ r8168e_hw_jumbo_enable(tp);
+ break;
+ default:
break;
+ }
+ rtl_lock_config_regs(tp);
+}
- /*
- * No action needed for jumbo frames with 8169.
- * No jumbo for 810x at all.
- */
- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_51:
+static void rtl_hw_jumbo_disable(struct rtl8169_private *tp)
+{
+ rtl_unlock_config_regs(tp);
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_11:
+ r8168b_0_hw_jumbo_disable(tp);
+ break;
+ case RTL_GIGA_MAC_VER_12:
+ case RTL_GIGA_MAC_VER_17:
+ r8168b_1_hw_jumbo_disable(tp);
+ break;
+ case RTL_GIGA_MAC_VER_18 ... RTL_GIGA_MAC_VER_26:
+ r8168c_hw_jumbo_disable(tp);
+ break;
+ case RTL_GIGA_MAC_VER_27 ... RTL_GIGA_MAC_VER_28:
+ r8168dp_hw_jumbo_disable(tp);
+ break;
+ case RTL_GIGA_MAC_VER_31 ... RTL_GIGA_MAC_VER_34:
+ r8168e_hw_jumbo_disable(tp);
+ break;
default:
- ops->disable = NULL;
- ops->enable = NULL;
break;
}
+ rtl_lock_config_regs(tp);
}
DECLARE_RTL_COND(rtl_chipcmd_cond)
@@ -4435,35 +4031,28 @@ static void rtl_hw_reset(struct rtl8169_private *tp)
static void rtl_request_firmware(struct rtl8169_private *tp)
{
struct rtl_fw *rtl_fw;
- int rc = -ENOMEM;
/* firmware loaded already or no firmware available */
if (tp->rtl_fw || !tp->fw_name)
return;
rtl_fw = kzalloc(sizeof(*rtl_fw), GFP_KERNEL);
- if (!rtl_fw)
- goto err_warn;
-
- rc = request_firmware(&rtl_fw->fw, tp->fw_name, tp_to_dev(tp));
- if (rc < 0)
- goto err_free;
-
- rc = rtl_check_firmware(tp, rtl_fw);
- if (rc < 0)
- goto err_release_firmware;
-
- tp->rtl_fw = rtl_fw;
+ if (!rtl_fw) {
+ netif_warn(tp, ifup, tp->dev, "Unable to load firmware, out of memory\n");
+ return;
+ }
- return;
+ rtl_fw->phy_write = rtl_writephy;
+ rtl_fw->phy_read = rtl_readphy;
+ rtl_fw->mac_mcu_write = mac_mcu_write;
+ rtl_fw->mac_mcu_read = mac_mcu_read;
+ rtl_fw->fw_name = tp->fw_name;
+ rtl_fw->dev = tp_to_dev(tp);
-err_release_firmware:
- release_firmware(rtl_fw->fw);
-err_free:
- kfree(rtl_fw);
-err_warn:
- netif_warn(tp, ifup, tp->dev, "unable to load firmware patch %s (%d)\n",
- tp->fw_name, rc);
+ if (rtl_fw_request_firmware(rtl_fw))
+ kfree(rtl_fw);
+ else
+ tp->rtl_fw = rtl_fw;
}
static void rtl_rx_close(struct rtl8169_private *tp)
@@ -4513,8 +4102,7 @@ static void rtl_set_tx_config_registers(struct rtl8169_private *tp)
u32 val = TX_DMA_BURST << TxDMAShift |
InterFrameGap << TxInterFrameGapShift;
- if (tp->mac_version >= RTL_GIGA_MAC_VER_34 &&
- tp->mac_version != RTL_GIGA_MAC_VER_39)
+ if (rtl_is_8168evl_up(tp))
val |= TXCFG_AUTO_FIFO;
RTL_W32(tp, TxConfig, val);
@@ -4608,53 +4196,6 @@ static void rtl_set_rx_mode(struct net_device *dev)
RTL_W32(tp, RxConfig, tmp);
}
-static void rtl_hw_start(struct rtl8169_private *tp)
-{
- rtl_unlock_config_regs(tp);
-
- tp->hw_start(tp);
-
- rtl_set_rx_max_size(tp);
- rtl_set_rx_tx_desc_registers(tp);
- rtl_lock_config_regs(tp);
-
- /* disable interrupt coalescing */
- RTL_W16(tp, IntrMitigate, 0x0000);
- /* Initially a 10 us delay. Turned it into a PCI commit. - FR */
- RTL_R8(tp, IntrMask);
- RTL_W8(tp, ChipCmd, CmdTxEnb | CmdRxEnb);
- rtl_init_rxcfg(tp);
- rtl_set_tx_config_registers(tp);
-
- rtl_set_rx_mode(tp->dev);
- /* no early-rx interrupts */
- RTL_W16(tp, MultiIntr, RTL_R16(tp, MultiIntr) & 0xf000);
- rtl_irq_enable(tp);
-}
-
-static void rtl_hw_start_8169(struct rtl8169_private *tp)
-{
- if (tp->mac_version == RTL_GIGA_MAC_VER_05)
- pci_write_config_byte(tp->pci_dev, PCI_CACHE_LINE_SIZE, 0x08);
-
- RTL_W8(tp, EarlyTxThres, NoEarlyTx);
-
- tp->cp_cmd |= PCIMulRW;
-
- if (tp->mac_version == RTL_GIGA_MAC_VER_02 ||
- tp->mac_version == RTL_GIGA_MAC_VER_03) {
- netif_dbg(tp, drv, tp->dev,
- "Set MAC Reg C+CR Offset 0xe0. Bit 3 and Bit 14 MUST be 1\n");
- tp->cp_cmd |= (1 << 14);
- }
-
- RTL_W16(tp, CPlusCmd, tp->cp_cmd);
-
- rtl8169_set_magic_reg(tp, tp->mac_version);
-
- RTL_W32(tp, RxMissed, 0);
-}
-
DECLARE_RTL_COND(rtl_csiar_cond)
{
return RTL_R32(tp, CSIAR) & CSIAR_FLAG;
@@ -4746,7 +4287,8 @@ static void rtl_pcie_state_l2l3_disable(struct rtl8169_private *tp)
static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable)
{
- if (enable) {
+ /* Don't enable ASPM in the chip if OS can't control ASPM */
+ if (enable && tp->aspm_manageable) {
RTL_W8(tp, Config5, RTL_R8(tp, Config5) | ASPM_en);
RTL_W8(tp, Config2, RTL_R8(tp, Config2) | ClkReqEn);
} else {
@@ -4779,9 +4321,6 @@ static void rtl_hw_start_8168bb(struct rtl8169_private *tp)
{
RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Beacon_en);
- tp->cp_cmd &= CPCMD_QUIRK_MASK;
- RTL_W16(tp, CPlusCmd, tp->cp_cmd);
-
if (tp->dev->mtu <= ETH_DATA_LEN) {
rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B |
PCI_EXP_DEVCTL_NOSNOOP_EN);
@@ -4792,8 +4331,6 @@ static void rtl_hw_start_8168bef(struct rtl8169_private *tp)
{
rtl_hw_start_8168bb(tp);
- RTL_W8(tp, MaxTxPacketSize, TxPacketMax);
-
RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~(1 << 0));
}
@@ -4807,9 +4344,6 @@ static void __rtl_hw_start_8168cp(struct rtl8169_private *tp)
rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B);
rtl_disable_clock_request(tp);
-
- tp->cp_cmd &= CPCMD_QUIRK_MASK;
- RTL_W16(tp, CPlusCmd, tp->cp_cmd);
}
static void rtl_hw_start_8168cp_1(struct rtl8169_private *tp)
@@ -4837,9 +4371,6 @@ static void rtl_hw_start_8168cp_2(struct rtl8169_private *tp)
if (tp->dev->mtu <= ETH_DATA_LEN)
rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B);
-
- tp->cp_cmd &= CPCMD_QUIRK_MASK;
- RTL_W16(tp, CPlusCmd, tp->cp_cmd);
}
static void rtl_hw_start_8168cp_3(struct rtl8169_private *tp)
@@ -4851,13 +4382,8 @@ static void rtl_hw_start_8168cp_3(struct rtl8169_private *tp)
/* Magic. */
RTL_W8(tp, DBG_REG, 0x20);
- RTL_W8(tp, MaxTxPacketSize, TxPacketMax);
-
if (tp->dev->mtu <= ETH_DATA_LEN)
rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B);
-
- tp->cp_cmd &= CPCMD_QUIRK_MASK;
- RTL_W16(tp, CPlusCmd, tp->cp_cmd);
}
static void rtl_hw_start_8168c_1(struct rtl8169_private *tp)
@@ -4909,13 +4435,8 @@ static void rtl_hw_start_8168d(struct rtl8169_private *tp)
rtl_disable_clock_request(tp);
- RTL_W8(tp, MaxTxPacketSize, TxPacketMax);
-
if (tp->dev->mtu <= ETH_DATA_LEN)
rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B);
-
- tp->cp_cmd &= CPCMD_QUIRK_MASK;
- RTL_W16(tp, CPlusCmd, tp->cp_cmd);
}
static void rtl_hw_start_8168dp(struct rtl8169_private *tp)
@@ -4925,8 +4446,6 @@ static void rtl_hw_start_8168dp(struct rtl8169_private *tp)
if (tp->dev->mtu <= ETH_DATA_LEN)
rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B);
- RTL_W8(tp, MaxTxPacketSize, TxPacketMax);
-
rtl_disable_clock_request(tp);
}
@@ -4942,8 +4461,6 @@ static void rtl_hw_start_8168d_4(struct rtl8169_private *tp)
rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B);
- RTL_W8(tp, MaxTxPacketSize, TxPacketMax);
-
rtl_ephy_init(tp, e_info_8168d_4);
rtl_enable_clock_request(tp);
@@ -4974,8 +4491,6 @@ static void rtl_hw_start_8168e_1(struct rtl8169_private *tp)
if (tp->dev->mtu <= ETH_DATA_LEN)
rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B);
- RTL_W8(tp, MaxTxPacketSize, TxPacketMax);
-
rtl_disable_clock_request(tp);
/* Reset tx FIFO pointer */
@@ -5007,8 +4522,6 @@ static void rtl_hw_start_8168e_2(struct rtl8169_private *tp)
rtl_eri_set_bits(tp, 0x1b0, ERIAR_MASK_0001, BIT(4));
rtl_w0w1_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0xff00);
- RTL_W8(tp, MaxTxPacketSize, EarlySize);
-
rtl_disable_clock_request(tp);
RTL_W8(tp, MCU, RTL_R8(tp, MCU) & ~NOW_IS_OOB);
@@ -5037,8 +4550,6 @@ static void rtl_hw_start_8168f(struct rtl8169_private *tp)
rtl_eri_write(tp, 0xcc, ERIAR_MASK_1111, 0x00000050);
rtl_eri_write(tp, 0xd0, ERIAR_MASK_1111, 0x00000060);
- RTL_W8(tp, MaxTxPacketSize, EarlySize);
-
rtl_disable_clock_request(tp);
RTL_W8(tp, MCU, RTL_R8(tp, MCU) & ~NOW_IS_OOB);
@@ -5095,7 +4606,6 @@ static void rtl_hw_start_8168g(struct rtl8169_private *tp)
rtl_eri_write(tp, 0x2f8, ERIAR_MASK_0011, 0x1d8f);
RTL_W32(tp, MISC, RTL_R32(tp, MISC) & ~RXDV_GATED_EN);
- RTL_W8(tp, MaxTxPacketSize, EarlySize);
rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000);
rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000);
@@ -5157,6 +4667,143 @@ static void rtl_hw_start_8411_2(struct rtl8169_private *tp)
/* disable aspm and clock request before access ephy */
rtl_hw_aspm_clkreq_enable(tp, false);
rtl_ephy_init(tp, e_info_8411_2);
+
+ /* The following Realtek-provided magic fixes an issue with the RX unit
+ * getting confused after the PHY having been powered-down.
+ */
+ r8168_mac_ocp_write(tp, 0xFC28, 0x0000);
+ r8168_mac_ocp_write(tp, 0xFC2A, 0x0000);
+ r8168_mac_ocp_write(tp, 0xFC2C, 0x0000);
+ r8168_mac_ocp_write(tp, 0xFC2E, 0x0000);
+ r8168_mac_ocp_write(tp, 0xFC30, 0x0000);
+ r8168_mac_ocp_write(tp, 0xFC32, 0x0000);
+ r8168_mac_ocp_write(tp, 0xFC34, 0x0000);
+ r8168_mac_ocp_write(tp, 0xFC36, 0x0000);
+ mdelay(3);
+ r8168_mac_ocp_write(tp, 0xFC26, 0x0000);
+
+ r8168_mac_ocp_write(tp, 0xF800, 0xE008);
+ r8168_mac_ocp_write(tp, 0xF802, 0xE00A);
+ r8168_mac_ocp_write(tp, 0xF804, 0xE00C);
+ r8168_mac_ocp_write(tp, 0xF806, 0xE00E);
+ r8168_mac_ocp_write(tp, 0xF808, 0xE027);
+ r8168_mac_ocp_write(tp, 0xF80A, 0xE04F);
+ r8168_mac_ocp_write(tp, 0xF80C, 0xE05E);
+ r8168_mac_ocp_write(tp, 0xF80E, 0xE065);
+ r8168_mac_ocp_write(tp, 0xF810, 0xC602);
+ r8168_mac_ocp_write(tp, 0xF812, 0xBE00);
+ r8168_mac_ocp_write(tp, 0xF814, 0x0000);
+ r8168_mac_ocp_write(tp, 0xF816, 0xC502);
+ r8168_mac_ocp_write(tp, 0xF818, 0xBD00);
+ r8168_mac_ocp_write(tp, 0xF81A, 0x074C);
+ r8168_mac_ocp_write(tp, 0xF81C, 0xC302);
+ r8168_mac_ocp_write(tp, 0xF81E, 0xBB00);
+ r8168_mac_ocp_write(tp, 0xF820, 0x080A);
+ r8168_mac_ocp_write(tp, 0xF822, 0x6420);
+ r8168_mac_ocp_write(tp, 0xF824, 0x48C2);
+ r8168_mac_ocp_write(tp, 0xF826, 0x8C20);
+ r8168_mac_ocp_write(tp, 0xF828, 0xC516);
+ r8168_mac_ocp_write(tp, 0xF82A, 0x64A4);
+ r8168_mac_ocp_write(tp, 0xF82C, 0x49C0);
+ r8168_mac_ocp_write(tp, 0xF82E, 0xF009);
+ r8168_mac_ocp_write(tp, 0xF830, 0x74A2);
+ r8168_mac_ocp_write(tp, 0xF832, 0x8CA5);
+ r8168_mac_ocp_write(tp, 0xF834, 0x74A0);
+ r8168_mac_ocp_write(tp, 0xF836, 0xC50E);
+ r8168_mac_ocp_write(tp, 0xF838, 0x9CA2);
+ r8168_mac_ocp_write(tp, 0xF83A, 0x1C11);
+ r8168_mac_ocp_write(tp, 0xF83C, 0x9CA0);
+ r8168_mac_ocp_write(tp, 0xF83E, 0xE006);
+ r8168_mac_ocp_write(tp, 0xF840, 0x74F8);
+ r8168_mac_ocp_write(tp, 0xF842, 0x48C4);
+ r8168_mac_ocp_write(tp, 0xF844, 0x8CF8);
+ r8168_mac_ocp_write(tp, 0xF846, 0xC404);
+ r8168_mac_ocp_write(tp, 0xF848, 0xBC00);
+ r8168_mac_ocp_write(tp, 0xF84A, 0xC403);
+ r8168_mac_ocp_write(tp, 0xF84C, 0xBC00);
+ r8168_mac_ocp_write(tp, 0xF84E, 0x0BF2);
+ r8168_mac_ocp_write(tp, 0xF850, 0x0C0A);
+ r8168_mac_ocp_write(tp, 0xF852, 0xE434);
+ r8168_mac_ocp_write(tp, 0xF854, 0xD3C0);
+ r8168_mac_ocp_write(tp, 0xF856, 0x49D9);
+ r8168_mac_ocp_write(tp, 0xF858, 0xF01F);
+ r8168_mac_ocp_write(tp, 0xF85A, 0xC526);
+ r8168_mac_ocp_write(tp, 0xF85C, 0x64A5);
+ r8168_mac_ocp_write(tp, 0xF85E, 0x1400);
+ r8168_mac_ocp_write(tp, 0xF860, 0xF007);
+ r8168_mac_ocp_write(tp, 0xF862, 0x0C01);
+ r8168_mac_ocp_write(tp, 0xF864, 0x8CA5);
+ r8168_mac_ocp_write(tp, 0xF866, 0x1C15);
+ r8168_mac_ocp_write(tp, 0xF868, 0xC51B);
+ r8168_mac_ocp_write(tp, 0xF86A, 0x9CA0);
+ r8168_mac_ocp_write(tp, 0xF86C, 0xE013);
+ r8168_mac_ocp_write(tp, 0xF86E, 0xC519);
+ r8168_mac_ocp_write(tp, 0xF870, 0x74A0);
+ r8168_mac_ocp_write(tp, 0xF872, 0x48C4);
+ r8168_mac_ocp_write(tp, 0xF874, 0x8CA0);
+ r8168_mac_ocp_write(tp, 0xF876, 0xC516);
+ r8168_mac_ocp_write(tp, 0xF878, 0x74A4);
+ r8168_mac_ocp_write(tp, 0xF87A, 0x48C8);
+ r8168_mac_ocp_write(tp, 0xF87C, 0x48CA);
+ r8168_mac_ocp_write(tp, 0xF87E, 0x9CA4);
+ r8168_mac_ocp_write(tp, 0xF880, 0xC512);
+ r8168_mac_ocp_write(tp, 0xF882, 0x1B00);
+ r8168_mac_ocp_write(tp, 0xF884, 0x9BA0);
+ r8168_mac_ocp_write(tp, 0xF886, 0x1B1C);
+ r8168_mac_ocp_write(tp, 0xF888, 0x483F);
+ r8168_mac_ocp_write(tp, 0xF88A, 0x9BA2);
+ r8168_mac_ocp_write(tp, 0xF88C, 0x1B04);
+ r8168_mac_ocp_write(tp, 0xF88E, 0xC508);
+ r8168_mac_ocp_write(tp, 0xF890, 0x9BA0);
+ r8168_mac_ocp_write(tp, 0xF892, 0xC505);
+ r8168_mac_ocp_write(tp, 0xF894, 0xBD00);
+ r8168_mac_ocp_write(tp, 0xF896, 0xC502);
+ r8168_mac_ocp_write(tp, 0xF898, 0xBD00);
+ r8168_mac_ocp_write(tp, 0xF89A, 0x0300);
+ r8168_mac_ocp_write(tp, 0xF89C, 0x051E);
+ r8168_mac_ocp_write(tp, 0xF89E, 0xE434);
+ r8168_mac_ocp_write(tp, 0xF8A0, 0xE018);
+ r8168_mac_ocp_write(tp, 0xF8A2, 0xE092);
+ r8168_mac_ocp_write(tp, 0xF8A4, 0xDE20);
+ r8168_mac_ocp_write(tp, 0xF8A6, 0xD3C0);
+ r8168_mac_ocp_write(tp, 0xF8A8, 0xC50F);
+ r8168_mac_ocp_write(tp, 0xF8AA, 0x76A4);
+ r8168_mac_ocp_write(tp, 0xF8AC, 0x49E3);
+ r8168_mac_ocp_write(tp, 0xF8AE, 0xF007);
+ r8168_mac_ocp_write(tp, 0xF8B0, 0x49C0);
+ r8168_mac_ocp_write(tp, 0xF8B2, 0xF103);
+ r8168_mac_ocp_write(tp, 0xF8B4, 0xC607);
+ r8168_mac_ocp_write(tp, 0xF8B6, 0xBE00);
+ r8168_mac_ocp_write(tp, 0xF8B8, 0xC606);
+ r8168_mac_ocp_write(tp, 0xF8BA, 0xBE00);
+ r8168_mac_ocp_write(tp, 0xF8BC, 0xC602);
+ r8168_mac_ocp_write(tp, 0xF8BE, 0xBE00);
+ r8168_mac_ocp_write(tp, 0xF8C0, 0x0C4C);
+ r8168_mac_ocp_write(tp, 0xF8C2, 0x0C28);
+ r8168_mac_ocp_write(tp, 0xF8C4, 0x0C2C);
+ r8168_mac_ocp_write(tp, 0xF8C6, 0xDC00);
+ r8168_mac_ocp_write(tp, 0xF8C8, 0xC707);
+ r8168_mac_ocp_write(tp, 0xF8CA, 0x1D00);
+ r8168_mac_ocp_write(tp, 0xF8CC, 0x8DE2);
+ r8168_mac_ocp_write(tp, 0xF8CE, 0x48C1);
+ r8168_mac_ocp_write(tp, 0xF8D0, 0xC502);
+ r8168_mac_ocp_write(tp, 0xF8D2, 0xBD00);
+ r8168_mac_ocp_write(tp, 0xF8D4, 0x00AA);
+ r8168_mac_ocp_write(tp, 0xF8D6, 0xE0C0);
+ r8168_mac_ocp_write(tp, 0xF8D8, 0xC502);
+ r8168_mac_ocp_write(tp, 0xF8DA, 0xBD00);
+ r8168_mac_ocp_write(tp, 0xF8DC, 0x0132);
+
+ r8168_mac_ocp_write(tp, 0xFC26, 0x8000);
+
+ r8168_mac_ocp_write(tp, 0xFC2A, 0x0743);
+ r8168_mac_ocp_write(tp, 0xFC2C, 0x0801);
+ r8168_mac_ocp_write(tp, 0xFC2E, 0x0BE9);
+ r8168_mac_ocp_write(tp, 0xFC30, 0x02FD);
+ r8168_mac_ocp_write(tp, 0xFC32, 0x0C25);
+ r8168_mac_ocp_write(tp, 0xFC34, 0x00A9);
+ r8168_mac_ocp_write(tp, 0xFC36, 0x012D);
+
rtl_hw_aspm_clkreq_enable(tp, true);
}
@@ -5193,7 +4840,6 @@ static void rtl_hw_start_8168h_1(struct rtl8169_private *tp)
rtl_eri_write(tp, 0x5f0, ERIAR_MASK_0011, 0x4f87);
RTL_W32(tp, MISC, RTL_R32(tp, MISC) & ~RXDV_GATED_EN);
- RTL_W8(tp, MaxTxPacketSize, EarlySize);
rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000);
rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000);
@@ -5269,7 +4915,6 @@ static void rtl_hw_start_8168ep(struct rtl8169_private *tp)
rtl_eri_write(tp, 0x5f0, ERIAR_MASK_0011, 0x4f87);
RTL_W32(tp, MISC, RTL_R32(tp, MISC) & ~RXDV_GATED_EN);
- RTL_W8(tp, MaxTxPacketSize, EarlySize);
rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000);
rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000);
@@ -5536,33 +5181,70 @@ static void rtl_hw_config(struct rtl8169_private *tp)
static void rtl_hw_start_8168(struct rtl8169_private *tp)
{
- RTL_W8(tp, MaxTxPacketSize, TxPacketMax);
+ if (tp->mac_version == RTL_GIGA_MAC_VER_13 ||
+ tp->mac_version == RTL_GIGA_MAC_VER_16)
+ pcie_capability_set_word(tp->pci_dev, PCI_EXP_DEVCTL,
+ PCI_EXP_DEVCTL_NOSNOOP_EN);
- /* Workaround for RxFIFO overflow. */
- if (tp->mac_version == RTL_GIGA_MAC_VER_11) {
- tp->irq_mask |= RxFIFOOver;
- tp->irq_mask &= ~RxOverflow;
- }
+ if (rtl_is_8168evl_up(tp))
+ RTL_W8(tp, MaxTxPacketSize, EarlySize);
+ else
+ RTL_W8(tp, MaxTxPacketSize, TxPacketMax);
rtl_hw_config(tp);
}
-static void rtl_hw_start_8101(struct rtl8169_private *tp)
+static void rtl_hw_start_8169(struct rtl8169_private *tp)
{
- if (tp->mac_version >= RTL_GIGA_MAC_VER_30)
- tp->irq_mask &= ~RxFIFOOver;
+ if (tp->mac_version == RTL_GIGA_MAC_VER_05)
+ pci_write_config_byte(tp->pci_dev, PCI_CACHE_LINE_SIZE, 0x08);
- if (tp->mac_version == RTL_GIGA_MAC_VER_13 ||
- tp->mac_version == RTL_GIGA_MAC_VER_16)
- pcie_capability_set_word(tp->pci_dev, PCI_EXP_DEVCTL,
- PCI_EXP_DEVCTL_NOSNOOP_EN);
+ RTL_W8(tp, EarlyTxThres, NoEarlyTx);
- RTL_W8(tp, MaxTxPacketSize, TxPacketMax);
+ tp->cp_cmd |= PCIMulRW;
+
+ if (tp->mac_version == RTL_GIGA_MAC_VER_02 ||
+ tp->mac_version == RTL_GIGA_MAC_VER_03) {
+ netif_dbg(tp, drv, tp->dev,
+ "Set MAC Reg C+CR Offset 0xe0. Bit 3 and Bit 14 MUST be 1\n");
+ tp->cp_cmd |= (1 << 14);
+ }
- tp->cp_cmd &= CPCMD_QUIRK_MASK;
RTL_W16(tp, CPlusCmd, tp->cp_cmd);
- rtl_hw_config(tp);
+ rtl8169_set_magic_reg(tp, tp->mac_version);
+
+ RTL_W32(tp, RxMissed, 0);
+}
+
+static void rtl_hw_start(struct rtl8169_private *tp)
+{
+ rtl_unlock_config_regs(tp);
+
+ tp->cp_cmd &= CPCMD_MASK;
+ RTL_W16(tp, CPlusCmd, tp->cp_cmd);
+
+ if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
+ rtl_hw_start_8169(tp);
+ else
+ rtl_hw_start_8168(tp);
+
+ rtl_set_rx_max_size(tp);
+ rtl_set_rx_tx_desc_registers(tp);
+ rtl_lock_config_regs(tp);
+
+ /* disable interrupt coalescing */
+ RTL_W16(tp, IntrMitigate, 0x0000);
+ /* Initially a 10 us delay. Turned it into a PCI commit. - FR */
+ RTL_R8(tp, IntrMask);
+ RTL_W8(tp, ChipCmd, CmdTxEnb | CmdRxEnb);
+ rtl_init_rxcfg(tp);
+ rtl_set_tx_config_registers(tp);
+
+ rtl_set_rx_mode(tp->dev);
+ /* no early-rx interrupts */
+ RTL_W16(tp, MultiIntr, RTL_R16(tp, MultiIntr) & 0xf000);
+ rtl_irq_enable(tp);
}
static int rtl8169_change_mtu(struct net_device *dev, int new_mtu)
@@ -5834,7 +5516,7 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
static void r8169_csum_workaround(struct rtl8169_private *tp,
struct sk_buff *skb)
{
- if (skb_shinfo(skb)->gso_size) {
+ if (skb_is_gso(skb)) {
netdev_features_t features = tp->dev->features;
struct sk_buff *segs, *nskb;
@@ -5857,11 +5539,8 @@ static void r8169_csum_workaround(struct rtl8169_private *tp,
rtl8169_start_xmit(skb, tp->dev);
} else {
- struct net_device_stats *stats;
-
drop:
- stats = &tp->dev->stats;
- stats->tx_dropped++;
+ tp->dev->stats.tx_dropped++;
dev_kfree_skb_any(skb);
}
}
@@ -5889,8 +5568,7 @@ static int msdn_giant_send_check(struct sk_buff *skb)
return ret;
}
-static bool rtl8169_tso_csum_v1(struct rtl8169_private *tp,
- struct sk_buff *skb, u32 *opts)
+static void rtl8169_tso_csum_v1(struct sk_buff *skb, u32 *opts)
{
u32 mss = skb_shinfo(skb)->gso_size;
@@ -5907,8 +5585,6 @@ static bool rtl8169_tso_csum_v1(struct rtl8169_private *tp,
else
WARN_ON_ONCE(1);
}
-
- return true;
}
static bool rtl8169_tso_csum_v2(struct rtl8169_private *tp,
@@ -5998,6 +5674,18 @@ static bool rtl_tx_slots_avail(struct rtl8169_private *tp,
return slots_avail > nr_frags;
}
+/* Versions RTL8102e and from RTL8168c onwards support csum_v2 */
+static bool rtl_chip_supports_csum_v2(struct rtl8169_private *tp)
+{
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06:
+ case RTL_GIGA_MAC_VER_10 ... RTL_GIGA_MAC_VER_17:
+ return false;
+ default:
+ return true;
+ }
+}
+
static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
@@ -6017,12 +5705,16 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
if (unlikely(le32_to_cpu(txd->opts1) & DescOwn))
goto err_stop_0;
- opts[1] = cpu_to_le32(rtl8169_tx_vlan_tag(skb));
+ opts[1] = rtl8169_tx_vlan_tag(skb);
opts[0] = DescOwn;
- if (!tp->tso_csum(tp, skb, opts)) {
- r8169_csum_workaround(tp, skb);
- return NETDEV_TX_OK;
+ if (rtl_chip_supports_csum_v2(tp)) {
+ if (!rtl8169_tso_csum_v2(tp, skb, opts)) {
+ r8169_csum_workaround(tp, skb);
+ return NETDEV_TX_OK;
+ }
+ } else {
+ rtl8169_tso_csum_v1(skb, opts);
}
len = skb_headlen(skb);
@@ -6229,7 +5921,6 @@ static struct sk_buff *rtl8169_try_rx_copy(void *data,
skb = napi_alloc_skb(&tp->napi, pkt_size);
if (skb)
skb_copy_to_linear_data(skb, data, pkt_size);
- dma_sync_single_for_device(d, addr, pkt_size, DMA_FROM_DEVICE);
return skb;
}
@@ -6264,14 +5955,8 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, u32 budget
dev->stats.rx_length_errors++;
if (status & RxCRC)
dev->stats.rx_crc_errors++;
- /* RxFOVF is a reserved bit on later chip versions */
- if (tp->mac_version == RTL_GIGA_MAC_VER_01 &&
- status & RxFOVF) {
- rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
- dev->stats.rx_fifo_errors++;
- } else if (status & (RxRUNT | RxCRC) &&
- !(status & RxRWT) &&
- dev->features & NETIF_F_RXALL) {
+ if (status & (RxRUNT | RxCRC) && !(status & RxRWT) &&
+ dev->features & NETIF_F_RXALL) {
goto process_pkt;
}
} else {
@@ -6451,7 +6136,10 @@ static int r8169_phy_connect(struct rtl8169_private *tp)
if (ret)
return ret;
- if (!tp->supports_gmii)
+ if (tp->supports_gmii)
+ phy_remove_link_mode(phydev,
+ ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
+ else
phy_set_max_speed(phydev, SPEED_100);
phy_support_asym_pause(phydev);
@@ -6884,30 +6572,18 @@ static const struct net_device_ops rtl_netdev_ops = {
};
-static const struct rtl_cfg_info {
- void (*hw_start)(struct rtl8169_private *tp);
- u16 irq_mask;
- unsigned int has_gmii:1;
- const struct rtl_coalesce_info *coalesce_info;
-} rtl_cfg_infos [] = {
- [RTL_CFG_0] = {
- .hw_start = rtl_hw_start_8169,
- .irq_mask = SYSErr | LinkChg | RxOverflow | RxFIFOOver,
- .has_gmii = 1,
- .coalesce_info = rtl_coalesce_info_8169,
- },
- [RTL_CFG_1] = {
- .hw_start = rtl_hw_start_8168,
- .irq_mask = LinkChg | RxOverflow,
- .has_gmii = 1,
- .coalesce_info = rtl_coalesce_info_8168_8136,
- },
- [RTL_CFG_2] = {
- .hw_start = rtl_hw_start_8101,
- .irq_mask = LinkChg | RxOverflow | RxFIFOOver,
- .coalesce_info = rtl_coalesce_info_8168_8136,
- }
-};
+static void rtl_set_irq_mask(struct rtl8169_private *tp)
+{
+ tp->irq_mask = RTL_EVENT_NAPI | LinkChg;
+
+ if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
+ tp->irq_mask |= SYSErr | RxOverflow | RxFIFOOver;
+ else if (tp->mac_version == RTL_GIGA_MAC_VER_11)
+ /* special workaround needed */
+ tp->irq_mask |= RxFIFOOver;
+ else
+ tp->irq_mask |= RxOverflow;
+}
static int rtl_alloc_irq(struct rtl8169_private *tp)
{
@@ -6928,13 +6604,10 @@ static int rtl_alloc_irq(struct rtl8169_private *tp)
static void rtl_read_mac_address(struct rtl8169_private *tp,
u8 mac_addr[ETH_ALEN])
{
- u32 value;
-
/* Get MAC address */
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_35 ... RTL_GIGA_MAC_VER_38:
- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_51:
- value = rtl_eri_read(tp, 0xe0);
+ if (rtl_is_8168evl_up(tp) && tp->mac_version != RTL_GIGA_MAC_VER_34) {
+ u32 value = rtl_eri_read(tp, 0xe0);
+
mac_addr[0] = (value >> 0) & 0xff;
mac_addr[1] = (value >> 8) & 0xff;
mac_addr[2] = (value >> 16) & 0xff;
@@ -6943,9 +6616,6 @@ static void rtl_read_mac_address(struct rtl8169_private *tp,
value = rtl_eri_read(tp, 0xe4);
mac_addr[4] = (value >> 0) & 0xff;
mac_addr[5] = (value >> 8) & 0xff;
- break;
- default:
- break;
}
}
@@ -7046,42 +6716,23 @@ static void rtl_hw_init_8168g(struct rtl8169_private *tp)
data |= (1 << 15);
r8168_mac_ocp_write(tp, 0xe8de, data);
- if (!rtl_udelay_loop_wait_high(tp, &rtl_link_list_ready_cond, 100, 42))
- return;
-}
-
-static void rtl_hw_init_8168ep(struct rtl8169_private *tp)
-{
- rtl8168ep_stop_cmac(tp);
- rtl_hw_init_8168g(tp);
+ rtl_udelay_loop_wait_high(tp, &rtl_link_list_ready_cond, 100, 42);
}
static void rtl_hw_initialize(struct rtl8169_private *tp)
{
switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_49 ... RTL_GIGA_MAC_VER_51:
+ rtl8168ep_stop_cmac(tp);
+ /* fall through */
case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_48:
rtl_hw_init_8168g(tp);
break;
- case RTL_GIGA_MAC_VER_49 ... RTL_GIGA_MAC_VER_51:
- rtl_hw_init_8168ep(tp);
- break;
default:
break;
}
}
-/* Versions RTL8102e and from RTL8168c onwards support csum_v2 */
-static bool rtl_chip_supports_csum_v2(struct rtl8169_private *tp)
-{
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_01 ... RTL_GIGA_MAC_VER_06:
- case RTL_GIGA_MAC_VER_10 ... RTL_GIGA_MAC_VER_17:
- return false;
- default:
- return true;
- }
-}
-
static int rtl_jumbo_max(struct rtl8169_private *tp)
{
/* Non-GBit versions don't support jumbo frames */
@@ -7090,7 +6741,7 @@ static int rtl_jumbo_max(struct rtl8169_private *tp)
switch (tp->mac_version) {
/* RTL8169 */
- case RTL_GIGA_MAC_VER_01 ... RTL_GIGA_MAC_VER_06:
+ case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06:
return JUMBO_7K;
/* RTL8168b */
case RTL_GIGA_MAC_VER_11:
@@ -7136,14 +6787,36 @@ static int rtl_get_ether_clk(struct rtl8169_private *tp)
return rc;
}
+static void rtl_init_mac_address(struct rtl8169_private *tp)
+{
+ struct net_device *dev = tp->dev;
+ u8 *mac_addr = dev->dev_addr;
+ int rc, i;
+
+ rc = eth_platform_get_mac_address(tp_to_dev(tp), mac_addr);
+ if (!rc)
+ goto done;
+
+ rtl_read_mac_address(tp, mac_addr);
+ if (is_valid_ether_addr(mac_addr))
+ goto done;
+
+ for (i = 0; i < ETH_ALEN; i++)
+ mac_addr[i] = RTL_R8(tp, MAC0 + i);
+ if (is_valid_ether_addr(mac_addr))
+ goto done;
+
+ eth_hw_addr_random(dev);
+ dev_warn(tp_to_dev(tp), "can't read MAC address, setting random one\n");
+done:
+ rtl_rar_set(tp, mac_addr);
+}
+
static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- const struct rtl_cfg_info *cfg = rtl_cfg_infos + ent->driver_data;
- /* align to u16 for is_valid_ether_addr() */
- u8 mac_addr[ETH_ALEN] __aligned(2) = {};
struct rtl8169_private *tp;
struct net_device *dev;
- int chipset, region, i;
+ int chipset, region;
int jumbo_max, rc;
dev = devm_alloc_etherdev(&pdev->dev, sizeof (*tp));
@@ -7156,7 +6829,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
tp->dev = dev;
tp->pci_dev = pdev;
tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT);
- tp->supports_gmii = cfg->has_gmii;
+ tp->supports_gmii = ent->driver_data == RTL_CFG_NO_GBIT ? 0 : 1;
/* Get the *optional* external "ether_clk" used on some boards */
rc = rtl_get_ether_clk(tp);
@@ -7166,7 +6839,9 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Disable ASPM completely as that cause random device stop working
* problems as well as full system hangs for some PCIe devices users.
*/
- pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
+ rc = pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S |
+ PCIE_LINK_STATE_L1);
+ tp->aspm_manageable = !rc;
/* enable device (incl. PCI PM wakeup and hotplug setup) */
rc = pcim_enable_device(pdev);
@@ -7204,23 +6879,11 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (tp->mac_version == RTL_GIGA_MAC_NONE)
return -ENODEV;
- if (rtl_tbi_enabled(tp)) {
- dev_err(&pdev->dev, "TBI fiber mode not supported\n");
- return -ENODEV;
- }
-
tp->cp_cmd = RTL_R16(tp, CPlusCmd);
if (sizeof(dma_addr_t) > 4 && tp->mac_version >= RTL_GIGA_MAC_VER_18 &&
- !dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) {
+ !dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)))
dev->features |= NETIF_F_HIGHDMA;
- } else {
- rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
- if (rc < 0) {
- dev_err(&pdev->dev, "DMA configuration failed\n");
- return rc;
- }
- }
rtl_init_rxcfg(tp);
@@ -7232,9 +6895,6 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_master(pdev);
- rtl_init_mdio_ops(tp);
- rtl_init_jumbo_ops(tp);
-
chipset = tp->mac_version;
rc = rtl_alloc_irq(tp);
@@ -7248,16 +6908,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
u64_stats_init(&tp->rx_stats.syncp);
u64_stats_init(&tp->tx_stats.syncp);
- /* get MAC address */
- rc = eth_platform_get_mac_address(&pdev->dev, mac_addr);
- if (rc)
- rtl_read_mac_address(tp, mac_addr);
-
- if (is_valid_ether_addr(mac_addr))
- rtl_rar_set(tp, mac_addr);
-
- for (i = 0; i < ETH_ALEN; i++)
- dev->dev_addr[i] = RTL_R8(tp, MAC0 + i);
+ rtl_init_mac_address(tp);
dev->ethtool_ops = &rtl8169_ethtool_ops;
@@ -7285,12 +6936,8 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Disallow toggling */
dev->hw_features &= ~NETIF_F_HW_VLAN_CTAG_RX;
- if (rtl_chip_supports_csum_v2(tp)) {
- tp->tso_csum = rtl8169_tso_csum_v2;
+ if (rtl_chip_supports_csum_v2(tp))
dev->hw_features |= NETIF_F_IPV6_CSUM | NETIF_F_TSO6;
- } else {
- tp->tso_csum = rtl8169_tso_csum_v1;
- }
dev->hw_features |= NETIF_F_RXALL;
dev->hw_features |= NETIF_F_RXFCS;
@@ -7300,9 +6947,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
jumbo_max = rtl_jumbo_max(tp);
dev->max_mtu = jumbo_max;
- tp->hw_start = cfg->hw_start;
- tp->irq_mask = RTL_EVENT_NAPI | cfg->irq_mask;
- tp->coalesce_info = cfg->coalesce_info;
+ rtl_set_irq_mask(tp);
tp->fw_name = rtl_chip_infos[chipset].fw_name;
diff --git a/drivers/net/ethernet/rocker/rocker_main.c b/drivers/net/ethernet/rocker/rocker_main.c
index 3e5bc1fc3c46..079f459c73a5 100644
--- a/drivers/net/ethernet/rocker/rocker_main.c
+++ b/drivers/net/ethernet/rocker/rocker_main.c
@@ -2210,6 +2210,10 @@ static int rocker_router_fib_event(struct notifier_block *nb,
NL_SET_ERR_MSG_MOD(info->extack, "IPv6 gateway with IPv4 route is not supported");
return notifier_from_errno(-EINVAL);
}
+ if (fen_info->fi->nh) {
+ NL_SET_ERR_MSG_MOD(info->extack, "IPv4 route with nexthop objects is not supported");
+ return notifier_from_errno(-EINVAL);
+ }
}
memcpy(&fib_work->fen_info, ptr, sizeof(fib_work->fen_info));
diff --git a/drivers/net/ethernet/rocker/rocker_ofdpa.c b/drivers/net/ethernet/rocker/rocker_ofdpa.c
index bdfa6a19d620..7072b249c8bd 100644
--- a/drivers/net/ethernet/rocker/rocker_ofdpa.c
+++ b/drivers/net/ethernet/rocker/rocker_ofdpa.c
@@ -18,6 +18,7 @@
#include <net/neighbour.h>
#include <net/switchdev.h>
#include <net/ip_fib.h>
+#include <net/nexthop.h>
#include <net/arp.h>
#include "rocker.h"
@@ -2282,8 +2283,8 @@ static int ofdpa_port_fib_ipv4(struct ofdpa_port *ofdpa_port, __be32 dst,
/* XXX support ECMP */
- nh = fi->fib_nh;
- nh_on_port = (fi->fib_dev == ofdpa_port->dev);
+ nh = fib_info_nh(fi, 0);
+ nh_on_port = (nh->fib_nh_dev == ofdpa_port->dev);
has_gw = !!nh->fib_nh_gw4;
if (has_gw && nh_on_port) {
@@ -2733,11 +2734,13 @@ static int ofdpa_fib4_add(struct rocker *rocker,
{
struct ofdpa *ofdpa = rocker->wpriv;
struct ofdpa_port *ofdpa_port;
+ struct fib_nh *nh;
int err;
if (ofdpa->fib_aborted)
return 0;
- ofdpa_port = ofdpa_port_dev_lower_find(fen_info->fi->fib_dev, rocker);
+ nh = fib_info_nh(fen_info->fi, 0);
+ ofdpa_port = ofdpa_port_dev_lower_find(nh->fib_nh_dev, rocker);
if (!ofdpa_port)
return 0;
err = ofdpa_port_fib_ipv4(ofdpa_port, htonl(fen_info->dst),
@@ -2745,7 +2748,7 @@ static int ofdpa_fib4_add(struct rocker *rocker,
fen_info->tb_id, 0);
if (err)
return err;
- fen_info->fi->fib_nh->fib_nh_flags |= RTNH_F_OFFLOAD;
+ nh->fib_nh_flags |= RTNH_F_OFFLOAD;
return 0;
}
@@ -2754,13 +2757,15 @@ static int ofdpa_fib4_del(struct rocker *rocker,
{
struct ofdpa *ofdpa = rocker->wpriv;
struct ofdpa_port *ofdpa_port;
+ struct fib_nh *nh;
if (ofdpa->fib_aborted)
return 0;
- ofdpa_port = ofdpa_port_dev_lower_find(fen_info->fi->fib_dev, rocker);
+ nh = fib_info_nh(fen_info->fi, 0);
+ ofdpa_port = ofdpa_port_dev_lower_find(nh->fib_nh_dev, rocker);
if (!ofdpa_port)
return 0;
- fen_info->fi->fib_nh->fib_nh_flags &= ~RTNH_F_OFFLOAD;
+ nh->fib_nh_flags &= ~RTNH_F_OFFLOAD;
return ofdpa_port_fib_ipv4(ofdpa_port, htonl(fen_info->dst),
fen_info->dst_len, fen_info->fi,
fen_info->tb_id, OFDPA_OP_FLAG_REMOVE);
@@ -2780,14 +2785,16 @@ static void ofdpa_fib4_abort(struct rocker *rocker)
spin_lock_irqsave(&ofdpa->flow_tbl_lock, flags);
hash_for_each_safe(ofdpa->flow_tbl, bkt, tmp, flow_entry, entry) {
+ struct fib_nh *nh;
+
if (flow_entry->key.tbl_id !=
ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING)
continue;
- ofdpa_port = ofdpa_port_dev_lower_find(flow_entry->fi->fib_dev,
- rocker);
+ nh = fib_info_nh(flow_entry->fi, 0);
+ ofdpa_port = ofdpa_port_dev_lower_find(nh->fib_nh_dev, rocker);
if (!ofdpa_port)
continue;
- flow_entry->fi->fib_nh->fib_nh_flags &= ~RTNH_F_OFFLOAD;
+ nh->fib_nh_flags &= ~RTNH_F_OFFLOAD;
ofdpa_flow_tbl_del(ofdpa_port, OFDPA_OP_FLAG_REMOVE,
flow_entry);
}
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h b/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h
index c61f260e18a4..049dc6cf4611 100644
--- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/* 10G controller driver for Samsung SoCs
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Siva Reddy Kallam <siva.kallam@samsung.com>
- *
- * 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.
*/
#ifndef __SXGBE_COMMON_H__
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_core.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_core.c
index 58c35692560e..e96e2bd295ef 100644
--- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_core.c
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_core.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* 10G controller driver for Samsung SoCs
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Siva Reddy Kallam <siva.kallam@samsung.com>
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.c
index 2686bb5b6765..b33ebf2dca47 100644
--- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.c
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* 10G controller driver for Samsung SoCs
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Siva Reddy Kallam <siva.kallam@samsung.com>
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.h b/drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.h
index 18609324db72..ede0827bf122 100644
--- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.h
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/* 10G controller driver for Samsung SoCs
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Siva Reddy Kallam <siva.kallam@samsung.com>
- *
- * 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.
*/
#ifndef __SXGBE_DESC_H__
#define __SXGBE_DESC_H__
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.c
index bb9b5b8afc5f..243db04b968c 100644
--- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.c
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* 10G controller driver for Samsung SoCs
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Siva Reddy Kallam <siva.kallam@samsung.com>
- *
- * 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.
*/
#include <linux/delay.h>
#include <linux/export.h>
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.h b/drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.h
index 1607b54c9bb0..e8f79a297278 100644
--- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.h
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/* 10G controller driver for Samsung SoCs
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Siva Reddy Kallam <siva.kallam@samsung.com>
- *
- * 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.
*/
#ifndef __SXGBE_DMA_H__
#define __SXGBE_DMA_H__
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c
index c9aad0eda57f..0775b9464b4e 100644
--- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* 10G controller driver for Samsung SoCs
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Siva Reddy Kallam <siva.kallam@samsung.com>
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
index 6d22dd500790..c56fcbb37066 100644
--- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* 10G controller driver for Samsung SoCs
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Siva Reddy Kallam <siva.kallam@samsung.com>
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_mdio.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_mdio.c
index 467ff7033606..b1e7f7ab281c 100644
--- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_mdio.c
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_mdio.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* 10G controller driver for Samsung SoCs
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Siva Reddy Kallam <siva.kallam@samsung.com>
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.c
index 324681c2bb74..298a7402e39c 100644
--- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.c
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* 10G controller driver for Samsung SoCs
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Siva Reddy Kallam <siva.kallam@samsung.com>
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.h b/drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.h
index 7e4810c4137e..e5634520700f 100644
--- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.h
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/* 10G controller driver for Samsung SoCs
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Siva Reddy Kallam <siva.kallam@samsung.com>
- *
- * 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.
*/
#ifndef __SXGBE_MTL_H__
#define __SXGBE_MTL_H__
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c
index d2bc9412ba03..d2c48116f181 100644
--- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* 10G controller driver for Samsung SoCs
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Siva Reddy Kallam <siva.kallam@samsung.com>
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_reg.h b/drivers/net/ethernet/samsung/sxgbe/sxgbe_reg.h
index 81437d91df99..4def84ebf143 100644
--- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_reg.h
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_reg.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/* 10G controller driver for Samsung SoCs
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Siva Reddy Kallam <siva.kallam@samsung.com>
- *
- * 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.
*/
#ifndef __SXGBE_REGMAP_H__
#define __SXGBE_REGMAP_H__
diff --git a/drivers/net/ethernet/seeq/ether3.c b/drivers/net/ethernet/seeq/ether3.c
index d1bb73bf9914..632a7c85964d 100644
--- a/drivers/net/ethernet/seeq/ether3.c
+++ b/drivers/net/ethernet/seeq/ether3.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/acorn/net/ether3.c
*
* Copyright (C) 1995-2000 Russell King
*
- * 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.
- *
* SEEQ nq8005 ethernet driver for Acorn/ANT Ether3 card
* for Acorn machines
*
diff --git a/drivers/net/ethernet/seeq/ether3.h b/drivers/net/ethernet/seeq/ether3.h
index be19e5fa5cf2..585dd51be201 100644
--- a/drivers/net/ethernet/seeq/ether3.h
+++ b/drivers/net/ethernet/seeq/ether3.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/drivers/acorn/net/ether3.h
*
* Copyright (C) 1995-2000 Russell King
*
- * 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.
- *
* network driver for Acorn/ANT Ether3 cards
*/
diff --git a/drivers/net/ethernet/sfc/bitfield.h b/drivers/net/ethernet/sfc/bitfield.h
index 41ad07d45144..1b59e9fe58b4 100644
--- a/drivers/net/ethernet/sfc/bitfield.h
+++ b/drivers/net/ethernet/sfc/bitfield.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2013 Solarflare Communications 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_BITFIELD_H
diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c
index e888b479c596..16d6952c312a 100644
--- a/drivers/net/ethernet/sfc/ef10.c
+++ b/drivers/net/ethernet/sfc/ef10.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2012-2013 Solarflare Communications 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 "net_driver.h"
diff --git a/drivers/net/ethernet/sfc/ef10_regs.h b/drivers/net/ethernet/sfc/ef10_regs.h
index 6a56778cf06c..154cfad95186 100644
--- a/drivers/net/ethernet/sfc/ef10_regs.h
+++ b/drivers/net/ethernet/sfc/ef10_regs.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2012-2017 Solarflare Communications 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_EF10_REGS_H
diff --git a/drivers/net/ethernet/sfc/ef10_sriov.c b/drivers/net/ethernet/sfc/ef10_sriov.c
index 3d76fd1504c2..52bd43f45761 100644
--- a/drivers/net/ethernet/sfc/ef10_sriov.c
+++ b/drivers/net/ethernet/sfc/ef10_sriov.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2015 Solarflare Communications 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 <linux/etherdevice.h>
#include <linux/pci.h>
diff --git a/drivers/net/ethernet/sfc/ef10_sriov.h b/drivers/net/ethernet/sfc/ef10_sriov.h
index 2aa444ed42de..cfe556d17313 100644
--- a/drivers/net/ethernet/sfc/ef10_sriov.h
+++ b/drivers/net/ethernet/sfc/ef10_sriov.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2015 Solarflare Communications 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 EF10_SRIOV_H
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
index bc655ffc9e02..ab58b837df47 100644
--- a/drivers/net/ethernet/sfc/efx.c
+++ b/drivers/net/ethernet/sfc/efx.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2005-2013 Solarflare Communications 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 <linux/module.h>
@@ -3617,11 +3614,7 @@ static int efx_pci_probe(struct pci_dev *pci_dev,
netif_warn(efx, probe, efx->net_dev,
"failed to create MTDs (%d)\n", rc);
- rc = pci_enable_pcie_error_reporting(pci_dev);
- if (rc && rc != -EINVAL)
- netif_notice(efx, probe, efx->net_dev,
- "PCIE error reporting unavailable (%d).\n",
- rc);
+ (void)pci_enable_pcie_error_reporting(pci_dev);
if (efx->type->udp_tnl_push_ports)
efx->type->udp_tnl_push_ports(efx);
diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h
index 3f759ebdcf10..04fed7c06618 100644
--- a/drivers/net/ethernet/sfc/efx.h
+++ b/drivers/net/ethernet/sfc/efx.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2013 Solarflare Communications 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_EFX_H
diff --git a/drivers/net/ethernet/sfc/enum.h b/drivers/net/ethernet/sfc/enum.h
index 6fa824211d91..3332cdf2918a 100644
--- a/drivers/net/ethernet/sfc/enum.h
+++ b/drivers/net/ethernet/sfc/enum.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2007-2013 Solarflare Communications 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_ENUM_H
diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c
index 600d7b895cf2..86b965875540 100644
--- a/drivers/net/ethernet/sfc/ethtool.c
+++ b/drivers/net/ethernet/sfc/ethtool.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2013 Solarflare Communications 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 <linux/netdevice.h>
diff --git a/drivers/net/ethernet/sfc/falcon/bitfield.h b/drivers/net/ethernet/sfc/falcon/bitfield.h
index 230fd77bd311..5eb178d0c149 100644
--- a/drivers/net/ethernet/sfc/falcon/bitfield.h
+++ b/drivers/net/ethernet/sfc/falcon/bitfield.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2013 Solarflare Communications 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 EF4_BITFIELD_H
diff --git a/drivers/net/ethernet/sfc/falcon/efx.c b/drivers/net/ethernet/sfc/falcon/efx.c
index 8b1f94d7a6c5..9b15c39ac670 100644
--- a/drivers/net/ethernet/sfc/falcon/efx.c
+++ b/drivers/net/ethernet/sfc/falcon/efx.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2005-2013 Solarflare Communications 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 <linux/module.h>
diff --git a/drivers/net/ethernet/sfc/falcon/efx.h b/drivers/net/ethernet/sfc/falcon/efx.h
index a4e4d8ea4078..d3b4646545fa 100644
--- a/drivers/net/ethernet/sfc/falcon/efx.h
+++ b/drivers/net/ethernet/sfc/falcon/efx.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2013 Solarflare Communications 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 EF4_EFX_H
diff --git a/drivers/net/ethernet/sfc/falcon/enum.h b/drivers/net/ethernet/sfc/falcon/enum.h
index 4824fcf5c3d4..7e6277fb47ec 100644
--- a/drivers/net/ethernet/sfc/falcon/enum.h
+++ b/drivers/net/ethernet/sfc/falcon/enum.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2007-2013 Solarflare Communications 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 EF4_ENUM_H
diff --git a/drivers/net/ethernet/sfc/falcon/ethtool.c b/drivers/net/ethernet/sfc/falcon/ethtool.c
index 72cedec945c1..08bd6a321918 100644
--- a/drivers/net/ethernet/sfc/falcon/ethtool.c
+++ b/drivers/net/ethernet/sfc/falcon/ethtool.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2013 Solarflare Communications 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 <linux/netdevice.h>
diff --git a/drivers/net/ethernet/sfc/falcon/falcon.c b/drivers/net/ethernet/sfc/falcon/falcon.c
index 6520d7bc8d21..3324a6219a09 100644
--- a/drivers/net/ethernet/sfc/falcon/falcon.c
+++ b/drivers/net/ethernet/sfc/falcon/falcon.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2013 Solarflare Communications 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 <linux/bitops.h>
diff --git a/drivers/net/ethernet/sfc/falcon/falcon_boards.c b/drivers/net/ethernet/sfc/falcon/falcon_boards.c
index dec83a217093..839189dab98e 100644
--- a/drivers/net/ethernet/sfc/falcon/falcon_boards.c
+++ b/drivers/net/ethernet/sfc/falcon/falcon_boards.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2007-2012 Solarflare Communications 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 <linux/rtnetlink.h>
diff --git a/drivers/net/ethernet/sfc/falcon/farch.c b/drivers/net/ethernet/sfc/falcon/farch.c
index 411a2f419447..332183280a45 100644
--- a/drivers/net/ethernet/sfc/falcon/farch.c
+++ b/drivers/net/ethernet/sfc/falcon/farch.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2013 Solarflare Communications 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 <linux/bitops.h>
diff --git a/drivers/net/ethernet/sfc/falcon/farch_regs.h b/drivers/net/ethernet/sfc/falcon/farch_regs.h
index 8095f273d574..5b01f3f3fde1 100644
--- a/drivers/net/ethernet/sfc/falcon/farch_regs.h
+++ b/drivers/net/ethernet/sfc/falcon/farch_regs.h
@@ -1,11 +1,8 @@
+/* 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.
- *
- * 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 EF4_FARCH_REGS_H
diff --git a/drivers/net/ethernet/sfc/falcon/filter.h b/drivers/net/ethernet/sfc/falcon/filter.h
index 647f6b2725c5..bc6f5f563e70 100644
--- a/drivers/net/ethernet/sfc/falcon/filter.h
+++ b/drivers/net/ethernet/sfc/falcon/filter.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2013 Solarflare Communications 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 EF4_FILTER_H
diff --git a/drivers/net/ethernet/sfc/falcon/io.h b/drivers/net/ethernet/sfc/falcon/io.h
index c3577643fbda..bc23c800a10f 100644
--- a/drivers/net/ethernet/sfc/falcon/io.h
+++ b/drivers/net/ethernet/sfc/falcon/io.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2013 Solarflare Communications 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 EF4_IO_H
diff --git a/drivers/net/ethernet/sfc/falcon/mdio_10g.c b/drivers/net/ethernet/sfc/falcon/mdio_10g.c
index ee0713f03d01..540278161449 100644
--- a/drivers/net/ethernet/sfc/falcon/mdio_10g.c
+++ b/drivers/net/ethernet/sfc/falcon/mdio_10g.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2006-2011 Solarflare Communications 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.
*/
/*
* Useful functions for working with MDIO clause 45 PHYs
diff --git a/drivers/net/ethernet/sfc/falcon/mdio_10g.h b/drivers/net/ethernet/sfc/falcon/mdio_10g.h
index 53cb5cc4ad37..de676bfa064d 100644
--- a/drivers/net/ethernet/sfc/falcon/mdio_10g.h
+++ b/drivers/net/ethernet/sfc/falcon/mdio_10g.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2006-2011 Solarflare Communications 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 EF4_MDIO_10G_H
diff --git a/drivers/net/ethernet/sfc/falcon/mtd.c b/drivers/net/ethernet/sfc/falcon/mtd.c
index 2d67e4621a3d..15bd47bf9e8e 100644
--- a/drivers/net/ethernet/sfc/falcon/mtd.c
+++ b/drivers/net/ethernet/sfc/falcon/mtd.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2013 Solarflare Communications 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 <linux/module.h>
diff --git a/drivers/net/ethernet/sfc/falcon/net_driver.h b/drivers/net/ethernet/sfc/falcon/net_driver.h
index 37a8bdf32206..a49ea2e719b6 100644
--- a/drivers/net/ethernet/sfc/falcon/net_driver.h
+++ b/drivers/net/ethernet/sfc/falcon/net_driver.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2005-2013 Solarflare Communications 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.
*/
/* Common definitions for all Efx net driver code */
diff --git a/drivers/net/ethernet/sfc/falcon/nic.c b/drivers/net/ethernet/sfc/falcon/nic.c
index 9c07b5175581..156da315ec89 100644
--- a/drivers/net/ethernet/sfc/falcon/nic.c
+++ b/drivers/net/ethernet/sfc/falcon/nic.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2013 Solarflare Communications 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 <linux/bitops.h>
diff --git a/drivers/net/ethernet/sfc/falcon/nic.h b/drivers/net/ethernet/sfc/falcon/nic.h
index 07c62dc552cb..9f413474bd9f 100644
--- a/drivers/net/ethernet/sfc/falcon/nic.h
+++ b/drivers/net/ethernet/sfc/falcon/nic.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2013 Solarflare Communications 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 EF4_NIC_H
diff --git a/drivers/net/ethernet/sfc/falcon/phy.h b/drivers/net/ethernet/sfc/falcon/phy.h
index 362141cee313..69bb548eae59 100644
--- a/drivers/net/ethernet/sfc/falcon/phy.h
+++ b/drivers/net/ethernet/sfc/falcon/phy.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2007-2010 Solarflare Communications 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 EF4_PHY_H
diff --git a/drivers/net/ethernet/sfc/falcon/qt202x_phy.c b/drivers/net/ethernet/sfc/falcon/qt202x_phy.c
index f5e0f18d4ea8..21af67e42296 100644
--- a/drivers/net/ethernet/sfc/falcon/qt202x_phy.c
+++ b/drivers/net/ethernet/sfc/falcon/qt202x_phy.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2006-2012 Solarflare Communications 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.
*/
/*
* Driver for AMCC QT202x SFP+ and XFP adapters; see www.amcc.com for details
diff --git a/drivers/net/ethernet/sfc/falcon/rx.c b/drivers/net/ethernet/sfc/falcon/rx.c
index 02456ed13a7d..fd850d3d8ec0 100644
--- a/drivers/net/ethernet/sfc/falcon/rx.c
+++ b/drivers/net/ethernet/sfc/falcon/rx.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2005-2013 Solarflare Communications 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 <linux/socket.h>
diff --git a/drivers/net/ethernet/sfc/falcon/selftest.c b/drivers/net/ethernet/sfc/falcon/selftest.c
index 55c0fbbc4fb8..147677c7c72f 100644
--- a/drivers/net/ethernet/sfc/falcon/selftest.c
+++ b/drivers/net/ethernet/sfc/falcon/selftest.c
@@ -1,11 +1,8 @@
+// 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.
- *
- * 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 <linux/netdevice.h>
diff --git a/drivers/net/ethernet/sfc/falcon/selftest.h b/drivers/net/ethernet/sfc/falcon/selftest.h
index be52a49c006a..c0dbc6394e0f 100644
--- a/drivers/net/ethernet/sfc/falcon/selftest.h
+++ b/drivers/net/ethernet/sfc/falcon/selftest.h
@@ -1,11 +1,8 @@
+/* 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.
- *
- * 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 EF4_SELFTEST_H
diff --git a/drivers/net/ethernet/sfc/falcon/tenxpress.c b/drivers/net/ethernet/sfc/falcon/tenxpress.c
index ff9b4e2b590c..e27824ef121f 100644
--- a/drivers/net/ethernet/sfc/falcon/tenxpress.c
+++ b/drivers/net/ethernet/sfc/falcon/tenxpress.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2007-2011 Solarflare Communications 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 <linux/delay.h>
diff --git a/drivers/net/ethernet/sfc/falcon/tx.c b/drivers/net/ethernet/sfc/falcon/tx.c
index c5059f456f37..f7306e93a8b8 100644
--- a/drivers/net/ethernet/sfc/falcon/tx.c
+++ b/drivers/net/ethernet/sfc/falcon/tx.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2005-2013 Solarflare Communications 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 <linux/pci.h>
diff --git a/drivers/net/ethernet/sfc/falcon/tx.h b/drivers/net/ethernet/sfc/falcon/tx.h
index a607eb0087a8..2a88c59cbbbe 100644
--- a/drivers/net/ethernet/sfc/falcon/tx.h
+++ b/drivers/net/ethernet/sfc/falcon/tx.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2015 Solarflare Communications 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 EF4_TX_H
diff --git a/drivers/net/ethernet/sfc/falcon/txc43128_phy.c b/drivers/net/ethernet/sfc/falcon/txc43128_phy.c
index 3c55fd23c271..f3503965c52c 100644
--- a/drivers/net/ethernet/sfc/falcon/txc43128_phy.c
+++ b/drivers/net/ethernet/sfc/falcon/txc43128_phy.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2006-2011 Solarflare Communications 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.
*/
/*
diff --git a/drivers/net/ethernet/sfc/falcon/workarounds.h b/drivers/net/ethernet/sfc/falcon/workarounds.h
index 6af800bc9633..e28c67fc92a3 100644
--- a/drivers/net/ethernet/sfc/falcon/workarounds.h
+++ b/drivers/net/ethernet/sfc/falcon/workarounds.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2006-2013 Solarflare Communications 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 EF4_WORKAROUNDS_H
diff --git a/drivers/net/ethernet/sfc/farch.c b/drivers/net/ethernet/sfc/farch.c
index e045a5d6b938..eedd32e2bfcb 100644
--- a/drivers/net/ethernet/sfc/farch.c
+++ b/drivers/net/ethernet/sfc/farch.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2013 Solarflare Communications 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 <linux/bitops.h>
diff --git a/drivers/net/ethernet/sfc/farch_regs.h b/drivers/net/ethernet/sfc/farch_regs.h
index 7019a712e799..d138be423e63 100644
--- a/drivers/net/ethernet/sfc/farch_regs.h
+++ b/drivers/net/ethernet/sfc/farch_regs.h
@@ -1,11 +1,8 @@
+/* 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.
- *
- * 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_FARCH_REGS_H
diff --git a/drivers/net/ethernet/sfc/filter.h b/drivers/net/ethernet/sfc/filter.h
index 59021ad6d98d..40b2af8bfb81 100644
--- a/drivers/net/ethernet/sfc/filter.h
+++ b/drivers/net/ethernet/sfc/filter.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2013 Solarflare Communications 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_FILTER_H
diff --git a/drivers/net/ethernet/sfc/io.h b/drivers/net/ethernet/sfc/io.h
index 2774a10f44e9..c3c011bc6a68 100644
--- a/drivers/net/ethernet/sfc/io.h
+++ b/drivers/net/ethernet/sfc/io.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2013 Solarflare Communications 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_IO_H
diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c
index 295ec1787b9f..2713300343c7 100644
--- a/drivers/net/ethernet/sfc/mcdi.c
+++ b/drivers/net/ethernet/sfc/mcdi.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2008-2013 Solarflare Communications 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 <linux/delay.h>
diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h
index ebd95972ae7b..9081f84a2604 100644
--- a/drivers/net/ethernet/sfc/mcdi.h
+++ b/drivers/net/ethernet/sfc/mcdi.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2008-2013 Solarflare Communications 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_MCDI_H
diff --git a/drivers/net/ethernet/sfc/mcdi_mon.c b/drivers/net/ethernet/sfc/mcdi_mon.c
index f17751559ccc..5954fcfee2b1 100644
--- a/drivers/net/ethernet/sfc/mcdi_mon.c
+++ b/drivers/net/ethernet/sfc/mcdi_mon.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2011-2013 Solarflare Communications 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 <linux/bitops.h>
diff --git a/drivers/net/ethernet/sfc/mcdi_pcol.h b/drivers/net/ethernet/sfc/mcdi_pcol.h
index 20a5523bf9f3..79d834a4ae49 100644
--- a/drivers/net/ethernet/sfc/mcdi_pcol.h
+++ b/drivers/net/ethernet/sfc/mcdi_pcol.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2009-2013 Solarflare Communications 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.
*/
diff --git a/drivers/net/ethernet/sfc/mcdi_port.c b/drivers/net/ethernet/sfc/mcdi_port.c
index a4bbfebe3d64..fb7cde4980ed 100644
--- a/drivers/net/ethernet/sfc/mcdi_port.c
+++ b/drivers/net/ethernet/sfc/mcdi_port.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2009-2013 Solarflare Communications 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.
*/
/*
diff --git a/drivers/net/ethernet/sfc/mtd.c b/drivers/net/ethernet/sfc/mtd.c
index 0d03e0577d85..273c08e5455f 100644
--- a/drivers/net/ethernet/sfc/mtd.c
+++ b/drivers/net/ethernet/sfc/mtd.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2013 Solarflare Communications 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 <linux/module.h>
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
index 961b92979640..284a1b047ac2 100644
--- a/drivers/net/ethernet/sfc/net_driver.h
+++ b/drivers/net/ethernet/sfc/net_driver.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2005-2013 Solarflare Communications 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.
*/
/* Common definitions for all Efx net driver code */
diff --git a/drivers/net/ethernet/sfc/nic.c b/drivers/net/ethernet/sfc/nic.c
index c2d45a40eb48..b0baa70fbba7 100644
--- a/drivers/net/ethernet/sfc/nic.c
+++ b/drivers/net/ethernet/sfc/nic.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2013 Solarflare Communications 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 <linux/bitops.h>
diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h
index 5cca0556b47f..1f7c5717de75 100644
--- a/drivers/net/ethernet/sfc/nic.h
+++ b/drivers/net/ethernet/sfc/nic.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2013 Solarflare Communications 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_NIC_H
diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c
index f21661532ed3..02ed6d1b716c 100644
--- a/drivers/net/ethernet/sfc/ptp.c
+++ b/drivers/net/ethernet/sfc/ptp.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2011-2013 Solarflare Communications 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.
*/
/* Theory of operation:
diff --git a/drivers/net/ethernet/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c
index 8702ab44d80b..d5db045535d3 100644
--- a/drivers/net/ethernet/sfc/rx.c
+++ b/drivers/net/ethernet/sfc/rx.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2005-2013 Solarflare Communications 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 <linux/socket.h>
diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c
index f6936949fc85..8474cf8ea7d3 100644
--- a/drivers/net/ethernet/sfc/selftest.c
+++ b/drivers/net/ethernet/sfc/selftest.c
@@ -1,11 +1,8 @@
+// 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.
- *
- * 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 <linux/netdevice.h>
diff --git a/drivers/net/ethernet/sfc/selftest.h b/drivers/net/ethernet/sfc/selftest.h
index 32a427253a03..a3553816d92c 100644
--- a/drivers/net/ethernet/sfc/selftest.h
+++ b/drivers/net/ethernet/sfc/selftest.h
@@ -1,11 +1,8 @@
+/* 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.
- *
- * 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_SELFTEST_H
diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c
index 65161f68265a..81499244a4b4 100644
--- a/drivers/net/ethernet/sfc/siena.c
+++ b/drivers/net/ethernet/sfc/siena.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2013 Solarflare Communications 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 <linux/bitops.h>
diff --git a/drivers/net/ethernet/sfc/siena_sriov.c b/drivers/net/ethernet/sfc/siena_sriov.c
index da7b94f34604..dfbdf05dcf79 100644
--- a/drivers/net/ethernet/sfc/siena_sriov.c
+++ b/drivers/net/ethernet/sfc/siena_sriov.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2010-2012 Solarflare Communications 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 <linux/pci.h>
#include <linux/module.h>
diff --git a/drivers/net/ethernet/sfc/siena_sriov.h b/drivers/net/ethernet/sfc/siena_sriov.h
index d88d4dab170a..e441c89c25ce 100644
--- a/drivers/net/ethernet/sfc/siena_sriov.h
+++ b/drivers/net/ethernet/sfc/siena_sriov.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2015 Solarflare Communications 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 SIENA_SRIOV_H
diff --git a/drivers/net/ethernet/sfc/sriov.c b/drivers/net/ethernet/sfc/sriov.c
index 0b766fdbcddb..3f241e6c881a 100644
--- a/drivers/net/ethernet/sfc/sriov.c
+++ b/drivers/net/ethernet/sfc/sriov.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2014-2015 Solarflare Communications 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 <linux/module.h>
#include "net_driver.h"
diff --git a/drivers/net/ethernet/sfc/sriov.h b/drivers/net/ethernet/sfc/sriov.h
index 84c7984edcaf..747707bee483 100644
--- a/drivers/net/ethernet/sfc/sriov.h
+++ b/drivers/net/ethernet/sfc/sriov.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2014-2015 Solarflare Communications 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_SRIOV_H
diff --git a/drivers/net/ethernet/sfc/tx.c b/drivers/net/ethernet/sfc/tx.c
index e182055ec2eb..31ec56091a5d 100644
--- a/drivers/net/ethernet/sfc/tx.c
+++ b/drivers/net/ethernet/sfc/tx.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2005-2013 Solarflare Communications 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 <linux/pci.h>
diff --git a/drivers/net/ethernet/sfc/tx.h b/drivers/net/ethernet/sfc/tx.h
index 1cccc97ec676..e04d5ddeb32c 100644
--- a/drivers/net/ethernet/sfc/tx.h
+++ b/drivers/net/ethernet/sfc/tx.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2015 Solarflare Communications 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_TX_H
diff --git a/drivers/net/ethernet/sfc/tx_tso.c b/drivers/net/ethernet/sfc/tx_tso.c
index e0cbda9ae859..898e5c61d908 100644
--- a/drivers/net/ethernet/sfc/tx_tso.c
+++ b/drivers/net/ethernet/sfc/tx_tso.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2005-2015 Solarflare Communications 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 <linux/pci.h>
diff --git a/drivers/net/ethernet/sfc/vfdi.h b/drivers/net/ethernet/sfc/vfdi.h
index f62901d4cae0..480b872eb4d1 100644
--- a/drivers/net/ethernet/sfc/vfdi.h
+++ b/drivers/net/ethernet/sfc/vfdi.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2010-2012 Solarflare Communications 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 _VFDI_H
#define _VFDI_H
diff --git a/drivers/net/ethernet/sfc/workarounds.h b/drivers/net/ethernet/sfc/workarounds.h
index c67fa18b8121..815be2d20c4b 100644
--- a/drivers/net/ethernet/sfc/workarounds.h
+++ b/drivers/net/ethernet/sfc/workarounds.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2006-2013 Solarflare Communications 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_WORKAROUNDS_H
diff --git a/drivers/net/ethernet/sis/sis900.c b/drivers/net/ethernet/sis/sis900.c
index 67f9bb6e941b..6e07f5ebacfc 100644
--- a/drivers/net/ethernet/sis/sis900.c
+++ b/drivers/net/ethernet/sis/sis900.c
@@ -262,7 +262,7 @@ static int sis900_get_mac_addr(struct pci_dev *pci_dev,
/* check to see if we have sane EEPROM */
signature = (u16) read_eeprom(ioaddr, EEPROMSignature);
if (signature == 0xffff || signature == 0x0000) {
- printk (KERN_WARNING "%s: Error EERPOM read %x\n",
+ printk (KERN_WARNING "%s: Error EEPROM read %x\n",
pci_name(pci_dev), signature);
return 0;
}
@@ -359,9 +359,9 @@ static int sis635_get_mac_addr(struct pci_dev *pci_dev,
*
* SiS962 or SiS963 model, use EEPROM to store MAC address. And EEPROM
* is shared by
- * LAN and 1394. When access EEPROM, send EEREQ signal to hardware first
- * and wait for EEGNT. If EEGNT is ON, EEPROM is permitted to be access
- * by LAN, otherwise is not. After MAC address is read from EEPROM, send
+ * LAN and 1394. When accessing EEPROM, send EEREQ signal to hardware first
+ * and wait for EEGNT. If EEGNT is ON, EEPROM is permitted to be accessed
+ * by LAN, otherwise it is not. After MAC address is read from EEPROM, send
* EEDONE signal to refuse EEPROM access by LAN.
* The EEPROM map of SiS962 or SiS963 is different to SiS900.
* The signature field in SiS962 or SiS963 spec is meaningless.
@@ -882,7 +882,7 @@ static void mdio_reset(struct sis900_private *sp)
* mdio_read - read MII PHY register
* @net_dev: the net device to read
* @phy_id: the phy address to read
- * @location: the phy regiester id to read
+ * @location: the phy register id to read
*
* Read MII registers through MDIO and MDC
* using MDIO management frame structure and protocol(defined by ISO/IEC).
@@ -926,7 +926,7 @@ static int mdio_read(struct net_device *net_dev, int phy_id, int location)
* mdio_write - write MII PHY register
* @net_dev: the net device to write
* @phy_id: the phy address to write
- * @location: the phy regiester id to write
+ * @location: the phy register id to write
* @value: the register value to write with
*
* Write MII registers with @value through MDIO and MDC
@@ -1057,7 +1057,7 @@ sis900_open(struct net_device *net_dev)
sis900_set_mode(sis_priv, HW_SPEED_10_MBPS, FDX_CAPABLE_HALF_SELECTED);
/* Enable all known interrupts by setting the interrupt mask. */
- sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE);
+ sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxDESC);
sw32(cr, RxENA | sr32(cr));
sw32(ier, IE);
@@ -1101,7 +1101,7 @@ sis900_init_rxfilter (struct net_device * net_dev)
sw32(rfdr, w);
if (netif_msg_hw(sis_priv)) {
- printk(KERN_DEBUG "%s: Receive Filter Addrss[%d]=%x\n",
+ printk(KERN_DEBUG "%s: Receive Filter Address[%d]=%x\n",
net_dev->name, i, sr32(rfdr));
}
}
@@ -1148,7 +1148,7 @@ sis900_init_tx_ring(struct net_device *net_dev)
* @net_dev: the net device to initialize for
*
* Initialize the Rx descriptor ring,
- * and pre-allocate recevie buffers (socket buffer)
+ * and pre-allocate receive buffers (socket buffer)
*/
static void
@@ -1578,7 +1578,7 @@ static void sis900_tx_timeout(struct net_device *net_dev)
sw32(txdp, sis_priv->tx_ring_dma);
/* Enable all known interrupts by setting the interrupt mask. */
- sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE);
+ sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxDESC);
}
/**
@@ -1618,7 +1618,7 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
spin_unlock_irqrestore(&sis_priv->lock, flags);
return NETDEV_TX_OK;
}
- sis_priv->tx_ring[entry].cmdsts = (OWN | skb->len);
+ sis_priv->tx_ring[entry].cmdsts = (OWN | INTR | skb->len);
sw32(cr, TxENA | sr32(cr));
sis_priv->cur_tx ++;
@@ -1674,8 +1674,8 @@ static irqreturn_t sis900_interrupt(int irq, void *dev_instance)
do {
status = sr32(isr);
- if ((status & (HIBERR|TxURN|TxERR|TxIDLE|RxORN|RxERR|RxOK)) == 0)
- /* nothing intresting happened */
+ if ((status & (HIBERR|TxURN|TxERR|TxDESC|RxORN|RxERR|RxOK)) == 0)
+ /* nothing interesting happened */
break;
handled = 1;
@@ -1684,7 +1684,7 @@ static irqreturn_t sis900_interrupt(int irq, void *dev_instance)
/* Rx interrupt */
sis900_rx(net_dev);
- if (status & (TxURN | TxERR | TxIDLE))
+ if (status & (TxURN | TxERR | TxDESC))
/* Tx interrupt */
sis900_finish_xmit(net_dev);
@@ -1896,8 +1896,8 @@ static void sis900_finish_xmit (struct net_device *net_dev)
if (tx_status & OWN) {
/* The packet is not transmitted yet (owned by hardware) !
- * Note: the interrupt is generated only when Tx Machine
- * is idle, so this is an almost impossible case */
+ * Note: this is an almost impossible condition
+ * on TxDESC interrupt ('descriptor interrupt') */
break;
}
@@ -2473,7 +2473,7 @@ static int sis900_resume(struct pci_dev *pci_dev)
sis900_set_mode(sis_priv, HW_SPEED_10_MBPS, FDX_CAPABLE_HALF_SELECTED);
/* Enable all known interrupts by setting the interrupt mask. */
- sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE);
+ sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxDESC);
sw32(cr, RxENA | sr32(cr));
sw32(ier, IE);
diff --git a/drivers/net/ethernet/smsc/Kconfig b/drivers/net/ethernet/smsc/Kconfig
index d1b6a78557ec..9e1c3752b200 100644
--- a/drivers/net/ethernet/smsc/Kconfig
+++ b/drivers/net/ethernet/smsc/Kconfig
@@ -49,7 +49,7 @@ config SMC91X
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called smc91x. If you want to compile it as a
- module, say M here and read <file:Documentation/kbuild/modules.txt>.
+ module, say M here and read <file:Documentation/kbuild/modules.rst>.
config PCMCIA_SMC91C92
tristate "SMC 91Cxx PCMCIA support"
@@ -86,7 +86,7 @@ config SMC911X
This driver is also available as a module. The module will be
called smc911x. If you want to compile it as a module, say M
- here and read <file:Documentation/kbuild/modules.txt>
+ here and read <file:Documentation/kbuild/modules.rst>
config SMSC911X
tristate "SMSC LAN911x/LAN921x families embedded ethernet support"
@@ -121,6 +121,6 @@ config SMSC9420
This driver is also available as a module. The module will be
called smsc9420. If you want to compile it as a module, say M
- here and read <file:Documentation/kbuild/modules.txt>
+ here and read <file:Documentation/kbuild/modules.rst>
endif # NET_VENDOR_SMSC
diff --git a/drivers/net/ethernet/socionext/Kconfig b/drivers/net/ethernet/socionext/Kconfig
index 25f18be27423..95e99baf3f45 100644
--- a/drivers/net/ethernet/socionext/Kconfig
+++ b/drivers/net/ethernet/socionext/Kconfig
@@ -26,6 +26,7 @@ config SNI_NETSEC
tristate "Socionext NETSEC ethernet support"
depends on (ARCH_SYNQUACER || COMPILE_TEST) && OF
select PHYLIB
+ select PAGE_POOL
select MII
---help---
Enable to add support for the SocioNext NetSec Gigabit Ethernet
diff --git a/drivers/net/ethernet/socionext/netsec.c b/drivers/net/ethernet/socionext/netsec.c
index cba5881b2746..1502fe8b0456 100644
--- a/drivers/net/ethernet/socionext/netsec.c
+++ b/drivers/net/ethernet/socionext/netsec.c
@@ -9,8 +9,12 @@
#include <linux/etherdevice.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/netlink.h>
+#include <linux/bpf.h>
+#include <linux/bpf_trace.h>
#include <net/tcp.h>
+#include <net/page_pool.h>
#include <net/ip6_checksum.h>
#define NETSEC_REG_SOFT_RST 0x104
@@ -235,22 +239,41 @@
#define DESC_NUM 256
#define NETSEC_SKB_PAD (NET_SKB_PAD + NET_IP_ALIGN)
-#define NETSEC_RX_BUF_SZ 1536
+#define NETSEC_RXBUF_HEADROOM (max(XDP_PACKET_HEADROOM, NET_SKB_PAD) + \
+ NET_IP_ALIGN)
+#define NETSEC_RX_BUF_NON_DATA (NETSEC_RXBUF_HEADROOM + \
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
#define DESC_SZ sizeof(struct netsec_de)
#define NETSEC_F_NETSEC_VER_MAJOR_NUM(x) ((x) & 0xffff0000)
+#define NETSEC_XDP_PASS 0
+#define NETSEC_XDP_CONSUMED BIT(0)
+#define NETSEC_XDP_TX BIT(1)
+#define NETSEC_XDP_REDIR BIT(2)
+#define NETSEC_XDP_RX_OK (NETSEC_XDP_PASS | NETSEC_XDP_TX | NETSEC_XDP_REDIR)
+
enum ring_id {
NETSEC_RING_TX = 0,
NETSEC_RING_RX
};
+enum buf_type {
+ TYPE_NETSEC_SKB = 0,
+ TYPE_NETSEC_XDP_TX,
+ TYPE_NETSEC_XDP_NDO,
+};
+
struct netsec_desc {
- struct sk_buff *skb;
+ union {
+ struct sk_buff *skb;
+ struct xdp_frame *xdpf;
+ };
dma_addr_t dma_addr;
void *addr;
u16 len;
+ u8 buf_type;
};
struct netsec_desc_ring {
@@ -258,11 +281,17 @@ struct netsec_desc_ring {
struct netsec_desc *desc;
void *vaddr;
u16 head, tail;
+ u16 xdp_xmit; /* netsec_xdp_xmit packets */
+ bool is_xdp;
+ struct page_pool *page_pool;
+ struct xdp_rxq_info xdp_rxq;
+ spinlock_t lock; /* XDP tx queue locking */
};
struct netsec_priv {
struct netsec_desc_ring desc_ring[NETSEC_RING_MAX];
struct ethtool_coalesce et_coalesce;
+ struct bpf_prog *xdp_prog;
spinlock_t reglock; /* protect reg access */
struct napi_struct napi;
phy_interface_t phy_interface;
@@ -600,12 +629,14 @@ static void netsec_set_rx_de(struct netsec_priv *priv,
static bool netsec_clean_tx_dring(struct netsec_priv *priv)
{
struct netsec_desc_ring *dring = &priv->desc_ring[NETSEC_RING_TX];
- unsigned int pkts, bytes;
struct netsec_de *entry;
int tail = dring->tail;
+ unsigned int bytes;
int cnt = 0;
- pkts = 0;
+ if (dring->is_xdp)
+ spin_lock(&dring->lock);
+
bytes = 0;
entry = dring->vaddr + DESC_SZ * tail;
@@ -618,13 +649,23 @@ static bool netsec_clean_tx_dring(struct netsec_priv *priv)
eop = (entry->attr >> NETSEC_TX_LAST) & 1;
dma_rmb();
- dma_unmap_single(priv->dev, desc->dma_addr, desc->len,
- DMA_TO_DEVICE);
- if (eop) {
- pkts++;
+ /* if buf_type is either TYPE_NETSEC_SKB or
+ * TYPE_NETSEC_XDP_NDO we mapped it
+ */
+ if (desc->buf_type != TYPE_NETSEC_XDP_TX)
+ dma_unmap_single(priv->dev, desc->dma_addr, desc->len,
+ DMA_TO_DEVICE);
+
+ if (!eop)
+ goto next;
+
+ if (desc->buf_type == TYPE_NETSEC_SKB) {
bytes += desc->skb->len;
dev_kfree_skb(desc->skb);
+ } else {
+ xdp_return_frame(desc->xdpf);
}
+next:
/* clean up so netsec_uninit_pkt_dring() won't free the skb
* again
*/
@@ -641,6 +682,8 @@ static bool netsec_clean_tx_dring(struct netsec_priv *priv)
entry = dring->vaddr + DESC_SZ * tail;
cnt++;
}
+ if (dring->is_xdp)
+ spin_unlock(&dring->lock);
if (!cnt)
return false;
@@ -673,33 +716,31 @@ static void netsec_process_tx(struct netsec_priv *priv)
}
static void *netsec_alloc_rx_data(struct netsec_priv *priv,
- dma_addr_t *dma_handle, u16 *desc_len,
- bool napi)
+ dma_addr_t *dma_handle, u16 *desc_len)
+
{
- size_t total_len = SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
- size_t payload_len = NETSEC_RX_BUF_SZ;
- dma_addr_t mapping;
- void *buf;
- total_len += SKB_DATA_ALIGN(payload_len + NETSEC_SKB_PAD);
+ struct netsec_desc_ring *dring = &priv->desc_ring[NETSEC_RING_RX];
+ enum dma_data_direction dma_dir;
+ struct page *page;
- buf = napi ? napi_alloc_frag(total_len) : netdev_alloc_frag(total_len);
- if (!buf)
+ page = page_pool_dev_alloc_pages(dring->page_pool);
+ if (!page)
return NULL;
- mapping = dma_map_single(priv->dev, buf + NETSEC_SKB_PAD, payload_len,
- DMA_FROM_DEVICE);
- if (unlikely(dma_mapping_error(priv->dev, mapping)))
- goto err_out;
-
- *dma_handle = mapping;
- *desc_len = payload_len;
-
- return buf;
+ /* We allocate the same buffer length for XDP and non-XDP cases.
+ * page_pool API will map the whole page, skip what's needed for
+ * network payloads and/or XDP
+ */
+ *dma_handle = page_pool_get_dma_addr(page) + NETSEC_RXBUF_HEADROOM;
+ /* Make sure the incoming payload fits in the page for XDP and non-XDP
+ * cases and reserve enough space for headroom + skb_shared_info
+ */
+ *desc_len = PAGE_SIZE - NETSEC_RX_BUF_NON_DATA;
+ dma_dir = page_pool_get_dma_dir(dring->page_pool);
+ dma_sync_single_for_device(priv->dev, *dma_handle, *desc_len, dma_dir);
-err_out:
- skb_free_frag(buf);
- return NULL;
+ return page_address(page);
}
static void netsec_rx_fill(struct netsec_priv *priv, u16 from, u16 num)
@@ -716,22 +757,201 @@ static void netsec_rx_fill(struct netsec_priv *priv, u16 from, u16 num)
}
}
+static void netsec_xdp_ring_tx_db(struct netsec_priv *priv, u16 pkts)
+{
+ if (likely(pkts))
+ netsec_write(priv, NETSEC_REG_NRM_TX_PKTCNT, pkts);
+}
+
+static void netsec_finalize_xdp_rx(struct netsec_priv *priv, u32 xdp_res,
+ u16 pkts)
+{
+ if (xdp_res & NETSEC_XDP_REDIR)
+ xdp_do_flush_map();
+
+ if (xdp_res & NETSEC_XDP_TX)
+ netsec_xdp_ring_tx_db(priv, pkts);
+}
+
+static void netsec_set_tx_de(struct netsec_priv *priv,
+ struct netsec_desc_ring *dring,
+ const struct netsec_tx_pkt_ctrl *tx_ctrl,
+ const struct netsec_desc *desc, void *buf)
+{
+ int idx = dring->head;
+ struct netsec_de *de;
+ u32 attr;
+
+ de = dring->vaddr + (DESC_SZ * idx);
+
+ attr = (1 << NETSEC_TX_SHIFT_OWN_FIELD) |
+ (1 << NETSEC_TX_SHIFT_PT_FIELD) |
+ (NETSEC_RING_GMAC << NETSEC_TX_SHIFT_TDRID_FIELD) |
+ (1 << NETSEC_TX_SHIFT_FS_FIELD) |
+ (1 << NETSEC_TX_LAST) |
+ (tx_ctrl->cksum_offload_flag << NETSEC_TX_SHIFT_CO) |
+ (tx_ctrl->tcp_seg_offload_flag << NETSEC_TX_SHIFT_SO) |
+ (1 << NETSEC_TX_SHIFT_TRS_FIELD);
+ if (idx == DESC_NUM - 1)
+ attr |= (1 << NETSEC_TX_SHIFT_LD_FIELD);
+
+ de->data_buf_addr_up = upper_32_bits(desc->dma_addr);
+ de->data_buf_addr_lw = lower_32_bits(desc->dma_addr);
+ de->buf_len_info = (tx_ctrl->tcp_seg_len << 16) | desc->len;
+ de->attr = attr;
+ /* under spin_lock if using XDP */
+ if (!dring->is_xdp)
+ dma_wmb();
+
+ dring->desc[idx] = *desc;
+ if (desc->buf_type == TYPE_NETSEC_SKB)
+ dring->desc[idx].skb = buf;
+ else if (desc->buf_type == TYPE_NETSEC_XDP_TX ||
+ desc->buf_type == TYPE_NETSEC_XDP_NDO)
+ dring->desc[idx].xdpf = buf;
+
+ /* move head ahead */
+ dring->head = (dring->head + 1) % DESC_NUM;
+}
+
+/* The current driver only supports 1 Txq, this should run under spin_lock() */
+static u32 netsec_xdp_queue_one(struct netsec_priv *priv,
+ struct xdp_frame *xdpf, bool is_ndo)
+
+{
+ struct netsec_desc_ring *tx_ring = &priv->desc_ring[NETSEC_RING_TX];
+ struct page *page = virt_to_page(xdpf->data);
+ struct netsec_tx_pkt_ctrl tx_ctrl = {};
+ struct netsec_desc tx_desc;
+ dma_addr_t dma_handle;
+ u16 filled;
+
+ if (tx_ring->head >= tx_ring->tail)
+ filled = tx_ring->head - tx_ring->tail;
+ else
+ filled = tx_ring->head + DESC_NUM - tx_ring->tail;
+
+ if (DESC_NUM - filled <= 1)
+ return NETSEC_XDP_CONSUMED;
+
+ if (is_ndo) {
+ /* this is for ndo_xdp_xmit, the buffer needs mapping before
+ * sending
+ */
+ dma_handle = dma_map_single(priv->dev, xdpf->data, xdpf->len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(priv->dev, dma_handle))
+ return NETSEC_XDP_CONSUMED;
+ tx_desc.buf_type = TYPE_NETSEC_XDP_NDO;
+ } else {
+ /* This is the device Rx buffer from page_pool. No need to remap
+ * just sync and send it
+ */
+ struct netsec_desc_ring *rx_ring =
+ &priv->desc_ring[NETSEC_RING_RX];
+ enum dma_data_direction dma_dir =
+ page_pool_get_dma_dir(rx_ring->page_pool);
+
+ dma_handle = page_pool_get_dma_addr(page) +
+ NETSEC_RXBUF_HEADROOM;
+ dma_sync_single_for_device(priv->dev, dma_handle, xdpf->len,
+ dma_dir);
+ tx_desc.buf_type = TYPE_NETSEC_XDP_TX;
+ }
+
+ tx_desc.dma_addr = dma_handle;
+ tx_desc.addr = xdpf->data;
+ tx_desc.len = xdpf->len;
+
+ netsec_set_tx_de(priv, tx_ring, &tx_ctrl, &tx_desc, xdpf);
+
+ return NETSEC_XDP_TX;
+}
+
+static u32 netsec_xdp_xmit_back(struct netsec_priv *priv, struct xdp_buff *xdp)
+{
+ struct netsec_desc_ring *tx_ring = &priv->desc_ring[NETSEC_RING_TX];
+ struct xdp_frame *xdpf = convert_to_xdp_frame(xdp);
+ u32 ret;
+
+ if (unlikely(!xdpf))
+ return NETSEC_XDP_CONSUMED;
+
+ spin_lock(&tx_ring->lock);
+ ret = netsec_xdp_queue_one(priv, xdpf, false);
+ spin_unlock(&tx_ring->lock);
+
+ return ret;
+}
+
+static u32 netsec_run_xdp(struct netsec_priv *priv, struct bpf_prog *prog,
+ struct xdp_buff *xdp)
+{
+ u32 ret = NETSEC_XDP_PASS;
+ int err;
+ u32 act;
+
+ act = bpf_prog_run_xdp(prog, xdp);
+
+ switch (act) {
+ case XDP_PASS:
+ ret = NETSEC_XDP_PASS;
+ break;
+ case XDP_TX:
+ ret = netsec_xdp_xmit_back(priv, xdp);
+ if (ret != NETSEC_XDP_TX)
+ xdp_return_buff(xdp);
+ break;
+ case XDP_REDIRECT:
+ err = xdp_do_redirect(priv->ndev, xdp, prog);
+ if (!err) {
+ ret = NETSEC_XDP_REDIR;
+ } else {
+ ret = NETSEC_XDP_CONSUMED;
+ xdp_return_buff(xdp);
+ }
+ break;
+ default:
+ bpf_warn_invalid_xdp_action(act);
+ /* fall through */
+ case XDP_ABORTED:
+ trace_xdp_exception(priv->ndev, prog, act);
+ /* fall through -- handle aborts by dropping packet */
+ case XDP_DROP:
+ ret = NETSEC_XDP_CONSUMED;
+ xdp_return_buff(xdp);
+ break;
+ }
+
+ return ret;
+}
+
static int netsec_process_rx(struct netsec_priv *priv, int budget)
{
struct netsec_desc_ring *dring = &priv->desc_ring[NETSEC_RING_RX];
struct net_device *ndev = priv->ndev;
struct netsec_rx_pkt_info rx_info;
- struct sk_buff *skb;
+ enum dma_data_direction dma_dir;
+ struct bpf_prog *xdp_prog;
+ struct sk_buff *skb = NULL;
+ u16 xdp_xmit = 0;
+ u32 xdp_act = 0;
int done = 0;
+ rcu_read_lock();
+ xdp_prog = READ_ONCE(priv->xdp_prog);
+ dma_dir = page_pool_get_dma_dir(dring->page_pool);
+
while (done < budget) {
u16 idx = dring->tail;
struct netsec_de *de = dring->vaddr + (DESC_SZ * idx);
struct netsec_desc *desc = &dring->desc[idx];
+ struct page *page = virt_to_page(desc->addr);
+ u32 xdp_result = XDP_PASS;
u16 pkt_len, desc_len;
dma_addr_t dma_handle;
+ struct xdp_buff xdp;
void *buf_addr;
- u32 truesize;
if (de->attr & (1U << NETSEC_RX_PKT_OWN_FIELD)) {
/* reading the register clears the irq */
@@ -766,53 +986,71 @@ static int netsec_process_rx(struct netsec_priv *priv, int budget)
/* allocate a fresh buffer and map it to the hardware.
* This will eventually replace the old buffer in the hardware
*/
- buf_addr = netsec_alloc_rx_data(priv, &dma_handle, &desc_len,
- true);
+ buf_addr = netsec_alloc_rx_data(priv, &dma_handle, &desc_len);
+
if (unlikely(!buf_addr))
break;
dma_sync_single_for_cpu(priv->dev, desc->dma_addr, pkt_len,
- DMA_FROM_DEVICE);
+ dma_dir);
prefetch(desc->addr);
- truesize = SKB_DATA_ALIGN(desc->len + NETSEC_SKB_PAD) +
- SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
- skb = build_skb(desc->addr, truesize);
+ xdp.data_hard_start = desc->addr;
+ xdp.data = desc->addr + NETSEC_RXBUF_HEADROOM;
+ xdp_set_data_meta_invalid(&xdp);
+ xdp.data_end = xdp.data + pkt_len;
+ xdp.rxq = &dring->xdp_rxq;
+
+ if (xdp_prog) {
+ xdp_result = netsec_run_xdp(priv, xdp_prog, &xdp);
+ if (xdp_result != NETSEC_XDP_PASS) {
+ xdp_act |= xdp_result;
+ if (xdp_result == NETSEC_XDP_TX)
+ xdp_xmit++;
+ goto next;
+ }
+ }
+ skb = build_skb(desc->addr, desc->len + NETSEC_RX_BUF_NON_DATA);
+
if (unlikely(!skb)) {
- /* free the newly allocated buffer, we are not going to
- * use it
+ /* If skb fails recycle_direct will either unmap and
+ * free the page or refill the cache depending on the
+ * cache state. Since we paid the allocation cost if
+ * building an skb fails try to put the page into cache
*/
- dma_unmap_single(priv->dev, dma_handle, desc_len,
- DMA_FROM_DEVICE);
- skb_free_frag(buf_addr);
+ page_pool_recycle_direct(dring->page_pool, page);
netif_err(priv, drv, priv->ndev,
"rx failed to build skb\n");
break;
}
- dma_unmap_single_attrs(priv->dev, desc->dma_addr, desc->len,
- DMA_FROM_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
-
- /* Update the descriptor with the new buffer we allocated */
- desc->len = desc_len;
- desc->dma_addr = dma_handle;
- desc->addr = buf_addr;
+ page_pool_release_page(dring->page_pool, page);
- skb_reserve(skb, NETSEC_SKB_PAD);
- skb_put(skb, pkt_len);
+ skb_reserve(skb, xdp.data - xdp.data_hard_start);
+ skb_put(skb, xdp.data_end - xdp.data);
skb->protocol = eth_type_trans(skb, priv->ndev);
if (priv->rx_cksum_offload_flag &&
rx_info.rx_cksum_result == NETSEC_RX_CKSUM_OK)
skb->ip_summed = CHECKSUM_UNNECESSARY;
- if (napi_gro_receive(&priv->napi, skb) != GRO_DROP) {
+next:
+ if ((skb && napi_gro_receive(&priv->napi, skb) != GRO_DROP) ||
+ xdp_result & NETSEC_XDP_RX_OK) {
ndev->stats.rx_packets++;
- ndev->stats.rx_bytes += pkt_len;
+ ndev->stats.rx_bytes += xdp.data_end - xdp.data;
}
+ /* Update the descriptor with fresh buffers */
+ desc->len = desc_len;
+ desc->dma_addr = dma_handle;
+ desc->addr = buf_addr;
+
netsec_rx_fill(priv, idx, 1);
dring->tail = (dring->tail + 1) % DESC_NUM;
}
+ netsec_finalize_xdp_rx(priv, xdp_act, xdp_xmit);
+
+ rcu_read_unlock();
return done;
}
@@ -820,19 +1058,12 @@ static int netsec_process_rx(struct netsec_priv *priv, int budget)
static int netsec_napi_poll(struct napi_struct *napi, int budget)
{
struct netsec_priv *priv;
- int rx, done, todo;
+ int done;
priv = container_of(napi, struct netsec_priv, napi);
netsec_process_tx(priv);
-
- todo = budget;
- do {
- rx = netsec_process_rx(priv, todo);
- todo -= rx;
- } while (rx);
-
- done = budget - todo;
+ done = netsec_process_rx(priv, budget);
if (done < budget && napi_complete_done(napi, done)) {
unsigned long flags;
@@ -846,41 +1077,6 @@ static int netsec_napi_poll(struct napi_struct *napi, int budget)
return done;
}
-static void netsec_set_tx_de(struct netsec_priv *priv,
- struct netsec_desc_ring *dring,
- const struct netsec_tx_pkt_ctrl *tx_ctrl,
- const struct netsec_desc *desc,
- struct sk_buff *skb)
-{
- int idx = dring->head;
- struct netsec_de *de;
- u32 attr;
-
- de = dring->vaddr + (DESC_SZ * idx);
-
- attr = (1 << NETSEC_TX_SHIFT_OWN_FIELD) |
- (1 << NETSEC_TX_SHIFT_PT_FIELD) |
- (NETSEC_RING_GMAC << NETSEC_TX_SHIFT_TDRID_FIELD) |
- (1 << NETSEC_TX_SHIFT_FS_FIELD) |
- (1 << NETSEC_TX_LAST) |
- (tx_ctrl->cksum_offload_flag << NETSEC_TX_SHIFT_CO) |
- (tx_ctrl->tcp_seg_offload_flag << NETSEC_TX_SHIFT_SO) |
- (1 << NETSEC_TX_SHIFT_TRS_FIELD);
- if (idx == DESC_NUM - 1)
- attr |= (1 << NETSEC_TX_SHIFT_LD_FIELD);
-
- de->data_buf_addr_up = upper_32_bits(desc->dma_addr);
- de->data_buf_addr_lw = lower_32_bits(desc->dma_addr);
- de->buf_len_info = (tx_ctrl->tcp_seg_len << 16) | desc->len;
- de->attr = attr;
- dma_wmb();
-
- dring->desc[idx] = *desc;
- dring->desc[idx].skb = skb;
-
- /* move head ahead */
- dring->head = (dring->head + 1) % DESC_NUM;
-}
static int netsec_desc_used(struct netsec_desc_ring *dring)
{
@@ -927,8 +1123,12 @@ static netdev_tx_t netsec_netdev_start_xmit(struct sk_buff *skb,
u16 tso_seg_len = 0;
int filled;
+ if (dring->is_xdp)
+ spin_lock_bh(&dring->lock);
filled = netsec_desc_used(dring);
if (netsec_check_stop_tx(priv, filled)) {
+ if (dring->is_xdp)
+ spin_unlock_bh(&dring->lock);
net_warn_ratelimited("%s %s Tx queue full\n",
dev_name(priv->dev), ndev->name);
return NETDEV_TX_BUSY;
@@ -961,6 +1161,8 @@ static netdev_tx_t netsec_netdev_start_xmit(struct sk_buff *skb,
tx_desc.dma_addr = dma_map_single(priv->dev, skb->data,
skb_headlen(skb), DMA_TO_DEVICE);
if (dma_mapping_error(priv->dev, tx_desc.dma_addr)) {
+ if (dring->is_xdp)
+ spin_unlock_bh(&dring->lock);
netif_err(priv, drv, priv->ndev,
"%s: DMA mapping failed\n", __func__);
ndev->stats.tx_dropped++;
@@ -969,11 +1171,14 @@ static netdev_tx_t netsec_netdev_start_xmit(struct sk_buff *skb,
}
tx_desc.addr = skb->data;
tx_desc.len = skb_headlen(skb);
+ tx_desc.buf_type = TYPE_NETSEC_SKB;
skb_tx_timestamp(skb);
netdev_sent_queue(priv->ndev, skb->len);
netsec_set_tx_de(priv, dring, &tx_ctrl, &tx_desc, skb);
+ if (dring->is_xdp)
+ spin_unlock_bh(&dring->lock);
netsec_write(priv, NETSEC_REG_NRM_TX_PKTCNT, 1); /* submit another tx */
return NETDEV_TX_OK;
@@ -987,19 +1192,27 @@ static void netsec_uninit_pkt_dring(struct netsec_priv *priv, int id)
if (!dring->vaddr || !dring->desc)
return;
-
for (idx = 0; idx < DESC_NUM; idx++) {
desc = &dring->desc[idx];
if (!desc->addr)
continue;
- dma_unmap_single(priv->dev, desc->dma_addr, desc->len,
- id == NETSEC_RING_RX ? DMA_FROM_DEVICE :
- DMA_TO_DEVICE);
- if (id == NETSEC_RING_RX)
- skb_free_frag(desc->addr);
- else if (id == NETSEC_RING_TX)
+ if (id == NETSEC_RING_RX) {
+ struct page *page = virt_to_page(desc->addr);
+
+ page_pool_put_page(dring->page_pool, page, false);
+ } else if (id == NETSEC_RING_TX) {
+ dma_unmap_single(priv->dev, desc->dma_addr, desc->len,
+ DMA_TO_DEVICE);
dev_kfree_skb(desc->skb);
+ }
+ }
+
+ /* Rx is currently using page_pool */
+ if (id == NETSEC_RING_RX) {
+ if (xdp_rxq_info_is_reg(&dring->xdp_rxq))
+ xdp_rxq_info_unreg(&dring->xdp_rxq);
+ page_pool_destroy(dring->page_pool);
}
memset(dring->desc, 0, sizeof(struct netsec_desc) * DESC_NUM);
@@ -1029,7 +1242,6 @@ static void netsec_free_dring(struct netsec_priv *priv, int id)
static int netsec_alloc_dring(struct netsec_priv *priv, enum ring_id id)
{
struct netsec_desc_ring *dring = &priv->desc_ring[id];
- int i;
dring->vaddr = dma_alloc_coherent(priv->dev, DESC_SZ * DESC_NUM,
&dring->desc_dma, GFP_KERNEL);
@@ -1040,19 +1252,6 @@ static int netsec_alloc_dring(struct netsec_priv *priv, enum ring_id id)
if (!dring->desc)
goto err;
- if (id == NETSEC_RING_TX) {
- for (i = 0; i < DESC_NUM; i++) {
- struct netsec_de *de;
-
- de = dring->vaddr + (DESC_SZ * i);
- /* de->attr is not going to be accessed by the NIC
- * until netsec_set_tx_de() is called.
- * No need for a dma_wmb() here
- */
- de->attr = 1U << NETSEC_TX_SHIFT_OWN_FIELD;
- }
- }
-
return 0;
err:
netsec_free_dring(priv, id);
@@ -1060,10 +1259,60 @@ err:
return -ENOMEM;
}
+static void netsec_setup_tx_dring(struct netsec_priv *priv)
+{
+ struct netsec_desc_ring *dring = &priv->desc_ring[NETSEC_RING_TX];
+ struct bpf_prog *xdp_prog = READ_ONCE(priv->xdp_prog);
+ int i;
+
+ for (i = 0; i < DESC_NUM; i++) {
+ struct netsec_de *de;
+
+ de = dring->vaddr + (DESC_SZ * i);
+ /* de->attr is not going to be accessed by the NIC
+ * until netsec_set_tx_de() is called.
+ * No need for a dma_wmb() here
+ */
+ de->attr = 1U << NETSEC_TX_SHIFT_OWN_FIELD;
+ }
+
+ if (xdp_prog)
+ dring->is_xdp = true;
+ else
+ dring->is_xdp = false;
+
+}
+
static int netsec_setup_rx_dring(struct netsec_priv *priv)
{
struct netsec_desc_ring *dring = &priv->desc_ring[NETSEC_RING_RX];
- int i;
+ struct bpf_prog *xdp_prog = READ_ONCE(priv->xdp_prog);
+ struct page_pool_params pp_params = { 0 };
+ int i, err;
+
+ pp_params.order = 0;
+ /* internal DMA mapping in page_pool */
+ pp_params.flags = PP_FLAG_DMA_MAP;
+ pp_params.pool_size = DESC_NUM;
+ pp_params.nid = cpu_to_node(0);
+ pp_params.dev = priv->dev;
+ pp_params.dma_dir = xdp_prog ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE;
+
+ dring->page_pool = page_pool_create(&pp_params);
+ if (IS_ERR(dring->page_pool)) {
+ err = PTR_ERR(dring->page_pool);
+ dring->page_pool = NULL;
+ goto err_out;
+ }
+
+ err = xdp_rxq_info_reg(&dring->xdp_rxq, priv->ndev, 0);
+ if (err)
+ goto err_out;
+
+ err = xdp_rxq_info_reg_mem_model(&dring->xdp_rxq, MEM_TYPE_PAGE_POOL,
+ dring->page_pool);
+ if (err)
+ goto err_out;
for (i = 0; i < DESC_NUM; i++) {
struct netsec_desc *desc = &dring->desc[i];
@@ -1071,10 +1320,10 @@ static int netsec_setup_rx_dring(struct netsec_priv *priv)
void *buf;
u16 len;
- buf = netsec_alloc_rx_data(priv, &dma_handle, &len,
- false);
+ buf = netsec_alloc_rx_data(priv, &dma_handle, &len);
+
if (!buf) {
- netsec_uninit_pkt_dring(priv, NETSEC_RING_RX);
+ err = -ENOMEM;
goto err_out;
}
desc->dma_addr = dma_handle;
@@ -1087,7 +1336,8 @@ static int netsec_setup_rx_dring(struct netsec_priv *priv)
return 0;
err_out:
- return -ENOMEM;
+ netsec_uninit_pkt_dring(priv, NETSEC_RING_RX);
+ return err;
}
static int netsec_netdev_load_ucode_region(struct netsec_priv *priv, u32 reg,
@@ -1361,6 +1611,7 @@ static int netsec_netdev_open(struct net_device *ndev)
pm_runtime_get_sync(priv->dev);
+ netsec_setup_tx_dring(priv);
ret = netsec_setup_rx_dring(priv);
if (ret) {
netif_err(priv, probe, priv->ndev,
@@ -1466,6 +1717,9 @@ static int netsec_netdev_init(struct net_device *ndev)
if (ret)
goto err2;
+ spin_lock_init(&priv->desc_ring[NETSEC_RING_TX].lock);
+ spin_lock_init(&priv->desc_ring[NETSEC_RING_RX].lock);
+
return 0;
err2:
netsec_free_dring(priv, NETSEC_RING_RX);
@@ -1498,6 +1752,81 @@ static int netsec_netdev_ioctl(struct net_device *ndev, struct ifreq *ifr,
return phy_mii_ioctl(ndev->phydev, ifr, cmd);
}
+static int netsec_xdp_xmit(struct net_device *ndev, int n,
+ struct xdp_frame **frames, u32 flags)
+{
+ struct netsec_priv *priv = netdev_priv(ndev);
+ struct netsec_desc_ring *tx_ring = &priv->desc_ring[NETSEC_RING_TX];
+ int drops = 0;
+ int i;
+
+ if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK))
+ return -EINVAL;
+
+ spin_lock(&tx_ring->lock);
+ for (i = 0; i < n; i++) {
+ struct xdp_frame *xdpf = frames[i];
+ int err;
+
+ err = netsec_xdp_queue_one(priv, xdpf, true);
+ if (err != NETSEC_XDP_TX) {
+ xdp_return_frame_rx_napi(xdpf);
+ drops++;
+ } else {
+ tx_ring->xdp_xmit++;
+ }
+ }
+ spin_unlock(&tx_ring->lock);
+
+ if (unlikely(flags & XDP_XMIT_FLUSH)) {
+ netsec_xdp_ring_tx_db(priv, tx_ring->xdp_xmit);
+ tx_ring->xdp_xmit = 0;
+ }
+
+ return n - drops;
+}
+
+static int netsec_xdp_setup(struct netsec_priv *priv, struct bpf_prog *prog,
+ struct netlink_ext_ack *extack)
+{
+ struct net_device *dev = priv->ndev;
+ struct bpf_prog *old_prog;
+
+ /* For now just support only the usual MTU sized frames */
+ if (prog && dev->mtu > 1500) {
+ NL_SET_ERR_MSG_MOD(extack, "Jumbo frames not supported on XDP");
+ return -EOPNOTSUPP;
+ }
+
+ if (netif_running(dev))
+ netsec_netdev_stop(dev);
+
+ /* Detach old prog, if any */
+ old_prog = xchg(&priv->xdp_prog, prog);
+ if (old_prog)
+ bpf_prog_put(old_prog);
+
+ if (netif_running(dev))
+ netsec_netdev_open(dev);
+
+ return 0;
+}
+
+static int netsec_xdp(struct net_device *ndev, struct netdev_bpf *xdp)
+{
+ struct netsec_priv *priv = netdev_priv(ndev);
+
+ switch (xdp->command) {
+ case XDP_SETUP_PROG:
+ return netsec_xdp_setup(priv, xdp->prog, xdp->extack);
+ case XDP_QUERY_PROG:
+ xdp->prog_id = priv->xdp_prog ? priv->xdp_prog->aux->id : 0;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
static const struct net_device_ops netsec_netdev_ops = {
.ndo_init = netsec_netdev_init,
.ndo_uninit = netsec_netdev_uninit,
@@ -1508,6 +1837,8 @@ static const struct net_device_ops netsec_netdev_ops = {
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
.ndo_do_ioctl = netsec_netdev_ioctl,
+ .ndo_xdp_xmit = netsec_xdp_xmit,
+ .ndo_bpf = netsec_xdp,
};
static int netsec_of_probe(struct platform_device *pdev,
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index 06545d7399fc..2325b40dff6e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -1,9 +1,10 @@
# SPDX-License-Identifier: GPL-2.0-only
config STMMAC_ETH
- tristate "STMicroelectronics 10/100/1000/EQOS Ethernet driver"
+ tristate "STMicroelectronics Multi-Gigabit Ethernet driver"
depends on HAS_IOMEM && HAS_DMA
select MII
- select PHYLIB
+ select PAGE_POOL
+ select PHYLINK
select CRC32
imply PTP_1588_CLOCK
select RESET_CONTROLLER
@@ -13,6 +14,16 @@ config STMMAC_ETH
if STMMAC_ETH
+config STMMAC_SELFTESTS
+ bool "Support for STMMAC Selftests"
+ depends on INET
+ depends on STMMAC_ETH
+ default n
+ ---help---
+ This adds support for STMMAC Selftests using ethtool. Enable this
+ feature if you are facing problems with your HW and submit the test
+ results to the netdev Mailing List.
+
config STMMAC_PLATFORM
tristate "STMMAC Platform bus support"
depends on STMMAC_ETH
@@ -31,7 +42,6 @@ if STMMAC_PLATFORM
config DWMAC_DWC_QOS_ETH
tristate "Support for snps,dwc-qos-ethernet.txt DT binding."
- select PHYLIB
select CRC32
select MII
depends on OF && HAS_DMA
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index c529c21e9bdd..c59926d96bcc 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -8,6 +8,8 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \
stmmac_tc.o dwxgmac2_core.o dwxgmac2_dma.o dwxgmac2_descs.o \
$(stmmac-y)
+stmmac-$(CONFIG_STMMAC_SELFTESTS) += stmmac_selftests.o
+
# Ordering matters. Generic driver must be last.
obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o
obj-$(CONFIG_DWMAC_ANARION) += dwmac-anarion.o
diff --git a/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c b/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c
index 8b50afcdb52d..cd478d2cd871 100644
--- a/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c
+++ b/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* Copyright Altera Corporation (C) 2016. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
* Author: Tien Hock Loh <thloh@altera.com>
*/
diff --git a/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.h b/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.h
index 2f5882450b06..442812c0a4bd 100644
--- a/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.h
+++ b/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.h
@@ -1,17 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright Altera Corporation (C) 2016. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
* Author: Tien Hock Loh <thloh@altera.com>
*/
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index ceb0d23f5041..ed872eed1cab 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -246,12 +246,13 @@ struct stmmac_safety_stats {
/* Max/Min RI Watchdog Timer count value */
#define MAX_DMA_RIWT 0xff
-#define MIN_DMA_RIWT 0x20
+#define MIN_DMA_RIWT 0x10
/* Tx coalesce parameters */
#define STMMAC_COAL_TX_TIMER 1000
#define STMMAC_MAX_COAL_TX_TICK 100000
#define STMMAC_TX_MAX_FRAMES 256
-#define STMMAC_TX_FRAMES 25
+#define STMMAC_TX_FRAMES 1
+#define STMMAC_RX_FRAMES 25
/* Packets types */
enum packets_types {
@@ -325,6 +326,7 @@ struct dma_features {
/* 802.3az - Energy-Efficient Ethernet (EEE) */
unsigned int eee;
unsigned int av;
+ unsigned int hash_tb_sz;
unsigned int tsoen;
/* TX and RX csum */
unsigned int tx_coe;
@@ -351,6 +353,7 @@ struct dma_features {
unsigned int frpsel;
unsigned int frpbs;
unsigned int frpes;
+ unsigned int addr64;
};
/* GMAC TX FIFO is 8K, Rx FIFO is 16K */
@@ -392,8 +395,12 @@ struct mac_link {
u32 speed100;
u32 speed1000;
u32 speed2500;
- u32 speed10000;
u32 duplex;
+ struct {
+ u32 speed2500;
+ u32 speed5000;
+ u32 speed10000;
+ } xgmii;
};
struct mii_regs {
@@ -414,12 +421,13 @@ struct mac_device_info {
const struct stmmac_mode_ops *mode;
const struct stmmac_hwtimestamp *ptp;
const struct stmmac_tc_ops *tc;
+ const struct stmmac_mmc_ops *mmc;
struct mii_regs mii; /* MII register Addresses */
struct mac_link link;
void __iomem *pcsr; /* vpointer to device CSRs */
- int multicast_filter_bins;
- int unicast_filter_entries;
- int mcast_bits_log2;
+ unsigned int multicast_filter_bins;
+ unsigned int unicast_filter_entries;
+ unsigned int mcast_bits_log2;
unsigned int rx_csum;
unsigned int pcs;
unsigned int pmt;
diff --git a/drivers/net/ethernet/stmicro/stmmac/descs.h b/drivers/net/ethernet/stmicro/stmmac/descs.h
index 10429b05f932..9f0b9a9e63b3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/descs.h
+++ b/drivers/net/ethernet/stmicro/stmmac/descs.h
@@ -123,7 +123,7 @@
#define ETDES1_BUFFER2_SIZE_SHIFT 16
/* Extended Receive descriptor definitions */
-#define ERDES4_IP_PAYLOAD_TYPE_MASK GENMASK(2, 6)
+#define ERDES4_IP_PAYLOAD_TYPE_MASK GENMASK(6, 2)
#define ERDES4_IP_HDR_ERR BIT(3)
#define ERDES4_IP_PAYLOAD_ERR BIT(4)
#define ERDES4_IP_CSUM_BYPASSED BIT(5)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
index 126b66bb73a6..79f2ee37afed 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
@@ -9,6 +9,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_net.h>
+#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/stmmac.h>
@@ -298,6 +299,9 @@ static int mediatek_dwmac_init(struct platform_device *pdev, void *priv)
return ret;
}
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
+
return 0;
}
@@ -307,6 +311,9 @@ static void mediatek_dwmac_exit(struct platform_device *pdev, void *priv)
const struct mediatek_dwmac_variant *variant = plat->variant;
clk_bulk_disable_unprepare(variant->num_clks, plat->clks);
+
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
}
static int mediatek_dwmac_probe(struct platform_device *pdev)
@@ -349,6 +356,7 @@ static int mediatek_dwmac_probe(struct platform_device *pdev)
plat_dat->has_gmac4 = 1;
plat_dat->has_gmac = 0;
plat_dat->pmt = 0;
+ plat_dat->riwt_off = 1;
plat_dat->maxmtu = ETH_DATA_LEN;
plat_dat->bsp_priv = priv_plat;
plat_dat->init = mediatek_dwmac_init;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
index d466e33635b0..c141fe783e87 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* Copyright Altera Corporation (C) 2014. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
* Adopted from dwmac-sti.c
*/
@@ -38,9 +27,12 @@
#define SYSMGR_EMACGRP_CTRL_PHYSEL_WIDTH 2
#define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK 0x00000003
#define SYSMGR_EMACGRP_CTRL_PTP_REF_CLK_MASK 0x00000010
+#define SYSMGR_GEN10_EMACGRP_CTRL_PTP_REF_CLK_MASK 0x00000100
#define SYSMGR_FPGAGRP_MODULE_REG 0x00000028
#define SYSMGR_FPGAGRP_MODULE_EMAC 0x00000004
+#define SYSMGR_FPGAINTF_EMAC_REG 0x00000070
+#define SYSMGR_FPGAINTF_EMAC_BIT 0x1
#define EMAC_SPLITTER_CTRL_REG 0x0
#define EMAC_SPLITTER_CTRL_SPEED_MASK 0x3
@@ -48,6 +40,11 @@
#define EMAC_SPLITTER_CTRL_SPEED_100 0x3
#define EMAC_SPLITTER_CTRL_SPEED_1000 0x0
+struct socfpga_dwmac;
+struct socfpga_dwmac_ops {
+ int (*set_phy_mode)(struct socfpga_dwmac *dwmac_priv);
+};
+
struct socfpga_dwmac {
int interface;
u32 reg_offset;
@@ -59,6 +56,7 @@ struct socfpga_dwmac {
void __iomem *splitter_base;
bool f2h_ptp_ref_clk;
struct tse_pcs pcs;
+ const struct socfpga_dwmac_ops *ops;
};
static void socfpga_dwmac_fix_mac_speed(void *priv, unsigned int speed)
@@ -233,25 +231,36 @@ err_node_put:
return ret;
}
-static int socfpga_dwmac_set_phy_mode(struct socfpga_dwmac *dwmac)
+static int socfpga_set_phy_mode_common(int phymode, u32 *val)
{
- struct regmap *sys_mgr_base_addr = dwmac->sys_mgr_base_addr;
- int phymode = dwmac->interface;
- u32 reg_offset = dwmac->reg_offset;
- u32 reg_shift = dwmac->reg_shift;
- u32 ctrl, val, module;
-
switch (phymode) {
case PHY_INTERFACE_MODE_RGMII:
case PHY_INTERFACE_MODE_RGMII_ID:
- val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII;
+ *val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII;
break;
case PHY_INTERFACE_MODE_MII:
case PHY_INTERFACE_MODE_GMII:
case PHY_INTERFACE_MODE_SGMII:
- val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII;
+ *val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII;
+ break;
+ case PHY_INTERFACE_MODE_RMII:
+ *val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII;
break;
default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int socfpga_gen5_set_phy_mode(struct socfpga_dwmac *dwmac)
+{
+ struct regmap *sys_mgr_base_addr = dwmac->sys_mgr_base_addr;
+ int phymode = dwmac->interface;
+ u32 reg_offset = dwmac->reg_offset;
+ u32 reg_shift = dwmac->reg_shift;
+ u32 ctrl, val, module;
+
+ if (socfpga_set_phy_mode_common(phymode, &val)) {
dev_err(dwmac->dev, "bad phy mode %d\n", phymode);
return -EINVAL;
}
@@ -302,6 +311,62 @@ static int socfpga_dwmac_set_phy_mode(struct socfpga_dwmac *dwmac)
return 0;
}
+static int socfpga_gen10_set_phy_mode(struct socfpga_dwmac *dwmac)
+{
+ struct regmap *sys_mgr_base_addr = dwmac->sys_mgr_base_addr;
+ int phymode = dwmac->interface;
+ u32 reg_offset = dwmac->reg_offset;
+ u32 reg_shift = dwmac->reg_shift;
+ u32 ctrl, val, module;
+
+ if (socfpga_set_phy_mode_common(phymode, &val))
+ return -EINVAL;
+
+ /* Overwrite val to GMII if splitter core is enabled. The phymode here
+ * is the actual phy mode on phy hardware, but phy interface from
+ * EMAC core is GMII.
+ */
+ if (dwmac->splitter_base)
+ val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII;
+
+ /* Assert reset to the enet controller before changing the phy mode */
+ reset_control_assert(dwmac->stmmac_ocp_rst);
+ reset_control_assert(dwmac->stmmac_rst);
+
+ regmap_read(sys_mgr_base_addr, reg_offset, &ctrl);
+ ctrl &= ~(SYSMGR_EMACGRP_CTRL_PHYSEL_MASK);
+ ctrl |= val;
+
+ if (dwmac->f2h_ptp_ref_clk ||
+ phymode == PHY_INTERFACE_MODE_MII ||
+ phymode == PHY_INTERFACE_MODE_GMII ||
+ phymode == PHY_INTERFACE_MODE_SGMII) {
+ ctrl |= SYSMGR_GEN10_EMACGRP_CTRL_PTP_REF_CLK_MASK;
+ regmap_read(sys_mgr_base_addr, SYSMGR_FPGAINTF_EMAC_REG,
+ &module);
+ module |= (SYSMGR_FPGAINTF_EMAC_BIT << reg_shift);
+ regmap_write(sys_mgr_base_addr, SYSMGR_FPGAINTF_EMAC_REG,
+ module);
+ } else {
+ ctrl &= ~SYSMGR_GEN10_EMACGRP_CTRL_PTP_REF_CLK_MASK;
+ }
+
+ regmap_write(sys_mgr_base_addr, reg_offset, ctrl);
+
+ /* Deassert reset for the phy configuration to be sampled by
+ * the enet controller, and operation to start in requested mode
+ */
+ reset_control_deassert(dwmac->stmmac_ocp_rst);
+ reset_control_deassert(dwmac->stmmac_rst);
+ if (phymode == PHY_INTERFACE_MODE_SGMII) {
+ if (tse_pcs_init(dwmac->pcs.tse_pcs_base, &dwmac->pcs) != 0) {
+ dev_err(dwmac->dev, "Unable to initialize TSE PCS");
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
static int socfpga_dwmac_probe(struct platform_device *pdev)
{
struct plat_stmmacenet_data *plat_dat;
@@ -311,6 +376,13 @@ static int socfpga_dwmac_probe(struct platform_device *pdev)
struct socfpga_dwmac *dwmac;
struct net_device *ndev;
struct stmmac_priv *stpriv;
+ const struct socfpga_dwmac_ops *ops;
+
+ ops = device_get_match_data(&pdev->dev);
+ if (!ops) {
+ dev_err(&pdev->dev, "no of match data provided\n");
+ return -EINVAL;
+ }
ret = stmmac_get_platform_resources(pdev, &stmmac_res);
if (ret)
@@ -341,6 +413,7 @@ static int socfpga_dwmac_probe(struct platform_device *pdev)
goto err_remove_config_dt;
}
+ dwmac->ops = ops;
plat_dat->bsp_priv = dwmac;
plat_dat->fix_mac_speed = socfpga_dwmac_fix_mac_speed;
@@ -357,7 +430,7 @@ static int socfpga_dwmac_probe(struct platform_device *pdev)
*/
dwmac->stmmac_rst = stpriv->plat->stmmac_rst;
- ret = socfpga_dwmac_set_phy_mode(dwmac);
+ ret = ops->set_phy_mode(dwmac);
if (ret)
goto err_dvr_remove;
@@ -376,8 +449,9 @@ static int socfpga_dwmac_resume(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
struct stmmac_priv *priv = netdev_priv(ndev);
+ struct socfpga_dwmac *dwmac_priv = get_stmmac_bsp_priv(dev);
- socfpga_dwmac_set_phy_mode(priv->plat->bsp_priv);
+ dwmac_priv->ops->set_phy_mode(priv->plat->bsp_priv);
/* Before the enet controller is suspended, the phy is suspended.
* This causes the phy clock to be gated. The enet controller is
@@ -404,8 +478,17 @@ static int socfpga_dwmac_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(socfpga_dwmac_pm_ops, stmmac_suspend,
socfpga_dwmac_resume);
+static const struct socfpga_dwmac_ops socfpga_gen5_ops = {
+ .set_phy_mode = socfpga_gen5_set_phy_mode,
+};
+
+static const struct socfpga_dwmac_ops socfpga_gen10_ops = {
+ .set_phy_mode = socfpga_gen10_set_phy_mode,
+};
+
static const struct of_device_id socfpga_dwmac_match[] = {
- { .compatible = "altr,socfpga-stmmac" },
+ { .compatible = "altr,socfpga-stmmac", .data = &socfpga_gen5_ops },
+ { .compatible = "altr,socfpga-stmmac-a10-s10", .data = &socfpga_gen10_ops },
{ }
};
MODULE_DEVICE_TABLE(of, socfpga_dwmac_match);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
index a69c34f605b1..4083019c547a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
@@ -138,6 +138,20 @@ static const struct emac_variant emac_variant_a64 = {
.tx_delay_max = 7,
};
+static const struct emac_variant emac_variant_h6 = {
+ .default_syscon_value = 0x50000,
+ .syscon_field = &sun8i_syscon_reg_field,
+ /* The "Internal PHY" of H6 is not on the die. It's on the
+ * co-packaged AC200 chip instead.
+ */
+ .soc_has_internal_phy = false,
+ .support_mii = true,
+ .support_rmii = true,
+ .support_rgmii = true,
+ .rx_delay_max = 31,
+ .tx_delay_max = 7,
+};
+
#define EMAC_BASIC_CTL0 0x00
#define EMAC_BASIC_CTL1 0x04
#define EMAC_INT_STA 0x08
@@ -178,7 +192,7 @@ static const struct emac_variant emac_variant_a64 = {
/* Used in RX_CTL1*/
#define EMAC_RX_MD BIT(1)
-#define EMAC_RX_TH_MASK GENMASK(4, 5)
+#define EMAC_RX_TH_MASK GENMASK(5, 4)
#define EMAC_RX_TH_32 0
#define EMAC_RX_TH_64 (0x1 << 4)
#define EMAC_RX_TH_96 (0x2 << 4)
@@ -189,7 +203,7 @@ static const struct emac_variant emac_variant_a64 = {
/* Used in TX_CTL1*/
#define EMAC_TX_MD BIT(1)
#define EMAC_TX_NEXT_FRM BIT(2)
-#define EMAC_TX_TH_MASK GENMASK(8, 10)
+#define EMAC_TX_TH_MASK GENMASK(10, 8)
#define EMAC_TX_TH_64 0
#define EMAC_TX_TH_128 (0x1 << 8)
#define EMAC_TX_TH_192 (0x2 << 8)
@@ -275,18 +289,18 @@ static void sun8i_dwmac_dma_init(void __iomem *ioaddr,
static void sun8i_dwmac_dma_init_rx(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg,
- u32 dma_rx_phy, u32 chan)
+ dma_addr_t dma_rx_phy, u32 chan)
{
/* Write RX descriptors address */
- writel(dma_rx_phy, ioaddr + EMAC_RX_DESC_LIST);
+ writel(lower_32_bits(dma_rx_phy), ioaddr + EMAC_RX_DESC_LIST);
}
static void sun8i_dwmac_dma_init_tx(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg,
- u32 dma_tx_phy, u32 chan)
+ dma_addr_t dma_tx_phy, u32 chan)
{
/* Write TX descriptors address */
- writel(dma_tx_phy, ioaddr + EMAC_TX_DESC_LIST);
+ writel(lower_32_bits(dma_tx_phy), ioaddr + EMAC_TX_DESC_LIST);
}
/* sun8i_dwmac_dump_regs() - Dump EMAC address space
@@ -884,6 +898,11 @@ static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv)
* address. No need to mask it again.
*/
reg |= 1 << H3_EPHY_ADDR_SHIFT;
+ } else {
+ /* For SoCs without internal PHY the PHY selection bit should be
+ * set to 0 (external PHY).
+ */
+ reg &= ~H3_EPHY_SELECT;
}
if (!of_property_read_u32(node, "allwinner,tx-delay-ps", &val)) {
@@ -977,6 +996,18 @@ static void sun8i_dwmac_exit(struct platform_device *pdev, void *priv)
regulator_disable(gmac->regulator);
}
+static void sun8i_dwmac_set_mac_loopback(void __iomem *ioaddr, bool enable)
+{
+ u32 value = readl(ioaddr + EMAC_BASIC_CTL0);
+
+ if (enable)
+ value |= EMAC_LOOPBACK;
+ else
+ value &= ~EMAC_LOOPBACK;
+
+ writel(value, ioaddr + EMAC_BASIC_CTL0);
+}
+
static const struct stmmac_ops sun8i_dwmac_ops = {
.core_init = sun8i_dwmac_core_init,
.set_mac = sun8i_dwmac_set_mac,
@@ -986,6 +1017,7 @@ static const struct stmmac_ops sun8i_dwmac_ops = {
.flow_ctrl = sun8i_dwmac_flow_ctrl,
.set_umac_addr = sun8i_dwmac_set_umac_addr,
.get_umac_addr = sun8i_dwmac_get_umac_addr,
+ .set_mac_loopback = sun8i_dwmac_set_mac_loopback,
};
static struct mac_device_info *sun8i_dwmac_setup(void *ppriv)
@@ -1203,6 +1235,8 @@ static const struct of_device_id sun8i_dwmac_match[] = {
.data = &emac_variant_r40 },
{ .compatible = "allwinner,sun50i-a64-emac",
.data = &emac_variant_a64 },
+ { .compatible = "allwinner,sun50i-h6-emac",
+ .data = &emac_variant_h6 },
{ }
};
MODULE_DEVICE_TABLE(of, sun8i_dwmac_match);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
index b83d3a98f5f1..b70d44ac0990 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
@@ -136,6 +136,7 @@ enum inter_frame_gap {
#define GMAC_FRAME_FILTER_DAIF 0x00000008 /* DA Inverse Filtering */
#define GMAC_FRAME_FILTER_PM 0x00000010 /* Pass all multicast */
#define GMAC_FRAME_FILTER_DBF 0x00000020 /* Disable Broadcast frames */
+#define GMAC_FRAME_FILTER_PCF 0x00000080 /* Pass Control frames */
#define GMAC_FRAME_FILTER_SAIF 0x00000100 /* Inverse Filtering */
#define GMAC_FRAME_FILTER_SAF 0x00000200 /* Source Address Filter */
#define GMAC_FRAME_FILTER_HPF 0x00000400 /* Hash or perfect Filter */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
index 9fff81170163..3d69da112625 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
@@ -162,7 +162,7 @@ static void dwmac1000_set_filter(struct mac_device_info *hw,
memset(mc_filter, 0, sizeof(mc_filter));
if (dev->flags & IFF_PROMISC) {
- value = GMAC_FRAME_FILTER_PR;
+ value = GMAC_FRAME_FILTER_PR | GMAC_FRAME_FILTER_PCF;
} else if (dev->flags & IFF_ALLMULTI) {
value = GMAC_FRAME_FILTER_PM; /* pass all multi */
} else if (!netdev_mc_empty(dev)) {
@@ -188,6 +188,7 @@ static void dwmac1000_set_filter(struct mac_device_info *hw,
}
}
+ value |= GMAC_FRAME_FILTER_HPF;
dwmac1000_set_mchash(ioaddr, mc_filter, mcbitslog2);
/* Handle multiple unicast addresses (perfect filtering) */
@@ -206,6 +207,12 @@ static void dwmac1000_set_filter(struct mac_device_info *hw,
GMAC_ADDR_LOW(reg));
reg++;
}
+
+ while (reg <= perfect_addr_number) {
+ writel(0, ioaddr + GMAC_ADDR_HIGH(reg));
+ writel(0, ioaddr + GMAC_ADDR_LOW(reg));
+ reg++;
+ }
}
#ifdef FRAME_FILTER_DEBUG
@@ -489,6 +496,18 @@ static void dwmac1000_debug(void __iomem *ioaddr, struct stmmac_extra_stats *x,
x->mac_gmii_rx_proto_engine++;
}
+static void dwmac1000_set_mac_loopback(void __iomem *ioaddr, bool enable)
+{
+ u32 value = readl(ioaddr + GMAC_CONTROL);
+
+ if (enable)
+ value |= GMAC_CONTROL_LM;
+ else
+ value &= ~GMAC_CONTROL_LM;
+
+ writel(value, ioaddr + GMAC_CONTROL);
+}
+
const struct stmmac_ops dwmac1000_ops = {
.core_init = dwmac1000_core_init,
.set_mac = stmmac_set_mac,
@@ -508,6 +527,7 @@ const struct stmmac_ops dwmac1000_ops = {
.pcs_ctrl_ane = dwmac1000_ctrl_ane,
.pcs_rane = dwmac1000_rane,
.pcs_get_adv_lp = dwmac1000_get_adv_lp,
+ .set_mac_loopback = dwmac1000_set_mac_loopback,
};
int dwmac1000_setup(struct stmmac_priv *priv)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
index 1fdedf77678f..2bac49b49f73 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
@@ -112,18 +112,18 @@ static void dwmac1000_dma_init(void __iomem *ioaddr,
static void dwmac1000_dma_init_rx(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg,
- u32 dma_rx_phy, u32 chan)
+ dma_addr_t dma_rx_phy, u32 chan)
{
/* RX descriptor base address list must be written into DMA CSR3 */
- writel(dma_rx_phy, ioaddr + DMA_RCV_BASE_ADDR);
+ writel(lower_32_bits(dma_rx_phy), ioaddr + DMA_RCV_BASE_ADDR);
}
static void dwmac1000_dma_init_tx(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg,
- u32 dma_tx_phy, u32 chan)
+ dma_addr_t dma_tx_phy, u32 chan)
{
/* TX descriptor base address list must be written into DMA CSR4 */
- writel(dma_tx_phy, ioaddr + DMA_TX_BASE_ADDR);
+ writel(lower_32_bits(dma_tx_phy), ioaddr + DMA_TX_BASE_ADDR);
}
static u32 dwmac1000_configure_fc(u32 csr6, int rxfifosz)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
index 8842f6627cb8..ebcad8dd99db 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
@@ -150,6 +150,18 @@ static void dwmac100_pmt(struct mac_device_info *hw, unsigned long mode)
return;
}
+static void dwmac100_set_mac_loopback(void __iomem *ioaddr, bool enable)
+{
+ u32 value = readl(ioaddr + MAC_CONTROL);
+
+ if (enable)
+ value |= MAC_CONTROL_OM;
+ else
+ value &= ~MAC_CONTROL_OM;
+
+ writel(value, ioaddr + MAC_CONTROL);
+}
+
const struct stmmac_ops dwmac100_ops = {
.core_init = dwmac100_core_init,
.set_mac = stmmac_set_mac,
@@ -161,6 +173,7 @@ const struct stmmac_ops dwmac100_ops = {
.pmt = dwmac100_pmt,
.set_umac_addr = dwmac100_set_umac_addr,
.get_umac_addr = dwmac100_get_umac_addr,
+ .set_mac_loopback = dwmac100_set_mac_loopback,
};
int dwmac100_setup(struct stmmac_priv *priv)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
index c980cc7360a4..8f0d9bc7cab5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
@@ -31,18 +31,18 @@ static void dwmac100_dma_init(void __iomem *ioaddr,
static void dwmac100_dma_init_rx(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg,
- u32 dma_rx_phy, u32 chan)
+ dma_addr_t dma_rx_phy, u32 chan)
{
/* RX descriptor base addr lists must be written into DMA CSR3 */
- writel(dma_rx_phy, ioaddr + DMA_RCV_BASE_ADDR);
+ writel(lower_32_bits(dma_rx_phy), ioaddr + DMA_RCV_BASE_ADDR);
}
static void dwmac100_dma_init_tx(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg,
- u32 dma_tx_phy, u32 chan)
+ dma_addr_t dma_tx_phy, u32 chan)
{
/* TX descriptor base addr lists must be written into DMA CSR4 */
- writel(dma_tx_phy, ioaddr + DMA_TX_BASE_ADDR);
+ writel(lower_32_bits(dma_tx_phy), ioaddr + DMA_TX_BASE_ADDR);
}
/* Store and Forward capability is not used at all.
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
index 80234f12bf7f..2ed11a581d80 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
@@ -15,8 +15,7 @@
/* MAC registers */
#define GMAC_CONFIG 0x00000000
#define GMAC_PACKET_FILTER 0x00000008
-#define GMAC_HASH_TAB_0_31 0x00000010
-#define GMAC_HASH_TAB_32_63 0x00000014
+#define GMAC_HASH_TAB(x) (0x10 + (x) * 4)
#define GMAC_RX_FLOW_CTRL 0x00000090
#define GMAC_QX_TX_FLOW_CTRL(x) (0x70 + x * 4)
#define GMAC_TXQ_PRTY_MAP0 0x98
@@ -61,6 +60,8 @@
#define GMAC_PACKET_FILTER_PR BIT(0)
#define GMAC_PACKET_FILTER_HMC BIT(2)
#define GMAC_PACKET_FILTER_PM BIT(4)
+#define GMAC_PACKET_FILTER_PCF BIT(7)
+#define GMAC_PACKET_FILTER_HPF BIT(10)
#define GMAC_MAX_PERFECT_ADDRESSES 128
@@ -157,6 +158,7 @@ enum power_event {
#define GMAC_CONFIG_PS BIT(15)
#define GMAC_CONFIG_FES BIT(14)
#define GMAC_CONFIG_DM BIT(13)
+#define GMAC_CONFIG_LM BIT(12)
#define GMAC_CONFIG_DCRS BIT(9)
#define GMAC_CONFIG_TE BIT(1)
#define GMAC_CONFIG_RE BIT(0)
@@ -178,6 +180,7 @@ enum power_event {
#define GMAC_HW_FEAT_MIISEL BIT(0)
/* MAC HW features1 bitmap */
+#define GMAC_HW_HASH_TB_SZ GENMASK(25, 24)
#define GMAC_HW_FEAT_AVSEL BIT(20)
#define GMAC_HW_TSOEN BIT(18)
#define GMAC_HW_TXFIFOSIZE GENMASK(10, 6)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
index 99d772517242..01c2e2d83e76 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -400,57 +400,74 @@ static void dwmac4_set_filter(struct mac_device_info *hw,
struct net_device *dev)
{
void __iomem *ioaddr = (void __iomem *)dev->base_addr;
- unsigned int value = 0;
+ int numhashregs = (hw->multicast_filter_bins >> 5);
+ int mcbitslog2 = hw->mcast_bits_log2;
+ unsigned int value;
+ int i;
+ value = readl(ioaddr + GMAC_PACKET_FILTER);
+ value &= ~GMAC_PACKET_FILTER_HMC;
+ value &= ~GMAC_PACKET_FILTER_HPF;
+ value &= ~GMAC_PACKET_FILTER_PCF;
+ value &= ~GMAC_PACKET_FILTER_PM;
+ value &= ~GMAC_PACKET_FILTER_PR;
if (dev->flags & IFF_PROMISC) {
- value = GMAC_PACKET_FILTER_PR;
+ value = GMAC_PACKET_FILTER_PR | GMAC_PACKET_FILTER_PCF;
} else if ((dev->flags & IFF_ALLMULTI) ||
- (netdev_mc_count(dev) > HASH_TABLE_SIZE)) {
+ (netdev_mc_count(dev) > hw->multicast_filter_bins)) {
/* Pass all multi */
- value = GMAC_PACKET_FILTER_PM;
- /* Set the 64 bits of the HASH tab. To be updated if taller
- * hash table is used
- */
- writel(0xffffffff, ioaddr + GMAC_HASH_TAB_0_31);
- writel(0xffffffff, ioaddr + GMAC_HASH_TAB_32_63);
+ value |= GMAC_PACKET_FILTER_PM;
+ /* Set all the bits of the HASH tab */
+ for (i = 0; i < numhashregs; i++)
+ writel(0xffffffff, ioaddr + GMAC_HASH_TAB(i));
} else if (!netdev_mc_empty(dev)) {
- u32 mc_filter[2];
struct netdev_hw_addr *ha;
+ u32 mc_filter[8];
/* Hash filter for multicast */
- value = GMAC_PACKET_FILTER_HMC;
+ value |= GMAC_PACKET_FILTER_HMC;
memset(mc_filter, 0, sizeof(mc_filter));
netdev_for_each_mc_addr(ha, dev) {
- /* The upper 6 bits of the calculated CRC are used to
- * index the content of the Hash Table Reg 0 and 1.
+ /* The upper n bits of the calculated CRC are used to
+ * index the contents of the hash table. The number of
+ * bits used depends on the hardware configuration
+ * selected at core configuration time.
*/
- int bit_nr =
- (bitrev32(~crc32_le(~0, ha->addr, 6)) >> 26);
- /* The most significant bit determines the register
- * to use while the other 5 bits determines the bit
- * within the selected register
+ int bit_nr = bitrev32(~crc32_le(~0, ha->addr,
+ ETH_ALEN)) >> (32 - mcbitslog2);
+ /* The most significant bit determines the register to
+ * use (H/L) while the other 5 bits determine the bit
+ * within the register.
*/
- mc_filter[bit_nr >> 5] |= (1 << (bit_nr & 0x1F));
+ mc_filter[bit_nr >> 5] |= (1 << (bit_nr & 0x1f));
}
- writel(mc_filter[0], ioaddr + GMAC_HASH_TAB_0_31);
- writel(mc_filter[1], ioaddr + GMAC_HASH_TAB_32_63);
+ for (i = 0; i < numhashregs; i++)
+ writel(mc_filter[i], ioaddr + GMAC_HASH_TAB(i));
}
+ value |= GMAC_PACKET_FILTER_HPF;
+
/* Handle multiple unicast addresses */
if (netdev_uc_count(dev) > GMAC_MAX_PERFECT_ADDRESSES) {
/* Switch to promiscuous mode if more than 128 addrs
* are required
*/
value |= GMAC_PACKET_FILTER_PR;
- } else if (!netdev_uc_empty(dev)) {
- int reg = 1;
+ } else {
struct netdev_hw_addr *ha;
+ int reg = 1;
netdev_for_each_uc_addr(ha, dev) {
dwmac4_set_umac_addr(hw, ha->addr, reg);
reg++;
}
+
+ while (reg < GMAC_MAX_PERFECT_ADDRESSES) {
+ writel(0, ioaddr + GMAC_ADDR_HIGH(reg));
+ writel(0, ioaddr + GMAC_ADDR_LOW(reg));
+ reg++;
+ }
}
writel(value, ioaddr + GMAC_PACKET_FILTER);
@@ -468,8 +485,9 @@ static void dwmac4_flow_ctrl(struct mac_device_info *hw, unsigned int duplex,
if (fc & FLOW_RX) {
pr_debug("\tReceive Flow-Control ON\n");
flow |= GMAC_RX_FLOW_CTRL_RFE;
- writel(flow, ioaddr + GMAC_RX_FLOW_CTRL);
}
+ writel(flow, ioaddr + GMAC_RX_FLOW_CTRL);
+
if (fc & FLOW_TX) {
pr_debug("\tTransmit Flow-Control ON\n");
@@ -477,7 +495,7 @@ static void dwmac4_flow_ctrl(struct mac_device_info *hw, unsigned int duplex,
pr_debug("\tduplex mode: PAUSE %d\n", pause_time);
for (queue = 0; queue < tx_cnt; queue++) {
- flow |= GMAC_TX_FLOW_CTRL_TFE;
+ flow = GMAC_TX_FLOW_CTRL_TFE;
if (duplex)
flow |=
@@ -485,6 +503,9 @@ static void dwmac4_flow_ctrl(struct mac_device_info *hw, unsigned int duplex,
writel(flow, ioaddr + GMAC_QX_TX_FLOW_CTRL(queue));
}
+ } else {
+ for (queue = 0; queue < tx_cnt; queue++)
+ writel(0, ioaddr + GMAC_QX_TX_FLOW_CTRL(queue));
}
}
@@ -700,6 +721,18 @@ static void dwmac4_debug(void __iomem *ioaddr, struct stmmac_extra_stats *x,
x->mac_gmii_rx_proto_engine++;
}
+static void dwmac4_set_mac_loopback(void __iomem *ioaddr, bool enable)
+{
+ u32 value = readl(ioaddr + GMAC_CONFIG);
+
+ if (enable)
+ value |= GMAC_CONFIG_LM;
+ else
+ value &= ~GMAC_CONFIG_LM;
+
+ writel(value, ioaddr + GMAC_CONFIG);
+}
+
const struct stmmac_ops dwmac4_ops = {
.core_init = dwmac4_core_init,
.set_mac = stmmac_set_mac,
@@ -729,6 +762,7 @@ const struct stmmac_ops dwmac4_ops = {
.pcs_get_adv_lp = dwmac4_get_adv_lp,
.debug = dwmac4_debug,
.set_filter = dwmac4_set_filter,
+ .set_mac_loopback = dwmac4_set_mac_loopback,
};
const struct stmmac_ops dwmac410_ops = {
@@ -760,6 +794,7 @@ const struct stmmac_ops dwmac410_ops = {
.pcs_get_adv_lp = dwmac4_get_adv_lp,
.debug = dwmac4_debug,
.set_filter = dwmac4_set_filter,
+ .set_mac_loopback = dwmac4_set_mac_loopback,
};
const struct stmmac_ops dwmac510_ops = {
@@ -796,6 +831,7 @@ const struct stmmac_ops dwmac510_ops = {
.safety_feat_dump = dwmac5_safety_feat_dump,
.rxp_config = dwmac5_rxp_config,
.flex_pps_config = dwmac5_flex_pps_config,
+ .set_mac_loopback = dwmac4_set_mac_loopback,
};
int dwmac4_setup(struct stmmac_priv *priv)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
index cf6436d3d6c7..dbde23e7e169 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
@@ -443,6 +443,15 @@ static void dwmac4_clear(struct dma_desc *p)
p->des3 = 0;
}
+static int set_16kib_bfsize(int mtu)
+{
+ int ret = 0;
+
+ if (unlikely(mtu >= BUF_SIZE_8KiB))
+ ret = BUF_SIZE_16KiB;
+ return ret;
+}
+
const struct stmmac_desc_ops dwmac4_desc_ops = {
.tx_status = dwmac4_wrback_get_tx_status,
.rx_status = dwmac4_wrback_get_rx_status,
@@ -469,4 +478,6 @@ const struct stmmac_desc_ops dwmac4_desc_ops = {
.clear = dwmac4_clear,
};
-const struct stmmac_mode_ops dwmac4_ring_mode_ops = { };
+const struct stmmac_mode_ops dwmac4_ring_mode_ops = {
+ .set_16kib_bfsize = set_16kib_bfsize,
+};
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
index 0f208e13da9f..3ed5508586ef 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
@@ -70,7 +70,7 @@ static void dwmac4_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
static void dwmac4_dma_init_rx_chan(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg,
- u32 dma_rx_phy, u32 chan)
+ dma_addr_t dma_rx_phy, u32 chan)
{
u32 value;
u32 rxpbl = dma_cfg->rxpbl ?: dma_cfg->pbl;
@@ -79,12 +79,12 @@ static void dwmac4_dma_init_rx_chan(void __iomem *ioaddr,
value = value | (rxpbl << DMA_BUS_MODE_RPBL_SHIFT);
writel(value, ioaddr + DMA_CHAN_RX_CONTROL(chan));
- writel(dma_rx_phy, ioaddr + DMA_CHAN_RX_BASE_ADDR(chan));
+ writel(lower_32_bits(dma_rx_phy), ioaddr + DMA_CHAN_RX_BASE_ADDR(chan));
}
static void dwmac4_dma_init_tx_chan(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg,
- u32 dma_tx_phy, u32 chan)
+ dma_addr_t dma_tx_phy, u32 chan)
{
u32 value;
u32 txpbl = dma_cfg->txpbl ?: dma_cfg->pbl;
@@ -97,7 +97,7 @@ static void dwmac4_dma_init_tx_chan(void __iomem *ioaddr,
writel(value, ioaddr + DMA_CHAN_TX_CONTROL(chan));
- writel(dma_tx_phy, ioaddr + DMA_CHAN_TX_BASE_ADDR(chan));
+ writel(lower_32_bits(dma_tx_phy), ioaddr + DMA_CHAN_TX_BASE_ADDR(chan));
}
static void dwmac4_dma_init_channel(void __iomem *ioaddr,
@@ -351,6 +351,7 @@ static void dwmac4_get_hw_feature(void __iomem *ioaddr,
/* MAC HW feature1 */
hw_cap = readl(ioaddr + GMAC_HW_FEATURE1);
+ dma_cap->hash_tb_sz = (hw_cap & GMAC_HW_HASH_TB_SZ) >> 24;
dma_cap->av = (hw_cap & GMAC_HW_FEAT_AVSEL) >> 20;
dma_cap->tsoen = (hw_cap & GMAC_HW_TSOEN) >> 18;
/* RX and TX FIFO sizes are encoded as log2(n / 128). Undo that by
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
index 85826524683c..f2a29a90e085 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
@@ -85,10 +85,6 @@ void dwmac4_dma_stop_rx(void __iomem *ioaddr, u32 chan)
value &= ~DMA_CONTROL_SR;
writel(value, ioaddr + DMA_CHAN_RX_CONTROL(chan));
-
- value = readl(ioaddr + GMAC_CONFIG);
- value &= ~GMAC_CONFIG_RE;
- writel(value, ioaddr + GMAC_CONFIG);
}
void dwmac4_set_tx_ring_len(void __iomem *ioaddr, u32 len, u32 chan)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
index 085b700a4994..7f86dffb264d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
@@ -15,10 +15,14 @@
/* MAC Registers */
#define XGMAC_TX_CONFIG 0x00000000
#define XGMAC_CONFIG_SS_OFF 29
-#define XGMAC_CONFIG_SS_MASK GENMASK(30, 29)
+#define XGMAC_CONFIG_SS_MASK GENMASK(31, 29)
#define XGMAC_CONFIG_SS_10000 (0x0 << XGMAC_CONFIG_SS_OFF)
-#define XGMAC_CONFIG_SS_2500 (0x2 << XGMAC_CONFIG_SS_OFF)
-#define XGMAC_CONFIG_SS_1000 (0x3 << XGMAC_CONFIG_SS_OFF)
+#define XGMAC_CONFIG_SS_2500_GMII (0x2 << XGMAC_CONFIG_SS_OFF)
+#define XGMAC_CONFIG_SS_1000_GMII (0x3 << XGMAC_CONFIG_SS_OFF)
+#define XGMAC_CONFIG_SS_100_MII (0x4 << XGMAC_CONFIG_SS_OFF)
+#define XGMAC_CONFIG_SS_5000 (0x5 << XGMAC_CONFIG_SS_OFF)
+#define XGMAC_CONFIG_SS_2500 (0x6 << XGMAC_CONFIG_SS_OFF)
+#define XGMAC_CONFIG_SS_10_MII (0x7 << XGMAC_CONFIG_SS_OFF)
#define XGMAC_CONFIG_SARC GENMASK(22, 20)
#define XGMAC_CONFIG_SARC_SHIFT 20
#define XGMAC_CONFIG_JD BIT(16)
@@ -29,6 +33,7 @@
#define XGMAC_CONFIG_GPSL GENMASK(29, 16)
#define XGMAC_CONFIG_GPSL_SHIFT 16
#define XGMAC_CONFIG_S2KP BIT(11)
+#define XGMAC_CONFIG_LM BIT(10)
#define XGMAC_CONFIG_IPC BIT(9)
#define XGMAC_CONFIG_JE BIT(8)
#define XGMAC_CONFIG_WD BIT(7)
@@ -39,6 +44,7 @@
#define XGMAC_CORE_INIT_RX 0
#define XGMAC_PACKET_FILTER 0x00000008
#define XGMAC_FILTER_RA BIT(31)
+#define XGMAC_FILTER_PCF BIT(7)
#define XGMAC_FILTER_PM BIT(4)
#define XGMAC_FILTER_HMC BIT(2)
#define XGMAC_FILTER_PR BIT(0)
@@ -81,6 +87,7 @@
#define XGMAC_HWFEAT_GMIISEL BIT(1)
#define XGMAC_HW_FEATURE1 0x00000120
#define XGMAC_HWFEAT_TSOEN BIT(18)
+#define XGMAC_HWFEAT_ADDR64 GENMASK(15, 14)
#define XGMAC_HWFEAT_TXFIFOSIZE GENMASK(10, 6)
#define XGMAC_HWFEAT_RXFIFOSIZE GENMASK(4, 0)
#define XGMAC_HW_FEATURE2 0x00000124
@@ -166,6 +173,7 @@
#define XGMAC_EN_LPI BIT(15)
#define XGMAC_LPI_XIT_PKT BIT(14)
#define XGMAC_AAL BIT(12)
+#define XGMAC_EAME BIT(11)
#define XGMAC_BLEN GENMASK(7, 1)
#define XGMAC_BLEN256 BIT(7)
#define XGMAC_BLEN128 BIT(6)
@@ -175,6 +183,10 @@
#define XGMAC_BLEN8 BIT(2)
#define XGMAC_BLEN4 BIT(1)
#define XGMAC_UNDEF BIT(0)
+#define XGMAC_TX_EDMA_CTRL 0x00003040
+#define XGMAC_TDPS GENMASK(29, 0)
+#define XGMAC_RX_EDMA_CTRL 0x00003044
+#define XGMAC_RDPS GENMASK(29, 0)
#define XGMAC_DMA_CH_CONTROL(x) (0x00003100 + (0x80 * (x)))
#define XGMAC_PBLx8 BIT(16)
#define XGMAC_DMA_CH_TX_CONTROL(x) (0x00003104 + (0x80 * (x)))
@@ -187,7 +199,9 @@
#define XGMAC_RxPBL GENMASK(21, 16)
#define XGMAC_RxPBL_SHIFT 16
#define XGMAC_RXST BIT(0)
+#define XGMAC_DMA_CH_TxDESC_HADDR(x) (0x00003110 + (0x80 * (x)))
#define XGMAC_DMA_CH_TxDESC_LADDR(x) (0x00003114 + (0x80 * (x)))
+#define XGMAC_DMA_CH_RxDESC_HADDR(x) (0x00003118 + (0x80 * (x)))
#define XGMAC_DMA_CH_RxDESC_LADDR(x) (0x0000311c + (0x80 * (x)))
#define XGMAC_DMA_CH_TxDESC_TAIL_LPTR(x) (0x00003124 + (0x80 * (x)))
#define XGMAC_DMA_CH_RxDESC_TAIL_LPTR(x) (0x0000312c + (0x80 * (x)))
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
index 64b8cb88ea45..0a32c96a7854 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
@@ -36,7 +36,7 @@ static void dwxgmac2_core_init(struct mac_device_info *hw,
switch (hw->ps) {
case SPEED_10000:
- tx |= hw->link.speed10000;
+ tx |= hw->link.xgmii.speed10000;
break;
case SPEED_2500:
tx |= hw->link.speed2500;
@@ -310,7 +310,7 @@ static void dwxgmac2_set_filter(struct mac_device_info *hw,
u32 value = XGMAC_FILTER_RA;
if (dev->flags & IFF_PROMISC) {
- value |= XGMAC_FILTER_PR;
+ value |= XGMAC_FILTER_PR | XGMAC_FILTER_PCF;
} else if ((dev->flags & IFF_ALLMULTI) ||
(netdev_mc_count(dev) > HASH_TABLE_SIZE)) {
value |= XGMAC_FILTER_PM;
@@ -321,6 +321,18 @@ static void dwxgmac2_set_filter(struct mac_device_info *hw,
writel(value, ioaddr + XGMAC_PACKET_FILTER);
}
+static void dwxgmac2_set_mac_loopback(void __iomem *ioaddr, bool enable)
+{
+ u32 value = readl(ioaddr + XGMAC_RX_CONFIG);
+
+ if (enable)
+ value |= XGMAC_CONFIG_LM;
+ else
+ value &= ~XGMAC_CONFIG_LM;
+
+ writel(value, ioaddr + XGMAC_RX_CONFIG);
+}
+
const struct stmmac_ops dwxgmac210_ops = {
.core_init = dwxgmac2_core_init,
.set_mac = dwxgmac2_set_mac,
@@ -350,6 +362,7 @@ const struct stmmac_ops dwxgmac210_ops = {
.pcs_get_adv_lp = NULL,
.debug = NULL,
.set_filter = dwxgmac2_set_filter,
+ .set_mac_loopback = dwxgmac2_set_mac_loopback,
};
int dwxgmac2_setup(struct stmmac_priv *priv)
@@ -368,11 +381,13 @@ int dwxgmac2_setup(struct stmmac_priv *priv)
mac->mcast_bits_log2 = ilog2(mac->multicast_filter_bins);
mac->link.duplex = 0;
- mac->link.speed10 = 0;
- mac->link.speed100 = 0;
- mac->link.speed1000 = XGMAC_CONFIG_SS_1000;
- mac->link.speed2500 = XGMAC_CONFIG_SS_2500;
- mac->link.speed10000 = XGMAC_CONFIG_SS_10000;
+ mac->link.speed10 = XGMAC_CONFIG_SS_10_MII;
+ mac->link.speed100 = XGMAC_CONFIG_SS_100_MII;
+ mac->link.speed1000 = XGMAC_CONFIG_SS_1000_GMII;
+ mac->link.speed2500 = XGMAC_CONFIG_SS_2500_GMII;
+ mac->link.xgmii.speed2500 = XGMAC_CONFIG_SS_2500;
+ mac->link.xgmii.speed5000 = XGMAC_CONFIG_SS_5000;
+ mac->link.xgmii.speed10000 = XGMAC_CONFIG_SS_10000;
mac->link.speed_mask = XGMAC_CONFIG_SS_MASK;
mac->mii.addr = XGMAC_MDIO_ADDR;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c
index 98fa471da7c0..c4c45402b8f8 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c
@@ -242,8 +242,8 @@ static void dwxgmac2_get_addr(struct dma_desc *p, unsigned int *addr)
static void dwxgmac2_set_addr(struct dma_desc *p, dma_addr_t addr)
{
- p->des0 = cpu_to_le32(addr);
- p->des1 = 0;
+ p->des0 = cpu_to_le32(lower_32_bits(addr));
+ p->des1 = cpu_to_le32(upper_32_bits(addr));
}
static void dwxgmac2_clear(struct dma_desc *p)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
index e79037f511e1..a4f236e3593e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
@@ -27,7 +27,7 @@ static void dwxgmac2_dma_init(void __iomem *ioaddr,
if (dma_cfg->aal)
value |= XGMAC_AAL;
- writel(value, ioaddr + XGMAC_DMA_SYSBUS_MODE);
+ writel(value | XGMAC_EAME, ioaddr + XGMAC_DMA_SYSBUS_MODE);
}
static void dwxgmac2_dma_init_chan(void __iomem *ioaddr,
@@ -44,7 +44,7 @@ static void dwxgmac2_dma_init_chan(void __iomem *ioaddr,
static void dwxgmac2_dma_init_rx_chan(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg,
- u32 dma_rx_phy, u32 chan)
+ dma_addr_t phy, u32 chan)
{
u32 rxpbl = dma_cfg->rxpbl ?: dma_cfg->pbl;
u32 value;
@@ -54,12 +54,13 @@ static void dwxgmac2_dma_init_rx_chan(void __iomem *ioaddr,
value |= (rxpbl << XGMAC_RxPBL_SHIFT) & XGMAC_RxPBL;
writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
- writel(dma_rx_phy, ioaddr + XGMAC_DMA_CH_RxDESC_LADDR(chan));
+ writel(upper_32_bits(phy), ioaddr + XGMAC_DMA_CH_RxDESC_HADDR(chan));
+ writel(lower_32_bits(phy), ioaddr + XGMAC_DMA_CH_RxDESC_LADDR(chan));
}
static void dwxgmac2_dma_init_tx_chan(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg,
- u32 dma_tx_phy, u32 chan)
+ dma_addr_t phy, u32 chan)
{
u32 txpbl = dma_cfg->txpbl ?: dma_cfg->pbl;
u32 value;
@@ -70,7 +71,8 @@ static void dwxgmac2_dma_init_tx_chan(void __iomem *ioaddr,
value |= XGMAC_OSP;
writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
- writel(dma_tx_phy, ioaddr + XGMAC_DMA_CH_TxDESC_LADDR(chan));
+ writel(upper_32_bits(phy), ioaddr + XGMAC_DMA_CH_TxDESC_HADDR(chan));
+ writel(lower_32_bits(phy), ioaddr + XGMAC_DMA_CH_TxDESC_LADDR(chan));
}
static void dwxgmac2_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
@@ -91,11 +93,11 @@ static void dwxgmac2_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
value |= (axi->axi_rd_osr_lmt << XGMAC_RD_OSR_LMT_SHIFT) &
XGMAC_RD_OSR_LMT;
+ if (!axi->axi_fb)
+ value |= XGMAC_UNDEF;
+
value &= ~XGMAC_BLEN;
for (i = 0; i < AXI_BLEN; i++) {
- if (axi->axi_blen[i])
- value &= ~XGMAC_UNDEF;
-
switch (axi->axi_blen[i]) {
case 256:
value |= XGMAC_BLEN256;
@@ -122,6 +124,8 @@ static void dwxgmac2_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
}
writel(value, ioaddr + XGMAC_DMA_SYSBUS_MODE);
+ writel(XGMAC_TDPS, ioaddr + XGMAC_TX_EDMA_CTRL);
+ writel(XGMAC_RDPS, ioaddr + XGMAC_RX_EDMA_CTRL);
}
static void dwxgmac2_dma_rx_mode(void __iomem *ioaddr, int mode,
@@ -299,10 +303,6 @@ static void dwxgmac2_dma_stop_rx(void __iomem *ioaddr, u32 chan)
value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
value &= ~XGMAC_RXST;
writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
-
- value = readl(ioaddr + XGMAC_RX_CONFIG);
- value &= ~XGMAC_CONFIG_RE;
- writel(value, ioaddr + XGMAC_RX_CONFIG);
}
static int dwxgmac2_dma_interrupt(void __iomem *ioaddr,
@@ -363,6 +363,23 @@ static void dwxgmac2_get_hw_feature(void __iomem *ioaddr,
/* MAC HW feature 1 */
hw_cap = readl(ioaddr + XGMAC_HW_FEATURE1);
dma_cap->tsoen = (hw_cap & XGMAC_HWFEAT_TSOEN) >> 18;
+
+ dma_cap->addr64 = (hw_cap & XGMAC_HWFEAT_ADDR64) >> 14;
+ switch (dma_cap->addr64) {
+ case 0:
+ dma_cap->addr64 = 32;
+ break;
+ case 1:
+ dma_cap->addr64 = 40;
+ break;
+ case 2:
+ dma_cap->addr64 = 48;
+ break;
+ default:
+ dma_cap->addr64 = 32;
+ break;
+ }
+
dma_cap->tx_fifo_size =
128 << ((hw_cap & XGMAC_HWFEAT_TXFIFOSIZE) >> 6);
dma_cap->rx_fifo_size =
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c b/drivers/net/ethernet/stmicro/stmmac/hwif.c
index 81b966a8261b..6c61b753b55e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.c
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c
@@ -81,6 +81,7 @@ static const struct stmmac_hwif_entry {
const void *hwtimestamp;
const void *mode;
const void *tc;
+ const void *mmc;
int (*setup)(struct stmmac_priv *priv);
int (*quirks)(struct stmmac_priv *priv);
} stmmac_hw[] = {
@@ -100,6 +101,7 @@ static const struct stmmac_hwif_entry {
.hwtimestamp = &stmmac_ptp,
.mode = NULL,
.tc = NULL,
+ .mmc = &dwmac_mmc_ops,
.setup = dwmac100_setup,
.quirks = stmmac_dwmac1_quirks,
}, {
@@ -117,6 +119,7 @@ static const struct stmmac_hwif_entry {
.hwtimestamp = &stmmac_ptp,
.mode = NULL,
.tc = NULL,
+ .mmc = &dwmac_mmc_ops,
.setup = dwmac1000_setup,
.quirks = stmmac_dwmac1_quirks,
}, {
@@ -134,6 +137,7 @@ static const struct stmmac_hwif_entry {
.hwtimestamp = &stmmac_ptp,
.mode = NULL,
.tc = &dwmac510_tc_ops,
+ .mmc = &dwmac_mmc_ops,
.setup = dwmac4_setup,
.quirks = stmmac_dwmac4_quirks,
}, {
@@ -151,6 +155,7 @@ static const struct stmmac_hwif_entry {
.hwtimestamp = &stmmac_ptp,
.mode = &dwmac4_ring_mode_ops,
.tc = &dwmac510_tc_ops,
+ .mmc = &dwmac_mmc_ops,
.setup = dwmac4_setup,
.quirks = NULL,
}, {
@@ -168,6 +173,7 @@ static const struct stmmac_hwif_entry {
.hwtimestamp = &stmmac_ptp,
.mode = &dwmac4_ring_mode_ops,
.tc = &dwmac510_tc_ops,
+ .mmc = &dwmac_mmc_ops,
.setup = dwmac4_setup,
.quirks = NULL,
}, {
@@ -185,6 +191,7 @@ static const struct stmmac_hwif_entry {
.hwtimestamp = &stmmac_ptp,
.mode = &dwmac4_ring_mode_ops,
.tc = &dwmac510_tc_ops,
+ .mmc = &dwmac_mmc_ops,
.setup = dwmac4_setup,
.quirks = NULL,
}, {
@@ -202,6 +209,7 @@ static const struct stmmac_hwif_entry {
.hwtimestamp = &stmmac_ptp,
.mode = NULL,
.tc = &dwmac510_tc_ops,
+ .mmc = NULL,
.setup = dwxgmac2_setup,
.quirks = NULL,
},
@@ -267,6 +275,7 @@ int stmmac_hwif_init(struct stmmac_priv *priv)
mac->ptp = mac->ptp ? : entry->hwtimestamp;
mac->mode = mac->mode ? : entry->mode;
mac->tc = mac->tc ? : entry->tc;
+ mac->mmc = mac->mmc ? : entry->mmc;
priv->hw = mac;
priv->ptpaddr = priv->ioaddr + entry->regs.ptp_off;
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h
index 5bb00234d961..278c0dbec9d9 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
@@ -6,6 +6,7 @@
#define __STMMAC_HWIF_H__
#include <linux/netdevice.h>
+#include <linux/stmmac.h>
#define stmmac_do_void_callback(__priv, __module, __cname, __arg0, __args...) \
({ \
@@ -149,10 +150,10 @@ struct stmmac_dma_ops {
struct stmmac_dma_cfg *dma_cfg, u32 chan);
void (*init_rx_chan)(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg,
- u32 dma_rx_phy, u32 chan);
+ dma_addr_t phy, u32 chan);
void (*init_tx_chan)(void __iomem *ioaddr,
struct stmmac_dma_cfg *dma_cfg,
- u32 dma_tx_phy, u32 chan);
+ dma_addr_t phy, u32 chan);
/* Configure the AXI Bus Mode Register */
void (*axi)(void __iomem *ioaddr, struct stmmac_axi *axi);
/* Dump DMA registers */
@@ -324,6 +325,8 @@ struct stmmac_ops {
int (*flex_pps_config)(void __iomem *ioaddr, int index,
struct stmmac_pps_cfg *cfg, bool enable,
u32 sub_second_inc, u32 systime_flags);
+ /* Loopback for selftests */
+ void (*set_mac_loopback)(void __iomem *ioaddr, bool enable);
};
#define stmmac_core_init(__priv, __args...) \
@@ -392,6 +395,8 @@ struct stmmac_ops {
stmmac_do_callback(__priv, mac, rxp_config, __args)
#define stmmac_flex_pps_config(__priv, __args...) \
stmmac_do_callback(__priv, mac, flex_pps_config, __args)
+#define stmmac_set_mac_loopback(__priv, __args...) \
+ stmmac_do_void_callback(__priv, mac, set_mac_loopback, __args)
/* PTP and HW Timer helpers */
struct stmmac_hwtimestamp {
@@ -464,6 +469,21 @@ struct stmmac_tc_ops {
#define stmmac_tc_setup_cbs(__priv, __args...) \
stmmac_do_callback(__priv, tc, setup_cbs, __args)
+struct stmmac_counters;
+
+struct stmmac_mmc_ops {
+ void (*ctrl)(void __iomem *ioaddr, unsigned int mode);
+ void (*intr_all_mask)(void __iomem *ioaddr);
+ void (*read)(void __iomem *ioaddr, struct stmmac_counters *mmc);
+};
+
+#define stmmac_mmc_ctrl(__priv, __args...) \
+ stmmac_do_void_callback(__priv, mmc, ctrl, __args)
+#define stmmac_mmc_intr_all_mask(__priv, __args...) \
+ stmmac_do_void_callback(__priv, mmc, intr_all_mask, __args)
+#define stmmac_mmc_read(__priv, __args...) \
+ stmmac_do_void_callback(__priv, mmc, read, __args)
+
struct stmmac_regs_off {
u32 ptp_off;
u32 mmc_off;
@@ -482,6 +502,7 @@ extern const struct stmmac_tc_ops dwmac510_tc_ops;
extern const struct stmmac_ops dwxgmac210_ops;
extern const struct stmmac_dma_ops dwxgmac210_dma_ops;
extern const struct stmmac_desc_ops dwxgmac210_desc_ops;
+extern const struct stmmac_mmc_ops dwmac_mmc_ops;
#define GMAC_VERSION 0x00000020 /* GMAC CORE Version */
#define GMAC4_VERSION 0x00000110 /* GMAC4+ CORE Version */
diff --git a/drivers/net/ethernet/stmicro/stmmac/mmc.h b/drivers/net/ethernet/stmicro/stmmac/mmc.h
index 6c8fdee3b25a..3587ceb9faf5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/mmc.h
+++ b/drivers/net/ethernet/stmicro/stmmac/mmc.h
@@ -118,8 +118,4 @@ struct stmmac_counters {
unsigned int mmc_rx_icmp_err_octets;
};
-void dwmac_mmc_ctrl(void __iomem *ioaddr, unsigned int mode);
-void dwmac_mmc_intr_all_mask(void __iomem *ioaddr);
-void dwmac_mmc_read(void __iomem *ioaddr, struct stmmac_counters *mmc);
-
#endif /* __MMC_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
index 1d967b8f91a0..a471db6d7b11 100644
--- a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
@@ -10,6 +10,7 @@
#include <linux/kernel.h>
#include <linux/io.h>
+#include "hwif.h"
#include "mmc.h"
/* MAC Management Counters register offset */
@@ -118,7 +119,7 @@
#define MMC_RX_ICMP_GD_OCTETS 0x180
#define MMC_RX_ICMP_ERR_OCTETS 0x184
-void dwmac_mmc_ctrl(void __iomem *mmcaddr, unsigned int mode)
+static void dwmac_mmc_ctrl(void __iomem *mmcaddr, unsigned int mode)
{
u32 value = readl(mmcaddr + MMC_CNTRL);
@@ -131,7 +132,7 @@ void dwmac_mmc_ctrl(void __iomem *mmcaddr, unsigned int mode)
}
/* To mask all all interrupts.*/
-void dwmac_mmc_intr_all_mask(void __iomem *mmcaddr)
+static void dwmac_mmc_intr_all_mask(void __iomem *mmcaddr)
{
writel(MMC_DEFAULT_MASK, mmcaddr + MMC_RX_INTR_MASK);
writel(MMC_DEFAULT_MASK, mmcaddr + MMC_TX_INTR_MASK);
@@ -143,7 +144,7 @@ void dwmac_mmc_intr_all_mask(void __iomem *mmcaddr)
* counter after a read. So all the field of the mmc struct
* have to be incremented.
*/
-void dwmac_mmc_read(void __iomem *mmcaddr, struct stmmac_counters *mmc)
+static void dwmac_mmc_read(void __iomem *mmcaddr, struct stmmac_counters *mmc)
{
mmc->mmc_tx_octetcount_gb += readl(mmcaddr + MMC_TX_OCTETCOUNT_GB);
mmc->mmc_tx_framecount_gb += readl(mmcaddr + MMC_TX_FRAMECOUNT_GB);
@@ -256,3 +257,9 @@ void dwmac_mmc_read(void __iomem *mmcaddr, struct stmmac_counters *mmc)
mmc->mmc_rx_icmp_gd_octets += readl(mmcaddr + MMC_RX_ICMP_GD_OCTETS);
mmc->mmc_rx_icmp_err_octets += readl(mmcaddr + MMC_RX_ICMP_ERR_OCTETS);
}
+
+const struct stmmac_mmc_ops dwmac_mmc_ops = {
+ .ctrl = dwmac_mmc_ctrl,
+ .intr_all_mask = dwmac_mmc_intr_all_mask,
+ .read = dwmac_mmc_read,
+};
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 62a64356ad22..5cd966c154f3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -14,12 +14,13 @@
#include <linux/clk.h>
#include <linux/stmmac.h>
-#include <linux/phy.h>
+#include <linux/phylink.h>
#include <linux/pci.h>
#include "common.h"
#include <linux/ptp_clock_kernel.h>
#include <linux/net_tstamp.h>
#include <linux/reset.h>
+#include <net/page_pool.h>
struct stmmac_resources {
void __iomem *addr;
@@ -54,13 +55,19 @@ struct stmmac_tx_queue {
u32 mss;
};
+struct stmmac_rx_buffer {
+ struct page *page;
+ dma_addr_t addr;
+};
+
struct stmmac_rx_queue {
+ u32 rx_count_frames;
u32 queue_index;
+ struct page_pool *page_pool;
+ struct stmmac_rx_buffer *buf_pool;
struct stmmac_priv *priv_data;
struct dma_extended_desc *dma_erx;
struct dma_desc *dma_rx ____cacheline_aligned_in_smp;
- struct sk_buff **rx_skbuff;
- dma_addr_t *rx_skbuff_dma;
unsigned int cur_rx;
unsigned int dirty_rx;
u32 rx_zeroc_thresh;
@@ -110,6 +117,7 @@ struct stmmac_priv {
/* Frequently used values are kept adjacent for cache effect */
u32 tx_coal_frames;
u32 tx_coal_timer;
+ u32 rx_coal_frames;
int tx_coalesce;
int hwts_tx_en;
@@ -137,14 +145,15 @@ struct stmmac_priv {
/* Generic channel for NAPI */
struct stmmac_channel channel[STMMAC_CH_MAX];
- bool oldlink;
int speed;
- int oldduplex;
unsigned int flow_ctrl;
unsigned int pause;
struct mii_bus *mii;
int mii_irq[PHY_MAX_ADDR];
+ struct phylink_config phylink_config;
+ struct phylink *phylink;
+
struct stmmac_extra_stats xstats ____cacheline_aligned_in_smp;
struct stmmac_safety_stats sstats;
struct plat_stmmacenet_data *plat;
@@ -219,4 +228,26 @@ int stmmac_dvr_probe(struct device *device,
void stmmac_disable_eee_mode(struct stmmac_priv *priv);
bool stmmac_eee_init(struct stmmac_priv *priv);
+#if IS_ENABLED(CONFIG_STMMAC_SELFTESTS)
+void stmmac_selftest_run(struct net_device *dev,
+ struct ethtool_test *etest, u64 *buf);
+void stmmac_selftest_get_strings(struct stmmac_priv *priv, u8 *data);
+int stmmac_selftest_get_count(struct stmmac_priv *priv);
+#else
+static inline void stmmac_selftest_run(struct net_device *dev,
+ struct ethtool_test *etest, u64 *buf)
+{
+ /* Not enabled */
+}
+static inline void stmmac_selftest_get_strings(struct stmmac_priv *priv,
+ u8 *data)
+{
+ /* Not enabled */
+}
+static inline int stmmac_selftest_get_count(struct stmmac_priv *priv)
+{
+ return -EOPNOTSUPP;
+}
+#endif /* CONFIG_STMMAC_SELFTESTS */
+
#endif /* __STMMAC_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index e7af3dc3dd8f..6efb66820d4c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -12,7 +12,7 @@
#include <linux/ethtool.h>
#include <linux/interrupt.h>
#include <linux/mii.h>
-#include <linux/phy.h>
+#include <linux/phylink.h>
#include <linux/net_tstamp.h>
#include <asm/io.h>
@@ -264,7 +264,6 @@ static int stmmac_ethtool_get_link_ksettings(struct net_device *dev,
struct ethtool_link_ksettings *cmd)
{
struct stmmac_priv *priv = netdev_priv(dev);
- struct phy_device *phy = dev->phydev;
if (priv->hw->pcs & STMMAC_PCS_RGMII ||
priv->hw->pcs & STMMAC_PCS_SGMII) {
@@ -343,18 +342,7 @@ static int stmmac_ethtool_get_link_ksettings(struct net_device *dev,
return 0;
}
- if (phy == NULL) {
- pr_err("%s: %s: PHY is not registered\n",
- __func__, dev->name);
- return -ENODEV;
- }
- if (!netif_running(dev)) {
- pr_err("%s: interface is disabled: we cannot track "
- "link speed / duplex setting\n", dev->name);
- return -EBUSY;
- }
- phy_ethtool_ksettings_get(phy, cmd);
- return 0;
+ return phylink_ethtool_ksettings_get(priv->phylink, cmd);
}
static int
@@ -362,8 +350,6 @@ stmmac_ethtool_set_link_ksettings(struct net_device *dev,
const struct ethtool_link_ksettings *cmd)
{
struct stmmac_priv *priv = netdev_priv(dev);
- struct phy_device *phy = dev->phydev;
- int rc;
if (priv->hw->pcs & STMMAC_PCS_RGMII ||
priv->hw->pcs & STMMAC_PCS_SGMII) {
@@ -387,9 +373,7 @@ stmmac_ethtool_set_link_ksettings(struct net_device *dev,
return 0;
}
- rc = phy_ethtool_ksettings_set(phy, cmd);
-
- return rc;
+ return phylink_ethtool_ksettings_set(priv->phylink, cmd);
}
static u32 stmmac_ethtool_getmsglevel(struct net_device *dev)
@@ -433,6 +417,13 @@ static void stmmac_ethtool_gregs(struct net_device *dev,
NUM_DWMAC1000_DMA_REGS * 4);
}
+static int stmmac_nway_reset(struct net_device *dev)
+{
+ struct stmmac_priv *priv = netdev_priv(dev);
+
+ return phylink_ethtool_nway_reset(priv->phylink);
+}
+
static void
stmmac_get_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pause)
@@ -440,28 +431,13 @@ stmmac_get_pauseparam(struct net_device *netdev,
struct stmmac_priv *priv = netdev_priv(netdev);
struct rgmii_adv adv_lp;
- pause->rx_pause = 0;
- pause->tx_pause = 0;
-
if (priv->hw->pcs && !stmmac_pcs_get_adv_lp(priv, priv->ioaddr, &adv_lp)) {
pause->autoneg = 1;
if (!adv_lp.pause)
return;
} else {
- if (!linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
- netdev->phydev->supported) ||
- !linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
- netdev->phydev->supported))
- return;
+ phylink_ethtool_get_pauseparam(priv->phylink, pause);
}
-
- pause->autoneg = netdev->phydev->autoneg;
-
- if (priv->flow_ctrl & FLOW_RX)
- pause->rx_pause = 1;
- if (priv->flow_ctrl & FLOW_TX)
- pause->tx_pause = 1;
-
}
static int
@@ -469,39 +445,16 @@ stmmac_set_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pause)
{
struct stmmac_priv *priv = netdev_priv(netdev);
- u32 tx_cnt = priv->plat->tx_queues_to_use;
- struct phy_device *phy = netdev->phydev;
- int new_pause = FLOW_OFF;
struct rgmii_adv adv_lp;
if (priv->hw->pcs && !stmmac_pcs_get_adv_lp(priv, priv->ioaddr, &adv_lp)) {
pause->autoneg = 1;
if (!adv_lp.pause)
return -EOPNOTSUPP;
+ return 0;
} else {
- if (!linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
- phy->supported) ||
- !linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
- phy->supported))
- return -EOPNOTSUPP;
- }
-
- if (pause->rx_pause)
- new_pause |= FLOW_RX;
- if (pause->tx_pause)
- new_pause |= FLOW_TX;
-
- priv->flow_ctrl = new_pause;
- phy->autoneg = pause->autoneg;
-
- if (phy->autoneg) {
- if (netif_running(netdev))
- return phy_start_aneg(phy);
+ return phylink_ethtool_set_pauseparam(priv->phylink, pause);
}
-
- stmmac_flow_ctrl(priv, priv->hw, phy->duplex, priv->flow_ctrl,
- priv->pause, tx_cnt);
- return 0;
}
static void stmmac_get_ethtool_stats(struct net_device *dev,
@@ -527,7 +480,7 @@ static void stmmac_get_ethtool_stats(struct net_device *dev,
if (ret) {
/* If supported, for new GMAC chips expose the MMC counters */
if (priv->dma_cap.rmon) {
- dwmac_mmc_read(priv->mmcaddr, &priv->mmc);
+ stmmac_mmc_read(priv, priv->mmcaddr, &priv->mmc);
for (i = 0; i < STMMAC_MMC_STATS_LEN; i++) {
char *p;
@@ -539,7 +492,7 @@ static void stmmac_get_ethtool_stats(struct net_device *dev,
}
}
if (priv->eee_enabled) {
- int val = phy_get_eee_err(dev->phydev);
+ int val = phylink_get_eee_err(priv->phylink);
if (val)
priv->xstats.phy_eee_wakeup_error_n = val;
}
@@ -579,6 +532,8 @@ static int stmmac_get_sset_count(struct net_device *netdev, int sset)
}
return len;
+ case ETH_SS_TEST:
+ return stmmac_selftest_get_count(priv);
default:
return -EOPNOTSUPP;
}
@@ -615,6 +570,9 @@ static void stmmac_get_strings(struct net_device *dev, u32 stringset, u8 *data)
p += ETH_GSTRING_LEN;
}
break;
+ case ETH_SS_TEST:
+ stmmac_selftest_get_strings(priv, p);
+ break;
default:
WARN_ON(1);
break;
@@ -679,7 +637,7 @@ static int stmmac_ethtool_op_get_eee(struct net_device *dev,
edata->eee_active = priv->eee_active;
edata->tx_lpi_timer = priv->tx_lpi_timer;
- return phy_ethtool_get_eee(dev->phydev, edata);
+ return phylink_ethtool_get_eee(priv->phylink, edata);
}
static int stmmac_ethtool_op_set_eee(struct net_device *dev,
@@ -700,7 +658,7 @@ static int stmmac_ethtool_op_set_eee(struct net_device *dev,
return -EOPNOTSUPP;
}
- ret = phy_ethtool_set_eee(dev->phydev, edata);
+ ret = phylink_ethtool_set_eee(priv->phylink, edata);
if (ret)
return ret;
@@ -743,8 +701,10 @@ static int stmmac_get_coalesce(struct net_device *dev,
ec->tx_coalesce_usecs = priv->tx_coal_timer;
ec->tx_max_coalesced_frames = priv->tx_coal_frames;
- if (priv->use_riwt)
+ if (priv->use_riwt) {
+ ec->rx_max_coalesced_frames = priv->rx_coal_frames;
ec->rx_coalesce_usecs = stmmac_riwt2usec(priv->rx_riwt, priv);
+ }
return 0;
}
@@ -757,7 +717,7 @@ static int stmmac_set_coalesce(struct net_device *dev,
unsigned int rx_riwt;
/* Check not supported parameters */
- if ((ec->rx_max_coalesced_frames) || (ec->rx_coalesce_usecs_irq) ||
+ if ((ec->rx_coalesce_usecs_irq) ||
(ec->rx_max_coalesced_frames_irq) || (ec->tx_coalesce_usecs_irq) ||
(ec->use_adaptive_rx_coalesce) || (ec->use_adaptive_tx_coalesce) ||
(ec->pkt_rate_low) || (ec->rx_coalesce_usecs_low) ||
@@ -791,6 +751,7 @@ static int stmmac_set_coalesce(struct net_device *dev,
/* Only copy relevant parameters, ignore all others. */
priv->tx_coal_frames = ec->tx_max_coalesced_frames;
priv->tx_coal_timer = ec->tx_coalesce_usecs;
+ priv->rx_coal_frames = ec->rx_max_coalesced_frames;
priv->rx_riwt = rx_riwt;
stmmac_rx_watchdog(priv, priv->ioaddr, priv->rx_riwt, rx_cnt);
@@ -877,9 +838,10 @@ static const struct ethtool_ops stmmac_ethtool_ops = {
.get_regs = stmmac_ethtool_gregs,
.get_regs_len = stmmac_ethtool_get_regs_len,
.get_link = ethtool_op_get_link,
- .nway_reset = phy_ethtool_nway_reset,
+ .nway_reset = stmmac_nway_reset,
.get_pauseparam = stmmac_get_pauseparam,
.set_pauseparam = stmmac_set_pauseparam,
+ .self_test = stmmac_selftest_run,
.get_ethtool_stats = stmmac_get_ethtool_stats,
.get_strings = stmmac_get_strings,
.get_wol = stmmac_get_wol,
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
index 2dcdf761d525..020159622559 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
@@ -112,7 +112,7 @@ static int adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec,
* programmed with (2^32 – <new_sec_value>)
*/
if (gmac4)
- sec = (100000000ULL - sec);
+ sec = -sec;
value = readl(ioaddr + PTP_TCR);
if (value & PTP_TCR_TSCTRLSSR)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 06dd51f47cfd..c7c9e5f162e6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -35,6 +35,7 @@
#include <linux/seq_file.h>
#endif /* CONFIG_DEBUG_FS */
#include <linux/net_tstamp.h>
+#include <linux/phylink.h>
#include <net/pkt_cls.h>
#include "stmmac_ptp.h"
#include "stmmac.h"
@@ -318,21 +319,6 @@ static inline u32 stmmac_rx_dirty(struct stmmac_priv *priv, u32 queue)
}
/**
- * stmmac_hw_fix_mac_speed - callback for speed selection
- * @priv: driver private structure
- * Description: on some platforms (e.g. ST), some HW system configuration
- * registers have to be set according to the link speed negotiated.
- */
-static inline void stmmac_hw_fix_mac_speed(struct stmmac_priv *priv)
-{
- struct net_device *ndev = priv->dev;
- struct phy_device *phydev = ndev->phydev;
-
- if (likely(priv->plat->fix_mac_speed))
- priv->plat->fix_mac_speed(priv->plat->bsp_priv, phydev->speed);
-}
-
-/**
* stmmac_enable_eee_mode - check and enter in LPI mode
* @priv: driver private structure
* Description: this function is to verify and enter in LPI mode in case of
@@ -395,14 +381,7 @@ static void stmmac_eee_ctrl_timer(struct timer_list *t)
*/
bool stmmac_eee_init(struct stmmac_priv *priv)
{
- struct net_device *ndev = priv->dev;
- int interface = priv->plat->interface;
- bool ret = false;
-
- if ((interface != PHY_INTERFACE_MODE_MII) &&
- (interface != PHY_INTERFACE_MODE_GMII) &&
- !phy_interface_mode_is_rgmii(interface))
- goto out;
+ int tx_lpi_timer = priv->tx_lpi_timer;
/* Using PCS we cannot dial with the phy registers at this stage
* so we do not support extra feature like EEE.
@@ -410,52 +389,35 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
if ((priv->hw->pcs == STMMAC_PCS_RGMII) ||
(priv->hw->pcs == STMMAC_PCS_TBI) ||
(priv->hw->pcs == STMMAC_PCS_RTBI))
- goto out;
-
- /* MAC core supports the EEE feature. */
- if (priv->dma_cap.eee) {
- int tx_lpi_timer = priv->tx_lpi_timer;
-
- /* Check if the PHY supports EEE */
- if (phy_init_eee(ndev->phydev, 1)) {
- /* To manage at run-time if the EEE cannot be supported
- * anymore (for example because the lp caps have been
- * changed).
- * In that case the driver disable own timers.
- */
- mutex_lock(&priv->lock);
- if (priv->eee_active) {
- netdev_dbg(priv->dev, "disable EEE\n");
- del_timer_sync(&priv->eee_ctrl_timer);
- stmmac_set_eee_timer(priv, priv->hw, 0,
- tx_lpi_timer);
- }
- priv->eee_active = 0;
- mutex_unlock(&priv->lock);
- goto out;
- }
- /* Activate the EEE and start timers */
- mutex_lock(&priv->lock);
- if (!priv->eee_active) {
- priv->eee_active = 1;
- timer_setup(&priv->eee_ctrl_timer,
- stmmac_eee_ctrl_timer, 0);
- mod_timer(&priv->eee_ctrl_timer,
- STMMAC_LPI_T(eee_timer));
-
- stmmac_set_eee_timer(priv, priv->hw,
- STMMAC_DEFAULT_LIT_LS, tx_lpi_timer);
- }
- /* Set HW EEE according to the speed */
- stmmac_set_eee_pls(priv, priv->hw, ndev->phydev->link);
+ return false;
+
+ /* Check if MAC core supports the EEE feature. */
+ if (!priv->dma_cap.eee)
+ return false;
+
+ mutex_lock(&priv->lock);
- ret = true;
+ /* Check if it needs to be deactivated */
+ if (!priv->eee_active) {
+ if (priv->eee_enabled) {
+ netdev_dbg(priv->dev, "disable EEE\n");
+ del_timer_sync(&priv->eee_ctrl_timer);
+ stmmac_set_eee_timer(priv, priv->hw, 0, tx_lpi_timer);
+ }
mutex_unlock(&priv->lock);
+ return false;
+ }
- netdev_dbg(priv->dev, "Energy-Efficient Ethernet initialized\n");
+ if (priv->eee_active && !priv->eee_enabled) {
+ timer_setup(&priv->eee_ctrl_timer, stmmac_eee_ctrl_timer, 0);
+ mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(eee_timer));
+ stmmac_set_eee_timer(priv, priv->hw, STMMAC_DEFAULT_LIT_LS,
+ tx_lpi_timer);
}
-out:
- return ret;
+
+ mutex_unlock(&priv->lock);
+ netdev_dbg(priv->dev, "Energy-Efficient Ethernet initialized\n");
+ return true;
}
/* stmmac_get_tx_hwtstamp - get HW TX timestamps
@@ -838,97 +800,171 @@ static void stmmac_mac_flow_ctrl(struct stmmac_priv *priv, u32 duplex)
priv->pause, tx_cnt);
}
-/**
- * stmmac_adjust_link - adjusts the link parameters
- * @dev: net device structure
- * Description: this is the helper called by the physical abstraction layer
- * drivers to communicate the phy link status. According the speed and duplex
- * this driver can invoke registered glue-logic as well.
- * It also invoke the eee initialization because it could happen when switch
- * on different networks (that are eee capable).
- */
-static void stmmac_adjust_link(struct net_device *dev)
+static void stmmac_validate(struct phylink_config *config,
+ unsigned long *supported,
+ struct phylink_link_state *state)
{
- struct stmmac_priv *priv = netdev_priv(dev);
- struct phy_device *phydev = dev->phydev;
- bool new_state = false;
-
- if (!phydev)
- return;
+ struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(mac_supported) = { 0, };
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
+ int tx_cnt = priv->plat->tx_queues_to_use;
+ int max_speed = priv->plat->max_speed;
- mutex_lock(&priv->lock);
+ phylink_set(mac_supported, 10baseT_Half);
+ phylink_set(mac_supported, 10baseT_Full);
+ phylink_set(mac_supported, 100baseT_Half);
+ phylink_set(mac_supported, 100baseT_Full);
+
+ phylink_set(mac_supported, Autoneg);
+ phylink_set(mac_supported, Pause);
+ phylink_set(mac_supported, Asym_Pause);
+ phylink_set_port_modes(mac_supported);
+
+ if (priv->plat->has_gmac ||
+ priv->plat->has_gmac4 ||
+ priv->plat->has_xgmac) {
+ phylink_set(mac_supported, 1000baseT_Half);
+ phylink_set(mac_supported, 1000baseT_Full);
+ phylink_set(mac_supported, 1000baseKX_Full);
+ }
+
+ /* Cut down 1G if asked to */
+ if ((max_speed > 0) && (max_speed < 1000)) {
+ phylink_set(mask, 1000baseT_Full);
+ phylink_set(mask, 1000baseX_Full);
+ } else if (priv->plat->has_xgmac) {
+ phylink_set(mac_supported, 2500baseT_Full);
+ phylink_set(mac_supported, 5000baseT_Full);
+ phylink_set(mac_supported, 10000baseSR_Full);
+ phylink_set(mac_supported, 10000baseLR_Full);
+ phylink_set(mac_supported, 10000baseER_Full);
+ phylink_set(mac_supported, 10000baseLRM_Full);
+ phylink_set(mac_supported, 10000baseT_Full);
+ phylink_set(mac_supported, 10000baseKX4_Full);
+ phylink_set(mac_supported, 10000baseKR_Full);
+ }
+
+ /* Half-Duplex can only work with single queue */
+ if (tx_cnt > 1) {
+ phylink_set(mask, 10baseT_Half);
+ phylink_set(mask, 100baseT_Half);
+ phylink_set(mask, 1000baseT_Half);
+ }
+
+ bitmap_and(supported, supported, mac_supported,
+ __ETHTOOL_LINK_MODE_MASK_NBITS);
+ bitmap_andnot(supported, supported, mask,
+ __ETHTOOL_LINK_MODE_MASK_NBITS);
+ bitmap_and(state->advertising, state->advertising, mac_supported,
+ __ETHTOOL_LINK_MODE_MASK_NBITS);
+ bitmap_andnot(state->advertising, state->advertising, mask,
+ __ETHTOOL_LINK_MODE_MASK_NBITS);
+}
- if (phydev->link) {
- u32 ctrl = readl(priv->ioaddr + MAC_CTRL_REG);
+static int stmmac_mac_link_state(struct phylink_config *config,
+ struct phylink_link_state *state)
+{
+ return -EOPNOTSUPP;
+}
- /* Now we make sure that we can be in full duplex mode.
- * If not, we operate in half-duplex mode. */
- if (phydev->duplex != priv->oldduplex) {
- new_state = true;
- if (!phydev->duplex)
- ctrl &= ~priv->hw->link.duplex;
- else
- ctrl |= priv->hw->link.duplex;
- priv->oldduplex = phydev->duplex;
- }
- /* Flow Control operation */
- if (phydev->pause)
- stmmac_mac_flow_ctrl(priv, phydev->duplex);
-
- if (phydev->speed != priv->speed) {
- new_state = true;
- ctrl &= ~priv->hw->link.speed_mask;
- switch (phydev->speed) {
- case SPEED_1000:
- ctrl |= priv->hw->link.speed1000;
- break;
- case SPEED_100:
- ctrl |= priv->hw->link.speed100;
- break;
- case SPEED_10:
- ctrl |= priv->hw->link.speed10;
- break;
- default:
- netif_warn(priv, link, priv->dev,
- "broken speed: %d\n", phydev->speed);
- phydev->speed = SPEED_UNKNOWN;
- break;
- }
- if (phydev->speed != SPEED_UNKNOWN)
- stmmac_hw_fix_mac_speed(priv);
- priv->speed = phydev->speed;
- }
+static void stmmac_mac_config(struct phylink_config *config, unsigned int mode,
+ const struct phylink_link_state *state)
+{
+ struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
+ u32 ctrl;
- writel(ctrl, priv->ioaddr + MAC_CTRL_REG);
+ ctrl = readl(priv->ioaddr + MAC_CTRL_REG);
+ ctrl &= ~priv->hw->link.speed_mask;
- if (!priv->oldlink) {
- new_state = true;
- priv->oldlink = true;
+ if (state->interface == PHY_INTERFACE_MODE_USXGMII) {
+ switch (state->speed) {
+ case SPEED_10000:
+ ctrl |= priv->hw->link.xgmii.speed10000;
+ break;
+ case SPEED_5000:
+ ctrl |= priv->hw->link.xgmii.speed5000;
+ break;
+ case SPEED_2500:
+ ctrl |= priv->hw->link.xgmii.speed2500;
+ break;
+ default:
+ return;
+ }
+ } else {
+ switch (state->speed) {
+ case SPEED_2500:
+ ctrl |= priv->hw->link.speed2500;
+ break;
+ case SPEED_1000:
+ ctrl |= priv->hw->link.speed1000;
+ break;
+ case SPEED_100:
+ ctrl |= priv->hw->link.speed100;
+ break;
+ case SPEED_10:
+ ctrl |= priv->hw->link.speed10;
+ break;
+ default:
+ return;
}
- } else if (priv->oldlink) {
- new_state = true;
- priv->oldlink = false;
- priv->speed = SPEED_UNKNOWN;
- priv->oldduplex = DUPLEX_UNKNOWN;
}
- if (new_state && netif_msg_link(priv))
- phy_print_status(phydev);
+ priv->speed = state->speed;
- mutex_unlock(&priv->lock);
+ if (priv->plat->fix_mac_speed)
+ priv->plat->fix_mac_speed(priv->plat->bsp_priv, state->speed);
- if (phydev->is_pseudo_fixed_link)
- /* Stop PHY layer to call the hook to adjust the link in case
- * of a switch is attached to the stmmac driver.
- */
- phydev->irq = PHY_IGNORE_INTERRUPT;
+ if (!state->duplex)
+ ctrl &= ~priv->hw->link.duplex;
else
- /* At this stage, init the EEE if supported.
- * Never called in case of fixed_link.
- */
+ ctrl |= priv->hw->link.duplex;
+
+ /* Flow Control operation */
+ if (state->pause)
+ stmmac_mac_flow_ctrl(priv, state->duplex);
+
+ writel(ctrl, priv->ioaddr + MAC_CTRL_REG);
+}
+
+static void stmmac_mac_an_restart(struct phylink_config *config)
+{
+ /* Not Supported */
+}
+
+static void stmmac_mac_link_down(struct phylink_config *config,
+ unsigned int mode, phy_interface_t interface)
+{
+ struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
+
+ stmmac_mac_set(priv, priv->ioaddr, false);
+ priv->eee_active = false;
+ stmmac_eee_init(priv);
+ stmmac_set_eee_pls(priv, priv->hw, false);
+}
+
+static void stmmac_mac_link_up(struct phylink_config *config,
+ unsigned int mode, phy_interface_t interface,
+ struct phy_device *phy)
+{
+ struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
+
+ stmmac_mac_set(priv, priv->ioaddr, true);
+ if (phy && priv->dma_cap.eee) {
+ priv->eee_active = phy_init_eee(phy, 1) >= 0;
priv->eee_enabled = stmmac_eee_init(priv);
+ stmmac_set_eee_pls(priv, priv->hw, true);
+ }
}
+static const struct phylink_mac_ops stmmac_phylink_mac_ops = {
+ .validate = stmmac_validate,
+ .mac_link_state = stmmac_mac_link_state,
+ .mac_config = stmmac_mac_config,
+ .mac_an_restart = stmmac_mac_an_restart,
+ .mac_link_down = stmmac_mac_link_down,
+ .mac_link_up = stmmac_mac_link_up,
+};
+
/**
* stmmac_check_pcs_mode - verify if RGMII/SGMII is supported
* @priv: driver private structure
@@ -965,79 +1001,48 @@ static void stmmac_check_pcs_mode(struct stmmac_priv *priv)
static int stmmac_init_phy(struct net_device *dev)
{
struct stmmac_priv *priv = netdev_priv(dev);
- u32 tx_cnt = priv->plat->tx_queues_to_use;
- struct phy_device *phydev;
- char phy_id_fmt[MII_BUS_ID_SIZE + 3];
- char bus_id[MII_BUS_ID_SIZE];
- int interface = priv->plat->interface;
- int max_speed = priv->plat->max_speed;
- priv->oldlink = false;
- priv->speed = SPEED_UNKNOWN;
- priv->oldduplex = DUPLEX_UNKNOWN;
+ struct device_node *node;
+ int ret;
- if (priv->plat->phy_node) {
- phydev = of_phy_connect(dev, priv->plat->phy_node,
- &stmmac_adjust_link, 0, interface);
- } else {
- snprintf(bus_id, MII_BUS_ID_SIZE, "stmmac-%x",
- priv->plat->bus_id);
+ node = priv->plat->phylink_node;
- snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id,
- priv->plat->phy_addr);
- netdev_dbg(priv->dev, "%s: trying to attach to %s\n", __func__,
- phy_id_fmt);
+ if (node)
+ ret = phylink_of_phy_connect(priv->phylink, node, 0);
- phydev = phy_connect(dev, phy_id_fmt, &stmmac_adjust_link,
- interface);
- }
+ /* Some DT bindings do not set-up the PHY handle. Let's try to
+ * manually parse it
+ */
+ if (!node || ret) {
+ int addr = priv->plat->phy_addr;
+ struct phy_device *phydev;
- if (IS_ERR_OR_NULL(phydev)) {
- netdev_err(priv->dev, "Could not attach to PHY\n");
- if (!phydev)
+ phydev = mdiobus_get_phy(priv->mii, addr);
+ if (!phydev) {
+ netdev_err(priv->dev, "no phy at addr %d\n", addr);
return -ENODEV;
+ }
- return PTR_ERR(phydev);
+ ret = phylink_connect_phy(priv->phylink, phydev);
}
- /* Stop Advertising 1000BASE Capability if interface is not GMII */
- if ((interface == PHY_INTERFACE_MODE_MII) ||
- (interface == PHY_INTERFACE_MODE_RMII) ||
- (max_speed < 1000 && max_speed > 0))
- phy_set_max_speed(phydev, SPEED_100);
+ return ret;
+}
- /*
- * Half-duplex mode not supported with multiqueue
- * half-duplex can only works with single queue
- */
- if (tx_cnt > 1) {
- phy_remove_link_mode(phydev,
- ETHTOOL_LINK_MODE_10baseT_Half_BIT);
- phy_remove_link_mode(phydev,
- ETHTOOL_LINK_MODE_100baseT_Half_BIT);
- phy_remove_link_mode(phydev,
- ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
- }
+static int stmmac_phy_setup(struct stmmac_priv *priv)
+{
+ struct fwnode_handle *fwnode = of_fwnode_handle(priv->plat->phylink_node);
+ int mode = priv->plat->interface;
+ struct phylink *phylink;
- /*
- * Broken HW is sometimes missing the pull-up resistor on the
- * MDIO line, which results in reads to non-existent devices returning
- * 0 rather than 0xffff. Catch this here and treat 0 as a non-existent
- * device as well.
- * Note: phydev->phy_id is the result of reading the UID PHY registers.
- */
- if (!priv->plat->phy_node && phydev->phy_id == 0) {
- phy_disconnect(phydev);
- return -ENODEV;
- }
+ priv->phylink_config.dev = &priv->dev->dev;
+ priv->phylink_config.type = PHYLINK_NETDEV;
- /* stmmac_adjust_link will change this to PHY_IGNORE_INTERRUPT to avoid
- * subsequent PHY polling, make sure we force a link transition if
- * we have a UP/DOWN/UP transition
- */
- if (phydev->is_pseudo_fixed_link)
- phydev->irq = PHY_POLL;
+ phylink = phylink_create(&priv->phylink_config, fwnode,
+ mode, &stmmac_phylink_mac_ops);
+ if (IS_ERR(phylink))
+ return PTR_ERR(phylink);
- phy_attached_info(phydev);
+ priv->phylink = phylink;
return 0;
}
@@ -1192,26 +1197,14 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,
int i, gfp_t flags, u32 queue)
{
struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];
- struct sk_buff *skb;
+ struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i];
- skb = __netdev_alloc_skb_ip_align(priv->dev, priv->dma_buf_sz, flags);
- if (!skb) {
- netdev_err(priv->dev,
- "%s: Rx init fails; skb is NULL\n", __func__);
+ buf->page = page_pool_dev_alloc_pages(rx_q->page_pool);
+ if (!buf->page)
return -ENOMEM;
- }
- rx_q->rx_skbuff[i] = skb;
- rx_q->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data,
- priv->dma_buf_sz,
- DMA_FROM_DEVICE);
- if (dma_mapping_error(priv->device, rx_q->rx_skbuff_dma[i])) {
- netdev_err(priv->dev, "%s: DMA mapping error\n", __func__);
- dev_kfree_skb_any(skb);
- return -EINVAL;
- }
-
- stmmac_set_desc_addr(priv, p, rx_q->rx_skbuff_dma[i]);
+ buf->addr = page_pool_get_dma_addr(buf->page);
+ stmmac_set_desc_addr(priv, p, buf->addr);
if (priv->dma_buf_sz == BUF_SIZE_16KiB)
stmmac_init_desc3(priv, p);
@@ -1227,13 +1220,11 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,
static void stmmac_free_rx_buffer(struct stmmac_priv *priv, u32 queue, int i)
{
struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];
+ struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i];
- if (rx_q->rx_skbuff[i]) {
- dma_unmap_single(priv->device, rx_q->rx_skbuff_dma[i],
- priv->dma_buf_sz, DMA_FROM_DEVICE);
- dev_kfree_skb_any(rx_q->rx_skbuff[i]);
- }
- rx_q->rx_skbuff[i] = NULL;
+ if (buf->page)
+ page_pool_put_page(rx_q->page_pool, buf->page, false);
+ buf->page = NULL;
}
/**
@@ -1316,10 +1307,6 @@ static int init_dma_rx_desc_rings(struct net_device *dev, gfp_t flags)
queue);
if (ret)
goto err_init_rx_buffers;
-
- netif_dbg(priv, probe, priv->dev, "[%p]\t[%p]\t[%x]\n",
- rx_q->rx_skbuff[i], rx_q->rx_skbuff[i]->data,
- (unsigned int)rx_q->rx_skbuff_dma[i]);
}
rx_q->cur_rx = 0;
@@ -1493,8 +1480,11 @@ static void free_dma_rx_desc_resources(struct stmmac_priv *priv)
sizeof(struct dma_extended_desc),
rx_q->dma_erx, rx_q->dma_rx_phy);
- kfree(rx_q->rx_skbuff_dma);
- kfree(rx_q->rx_skbuff);
+ kfree(rx_q->buf_pool);
+ if (rx_q->page_pool) {
+ page_pool_request_shutdown(rx_q->page_pool);
+ page_pool_destroy(rx_q->page_pool);
+ }
}
}
@@ -1546,20 +1536,29 @@ static int alloc_dma_rx_desc_resources(struct stmmac_priv *priv)
/* RX queues buffers and DMA */
for (queue = 0; queue < rx_count; queue++) {
struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];
+ struct page_pool_params pp_params = { 0 };
rx_q->queue_index = queue;
rx_q->priv_data = priv;
- rx_q->rx_skbuff_dma = kmalloc_array(DMA_RX_SIZE,
- sizeof(dma_addr_t),
- GFP_KERNEL);
- if (!rx_q->rx_skbuff_dma)
+ pp_params.flags = PP_FLAG_DMA_MAP;
+ pp_params.pool_size = DMA_RX_SIZE;
+ pp_params.order = DIV_ROUND_UP(priv->dma_buf_sz, PAGE_SIZE);
+ pp_params.nid = dev_to_node(priv->device);
+ pp_params.dev = priv->device;
+ pp_params.dma_dir = DMA_FROM_DEVICE;
+
+ rx_q->page_pool = page_pool_create(&pp_params);
+ if (IS_ERR(rx_q->page_pool)) {
+ ret = PTR_ERR(rx_q->page_pool);
+ rx_q->page_pool = NULL;
goto err_dma;
+ }
- rx_q->rx_skbuff = kmalloc_array(DMA_RX_SIZE,
- sizeof(struct sk_buff *),
- GFP_KERNEL);
- if (!rx_q->rx_skbuff)
+ rx_q->buf_pool = kmalloc_array(DMA_RX_SIZE,
+ sizeof(*rx_q->buf_pool),
+ GFP_KERNEL);
+ if (!rx_q->buf_pool)
goto err_dma;
if (priv->extend_desc) {
@@ -2049,14 +2048,15 @@ static int stmmac_napi_check(struct stmmac_priv *priv, u32 chan)
struct stmmac_channel *ch = &priv->channel[chan];
if ((status & handle_rx) && (chan < priv->plat->rx_queues_to_use)) {
- stmmac_disable_dma_irq(priv, priv->ioaddr, chan);
- napi_schedule_irqoff(&ch->rx_napi);
+ if (napi_schedule_prep(&ch->rx_napi)) {
+ stmmac_disable_dma_irq(priv, priv->ioaddr, chan);
+ __napi_schedule_irqoff(&ch->rx_napi);
+ status |= handle_tx;
+ }
}
- if ((status & handle_tx) && (chan < priv->plat->tx_queues_to_use)) {
- stmmac_disable_dma_irq(priv, priv->ioaddr, chan);
+ if ((status & handle_tx) && (chan < priv->plat->tx_queues_to_use))
napi_schedule_irqoff(&ch->tx_napi);
- }
return status;
}
@@ -2118,10 +2118,10 @@ static void stmmac_mmc_setup(struct stmmac_priv *priv)
unsigned int mode = MMC_CNTRL_RESET_ON_READ | MMC_CNTRL_COUNTER_RESET |
MMC_CNTRL_PRESET | MMC_CNTRL_FULL_HALF_PRESET;
- dwmac_mmc_intr_all_mask(priv->mmcaddr);
+ stmmac_mmc_intr_all_mask(priv, priv->mmcaddr);
if (priv->dma_cap.rmon) {
- dwmac_mmc_ctrl(priv->mmcaddr, mode);
+ stmmac_mmc_ctrl(priv, priv->mmcaddr, mode);
memset(&priv->mmc, 0, sizeof(struct stmmac_counters));
} else
netdev_info(priv->dev, "No MAC Management Counters available\n");
@@ -2154,8 +2154,8 @@ static void stmmac_check_ether_addr(struct stmmac_priv *priv)
stmmac_get_umac_addr(priv, priv->hw, priv->dev->dev_addr, 0);
if (!is_valid_ether_addr(priv->dev->dev_addr))
eth_hw_addr_random(priv->dev);
- netdev_info(priv->dev, "device MAC address %pM\n",
- priv->dev->dev_addr);
+ dev_info(priv->device, "device MAC address %pM\n",
+ priv->dev->dev_addr);
}
}
@@ -2262,20 +2262,21 @@ static void stmmac_tx_timer(struct timer_list *t)
}
/**
- * stmmac_init_tx_coalesce - init tx mitigation options.
+ * stmmac_init_coalesce - init mitigation options.
* @priv: driver private structure
* Description:
- * This inits the transmit coalesce parameters: i.e. timer rate,
+ * This inits the coalesce parameters: i.e. timer rate,
* timer handler and default threshold used for enabling the
* interrupt on completion bit.
*/
-static void stmmac_init_tx_coalesce(struct stmmac_priv *priv)
+static void stmmac_init_coalesce(struct stmmac_priv *priv)
{
u32 tx_channel_count = priv->plat->tx_queues_to_use;
u32 chan;
priv->tx_coal_frames = STMMAC_TX_FRAMES;
priv->tx_coal_timer = STMMAC_COAL_TX_TIMER;
+ priv->rx_coal_frames = STMMAC_RX_FRAMES;
for (chan = 0; chan < tx_channel_count; chan++) {
struct stmmac_tx_queue *tx_q = &priv->tx_queue[chan];
@@ -2561,9 +2562,9 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS;
if (priv->use_riwt) {
- ret = stmmac_rx_watchdog(priv, priv->ioaddr, MAX_DMA_RIWT, rx_cnt);
+ ret = stmmac_rx_watchdog(priv, priv->ioaddr, MIN_DMA_RIWT, rx_cnt);
if (!ret)
- priv->rx_riwt = MAX_DMA_RIWT;
+ priv->rx_riwt = MIN_DMA_RIWT;
}
if (priv->hw->pcs)
@@ -2645,10 +2646,9 @@ static int stmmac_open(struct net_device *dev)
goto init_error;
}
- stmmac_init_tx_coalesce(priv);
+ stmmac_init_coalesce(priv);
- if (dev->phydev)
- phy_start(dev->phydev);
+ phylink_start(priv->phylink);
/* Request the IRQ lines */
ret = request_irq(dev->irq, stmmac_interrupt,
@@ -2695,8 +2695,7 @@ lpiirq_error:
wolirq_error:
free_irq(dev->irq, dev);
irq_error:
- if (dev->phydev)
- phy_stop(dev->phydev);
+ phylink_stop(priv->phylink);
for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++)
del_timer_sync(&priv->tx_queue[chan].txtimer);
@@ -2705,9 +2704,7 @@ irq_error:
init_error:
free_dma_desc_resources(priv);
dma_desc_error:
- if (dev->phydev)
- phy_disconnect(dev->phydev);
-
+ phylink_disconnect_phy(priv->phylink);
return ret;
}
@@ -2726,10 +2723,8 @@ static int stmmac_release(struct net_device *dev)
del_timer_sync(&priv->eee_ctrl_timer);
/* Stop and disconnect the PHY */
- if (dev->phydev) {
- phy_stop(dev->phydev);
- phy_disconnect(dev->phydev);
- }
+ phylink_stop(priv->phylink);
+ phylink_disconnect_phy(priv->phylink);
stmmac_stop_all_queues(priv);
@@ -2772,7 +2767,7 @@ static int stmmac_release(struct net_device *dev)
* This function fills descriptor and request new descriptors according to
* buffer length to fill
*/
-static void stmmac_tso_allocator(struct stmmac_priv *priv, unsigned int des,
+static void stmmac_tso_allocator(struct stmmac_priv *priv, dma_addr_t des,
int total_len, bool last_segment, u32 queue)
{
struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue];
@@ -2783,11 +2778,18 @@ static void stmmac_tso_allocator(struct stmmac_priv *priv, unsigned int des,
tmp_len = total_len;
while (tmp_len > 0) {
+ dma_addr_t curr_addr;
+
tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, DMA_TX_SIZE);
WARN_ON(tx_q->tx_skbuff[tx_q->cur_tx]);
desc = tx_q->dma_tx + tx_q->cur_tx;
- desc->des0 = cpu_to_le32(des + (total_len - tmp_len));
+ curr_addr = des + (total_len - tmp_len);
+ if (priv->dma_cap.addr64 <= 32)
+ desc->des0 = cpu_to_le32(curr_addr);
+ else
+ stmmac_set_desc_addr(priv, desc, curr_addr);
+
buff_size = tmp_len >= TSO_MAX_BUFF_SIZE ?
TSO_MAX_BUFF_SIZE : tmp_len;
@@ -2833,11 +2835,12 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
struct stmmac_priv *priv = netdev_priv(dev);
int nfrags = skb_shinfo(skb)->nr_frags;
u32 queue = skb_get_queue_mapping(skb);
- unsigned int first_entry, des;
+ unsigned int first_entry;
struct stmmac_tx_queue *tx_q;
int tmp_pay_len = 0;
u32 pay_len, mss;
u8 proto_hdr_len;
+ dma_addr_t des;
int i;
tx_q = &priv->tx_queue[queue];
@@ -2894,14 +2897,19 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
tx_q->tx_skbuff_dma[first_entry].buf = des;
tx_q->tx_skbuff_dma[first_entry].len = skb_headlen(skb);
- first->des0 = cpu_to_le32(des);
+ if (priv->dma_cap.addr64 <= 32) {
+ first->des0 = cpu_to_le32(des);
- /* Fill start of payload in buff2 of first descriptor */
- if (pay_len)
- first->des1 = cpu_to_le32(des + proto_hdr_len);
+ /* Fill start of payload in buff2 of first descriptor */
+ if (pay_len)
+ first->des1 = cpu_to_le32(des + proto_hdr_len);
- /* If needed take extra descriptors to fill the remaining payload */
- tmp_pay_len = pay_len - TSO_MAX_BUFF_SIZE;
+ /* If needed take extra descriptors to fill the remaining payload */
+ tmp_pay_len = pay_len - TSO_MAX_BUFF_SIZE;
+ } else {
+ stmmac_set_desc_addr(priv, first, des);
+ tmp_pay_len = pay_len;
+ }
stmmac_tso_allocator(priv, des, tmp_pay_len, (nfrags == 0), queue);
@@ -2947,12 +2955,15 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
/* Manage tx mitigation */
tx_q->tx_count_frames += nfrags + 1;
- if (priv->tx_coal_frames <= tx_q->tx_count_frames) {
+ if (likely(priv->tx_coal_frames > tx_q->tx_count_frames) &&
+ !(priv->synopsys_id >= DWMAC_CORE_4_00 &&
+ (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
+ priv->hwts_tx_en)) {
+ stmmac_tx_timer_arm(priv, queue);
+ } else {
+ tx_q->tx_count_frames = 0;
stmmac_set_tx_ic(priv, desc);
priv->xstats.tx_set_ic_bit++;
- tx_q->tx_count_frames = 0;
- } else {
- stmmac_tx_timer_arm(priv, queue);
}
skb_tx_timestamp(skb);
@@ -3028,12 +3039,12 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
int i, csum_insertion = 0, is_jumbo = 0;
u32 queue = skb_get_queue_mapping(skb);
int nfrags = skb_shinfo(skb)->nr_frags;
- int entry;
- unsigned int first_entry;
struct dma_desc *desc, *first;
struct stmmac_tx_queue *tx_q;
+ unsigned int first_entry;
unsigned int enh_desc;
- unsigned int des;
+ dma_addr_t des;
+ int entry;
tx_q = &priv->tx_queue[queue];
@@ -3042,17 +3053,8 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
/* Manage oversized TCP frames for GMAC4 device */
if (skb_is_gso(skb) && priv->tso) {
- if (skb_shinfo(skb)->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) {
- /*
- * There is no way to determine the number of TSO
- * capable Queues. Let's use always the Queue 0
- * because if TSO is supported then at least this
- * one will be capable.
- */
- skb_set_queue_mapping(skb, 0);
-
+ if (skb_shinfo(skb)->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))
return stmmac_tso_xmit(skb, dev);
- }
}
if (unlikely(stmmac_tx_avail(priv, queue) < nfrags + 1)) {
@@ -3166,12 +3168,15 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
* element in case of no SG.
*/
tx_q->tx_count_frames += nfrags + 1;
- if (priv->tx_coal_frames <= tx_q->tx_count_frames) {
+ if (likely(priv->tx_coal_frames > tx_q->tx_count_frames) &&
+ !(priv->synopsys_id >= DWMAC_CORE_4_00 &&
+ (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
+ priv->hwts_tx_en)) {
+ stmmac_tx_timer_arm(priv, queue);
+ } else {
+ tx_q->tx_count_frames = 0;
stmmac_set_tx_ic(priv, desc);
priv->xstats.tx_set_ic_bit++;
- tx_q->tx_count_frames = 0;
- } else {
- stmmac_tx_timer_arm(priv, queue);
}
skb_tx_timestamp(skb);
@@ -3275,59 +3280,38 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue)
int dirty = stmmac_rx_dirty(priv, queue);
unsigned int entry = rx_q->dirty_rx;
- int bfsize = priv->dma_buf_sz;
-
while (dirty-- > 0) {
+ struct stmmac_rx_buffer *buf = &rx_q->buf_pool[entry];
struct dma_desc *p;
+ bool use_rx_wd;
if (priv->extend_desc)
p = (struct dma_desc *)(rx_q->dma_erx + entry);
else
p = rx_q->dma_rx + entry;
- if (likely(!rx_q->rx_skbuff[entry])) {
- struct sk_buff *skb;
-
- skb = netdev_alloc_skb_ip_align(priv->dev, bfsize);
- if (unlikely(!skb)) {
- /* so for a while no zero-copy! */
- rx_q->rx_zeroc_thresh = STMMAC_RX_THRESH;
- if (unlikely(net_ratelimit()))
- dev_err(priv->device,
- "fail to alloc skb entry %d\n",
- entry);
- break;
- }
-
- rx_q->rx_skbuff[entry] = skb;
- rx_q->rx_skbuff_dma[entry] =
- dma_map_single(priv->device, skb->data, bfsize,
- DMA_FROM_DEVICE);
- if (dma_mapping_error(priv->device,
- rx_q->rx_skbuff_dma[entry])) {
- netdev_err(priv->dev, "Rx DMA map failed\n");
- dev_kfree_skb(skb);
+ if (!buf->page) {
+ buf->page = page_pool_dev_alloc_pages(rx_q->page_pool);
+ if (!buf->page)
break;
- }
-
- stmmac_set_desc_addr(priv, p, rx_q->rx_skbuff_dma[entry]);
- stmmac_refill_desc3(priv, rx_q, p);
-
- if (rx_q->rx_zeroc_thresh > 0)
- rx_q->rx_zeroc_thresh--;
-
- netif_dbg(priv, rx_status, priv->dev,
- "refill entry #%d\n", entry);
}
- dma_wmb();
- stmmac_set_rx_owner(priv, p, priv->use_riwt);
+ buf->addr = page_pool_get_dma_addr(buf->page);
+ stmmac_set_desc_addr(priv, p, buf->addr);
+ stmmac_refill_desc3(priv, rx_q, p);
+
+ rx_q->rx_count_frames++;
+ rx_q->rx_count_frames %= priv->rx_coal_frames;
+ use_rx_wd = priv->use_riwt && rx_q->rx_count_frames;
dma_wmb();
+ stmmac_set_rx_owner(priv, p, use_rx_wd);
entry = STMMAC_GET_ENTRY(entry, DMA_RX_SIZE);
}
rx_q->dirty_rx = entry;
+ rx_q->rx_tail_addr = rx_q->dma_rx_phy +
+ (rx_q->dirty_rx * sizeof(struct dma_desc));
stmmac_set_rx_tail_ptr(priv, priv->ioaddr, rx_q->rx_tail_addr, queue);
}
@@ -3346,9 +3330,6 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
unsigned int next_entry = rx_q->cur_rx;
int coe = priv->hw->rx_csum;
unsigned int count = 0;
- bool xmac;
-
- xmac = priv->plat->has_gmac4 || priv->plat->has_xgmac;
if (netif_msg_rx_status(priv)) {
void *rx_head;
@@ -3362,11 +3343,12 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
stmmac_display_ring(priv, rx_head, DMA_RX_SIZE, true);
}
while (count < limit) {
+ struct stmmac_rx_buffer *buf;
+ struct dma_desc *np, *p;
int entry, status;
- struct dma_desc *p;
- struct dma_desc *np;
entry = next_entry;
+ buf = &rx_q->buf_pool[entry];
if (priv->extend_desc)
p = (struct dma_desc *)(rx_q->dma_erx + entry);
@@ -3396,20 +3378,9 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
stmmac_rx_extended_status(priv, &priv->dev->stats,
&priv->xstats, rx_q->dma_erx + entry);
if (unlikely(status == discard_frame)) {
+ page_pool_recycle_direct(rx_q->page_pool, buf->page);
priv->dev->stats.rx_errors++;
- if (priv->hwts_rx_en && !priv->extend_desc) {
- /* DESC2 & DESC3 will be overwritten by device
- * with timestamp value, hence reinitialize
- * them in stmmac_rx_refill() function so that
- * device can reuse it.
- */
- dev_kfree_skb_any(rx_q->rx_skbuff[entry]);
- rx_q->rx_skbuff[entry] = NULL;
- dma_unmap_single(priv->device,
- rx_q->rx_skbuff_dma[entry],
- priv->dma_buf_sz,
- DMA_FROM_DEVICE);
- }
+ buf->page = NULL;
} else {
struct sk_buff *skb;
int frame_len;
@@ -3449,58 +3420,20 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
frame_len, status);
}
- /* The zero-copy is always used for all the sizes
- * in case of GMAC4 because it needs
- * to refill the used descriptors, always.
- */
- if (unlikely(!xmac &&
- ((frame_len < priv->rx_copybreak) ||
- stmmac_rx_threshold_count(rx_q)))) {
- skb = netdev_alloc_skb_ip_align(priv->dev,
- frame_len);
- if (unlikely(!skb)) {
- if (net_ratelimit())
- dev_warn(priv->device,
- "packet dropped\n");
- priv->dev->stats.rx_dropped++;
- continue;
- }
-
- dma_sync_single_for_cpu(priv->device,
- rx_q->rx_skbuff_dma
- [entry], frame_len,
- DMA_FROM_DEVICE);
- skb_copy_to_linear_data(skb,
- rx_q->
- rx_skbuff[entry]->data,
- frame_len);
-
- skb_put(skb, frame_len);
- dma_sync_single_for_device(priv->device,
- rx_q->rx_skbuff_dma
- [entry], frame_len,
- DMA_FROM_DEVICE);
- } else {
- skb = rx_q->rx_skbuff[entry];
- if (unlikely(!skb)) {
- if (net_ratelimit())
- netdev_err(priv->dev,
- "%s: Inconsistent Rx chain\n",
- priv->dev->name);
- priv->dev->stats.rx_dropped++;
- continue;
- }
- prefetch(skb->data - NET_IP_ALIGN);
- rx_q->rx_skbuff[entry] = NULL;
- rx_q->rx_zeroc_thresh++;
-
- skb_put(skb, frame_len);
- dma_unmap_single(priv->device,
- rx_q->rx_skbuff_dma[entry],
- priv->dma_buf_sz,
- DMA_FROM_DEVICE);
+ skb = netdev_alloc_skb_ip_align(priv->dev, frame_len);
+ if (unlikely(!skb)) {
+ priv->dev->stats.rx_dropped++;
+ continue;
}
+ dma_sync_single_for_cpu(priv->device, buf->addr,
+ frame_len, DMA_FROM_DEVICE);
+ skb_copy_to_linear_data(skb, page_address(buf->page),
+ frame_len);
+ skb_put(skb, frame_len);
+ dma_sync_single_for_device(priv->device, buf->addr,
+ frame_len, DMA_FROM_DEVICE);
+
if (netif_msg_pktdata(priv)) {
netdev_dbg(priv->dev, "frame received (%dbytes)",
frame_len);
@@ -3520,6 +3453,10 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
napi_gro_receive(&ch->rx_napi, skb);
+ /* Data payload copied into SKB, page ready for recycle */
+ page_pool_recycle_direct(rx_q->page_pool, buf->page);
+ buf->page = NULL;
+
priv->dev->stats.rx_packets++;
priv->dev->stats.rx_bytes += frame_len;
}
@@ -3562,8 +3499,8 @@ static int stmmac_napi_poll_tx(struct napi_struct *napi, int budget)
work_done = stmmac_tx_clean(priv, DMA_TX_SIZE, chan);
work_done = min(work_done, budget);
- if (work_done < budget && napi_complete_done(napi, work_done))
- stmmac_enable_dma_irq(priv, priv->ioaddr, chan);
+ if (work_done < budget)
+ napi_complete_done(napi, work_done);
/* Force transmission restart */
tx_q = &priv->tx_queue[chan];
@@ -3786,6 +3723,7 @@ static void stmmac_poll_controller(struct net_device *dev)
*/
static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
+ struct stmmac_priv *priv = netdev_priv (dev);
int ret = -EOPNOTSUPP;
if (!netif_running(dev))
@@ -3795,9 +3733,7 @@ static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
case SIOCGMIIPHY:
case SIOCGMIIREG:
case SIOCSMIIREG:
- if (!dev->phydev)
- return -EINVAL;
- ret = phy_mii_ioctl(dev->phydev, rq, cmd);
+ ret = phylink_mii_ioctl(priv->phylink, rq, cmd);
break;
case SIOCSHWTSTAMP:
ret = stmmac_hwtstamp_set(dev, rq);
@@ -3833,23 +3769,7 @@ static int stmmac_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
return ret;
}
-static int stmmac_setup_tc_block(struct stmmac_priv *priv,
- struct tc_block_offload *f)
-{
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
- return -EOPNOTSUPP;
-
- switch (f->command) {
- case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block, stmmac_setup_tc_block_cb,
- priv, priv, f->extack);
- case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block, stmmac_setup_tc_block_cb, priv);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-}
+static LIST_HEAD(stmmac_block_cb_list);
static int stmmac_setup_tc(struct net_device *ndev, enum tc_setup_type type,
void *type_data)
@@ -3858,7 +3778,10 @@ static int stmmac_setup_tc(struct net_device *ndev, enum tc_setup_type type,
switch (type) {
case TC_SETUP_BLOCK:
- return stmmac_setup_tc_block(priv, type_data);
+ return flow_block_cb_setup_simple(type_data,
+ &stmmac_block_cb_list,
+ stmmac_setup_tc_block_cb,
+ priv, priv, true);
case TC_SETUP_QDISC_CBS:
return stmmac_tc_setup_cbs(priv, priv, type_data);
default:
@@ -3866,6 +3789,22 @@ static int stmmac_setup_tc(struct net_device *ndev, enum tc_setup_type type,
}
}
+static u16 stmmac_select_queue(struct net_device *dev, struct sk_buff *skb,
+ struct net_device *sb_dev)
+{
+ if (skb_shinfo(skb)->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) {
+ /*
+ * There is no way to determine the number of TSO
+ * capable Queues. Let's use always the Queue 0
+ * because if TSO is supported then at least this
+ * one will be capable.
+ */
+ return 0;
+ }
+
+ return netdev_pick_tx(dev, skb, NULL) % dev->real_num_tx_queues;
+}
+
static int stmmac_set_mac_address(struct net_device *ndev, void *addr)
{
struct stmmac_priv *priv = netdev_priv(ndev);
@@ -4082,6 +4021,7 @@ static const struct net_device_ops stmmac_netdev_ops = {
.ndo_tx_timeout = stmmac_tx_timeout,
.ndo_do_ioctl = stmmac_ioctl,
.ndo_setup_tc = stmmac_setup_tc,
+ .ndo_select_queue = stmmac_select_queue,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = stmmac_poll_controller,
#endif
@@ -4154,6 +4094,12 @@ 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->hw->pmt = priv->plat->pmt;
+ if (priv->dma_cap.hash_tb_sz) {
+ priv->hw->multicast_filter_bins =
+ (BIT(priv->dma_cap.hash_tb_sz) << 5);
+ priv->hw->mcast_bits_log2 =
+ ilog2(priv->hw->multicast_filter_bins);
+ }
/* TXCOE doesn't work in thresh DMA mode */
if (priv->plat->force_thresh_dma_mode)
@@ -4231,9 +4177,8 @@ int stmmac_dvr_probe(struct device *device,
u32 queue, maxq;
int ret = 0;
- ndev = alloc_etherdev_mqs(sizeof(struct stmmac_priv),
- MTL_MAX_TX_QUEUES,
- MTL_MAX_RX_QUEUES);
+ ndev = devm_alloc_etherdev_mqs(device, sizeof(struct stmmac_priv),
+ MTL_MAX_TX_QUEUES, MTL_MAX_RX_QUEUES);
if (!ndev)
return -ENOMEM;
@@ -4265,8 +4210,7 @@ int stmmac_dvr_probe(struct device *device,
priv->wq = create_singlethread_workqueue("stmmac_wq");
if (!priv->wq) {
dev_err(priv->device, "failed to create workqueue\n");
- ret = -ENOMEM;
- goto error_wq;
+ return -ENOMEM;
}
INIT_WORK(&priv->service_task, stmmac_service_task);
@@ -4313,6 +4257,24 @@ int stmmac_dvr_probe(struct device *device,
priv->tso = true;
dev_info(priv->device, "TSO feature enabled\n");
}
+
+ if (priv->dma_cap.addr64) {
+ ret = dma_set_mask_and_coherent(device,
+ DMA_BIT_MASK(priv->dma_cap.addr64));
+ if (!ret) {
+ dev_info(priv->device, "Using %d bits DMA width\n",
+ priv->dma_cap.addr64);
+ } else {
+ ret = dma_set_mask_and_coherent(device, DMA_BIT_MASK(32));
+ if (ret) {
+ dev_err(priv->device, "Failed to set DMA Mask\n");
+ goto error_hw_init;
+ }
+
+ priv->dma_cap.addr64 = 32;
+ }
+ }
+
ndev->features |= ndev->hw_features | NETIF_F_HIGHDMA;
ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
#ifdef STMMAC_VLAN_TAG_USED
@@ -4390,6 +4352,12 @@ int stmmac_dvr_probe(struct device *device,
}
}
+ ret = stmmac_phy_setup(priv);
+ if (ret) {
+ netdev_err(ndev, "failed to setup phy (%d)\n", ret);
+ goto error_phy_setup;
+ }
+
ret = register_netdev(ndev);
if (ret) {
dev_err(priv->device, "%s: ERROR %i registering the device\n",
@@ -4407,6 +4375,8 @@ int stmmac_dvr_probe(struct device *device,
return ret;
error_netdev_register:
+ phylink_destroy(priv->phylink);
+error_phy_setup:
if (priv->hw->pcs != STMMAC_PCS_RGMII &&
priv->hw->pcs != STMMAC_PCS_TBI &&
priv->hw->pcs != STMMAC_PCS_RTBI)
@@ -4422,8 +4392,6 @@ error_mdio_register:
}
error_hw_init:
destroy_workqueue(priv->wq);
-error_wq:
- free_netdev(ndev);
return ret;
}
@@ -4450,6 +4418,7 @@ int stmmac_dvr_remove(struct device *dev)
stmmac_mac_set(priv, priv->ioaddr, false);
netif_carrier_off(ndev);
unregister_netdev(ndev);
+ phylink_destroy(priv->phylink);
if (priv->plat->stmmac_rst)
reset_control_assert(priv->plat->stmmac_rst);
clk_disable_unprepare(priv->plat->pclk);
@@ -4460,7 +4429,6 @@ int stmmac_dvr_remove(struct device *dev)
stmmac_mdio_unregister(ndev);
destroy_workqueue(priv->wq);
mutex_destroy(&priv->lock);
- free_netdev(ndev);
return 0;
}
@@ -4481,8 +4449,7 @@ int stmmac_suspend(struct device *dev)
if (!ndev || !netif_running(ndev))
return 0;
- if (ndev->phydev)
- phy_stop(ndev->phydev);
+ phylink_stop(priv->phylink);
mutex_lock(&priv->lock);
@@ -4507,9 +4474,7 @@ int stmmac_suspend(struct device *dev)
}
mutex_unlock(&priv->lock);
- priv->oldlink = false;
priv->speed = SPEED_UNKNOWN;
- priv->oldduplex = DUPLEX_UNKNOWN;
return 0;
}
EXPORT_SYMBOL_GPL(stmmac_suspend);
@@ -4584,7 +4549,7 @@ int stmmac_resume(struct device *dev)
stmmac_clear_descriptors(priv);
stmmac_hw_setup(ndev, false);
- stmmac_init_tx_coalesce(priv);
+ stmmac_init_coalesce(priv);
stmmac_set_rx_mode(ndev);
stmmac_enable_all_queues(priv);
@@ -4593,8 +4558,7 @@ int stmmac_resume(struct device *dev)
mutex_unlock(&priv->lock);
- if (ndev->phydev)
- phy_start(ndev->phydev);
+ phylink_start(priv->phylink);
return 0;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
index 1341bb5f693c..4304c1abc5d1 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
@@ -10,13 +10,13 @@
Maintainer: Giuseppe Cavallaro <peppe.cavallaro@st.com>
*******************************************************************************/
+#include <linux/gpio/consumer.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/mii.h>
-#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/of_mdio.h>
#include <linux/phy.h>
+#include <linux/property.h>
#include <linux/slab.h>
#include "dwxgmac2.h"
@@ -24,11 +24,14 @@
#define MII_BUSY 0x00000001
#define MII_WRITE 0x00000002
+#define MII_DATA_MASK GENMASK(15, 0)
/* GMAC4 defines */
#define MII_GMAC4_GOC_SHIFT 2
+#define MII_GMAC4_REG_ADDR_SHIFT 16
#define MII_GMAC4_WRITE (1 << MII_GMAC4_GOC_SHIFT)
#define MII_GMAC4_READ (3 << MII_GMAC4_GOC_SHIFT)
+#define MII_GMAC4_C45E BIT(1)
/* XGMAC defines */
#define MII_XGMAC_SADDR BIT(18)
@@ -155,22 +158,34 @@ static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
struct stmmac_priv *priv = netdev_priv(ndev);
unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data;
- u32 v;
- int data;
u32 value = MII_BUSY;
+ int data = 0;
+ u32 v;
value |= (phyaddr << priv->hw->mii.addr_shift)
& priv->hw->mii.addr_mask;
value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
& priv->hw->mii.clk_csr_mask;
- if (priv->plat->has_gmac4)
+ if (priv->plat->has_gmac4) {
value |= MII_GMAC4_READ;
+ if (phyreg & MII_ADDR_C45) {
+ value |= MII_GMAC4_C45E;
+ value &= ~priv->hw->mii.reg_mask;
+ value |= ((phyreg >> MII_DEVADDR_C45_SHIFT) <<
+ priv->hw->mii.reg_shift) &
+ priv->hw->mii.reg_mask;
+
+ data |= (phyreg & MII_REGADDR_C45_MASK) <<
+ MII_GMAC4_REG_ADDR_SHIFT;
+ }
+ }
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
100, 10000))
return -EBUSY;
+ writel(data, priv->ioaddr + mii_data);
writel(value, priv->ioaddr + mii_address);
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
@@ -178,7 +193,7 @@ static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
return -EBUSY;
/* Read the data from the MII data register */
- data = (int)readl(priv->ioaddr + mii_data);
+ data = (int)readl(priv->ioaddr + mii_data) & MII_DATA_MASK;
return data;
}
@@ -198,8 +213,9 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
struct stmmac_priv *priv = netdev_priv(ndev);
unsigned int mii_address = priv->hw->mii.addr;
unsigned int mii_data = priv->hw->mii.data;
- u32 v;
u32 value = MII_BUSY;
+ int data = phydata;
+ u32 v;
value |= (phyaddr << priv->hw->mii.addr_shift)
& priv->hw->mii.addr_mask;
@@ -207,10 +223,21 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
& priv->hw->mii.clk_csr_mask;
- if (priv->plat->has_gmac4)
+ if (priv->plat->has_gmac4) {
value |= MII_GMAC4_WRITE;
- else
+ if (phyreg & MII_ADDR_C45) {
+ value |= MII_GMAC4_C45E;
+ value &= ~priv->hw->mii.reg_mask;
+ value |= ((phyreg >> MII_DEVADDR_C45_SHIFT) <<
+ priv->hw->mii.reg_shift) &
+ priv->hw->mii.reg_mask;
+
+ data |= (phyreg & MII_REGADDR_C45_MASK) <<
+ MII_GMAC4_REG_ADDR_SHIFT;
+ }
+ } else {
value |= MII_WRITE;
+ }
/* Wait until any existing MII operation is complete */
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
@@ -218,7 +245,7 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
return -EBUSY;
/* Set the MII address register to write */
- writel(phydata, priv->ioaddr + mii_data);
+ writel(data, priv->ioaddr + mii_data);
writel(value, priv->ioaddr + mii_address);
/* Wait until any existing MII operation is complete */
@@ -237,51 +264,35 @@ int stmmac_mdio_reset(struct mii_bus *bus)
struct net_device *ndev = bus->priv;
struct stmmac_priv *priv = netdev_priv(ndev);
unsigned int mii_address = priv->hw->mii.addr;
- struct stmmac_mdio_bus_data *data = priv->plat->mdio_bus_data;
#ifdef CONFIG_OF
if (priv->device->of_node) {
- if (data->reset_gpio < 0) {
- struct device_node *np = priv->device->of_node;
+ struct gpio_desc *reset_gpio;
+ u32 delays[3] = { 0, 0, 0 };
- if (!np)
- return 0;
+ reset_gpio = devm_gpiod_get_optional(priv->device,
+ "snps,reset",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(reset_gpio))
+ return PTR_ERR(reset_gpio);
- data->reset_gpio = of_get_named_gpio(np,
- "snps,reset-gpio", 0);
- if (data->reset_gpio < 0)
- return 0;
+ device_property_read_u32_array(priv->device,
+ "snps,reset-delays-us",
+ delays, ARRAY_SIZE(delays));
- data->active_low = of_property_read_bool(np,
- "snps,reset-active-low");
- of_property_read_u32_array(np,
- "snps,reset-delays-us", data->delays, 3);
+ if (delays[0])
+ msleep(DIV_ROUND_UP(delays[0], 1000));
- if (devm_gpio_request(priv->device, data->reset_gpio,
- "mdio-reset"))
- return 0;
- }
-
- gpio_direction_output(data->reset_gpio,
- data->active_low ? 1 : 0);
- if (data->delays[0])
- msleep(DIV_ROUND_UP(data->delays[0], 1000));
+ gpiod_set_value_cansleep(reset_gpio, 1);
+ if (delays[1])
+ msleep(DIV_ROUND_UP(delays[1], 1000));
- gpio_set_value(data->reset_gpio, data->active_low ? 0 : 1);
- if (data->delays[1])
- msleep(DIV_ROUND_UP(data->delays[1], 1000));
-
- gpio_set_value(data->reset_gpio, data->active_low ? 1 : 0);
- if (data->delays[2])
- msleep(DIV_ROUND_UP(data->delays[2], 1000));
+ gpiod_set_value_cansleep(reset_gpio, 0);
+ if (delays[2])
+ msleep(DIV_ROUND_UP(delays[2], 1000));
}
#endif
- if (data->phy_reset) {
- netdev_dbg(ndev, "stmmac_mdio_reset: calling phy_reset\n");
- data->phy_reset(priv->plat->bsp_priv);
- }
-
/* This is a workaround for problems with the STE101P PHY.
* It doesn't complete its reset until at least one clock cycle
* on MDC, so perform a dummy mdio read. To be updated for GMAC4
@@ -318,11 +329,6 @@ int stmmac_mdio_register(struct net_device *ndev)
if (mdio_bus_data->irqs)
memcpy(new_bus->irq, mdio_bus_data->irqs, sizeof(new_bus->irq));
-#ifdef CONFIG_OF
- if (priv->device->of_node)
- mdio_bus_data->reset_gpio = -1;
-#endif
-
new_bus->name = "stmmac";
if (priv->plat->has_xgmac) {
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
index 0bd72739a071..86f9c07a38cf 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
@@ -63,7 +63,6 @@ static void common_default_data(struct plat_stmmacenet_data *plat)
plat->has_gmac = 1;
plat->force_sf_dma_mode = 1;
- plat->mdio_bus_data->phy_reset = NULL;
plat->mdio_bus_data->phy_mask = 0;
/* 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 0f0f4b31eb7e..73fc2524372e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -323,21 +323,6 @@ static int stmmac_dt_phy(struct plat_stmmacenet_data *plat,
{},
};
- /* If phy-handle property is passed from DT, use it as the PHY */
- plat->phy_node = of_parse_phandle(np, "phy-handle", 0);
- if (plat->phy_node)
- dev_dbg(dev, "Found phy-handle subnode\n");
-
- /* If phy-handle is not specified, check if we have a fixed-phy */
- if (!plat->phy_node && of_phy_is_fixed_link(np)) {
- if ((of_phy_register_fixed_link(np) < 0))
- return -ENODEV;
-
- dev_dbg(dev, "Found fixed-link subnode\n");
- plat->phy_node = of_node_get(np);
- mdio = false;
- }
-
if (of_match_node(need_mdio_ids, np)) {
plat->mdio_node = of_get_child_by_name(np, "mdio");
} else {
@@ -387,6 +372,13 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
*mac = of_get_mac_address(np);
plat->interface = of_get_phy_mode(np);
+ /* 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;
+
/* Get max speed of operation from device tree */
if (of_property_read_u32(np, "max-speed", &plat->max_speed))
plat->max_speed = -1;
@@ -581,10 +573,6 @@ error_pclk_get:
void stmmac_remove_config_dt(struct platform_device *pdev,
struct plat_stmmacenet_data *plat)
{
- struct device_node *np = pdev->dev.of_node;
-
- if (of_phy_is_fixed_link(np))
- of_phy_deregister_fixed_link(np);
of_node_put(plat->phy_node);
of_node_put(plat->mdio_node);
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c
new file mode 100644
index 000000000000..a97b1ea76438
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c
@@ -0,0 +1,850 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Synopsys, Inc. and/or its affiliates.
+ * stmmac Selftests Support
+ *
+ * Author: Jose Abreu <joabreu@synopsys.com>
+ */
+
+#include <linux/completion.h>
+#include <linux/ethtool.h>
+#include <linux/ip.h>
+#include <linux/phy.h>
+#include <linux/udp.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include "stmmac.h"
+
+struct stmmachdr {
+ __be32 version;
+ __be64 magic;
+ u8 id;
+} __packed;
+
+#define STMMAC_TEST_PKT_SIZE (sizeof(struct ethhdr) + sizeof(struct iphdr) + \
+ sizeof(struct stmmachdr))
+#define STMMAC_TEST_PKT_MAGIC 0xdeadcafecafedeadULL
+#define STMMAC_LB_TIMEOUT msecs_to_jiffies(200)
+
+struct stmmac_packet_attrs {
+ int vlan;
+ int vlan_id_in;
+ int vlan_id_out;
+ unsigned char *src;
+ unsigned char *dst;
+ u32 ip_src;
+ u32 ip_dst;
+ int tcp;
+ int sport;
+ int dport;
+ u32 exp_hash;
+ int dont_wait;
+ int timeout;
+ int size;
+ int remove_sa;
+ u8 id;
+};
+
+static u8 stmmac_test_next_id;
+
+static struct sk_buff *stmmac_test_get_udp_skb(struct stmmac_priv *priv,
+ struct stmmac_packet_attrs *attr)
+{
+ struct sk_buff *skb = NULL;
+ struct udphdr *uhdr = NULL;
+ struct tcphdr *thdr = NULL;
+ struct stmmachdr *shdr;
+ struct ethhdr *ehdr;
+ struct iphdr *ihdr;
+ int iplen, size;
+
+ size = attr->size + STMMAC_TEST_PKT_SIZE;
+ if (attr->vlan) {
+ size += 4;
+ if (attr->vlan > 1)
+ size += 4;
+ }
+
+ if (attr->tcp)
+ size += sizeof(struct tcphdr);
+ else
+ size += sizeof(struct udphdr);
+
+ skb = netdev_alloc_skb(priv->dev, size);
+ if (!skb)
+ return NULL;
+
+ prefetchw(skb->data);
+ skb_reserve(skb, NET_IP_ALIGN);
+
+ if (attr->vlan > 1)
+ ehdr = skb_push(skb, ETH_HLEN + 8);
+ else if (attr->vlan)
+ ehdr = skb_push(skb, ETH_HLEN + 4);
+ else if (attr->remove_sa)
+ ehdr = skb_push(skb, ETH_HLEN - 6);
+ else
+ ehdr = skb_push(skb, ETH_HLEN);
+ skb_reset_mac_header(skb);
+
+ skb_set_network_header(skb, skb->len);
+ ihdr = skb_put(skb, sizeof(*ihdr));
+
+ skb_set_transport_header(skb, skb->len);
+ if (attr->tcp)
+ thdr = skb_put(skb, sizeof(*thdr));
+ else
+ uhdr = skb_put(skb, sizeof(*uhdr));
+
+ if (!attr->remove_sa)
+ eth_zero_addr(ehdr->h_source);
+ eth_zero_addr(ehdr->h_dest);
+ if (attr->src && !attr->remove_sa)
+ ether_addr_copy(ehdr->h_source, attr->src);
+ if (attr->dst)
+ ether_addr_copy(ehdr->h_dest, attr->dst);
+
+ if (!attr->remove_sa) {
+ ehdr->h_proto = htons(ETH_P_IP);
+ } else {
+ __be16 *ptr = (__be16 *)ehdr;
+
+ /* HACK */
+ ptr[3] = htons(ETH_P_IP);
+ }
+
+ if (attr->vlan) {
+ __be16 *tag, *proto;
+
+ if (!attr->remove_sa) {
+ tag = (void *)ehdr + ETH_HLEN;
+ proto = (void *)ehdr + (2 * ETH_ALEN);
+ } else {
+ tag = (void *)ehdr + ETH_HLEN - 6;
+ proto = (void *)ehdr + ETH_ALEN;
+ }
+
+ proto[0] = htons(ETH_P_8021Q);
+ tag[0] = htons(attr->vlan_id_out);
+ tag[1] = htons(ETH_P_IP);
+ if (attr->vlan > 1) {
+ proto[0] = htons(ETH_P_8021AD);
+ tag[1] = htons(ETH_P_8021Q);
+ tag[2] = htons(attr->vlan_id_in);
+ tag[3] = htons(ETH_P_IP);
+ }
+ }
+
+ if (attr->tcp) {
+ thdr->source = htons(attr->sport);
+ thdr->dest = htons(attr->dport);
+ thdr->doff = sizeof(struct tcphdr) / 4;
+ thdr->check = 0;
+ } else {
+ uhdr->source = htons(attr->sport);
+ uhdr->dest = htons(attr->dport);
+ uhdr->len = htons(sizeof(*shdr) + sizeof(*uhdr) + attr->size);
+ uhdr->check = 0;
+ }
+
+ ihdr->ihl = 5;
+ ihdr->ttl = 32;
+ ihdr->version = 4;
+ if (attr->tcp)
+ ihdr->protocol = IPPROTO_TCP;
+ else
+ ihdr->protocol = IPPROTO_UDP;
+ iplen = sizeof(*ihdr) + sizeof(*shdr) + attr->size;
+ if (attr->tcp)
+ iplen += sizeof(*thdr);
+ else
+ iplen += sizeof(*uhdr);
+ ihdr->tot_len = htons(iplen);
+ ihdr->frag_off = 0;
+ ihdr->saddr = 0;
+ ihdr->daddr = htonl(attr->ip_dst);
+ ihdr->tos = 0;
+ ihdr->id = 0;
+ ip_send_check(ihdr);
+
+ shdr = skb_put(skb, sizeof(*shdr));
+ shdr->version = 0;
+ shdr->magic = cpu_to_be64(STMMAC_TEST_PKT_MAGIC);
+ attr->id = stmmac_test_next_id;
+ shdr->id = stmmac_test_next_id++;
+
+ if (attr->size)
+ skb_put(skb, attr->size);
+
+ skb->csum = 0;
+ skb->ip_summed = CHECKSUM_PARTIAL;
+ if (attr->tcp) {
+ thdr->check = ~tcp_v4_check(skb->len, ihdr->saddr, ihdr->daddr, 0);
+ skb->csum_start = skb_transport_header(skb) - skb->head;
+ skb->csum_offset = offsetof(struct tcphdr, check);
+ } else {
+ udp4_hwcsum(skb, ihdr->saddr, ihdr->daddr);
+ }
+
+ skb->protocol = htons(ETH_P_IP);
+ skb->pkt_type = PACKET_HOST;
+ skb->dev = priv->dev;
+
+ return skb;
+}
+
+struct stmmac_test_priv {
+ struct stmmac_packet_attrs *packet;
+ struct packet_type pt;
+ struct completion comp;
+ int double_vlan;
+ int vlan_id;
+ int ok;
+};
+
+static int stmmac_test_loopback_validate(struct sk_buff *skb,
+ struct net_device *ndev,
+ struct packet_type *pt,
+ struct net_device *orig_ndev)
+{
+ struct stmmac_test_priv *tpriv = pt->af_packet_priv;
+ struct stmmachdr *shdr;
+ struct ethhdr *ehdr;
+ struct udphdr *uhdr;
+ struct tcphdr *thdr;
+ struct iphdr *ihdr;
+
+ skb = skb_unshare(skb, GFP_ATOMIC);
+ if (!skb)
+ goto out;
+
+ if (skb_linearize(skb))
+ goto out;
+ if (skb_headlen(skb) < (STMMAC_TEST_PKT_SIZE - ETH_HLEN))
+ goto out;
+
+ ehdr = (struct ethhdr *)skb_mac_header(skb);
+ if (tpriv->packet->dst) {
+ if (!ether_addr_equal(ehdr->h_dest, tpriv->packet->dst))
+ goto out;
+ }
+ if (tpriv->packet->src) {
+ if (!ether_addr_equal(ehdr->h_source, orig_ndev->dev_addr))
+ goto out;
+ }
+
+ ihdr = ip_hdr(skb);
+ if (tpriv->double_vlan)
+ ihdr = (struct iphdr *)(skb_network_header(skb) + 4);
+
+ if (tpriv->packet->tcp) {
+ if (ihdr->protocol != IPPROTO_TCP)
+ goto out;
+
+ thdr = (struct tcphdr *)((u8 *)ihdr + 4 * ihdr->ihl);
+ if (thdr->dest != htons(tpriv->packet->dport))
+ goto out;
+
+ shdr = (struct stmmachdr *)((u8 *)thdr + sizeof(*thdr));
+ } else {
+ if (ihdr->protocol != IPPROTO_UDP)
+ goto out;
+
+ uhdr = (struct udphdr *)((u8 *)ihdr + 4 * ihdr->ihl);
+ if (uhdr->dest != htons(tpriv->packet->dport))
+ goto out;
+
+ shdr = (struct stmmachdr *)((u8 *)uhdr + sizeof(*uhdr));
+ }
+
+ if (shdr->magic != cpu_to_be64(STMMAC_TEST_PKT_MAGIC))
+ goto out;
+ if (tpriv->packet->exp_hash && !skb->hash)
+ goto out;
+ if (tpriv->packet->id != shdr->id)
+ goto out;
+
+ tpriv->ok = true;
+ complete(&tpriv->comp);
+out:
+ kfree_skb(skb);
+ return 0;
+}
+
+static int __stmmac_test_loopback(struct stmmac_priv *priv,
+ struct stmmac_packet_attrs *attr)
+{
+ struct stmmac_test_priv *tpriv;
+ struct sk_buff *skb = NULL;
+ int ret = 0;
+
+ tpriv = kzalloc(sizeof(*tpriv), GFP_KERNEL);
+ if (!tpriv)
+ return -ENOMEM;
+
+ tpriv->ok = false;
+ init_completion(&tpriv->comp);
+
+ tpriv->pt.type = htons(ETH_P_IP);
+ tpriv->pt.func = stmmac_test_loopback_validate;
+ tpriv->pt.dev = priv->dev;
+ tpriv->pt.af_packet_priv = tpriv;
+ tpriv->packet = attr;
+ dev_add_pack(&tpriv->pt);
+
+ skb = stmmac_test_get_udp_skb(priv, attr);
+ if (!skb) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ skb_set_queue_mapping(skb, 0);
+ ret = dev_queue_xmit(skb);
+ if (ret)
+ goto cleanup;
+
+ if (attr->dont_wait)
+ goto cleanup;
+
+ if (!attr->timeout)
+ attr->timeout = STMMAC_LB_TIMEOUT;
+
+ wait_for_completion_timeout(&tpriv->comp, attr->timeout);
+ ret = !tpriv->ok;
+
+cleanup:
+ dev_remove_pack(&tpriv->pt);
+ kfree(tpriv);
+ return ret;
+}
+
+static int stmmac_test_mac_loopback(struct stmmac_priv *priv)
+{
+ struct stmmac_packet_attrs attr = { };
+
+ attr.dst = priv->dev->dev_addr;
+ return __stmmac_test_loopback(priv, &attr);
+}
+
+static int stmmac_test_phy_loopback(struct stmmac_priv *priv)
+{
+ struct stmmac_packet_attrs attr = { };
+ int ret;
+
+ if (!priv->dev->phydev)
+ return -EBUSY;
+
+ ret = phy_loopback(priv->dev->phydev, true);
+ if (ret)
+ return ret;
+
+ attr.dst = priv->dev->dev_addr;
+ ret = __stmmac_test_loopback(priv, &attr);
+
+ phy_loopback(priv->dev->phydev, false);
+ return ret;
+}
+
+static int stmmac_test_mmc(struct stmmac_priv *priv)
+{
+ struct stmmac_counters initial, final;
+ int ret;
+
+ memset(&initial, 0, sizeof(initial));
+ memset(&final, 0, sizeof(final));
+
+ if (!priv->dma_cap.rmon)
+ return -EOPNOTSUPP;
+
+ /* Save previous results into internal struct */
+ stmmac_mmc_read(priv, priv->mmcaddr, &priv->mmc);
+
+ ret = stmmac_test_mac_loopback(priv);
+ if (ret)
+ return ret;
+
+ /* These will be loopback results so no need to save them */
+ stmmac_mmc_read(priv, priv->mmcaddr, &final);
+
+ /*
+ * The number of MMC counters available depends on HW configuration
+ * so we just use this one to validate the feature. I hope there is
+ * not a version without this counter.
+ */
+ if (final.mmc_tx_framecount_g <= initial.mmc_tx_framecount_g)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int stmmac_test_eee(struct stmmac_priv *priv)
+{
+ struct stmmac_extra_stats *initial, *final;
+ int retries = 10;
+ int ret;
+
+ if (!priv->dma_cap.eee || !priv->eee_active)
+ return -EOPNOTSUPP;
+
+ initial = kzalloc(sizeof(*initial), GFP_KERNEL);
+ if (!initial)
+ return -ENOMEM;
+
+ final = kzalloc(sizeof(*final), GFP_KERNEL);
+ if (!final) {
+ ret = -ENOMEM;
+ goto out_free_initial;
+ }
+
+ memcpy(initial, &priv->xstats, sizeof(*initial));
+
+ ret = stmmac_test_mac_loopback(priv);
+ if (ret)
+ goto out_free_final;
+
+ /* We have no traffic in the line so, sooner or later it will go LPI */
+ while (--retries) {
+ memcpy(final, &priv->xstats, sizeof(*final));
+
+ if (final->irq_tx_path_in_lpi_mode_n >
+ initial->irq_tx_path_in_lpi_mode_n)
+ break;
+ msleep(100);
+ }
+
+ if (!retries) {
+ ret = -ETIMEDOUT;
+ goto out_free_final;
+ }
+
+ if (final->irq_tx_path_in_lpi_mode_n <=
+ initial->irq_tx_path_in_lpi_mode_n) {
+ ret = -EINVAL;
+ goto out_free_final;
+ }
+
+ if (final->irq_tx_path_exit_lpi_mode_n <=
+ initial->irq_tx_path_exit_lpi_mode_n) {
+ ret = -EINVAL;
+ goto out_free_final;
+ }
+
+out_free_final:
+ kfree(final);
+out_free_initial:
+ kfree(initial);
+ return ret;
+}
+
+static int stmmac_filter_check(struct stmmac_priv *priv)
+{
+ if (!(priv->dev->flags & IFF_PROMISC))
+ return 0;
+
+ netdev_warn(priv->dev, "Test can't be run in promiscuous mode!\n");
+ return -EOPNOTSUPP;
+}
+
+static int stmmac_test_hfilt(struct stmmac_priv *priv)
+{
+ unsigned char gd_addr[ETH_ALEN] = {0x01, 0x00, 0xcc, 0xcc, 0xdd, 0xdd};
+ unsigned char bd_addr[ETH_ALEN] = {0x09, 0x00, 0xaa, 0xaa, 0xbb, 0xbb};
+ struct stmmac_packet_attrs attr = { };
+ int ret;
+
+ ret = stmmac_filter_check(priv);
+ if (ret)
+ return ret;
+
+ ret = dev_mc_add(priv->dev, gd_addr);
+ if (ret)
+ return ret;
+
+ attr.dst = gd_addr;
+
+ /* Shall receive packet */
+ ret = __stmmac_test_loopback(priv, &attr);
+ if (ret)
+ goto cleanup;
+
+ attr.dst = bd_addr;
+
+ /* Shall NOT receive packet */
+ ret = __stmmac_test_loopback(priv, &attr);
+ ret = !ret;
+
+cleanup:
+ dev_mc_del(priv->dev, gd_addr);
+ return ret;
+}
+
+static int stmmac_test_pfilt(struct stmmac_priv *priv)
+{
+ unsigned char gd_addr[ETH_ALEN] = {0x00, 0x01, 0x44, 0x55, 0x66, 0x77};
+ unsigned char bd_addr[ETH_ALEN] = {0x08, 0x00, 0x22, 0x33, 0x44, 0x55};
+ struct stmmac_packet_attrs attr = { };
+ int ret;
+
+ if (stmmac_filter_check(priv))
+ return -EOPNOTSUPP;
+
+ ret = dev_uc_add(priv->dev, gd_addr);
+ if (ret)
+ return ret;
+
+ attr.dst = gd_addr;
+
+ /* Shall receive packet */
+ ret = __stmmac_test_loopback(priv, &attr);
+ if (ret)
+ goto cleanup;
+
+ attr.dst = bd_addr;
+
+ /* Shall NOT receive packet */
+ ret = __stmmac_test_loopback(priv, &attr);
+ ret = !ret;
+
+cleanup:
+ dev_uc_del(priv->dev, gd_addr);
+ return ret;
+}
+
+static int stmmac_dummy_sync(struct net_device *netdev, const u8 *addr)
+{
+ return 0;
+}
+
+static void stmmac_test_set_rx_mode(struct net_device *netdev)
+{
+ /* As we are in test mode of ethtool we already own the rtnl lock
+ * so no address will change from user. We can just call the
+ * ndo_set_rx_mode() callback directly */
+ if (netdev->netdev_ops->ndo_set_rx_mode)
+ netdev->netdev_ops->ndo_set_rx_mode(netdev);
+}
+
+static int stmmac_test_mcfilt(struct stmmac_priv *priv)
+{
+ unsigned char uc_addr[ETH_ALEN] = {0x00, 0x01, 0x44, 0x55, 0x66, 0x77};
+ unsigned char mc_addr[ETH_ALEN] = {0x01, 0x01, 0x44, 0x55, 0x66, 0x77};
+ struct stmmac_packet_attrs attr = { };
+ int ret;
+
+ if (stmmac_filter_check(priv))
+ return -EOPNOTSUPP;
+
+ /* Remove all MC addresses */
+ __dev_mc_unsync(priv->dev, NULL);
+ stmmac_test_set_rx_mode(priv->dev);
+
+ ret = dev_uc_add(priv->dev, uc_addr);
+ if (ret)
+ goto cleanup;
+
+ attr.dst = uc_addr;
+
+ /* Shall receive packet */
+ ret = __stmmac_test_loopback(priv, &attr);
+ if (ret)
+ goto cleanup;
+
+ attr.dst = mc_addr;
+
+ /* Shall NOT receive packet */
+ ret = __stmmac_test_loopback(priv, &attr);
+ ret = !ret;
+
+cleanup:
+ dev_uc_del(priv->dev, uc_addr);
+ __dev_mc_sync(priv->dev, stmmac_dummy_sync, NULL);
+ stmmac_test_set_rx_mode(priv->dev);
+ return ret;
+}
+
+static int stmmac_test_ucfilt(struct stmmac_priv *priv)
+{
+ unsigned char uc_addr[ETH_ALEN] = {0x00, 0x01, 0x44, 0x55, 0x66, 0x77};
+ unsigned char mc_addr[ETH_ALEN] = {0x01, 0x01, 0x44, 0x55, 0x66, 0x77};
+ struct stmmac_packet_attrs attr = { };
+ int ret;
+
+ if (stmmac_filter_check(priv))
+ return -EOPNOTSUPP;
+
+ /* Remove all UC addresses */
+ __dev_uc_unsync(priv->dev, NULL);
+ stmmac_test_set_rx_mode(priv->dev);
+
+ ret = dev_mc_add(priv->dev, mc_addr);
+ if (ret)
+ goto cleanup;
+
+ attr.dst = mc_addr;
+
+ /* Shall receive packet */
+ ret = __stmmac_test_loopback(priv, &attr);
+ if (ret)
+ goto cleanup;
+
+ attr.dst = uc_addr;
+
+ /* Shall NOT receive packet */
+ ret = __stmmac_test_loopback(priv, &attr);
+ ret = !ret;
+
+cleanup:
+ dev_mc_del(priv->dev, mc_addr);
+ __dev_uc_sync(priv->dev, stmmac_dummy_sync, NULL);
+ stmmac_test_set_rx_mode(priv->dev);
+ return ret;
+}
+
+static int stmmac_test_flowctrl_validate(struct sk_buff *skb,
+ struct net_device *ndev,
+ struct packet_type *pt,
+ struct net_device *orig_ndev)
+{
+ struct stmmac_test_priv *tpriv = pt->af_packet_priv;
+ struct ethhdr *ehdr;
+
+ ehdr = (struct ethhdr *)skb_mac_header(skb);
+ if (!ether_addr_equal(ehdr->h_source, orig_ndev->dev_addr))
+ goto out;
+ if (ehdr->h_proto != htons(ETH_P_PAUSE))
+ goto out;
+
+ tpriv->ok = true;
+ complete(&tpriv->comp);
+out:
+ kfree_skb(skb);
+ return 0;
+}
+
+static int stmmac_test_flowctrl(struct stmmac_priv *priv)
+{
+ unsigned char paddr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x01};
+ struct phy_device *phydev = priv->dev->phydev;
+ u32 rx_cnt = priv->plat->rx_queues_to_use;
+ struct stmmac_test_priv *tpriv;
+ unsigned int pkt_count;
+ int i, ret = 0;
+
+ if (!phydev || !phydev->pause)
+ return -EOPNOTSUPP;
+
+ tpriv = kzalloc(sizeof(*tpriv), GFP_KERNEL);
+ if (!tpriv)
+ return -ENOMEM;
+
+ tpriv->ok = false;
+ init_completion(&tpriv->comp);
+ tpriv->pt.type = htons(ETH_P_PAUSE);
+ tpriv->pt.func = stmmac_test_flowctrl_validate;
+ tpriv->pt.dev = priv->dev;
+ tpriv->pt.af_packet_priv = tpriv;
+ dev_add_pack(&tpriv->pt);
+
+ /* Compute minimum number of packets to make FIFO full */
+ pkt_count = priv->plat->rx_fifo_size;
+ if (!pkt_count)
+ pkt_count = priv->dma_cap.rx_fifo_size;
+ pkt_count /= 1400;
+ pkt_count *= 2;
+
+ for (i = 0; i < rx_cnt; i++)
+ stmmac_stop_rx(priv, priv->ioaddr, i);
+
+ ret = dev_set_promiscuity(priv->dev, 1);
+ if (ret)
+ goto cleanup;
+
+ ret = dev_mc_add(priv->dev, paddr);
+ if (ret)
+ goto cleanup;
+
+ for (i = 0; i < pkt_count; i++) {
+ struct stmmac_packet_attrs attr = { };
+
+ attr.dst = priv->dev->dev_addr;
+ attr.dont_wait = true;
+ attr.size = 1400;
+
+ ret = __stmmac_test_loopback(priv, &attr);
+ if (ret)
+ goto cleanup;
+ if (tpriv->ok)
+ break;
+ }
+
+ /* Wait for some time in case RX Watchdog is enabled */
+ msleep(200);
+
+ for (i = 0; i < rx_cnt; i++) {
+ struct stmmac_channel *ch = &priv->channel[i];
+
+ stmmac_start_rx(priv, priv->ioaddr, i);
+ local_bh_disable();
+ napi_reschedule(&ch->rx_napi);
+ local_bh_enable();
+ }
+
+ wait_for_completion_timeout(&tpriv->comp, STMMAC_LB_TIMEOUT);
+ ret = !tpriv->ok;
+
+cleanup:
+ dev_mc_del(priv->dev, paddr);
+ dev_set_promiscuity(priv->dev, -1);
+ dev_remove_pack(&tpriv->pt);
+ kfree(tpriv);
+ return ret;
+}
+
+#define STMMAC_LOOPBACK_NONE 0
+#define STMMAC_LOOPBACK_MAC 1
+#define STMMAC_LOOPBACK_PHY 2
+
+static const struct stmmac_test {
+ char name[ETH_GSTRING_LEN];
+ int lb;
+ int (*fn)(struct stmmac_priv *priv);
+} stmmac_selftests[] = {
+ {
+ .name = "MAC Loopback ",
+ .lb = STMMAC_LOOPBACK_MAC,
+ .fn = stmmac_test_mac_loopback,
+ }, {
+ .name = "PHY Loopback ",
+ .lb = STMMAC_LOOPBACK_NONE, /* Test will handle it */
+ .fn = stmmac_test_phy_loopback,
+ }, {
+ .name = "MMC Counters ",
+ .lb = STMMAC_LOOPBACK_PHY,
+ .fn = stmmac_test_mmc,
+ }, {
+ .name = "EEE ",
+ .lb = STMMAC_LOOPBACK_PHY,
+ .fn = stmmac_test_eee,
+ }, {
+ .name = "Hash Filter MC ",
+ .lb = STMMAC_LOOPBACK_PHY,
+ .fn = stmmac_test_hfilt,
+ }, {
+ .name = "Perfect Filter UC ",
+ .lb = STMMAC_LOOPBACK_PHY,
+ .fn = stmmac_test_pfilt,
+ }, {
+ .name = "MC Filter ",
+ .lb = STMMAC_LOOPBACK_PHY,
+ .fn = stmmac_test_mcfilt,
+ }, {
+ .name = "UC Filter ",
+ .lb = STMMAC_LOOPBACK_PHY,
+ .fn = stmmac_test_ucfilt,
+ }, {
+ .name = "Flow Control ",
+ .lb = STMMAC_LOOPBACK_PHY,
+ .fn = stmmac_test_flowctrl,
+ },
+};
+
+void stmmac_selftest_run(struct net_device *dev,
+ struct ethtool_test *etest, u64 *buf)
+{
+ struct stmmac_priv *priv = netdev_priv(dev);
+ int count = stmmac_selftest_get_count(priv);
+ int carrier = netif_carrier_ok(dev);
+ int i, ret;
+
+ memset(buf, 0, sizeof(*buf) * count);
+ stmmac_test_next_id = 0;
+
+ if (etest->flags != ETH_TEST_FL_OFFLINE) {
+ netdev_err(priv->dev, "Only offline tests are supported\n");
+ etest->flags |= ETH_TEST_FL_FAILED;
+ return;
+ } else if (!carrier) {
+ netdev_err(priv->dev, "You need valid Link to execute tests\n");
+ etest->flags |= ETH_TEST_FL_FAILED;
+ return;
+ }
+
+ /* We don't want extra traffic */
+ netif_carrier_off(dev);
+
+ /* Wait for queues drain */
+ msleep(200);
+
+ for (i = 0; i < count; i++) {
+ ret = 0;
+
+ switch (stmmac_selftests[i].lb) {
+ case STMMAC_LOOPBACK_PHY:
+ ret = -EOPNOTSUPP;
+ if (dev->phydev)
+ ret = phy_loopback(dev->phydev, true);
+ if (!ret)
+ break;
+ /* Fallthrough */
+ case STMMAC_LOOPBACK_MAC:
+ ret = stmmac_set_mac_loopback(priv, priv->ioaddr, true);
+ break;
+ case STMMAC_LOOPBACK_NONE:
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ /*
+ * First tests will always be MAC / PHY loobpack. If any of
+ * them is not supported we abort earlier.
+ */
+ if (ret) {
+ netdev_err(priv->dev, "Loopback is not supported\n");
+ etest->flags |= ETH_TEST_FL_FAILED;
+ break;
+ }
+
+ ret = stmmac_selftests[i].fn(priv);
+ if (ret && (ret != -EOPNOTSUPP))
+ etest->flags |= ETH_TEST_FL_FAILED;
+ buf[i] = ret;
+
+ switch (stmmac_selftests[i].lb) {
+ case STMMAC_LOOPBACK_PHY:
+ ret = -EOPNOTSUPP;
+ if (dev->phydev)
+ ret = phy_loopback(dev->phydev, false);
+ if (!ret)
+ break;
+ /* Fallthrough */
+ case STMMAC_LOOPBACK_MAC:
+ stmmac_set_mac_loopback(priv, priv->ioaddr, false);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* Restart everything */
+ if (carrier)
+ netif_carrier_on(dev);
+}
+
+void stmmac_selftest_get_strings(struct stmmac_priv *priv, u8 *data)
+{
+ u8 *p = data;
+ int i;
+
+ for (i = 0; i < stmmac_selftest_get_count(priv); i++) {
+ snprintf(p, ETH_GSTRING_LEN, "%2d. %s", i + 1,
+ stmmac_selftests[i].name);
+ p += ETH_GSTRING_LEN;
+ }
+}
+
+int stmmac_selftest_get_count(struct stmmac_priv *priv)
+{
+ return ARRAY_SIZE(stmmac_selftests);
+}
diff --git a/drivers/net/ethernet/sun/niu.c b/drivers/net/ethernet/sun/niu.c
index 6f99437a6962..0bc5863bffeb 100644
--- a/drivers/net/ethernet/sun/niu.c
+++ b/drivers/net/ethernet/sun/niu.c
@@ -1217,8 +1217,6 @@ static int link_status_1g_rgmii(struct niu *np, int *link_up_p)
spin_lock_irqsave(&np->lock, flags);
- err = -EINVAL;
-
err = mii_read(np, np->phy_addr, MII_BMSR);
if (err < 0)
goto out;
diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig
index bd05a977ee7e..834afca3a019 100644
--- a/drivers/net/ethernet/ti/Kconfig
+++ b/drivers/net/ethernet/ti/Kconfig
@@ -50,6 +50,7 @@ config TI_CPSW
depends on ARCH_DAVINCI || ARCH_OMAP2PLUS || COMPILE_TEST
select TI_DAVINCI_MDIO
select MFD_SYSCON
+ select PAGE_POOL
select REGMAP
---help---
This driver supports TI's CPSW Ethernet Switch.
@@ -60,6 +61,7 @@ config TI_CPSW
config TI_CPTS
bool "TI Common Platform Time Sync (CPTS) Support"
depends on TI_CPSW || TI_KEYSTONE_NETCP || COMPILE_TEST
+ depends on COMMON_CLK
depends on POSIX_TIMERS
---help---
This driver supports the Common Platform Time Sync unit of
diff --git a/drivers/net/ethernet/ti/cpsw-phy-sel.c b/drivers/net/ethernet/ti/cpsw-phy-sel.c
index 48e0924259f5..4e184eecc8e1 100644
--- a/drivers/net/ethernet/ti/cpsw-phy-sel.c
+++ b/drivers/net/ethernet/ti/cpsw-phy-sel.c
@@ -151,9 +151,9 @@ static void cpsw_gmii_sel_dra7xx(struct cpsw_phy_sel_priv *priv,
}
static struct platform_driver cpsw_phy_sel_driver;
-static int match(struct device *dev, void *data)
+static int match(struct device *dev, const void *data)
{
- struct device_node *node = (struct device_node *)data;
+ const struct device_node *node = (const struct device_node *)data;
return dev->of_node == node &&
dev->driver == &cpsw_phy_sel_driver.driver;
}
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 634fc484a0b3..32a89744972d 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -31,6 +31,10 @@
#include <linux/if_vlan.h>
#include <linux/kmemleak.h>
#include <linux/sys_soc.h>
+#include <net/page_pool.h>
+#include <linux/bpf.h>
+#include <linux/bpf_trace.h>
+#include <linux/filter.h>
#include <linux/pinctrl/consumer.h>
#include <net/pkt_cls.h>
@@ -60,6 +64,10 @@ static int descs_pool_size = CPSW_CPDMA_DESCS_POOL_SIZE_DEFAULT;
module_param(descs_pool_size, int, 0444);
MODULE_PARM_DESC(descs_pool_size, "Number of CPDMA CPPI descriptors in pool");
+/* The buf includes headroom compatible with both skb and xdpf */
+#define CPSW_HEADROOM_NA (max(XDP_PACKET_HEADROOM, NET_SKB_PAD) + NET_IP_ALIGN)
+#define CPSW_HEADROOM ALIGN(CPSW_HEADROOM_NA, sizeof(long))
+
#define for_each_slave(priv, func, arg...) \
do { \
struct cpsw_slave *slave; \
@@ -74,6 +82,11 @@ MODULE_PARM_DESC(descs_pool_size, "Number of CPDMA CPPI descriptors in pool");
(func)(slave++, ##arg); \
} while (0)
+#define CPSW_XMETA_OFFSET ALIGN(sizeof(struct xdp_frame), sizeof(long))
+
+#define CPSW_XDP_CONSUMED 1
+#define CPSW_XDP_PASS 0
+
static int cpsw_ndo_vlan_rx_add_vid(struct net_device *ndev,
__be16 proto, u16 vid);
@@ -337,24 +350,58 @@ void cpsw_intr_disable(struct cpsw_common *cpsw)
return;
}
+static int cpsw_is_xdpf_handle(void *handle)
+{
+ return (unsigned long)handle & BIT(0);
+}
+
+static void *cpsw_xdpf_to_handle(struct xdp_frame *xdpf)
+{
+ return (void *)((unsigned long)xdpf | BIT(0));
+}
+
+static struct xdp_frame *cpsw_handle_to_xdpf(void *handle)
+{
+ return (struct xdp_frame *)((unsigned long)handle & ~BIT(0));
+}
+
+struct __aligned(sizeof(long)) cpsw_meta_xdp {
+ struct net_device *ndev;
+ int ch;
+};
+
void cpsw_tx_handler(void *token, int len, int status)
{
+ struct cpsw_meta_xdp *xmeta;
+ struct xdp_frame *xdpf;
+ struct net_device *ndev;
struct netdev_queue *txq;
- struct sk_buff *skb = token;
- struct net_device *ndev = skb->dev;
- struct cpsw_common *cpsw = ndev_to_cpsw(ndev);
+ struct sk_buff *skb;
+ int ch;
+
+ if (cpsw_is_xdpf_handle(token)) {
+ xdpf = cpsw_handle_to_xdpf(token);
+ xmeta = (void *)xdpf + CPSW_XMETA_OFFSET;
+ ndev = xmeta->ndev;
+ ch = xmeta->ch;
+ xdp_return_frame(xdpf);
+ } else {
+ skb = token;
+ ndev = skb->dev;
+ ch = skb_get_queue_mapping(skb);
+ cpts_tx_timestamp(ndev_to_cpsw(ndev)->cpts, skb);
+ dev_kfree_skb_any(skb);
+ }
/* Check whether the queue is stopped due to stalled tx dma, if the
* queue is stopped then start the queue as we have free desc for tx
*/
- txq = netdev_get_tx_queue(ndev, skb_get_queue_mapping(skb));
+ txq = netdev_get_tx_queue(ndev, ch);
if (unlikely(netif_tx_queue_stopped(txq)))
netif_tx_wake_queue(txq);
- cpts_tx_timestamp(cpsw->cpts, skb);
ndev->stats.tx_packets++;
ndev->stats.tx_bytes += len;
- dev_kfree_skb_any(skb);
}
static void cpsw_rx_vlan_encap(struct sk_buff *skb)
@@ -400,24 +447,252 @@ static void cpsw_rx_vlan_encap(struct sk_buff *skb)
}
}
+static int cpsw_xdp_tx_frame(struct cpsw_priv *priv, struct xdp_frame *xdpf,
+ struct page *page)
+{
+ struct cpsw_common *cpsw = priv->cpsw;
+ struct cpsw_meta_xdp *xmeta;
+ struct cpdma_chan *txch;
+ dma_addr_t dma;
+ int ret, port;
+
+ xmeta = (void *)xdpf + CPSW_XMETA_OFFSET;
+ xmeta->ndev = priv->ndev;
+ xmeta->ch = 0;
+ txch = cpsw->txv[0].ch;
+
+ port = priv->emac_port + cpsw->data.dual_emac;
+ if (page) {
+ dma = page_pool_get_dma_addr(page);
+ dma += xdpf->headroom + sizeof(struct xdp_frame);
+ ret = cpdma_chan_submit_mapped(txch, cpsw_xdpf_to_handle(xdpf),
+ dma, xdpf->len, port);
+ } else {
+ if (sizeof(*xmeta) > xdpf->headroom) {
+ xdp_return_frame_rx_napi(xdpf);
+ return -EINVAL;
+ }
+
+ ret = cpdma_chan_submit(txch, cpsw_xdpf_to_handle(xdpf),
+ xdpf->data, xdpf->len, port);
+ }
+
+ if (ret) {
+ priv->ndev->stats.tx_dropped++;
+ xdp_return_frame_rx_napi(xdpf);
+ }
+
+ return ret;
+}
+
+static int cpsw_run_xdp(struct cpsw_priv *priv, int ch, struct xdp_buff *xdp,
+ struct page *page)
+{
+ struct cpsw_common *cpsw = priv->cpsw;
+ struct net_device *ndev = priv->ndev;
+ int ret = CPSW_XDP_CONSUMED;
+ struct xdp_frame *xdpf;
+ struct bpf_prog *prog;
+ u32 act;
+
+ rcu_read_lock();
+
+ prog = READ_ONCE(priv->xdp_prog);
+ if (!prog) {
+ ret = CPSW_XDP_PASS;
+ goto out;
+ }
+
+ act = bpf_prog_run_xdp(prog, xdp);
+ switch (act) {
+ case XDP_PASS:
+ ret = CPSW_XDP_PASS;
+ break;
+ case XDP_TX:
+ xdpf = convert_to_xdp_frame(xdp);
+ if (unlikely(!xdpf))
+ goto drop;
+
+ cpsw_xdp_tx_frame(priv, xdpf, page);
+ break;
+ case XDP_REDIRECT:
+ if (xdp_do_redirect(ndev, xdp, prog))
+ goto drop;
+
+ /* Have to flush here, per packet, instead of doing it in bulk
+ * at the end of the napi handler. The RX devices on this
+ * particular hardware is sharing a common queue, so the
+ * incoming device might change per packet.
+ */
+ xdp_do_flush_map();
+ break;
+ default:
+ bpf_warn_invalid_xdp_action(act);
+ /* fall through */
+ case XDP_ABORTED:
+ trace_xdp_exception(ndev, prog, act);
+ /* fall through -- handle aborts by dropping packet */
+ case XDP_DROP:
+ goto drop;
+ }
+out:
+ rcu_read_unlock();
+ return ret;
+drop:
+ rcu_read_unlock();
+ page_pool_recycle_direct(cpsw->page_pool[ch], page);
+ return ret;
+}
+
+static unsigned int cpsw_rxbuf_total_len(unsigned int len)
+{
+ len += CPSW_HEADROOM;
+ len += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+
+ return SKB_DATA_ALIGN(len);
+}
+
+static struct page_pool *cpsw_create_page_pool(struct cpsw_common *cpsw,
+ int size)
+{
+ struct page_pool_params pp_params;
+ struct page_pool *pool;
+
+ pp_params.order = 0;
+ pp_params.flags = PP_FLAG_DMA_MAP;
+ pp_params.pool_size = size;
+ pp_params.nid = NUMA_NO_NODE;
+ pp_params.dma_dir = DMA_BIDIRECTIONAL;
+ pp_params.dev = cpsw->dev;
+
+ pool = page_pool_create(&pp_params);
+ if (IS_ERR(pool))
+ dev_err(cpsw->dev, "cannot create rx page pool\n");
+
+ return pool;
+}
+
+static int cpsw_ndev_create_xdp_rxq(struct cpsw_priv *priv, int ch)
+{
+ struct cpsw_common *cpsw = priv->cpsw;
+ struct xdp_rxq_info *rxq;
+ struct page_pool *pool;
+ int ret;
+
+ pool = cpsw->page_pool[ch];
+ rxq = &priv->xdp_rxq[ch];
+
+ ret = xdp_rxq_info_reg(rxq, priv->ndev, ch);
+ if (ret)
+ return ret;
+
+ ret = xdp_rxq_info_reg_mem_model(rxq, MEM_TYPE_PAGE_POOL, pool);
+ if (ret)
+ xdp_rxq_info_unreg(rxq);
+
+ return ret;
+}
+
+static void cpsw_ndev_destroy_xdp_rxq(struct cpsw_priv *priv, int ch)
+{
+ struct xdp_rxq_info *rxq = &priv->xdp_rxq[ch];
+
+ if (!xdp_rxq_info_is_reg(rxq))
+ return;
+
+ xdp_rxq_info_unreg(rxq);
+}
+
+static int cpsw_create_rx_pool(struct cpsw_common *cpsw, int ch)
+{
+ struct page_pool *pool;
+ int ret = 0, pool_size;
+
+ pool_size = cpdma_chan_get_rx_buf_num(cpsw->rxv[ch].ch);
+ pool = cpsw_create_page_pool(cpsw, pool_size);
+ if (IS_ERR(pool))
+ ret = PTR_ERR(pool);
+ else
+ cpsw->page_pool[ch] = pool;
+
+ return ret;
+}
+
+void cpsw_destroy_xdp_rxqs(struct cpsw_common *cpsw)
+{
+ struct net_device *ndev;
+ int i, ch;
+
+ for (ch = 0; ch < cpsw->rx_ch_num; ch++) {
+ for (i = 0; i < cpsw->data.slaves; i++) {
+ ndev = cpsw->slaves[i].ndev;
+ if (!ndev)
+ continue;
+
+ cpsw_ndev_destroy_xdp_rxq(netdev_priv(ndev), ch);
+ }
+
+ page_pool_destroy(cpsw->page_pool[ch]);
+ cpsw->page_pool[ch] = NULL;
+ }
+}
+
+int cpsw_create_xdp_rxqs(struct cpsw_common *cpsw)
+{
+ struct net_device *ndev;
+ int i, ch, ret;
+
+ for (ch = 0; ch < cpsw->rx_ch_num; ch++) {
+ ret = cpsw_create_rx_pool(cpsw, ch);
+ if (ret)
+ goto err_cleanup;
+
+ /* using same page pool is allowed as no running rx handlers
+ * simultaneously for both ndevs
+ */
+ for (i = 0; i < cpsw->data.slaves; i++) {
+ ndev = cpsw->slaves[i].ndev;
+ if (!ndev)
+ continue;
+
+ ret = cpsw_ndev_create_xdp_rxq(netdev_priv(ndev), ch);
+ if (ret)
+ goto err_cleanup;
+ }
+ }
+
+ return 0;
+
+err_cleanup:
+ cpsw_destroy_xdp_rxqs(cpsw);
+
+ return ret;
+}
+
static void cpsw_rx_handler(void *token, int len, int status)
{
- struct cpdma_chan *ch;
- struct sk_buff *skb = token;
- struct sk_buff *new_skb;
- struct net_device *ndev = skb->dev;
- int ret = 0, port;
- struct cpsw_common *cpsw = ndev_to_cpsw(ndev);
+ struct page *new_page, *page = token;
+ void *pa = page_address(page);
+ struct cpsw_meta_xdp *xmeta = pa + CPSW_XMETA_OFFSET;
+ struct cpsw_common *cpsw = ndev_to_cpsw(xmeta->ndev);
+ int pkt_size = cpsw->rx_packet_max;
+ int ret = 0, port, ch = xmeta->ch;
+ int headroom = CPSW_HEADROOM;
+ struct net_device *ndev = xmeta->ndev;
struct cpsw_priv *priv;
+ struct page_pool *pool;
+ struct sk_buff *skb;
+ struct xdp_buff xdp;
+ dma_addr_t dma;
- if (cpsw->data.dual_emac) {
+ if (cpsw->data.dual_emac && status >= 0) {
port = CPDMA_RX_SOURCE_PORT(status);
- if (port) {
+ if (port)
ndev = cpsw->slaves[--port].ndev;
- skb->dev = ndev;
- }
}
+ priv = netdev_priv(ndev);
+ pool = cpsw->page_pool[ch];
if (unlikely(status < 0) || unlikely(!netif_running(ndev))) {
/* In dual emac mode check for all interfaces */
if (cpsw->data.dual_emac && cpsw->usage_count &&
@@ -426,47 +701,88 @@ static void cpsw_rx_handler(void *token, int len, int status)
* is already down and the other interface is up
* and running, instead of freeing which results
* in reducing of the number of rx descriptor in
- * DMA engine, requeue skb back to cpdma.
+ * DMA engine, requeue page back to cpdma.
*/
- new_skb = skb;
+ new_page = page;
goto requeue;
}
- /* the interface is going down, skbs are purged */
- dev_kfree_skb_any(skb);
+ /* the interface is going down, pages are purged */
+ page_pool_recycle_direct(pool, page);
return;
}
- new_skb = netdev_alloc_skb_ip_align(ndev, cpsw->rx_packet_max);
- if (new_skb) {
- skb_copy_queue_mapping(new_skb, skb);
- skb_put(skb, len);
- if (status & CPDMA_RX_VLAN_ENCAP)
- cpsw_rx_vlan_encap(skb);
- priv = netdev_priv(ndev);
- if (priv->rx_ts_enabled)
- cpts_rx_timestamp(cpsw->cpts, skb);
- skb->protocol = eth_type_trans(skb, ndev);
- netif_receive_skb(skb);
- ndev->stats.rx_bytes += len;
- ndev->stats.rx_packets++;
- kmemleak_not_leak(new_skb);
- } else {
+ new_page = page_pool_dev_alloc_pages(pool);
+ if (unlikely(!new_page)) {
+ new_page = page;
ndev->stats.rx_dropped++;
- new_skb = skb;
+ goto requeue;
}
-requeue:
- if (netif_dormant(ndev)) {
- dev_kfree_skb_any(new_skb);
- return;
+ if (priv->xdp_prog) {
+ if (status & CPDMA_RX_VLAN_ENCAP) {
+ xdp.data = pa + CPSW_HEADROOM +
+ CPSW_RX_VLAN_ENCAP_HDR_SIZE;
+ xdp.data_end = xdp.data + len -
+ CPSW_RX_VLAN_ENCAP_HDR_SIZE;
+ } else {
+ xdp.data = pa + CPSW_HEADROOM;
+ xdp.data_end = xdp.data + len;
+ }
+
+ xdp_set_data_meta_invalid(&xdp);
+
+ xdp.data_hard_start = pa;
+ xdp.rxq = &priv->xdp_rxq[ch];
+
+ ret = cpsw_run_xdp(priv, ch, &xdp, page);
+ if (ret != CPSW_XDP_PASS)
+ goto requeue;
+
+ /* XDP prog might have changed packet data and boundaries */
+ len = xdp.data_end - xdp.data;
+ headroom = xdp.data - xdp.data_hard_start;
+
+ /* XDP prog can modify vlan tag, so can't use encap header */
+ status &= ~CPDMA_RX_VLAN_ENCAP;
+ }
+
+ /* pass skb to netstack if no XDP prog or returned XDP_PASS */
+ skb = build_skb(pa, cpsw_rxbuf_total_len(pkt_size));
+ if (!skb) {
+ ndev->stats.rx_dropped++;
+ page_pool_recycle_direct(pool, page);
+ goto requeue;
}
- ch = cpsw->rxv[skb_get_queue_mapping(new_skb)].ch;
- ret = cpdma_chan_submit(ch, new_skb, new_skb->data,
- skb_tailroom(new_skb), 0);
- if (WARN_ON(ret < 0))
- dev_kfree_skb_any(new_skb);
+ skb_reserve(skb, headroom);
+ skb_put(skb, len);
+ skb->dev = ndev;
+ if (status & CPDMA_RX_VLAN_ENCAP)
+ cpsw_rx_vlan_encap(skb);
+ if (priv->rx_ts_enabled)
+ cpts_rx_timestamp(cpsw->cpts, skb);
+ skb->protocol = eth_type_trans(skb, ndev);
+
+ /* unmap page as no netstack skb page recycling */
+ page_pool_release_page(pool, page);
+ netif_receive_skb(skb);
+
+ ndev->stats.rx_bytes += len;
+ ndev->stats.rx_packets++;
+
+requeue:
+ xmeta = page_address(new_page) + CPSW_XMETA_OFFSET;
+ xmeta->ndev = ndev;
+ xmeta->ch = ch;
+
+ dma = page_pool_get_dma_addr(new_page) + CPSW_HEADROOM;
+ ret = cpdma_chan_submit_mapped(cpsw->rxv[ch].ch, new_page, dma,
+ pkt_size, 0);
+ if (ret < 0) {
+ WARN_ON(ret == -ENOMEM);
+ page_pool_recycle_direct(pool, new_page);
+ }
}
void cpsw_split_res(struct cpsw_common *cpsw)
@@ -1035,33 +1351,39 @@ static void cpsw_init_host_port(struct cpsw_priv *priv)
int cpsw_fill_rx_channels(struct cpsw_priv *priv)
{
struct cpsw_common *cpsw = priv->cpsw;
- struct sk_buff *skb;
+ struct cpsw_meta_xdp *xmeta;
+ struct page_pool *pool;
+ struct page *page;
int ch_buf_num;
int ch, i, ret;
+ dma_addr_t dma;
for (ch = 0; ch < cpsw->rx_ch_num; ch++) {
+ pool = cpsw->page_pool[ch];
ch_buf_num = cpdma_chan_get_rx_buf_num(cpsw->rxv[ch].ch);
for (i = 0; i < ch_buf_num; i++) {
- skb = __netdev_alloc_skb_ip_align(priv->ndev,
- cpsw->rx_packet_max,
- GFP_KERNEL);
- if (!skb) {
- cpsw_err(priv, ifup, "cannot allocate skb\n");
+ page = page_pool_dev_alloc_pages(pool);
+ if (!page) {
+ cpsw_err(priv, ifup, "allocate rx page err\n");
return -ENOMEM;
}
- skb_set_queue_mapping(skb, ch);
- ret = cpdma_chan_submit(cpsw->rxv[ch].ch, skb,
- skb->data, skb_tailroom(skb),
- 0);
+ xmeta = page_address(page) + CPSW_XMETA_OFFSET;
+ xmeta->ndev = priv->ndev;
+ xmeta->ch = ch;
+
+ dma = page_pool_get_dma_addr(page) + CPSW_HEADROOM;
+ ret = cpdma_chan_idle_submit_mapped(cpsw->rxv[ch].ch,
+ page, dma,
+ cpsw->rx_packet_max,
+ 0);
if (ret < 0) {
cpsw_err(priv, ifup,
- "cannot submit skb to channel %d rx, error %d\n",
+ "cannot submit page to channel %d rx, error %d\n",
ch, ret);
- kfree_skb(skb);
+ page_pool_recycle_direct(pool, page);
return ret;
}
- kmemleak_not_leak(skb);
}
cpsw_info(priv, ifup, "ch %d rx, submitted %d descriptors\n",
@@ -1397,6 +1719,13 @@ static int cpsw_ndo_open(struct net_device *ndev)
enable_irq(cpsw->irqs_table[0]);
}
+ /* create rxqs for both infs in dual mac as they use same pool
+ * and must be destroyed together when no users.
+ */
+ ret = cpsw_create_xdp_rxqs(cpsw);
+ if (ret < 0)
+ goto err_cleanup;
+
ret = cpsw_fill_rx_channels(priv);
if (ret < 0)
goto err_cleanup;
@@ -1423,7 +1752,11 @@ static int cpsw_ndo_open(struct net_device *ndev)
return 0;
err_cleanup:
- cpdma_ctlr_stop(cpsw->dma);
+ if (!cpsw->usage_count) {
+ cpdma_ctlr_stop(cpsw->dma);
+ cpsw_destroy_xdp_rxqs(cpsw);
+ }
+
for_each_slave(priv, cpsw_slave_stop, cpsw);
pm_runtime_put_sync(cpsw->dev);
netif_carrier_off(priv->ndev);
@@ -1447,6 +1780,7 @@ static int cpsw_ndo_stop(struct net_device *ndev)
cpsw_intr_disable(cpsw);
cpdma_ctlr_stop(cpsw->dma);
cpsw_ale_stop(cpsw->ale);
+ cpsw_destroy_xdp_rxqs(cpsw);
}
for_each_slave(priv, cpsw_slave_stop, cpsw);
@@ -2004,6 +2338,64 @@ static int cpsw_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type,
}
}
+static int cpsw_xdp_prog_setup(struct cpsw_priv *priv, struct netdev_bpf *bpf)
+{
+ struct bpf_prog *prog = bpf->prog;
+
+ if (!priv->xdpi.prog && !prog)
+ return 0;
+
+ if (!xdp_attachment_flags_ok(&priv->xdpi, bpf))
+ return -EBUSY;
+
+ WRITE_ONCE(priv->xdp_prog, prog);
+
+ xdp_attachment_setup(&priv->xdpi, bpf);
+
+ return 0;
+}
+
+static int cpsw_ndo_bpf(struct net_device *ndev, struct netdev_bpf *bpf)
+{
+ struct cpsw_priv *priv = netdev_priv(ndev);
+
+ switch (bpf->command) {
+ case XDP_SETUP_PROG:
+ return cpsw_xdp_prog_setup(priv, bpf);
+
+ case XDP_QUERY_PROG:
+ return xdp_attachment_query(&priv->xdpi, bpf);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int cpsw_ndo_xdp_xmit(struct net_device *ndev, int n,
+ struct xdp_frame **frames, u32 flags)
+{
+ struct cpsw_priv *priv = netdev_priv(ndev);
+ struct xdp_frame *xdpf;
+ int i, drops = 0;
+
+ if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK))
+ return -EINVAL;
+
+ for (i = 0; i < n; i++) {
+ xdpf = frames[i];
+ if (xdpf->len < CPSW_MIN_PACKET_SIZE) {
+ xdp_return_frame_rx_napi(xdpf);
+ drops++;
+ continue;
+ }
+
+ if (cpsw_xdp_tx_frame(priv, xdpf, NULL))
+ drops++;
+ }
+
+ return n - drops;
+}
+
#ifdef CONFIG_NET_POLL_CONTROLLER
static void cpsw_ndo_poll_controller(struct net_device *ndev)
{
@@ -2032,6 +2424,8 @@ static const struct net_device_ops cpsw_netdev_ops = {
.ndo_vlan_rx_add_vid = cpsw_ndo_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = cpsw_ndo_vlan_rx_kill_vid,
.ndo_setup_tc = cpsw_ndo_setup_tc,
+ .ndo_bpf = cpsw_ndo_bpf,
+ .ndo_xdp_xmit = cpsw_ndo_xdp_xmit,
};
static void cpsw_get_drvinfo(struct net_device *ndev,
@@ -2176,9 +2570,10 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
ret = PTR_ERR(slave_data->ifphy);
dev_err(&pdev->dev,
"%d: Error retrieving port phy: %d\n", i, ret);
- return ret;
+ goto err_node_put;
}
+ slave_data->slave_node = slave_node;
slave_data->phy_node = of_parse_phandle(slave_node,
"phy-handle", 0);
parp = of_get_property(slave_node, "phy_id", &lenp);
@@ -2194,7 +2589,7 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev, "failed to register fixed-link phy: %d\n", ret);
- return ret;
+ goto err_node_put;
}
slave_data->phy_node = of_node_get(slave_node);
} else if (parp) {
@@ -2212,7 +2607,8 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
of_node_put(mdio_node);
if (!mdio) {
dev_err(&pdev->dev, "Missing mdio platform device\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err_node_put;
}
snprintf(slave_data->phy_id, sizeof(slave_data->phy_id),
PHY_ID_FMT, mdio->name, phyid);
@@ -2227,7 +2623,8 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
if (slave_data->phy_if < 0) {
dev_err(&pdev->dev, "Missing or malformed slave[%d] phy-mode property\n",
i);
- return slave_data->phy_if;
+ ret = slave_data->phy_if;
+ goto err_node_put;
}
no_phy_slave:
@@ -2238,7 +2635,7 @@ no_phy_slave:
ret = ti_cm_get_macid(&pdev->dev, i,
slave_data->mac_addr);
if (ret)
- return ret;
+ goto err_node_put;
}
if (data->dual_emac) {
if (of_property_read_u32(slave_node, "dual_emac_res_vlan",
@@ -2253,17 +2650,22 @@ no_phy_slave:
}
i++;
- if (i == data->slaves)
- break;
+ if (i == data->slaves) {
+ ret = 0;
+ goto err_node_put;
+ }
}
return 0;
+
+err_node_put:
+ of_node_put(slave_node);
+ return ret;
}
static void cpsw_remove_dt(struct platform_device *pdev)
{
- struct net_device *ndev = platform_get_drvdata(pdev);
- struct cpsw_common *cpsw = ndev_to_cpsw(ndev);
+ struct cpsw_common *cpsw = platform_get_drvdata(pdev);
struct cpsw_platform_data *data = &cpsw->data;
struct device_node *node = pdev->dev.of_node;
struct device_node *slave_node;
@@ -2281,8 +2683,10 @@ static void cpsw_remove_dt(struct platform_device *pdev)
of_node_put(slave_data->phy_node);
i++;
- if (i == data->slaves)
+ if (i == data->slaves) {
+ of_node_put(slave_node);
break;
+ }
}
of_platform_depopulate(&pdev->dev);
@@ -2330,6 +2734,7 @@ static int cpsw_probe_dual_emac(struct cpsw_priv *priv)
/* register the network device */
SET_NETDEV_DEV(ndev, cpsw->dev);
+ ndev->dev.of_node = cpsw->slaves[1].data->slave_node;
ret = register_netdev(ndev);
if (ret)
dev_err(cpsw->dev, "cpsw: error registering net device\n");
@@ -2474,7 +2879,7 @@ static int cpsw_probe(struct platform_device *pdev)
goto clean_cpts;
}
- platform_set_drvdata(pdev, ndev);
+ platform_set_drvdata(pdev, cpsw);
priv = netdev_priv(ndev);
priv->cpsw = cpsw;
priv->ndev = ndev;
@@ -2507,6 +2912,7 @@ static int cpsw_probe(struct platform_device *pdev)
/* register the network device */
SET_NETDEV_DEV(ndev, dev);
+ ndev->dev.of_node = cpsw->slaves[0].data->slave_node;
ret = register_netdev(ndev);
if (ret) {
dev_err(dev, "error registering net device\n");
@@ -2567,9 +2973,8 @@ clean_runtime_disable_ret:
static int cpsw_remove(struct platform_device *pdev)
{
- struct net_device *ndev = platform_get_drvdata(pdev);
- struct cpsw_common *cpsw = ndev_to_cpsw(ndev);
- int ret;
+ struct cpsw_common *cpsw = platform_get_drvdata(pdev);
+ int i, ret;
ret = pm_runtime_get_sync(&pdev->dev);
if (ret < 0) {
@@ -2577,9 +2982,9 @@ static int cpsw_remove(struct platform_device *pdev)
return ret;
}
- if (cpsw->data.dual_emac)
- unregister_netdev(cpsw->slaves[1].ndev);
- unregister_netdev(ndev);
+ for (i = 0; i < cpsw->data.slaves; i++)
+ if (cpsw->slaves[i].ndev)
+ unregister_netdev(cpsw->slaves[i].ndev);
cpts_release(cpsw->cpts);
cpdma_ctlr_destroy(cpsw->dma);
@@ -2592,20 +2997,13 @@ static int cpsw_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int cpsw_suspend(struct device *dev)
{
- struct net_device *ndev = dev_get_drvdata(dev);
- struct cpsw_common *cpsw = ndev_to_cpsw(ndev);
-
- if (cpsw->data.dual_emac) {
- int i;
+ struct cpsw_common *cpsw = dev_get_drvdata(dev);
+ int i;
- for (i = 0; i < cpsw->data.slaves; i++) {
+ for (i = 0; i < cpsw->data.slaves; i++)
+ if (cpsw->slaves[i].ndev)
if (netif_running(cpsw->slaves[i].ndev))
cpsw_ndo_stop(cpsw->slaves[i].ndev);
- }
- } else {
- if (netif_running(ndev))
- cpsw_ndo_stop(ndev);
- }
/* Select sleep pin state */
pinctrl_pm_select_sleep_state(dev);
@@ -2615,25 +3013,20 @@ static int cpsw_suspend(struct device *dev)
static int cpsw_resume(struct device *dev)
{
- struct net_device *ndev = dev_get_drvdata(dev);
- struct cpsw_common *cpsw = ndev_to_cpsw(ndev);
+ struct cpsw_common *cpsw = dev_get_drvdata(dev);
+ int i;
/* Select default pin state */
pinctrl_pm_select_default_state(dev);
/* shut up ASSERT_RTNL() warning in netif_set_real_num_tx/rx_queues */
rtnl_lock();
- if (cpsw->data.dual_emac) {
- int i;
- for (i = 0; i < cpsw->data.slaves; i++) {
+ for (i = 0; i < cpsw->data.slaves; i++)
+ if (cpsw->slaves[i].ndev)
if (netif_running(cpsw->slaves[i].ndev))
cpsw_ndo_open(cpsw->slaves[i].ndev);
- }
- } else {
- if (netif_running(ndev))
- cpsw_ndo_open(ndev);
- }
+
rtnl_unlock();
return 0;
diff --git a/drivers/net/ethernet/ti/cpsw_ethtool.c b/drivers/net/ethernet/ti/cpsw_ethtool.c
index 6d1c9ebae7cc..31248a6cc642 100644
--- a/drivers/net/ethernet/ti/cpsw_ethtool.c
+++ b/drivers/net/ethernet/ti/cpsw_ethtool.c
@@ -458,21 +458,22 @@ int cpsw_nway_reset(struct net_device *ndev)
static void cpsw_suspend_data_pass(struct net_device *ndev)
{
struct cpsw_common *cpsw = ndev_to_cpsw(ndev);
- struct cpsw_slave *slave;
int i;
/* Disable NAPI scheduling */
cpsw_intr_disable(cpsw);
/* Stop all transmit queues for every network device.
- * Disable re-using rx descriptors with dormant_on.
*/
- for (i = cpsw->data.slaves, slave = cpsw->slaves; i; i--, slave++) {
- if (!(slave->ndev && netif_running(slave->ndev)))
+ for (i = 0; i < cpsw->data.slaves; i++) {
+ ndev = cpsw->slaves[i].ndev;
+ if (!(ndev && netif_running(ndev)))
continue;
- netif_tx_stop_all_queues(slave->ndev);
- netif_dormant_on(slave->ndev);
+ netif_tx_stop_all_queues(ndev);
+
+ /* Barrier, so that stop_queue visible to other cpus */
+ smp_mb__after_atomic();
}
/* Handle rest of tx packets and stop cpdma channels */
@@ -483,14 +484,8 @@ static int cpsw_resume_data_pass(struct net_device *ndev)
{
struct cpsw_priv *priv = netdev_priv(ndev);
struct cpsw_common *cpsw = priv->cpsw;
- struct cpsw_slave *slave;
int i, ret;
- /* Allow rx packets handling */
- for (i = cpsw->data.slaves, slave = cpsw->slaves; i; i--, slave++)
- if (slave->ndev && netif_running(slave->ndev))
- netif_dormant_off(slave->ndev);
-
/* After this receive is started */
if (cpsw->usage_count) {
ret = cpsw_fill_rx_channels(priv);
@@ -502,9 +497,11 @@ static int cpsw_resume_data_pass(struct net_device *ndev)
}
/* Resume transmit for every affected interface */
- for (i = cpsw->data.slaves, slave = cpsw->slaves; i; i--, slave++)
- if (slave->ndev && netif_running(slave->ndev))
- netif_tx_start_all_queues(slave->ndev);
+ for (i = 0; i < cpsw->data.slaves; i++) {
+ ndev = cpsw->slaves[i].ndev;
+ if (ndev && netif_running(ndev))
+ netif_tx_start_all_queues(ndev);
+ }
return 0;
}
@@ -581,14 +578,26 @@ static int cpsw_update_channels_res(struct cpsw_priv *priv, int ch_num, int rx,
return 0;
}
+static void cpsw_fail(struct cpsw_common *cpsw)
+{
+ struct net_device *ndev;
+ int i;
+
+ for (i = 0; i < cpsw->data.slaves; i++) {
+ ndev = cpsw->slaves[i].ndev;
+ if (ndev)
+ dev_close(ndev);
+ }
+}
+
int cpsw_set_channels_common(struct net_device *ndev,
struct ethtool_channels *chs,
cpdma_handler_fn rx_handler)
{
struct cpsw_priv *priv = netdev_priv(ndev);
struct cpsw_common *cpsw = priv->cpsw;
- struct cpsw_slave *slave;
- int i, ret;
+ struct net_device *sl_ndev;
+ int i, new_pools, ret;
ret = cpsw_check_ch_settings(cpsw, chs);
if (ret < 0)
@@ -596,6 +605,8 @@ int cpsw_set_channels_common(struct net_device *ndev,
cpsw_suspend_data_pass(ndev);
+ new_pools = (chs->rx_count != cpsw->rx_ch_num) && cpsw->usage_count;
+
ret = cpsw_update_channels_res(priv, chs->rx_count, 1, rx_handler);
if (ret)
goto err;
@@ -604,35 +615,40 @@ int cpsw_set_channels_common(struct net_device *ndev,
if (ret)
goto err;
- for (i = cpsw->data.slaves, slave = cpsw->slaves; i; i--, slave++) {
- if (!(slave->ndev && netif_running(slave->ndev)))
+ for (i = 0; i < cpsw->data.slaves; i++) {
+ sl_ndev = cpsw->slaves[i].ndev;
+ if (!(sl_ndev && netif_running(sl_ndev)))
continue;
/* Inform stack about new count of queues */
- ret = netif_set_real_num_tx_queues(slave->ndev,
- cpsw->tx_ch_num);
+ ret = netif_set_real_num_tx_queues(sl_ndev, cpsw->tx_ch_num);
if (ret) {
dev_err(priv->dev, "cannot set real number of tx queues\n");
goto err;
}
- ret = netif_set_real_num_rx_queues(slave->ndev,
- cpsw->rx_ch_num);
+ ret = netif_set_real_num_rx_queues(sl_ndev, cpsw->rx_ch_num);
if (ret) {
dev_err(priv->dev, "cannot set real number of rx queues\n");
goto err;
}
}
- if (cpsw->usage_count)
- cpsw_split_res(cpsw);
+ cpsw_split_res(cpsw);
+
+ if (new_pools) {
+ cpsw_destroy_xdp_rxqs(cpsw);
+ ret = cpsw_create_xdp_rxqs(cpsw);
+ if (ret)
+ goto err;
+ }
ret = cpsw_resume_data_pass(ndev);
if (!ret)
return 0;
err:
dev_err(priv->dev, "cannot update channels number, closing device\n");
- dev_close(ndev);
+ cpsw_fail(cpsw);
return ret;
}
@@ -652,9 +668,8 @@ void cpsw_get_ringparam(struct net_device *ndev,
int cpsw_set_ringparam(struct net_device *ndev,
struct ethtool_ringparam *ering)
{
- struct cpsw_priv *priv = netdev_priv(ndev);
- struct cpsw_common *cpsw = priv->cpsw;
- int ret;
+ struct cpsw_common *cpsw = ndev_to_cpsw(ndev);
+ int descs_num, ret;
/* ignore ering->tx_pending - only rx_pending adjustment is supported */
@@ -663,22 +678,34 @@ int cpsw_set_ringparam(struct net_device *ndev,
ering->rx_pending > (cpsw->descs_pool_size - CPSW_MAX_QUEUES))
return -EINVAL;
- if (ering->rx_pending == cpdma_get_num_rx_descs(cpsw->dma))
+ descs_num = cpdma_get_num_rx_descs(cpsw->dma);
+ if (ering->rx_pending == descs_num)
return 0;
cpsw_suspend_data_pass(ndev);
- cpdma_set_num_rx_descs(cpsw->dma, ering->rx_pending);
+ ret = cpdma_set_num_rx_descs(cpsw->dma, ering->rx_pending);
+ if (ret) {
+ if (cpsw_resume_data_pass(ndev))
+ goto err;
+
+ return ret;
+ }
- if (cpsw->usage_count)
- cpdma_chan_split_pool(cpsw->dma);
+ if (cpsw->usage_count) {
+ cpsw_destroy_xdp_rxqs(cpsw);
+ ret = cpsw_create_xdp_rxqs(cpsw);
+ if (ret)
+ goto err;
+ }
ret = cpsw_resume_data_pass(ndev);
if (!ret)
return 0;
-
+err:
+ cpdma_set_num_rx_descs(cpsw->dma, descs_num);
dev_err(cpsw->dev, "cannot set ring params, closing device\n");
- dev_close(ndev);
+ cpsw_fail(cpsw);
return ret;
}
diff --git a/drivers/net/ethernet/ti/cpsw_priv.h b/drivers/net/ethernet/ti/cpsw_priv.h
index 04795b97ee71..362c5a986869 100644
--- a/drivers/net/ethernet/ti/cpsw_priv.h
+++ b/drivers/net/ethernet/ti/cpsw_priv.h
@@ -272,6 +272,7 @@ struct cpsw_host_regs {
};
struct cpsw_slave_data {
+ struct device_node *slave_node;
struct device_node *phy_node;
char phy_id[MII_BUS_ID_SIZE];
int phy_if;
@@ -346,6 +347,7 @@ struct cpsw_common {
int rx_ch_num, tx_ch_num;
int speed;
int usage_count;
+ struct page_pool *page_pool[CPSW_MAX_QUEUES];
};
struct cpsw_priv {
@@ -360,6 +362,10 @@ struct cpsw_priv {
int shp_cfg_speed;
int tx_ts_enabled;
int rx_ts_enabled;
+ struct bpf_prog *xdp_prog;
+ struct xdp_rxq_info xdp_rxq[CPSW_MAX_QUEUES];
+ struct xdp_attachment_info xdpi;
+
u32 emac_port;
struct cpsw_common *cpsw;
};
@@ -391,6 +397,8 @@ int cpsw_fill_rx_channels(struct cpsw_priv *priv);
void cpsw_intr_enable(struct cpsw_common *cpsw);
void cpsw_intr_disable(struct cpsw_common *cpsw);
void cpsw_tx_handler(void *token, int len, int status);
+int cpsw_create_xdp_rxqs(struct cpsw_common *cpsw);
+void cpsw_destroy_xdp_rxqs(struct cpsw_common *cpsw);
/* ethtool */
u32 cpsw_get_msglevel(struct net_device *ndev);
diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c
index e257018ada71..61136428e2c0 100644
--- a/drivers/net/ethernet/ti/cpts.c
+++ b/drivers/net/ethernet/ti/cpts.c
@@ -5,6 +5,7 @@
* Copyright (C) 2012 Richard Cochran <richardcochran@gmail.com>
*
*/
+#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/if.h>
#include <linux/hrtimer.h>
@@ -532,6 +533,82 @@ static void cpts_calc_mult_shift(struct cpts *cpts)
freq, cpts->cc.mult, cpts->cc.shift, (ns - NSEC_PER_SEC));
}
+static int cpts_of_mux_clk_setup(struct cpts *cpts, struct device_node *node)
+{
+ struct device_node *refclk_np;
+ const char **parent_names;
+ unsigned int num_parents;
+ struct clk_hw *clk_hw;
+ int ret = -EINVAL;
+ u32 *mux_table;
+
+ refclk_np = of_get_child_by_name(node, "cpts-refclk-mux");
+ if (!refclk_np)
+ /* refclk selection supported not for all SoCs */
+ return 0;
+
+ num_parents = of_clk_get_parent_count(refclk_np);
+ if (num_parents < 1) {
+ dev_err(cpts->dev, "mux-clock %s must have parents\n",
+ refclk_np->name);
+ goto mux_fail;
+ }
+
+ parent_names = devm_kzalloc(cpts->dev, (sizeof(char *) * num_parents),
+ GFP_KERNEL);
+
+ mux_table = devm_kzalloc(cpts->dev, sizeof(*mux_table) * num_parents,
+ GFP_KERNEL);
+ if (!mux_table || !parent_names) {
+ ret = -ENOMEM;
+ goto mux_fail;
+ }
+
+ of_clk_parent_fill(refclk_np, parent_names, num_parents);
+
+ ret = of_property_read_variable_u32_array(refclk_np, "ti,mux-tbl",
+ mux_table,
+ num_parents, num_parents);
+ if (ret < 0)
+ goto mux_fail;
+
+ clk_hw = clk_hw_register_mux_table(cpts->dev, refclk_np->name,
+ parent_names, num_parents,
+ 0,
+ &cpts->reg->rftclk_sel, 0, 0x1F,
+ 0, mux_table, NULL);
+ if (IS_ERR(clk_hw)) {
+ ret = PTR_ERR(clk_hw);
+ goto mux_fail;
+ }
+
+ ret = devm_add_action_or_reset(cpts->dev,
+ (void(*)(void *))clk_hw_unregister_mux,
+ clk_hw);
+ if (ret) {
+ dev_err(cpts->dev, "add clkmux unreg action %d", ret);
+ goto mux_fail;
+ }
+
+ ret = of_clk_add_hw_provider(refclk_np, of_clk_hw_simple_get, clk_hw);
+ if (ret)
+ goto mux_fail;
+
+ ret = devm_add_action_or_reset(cpts->dev,
+ (void(*)(void *))of_clk_del_provider,
+ refclk_np);
+ if (ret) {
+ dev_err(cpts->dev, "add clkmux provider unreg action %d", ret);
+ goto mux_fail;
+ }
+
+ return ret;
+
+mux_fail:
+ of_node_put(refclk_np);
+ return ret;
+}
+
static int cpts_of_parse(struct cpts *cpts, struct device_node *node)
{
int ret = -EINVAL;
@@ -547,7 +624,7 @@ static int cpts_of_parse(struct cpts *cpts, struct device_node *node)
(!cpts->cc.mult && cpts->cc.shift))
goto of_error;
- return 0;
+ return cpts_of_mux_clk_setup(cpts, node);
of_error:
dev_err(cpts->dev, "CPTS: Missing property in the DT.\n");
@@ -572,9 +649,14 @@ struct cpts *cpts_create(struct device *dev, void __iomem *regs,
if (ret)
return ERR_PTR(ret);
- cpts->refclk = devm_clk_get(dev, "cpts");
+ cpts->refclk = devm_get_clk_from_child(dev, node, "cpts");
+ if (IS_ERR(cpts->refclk))
+ /* try get clk from dev node for compatibility */
+ cpts->refclk = devm_clk_get(dev, "cpts");
+
if (IS_ERR(cpts->refclk)) {
- dev_err(dev, "Failed to get cpts refclk\n");
+ dev_err(dev, "Failed to get cpts refclk %ld\n",
+ PTR_ERR(cpts->refclk));
return ERR_CAST(cpts->refclk);
}
diff --git a/drivers/net/ethernet/ti/cpts.h b/drivers/net/ethernet/ti/cpts.h
index 024aab6af12f..bb997c11ee15 100644
--- a/drivers/net/ethernet/ti/cpts.h
+++ b/drivers/net/ethernet/ti/cpts.h
@@ -24,7 +24,7 @@
struct cpsw_cpts {
u32 idver; /* Identification and version */
u32 control; /* Time sync control */
- u32 res1;
+ u32 rftclk_sel; /* Reference Clock Select Register */
u32 ts_push; /* Time stamp event push */
u32 ts_load_val; /* Time stamp load value */
u32 ts_load_en; /* Time stamp load enable */
diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c
index 35bf14d8e7af..a65edd2770e6 100644
--- a/drivers/net/ethernet/ti/davinci_cpdma.c
+++ b/drivers/net/ethernet/ti/davinci_cpdma.c
@@ -134,6 +134,15 @@ struct cpdma_control_info {
#define ACCESS_RW (ACCESS_RO | ACCESS_WO)
};
+struct submit_info {
+ struct cpdma_chan *chan;
+ int directed;
+ void *token;
+ void *data_virt;
+ dma_addr_t data_dma;
+ int len;
+};
+
static struct cpdma_control_info controls[] = {
[CPDMA_TX_RLIM] = {CPDMA_DMACONTROL, 8, 0xffff, ACCESS_RW},
[CPDMA_CMD_IDLE] = {CPDMA_DMACONTROL, 3, 1, ACCESS_WO},
@@ -176,6 +185,8 @@ static struct cpdma_control_info controls[] = {
(directed << CPDMA_TO_PORT_SHIFT)); \
} while (0)
+#define CPDMA_DMA_EXT_MAP BIT(16)
+
static void cpdma_desc_pool_destroy(struct cpdma_ctlr *ctlr)
{
struct cpdma_desc_pool *pool = ctlr->pool;
@@ -1002,34 +1013,26 @@ static void __cpdma_chan_submit(struct cpdma_chan *chan,
}
}
-int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
- int len, int directed)
+static int cpdma_chan_submit_si(struct submit_info *si)
{
+ struct cpdma_chan *chan = si->chan;
struct cpdma_ctlr *ctlr = chan->ctlr;
+ int len = si->len;
+ int swlen = len;
struct cpdma_desc __iomem *desc;
dma_addr_t buffer;
- unsigned long flags;
u32 mode;
- int ret = 0;
-
- spin_lock_irqsave(&chan->lock, flags);
-
- if (chan->state == CPDMA_STATE_TEARDOWN) {
- ret = -EINVAL;
- goto unlock_ret;
- }
+ int ret;
if (chan->count >= chan->desc_num) {
chan->stats.desc_alloc_fail++;
- ret = -ENOMEM;
- goto unlock_ret;
+ return -ENOMEM;
}
desc = cpdma_desc_alloc(ctlr->pool);
if (!desc) {
chan->stats.desc_alloc_fail++;
- ret = -ENOMEM;
- goto unlock_ret;
+ return -ENOMEM;
}
if (len < ctlr->params.min_packet_size) {
@@ -1037,16 +1040,21 @@ int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
chan->stats.runt_transmit_buff++;
}
- buffer = dma_map_single(ctlr->dev, data, len, chan->dir);
- ret = dma_mapping_error(ctlr->dev, buffer);
- if (ret) {
- cpdma_desc_free(ctlr->pool, desc, 1);
- ret = -EINVAL;
- goto unlock_ret;
- }
-
mode = CPDMA_DESC_OWNER | CPDMA_DESC_SOP | CPDMA_DESC_EOP;
- cpdma_desc_to_port(chan, mode, directed);
+ cpdma_desc_to_port(chan, mode, si->directed);
+
+ if (si->data_dma) {
+ buffer = si->data_dma;
+ dma_sync_single_for_device(ctlr->dev, buffer, len, chan->dir);
+ swlen |= CPDMA_DMA_EXT_MAP;
+ } else {
+ buffer = dma_map_single(ctlr->dev, si->data_virt, len, chan->dir);
+ ret = dma_mapping_error(ctlr->dev, buffer);
+ if (ret) {
+ cpdma_desc_free(ctlr->pool, desc, 1);
+ return -EINVAL;
+ }
+ }
/* Relaxed IO accessors can be used here as there is read barrier
* at the end of write sequence.
@@ -1055,9 +1063,9 @@ int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
writel_relaxed(buffer, &desc->hw_buffer);
writel_relaxed(len, &desc->hw_len);
writel_relaxed(mode | len, &desc->hw_mode);
- writel_relaxed((uintptr_t)token, &desc->sw_token);
+ writel_relaxed((uintptr_t)si->token, &desc->sw_token);
writel_relaxed(buffer, &desc->sw_buffer);
- writel_relaxed(len, &desc->sw_len);
+ writel_relaxed(swlen, &desc->sw_len);
desc_read(desc, sw_len);
__cpdma_chan_submit(chan, desc);
@@ -1066,8 +1074,105 @@ int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
chan_write(chan, rxfree, 1);
chan->count++;
+ return 0;
+}
-unlock_ret:
+int cpdma_chan_idle_submit(struct cpdma_chan *chan, void *token, void *data,
+ int len, int directed)
+{
+ struct submit_info si;
+ unsigned long flags;
+ int ret;
+
+ si.chan = chan;
+ si.token = token;
+ si.data_virt = data;
+ si.data_dma = 0;
+ si.len = len;
+ si.directed = directed;
+
+ spin_lock_irqsave(&chan->lock, flags);
+ if (chan->state == CPDMA_STATE_TEARDOWN) {
+ spin_unlock_irqrestore(&chan->lock, flags);
+ return -EINVAL;
+ }
+
+ ret = cpdma_chan_submit_si(&si);
+ spin_unlock_irqrestore(&chan->lock, flags);
+ return ret;
+}
+
+int cpdma_chan_idle_submit_mapped(struct cpdma_chan *chan, void *token,
+ dma_addr_t data, int len, int directed)
+{
+ struct submit_info si;
+ unsigned long flags;
+ int ret;
+
+ si.chan = chan;
+ si.token = token;
+ si.data_virt = NULL;
+ si.data_dma = data;
+ si.len = len;
+ si.directed = directed;
+
+ spin_lock_irqsave(&chan->lock, flags);
+ if (chan->state == CPDMA_STATE_TEARDOWN) {
+ spin_unlock_irqrestore(&chan->lock, flags);
+ return -EINVAL;
+ }
+
+ ret = cpdma_chan_submit_si(&si);
+ spin_unlock_irqrestore(&chan->lock, flags);
+ return ret;
+}
+
+int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
+ int len, int directed)
+{
+ struct submit_info si;
+ unsigned long flags;
+ int ret;
+
+ si.chan = chan;
+ si.token = token;
+ si.data_virt = data;
+ si.data_dma = 0;
+ si.len = len;
+ si.directed = directed;
+
+ spin_lock_irqsave(&chan->lock, flags);
+ if (chan->state != CPDMA_STATE_ACTIVE) {
+ spin_unlock_irqrestore(&chan->lock, flags);
+ return -EINVAL;
+ }
+
+ ret = cpdma_chan_submit_si(&si);
+ spin_unlock_irqrestore(&chan->lock, flags);
+ return ret;
+}
+
+int cpdma_chan_submit_mapped(struct cpdma_chan *chan, void *token,
+ dma_addr_t data, int len, int directed)
+{
+ struct submit_info si;
+ unsigned long flags;
+ int ret;
+
+ si.chan = chan;
+ si.token = token;
+ si.data_virt = NULL;
+ si.data_dma = data;
+ si.len = len;
+ si.directed = directed;
+
+ spin_lock_irqsave(&chan->lock, flags);
+ if (chan->state != CPDMA_STATE_ACTIVE) {
+ spin_unlock_irqrestore(&chan->lock, flags);
+ return -EINVAL;
+ }
+
+ ret = cpdma_chan_submit_si(&si);
spin_unlock_irqrestore(&chan->lock, flags);
return ret;
}
@@ -1097,10 +1202,17 @@ static void __cpdma_chan_free(struct cpdma_chan *chan,
uintptr_t token;
token = desc_read(desc, sw_token);
- buff_dma = desc_read(desc, sw_buffer);
origlen = desc_read(desc, sw_len);
- dma_unmap_single(ctlr->dev, buff_dma, origlen, chan->dir);
+ buff_dma = desc_read(desc, sw_buffer);
+ if (origlen & CPDMA_DMA_EXT_MAP) {
+ origlen &= ~CPDMA_DMA_EXT_MAP;
+ dma_sync_single_for_cpu(ctlr->dev, buff_dma, origlen,
+ chan->dir);
+ } else {
+ dma_unmap_single(ctlr->dev, buff_dma, origlen, chan->dir);
+ }
+
cpdma_desc_free(pool, desc, 1);
(*chan->handler)((void *)token, outlen, status);
}
@@ -1311,8 +1423,23 @@ int cpdma_get_num_tx_descs(struct cpdma_ctlr *ctlr)
return ctlr->num_tx_desc;
}
-void cpdma_set_num_rx_descs(struct cpdma_ctlr *ctlr, int num_rx_desc)
+int cpdma_set_num_rx_descs(struct cpdma_ctlr *ctlr, int num_rx_desc)
{
+ unsigned long flags;
+ int temp, ret;
+
+ spin_lock_irqsave(&ctlr->lock, flags);
+
+ temp = ctlr->num_rx_desc;
ctlr->num_rx_desc = num_rx_desc;
ctlr->num_tx_desc = ctlr->pool->num_desc - ctlr->num_rx_desc;
+ ret = cpdma_chan_split_pool(ctlr);
+ if (ret) {
+ ctlr->num_rx_desc = temp;
+ ctlr->num_tx_desc = ctlr->pool->num_desc - ctlr->num_rx_desc;
+ }
+
+ spin_unlock_irqrestore(&ctlr->lock, flags);
+
+ return ret;
}
diff --git a/drivers/net/ethernet/ti/davinci_cpdma.h b/drivers/net/ethernet/ti/davinci_cpdma.h
index 10376062dafa..d3cfe234d16a 100644
--- a/drivers/net/ethernet/ti/davinci_cpdma.h
+++ b/drivers/net/ethernet/ti/davinci_cpdma.h
@@ -77,8 +77,14 @@ int cpdma_chan_stop(struct cpdma_chan *chan);
int cpdma_chan_get_stats(struct cpdma_chan *chan,
struct cpdma_chan_stats *stats);
+int cpdma_chan_submit_mapped(struct cpdma_chan *chan, void *token,
+ dma_addr_t data, int len, int directed);
int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
int len, int directed);
+int cpdma_chan_idle_submit_mapped(struct cpdma_chan *chan, void *token,
+ dma_addr_t data, int len, int directed);
+int cpdma_chan_idle_submit(struct cpdma_chan *chan, void *token, void *data,
+ int len, int directed);
int cpdma_chan_process(struct cpdma_chan *chan, int quota);
int cpdma_ctlr_int_ctrl(struct cpdma_ctlr *ctlr, bool enable);
@@ -110,8 +116,7 @@ enum cpdma_control {
int cpdma_control_get(struct cpdma_ctlr *ctlr, int control);
int cpdma_control_set(struct cpdma_ctlr *ctlr, int control, int value);
int cpdma_get_num_rx_descs(struct cpdma_ctlr *ctlr);
-void cpdma_set_num_rx_descs(struct cpdma_ctlr *ctlr, int num_rx_desc);
+int cpdma_set_num_rx_descs(struct cpdma_ctlr *ctlr, int num_rx_desc);
int cpdma_get_num_tx_descs(struct cpdma_ctlr *ctlr);
-int cpdma_chan_split_pool(struct cpdma_ctlr *ctlr);
#endif
diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c
index 4bf65cab79e6..ae27be85e363 100644
--- a/drivers/net/ethernet/ti/davinci_emac.c
+++ b/drivers/net/ethernet/ti/davinci_emac.c
@@ -1371,7 +1371,7 @@ static int emac_devioctl(struct net_device *ndev, struct ifreq *ifrq, int cmd)
return -EOPNOTSUPP;
}
-static int match_first_device(struct device *dev, void *data)
+static int match_first_device(struct device *dev, const void *data)
{
if (dev->parent && dev->parent->of_node)
return of_device_is_compatible(dev->parent->of_node,
@@ -1428,8 +1428,8 @@ static int emac_dev_open(struct net_device *ndev)
if (!skb)
break;
- ret = cpdma_chan_submit(priv->rxchan, skb, skb->data,
- skb_tailroom(skb), 0);
+ ret = cpdma_chan_idle_submit(priv->rxchan, skb, skb->data,
+ skb_tailroom(skb), 0);
if (WARN_ON(ret < 0))
break;
}
diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c
index ec179700c184..2c1fac33136c 100644
--- a/drivers/net/ethernet/ti/netcp_ethss.c
+++ b/drivers/net/ethernet/ti/netcp_ethss.c
@@ -3554,7 +3554,7 @@ static int set_gbenu_ethss_priv(struct gbe_priv *gbe_dev,
static int gbe_probe(struct netcp_device *netcp_device, struct device *dev,
struct device_node *node, void **inst_priv)
{
- struct device_node *interfaces, *interface;
+ struct device_node *interfaces, *interface, *cpts_node;
struct device_node *secondary_ports;
struct cpsw_ale_params ale_params;
struct gbe_priv *gbe_dev;
@@ -3713,7 +3713,12 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev,
dev_dbg(gbe_dev->dev, "Created a gbe ale engine\n");
}
- gbe_dev->cpts = cpts_create(gbe_dev->dev, gbe_dev->cpts_reg, node);
+ cpts_node = of_get_child_by_name(node, "cpts");
+ if (!cpts_node)
+ cpts_node = of_node_get(node);
+
+ gbe_dev->cpts = cpts_create(gbe_dev->dev, gbe_dev->cpts_reg, cpts_node);
+ of_node_put(cpts_node);
if (IS_ENABLED(CONFIG_TI_CPTS) && IS_ERR(gbe_dev->cpts)) {
ret = PTR_ERR(gbe_dev->cpts);
goto free_sec_ports;
diff --git a/drivers/net/ethernet/ti/tlan.c b/drivers/net/ethernet/ti/tlan.c
index b4ab1a5f6cd0..78f0f2d59e22 100644
--- a/drivers/net/ethernet/ti/tlan.c
+++ b/drivers/net/ethernet/ti/tlan.c
@@ -855,7 +855,6 @@ static int tlan_init(struct net_device *dev)
dev->name);
return -ENOMEM;
}
- memset(priv->dma_storage, 0, dma_size);
priv->rx_list = (struct tlan_list *)
ALIGN((unsigned long)priv->dma_storage, 8);
priv->rx_list_dma = ALIGN(priv->dma_storage_dma, 8);
diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_net.h b/drivers/net/ethernet/toshiba/ps3_gelic_net.h
index 3ecddb72f45a..051033580f0a 100644
--- a/drivers/net/ethernet/toshiba/ps3_gelic_net.h
+++ b/drivers/net/ethernet/toshiba/ps3_gelic_net.h
@@ -301,7 +301,7 @@ struct gelic_card {
*/
unsigned int irq;
struct gelic_descr *tx_top, *rx_top;
- struct gelic_descr descr[0]; /* must be the last */
+ struct gelic_descr descr[]; /* must be the last */
};
struct gelic_port {
diff --git a/drivers/net/ethernet/toshiba/tc35815.c b/drivers/net/ethernet/toshiba/tc35815.c
index c50a9772f4af..8479a440527b 100644
--- a/drivers/net/ethernet/toshiba/tc35815.c
+++ b/drivers/net/ethernet/toshiba/tc35815.c
@@ -694,10 +694,10 @@ err_out:
* should provide a "tc35815-mac" device with a MAC address in its
* platform_data.
*/
-static int tc35815_mac_match(struct device *dev, void *data)
+static int tc35815_mac_match(struct device *dev, const void *data)
{
struct platform_device *plat_dev = to_platform_device(dev);
- struct pci_dev *pci_dev = data;
+ const struct pci_dev *pci_dev = data;
unsigned int id = pci_dev->irq;
return !strcmp(plat_dev->name, "tc35815-mac") && plat_dev->id == id;
}
diff --git a/drivers/net/ethernet/via/via-velocity.h b/drivers/net/ethernet/via/via-velocity.h
index c0ecc6c7b5e0..cdfe7809e3c1 100644
--- a/drivers/net/ethernet/via/via-velocity.h
+++ b/drivers/net/ethernet/via/via-velocity.h
@@ -1509,7 +1509,7 @@ static inline int velocity_get_ip(struct velocity_info *vptr)
rcu_read_lock();
in_dev = __in_dev_get_rcu(vptr->netdev);
if (in_dev != NULL) {
- ifa = (struct in_ifaddr *) in_dev->ifa_list;
+ ifa = rcu_dereference(in_dev->ifa_list);
if (ifa != NULL) {
memcpy(vptr->ip_addr, &ifa->ifa_address, 4);
res = 0;
diff --git a/drivers/net/ethernet/wiznet/w5100-spi.c b/drivers/net/ethernet/wiznet/w5100-spi.c
index 918b3e50850a..2b4126d2427d 100644
--- a/drivers/net/ethernet/wiznet/w5100-spi.c
+++ b/drivers/net/ethernet/wiznet/w5100-spi.c
@@ -15,6 +15,7 @@
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/of_net.h>
+#include <linux/of_device.h>
#include <linux/spi/spi.h>
#include "w5100.h"
@@ -409,14 +410,32 @@ static const struct w5100_ops w5500_ops = {
.init = w5500_spi_init,
};
+static const struct of_device_id w5100_of_match[] = {
+ { .compatible = "wiznet,w5100", .data = (const void*)W5100, },
+ { .compatible = "wiznet,w5200", .data = (const void*)W5200, },
+ { .compatible = "wiznet,w5500", .data = (const void*)W5500, },
+ { },
+};
+MODULE_DEVICE_TABLE(of, w5100_of_match);
+
static int w5100_spi_probe(struct spi_device *spi)
{
- const struct spi_device_id *id = spi_get_device_id(spi);
+ const struct of_device_id *of_id;
const struct w5100_ops *ops;
+ kernel_ulong_t driver_data;
int priv_size;
const void *mac = of_get_mac_address(spi->dev.of_node);
- switch (id->driver_data) {
+ if (spi->dev.of_node) {
+ of_id = of_match_device(w5100_of_match, &spi->dev);
+ if (!of_id)
+ return -ENODEV;
+ driver_data = (kernel_ulong_t)of_id->data;
+ } else {
+ driver_data = spi_get_device_id(spi)->driver_data;
+ }
+
+ switch (driver_data) {
case W5100:
ops = &w5100_spi_ops;
priv_size = 0;
@@ -453,6 +472,7 @@ static struct spi_driver w5100_spi_driver = {
.driver = {
.name = "w5100",
.pm = &w5100_pm_ops,
+ .of_match_table = w5100_of_match,
},
.probe = w5100_spi_probe,
.remove = w5100_spi_remove,
diff --git a/drivers/net/ethernet/xilinx/Kconfig b/drivers/net/ethernet/xilinx/Kconfig
index af96e05c5bcd..8d994cebb6b0 100644
--- a/drivers/net/ethernet/xilinx/Kconfig
+++ b/drivers/net/ethernet/xilinx/Kconfig
@@ -6,7 +6,7 @@
config NET_VENDOR_XILINX
bool "Xilinx devices"
default y
- depends on PPC || PPC32 || MICROBLAZE || ARCH_ZYNQ || MIPS || X86 || COMPILE_TEST
+ depends on PPC || PPC32 || MICROBLAZE || ARCH_ZYNQ || MIPS || X86 || ARM || COMPILE_TEST
---help---
If you have a network (Ethernet) card belonging to this class, say Y.
@@ -26,8 +26,8 @@ config XILINX_EMACLITE
config XILINX_AXI_EMAC
tristate "Xilinx 10/100/1000 AXI Ethernet support"
- depends on MICROBLAZE
- select PHYLIB
+ depends on MICROBLAZE || X86 || ARM || COMPILE_TEST
+ select PHYLINK
---help---
This driver supports the 10/100/1000 Ethernet from Xilinx for the
AXI bus interface used in Xilinx Virtex FPGAs.
diff --git a/drivers/net/ethernet/xilinx/ll_temac.h b/drivers/net/ethernet/xilinx/ll_temac.h
index 1aeda084b8f1..276292bca334 100644
--- a/drivers/net/ethernet/xilinx/ll_temac.h
+++ b/drivers/net/ethernet/xilinx/ll_temac.h
@@ -361,7 +361,7 @@ struct temac_local {
/* For synchronization of indirect register access. Must be
* shared mutex between interfaces in same TEMAC block.
*/
- struct mutex *indirect_mutex;
+ spinlock_t *indirect_lock;
u32 options; /* Current options word */
int last_link;
unsigned int temac_features;
@@ -388,8 +388,9 @@ struct temac_local {
/* xilinx_temac.c */
int temac_indirect_busywait(struct temac_local *lp);
u32 temac_indirect_in32(struct temac_local *lp, int reg);
+u32 temac_indirect_in32_locked(struct temac_local *lp, int reg);
void temac_indirect_out32(struct temac_local *lp, int reg, u32 value);
-
+void temac_indirect_out32_locked(struct temac_local *lp, int reg, u32 value);
/* xilinx_temac_mdio.c */
int temac_mdio_setup(struct temac_local *lp, struct platform_device *pdev);
diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index 14870d659f7d..21c1b4322ea7 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -22,7 +22,6 @@
*
* TODO:
* - Factor out locallink DMA code into separate driver
- * - Fix multicast assignment.
* - Fix support for hardware checksumming.
* - Testing. Lots and lots of testing.
*
@@ -53,6 +52,7 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
+#include <linux/processor.h>
#include <linux/platform_data/xilinx-ll-temac.h>
#include "ll_temac.h"
@@ -84,51 +84,118 @@ static void _temac_iow_le(struct temac_local *lp, int offset, u32 value)
return iowrite32(value, lp->regs + offset);
}
+static bool hard_acs_rdy(struct temac_local *lp)
+{
+ return temac_ior(lp, XTE_RDY0_OFFSET) & XTE_RDY0_HARD_ACS_RDY_MASK;
+}
+
+static bool hard_acs_rdy_or_timeout(struct temac_local *lp, ktime_t timeout)
+{
+ ktime_t cur = ktime_get();
+
+ return hard_acs_rdy(lp) || ktime_after(cur, timeout);
+}
+
+/* Poll for maximum 20 ms. This is similar to the 2 jiffies @ 100 Hz
+ * that was used before, and should cover MDIO bus speed down to 3200
+ * Hz.
+ */
+#define HARD_ACS_RDY_POLL_NS (20 * NSEC_PER_MSEC)
+
+/**
+ * temac_indirect_busywait - Wait for current indirect register access
+ * to complete.
+ */
int temac_indirect_busywait(struct temac_local *lp)
{
- unsigned long end = jiffies + 2;
+ ktime_t timeout = ktime_add_ns(ktime_get(), HARD_ACS_RDY_POLL_NS);
- while (!(temac_ior(lp, XTE_RDY0_OFFSET) & XTE_RDY0_HARD_ACS_RDY_MASK)) {
- if (time_before_eq(end, jiffies)) {
- WARN_ON(1);
- return -ETIMEDOUT;
- }
- usleep_range(500, 1000);
- }
- return 0;
+ spin_until_cond(hard_acs_rdy_or_timeout(lp, timeout));
+ if (WARN_ON(!hard_acs_rdy(lp)))
+ return -ETIMEDOUT;
+ else
+ return 0;
}
/**
- * temac_indirect_in32
- *
- * lp->indirect_mutex must be held when calling this function
+ * temac_indirect_in32 - Indirect register read access. This function
+ * must be called without lp->indirect_lock being held.
*/
u32 temac_indirect_in32(struct temac_local *lp, int reg)
{
- u32 val;
+ unsigned long flags;
+ int val;
+
+ spin_lock_irqsave(lp->indirect_lock, flags);
+ val = temac_indirect_in32_locked(lp, reg);
+ spin_unlock_irqrestore(lp->indirect_lock, flags);
+ return val;
+}
- if (temac_indirect_busywait(lp))
+/**
+ * temac_indirect_in32_locked - Indirect register read access. This
+ * function must be called with lp->indirect_lock being held. Use
+ * this together with spin_lock_irqsave/spin_lock_irqrestore to avoid
+ * repeated lock/unlock and to ensure uninterrupted access to indirect
+ * registers.
+ */
+u32 temac_indirect_in32_locked(struct temac_local *lp, int reg)
+{
+ /* This initial wait should normally not spin, as we always
+ * try to wait for indirect access to complete before
+ * releasing the indirect_lock.
+ */
+ if (WARN_ON(temac_indirect_busywait(lp)))
return -ETIMEDOUT;
+ /* Initiate read from indirect register */
temac_iow(lp, XTE_CTL0_OFFSET, reg);
- if (temac_indirect_busywait(lp))
+ /* Wait for indirect register access to complete. We really
+ * should not see timeouts, and could even end up causing
+ * problem for following indirect access, so let's make a bit
+ * of WARN noise.
+ */
+ if (WARN_ON(temac_indirect_busywait(lp)))
return -ETIMEDOUT;
- val = temac_ior(lp, XTE_LSW0_OFFSET);
-
- return val;
+ /* Value is ready now */
+ return temac_ior(lp, XTE_LSW0_OFFSET);
}
/**
- * temac_indirect_out32
- *
- * lp->indirect_mutex must be held when calling this function
+ * temac_indirect_out32 - Indirect register write access. This function
+ * must be called without lp->indirect_lock being held.
*/
void temac_indirect_out32(struct temac_local *lp, int reg, u32 value)
{
- if (temac_indirect_busywait(lp))
+ unsigned long flags;
+
+ spin_lock_irqsave(lp->indirect_lock, flags);
+ temac_indirect_out32_locked(lp, reg, value);
+ spin_unlock_irqrestore(lp->indirect_lock, flags);
+}
+
+/**
+ * temac_indirect_out32_locked - Indirect register write access. This
+ * function must be called with lp->indirect_lock being held. Use
+ * this together with spin_lock_irqsave/spin_lock_irqrestore to avoid
+ * repeated lock/unlock and to ensure uninterrupted access to indirect
+ * registers.
+ */
+void temac_indirect_out32_locked(struct temac_local *lp, int reg, u32 value)
+{
+ /* As in temac_indirect_in32_locked(), we should normally not
+ * spin here. And if it happens, we actually end up silently
+ * ignoring the write request. Ouch.
+ */
+ if (WARN_ON(temac_indirect_busywait(lp)))
return;
+ /* Initiate write to indirect register */
temac_iow(lp, XTE_LSW0_OFFSET, value);
temac_iow(lp, XTE_CTL0_OFFSET, CNTLREG_WRITE_ENABLE_MASK | reg);
- temac_indirect_busywait(lp);
+ /* As in temac_indirect_in32_locked(), we should not see timeouts
+ * here. And if it happens, we continue before the write has
+ * completed. Not good.
+ */
+ WARN_ON(temac_indirect_busywait(lp));
}
/**
@@ -344,20 +411,21 @@ out:
static void temac_do_set_mac_address(struct net_device *ndev)
{
struct temac_local *lp = netdev_priv(ndev);
+ unsigned long flags;
/* set up unicast MAC address filter set its mac address */
- mutex_lock(lp->indirect_mutex);
- temac_indirect_out32(lp, XTE_UAW0_OFFSET,
- (ndev->dev_addr[0]) |
- (ndev->dev_addr[1] << 8) |
- (ndev->dev_addr[2] << 16) |
- (ndev->dev_addr[3] << 24));
+ spin_lock_irqsave(lp->indirect_lock, flags);
+ temac_indirect_out32_locked(lp, XTE_UAW0_OFFSET,
+ (ndev->dev_addr[0]) |
+ (ndev->dev_addr[1] << 8) |
+ (ndev->dev_addr[2] << 16) |
+ (ndev->dev_addr[3] << 24));
/* There are reserved bits in EUAW1
* so don't affect them Set MAC bits [47:32] in EUAW1 */
- temac_indirect_out32(lp, XTE_UAW1_OFFSET,
- (ndev->dev_addr[4] & 0x000000ff) |
- (ndev->dev_addr[5] << 8));
- mutex_unlock(lp->indirect_mutex);
+ temac_indirect_out32_locked(lp, XTE_UAW1_OFFSET,
+ (ndev->dev_addr[4] & 0x000000ff) |
+ (ndev->dev_addr[5] << 8));
+ spin_unlock_irqrestore(lp->indirect_lock, flags);
}
static int temac_init_mac_address(struct net_device *ndev, const void *address)
@@ -383,49 +451,58 @@ static int temac_set_mac_address(struct net_device *ndev, void *p)
static void temac_set_multicast_list(struct net_device *ndev)
{
struct temac_local *lp = netdev_priv(ndev);
- u32 multi_addr_msw, multi_addr_lsw, val;
- int i;
+ u32 multi_addr_msw, multi_addr_lsw;
+ int i = 0;
+ unsigned long flags;
+ bool promisc_mode_disabled = false;
- mutex_lock(lp->indirect_mutex);
- if (ndev->flags & (IFF_ALLMULTI | IFF_PROMISC) ||
- netdev_mc_count(ndev) > MULTICAST_CAM_TABLE_NUM) {
- /*
- * We must make the kernel realise we had to move
- * into promisc mode or we start all out war on
- * the cable. If it was a promisc request the
- * flag is already set. If not we assert it.
- */
- ndev->flags |= IFF_PROMISC;
+ if (ndev->flags & (IFF_PROMISC | IFF_ALLMULTI) ||
+ (netdev_mc_count(ndev) > MULTICAST_CAM_TABLE_NUM)) {
temac_indirect_out32(lp, XTE_AFM_OFFSET, XTE_AFM_EPPRM_MASK);
dev_info(&ndev->dev, "Promiscuous mode enabled.\n");
- } else if (!netdev_mc_empty(ndev)) {
+ return;
+ }
+
+ spin_lock_irqsave(lp->indirect_lock, flags);
+
+ if (!netdev_mc_empty(ndev)) {
struct netdev_hw_addr *ha;
- i = 0;
netdev_for_each_mc_addr(ha, ndev) {
- if (i >= MULTICAST_CAM_TABLE_NUM)
+ if (WARN_ON(i >= MULTICAST_CAM_TABLE_NUM))
break;
multi_addr_msw = ((ha->addr[3] << 24) |
(ha->addr[2] << 16) |
(ha->addr[1] << 8) |
(ha->addr[0]));
- temac_indirect_out32(lp, XTE_MAW0_OFFSET,
- multi_addr_msw);
+ temac_indirect_out32_locked(lp, XTE_MAW0_OFFSET,
+ multi_addr_msw);
multi_addr_lsw = ((ha->addr[5] << 8) |
(ha->addr[4]) | (i << 16));
- temac_indirect_out32(lp, XTE_MAW1_OFFSET,
- multi_addr_lsw);
+ temac_indirect_out32_locked(lp, XTE_MAW1_OFFSET,
+ multi_addr_lsw);
i++;
}
- } else {
- val = temac_indirect_in32(lp, XTE_AFM_OFFSET);
- temac_indirect_out32(lp, XTE_AFM_OFFSET,
- val & ~XTE_AFM_EPPRM_MASK);
- temac_indirect_out32(lp, XTE_MAW0_OFFSET, 0);
- temac_indirect_out32(lp, XTE_MAW1_OFFSET, 0);
- dev_info(&ndev->dev, "Promiscuous mode disabled.\n");
}
- mutex_unlock(lp->indirect_mutex);
+
+ /* Clear all or remaining/unused address table entries */
+ while (i < MULTICAST_CAM_TABLE_NUM) {
+ temac_indirect_out32_locked(lp, XTE_MAW0_OFFSET, 0);
+ temac_indirect_out32_locked(lp, XTE_MAW1_OFFSET, i << 16);
+ i++;
+ }
+
+ /* Enable address filter block if currently disabled */
+ if (temac_indirect_in32_locked(lp, XTE_AFM_OFFSET)
+ & XTE_AFM_EPPRM_MASK) {
+ temac_indirect_out32_locked(lp, XTE_AFM_OFFSET, 0);
+ promisc_mode_disabled = true;
+ }
+
+ spin_unlock_irqrestore(lp->indirect_lock, flags);
+
+ if (promisc_mode_disabled)
+ dev_info(&ndev->dev, "Promiscuous mode disabled.\n");
}
static struct temac_option {
@@ -516,17 +593,19 @@ static u32 temac_setoptions(struct net_device *ndev, u32 options)
struct temac_local *lp = netdev_priv(ndev);
struct temac_option *tp = &temac_options[0];
int reg;
+ unsigned long flags;
- mutex_lock(lp->indirect_mutex);
+ spin_lock_irqsave(lp->indirect_lock, flags);
while (tp->opt) {
- reg = temac_indirect_in32(lp, tp->reg) & ~tp->m_or;
- if (options & tp->opt)
+ reg = temac_indirect_in32_locked(lp, tp->reg) & ~tp->m_or;
+ if (options & tp->opt) {
reg |= tp->m_or;
- temac_indirect_out32(lp, tp->reg, reg);
+ temac_indirect_out32_locked(lp, tp->reg, reg);
+ }
tp++;
}
+ spin_unlock_irqrestore(lp->indirect_lock, flags);
lp->options |= options;
- mutex_unlock(lp->indirect_mutex);
return 0;
}
@@ -537,6 +616,7 @@ static void temac_device_reset(struct net_device *ndev)
struct temac_local *lp = netdev_priv(ndev);
u32 timeout;
u32 val;
+ unsigned long flags;
/* Perform a software reset */
@@ -545,7 +625,6 @@ static void temac_device_reset(struct net_device *ndev)
dev_dbg(&ndev->dev, "%s()\n", __func__);
- mutex_lock(lp->indirect_mutex);
/* Reset the receiver and wait for it to finish reset */
temac_indirect_out32(lp, XTE_RXC1_OFFSET, XTE_RXC1_RXRST_MASK);
timeout = 1000;
@@ -571,8 +650,11 @@ static void temac_device_reset(struct net_device *ndev)
}
/* Disable the receiver */
- val = temac_indirect_in32(lp, XTE_RXC1_OFFSET);
- temac_indirect_out32(lp, XTE_RXC1_OFFSET, val & ~XTE_RXC1_RXEN_MASK);
+ spin_lock_irqsave(lp->indirect_lock, flags);
+ val = temac_indirect_in32_locked(lp, XTE_RXC1_OFFSET);
+ temac_indirect_out32_locked(lp, XTE_RXC1_OFFSET,
+ val & ~XTE_RXC1_RXEN_MASK);
+ spin_unlock_irqrestore(lp->indirect_lock, flags);
/* Reset Local Link (DMA) */
lp->dma_out(lp, DMA_CONTROL_REG, DMA_CONTROL_RST);
@@ -592,12 +674,12 @@ static void temac_device_reset(struct net_device *ndev)
"temac_device_reset descriptor allocation failed\n");
}
- temac_indirect_out32(lp, XTE_RXC0_OFFSET, 0);
- temac_indirect_out32(lp, XTE_RXC1_OFFSET, 0);
- temac_indirect_out32(lp, XTE_TXC_OFFSET, 0);
- temac_indirect_out32(lp, XTE_FCC_OFFSET, XTE_FCC_RXFLO_MASK);
-
- mutex_unlock(lp->indirect_mutex);
+ spin_lock_irqsave(lp->indirect_lock, flags);
+ temac_indirect_out32_locked(lp, XTE_RXC0_OFFSET, 0);
+ temac_indirect_out32_locked(lp, XTE_RXC1_OFFSET, 0);
+ temac_indirect_out32_locked(lp, XTE_TXC_OFFSET, 0);
+ temac_indirect_out32_locked(lp, XTE_FCC_OFFSET, XTE_FCC_RXFLO_MASK);
+ spin_unlock_irqrestore(lp->indirect_lock, flags);
/* Sync default options with HW
* but leave receiver and transmitter disabled. */
@@ -621,13 +703,14 @@ static void temac_adjust_link(struct net_device *ndev)
struct phy_device *phy = ndev->phydev;
u32 mii_speed;
int link_state;
+ unsigned long flags;
/* hash together the state values to decide if something has changed */
link_state = phy->speed | (phy->duplex << 1) | phy->link;
- mutex_lock(lp->indirect_mutex);
if (lp->last_link != link_state) {
- mii_speed = temac_indirect_in32(lp, XTE_EMCFG_OFFSET);
+ spin_lock_irqsave(lp->indirect_lock, flags);
+ mii_speed = temac_indirect_in32_locked(lp, XTE_EMCFG_OFFSET);
mii_speed &= ~XTE_EMCFG_LINKSPD_MASK;
switch (phy->speed) {
@@ -637,11 +720,12 @@ static void temac_adjust_link(struct net_device *ndev)
}
/* Write new speed setting out to TEMAC */
- temac_indirect_out32(lp, XTE_EMCFG_OFFSET, mii_speed);
+ temac_indirect_out32_locked(lp, XTE_EMCFG_OFFSET, mii_speed);
+ spin_unlock_irqrestore(lp->indirect_lock, flags);
+
lp->last_link = link_state;
phy_print_status(phy);
}
- mutex_unlock(lp->indirect_mutex);
}
#ifdef CONFIG_64BIT
@@ -1011,6 +1095,7 @@ static const struct net_device_ops temac_netdev_ops = {
.ndo_open = temac_open,
.ndo_stop = temac_stop,
.ndo_start_xmit = temac_start_xmit,
+ .ndo_set_rx_mode = temac_set_multicast_list,
.ndo_set_mac_address = temac_set_mac_address,
.ndo_validate_addr = eth_validate_addr,
.ndo_do_ioctl = temac_ioctl,
@@ -1076,7 +1161,6 @@ static int temac_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ndev);
SET_NETDEV_DEV(ndev, &pdev->dev);
- ndev->flags &= ~IFF_MULTICAST; /* clear multicast */
ndev->features = NETIF_F_SG;
ndev->netdev_ops = &temac_netdev_ops;
ndev->ethtool_ops = &temac_ethtool_ops;
@@ -1103,17 +1187,17 @@ static int temac_probe(struct platform_device *pdev)
/* Setup mutex for synchronization of indirect register access */
if (pdata) {
- if (!pdata->indirect_mutex) {
+ if (!pdata->indirect_lock) {
dev_err(&pdev->dev,
- "indirect_mutex missing in platform_data\n");
+ "indirect_lock missing in platform_data\n");
return -EINVAL;
}
- lp->indirect_mutex = pdata->indirect_mutex;
+ lp->indirect_lock = pdata->indirect_lock;
} else {
- lp->indirect_mutex = devm_kmalloc(&pdev->dev,
- sizeof(*lp->indirect_mutex),
- GFP_KERNEL);
- mutex_init(lp->indirect_mutex);
+ lp->indirect_lock = devm_kmalloc(&pdev->dev,
+ sizeof(*lp->indirect_lock),
+ GFP_KERNEL);
+ spin_lock_init(lp->indirect_lock);
}
/* map device registers */
diff --git a/drivers/net/ethernet/xilinx/ll_temac_mdio.c b/drivers/net/ethernet/xilinx/ll_temac_mdio.c
index a4667326f745..6fd2dea4e60f 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_mdio.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_mdio.c
@@ -25,14 +25,15 @@ static int temac_mdio_read(struct mii_bus *bus, int phy_id, int reg)
{
struct temac_local *lp = bus->priv;
u32 rc;
+ unsigned long flags;
/* Write the PHY address to the MIIM Access Initiator register.
* When the transfer completes, the PHY register value will appear
* in the LSW0 register */
- mutex_lock(lp->indirect_mutex);
+ spin_lock_irqsave(lp->indirect_lock, flags);
temac_iow(lp, XTE_LSW0_OFFSET, (phy_id << 5) | reg);
- rc = temac_indirect_in32(lp, XTE_MIIMAI_OFFSET);
- mutex_unlock(lp->indirect_mutex);
+ rc = temac_indirect_in32_locked(lp, XTE_MIIMAI_OFFSET);
+ spin_unlock_irqrestore(lp->indirect_lock, flags);
dev_dbg(lp->dev, "temac_mdio_read(phy_id=%i, reg=%x) == %x\n",
phy_id, reg, rc);
@@ -43,6 +44,7 @@ static int temac_mdio_read(struct mii_bus *bus, int phy_id, int reg)
static int temac_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 val)
{
struct temac_local *lp = bus->priv;
+ unsigned long flags;
dev_dbg(lp->dev, "temac_mdio_write(phy_id=%i, reg=%x, val=%x)\n",
phy_id, reg, val);
@@ -50,10 +52,10 @@ static int temac_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 val)
/* First write the desired value into the write data register
* and then write the address into the access initiator register
*/
- mutex_lock(lp->indirect_mutex);
- temac_indirect_out32(lp, XTE_MGTDR_OFFSET, val);
- temac_indirect_out32(lp, XTE_MIIMAI_OFFSET, (phy_id << 5) | reg);
- mutex_unlock(lp->indirect_mutex);
+ spin_lock_irqsave(lp->indirect_lock, flags);
+ temac_indirect_out32_locked(lp, XTE_MGTDR_OFFSET, val);
+ temac_indirect_out32_locked(lp, XTE_MIIMAI_OFFSET, (phy_id << 5) | reg);
+ spin_unlock_irqrestore(lp->indirect_lock, flags);
return 0;
}
@@ -87,9 +89,7 @@ int temac_mdio_setup(struct temac_local *lp, struct platform_device *pdev)
/* Enable the MDIO bus by asserting the enable bit and writing
* in the clock config */
- mutex_lock(lp->indirect_mutex);
temac_indirect_out32(lp, XTE_MC_OFFSET, 1 << 6 | clk_div);
- mutex_unlock(lp->indirect_mutex);
bus = devm_mdiobus_alloc(&pdev->dev);
if (!bus)
@@ -116,10 +116,8 @@ int temac_mdio_setup(struct temac_local *lp, struct platform_device *pdev)
if (rc)
return rc;
- mutex_lock(lp->indirect_mutex);
dev_dbg(lp->dev, "MDIO bus registered; MC:%x\n",
temac_indirect_in32(lp, XTE_MC_OFFSET));
- mutex_unlock(lp->indirect_mutex);
return 0;
}
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
index 011adae32b89..2dacfc85b3ba 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
@@ -13,6 +13,7 @@
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/if_vlan.h>
+#include <linux/phylink.h>
/* Packet size info */
#define XAE_HDR_SIZE 14 /* Size of Ethernet header */
@@ -83,6 +84,8 @@
#define XAXIDMA_CR_RUNSTOP_MASK 0x00000001 /* Start/stop DMA channel */
#define XAXIDMA_CR_RESET_MASK 0x00000004 /* Reset DMA engine */
+#define XAXIDMA_SR_HALT_MASK 0x00000001 /* Indicates DMA channel halted */
+
#define XAXIDMA_BD_NDESC_OFFSET 0x00 /* Next descriptor pointer */
#define XAXIDMA_BD_BUFA_OFFSET 0x08 /* Buffer address */
#define XAXIDMA_BD_CTRL_LEN_OFFSET 0x18 /* Control/buffer length */
@@ -356,9 +359,6 @@
* @app2: MM2S/S2MM User Application Field 2.
* @app3: MM2S/S2MM User Application Field 3.
* @app4: MM2S/S2MM User Application Field 4.
- * @sw_id_offset: MM2S/S2MM Sw ID
- * @reserved5: Reserved and not used
- * @reserved6: Reserved and not used
*/
struct axidma_bd {
u32 next; /* Physical address of next buffer descriptor */
@@ -373,11 +373,9 @@ struct axidma_bd {
u32 app1; /* TX start << 16 | insert */
u32 app2; /* TX csum seed */
u32 app3;
- u32 app4;
- u32 sw_id_offset;
- u32 reserved5;
- u32 reserved6;
-};
+ u32 app4; /* Last field used by HW */
+ struct sk_buff *skb;
+} __aligned(XAXIDMA_BD_MINIMUM_ALIGNMENT);
/**
* struct axienet_local - axienet private per device data
@@ -385,6 +383,7 @@ struct axidma_bd {
* @dev: Pointer to device structure
* @phy_node: Pointer to device node structure
* @mii_bus: Pointer to MII bus structure
+ * @regs_start: Resource start for axienet device addresses
* @regs: Base address for the axienet_local device address space
* @dma_regs: Base address for the axidma device address space
* @dma_err_tasklet: Tasklet structure to process Axi DMA errors
@@ -422,10 +421,17 @@ struct axienet_local {
/* Connection to PHY device */
struct device_node *phy_node;
+ struct phylink *phylink;
+ struct phylink_config phylink_config;
+
+ /* Clock for AXI bus */
+ struct clk *clk;
+
/* MDIO bus data */
struct mii_bus *mii_bus; /* MII bus reference */
/* IO registers, dma functions and IRQs */
+ resource_size_t regs_start;
void __iomem *regs;
void __iomem *dma_regs;
@@ -433,17 +439,19 @@ struct axienet_local {
int tx_irq;
int rx_irq;
+ int eth_irq;
phy_interface_t phy_mode;
u32 options; /* Current options word */
- u32 last_link;
u32 features;
/* Buffer descriptors */
struct axidma_bd *tx_bd_v;
dma_addr_t tx_bd_p;
+ u32 tx_bd_num;
struct axidma_bd *rx_bd_v;
dma_addr_t rx_bd_p;
+ u32 rx_bd_num;
u32 tx_bd_ci;
u32 tx_bd_tail;
u32 rx_bd_ci;
@@ -481,7 +489,7 @@ struct axienet_option {
*/
static inline u32 axienet_ior(struct axienet_local *lp, off_t offset)
{
- return in_be32(lp->regs + offset);
+ return ioread32(lp->regs + offset);
}
static inline u32 axinet_ior_read_mcr(struct axienet_local *lp)
@@ -501,12 +509,13 @@ static inline u32 axinet_ior_read_mcr(struct axienet_local *lp)
static inline void axienet_iow(struct axienet_local *lp, off_t offset,
u32 value)
{
- out_be32((lp->regs + offset), value);
+ iowrite32(value, lp->regs + offset);
}
/* Function prototypes visible in xilinx_axienet_mdio.c for other files */
-int axienet_mdio_setup(struct axienet_local *lp, struct device_node *np);
-int axienet_mdio_wait_until_ready(struct axienet_local *lp);
+int axienet_mdio_enable(struct axienet_local *lp);
+void axienet_mdio_disable(struct axienet_local *lp);
+int axienet_mdio_setup(struct axienet_local *lp);
void axienet_mdio_teardown(struct axienet_local *lp);
#endif /* XILINX_AXI_ENET_H */
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 831967f6eff8..4fc627fb4d11 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -7,6 +7,7 @@
* Copyright (c) 2008-2009 Secret Lab Technologies Ltd.
* Copyright (c) 2010 - 2011 Michal Simek <monstr@monstr.eu>
* Copyright (c) 2010 - 2011 PetaLogix
+ * Copyright (c) 2019 SED Systems, a division of Calian Ltd.
* Copyright (c) 2010 - 2012 Xilinx, Inc. All rights reserved.
*
* This is a driver for the Xilinx Axi Ethernet which is used in the Virtex6
@@ -21,6 +22,7 @@
* - Add support for extended VLAN support.
*/
+#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/module.h>
@@ -38,16 +40,18 @@
#include "xilinx_axienet.h"
-/* Descriptors defines for Tx and Rx DMA - 2^n for the best performance */
-#define TX_BD_NUM 64
-#define RX_BD_NUM 128
+/* Descriptors defines for Tx and Rx DMA */
+#define TX_BD_NUM_DEFAULT 64
+#define RX_BD_NUM_DEFAULT 1024
+#define TX_BD_NUM_MAX 4096
+#define RX_BD_NUM_MAX 4096
/* Must be shorter than length of ethtool_drvinfo.driver field to fit */
#define DRIVER_NAME "xaxienet"
#define DRIVER_DESCRIPTION "Xilinx Axi Ethernet driver"
#define DRIVER_VERSION "1.00a"
-#define AXIENET_REGS_N 32
+#define AXIENET_REGS_N 40
/* Match table for of_platform binding */
static const struct of_device_id axienet_of_match[] = {
@@ -125,7 +129,7 @@ static struct axienet_option axienet_options[] = {
*/
static inline u32 axienet_dma_in32(struct axienet_local *lp, off_t reg)
{
- return in_be32(lp->dma_regs + reg);
+ return ioread32(lp->dma_regs + reg);
}
/**
@@ -140,7 +144,7 @@ static inline u32 axienet_dma_in32(struct axienet_local *lp, off_t reg)
static inline void axienet_dma_out32(struct axienet_local *lp,
off_t reg, u32 value)
{
- out_be32((lp->dma_regs + reg), value);
+ iowrite32(value, lp->dma_regs + reg);
}
/**
@@ -156,22 +160,21 @@ static void axienet_dma_bd_release(struct net_device *ndev)
int i;
struct axienet_local *lp = netdev_priv(ndev);
- for (i = 0; i < RX_BD_NUM; i++) {
+ for (i = 0; i < lp->rx_bd_num; i++) {
dma_unmap_single(ndev->dev.parent, lp->rx_bd_v[i].phys,
lp->max_frm_size, DMA_FROM_DEVICE);
- dev_kfree_skb((struct sk_buff *)
- (lp->rx_bd_v[i].sw_id_offset));
+ dev_kfree_skb(lp->rx_bd_v[i].skb);
}
if (lp->rx_bd_v) {
dma_free_coherent(ndev->dev.parent,
- sizeof(*lp->rx_bd_v) * RX_BD_NUM,
+ sizeof(*lp->rx_bd_v) * lp->rx_bd_num,
lp->rx_bd_v,
lp->rx_bd_p);
}
if (lp->tx_bd_v) {
dma_free_coherent(ndev->dev.parent,
- sizeof(*lp->tx_bd_v) * TX_BD_NUM,
+ sizeof(*lp->tx_bd_v) * lp->tx_bd_num,
lp->tx_bd_v,
lp->tx_bd_p);
}
@@ -201,33 +204,33 @@ static int axienet_dma_bd_init(struct net_device *ndev)
/* Allocate the Tx and Rx buffer descriptors. */
lp->tx_bd_v = dma_alloc_coherent(ndev->dev.parent,
- sizeof(*lp->tx_bd_v) * TX_BD_NUM,
+ sizeof(*lp->tx_bd_v) * lp->tx_bd_num,
&lp->tx_bd_p, GFP_KERNEL);
if (!lp->tx_bd_v)
goto out;
lp->rx_bd_v = dma_alloc_coherent(ndev->dev.parent,
- sizeof(*lp->rx_bd_v) * RX_BD_NUM,
+ sizeof(*lp->rx_bd_v) * lp->rx_bd_num,
&lp->rx_bd_p, GFP_KERNEL);
if (!lp->rx_bd_v)
goto out;
- for (i = 0; i < TX_BD_NUM; i++) {
+ for (i = 0; i < lp->tx_bd_num; i++) {
lp->tx_bd_v[i].next = lp->tx_bd_p +
sizeof(*lp->tx_bd_v) *
- ((i + 1) % TX_BD_NUM);
+ ((i + 1) % lp->tx_bd_num);
}
- for (i = 0; i < RX_BD_NUM; i++) {
+ for (i = 0; i < lp->rx_bd_num; i++) {
lp->rx_bd_v[i].next = lp->rx_bd_p +
sizeof(*lp->rx_bd_v) *
- ((i + 1) % RX_BD_NUM);
+ ((i + 1) % lp->rx_bd_num);
skb = netdev_alloc_skb_ip_align(ndev, lp->max_frm_size);
if (!skb)
goto out;
- lp->rx_bd_v[i].sw_id_offset = (u32) skb;
+ lp->rx_bd_v[i].skb = skb;
lp->rx_bd_v[i].phys = dma_map_single(ndev->dev.parent,
skb->data,
lp->max_frm_size,
@@ -269,7 +272,7 @@ static int axienet_dma_bd_init(struct net_device *ndev)
axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET,
cr | XAXIDMA_CR_RUNSTOP_MASK);
axienet_dma_out32(lp, XAXIDMA_RX_TDESC_OFFSET, lp->rx_bd_p +
- (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1)));
+ (sizeof(*lp->rx_bd_v) * (lp->rx_bd_num - 1)));
/* Write to the RS (Run-stop) bit in the Tx channel control register.
* Tx channel is now ready to run. But only after we write to the
@@ -434,17 +437,20 @@ static void axienet_setoptions(struct net_device *ndev, u32 options)
lp->options |= options;
}
-static void __axienet_device_reset(struct axienet_local *lp, off_t offset)
+static void __axienet_device_reset(struct axienet_local *lp)
{
u32 timeout;
/* Reset Axi DMA. This would reset Axi Ethernet core as well. The reset
* process of Axi DMA takes a while to complete as all pending
* commands/transfers will be flushed or completed during this
* reset process.
+ * Note that even though both TX and RX have their own reset register,
+ * they both reset the entire DMA core, so only one needs to be used.
*/
- axienet_dma_out32(lp, offset, XAXIDMA_CR_RESET_MASK);
+ axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, XAXIDMA_CR_RESET_MASK);
timeout = DELAY_OF_ONE_MILLISEC;
- while (axienet_dma_in32(lp, offset) & XAXIDMA_CR_RESET_MASK) {
+ while (axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET) &
+ XAXIDMA_CR_RESET_MASK) {
udelay(1);
if (--timeout == 0) {
netdev_err(lp->ndev, "%s: DMA reset timeout!\n",
@@ -470,8 +476,7 @@ static void axienet_device_reset(struct net_device *ndev)
u32 axienet_status;
struct axienet_local *lp = netdev_priv(ndev);
- __axienet_device_reset(lp, XAXIDMA_TX_CR_OFFSET);
- __axienet_device_reset(lp, XAXIDMA_RX_CR_OFFSET);
+ __axienet_device_reset(lp);
lp->max_frm_size = XAE_MAX_VLAN_FRAME_SIZE;
lp->options |= XAE_OPTION_VLAN;
@@ -498,6 +503,8 @@ static void axienet_device_reset(struct net_device *ndev)
axienet_status = axienet_ior(lp, XAE_IP_OFFSET);
if (axienet_status & XAE_INT_RXRJECT_MASK)
axienet_iow(lp, XAE_IS_OFFSET, XAE_INT_RXRJECT_MASK);
+ axienet_iow(lp, XAE_IE_OFFSET, lp->eth_irq > 0 ?
+ XAE_INT_RECV_ERROR_MASK : 0);
axienet_iow(lp, XAE_FCC_OFFSET, XAE_FCC_FCRX_MASK);
@@ -514,63 +521,6 @@ static void axienet_device_reset(struct net_device *ndev)
}
/**
- * axienet_adjust_link - Adjust the PHY link speed/duplex.
- * @ndev: Pointer to the net_device structure
- *
- * This function is called to change the speed and duplex setting after
- * auto negotiation is done by the PHY. This is the function that gets
- * registered with the PHY interface through the "of_phy_connect" call.
- */
-static void axienet_adjust_link(struct net_device *ndev)
-{
- u32 emmc_reg;
- u32 link_state;
- u32 setspeed = 1;
- struct axienet_local *lp = netdev_priv(ndev);
- struct phy_device *phy = ndev->phydev;
-
- link_state = phy->speed | (phy->duplex << 1) | phy->link;
- if (lp->last_link != link_state) {
- if ((phy->speed == SPEED_10) || (phy->speed == SPEED_100)) {
- if (lp->phy_mode == PHY_INTERFACE_MODE_1000BASEX)
- setspeed = 0;
- } else {
- if ((phy->speed == SPEED_1000) &&
- (lp->phy_mode == PHY_INTERFACE_MODE_MII))
- setspeed = 0;
- }
-
- if (setspeed == 1) {
- emmc_reg = axienet_ior(lp, XAE_EMMC_OFFSET);
- emmc_reg &= ~XAE_EMMC_LINKSPEED_MASK;
-
- switch (phy->speed) {
- case SPEED_1000:
- emmc_reg |= XAE_EMMC_LINKSPD_1000;
- break;
- case SPEED_100:
- emmc_reg |= XAE_EMMC_LINKSPD_100;
- break;
- case SPEED_10:
- emmc_reg |= XAE_EMMC_LINKSPD_10;
- break;
- default:
- dev_err(&ndev->dev, "Speed other than 10, 100 "
- "or 1Gbps is not supported\n");
- break;
- }
-
- axienet_iow(lp, XAE_EMMC_OFFSET, emmc_reg);
- lp->last_link = link_state;
- phy_print_status(phy);
- } else {
- netdev_err(ndev,
- "Error setting Axi Ethernet mac speed\n");
- }
- }
-}
-
-/**
* axienet_start_xmit_done - Invoked once a transmit is completed by the
* Axi DMA Tx channel.
* @ndev: Pointer to the net_device structure
@@ -595,26 +545,31 @@ static void axienet_start_xmit_done(struct net_device *ndev)
dma_unmap_single(ndev->dev.parent, cur_p->phys,
(cur_p->cntrl & XAXIDMA_BD_CTRL_LENGTH_MASK),
DMA_TO_DEVICE);
- if (cur_p->app4)
- dev_consume_skb_irq((struct sk_buff *)cur_p->app4);
+ if (cur_p->skb)
+ dev_consume_skb_irq(cur_p->skb);
/*cur_p->phys = 0;*/
cur_p->app0 = 0;
cur_p->app1 = 0;
cur_p->app2 = 0;
cur_p->app4 = 0;
cur_p->status = 0;
+ cur_p->skb = NULL;
size += status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK;
packets++;
- ++lp->tx_bd_ci;
- lp->tx_bd_ci %= TX_BD_NUM;
+ if (++lp->tx_bd_ci >= lp->tx_bd_num)
+ lp->tx_bd_ci = 0;
cur_p = &lp->tx_bd_v[lp->tx_bd_ci];
status = cur_p->status;
}
ndev->stats.tx_packets += packets;
ndev->stats.tx_bytes += size;
+
+ /* Matches barrier in axienet_start_xmit */
+ smp_mb();
+
netif_wake_queue(ndev);
}
@@ -635,7 +590,7 @@ static inline int axienet_check_tx_bd_space(struct axienet_local *lp,
int num_frag)
{
struct axidma_bd *cur_p;
- cur_p = &lp->tx_bd_v[(lp->tx_bd_tail + num_frag) % TX_BD_NUM];
+ cur_p = &lp->tx_bd_v[(lp->tx_bd_tail + num_frag) % lp->tx_bd_num];
if (cur_p->status & XAXIDMA_BD_STS_ALL_MASK)
return NETDEV_TX_BUSY;
return 0;
@@ -670,9 +625,19 @@ axienet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
if (axienet_check_tx_bd_space(lp, num_frag)) {
- if (!netif_queue_stopped(ndev))
- netif_stop_queue(ndev);
- return NETDEV_TX_BUSY;
+ if (netif_queue_stopped(ndev))
+ return NETDEV_TX_BUSY;
+
+ netif_stop_queue(ndev);
+
+ /* Matches barrier in axienet_start_xmit_done */
+ smp_mb();
+
+ /* Space might have just been freed - check again */
+ if (axienet_check_tx_bd_space(lp, num_frag))
+ return NETDEV_TX_BUSY;
+
+ netif_wake_queue(ndev);
}
if (skb->ip_summed == CHECKSUM_PARTIAL) {
@@ -695,8 +660,8 @@ axienet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
skb_headlen(skb), DMA_TO_DEVICE);
for (ii = 0; ii < num_frag; ii++) {
- ++lp->tx_bd_tail;
- lp->tx_bd_tail %= TX_BD_NUM;
+ if (++lp->tx_bd_tail >= lp->tx_bd_num)
+ lp->tx_bd_tail = 0;
cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
frag = &skb_shinfo(skb)->frags[ii];
cur_p->phys = dma_map_single(ndev->dev.parent,
@@ -707,13 +672,13 @@ axienet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
}
cur_p->cntrl |= XAXIDMA_BD_CTRL_TXEOF_MASK;
- cur_p->app4 = (unsigned long)skb;
+ cur_p->skb = skb;
tail_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail;
/* Start the transfer */
axienet_dma_out32(lp, XAXIDMA_TX_TDESC_OFFSET, tail_p);
- ++lp->tx_bd_tail;
- lp->tx_bd_tail %= TX_BD_NUM;
+ if (++lp->tx_bd_tail >= lp->tx_bd_num)
+ lp->tx_bd_tail = 0;
return NETDEV_TX_OK;
}
@@ -742,13 +707,15 @@ static void axienet_recv(struct net_device *ndev)
while ((cur_p->status & XAXIDMA_BD_STS_COMPLETE_MASK)) {
tail_p = lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_ci;
- skb = (struct sk_buff *) (cur_p->sw_id_offset);
- length = cur_p->app4 & 0x0000FFFF;
dma_unmap_single(ndev->dev.parent, cur_p->phys,
lp->max_frm_size,
DMA_FROM_DEVICE);
+ skb = cur_p->skb;
+ cur_p->skb = NULL;
+ length = cur_p->app4 & 0x0000FFFF;
+
skb_put(skb, length);
skb->protocol = eth_type_trans(skb, ndev);
/*skb_checksum_none_assert(skb);*/
@@ -783,10 +750,10 @@ static void axienet_recv(struct net_device *ndev)
DMA_FROM_DEVICE);
cur_p->cntrl = lp->max_frm_size;
cur_p->status = 0;
- cur_p->sw_id_offset = (u32) new_skb;
+ cur_p->skb = new_skb;
- ++lp->rx_bd_ci;
- lp->rx_bd_ci %= RX_BD_NUM;
+ if (++lp->rx_bd_ci >= lp->rx_bd_num)
+ lp->rx_bd_ci = 0;
cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
}
@@ -802,7 +769,7 @@ static void axienet_recv(struct net_device *ndev)
* @irq: irq number
* @_ndev: net_device pointer
*
- * Return: IRQ_HANDLED for all cases.
+ * Return: IRQ_HANDLED if device generated a TX interrupt, IRQ_NONE otherwise.
*
* This is the Axi DMA Tx done Isr. It invokes "axienet_start_xmit_done"
* to complete the BD processing.
@@ -821,7 +788,7 @@ static irqreturn_t axienet_tx_irq(int irq, void *_ndev)
goto out;
}
if (!(status & XAXIDMA_IRQ_ALL_MASK))
- dev_err(&ndev->dev, "No interrupts asserted in Tx path\n");
+ return IRQ_NONE;
if (status & XAXIDMA_IRQ_ERROR_MASK) {
dev_err(&ndev->dev, "DMA Tx error 0x%x\n", status);
dev_err(&ndev->dev, "Current BD is at: 0x%x\n",
@@ -851,7 +818,7 @@ out:
* @irq: irq number
* @_ndev: net_device pointer
*
- * Return: IRQ_HANDLED for all cases.
+ * Return: IRQ_HANDLED if device generated a RX interrupt, IRQ_NONE otherwise.
*
* This is the Axi DMA Rx Isr. It invokes "axienet_recv" to complete the BD
* processing.
@@ -870,7 +837,7 @@ static irqreturn_t axienet_rx_irq(int irq, void *_ndev)
goto out;
}
if (!(status & XAXIDMA_IRQ_ALL_MASK))
- dev_err(&ndev->dev, "No interrupts asserted in Rx path\n");
+ return IRQ_NONE;
if (status & XAXIDMA_IRQ_ERROR_MASK) {
dev_err(&ndev->dev, "DMA Rx error 0x%x\n", status);
dev_err(&ndev->dev, "Current BD is at: 0x%x\n",
@@ -895,6 +862,35 @@ out:
return IRQ_HANDLED;
}
+/**
+ * axienet_eth_irq - Ethernet core Isr.
+ * @irq: irq number
+ * @_ndev: net_device pointer
+ *
+ * Return: IRQ_HANDLED if device generated a core interrupt, IRQ_NONE otherwise.
+ *
+ * Handle miscellaneous conditions indicated by Ethernet core IRQ.
+ */
+static irqreturn_t axienet_eth_irq(int irq, void *_ndev)
+{
+ struct net_device *ndev = _ndev;
+ struct axienet_local *lp = netdev_priv(ndev);
+ unsigned int pending;
+
+ pending = axienet_ior(lp, XAE_IP_OFFSET);
+ if (!pending)
+ return IRQ_NONE;
+
+ if (pending & XAE_INT_RXFIFOOVR_MASK)
+ ndev->stats.rx_missed_errors++;
+
+ if (pending & XAE_INT_RXRJECT_MASK)
+ ndev->stats.rx_frame_errors++;
+
+ axienet_iow(lp, XAE_IS_OFFSET, pending);
+ return IRQ_HANDLED;
+}
+
static void axienet_dma_err_handler(unsigned long data);
/**
@@ -904,67 +900,72 @@ static void axienet_dma_err_handler(unsigned long data);
* Return: 0, on success.
* non-zero error value on failure
*
- * This is the driver open routine. It calls phy_start to start the PHY device.
+ * This is the driver open routine. It calls phylink_start to start the
+ * PHY device.
* It also allocates interrupt service routines, enables the interrupt lines
* and ISR handling. Axi Ethernet core is reset through Axi DMA core. Buffer
* descriptors are initialized.
*/
static int axienet_open(struct net_device *ndev)
{
- int ret, mdio_mcreg;
+ int ret;
struct axienet_local *lp = netdev_priv(ndev);
- struct phy_device *phydev = NULL;
dev_dbg(&ndev->dev, "axienet_open()\n");
- mdio_mcreg = axienet_ior(lp, XAE_MDIO_MC_OFFSET);
- ret = axienet_mdio_wait_until_ready(lp);
- if (ret < 0)
- return ret;
/* Disable the MDIO interface till Axi Ethernet Reset is completed.
* When we do an Axi Ethernet reset, it resets the complete core
- * including the MDIO. If MDIO is not disabled when the reset
- * process is started, MDIO will be broken afterwards.
+ * including the MDIO. MDIO must be disabled before resetting
+ * and re-enabled afterwards.
+ * Hold MDIO bus lock to avoid MDIO accesses during the reset.
*/
- axienet_iow(lp, XAE_MDIO_MC_OFFSET,
- (mdio_mcreg & (~XAE_MDIO_MC_MDIOEN_MASK)));
+ mutex_lock(&lp->mii_bus->mdio_lock);
+ axienet_mdio_disable(lp);
axienet_device_reset(ndev);
- /* Enable the MDIO */
- axienet_iow(lp, XAE_MDIO_MC_OFFSET, mdio_mcreg);
- ret = axienet_mdio_wait_until_ready(lp);
+ ret = axienet_mdio_enable(lp);
+ mutex_unlock(&lp->mii_bus->mdio_lock);
if (ret < 0)
return ret;
- if (lp->phy_node) {
- phydev = of_phy_connect(lp->ndev, lp->phy_node,
- axienet_adjust_link, 0, lp->phy_mode);
-
- if (!phydev)
- dev_err(lp->dev, "of_phy_connect() failed\n");
- else
- phy_start(phydev);
+ ret = phylink_of_phy_connect(lp->phylink, lp->dev->of_node, 0);
+ if (ret) {
+ dev_err(lp->dev, "phylink_of_phy_connect() failed: %d\n", ret);
+ return ret;
}
+ phylink_start(lp->phylink);
+
/* Enable tasklets for Axi DMA error handling */
tasklet_init(&lp->dma_err_tasklet, axienet_dma_err_handler,
(unsigned long) lp);
/* Enable interrupts for Axi DMA Tx */
- ret = request_irq(lp->tx_irq, axienet_tx_irq, 0, ndev->name, ndev);
+ ret = request_irq(lp->tx_irq, axienet_tx_irq, IRQF_SHARED,
+ ndev->name, ndev);
if (ret)
goto err_tx_irq;
/* Enable interrupts for Axi DMA Rx */
- ret = request_irq(lp->rx_irq, axienet_rx_irq, 0, ndev->name, ndev);
+ ret = request_irq(lp->rx_irq, axienet_rx_irq, IRQF_SHARED,
+ ndev->name, ndev);
if (ret)
goto err_rx_irq;
+ /* Enable interrupts for Axi Ethernet core (if defined) */
+ if (lp->eth_irq > 0) {
+ ret = request_irq(lp->eth_irq, axienet_eth_irq, IRQF_SHARED,
+ ndev->name, ndev);
+ if (ret)
+ goto err_eth_irq;
+ }
return 0;
+err_eth_irq:
+ free_irq(lp->rx_irq, ndev);
err_rx_irq:
free_irq(lp->tx_irq, ndev);
err_tx_irq:
- if (phydev)
- phy_disconnect(phydev);
+ phylink_stop(lp->phylink);
+ phylink_disconnect_phy(lp->phylink);
tasklet_kill(&lp->dma_err_tasklet);
dev_err(lp->dev, "request_irq() failed\n");
return ret;
@@ -976,34 +977,61 @@ err_tx_irq:
*
* Return: 0, on success.
*
- * This is the driver stop routine. It calls phy_disconnect to stop the PHY
+ * This is the driver stop routine. It calls phylink_disconnect to stop the PHY
* device. It also removes the interrupt handlers and disables the interrupts.
* The Axi DMA Tx/Rx BDs are released.
*/
static int axienet_stop(struct net_device *ndev)
{
- u32 cr;
+ u32 cr, sr;
+ int count;
struct axienet_local *lp = netdev_priv(ndev);
dev_dbg(&ndev->dev, "axienet_close()\n");
- cr = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET);
- axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET,
- cr & (~XAXIDMA_CR_RUNSTOP_MASK));
- cr = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET);
- axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET,
- cr & (~XAXIDMA_CR_RUNSTOP_MASK));
+ phylink_stop(lp->phylink);
+ phylink_disconnect_phy(lp->phylink);
+
axienet_setoptions(ndev, lp->options &
~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
+ cr = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET);
+ cr &= ~(XAXIDMA_CR_RUNSTOP_MASK | XAXIDMA_IRQ_ALL_MASK);
+ axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET, cr);
+
+ cr = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET);
+ cr &= ~(XAXIDMA_CR_RUNSTOP_MASK | XAXIDMA_IRQ_ALL_MASK);
+ axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET, cr);
+
+ axienet_iow(lp, XAE_IE_OFFSET, 0);
+
+ /* Give DMAs a chance to halt gracefully */
+ sr = axienet_dma_in32(lp, XAXIDMA_RX_SR_OFFSET);
+ for (count = 0; !(sr & XAXIDMA_SR_HALT_MASK) && count < 5; ++count) {
+ msleep(20);
+ sr = axienet_dma_in32(lp, XAXIDMA_RX_SR_OFFSET);
+ }
+
+ sr = axienet_dma_in32(lp, XAXIDMA_TX_SR_OFFSET);
+ for (count = 0; !(sr & XAXIDMA_SR_HALT_MASK) && count < 5; ++count) {
+ msleep(20);
+ sr = axienet_dma_in32(lp, XAXIDMA_TX_SR_OFFSET);
+ }
+
+ /* Do a reset to ensure DMA is really stopped */
+ mutex_lock(&lp->mii_bus->mdio_lock);
+ axienet_mdio_disable(lp);
+ __axienet_device_reset(lp);
+ axienet_mdio_enable(lp);
+ mutex_unlock(&lp->mii_bus->mdio_lock);
+
tasklet_kill(&lp->dma_err_tasklet);
+ if (lp->eth_irq > 0)
+ free_irq(lp->eth_irq, ndev);
free_irq(lp->tx_irq, ndev);
free_irq(lp->rx_irq, ndev);
- if (ndev->phydev)
- phy_disconnect(ndev->phydev);
-
axienet_dma_bd_release(ndev);
return 0;
}
@@ -1151,6 +1179,48 @@ static void axienet_ethtools_get_regs(struct net_device *ndev,
data[29] = axienet_ior(lp, XAE_FMI_OFFSET);
data[30] = axienet_ior(lp, XAE_AF0_OFFSET);
data[31] = axienet_ior(lp, XAE_AF1_OFFSET);
+ data[32] = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET);
+ data[33] = axienet_dma_in32(lp, XAXIDMA_TX_SR_OFFSET);
+ data[34] = axienet_dma_in32(lp, XAXIDMA_TX_CDESC_OFFSET);
+ data[35] = axienet_dma_in32(lp, XAXIDMA_TX_TDESC_OFFSET);
+ data[36] = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET);
+ data[37] = axienet_dma_in32(lp, XAXIDMA_RX_SR_OFFSET);
+ data[38] = axienet_dma_in32(lp, XAXIDMA_RX_CDESC_OFFSET);
+ data[39] = axienet_dma_in32(lp, XAXIDMA_RX_TDESC_OFFSET);
+}
+
+static void axienet_ethtools_get_ringparam(struct net_device *ndev,
+ struct ethtool_ringparam *ering)
+{
+ struct axienet_local *lp = netdev_priv(ndev);
+
+ ering->rx_max_pending = RX_BD_NUM_MAX;
+ ering->rx_mini_max_pending = 0;
+ ering->rx_jumbo_max_pending = 0;
+ ering->tx_max_pending = TX_BD_NUM_MAX;
+ ering->rx_pending = lp->rx_bd_num;
+ ering->rx_mini_pending = 0;
+ ering->rx_jumbo_pending = 0;
+ ering->tx_pending = lp->tx_bd_num;
+}
+
+static int axienet_ethtools_set_ringparam(struct net_device *ndev,
+ struct ethtool_ringparam *ering)
+{
+ struct axienet_local *lp = netdev_priv(ndev);
+
+ if (ering->rx_pending > RX_BD_NUM_MAX ||
+ ering->rx_mini_pending ||
+ ering->rx_jumbo_pending ||
+ ering->rx_pending > TX_BD_NUM_MAX)
+ return -EINVAL;
+
+ if (netif_running(ndev))
+ return -EBUSY;
+
+ lp->rx_bd_num = ering->rx_pending;
+ lp->tx_bd_num = ering->tx_pending;
+ return 0;
}
/**
@@ -1166,12 +1236,9 @@ static void
axienet_ethtools_get_pauseparam(struct net_device *ndev,
struct ethtool_pauseparam *epauseparm)
{
- u32 regval;
struct axienet_local *lp = netdev_priv(ndev);
- epauseparm->autoneg = 0;
- regval = axienet_ior(lp, XAE_FCC_OFFSET);
- epauseparm->tx_pause = regval & XAE_FCC_FCTX_MASK;
- epauseparm->rx_pause = regval & XAE_FCC_FCRX_MASK;
+
+ phylink_ethtool_get_pauseparam(lp->phylink, epauseparm);
}
/**
@@ -1190,27 +1257,9 @@ static int
axienet_ethtools_set_pauseparam(struct net_device *ndev,
struct ethtool_pauseparam *epauseparm)
{
- u32 regval = 0;
struct axienet_local *lp = netdev_priv(ndev);
- if (netif_running(ndev)) {
- netdev_err(ndev,
- "Please stop netif before applying configuration\n");
- return -EFAULT;
- }
-
- regval = axienet_ior(lp, XAE_FCC_OFFSET);
- if (epauseparm->tx_pause)
- regval |= XAE_FCC_FCTX_MASK;
- else
- regval &= ~XAE_FCC_FCTX_MASK;
- if (epauseparm->rx_pause)
- regval |= XAE_FCC_FCRX_MASK;
- else
- regval &= ~XAE_FCC_FCRX_MASK;
- axienet_iow(lp, XAE_FCC_OFFSET, regval);
-
- return 0;
+ return phylink_ethtool_set_pauseparam(lp->phylink, epauseparm);
}
/**
@@ -1289,17 +1338,170 @@ static int axienet_ethtools_set_coalesce(struct net_device *ndev,
return 0;
}
+static int
+axienet_ethtools_get_link_ksettings(struct net_device *ndev,
+ struct ethtool_link_ksettings *cmd)
+{
+ struct axienet_local *lp = netdev_priv(ndev);
+
+ return phylink_ethtool_ksettings_get(lp->phylink, cmd);
+}
+
+static int
+axienet_ethtools_set_link_ksettings(struct net_device *ndev,
+ const struct ethtool_link_ksettings *cmd)
+{
+ struct axienet_local *lp = netdev_priv(ndev);
+
+ return phylink_ethtool_ksettings_set(lp->phylink, cmd);
+}
+
static const struct ethtool_ops axienet_ethtool_ops = {
.get_drvinfo = axienet_ethtools_get_drvinfo,
.get_regs_len = axienet_ethtools_get_regs_len,
.get_regs = axienet_ethtools_get_regs,
.get_link = ethtool_op_get_link,
+ .get_ringparam = axienet_ethtools_get_ringparam,
+ .set_ringparam = axienet_ethtools_set_ringparam,
.get_pauseparam = axienet_ethtools_get_pauseparam,
.set_pauseparam = axienet_ethtools_set_pauseparam,
.get_coalesce = axienet_ethtools_get_coalesce,
.set_coalesce = axienet_ethtools_set_coalesce,
- .get_link_ksettings = phy_ethtool_get_link_ksettings,
- .set_link_ksettings = phy_ethtool_set_link_ksettings,
+ .get_link_ksettings = axienet_ethtools_get_link_ksettings,
+ .set_link_ksettings = axienet_ethtools_set_link_ksettings,
+};
+
+static void axienet_validate(struct phylink_config *config,
+ unsigned long *supported,
+ struct phylink_link_state *state)
+{
+ struct net_device *ndev = to_net_dev(config->dev);
+ struct axienet_local *lp = netdev_priv(ndev);
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
+
+ /* Only support the mode we are configured for */
+ if (state->interface != PHY_INTERFACE_MODE_NA &&
+ state->interface != lp->phy_mode) {
+ netdev_warn(ndev, "Cannot use PHY mode %s, supported: %s\n",
+ phy_modes(state->interface),
+ phy_modes(lp->phy_mode));
+ bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
+ return;
+ }
+
+ phylink_set(mask, Autoneg);
+ phylink_set_port_modes(mask);
+
+ phylink_set(mask, Asym_Pause);
+ phylink_set(mask, Pause);
+ phylink_set(mask, 1000baseX_Full);
+ phylink_set(mask, 10baseT_Full);
+ phylink_set(mask, 100baseT_Full);
+ phylink_set(mask, 1000baseT_Full);
+
+ bitmap_and(supported, supported, mask,
+ __ETHTOOL_LINK_MODE_MASK_NBITS);
+ bitmap_and(state->advertising, state->advertising, mask,
+ __ETHTOOL_LINK_MODE_MASK_NBITS);
+}
+
+static int axienet_mac_link_state(struct phylink_config *config,
+ struct phylink_link_state *state)
+{
+ struct net_device *ndev = to_net_dev(config->dev);
+ struct axienet_local *lp = netdev_priv(ndev);
+ u32 emmc_reg, fcc_reg;
+
+ state->interface = lp->phy_mode;
+
+ emmc_reg = axienet_ior(lp, XAE_EMMC_OFFSET);
+ if (emmc_reg & XAE_EMMC_LINKSPD_1000)
+ state->speed = SPEED_1000;
+ else if (emmc_reg & XAE_EMMC_LINKSPD_100)
+ state->speed = SPEED_100;
+ else
+ state->speed = SPEED_10;
+
+ state->pause = 0;
+ fcc_reg = axienet_ior(lp, XAE_FCC_OFFSET);
+ if (fcc_reg & XAE_FCC_FCTX_MASK)
+ state->pause |= MLO_PAUSE_TX;
+ if (fcc_reg & XAE_FCC_FCRX_MASK)
+ state->pause |= MLO_PAUSE_RX;
+
+ state->an_complete = 0;
+ state->duplex = 1;
+
+ return 1;
+}
+
+static void axienet_mac_an_restart(struct phylink_config *config)
+{
+ /* Unsupported, do nothing */
+}
+
+static void axienet_mac_config(struct phylink_config *config, unsigned int mode,
+ const struct phylink_link_state *state)
+{
+ struct net_device *ndev = to_net_dev(config->dev);
+ struct axienet_local *lp = netdev_priv(ndev);
+ u32 emmc_reg, fcc_reg;
+
+ emmc_reg = axienet_ior(lp, XAE_EMMC_OFFSET);
+ emmc_reg &= ~XAE_EMMC_LINKSPEED_MASK;
+
+ switch (state->speed) {
+ case SPEED_1000:
+ emmc_reg |= XAE_EMMC_LINKSPD_1000;
+ break;
+ case SPEED_100:
+ emmc_reg |= XAE_EMMC_LINKSPD_100;
+ break;
+ case SPEED_10:
+ emmc_reg |= XAE_EMMC_LINKSPD_10;
+ break;
+ default:
+ dev_err(&ndev->dev,
+ "Speed other than 10, 100 or 1Gbps is not supported\n");
+ break;
+ }
+
+ axienet_iow(lp, XAE_EMMC_OFFSET, emmc_reg);
+
+ fcc_reg = axienet_ior(lp, XAE_FCC_OFFSET);
+ if (state->pause & MLO_PAUSE_TX)
+ fcc_reg |= XAE_FCC_FCTX_MASK;
+ else
+ fcc_reg &= ~XAE_FCC_FCTX_MASK;
+ if (state->pause & MLO_PAUSE_RX)
+ fcc_reg |= XAE_FCC_FCRX_MASK;
+ else
+ fcc_reg &= ~XAE_FCC_FCRX_MASK;
+ axienet_iow(lp, XAE_FCC_OFFSET, fcc_reg);
+}
+
+static void axienet_mac_link_down(struct phylink_config *config,
+ unsigned int mode,
+ phy_interface_t interface)
+{
+ /* nothing meaningful to do */
+}
+
+static void axienet_mac_link_up(struct phylink_config *config,
+ unsigned int mode,
+ phy_interface_t interface,
+ struct phy_device *phy)
+{
+ /* nothing meaningful to do */
+}
+
+static const struct phylink_mac_ops axienet_phylink_ops = {
+ .validate = axienet_validate,
+ .mac_link_state = axienet_mac_link_state,
+ .mac_an_restart = axienet_mac_an_restart,
+ .mac_config = axienet_mac_config,
+ .mac_link_down = axienet_mac_link_down,
+ .mac_link_up = axienet_mac_link_up,
};
/**
@@ -1313,38 +1515,33 @@ static void axienet_dma_err_handler(unsigned long data)
{
u32 axienet_status;
u32 cr, i;
- int mdio_mcreg;
struct axienet_local *lp = (struct axienet_local *) data;
struct net_device *ndev = lp->ndev;
struct axidma_bd *cur_p;
axienet_setoptions(ndev, lp->options &
~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
- mdio_mcreg = axienet_ior(lp, XAE_MDIO_MC_OFFSET);
- axienet_mdio_wait_until_ready(lp);
/* Disable the MDIO interface till Axi Ethernet Reset is completed.
* When we do an Axi Ethernet reset, it resets the complete core
- * including the MDIO. So if MDIO is not disabled when the reset
- * process is started, MDIO will be broken afterwards.
+ * including the MDIO. MDIO must be disabled before resetting
+ * and re-enabled afterwards.
+ * Hold MDIO bus lock to avoid MDIO accesses during the reset.
*/
- axienet_iow(lp, XAE_MDIO_MC_OFFSET, (mdio_mcreg &
- ~XAE_MDIO_MC_MDIOEN_MASK));
+ mutex_lock(&lp->mii_bus->mdio_lock);
+ axienet_mdio_disable(lp);
+ __axienet_device_reset(lp);
+ axienet_mdio_enable(lp);
+ mutex_unlock(&lp->mii_bus->mdio_lock);
- __axienet_device_reset(lp, XAXIDMA_TX_CR_OFFSET);
- __axienet_device_reset(lp, XAXIDMA_RX_CR_OFFSET);
-
- axienet_iow(lp, XAE_MDIO_MC_OFFSET, mdio_mcreg);
- axienet_mdio_wait_until_ready(lp);
-
- for (i = 0; i < TX_BD_NUM; i++) {
+ for (i = 0; i < lp->tx_bd_num; i++) {
cur_p = &lp->tx_bd_v[i];
if (cur_p->phys)
dma_unmap_single(ndev->dev.parent, cur_p->phys,
(cur_p->cntrl &
XAXIDMA_BD_CTRL_LENGTH_MASK),
DMA_TO_DEVICE);
- if (cur_p->app4)
- dev_kfree_skb_irq((struct sk_buff *) cur_p->app4);
+ if (cur_p->skb)
+ dev_kfree_skb_irq(cur_p->skb);
cur_p->phys = 0;
cur_p->cntrl = 0;
cur_p->status = 0;
@@ -1353,10 +1550,10 @@ static void axienet_dma_err_handler(unsigned long data)
cur_p->app2 = 0;
cur_p->app3 = 0;
cur_p->app4 = 0;
- cur_p->sw_id_offset = 0;
+ cur_p->skb = NULL;
}
- for (i = 0; i < RX_BD_NUM; i++) {
+ for (i = 0; i < lp->rx_bd_num; i++) {
cur_p = &lp->rx_bd_v[i];
cur_p->status = 0;
cur_p->app0 = 0;
@@ -1404,7 +1601,7 @@ static void axienet_dma_err_handler(unsigned long data)
axienet_dma_out32(lp, XAXIDMA_RX_CR_OFFSET,
cr | XAXIDMA_CR_RUNSTOP_MASK);
axienet_dma_out32(lp, XAXIDMA_RX_TDESC_OFFSET, lp->rx_bd_p +
- (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1)));
+ (sizeof(*lp->rx_bd_v) * (lp->rx_bd_num - 1)));
/* Write to the RS (Run-stop) bit in the Tx channel control register.
* Tx channel is now ready to run. But only after we write to the
@@ -1422,6 +1619,8 @@ static void axienet_dma_err_handler(unsigned long data)
axienet_status = axienet_ior(lp, XAE_IP_OFFSET);
if (axienet_status & XAE_INT_RXRJECT_MASK)
axienet_iow(lp, XAE_IS_OFFSET, XAE_INT_RXRJECT_MASK);
+ axienet_iow(lp, XAE_IE_OFFSET, lp->eth_irq > 0 ?
+ XAE_INT_RECV_ERROR_MASK : 0);
axienet_iow(lp, XAE_FCC_OFFSET, XAE_FCC_FCRX_MASK);
/* Sync default options with HW but leave receiver and
@@ -1453,7 +1652,7 @@ static int axienet_probe(struct platform_device *pdev)
struct axienet_local *lp;
struct net_device *ndev;
const void *mac_addr;
- struct resource *ethres, dmares;
+ struct resource *ethres;
u32 value;
ndev = alloc_etherdev(sizeof(*lp));
@@ -1476,6 +1675,8 @@ static int axienet_probe(struct platform_device *pdev)
lp->ndev = ndev;
lp->dev = &pdev->dev;
lp->options = XAE_OPTION_DEFAULTS;
+ lp->rx_bd_num = RX_BD_NUM_DEFAULT;
+ lp->tx_bd_num = TX_BD_NUM_DEFAULT;
/* Map device registers */
ethres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
lp->regs = devm_ioremap_resource(&pdev->dev, ethres);
@@ -1484,6 +1685,7 @@ static int axienet_probe(struct platform_device *pdev)
ret = PTR_ERR(lp->regs);
goto free_netdev;
}
+ lp->regs_start = ethres->start;
/* Setup checksum offload, but default to off if not specified */
lp->features = 0;
@@ -1568,38 +1770,56 @@ static int axienet_probe(struct platform_device *pdev)
/* Find the DMA node, map the DMA registers, and decode the DMA IRQs */
np = of_parse_phandle(pdev->dev.of_node, "axistream-connected", 0);
- if (!np) {
- dev_err(&pdev->dev, "could not find DMA node\n");
- ret = -ENODEV;
- goto free_netdev;
- }
- ret = of_address_to_resource(np, 0, &dmares);
- if (ret) {
- dev_err(&pdev->dev, "unable to get DMA resource\n");
+ if (np) {
+ struct resource dmares;
+
+ ret = of_address_to_resource(np, 0, &dmares);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "unable to get DMA resource\n");
+ of_node_put(np);
+ goto free_netdev;
+ }
+ lp->dma_regs = devm_ioremap_resource(&pdev->dev,
+ &dmares);
+ lp->rx_irq = irq_of_parse_and_map(np, 1);
+ lp->tx_irq = irq_of_parse_and_map(np, 0);
of_node_put(np);
- goto free_netdev;
+ lp->eth_irq = platform_get_irq(pdev, 0);
+ } else {
+ /* Check for these resources directly on the Ethernet node. */
+ struct resource *res = platform_get_resource(pdev,
+ IORESOURCE_MEM, 1);
+ if (!res) {
+ dev_err(&pdev->dev, "unable to get DMA memory resource\n");
+ goto free_netdev;
+ }
+ lp->dma_regs = devm_ioremap_resource(&pdev->dev, res);
+ lp->rx_irq = platform_get_irq(pdev, 1);
+ lp->tx_irq = platform_get_irq(pdev, 0);
+ lp->eth_irq = platform_get_irq(pdev, 2);
}
- lp->dma_regs = devm_ioremap_resource(&pdev->dev, &dmares);
if (IS_ERR(lp->dma_regs)) {
dev_err(&pdev->dev, "could not map DMA regs\n");
ret = PTR_ERR(lp->dma_regs);
- of_node_put(np);
goto free_netdev;
}
- lp->rx_irq = irq_of_parse_and_map(np, 1);
- lp->tx_irq = irq_of_parse_and_map(np, 0);
- of_node_put(np);
if ((lp->rx_irq <= 0) || (lp->tx_irq <= 0)) {
dev_err(&pdev->dev, "could not determine irqs\n");
ret = -ENOMEM;
goto free_netdev;
}
+ /* Check for Ethernet core IRQ (optional) */
+ if (lp->eth_irq <= 0)
+ dev_info(&pdev->dev, "Ethernet core IRQ not defined\n");
+
/* Retrieve the MAC address */
mac_addr = of_get_mac_address(pdev->dev.of_node);
if (IS_ERR(mac_addr)) {
- dev_err(&pdev->dev, "could not find MAC address\n");
- goto free_netdev;
+ dev_warn(&pdev->dev, "could not find MAC address property: %ld\n",
+ PTR_ERR(mac_addr));
+ mac_addr = NULL;
}
axienet_set_mac_address(ndev, mac_addr);
@@ -1608,9 +1828,36 @@ static int axienet_probe(struct platform_device *pdev)
lp->phy_node = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0);
if (lp->phy_node) {
- ret = axienet_mdio_setup(lp, pdev->dev.of_node);
+ lp->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(lp->clk)) {
+ dev_warn(&pdev->dev, "Failed to get clock: %ld\n",
+ PTR_ERR(lp->clk));
+ lp->clk = NULL;
+ } else {
+ ret = clk_prepare_enable(lp->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to enable clock: %d\n",
+ ret);
+ goto free_netdev;
+ }
+ }
+
+ ret = axienet_mdio_setup(lp);
if (ret)
- dev_warn(&pdev->dev, "error registering MDIO bus\n");
+ dev_warn(&pdev->dev,
+ "error registering MDIO bus: %d\n", ret);
+ }
+
+ lp->phylink_config.dev = &ndev->dev;
+ lp->phylink_config.type = PHYLINK_NETDEV;
+
+ lp->phylink = phylink_create(&lp->phylink_config, pdev->dev.fwnode,
+ lp->phy_mode,
+ &axienet_phylink_ops);
+ if (IS_ERR(lp->phylink)) {
+ ret = PTR_ERR(lp->phylink);
+ dev_err(&pdev->dev, "phylink_create error (%i)\n", ret);
+ goto free_netdev;
}
ret = register_netdev(lp->ndev);
@@ -1632,9 +1879,16 @@ static int axienet_remove(struct platform_device *pdev)
struct net_device *ndev = platform_get_drvdata(pdev);
struct axienet_local *lp = netdev_priv(ndev);
- axienet_mdio_teardown(lp);
unregister_netdev(ndev);
+ if (lp->phylink)
+ phylink_destroy(lp->phylink);
+
+ axienet_mdio_teardown(lp);
+
+ if (lp->clk)
+ clk_disable_unprepare(lp->clk);
+
of_node_put(lp->phy_node);
lp->phy_node = NULL;
@@ -1643,9 +1897,23 @@ static int axienet_remove(struct platform_device *pdev)
return 0;
}
+static void axienet_shutdown(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+
+ rtnl_lock();
+ netif_device_detach(ndev);
+
+ if (netif_running(ndev))
+ dev_close(ndev);
+
+ rtnl_unlock();
+}
+
static struct platform_driver axienet_driver = {
.probe = axienet_probe,
.remove = axienet_remove,
+ .shutdown = axienet_shutdown,
.driver = {
.name = "xilinx_axienet",
.of_match_table = axienet_of_match,
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c b/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c
index 704babdbc8a2..435ed308d990 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c
@@ -5,9 +5,11 @@
* Copyright (c) 2009 Secret Lab Technologies, Ltd.
* Copyright (c) 2010 - 2011 Michal Simek <monstr@monstr.eu>
* Copyright (c) 2010 - 2011 PetaLogix
+ * Copyright (c) 2019 SED Systems, a division of Calian Ltd.
* Copyright (c) 2010 - 2012 Xilinx, Inc. All rights reserved.
*/
+#include <linux/clk.h>
#include <linux/of_address.h>
#include <linux/of_mdio.h>
#include <linux/jiffies.h>
@@ -16,10 +18,10 @@
#include "xilinx_axienet.h"
#define MAX_MDIO_FREQ 2500000 /* 2.5 MHz */
-#define DEFAULT_CLOCK_DIVISOR XAE_MDIO_DIV_DFT
+#define DEFAULT_HOST_CLOCK 150000000 /* 150 MHz */
/* Wait till MDIO interface is ready to accept a new transaction.*/
-int axienet_mdio_wait_until_ready(struct axienet_local *lp)
+static int axienet_mdio_wait_until_ready(struct axienet_local *lp)
{
u32 val;
@@ -112,23 +114,42 @@ static int axienet_mdio_write(struct mii_bus *bus, int phy_id, int reg,
}
/**
- * axienet_mdio_setup - MDIO setup function
+ * axienet_mdio_enable - MDIO hardware setup function
* @lp: Pointer to axienet local data structure.
- * @np: Pointer to device node
*
- * Return: 0 on success, -ETIMEDOUT on a timeout, -ENOMEM when
- * mdiobus_alloc (to allocate memory for mii bus structure) fails.
+ * Return: 0 on success, -ETIMEDOUT on a timeout.
*
* Sets up the MDIO interface by initializing the MDIO clock and enabling the
- * MDIO interface in hardware. Register the MDIO interface.
+ * MDIO interface in hardware.
**/
-int axienet_mdio_setup(struct axienet_local *lp, struct device_node *np)
+int axienet_mdio_enable(struct axienet_local *lp)
{
- int ret;
u32 clk_div, host_clock;
- struct mii_bus *bus;
- struct resource res;
- struct device_node *np1;
+
+ if (lp->clk) {
+ host_clock = clk_get_rate(lp->clk);
+ } else {
+ struct device_node *np1;
+
+ /* Legacy fallback: detect CPU clock frequency and use as AXI
+ * bus clock frequency. This only works on certain platforms.
+ */
+ np1 = of_find_node_by_name(NULL, "cpu");
+ if (!np1) {
+ netdev_warn(lp->ndev, "Could not find CPU device node.\n");
+ host_clock = DEFAULT_HOST_CLOCK;
+ } else {
+ int ret = of_property_read_u32(np1, "clock-frequency",
+ &host_clock);
+ if (ret) {
+ netdev_warn(lp->ndev, "CPU clock-frequency property not found.\n");
+ host_clock = DEFAULT_HOST_CLOCK;
+ }
+ of_node_put(np1);
+ }
+ netdev_info(lp->ndev, "Setting assumed host clock to %u\n",
+ host_clock);
+ }
/* clk_div can be calculated by deriving it from the equation:
* fMDIO = fHOST / ((1 + clk_div) * 2)
@@ -155,25 +176,6 @@ int axienet_mdio_setup(struct axienet_local *lp, struct device_node *np)
* "clock-frequency" from the CPU
*/
- np1 = of_find_node_by_name(NULL, "cpu");
- if (!np1) {
- netdev_warn(lp->ndev, "Could not find CPU device node.\n");
- netdev_warn(lp->ndev,
- "Setting MDIO clock divisor to default %d\n",
- DEFAULT_CLOCK_DIVISOR);
- clk_div = DEFAULT_CLOCK_DIVISOR;
- goto issue;
- }
- if (of_property_read_u32(np1, "clock-frequency", &host_clock)) {
- netdev_warn(lp->ndev, "clock-frequency property not found.\n");
- netdev_warn(lp->ndev,
- "Setting MDIO clock divisor to default %d\n",
- DEFAULT_CLOCK_DIVISOR);
- clk_div = DEFAULT_CLOCK_DIVISOR;
- of_node_put(np1);
- goto issue;
- }
-
clk_div = (host_clock / (MAX_MDIO_FREQ * 2)) - 1;
/* If there is any remainder from the division of
* fHOST / (MAX_MDIO_FREQ * 2), then we need to add
@@ -186,12 +188,39 @@ int axienet_mdio_setup(struct axienet_local *lp, struct device_node *np)
"Setting MDIO clock divisor to %u/%u Hz host clock.\n",
clk_div, host_clock);
- of_node_put(np1);
-issue:
- axienet_iow(lp, XAE_MDIO_MC_OFFSET,
- (((u32) clk_div) | XAE_MDIO_MC_MDIOEN_MASK));
+ axienet_iow(lp, XAE_MDIO_MC_OFFSET, clk_div | XAE_MDIO_MC_MDIOEN_MASK);
- ret = axienet_mdio_wait_until_ready(lp);
+ return axienet_mdio_wait_until_ready(lp);
+}
+
+/**
+ * axienet_mdio_disable - MDIO hardware disable function
+ * @lp: Pointer to axienet local data structure.
+ *
+ * Disable the MDIO interface in hardware.
+ **/
+void axienet_mdio_disable(struct axienet_local *lp)
+{
+ axienet_iow(lp, XAE_MDIO_MC_OFFSET, 0);
+}
+
+/**
+ * axienet_mdio_setup - MDIO setup function
+ * @lp: Pointer to axienet local data structure.
+ *
+ * Return: 0 on success, -ETIMEDOUT on a timeout, -ENOMEM when
+ * mdiobus_alloc (to allocate memory for mii bus structure) fails.
+ *
+ * Sets up the MDIO interface by initializing the MDIO clock and enabling the
+ * MDIO interface in hardware. Register the MDIO interface.
+ **/
+int axienet_mdio_setup(struct axienet_local *lp)
+{
+ struct device_node *mdio_node;
+ struct mii_bus *bus;
+ int ret;
+
+ ret = axienet_mdio_enable(lp);
if (ret < 0)
return ret;
@@ -199,10 +228,8 @@ issue:
if (!bus)
return -ENOMEM;
- np1 = of_get_parent(lp->phy_node);
- of_address_to_resource(np1, 0, &res);
- snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx",
- (unsigned long long) res.start);
+ snprintf(bus->id, MII_BUS_ID_SIZE, "axienet-%.8llx",
+ (unsigned long long)lp->regs_start);
bus->priv = lp;
bus->name = "Xilinx Axi Ethernet MDIO";
@@ -211,7 +238,9 @@ issue:
bus->parent = lp->dev;
lp->mii_bus = bus;
- ret = of_mdiobus_register(bus, np1);
+ mdio_node = of_get_child_by_name(lp->dev->of_node, "mdio");
+ ret = of_mdiobus_register(bus, mdio_node);
+ of_node_put(mdio_node);
if (ret) {
mdiobus_free(bus);
lp->mii_bus = NULL;
diff --git a/drivers/net/fddi/defza.c b/drivers/net/fddi/defza.c
index c5cae8e74dc4..060712c666bf 100644
--- a/drivers/net/fddi/defza.c
+++ b/drivers/net/fddi/defza.c
@@ -33,6 +33,7 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/list.h>
diff --git a/drivers/net/fddi/skfp/drvfbi.c b/drivers/net/fddi/skfp/drvfbi.c
index bdd5700e71fa..9c8aa3a95463 100644
--- a/drivers/net/fddi/skfp/drvfbi.c
+++ b/drivers/net/fddi/skfp/drvfbi.c
@@ -20,6 +20,7 @@
#include "h/supern_2.h"
#include "h/skfbiinc.h"
#include <linux/bitrev.h>
+#include <linux/pci_regs.h>
#ifndef lint
static const char ID_sccs[] = "@(#)drvfbi.c 1.63 99/02/11 (C) SK " ;
@@ -127,7 +128,7 @@ static void card_start(struct s_smc *smc)
* at very first before any other initialization functions is
* executed.
*/
- rev_id = inp(PCI_C(PCI_REV_ID)) ;
+ rev_id = inp(PCI_C(PCI_REVISION_ID)) ;
if ((rev_id & 0xf0) == SK_ML_ID_1 || (rev_id & 0xf0) == SK_ML_ID_2) {
smc->hw.hw_is_64bit = TRUE ;
} else {
diff --git a/drivers/net/fddi/skfp/h/skfbi.h b/drivers/net/fddi/skfp/h/skfbi.h
index 89557457b352..480795681719 100644
--- a/drivers/net/fddi/skfp/h/skfbi.h
+++ b/drivers/net/fddi/skfp/h/skfbi.h
@@ -24,49 +24,6 @@
* (ML) = only defined for Monalisa
*/
-/*
- * Configuration Space header
- */
-#define PCI_VENDOR_ID 0x00 /* 16 bit Vendor ID */
-#define PCI_DEVICE_ID 0x02 /* 16 bit Device ID */
-#define PCI_COMMAND 0x04 /* 16 bit Command */
-#define PCI_STATUS 0x06 /* 16 bit Status */
-#define PCI_REV_ID 0x08 /* 8 bit Revision ID */
-#define PCI_CLASS_CODE 0x09 /* 24 bit Class Code */
-#define PCI_CACHE_LSZ 0x0c /* 8 bit Cache Line Size */
-#define PCI_LAT_TIM 0x0d /* 8 bit Latency Timer */
-#define PCI_HEADER_T 0x0e /* 8 bit Header Type */
-#define PCI_BIST 0x0f /* 8 bit Built-in selftest */
-#define PCI_BASE_1ST 0x10 /* 32 bit 1st Base address */
-#define PCI_BASE_2ND 0x14 /* 32 bit 2nd Base address */
-/* Byte 18..2b: Reserved */
-#define PCI_SUB_VID 0x2c /* 16 bit Subsystem Vendor ID */
-#define PCI_SUB_ID 0x2e /* 16 bit Subsystem ID */
-#define PCI_BASE_ROM 0x30 /* 32 bit Expansion ROM Base Address */
-/* Byte 34..33: Reserved */
-#define PCI_CAP_PTR 0x34 /* 8 bit (ML) Capabilities Ptr */
-/* Byte 35..3b: Reserved */
-#define PCI_IRQ_LINE 0x3c /* 8 bit Interrupt Line */
-#define PCI_IRQ_PIN 0x3d /* 8 bit Interrupt Pin */
-#define PCI_MIN_GNT 0x3e /* 8 bit Min_Gnt */
-#define PCI_MAX_LAT 0x3f /* 8 bit Max_Lat */
-/* Device Dependent Region */
-#define PCI_OUR_REG 0x40 /* 32 bit (DV) Our Register */
-#define PCI_OUR_REG_1 0x40 /* 32 bit (ML) Our Register 1 */
-#define PCI_OUR_REG_2 0x44 /* 32 bit (ML) Our Register 2 */
-/* Power Management Region */
-#define PCI_PM_CAP_ID 0x48 /* 8 bit (ML) Power Management Cap. ID */
-#define PCI_PM_NITEM 0x49 /* 8 bit (ML) Next Item Ptr */
-#define PCI_PM_CAP_REG 0x4a /* 16 bit (ML) Power Management Capabilities */
-#define PCI_PM_CTL_STS 0x4c /* 16 bit (ML) Power Manag. Control/Status */
-/* Byte 0x4e: Reserved */
-#define PCI_PM_DAT_REG 0x4f /* 8 bit (ML) Power Manag. Data Register */
-/* VPD Region */
-#define PCI_VPD_CAP_ID 0x50 /* 8 bit (ML) VPD Cap. ID */
-#define PCI_VPD_NITEM 0x51 /* 8 bit (ML) Next Item Ptr */
-#define PCI_VPD_ADR_REG 0x52 /* 16 bit (ML) VPD Address Register */
-#define PCI_VPD_DAT_REG 0x54 /* 32 bit (ML) VPD Data Register */
-/* Byte 58..ff: Reserved */
/*
* I2C Address (PCI Config)
@@ -76,176 +33,10 @@
*/
#define I2C_ADDR_VPD 0xA0 /* I2C address for the VPD EEPROM */
-/*
- * Define Bits and Values of the registers
- */
-/* PCI_VENDOR_ID 16 bit Vendor ID */
-/* PCI_DEVICE_ID 16 bit Device ID */
-/* Values for Vendor ID and Device ID shall be patched into the code */
-/* PCI_COMMAND 16 bit Command */
-#define PCI_FBTEN 0x0200 /* Bit 9: Fast Back-To-Back enable */
-#define PCI_SERREN 0x0100 /* Bit 8: SERR enable */
-#define PCI_ADSTEP 0x0080 /* Bit 7: Address Stepping */
-#define PCI_PERREN 0x0040 /* Bit 6: Parity Report Response enable */
-#define PCI_VGA_SNOOP 0x0020 /* Bit 5: VGA palette snoop */
-#define PCI_MWIEN 0x0010 /* Bit 4: Memory write an inv cycl ena */
-#define PCI_SCYCEN 0x0008 /* Bit 3: Special Cycle enable */
-#define PCI_BMEN 0x0004 /* Bit 2: Bus Master enable */
-#define PCI_MEMEN 0x0002 /* Bit 1: Memory Space Access enable */
-#define PCI_IOEN 0x0001 /* Bit 0: IO Space Access enable */
-
-/* PCI_STATUS 16 bit Status */
-#define PCI_PERR 0x8000 /* Bit 15: Parity Error */
-#define PCI_SERR 0x4000 /* Bit 14: Signaled SERR */
-#define PCI_RMABORT 0x2000 /* Bit 13: Received Master Abort */
-#define PCI_RTABORT 0x1000 /* Bit 12: Received Target Abort */
-#define PCI_STABORT 0x0800 /* Bit 11: Sent Target Abort */
-#define PCI_DEVSEL 0x0600 /* Bit 10..9: DEVSEL Timing */
-#define PCI_DEV_FAST (0<<9) /* fast */
-#define PCI_DEV_MEDIUM (1<<9) /* medium */
-#define PCI_DEV_SLOW (2<<9) /* slow */
-#define PCI_DATAPERR 0x0100 /* Bit 8: DATA Parity error detected */
-#define PCI_FB2BCAP 0x0080 /* Bit 7: Fast Back-to-Back Capability */
-#define PCI_UDF 0x0040 /* Bit 6: User Defined Features */
-#define PCI_66MHZCAP 0x0020 /* Bit 5: 66 MHz PCI bus clock capable */
-#define PCI_NEWCAP 0x0010 /* Bit 4: New cap. list implemented */
-
-#define PCI_ERRBITS (PCI_PERR|PCI_SERR|PCI_RMABORT|PCI_STABORT|PCI_DATAPERR)
-
-/* PCI_REV_ID 8 bit Revision ID */
-/* PCI_CLASS_CODE 24 bit Class Code */
-/* Byte 2: Base Class (02) */
-/* Byte 1: SubClass (02) */
-/* Byte 0: Programming Interface (00) */
-
-/* PCI_CACHE_LSZ 8 bit Cache Line Size */
-/* Possible values: 0,2,4,8,16 */
-
-/* PCI_LAT_TIM 8 bit Latency Timer */
-
-/* PCI_HEADER_T 8 bit Header Type */
-#define PCI_HD_MF_DEV 0x80 /* Bit 7: 0= single, 1= multi-func dev */
-#define PCI_HD_TYPE 0x7f /* Bit 6..0: Header Layout 0= normal */
-
-/* PCI_BIST 8 bit Built-in selftest */
-#define PCI_BIST_CAP 0x80 /* Bit 7: BIST Capable */
-#define PCI_BIST_ST 0x40 /* Bit 6: Start BIST */
-#define PCI_BIST_RET 0x0f /* Bit 3..0: Completion Code */
-
-/* PCI_BASE_1ST 32 bit 1st Base address */
-#define PCI_MEMSIZE 0x800L /* use 2 kB Memory Base */
-#define PCI_MEMBASE_BITS 0xfffff800L /* Bit 31..11: Memory Base Address */
-#define PCI_MEMSIZE_BIIS 0x000007f0L /* Bit 10..4: Memory Size Req. */
-#define PCI_PREFEN 0x00000008L /* Bit 3: Prefetchable */
-#define PCI_MEM_TYP 0x00000006L /* Bit 2..1: Memory Type */
-#define PCI_MEM32BIT (0<<1) /* Base addr anywhere in 32 Bit range */
-#define PCI_MEM1M (1<<1) /* Base addr below 1 MegaByte */
-#define PCI_MEM64BIT (2<<1) /* Base addr anywhere in 64 Bit range */
-#define PCI_MEMSPACE 0x00000001L /* Bit 0: Memory Space Indic. */
-
-/* PCI_SUB_VID 16 bit Subsystem Vendor ID */
-/* PCI_SUB_ID 16 bit Subsystem ID */
-
-/* PCI_BASE_ROM 32 bit Expansion ROM Base Address */
-#define PCI_ROMBASE 0xfffe0000L /* Bit 31..17: ROM BASE address (1st) */
-#define PCI_ROMBASZ 0x0001c000L /* Bit 16..14: Treat as BASE or SIZE */
-#define PCI_ROMSIZE 0x00003800L /* Bit 13..11: ROM Size Requirements */
-#define PCI_ROMEN 0x00000001L /* Bit 0: Address Decode enable */
-
-/* PCI_CAP_PTR 8 bit New Capabilities Pointers */
-/* PCI_IRQ_LINE 8 bit Interrupt Line */
-/* PCI_IRQ_PIN 8 bit Interrupt Pin */
-/* PCI_MIN_GNT 8 bit Min_Gnt */
-/* PCI_MAX_LAT 8 bit Max_Lat */
-/* Device Dependent Region */
-/* PCI_OUR_REG (DV) 32 bit Our Register */
-/* PCI_OUR_REG_1 (ML) 32 bit Our Register 1 */
- /* Bit 31..29: reserved */
-#define PCI_PATCH_DIR (3L<<27) /*(DV) Bit 28..27: Ext Patchs direction */
-#define PCI_PATCH_DIR_0 (1L<<27) /*(DV) Type of the pins EXT_PATCHS<1..0> */
-#define PCI_PATCH_DIR_1 (1L<<28) /* 0 = input */
- /* 1 = output */
-#define PCI_EXT_PATCHS (3L<<25) /*(DV) Bit 26..25: Extended Patches */
-#define PCI_EXT_PATCH_0 (1L<<25) /*(DV) */
-#define PCI_EXT_PATCH_1 (1L<<26) /* CLK for MicroWire (ML) */
-#define PCI_VIO (1L<<25) /*(ML) */
-#define PCI_EN_BOOT (1L<<24) /* Bit 24: Enable BOOT via ROM */
- /* 1 = Don't boot with ROM */
- /* 0 = Boot with ROM */
-#define PCI_EN_IO (1L<<23) /* Bit 23: Mapping to IO space */
-#define PCI_EN_FPROM (1L<<22) /* Bit 22: FLASH mapped to mem? */
- /* 1 = Map Flash to Memory */
- /* 0 = Disable all addr. decoding */
-#define PCI_PAGESIZE (3L<<20) /* Bit 21..20: FLASH Page Size */
-#define PCI_PAGE_16 (0L<<20) /* 16 k pages */
-#define PCI_PAGE_32K (1L<<20) /* 32 k pages */
-#define PCI_PAGE_64K (2L<<20) /* 64 k pages */
-#define PCI_PAGE_128K (3L<<20) /* 128 k pages */
- /* Bit 19: reserved (ML) and (DV) */
-#define PCI_PAGEREG (7L<<16) /* Bit 18..16: Page Register */
- /* Bit 15: reserved */
-#define PCI_FORCE_BE (1L<<14) /* Bit 14: Assert all BEs on MR */
-#define PCI_DIS_MRL (1L<<13) /* Bit 13: Disable Mem R Line */
-#define PCI_DIS_MRM (1L<<12) /* Bit 12: Disable Mem R multip */
-#define PCI_DIS_MWI (1L<<11) /* Bit 11: Disable Mem W & inv */
-#define PCI_DISC_CLS (1L<<10) /* Bit 10: Disc: cacheLsz bound */
-#define PCI_BURST_DIS (1L<<9) /* Bit 9: Burst Disable */
-#define PCI_BYTE_SWAP (1L<<8) /*(DV) Bit 8: Byte Swap in DATA */
-#define PCI_SKEW_DAS (0xfL<<4) /* Bit 7..4: Skew Ctrl, DAS Ext */
-#define PCI_SKEW_BASE (0xfL<<0) /* Bit 3..0: Skew Ctrl, Base */
-
-/* PCI_OUR_REG_2 (ML) 32 bit Our Register 2 (Monalisa only) */
-#define PCI_VPD_WR_TH (0xffL<<24) /* Bit 24..31 VPD Write Threshold */
-#define PCI_DEV_SEL (0x7fL<<17) /* Bit 17..23 EEPROM Device Select */
-#define PCI_VPD_ROM_SZ (7L<<14) /* Bit 14..16 VPD ROM Size */
- /* Bit 12..13 reserved */
-#define PCI_PATCH_DIR2 (0xfL<<8) /* Bit 8..11 Ext Patchs dir 2..5 */
-#define PCI_PATCH_DIR_2 (1L<<8) /* Bit 8 CS for MicroWire */
-#define PCI_PATCH_DIR_3 (1L<<9)
-#define PCI_PATCH_DIR_4 (1L<<10)
-#define PCI_PATCH_DIR_5 (1L<<11)
-#define PCI_EXT_PATCHS2 (0xfL<<4) /* Bit 4..7 Extended Patches */
-#define PCI_EXT_PATCH_2 (1L<<4) /* Bit 4 CS for MicroWire */
-#define PCI_EXT_PATCH_3 (1L<<5)
-#define PCI_EXT_PATCH_4 (1L<<6)
-#define PCI_EXT_PATCH_5 (1L<<7)
-#define PCI_EN_DUMMY_RD (1L<<3) /* Bit 3 Enable Dummy Read */
-#define PCI_REV_DESC (1L<<2) /* Bit 2 Reverse Desc. Bytes */
-#define PCI_USEADDR64 (1L<<1) /* Bit 1 Use 64 Bit Addresse */
-#define PCI_USEDATA64 (1L<<0) /* Bit 0 Use 64 Bit Data bus ext*/
-
-/* Power Management Region */
-/* PCI_PM_CAP_ID 8 bit (ML) Power Management Cap. ID */
-/* PCI_PM_NITEM 8 bit (ML) Next Item Ptr */
-/* PCI_PM_CAP_REG 16 bit (ML) Power Management Capabilities*/
-#define PCI_PME_SUP (0x1f<<11) /* Bit 11..15 PM Manag. Event Support*/
-#define PCI_PM_D2_SUB (1<<10) /* Bit 10 D2 Support Bit */
-#define PCI_PM_D1_SUB (1<<9) /* Bit 9 D1 Support Bit */
- /* Bit 6..8 reserved */
-#define PCI_PM_DSI (1<<5) /* Bit 5 Device Specific Init.*/
-#define PCI_PM_APS (1<<4) /* Bit 4 Auxialiary Power Src */
-#define PCI_PME_CLOCK (1<<3) /* Bit 3 PM Event Clock */
-#define PCI_PM_VER (7<<0) /* Bit 0..2 PM PCI Spec. version */
-
-/* PCI_PM_CTL_STS 16 bit (ML) Power Manag. Control/Status */
-#define PCI_PME_STATUS (1<<15) /* Bit 15 PFA doesn't sup. PME#*/
-#define PCI_PM_DAT_SCL (3<<13) /* Bit 13..14 dat reg Scaling factor */
-#define PCI_PM_DAT_SEL (0xf<<9) /* Bit 9..12 PM data selector field */
- /* Bit 7.. 2 reserved */
-#define PCI_PM_STATE (3<<0) /* Bit 0.. 1 Power Management State */
-#define PCI_PM_STATE_D0 (0<<0) /* D0: Operational (default) */
-#define PCI_PM_STATE_D1 (1<<0) /* D1: not supported */
-#define PCI_PM_STATE_D2 (2<<0) /* D2: not supported */
-#define PCI_PM_STATE_D3 (3<<0) /* D3: HOT, Power Down and Reset */
-
-/* PCI_PM_DAT_REG 8 bit (ML) Power Manag. Data Register */
-/* VPD Region */
-/* PCI_VPD_CAP_ID 8 bit (ML) VPD Cap. ID */
-/* PCI_VPD_NITEM 8 bit (ML) Next Item Ptr */
-/* PCI_VPD_ADR_REG 16 bit (ML) VPD Address Register */
-#define PCI_VPD_FLAG (1<<15) /* Bit 15 starts VPD rd/wd cycle*/
-
-/* PCI_VPD_DAT_REG 32 bit (ML) VPD Data Register */
+
+#define PCI_ERRBITS (PCI_STATUS_DETECTED_PARITY | PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_SIG_TARGET_ABORT | PCI_STATUS_PARITY)
+
+
/*
* Control Register File:
@@ -873,20 +664,6 @@
#define T3_MUX (3<<2) /* Bit 3..2: Mux position */
#define T3_VRAM (3<<0) /* Bit 1..0: Virtual RAM buffer Address */
-/* PCI card IDs */
-/*
- * Note: The following 4 byte definitions shall not be used! Use OEM Concept!
- */
-#define PCI_VEND_ID0 0x48 /* PCI vendor ID (SysKonnect) */
-#define PCI_VEND_ID1 0x11 /* PCI vendor ID (SysKonnect) */
- /* (High byte) */
-#define PCI_DEV_ID0 0x00 /* PCI device ID */
-#define PCI_DEV_ID1 0x40 /* PCI device ID (High byte) */
-
-/*#define PCI_CLASS 0x02*/ /* PCI class code: network device */
-#define PCI_NW_CLASS 0x02 /* PCI class code: network device */
-#define PCI_SUB_CLASS 0x02 /* PCI subclass ID: FDDI device */
-#define PCI_PROG_INTFC 0x00 /* PCI programming Interface (=0) */
/*
* address transmission from logical to physical offset address on board
diff --git a/drivers/net/fjes/fjes_debugfs.c b/drivers/net/fjes/fjes_debugfs.c
index 153fc998f9c1..2c2095e7cf1e 100644
--- a/drivers/net/fjes/fjes_debugfs.c
+++ b/drivers/net/fjes/fjes_debugfs.c
@@ -52,20 +52,11 @@ DEFINE_SHOW_ATTRIBUTE(fjes_dbg_status);
void fjes_dbg_adapter_init(struct fjes_adapter *adapter)
{
const char *name = dev_name(&adapter->plat_dev->dev);
- struct dentry *pfile;
adapter->dbg_adapter = debugfs_create_dir(name, fjes_debug_root);
- if (!adapter->dbg_adapter) {
- dev_err(&adapter->plat_dev->dev,
- "debugfs entry for %s failed\n", name);
- return;
- }
- pfile = debugfs_create_file("status", 0444, adapter->dbg_adapter,
- adapter, &fjes_dbg_status_fops);
- if (!pfile)
- dev_err(&adapter->plat_dev->dev,
- "debugfs status for %s failed\n", name);
+ debugfs_create_file("status", 0444, adapter->dbg_adapter, adapter,
+ &fjes_dbg_status_fops);
}
void fjes_dbg_adapter_exit(struct fjes_adapter *adapter)
@@ -77,8 +68,6 @@ void fjes_dbg_adapter_exit(struct fjes_adapter *adapter)
void fjes_dbg_init(void)
{
fjes_debug_root = debugfs_create_dir(fjes_driver_name, NULL);
- if (!fjes_debug_root)
- pr_info("init of debugfs failed\n");
}
void fjes_dbg_exit(void)
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
index 98d1a45c0606..cb2ea8facd8d 100644
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* GENEVE: Generic Network Virtualization Encapsulation
*
* Copyright (c) 2015 Red Hat, 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -395,7 +392,7 @@ static int geneve_udp_encap_err_lookup(struct sock *sk, struct sk_buff *skb)
u8 zero_vni[3] = { 0 };
u8 *vni = zero_vni;
- if (skb->len < GENEVE_BASE_HLEN)
+ if (!pskb_may_pull(skb, skb_transport_offset(skb) + GENEVE_BASE_HLEN))
return -EINVAL;
geneveh = geneve_hdr(skb);
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index fc45b749db46..ecfe26215935 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -285,16 +285,29 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
return gtp_rx(pctx, skb, hdrlen, gtp->role);
}
-static void gtp_encap_destroy(struct sock *sk)
+static void __gtp_encap_destroy(struct sock *sk)
{
struct gtp_dev *gtp;
- gtp = rcu_dereference_sk_user_data(sk);
+ lock_sock(sk);
+ gtp = sk->sk_user_data;
if (gtp) {
+ if (gtp->sk0 == sk)
+ gtp->sk0 = NULL;
+ else
+ gtp->sk1u = NULL;
udp_sk(sk)->encap_type = 0;
rcu_assign_sk_user_data(sk, NULL);
sock_put(sk);
}
+ release_sock(sk);
+}
+
+static void gtp_encap_destroy(struct sock *sk)
+{
+ rtnl_lock();
+ __gtp_encap_destroy(sk);
+ rtnl_unlock();
}
static void gtp_encap_disable_sock(struct sock *sk)
@@ -302,7 +315,7 @@ static void gtp_encap_disable_sock(struct sock *sk)
if (!sk)
return;
- gtp_encap_destroy(sk);
+ __gtp_encap_destroy(sk);
}
static void gtp_encap_disable(struct gtp_dev *gtp)
@@ -681,7 +694,6 @@ static void gtp_dellink(struct net_device *dev, struct list_head *head)
{
struct gtp_dev *gtp = netdev_priv(dev);
- gtp_encap_disable(gtp);
gtp_hashtable_free(gtp);
list_del_rcu(&gtp->list);
unregister_netdevice_queue(dev, head);
@@ -796,7 +808,8 @@ static struct sock *gtp_encap_enable_socket(int fd, int type,
goto out_sock;
}
- if (rcu_dereference_sk_user_data(sock->sk)) {
+ lock_sock(sock->sk);
+ if (sock->sk->sk_user_data) {
sk = ERR_PTR(-EBUSY);
goto out_sock;
}
@@ -812,6 +825,7 @@ static struct sock *gtp_encap_enable_socket(int fd, int type,
setup_udp_tunnel_sock(sock_net(sock->sk), sock, &tuncfg);
out_sock:
+ release_sock(sock->sk);
sockfd_put(sock);
return sk;
}
@@ -843,8 +857,13 @@ static int gtp_encap_enable(struct gtp_dev *gtp, struct nlattr *data[])
if (data[IFLA_GTP_ROLE]) {
role = nla_get_u32(data[IFLA_GTP_ROLE]);
- if (role > GTP_ROLE_SGSN)
+ if (role > GTP_ROLE_SGSN) {
+ if (sk0)
+ gtp_encap_disable_sock(sk0);
+ if (sk1u)
+ gtp_encap_disable_sock(sk1u);
return -EINVAL;
+ }
}
gtp->sk0 = sk0;
@@ -945,7 +964,7 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, struct sock *sk,
}
- pctx = kmalloc(sizeof(struct pdp_ctx), GFP_KERNEL);
+ pctx = kmalloc(sizeof(*pctx), GFP_ATOMIC);
if (pctx == NULL)
return -ENOMEM;
@@ -1034,6 +1053,7 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
}
+ rtnl_lock();
rcu_read_lock();
gtp = gtp_find_dev(sock_net(skb->sk), info->attrs);
@@ -1058,6 +1078,7 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)
out_unlock:
rcu_read_unlock();
+ rtnl_unlock();
return err;
}
@@ -1360,9 +1381,9 @@ late_initcall(gtp_init);
static void __exit gtp_fini(void)
{
- unregister_pernet_subsys(&gtp_net_ops);
genl_unregister_family(&gtp_genl_family);
rtnl_link_unregister(&gtp_link_ops);
+ unregister_pernet_subsys(&gtp_net_ops);
pr_info("GTP module unloaded\n");
}
diff --git a/drivers/net/hippi/rrunner.c b/drivers/net/hippi/rrunner.c
index 7b9350dbebdd..2a6ec5394966 100644
--- a/drivers/net/hippi/rrunner.c
+++ b/drivers/net/hippi/rrunner.c
@@ -1196,7 +1196,6 @@ static int rr_open(struct net_device *dev)
goto error;
}
rrpriv->rx_ctrl_dma = dma_addr;
- memset(rrpriv->rx_ctrl, 0, 256*sizeof(struct ring_ctrl));
rrpriv->info = pci_alloc_consistent(pdev, sizeof(struct rr_info),
&dma_addr);
@@ -1205,7 +1204,6 @@ static int rr_open(struct net_device *dev)
goto error;
}
rrpriv->info_dma = dma_addr;
- memset(rrpriv->info, 0, sizeof(struct rr_info));
wmb();
spin_lock_irqsave(&rrpriv->lock, flags);
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 03ea5a7ed3a4..afdcc5664ea6 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -2407,7 +2407,7 @@ static struct hv_driver netvsc_drv = {
.probe = netvsc_probe,
.remove = netvsc_remove,
.driver = {
- .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ .probe_type = PROBE_FORCE_SYNCHRONOUS,
},
};
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 87d361666cdd..14545a8797a8 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -55,6 +55,13 @@
#include <net/net_namespace.h>
#include <linux/u64_stats_sync.h>
+/* blackhole_netdev - a device used for dsts that are marked expired!
+ * This is global device (instead of per-net-ns) since it's not needed
+ * to be per-ns and gets initialized at boot time.
+ */
+struct net_device *blackhole_netdev;
+EXPORT_SYMBOL(blackhole_netdev);
+
/* The higher levels take care of making this non-reentrant (it's
* called with bh's disabled).
*/
@@ -150,12 +157,14 @@ static const struct net_device_ops loopback_ops = {
.ndo_set_mac_address = eth_mac_addr,
};
-/* The loopback device is special. There is only one instance
- * per network namespace.
- */
-static void loopback_setup(struct net_device *dev)
+static void gen_lo_setup(struct net_device *dev,
+ unsigned int mtu,
+ const struct ethtool_ops *eth_ops,
+ const struct header_ops *hdr_ops,
+ const struct net_device_ops *dev_ops,
+ void (*dev_destructor)(struct net_device *dev))
{
- dev->mtu = 64 * 1024;
+ dev->mtu = mtu;
dev->hard_header_len = ETH_HLEN; /* 14 */
dev->min_header_len = ETH_HLEN; /* 14 */
dev->addr_len = ETH_ALEN; /* 6 */
@@ -174,11 +183,20 @@ static void loopback_setup(struct net_device *dev)
| NETIF_F_NETNS_LOCAL
| NETIF_F_VLAN_CHALLENGED
| NETIF_F_LOOPBACK;
- dev->ethtool_ops = &loopback_ethtool_ops;
- dev->header_ops = &eth_header_ops;
- dev->netdev_ops = &loopback_ops;
+ dev->ethtool_ops = eth_ops;
+ dev->header_ops = hdr_ops;
+ dev->netdev_ops = dev_ops;
dev->needs_free_netdev = true;
- dev->priv_destructor = loopback_dev_free;
+ dev->priv_destructor = dev_destructor;
+}
+
+/* The loopback device is special. There is only one instance
+ * per network namespace.
+ */
+static void loopback_setup(struct net_device *dev)
+{
+ gen_lo_setup(dev, (64 * 1024), &loopback_ethtool_ops, &eth_header_ops,
+ &loopback_ops, loopback_dev_free);
}
/* Setup and register the loopback device. */
@@ -213,3 +231,45 @@ out:
struct pernet_operations __net_initdata loopback_net_ops = {
.init = loopback_net_init,
};
+
+/* blackhole netdevice */
+static netdev_tx_t blackhole_netdev_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ kfree_skb(skb);
+ net_warn_ratelimited("%s(): Dropping skb.\n", __func__);
+ return NETDEV_TX_OK;
+}
+
+static const struct net_device_ops blackhole_netdev_ops = {
+ .ndo_start_xmit = blackhole_netdev_xmit,
+};
+
+/* This is a dst-dummy device used specifically for invalidated
+ * DSTs and unlike loopback, this is not per-ns.
+ */
+static void blackhole_netdev_setup(struct net_device *dev)
+{
+ gen_lo_setup(dev, ETH_MIN_MTU, NULL, NULL, &blackhole_netdev_ops, NULL);
+}
+
+/* Setup and register the blackhole_netdev. */
+static int __init blackhole_netdev_init(void)
+{
+ blackhole_netdev = alloc_netdev(0, "blackhole_dev", NET_NAME_UNKNOWN,
+ blackhole_netdev_setup);
+ if (!blackhole_netdev)
+ return -ENOMEM;
+
+ rtnl_lock();
+ dev_init_scheduler(blackhole_netdev);
+ dev_activate(blackhole_netdev);
+ rtnl_unlock();
+
+ blackhole_netdev->flags |= IFF_UP | IFF_RUNNING;
+ dev_net_set(blackhole_netdev, &init_net);
+
+ return 0;
+}
+
+device_initcall(blackhole_netdev_init);
diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index 75aebf65cd09..8f46aa1ddec0 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c
@@ -865,6 +865,7 @@ static void macsec_reset_skb(struct sk_buff *skb, struct net_device *dev)
static void macsec_finalize_skb(struct sk_buff *skb, u8 icv_len, u8 hdr_len)
{
+ skb->ip_summed = CHECKSUM_NONE;
memmove(skb->data + hdr_len, skb->data, 2 * ETH_ALEN);
skb_pull(skb, hdr_len);
pskb_trim_unique(skb, skb->len - icv_len);
@@ -1099,10 +1100,9 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb)
}
skb = skb_unshare(skb, GFP_ATOMIC);
- if (!skb) {
- *pskb = NULL;
+ *pskb = skb;
+ if (!skb)
return RX_HANDLER_CONSUMED;
- }
pulled_sci = pskb_may_pull(skb, macsec_extra_len(true));
if (!pulled_sci) {
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 681a882c32cd..940192c057b6 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -827,7 +827,7 @@ static int macvlan_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
struct ifreq ifrr;
int err = -EOPNOTSUPP;
- strncpy(ifrr.ifr_name, real_dev->name, IFNAMSIZ);
+ strscpy(ifrr.ifr_name, real_dev->name, IFNAMSIZ);
ifrr.ifr_ifru = ifr->ifr_ifru;
switch (cmd) {
diff --git a/drivers/net/mdio.c b/drivers/net/mdio.c
index 077364cbf439..5e72cc55afbd 100644
--- a/drivers/net/mdio.c
+++ b/drivers/net/mdio.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* mdio.c: Generic support for MDIO-compatible transceivers
* Copyright 2006-2009 Solarflare Communications 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 <linux/kernel.h>
diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c
index b509b941d5ca..c5c417a3c0ce 100644
--- a/drivers/net/netdevsim/dev.c
+++ b/drivers/net/netdevsim/dev.c
@@ -38,6 +38,8 @@ static int nsim_dev_debugfs_init(struct nsim_dev *nsim_dev)
nsim_dev->ports_ddir = debugfs_create_dir("ports", nsim_dev->ddir);
if (IS_ERR_OR_NULL(nsim_dev->ports_ddir))
return PTR_ERR_OR_ZERO(nsim_dev->ports_ddir) ?: -EINVAL;
+ debugfs_create_bool("fw_update_status", 0600, nsim_dev->ddir,
+ &nsim_dev->fw_update_status);
return 0;
}
@@ -220,8 +222,49 @@ static int nsim_dev_reload(struct devlink *devlink,
return 0;
}
+#define NSIM_DEV_FLASH_SIZE 500000
+#define NSIM_DEV_FLASH_CHUNK_SIZE 1000
+#define NSIM_DEV_FLASH_CHUNK_TIME_MS 10
+
+static int nsim_dev_flash_update(struct devlink *devlink, const char *file_name,
+ const char *component,
+ struct netlink_ext_ack *extack)
+{
+ struct nsim_dev *nsim_dev = devlink_priv(devlink);
+ int i;
+
+ if (nsim_dev->fw_update_status) {
+ devlink_flash_update_begin_notify(devlink);
+ devlink_flash_update_status_notify(devlink,
+ "Preparing to flash",
+ component, 0, 0);
+ }
+
+ for (i = 0; i < NSIM_DEV_FLASH_SIZE / NSIM_DEV_FLASH_CHUNK_SIZE; i++) {
+ if (nsim_dev->fw_update_status)
+ devlink_flash_update_status_notify(devlink, "Flashing",
+ component,
+ i * NSIM_DEV_FLASH_CHUNK_SIZE,
+ NSIM_DEV_FLASH_SIZE);
+ msleep(NSIM_DEV_FLASH_CHUNK_TIME_MS);
+ }
+
+ if (nsim_dev->fw_update_status) {
+ devlink_flash_update_status_notify(devlink, "Flashing",
+ component,
+ NSIM_DEV_FLASH_SIZE,
+ NSIM_DEV_FLASH_SIZE);
+ devlink_flash_update_status_notify(devlink, "Flashing done",
+ component, 0, 0);
+ devlink_flash_update_end_notify(devlink);
+ }
+
+ return 0;
+}
+
static const struct devlink_ops nsim_dev_devlink_ops = {
.reload = nsim_dev_reload,
+ .flash_update = nsim_dev_flash_update,
};
static struct nsim_dev *
@@ -240,6 +283,7 @@ nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev, unsigned int port_count)
get_random_bytes(nsim_dev->switch_id.id, nsim_dev->switch_id.id_len);
INIT_LIST_HEAD(&nsim_dev->port_list);
mutex_init(&nsim_dev->port_list_lock);
+ nsim_dev->fw_update_status = true;
nsim_dev->fib_data = nsim_fib_create();
if (IS_ERR(nsim_dev->fib_data)) {
diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c
index e5c8aa08e1cd..0740940f41b1 100644
--- a/drivers/net/netdevsim/netdev.c
+++ b/drivers/net/netdevsim/netdev.c
@@ -78,26 +78,6 @@ nsim_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv)
return nsim_bpf_setup_tc_block_cb(type, type_data, cb_priv);
}
-static int
-nsim_setup_tc_block(struct net_device *dev, struct tc_block_offload *f)
-{
- struct netdevsim *ns = netdev_priv(dev);
-
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
- return -EOPNOTSUPP;
-
- switch (f->command) {
- case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block, nsim_setup_tc_block_cb,
- ns, ns, f->extack);
- case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block, nsim_setup_tc_block_cb, ns);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-}
-
static int nsim_set_vf_mac(struct net_device *dev, int vf, u8 *mac)
{
struct netdevsim *ns = netdev_priv(dev);
@@ -223,12 +203,19 @@ static int nsim_set_vf_link_state(struct net_device *dev, int vf, int state)
return 0;
}
+static LIST_HEAD(nsim_block_cb_list);
+
static int
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_BLOCK:
- return nsim_setup_tc_block(dev, type_data);
+ return flow_block_cb_setup_simple(type_data,
+ &nsim_block_cb_list,
+ nsim_setup_tc_block_cb,
+ ns, ns, true);
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h
index 3f398797c2bc..79c05af2a7c0 100644
--- a/drivers/net/netdevsim/netdevsim.h
+++ b/drivers/net/netdevsim/netdevsim.h
@@ -157,6 +157,7 @@ struct nsim_dev {
struct netdev_phys_item_id switch_id;
struct list_head port_list;
struct mutex port_list_lock; /* protects port list */
+ bool fw_update_status;
};
int nsim_dev_init(void);
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index f99f27800fdb..20f14c5fbb7e 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -254,7 +254,7 @@ config AQUANTIA_PHY
---help---
Currently supports the Aquantia AQ1202, AQ2104, AQR105, AQR405
-config ASIX_PHY
+config AX88796B_PHY
tristate "Asix PHYs"
help
Currently supports the Asix Electronics PHY found in the X-Surf 100
@@ -416,6 +416,12 @@ config NATIONAL_PHY
---help---
Currently supports the DP83865 PHY.
+config NXP_TJA11XX_PHY
+ tristate "NXP TJA11xx PHYs support"
+ depends on HWMON
+ ---help---
+ Currently supports the NXP TJA1100 and TJA1101 PHY.
+
config QSEMI_PHY
tristate "Quality Semiconductor PHYs"
---help---
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 27d7f9f3b0de..839acb292c38 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -52,7 +52,7 @@ ifdef CONFIG_HWMON
aquantia-objs += aquantia_hwmon.o
endif
obj-$(CONFIG_AQUANTIA_PHY) += aquantia.o
-obj-$(CONFIG_ASIX_PHY) += asix.o
+obj-$(CONFIG_AX88796B_PHY) += ax88796b.o
obj-$(CONFIG_AT803X_PHY) += at803x.o
obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o
obj-$(CONFIG_BCM7XXX_PHY) += bcm7xxx.o
@@ -82,6 +82,7 @@ obj-$(CONFIG_MICROCHIP_PHY) += microchip.o
obj-$(CONFIG_MICROCHIP_T1_PHY) += microchip_t1.o
obj-$(CONFIG_MICROSEMI_PHY) += mscc.o
obj-$(CONFIG_NATIONAL_PHY) += national.o
+obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o
obj-$(CONFIG_QSEMI_PHY) += qsemi.o
obj-$(CONFIG_REALTEK_PHY) += realtek.o
obj-$(CONFIG_RENESAS_PHY) += uPD60620.o
diff --git a/drivers/net/phy/aquantia_main.c b/drivers/net/phy/aquantia_main.c
index 0fedd28fdb6e..3b29d381116f 100644
--- a/drivers/net/phy/aquantia_main.c
+++ b/drivers/net/phy/aquantia_main.c
@@ -27,6 +27,7 @@
#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK GENMASK(7, 3)
#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_KR 0
#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_XFI 2
+#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_USXGMII 3
#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_SGMII 6
#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_OCSGMII 10
@@ -360,6 +361,9 @@ static int aqr107_read_status(struct phy_device *phydev)
case MDIO_PHYXS_VEND_IF_STATUS_TYPE_XFI:
phydev->interface = PHY_INTERFACE_MODE_10GKR;
break;
+ case MDIO_PHYXS_VEND_IF_STATUS_TYPE_USXGMII:
+ phydev->interface = PHY_INTERFACE_MODE_USXGMII;
+ break;
case MDIO_PHYXS_VEND_IF_STATUS_TYPE_SGMII:
phydev->interface = PHY_INTERFACE_MODE_SGMII;
break;
@@ -488,9 +492,13 @@ static int aqr107_config_init(struct phy_device *phydev)
if (phydev->interface != PHY_INTERFACE_MODE_SGMII &&
phydev->interface != PHY_INTERFACE_MODE_2500BASEX &&
phydev->interface != PHY_INTERFACE_MODE_XGMII &&
+ phydev->interface != PHY_INTERFACE_MODE_USXGMII &&
phydev->interface != PHY_INTERFACE_MODE_10GKR)
return -ENODEV;
+ WARN(phydev->interface == PHY_INTERFACE_MODE_XGMII,
+ "Your devicetree is out of date, please update it. The AQR107 family doesn't support XGMII, maybe you mean USXGMII.\n");
+
ret = aqr107_wait_reset_complete(phydev);
if (!ret)
aqr107_chip_info(phydev);
diff --git a/drivers/net/phy/asix.c b/drivers/net/phy/ax88796b.c
index 79bf7ef1fcfd..79bf7ef1fcfd 100644
--- a/drivers/net/phy/asix.c
+++ b/drivers/net/phy/ax88796b.c
diff --git a/drivers/net/phy/bcm87xx.c b/drivers/net/phy/bcm87xx.c
index f0c0eefe2202..f6dce6850850 100644
--- a/drivers/net/phy/bcm87xx.c
+++ b/drivers/net/phy/bcm87xx.c
@@ -81,22 +81,18 @@ static int bcm87xx_of_reg_init(struct phy_device *phydev)
}
#endif /* CONFIG_OF_MDIO */
-static int bcm87xx_config_init(struct phy_device *phydev)
+static int bcm87xx_get_features(struct phy_device *phydev)
{
- linkmode_zero(phydev->supported);
linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
phydev->supported);
- linkmode_zero(phydev->advertising);
- linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
- phydev->advertising);
- phydev->state = PHY_NOLINK;
- phydev->autoneg = AUTONEG_DISABLE;
-
- bcm87xx_of_reg_init(phydev);
-
return 0;
}
+static int bcm87xx_config_init(struct phy_device *phydev)
+{
+ return bcm87xx_of_reg_init(phydev);
+}
+
static int bcm87xx_config_aneg(struct phy_device *phydev)
{
return -EINVAL;
@@ -194,7 +190,7 @@ static struct phy_driver bcm87xx_driver[] = {
.phy_id = PHY_ID_BCM8706,
.phy_id_mask = 0xffffffff,
.name = "Broadcom BCM8706",
- .features = PHY_10GBIT_FEC_FEATURES,
+ .get_features = bcm87xx_get_features,
.config_init = bcm87xx_config_init,
.config_aneg = bcm87xx_config_aneg,
.read_status = bcm87xx_read_status,
@@ -206,7 +202,7 @@ static struct phy_driver bcm87xx_driver[] = {
.phy_id = PHY_ID_BCM8727,
.phy_id_mask = 0xffffffff,
.name = "Broadcom BCM8727",
- .features = PHY_10GBIT_FEC_FEATURES,
+ .get_features = bcm87xx_get_features,
.config_init = bcm87xx_config_init,
.config_aneg = bcm87xx_config_aneg,
.read_status = bcm87xx_read_status,
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
index 67fa05d67523..937d0059e8ac 100644
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -663,6 +663,8 @@ static struct phy_driver broadcom_drivers[] = {
.config_init = bcm54xx_config_init,
.ack_interrupt = bcm_phy_ack_intr,
.config_intr = bcm_phy_config_intr,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
}, {
.phy_id = PHY_ID_BCM5481,
.phy_id_mask = 0xfffffff0,
diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c
index c71c7d0f53f0..1f1ecee0ee2f 100644
--- a/drivers/net/phy/dp83867.c
+++ b/drivers/net/phy/dp83867.c
@@ -34,6 +34,7 @@
#define DP83867_RGMIICTL 0x0032
#define DP83867_STRAP_STS1 0x006E
+#define DP83867_STRAP_STS2 0x006f
#define DP83867_RGMIIDCTL 0x0086
#define DP83867_IO_MUX_CFG 0x0170
#define DP83867_10M_SGMII_CFG 0x016F
@@ -63,19 +64,30 @@
/* STRAP_STS1 bits */
#define DP83867_STRAP_STS1_RESERVED BIT(11)
+/* STRAP_STS2 bits */
+#define DP83867_STRAP_STS2_CLK_SKEW_TX_MASK GENMASK(6, 4)
+#define DP83867_STRAP_STS2_CLK_SKEW_TX_SHIFT 4
+#define DP83867_STRAP_STS2_CLK_SKEW_RX_MASK GENMASK(2, 0)
+#define DP83867_STRAP_STS2_CLK_SKEW_RX_SHIFT 0
+#define DP83867_STRAP_STS2_CLK_SKEW_NONE BIT(2)
+
/* PHY CTRL bits */
#define DP83867_PHYCR_FIFO_DEPTH_SHIFT 14
-#define DP83867_PHYCR_FIFO_DEPTH_MASK (3 << 14)
+#define DP83867_PHYCR_FIFO_DEPTH_MAX 0x03
+#define DP83867_PHYCR_FIFO_DEPTH_MASK GENMASK(15, 14)
#define DP83867_PHYCR_RESERVED_MASK BIT(11)
/* RGMIIDCTL bits */
+#define DP83867_RGMII_TX_CLK_DELAY_MAX 0xf
#define DP83867_RGMII_TX_CLK_DELAY_SHIFT 4
+#define DP83867_RGMII_RX_CLK_DELAY_MAX 0xf
+#define DP83867_RGMII_RX_CLK_DELAY_SHIFT 0
/* IO_MUX_CFG bits */
-#define DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL 0x1f
-
+#define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MASK 0x1f
#define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX 0x0
#define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MIN 0x1f
+#define DP83867_IO_MUX_CFG_CLK_O_DISABLE BIT(6)
#define DP83867_IO_MUX_CFG_CLK_O_SEL_MASK (0x1f << 8)
#define DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT 8
@@ -89,13 +101,14 @@ enum {
};
struct dp83867_private {
- int rx_id_delay;
- int tx_id_delay;
- int fifo_depth;
+ u32 rx_id_delay;
+ u32 tx_id_delay;
+ u32 fifo_depth;
int io_impedance;
int port_mirroring;
bool rxctrl_strap_quirk;
- int clk_output_sel;
+ bool set_clk_output;
+ u32 clk_output_sel;
};
static int dp83867_ack_interrupt(struct phy_device *phydev)
@@ -157,38 +170,83 @@ static int dp83867_of_init(struct phy_device *phydev)
if (!of_node)
return -ENODEV;
- dp83867->io_impedance = -EINVAL;
-
/* Optional configuration */
ret = of_property_read_u32(of_node, "ti,clk-output-sel",
&dp83867->clk_output_sel);
- if (ret || dp83867->clk_output_sel > DP83867_CLK_O_SEL_REF_CLK)
- /* Keep the default value if ti,clk-output-sel is not set
- * or too high
+ /* If not set, keep default */
+ if (!ret) {
+ dp83867->set_clk_output = true;
+ /* Valid values are 0 to DP83867_CLK_O_SEL_REF_CLK or
+ * DP83867_CLK_O_SEL_OFF.
*/
- dp83867->clk_output_sel = DP83867_CLK_O_SEL_REF_CLK;
+ if (dp83867->clk_output_sel > DP83867_CLK_O_SEL_REF_CLK &&
+ dp83867->clk_output_sel != DP83867_CLK_O_SEL_OFF) {
+ phydev_err(phydev, "ti,clk-output-sel value %u out of range\n",
+ dp83867->clk_output_sel);
+ return -EINVAL;
+ }
+ }
if (of_property_read_bool(of_node, "ti,max-output-impedance"))
dp83867->io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX;
else if (of_property_read_bool(of_node, "ti,min-output-impedance"))
dp83867->io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MIN;
+ else
+ dp83867->io_impedance = -1; /* leave at default */
dp83867->rxctrl_strap_quirk = of_property_read_bool(of_node,
"ti,dp83867-rxctrl-strap-quirk");
- ret = of_property_read_u32(of_node, "ti,rx-internal-delay",
- &dp83867->rx_id_delay);
- if (ret &&
- (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
- phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID))
- return ret;
+ /* Existing behavior was to use default pin strapping delay in rgmii
+ * mode, but rgmii should have meant no delay. Warn existing users.
+ */
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
+ const u16 val = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_STRAP_STS2);
+ const u16 txskew = (val & DP83867_STRAP_STS2_CLK_SKEW_TX_MASK) >>
+ DP83867_STRAP_STS2_CLK_SKEW_TX_SHIFT;
+ const u16 rxskew = (val & DP83867_STRAP_STS2_CLK_SKEW_RX_MASK) >>
+ DP83867_STRAP_STS2_CLK_SKEW_RX_SHIFT;
+
+ if (txskew != DP83867_STRAP_STS2_CLK_SKEW_NONE ||
+ rxskew != DP83867_STRAP_STS2_CLK_SKEW_NONE)
+ phydev_warn(phydev,
+ "PHY has delays via pin strapping, but phy-mode = 'rgmii'\n"
+ "Should be 'rgmii-id' to use internal delays\n");
+ }
- ret = of_property_read_u32(of_node, "ti,tx-internal-delay",
- &dp83867->tx_id_delay);
- if (ret &&
- (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
- phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID))
- return ret;
+ /* RX delay *must* be specified if internal delay of RX is used. */
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+ phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
+ ret = of_property_read_u32(of_node, "ti,rx-internal-delay",
+ &dp83867->rx_id_delay);
+ if (ret) {
+ phydev_err(phydev, "ti,rx-internal-delay must be specified\n");
+ return ret;
+ }
+ if (dp83867->rx_id_delay > DP83867_RGMII_RX_CLK_DELAY_MAX) {
+ phydev_err(phydev,
+ "ti,rx-internal-delay value of %u out of range\n",
+ dp83867->rx_id_delay);
+ return -EINVAL;
+ }
+ }
+
+ /* TX delay *must* be specified if internal delay of RX is used. */
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+ phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
+ ret = of_property_read_u32(of_node, "ti,tx-internal-delay",
+ &dp83867->tx_id_delay);
+ if (ret) {
+ phydev_err(phydev, "ti,tx-internal-delay must be specified\n");
+ return ret;
+ }
+ if (dp83867->tx_id_delay > DP83867_RGMII_TX_CLK_DELAY_MAX) {
+ phydev_err(phydev,
+ "ti,tx-internal-delay value of %u out of range\n",
+ dp83867->tx_id_delay);
+ return -EINVAL;
+ }
+ }
if (of_property_read_bool(of_node, "enet-phy-lane-swap"))
dp83867->port_mirroring = DP83867_PORT_MIRROING_EN;
@@ -196,8 +254,20 @@ static int dp83867_of_init(struct phy_device *phydev)
if (of_property_read_bool(of_node, "enet-phy-lane-no-swap"))
dp83867->port_mirroring = DP83867_PORT_MIRROING_DIS;
- return of_property_read_u32(of_node, "ti,fifo-depth",
+ ret = of_property_read_u32(of_node, "ti,fifo-depth",
&dp83867->fifo_depth);
+ if (ret) {
+ phydev_err(phydev,
+ "ti,fifo-depth property is required\n");
+ return ret;
+ }
+ if (dp83867->fifo_depth > DP83867_PHYCR_FIFO_DEPTH_MAX) {
+ phydev_err(phydev,
+ "ti,fifo-depth value %u out of range\n",
+ dp83867->fifo_depth);
+ return -EINVAL;
+ }
+ return 0;
}
#else
static int dp83867_of_init(struct phy_device *phydev)
@@ -206,25 +276,29 @@ static int dp83867_of_init(struct phy_device *phydev)
}
#endif /* CONFIG_OF_MDIO */
-static int dp83867_config_init(struct phy_device *phydev)
+static int dp83867_probe(struct phy_device *phydev)
{
struct dp83867_private *dp83867;
+
+ dp83867 = devm_kzalloc(&phydev->mdio.dev, sizeof(*dp83867),
+ GFP_KERNEL);
+ if (!dp83867)
+ return -ENOMEM;
+
+ phydev->priv = dp83867;
+
+ return 0;
+}
+
+static int dp83867_config_init(struct phy_device *phydev)
+{
+ struct dp83867_private *dp83867 = phydev->priv;
int ret, val, bs;
u16 delay;
- if (!phydev->priv) {
- dp83867 = devm_kzalloc(&phydev->mdio.dev, sizeof(*dp83867),
- GFP_KERNEL);
- if (!dp83867)
- return -ENOMEM;
-
- phydev->priv = dp83867;
- ret = dp83867_of_init(phydev);
- if (ret)
- return ret;
- } else {
- dp83867 = (struct dp83867_private *)phydev->priv;
- }
+ ret = dp83867_of_init(phydev);
+ if (ret)
+ return ret;
/* RX_DV/RX_CTRL strapped in mode 1 or mode 2 workaround */
if (dp83867->rxctrl_strap_quirk)
@@ -256,9 +330,16 @@ static int dp83867_config_init(struct phy_device *phydev)
if (ret)
return ret;
- /* Set up RGMII delays */
+ /* If rgmii mode with no internal delay is selected, we do NOT use
+ * aligned mode as one might expect. Instead we use the PHY's default
+ * based on pin strapping. And the "mode 0" default is to *use*
+ * internal delay with a value of 7 (2.00 ns).
+ *
+ * Set up RGMII delays
+ */
val = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_RGMIICTL);
+ val &= ~(DP83867_RGMII_TX_CLK_DELAY_EN | DP83867_RGMII_RX_CLK_DELAY_EN);
if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
val |= (DP83867_RGMII_TX_CLK_DELAY_EN | DP83867_RGMII_RX_CLK_DELAY_EN);
@@ -275,14 +356,14 @@ static int dp83867_config_init(struct phy_device *phydev)
phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RGMIIDCTL,
delay);
-
- if (dp83867->io_impedance >= 0)
- phy_modify_mmd(phydev, DP83867_DEVADDR, DP83867_IO_MUX_CFG,
- DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL,
- dp83867->io_impedance &
- DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL);
}
+ /* If specified, set io impedance */
+ if (dp83867->io_impedance >= 0)
+ phy_modify_mmd(phydev, DP83867_DEVADDR, DP83867_IO_MUX_CFG,
+ DP83867_IO_MUX_CFG_IO_IMPEDANCE_MASK,
+ dp83867->io_impedance);
+
if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
/* For support SPEED_10 in SGMII mode
* DP83867_10M_SGMII_RATE_ADAPT bit
@@ -321,11 +402,20 @@ static int dp83867_config_init(struct phy_device *phydev)
dp83867_config_port_mirroring(phydev);
/* Clock output selection if muxing property is set */
- if (dp83867->clk_output_sel != DP83867_CLK_O_SEL_REF_CLK)
+ if (dp83867->set_clk_output) {
+ u16 mask = DP83867_IO_MUX_CFG_CLK_O_DISABLE;
+
+ if (dp83867->clk_output_sel == DP83867_CLK_O_SEL_OFF) {
+ val = DP83867_IO_MUX_CFG_CLK_O_DISABLE;
+ } else {
+ mask |= DP83867_IO_MUX_CFG_CLK_O_SEL_MASK;
+ val = dp83867->clk_output_sel <<
+ DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT;
+ }
+
phy_modify_mmd(phydev, DP83867_DEVADDR, DP83867_IO_MUX_CFG,
- DP83867_IO_MUX_CFG_CLK_O_SEL_MASK,
- dp83867->clk_output_sel <<
- DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT);
+ mask, val);
+ }
return 0;
}
@@ -350,6 +440,7 @@ static struct phy_driver dp83867_driver[] = {
.name = "TI DP83867",
/* PHY_GBIT_FEATURES */
+ .probe = dp83867_probe,
.config_init = dp83867_config_init,
.soft_reset = dp83867_phy_reset,
diff --git a/drivers/net/phy/lxt.c b/drivers/net/phy/lxt.c
index 314486288119..356bd6472f49 100644
--- a/drivers/net/phy/lxt.c
+++ b/drivers/net/phy/lxt.c
@@ -262,6 +262,8 @@ static struct phy_driver lxt97x_driver[] = {
/* PHY_BASIC_FEATURES */
.ack_interrupt = lxt971_ack_interrupt,
.config_intr = lxt971_config_intr,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
}, {
.phy_id = 0x00137a10,
.name = "LXT973-A2",
@@ -271,6 +273,8 @@ static struct phy_driver lxt97x_driver[] = {
.probe = lxt973_probe,
.config_aneg = lxt973_config_aneg,
.read_status = lxt973a2_read_status,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
}, {
.phy_id = 0x00137a10,
.name = "LXT973",
@@ -279,6 +283,8 @@ static struct phy_driver lxt97x_driver[] = {
.flags = 0,
.probe = lxt973_probe,
.config_aneg = lxt973_config_aneg,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
} };
module_phy_driver(lxt97x_driver);
diff --git a/drivers/net/phy/nxp-tja11xx.c b/drivers/net/phy/nxp-tja11xx.c
new file mode 100644
index 000000000000..b705d0bd798b
--- /dev/null
+++ b/drivers/net/phy/nxp-tja11xx.c
@@ -0,0 +1,403 @@
+// SPDX-License-Identifier: GPL-2.0
+/* NXP TJA1100 BroadRReach PHY driver
+ *
+ * Copyright (C) 2018 Marek Vasut <marex@denx.de>
+ */
+#include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <linux/kernel.h>
+#include <linux/mii.h>
+#include <linux/module.h>
+#include <linux/phy.h>
+#include <linux/hwmon.h>
+#include <linux/bitfield.h>
+
+#define PHY_ID_MASK 0xfffffff0
+#define PHY_ID_TJA1100 0x0180dc40
+#define PHY_ID_TJA1101 0x0180dd00
+
+#define MII_ECTRL 17
+#define MII_ECTRL_LINK_CONTROL BIT(15)
+#define MII_ECTRL_POWER_MODE_MASK GENMASK(14, 11)
+#define MII_ECTRL_POWER_MODE_NO_CHANGE (0x0 << 11)
+#define MII_ECTRL_POWER_MODE_NORMAL (0x3 << 11)
+#define MII_ECTRL_POWER_MODE_STANDBY (0xc << 11)
+#define MII_ECTRL_CONFIG_EN BIT(2)
+#define MII_ECTRL_WAKE_REQUEST BIT(0)
+
+#define MII_CFG1 18
+#define MII_CFG1_AUTO_OP BIT(14)
+#define MII_CFG1_SLEEP_CONFIRM BIT(6)
+#define MII_CFG1_LED_MODE_MASK GENMASK(5, 4)
+#define MII_CFG1_LED_MODE_LINKUP 0
+#define MII_CFG1_LED_ENABLE BIT(3)
+
+#define MII_CFG2 19
+#define MII_CFG2_SLEEP_REQUEST_TO GENMASK(1, 0)
+#define MII_CFG2_SLEEP_REQUEST_TO_16MS 0x3
+
+#define MII_INTSRC 21
+#define MII_INTSRC_TEMP_ERR BIT(1)
+#define MII_INTSRC_UV_ERR BIT(3)
+
+#define MII_COMMSTAT 23
+#define MII_COMMSTAT_LINK_UP BIT(15)
+
+#define MII_GENSTAT 24
+#define MII_GENSTAT_PLL_LOCKED BIT(14)
+
+#define MII_COMMCFG 27
+#define MII_COMMCFG_AUTO_OP BIT(15)
+
+struct tja11xx_priv {
+ char *hwmon_name;
+ struct device *hwmon_dev;
+};
+
+struct tja11xx_phy_stats {
+ const char *string;
+ u8 reg;
+ u8 off;
+ u16 mask;
+};
+
+static struct tja11xx_phy_stats tja11xx_hw_stats[] = {
+ { "phy_symbol_error_count", 20, 0, GENMASK(15, 0) },
+ { "phy_polarity_detect", 25, 6, BIT(6) },
+ { "phy_open_detect", 25, 7, BIT(7) },
+ { "phy_short_detect", 25, 8, BIT(8) },
+ { "phy_rem_rcvr_count", 26, 0, GENMASK(7, 0) },
+ { "phy_loc_rcvr_count", 26, 8, GENMASK(15, 8) },
+};
+
+static int tja11xx_check(struct phy_device *phydev, u8 reg, u16 mask, u16 set)
+{
+ int i, ret;
+
+ for (i = 0; i < 200; i++) {
+ ret = phy_read(phydev, reg);
+ if (ret < 0)
+ return ret;
+
+ if ((ret & mask) == set)
+ return 0;
+
+ usleep_range(100, 150);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int phy_modify_check(struct phy_device *phydev, u8 reg,
+ u16 mask, u16 set)
+{
+ int ret;
+
+ ret = phy_modify(phydev, reg, mask, set);
+ if (ret)
+ return ret;
+
+ return tja11xx_check(phydev, reg, mask, set);
+}
+
+static int tja11xx_enable_reg_write(struct phy_device *phydev)
+{
+ return phy_set_bits(phydev, MII_ECTRL, MII_ECTRL_CONFIG_EN);
+}
+
+static int tja11xx_enable_link_control(struct phy_device *phydev)
+{
+ return phy_set_bits(phydev, MII_ECTRL, MII_ECTRL_LINK_CONTROL);
+}
+
+static int tja11xx_wakeup(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = phy_read(phydev, MII_ECTRL);
+ if (ret < 0)
+ return ret;
+
+ switch (ret & MII_ECTRL_POWER_MODE_MASK) {
+ case MII_ECTRL_POWER_MODE_NO_CHANGE:
+ break;
+ case MII_ECTRL_POWER_MODE_NORMAL:
+ ret = phy_set_bits(phydev, MII_ECTRL, MII_ECTRL_WAKE_REQUEST);
+ if (ret)
+ return ret;
+
+ ret = phy_clear_bits(phydev, MII_ECTRL, MII_ECTRL_WAKE_REQUEST);
+ if (ret)
+ return ret;
+ break;
+ case MII_ECTRL_POWER_MODE_STANDBY:
+ ret = phy_modify_check(phydev, MII_ECTRL,
+ MII_ECTRL_POWER_MODE_MASK,
+ MII_ECTRL_POWER_MODE_STANDBY);
+ if (ret)
+ return ret;
+
+ ret = phy_modify(phydev, MII_ECTRL, MII_ECTRL_POWER_MODE_MASK,
+ MII_ECTRL_POWER_MODE_NORMAL);
+ if (ret)
+ return ret;
+
+ ret = phy_modify_check(phydev, MII_GENSTAT,
+ MII_GENSTAT_PLL_LOCKED,
+ MII_GENSTAT_PLL_LOCKED);
+ if (ret)
+ return ret;
+
+ return tja11xx_enable_link_control(phydev);
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int tja11xx_soft_reset(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = tja11xx_enable_reg_write(phydev);
+ if (ret)
+ return ret;
+
+ return genphy_soft_reset(phydev);
+}
+
+static int tja11xx_config_init(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = tja11xx_enable_reg_write(phydev);
+ if (ret)
+ return ret;
+
+ phydev->autoneg = AUTONEG_DISABLE;
+ phydev->speed = SPEED_100;
+ phydev->duplex = DUPLEX_FULL;
+
+ switch (phydev->phy_id & PHY_ID_MASK) {
+ case PHY_ID_TJA1100:
+ ret = phy_modify(phydev, MII_CFG1,
+ MII_CFG1_AUTO_OP | MII_CFG1_LED_MODE_MASK |
+ MII_CFG1_LED_ENABLE,
+ MII_CFG1_AUTO_OP | MII_CFG1_LED_MODE_LINKUP |
+ MII_CFG1_LED_ENABLE);
+ if (ret)
+ return ret;
+ break;
+ case PHY_ID_TJA1101:
+ ret = phy_set_bits(phydev, MII_COMMCFG, MII_COMMCFG_AUTO_OP);
+ if (ret)
+ return ret;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = phy_clear_bits(phydev, MII_CFG1, MII_CFG1_SLEEP_CONFIRM);
+ if (ret)
+ return ret;
+
+ ret = phy_modify(phydev, MII_CFG2, MII_CFG2_SLEEP_REQUEST_TO,
+ MII_CFG2_SLEEP_REQUEST_TO_16MS);
+ if (ret)
+ return ret;
+
+ ret = tja11xx_wakeup(phydev);
+ if (ret < 0)
+ return ret;
+
+ /* ACK interrupts by reading the status register */
+ ret = phy_read(phydev, MII_INTSRC);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int tja11xx_read_status(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = genphy_update_link(phydev);
+ if (ret)
+ return ret;
+
+ if (phydev->link) {
+ ret = phy_read(phydev, MII_COMMSTAT);
+ if (ret < 0)
+ return ret;
+
+ if (!(ret & MII_COMMSTAT_LINK_UP))
+ phydev->link = 0;
+ }
+
+ return 0;
+}
+
+static int tja11xx_get_sset_count(struct phy_device *phydev)
+{
+ return ARRAY_SIZE(tja11xx_hw_stats);
+}
+
+static void tja11xx_get_strings(struct phy_device *phydev, u8 *data)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(tja11xx_hw_stats); i++) {
+ strncpy(data + i * ETH_GSTRING_LEN,
+ tja11xx_hw_stats[i].string, ETH_GSTRING_LEN);
+ }
+}
+
+static void tja11xx_get_stats(struct phy_device *phydev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ int i, ret;
+
+ for (i = 0; i < ARRAY_SIZE(tja11xx_hw_stats); i++) {
+ ret = phy_read(phydev, tja11xx_hw_stats[i].reg);
+ if (ret < 0)
+ data[i] = U64_MAX;
+ else {
+ data[i] = ret & tja11xx_hw_stats[i].mask;
+ data[i] >>= tja11xx_hw_stats[i].off;
+ }
+ }
+}
+
+static int tja11xx_hwmon_read(struct device *dev,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel, long *value)
+{
+ struct phy_device *phydev = dev_get_drvdata(dev);
+ int ret;
+
+ if (type == hwmon_in && attr == hwmon_in_lcrit_alarm) {
+ ret = phy_read(phydev, MII_INTSRC);
+ if (ret < 0)
+ return ret;
+
+ *value = !!(ret & MII_INTSRC_TEMP_ERR);
+ return 0;
+ }
+
+ if (type == hwmon_temp && attr == hwmon_temp_crit_alarm) {
+ ret = phy_read(phydev, MII_INTSRC);
+ if (ret < 0)
+ return ret;
+
+ *value = !!(ret & MII_INTSRC_UV_ERR);
+ return 0;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+static umode_t tja11xx_hwmon_is_visible(const void *data,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ if (type == hwmon_in && attr == hwmon_in_lcrit_alarm)
+ return 0444;
+
+ if (type == hwmon_temp && attr == hwmon_temp_crit_alarm)
+ return 0444;
+
+ return 0;
+}
+
+static const struct hwmon_channel_info *tja11xx_hwmon_info[] = {
+ HWMON_CHANNEL_INFO(in, HWMON_I_LCRIT_ALARM),
+ HWMON_CHANNEL_INFO(temp, HWMON_T_CRIT_ALARM),
+ NULL
+};
+
+static const struct hwmon_ops tja11xx_hwmon_hwmon_ops = {
+ .is_visible = tja11xx_hwmon_is_visible,
+ .read = tja11xx_hwmon_read,
+};
+
+static const struct hwmon_chip_info tja11xx_hwmon_chip_info = {
+ .ops = &tja11xx_hwmon_hwmon_ops,
+ .info = tja11xx_hwmon_info,
+};
+
+static int tja11xx_probe(struct phy_device *phydev)
+{
+ struct device *dev = &phydev->mdio.dev;
+ struct tja11xx_priv *priv;
+ int i;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->hwmon_name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL);
+ if (!priv->hwmon_name)
+ return -ENOMEM;
+
+ for (i = 0; priv->hwmon_name[i]; i++)
+ if (hwmon_is_bad_char(priv->hwmon_name[i]))
+ priv->hwmon_name[i] = '_';
+
+ priv->hwmon_dev =
+ devm_hwmon_device_register_with_info(dev, priv->hwmon_name,
+ phydev,
+ &tja11xx_hwmon_chip_info,
+ NULL);
+
+ return PTR_ERR_OR_ZERO(priv->hwmon_dev);
+}
+
+static struct phy_driver tja11xx_driver[] = {
+ {
+ PHY_ID_MATCH_MODEL(PHY_ID_TJA1100),
+ .name = "NXP TJA1100",
+ .features = PHY_BASIC_T1_FEATURES,
+ .probe = tja11xx_probe,
+ .soft_reset = tja11xx_soft_reset,
+ .config_init = tja11xx_config_init,
+ .read_status = tja11xx_read_status,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+ .set_loopback = genphy_loopback,
+ /* Statistics */
+ .get_sset_count = tja11xx_get_sset_count,
+ .get_strings = tja11xx_get_strings,
+ .get_stats = tja11xx_get_stats,
+ }, {
+ PHY_ID_MATCH_MODEL(PHY_ID_TJA1101),
+ .name = "NXP TJA1101",
+ .features = PHY_BASIC_T1_FEATURES,
+ .probe = tja11xx_probe,
+ .soft_reset = tja11xx_soft_reset,
+ .config_init = tja11xx_config_init,
+ .read_status = tja11xx_read_status,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+ .set_loopback = genphy_loopback,
+ /* Statistics */
+ .get_sset_count = tja11xx_get_sset_count,
+ .get_strings = tja11xx_get_strings,
+ .get_stats = tja11xx_get_stats,
+ }
+};
+
+module_phy_driver(tja11xx_driver);
+
+static struct mdio_device_id __maybe_unused tja11xx_tbl[] = {
+ { PHY_ID_MATCH_MODEL(PHY_ID_TJA1100) },
+ { PHY_ID_MATCH_MODEL(PHY_ID_TJA1101) },
+ { }
+};
+
+MODULE_DEVICE_TABLE(mdio, tja11xx_tbl);
+
+MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
+MODULE_DESCRIPTION("NXP TJA11xx BoardR-Reach PHY driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c
index 3daf0214a242..16667fbac8bf 100644
--- a/drivers/net/phy/phy-core.c
+++ b/drivers/net/phy/phy-core.c
@@ -8,7 +8,7 @@
const char *phy_speed_to_str(int speed)
{
- BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 67,
+ BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 69,
"Enum ethtool_link_mode_bit_indices and phylib are out of sync. "
"If a speed or mode has been added please update phy_speed_to_str "
"and the PHY settings array.\n");
@@ -131,9 +131,11 @@ static const struct phy_setting settings[] = {
PHY_SETTING( 1000, FULL, 1000baseKX_Full ),
PHY_SETTING( 1000, FULL, 1000baseT_Full ),
PHY_SETTING( 1000, HALF, 1000baseT_Half ),
+ PHY_SETTING( 1000, FULL, 1000baseT1_Full ),
PHY_SETTING( 1000, FULL, 1000baseX_Full ),
/* 100M */
PHY_SETTING( 100, FULL, 100baseT_Full ),
+ PHY_SETTING( 100, FULL, 100baseT1_Full ),
PHY_SETTING( 100, HALF, 100baseT_Half ),
/* 10M */
PHY_SETTING( 10, FULL, 10baseT_Full ),
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index e8885429293a..ef7aa738e0dc 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -29,6 +29,8 @@
#include <linux/uaccess.h>
#include <linux/atomic.h>
+#define PHY_STATE_TIME HZ
+
#define PHY_STATE_STR(_state) \
case PHY_##_state: \
return __stringify(_state); \
@@ -41,7 +43,6 @@ static const char *phy_state_to_str(enum phy_state st)
PHY_STATE_STR(UP)
PHY_STATE_STR(RUNNING)
PHY_STATE_STR(NOLINK)
- PHY_STATE_STR(FORCING)
PHY_STATE_STR(HALTED)
}
@@ -297,12 +298,8 @@ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd)
linkmode_copy(phydev->advertising, advertising);
- if (AUTONEG_ENABLE == cmd->autoneg)
- linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
- phydev->advertising);
- else
- linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
- phydev->advertising);
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
+ phydev->advertising, AUTONEG_ENABLE == cmd->autoneg);
phydev->duplex = cmd->duplex;
@@ -352,12 +349,8 @@ int phy_ethtool_ksettings_set(struct phy_device *phydev,
linkmode_copy(phydev->advertising, advertising);
- if (autoneg == AUTONEG_ENABLE)
- linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
- phydev->advertising);
- else
- linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
- phydev->advertising);
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
+ phydev->advertising, autoneg == AUTONEG_ENABLE);
phydev->duplex = duplex;
@@ -407,6 +400,7 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd)
struct mii_ioctl_data *mii_data = if_mii(ifr);
u16 val = mii_data->val_in;
bool change_autoneg = false;
+ int prtad, devad;
switch (cmd) {
case SIOCGMIIPHY:
@@ -414,14 +408,29 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd)
/* fall through */
case SIOCGMIIREG:
- mii_data->val_out = mdiobus_read(phydev->mdio.bus,
- mii_data->phy_id,
- mii_data->reg_num);
+ if (mdio_phy_id_is_c45(mii_data->phy_id)) {
+ prtad = mdio_phy_id_prtad(mii_data->phy_id);
+ devad = mdio_phy_id_devad(mii_data->phy_id);
+ devad = MII_ADDR_C45 | devad << 16 | mii_data->reg_num;
+ } else {
+ prtad = mii_data->phy_id;
+ devad = mii_data->reg_num;
+ }
+ mii_data->val_out = mdiobus_read(phydev->mdio.bus, prtad,
+ devad);
return 0;
case SIOCSMIIREG:
- if (mii_data->phy_id == phydev->mdio.addr) {
- switch (mii_data->reg_num) {
+ if (mdio_phy_id_is_c45(mii_data->phy_id)) {
+ prtad = mdio_phy_id_prtad(mii_data->phy_id);
+ devad = mdio_phy_id_devad(mii_data->phy_id);
+ devad = MII_ADDR_C45 | devad << 16 | mii_data->reg_num;
+ } else {
+ prtad = mii_data->phy_id;
+ devad = mii_data->reg_num;
+ }
+ if (prtad == phydev->mdio.addr) {
+ switch (devad) {
case MII_BMCR:
if ((val & (BMCR_RESET | BMCR_ANENABLE)) == 0) {
if (phydev->autoneg == AUTONEG_ENABLE)
@@ -454,11 +463,10 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd)
}
}
- mdiobus_write(phydev->mdio.bus, mii_data->phy_id,
- mii_data->reg_num, val);
+ mdiobus_write(phydev->mdio.bus, prtad, devad, val);
- if (mii_data->phy_id == phydev->mdio.addr &&
- mii_data->reg_num == MII_BMCR &&
+ if (prtad == phydev->mdio.addr &&
+ devad == MII_BMCR &&
val & BMCR_RESET)
return phy_init_hw(phydev);
@@ -478,12 +486,12 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd)
}
EXPORT_SYMBOL(phy_mii_ioctl);
-static void phy_queue_state_machine(struct phy_device *phydev,
- unsigned int secs)
+void phy_queue_state_machine(struct phy_device *phydev, unsigned long jiffies)
{
mod_delayed_work(system_power_efficient_wq, &phydev->state_queue,
- secs * HZ);
+ jiffies);
}
+EXPORT_SYMBOL(phy_queue_state_machine);
static void phy_trigger_machine(struct phy_device *phydev)
{
@@ -560,15 +568,8 @@ int phy_start_aneg(struct phy_device *phydev)
if (err < 0)
goto out_unlock;
- if (phy_is_started(phydev)) {
- if (phydev->autoneg == AUTONEG_ENABLE) {
- err = phy_check_link_status(phydev);
- } else {
- phydev->state = PHY_FORCING;
- phydev->link_timeout = PHY_FORCE_TIMEOUT;
- }
- }
-
+ if (phy_is_started(phydev))
+ err = phy_check_link_status(phydev);
out_unlock:
mutex_unlock(&phydev->lock);
@@ -772,8 +773,13 @@ static irqreturn_t phy_interrupt(int irq, void *phy_dat)
if (phydev->drv->did_interrupt && !phydev->drv->did_interrupt(phydev))
return IRQ_NONE;
- /* reschedule state queue work to run as soon as possible */
- phy_trigger_machine(phydev);
+ if (phydev->drv->handle_interrupt) {
+ if (phydev->drv->handle_interrupt(phydev))
+ goto phy_err;
+ } else {
+ /* reschedule state queue work to run as soon as possible */
+ phy_trigger_machine(phydev);
+ }
if (phy_clear_interrupt(phydev))
goto phy_err;
@@ -799,10 +805,10 @@ static int phy_enable_interrupts(struct phy_device *phydev)
}
/**
- * phy_request_interrupt - request interrupt for a PHY device
+ * phy_request_interrupt - request and enable interrupt for a PHY device
* @phydev: target phy_device struct
*
- * Description: Request the interrupt for the given PHY.
+ * Description: Request and enable the interrupt for the given PHY.
* If this fails, then we set irq to PHY_POLL.
* This should only be called with a valid IRQ number.
*/
@@ -817,11 +823,31 @@ void phy_request_interrupt(struct phy_device *phydev)
phydev_warn(phydev, "Error %d requesting IRQ %d, falling back to polling\n",
err, phydev->irq);
phydev->irq = PHY_POLL;
+ } else {
+ if (phy_enable_interrupts(phydev)) {
+ phydev_warn(phydev, "Can't enable interrupt, falling back to polling\n");
+ phy_free_interrupt(phydev);
+ phydev->irq = PHY_POLL;
+ }
}
}
EXPORT_SYMBOL(phy_request_interrupt);
/**
+ * phy_free_interrupt - disable and free interrupt for a PHY device
+ * @phydev: target phy_device struct
+ *
+ * Description: Disable and free the interrupt for the given PHY.
+ * This should only be called with a valid IRQ number.
+ */
+void phy_free_interrupt(struct phy_device *phydev)
+{
+ phy_disable_interrupts(phydev);
+ free_irq(phydev->irq, phydev);
+}
+EXPORT_SYMBOL(phy_free_interrupt);
+
+/**
* phy_stop - Bring down the PHY link, and stop checking the status
* @phydev: target phy_device struct
*/
@@ -835,9 +861,6 @@ void phy_stop(struct phy_device *phydev)
mutex_lock(&phydev->lock);
- if (phy_interrupt_is_valid(phydev))
- phy_disable_interrupts(phydev);
-
phydev->state = PHY_HALTED;
mutex_unlock(&phydev->lock);
@@ -864,8 +887,6 @@ EXPORT_SYMBOL(phy_stop);
*/
void phy_start(struct phy_device *phydev)
{
- int err;
-
mutex_lock(&phydev->lock);
if (phydev->state != PHY_READY && phydev->state != PHY_HALTED) {
@@ -877,13 +898,6 @@ void phy_start(struct phy_device *phydev)
/* if phy was suspended, bring the physical link up again */
__phy_resume(phydev);
- /* make sure interrupts are enabled for the PHY */
- if (phy_interrupt_is_valid(phydev)) {
- err = phy_enable_interrupts(phydev);
- if (err < 0)
- goto out;
- }
-
phydev->state = PHY_UP;
phy_start_machine(phydev);
@@ -921,20 +935,6 @@ void phy_state_machine(struct work_struct *work)
case PHY_RUNNING:
err = phy_check_link_status(phydev);
break;
- case PHY_FORCING:
- err = genphy_update_link(phydev);
- if (err)
- break;
-
- if (phydev->link) {
- phydev->state = PHY_RUNNING;
- phy_link_up(phydev);
- } else {
- if (0 == phydev->link_timeout--)
- needs_aneg = true;
- phy_link_down(phydev, false);
- }
- break;
case PHY_HALTED:
if (phydev->link) {
phydev->link = 0;
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index dcc93a873174..6b5cb87f3866 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -56,19 +56,19 @@ EXPORT_SYMBOL_GPL(phy_10gbit_features);
__ETHTOOL_DECLARE_LINK_MODE_MASK(phy_10gbit_fec_features) __ro_after_init;
EXPORT_SYMBOL_GPL(phy_10gbit_fec_features);
-static const int phy_basic_ports_array[] = {
+const int phy_basic_ports_array[3] = {
ETHTOOL_LINK_MODE_Autoneg_BIT,
ETHTOOL_LINK_MODE_TP_BIT,
ETHTOOL_LINK_MODE_MII_BIT,
};
EXPORT_SYMBOL_GPL(phy_basic_ports_array);
-static const int phy_fibre_port_array[] = {
+const int phy_fibre_port_array[1] = {
ETHTOOL_LINK_MODE_FIBRE_BIT,
};
EXPORT_SYMBOL_GPL(phy_fibre_port_array);
-static const int phy_all_ports_features_array[] = {
+const int phy_all_ports_features_array[7] = {
ETHTOOL_LINK_MODE_Autoneg_BIT,
ETHTOOL_LINK_MODE_TP_BIT,
ETHTOOL_LINK_MODE_MII_BIT,
@@ -89,7 +89,7 @@ EXPORT_SYMBOL_GPL(phy_10_100_features_array);
const int phy_basic_t1_features_array[2] = {
ETHTOOL_LINK_MODE_TP_BIT,
- ETHTOOL_LINK_MODE_100baseT_Full_BIT,
+ ETHTOOL_LINK_MODE_100baseT1_Full_BIT,
};
EXPORT_SYMBOL_GPL(phy_basic_t1_features_array);
@@ -948,6 +948,9 @@ int phy_connect_direct(struct net_device *dev, struct phy_device *phydev,
{
int rc;
+ if (!dev)
+ return -EINVAL;
+
rc = phy_attach_direct(dev, phydev, phydev->dev_flags, interface);
if (rc)
return rc;
@@ -1013,7 +1016,7 @@ void phy_disconnect(struct phy_device *phydev)
phy_stop(phydev);
if (phy_interrupt_is_valid(phydev))
- free_irq(phydev->irq, phydev);
+ phy_free_interrupt(phydev);
phydev->adjust_link = NULL;
@@ -1133,6 +1136,44 @@ void phy_attached_print(struct phy_device *phydev, const char *fmt, ...)
}
EXPORT_SYMBOL(phy_attached_print);
+static void phy_sysfs_create_links(struct phy_device *phydev)
+{
+ struct net_device *dev = phydev->attached_dev;
+ int err;
+
+ if (!dev)
+ return;
+
+ err = sysfs_create_link(&phydev->mdio.dev.kobj, &dev->dev.kobj,
+ "attached_dev");
+ if (err)
+ return;
+
+ err = sysfs_create_link_nowarn(&dev->dev.kobj,
+ &phydev->mdio.dev.kobj,
+ "phydev");
+ if (err) {
+ dev_err(&dev->dev, "could not add device link to %s err %d\n",
+ kobject_name(&phydev->mdio.dev.kobj),
+ err);
+ /* non-fatal - some net drivers can use one netdevice
+ * with more then one phy
+ */
+ }
+
+ phydev->sysfs_links = true;
+}
+
+static ssize_t
+phy_standalone_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct phy_device *phydev = to_phy_device(dev);
+
+ return sprintf(buf, "%d\n", !phydev->attached_dev);
+}
+static DEVICE_ATTR_RO(phy_standalone);
+
/**
* phy_attach_direct - attach a network device to a given PHY device pointer
* @dev: network device to attach
@@ -1151,9 +1192,9 @@ EXPORT_SYMBOL(phy_attached_print);
int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
u32 flags, phy_interface_t interface)
{
- struct module *ndev_owner = dev->dev.parent->driver->owner;
struct mii_bus *bus = phydev->mdio.bus;
struct device *d = &phydev->mdio.dev;
+ struct module *ndev_owner = NULL;
bool using_genphy = false;
int err;
@@ -1162,8 +1203,10 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
* our own module->refcnt here, otherwise we would not be able to
* unload later on.
*/
+ if (dev)
+ ndev_owner = dev->dev.parent->driver->owner;
if (ndev_owner != bus->owner && !try_module_get(bus->owner)) {
- dev_err(&dev->dev, "failed to get the bus module\n");
+ phydev_err(phydev, "failed to get the bus module\n");
return -EIO;
}
@@ -1182,7 +1225,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
}
if (!try_module_get(d->driver->owner)) {
- dev_err(&dev->dev, "failed to get the device driver module\n");
+ phydev_err(phydev, "failed to get the device driver module\n");
err = -EIO;
goto error_put_device;
}
@@ -1203,8 +1246,10 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
}
phydev->phy_link_change = phy_link_change;
- phydev->attached_dev = dev;
- dev->phydev = phydev;
+ if (dev) {
+ phydev->attached_dev = dev;
+ dev->phydev = phydev;
+ }
/* Some Ethernet drivers try to connect to a PHY device before
* calling register_netdevice() -> netdev_register_kobject() and
@@ -1216,22 +1261,13 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
*/
phydev->sysfs_links = false;
- err = sysfs_create_link(&phydev->mdio.dev.kobj, &dev->dev.kobj,
- "attached_dev");
- if (!err) {
- err = sysfs_create_link_nowarn(&dev->dev.kobj,
- &phydev->mdio.dev.kobj,
- "phydev");
- if (err) {
- dev_err(&dev->dev, "could not add device link to %s err %d\n",
- kobject_name(&phydev->mdio.dev.kobj),
- err);
- /* non-fatal - some net drivers can use one netdevice
- * with more then one phy
- */
- }
+ phy_sysfs_create_links(phydev);
- phydev->sysfs_links = true;
+ if (!phydev->attached_dev) {
+ err = sysfs_create_file(&phydev->mdio.dev.kobj,
+ &dev_attr_phy_standalone.attr);
+ if (err)
+ phydev_err(phydev, "error creating 'phy_standalone' sysfs entry\n");
}
phydev->dev_flags = flags;
@@ -1243,7 +1279,8 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
/* Initial carrier state is off as the phy is about to be
* (re)initialized.
*/
- netif_carrier_off(phydev->attached_dev);
+ if (dev)
+ netif_carrier_off(phydev->attached_dev);
/* Do initial configuration here, now that
* we have certain key parameters
@@ -1290,6 +1327,9 @@ struct phy_device *phy_attach(struct net_device *dev, const char *bus_id,
struct device *d;
int rc;
+ if (!dev)
+ return ERR_PTR(-EINVAL);
+
/* Search the list of PHY devices on the mdio bus for the
* PHY with the requested name
*/
@@ -1349,16 +1389,24 @@ EXPORT_SYMBOL_GPL(phy_driver_is_genphy_10g);
void phy_detach(struct phy_device *phydev)
{
struct net_device *dev = phydev->attached_dev;
- struct module *ndev_owner = dev->dev.parent->driver->owner;
+ struct module *ndev_owner = NULL;
struct mii_bus *bus;
if (phydev->sysfs_links) {
- sysfs_remove_link(&dev->dev.kobj, "phydev");
+ if (dev)
+ sysfs_remove_link(&dev->dev.kobj, "phydev");
sysfs_remove_link(&phydev->mdio.dev.kobj, "attached_dev");
}
+
+ if (!phydev->attached_dev)
+ sysfs_remove_file(&phydev->mdio.dev.kobj,
+ &dev_attr_phy_standalone.attr);
+
phy_suspend(phydev);
- phydev->attached_dev->phydev = NULL;
- phydev->attached_dev = NULL;
+ if (dev) {
+ phydev->attached_dev->phydev = NULL;
+ phydev->attached_dev = NULL;
+ }
phydev->phylink = NULL;
phy_led_triggers_unregister(phydev);
@@ -1381,6 +1429,8 @@ void phy_detach(struct phy_device *phydev)
bus = phydev->mdio.bus;
put_device(&phydev->mdio.dev);
+ if (dev)
+ ndev_owner = dev->dev.parent->driver->owner;
if (ndev_owner != bus->owner)
module_put(bus->owner);
@@ -1880,6 +1930,9 @@ int genphy_config_init(struct phy_device *phydev)
if (val & ESTATUS_1000_THALF)
linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
features);
+ if (val & ESTATUS_1000_XFULL)
+ linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
+ features);
}
linkmode_and(phydev->supported, phydev->supported, features);
@@ -1931,6 +1984,8 @@ int genphy_read_abilities(struct phy_device *phydev)
phydev->supported, val & ESTATUS_1000_TFULL);
linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
phydev->supported, val & ESTATUS_1000_THALF);
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
+ phydev->supported, val & ESTATUS_1000_XFULL);
}
return 0;
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index 4c0616ba314d..5d0af041b8f9 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -41,6 +41,9 @@ struct phylink {
/* private: */
struct net_device *netdev;
const struct phylink_mac_ops *ops;
+ struct phylink_config *config;
+ struct device *dev;
+ unsigned int old_link_state:1;
unsigned long phylink_disable_state; /* bitmask of disables */
struct phy_device *phydev;
@@ -56,6 +59,7 @@ struct phylink {
phy_interface_t cur_interface;
struct gpio_desc *link_gpio;
+ unsigned int link_irq;
struct timer_list link_poll;
void (*get_fixed_state)(struct net_device *dev,
struct phylink_link_state *s);
@@ -69,6 +73,23 @@ struct phylink {
struct sfp_bus *sfp_bus;
};
+#define phylink_printk(level, pl, fmt, ...) \
+ do { \
+ if ((pl)->config->type == PHYLINK_NETDEV) \
+ netdev_printk(level, (pl)->netdev, fmt, ##__VA_ARGS__); \
+ else if ((pl)->config->type == PHYLINK_DEV) \
+ dev_printk(level, (pl)->dev, fmt, ##__VA_ARGS__); \
+ } while (0)
+
+#define phylink_err(pl, fmt, ...) \
+ phylink_printk(KERN_ERR, pl, fmt, ##__VA_ARGS__)
+#define phylink_warn(pl, fmt, ...) \
+ phylink_printk(KERN_WARNING, pl, fmt, ##__VA_ARGS__)
+#define phylink_info(pl, fmt, ...) \
+ phylink_printk(KERN_INFO, pl, fmt, ##__VA_ARGS__)
+#define phylink_dbg(pl, fmt, ...) \
+ phylink_printk(KERN_DEBUG, pl, fmt, ##__VA_ARGS__)
+
/**
* phylink_set_port_modes() - set the port type modes in the ethtool mask
* @mask: ethtool link mode mask
@@ -115,7 +136,7 @@ static const char *phylink_an_mode_str(unsigned int mode)
static int phylink_validate(struct phylink *pl, unsigned long *supported,
struct phylink_link_state *state)
{
- pl->ops->validate(pl->netdev, supported, state);
+ pl->ops->validate(pl->config, supported, state);
return phylink_is_empty_linkmode(supported) ? -EINVAL : 0;
}
@@ -165,7 +186,7 @@ static int phylink_parse_fixedlink(struct phylink *pl,
ret = fwnode_property_read_u32_array(fwnode, "fixed-link",
NULL, 0);
if (ret != ARRAY_SIZE(prop)) {
- netdev_err(pl->netdev, "broken fixed-link?\n");
+ phylink_err(pl, "broken fixed-link?\n");
return -EINVAL;
}
@@ -184,8 +205,8 @@ static int phylink_parse_fixedlink(struct phylink *pl,
if (pl->link_config.speed > SPEED_1000 &&
pl->link_config.duplex != DUPLEX_FULL)
- netdev_warn(pl->netdev, "fixed link specifies half duplex for %dMbps link?\n",
- pl->link_config.speed);
+ phylink_warn(pl, "fixed link specifies half duplex for %dMbps link?\n",
+ pl->link_config.speed);
bitmap_fill(pl->supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
linkmode_copy(pl->link_config.advertising, pl->supported);
@@ -198,9 +219,9 @@ static int phylink_parse_fixedlink(struct phylink *pl,
if (s) {
__set_bit(s->bit, pl->supported);
} else {
- netdev_warn(pl->netdev, "fixed link %s duplex %dMbps not recognised\n",
- pl->link_config.duplex == DUPLEX_FULL ? "full" : "half",
- pl->link_config.speed);
+ phylink_warn(pl, "fixed link %s duplex %dMbps not recognised\n",
+ pl->link_config.duplex == DUPLEX_FULL ? "full" : "half",
+ pl->link_config.speed);
}
linkmode_and(pl->link_config.advertising, pl->link_config.advertising,
@@ -225,8 +246,8 @@ static int phylink_parse_mode(struct phylink *pl, struct fwnode_handle *fwnode)
if (fwnode_property_read_string(fwnode, "managed", &managed) == 0 &&
strcmp(managed, "in-band-status") == 0) {
if (pl->link_an_mode == MLO_AN_FIXED) {
- netdev_err(pl->netdev,
- "can't use both fixed-link and in-band-status\n");
+ phylink_err(pl,
+ "can't use both fixed-link and in-band-status\n");
return -EINVAL;
}
@@ -273,17 +294,17 @@ static int phylink_parse_mode(struct phylink *pl, struct fwnode_handle *fwnode)
break;
default:
- netdev_err(pl->netdev,
- "incorrect link mode %s for in-band status\n",
- phy_modes(pl->link_config.interface));
+ phylink_err(pl,
+ "incorrect link mode %s for in-band status\n",
+ phy_modes(pl->link_config.interface));
return -EINVAL;
}
linkmode_copy(pl->link_config.advertising, pl->supported);
if (phylink_validate(pl, pl->supported, &pl->link_config)) {
- netdev_err(pl->netdev,
- "failed to validate link configuration for in-band status\n");
+ phylink_err(pl,
+ "failed to validate link configuration for in-band status\n");
return -EINVAL;
}
}
@@ -294,16 +315,16 @@ static int phylink_parse_mode(struct phylink *pl, struct fwnode_handle *fwnode)
static void phylink_mac_config(struct phylink *pl,
const struct phylink_link_state *state)
{
- netdev_dbg(pl->netdev,
- "%s: mode=%s/%s/%s/%s adv=%*pb pause=%02x link=%u an=%u\n",
- __func__, phylink_an_mode_str(pl->link_an_mode),
- phy_modes(state->interface),
- phy_speed_to_str(state->speed),
- phy_duplex_to_str(state->duplex),
- __ETHTOOL_LINK_MODE_MASK_NBITS, state->advertising,
- state->pause, state->link, state->an_enabled);
-
- pl->ops->mac_config(pl->netdev, pl->link_an_mode, state);
+ phylink_dbg(pl,
+ "%s: mode=%s/%s/%s/%s adv=%*pb pause=%02x link=%u an=%u\n",
+ __func__, phylink_an_mode_str(pl->link_an_mode),
+ phy_modes(state->interface),
+ phy_speed_to_str(state->speed),
+ phy_duplex_to_str(state->duplex),
+ __ETHTOOL_LINK_MODE_MASK_NBITS, state->advertising,
+ state->pause, state->link, state->an_enabled);
+
+ pl->ops->mac_config(pl->config, pl->link_an_mode, state);
}
static void phylink_mac_config_up(struct phylink *pl,
@@ -317,12 +338,11 @@ static void phylink_mac_an_restart(struct phylink *pl)
{
if (pl->link_config.an_enabled &&
phy_interface_mode_is_8023z(pl->link_config.interface))
- pl->ops->mac_an_restart(pl->netdev);
+ pl->ops->mac_an_restart(pl->config);
}
static int phylink_get_mac_state(struct phylink *pl, struct phylink_link_state *state)
{
- struct net_device *ndev = pl->netdev;
linkmode_copy(state->advertising, pl->link_config.advertising);
linkmode_zero(state->lp_advertising);
@@ -334,7 +354,7 @@ static int phylink_get_mac_state(struct phylink *pl, struct phylink_link_state *
state->an_complete = 0;
state->link = 1;
- return pl->ops->mac_link_state(ndev, state);
+ return pl->ops->mac_link_state(pl->config, state);
}
/* The fixed state is... fixed except for the link state,
@@ -399,11 +419,43 @@ static const char *phylink_pause_to_str(int pause)
}
}
+static void phylink_mac_link_up(struct phylink *pl,
+ struct phylink_link_state link_state)
+{
+ struct net_device *ndev = pl->netdev;
+
+ pl->cur_interface = link_state.interface;
+ pl->ops->mac_link_up(pl->config, pl->link_an_mode,
+ pl->phy_state.interface,
+ pl->phydev);
+
+ if (ndev)
+ netif_carrier_on(ndev);
+
+ phylink_info(pl,
+ "Link is Up - %s/%s - flow control %s\n",
+ phy_speed_to_str(link_state.speed),
+ phy_duplex_to_str(link_state.duplex),
+ phylink_pause_to_str(link_state.pause));
+}
+
+static void phylink_mac_link_down(struct phylink *pl)
+{
+ struct net_device *ndev = pl->netdev;
+
+ if (ndev)
+ netif_carrier_off(ndev);
+ pl->ops->mac_link_down(pl->config, pl->link_an_mode,
+ pl->cur_interface);
+ phylink_info(pl, "Link is Down\n");
+}
+
static void phylink_resolve(struct work_struct *w)
{
struct phylink *pl = container_of(w, struct phylink, resolve);
struct phylink_link_state link_state;
struct net_device *ndev = pl->netdev;
+ int link_changed;
mutex_lock(&pl->state_mutex);
if (pl->phylink_disable_state) {
@@ -446,25 +498,17 @@ static void phylink_resolve(struct work_struct *w)
}
}
- if (link_state.link != netif_carrier_ok(ndev)) {
- if (!link_state.link) {
- netif_carrier_off(ndev);
- pl->ops->mac_link_down(ndev, pl->link_an_mode,
- pl->cur_interface);
- netdev_info(ndev, "Link is Down\n");
- } else {
- pl->cur_interface = link_state.interface;
- pl->ops->mac_link_up(ndev, pl->link_an_mode,
- pl->cur_interface, pl->phydev);
-
- netif_carrier_on(ndev);
-
- netdev_info(ndev,
- "Link is Up - %s/%s - flow control %s\n",
- phy_speed_to_str(link_state.speed),
- phy_duplex_to_str(link_state.duplex),
- phylink_pause_to_str(link_state.pause));
- }
+ if (pl->netdev)
+ link_changed = (link_state.link != netif_carrier_ok(ndev));
+ else
+ link_changed = (link_state.link != pl->old_link_state);
+
+ if (link_changed) {
+ pl->old_link_state = link_state.link;
+ if (!link_state.link)
+ phylink_mac_link_down(pl);
+ else
+ phylink_mac_link_up(pl, link_state);
}
if (!link_state.link && pl->mac_link_dropped) {
pl->mac_link_dropped = false;
@@ -516,13 +560,12 @@ static int phylink_register_sfp(struct phylink *pl,
if (ret == -ENOENT)
return 0;
- netdev_err(pl->netdev, "unable to parse \"sfp\" node: %d\n",
- ret);
+ phylink_err(pl, "unable to parse \"sfp\" node: %d\n",
+ ret);
return ret;
}
- pl->sfp_bus = sfp_register_upstream(ref.fwnode, pl->netdev, pl,
- &sfp_phylink_ops);
+ pl->sfp_bus = sfp_register_upstream(ref.fwnode, pl, &sfp_phylink_ops);
if (!pl->sfp_bus)
return -ENOMEM;
@@ -543,7 +586,7 @@ static int phylink_register_sfp(struct phylink *pl,
* Returns a pointer to a &struct phylink, or an error-pointer value. Users
* must use IS_ERR() to check for errors from this function.
*/
-struct phylink *phylink_create(struct net_device *ndev,
+struct phylink *phylink_create(struct phylink_config *config,
struct fwnode_handle *fwnode,
phy_interface_t iface,
const struct phylink_mac_ops *ops)
@@ -557,7 +600,17 @@ struct phylink *phylink_create(struct net_device *ndev,
mutex_init(&pl->state_mutex);
INIT_WORK(&pl->resolve, phylink_resolve);
- pl->netdev = ndev;
+
+ pl->config = config;
+ if (config->type == PHYLINK_NETDEV) {
+ pl->netdev = to_net_dev(config->dev);
+ } else if (config->type == PHYLINK_DEV) {
+ pl->dev = config->dev;
+ } else {
+ kfree(pl);
+ return ERR_PTR(-EINVAL);
+ }
+
pl->phy_state.interface = iface;
pl->link_interface = iface;
if (iface == PHY_INTERFACE_MODE_MOCA)
@@ -612,7 +665,7 @@ void phylink_destroy(struct phylink *pl)
{
if (pl->sfp_bus)
sfp_unregister_upstream(pl->sfp_bus);
- if (!IS_ERR_OR_NULL(pl->link_gpio))
+ if (pl->link_gpio)
gpiod_put(pl->link_gpio);
cancel_work_sync(&pl->resolve);
@@ -639,10 +692,10 @@ static void phylink_phy_change(struct phy_device *phydev, bool up,
phylink_run_resolve(pl);
- netdev_dbg(pl->netdev, "phy link %s %s/%s/%s\n", up ? "up" : "down",
- phy_modes(phydev->interface),
- phy_speed_to_str(phydev->speed),
- phy_duplex_to_str(phydev->duplex));
+ phylink_dbg(pl, "phy link %s %s/%s/%s\n", up ? "up" : "down",
+ phy_modes(phydev->interface),
+ phy_speed_to_str(phydev->speed),
+ phy_duplex_to_str(phydev->duplex));
}
static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy)
@@ -675,9 +728,9 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy)
phy->phylink = pl;
phy->phy_link_change = phylink_phy_change;
- netdev_info(pl->netdev,
- "PHY [%s] driver [%s]\n", dev_name(&phy->mdio.dev),
- phy->drv->name);
+ phylink_info(pl,
+ "PHY [%s] driver [%s]\n", dev_name(&phy->mdio.dev),
+ phy->drv->name);
mutex_lock(&phy->lock);
mutex_lock(&pl->state_mutex);
@@ -690,10 +743,10 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy)
mutex_unlock(&pl->state_mutex);
mutex_unlock(&phy->lock);
- netdev_dbg(pl->netdev,
- "phy: setting supported %*pb advertising %*pb\n",
- __ETHTOOL_LINK_MODE_MASK_NBITS, pl->supported,
- __ETHTOOL_LINK_MODE_MASK_NBITS, phy->advertising);
+ phylink_dbg(pl,
+ "phy: setting supported %*pb advertising %*pb\n",
+ __ETHTOOL_LINK_MODE_MASK_NBITS, pl->supported,
+ __ETHTOOL_LINK_MODE_MASK_NBITS, phy->advertising);
if (phy_interrupt_is_valid(phy))
phy_request_interrupt(phy);
@@ -871,10 +924,19 @@ void phylink_mac_change(struct phylink *pl, bool up)
if (!up)
pl->mac_link_dropped = true;
phylink_run_resolve(pl);
- netdev_dbg(pl->netdev, "mac link %s\n", up ? "up" : "down");
+ phylink_dbg(pl, "mac link %s\n", up ? "up" : "down");
}
EXPORT_SYMBOL_GPL(phylink_mac_change);
+static irqreturn_t phylink_link_handler(int irq, void *data)
+{
+ struct phylink *pl = data;
+
+ phylink_run_resolve(pl);
+
+ return IRQ_HANDLED;
+}
+
/**
* phylink_start() - start a phylink instance
* @pl: a pointer to a &struct phylink returned from phylink_create()
@@ -887,12 +949,13 @@ void phylink_start(struct phylink *pl)
{
ASSERT_RTNL();
- netdev_info(pl->netdev, "configuring for %s/%s link mode\n",
- phylink_an_mode_str(pl->link_an_mode),
- phy_modes(pl->link_config.interface));
+ phylink_info(pl, "configuring for %s/%s link mode\n",
+ phylink_an_mode_str(pl->link_an_mode),
+ phy_modes(pl->link_config.interface));
/* Always set the carrier off */
- netif_carrier_off(pl->netdev);
+ if (pl->netdev)
+ netif_carrier_off(pl->netdev);
/* Apply the link configuration to the MAC when starting. This allows
* a fixed-link to start with the correct parameters, and also
@@ -910,7 +973,22 @@ void phylink_start(struct phylink *pl)
clear_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state);
phylink_run_resolve(pl);
- if (pl->link_an_mode == MLO_AN_FIXED && !IS_ERR(pl->link_gpio))
+ if (pl->link_an_mode == MLO_AN_FIXED && pl->link_gpio) {
+ int irq = gpiod_to_irq(pl->link_gpio);
+
+ if (irq > 0) {
+ if (!request_irq(irq, phylink_link_handler,
+ IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING,
+ "netdev link", pl))
+ pl->link_irq = irq;
+ else
+ irq = 0;
+ }
+ if (irq <= 0)
+ mod_timer(&pl->link_poll, jiffies + HZ);
+ }
+ if (pl->link_an_mode == MLO_AN_FIXED && pl->get_fixed_state)
mod_timer(&pl->link_poll, jiffies + HZ);
if (pl->sfp_bus)
sfp_upstream_start(pl->sfp_bus);
@@ -936,8 +1014,11 @@ void phylink_stop(struct phylink *pl)
phy_stop(pl->phydev);
if (pl->sfp_bus)
sfp_upstream_stop(pl->sfp_bus);
- if (pl->link_an_mode == MLO_AN_FIXED && !IS_ERR(pl->link_gpio))
- del_timer_sync(&pl->link_poll);
+ del_timer_sync(&pl->link_poll);
+ if (pl->link_irq) {
+ free_irq(pl->link_irq, pl);
+ pl->link_irq = 0;
+ }
phylink_run_resolve_and_disable(pl, PHYLINK_DISABLE_STOPPED);
}
@@ -1239,7 +1320,8 @@ int phylink_ethtool_set_pauseparam(struct phylink *pl,
switch (pl->link_an_mode) {
case MLO_AN_PHY:
/* Silently mark the carrier down, and then trigger a resolve */
- netif_carrier_off(pl->netdev);
+ if (pl->netdev)
+ netif_carrier_off(pl->netdev);
phylink_run_resolve(pl);
break;
@@ -1342,8 +1424,8 @@ EXPORT_SYMBOL_GPL(phylink_ethtool_set_eee);
*
* FIXME: should deal with negotiation state too.
*/
-static int phylink_mii_emul_read(struct net_device *ndev, unsigned int reg,
- struct phylink_link_state *state, bool aneg)
+static int phylink_mii_emul_read(unsigned int reg,
+ struct phylink_link_state *state)
{
struct fixed_phy_status fs;
int val;
@@ -1358,8 +1440,6 @@ static int phylink_mii_emul_read(struct net_device *ndev, unsigned int reg,
if (reg == MII_BMSR) {
if (!state->an_complete)
val &= ~BMSR_ANEGCOMPLETE;
- if (!aneg)
- val &= ~BMSR_ANEGCAPABLE;
}
return val;
}
@@ -1455,8 +1535,7 @@ static int phylink_mii_read(struct phylink *pl, unsigned int phy_id,
case MLO_AN_FIXED:
if (phy_id == 0) {
phylink_get_fixed_state(pl, &state);
- val = phylink_mii_emul_read(pl->netdev, reg, &state,
- true);
+ val = phylink_mii_emul_read(reg, &state);
}
break;
@@ -1469,8 +1548,7 @@ static int phylink_mii_read(struct phylink *pl, unsigned int phy_id,
if (val < 0)
return val;
- val = phylink_mii_emul_read(pl->netdev, reg, &state,
- true);
+ val = phylink_mii_emul_read(reg, &state);
}
break;
}
@@ -1573,6 +1651,20 @@ int phylink_mii_ioctl(struct phylink *pl, struct ifreq *ifr, int cmd)
}
EXPORT_SYMBOL_GPL(phylink_mii_ioctl);
+static void phylink_sfp_attach(void *upstream, struct sfp_bus *bus)
+{
+ struct phylink *pl = upstream;
+
+ pl->netdev->sfp_bus = bus;
+}
+
+static void phylink_sfp_detach(void *upstream, struct sfp_bus *bus)
+{
+ struct phylink *pl = upstream;
+
+ pl->netdev->sfp_bus = NULL;
+}
+
static int phylink_sfp_module_insert(void *upstream,
const struct sfp_eeprom_id *id)
{
@@ -1601,8 +1693,8 @@ static int phylink_sfp_module_insert(void *upstream,
/* Ignore errors if we're expecting a PHY to attach later */
ret = phylink_validate(pl, support, &config);
if (ret) {
- netdev_err(pl->netdev, "validation with support %*pb failed: %d\n",
- __ETHTOOL_LINK_MODE_MASK_NBITS, support, ret);
+ phylink_err(pl, "validation with support %*pb failed: %d\n",
+ __ETHTOOL_LINK_MODE_MASK_NBITS, support, ret);
return ret;
}
@@ -1610,26 +1702,26 @@ static int phylink_sfp_module_insert(void *upstream,
iface = sfp_select_interface(pl->sfp_bus, id, config.advertising);
if (iface == PHY_INTERFACE_MODE_NA) {
- netdev_err(pl->netdev,
- "selection of interface failed, advertisement %*pb\n",
- __ETHTOOL_LINK_MODE_MASK_NBITS, config.advertising);
+ phylink_err(pl,
+ "selection of interface failed, advertisement %*pb\n",
+ __ETHTOOL_LINK_MODE_MASK_NBITS, config.advertising);
return -EINVAL;
}
config.interface = iface;
ret = phylink_validate(pl, support1, &config);
if (ret) {
- netdev_err(pl->netdev, "validation of %s/%s with support %*pb failed: %d\n",
- phylink_an_mode_str(MLO_AN_INBAND),
- phy_modes(config.interface),
- __ETHTOOL_LINK_MODE_MASK_NBITS, support, ret);
+ phylink_err(pl, "validation of %s/%s with support %*pb failed: %d\n",
+ phylink_an_mode_str(MLO_AN_INBAND),
+ phy_modes(config.interface),
+ __ETHTOOL_LINK_MODE_MASK_NBITS, support, ret);
return ret;
}
- netdev_dbg(pl->netdev, "requesting link mode %s/%s with support %*pb\n",
- phylink_an_mode_str(MLO_AN_INBAND),
- phy_modes(config.interface),
- __ETHTOOL_LINK_MODE_MASK_NBITS, support);
+ phylink_dbg(pl, "requesting link mode %s/%s with support %*pb\n",
+ phylink_an_mode_str(MLO_AN_INBAND),
+ phy_modes(config.interface),
+ __ETHTOOL_LINK_MODE_MASK_NBITS, support);
if (phy_interface_mode_is_8023z(iface) && pl->phydev)
return -EINVAL;
@@ -1648,9 +1740,9 @@ static int phylink_sfp_module_insert(void *upstream,
changed = true;
- netdev_info(pl->netdev, "switched to %s/%s link mode\n",
- phylink_an_mode_str(MLO_AN_INBAND),
- phy_modes(config.interface));
+ phylink_info(pl, "switched to %s/%s link mode\n",
+ phylink_an_mode_str(MLO_AN_INBAND),
+ phy_modes(config.interface));
}
pl->link_port = port;
@@ -1694,6 +1786,8 @@ static void phylink_sfp_disconnect_phy(void *upstream)
}
static const struct sfp_upstream_ops sfp_phylink_ops = {
+ .attach = phylink_sfp_attach,
+ .detach = phylink_sfp_detach,
.module_insert = phylink_sfp_module_insert,
.link_up = phylink_sfp_link_up,
.link_down = phylink_sfp_link_down,
diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c
index e9c187946cca..b23fc41896ef 100644
--- a/drivers/net/phy/sfp-bus.c
+++ b/drivers/net/phy/sfp-bus.c
@@ -24,7 +24,6 @@ struct sfp_bus {
const struct sfp_upstream_ops *upstream_ops;
void *upstream;
- struct net_device *netdev;
struct phy_device *phydev;
bool registered;
@@ -351,7 +350,7 @@ static int sfp_register_bus(struct sfp_bus *bus)
bus->socket_ops->attach(bus->sfp);
if (bus->started)
bus->socket_ops->start(bus->sfp);
- bus->netdev->sfp_bus = bus;
+ bus->upstream_ops->attach(bus->upstream, bus);
bus->registered = true;
return 0;
}
@@ -360,8 +359,8 @@ static void sfp_unregister_bus(struct sfp_bus *bus)
{
const struct sfp_upstream_ops *ops = bus->upstream_ops;
- bus->netdev->sfp_bus = NULL;
if (bus->registered) {
+ bus->upstream_ops->detach(bus->upstream, bus);
if (bus->started)
bus->socket_ops->stop(bus->sfp);
bus->socket_ops->detach(bus->sfp);
@@ -443,13 +442,11 @@ static void sfp_upstream_clear(struct sfp_bus *bus)
{
bus->upstream_ops = NULL;
bus->upstream = NULL;
- bus->netdev = NULL;
}
/**
* sfp_register_upstream() - Register the neighbouring device
* @fwnode: firmware node for the SFP bus
- * @ndev: network device associated with the interface
* @upstream: the upstream private data
* @ops: the upstream's &struct sfp_upstream_ops
*
@@ -460,7 +457,7 @@ static void sfp_upstream_clear(struct sfp_bus *bus)
* On error, returns %NULL.
*/
struct sfp_bus *sfp_register_upstream(struct fwnode_handle *fwnode,
- struct net_device *ndev, void *upstream,
+ void *upstream,
const struct sfp_upstream_ops *ops)
{
struct sfp_bus *bus = sfp_bus_get(fwnode);
@@ -470,7 +467,6 @@ struct sfp_bus *sfp_register_upstream(struct fwnode_handle *fwnode,
rtnl_lock();
bus->upstream_ops = ops;
bus->upstream = upstream;
- bus->netdev = ndev;
if (bus->sfp) {
ret = sfp_register_bus(bus);
@@ -592,7 +588,7 @@ struct sfp_bus *sfp_register_socket(struct device *dev, struct sfp *sfp,
bus->sfp = sfp;
bus->socket_ops = ops;
- if (bus->netdev) {
+ if (bus->upstream_ops) {
ret = sfp_register_bus(bus);
if (ret)
sfp_socket_clear(bus);
@@ -612,7 +608,7 @@ EXPORT_SYMBOL_GPL(sfp_register_socket);
void sfp_unregister_socket(struct sfp_bus *bus)
{
rtnl_lock();
- if (bus->netdev)
+ if (bus->upstream_ops)
sfp_unregister_bus(bus);
sfp_socket_clear(bus);
rtnl_unlock();
diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
index 71812be0ac64..2d816aadea79 100644
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -1,4 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
+#include <linux/acpi.h>
#include <linux/ctype.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
@@ -184,12 +185,14 @@ struct sfp {
int (*write)(struct sfp *, bool, u8, void *, size_t);
struct gpio_desc *gpio[GPIO_MAX];
+ int gpio_irq[GPIO_MAX];
bool attached;
+ struct mutex st_mutex; /* Protects state */
unsigned int state;
struct delayed_work poll;
struct delayed_work timeout;
- struct mutex sm_mutex;
+ struct mutex sm_mutex; /* Protects state machine */
unsigned char sm_mod_state;
unsigned char sm_dev_state;
unsigned short sm_state;
@@ -1719,6 +1722,7 @@ static void sfp_check_state(struct sfp *sfp)
{
unsigned int state, i, changed;
+ mutex_lock(&sfp->st_mutex);
state = sfp_get_state(sfp);
changed = state ^ sfp->state;
changed &= SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT;
@@ -1744,6 +1748,7 @@ static void sfp_check_state(struct sfp *sfp)
sfp_sm_event(sfp, state & SFP_F_LOS ?
SFP_E_LOS_HIGH : SFP_E_LOS_LOW);
rtnl_unlock();
+ mutex_unlock(&sfp->st_mutex);
}
static irqreturn_t sfp_irq(int irq, void *data)
@@ -1774,6 +1779,7 @@ static struct sfp *sfp_alloc(struct device *dev)
sfp->dev = dev;
mutex_init(&sfp->sm_mutex);
+ mutex_init(&sfp->st_mutex);
INIT_DELAYED_WORK(&sfp->poll, sfp_poll);
INIT_DELAYED_WORK(&sfp->timeout, sfp_timeout);
@@ -1798,9 +1804,10 @@ static void sfp_cleanup(void *data)
static int sfp_probe(struct platform_device *pdev)
{
const struct sff_data *sff;
+ struct i2c_adapter *i2c;
struct sfp *sfp;
bool poll = false;
- int irq, err, i;
+ int err, i;
sfp = sfp_alloc(&pdev->dev);
if (IS_ERR(sfp))
@@ -1817,7 +1824,6 @@ static int sfp_probe(struct platform_device *pdev)
if (pdev->dev.of_node) {
struct device_node *node = pdev->dev.of_node;
const struct of_device_id *id;
- struct i2c_adapter *i2c;
struct device_node *np;
id = of_match_node(sfp_of_match, node);
@@ -1834,14 +1840,32 @@ static int sfp_probe(struct platform_device *pdev)
i2c = of_find_i2c_adapter_by_node(np);
of_node_put(np);
- if (!i2c)
- return -EPROBE_DEFER;
-
- err = sfp_i2c_configure(sfp, i2c);
- if (err < 0) {
- i2c_put_adapter(i2c);
- return err;
+ } else if (has_acpi_companion(&pdev->dev)) {
+ struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
+ struct fwnode_handle *fw = acpi_fwnode_handle(adev);
+ struct fwnode_reference_args args;
+ struct acpi_handle *acpi_handle;
+ int ret;
+
+ ret = acpi_node_get_property_reference(fw, "i2c-bus", 0, &args);
+ if (ret || !is_acpi_device_node(args.fwnode)) {
+ dev_err(&pdev->dev, "missing 'i2c-bus' property\n");
+ return -ENODEV;
}
+
+ acpi_handle = ACPI_HANDLE_FWNODE(args.fwnode);
+ i2c = i2c_acpi_find_adapter_by_handle(acpi_handle);
+ } else {
+ return -EINVAL;
+ }
+
+ if (!i2c)
+ return -EPROBE_DEFER;
+
+ err = sfp_i2c_configure(sfp, i2c);
+ if (err < 0) {
+ i2c_put_adapter(i2c);
+ return err;
}
for (i = 0; i < GPIO_MAX; i++)
@@ -1882,19 +1906,22 @@ static int sfp_probe(struct platform_device *pdev)
if (gpio_flags[i] != GPIOD_IN || !sfp->gpio[i])
continue;
- irq = gpiod_to_irq(sfp->gpio[i]);
- if (!irq) {
+ sfp->gpio_irq[i] = gpiod_to_irq(sfp->gpio[i]);
+ if (!sfp->gpio_irq[i]) {
poll = true;
continue;
}
- err = devm_request_threaded_irq(sfp->dev, irq, NULL, sfp_irq,
+ err = devm_request_threaded_irq(sfp->dev, sfp->gpio_irq[i],
+ NULL, sfp_irq,
IRQF_ONESHOT |
IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING,
dev_name(sfp->dev), sfp);
- if (err)
+ if (err) {
+ sfp->gpio_irq[i] = 0;
poll = true;
+ }
}
if (poll)
@@ -1925,9 +1952,26 @@ static int sfp_remove(struct platform_device *pdev)
return 0;
}
+static void sfp_shutdown(struct platform_device *pdev)
+{
+ struct sfp *sfp = platform_get_drvdata(pdev);
+ int i;
+
+ for (i = 0; i < GPIO_MAX; i++) {
+ if (!sfp->gpio_irq[i])
+ continue;
+
+ devm_free_irq(sfp->dev, sfp->gpio_irq[i], sfp);
+ }
+
+ cancel_delayed_work_sync(&sfp->poll);
+ cancel_delayed_work_sync(&sfp->timeout);
+}
+
static struct platform_driver sfp_driver = {
.probe = sfp_probe,
.remove = sfp_remove,
+ .shutdown = sfp_shutdown,
.driver = {
.name = "sfp",
.of_match_table = sfp_of_match,
diff --git a/drivers/net/plip/plip.c b/drivers/net/plip/plip.c
index 8ac33ca9ac3a..e89cdebae6f1 100644
--- a/drivers/net/plip/plip.c
+++ b/drivers/net/plip/plip.c
@@ -1008,7 +1008,7 @@ plip_rewrite_address(const struct net_device *dev, struct ethhdr *eth)
in_dev = __in_dev_get_rcu(dev);
if (in_dev) {
/* Any address will do - we take the first */
- const struct in_ifaddr *ifa = in_dev->ifa_list;
+ const struct in_ifaddr *ifa = rcu_dereference(in_dev->ifa_list);
if (ifa) {
memcpy(eth->h_source, dev->dev_addr, ETH_ALEN);
memset(eth->h_dest, 0xfc, 2);
@@ -1103,7 +1103,7 @@ plip_open(struct net_device *dev)
/* Any address will do - we take the first. We already
have the first two bytes filled with 0xfc, from
plip_init_dev(). */
- struct in_ifaddr *ifa=in_dev->ifa_list;
+ const struct in_ifaddr *ifa = rcu_dereference(in_dev->ifa_list);
if (ifa != NULL) {
memcpy(dev->dev_addr+2, &ifa->ifa_local, 4);
}
diff --git a/drivers/net/ppp/Kconfig b/drivers/net/ppp/Kconfig
index bf395df3bb37..1a2e2f7629f3 100644
--- a/drivers/net/ppp/Kconfig
+++ b/drivers/net/ppp/Kconfig
@@ -87,8 +87,7 @@ config PPP_MPPE
depends on PPP
select CRYPTO
select CRYPTO_SHA1
- select CRYPTO_ARC4
- select CRYPTO_ECB
+ select CRYPTO_LIB_ARC4
---help---
Support for the MPPE Encryption protocol, as employed by the
Microsoft Point-to-Point Tunneling Protocol.
diff --git a/drivers/net/ppp/ppp_deflate.c b/drivers/net/ppp/ppp_deflate.c
index 685e875f5164..c457f849e553 100644
--- a/drivers/net/ppp/ppp_deflate.c
+++ b/drivers/net/ppp/ppp_deflate.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ppp_deflate.c - interface the zlib procedures for Deflate compression
* and decompression (as used by gzip) to the PPP code.
*
* Copyright 1994-1998 Paul Mackerras.
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/net/ppp/ppp_mppe.c b/drivers/net/ppp/ppp_mppe.c
index ff61dd8748de..de3b57d09d0c 100644
--- a/drivers/net/ppp/ppp_mppe.c
+++ b/drivers/net/ppp/ppp_mppe.c
@@ -42,9 +42,10 @@
* deprecated in 2.6
*/
+#include <crypto/arc4.h>
#include <crypto/hash.h>
-#include <crypto/skcipher.h>
#include <linux/err.h>
+#include <linux/fips.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -65,13 +66,6 @@ MODULE_LICENSE("Dual BSD/GPL");
MODULE_ALIAS("ppp-compress-" __stringify(CI_MPPE));
MODULE_VERSION("1.0.2");
-static unsigned int
-setup_sg(struct scatterlist *sg, const void *address, unsigned int length)
-{
- sg_set_buf(sg, address, length);
- return length;
-}
-
#define SHA1_PAD_SIZE 40
/*
@@ -95,7 +89,7 @@ static inline void sha_pad_init(struct sha_pad *shapad)
* State for an MPPE (de)compressor.
*/
struct ppp_mppe_state {
- struct crypto_sync_skcipher *arc4;
+ struct arc4_ctx arc4;
struct shash_desc *sha1;
unsigned char *sha1_digest;
unsigned char master_key[MPPE_MAX_KEY_LEN];
@@ -154,24 +148,11 @@ static void get_new_key_from_sha(struct ppp_mppe_state * state)
*/
static void mppe_rekey(struct ppp_mppe_state * state, int initial_key)
{
- struct scatterlist sg_in[1], sg_out[1];
- SYNC_SKCIPHER_REQUEST_ON_STACK(req, state->arc4);
-
- skcipher_request_set_sync_tfm(req, state->arc4);
- skcipher_request_set_callback(req, 0, NULL, NULL);
-
get_new_key_from_sha(state);
if (!initial_key) {
- crypto_sync_skcipher_setkey(state->arc4, state->sha1_digest,
- state->keylen);
- sg_init_table(sg_in, 1);
- sg_init_table(sg_out, 1);
- setup_sg(sg_in, state->sha1_digest, state->keylen);
- setup_sg(sg_out, state->session_key, state->keylen);
- skcipher_request_set_crypt(req, sg_in, sg_out, state->keylen,
- NULL);
- if (crypto_skcipher_encrypt(req))
- printk(KERN_WARNING "mppe_rekey: cipher_encrypt failed\n");
+ arc4_setkey(&state->arc4, state->sha1_digest, state->keylen);
+ arc4_crypt(&state->arc4, state->session_key, state->sha1_digest,
+ state->keylen);
} else {
memcpy(state->session_key, state->sha1_digest, state->keylen);
}
@@ -181,9 +162,7 @@ static void mppe_rekey(struct ppp_mppe_state * state, int initial_key)
state->session_key[1] = 0x26;
state->session_key[2] = 0x9e;
}
- crypto_sync_skcipher_setkey(state->arc4, state->session_key,
- state->keylen);
- skcipher_request_zero(req);
+ arc4_setkey(&state->arc4, state->session_key, state->keylen);
}
/*
@@ -196,7 +175,8 @@ static void *mppe_alloc(unsigned char *options, int optlen)
unsigned int digestsize;
if (optlen != CILEN_MPPE + sizeof(state->master_key) ||
- options[0] != CI_MPPE || options[1] != CILEN_MPPE)
+ options[0] != CI_MPPE || options[1] != CILEN_MPPE ||
+ fips_enabled)
goto out;
state = kzalloc(sizeof(*state), GFP_KERNEL);
@@ -204,12 +184,6 @@ static void *mppe_alloc(unsigned char *options, int optlen)
goto out;
- state->arc4 = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0);
- if (IS_ERR(state->arc4)) {
- state->arc4 = NULL;
- goto out_free;
- }
-
shash = crypto_alloc_shash("sha1", 0, 0);
if (IS_ERR(shash))
goto out_free;
@@ -250,7 +224,6 @@ out_free:
crypto_free_shash(state->sha1->tfm);
kzfree(state->sha1);
}
- crypto_free_sync_skcipher(state->arc4);
kfree(state);
out:
return NULL;
@@ -266,8 +239,7 @@ static void mppe_free(void *arg)
kfree(state->sha1_digest);
crypto_free_shash(state->sha1->tfm);
kzfree(state->sha1);
- crypto_free_sync_skcipher(state->arc4);
- kfree(state);
+ kzfree(state);
}
}
@@ -366,10 +338,7 @@ mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf,
int isize, int osize)
{
struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
- SYNC_SKCIPHER_REQUEST_ON_STACK(req, state->arc4);
int proto;
- int err;
- struct scatterlist sg_in[1], sg_out[1];
/*
* Check that the protocol is in the range we handle.
@@ -420,21 +389,7 @@ mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf,
ibuf += 2; /* skip to proto field */
isize -= 2;
- /* Encrypt packet */
- sg_init_table(sg_in, 1);
- sg_init_table(sg_out, 1);
- setup_sg(sg_in, ibuf, isize);
- setup_sg(sg_out, obuf, osize);
-
- skcipher_request_set_sync_tfm(req, state->arc4);
- skcipher_request_set_callback(req, 0, NULL, NULL);
- skcipher_request_set_crypt(req, sg_in, sg_out, isize, NULL);
- err = crypto_skcipher_encrypt(req);
- skcipher_request_zero(req);
- if (err) {
- printk(KERN_DEBUG "crypto_cypher_encrypt failed\n");
- return -1;
- }
+ arc4_crypt(&state->arc4, obuf, ibuf, isize);
state->stats.unc_bytes += isize;
state->stats.unc_packets++;
@@ -480,10 +435,8 @@ mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf,
int osize)
{
struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
- SYNC_SKCIPHER_REQUEST_ON_STACK(req, state->arc4);
unsigned ccount;
int flushed = MPPE_BITS(ibuf) & MPPE_BIT_FLUSHED;
- struct scatterlist sg_in[1], sg_out[1];
if (isize <= PPP_HDRLEN + MPPE_OVHD) {
if (state->debug)
@@ -610,19 +563,7 @@ mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf,
* Decrypt the first byte in order to check if it is
* a compressed or uncompressed protocol field.
*/
- sg_init_table(sg_in, 1);
- sg_init_table(sg_out, 1);
- setup_sg(sg_in, ibuf, 1);
- setup_sg(sg_out, obuf, 1);
-
- skcipher_request_set_sync_tfm(req, state->arc4);
- skcipher_request_set_callback(req, 0, NULL, NULL);
- skcipher_request_set_crypt(req, sg_in, sg_out, 1, NULL);
- if (crypto_skcipher_decrypt(req)) {
- printk(KERN_DEBUG "crypto_cypher_decrypt failed\n");
- osize = DECOMP_ERROR;
- goto out_zap_req;
- }
+ arc4_crypt(&state->arc4, obuf, ibuf, 1);
/*
* Do PFC decompression.
@@ -637,14 +578,7 @@ mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf,
}
/* And finally, decrypt the rest of the packet. */
- setup_sg(sg_in, ibuf + 1, isize - 1);
- setup_sg(sg_out, obuf + 1, osize - 1);
- skcipher_request_set_crypt(req, sg_in, sg_out, isize - 1, NULL);
- if (crypto_skcipher_decrypt(req)) {
- printk(KERN_DEBUG "crypto_cypher_decrypt failed\n");
- osize = DECOMP_ERROR;
- goto out_zap_req;
- }
+ arc4_crypt(&state->arc4, obuf + 1, ibuf + 1, isize - 1);
state->stats.unc_bytes += osize;
state->stats.unc_packets++;
@@ -654,8 +588,6 @@ mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf,
/* good packet credit */
state->sanity_errors >>= 1;
-out_zap_req:
- skcipher_request_zero(req);
return osize;
sanity_error:
@@ -728,8 +660,7 @@ static struct compressor ppp_mppe = {
static int __init ppp_mppe_init(void)
{
int answer;
- if (!(crypto_has_skcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC) &&
- crypto_has_ahash("sha1", 0, CRYPTO_ALG_ASYNC)))
+ if (fips_enabled || !crypto_has_ahash("sha1", 0, CRYPTO_ALG_ASYNC))
return -ENODEV;
sha_pad = kmalloc(sizeof(struct sha_pad), GFP_KERNEL);
diff --git a/drivers/net/tap.c b/drivers/net/tap.c
index 8e01390c738e..dd614c2cd994 100644
--- a/drivers/net/tap.c
+++ b/drivers/net/tap.c
@@ -520,8 +520,7 @@ static int tap_open(struct inode *inode, struct file *file)
goto err;
}
- RCU_INIT_POINTER(q->sock.wq, &q->wq);
- init_waitqueue_head(&q->wq.wait);
+ init_waitqueue_head(&q->sock.wq.wait);
q->sock.type = SOCK_RAW;
q->sock.state = SS_CONNECTED;
q->sock.file = file;
@@ -579,7 +578,7 @@ static __poll_t tap_poll(struct file *file, poll_table *wait)
goto out;
mask = 0;
- poll_wait(file, &q->wq.wait, wait);
+ poll_wait(file, &q->sock.wq.wait, wait);
if (!ptr_ring_empty(&q->ring))
mask |= EPOLLIN | EPOLLRDNORM;
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index b48006e7fa2f..abfa0da9bbd2 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -2054,9 +2054,34 @@ static void team_ethtool_get_drvinfo(struct net_device *dev,
strlcpy(drvinfo->version, UTS_RELEASE, sizeof(drvinfo->version));
}
+static int team_ethtool_get_link_ksettings(struct net_device *dev,
+ struct ethtool_link_ksettings *cmd)
+{
+ struct team *team= netdev_priv(dev);
+ unsigned long speed = 0;
+ struct team_port *port;
+
+ cmd->base.duplex = DUPLEX_UNKNOWN;
+ cmd->base.port = PORT_OTHER;
+
+ list_for_each_entry(port, &team->port_list, list) {
+ if (team_port_txable(port)) {
+ if (port->state.speed != SPEED_UNKNOWN)
+ speed += port->state.speed;
+ if (cmd->base.duplex == DUPLEX_UNKNOWN &&
+ port->state.duplex != DUPLEX_UNKNOWN)
+ cmd->base.duplex = port->state.duplex;
+ }
+ }
+ cmd->base.speed = speed ? : SPEED_UNKNOWN;
+
+ return 0;
+}
+
static const struct ethtool_ops team_ethtool_ops = {
.get_drvinfo = team_ethtool_get_drvinfo,
.get_link = ethtool_op_get_link,
+ .get_link_ksettings = team_ethtool_get_link_ksettings,
};
/***********************
@@ -2128,12 +2153,12 @@ static void team_setup(struct net_device *dev)
dev->features |= NETIF_F_NETNS_LOCAL;
dev->hw_features = TEAM_VLAN_FEATURES |
- NETIF_F_HW_VLAN_CTAG_TX |
NETIF_F_HW_VLAN_CTAG_RX |
NETIF_F_HW_VLAN_CTAG_FILTER;
dev->hw_features |= NETIF_F_GSO_ENCAP_ALL | NETIF_F_GSO_UDP_L4;
dev->features |= dev->hw_features;
+ dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX;
}
static int team_newlink(struct net *src_net, struct net_device *dev,
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index c452d6d831dd..3d443597bd04 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -160,7 +160,6 @@ struct tun_pcpu_stats {
struct tun_file {
struct sock sk;
struct socket socket;
- struct socket_wq wq;
struct tun_struct __rcu *tun;
struct fasync_struct *fasync;
/* only used for fasnyc */
@@ -1014,18 +1013,8 @@ static void tun_net_uninit(struct net_device *dev)
/* Net device open. */
static int tun_net_open(struct net_device *dev)
{
- struct tun_struct *tun = netdev_priv(dev);
- int i;
-
netif_tx_start_all_queues(dev);
- for (i = 0; i < tun->numqueues; i++) {
- struct tun_file *tfile;
-
- tfile = rtnl_dereference(tun->tfiles[i]);
- tfile->socket.sk->sk_write_space(tfile->socket.sk);
- }
-
return 0;
}
@@ -2175,7 +2164,7 @@ static void *tun_ring_recv(struct tun_file *tfile, int noblock, int *err)
goto out;
}
- add_wait_queue(&tfile->wq.wait, &wait);
+ add_wait_queue(&tfile->socket.wq.wait, &wait);
while (1) {
set_current_state(TASK_INTERRUPTIBLE);
@@ -2195,7 +2184,7 @@ static void *tun_ring_recv(struct tun_file *tfile, int noblock, int *err)
}
__set_current_state(TASK_RUNNING);
- remove_wait_queue(&tfile->wq.wait, &wait);
+ remove_wait_queue(&tfile->socket.wq.wait, &wait);
out:
*err = error;
@@ -3425,8 +3414,7 @@ static int tun_chr_open(struct inode *inode, struct file * file)
tfile->flags = 0;
tfile->ifindex = 0;
- init_waitqueue_head(&tfile->wq.wait);
- RCU_INIT_POINTER(tfile->socket.wq, &tfile->wq);
+ init_waitqueue_head(&tfile->socket.wq.wait);
tfile->socket.file = file;
tfile->socket.ops = &tun_socket_ops;
@@ -3634,6 +3622,7 @@ static int tun_device_event(struct notifier_block *unused,
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct tun_struct *tun = netdev_priv(dev);
+ int i;
if (dev->rtnl_link_ops != &tun_link_ops)
return NOTIFY_DONE;
@@ -3643,6 +3632,14 @@ static int tun_device_event(struct notifier_block *unused,
if (tun_queue_resize(tun))
return NOTIFY_BAD;
break;
+ case NETDEV_UP:
+ for (i = 0; i < tun->numqueues; i++) {
+ struct tun_file *tfile;
+
+ tfile = rtnl_dereference(tun->tfiles[i]);
+ tfile->socket.sk->sk_write_space(tfile->socket.sk);
+ }
+ break;
default:
break;
}
diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c
index c9bc96310ed4..ef548beba684 100644
--- a/drivers/net/usb/asix_devices.c
+++ b/drivers/net/usb/asix_devices.c
@@ -226,7 +226,7 @@ static void asix_phy_reset(struct usbnet *dev, unsigned int reset_bits)
static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf)
{
int ret = 0;
- u8 buf[ETH_ALEN];
+ u8 buf[ETH_ALEN] = {0};
int i;
unsigned long gpio_bits = dev->driver_info->data;
@@ -677,7 +677,7 @@ static int asix_resume(struct usb_interface *intf)
static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
{
int ret, i;
- u8 buf[ETH_ALEN], chipcode = 0;
+ u8 buf[ETH_ALEN] = {0}, chipcode = 0;
u32 phyid;
struct asix_common_private *priv;
@@ -1061,7 +1061,7 @@ static const struct net_device_ops ax88178_netdev_ops = {
static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf)
{
int ret;
- u8 buf[ETH_ALEN];
+ u8 buf[ETH_ALEN] = {0};
usbnet_get_endpoints(dev,intf);
diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c
index 28321aca48fe..eb100eb33de3 100644
--- a/drivers/net/usb/cdc_mbim.c
+++ b/drivers/net/usb/cdc_mbim.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012 Smith Micro Software, Inc.
* Copyright (c) 2012 Bjørn Mork <bjorn@mork.no>
*
* This driver is based on and reuse most of cdc_ncm, which is
* Copyright (C) ST-Ericsson 2010-2012
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/net/usb/huawei_cdc_ncm.c b/drivers/net/usb/huawei_cdc_ncm.c
index 63f28908afda..e15a472c6a54 100644
--- a/drivers/net/usb/huawei_cdc_ncm.c
+++ b/drivers/net/usb/huawei_cdc_ncm.c
@@ -1,8 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* huawei_cdc_ncm.c - handles Huawei devices using the CDC NCM protocol as
* transport layer.
* Copyright (C) 2013 Enrico Mioso <mrkiko.rs@gmail.com>
*
- *
* ABSTRACT:
* This driver handles devices resembling the CDC NCM standard, but
* encapsulating another protocol inside it. An example are some Huawei 3G
@@ -11,10 +11,6 @@
* This code has been heavily inspired by the cdc_mbim.c driver, which is
* Copyright (c) 2012 Smith Micro Software, Inc.
* Copyright (c) 2012 Bjørn Mork <bjorn@mork.no>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index 63e44e746ccc..6d25dea5ad4b 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 1999-2013 Petko Manolov (petkan@nucleusys.com)
*
- * 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.
- *
* ChangeLog:
* .... Most of the time spent on reading sources & docs.
* v0.2.x First official release for the Linux kernel.
diff --git a/drivers/net/usb/pegasus.h b/drivers/net/usb/pegasus.h
index 9b7ea9c9167d..a05b143155ba 100644
--- a/drivers/net/usb/pegasus.h
+++ b/drivers/net/usb/pegasus.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 1999-2013 Petko Manolov (petkan@nucleusys.com)
- *
- * 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.
*/
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index d9a6699abe59..69e0a2acfcb0 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012 Bjørn Mork <bjorn@mork.no>
*
* The probing code is heavily inspired by cdc_ether, which is:
* Copyright (C) 2003-2005 by David Brownell
* Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync)
- *
- * 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.
*/
#include <linux/module.h>
@@ -22,6 +19,7 @@
#include <linux/usb/cdc.h>
#include <linux/usb/usbnet.h>
#include <linux/usb/cdc-wdm.h>
+#include <linux/u64_stats_sync.h>
/* This driver supports wwan (3G/LTE/?) devices using a vendor
* specific management protocol called Qualcomm MSM Interface (QMI) -
@@ -75,6 +73,7 @@ struct qmimux_hdr {
struct qmimux_priv {
struct net_device *real_dev;
u8 mux_id;
+ struct pcpu_sw_netstats __percpu *stats64;
};
static int qmimux_open(struct net_device *dev)
@@ -101,19 +100,65 @@ static netdev_tx_t qmimux_start_xmit(struct sk_buff *skb, struct net_device *dev
struct qmimux_priv *priv = netdev_priv(dev);
unsigned int len = skb->len;
struct qmimux_hdr *hdr;
+ netdev_tx_t ret;
hdr = skb_push(skb, sizeof(struct qmimux_hdr));
hdr->pad = 0;
hdr->mux_id = priv->mux_id;
hdr->pkt_len = cpu_to_be16(len);
skb->dev = priv->real_dev;
- return dev_queue_xmit(skb);
+ ret = dev_queue_xmit(skb);
+
+ if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {
+ struct pcpu_sw_netstats *stats64 = this_cpu_ptr(priv->stats64);
+
+ u64_stats_update_begin(&stats64->syncp);
+ stats64->tx_packets++;
+ stats64->tx_bytes += len;
+ u64_stats_update_end(&stats64->syncp);
+ } else {
+ dev->stats.tx_dropped++;
+ }
+
+ return ret;
+}
+
+static void qmimux_get_stats64(struct net_device *net,
+ struct rtnl_link_stats64 *stats)
+{
+ struct qmimux_priv *priv = netdev_priv(net);
+ unsigned int start;
+ int cpu;
+
+ netdev_stats_to_stats64(stats, &net->stats);
+
+ for_each_possible_cpu(cpu) {
+ struct pcpu_sw_netstats *stats64;
+ u64 rx_packets, rx_bytes;
+ u64 tx_packets, tx_bytes;
+
+ stats64 = per_cpu_ptr(priv->stats64, cpu);
+
+ do {
+ start = u64_stats_fetch_begin_irq(&stats64->syncp);
+ rx_packets = stats64->rx_packets;
+ rx_bytes = stats64->rx_bytes;
+ tx_packets = stats64->tx_packets;
+ tx_bytes = stats64->tx_bytes;
+ } while (u64_stats_fetch_retry_irq(&stats64->syncp, start));
+
+ stats->rx_packets += rx_packets;
+ stats->rx_bytes += rx_bytes;
+ stats->tx_packets += tx_packets;
+ stats->tx_bytes += tx_bytes;
+ }
}
static const struct net_device_ops qmimux_netdev_ops = {
- .ndo_open = qmimux_open,
- .ndo_stop = qmimux_stop,
- .ndo_start_xmit = qmimux_start_xmit,
+ .ndo_open = qmimux_open,
+ .ndo_stop = qmimux_stop,
+ .ndo_start_xmit = qmimux_start_xmit,
+ .ndo_get_stats64 = qmimux_get_stats64,
};
static void qmimux_setup(struct net_device *dev)
@@ -153,7 +198,7 @@ static bool qmimux_has_slaves(struct usbnet *dev)
static int qmimux_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
- unsigned int len, offset = 0;
+ unsigned int len, offset = 0, pad_len, pkt_len;
struct qmimux_hdr *hdr;
struct net_device *net;
struct sk_buff *skbn;
@@ -171,10 +216,16 @@ static int qmimux_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
if (hdr->pad & 0x80)
goto skip;
+ /* extract padding length and check for valid length info */
+ pad_len = hdr->pad & 0x3f;
+ if (len == 0 || pad_len >= len)
+ goto skip;
+ pkt_len = len - pad_len;
+
net = qmimux_find_dev(dev, hdr->mux_id);
if (!net)
goto skip;
- skbn = netdev_alloc_skb(net, len);
+ skbn = netdev_alloc_skb(net, pkt_len);
if (!skbn)
return 0;
skbn->dev = net;
@@ -191,9 +242,20 @@ static int qmimux_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
goto skip;
}
- skb_put_data(skbn, skb->data + offset + qmimux_hdr_sz, len);
- if (netif_rx(skbn) != NET_RX_SUCCESS)
+ skb_put_data(skbn, skb->data + offset + qmimux_hdr_sz, pkt_len);
+ if (netif_rx(skbn) != NET_RX_SUCCESS) {
+ net->stats.rx_errors++;
return 0;
+ } else {
+ struct pcpu_sw_netstats *stats64;
+ struct qmimux_priv *priv = netdev_priv(net);
+
+ stats64 = this_cpu_ptr(priv->stats64);
+ u64_stats_update_begin(&stats64->syncp);
+ stats64->rx_packets++;
+ stats64->rx_bytes += pkt_len;
+ u64_stats_update_end(&stats64->syncp);
+ }
skip:
offset += len + qmimux_hdr_sz;
@@ -217,6 +279,12 @@ static int qmimux_register_device(struct net_device *real_dev, u8 mux_id)
priv->mux_id = mux_id;
priv->real_dev = real_dev;
+ priv->stats64 = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
+ if (!priv->stats64) {
+ err = -ENOBUFS;
+ goto out_free_newdev;
+ }
+
err = register_netdevice(new_dev);
if (err < 0)
goto out_free_newdev;
@@ -241,13 +309,15 @@ out_free_newdev:
return err;
}
-static void qmimux_unregister_device(struct net_device *dev)
+static void qmimux_unregister_device(struct net_device *dev,
+ struct list_head *head)
{
struct qmimux_priv *priv = netdev_priv(dev);
struct net_device *real_dev = priv->real_dev;
+ free_percpu(priv->stats64);
netdev_upper_dev_unlink(real_dev, dev);
- unregister_netdevice(dev);
+ unregister_netdevice_queue(dev, head);
/* Get rid of the reference to real_dev */
dev_put(real_dev);
@@ -356,8 +426,8 @@ static ssize_t add_mux_store(struct device *d, struct device_attribute *attr, c
if (kstrtou8(buf, 0, &mux_id))
return -EINVAL;
- /* mux_id [1 - 0x7f] range empirically found */
- if (mux_id < 1 || mux_id > 0x7f)
+ /* mux_id [1 - 254] for compatibility with ip(8) and the rmnet driver */
+ if (mux_id < 1 || mux_id > 254)
return -EINVAL;
if (!rtnl_trylock())
@@ -418,7 +488,7 @@ static ssize_t del_mux_store(struct device *d, struct device_attribute *attr, c
ret = -EINVAL;
goto err;
}
- qmimux_unregister_device(del_dev);
+ qmimux_unregister_device(del_dev, NULL);
if (!qmimux_has_slaves(dev))
info->flags &= ~QMI_WWAN_FLAG_MUX;
@@ -1222,6 +1292,7 @@ static const struct usb_device_id products[] = {
{QMI_FIXED_INTF(0x2001, 0x7e16, 3)}, /* D-Link DWM-221 */
{QMI_FIXED_INTF(0x2001, 0x7e19, 4)}, /* D-Link DWM-221 B1 */
{QMI_FIXED_INTF(0x2001, 0x7e35, 4)}, /* D-Link DWM-222 */
+ {QMI_FIXED_INTF(0x2001, 0x7e3d, 4)}, /* D-Link DWM-222 A2 */
{QMI_FIXED_INTF(0x2020, 0x2031, 4)}, /* Olicard 600 */
{QMI_FIXED_INTF(0x2020, 0x2033, 4)}, /* BroadMobi BM806U */
{QMI_FIXED_INTF(0x0f3d, 0x68a2, 8)}, /* Sierra Wireless MC7700 */
@@ -1412,7 +1483,7 @@ static int qmi_wwan_probe(struct usb_interface *intf,
* different. Ignore the current interface if the number of endpoints
* equals the number for the diag interface (two).
*/
- info = (void *)&id->driver_info;
+ info = (void *)id->driver_info;
if (info->data & QMI_WWAN_QUIRK_QUECTEL_DYNCFG) {
if (desc->bNumEndpoints == 2)
@@ -1428,6 +1499,7 @@ static void qmi_wwan_disconnect(struct usb_interface *intf)
struct qmi_wwan_state *info;
struct list_head *iter;
struct net_device *ldev;
+ LIST_HEAD(list);
/* called twice if separate control and data intf */
if (!dev)
@@ -1440,8 +1512,9 @@ static void qmi_wwan_disconnect(struct usb_interface *intf)
}
rcu_read_lock();
netdev_for_each_upper_dev_rcu(dev->net, ldev, iter)
- qmimux_unregister_device(ldev);
+ qmimux_unregister_device(ldev, &list);
rcu_read_unlock();
+ unregister_netdevice_many(&list);
rtnl_unlock();
info->flags &= ~QMI_WWAN_FLAG_MUX;
}
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index b01bfa63860d..39e0768d734d 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -1,10 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014 Realtek Semiconductor Corp. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
*/
#include <linux/signal.h>
@@ -32,7 +28,7 @@
#define NETNEXT_VERSION "09"
/* Information for net */
-#define NET_VERSION "9"
+#define NET_VERSION "10"
#define DRIVER_VERSION "v1." NETNEXT_VERSION "." NET_VERSION
#define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>"
@@ -57,6 +53,9 @@
#define PAL_BDC_CR 0xd1a0
#define PLA_TEREDO_TIMER 0xd2cc
#define PLA_REALWOW_TIMER 0xd2e8
+#define PLA_SUSPEND_FLAG 0xd38a
+#define PLA_INDICATE_FALG 0xd38c
+#define PLA_EXTRA_STATUS 0xd398
#define PLA_EFUSE_DATA 0xdd00
#define PLA_EFUSE_CMD 0xdd02
#define PLA_LEDSEL 0xdd90
@@ -340,6 +339,15 @@
/* PLA_BOOT_CTRL */
#define AUTOLOAD_DONE 0x0002
+/* PLA_SUSPEND_FLAG */
+#define LINK_CHG_EVENT BIT(0)
+
+/* PLA_INDICATE_FALG */
+#define UPCOMING_RUNTIME_D3 BIT(0)
+
+/* PLA_EXTRA_STATUS */
+#define LINK_CHANGE_FLAG BIT(8)
+
/* USB_USB2PHY */
#define USB2PHY_SUSPEND 0x0001
#define USB2PHY_L1 0x0002
@@ -817,6 +825,14 @@ int set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
return ret;
}
+static void rtl_set_unplug(struct r8152 *tp)
+{
+ if (tp->udev->state == USB_STATE_NOTATTACHED) {
+ set_bit(RTL8152_UNPLUG, &tp->flags);
+ smp_mb__after_atomic();
+ }
+}
+
static int generic_ocp_read(struct r8152 *tp, u16 index, u16 size,
void *data, u16 type)
{
@@ -855,7 +871,7 @@ static int generic_ocp_read(struct r8152 *tp, u16 index, u16 size,
}
if (ret == -ENODEV)
- set_bit(RTL8152_UNPLUG, &tp->flags);
+ rtl_set_unplug(tp);
return ret;
}
@@ -925,7 +941,7 @@ static int generic_ocp_write(struct r8152 *tp, u16 index, u16 byteen,
error1:
if (ret == -ENODEV)
- set_bit(RTL8152_UNPLUG, &tp->flags);
+ rtl_set_unplug(tp);
return ret;
}
@@ -1313,7 +1329,7 @@ static void read_bulk_callback(struct urb *urb)
napi_schedule(&tp->napi);
return;
case -ESHUTDOWN:
- set_bit(RTL8152_UNPLUG, &tp->flags);
+ rtl_set_unplug(tp);
netif_device_detach(tp->netdev);
return;
case -ENOENT:
@@ -1433,7 +1449,7 @@ static void intr_callback(struct urb *urb)
resubmit:
res = usb_submit_urb(urb, GFP_ATOMIC);
if (res == -ENODEV) {
- set_bit(RTL8152_UNPLUG, &tp->flags);
+ rtl_set_unplug(tp);
netif_device_detach(tp->netdev);
} else if (res) {
netif_err(tp, intr, tp->netdev,
@@ -2028,7 +2044,7 @@ static void tx_bottom(struct r8152 *tp)
struct net_device *netdev = tp->netdev;
if (res == -ENODEV) {
- set_bit(RTL8152_UNPLUG, &tp->flags);
+ rtl_set_unplug(tp);
netif_device_detach(netdev);
} else {
struct net_device_stats *stats = &netdev->stats;
@@ -2102,7 +2118,7 @@ int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags)
ret = usb_submit_urb(agg->urb, mem_flags);
if (ret == -ENODEV) {
- set_bit(RTL8152_UNPLUG, &tp->flags);
+ rtl_set_unplug(tp);
netif_device_detach(tp->netdev);
} else if (ret) {
struct urb *urb = agg->urb;
@@ -2359,6 +2375,12 @@ static int rtl_stop_rx(struct r8152 *tp)
return 0;
}
+static inline void r8153b_rx_agg_chg_indicate(struct r8152 *tp)
+{
+ ocp_write_byte(tp, MCU_TYPE_USB, USB_UPT_RXDMA_OWN,
+ OWN_UPDATE | OWN_CLEAR);
+}
+
static int rtl_enable(struct r8152 *tp)
{
u32 ocp_data;
@@ -2369,6 +2391,15 @@ static int rtl_enable(struct r8152 *tp)
ocp_data |= CR_RE | CR_TE;
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, ocp_data);
+ switch (tp->version) {
+ case RTL_VER_08:
+ case RTL_VER_09:
+ r8153b_rx_agg_chg_indicate(tp);
+ break;
+ default:
+ break;
+ }
+
rxdy_gated_en(tp, false);
return 0;
@@ -2385,12 +2416,6 @@ static int rtl8152_enable(struct r8152 *tp)
return rtl_enable(tp);
}
-static inline void r8153b_rx_agg_chg_indicate(struct r8152 *tp)
-{
- ocp_write_byte(tp, MCU_TYPE_USB, USB_UPT_RXDMA_OWN,
- OWN_UPDATE | OWN_CLEAR);
-}
-
static void r8153_set_rx_early_timeout(struct r8152 *tp)
{
u32 ocp_data = tp->coalesce / 8;
@@ -2413,7 +2438,6 @@ static void r8153_set_rx_early_timeout(struct r8152 *tp)
128 / 8);
ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EXTRA_AGGR_TMR,
ocp_data);
- r8153b_rx_agg_chg_indicate(tp);
break;
default:
@@ -2437,7 +2461,6 @@ static void r8153_set_rx_early_size(struct r8152 *tp)
case RTL_VER_09:
ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_SIZE,
ocp_data / 8);
- r8153b_rx_agg_chg_indicate(tp);
break;
default:
WARN_ON_ONCE(1);
@@ -2810,20 +2833,24 @@ static void r8153b_power_cut_en(struct r8152 *tp, bool enable)
ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data);
}
-static void r8153b_queue_wake(struct r8152 *tp, bool enable)
+static void r8153_queue_wake(struct r8152 *tp, bool enable)
{
u32 ocp_data;
- ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, 0xd38a);
+ ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_INDICATE_FALG);
if (enable)
- ocp_data |= BIT(0);
+ ocp_data |= UPCOMING_RUNTIME_D3;
else
- ocp_data &= ~BIT(0);
- ocp_write_byte(tp, MCU_TYPE_PLA, 0xd38a, ocp_data);
+ ocp_data &= ~UPCOMING_RUNTIME_D3;
+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_INDICATE_FALG, ocp_data);
+
+ ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_SUSPEND_FLAG);
+ ocp_data &= ~LINK_CHG_EVENT;
+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_SUSPEND_FLAG, ocp_data);
- ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, 0xd38c);
- ocp_data &= ~BIT(0);
- ocp_write_byte(tp, MCU_TYPE_PLA, 0xd38c, ocp_data);
+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS);
+ ocp_data &= ~LINK_CHANGE_FLAG;
+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS, ocp_data);
}
static bool rtl_can_wakeup(struct r8152 *tp)
@@ -2891,14 +2918,14 @@ static void rtl8153_runtime_enable(struct r8152 *tp, bool enable)
static void rtl8153b_runtime_enable(struct r8152 *tp, bool enable)
{
if (enable) {
- r8153b_queue_wake(tp, true);
+ r8153_queue_wake(tp, true);
r8153b_u1u2en(tp, false);
r8153_u2p3en(tp, false);
rtl_runtime_suspend_enable(tp, true);
r8153b_ups_en(tp, true);
} else {
r8153b_ups_en(tp, false);
- r8153b_queue_wake(tp, false);
+ r8153_queue_wake(tp, false);
rtl_runtime_suspend_enable(tp, false);
r8153_u2p3en(tp, true);
r8153b_u1u2en(tp, true);
@@ -4225,7 +4252,7 @@ static void r8153b_init(struct r8152 *tp)
r8153b_power_cut_en(tp, false);
r8153b_ups_en(tp, false);
- r8153b_queue_wake(tp, false);
+ r8153_queue_wake(tp, false);
rtl_runtime_suspend_enable(tp, false);
r8153b_u1u2en(tp, true);
usb_enable_lpm(tp->udev);
@@ -4907,8 +4934,17 @@ static int rtl8152_set_coalesce(struct net_device *netdev,
if (tp->coalesce != coalesce->rx_coalesce_usecs) {
tp->coalesce = coalesce->rx_coalesce_usecs;
- if (netif_running(tp->netdev) && netif_carrier_ok(netdev))
- r8153_set_rx_early_timeout(tp);
+ if (netif_running(netdev) && netif_carrier_ok(netdev)) {
+ netif_stop_queue(netdev);
+ napi_disable(&tp->napi);
+ tp->rtl_ops.disable(tp);
+ tp->rtl_ops.enable(tp);
+ rtl_start_rx(tp);
+ clear_bit(RTL8152_SET_RX_MODE, &tp->flags);
+ _rtl8152_set_rx_mode(netdev);
+ napi_enable(&tp->napi);
+ netif_wake_queue(netdev);
+ }
}
mutex_unlock(&tp->control);
@@ -5327,10 +5363,7 @@ static void rtl8152_disconnect(struct usb_interface *intf)
usb_set_intfdata(intf, NULL);
if (tp) {
- struct usb_device *udev = tp->udev;
-
- if (udev->state == USB_STATE_NOTATTACHED)
- set_bit(RTL8152_UNPLUG, &tp->flags);
+ rtl_set_unplug(tp);
netif_napi_del(&tp->napi);
unregister_netdev(tp->netdev);
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
index 59dbdbb5feff..98f33e270af1 100644
--- a/drivers/net/usb/rtl8150.c
+++ b/drivers/net/usb/rtl8150.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2002 Petko Manolov (petkan@users.sourceforge.net)
- *
- * 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.
*/
#include <linux/signal.h>
diff --git a/drivers/net/usb/sr9700.h b/drivers/net/usb/sr9700.h
index 258b030277e7..ea2b4de621c8 100644
--- a/drivers/net/usb/sr9700.h
+++ b/drivers/net/usb/sr9700.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* CoreChip-sz SR9700 one chip USB 1.1 Ethernet Devices
*
* Author : Liu Junliang <liujunliang_ljl@163.com>
- *
- * 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.
*/
#ifndef _SR9700_H
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 52110e54e621..9f3c839f9e5f 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -38,6 +38,8 @@
#define VETH_XDP_TX BIT(0)
#define VETH_XDP_REDIR BIT(1)
+#define VETH_XDP_TX_BULK_SIZE 16
+
struct veth_rq_stats {
u64 xdp_packets;
u64 xdp_bytes;
@@ -64,6 +66,11 @@ struct veth_priv {
unsigned int requested_headroom;
};
+struct veth_xdp_tx_bq {
+ struct xdp_frame *q[VETH_XDP_TX_BULK_SIZE];
+ unsigned int count;
+};
+
/*
* ethtool interface
*/
@@ -442,13 +449,30 @@ drop:
return ret;
}
-static void veth_xdp_flush(struct net_device *dev)
+static void veth_xdp_flush_bq(struct net_device *dev, struct veth_xdp_tx_bq *bq)
+{
+ int sent, i, err = 0;
+
+ sent = veth_xdp_xmit(dev, bq->count, bq->q, 0);
+ if (sent < 0) {
+ err = sent;
+ sent = 0;
+ for (i = 0; i < bq->count; i++)
+ xdp_return_frame(bq->q[i]);
+ }
+ trace_xdp_bulk_tx(dev, sent, bq->count - sent, err);
+
+ bq->count = 0;
+}
+
+static void veth_xdp_flush(struct net_device *dev, struct veth_xdp_tx_bq *bq)
{
struct veth_priv *rcv_priv, *priv = netdev_priv(dev);
struct net_device *rcv;
struct veth_rq *rq;
rcu_read_lock();
+ veth_xdp_flush_bq(dev, bq);
rcv = rcu_dereference(priv->peer);
if (unlikely(!rcv))
goto out;
@@ -464,19 +488,26 @@ out:
rcu_read_unlock();
}
-static int veth_xdp_tx(struct net_device *dev, struct xdp_buff *xdp)
+static int veth_xdp_tx(struct net_device *dev, struct xdp_buff *xdp,
+ struct veth_xdp_tx_bq *bq)
{
struct xdp_frame *frame = convert_to_xdp_frame(xdp);
if (unlikely(!frame))
return -EOVERFLOW;
- return veth_xdp_xmit(dev, 1, &frame, 0);
+ if (unlikely(bq->count == VETH_XDP_TX_BULK_SIZE))
+ veth_xdp_flush_bq(dev, bq);
+
+ bq->q[bq->count++] = frame;
+
+ return 0;
}
static struct sk_buff *veth_xdp_rcv_one(struct veth_rq *rq,
struct xdp_frame *frame,
- unsigned int *xdp_xmit)
+ unsigned int *xdp_xmit,
+ struct veth_xdp_tx_bq *bq)
{
void *hard_start = frame->data - frame->headroom;
void *head = hard_start - sizeof(struct xdp_frame);
@@ -509,7 +540,7 @@ static struct sk_buff *veth_xdp_rcv_one(struct veth_rq *rq,
orig_frame = *frame;
xdp.data_hard_start = head;
xdp.rxq->mem = frame->mem;
- if (unlikely(veth_xdp_tx(rq->dev, &xdp) < 0)) {
+ if (unlikely(veth_xdp_tx(rq->dev, &xdp, bq) < 0)) {
trace_xdp_exception(rq->dev, xdp_prog, act);
frame = &orig_frame;
goto err_xdp;
@@ -547,6 +578,7 @@ static struct sk_buff *veth_xdp_rcv_one(struct veth_rq *rq,
goto err;
}
+ xdp_release_frame(frame);
xdp_scrub_frame(frame);
skb->protocol = eth_type_trans(skb, rq->dev);
err:
@@ -559,7 +591,8 @@ xdp_xmit:
}
static struct sk_buff *veth_xdp_rcv_skb(struct veth_rq *rq, struct sk_buff *skb,
- unsigned int *xdp_xmit)
+ unsigned int *xdp_xmit,
+ struct veth_xdp_tx_bq *bq)
{
u32 pktlen, headroom, act, metalen;
void *orig_data, *orig_data_end;
@@ -635,7 +668,7 @@ static struct sk_buff *veth_xdp_rcv_skb(struct veth_rq *rq, struct sk_buff *skb,
get_page(virt_to_page(xdp.data));
consume_skb(skb);
xdp.rxq->mem = rq->xdp_mem;
- if (unlikely(veth_xdp_tx(rq->dev, &xdp) < 0)) {
+ if (unlikely(veth_xdp_tx(rq->dev, &xdp, bq) < 0)) {
trace_xdp_exception(rq->dev, xdp_prog, act);
goto err_xdp;
}
@@ -690,7 +723,8 @@ xdp_xmit:
return NULL;
}
-static int veth_xdp_rcv(struct veth_rq *rq, int budget, unsigned int *xdp_xmit)
+static int veth_xdp_rcv(struct veth_rq *rq, int budget, unsigned int *xdp_xmit,
+ struct veth_xdp_tx_bq *bq)
{
int i, done = 0, drops = 0, bytes = 0;
@@ -706,11 +740,11 @@ static int veth_xdp_rcv(struct veth_rq *rq, int budget, unsigned int *xdp_xmit)
struct xdp_frame *frame = veth_ptr_to_xdp(ptr);
bytes += frame->len;
- skb = veth_xdp_rcv_one(rq, frame, &xdp_xmit_one);
+ skb = veth_xdp_rcv_one(rq, frame, &xdp_xmit_one, bq);
} else {
skb = ptr;
bytes += skb->len;
- skb = veth_xdp_rcv_skb(rq, skb, &xdp_xmit_one);
+ skb = veth_xdp_rcv_skb(rq, skb, &xdp_xmit_one, bq);
}
*xdp_xmit |= xdp_xmit_one;
@@ -736,10 +770,13 @@ static int veth_poll(struct napi_struct *napi, int budget)
struct veth_rq *rq =
container_of(napi, struct veth_rq, xdp_napi);
unsigned int xdp_xmit = 0;
+ struct veth_xdp_tx_bq bq;
int done;
+ bq.count = 0;
+
xdp_set_return_frame_no_direct();
- done = veth_xdp_rcv(rq, budget, &xdp_xmit);
+ done = veth_xdp_rcv(rq, budget, &xdp_xmit, &bq);
if (done < budget && napi_complete_done(napi, done)) {
/* Write rx_notify_masked before reading ptr_ring */
@@ -751,7 +788,7 @@ static int veth_poll(struct napi_struct *napi, int budget)
}
if (xdp_xmit & VETH_XDP_TX)
- veth_xdp_flush(rq->dev);
+ veth_xdp_flush(rq->dev, &bq);
if (xdp_xmit & VETH_XDP_REDIR)
xdp_do_flush_map();
xdp_clear_return_frame_no_direct();
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 0d4115c9e20b..4f3de0ac8b0b 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -26,7 +26,7 @@
static int napi_weight = NAPI_POLL_WEIGHT;
module_param(napi_weight, int, 0444);
-static bool csum = true, gso = true, napi_tx;
+static bool csum = true, gso = true, napi_tx = true;
module_param(csum, bool, 0444);
module_param(gso, bool, 0444);
module_param(napi_tx, bool, 0644);
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index 89984fcab01e..2a1918f25e47 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -3247,6 +3247,7 @@ vmxnet3_probe_device(struct pci_dev *pdev,
.ndo_start_xmit = vmxnet3_xmit_frame,
.ndo_set_mac_address = vmxnet3_set_mac_addr,
.ndo_change_mtu = vmxnet3_change_mtu,
+ .ndo_fix_features = vmxnet3_fix_features,
.ndo_set_features = vmxnet3_set_features,
.ndo_get_stats64 = vmxnet3_get_stats64,
.ndo_tx_timeout = vmxnet3_tx_timeout,
@@ -3429,7 +3430,6 @@ vmxnet3_probe_device(struct pci_dev *pdev,
err = -ENOMEM;
goto err_ver;
}
- memset(adapter->coal_conf, 0, sizeof(*adapter->coal_conf));
adapter->coal_conf->coalMode = VMXNET3_COALESCE_DISABLED;
adapter->default_coal_mode = true;
}
@@ -3651,13 +3651,19 @@ vmxnet3_suspend(struct device *device)
}
if (adapter->wol & WAKE_ARP) {
- in_dev = in_dev_get(netdev);
- if (!in_dev)
+ rcu_read_lock();
+
+ in_dev = __in_dev_get_rcu(netdev);
+ if (!in_dev) {
+ rcu_read_unlock();
goto skip_arp;
+ }
- ifa = (struct in_ifaddr *)in_dev->ifa_list;
- if (!ifa)
+ ifa = rcu_dereference(in_dev->ifa_list);
+ if (!ifa) {
+ rcu_read_unlock();
goto skip_arp;
+ }
pmConf->filters[i].patternSize = ETH_HLEN + /* Ethernet header*/
sizeof(struct arphdr) + /* ARP header */
@@ -3677,7 +3683,9 @@ vmxnet3_suspend(struct device *device)
/* The Unicast IPv4 address in 'tip' field. */
arpreq += 2 * ETH_ALEN + sizeof(u32);
- *(u32 *)arpreq = ifa->ifa_address;
+ *(__be32 *)arpreq = ifa->ifa_address;
+
+ rcu_read_unlock();
/* The mask for the relevant bits. */
pmConf->filters[i].mask[0] = 0x00;
@@ -3686,7 +3694,6 @@ vmxnet3_suspend(struct device *device)
pmConf->filters[i].mask[3] = 0x00;
pmConf->filters[i].mask[4] = 0xC0; /* IPv4 TIP */
pmConf->filters[i].mask[5] = 0x03; /* IPv4 TIP */
- in_dev_put(in_dev);
pmConf->wakeUpEvents |= VMXNET3_PM_WAKEUP_FILTER;
i++;
diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c
index 559db051a500..0a38c76688ab 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethtool.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c
@@ -257,6 +257,16 @@ 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)
+{
+ /* If Rx checksum is disabled, then LRO should also be disabled */
+ if (!(features & NETIF_F_RXCSUM))
+ features &= ~NETIF_F_LRO;
+
+ return features;
+}
+
int vmxnet3_set_features(struct net_device *netdev, netdev_features_t features)
{
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h
index a2c554f8a61b..1cc1cd4aaa59 100644
--- a/drivers/net/vmxnet3/vmxnet3_int.h
+++ b/drivers/net/vmxnet3/vmxnet3_int.h
@@ -69,12 +69,12 @@
/*
* Version numbers
*/
-#define VMXNET3_DRIVER_VERSION_STRING "1.4.16.0-k"
+#define VMXNET3_DRIVER_VERSION_STRING "1.4.17.0-k"
/* Each byte of this 32-bit integer encodes a version number in
* VMXNET3_DRIVER_VERSION_STRING.
*/
-#define VMXNET3_DRIVER_VERSION_NUM 0x01041000
+#define VMXNET3_DRIVER_VERSION_NUM 0x01041100
#if defined(CONFIG_PCI_MSI)
/* RSS only makes sense if MSI-X is supported. */
@@ -454,6 +454,9 @@ vmxnet3_tq_destroy_all(struct vmxnet3_adapter *adapter);
void
vmxnet3_rq_destroy_all(struct vmxnet3_adapter *adapter);
+netdev_features_t
+vmxnet3_fix_features(struct net_device *netdev, netdev_features_t features);
+
int
vmxnet3_set_features(struct net_device *netdev, netdev_features_t features);
diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
index 11b9525dff27..54edf8956a25 100644
--- a/drivers/net/vrf.c
+++ b/drivers/net/vrf.c
@@ -350,8 +350,8 @@ static int vrf_finish_output6(struct net *net, struct sock *sk,
{
struct dst_entry *dst = skb_dst(skb);
struct net_device *dev = dst->dev;
+ const struct in6_addr *nexthop;
struct neighbour *neigh;
- struct in6_addr *nexthop;
int ret;
nf_reset(skb);
@@ -1072,12 +1072,14 @@ static struct sk_buff *vrf_l3_rcv(struct net_device *vrf_dev,
#if IS_ENABLED(CONFIG_IPV6)
/* send to link-local or multicast address via interface enslaved to
* VRF device. Force lookup to VRF table without changing flow struct
+ * Note: Caller to this function must hold rcu_read_lock() and no refcnt
+ * is taken on the dst by this function.
*/
static struct dst_entry *vrf_link_scope_lookup(const struct net_device *dev,
struct flowi6 *fl6)
{
struct net *net = dev_net(dev);
- int flags = RT6_LOOKUP_F_IFACE;
+ int flags = RT6_LOOKUP_F_IFACE | RT6_LOOKUP_F_DST_NOREF;
struct dst_entry *dst = NULL;
struct rt6_info *rt;
@@ -1087,7 +1089,6 @@ static struct dst_entry *vrf_link_scope_lookup(const struct net_device *dev,
*/
if (fl6->flowi6_oif == dev->ifindex) {
dst = &net->ipv6.ip6_null_entry->dst;
- dst_hold(dst);
return dst;
}
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 5994d5415a03..3d9bcc957f7d 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* VXLAN: Virtual eXtensible Local Area Network
*
* Copyright (c) 2012-2013 Vyatta 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -471,14 +468,19 @@ static u32 eth_vni_hash(const unsigned char *addr, __be32 vni)
return jhash_2words(key, vni, vxlan_salt) & (FDB_HASH_SIZE - 1);
}
+static u32 fdb_head_index(struct vxlan_dev *vxlan, const u8 *mac, __be32 vni)
+{
+ if (vxlan->cfg.flags & VXLAN_F_COLLECT_METADATA)
+ return eth_vni_hash(mac, vni);
+ else
+ return eth_hash(mac);
+}
+
/* Hash chain to use given mac address */
static inline struct hlist_head *vxlan_fdb_head(struct vxlan_dev *vxlan,
const u8 *mac, __be32 vni)
{
- if (vxlan->cfg.flags & VXLAN_F_COLLECT_METADATA)
- return &vxlan->fdb_head[eth_vni_hash(mac, vni)];
- else
- return &vxlan->fdb_head[eth_hash(mac)];
+ return &vxlan->fdb_head[fdb_head_index(vxlan, mac, vni)];
}
/* Look up Ethernet address in forwarding table */
@@ -593,8 +595,8 @@ int vxlan_fdb_replay(const struct net_device *dev, __be32 vni,
return -EINVAL;
vxlan = netdev_priv(dev);
- spin_lock_bh(&vxlan->hash_lock);
for (h = 0; h < FDB_HASH_SIZE; ++h) {
+ spin_lock_bh(&vxlan->hash_lock[h]);
hlist_for_each_entry(f, &vxlan->fdb_head[h], hlist) {
if (f->vni == vni) {
list_for_each_entry(rdst, &f->remotes, list) {
@@ -602,14 +604,16 @@ int vxlan_fdb_replay(const struct net_device *dev, __be32 vni,
f, rdst,
extack);
if (rc)
- goto out;
+ goto unlock;
}
}
}
+ spin_unlock_bh(&vxlan->hash_lock[h]);
}
+ return 0;
-out:
- spin_unlock_bh(&vxlan->hash_lock);
+unlock:
+ spin_unlock_bh(&vxlan->hash_lock[h]);
return rc;
}
EXPORT_SYMBOL_GPL(vxlan_fdb_replay);
@@ -625,14 +629,15 @@ void vxlan_fdb_clear_offload(const struct net_device *dev, __be32 vni)
return;
vxlan = netdev_priv(dev);
- spin_lock_bh(&vxlan->hash_lock);
for (h = 0; h < FDB_HASH_SIZE; ++h) {
+ spin_lock_bh(&vxlan->hash_lock[h]);
hlist_for_each_entry(f, &vxlan->fdb_head[h], hlist)
if (f->vni == vni)
list_for_each_entry(rdst, &f->remotes, list)
rdst->offloaded = false;
+ spin_unlock_bh(&vxlan->hash_lock[h]);
}
- spin_unlock_bh(&vxlan->hash_lock);
+
}
EXPORT_SYMBOL_GPL(vxlan_fdb_clear_offload);
@@ -807,6 +812,14 @@ static struct vxlan_fdb *vxlan_fdb_alloc(struct vxlan_dev *vxlan,
return f;
}
+static void vxlan_fdb_insert(struct vxlan_dev *vxlan, const u8 *mac,
+ __be32 src_vni, struct vxlan_fdb *f)
+{
+ ++vxlan->addrcnt;
+ hlist_add_head_rcu(&f->hlist,
+ vxlan_fdb_head(vxlan, mac, src_vni));
+}
+
static int vxlan_fdb_create(struct vxlan_dev *vxlan,
const u8 *mac, union vxlan_addr *ip,
__u16 state, __be16 port, __be32 src_vni,
@@ -832,18 +845,13 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan,
return rc;
}
- ++vxlan->addrcnt;
- hlist_add_head_rcu(&f->hlist,
- vxlan_fdb_head(vxlan, mac, src_vni));
-
*fdb = f;
return 0;
}
-static void vxlan_fdb_free(struct rcu_head *head)
+static void __vxlan_fdb_free(struct vxlan_fdb *f)
{
- struct vxlan_fdb *f = container_of(head, struct vxlan_fdb, rcu);
struct vxlan_rdst *rd, *nd;
list_for_each_entry_safe(rd, nd, &f->remotes, list) {
@@ -853,6 +861,13 @@ static void vxlan_fdb_free(struct rcu_head *head)
kfree(f);
}
+static void vxlan_fdb_free(struct rcu_head *head)
+{
+ struct vxlan_fdb *f = container_of(head, struct vxlan_fdb, rcu);
+
+ __vxlan_fdb_free(f);
+}
+
static void vxlan_fdb_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f,
bool do_notify, bool swdev_notify)
{
@@ -980,6 +995,7 @@ static int vxlan_fdb_update_create(struct vxlan_dev *vxlan,
if (rc < 0)
return rc;
+ vxlan_fdb_insert(vxlan, mac, src_vni, f);
rc = vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_NEWNEIGH,
swdev_notify, extack);
if (rc)
@@ -1108,6 +1124,7 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
__be16 port;
__be32 src_vni, vni;
u32 ifindex;
+ u32 hash_index;
int err;
if (!(ndm->ndm_state & (NUD_PERMANENT|NUD_REACHABLE))) {
@@ -1126,12 +1143,13 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
if (vxlan->default_dst.remote_ip.sa.sa_family != ip.sa.sa_family)
return -EAFNOSUPPORT;
- spin_lock_bh(&vxlan->hash_lock);
+ hash_index = fdb_head_index(vxlan, addr, src_vni);
+ spin_lock_bh(&vxlan->hash_lock[hash_index]);
err = vxlan_fdb_update(vxlan, addr, &ip, ndm->ndm_state, flags,
port, src_vni, vni, ifindex,
ndm->ndm_flags | NTF_VXLAN_ADDED_BY_USER,
true, extack);
- spin_unlock_bh(&vxlan->hash_lock);
+ spin_unlock_bh(&vxlan->hash_lock[hash_index]);
return err;
}
@@ -1179,16 +1197,18 @@ static int vxlan_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
__be32 src_vni, vni;
__be16 port;
u32 ifindex;
+ u32 hash_index;
int err;
err = vxlan_fdb_parse(tb, vxlan, &ip, &port, &src_vni, &vni, &ifindex);
if (err)
return err;
- spin_lock_bh(&vxlan->hash_lock);
+ hash_index = fdb_head_index(vxlan, addr, src_vni);
+ spin_lock_bh(&vxlan->hash_lock[hash_index]);
err = __vxlan_fdb_delete(vxlan, addr, ip, port, src_vni, vni, ifindex,
true);
- spin_unlock_bh(&vxlan->hash_lock);
+ spin_unlock_bh(&vxlan->hash_lock[hash_index]);
return err;
}
@@ -1300,8 +1320,10 @@ static bool vxlan_snoop(struct net_device *dev,
f->updated = jiffies;
vxlan_fdb_notify(vxlan, f, rdst, RTM_NEWNEIGH, true, NULL);
} else {
+ u32 hash_index = fdb_head_index(vxlan, src_mac, vni);
+
/* learned new entry */
- spin_lock(&vxlan->hash_lock);
+ spin_lock(&vxlan->hash_lock[hash_index]);
/* close off race between vxlan_flush and incoming packets */
if (netif_running(dev))
@@ -1312,7 +1334,7 @@ static bool vxlan_snoop(struct net_device *dev,
vni,
vxlan->default_dst.remote_vni,
ifindex, NTF_SELF, true, NULL);
- spin_unlock(&vxlan->hash_lock);
+ spin_unlock(&vxlan->hash_lock[hash_index]);
}
return false;
@@ -1766,7 +1788,7 @@ static int vxlan_err_lookup(struct sock *sk, struct sk_buff *skb)
struct vxlanhdr *hdr;
__be32 vni;
- if (skb->len < VXLAN_HLEN)
+ if (!pskb_may_pull(skb, skb_transport_offset(skb) + VXLAN_HLEN))
return -EINVAL;
hdr = vxlan_hdr(skb);
@@ -2222,7 +2244,7 @@ static struct rtable *vxlan_get_route(struct vxlan_dev *vxlan, struct net_device
fl4.fl4_sport = sport;
rt = ip_route_output_key(vxlan->net, &fl4);
- if (likely(!IS_ERR(rt))) {
+ if (!IS_ERR(rt)) {
if (rt->dst.dev == dev) {
netdev_dbg(dev, "circular route to %pI4\n", &daddr);
ip_rt_put(rt);
@@ -2702,7 +2724,7 @@ static void vxlan_cleanup(struct timer_list *t)
for (h = 0; h < FDB_HASH_SIZE; ++h) {
struct hlist_node *p, *n;
- spin_lock(&vxlan->hash_lock);
+ spin_lock(&vxlan->hash_lock[h]);
hlist_for_each_safe(p, n, &vxlan->fdb_head[h]) {
struct vxlan_fdb *f
= container_of(p, struct vxlan_fdb, hlist);
@@ -2724,7 +2746,7 @@ static void vxlan_cleanup(struct timer_list *t)
} else if (time_before(timeout, next_timer))
next_timer = timeout;
}
- spin_unlock(&vxlan->hash_lock);
+ spin_unlock(&vxlan->hash_lock[h]);
}
mod_timer(&vxlan->age_timer, next_timer);
@@ -2767,12 +2789,13 @@ static int vxlan_init(struct net_device *dev)
static void vxlan_fdb_delete_default(struct vxlan_dev *vxlan, __be32 vni)
{
struct vxlan_fdb *f;
+ u32 hash_index = fdb_head_index(vxlan, all_zeros_mac, vni);
- spin_lock_bh(&vxlan->hash_lock);
+ spin_lock_bh(&vxlan->hash_lock[hash_index]);
f = __vxlan_find_mac(vxlan, all_zeros_mac, vni);
if (f)
vxlan_fdb_destroy(vxlan, f, true, true);
- spin_unlock_bh(&vxlan->hash_lock);
+ spin_unlock_bh(&vxlan->hash_lock[hash_index]);
}
static void vxlan_uninit(struct net_device *dev)
@@ -2817,9 +2840,10 @@ static void vxlan_flush(struct vxlan_dev *vxlan, bool do_all)
{
unsigned int h;
- spin_lock_bh(&vxlan->hash_lock);
for (h = 0; h < FDB_HASH_SIZE; ++h) {
struct hlist_node *p, *n;
+
+ spin_lock_bh(&vxlan->hash_lock[h]);
hlist_for_each_safe(p, n, &vxlan->fdb_head[h]) {
struct vxlan_fdb *f
= container_of(p, struct vxlan_fdb, hlist);
@@ -2829,8 +2853,8 @@ static void vxlan_flush(struct vxlan_dev *vxlan, bool do_all)
if (!is_zero_ether_addr(f->eth_addr))
vxlan_fdb_destroy(vxlan, f, true, true);
}
+ spin_unlock_bh(&vxlan->hash_lock[h]);
}
- spin_unlock_bh(&vxlan->hash_lock);
}
/* Cleanup timer and forwarding table on shutdown */
@@ -3014,7 +3038,6 @@ static void vxlan_setup(struct net_device *dev)
dev->max_mtu = ETH_MAX_MTU;
INIT_LIST_HEAD(&vxlan->next);
- spin_lock_init(&vxlan->hash_lock);
timer_setup(&vxlan->age_timer, vxlan_cleanup, TIMER_DEFERRABLE);
@@ -3022,8 +3045,10 @@ static void vxlan_setup(struct net_device *dev)
gro_cells_init(&vxlan->gro_cells, dev);
- for (h = 0; h < FDB_HASH_SIZE; ++h)
+ for (h = 0; h < FDB_HASH_SIZE; ++h) {
+ spin_lock_init(&vxlan->hash_lock[h]);
INIT_HLIST_HEAD(&vxlan->fdb_head[h]);
+ }
}
static void vxlan_ether_setup(struct net_device *dev)
@@ -3574,12 +3599,17 @@ static int __vxlan_dev_create(struct net *net, struct net_device *dev,
if (err)
goto errout;
- /* notify default fdb entry */
if (f) {
+ vxlan_fdb_insert(vxlan, all_zeros_mac,
+ vxlan->default_dst.remote_vni, f);
+
+ /* notify default fdb entry */
err = vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f),
RTM_NEWNEIGH, true, extack);
- if (err)
- goto errout;
+ if (err) {
+ vxlan_fdb_destroy(vxlan, f, false, false);
+ goto unregister;
+ }
}
list_add(&vxlan->next, &vn->vxlan_list);
@@ -3591,7 +3621,8 @@ errout:
* destroy the entry by hand here.
*/
if (f)
- vxlan_fdb_destroy(vxlan, f, false, false);
+ __vxlan_fdb_free(f);
+unregister:
if (unregister)
unregister_netdevice(dev);
return err;
@@ -3917,7 +3948,9 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[],
/* handle default dst entry */
if (!vxlan_addr_equal(&conf.remote_ip, &dst->remote_ip)) {
- spin_lock_bh(&vxlan->hash_lock);
+ u32 hash_index = fdb_head_index(vxlan, all_zeros_mac, conf.vni);
+
+ spin_lock_bh(&vxlan->hash_lock[hash_index]);
if (!vxlan_addr_any(&conf.remote_ip)) {
err = vxlan_fdb_update(vxlan, all_zeros_mac,
&conf.remote_ip,
@@ -3928,7 +3961,7 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[],
conf.remote_ifindex,
NTF_SELF, true, extack);
if (err) {
- spin_unlock_bh(&vxlan->hash_lock);
+ spin_unlock_bh(&vxlan->hash_lock[hash_index]);
return err;
}
}
@@ -3940,7 +3973,7 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[],
dst->remote_vni,
dst->remote_ifindex,
true);
- spin_unlock_bh(&vxlan->hash_lock);
+ spin_unlock_bh(&vxlan->hash_lock[hash_index]);
}
if (conf.age_interval != vxlan->cfg.age_interval)
@@ -4195,8 +4228,11 @@ vxlan_fdb_offloaded_set(struct net_device *dev,
struct vxlan_dev *vxlan = netdev_priv(dev);
struct vxlan_rdst *rdst;
struct vxlan_fdb *f;
+ u32 hash_index;
+
+ hash_index = fdb_head_index(vxlan, fdb_info->eth_addr, fdb_info->vni);
- spin_lock_bh(&vxlan->hash_lock);
+ spin_lock_bh(&vxlan->hash_lock[hash_index]);
f = vxlan_find_mac(vxlan, fdb_info->eth_addr, fdb_info->vni);
if (!f)
@@ -4212,7 +4248,7 @@ vxlan_fdb_offloaded_set(struct net_device *dev,
rdst->offloaded = fdb_info->offloaded;
out:
- spin_unlock_bh(&vxlan->hash_lock);
+ spin_unlock_bh(&vxlan->hash_lock[hash_index]);
}
static int
@@ -4221,11 +4257,13 @@ vxlan_fdb_external_learn_add(struct net_device *dev,
{
struct vxlan_dev *vxlan = netdev_priv(dev);
struct netlink_ext_ack *extack;
+ u32 hash_index;
int err;
+ hash_index = fdb_head_index(vxlan, fdb_info->eth_addr, fdb_info->vni);
extack = switchdev_notifier_info_to_extack(&fdb_info->info);
- spin_lock_bh(&vxlan->hash_lock);
+ spin_lock_bh(&vxlan->hash_lock[hash_index]);
err = vxlan_fdb_update(vxlan, fdb_info->eth_addr, &fdb_info->remote_ip,
NUD_REACHABLE,
NLM_F_CREATE | NLM_F_REPLACE,
@@ -4235,7 +4273,7 @@ vxlan_fdb_external_learn_add(struct net_device *dev,
fdb_info->remote_ifindex,
NTF_USE | NTF_SELF | NTF_EXT_LEARNED,
false, extack);
- spin_unlock_bh(&vxlan->hash_lock);
+ spin_unlock_bh(&vxlan->hash_lock[hash_index]);
return err;
}
@@ -4246,9 +4284,11 @@ vxlan_fdb_external_learn_del(struct net_device *dev,
{
struct vxlan_dev *vxlan = netdev_priv(dev);
struct vxlan_fdb *f;
+ u32 hash_index;
int err = 0;
- spin_lock_bh(&vxlan->hash_lock);
+ hash_index = fdb_head_index(vxlan, fdb_info->eth_addr, fdb_info->vni);
+ spin_lock_bh(&vxlan->hash_lock[hash_index]);
f = vxlan_find_mac(vxlan, fdb_info->eth_addr, fdb_info->vni);
if (!f)
@@ -4262,7 +4302,7 @@ vxlan_fdb_external_learn_del(struct net_device *dev,
fdb_info->remote_ifindex,
false);
- spin_unlock_bh(&vxlan->hash_lock);
+ spin_unlock_bh(&vxlan->hash_lock[hash_index]);
return err;
}
diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c
index 61d8f6389c64..a030f5aa6b95 100644
--- a/drivers/net/wan/hdlc_cisco.c
+++ b/drivers/net/wan/hdlc_cisco.c
@@ -193,16 +193,15 @@ static int cisco_rx(struct sk_buff *skb)
mask = ~cpu_to_be32(0); /* is the mask correct? */
if (in_dev != NULL) {
- struct in_ifaddr **ifap = &in_dev->ifa_list;
+ const struct in_ifaddr *ifa;
- while (*ifap != NULL) {
+ in_dev_for_each_ifa_rcu(ifa, in_dev) {
if (strcmp(dev->name,
- (*ifap)->ifa_label) == 0) {
- addr = (*ifap)->ifa_local;
- mask = (*ifap)->ifa_mask;
+ ifa->ifa_label) == 0) {
+ addr = ifa->ifa_local;
+ mask = ifa->ifa_mask;
break;
}
- ifap = &(*ifap)->ifa_next;
}
cisco_keepalive_send(dev, CISCO_ADDR_REPLY,
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index d78bc838d631..914be5847386 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -602,8 +602,8 @@ static void x25_asy_close_tty(struct tty_struct *tty)
err = lapb_unregister(sl->dev);
if (err != LAPB_OK)
- pr_err("x25_asy_close: lapb_unregister error: %d\n",
- err);
+ pr_err("%s: lapb_unregister error: %d\n",
+ __func__, err);
tty->disc_data = NULL;
sl->tty = NULL;
diff --git a/drivers/net/wireless/admtek/adm8211.c b/drivers/net/wireless/admtek/adm8211.c
index 3b0802fc5bf5..46f1427e6e9e 100644
--- a/drivers/net/wireless/admtek/adm8211.c
+++ b/drivers/net/wireless/admtek/adm8211.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Linux device driver for ADMtek ADM8211 (IEEE 802.11b MAC/BBP)
@@ -8,11 +9,6 @@
* and used with permission.
*
* Much thanks to Infineon-ADMtek for their support of this driver.
- *
- * 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. See README and COPYING for
- * more details.
*/
#include <linux/interrupt.h>
diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig
index af2049e99188..d98d6ac90f3d 100644
--- a/drivers/net/wireless/ath/Kconfig
+++ b/drivers/net/wireless/ath/Kconfig
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0-only
+# SPDX-License-Identifier: ISC
config ATH_COMMON
tristate
diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile
index e4e460b5498e..ee2b2431e5a3 100644
--- a/drivers/net/wireless/ath/Makefile
+++ b/drivers/net/wireless/ath/Makefile
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: ISC
obj-$(CONFIG_ATH5K) += ath5k/
obj-$(CONFIG_ATH9K_HW) += ath9k/
obj-$(CONFIG_CARL9170) += carl9170/
diff --git a/drivers/net/wireless/ath/ar5523/Kconfig b/drivers/net/wireless/ath/ar5523/Kconfig
index 75fc66983da5..41d3c9a48b08 100644
--- a/drivers/net/wireless/ath/ar5523/Kconfig
+++ b/drivers/net/wireless/ath/ar5523/Kconfig
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0-only
+# SPDX-License-Identifier: ISC
config AR5523
tristate "Atheros AR5523 wireless driver support"
depends on MAC80211 && USB
diff --git a/drivers/net/wireless/ath/ar5523/Makefile b/drivers/net/wireless/ath/ar5523/Makefile
index 84fc88aa109e..34efa5772096 100644
--- a/drivers/net/wireless/ath/ar5523/Makefile
+++ b/drivers/net/wireless/ath/ar5523/Makefile
@@ -1,2 +1,2 @@
-# SPDX-License-Identifier: GPL-2.0-only
+# SPDX-License-Identifier: ISC
obj-$(CONFIG_AR5523) := ar5523.o
diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig
index 3522f251fa7f..6b3ff02a373d 100644
--- a/drivers/net/wireless/ath/ath10k/Kconfig
+++ b/drivers/net/wireless/ath/ath10k/Kconfig
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0-only
+# SPDX-License-Identifier: ISC
config ATH10K
tristate "Atheros 802.11ac wireless cards support"
depends on MAC80211 && HAS_DMA
diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c
index 0bf726c55736..f80854180e21 100644
--- a/drivers/net/wireless/ath/ath10k/ahb.c
+++ b/drivers/net/wireless/ath/ath10k/ahb.c
@@ -740,7 +740,7 @@ static int ath10k_ahb_probe(struct platform_device *pdev)
enum ath10k_hw_rev hw_rev;
size_t size;
int ret;
- struct ath10k_bus_params bus_params;
+ struct ath10k_bus_params bus_params = {};
of_id = of_match_device(ath10k_ahb_of_match, &pdev->dev);
if (!of_id) {
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index aff585658fc0..dc45d16e8d21 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -2,7 +2,7 @@
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
@@ -26,10 +26,13 @@
#include "coredump.h"
unsigned int ath10k_debug_mask;
+EXPORT_SYMBOL(ath10k_debug_mask);
+
static unsigned int ath10k_cryptmode_param;
static bool uart_print;
static bool skip_otp;
static bool rawmode;
+static bool fw_diag_log;
unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) |
BIT(ATH10K_FW_CRASH_DUMP_CE_DATA);
@@ -40,6 +43,7 @@ module_param_named(cryptmode, ath10k_cryptmode_param, uint, 0644);
module_param(uart_print, bool, 0644);
module_param(skip_otp, bool, 0644);
module_param(rawmode, bool, 0644);
+module_param(fw_diag_log, bool, 0644);
module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444);
MODULE_PARM_DESC(debug_mask, "Debugging mask");
@@ -48,6 +52,7 @@ MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode");
MODULE_PARM_DESC(cryptmode, "Crypto mode: 0-hardware, 1-software");
MODULE_PARM_DESC(rawmode, "Use raw 802.11 frame datapath");
MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file");
+MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging");
static const struct ath10k_hw_params ath10k_hw_params_list[] = {
{
@@ -83,6 +88,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.rri_on_ddr = false,
.hw_filter_reset_required = true,
.fw_diag_ce_download = false,
+ .tx_stats_over_pktlog = true,
},
{
.id = QCA988X_HW_2_0_VERSION,
@@ -117,6 +123,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.rri_on_ddr = false,
.hw_filter_reset_required = true,
.fw_diag_ce_download = false,
+ .tx_stats_over_pktlog = true,
},
{
.id = QCA9887_HW_1_0_VERSION,
@@ -152,6 +159,35 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.rri_on_ddr = false,
.hw_filter_reset_required = true,
.fw_diag_ce_download = false,
+ .tx_stats_over_pktlog = false,
+ },
+ {
+ .id = QCA6174_HW_3_2_VERSION,
+ .dev_id = QCA6174_3_2_DEVICE_ID,
+ .bus = ATH10K_BUS_SDIO,
+ .name = "qca6174 hw3.2 sdio",
+ .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR,
+ .uart_pin = 19,
+ .otp_exe_param = 0,
+ .channel_counters_freq_hz = 88000,
+ .max_probe_resp_desc_thres = 0,
+ .cal_data_len = 0,
+ .fw = {
+ .dir = QCA6174_HW_3_0_FW_DIR,
+ .board = QCA6174_HW_3_0_BOARD_DATA_FILE,
+ .board_size = QCA6174_BOARD_DATA_SZ,
+ .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,
+ },
+ .hw_ops = &qca6174_sdio_ops,
+ .hw_clk = qca6174_clk,
+ .target_cpu_freq = 176000000,
+ .decap_align_bytes = 4,
+ .n_cipher_suites = 8,
+ .num_peers = 10,
+ .ast_skid_limit = 0x10,
+ .num_wds_entries = 0x20,
+ .uart_pin_workaround = true,
+ .tx_stats_over_pktlog = false,
},
{
.id = QCA6174_HW_2_1_VERSION,
@@ -186,6 +222,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.rri_on_ddr = false,
.hw_filter_reset_required = true,
.fw_diag_ce_download = false,
+ .tx_stats_over_pktlog = false,
},
{
.id = QCA6174_HW_2_1_VERSION,
@@ -220,6 +257,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.rri_on_ddr = false,
.hw_filter_reset_required = true,
.fw_diag_ce_download = false,
+ .tx_stats_over_pktlog = false,
},
{
.id = QCA6174_HW_3_0_VERSION,
@@ -254,6 +292,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.rri_on_ddr = false,
.hw_filter_reset_required = true,
.fw_diag_ce_download = false,
+ .tx_stats_over_pktlog = false,
},
{
.id = QCA6174_HW_3_2_VERSION,
@@ -291,6 +330,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.rri_on_ddr = false,
.hw_filter_reset_required = true,
.fw_diag_ce_download = true,
+ .tx_stats_over_pktlog = false,
},
{
.id = QCA99X0_HW_2_0_DEV_VERSION,
@@ -331,6 +371,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.rri_on_ddr = false,
.hw_filter_reset_required = true,
.fw_diag_ce_download = false,
+ .tx_stats_over_pktlog = false,
},
{
.id = QCA9984_HW_1_0_DEV_VERSION,
@@ -378,6 +419,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.rri_on_ddr = false,
.hw_filter_reset_required = true,
.fw_diag_ce_download = false,
+ .tx_stats_over_pktlog = false,
},
{
.id = QCA9888_HW_2_0_DEV_VERSION,
@@ -422,6 +464,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.rri_on_ddr = false,
.hw_filter_reset_required = true,
.fw_diag_ce_download = false,
+ .tx_stats_over_pktlog = false,
},
{
.id = QCA9377_HW_1_0_DEV_VERSION,
@@ -456,6 +499,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.rri_on_ddr = false,
.hw_filter_reset_required = true,
.fw_diag_ce_download = false,
+ .tx_stats_over_pktlog = false,
},
{
.id = QCA9377_HW_1_1_DEV_VERSION,
@@ -492,6 +536,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.rri_on_ddr = false,
.hw_filter_reset_required = true,
.fw_diag_ce_download = true,
+ .tx_stats_over_pktlog = false,
},
{
.id = QCA4019_HW_1_0_DEV_VERSION,
@@ -533,6 +578,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.rri_on_ddr = false,
.hw_filter_reset_required = true,
.fw_diag_ce_download = false,
+ .tx_stats_over_pktlog = false,
},
{
.id = WCN3990_HW_1_0_DEV_VERSION,
@@ -560,6 +606,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.rri_on_ddr = true,
.hw_filter_reset_required = false,
.fw_diag_ce_download = false,
+ .tx_stats_over_pktlog = false,
},
};
@@ -585,6 +632,7 @@ static const char *const ath10k_core_fw_feature_str[] = {
[ATH10K_FW_FEATURE_MGMT_TX_BY_REF] = "mgmt-tx-by-reference",
[ATH10K_FW_FEATURE_NON_BMI] = "non-bmi",
[ATH10K_FW_FEATURE_SINGLE_CHAN_INFO_PER_CHANNEL] = "single-chan-info-per-channel",
+ [ATH10K_FW_FEATURE_PEER_FIXED_RATE] = "peer-fixed-rate",
};
static unsigned int ath10k_core_get_fw_feature_str(char *buf,
@@ -629,7 +677,7 @@ static void ath10k_send_suspend_complete(struct ath10k *ar)
complete(&ar->target_suspend);
}
-static void ath10k_init_sdio(struct ath10k *ar)
+static void ath10k_init_sdio(struct ath10k *ar, enum ath10k_firmware_mode mode)
{
u32 param = 0;
@@ -646,7 +694,12 @@ static void ath10k_init_sdio(struct ath10k *ar)
* not big enough for mac80211 / native wifi frames. disable it
*/
param &= ~HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE;
- param |= HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET;
+
+ if (mode == ATH10K_FIRMWARE_MODE_UTF)
+ param &= ~HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET;
+ else
+ param |= HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET;
+
ath10k_bmi_write32(ar, hi_acs_flags, param);
/* Explicitly set fwlog prints to zero as target may turn it on
@@ -2065,8 +2118,16 @@ static int ath10k_init_uart(struct ath10k *ar)
return ret;
}
- if (!uart_print)
+ if (!uart_print && ar->hw_params.uart_pin_workaround) {
+ ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin,
+ ar->hw_params.uart_pin);
+ if (ret) {
+ ath10k_warn(ar, "failed to set UART TX pin: %d", ret);
+ return ret;
+ }
+
return 0;
+ }
ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, ar->hw_params.uart_pin);
if (ret) {
@@ -2139,6 +2200,7 @@ static void ath10k_core_restart(struct work_struct *work)
complete(&ar->offchan_tx_completed);
complete(&ar->install_key_done);
complete(&ar->vdev_setup_done);
+ complete(&ar->vdev_delete_done);
complete(&ar->thermal.wmi_sync);
complete(&ar->bss_survey_done);
wake_up(&ar->htt.empty_tx_wq);
@@ -2501,7 +2563,7 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
goto err;
if (ar->hif.bus == ATH10K_BUS_SDIO)
- ath10k_init_sdio(ar);
+ ath10k_init_sdio(ar, mode);
}
ar->htc.htc_ops.target_send_suspend_complete =
@@ -2720,6 +2782,12 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
if (status)
goto err_hif_stop;
+ status = ath10k_hif_set_target_log_mode(ar, fw_diag_log);
+ if (status && status != -EOPNOTSUPP) {
+ ath10k_warn(ar, "set traget log mode faileds: %d\n", status);
+ goto err_hif_stop;
+ }
+
return 0;
err_hif_stop:
@@ -3105,8 +3173,10 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
init_completion(&ar->install_key_done);
init_completion(&ar->vdev_setup_done);
+ init_completion(&ar->vdev_delete_done);
init_completion(&ar->thermal.wmi_sync);
init_completion(&ar->bss_survey_done);
+ init_completion(&ar->peer_delete_done);
INIT_DELAYED_WORK(&ar->scan.timeout, ath10k_scan_timeout_work);
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index e35aae5146f1..4d7db07db6ba 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -2,7 +2,7 @@
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*/
#ifndef _CORE_H_
@@ -196,7 +196,7 @@ struct ath10k_fw_extd_stats_peer {
struct list_head list;
u8 peer_macaddr[ETH_ALEN];
- u32 rx_duration;
+ u64 rx_duration;
};
struct ath10k_fw_stats_vdev {
@@ -400,6 +400,14 @@ struct ath10k_peer {
/* protected by ar->data_lock */
struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1];
+ union htt_rx_pn_t tids_last_pn[ATH10K_TXRX_NUM_EXT_TIDS];
+ bool tids_last_pn_valid[ATH10K_TXRX_NUM_EXT_TIDS];
+ union htt_rx_pn_t frag_tids_last_pn[ATH10K_TXRX_NUM_EXT_TIDS];
+ u32 frag_tids_seq[ATH10K_TXRX_NUM_EXT_TIDS];
+ struct {
+ enum htt_security_types sec_type;
+ int pn_len;
+ } rx_pn[ATH10K_HTT_TXRX_PEER_SECURITY_MAX];
};
struct ath10k_txq {
@@ -506,7 +514,8 @@ struct ath10k_sta {
u32 peer_ps_state;
};
-#define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5 * HZ)
+#define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5 * HZ)
+#define ATH10K_VDEV_DELETE_TIMEOUT_HZ (5 * HZ)
enum ath10k_beacon_state {
ATH10K_BEACON_SCHEDULED = 0,
@@ -571,6 +580,10 @@ struct ath10k_vif {
struct work_struct ap_csa_work;
struct delayed_work connection_loss_work;
struct cfg80211_bitrate_mask bitrate_mask;
+
+ /* For setting VHT peer fixed rate, protected by conf_mutex */
+ int vht_num_rates;
+ u8 vht_pfr;
};
struct ath10k_vif_iter {
@@ -614,6 +627,7 @@ struct ath10k_debug {
bool fw_stats_done;
unsigned long htt_stats_mask;
+ unsigned long reset_htt_stats;
struct delayed_work htt_stats_dwork;
struct ath10k_dfs_stats dfs_stats;
struct ath_dfs_pool_stats dfs_pool_stats;
@@ -631,6 +645,7 @@ struct ath10k_debug {
u32 nf_cal_period;
void *cal_data;
u32 enable_extd_tx_stats;
+ u8 fw_dbglog_mode;
};
enum ath10k_state {
@@ -761,6 +776,9 @@ enum ath10k_fw_features {
/* Firmware sends only one chan_info event per channel */
ATH10K_FW_FEATURE_SINGLE_CHAN_INFO_PER_CHANNEL = 20,
+ /* Firmware allows setting peer fixed rate */
+ ATH10K_FW_FEATURE_PEER_FIXED_RATE = 21,
+
/* keep last */
ATH10K_FW_FEATURE_COUNT,
};
@@ -919,6 +937,7 @@ struct ath10k_bus_params {
u32 chip_id;
enum ath10k_dev_type dev_type;
bool link_can_suspend;
+ bool hl_msdu_ids;
};
struct ath10k {
@@ -1055,6 +1074,7 @@ struct ath10k {
int last_wmi_vdev_start_status;
struct completion vdev_setup_done;
+ struct completion vdev_delete_done;
struct workqueue_struct *workqueue;
/* Auxiliary workqueue */
@@ -1189,6 +1209,7 @@ struct ath10k {
struct ath10k_radar_found_info last_radar_info;
struct work_struct radar_confirmation_work;
struct ath10k_bus_params bus_param;
+ struct completion peer_delete_done;
/* must be last */
u8 drv_priv[0] __aligned(sizeof(void *));
diff --git a/drivers/net/wireless/ath/ath10k/coredump.c b/drivers/net/wireless/ath/ath10k/coredump.c
index 45a355fb62b9..b6d2932383cf 100644
--- a/drivers/net/wireless/ath/ath10k/coredump.c
+++ b/drivers/net/wireless/ath/ath10k/coredump.c
@@ -1192,8 +1192,8 @@ static struct ath10k_dump_file_data *ath10k_coredump_build(struct ath10k *ar)
if (test_bit(ATH10K_FW_CRASH_DUMP_CE_DATA, &ath10k_coredump_mask)) {
dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_CE_DATA);
- dump_tlv->tlv_len = cpu_to_le32(sizeof(*ce_hdr) +
- CE_COUNT * sizeof(ce_hdr->entries[0]));
+ dump_tlv->tlv_len = cpu_to_le32(struct_size(ce_hdr, entries,
+ CE_COUNT));
ce_hdr = (struct ath10k_ce_crash_hdr *)(dump_tlv->tlv_data);
ce_hdr->ce_count = cpu_to_le32(CE_COUNT);
memset(ce_hdr->reserved, 0, sizeof(ce_hdr->reserved));
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index 32d967a31c65..bd2b5628f850 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -305,6 +305,9 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
if (is_end)
ar->debug.fw_stats_done = true;
+ if (stats.extended)
+ ar->debug.fw_stats.extended = true;
+
is_started = !list_empty(&ar->debug.fw_stats.pdevs);
if (is_started && !is_end) {
@@ -873,7 +876,7 @@ static int ath10k_debug_htt_stats_req(struct ath10k *ar)
cookie = get_jiffies_64();
ret = ath10k_htt_h2t_stats_req(&ar->htt, ar->debug.htt_stats_mask,
- cookie);
+ ar->debug.reset_htt_stats, cookie);
if (ret) {
ath10k_warn(ar, "failed to send htt stats request: %d\n", ret);
return ret;
@@ -922,8 +925,8 @@ static ssize_t ath10k_write_htt_stats_mask(struct file *file,
if (ret)
return ret;
- /* max 8 bit masks (for now) */
- if (mask > 0xff)
+ /* max 17 bit masks (for now) */
+ if (mask > HTT_STATS_BIT_MASK)
return -E2BIG;
mutex_lock(&ar->conf_mutex);
@@ -2469,6 +2472,44 @@ static const struct file_operations fops_ps_state_enable = {
.llseek = default_llseek,
};
+static ssize_t ath10k_write_reset_htt_stats(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ unsigned long reset;
+ int ret;
+
+ ret = kstrtoul_from_user(user_buf, count, 0, &reset);
+ if (ret)
+ return ret;
+
+ if (reset == 0 || reset > 0x1ffff)
+ return -EINVAL;
+
+ mutex_lock(&ar->conf_mutex);
+
+ ar->debug.reset_htt_stats = reset;
+
+ ret = ath10k_debug_htt_stats_req(ar);
+ if (ret)
+ goto out;
+
+ ar->debug.reset_htt_stats = 0;
+ ret = count;
+
+out:
+ mutex_unlock(&ar->conf_mutex);
+ return ret;
+}
+
+static const struct file_operations fops_reset_htt_stats = {
+ .write = ath10k_write_reset_htt_stats,
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .llseek = default_llseek,
+};
+
int ath10k_debug_create(struct ath10k *ar)
{
ar->debug.cal_data = vzalloc(ATH10K_DEBUG_CAL_DATA_LEN);
@@ -2609,6 +2650,9 @@ int ath10k_debug_register(struct ath10k *ar)
debugfs_create_file("ps_state_enable", 0600, ar->debug.debugfs_phy, ar,
&fops_ps_state_enable);
+ debugfs_create_file("reset_htt_stats", 0200, ar->debug.debugfs_phy, ar,
+ &fops_reset_htt_stats);
+
return 0;
}
@@ -2620,8 +2664,8 @@ void ath10k_debug_unregister(struct ath10k *ar)
#endif /* CONFIG_ATH10K_DEBUGFS */
#ifdef CONFIG_ATH10K_DEBUG
-void ath10k_dbg(struct ath10k *ar, enum ath10k_debug_mask mask,
- const char *fmt, ...)
+void __ath10k_dbg(struct ath10k *ar, enum ath10k_debug_mask mask,
+ const char *fmt, ...)
{
struct va_format vaf;
va_list args;
@@ -2638,7 +2682,7 @@ void ath10k_dbg(struct ath10k *ar, enum ath10k_debug_mask mask,
va_end(args);
}
-EXPORT_SYMBOL(ath10k_dbg);
+EXPORT_SYMBOL(__ath10k_dbg);
void ath10k_dbg_dump(struct ath10k *ar,
enum ath10k_debug_mask mask,
@@ -2651,7 +2695,7 @@ void ath10k_dbg_dump(struct ath10k *ar,
if (ath10k_debug_mask & mask) {
if (msg)
- ath10k_dbg(ar, mask, "%s\n", msg);
+ __ath10k_dbg(ar, mask, "%s\n", msg);
for (ptr = buf; (ptr - buf) < len; ptr += 16) {
linebuflen = 0;
diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
index db78e855a80f..82f7eb8583d9 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -71,6 +71,9 @@ struct ath10k_pktlog_hdr {
/* FIXME: How to calculate the buffer size sanely? */
#define ATH10K_FW_STATS_BUF_SIZE (1024 * 1024)
+#define ATH10K_TX_POWER_MAX_VAL 70
+#define ATH10K_TX_POWER_MIN_VAL 0
+
extern unsigned int ath10k_debug_mask;
__printf(2, 3) void ath10k_info(struct ath10k *ar, const char *fmt, ...);
@@ -240,18 +243,18 @@ void ath10k_sta_update_rx_tid_stats_ampdu(struct ath10k *ar,
#endif /* CONFIG_MAC80211_DEBUGFS */
#ifdef CONFIG_ATH10K_DEBUG
-__printf(3, 4) void ath10k_dbg(struct ath10k *ar,
- enum ath10k_debug_mask mask,
- const char *fmt, ...);
+__printf(3, 4) void __ath10k_dbg(struct ath10k *ar,
+ enum ath10k_debug_mask mask,
+ const char *fmt, ...);
void ath10k_dbg_dump(struct ath10k *ar,
enum ath10k_debug_mask mask,
const char *msg, const char *prefix,
const void *buf, size_t len);
#else /* CONFIG_ATH10K_DEBUG */
-static inline int ath10k_dbg(struct ath10k *ar,
- enum ath10k_debug_mask dbg_mask,
- const char *fmt, ...)
+static inline int __ath10k_dbg(struct ath10k *ar,
+ enum ath10k_debug_mask dbg_mask,
+ const char *fmt, ...)
{
return 0;
}
@@ -263,4 +266,14 @@ static inline void ath10k_dbg_dump(struct ath10k *ar,
{
}
#endif /* CONFIG_ATH10K_DEBUG */
+
+/* Avoid calling __ath10k_dbg() if debug_mask is not set and tracing
+ * disabled.
+ */
+#define ath10k_dbg(ar, dbg_mask, fmt, ...) \
+do { \
+ if ((ath10k_debug_mask & dbg_mask) || \
+ trace_ath10k_log_dbg_enabled()) \
+ __ath10k_dbg(ar, dbg_mask, fmt, ##__VA_ARGS__); \
+} while (0)
#endif /* _DEBUG_H_ */
diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c
index c704ae371c4d..42931a669b02 100644
--- a/drivers/net/wireless/ath/ath10k/debugfs_sta.c
+++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c
@@ -663,6 +663,13 @@ static ssize_t ath10k_dbg_sta_dump_tx_stats(struct file *file,
mutex_lock(&ar->conf_mutex);
+ if (!arsta->tx_stats) {
+ ath10k_warn(ar, "failed to get tx stats");
+ mutex_unlock(&ar->conf_mutex);
+ kfree(buf);
+ return 0;
+ }
+
spin_lock_bh(&ar->data_lock);
for (k = 0; k < ATH10K_STATS_TYPE_MAX; k++) {
for (j = 0; j < ATH10K_COUNTER_TYPE_MAX; j++) {
diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h
index fe5417962f40..496ee34a4d78 100644
--- a/drivers/net/wireless/ath/ath10k/hif.h
+++ b/drivers/net/wireless/ath/ath10k/hif.h
@@ -12,6 +12,12 @@
#include "bmi.h"
#include "debug.h"
+/* Types of fw logging mode */
+enum ath_dbg_mode {
+ ATH10K_ENABLE_FW_LOG_DIAG,
+ ATH10K_ENABLE_FW_LOG_CE,
+};
+
struct ath10k_hif_sg_item {
u16 transfer_id;
void *transfer_context; /* NULL = tx completion callback not called */
@@ -88,6 +94,7 @@ struct ath10k_hif_ops {
int (*get_target_info)(struct ath10k *ar,
struct bmi_target_info *target_info);
+ int (*set_target_log_mode)(struct ath10k *ar, u8 fw_log_mode);
};
static inline int ath10k_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
@@ -230,4 +237,12 @@ static inline int ath10k_hif_get_target_info(struct ath10k *ar,
return ar->hif.ops->get_target_info(ar, tgt_info);
}
+static inline int ath10k_hif_set_target_log_mode(struct ath10k *ar,
+ u8 fw_log_mode)
+{
+ if (!ar->hif.ops->set_target_log_mode)
+ return -EOPNOTSUPP;
+
+ return ar->hif.ops->set_target_log_mode(ar, fw_log_mode);
+}
#endif /* _HIF_H_ */
diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c
index 805a7f8a04f2..1d4d1a1992fe 100644
--- a/drivers/net/wireless/ath/ath10k/htc.c
+++ b/drivers/net/wireless/ath/ath10k/htc.c
@@ -73,6 +73,7 @@ static void ath10k_htc_prepare_tx_skb(struct ath10k_htc_ep *ep,
struct ath10k_htc_hdr *hdr;
hdr = (struct ath10k_htc_hdr *)skb->data;
+ memset(hdr, 0, sizeof(struct ath10k_htc_hdr));
hdr->eid = ep->eid;
hdr->len = __cpu_to_le16(skb->len - sizeof(*hdr));
diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c
index d235ff3098e8..7b75200ceae5 100644
--- a/drivers/net/wireless/ath/ath10k/htt.c
+++ b/drivers/net/wireless/ath/ath10k/htt.c
@@ -257,7 +257,7 @@ int ath10k_htt_setup(struct ath10k_htt *htt)
return status;
}
- status = htt->tx_ops->htt_h2t_aggr_cfg_msg(htt,
+ status = ath10k_htt_h2t_aggr_cfg_msg(htt,
htt->max_num_ampdu,
htt->max_num_amsdu);
if (status) {
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index 4cee5492abc8..30c080094af1 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -315,6 +315,7 @@ struct htt_stats_req {
} __packed;
#define HTT_STATS_REQ_CFG_STAT_TYPE_INVALID 0xff
+#define HTT_STATS_BIT_MASK GENMASK(16, 0)
/*
* htt_oob_sync_req - request out-of-band sync
@@ -733,6 +734,20 @@ struct htt_rx_indication_hl {
struct htt_rx_indication_mpdu_range mpdu_ranges[0];
} __packed;
+struct htt_hl_rx_desc {
+ __le32 info;
+ __le32 pn_31_0;
+ union {
+ struct {
+ __le16 pn_47_32;
+ __le16 pn_63_48;
+ } pn16;
+ __le32 pn_63_32;
+ } u0;
+ __le32 pn_95_64;
+ __le32 pn_127_96;
+} __packed;
+
static inline struct htt_rx_indication_mpdu_range *
htt_rx_ind_get_mpdu_ranges(struct htt_rx_indication *rx_ind)
{
@@ -790,6 +805,21 @@ struct htt_rx_peer_unmap {
__le16 peer_id;
} __packed;
+enum htt_txrx_sec_cast_type {
+ HTT_TXRX_SEC_MCAST = 0,
+ HTT_TXRX_SEC_UCAST
+};
+
+enum htt_rx_pn_check_type {
+ HTT_RX_NON_PN_CHECK = 0,
+ HTT_RX_PN_CHECK
+};
+
+enum htt_rx_tkip_demic_type {
+ HTT_RX_NON_TKIP_MIC = 0,
+ HTT_RX_TKIP_MIC
+};
+
enum htt_security_types {
HTT_SECURITY_NONE,
HTT_SECURITY_WEP128,
@@ -803,6 +833,9 @@ enum htt_security_types {
HTT_NUM_SECURITY_TYPES /* keep this last! */
};
+#define ATH10K_HTT_TXRX_PEER_SECURITY_MAX 2
+#define ATH10K_TXRX_NUM_EXT_TIDS 19
+
enum htt_security_flags {
#define HTT_SECURITY_TYPE_MASK 0x7F
#define HTT_SECURITY_TYPE_LSB 0
@@ -1010,6 +1043,11 @@ struct htt_rx_fragment_indication {
u8 fw_msdu_rx_desc[0];
} __packed;
+#define ATH10K_IEEE80211_EXTIV BIT(5)
+#define ATH10K_IEEE80211_TKIP_MICLEN 8 /* trailing MIC */
+
+#define HTT_RX_FRAG_IND_INFO0_HEADER_LEN 16
+
#define HTT_RX_FRAG_IND_INFO0_EXT_TID_MASK 0x1F
#define HTT_RX_FRAG_IND_INFO0_EXT_TID_LSB 0
#define HTT_RX_FRAG_IND_INFO0_FLUSH_VALID_MASK 0x20
@@ -2048,6 +2086,19 @@ static inline void ath10k_htt_free_txbuff(struct ath10k_htt *htt)
htt->tx_ops->htt_free_txbuff(htt);
}
+static inline int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
+ u8 max_subfrms_ampdu,
+ u8 max_subfrms_amsdu)
+
+{
+ if (!htt->tx_ops->htt_h2t_aggr_cfg_msg)
+ return -EOPNOTSUPP;
+
+ return htt->tx_ops->htt_h2t_aggr_cfg_msg(htt,
+ max_subfrms_ampdu,
+ max_subfrms_amsdu);
+}
+
struct ath10k_htt_rx_ops {
size_t (*htt_get_rx_ring_size)(struct ath10k_htt *htt);
void (*htt_config_paddrs_ring)(struct ath10k_htt *htt, void *vaddr);
@@ -2055,6 +2106,9 @@ struct ath10k_htt_rx_ops {
int idx);
void* (*htt_get_vaddr_ring)(struct ath10k_htt *htt);
void (*htt_reset_paddrs_ring)(struct ath10k_htt *htt, int idx);
+ bool (*htt_rx_proc_rx_frag_ind)(struct ath10k_htt *htt,
+ struct htt_rx_fragment_indication *rx,
+ struct sk_buff *skb);
};
static inline size_t ath10k_htt_get_rx_ring_size(struct ath10k_htt *htt)
@@ -2094,6 +2148,16 @@ static inline void ath10k_htt_reset_paddrs_ring(struct ath10k_htt *htt, int idx)
htt->rx_ops->htt_reset_paddrs_ring(htt, idx);
}
+static inline bool ath10k_htt_rx_proc_rx_frag_ind(struct ath10k_htt *htt,
+ struct htt_rx_fragment_indication *rx,
+ struct sk_buff *skb)
+{
+ if (!htt->rx_ops->htt_rx_proc_rx_frag_ind)
+ return true;
+
+ return htt->rx_ops->htt_rx_proc_rx_frag_ind(htt, rx, skb);
+}
+
#define RX_HTT_HDR_STATUS_LEN 64
/* This structure layout is programmed via rx ring setup
@@ -2128,10 +2192,8 @@ struct htt_rx_desc {
#define HTT_RX_DESC_HL_INFO_ENCRYPTED_LSB 12
#define HTT_RX_DESC_HL_INFO_CHAN_INFO_PRESENT_MASK 0x00002000
#define HTT_RX_DESC_HL_INFO_CHAN_INFO_PRESENT_LSB 13
-#define HTT_RX_DESC_HL_INFO_MCAST_BCAST_MASK 0x00008000
-#define HTT_RX_DESC_HL_INFO_MCAST_BCAST_LSB 15
-#define HTT_RX_DESC_HL_INFO_FRAGMENT_MASK 0x00010000
-#define HTT_RX_DESC_HL_INFO_FRAGMENT_LSB 16
+#define HTT_RX_DESC_HL_INFO_MCAST_BCAST_MASK 0x00010000
+#define HTT_RX_DESC_HL_INFO_MCAST_BCAST_LSB 16
#define HTT_RX_DESC_HL_INFO_KEY_ID_OCT_MASK 0x01fe0000
#define HTT_RX_DESC_HL_INFO_KEY_ID_OCT_LSB 17
@@ -2195,10 +2257,8 @@ void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb);
void ath10k_htt_htc_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb);
bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb);
int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt);
-int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie);
-int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
- u8 max_subfrms_ampdu,
- u8 max_subfrms_amsdu);
+int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u32 mask, u32 reset_mask,
+ u64 cookie);
void ath10k_htt_hif_tx_complete(struct ath10k *ar, struct sk_buff *skb);
int ath10k_htt_tx_fetch_resp(struct ath10k *ar,
__le32 token,
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 1acc622d2183..83a7fb68fd24 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -2061,9 +2061,91 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt)
return 0;
}
+static void ath10k_htt_rx_mpdu_desc_pn_hl(struct htt_hl_rx_desc *rx_desc,
+ union htt_rx_pn_t *pn,
+ int pn_len_bits)
+{
+ switch (pn_len_bits) {
+ case 48:
+ pn->pn48 = __le32_to_cpu(rx_desc->pn_31_0) +
+ ((u64)(__le32_to_cpu(rx_desc->u0.pn_63_32) & 0xFFFF) << 32);
+ break;
+ case 24:
+ pn->pn24 = __le32_to_cpu(rx_desc->pn_31_0);
+ break;
+ };
+}
+
+static bool ath10k_htt_rx_pn_cmp48(union htt_rx_pn_t *new_pn,
+ union htt_rx_pn_t *old_pn)
+{
+ return ((new_pn->pn48 & 0xffffffffffffULL) <=
+ (old_pn->pn48 & 0xffffffffffffULL));
+}
+
+static bool ath10k_htt_rx_pn_check_replay_hl(struct ath10k *ar,
+ struct ath10k_peer *peer,
+ struct htt_rx_indication_hl *rx)
+{
+ bool last_pn_valid, pn_invalid = false;
+ enum htt_txrx_sec_cast_type sec_index;
+ enum htt_security_types sec_type;
+ union htt_rx_pn_t new_pn = {0};
+ struct htt_hl_rx_desc *rx_desc;
+ union htt_rx_pn_t *last_pn;
+ u32 rx_desc_info, tid;
+ int num_mpdu_ranges;
+
+ lockdep_assert_held(&ar->data_lock);
+
+ if (!peer)
+ return false;
+
+ if (!(rx->fw_desc.flags & FW_RX_DESC_FLAGS_FIRST_MSDU))
+ return false;
+
+ num_mpdu_ranges = MS(__le32_to_cpu(rx->hdr.info1),
+ HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES);
+
+ rx_desc = (struct htt_hl_rx_desc *)&rx->mpdu_ranges[num_mpdu_ranges];
+ rx_desc_info = __le32_to_cpu(rx_desc->info);
+
+ if (!MS(rx_desc_info, HTT_RX_DESC_HL_INFO_ENCRYPTED))
+ return false;
+
+ tid = MS(rx->hdr.info0, HTT_RX_INDICATION_INFO0_EXT_TID);
+ last_pn_valid = peer->tids_last_pn_valid[tid];
+ last_pn = &peer->tids_last_pn[tid];
+
+ if (MS(rx_desc_info, HTT_RX_DESC_HL_INFO_MCAST_BCAST))
+ sec_index = HTT_TXRX_SEC_MCAST;
+ else
+ sec_index = HTT_TXRX_SEC_UCAST;
+
+ sec_type = peer->rx_pn[sec_index].sec_type;
+ ath10k_htt_rx_mpdu_desc_pn_hl(rx_desc, &new_pn, peer->rx_pn[sec_index].pn_len);
+
+ if (sec_type != HTT_SECURITY_AES_CCMP &&
+ sec_type != HTT_SECURITY_TKIP &&
+ sec_type != HTT_SECURITY_TKIP_NOMIC)
+ return false;
+
+ if (last_pn_valid)
+ pn_invalid = ath10k_htt_rx_pn_cmp48(&new_pn, last_pn);
+ else
+ peer->tids_last_pn_valid[tid] = 1;
+
+ if (!pn_invalid)
+ last_pn->pn48 = new_pn.pn48;
+
+ return pn_invalid;
+}
+
static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
struct htt_rx_indication_hl *rx,
- struct sk_buff *skb)
+ struct sk_buff *skb,
+ enum htt_rx_pn_check_type check_pn_type,
+ enum htt_rx_tkip_demic_type tkip_mic_type)
{
struct ath10k *ar = htt->ar;
struct ath10k_peer *peer;
@@ -2076,13 +2158,14 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
int num_mpdu_ranges;
size_t tot_hdr_len;
struct ieee80211_channel *ch;
+ bool pn_invalid;
peer_id = __le16_to_cpu(rx->hdr.peer_id);
spin_lock_bh(&ar->data_lock);
peer = ath10k_peer_find_by_id(ar, peer_id);
spin_unlock_bh(&ar->data_lock);
- if (!peer)
+ if (!peer && peer_id != HTT_INVALID_PEERID)
ath10k_warn(ar, "Got RX ind from invalid peer: %u\n", peer_id);
num_mpdu_ranges = MS(__le32_to_cpu(rx->hdr.info1),
@@ -2101,12 +2184,22 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
num_mpdu_ranges);
if (mpdu_ranges->mpdu_range_status !=
- HTT_RX_IND_MPDU_STATUS_OK) {
+ HTT_RX_IND_MPDU_STATUS_OK &&
+ mpdu_ranges->mpdu_range_status !=
+ HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR) {
ath10k_warn(ar, "MPDU range status: %d\n",
mpdu_ranges->mpdu_range_status);
goto err;
}
+ if (check_pn_type == HTT_RX_PN_CHECK) {
+ spin_lock_bh(&ar->data_lock);
+ pn_invalid = ath10k_htt_rx_pn_check_replay_hl(ar, peer, rx);
+ spin_unlock_bh(&ar->data_lock);
+ if (pn_invalid)
+ goto err;
+ }
+
/* Strip off all headers before the MAC header before delivery to
* mac80211
*/
@@ -2114,6 +2207,7 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
sizeof(rx->ppdu) + sizeof(rx->prefix) +
sizeof(rx->fw_desc) +
sizeof(*mpdu_ranges) * num_mpdu_ranges + rx_desc_len;
+
skb_pull(skb, tot_hdr_len);
hdr = (struct ieee80211_hdr *)skb->data;
@@ -2162,6 +2256,13 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
RX_FLAG_MMIC_STRIPPED;
}
+ if (tkip_mic_type == HTT_RX_TKIP_MIC)
+ rx_status->flag &= ~RX_FLAG_IV_STRIPPED &
+ ~RX_FLAG_MMIC_STRIPPED;
+
+ if (mpdu_ranges->mpdu_range_status == HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR)
+ rx_status->flag |= RX_FLAG_MMIC_ERROR;
+
ieee80211_rx_ni(ar->hw, skb);
/* We have delivered the skb to the upper layers (mac80211) so we
@@ -2175,6 +2276,231 @@ err:
return true;
}
+static int ath10k_htt_rx_frag_tkip_decap_nomic(struct sk_buff *skb,
+ u16 head_len,
+ u16 hdr_len)
+{
+ u8 *ivp, *orig_hdr;
+
+ orig_hdr = skb->data;
+ ivp = orig_hdr + hdr_len + head_len;
+
+ /* the ExtIV bit is always set to 1 for TKIP */
+ if (!(ivp[IEEE80211_WEP_IV_LEN - 1] & ATH10K_IEEE80211_EXTIV))
+ return -EINVAL;
+
+ memmove(orig_hdr + IEEE80211_TKIP_IV_LEN, orig_hdr, head_len + hdr_len);
+ skb_pull(skb, IEEE80211_TKIP_IV_LEN);
+ skb_trim(skb, skb->len - ATH10K_IEEE80211_TKIP_MICLEN);
+ return 0;
+}
+
+static int ath10k_htt_rx_frag_tkip_decap_withmic(struct sk_buff *skb,
+ u16 head_len,
+ u16 hdr_len)
+{
+ u8 *ivp, *orig_hdr;
+
+ orig_hdr = skb->data;
+ ivp = orig_hdr + hdr_len + head_len;
+
+ /* the ExtIV bit is always set to 1 for TKIP */
+ if (!(ivp[IEEE80211_WEP_IV_LEN - 1] & ATH10K_IEEE80211_EXTIV))
+ return -EINVAL;
+
+ memmove(orig_hdr + IEEE80211_TKIP_IV_LEN, orig_hdr, head_len + hdr_len);
+ skb_pull(skb, IEEE80211_TKIP_IV_LEN);
+ skb_trim(skb, skb->len - IEEE80211_TKIP_ICV_LEN);
+ return 0;
+}
+
+static int ath10k_htt_rx_frag_ccmp_decap(struct sk_buff *skb,
+ u16 head_len,
+ u16 hdr_len)
+{
+ u8 *ivp, *orig_hdr;
+
+ orig_hdr = skb->data;
+ ivp = orig_hdr + hdr_len + head_len;
+
+ /* the ExtIV bit is always set to 1 for CCMP */
+ if (!(ivp[IEEE80211_WEP_IV_LEN - 1] & ATH10K_IEEE80211_EXTIV))
+ return -EINVAL;
+
+ skb_trim(skb, skb->len - IEEE80211_CCMP_MIC_LEN);
+ memmove(orig_hdr + IEEE80211_CCMP_HDR_LEN, orig_hdr, head_len + hdr_len);
+ skb_pull(skb, IEEE80211_CCMP_HDR_LEN);
+ return 0;
+}
+
+static int ath10k_htt_rx_frag_wep_decap(struct sk_buff *skb,
+ u16 head_len,
+ u16 hdr_len)
+{
+ u8 *orig_hdr;
+
+ orig_hdr = skb->data;
+
+ memmove(orig_hdr + IEEE80211_WEP_IV_LEN,
+ orig_hdr, head_len + hdr_len);
+ skb_pull(skb, IEEE80211_WEP_IV_LEN);
+ skb_trim(skb, skb->len - IEEE80211_WEP_ICV_LEN);
+ return 0;
+}
+
+static bool ath10k_htt_rx_proc_rx_frag_ind_hl(struct ath10k_htt *htt,
+ struct htt_rx_fragment_indication *rx,
+ struct sk_buff *skb)
+{
+ struct ath10k *ar = htt->ar;
+ enum htt_rx_tkip_demic_type tkip_mic = HTT_RX_NON_TKIP_MIC;
+ enum htt_txrx_sec_cast_type sec_index;
+ struct htt_rx_indication_hl *rx_hl;
+ enum htt_security_types sec_type;
+ u32 tid, frag, seq, rx_desc_info;
+ union htt_rx_pn_t new_pn = {0};
+ struct htt_hl_rx_desc *rx_desc;
+ u16 peer_id, sc, hdr_space;
+ union htt_rx_pn_t *last_pn;
+ struct ieee80211_hdr *hdr;
+ int ret, num_mpdu_ranges;
+ struct ath10k_peer *peer;
+ struct htt_resp *resp;
+ size_t tot_hdr_len;
+
+ resp = (struct htt_resp *)(skb->data + HTT_RX_FRAG_IND_INFO0_HEADER_LEN);
+ skb_pull(skb, HTT_RX_FRAG_IND_INFO0_HEADER_LEN);
+ skb_trim(skb, skb->len - FCS_LEN);
+
+ peer_id = __le16_to_cpu(rx->peer_id);
+ rx_hl = (struct htt_rx_indication_hl *)(&resp->rx_ind_hl);
+
+ spin_lock_bh(&ar->data_lock);
+ peer = ath10k_peer_find_by_id(ar, peer_id);
+ if (!peer) {
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "invalid peer: %u\n", peer_id);
+ goto err;
+ }
+
+ num_mpdu_ranges = MS(__le32_to_cpu(rx_hl->hdr.info1),
+ HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES);
+
+ tot_hdr_len = sizeof(struct htt_resp_hdr) +
+ sizeof(rx_hl->hdr) +
+ sizeof(rx_hl->ppdu) +
+ sizeof(rx_hl->prefix) +
+ sizeof(rx_hl->fw_desc) +
+ sizeof(struct htt_rx_indication_mpdu_range) * num_mpdu_ranges;
+
+ tid = MS(rx_hl->hdr.info0, HTT_RX_INDICATION_INFO0_EXT_TID);
+ rx_desc = (struct htt_hl_rx_desc *)(skb->data + tot_hdr_len);
+ rx_desc_info = __le32_to_cpu(rx_desc->info);
+
+ if (!MS(rx_desc_info, HTT_RX_DESC_HL_INFO_ENCRYPTED)) {
+ spin_unlock_bh(&ar->data_lock);
+ return ath10k_htt_rx_proc_rx_ind_hl(htt, &resp->rx_ind_hl, skb,
+ HTT_RX_NON_PN_CHECK,
+ HTT_RX_NON_TKIP_MIC);
+ }
+
+ hdr = (struct ieee80211_hdr *)((u8 *)rx_desc + rx_hl->fw_desc.len);
+
+ if (ieee80211_has_retry(hdr->frame_control))
+ goto err;
+
+ hdr_space = ieee80211_hdrlen(hdr->frame_control);
+ sc = __le16_to_cpu(hdr->seq_ctrl);
+ seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
+ frag = sc & IEEE80211_SCTL_FRAG;
+
+ sec_index = MS(rx_desc_info, HTT_RX_DESC_HL_INFO_MCAST_BCAST) ?
+ HTT_TXRX_SEC_MCAST : HTT_TXRX_SEC_UCAST;
+ sec_type = peer->rx_pn[sec_index].sec_type;
+ ath10k_htt_rx_mpdu_desc_pn_hl(rx_desc, &new_pn, peer->rx_pn[sec_index].pn_len);
+
+ switch (sec_type) {
+ case HTT_SECURITY_TKIP:
+ tkip_mic = HTT_RX_TKIP_MIC;
+ ret = ath10k_htt_rx_frag_tkip_decap_withmic(skb,
+ tot_hdr_len +
+ rx_hl->fw_desc.len,
+ hdr_space);
+ if (ret)
+ goto err;
+ break;
+ case HTT_SECURITY_TKIP_NOMIC:
+ ret = ath10k_htt_rx_frag_tkip_decap_nomic(skb,
+ tot_hdr_len +
+ rx_hl->fw_desc.len,
+ hdr_space);
+ if (ret)
+ goto err;
+ break;
+ case HTT_SECURITY_AES_CCMP:
+ ret = ath10k_htt_rx_frag_ccmp_decap(skb,
+ tot_hdr_len + rx_hl->fw_desc.len,
+ hdr_space);
+ if (ret)
+ goto err;
+ break;
+ case HTT_SECURITY_WEP128:
+ case HTT_SECURITY_WEP104:
+ case HTT_SECURITY_WEP40:
+ ret = ath10k_htt_rx_frag_wep_decap(skb,
+ tot_hdr_len + rx_hl->fw_desc.len,
+ hdr_space);
+ if (ret)
+ goto err;
+ break;
+ default:
+ break;
+ }
+
+ resp = (struct htt_resp *)(skb->data);
+
+ if (sec_type != HTT_SECURITY_AES_CCMP &&
+ sec_type != HTT_SECURITY_TKIP &&
+ sec_type != HTT_SECURITY_TKIP_NOMIC) {
+ spin_unlock_bh(&ar->data_lock);
+ return ath10k_htt_rx_proc_rx_ind_hl(htt, &resp->rx_ind_hl, skb,
+ HTT_RX_NON_PN_CHECK,
+ HTT_RX_NON_TKIP_MIC);
+ }
+
+ last_pn = &peer->frag_tids_last_pn[tid];
+
+ if (frag == 0) {
+ if (ath10k_htt_rx_pn_check_replay_hl(ar, peer, &resp->rx_ind_hl))
+ goto err;
+
+ last_pn->pn48 = new_pn.pn48;
+ peer->frag_tids_seq[tid] = seq;
+ } else if (sec_type == HTT_SECURITY_AES_CCMP) {
+ if (seq != peer->frag_tids_seq[tid])
+ goto err;
+
+ if (new_pn.pn48 != last_pn->pn48 + 1)
+ goto err;
+
+ last_pn->pn48 = new_pn.pn48;
+ last_pn = &peer->tids_last_pn[tid];
+ last_pn->pn48 = new_pn.pn48;
+ }
+
+ spin_unlock_bh(&ar->data_lock);
+
+ return ath10k_htt_rx_proc_rx_ind_hl(htt, &resp->rx_ind_hl, skb,
+ HTT_RX_NON_PN_CHECK, tkip_mic);
+
+err:
+ spin_unlock_bh(&ar->data_lock);
+
+ /* Tell the caller that it must free the skb since we have not
+ * consumed it
+ */
+ return true;
+}
+
static void ath10k_htt_rx_proc_rx_ind_ll(struct ath10k_htt *htt,
struct htt_rx_indication *rx)
{
@@ -2193,9 +2519,7 @@ static void ath10k_htt_rx_proc_rx_ind_ll(struct ath10k_htt *htt,
mpdu_ranges = htt_rx_ind_get_mpdu_ranges(rx);
ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ",
- rx, sizeof(*rx) +
- (sizeof(struct htt_rx_indication_mpdu_range) *
- num_mpdu_ranges));
+ rx, struct_size(rx, mpdu_ranges, num_mpdu_ranges));
for (i = 0; i < num_mpdu_ranges; i++)
mpdu_count += mpdu_ranges[i].mpdu_count;
@@ -2277,7 +2601,9 @@ static void ath10k_htt_rx_tx_compl_ind(struct ath10k *ar,
* Note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these macro.
*/
- if (!kfifo_put(&htt->txdone_fifo, tx_done)) {
+ if (ar->bus_param.dev_type == ATH10K_DEV_TYPE_HL) {
+ ath10k_txrx_tx_unref(htt, &tx_done);
+ } else if (!kfifo_put(&htt->txdone_fifo, tx_done)) {
ath10k_warn(ar, "txdone fifo overrun, msdu_id %d status %d\n",
tx_done.msdu_id, tx_done.status);
ath10k_txrx_tx_unref(htt, &tx_done);
@@ -2938,14 +3264,14 @@ ath10k_accumulate_per_peer_tx_stats(struct ath10k *ar,
#define STATS_OP_FMT(name) tx_stats->stats[ATH10K_STATS_TYPE_##name]
- if (txrate->flags == RATE_INFO_FLAGS_VHT_MCS) {
+ if (txrate->flags & RATE_INFO_FLAGS_VHT_MCS) {
STATS_OP_FMT(SUCC).vht[0][mcs] += pstats->succ_bytes;
STATS_OP_FMT(SUCC).vht[1][mcs] += pstats->succ_pkts;
STATS_OP_FMT(FAIL).vht[0][mcs] += pstats->failed_bytes;
STATS_OP_FMT(FAIL).vht[1][mcs] += pstats->failed_pkts;
STATS_OP_FMT(RETRY).vht[0][mcs] += pstats->retry_bytes;
STATS_OP_FMT(RETRY).vht[1][mcs] += pstats->retry_pkts;
- } else if (txrate->flags == RATE_INFO_FLAGS_MCS) {
+ } else if (txrate->flags & RATE_INFO_FLAGS_MCS) {
STATS_OP_FMT(SUCC).ht[0][ht_idx] += pstats->succ_bytes;
STATS_OP_FMT(SUCC).ht[1][ht_idx] += pstats->succ_pkts;
STATS_OP_FMT(FAIL).ht[0][ht_idx] += pstats->failed_bytes;
@@ -2966,7 +3292,7 @@ ath10k_accumulate_per_peer_tx_stats(struct ath10k *ar,
if (ATH10K_HW_AMPDU(pstats->flags)) {
tx_stats->ba_fails += ATH10K_HW_BA_FAIL(pstats->flags);
- if (txrate->flags == RATE_INFO_FLAGS_MCS) {
+ if (txrate->flags & RATE_INFO_FLAGS_MCS) {
STATS_OP_FMT(AMPDU).ht[0][ht_idx] +=
pstats->succ_bytes + pstats->retry_bytes;
STATS_OP_FMT(AMPDU).ht[1][ht_idx] +=
@@ -3265,6 +3591,51 @@ out:
rcu_read_unlock();
}
+static int ath10k_htt_rx_pn_len(enum htt_security_types sec_type)
+{
+ switch (sec_type) {
+ case HTT_SECURITY_TKIP:
+ case HTT_SECURITY_TKIP_NOMIC:
+ case HTT_SECURITY_AES_CCMP:
+ return 48;
+ default:
+ return 0;
+ }
+}
+
+static void ath10k_htt_rx_sec_ind_handler(struct ath10k *ar,
+ struct htt_security_indication *ev)
+{
+ enum htt_txrx_sec_cast_type sec_index;
+ enum htt_security_types sec_type;
+ struct ath10k_peer *peer;
+
+ spin_lock_bh(&ar->data_lock);
+
+ peer = ath10k_peer_find_by_id(ar, __le16_to_cpu(ev->peer_id));
+ if (!peer) {
+ ath10k_warn(ar, "failed to find peer id %d for security indication",
+ __le16_to_cpu(ev->peer_id));
+ goto out;
+ }
+
+ sec_type = MS(ev->flags, HTT_SECURITY_TYPE);
+
+ if (ev->flags & HTT_SECURITY_IS_UNICAST)
+ sec_index = HTT_TXRX_SEC_UCAST;
+ else
+ sec_index = HTT_TXRX_SEC_MCAST;
+
+ peer->rx_pn[sec_index].sec_type = sec_type;
+ peer->rx_pn[sec_index].pn_len = ath10k_htt_rx_pn_len(sec_type);
+
+ memset(peer->tids_last_pn_valid, 0, sizeof(peer->tids_last_pn_valid));
+ memset(peer->tids_last_pn, 0, sizeof(peer->tids_last_pn));
+
+out:
+ spin_unlock_bh(&ar->data_lock);
+}
+
bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
{
struct ath10k_htt *htt = &ar->htt;
@@ -3296,7 +3667,9 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
if (ar->bus_param.dev_type == ATH10K_DEV_TYPE_HL)
return ath10k_htt_rx_proc_rx_ind_hl(htt,
&resp->rx_ind_hl,
- skb);
+ skb,
+ HTT_RX_PN_CHECK,
+ HTT_RX_NON_TKIP_MIC);
else
ath10k_htt_rx_proc_rx_ind_ll(htt, &resp->rx_ind);
break;
@@ -3358,6 +3731,7 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
struct ath10k *ar = htt->ar;
struct htt_security_indication *ev = &resp->security_indication;
+ ath10k_htt_rx_sec_ind_handler(ar, ev);
ath10k_dbg(ar, ATH10K_DBG_HTT,
"sec ind peer_id %d unicast %d type %d\n",
__le16_to_cpu(ev->peer_id),
@@ -3370,6 +3744,10 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt event: ",
skb->data, skb->len);
atomic_inc(&htt->num_mpdus_ready);
+
+ return ath10k_htt_rx_proc_rx_frag_ind(htt,
+ &resp->rx_frag_ind,
+ skb);
break;
}
case HTT_T2H_MSG_TYPE_TEST:
@@ -3583,6 +3961,7 @@ static const struct ath10k_htt_rx_ops htt_rx_ops_64 = {
};
static const struct ath10k_htt_rx_ops htt_rx_ops_hl = {
+ .htt_rx_proc_rx_frag_ind = ath10k_htt_rx_proc_rx_frag_ind_hl,
};
void ath10k_htt_set_rx_ops(struct ath10k_htt *htt)
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index d8e9cc0bb772..2ef717f18795 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -580,7 +580,8 @@ int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt)
return 0;
}
-int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie)
+int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u32 mask, u32 reset_mask,
+ u64 cookie)
{
struct ath10k *ar = htt->ar;
struct htt_stats_req *req;
@@ -603,11 +604,11 @@ int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie)
memset(req, 0, sizeof(*req));
- /* currently we support only max 8 bit masks so no need to worry
+ /* currently we support only max 24 bit masks so no need to worry
* about endian support
*/
- req->upload_types[0] = mask;
- req->reset_types[0] = mask;
+ memcpy(req->upload_types, &mask, 3);
+ memcpy(req->reset_types, &reset_mask, 3);
req->stat_type = HTT_STATS_REQ_CFG_STAT_TYPE_INVALID;
req->cookie_lsb = cpu_to_le32(cookie & 0xffffffff);
req->cookie_msb = cpu_to_le32((cookie & 0xffffffff00000000ULL) >> 32);
@@ -977,9 +978,9 @@ static int ath10k_htt_send_rx_ring_cfg_hl(struct ath10k_htt *htt)
return 0;
}
-int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
- u8 max_subfrms_ampdu,
- u8 max_subfrms_amsdu)
+static int ath10k_htt_h2t_aggr_cfg_msg_32(struct ath10k_htt *htt,
+ u8 max_subfrms_ampdu,
+ u8 max_subfrms_amsdu)
{
struct ath10k *ar = htt->ar;
struct htt_aggr_conf *aggr_conf;
@@ -1244,6 +1245,7 @@ static int ath10k_htt_tx_hl(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txm
u8 tid = ath10k_htt_tx_get_tid(msdu, is_eth);
u8 flags0 = 0;
u16 flags1 = 0;
+ u16 msdu_id = 0;
data_len = msdu->len;
@@ -1291,6 +1293,23 @@ static int ath10k_htt_tx_hl(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txm
}
}
+ if (ar->bus_param.hl_msdu_ids) {
+ flags1 |= HTT_DATA_TX_DESC_FLAGS1_POSTPONED;
+ res = ath10k_htt_tx_alloc_msdu_id(htt, msdu);
+ if (res < 0) {
+ ath10k_err(ar, "msdu_id allocation failed %d\n", res);
+ goto out;
+ }
+ msdu_id = res;
+ }
+
+ /* As msdu is freed by mac80211 (in ieee80211_tx_status()) and by
+ * ath10k (in ath10k_htt_htc_tx_complete()) we have to increase
+ * reference by one to avoid a use-after-free case and a double
+ * free.
+ */
+ skb_get(msdu);
+
skb_push(msdu, sizeof(*cmd_hdr));
skb_push(msdu, sizeof(*tx_desc));
cmd_hdr = (struct htt_cmd_hdr *)msdu->data;
@@ -1300,7 +1319,7 @@ static int ath10k_htt_tx_hl(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txm
tx_desc->flags0 = flags0;
tx_desc->flags1 = __cpu_to_le16(flags1);
tx_desc->len = __cpu_to_le16(data_len);
- tx_desc->id = 0;
+ tx_desc->id = __cpu_to_le16(msdu_id);
tx_desc->frags_paddr = 0; /* always zero */
/* Initialize peer_id to INVALID_PEER because this is NOT
* Reinjection path
@@ -1728,7 +1747,7 @@ static const struct ath10k_htt_tx_ops htt_tx_ops_32 = {
.htt_tx = ath10k_htt_tx_32,
.htt_alloc_txbuff = ath10k_htt_tx_alloc_cont_txbuf_32,
.htt_free_txbuff = ath10k_htt_tx_free_cont_txbuf_32,
- .htt_h2t_aggr_cfg_msg = ath10k_htt_h2t_aggr_cfg_msg,
+ .htt_h2t_aggr_cfg_msg = ath10k_htt_h2t_aggr_cfg_msg_32,
};
static const struct ath10k_htt_tx_ops htt_tx_ops_64 = {
@@ -1746,6 +1765,7 @@ static const struct ath10k_htt_tx_ops htt_tx_ops_hl = {
.htt_send_rx_ring_cfg = ath10k_htt_send_rx_ring_cfg_hl,
.htt_send_frag_desc_bank_cfg = ath10k_htt_send_frag_desc_bank_cfg_32,
.htt_tx = ath10k_htt_tx_hl,
+ .htt_h2t_aggr_cfg_msg = ath10k_htt_h2t_aggr_cfg_msg_32,
};
void ath10k_htt_set_tx_ops(struct ath10k_htt *htt)
diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c
index ad082b7d7643..c415e971735b 100644
--- a/drivers/net/wireless/ath/ath10k/hw.c
+++ b/drivers/net/wireless/ath/ath10k/hw.c
@@ -158,7 +158,7 @@ const struct ath10k_hw_values qca6174_values = {
};
const struct ath10k_hw_values qca99x0_values = {
- .rtc_state_val_on = 5,
+ .rtc_state_val_on = 7,
.ce_count = 12,
.msi_assign_ce_max = 12,
.num_target_ce_config_wlan = 10,
@@ -1153,6 +1153,10 @@ const struct ath10k_hw_ops qca6174_ops = {
.is_rssi_enable = ath10k_htt_tx_rssi_enable,
};
+const struct ath10k_hw_ops qca6174_sdio_ops = {
+ .enable_pll_clk = ath10k_hw_qca6174_enable_pll_clock,
+};
+
const struct ath10k_hw_ops wcn3990_ops = {
.tx_data_rssi_pad_bytes = ath10k_get_htt_tx_data_rssi_pad,
.is_rssi_enable = ath10k_htt_tx_rssi_enable_wcn3990,
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 71314999aa24..2ae57c1de7b5 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -24,6 +24,7 @@ enum ath10k_bus {
#define QCA988X_2_0_DEVICE_ID (0x003c)
#define QCA6164_2_1_DEVICE_ID (0x0041)
#define QCA6174_2_1_DEVICE_ID (0x003e)
+#define QCA6174_3_2_DEVICE_ID (0x0042)
#define QCA99X0_2_0_DEVICE_ID (0x0040)
#define QCA9888_2_0_DEVICE_ID (0x0056)
#define QCA9984_1_0_DEVICE_ID (0x0046)
@@ -151,6 +152,8 @@ enum qca9377_chip_id_rev {
#define ATH10K_FW_UTF_FILE "utf.bin"
#define ATH10K_FW_UTF_API2_FILE "utf-2.bin"
+#define ATH10K_FW_UTF_FILE_BASE "utf"
+
/* includes also the null byte */
#define ATH10K_FIRMWARE_MAGIC "QCA-ATH10K"
#define ATH10K_BOARD_MAGIC "QCA-ATH10K-BOARD"
@@ -606,6 +609,14 @@ struct ath10k_hw_params {
/* target supporting fw download via diag ce */
bool fw_diag_ce_download;
+
+ /* need to set uart pin if disable uart print, workaround for a
+ * firmware bug
+ */
+ bool uart_pin_workaround;
+
+ /* tx stats support over pktlog */
+ bool tx_stats_over_pktlog;
};
struct htt_rx_desc;
@@ -625,6 +636,7 @@ struct ath10k_hw_ops {
extern const struct ath10k_hw_ops qca988x_ops;
extern const struct ath10k_hw_ops qca99x0_ops;
extern const struct ath10k_hw_ops qca6174_ops;
+extern const struct ath10k_hw_ops qca6174_sdio_ops;
extern const struct ath10k_hw_ops wcn3990_ops;
extern const struct ath10k_hw_clk_params qca6174_clk[];
@@ -1095,6 +1107,7 @@ ath10k_is_rssi_enable(struct ath10k_hw_params *hw,
#define MBOX_CPU_INT_STATUS_ENABLE_ADDRESS 0x00000819
#define MBOX_CPU_INT_STATUS_ENABLE_BIT_LSB 0
#define MBOX_CPU_INT_STATUS_ENABLE_BIT_MASK 0x000000ff
+#define MBOX_CPU_STATUS_ENABLE_ASSERT_MASK 0x00000001
#define MBOX_ERROR_STATUS_ENABLE_ADDRESS 0x0000081a
#define MBOX_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB 1
#define MBOX_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK 0x00000002
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 9c703d287333..0606416dc971 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -693,6 +693,26 @@ ath10k_mac_get_any_chandef_iter(struct ieee80211_hw *hw,
*def = &conf->def;
}
+static void ath10k_wait_for_peer_delete_done(struct ath10k *ar, u32 vdev_id,
+ const u8 *addr)
+{
+ unsigned long time_left;
+ int ret;
+
+ if (test_bit(WMI_SERVICE_SYNC_DELETE_CMDS, ar->wmi.svc_map)) {
+ ret = ath10k_wait_for_peer_deleted(ar, vdev_id, addr);
+ if (ret) {
+ ath10k_warn(ar, "failed wait for peer deleted");
+ return;
+ }
+
+ time_left = wait_for_completion_timeout(&ar->peer_delete_done,
+ 5 * HZ);
+ if (!time_left)
+ ath10k_warn(ar, "Timeout in receiving peer delete response\n");
+ }
+}
+
static int ath10k_peer_create(struct ath10k *ar,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@@ -737,7 +757,7 @@ static int ath10k_peer_create(struct ath10k *ar,
spin_unlock_bh(&ar->data_lock);
ath10k_warn(ar, "failed to find peer %pM on vdev %i after creation\n",
addr, vdev_id);
- ath10k_wmi_peer_delete(ar, vdev_id, addr);
+ ath10k_wait_for_peer_delete_done(ar, vdev_id, addr);
return -ENOENT;
}
@@ -819,6 +839,18 @@ static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr)
if (ret)
return ret;
+ if (test_bit(WMI_SERVICE_SYNC_DELETE_CMDS, ar->wmi.svc_map)) {
+ unsigned long time_left;
+
+ time_left = wait_for_completion_timeout
+ (&ar->peer_delete_done, 5 * HZ);
+
+ if (!time_left) {
+ ath10k_warn(ar, "Timeout in receiving peer delete response\n");
+ return -ETIMEDOUT;
+ }
+ }
+
ar->num_peers--;
return 0;
@@ -1011,6 +1043,7 @@ static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id)
arg.channel.max_antenna_gain = channel->max_antenna_gain * 2;
reinit_completion(&ar->vdev_setup_done);
+ reinit_completion(&ar->vdev_delete_done);
ret = ath10k_wmi_vdev_start(ar, &arg);
if (ret) {
@@ -1060,6 +1093,7 @@ static int ath10k_monitor_vdev_stop(struct ath10k *ar)
ar->monitor_vdev_id, ret);
reinit_completion(&ar->vdev_setup_done);
+ reinit_completion(&ar->vdev_delete_done);
ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id);
if (ret)
@@ -1401,6 +1435,7 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif)
lockdep_assert_held(&ar->conf_mutex);
reinit_completion(&ar->vdev_setup_done);
+ reinit_completion(&ar->vdev_delete_done);
ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id);
if (ret) {
@@ -1437,6 +1472,7 @@ static int ath10k_vdev_start_restart(struct ath10k_vif *arvif,
lockdep_assert_held(&ar->conf_mutex);
reinit_completion(&ar->vdev_setup_done);
+ reinit_completion(&ar->vdev_delete_done);
arg.vdev_id = arvif->vdev_id;
arg.dtim_period = arvif->dtim_period;
@@ -1630,6 +1666,10 @@ static int ath10k_mac_setup_prb_tmpl(struct ath10k_vif *arvif)
if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
return 0;
+ /* For mesh, probe response and beacon share the same template */
+ if (ieee80211_vif_is_mesh(vif))
+ return 0;
+
prb = ieee80211_proberesp_get(hw, vif);
if (!prb) {
ath10k_warn(ar, "failed to get probe resp template from mac80211\n");
@@ -5415,8 +5455,11 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
err_peer_delete:
if (arvif->vdev_type == WMI_VDEV_TYPE_AP ||
- arvif->vdev_type == WMI_VDEV_TYPE_IBSS)
+ arvif->vdev_type == WMI_VDEV_TYPE_IBSS) {
ath10k_wmi_peer_delete(ar, arvif->vdev_id, vif->addr);
+ ath10k_wait_for_peer_delete_done(ar, arvif->vdev_id,
+ vif->addr);
+ }
err_vdev_delete:
ath10k_wmi_vdev_delete(ar, arvif->vdev_id);
@@ -5451,6 +5494,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
struct ath10k *ar = hw->priv;
struct ath10k_vif *arvif = (void *)vif->drv_priv;
struct ath10k_peer *peer;
+ unsigned long time_left;
int ret;
int i;
@@ -5481,6 +5525,8 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
ath10k_warn(ar, "failed to submit AP/IBSS self-peer removal on vdev %i: %d\n",
arvif->vdev_id, ret);
+ ath10k_wait_for_peer_delete_done(ar, arvif->vdev_id,
+ vif->addr);
kfree(arvif->u.ap.noa_data);
}
@@ -5492,6 +5538,15 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
ath10k_warn(ar, "failed to delete WMI vdev %i: %d\n",
arvif->vdev_id, ret);
+ if (test_bit(WMI_SERVICE_SYNC_DELETE_CMDS, ar->wmi.svc_map)) {
+ time_left = wait_for_completion_timeout(&ar->vdev_delete_done,
+ ATH10K_VDEV_DELETE_TIMEOUT_HZ);
+ if (time_left == 0) {
+ ath10k_warn(ar, "Timeout in receiving vdev delete response\n");
+ goto out;
+ }
+ }
+
/* Some firmware revisions don't notify host about self-peer removal
* until after associated vdev is deleted.
*/
@@ -5542,6 +5597,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
ath10k_mac_txq_unref(ar, vif->txq);
+out:
mutex_unlock(&ar->conf_mutex);
}
@@ -5588,8 +5644,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
struct cfg80211_chan_def def;
u32 vdev_param, pdev_param, slottime, preamble;
u16 bitrate, hw_value;
- u8 rate, basic_rate_idx;
- int rateidx, ret = 0, hw_rate_code;
+ u8 rate, basic_rate_idx, rateidx;
+ int ret = 0, hw_rate_code, mcast_rate;
enum nl80211_band band;
const struct ieee80211_supported_band *sband;
@@ -5776,7 +5832,11 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_MCAST_RATE &&
!ath10k_mac_vif_chan(arvif->vif, &def)) {
band = def.chan->band;
- rateidx = vif->bss_conf.mcast_rate[band] - 1;
+ mcast_rate = vif->bss_conf.mcast_rate[band];
+ if (mcast_rate > 0)
+ rateidx = mcast_rate - 1;
+ else
+ rateidx = ffs(vif->bss_conf.basic_rates) - 1;
if (ar->phy_capability & WHAL_WLAN_11A_CAPABILITY)
rateidx += ATH10K_MAC_FIRST_OFDM_RATE_IDX;
@@ -6350,6 +6410,41 @@ static void ath10k_mac_dec_num_stations(struct ath10k_vif *arvif,
ar->num_stations--;
}
+static int ath10k_sta_set_txpwr(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct ath10k *ar = hw->priv;
+ struct ath10k_vif *arvif = (void *)vif->drv_priv;
+ int ret = 0;
+ s16 txpwr;
+
+ if (sta->txpwr.type == NL80211_TX_POWER_AUTOMATIC) {
+ txpwr = 0;
+ } else {
+ txpwr = sta->txpwr.power;
+ if (!txpwr)
+ return -EINVAL;
+ }
+
+ if (txpwr > ATH10K_TX_POWER_MAX_VAL || txpwr < ATH10K_TX_POWER_MIN_VAL)
+ return -EINVAL;
+
+ mutex_lock(&ar->conf_mutex);
+
+ ret = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
+ WMI_PEER_USE_FIXED_PWR, txpwr);
+ if (ret) {
+ ath10k_warn(ar, "failed to set tx power for station ret: %d\n",
+ ret);
+ goto out;
+ }
+
+out:
+ mutex_unlock(&ar->conf_mutex);
+ return ret;
+}
+
static int ath10k_sta_state(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@@ -7099,18 +7194,23 @@ exit:
static bool
ath10k_mac_bitrate_mask_has_single_rate(struct ath10k *ar,
enum nl80211_band band,
- const struct cfg80211_bitrate_mask *mask)
+ const struct cfg80211_bitrate_mask *mask,
+ int *vht_num_rates)
{
int num_rates = 0;
- int i;
+ int i, tmp;
num_rates += hweight32(mask->control[band].legacy);
for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++)
num_rates += hweight8(mask->control[band].ht_mcs[i]);
- for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++)
- num_rates += hweight16(mask->control[band].vht_mcs[i]);
+ *vht_num_rates = 0;
+ for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++) {
+ tmp = hweight16(mask->control[band].vht_mcs[i]);
+ num_rates += tmp;
+ *vht_num_rates += tmp;
+ }
return num_rates == 1;
}
@@ -7168,7 +7268,7 @@ static int
ath10k_mac_bitrate_mask_get_single_rate(struct ath10k *ar,
enum nl80211_band band,
const struct cfg80211_bitrate_mask *mask,
- u8 *rate, u8 *nss)
+ u8 *rate, u8 *nss, bool vht_only)
{
int rate_idx;
int i;
@@ -7176,6 +7276,9 @@ ath10k_mac_bitrate_mask_get_single_rate(struct ath10k *ar,
u8 preamble;
u8 hw_rate;
+ if (vht_only)
+ goto next;
+
if (hweight32(mask->control[band].legacy) == 1) {
rate_idx = ffs(mask->control[band].legacy) - 1;
@@ -7209,6 +7312,7 @@ ath10k_mac_bitrate_mask_get_single_rate(struct ath10k *ar,
}
}
+next:
for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++) {
if (hweight16(mask->control[band].vht_mcs[i]) == 1) {
*nss = i + 1;
@@ -7270,7 +7374,8 @@ static int ath10k_mac_set_fixed_rate_params(struct ath10k_vif *arvif,
static bool
ath10k_mac_can_set_bitrate_mask(struct ath10k *ar,
enum nl80211_band band,
- const struct cfg80211_bitrate_mask *mask)
+ const struct cfg80211_bitrate_mask *mask,
+ bool allow_pfr)
{
int i;
u16 vht_mcs;
@@ -7289,7 +7394,8 @@ ath10k_mac_can_set_bitrate_mask(struct ath10k *ar,
case BIT(10) - 1:
break;
default:
- ath10k_warn(ar, "refusing bitrate mask with missing 0-7 VHT MCS rates\n");
+ if (!allow_pfr)
+ ath10k_warn(ar, "refusing bitrate mask with missing 0-7 VHT MCS rates\n");
return false;
}
}
@@ -7297,6 +7403,26 @@ ath10k_mac_can_set_bitrate_mask(struct ath10k *ar,
return true;
}
+static bool ath10k_mac_set_vht_bitrate_mask_fixup(struct ath10k *ar,
+ struct ath10k_vif *arvif,
+ struct ieee80211_sta *sta)
+{
+ int err;
+ u8 rate = arvif->vht_pfr;
+
+ /* skip non vht and multiple rate peers */
+ if (!sta->vht_cap.vht_supported || arvif->vht_num_rates != 1)
+ return false;
+
+ err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
+ WMI_PEER_PARAM_FIXED_RATE, rate);
+ if (err)
+ ath10k_warn(ar, "failed to eanble STA %pM peer fixed rate: %d\n",
+ sta->addr, err);
+
+ return true;
+}
+
static void ath10k_mac_set_bitrate_mask_iter(void *data,
struct ieee80211_sta *sta)
{
@@ -7307,6 +7433,9 @@ static void ath10k_mac_set_bitrate_mask_iter(void *data,
if (arsta->arvif != arvif)
return;
+ if (ath10k_mac_set_vht_bitrate_mask_fixup(ar, arvif, sta))
+ return;
+
spin_lock_bh(&ar->data_lock);
arsta->changed |= IEEE80211_RC_SUPP_RATES_CHANGED;
spin_unlock_bh(&ar->data_lock);
@@ -7314,6 +7443,26 @@ static void ath10k_mac_set_bitrate_mask_iter(void *data,
ieee80211_queue_work(ar->hw, &arsta->update_wk);
}
+static void ath10k_mac_clr_bitrate_mask_iter(void *data,
+ struct ieee80211_sta *sta)
+{
+ struct ath10k_vif *arvif = data;
+ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
+ struct ath10k *ar = arvif->ar;
+ int err;
+
+ /* clear vht peers only */
+ if (arsta->arvif != arvif || !sta->vht_cap.vht_supported)
+ return;
+
+ err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
+ WMI_PEER_PARAM_FIXED_RATE,
+ WMI_FIXED_RATE_NONE);
+ if (err)
+ ath10k_warn(ar, "failed to clear STA %pM peer fixed rate: %d\n",
+ sta->addr, err);
+}
+
static int ath10k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
const struct cfg80211_bitrate_mask *mask)
@@ -7330,6 +7479,9 @@ static int ath10k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
u8 ldpc;
int single_nss;
int ret;
+ int vht_num_rates, allow_pfr;
+ u8 vht_pfr;
+ bool update_bitrate_mask = true;
if (ath10k_mac_vif_chan(vif, &def))
return -EPERM;
@@ -7343,9 +7495,21 @@ static int ath10k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
if (sgi == NL80211_TXRATE_FORCE_LGI)
return -EINVAL;
- if (ath10k_mac_bitrate_mask_has_single_rate(ar, band, mask)) {
+ allow_pfr = test_bit(ATH10K_FW_FEATURE_PEER_FIXED_RATE,
+ ar->normal_mode_fw.fw_file.fw_features);
+ if (allow_pfr) {
+ mutex_lock(&ar->conf_mutex);
+ ieee80211_iterate_stations_atomic(ar->hw,
+ ath10k_mac_clr_bitrate_mask_iter,
+ arvif);
+ mutex_unlock(&ar->conf_mutex);
+ }
+
+ if (ath10k_mac_bitrate_mask_has_single_rate(ar, band, mask,
+ &vht_num_rates)) {
ret = ath10k_mac_bitrate_mask_get_single_rate(ar, band, mask,
- &rate, &nss);
+ &rate, &nss,
+ false);
if (ret) {
ath10k_warn(ar, "failed to get single rate for vdev %i: %d\n",
arvif->vdev_id, ret);
@@ -7361,12 +7525,32 @@ static int ath10k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
max(ath10k_mac_max_ht_nss(ht_mcs_mask),
ath10k_mac_max_vht_nss(vht_mcs_mask)));
- if (!ath10k_mac_can_set_bitrate_mask(ar, band, mask))
- return -EINVAL;
+ if (!ath10k_mac_can_set_bitrate_mask(ar, band, mask,
+ allow_pfr)) {
+ u8 vht_nss;
+
+ if (!allow_pfr || vht_num_rates != 1)
+ return -EINVAL;
+
+ /* Reach here, firmware supports peer fixed rate and has
+ * single vht rate, and don't update vif birate_mask, as
+ * the rate only for specific peer.
+ */
+ ath10k_mac_bitrate_mask_get_single_rate(ar, band, mask,
+ &vht_pfr,
+ &vht_nss,
+ true);
+ update_bitrate_mask = false;
+ } else {
+ vht_pfr = 0;
+ }
mutex_lock(&ar->conf_mutex);
- arvif->bitrate_mask = *mask;
+ if (update_bitrate_mask)
+ arvif->bitrate_mask = *mask;
+ arvif->vht_num_rates = vht_num_rates;
+ arvif->vht_pfr = vht_pfr;
ieee80211_iterate_stations_atomic(ar->hw,
ath10k_mac_set_bitrate_mask_iter,
arvif);
@@ -7869,7 +8053,8 @@ ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
arvif->vdev_id, ret);
}
- if (ath10k_peer_stats_enabled(ar)) {
+ if (ath10k_peer_stats_enabled(ar) &&
+ ar->hw_params.tx_stats_over_pktlog) {
ar->pktlog_filter |= ATH10K_PKTLOG_PEER_STATS;
ret = ath10k_wmi_pdev_pktlog_enable(ar,
ar->pktlog_filter);
@@ -8007,6 +8192,7 @@ static const struct ieee80211_ops ath10k_ops = {
.set_key = ath10k_set_key,
.set_default_unicast_key = ath10k_set_default_unicast_key,
.sta_state = ath10k_sta_state,
+ .sta_set_txpwr = ath10k_sta_set_txpwr,
.conf_tx = ath10k_conf_tx,
.remain_on_channel = ath10k_remain_on_channel,
.cancel_remain_on_channel = ath10k_cancel_remain_on_channel,
@@ -8695,6 +8881,9 @@ int ath10k_mac_register(struct ath10k *ar)
wiphy_ext_feature_set(ar->hw->wiphy,
NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER);
+ if (test_bit(WMI_SERVICE_TX_PWR_PER_PEER, ar->wmi.svc_map))
+ wiphy_ext_feature_set(ar->hw->wiphy,
+ NL80211_EXT_FEATURE_STA_TX_PWR);
/*
* on LL hardware queues are managed entirely by the FW
* so we only advertise to mac we can do the queues thing
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 2c27f407a851..a0b4d265c6eb 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -909,7 +909,7 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
/* Host buffer address in CE space */
u32 ce_data;
dma_addr_t ce_data_base = 0;
- void *data_buf = NULL;
+ void *data_buf;
int i;
mutex_lock(&ar_pci->ce_diag_mutex);
@@ -923,10 +923,8 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
*/
alloc_nbytes = min_t(unsigned int, nbytes, DIAG_TRANSFER_LIMIT);
- data_buf = (unsigned char *)dma_alloc_coherent(ar->dev, alloc_nbytes,
- &ce_data_base,
- GFP_ATOMIC);
-
+ data_buf = dma_alloc_coherent(ar->dev, alloc_nbytes, &ce_data_base,
+ GFP_ATOMIC);
if (!data_buf) {
ret = -ENOMEM;
goto done;
@@ -1054,7 +1052,7 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
u32 *buf;
unsigned int completed_nbytes, alloc_nbytes, remaining_bytes;
struct ath10k_ce_pipe *ce_diag;
- void *data_buf = NULL;
+ void *data_buf;
dma_addr_t ce_data_base = 0;
int i;
@@ -1069,10 +1067,8 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
*/
alloc_nbytes = min_t(unsigned int, nbytes, DIAG_TRANSFER_LIMIT);
- data_buf = (unsigned char *)dma_alloc_coherent(ar->dev,
- alloc_nbytes,
- &ce_data_base,
- GFP_ATOMIC);
+ data_buf = dma_alloc_coherent(ar->dev, alloc_nbytes, &ce_data_base,
+ GFP_ATOMIC);
if (!data_buf) {
ret = -ENOMEM;
goto done;
@@ -2059,6 +2055,11 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif stop\n");
+ ath10k_pci_irq_disable(ar);
+ ath10k_pci_irq_sync(ar);
+ napi_synchronize(&ar->napi);
+ napi_disable(&ar->napi);
+
/* Most likely the device has HTT Rx ring configured. The only way to
* prevent the device from accessing (and possible corrupting) host
* memory is to reset the chip now.
@@ -2072,10 +2073,6 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
*/
ath10k_pci_safe_chip_reset(ar);
- ath10k_pci_irq_disable(ar);
- ath10k_pci_irq_sync(ar);
- napi_synchronize(&ar->napi);
- napi_disable(&ar->napi);
ath10k_pci_flush(ar);
spin_lock_irqsave(&ar_pci->ps_lock, flags);
@@ -3492,7 +3489,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
struct ath10k *ar;
struct ath10k_pci *ar_pci;
enum ath10k_hw_rev hw_rev;
- struct ath10k_bus_params bus_params;
+ struct ath10k_bus_params bus_params = {};
bool pci_ps;
int (*pci_soft_reset)(struct ath10k *ar);
int (*pci_hard_reset)(struct ath10k *ar);
diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c
index a7bc2c70d076..3b63b6257c43 100644
--- a/drivers/net/wireless/ath/ath10k/qmi.c
+++ b/drivers/net/wireless/ath/ath10k/qmi.c
@@ -506,6 +506,7 @@ static int ath10k_qmi_cap_send_sync_msg(struct ath10k_qmi *qmi)
struct wlfw_cap_resp_msg_v01 *resp;
struct wlfw_cap_req_msg_v01 req = {};
struct ath10k *ar = qmi->ar;
+ struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
struct qmi_txn txn;
int ret;
@@ -560,13 +561,13 @@ static int ath10k_qmi_cap_send_sync_msg(struct ath10k_qmi *qmi)
strlcpy(qmi->fw_build_id, resp->fw_build_id,
MAX_BUILD_ID_LEN + 1);
- ath10k_dbg(ar, ATH10K_DBG_QMI,
- "qmi chip_id 0x%x chip_family 0x%x board_id 0x%x soc_id 0x%x",
- qmi->chip_info.chip_id, qmi->chip_info.chip_family,
- qmi->board_info.board_id, qmi->soc_info.soc_id);
- ath10k_dbg(ar, ATH10K_DBG_QMI,
- "qmi fw_version 0x%x fw_build_timestamp %s fw_build_id %s",
- qmi->fw_version, qmi->fw_build_timestamp, qmi->fw_build_id);
+ if (!test_bit(ATH10K_SNOC_FLAG_REGISTERED, &ar_snoc->flags)) {
+ ath10k_info(ar, "qmi chip_id 0x%x chip_family 0x%x board_id 0x%x soc_id 0x%x",
+ qmi->chip_info.chip_id, qmi->chip_info.chip_family,
+ qmi->board_info.board_id, qmi->soc_info.soc_id);
+ ath10k_info(ar, "qmi fw_version 0x%x fw_build_timestamp %s fw_build_id %s",
+ qmi->fw_version, qmi->fw_build_timestamp, qmi->fw_build_id);
+ }
kfree(resp);
return 0;
@@ -619,6 +620,51 @@ out:
return ret;
}
+int ath10k_qmi_set_fw_log_mode(struct ath10k *ar, u8 fw_log_mode)
+{
+ struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+ struct wlfw_ini_resp_msg_v01 resp = {};
+ struct ath10k_qmi *qmi = ar_snoc->qmi;
+ struct wlfw_ini_req_msg_v01 req = {};
+ struct qmi_txn txn;
+ int ret;
+
+ req.enablefwlog_valid = 1;
+ req.enablefwlog = fw_log_mode;
+
+ ret = qmi_txn_init(&qmi->qmi_hdl, &txn, wlfw_ini_resp_msg_v01_ei,
+ &resp);
+ if (ret < 0)
+ goto out;
+
+ ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
+ QMI_WLFW_INI_REQ_V01,
+ WLFW_INI_REQ_MSG_V01_MAX_MSG_LEN,
+ wlfw_ini_req_msg_v01_ei, &req);
+ if (ret < 0) {
+ qmi_txn_cancel(&txn);
+ ath10k_err(ar, "fail to send fw log reqest: %d\n", ret);
+ goto out;
+ }
+
+ ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ);
+ if (ret < 0)
+ goto out;
+
+ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ ath10k_err(ar, "fw log request rejectedr: %d\n",
+ resp.resp.error);
+ ret = -EINVAL;
+ goto out;
+ }
+ ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi fw log request completed, mode: %d\n",
+ fw_log_mode);
+ return 0;
+
+out:
+ return ret;
+}
+
static int
ath10k_qmi_ind_register_send_sync_msg(struct ath10k_qmi *qmi)
{
@@ -1002,6 +1048,7 @@ int ath10k_qmi_deinit(struct ath10k *ar)
qmi_handle_release(&qmi->qmi_hdl);
cancel_work_sync(&qmi->event_work);
destroy_workqueue(qmi->event_wq);
+ kfree(qmi);
ar_snoc->qmi = NULL;
return 0;
diff --git a/drivers/net/wireless/ath/ath10k/qmi.h b/drivers/net/wireless/ath/ath10k/qmi.h
index e4aa20445666..40aafb875ed0 100644
--- a/drivers/net/wireless/ath/ath10k/qmi.h
+++ b/drivers/net/wireless/ath/ath10k/qmi.h
@@ -114,5 +114,6 @@ int ath10k_qmi_wlan_disable(struct ath10k *ar);
int ath10k_qmi_register_service_notifier(struct notifier_block *nb);
int ath10k_qmi_init(struct ath10k *ar, u32 msa_size);
int ath10k_qmi_deinit(struct ath10k *ar);
+int ath10k_qmi_set_fw_log_mode(struct ath10k *ar, u8 fw_log_mode);
#endif /* ATH10K_QMI_H */
diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index fae56c67766f..8ed4fbd8d6c3 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -584,6 +584,11 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
act_len,
&bndl_cnt);
+ if (ret) {
+ ath10k_warn(ar, "alloc_bundle error %d\n", ret);
+ goto err;
+ }
+
n_lookaheads += bndl_cnt;
i += bndl_cnt;
/*Next buffer will be the last in the bundle */
@@ -602,6 +607,10 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
full_len,
last_in_bundle,
last_in_bundle);
+ if (ret) {
+ ath10k_warn(ar, "alloc_rx_pkt error %d\n", ret);
+ goto err;
+ }
}
ar_sdio->n_rx_pkts = i;
@@ -850,6 +859,10 @@ static int ath10k_sdio_mbox_proc_cpu_intr(struct ath10k *ar)
out:
mutex_unlock(&irq_data->mtx);
+ if (cpu_int_status & MBOX_CPU_STATUS_ENABLE_ASSERT_MASK) {
+ ath10k_err(ar, "firmware crashed!\n");
+ queue_work(ar->workqueue, &ar->restart_work);
+ }
return ret;
}
@@ -1495,8 +1508,10 @@ static int ath10k_sdio_hif_enable_intrs(struct ath10k *ar)
regs->int_status_en |=
FIELD_PREP(MBOX_INT_STATUS_ENABLE_MBOX_DATA_MASK, 1);
- /* Set up the CPU Interrupt status Register */
- regs->cpu_int_status_en = 0;
+ /* Set up the CPU Interrupt Status Register, enable CPU sourced interrupt #0
+ * #0 is used for report assertion from target
+ */
+ regs->cpu_int_status_en = FIELD_PREP(MBOX_CPU_STATUS_ENABLE_ASSERT_MASK, 1);
/* Set up the Error Interrupt status Register */
regs->err_int_status_en =
@@ -1637,7 +1652,12 @@ static int ath10k_sdio_hif_swap_mailbox(struct ath10k *ar)
ath10k_dbg(ar, ATH10K_DBG_SDIO,
"sdio mailbox swap service enabled\n");
ar_sdio->swap_mbox = true;
+ } else {
+ ath10k_dbg(ar, ATH10K_DBG_SDIO,
+ "sdio mailbox swap service disabled\n");
+ ar_sdio->swap_mbox = false;
}
+
return 0;
}
@@ -1954,7 +1974,7 @@ static int ath10k_sdio_probe(struct sdio_func *func,
struct ath10k *ar;
enum ath10k_hw_rev hw_rev;
u32 dev_id_base;
- struct ath10k_bus_params bus_params;
+ struct ath10k_bus_params bus_params = {};
int ret, i;
/* Assumption: All SDIO based chipsets (so far) are QCA6174 based.
@@ -2045,6 +2065,8 @@ static int ath10k_sdio_probe(struct sdio_func *func,
bus_params.dev_type = ATH10K_DEV_TYPE_HL;
/* TODO: don't know yet how to get chip_id with SDIO */
bus_params.chip_id = 0;
+ bus_params.hl_msdu_ids = true;
+
ret = ath10k_core_register(ar, &bus_params);
if (ret) {
ath10k_err(ar, "failed to register driver core: %d\n", ret);
@@ -2052,7 +2074,7 @@ static int ath10k_sdio_probe(struct sdio_func *func,
}
/* TODO: remove this once SDIO support is fully implemented */
- ath10k_warn(ar, "WARNING: ath10k SDIO support is incomplete, don't expect anything to work!\n");
+ ath10k_warn(ar, "WARNING: ath10k SDIO support is work-in-progress, problems may arise!\n");
return 0;
@@ -2073,10 +2095,11 @@ static void ath10k_sdio_remove(struct sdio_func *func)
"sdio removed func %d vendor 0x%x device 0x%x\n",
func->num, func->vendor, func->device);
- (void)ath10k_sdio_hif_disable_intrs(ar);
- cancel_work_sync(&ar_sdio->wr_async_work);
ath10k_core_unregister(ar);
ath10k_core_destroy(ar);
+
+ flush_workqueue(ar_sdio->workqueue);
+ destroy_workqueue(ar_sdio->workqueue);
}
static const struct sdio_device_id ath10k_sdio_devices[] = {
diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c
index 873cb4ce419b..b491361e6ed4 100644
--- a/drivers/net/wireless/ath/ath10k/snoc.c
+++ b/drivers/net/wireless/ath/ath10k/snoc.c
@@ -165,7 +165,7 @@ static struct ce_attr host_ce_config_wlan[] = {
/* CE4: host->target HTT */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
- .src_nentries = 256,
+ .src_nentries = 2048,
.src_sz_max = 256,
.dest_nentries = 0,
.send_cb = ath10k_snoc_htt_tx_cb,
@@ -1050,6 +1050,19 @@ err_wlan_enable:
return ret;
}
+static int ath10k_snoc_hif_set_target_log_mode(struct ath10k *ar,
+ u8 fw_log_mode)
+{
+ u8 fw_dbg_mode;
+
+ if (fw_log_mode)
+ fw_dbg_mode = ATH10K_ENABLE_FW_LOG_CE;
+ else
+ fw_dbg_mode = ATH10K_ENABLE_FW_LOG_DIAG;
+
+ return ath10k_qmi_set_fw_log_mode(ar, fw_dbg_mode);
+}
+
#ifdef CONFIG_PM
static int ath10k_snoc_hif_suspend(struct ath10k *ar)
{
@@ -1103,6 +1116,8 @@ static const struct ath10k_hif_ops ath10k_snoc_hif_ops = {
.send_complete_check = ath10k_snoc_hif_send_complete_check,
.get_free_queue_number = ath10k_snoc_hif_get_free_queue_number,
.get_target_info = ath10k_snoc_hif_get_target_info,
+ .set_target_log_mode = ath10k_snoc_hif_set_target_log_mode,
+
#ifdef CONFIG_PM
.suspend = ath10k_snoc_hif_suspend,
.resume = ath10k_snoc_hif_resume,
@@ -1249,7 +1264,7 @@ out:
int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type)
{
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
- struct ath10k_bus_params bus_params;
+ struct ath10k_bus_params bus_params = {};
int ret;
if (test_bit(ATH10K_SNOC_FLAG_UNREGISTERING, &ar_snoc->flags))
diff --git a/drivers/net/wireless/ath/ath10k/swap.c b/drivers/net/wireless/ath/ath10k/swap.c
index 4dddeee684b4..7198a386f2fb 100644
--- a/drivers/net/wireless/ath/ath10k/swap.c
+++ b/drivers/net/wireless/ath/ath10k/swap.c
@@ -106,10 +106,8 @@ ath10k_swap_code_seg_alloc(struct ath10k *ar, size_t swap_bin_len)
virt_addr = dma_alloc_coherent(ar->dev, swap_bin_len, &paddr,
GFP_KERNEL);
- if (!virt_addr) {
- ath10k_err(ar, "failed to allocate dma coherent memory\n");
+ if (!virt_addr)
return NULL;
- }
seg_info->seg_hw_info.bus_addr[0] = __cpu_to_le32(paddr);
seg_info->seg_hw_info.size = __cpu_to_le32(swap_bin_len);
diff --git a/drivers/net/wireless/ath/ath10k/testmode.c b/drivers/net/wireless/ath/ath10k/testmode.c
index a29cfb9c72c2..1bffe3fbea3f 100644
--- a/drivers/net/wireless/ath/ath10k/testmode.c
+++ b/drivers/net/wireless/ath/ath10k/testmode.c
@@ -174,8 +174,23 @@ static int ath10k_tm_fetch_firmware(struct ath10k *ar)
{
struct ath10k_fw_components *utf_mode_fw;
int ret;
+ char fw_name[100];
+ int fw_api2 = 2;
+
+ switch (ar->hif.bus) {
+ case ATH10K_BUS_SDIO:
+ case ATH10K_BUS_USB:
+ scnprintf(fw_name, sizeof(fw_name), "%s-%s-%d.bin",
+ ATH10K_FW_UTF_FILE_BASE, ath10k_bus_str(ar->hif.bus),
+ fw_api2);
+ break;
+ default:
+ scnprintf(fw_name, sizeof(fw_name), "%s-%d.bin",
+ ATH10K_FW_UTF_FILE_BASE, fw_api2);
+ break;
+ }
- ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_UTF_API2_FILE,
+ ret = ath10k_core_fetch_firmware_api_n(ar, fw_name,
&ar->testmode.utf_mode_fw.fw_file);
if (ret == 0) {
ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode using fw utf api 2");
diff --git a/drivers/net/wireless/ath/ath10k/trace.c b/drivers/net/wireless/ath/ath10k/trace.c
index 3ecdff17f64e..c7d4c97e6079 100644
--- a/drivers/net/wireless/ath/ath10k/trace.c
+++ b/drivers/net/wireless/ath/ath10k/trace.c
@@ -7,3 +7,4 @@
#define CREATE_TRACE_POINTS
#include "trace.h"
+EXPORT_SYMBOL(__tracepoint_ath10k_log_dbg);
diff --git a/drivers/net/wireless/ath/ath10k/trace.h b/drivers/net/wireless/ath/ath10k/trace.h
index ba977bbe6291..ab916459d237 100644
--- a/drivers/net/wireless/ath/ath10k/trace.h
+++ b/drivers/net/wireless/ath/ath10k/trace.h
@@ -29,7 +29,11 @@ static inline u32 ath10k_frm_hdr_len(const void *buf, size_t len)
#if !defined(CONFIG_ATH10K_TRACING)
#undef TRACE_EVENT
#define TRACE_EVENT(name, proto, ...) \
-static inline void trace_ ## name(proto) {}
+static inline void trace_ ## name(proto) {} \
+static inline bool trace_##name##_enabled(void) \
+{ \
+ return false; \
+}
#undef DECLARE_EVENT_CLASS
#define DECLARE_EVENT_CLASS(...)
#undef DEFINE_EVENT
diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c
index c5818d28f55a..4102df016931 100644
--- a/drivers/net/wireless/ath/ath10k/txrx.c
+++ b/drivers/net/wireless/ath/ath10k/txrx.c
@@ -150,6 +150,9 @@ struct ath10k_peer *ath10k_peer_find_by_id(struct ath10k *ar, int peer_id)
{
struct ath10k_peer *peer;
+ if (peer_id >= BITS_PER_TYPE(peer->peer_ids))
+ return NULL;
+
lockdep_assert_held(&ar->data_lock);
list_for_each_entry(peer, &ar->peers, list)
diff --git a/drivers/net/wireless/ath/ath10k/usb.c b/drivers/net/wireless/ath/ath10k/usb.c
index 970cf69ac35f..e1420f67f776 100644
--- a/drivers/net/wireless/ath/ath10k/usb.c
+++ b/drivers/net/wireless/ath/ath10k/usb.c
@@ -973,7 +973,7 @@ static int ath10k_usb_probe(struct usb_interface *interface,
struct usb_device *dev = interface_to_usbdev(interface);
int ret, vendor_id, product_id;
enum ath10k_hw_rev hw_rev;
- struct ath10k_bus_params bus_params;
+ struct ath10k_bus_params bus_params = {};
/* Assumption: All USB based chipsets (so far) are QCA9377 based.
* If there will be newer chipsets that does not use the hw reg
@@ -1016,7 +1016,7 @@ static int ath10k_usb_probe(struct usb_interface *interface,
}
/* TODO: remove this once USB support is fully implemented */
- ath10k_warn(ar, "WARNING: ath10k USB support is incomplete, don't expect anything to work!\n");
+ ath10k_warn(ar, "Warning: ath10k USB support is incomplete, don't expect anything to work!\n");
return 0;
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index 582fb11f648a..2985bb17decd 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -2,7 +2,7 @@
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*/
#include "core.h"
#include "debug.h"
@@ -212,6 +212,13 @@ static int ath10k_wmi_tlv_event_bcn_tx_status(struct ath10k *ar,
return 0;
}
+static void ath10k_wmi_tlv_event_vdev_delete_resp(struct ath10k *ar,
+ struct sk_buff *skb)
+{
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_DELETE_RESP_EVENTID\n");
+ complete(&ar->vdev_delete_done);
+}
+
static int ath10k_wmi_tlv_event_diag_data(struct ath10k *ar,
struct sk_buff *skb)
{
@@ -458,6 +465,24 @@ static void ath10k_wmi_event_tdls_peer(struct ath10k *ar, struct sk_buff *skb)
kfree(tb);
}
+static int ath10k_wmi_tlv_event_peer_delete_resp(struct ath10k *ar,
+ struct sk_buff *skb)
+{
+ struct wmi_peer_delete_resp_ev_arg *arg;
+ struct wmi_tlv *tlv_hdr;
+
+ tlv_hdr = (struct wmi_tlv *)skb->data;
+ arg = (struct wmi_peer_delete_resp_ev_arg *)tlv_hdr->value;
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "vdev id %d", arg->vdev_id);
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "peer mac addr %pM", &arg->peer_addr);
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer delete response\n");
+
+ complete(&ar->peer_delete_done);
+
+ return 0;
+}
+
/***********/
/* TLV ops */
/***********/
@@ -514,6 +539,9 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb)
case WMI_TLV_VDEV_STOPPED_EVENTID:
ath10k_wmi_event_vdev_stopped(ar, skb);
break;
+ case WMI_TLV_VDEV_DELETE_RESP_EVENTID:
+ ath10k_wmi_tlv_event_vdev_delete_resp(ar, skb);
+ break;
case WMI_TLV_PEER_STA_KICKOUT_EVENTID:
ath10k_wmi_event_peer_sta_kickout(ar, skb);
break;
@@ -607,6 +635,9 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb)
case WMI_TLV_TDLS_PEER_EVENTID:
ath10k_wmi_event_tdls_peer(ar, skb);
break;
+ case WMI_TLV_PEER_DELETE_RESP_EVENTID:
+ ath10k_wmi_tlv_event_peer_delete_resp(ar, skb);
+ break;
case WMI_TLV_MGMT_TX_COMPLETION_EVENTID:
ath10k_wmi_event_mgmt_tx_compl(ar, skb);
break;
@@ -1905,6 +1936,28 @@ ath10k_wmi_tlv_op_gen_stop_scan(struct ath10k *ar,
return skb;
}
+static int ath10k_wmi_tlv_op_get_vdev_subtype(struct ath10k *ar,
+ enum wmi_vdev_subtype subtype)
+{
+ switch (subtype) {
+ case WMI_VDEV_SUBTYPE_NONE:
+ return WMI_TLV_VDEV_SUBTYPE_NONE;
+ case WMI_VDEV_SUBTYPE_P2P_DEVICE:
+ return WMI_TLV_VDEV_SUBTYPE_P2P_DEV;
+ case WMI_VDEV_SUBTYPE_P2P_CLIENT:
+ return WMI_TLV_VDEV_SUBTYPE_P2P_CLI;
+ case WMI_VDEV_SUBTYPE_P2P_GO:
+ return WMI_TLV_VDEV_SUBTYPE_P2P_GO;
+ case WMI_VDEV_SUBTYPE_PROXY_STA:
+ return WMI_TLV_VDEV_SUBTYPE_PROXY_STA;
+ case WMI_VDEV_SUBTYPE_MESH_11S:
+ return WMI_TLV_VDEV_SUBTYPE_MESH_11S;
+ case WMI_VDEV_SUBTYPE_MESH_NON_11S:
+ return -ENOTSUPP;
+ }
+ return -ENOTSUPP;
+}
+
static struct sk_buff *
ath10k_wmi_tlv_op_gen_vdev_create(struct ath10k *ar,
u32 vdev_id,
@@ -2840,8 +2893,10 @@ ath10k_wmi_tlv_op_gen_mgmt_tx_send(struct ath10k *ar, struct sk_buff *msdu,
if ((ieee80211_is_action(hdr->frame_control) ||
ieee80211_is_deauth(hdr->frame_control) ||
ieee80211_is_disassoc(hdr->frame_control)) &&
- ieee80211_has_protected(hdr->frame_control))
+ ieee80211_has_protected(hdr->frame_control)) {
+ skb_put(msdu, IEEE80211_CCMP_MIC_LEN);
buf_len += IEEE80211_CCMP_MIC_LEN;
+ }
buf_len = min_t(u32, buf_len, WMI_TLV_MGMT_TX_FRAME_MAX_LEN);
buf_len = round_up(buf_len, 4);
@@ -4305,7 +4360,7 @@ static const struct wmi_ops wmi_tlv_ops = {
.gen_tdls_peer_update = ath10k_wmi_tlv_op_gen_tdls_peer_update,
.gen_adaptive_qcs = ath10k_wmi_tlv_op_gen_adaptive_qcs,
.fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill,
- .get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype,
+ .get_vdev_subtype = ath10k_wmi_tlv_op_get_vdev_subtype,
.gen_echo = ath10k_wmi_tlv_op_gen_echo,
.gen_vdev_spectral_conf = ath10k_wmi_tlv_op_gen_vdev_spectral_conf,
.gen_vdev_spectral_enable = ath10k_wmi_tlv_op_gen_vdev_spectral_enable,
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
index 65e6aa520b06..d691f06e58f2 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
@@ -2,7 +2,7 @@
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*/
#ifndef _WMI_TLV_H
#define _WMI_TLV_H
@@ -301,11 +301,15 @@ enum wmi_tlv_event_id {
WMI_TLV_VDEV_STOPPED_EVENTID,
WMI_TLV_VDEV_INSTALL_KEY_COMPLETE_EVENTID,
WMI_TLV_VDEV_MCC_BCN_INTERVAL_CHANGE_REQ_EVENTID,
+ WMI_TLV_VDEV_TSF_REPORT_EVENTID,
+ WMI_TLV_VDEV_DELETE_RESP_EVENTID,
WMI_TLV_PEER_STA_KICKOUT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_PEER),
WMI_TLV_PEER_INFO_EVENTID,
WMI_TLV_PEER_TX_FAIL_CNT_THR_EVENTID,
WMI_TLV_PEER_ESTIMATED_LINKSPEED_EVENTID,
WMI_TLV_PEER_STATE_EVENTID,
+ WMI_TLV_PEER_ASSOC_CONF_EVENTID,
+ WMI_TLV_PEER_DELETE_RESP_EVENTID,
WMI_TLV_MGMT_RX_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_MGMT),
WMI_TLV_HOST_SWBA_EVENTID,
WMI_TLV_TBTTOFFSET_UPDATE_EVENTID,
@@ -1567,6 +1571,10 @@ wmi_tlv_svc_map(const __le32 *in, unsigned long *out, size_t len)
WMI_SERVICE_SAP_AUTH_OFFLOAD, len);
SVCMAP(WMI_TLV_SERVICE_MGMT_TX_WMI,
WMI_SERVICE_MGMT_TX_WMI, len);
+ SVCMAP(WMI_TLV_SERVICE_MESH_11S,
+ WMI_SERVICE_MESH_11S, len);
+ SVCMAP(WMI_TLV_SERVICE_SYNC_DELETE_CMDS,
+ WMI_SERVICE_SYNC_DELETE_CMDS, len);
}
static inline void
@@ -1775,6 +1783,16 @@ struct wmi_tlv_start_scan_cmd {
struct wmi_mac_addr mac_mask;
} __packed;
+enum wmi_tlv_vdev_subtype {
+ WMI_TLV_VDEV_SUBTYPE_NONE = 0,
+ WMI_TLV_VDEV_SUBTYPE_P2P_DEV = 1,
+ WMI_TLV_VDEV_SUBTYPE_P2P_CLI = 2,
+ WMI_TLV_VDEV_SUBTYPE_P2P_GO = 3,
+ WMI_TLV_VDEV_SUBTYPE_PROXY_STA = 4,
+ WMI_TLV_VDEV_SUBTYPE_MESH = 5,
+ WMI_TLV_VDEV_SUBTYPE_MESH_11S = 6,
+};
+
struct wmi_tlv_vdev_start_cmd {
__le32 vdev_id;
__le32 requestor_id;
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 98a90e49d666..4f707c6394bb 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -8309,7 +8309,7 @@ ath10k_wmi_fw_vdev_stats_fill(const struct ath10k_fw_stats_vdev *vdev,
static void
ath10k_wmi_fw_peer_stats_fill(const struct ath10k_fw_stats_peer *peer,
- char *buf, u32 *length)
+ char *buf, u32 *length, bool extended_peer)
{
u32 len = *length;
u32 buf_len = ATH10K_FW_STATS_BUF_SIZE;
@@ -8322,13 +8322,27 @@ ath10k_wmi_fw_peer_stats_fill(const struct ath10k_fw_stats_peer *peer,
"Peer TX rate", peer->peer_tx_rate);
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
"Peer RX rate", peer->peer_rx_rate);
- len += scnprintf(buf + len, buf_len - len, "%30s %llu\n",
- "Peer RX duration", peer->rx_duration);
+ if (!extended_peer)
+ len += scnprintf(buf + len, buf_len - len, "%30s %llu\n",
+ "Peer RX duration", peer->rx_duration);
len += scnprintf(buf + len, buf_len - len, "\n");
*length = len;
}
+static void
+ath10k_wmi_fw_extd_peer_stats_fill(const struct ath10k_fw_extd_stats_peer *peer,
+ char *buf, u32 *length)
+{
+ u32 len = *length;
+ u32 buf_len = ATH10K_FW_STATS_BUF_SIZE;
+
+ len += scnprintf(buf + len, buf_len - len, "%30s %pM\n",
+ "Peer MAC address", peer->peer_macaddr);
+ len += scnprintf(buf + len, buf_len - len, "%30s %llu\n",
+ "Peer RX duration", peer->rx_duration);
+}
+
void ath10k_wmi_main_op_fw_stats_fill(struct ath10k *ar,
struct ath10k_fw_stats *fw_stats,
char *buf)
@@ -8374,7 +8388,8 @@ void ath10k_wmi_main_op_fw_stats_fill(struct ath10k *ar,
"=================");
list_for_each_entry(peer, &fw_stats->peers, list) {
- ath10k_wmi_fw_peer_stats_fill(peer, buf, &len);
+ ath10k_wmi_fw_peer_stats_fill(peer, buf, &len,
+ fw_stats->extended);
}
unlock:
@@ -8432,7 +8447,8 @@ void ath10k_wmi_10x_op_fw_stats_fill(struct ath10k *ar,
"=================");
list_for_each_entry(peer, &fw_stats->peers, list) {
- ath10k_wmi_fw_peer_stats_fill(peer, buf, &len);
+ ath10k_wmi_fw_peer_stats_fill(peer, buf, &len,
+ fw_stats->extended);
}
unlock:
@@ -8541,6 +8557,7 @@ void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar,
const struct ath10k_fw_stats_pdev *pdev;
const struct ath10k_fw_stats_vdev_extd *vdev;
const struct ath10k_fw_stats_peer *peer;
+ const struct ath10k_fw_extd_stats_peer *extd_peer;
size_t num_peers;
size_t num_vdevs;
@@ -8603,7 +8620,15 @@ void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar,
"=================");
list_for_each_entry(peer, &fw_stats->peers, list) {
- ath10k_wmi_fw_peer_stats_fill(peer, buf, &len);
+ ath10k_wmi_fw_peer_stats_fill(peer, buf, &len,
+ fw_stats->extended);
+ }
+
+ if (fw_stats->extended) {
+ list_for_each_entry(extd_peer, &fw_stats->peers_extd, list) {
+ ath10k_wmi_fw_extd_peer_stats_fill(extd_peer, buf,
+ &len);
+ }
}
unlock:
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index e1c40bb69932..838768c98adc 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -2,7 +2,7 @@
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*/
#ifndef _WMI_H_
@@ -200,6 +200,8 @@ enum wmi_service {
WMI_SERVICE_RTT_RESPONDER_ROLE,
WMI_SERVICE_PER_PACKET_SW_ENCRYPT,
WMI_SERVICE_REPORT_AIRTIME,
+ WMI_SERVICE_SYNC_DELETE_CMDS,
+ WMI_SERVICE_TX_PWR_PER_PEER,
/* Remember to add the new value to wmi_service_name()! */
@@ -367,6 +369,7 @@ enum wmi_10_4_service {
WMI_10_4_SERVICE_RTT_RESPONDER_ROLE,
WMI_10_4_SERVICE_EXT_PEER_TID_CONFIGS_SUPPORT,
WMI_10_4_SERVICE_REPORT_AIRTIME,
+ WMI_10_4_SERVICE_TX_PWR_PER_PEER,
};
static inline char *wmi_service_name(enum wmi_service service_id)
@@ -491,6 +494,8 @@ static inline char *wmi_service_name(enum wmi_service service_id)
SVCSTR(WMI_SERVICE_RTT_RESPONDER_ROLE);
SVCSTR(WMI_SERVICE_PER_PACKET_SW_ENCRYPT);
SVCSTR(WMI_SERVICE_REPORT_AIRTIME);
+ SVCSTR(WMI_SERVICE_SYNC_DELETE_CMDS);
+ SVCSTR(WMI_SERVICE_TX_PWR_PER_PEER);
case WMI_SERVICE_MAX:
return NULL;
@@ -818,6 +823,8 @@ static inline void wmi_10_4_svc_map(const __le32 *in, unsigned long *out,
WMI_SERVICE_PER_PACKET_SW_ENCRYPT, len);
SVCMAP(WMI_10_4_SERVICE_REPORT_AIRTIME,
WMI_SERVICE_REPORT_AIRTIME, len);
+ SVCMAP(WMI_10_4_SERVICE_TX_PWR_PER_PEER,
+ WMI_SERVICE_TX_PWR_PER_PEER, len);
}
#undef SVCMAP
@@ -4535,9 +4542,10 @@ enum wmi_10_4_stats_id {
};
enum wmi_tlv_stats_id {
- WMI_TLV_STAT_PDEV = BIT(0),
- WMI_TLV_STAT_VDEV = BIT(1),
- WMI_TLV_STAT_PEER = BIT(2),
+ WMI_TLV_STAT_PEER = BIT(0),
+ WMI_TLV_STAT_AP = BIT(1),
+ WMI_TLV_STAT_PDEV = BIT(2),
+ WMI_TLV_STAT_VDEV = BIT(3),
WMI_TLV_STAT_PEER_EXTD = BIT(10),
};
@@ -6259,6 +6267,8 @@ enum wmi_peer_param {
WMI_PEER_CHAN_WIDTH = 0x4,
WMI_PEER_NSS = 0x5,
WMI_PEER_USE_4ADDR = 0x6,
+ WMI_PEER_USE_FIXED_PWR = 0x8,
+ WMI_PEER_PARAM_FIXED_RATE = 0x9,
WMI_PEER_DEBUG = 0xa,
WMI_PEER_PHYMODE = 0xd,
WMI_PEER_DUMMY_VAR = 0xff, /* dummy parameter for STA PS workaround */
@@ -6756,6 +6766,11 @@ struct wmi_tlv_mgmt_tx_bundle_compl_ev_arg {
const __le32 *ack_rssi;
};
+struct wmi_peer_delete_resp_ev_arg {
+ __le32 vdev_id;
+ struct wmi_mac_addr peer_addr;
+};
+
struct wmi_mgmt_rx_ev_arg {
__le32 channel;
__le32 snr;
diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig
index c587146795f6..802f8f87773a 100644
--- a/drivers/net/wireless/ath/ath5k/Kconfig
+++ b/drivers/net/wireless/ath/ath5k/Kconfig
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0-only
+# SPDX-License-Identifier: ISC
config ATH5K
tristate "Atheros 5xxx wireless cards support"
depends on (PCI || ATH25) && MAC80211
diff --git a/drivers/net/wireless/ath/ath5k/Makefile b/drivers/net/wireless/ath/ath5k/Makefile
index a8724eee21f8..78f318d49af5 100644
--- a/drivers/net/wireless/ath/ath5k/Makefile
+++ b/drivers/net/wireless/ath/ath5k/Makefile
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: ISC
ath5k-y += caps.o
ath5k-y += initvals.o
ath5k-y += eeprom.o
diff --git a/drivers/net/wireless/ath/ath6kl/Kconfig b/drivers/net/wireless/ath/ath6kl/Kconfig
index 2b27a87e74f5..dcf8ca0dcc52 100644
--- a/drivers/net/wireless/ath/ath6kl/Kconfig
+++ b/drivers/net/wireless/ath/ath6kl/Kconfig
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0-only
+# SPDX-License-Identifier: ISC
config ATH6KL
tristate "Atheros mobile chipsets support"
depends on CFG80211
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 5477a014e1fb..37cf602d8adf 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -2194,13 +2194,13 @@ static int ath6kl_wow_suspend_vif(struct ath6kl_vif *vif,
if (!in_dev)
return 0;
- ifa = in_dev->ifa_list;
+ ifa = rtnl_dereference(in_dev->ifa_list);
memset(&ips, 0, sizeof(ips));
/* Configure IP addr only if IP address count < MAX_IP_ADDRS */
while (index < MAX_IP_ADDRS && ifa) {
ips[index] = ifa->ifa_local;
- ifa = ifa->ifa_next;
+ ifa = rtnl_dereference(ifa->ifa_next);
index++;
}
diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c
index 4e94b22eaada..54337d60f288 100644
--- a/drivers/net/wireless/ath/ath6kl/debug.c
+++ b/drivers/net/wireless/ath/ath6kl/debug.c
@@ -1132,8 +1132,7 @@ int ath6kl_debug_roam_tbl_event(struct ath6kl *ar, const void *buf,
tbl = (const struct wmi_target_roam_tbl *) buf;
num_entries = le16_to_cpu(tbl->num_entries);
- if (sizeof(*tbl) + num_entries * sizeof(struct wmi_bss_roam_info) >
- len)
+ if (struct_size(tbl, info, num_entries) > len)
return -EINVAL;
if (ar->debug.roam_tbl == NULL ||
diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c
index 434b66829646..c68848819a52 100644
--- a/drivers/net/wireless/ath/ath6kl/htc_pipe.c
+++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c
@@ -898,9 +898,6 @@ static int htc_process_trailer(struct htc_target *target, u8 *buffer,
break;
}
- if (status != 0)
- break;
-
/* advance buffer past this record for next time around */
buffer += record->len;
len -= record->len;
diff --git a/drivers/net/wireless/ath/ath6kl/trace.h b/drivers/net/wireless/ath/ath6kl/trace.h
index 91e735cfdef7..a3d3740419eb 100644
--- a/drivers/net/wireless/ath/ath6kl/trace.h
+++ b/drivers/net/wireless/ath/ath6kl/trace.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: ISC */
#if !defined(_ATH6KL_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
#include <net/cfg80211.h>
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 68854c45d0a4..2382c6c46851 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -1176,6 +1176,10 @@ static int ath6kl_wmi_pstream_timeout_event_rx(struct wmi *wmi, u8 *datap,
return -EINVAL;
ev = (struct wmi_pstream_timeout_event *) datap;
+ if (ev->traffic_class >= WMM_NUM_AC) {
+ ath6kl_err("invalid traffic class: %d\n", ev->traffic_class);
+ return -EINVAL;
+ }
/*
* When the pstream (fat pipe == AC) timesout, it means there were
@@ -1295,8 +1299,7 @@ static int ath6kl_wmi_neighbor_report_event_rx(struct wmi *wmi, u8 *datap,
if (len < sizeof(*ev))
return -EINVAL;
ev = (struct wmi_neighbor_report_event *) datap;
- if (sizeof(*ev) + ev->num_neighbors * sizeof(struct wmi_neighbor_info)
- > len) {
+ if (struct_size(ev, neighbor, ev->num_neighbors) > len) {
ath6kl_dbg(ATH6KL_DBG_WMI,
"truncated neighbor event (num=%d len=%d)\n",
ev->num_neighbors, len);
@@ -1517,6 +1520,10 @@ static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len,
return -EINVAL;
reply = (struct wmi_cac_event *) datap;
+ if (reply->ac >= WMM_NUM_AC) {
+ ath6kl_err("invalid AC: %d\n", reply->ac);
+ return -EINVAL;
+ }
if ((reply->cac_indication == CAC_INDICATION_ADMISSION_RESP) &&
(reply->status_code != IEEE80211_TSPEC_STATUS_ADMISS_ACCEPTED)) {
@@ -2633,7 +2640,7 @@ int ath6kl_wmi_delete_pstream_cmd(struct wmi *wmi, u8 if_idx, u8 traffic_class,
u16 active_tsids = 0;
int ret;
- if (traffic_class > 3) {
+ if (traffic_class >= WMM_NUM_AC) {
ath6kl_err("invalid traffic class: %d\n", traffic_class);
return -EINVAL;
}
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig
index a1ef8769983a..5601cfd6a293 100644
--- a/drivers/net/wireless/ath/ath9k/Kconfig
+++ b/drivers/net/wireless/ath/ath9k/Kconfig
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0-only
+# SPDX-License-Identifier: ISC
config ATH9K_HW
tristate
config ATH9K_COMMON
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index f71b2ad8275c..15af0a836925 100644
--- a/drivers/net/wireless/ath/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: ISC
ath9k-y += beacon.o \
gpio.o \
init.o \
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index 98c5f524a360..daf30f9946b4 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -157,7 +157,9 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
freq = centers.synth_center;
if (freq < 4800) { /* 2 GHz, fractional mode */
- if (AR_SREV_9330(ah)) {
+ if (AR_SREV_9330(ah) || AR_SREV_9485(ah) ||
+ AR_SREV_9531(ah) || AR_SREV_9550(ah) ||
+ AR_SREV_9561(ah) || AR_SREV_9565(ah)) {
if (ah->is_clk_25mhz)
div = 75;
else
@@ -166,16 +168,6 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
channelSel = (freq * 4) / div;
chan_frac = (((freq * 4) % div) * 0x20000) / div;
channelSel = (channelSel << 17) | chan_frac;
- } else if (AR_SREV_9485(ah) || AR_SREV_9565(ah)) {
- /*
- * freq_ref = 40 / (refdiva >> amoderefsel);
- * where refdiva=1 and amoderefsel=0
- * ndiv = ((chan_mhz * 4) / 3) / freq_ref;
- * chansel = int(ndiv), chanfrac = (ndiv - chansel) * 0x20000
- */
- channelSel = (freq * 4) / 120;
- chan_frac = (((freq * 4) % 120) * 0x20000) / 120;
- channelSel = (channelSel << 17) | chan_frac;
} else if (AR_SREV_9340(ah)) {
if (ah->is_clk_25mhz) {
channelSel = (freq * 2) / 75;
@@ -184,16 +176,6 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
} else {
channelSel = CHANSEL_2G(freq) >> 1;
}
- } else if (AR_SREV_9550(ah) || AR_SREV_9531(ah) ||
- AR_SREV_9561(ah)) {
- if (ah->is_clk_25mhz)
- div = 75;
- else
- div = 120;
-
- channelSel = (freq * 4) / div;
- chan_frac = (((freq * 4) % div) * 0x20000) / div;
- channelSel = (channelSel << 17) | chan_frac;
} else {
channelSel = CHANSEL_2G(freq);
}
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c
index 6fbd5559c0c0..c22d457dbc54 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom.c
@@ -428,7 +428,7 @@ u16 ath9k_hw_get_scaled_power(struct ath_hw *ah, u16 power_limit,
else
power_limit = 0;
- return power_limit;
+ return min_t(u16, power_limit, MAX_RATE_POWER);
}
void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah)
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
index b8c0a08066a0..e8c2cc03be0c 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
@@ -424,6 +424,7 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
ath9k_hw_get_channel_centers(ah, chan, &centers);
scaledPower = powerLimit - antenna_reduction;
+ scaledPower = min_t(u16, scaledPower, MAX_RATE_POWER);
numCtlModes = ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40;
pCtlMode = ctlModesFor11g;
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 8581d917635a..052deffb4c9d 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -252,8 +252,9 @@ void ath9k_hw_get_channel_centers(struct ath_hw *ah,
/* Chip Revisions */
/******************/
-static void ath9k_hw_read_revisions(struct ath_hw *ah)
+static bool ath9k_hw_read_revisions(struct ath_hw *ah)
{
+ u32 srev;
u32 val;
if (ah->get_mac_revision)
@@ -269,25 +270,33 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah)
val = REG_READ(ah, AR_SREV);
ah->hw_version.macRev = MS(val, AR_SREV_REVISION2);
}
- return;
+ return true;
case AR9300_DEVID_AR9340:
ah->hw_version.macVersion = AR_SREV_VERSION_9340;
- return;
+ return true;
case AR9300_DEVID_QCA955X:
ah->hw_version.macVersion = AR_SREV_VERSION_9550;
- return;
+ return true;
case AR9300_DEVID_AR953X:
ah->hw_version.macVersion = AR_SREV_VERSION_9531;
- return;
+ return true;
case AR9300_DEVID_QCA956X:
ah->hw_version.macVersion = AR_SREV_VERSION_9561;
- return;
+ return true;
}
- val = REG_READ(ah, AR_SREV) & AR_SREV_ID;
+ srev = REG_READ(ah, AR_SREV);
+
+ if (srev == -EIO) {
+ ath_err(ath9k_hw_common(ah),
+ "Failed to read SREV register");
+ return false;
+ }
+
+ val = srev & AR_SREV_ID;
if (val == 0xFF) {
- val = REG_READ(ah, AR_SREV);
+ val = srev;
ah->hw_version.macVersion =
(val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S;
ah->hw_version.macRev = MS(val, AR_SREV_REVISION2);
@@ -306,6 +315,8 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah)
if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCIE)
ah->is_pciexpress = true;
}
+
+ return true;
}
/************************************/
@@ -446,7 +457,7 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
regulatory->country_code = CTRY_DEFAULT;
- regulatory->power_limit = MAX_RATE_POWER;
+ regulatory->power_limit = MAX_COMBINED_POWER;
ah->hw_version.magic = AR5416_MAGIC;
ah->hw_version.subvendorid = 0;
@@ -559,7 +570,10 @@ static int __ath9k_hw_init(struct ath_hw *ah)
struct ath_common *common = ath9k_hw_common(ah);
int r = 0;
- ath9k_hw_read_revisions(ah);
+ if (!ath9k_hw_read_revisions(ah)) {
+ ath_err(common, "Could not read hardware revisions");
+ return -EOPNOTSUPP;
+ }
switch (ah->hw_version.macVersion) {
case AR_SREV_VERSION_5416_PCI:
@@ -2952,7 +2966,7 @@ void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan,
ctl = ath9k_regd_get_ctl(reg, chan);
channel = chan->chan;
- chan_pwr = min_t(int, channel->max_power * 2, MAX_RATE_POWER);
+ chan_pwr = min_t(int, channel->max_power * 2, MAX_COMBINED_POWER);
new_pwr = min_t(int, chan_pwr, reg->power_limit);
ah->eep_ops->set_txpower(ah, chan, ctl,
@@ -2965,9 +2979,9 @@ void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test)
struct ath9k_channel *chan = ah->curchan;
struct ieee80211_channel *channel = chan->chan;
- reg->power_limit = min_t(u32, limit, MAX_RATE_POWER);
+ reg->power_limit = min_t(u32, limit, MAX_COMBINED_POWER);
if (test)
- channel->max_power = MAX_RATE_POWER / 2;
+ channel->max_power = MAX_COMBINED_POWER / 2;
ath9k_hw_apply_txpower(ah, chan, test);
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 68956cdc8c9a..2e4489700a85 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -173,6 +173,7 @@
#define ATH9K_NUM_QUEUES 10
#define MAX_RATE_POWER 63
+#define MAX_COMBINED_POWER 254 /* 128 dBm, chosen to fit in u8 */
#define AH_WAIT_TIMEOUT 100000 /* (us) */
#define AH_TSF_WRITE_TIMEOUT 100 /* (us) */
#define AH_TIME_QUANTUM 10
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index a04d8616fe09..17c318902cb8 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -805,7 +805,7 @@ static void ath9k_init_band_txpower(struct ath_softc *sc, int band)
ah->curchan = &ah->channels[chan->hw_value];
cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_HT20);
ath9k_cmn_get_channel(sc->hw, ah, &chandef);
- ath9k_hw_set_txpowerlimit(ah, MAX_RATE_POWER, true);
+ ath9k_hw_set_txpowerlimit(ah, MAX_COMBINED_POWER, true);
}
}
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 4e97f7f3b2a3..06e660858766 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -815,6 +815,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_hdr *hdr;
bool discard_current = sc->rx.discard_next;
+ bool is_phyerr;
/*
* Discard corrupt descriptors which are marked in
@@ -827,8 +828,11 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
/*
* Discard zero-length packets and packets smaller than an ACK
+ * which are not PHY_ERROR (short radar pulses have a length of 3)
*/
- if (rx_stats->rs_datalen < 10) {
+ is_phyerr = rx_stats->rs_status & ATH9K_RXERR_PHY;
+ if (!rx_stats->rs_datalen ||
+ (rx_stats->rs_datalen < 10 && !is_phyerr)) {
RX_STAT_INC(sc, rx_len_err);
goto corrupt;
}
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index b17e1ca40995..31e7b108279c 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -410,7 +410,6 @@ static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf,
struct ath_tx_status *ts, int txok,
int *nframes, int *nbad)
{
- struct ath_frame_info *fi;
u16 seq_st = 0;
u32 ba[WME_BA_BMP_SIZE >> 5];
int ba_index;
@@ -426,7 +425,6 @@ static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf,
}
while (bf) {
- fi = get_frame_info(bf->bf_mpdu);
ba_index = ATH_BA_INDEX(seq_st, bf->bf_state.seqno);
(*nframes)++;
@@ -446,7 +444,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
{
struct ath_node *an = NULL;
struct sk_buff *skb;
- struct ieee80211_hdr *hdr;
struct ieee80211_tx_info *tx_info;
struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;
struct list_head bf_head;
@@ -463,8 +460,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
int bar_index = -1;
skb = bf->bf_mpdu;
- hdr = (struct ieee80211_hdr *)skb->data;
-
tx_info = IEEE80211_SKB_CB(skb);
memcpy(rates, bf->rates, sizeof(rates));
@@ -668,7 +663,8 @@ static bool bf_is_ampdu_not_probing(struct ath_buf *bf)
static void ath_tx_count_airtime(struct ath_softc *sc,
struct ieee80211_sta *sta,
struct ath_buf *bf,
- struct ath_tx_status *ts)
+ struct ath_tx_status *ts,
+ u8 tid)
{
u32 airtime = 0;
int i;
@@ -679,7 +675,7 @@ static void ath_tx_count_airtime(struct ath_softc *sc,
airtime += rate_dur * bf->rates[i].count;
}
- ieee80211_sta_register_airtime(sta, ts->tid, airtime, 0);
+ ieee80211_sta_register_airtime(sta, tid, airtime, 0);
}
static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
@@ -709,7 +705,7 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
if (sta) {
struct ath_node *an = (struct ath_node *)sta->drv_priv;
tid = ath_get_skb_tid(sc, an, bf->bf_mpdu);
- ath_tx_count_airtime(sc, sta, bf, ts);
+ ath_tx_count_airtime(sc, sta, bf, ts, tid->tidno);
if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY))
tid->clear_ps_filter = true;
}
@@ -2269,12 +2265,10 @@ static int ath_tx_prepare(struct ieee80211_hw *hw, struct sk_buff *skb,
int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ath_tx_control *txctl)
{
- struct ieee80211_hdr *hdr;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_sta *sta = txctl->sta;
struct ieee80211_vif *vif = info->control.vif;
struct ath_frame_info *fi = get_frame_info(skb);
- struct ath_vif *avp = NULL;
struct ath_softc *sc = hw->priv;
struct ath_txq *txq = txctl->txq;
struct ath_atx_tid *tid = NULL;
@@ -2283,16 +2277,12 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
bool ps_resp;
int q, ret;
- if (vif)
- avp = (void *)vif->drv_priv;
-
ps_resp = !!(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE);
ret = ath_tx_prepare(hw, skb, txctl);
if (ret)
return ret;
- hdr = (struct ieee80211_hdr *) skb->data;
/*
* At this point, the vif, hw_key and sta pointers in the tx control
* info are no longer valid (overwritten by the ath_frame_info data.
diff --git a/drivers/net/wireless/ath/carl9170/mac.c b/drivers/net/wireless/ath/carl9170/mac.c
index 7d4a72dc98db..b2eeb9fd68d2 100644
--- a/drivers/net/wireless/ath/carl9170/mac.c
+++ b/drivers/net/wireless/ath/carl9170/mac.c
@@ -519,7 +519,7 @@ int carl9170_set_mac_tpc(struct ar9170 *ar, struct ieee80211_channel *channel)
power = ar->power_5G_leg[0] & 0x3f;
break;
default:
- BUG_ON(1);
+ BUG();
}
power = min_t(unsigned int, power, ar->hw->conf.power_level * 2);
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index 7f1bdea742b8..40a8054f8aa6 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -1387,13 +1387,8 @@ static int carl9170_op_conf_tx(struct ieee80211_hw *hw,
int ret;
mutex_lock(&ar->mutex);
- if (queue < ar->hw->queues) {
- memcpy(&ar->edcf[ar9170_qmap[queue]], param, sizeof(*param));
- ret = carl9170_set_qos(ar);
- } else {
- ret = -EINVAL;
- }
-
+ memcpy(&ar->edcf[ar9170_qmap[queue]], param, sizeof(*param));
+ ret = carl9170_set_qos(ar);
mutex_unlock(&ar->mutex);
return ret;
}
diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c
index 8e154f6364a3..23ab8a80c18c 100644
--- a/drivers/net/wireless/ath/carl9170/rx.c
+++ b/drivers/net/wireless/ath/carl9170/rx.c
@@ -795,7 +795,7 @@ static void carl9170_rx_untie_data(struct ar9170 *ar, u8 *buf, int len)
break;
default:
- BUG_ON(1);
+ BUG();
break;
}
diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c
index e7c3f3b8457d..99f1897a775d 100644
--- a/drivers/net/wireless/ath/carl9170/usb.c
+++ b/drivers/net/wireless/ath/carl9170/usb.c
@@ -128,6 +128,8 @@ static const struct usb_device_id carl9170_usb_ids[] = {
};
MODULE_DEVICE_TABLE(usb, carl9170_usb_ids);
+static struct usb_driver carl9170_driver;
+
static void carl9170_usb_submit_data_urb(struct ar9170 *ar)
{
struct urb *urb;
@@ -966,32 +968,28 @@ err_out:
static void carl9170_usb_firmware_failed(struct ar9170 *ar)
{
- struct device *parent = ar->udev->dev.parent;
- struct usb_device *udev;
-
- /*
- * Store a copy of the usb_device pointer locally.
- * This is because device_release_driver initiates
- * carl9170_usb_disconnect, which in turn frees our
- * driver context (ar).
+ /* Store a copies of the usb_interface and usb_device pointer locally.
+ * This is because release_driver initiates carl9170_usb_disconnect,
+ * which in turn frees our driver context (ar).
*/
- udev = ar->udev;
+ struct usb_interface *intf = ar->intf;
+ struct usb_device *udev = ar->udev;
complete(&ar->fw_load_wait);
+ /* at this point 'ar' could be already freed. Don't use it anymore */
+ ar = NULL;
/* unbind anything failed */
- if (parent)
- device_lock(parent);
-
- device_release_driver(&udev->dev);
- if (parent)
- device_unlock(parent);
+ usb_lock_device(udev);
+ usb_driver_release_interface(&carl9170_driver, intf);
+ usb_unlock_device(udev);
- usb_put_dev(udev);
+ usb_put_intf(intf);
}
static void carl9170_usb_firmware_finish(struct ar9170 *ar)
{
+ struct usb_interface *intf = ar->intf;
int err;
err = carl9170_parse_firmware(ar);
@@ -1009,7 +1007,7 @@ static void carl9170_usb_firmware_finish(struct ar9170 *ar)
goto err_unrx;
complete(&ar->fw_load_wait);
- usb_put_dev(ar->udev);
+ usb_put_intf(intf);
return;
err_unrx:
@@ -1052,7 +1050,6 @@ static int carl9170_usb_probe(struct usb_interface *intf,
return PTR_ERR(ar);
udev = interface_to_usbdev(intf);
- usb_get_dev(udev);
ar->udev = udev;
ar->intf = intf;
ar->features = id->driver_info;
@@ -1094,15 +1091,14 @@ static int carl9170_usb_probe(struct usb_interface *intf,
atomic_set(&ar->rx_anch_urbs, 0);
atomic_set(&ar->rx_pool_urbs, 0);
- usb_get_dev(ar->udev);
+ usb_get_intf(intf);
carl9170_set_state(ar, CARL9170_STOPPED);
err = request_firmware_nowait(THIS_MODULE, 1, CARL9170FW_NAME,
&ar->udev->dev, GFP_KERNEL, ar, carl9170_usb_firmware_step2);
if (err) {
- usb_put_dev(udev);
- usb_put_dev(udev);
+ usb_put_intf(intf);
carl9170_free(ar);
}
return err;
@@ -1131,7 +1127,6 @@ static void carl9170_usb_disconnect(struct usb_interface *intf)
carl9170_release_firmware(ar);
carl9170_free(ar);
- usb_put_dev(udev);
}
#ifdef CONFIG_PM
diff --git a/drivers/net/wireless/ath/dfs_pattern_detector.c b/drivers/net/wireless/ath/dfs_pattern_detector.c
index d52b31b45df7..a274eb0d1968 100644
--- a/drivers/net/wireless/ath/dfs_pattern_detector.c
+++ b/drivers/net/wireless/ath/dfs_pattern_detector.c
@@ -111,7 +111,7 @@ static const struct radar_detector_specs jp_radar_ref_types[] = {
JP_PATTERN(0, 0, 1, 1428, 1428, 1, 18, 29, false),
JP_PATTERN(1, 2, 3, 3846, 3846, 1, 18, 29, false),
JP_PATTERN(2, 0, 1, 1388, 1388, 1, 18, 50, false),
- JP_PATTERN(3, 1, 2, 4000, 4000, 1, 18, 50, false),
+ JP_PATTERN(3, 0, 4, 4000, 4000, 1, 18, 50, false),
JP_PATTERN(4, 0, 5, 150, 230, 1, 23, 50, false),
JP_PATTERN(5, 6, 10, 200, 500, 1, 16, 50, false),
JP_PATTERN(6, 11, 20, 200, 500, 1, 12, 50, false),
diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h
index 75ddaefdd049..8d5a16b558e6 100644
--- a/drivers/net/wireless/ath/regd.h
+++ b/drivers/net/wireless/ath/regd.h
@@ -28,7 +28,6 @@ enum ctl_group {
CTL_ETSI = 0x30,
};
-#define NO_CTL 0xff
#define SD_NO_CTL 0xE0
#define NO_CTL 0xff
#define CTL_11A 0
diff --git a/drivers/net/wireless/ath/wcn36xx/Kconfig b/drivers/net/wireless/ath/wcn36xx/Kconfig
index 4ab2d59ff2ca..a4b153470a2c 100644
--- a/drivers/net/wireless/ath/wcn36xx/Kconfig
+++ b/drivers/net/wireless/ath/wcn36xx/Kconfig
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0-only
+# SPDX-License-Identifier: ISC
config WCN36XX
tristate "Qualcomm Atheros WCN3660/3680 support"
depends on MAC80211 && HAS_DMA
diff --git a/drivers/net/wireless/ath/wcn36xx/Makefile b/drivers/net/wireless/ath/wcn36xx/Makefile
index 582049f65735..27413703ad69 100644
--- a/drivers/net/wireless/ath/wcn36xx/Makefile
+++ b/drivers/net/wireless/ath/wcn36xx/Makefile
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: ISC
obj-$(CONFIG_WCN36XX) := wcn36xx.o
wcn36xx-y += main.o \
dxe.o \
diff --git a/drivers/net/wireless/ath/wil6210/Kconfig b/drivers/net/wireless/ath/wil6210/Kconfig
index b1a339859feb..0d1a8dab30ed 100644
--- a/drivers/net/wireless/ath/wil6210/Kconfig
+++ b/drivers/net/wireless/ath/wil6210/Kconfig
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0-only
+# SPDX-License-Identifier: ISC
config WIL6210
tristate "Wilocity 60g WiFi card wil6210 support"
select WANT_DEV_COREDUMP
diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile
index d3d61ae459e2..53a0d995ddb0 100644
--- a/drivers/net/wireless/ath/wil6210/Makefile
+++ b/drivers/net/wireless/ath/wil6210/Makefile
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: ISC
obj-$(CONFIG_WIL6210) += wil6210.o
wil6210-y := main.o
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 804955d24b30..d436cc51dfd1 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -314,7 +314,8 @@ int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid,
memset(&reply, 0, sizeof(reply));
rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, vif->mid, &cmd, sizeof(cmd),
- WMI_NOTIFY_REQ_DONE_EVENTID, &reply, sizeof(reply), 20);
+ WMI_NOTIFY_REQ_DONE_EVENTID, &reply, sizeof(reply),
+ WIL_WMI_CALL_GENERAL_TO_MS);
if (rc)
return rc;
@@ -380,8 +381,8 @@ static int wil_cfg80211_get_station(struct wiphy *wiphy,
wil_dbg_misc(wil, "get_station: %pM CID %d MID %d\n", mac, cid,
vif->mid);
- if (cid < 0)
- return cid;
+ if (!wil_cid_valid(wil, cid))
+ return -ENOENT;
rc = wil_cid_fill_sinfo(vif, cid, sinfo);
@@ -395,7 +396,7 @@ static int wil_find_cid_by_idx(struct wil6210_priv *wil, u8 mid, int idx)
{
int i;
- for (i = 0; i < max_assoc_sta; i++) {
+ for (i = 0; i < wil->max_assoc_sta; i++) {
if (wil->sta[i].status == wil_sta_unused)
continue;
if (wil->sta[i].mid != mid)
@@ -417,7 +418,7 @@ static int wil_cfg80211_dump_station(struct wiphy *wiphy,
int rc;
int cid = wil_find_cid_by_idx(wil, vif->mid, idx);
- if (cid < 0)
+ if (!wil_cid_valid(wil, cid))
return -ENOENT;
ether_addr_copy(mac, wil->sta[cid].addr);
@@ -643,6 +644,16 @@ out:
return rc;
}
+static bool wil_is_safe_switch(enum nl80211_iftype from,
+ enum nl80211_iftype to)
+{
+ if (from == NL80211_IFTYPE_STATION &&
+ to == NL80211_IFTYPE_P2P_CLIENT)
+ return true;
+
+ return false;
+}
+
static int wil_cfg80211_change_iface(struct wiphy *wiphy,
struct net_device *ndev,
enum nl80211_iftype type,
@@ -668,7 +679,8 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy,
* because it can cause significant disruption
*/
if (!wil_has_other_active_ifaces(wil, ndev, true, false) &&
- netif_running(ndev) && !wil_is_recovery_blocked(wil)) {
+ netif_running(ndev) && !wil_is_recovery_blocked(wil) &&
+ !wil_is_safe_switch(wdev->iftype, type)) {
wil_dbg_misc(wil, "interface is up. resetting...\n");
mutex_lock(&wil->mutex);
__wil_down(wil);
@@ -3022,7 +3034,7 @@ static int wil_rf_sector_set_selected(struct wiphy *wiphy,
wil, vif->mid, WMI_INVALID_RF_SECTOR_INDEX,
sector_type, WIL_CID_ALL);
if (rc == -EINVAL) {
- for (i = 0; i < max_assoc_sta; i++) {
+ for (i = 0; i < wil->max_assoc_sta; i++) {
if (wil->sta[i].mid != vif->mid)
continue;
rc = wil_rf_sector_wmi_set_selected(
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index df2adff6c33a..74834131cf7c 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -63,7 +63,9 @@ static void wil_print_desc_edma(struct seq_file *s, struct wil6210_priv *wil,
&ring->va[idx].rx.enhanced;
u16 buff_id = le16_to_cpu(rx_d->mac.buff_id);
- has_skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb;
+ if (wil->rx_buff_mgmt.buff_arr &&
+ wil_val_in_range(buff_id, 0, wil->rx_buff_mgmt.size))
+ has_skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb;
seq_printf(s, "%c", (has_skb) ? _h : _s);
} else {
struct wil_tx_enhanced_desc *d =
@@ -71,9 +73,9 @@ static void wil_print_desc_edma(struct seq_file *s, struct wil6210_priv *wil,
&ring->va[idx].tx.enhanced;
num_of_descs = (u8)d->mac.d[2];
- has_skb = ring->ctx[idx].skb;
+ has_skb = ring->ctx && ring->ctx[idx].skb;
if (num_of_descs >= 1)
- seq_printf(s, "%c", ring->ctx[idx].skb ? _h : _s);
+ seq_printf(s, "%c", has_skb ? _h : _s);
else
/* num_of_descs == 0, it's a frag in a list of descs */
seq_printf(s, "%c", has_skb ? 'h' : _s);
@@ -84,7 +86,7 @@ static void wil_print_ring(struct seq_file *s, struct wil6210_priv *wil,
const char *name, struct wil_ring *ring,
char _s, char _h)
{
- void __iomem *x = wmi_addr(wil, ring->hwtail);
+ void __iomem *x;
u32 v;
seq_printf(s, "RING %s = {\n", name);
@@ -96,7 +98,21 @@ static void wil_print_ring(struct seq_file *s, struct wil6210_priv *wil,
else
seq_printf(s, " swtail = %d\n", ring->swtail);
seq_printf(s, " swhead = %d\n", ring->swhead);
+ if (wil->use_enhanced_dma_hw) {
+ int ring_id = ring->is_rx ?
+ WIL_RX_DESC_RING_ID : ring - wil->ring_tx;
+ /* SUBQ_CONS is a table of 32 entries, one for each Q pair.
+ * lower 16bits are for even ring_id and upper 16bits are for
+ * odd ring_id
+ */
+ x = wmi_addr(wil, RGF_DMA_SCM_SUBQ_CONS + 4 * (ring_id / 2));
+ v = readl_relaxed(x);
+
+ v = (ring_id % 2 ? (v >> 16) : (v & 0xffff));
+ seq_printf(s, " hwhead = %u\n", v);
+ }
seq_printf(s, " hwtail = [0x%08x] -> ", ring->hwtail);
+ x = wmi_addr(wil, ring->hwtail);
if (x) {
v = readl(x);
seq_printf(s, "0x%08x = %d\n", v, v);
@@ -162,7 +178,7 @@ static int ring_show(struct seq_file *s, void *data)
snprintf(name, sizeof(name), "tx_%2d", i);
- if (cid < max_assoc_sta)
+ if (cid < wil->max_assoc_sta)
seq_printf(s,
"\n%pM CID %d TID %d 1x%s BACK([%u] %u TU A%s) [%3d|%3d] idle %s\n",
wil->sta[cid].addr, cid, tid,
@@ -188,7 +204,7 @@ DEFINE_SHOW_ATTRIBUTE(ring);
static void wil_print_sring(struct seq_file *s, struct wil6210_priv *wil,
struct wil_status_ring *sring)
{
- void __iomem *x = wmi_addr(wil, sring->hwtail);
+ void __iomem *x;
int sring_idx = sring - wil->srings;
u32 v;
@@ -199,7 +215,19 @@ static void wil_print_sring(struct seq_file *s, struct wil6210_priv *wil,
seq_printf(s, " size = %d\n", sring->size);
seq_printf(s, " elem_size = %zu\n", sring->elem_size);
seq_printf(s, " swhead = %d\n", sring->swhead);
+ if (wil->use_enhanced_dma_hw) {
+ /* COMPQ_PROD is a table of 32 entries, one for each Q pair.
+ * lower 16bits are for even ring_id and upper 16bits are for
+ * odd ring_id
+ */
+ x = wmi_addr(wil, RGF_DMA_SCM_COMPQ_PROD + 4 * (sring_idx / 2));
+ v = readl_relaxed(x);
+
+ v = (sring_idx % 2 ? (v >> 16) : (v & 0xffff));
+ seq_printf(s, " hwhead = %u\n", v);
+ }
seq_printf(s, " hwtail = [0x%08x] -> ", sring->hwtail);
+ x = wmi_addr(wil, sring->hwtail);
if (x) {
v = readl_relaxed(x);
seq_printf(s, "0x%08x = %d\n", v, v);
@@ -394,25 +422,18 @@ static int wil_debugfs_iomem_x32_get(void *data, u64 *val)
DEFINE_DEBUGFS_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get,
wil_debugfs_iomem_x32_set, "0x%08llx\n");
-static struct dentry *wil_debugfs_create_iomem_x32(const char *name,
- umode_t mode,
- struct dentry *parent,
- void *value,
- struct wil6210_priv *wil)
+static void wil_debugfs_create_iomem_x32(const char *name, umode_t mode,
+ struct dentry *parent, void *value,
+ struct wil6210_priv *wil)
{
- struct dentry *file;
struct wil_debugfs_iomem_data *data = &wil->dbg_data.data_arr[
wil->dbg_data.iomem_data_count];
data->wil = wil;
data->offset = value;
- file = debugfs_create_file_unsafe(name, mode, parent, data,
- &fops_iomem_x32);
- if (!IS_ERR_OR_NULL(file))
- wil->dbg_data.iomem_data_count++;
-
- return file;
+ debugfs_create_file_unsafe(name, mode, parent, data, &fops_iomem_x32);
+ wil->dbg_data.iomem_data_count++;
}
static int wil_debugfs_ulong_set(void *data, u64 val)
@@ -430,14 +451,6 @@ static int wil_debugfs_ulong_get(void *data, u64 *val)
DEFINE_DEBUGFS_ATTRIBUTE(wil_fops_ulong, wil_debugfs_ulong_get,
wil_debugfs_ulong_set, "0x%llx\n");
-static struct dentry *wil_debugfs_create_ulong(const char *name, umode_t mode,
- struct dentry *parent,
- ulong *value)
-{
- return debugfs_create_file_unsafe(name, mode, parent, value,
- &wil_fops_ulong);
-}
-
/**
* wil6210_debugfs_init_offset - create set of debugfs files
* @wil - driver's context, used for printing
@@ -454,37 +467,30 @@ static void wil6210_debugfs_init_offset(struct wil6210_priv *wil,
int i;
for (i = 0; tbl[i].name; i++) {
- struct dentry *f;
-
switch (tbl[i].type) {
case doff_u32:
- f = debugfs_create_u32(tbl[i].name, tbl[i].mode, dbg,
- base + tbl[i].off);
+ debugfs_create_u32(tbl[i].name, tbl[i].mode, dbg,
+ base + tbl[i].off);
break;
case doff_x32:
- f = debugfs_create_x32(tbl[i].name, tbl[i].mode, dbg,
- base + tbl[i].off);
+ debugfs_create_x32(tbl[i].name, tbl[i].mode, dbg,
+ base + tbl[i].off);
break;
case doff_ulong:
- f = wil_debugfs_create_ulong(tbl[i].name, tbl[i].mode,
- dbg, base + tbl[i].off);
+ debugfs_create_file_unsafe(tbl[i].name, tbl[i].mode,
+ dbg, base + tbl[i].off,
+ &wil_fops_ulong);
break;
case doff_io32:
- f = wil_debugfs_create_iomem_x32(tbl[i].name,
- tbl[i].mode, dbg,
- base + tbl[i].off,
- wil);
+ wil_debugfs_create_iomem_x32(tbl[i].name, tbl[i].mode,
+ dbg, base + tbl[i].off,
+ wil);
break;
case doff_u8:
- f = debugfs_create_u8(tbl[i].name, tbl[i].mode, dbg,
- base + tbl[i].off);
+ debugfs_create_u8(tbl[i].name, tbl[i].mode, dbg,
+ base + tbl[i].off);
break;
- default:
- f = ERR_PTR(-EINVAL);
}
- if (IS_ERR_OR_NULL(f))
- wil_err(wil, "Create file \"%s\": err %ld\n",
- tbl[i].name, PTR_ERR(f));
}
}
@@ -499,19 +505,14 @@ static const struct dbg_off isr_off[] = {
{},
};
-static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil,
- const char *name,
- struct dentry *parent, u32 off)
+static void wil6210_debugfs_create_ISR(struct wil6210_priv *wil,
+ const char *name, struct dentry *parent,
+ u32 off)
{
struct dentry *d = debugfs_create_dir(name, parent);
- if (IS_ERR_OR_NULL(d))
- return -ENODEV;
-
wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr + off,
isr_off);
-
- return 0;
}
static const struct dbg_off pseudo_isr_off[] = {
@@ -521,18 +522,13 @@ static const struct dbg_off pseudo_isr_off[] = {
{},
};
-static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil,
- struct dentry *parent)
+static void wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil,
+ struct dentry *parent)
{
struct dentry *d = debugfs_create_dir("PSEUDO_ISR", parent);
- if (IS_ERR_OR_NULL(d))
- return -ENODEV;
-
wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr,
pseudo_isr_off);
-
- return 0;
}
static const struct dbg_off lgc_itr_cnt_off[] = {
@@ -580,13 +576,9 @@ static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil,
struct dentry *d, *dtx, *drx;
d = debugfs_create_dir("ITR_CNT", parent);
- if (IS_ERR_OR_NULL(d))
- return -ENODEV;
dtx = debugfs_create_dir("TX", d);
drx = debugfs_create_dir("RX", d);
- if (IS_ERR_OR_NULL(dtx) || IS_ERR_OR_NULL(drx))
- return -ENODEV;
wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr,
lgc_itr_cnt_off);
@@ -749,6 +741,44 @@ static const struct file_operations fops_rxon = {
.open = simple_open,
};
+static ssize_t wil_write_file_rbufcap(struct file *file,
+ const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct wil6210_priv *wil = file->private_data;
+ int val;
+ int rc;
+
+ rc = kstrtoint_from_user(buf, count, 0, &val);
+ if (rc) {
+ wil_err(wil, "Invalid argument\n");
+ return rc;
+ }
+ /* input value: negative to disable, 0 to use system default,
+ * 1..ring size to set descriptor threshold
+ */
+ wil_info(wil, "%s RBUFCAP, descriptors threshold - %d\n",
+ val < 0 ? "Disabling" : "Enabling", val);
+
+ if (!wil->ring_rx.va || val > wil->ring_rx.size) {
+ wil_err(wil, "Invalid descriptors threshold, %d\n", val);
+ return -EINVAL;
+ }
+
+ rc = wmi_rbufcap_cfg(wil, val < 0 ? 0 : 1, val < 0 ? 0 : val);
+ if (rc) {
+ wil_err(wil, "RBUFCAP config failed: %d\n", rc);
+ return rc;
+ }
+
+ return count;
+}
+
+static const struct file_operations fops_rbufcap = {
+ .write = wil_write_file_rbufcap,
+ .open = simple_open,
+};
+
/* block ack control, write:
* - "add <ringid> <agg_size> <timeout>" to trigger ADDBA
* - "del_tx <ringid> <reason>" to trigger DELBA for Tx side
@@ -811,7 +841,7 @@ static ssize_t wil_write_back(struct file *file, const char __user *buf,
"BACK: del_rx require at least 2 params\n");
return -EINVAL;
}
- if (p1 < 0 || p1 >= max_assoc_sta) {
+ if (p1 < 0 || p1 >= wil->max_assoc_sta) {
wil_err(wil, "BACK: invalid CID %d\n", p1);
return -EINVAL;
}
@@ -910,9 +940,8 @@ static ssize_t wil_read_pmccfg(struct file *file, char __user *user_buf,
" - \"alloc <num descriptors> <descriptor_size>\" to allocate pmc\n"
" - \"free\" to free memory allocated for pmc\n";
- sprintf(text, "Last command status: %d\n\n%s",
- wil_pmc_last_cmd_status(wil),
- help);
+ snprintf(text, sizeof(text), "Last command status: %d\n\n%s",
+ wil_pmc_last_cmd_status(wil), help);
return simple_read_from_buffer(user_buf, count, ppos, text,
strlen(text) + 1);
@@ -1091,19 +1120,18 @@ static int txdesc_show(struct seq_file *s, void *data)
if (wil->use_enhanced_dma_hw) {
if (tx) {
- skb = ring->ctx[txdesc_idx].skb;
- } else {
+ skb = ring->ctx ? ring->ctx[txdesc_idx].skb : NULL;
+ } else if (wil->rx_buff_mgmt.buff_arr) {
struct wil_rx_enhanced_desc *rx_d =
(struct wil_rx_enhanced_desc *)
&ring->va[txdesc_idx].rx.enhanced;
u16 buff_id = le16_to_cpu(rx_d->mac.buff_id);
if (!wil_val_in_range(buff_id, 0,
- wil->rx_buff_mgmt.size)) {
+ wil->rx_buff_mgmt.size))
seq_printf(s, "invalid buff_id %d\n", buff_id);
- return 0;
- }
- skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb;
+ else
+ skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb;
}
} else {
skb = ring->ctx[txdesc_idx].skb;
@@ -1136,7 +1164,7 @@ static int status_msg_show(struct seq_file *s, void *data)
struct wil6210_priv *wil = s->private;
int sring_idx = dbg_sring_index;
struct wil_status_ring *sring;
- bool tx = sring_idx == wil->tx_sring_idx ? 1 : 0;
+ bool tx;
u32 status_msg_idx = dbg_status_msg_index;
u32 *u;
@@ -1146,6 +1174,7 @@ static int status_msg_show(struct seq_file *s, void *data)
}
sring = &wil->srings[sring_idx];
+ tx = !sring->is_rx;
if (!sring->va) {
seq_printf(s, "No %cX status ring\n", tx ? 'T' : 'R');
@@ -1262,14 +1291,14 @@ static int bf_show(struct seq_file *s, void *data)
memset(&reply, 0, sizeof(reply));
- for (i = 0; i < max_assoc_sta; i++) {
+ for (i = 0; i < wil->max_assoc_sta; i++) {
u32 status;
cmd.cid = i;
rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, vif->mid,
&cmd, sizeof(cmd),
WMI_NOTIFY_REQ_DONE_EVENTID, &reply,
- sizeof(reply), 20);
+ sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS);
/* if reply is all-0, ignore this CID */
if (rc || is_all_zeros(&reply.evt, sizeof(reply.evt)))
continue;
@@ -1307,7 +1336,7 @@ static void print_temp(struct seq_file *s, const char *prefix, s32 t)
{
switch (t) {
case 0:
- case ~(u32)0:
+ case WMI_INVALID_TEMPERATURE:
seq_printf(s, "%s N/A\n", prefix);
break;
default:
@@ -1320,17 +1349,41 @@ static void print_temp(struct seq_file *s, const char *prefix, s32 t)
static int temp_show(struct seq_file *s, void *data)
{
struct wil6210_priv *wil = s->private;
- s32 t_m, t_r;
- int rc = wmi_get_temperature(wil, &t_m, &t_r);
+ int rc, i;
- if (rc) {
- seq_puts(s, "Failed\n");
- return 0;
- }
+ if (test_bit(WMI_FW_CAPABILITY_TEMPERATURE_ALL_RF,
+ wil->fw_capabilities)) {
+ struct wmi_temp_sense_all_done_event sense_all_evt;
- print_temp(s, "T_mac =", t_m);
- print_temp(s, "T_radio =", t_r);
+ wil_dbg_misc(wil,
+ "WMI_FW_CAPABILITY_TEMPERATURE_ALL_RF is supported");
+ rc = wmi_get_all_temperatures(wil, &sense_all_evt);
+ if (rc) {
+ seq_puts(s, "Failed\n");
+ return 0;
+ }
+ print_temp(s, "T_mac =",
+ le32_to_cpu(sense_all_evt.baseband_t1000));
+ seq_printf(s, "Connected RFs [0x%08x]\n",
+ sense_all_evt.rf_bitmap);
+ for (i = 0; i < WMI_MAX_XIF_PORTS_NUM; i++) {
+ seq_printf(s, "RF[%d] = ", i);
+ print_temp(s, "",
+ le32_to_cpu(sense_all_evt.rf_t1000[i]));
+ }
+ } else {
+ s32 t_m, t_r;
+ wil_dbg_misc(wil,
+ "WMI_FW_CAPABILITY_TEMPERATURE_ALL_RF is not supported");
+ rc = wmi_get_temperature(wil, &t_m, &t_r);
+ if (rc) {
+ seq_puts(s, "Failed\n");
+ return 0;
+ }
+ print_temp(s, "T_mac =", t_m);
+ print_temp(s, "T_radio =", t_r);
+ }
return 0;
}
DEFINE_SHOW_ATTRIBUTE(temp);
@@ -1359,7 +1412,7 @@ static int link_show(struct seq_file *s, void *data)
if (!sinfo)
return -ENOMEM;
- for (i = 0; i < max_assoc_sta; i++) {
+ for (i = 0; i < wil->max_assoc_sta; i++) {
struct wil_sta_info *p = &wil->sta[i];
char *status = "unknown";
struct wil6210_vif *vif;
@@ -1561,7 +1614,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
struct wil6210_priv *wil = s->private;
int i, tid, mcs;
- for (i = 0; i < max_assoc_sta; i++) {
+ for (i = 0; i < wil->max_assoc_sta; i++) {
struct wil_sta_info *p = &wil->sta[i];
char *status = "unknown";
u8 aid = 0;
@@ -1670,7 +1723,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
struct wil6210_priv *wil = s->private;
int i, bin;
- for (i = 0; i < max_assoc_sta; i++) {
+ for (i = 0; i < wil->max_assoc_sta; i++) {
struct wil_sta_info *p = &wil->sta[i];
char *status = "unknown";
u8 aid = 0;
@@ -1759,7 +1812,7 @@ static ssize_t wil_tx_latency_write(struct file *file, const char __user *buf,
size_t sz = sizeof(u64) * WIL_NUM_LATENCY_BINS;
wil->tx_latency_res = val;
- for (i = 0; i < max_assoc_sta; i++) {
+ for (i = 0; i < wil->max_assoc_sta; i++) {
struct wil_sta_info *sta = &wil->sta[i];
kfree(sta->tx_latency_bins);
@@ -1844,7 +1897,7 @@ static void wil_link_stats_debugfs_show_vif(struct wil6210_vif *vif,
}
seq_printf(s, "TSF %lld\n", vif->fw_stats_tsf);
- for (i = 0; i < max_assoc_sta; i++) {
+ for (i = 0; i < wil->max_assoc_sta; i++) {
if (wil->sta[i].status == wil_sta_unused)
continue;
if (wil->sta[i].mid != vif->mid)
@@ -2336,6 +2389,7 @@ static const struct {
{"tx_latency", 0644, &fops_tx_latency},
{"link_stats", 0644, &fops_link_stats},
{"link_stats_global", 0644, &fops_link_stats_global},
+ {"rbufcap", 0244, &fops_rbufcap},
};
static void wil6210_debugfs_init_files(struct wil6210_priv *wil,
@@ -2460,7 +2514,7 @@ void wil6210_debugfs_remove(struct wil6210_priv *wil)
wil->debug = NULL;
kfree(wil->dbg_data.data_arr);
- for (i = 0; i < max_assoc_sta; i++)
+ for (i = 0; i < wil->max_assoc_sta; i++)
kfree(wil->sta[i].tx_latency_bins);
/* free pmc memory without sending command to fw, as it will
diff --git a/drivers/net/wireless/ath/wil6210/fw.h b/drivers/net/wireless/ath/wil6210/fw.h
index 3e7a28045cab..fa3164765b20 100644
--- a/drivers/net/wireless/ath/wil6210/fw.h
+++ b/drivers/net/wireless/ath/wil6210/fw.h
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2014,2016 Qualcomm Atheros, Inc.
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -109,12 +109,17 @@ struct wil_fw_record_concurrency { /* type == wil_fw_type_comment */
/* brd file info encoded inside a comment record */
#define WIL_BRD_FILE_MAGIC (0xabcddcbb)
+
+struct brd_info {
+ __le32 base_addr;
+ __le32 max_size_bytes;
+} __packed;
+
struct wil_fw_record_brd_file { /* type == wil_fw_type_comment */
/* identifies brd file record */
struct wil_fw_record_comment_hdr hdr;
__le32 version;
- __le32 base_addr;
- __le32 max_size_bytes;
+ struct brd_info brd_info[0];
} __packed;
/* perform action
diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c
index 3ec0f2fab9b7..94ebfa338e3f 100644
--- a/drivers/net/wireless/ath/wil6210/fw_inc.c
+++ b/drivers/net/wireless/ath/wil6210/fw_inc.c
@@ -156,17 +156,52 @@ fw_handle_brd_file(struct wil6210_priv *wil, const void *data,
size_t size)
{
const struct wil_fw_record_brd_file *rec = data;
+ u32 max_num_ent, i, ent_size;
- if (size < sizeof(*rec)) {
- wil_err_fw(wil, "brd_file record too short: %zu\n", size);
- return 0;
+ if (size <= offsetof(struct wil_fw_record_brd_file, brd_info)) {
+ wil_err(wil, "board record too short, size %zu\n", size);
+ return -EINVAL;
+ }
+
+ ent_size = size - offsetof(struct wil_fw_record_brd_file, brd_info);
+ max_num_ent = ent_size / sizeof(struct brd_info);
+
+ if (!max_num_ent) {
+ wil_err(wil, "brd info entries are missing\n");
+ return -EINVAL;
}
- wil->brd_file_addr = le32_to_cpu(rec->base_addr);
- wil->brd_file_max_size = le32_to_cpu(rec->max_size_bytes);
+ wil->brd_info = kcalloc(max_num_ent, sizeof(struct wil_brd_info),
+ GFP_KERNEL);
+ if (!wil->brd_info)
+ return -ENOMEM;
- wil_dbg_fw(wil, "brd_file_addr 0x%x, brd_file_max_size %d\n",
- wil->brd_file_addr, wil->brd_file_max_size);
+ for (i = 0; i < max_num_ent; i++) {
+ wil->brd_info[i].file_addr =
+ le32_to_cpu(rec->brd_info[i].base_addr);
+ wil->brd_info[i].file_max_size =
+ le32_to_cpu(rec->brd_info[i].max_size_bytes);
+
+ if (!wil->brd_info[i].file_addr)
+ break;
+
+ wil_dbg_fw(wil,
+ "brd info %d: file_addr 0x%x, file_max_size %d\n",
+ i, wil->brd_info[i].file_addr,
+ wil->brd_info[i].file_max_size);
+ }
+
+ wil->num_of_brd_entries = i;
+ if (wil->num_of_brd_entries == 0) {
+ kfree(wil->brd_info);
+ wil->brd_info = NULL;
+ wil_dbg_fw(wil,
+ "no valid brd info entries, using brd file addr\n");
+
+ } else {
+ wil_dbg_fw(wil, "num of brd info entries %d\n",
+ wil->num_of_brd_entries);
+ }
return 0;
}
@@ -634,6 +669,11 @@ int wil_request_firmware(struct wil6210_priv *wil, const char *name,
}
wil_dbg_fw(wil, "Loading <%s>, %zu bytes\n", name, fw->size);
+ /* re-initialize board info params */
+ wil->num_of_brd_entries = 0;
+ kfree(wil->brd_info);
+ wil->brd_info = NULL;
+
for (sz = fw->size, d = fw->data; sz; sz -= rc1, d += rc1) {
rc1 = wil_fw_verify(wil, d, sz);
if (rc1 < 0) {
@@ -662,11 +702,13 @@ static int wil_brd_process(struct wil6210_priv *wil, const void *data,
{
int rc = 0;
const struct wil_fw_record_head *hdr = data;
- size_t s, hdr_sz;
+ size_t s, hdr_sz = 0;
u16 type;
+ int i = 0;
- /* Assuming the board file includes only one header record and one data
- * record. Each record starts with wil_fw_record_head.
+ /* Assuming the board file includes only one file header
+ * and one or several data records.
+ * Each record starts with wil_fw_record_head.
*/
if (size < sizeof(*hdr))
return -EINVAL;
@@ -674,40 +716,67 @@ static int wil_brd_process(struct wil6210_priv *wil, const void *data,
if (s > size)
return -EINVAL;
- /* Skip the header record and handle the data record */
- hdr = (const void *)hdr + s;
+ /* Skip the header record and handle the data records */
size -= s;
- if (size < sizeof(*hdr))
- return -EINVAL;
- hdr_sz = le32_to_cpu(hdr->size);
- if (wil->brd_file_max_size && hdr_sz > wil->brd_file_max_size)
- return -EINVAL;
- if (sizeof(*hdr) + hdr_sz > size)
- return -EINVAL;
- if (hdr_sz % 4) {
- wil_err_fw(wil, "unaligned record size: %zu\n",
- hdr_sz);
- return -EINVAL;
- }
- type = le16_to_cpu(hdr->type);
- if (type != wil_fw_type_data) {
- wil_err_fw(wil, "invalid record type for board file: %d\n",
- type);
- return -EINVAL;
+ for (hdr = data + s;; hdr = (const void *)hdr + s, size -= s, i++) {
+ if (size < sizeof(*hdr))
+ break;
+
+ if (i >= wil->num_of_brd_entries) {
+ wil_err_fw(wil,
+ "Too many brd records: %d, num of expected entries %d\n",
+ i, wil->num_of_brd_entries);
+ break;
+ }
+
+ hdr_sz = le32_to_cpu(hdr->size);
+ s = sizeof(*hdr) + hdr_sz;
+ if (wil->brd_info[i].file_max_size &&
+ hdr_sz > wil->brd_info[i].file_max_size)
+ return -EINVAL;
+ if (sizeof(*hdr) + hdr_sz > size)
+ return -EINVAL;
+ if (hdr_sz % 4) {
+ wil_err_fw(wil, "unaligned record size: %zu\n",
+ hdr_sz);
+ return -EINVAL;
+ }
+ type = le16_to_cpu(hdr->type);
+ if (type != wil_fw_type_data) {
+ wil_err_fw(wil,
+ "invalid record type for board file: %d\n",
+ type);
+ return -EINVAL;
+ }
+ if (hdr_sz < sizeof(struct wil_fw_record_data)) {
+ wil_err_fw(wil, "data record too short: %zu\n", hdr_sz);
+ return -EINVAL;
+ }
+
+ wil_dbg_fw(wil,
+ "using info from fw file for record %d: addr[0x%08x], max size %d\n",
+ i, wil->brd_info[i].file_addr,
+ wil->brd_info[i].file_max_size);
+
+ rc = __fw_handle_data(wil, &hdr[1], hdr_sz,
+ cpu_to_le32(wil->brd_info[i].file_addr));
+ if (rc)
+ return rc;
}
- if (hdr_sz < sizeof(struct wil_fw_record_data)) {
- wil_err_fw(wil, "data record too short: %zu\n", hdr_sz);
+
+ if (size) {
+ wil_err_fw(wil, "unprocessed bytes: %zu\n", size);
+ if (size >= sizeof(*hdr)) {
+ wil_err_fw(wil,
+ "Stop at offset %ld record type %d [%zd bytes]\n",
+ (long)((const void *)hdr - data),
+ le16_to_cpu(hdr->type), hdr_sz);
+ }
return -EINVAL;
}
- wil_dbg_fw(wil, "using addr from fw file: [0x%08x]\n",
- wil->brd_file_addr);
-
- rc = __fw_handle_data(wil, &hdr[1], hdr_sz,
- cpu_to_le32(wil->brd_file_addr));
-
- return rc;
+ return 0;
}
/**
@@ -738,7 +807,8 @@ int wil_request_board(struct wil6210_priv *wil, const char *name)
rc = dlen;
goto out;
}
- /* Process the data record */
+
+ /* Process the data records */
rc = wil_brd_process(wil, brd->data, dlen);
out:
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
index 3f5bd177d55f..b00a13d6d530 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -296,21 +296,24 @@ void wil_configure_interrupt_moderation(struct wil6210_priv *wil)
static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
{
struct wil6210_priv *wil = cookie;
- u32 isr = wil_ioread32_and_clear(wil->csr +
- HOSTADDR(RGF_DMA_EP_RX_ICR) +
- offsetof(struct RGF_ICR, ICR));
+ u32 isr;
bool need_unmask = true;
+ wil6210_mask_irq_rx(wil);
+
+ isr = wil_ioread32_and_clear(wil->csr +
+ HOSTADDR(RGF_DMA_EP_RX_ICR) +
+ offsetof(struct RGF_ICR, ICR));
+
trace_wil6210_irq_rx(isr);
wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr);
if (unlikely(!isr)) {
wil_err_ratelimited(wil, "spurious IRQ: RX\n");
+ wil6210_unmask_irq_rx(wil);
return IRQ_NONE;
}
- wil6210_mask_irq_rx(wil);
-
/* RX_DONE and RX_HTRSH interrupts are the same if interrupt
* moderation is not used. Interrupt moderation may cause RX
* buffer overflow while RX_DONE is delayed. The required
@@ -355,21 +358,24 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
static irqreturn_t wil6210_irq_rx_edma(int irq, void *cookie)
{
struct wil6210_priv *wil = cookie;
- u32 isr = wil_ioread32_and_clear(wil->csr +
- HOSTADDR(RGF_INT_GEN_RX_ICR) +
- offsetof(struct RGF_ICR, ICR));
+ u32 isr;
bool need_unmask = true;
+ wil6210_mask_irq_rx_edma(wil);
+
+ isr = wil_ioread32_and_clear(wil->csr +
+ HOSTADDR(RGF_INT_GEN_RX_ICR) +
+ offsetof(struct RGF_ICR, ICR));
+
trace_wil6210_irq_rx(isr);
wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr);
if (unlikely(!isr)) {
wil_err(wil, "spurious IRQ: RX\n");
+ wil6210_unmask_irq_rx_edma(wil);
return IRQ_NONE;
}
- wil6210_mask_irq_rx_edma(wil);
-
if (likely(isr & BIT_RX_STATUS_IRQ)) {
wil_dbg_irq(wil, "RX status ring\n");
isr &= ~BIT_RX_STATUS_IRQ;
@@ -403,21 +409,24 @@ static irqreturn_t wil6210_irq_rx_edma(int irq, void *cookie)
static irqreturn_t wil6210_irq_tx_edma(int irq, void *cookie)
{
struct wil6210_priv *wil = cookie;
- u32 isr = wil_ioread32_and_clear(wil->csr +
- HOSTADDR(RGF_INT_GEN_TX_ICR) +
- offsetof(struct RGF_ICR, ICR));
+ u32 isr;
bool need_unmask = true;
+ wil6210_mask_irq_tx_edma(wil);
+
+ isr = wil_ioread32_and_clear(wil->csr +
+ HOSTADDR(RGF_INT_GEN_TX_ICR) +
+ offsetof(struct RGF_ICR, ICR));
+
trace_wil6210_irq_tx(isr);
wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr);
if (unlikely(!isr)) {
wil_err(wil, "spurious IRQ: TX\n");
+ wil6210_unmask_irq_tx_edma(wil);
return IRQ_NONE;
}
- wil6210_mask_irq_tx_edma(wil);
-
if (likely(isr & BIT_TX_STATUS_IRQ)) {
wil_dbg_irq(wil, "TX status ring\n");
isr &= ~BIT_TX_STATUS_IRQ;
@@ -446,21 +455,24 @@ static irqreturn_t wil6210_irq_tx_edma(int irq, void *cookie)
static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
{
struct wil6210_priv *wil = cookie;
- u32 isr = wil_ioread32_and_clear(wil->csr +
- HOSTADDR(RGF_DMA_EP_TX_ICR) +
- offsetof(struct RGF_ICR, ICR));
+ u32 isr;
bool need_unmask = true;
+ wil6210_mask_irq_tx(wil);
+
+ isr = wil_ioread32_and_clear(wil->csr +
+ HOSTADDR(RGF_DMA_EP_TX_ICR) +
+ offsetof(struct RGF_ICR, ICR));
+
trace_wil6210_irq_tx(isr);
wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr);
if (unlikely(!isr)) {
wil_err_ratelimited(wil, "spurious IRQ: TX\n");
+ wil6210_unmask_irq_tx(wil);
return IRQ_NONE;
}
- wil6210_mask_irq_tx(wil);
-
if (likely(isr & BIT_DMA_EP_TX_ICR_TX_DONE)) {
wil_dbg_irq(wil, "TX done\n");
isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE;
@@ -532,20 +544,23 @@ static bool wil_validate_mbox_regs(struct wil6210_priv *wil)
static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
{
struct wil6210_priv *wil = cookie;
- u32 isr = wil_ioread32_and_clear(wil->csr +
- HOSTADDR(RGF_DMA_EP_MISC_ICR) +
- offsetof(struct RGF_ICR, ICR));
+ u32 isr;
+
+ wil6210_mask_irq_misc(wil, false);
+
+ isr = wil_ioread32_and_clear(wil->csr +
+ HOSTADDR(RGF_DMA_EP_MISC_ICR) +
+ offsetof(struct RGF_ICR, ICR));
trace_wil6210_irq_misc(isr);
wil_dbg_irq(wil, "ISR MISC 0x%08x\n", isr);
if (!isr) {
wil_err(wil, "spurious IRQ: MISC\n");
+ wil6210_unmask_irq_misc(wil, false);
return IRQ_NONE;
}
- wil6210_mask_irq_misc(wil, false);
-
if (isr & ISR_MISC_FW_ERROR) {
u32 fw_assert_code = wil_r(wil, wil->rgf_fw_assert_code_addr);
u32 ucode_assert_code =
@@ -580,7 +595,7 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
/* no need to handle HALP ICRs until next vote */
wil->halp.handle_icr = false;
wil_dbg_irq(wil, "irq_misc: HALP IRQ invoked\n");
- wil6210_mask_halp(wil);
+ wil6210_mask_irq_misc(wil, true);
complete(&wil->halp.comp);
}
}
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 9b9c9ec01536..173561fe593d 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -241,7 +241,7 @@ static bool wil_vif_is_connected(struct wil6210_priv *wil, u8 mid)
{
int i;
- for (i = 0; i < max_assoc_sta; i++) {
+ for (i = 0; i < wil->max_assoc_sta; i++) {
if (wil->sta[i].mid == mid &&
wil->sta[i].status == wil_sta_connected)
return true;
@@ -340,11 +340,11 @@ static void _wil6210_disconnect_complete(struct wil6210_vif *vif,
wil_dbg_misc(wil,
"Disconnect complete %pM, CID=%d, reason=%d\n",
bssid, cid, reason_code);
- if (cid >= 0) /* disconnect 1 peer */
+ if (wil_cid_valid(wil, cid)) /* disconnect 1 peer */
wil_disconnect_cid_complete(vif, cid, reason_code);
} else { /* all */
wil_dbg_misc(wil, "Disconnect complete all\n");
- for (cid = 0; cid < max_assoc_sta; cid++)
+ for (cid = 0; cid < wil->max_assoc_sta; cid++)
wil_disconnect_cid_complete(vif, cid, reason_code);
}
@@ -452,11 +452,11 @@ static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid,
cid = wil_find_cid(wil, vif->mid, bssid);
wil_dbg_misc(wil, "Disconnect %pM, CID=%d, reason=%d\n",
bssid, cid, reason_code);
- if (cid >= 0) /* disconnect 1 peer */
+ if (wil_cid_valid(wil, cid)) /* disconnect 1 peer */
wil_disconnect_cid(vif, cid, reason_code);
} else { /* all */
wil_dbg_misc(wil, "Disconnect all\n");
- for (cid = 0; cid < max_assoc_sta; cid++)
+ for (cid = 0; cid < wil->max_assoc_sta; cid++)
wil_disconnect_cid(vif, cid, reason_code);
}
@@ -753,6 +753,7 @@ int wil_priv_init(struct wil6210_priv *wil)
wil->reply_mid = U8_MAX;
wil->max_vifs = 1;
+ wil->max_assoc_sta = max_assoc_sta;
/* edma configuration can be updated via debugfs before allocation */
wil->num_rx_status_rings = WIL_DEFAULT_NUM_RX_STATUS_RINGS;
@@ -838,6 +839,7 @@ void wil_priv_deinit(struct wil6210_priv *wil)
wmi_event_flush(wil);
destroy_workqueue(wil->wq_service);
destroy_workqueue(wil->wmi_wq);
+ kfree(wil->brd_info);
}
static void wil_shutdown_bl(struct wil6210_priv *wil)
@@ -1520,6 +1522,7 @@ int wil_ps_update(struct wil6210_priv *wil, enum wmi_ps_profile_type ps_profile)
static void wil_pre_fw_config(struct wil6210_priv *wil)
{
+ wil_clear_fw_log_addr(wil);
/* Mark FW as loaded from host */
wil_s(wil, RGF_USER_USAGE_6, 1);
@@ -1577,6 +1580,20 @@ static int wil_restore_vifs(struct wil6210_priv *wil)
}
/*
+ * Clear FW and ucode log start addr to indicate FW log is not ready. The host
+ * driver clears the addresses before FW starts and FW initializes the address
+ * when it is ready to send logs.
+ */
+void wil_clear_fw_log_addr(struct wil6210_priv *wil)
+{
+ /* FW log addr */
+ wil_w(wil, RGF_USER_USAGE_1, 0);
+ /* ucode log addr */
+ wil_w(wil, RGF_USER_USAGE_2, 0);
+ wil_dbg_misc(wil, "Cleared FW and ucode log address");
+}
+
+/*
* We reset all the structures, and we reset the UMAC.
* After calling this routine, you're expected to reload
* the firmware.
@@ -1709,7 +1726,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
rc = wil_request_firmware(wil, wil->wil_fw_name, true);
if (rc)
goto out;
- if (wil->brd_file_addr)
+ if (wil->num_of_brd_entries)
rc = wil_request_board(wil, board_file);
else
rc = wil_request_firmware(wil, board_file, true);
@@ -1921,7 +1938,7 @@ int wil_find_cid(struct wil6210_priv *wil, u8 mid, const u8 *mac)
int i;
int rc = -ENOENT;
- for (i = 0; i < max_assoc_sta; i++) {
+ for (i = 0; i < wil->max_assoc_sta; i++) {
if (wil->sta[i].mid == mid &&
wil->sta[i].status != wil_sta_unused &&
ether_addr_equal(wil->sta[i].addr, mac)) {
@@ -1938,6 +1955,9 @@ void wil_halp_vote(struct wil6210_priv *wil)
unsigned long rc;
unsigned long to_jiffies = msecs_to_jiffies(WAIT_FOR_HALP_VOTE_MS);
+ if (wil->hw_version >= HW_VER_TALYN_MB)
+ return;
+
mutex_lock(&wil->halp.lock);
wil_dbg_irq(wil, "halp_vote: start, HALP ref_cnt (%d)\n",
@@ -1969,6 +1989,9 @@ void wil_halp_vote(struct wil6210_priv *wil)
void wil_halp_unvote(struct wil6210_priv *wil)
{
+ if (wil->hw_version >= HW_VER_TALYN_MB)
+ return;
+
WARN_ON(wil->halp.ref_cnt == 0);
mutex_lock(&wil->halp.lock);
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index 3b82d6cfc218..9f5a914abc18 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -142,6 +142,8 @@ int wil_set_capabilities(struct wil6210_priv *wil)
min(sizeof(wil->platform_capa), sizeof(platform_capa)));
}
+ wil_info(wil, "platform_capa 0x%lx\n", *wil->platform_capa);
+
/* extract FW capabilities from file without loading the FW */
wil_request_firmware(wil, wil->wil_fw_name, false);
wil_refresh_fw_capabilities(wil);
@@ -418,6 +420,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
/* rollback to bus_disable */
+ wil_clear_fw_log_addr(wil);
rc = wil_if_add(wil);
if (rc) {
wil_err(wil, "wil_if_add failed: %d\n", rc);
diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c
index 32b14fc33a59..784239bcb3a6 100644
--- a/drivers/net/wireless/ath/wil6210/rx_reorder.c
+++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c
@@ -316,7 +316,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
u16 agg_timeout = le16_to_cpu(ba_timeout);
u16 seq_ctrl = le16_to_cpu(ba_seq_ctrl);
struct wil_sta_info *sta;
- u16 agg_wsize = 0;
+ u16 agg_wsize;
/* bit 0: A-MSDU supported
* bit 1: policy (should be 0 for us)
* bits 2..5: TID
@@ -328,7 +328,6 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
test_bit(WMI_FW_CAPABILITY_AMSDU, wil->fw_capabilities) &&
wil->amsdu_en && (param_set & BIT(0));
int ba_policy = param_set & BIT(1);
- u16 status = WLAN_STATUS_SUCCESS;
u16 ssn = seq_ctrl >> 4;
struct wil_tid_ampdu_rx *r;
int rc = 0;
@@ -336,7 +335,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
might_sleep();
/* sanity checks */
- if (cid >= max_assoc_sta) {
+ if (cid >= wil->max_assoc_sta) {
wil_err(wil, "BACK: invalid CID %d\n", cid);
rc = -EINVAL;
goto out;
@@ -355,27 +354,19 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
agg_amsdu ? "+" : "-", !!ba_policy, dialog_token, ssn);
/* apply policies */
- if (ba_policy) {
- wil_err(wil, "BACK requested unsupported ba_policy == 1\n");
- status = WLAN_STATUS_INVALID_QOS_PARAM;
- }
- if (status == WLAN_STATUS_SUCCESS) {
- if (req_agg_wsize == 0) {
- wil_dbg_misc(wil, "Suggest BACK wsize %d\n",
- wil->max_agg_wsize);
- agg_wsize = wil->max_agg_wsize;
- } else {
- agg_wsize = min_t(u16,
- wil->max_agg_wsize, req_agg_wsize);
- }
+ if (req_agg_wsize == 0) {
+ wil_dbg_misc(wil, "Suggest BACK wsize %d\n",
+ wil->max_agg_wsize);
+ agg_wsize = wil->max_agg_wsize;
+ } else {
+ agg_wsize = min_t(u16, wil->max_agg_wsize, req_agg_wsize);
}
rc = wil->txrx_ops.wmi_addba_rx_resp(wil, mid, cid, tid, dialog_token,
- status, agg_amsdu, agg_wsize,
- agg_timeout);
- if (rc || (status != WLAN_STATUS_SUCCESS)) {
- wil_err(wil, "do not apply ba, rc(%d), status(%d)\n", rc,
- status);
+ WLAN_STATUS_SUCCESS, agg_amsdu,
+ agg_wsize, agg_timeout);
+ if (rc) {
+ wil_err(wil, "do not apply ba, rc(%d)\n", rc);
goto out;
}
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 4ccfd1404458..eae00aafaa88 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -411,7 +411,7 @@ static int wil_rx_get_cid_by_skb(struct wil6210_priv *wil, struct sk_buff *skb)
ta = hdr->addr2;
}
- if (max_assoc_sta <= WIL6210_RX_DESC_MAX_CID)
+ if (wil->max_assoc_sta <= WIL6210_RX_DESC_MAX_CID)
return cid;
/* assuming no concurrency between AP interfaces and STA interfaces.
@@ -426,14 +426,14 @@ static int wil_rx_get_cid_by_skb(struct wil6210_priv *wil, struct sk_buff *skb)
* to find the real cid, compare transmitter address with the stored
* stations mac address in the driver sta array
*/
- for (i = cid; i < max_assoc_sta; i += WIL6210_RX_DESC_MAX_CID) {
+ for (i = cid; i < wil->max_assoc_sta; i += WIL6210_RX_DESC_MAX_CID) {
if (wil->sta[i].status != wil_sta_unused &&
ether_addr_equal(wil->sta[i].addr, ta)) {
cid = i;
break;
}
}
- if (i >= max_assoc_sta) {
+ if (i >= wil->max_assoc_sta) {
wil_err_ratelimited(wil, "Could not find cid for frame with transmit addr = %pM, iftype = %d, frametype = %d, len = %d\n",
ta, vif->wdev.iftype, ftype, skb->len);
cid = -ENOENT;
@@ -750,6 +750,7 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
[GRO_HELD] = "GRO_HELD",
[GRO_NORMAL] = "GRO_NORMAL",
[GRO_DROP] = "GRO_DROP",
+ [GRO_CONSUMED] = "GRO_CONSUMED",
};
wil->txrx_ops.get_netif_rx_params(skb, &cid, &security);
@@ -1036,7 +1037,8 @@ static int wil_vring_init_tx(struct wil6210_vif *vif, int id, int size,
if (!vif->privacy)
txdata->dot1x_open = true;
rc = wmi_call(wil, WMI_VRING_CFG_CMDID, vif->mid, &cmd, sizeof(cmd),
- WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100);
+ WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply),
+ WIL_WMI_CALL_GENERAL_TO_MS);
if (rc)
goto out_free;
@@ -1063,7 +1065,7 @@ static int wil_vring_init_tx(struct wil6210_vif *vif, int id, int size,
txdata->enabled = 0;
spin_unlock_bh(&txdata->lock);
wil_vring_free(wil, vring);
- wil->ring2cid_tid[id][0] = max_assoc_sta;
+ wil->ring2cid_tid[id][0] = wil->max_assoc_sta;
wil->ring2cid_tid[id][1] = 0;
out:
@@ -1124,7 +1126,8 @@ static int wil_tx_vring_modify(struct wil6210_vif *vif, int ring_id, int cid,
cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
rc = wmi_call(wil, WMI_VRING_CFG_CMDID, vif->mid, &cmd, sizeof(cmd),
- WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100);
+ WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply),
+ WIL_WMI_CALL_GENERAL_TO_MS);
if (rc)
goto fail;
@@ -1148,7 +1151,7 @@ fail:
txdata->dot1x_open = false;
txdata->enabled = 0;
spin_unlock_bh(&txdata->lock);
- wil->ring2cid_tid[ring_id][0] = max_assoc_sta;
+ wil->ring2cid_tid[ring_id][0] = wil->max_assoc_sta;
wil->ring2cid_tid[ring_id][1] = 0;
return rc;
}
@@ -1195,7 +1198,7 @@ int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size)
if (rc)
goto out;
- wil->ring2cid_tid[id][0] = max_assoc_sta; /* CID */
+ wil->ring2cid_tid[id][0] = wil->max_assoc_sta; /* CID */
wil->ring2cid_tid[id][1] = 0; /* TID */
cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
@@ -1204,7 +1207,8 @@ int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size)
txdata->dot1x_open = true;
rc = wmi_call(wil, WMI_BCAST_VRING_CFG_CMDID, vif->mid,
&cmd, sizeof(cmd),
- WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100);
+ WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply),
+ WIL_WMI_CALL_GENERAL_TO_MS);
if (rc)
goto out_free;
@@ -1243,7 +1247,7 @@ static struct wil_ring *wil_find_tx_ucast(struct wil6210_priv *wil,
cid = wil_find_cid(wil, vif->mid, da);
- if (cid < 0 || cid >= max_assoc_sta)
+ if (cid < 0 || cid >= wil->max_assoc_sta)
return NULL;
/* TODO: fix for multiple TID */
@@ -1295,7 +1299,7 @@ static struct wil_ring *wil_find_tx_ring_sta(struct wil6210_priv *wil,
continue;
cid = wil->ring2cid_tid[i][0];
- if (cid >= max_assoc_sta) /* skip BCAST */
+ if (cid >= wil->max_assoc_sta) /* skip BCAST */
continue;
if (!wil->ring_tx_data[i].dot1x_open &&
@@ -1373,7 +1377,7 @@ static struct wil_ring *wil_find_tx_bcast_2(struct wil6210_priv *wil,
continue;
cid = wil->ring2cid_tid[i][0];
- if (cid >= max_assoc_sta) /* skip BCAST */
+ if (cid >= wil->max_assoc_sta) /* skip BCAST */
continue;
if (!wil->ring_tx_data[i].dot1x_open &&
skb->protocol != cpu_to_be16(ETH_P_PAE))
@@ -1401,7 +1405,7 @@ found:
if (!v2->va || txdata2->mid != vif->mid)
continue;
cid = wil->ring2cid_tid[i][0];
- if (cid >= max_assoc_sta) /* skip BCAST */
+ if (cid >= wil->max_assoc_sta) /* skip BCAST */
continue;
if (!wil->ring_tx_data[i].dot1x_open &&
skb->protocol != cpu_to_be16(ETH_P_PAE))
@@ -1760,6 +1764,9 @@ static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct wil6210_vif *vif,
}
}
+ if (!_desc)
+ goto mem_error;
+
/* first descriptor may also be the last.
* in this case d pointer is invalid
*/
@@ -2254,7 +2261,7 @@ int wil_tx_complete(struct wil6210_vif *vif, int ringid)
used_before_complete = wil_ring_used_tx(vring);
- if (cid < max_assoc_sta)
+ if (cid < wil->max_assoc_sta)
stats = &wil->sta[cid].stats;
while (!wil_ring_is_empty(vring)) {
diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c b/drivers/net/wireless/ath/wil6210/txrx_edma.c
index f6fce6ff73d9..dc040cd4ab06 100644
--- a/drivers/net/wireless/ath/wil6210/txrx_edma.c
+++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c
@@ -26,6 +26,10 @@
#include "txrx.h"
#include "trace.h"
+/* Max number of entries (packets to complete) to update the hwtail of tx
+ * status ring. Should be power of 2
+ */
+#define WIL_EDMA_TX_SRING_UPDATE_HW_TAIL 128
#define WIL_EDMA_MAX_DATA_OFFSET (2)
/* RX buffer size must be aligned to 4 bytes */
#define WIL_EDMA_RX_BUF_LEN_DEFAULT (2048)
@@ -269,6 +273,9 @@ static void wil_move_all_rx_buff_to_free_list(struct wil6210_priv *wil,
struct list_head *active = &wil->rx_buff_mgmt.active;
dma_addr_t pa;
+ if (!wil->rx_buff_mgmt.buff_arr)
+ return;
+
while (!list_empty(active)) {
struct wil_rx_buff *rx_buff =
list_first_entry(active, struct wil_rx_buff, list);
@@ -734,7 +741,7 @@ static int wil_ring_init_tx_edma(struct wil6210_vif *vif, int ring_id,
txdata->enabled = 0;
spin_unlock_bh(&txdata->lock);
wil_ring_free_edma(wil, ring);
- wil->ring2cid_tid[ring_id][0] = max_assoc_sta;
+ wil->ring2cid_tid[ring_id][0] = wil->max_assoc_sta;
wil->ring2cid_tid[ring_id][1] = 0;
out:
@@ -944,7 +951,7 @@ again:
eop = wil_rx_status_get_eop(msg);
cid = wil_rx_status_get_cid(msg);
- if (unlikely(!wil_val_in_range(cid, 0, max_assoc_sta))) {
+ if (unlikely(!wil_val_in_range(cid, 0, wil->max_assoc_sta))) {
wil_err(wil, "Corrupt cid=%d, sring->swhead=%d\n",
cid, sring->swhead);
rxdata->skipping = true;
@@ -1152,7 +1159,7 @@ int wil_tx_sring_handler(struct wil6210_priv *wil,
struct wil_net_stats *stats;
struct wil_tx_enhanced_desc *_d;
unsigned int ring_id;
- unsigned int num_descs;
+ unsigned int num_descs, num_statuses = 0;
int i;
u8 dr_bit; /* Descriptor Ready bit */
struct wil_ring_tx_status msg;
@@ -1199,7 +1206,8 @@ int wil_tx_sring_handler(struct wil6210_priv *wil,
ndev = vif_to_ndev(vif);
cid = wil->ring2cid_tid[ring_id][0];
- stats = (cid < max_assoc_sta ? &wil->sta[cid].stats : NULL);
+ stats = (cid < wil->max_assoc_sta) ? &wil->sta[cid].stats :
+ NULL;
wil_dbg_txrx(wil,
"tx_status: completed desc_ring (%d), num_descs (%d)\n",
@@ -1272,6 +1280,11 @@ int wil_tx_sring_handler(struct wil6210_priv *wil,
}
again:
+ num_statuses++;
+ if (num_statuses % WIL_EDMA_TX_SRING_UPDATE_HW_TAIL == 0)
+ /* update HW tail to allow HW to push new statuses */
+ wil_w(wil, sring->hwtail, sring->swhead);
+
wil_sring_advance_swhead(sring);
wil_get_next_tx_status_msg(sring, &msg);
@@ -1282,8 +1295,9 @@ again:
if (desc_cnt)
wil_update_net_queues(wil, vif, NULL, false);
- /* Update the HW tail ptr (RD ptr) */
- wil_w(wil, sring->hwtail, (sring->swhead - 1) % sring->size);
+ if (num_statuses % WIL_EDMA_TX_SRING_UPDATE_HW_TAIL != 0)
+ /* Update the HW tail ptr (RD ptr) */
+ wil_w(wil, sring->hwtail, (sring->swhead - 1) % sring->size);
return desc_cnt;
}
diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.h b/drivers/net/wireless/ath/wil6210/txrx_edma.h
index bb4ff28b73e5..e9e6ea9b16b9 100644
--- a/drivers/net/wireless/ath/wil6210/txrx_edma.h
+++ b/drivers/net/wireless/ath/wil6210/txrx_edma.h
@@ -24,7 +24,7 @@
#define WIL_SRING_SIZE_ORDER_MAX (WIL_RING_SIZE_ORDER_MAX)
/* RX sring order should be bigger than RX ring order */
#define WIL_RX_SRING_SIZE_ORDER_DEFAULT (12)
-#define WIL_TX_SRING_SIZE_ORDER_DEFAULT (12)
+#define WIL_TX_SRING_SIZE_ORDER_DEFAULT (14)
#define WIL_RX_BUFF_ARR_SIZE_DEFAULT (2600)
#define WIL_DEFAULT_RX_STATUS_RING_ID 0
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 8724d9975606..6f456b311a39 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -99,6 +99,7 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)
#define WIL_MAX_AMPDU_SIZE_128 (128 * 1024) /* FW/HW limit */
#define WIL_MAX_AGG_WSIZE_64 (64) /* FW/HW limit */
#define WIL6210_MAX_STATUS_RINGS (8)
+#define WIL_WMI_CALL_GENERAL_TO_MS 100
/* Hardware offload block adds the following:
* 26 bytes - 3-address QoS data header
@@ -335,6 +336,11 @@ struct RGF_ICR {
#define BIT_BOOT_FROM_ROM BIT(31)
/* eDMA */
+#define RGF_SCM_PTRS_SUBQ_RD_PTR (0x8b4000)
+#define RGF_SCM_PTRS_COMPQ_RD_PTR (0x8b4100)
+#define RGF_DMA_SCM_SUBQ_CONS (0x8b60ec)
+#define RGF_DMA_SCM_COMPQ_PROD (0x8b616c)
+
#define RGF_INT_COUNT_ON_SPECIAL_EVT (0x8b62d8)
#define RGF_INT_CTRL_INT_GEN_CFG_0 (0x8bc000)
@@ -456,15 +462,6 @@ static inline void parse_cidxtid(u8 cidxtid, u8 *cid, u8 *tid)
*tid = (cidxtid >> 4) & 0xf;
}
-/**
- * wil_cid_valid - check cid is valid
- * @cid: CID value
- */
-static inline bool wil_cid_valid(u8 cid)
-{
- return (cid >= 0 && cid < max_assoc_sta);
-}
-
struct wil6210_mbox_ring {
u32 base;
u16 entry_size; /* max. size of mbox entry, incl. all headers */
@@ -913,6 +910,11 @@ struct wil_fw_stats_global {
struct wmi_link_stats_global stats;
};
+struct wil_brd_info {
+ u32 file_addr;
+ u32 file_max_size;
+};
+
struct wil6210_priv {
struct pci_dev *pdev;
u32 bar_size;
@@ -927,8 +929,8 @@ struct wil6210_priv {
const char *hw_name;
const char *wil_fw_name;
char *board_file;
- u32 brd_file_addr;
- u32 brd_file_max_size;
+ u32 num_of_brd_entries;
+ struct wil_brd_info *brd_info;
DECLARE_BITMAP(hw_capa, hw_capa_last);
DECLARE_BITMAP(fw_capabilities, WMI_FW_CAPABILITY_MAX);
DECLARE_BITMAP(platform_capa, WIL_PLATFORM_CAPA_MAX);
@@ -940,6 +942,8 @@ struct wil6210_priv {
struct wil6210_vif *vifs[WIL_MAX_VIFS];
struct mutex vif_mutex; /* protects access to VIF entries */
atomic_t connected_vifs;
+ u32 max_assoc_sta; /* max sta's supported by the driver and the FW */
+
/* profile */
struct cfg80211_chan_def monitor_chandef;
u32 monitor_flags;
@@ -1137,6 +1141,14 @@ static inline void wil_c(struct wil6210_priv *wil, u32 reg, u32 val)
wil_w(wil, reg, wil_r(wil, reg) & ~val);
}
+/**
+ * wil_cid_valid - check cid is valid
+ */
+static inline bool wil_cid_valid(struct wil6210_priv *wil, u8 cid)
+{
+ return (cid >= 0 && cid < wil->max_assoc_sta);
+}
+
void wil_get_board_file(struct wil6210_priv *wil, char *buf, size_t len);
#if defined(CONFIG_DYNAMIC_DEBUG)
@@ -1241,6 +1253,9 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct wil_ring *vring);
int wmi_update_ft_ies(struct wil6210_vif *vif, u16 ie_len, const void *ie);
int wmi_rxon(struct wil6210_priv *wil, bool on);
int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r);
+int wmi_get_all_temperatures(struct wil6210_priv *wil,
+ struct wmi_temp_sense_all_done_event
+ *sense_all_evt);
int wmi_disconnect_sta(struct wil6210_vif *vif, const u8 *mac, u16 reason,
bool del_sta);
int wmi_addba(struct wil6210_priv *wil, u8 mid,
@@ -1395,6 +1410,7 @@ int wmi_stop_sched_scan(struct wil6210_priv *wil);
int wmi_mgmt_tx(struct wil6210_vif *vif, const u8 *buf, size_t len);
int wmi_mgmt_tx_ext(struct wil6210_vif *vif, const u8 *buf, size_t len,
u8 channel, u16 duration_ms);
+int wmi_rbufcap_cfg(struct wil6210_priv *wil, bool enable, u16 threshold);
int reverse_memcmp(const void *cs, const void *ct, size_t count);
@@ -1413,4 +1429,5 @@ int wmi_addba_rx_resp_edma(struct wil6210_priv *wil, u8 mid, u8 cid,
void update_supported_bands(struct wil6210_priv *wil);
+void wil_clear_fw_log_addr(struct wil6210_priv *wil);
#endif /* __WIL6210_H__ */
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index d89cd41e78ac..475b1a233cc9 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -40,7 +40,6 @@ MODULE_PARM_DESC(led_id,
" 60G device led enablement. Set the led ID (0-2) to enable");
#define WIL_WAIT_FOR_SUSPEND_RESUME_COMP 200
-#define WIL_WMI_CALL_GENERAL_TO_MS 100
#define WIL_WMI_PCP_STOP_TO_MS 5000
/**
@@ -484,6 +483,10 @@ static const char *cmdid2name(u16 cmdid)
return "WMI_FT_REASSOC_CMD";
case WMI_UPDATE_FT_IES_CMDID:
return "WMI_UPDATE_FT_IES_CMD";
+ case WMI_RBUFCAP_CFG_CMDID:
+ return "WMI_RBUFCAP_CFG_CMD";
+ case WMI_TEMP_SENSE_ALL_CMDID:
+ return "WMI_TEMP_SENSE_ALL_CMDID";
default:
return "Untracked CMD";
}
@@ -628,6 +631,10 @@ static const char *eventid2name(u16 eventid)
return "WMI_FT_AUTH_STATUS_EVENT";
case WMI_FT_REASSOC_STATUS_EVENTID:
return "WMI_FT_REASSOC_STATUS_EVENT";
+ case WMI_RBUFCAP_CFG_EVENTID:
+ return "WMI_RBUFCAP_CFG_EVENT";
+ case WMI_TEMP_SENSE_ALL_DONE_EVENTID:
+ return "WMI_TEMP_SENSE_ALL_DONE_EVENTID";
default:
return "Untracked EVENT";
}
@@ -806,8 +813,8 @@ static void wmi_evt_ready(struct wil6210_vif *vif, int id, void *d, int len)
}
}
- max_assoc_sta = min_t(uint, max_assoc_sta, fw_max_assoc_sta);
- wil_dbg_wmi(wil, "setting max assoc sta to %d\n", max_assoc_sta);
+ wil->max_assoc_sta = min_t(uint, max_assoc_sta, fw_max_assoc_sta);
+ wil_dbg_wmi(wil, "setting max assoc sta to %d\n", wil->max_assoc_sta);
wil_set_recovery_state(wil, fw_recovery_idle);
set_bit(wil_status_fwready, wil->status);
@@ -974,7 +981,7 @@ static void wmi_evt_connect(struct wil6210_vif *vif, int id, void *d, int len)
evt->assoc_req_len, evt->assoc_resp_len);
return;
}
- if (evt->cid >= max_assoc_sta) {
+ if (evt->cid >= wil->max_assoc_sta) {
wil_err(wil, "Connect CID invalid : %d\n", evt->cid);
return;
}
@@ -1236,7 +1243,7 @@ static void wmi_evt_ring_en(struct wil6210_vif *vif, int id, void *d, int len)
return;
cid = wil->ring2cid_tid[vri][0];
- if (!wil_cid_valid(cid)) {
+ if (!wil_cid_valid(wil, cid)) {
wil_err(wil, "invalid cid %d for vring %d\n", cid, vri);
return;
}
@@ -1439,7 +1446,7 @@ static void wil_link_stats_store_basic(struct wil6210_vif *vif,
u8 cid = basic->cid;
struct wil_sta_info *sta;
- if (cid < 0 || cid >= max_assoc_sta) {
+ if (cid < 0 || cid >= wil->max_assoc_sta) {
wil_err(wil, "invalid cid %d\n", cid);
return;
}
@@ -1589,7 +1596,7 @@ static int wil_find_cid_ringid_sta(struct wil6210_priv *wil,
continue;
lcid = wil->ring2cid_tid[i][0];
- if (lcid >= max_assoc_sta) /* skip BCAST */
+ if (lcid >= wil->max_assoc_sta) /* skip BCAST */
continue;
wil_dbg_wmi(wil, "find sta -> ringid %d cid %d\n", i, lcid);
@@ -2051,7 +2058,8 @@ int wmi_echo(struct wil6210_priv *wil)
};
return wmi_call(wil, WMI_ECHO_CMDID, vif->mid, &cmd, sizeof(cmd),
- WMI_ECHO_RSP_EVENTID, NULL, 0, 50);
+ WMI_ECHO_RSP_EVENTID, NULL, 0,
+ WIL_WMI_CALL_GENERAL_TO_MS);
}
int wmi_set_mac_address(struct wil6210_priv *wil, void *addr)
@@ -2110,7 +2118,7 @@ int wmi_led_cfg(struct wil6210_priv *wil, bool enable)
rc = wmi_call(wil, WMI_LED_CFG_CMDID, vif->mid, &cmd, sizeof(cmd),
WMI_LED_CFG_DONE_EVENTID, &reply, sizeof(reply),
- 100);
+ WIL_WMI_CALL_GENERAL_TO_MS);
if (rc)
goto out;
@@ -2124,6 +2132,37 @@ out:
return rc;
}
+int wmi_rbufcap_cfg(struct wil6210_priv *wil, bool enable, u16 threshold)
+{
+ struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
+ int rc;
+
+ struct wmi_rbufcap_cfg_cmd cmd = {
+ .enable = enable,
+ .rx_desc_threshold = cpu_to_le16(threshold),
+ };
+ struct {
+ struct wmi_cmd_hdr wmi;
+ struct wmi_rbufcap_cfg_event evt;
+ } __packed reply = {
+ .evt = {.status = WMI_FW_STATUS_FAILURE},
+ };
+
+ rc = wmi_call(wil, WMI_RBUFCAP_CFG_CMDID, vif->mid, &cmd, sizeof(cmd),
+ WMI_RBUFCAP_CFG_EVENTID, &reply, sizeof(reply),
+ WIL_WMI_CALL_GENERAL_TO_MS);
+ if (rc)
+ return rc;
+
+ if (reply.evt.status != WMI_FW_STATUS_SUCCESS) {
+ wil_err(wil, "RBUFCAP_CFG failed. status %d\n",
+ reply.evt.status);
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
int wmi_pcp_start(struct wil6210_vif *vif,
int bi, u8 wmi_nettype, u8 chan, u8 hidden_ssid, u8 is_go)
{
@@ -2135,7 +2174,7 @@ int wmi_pcp_start(struct wil6210_vif *vif,
.network_type = wmi_nettype,
.disable_sec_offload = 1,
.channel = chan - 1,
- .pcp_max_assoc_sta = max_assoc_sta,
+ .pcp_max_assoc_sta = wil->max_assoc_sta,
.hidden_ssid = hidden_ssid,
.is_go = is_go,
.ap_sme_offload_mode = disable_ap_sme ?
@@ -2228,7 +2267,8 @@ int wmi_get_ssid(struct wil6210_vif *vif, u8 *ssid_len, void *ssid)
memset(&reply, 0, sizeof(reply));
rc = wmi_call(wil, WMI_GET_SSID_CMDID, vif->mid, NULL, 0,
- WMI_GET_SSID_EVENTID, &reply, sizeof(reply), 20);
+ WMI_GET_SSID_EVENTID, &reply, sizeof(reply),
+ WIL_WMI_CALL_GENERAL_TO_MS);
if (rc)
return rc;
@@ -2265,7 +2305,8 @@ int wmi_get_channel(struct wil6210_priv *wil, int *channel)
memset(&reply, 0, sizeof(reply));
rc = wmi_call(wil, WMI_GET_PCP_CHANNEL_CMDID, vif->mid, NULL, 0,
- WMI_GET_PCP_CHANNEL_EVENTID, &reply, sizeof(reply), 20);
+ WMI_GET_PCP_CHANNEL_EVENTID, &reply, sizeof(reply),
+ WIL_WMI_CALL_GENERAL_TO_MS);
if (rc)
return rc;
@@ -2361,7 +2402,8 @@ int wmi_stop_discovery(struct wil6210_vif *vif)
wil_dbg_wmi(wil, "sending WMI_DISCOVERY_STOP_CMDID\n");
rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, vif->mid, NULL, 0,
- WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, 100);
+ WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0,
+ WIL_WMI_CALL_GENERAL_TO_MS);
if (rc)
wil_err(wil, "Failed to stop discovery\n");
@@ -2507,12 +2549,14 @@ int wmi_rxon(struct wil6210_priv *wil, bool on)
if (on) {
rc = wmi_call(wil, WMI_START_LISTEN_CMDID, vif->mid, NULL, 0,
WMI_LISTEN_STARTED_EVENTID,
- &reply, sizeof(reply), 100);
+ &reply, sizeof(reply),
+ WIL_WMI_CALL_GENERAL_TO_MS);
if ((rc == 0) && (reply.evt.status != WMI_FW_STATUS_SUCCESS))
rc = -EINVAL;
} else {
rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, vif->mid, NULL, 0,
- WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, 20);
+ WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0,
+ WIL_WMI_CALL_GENERAL_TO_MS);
}
return rc;
@@ -2601,7 +2645,8 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf)
memset(&reply, 0, sizeof(reply));
rc = wmi_call(wil, WMI_TEMP_SENSE_CMDID, vif->mid, &cmd, sizeof(cmd),
- WMI_TEMP_SENSE_DONE_EVENTID, &reply, sizeof(reply), 100);
+ WMI_TEMP_SENSE_DONE_EVENTID, &reply, sizeof(reply),
+ WIL_WMI_CALL_GENERAL_TO_MS);
if (rc)
return rc;
@@ -2613,6 +2658,44 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf)
return 0;
}
+int wmi_get_all_temperatures(struct wil6210_priv *wil,
+ struct wmi_temp_sense_all_done_event
+ *sense_all_evt)
+{
+ struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
+ int rc;
+ struct wmi_temp_sense_all_cmd cmd = {
+ .measure_baseband_en = true,
+ .measure_rf_en = true,
+ .measure_mode = TEMPERATURE_MEASURE_NOW,
+ };
+ struct {
+ struct wmi_cmd_hdr wmi;
+ struct wmi_temp_sense_all_done_event evt;
+ } __packed reply;
+
+ if (!sense_all_evt) {
+ wil_err(wil, "Invalid sense_all_evt value\n");
+ return -EINVAL;
+ }
+
+ memset(&reply, 0, sizeof(reply));
+ reply.evt.status = WMI_FW_STATUS_FAILURE;
+ rc = wmi_call(wil, WMI_TEMP_SENSE_ALL_CMDID, vif->mid, &cmd,
+ sizeof(cmd), WMI_TEMP_SENSE_ALL_DONE_EVENTID,
+ &reply, sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS);
+ if (rc)
+ return rc;
+
+ if (reply.evt.status == WMI_FW_STATUS_FAILURE) {
+ wil_err(wil, "Failed geting TEMP_SENSE_ALL\n");
+ return -EINVAL;
+ }
+
+ memcpy(sense_all_evt, &reply.evt, sizeof(reply.evt));
+ return 0;
+}
+
int wmi_disconnect_sta(struct wil6210_vif *vif, const u8 *mac, u16 reason,
bool del_sta)
{
@@ -2715,7 +2798,7 @@ int wmi_addba_rx_resp(struct wil6210_priv *wil,
.dialog_token = token,
.status_code = cpu_to_le16(status),
/* bit 0: A-MSDU supported
- * bit 1: policy (should be 0 for us)
+ * bit 1: policy (controlled by FW)
* bits 2..5: TID
* bits 6..15: buffer size
*/
@@ -2745,7 +2828,7 @@ int wmi_addba_rx_resp(struct wil6210_priv *wil,
rc = wmi_call(wil, WMI_RCP_ADDBA_RESP_CMDID, mid, &cmd, sizeof(cmd),
WMI_RCP_ADDBA_RESP_SENT_EVENTID, &reply, sizeof(reply),
- 100);
+ WIL_WMI_CALL_GENERAL_TO_MS);
if (rc)
return rc;
@@ -2769,7 +2852,7 @@ int wmi_addba_rx_resp_edma(struct wil6210_priv *wil, u8 mid, u8 cid, u8 tid,
.dialog_token = token,
.status_code = cpu_to_le16(status),
/* bit 0: A-MSDU supported
- * bit 1: policy (should be 0 for us)
+ * bit 1: policy (controlled by FW)
* bits 2..5: TID
* bits 6..15: buffer size
*/
@@ -2827,7 +2910,7 @@ int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil,
rc = wmi_call(wil, WMI_PS_DEV_PROFILE_CFG_CMDID, vif->mid,
&cmd, sizeof(cmd),
WMI_PS_DEV_PROFILE_CFG_EVENTID, &reply, sizeof(reply),
- 100);
+ WIL_WMI_CALL_GENERAL_TO_MS);
if (rc)
return rc;
@@ -2864,7 +2947,7 @@ int wmi_set_mgmt_retry(struct wil6210_priv *wil, u8 retry_short)
rc = wmi_call(wil, WMI_SET_MGMT_RETRY_LIMIT_CMDID, vif->mid,
&cmd, sizeof(cmd),
WMI_SET_MGMT_RETRY_LIMIT_EVENTID, &reply, sizeof(reply),
- 100);
+ WIL_WMI_CALL_GENERAL_TO_MS);
if (rc)
return rc;
@@ -2894,7 +2977,7 @@ int wmi_get_mgmt_retry(struct wil6210_priv *wil, u8 *retry_short)
memset(&reply, 0, sizeof(reply));
rc = wmi_call(wil, WMI_GET_MGMT_RETRY_LIMIT_CMDID, vif->mid, NULL, 0,
WMI_GET_MGMT_RETRY_LIMIT_EVENTID, &reply, sizeof(reply),
- 100);
+ WIL_WMI_CALL_GENERAL_TO_MS);
if (rc)
return rc;
@@ -3220,7 +3303,18 @@ static void wmi_event_handle(struct wil6210_priv *wil,
/* check if someone waits for this event */
if (wil->reply_id && wil->reply_id == id &&
wil->reply_mid == mid) {
- WARN_ON(wil->reply_buf);
+ if (wil->reply_buf) {
+ /* event received while wmi_call is waiting
+ * with a buffer. Such event should be handled
+ * in wmi_recv_cmd function. Handling the event
+ * here means a previous wmi_call was timeout.
+ * Drop the event and do not handle it.
+ */
+ wil_err(wil,
+ "Old event (%d, %s) while wmi_call is waiting. Drop it and Continue waiting\n",
+ id, eventid2name(id));
+ return;
+ }
wmi_evt_call_handler(vif, id, evt_data,
len - sizeof(*wmi));
@@ -3800,6 +3894,7 @@ int wil_wmi_bcast_desc_ring_add(struct wil6210_vif *vif, int ring_id)
.ring_size = cpu_to_le16(ring->size),
.ring_id = ring_id,
},
+ .max_msdu_size = cpu_to_le16(wil_mtu2macbuf(mtu_max)),
.status_ring_id = wil->tx_sring_idx,
.encap_trans_type = WMI_VRING_ENC_TYPE_802_3,
};
diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h
index da46fc8d39cf..3e37229b36b5 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.h
+++ b/drivers/net/wireless/ath/wil6210/wmi.h
@@ -35,6 +35,7 @@
#define WMI_PROX_RANGE_NUM (3)
#define WMI_MAX_LOSS_DMG_BEACONS (20)
#define MAX_NUM_OF_SECTORS (128)
+#define WMI_INVALID_TEMPERATURE (0xFFFFFFFF)
#define WMI_SCHED_MAX_ALLOCS_PER_CMD (4)
#define WMI_RF_DTYPE_LENGTH (3)
#define WMI_RF_ETYPE_LENGTH (3)
@@ -64,6 +65,7 @@
#define WMI_QOS_MAX_WEIGHT 50
#define WMI_QOS_SET_VIF_PRIORITY (0xFF)
#define WMI_QOS_DEFAULT_PRIORITY (WMI_QOS_NUM_OF_PRIORITY)
+#define WMI_MAX_XIF_PORTS_NUM (8)
/* Mailbox interface
* used for commands and events
@@ -105,6 +107,7 @@ enum wmi_fw_capability {
WMI_FW_CAPABILITY_TX_REQ_EXT = 25,
WMI_FW_CAPABILITY_CHANNEL_4 = 26,
WMI_FW_CAPABILITY_IPA = 27,
+ WMI_FW_CAPABILITY_TEMPERATURE_ALL_RF = 30,
WMI_FW_CAPABILITY_MAX,
};
@@ -296,6 +299,7 @@ enum wmi_command_id {
WMI_SET_VRING_PRIORITY_WEIGHT_CMDID = 0xA10,
WMI_SET_VRING_PRIORITY_CMDID = 0xA11,
WMI_RBUFCAP_CFG_CMDID = 0xA12,
+ WMI_TEMP_SENSE_ALL_CMDID = 0xA13,
WMI_SET_MAC_ADDRESS_CMDID = 0xF003,
WMI_ABORT_SCAN_CMDID = 0xF007,
WMI_SET_PROMISCUOUS_MODE_CMDID = 0xF041,
@@ -1411,12 +1415,7 @@ struct wmi_rf_xpm_write_cmd {
u8 data_bytes[0];
} __packed;
-/* WMI_TEMP_SENSE_CMDID
- *
- * Measure MAC and radio temperatures
- *
- * Possible modes for temperature measurement
- */
+/* Possible modes for temperature measurement */
enum wmi_temperature_measure_mode {
TEMPERATURE_USE_OLD_VALUE = 0x01,
TEMPERATURE_MEASURE_NOW = 0x02,
@@ -1942,6 +1941,14 @@ struct wmi_set_ap_slot_size_cmd {
__le32 slot_size;
} __packed;
+/* WMI_TEMP_SENSE_ALL_CMDID */
+struct wmi_temp_sense_all_cmd {
+ u8 measure_baseband_en;
+ u8 measure_rf_en;
+ u8 measure_mode;
+ u8 reserved;
+} __packed;
+
/* WMI Events
* List of Events (target to host)
*/
@@ -2101,6 +2108,7 @@ enum wmi_event_id {
WMI_SET_VRING_PRIORITY_WEIGHT_EVENTID = 0x1A10,
WMI_SET_VRING_PRIORITY_EVENTID = 0x1A11,
WMI_RBUFCAP_CFG_EVENTID = 0x1A12,
+ WMI_TEMP_SENSE_ALL_DONE_EVENTID = 0x1A13,
WMI_SET_CHANNEL_EVENTID = 0x9000,
WMI_ASSOC_REQ_EVENTID = 0x9001,
WMI_EAPOL_RX_EVENTID = 0x9002,
@@ -2784,11 +2792,13 @@ struct wmi_fixed_scheduling_ul_config_event {
*/
struct wmi_temp_sense_done_event {
/* Temperature times 1000 (actual temperature will be achieved by
- * dividing the value by 1000)
+ * dividing the value by 1000). When temperature cannot be read from
+ * device return WMI_INVALID_TEMPERATURE
*/
__le32 baseband_t1000;
/* Temperature times 1000 (actual temperature will be achieved by
- * dividing the value by 1000)
+ * dividing the value by 1000). When temperature cannot be read from
+ * device return WMI_INVALID_TEMPERATURE
*/
__le32 rf_t1000;
} __packed;
@@ -4140,4 +4150,25 @@ struct wmi_rbufcap_cfg_event {
u8 reserved[3];
} __packed;
+/* WMI_TEMP_SENSE_ALL_DONE_EVENTID
+ * Measure MAC and all radio temperatures
+ */
+struct wmi_temp_sense_all_done_event {
+ /* enum wmi_fw_status */
+ u8 status;
+ /* Bitmap of connected RFs */
+ u8 rf_bitmap;
+ u8 reserved[2];
+ /* Temperature times 1000 (actual temperature will be achieved by
+ * dividing the value by 1000). When temperature cannot be read from
+ * device return WMI_INVALID_TEMPERATURE
+ */
+ __le32 rf_t1000[WMI_MAX_XIF_PORTS_NUM];
+ /* Temperature times 1000 (actual temperature will be achieved by
+ * dividing the value by 1000). When temperature cannot be read from
+ * device return WMI_INVALID_TEMPERATURE
+ */
+ __le32 baseband_t1000;
+} __packed;
+
#endif /* __WILOCITY_WMI_H__ */
diff --git a/drivers/net/wireless/broadcom/b43/dma.c b/drivers/net/wireless/broadcom/b43/dma.c
index 806406aab43d..31bf71a80c26 100644
--- a/drivers/net/wireless/broadcom/b43/dma.c
+++ b/drivers/net/wireless/broadcom/b43/dma.c
@@ -797,7 +797,7 @@ static void free_all_descbuffers(struct b43_dmaring *ring)
}
}
-static u64 supported_dma_mask(struct b43_wldev *dev)
+static enum b43_dmatype b43_engine_type(struct b43_wldev *dev)
{
u32 tmp;
u16 mmio_base;
@@ -807,14 +807,14 @@ static u64 supported_dma_mask(struct b43_wldev *dev)
case B43_BUS_BCMA:
tmp = bcma_aread32(dev->dev->bdev, BCMA_IOST);
if (tmp & BCMA_IOST_DMA64)
- return DMA_BIT_MASK(64);
+ return B43_DMA_64BIT;
break;
#endif
#ifdef CONFIG_B43_SSB
case B43_BUS_SSB:
tmp = ssb_read32(dev->dev->sdev, SSB_TMSHIGH);
if (tmp & SSB_TMSHIGH_DMA64)
- return DMA_BIT_MASK(64);
+ return B43_DMA_64BIT;
break;
#endif
}
@@ -823,20 +823,7 @@ static u64 supported_dma_mask(struct b43_wldev *dev)
b43_write32(dev, mmio_base + B43_DMA32_TXCTL, B43_DMA32_TXADDREXT_MASK);
tmp = b43_read32(dev, mmio_base + B43_DMA32_TXCTL);
if (tmp & B43_DMA32_TXADDREXT_MASK)
- return DMA_BIT_MASK(32);
-
- return DMA_BIT_MASK(30);
-}
-
-static enum b43_dmatype dma_mask_to_engine_type(u64 dmamask)
-{
- if (dmamask == DMA_BIT_MASK(30))
- return B43_DMA_30BIT;
- if (dmamask == DMA_BIT_MASK(32))
return B43_DMA_32BIT;
- if (dmamask == DMA_BIT_MASK(64))
- return B43_DMA_64BIT;
- B43_WARN_ON(1);
return B43_DMA_30BIT;
}
@@ -1043,42 +1030,6 @@ void b43_dma_free(struct b43_wldev *dev)
destroy_ring(dma, tx_ring_mcast);
}
-static int b43_dma_set_mask(struct b43_wldev *dev, u64 mask)
-{
- u64 orig_mask = mask;
- bool fallback = false;
- int err;
-
- /* Try to set the DMA mask. If it fails, try falling back to a
- * lower mask, as we can always also support a lower one. */
- while (1) {
- err = dma_set_mask_and_coherent(dev->dev->dma_dev, mask);
- if (!err)
- break;
- if (mask == DMA_BIT_MASK(64)) {
- mask = DMA_BIT_MASK(32);
- fallback = true;
- continue;
- }
- if (mask == DMA_BIT_MASK(32)) {
- mask = DMA_BIT_MASK(30);
- fallback = true;
- continue;
- }
- b43err(dev->wl, "The machine/kernel does not support "
- "the required %u-bit DMA mask\n",
- (unsigned int)dma_mask_to_engine_type(orig_mask));
- return -EOPNOTSUPP;
- }
- if (fallback) {
- b43info(dev->wl, "DMA mask fallback from %u-bit to %u-bit\n",
- (unsigned int)dma_mask_to_engine_type(orig_mask),
- (unsigned int)dma_mask_to_engine_type(mask));
- }
-
- return 0;
-}
-
/* Some hardware with 64-bit DMA seems to be bugged and looks for translation
* bit in low address word instead of high one.
*/
@@ -1101,15 +1052,15 @@ static bool b43_dma_translation_in_low_word(struct b43_wldev *dev,
int b43_dma_init(struct b43_wldev *dev)
{
struct b43_dma *dma = &dev->dma;
+ enum b43_dmatype type = b43_engine_type(dev);
int err;
- u64 dmamask;
- enum b43_dmatype type;
- dmamask = supported_dma_mask(dev);
- type = dma_mask_to_engine_type(dmamask);
- err = b43_dma_set_mask(dev, dmamask);
- if (err)
+ err = dma_set_mask_and_coherent(dev->dev->dma_dev, DMA_BIT_MASK(type));
+ if (err) {
+ b43err(dev->wl, "The machine/kernel does not support "
+ "the required %u-bit DMA mask\n", type);
return err;
+ }
switch (dev->dev->bus_type) {
#ifdef CONFIG_B43_BCMA
@@ -1813,7 +1764,7 @@ void b43_dma_direct_fifo_rx(struct b43_wldev *dev,
enum b43_dmatype type;
u16 mmio_base;
- type = dma_mask_to_engine_type(supported_dma_mask(dev));
+ type = b43_engine_type(dev);
mmio_base = b43_dmacontroller_base(type, engine_index);
direct_fifo_rx(dev, type, mmio_base, enable);
diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c
index 20815a71680b..b85603e91c7a 100644
--- a/drivers/net/wireless/broadcom/b43/main.c
+++ b/drivers/net/wireless/broadcom/b43/main.c
@@ -2590,18 +2590,13 @@ start_ieee80211:
err = ieee80211_register_hw(wl->hw);
if (err)
- goto err_one_core_detach;
+ goto out;
wl->hw_registered = true;
b43_leds_register(wl->current_dev);
/* Register HW RNG driver */
b43_rng_init(wl);
- goto out;
-
-err_one_core_detach:
- b43_one_core_detach(dev->dev);
-
out:
kfree(ctx);
}
diff --git a/drivers/net/wireless/broadcom/b43legacy/dma.c b/drivers/net/wireless/broadcom/b43legacy/dma.c
index 1cc25f44dd9a..f7594e2a896e 100644
--- a/drivers/net/wireless/broadcom/b43legacy/dma.c
+++ b/drivers/net/wireless/broadcom/b43legacy/dma.c
@@ -603,7 +603,7 @@ static void free_all_descbuffers(struct b43legacy_dmaring *ring)
}
}
-static u64 supported_dma_mask(struct b43legacy_wldev *dev)
+static enum b43legacy_dmatype b43legacy_engine_type(struct b43legacy_wldev *dev)
{
u32 tmp;
u16 mmio_base;
@@ -615,18 +615,7 @@ static u64 supported_dma_mask(struct b43legacy_wldev *dev)
tmp = b43legacy_read32(dev, mmio_base +
B43legacy_DMA32_TXCTL);
if (tmp & B43legacy_DMA32_TXADDREXT_MASK)
- return DMA_BIT_MASK(32);
-
- return DMA_BIT_MASK(30);
-}
-
-static enum b43legacy_dmatype dma_mask_to_engine_type(u64 dmamask)
-{
- if (dmamask == DMA_BIT_MASK(30))
- return B43legacy_DMA_30BIT;
- if (dmamask == DMA_BIT_MASK(32))
return B43legacy_DMA_32BIT;
- B43legacy_WARN_ON(1);
return B43legacy_DMA_30BIT;
}
@@ -784,54 +773,14 @@ void b43legacy_dma_free(struct b43legacy_wldev *dev)
dma->tx_ring0 = NULL;
}
-static int b43legacy_dma_set_mask(struct b43legacy_wldev *dev, u64 mask)
-{
- u64 orig_mask = mask;
- bool fallback = false;
- int err;
-
- /* Try to set the DMA mask. If it fails, try falling back to a
- * lower mask, as we can always also support a lower one. */
- while (1) {
- err = dma_set_mask_and_coherent(dev->dev->dma_dev, mask);
- if (!err)
- break;
- if (mask == DMA_BIT_MASK(64)) {
- mask = DMA_BIT_MASK(32);
- fallback = true;
- continue;
- }
- if (mask == DMA_BIT_MASK(32)) {
- mask = DMA_BIT_MASK(30);
- fallback = true;
- continue;
- }
- b43legacyerr(dev->wl, "The machine/kernel does not support "
- "the required %u-bit DMA mask\n",
- (unsigned int)dma_mask_to_engine_type(orig_mask));
- return -EOPNOTSUPP;
- }
- if (fallback) {
- b43legacyinfo(dev->wl, "DMA mask fallback from %u-bit to %u-"
- "bit\n",
- (unsigned int)dma_mask_to_engine_type(orig_mask),
- (unsigned int)dma_mask_to_engine_type(mask));
- }
-
- return 0;
-}
-
int b43legacy_dma_init(struct b43legacy_wldev *dev)
{
struct b43legacy_dma *dma = &dev->dma;
struct b43legacy_dmaring *ring;
+ enum b43legacy_dmatype type = b43legacy_engine_type(dev);
int err;
- u64 dmamask;
- enum b43legacy_dmatype type;
- dmamask = supported_dma_mask(dev);
- type = dma_mask_to_engine_type(dmamask);
- err = b43legacy_dma_set_mask(dev, dmamask);
+ err = dma_set_mask_and_coherent(dev->dev->dma_dev, DMA_BIT_MASK(type));
if (err) {
#ifdef CONFIG_B43LEGACY_PIO
b43legacywarn(dev->wl, "DMA for this device not supported. "
diff --git a/drivers/net/wireless/broadcom/brcm80211/Kconfig b/drivers/net/wireless/broadcom/brcm80211/Kconfig
index 1df56d1f5e00..a5bf16c4f495 100644
--- a/drivers/net/wireless/broadcom/brcm80211/Kconfig
+++ b/drivers/net/wireless/broadcom/brcm80211/Kconfig
@@ -18,55 +18,7 @@ config BRCMSMAC
be available if you select BCMA_DRIVER_GPIO. If you choose to build a
module, the driver will be called brcmsmac.ko.
-config BRCMFMAC
- tristate "Broadcom FullMAC WLAN driver"
- depends on CFG80211
- select BRCMUTIL
- ---help---
- This module adds support for wireless adapters based on Broadcom
- FullMAC chipsets. It has to work with at least one of the bus
- interface support. If you choose to build a module, it'll be called
- brcmfmac.ko.
-
-config BRCMFMAC_PROTO_BCDC
- bool
-
-config BRCMFMAC_PROTO_MSGBUF
- bool
-
-config BRCMFMAC_SDIO
- bool "SDIO bus interface support for FullMAC driver"
- depends on (MMC = y || MMC = BRCMFMAC)
- depends on BRCMFMAC
- select BRCMFMAC_PROTO_BCDC
- select FW_LOADER
- default y
- ---help---
- This option enables the SDIO bus interface support for Broadcom
- IEEE802.11n embedded FullMAC WLAN driver. Say Y if you want to
- use the driver for a SDIO wireless card.
-
-config BRCMFMAC_USB
- bool "USB bus interface support for FullMAC driver"
- depends on (USB = y || USB = BRCMFMAC)
- depends on BRCMFMAC
- select BRCMFMAC_PROTO_BCDC
- select FW_LOADER
- ---help---
- This option enables the USB bus interface support for Broadcom
- IEEE802.11n embedded FullMAC WLAN driver. Say Y if you want to
- use the driver for an USB wireless card.
-
-config BRCMFMAC_PCIE
- bool "PCIE bus interface support for FullMAC driver"
- depends on BRCMFMAC
- depends on PCI
- select BRCMFMAC_PROTO_MSGBUF
- select FW_LOADER
- ---help---
- This option enables the PCIE bus interface support for Broadcom
- IEEE802.11ac embedded FullMAC WLAN driver. Say Y if you want to
- use the driver for an PCIE wireless card.
+source "drivers/net/wireless/broadcom/brcm80211/brcmfmac/Kconfig"
config BRCM_TRACING
bool "Broadcom device tracing"
@@ -82,6 +34,6 @@ config BRCM_TRACING
config BRCMDBG
bool "Broadcom driver debug functions"
depends on BRCMSMAC || BRCMFMAC
- select WANT_DEV_COREDUMP
+ select WANT_DEV_COREDUMP if BRCMFMAC
---help---
Selecting this enables additional code for debug purposes.
diff --git a/drivers/net/wireless/broadcom/brcm80211/Makefile b/drivers/net/wireless/broadcom/brcm80211/Makefile
index b987920e982e..88115d072624 100644
--- a/drivers/net/wireless/broadcom/brcm80211/Makefile
+++ b/drivers/net/wireless/broadcom/brcm80211/Makefile
@@ -1,19 +1,9 @@
+# SPDX-License-Identifier: ISC
#
-# Makefile fragment for Broadcom 802.11n Networking Device Driver
+# Makefile fragment for Broadcom 802.11 Networking Device Driver
#
# Copyright (c) 2010 Broadcom Corporation
#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
-# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
-# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# common flags
subdir-ccflags-$(CONFIG_BRCMDBG) += -DDEBUG
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Kconfig b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Kconfig
new file mode 100644
index 000000000000..32794c1eca23
--- /dev/null
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Kconfig
@@ -0,0 +1,50 @@
+config BRCMFMAC
+ tristate "Broadcom FullMAC WLAN driver"
+ depends on CFG80211
+ select BRCMUTIL
+ help
+ This module adds support for wireless adapters based on Broadcom
+ FullMAC chipsets. It has to work with at least one of the bus
+ interface support. If you choose to build a module, it'll be called
+ brcmfmac.ko.
+
+config BRCMFMAC_PROTO_BCDC
+ bool
+
+config BRCMFMAC_PROTO_MSGBUF
+ bool
+
+config BRCMFMAC_SDIO
+ bool "SDIO bus interface support for FullMAC driver"
+ depends on (MMC = y || MMC = BRCMFMAC)
+ depends on BRCMFMAC
+ select BRCMFMAC_PROTO_BCDC
+ select FW_LOADER
+ default y
+ help
+ This option enables the SDIO bus interface support for Broadcom
+ IEEE802.11n embedded FullMAC WLAN driver. Say Y if you want to
+ use the driver for a SDIO wireless card.
+
+config BRCMFMAC_USB
+ bool "USB bus interface support for FullMAC driver"
+ depends on (USB = y || USB = BRCMFMAC)
+ depends on BRCMFMAC
+ select BRCMFMAC_PROTO_BCDC
+ select FW_LOADER
+ help
+ This option enables the USB bus interface support for Broadcom
+ IEEE802.11n embedded FullMAC WLAN driver. Say Y if you want to
+ use the driver for an USB wireless card.
+
+config BRCMFMAC_PCIE
+ bool "PCIE bus interface support for FullMAC driver"
+ depends on BRCMFMAC
+ depends on PCI
+ select BRCMFMAC_PROTO_MSGBUF
+ select FW_LOADER
+ help
+ This option enables the PCIE bus interface support for Broadcom
+ IEEE802.11ac embedded FullMAC WLAN driver. Say Y if you want to
+ use the driver for an PCIE wireless card.
+
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile
index f7cf3e5f4849..9b15bc3f6054 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile
@@ -1,19 +1,9 @@
+# SPDX-License-Identifier: ISC
#
-# Makefile fragment for Broadcom 802.11n Networking Device Driver
+# Makefile fragment for Broadcom 802.11 Networking Device Driver
#
# Copyright (c) 2010 Broadcom Corporation
#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
-# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
-# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
ccflags-y += \
-I $(srctree)/$(src) \
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
index 98b168736df0..322e913ca7aa 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*******************************************************************************
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.h
index 4bc52240ccea..102e6938905c 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2013 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef BRCMFMAC_BCDC_H
#define BRCMFMAC_BCDC_H
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
index 60aede5abb4d..fc12598b2dd3 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* ****************** SDIO CARD Interface Functions **************************/
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c
index 372363a6e752..ec2bec0999d1 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2013 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/slab.h>
#include <linux/netdevice.h>
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.h
index 19647c68aa9e..418b9424a179 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2013 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef WL_BTCOEX_H_
#define WL_BTCOEX_H_
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
index 2fe167eae22c..0988a166a785 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef BRCMFMAC_BUS_H
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 8ee8af4e7ec4..b6d0df354b36 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
index 9a6287f084a9..b7b50b07f776 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef BRCMFMAC_CFG80211_H
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
index 22534bf2a90c..1ec48c4f4d4a 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2014 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/kernel.h>
#include <linux/delay.h>
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h
index 0ae3b33bab62..206d7695d57a 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2014 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef BRCMF_CHIP_H
#define BRCMF_CHIP_H
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
index 96b8d5b3aeed..aa89d620ee5d 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/kernel.h>
@@ -269,7 +258,7 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
/* query for 'ver' to get version info from firmware */
memset(buf, 0, sizeof(buf));
- strcpy(buf, "ver");
+ strlcpy(buf, "ver", sizeof(buf));
err = brcmf_fil_iovar_data_get(ifp, "ver", buf, sizeof(buf));
if (err < 0) {
bphy_err(drvr, "Retrieving version information failed, %d\n",
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
index 4ce56be90b74..144cf4570bc3 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
@@ -1,16 +1,6 @@
-/* Copyright (c) 2014 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+// SPDX-License-Identifier: ISC
+/*
+ * Copyright (c) 2014 Broadcom Corporation
*/
#ifndef BRCMFMAC_COMMON_H
#define BRCMFMAC_COMMON_H
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/commonring.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/commonring.c
index 7b0e52195a85..49db54d23e03 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/commonring.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/commonring.c
@@ -1,16 +1,6 @@
-/* Copyright (c) 2014 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+// SPDX-License-Identifier: ISC
+/*
+ * Copyright (c) 2014 Broadcom Corporation
*/
#include <linux/types.h>
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/commonring.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/commonring.h
index b85033611c8d..7fb11f4823e4 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/commonring.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/commonring.h
@@ -1,16 +1,6 @@
-/* Copyright (c) 2014 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+// SPDX-License-Identifier: ISC
+/*
+ * Copyright (c) 2014 Broadcom Corporation
*/
#ifndef BRCMFMAC_COMMONRING_H
#define BRCMFMAC_COMMONRING_H
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
index 7d6a08779693..bf18491a33a5 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/kernel.h>
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
index 9f09aa31eeda..86517a3d74b1 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/****************
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c
index 489b5dfdf5b9..120515fe8250 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2012 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/debugfs.h>
#include <linux/netdevice.h>
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h
index 2998726b62c3..ea6e8e839cae 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef BRCMFMAC_DEBUG_H
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c
index 9f1417e00073..4aa2561934d7 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright 2018 Hans de Goede <hdegoede@redhat.com>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/dmi.h>
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
index acca719b3907..73aff4e4039d 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2014 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/netdevice.h>
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
index 5e88a7f16ad2..f127eb2030a6 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2014 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _BRCMF_FEATURE_H
#define _BRCMF_FEATURE_H
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
index 6a333dd80b2d..3aed4c4b887a 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2013 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/efi.h>
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
index a0834be8864e..3347439543bb 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2013 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef BRCMFMAC_FIRMWARE_H
#define BRCMFMAC_FIRMWARE_H
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c
index d0d8b32af7d0..8e9d067bdfed 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c
@@ -1,16 +1,6 @@
-/* Copyright (c) 2014 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+// SPDX-License-Identifier: ISC
+/*
+ * Copyright (c) 2014 Broadcom Corporation
*/
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h
index 068e68d94999..818882b0fd01 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h
@@ -1,16 +1,6 @@
-/* Copyright (c) 2014 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+// SPDX-License-Identifier: ISC
+/*
+ * Copyright (c) 2014 Broadcom Corporation
*/
#ifndef BRCMFMAC_FLOWRING_H
#define BRCMFMAC_FLOWRING_H
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
index 63e98fd583ab..adedd4fac10b 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2012 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/netdevice.h>
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h
index 7027243db17e..a82f51bc1e69 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2012 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c
index 8ea27489734e..9ed85420f3ca 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2012 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* FWIL is the Firmware Interface Layer. In this module the support functions
@@ -314,7 +303,7 @@ brcmf_create_bsscfg(s32 bsscfgidx, char *name, char *data, u32 datalen,
return brcmf_create_iovar(name, data, datalen, buf, buflen);
prefixlen = strlen(prefix);
- namelen = strlen(name) + 1; /* lengh of iovar name + null */
+ namelen = strlen(name) + 1; /* length of iovar name + null */
iolen = prefixlen + namelen + sizeof(bsscfgidx_le) + datalen;
if (buflen < iolen) {
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h
index b6b183b18413..0ff6f5212a94 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2012 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _fwil_h_
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
index 39ac1bbb6cc0..37c512036e0e 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2012 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
index c22c49ae552e..b8452cb46297 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/types.h>
#include <linux/module.h>
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h
index 749c06dcdc17..10184eeaad94 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2012 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-
#ifndef FWSIGNAL_H_
#define FWSIGNAL_H_
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
index 9d1f9ff25bfa..241747bd5cb2 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
@@ -1,16 +1,6 @@
-/* Copyright (c) 2014 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+// SPDX-License-Identifier: ISC
+/*
+ * Copyright (c) 2014 Broadcom Corporation
*/
/*******************************************************************************
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h
index 692235d25277..2e322edbb907 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h
@@ -1,16 +1,6 @@
-/* Copyright (c) 2014 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+// SPDX-License-Identifier: ISC
+/*
+ * Copyright (c) 2014 Broadcom Corporation
*/
#ifndef BRCMFMAC_MSGBUF_H
#define BRCMFMAC_MSGBUF_H
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
index 84e3373289eb..b886b56a5e5a 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2014 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/init.h>
#include <linux/of.h>
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h
index 95b7032d54b1..10bf52253337 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2014 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef CONFIG_OF
void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
index 73a0e550f2b2..7ba9f6a68645 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2012 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/slab.h>
#include <linux/netdevice.h>
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.h
index 39f0d0218088..64ab9b6a677d 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2012 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef WL_CFGP2P_H_
#define WL_CFGP2P_H_
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
index 83e4938527f4..4ea5401c4d6b 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
@@ -1,16 +1,6 @@
-/* Copyright (c) 2014 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+// SPDX-License-Identifier: ISC
+/*
+ * Copyright (c) 2014 Broadcom Corporation
*/
#include <linux/kernel.h>
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.h
index 6edaaf8ef5ce..d026401d2001 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.h
@@ -1,16 +1,6 @@
-/* Copyright (c) 2014 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+// SPDX-License-Identifier: ISC
+/*
+ * Copyright (c) 2014 Broadcom Corporation
*/
#ifndef BRCMFMAC_PCIE_H
#define BRCMFMAC_PCIE_H
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
index 0fb97f7dd5a2..14e530601ef3 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2016 Broadcom
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/netdevice.h>
#include <linux/gcd.h>
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h
index cd9e35ae3b21..25d406019ac3 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2016 Broadcom
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _BRCMF_PNO_H
#define _BRCMF_PNO_H
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c
index c7964ccdda69..e3d1b075044b 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2013 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
index 72355aea9028..8d55fad531d0 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2013 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef BRCMFMAC_PROTO_H
#define BRCMFMAC_PROTO_H
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
index 22b73da42822..629140b6d7e2 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/types.h>
@@ -678,6 +667,12 @@ brcmf_sdio_kso_control(struct brcmf_sdio *bus, bool on)
brcmf_dbg(TRACE, "Enter: on=%d\n", on);
+ sdio_retune_crc_disable(bus->sdiodev->func1);
+
+ /* Cannot re-tune if device is asleep; defer till we're awake */
+ if (on)
+ sdio_retune_hold_now(bus->sdiodev->func1);
+
wr_val = (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
/* 1st KSO write goes to AOS wake up core if device is asleep */
brcmf_sdiod_writeb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err);
@@ -738,6 +733,11 @@ brcmf_sdio_kso_control(struct brcmf_sdio *bus, bool on)
if (try_cnt > MAX_KSO_ATTEMPTS)
brcmf_err("max tries: rd_val=0x%x err=%d\n", rd_val, err);
+ if (on)
+ sdio_retune_release(bus->sdiodev->func1);
+
+ sdio_retune_crc_enable(bus->sdiodev->func1);
+
return err;
}
@@ -3375,11 +3375,7 @@ err:
static bool brcmf_sdio_aos_no_decode(struct brcmf_sdio *bus)
{
- if (bus->ci->chip == CY_CC_43012_CHIP_ID ||
- bus->ci->chip == CY_CC_4373_CHIP_ID ||
- bus->ci->chip == BRCM_CC_4339_CHIP_ID ||
- bus->ci->chip == BRCM_CC_4345_CHIP_ID ||
- bus->ci->chip == BRCM_CC_4354_CHIP_ID)
+ if (bus->ci->chip == CY_CC_43012_CHIP_ID)
return true;
else
return false;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
index 34b031154da9..0bd47c119dae 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef BRCMFMAC_SDIO_H
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/tracepoint.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/tracepoint.c
index a5c271bff446..814fcc7538d5 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/tracepoint.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/tracepoint.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2012 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/device.h>
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/tracepoint.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/tracepoint.h
index 4d7d51f95716..338c66d0c5f8 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/tracepoint.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/tracepoint.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2013 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#if !defined(BRCMF_TRACEPOINT_H_) || defined(TRACE_HEADER_MULTI_READ)
#define BRCMF_TRACEPOINT_H_
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
index 75fcd6752edc..d33628b79a3a 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2011 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/kernel.h>
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.h
index f483a8c9945b..ee273e3bb101 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2011 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef BRCMFMAC_USB_H
#define BRCMFMAC_USB_H
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.c
index d493021f6031..f6500899fc14 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2014 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/vmalloc.h>
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.h
index 061b7bfa2e1c..418f33ea6fd3 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2014 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _vendor_h_
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c
index 35e3b101e5cf..2441714169de 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/kernel.h>
#include <linux/delay.h>
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 4d3734f48d9c..2e6a3d454ee8 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_hal.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_hal.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_int.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_int.h
index e9e8337f386c..8668fa5558a2 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_int.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_int.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _BRCM_PHY_INT_H_
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c
index c6e107f41948..7ef36234a25d 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/kernel.h>
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.h
index f4a8ab09da43..ae0e8d5df339 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _BRCM_PHY_LCN_H_
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c
index f4f5e9044152..07f61d6155ea 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_qmath.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_qmath.c
index b24bc57ca91b..45dcd277a89f 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_qmath.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_qmath.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "phy_qmath.h"
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_qmath.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_qmath.h
index 20e3783f921b..5d0083a87fd0 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_qmath.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_qmath.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _BRCM_QMATH_H_
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_radio.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_radio.h
index c3a675455ff5..706ab03c8346 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_radio.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_radio.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _BRCM_PHY_RADIO_H_
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phyreg_n.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phyreg_n.h
index a97c3a799479..f49a10c452e9 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phyreg_n.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phyreg_n.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define NPHY_TBL_ID_GAIN1 0
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phytbl_lcn.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phytbl_lcn.c
index d7fa312214f3..be703be34616 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phytbl_lcn.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phytbl_lcn.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <types.h>
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phytbl_lcn.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phytbl_lcn.h
index 489422a36085..b49580c654fb 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phytbl_lcn.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phytbl_lcn.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <types.h>
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phytbl_n.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phytbl_n.c
index 533bd4b0277e..7607e67d20c7 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phytbl_n.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phytbl_n.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/kernel.h>
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phytbl_n.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phytbl_n.h
index dc8a84e85117..28208aba4af2 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phytbl_n.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phytbl_n.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define ANT_SWCTRL_TBL_REV3_IDX (0)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmutil/Makefile b/drivers/net/wireless/broadcom/brcm80211/brcmutil/Makefile
index bb02c6220a88..7a82d615ba2a 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmutil/Makefile
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmutil/Makefile
@@ -1,20 +1,9 @@
+# SPDX-License-Identifier: ISC
#
# Makefile fragment for Broadcom 802.11n Networking Device Driver Utilities
#
# Copyright (c) 2011 Broadcom Corporation
#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
-# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
-# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
ccflags-y := -I $(srctree)/$(src)/../include
obj-$(CONFIG_BRCMUTIL) += brcmutil.o
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c b/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c
index 8ac34821f1c1..1e2b1e487eb7 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2013 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*********************channel spec common functions*********************/
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmutil/utils.c b/drivers/net/wireless/broadcom/brcm80211/brcmutil/utils.c
index 0543607002fd..4c84c3001c3f 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmutil/utils.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmutil/utils.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h
index 839980da9643..d1037b6ef2d6 100644
--- a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h
+++ b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _BRCM_HW_IDS_H_
diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_d11.h b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_d11.h
index 8b8b2ecb3199..f6344023855c 100644
--- a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_d11.h
+++ b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_d11.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _BRCMU_D11_H_
diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_utils.h b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_utils.h
index 41969527b459..946532328667 100644
--- a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_utils.h
+++ b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_utils.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _BRCMU_UTILS_H_
diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h
index dddebaa60352..7b31c212694d 100644
--- a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h
+++ b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _BRCMU_WIFI_H_
diff --git a/drivers/net/wireless/broadcom/brcm80211/include/chipcommon.h b/drivers/net/wireless/broadcom/brcm80211/include/chipcommon.h
index de8225e6248b..0340bba96868 100644
--- a/drivers/net/wireless/broadcom/brcm80211/include/chipcommon.h
+++ b/drivers/net/wireless/broadcom/brcm80211/include/chipcommon.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _SBCHIPC_H
diff --git a/drivers/net/wireless/broadcom/brcm80211/include/defs.h b/drivers/net/wireless/broadcom/brcm80211/include/defs.h
index 8d1e85e0ed51..9e7e6116eb74 100644
--- a/drivers/net/wireless/broadcom/brcm80211/include/defs.h
+++ b/drivers/net/wireless/broadcom/brcm80211/include/defs.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _BRCM_DEFS_H_
diff --git a/drivers/net/wireless/broadcom/brcm80211/include/soc.h b/drivers/net/wireless/broadcom/brcm80211/include/soc.h
index 123cfa854a0d..92d942b44f2c 100644
--- a/drivers/net/wireless/broadcom/brcm80211/include/soc.h
+++ b/drivers/net/wireless/broadcom/brcm80211/include/soc.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _BRCM_SOC_H
diff --git a/drivers/net/wireless/cisco/Kconfig b/drivers/net/wireless/cisco/Kconfig
index 7329830ed7cc..01e173ede894 100644
--- a/drivers/net/wireless/cisco/Kconfig
+++ b/drivers/net/wireless/cisco/Kconfig
@@ -17,6 +17,7 @@ config AIRO
depends on CFG80211 && ISA_DMA_API && (PCI || BROKEN)
select WIRELESS_EXT
select CRYPTO
+ select CRYPTO_BLKCIPHER
select WEXT_SPY
select WEXT_PRIV
---help---
@@ -40,6 +41,7 @@ config AIRO_CS
select WEXT_PRIV
select CRYPTO
select CRYPTO_AES
+ select CRYPTO_CTR
---help---
This is the standard Linux driver to support Cisco/Aironet PCMCIA
802.11 wireless cards. This driver is the same as the Aironet
diff --git a/drivers/net/wireless/cisco/airo.c b/drivers/net/wireless/cisco/airo.c
index 3f5a14112c6b..9342ffbe1e81 100644
--- a/drivers/net/wireless/cisco/airo.c
+++ b/drivers/net/wireless/cisco/airo.c
@@ -49,6 +49,9 @@
#include <linux/kthread.h>
#include <linux/freezer.h>
+#include <crypto/aes.h>
+#include <crypto/skcipher.h>
+
#include <net/cfg80211.h>
#include <net/iw_handler.h>
@@ -951,7 +954,7 @@ typedef struct {
} mic_statistics;
typedef struct {
- u32 coeff[((EMMH32_MSGLEN_MAX)+3)>>2];
+ __be32 coeff[((EMMH32_MSGLEN_MAX)+3)>>2];
u64 accum; // accumulated mic, reduced to u32 in final()
int position; // current position (byte offset) in message
union {
@@ -1216,7 +1219,7 @@ struct airo_info {
struct iw_spy_data spy_data;
struct iw_public_data wireless_data;
/* MIC stuff */
- struct crypto_cipher *tfm;
+ struct crypto_sync_skcipher *tfm;
mic_module mod[2];
mic_statistics micstats;
HostRxDesc rxfids[MPI_MAX_FIDS]; // rx/tx/config MPI350 descriptors
@@ -1291,14 +1294,14 @@ static int flashrestart(struct airo_info *ai,struct net_device *dev);
static int RxSeqValid (struct airo_info *ai,miccntx *context,int mcast,u32 micSeq);
static void MoveWindow(miccntx *context, u32 micSeq);
static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen,
- struct crypto_cipher *tfm);
+ struct crypto_sync_skcipher *tfm);
static void emmh32_init(emmh32_context *context);
static void emmh32_update(emmh32_context *context, u8 *pOctets, int len);
static void emmh32_final(emmh32_context *context, u8 digest[4]);
static int flashpchar(struct airo_info *ai,int byte,int dwelltime);
static void age_mic_context(miccntx *cur, miccntx *old, u8 *key, int key_len,
- struct crypto_cipher *tfm)
+ struct crypto_sync_skcipher *tfm)
{
/* If the current MIC context is valid and its key is the same as
* the MIC register, there's nothing to do.
@@ -1359,7 +1362,7 @@ static int micsetup(struct airo_info *ai) {
int i;
if (ai->tfm == NULL)
- ai->tfm = crypto_alloc_cipher("aes", 0, 0);
+ ai->tfm = crypto_alloc_sync_skcipher("ctr(aes)", 0, 0);
if (IS_ERR(ai->tfm)) {
airo_print_err(ai->dev->name, "failed to load transform for AES");
@@ -1624,37 +1627,31 @@ static void MoveWindow(miccntx *context, u32 micSeq)
/* mic accumulate */
#define MIC_ACCUM(val) \
- context->accum += (u64)(val) * context->coeff[coeff_position++];
-
-static unsigned char aes_counter[16];
+ context->accum += (u64)(val) * be32_to_cpu(context->coeff[coeff_position++]);
/* expand the key to fill the MMH coefficient array */
static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen,
- struct crypto_cipher *tfm)
+ struct crypto_sync_skcipher *tfm)
{
/* take the keying material, expand if necessary, truncate at 16-bytes */
/* run through AES counter mode to generate context->coeff[] */
- int i,j;
- u32 counter;
- u8 *cipher, plain[16];
-
- crypto_cipher_setkey(tfm, pkey, 16);
- counter = 0;
- for (i = 0; i < ARRAY_SIZE(context->coeff); ) {
- aes_counter[15] = (u8)(counter >> 0);
- aes_counter[14] = (u8)(counter >> 8);
- aes_counter[13] = (u8)(counter >> 16);
- aes_counter[12] = (u8)(counter >> 24);
- counter++;
- memcpy (plain, aes_counter, 16);
- crypto_cipher_encrypt_one(tfm, plain, plain);
- cipher = plain;
- for (j = 0; (j < 16) && (i < ARRAY_SIZE(context->coeff)); ) {
- context->coeff[i++] = ntohl(*(__be32 *)&cipher[j]);
- j += 4;
- }
- }
+ SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
+ struct scatterlist sg;
+ u8 iv[AES_BLOCK_SIZE] = {};
+ int ret;
+
+ crypto_sync_skcipher_setkey(tfm, pkey, 16);
+
+ memset(context->coeff, 0, sizeof(context->coeff));
+ sg_init_one(&sg, context->coeff, sizeof(context->coeff));
+
+ skcipher_request_set_sync_tfm(req, tfm);
+ skcipher_request_set_callback(req, 0, NULL, NULL);
+ skcipher_request_set_crypt(req, &sg, &sg, sizeof(context->coeff), iv);
+
+ ret = crypto_skcipher_encrypt(req);
+ WARN_ON_ONCE(ret);
}
/* prepare for calculation of a new mic */
@@ -2415,7 +2412,7 @@ void stop_airo_card( struct net_device *dev, int freeres )
ai->shared, ai->shared_dma);
}
}
- crypto_free_cipher(ai->tfm);
+ crypto_free_sync_skcipher(ai->tfm);
del_airo_dev(ai);
free_netdev( dev );
}
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw.h b/drivers/net/wireless/intel/ipw2x00/ipw.h
index 4007bf5ed6f3..7b230a132daa 100644
--- a/drivers/net/wireless/intel/ipw2x00/ipw.h
+++ b/drivers/net/wireless/intel/ipw2x00/ipw.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Intel Pro/Wireless 2100, 2200BG, 2915ABG network connection driver
*
* Copyright 2012 Stanislav Yakovlev <stas.yakovlev@gmail.com>
- *
- * 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.
*/
#ifndef __IPW_H__
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c
index 52e5ed2d3bc2..75c0c29d81f0 100644
--- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c
@@ -1,22 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/******************************************************************************
Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved.
- This program is free software; you can redistribute it and/or modify it
- under the terms of version 2 of the GNU General Public License as
- published by the Free Software Foundation.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59
- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- The full GNU General Public License is included in this distribution in the
- file called LICENSE.
Contact Information:
Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.h b/drivers/net/wireless/intel/ipw2x00/ipw2100.h
index 8c11c7fa2eef..b34085ade3aa 100644
--- a/drivers/net/wireless/intel/ipw2x00/ipw2100.h
+++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.h
@@ -1,22 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/******************************************************************************
Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved.
- This program is free software; you can redistribute it and/or modify it
- under the terms of version 2 of the GNU General Public License as
- published by the Free Software Foundation.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59
- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- The full GNU General Public License is included in this distribution in the
- file called LICENSE.
Contact Information:
Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c
index fa400f92d7e2..fa55d2ccbfab 100644
--- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/******************************************************************************
Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved.
@@ -8,21 +9,6 @@
By Gerald Combs <gerald@ethereal.com>
Copyright 1998 Gerald Combs
- This program is free software; you can redistribute it and/or modify it
- under the terms of version 2 of the GNU General Public License as
- published by the Free Software Foundation.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59
- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- The full GNU General Public License is included in this distribution in the
- file called LICENSE.
Contact Information:
Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.h b/drivers/net/wireless/intel/ipw2x00/ipw2200.h
index f98ab1f71edd..4346520545c4 100644
--- a/drivers/net/wireless/intel/ipw2x00/ipw2200.h
+++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.h
@@ -1,22 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/******************************************************************************
Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved.
- This program is free software; you can redistribute it and/or modify it
- under the terms of version 2 of the GNU General Public License as
- published by the Free Software Foundation.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59
- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- The full GNU General Public License is included in this distribution in the
- file called LICENSE.
Contact Information:
Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw.h b/drivers/net/wireless/intel/ipw2x00/libipw.h
index b51355134e04..e4a6ab4e8391 100644
--- a/drivers/net/wireless/intel/ipw2x00/libipw.h
+++ b/drivers/net/wireless/intel/ipw2x00/libipw.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Merged with mainline ieee80211.h in Aug 2004. Original ieee802_11
* remains copyright by the original authors
@@ -13,11 +14,6 @@
* <jketreno@linux.intel.com>
* Copyright (c) 2004-2005, Intel Corporation
*
- * 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. See README and COPYING for
- * more details.
- *
* API Version History
* 1.0.x -- Initial version
* 1.1.x -- Added radiotap, QoS, TIM, libipw_geo APIs,
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_geo.c b/drivers/net/wireless/intel/ipw2x00/libipw_geo.c
index ce7eda20a68f..f2ae3f8f2f5c 100644
--- a/drivers/net/wireless/intel/ipw2x00/libipw_geo.c
+++ b/drivers/net/wireless/intel/ipw2x00/libipw_geo.c
@@ -1,22 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/******************************************************************************
Copyright(c) 2005 Intel Corporation. All rights reserved.
- This program is free software; you can redistribute it and/or modify it
- under the terms of version 2 of the GNU General Public License as
- published by the Free Software Foundation.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59
- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- The full GNU General Public License is included in this distribution in the
- file called LICENSE.
Contact Information:
Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_module.c b/drivers/net/wireless/intel/ipw2x00/libipw_module.c
index f00d45f54c76..436b819aeb36 100644
--- a/drivers/net/wireless/intel/ipw2x00/libipw_module.c
+++ b/drivers/net/wireless/intel/ipw2x00/libipw_module.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*******************************************************************************
Copyright(c) 2004-2005 Intel Corporation. All rights reserved.
@@ -8,21 +9,6 @@
<j@w1.fi>
Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
- This program is free software; you can redistribute it and/or modify it
- under the terms of version 2 of the GNU General Public License as
- published by the Free Software Foundation.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59
- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- The full GNU General Public License is included in this distribution in the
- file called LICENSE.
Contact Information:
Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_rx.c b/drivers/net/wireless/intel/ipw2x00/libipw_rx.c
index 6df19f03355a..34cfd8162855 100644
--- a/drivers/net/wireless/intel/ipw2x00/libipw_rx.c
+++ b/drivers/net/wireless/intel/ipw2x00/libipw_rx.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Original code based Host AP (software wireless LAN access point) driver
* for Intersil Prism2/2.5/3 - hostap.o module, common routines
@@ -6,11 +7,6 @@
* <j@w1.fi>
* Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
* Copyright (c) 2004-2005, Intel Corporation
- *
- * 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. See README and COPYING for
- * more details.
*/
#include <linux/compiler.h>
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_tx.c b/drivers/net/wireless/intel/ipw2x00/libipw_tx.c
index 84205aa508df..d9baa2fa603b 100644
--- a/drivers/net/wireless/intel/ipw2x00/libipw_tx.c
+++ b/drivers/net/wireless/intel/ipw2x00/libipw_tx.c
@@ -1,22 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/******************************************************************************
Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved.
- This program is free software; you can redistribute it and/or modify it
- under the terms of version 2 of the GNU General Public License as
- published by the Free Software Foundation.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59
- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- The full GNU General Public License is included in this distribution in the
- file called LICENSE.
Contact Information:
Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_wx.c b/drivers/net/wireless/intel/ipw2x00/libipw_wx.c
index d32d39fa2686..3d558b47168b 100644
--- a/drivers/net/wireless/intel/ipw2x00/libipw_wx.c
+++ b/drivers/net/wireless/intel/ipw2x00/libipw_wx.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/******************************************************************************
Copyright(c) 2004-2005 Intel Corporation. All rights reserved.
@@ -8,21 +9,6 @@
<j@w1.fi>
Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
- This program is free software; you can redistribute it and/or modify it
- under the terms of version 2 of the GNU General Public License as
- published by the Free Software Foundation.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59
- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- The full GNU General Public License is included in this distribution in the
- file called LICENSE.
Contact Information:
Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/intel/iwlegacy/3945-rs.c b/drivers/net/wireless/intel/iwlegacy/3945-rs.c
index 5bd8a9ee8b1e..6209f85a71dd 100644
--- a/drivers/net/wireless/intel/iwlegacy/3945-rs.c
+++ b/drivers/net/wireless/intel/iwlegacy/3945-rs.c
@@ -631,9 +631,6 @@ il3945_rs_get_rate(void *il_r, struct ieee80211_sta *sta, void *il_sta,
il_sta = NULL;
}
- if (rate_control_send_low(sta, il_sta, txrc))
- return;
-
rate_mask = sta->supp_rates[sband->band];
/* get user max rate if set */
@@ -846,17 +843,8 @@ il3945_add_debugfs(void *il, void *il_sta, struct dentry *dir)
{
struct il3945_rs_sta *lq_sta = il_sta;
- lq_sta->rs_sta_dbgfs_stats_table_file =
- debugfs_create_file("rate_stats_table", 0600, dir, lq_sta,
- &rs_sta_dbgfs_stats_table_ops);
-
-}
-
-static void
-il3945_remove_debugfs(void *il, void *il_sta)
-{
- struct il3945_rs_sta *lq_sta = il_sta;
- debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file);
+ debugfs_create_file("rate_stats_table", 0600, dir, lq_sta,
+ &rs_sta_dbgfs_stats_table_ops);
}
#endif
@@ -883,7 +871,6 @@ static const struct rate_control_ops rs_ops = {
.free_sta = il3945_rs_free_sta,
#ifdef CONFIG_MAC80211_DEBUGFS
.add_sta_debugfs = il3945_add_debugfs,
- .remove_sta_debugfs = il3945_remove_debugfs,
#endif
};
diff --git a/drivers/net/wireless/intel/iwlegacy/3945.h b/drivers/net/wireless/intel/iwlegacy/3945.h
index 8e97e95fcbc4..82e4a4878bc2 100644
--- a/drivers/net/wireless/intel/iwlegacy/3945.h
+++ b/drivers/net/wireless/intel/iwlegacy/3945.h
@@ -72,9 +72,6 @@ struct il3945_rs_sta {
u8 start_rate;
struct timer_list rate_scale_flush;
struct il3945_rate_scale_data win[RATE_COUNT_3945];
-#ifdef CONFIG_MAC80211_DEBUGFS
- struct dentry *rs_sta_dbgfs_stats_table_file;
-#endif
/* used to be in sta_info */
int last_txrate_idx;
diff --git a/drivers/net/wireless/intel/iwlegacy/4965-rs.c b/drivers/net/wireless/intel/iwlegacy/4965-rs.c
index a824a10a43b6..7c6e2c863497 100644
--- a/drivers/net/wireless/intel/iwlegacy/4965-rs.c
+++ b/drivers/net/wireless/intel/iwlegacy/4965-rs.c
@@ -2209,10 +2209,6 @@ il4965_rs_get_rate(void *il_r, struct ieee80211_sta *sta, void *il_sta,
il_sta = NULL;
}
- /* Send management frames and NO_ACK data using lowest rate. */
- if (rate_control_send_low(sta, il_sta, txrc))
- return;
-
if (!lq_sta)
return;
@@ -2752,29 +2748,15 @@ static void
il4965_rs_add_debugfs(void *il, void *il_sta, struct dentry *dir)
{
struct il_lq_sta *lq_sta = il_sta;
- lq_sta->rs_sta_dbgfs_scale_table_file =
- debugfs_create_file("rate_scale_table", 0600, dir,
- lq_sta, &rs_sta_dbgfs_scale_table_ops);
- lq_sta->rs_sta_dbgfs_stats_table_file =
- debugfs_create_file("rate_stats_table", 0400, dir, lq_sta,
- &rs_sta_dbgfs_stats_table_ops);
- lq_sta->rs_sta_dbgfs_rate_scale_data_file =
- debugfs_create_file("rate_scale_data", 0400, dir, lq_sta,
- &rs_sta_dbgfs_rate_scale_data_ops);
- lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file =
- debugfs_create_u8("tx_agg_tid_enable", 0600, dir,
- &lq_sta->tx_agg_tid_en);
-
-}
-static void
-il4965_rs_remove_debugfs(void *il, void *il_sta)
-{
- struct il_lq_sta *lq_sta = il_sta;
- debugfs_remove(lq_sta->rs_sta_dbgfs_scale_table_file);
- debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file);
- debugfs_remove(lq_sta->rs_sta_dbgfs_rate_scale_data_file);
- debugfs_remove(lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file);
+ debugfs_create_file("rate_scale_table", 0600, dir, lq_sta,
+ &rs_sta_dbgfs_scale_table_ops);
+ debugfs_create_file("rate_stats_table", 0400, dir, lq_sta,
+ &rs_sta_dbgfs_stats_table_ops);
+ debugfs_create_file("rate_scale_data", 0400, dir, lq_sta,
+ &rs_sta_dbgfs_rate_scale_data_ops);
+ debugfs_create_u8("tx_agg_tid_enable", 0600, dir,
+ &lq_sta->tx_agg_tid_en);
}
#endif
@@ -2801,7 +2783,6 @@ static const struct rate_control_ops rs_4965_ops = {
.free_sta = il4965_rs_free_sta,
#ifdef CONFIG_MAC80211_DEBUGFS
.add_sta_debugfs = il4965_rs_add_debugfs,
- .remove_sta_debugfs = il4965_rs_remove_debugfs,
#endif
};
diff --git a/drivers/net/wireless/intel/iwlegacy/Kconfig b/drivers/net/wireless/intel/iwlegacy/Kconfig
index aa01c83e0060..e329fd7b09c0 100644
--- a/drivers/net/wireless/intel/iwlegacy/Kconfig
+++ b/drivers/net/wireless/intel/iwlegacy/Kconfig
@@ -32,7 +32,7 @@ config IWL4965
If you want to compile the driver as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
- say M here and read <file:Documentation/kbuild/modules.txt>. The
+ say M here and read <file:Documentation/kbuild/modules.rst>. The
module will be called iwl4965.
config IWL3945
@@ -58,7 +58,7 @@ config IWL3945
If you want to compile the driver as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
- say M here and read <file:Documentation/kbuild/modules.txt>. The
+ say M here and read <file:Documentation/kbuild/modules.rst>. The
module will be called iwl3945.
menu "iwl3945 / iwl4965 Debugging Options"
diff --git a/drivers/net/wireless/intel/iwlegacy/common.h b/drivers/net/wireless/intel/iwlegacy/common.h
index 6685b9a7e7d1..e7fb8e6bb9e7 100644
--- a/drivers/net/wireless/intel/iwlegacy/common.h
+++ b/drivers/net/wireless/intel/iwlegacy/common.h
@@ -2807,10 +2807,6 @@ struct il_lq_sta {
struct il_traffic_load load[TID_MAX_LOAD_COUNT];
u8 tx_agg_tid_en;
#ifdef CONFIG_MAC80211_DEBUGFS
- struct dentry *rs_sta_dbgfs_scale_table_file;
- struct dentry *rs_sta_dbgfs_stats_table_file;
- struct dentry *rs_sta_dbgfs_rate_scale_data_file;
- struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file;
u32 dbg_fixed_rate;
#endif
struct il_priv *drv;
diff --git a/drivers/net/wireless/intel/iwlwifi/Kconfig b/drivers/net/wireless/intel/iwlwifi/Kconfig
index e5528189163f..235349a33a3c 100644
--- a/drivers/net/wireless/intel/iwlwifi/Kconfig
+++ b/drivers/net/wireless/intel/iwlwifi/Kconfig
@@ -40,7 +40,7 @@ config IWLWIFI
If you want to compile the driver as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
- say M here and read <file:Documentation/kbuild/modules.txt>. The
+ say M here and read <file:Documentation/kbuild/modules.rst>. The
module will be called iwlwifi.
if IWLWIFI
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
index a9c846c59289..1f500cddb3a7 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
@@ -80,8 +80,11 @@
#define IWL_22000_QU_B_HR_B_FW_PRE "iwlwifi-Qu-b0-hr-b0-"
#define IWL_22000_HR_B_FW_PRE "iwlwifi-QuQnj-b0-hr-b0-"
#define IWL_22000_HR_A0_FW_PRE "iwlwifi-QuQnj-a0-hr-a0-"
+#define IWL_QU_C_HR_B_FW_PRE "iwlwifi-Qu-c0-hr-b0-"
#define IWL_QU_B_JF_B_FW_PRE "iwlwifi-Qu-b0-jf-b0-"
+#define IWL_QU_C_JF_B_FW_PRE "iwlwifi-Qu-c0-jf-b0-"
#define IWL_QUZ_A_HR_B_FW_PRE "iwlwifi-QuZ-a0-hr-b0-"
+#define IWL_QUZ_A_JF_B_FW_PRE "iwlwifi-QuZ-a0-jf-b0-"
#define IWL_QNJ_B_JF_B_FW_PRE "iwlwifi-QuQnj-b0-jf-b0-"
#define IWL_CC_A_FW_PRE "iwlwifi-cc-a0-"
#define IWL_22000_SO_A_JF_B_FW_PRE "iwlwifi-so-a0-jf-b0-"
@@ -106,6 +109,10 @@
IWL_22000_HR_A0_FW_PRE __stringify(api) ".ucode"
#define IWL_QUZ_A_HR_B_MODULE_FIRMWARE(api) \
IWL_QUZ_A_HR_B_FW_PRE __stringify(api) ".ucode"
+#define IWL_QUZ_A_JF_B_MODULE_FIRMWARE(api) \
+ IWL_QUZ_A_JF_B_FW_PRE __stringify(api) ".ucode"
+#define IWL_QU_C_HR_B_MODULE_FIRMWARE(api) \
+ IWL_QU_C_HR_B_FW_PRE __stringify(api) ".ucode"
#define IWL_QU_B_JF_B_MODULE_FIRMWARE(api) \
IWL_QU_B_JF_B_FW_PRE __stringify(api) ".ucode"
#define IWL_QNJ_B_JF_B_MODULE_FIRMWARE(api) \
@@ -241,6 +248,42 @@ const struct iwl_cfg iwl_ax101_cfg_qu_hr = {
.max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
};
+const struct iwl_cfg iwl_ax201_cfg_qu_hr = {
+ .name = "Intel(R) Wi-Fi 6 AX201 160MHz",
+ .fw_name_pre = IWL_22000_QU_B_HR_B_FW_PRE,
+ IWL_DEVICE_22500,
+ /*
+ * This device doesn't support receiving BlockAck with a large bitmap
+ * so we need to restrict the size of transmitted aggregation to the
+ * HT size; mac80211 would otherwise pick the HE max (256) by default.
+ */
+ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+};
+
+const struct iwl_cfg iwl_ax101_cfg_qu_c0_hr_b0 = {
+ .name = "Intel(R) Wi-Fi 6 AX101",
+ .fw_name_pre = IWL_QU_C_HR_B_FW_PRE,
+ IWL_DEVICE_22500,
+ /*
+ * This device doesn't support receiving BlockAck with a large bitmap
+ * so we need to restrict the size of transmitted aggregation to the
+ * HT size; mac80211 would otherwise pick the HE max (256) by default.
+ */
+ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+};
+
+const struct iwl_cfg iwl_ax201_cfg_qu_c0_hr_b0 = {
+ .name = "Intel(R) Wi-Fi 6 AX201 160MHz",
+ .fw_name_pre = IWL_QU_C_HR_B_FW_PRE,
+ IWL_DEVICE_22500,
+ /*
+ * This device doesn't support receiving BlockAck with a large bitmap
+ * so we need to restrict the size of transmitted aggregation to the
+ * HT size; mac80211 would otherwise pick the HE max (256) by default.
+ */
+ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+};
+
const struct iwl_cfg iwl_ax101_cfg_quz_hr = {
.name = "Intel(R) Wi-Fi 6 AX101",
.fw_name_pre = IWL_QUZ_A_HR_B_FW_PRE,
@@ -253,6 +296,42 @@ const struct iwl_cfg iwl_ax101_cfg_quz_hr = {
.max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
};
+const struct iwl_cfg iwl_ax201_cfg_quz_hr = {
+ .name = "Intel(R) Wi-Fi 6 AX201 160MHz",
+ .fw_name_pre = IWL_QUZ_A_HR_B_FW_PRE,
+ IWL_DEVICE_22500,
+ /*
+ * This device doesn't support receiving BlockAck with a large bitmap
+ * so we need to restrict the size of transmitted aggregation to the
+ * HT size; mac80211 would otherwise pick the HE max (256) by default.
+ */
+ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+};
+
+const struct iwl_cfg iwl_ax1650s_cfg_quz_hr = {
+ .name = "Killer(R) Wi-Fi 6 AX1650s 160MHz Wireless Network Adapter (201D2W)",
+ .fw_name_pre = IWL_QUZ_A_HR_B_FW_PRE,
+ IWL_DEVICE_22500,
+ /*
+ * This device doesn't support receiving BlockAck with a large bitmap
+ * so we need to restrict the size of transmitted aggregation to the
+ * HT size; mac80211 would otherwise pick the HE max (256) by default.
+ */
+ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+};
+
+const struct iwl_cfg iwl_ax1650i_cfg_quz_hr = {
+ .name = "Killer(R) Wi-Fi 6 AX1650i 160MHz Wireless Network Adapter (201NGW)",
+ .fw_name_pre = IWL_QUZ_A_HR_B_FW_PRE,
+ IWL_DEVICE_22500,
+ /*
+ * This device doesn't support receiving BlockAck with a large bitmap
+ * so we need to restrict the size of transmitted aggregation to the
+ * HT size; mac80211 would otherwise pick the HE max (256) by default.
+ */
+ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+};
+
const struct iwl_cfg iwl_ax200_cfg_cc = {
.name = "Intel(R) Wi-Fi 6 AX200 160MHz",
.fw_name_pre = IWL_CC_A_FW_PRE,
@@ -321,6 +400,30 @@ const struct iwl_cfg iwl9560_2ac_160_cfg_qu_b0_jf_b0 = {
IWL_DEVICE_22500,
};
+const struct iwl_cfg iwl9461_2ac_cfg_qu_c0_jf_b0 = {
+ .name = "Intel(R) Wireless-AC 9461",
+ .fw_name_pre = IWL_QU_C_JF_B_FW_PRE,
+ IWL_DEVICE_22500,
+};
+
+const struct iwl_cfg iwl9462_2ac_cfg_qu_c0_jf_b0 = {
+ .name = "Intel(R) Wireless-AC 9462",
+ .fw_name_pre = IWL_QU_C_JF_B_FW_PRE,
+ IWL_DEVICE_22500,
+};
+
+const struct iwl_cfg iwl9560_2ac_cfg_qu_c0_jf_b0 = {
+ .name = "Intel(R) Wireless-AC 9560",
+ .fw_name_pre = IWL_QU_C_JF_B_FW_PRE,
+ IWL_DEVICE_22500,
+};
+
+const struct iwl_cfg iwl9560_2ac_160_cfg_qu_c0_jf_b0 = {
+ .name = "Intel(R) Wireless-AC 9560 160MHz",
+ .fw_name_pre = IWL_QU_C_JF_B_FW_PRE,
+ IWL_DEVICE_22500,
+};
+
const struct iwl_cfg iwl9560_2ac_cfg_qnj_jf_b0 = {
.name = "Intel(R) Wireless-AC 9560 160MHz",
.fw_name_pre = IWL_QNJ_B_JF_B_FW_PRE,
@@ -333,6 +436,90 @@ const struct iwl_cfg iwl9560_2ac_cfg_qnj_jf_b0 = {
.max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
};
+const struct iwl_cfg iwl9560_2ac_cfg_quz_a0_jf_b0_soc = {
+ .name = "Intel(R) Wireless-AC 9560 160MHz",
+ .fw_name_pre = IWL_QUZ_A_JF_B_FW_PRE,
+ IWL_DEVICE_22500,
+ /*
+ * This device doesn't support receiving BlockAck with a large bitmap
+ * so we need to restrict the size of transmitted aggregation to the
+ * HT size; mac80211 would otherwise pick the HE max (256) by default.
+ */
+ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+ .integrated = true,
+ .soc_latency = 5000,
+};
+
+const struct iwl_cfg iwl9560_2ac_160_cfg_quz_a0_jf_b0_soc = {
+ .name = "Intel(R) Wireless-AC 9560 160MHz",
+ .fw_name_pre = IWL_QUZ_A_JF_B_FW_PRE,
+ IWL_DEVICE_22500,
+ /*
+ * This device doesn't support receiving BlockAck with a large bitmap
+ * so we need to restrict the size of transmitted aggregation to the
+ * HT size; mac80211 would otherwise pick the HE max (256) by default.
+ */
+ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+ .integrated = true,
+ .soc_latency = 5000,
+};
+
+const struct iwl_cfg iwl9461_2ac_cfg_quz_a0_jf_b0_soc = {
+ .name = "Intel(R) Dual Band Wireless AC 9461",
+ .fw_name_pre = IWL_QUZ_A_JF_B_FW_PRE,
+ IWL_DEVICE_22500,
+ /*
+ * This device doesn't support receiving BlockAck with a large bitmap
+ * so we need to restrict the size of transmitted aggregation to the
+ * HT size; mac80211 would otherwise pick the HE max (256) by default.
+ */
+ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+ .integrated = true,
+ .soc_latency = 5000,
+};
+
+const struct iwl_cfg iwl9462_2ac_cfg_quz_a0_jf_b0_soc = {
+ .name = "Intel(R) Dual Band Wireless AC 9462",
+ .fw_name_pre = IWL_QUZ_A_JF_B_FW_PRE,
+ IWL_DEVICE_22500,
+ /*
+ * This device doesn't support receiving BlockAck with a large bitmap
+ * so we need to restrict the size of transmitted aggregation to the
+ * HT size; mac80211 would otherwise pick the HE max (256) by default.
+ */
+ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+ .integrated = true,
+ .soc_latency = 5000,
+};
+
+const struct iwl_cfg iwl9560_killer_s_2ac_cfg_quz_a0_jf_b0_soc = {
+ .name = "Killer (R) Wireless-AC 1550s Wireless Network Adapter (9560NGW)",
+ .fw_name_pre = IWL_QUZ_A_JF_B_FW_PRE,
+ IWL_DEVICE_22500,
+ /*
+ * This device doesn't support receiving BlockAck with a large bitmap
+ * so we need to restrict the size of transmitted aggregation to the
+ * HT size; mac80211 would otherwise pick the HE max (256) by default.
+ */
+ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+ .integrated = true,
+ .soc_latency = 5000,
+};
+
+const struct iwl_cfg iwl9560_killer_i_2ac_cfg_quz_a0_jf_b0_soc = {
+ .name = "Killer (R) Wireless-AC 1550i Wireless Network Adapter (9560NGW)",
+ .fw_name_pre = IWL_QUZ_A_JF_B_FW_PRE,
+ IWL_DEVICE_22500,
+ /*
+ * This device doesn't support receiving BlockAck with a large bitmap
+ * so we need to restrict the size of transmitted aggregation to the
+ * HT size; mac80211 would otherwise pick the HE max (256) by default.
+ */
+ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+ .integrated = true,
+ .soc_latency = 5000,
+};
+
const struct iwl_cfg killer1550i_2ac_cfg_qu_b0_jf_b0 = {
.name = "Killer (R) Wireless-AC 1550i Wireless Network Adapter (9560NGW)",
.fw_name_pre = IWL_QU_B_JF_B_FW_PRE,
@@ -424,12 +611,12 @@ const struct iwl_cfg iwlax210_2ax_cfg_so_jf_a0 = {
};
const struct iwl_cfg iwlax210_2ax_cfg_so_hr_a0 = {
- .name = "Intel(R) Wi-Fi 6 AX201 160MHz",
+ .name = "Intel(R) Wi-Fi 7 AX210 160MHz",
.fw_name_pre = IWL_22000_SO_A_HR_B_FW_PRE,
IWL_DEVICE_AX210,
};
-const struct iwl_cfg iwlax210_2ax_cfg_so_gf_a0 = {
+const struct iwl_cfg iwlax211_2ax_cfg_so_gf_a0 = {
.name = "Intel(R) Wi-Fi 7 AX211 160MHz",
.fw_name_pre = IWL_22000_SO_A_GF_A_FW_PRE,
.uhb_supported = true,
@@ -443,8 +630,8 @@ const struct iwl_cfg iwlax210_2ax_cfg_ty_gf_a0 = {
IWL_DEVICE_AX210,
};
-const struct iwl_cfg iwlax210_2ax_cfg_so_gf4_a0 = {
- .name = "Intel(R) Wi-Fi 7 AX210 160MHz",
+const struct iwl_cfg iwlax411_2ax_cfg_so_gf4_a0 = {
+ .name = "Intel(R) Wi-Fi 7 AX411 160MHz",
.fw_name_pre = IWL_22000_SO_A_GF4_A_FW_PRE,
IWL_DEVICE_AX210,
};
@@ -455,8 +642,10 @@ MODULE_FIRMWARE(IWL_22000_HR_A_F0_QNJ_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_22000_HR_B_F0_QNJ_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_22000_HR_B_QNJ_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_22000_HR_A0_QNJ_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
+MODULE_FIRMWARE(IWL_QU_C_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_QU_B_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_QUZ_A_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
+MODULE_FIRMWARE(IWL_QUZ_A_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_QNJ_B_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_CC_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_22000_SO_A_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/lib.c b/drivers/net/wireless/intel/iwlwifi/dvm/lib.c
index 1fd6bf578474..eab94d2f46b1 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/lib.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/lib.c
@@ -1009,8 +1009,7 @@ int iwlagn_send_patterns(struct iwl_priv *priv,
if (!wowlan->n_patterns)
return 0;
- cmd.len[0] = sizeof(*pattern_cmd) +
- wowlan->n_patterns * sizeof(struct iwlagn_wowlan_pattern);
+ cmd.len[0] = struct_size(pattern_cmd, patterns, wowlan->n_patterns);
pattern_cmd = kmalloc(cmd.len[0], GFP_KERNEL);
if (!pattern_cmd)
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rs.c b/drivers/net/wireless/intel/iwlwifi/dvm/rs.c
index b500c9279a32..b1e5d64ca60d 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/rs.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/rs.c
@@ -2720,10 +2720,6 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
priv_sta = NULL;
}
- /* Send management frames and NO_ACK data using lowest rate. */
- if (rate_control_send_low(sta, priv_sta, txrc))
- return;
-
rate_idx = lq_sta->last_txrate_idx;
if (lq_sta->last_rate_n_flags & RATE_MCS_HT_MSK) {
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
index 405038ce98d6..7573af2d88ce 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
@@ -97,7 +97,7 @@ IWL_EXPORT_SYMBOL(iwl_acpi_get_object);
union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
union acpi_object *data,
- int data_size)
+ int data_size, int *tbl_rev)
{
int i;
union acpi_object *wifi_pkg;
@@ -113,16 +113,19 @@ union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
/*
* We need at least two packages, one for the revision and one
* for the data itself. Also check that the revision is valid
- * (i.e. it is an integer set to 0).
+ * (i.e. it is an integer smaller than 2, as we currently support only
+ * 2 revisions).
*/
if (data->type != ACPI_TYPE_PACKAGE ||
data->package.count < 2 ||
data->package.elements[0].type != ACPI_TYPE_INTEGER ||
- data->package.elements[0].integer.value != 0) {
+ data->package.elements[0].integer.value > 1) {
IWL_DEBUG_DEV_RADIO(dev, "Unsupported packages structure\n");
return ERR_PTR(-EINVAL);
}
+ *tbl_rev = data->package.elements[0].integer.value;
+
/* loop through all the packages to find the one for WiFi */
for (i = 1; i < data->package.count; i++) {
union acpi_object *domain;
@@ -151,14 +154,15 @@ int iwl_acpi_get_mcc(struct device *dev, char *mcc)
{
union acpi_object *wifi_pkg, *data;
u32 mcc_val;
- int ret;
+ int ret, tbl_rev;
data = iwl_acpi_get_object(dev, ACPI_WRDD_METHOD);
if (IS_ERR(data))
return PTR_ERR(data);
- wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_WRDD_WIFI_DATA_SIZE);
- if (IS_ERR(wifi_pkg)) {
+ wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_WRDD_WIFI_DATA_SIZE,
+ &tbl_rev);
+ if (IS_ERR(wifi_pkg) || tbl_rev != 0) {
ret = PTR_ERR(wifi_pkg);
goto out_free;
}
@@ -185,6 +189,7 @@ u64 iwl_acpi_get_pwr_limit(struct device *dev)
{
union acpi_object *data, *wifi_pkg;
u64 dflt_pwr_limit;
+ int tbl_rev;
data = iwl_acpi_get_object(dev, ACPI_SPLC_METHOD);
if (IS_ERR(data)) {
@@ -193,8 +198,8 @@ u64 iwl_acpi_get_pwr_limit(struct device *dev)
}
wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data,
- ACPI_SPLC_WIFI_DATA_SIZE);
- if (IS_ERR(wifi_pkg) ||
+ ACPI_SPLC_WIFI_DATA_SIZE, &tbl_rev);
+ if (IS_ERR(wifi_pkg) || tbl_rev != 0 ||
wifi_pkg->package.elements[1].integer.value != ACPI_TYPE_INTEGER) {
dflt_pwr_limit = 0;
goto out_free;
@@ -211,14 +216,15 @@ IWL_EXPORT_SYMBOL(iwl_acpi_get_pwr_limit);
int iwl_acpi_get_eckv(struct device *dev, u32 *extl_clk)
{
union acpi_object *wifi_pkg, *data;
- int ret;
+ int ret, tbl_rev;
data = iwl_acpi_get_object(dev, ACPI_ECKV_METHOD);
if (IS_ERR(data))
return PTR_ERR(data);
- wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_ECKV_WIFI_DATA_SIZE);
- if (IS_ERR(wifi_pkg)) {
+ wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_ECKV_WIFI_DATA_SIZE,
+ &tbl_rev);
+ if (IS_ERR(wifi_pkg) || tbl_rev != 0) {
ret = PTR_ERR(wifi_pkg);
goto out_free;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
index f5704e16643f..991a23450999 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
@@ -97,7 +97,7 @@
void *iwl_acpi_get_object(struct device *dev, acpi_string method);
union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
union acpi_object *data,
- int data_size);
+ int data_size, int *tbl_rev);
/**
* iwl_acpi_get_mcc - read MCC from ACPI, if available
@@ -131,7 +131,8 @@ static inline void *iwl_acpi_get_object(struct device *dev, acpi_string method)
static inline union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
union acpi_object *data,
- int data_size)
+ int data_size,
+ int *tbl_rev)
{
return ERR_PTR(-ENOENT);
}
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h
index f4202bc231a6..aaf3974a9a20 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h
@@ -291,6 +291,28 @@ struct iwl_fw_ini_trigger_tlv {
struct iwl_fw_ini_trigger trigger_config[];
} __packed; /* FW_TLV_DEBUG_TRIGGERS_API_S_VER_1 */
+#define IWL_FW_INI_MAX_IMG_NAME_LEN 32
+#define IWL_FW_INI_MAX_DBG_CFG_NAME_LEN 64
+
+/**
+ * struct iwl_fw_ini_debug_info_tlv - (IWL_UCODE_TLV_TYPE_DEBUG_INFO)
+ *
+ * holds image name and debug configuration name
+ *
+ * @header: header
+ * @img_name_len: length of the image name string
+ * @img_name: image name string
+ * @dbg_cfg_name_len : length of the debug configuration name string
+ * @dbg_cfg_name: debug configuration name string
+ */
+struct iwl_fw_ini_debug_info_tlv {
+ struct iwl_fw_ini_header header;
+ __le32 img_name_len;
+ u8 img_name[IWL_FW_INI_MAX_IMG_NAME_LEN];
+ __le32 dbg_cfg_name_len;
+ u8 dbg_cfg_name[IWL_FW_INI_MAX_DBG_CFG_NAME_LEN];
+} __packed; /* FW_DEBUG_TLV_INFO_API_S_VER_1 */
+
/**
* enum iwl_fw_ini_trigger_id
*
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/location.h b/drivers/net/wireless/intel/iwlwifi/fw/api/location.h
index 8d78b0e671c0..ec864c7b497f 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/location.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/location.h
@@ -937,8 +937,13 @@ struct iwl_ftm_responder_stats {
__le16 reserved;
} __packed; /* TOF_RESPONDER_STATISTICS_NTFY_S_VER_2 */
-#define IWL_CSI_CHUNK_CTL_NUM_MASK 0x3
-#define IWL_CSI_CHUNK_CTL_IDX_MASK 0xc
+#define IWL_CSI_MAX_EXPECTED_CHUNKS 16
+
+#define IWL_CSI_CHUNK_CTL_NUM_MASK_VER_1 0x0003
+#define IWL_CSI_CHUNK_CTL_IDX_MASK_VER_1 0x000c
+
+#define IWL_CSI_CHUNK_CTL_NUM_MASK_VER_2 0x00ff
+#define IWL_CSI_CHUNK_CTL_IDX_MASK_VER_2 0xff00
struct iwl_csi_chunk_notification {
__le32 token;
@@ -946,6 +951,6 @@ struct iwl_csi_chunk_notification {
__le16 ctl;
__le32 size;
u8 data[];
-} __packed; /* CSI_CHUNKS_HDR_NTFY_API_S_VER_1 */
+} __packed; /* CSI_CHUNKS_HDR_NTFY_API_S_VER_1/VER_2 */
#endif /* __iwl_fw_api_location_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h
index 01f003c6cff9..f195db398bed 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h
@@ -420,13 +420,25 @@ struct iwl_per_chain_offset_group {
} __packed; /* PER_CHAIN_LIMIT_OFFSET_GROUP_S_VER_1 */
/**
+ * struct iwl_geo_tx_power_profile_cmd_v1 - struct for GEO_TX_POWER_LIMIT cmd.
+ * @ops: operations, value from &enum iwl_geo_per_chain_offset_operation
+ * @table: offset profile per band.
+ */
+struct iwl_geo_tx_power_profiles_cmd_v1 {
+ __le32 ops;
+ struct iwl_per_chain_offset_group table[IWL_NUM_GEO_PROFILES];
+} __packed; /* GEO_TX_POWER_LIMIT_VER_1 */
+
+/**
* struct iwl_geo_tx_power_profile_cmd - struct for GEO_TX_POWER_LIMIT cmd.
* @ops: operations, value from &enum iwl_geo_per_chain_offset_operation
* @table: offset profile per band.
+ * @table_revision: BIOS table revision.
*/
struct iwl_geo_tx_power_profiles_cmd {
__le32 ops;
struct iwl_per_chain_offset_group table[IWL_NUM_GEO_PROFILES];
+ __le32 table_revision;
} __packed; /* GEO_TX_POWER_LIMIT */
/**
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
index 1a67a2a439ab..c4960f045415 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
@@ -750,6 +750,21 @@ struct iwl_scan_req_umac {
struct iwl_scan_umac_chan_param channel;
u8 data[];
} v8; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_8 */
+ struct {
+ u8 active_dwell[SCAN_TWO_LMACS];
+ u8 adwell_default_hb_n_aps;
+ u8 adwell_default_lb_n_aps;
+ u8 adwell_default_n_aps_social;
+ u8 general_flags2;
+ __le16 adwell_max_budget;
+ __le32 max_out_time[SCAN_TWO_LMACS];
+ __le32 suspend_time[SCAN_TWO_LMACS];
+ __le32 scan_priority;
+ u8 passive_dwell[SCAN_TWO_LMACS];
+ u8 num_of_fragments[SCAN_TWO_LMACS];
+ struct iwl_scan_umac_chan_param channel;
+ u8 data[];
+ } v9; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_9 */
};
} __packed;
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
index 5f52e40a2903..e411ac98290d 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
@@ -1059,7 +1059,7 @@ static int iwl_dump_ini_prph_iter(struct iwl_fw_runtime *fwrt,
u32 addr = le32_to_cpu(reg->start_addr[idx]) + le32_to_cpu(reg->offset);
int i;
- range->start_addr = cpu_to_le64(addr);
+ range->internal_base_addr = cpu_to_le32(addr);
range->range_data_size = reg->internal.range_data_size;
for (i = 0; i < le32_to_cpu(reg->internal.range_data_size); i += 4) {
prph_val = iwl_read_prph(fwrt->trans, addr + i);
@@ -1080,7 +1080,7 @@ static int iwl_dump_ini_csr_iter(struct iwl_fw_runtime *fwrt,
u32 addr = le32_to_cpu(reg->start_addr[idx]) + le32_to_cpu(reg->offset);
int i;
- range->start_addr = cpu_to_le64(addr);
+ range->internal_base_addr = cpu_to_le32(addr);
range->range_data_size = reg->internal.range_data_size;
for (i = 0; i < le32_to_cpu(reg->internal.range_data_size); i += 4)
*val++ = cpu_to_le32(iwl_trans_read32(fwrt->trans, addr + i));
@@ -1095,7 +1095,7 @@ static int iwl_dump_ini_dev_mem_iter(struct iwl_fw_runtime *fwrt,
struct iwl_fw_ini_error_dump_range *range = range_ptr;
u32 addr = le32_to_cpu(reg->start_addr[idx]) + le32_to_cpu(reg->offset);
- range->start_addr = cpu_to_le64(addr);
+ range->internal_base_addr = cpu_to_le32(addr);
range->range_data_size = reg->internal.range_data_size;
iwl_trans_read_mem_bytes(fwrt->trans, addr, range->data,
le32_to_cpu(reg->internal.range_data_size));
@@ -1111,7 +1111,7 @@ iwl_dump_ini_paging_gen2_iter(struct iwl_fw_runtime *fwrt,
struct iwl_fw_ini_error_dump_range *range = range_ptr;
u32 page_size = fwrt->trans->init_dram.paging[idx].size;
- range->start_addr = cpu_to_le64(idx);
+ range->page_num = cpu_to_le32(idx);
range->range_data_size = cpu_to_le32(page_size);
memcpy(range->data, fwrt->trans->init_dram.paging[idx].block,
page_size);
@@ -1131,7 +1131,7 @@ static int iwl_dump_ini_paging_iter(struct iwl_fw_runtime *fwrt,
dma_addr_t addr = fwrt->fw_paging_db[idx].fw_paging_phys;
u32 page_size = fwrt->fw_paging_db[idx].fw_paging_size;
- range->start_addr = cpu_to_le64(idx);
+ range->page_num = cpu_to_le32(idx);
range->range_data_size = cpu_to_le32(page_size);
dma_sync_single_for_cpu(fwrt->trans->dev, addr, page_size,
DMA_BIDIRECTIONAL);
@@ -1154,11 +1154,11 @@ iwl_dump_ini_mon_dram_iter(struct iwl_fw_runtime *fwrt,
if (start_addr == 0x5a5a5a5a)
return -EBUSY;
- range->start_addr = cpu_to_le64(start_addr);
- range->range_data_size = cpu_to_le32(fwrt->trans->fw_mon[idx].size);
+ range->dram_base_addr = cpu_to_le64(start_addr);
+ range->range_data_size = cpu_to_le32(fwrt->trans->dbg.fw_mon[idx].size);
- memcpy(range->data, fwrt->trans->fw_mon[idx].block,
- fwrt->trans->fw_mon[idx].size);
+ memcpy(range->data, fwrt->trans->dbg.fw_mon[idx].block,
+ fwrt->trans->dbg.fw_mon[idx].size);
return sizeof(*range) + le32_to_cpu(range->range_data_size);
}
@@ -1228,7 +1228,7 @@ static int iwl_dump_ini_txf_iter(struct iwl_fw_runtime *fwrt,
struct iwl_fw_ini_region_cfg *reg,
void *range_ptr, int idx)
{
- struct iwl_fw_ini_fifo_error_dump_range *range = range_ptr;
+ struct iwl_fw_ini_error_dump_range *range = range_ptr;
struct iwl_ini_txf_iter_data *iter;
struct iwl_fw_ini_error_dump_register *reg_dump = (void *)range->data;
u32 offs = le32_to_cpu(reg->offset), addr;
@@ -1246,8 +1246,8 @@ static int iwl_dump_ini_txf_iter(struct iwl_fw_runtime *fwrt,
iter = fwrt->dump.fifo_iter;
- range->fifo_num = cpu_to_le32(iter->fifo);
- range->num_of_registers = reg->fifos.num_of_registers;
+ range->fifo_hdr.fifo_num = cpu_to_le32(iter->fifo);
+ range->fifo_hdr.num_of_registers = reg->fifos.num_of_registers;
range->range_data_size = cpu_to_le32(iter->fifo_size + registers_size);
iwl_write_prph_no_grab(fwrt->trans, TXF_LARC_NUM + offs, iter->fifo);
@@ -1336,7 +1336,7 @@ static int iwl_dump_ini_rxf_iter(struct iwl_fw_runtime *fwrt,
struct iwl_fw_ini_region_cfg *reg,
void *range_ptr, int idx)
{
- struct iwl_fw_ini_fifo_error_dump_range *range = range_ptr;
+ struct iwl_fw_ini_error_dump_range *range = range_ptr;
struct iwl_ini_rxf_data rxf_data;
struct iwl_fw_ini_error_dump_register *reg_dump = (void *)range->data;
u32 offs = le32_to_cpu(reg->offset), addr;
@@ -1353,8 +1353,8 @@ static int iwl_dump_ini_rxf_iter(struct iwl_fw_runtime *fwrt,
if (!iwl_trans_grab_nic_access(fwrt->trans, &flags))
return -EBUSY;
- range->fifo_num = cpu_to_le32(rxf_data.fifo_num);
- range->num_of_registers = reg->fifos.num_of_registers;
+ range->fifo_hdr.fifo_num = cpu_to_le32(rxf_data.fifo_num);
+ range->fifo_hdr.num_of_registers = reg->fifos.num_of_registers;
range->range_data_size = cpu_to_le32(rxf_data.size + registers_size);
/*
@@ -1408,7 +1408,7 @@ static void *iwl_dump_ini_mem_fill_header(struct iwl_fw_runtime *fwrt,
{
struct iwl_fw_ini_error_dump *dump = data;
- dump->header.version = cpu_to_le32(IWL_INI_DUMP_MEM_VER);
+ dump->header.version = cpu_to_le32(IWL_INI_DUMP_VER);
return dump->ranges;
}
@@ -1433,7 +1433,7 @@ static void
iwl_trans_release_nic_access(fwrt->trans, &flags);
- data->header.version = cpu_to_le32(IWL_INI_DUMP_MONITOR_VER);
+ data->header.version = cpu_to_le32(IWL_INI_DUMP_VER);
data->write_ptr = cpu_to_le32(write_ptr & write_ptr_msk);
data->cycle_cnt = cpu_to_le32(cycle_cnt & cycle_cnt_msk);
@@ -1490,17 +1490,6 @@ static void
}
-static void *iwl_dump_ini_fifo_fill_header(struct iwl_fw_runtime *fwrt,
- struct iwl_fw_ini_region_cfg *reg,
- void *data)
-{
- struct iwl_fw_ini_fifo_error_dump *dump = data;
-
- dump->header.version = cpu_to_le32(IWL_INI_DUMP_FIFO_VER);
-
- return dump->ranges;
-}
-
static u32 iwl_dump_ini_mem_ranges(struct iwl_fw_runtime *fwrt,
struct iwl_fw_ini_region_cfg *reg)
{
@@ -1592,8 +1581,8 @@ static u32 iwl_dump_ini_mon_dram_get_size(struct iwl_fw_runtime *fwrt,
u32 size = sizeof(struct iwl_fw_ini_monitor_dump) +
sizeof(struct iwl_fw_ini_error_dump_range);
- if (fwrt->trans->num_blocks)
- size += fwrt->trans->fw_mon[0].size;
+ if (fwrt->trans->dbg.num_blocks)
+ size += fwrt->trans->dbg.fw_mon[0].size;
return size;
}
@@ -1613,8 +1602,9 @@ static u32 iwl_dump_ini_txf_get_size(struct iwl_fw_runtime *fwrt,
struct iwl_ini_txf_iter_data iter = { .init = true };
void *fifo_iter = fwrt->dump.fifo_iter;
u32 size = 0;
- u32 fifo_hdr = sizeof(struct iwl_fw_ini_fifo_error_dump_range) +
- le32_to_cpu(reg->fifos.num_of_registers) * sizeof(__le32) * 2;
+ u32 fifo_hdr = sizeof(struct iwl_fw_ini_error_dump_range) +
+ le32_to_cpu(reg->fifos.num_of_registers) *
+ sizeof(struct iwl_fw_ini_error_dump_register);
fwrt->dump.fifo_iter = &iter;
while (iwl_ini_txf_iter(fwrt, reg)) {
@@ -1624,7 +1614,7 @@ static u32 iwl_dump_ini_txf_get_size(struct iwl_fw_runtime *fwrt,
}
if (size)
- size += sizeof(struct iwl_fw_ini_fifo_error_dump);
+ size += sizeof(struct iwl_fw_ini_error_dump);
fwrt->dump.fifo_iter = fifo_iter;
@@ -1635,9 +1625,10 @@ static u32 iwl_dump_ini_rxf_get_size(struct iwl_fw_runtime *fwrt,
struct iwl_fw_ini_region_cfg *reg)
{
struct iwl_ini_rxf_data rx_data;
- u32 size = sizeof(struct iwl_fw_ini_fifo_error_dump) +
- sizeof(struct iwl_fw_ini_fifo_error_dump_range) +
- le32_to_cpu(reg->fifos.num_of_registers) * sizeof(__le32) * 2;
+ u32 size = sizeof(struct iwl_fw_ini_error_dump) +
+ sizeof(struct iwl_fw_ini_error_dump_range) +
+ le32_to_cpu(reg->fifos.num_of_registers) *
+ sizeof(struct iwl_fw_ini_error_dump_register);
if (reg->fifos.header_only)
return size;
@@ -1683,20 +1674,24 @@ iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt,
struct iwl_dump_ini_mem_ops *ops)
{
struct iwl_fw_ini_error_dump_header *header = (void *)(*data)->data;
- u32 num_of_ranges, i, type = le32_to_cpu(reg->region_type);
+ u32 num_of_ranges, i, type = le32_to_cpu(reg->region_type), size;
void *range;
if (WARN_ON(!ops || !ops->get_num_of_ranges || !ops->get_size ||
!ops->fill_mem_hdr || !ops->fill_range))
return;
+ size = ops->get_size(fwrt, reg);
+ if (!size)
+ return;
+
IWL_DEBUG_FW(fwrt, "WRT: collecting region: id=%d, type=%d\n",
le32_to_cpu(reg->region_id), type);
num_of_ranges = ops->get_num_of_ranges(fwrt, reg);
- (*data)->type = cpu_to_le32(type | INI_DUMP_BIT);
- (*data)->len = cpu_to_le32(ops->get_size(fwrt, reg));
+ (*data)->type = cpu_to_le32(type);
+ (*data)->len = cpu_to_le32(size);
header->region_id = reg->region_id;
header->num_of_ranges = cpu_to_le32(num_of_ranges);
@@ -1709,7 +1704,7 @@ iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt,
IWL_ERR(fwrt,
"WRT: failed to fill region header: id=%d, type=%d\n",
le32_to_cpu(reg->region_id), type);
- memset(*data, 0, le32_to_cpu((*data)->len));
+ memset(*data, 0, size);
return;
}
@@ -1720,7 +1715,7 @@ iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt,
IWL_ERR(fwrt,
"WRT: failed to dump region: id=%d, type=%d\n",
le32_to_cpu(reg->region_id), type);
- memset(*data, 0, le32_to_cpu((*data)->len));
+ memset(*data, 0, size);
return;
}
range = range + range_size;
@@ -1728,10 +1723,71 @@ iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt,
*data = iwl_fw_error_next_data(*data);
}
+static void iwl_dump_ini_info(struct iwl_fw_runtime *fwrt,
+ struct iwl_fw_ini_trigger *trigger,
+ struct iwl_fw_error_dump_data **data)
+{
+ struct iwl_fw_ini_dump_info *dump = (void *)(*data)->data;
+ u32 reg_ids_size = le32_to_cpu(trigger->num_regions) * sizeof(__le32);
+
+ (*data)->type = cpu_to_le32(IWL_INI_DUMP_INFO_TYPE);
+ (*data)->len = cpu_to_le32(sizeof(*dump) + reg_ids_size);
+
+ dump->version = cpu_to_le32(IWL_INI_DUMP_VER);
+ dump->trigger_id = trigger->trigger_id;
+ dump->is_external_cfg =
+ cpu_to_le32(fwrt->trans->dbg.external_ini_loaded);
+
+ dump->ver_type = cpu_to_le32(fwrt->dump.fw_ver.type);
+ dump->ver_subtype = cpu_to_le32(fwrt->dump.fw_ver.subtype);
+
+ dump->hw_step = cpu_to_le32(CSR_HW_REV_STEP(fwrt->trans->hw_rev));
+ dump->hw_type = cpu_to_le32(CSR_HW_REV_TYPE(fwrt->trans->hw_rev));
+
+ dump->rf_id_flavor =
+ cpu_to_le32(CSR_HW_RFID_FLAVOR(fwrt->trans->hw_rf_id));
+ dump->rf_id_dash = cpu_to_le32(CSR_HW_RFID_DASH(fwrt->trans->hw_rf_id));
+ dump->rf_id_step = cpu_to_le32(CSR_HW_RFID_STEP(fwrt->trans->hw_rf_id));
+ dump->rf_id_type = cpu_to_le32(CSR_HW_RFID_TYPE(fwrt->trans->hw_rf_id));
+
+ dump->lmac_major = cpu_to_le32(fwrt->dump.fw_ver.lmac_major);
+ dump->lmac_minor = cpu_to_le32(fwrt->dump.fw_ver.lmac_minor);
+ dump->umac_major = cpu_to_le32(fwrt->dump.fw_ver.umac_major);
+ dump->umac_minor = cpu_to_le32(fwrt->dump.fw_ver.umac_minor);
+
+ dump->build_tag_len = cpu_to_le32(sizeof(dump->build_tag));
+ memcpy(dump->build_tag, fwrt->fw->human_readable,
+ sizeof(dump->build_tag));
+
+ dump->img_name_len = cpu_to_le32(sizeof(dump->img_name));
+ memcpy(dump->img_name, fwrt->dump.img_name, sizeof(dump->img_name));
+
+ dump->internal_dbg_cfg_name_len =
+ cpu_to_le32(sizeof(dump->internal_dbg_cfg_name));
+ memcpy(dump->internal_dbg_cfg_name, fwrt->dump.internal_dbg_cfg_name,
+ sizeof(dump->internal_dbg_cfg_name));
+
+ dump->external_dbg_cfg_name_len =
+ cpu_to_le32(sizeof(dump->external_dbg_cfg_name));
+
+ /* dump info size is allocated in iwl_fw_ini_get_trigger_len.
+ * The driver allocates (sizeof(*dump) + reg_ids_size) so it is safe to
+ * use reg_ids_size
+ */
+ memcpy(dump->external_dbg_cfg_name, fwrt->dump.external_dbg_cfg_name,
+ sizeof(dump->external_dbg_cfg_name));
+
+ dump->regions_num = trigger->num_regions;
+ memcpy(dump->region_ids, trigger->data, reg_ids_size);
+
+ *data = iwl_fw_error_next_data(*data);
+}
+
static int iwl_fw_ini_get_trigger_len(struct iwl_fw_runtime *fwrt,
struct iwl_fw_ini_trigger *trigger)
{
- int i, size = 0, hdr_len = sizeof(struct iwl_fw_error_dump_data);
+ int i, ret_size = 0, hdr_len = sizeof(struct iwl_fw_error_dump_data);
+ u32 size;
if (!trigger || !trigger->num_regions)
return 0;
@@ -1763,32 +1819,40 @@ static int iwl_fw_ini_get_trigger_len(struct iwl_fw_runtime *fwrt,
case IWL_FW_INI_REGION_CSR:
case IWL_FW_INI_REGION_LMAC_ERROR_TABLE:
case IWL_FW_INI_REGION_UMAC_ERROR_TABLE:
- size += hdr_len + iwl_dump_ini_mem_get_size(fwrt, reg);
+ size = iwl_dump_ini_mem_get_size(fwrt, reg);
+ if (size)
+ ret_size += hdr_len + size;
break;
case IWL_FW_INI_REGION_TXF:
- size += hdr_len + iwl_dump_ini_txf_get_size(fwrt, reg);
+ size = iwl_dump_ini_txf_get_size(fwrt, reg);
+ if (size)
+ ret_size += hdr_len + size;
break;
case IWL_FW_INI_REGION_RXF:
- size += hdr_len + iwl_dump_ini_rxf_get_size(fwrt, reg);
+ size = iwl_dump_ini_rxf_get_size(fwrt, reg);
+ if (size)
+ ret_size += hdr_len + size;
break;
case IWL_FW_INI_REGION_PAGING:
- size += hdr_len;
- if (iwl_fw_dbg_is_paging_enabled(fwrt)) {
- size += iwl_dump_ini_paging_get_size(fwrt, reg);
- } else {
- size += iwl_dump_ini_paging_gen2_get_size(fwrt,
- reg);
- }
+ if (iwl_fw_dbg_is_paging_enabled(fwrt))
+ size = iwl_dump_ini_paging_get_size(fwrt, reg);
+ else
+ size = iwl_dump_ini_paging_gen2_get_size(fwrt,
+ reg);
+ if (size)
+ ret_size += hdr_len + size;
break;
case IWL_FW_INI_REGION_DRAM_BUFFER:
- if (!fwrt->trans->num_blocks)
+ if (!fwrt->trans->dbg.num_blocks)
break;
- size += hdr_len +
- iwl_dump_ini_mon_dram_get_size(fwrt, reg);
+ size = iwl_dump_ini_mon_dram_get_size(fwrt, reg);
+ if (size)
+ ret_size += hdr_len + size;
break;
case IWL_FW_INI_REGION_INTERNAL_BUFFER:
- size += hdr_len +
- iwl_dump_ini_mon_smem_get_size(fwrt, reg);
+ size = iwl_dump_ini_mon_smem_get_size(fwrt, reg);
+ if (size)
+ ret_size += hdr_len + size;
break;
case IWL_FW_INI_REGION_DRAM_IMR:
/* Undefined yet */
@@ -1796,7 +1860,13 @@ static int iwl_fw_ini_get_trigger_len(struct iwl_fw_runtime *fwrt,
break;
}
}
- return size;
+
+ /* add dump info size */
+ if (ret_size)
+ ret_size += hdr_len + sizeof(struct iwl_fw_ini_dump_info) +
+ (le32_to_cpu(trigger->num_regions) * sizeof(__le32));
+
+ return ret_size;
}
static void iwl_fw_ini_dump_trigger(struct iwl_fw_runtime *fwrt,
@@ -1805,6 +1875,8 @@ static void iwl_fw_ini_dump_trigger(struct iwl_fw_runtime *fwrt,
{
int i, num = le32_to_cpu(trigger->num_regions);
+ iwl_dump_ini_info(fwrt, trigger, data);
+
for (i = 0; i < num; i++) {
u32 reg_id = le32_to_cpu(trigger->data[i]);
struct iwl_fw_ini_region_cfg *reg;
@@ -1879,7 +1951,7 @@ static void iwl_fw_ini_dump_trigger(struct iwl_fw_runtime *fwrt,
fwrt->dump.fifo_iter = &iter;
ops.get_num_of_ranges = iwl_dump_ini_txf_ranges;
ops.get_size = iwl_dump_ini_txf_get_size;
- ops.fill_mem_hdr = iwl_dump_ini_fifo_fill_header;
+ ops.fill_mem_hdr = iwl_dump_ini_mem_fill_header;
ops.fill_range = iwl_dump_ini_txf_iter;
iwl_dump_ini_mem(fwrt, data, reg, &ops);
fwrt->dump.fifo_iter = fifo_iter;
@@ -1888,7 +1960,7 @@ static void iwl_fw_ini_dump_trigger(struct iwl_fw_runtime *fwrt,
case IWL_FW_INI_REGION_RXF:
ops.get_num_of_ranges = iwl_dump_ini_rxf_ranges;
ops.get_size = iwl_dump_ini_rxf_get_size;
- ops.fill_mem_hdr = iwl_dump_ini_fifo_fill_header;
+ ops.fill_mem_hdr = iwl_dump_ini_mem_fill_header;
ops.fill_range = iwl_dump_ini_rxf_iter;
iwl_dump_ini_mem(fwrt, data, reg, &ops);
break;
@@ -1908,18 +1980,18 @@ static void iwl_fw_ini_dump_trigger(struct iwl_fw_runtime *fwrt,
}
static struct iwl_fw_error_dump_file *
-iwl_fw_error_ini_dump_file(struct iwl_fw_runtime *fwrt)
+iwl_fw_error_ini_dump_file(struct iwl_fw_runtime *fwrt,
+ enum iwl_fw_ini_trigger_id trig_id)
{
int size;
struct iwl_fw_error_dump_data *dump_data;
struct iwl_fw_error_dump_file *dump_file;
struct iwl_fw_ini_trigger *trigger;
- enum iwl_fw_ini_trigger_id id = fwrt->dump.ini_trig_id;
- if (!iwl_fw_ini_trigger_on(fwrt, id))
+ if (!iwl_fw_ini_trigger_on(fwrt, trig_id))
return NULL;
- trigger = fwrt->dump.active_trigs[id].trig;
+ trigger = fwrt->dump.active_trigs[trig_id].trig;
size = iwl_fw_ini_get_trigger_len(fwrt, trigger);
if (!size)
@@ -1931,7 +2003,7 @@ iwl_fw_error_ini_dump_file(struct iwl_fw_runtime *fwrt)
if (!dump_file)
return NULL;
- dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER);
+ dump_file->barker = cpu_to_le32(IWL_FW_INI_ERROR_DUMP_BARKER);
dump_data = (void *)dump_file->data;
dump_file->file_len = cpu_to_le32(size);
@@ -1952,7 +2024,7 @@ static void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
if (!dump_file)
goto out;
- if (!fwrt->trans->ini_valid && fwrt->dump.monitor_only)
+ if (fwrt->dump.monitor_only)
dump_mask &= IWL_FW_ERROR_DUMP_FW_MONITOR;
fw_error_dump.trans_ptr = iwl_trans_dump_data(fwrt->trans, dump_mask);
@@ -1984,16 +2056,16 @@ static void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
out:
iwl_fw_free_dump_desc(fwrt);
- clear_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status);
}
-static void iwl_fw_error_ini_dump(struct iwl_fw_runtime *fwrt)
+static void iwl_fw_error_ini_dump(struct iwl_fw_runtime *fwrt, u8 wk_idx)
{
+ enum iwl_fw_ini_trigger_id trig_id = fwrt->dump.wks[wk_idx].ini_trig_id;
struct iwl_fw_error_dump_file *dump_file;
struct scatterlist *sg_dump_data;
u32 file_len;
- dump_file = iwl_fw_error_ini_dump_file(fwrt);
+ dump_file = iwl_fw_error_ini_dump_file(fwrt, trig_id);
if (!dump_file)
goto out;
@@ -2008,8 +2080,7 @@ static void iwl_fw_error_ini_dump(struct iwl_fw_runtime *fwrt)
}
vfree(dump_file);
out:
- fwrt->dump.ini_trig_id = IWL_FW_TRIGGER_ID_INVALID;
- clear_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status);
+ fwrt->dump.wks[wk_idx].ini_trig_id = IWL_FW_TRIGGER_ID_INVALID;
}
const struct iwl_fw_dump_desc iwl_dump_desc_assert = {
@@ -2027,7 +2098,7 @@ int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt,
u32 trig_type = le32_to_cpu(desc->trig_desc.type);
int ret;
- if (fwrt->trans->ini_valid) {
+ if (fwrt->trans->dbg.ini_valid) {
ret = iwl_fw_dbg_ini_collect(fwrt, trig_type);
if (!ret)
iwl_fw_free_dump_desc(fwrt);
@@ -2035,7 +2106,10 @@ int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt,
return ret;
}
- if (test_and_set_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status))
+ /* use wks[0] since dump flow prior to ini does not need to support
+ * consecutive triggers collection
+ */
+ if (test_and_set_bit(fwrt->dump.wks[0].idx, &fwrt->dump.active_wks))
return -EBUSY;
if (WARN_ON(fwrt->dump.desc))
@@ -2047,7 +2121,7 @@ int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt,
fwrt->dump.desc = desc;
fwrt->dump.monitor_only = monitor_only;
- schedule_delayed_work(&fwrt->dump.wk, usecs_to_jiffies(delay));
+ schedule_delayed_work(&fwrt->dump.wks[0].wk, usecs_to_jiffies(delay));
return 0;
}
@@ -2057,9 +2131,12 @@ int iwl_fw_dbg_error_collect(struct iwl_fw_runtime *fwrt,
enum iwl_fw_dbg_trigger trig_type)
{
int ret;
- struct iwl_fw_dump_desc *iwl_dump_error_desc =
- kmalloc(sizeof(*iwl_dump_error_desc), GFP_KERNEL);
+ struct iwl_fw_dump_desc *iwl_dump_error_desc;
+
+ if (!test_bit(STATUS_DEVICE_ENABLED, &fwrt->trans->status))
+ return -EIO;
+ iwl_dump_error_desc = kmalloc(sizeof(*iwl_dump_error_desc), GFP_KERNEL);
if (!iwl_dump_error_desc)
return -ENOMEM;
@@ -2123,13 +2200,11 @@ int _iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt,
{
struct iwl_fw_ini_active_triggers *active;
u32 occur, delay;
+ unsigned long idx;
if (WARN_ON(!iwl_fw_ini_trigger_on(fwrt, id)))
return -EINVAL;
- if (test_and_set_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status))
- return -EBUSY;
-
if (!iwl_fw_ini_trigger_on(fwrt, id)) {
IWL_WARN(fwrt, "WRT: Trigger %d is not active, aborting dump\n",
id);
@@ -2150,14 +2225,24 @@ int _iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt,
return 0;
}
- if (test_and_set_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status))
+ /* Check there is an available worker.
+ * ffz return value is undefined if no zero exists,
+ * so check against ~0UL first.
+ */
+ if (fwrt->dump.active_wks == ~0UL)
+ return -EBUSY;
+
+ idx = ffz(fwrt->dump.active_wks);
+
+ if (idx >= IWL_FW_RUNTIME_DUMP_WK_NUM ||
+ test_and_set_bit(fwrt->dump.wks[idx].idx, &fwrt->dump.active_wks))
return -EBUSY;
- fwrt->dump.ini_trig_id = id;
+ fwrt->dump.wks[idx].ini_trig_id = id;
IWL_WARN(fwrt, "WRT: collecting data: ini trigger %d fired.\n", id);
- schedule_delayed_work(&fwrt->dump.wk, usecs_to_jiffies(delay));
+ schedule_delayed_work(&fwrt->dump.wks[idx].wk, usecs_to_jiffies(delay));
return 0;
}
@@ -2191,9 +2276,6 @@ int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt,
int ret, len = 0;
char buf[64];
- if (fwrt->trans->ini_valid)
- return 0;
-
if (fmt) {
va_list ap;
@@ -2270,56 +2352,57 @@ IWL_EXPORT_SYMBOL(iwl_fw_start_dbg_conf);
/* this function assumes dump_start was called beforehand and dump_end will be
* called afterwards
*/
-void iwl_fw_dbg_collect_sync(struct iwl_fw_runtime *fwrt)
+static void iwl_fw_dbg_collect_sync(struct iwl_fw_runtime *fwrt, u8 wk_idx)
{
struct iwl_fw_dbg_params params = {0};
- if (!test_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status))
+ if (!test_bit(wk_idx, &fwrt->dump.active_wks))
return;
if (fwrt->ops && fwrt->ops->fw_running &&
!fwrt->ops->fw_running(fwrt->ops_ctx)) {
IWL_ERR(fwrt, "Firmware not running - cannot dump error\n");
iwl_fw_free_dump_desc(fwrt);
- clear_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status);
- return;
+ goto out;
}
/* there's no point in fw dump if the bus is dead */
if (test_bit(STATUS_TRANS_DEAD, &fwrt->trans->status)) {
IWL_ERR(fwrt, "Skip fw error dump since bus is dead\n");
- return;
+ goto out;
}
- iwl_fw_dbg_stop_recording(fwrt, &params);
+ iwl_fw_dbg_stop_recording(fwrt->trans, &params);
IWL_DEBUG_FW_INFO(fwrt, "WRT: data collection start\n");
- if (fwrt->trans->ini_valid)
- iwl_fw_error_ini_dump(fwrt);
+ if (fwrt->trans->dbg.ini_valid)
+ iwl_fw_error_ini_dump(fwrt, wk_idx);
else
iwl_fw_error_dump(fwrt);
IWL_DEBUG_FW_INFO(fwrt, "WRT: data collection done\n");
- /* start recording again if the firmware is not crashed */
- if (!test_bit(STATUS_FW_ERROR, &fwrt->trans->status) &&
- fwrt->fw->dbg.dest_tlv) {
- /* wait before we collect the data till the DBGC stop */
- udelay(500);
- iwl_fw_dbg_restart_recording(fwrt, &params);
- }
+ iwl_fw_dbg_restart_recording(fwrt, &params);
+
+out:
+ clear_bit(wk_idx, &fwrt->dump.active_wks);
}
-IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect_sync);
void iwl_fw_error_dump_wk(struct work_struct *work)
{
- struct iwl_fw_runtime *fwrt =
- container_of(work, struct iwl_fw_runtime, dump.wk.work);
+ struct iwl_fw_runtime *fwrt;
+ typeof(fwrt->dump.wks[0]) *wks;
+
+ wks = container_of(work, typeof(fwrt->dump.wks[0]), wk.work);
+ fwrt = container_of(wks, struct iwl_fw_runtime, dump.wks[wks->idx]);
+ /* assumes the op mode mutex is locked in dump_start since
+ * iwl_fw_dbg_collect_sync can't run in parallel
+ */
if (fwrt->ops && fwrt->ops->dump_start &&
fwrt->ops->dump_start(fwrt->ops_ctx))
return;
- iwl_fw_dbg_collect_sync(fwrt);
+ iwl_fw_dbg_collect_sync(fwrt, wks->idx);
if (fwrt->ops && fwrt->ops->dump_end)
fwrt->ops->dump_end(fwrt->ops_ctx);
@@ -2349,6 +2432,38 @@ void iwl_fw_dbg_read_d3_debug_data(struct iwl_fw_runtime *fwrt)
}
IWL_EXPORT_SYMBOL(iwl_fw_dbg_read_d3_debug_data);
+static void iwl_fw_dbg_info_apply(struct iwl_fw_runtime *fwrt,
+ struct iwl_fw_ini_debug_info_tlv *dbg_info,
+ bool ext, enum iwl_fw_ini_apply_point pnt)
+{
+ u32 img_name_len = le32_to_cpu(dbg_info->img_name_len);
+ u32 dbg_cfg_name_len = le32_to_cpu(dbg_info->dbg_cfg_name_len);
+ const char err_str[] =
+ "WRT: ext=%d. Invalid %s name length %d, expected %d\n";
+
+ if (img_name_len != IWL_FW_INI_MAX_IMG_NAME_LEN) {
+ IWL_WARN(fwrt, err_str, ext, "image", img_name_len,
+ IWL_FW_INI_MAX_IMG_NAME_LEN);
+ return;
+ }
+
+ if (dbg_cfg_name_len != IWL_FW_INI_MAX_DBG_CFG_NAME_LEN) {
+ IWL_WARN(fwrt, err_str, ext, "debug cfg", dbg_cfg_name_len,
+ IWL_FW_INI_MAX_DBG_CFG_NAME_LEN);
+ return;
+ }
+
+ if (ext) {
+ memcpy(fwrt->dump.external_dbg_cfg_name, dbg_info->dbg_cfg_name,
+ sizeof(fwrt->dump.external_dbg_cfg_name));
+ } else {
+ memcpy(fwrt->dump.img_name, dbg_info->img_name,
+ sizeof(fwrt->dump.img_name));
+ memcpy(fwrt->dump.internal_dbg_cfg_name, dbg_info->dbg_cfg_name,
+ sizeof(fwrt->dump.internal_dbg_cfg_name));
+ }
+}
+
static void
iwl_fw_dbg_buffer_allocation(struct iwl_fw_runtime *fwrt, u32 size)
{
@@ -2356,7 +2471,8 @@ iwl_fw_dbg_buffer_allocation(struct iwl_fw_runtime *fwrt, u32 size)
void *virtual_addr = NULL;
dma_addr_t phys_addr;
- if (WARN_ON_ONCE(trans->num_blocks == ARRAY_SIZE(trans->fw_mon)))
+ if (WARN_ON_ONCE(trans->dbg.num_blocks ==
+ ARRAY_SIZE(trans->dbg.fw_mon)))
return;
virtual_addr =
@@ -2370,12 +2486,12 @@ iwl_fw_dbg_buffer_allocation(struct iwl_fw_runtime *fwrt, u32 size)
IWL_DEBUG_FW(trans,
"Allocated DRAM buffer[%d], size=0x%x\n",
- trans->num_blocks, size);
+ trans->dbg.num_blocks, size);
- trans->fw_mon[trans->num_blocks].block = virtual_addr;
- trans->fw_mon[trans->num_blocks].physical = phys_addr;
- trans->fw_mon[trans->num_blocks].size = size;
- trans->num_blocks++;
+ trans->dbg.fw_mon[trans->dbg.num_blocks].block = virtual_addr;
+ trans->dbg.fw_mon[trans->dbg.num_blocks].physical = phys_addr;
+ trans->dbg.fw_mon[trans->dbg.num_blocks].size = size;
+ trans->dbg.num_blocks++;
}
static void iwl_fw_dbg_buffer_apply(struct iwl_fw_runtime *fwrt,
@@ -2393,20 +2509,26 @@ static void iwl_fw_dbg_buffer_apply(struct iwl_fw_runtime *fwrt,
.data[0] = &ldbg_cmd,
.len[0] = sizeof(ldbg_cmd),
};
- int block_idx = trans->num_blocks;
+ int block_idx = trans->dbg.num_blocks;
u32 buf_location = le32_to_cpu(alloc->tlv.buffer_location);
+ if (fwrt->trans->dbg.ini_dest == IWL_FW_INI_LOCATION_INVALID)
+ fwrt->trans->dbg.ini_dest = buf_location;
+
+ if (buf_location != fwrt->trans->dbg.ini_dest) {
+ WARN(fwrt,
+ "WRT: attempt to override buffer location on apply point %d\n",
+ pnt);
+
+ return;
+ }
+
if (buf_location == IWL_FW_INI_LOCATION_SRAM_PATH) {
- if (!WARN(pnt != IWL_FW_INI_APPLY_EARLY,
- "WRT: Invalid apply point %d for SMEM buffer allocation, aborting\n",
- pnt)) {
- IWL_DEBUG_FW(trans,
- "WRT: applying SMEM buffer destination\n");
-
- /* set sram monitor by enabling bit 7 */
- iwl_set_bit(fwrt->trans, CSR_HW_IF_CONFIG_REG,
- CSR_HW_IF_CONFIG_REG_BIT_MONITOR_SRAM);
- }
+ IWL_DEBUG_FW(trans, "WRT: applying SMEM buffer destination\n");
+ /* set sram monitor by enabling bit 7 */
+ iwl_set_bit(fwrt->trans, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_MONITOR_SRAM);
+
return;
}
@@ -2416,13 +2538,13 @@ static void iwl_fw_dbg_buffer_apply(struct iwl_fw_runtime *fwrt,
if (!alloc->is_alloc) {
iwl_fw_dbg_buffer_allocation(fwrt,
le32_to_cpu(alloc->tlv.size));
- if (block_idx == trans->num_blocks)
+ if (block_idx == trans->dbg.num_blocks)
return;
alloc->is_alloc = 1;
}
/* First block is assigned via registers / context info */
- if (trans->num_blocks == 1)
+ if (trans->dbg.num_blocks == 1)
return;
IWL_DEBUG_FW(trans,
@@ -2430,7 +2552,7 @@ static void iwl_fw_dbg_buffer_apply(struct iwl_fw_runtime *fwrt,
cmd->num_frags = cpu_to_le32(1);
cmd->fragments[0].address =
- cpu_to_le64(trans->fw_mon[block_idx].physical);
+ cpu_to_le64(trans->dbg.fw_mon[block_idx].physical);
cmd->fragments[0].size = alloc->tlv.size;
cmd->allocation_id = alloc->tlv.allocation_id;
cmd->buffer_location = alloc->tlv.buffer_location;
@@ -2653,20 +2775,30 @@ static void _iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
struct iwl_ucode_tlv *tlv = iter;
void *ini_tlv = (void *)tlv->data;
u32 type = le32_to_cpu(tlv->type);
+ const char invalid_ap_str[] =
+ "WRT: ext=%d. Invalid apply point %d for %s\n";
switch (type) {
+ case IWL_UCODE_TLV_TYPE_DEBUG_INFO:
+ iwl_fw_dbg_info_apply(fwrt, ini_tlv, ext, pnt);
+ break;
case IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION: {
struct iwl_fw_ini_allocation_data *buf_alloc = ini_tlv;
+ if (pnt != IWL_FW_INI_APPLY_EARLY) {
+ IWL_ERR(fwrt, invalid_ap_str, ext, pnt,
+ "buffer allocation");
+ goto next;
+ }
+
iwl_fw_dbg_buffer_apply(fwrt, ini_tlv, pnt);
iter += sizeof(buf_alloc->is_alloc);
break;
}
case IWL_UCODE_TLV_TYPE_HCMD:
if (pnt < IWL_FW_INI_APPLY_AFTER_ALIVE) {
- IWL_ERR(fwrt,
- "WRT: ext=%d. Invalid apply point %d for host command\n",
- ext, pnt);
+ IWL_ERR(fwrt, invalid_ap_str, ext, pnt,
+ "host command");
goto next;
}
iwl_fw_dbg_send_hcmd(fwrt, tlv, ext);
@@ -2690,34 +2822,51 @@ next:
}
}
+static void iwl_fw_dbg_ini_reset_cfg(struct iwl_fw_runtime *fwrt)
+{
+ int i;
+
+ for (i = 0; i < IWL_FW_INI_MAX_REGION_ID; i++)
+ fwrt->dump.active_regs[i] = NULL;
+
+ /* disable the triggers, used in recovery flow */
+ for (i = 0; i < IWL_FW_TRIGGER_ID_NUM; i++)
+ fwrt->dump.active_trigs[i].active = false;
+
+ memset(fwrt->dump.img_name, 0,
+ sizeof(fwrt->dump.img_name));
+ memset(fwrt->dump.internal_dbg_cfg_name, 0,
+ sizeof(fwrt->dump.internal_dbg_cfg_name));
+ memset(fwrt->dump.external_dbg_cfg_name, 0,
+ sizeof(fwrt->dump.external_dbg_cfg_name));
+
+ fwrt->trans->dbg.ini_dest = IWL_FW_INI_LOCATION_INVALID;
+}
+
void iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
enum iwl_fw_ini_apply_point apply_point)
{
- void *data = &fwrt->trans->apply_points[apply_point];
- int i;
+ void *data = &fwrt->trans->dbg.apply_points[apply_point];
IWL_DEBUG_FW(fwrt, "WRT: enabling apply point %d\n", apply_point);
- if (apply_point == IWL_FW_INI_APPLY_EARLY) {
- for (i = 0; i < IWL_FW_INI_MAX_REGION_ID; i++)
- fwrt->dump.active_regs[i] = NULL;
-
- /* disable the triggers, used in recovery flow */
- for (i = 0; i < IWL_FW_TRIGGER_ID_NUM; i++)
- fwrt->dump.active_trigs[i].active = false;
- }
+ if (apply_point == IWL_FW_INI_APPLY_EARLY)
+ iwl_fw_dbg_ini_reset_cfg(fwrt);
_iwl_fw_dbg_apply_point(fwrt, data, apply_point, false);
- data = &fwrt->trans->apply_points_ext[apply_point];
+ data = &fwrt->trans->dbg.apply_points_ext[apply_point];
_iwl_fw_dbg_apply_point(fwrt, data, apply_point, true);
}
IWL_EXPORT_SYMBOL(iwl_fw_dbg_apply_point);
void iwl_fwrt_stop_device(struct iwl_fw_runtime *fwrt)
{
+ int i;
+
del_timer(&fwrt->dump.periodic_trig);
- iwl_fw_dbg_collect_sync(fwrt);
+ for (i = 0; i < IWL_FW_RUNTIME_DUMP_WK_NUM; i++)
+ iwl_fw_dbg_collect_sync(fwrt, i);
iwl_trans_stop_device(fwrt->trans);
}
@@ -2747,3 +2896,42 @@ void iwl_fw_dbg_periodic_trig_handler(struct timer_list *t)
jiffies + msecs_to_jiffies(collect_interval));
}
}
+
+#define FSEQ_REG(x) { .addr = (x), .str = #x, }
+
+void iwl_fw_error_print_fseq_regs(struct iwl_fw_runtime *fwrt)
+{
+ struct iwl_trans *trans = fwrt->trans;
+ unsigned long flags;
+ int i;
+ struct {
+ u32 addr;
+ const char *str;
+ } fseq_regs[] = {
+ FSEQ_REG(FSEQ_ERROR_CODE),
+ FSEQ_REG(FSEQ_TOP_INIT_VERSION),
+ FSEQ_REG(FSEQ_CNVIO_INIT_VERSION),
+ FSEQ_REG(FSEQ_OTP_VERSION),
+ FSEQ_REG(FSEQ_TOP_CONTENT_VERSION),
+ FSEQ_REG(FSEQ_ALIVE_TOKEN),
+ FSEQ_REG(FSEQ_CNVI_ID),
+ FSEQ_REG(FSEQ_CNVR_ID),
+ FSEQ_REG(CNVI_AUX_MISC_CHIP),
+ FSEQ_REG(CNVR_AUX_MISC_CHIP),
+ FSEQ_REG(CNVR_SCU_SD_REGS_SD_REG_DIG_DCDC_VTRIM),
+ FSEQ_REG(CNVR_SCU_SD_REGS_SD_REG_ACTIVE_VDIG_MIRROR),
+ };
+
+ if (!iwl_trans_grab_nic_access(trans, &flags))
+ return;
+
+ IWL_ERR(fwrt, "Fseq Registers:\n");
+
+ for (i = 0; i < ARRAY_SIZE(fseq_regs); i++)
+ IWL_ERR(fwrt, "0x%08X | %s\n",
+ iwl_read_prph_no_grab(trans, fseq_regs[i].addr),
+ fseq_regs[i].str);
+
+ iwl_trans_release_nic_access(trans, &flags);
+}
+IWL_EXPORT_SYMBOL(iwl_fw_error_print_fseq_regs);
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h
index 2a9e560a906b..a8459ac71b2c 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h
@@ -73,6 +73,7 @@
#include "error-dump.h"
#include "api/commands.h"
#include "api/dbg-tlv.h"
+#include "api/alive.h"
/**
* struct iwl_fw_dump_desc - describes the dump
@@ -201,7 +202,7 @@ _iwl_fw_dbg_trigger_on(struct iwl_fw_runtime *fwrt,
{
struct iwl_fw_dbg_trigger_tlv *trig;
- if (fwrt->trans->ini_valid)
+ if (fwrt->trans->dbg.ini_valid)
return NULL;
if (!iwl_fw_dbg_trigger_enabled(fwrt->fw, id))
@@ -228,7 +229,7 @@ iwl_fw_ini_trigger_on(struct iwl_fw_runtime *fwrt,
struct iwl_fw_ini_trigger *trig;
u32 usec;
- if (!fwrt->trans->ini_valid || id == IWL_FW_TRIGGER_ID_INVALID ||
+ if (!fwrt->trans->dbg.ini_valid || id == IWL_FW_TRIGGER_ID_INVALID ||
id >= IWL_FW_TRIGGER_ID_NUM || !fwrt->dump.active_trigs[id].active)
return false;
@@ -262,23 +263,6 @@ _iwl_fw_dbg_trigger_simple_stop(struct iwl_fw_runtime *fwrt,
iwl_fw_dbg_get_trigger((fwrt)->fw,\
(trig)))
-static inline int
-iwl_fw_dbg_start_stop_hcmd(struct iwl_fw_runtime *fwrt, bool start)
-{
- struct iwl_ldbg_config_cmd cmd = {
- .type = start ? cpu_to_le32(START_DEBUG_RECORDING) :
- cpu_to_le32(STOP_DEBUG_RECORDING),
- };
- struct iwl_host_cmd hcmd = {
- .id = LDBG_CONFIG_CMD,
- .flags = CMD_ASYNC,
- .data[0] = &cmd,
- .len[0] = sizeof(cmd),
- };
-
- return iwl_trans_send_cmd(fwrt->trans, &hcmd);
-}
-
static inline void
_iwl_fw_dbg_stop_recording(struct iwl_trans *trans,
struct iwl_fw_dbg_params *params)
@@ -294,21 +278,35 @@ _iwl_fw_dbg_stop_recording(struct iwl_trans *trans,
}
iwl_write_umac_prph(trans, DBGC_IN_SAMPLE, 0);
- udelay(100);
+ /* wait for the DBGC to finish writing the internal buffer to DRAM to
+ * avoid halting the HW while writing
+ */
+ usleep_range(700, 1000);
iwl_write_umac_prph(trans, DBGC_OUT_CTRL, 0);
#ifdef CONFIG_IWLWIFI_DEBUGFS
- trans->dbg_rec_on = false;
+ trans->dbg.rec_on = false;
#endif
}
static inline void
-iwl_fw_dbg_stop_recording(struct iwl_fw_runtime *fwrt,
+iwl_fw_dbg_stop_recording(struct iwl_trans *trans,
struct iwl_fw_dbg_params *params)
{
- if (fwrt->trans->cfg->device_family < IWL_DEVICE_FAMILY_22560)
- _iwl_fw_dbg_stop_recording(fwrt->trans, params);
- else
- iwl_fw_dbg_start_stop_hcmd(fwrt, false);
+ /* if the FW crashed or not debug monitor cfg was given, there is
+ * no point in stopping
+ */
+ if (test_bit(STATUS_FW_ERROR, &trans->status) ||
+ (!trans->dbg.dest_tlv &&
+ trans->dbg.ini_dest == IWL_FW_INI_LOCATION_INVALID))
+ return;
+
+ if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560) {
+ IWL_ERR(trans,
+ "WRT: unsupported device family %d for debug stop recording\n",
+ trans->cfg->device_family);
+ return;
+ }
+ _iwl_fw_dbg_stop_recording(trans, params);
}
static inline void
@@ -324,7 +322,6 @@ _iwl_fw_dbg_restart_recording(struct iwl_trans *trans,
iwl_set_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x1);
} else {
iwl_write_umac_prph(trans, DBGC_IN_SAMPLE, params->in_sample);
- udelay(100);
iwl_write_umac_prph(trans, DBGC_OUT_CTRL, params->out_ctrl);
}
}
@@ -332,8 +329,10 @@ _iwl_fw_dbg_restart_recording(struct iwl_trans *trans,
#ifdef CONFIG_IWLWIFI_DEBUGFS
static inline void iwl_fw_set_dbg_rec_on(struct iwl_fw_runtime *fwrt)
{
- if (fwrt->fw->dbg.dest_tlv && fwrt->cur_fw_img == IWL_UCODE_REGULAR)
- fwrt->trans->dbg_rec_on = true;
+ if (fwrt->cur_fw_img == IWL_UCODE_REGULAR &&
+ (fwrt->fw->dbg.dest_tlv ||
+ fwrt->trans->dbg.ini_dest != IWL_FW_INI_LOCATION_INVALID))
+ fwrt->trans->dbg.rec_on = true;
}
#endif
@@ -341,10 +340,21 @@ static inline void
iwl_fw_dbg_restart_recording(struct iwl_fw_runtime *fwrt,
struct iwl_fw_dbg_params *params)
{
- if (fwrt->trans->cfg->device_family < IWL_DEVICE_FAMILY_22560)
- _iwl_fw_dbg_restart_recording(fwrt->trans, params);
- else
- iwl_fw_dbg_start_stop_hcmd(fwrt, true);
+ /* if the FW crashed or not debug monitor cfg was given, there is
+ * no point in restarting
+ */
+ if (test_bit(STATUS_FW_ERROR, &fwrt->trans->status) ||
+ (!fwrt->trans->dbg.dest_tlv &&
+ fwrt->trans->dbg.ini_dest == IWL_FW_INI_LOCATION_INVALID))
+ return;
+
+ if (fwrt->trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560) {
+ IWL_ERR(fwrt,
+ "WRT: unsupported device family %d for debug restart recording\n",
+ fwrt->trans->cfg->device_family);
+ return;
+ }
+ _iwl_fw_dbg_restart_recording(fwrt->trans, params);
#ifdef CONFIG_IWLWIFI_DEBUGFS
iwl_fw_set_dbg_rec_on(fwrt);
#endif
@@ -359,7 +369,7 @@ void iwl_fw_error_dump_wk(struct work_struct *work);
static inline bool iwl_fw_dbg_type_on(struct iwl_fw_runtime *fwrt, u32 type)
{
- return (fwrt->fw->dbg.dump_mask & BIT(type) || fwrt->trans->ini_valid);
+ return (fwrt->fw->dbg.dump_mask & BIT(type));
}
static inline bool iwl_fw_dbg_is_d3_debug_enabled(struct iwl_fw_runtime *fwrt)
@@ -383,16 +393,26 @@ static inline bool iwl_fw_dbg_is_paging_enabled(struct iwl_fw_runtime *fwrt)
void iwl_fw_dbg_read_d3_debug_data(struct iwl_fw_runtime *fwrt);
-static inline void iwl_fw_flush_dump(struct iwl_fw_runtime *fwrt)
+static inline void iwl_fw_flush_dumps(struct iwl_fw_runtime *fwrt)
{
+ int i;
+
del_timer(&fwrt->dump.periodic_trig);
- flush_delayed_work(&fwrt->dump.wk);
+ for (i = 0; i < IWL_FW_RUNTIME_DUMP_WK_NUM; i++) {
+ flush_delayed_work(&fwrt->dump.wks[i].wk);
+ fwrt->dump.wks[i].ini_trig_id = IWL_FW_TRIGGER_ID_INVALID;
+ }
}
-static inline void iwl_fw_cancel_dump(struct iwl_fw_runtime *fwrt)
+static inline void iwl_fw_cancel_dumps(struct iwl_fw_runtime *fwrt)
{
+ int i;
+
del_timer(&fwrt->dump.periodic_trig);
- cancel_delayed_work_sync(&fwrt->dump.wk);
+ for (i = 0; i < IWL_FW_RUNTIME_DUMP_WK_NUM; i++) {
+ cancel_delayed_work_sync(&fwrt->dump.wks[i].wk);
+ fwrt->dump.wks[i].ini_trig_id = IWL_FW_TRIGGER_ID_INVALID;
+ }
}
#ifdef CONFIG_IWLWIFI_DEBUGFS
@@ -431,7 +451,6 @@ static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt) {}
#endif /* CONFIG_IWLWIFI_DEBUGFS */
-void iwl_fw_dbg_collect_sync(struct iwl_fw_runtime *fwrt);
void iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
enum iwl_fw_ini_apply_point apply_point);
@@ -440,35 +459,51 @@ void iwl_fwrt_stop_device(struct iwl_fw_runtime *fwrt);
static inline void iwl_fw_lmac1_set_alive_err_table(struct iwl_trans *trans,
u32 lmac_error_event_table)
{
- if (!(trans->error_event_table_tlv_status &
+ if (!(trans->dbg.error_event_table_tlv_status &
IWL_ERROR_EVENT_TABLE_LMAC1) ||
- WARN_ON(trans->lmac_error_event_table[0] !=
+ WARN_ON(trans->dbg.lmac_error_event_table[0] !=
lmac_error_event_table))
- trans->lmac_error_event_table[0] = lmac_error_event_table;
+ trans->dbg.lmac_error_event_table[0] = lmac_error_event_table;
}
static inline void iwl_fw_umac_set_alive_err_table(struct iwl_trans *trans,
u32 umac_error_event_table)
{
- if (!(trans->error_event_table_tlv_status &
+ if (!(trans->dbg.error_event_table_tlv_status &
IWL_ERROR_EVENT_TABLE_UMAC) ||
- WARN_ON(trans->umac_error_event_table !=
+ WARN_ON(trans->dbg.umac_error_event_table !=
umac_error_event_table))
- trans->umac_error_event_table = umac_error_event_table;
+ trans->dbg.umac_error_event_table = umac_error_event_table;
}
-/* This bit is used to differentiate the legacy dump from the ini dump */
-#define INI_DUMP_BIT BIT(31)
-
static inline void iwl_fw_error_collect(struct iwl_fw_runtime *fwrt)
{
- if (fwrt->trans->ini_valid && fwrt->trans->hw_error) {
+ if (fwrt->trans->dbg.ini_valid && fwrt->trans->dbg.hw_error) {
_iwl_fw_dbg_ini_collect(fwrt, IWL_FW_TRIGGER_ID_FW_HW_ERROR);
- fwrt->trans->hw_error = false;
+ fwrt->trans->dbg.hw_error = false;
} else {
iwl_fw_dbg_collect_desc(fwrt, &iwl_dump_desc_assert, false, 0);
}
}
void iwl_fw_dbg_periodic_trig_handler(struct timer_list *t);
+
+void iwl_fw_error_print_fseq_regs(struct iwl_fw_runtime *fwrt);
+
+static inline void iwl_fwrt_update_fw_versions(struct iwl_fw_runtime *fwrt,
+ struct iwl_lmac_alive *lmac,
+ struct iwl_umac_alive *umac)
+{
+ if (lmac) {
+ fwrt->dump.fw_ver.type = lmac->ver_type;
+ fwrt->dump.fw_ver.subtype = lmac->ver_subtype;
+ fwrt->dump.fw_ver.lmac_major = le32_to_cpu(lmac->ucode_major);
+ fwrt->dump.fw_ver.lmac_minor = le32_to_cpu(lmac->ucode_minor);
+ }
+
+ if (umac) {
+ fwrt->dump.fw_ver.umac_major = le32_to_cpu(umac->umac_major);
+ fwrt->dump.fw_ver.umac_minor = le32_to_cpu(umac->umac_minor);
+ }
+}
#endif /* __iwl_fw_dbg_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h
index 0feff4c33e39..00a45ea85b69 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h
@@ -67,6 +67,7 @@
#include <linux/types.h>
#define IWL_FW_ERROR_DUMP_BARKER 0x14789632
+#define IWL_FW_INI_ERROR_DUMP_BARKER 0x14789633
/**
* enum iwl_fw_error_dump_type - types of data in the dump file
@@ -278,19 +279,42 @@ struct iwl_fw_error_dump_mem {
u8 data[];
};
-#define IWL_INI_DUMP_MEM_VER 1
-#define IWL_INI_DUMP_MONITOR_VER 1
-#define IWL_INI_DUMP_FIFO_VER 1
+/* Dump version, used by the dump parser to differentiate between
+ * different dump formats
+ */
+#define IWL_INI_DUMP_VER 1
+
+/* Use bit 31 as dump info type to avoid colliding with region types */
+#define IWL_INI_DUMP_INFO_TYPE BIT(31)
+
+/**
+ * struct iwl_fw_ini_fifo_hdr - fifo range header
+ * @fifo_num: the fifo number. In case of umac rx fifo, set BIT(31) to
+ * distinguish between lmac and umac rx fifos
+ * @num_of_registers: num of registers to dump, dword size each
+ */
+struct iwl_fw_ini_fifo_hdr {
+ __le32 fifo_num;
+ __le32 num_of_registers;
+} __packed;
/**
* struct iwl_fw_ini_error_dump_range - range of memory
* @range_data_size: the size of this range, in bytes
- * @start_addr: the start address of this range
+ * @internal_base_addr - base address of internal memory range
+ * @dram_base_addr - base address of dram monitor range
+ * @page_num - page number of memory range
+ * @fifo_hdr - fifo header of memory range
* @data: the actual memory
*/
struct iwl_fw_ini_error_dump_range {
__le32 range_data_size;
- __le64 start_addr;
+ union {
+ __le32 internal_base_addr;
+ __le64 dram_base_addr;
+ __le32 page_num;
+ struct iwl_fw_ini_fifo_hdr fifo_hdr;
+ };
__le32 data[];
} __packed;
@@ -333,30 +357,63 @@ struct iwl_fw_ini_error_dump_register {
__le32 data;
} __packed;
-/**
- * struct iwl_fw_ini_fifo_error_dump_range - ini fifo range dump
- * @fifo_num: the fifo num. In case of rxf and umac rxf, set BIT(31) to
- * distinguish between lmac and umac
- * @num_of_registers: num of registers to dump, dword size each
- * @range_data_size: the size of the data
- * @data: consist of
- * num_of_registers * (register address + register value) + fifo data
+/* struct iwl_fw_ini_dump_info - ini dump information
+ * @version: dump version
+ * @trigger_id: trigger id that caused the dump collection
+ * @trigger_reason: not supported yet
+ * @is_external_cfg: 1 if an external debug configuration was loaded
+ * and 0 otherwise
+ * @ver_type: FW version type
+ * @ver_subtype: FW version subype
+ * @hw_step: HW step
+ * @hw_type: HW type
+ * @rf_id_flavor: HW RF id flavor
+ * @rf_id_dash: HW RF id dash
+ * @rf_id_step: HW RF id step
+ * @rf_id_type: HW RF id type
+ * @lmac_major: lmac major version
+ * @lmac_minor: lmac minor version
+ * @umac_major: umac major version
+ * @umac_minor: umac minor version
+ * @build_tag_len: length of the build tag
+ * @build_tag: build tag string
+ * @img_name_len: length of the FW image name
+ * @img_name: FW image name
+ * @internal_dbg_cfg_name_len: length of the internal debug configuration name
+ * @internal_dbg_cfg_name: internal debug configuration name
+ * @external_dbg_cfg_name_len: length of the external debug configuration name
+ * @external_dbg_cfg_name: external debug configuration name
+ * @regions_num: number of region ids
+ * @region_ids: region ids the trigger configured to collect
*/
-struct iwl_fw_ini_fifo_error_dump_range {
- __le32 fifo_num;
- __le32 num_of_registers;
- __le32 range_data_size;
- __le32 data[];
-} __packed;
+struct iwl_fw_ini_dump_info {
+ __le32 version;
+ __le32 trigger_id;
+ __le32 trigger_reason;
+ __le32 is_external_cfg;
+ __le32 ver_type;
+ __le32 ver_subtype;
+ __le32 hw_step;
+ __le32 hw_type;
+ __le32 rf_id_flavor;
+ __le32 rf_id_dash;
+ __le32 rf_id_step;
+ __le32 rf_id_type;
+ __le32 lmac_major;
+ __le32 lmac_minor;
+ __le32 umac_major;
+ __le32 umac_minor;
+ __le32 build_tag_len;
+ u8 build_tag[FW_VER_HUMAN_READABLE_SZ];
+ __le32 img_name_len;
+ u8 img_name[IWL_FW_INI_MAX_IMG_NAME_LEN];
+ __le32 internal_dbg_cfg_name_len;
+ u8 internal_dbg_cfg_name[IWL_FW_INI_MAX_DBG_CFG_NAME_LEN];
+ __le32 external_dbg_cfg_name_len;
+ u8 external_dbg_cfg_name[IWL_FW_INI_MAX_DBG_CFG_NAME_LEN];
+ __le32 regions_num;
+ __le32 region_ids[];
-/**
- * struct iwl_fw_ini_fifo_error_dump - ini fifo region dump
- * @header: the header of this region
- * @ranges: the memory ranges of this region
- */
-struct iwl_fw_ini_fifo_error_dump {
- struct iwl_fw_ini_error_dump_header header;
- struct iwl_fw_ini_fifo_error_dump_range ranges[];
} __packed;
/**
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h
index de9243d30135..0c38e7392b61 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/file.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h
@@ -151,12 +151,13 @@ enum iwl_ucode_tlv_type {
IWL_UCODE_TLV_FW_RECOVERY_INFO = 57,
IWL_UCODE_TLV_FW_FSEQ_VERSION = 60,
- IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION = IWL_UCODE_INI_TLV_GROUP + 0x1,
- IWL_UCODE_TLV_DEBUG_BASE = IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION,
- IWL_UCODE_TLV_TYPE_HCMD = IWL_UCODE_INI_TLV_GROUP + 0x2,
- IWL_UCODE_TLV_TYPE_REGIONS = IWL_UCODE_INI_TLV_GROUP + 0x3,
- IWL_UCODE_TLV_TYPE_TRIGGERS = IWL_UCODE_INI_TLV_GROUP + 0x4,
- IWL_UCODE_TLV_TYPE_DEBUG_FLOW = IWL_UCODE_INI_TLV_GROUP + 0x5,
+ IWL_UCODE_TLV_DEBUG_BASE = IWL_UCODE_INI_TLV_GROUP,
+ IWL_UCODE_TLV_TYPE_DEBUG_INFO = IWL_UCODE_TLV_DEBUG_BASE + 0,
+ IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION = IWL_UCODE_TLV_DEBUG_BASE + 1,
+ IWL_UCODE_TLV_TYPE_HCMD = IWL_UCODE_TLV_DEBUG_BASE + 2,
+ IWL_UCODE_TLV_TYPE_REGIONS = IWL_UCODE_TLV_DEBUG_BASE + 3,
+ IWL_UCODE_TLV_TYPE_TRIGGERS = IWL_UCODE_TLV_DEBUG_BASE + 4,
+ IWL_UCODE_TLV_TYPE_DEBUG_FLOW = IWL_UCODE_TLV_DEBUG_BASE + 5,
IWL_UCODE_TLV_DEBUG_MAX = IWL_UCODE_TLV_TYPE_DEBUG_FLOW,
/* TLVs 0x1000-0x2000 are for internal driver usage */
@@ -286,6 +287,8 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t;
* SCAN_OFFLOAD_PROFILES_QUERY_RSP_S.
* @IWL_UCODE_TLV_API_MBSSID_HE: This ucode supports v2 of
* STA_CONTEXT_DOT11AX_API_S
+ * @IWL_UCODE_TLV_CAPA_SAR_TABLE_VER: This ucode supports different sar
+ * version tables.
*
* @NUM_IWL_UCODE_TLV_API: number of bits used
*/
@@ -318,6 +321,8 @@ enum iwl_ucode_tlv_api {
IWL_UCODE_TLV_API_MBSSID_HE = (__force iwl_ucode_tlv_api_t)52,
IWL_UCODE_TLV_API_WOWLAN_TCP_SYN_WAKE = (__force iwl_ucode_tlv_api_t)53,
IWL_UCODE_TLV_API_FTM_RTT_ACCURACY = (__force iwl_ucode_tlv_api_t)54,
+ IWL_UCODE_TLV_API_SAR_TABLE_VER = (__force iwl_ucode_tlv_api_t)55,
+ IWL_UCODE_TLV_API_ADWELL_HB_DEF_N_AP = (__force iwl_ucode_tlv_api_t)57,
NUM_IWL_UCODE_TLV_API
#ifdef __CHECKER__
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/init.c b/drivers/net/wireless/intel/iwlwifi/fw/init.c
index 4435c0ce3013..c16d6e126e3c 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/init.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/init.c
@@ -67,6 +67,8 @@ void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans,
const struct iwl_fw_runtime_ops *ops, void *ops_ctx,
struct dentry *dbgfs_dir)
{
+ int i;
+
memset(fwrt, 0, sizeof(*fwrt));
fwrt->trans = trans;
fwrt->fw = fw;
@@ -74,7 +76,10 @@ void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans,
fwrt->dump.conf = FW_DBG_INVALID;
fwrt->ops = ops;
fwrt->ops_ctx = ops_ctx;
- INIT_DELAYED_WORK(&fwrt->dump.wk, iwl_fw_error_dump_wk);
+ for (i = 0; i < IWL_FW_RUNTIME_DUMP_WK_NUM; i++) {
+ fwrt->dump.wks[i].idx = i;
+ INIT_DELAYED_WORK(&fwrt->dump.wks[i].wk, iwl_fw_error_dump_wk);
+ }
iwl_fwrt_dbgfs_register(fwrt, dbgfs_dir);
timer_setup(&fwrt->dump.periodic_trig,
iwl_fw_dbg_periodic_trig_handler, 0);
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h
index a6402a0b3854..406ef73992c1 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h
@@ -89,9 +89,7 @@ struct iwl_fwrt_shared_mem_cfg {
u32 internal_txfifo_size[TX_FIFO_INTERNAL_MAX_NUM];
};
-enum iwl_fw_runtime_status {
- IWL_FWRT_STATUS_DUMPING = 0,
-};
+#define IWL_FW_RUNTIME_DUMP_WK_NUM 5
/**
* struct iwl_fw_runtime - runtime data for firmware
@@ -100,7 +98,6 @@ enum iwl_fw_runtime_status {
* @dev: device pointer
* @ops: user ops
* @ops_ctx: user ops context
- * @status: status flags
* @fw_paging_db: paging database
* @num_of_paging_blk: number of paging blocks
* @num_of_pages_in_last_blk: number of pages in the last block
@@ -117,8 +114,6 @@ struct iwl_fw_runtime {
const struct iwl_fw_runtime_ops *ops;
void *ops_ctx;
- unsigned long status;
-
/* Paging */
struct iwl_fw_paging fw_paging_db[NUM_OF_FW_PAGING_BLOCKS];
u16 num_of_paging_blk;
@@ -133,7 +128,12 @@ struct iwl_fw_runtime {
struct {
const struct iwl_fw_dump_desc *desc;
bool monitor_only;
- struct delayed_work wk;
+ struct {
+ u8 idx;
+ enum iwl_fw_ini_trigger_id ini_trig_id;
+ struct delayed_work wk;
+ } wks[IWL_FW_RUNTIME_DUMP_WK_NUM];
+ unsigned long active_wks;
u8 conf;
@@ -145,8 +145,20 @@ struct iwl_fw_runtime {
u32 lmac_err_id[MAX_NUM_LMAC];
u32 umac_err_id;
void *fifo_iter;
- enum iwl_fw_ini_trigger_id ini_trig_id;
struct timer_list periodic_trig;
+
+ u8 img_name[IWL_FW_INI_MAX_IMG_NAME_LEN];
+ u8 internal_dbg_cfg_name[IWL_FW_INI_MAX_DBG_CFG_NAME_LEN];
+ u8 external_dbg_cfg_name[IWL_FW_INI_MAX_DBG_CFG_NAME_LEN];
+
+ struct {
+ u8 type;
+ u8 subtype;
+ u32 lmac_major;
+ u32 lmac_minor;
+ u32 umac_major;
+ u32 umac_minor;
+ } fw_ver;
} dump;
#ifdef CONFIG_IWLWIFI_DEBUGFS
struct {
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/smem.c b/drivers/net/wireless/intel/iwlwifi/fw/smem.c
index ff85d69c2a8c..557ee47bffd8 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/smem.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/smem.c
@@ -8,7 +8,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
- * Copyright(c) 2018 Intel Corporation
+ * Copyright(c) 2018 - 2019 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -31,7 +31,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
- * Copyright(c) 2018 Intel Corporation
+ * Copyright(c) 2018 - 2019 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -134,6 +134,7 @@ void iwl_get_shared_mem_conf(struct iwl_fw_runtime *fwrt)
.len = { 0, },
};
struct iwl_rx_packet *pkt;
+ int ret;
if (fw_has_capa(&fwrt->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG))
@@ -141,8 +142,13 @@ void iwl_get_shared_mem_conf(struct iwl_fw_runtime *fwrt)
else
cmd.id = SHARED_MEM_CFG;
- if (WARN_ON(iwl_trans_send_cmd(fwrt->trans, &cmd)))
+ ret = iwl_trans_send_cmd(fwrt->trans, &cmd);
+
+ if (ret) {
+ WARN(ret != -ERFKILL,
+ "Could not send the SMEM command: %d\n", ret);
return;
+ }
pkt = cmd.resp_pkt;
if (fwrt->trans->cfg->device_family >= IWL_DEVICE_FAMILY_22000)
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h
index f3e69edf8907..1c1bf1b281cd 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h
@@ -540,14 +540,20 @@ extern const struct iwl_cfg iwl9260_killer_2ac_cfg;
extern const struct iwl_cfg iwl9270_2ac_cfg;
extern const struct iwl_cfg iwl9460_2ac_cfg;
extern const struct iwl_cfg iwl9560_2ac_cfg;
+extern const struct iwl_cfg iwl9560_2ac_cfg_quz_a0_jf_b0_soc;
extern const struct iwl_cfg iwl9560_2ac_160_cfg;
+extern const struct iwl_cfg iwl9560_2ac_160_cfg_quz_a0_jf_b0_soc;
extern const struct iwl_cfg iwl9460_2ac_cfg_soc;
extern const struct iwl_cfg iwl9461_2ac_cfg_soc;
+extern const struct iwl_cfg iwl9461_2ac_cfg_quz_a0_jf_b0_soc;
extern const struct iwl_cfg iwl9462_2ac_cfg_soc;
+extern const struct iwl_cfg iwl9462_2ac_cfg_quz_a0_jf_b0_soc;
extern const struct iwl_cfg iwl9560_2ac_cfg_soc;
extern const struct iwl_cfg iwl9560_2ac_160_cfg_soc;
extern const struct iwl_cfg iwl9560_killer_2ac_cfg_soc;
extern const struct iwl_cfg iwl9560_killer_s_2ac_cfg_soc;
+extern const struct iwl_cfg iwl9560_killer_i_2ac_cfg_quz_a0_jf_b0_soc;
+extern const struct iwl_cfg iwl9560_killer_s_2ac_cfg_quz_a0_jf_b0_soc;
extern const struct iwl_cfg iwl9460_2ac_cfg_shared_clk;
extern const struct iwl_cfg iwl9461_2ac_cfg_shared_clk;
extern const struct iwl_cfg iwl9462_2ac_cfg_shared_clk;
@@ -559,9 +565,16 @@ extern const struct iwl_cfg iwl22000_2ac_cfg_hr;
extern const struct iwl_cfg iwl22000_2ac_cfg_hr_cdb;
extern const struct iwl_cfg iwl22000_2ac_cfg_jf;
extern const struct iwl_cfg iwl_ax101_cfg_qu_hr;
+extern const struct iwl_cfg iwl_ax101_cfg_qu_c0_hr_b0;
extern const struct iwl_cfg iwl_ax101_cfg_quz_hr;
extern const struct iwl_cfg iwl22000_2ax_cfg_hr;
extern const struct iwl_cfg iwl_ax200_cfg_cc;
+extern const struct iwl_cfg iwl_ax201_cfg_qu_hr;
+extern const struct iwl_cfg iwl_ax201_cfg_qu_hr;
+extern const struct iwl_cfg iwl_ax201_cfg_qu_c0_hr_b0;
+extern const struct iwl_cfg iwl_ax201_cfg_quz_hr;
+extern const struct iwl_cfg iwl_ax1650i_cfg_quz_hr;
+extern const struct iwl_cfg iwl_ax1650s_cfg_quz_hr;
extern const struct iwl_cfg killer1650s_2ax_cfg_qu_b0_hr_b0;
extern const struct iwl_cfg killer1650i_2ax_cfg_qu_b0_hr_b0;
extern const struct iwl_cfg killer1650x_2ax_cfg;
@@ -570,6 +583,10 @@ extern const struct iwl_cfg iwl9461_2ac_cfg_qu_b0_jf_b0;
extern const struct iwl_cfg iwl9462_2ac_cfg_qu_b0_jf_b0;
extern const struct iwl_cfg iwl9560_2ac_cfg_qu_b0_jf_b0;
extern const struct iwl_cfg iwl9560_2ac_160_cfg_qu_b0_jf_b0;
+extern const struct iwl_cfg iwl9461_2ac_cfg_qu_c0_jf_b0;
+extern const struct iwl_cfg iwl9462_2ac_cfg_qu_c0_jf_b0;
+extern const struct iwl_cfg iwl9560_2ac_cfg_qu_c0_jf_b0;
+extern const struct iwl_cfg iwl9560_2ac_160_cfg_qu_c0_jf_b0;
extern const struct iwl_cfg killer1550i_2ac_cfg_qu_b0_jf_b0;
extern const struct iwl_cfg killer1550s_2ac_cfg_qu_b0_jf_b0;
extern const struct iwl_cfg iwl22000_2ax_cfg_jf;
@@ -580,9 +597,9 @@ extern const struct iwl_cfg iwl9560_2ac_cfg_qnj_jf_b0;
extern const struct iwl_cfg iwl22000_2ax_cfg_qnj_hr_a0;
extern const struct iwl_cfg iwlax210_2ax_cfg_so_jf_a0;
extern const struct iwl_cfg iwlax210_2ax_cfg_so_hr_a0;
-extern const struct iwl_cfg iwlax210_2ax_cfg_so_gf_a0;
+extern const struct iwl_cfg iwlax211_2ax_cfg_so_gf_a0;
extern const struct iwl_cfg iwlax210_2ax_cfg_ty_gf_a0;
-extern const struct iwl_cfg iwlax210_2ax_cfg_so_gf4_a0;
+extern const struct iwl_cfg iwlax411_2ax_cfg_so_gf4_a0;
#endif /* CPTCFG_IWLMVM || CPTCFG_IWLFMAC */
#endif /* __IWL_CONFIG_H__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h
index 553554846009..cb4c5514a556 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h
@@ -328,6 +328,8 @@ enum {
#define CSR_HW_REV_TYPE_NONE (0x00001F0)
#define CSR_HW_REV_TYPE_QNJ (0x0000360)
#define CSR_HW_REV_TYPE_QNJ_B0 (0x0000364)
+#define CSR_HW_REV_TYPE_QU_B0 (0x0000334)
+#define CSR_HW_REV_TYPE_QU_C0 (0x0000338)
#define CSR_HW_REV_TYPE_QUZ (0x0000354)
#define CSR_HW_REV_TYPE_HR_CDB (0x0000340)
#define CSR_HW_REV_TYPE_SO (0x0000370)
@@ -336,6 +338,7 @@ enum {
/* RF_ID value */
#define CSR_HW_RF_ID_TYPE_JF (0x00105100)
#define CSR_HW_RF_ID_TYPE_HR (0x0010A000)
+#define CSR_HW_RF_ID_TYPE_HR1 (0x0010c100)
#define CSR_HW_RF_ID_TYPE_HRCDB (0x00109F00)
#define CSR_HW_RF_ID_TYPE_GF (0x0010D000)
#define CSR_HW_RF_ID_TYPE_GF4 (0x0010E000)
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c
index ba66f7fba064..fcaec410b3be 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c
@@ -81,9 +81,9 @@ void iwl_fw_dbg_copy_tlv(struct iwl_trans *trans, struct iwl_ucode_tlv *tlv,
return;
if (ext)
- data = &trans->apply_points_ext[apply_point];
+ data = &trans->dbg.apply_points_ext[apply_point];
else
- data = &trans->apply_points[apply_point];
+ data = &trans->dbg.apply_points[apply_point];
/* add room for is_alloc field in &iwl_fw_ini_allocation_data struct */
if (le32_to_cpu(tlv->type) == IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION) {
@@ -172,14 +172,14 @@ void iwl_alloc_dbg_tlv(struct iwl_trans *trans, size_t len, const u8 *data,
}
if (ext) {
- trans->apply_points_ext[i].data = mem;
- trans->apply_points_ext[i].size = size[i];
+ trans->dbg.apply_points_ext[i].data = mem;
+ trans->dbg.apply_points_ext[i].size = size[i];
} else {
- trans->apply_points[i].data = mem;
- trans->apply_points[i].size = size[i];
+ trans->dbg.apply_points[i].data = mem;
+ trans->dbg.apply_points[i].size = size[i];
}
- trans->ini_valid = true;
+ trans->dbg.ini_valid = true;
}
}
@@ -187,14 +187,14 @@ void iwl_fw_dbg_free(struct iwl_trans *trans)
{
int i;
- for (i = 0; i < ARRAY_SIZE(trans->apply_points); i++) {
- kfree(trans->apply_points[i].data);
- trans->apply_points[i].size = 0;
- trans->apply_points[i].offset = 0;
+ for (i = 0; i < ARRAY_SIZE(trans->dbg.apply_points); i++) {
+ kfree(trans->dbg.apply_points[i].data);
+ trans->dbg.apply_points[i].size = 0;
+ trans->dbg.apply_points[i].offset = 0;
- kfree(trans->apply_points_ext[i].data);
- trans->apply_points_ext[i].size = 0;
- trans->apply_points_ext[i].offset = 0;
+ kfree(trans->dbg.apply_points_ext[i].data);
+ trans->dbg.apply_points_ext[i].size = 0;
+ trans->dbg.apply_points_ext[i].offset = 0;
}
}
@@ -221,6 +221,7 @@ static int iwl_parse_fw_dbg_tlv(struct iwl_trans *trans, const u8 *data,
data += sizeof(*tlv) + ALIGN(tlv_len, 4);
switch (tlv_type) {
+ case IWL_UCODE_TLV_TYPE_DEBUG_INFO:
case IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION:
case IWL_UCODE_TLV_TYPE_HCMD:
case IWL_UCODE_TLV_TYPE_REGIONS:
@@ -242,7 +243,7 @@ void iwl_load_fw_dbg_tlv(struct device *dev, struct iwl_trans *trans)
const struct firmware *fw;
int res;
- if (trans->external_ini_loaded || !iwlwifi_mod_params.enable_ini)
+ if (trans->dbg.external_ini_loaded || !iwlwifi_mod_params.enable_ini)
return;
res = request_firmware(&fw, "iwl-dbg-tlv.ini", dev);
@@ -252,6 +253,6 @@ void iwl_load_fw_dbg_tlv(struct device *dev, struct iwl_trans *trans)
iwl_alloc_dbg_tlv(trans, fw->size, fw->data, true);
iwl_parse_fw_dbg_tlv(trans, fw->data, fw->size);
- trans->external_ini_loaded = true;
+ trans->dbg.external_ini_loaded = true;
release_firmware(fw);
}
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
index 852d3cbfc719..57d09049e615 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
@@ -1105,6 +1105,18 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
le32_to_cpu(recov_info->buf_size);
}
break;
+ case IWL_UCODE_TLV_FW_FSEQ_VERSION: {
+ struct {
+ u8 version[32];
+ u8 sha1[20];
+ } *fseq_ver = (void *)tlv_data;
+
+ if (tlv_len != sizeof(*fseq_ver))
+ goto invalid_tlv_len;
+ IWL_INFO(drv, "TLV_FW_FSEQ_VERSION: %s\n",
+ fseq_ver->version);
+ }
+ break;
case IWL_UCODE_TLV_UMAC_DEBUG_ADDRS: {
struct iwl_umac_debug_addrs *dbg_ptrs =
(void *)tlv_data;
@@ -1114,10 +1126,10 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
if (drv->trans->cfg->device_family <
IWL_DEVICE_FAMILY_22000)
break;
- drv->trans->umac_error_event_table =
+ drv->trans->dbg.umac_error_event_table =
le32_to_cpu(dbg_ptrs->error_info_addr) &
~FW_ADDR_CACHE_CONTROL;
- drv->trans->error_event_table_tlv_status |=
+ drv->trans->dbg.error_event_table_tlv_status |=
IWL_ERROR_EVENT_TABLE_UMAC;
break;
}
@@ -1130,13 +1142,14 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
if (drv->trans->cfg->device_family <
IWL_DEVICE_FAMILY_22000)
break;
- drv->trans->lmac_error_event_table[0] =
+ drv->trans->dbg.lmac_error_event_table[0] =
le32_to_cpu(dbg_ptrs->error_event_table_ptr) &
~FW_ADDR_CACHE_CONTROL;
- drv->trans->error_event_table_tlv_status |=
+ drv->trans->dbg.error_event_table_tlv_status |=
IWL_ERROR_EVENT_TABLE_LMAC1;
break;
}
+ case IWL_UCODE_TLV_TYPE_DEBUG_INFO:
case IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION:
case IWL_UCODE_TLV_TYPE_HCMD:
case IWL_UCODE_TLV_TYPE_REGIONS:
@@ -1597,7 +1610,6 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
goto free;
out_free_fw:
- iwl_dealloc_ucode(drv);
release_firmware(ucode_raw);
out_unbind:
complete(&drv->request_firmware_complete);
@@ -1745,7 +1757,7 @@ IWL_EXPORT_SYMBOL(iwl_opmode_deregister);
static int __init iwl_drv_init(void)
{
- int i;
+ int i, err;
mutex_init(&iwlwifi_opmode_table_mtx);
@@ -1760,7 +1772,17 @@ static int __init iwl_drv_init(void)
iwl_dbgfs_root = debugfs_create_dir(DRV_NAME, NULL);
#endif
- return iwl_pci_register_driver();
+ err = iwl_pci_register_driver();
+ if (err)
+ goto cleanup_debugfs;
+
+ return 0;
+
+cleanup_debugfs:
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ debugfs_remove_recursive(iwl_dbgfs_root);
+#endif
+ return err;
}
module_init(iwl_drv_init);
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h
index 8e6a0c363c0d..8d930bfe0727 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h
@@ -395,7 +395,11 @@ enum {
WFPM_AUX_CTL_AUX_IF_MAC_OWNER_MSK = 0x80000000,
};
-#define AUX_MISC_REG 0xA200B0
+#define CNVI_AUX_MISC_CHIP 0xA200B0
+#define CNVR_AUX_MISC_CHIP 0xA2B800
+#define CNVR_SCU_SD_REGS_SD_REG_DIG_DCDC_VTRIM 0xA29890
+#define CNVR_SCU_SD_REGS_SD_REG_ACTIVE_VDIG_MIRROR 0xA29938
+
enum {
HW_STEP_LOCATION_BITS = 24,
};
@@ -408,7 +412,12 @@ enum aux_misc_master1_en {
#define AUX_MISC_MASTER1_SMPHR_STATUS 0xA20800
#define RSA_ENABLE 0xA24B08
#define PREG_AUX_BUS_WPROT_0 0xA04CC0
-#define PREG_PRPH_WPROT_0 0xA04CE0
+
+/* device family 9000 WPROT register */
+#define PREG_PRPH_WPROT_9000 0xA04CE0
+/* device family 22000 WPROT register */
+#define PREG_PRPH_WPROT_22000 0xA04D00
+
#define SB_CPU_1_STATUS 0xA01E30
#define SB_CPU_2_STATUS 0xA01E34
#define UMAG_SB_CPU_1_STATUS 0xA038C0
@@ -442,4 +451,13 @@ enum {
#define UREG_DOORBELL_TO_ISR6 0xA05C04
#define UREG_DOORBELL_TO_ISR6_NMI_BIT BIT(0)
+
+#define FSEQ_ERROR_CODE 0xA340C8
+#define FSEQ_TOP_INIT_VERSION 0xA34038
+#define FSEQ_CNVIO_INIT_VERSION 0xA3403C
+#define FSEQ_OTP_VERSION 0xA340FC
+#define FSEQ_TOP_CONTENT_VERSION 0xA340F4
+#define FSEQ_ALIVE_TOKEN 0xA340F0
+#define FSEQ_CNVI_ID 0xA3408C
+#define FSEQ_CNVR_ID 0xA34090
#endif /* __iwl_prph_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
index 1e4c9ef548cc..0f8aeb111b0e 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
@@ -722,6 +722,50 @@ struct iwl_self_init_dram {
};
/**
+ * struct iwl_trans_debug - transport debug related data
+ *
+ * @n_dest_reg: num of reg_ops in %dbg_dest_tlv
+ * @rec_on: true iff there is a fw debug recording currently active
+ * @dest_tlv: points to the destination TLV for debug
+ * @conf_tlv: array of pointers to configuration TLVs for debug
+ * @trigger_tlv: array of pointers to triggers TLVs for debug
+ * @lmac_error_event_table: addrs of lmacs error tables
+ * @umac_error_event_table: addr of umac error table
+ * @error_event_table_tlv_status: bitmap that indicates what error table
+ * pointers was recevied via TLV. uses enum &iwl_error_event_table_status
+ * @external_ini_loaded: indicates if an external ini cfg was given
+ * @ini_valid: indicates if debug ini mode is on
+ * @num_blocks: number of blocks in fw_mon
+ * @fw_mon: address of the buffers for firmware monitor
+ * @hw_error: equals true if hw error interrupt was received from the FW
+ * @ini_dest: debug monitor destination uses &enum iwl_fw_ini_buffer_location
+ */
+struct iwl_trans_debug {
+ u8 n_dest_reg;
+ bool rec_on;
+
+ const struct iwl_fw_dbg_dest_tlv_v1 *dest_tlv;
+ const struct iwl_fw_dbg_conf_tlv *conf_tlv[FW_DBG_CONF_MAX];
+ struct iwl_fw_dbg_trigger_tlv * const *trigger_tlv;
+
+ u32 lmac_error_event_table[2];
+ u32 umac_error_event_table;
+ unsigned int error_event_table_tlv_status;
+
+ bool external_ini_loaded;
+ bool ini_valid;
+
+ struct iwl_apply_point_data apply_points[IWL_FW_INI_APPLY_NUM];
+ struct iwl_apply_point_data apply_points_ext[IWL_FW_INI_APPLY_NUM];
+
+ int num_blocks;
+ struct iwl_dram_data fw_mon[IWL_FW_INI_APPLY_NUM];
+
+ bool hw_error;
+ enum iwl_fw_ini_buffer_location ini_dest;
+};
+
+/**
* struct iwl_trans - transport common data
*
* @ops - pointer to iwl_trans_ops
@@ -750,24 +794,12 @@ struct iwl_self_init_dram {
* @rx_mpdu_cmd_hdr_size: used for tracing, amount of data before the
* start of the 802.11 header in the @rx_mpdu_cmd
* @dflt_pwr_limit: default power limit fetched from the platform (ACPI)
- * @dbg_dest_tlv: points to the destination TLV for debug
- * @dbg_conf_tlv: array of pointers to configuration TLVs for debug
- * @dbg_trigger_tlv: array of pointers to triggers TLVs for debug
- * @dbg_n_dest_reg: num of reg_ops in %dbg_dest_tlv
- * @num_blocks: number of blocks in fw_mon
- * @fw_mon: address of the buffers for firmware monitor
* @system_pm_mode: the system-wide power management mode in use.
* This mode is set dynamically, depending on the WoWLAN values
* configured from the userspace at runtime.
* @runtime_pm_mode: the runtime power management mode in use. This
* mode is set during the initialization phase and is not
* supposed to change during runtime.
- * @dbg_rec_on: true iff there is a fw debug recording currently active
- * @lmac_error_event_table: addrs of lmacs error tables
- * @umac_error_event_table: addr of umac error table
- * @error_event_table_tlv_status: bitmap that indicates what error table
- * pointers was recevied via TLV. use enum &iwl_error_event_table_status
- * @hw_error: equals true if hw error interrupt was received from the FW
*/
struct iwl_trans {
const struct iwl_trans_ops *ops;
@@ -808,29 +840,12 @@ struct iwl_trans {
struct lockdep_map sync_cmd_lockdep_map;
#endif
- struct iwl_apply_point_data apply_points[IWL_FW_INI_APPLY_NUM];
- struct iwl_apply_point_data apply_points_ext[IWL_FW_INI_APPLY_NUM];
-
- bool external_ini_loaded;
- bool ini_valid;
-
- const struct iwl_fw_dbg_dest_tlv_v1 *dbg_dest_tlv;
- const struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX];
- struct iwl_fw_dbg_trigger_tlv * const *dbg_trigger_tlv;
- u8 dbg_n_dest_reg;
- int num_blocks;
- struct iwl_dram_data fw_mon[IWL_FW_INI_APPLY_NUM];
+ struct iwl_trans_debug dbg;
struct iwl_self_init_dram init_dram;
enum iwl_plat_pm_mode system_pm_mode;
enum iwl_plat_pm_mode runtime_pm_mode;
bool suspending;
- bool dbg_rec_on;
-
- u32 lmac_error_event_table[2];
- u32 umac_error_event_table;
- unsigned int error_event_table_tlv_status;
- bool hw_error;
/* pointer to trans specific struct */
/*Ensure that this pointer will always be aligned to sizeof pointer */
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h
index dff14f1ec55f..915b172da57a 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h
@@ -152,5 +152,6 @@
#define IWL_MVM_FTM_INITIATOR_ALGO IWL_TOF_ALGO_TYPE_MAX_LIKE
#define IWL_MVM_FTM_INITIATOR_DYNACK true
#define IWL_MVM_D3_DEBUG false
+#define IWL_MVM_USE_TWT false
#endif /* __MVM_CONSTANTS_H */
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
index 60f5d337f16d..cec40855a641 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
@@ -398,8 +398,7 @@ static int iwl_mvm_send_patterns_v1(struct iwl_mvm *mvm,
if (!wowlan->n_patterns)
return 0;
- cmd.len[0] = sizeof(*pattern_cmd) +
- wowlan->n_patterns * sizeof(struct iwl_wowlan_pattern_v1);
+ cmd.len[0] = struct_size(pattern_cmd, patterns, wowlan->n_patterns);
pattern_cmd = kmalloc(cmd.len[0], GFP_KERNEL);
if (!pattern_cmd)
@@ -1079,11 +1078,12 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
#endif
/*
- * TODO: this is needed because the firmware is not stopping
- * the recording automatically before entering D3. This can
- * be removed once the FW starts doing that.
+ * Prior to 9000 device family the driver needs to stop the dbg
+ * recording before entering D3. In later devices the FW stops the
+ * recording automatically.
*/
- _iwl_fw_dbg_stop_recording(mvm->fwrt.trans, NULL);
+ if (mvm->trans->cfg->device_family < IWL_DEVICE_FAMILY_9000)
+ iwl_fw_dbg_stop_recording(mvm->trans, NULL);
/* must be last -- this switches firmware state */
ret = iwl_mvm_send_cmd(mvm, &d3_cfg_cmd);
@@ -1972,26 +1972,6 @@ out:
}
}
-static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm)
-{
-#ifdef CONFIG_IWLWIFI_DEBUGFS
- const struct fw_img *img = &mvm->fw->img[IWL_UCODE_WOWLAN];
- u32 len = img->sec[IWL_UCODE_SECTION_DATA].len;
- u32 offs = img->sec[IWL_UCODE_SECTION_DATA].offset;
-
- if (!mvm->store_d3_resume_sram)
- return;
-
- if (!mvm->d3_resume_sram) {
- mvm->d3_resume_sram = kzalloc(len, GFP_KERNEL);
- if (!mvm->d3_resume_sram)
- return;
- }
-
- iwl_trans_read_mem_bytes(mvm->trans, offs, mvm->d3_resume_sram, len);
-#endif
-}
-
static void iwl_mvm_d3_disconnect_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
@@ -2006,7 +1986,7 @@ static void iwl_mvm_d3_disconnect_iter(void *data, u8 *mac,
static int iwl_mvm_check_rt_status(struct iwl_mvm *mvm,
struct ieee80211_vif *vif)
{
- u32 base = mvm->trans->lmac_error_event_table[0];
+ u32 base = mvm->trans->dbg.lmac_error_event_table[0];
struct error_table_start {
/* cf. struct iwl_error_event_table */
u32 valid;
@@ -2054,8 +2034,6 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
}
iwl_fw_dbg_read_d3_debug_data(&mvm->fwrt);
- /* query SRAM first in case we want event logging */
- iwl_mvm_read_d3_sram(mvm);
if (iwl_mvm_check_rt_status(mvm, vif)) {
set_bit(STATUS_FW_ERROR, &mvm->trans->status);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
index d4ff6b44de2c..0c188a82cfc1 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
@@ -467,6 +467,46 @@ static ssize_t iwl_dbgfs_rs_data_read(struct file *file, char __user *user_buf,
return ret;
}
+static ssize_t iwl_dbgfs_amsdu_len_write(struct ieee80211_sta *sta,
+ char *buf, size_t count,
+ loff_t *ppos)
+{
+ struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ int i;
+ u16 amsdu_len;
+
+ if (kstrtou16(buf, 0, &amsdu_len))
+ return -EINVAL;
+
+ if (amsdu_len) {
+ mvmsta->orig_amsdu_len = sta->max_amsdu_len;
+ sta->max_amsdu_len = amsdu_len;
+ for (i = 0; i < ARRAY_SIZE(sta->max_tid_amsdu_len); i++)
+ sta->max_tid_amsdu_len[i] = amsdu_len;
+ } else {
+ sta->max_amsdu_len = mvmsta->orig_amsdu_len;
+ mvmsta->orig_amsdu_len = 0;
+ }
+ return count;
+}
+
+static ssize_t iwl_dbgfs_amsdu_len_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_sta *sta = file->private_data;
+ struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+
+ char buf[32];
+ int pos;
+
+ pos = scnprintf(buf, sizeof(buf), "current %d ", sta->max_amsdu_len);
+ pos += scnprintf(buf + pos, sizeof(buf) - pos, "stored %d\n",
+ mvmsta->orig_amsdu_len);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
static ssize_t iwl_dbgfs_disable_power_off_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
@@ -1356,24 +1396,6 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm,
return count;
}
-static ssize_t iwl_dbgfs_max_amsdu_len_write(struct iwl_mvm *mvm,
- char *buf, size_t count,
- loff_t *ppos)
-{
- unsigned int max_amsdu_len;
- int ret;
-
- ret = kstrtouint(buf, 0, &max_amsdu_len);
- if (ret)
- return ret;
-
- if (max_amsdu_len > IEEE80211_MAX_MPDU_LEN_VHT_11454)
- return -EINVAL;
- mvm->max_amsdu_len = max_amsdu_len;
-
- return count;
-}
-
#define ADD_TEXT(...) pos += scnprintf(buf + pos, bufsz - pos, __VA_ARGS__)
#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
static ssize_t iwl_dbgfs_bcast_filters_read(struct file *file,
@@ -1557,59 +1579,6 @@ static ssize_t iwl_dbgfs_bcast_filters_macs_write(struct iwl_mvm *mvm,
}
#endif
-#ifdef CONFIG_PM_SLEEP
-static ssize_t iwl_dbgfs_d3_sram_write(struct iwl_mvm *mvm, char *buf,
- size_t count, loff_t *ppos)
-{
- int store;
-
- if (sscanf(buf, "%d", &store) != 1)
- return -EINVAL;
-
- mvm->store_d3_resume_sram = store;
-
- return count;
-}
-
-static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct iwl_mvm *mvm = file->private_data;
- const struct fw_img *img;
- int ofs, len, pos = 0;
- size_t bufsz, ret;
- char *buf;
- u8 *ptr = mvm->d3_resume_sram;
-
- img = &mvm->fw->img[IWL_UCODE_WOWLAN];
- len = img->sec[IWL_UCODE_SECTION_DATA].len;
-
- bufsz = len * 4 + 256;
- buf = kzalloc(bufsz, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- pos += scnprintf(buf, bufsz, "D3 SRAM capture: %sabled\n",
- mvm->store_d3_resume_sram ? "en" : "dis");
-
- if (ptr) {
- for (ofs = 0; ofs < len; ofs += 16) {
- pos += scnprintf(buf + pos, bufsz - pos,
- "0x%.4x %16ph\n", ofs, ptr + ofs);
- }
- } else {
- pos += scnprintf(buf + pos, bufsz - pos,
- "(no data captured)\n");
- }
-
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-
- kfree(buf);
-
- return ret;
-}
-#endif
-
#define PRINT_MVM_REF(ref) do { \
if (mvm->refs[ref]) \
pos += scnprintf(buf + pos, bufsz - pos, \
@@ -1926,7 +1895,6 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg_conf, 8);
MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_collect, 64);
-MVM_DEBUGFS_WRITE_FILE_OPS(max_amsdu_len, 8);
MVM_DEBUGFS_WRITE_FILE_OPS(indirection_tbl,
(IWL_RSS_INDIRECTION_TABLE_SIZE * 2));
MVM_DEBUGFS_WRITE_FILE_OPS(inject_packet, 512);
@@ -1940,13 +1908,12 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256);
#endif
-#ifdef CONFIG_PM_SLEEP
-MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8);
-#endif
#ifdef CONFIG_ACPI
MVM_DEBUGFS_READ_FILE_OPS(sar_geo_profile);
#endif
+MVM_DEBUGFS_READ_WRITE_STA_FILE_OPS(amsdu_len, 16);
+
MVM_DEBUGFS_READ_WRITE_FILE_OPS(he_sniffer_params, 32);
static ssize_t iwl_dbgfs_mem_read(struct file *file, char __user *user_buf,
@@ -2088,8 +2055,10 @@ void iwl_mvm_sta_add_debugfs(struct ieee80211_hw *hw,
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
- if (iwl_mvm_has_tlc_offload(mvm))
+ if (iwl_mvm_has_tlc_offload(mvm)) {
MVM_DEBUGFS_ADD_STA_FILE(rs_data, dir, 0400);
+ }
+ MVM_DEBUGFS_ADD_STA_FILE(amsdu_len, dir, 0600);
}
void iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
@@ -2125,7 +2094,6 @@ void iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, 0600);
MVM_DEBUGFS_ADD_FILE(fw_dbg_conf, mvm->debugfs_dir, 0600);
MVM_DEBUGFS_ADD_FILE(fw_dbg_collect, mvm->debugfs_dir, 0200);
- MVM_DEBUGFS_ADD_FILE(max_amsdu_len, mvm->debugfs_dir, 0200);
MVM_DEBUGFS_ADD_FILE(send_echo_cmd, mvm->debugfs_dir, 0200);
MVM_DEBUGFS_ADD_FILE(indirection_tbl, mvm->debugfs_dir, 0200);
MVM_DEBUGFS_ADD_FILE(inject_packet, mvm->debugfs_dir, 0200);
@@ -2159,7 +2127,6 @@ void iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
#endif
#ifdef CONFIG_PM_SLEEP
- MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, 0600);
MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, 0400);
debugfs_create_bool("d3_wake_sysassert", 0600, mvm->debugfs_dir,
&mvm->d3_wake_sysassert);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c
index fec38a47696e..9f4b117db9d7 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c
@@ -93,7 +93,7 @@ void iwl_mvm_ftm_restart(struct iwl_mvm *mvm)
struct cfg80211_pmsr_result result = {
.status = NL80211_PMSR_STATUS_FAILURE,
.final = 1,
- .host_time = ktime_get_boot_ns(),
+ .host_time = ktime_get_boottime_ns(),
.type = NL80211_PMSR_TYPE_FTM,
};
int i;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index ab68b5d53ec9..1d608e9e9101 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -238,7 +238,7 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
iwl_fw_lmac1_set_alive_err_table(mvm->trans, lmac_error_event_table);
if (lmac2)
- mvm->trans->lmac_error_event_table[1] =
+ mvm->trans->dbg.lmac_error_event_table[1] =
le32_to_cpu(lmac2->dbg_ptrs.error_event_table_ptr);
umac_error_event_table = le32_to_cpu(umac->dbg_ptrs.error_info_addr);
@@ -276,6 +276,8 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
le32_to_cpu(umac->umac_major),
le32_to_cpu(umac->umac_minor));
+ iwl_fwrt_update_fw_versions(&mvm->fwrt, lmac1, umac);
+
return true;
}
@@ -311,6 +313,8 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
int ret;
enum iwl_ucode_type old_type = mvm->fwrt.cur_fw_img;
static const u16 alive_cmd[] = { MVM_ALIVE };
+ bool run_in_rfkill =
+ ucode_type == IWL_UCODE_INIT || iwl_mvm_has_unified_ucode(mvm);
if (ucode_type == IWL_UCODE_REGULAR &&
iwl_fw_dbg_conf_usniffer(mvm->fw, FW_DBG_START_FROM_ALIVE) &&
@@ -328,7 +332,12 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
alive_cmd, ARRAY_SIZE(alive_cmd),
iwl_alive_fn, &alive_data);
- ret = iwl_trans_start_fw(mvm->trans, fw, ucode_type == IWL_UCODE_INIT);
+ /*
+ * We want to load the INIT firmware even in RFKILL
+ * For the unified firmware case, the ucode_type is not
+ * INIT, but we still need to run it.
+ */
+ ret = iwl_trans_start_fw(mvm->trans, fw, run_in_rfkill);
if (ret) {
iwl_fw_set_current_image(&mvm->fwrt, old_type);
iwl_remove_notification(&mvm->notif_wait, &alive_wait);
@@ -412,6 +421,8 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
lockdep_assert_held(&mvm->mutex);
+ mvm->rfkill_safe_init_done = false;
+
iwl_init_notification_wait(&mvm->notif_wait,
&init_wait,
init_complete,
@@ -433,7 +444,8 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
* commands
*/
ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(SYSTEM_GROUP,
- INIT_EXTENDED_CFG_CMD), 0,
+ INIT_EXTENDED_CFG_CMD),
+ CMD_SEND_IN_RFKILL,
sizeof(init_cfg), &init_cfg);
if (ret) {
IWL_ERR(mvm, "Failed to run init config command: %d\n",
@@ -457,7 +469,8 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
}
ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(REGULATORY_AND_NVM_GROUP,
- NVM_ACCESS_COMPLETE), 0,
+ NVM_ACCESS_COMPLETE),
+ CMD_SEND_IN_RFKILL,
sizeof(nvm_complete), &nvm_complete);
if (ret) {
IWL_ERR(mvm, "Failed to run complete NVM access: %d\n",
@@ -482,6 +495,8 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
}
}
+ mvm->rfkill_safe_init_done = true;
+
return 0;
error:
@@ -526,8 +541,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
lockdep_assert_held(&mvm->mutex);
- if (WARN_ON_ONCE(mvm->calibrating))
- return 0;
+ mvm->rfkill_safe_init_done = false;
iwl_init_notification_wait(&mvm->notif_wait,
&calib_wait,
@@ -576,7 +590,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
goto remove_notif;
}
- mvm->calibrating = true;
+ mvm->rfkill_safe_init_done = true;
/* Send TX valid antennas before triggering calibrations */
ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm));
@@ -612,7 +626,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
remove_notif:
iwl_remove_notification(&mvm->notif_wait, &calib_wait);
out:
- mvm->calibrating = false;
+ mvm->rfkill_safe_init_done = false;
if (iwlmvm_mod_params.init_dbg && !mvm->nvm_data) {
/* we want to debug INIT and we have no NVM - fake */
mvm->nvm_data = kzalloc(sizeof(struct iwl_nvm_data) +
@@ -670,15 +684,15 @@ static int iwl_mvm_sar_get_wrds_table(struct iwl_mvm *mvm)
{
union acpi_object *wifi_pkg, *table, *data;
bool enabled;
- int ret;
+ int ret, tbl_rev;
data = iwl_acpi_get_object(mvm->dev, ACPI_WRDS_METHOD);
if (IS_ERR(data))
return PTR_ERR(data);
wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data,
- ACPI_WRDS_WIFI_DATA_SIZE);
- if (IS_ERR(wifi_pkg)) {
+ ACPI_WRDS_WIFI_DATA_SIZE, &tbl_rev);
+ if (IS_ERR(wifi_pkg) || tbl_rev != 0) {
ret = PTR_ERR(wifi_pkg);
goto out_free;
}
@@ -707,15 +721,15 @@ static int iwl_mvm_sar_get_ewrd_table(struct iwl_mvm *mvm)
{
union acpi_object *wifi_pkg, *data;
bool enabled;
- int i, n_profiles, ret;
+ int i, n_profiles, ret, tbl_rev;
data = iwl_acpi_get_object(mvm->dev, ACPI_EWRD_METHOD);
if (IS_ERR(data))
return PTR_ERR(data);
wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data,
- ACPI_EWRD_WIFI_DATA_SIZE);
- if (IS_ERR(wifi_pkg)) {
+ ACPI_EWRD_WIFI_DATA_SIZE, &tbl_rev);
+ if (IS_ERR(wifi_pkg) || tbl_rev != 0) {
ret = PTR_ERR(wifi_pkg);
goto out_free;
}
@@ -766,7 +780,7 @@ out_free:
static int iwl_mvm_sar_get_wgds_table(struct iwl_mvm *mvm)
{
union acpi_object *wifi_pkg, *data;
- int i, j, ret;
+ int i, j, ret, tbl_rev;
int idx = 1;
data = iwl_acpi_get_object(mvm->dev, ACPI_WGDS_METHOD);
@@ -774,12 +788,13 @@ static int iwl_mvm_sar_get_wgds_table(struct iwl_mvm *mvm)
return PTR_ERR(data);
wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data,
- ACPI_WGDS_WIFI_DATA_SIZE);
- if (IS_ERR(wifi_pkg)) {
+ ACPI_WGDS_WIFI_DATA_SIZE, &tbl_rev);
+ if (IS_ERR(wifi_pkg) || tbl_rev > 1) {
ret = PTR_ERR(wifi_pkg);
goto out_free;
}
+ mvm->geo_rev = tbl_rev;
for (i = 0; i < ACPI_NUM_GEO_PROFILES; i++) {
for (j = 0; j < ACPI_GEO_TABLE_SIZE; j++) {
union acpi_object *entry;
@@ -847,6 +862,9 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b)
return -ENOENT;
}
+ IWL_DEBUG_INFO(mvm,
+ "SAR EWRD: chain %d profile index %d\n",
+ i, profs[i]);
IWL_DEBUG_RADIO(mvm, " Chain[%d]:\n", i);
for (j = 0; j < ACPI_SAR_NUM_SUB_BANDS; j++) {
idx = (i * ACPI_SAR_NUM_SUB_BANDS) + j;
@@ -866,15 +884,29 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm)
{
struct iwl_geo_tx_power_profiles_resp *resp;
int ret;
+ u16 len;
+ void *data;
+ struct iwl_geo_tx_power_profiles_cmd geo_cmd;
+ struct iwl_geo_tx_power_profiles_cmd_v1 geo_cmd_v1;
+ struct iwl_host_cmd cmd;
+
+ if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_SAR_TABLE_VER)) {
+ geo_cmd.ops =
+ cpu_to_le32(IWL_PER_CHAIN_OFFSET_GET_CURRENT_TABLE);
+ len = sizeof(geo_cmd);
+ data = &geo_cmd;
+ } else {
+ geo_cmd_v1.ops =
+ cpu_to_le32(IWL_PER_CHAIN_OFFSET_GET_CURRENT_TABLE);
+ len = sizeof(geo_cmd_v1);
+ data = &geo_cmd_v1;
+ }
- struct iwl_geo_tx_power_profiles_cmd geo_cmd = {
- .ops = cpu_to_le32(IWL_PER_CHAIN_OFFSET_GET_CURRENT_TABLE),
- };
- struct iwl_host_cmd cmd = {
+ cmd = (struct iwl_host_cmd){
.id = WIDE_ID(PHY_OPS_GROUP, GEO_TX_POWER_LIMIT),
- .len = { sizeof(geo_cmd), },
+ .len = { len, },
.flags = CMD_WANT_SKB,
- .data = { &geo_cmd },
+ .data = { data },
};
ret = iwl_mvm_send_cmd(mvm, &cmd);
@@ -944,6 +976,16 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm)
i, j, value[1], value[2], value[0]);
}
}
+
+ cmd.table_revision = cpu_to_le32(mvm->geo_rev);
+
+ if (!fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_SAR_TABLE_VER)) {
+ return iwl_mvm_send_cmd_pdu(mvm, cmd_wide_id, 0,
+ sizeof(struct iwl_geo_tx_power_profiles_cmd_v1),
+ &cmd);
+ }
+
return iwl_mvm_send_cmd_pdu(mvm, cmd_wide_id, 0, sizeof(cmd), &cmd);
}
@@ -1097,10 +1139,13 @@ static int iwl_mvm_load_rt_fw(struct iwl_mvm *mvm)
iwl_fw_dbg_apply_point(&mvm->fwrt, IWL_FW_INI_APPLY_EARLY);
+ mvm->rfkill_safe_init_done = false;
ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_REGULAR);
if (ret)
return ret;
+ mvm->rfkill_safe_init_done = true;
+
iwl_fw_dbg_apply_point(&mvm->fwrt, IWL_FW_INI_APPLY_AFTER_ALIVE);
return iwl_init_paging(&mvm->fwrt, mvm->fwrt.cur_fw_img);
@@ -1133,7 +1178,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
if (ret)
IWL_ERR(mvm, "Failed to initialize Smart Fifo\n");
- if (!mvm->trans->ini_valid) {
+ if (!mvm->trans->dbg.ini_valid) {
mvm->fwrt.dump.conf = FW_DBG_INVALID;
/* if we have a destination, assume EARLY START */
if (mvm->fw->dbg.dest_tlv)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
index 53c217af13c8..cb22d447fcb8 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
@@ -558,15 +558,16 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
u8 txf = iwl_mvm_mac_ac_to_tx_fifo(mvm, i);
+ u8 ucode_ac = iwl_mvm_mac80211_ac_to_ucode_ac(i);
- cmd->ac[txf].cw_min =
+ cmd->ac[ucode_ac].cw_min =
cpu_to_le16(mvmvif->queue_params[i].cw_min);
- cmd->ac[txf].cw_max =
+ cmd->ac[ucode_ac].cw_max =
cpu_to_le16(mvmvif->queue_params[i].cw_max);
- cmd->ac[txf].edca_txop =
+ cmd->ac[ucode_ac].edca_txop =
cpu_to_le16(mvmvif->queue_params[i].txop * 32);
- cmd->ac[txf].aifsn = mvmvif->queue_params[i].aifs;
- cmd->ac[txf].fifos_mask = BIT(txf);
+ cmd->ac[ucode_ac].aifsn = mvmvif->queue_params[i].aifs;
+ cmd->ac[ucode_ac].fifos_mask = BIT(txf);
}
if (vif->bss_conf.qos)
@@ -678,7 +679,7 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
if (vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax) {
cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_11AX);
- if (vif->bss_conf.twt_requester)
+ if (vif->bss_conf.twt_requester && IWL_MVM_USE_TWT)
ctxt_sta->data_policy |= cpu_to_le32(TWT_SUPPORTED);
}
@@ -1081,9 +1082,6 @@ static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm,
IWL_DEBUG_HC(mvm, "No need to receive beacons\n");
}
- if (vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax)
- cmd->filter_flags |= cpu_to_le32(MAC_FILTER_IN_11AX);
-
ctxt_ap->bi = cpu_to_le32(vif->bss_conf.beacon_int);
ctxt_ap->dtim_interval = cpu_to_le32(vif->bss_conf.beacon_int *
vif->bss_conf.dtim_period);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 5c52469288be..55cd49ccbf0b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -207,6 +207,12 @@ static const struct cfg80211_pmsr_capabilities iwl_mvm_pmsr_capa = {
},
};
+static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
+ enum set_key_cmd cmd,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key);
+
void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type)
{
if (!iwl_mvm_is_d0i3_supported(mvm))
@@ -1209,7 +1215,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
mvm->scan_status = 0;
mvm->ps_disabled = false;
- mvm->calibrating = false;
+ mvm->rfkill_safe_init_done = false;
/* just in case one was running */
iwl_mvm_cleanup_roc_te(mvm);
@@ -1439,7 +1445,7 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
*/
clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status);
- iwl_fw_cancel_dump(&mvm->fwrt);
+ iwl_fw_cancel_dumps(&mvm->fwrt);
cancel_delayed_work_sync(&mvm->cs_tx_unblock_dwork);
cancel_delayed_work_sync(&mvm->scan_timeout_dwork);
iwl_fw_free_dump_desc(&mvm->fwrt);
@@ -2365,22 +2371,23 @@ static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm,
/* Mark MU EDCA as enabled, unless none detected on some AC */
flags |= STA_CTXT_HE_MU_EDCA_CW;
- for (i = 0; i < AC_NUM; i++) {
+ for (i = 0; i < IEEE80211_NUM_ACS; i++) {
struct ieee80211_he_mu_edca_param_ac_rec *mu_edca =
&mvmvif->queue_params[i].mu_edca_param_rec;
+ u8 ac = iwl_mvm_mac80211_ac_to_ucode_ac(i);
if (!mvmvif->queue_params[i].mu_edca) {
flags &= ~STA_CTXT_HE_MU_EDCA_CW;
break;
}
- sta_ctxt_cmd.trig_based_txf[i].cwmin =
+ sta_ctxt_cmd.trig_based_txf[ac].cwmin =
cpu_to_le16(mu_edca->ecw_min_max & 0xf);
- sta_ctxt_cmd.trig_based_txf[i].cwmax =
+ sta_ctxt_cmd.trig_based_txf[ac].cwmax =
cpu_to_le16((mu_edca->ecw_min_max & 0xf0) >> 4);
- sta_ctxt_cmd.trig_based_txf[i].aifsn =
+ sta_ctxt_cmd.trig_based_txf[ac].aifsn =
cpu_to_le16(mu_edca->aifsn);
- sta_ctxt_cmd.trig_based_txf[i].mu_time =
+ sta_ctxt_cmd.trig_based_txf[ac].mu_time =
cpu_to_le16(mu_edca->mu_edca_timer);
}
@@ -2636,7 +2643,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- int ret;
+ int ret, i;
/*
* iwl_mvm_mac_ctxt_add() might read directly from the device
@@ -2710,6 +2717,20 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
/* must be set before quota calculations */
mvmvif->ap_ibss_active = true;
+ /* send all the early keys to the device now */
+ for (i = 0; i < ARRAY_SIZE(mvmvif->ap_early_keys); i++) {
+ struct ieee80211_key_conf *key = mvmvif->ap_early_keys[i];
+
+ if (!key)
+ continue;
+
+ mvmvif->ap_early_keys[i] = NULL;
+
+ ret = iwl_mvm_mac_set_key(hw, SET_KEY, vif, NULL, key);
+ if (ret)
+ goto out_quota_failed;
+ }
+
if (vif->type == NL80211_IFTYPE_AP && !vif->p2p) {
iwl_mvm_vif_set_low_latency(mvmvif, true,
LOW_LATENCY_VIF_TYPE);
@@ -3479,11 +3500,12 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mvm_sta *mvmsta;
struct iwl_mvm_key_pn *ptk_pn;
int keyidx = key->keyidx;
- int ret;
+ int ret, i;
u8 key_offset;
if (iwlwifi_mod_params.swcrypto) {
@@ -3556,6 +3578,22 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
key->hw_key_idx = STA_KEY_IDX_INVALID;
break;
}
+
+ if (!mvmvif->ap_ibss_active) {
+ for (i = 0;
+ i < ARRAY_SIZE(mvmvif->ap_early_keys);
+ i++) {
+ if (!mvmvif->ap_early_keys[i]) {
+ mvmvif->ap_early_keys[i] = key;
+ break;
+ }
+ }
+
+ if (i >= ARRAY_SIZE(mvmvif->ap_early_keys))
+ ret = -ENOSPC;
+
+ break;
+ }
}
/* During FW restart, in order to restore the state as it was,
@@ -3624,6 +3662,18 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
break;
case DISABLE_KEY:
+ ret = -ENOENT;
+ for (i = 0; i < ARRAY_SIZE(mvmvif->ap_early_keys); i++) {
+ if (mvmvif->ap_early_keys[i] == key) {
+ mvmvif->ap_early_keys[i] = NULL;
+ ret = 0;
+ }
+ }
+
+ /* found in pending list - don't do anything else */
+ if (ret == 0)
+ break;
+
if (key->hw_key_idx == STA_KEY_IDX_INVALID) {
ret = 0;
break;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index 8dc2a9850bc5..48c77af54e99 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -501,6 +501,9 @@ struct iwl_mvm_vif {
netdev_features_t features;
struct iwl_probe_resp_data __rcu *probe_resp_data;
+
+ /* we can only have 2 GTK + 2 IGTK active at a time */
+ struct ieee80211_key_conf *ap_early_keys[4];
};
static inline struct iwl_mvm_vif *
@@ -880,7 +883,7 @@ struct iwl_mvm {
struct iwl_mvm_vif *bf_allowed_vif;
bool hw_registered;
- bool calibrating;
+ bool rfkill_safe_init_done;
bool support_umac_log;
u32 ampdu_ref;
@@ -1039,8 +1042,6 @@ struct iwl_mvm {
#ifdef CONFIG_IWLWIFI_DEBUGFS
bool d3_wake_sysassert;
bool d3_test_active;
- bool store_d3_resume_sram;
- void *d3_resume_sram;
u32 d3_test_pme_ptr;
struct ieee80211_vif *keep_vif;
u32 last_netdetect_scans; /* no. of scans in the last net-detect wake */
@@ -1109,7 +1110,6 @@ struct iwl_mvm {
u8 ps_disabled; /* u8 instead of bool to ease debugfs_create_* usage */
/* Indicate if 32Khz external clock is valid */
u32 ext_clock_valid;
- unsigned int max_amsdu_len; /* used for debugfs only */
struct ieee80211_vif __rcu *csa_vif;
struct ieee80211_vif __rcu *csa_tx_blocked_vif;
@@ -1183,6 +1183,7 @@ struct iwl_mvm {
#ifdef CONFIG_ACPI
struct iwl_mvm_sar_profile sar_profiles[ACPI_SAR_PROFILE_NUM];
struct iwl_mvm_geo_profile geo_profiles[ACPI_NUM_GEO_PROFILES];
+ u32 geo_rev;
#endif
};
@@ -1309,6 +1310,12 @@ static inline bool iwl_mvm_is_adaptive_dwell_v2_supported(struct iwl_mvm *mvm)
IWL_UCODE_TLV_API_ADAPTIVE_DWELL_V2);
}
+static inline bool iwl_mvm_is_adwell_hb_ap_num_supported(struct iwl_mvm *mvm)
+{
+ return fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_ADWELL_HB_DEF_N_AP);
+}
+
static inline bool iwl_mvm_is_oce_supported(struct iwl_mvm *mvm)
{
/* OCE should never be enabled for LMAC scan FWs */
@@ -1534,6 +1541,7 @@ void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags,
enum nl80211_band band,
struct ieee80211_tx_rate *r);
u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx);
+u8 iwl_mvm_mac80211_ac_to_ucode_ac(enum ieee80211_ac_numbers ac);
void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm);
u8 first_antenna(u8 mask);
u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
index 7bdbd010ae6b..719f793b3487 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
@@ -620,6 +620,7 @@ void iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm,
enum iwl_mcc_source src;
char mcc[3];
struct ieee80211_regdomain *regd;
+ u32 wgds_tbl_idx;
lockdep_assert_held(&mvm->mutex);
@@ -643,6 +644,14 @@ void iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm,
if (IS_ERR_OR_NULL(regd))
return;
+ wgds_tbl_idx = iwl_mvm_get_sar_geo_profile(mvm);
+ if (wgds_tbl_idx < 0)
+ IWL_DEBUG_INFO(mvm, "SAR WGDS is disabled (%d)\n",
+ wgds_tbl_idx);
+ else
+ IWL_DEBUG_INFO(mvm, "SAR WGDS: geo profile %d is configured\n",
+ wgds_tbl_idx);
+
regulatory_set_wiphy_regd(mvm->hw->wiphy, regd);
kfree(regd);
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
index acd2fda12466..d7d6f3398f86 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
@@ -564,24 +564,24 @@ unlock:
static int iwl_mvm_fwrt_dump_start(void *ctx)
{
struct iwl_mvm *mvm = ctx;
- int ret;
+ int ret = 0;
+
+ mutex_lock(&mvm->mutex);
ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_FW_DBG_COLLECT);
if (ret)
- return ret;
+ mutex_unlock(&mvm->mutex);
- mutex_lock(&mvm->mutex);
-
- return 0;
+ return ret;
}
static void iwl_mvm_fwrt_dump_end(void *ctx)
{
struct iwl_mvm *mvm = ctx;
- mutex_unlock(&mvm->mutex);
-
iwl_mvm_unref(mvm, IWL_MVM_REF_FW_DBG_COLLECT);
+
+ mutex_unlock(&mvm->mutex);
}
static bool iwl_mvm_fwrt_fw_running(void *ctx)
@@ -799,11 +799,11 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
iwl_trans_configure(mvm->trans, &trans_cfg);
trans->rx_mpdu_cmd = REPLY_RX_MPDU_CMD;
- trans->dbg_dest_tlv = mvm->fw->dbg.dest_tlv;
- trans->dbg_n_dest_reg = mvm->fw->dbg.n_dest_reg;
- memcpy(trans->dbg_conf_tlv, mvm->fw->dbg.conf_tlv,
- sizeof(trans->dbg_conf_tlv));
- trans->dbg_trigger_tlv = mvm->fw->dbg.trigger_tlv;
+ trans->dbg.dest_tlv = mvm->fw->dbg.dest_tlv;
+ trans->dbg.n_dest_reg = mvm->fw->dbg.n_dest_reg;
+ memcpy(trans->dbg.conf_tlv, mvm->fw->dbg.conf_tlv,
+ sizeof(trans->dbg.conf_tlv));
+ trans->dbg.trigger_tlv = mvm->fw->dbg.trigger_tlv;
trans->iml = mvm->fw->iml;
trans->iml_len = mvm->fw->iml_len;
@@ -880,7 +880,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
return op_mode;
out_free:
- iwl_fw_flush_dump(&mvm->fwrt);
+ iwl_fw_flush_dumps(&mvm->fwrt);
iwl_fw_runtime_free(&mvm->fwrt);
if (iwlmvm_mod_params.init_dbg)
@@ -918,9 +918,6 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
kfree(mvm->error_recovery_buf);
mvm->error_recovery_buf = NULL;
-#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS)
- kfree(mvm->d3_resume_sram);
-#endif
iwl_trans_op_mode_leave(mvm->trans);
iwl_phy_db_free(mvm->phy_db);
@@ -1212,7 +1209,8 @@ void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state)
static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
{
struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
- bool calibrating = READ_ONCE(mvm->calibrating);
+ bool rfkill_safe_init_done = READ_ONCE(mvm->rfkill_safe_init_done);
+ bool unified = iwl_mvm_has_unified_ucode(mvm);
if (state)
set_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status);
@@ -1221,15 +1219,23 @@ static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
iwl_mvm_set_rfkill_state(mvm);
- /* iwl_run_init_mvm_ucode is waiting for results, abort it */
- if (calibrating)
+ /* iwl_run_init_mvm_ucode is waiting for results, abort it. */
+ if (rfkill_safe_init_done)
iwl_abort_notification_waits(&mvm->notif_wait);
/*
+ * Don't ask the transport to stop the firmware. We'll do it
+ * after cfg80211 takes us down.
+ */
+ if (unified)
+ return false;
+
+ /*
* Stop the device if we run OPERATIONAL firmware or if we are in the
* middle of the calibrations.
*/
- return state && (mvm->fwrt.cur_fw_img != IWL_UCODE_INIT || calibrating);
+ return state && (mvm->fwrt.cur_fw_img != IWL_UCODE_INIT ||
+ rfkill_safe_init_done);
}
static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
index 659e21b2d4e7..08b67812e94e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
@@ -101,7 +101,7 @@ static u8 rs_fw_sgi_cw_support(struct ieee80211_sta *sta)
struct ieee80211_sta_he_cap *he_cap = &sta->he_cap;
u8 supp = 0;
- if (he_cap && he_cap->has_he)
+ if (he_cap->has_he)
return 0;
if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20)
@@ -123,12 +123,12 @@ static u16 rs_fw_get_config_flags(struct iwl_mvm *mvm,
struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
struct ieee80211_sta_he_cap *he_cap = &sta->he_cap;
- bool vht_ena = vht_cap && vht_cap->vht_supported;
+ bool vht_ena = vht_cap->vht_supported;
u16 flags = 0;
if (mvm->cfg->ht_params->stbc &&
(num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1)) {
- if (he_cap && he_cap->has_he) {
+ if (he_cap->has_he) {
if (he_cap->he_cap_elem.phy_cap_info[2] &
IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ)
flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK;
@@ -136,15 +136,14 @@ static u16 rs_fw_get_config_flags(struct iwl_mvm *mvm,
if (he_cap->he_cap_elem.phy_cap_info[7] &
IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ)
flags |= IWL_TLC_MNG_CFG_FLAGS_HE_STBC_160MHZ_MSK;
- } else if ((ht_cap &&
- (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC)) ||
+ } else if ((ht_cap->cap & IEEE80211_HT_CAP_RX_STBC) ||
(vht_ena &&
(vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK)))
flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK;
}
if (mvm->cfg->ht_params->ldpc &&
- ((ht_cap && (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING)) ||
+ ((ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING) ||
(vht_ena && (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC))))
flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK;
@@ -154,7 +153,7 @@ static u16 rs_fw_get_config_flags(struct iwl_mvm *mvm,
IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD))
flags &= ~IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK;
- if (he_cap && he_cap->has_he &&
+ if (he_cap->has_he &&
(he_cap->he_cap_elem.phy_cap_info[3] &
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_MASK))
flags |= IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_1_MSK;
@@ -293,13 +292,13 @@ static void rs_fw_set_supp_rates(struct ieee80211_sta *sta,
cmd->mode = IWL_TLC_MNG_MODE_NON_HT;
/* HT/VHT rates */
- if (he_cap && he_cap->has_he) {
+ if (he_cap->has_he) {
cmd->mode = IWL_TLC_MNG_MODE_HE;
rs_fw_he_set_enabled_rates(sta, sband, cmd);
- } else if (vht_cap && vht_cap->vht_supported) {
+ } else if (vht_cap->vht_supported) {
cmd->mode = IWL_TLC_MNG_MODE_VHT;
rs_fw_vht_set_enabled_rates(sta, vht_cap, cmd);
- } else if (ht_cap && ht_cap->ht_supported) {
+ } else if (ht_cap->ht_supported) {
cmd->mode = IWL_TLC_MNG_MODE_HT;
cmd->ht_rates[0][0] = cpu_to_le16(ht_cap->mcs.rx_mask[0]);
cmd->ht_rates[1][0] = cpu_to_le16(ht_cap->mcs.rx_mask[1]);
@@ -344,7 +343,7 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm,
lq_sta->last_rate_n_flags);
}
- if (flags & IWL_TLC_NOTIF_FLAG_AMSDU) {
+ if (flags & IWL_TLC_NOTIF_FLAG_AMSDU && !mvmsta->orig_amsdu_len) {
u16 size = le32_to_cpu(notif->amsdu_size);
int i;
@@ -381,7 +380,7 @@ static u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta)
const struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
- if (vht_cap && vht_cap->vht_supported) {
+ if (vht_cap->vht_supported) {
switch (vht_cap->cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK) {
case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:
return IEEE80211_MAX_MPDU_LEN_VHT_11454;
@@ -391,7 +390,7 @@ static u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta)
return IEEE80211_MAX_MPDU_LEN_VHT_3895;
}
- } else if (ht_cap && ht_cap->ht_supported) {
+ } else if (ht_cap->ht_supported) {
if (ht_cap->cap & IEEE80211_HT_CAP_MAX_AMSDU)
/*
* agg is offloaded so we need to assume that agg
@@ -441,7 +440,8 @@ void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
*/
sta->max_amsdu_len = max_amsdu_len;
- ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cfg_cmd), &cfg_cmd);
+ ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, CMD_ASYNC, sizeof(cfg_cmd),
+ &cfg_cmd);
if (ret)
IWL_ERR(mvm, "Failed to send rate scale config (%d)\n", ret);
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
index 63fdb4e68e9d..8c9069f28a58 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
@@ -2949,10 +2949,6 @@ static void rs_drv_get_rate(void *mvm_r, struct ieee80211_sta *sta,
mvm_sta = NULL;
}
- /* Send management frames and NO_ACK data using lowest rate. */
- if (rate_control_send_low(sta, mvm_sta, txrc))
- return;
-
if (!mvm_sta)
return;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
index fbd3014e8b82..160b0db27103 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
@@ -555,7 +555,7 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi,
if (unlikely(ieee80211_is_beacon(hdr->frame_control) ||
ieee80211_is_probe_resp(hdr->frame_control)))
- rx_status->boottime_ns = ktime_get_boot_ns();
+ rx_status->boottime_ns = ktime_get_boottime_ns();
/* Take a reference briefly to kick off a d0i3 entry delay so
* we can handle bursts of RX packets without toggling the
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
index 1824566d08fc..64f950501287 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
@@ -1684,7 +1684,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
if (unlikely(ieee80211_is_beacon(hdr->frame_control) ||
ieee80211_is_probe_resp(hdr->frame_control)))
- rx_status->boottime_ns = ktime_get_boot_ns();
+ rx_status->boottime_ns = ktime_get_boottime_ns();
}
if (iwl_mvm_create_skb(mvm, skb, hdr, len, crypt_len, rxb)) {
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
index d9ddf9ff6428..c284e6975b1b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
@@ -83,8 +83,10 @@
#define IWL_SCAN_ADWELL_MAX_BUDGET_FULL_SCAN 300
/* adaptive dwell max budget time [TU] for directed scan */
#define IWL_SCAN_ADWELL_MAX_BUDGET_DIRECTED_SCAN 100
-/* adaptive dwell default APs number */
-#define IWL_SCAN_ADWELL_DEFAULT_N_APS 2
+/* adaptive dwell default high band APs number */
+#define IWL_SCAN_ADWELL_DEFAULT_HB_N_APS 8
+/* adaptive dwell default low band APs number */
+#define IWL_SCAN_ADWELL_DEFAULT_LB_N_APS 2
/* adaptive dwell default APs number in social channels (1, 6, 11) */
#define IWL_SCAN_ADWELL_DEFAULT_N_APS_SOCIAL 10
@@ -1288,7 +1290,11 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm,
cmd->v7.adwell_default_n_aps_social =
IWL_SCAN_ADWELL_DEFAULT_N_APS_SOCIAL;
cmd->v7.adwell_default_n_aps =
- IWL_SCAN_ADWELL_DEFAULT_N_APS;
+ IWL_SCAN_ADWELL_DEFAULT_LB_N_APS;
+
+ if (iwl_mvm_is_adwell_hb_ap_num_supported(mvm))
+ cmd->v9.adwell_default_hb_n_aps =
+ IWL_SCAN_ADWELL_DEFAULT_HB_N_APS;
/* if custom max budget was configured with debugfs */
if (IWL_MVM_ADWELL_MAX_BUDGET)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
index b4d4071b865d..4487cc3e07c1 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
@@ -386,6 +386,9 @@ struct iwl_mvm_rxq_dup_data {
* @amsdu_enabled: bitmap of TX AMSDU allowed TIDs.
* In case TLC offload is not active it is either 0xFFFF or 0.
* @max_amsdu_len: max AMSDU length
+ * @orig_amsdu_len: used to save the original amsdu_len when it is changed via
+ * debugfs. If it's set to 0, it means that it is it's not set via
+ * debugfs.
* @agg_tids: bitmap of tids whose status is operational aggregated (IWL_AGG_ON)
* @sleep_tx_count: the number of frames that we told the firmware to let out
* even when that station is asleep. This is useful in case the queue
@@ -434,6 +437,7 @@ struct iwl_mvm_sta {
bool disable_tx;
u16 amsdu_enabled;
u16 max_amsdu_len;
+ u16 orig_amsdu_len;
bool sleeping;
u8 agg_tids;
u8 sleep_tx_count;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
index 0c2aabc842f9..a3e5d88f1c07 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
@@ -726,6 +726,9 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
memcpy(&info, skb->cb, sizeof(info));
+ if (WARN_ON_ONCE(skb->len > IEEE80211_MAX_DATA_LEN + hdrlen))
+ return -1;
+
if (WARN_ON_ONCE(info.flags & IEEE80211_TX_CTL_AMPDU))
return -1;
@@ -893,18 +896,15 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
unsigned int mss = skb_shinfo(skb)->gso_size;
unsigned int num_subframes, tcp_payload_len, subf_len, max_amsdu_len;
u16 snap_ip_tcp, pad;
- unsigned int dbg_max_amsdu_len;
netdev_features_t netdev_flags = NETIF_F_CSUM_MASK | NETIF_F_SG;
u8 tid;
snap_ip_tcp = 8 + skb_transport_header(skb) - skb_network_header(skb) +
tcp_hdrlen(skb);
- dbg_max_amsdu_len = READ_ONCE(mvm->max_amsdu_len);
-
if (!mvmsta->max_amsdu_len ||
!ieee80211_is_data_qos(hdr->frame_control) ||
- (!mvmsta->amsdu_enabled && !dbg_max_amsdu_len))
+ !mvmsta->amsdu_enabled)
return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb);
/*
@@ -936,10 +936,6 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
max_amsdu_len = iwl_mvm_max_amsdu_size(mvm, sta, tid);
- if (unlikely(dbg_max_amsdu_len))
- max_amsdu_len = min_t(unsigned int, max_amsdu_len,
- dbg_max_amsdu_len);
-
/*
* Limit A-MSDU in A-MPDU to 4095 bytes when VHT is not
* supported. This is a spec requirement (IEEE 802.11-2015
@@ -1063,7 +1059,9 @@ static int iwl_mvm_tx_pkt_queued(struct iwl_mvm *mvm,
}
/*
- * Sets the fields in the Tx cmd that are crypto related
+ * Sets the fields in the Tx cmd that are crypto related.
+ *
+ * This function must be called with BHs disabled.
*/
static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
struct ieee80211_tx_info *info,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
index b9914efc55c4..9ecd5f09615a 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
@@ -238,6 +238,18 @@ u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx)
return fw_rate_idx_to_plcp[rate_idx];
}
+u8 iwl_mvm_mac80211_ac_to_ucode_ac(enum ieee80211_ac_numbers ac)
+{
+ static const u8 mac80211_ac_to_ucode_ac[] = {
+ AC_VO,
+ AC_VI,
+ AC_BE,
+ AC_BK
+ };
+
+ return mac80211_ac_to_ucode_ac[ac];
+}
+
void iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
@@ -457,10 +469,10 @@ static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm)
{
struct iwl_trans *trans = mvm->trans;
struct iwl_umac_error_event_table table;
- u32 base = mvm->trans->umac_error_event_table;
+ u32 base = mvm->trans->dbg.umac_error_event_table;
if (!mvm->support_umac_log &&
- !(mvm->trans->error_event_table_tlv_status &
+ !(mvm->trans->dbg.error_event_table_tlv_status &
IWL_ERROR_EVENT_TABLE_UMAC))
return;
@@ -496,7 +508,7 @@ static void iwl_mvm_dump_lmac_error_log(struct iwl_mvm *mvm, u8 lmac_num)
{
struct iwl_trans *trans = mvm->trans;
struct iwl_error_event_table table;
- u32 val, base = mvm->trans->lmac_error_event_table[lmac_num];
+ u32 val, base = mvm->trans->dbg.lmac_error_event_table[lmac_num];
if (mvm->fwrt.cur_fw_img == IWL_UCODE_INIT) {
if (!base)
@@ -592,10 +604,12 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
iwl_mvm_dump_lmac_error_log(mvm, 0);
- if (mvm->trans->lmac_error_event_table[1])
+ if (mvm->trans->dbg.lmac_error_event_table[1])
iwl_mvm_dump_lmac_error_log(mvm, 1);
iwl_mvm_dump_umac_error_log(mvm);
+
+ iwl_fw_error_print_fseq_regs(&mvm->fwrt);
}
int iwl_mvm_reconfig_scd(struct iwl_mvm *mvm, int queue, int fifo, int sta_id,
@@ -1443,7 +1457,7 @@ void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, u32 *gp2, u64 *boottime)
}
*gp2 = iwl_mvm_get_systime(mvm);
- *boottime = ktime_get_boot_ns();
+ *boottime = ktime_get_boottime_ns();
if (!ps_disabled) {
mvm->ps_disabled = ps_disabled;
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
index f496d1bcb643..5e86783d616b 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
@@ -96,13 +96,13 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans,
cpu_to_le64(trans_pcie->rxq->bd_dma);
/* Configure debug, for integration */
- if (!trans->ini_valid)
+ if (!trans->dbg.ini_valid)
iwl_pcie_alloc_fw_monitor(trans, 0);
- if (trans->num_blocks) {
+ if (trans->dbg.num_blocks) {
prph_sc_ctrl->hwm_cfg.hwm_base_addr =
- cpu_to_le64(trans->fw_mon[0].physical);
+ cpu_to_le64(trans->dbg.fw_mon[0].physical);
prph_sc_ctrl->hwm_cfg.hwm_size =
- cpu_to_le32(trans->fw_mon[0].size);
+ cpu_to_le32(trans->dbg.fw_mon[0].size);
}
/* allocate ucode sections in dram and set addresses */
@@ -169,7 +169,7 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans,
memcpy(iml_img, trans->iml, trans->iml_len);
- iwl_enable_interrupts(trans);
+ iwl_enable_fw_load_int_ctx_info(trans);
/* kick FW self load */
iwl_write64(trans, CSR_CTXT_INFO_ADDR,
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c
index 8969b47bacf2..d38cefbb779e 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c
@@ -222,7 +222,7 @@ int iwl_pcie_ctxt_info_init(struct iwl_trans *trans,
trans_pcie->ctxt_info = ctxt_info;
- iwl_enable_interrupts(trans);
+ iwl_enable_fw_load_int_ctx_info(trans);
/* Configure debug, if exists */
if (iwl_pcie_dbg_on(trans))
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
index cd035061cdd5..ea2a03d4bf55 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
@@ -513,62 +513,56 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x24FD, 0x9074, iwl8265_2ac_cfg)},
/* 9000 Series */
- {IWL_PCI_DEVICE(0x02F0, 0x0030, iwl9560_2ac_160_cfg_soc)},
- {IWL_PCI_DEVICE(0x02F0, 0x0034, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x02F0, 0x0038, iwl9560_2ac_160_cfg_soc)},
- {IWL_PCI_DEVICE(0x02F0, 0x003C, iwl9560_2ac_160_cfg_soc)},
- {IWL_PCI_DEVICE(0x02F0, 0x0040, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x02F0, 0x0044, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x02F0, 0x0060, iwl9461_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x02F0, 0x0064, iwl9461_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x02F0, 0x00A0, iwl9462_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x02F0, 0x00A4, iwl9462_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x02F0, 0x0230, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x02F0, 0x0234, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x02F0, 0x0238, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x02F0, 0x023C, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x02F0, 0x0244, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x02F0, 0x0260, iwl9461_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x02F0, 0x0264, iwl9461_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x02F0, 0x02A0, iwl9462_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x02F0, 0x02A4, iwl9462_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x02F0, 0x1551, iwl9560_killer_s_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x02F0, 0x1552, iwl9560_killer_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x02F0, 0x2030, iwl9560_2ac_160_cfg_soc)},
- {IWL_PCI_DEVICE(0x02F0, 0x2034, iwl9560_2ac_160_cfg_soc)},
- {IWL_PCI_DEVICE(0x02F0, 0x4030, iwl9560_2ac_160_cfg_soc)},
- {IWL_PCI_DEVICE(0x02F0, 0x4034, iwl9560_2ac_160_cfg_soc)},
- {IWL_PCI_DEVICE(0x02F0, 0x40A4, iwl9462_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x02F0, 0x4234, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x02F0, 0x42A4, iwl9462_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x06F0, 0x0030, iwl9560_2ac_160_cfg_soc)},
- {IWL_PCI_DEVICE(0x06F0, 0x0034, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x06F0, 0x0038, iwl9560_2ac_160_cfg_soc)},
- {IWL_PCI_DEVICE(0x06F0, 0x003C, iwl9560_2ac_160_cfg_soc)},
- {IWL_PCI_DEVICE(0x06F0, 0x0040, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x06F0, 0x0044, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x06F0, 0x0060, iwl9461_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x06F0, 0x0064, iwl9461_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x06F0, 0x00A0, iwl9462_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x06F0, 0x00A4, iwl9462_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x06F0, 0x0230, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x06F0, 0x0234, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x06F0, 0x0238, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x06F0, 0x023C, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x06F0, 0x0244, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x06F0, 0x0260, iwl9461_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x06F0, 0x0264, iwl9461_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x06F0, 0x02A0, iwl9462_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x06F0, 0x02A4, iwl9462_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x06F0, 0x1551, iwl9560_killer_s_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x06F0, 0x1552, iwl9560_killer_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x06F0, 0x2030, iwl9560_2ac_160_cfg_soc)},
- {IWL_PCI_DEVICE(0x06F0, 0x2034, iwl9560_2ac_160_cfg_soc)},
- {IWL_PCI_DEVICE(0x06F0, 0x4030, iwl9560_2ac_160_cfg_soc)},
- {IWL_PCI_DEVICE(0x06F0, 0x4034, iwl9560_2ac_160_cfg_soc)},
- {IWL_PCI_DEVICE(0x06F0, 0x40A4, iwl9462_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x06F0, 0x4234, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x06F0, 0x42A4, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x02F0, 0x0030, iwl9560_2ac_160_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x02F0, 0x0034, iwl9560_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x02F0, 0x0038, iwl9560_2ac_160_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x02F0, 0x003C, iwl9560_2ac_160_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x02F0, 0x0060, iwl9461_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x02F0, 0x0064, iwl9461_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x02F0, 0x00A0, iwl9462_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x02F0, 0x00A4, iwl9462_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x02F0, 0x0230, iwl9560_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x02F0, 0x0234, iwl9560_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x02F0, 0x0238, iwl9560_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x02F0, 0x023C, iwl9560_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x02F0, 0x0260, iwl9461_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x02F0, 0x0264, iwl9461_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x02F0, 0x02A0, iwl9462_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x02F0, 0x02A4, iwl9462_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x02F0, 0x1551, iwl9560_killer_s_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x02F0, 0x1552, iwl9560_killer_i_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x02F0, 0x2030, iwl9560_2ac_160_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x02F0, 0x2034, iwl9560_2ac_160_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x02F0, 0x4030, iwl9560_2ac_160_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x02F0, 0x4034, iwl9560_2ac_160_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x02F0, 0x40A4, iwl9462_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x02F0, 0x4234, iwl9560_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x02F0, 0x42A4, iwl9462_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x06F0, 0x0030, iwl9560_2ac_160_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x06F0, 0x0034, iwl9560_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x06F0, 0x0038, iwl9560_2ac_160_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x06F0, 0x003C, iwl9560_2ac_160_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x06F0, 0x0060, iwl9461_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x06F0, 0x0064, iwl9461_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x06F0, 0x00A0, iwl9462_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x06F0, 0x00A4, iwl9462_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x06F0, 0x0230, iwl9560_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x06F0, 0x0234, iwl9560_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x06F0, 0x0238, iwl9560_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x06F0, 0x023C, iwl9560_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x06F0, 0x0260, iwl9461_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x06F0, 0x0264, iwl9461_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x06F0, 0x02A0, iwl9462_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x06F0, 0x02A4, iwl9462_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x06F0, 0x1551, iwl9560_killer_s_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x06F0, 0x1552, iwl9560_killer_i_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x06F0, 0x2030, iwl9560_2ac_160_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x06F0, 0x2034, iwl9560_2ac_160_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x06F0, 0x4030, iwl9560_2ac_160_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x06F0, 0x4034, iwl9560_2ac_160_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x06F0, 0x40A4, iwl9462_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x06F0, 0x4234, iwl9560_2ac_cfg_quz_a0_jf_b0_soc)},
+ {IWL_PCI_DEVICE(0x06F0, 0x42A4, iwl9462_2ac_cfg_quz_a0_jf_b0_soc)},
{IWL_PCI_DEVICE(0x2526, 0x0010, iwl9260_2ac_160_cfg)},
{IWL_PCI_DEVICE(0x2526, 0x0014, iwl9260_2ac_160_cfg)},
{IWL_PCI_DEVICE(0x2526, 0x0018, iwl9260_2ac_160_cfg)},
@@ -610,6 +604,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x2526, 0x40A4, iwl9460_2ac_cfg)},
{IWL_PCI_DEVICE(0x2526, 0x4234, iwl9560_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x2526, 0x42A4, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x2526, 0x6014, iwl9260_2ac_160_cfg)},
{IWL_PCI_DEVICE(0x2526, 0x8014, iwl9260_2ac_160_cfg)},
{IWL_PCI_DEVICE(0x2526, 0x8010, iwl9260_2ac_160_cfg)},
{IWL_PCI_DEVICE(0x2526, 0xA014, iwl9260_2ac_160_cfg)},
@@ -621,7 +616,6 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x2720, 0x0034, iwl9560_2ac_160_cfg)},
{IWL_PCI_DEVICE(0x2720, 0x0038, iwl9560_2ac_160_cfg)},
{IWL_PCI_DEVICE(0x2720, 0x003C, iwl9560_2ac_160_cfg)},
- {IWL_PCI_DEVICE(0x2720, 0x0044, iwl_ax101_cfg_qu_hr)},
{IWL_PCI_DEVICE(0x2720, 0x0060, iwl9461_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x2720, 0x0064, iwl9461_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x2720, 0x00A0, iwl9462_2ac_cfg_soc)},
@@ -630,7 +624,6 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x2720, 0x0234, iwl9560_2ac_cfg)},
{IWL_PCI_DEVICE(0x2720, 0x0238, iwl9560_2ac_cfg)},
{IWL_PCI_DEVICE(0x2720, 0x023C, iwl9560_2ac_cfg)},
- {IWL_PCI_DEVICE(0x2720, 0x0244, iwl_ax101_cfg_qu_hr)},
{IWL_PCI_DEVICE(0x2720, 0x0260, iwl9461_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x2720, 0x0264, iwl9461_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x2720, 0x02A0, iwl9462_2ac_cfg_soc)},
@@ -708,7 +701,6 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x34F0, 0x0034, iwl9560_2ac_cfg_qu_b0_jf_b0)},
{IWL_PCI_DEVICE(0x34F0, 0x0038, iwl9560_2ac_160_cfg_qu_b0_jf_b0)},
{IWL_PCI_DEVICE(0x34F0, 0x003C, iwl9560_2ac_160_cfg_qu_b0_jf_b0)},
- {IWL_PCI_DEVICE(0x34F0, 0x0044, iwl_ax101_cfg_qu_hr)},
{IWL_PCI_DEVICE(0x34F0, 0x0060, iwl9461_2ac_cfg_qu_b0_jf_b0)},
{IWL_PCI_DEVICE(0x34F0, 0x0064, iwl9461_2ac_cfg_qu_b0_jf_b0)},
{IWL_PCI_DEVICE(0x34F0, 0x00A0, iwl9462_2ac_cfg_qu_b0_jf_b0)},
@@ -717,7 +709,6 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x34F0, 0x0234, iwl9560_2ac_cfg_qu_b0_jf_b0)},
{IWL_PCI_DEVICE(0x34F0, 0x0238, iwl9560_2ac_cfg_qu_b0_jf_b0)},
{IWL_PCI_DEVICE(0x34F0, 0x023C, iwl9560_2ac_cfg_qu_b0_jf_b0)},
- {IWL_PCI_DEVICE(0x34F0, 0x0244, iwl_ax101_cfg_qu_hr)},
{IWL_PCI_DEVICE(0x34F0, 0x0260, iwl9461_2ac_cfg_qu_b0_jf_b0)},
{IWL_PCI_DEVICE(0x34F0, 0x0264, iwl9461_2ac_cfg_qu_b0_jf_b0)},
{IWL_PCI_DEVICE(0x34F0, 0x02A0, iwl9462_2ac_cfg_qu_b0_jf_b0)},
@@ -764,7 +755,6 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x43F0, 0x0034, iwl9560_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x43F0, 0x0038, iwl9560_2ac_160_cfg_soc)},
{IWL_PCI_DEVICE(0x43F0, 0x003C, iwl9560_2ac_160_cfg_soc)},
- {IWL_PCI_DEVICE(0x43F0, 0x0044, iwl_ax101_cfg_qu_hr)},
{IWL_PCI_DEVICE(0x43F0, 0x0060, iwl9461_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x43F0, 0x0064, iwl9461_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x43F0, 0x00A0, iwl9462_2ac_cfg_soc)},
@@ -773,7 +763,6 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x43F0, 0x0234, iwl9560_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x43F0, 0x0238, iwl9560_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x43F0, 0x023C, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x43F0, 0x0244, iwl_ax101_cfg_qu_hr)},
{IWL_PCI_DEVICE(0x43F0, 0x0260, iwl9461_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x43F0, 0x0264, iwl9461_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x43F0, 0x02A0, iwl9462_2ac_cfg_soc)},
@@ -833,7 +822,6 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0xA0F0, 0x0034, iwl9560_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0xA0F0, 0x0038, iwl9560_2ac_160_cfg_soc)},
{IWL_PCI_DEVICE(0xA0F0, 0x003C, iwl9560_2ac_160_cfg_soc)},
- {IWL_PCI_DEVICE(0xA0F0, 0x0044, iwl_ax101_cfg_qu_hr)},
{IWL_PCI_DEVICE(0xA0F0, 0x0060, iwl9461_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0xA0F0, 0x0064, iwl9461_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0xA0F0, 0x00A0, iwl9462_2ac_cfg_soc)},
@@ -842,7 +830,6 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0xA0F0, 0x0234, iwl9560_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0xA0F0, 0x0238, iwl9560_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0xA0F0, 0x023C, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0xA0F0, 0x0244, iwl_ax101_cfg_qu_hr)},
{IWL_PCI_DEVICE(0xA0F0, 0x0260, iwl9461_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0xA0F0, 0x0264, iwl9461_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0xA0F0, 0x02A0, iwl9462_2ac_cfg_soc)},
@@ -890,63 +877,80 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x2720, 0x0030, iwl9560_2ac_cfg_qnj_jf_b0)},
/* 22000 Series */
- {IWL_PCI_DEVICE(0x02F0, 0x0070, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x02F0, 0x0074, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x02F0, 0x0078, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x02F0, 0x007C, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x02F0, 0x0310, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x02F0, 0x1651, killer1650s_2ax_cfg_qu_b0_hr_b0)},
- {IWL_PCI_DEVICE(0x02F0, 0x1652, killer1650i_2ax_cfg_qu_b0_hr_b0)},
- {IWL_PCI_DEVICE(0x02F0, 0x4070, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x06F0, 0x0070, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x06F0, 0x0074, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x06F0, 0x0078, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x06F0, 0x007C, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x06F0, 0x0310, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x06F0, 0x1651, killer1650s_2ax_cfg_qu_b0_hr_b0)},
- {IWL_PCI_DEVICE(0x06F0, 0x1652, killer1650i_2ax_cfg_qu_b0_hr_b0)},
- {IWL_PCI_DEVICE(0x06F0, 0x4070, iwl_ax101_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0x02F0, 0x0070, iwl_ax201_cfg_quz_hr)},
+ {IWL_PCI_DEVICE(0x02F0, 0x0074, iwl_ax201_cfg_quz_hr)},
+ {IWL_PCI_DEVICE(0x02F0, 0x0078, iwl_ax201_cfg_quz_hr)},
+ {IWL_PCI_DEVICE(0x02F0, 0x007C, iwl_ax201_cfg_quz_hr)},
+ {IWL_PCI_DEVICE(0x02F0, 0x0244, iwl_ax101_cfg_quz_hr)},
+ {IWL_PCI_DEVICE(0x02F0, 0x0310, iwl_ax201_cfg_quz_hr)},
+ {IWL_PCI_DEVICE(0x02F0, 0x1651, iwl_ax1650s_cfg_quz_hr)},
+ {IWL_PCI_DEVICE(0x02F0, 0x1652, iwl_ax1650i_cfg_quz_hr)},
+ {IWL_PCI_DEVICE(0x02F0, 0x2074, iwl_ax201_cfg_quz_hr)},
+ {IWL_PCI_DEVICE(0x02F0, 0x4070, iwl_ax201_cfg_quz_hr)},
+ {IWL_PCI_DEVICE(0x02F0, 0x4244, iwl_ax101_cfg_quz_hr)},
+ {IWL_PCI_DEVICE(0x06F0, 0x0070, iwl_ax201_cfg_quz_hr)},
+ {IWL_PCI_DEVICE(0x06F0, 0x0074, iwl_ax201_cfg_quz_hr)},
+ {IWL_PCI_DEVICE(0x06F0, 0x0078, iwl_ax201_cfg_quz_hr)},
+ {IWL_PCI_DEVICE(0x06F0, 0x007C, iwl_ax201_cfg_quz_hr)},
+ {IWL_PCI_DEVICE(0x06F0, 0x0244, iwl_ax101_cfg_quz_hr)},
+ {IWL_PCI_DEVICE(0x06F0, 0x0310, iwl_ax201_cfg_quz_hr)},
+ {IWL_PCI_DEVICE(0x06F0, 0x1651, iwl_ax1650s_cfg_quz_hr)},
+ {IWL_PCI_DEVICE(0x06F0, 0x1652, iwl_ax1650i_cfg_quz_hr)},
+ {IWL_PCI_DEVICE(0x06F0, 0x2074, iwl_ax201_cfg_quz_hr)},
+ {IWL_PCI_DEVICE(0x06F0, 0x4070, iwl_ax201_cfg_quz_hr)},
+ {IWL_PCI_DEVICE(0x06F0, 0x4244, iwl_ax101_cfg_quz_hr)},
{IWL_PCI_DEVICE(0x2720, 0x0000, iwl_ax101_cfg_qu_hr)},
{IWL_PCI_DEVICE(0x2720, 0x0040, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x2720, 0x0070, iwl22000_2ac_cfg_hr_cdb)},
- {IWL_PCI_DEVICE(0x2720, 0x0074, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x2720, 0x0078, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x2720, 0x007C, iwl_ax101_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0x2720, 0x0044, iwl_ax101_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0x2720, 0x0070, iwl_ax201_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0x2720, 0x0074, iwl_ax201_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0x2720, 0x0078, iwl_ax201_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0x2720, 0x007C, iwl_ax201_cfg_qu_hr)},
{IWL_PCI_DEVICE(0x2720, 0x0090, iwl22000_2ac_cfg_hr_cdb)},
- {IWL_PCI_DEVICE(0x2720, 0x0310, iwl22000_2ac_cfg_hr_cdb)},
- {IWL_PCI_DEVICE(0x2720, 0x0A10, iwl22000_2ac_cfg_hr_cdb)},
+ {IWL_PCI_DEVICE(0x2720, 0x0244, iwl_ax101_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0x2720, 0x0310, iwl_ax201_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0x2720, 0x0A10, iwl_ax201_cfg_qu_hr)},
{IWL_PCI_DEVICE(0x2720, 0x1080, iwl_ax101_cfg_qu_hr)},
{IWL_PCI_DEVICE(0x2720, 0x1651, killer1650s_2ax_cfg_qu_b0_hr_b0)},
{IWL_PCI_DEVICE(0x2720, 0x1652, killer1650i_2ax_cfg_qu_b0_hr_b0)},
- {IWL_PCI_DEVICE(0x2720, 0x4070, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x34F0, 0x0040, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x34F0, 0x0070, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x34F0, 0x0074, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x34F0, 0x0078, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x34F0, 0x007C, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x34F0, 0x0310, iwl_ax101_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0x2720, 0x2074, iwl_ax201_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0x2720, 0x4070, iwl_ax201_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0x2720, 0x4244, iwl_ax101_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0x34F0, 0x0044, iwl_ax101_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0x34F0, 0x0070, iwl_ax201_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0x34F0, 0x0074, iwl_ax201_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0x34F0, 0x0078, iwl_ax201_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0x34F0, 0x007C, iwl_ax201_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0x34F0, 0x0244, iwl_ax101_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0x34F0, 0x0310, iwl_ax201_cfg_qu_hr)},
{IWL_PCI_DEVICE(0x34F0, 0x1651, killer1650s_2ax_cfg_qu_b0_hr_b0)},
{IWL_PCI_DEVICE(0x34F0, 0x1652, killer1650i_2ax_cfg_qu_b0_hr_b0)},
- {IWL_PCI_DEVICE(0x34F0, 0x4070, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x43F0, 0x0040, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x43F0, 0x0070, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x43F0, 0x0074, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x43F0, 0x0078, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0x43F0, 0x007C, iwl_ax101_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0x34F0, 0x2074, iwl_ax201_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0x34F0, 0x4070, iwl_ax201_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0x34F0, 0x4244, iwl_ax101_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0x43F0, 0x0044, iwl_ax101_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0x43F0, 0x0070, iwl_ax201_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0x43F0, 0x0074, iwl_ax201_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0x43F0, 0x0078, iwl_ax201_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0x43F0, 0x007C, iwl_ax201_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0x43F0, 0x0244, iwl_ax101_cfg_qu_hr)},
{IWL_PCI_DEVICE(0x43F0, 0x1651, killer1650s_2ax_cfg_qu_b0_hr_b0)},
{IWL_PCI_DEVICE(0x43F0, 0x1652, killer1650i_2ax_cfg_qu_b0_hr_b0)},
- {IWL_PCI_DEVICE(0x43F0, 0x4070, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0xA0F0, 0x0000, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0xA0F0, 0x0040, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0xA0F0, 0x0070, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0xA0F0, 0x0074, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0xA0F0, 0x0078, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0xA0F0, 0x007C, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0xA0F0, 0x00B0, iwl_ax101_cfg_qu_hr)},
- {IWL_PCI_DEVICE(0xA0F0, 0x0A10, iwl_ax101_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0x43F0, 0x2074, iwl_ax201_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0x43F0, 0x4070, iwl_ax201_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0x43F0, 0x4244, iwl_ax101_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x0044, iwl_ax101_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x0070, iwl_ax201_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x0074, iwl_ax201_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x0078, iwl_ax201_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x007C, iwl_ax201_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x0244, iwl_ax101_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x0A10, iwl_ax201_cfg_qu_hr)},
{IWL_PCI_DEVICE(0xA0F0, 0x1651, killer1650s_2ax_cfg_qu_b0_hr_b0)},
{IWL_PCI_DEVICE(0xA0F0, 0x1652, killer1650i_2ax_cfg_qu_b0_hr_b0)},
- {IWL_PCI_DEVICE(0xA0F0, 0x4070, iwl_ax101_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x2074, iwl_ax201_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x4070, iwl_ax201_cfg_qu_hr)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x4244, iwl_ax101_cfg_qu_hr)},
{IWL_PCI_DEVICE(0x2723, 0x0080, iwl_ax200_cfg_cc)},
{IWL_PCI_DEVICE(0x2723, 0x0084, iwl_ax200_cfg_cc)},
@@ -958,13 +962,20 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x2723, 0x4080, iwl_ax200_cfg_cc)},
{IWL_PCI_DEVICE(0x2723, 0x4088, iwl_ax200_cfg_cc)},
- {IWL_PCI_DEVICE(0x2725, 0x0090, iwlax210_2ax_cfg_so_hr_a0)},
- {IWL_PCI_DEVICE(0x7A70, 0x0090, iwlax210_2ax_cfg_so_hr_a0)},
- {IWL_PCI_DEVICE(0x7A70, 0x0310, iwlax210_2ax_cfg_so_hr_a0)},
- {IWL_PCI_DEVICE(0x2725, 0x0020, iwlax210_2ax_cfg_so_hr_a0)},
- {IWL_PCI_DEVICE(0x2725, 0x0310, iwlax210_2ax_cfg_so_hr_a0)},
- {IWL_PCI_DEVICE(0x2725, 0x0A10, iwlax210_2ax_cfg_so_hr_a0)},
- {IWL_PCI_DEVICE(0x2725, 0x00B0, iwlax210_2ax_cfg_so_hr_a0)},
+ {IWL_PCI_DEVICE(0x2725, 0x0090, iwlax211_2ax_cfg_so_gf_a0)},
+ {IWL_PCI_DEVICE(0x2725, 0x0020, iwlax210_2ax_cfg_ty_gf_a0)},
+ {IWL_PCI_DEVICE(0x2725, 0x0310, iwlax210_2ax_cfg_ty_gf_a0)},
+ {IWL_PCI_DEVICE(0x2725, 0x0510, iwlax210_2ax_cfg_ty_gf_a0)},
+ {IWL_PCI_DEVICE(0x2725, 0x0A10, iwlax210_2ax_cfg_ty_gf_a0)},
+ {IWL_PCI_DEVICE(0x2725, 0x00B0, iwlax411_2ax_cfg_so_gf4_a0)},
+ {IWL_PCI_DEVICE(0x7A70, 0x0090, iwlax211_2ax_cfg_so_gf_a0)},
+ {IWL_PCI_DEVICE(0x7A70, 0x0310, iwlax211_2ax_cfg_so_gf_a0)},
+ {IWL_PCI_DEVICE(0x7A70, 0x0510, iwlax211_2ax_cfg_so_gf_a0)},
+ {IWL_PCI_DEVICE(0x7A70, 0x0A10, iwlax211_2ax_cfg_so_gf_a0)},
+ {IWL_PCI_DEVICE(0x7AF0, 0x0090, iwlax211_2ax_cfg_so_gf_a0)},
+ {IWL_PCI_DEVICE(0x7AF0, 0x0310, iwlax211_2ax_cfg_so_gf_a0)},
+ {IWL_PCI_DEVICE(0x7AF0, 0x0510, iwlax211_2ax_cfg_so_gf_a0)},
+ {IWL_PCI_DEVICE(0x7AF0, 0x0A10, iwlax211_2ax_cfg_so_gf_a0)},
#endif /* CONFIG_IWLMVM */
@@ -1028,6 +1039,27 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
iwl_trans->cfg = cfg;
}
+
+ /*
+ * This is a hack to switch from Qu B0 to Qu C0. We need to
+ * do this for all cfgs that use Qu B0. All this code is in
+ * urgent need for a refactor, but for now this is the easiest
+ * thing to do to support Qu C-step.
+ */
+ if (iwl_trans->hw_rev == CSR_HW_REV_TYPE_QU_C0) {
+ if (iwl_trans->cfg == &iwl_ax101_cfg_qu_hr)
+ iwl_trans->cfg = &iwl_ax101_cfg_qu_c0_hr_b0;
+ else if (iwl_trans->cfg == &iwl_ax201_cfg_qu_hr)
+ iwl_trans->cfg = &iwl_ax201_cfg_qu_c0_hr_b0;
+ else if (iwl_trans->cfg == &iwl9461_2ac_cfg_qu_b0_jf_b0)
+ iwl_trans->cfg = &iwl9461_2ac_cfg_qu_c0_jf_b0;
+ else if (iwl_trans->cfg == &iwl9462_2ac_cfg_qu_b0_jf_b0)
+ iwl_trans->cfg = &iwl9462_2ac_cfg_qu_c0_jf_b0;
+ else if (iwl_trans->cfg == &iwl9560_2ac_cfg_qu_b0_jf_b0)
+ iwl_trans->cfg = &iwl9560_2ac_cfg_qu_c0_jf_b0;
+ else if (iwl_trans->cfg == &iwl9560_2ac_160_cfg_qu_b0_jf_b0)
+ iwl_trans->cfg = &iwl9560_2ac_160_cfg_qu_c0_jf_b0;
+ }
#endif
pci_set_drvdata(pdev, iwl_trans);
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
index b513037dc066..9f5d0fc839fe 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
@@ -874,6 +874,33 @@ static inline void iwl_enable_fw_load_int(struct iwl_trans *trans)
}
}
+static inline void iwl_enable_fw_load_int_ctx_info(struct iwl_trans *trans)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+ IWL_DEBUG_ISR(trans, "Enabling ALIVE interrupt only\n");
+
+ if (!trans_pcie->msix_enabled) {
+ /*
+ * When we'll receive the ALIVE interrupt, the ISR will call
+ * iwl_enable_fw_load_int_ctx_info again to set the ALIVE
+ * interrupt (which is not really needed anymore) but also the
+ * RX interrupt which will allow us to receive the ALIVE
+ * notification (which is Rx) and continue the flow.
+ */
+ trans_pcie->inta_mask = CSR_INT_BIT_ALIVE | CSR_INT_BIT_FH_RX;
+ iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask);
+ } else {
+ iwl_enable_hw_int_msk_msix(trans,
+ MSIX_HW_INT_CAUSES_REG_ALIVE);
+ /*
+ * Leave all the FH causes enabled to get the ALIVE
+ * notification.
+ */
+ iwl_enable_fh_int_msk_msix(trans, trans_pcie->fh_init_mask);
+ }
+}
+
static inline u16 iwl_pcie_get_cmd_index(const struct iwl_txq *q, u32 index)
{
return index & (q->n_window - 1);
@@ -928,7 +955,7 @@ static inline void iwl_enable_rfkill_int(struct iwl_trans *trans)
MSIX_HW_INT_CAUSES_REG_RF_KILL);
}
- if (trans->cfg->device_family == IWL_DEVICE_FAMILY_9000) {
+ if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_9000) {
/*
* On 9000-series devices this bit isn't enabled by default, so
* when we power down the device we need set the bit to allow it
@@ -1018,7 +1045,7 @@ static inline void __iwl_trans_pcie_set_bit(struct iwl_trans *trans,
static inline bool iwl_pcie_dbg_on(struct iwl_trans *trans)
{
- return (trans->dbg_dest_tlv || trans->ini_valid);
+ return (trans->dbg.dest_tlv || trans->dbg.ini_valid);
}
void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state);
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
index 31b3591f71d1..a2d709642b2a 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
@@ -1827,26 +1827,26 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
goto out;
}
- if (iwl_have_debug_level(IWL_DL_ISR)) {
- /* NIC fires this, but we don't use it, redundant with WAKEUP */
- if (inta & CSR_INT_BIT_SCD) {
- IWL_DEBUG_ISR(trans,
- "Scheduler finished to transmit the frame/frames.\n");
- isr_stats->sch++;
- }
+ /* NIC fires this, but we don't use it, redundant with WAKEUP */
+ if (inta & CSR_INT_BIT_SCD) {
+ IWL_DEBUG_ISR(trans,
+ "Scheduler finished to transmit the frame/frames.\n");
+ isr_stats->sch++;
+ }
- /* Alive notification via Rx interrupt will do the real work */
- if (inta & CSR_INT_BIT_ALIVE) {
- IWL_DEBUG_ISR(trans, "Alive interrupt\n");
- isr_stats->alive++;
- if (trans->cfg->gen2) {
- /*
- * We can restock, since firmware configured
- * the RFH
- */
- iwl_pcie_rxmq_restock(trans, trans_pcie->rxq);
- }
+ /* Alive notification via Rx interrupt will do the real work */
+ if (inta & CSR_INT_BIT_ALIVE) {
+ IWL_DEBUG_ISR(trans, "Alive interrupt\n");
+ isr_stats->alive++;
+ if (trans->cfg->gen2) {
+ /*
+ * We can restock, since firmware configured
+ * the RFH
+ */
+ iwl_pcie_rxmq_restock(trans, trans_pcie->rxq);
}
+
+ handled |= CSR_INT_BIT_ALIVE;
}
/* Safely ignore these bits for debug checks below */
@@ -1965,6 +1965,9 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
/* Re-enable RF_KILL if it occurred */
else if (handled & CSR_INT_BIT_RF_KILL)
iwl_enable_rfkill_int(trans);
+ /* Re-enable the ALIVE / Rx interrupt if it occurred */
+ else if (handled & (CSR_INT_BIT_ALIVE | CSR_INT_BIT_FH_RX))
+ iwl_enable_fw_load_int_ctx_info(trans);
spin_unlock(&trans_pcie->irq_lock);
out:
@@ -2108,10 +2111,18 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id)
return IRQ_NONE;
}
- if (iwl_have_debug_level(IWL_DL_ISR))
- IWL_DEBUG_ISR(trans, "ISR inta_fh 0x%08x, enabled 0x%08x\n",
- inta_fh,
+ if (iwl_have_debug_level(IWL_DL_ISR)) {
+ IWL_DEBUG_ISR(trans,
+ "ISR inta_fh 0x%08x, enabled (sw) 0x%08x (hw) 0x%08x\n",
+ inta_fh, trans_pcie->fh_mask,
iwl_read32(trans, CSR_MSIX_FH_INT_MASK_AD));
+ if (inta_fh & ~trans_pcie->fh_mask)
+ IWL_DEBUG_ISR(trans,
+ "We got a masked interrupt (0x%08x)\n",
+ inta_fh & ~trans_pcie->fh_mask);
+ }
+
+ inta_fh &= trans_pcie->fh_mask;
if ((trans_pcie->shared_vec_mask & IWL_SHARED_IRQ_NON_RX) &&
inta_fh & MSIX_FH_INT_CAUSES_Q0) {
@@ -2151,11 +2162,18 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id)
}
/* After checking FH register check HW register */
- if (iwl_have_debug_level(IWL_DL_ISR))
+ if (iwl_have_debug_level(IWL_DL_ISR)) {
IWL_DEBUG_ISR(trans,
- "ISR inta_hw 0x%08x, enabled 0x%08x\n",
- inta_hw,
+ "ISR inta_hw 0x%08x, enabled (sw) 0x%08x (hw) 0x%08x\n",
+ inta_hw, trans_pcie->hw_mask,
iwl_read32(trans, CSR_MSIX_HW_INT_MASK_AD));
+ if (inta_hw & ~trans_pcie->hw_mask)
+ IWL_DEBUG_ISR(trans,
+ "We got a masked interrupt 0x%08x\n",
+ inta_hw & ~trans_pcie->hw_mask);
+ }
+
+ inta_hw &= trans_pcie->hw_mask;
/* Alive notification via Rx interrupt will do the real work */
if (inta_hw & MSIX_HW_INT_CAUSES_REG_ALIVE) {
@@ -2212,7 +2230,7 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id)
"Hardware error detected. Restarting.\n");
isr_stats->hw++;
- trans->hw_error = true;
+ trans->dbg.hw_error = true;
iwl_pcie_irq_handle_error(trans);
}
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c
index 8507a7bdcfdd..8d17e68577fd 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c
@@ -148,7 +148,7 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power)
trans_pcie->is_down = true;
/* Stop dbgc before stopping device */
- _iwl_fw_dbg_stop_recording(trans, NULL);
+ iwl_fw_dbg_stop_recording(trans, NULL);
/* tell the device to stop sending interrupts */
iwl_disable_interrupts(trans);
@@ -273,6 +273,15 @@ void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans, u32 scd_addr)
* paging memory cannot be freed included since FW will still use it
*/
iwl_pcie_ctxt_info_free(trans);
+
+ /*
+ * Re-enable all the interrupts, including the RF-Kill one, now that
+ * the firmware is alive.
+ */
+ iwl_enable_interrupts(trans);
+ mutex_lock(&trans_pcie->mutex);
+ iwl_pcie_check_hw_rf_kill(trans);
+ mutex_unlock(&trans_pcie->mutex);
}
int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans,
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index 803fcbac4152..f5df5b370d78 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -90,8 +90,10 @@
void iwl_trans_pcie_dump_regs(struct iwl_trans *trans)
{
-#define PCI_DUMP_SIZE 64
-#define PREFIX_LEN 32
+#define PCI_DUMP_SIZE 352
+#define PCI_MEM_DUMP_SIZE 64
+#define PCI_PARENT_DUMP_SIZE 524
+#define PREFIX_LEN 32
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct pci_dev *pdev = trans_pcie->pci_dev;
u32 i, pos, alloc_size, *ptr, *buf;
@@ -102,11 +104,15 @@ void iwl_trans_pcie_dump_regs(struct iwl_trans *trans)
/* Should be a multiple of 4 */
BUILD_BUG_ON(PCI_DUMP_SIZE > 4096 || PCI_DUMP_SIZE & 0x3);
+ BUILD_BUG_ON(PCI_MEM_DUMP_SIZE > 4096 || PCI_MEM_DUMP_SIZE & 0x3);
+ BUILD_BUG_ON(PCI_PARENT_DUMP_SIZE > 4096 || PCI_PARENT_DUMP_SIZE & 0x3);
+
/* Alloc a max size buffer */
- if (PCI_ERR_ROOT_ERR_SRC + 4 > PCI_DUMP_SIZE)
- alloc_size = PCI_ERR_ROOT_ERR_SRC + 4 + PREFIX_LEN;
- else
- alloc_size = PCI_DUMP_SIZE + PREFIX_LEN;
+ alloc_size = PCI_ERR_ROOT_ERR_SRC + 4 + PREFIX_LEN;
+ alloc_size = max_t(u32, alloc_size, PCI_DUMP_SIZE + PREFIX_LEN);
+ alloc_size = max_t(u32, alloc_size, PCI_MEM_DUMP_SIZE + PREFIX_LEN);
+ alloc_size = max_t(u32, alloc_size, PCI_PARENT_DUMP_SIZE + PREFIX_LEN);
+
buf = kmalloc(alloc_size, GFP_ATOMIC);
if (!buf)
return;
@@ -123,7 +129,7 @@ void iwl_trans_pcie_dump_regs(struct iwl_trans *trans)
print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0);
IWL_ERR(trans, "iwlwifi device memory mapped registers:\n");
- for (i = 0, ptr = buf; i < PCI_DUMP_SIZE; i += 4, ptr++)
+ for (i = 0, ptr = buf; i < PCI_MEM_DUMP_SIZE; i += 4, ptr++)
*ptr = iwl_read32(trans, i);
print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0);
@@ -146,7 +152,7 @@ void iwl_trans_pcie_dump_regs(struct iwl_trans *trans)
IWL_ERR(trans, "iwlwifi parent port (%s) config registers:\n",
pci_name(pdev));
- for (i = 0, ptr = buf; i < PCI_DUMP_SIZE; i += 4, ptr++)
+ for (i = 0, ptr = buf; i < PCI_PARENT_DUMP_SIZE; i += 4, ptr++)
if (pci_read_config_dword(pdev, i, ptr))
goto err_read;
print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0);
@@ -188,14 +194,14 @@ static void iwl_pcie_free_fw_monitor(struct iwl_trans *trans)
{
int i;
- for (i = 0; i < trans->num_blocks; i++) {
- dma_free_coherent(trans->dev, trans->fw_mon[i].size,
- trans->fw_mon[i].block,
- trans->fw_mon[i].physical);
- trans->fw_mon[i].block = NULL;
- trans->fw_mon[i].physical = 0;
- trans->fw_mon[i].size = 0;
- trans->num_blocks--;
+ for (i = 0; i < trans->dbg.num_blocks; i++) {
+ dma_free_coherent(trans->dev, trans->dbg.fw_mon[i].size,
+ trans->dbg.fw_mon[i].block,
+ trans->dbg.fw_mon[i].physical);
+ trans->dbg.fw_mon[i].block = NULL;
+ trans->dbg.fw_mon[i].physical = 0;
+ trans->dbg.fw_mon[i].size = 0;
+ trans->dbg.num_blocks--;
}
}
@@ -230,10 +236,10 @@ static void iwl_pcie_alloc_fw_monitor_block(struct iwl_trans *trans,
(unsigned long)BIT(power - 10),
(unsigned long)BIT(max_power - 10));
- trans->fw_mon[trans->num_blocks].block = cpu_addr;
- trans->fw_mon[trans->num_blocks].physical = phys;
- trans->fw_mon[trans->num_blocks].size = size;
- trans->num_blocks++;
+ trans->dbg.fw_mon[trans->dbg.num_blocks].block = cpu_addr;
+ trans->dbg.fw_mon[trans->dbg.num_blocks].physical = phys;
+ trans->dbg.fw_mon[trans->dbg.num_blocks].size = size;
+ trans->dbg.num_blocks++;
}
void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power)
@@ -254,7 +260,7 @@ void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power)
* This function allocats the default fw monitor.
* The optional additional ones will be allocated in runtime
*/
- if (trans->num_blocks)
+ if (trans->dbg.num_blocks)
return;
iwl_pcie_alloc_fw_monitor_block(trans, max_power, 11);
@@ -889,21 +895,21 @@ static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans,
void iwl_pcie_apply_destination(struct iwl_trans *trans)
{
- const struct iwl_fw_dbg_dest_tlv_v1 *dest = trans->dbg_dest_tlv;
+ const struct iwl_fw_dbg_dest_tlv_v1 *dest = trans->dbg.dest_tlv;
int i;
- if (trans->ini_valid) {
- if (!trans->num_blocks)
+ if (trans->dbg.ini_valid) {
+ if (!trans->dbg.num_blocks)
return;
IWL_DEBUG_FW(trans,
"WRT: applying DRAM buffer[0] destination\n");
iwl_write_umac_prph(trans, MON_BUFF_BASE_ADDR_VER2,
- trans->fw_mon[0].physical >>
+ trans->dbg.fw_mon[0].physical >>
MON_BUFF_SHIFT_VER2);
iwl_write_umac_prph(trans, MON_BUFF_END_ADDR_VER2,
- (trans->fw_mon[0].physical +
- trans->fw_mon[0].size - 256) >>
+ (trans->dbg.fw_mon[0].physical +
+ trans->dbg.fw_mon[0].size - 256) >>
MON_BUFF_SHIFT_VER2);
return;
}
@@ -916,7 +922,7 @@ void iwl_pcie_apply_destination(struct iwl_trans *trans)
else
IWL_WARN(trans, "PCI should have external buffer debug\n");
- for (i = 0; i < trans->dbg_n_dest_reg; i++) {
+ for (i = 0; i < trans->dbg.n_dest_reg; i++) {
u32 addr = le32_to_cpu(dest->reg_ops[i].addr);
u32 val = le32_to_cpu(dest->reg_ops[i].val);
@@ -955,18 +961,19 @@ void iwl_pcie_apply_destination(struct iwl_trans *trans)
}
monitor:
- if (dest->monitor_mode == EXTERNAL_MODE && trans->fw_mon[0].size) {
+ if (dest->monitor_mode == EXTERNAL_MODE && trans->dbg.fw_mon[0].size) {
iwl_write_prph(trans, le32_to_cpu(dest->base_reg),
- trans->fw_mon[0].physical >> dest->base_shift);
+ trans->dbg.fw_mon[0].physical >>
+ dest->base_shift);
if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000)
iwl_write_prph(trans, le32_to_cpu(dest->end_reg),
- (trans->fw_mon[0].physical +
- trans->fw_mon[0].size - 256) >>
+ (trans->dbg.fw_mon[0].physical +
+ trans->dbg.fw_mon[0].size - 256) >>
dest->end_shift);
else
iwl_write_prph(trans, le32_to_cpu(dest->end_reg),
- (trans->fw_mon[0].physical +
- trans->fw_mon[0].size) >>
+ (trans->dbg.fw_mon[0].physical +
+ trans->dbg.fw_mon[0].size) >>
dest->end_shift);
}
}
@@ -1003,12 +1010,12 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
iwl_pcie_alloc_fw_monitor(trans, 0);
- if (trans->fw_mon[0].size) {
+ if (trans->dbg.fw_mon[0].size) {
iwl_write_prph(trans, MON_BUFF_BASE_ADDR,
- trans->fw_mon[0].physical >> 4);
+ trans->dbg.fw_mon[0].physical >> 4);
iwl_write_prph(trans, MON_BUFF_END_ADDR,
- (trans->fw_mon[0].physical +
- trans->fw_mon[0].size) >> 4);
+ (trans->dbg.fw_mon[0].physical +
+ trans->dbg.fw_mon[0].size) >> 4);
}
} else if (iwl_pcie_dbg_on(trans)) {
iwl_pcie_apply_destination(trans);
@@ -1236,7 +1243,7 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
trans_pcie->is_down = true;
/* Stop dbgc before stopping device */
- _iwl_fw_dbg_stop_recording(trans, NULL);
+ iwl_fw_dbg_stop_recording(trans, NULL);
/* tell the device to stop sending interrupts */
iwl_disable_interrupts(trans);
@@ -1698,26 +1705,26 @@ static int iwl_pcie_init_msix_handler(struct pci_dev *pdev,
return 0;
}
-static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power)
+static int iwl_trans_pcie_clear_persistence_bit(struct iwl_trans *trans)
{
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
- u32 hpm;
- int err;
-
- lockdep_assert_held(&trans_pcie->mutex);
+ u32 hpm, wprot;
- err = iwl_pcie_prepare_card_hw(trans);
- if (err) {
- IWL_ERR(trans, "Error while preparing HW: %d\n", err);
- return err;
+ switch (trans->cfg->device_family) {
+ case IWL_DEVICE_FAMILY_9000:
+ wprot = PREG_PRPH_WPROT_9000;
+ break;
+ case IWL_DEVICE_FAMILY_22000:
+ wprot = PREG_PRPH_WPROT_22000;
+ break;
+ default:
+ return 0;
}
hpm = iwl_read_umac_prph_no_grab(trans, HPM_DEBUG);
if (hpm != 0xa5a5a5a0 && (hpm & PERSISTENCE_BIT)) {
- int wfpm_val = iwl_read_umac_prph_no_grab(trans,
- PREG_PRPH_WPROT_0);
+ u32 wprot_val = iwl_read_umac_prph_no_grab(trans, wprot);
- if (wfpm_val & PREG_WFPM_ACCESS) {
+ if (wprot_val & PREG_WFPM_ACCESS) {
IWL_ERR(trans,
"Error, can not clear persistence bit\n");
return -EPERM;
@@ -1726,6 +1733,26 @@ static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power)
hpm & ~PERSISTENCE_BIT);
}
+ return 0;
+}
+
+static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ int err;
+
+ lockdep_assert_held(&trans_pcie->mutex);
+
+ err = iwl_pcie_prepare_card_hw(trans);
+ if (err) {
+ IWL_ERR(trans, "Error while preparing HW: %d\n", err);
+ return err;
+ }
+
+ err = iwl_trans_pcie_clear_persistence_bit(trans);
+ if (err)
+ return err;
+
iwl_trans_pcie_sw_reset(trans);
err = iwl_pcie_apm_init(trans);
@@ -2709,8 +2736,8 @@ static int iwl_dbgfs_monitor_data_open(struct inode *inode,
struct iwl_trans *trans = inode->i_private;
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
- if (!trans->dbg_dest_tlv ||
- trans->dbg_dest_tlv->monitor_mode != EXTERNAL_MODE) {
+ if (!trans->dbg.dest_tlv ||
+ trans->dbg.dest_tlv->monitor_mode != EXTERNAL_MODE) {
IWL_ERR(trans, "Debug destination is not set to DRAM\n");
return -ENOENT;
}
@@ -2757,22 +2784,22 @@ static ssize_t iwl_dbgfs_monitor_data_read(struct file *file,
{
struct iwl_trans *trans = file->private_data;
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
- void *cpu_addr = (void *)trans->fw_mon[0].block, *curr_buf;
+ void *cpu_addr = (void *)trans->dbg.fw_mon[0].block, *curr_buf;
struct cont_rec *data = &trans_pcie->fw_mon_data;
u32 write_ptr_addr, wrap_cnt_addr, write_ptr, wrap_cnt;
ssize_t size, bytes_copied = 0;
bool b_full;
- if (trans->dbg_dest_tlv) {
+ if (trans->dbg.dest_tlv) {
write_ptr_addr =
- le32_to_cpu(trans->dbg_dest_tlv->write_ptr_reg);
- wrap_cnt_addr = le32_to_cpu(trans->dbg_dest_tlv->wrap_count);
+ le32_to_cpu(trans->dbg.dest_tlv->write_ptr_reg);
+ wrap_cnt_addr = le32_to_cpu(trans->dbg.dest_tlv->wrap_count);
} else {
write_ptr_addr = MON_BUFF_WRPTR;
wrap_cnt_addr = MON_BUFF_CYCLE_CNT;
}
- if (unlikely(!trans->dbg_rec_on))
+ if (unlikely(!trans->dbg.rec_on))
return 0;
mutex_lock(&data->mutex);
@@ -2796,7 +2823,7 @@ static ssize_t iwl_dbgfs_monitor_data_read(struct file *file,
} else if (data->prev_wrap_cnt == wrap_cnt - 1 &&
write_ptr < data->prev_wr_ptr) {
- size = trans->fw_mon[0].size - data->prev_wr_ptr;
+ size = trans->dbg.fw_mon[0].size - data->prev_wr_ptr;
curr_buf = cpu_addr + data->prev_wr_ptr;
b_full = iwl_write_to_user_buf(user_buf, count,
curr_buf, &size,
@@ -3015,14 +3042,10 @@ iwl_trans_pcie_dump_pointers(struct iwl_trans *trans,
base_high = DBGC_CUR_DBGBUF_BASE_ADDR_MSB;
write_ptr = DBGC_CUR_DBGBUF_STATUS;
wrap_cnt = DBGC_DBGBUF_WRAP_AROUND;
- } else if (trans->ini_valid) {
- base = iwl_umac_prph(trans, MON_BUFF_BASE_ADDR_VER2);
- write_ptr = iwl_umac_prph(trans, MON_BUFF_WRPTR_VER2);
- wrap_cnt = iwl_umac_prph(trans, MON_BUFF_CYCLE_CNT_VER2);
- } else if (trans->dbg_dest_tlv) {
- write_ptr = le32_to_cpu(trans->dbg_dest_tlv->write_ptr_reg);
- wrap_cnt = le32_to_cpu(trans->dbg_dest_tlv->wrap_count);
- base = le32_to_cpu(trans->dbg_dest_tlv->base_reg);
+ } else if (trans->dbg.dest_tlv) {
+ write_ptr = le32_to_cpu(trans->dbg.dest_tlv->write_ptr_reg);
+ wrap_cnt = le32_to_cpu(trans->dbg.dest_tlv->wrap_count);
+ base = le32_to_cpu(trans->dbg.dest_tlv->base_reg);
} else {
base = MON_BUFF_BASE_ADDR;
write_ptr = MON_BUFF_WRPTR;
@@ -3049,11 +3072,10 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans,
{
u32 len = 0;
- if ((trans->num_blocks &&
+ if (trans->dbg.dest_tlv ||
+ (trans->dbg.num_blocks &&
(trans->cfg->device_family == IWL_DEVICE_FAMILY_7000 ||
- trans->cfg->device_family >= IWL_DEVICE_FAMILY_AX210 ||
- trans->ini_valid)) ||
- (trans->dbg_dest_tlv && !trans->ini_valid)) {
+ trans->cfg->device_family >= IWL_DEVICE_FAMILY_AX210))) {
struct iwl_fw_error_dump_fw_mon *fw_mon_data;
(*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_FW_MONITOR);
@@ -3062,32 +3084,32 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans,
iwl_trans_pcie_dump_pointers(trans, fw_mon_data);
len += sizeof(**data) + sizeof(*fw_mon_data);
- if (trans->num_blocks) {
+ if (trans->dbg.num_blocks) {
memcpy(fw_mon_data->data,
- trans->fw_mon[0].block,
- trans->fw_mon[0].size);
+ trans->dbg.fw_mon[0].block,
+ trans->dbg.fw_mon[0].size);
- monitor_len = trans->fw_mon[0].size;
- } else if (trans->dbg_dest_tlv->monitor_mode == SMEM_MODE) {
+ monitor_len = trans->dbg.fw_mon[0].size;
+ } else if (trans->dbg.dest_tlv->monitor_mode == SMEM_MODE) {
u32 base = le32_to_cpu(fw_mon_data->fw_mon_base_ptr);
/*
* Update pointers to reflect actual values after
* shifting
*/
- if (trans->dbg_dest_tlv->version) {
+ if (trans->dbg.dest_tlv->version) {
base = (iwl_read_prph(trans, base) &
IWL_LDBG_M2S_BUF_BA_MSK) <<
- trans->dbg_dest_tlv->base_shift;
+ trans->dbg.dest_tlv->base_shift;
base *= IWL_M2S_UNIT_SIZE;
base += trans->cfg->smem_offset;
} else {
base = iwl_read_prph(trans, base) <<
- trans->dbg_dest_tlv->base_shift;
+ trans->dbg.dest_tlv->base_shift;
}
iwl_trans_read_mem(trans, base, fw_mon_data->data,
monitor_len / sizeof(u32));
- } else if (trans->dbg_dest_tlv->monitor_mode == MARBH_MODE) {
+ } else if (trans->dbg.dest_tlv->monitor_mode == MARBH_MODE) {
monitor_len =
iwl_trans_pci_dump_marbh_monitor(trans,
fw_mon_data,
@@ -3106,40 +3128,40 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans,
static int iwl_trans_get_fw_monitor_len(struct iwl_trans *trans, u32 *len)
{
- if (trans->num_blocks) {
+ if (trans->dbg.num_blocks) {
*len += sizeof(struct iwl_fw_error_dump_data) +
sizeof(struct iwl_fw_error_dump_fw_mon) +
- trans->fw_mon[0].size;
- return trans->fw_mon[0].size;
- } else if (trans->dbg_dest_tlv) {
+ trans->dbg.fw_mon[0].size;
+ return trans->dbg.fw_mon[0].size;
+ } else if (trans->dbg.dest_tlv) {
u32 base, end, cfg_reg, monitor_len;
- if (trans->dbg_dest_tlv->version == 1) {
- cfg_reg = le32_to_cpu(trans->dbg_dest_tlv->base_reg);
+ if (trans->dbg.dest_tlv->version == 1) {
+ cfg_reg = le32_to_cpu(trans->dbg.dest_tlv->base_reg);
cfg_reg = iwl_read_prph(trans, cfg_reg);
base = (cfg_reg & IWL_LDBG_M2S_BUF_BA_MSK) <<
- trans->dbg_dest_tlv->base_shift;
+ trans->dbg.dest_tlv->base_shift;
base *= IWL_M2S_UNIT_SIZE;
base += trans->cfg->smem_offset;
monitor_len =
(cfg_reg & IWL_LDBG_M2S_BUF_SIZE_MSK) >>
- trans->dbg_dest_tlv->end_shift;
+ trans->dbg.dest_tlv->end_shift;
monitor_len *= IWL_M2S_UNIT_SIZE;
} else {
- base = le32_to_cpu(trans->dbg_dest_tlv->base_reg);
- end = le32_to_cpu(trans->dbg_dest_tlv->end_reg);
+ base = le32_to_cpu(trans->dbg.dest_tlv->base_reg);
+ end = le32_to_cpu(trans->dbg.dest_tlv->end_reg);
base = iwl_read_prph(trans, base) <<
- trans->dbg_dest_tlv->base_shift;
+ trans->dbg.dest_tlv->base_shift;
end = iwl_read_prph(trans, end) <<
- trans->dbg_dest_tlv->end_shift;
+ trans->dbg.dest_tlv->end_shift;
/* Make "end" point to the actual end */
if (trans->cfg->device_family >=
IWL_DEVICE_FAMILY_8000 ||
- trans->dbg_dest_tlv->monitor_mode == MARBH_MODE)
- end += (1 << trans->dbg_dest_tlv->end_shift);
+ trans->dbg.dest_tlv->monitor_mode == MARBH_MODE)
+ end += (1 << trans->dbg.dest_tlv->end_shift);
monitor_len = end - base;
}
*len += sizeof(struct iwl_fw_error_dump_data) +
@@ -3172,7 +3194,7 @@ static struct iwl_trans_dump_data
len = sizeof(*dump_data);
/* host commands */
- if (dump_mask & BIT(IWL_FW_ERROR_DUMP_TXCMD))
+ if (dump_mask & BIT(IWL_FW_ERROR_DUMP_TXCMD) && cmdq)
len += sizeof(*data) +
cmdq->n_window * (sizeof(*txcmd) +
TFD_MAX_PAYLOAD_SIZE);
@@ -3224,7 +3246,7 @@ static struct iwl_trans_dump_data
len = 0;
data = (void *)dump_data->data;
- if (dump_mask & BIT(IWL_FW_ERROR_DUMP_TXCMD)) {
+ if (dump_mask & BIT(IWL_FW_ERROR_DUMP_TXCMD) && cmdq) {
u16 tfd_size = trans_pcie->tfd_size;
data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_TXCMD);
@@ -3526,7 +3548,8 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
hw_step |= ENABLE_WFPM;
iwl_write_umac_prph_no_grab(trans, WFPM_CTRL_REG,
hw_step);
- hw_step = iwl_read_prph_no_grab(trans, AUX_MISC_REG);
+ hw_step = iwl_read_prph_no_grab(trans,
+ CNVI_AUX_MISC_CHIP);
hw_step = (hw_step >> HW_STEP_LOCATION_BITS) & 0xF;
if (hw_step == 0x3)
trans->hw_rev = (trans->hw_rev & 0xFFFFFFF3) |
@@ -3548,15 +3571,17 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
trans->cfg = &iwlax210_2ax_cfg_so_jf_a0;
} else if (CSR_HW_RF_ID_TYPE_CHIP_ID(trans->hw_rf_id) ==
CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_GF)) {
- trans->cfg = &iwlax210_2ax_cfg_so_gf_a0;
+ trans->cfg = &iwlax211_2ax_cfg_so_gf_a0;
} else if (CSR_HW_RF_ID_TYPE_CHIP_ID(trans->hw_rf_id) ==
CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_GF4)) {
- trans->cfg = &iwlax210_2ax_cfg_so_gf4_a0;
+ trans->cfg = &iwlax411_2ax_cfg_so_gf4_a0;
}
} else if (cfg == &iwl_ax101_cfg_qu_hr) {
- if (CSR_HW_RF_ID_TYPE_CHIP_ID(trans->hw_rf_id) ==
- CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_HR) &&
- trans->hw_rev == CSR_HW_REV_TYPE_QNJ_B0) {
+ if ((CSR_HW_RF_ID_TYPE_CHIP_ID(trans->hw_rf_id) ==
+ CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_HR) &&
+ trans->hw_rev == CSR_HW_REV_TYPE_QNJ_B0) ||
+ (CSR_HW_RF_ID_TYPE_CHIP_ID(trans->hw_rf_id) ==
+ CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_HR1))) {
trans->cfg = &iwl22000_2ax_cfg_qnj_hr_b0;
} else if (CSR_HW_RF_ID_TYPE_CHIP_ID(trans->hw_rf_id) ==
CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_HR)) {
@@ -3577,7 +3602,10 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
}
} else if (CSR_HW_RF_ID_TYPE_CHIP_ID(trans->hw_rf_id) ==
CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_HR) &&
- (trans->cfg != &iwl_ax200_cfg_cc ||
+ ((trans->cfg != &iwl_ax200_cfg_cc &&
+ trans->cfg != &killer1650x_2ax_cfg &&
+ trans->cfg != &killer1650w_2ax_cfg &&
+ trans->cfg != &iwl_ax201_cfg_quz_hr) ||
trans->hw_rev == CSR_HW_REV_TYPE_QNJ_B0)) {
u32 hw_status;
@@ -3658,6 +3686,7 @@ void iwl_trans_pcie_sync_nmi(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
unsigned long timeout = jiffies + IWL_TRANS_NMI_TIMEOUT;
+ bool interrupts_enabled = test_bit(STATUS_INT_ENABLED, &trans->status);
u32 inta_addr, sw_err_bit;
if (trans_pcie->msix_enabled) {
@@ -3668,7 +3697,12 @@ void iwl_trans_pcie_sync_nmi(struct iwl_trans *trans)
sw_err_bit = CSR_INT_BIT_SW_ERR;
}
- iwl_disable_interrupts(trans);
+ /* if the interrupts were already disabled, there is no point in
+ * calling iwl_disable_interrupts
+ */
+ if (interrupts_enabled)
+ iwl_disable_interrupts(trans);
+
iwl_force_nmi(trans);
while (time_after(timeout, jiffies)) {
u32 inta_hw = iwl_read32(trans, inta_addr);
@@ -3682,6 +3716,13 @@ void iwl_trans_pcie_sync_nmi(struct iwl_trans *trans)
mdelay(1);
}
- iwl_enable_interrupts(trans);
+
+ /* enable interrupts only if there were already enabled before this
+ * function to avoid a case were the driver enable interrupts before
+ * proper configurations were made
+ */
+ if (interrupts_enabled)
+ iwl_enable_interrupts(trans);
+
iwl_trans_fw_error(trans);
}
diff --git a/drivers/net/wireless/intersil/hostap/hostap_hw.c b/drivers/net/wireless/intersil/hostap/hostap_hw.c
index ad1aa65fee7f..158a3d762e55 100644
--- a/drivers/net/wireless/intersil/hostap/hostap_hw.c
+++ b/drivers/net/wireless/intersil/hostap/hostap_hw.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Host AP (software wireless LAN access point) driver for
* Intersil Prism2/2.5/3.
@@ -6,11 +7,6 @@
* <j@w1.fi>
* Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
*
- * 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. See README and COPYING for
- * more details.
- *
* FIX:
* - there is currently no way of associating TX packets to correct wds device
* when TX Exc/OK event occurs, so all tx_packets and some
diff --git a/drivers/net/wireless/intersil/hostap/hostap_main.c b/drivers/net/wireless/intersil/hostap/hostap_main.c
index b0e7c0a0617e..05466281afb6 100644
--- a/drivers/net/wireless/intersil/hostap/hostap_main.c
+++ b/drivers/net/wireless/intersil/hostap/hostap_main.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Host AP (software wireless LAN access point) driver for
* Intersil Prism2/2.5/3 - hostap.o module, common routines
@@ -5,11 +6,6 @@
* Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
* <j@w1.fi>
* Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
- *
- * 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. See README and COPYING for
- * more details.
*/
#include <linux/module.h>
diff --git a/drivers/net/wireless/intersil/p54/eeprom.c b/drivers/net/wireless/intersil/p54/eeprom.c
index de2ef95c386c..5bd35c147e19 100644
--- a/drivers/net/wireless/intersil/p54/eeprom.c
+++ b/drivers/net/wireless/intersil/p54/eeprom.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* EEPROM parser code for mac80211 Prism54 drivers
*
@@ -10,10 +11,6 @@
* Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
* - stlc45xx driver
* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
- *
- * 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.
*/
#include <linux/firmware.h>
diff --git a/drivers/net/wireless/intersil/p54/eeprom.h b/drivers/net/wireless/intersil/p54/eeprom.h
index 20ebe39a3f4e..b8f46883a292 100644
--- a/drivers/net/wireless/intersil/p54/eeprom.h
+++ b/drivers/net/wireless/intersil/p54/eeprom.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* eeprom specific definitions for mac80211 Prism54 drivers
*
@@ -13,10 +14,6 @@
*
* - islmvc driver
* Copyright (C) 2001 Intersil Americas 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.
*/
#ifndef EEPROM_H
diff --git a/drivers/net/wireless/intersil/p54/fwio.c b/drivers/net/wireless/intersil/p54/fwio.c
index 52c095c7765f..a5afcc865196 100644
--- a/drivers/net/wireless/intersil/p54/fwio.c
+++ b/drivers/net/wireless/intersil/p54/fwio.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Firmware I/O code for mac80211 Prism54 drivers
*
@@ -10,10 +11,6 @@
* Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
* - stlc45xx driver
* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
- *
- * 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.
*/
#include <linux/slab.h>
diff --git a/drivers/net/wireless/intersil/p54/led.c b/drivers/net/wireless/intersil/p54/led.c
index 9a8fedd3c0f5..4bc77010f9c1 100644
--- a/drivers/net/wireless/intersil/p54/led.c
+++ b/drivers/net/wireless/intersil/p54/led.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Common code for mac80211 Prism54 drivers
*
@@ -10,10 +11,6 @@
* Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
* - stlc45xx driver
* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
- *
- * 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.
*/
#include <linux/firmware.h>
diff --git a/drivers/net/wireless/intersil/p54/lmac.h b/drivers/net/wireless/intersil/p54/lmac.h
index de1d46bf97df..e00761536cfc 100644
--- a/drivers/net/wireless/intersil/p54/lmac.h
+++ b/drivers/net/wireless/intersil/p54/lmac.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* LMAC Interface specific definitions for mac80211 Prism54 drivers
*
@@ -10,10 +11,6 @@
*
* - LMAC API interface header file for STLC4560 (lmac_longbow.h)
* Copyright (C) 2007 Conexant Systems, 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.
*/
#ifndef LMAC_H
diff --git a/drivers/net/wireless/intersil/p54/main.c b/drivers/net/wireless/intersil/p54/main.c
index 1c6d428515a4..a3ca6620dc0c 100644
--- a/drivers/net/wireless/intersil/p54/main.c
+++ b/drivers/net/wireless/intersil/p54/main.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* mac80211 glue code for mac80211 Prism54 drivers
*
@@ -10,10 +11,6 @@
* Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
* - stlc45xx driver
* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
- *
- * 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.
*/
#include <linux/slab.h>
@@ -414,12 +411,9 @@ static int p54_conf_tx(struct ieee80211_hw *dev,
int ret;
mutex_lock(&priv->conf_mutex);
- if (queue < dev->queues) {
- P54_SET_QUEUE(priv->qos_params[queue], params->aifs,
- params->cw_min, params->cw_max, params->txop);
- ret = p54_set_edcf(priv);
- } else
- ret = -EINVAL;
+ P54_SET_QUEUE(priv->qos_params[queue], params->aifs,
+ params->cw_min, params->cw_max, params->txop);
+ ret = p54_set_edcf(priv);
mutex_unlock(&priv->conf_mutex);
return ret;
}
diff --git a/drivers/net/wireless/intersil/p54/p54.h b/drivers/net/wireless/intersil/p54/p54.h
index 529939e611cd..0a9c1a19380f 100644
--- a/drivers/net/wireless/intersil/p54/p54.h
+++ b/drivers/net/wireless/intersil/p54/p54.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Shared defines for all mac80211 Prism54 code
*
@@ -5,10 +6,6 @@
*
* Based on the islsm (softmac prism54) driver, which is:
* Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
- *
- * 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.
*/
#ifndef P54_H
diff --git a/drivers/net/wireless/intersil/p54/p54pci.c b/drivers/net/wireless/intersil/p54/p54pci.c
index 57ad56435dda..80ad0b7eaef4 100644
--- a/drivers/net/wireless/intersil/p54/p54pci.c
+++ b/drivers/net/wireless/intersil/p54/p54pci.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Linux device driver for PCI based Prism54
@@ -7,10 +8,6 @@
*
* Based on the islsm (softmac prism54) driver, which is:
* Copyright 2004-2006 Jean-Baptiste Note <jean-baptiste.note@m4x.org>, et al.
- *
- * 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.
*/
#include <linux/pci.h>
diff --git a/drivers/net/wireless/intersil/p54/p54pci.h b/drivers/net/wireless/intersil/p54/p54pci.h
index 68405c142f97..3867e5935ac4 100644
--- a/drivers/net/wireless/intersil/p54/p54pci.h
+++ b/drivers/net/wireless/intersil/p54/p54pci.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef P54PCI_H
#define P54PCI_H
#include <linux/interrupt.h>
@@ -9,10 +10,6 @@
*
* Based on the islsm (softmac prism54) driver, which is:
* Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
- *
- * 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.
*/
/* Device Interrupt register bits */
diff --git a/drivers/net/wireless/intersil/p54/p54usb.c b/drivers/net/wireless/intersil/p54/p54usb.c
index b0b86f701061..b94764c88750 100644
--- a/drivers/net/wireless/intersil/p54/p54usb.c
+++ b/drivers/net/wireless/intersil/p54/p54usb.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Linux device driver for USB based Prism54
@@ -6,10 +7,6 @@
*
* Based on the islsm (softmac prism54) driver, which is:
* Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
- *
- * 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.
*/
#include <linux/usb.h>
@@ -33,6 +30,8 @@ MODULE_ALIAS("prism54usb");
MODULE_FIRMWARE("isl3886usb");
MODULE_FIRMWARE("isl3887usb");
+static struct usb_driver p54u_driver;
+
/*
* Note:
*
@@ -921,9 +920,9 @@ static void p54u_load_firmware_cb(const struct firmware *firmware,
{
struct p54u_priv *priv = context;
struct usb_device *udev = priv->udev;
+ struct usb_interface *intf = priv->intf;
int err;
- complete(&priv->fw_wait_load);
if (firmware) {
priv->fw = firmware;
err = p54u_start_ops(priv);
@@ -932,26 +931,22 @@ static void p54u_load_firmware_cb(const struct firmware *firmware,
dev_err(&udev->dev, "Firmware not found.\n");
}
- if (err) {
- struct device *parent = priv->udev->dev.parent;
-
- dev_err(&udev->dev, "failed to initialize device (%d)\n", err);
-
- if (parent)
- device_lock(parent);
+ complete(&priv->fw_wait_load);
+ /*
+ * At this point p54u_disconnect may have already freed
+ * the "priv" context. Do not use it anymore!
+ */
+ priv = NULL;
- device_release_driver(&udev->dev);
- /*
- * At this point p54u_disconnect has already freed
- * the "priv" context. Do not use it anymore!
- */
- priv = NULL;
+ if (err) {
+ dev_err(&intf->dev, "failed to initialize device (%d)\n", err);
- if (parent)
- device_unlock(parent);
+ usb_lock_device(udev);
+ usb_driver_release_interface(&p54u_driver, intf);
+ usb_unlock_device(udev);
}
- usb_put_dev(udev);
+ usb_put_intf(intf);
}
static int p54u_load_firmware(struct ieee80211_hw *dev,
@@ -972,14 +967,14 @@ static int p54u_load_firmware(struct ieee80211_hw *dev,
dev_info(&priv->udev->dev, "Loading firmware file %s\n",
p54u_fwlist[i].fw);
- usb_get_dev(udev);
+ usb_get_intf(intf);
err = request_firmware_nowait(THIS_MODULE, 1, p54u_fwlist[i].fw,
device, GFP_KERNEL, priv,
p54u_load_firmware_cb);
if (err) {
dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s "
"(%d)!\n", p54u_fwlist[i].fw, err);
- usb_put_dev(udev);
+ usb_put_intf(intf);
}
return err;
@@ -1011,8 +1006,6 @@ static int p54u_probe(struct usb_interface *intf,
skb_queue_head_init(&priv->rx_queue);
init_usb_anchor(&priv->submitted);
- usb_get_dev(udev);
-
/* really lazy and simple way of figuring out if we're a 3887 */
/* TODO: should just stick the identification in the device table */
i = intf->altsetting->desc.bNumEndpoints;
@@ -1053,10 +1046,8 @@ static int p54u_probe(struct usb_interface *intf,
priv->upload_fw = p54u_upload_firmware_net2280;
}
err = p54u_load_firmware(dev, intf);
- if (err) {
- usb_put_dev(udev);
+ if (err)
p54_free_common(dev);
- }
return err;
}
@@ -1072,7 +1063,6 @@ static void p54u_disconnect(struct usb_interface *intf)
wait_for_completion(&priv->fw_wait_load);
p54_unregister_common(dev);
- usb_put_dev(interface_to_usbdev(intf));
release_firmware(priv->fw);
p54_free_common(dev);
}
diff --git a/drivers/net/wireless/intersil/p54/p54usb.h b/drivers/net/wireless/intersil/p54/p54usb.h
index a5f5f0fea3bd..b2d1bce1b9e7 100644
--- a/drivers/net/wireless/intersil/p54/p54usb.h
+++ b/drivers/net/wireless/intersil/p54/p54usb.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef P54USB_H
#define P54USB_H
@@ -8,10 +9,6 @@
*
* Based on the islsm (softmac prism54) driver, which is:
* Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
- *
- * 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.
*/
/* for isl3886 register definitions used on ver 1 devices */
diff --git a/drivers/net/wireless/intersil/p54/txrx.c b/drivers/net/wireless/intersil/p54/txrx.c
index 790784568ad2..873fea59894f 100644
--- a/drivers/net/wireless/intersil/p54/txrx.c
+++ b/drivers/net/wireless/intersil/p54/txrx.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Common code for mac80211 Prism54 drivers
*
@@ -10,10 +11,6 @@
* Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
* - stlc45xx driver
* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
- *
- * 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.
*/
#include <linux/export.h>
@@ -142,7 +139,10 @@ static int p54_assign_address(struct p54_common *priv, struct sk_buff *skb)
unlikely(GET_HW_QUEUE(skb) == P54_QUEUE_BEACON))
priv->beacon_req_id = data->req_id;
- __skb_queue_after(&priv->tx_queue, target_skb, skb);
+ if (target_skb)
+ __skb_queue_after(&priv->tx_queue, target_skb, skb);
+ else
+ __skb_queue_head(&priv->tx_queue, skb);
spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
return 0;
}
@@ -331,6 +331,7 @@ static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
u16 freq = le16_to_cpu(hdr->freq);
size_t header_len = sizeof(*hdr);
u32 tsf32;
+ __le16 fc;
u8 rate = hdr->rate & 0xf;
/*
@@ -379,6 +380,11 @@ static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
skb_pull(skb, header_len);
skb_trim(skb, le16_to_cpu(hdr->len));
+
+ fc = ((struct ieee80211_hdr *)skb->data)->frame_control;
+ if (ieee80211_is_probe_resp(fc) || ieee80211_is_beacon(fc))
+ rx_status->boottime_ns = ktime_get_boottime_ns();
+
if (unlikely(priv->hw->conf.flags & IEEE80211_CONF_PS))
p54_pspoll_workaround(priv, skb);
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 60ca13e0f15b..519b4ee88c5c 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* mac80211_hwsim - software simulator of 802.11 radio(s) for mac80211
* Copyright (c) 2008, Jouni Malinen <j@w1.fi>
* Copyright (c) 2011, Javier Lopez <jlopex@gmail.com>
* Copyright (c) 2016 - 2017 Intel Deutschland GmbH
* Copyright (C) 2018 Intel Corporation
- *
- * 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.
*/
/*
@@ -457,6 +454,8 @@ static struct wiphy_vendor_command mac80211_hwsim_vendor_commands[] = {
.subcmd = QCA_NL80211_SUBCMD_TEST },
.flags = WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = mac80211_hwsim_vendor_cmd_test,
+ .policy = hwsim_vendor_test_policy,
+ .maxattr = QCA_WLAN_VENDOR_ATTR_MAX,
}
};
@@ -1274,7 +1273,7 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
*/
if (ieee80211_is_beacon(hdr->frame_control) ||
ieee80211_is_probe_resp(hdr->frame_control)) {
- rx_status.boottime_ns = ktime_get_boot_ns();
+ rx_status.boottime_ns = ktime_get_boottime_ns();
now = data->abs_bcn_ts;
} else {
now = mac80211_hwsim_get_tsf_raw();
@@ -3851,6 +3850,7 @@ static int __init init_mac80211_hwsim(void)
break;
case HWSIM_REGTEST_STRICT_ALL:
param.reg_strict = true;
+ /* fall through */
case HWSIM_REGTEST_DRIVER_REG_ALL:
param.reg_alpha2 = hwsim_alpha2s[0];
break;
diff --git a/drivers/net/wireless/mac80211_hwsim.h b/drivers/net/wireless/mac80211_hwsim.h
index a1ef8457fad4..a85bc7c5c030 100644
--- a/drivers/net/wireless/mac80211_hwsim.h
+++ b/drivers/net/wireless/mac80211_hwsim.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* mac80211_hwsim - software simulator of 802.11 radio(s) for mac80211
* Copyright (c) 2008, Jouni Malinen <j@w1.fi>
* Copyright (c) 2011, Javier Lopez <jlopex@gmail.com>
- *
- * 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.
*/
#ifndef __MAC80211_HWSIM_H
diff --git a/drivers/net/wireless/marvell/libertas/if_usb.c b/drivers/net/wireless/marvell/libertas/if_usb.c
index f1622f0ff8c9..afac2481909b 100644
--- a/drivers/net/wireless/marvell/libertas/if_usb.c
+++ b/drivers/net/wireless/marvell/libertas/if_usb.c
@@ -368,7 +368,7 @@ static int if_usb_send_fw_pkt(struct if_usb_card *cardp)
cardp->fwseqnum, cardp->totalbytes);
} else if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) {
lbs_deb_usb2(&cardp->udev->dev, "Host has finished FW downloading\n");
- lbs_deb_usb2(&cardp->udev->dev, "Donwloading FW JUMP BLOCK\n");
+ lbs_deb_usb2(&cardp->udev->dev, "Downloading FW JUMP BLOCK\n");
cardp->fwfinalblk = 1;
}
diff --git a/drivers/net/wireless/marvell/libertas_tf/if_usb.c b/drivers/net/wireless/marvell/libertas_tf/if_usb.c
index 28a8bd3cf10c..25ac9db35dbf 100644
--- a/drivers/net/wireless/marvell/libertas_tf/if_usb.c
+++ b/drivers/net/wireless/marvell/libertas_tf/if_usb.c
@@ -315,7 +315,7 @@ static int if_usb_send_fw_pkt(struct if_usb_card *cardp)
} else if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) {
lbtf_deb_usb2(&cardp->udev->dev,
"Host has finished FW downloading\n");
- lbtf_deb_usb2(&cardp->udev->dev, "Donwloading FW JUMP BLOCK\n");
+ lbtf_deb_usb2(&cardp->udev->dev, "Downloading FW JUMP BLOCK\n");
/* Host has finished FW downloading
* Donwloading FW JUMP BLOCK
diff --git a/drivers/net/wireless/marvell/mwifiex/11n.c b/drivers/net/wireless/marvell/mwifiex/11n.c
index 5d75c971004b..e435f801bc91 100644
--- a/drivers/net/wireless/marvell/mwifiex/11n.c
+++ b/drivers/net/wireless/marvell/mwifiex/11n.c
@@ -84,17 +84,15 @@ mwifiex_get_ba_status(struct mwifiex_private *priv,
enum mwifiex_ba_status ba_status)
{
struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
- unsigned long flags;
- spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
+ spin_lock_bh(&priv->tx_ba_stream_tbl_lock);
list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
if (tx_ba_tsr_tbl->ba_status == ba_status) {
- spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock,
- flags);
+ spin_unlock_bh(&priv->tx_ba_stream_tbl_lock);
return tx_ba_tsr_tbl;
}
}
- spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
+ spin_unlock_bh(&priv->tx_ba_stream_tbl_lock);
return NULL;
}
@@ -516,13 +514,12 @@ void mwifiex_11n_delete_all_tx_ba_stream_tbl(struct mwifiex_private *priv)
{
int i;
struct mwifiex_tx_ba_stream_tbl *del_tbl_ptr, *tmp_node;
- unsigned long flags;
- spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
+ spin_lock_bh(&priv->tx_ba_stream_tbl_lock);
list_for_each_entry_safe(del_tbl_ptr, tmp_node,
&priv->tx_ba_stream_tbl_ptr, list)
mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, del_tbl_ptr);
- spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
+ spin_unlock_bh(&priv->tx_ba_stream_tbl_lock);
INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr);
@@ -539,18 +536,16 @@ struct mwifiex_tx_ba_stream_tbl *
mwifiex_get_ba_tbl(struct mwifiex_private *priv, int tid, u8 *ra)
{
struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
- unsigned long flags;
- spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
+ spin_lock_bh(&priv->tx_ba_stream_tbl_lock);
list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
if (ether_addr_equal_unaligned(tx_ba_tsr_tbl->ra, ra) &&
tx_ba_tsr_tbl->tid == tid) {
- spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock,
- flags);
+ spin_unlock_bh(&priv->tx_ba_stream_tbl_lock);
return tx_ba_tsr_tbl;
}
}
- spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
+ spin_unlock_bh(&priv->tx_ba_stream_tbl_lock);
return NULL;
}
@@ -563,7 +558,6 @@ void mwifiex_create_ba_tbl(struct mwifiex_private *priv, u8 *ra, int tid,
{
struct mwifiex_tx_ba_stream_tbl *new_node;
struct mwifiex_ra_list_tbl *ra_list;
- unsigned long flags;
int tid_down;
if (!mwifiex_get_ba_tbl(priv, tid, ra)) {
@@ -584,9 +578,9 @@ void mwifiex_create_ba_tbl(struct mwifiex_private *priv, u8 *ra, int tid,
new_node->ba_status = ba_status;
memcpy(new_node->ra, ra, ETH_ALEN);
- spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
+ spin_lock_bh(&priv->tx_ba_stream_tbl_lock);
list_add_tail(&new_node->list, &priv->tx_ba_stream_tbl_ptr);
- spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
+ spin_unlock_bh(&priv->tx_ba_stream_tbl_lock);
}
}
@@ -599,7 +593,6 @@ int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac)
u32 tx_win_size = priv->add_ba_param.tx_win_size;
static u8 dialog_tok;
int ret;
- unsigned long flags;
u16 block_ack_param_set;
mwifiex_dbg(priv->adapter, CMD, "cmd: %s: tid %d\n", __func__, tid);
@@ -612,10 +605,10 @@ int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac)
memcmp(priv->cfg_bssid, peer_mac, ETH_ALEN)) {
struct mwifiex_sta_node *sta_ptr;
- spin_lock_irqsave(&priv->sta_list_spinlock, flags);
+ spin_lock_bh(&priv->sta_list_spinlock);
sta_ptr = mwifiex_get_sta_entry(priv, peer_mac);
if (!sta_ptr) {
- spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+ spin_unlock_bh(&priv->sta_list_spinlock);
mwifiex_dbg(priv->adapter, ERROR,
"BA setup with unknown TDLS peer %pM!\n",
peer_mac);
@@ -623,7 +616,7 @@ int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac)
}
if (sta_ptr->is_11ac_enabled)
tx_win_size = MWIFIEX_11AC_STA_AMPDU_DEF_TXWINSIZE;
- spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+ spin_unlock_bh(&priv->sta_list_spinlock);
}
block_ack_param_set = (u16)((tid << BLOCKACKPARAM_TID_POS) |
@@ -687,9 +680,8 @@ int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac,
void mwifiex_11n_delba(struct mwifiex_private *priv, int tid)
{
struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
- unsigned long flags;
- spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+ spin_lock_bh(&priv->rx_reorder_tbl_lock);
list_for_each_entry(rx_reor_tbl_ptr, &priv->rx_reorder_tbl_ptr, list) {
if (rx_reor_tbl_ptr->tid == tid) {
dev_dbg(priv->adapter->dev,
@@ -700,7 +692,7 @@ void mwifiex_11n_delba(struct mwifiex_private *priv, int tid)
}
}
exit:
- spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
+ spin_unlock_bh(&priv->rx_reorder_tbl_lock);
}
/*
@@ -729,9 +721,8 @@ int mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv,
struct mwifiex_ds_rx_reorder_tbl *rx_reo_tbl = buf;
struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr;
int count = 0;
- unsigned long flags;
- spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+ spin_lock_bh(&priv->rx_reorder_tbl_lock);
list_for_each_entry(rx_reorder_tbl_ptr, &priv->rx_reorder_tbl_ptr,
list) {
rx_reo_tbl->tid = (u16) rx_reorder_tbl_ptr->tid;
@@ -750,7 +741,7 @@ int mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv,
if (count >= MWIFIEX_MAX_RX_BASTREAM_SUPPORTED)
break;
}
- spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
+ spin_unlock_bh(&priv->rx_reorder_tbl_lock);
return count;
}
@@ -764,9 +755,8 @@ int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
struct mwifiex_ds_tx_ba_stream_tbl *rx_reo_tbl = buf;
int count = 0;
- unsigned long flags;
- spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
+ spin_lock_bh(&priv->tx_ba_stream_tbl_lock);
list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
rx_reo_tbl->tid = (u16) tx_ba_tsr_tbl->tid;
mwifiex_dbg(priv->adapter, DATA, "data: %s tid=%d\n",
@@ -778,7 +768,7 @@ int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
if (count >= MWIFIEX_MAX_TX_BASTREAM_SUPPORTED)
break;
}
- spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
+ spin_unlock_bh(&priv->tx_ba_stream_tbl_lock);
return count;
}
@@ -790,16 +780,15 @@ int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
void mwifiex_del_tx_ba_stream_tbl_by_ra(struct mwifiex_private *priv, u8 *ra)
{
struct mwifiex_tx_ba_stream_tbl *tbl, *tmp;
- unsigned long flags;
if (!ra)
return;
- spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
+ spin_lock_bh(&priv->tx_ba_stream_tbl_lock);
list_for_each_entry_safe(tbl, tmp, &priv->tx_ba_stream_tbl_ptr, list)
if (!memcmp(tbl->ra, ra, ETH_ALEN))
mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, tbl);
- spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
+ spin_unlock_bh(&priv->tx_ba_stream_tbl_lock);
return;
}
diff --git a/drivers/net/wireless/marvell/mwifiex/11n.h b/drivers/net/wireless/marvell/mwifiex/11n.h
index ea0fa68b9913..33268ce2cd82 100644
--- a/drivers/net/wireless/marvell/mwifiex/11n.h
+++ b/drivers/net/wireless/marvell/mwifiex/11n.h
@@ -147,11 +147,10 @@ mwifiex_find_stream_to_delete(struct mwifiex_private *priv, int ptr_tid,
int tid;
u8 ret = false;
struct mwifiex_tx_ba_stream_tbl *tx_tbl;
- unsigned long flags;
tid = priv->aggr_prio_tbl[ptr_tid].ampdu_user;
- spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
+ spin_lock_bh(&priv->tx_ba_stream_tbl_lock);
list_for_each_entry(tx_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
if (tid > priv->aggr_prio_tbl[tx_tbl->tid].ampdu_user) {
tid = priv->aggr_prio_tbl[tx_tbl->tid].ampdu_user;
@@ -160,7 +159,7 @@ mwifiex_find_stream_to_delete(struct mwifiex_private *priv, int ptr_tid,
ret = true;
}
}
- spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
+ spin_unlock_bh(&priv->tx_ba_stream_tbl_lock);
return ret;
}
diff --git a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c
index 042a1d07f686..088612438530 100644
--- a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c
+++ b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c
@@ -155,7 +155,7 @@ mwifiex_11n_form_amsdu_txpd(struct mwifiex_private *priv,
int
mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
struct mwifiex_ra_list_tbl *pra_list,
- int ptrindex, unsigned long ra_list_flags)
+ int ptrindex)
__releases(&priv->wmm.ra_list_spinlock)
{
struct mwifiex_adapter *adapter = priv->adapter;
@@ -168,8 +168,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
skb_src = skb_peek(&pra_list->skb_head);
if (!skb_src) {
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
- ra_list_flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
return 0;
}
@@ -177,8 +176,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
skb_aggr = mwifiex_alloc_dma_align_buf(adapter->tx_buf_size,
GFP_ATOMIC);
if (!skb_aggr) {
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
- ra_list_flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
return -1;
}
@@ -208,17 +206,15 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
pra_list->total_pkt_count--;
atomic_dec(&priv->wmm.tx_pkts_queued);
aggr_num++;
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
- ra_list_flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
mwifiex_11n_form_amsdu_pkt(skb_aggr, skb_src, &pad);
mwifiex_write_data_complete(adapter, skb_src, 0, 0);
- spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
+ spin_lock_bh(&priv->wmm.ra_list_spinlock);
if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) {
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
- ra_list_flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
return -1;
}
@@ -232,7 +228,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
} while (skb_src);
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
/* Last AMSDU packet does not need padding */
skb_trim(skb_aggr, skb_aggr->len - pad);
@@ -265,10 +261,9 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
}
switch (ret) {
case -EBUSY:
- spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
+ spin_lock_bh(&priv->wmm.ra_list_spinlock);
if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) {
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
- ra_list_flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
mwifiex_write_data_complete(adapter, skb_aggr, 1, -1);
return -1;
}
@@ -286,8 +281,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
atomic_inc(&priv->wmm.tx_pkts_queued);
tx_info_aggr->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT;
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
- ra_list_flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
mwifiex_dbg(adapter, ERROR, "data: -EBUSY is returned\n");
break;
case -1:
diff --git a/drivers/net/wireless/marvell/mwifiex/11n_aggr.h b/drivers/net/wireless/marvell/mwifiex/11n_aggr.h
index 0cd2a3eb6c17..8279b159da7c 100644
--- a/drivers/net/wireless/marvell/mwifiex/11n_aggr.h
+++ b/drivers/net/wireless/marvell/mwifiex/11n_aggr.h
@@ -27,7 +27,7 @@ int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv,
struct sk_buff *skb);
int mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
struct mwifiex_ra_list_tbl *ptr,
- int ptr_index, unsigned long flags)
+ int ptr_index)
__releases(&priv->wmm.ra_list_spinlock);
#endif /* !_MWIFIEX_11N_AGGR_H_ */
diff --git a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c
index 5380fba652cc..05a3c61ac603 100644
--- a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c
+++ b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c
@@ -76,7 +76,8 @@ static int mwifiex_11n_dispatch_amsdu_pkt(struct mwifiex_private *priv,
/* This function will process the rx packet and forward it to kernel/upper
* layer.
*/
-static int mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv, void *payload)
+static int mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv,
+ struct sk_buff *payload)
{
int ret;
@@ -109,27 +110,25 @@ mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv,
struct mwifiex_rx_reorder_tbl *tbl,
int start_win)
{
+ struct sk_buff_head list;
+ struct sk_buff *skb;
int pkt_to_send, i;
- void *rx_tmp_ptr;
- unsigned long flags;
+
+ __skb_queue_head_init(&list);
+ spin_lock_bh(&priv->rx_reorder_tbl_lock);
pkt_to_send = (start_win > tbl->start_win) ?
min((start_win - tbl->start_win), tbl->win_size) :
tbl->win_size;
for (i = 0; i < pkt_to_send; ++i) {
- spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
- rx_tmp_ptr = NULL;
if (tbl->rx_reorder_ptr[i]) {
- rx_tmp_ptr = tbl->rx_reorder_ptr[i];
+ skb = tbl->rx_reorder_ptr[i];
+ __skb_queue_tail(&list, skb);
tbl->rx_reorder_ptr[i] = NULL;
}
- spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
- if (rx_tmp_ptr)
- mwifiex_11n_dispatch_pkt(priv, rx_tmp_ptr);
}
- spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
/*
* We don't have a circular buffer, hence use rotation to simulate
* circular buffer
@@ -140,7 +139,10 @@ mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv,
}
tbl->start_win = start_win;
- spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
+ spin_unlock_bh(&priv->rx_reorder_tbl_lock);
+
+ while ((skb = __skb_dequeue(&list)))
+ mwifiex_11n_dispatch_pkt(priv, skb);
}
/*
@@ -155,24 +157,21 @@ static void
mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv,
struct mwifiex_rx_reorder_tbl *tbl)
{
+ struct sk_buff_head list;
+ struct sk_buff *skb;
int i, j, xchg;
- void *rx_tmp_ptr;
- unsigned long flags;
+
+ __skb_queue_head_init(&list);
+ spin_lock_bh(&priv->rx_reorder_tbl_lock);
for (i = 0; i < tbl->win_size; ++i) {
- spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
- if (!tbl->rx_reorder_ptr[i]) {
- spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
- flags);
+ if (!tbl->rx_reorder_ptr[i])
break;
- }
- rx_tmp_ptr = tbl->rx_reorder_ptr[i];
+ skb = tbl->rx_reorder_ptr[i];
+ __skb_queue_tail(&list, skb);
tbl->rx_reorder_ptr[i] = NULL;
- spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
- mwifiex_11n_dispatch_pkt(priv, rx_tmp_ptr);
}
- spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
/*
* We don't have a circular buffer, hence use rotation to simulate
* circular buffer
@@ -185,7 +184,11 @@ mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv,
}
}
tbl->start_win = (tbl->start_win + i) & (MAX_TID_VALUE - 1);
- spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
+
+ spin_unlock_bh(&priv->rx_reorder_tbl_lock);
+
+ while ((skb = __skb_dequeue(&list)))
+ mwifiex_11n_dispatch_pkt(priv, skb);
}
/*
@@ -198,19 +201,18 @@ static void
mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv,
struct mwifiex_rx_reorder_tbl *tbl)
{
- unsigned long flags;
int start_win;
if (!tbl)
return;
- spin_lock_irqsave(&priv->adapter->rx_proc_lock, flags);
+ spin_lock_bh(&priv->adapter->rx_proc_lock);
priv->adapter->rx_locked = true;
if (priv->adapter->rx_processing) {
- spin_unlock_irqrestore(&priv->adapter->rx_proc_lock, flags);
+ spin_unlock_bh(&priv->adapter->rx_proc_lock);
flush_workqueue(priv->adapter->rx_workqueue);
} else {
- spin_unlock_irqrestore(&priv->adapter->rx_proc_lock, flags);
+ spin_unlock_bh(&priv->adapter->rx_proc_lock);
}
start_win = (tbl->start_win + tbl->win_size) & (MAX_TID_VALUE - 1);
@@ -219,16 +221,16 @@ mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv,
del_timer_sync(&tbl->timer_context.timer);
tbl->timer_context.timer_is_set = false;
- spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+ spin_lock_bh(&priv->rx_reorder_tbl_lock);
list_del(&tbl->list);
- spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
+ spin_unlock_bh(&priv->rx_reorder_tbl_lock);
kfree(tbl->rx_reorder_ptr);
kfree(tbl);
- spin_lock_irqsave(&priv->adapter->rx_proc_lock, flags);
+ spin_lock_bh(&priv->adapter->rx_proc_lock);
priv->adapter->rx_locked = false;
- spin_unlock_irqrestore(&priv->adapter->rx_proc_lock, flags);
+ spin_unlock_bh(&priv->adapter->rx_proc_lock);
}
@@ -240,17 +242,15 @@ struct mwifiex_rx_reorder_tbl *
mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta)
{
struct mwifiex_rx_reorder_tbl *tbl;
- unsigned long flags;
- spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+ spin_lock_bh(&priv->rx_reorder_tbl_lock);
list_for_each_entry(tbl, &priv->rx_reorder_tbl_ptr, list) {
if (!memcmp(tbl->ta, ta, ETH_ALEN) && tbl->tid == tid) {
- spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
- flags);
+ spin_unlock_bh(&priv->rx_reorder_tbl_lock);
return tbl;
}
}
- spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
+ spin_unlock_bh(&priv->rx_reorder_tbl_lock);
return NULL;
}
@@ -261,21 +261,19 @@ mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta)
void mwifiex_11n_del_rx_reorder_tbl_by_ta(struct mwifiex_private *priv, u8 *ta)
{
struct mwifiex_rx_reorder_tbl *tbl, *tmp;
- unsigned long flags;
if (!ta)
return;
- spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+ spin_lock_bh(&priv->rx_reorder_tbl_lock);
list_for_each_entry_safe(tbl, tmp, &priv->rx_reorder_tbl_ptr, list) {
if (!memcmp(tbl->ta, ta, ETH_ALEN)) {
- spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
- flags);
+ spin_unlock_bh(&priv->rx_reorder_tbl_lock);
mwifiex_del_rx_reorder_entry(priv, tbl);
- spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+ spin_lock_bh(&priv->rx_reorder_tbl_lock);
}
}
- spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
+ spin_unlock_bh(&priv->rx_reorder_tbl_lock);
return;
}
@@ -289,18 +287,16 @@ mwifiex_11n_find_last_seq_num(struct reorder_tmr_cnxt *ctx)
{
struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr = ctx->ptr;
struct mwifiex_private *priv = ctx->priv;
- unsigned long flags;
int i;
- spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+ spin_lock_bh(&priv->rx_reorder_tbl_lock);
for (i = rx_reorder_tbl_ptr->win_size - 1; i >= 0; --i) {
if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) {
- spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
- flags);
+ spin_unlock_bh(&priv->rx_reorder_tbl_lock);
return i;
}
}
- spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
+ spin_unlock_bh(&priv->rx_reorder_tbl_lock);
return -1;
}
@@ -348,7 +344,6 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
int i;
struct mwifiex_rx_reorder_tbl *tbl, *new_node;
u16 last_seq = 0;
- unsigned long flags;
struct mwifiex_sta_node *node;
/*
@@ -372,7 +367,7 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
new_node->init_win = seq_num;
new_node->flags = 0;
- spin_lock_irqsave(&priv->sta_list_spinlock, flags);
+ spin_lock_bh(&priv->sta_list_spinlock);
if (mwifiex_queuing_ra_based(priv)) {
if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) {
node = mwifiex_get_sta_entry(priv, ta);
@@ -386,7 +381,7 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
else
last_seq = priv->rx_seq[tid];
}
- spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+ spin_unlock_bh(&priv->sta_list_spinlock);
mwifiex_dbg(priv->adapter, INFO,
"info: last_seq=%d start_win=%d\n",
@@ -418,9 +413,9 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
for (i = 0; i < win_size; ++i)
new_node->rx_reorder_ptr[i] = NULL;
- spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+ spin_lock_bh(&priv->rx_reorder_tbl_lock);
list_add_tail(&new_node->list, &priv->rx_reorder_tbl_ptr);
- spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
+ spin_unlock_bh(&priv->rx_reorder_tbl_lock);
}
static void
@@ -476,18 +471,17 @@ int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv,
u32 rx_win_size = priv->add_ba_param.rx_win_size;
u8 tid;
int win_size;
- unsigned long flags;
uint16_t block_ack_param_set;
if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
priv->adapter->is_hw_11ac_capable &&
memcmp(priv->cfg_bssid, cmd_addba_req->peer_mac_addr, ETH_ALEN)) {
- spin_lock_irqsave(&priv->sta_list_spinlock, flags);
+ spin_lock_bh(&priv->sta_list_spinlock);
sta_ptr = mwifiex_get_sta_entry(priv,
cmd_addba_req->peer_mac_addr);
if (!sta_ptr) {
- spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+ spin_unlock_bh(&priv->sta_list_spinlock);
mwifiex_dbg(priv->adapter, ERROR,
"BA setup with unknown TDLS peer %pM!\n",
cmd_addba_req->peer_mac_addr);
@@ -495,7 +489,7 @@ int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv,
}
if (sta_ptr->is_11ac_enabled)
rx_win_size = MWIFIEX_11AC_STA_AMPDU_DEF_RXWINSIZE;
- spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+ spin_unlock_bh(&priv->sta_list_spinlock);
}
cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_RSP);
@@ -682,7 +676,6 @@ mwifiex_del_ba_tbl(struct mwifiex_private *priv, int tid, u8 *peer_mac,
struct mwifiex_tx_ba_stream_tbl *ptx_tbl;
struct mwifiex_ra_list_tbl *ra_list;
u8 cleanup_rx_reorder_tbl;
- unsigned long flags;
int tid_down;
if (type == TYPE_DELBA_RECEIVE)
@@ -716,9 +709,9 @@ mwifiex_del_ba_tbl(struct mwifiex_private *priv, int tid, u8 *peer_mac,
ra_list->amsdu_in_ampdu = false;
ra_list->ba_status = BA_SETUP_NONE;
}
- spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
+ spin_lock_bh(&priv->tx_ba_stream_tbl_lock);
mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, ptx_tbl);
- spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
+ spin_unlock_bh(&priv->tx_ba_stream_tbl_lock);
}
}
@@ -804,17 +797,16 @@ void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv,
void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv)
{
struct mwifiex_rx_reorder_tbl *del_tbl_ptr, *tmp_node;
- unsigned long flags;
- spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+ spin_lock_bh(&priv->rx_reorder_tbl_lock);
list_for_each_entry_safe(del_tbl_ptr, tmp_node,
&priv->rx_reorder_tbl_ptr, list) {
- spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
+ spin_unlock_bh(&priv->rx_reorder_tbl_lock);
mwifiex_del_rx_reorder_entry(priv, del_tbl_ptr);
- spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+ spin_lock_bh(&priv->rx_reorder_tbl_lock);
}
INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
- spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
+ spin_unlock_bh(&priv->rx_reorder_tbl_lock);
mwifiex_reset_11n_rx_seq_num(priv);
}
@@ -826,7 +818,6 @@ void mwifiex_update_rxreor_flags(struct mwifiex_adapter *adapter, u8 flags)
{
struct mwifiex_private *priv;
struct mwifiex_rx_reorder_tbl *tbl;
- unsigned long lock_flags;
int i;
for (i = 0; i < adapter->priv_num; i++) {
@@ -834,10 +825,10 @@ void mwifiex_update_rxreor_flags(struct mwifiex_adapter *adapter, u8 flags)
if (!priv)
continue;
- spin_lock_irqsave(&priv->rx_reorder_tbl_lock, lock_flags);
+ spin_lock_bh(&priv->rx_reorder_tbl_lock);
list_for_each_entry(tbl, &priv->rx_reorder_tbl_ptr, list)
tbl->flags = flags;
- spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, lock_flags);
+ spin_unlock_bh(&priv->rx_reorder_tbl_lock);
}
return;
diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
index e11a4bb67172..d89684168500 100644
--- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
@@ -876,13 +876,13 @@ static int mwifiex_deinit_priv_params(struct mwifiex_private *priv)
spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
}
- spin_lock_irqsave(&adapter->rx_proc_lock, flags);
+ spin_lock_bh(&adapter->rx_proc_lock);
adapter->rx_locked = true;
if (adapter->rx_processing) {
- spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
+ spin_unlock_bh(&adapter->rx_proc_lock);
flush_workqueue(adapter->rx_workqueue);
} else {
- spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
+ spin_unlock_bh(&adapter->rx_proc_lock);
}
mwifiex_free_priv(priv);
@@ -934,9 +934,9 @@ mwifiex_init_new_priv_params(struct mwifiex_private *priv,
adapter->main_locked = false;
spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
- spin_lock_irqsave(&adapter->rx_proc_lock, flags);
+ spin_lock_bh(&adapter->rx_proc_lock);
adapter->rx_locked = false;
- spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
+ spin_unlock_bh(&adapter->rx_proc_lock);
mwifiex_set_mac_address(priv, dev, false, NULL);
@@ -1827,7 +1827,6 @@ mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev,
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
struct mwifiex_sta_node *sta_node;
u8 deauth_mac[ETH_ALEN];
- unsigned long flags;
if (!priv->bss_started && priv->wdev.cac_started) {
mwifiex_dbg(priv->adapter, INFO, "%s: abort CAC!\n", __func__);
@@ -1845,11 +1844,11 @@ mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev,
eth_zero_addr(deauth_mac);
- spin_lock_irqsave(&priv->sta_list_spinlock, flags);
+ spin_lock_bh(&priv->sta_list_spinlock);
sta_node = mwifiex_get_sta_entry(priv, params->mac);
if (sta_node)
ether_addr_copy(deauth_mac, params->mac);
- spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+ spin_unlock_bh(&priv->sta_list_spinlock);
if (is_valid_ether_addr(deauth_mac)) {
if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_STA_DEAUTH,
@@ -3268,7 +3267,7 @@ static void mwifiex_set_auto_arp_mef_entry(struct mwifiex_private *priv,
in_dev = __in_dev_get_rtnl(adapter->priv[i]->netdev);
if (!in_dev)
continue;
- ifa = in_dev->ifa_list;
+ ifa = rtnl_dereference(in_dev->ifa_list);
if (!ifa || !ifa->ifa_local)
continue;
ips[i] = ifa->ifa_local;
@@ -3852,15 +3851,14 @@ mwifiex_cfg80211_tdls_chan_switch(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_chan_def *chandef)
{
struct mwifiex_sta_node *sta_ptr;
- unsigned long flags;
u16 chan;
u8 second_chan_offset, band;
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
- spin_lock_irqsave(&priv->sta_list_spinlock, flags);
+ spin_lock_bh(&priv->sta_list_spinlock);
sta_ptr = mwifiex_get_sta_entry(priv, addr);
if (!sta_ptr) {
- spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+ spin_unlock_bh(&priv->sta_list_spinlock);
wiphy_err(wiphy, "%s: Invalid TDLS peer %pM\n",
__func__, addr);
return -ENOENT;
@@ -3868,18 +3866,18 @@ mwifiex_cfg80211_tdls_chan_switch(struct wiphy *wiphy, struct net_device *dev,
if (!(sta_ptr->tdls_cap.extcap.ext_capab[3] &
WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH)) {
- spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+ spin_unlock_bh(&priv->sta_list_spinlock);
wiphy_err(wiphy, "%pM do not support tdls cs\n", addr);
return -ENOENT;
}
if (sta_ptr->tdls_status == TDLS_CHAN_SWITCHING ||
sta_ptr->tdls_status == TDLS_IN_OFF_CHAN) {
- spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+ spin_unlock_bh(&priv->sta_list_spinlock);
wiphy_err(wiphy, "channel switch is running, abort request\n");
return -EALREADY;
}
- spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+ spin_unlock_bh(&priv->sta_list_spinlock);
chan = chandef->chan->hw_value;
second_chan_offset = mwifiex_get_sec_chan_offset(chan);
@@ -3895,23 +3893,22 @@ mwifiex_cfg80211_tdls_cancel_chan_switch(struct wiphy *wiphy,
const u8 *addr)
{
struct mwifiex_sta_node *sta_ptr;
- unsigned long flags;
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
- spin_lock_irqsave(&priv->sta_list_spinlock, flags);
+ spin_lock_bh(&priv->sta_list_spinlock);
sta_ptr = mwifiex_get_sta_entry(priv, addr);
if (!sta_ptr) {
- spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+ spin_unlock_bh(&priv->sta_list_spinlock);
wiphy_err(wiphy, "%s: Invalid TDLS peer %pM\n",
__func__, addr);
} else if (!(sta_ptr->tdls_status == TDLS_CHAN_SWITCHING ||
sta_ptr->tdls_status == TDLS_IN_BASE_CHAN ||
sta_ptr->tdls_status == TDLS_IN_OFF_CHAN)) {
- spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+ spin_unlock_bh(&priv->sta_list_spinlock);
wiphy_err(wiphy, "tdls chan switch not initialize by %pM\n",
addr);
} else {
- spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+ spin_unlock_bh(&priv->sta_list_spinlock);
mwifiex_stop_tdls_cs(priv, addr);
}
}
diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c
index 8c35441fd9b7..e8788c35a453 100644
--- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c
@@ -39,10 +39,11 @@ static void mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter);
static void
mwifiex_init_cmd_node(struct mwifiex_private *priv,
struct cmd_ctrl_node *cmd_node,
- u32 cmd_oid, void *data_buf, bool sync)
+ u32 cmd_no, void *data_buf, bool sync)
{
cmd_node->priv = priv;
- cmd_node->cmd_oid = cmd_oid;
+ cmd_node->cmd_no = cmd_no;
+
if (sync) {
cmd_node->wait_q_enabled = true;
cmd_node->cmd_wait_q_woken = false;
@@ -60,19 +61,18 @@ static struct cmd_ctrl_node *
mwifiex_get_cmd_node(struct mwifiex_adapter *adapter)
{
struct cmd_ctrl_node *cmd_node;
- unsigned long flags;
- spin_lock_irqsave(&adapter->cmd_free_q_lock, flags);
+ spin_lock_bh(&adapter->cmd_free_q_lock);
if (list_empty(&adapter->cmd_free_q)) {
mwifiex_dbg(adapter, ERROR,
"GET_CMD_NODE: cmd node not available\n");
- spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags);
+ spin_unlock_bh(&adapter->cmd_free_q_lock);
return NULL;
}
cmd_node = list_first_entry(&adapter->cmd_free_q,
struct cmd_ctrl_node, list);
list_del(&cmd_node->list);
- spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags);
+ spin_unlock_bh(&adapter->cmd_free_q_lock);
return cmd_node;
}
@@ -92,7 +92,7 @@ static void
mwifiex_clean_cmd_node(struct mwifiex_adapter *adapter,
struct cmd_ctrl_node *cmd_node)
{
- cmd_node->cmd_oid = 0;
+ cmd_node->cmd_no = 0;
cmd_node->cmd_flag = 0;
cmd_node->data_buf = NULL;
cmd_node->wait_q_enabled = false;
@@ -116,8 +116,6 @@ static void
mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter,
struct cmd_ctrl_node *cmd_node)
{
- unsigned long flags;
-
if (!cmd_node)
return;
@@ -127,9 +125,9 @@ mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter,
mwifiex_clean_cmd_node(adapter, cmd_node);
/* Insert node into cmd_free_q */
- spin_lock_irqsave(&adapter->cmd_free_q_lock, flags);
+ spin_lock_bh(&adapter->cmd_free_q_lock);
list_add_tail(&cmd_node->list, &adapter->cmd_free_q);
- spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags);
+ spin_unlock_bh(&adapter->cmd_free_q_lock);
}
/* This function reuses a command node. */
@@ -182,7 +180,6 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
struct host_cmd_ds_command *host_cmd;
uint16_t cmd_code;
uint16_t cmd_size;
- unsigned long flags;
if (!adapter || !cmd_node)
return -1;
@@ -201,6 +198,7 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
}
cmd_code = le16_to_cpu(host_cmd->command);
+ cmd_node->cmd_no = cmd_code;
cmd_size = le16_to_cpu(host_cmd->size);
if (adapter->hw_status == MWIFIEX_HW_STATUS_RESET &&
@@ -221,9 +219,9 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
cmd_node->priv->bss_num,
cmd_node->priv->bss_type));
- spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+ spin_lock_bh(&adapter->mwifiex_cmd_lock);
adapter->curr_cmd = cmd_node;
- spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+ spin_unlock_bh(&adapter->mwifiex_cmd_lock);
/* Adjust skb length */
if (cmd_node->cmd_skb->len > cmd_size)
@@ -274,9 +272,9 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
adapter->cmd_wait_q.status = -1;
mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
- spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+ spin_lock_bh(&adapter->mwifiex_cmd_lock);
adapter->curr_cmd = NULL;
- spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+ spin_unlock_bh(&adapter->mwifiex_cmd_lock);
adapter->dbg.num_cmd_host_to_card_failure++;
return -1;
@@ -621,7 +619,7 @@ int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no,
}
/* Initialize the command node */
- mwifiex_init_cmd_node(priv, cmd_node, cmd_oid, data_buf, sync);
+ mwifiex_init_cmd_node(priv, cmd_node, cmd_no, data_buf, sync);
if (!cmd_node->cmd_skb) {
mwifiex_dbg(adapter, ERROR,
@@ -695,7 +693,6 @@ mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter,
{
struct host_cmd_ds_command *host_cmd = NULL;
u16 command;
- unsigned long flags;
bool add_tail = true;
host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data);
@@ -717,12 +714,12 @@ mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter,
}
}
- spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
+ spin_lock_bh(&adapter->cmd_pending_q_lock);
if (add_tail)
list_add_tail(&cmd_node->list, &adapter->cmd_pending_q);
else
list_add(&cmd_node->list, &adapter->cmd_pending_q);
- spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
+ spin_unlock_bh(&adapter->cmd_pending_q_lock);
atomic_inc(&adapter->cmd_pending);
mwifiex_dbg(adapter, CMD,
@@ -747,8 +744,6 @@ int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter)
struct cmd_ctrl_node *cmd_node;
int ret = 0;
struct host_cmd_ds_command *host_cmd;
- unsigned long cmd_flags;
- unsigned long cmd_pending_q_flags;
/* Check if already in processing */
if (adapter->curr_cmd) {
@@ -757,13 +752,12 @@ int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter)
return -1;
}
- spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
+ spin_lock_bh(&adapter->mwifiex_cmd_lock);
/* Check if any command is pending */
- spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_pending_q_flags);
+ spin_lock_bh(&adapter->cmd_pending_q_lock);
if (list_empty(&adapter->cmd_pending_q)) {
- spin_unlock_irqrestore(&adapter->cmd_pending_q_lock,
- cmd_pending_q_flags);
- spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
+ spin_unlock_bh(&adapter->cmd_pending_q_lock);
+ spin_unlock_bh(&adapter->mwifiex_cmd_lock);
return 0;
}
cmd_node = list_first_entry(&adapter->cmd_pending_q,
@@ -776,17 +770,15 @@ int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter)
mwifiex_dbg(adapter, ERROR,
"%s: cannot send cmd in sleep state,\t"
"this should not happen\n", __func__);
- spin_unlock_irqrestore(&adapter->cmd_pending_q_lock,
- cmd_pending_q_flags);
- spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
+ spin_unlock_bh(&adapter->cmd_pending_q_lock);
+ spin_unlock_bh(&adapter->mwifiex_cmd_lock);
return ret;
}
list_del(&cmd_node->list);
- spin_unlock_irqrestore(&adapter->cmd_pending_q_lock,
- cmd_pending_q_flags);
+ spin_unlock_bh(&adapter->cmd_pending_q_lock);
- spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
+ spin_unlock_bh(&adapter->mwifiex_cmd_lock);
ret = mwifiex_dnld_cmd_to_fw(priv, cmd_node);
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
/* Any command sent to the firmware when host is in sleep
@@ -820,10 +812,6 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
uint16_t orig_cmdresp_no;
uint16_t cmdresp_no;
uint16_t cmdresp_result;
- unsigned long flags;
-
- /* Now we got response from FW, cancel the command timer */
- del_timer_sync(&adapter->cmd_timer);
if (!adapter->curr_cmd || !adapter->curr_cmd->resp_skb) {
resp = (struct host_cmd_ds_command *) adapter->upld_buf;
@@ -833,9 +821,20 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
return -1;
}
+ resp = (struct host_cmd_ds_command *)adapter->curr_cmd->resp_skb->data;
+ orig_cmdresp_no = le16_to_cpu(resp->command);
+ cmdresp_no = (orig_cmdresp_no & HostCmd_CMD_ID_MASK);
+
+ if (adapter->curr_cmd->cmd_no != cmdresp_no) {
+ mwifiex_dbg(adapter, ERROR,
+ "cmdresp error: cmd=0x%x cmd_resp=0x%x\n",
+ adapter->curr_cmd->cmd_no, cmdresp_no);
+ return -1;
+ }
+ /* Now we got response from FW, cancel the command timer */
+ del_timer_sync(&adapter->cmd_timer);
clear_bit(MWIFIEX_IS_CMD_TIMEDOUT, &adapter->work_flags);
- resp = (struct host_cmd_ds_command *) adapter->curr_cmd->resp_skb->data;
if (adapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) {
/* Copy original response back to response buffer */
struct mwifiex_ds_misc_cmd *hostcmd;
@@ -849,7 +848,6 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
memcpy(hostcmd->cmd, resp, size);
}
}
- orig_cmdresp_no = le16_to_cpu(resp->command);
/* Get BSS number and corresponding priv */
priv = mwifiex_get_priv_by_id(adapter,
@@ -882,9 +880,9 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
adapter->cmd_wait_q.status = -1;
mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
- spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+ spin_lock_bh(&adapter->mwifiex_cmd_lock);
adapter->curr_cmd = NULL;
- spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+ spin_unlock_bh(&adapter->mwifiex_cmd_lock);
return -1;
}
@@ -916,9 +914,9 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
- spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+ spin_lock_bh(&adapter->mwifiex_cmd_lock);
adapter->curr_cmd = NULL;
- spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+ spin_unlock_bh(&adapter->mwifiex_cmd_lock);
}
return ret;
@@ -1024,17 +1022,16 @@ void
mwifiex_cancel_pending_scan_cmd(struct mwifiex_adapter *adapter)
{
struct cmd_ctrl_node *cmd_node = NULL, *tmp_node;
- unsigned long flags;
/* Cancel all pending scan command */
- spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+ spin_lock_bh(&adapter->scan_pending_q_lock);
list_for_each_entry_safe(cmd_node, tmp_node,
&adapter->scan_pending_q, list) {
list_del(&cmd_node->list);
cmd_node->wait_q_enabled = false;
mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
}
- spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+ spin_unlock_bh(&adapter->scan_pending_q_lock);
}
/*
@@ -1048,9 +1045,8 @@ void
mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
{
struct cmd_ctrl_node *cmd_node = NULL, *tmp_node;
- unsigned long flags, cmd_flags;
- spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
+ spin_lock_bh(&adapter->mwifiex_cmd_lock);
/* Cancel current cmd */
if ((adapter->curr_cmd) && (adapter->curr_cmd->wait_q_enabled)) {
adapter->cmd_wait_q.status = -1;
@@ -1059,7 +1055,7 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
/* no recycle probably wait for response */
}
/* Cancel all pending command */
- spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
+ spin_lock_bh(&adapter->cmd_pending_q_lock);
list_for_each_entry_safe(cmd_node, tmp_node,
&adapter->cmd_pending_q, list) {
list_del(&cmd_node->list);
@@ -1068,8 +1064,8 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
adapter->cmd_wait_q.status = -1;
mwifiex_recycle_cmd_node(adapter, cmd_node);
}
- spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
- spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
+ spin_unlock_bh(&adapter->cmd_pending_q_lock);
+ spin_unlock_bh(&adapter->mwifiex_cmd_lock);
mwifiex_cancel_scan(adapter);
}
@@ -1088,11 +1084,10 @@ static void
mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
{
struct cmd_ctrl_node *cmd_node = NULL;
- unsigned long cmd_flags;
if ((adapter->curr_cmd) &&
(adapter->curr_cmd->wait_q_enabled)) {
- spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
+ spin_lock_bh(&adapter->mwifiex_cmd_lock);
cmd_node = adapter->curr_cmd;
/* setting curr_cmd to NULL is quite dangerous, because
* mwifiex_process_cmdresp checks curr_cmd to be != NULL
@@ -1103,7 +1098,7 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
* at that point
*/
adapter->curr_cmd = NULL;
- spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
+ spin_unlock_bh(&adapter->mwifiex_cmd_lock);
mwifiex_recycle_cmd_node(adapter, cmd_node);
}
diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h
index b73f99dc5a72..1fb76d2f5d3f 100644
--- a/drivers/net/wireless/marvell/mwifiex/fw.h
+++ b/drivers/net/wireless/marvell/mwifiex/fw.h
@@ -1759,9 +1759,10 @@ struct mwifiex_ie_types_wmm_queue_status {
struct ieee_types_vendor_header {
u8 element_id;
u8 len;
- u8 oui[4]; /* 0~2: oui, 3: oui_type */
- u8 oui_subtype;
- u8 version;
+ struct {
+ u8 oui[3];
+ u8 oui_type;
+ } __packed oui;
} __packed;
struct ieee_types_wmm_parameter {
@@ -1775,6 +1776,9 @@ struct ieee_types_wmm_parameter {
* Version [1]
*/
struct ieee_types_vendor_header vend_hdr;
+ u8 oui_subtype;
+ u8 version;
+
u8 qos_info_bitmap;
u8 reserved;
struct ieee_types_wmm_ac_parameters ac_params[IEEE80211_NUM_ACS];
@@ -1792,6 +1796,8 @@ struct ieee_types_wmm_info {
* Version [1]
*/
struct ieee_types_vendor_header vend_hdr;
+ u8 oui_subtype;
+ u8 version;
u8 qos_info_bitmap;
} __packed;
diff --git a/drivers/net/wireless/marvell/mwifiex/ie.c b/drivers/net/wireless/marvell/mwifiex/ie.c
index 6845eb57b39a..653d347a9a19 100644
--- a/drivers/net/wireless/marvell/mwifiex/ie.c
+++ b/drivers/net/wireless/marvell/mwifiex/ie.c
@@ -329,6 +329,8 @@ static int mwifiex_uap_parse_tail_ies(struct mwifiex_private *priv,
struct ieee80211_vendor_ie *vendorhdr;
u16 gen_idx = MWIFIEX_AUTO_IDX_MASK, ie_len = 0;
int left_len, parsed_len = 0;
+ unsigned int token_len;
+ int err = 0;
if (!info->tail || !info->tail_len)
return 0;
@@ -344,6 +346,12 @@ static int mwifiex_uap_parse_tail_ies(struct mwifiex_private *priv,
*/
while (left_len > sizeof(struct ieee_types_header)) {
hdr = (void *)(info->tail + parsed_len);
+ token_len = hdr->len + sizeof(struct ieee_types_header);
+ if (token_len > left_len) {
+ err = -EINVAL;
+ goto out;
+ }
+
switch (hdr->element_id) {
case WLAN_EID_SSID:
case WLAN_EID_SUPP_RATES:
@@ -361,17 +369,20 @@ static int mwifiex_uap_parse_tail_ies(struct mwifiex_private *priv,
if (cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
WLAN_OUI_TYPE_MICROSOFT_WMM,
(const u8 *)hdr,
- hdr->len + sizeof(struct ieee_types_header)))
+ token_len))
break;
/* fall through */
default:
- memcpy(gen_ie->ie_buffer + ie_len, hdr,
- hdr->len + sizeof(struct ieee_types_header));
- ie_len += hdr->len + sizeof(struct ieee_types_header);
+ if (ie_len + token_len > IEEE_MAX_IE_SIZE) {
+ err = -EINVAL;
+ goto out;
+ }
+ memcpy(gen_ie->ie_buffer + ie_len, hdr, token_len);
+ ie_len += token_len;
break;
}
- left_len -= hdr->len + sizeof(struct ieee_types_header);
- parsed_len += hdr->len + sizeof(struct ieee_types_header);
+ left_len -= token_len;
+ parsed_len += token_len;
}
/* parse only WPA vendor IE from tail, WMM IE is configured by
@@ -381,15 +392,17 @@ static int mwifiex_uap_parse_tail_ies(struct mwifiex_private *priv,
WLAN_OUI_TYPE_MICROSOFT_WPA,
info->tail, info->tail_len);
if (vendorhdr) {
- memcpy(gen_ie->ie_buffer + ie_len, vendorhdr,
- vendorhdr->len + sizeof(struct ieee_types_header));
- ie_len += vendorhdr->len + sizeof(struct ieee_types_header);
+ token_len = vendorhdr->len + sizeof(struct ieee_types_header);
+ if (ie_len + token_len > IEEE_MAX_IE_SIZE) {
+ err = -EINVAL;
+ goto out;
+ }
+ memcpy(gen_ie->ie_buffer + ie_len, vendorhdr, token_len);
+ ie_len += token_len;
}
- if (!ie_len) {
- kfree(gen_ie);
- return 0;
- }
+ if (!ie_len)
+ goto out;
gen_ie->ie_index = cpu_to_le16(gen_idx);
gen_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON |
@@ -399,13 +412,15 @@ static int mwifiex_uap_parse_tail_ies(struct mwifiex_private *priv,
if (mwifiex_update_uap_custom_ie(priv, gen_ie, &gen_idx, NULL, NULL,
NULL, NULL)) {
- kfree(gen_ie);
- return -1;
+ err = -EINVAL;
+ goto out;
}
priv->gen_idx = gen_idx;
+
+ out:
kfree(gen_ie);
- return 0;
+ return err;
}
/* This function parses different IEs-head & tail IEs, beacon IEs,
diff --git a/drivers/net/wireless/marvell/mwifiex/init.c b/drivers/net/wireless/marvell/mwifiex/init.c
index 673e89dff0b5..6c0e52eb8794 100644
--- a/drivers/net/wireless/marvell/mwifiex/init.c
+++ b/drivers/net/wireless/marvell/mwifiex/init.c
@@ -36,7 +36,6 @@ static int mwifiex_add_bss_prio_tbl(struct mwifiex_private *priv)
struct mwifiex_adapter *adapter = priv->adapter;
struct mwifiex_bss_prio_node *bss_prio;
struct mwifiex_bss_prio_tbl *tbl = adapter->bss_prio_tbl;
- unsigned long flags;
bss_prio = kzalloc(sizeof(struct mwifiex_bss_prio_node), GFP_KERNEL);
if (!bss_prio)
@@ -45,9 +44,9 @@ static int mwifiex_add_bss_prio_tbl(struct mwifiex_private *priv)
bss_prio->priv = priv;
INIT_LIST_HEAD(&bss_prio->list);
- spin_lock_irqsave(&tbl[priv->bss_priority].bss_prio_lock, flags);
+ spin_lock_bh(&tbl[priv->bss_priority].bss_prio_lock);
list_add_tail(&bss_prio->list, &tbl[priv->bss_priority].bss_prio_head);
- spin_unlock_irqrestore(&tbl[priv->bss_priority].bss_prio_lock, flags);
+ spin_unlock_bh(&tbl[priv->bss_priority].bss_prio_lock);
return 0;
}
@@ -344,11 +343,9 @@ void mwifiex_set_trans_start(struct net_device *dev)
void mwifiex_wake_up_net_dev_queue(struct net_device *netdev,
struct mwifiex_adapter *adapter)
{
- unsigned long dev_queue_flags;
-
- spin_lock_irqsave(&adapter->queue_lock, dev_queue_flags);
+ spin_lock_bh(&adapter->queue_lock);
netif_tx_wake_all_queues(netdev);
- spin_unlock_irqrestore(&adapter->queue_lock, dev_queue_flags);
+ spin_unlock_bh(&adapter->queue_lock);
}
/*
@@ -357,11 +354,9 @@ void mwifiex_wake_up_net_dev_queue(struct net_device *netdev,
void mwifiex_stop_net_dev_queue(struct net_device *netdev,
struct mwifiex_adapter *adapter)
{
- unsigned long dev_queue_flags;
-
- spin_lock_irqsave(&adapter->queue_lock, dev_queue_flags);
+ spin_lock_bh(&adapter->queue_lock);
netif_tx_stop_all_queues(netdev);
- spin_unlock_irqrestore(&adapter->queue_lock, dev_queue_flags);
+ spin_unlock_bh(&adapter->queue_lock);
}
/*
@@ -506,7 +501,6 @@ int mwifiex_init_fw(struct mwifiex_adapter *adapter)
struct mwifiex_private *priv;
u8 i, first_sta = true;
int is_cmd_pend_q_empty;
- unsigned long flags;
adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING;
@@ -547,9 +541,9 @@ int mwifiex_init_fw(struct mwifiex_adapter *adapter)
}
}
- spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
+ spin_lock_bh(&adapter->cmd_pending_q_lock);
is_cmd_pend_q_empty = list_empty(&adapter->cmd_pending_q);
- spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
+ spin_unlock_bh(&adapter->cmd_pending_q_lock);
if (!is_cmd_pend_q_empty) {
/* Send the first command in queue and return */
if (mwifiex_main_process(adapter) != -1)
@@ -574,7 +568,6 @@ static void mwifiex_delete_bss_prio_tbl(struct mwifiex_private *priv)
struct mwifiex_bss_prio_node *bssprio_node, *tmp_node;
struct list_head *head;
spinlock_t *lock; /* bss priority lock */
- unsigned long flags;
for (i = 0; i < adapter->priv_num; ++i) {
head = &adapter->bss_prio_tbl[i].bss_prio_head;
@@ -586,7 +579,7 @@ static void mwifiex_delete_bss_prio_tbl(struct mwifiex_private *priv)
priv->bss_type, priv->bss_num, i, head);
{
- spin_lock_irqsave(lock, flags);
+ spin_lock_bh(lock);
list_for_each_entry_safe(bssprio_node, tmp_node, head,
list) {
if (bssprio_node->priv == priv) {
@@ -598,7 +591,7 @@ static void mwifiex_delete_bss_prio_tbl(struct mwifiex_private *priv)
kfree(bssprio_node);
}
}
- spin_unlock_irqrestore(lock, flags);
+ spin_unlock_bh(lock);
}
}
}
@@ -630,7 +623,6 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
{
struct mwifiex_private *priv;
s32 i;
- unsigned long flags;
struct sk_buff *skb;
/* mwifiex already shutdown */
@@ -665,7 +657,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
while ((skb = skb_dequeue(&adapter->tx_data_q)))
mwifiex_write_data_complete(adapter, skb, 0, 0);
- spin_lock_irqsave(&adapter->rx_proc_lock, flags);
+ spin_lock_bh(&adapter->rx_proc_lock);
while ((skb = skb_dequeue(&adapter->rx_data_q))) {
struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
@@ -678,7 +670,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
dev_kfree_skb_any(skb);
}
- spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
+ spin_unlock_bh(&adapter->rx_proc_lock);
mwifiex_adapter_cleanup(adapter);
diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c
index f6da8edab7f1..a9657ae6d782 100644
--- a/drivers/net/wireless/marvell/mwifiex/main.c
+++ b/drivers/net/wireless/marvell/mwifiex/main.c
@@ -173,30 +173,27 @@ EXPORT_SYMBOL_GPL(mwifiex_queue_main_work);
static void mwifiex_queue_rx_work(struct mwifiex_adapter *adapter)
{
- unsigned long flags;
-
- spin_lock_irqsave(&adapter->rx_proc_lock, flags);
+ spin_lock_bh(&adapter->rx_proc_lock);
if (adapter->rx_processing) {
- spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
+ spin_unlock_bh(&adapter->rx_proc_lock);
} else {
- spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
+ spin_unlock_bh(&adapter->rx_proc_lock);
queue_work(adapter->rx_workqueue, &adapter->rx_work);
}
}
static int mwifiex_process_rx(struct mwifiex_adapter *adapter)
{
- unsigned long flags;
struct sk_buff *skb;
struct mwifiex_rxinfo *rx_info;
- spin_lock_irqsave(&adapter->rx_proc_lock, flags);
+ spin_lock_bh(&adapter->rx_proc_lock);
if (adapter->rx_processing || adapter->rx_locked) {
- spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
+ spin_unlock_bh(&adapter->rx_proc_lock);
goto exit_rx_proc;
} else {
adapter->rx_processing = true;
- spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
+ spin_unlock_bh(&adapter->rx_proc_lock);
}
/* Check for Rx data */
@@ -219,9 +216,9 @@ static int mwifiex_process_rx(struct mwifiex_adapter *adapter)
mwifiex_handle_rx_packet(adapter, skb);
}
}
- spin_lock_irqsave(&adapter->rx_proc_lock, flags);
+ spin_lock_bh(&adapter->rx_proc_lock);
adapter->rx_processing = false;
- spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
+ spin_unlock_bh(&adapter->rx_proc_lock);
exit_rx_proc:
return 0;
@@ -825,13 +822,12 @@ mwifiex_clone_skb_for_tx_status(struct mwifiex_private *priv,
skb = skb_clone(skb, GFP_ATOMIC);
if (skb) {
- unsigned long flags;
int id;
- spin_lock_irqsave(&priv->ack_status_lock, flags);
+ spin_lock_bh(&priv->ack_status_lock);
id = idr_alloc(&priv->ack_status_frames, orig_skb,
1, 0x10, GFP_ATOMIC);
- spin_unlock_irqrestore(&priv->ack_status_lock, flags);
+ spin_unlock_bh(&priv->ack_status_lock);
if (id >= 0) {
tx_info = MWIFIEX_SKB_TXCB(skb);
@@ -960,10 +956,10 @@ int mwifiex_set_mac_address(struct mwifiex_private *priv,
mac_addr = old_mac_addr;
- if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P)
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P) {
mac_addr |= BIT_ULL(MWIFIEX_MAC_LOCAL_ADMIN_BIT);
-
- if (mwifiex_get_intf_num(priv->adapter, priv->bss_type) > 1) {
+ mac_addr += priv->bss_num;
+ } else if (priv->adapter->priv[0] != priv) {
/* Set mac address based on bss_type/bss_num */
mac_addr ^= BIT_ULL(priv->bss_type + 8);
mac_addr += priv->bss_num;
@@ -1354,12 +1350,11 @@ void mwifiex_init_priv_params(struct mwifiex_private *priv,
*/
int is_command_pending(struct mwifiex_adapter *adapter)
{
- unsigned long flags;
int is_cmd_pend_q_empty;
- spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
+ spin_lock_bh(&adapter->cmd_pending_q_lock);
is_cmd_pend_q_empty = list_empty(&adapter->cmd_pending_q);
- spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
+ spin_unlock_bh(&adapter->cmd_pending_q_lock);
return !is_cmd_pend_q_empty;
}
diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h
index b025ba164412..3e442c7f7882 100644
--- a/drivers/net/wireless/marvell/mwifiex/main.h
+++ b/drivers/net/wireless/marvell/mwifiex/main.h
@@ -747,7 +747,7 @@ struct mwifiex_bss_prio_tbl {
struct cmd_ctrl_node {
struct list_head list;
struct mwifiex_private *priv;
- u32 cmd_oid;
+ u32 cmd_no;
u32 cmd_flag;
struct sk_buff *cmd_skb;
struct sk_buff *resp_skb;
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index 3fe81b2a929a..b54f73e3d508 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -2924,10 +2924,9 @@ static int mwifiex_init_pcie(struct mwifiex_adapter *adapter)
pci_set_master(pdev);
- pr_notice("try set_consistent_dma_mask(32)\n");
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (ret) {
- pr_err("set_dma_mask(32) failed\n");
+ pr_err("set_dma_mask(32) failed: %d\n", ret);
goto err_set_dma_mask;
}
@@ -2960,7 +2959,7 @@ static int mwifiex_init_pcie(struct mwifiex_adapter *adapter)
goto err_iomap2;
}
- pr_notice("PCI memory map Virt0: %p PCI memory map Virt2: %p\n",
+ pr_notice("PCI memory map Virt0: %pK PCI memory map Virt2: %pK\n",
card->pci_mmap, card->pci_mmap1);
ret = mwifiex_pcie_alloc_buffers(adapter);
diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c
index 935778ec9a1b..0d6d41727037 100644
--- a/drivers/net/wireless/marvell/mwifiex/scan.c
+++ b/drivers/net/wireless/marvell/mwifiex/scan.c
@@ -1247,6 +1247,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
}
switch (element_id) {
case WLAN_EID_SSID:
+ if (element_len > IEEE80211_MAX_SSID_LEN)
+ return -EINVAL;
bss_entry->ssid.ssid_len = element_len;
memcpy(bss_entry->ssid.ssid, (current_ptr + 2),
element_len);
@@ -1256,6 +1258,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
break;
case WLAN_EID_SUPP_RATES:
+ if (element_len > MWIFIEX_SUPPORTED_RATES)
+ return -EINVAL;
memcpy(bss_entry->data_rates, current_ptr + 2,
element_len);
memcpy(bss_entry->supported_rates, current_ptr + 2,
@@ -1265,6 +1269,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
break;
case WLAN_EID_FH_PARAMS:
+ if (element_len + 2 < sizeof(*fh_param_set))
+ return -EINVAL;
fh_param_set =
(struct ieee_types_fh_param_set *) current_ptr;
memcpy(&bss_entry->phy_param_set.fh_param_set,
@@ -1273,6 +1279,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
break;
case WLAN_EID_DS_PARAMS:
+ if (element_len + 2 < sizeof(*ds_param_set))
+ return -EINVAL;
ds_param_set =
(struct ieee_types_ds_param_set *) current_ptr;
@@ -1284,6 +1292,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
break;
case WLAN_EID_CF_PARAMS:
+ if (element_len + 2 < sizeof(*cf_param_set))
+ return -EINVAL;
cf_param_set =
(struct ieee_types_cf_param_set *) current_ptr;
memcpy(&bss_entry->ss_param_set.cf_param_set,
@@ -1292,6 +1302,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
break;
case WLAN_EID_IBSS_PARAMS:
+ if (element_len + 2 < sizeof(*ibss_param_set))
+ return -EINVAL;
ibss_param_set =
(struct ieee_types_ibss_param_set *)
current_ptr;
@@ -1301,10 +1313,14 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
break;
case WLAN_EID_ERP_INFO:
+ if (!element_len)
+ return -EINVAL;
bss_entry->erp_flags = *(current_ptr + 2);
break;
case WLAN_EID_PWR_CONSTRAINT:
+ if (!element_len)
+ return -EINVAL;
bss_entry->local_constraint = *(current_ptr + 2);
bss_entry->sensed_11h = true;
break;
@@ -1348,15 +1364,22 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
vendor_ie = (struct ieee_types_vendor_specific *)
current_ptr;
- if (!memcmp
- (vendor_ie->vend_hdr.oui, wpa_oui,
- sizeof(wpa_oui))) {
+ /* 802.11 requires at least 3-byte OUI. */
+ if (element_len < sizeof(vendor_ie->vend_hdr.oui.oui))
+ return -EINVAL;
+
+ /* Not long enough for a match? Skip it. */
+ if (element_len < sizeof(wpa_oui))
+ break;
+
+ if (!memcmp(&vendor_ie->vend_hdr.oui, wpa_oui,
+ sizeof(wpa_oui))) {
bss_entry->bcn_wpa_ie =
(struct ieee_types_vendor_specific *)
current_ptr;
bss_entry->wpa_offset = (u16)
(current_ptr - bss_entry->beacon_buf);
- } else if (!memcmp(vendor_ie->vend_hdr.oui, wmm_oui,
+ } else if (!memcmp(&vendor_ie->vend_hdr.oui, wmm_oui,
sizeof(wmm_oui))) {
if (total_ie_len ==
sizeof(struct ieee_types_wmm_parameter) ||
@@ -1481,7 +1504,6 @@ int mwifiex_scan_networks(struct mwifiex_private *priv,
u8 filtered_scan;
u8 scan_current_chan_only;
u8 max_chan_per_scan;
- unsigned long flags;
if (adapter->scan_processing) {
mwifiex_dbg(adapter, WARN,
@@ -1502,9 +1524,9 @@ int mwifiex_scan_networks(struct mwifiex_private *priv,
return -EFAULT;
}
- spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+ spin_lock_bh(&adapter->mwifiex_cmd_lock);
adapter->scan_processing = true;
- spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+ spin_unlock_bh(&adapter->mwifiex_cmd_lock);
scan_cfg_out = kzalloc(sizeof(union mwifiex_scan_cmd_config_tlv),
GFP_KERNEL);
@@ -1532,13 +1554,12 @@ int mwifiex_scan_networks(struct mwifiex_private *priv,
/* Get scan command from scan_pending_q and put to cmd_pending_q */
if (!ret) {
- spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+ spin_lock_bh(&adapter->scan_pending_q_lock);
if (!list_empty(&adapter->scan_pending_q)) {
cmd_node = list_first_entry(&adapter->scan_pending_q,
struct cmd_ctrl_node, list);
list_del(&cmd_node->list);
- spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
- flags);
+ spin_unlock_bh(&adapter->scan_pending_q_lock);
mwifiex_insert_cmd_to_pending_q(adapter, cmd_node);
queue_work(adapter->workqueue, &adapter->main_work);
@@ -1549,8 +1570,7 @@ int mwifiex_scan_networks(struct mwifiex_private *priv,
mwifiex_wait_queue_complete(adapter, cmd_node);
}
} else {
- spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
- flags);
+ spin_unlock_bh(&adapter->scan_pending_q_lock);
}
}
@@ -1558,9 +1578,9 @@ int mwifiex_scan_networks(struct mwifiex_private *priv,
kfree(scan_chan_list);
done:
if (ret) {
- spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+ spin_lock_bh(&adapter->mwifiex_cmd_lock);
adapter->scan_processing = false;
- spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+ spin_unlock_bh(&adapter->mwifiex_cmd_lock);
}
return ret;
}
@@ -1696,7 +1716,6 @@ static int mwifiex_update_curr_bss_params(struct mwifiex_private *priv,
{
struct mwifiex_bssdescriptor *bss_desc;
int ret;
- unsigned long flags;
/* Allocate and fill new bss descriptor */
bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor), GFP_KERNEL);
@@ -1711,7 +1730,7 @@ static int mwifiex_update_curr_bss_params(struct mwifiex_private *priv,
if (ret)
goto done;
- spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags);
+ spin_lock_bh(&priv->curr_bcn_buf_lock);
/* Make a copy of current BSSID descriptor */
memcpy(&priv->curr_bss_params.bss_descriptor, bss_desc,
sizeof(priv->curr_bss_params.bss_descriptor));
@@ -1720,7 +1739,7 @@ static int mwifiex_update_curr_bss_params(struct mwifiex_private *priv,
* in mwifiex_save_curr_bcn()
*/
mwifiex_save_curr_bcn(priv);
- spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags);
+ spin_unlock_bh(&priv->curr_bcn_buf_lock);
done:
/* beacon_ie buffer was allocated in function
@@ -1974,15 +1993,14 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv)
{
struct mwifiex_adapter *adapter = priv->adapter;
struct cmd_ctrl_node *cmd_node;
- unsigned long flags;
- spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+ spin_lock_bh(&adapter->scan_pending_q_lock);
if (list_empty(&adapter->scan_pending_q)) {
- spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+ spin_unlock_bh(&adapter->scan_pending_q_lock);
- spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+ spin_lock_bh(&adapter->mwifiex_cmd_lock);
adapter->scan_processing = false;
- spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+ spin_unlock_bh(&adapter->mwifiex_cmd_lock);
mwifiex_active_scan_req_for_passive_chan(priv);
@@ -2006,13 +2024,13 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv)
}
} else if ((priv->scan_aborting && !priv->scan_request) ||
priv->scan_block) {
- spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+ spin_unlock_bh(&adapter->scan_pending_q_lock);
mwifiex_cancel_pending_scan_cmd(adapter);
- spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+ spin_lock_bh(&adapter->mwifiex_cmd_lock);
adapter->scan_processing = false;
- spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+ spin_unlock_bh(&adapter->mwifiex_cmd_lock);
if (!adapter->active_scan_triggered) {
if (priv->scan_request) {
@@ -2038,7 +2056,7 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv)
cmd_node = list_first_entry(&adapter->scan_pending_q,
struct cmd_ctrl_node, list);
list_del(&cmd_node->list);
- spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+ spin_unlock_bh(&adapter->scan_pending_q_lock);
mwifiex_insert_cmd_to_pending_q(adapter, cmd_node);
}
@@ -2048,15 +2066,14 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv)
void mwifiex_cancel_scan(struct mwifiex_adapter *adapter)
{
struct mwifiex_private *priv;
- unsigned long cmd_flags;
int i;
mwifiex_cancel_pending_scan_cmd(adapter);
if (adapter->scan_processing) {
- spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
+ spin_lock_bh(&adapter->mwifiex_cmd_lock);
adapter->scan_processing = false;
- spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
+ spin_unlock_bh(&adapter->mwifiex_cmd_lock);
for (i = 0; i < adapter->priv_num; i++) {
priv = adapter->priv[i];
if (!priv)
@@ -2538,7 +2555,6 @@ int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv,
struct host_cmd_ds_command *cmd_ptr;
struct cmd_ctrl_node *cmd_node;
- unsigned long cmd_flags, scan_flags;
bool complete_scan = false;
mwifiex_dbg(adapter, INFO, "info: EXT scan returns successfully\n");
@@ -2573,8 +2589,8 @@ int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv,
sizeof(struct mwifiex_ie_types_header));
}
- spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_flags);
- spin_lock_irqsave(&adapter->scan_pending_q_lock, scan_flags);
+ spin_lock_bh(&adapter->cmd_pending_q_lock);
+ spin_lock_bh(&adapter->scan_pending_q_lock);
if (list_empty(&adapter->scan_pending_q)) {
complete_scan = true;
list_for_each_entry(cmd_node, &adapter->cmd_pending_q, list) {
@@ -2588,8 +2604,8 @@ int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv,
}
}
}
- spin_unlock_irqrestore(&adapter->scan_pending_q_lock, scan_flags);
- spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, cmd_flags);
+ spin_unlock_bh(&adapter->scan_pending_q_lock);
+ spin_unlock_bh(&adapter->cmd_pending_q_lock);
if (complete_scan)
mwifiex_complete_scan(priv);
@@ -2761,13 +2777,12 @@ mwifiex_queue_scan_cmd(struct mwifiex_private *priv,
struct cmd_ctrl_node *cmd_node)
{
struct mwifiex_adapter *adapter = priv->adapter;
- unsigned long flags;
cmd_node->wait_q_enabled = true;
cmd_node->condition = &adapter->scan_wait_q_woken;
- spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+ spin_lock_bh(&adapter->scan_pending_q_lock);
list_add_tail(&cmd_node->list, &adapter->scan_pending_q);
- spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+ spin_unlock_bh(&adapter->scan_pending_q_lock);
}
/*
diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c
index 24b33e20e7a9..20c206da0631 100644
--- a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c
+++ b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c
@@ -46,7 +46,6 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv,
{
struct mwifiex_adapter *adapter = priv->adapter;
struct host_cmd_ds_802_11_ps_mode_enh *pm;
- unsigned long flags;
mwifiex_dbg(adapter, ERROR,
"CMD_RESP: cmd %#x error, result=%#x\n",
@@ -87,9 +86,9 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv,
/* Handling errors here */
mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
- spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+ spin_lock_bh(&adapter->mwifiex_cmd_lock);
adapter->curr_cmd = NULL;
- spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+ spin_unlock_bh(&adapter->mwifiex_cmd_lock);
}
/*
diff --git a/drivers/net/wireless/marvell/mwifiex/sta_event.c b/drivers/net/wireless/marvell/mwifiex/sta_event.c
index 8b3123cb84c8..5fdffb114913 100644
--- a/drivers/net/wireless/marvell/mwifiex/sta_event.c
+++ b/drivers/net/wireless/marvell/mwifiex/sta_event.c
@@ -345,7 +345,6 @@ static void mwifiex_process_uap_tx_pause(struct mwifiex_private *priv,
{
struct mwifiex_tx_pause_tlv *tp;
struct mwifiex_sta_node *sta_ptr;
- unsigned long flags;
tp = (void *)tlv;
mwifiex_dbg(priv->adapter, EVENT,
@@ -361,14 +360,14 @@ static void mwifiex_process_uap_tx_pause(struct mwifiex_private *priv,
} else if (is_multicast_ether_addr(tp->peermac)) {
mwifiex_update_ralist_tx_pause(priv, tp->peermac, tp->tx_pause);
} else {
- spin_lock_irqsave(&priv->sta_list_spinlock, flags);
+ spin_lock_bh(&priv->sta_list_spinlock);
sta_ptr = mwifiex_get_sta_entry(priv, tp->peermac);
if (sta_ptr && sta_ptr->tx_pause != tp->tx_pause) {
sta_ptr->tx_pause = tp->tx_pause;
mwifiex_update_ralist_tx_pause(priv, tp->peermac,
tp->tx_pause);
}
- spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+ spin_unlock_bh(&priv->sta_list_spinlock);
}
}
@@ -378,7 +377,6 @@ static void mwifiex_process_sta_tx_pause(struct mwifiex_private *priv,
struct mwifiex_tx_pause_tlv *tp;
struct mwifiex_sta_node *sta_ptr;
int status;
- unsigned long flags;
tp = (void *)tlv;
mwifiex_dbg(priv->adapter, EVENT,
@@ -397,7 +395,7 @@ static void mwifiex_process_sta_tx_pause(struct mwifiex_private *priv,
status = mwifiex_get_tdls_link_status(priv, tp->peermac);
if (mwifiex_is_tdls_link_setup(status)) {
- spin_lock_irqsave(&priv->sta_list_spinlock, flags);
+ spin_lock_bh(&priv->sta_list_spinlock);
sta_ptr = mwifiex_get_sta_entry(priv, tp->peermac);
if (sta_ptr && sta_ptr->tx_pause != tp->tx_pause) {
sta_ptr->tx_pause = tp->tx_pause;
@@ -405,7 +403,7 @@ static void mwifiex_process_sta_tx_pause(struct mwifiex_private *priv,
tp->peermac,
tp->tx_pause);
}
- spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+ spin_unlock_bh(&priv->sta_list_spinlock);
}
}
}
diff --git a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c
index ebc0e41e5d3b..74e50566db1f 100644
--- a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c
@@ -1351,7 +1351,7 @@ mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr,
/* Test to see if it is a WPA IE, if not, then
* it is a gen IE
*/
- if (!memcmp(pvendor_ie->oui, wpa_oui,
+ if (!memcmp(&pvendor_ie->oui, wpa_oui,
sizeof(wpa_oui))) {
/* IE is a WPA/WPA2 IE so call set_wpa function
*/
@@ -1361,7 +1361,7 @@ mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr,
goto next_ie;
}
- if (!memcmp(pvendor_ie->oui, wps_oui,
+ if (!memcmp(&pvendor_ie->oui, wps_oui,
sizeof(wps_oui))) {
/* Test to see if it is a WPS IE,
* if so, enable wps session flag
diff --git a/drivers/net/wireless/marvell/mwifiex/tdls.c b/drivers/net/wireless/marvell/mwifiex/tdls.c
index 27779d7317fd..18e654dc34c6 100644
--- a/drivers/net/wireless/marvell/mwifiex/tdls.c
+++ b/drivers/net/wireless/marvell/mwifiex/tdls.c
@@ -33,12 +33,11 @@ static void mwifiex_restore_tdls_packets(struct mwifiex_private *priv,
struct list_head *tid_list;
struct sk_buff *skb, *tmp;
struct mwifiex_txinfo *tx_info;
- unsigned long flags;
u32 tid;
u8 tid_down;
mwifiex_dbg(priv->adapter, DATA, "%s: %pM\n", __func__, mac);
- spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
+ spin_lock_bh(&priv->wmm.ra_list_spinlock);
skb_queue_walk_safe(&priv->tdls_txq, skb, tmp) {
if (!ether_addr_equal(mac, skb->data))
@@ -78,7 +77,7 @@ static void mwifiex_restore_tdls_packets(struct mwifiex_private *priv,
atomic_inc(&priv->wmm.tx_pkts_queued);
}
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
return;
}
@@ -88,11 +87,10 @@ static void mwifiex_hold_tdls_packets(struct mwifiex_private *priv,
struct mwifiex_ra_list_tbl *ra_list;
struct list_head *ra_list_head;
struct sk_buff *skb, *tmp;
- unsigned long flags;
int i;
mwifiex_dbg(priv->adapter, DATA, "%s: %pM\n", __func__, mac);
- spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
+ spin_lock_bh(&priv->wmm.ra_list_spinlock);
for (i = 0; i < MAX_NUM_TID; i++) {
if (!list_empty(&priv->wmm.tid_tbl_ptr[i].ra_list)) {
@@ -111,7 +109,7 @@ static void mwifiex_hold_tdls_packets(struct mwifiex_private *priv,
}
}
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
return;
}
@@ -1070,7 +1068,6 @@ mwifiex_tdls_process_disable_link(struct mwifiex_private *priv, const u8 *peer)
{
struct mwifiex_sta_node *sta_ptr;
struct mwifiex_ds_tdls_oper tdls_oper;
- unsigned long flags;
memset(&tdls_oper, 0, sizeof(struct mwifiex_ds_tdls_oper));
sta_ptr = mwifiex_get_sta_entry(priv, peer);
@@ -1078,11 +1075,9 @@ mwifiex_tdls_process_disable_link(struct mwifiex_private *priv, const u8 *peer)
if (sta_ptr) {
if (sta_ptr->is_11n_enabled) {
mwifiex_11n_cleanup_reorder_tbl(priv);
- spin_lock_irqsave(&priv->wmm.ra_list_spinlock,
- flags);
+ spin_lock_bh(&priv->wmm.ra_list_spinlock);
mwifiex_11n_delete_all_tx_ba_stream_tbl(priv);
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
- flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
}
mwifiex_del_sta_entry(priv, peer);
}
@@ -1100,7 +1095,6 @@ mwifiex_tdls_process_enable_link(struct mwifiex_private *priv, const u8 *peer)
{
struct mwifiex_sta_node *sta_ptr;
struct ieee80211_mcs_info mcs;
- unsigned long flags;
int i;
sta_ptr = mwifiex_get_sta_entry(priv, peer);
@@ -1145,11 +1139,9 @@ mwifiex_tdls_process_enable_link(struct mwifiex_private *priv, const u8 *peer)
"tdls: enable link %pM failed\n", peer);
if (sta_ptr) {
mwifiex_11n_cleanup_reorder_tbl(priv);
- spin_lock_irqsave(&priv->wmm.ra_list_spinlock,
- flags);
+ spin_lock_bh(&priv->wmm.ra_list_spinlock);
mwifiex_11n_delete_all_tx_ba_stream_tbl(priv);
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
- flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
mwifiex_del_sta_entry(priv, peer);
}
mwifiex_restore_tdls_packets(priv, peer, TDLS_LINK_TEARDOWN);
@@ -1194,7 +1186,6 @@ int mwifiex_get_tdls_list(struct mwifiex_private *priv,
struct mwifiex_sta_node *sta_ptr;
struct tdls_peer_info *peer = buf;
int count = 0;
- unsigned long flags;
if (!ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info))
return 0;
@@ -1203,7 +1194,7 @@ int mwifiex_get_tdls_list(struct mwifiex_private *priv,
if (!(priv->bss_type == MWIFIEX_BSS_TYPE_STA && priv->media_connected))
return 0;
- spin_lock_irqsave(&priv->sta_list_spinlock, flags);
+ spin_lock_bh(&priv->sta_list_spinlock);
list_for_each_entry(sta_ptr, &priv->sta_list, list) {
if (mwifiex_is_tdls_link_setup(sta_ptr->tdls_status)) {
ether_addr_copy(peer->peer_addr, sta_ptr->mac_addr);
@@ -1213,7 +1204,7 @@ int mwifiex_get_tdls_list(struct mwifiex_private *priv,
break;
}
}
- spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+ spin_unlock_bh(&priv->sta_list_spinlock);
return count;
}
@@ -1222,7 +1213,6 @@ void mwifiex_disable_all_tdls_links(struct mwifiex_private *priv)
{
struct mwifiex_sta_node *sta_ptr;
struct mwifiex_ds_tdls_oper tdls_oper;
- unsigned long flags;
if (list_empty(&priv->sta_list))
return;
@@ -1232,11 +1222,9 @@ void mwifiex_disable_all_tdls_links(struct mwifiex_private *priv)
if (sta_ptr->is_11n_enabled) {
mwifiex_11n_cleanup_reorder_tbl(priv);
- spin_lock_irqsave(&priv->wmm.ra_list_spinlock,
- flags);
+ spin_lock_bh(&priv->wmm.ra_list_spinlock);
mwifiex_11n_delete_all_tx_ba_stream_tbl(priv);
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
- flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
}
mwifiex_restore_tdls_packets(priv, sta_ptr->mac_addr,
@@ -1256,12 +1244,11 @@ void mwifiex_disable_all_tdls_links(struct mwifiex_private *priv)
int mwifiex_tdls_check_tx(struct mwifiex_private *priv, struct sk_buff *skb)
{
struct mwifiex_auto_tdls_peer *peer;
- unsigned long flags;
u8 mac[ETH_ALEN];
ether_addr_copy(mac, skb->data);
- spin_lock_irqsave(&priv->auto_tdls_lock, flags);
+ spin_lock_bh(&priv->auto_tdls_lock);
list_for_each_entry(peer, &priv->auto_tdls_list, list) {
if (!memcmp(mac, peer->mac_addr, ETH_ALEN)) {
if (peer->rssi <= MWIFIEX_TDLS_RSSI_HIGH &&
@@ -1290,7 +1277,7 @@ int mwifiex_tdls_check_tx(struct mwifiex_private *priv, struct sk_buff *skb)
}
}
}
- spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
+ spin_unlock_bh(&priv->auto_tdls_lock);
return 0;
}
@@ -1298,33 +1285,31 @@ int mwifiex_tdls_check_tx(struct mwifiex_private *priv, struct sk_buff *skb)
void mwifiex_flush_auto_tdls_list(struct mwifiex_private *priv)
{
struct mwifiex_auto_tdls_peer *peer, *tmp_node;
- unsigned long flags;
- spin_lock_irqsave(&priv->auto_tdls_lock, flags);
+ spin_lock_bh(&priv->auto_tdls_lock);
list_for_each_entry_safe(peer, tmp_node, &priv->auto_tdls_list, list) {
list_del(&peer->list);
kfree(peer);
}
INIT_LIST_HEAD(&priv->auto_tdls_list);
- spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
+ spin_unlock_bh(&priv->auto_tdls_lock);
priv->check_tdls_tx = false;
}
void mwifiex_add_auto_tdls_peer(struct mwifiex_private *priv, const u8 *mac)
{
struct mwifiex_auto_tdls_peer *tdls_peer;
- unsigned long flags;
if (!priv->adapter->auto_tdls)
return;
- spin_lock_irqsave(&priv->auto_tdls_lock, flags);
+ spin_lock_bh(&priv->auto_tdls_lock);
list_for_each_entry(tdls_peer, &priv->auto_tdls_list, list) {
if (!memcmp(tdls_peer->mac_addr, mac, ETH_ALEN)) {
tdls_peer->tdls_status = TDLS_SETUP_INPROGRESS;
tdls_peer->rssi_jiffies = jiffies;
- spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
+ spin_unlock_bh(&priv->auto_tdls_lock);
return;
}
}
@@ -1341,19 +1326,18 @@ void mwifiex_add_auto_tdls_peer(struct mwifiex_private *priv, const u8 *mac)
"Add auto TDLS peer= %pM to list\n", mac);
}
- spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
+ spin_unlock_bh(&priv->auto_tdls_lock);
}
void mwifiex_auto_tdls_update_peer_status(struct mwifiex_private *priv,
const u8 *mac, u8 link_status)
{
struct mwifiex_auto_tdls_peer *peer;
- unsigned long flags;
if (!priv->adapter->auto_tdls)
return;
- spin_lock_irqsave(&priv->auto_tdls_lock, flags);
+ spin_lock_bh(&priv->auto_tdls_lock);
list_for_each_entry(peer, &priv->auto_tdls_list, list) {
if (!memcmp(peer->mac_addr, mac, ETH_ALEN)) {
if ((link_status == TDLS_NOT_SETUP) &&
@@ -1366,19 +1350,18 @@ void mwifiex_auto_tdls_update_peer_status(struct mwifiex_private *priv,
break;
}
}
- spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
+ spin_unlock_bh(&priv->auto_tdls_lock);
}
void mwifiex_auto_tdls_update_peer_signal(struct mwifiex_private *priv,
u8 *mac, s8 snr, s8 nflr)
{
struct mwifiex_auto_tdls_peer *peer;
- unsigned long flags;
if (!priv->adapter->auto_tdls)
return;
- spin_lock_irqsave(&priv->auto_tdls_lock, flags);
+ spin_lock_bh(&priv->auto_tdls_lock);
list_for_each_entry(peer, &priv->auto_tdls_list, list) {
if (!memcmp(peer->mac_addr, mac, ETH_ALEN)) {
peer->rssi = nflr - snr;
@@ -1386,14 +1369,13 @@ void mwifiex_auto_tdls_update_peer_signal(struct mwifiex_private *priv,
break;
}
}
- spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
+ spin_unlock_bh(&priv->auto_tdls_lock);
}
void mwifiex_check_auto_tdls(struct timer_list *t)
{
struct mwifiex_private *priv = from_timer(priv, t, auto_tdls_timer);
struct mwifiex_auto_tdls_peer *tdls_peer;
- unsigned long flags;
u16 reason = WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED;
if (WARN_ON_ONCE(!priv || !priv->adapter)) {
@@ -1413,7 +1395,7 @@ void mwifiex_check_auto_tdls(struct timer_list *t)
priv->check_tdls_tx = false;
- spin_lock_irqsave(&priv->auto_tdls_lock, flags);
+ spin_lock_bh(&priv->auto_tdls_lock);
list_for_each_entry(tdls_peer, &priv->auto_tdls_list, list) {
if ((jiffies - tdls_peer->rssi_jiffies) >
(MWIFIEX_AUTO_TDLS_IDLE_TIME * HZ)) {
@@ -1448,7 +1430,7 @@ void mwifiex_check_auto_tdls(struct timer_list *t)
tdls_peer->rssi);
}
}
- spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
+ spin_unlock_bh(&priv->auto_tdls_lock);
mod_timer(&priv->auto_tdls_timer,
jiffies + msecs_to_jiffies(MWIFIEX_TIMER_10S));
diff --git a/drivers/net/wireless/marvell/mwifiex/txrx.c b/drivers/net/wireless/marvell/mwifiex/txrx.c
index d848933466d9..e3c1446dd847 100644
--- a/drivers/net/wireless/marvell/mwifiex/txrx.c
+++ b/drivers/net/wireless/marvell/mwifiex/txrx.c
@@ -334,15 +334,14 @@ void mwifiex_parse_tx_status_event(struct mwifiex_private *priv,
{
struct tx_status_event *tx_status = (void *)priv->adapter->event_body;
struct sk_buff *ack_skb;
- unsigned long flags;
struct mwifiex_txinfo *tx_info;
if (!tx_status->tx_token_id)
return;
- spin_lock_irqsave(&priv->ack_status_lock, flags);
+ spin_lock_bh(&priv->ack_status_lock);
ack_skb = idr_remove(&priv->ack_status_frames, tx_status->tx_token_id);
- spin_unlock_irqrestore(&priv->ack_status_lock, flags);
+ spin_unlock_bh(&priv->ack_status_lock);
if (ack_skb) {
tx_info = MWIFIEX_SKB_TXCB(ack_skb);
diff --git a/drivers/net/wireless/marvell/mwifiex/uap_txrx.c b/drivers/net/wireless/marvell/mwifiex/uap_txrx.c
index 5ce85d5727e4..354b09c5e8dc 100644
--- a/drivers/net/wireless/marvell/mwifiex/uap_txrx.c
+++ b/drivers/net/wireless/marvell/mwifiex/uap_txrx.c
@@ -71,11 +71,10 @@ mwifiex_uap_del_tx_pkts_in_ralist(struct mwifiex_private *priv,
*/
static void mwifiex_uap_cleanup_tx_queues(struct mwifiex_private *priv)
{
- unsigned long flags;
struct list_head *ra_list;
int i;
- spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
+ spin_lock_bh(&priv->wmm.ra_list_spinlock);
for (i = 0; i < MAX_NUM_TID; i++, priv->del_list_idx++) {
if (priv->del_list_idx == MAX_NUM_TID)
@@ -87,7 +86,7 @@ static void mwifiex_uap_cleanup_tx_queues(struct mwifiex_private *priv)
}
}
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
}
@@ -378,7 +377,6 @@ int mwifiex_process_uap_rx_packet(struct mwifiex_private *priv,
struct rx_packet_hdr *rx_pkt_hdr;
u16 rx_pkt_type;
u8 ta[ETH_ALEN], pkt_type;
- unsigned long flags;
struct mwifiex_sta_node *node;
uap_rx_pd = (struct uap_rxpd *)(skb->data);
@@ -413,12 +411,12 @@ int mwifiex_process_uap_rx_packet(struct mwifiex_private *priv,
if (rx_pkt_type != PKT_TYPE_BAR && uap_rx_pd->priority < MAX_NUM_TID) {
- spin_lock_irqsave(&priv->sta_list_spinlock, flags);
+ spin_lock_bh(&priv->sta_list_spinlock);
node = mwifiex_get_sta_entry(priv, ta);
if (node)
node->rx_seq[uap_rx_pd->priority] =
le16_to_cpu(uap_rx_pd->seq_num);
- spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+ spin_unlock_bh(&priv->sta_list_spinlock);
}
if (!priv->ap_11n_enabled ||
diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c
index d445acc4786b..c2365eeb7016 100644
--- a/drivers/net/wireless/marvell/mwifiex/usb.c
+++ b/drivers/net/wireless/marvell/mwifiex/usb.c
@@ -1128,10 +1128,9 @@ static void mwifiex_usb_tx_aggr_tmo(struct timer_list *t)
from_timer(timer_context, t, hold_timer);
struct mwifiex_adapter *adapter = timer_context->adapter;
struct usb_tx_data_port *port = timer_context->port;
- unsigned long flags;
int err = 0;
- spin_lock_irqsave(&port->tx_aggr_lock, flags);
+ spin_lock_bh(&port->tx_aggr_lock);
err = mwifiex_usb_prepare_tx_aggr_skb(adapter, port, &skb_send);
if (err) {
mwifiex_dbg(adapter, ERROR,
@@ -1158,7 +1157,7 @@ done:
if (err == -1)
mwifiex_write_data_complete(adapter, skb_send, 0, -1);
unlock:
- spin_unlock_irqrestore(&port->tx_aggr_lock, flags);
+ spin_unlock_bh(&port->tx_aggr_lock);
}
/* This function write a command/data packet to card. */
@@ -1169,7 +1168,6 @@ static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep,
struct usb_card_rec *card = adapter->card;
struct urb_context *context = NULL;
struct usb_tx_data_port *port = NULL;
- unsigned long flags;
int idx, ret;
if (test_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags)) {
@@ -1211,10 +1209,10 @@ static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep,
}
if (adapter->bus_aggr.enable) {
- spin_lock_irqsave(&port->tx_aggr_lock, flags);
+ spin_lock_bh(&port->tx_aggr_lock);
ret = mwifiex_usb_aggr_tx_data(adapter, ep, skb,
tx_param, port);
- spin_unlock_irqrestore(&port->tx_aggr_lock, flags);
+ spin_unlock_bh(&port->tx_aggr_lock);
return ret;
}
diff --git a/drivers/net/wireless/marvell/mwifiex/util.c b/drivers/net/wireless/marvell/mwifiex/util.c
index f9b71539d33e..3b0d31827681 100644
--- a/drivers/net/wireless/marvell/mwifiex/util.c
+++ b/drivers/net/wireless/marvell/mwifiex/util.c
@@ -607,12 +607,11 @@ struct mwifiex_sta_node *
mwifiex_add_sta_entry(struct mwifiex_private *priv, const u8 *mac)
{
struct mwifiex_sta_node *node;
- unsigned long flags;
if (!mac)
return NULL;
- spin_lock_irqsave(&priv->sta_list_spinlock, flags);
+ spin_lock_bh(&priv->sta_list_spinlock);
node = mwifiex_get_sta_entry(priv, mac);
if (node)
goto done;
@@ -625,7 +624,7 @@ mwifiex_add_sta_entry(struct mwifiex_private *priv, const u8 *mac)
list_add_tail(&node->list, &priv->sta_list);
done:
- spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+ spin_unlock_bh(&priv->sta_list_spinlock);
return node;
}
@@ -662,9 +661,8 @@ mwifiex_set_sta_ht_cap(struct mwifiex_private *priv, const u8 *ies,
void mwifiex_del_sta_entry(struct mwifiex_private *priv, const u8 *mac)
{
struct mwifiex_sta_node *node;
- unsigned long flags;
- spin_lock_irqsave(&priv->sta_list_spinlock, flags);
+ spin_lock_bh(&priv->sta_list_spinlock);
node = mwifiex_get_sta_entry(priv, mac);
if (node) {
@@ -672,7 +670,7 @@ void mwifiex_del_sta_entry(struct mwifiex_private *priv, const u8 *mac)
kfree(node);
}
- spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+ spin_unlock_bh(&priv->sta_list_spinlock);
return;
}
@@ -680,9 +678,8 @@ void mwifiex_del_sta_entry(struct mwifiex_private *priv, const u8 *mac)
void mwifiex_del_all_sta_list(struct mwifiex_private *priv)
{
struct mwifiex_sta_node *node, *tmp;
- unsigned long flags;
- spin_lock_irqsave(&priv->sta_list_spinlock, flags);
+ spin_lock_bh(&priv->sta_list_spinlock);
list_for_each_entry_safe(node, tmp, &priv->sta_list, list) {
list_del(&node->list);
@@ -690,7 +687,7 @@ void mwifiex_del_all_sta_list(struct mwifiex_private *priv)
}
INIT_LIST_HEAD(&priv->sta_list);
- spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+ spin_unlock_bh(&priv->sta_list_spinlock);
return;
}
diff --git a/drivers/net/wireless/marvell/mwifiex/wmm.c b/drivers/net/wireless/marvell/mwifiex/wmm.c
index 407b9932ca4d..41f0231376c0 100644
--- a/drivers/net/wireless/marvell/mwifiex/wmm.c
+++ b/drivers/net/wireless/marvell/mwifiex/wmm.c
@@ -138,7 +138,6 @@ void mwifiex_ralist_add(struct mwifiex_private *priv, const u8 *ra)
struct mwifiex_ra_list_tbl *ra_list;
struct mwifiex_adapter *adapter = priv->adapter;
struct mwifiex_sta_node *node;
- unsigned long flags;
for (i = 0; i < MAX_NUM_TID; ++i) {
@@ -163,7 +162,7 @@ void mwifiex_ralist_add(struct mwifiex_private *priv, const u8 *ra)
ra_list->is_11n_enabled = IS_11N_ENABLED(priv);
}
} else {
- spin_lock_irqsave(&priv->sta_list_spinlock, flags);
+ spin_lock_bh(&priv->sta_list_spinlock);
node = mwifiex_get_sta_entry(priv, ra);
if (node)
ra_list->tx_paused = node->tx_pause;
@@ -171,7 +170,7 @@ void mwifiex_ralist_add(struct mwifiex_private *priv, const u8 *ra)
mwifiex_is_sta_11n_enabled(priv, node);
if (ra_list->is_11n_enabled)
ra_list->max_amsdu = node->max_amsdu;
- spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+ spin_unlock_bh(&priv->sta_list_spinlock);
}
mwifiex_dbg(adapter, DATA, "data: ralist %p: is_11n_enabled=%d\n",
@@ -240,7 +239,7 @@ mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv,
mwifiex_dbg(priv->adapter, INFO,
"info: WMM Parameter IE: version=%d,\t"
"qos_info Parameter Set Count=%d, Reserved=%#x\n",
- wmm_ie->vend_hdr.version, wmm_ie->qos_info_bitmap &
+ wmm_ie->version, wmm_ie->qos_info_bitmap &
IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK,
wmm_ie->reserved);
@@ -583,11 +582,10 @@ static int mwifiex_free_ack_frame(int id, void *p, void *data)
void
mwifiex_clean_txrx(struct mwifiex_private *priv)
{
- unsigned long flags;
struct sk_buff *skb, *tmp;
mwifiex_11n_cleanup_reorder_tbl(priv);
- spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
+ spin_lock_bh(&priv->wmm.ra_list_spinlock);
mwifiex_wmm_cleanup_queues(priv);
mwifiex_11n_delete_all_tx_ba_stream_tbl(priv);
@@ -601,7 +599,7 @@ mwifiex_clean_txrx(struct mwifiex_private *priv)
if (priv->adapter->if_ops.clean_pcie_ring &&
!test_bit(MWIFIEX_SURPRISE_REMOVED, &priv->adapter->work_flags))
priv->adapter->if_ops.clean_pcie_ring(priv->adapter);
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
skb_queue_walk_safe(&priv->tdls_txq, skb, tmp) {
skb_unlink(skb, &priv->tdls_txq);
@@ -642,10 +640,9 @@ void mwifiex_update_ralist_tx_pause(struct mwifiex_private *priv, u8 *mac,
{
struct mwifiex_ra_list_tbl *ra_list;
u32 pkt_cnt = 0, tx_pkts_queued;
- unsigned long flags;
int i;
- spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
+ spin_lock_bh(&priv->wmm.ra_list_spinlock);
for (i = 0; i < MAX_NUM_TID; ++i) {
ra_list = mwifiex_wmm_get_ralist_node(priv, i, mac);
@@ -671,7 +668,7 @@ void mwifiex_update_ralist_tx_pause(struct mwifiex_private *priv, u8 *mac,
atomic_set(&priv->wmm.tx_pkts_queued, tx_pkts_queued);
atomic_set(&priv->wmm.highest_queued_prio, HIGH_PRIO_TID);
}
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
}
/* This function updates non-tdls peer ralist tx_pause while
@@ -682,10 +679,9 @@ void mwifiex_update_ralist_tx_pause_in_tdls_cs(struct mwifiex_private *priv,
{
struct mwifiex_ra_list_tbl *ra_list;
u32 pkt_cnt = 0, tx_pkts_queued;
- unsigned long flags;
int i;
- spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
+ spin_lock_bh(&priv->wmm.ra_list_spinlock);
for (i = 0; i < MAX_NUM_TID; ++i) {
list_for_each_entry(ra_list, &priv->wmm.tid_tbl_ptr[i].ra_list,
@@ -716,7 +712,7 @@ void mwifiex_update_ralist_tx_pause_in_tdls_cs(struct mwifiex_private *priv,
atomic_set(&priv->wmm.tx_pkts_queued, tx_pkts_queued);
atomic_set(&priv->wmm.highest_queued_prio, HIGH_PRIO_TID);
}
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
}
/*
@@ -748,10 +744,9 @@ void
mwifiex_wmm_del_peer_ra_list(struct mwifiex_private *priv, const u8 *ra_addr)
{
struct mwifiex_ra_list_tbl *ra_list;
- unsigned long flags;
int i;
- spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
+ spin_lock_bh(&priv->wmm.ra_list_spinlock);
for (i = 0; i < MAX_NUM_TID; ++i) {
ra_list = mwifiex_wmm_get_ralist_node(priv, i, ra_addr);
@@ -767,7 +762,7 @@ mwifiex_wmm_del_peer_ra_list(struct mwifiex_private *priv, const u8 *ra_addr)
list_del(&ra_list->list);
kfree(ra_list);
}
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
}
/*
@@ -818,7 +813,6 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,
u32 tid;
struct mwifiex_ra_list_tbl *ra_list;
u8 ra[ETH_ALEN], tid_down;
- unsigned long flags;
struct list_head list_head;
int tdls_status = TDLS_NOT_SETUP;
struct ethhdr *eth_hdr = (struct ethhdr *)skb->data;
@@ -844,7 +838,7 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,
tid = skb->priority;
- spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
+ spin_lock_bh(&priv->wmm.ra_list_spinlock);
tid_down = mwifiex_wmm_downgrade_tid(priv, tid);
@@ -864,8 +858,7 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,
break;
case TDLS_SETUP_INPROGRESS:
skb_queue_tail(&priv->tdls_txq, skb);
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
- flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
return;
default:
list_head = priv->wmm.tid_tbl_ptr[tid_down].ra_list;
@@ -881,7 +874,7 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,
}
if (!ra_list) {
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
mwifiex_write_data_complete(adapter, skb, 0, -1);
return;
}
@@ -901,7 +894,7 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,
else
atomic_inc(&priv->wmm.tx_pkts_queued);
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
}
/*
@@ -1092,7 +1085,6 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
struct mwifiex_ra_list_tbl *ptr;
struct mwifiex_tid_tbl *tid_ptr;
atomic_t *hqp;
- unsigned long flags_ra;
int i, j;
/* check the BSS with highest priority first */
@@ -1118,8 +1110,7 @@ try_again:
hqp = &priv_tmp->wmm.highest_queued_prio;
for (i = atomic_read(hqp); i >= LOW_PRIO_TID; --i) {
- spin_lock_irqsave(&priv_tmp->wmm.
- ra_list_spinlock, flags_ra);
+ spin_lock_bh(&priv_tmp->wmm.ra_list_spinlock);
tid_ptr = &(priv_tmp)->wmm.
tid_tbl_ptr[tos_to_tid[i]];
@@ -1134,9 +1125,7 @@ try_again:
goto found;
}
- spin_unlock_irqrestore(&priv_tmp->wmm.
- ra_list_spinlock,
- flags_ra);
+ spin_unlock_bh(&priv_tmp->wmm.ra_list_spinlock);
}
if (atomic_read(&priv_tmp->wmm.tx_pkts_queued) != 0) {
@@ -1158,7 +1147,7 @@ found:
/* holds ra_list_spinlock */
if (atomic_read(hqp) > i)
atomic_set(hqp, i);
- spin_unlock_irqrestore(&priv_tmp->wmm.ra_list_spinlock, flags_ra);
+ spin_unlock_bh(&priv_tmp->wmm.ra_list_spinlock);
*priv = priv_tmp;
*tid = tos_to_tid[i];
@@ -1182,24 +1171,23 @@ void mwifiex_rotate_priolists(struct mwifiex_private *priv,
struct mwifiex_adapter *adapter = priv->adapter;
struct mwifiex_bss_prio_tbl *tbl = adapter->bss_prio_tbl;
struct mwifiex_tid_tbl *tid_ptr = &priv->wmm.tid_tbl_ptr[tid];
- unsigned long flags;
- spin_lock_irqsave(&tbl[priv->bss_priority].bss_prio_lock, flags);
+ spin_lock_bh(&tbl[priv->bss_priority].bss_prio_lock);
/*
* dirty trick: we remove 'head' temporarily and reinsert it after
* curr bss node. imagine list to stay fixed while head is moved
*/
list_move(&tbl[priv->bss_priority].bss_prio_head,
&tbl[priv->bss_priority].bss_prio_cur->list);
- spin_unlock_irqrestore(&tbl[priv->bss_priority].bss_prio_lock, flags);
+ spin_unlock_bh(&tbl[priv->bss_priority].bss_prio_lock);
- spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
+ spin_lock_bh(&priv->wmm.ra_list_spinlock);
if (mwifiex_is_ralist_valid(priv, ra, tid)) {
priv->wmm.packets_out[tid]++;
/* same as above */
list_move(&tid_ptr->ra_list, &ra->list);
}
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
}
/*
@@ -1236,8 +1224,7 @@ mwifiex_is_11n_aggragation_possible(struct mwifiex_private *priv,
*/
static void
mwifiex_send_single_packet(struct mwifiex_private *priv,
- struct mwifiex_ra_list_tbl *ptr, int ptr_index,
- unsigned long ra_list_flags)
+ struct mwifiex_ra_list_tbl *ptr, int ptr_index)
__releases(&priv->wmm.ra_list_spinlock)
{
struct sk_buff *skb, *skb_next;
@@ -1246,8 +1233,7 @@ mwifiex_send_single_packet(struct mwifiex_private *priv,
struct mwifiex_txinfo *tx_info;
if (skb_queue_empty(&ptr->skb_head)) {
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
- ra_list_flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
mwifiex_dbg(adapter, DATA, "data: nothing to send\n");
return;
}
@@ -1265,18 +1251,17 @@ mwifiex_send_single_packet(struct mwifiex_private *priv,
else
skb_next = NULL;
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
tx_param.next_pkt_len = ((skb_next) ? skb_next->len +
sizeof(struct txpd) : 0);
if (mwifiex_process_tx(priv, skb, &tx_param) == -EBUSY) {
/* Queue the packet back at the head */
- spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
+ spin_lock_bh(&priv->wmm.ra_list_spinlock);
if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
- ra_list_flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
mwifiex_write_data_complete(adapter, skb, 0, -1);
return;
}
@@ -1286,8 +1271,7 @@ mwifiex_send_single_packet(struct mwifiex_private *priv,
ptr->total_pkt_count++;
ptr->ba_pkt_count++;
tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT;
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
- ra_list_flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
} else {
mwifiex_rotate_priolists(priv, ptr, ptr_index);
atomic_dec(&priv->wmm.tx_pkts_queued);
@@ -1323,8 +1307,7 @@ mwifiex_is_ptr_processed(struct mwifiex_private *priv,
*/
static void
mwifiex_send_processed_packet(struct mwifiex_private *priv,
- struct mwifiex_ra_list_tbl *ptr, int ptr_index,
- unsigned long ra_list_flags)
+ struct mwifiex_ra_list_tbl *ptr, int ptr_index)
__releases(&priv->wmm.ra_list_spinlock)
{
struct mwifiex_tx_param tx_param;
@@ -1334,8 +1317,7 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,
struct mwifiex_txinfo *tx_info;
if (skb_queue_empty(&ptr->skb_head)) {
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
- ra_list_flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
return;
}
@@ -1343,8 +1325,7 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,
if (adapter->data_sent || adapter->tx_lock_flag) {
ptr->total_pkt_count--;
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
- ra_list_flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
skb_queue_tail(&adapter->tx_data_q, skb);
atomic_dec(&priv->wmm.tx_pkts_queued);
atomic_inc(&adapter->tx_queued);
@@ -1358,7 +1339,7 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,
tx_info = MWIFIEX_SKB_TXCB(skb);
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
tx_param.next_pkt_len =
((skb_next) ? skb_next->len +
@@ -1374,11 +1355,10 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,
switch (ret) {
case -EBUSY:
mwifiex_dbg(adapter, ERROR, "data: -EBUSY is returned\n");
- spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
+ spin_lock_bh(&priv->wmm.ra_list_spinlock);
if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
- ra_list_flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
mwifiex_write_data_complete(adapter, skb, 0, -1);
return;
}
@@ -1386,8 +1366,7 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,
skb_queue_tail(&ptr->skb_head, skb);
tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT;
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
- ra_list_flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
break;
case -1:
mwifiex_dbg(adapter, ERROR, "host_to_card failed: %#x\n", ret);
@@ -1404,10 +1383,9 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,
if (ret != -EBUSY) {
mwifiex_rotate_priolists(priv, ptr, ptr_index);
atomic_dec(&priv->wmm.tx_pkts_queued);
- spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
+ spin_lock_bh(&priv->wmm.ra_list_spinlock);
ptr->total_pkt_count--;
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
- ra_list_flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
}
}
@@ -1423,7 +1401,6 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
int ptr_index = 0;
u8 ra[ETH_ALEN];
int tid_del = 0, tid = 0;
- unsigned long flags;
ptr = mwifiex_wmm_get_highest_priolist_ptr(adapter, &priv, &ptr_index);
if (!ptr)
@@ -1433,14 +1410,14 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
mwifiex_dbg(adapter, DATA, "data: tid=%d\n", tid);
- spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
+ spin_lock_bh(&priv->wmm.ra_list_spinlock);
if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
+ spin_unlock_bh(&priv->wmm.ra_list_spinlock);
return -1;
}
if (mwifiex_is_ptr_processed(priv, ptr)) {
- mwifiex_send_processed_packet(priv, ptr, ptr_index, flags);
+ mwifiex_send_processed_packet(priv, ptr, ptr_index);
/* ra_list_spinlock has been freed in
mwifiex_send_processed_packet() */
return 0;
@@ -1455,12 +1432,12 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
mwifiex_is_amsdu_allowed(priv, tid) &&
mwifiex_is_11n_aggragation_possible(priv, ptr,
adapter->tx_buf_size))
- mwifiex_11n_aggregate_pkt(priv, ptr, ptr_index, flags);
+ mwifiex_11n_aggregate_pkt(priv, ptr, ptr_index);
/* ra_list_spinlock has been freed in
* mwifiex_11n_aggregate_pkt()
*/
else
- mwifiex_send_single_packet(priv, ptr, ptr_index, flags);
+ mwifiex_send_single_packet(priv, ptr, ptr_index);
/* ra_list_spinlock has been freed in
* mwifiex_send_single_packet()
*/
@@ -1481,11 +1458,11 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
if (mwifiex_is_amsdu_allowed(priv, tid) &&
mwifiex_is_11n_aggragation_possible(priv, ptr,
adapter->tx_buf_size))
- mwifiex_11n_aggregate_pkt(priv, ptr, ptr_index, flags);
+ mwifiex_11n_aggregate_pkt(priv, ptr, ptr_index);
/* ra_list_spinlock has been freed in
mwifiex_11n_aggregate_pkt() */
else
- mwifiex_send_single_packet(priv, ptr, ptr_index, flags);
+ mwifiex_send_single_packet(priv, ptr, ptr_index);
/* ra_list_spinlock has been freed in
mwifiex_send_single_packet() */
}
diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index 4381155375e1..d8f61e540bfd 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -588,6 +588,7 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
{
int i;
+ netif_napi_del(&dev->tx_napi);
for (i = 0; i < ARRAY_SIZE(dev->q_tx); i++)
mt76_dma_tx_cleanup(dev, i, true);
diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
index 5b6a81ee457e..ec9efb79985f 100644
--- a/drivers/net/wireless/mediatek/mt76/mac80211.c
+++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
@@ -766,10 +766,21 @@ int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
*dbm = DIV_ROUND_UP(dev->txpower_cur, 2);
/* convert from per-chain power to combined
- * output on 2x2 devices
+ * output power
*/
- if (n_chains > 1)
+ switch (n_chains) {
+ case 4:
+ *dbm += 6;
+ break;
+ case 3:
+ *dbm += 4;
+ break;
+ case 2:
*dbm += 3;
+ break;
+ default:
+ break;
+ }
return 0;
}
@@ -820,3 +831,50 @@ mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
return 0;
}
EXPORT_SYMBOL_GPL(mt76_set_tim);
+
+void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id)
+{
+ struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
+ int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
+ u8 *hdr, *pn = status->iv;
+
+ __skb_push(skb, 8);
+ memmove(skb->data, skb->data + 8, hdr_len);
+ hdr = skb->data + hdr_len;
+
+ hdr[0] = pn[5];
+ hdr[1] = pn[4];
+ hdr[2] = 0;
+ hdr[3] = 0x20 | (key_id << 6);
+ hdr[4] = pn[3];
+ hdr[5] = pn[2];
+ hdr[6] = pn[1];
+ hdr[7] = pn[0];
+
+ status->flag &= ~RX_FLAG_IV_STRIPPED;
+}
+EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr);
+
+int mt76_get_rate(struct mt76_dev *dev,
+ struct ieee80211_supported_band *sband,
+ int idx, bool cck)
+{
+ int i, offset = 0, len = sband->n_bitrates;
+
+ if (cck) {
+ if (sband == &dev->sband_5g.sband)
+ return 0;
+
+ idx &= ~BIT(2); /* short preamble */
+ } else if (sband == &dev->sband_2g.sband) {
+ offset = 4;
+ }
+
+ for (i = offset; i < len; i++) {
+ if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx)
+ return i;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt76_get_rate);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index 8ecbf81a906f..989386ecb5e4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -30,6 +30,7 @@
#define MT_TX_RING_SIZE 256
#define MT_MCU_RING_SIZE 32
#define MT_RX_BUF_SIZE 2048
+#define MT_SKB_HEAD_LEN 128
struct mt76_dev;
struct mt76_wcid;
@@ -258,10 +259,11 @@ struct mt76_rx_tid {
#define MT_TX_CB_TXS_DONE BIT(1)
#define MT_TX_CB_TXS_FAILED BIT(2)
-#define MT_PACKET_ID_MASK GENMASK(7, 0)
+#define MT_PACKET_ID_MASK GENMASK(6, 0)
#define MT_PACKET_ID_NO_ACK 0
#define MT_PACKET_ID_NO_SKB 1
#define MT_PACKET_ID_FIRST 2
+#define MT_PACKET_ID_HAS_RATE BIT(7)
#define MT_TX_STATUS_SKB_TIMEOUT HZ
@@ -381,7 +383,8 @@ enum mt76u_out_ep {
__MT_EP_OUT_MAX,
};
-#define MT_SG_MAX_SIZE 8
+#define MT_TX_SG_MAX_SIZE 8
+#define MT_RX_SG_MAX_SIZE 1
#define MT_NUM_TX_ENTRIES 256
#define MT_NUM_RX_ENTRIES 128
#define MCU_RESP_URB_SIZE 1024
@@ -393,9 +396,7 @@ struct mt76_usb {
struct delayed_work stat_work;
u8 out_ep[__MT_EP_OUT_MAX];
- u16 out_max_packet;
u8 in_ep[__MT_EP_IN_MAX];
- u16 in_max_packet;
bool sg_en;
struct mt76u_mcu {
@@ -452,6 +453,7 @@ struct mt76_dev {
int tx_dma_idx[4];
struct tasklet_struct tx_tasklet;
+ struct napi_struct tx_napi;
struct delayed_work mac_work;
wait_queue_head_t tx_wait;
@@ -483,6 +485,8 @@ struct mt76_dev {
int txpower_conf;
int txpower_cur;
+ enum nl80211_dfs_regions region;
+
u32 debugfs_reg;
struct led_classdev led_cdev;
@@ -688,6 +692,14 @@ static inline void mt76_insert_hdr_pad(struct sk_buff *skb)
skb->data[len + 1] = 0;
}
+static inline bool mt76_is_skb_pktid(u8 pktid)
+{
+ if (pktid & MT_PACKET_ID_HAS_RATE)
+ return false;
+
+ return pktid >= MT_PACKET_ID_FIRST;
+}
+
void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb);
void mt76_tx(struct mt76_dev *dev, struct ieee80211_sta *sta,
struct mt76_wcid *wcid, struct sk_buff *skb);
@@ -749,6 +761,10 @@ void mt76_csa_check(struct mt76_dev *dev);
void mt76_csa_finish(struct mt76_dev *dev);
int mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set);
+void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id);
+int mt76_get_rate(struct mt76_dev *dev,
+ struct ieee80211_supported_band *sband,
+ int idx, bool cck);
/* internal */
void mt76_tx_free(struct mt76_dev *dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/core.c b/drivers/net/wireless/mediatek/mt76/mt7603/core.c
index 37e5644b45ef..e7ee58e3379c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/core.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/core.c
@@ -35,7 +35,7 @@ irqreturn_t mt7603_irq_handler(int irq, void *dev_instance)
if (intr & MT_INT_TX_DONE_ALL) {
mt7603_irq_disable(dev, MT_INT_TX_DONE_ALL);
- tasklet_schedule(&dev->mt76.tx_tasklet);
+ napi_schedule(&dev->mt76.tx_napi);
}
if (intr & MT_INT_RX_DONE(0)) {
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c
index f8b3b6ab6297..a1bc3103cbe9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c
@@ -40,6 +40,35 @@ mt7603_radio_read(struct seq_file *s, void *data)
return 0;
}
+static int
+mt7603_edcca_set(void *data, u64 val)
+{
+ struct mt7603_dev *dev = data;
+
+ mutex_lock(&dev->mt76.mutex);
+
+ dev->ed_monitor_enabled = !!val;
+ dev->ed_monitor = dev->ed_monitor_enabled &&
+ dev->mt76.region == NL80211_DFS_ETSI;
+ mt7603_init_edcca(dev);
+
+ mutex_unlock(&dev->mt76.mutex);
+
+ return 0;
+}
+
+static int
+mt7603_edcca_get(void *data, u64 *val)
+{
+ struct mt7603_dev *dev = data;
+
+ *val = dev->ed_monitor_enabled;
+ return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(fops_edcca, mt7603_edcca_get,
+ mt7603_edcca_set, "%lld\n");
+
void mt7603_init_debugfs(struct mt7603_dev *dev)
{
struct dentry *dir;
@@ -48,6 +77,7 @@ void mt7603_init_debugfs(struct mt7603_dev *dev)
if (!dir)
return;
+ debugfs_create_file("edcca", 0600, dir, dev, &fops_edcca);
debugfs_create_u32("reset_test", 0600, dir, &dev->reset_test);
debugfs_create_devm_seqfile(dev->mt76.dev, "reset", dir,
mt7603_reset_read);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c
index 27e2d9f90553..58dc511f93c5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c
@@ -139,15 +139,30 @@ static void
mt7603_tx_tasklet(unsigned long data)
{
struct mt7603_dev *dev = (struct mt7603_dev *)data;
+
+ mt76_txq_schedule_all(&dev->mt76);
+}
+
+static int mt7603_poll_tx(struct napi_struct *napi, int budget)
+{
+ struct mt7603_dev *dev;
int i;
+ dev = container_of(napi, struct mt7603_dev, mt76.tx_napi);
dev->tx_dma_check = 0;
+
for (i = MT_TXQ_MCU; i >= 0; i--)
mt76_queue_tx_cleanup(dev, i, false);
- mt76_txq_schedule_all(&dev->mt76);
+ if (napi_complete_done(napi, 0))
+ mt7603_irq_enable(dev, MT_INT_TX_DONE_ALL);
- mt7603_irq_enable(dev, MT_INT_TX_DONE_ALL);
+ for (i = MT_TXQ_MCU; i >= 0; i--)
+ mt76_queue_tx_cleanup(dev, i, false);
+
+ tasklet_schedule(&dev->mt76.tx_tasklet);
+
+ return 0;
}
int mt7603_dma_init(struct mt7603_dev *dev)
@@ -216,7 +231,15 @@ int mt7603_dma_init(struct mt7603_dev *dev)
return ret;
mt76_wr(dev, MT_DELAY_INT_CFG, 0);
- return mt76_init_queues(dev);
+ ret = mt76_init_queues(dev);
+ if (ret)
+ return ret;
+
+ netif_tx_napi_add(&dev->mt76.napi_dev, &dev->mt76.tx_napi,
+ mt7603_poll_tx, NAPI_POLL_WEIGHT);
+ napi_enable(&dev->mt76.tx_napi);
+
+ return 0;
}
void mt7603_dma_cleanup(struct mt7603_dev *dev)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.h
index f27b99b7e359..b893facfba48 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.h
@@ -69,6 +69,8 @@ enum mt7603_eeprom_field {
MT_EE_CP_FT_VERSION = 0x0f0,
+ MT_EE_TX_POWER_TSSI_OFF = 0x0f2,
+
MT_EE_XTAL_FREQ_OFFSET = 0x0f4,
MT_EE_XTAL_TRIM_2_COMP = 0x0f5,
MT_EE_XTAL_TRIM_3_COMP = 0x0f6,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/init.c b/drivers/net/wireless/mediatek/mt76/mt7603/init.c
index 78cdbb70e178..38834c7d0891 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/init.c
@@ -227,11 +227,19 @@ mt7603_mac_init(struct mt7603_dev *dev)
mt76_rmw_field(dev, MT_LPON_BTEIR, MT_LPON_BTEIR_MBSS_MODE, 2);
mt76_rmw_field(dev, MT_WF_RMACDR, MT_WF_RMACDR_MBSSID_MASK, 2);
- mt76_wr(dev, MT_AGG_ARUCR, FIELD_PREP(MT_AGG_ARxCR_LIMIT(0), 7));
+ mt76_wr(dev, MT_AGG_ARUCR,
+ FIELD_PREP(MT_AGG_ARxCR_LIMIT(0), 7) |
+ FIELD_PREP(MT_AGG_ARxCR_LIMIT(1), 2) |
+ FIELD_PREP(MT_AGG_ARxCR_LIMIT(2), 2) |
+ FIELD_PREP(MT_AGG_ARxCR_LIMIT(3), 2) |
+ FIELD_PREP(MT_AGG_ARxCR_LIMIT(4), 1) |
+ FIELD_PREP(MT_AGG_ARxCR_LIMIT(5), 1) |
+ FIELD_PREP(MT_AGG_ARxCR_LIMIT(6), 1) |
+ FIELD_PREP(MT_AGG_ARxCR_LIMIT(7), 1));
+
mt76_wr(dev, MT_AGG_ARDCR,
- FIELD_PREP(MT_AGG_ARxCR_LIMIT(0), 0) |
- FIELD_PREP(MT_AGG_ARxCR_LIMIT(1),
- max_t(int, 0, MT7603_RATE_RETRY - 2)) |
+ FIELD_PREP(MT_AGG_ARxCR_LIMIT(0), MT7603_RATE_RETRY - 1) |
+ FIELD_PREP(MT_AGG_ARxCR_LIMIT(1), MT7603_RATE_RETRY - 1) |
FIELD_PREP(MT_AGG_ARxCR_LIMIT(2), MT7603_RATE_RETRY - 1) |
FIELD_PREP(MT_AGG_ARxCR_LIMIT(3), MT7603_RATE_RETRY - 1) |
FIELD_PREP(MT_AGG_ARxCR_LIMIT(4), MT7603_RATE_RETRY - 1) |
@@ -437,7 +445,9 @@ mt7603_regd_notifier(struct wiphy *wiphy,
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct mt7603_dev *dev = hw->priv;
- dev->ed_monitor = request->dfs_region == NL80211_DFS_ETSI;
+ dev->mt76.region = request->dfs_region;
+ dev->ed_monitor = dev->ed_monitor_enabled &&
+ dev->mt76.region == NL80211_DFS_ETSI;
}
static int
@@ -463,9 +473,13 @@ mt7603_init_txpower(struct mt7603_dev *dev,
u8 *eeprom = (u8 *)dev->mt76.eeprom.data;
int target_power = eeprom[MT_EE_TX_POWER_0_START_2G + 2] & ~BIT(7);
u8 *rate_power = &eeprom[MT_EE_TX_POWER_CCK];
+ bool ext_pa = eeprom[MT_EE_NIC_CONF_0 + 1] & BIT(1);
int max_offset, cur_offset;
int i;
+ if (ext_pa && is_mt7603(dev))
+ target_power = eeprom[MT_EE_TX_POWER_TSSI_OFF] & ~BIT(7);
+
if (target_power & BIT(6))
target_power = -(target_power & GENMASK(5, 0));
@@ -488,7 +502,7 @@ mt7603_init_txpower(struct mt7603_dev *dev,
for (i = 0; i < sband->n_channels; i++) {
chan = &sband->channels[i];
- chan->max_power = target_power;
+ chan->max_power = min_t(int, chan->max_reg_power, target_power);
chan->orig_mpwr = target_power;
}
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
index 6d506e34c3ee..40db1cbc832d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
@@ -370,31 +370,6 @@ void mt7603_mac_tx_ba_reset(struct mt7603_dev *dev, int wcid, int tid,
mt76_rmw(dev, addr + (15 * 4), tid_mask, tid_val);
}
-static int
-mt7603_get_rate(struct mt7603_dev *dev, struct ieee80211_supported_band *sband,
- int idx, bool cck)
-{
- int offset = 0;
- int len = sband->n_bitrates;
- int i;
-
- if (cck) {
- if (sband == &dev->mt76.sband_5g.sband)
- return 0;
-
- idx &= ~BIT(2); /* short preamble */
- } else if (sband == &dev->mt76.sband_2g.sband) {
- offset = 4;
- }
-
- for (i = offset; i < len; i++) {
- if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx)
- return i;
- }
-
- return 0;
-}
-
static struct mt76_wcid *
mt7603_rx_get_wcid(struct mt7603_dev *dev, u8 idx, bool unicast)
{
@@ -418,30 +393,6 @@ mt7603_rx_get_wcid(struct mt7603_dev *dev, u8 idx, bool unicast)
return &sta->vif->sta.wcid;
}
-static void
-mt7603_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id)
-{
- struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
- int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
- u8 *pn = status->iv;
- u8 *hdr;
-
- __skb_push(skb, 8);
- memmove(skb->data, skb->data + 8, hdr_len);
- hdr = skb->data + hdr_len;
-
- hdr[0] = pn[5];
- hdr[1] = pn[4];
- hdr[2] = 0;
- hdr[3] = 0x20 | (key_id << 6);
- hdr[4] = pn[3];
- hdr[5] = pn[2];
- hdr[6] = pn[1];
- hdr[7] = pn[0];
-
- status->flag &= ~RX_FLAG_IV_STRIPPED;
-}
-
int
mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb)
{
@@ -532,7 +483,7 @@ mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb)
cck = true;
/* fall through */
case MT_PHY_TYPE_OFDM:
- i = mt7603_get_rate(dev, sband, i, cck);
+ i = mt76_get_rate(&dev->mt76, sband, i, cck);
break;
case MT_PHY_TYPE_HT_GF:
case MT_PHY_TYPE_HT:
@@ -580,7 +531,7 @@ mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb)
if (insert_ccmp_hdr) {
u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1);
- mt7603_insert_ccmp_hdr(skb, key_id);
+ mt76_insert_ccmp_hdr(skb, key_id);
}
hdr = (struct ieee80211_hdr *)skb->data;
@@ -640,6 +591,7 @@ void mt7603_wtbl_set_rates(struct mt7603_dev *dev, struct mt7603_sta *sta,
struct ieee80211_tx_rate *probe_rate,
struct ieee80211_tx_rate *rates)
{
+ struct ieee80211_tx_rate *ref;
int wcid = sta->wcid.idx;
u32 addr = mt7603_wtbl2_addr(wcid);
bool stbc = false;
@@ -648,7 +600,8 @@ void mt7603_wtbl_set_rates(struct mt7603_dev *dev, struct mt7603_sta *sta,
u16 val[4];
u16 probe_val;
u32 w9 = mt76_rr(dev, addr + 9 * 4);
- int i;
+ bool rateset;
+ int i, k;
if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000))
return;
@@ -656,6 +609,41 @@ void mt7603_wtbl_set_rates(struct mt7603_dev *dev, struct mt7603_sta *sta,
for (i = n_rates; i < 4; i++)
rates[i] = rates[n_rates - 1];
+ rateset = !(sta->rate_set_tsf & BIT(0));
+ memcpy(sta->rateset[rateset].rates, rates,
+ sizeof(sta->rateset[rateset].rates));
+ if (probe_rate) {
+ sta->rateset[rateset].probe_rate = *probe_rate;
+ ref = &sta->rateset[rateset].probe_rate;
+ } else {
+ sta->rateset[rateset].probe_rate.idx = -1;
+ ref = &sta->rateset[rateset].rates[0];
+ }
+
+ rates = sta->rateset[rateset].rates;
+ for (i = 0; i < ARRAY_SIZE(sta->rateset[rateset].rates); i++) {
+ /*
+ * We don't support switching between short and long GI
+ * within the rate set. For accurate tx status reporting, we
+ * need to make sure that flags match.
+ * For improved performance, avoid duplicate entries by
+ * decrementing the MCS index if necessary
+ */
+ if ((ref->flags ^ rates[i].flags) & IEEE80211_TX_RC_SHORT_GI)
+ rates[i].flags ^= IEEE80211_TX_RC_SHORT_GI;
+
+ for (k = 0; k < i; k++) {
+ if (rates[i].idx != rates[k].idx)
+ continue;
+ if ((rates[i].flags ^ rates[k].flags) &
+ IEEE80211_TX_RC_40_MHZ_WIDTH)
+ continue;
+
+ rates[i].idx--;
+ }
+
+ }
+
w9 &= MT_WTBL2_W9_SHORT_GI_20 | MT_WTBL2_W9_SHORT_GI_40 |
MT_WTBL2_W9_SHORT_GI_80;
@@ -699,19 +687,22 @@ void mt7603_wtbl_set_rates(struct mt7603_dev *dev, struct mt7603_sta *sta,
mt76_wr(dev, MT_WTBL_RIUCR1,
FIELD_PREP(MT_WTBL_RIUCR1_RATE0, probe_val) |
FIELD_PREP(MT_WTBL_RIUCR1_RATE1, val[0]) |
- FIELD_PREP(MT_WTBL_RIUCR1_RATE2_LO, val[0]));
+ FIELD_PREP(MT_WTBL_RIUCR1_RATE2_LO, val[1]));
mt76_wr(dev, MT_WTBL_RIUCR2,
- FIELD_PREP(MT_WTBL_RIUCR2_RATE2_HI, val[0] >> 8) |
+ FIELD_PREP(MT_WTBL_RIUCR2_RATE2_HI, val[1] >> 8) |
FIELD_PREP(MT_WTBL_RIUCR2_RATE3, val[1]) |
- FIELD_PREP(MT_WTBL_RIUCR2_RATE4, val[1]) |
+ FIELD_PREP(MT_WTBL_RIUCR2_RATE4, val[2]) |
FIELD_PREP(MT_WTBL_RIUCR2_RATE5_LO, val[2]));
mt76_wr(dev, MT_WTBL_RIUCR3,
FIELD_PREP(MT_WTBL_RIUCR3_RATE5_HI, val[2] >> 4) |
- FIELD_PREP(MT_WTBL_RIUCR3_RATE6, val[2]) |
+ FIELD_PREP(MT_WTBL_RIUCR3_RATE6, val[3]) |
FIELD_PREP(MT_WTBL_RIUCR3_RATE7, val[3]));
+ mt76_set(dev, MT_LPON_T0CR, MT_LPON_T0CR_MODE); /* TSF read */
+ sta->rate_set_tsf = (mt76_rr(dev, MT_LPON_UTTR0) & ~BIT(0)) | rateset;
+
mt76_wr(dev, MT_WTBL_UPDATE,
FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, wcid) |
MT_WTBL_UPDATE_RATE_UPDATE |
@@ -938,9 +929,9 @@ int mt7603_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) {
spin_lock_bh(&dev->mt76.lock);
- msta->rate_probe = true;
mt7603_wtbl_set_rates(dev, msta, &info->control.rates[0],
msta->rates);
+ msta->rate_probe = true;
spin_unlock_bh(&dev->mt76.lock);
}
@@ -955,10 +946,12 @@ mt7603_fill_txs(struct mt7603_dev *dev, struct mt7603_sta *sta,
struct ieee80211_tx_info *info, __le32 *txs_data)
{
struct ieee80211_supported_band *sband;
- int final_idx = 0;
+ struct mt7603_rate_set *rs;
+ int first_idx = 0, last_idx;
+ u32 rate_set_tsf;
u32 final_rate;
u32 final_rate_flags;
- bool final_mpdu;
+ bool rs_idx;
bool ack_timeout;
bool fixed_rate;
bool probe;
@@ -966,7 +959,6 @@ mt7603_fill_txs(struct mt7603_dev *dev, struct mt7603_sta *sta,
bool cck = false;
int count;
u32 txs;
- u8 pid;
int idx;
int i;
@@ -974,10 +966,9 @@ mt7603_fill_txs(struct mt7603_dev *dev, struct mt7603_sta *sta,
probe = !!(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
txs = le32_to_cpu(txs_data[4]);
- final_mpdu = txs & MT_TXS4_ACKED_MPDU;
ampdu = !fixed_rate && (txs & MT_TXS4_AMPDU);
- pid = FIELD_GET(MT_TXS4_PID, txs);
count = FIELD_GET(MT_TXS4_TX_COUNT, txs);
+ last_idx = FIELD_GET(MT_TXS4_LAST_TX_RATE, txs);
txs = le32_to_cpu(txs_data[0]);
final_rate = FIELD_GET(MT_TXS0_TX_RATE, txs);
@@ -999,38 +990,57 @@ mt7603_fill_txs(struct mt7603_dev *dev, struct mt7603_sta *sta,
if (ampdu || (info->flags & IEEE80211_TX_CTL_AMPDU))
info->flags |= IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_CTL_AMPDU;
+ first_idx = max_t(int, 0, last_idx - (count + 1) / MT7603_RATE_RETRY);
+
if (fixed_rate && !probe) {
info->status.rates[0].count = count;
+ i = 0;
goto out;
}
- for (i = 0, idx = 0; i < ARRAY_SIZE(info->status.rates); i++) {
- int cur_count = min_t(int, count, 2 * MT7603_RATE_RETRY);
+ rate_set_tsf = READ_ONCE(sta->rate_set_tsf);
+ rs_idx = !((u32)(FIELD_GET(MT_TXS1_F0_TIMESTAMP, le32_to_cpu(txs_data[1])) -
+ rate_set_tsf) < 1000000);
+ rs_idx ^= rate_set_tsf & BIT(0);
+ rs = &sta->rateset[rs_idx];
- if (!i && probe) {
- cur_count = 1;
- } else {
- info->status.rates[i] = sta->rates[idx];
- idx++;
- }
+ if (!first_idx && rs->probe_rate.idx >= 0) {
+ info->status.rates[0] = rs->probe_rate;
- if (i && info->status.rates[i].idx < 0) {
- info->status.rates[i - 1].count += count;
- break;
+ spin_lock_bh(&dev->mt76.lock);
+ if (sta->rate_probe) {
+ mt7603_wtbl_set_rates(dev, sta, NULL,
+ sta->rates);
+ sta->rate_probe = false;
}
+ spin_unlock_bh(&dev->mt76.lock);
+ } else
+ info->status.rates[0] = rs->rates[first_idx / 2];
+ info->status.rates[0].count = 0;
- if (!count) {
- info->status.rates[i].idx = -1;
- break;
- }
+ for (i = 0, idx = first_idx; count && idx <= last_idx; idx++) {
+ struct ieee80211_tx_rate *cur_rate;
+ int cur_count;
- info->status.rates[i].count = cur_count;
- final_idx = i;
+ cur_rate = &rs->rates[idx / 2];
+ cur_count = min_t(int, MT7603_RATE_RETRY, count);
count -= cur_count;
+
+ if (idx && (cur_rate->idx != info->status.rates[i].idx ||
+ cur_rate->flags != info->status.rates[i].flags)) {
+ i++;
+ if (i == ARRAY_SIZE(info->status.rates))
+ break;
+
+ info->status.rates[i] = *cur_rate;
+ info->status.rates[i].count = 0;
+ }
+
+ info->status.rates[i].count += cur_count;
}
out:
- final_rate_flags = info->status.rates[final_idx].flags;
+ final_rate_flags = info->status.rates[i].flags;
switch (FIELD_GET(MT_TX_RATE_MODE, final_rate)) {
case MT_PHY_TYPE_CCK:
@@ -1042,7 +1052,8 @@ out:
else
sband = &dev->mt76.sband_2g.sband;
final_rate &= GENMASK(5, 0);
- final_rate = mt7603_get_rate(dev, sband, final_rate, cck);
+ final_rate = mt76_get_rate(&dev->mt76, sband, final_rate,
+ cck);
final_rate_flags = 0;
break;
case MT_PHY_TYPE_HT_GF:
@@ -1056,8 +1067,8 @@ out:
return false;
}
- info->status.rates[final_idx].idx = final_rate;
- info->status.rates[final_idx].flags = final_rate_flags;
+ info->status.rates[i].idx = final_rate;
+ info->status.rates[i].flags = final_rate_flags;
return true;
}
@@ -1078,16 +1089,6 @@ mt7603_mac_add_txs_skb(struct mt7603_dev *dev, struct mt7603_sta *sta, int pid,
if (skb) {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) {
- spin_lock_bh(&dev->mt76.lock);
- if (sta->rate_probe) {
- mt7603_wtbl_set_rates(dev, sta, NULL,
- sta->rates);
- sta->rate_probe = false;
- }
- spin_unlock_bh(&dev->mt76.lock);
- }
-
if (!mt7603_fill_txs(dev, sta, info, txs_data)) {
ieee80211_tx_info_clear_status(info);
info->status.rates[0].idx = -1;
@@ -1282,6 +1283,7 @@ static void mt7603_mac_watchdog_reset(struct mt7603_dev *dev)
tasklet_disable(&dev->mt76.pre_tbtt_tasklet);
napi_disable(&dev->mt76.napi[0]);
napi_disable(&dev->mt76.napi[1]);
+ napi_disable(&dev->mt76.tx_napi);
mutex_lock(&dev->mt76.mutex);
@@ -1326,7 +1328,8 @@ skip_dma_reset:
mutex_unlock(&dev->mt76.mutex);
tasklet_enable(&dev->mt76.tx_tasklet);
- tasklet_schedule(&dev->mt76.tx_tasklet);
+ napi_enable(&dev->mt76.tx_napi);
+ napi_schedule(&dev->mt76.tx_napi);
tasklet_enable(&dev->mt76.pre_tbtt_tasklet);
mt7603_beacon_set_timer(dev, -1, beacon_int);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c
index 0a0334dc40d5..e5d4cb6381a8 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c
@@ -103,8 +103,7 @@ mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
mutex_unlock(&dev->mt76.mutex);
}
-static void
-mt7603_init_edcca(struct mt7603_dev *dev)
+void mt7603_init_edcca(struct mt7603_dev *dev)
{
/* Set lower signal level to -65dBm */
mt76_rmw_field(dev, MT_RXTD(8), MT_RXTD_8_LOWER_SIGNAL, 0x23);
@@ -207,8 +206,11 @@ mt7603_config(struct ieee80211_hw *hw, u32 changed)
int ret = 0;
if (changed & (IEEE80211_CONF_CHANGE_CHANNEL |
- IEEE80211_CONF_CHANGE_POWER))
+ IEEE80211_CONF_CHANGE_POWER)) {
+ ieee80211_stop_queues(hw);
ret = mt7603_set_channel(dev, &hw->conf.chandef);
+ ieee80211_wake_queues(hw);
+ }
if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
mutex_lock(&dev->mt76.mutex);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7603/mcu.c
index 6357b5658a32..343ddc5543c2 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/mcu.c
@@ -346,7 +346,7 @@ int mt7603_mcu_set_eeprom(struct mt7603_dev *dev)
};
struct req_data {
- u16 addr;
+ __le16 addr;
u8 val;
u8 pad;
} __packed;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h
index fa64bbaab0d2..2c6f7b4cf0e9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h
@@ -51,6 +51,11 @@ enum mt7603_bw {
MT_BW_80,
};
+struct mt7603_rate_set {
+ struct ieee80211_tx_rate probe_rate;
+ struct ieee80211_tx_rate rates[4];
+};
+
struct mt7603_sta {
struct mt76_wcid wcid; /* must be first */
@@ -58,7 +63,11 @@ struct mt7603_sta {
struct sk_buff_head psq;
- struct ieee80211_tx_rate rates[8];
+ struct ieee80211_tx_rate rates[4];
+
+ struct mt7603_rate_set rateset[2];
+ u32 rate_set_tsf;
+
u8 rate_count;
u8 n_rates;
@@ -117,8 +126,9 @@ struct mt7603_dev {
u8 mac_work_count;
u8 mcu_running;
- u8 ed_monitor;
+ u8 ed_monitor_enabled;
+ u8 ed_monitor;
s8 ed_trigger;
u8 ed_strict_mode;
u8 ed_strong_signal;
@@ -241,4 +251,5 @@ void mt7603_update_channel(struct mt76_dev *mdev);
void mt7603_edcca_set_strict(struct mt7603_dev *dev, bool val);
void mt7603_cca_stats_reset(struct mt7603_dev *dev);
+void mt7603_init_edcca(struct mt7603_dev *dev);
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/regs.h b/drivers/net/wireless/mediatek/mt76/mt7603/regs.h
index 9d257d5c309d..eb9eefe8e125 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/regs.h
@@ -480,6 +480,12 @@ enum {
#define MT_LPON_BASE 0x24000
#define MT_LPON(n) (MT_LPON_BASE + (n))
+#define MT_LPON_T0CR MT_LPON(0x010)
+#define MT_LPON_T0CR_MODE GENMASK(1, 0)
+
+#define MT_LPON_UTTR0 MT_LPON(0x018)
+#define MT_LPON_UTTR1 MT_LPON(0x01c)
+
#define MT_LPON_BTEIR MT_LPON(0x020)
#define MT_LPON_BTEIR_MBSS_MODE GENMASK(31, 29)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
index 3ec6582afd8f..6a70273d4a69 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
@@ -93,18 +93,33 @@ void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
static void mt7615_tx_tasklet(unsigned long data)
{
struct mt7615_dev *dev = (struct mt7615_dev *)data;
+
+ mt76_txq_schedule_all(&dev->mt76);
+}
+
+static int mt7615_poll_tx(struct napi_struct *napi, int budget)
+{
static const u8 queue_map[] = {
MT_TXQ_MCU,
MT_TXQ_BE
};
+ struct mt7615_dev *dev;
int i;
+ dev = container_of(napi, struct mt7615_dev, mt76.tx_napi);
+
for (i = 0; i < ARRAY_SIZE(queue_map); i++)
mt76_queue_tx_cleanup(dev, queue_map[i], false);
- mt76_txq_schedule_all(&dev->mt76);
+ if (napi_complete_done(napi, 0))
+ mt7615_irq_enable(dev, MT_INT_TX_DONE_ALL);
- mt7615_irq_enable(dev, MT_INT_TX_DONE_ALL);
+ for (i = 0; i < ARRAY_SIZE(queue_map); i++)
+ mt76_queue_tx_cleanup(dev, queue_map[i], false);
+
+ tasklet_schedule(&dev->mt76.tx_tasklet);
+
+ return 0;
}
int mt7615_dma_init(struct mt7615_dev *dev)
@@ -178,6 +193,10 @@ int mt7615_dma_init(struct mt7615_dev *dev)
if (ret < 0)
return ret;
+ netif_tx_napi_add(&dev->mt76.napi_dev, &dev->mt76.tx_napi,
+ mt7615_poll_tx, NAPI_POLL_WEIGHT);
+ napi_enable(&dev->mt76.tx_napi);
+
mt76_poll(dev, MT_WPDMA_GLO_CFG,
MT_WPDMA_GLO_CFG_TX_DMA_BUSY |
MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 1000);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c
index dd5ab46a4f66..dc94f52e6e8b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c
@@ -42,13 +42,13 @@ static int mt7615_efuse_read(struct mt7615_dev *dev, u32 base,
static int mt7615_efuse_init(struct mt7615_dev *dev)
{
- u32 base = mt7615_reg_map(dev, MT_EFUSE_BASE);
- int len = MT7615_EEPROM_SIZE;
- int ret, i;
+ u32 val, base = mt7615_reg_map(dev, MT_EFUSE_BASE);
+ int i, len = MT7615_EEPROM_SIZE;
void *buf;
- if (mt76_rr(dev, base + MT_EFUSE_BASE_CTRL) & MT_EFUSE_BASE_CTRL_EMPTY)
- return -EINVAL;
+ val = mt76_rr(dev, base + MT_EFUSE_BASE_CTRL);
+ if (val & MT_EFUSE_BASE_CTRL_EMPTY)
+ return 0;
dev->mt76.otp.data = devm_kzalloc(dev->mt76.dev, len, GFP_KERNEL);
dev->mt76.otp.size = len;
@@ -57,6 +57,8 @@ static int mt7615_efuse_init(struct mt7615_dev *dev)
buf = dev->mt76.otp.data;
for (i = 0; i + 16 <= len; i += 16) {
+ int ret;
+
ret = mt7615_efuse_read(dev, base, i, buf + i);
if (ret)
return ret;
@@ -76,6 +78,82 @@ static int mt7615_eeprom_load(struct mt7615_dev *dev)
return mt7615_efuse_init(dev);
}
+static int mt7615_check_eeprom(struct mt76_dev *dev)
+{
+ u16 val = get_unaligned_le16(dev->eeprom.data);
+
+ switch (val) {
+ case 0x7615:
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static void mt7615_eeprom_parse_hw_cap(struct mt7615_dev *dev)
+{
+ u8 val, *eeprom = dev->mt76.eeprom.data;
+
+ val = FIELD_GET(MT_EE_NIC_WIFI_CONF_BAND_SEL,
+ eeprom[MT_EE_WIFI_CONF]);
+ switch (val) {
+ case MT_EE_5GHZ:
+ dev->mt76.cap.has_5ghz = true;
+ break;
+ case MT_EE_2GHZ:
+ dev->mt76.cap.has_2ghz = true;
+ break;
+ default:
+ dev->mt76.cap.has_2ghz = true;
+ dev->mt76.cap.has_5ghz = true;
+ break;
+ }
+}
+
+int mt7615_eeprom_get_power_index(struct mt7615_dev *dev,
+ struct ieee80211_channel *chan,
+ u8 chain_idx)
+{
+ int index;
+
+ if (chain_idx > 3)
+ return -EINVAL;
+
+ /* TSSI disabled */
+ if (mt7615_ext_pa_enabled(dev, chan->band)) {
+ if (chan->band == NL80211_BAND_2GHZ)
+ return MT_EE_EXT_PA_2G_TARGET_POWER;
+ else
+ return MT_EE_EXT_PA_5G_TARGET_POWER;
+ }
+
+ /* TSSI enabled */
+ if (chan->band == NL80211_BAND_2GHZ) {
+ index = MT_EE_TX0_2G_TARGET_POWER + chain_idx * 6;
+ } else {
+ int group = mt7615_get_channel_group(chan->hw_value);
+
+ switch (chain_idx) {
+ case 1:
+ index = MT_EE_TX1_5G_G0_TARGET_POWER;
+ break;
+ case 2:
+ index = MT_EE_TX2_5G_G0_TARGET_POWER;
+ break;
+ case 3:
+ index = MT_EE_TX3_5G_G0_TARGET_POWER;
+ break;
+ case 0:
+ default:
+ index = MT_EE_TX0_5G_G0_TARGET_POWER;
+ break;
+ }
+ index += 5 * group;
+ }
+
+ return index;
+}
+
int mt7615_eeprom_init(struct mt7615_dev *dev)
{
int ret;
@@ -84,11 +162,12 @@ int mt7615_eeprom_init(struct mt7615_dev *dev)
if (ret < 0)
return ret;
- memcpy(dev->mt76.eeprom.data, dev->mt76.otp.data, MT7615_EEPROM_SIZE);
-
- dev->mt76.cap.has_2ghz = true;
- dev->mt76.cap.has_5ghz = true;
+ ret = mt7615_check_eeprom(&dev->mt76);
+ if (ret && dev->mt76.otp.data)
+ memcpy(dev->mt76.eeprom.data, dev->mt76.otp.data,
+ MT7615_EEPROM_SIZE);
+ mt7615_eeprom_parse_hw_cap(dev);
memcpy(dev->mt76.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
ETH_ALEN);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h
index a4cf16688171..f4a4280768d2 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h
@@ -11,8 +11,69 @@ enum mt7615_eeprom_field {
MT_EE_VERSION = 0x002,
MT_EE_MAC_ADDR = 0x004,
MT_EE_NIC_CONF_0 = 0x034,
+ MT_EE_NIC_CONF_1 = 0x036,
+ MT_EE_WIFI_CONF = 0x03e,
+ MT_EE_TX0_2G_TARGET_POWER = 0x058,
+ MT_EE_TX0_5G_G0_TARGET_POWER = 0x070,
+ MT_EE_TX1_5G_G0_TARGET_POWER = 0x098,
+ MT_EE_EXT_PA_2G_TARGET_POWER = 0x0f2,
+ MT_EE_EXT_PA_5G_TARGET_POWER = 0x0f3,
+ MT_EE_TX2_5G_G0_TARGET_POWER = 0x142,
+ MT_EE_TX3_5G_G0_TARGET_POWER = 0x16a,
__MT_EE_MAX = 0x3bf
};
+#define MT_EE_NIC_CONF_TSSI_2G BIT(5)
+#define MT_EE_NIC_CONF_TSSI_5G BIT(6)
+
+#define MT_EE_NIC_WIFI_CONF_BAND_SEL GENMASK(5, 4)
+enum mt7615_eeprom_band {
+ MT_EE_DUAL_BAND,
+ MT_EE_5GHZ,
+ MT_EE_2GHZ,
+ MT_EE_DBDC,
+};
+
+enum mt7615_channel_group {
+ MT_CH_5G_JAPAN,
+ MT_CH_5G_UNII_1,
+ MT_CH_5G_UNII_2A,
+ MT_CH_5G_UNII_2B,
+ MT_CH_5G_UNII_2E_1,
+ MT_CH_5G_UNII_2E_2,
+ MT_CH_5G_UNII_2E_3,
+ MT_CH_5G_UNII_3,
+ __MT_CH_MAX
+};
+
+static inline enum mt7615_channel_group
+mt7615_get_channel_group(int channel)
+{
+ if (channel >= 184 && channel <= 196)
+ return MT_CH_5G_JAPAN;
+ if (channel <= 48)
+ return MT_CH_5G_UNII_1;
+ if (channel <= 64)
+ return MT_CH_5G_UNII_2A;
+ if (channel <= 114)
+ return MT_CH_5G_UNII_2E_1;
+ if (channel <= 144)
+ return MT_CH_5G_UNII_2E_2;
+ if (channel <= 161)
+ return MT_CH_5G_UNII_2E_3;
+ return MT_CH_5G_UNII_3;
+}
+
+static inline bool
+mt7615_ext_pa_enabled(struct mt7615_dev *dev, enum nl80211_band band)
+{
+ u8 *eep = dev->mt76.eeprom.data;
+
+ if (band == NL80211_BAND_5GHZ)
+ return !(eep[MT_EE_NIC_CONF_1 + 1] & MT_EE_NIC_CONF_TSSI_5G);
+ else
+ return !(eep[MT_EE_NIC_CONF_1 + 1] & MT_EE_NIC_CONF_TSSI_2G);
+}
+
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c
index 3ab3ff553ef2..859de2454ec6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c
@@ -9,6 +9,7 @@
#include <linux/etherdevice.h>
#include "mt7615.h"
#include "mac.h"
+#include "eeprom.h"
static void mt7615_phy_init(struct mt7615_dev *dev)
{
@@ -62,16 +63,11 @@ static void mt7615_mac_init(struct mt7615_dev *dev)
MT_AGG_ARCR_RATE_DOWN_RATIO_EN |
FIELD_PREP(MT_AGG_ARCR_RATE_DOWN_RATIO, 1) |
FIELD_PREP(MT_AGG_ARCR_RATE_UP_EXTRA_TH, 4)));
-
- dev->mt76.global_wcid.idx = MT7615_WTBL_RESERVED;
- dev->mt76.global_wcid.hw_key_idx = -1;
- rcu_assign_pointer(dev->mt76.wcid[MT7615_WTBL_RESERVED],
- &dev->mt76.global_wcid);
}
static int mt7615_init_hardware(struct mt7615_dev *dev)
{
- int ret;
+ int ret, idx;
mt76_wr(dev, MT_INT_SOURCE_CSR, ~0);
@@ -98,6 +94,15 @@ static int mt7615_init_hardware(struct mt7615_dev *dev)
mt7615_mcu_ctrl_pm_state(dev, 0);
mt7615_mcu_del_wtbl_all(dev);
+ /* Beacon and mgmt frames should occupy wcid 0 */
+ idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7615_WTBL_STA - 1);
+ if (idx)
+ return -ENOSPC;
+
+ dev->mt76.global_wcid.idx = idx;
+ dev->mt76.global_wcid.hw_key_idx = -1;
+ rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid);
+
return 0;
}
@@ -133,6 +138,9 @@ static const struct ieee80211_iface_limit if_limits[] = {
{
.max = MT7615_MAX_INTERFACES,
.types = BIT(NL80211_IFTYPE_AP) |
+#ifdef CONFIG_MAC80211_MESH
+ BIT(NL80211_IFTYPE_MESH_POINT) |
+#endif
BIT(NL80211_IFTYPE_STATION)
}
};
@@ -158,6 +166,48 @@ static int mt7615_init_debugfs(struct mt7615_dev *dev)
return 0;
}
+static void
+mt7615_init_txpower(struct mt7615_dev *dev,
+ struct ieee80211_supported_band *sband)
+{
+ int i, n_chains = hweight8(dev->mt76.antenna_mask), target_chains;
+ u8 *eep = (u8 *)dev->mt76.eeprom.data;
+ enum nl80211_band band = sband->band;
+
+ target_chains = mt7615_ext_pa_enabled(dev, band) ? 1 : n_chains;
+ for (i = 0; i < sband->n_channels; i++) {
+ struct ieee80211_channel *chan = &sband->channels[i];
+ u8 target_power = 0;
+ int j;
+
+ for (j = 0; j < target_chains; j++) {
+ int index;
+
+ index = mt7615_eeprom_get_power_index(dev, chan, j);
+ target_power = max(target_power, eep[index]);
+ }
+
+ target_power = DIV_ROUND_UP(target_power, 2);
+ switch (n_chains) {
+ case 4:
+ target_power += 6;
+ break;
+ case 3:
+ target_power += 4;
+ break;
+ case 2:
+ target_power += 3;
+ break;
+ default:
+ break;
+ }
+
+ chan->max_power = min_t(int, chan->max_reg_power,
+ target_power);
+ chan->orig_mpwr = target_power;
+ }
+}
+
int mt7615_register_device(struct mt7615_dev *dev)
{
struct ieee80211_hw *hw = mt76_hw(dev);
@@ -195,6 +245,9 @@ int mt7615_register_device(struct mt7615_dev *dev)
dev->mt76.antenna_mask = 0xf;
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+#ifdef CONFIG_MAC80211_MESH
+ BIT(NL80211_IFTYPE_MESH_POINT) |
+#endif
BIT(NL80211_IFTYPE_AP);
ret = mt76_register_device(&dev->mt76, true, mt7615_rates,
@@ -202,6 +255,9 @@ int mt7615_register_device(struct mt7615_dev *dev)
if (ret)
return ret;
+ mt7615_init_txpower(dev, &dev->mt76.sband_2g.sband);
+ mt7615_init_txpower(dev, &dev->mt76.sband_5g.sband);
+
hw->max_tx_fragments = MT_TXP_MAX_BUF_NUM;
return mt7615_init_debugfs(dev);
@@ -212,6 +268,10 @@ void mt7615_unregister_device(struct mt7615_dev *dev)
struct mt76_txwi_cache *txwi;
int id;
+ mt76_unregister_device(&dev->mt76);
+ mt7615_mcu_exit(dev);
+ mt7615_dma_cleanup(dev);
+
spin_lock_bh(&dev->token_lock);
idr_for_each_entry(&dev->token, txwi, id) {
mt7615_txp_skb_unmap(&dev->mt76, txwi);
@@ -221,9 +281,6 @@ void mt7615_unregister_device(struct mt7615_dev *dev)
}
spin_unlock_bh(&dev->token_lock);
idr_destroy(&dev->token);
- mt76_unregister_device(&dev->mt76);
- mt7615_mcu_exit(dev);
- mt7615_dma_cleanup(dev);
- ieee80211_free_hw(mt76_hw(dev));
+ mt76_free_device(&dev->mt76);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
index b8f48d10f27a..1eb0e9c9970c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
@@ -13,6 +13,11 @@
#include "../dma.h"
#include "mac.h"
+static inline s8 to_rssi(u32 field, u32 rxv)
+{
+ return (FIELD_GET(field, rxv) - 220) / 2;
+}
+
static struct mt76_wcid *mt7615_rx_get_wcid(struct mt7615_dev *dev,
u8 idx, bool unicast)
{
@@ -36,54 +41,6 @@ static struct mt76_wcid *mt7615_rx_get_wcid(struct mt7615_dev *dev,
return &sta->vif->sta.wcid;
}
-static int mt7615_get_rate(struct mt7615_dev *dev,
- struct ieee80211_supported_band *sband,
- int idx, bool cck)
-{
- int offset = 0;
- int len = sband->n_bitrates;
- int i;
-
- if (cck) {
- if (sband == &dev->mt76.sband_5g.sband)
- return 0;
-
- idx &= ~BIT(2); /* short preamble */
- } else if (sband == &dev->mt76.sband_2g.sband) {
- offset = 4;
- }
-
- for (i = offset; i < len; i++) {
- if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx)
- return i;
- }
-
- return 0;
-}
-
-static void mt7615_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id)
-{
- struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
- int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
- u8 *pn = status->iv;
- u8 *hdr;
-
- __skb_push(skb, 8);
- memmove(skb->data, skb->data + 8, hdr_len);
- hdr = skb->data + hdr_len;
-
- hdr[0] = pn[5];
- hdr[1] = pn[4];
- hdr[2] = 0;
- hdr[3] = 0x20 | (key_id << 6);
- hdr[4] = pn[3];
- hdr[5] = pn[2];
- hdr[6] = pn[1];
- hdr[7] = pn[0];
-
- status->flag &= ~RX_FLAG_IV_STRIPPED;
-}
-
int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
{
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
@@ -96,6 +53,9 @@ int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
bool unicast, remove_pad, insert_ccmp_hdr = false;
int i, idx;
+ if (!test_bit(MT76_STATE_RUNNING, &dev->mt76.state))
+ return -EINVAL;
+
memset(status, 0, sizeof(*status));
unicast = (rxd1 & MT_RXD1_NORMAL_ADDR_TYPE) == MT_RXD1_NORMAL_U2M;
@@ -165,6 +125,7 @@ int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
if (rxd0 & MT_RXD0_NORMAL_GROUP_3) {
u32 rxdg0 = le32_to_cpu(rxd[0]);
u32 rxdg1 = le32_to_cpu(rxd[1]);
+ u32 rxdg3 = le32_to_cpu(rxd[3]);
u8 stbc = FIELD_GET(MT_RXV1_HT_STBC, rxdg0);
bool cck = false;
@@ -174,7 +135,7 @@ int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
cck = true;
/* fall through */
case MT_PHY_TYPE_OFDM:
- i = mt7615_get_rate(dev, sband, i, cck);
+ i = mt76_get_rate(&dev->mt76, sband, i, cck);
break;
case MT_PHY_TYPE_HT_GF:
case MT_PHY_TYPE_HT:
@@ -214,7 +175,21 @@ int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc;
- /* TODO: RSSI */
+ status->chains = dev->mt76.antenna_mask;
+ status->chain_signal[0] = to_rssi(MT_RXV4_RCPI0, rxdg3);
+ status->chain_signal[1] = to_rssi(MT_RXV4_RCPI1, rxdg3);
+ status->chain_signal[2] = to_rssi(MT_RXV4_RCPI2, rxdg3);
+ status->chain_signal[3] = to_rssi(MT_RXV4_RCPI3, rxdg3);
+ status->signal = status->chain_signal[0];
+
+ for (i = 1; i < hweight8(dev->mt76.antenna_mask); i++) {
+ if (!(status->chains & BIT(i)))
+ continue;
+
+ status->signal = max(status->signal,
+ status->chain_signal[i]);
+ }
+
rxd += 6;
if ((u8 *)rxd - skb->data >= skb->len)
return -EINVAL;
@@ -225,7 +200,7 @@ int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
if (insert_ccmp_hdr) {
u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1);
- mt7615_insert_ccmp_hdr(skb, key_id);
+ mt76_insert_ccmp_hdr(skb, key_id);
}
hdr = (struct ieee80211_hdr *)skb->data;
@@ -549,23 +524,20 @@ static bool mt7615_fill_txs(struct mt7615_dev *dev, struct mt7615_sta *sta,
{
struct ieee80211_supported_band *sband;
int i, idx, count, final_idx = 0;
- bool fixed_rate, final_mpdu, ack_timeout;
+ bool fixed_rate, ack_timeout;
bool probe, ampdu, cck = false;
u32 final_rate, final_rate_flags, final_nss, txs;
- u8 pid;
fixed_rate = info->status.rates[0].count;
probe = !!(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
txs = le32_to_cpu(txs_data[1]);
- final_mpdu = txs & MT_TXS1_ACKED_MPDU;
ampdu = !fixed_rate && (txs & MT_TXS1_AMPDU);
txs = le32_to_cpu(txs_data[3]);
count = FIELD_GET(MT_TXS3_TX_COUNT, txs);
txs = le32_to_cpu(txs_data[0]);
- pid = FIELD_GET(MT_TXS0_PID, txs);
final_rate = FIELD_GET(MT_TXS0_TX_RATE, txs);
ack_timeout = txs & MT_TXS0_ACK_TIMEOUT;
@@ -628,7 +600,8 @@ out:
else
sband = &dev->mt76.sband_2g.sband;
final_rate &= MT_TX_RATE_IDX;
- final_rate = mt7615_get_rate(dev, sband, final_rate, cck);
+ final_rate = mt76_get_rate(&dev->mt76, sband, final_rate,
+ cck);
final_rate_flags = 0;
break;
case MT_PHY_TYPE_HT_GF:
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h
index 18ad4b8a3807..b00ce8db58e9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h
@@ -98,6 +98,11 @@ enum rx_pkt_type {
#define MT_RXV2_GROUP_ID GENMASK(26, 21)
#define MT_RXV2_LENGTH GENMASK(20, 0)
+#define MT_RXV4_RCPI3 GENMASK(31, 24)
+#define MT_RXV4_RCPI2 GENMASK(23, 16)
+#define MT_RXV4_RCPI1 GENMASK(15, 8)
+#define MT_RXV4_RCPI0 GENMASK(7, 0)
+
enum tx_header_format {
MT_HDR_FORMAT_802_3,
MT_HDR_FORMAT_CMD,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
index 80e6b211f60b..b4d6af812c54 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
@@ -37,6 +37,7 @@ static int get_omac_idx(enum nl80211_iftype type, u32 mask)
switch (type) {
case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_MESH_POINT:
/* ap use hw bssid 0 and ext bssid */
if (~mask & BIT(HW_BSSID_0))
return HW_BSSID_0;
@@ -77,11 +78,12 @@ static int mt7615_add_interface(struct ieee80211_hw *hw,
goto out;
}
- mvif->omac_idx = get_omac_idx(vif->type, dev->omac_mask);
- if (mvif->omac_idx < 0) {
+ idx = get_omac_idx(vif->type, dev->omac_mask);
+ if (idx < 0) {
ret = -ENOSPC;
goto out;
}
+ mvif->omac_idx = idx;
/* TODO: DBDC support. Use band 0 and wmm 0 for now */
mvif->band_idx = 0;
@@ -93,7 +95,7 @@ static int mt7615_add_interface(struct ieee80211_hw *hw,
dev->vif_mask |= BIT(mvif->idx);
dev->omac_mask |= BIT(mvif->omac_idx);
- idx = MT7615_WTBL_RESERVED - 1 - mvif->idx;
+ idx = MT7615_WTBL_RESERVED - mvif->idx;
mvif->sta.wcid.idx = idx;
mvif->sta.wcid.hw_key_idx = -1;
@@ -128,8 +130,7 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw,
mutex_unlock(&dev->mt76.mutex);
}
-static int mt7615_set_channel(struct mt7615_dev *dev,
- struct cfg80211_chan_def *def)
+static int mt7615_set_channel(struct mt7615_dev *dev)
{
int ret;
@@ -190,28 +191,28 @@ static int mt7615_config(struct ieee80211_hw *hw, u32 changed)
struct mt7615_dev *dev = hw->priv;
int ret = 0;
- if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
- mutex_lock(&dev->mt76.mutex);
+ mutex_lock(&dev->mt76.mutex);
+ if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
ieee80211_stop_queues(hw);
- ret = mt7615_set_channel(dev, &hw->conf.chandef);
+ ret = mt7615_set_channel(dev);
ieee80211_wake_queues(hw);
-
- mutex_unlock(&dev->mt76.mutex);
}
- if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
- mutex_lock(&dev->mt76.mutex);
+ if (changed & IEEE80211_CONF_CHANGE_POWER)
+ ret = mt7615_mcu_set_tx_power(dev);
+ if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
if (!(hw->conf.flags & IEEE80211_CONF_MONITOR))
dev->mt76.rxfilter |= MT_WF_RFCR_DROP_OTHER_UC;
else
dev->mt76.rxfilter &= ~MT_WF_RFCR_DROP_OTHER_UC;
mt76_wr(dev, MT_WF_RFCR, dev->mt76.rxfilter);
-
- mutex_unlock(&dev->mt76.mutex);
}
+
+ mutex_unlock(&dev->mt76.mutex);
+
return ret;
}
@@ -281,26 +282,18 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw,
mutex_lock(&dev->mt76.mutex);
- /* TODO: sta mode connect/disconnect
- * BSS_CHANGED_ASSOC | BSS_CHANGED_BSSID
- */
+ if (changed & BSS_CHANGED_ASSOC)
+ mt7615_mcu_set_bss_info(dev, vif, info->assoc);
/* TODO: update beacon content
* BSS_CHANGED_BEACON
*/
if (changed & BSS_CHANGED_BEACON_ENABLED) {
- if (info->enable_beacon) {
- mt7615_mcu_set_bss_info(dev, vif, 1);
- mt7615_mcu_add_wtbl_bmc(dev, vif);
- mt7615_mcu_set_sta_rec_bmc(dev, vif, 1);
- mt7615_mcu_set_bcn(dev, vif, 1);
- } else {
- mt7615_mcu_set_sta_rec_bmc(dev, vif, 0);
- mt7615_mcu_del_wtbl_bmc(dev, vif);
- mt7615_mcu_set_bss_info(dev, vif, 0);
- mt7615_mcu_set_bcn(dev, vif, 0);
- }
+ mt7615_mcu_set_bss_info(dev, vif, info->enable_beacon);
+ mt7615_mcu_wtbl_bmc(dev, vif, info->enable_beacon);
+ mt7615_mcu_set_sta_rec_bmc(dev, vif, info->enable_beacon);
+ mt7615_mcu_set_bcn(dev, vif, info->enable_beacon);
}
mutex_unlock(&dev->mt76.mutex);
@@ -343,7 +336,7 @@ void mt7615_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
mt7615_mcu_set_sta_rec(dev, vif, sta, 0);
- mt7615_mcu_del_wtbl(dev, vif, sta);
+ mt7615_mcu_del_wtbl(dev, sta);
}
static void mt7615_sta_rate_tbl_update(struct ieee80211_hw *hw,
@@ -496,4 +489,5 @@ const struct ieee80211_ops mt7615_ops = {
.sw_scan_start = mt7615_sw_scan,
.sw_scan_complete = mt7615_sw_scan_complete,
.release_buffered_frames = mt76_release_buffered_frames,
+ .get_txpower = mt76_get_txpower,
};
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
index ea67c6022fe6..cdad2c8dc297 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
@@ -49,7 +49,7 @@ struct mt7615_fw_trailer {
#define FW_START_WORKING_PDA_CR4 BIT(2)
static int __mt7615_mcu_msg_send(struct mt7615_dev *dev, struct sk_buff *skb,
- int cmd, int query, int dest, int *wait_seq)
+ int cmd, int *wait_seq)
{
struct mt7615_mcu_txd *mcu_txd;
u8 seq, q_idx, pkt_fmt;
@@ -57,9 +57,6 @@ static int __mt7615_mcu_msg_send(struct mt7615_dev *dev, struct sk_buff *skb,
u32 val;
__le32 *txd;
- if (!skb)
- return -EINVAL;
-
seq = ++dev->mt76.mmio.mcu.msg_seq & 0xf;
if (!seq)
seq = ++dev->mt76.mmio.mcu.msg_seq & 0xf;
@@ -94,16 +91,15 @@ static int __mt7615_mcu_msg_send(struct mt7615_dev *dev, struct sk_buff *skb,
mcu_txd->seq = seq;
if (cmd < 0) {
+ mcu_txd->set_query = MCU_Q_NA;
mcu_txd->cid = -cmd;
} else {
mcu_txd->cid = MCU_CMD_EXT_CID;
+ mcu_txd->set_query = MCU_Q_SET;
mcu_txd->ext_cid = cmd;
- if (query != MCU_Q_NA)
- mcu_txd->ext_cid_ack = 1;
+ mcu_txd->ext_cid_ack = 1;
}
-
- mcu_txd->set_query = query;
- mcu_txd->s2d_index = dest;
+ mcu_txd->s2d_index = MCU_S2D_H2N;
if (wait_seq)
*wait_seq = seq;
@@ -116,24 +112,30 @@ static int __mt7615_mcu_msg_send(struct mt7615_dev *dev, struct sk_buff *skb,
return mt76_tx_queue_skb_raw(dev, qid, skb, 0);
}
-static int mt7615_mcu_msg_send(struct mt7615_dev *dev, struct sk_buff *skb,
- int cmd, int query, int dest,
- struct sk_buff **skb_ret)
+static int
+mt7615_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data,
+ int len, bool wait_resp)
{
+ struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
unsigned long expires = jiffies + 10 * HZ;
struct mt7615_mcu_rxd *rxd;
+ struct sk_buff *skb;
int ret, seq;
- mutex_lock(&dev->mt76.mmio.mcu.mutex);
+ skb = mt7615_mcu_msg_alloc(data, len);
+ if (!skb)
+ return -ENOMEM;
- ret = __mt7615_mcu_msg_send(dev, skb, cmd, query, dest, &seq);
+ mutex_lock(&mdev->mmio.mcu.mutex);
+
+ ret = __mt7615_mcu_msg_send(dev, skb, cmd, &seq);
if (ret)
goto out;
- while (1) {
- skb = mt76_mcu_get_response(&dev->mt76, expires);
+ while (wait_resp) {
+ skb = mt76_mcu_get_response(mdev, expires);
if (!skb) {
- dev_err(dev->mt76.dev, "Message %d (seq %d) timeout\n",
+ dev_err(mdev->dev, "Message %d (seq %d) timeout\n",
cmd, seq);
ret = -ETIMEDOUT;
break;
@@ -143,23 +145,16 @@ static int mt7615_mcu_msg_send(struct mt7615_dev *dev, struct sk_buff *skb,
if (seq != rxd->seq)
continue;
- if (skb_ret) {
- int hdr_len = sizeof(*rxd);
-
- if (!test_bit(MT76_STATE_MCU_RUNNING,
- &dev->mt76.state))
- hdr_len -= 4;
- skb_pull(skb, hdr_len);
- *skb_ret = skb;
- } else {
- dev_kfree_skb(skb);
+ if (cmd == -MCU_CMD_PATCH_SEM_CONTROL) {
+ skb_pull(skb, sizeof(*rxd) - 4);
+ ret = *skb->data;
}
-
+ dev_kfree_skb(skb);
break;
}
out:
- mutex_unlock(&dev->mt76.mmio.mcu.mutex);
+ mutex_unlock(&mdev->mmio.mcu.mutex);
return ret;
}
@@ -176,28 +171,22 @@ static int mt7615_mcu_init_download(struct mt7615_dev *dev, u32 addr,
.len = cpu_to_le32(len),
.mode = cpu_to_le32(mode),
};
- struct sk_buff *skb = mt7615_mcu_msg_alloc(&req, sizeof(req));
- return mt7615_mcu_msg_send(dev, skb, -MCU_CMD_TARGET_ADDRESS_LEN_REQ,
- MCU_Q_NA, MCU_S2D_H2N, NULL);
+ return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_TARGET_ADDRESS_LEN_REQ,
+ &req, sizeof(req), true);
}
static int mt7615_mcu_send_firmware(struct mt7615_dev *dev, const void *data,
int len)
{
- struct sk_buff *skb;
- int ret = 0;
+ int ret = 0, cur_len;
while (len > 0) {
- int cur_len = min_t(int, 4096 - sizeof(struct mt7615_mcu_txd),
- len);
-
- skb = mt7615_mcu_msg_alloc(data, cur_len);
- if (!skb)
- return -ENOMEM;
+ cur_len = min_t(int, 4096 - sizeof(struct mt7615_mcu_txd),
+ len);
- ret = __mt7615_mcu_msg_send(dev, skb, -MCU_CMD_FW_SCATTER,
- MCU_Q_NA, MCU_S2D_H2N, NULL);
+ ret = __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_SCATTER,
+ data, cur_len, false);
if (ret)
break;
@@ -218,47 +207,27 @@ static int mt7615_mcu_start_firmware(struct mt7615_dev *dev, u32 addr,
.option = cpu_to_le32(option),
.addr = cpu_to_le32(addr),
};
- struct sk_buff *skb = mt7615_mcu_msg_alloc(&req, sizeof(req));
- return mt7615_mcu_msg_send(dev, skb, -MCU_CMD_FW_START_REQ,
- MCU_Q_NA, MCU_S2D_H2N, NULL);
+ return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_START_REQ,
+ &req, sizeof(req), true);
}
-static int mt7615_mcu_restart(struct mt7615_dev *dev)
+static int mt7615_mcu_restart(struct mt76_dev *dev)
{
- struct sk_buff *skb = mt7615_mcu_msg_alloc(NULL, 0);
-
- return mt7615_mcu_msg_send(dev, skb, -MCU_CMD_RESTART_DL_REQ,
- MCU_Q_NA, MCU_S2D_H2N, NULL);
+ return __mt76_mcu_send_msg(dev, -MCU_CMD_RESTART_DL_REQ, NULL,
+ 0, true);
}
static int mt7615_mcu_patch_sem_ctrl(struct mt7615_dev *dev, bool get)
{
struct {
- __le32 operation;
+ __le32 op;
} req = {
- .operation = cpu_to_le32(get ? PATCH_SEM_GET :
- PATCH_SEM_RELEASE),
+ .op = cpu_to_le32(get ? PATCH_SEM_GET : PATCH_SEM_RELEASE),
};
- struct event {
- u8 status;
- u8 reserved[3];
- } *resp;
- struct sk_buff *skb = mt7615_mcu_msg_alloc(&req, sizeof(req));
- struct sk_buff *skb_ret;
- int ret;
- ret = mt7615_mcu_msg_send(dev, skb, -MCU_CMD_PATCH_SEM_CONTROL,
- MCU_Q_NA, MCU_S2D_H2N, &skb_ret);
- if (ret)
- goto out;
-
- resp = (struct event *)(skb_ret->data);
- ret = resp->status;
- dev_kfree_skb(skb_ret);
-
-out:
- return ret;
+ return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_PATCH_SEM_CONTROL,
+ &req, sizeof(req), true);
}
static int mt7615_mcu_start_patch(struct mt7615_dev *dev)
@@ -269,10 +238,9 @@ static int mt7615_mcu_start_patch(struct mt7615_dev *dev)
} req = {
.check_crc = 0,
};
- struct sk_buff *skb = mt7615_mcu_msg_alloc(&req, sizeof(req));
- return mt7615_mcu_msg_send(dev, skb, -MCU_CMD_PATCH_FINISH_REQ,
- MCU_Q_NA, MCU_S2D_H2N, NULL);
+ return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_PATCH_FINISH_REQ,
+ &req, sizeof(req), true);
}
static int mt7615_driver_own(struct mt7615_dev *dev)
@@ -508,8 +476,14 @@ static int mt7615_load_firmware(struct mt7615_dev *dev)
int mt7615_mcu_init(struct mt7615_dev *dev)
{
+ static const struct mt76_mcu_ops mt7615_mcu_ops = {
+ .mcu_send_msg = mt7615_mcu_msg_send,
+ .mcu_restart = mt7615_mcu_restart,
+ };
int ret;
+ dev->mt76.mcu_ops = &mt7615_mcu_ops,
+
ret = mt7615_driver_own(dev);
if (ret)
return ret;
@@ -525,16 +499,13 @@ int mt7615_mcu_init(struct mt7615_dev *dev)
void mt7615_mcu_exit(struct mt7615_dev *dev)
{
- mt7615_mcu_restart(dev);
+ __mt76_mcu_restart(&dev->mt76);
mt76_wr(dev, MT_CFG_LPCR_HOST, MT_CFG_LPCR_HOST_FW_OWN);
skb_queue_purge(&dev->mt76.mmio.mcu.res_q);
}
int mt7615_mcu_set_eeprom(struct mt7615_dev *dev)
{
- struct req_data {
- u8 val;
- } __packed;
struct {
u8 buffer_mode;
u8 pad;
@@ -543,23 +514,22 @@ int mt7615_mcu_set_eeprom(struct mt7615_dev *dev)
.buffer_mode = 1,
.len = __MT_EE_MAX - MT_EE_NIC_CONF_0,
};
- struct sk_buff *skb;
- struct req_data *data;
- const int size = (__MT_EE_MAX - MT_EE_NIC_CONF_0) *
- sizeof(struct req_data);
- u8 *eep = (u8 *)dev->mt76.eeprom.data;
- u16 off;
-
- skb = mt7615_mcu_msg_alloc(NULL, size + sizeof(req_hdr));
- memcpy(skb_put(skb, sizeof(req_hdr)), &req_hdr, sizeof(req_hdr));
- data = (struct req_data *)skb_put(skb, size);
- memset(data, 0, size);
-
- for (off = MT_EE_NIC_CONF_0; off < __MT_EE_MAX; off++)
- data[off - MT_EE_NIC_CONF_0].val = eep[off];
-
- return mt7615_mcu_msg_send(dev, skb, MCU_EXT_CMD_EFUSE_BUFFER_MODE,
- MCU_Q_SET, MCU_S2D_H2N, NULL);
+ int ret, len = sizeof(req_hdr) + __MT_EE_MAX - MT_EE_NIC_CONF_0;
+ u8 *req, *eep = (u8 *)dev->mt76.eeprom.data;
+
+ req = kzalloc(len, GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+
+ memcpy(req, &req_hdr, sizeof(req_hdr));
+ memcpy(req + sizeof(req_hdr), eep + MT_EE_NIC_CONF_0,
+ __MT_EE_MAX - MT_EE_NIC_CONF_0);
+
+ ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE,
+ req, len, true);
+ kfree(req);
+
+ return ret;
}
int mt7615_mcu_init_mac(struct mt7615_dev *dev)
@@ -572,10 +542,9 @@ int mt7615_mcu_init_mac(struct mt7615_dev *dev)
.enable = 1,
.band = 0,
};
- struct sk_buff *skb = mt7615_mcu_msg_alloc(&req, sizeof(req));
- return mt7615_mcu_msg_send(dev, skb, MCU_EXT_CMD_MAC_INIT_CTRL,
- MCU_Q_SET, MCU_S2D_H2N, NULL);
+ return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_MAC_INIT_CTRL,
+ &req, sizeof(req), true);
}
int mt7615_mcu_set_rts_thresh(struct mt7615_dev *dev, u32 val)
@@ -592,10 +561,9 @@ int mt7615_mcu_set_rts_thresh(struct mt7615_dev *dev, u32 val)
.len_thresh = cpu_to_le32(val),
.pkt_thresh = cpu_to_le32(0x2),
};
- struct sk_buff *skb = mt7615_mcu_msg_alloc(&req, sizeof(req));
- return mt7615_mcu_msg_send(dev, skb, MCU_EXT_CMD_PROTECT_CTRL,
- MCU_Q_SET, MCU_S2D_H2N, NULL);
+ return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_PROTECT_CTRL,
+ &req, sizeof(req), true);
}
int mt7615_mcu_set_wmm(struct mt7615_dev *dev, u8 queue,
@@ -621,7 +589,6 @@ int mt7615_mcu_set_wmm(struct mt7615_dev *dev, u8 queue,
.aifs = params->aifs,
.txop = cpu_to_le16(params->txop),
};
- struct sk_buff *skb;
if (params->cw_min) {
req.valid |= WMM_CW_MIN_SET;
@@ -632,9 +599,8 @@ int mt7615_mcu_set_wmm(struct mt7615_dev *dev, u8 queue,
req.cw_max = cpu_to_le16(params->cw_max);
}
- skb = mt7615_mcu_msg_alloc(&req, sizeof(req));
- return mt7615_mcu_msg_send(dev, skb, MCU_EXT_CMD_EDCA_UPDATE,
- MCU_Q_SET, MCU_S2D_H2N, NULL);
+ return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EDCA_UPDATE,
+ &req, sizeof(req), true);
}
int mt7615_mcu_ctrl_pm_state(struct mt7615_dev *dev, int enter)
@@ -662,300 +628,200 @@ int mt7615_mcu_ctrl_pm_state(struct mt7615_dev *dev, int enter)
.pm_state = (enter) ? ENTER_PM_STATE : EXIT_PM_STATE,
.band_idx = 0,
};
- struct sk_buff *skb = mt7615_mcu_msg_alloc(&req, sizeof(req));
-
- return mt7615_mcu_msg_send(dev, skb, MCU_EXT_CMD_PM_STATE_CTRL,
- MCU_Q_SET, MCU_S2D_H2N, NULL);
-}
-
-static int __mt7615_mcu_set_dev_info(struct mt7615_dev *dev,
- struct dev_info *dev_info)
-{
- struct req_hdr {
- u8 omac_idx;
- u8 band_idx;
- __le16 tlv_num;
- u8 is_tlv_append;
- u8 rsv[3];
- } __packed req_hdr = {0};
- struct req_tlv {
- __le16 tag;
- __le16 len;
- u8 active;
- u8 band_idx;
- u8 omac_addr[ETH_ALEN];
- } __packed;
- struct sk_buff *skb;
- u16 tlv_num = 0;
-
- skb = mt7615_mcu_msg_alloc(NULL, sizeof(req_hdr) +
- sizeof(struct req_tlv));
- skb_reserve(skb, sizeof(req_hdr));
-
- if (dev_info->feature & BIT(DEV_INFO_ACTIVE)) {
- struct req_tlv req_tlv = {
- .tag = cpu_to_le16(DEV_INFO_ACTIVE),
- .len = cpu_to_le16(sizeof(req_tlv)),
- .active = dev_info->enable,
- .band_idx = dev_info->band_idx,
- };
- memcpy(req_tlv.omac_addr, dev_info->omac_addr, ETH_ALEN);
- memcpy(skb_put(skb, sizeof(req_tlv)), &req_tlv,
- sizeof(req_tlv));
- tlv_num++;
- }
-
- req_hdr.omac_idx = dev_info->omac_idx;
- req_hdr.band_idx = dev_info->band_idx;
- req_hdr.tlv_num = cpu_to_le16(tlv_num);
- req_hdr.is_tlv_append = tlv_num ? 1 : 0;
- memcpy(skb_push(skb, sizeof(req_hdr)), &req_hdr, sizeof(req_hdr));
-
- return mt7615_mcu_msg_send(dev, skb, MCU_EXT_CMD_DEV_INFO_UPDATE,
- MCU_Q_SET, MCU_S2D_H2N, NULL);
+ return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_PM_STATE_CTRL,
+ &req, sizeof(req), true);
}
-int mt7615_mcu_set_dev_info(struct mt7615_dev *dev, struct ieee80211_vif *vif,
- int en)
+int mt7615_mcu_set_dev_info(struct mt7615_dev *dev,
+ struct ieee80211_vif *vif, bool enable)
{
struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
- struct dev_info dev_info = {0};
-
- dev_info.omac_idx = mvif->omac_idx;
- memcpy(dev_info.omac_addr, vif->addr, ETH_ALEN);
- dev_info.band_idx = mvif->band_idx;
- dev_info.enable = en;
- dev_info.feature = BIT(DEV_INFO_ACTIVE);
+ struct {
+ struct req_hdr {
+ u8 omac_idx;
+ u8 band_idx;
+ __le16 tlv_num;
+ u8 is_tlv_append;
+ u8 rsv[3];
+ } __packed hdr;
+ struct req_tlv {
+ __le16 tag;
+ __le16 len;
+ u8 active;
+ u8 band_idx;
+ u8 omac_addr[ETH_ALEN];
+ } __packed tlv;
+ } data = {
+ .hdr = {
+ .omac_idx = mvif->omac_idx,
+ .band_idx = mvif->band_idx,
+ .tlv_num = cpu_to_le16(1),
+ .is_tlv_append = 1,
+ },
+ .tlv = {
+ .tag = cpu_to_le16(DEV_INFO_ACTIVE),
+ .len = cpu_to_le16(sizeof(struct req_tlv)),
+ .active = enable,
+ .band_idx = mvif->band_idx,
+ },
+ };
- return __mt7615_mcu_set_dev_info(dev, &dev_info);
+ memcpy(data.tlv.omac_addr, vif->addr, ETH_ALEN);
+ return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_DEV_INFO_UPDATE,
+ &data, sizeof(data), true);
}
-static void bss_info_omac_handler (struct mt7615_dev *dev,
- struct bss_info *bss_info,
- struct sk_buff *skb)
+static void
+mt7615_mcu_bss_info_omac_header(struct mt7615_vif *mvif, u8 *data,
+ u32 conn_type)
{
- struct bss_info_omac tlv = {0};
-
- tlv.tag = cpu_to_le16(BSS_INFO_OMAC);
- tlv.len = cpu_to_le16(sizeof(tlv));
- tlv.hw_bss_idx = (bss_info->omac_idx > EXT_BSSID_START) ?
- HW_BSSID_0 : bss_info->omac_idx;
- tlv.omac_idx = bss_info->omac_idx;
- tlv.band_idx = bss_info->band_idx;
- tlv.conn_type = cpu_to_le32(bss_info->conn_type);
-
- memcpy(skb_put(skb, sizeof(tlv)), &tlv, sizeof(tlv));
+ struct bss_info_omac *hdr = (struct bss_info_omac *)data;
+ u8 idx;
+
+ idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx;
+ hdr->tag = cpu_to_le16(BSS_INFO_OMAC);
+ hdr->len = cpu_to_le16(sizeof(struct bss_info_omac));
+ hdr->hw_bss_idx = idx;
+ hdr->omac_idx = mvif->omac_idx;
+ hdr->band_idx = mvif->band_idx;
+ hdr->conn_type = cpu_to_le32(conn_type);
}
-static void bss_info_basic_handler (struct mt7615_dev *dev,
- struct bss_info *bss_info,
- struct sk_buff *skb)
+static void
+mt7615_mcu_bss_info_basic_header(struct ieee80211_vif *vif, u8 *data,
+ u32 net_type, u8 tx_wlan_idx,
+ bool enable)
{
- struct bss_info_basic tlv = {0};
-
- tlv.tag = cpu_to_le16(BSS_INFO_BASIC);
- tlv.len = cpu_to_le16(sizeof(tlv));
- tlv.network_type = cpu_to_le32(bss_info->network_type);
- tlv.active = bss_info->enable;
- tlv.bcn_interval = cpu_to_le16(bss_info->bcn_interval);
- memcpy(tlv.bssid, bss_info->bssid, ETH_ALEN);
- tlv.wmm_idx = bss_info->wmm_idx;
- tlv.dtim_period = bss_info->dtim_period;
- tlv.bmc_tx_wlan_idx = bss_info->bmc_tx_wlan_idx;
-
- memcpy(skb_put(skb, sizeof(tlv)), &tlv, sizeof(tlv));
+ struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+ struct bss_info_basic *hdr = (struct bss_info_basic *)data;
+
+ hdr->tag = cpu_to_le16(BSS_INFO_BASIC);
+ hdr->len = cpu_to_le16(sizeof(struct bss_info_basic));
+ hdr->network_type = cpu_to_le32(net_type);
+ hdr->active = enable;
+ hdr->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int);
+ memcpy(hdr->bssid, vif->bss_conf.bssid, ETH_ALEN);
+ hdr->wmm_idx = mvif->wmm_idx;
+ hdr->dtim_period = vif->bss_conf.dtim_period;
+ hdr->bmc_tx_wlan_idx = tx_wlan_idx;
}
-static void bss_info_ext_bss_handler (struct mt7615_dev *dev,
- struct bss_info *bss_info,
- struct sk_buff *skb)
+static void
+mt7615_mcu_bss_info_ext_header(struct mt7615_vif *mvif, u8 *data)
{
/* SIFS 20us + 512 byte beacon tranmitted by 1Mbps (3906us) */
#define BCN_TX_ESTIMATE_TIME (4096 + 20)
- struct bss_info_ext_bss tlv = {0};
- int ext_bss_idx;
-
- ext_bss_idx = bss_info->omac_idx - EXT_BSSID_START;
+ struct bss_info_ext_bss *hdr = (struct bss_info_ext_bss *)data;
+ int ext_bss_idx, tsf_offset;
+ ext_bss_idx = mvif->omac_idx - EXT_BSSID_START;
if (ext_bss_idx < 0)
return;
- tlv.tag = cpu_to_le16(BSS_INFO_EXT_BSS);
- tlv.len = cpu_to_le16(sizeof(tlv));
- tlv.mbss_tsf_offset = ext_bss_idx * BCN_TX_ESTIMATE_TIME;
-
- memcpy(skb_put(skb, sizeof(tlv)), &tlv, sizeof(tlv));
+ hdr->tag = cpu_to_le16(BSS_INFO_EXT_BSS);
+ hdr->len = cpu_to_le16(sizeof(struct bss_info_ext_bss));
+ tsf_offset = ext_bss_idx * BCN_TX_ESTIMATE_TIME;
+ hdr->mbss_tsf_offset = cpu_to_le32(tsf_offset);
}
-static struct bss_info_tag_handler bss_info_tag_handler[] = {
- {BSS_INFO_OMAC, sizeof(struct bss_info_omac), bss_info_omac_handler},
- {BSS_INFO_BASIC, sizeof(struct bss_info_basic), bss_info_basic_handler},
- {BSS_INFO_RF_CH, sizeof(struct bss_info_rf_ch), NULL},
- {BSS_INFO_PM, 0, NULL},
- {BSS_INFO_UAPSD, 0, NULL},
- {BSS_INFO_ROAM_DETECTION, 0, NULL},
- {BSS_INFO_LQ_RM, 0, NULL},
- {BSS_INFO_EXT_BSS, sizeof(struct bss_info_ext_bss), bss_info_ext_bss_handler},
- {BSS_INFO_BMC_INFO, 0, NULL},
- {BSS_INFO_SYNC_MODE, 0, NULL},
- {BSS_INFO_RA, 0, NULL},
- {BSS_INFO_MAX_NUM, 0, NULL},
-};
-
-static int __mt7615_mcu_set_bss_info(struct mt7615_dev *dev,
- struct bss_info *bss_info)
+int mt7615_mcu_set_bss_info(struct mt7615_dev *dev,
+ struct ieee80211_vif *vif, int en)
{
+ struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
struct req_hdr {
u8 bss_idx;
u8 rsv0;
__le16 tlv_num;
u8 is_tlv_append;
u8 rsv1[3];
- } __packed req_hdr = {0};
- struct sk_buff *skb;
- u16 tlv_num = 0;
- u32 size = 0;
- int i;
+ } __packed;
+ int len = sizeof(struct req_hdr) + sizeof(struct bss_info_basic);
+ int ret, i, features = BIT(BSS_INFO_BASIC), ntlv = 1;
+ u32 conn_type = 0, net_type = NETWORK_INFRA;
+ u8 *buf, *data, tx_wlan_idx = 0;
+ struct req_hdr *hdr;
- for (i = 0; i < BSS_INFO_MAX_NUM; i++)
- if ((BIT(bss_info_tag_handler[i].tag) & bss_info->feature) &&
- bss_info_tag_handler[i].handler) {
- tlv_num++;
- size += bss_info_tag_handler[i].len;
+ if (en) {
+ len += sizeof(struct bss_info_omac);
+ features |= BIT(BSS_INFO_OMAC);
+ if (mvif->omac_idx > EXT_BSSID_START) {
+ len += sizeof(struct bss_info_ext_bss);
+ features |= BIT(BSS_INFO_EXT_BSS);
+ ntlv++;
}
+ ntlv++;
+ }
- skb = mt7615_mcu_msg_alloc(NULL, sizeof(req_hdr) + size);
-
- req_hdr.bss_idx = bss_info->bss_idx;
- req_hdr.tlv_num = cpu_to_le16(tlv_num);
- req_hdr.is_tlv_append = tlv_num ? 1 : 0;
-
- memcpy(skb_put(skb, sizeof(req_hdr)), &req_hdr, sizeof(req_hdr));
-
- for (i = 0; i < BSS_INFO_MAX_NUM; i++)
- if ((BIT(bss_info_tag_handler[i].tag) & bss_info->feature) &&
- bss_info_tag_handler[i].handler)
- bss_info_tag_handler[i].handler(dev, bss_info, skb);
-
- return mt7615_mcu_msg_send(dev, skb, MCU_EXT_CMD_BSS_INFO_UPDATE,
- MCU_Q_SET, MCU_S2D_H2N, NULL);
-}
-
-static void bss_info_convert_vif_type(enum nl80211_iftype type,
- u32 *network_type, u32 *conn_type)
-{
- switch (type) {
+ switch (vif->type) {
case NL80211_IFTYPE_AP:
- if (network_type)
- *network_type = NETWORK_INFRA;
- if (conn_type)
- *conn_type = CONNECTION_INFRA_AP;
+ case NL80211_IFTYPE_MESH_POINT:
+ tx_wlan_idx = mvif->sta.wcid.idx;
+ conn_type = CONNECTION_INFRA_AP;
break;
- case NL80211_IFTYPE_STATION:
- if (network_type)
- *network_type = NETWORK_INFRA;
- if (conn_type)
- *conn_type = CONNECTION_INFRA_STA;
+ case NL80211_IFTYPE_STATION: {
+ /* TODO: enable BSS_INFO_UAPSD & BSS_INFO_PM */
+ if (en) {
+ struct ieee80211_sta *sta;
+ struct mt7615_sta *msta;
+
+ rcu_read_lock();
+ sta = ieee80211_find_sta(vif, vif->bss_conf.bssid);
+ if (!sta) {
+ rcu_read_unlock();
+ return -EINVAL;
+ }
+
+ msta = (struct mt7615_sta *)sta->drv_priv;
+ tx_wlan_idx = msta->wcid.idx;
+ rcu_read_unlock();
+ }
+ conn_type = CONNECTION_INFRA_STA;
break;
+ }
default:
WARN_ON(1);
break;
- };
-}
-
-int mt7615_mcu_set_bss_info(struct mt7615_dev *dev, struct ieee80211_vif *vif,
- int en)
-{
- struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
- struct bss_info bss_info = {0};
- u8 bmc_tx_wlan_idx = 0;
- u32 network_type = 0, conn_type = 0;
-
- if (vif->type == NL80211_IFTYPE_AP) {
- bmc_tx_wlan_idx = mvif->sta.wcid.idx;
- } else if (vif->type == NL80211_IFTYPE_STATION) {
- /* find the unicast entry for sta mode bmc tx */
- struct ieee80211_sta *ap_sta;
- struct mt7615_sta *msta;
-
- rcu_read_lock();
-
- ap_sta = ieee80211_find_sta(vif, vif->bss_conf.bssid);
- if (!ap_sta) {
- rcu_read_unlock();
- return -EINVAL;
- }
-
- msta = (struct mt7615_sta *)ap_sta->drv_priv;
- bmc_tx_wlan_idx = msta->wcid.idx;
-
- rcu_read_unlock();
- } else {
- WARN_ON(1);
}
- bss_info_convert_vif_type(vif->type, &network_type, &conn_type);
-
- bss_info.bss_idx = mvif->idx;
- memcpy(bss_info.bssid, vif->bss_conf.bssid, ETH_ALEN);
- bss_info.omac_idx = mvif->omac_idx;
- bss_info.band_idx = mvif->band_idx;
- bss_info.bmc_tx_wlan_idx = bmc_tx_wlan_idx;
- bss_info.wmm_idx = mvif->wmm_idx;
- bss_info.network_type = network_type;
- bss_info.conn_type = conn_type;
- bss_info.bcn_interval = vif->bss_conf.beacon_int;
- bss_info.dtim_period = vif->bss_conf.dtim_period;
- bss_info.enable = en;
- bss_info.feature = BIT(BSS_INFO_BASIC);
- if (en) {
- bss_info.feature |= BIT(BSS_INFO_OMAC);
- if (mvif->omac_idx > EXT_BSSID_START)
- bss_info.feature |= BIT(BSS_INFO_EXT_BSS);
- }
-
- return __mt7615_mcu_set_bss_info(dev, &bss_info);
-}
+ buf = kzalloc(len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
-static int __mt7615_mcu_set_wtbl(struct mt7615_dev *dev, int wlan_idx,
- int operation, void *buf, int buf_len)
-{
- struct req_hdr {
- u8 wlan_idx;
- u8 operation;
- __le16 tlv_num;
- u8 rsv[4];
- } __packed req_hdr = {0};
- struct tlv {
- __le16 tag;
- __le16 len;
- u8 buf[0];
- } __packed;
- struct sk_buff *skb;
- u16 tlv_num = 0;
- int offset = 0;
+ hdr = (struct req_hdr *)buf;
+ hdr->bss_idx = mvif->idx;
+ hdr->tlv_num = cpu_to_le16(ntlv);
+ hdr->is_tlv_append = 1;
- while (offset < buf_len) {
- struct tlv *tlv = (struct tlv *)((u8 *)buf + offset);
+ data = buf + sizeof(*hdr);
+ for (i = 0; i < BSS_INFO_MAX_NUM; i++) {
+ int tag = ffs(features & BIT(i)) - 1;
- tlv_num++;
- offset += tlv->len;
+ switch (tag) {
+ case BSS_INFO_OMAC:
+ mt7615_mcu_bss_info_omac_header(mvif, data,
+ conn_type);
+ data += sizeof(struct bss_info_omac);
+ break;
+ case BSS_INFO_BASIC:
+ mt7615_mcu_bss_info_basic_header(vif, data, net_type,
+ tx_wlan_idx, en);
+ data += sizeof(struct bss_info_basic);
+ break;
+ case BSS_INFO_EXT_BSS:
+ mt7615_mcu_bss_info_ext_header(mvif, data);
+ data += sizeof(struct bss_info_ext_bss);
+ break;
+ default:
+ break;
+ }
}
- skb = mt7615_mcu_msg_alloc(NULL, sizeof(req_hdr) + buf_len);
-
- req_hdr.wlan_idx = wlan_idx;
- req_hdr.operation = operation;
- req_hdr.tlv_num = cpu_to_le16(tlv_num);
-
- memcpy(skb_put(skb, sizeof(req_hdr)), &req_hdr, sizeof(req_hdr));
-
- if (buf && buf_len)
- memcpy(skb_put(skb, buf_len), buf, buf_len);
+ ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_BSS_INFO_UPDATE,
+ buf, len, true);
+ kfree(buf);
- return mt7615_mcu_msg_send(dev, skb, MCU_EXT_CMD_WTBL_UPDATE,
- MCU_Q_SET, MCU_S2D_H2N, NULL);
+ return ret;
}
static enum mt7615_cipher_type
@@ -995,70 +861,90 @@ int mt7615_mcu_set_wtbl_key(struct mt7615_dev *dev, int wcid,
struct ieee80211_key_conf *key,
enum set_key_cmd cmd)
{
- struct wtbl_sec_key wtbl_sec_key = {0};
- int buf_len = sizeof(struct wtbl_sec_key);
- u8 cipher;
-
- wtbl_sec_key.tag = cpu_to_le16(WTBL_SEC_KEY);
- wtbl_sec_key.len = cpu_to_le16(buf_len);
- wtbl_sec_key.add = cmd;
+ struct {
+ struct wtbl_req_hdr hdr;
+ struct wtbl_sec_key key;
+ } req = {
+ .hdr = {
+ .wlan_idx = wcid,
+ .operation = WTBL_SET,
+ .tlv_num = cpu_to_le16(1),
+ },
+ .key = {
+ .tag = cpu_to_le16(WTBL_SEC_KEY),
+ .len = cpu_to_le16(sizeof(struct wtbl_sec_key)),
+ .add = cmd,
+ },
+ };
if (cmd == SET_KEY) {
- cipher = mt7615_get_key_info(key, wtbl_sec_key.key_material);
- if (cipher == MT_CIPHER_NONE && key)
+ u8 cipher;
+
+ cipher = mt7615_get_key_info(key, req.key.key_material);
+ if (cipher == MT_CIPHER_NONE)
return -EOPNOTSUPP;
- wtbl_sec_key.cipher_id = cipher;
- wtbl_sec_key.key_id = key->keyidx;
- wtbl_sec_key.key_len = key->keylen;
+ req.key.rkv = 1;
+ req.key.cipher_id = cipher;
+ req.key.key_id = key->keyidx;
+ req.key.key_len = key->keylen;
} else {
- wtbl_sec_key.key_len = sizeof(wtbl_sec_key.key_material);
+ req.key.key_len = sizeof(req.key.key_material);
}
- return __mt7615_mcu_set_wtbl(dev, wcid, WTBL_SET, &wtbl_sec_key,
- buf_len);
+ return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_WTBL_UPDATE,
+ &req, sizeof(req), true);
}
-int mt7615_mcu_add_wtbl_bmc(struct mt7615_dev *dev, struct ieee80211_vif *vif)
+static int
+mt7615_mcu_add_wtbl_bmc(struct mt7615_dev *dev,
+ struct mt7615_vif *mvif)
{
- struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
- struct wtbl_generic *wtbl_generic;
- struct wtbl_rx *wtbl_rx;
- int buf_len, ret;
- u8 *buf;
-
- buf = kzalloc(MT7615_WTBL_UPDATE_MAX_SIZE, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- wtbl_generic = (struct wtbl_generic *)buf;
- buf_len = sizeof(*wtbl_generic);
- wtbl_generic->tag = cpu_to_le16(WTBL_GENERIC);
- wtbl_generic->len = cpu_to_le16(buf_len);
- eth_broadcast_addr(wtbl_generic->peer_addr);
- wtbl_generic->muar_idx = 0xe;
-
- wtbl_rx = (struct wtbl_rx *)(buf + buf_len);
- buf_len += sizeof(*wtbl_rx);
- wtbl_rx->tag = cpu_to_le16(WTBL_RX);
- wtbl_rx->len = cpu_to_le16(sizeof(*wtbl_rx));
- wtbl_rx->rca1 = 1;
- wtbl_rx->rca2 = 1;
- wtbl_rx->rv = 1;
-
- ret = __mt7615_mcu_set_wtbl(dev, mvif->sta.wcid.idx,
- WTBL_RESET_AND_SET, buf, buf_len);
+ struct {
+ struct wtbl_req_hdr hdr;
+ struct wtbl_generic g_wtbl;
+ struct wtbl_rx rx_wtbl;
+ } req = {
+ .hdr = {
+ .wlan_idx = mvif->sta.wcid.idx,
+ .operation = WTBL_RESET_AND_SET,
+ .tlv_num = cpu_to_le16(2),
+ },
+ .g_wtbl = {
+ .tag = cpu_to_le16(WTBL_GENERIC),
+ .len = cpu_to_le16(sizeof(struct wtbl_generic)),
+ .muar_idx = 0xe,
+ },
+ .rx_wtbl = {
+ .tag = cpu_to_le16(WTBL_RX),
+ .len = cpu_to_le16(sizeof(struct wtbl_rx)),
+ .rca1 = 1,
+ .rca2 = 1,
+ .rv = 1,
+ },
+ };
+ eth_broadcast_addr(req.g_wtbl.peer_addr);
- kfree(buf);
- return ret;
+ return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_WTBL_UPDATE,
+ &req, sizeof(req), true);
}
-int mt7615_mcu_del_wtbl_bmc(struct mt7615_dev *dev, struct ieee80211_vif *vif)
+int mt7615_mcu_wtbl_bmc(struct mt7615_dev *dev,
+ struct ieee80211_vif *vif, bool enable)
{
struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
- return __mt7615_mcu_set_wtbl(dev, mvif->sta.wcid.idx,
- WTBL_RESET_AND_SET, NULL, 0);
+ if (!enable) {
+ struct wtbl_req_hdr req = {
+ .wlan_idx = mvif->sta.wcid.idx,
+ .operation = WTBL_RESET_AND_SET,
+ };
+
+ return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_WTBL_UPDATE,
+ &req, sizeof(req), true);
+ }
+
+ return mt7615_mcu_add_wtbl_bmc(dev, mvif);
}
int mt7615_mcu_add_wtbl(struct mt7615_dev *dev, struct ieee80211_vif *vif,
@@ -1066,175 +952,153 @@ int mt7615_mcu_add_wtbl(struct mt7615_dev *dev, struct ieee80211_vif *vif,
{
struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
- struct wtbl_generic *wtbl_generic;
- struct wtbl_rx *wtbl_rx;
- int buf_len, ret;
- u8 *buf;
-
- buf = kzalloc(MT7615_WTBL_UPDATE_MAX_SIZE, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- wtbl_generic = (struct wtbl_generic *)buf;
- buf_len = sizeof(*wtbl_generic);
- wtbl_generic->tag = cpu_to_le16(WTBL_GENERIC);
- wtbl_generic->len = cpu_to_le16(buf_len);
- memcpy(wtbl_generic->peer_addr, sta->addr, ETH_ALEN);
- wtbl_generic->muar_idx = mvif->omac_idx;
- wtbl_generic->qos = sta->wme;
- wtbl_generic->partial_aid = cpu_to_le16(sta->aid);
-
- wtbl_rx = (struct wtbl_rx *)(buf + buf_len);
- buf_len += sizeof(*wtbl_rx);
- wtbl_rx->tag = cpu_to_le16(WTBL_RX);
- wtbl_rx->len = cpu_to_le16(sizeof(*wtbl_rx));
- wtbl_rx->rca1 = (vif->type == NL80211_IFTYPE_AP) ? 0 : 1;
- wtbl_rx->rca2 = 1;
- wtbl_rx->rv = 1;
-
- ret = __mt7615_mcu_set_wtbl(dev, msta->wcid.idx,
- WTBL_RESET_AND_SET, buf, buf_len);
+ struct {
+ struct wtbl_req_hdr hdr;
+ struct wtbl_generic g_wtbl;
+ struct wtbl_rx rx_wtbl;
+ } req = {
+ .hdr = {
+ .wlan_idx = msta->wcid.idx,
+ .operation = WTBL_RESET_AND_SET,
+ .tlv_num = cpu_to_le16(2),
+ },
+ .g_wtbl = {
+ .tag = cpu_to_le16(WTBL_GENERIC),
+ .len = cpu_to_le16(sizeof(struct wtbl_generic)),
+ .muar_idx = mvif->omac_idx,
+ .qos = sta->wme,
+ .partial_aid = cpu_to_le16(sta->aid),
+ },
+ .rx_wtbl = {
+ .tag = cpu_to_le16(WTBL_RX),
+ .len = cpu_to_le16(sizeof(struct wtbl_rx)),
+ .rca1 = vif->type != NL80211_IFTYPE_AP,
+ .rca2 = 1,
+ .rv = 1,
+ },
+ };
+ memcpy(req.g_wtbl.peer_addr, sta->addr, ETH_ALEN);
- kfree(buf);
- return ret;
+ return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_WTBL_UPDATE,
+ &req, sizeof(req), true);
}
-int mt7615_mcu_del_wtbl(struct mt7615_dev *dev, struct ieee80211_vif *vif,
+int mt7615_mcu_del_wtbl(struct mt7615_dev *dev,
struct ieee80211_sta *sta)
{
struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
+ struct wtbl_req_hdr req = {
+ .wlan_idx = msta->wcid.idx,
+ .operation = WTBL_RESET_AND_SET,
+ };
- return __mt7615_mcu_set_wtbl(dev, msta->wcid.idx,
- WTBL_RESET_AND_SET, NULL, 0);
+ return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_WTBL_UPDATE,
+ &req, sizeof(req), true);
}
int mt7615_mcu_del_wtbl_all(struct mt7615_dev *dev)
{
- return __mt7615_mcu_set_wtbl(dev, 0, WTBL_RESET_ALL, NULL, 0);
-}
-
-static int __mt7615_mcu_set_sta_rec(struct mt7615_dev *dev, int bss_idx,
- int wlan_idx, int muar_idx, void *buf,
- int buf_len)
-{
- struct req_hdr {
- u8 bss_idx;
- u8 wlan_idx;
- __le16 tlv_num;
- u8 is_tlv_append;
- u8 muar_idx;
- u8 rsv[2];
- } __packed req_hdr = {0};
- struct tlv {
- __le16 tag;
- __le16 len;
- u8 buf[0];
- } __packed;
- struct sk_buff *skb;
- u16 tlv_num = 0;
- int offset = 0;
-
- while (offset < buf_len) {
- struct tlv *tlv = (struct tlv *)((u8 *)buf + offset);
-
- tlv_num++;
- offset += tlv->len;
- }
-
- skb = mt7615_mcu_msg_alloc(NULL, sizeof(req_hdr) + buf_len);
-
- req_hdr.bss_idx = bss_idx;
- req_hdr.wlan_idx = wlan_idx;
- req_hdr.tlv_num = cpu_to_le16(tlv_num);
- req_hdr.is_tlv_append = tlv_num ? 1 : 0;
- req_hdr.muar_idx = muar_idx;
-
- memcpy(skb_put(skb, sizeof(req_hdr)), &req_hdr, sizeof(req_hdr));
-
- if (buf && buf_len)
- memcpy(skb_put(skb, buf_len), buf, buf_len);
+ struct wtbl_req_hdr req = {
+ .operation = WTBL_RESET_ALL,
+ };
- return mt7615_mcu_msg_send(dev, skb, MCU_EXT_CMD_STA_REC_UPDATE,
- MCU_Q_SET, MCU_S2D_H2N, NULL);
+ return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_WTBL_UPDATE,
+ &req, sizeof(req), true);
}
int mt7615_mcu_set_sta_rec_bmc(struct mt7615_dev *dev,
struct ieee80211_vif *vif, bool en)
{
struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
- struct sta_rec_basic sta_rec_basic = {0};
- int buf_len = sizeof(struct sta_rec_basic);
+ struct {
+ struct sta_req_hdr hdr;
+ struct sta_rec_basic basic;
+ } req = {
+ .hdr = {
+ .bss_idx = mvif->idx,
+ .wlan_idx = mvif->sta.wcid.idx,
+ .tlv_num = cpu_to_le16(1),
+ .is_tlv_append = 1,
+ .muar_idx = mvif->omac_idx,
+ },
+ .basic = {
+ .tag = cpu_to_le16(STA_REC_BASIC),
+ .len = cpu_to_le16(sizeof(struct sta_rec_basic)),
+ .conn_type = cpu_to_le32(CONNECTION_INFRA_BC),
+ },
+ };
+ eth_broadcast_addr(req.basic.peer_addr);
- sta_rec_basic.tag = cpu_to_le16(STA_REC_BASIC);
- sta_rec_basic.len = cpu_to_le16(buf_len);
- sta_rec_basic.conn_type = cpu_to_le32(CONNECTION_INFRA_BC);
- eth_broadcast_addr(sta_rec_basic.peer_addr);
if (en) {
- sta_rec_basic.conn_state = CONN_STATE_PORT_SECURE;
- sta_rec_basic.extra_info =
- cpu_to_le16(EXTRA_INFO_VER | EXTRA_INFO_NEW);
+ req.basic.conn_state = CONN_STATE_PORT_SECURE;
+ req.basic.extra_info = cpu_to_le16(EXTRA_INFO_VER |
+ EXTRA_INFO_NEW);
} else {
- sta_rec_basic.conn_state = CONN_STATE_DISCONNECT;
- sta_rec_basic.extra_info = cpu_to_le16(EXTRA_INFO_VER);
+ req.basic.conn_state = CONN_STATE_DISCONNECT;
+ req.basic.extra_info = cpu_to_le16(EXTRA_INFO_VER);
}
- return __mt7615_mcu_set_sta_rec(dev, mvif->idx, mvif->sta.wcid.idx,
- mvif->omac_idx, &sta_rec_basic,
- buf_len);
+ return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_STA_REC_UPDATE,
+ &req, sizeof(req), true);
}
-static void sta_rec_convert_vif_type(enum nl80211_iftype type, u32 *conn_type)
+int mt7615_mcu_set_sta_rec(struct mt7615_dev *dev, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, bool en)
{
- switch (type) {
+ struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+ struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
+
+ struct {
+ struct sta_req_hdr hdr;
+ struct sta_rec_basic basic;
+ } req = {
+ .hdr = {
+ .bss_idx = mvif->idx,
+ .wlan_idx = msta->wcid.idx,
+ .tlv_num = cpu_to_le16(1),
+ .is_tlv_append = 1,
+ .muar_idx = mvif->omac_idx,
+ },
+ .basic = {
+ .tag = cpu_to_le16(STA_REC_BASIC),
+ .len = cpu_to_le16(sizeof(struct sta_rec_basic)),
+ .qos = sta->wme,
+ .aid = cpu_to_le16(sta->aid),
+ },
+ };
+ memcpy(req.basic.peer_addr, sta->addr, ETH_ALEN);
+
+ switch (vif->type) {
case NL80211_IFTYPE_AP:
- if (conn_type)
- *conn_type = CONNECTION_INFRA_STA;
+ case NL80211_IFTYPE_MESH_POINT:
+ req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_STA);
break;
case NL80211_IFTYPE_STATION:
- if (conn_type)
- *conn_type = CONNECTION_INFRA_AP;
+ req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_AP);
break;
default:
WARN_ON(1);
break;
};
-}
-
-int mt7615_mcu_set_sta_rec(struct mt7615_dev *dev, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta, bool en)
-{
- struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
- struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
- struct sta_rec_basic sta_rec_basic = {0};
- int buf_len = sizeof(struct sta_rec_basic);
- u32 conn_type = 0;
-
- sta_rec_convert_vif_type(vif->type, &conn_type);
-
- sta_rec_basic.tag = cpu_to_le16(STA_REC_BASIC);
- sta_rec_basic.len = cpu_to_le16(buf_len);
- sta_rec_basic.conn_type = cpu_to_le32(conn_type);
- sta_rec_basic.qos = sta->wme;
- sta_rec_basic.aid = cpu_to_le16(sta->aid);
- memcpy(sta_rec_basic.peer_addr, sta->addr, ETH_ALEN);
if (en) {
- sta_rec_basic.conn_state = CONN_STATE_PORT_SECURE;
- sta_rec_basic.extra_info =
- cpu_to_le16(EXTRA_INFO_VER | EXTRA_INFO_NEW);
+ req.basic.conn_state = CONN_STATE_PORT_SECURE;
+ req.basic.extra_info = cpu_to_le16(EXTRA_INFO_VER |
+ EXTRA_INFO_NEW);
} else {
- sta_rec_basic.conn_state = CONN_STATE_DISCONNECT;
- sta_rec_basic.extra_info = cpu_to_le16(EXTRA_INFO_VER);
+ req.basic.conn_state = CONN_STATE_DISCONNECT;
+ req.basic.extra_info = cpu_to_le16(EXTRA_INFO_VER);
}
- return __mt7615_mcu_set_sta_rec(dev, mvif->idx, msta->wcid.idx,
- mvif->omac_idx, &sta_rec_basic,
- buf_len);
+ return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_STA_REC_UPDATE,
+ &req, sizeof(req), true);
}
int mt7615_mcu_set_bcn(struct mt7615_dev *dev, struct ieee80211_vif *vif,
int en)
{
+ struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+ struct mt76_wcid *wcid = &dev->mt76.global_wcid;
struct req {
u8 omac_idx;
u8 enable;
@@ -1250,14 +1114,18 @@ int mt7615_mcu_set_bcn(struct mt7615_dev *dev, struct ieee80211_vif *vif,
/* bss color change */
u8 bcc_cnt;
__le16 bcc_ie_pos;
- } __packed req = {0};
- struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
- struct mt76_wcid *wcid = &dev->mt76.global_wcid;
+ } __packed req = {
+ .omac_idx = mvif->omac_idx,
+ .enable = en,
+ .wlan_idx = wcid->idx,
+ .band_idx = mvif->band_idx,
+ /* pky_type: 0 for bcn, 1 for tim */
+ .pkt_type = 0,
+ };
struct sk_buff *skb;
- u16 tim_off, tim_len;
-
- skb = ieee80211_beacon_get_tim(mt76_hw(dev), vif, &tim_off, &tim_len);
+ u16 tim_off;
+ skb = ieee80211_beacon_get_tim(mt76_hw(dev), vif, &tim_off, NULL);
if (!skb)
return -EINVAL;
@@ -1270,21 +1138,79 @@ int mt7615_mcu_set_bcn(struct mt7615_dev *dev, struct ieee80211_vif *vif,
mt7615_mac_write_txwi(dev, (__le32 *)(req.pkt), skb, wcid, NULL,
0, NULL);
memcpy(req.pkt + MT_TXD_SIZE, skb->data, skb->len);
- dev_kfree_skb(skb);
-
- req.omac_idx = mvif->omac_idx;
- req.enable = en;
- req.wlan_idx = wcid->idx;
- req.band_idx = mvif->band_idx;
- /* pky_type: 0 for bcn, 1 for tim */
- req.pkt_type = 0;
req.pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
req.tim_ie_pos = cpu_to_le16(MT_TXD_SIZE + tim_off);
- skb = mt7615_mcu_msg_alloc(&req, sizeof(req));
+ dev_kfree_skb(skb);
+
+ return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_BCN_OFFLOAD,
+ &req, sizeof(req), true);
+}
+
+int mt7615_mcu_set_tx_power(struct mt7615_dev *dev)
+{
+ int i, ret, n_chains = hweight8(dev->mt76.antenna_mask);
+ struct cfg80211_chan_def *chandef = &dev->mt76.chandef;
+ int freq = chandef->center_freq1, len, target_chains;
+ u8 *req, *data, *eep = (u8 *)dev->mt76.eeprom.data;
+ enum nl80211_band band = chandef->chan->band;
+ struct ieee80211_hw *hw = mt76_hw(dev);
+ struct {
+ u8 center_chan;
+ u8 dbdc_idx;
+ u8 band;
+ u8 rsv;
+ } __packed req_hdr = {
+ .center_chan = ieee80211_frequency_to_channel(freq),
+ .band = band,
+ };
+ s8 tx_power;
+
+ len = sizeof(req_hdr) + __MT_EE_MAX - MT_EE_NIC_CONF_0;
+ req = kzalloc(len, GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
- return mt7615_mcu_msg_send(dev, skb, MCU_EXT_CMD_BCN_OFFLOAD,
- MCU_Q_SET, MCU_S2D_H2N, NULL);
+ memcpy(req, &req_hdr, sizeof(req_hdr));
+ data = req + sizeof(req_hdr);
+ memcpy(data, eep + MT_EE_NIC_CONF_0,
+ __MT_EE_MAX - MT_EE_NIC_CONF_0);
+
+ tx_power = hw->conf.power_level * 2;
+ switch (n_chains) {
+ case 4:
+ tx_power -= 12;
+ break;
+ case 3:
+ tx_power -= 8;
+ break;
+ case 2:
+ tx_power -= 6;
+ break;
+ default:
+ break;
+ }
+ tx_power = max_t(s8, tx_power, 0);
+ dev->mt76.txpower_cur = tx_power;
+
+ target_chains = mt7615_ext_pa_enabled(dev, band) ? 1 : n_chains;
+ for (i = 0; i < target_chains; i++) {
+ int index = -MT_EE_NIC_CONF_0;
+
+ ret = mt7615_eeprom_get_power_index(dev, chandef->chan, i);
+ if (ret < 0)
+ goto out;
+
+ index += ret;
+ data[index] = min_t(u8, data[index], tx_power);
+ }
+
+ ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_TX_POWER_CTRL,
+ req, len, true);
+out:
+ kfree(req);
+
+ return ret;
}
int mt7615_mcu_set_channel(struct mt7615_dev *dev)
@@ -1309,7 +1235,6 @@ int mt7615_mcu_set_channel(struct mt7615_dev *dev)
u8 txpower_sku[53];
u8 rsv2[3];
} req = {0};
- struct sk_buff *skb;
int ret;
req.control_chan = chdef->chan->hw_value;
@@ -1345,18 +1270,15 @@ int mt7615_mcu_set_channel(struct mt7615_dev *dev)
default:
req.bw = CMD_CBW_20MHZ;
}
-
memset(req.txpower_sku, 0x3f, 49);
- skb = mt7615_mcu_msg_alloc(&req, sizeof(req));
- ret = mt7615_mcu_msg_send(dev, skb, MCU_EXT_CMD_CHANNEL_SWITCH,
- MCU_Q_SET, MCU_S2D_H2N, NULL);
+ ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_CHANNEL_SWITCH,
+ &req, sizeof(req), true);
if (ret)
return ret;
- skb = mt7615_mcu_msg_alloc(&req, sizeof(req));
- return mt7615_mcu_msg_send(dev, skb, MCU_EXT_CMD_SET_RX_PATH,
- MCU_Q_SET, MCU_S2D_H2N, NULL);
+ return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RX_PATH,
+ &req, sizeof(req), true);
}
int mt7615_mcu_set_ht_cap(struct mt7615_dev *dev, struct ieee80211_vif *vif,
@@ -1364,10 +1286,12 @@ int mt7615_mcu_set_ht_cap(struct mt7615_dev *dev, struct ieee80211_vif *vif,
{
struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
- struct wtbl_ht *wtbl_ht;
+ struct wtbl_req_hdr *wtbl_hdr;
+ struct sta_req_hdr *sta_hdr;
struct wtbl_raw *wtbl_raw;
- struct sta_rec_ht *sta_rec_ht;
- int buf_len, ret;
+ struct sta_rec_ht *sta_ht;
+ struct wtbl_ht *wtbl_ht;
+ int buf_len, ret, ntlv = 2;
u32 msk, val = 0;
u8 *buf;
@@ -1375,15 +1299,20 @@ int mt7615_mcu_set_ht_cap(struct mt7615_dev *dev, struct ieee80211_vif *vif,
if (!buf)
return -ENOMEM;
+ wtbl_hdr = (struct wtbl_req_hdr *)buf;
+ wtbl_hdr->wlan_idx = msta->wcid.idx;
+ wtbl_hdr->operation = WTBL_SET;
+ buf_len = sizeof(*wtbl_hdr);
+
/* ht basic */
- buf_len = sizeof(*wtbl_ht);
- wtbl_ht = (struct wtbl_ht *)buf;
+ wtbl_ht = (struct wtbl_ht *)(buf + buf_len);
wtbl_ht->tag = cpu_to_le16(WTBL_HT);
wtbl_ht->len = cpu_to_le16(sizeof(*wtbl_ht));
wtbl_ht->ht = 1;
wtbl_ht->ldpc = sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING;
wtbl_ht->af = sta->ht_cap.ampdu_factor;
wtbl_ht->mm = sta->ht_cap.ampdu_density;
+ buf_len += sizeof(*wtbl_ht);
if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20)
val |= MT_WTBL_W5_SHORT_GI_20;
@@ -1400,6 +1329,7 @@ int mt7615_mcu_set_ht_cap(struct mt7615_dev *dev, struct ieee80211_vif *vif,
wtbl_vht->len = cpu_to_le16(sizeof(*wtbl_vht));
wtbl_vht->ldpc = sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC;
wtbl_vht->vht = 1;
+ ntlv++;
if (sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80)
val |= MT_WTBL_W5_SHORT_GI_80;
@@ -1416,6 +1346,7 @@ int mt7615_mcu_set_ht_cap(struct mt7615_dev *dev, struct ieee80211_vif *vif,
wtbl_smps->tag = cpu_to_le16(WTBL_SMPS);
wtbl_smps->len = cpu_to_le16(sizeof(*wtbl_smps));
wtbl_smps->smps = 1;
+ ntlv++;
}
/* sgi */
@@ -1431,38 +1362,46 @@ int mt7615_mcu_set_ht_cap(struct mt7615_dev *dev, struct ieee80211_vif *vif,
wtbl_raw->msk = cpu_to_le32(~msk);
wtbl_raw->val = cpu_to_le32(val);
- ret = __mt7615_mcu_set_wtbl(dev, msta->wcid.idx, WTBL_SET, buf,
- buf_len);
- if (ret) {
- kfree(buf);
- return ret;
- }
+ wtbl_hdr->tlv_num = cpu_to_le16(ntlv);
+ ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_WTBL_UPDATE,
+ buf, buf_len, true);
+ if (ret)
+ goto out;
memset(buf, 0, MT7615_WTBL_UPDATE_MAX_SIZE);
- buf_len = sizeof(*sta_rec_ht);
- sta_rec_ht = (struct sta_rec_ht *)buf;
- sta_rec_ht->tag = cpu_to_le16(STA_REC_HT);
- sta_rec_ht->len = cpu_to_le16(sizeof(*sta_rec_ht));
- sta_rec_ht->ht_cap = cpu_to_le16(sta->ht_cap.cap);
+ sta_hdr = (struct sta_req_hdr *)buf;
+ sta_hdr->bss_idx = mvif->idx;
+ sta_hdr->wlan_idx = msta->wcid.idx;
+ sta_hdr->is_tlv_append = 1;
+ ntlv = sta->vht_cap.vht_supported ? 2 : 1;
+ sta_hdr->tlv_num = cpu_to_le16(ntlv);
+ sta_hdr->muar_idx = mvif->omac_idx;
+ buf_len = sizeof(*sta_hdr);
+
+ sta_ht = (struct sta_rec_ht *)(buf + buf_len);
+ sta_ht->tag = cpu_to_le16(STA_REC_HT);
+ sta_ht->len = cpu_to_le16(sizeof(*sta_ht));
+ sta_ht->ht_cap = cpu_to_le16(sta->ht_cap.cap);
+ buf_len += sizeof(*sta_ht);
if (sta->vht_cap.vht_supported) {
- struct sta_rec_vht *sta_rec_vht;
-
- sta_rec_vht = (struct sta_rec_vht *)(buf + buf_len);
- buf_len += sizeof(*sta_rec_vht);
- sta_rec_vht->tag = cpu_to_le16(STA_REC_VHT);
- sta_rec_vht->len = cpu_to_le16(sizeof(*sta_rec_vht));
- sta_rec_vht->vht_cap = cpu_to_le32(sta->vht_cap.cap);
- sta_rec_vht->vht_rx_mcs_map =
- cpu_to_le16(sta->vht_cap.vht_mcs.rx_mcs_map);
- sta_rec_vht->vht_tx_mcs_map =
- cpu_to_le16(sta->vht_cap.vht_mcs.tx_mcs_map);
+ struct sta_rec_vht *sta_vht;
+
+ sta_vht = (struct sta_rec_vht *)(buf + buf_len);
+ buf_len += sizeof(*sta_vht);
+ sta_vht->tag = cpu_to_le16(STA_REC_VHT);
+ sta_vht->len = cpu_to_le16(sizeof(*sta_vht));
+ sta_vht->vht_cap = cpu_to_le32(sta->vht_cap.cap);
+ sta_vht->vht_rx_mcs_map = sta->vht_cap.vht_mcs.rx_mcs_map;
+ sta_vht->vht_tx_mcs_map = sta->vht_cap.vht_mcs.tx_mcs_map;
}
- ret = __mt7615_mcu_set_sta_rec(dev, mvif->idx, msta->wcid.idx,
- mvif->omac_idx, buf, buf_len);
+ ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_STA_REC_UPDATE,
+ buf, buf_len, true);
+out:
kfree(buf);
+
return ret;
}
@@ -1470,98 +1409,128 @@ int mt7615_mcu_set_tx_ba(struct mt7615_dev *dev,
struct ieee80211_ampdu_params *params,
bool add)
{
- struct ieee80211_sta *sta = params->sta;
- struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
+ struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv;
struct mt7615_vif *mvif = msta->vif;
- u8 ba_range[8] = {4, 8, 12, 24, 36, 48, 54, 64};
- u16 tid = params->tid;
- u16 ba_size = params->buf_size;
- u16 ssn = params->ssn;
- struct wtbl_ba wtbl_ba = {0};
- struct sta_rec_ba sta_rec_ba = {0};
- int ret, buf_len;
-
- buf_len = sizeof(struct wtbl_ba);
-
- wtbl_ba.tag = cpu_to_le16(WTBL_BA);
- wtbl_ba.len = cpu_to_le16(buf_len);
- wtbl_ba.tid = tid;
- wtbl_ba.ba_type = MT_BA_TYPE_ORIGINATOR;
+ struct {
+ struct wtbl_req_hdr hdr;
+ struct wtbl_ba ba;
+ } wtbl_req = {
+ .hdr = {
+ .wlan_idx = msta->wcid.idx,
+ .operation = WTBL_SET,
+ .tlv_num = cpu_to_le16(1),
+ },
+ .ba = {
+ .tag = cpu_to_le16(WTBL_BA),
+ .len = cpu_to_le16(sizeof(struct wtbl_ba)),
+ .tid = params->tid,
+ .ba_type = MT_BA_TYPE_ORIGINATOR,
+ .sn = add ? cpu_to_le16(params->ssn) : 0,
+ .ba_en = add,
+ },
+ };
+ struct {
+ struct sta_req_hdr hdr;
+ struct sta_rec_ba ba;
+ } sta_req = {
+ .hdr = {
+ .bss_idx = mvif->idx,
+ .wlan_idx = msta->wcid.idx,
+ .tlv_num = cpu_to_le16(1),
+ .is_tlv_append = 1,
+ .muar_idx = mvif->omac_idx,
+ },
+ .ba = {
+ .tag = cpu_to_le16(STA_REC_BA),
+ .len = cpu_to_le16(sizeof(struct sta_rec_ba)),
+ .tid = params->tid,
+ .ba_type = MT_BA_TYPE_ORIGINATOR,
+ .amsdu = params->amsdu,
+ .ba_en = add << params->tid,
+ .ssn = cpu_to_le16(params->ssn),
+ .winsize = cpu_to_le16(params->buf_size),
+ },
+ };
+ int ret;
if (add) {
- u8 idx;
+ u8 idx, ba_range[] = { 4, 8, 12, 24, 36, 48, 54, 64 };
for (idx = 7; idx > 0; idx--) {
- if (ba_size >= ba_range[idx])
+ if (params->buf_size >= ba_range[idx])
break;
}
- wtbl_ba.sn = cpu_to_le16(ssn);
- wtbl_ba.ba_en = 1;
- wtbl_ba.ba_winsize_idx = idx;
+ wtbl_req.ba.ba_winsize_idx = idx;
}
- ret = __mt7615_mcu_set_wtbl(dev, msta->wcid.idx, WTBL_SET, &wtbl_ba,
- buf_len);
+ ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_WTBL_UPDATE,
+ &wtbl_req, sizeof(wtbl_req), true);
if (ret)
return ret;
- buf_len = sizeof(struct sta_rec_ba);
-
- sta_rec_ba.tag = cpu_to_le16(STA_REC_BA);
- sta_rec_ba.len = cpu_to_le16(buf_len);
- sta_rec_ba.tid = tid;
- sta_rec_ba.ba_type = MT_BA_TYPE_ORIGINATOR;
- sta_rec_ba.amsdu = params->amsdu;
- sta_rec_ba.ba_en = add << tid;
- sta_rec_ba.ssn = cpu_to_le16(ssn);
- sta_rec_ba.winsize = cpu_to_le16(ba_size);
-
- return __mt7615_mcu_set_sta_rec(dev, mvif->idx, msta->wcid.idx,
- mvif->omac_idx, &sta_rec_ba, buf_len);
+ return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_STA_REC_UPDATE,
+ &sta_req, sizeof(sta_req), true);
}
int mt7615_mcu_set_rx_ba(struct mt7615_dev *dev,
struct ieee80211_ampdu_params *params,
bool add)
{
- struct ieee80211_sta *sta = params->sta;
- struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
+ struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv;
struct mt7615_vif *mvif = msta->vif;
- u16 tid = params->tid;
- struct wtbl_ba wtbl_ba = {0};
- struct sta_rec_ba sta_rec_ba = {0};
- int ret, buf_len;
-
- buf_len = sizeof(struct sta_rec_ba);
-
- sta_rec_ba.tag = cpu_to_le16(STA_REC_BA);
- sta_rec_ba.len = cpu_to_le16(buf_len);
- sta_rec_ba.tid = tid;
- sta_rec_ba.ba_type = MT_BA_TYPE_RECIPIENT;
- sta_rec_ba.amsdu = params->amsdu;
- sta_rec_ba.ba_en = add << tid;
- sta_rec_ba.ssn = cpu_to_le16(params->ssn);
- sta_rec_ba.winsize = cpu_to_le16(params->buf_size);
-
- ret = __mt7615_mcu_set_sta_rec(dev, mvif->idx, msta->wcid.idx,
- mvif->omac_idx, &sta_rec_ba, buf_len);
- if (ret || !add)
- return ret;
+ struct {
+ struct wtbl_req_hdr hdr;
+ struct wtbl_ba ba;
+ } wtbl_req = {
+ .hdr = {
+ .wlan_idx = msta->wcid.idx,
+ .operation = WTBL_SET,
+ .tlv_num = cpu_to_le16(1),
+ },
+ .ba = {
+ .tag = cpu_to_le16(WTBL_BA),
+ .len = cpu_to_le16(sizeof(struct wtbl_ba)),
+ .tid = params->tid,
+ .ba_type = MT_BA_TYPE_RECIPIENT,
+ .rst_ba_tid = params->tid,
+ .rst_ba_sel = RST_BA_MAC_TID_MATCH,
+ .rst_ba_sb = 1,
+ },
+ };
+ struct {
+ struct sta_req_hdr hdr;
+ struct sta_rec_ba ba;
+ } sta_req = {
+ .hdr = {
+ .bss_idx = mvif->idx,
+ .wlan_idx = msta->wcid.idx,
+ .tlv_num = cpu_to_le16(1),
+ .is_tlv_append = 1,
+ .muar_idx = mvif->omac_idx,
+ },
+ .ba = {
+ .tag = cpu_to_le16(STA_REC_BA),
+ .len = cpu_to_le16(sizeof(struct sta_rec_ba)),
+ .tid = params->tid,
+ .ba_type = MT_BA_TYPE_RECIPIENT,
+ .amsdu = params->amsdu,
+ .ba_en = add << params->tid,
+ .ssn = cpu_to_le16(params->ssn),
+ .winsize = cpu_to_le16(params->buf_size),
+ },
+ };
+ int ret;
- buf_len = sizeof(struct wtbl_ba);
+ memcpy(wtbl_req.ba.peer_addr, params->sta->addr, ETH_ALEN);
- wtbl_ba.tag = cpu_to_le16(WTBL_BA);
- wtbl_ba.len = cpu_to_le16(buf_len);
- wtbl_ba.tid = tid;
- wtbl_ba.ba_type = MT_BA_TYPE_RECIPIENT;
- memcpy(wtbl_ba.peer_addr, sta->addr, ETH_ALEN);
- wtbl_ba.rst_ba_tid = tid;
- wtbl_ba.rst_ba_sel = RST_BA_MAC_TID_MATCH;
- wtbl_ba.rst_ba_sb = 1;
+ ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_STA_REC_UPDATE,
+ &sta_req, sizeof(sta_req), true);
+ if (ret || !add)
+ return ret;
- return __mt7615_mcu_set_wtbl(dev, msta->wcid.idx, WTBL_SET,
- &wtbl_ba, buf_len);
+ return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_WTBL_UPDATE,
+ &wtbl_req, sizeof(wtbl_req), true);
}
void mt7615_mcu_set_rates(struct mt7615_dev *dev, struct mt7615_sta *sta,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h
index 9455f8fa475d..f8b51ad25220 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h
@@ -70,6 +70,7 @@ enum {
enum {
MCU_EXT_CMD_PM_STATE_CTRL = 0x07,
MCU_EXT_CMD_CHANNEL_SWITCH = 0x08,
+ MCU_EXT_CMD_SET_TX_POWER_CTRL = 0x11,
MCU_EXT_CMD_EFUSE_BUFFER_MODE = 0x21,
MCU_EXT_CMD_STA_REC_UPDATE = 0x25,
MCU_EXT_CMD_BSS_INFO_UPDATE = 0x26,
@@ -105,25 +106,19 @@ enum {
#define STA_TYPE_STA BIT(0)
#define STA_TYPE_AP BIT(1)
#define STA_TYPE_ADHOC BIT(2)
-#define STA_TYPE_TDLS BIT(3)
#define STA_TYPE_WDS BIT(4)
#define STA_TYPE_BC BIT(5)
#define NETWORK_INFRA BIT(16)
#define NETWORK_P2P BIT(17)
#define NETWORK_IBSS BIT(18)
-#define NETWORK_MESH BIT(19)
-#define NETWORK_BOW BIT(20)
#define NETWORK_WDS BIT(21)
#define CONNECTION_INFRA_STA (STA_TYPE_STA | NETWORK_INFRA)
#define CONNECTION_INFRA_AP (STA_TYPE_AP | NETWORK_INFRA)
#define CONNECTION_P2P_GC (STA_TYPE_STA | NETWORK_P2P)
#define CONNECTION_P2P_GO (STA_TYPE_AP | NETWORK_P2P)
-#define CONNECTION_MESH_STA (STA_TYPE_STA | NETWORK_MESH)
-#define CONNECTION_MESH_AP (STA_TYPE_AP | NETWORK_MESH)
#define CONNECTION_IBSS_ADHOC (STA_TYPE_ADHOC | NETWORK_IBSS)
-#define CONNECTION_TDLS (STA_TYPE_STA | NETWORK_INFRA | STA_TYPE_TDLS)
#define CONNECTION_WDS (STA_TYPE_WDS | NETWORK_WDS)
#define CONNECTION_INFRA_BC (STA_TYPE_BC | NETWORK_INFRA)
@@ -131,41 +126,11 @@ enum {
#define CONN_STATE_CONNECT 1
#define CONN_STATE_PORT_SECURE 2
-struct dev_info {
- u8 omac_idx;
- u8 omac_addr[ETH_ALEN];
- u8 band_idx;
- u8 enable;
- u32 feature;
-};
-
enum {
DEV_INFO_ACTIVE,
DEV_INFO_MAX_NUM
};
-struct bss_info {
- u8 bss_idx;
- u8 bssid[ETH_ALEN];
- u8 omac_idx;
- u8 band_idx;
- u8 bmc_tx_wlan_idx; /* for bmc tx (sta mode use uc entry) */
- u8 wmm_idx;
- u32 network_type;
- u32 conn_type;
- u16 bcn_interval;
- u8 dtim_period;
- u8 enable;
- u32 feature;
-};
-
-struct bss_info_tag_handler {
- u32 tag;
- u32 len;
- void (*handler)(struct mt7615_dev *dev,
- struct bss_info *bss_info, struct sk_buff *skb);
-};
-
struct bss_info_omac {
__le16 tag;
__le16 len;
@@ -231,6 +196,13 @@ enum {
WTBL_RESET_ALL
};
+struct wtbl_req_hdr {
+ u8 wlan_idx;
+ u8 operation;
+ __le16 tlv_num;
+ u8 rsv[4];
+} __packed;
+
struct wtbl_generic {
__le16 tag;
__le16 len;
@@ -396,7 +368,8 @@ struct wtbl_raw {
__le32 val;
} __packed;
-#define MT7615_WTBL_UPDATE_MAX_SIZE (sizeof(struct wtbl_generic) + \
+#define MT7615_WTBL_UPDATE_MAX_SIZE (sizeof(struct wtbl_req_hdr) + \
+ sizeof(struct wtbl_generic) + \
sizeof(struct wtbl_rx) + \
sizeof(struct wtbl_ht) + \
sizeof(struct wtbl_vht) + \
@@ -430,6 +403,15 @@ enum {
WTBL_MAX_NUM
};
+struct sta_req_hdr {
+ u8 bss_idx;
+ u8 wlan_idx;
+ __le16 tlv_num;
+ u8 is_tlv_append;
+ u8 muar_idx;
+ u8 rsv[2];
+} __packed;
+
struct sta_rec_basic {
__le16 tag;
__le16 len;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
index 895c2904d7eb..f02ffcffe637 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
@@ -105,11 +105,14 @@ u32 mt7615_reg_map(struct mt7615_dev *dev, u32 addr);
int mt7615_register_device(struct mt7615_dev *dev);
void mt7615_unregister_device(struct mt7615_dev *dev);
int mt7615_eeprom_init(struct mt7615_dev *dev);
+int mt7615_eeprom_get_power_index(struct mt7615_dev *dev,
+ struct ieee80211_channel *chan,
+ u8 chain_idx);
int mt7615_dma_init(struct mt7615_dev *dev);
void mt7615_dma_cleanup(struct mt7615_dev *dev);
int mt7615_mcu_init(struct mt7615_dev *dev);
-int mt7615_mcu_set_dev_info(struct mt7615_dev *dev, struct ieee80211_vif *vif,
- int en);
+int mt7615_mcu_set_dev_info(struct mt7615_dev *dev,
+ struct ieee80211_vif *vif, bool enable);
int mt7615_mcu_set_bss_info(struct mt7615_dev *dev, struct ieee80211_vif *vif,
int en);
int mt7615_mcu_set_wtbl_key(struct mt7615_dev *dev, int wcid,
@@ -118,12 +121,11 @@ int mt7615_mcu_set_wtbl_key(struct mt7615_dev *dev, int wcid,
void mt7615_mcu_set_rates(struct mt7615_dev *dev, struct mt7615_sta *sta,
struct ieee80211_tx_rate *probe_rate,
struct ieee80211_tx_rate *rates);
-int mt7615_mcu_add_wtbl_bmc(struct mt7615_dev *dev, struct ieee80211_vif *vif);
-int mt7615_mcu_del_wtbl_bmc(struct mt7615_dev *dev, struct ieee80211_vif *vif);
+int mt7615_mcu_wtbl_bmc(struct mt7615_dev *dev, struct ieee80211_vif *vif,
+ bool enable);
int mt7615_mcu_add_wtbl(struct mt7615_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
-int mt7615_mcu_del_wtbl(struct mt7615_dev *dev, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta);
+int mt7615_mcu_del_wtbl(struct mt7615_dev *dev, struct ieee80211_sta *sta);
int mt7615_mcu_del_wtbl_all(struct mt7615_dev *dev);
int mt7615_mcu_set_sta_rec_bmc(struct mt7615_dev *dev,
struct ieee80211_vif *vif, bool en);
@@ -168,6 +170,7 @@ int mt7615_mcu_set_eeprom(struct mt7615_dev *dev);
int mt7615_mcu_init_mac(struct mt7615_dev *dev);
int mt7615_mcu_set_rts_thresh(struct mt7615_dev *dev, u32 val);
int mt7615_mcu_ctrl_pm_state(struct mt7615_dev *dev, int enter);
+int mt7615_mcu_set_tx_power(struct mt7615_dev *dev);
void mt7615_mcu_exit(struct mt7615_dev *dev);
int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
@@ -180,7 +183,6 @@ void mt7615_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
struct sk_buff *skb);
-void mt7615_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q);
void mt7615_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps);
int mt7615_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c
index 11122bd2d727..9e82cb53fd60 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c
@@ -27,14 +27,15 @@ u32 mt7615_reg_map(struct mt7615_dev *dev, u32 addr)
return MT_PCIE_REMAP_BASE_2 + offset;
}
-void mt7615_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q)
+static void
+mt7615_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q)
{
struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
mt7615_irq_enable(dev, MT_INT_RX_DONE(q));
}
-irqreturn_t mt7615_irq_handler(int irq, void *dev_instance)
+static irqreturn_t mt7615_irq_handler(int irq, void *dev_instance)
{
struct mt7615_dev *dev = dev_instance;
u32 intr;
@@ -49,7 +50,7 @@ irqreturn_t mt7615_irq_handler(int irq, void *dev_instance)
if (intr & MT_INT_TX_DONE_ALL) {
mt7615_irq_disable(dev, MT_INT_TX_DONE_ALL);
- tasklet_schedule(&dev->mt76.tx_tasklet);
+ napi_schedule(&dev->mt76.tx_napi);
}
if (intr & MT_INT_RX_DONE(0)) {
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c
index 71237d5cdf7f..cf7fc307322b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c
@@ -271,8 +271,9 @@ mt76x0_init_txpower(struct mt76x02_dev *dev,
mt76x0_get_tx_power_per_rate(dev, chan, &t);
mt76x0_get_power_info(dev, chan, &tp);
- chan->max_power = (mt76x02_get_max_rate_power(&t) + tp) / 2;
- chan->orig_mpwr = chan->max_power;
+ chan->orig_mpwr = (mt76x02_get_max_rate_power(&t) + tp) / 2;
+ chan->max_power = min_t(int, chan->max_reg_power,
+ chan->orig_mpwr);
}
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c
index a7f335d6e8f8..d7bf7bc15e52 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c
@@ -25,7 +25,7 @@ mt76x0_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef)
mt76_rr(dev, MT_CH_IDLE);
mt76_rr(dev, MT_CH_BUSY);
- mt76x02_edcca_init(dev, true);
+ mt76x02_edcca_init(dev);
if (mt76_is_mmio(dev)) {
mt76x02_dfs_init_params(dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c
index e11da6900222..1ecfc334ae79 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c
@@ -422,15 +422,15 @@ mt76x0_phy_set_chan_bbp_params(struct mt76x02_dev *dev, u16 rf_bw_band)
static void mt76x0_phy_ant_select(struct mt76x02_dev *dev)
{
u16 ee_ant = mt76x02_eeprom_get(dev, MT_EE_ANTENNA);
+ u16 ee_cfg1 = mt76x02_eeprom_get(dev, MT_EE_CFG1_INIT);
u16 nic_conf2 = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_2);
- u32 wlan, coex3, cmb;
+ u32 wlan, coex3;
bool ant_div;
wlan = mt76_rr(dev, MT_WLAN_FUN_CTRL);
- cmb = mt76_rr(dev, MT_CMB_CTRL);
coex3 = mt76_rr(dev, MT_COEXCFG3);
- cmb &= ~(BIT(14) | BIT(12));
+ ee_ant &= ~(BIT(14) | BIT(12));
wlan &= ~(BIT(6) | BIT(5));
coex3 &= ~GENMASK(5, 2);
@@ -439,7 +439,7 @@ static void mt76x0_phy_ant_select(struct mt76x02_dev *dev)
ant_div = !(nic_conf2 & MT_EE_NIC_CONF_2_ANT_OPT) &&
(nic_conf2 & MT_EE_NIC_CONF_2_ANT_DIV);
if (ant_div)
- cmb |= BIT(12);
+ ee_ant |= BIT(12);
else
coex3 |= BIT(4);
coex3 |= BIT(3);
@@ -456,10 +456,11 @@ static void mt76x0_phy_ant_select(struct mt76x02_dev *dev)
}
if (is_mt7630(dev))
- cmb |= BIT(14) | BIT(11);
+ ee_ant |= BIT(14) | BIT(11);
mt76_wr(dev, MT_WLAN_FUN_CTRL, wlan);
- mt76_wr(dev, MT_CMB_CTRL, cmb);
+ mt76_rmw(dev, MT_CMB_CTRL, GENMASK(15, 0), ee_ant);
+ mt76_rmw(dev, MT_CSR_EE_CFG1, GENMASK(15, 0), ee_cfg1);
mt76_clear(dev, MT_COEXCFG0, BIT(2));
mt76_wr(dev, MT_COEXCFG3, coex3);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
index 2dc67e68c6a2..627ed1fc7b15 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
@@ -183,7 +183,7 @@ static int mt76x0u_register_device(struct mt76x02_dev *dev)
/* check hw sg support in order to enable AMSDU */
if (dev->mt76.usb.sg_en)
- hw->max_tx_fragments = MT_SG_MAX_SIZE;
+ hw->max_tx_fragments = MT_TX_SG_MAX_SIZE;
else
hw->max_tx_fragments = 1;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h
index 687bd14b2d77..f7fd53a1738a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h
@@ -90,7 +90,6 @@ struct mt76x02_dev {
struct sk_buff *rx_head;
- struct napi_struct tx_napi;
struct delayed_work cal_work;
struct delayed_work wdt_work;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
index e196b9c0a686..d61c686e08de 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
@@ -189,10 +189,8 @@ mt76x02_resync_beacon_timer(struct mt76x02_dev *dev)
mt76_rmw_field(dev, MT_BEACON_TIME_CFG,
MT_BEACON_TIME_CFG_INTVAL, timer_val);
- if (dev->tbtt_count >= 64) {
+ if (dev->tbtt_count >= 64)
dev->tbtt_count = 0;
- return;
- }
}
EXPORT_SYMBOL_GPL(mt76x02_resync_beacon_timer);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c
index b1d6fd4861e3..1b1e424ccbb2 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c
@@ -120,12 +120,16 @@ static int
mt76_edcca_set(void *data, u64 val)
{
struct mt76x02_dev *dev = data;
- enum nl80211_dfs_regions region = dev->dfs_pd.region;
+ enum nl80211_dfs_regions region = dev->mt76.region;
+
+ mutex_lock(&dev->mt76.mutex);
dev->ed_monitor_enabled = !!val;
dev->ed_monitor = dev->ed_monitor_enabled &&
region == NL80211_DFS_ETSI;
- mt76x02_edcca_init(dev, true);
+ mt76x02_edcca_init(dev);
+
+ mutex_unlock(&dev->mt76.mutex);
return 0;
}
@@ -153,7 +157,7 @@ void mt76x02_init_debugfs(struct mt76x02_dev *dev)
debugfs_create_u8("temperature", 0400, dir, &dev->cal.temp);
debugfs_create_bool("tpc", 0600, dir, &dev->enable_tpc);
- debugfs_create_file("edcca", 0400, dir, dev, &fops_edcca);
+ debugfs_create_file("edcca", 0600, dir, dev, &fops_edcca);
debugfs_create_file("ampdu_stat", 0400, dir, dev, &fops_ampdu_stat);
debugfs_create_file("dfs_stats", 0400, dir, dev, &fops_dfs_stat);
debugfs_create_devm_seqfile(dev->mt76.dev, "txpower", dir,
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c b/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c
index 17d12d212d1b..50e9b310e496 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c
@@ -283,7 +283,7 @@ static bool mt76x02_dfs_check_hw_pulse(struct mt76x02_dev *dev,
if (!pulse->period || !pulse->w1)
return false;
- switch (dev->dfs_pd.region) {
+ switch (dev->mt76.region) {
case NL80211_DFS_FCC:
if (pulse->engine > 3)
break;
@@ -457,7 +457,7 @@ static int mt76x02_dfs_create_sequence(struct mt76x02_dev *dev,
with_sum = event->width + cur_event->width;
sw_params = &dfs_pd->sw_dpd_params;
- switch (dev->dfs_pd.region) {
+ switch (dev->mt76.region) {
case NL80211_DFS_FCC:
case NL80211_DFS_JP:
if (with_sum < 600)
@@ -685,7 +685,7 @@ static void mt76x02_dfs_init_sw_detector(struct mt76x02_dev *dev)
{
struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
- switch (dev->dfs_pd.region) {
+ switch (dev->mt76.region) {
case NL80211_DFS_FCC:
dfs_pd->sw_dpd_params.max_pri = MT_DFS_FCC_MAX_PRI;
dfs_pd->sw_dpd_params.min_pri = MT_DFS_FCC_MIN_PRI;
@@ -725,7 +725,7 @@ static void mt76x02_dfs_set_bbp_params(struct mt76x02_dev *dev)
break;
}
- switch (dev->dfs_pd.region) {
+ switch (dev->mt76.region) {
case NL80211_DFS_FCC:
radar_specs = &fcc_radar_specs[shift];
break;
@@ -836,7 +836,7 @@ void mt76x02_dfs_init_params(struct mt76x02_dev *dev)
struct cfg80211_chan_def *chandef = &dev->mt76.chandef;
if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) &&
- dev->dfs_pd.region != NL80211_DFS_UNSET) {
+ dev->mt76.region != NL80211_DFS_UNSET) {
mt76x02_dfs_init_sw_detector(dev);
mt76x02_dfs_set_bbp_params(dev);
/* enable debug mode */
@@ -869,7 +869,7 @@ void mt76x02_dfs_init_detector(struct mt76x02_dev *dev)
INIT_LIST_HEAD(&dfs_pd->sequences);
INIT_LIST_HEAD(&dfs_pd->seq_pool);
- dfs_pd->region = NL80211_DFS_UNSET;
+ dev->mt76.region = NL80211_DFS_UNSET;
dfs_pd->last_sw_check = jiffies;
tasklet_init(&dfs_pd->dfs_tasklet, mt76x02_dfs_tasklet,
(unsigned long)dev);
@@ -882,14 +882,14 @@ mt76x02_dfs_set_domain(struct mt76x02_dev *dev,
struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
mutex_lock(&dev->mt76.mutex);
- if (dfs_pd->region != region) {
+ if (dev->mt76.region != region) {
tasklet_disable(&dfs_pd->dfs_tasklet);
dev->ed_monitor = dev->ed_monitor_enabled &&
region == NL80211_DFS_ETSI;
- mt76x02_edcca_init(dev, true);
+ mt76x02_edcca_init(dev);
- dfs_pd->region = region;
+ dev->mt76.region = region;
mt76x02_dfs_init_params(dev);
tasklet_enable(&dfs_pd->dfs_tasklet);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.h b/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.h
index 70b394e17340..0408613b45a4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.h
@@ -118,8 +118,6 @@ struct mt76x02_dfs_seq_stats {
};
struct mt76x02_dfs_pattern_detector {
- enum nl80211_dfs_regions region;
-
u8 chirp_pulse_cnt;
u32 chirp_pulse_ts;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h
index e3442bc4e0a4..0ba536de3d6e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h
@@ -26,6 +26,7 @@ enum mt76x02_eeprom_field {
MT_EE_MAC_ADDR = 0x004,
MT_EE_PCI_ID = 0x00A,
MT_EE_ANTENNA = 0x022,
+ MT_EE_CFG1_INIT = 0x024,
MT_EE_NIC_CONF_0 = 0x034,
MT_EE_NIC_CONF_1 = 0x036,
MT_EE_COUNTRY_REGION_5GHZ = 0x038,
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
index 56510a1a843a..82bafb5ac326 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
@@ -420,30 +420,92 @@ void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi,
EXPORT_SYMBOL_GPL(mt76x02_mac_write_txwi);
static void
-mt76x02_mac_fill_tx_status(struct mt76x02_dev *dev,
+mt76x02_tx_rate_fallback(struct ieee80211_tx_rate *rates, int idx, int phy)
+{
+ u8 mcs, nss;
+
+ if (!idx)
+ return;
+
+ rates += idx - 1;
+ rates[1] = rates[0];
+ switch (phy) {
+ case MT_PHY_TYPE_VHT:
+ mcs = ieee80211_rate_get_vht_mcs(rates);
+ nss = ieee80211_rate_get_vht_nss(rates);
+
+ if (mcs == 0)
+ nss = max_t(int, nss - 1, 1);
+ else
+ mcs--;
+
+ ieee80211_rate_set_vht(rates + 1, mcs, nss);
+ break;
+ case MT_PHY_TYPE_HT_GF:
+ case MT_PHY_TYPE_HT:
+ /* MCS 8 falls back to MCS 0 */
+ if (rates[0].idx == 8) {
+ rates[1].idx = 0;
+ break;
+ }
+ /* fall through */
+ default:
+ rates[1].idx = max_t(int, rates[0].idx - 1, 0);
+ break;
+ }
+}
+
+static void
+mt76x02_mac_fill_tx_status(struct mt76x02_dev *dev, struct mt76x02_sta *msta,
struct ieee80211_tx_info *info,
struct mt76x02_tx_status *st, int n_frames)
{
struct ieee80211_tx_rate *rate = info->status.rates;
- int cur_idx, last_rate;
+ struct ieee80211_tx_rate last_rate;
+ u16 first_rate;
+ int retry = st->retry;
+ int phy;
int i;
if (!n_frames)
return;
- last_rate = min_t(int, st->retry, IEEE80211_TX_MAX_RATES - 1);
- mt76x02_mac_process_tx_rate(&rate[last_rate], st->rate,
+ phy = FIELD_GET(MT_RXWI_RATE_PHY, st->rate);
+
+ if (st->pktid & MT_PACKET_ID_HAS_RATE) {
+ first_rate = st->rate & ~MT_RXWI_RATE_INDEX;
+ first_rate |= st->pktid & MT_RXWI_RATE_INDEX;
+
+ mt76x02_mac_process_tx_rate(&rate[0], first_rate,
+ dev->mt76.chandef.chan->band);
+ } else if (rate[0].idx < 0) {
+ if (!msta)
+ return;
+
+ mt76x02_mac_process_tx_rate(&rate[0], msta->wcid.tx_info,
+ dev->mt76.chandef.chan->band);
+ }
+
+ mt76x02_mac_process_tx_rate(&last_rate, st->rate,
dev->mt76.chandef.chan->band);
- if (last_rate < IEEE80211_TX_MAX_RATES - 1)
- rate[last_rate + 1].idx = -1;
-
- cur_idx = rate[last_rate].idx + last_rate;
- for (i = 0; i <= last_rate; i++) {
- rate[i].flags = rate[last_rate].flags;
- rate[i].idx = max_t(int, 0, cur_idx - i);
- rate[i].count = 1;
+
+ for (i = 0; i < ARRAY_SIZE(info->status.rates); i++) {
+ retry--;
+ if (i + 1 == ARRAY_SIZE(info->status.rates)) {
+ info->status.rates[i] = last_rate;
+ info->status.rates[i].count = max_t(int, retry, 1);
+ break;
+ }
+
+ mt76x02_tx_rate_fallback(info->status.rates, i, phy);
+ if (info->status.rates[i].idx == last_rate.idx)
+ break;
+ }
+
+ if (i + 1 < ARRAY_SIZE(info->status.rates)) {
+ info->status.rates[i + 1].idx = -1;
+ info->status.rates[i + 1].count = 0;
}
- rate[last_rate].count = st->retry + 1 - last_rate;
info->status.ampdu_len = n_frames;
info->status.ampdu_ack_len = st->success ? n_frames : 0;
@@ -489,13 +551,19 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev,
mt76_tx_status_lock(mdev, &list);
if (wcid) {
- if (stat->pktid >= MT_PACKET_ID_FIRST)
+ if (mt76_is_skb_pktid(stat->pktid))
status.skb = mt76_tx_status_skb_get(mdev, wcid,
stat->pktid, &list);
if (status.skb)
status.info = IEEE80211_SKB_CB(status.skb);
}
+ if (!status.skb && !(stat->pktid & MT_PACKET_ID_HAS_RATE)) {
+ mt76_tx_status_unlock(mdev, &list);
+ rcu_read_unlock();
+ return;
+ }
+
if (msta && stat->aggr && !status.skb) {
u32 stat_val, stat_cache;
@@ -512,14 +580,14 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev,
return;
}
- mt76x02_mac_fill_tx_status(dev, status.info, &msta->status,
- msta->n_frames);
+ mt76x02_mac_fill_tx_status(dev, msta, status.info,
+ &msta->status, msta->n_frames);
msta->status = *stat;
msta->n_frames = 1;
*update = 0;
} else {
- mt76x02_mac_fill_tx_status(dev, status.info, stat, 1);
+ mt76x02_mac_fill_tx_status(dev, msta, status.info, stat, 1);
*update = 1;
}
@@ -945,12 +1013,12 @@ mt76x02_edcca_tx_enable(struct mt76x02_dev *dev, bool enable)
dev->ed_tx_blocked = !enable;
}
-void mt76x02_edcca_init(struct mt76x02_dev *dev, bool enable)
+void mt76x02_edcca_init(struct mt76x02_dev *dev)
{
dev->ed_trigger = 0;
dev->ed_silent = 0;
- if (dev->ed_monitor && enable) {
+ if (dev->ed_monitor) {
struct ieee80211_channel *chan = dev->mt76.chandef.chan;
u8 ed_th = chan->band == NL80211_BAND_5GHZ ? 0x0e : 0x20;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h
index e4a9e0d0924b..cb39da79527a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h
@@ -209,5 +209,5 @@ int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx,
void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev,
struct ieee80211_vif *vif, bool val);
-void mt76x02_edcca_init(struct mt76x02_dev *dev, bool enable);
+void mt76x02_edcca_init(struct mt76x02_dev *dev);
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
index 7b7163bc3b62..467b28379870 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
@@ -166,7 +166,8 @@ static void mt76x02_tx_tasklet(unsigned long data)
static int mt76x02_poll_tx(struct napi_struct *napi, int budget)
{
- struct mt76x02_dev *dev = container_of(napi, struct mt76x02_dev, tx_napi);
+ struct mt76x02_dev *dev = container_of(napi, struct mt76x02_dev,
+ mt76.tx_napi);
int i;
mt76x02_mac_poll_tx_status(dev, false);
@@ -245,9 +246,9 @@ int mt76x02_dma_init(struct mt76x02_dev *dev)
if (ret)
return ret;
- netif_tx_napi_add(&dev->mt76.napi_dev, &dev->tx_napi, mt76x02_poll_tx,
- NAPI_POLL_WEIGHT);
- napi_enable(&dev->tx_napi);
+ netif_tx_napi_add(&dev->mt76.napi_dev, &dev->mt76.tx_napi,
+ mt76x02_poll_tx, NAPI_POLL_WEIGHT);
+ napi_enable(&dev->mt76.tx_napi);
return 0;
}
@@ -303,7 +304,7 @@ irqreturn_t mt76x02_irq_handler(int irq, void *dev_instance)
if (intr & (MT_INT_TX_STAT | MT_INT_TX_DONE_ALL)) {
mt76x02_irq_disable(dev, MT_INT_TX_DONE_ALL);
- napi_schedule(&dev->tx_napi);
+ napi_schedule(&dev->mt76.tx_napi);
}
if (intr & MT_INT_GPTIMER) {
@@ -334,7 +335,6 @@ static void mt76x02_dma_enable(struct mt76x02_dev *dev)
void mt76x02_dma_cleanup(struct mt76x02_dev *dev)
{
tasklet_kill(&dev->mt76.tx_tasklet);
- netif_napi_del(&dev->tx_napi);
mt76_dma_cleanup(&dev->mt76);
}
EXPORT_SYMBOL_GPL(mt76x02_dma_cleanup);
@@ -454,7 +454,7 @@ static void mt76x02_watchdog_reset(struct mt76x02_dev *dev)
tasklet_disable(&dev->mt76.pre_tbtt_tasklet);
tasklet_disable(&dev->mt76.tx_tasklet);
- napi_disable(&dev->tx_napi);
+ napi_disable(&dev->mt76.tx_napi);
for (i = 0; i < ARRAY_SIZE(dev->mt76.napi); i++)
napi_disable(&dev->mt76.napi[i]);
@@ -508,8 +508,8 @@ static void mt76x02_watchdog_reset(struct mt76x02_dev *dev)
clear_bit(MT76_RESET, &dev->mt76.state);
tasklet_enable(&dev->mt76.tx_tasklet);
- napi_enable(&dev->tx_napi);
- napi_schedule(&dev->tx_napi);
+ napi_enable(&dev->mt76.tx_napi);
+ napi_schedule(&dev->mt76.tx_napi);
tasklet_enable(&dev->mt76.pre_tbtt_tasklet);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h b/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h
index 2ce05b543dff..ea7833964ec0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h
@@ -66,6 +66,9 @@
#define MT_WLAN_FUN_CTRL_GPIO_OUT GENMASK(23, 16) /* MT76x0 */
#define MT_WLAN_FUN_CTRL_GPIO_OUT_EN GENMASK(31, 24) /* MT76x0 */
+/* MT76x0 */
+#define MT_CSR_EE_CFG1 0x0104
+
#define MT_XO_CTRL0 0x0100
#define MT_XO_CTRL1 0x0104
#define MT_XO_CTRL2 0x0108
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c
index cf7abd9b7d2e..04118f08debc 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c
@@ -154,6 +154,7 @@ int mt76x02_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx_info->skb->data;
struct mt76x02_txwi *txwi = txwi_ptr;
+ bool ampdu = IEEE80211_SKB_CB(tx_info->skb)->flags & IEEE80211_TX_CTL_AMPDU;
int hdrlen, len, pid, qsel = MT_QSEL_EDCA;
if (qid == MT_TXQ_PSD && wcid && wcid->idx < 128)
@@ -164,9 +165,15 @@ int mt76x02_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
mt76x02_mac_write_txwi(dev, txwi, tx_info->skb, wcid, sta, len);
pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
+
+ /* encode packet rate for no-skb packet id to fix up status reporting */
+ if (pid == MT_PACKET_ID_NO_SKB)
+ pid = MT_PACKET_ID_HAS_RATE |
+ (le16_to_cpu(txwi->rate) & MT_RXWI_RATE_INDEX);
+
txwi->pktid = pid;
- if (pid >= MT_PACKET_ID_FIRST)
+ if (mt76_is_skb_pktid(pid) && ampdu)
qsel = MT_QSEL_MGMT;
tx_info->info = FIELD_PREP(MT_TXD_INFO_QSEL, qsel) |
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
index 6b89f7eab26c..e4332d5a5757 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
@@ -14,7 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include "mt76x02.h"
+#include "mt76x02_usb.h"
static void mt76x02u_remove_dma_hdr(struct sk_buff *skb)
{
@@ -53,7 +53,7 @@ int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags)
pad = round_up(skb->len, 4) + 4 - skb->len;
/* First packet of a A-MSDU burst keeps track of the whole burst
- * length, need to update lenght of it and the last packet.
+ * length, need to update length of it and the last packet.
*/
skb_walk_frags(skb, iter) {
last = iter;
@@ -79,6 +79,7 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
int pid, len = tx_info->skb->len, ep = q2ep(mdev->q_tx[qid].q->hw_idx);
struct mt76x02_txwi *txwi;
+ bool ampdu = IEEE80211_SKB_CB(tx_info->skb)->flags & IEEE80211_TX_CTL_AMPDU;
enum mt76_qsel qsel;
u32 flags;
@@ -89,9 +90,15 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
skb_push(tx_info->skb, sizeof(*txwi));
pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
+
+ /* encode packet rate for no-skb packet id to fix up status reporting */
+ if (pid == MT_PACKET_ID_NO_SKB)
+ pid = MT_PACKET_ID_HAS_RATE |
+ (le16_to_cpu(txwi->rate) & MT_RXWI_RATE_INDEX);
+
txwi->pktid = pid;
- if (pid >= MT_PACKET_ID_FIRST || ep == MT_EP_OUT_HCCA)
+ if ((mt76_is_skb_pktid(pid) && ampdu) || ep == MT_EP_OUT_HCCA)
qsel = MT_QSEL_MGMT;
else
qsel = MT_QSEL_EDCA;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/init.c
index c6078e90ca43..97c3543eed8a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/init.c
@@ -173,13 +173,14 @@ void mt76x2_init_txpower(struct mt76x02_dev *dev,
mt76x2_get_power_info(dev, &txp, chan);
mt76x2_get_rate_power(dev, &t, chan);
- chan->max_power = mt76x02_get_max_rate_power(&t) +
+ chan->orig_mpwr = mt76x02_get_max_rate_power(&t) +
txp.target_power;
- chan->max_power = DIV_ROUND_UP(chan->max_power, 2);
+ chan->orig_mpwr = DIV_ROUND_UP(chan->orig_mpwr, 2);
/* convert to combined output power on 2x2 devices */
- chan->max_power += 3;
- chan->orig_mpwr = chan->max_power;
+ chan->orig_mpwr += 3;
+ chan->max_power = min_t(int, chan->max_reg_power,
+ chan->orig_mpwr);
}
}
EXPORT_SYMBOL_GPL(mt76x2_init_txpower);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c
index e416eee6a306..3a1467326f4d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c
@@ -54,14 +54,14 @@ mt76x2_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef)
int ret;
cancel_delayed_work_sync(&dev->cal_work);
+ tasklet_disable(&dev->mt76.pre_tbtt_tasklet);
+ tasklet_disable(&dev->dfs_pd.dfs_tasklet);
+ mutex_lock(&dev->mt76.mutex);
set_bit(MT76_RESET, &dev->mt76.state);
mt76_set_channel(&dev->mt76);
- tasklet_disable(&dev->mt76.pre_tbtt_tasklet);
- tasklet_disable(&dev->dfs_pd.dfs_tasklet);
-
mt76x2_mac_stop(dev, true);
ret = mt76x2_phy_set_channel(dev, chandef);
@@ -72,10 +72,12 @@ mt76x2_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef)
mt76x02_dfs_init_params(dev);
mt76x2_mac_resume(dev);
- tasklet_enable(&dev->dfs_pd.dfs_tasklet);
- tasklet_enable(&dev->mt76.pre_tbtt_tasklet);
clear_bit(MT76_RESET, &dev->mt76.state);
+ mutex_unlock(&dev->mt76.mutex);
+
+ tasklet_enable(&dev->dfs_pd.dfs_tasklet);
+ tasklet_enable(&dev->mt76.pre_tbtt_tasklet);
mt76_txq_schedule_all(&dev->mt76);
@@ -111,14 +113,14 @@ mt76x2_config(struct ieee80211_hw *hw, u32 changed)
}
}
+ mutex_unlock(&dev->mt76.mutex);
+
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
ieee80211_stop_queues(hw);
ret = mt76x2_set_channel(dev, &hw->conf.chandef);
ieee80211_wake_queues(hw);
}
- mutex_unlock(&dev->mt76.mutex);
-
return ret;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c
index cc1aebcb0696..2edf1bd0c18c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c
@@ -74,7 +74,7 @@ mt76x2_phy_channel_calibrate(struct mt76x02_dev *dev, bool mac_stopped)
mt76x2_mac_resume(dev);
mt76x2_apply_gain_adj(dev);
- mt76x02_edcca_init(dev, true);
+ mt76x02_edcca_init(dev);
dev->cal.channel_cal_done = true;
}
@@ -294,10 +294,16 @@ void mt76x2_phy_calibrate(struct work_struct *work)
struct mt76x02_dev *dev;
dev = container_of(work, struct mt76x02_dev, cal_work.work);
+
+ mutex_lock(&dev->mt76.mutex);
+
mt76x2_phy_channel_calibrate(dev, false);
mt76x2_phy_tssi_compensate(dev);
mt76x2_phy_temp_compensate(dev);
mt76x2_phy_update_channel_gain(dev);
+
+ mutex_unlock(&dev->mt76.mutex);
+
ieee80211_queue_delayed_work(mt76_hw(dev), &dev->cal_work,
MT_CALIBRATE_INTERVAL);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c
index f2c57d5b87f9..94f52f98019b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c
@@ -225,7 +225,7 @@ int mt76x2u_register_device(struct mt76x02_dev *dev)
/* check hw sg support in order to enable AMSDU */
if (dev->mt76.usb.sg_en)
- hw->max_tx_fragments = MT_SG_MAX_SIZE;
+ hw->max_tx_fragments = MT_TX_SG_MAX_SIZE;
else
hw->max_tx_fragments = 1;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c
index 97bcf6494ec1..e4dfc3bea3c5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c
@@ -48,22 +48,23 @@ mt76x2u_set_channel(struct mt76x02_dev *dev,
int err;
cancel_delayed_work_sync(&dev->cal_work);
+ dev->beacon_ops->pre_tbtt_enable(dev, false);
+
+ mutex_lock(&dev->mt76.mutex);
set_bit(MT76_RESET, &dev->mt76.state);
mt76_set_channel(&dev->mt76);
- dev->beacon_ops->pre_tbtt_enable(dev, false);
-
mt76x2_mac_stop(dev, false);
err = mt76x2u_phy_set_channel(dev, chandef);
mt76x2_mac_resume(dev);
- mt76x02_edcca_init(dev, true);
-
- dev->beacon_ops->pre_tbtt_enable(dev, true);
clear_bit(MT76_RESET, &dev->mt76.state);
+ mutex_unlock(&dev->mt76.mutex);
+
+ dev->beacon_ops->pre_tbtt_enable(dev, true);
mt76_txq_schedule_all(&dev->mt76);
return err;
@@ -85,12 +86,6 @@ mt76x2u_config(struct ieee80211_hw *hw, u32 changed)
mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
}
- if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
- ieee80211_stop_queues(hw);
- err = mt76x2u_set_channel(dev, &hw->conf.chandef);
- ieee80211_wake_queues(hw);
- }
-
if (changed & IEEE80211_CONF_CHANGE_POWER) {
dev->mt76.txpower_conf = hw->conf.power_level * 2;
@@ -103,6 +98,12 @@ mt76x2u_config(struct ieee80211_hw *hw, u32 changed)
mutex_unlock(&dev->mt76.mutex);
+ if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+ ieee80211_stop_queues(hw);
+ err = mt76x2u_set_channel(dev, &hw->conf.chandef);
+ ieee80211_wake_queues(hw);
+ }
+
return err;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c
index 07f67cb6854c..dfd54f9b0e97 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c
@@ -45,7 +45,7 @@ mt76x2u_phy_channel_calibrate(struct mt76x02_dev *dev, bool mac_stopped)
if (!mac_stopped)
mt76x2_mac_resume(dev);
mt76x2_apply_gain_adj(dev);
- mt76x02_edcca_init(dev, true);
+ mt76x02_edcca_init(dev);
dev->cal.channel_cal_done = true;
}
@@ -55,10 +55,15 @@ void mt76x2u_phy_calibrate(struct work_struct *work)
struct mt76x02_dev *dev;
dev = container_of(work, struct mt76x02_dev, cal_work.work);
+
+ mutex_lock(&dev->mt76.mutex);
+
mt76x2u_phy_channel_calibrate(dev, false);
mt76x2_phy_tssi_compensate(dev);
mt76x2_phy_update_channel_gain(dev);
+ mutex_unlock(&dev->mt76.mutex);
+
ieee80211_queue_delayed_work(mt76_hw(dev), &dev->cal_work,
MT_CALIBRATE_INTERVAL);
}
diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c
index bbaa1365bbda..fb87ce7fbdf6 100644
--- a/drivers/net/wireless/mediatek/mt76/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/usb.c
@@ -267,12 +267,10 @@ mt76u_set_endpoints(struct usb_interface *intf,
if (usb_endpoint_is_bulk_in(ep_desc) &&
in_ep < __MT_EP_IN_MAX) {
usb->in_ep[in_ep] = usb_endpoint_num(ep_desc);
- usb->in_max_packet = usb_endpoint_maxp(ep_desc);
in_ep++;
} else if (usb_endpoint_is_bulk_out(ep_desc) &&
out_ep < __MT_EP_OUT_MAX) {
usb->out_ep[out_ep] = usb_endpoint_num(ep_desc);
- usb->out_max_packet = usb_endpoint_maxp(ep_desc);
out_ep++;
}
}
@@ -333,12 +331,13 @@ mt76u_refill_rx(struct mt76_dev *dev, struct urb *urb, int nsgs, gfp_t gfp)
}
static int
-mt76u_urb_alloc(struct mt76_dev *dev, struct mt76_queue_entry *e)
+mt76u_urb_alloc(struct mt76_dev *dev, struct mt76_queue_entry *e,
+ int sg_max_size)
{
unsigned int size = sizeof(struct urb);
if (dev->usb.sg_en)
- size += MT_SG_MAX_SIZE * sizeof(struct scatterlist);
+ size += sg_max_size * sizeof(struct scatterlist);
e->urb = kzalloc(size, GFP_KERNEL);
if (!e->urb)
@@ -357,11 +356,12 @@ mt76u_rx_urb_alloc(struct mt76_dev *dev, struct mt76_queue_entry *e)
{
int err;
- err = mt76u_urb_alloc(dev, e);
+ err = mt76u_urb_alloc(dev, e, MT_RX_SG_MAX_SIZE);
if (err)
return err;
- return mt76u_refill_rx(dev, e->urb, MT_SG_MAX_SIZE, GFP_KERNEL);
+ return mt76u_refill_rx(dev, e->urb, MT_RX_SG_MAX_SIZE,
+ GFP_KERNEL);
}
static void mt76u_urb_free(struct urb *urb)
@@ -429,6 +429,42 @@ static int mt76u_get_rx_entry_len(u8 *data, u32 data_len)
return dma_len;
}
+static struct sk_buff *
+mt76u_build_rx_skb(void *data, int len, int buf_size)
+{
+ struct sk_buff *skb;
+
+ if (SKB_WITH_OVERHEAD(buf_size) < MT_DMA_HDR_LEN + len) {
+ struct page *page;
+
+ /* slow path, not enough space for data and
+ * skb_shared_info
+ */
+ skb = alloc_skb(MT_SKB_HEAD_LEN, GFP_ATOMIC);
+ if (!skb)
+ return NULL;
+
+ skb_put_data(skb, data + MT_DMA_HDR_LEN, MT_SKB_HEAD_LEN);
+ data += (MT_DMA_HDR_LEN + MT_SKB_HEAD_LEN);
+ page = virt_to_head_page(data);
+ skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
+ page, data - page_address(page),
+ len - MT_SKB_HEAD_LEN, buf_size);
+
+ return skb;
+ }
+
+ /* fast path */
+ skb = build_skb(data, buf_size);
+ if (!skb)
+ return NULL;
+
+ skb_reserve(skb, MT_DMA_HDR_LEN);
+ __skb_put(skb, len);
+
+ return skb;
+}
+
static int
mt76u_process_rx_entry(struct mt76_dev *dev, struct urb *urb)
{
@@ -446,19 +482,11 @@ mt76u_process_rx_entry(struct mt76_dev *dev, struct urb *urb)
return 0;
data_len = min_t(int, len, data_len - MT_DMA_HDR_LEN);
- if (MT_DMA_HDR_LEN + data_len > SKB_WITH_OVERHEAD(q->buf_size)) {
- dev_err_ratelimited(dev->dev, "rx data too big %d\n", data_len);
- return 0;
- }
-
- skb = build_skb(data, q->buf_size);
+ skb = mt76u_build_rx_skb(data, data_len, q->buf_size);
if (!skb)
return 0;
- skb_reserve(skb, MT_DMA_HDR_LEN);
- __skb_put(skb, data_len);
len -= data_len;
-
while (len > 0 && nsgs < urb->num_sgs) {
data_len = min_t(int, len, urb->sg[nsgs].length);
skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
@@ -577,8 +605,9 @@ static int mt76u_alloc_rx(struct mt76_dev *dev)
if (!q->entry)
return -ENOMEM;
- q->buf_size = dev->usb.sg_en ? MT_RX_BUF_SIZE : PAGE_SIZE;
q->ndesc = MT_NUM_RX_ENTRIES;
+ q->buf_size = PAGE_SIZE;
+
for (i = 0; i < q->ndesc; i++) {
err = mt76u_rx_urb_alloc(dev, &q->entry[i]);
if (err < 0)
@@ -735,7 +764,7 @@ mt76u_tx_setup_buffers(struct mt76_dev *dev, struct sk_buff *skb,
urb->transfer_buffer = skb->data;
return 0;
} else {
- sg_init_table(urb->sg, MT_SG_MAX_SIZE);
+ sg_init_table(urb->sg, MT_TX_SG_MAX_SIZE);
urb->num_sgs = skb_to_sgvec(skb, urb->sg, 0, skb->len);
if (urb->num_sgs == 0)
return -ENOMEM;
@@ -829,7 +858,8 @@ static int mt76u_alloc_tx(struct mt76_dev *dev)
q->ndesc = MT_NUM_TX_ENTRIES;
for (j = 0; j < q->ndesc; j++) {
- err = mt76u_urb_alloc(dev, &q->entry[j]);
+ err = mt76u_urb_alloc(dev, &q->entry[j],
+ MT_TX_SG_MAX_SIZE);
if (err < 0)
return err;
}
diff --git a/drivers/net/wireless/mediatek/mt7601u/dma.c b/drivers/net/wireless/mediatek/mt7601u/dma.c
index 66d60283e456..f6a0454abe04 100644
--- a/drivers/net/wireless/mediatek/mt7601u/dma.c
+++ b/drivers/net/wireless/mediatek/mt7601u/dma.c
@@ -185,10 +185,23 @@ static void mt7601u_complete_rx(struct urb *urb)
struct mt7601u_rx_queue *q = &dev->rx_q;
unsigned long flags;
- spin_lock_irqsave(&dev->rx_lock, flags);
+ /* do no schedule rx tasklet if urb has been unlinked
+ * or the device has been removed
+ */
+ switch (urb->status) {
+ case -ECONNRESET:
+ case -ESHUTDOWN:
+ case -ENOENT:
+ return;
+ default:
+ dev_err_ratelimited(dev->dev, "rx urb failed: %d\n",
+ urb->status);
+ /* fall through */
+ case 0:
+ break;
+ }
- if (mt7601u_urb_has_error(urb))
- dev_err(dev->dev, "Error: RX urb failed:%d\n", urb->status);
+ spin_lock_irqsave(&dev->rx_lock, flags);
if (WARN_ONCE(q->e[q->end].urb != urb, "RX urb mismatch"))
goto out;
@@ -220,14 +233,25 @@ static void mt7601u_complete_tx(struct urb *urb)
struct sk_buff *skb;
unsigned long flags;
- spin_lock_irqsave(&dev->tx_lock, flags);
+ switch (urb->status) {
+ case -ECONNRESET:
+ case -ESHUTDOWN:
+ case -ENOENT:
+ return;
+ default:
+ dev_err_ratelimited(dev->dev, "tx urb failed: %d\n",
+ urb->status);
+ /* fall through */
+ case 0:
+ break;
+ }
- if (mt7601u_urb_has_error(urb))
- dev_err(dev->dev, "Error: TX urb failed:%d\n", urb->status);
+ spin_lock_irqsave(&dev->tx_lock, flags);
if (WARN_ONCE(q->e[q->start].urb != urb, "TX urb mismatch"))
goto out;
skb = q->e[q->start].skb;
+ q->e[q->start].skb = NULL;
trace_mt_tx_dma_done(dev, skb);
__skb_queue_tail(&dev->tx_skb_done, skb);
@@ -355,19 +379,9 @@ int mt7601u_dma_enqueue_tx(struct mt7601u_dev *dev, struct sk_buff *skb,
static void mt7601u_kill_rx(struct mt7601u_dev *dev)
{
int i;
- unsigned long flags;
-
- spin_lock_irqsave(&dev->rx_lock, flags);
-
- for (i = 0; i < dev->rx_q.entries; i++) {
- int next = dev->rx_q.end;
- spin_unlock_irqrestore(&dev->rx_lock, flags);
- usb_poison_urb(dev->rx_q.e[next].urb);
- spin_lock_irqsave(&dev->rx_lock, flags);
- }
-
- spin_unlock_irqrestore(&dev->rx_lock, flags);
+ for (i = 0; i < dev->rx_q.entries; i++)
+ usb_poison_urb(dev->rx_q.e[i].urb);
}
static int mt7601u_submit_rx_buf(struct mt7601u_dev *dev,
@@ -437,10 +451,10 @@ static void mt7601u_free_tx_queue(struct mt7601u_tx_queue *q)
{
int i;
- WARN_ON(q->used);
-
for (i = 0; i < q->entries; i++) {
usb_poison_urb(q->e[i].urb);
+ if (q->e[i].skb)
+ mt7601u_tx_status(q->dev, q->e[i].skb);
usb_free_urb(q->e[i].urb);
}
}
diff --git a/drivers/net/wireless/mediatek/mt7601u/tx.c b/drivers/net/wireless/mediatek/mt7601u/tx.c
index 906e19c5f628..f3dff8319a4c 100644
--- a/drivers/net/wireless/mediatek/mt7601u/tx.c
+++ b/drivers/net/wireless/mediatek/mt7601u/tx.c
@@ -109,9 +109,9 @@ void mt7601u_tx_status(struct mt7601u_dev *dev, struct sk_buff *skb)
info->status.rates[0].idx = -1;
info->flags |= IEEE80211_TX_STAT_ACK;
- spin_lock(&dev->mac_lock);
+ spin_lock_bh(&dev->mac_lock);
ieee80211_tx_status(dev->hw, skb);
- spin_unlock(&dev->mac_lock);
+ spin_unlock_bh(&dev->mac_lock);
}
static int mt7601u_skb_rooms(struct mt7601u_dev *dev, struct sk_buff *skb)
diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c
index 459f6b81d2eb..dc0c7244b60e 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/commands.c
+++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c
@@ -1011,9 +1011,8 @@ qtnf_parse_variable_mac_info(struct qtnf_wmac *mac,
if (WARN_ON(resp->n_reg_rules > NL80211_MAX_SUPP_REG_RULES))
return -E2BIG;
- mac->rd = kzalloc(sizeof(*mac->rd) +
- sizeof(struct ieee80211_reg_rule) *
- resp->n_reg_rules, GFP_KERNEL);
+ mac->rd = kzalloc(struct_size(mac->rd, reg_rules, resp->n_reg_rules),
+ GFP_KERNEL);
if (!mac->rd)
return -ENOMEM;
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
index 621cd4ce69e2..c9b957ac5733 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -30,6 +30,10 @@
#include "rt2800lib.h"
#include "rt2800.h"
+static bool modparam_watchdog;
+module_param_named(watchdog, modparam_watchdog, bool, S_IRUGO);
+MODULE_PARM_DESC(watchdog, "Enable watchdog to detect tx/rx hangs and reset hardware if detected");
+
/*
* Register access.
* All access to the CSR registers will go through the methods
@@ -1212,6 +1216,63 @@ void rt2800_txdone_nostatus(struct rt2x00_dev *rt2x00dev)
}
EXPORT_SYMBOL_GPL(rt2800_txdone_nostatus);
+static int rt2800_check_hung(struct data_queue *queue)
+{
+ unsigned int cur_idx = rt2800_drv_get_dma_done(queue);
+
+ if (queue->wd_idx != cur_idx)
+ queue->wd_count = 0;
+ else
+ queue->wd_count++;
+
+ return queue->wd_count > 16;
+}
+
+void rt2800_watchdog(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue;
+ bool hung_tx = false;
+ bool hung_rx = false;
+
+ if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags))
+ return;
+
+ queue_for_each(rt2x00dev, queue) {
+ switch (queue->qid) {
+ case QID_AC_VO:
+ case QID_AC_VI:
+ case QID_AC_BE:
+ case QID_AC_BK:
+ case QID_MGMT:
+ if (rt2x00queue_empty(queue))
+ continue;
+ hung_tx = rt2800_check_hung(queue);
+ break;
+ case QID_RX:
+ /* For station mode we should reactive at least
+ * beacons. TODO: need to find good way detect
+ * RX hung for AP mode.
+ */
+ if (rt2x00dev->intf_sta_count == 0)
+ continue;
+ hung_rx = rt2800_check_hung(queue);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (hung_tx)
+ rt2x00_warn(rt2x00dev, "Watchdog TX hung detected\n");
+
+ if (hung_rx)
+ rt2x00_warn(rt2x00dev, "Watchdog RX hung detected\n");
+
+ if (hung_tx || hung_rx)
+ ieee80211_restart_hw(rt2x00dev->hw);
+}
+EXPORT_SYMBOL_GPL(rt2800_watchdog);
+
static unsigned int rt2800_hw_beacon_base(struct rt2x00_dev *rt2x00dev,
unsigned int index)
{
@@ -1593,14 +1654,15 @@ static void rt2800_config_wcid_attr_cipher(struct rt2x00_dev *rt2x00dev,
offset = MAC_IVEIV_ENTRY(key->hw_key_idx);
- memset(&iveiv_entry, 0, sizeof(iveiv_entry));
+ rt2800_register_multiread(rt2x00dev, offset,
+ &iveiv_entry, sizeof(iveiv_entry));
if ((crypto->cipher == CIPHER_TKIP) ||
(crypto->cipher == CIPHER_TKIP_NO_MIC) ||
(crypto->cipher == CIPHER_AES))
iveiv_entry.iv[3] |= 0x20;
iveiv_entry.iv[3] |= key->keyidx << 6;
rt2800_register_multiwrite(rt2x00dev, offset,
- &iveiv_entry, sizeof(iveiv_entry));
+ &iveiv_entry, sizeof(iveiv_entry));
}
int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev,
@@ -1789,6 +1851,25 @@ int rt2800_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
}
EXPORT_SYMBOL_GPL(rt2800_sta_remove);
+void rt2800_pre_reset_hw(struct rt2x00_dev *rt2x00dev)
+{
+ struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
+ struct data_queue *queue = rt2x00dev->bcn;
+ struct queue_entry *entry;
+ int i, wcid;
+
+ for (wcid = WCID_START; wcid < WCID_END; wcid++) {
+ drv_data->wcid_to_sta[wcid - WCID_START] = NULL;
+ __clear_bit(wcid - WCID_START, drv_data->sta_ids);
+ }
+
+ for (i = 0; i < queue->limit; i++) {
+ entry = &queue->entries[i];
+ clear_bit(ENTRY_BCN_ASSIGNED, &entry->flags);
+ }
+}
+EXPORT_SYMBOL_GPL(rt2800_pre_reset_hw);
+
void rt2800_config_filter(struct rt2x00_dev *rt2x00dev,
const unsigned int filter_flags)
{
@@ -6006,13 +6087,11 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
* ASIC will keep garbage value after boot, clear encryption keys.
*/
for (i = 0; i < 4; i++)
- rt2800_register_write(rt2x00dev,
- SHARED_KEY_MODE_ENTRY(i), 0);
+ rt2800_register_write(rt2x00dev, SHARED_KEY_MODE_ENTRY(i), 0);
for (i = 0; i < 256; i++) {
rt2800_config_wcid(rt2x00dev, NULL, i);
rt2800_delete_wcid_attr(rt2x00dev, i);
- rt2800_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0);
}
/*
@@ -10211,6 +10290,13 @@ int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev)
__set_bit(REQUIRE_TASKLET_CONTEXT, &rt2x00dev->cap_flags);
}
+ if (modparam_watchdog) {
+ __set_bit(CAPABILITY_RESTART_HW, &rt2x00dev->cap_flags);
+ rt2x00dev->link.watchdog_interval = msecs_to_jiffies(100);
+ } else {
+ rt2x00dev->link.watchdog_disabled = true;
+ }
+
/*
* Set the rssi offset.
*/
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
index 48adc6cc3233..1139405c0ebb 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
@@ -65,6 +65,7 @@ struct rt2800_ops {
const u8 *data, const size_t len);
int (*drv_init_registers)(struct rt2x00_dev *rt2x00dev);
__le32 *(*drv_get_txwi)(struct queue_entry *entry);
+ unsigned int (*drv_get_dma_done)(struct data_queue *queue);
};
static inline u32 rt2800_register_read(struct rt2x00_dev *rt2x00dev,
@@ -166,6 +167,13 @@ static inline __le32 *rt2800_drv_get_txwi(struct queue_entry *entry)
return rt2800ops->drv_get_txwi(entry);
}
+static inline unsigned int rt2800_drv_get_dma_done(struct data_queue *queue)
+{
+ const struct rt2800_ops *rt2800ops = queue->rt2x00dev->ops->drv;
+
+ return rt2800ops->drv_get_dma_done(queue);
+}
+
void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
const u8 command, const u8 token,
const u8 arg0, const u8 arg1);
@@ -189,6 +197,8 @@ void rt2800_txdone_nostatus(struct rt2x00_dev *rt2x00dev);
bool rt2800_txstatus_timeout(struct rt2x00_dev *rt2x00dev);
bool rt2800_txstatus_pending(struct rt2x00_dev *rt2x00dev);
+void rt2800_watchdog(struct rt2x00_dev *rt2x00dev);
+
void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
void rt2800_clear_beacon(struct queue_entry *entry);
@@ -247,5 +257,6 @@ void rt2800_disable_wpdma(struct rt2x00_dev *rt2x00dev);
void rt2800_get_txwi_rxwi_size(struct rt2x00_dev *rt2x00dev,
unsigned short *txwi_size,
unsigned short *rxwi_size);
+void rt2800_pre_reset_hw(struct rt2x00_dev *rt2x00dev);
#endif /* RT2800LIB_H */
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
index d1de8e2ff690..110bb391c372 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
@@ -24,6 +24,37 @@
#include "rt2800lib.h"
#include "rt2800mmio.h"
+unsigned int rt2800mmio_get_dma_done(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ struct queue_entry *entry;
+ int idx, qid;
+
+ switch (queue->qid) {
+ case QID_AC_VO:
+ case QID_AC_VI:
+ case QID_AC_BE:
+ case QID_AC_BK:
+ qid = queue->qid;
+ idx = rt2x00mmio_register_read(rt2x00dev, TX_DTX_IDX(qid));
+ break;
+ case QID_MGMT:
+ idx = rt2x00mmio_register_read(rt2x00dev, TX_DTX_IDX(5));
+ break;
+ case QID_RX:
+ entry = rt2x00queue_get_entry(queue, Q_INDEX_DMA_DONE);
+ idx = entry->entry_idx;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ idx = 0;
+ break;
+ }
+
+ return idx;
+}
+EXPORT_SYMBOL_GPL(rt2800mmio_get_dma_done);
+
/*
* TX descriptor initialization
*/
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.h b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.h
index 29b5cfd2856f..adcd9d54ac1c 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.h
@@ -114,6 +114,8 @@
#define RXD_W3_PLCP_SIGNAL FIELD32(0x00020000)
#define RXD_W3_PLCP_RSSI FIELD32(0x00040000)
+unsigned int rt2800mmio_get_dma_done(struct data_queue *queue);
+
/* TX descriptor initialization */
__le32 *rt2800mmio_get_txwi(struct queue_entry *entry);
void rt2800mmio_write_tx_desc(struct queue_entry *entry,
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
index ead8bd3e9236..a23c26574002 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
@@ -326,6 +326,7 @@ static const struct rt2800_ops rt2800pci_rt2800_ops = {
.drv_write_firmware = rt2800pci_write_firmware,
.drv_init_registers = rt2800mmio_init_registers,
.drv_get_txwi = rt2800mmio_get_txwi,
+ .drv_get_dma_done = rt2800mmio_get_dma_done,
};
static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
@@ -350,6 +351,7 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
.link_tuner = rt2800_link_tuner,
.gain_calibration = rt2800_gain_calibration,
.vco_calibration = rt2800_vco_calibration,
+ .watchdog = rt2800_watchdog,
.start_queue = rt2800mmio_start_queue,
.kick_queue = rt2800mmio_kick_queue,
.stop_queue = rt2800mmio_stop_queue,
@@ -366,6 +368,7 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
.config_erp = rt2800_config_erp,
.config_ant = rt2800_config_ant,
.config = rt2800_config,
+ .pre_reset_hw = rt2800_pre_reset_hw,
};
static const struct rt2x00_ops rt2800pci_ops = {
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
index 230557d36c52..7b931bb96a9e 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
@@ -171,6 +171,7 @@ static const struct rt2800_ops rt2800soc_rt2800_ops = {
.drv_write_firmware = rt2800soc_write_firmware,
.drv_init_registers = rt2800mmio_init_registers,
.drv_get_txwi = rt2800mmio_get_txwi,
+ .drv_get_dma_done = rt2800mmio_get_dma_done,
};
static const struct rt2x00lib_ops rt2800soc_rt2x00_ops = {
@@ -195,6 +196,7 @@ static const struct rt2x00lib_ops rt2800soc_rt2x00_ops = {
.link_tuner = rt2800_link_tuner,
.gain_calibration = rt2800_gain_calibration,
.vco_calibration = rt2800_vco_calibration,
+ .watchdog = rt2800_watchdog,
.start_queue = rt2800mmio_start_queue,
.kick_queue = rt2800mmio_kick_queue,
.stop_queue = rt2800mmio_stop_queue,
@@ -211,6 +213,7 @@ static const struct rt2x00lib_ops rt2800soc_rt2x00_ops = {
.config_erp = rt2800_config_erp,
.config_ant = rt2800_config_ant,
.config = rt2800_config,
+ .pre_reset_hw = rt2800_pre_reset_hw,
};
static const struct rt2x00_ops rt2800soc_ops = {
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
index 551427b83775..fdf0504b5f1d 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
@@ -379,6 +379,14 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
return retval;
}
+static unsigned int rt2800usb_get_dma_done(struct data_queue *queue)
+{
+ struct queue_entry *entry;
+
+ entry = rt2x00queue_get_entry(queue, Q_INDEX_DMA_DONE);
+ return entry->entry_idx;
+}
+
/*
* TX descriptor initialization
*/
@@ -661,6 +669,7 @@ static const struct rt2800_ops rt2800usb_rt2800_ops = {
.drv_write_firmware = rt2800usb_write_firmware,
.drv_init_registers = rt2800usb_init_registers,
.drv_get_txwi = rt2800usb_get_txwi,
+ .drv_get_dma_done = rt2800usb_get_dma_done,
};
static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
@@ -678,6 +687,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
.link_tuner = rt2800_link_tuner,
.gain_calibration = rt2800_gain_calibration,
.vco_calibration = rt2800_vco_calibration,
+ .watchdog = rt2800_watchdog,
.start_queue = rt2800usb_start_queue,
.kick_queue = rt2x00usb_kick_queue,
.stop_queue = rt2800usb_stop_queue,
@@ -696,6 +706,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
.config_erp = rt2800_config_erp,
.config_ant = rt2800_config_ant,
.config = rt2800_config,
+ .pre_reset_hw = rt2800_pre_reset_hw,
};
static void rt2800usb_queue_init(struct data_queue *queue)
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
index 64a792a8fb2c..7e43690a861c 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
@@ -325,6 +325,8 @@ struct link {
* to bring the device/driver back into the desired state.
*/
struct delayed_work watchdog_work;
+ unsigned int watchdog_interval;
+ bool watchdog_disabled;
/*
* Work structure for scheduling periodic AGC adjustments.
@@ -615,6 +617,7 @@ struct rt2x00lib_ops {
void (*config) (struct rt2x00_dev *rt2x00dev,
struct rt2x00lib_conf *libconf,
const unsigned int changed_flags);
+ void (*pre_reset_hw) (struct rt2x00_dev *rt2x00dev);
int (*sta_add) (struct rt2x00_dev *rt2x00dev,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
@@ -710,6 +713,7 @@ enum rt2x00_capability_flags {
CAPABILITY_VCO_RECALIBRATION,
CAPABILITY_EXTERNAL_PA_TX0,
CAPABILITY_EXTERNAL_PA_TX1,
+ CAPABILITY_RESTART_HW,
};
/*
@@ -1266,6 +1270,12 @@ rt2x00_has_cap_vco_recalibration(struct rt2x00_dev *rt2x00dev)
return rt2x00_has_cap_flag(rt2x00dev, CAPABILITY_VCO_RECALIBRATION);
}
+static inline bool
+rt2x00_has_cap_restart_hw(struct rt2x00_dev *rt2x00dev)
+{
+ return rt2x00_has_cap_flag(rt2x00dev, CAPABILITY_RESTART_HW);
+}
+
/**
* rt2x00queue_map_txskb - Map a skb into DMA for TX purposes.
* @entry: Pointer to &struct queue_entry
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c
index aac3aae7afaa..ef5f51512212 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c
@@ -52,6 +52,7 @@ struct rt2x00debug_intf {
* - chipset file
* - device state flags file
* - device capability flags file
+ * - hardware restart file
* - register folder
* - csr offset/value files
* - eeprom offset/value files
@@ -68,6 +69,7 @@ struct rt2x00debug_intf {
struct dentry *chipset_entry;
struct dentry *dev_flags;
struct dentry *cap_flags;
+ struct dentry *restart_hw;
struct dentry *register_folder;
struct dentry *csr_off_entry;
struct dentry *csr_val_entry;
@@ -566,6 +568,34 @@ static const struct file_operations rt2x00debug_fop_cap_flags = {
.llseek = default_llseek,
};
+static ssize_t rt2x00debug_write_restart_hw(struct file *file,
+ const char __user *buf,
+ size_t length,
+ loff_t *offset)
+{
+ struct rt2x00debug_intf *intf = file->private_data;
+ struct rt2x00_dev *rt2x00dev = intf->rt2x00dev;
+ static unsigned long last_reset;
+
+ if (!rt2x00_has_cap_restart_hw(rt2x00dev))
+ return -EOPNOTSUPP;
+
+ if (time_before(jiffies, last_reset + msecs_to_jiffies(2000)))
+ return -EBUSY;
+
+ last_reset = jiffies;
+
+ ieee80211_restart_hw(rt2x00dev->hw);
+ return length;
+}
+
+static const struct file_operations rt2x00debug_restart_hw = {
+ .owner = THIS_MODULE,
+ .write = rt2x00debug_write_restart_hw,
+ .open = simple_open,
+ .llseek = generic_file_llseek,
+};
+
static struct dentry *rt2x00debug_create_file_driver(const char *name,
struct rt2x00debug_intf
*intf,
@@ -661,6 +691,10 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
intf->driver_folder, intf,
&rt2x00debug_fop_cap_flags);
+ intf->restart_hw = debugfs_create_file("restart_hw", 0200,
+ intf->driver_folder, intf,
+ &rt2x00debug_restart_hw);
+
intf->register_folder =
debugfs_create_dir("register", intf->driver_folder);
@@ -742,6 +776,7 @@ void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
debugfs_remove(intf->csr_off_entry);
debugfs_remove(intf->register_folder);
debugfs_remove(intf->dev_flags);
+ debugfs_remove(intf->restart_hw);
debugfs_remove(intf->cap_flags);
debugfs_remove(intf->chipset_entry);
debugfs_remove(intf->driver_entry);
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
index a6c374c483c2..35414f97a978 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
@@ -1258,8 +1258,14 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev)
{
int retval;
- if (test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags))
- return 0;
+ if (test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) {
+ /*
+ * This is special case for ieee80211_restart_hw(), otherwise
+ * mac80211 never call start() two times in row without stop();
+ */
+ rt2x00dev->ops->lib->pre_reset_hw(rt2x00dev);
+ rt2x00lib_stop(rt2x00dev);
+ }
/*
* If this is the first interface which is added,
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00link.c b/drivers/net/wireless/ralink/rt2x00/rt2x00link.c
index 939cfa5141c6..b052c96347d6 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00link.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00link.c
@@ -384,10 +384,10 @@ void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev)
struct link *link = &rt2x00dev->link;
if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
- rt2x00dev->ops->lib->watchdog)
+ rt2x00dev->ops->lib->watchdog && !link->watchdog_disabled)
ieee80211_queue_delayed_work(rt2x00dev->hw,
&link->watchdog_work,
- WATCHDOG_INTERVAL);
+ link->watchdog_interval);
}
void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev)
@@ -413,11 +413,16 @@ static void rt2x00link_watchdog(struct work_struct *work)
if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
ieee80211_queue_delayed_work(rt2x00dev->hw,
&link->watchdog_work,
- WATCHDOG_INTERVAL);
+ link->watchdog_interval);
}
void rt2x00link_register(struct rt2x00_dev *rt2x00dev)
{
- INIT_DELAYED_WORK(&rt2x00dev->link.watchdog_work, rt2x00link_watchdog);
- INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00link_tuner);
+ struct link *link = &rt2x00dev->link;
+
+ INIT_DELAYED_WORK(&link->work, rt2x00link_tuner);
+ INIT_DELAYED_WORK(&link->watchdog_work, rt2x00link_watchdog);
+
+ if (link->watchdog_interval == 0)
+ link->watchdog_interval = WATCHDOG_INTERVAL;
}
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.h b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.h
index 099e747f70e7..23739dd0bc9b 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.h
@@ -435,6 +435,9 @@ enum data_queue_flags {
* @length: Number of frames in queue.
* @index: Index pointers to entry positions in the queue,
* use &enum queue_index to get a specific index field.
+ * @wd_count: watchdog counter number of times entry does change
+ * in the queue
+ * @wd_idx: index of queue entry saved by watchdog
* @txop: maximum burst time.
* @aifs: The aifs value for outgoing frames (field ignored in RX queue).
* @cw_min: The cw min value for outgoing frames (field ignored in RX queue).
@@ -462,6 +465,9 @@ struct data_queue {
unsigned short length;
unsigned short index[Q_INDEX_MAX];
+ unsigned short wd_count;
+ unsigned int wd_idx;
+
unsigned short txop;
unsigned short aifs;
unsigned short cw_min;
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
index 67b81c7221c4..7e3a621b9c0d 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
@@ -372,15 +372,10 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
struct queue_entry *entry = (struct queue_entry *)urb->context;
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
- if (!test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
return;
/*
- * Report the frame as DMA done
- */
- rt2x00lib_dmadone(entry);
-
- /*
* Check if the received data is simply too small
* to be actually valid, or if the urb is signaling
* a problem.
@@ -389,6 +384,11 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
/*
+ * Report the frame as DMA done
+ */
+ rt2x00lib_dmadone(entry);
+
+ /*
* Schedule the delayed work for reading the RX status
* from the device.
*/
diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/grf5101.c b/drivers/net/wireless/realtek/rtl818x/rtl8180/grf5101.c
index b1bfee738937..fda6ba796385 100644
--- a/drivers/net/wireless/realtek/rtl818x/rtl8180/grf5101.c
+++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/grf5101.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Radio tuning for GCT GRF5101 on RTL8180
@@ -13,10 +14,6 @@
* A special Big Thanks also is for all people who donated me cards,
* making possible the creation of the original rtl8180 driver
* from which this code is derived!
- *
- * 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.
*/
#include <linux/pci.h>
diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/grf5101.h b/drivers/net/wireless/realtek/rtl818x/rtl8180/grf5101.h
index 4d80a2785123..91ff3185cd1b 100644
--- a/drivers/net/wireless/realtek/rtl818x/rtl8180/grf5101.h
+++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/grf5101.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef RTL8180_GRF5101_H
#define RTL8180_GRF5101_H
@@ -15,10 +16,6 @@
* A special Big Thanks also is for all people who donated me cards,
* making possible the creation of the original rtl8180 driver
* from which this code is derived!
- *
- * 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.
*/
#define GRF5101_ANTENNA 0xA3
diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/max2820.c b/drivers/net/wireless/realtek/rtl818x/rtl8180/max2820.c
index eebf23976524..27d04fec3691 100644
--- a/drivers/net/wireless/realtek/rtl818x/rtl8180/max2820.c
+++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/max2820.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Radio tuning for Maxim max2820 on RTL8180
*
@@ -12,10 +13,6 @@
* A special Big Thanks also is for all people who donated me cards,
* making possible the creation of the original rtl8180 driver
* from which this code is derived!
- *
- * 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.
*/
#include <linux/pci.h>
diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/max2820.h b/drivers/net/wireless/realtek/rtl818x/rtl8180/max2820.h
index 8e982b72b690..4cb800d2d3c8 100644
--- a/drivers/net/wireless/realtek/rtl818x/rtl8180/max2820.h
+++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/max2820.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef RTL8180_MAX2820_H
#define RTL8180_MAX2820_H
@@ -15,10 +16,6 @@
* A special Big Thanks also is for all people who donated me cards,
* making possible the creation of the original rtl8180 driver
* from which this code is derived!
- *
- * 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.
*/
#define MAXIM_ANTENNA 0xb3
diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225.c b/drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225.c
index 9bda5bc78eda..470a869e6658 100644
--- a/drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225.c
+++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Radio tuning for RTL8225 on RTL8180
@@ -9,10 +10,6 @@
* Copyright 2005 Andrea Merello <andrea.merello@gmail.com>, et al.
*
* Thanks to Realtek for their support!
- *
- * 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.
*/
#include <linux/pci.h>
diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225se.c b/drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225se.c
index 51e32df6120b..23cd4ff78e54 100644
--- a/drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225se.c
+++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225se.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* Radio tuning for RTL8225 on RTL8187SE
*
@@ -10,10 +11,6 @@
* Also based on the rtl8187 driver, which is:
* Copyright 2007 Michael Wu <flamingice@sourmilk.net>
* Copyright 2007 Andrea Merello <andrea.merello@gmail.com>
- *
- * 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.
*/
#include <net/mac80211.h>
diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225se.h b/drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225se.h
index 229400264088..f00972661888 100644
--- a/drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225se.h
+++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225se.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/* Definitions for RTL8187SE hardware
*
@@ -10,10 +11,6 @@
* Also based on the rtl8187 driver, which is:
* Copyright 2007 Michael Wu <flamingice@sourmilk.net>
* Copyright 2007 Andrea Merello <andrea.merello@gmail.com>
- *
- * 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.
*/
#ifndef RTL8187SE_RTL8225_H
diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/sa2400.c b/drivers/net/wireless/realtek/rtl818x/rtl8180/sa2400.c
index 959b049827de..dd12f5cdb19b 100644
--- a/drivers/net/wireless/realtek/rtl818x/rtl8180/sa2400.c
+++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/sa2400.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Radio tuning for Philips SA2400 on RTL8180
@@ -13,10 +14,6 @@
* A special Big Thanks also is for all people who donated me cards,
* making possible the creation of the original rtl8180 driver
* from which this code is derived!
- *
- * 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.
*/
#include <linux/pci.h>
diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/sa2400.h b/drivers/net/wireless/realtek/rtl818x/rtl8180/sa2400.h
index fb0093f35148..ef6565b20dbd 100644
--- a/drivers/net/wireless/realtek/rtl818x/rtl8180/sa2400.h
+++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/sa2400.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef RTL8180_SA2400_H
#define RTL8180_SA2400_H
@@ -15,10 +16,6 @@
* A special Big Thanks also is for all people who donated me cards,
* making possible the creation of the original rtl8180 driver
* from which this code is derived!
- *
- * 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.
*/
#define SA2400_ANTENNA 0x91
diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
index 1a2ea8b47714..eb68b2d3caa1 100644
--- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
+++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Linux device driver for RTL8187
*
@@ -14,10 +15,6 @@
*
* Magic delays and register offsets below are taken from the original
* r8187 driver sources. Thanks to Realtek for their support!
- *
- * 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.
*/
#include <linux/usb.h>
diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.c
index c089540116fa..49421d10e22b 100644
--- a/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.c
+++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Linux LED driver for RTL8187
*
@@ -7,10 +8,6 @@
* Copyright (c) Realtek Semiconductor Corp. All rights reserved.
*
* Thanks to Realtek for their support!
- *
- * 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.
*/
#ifdef CONFIG_RTL8187_LEDS
diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.h b/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.h
index d743c96d4a20..5565cbf92bbf 100644
--- a/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.h
+++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Definitions for RTL8187 leds
*
@@ -5,10 +6,6 @@
*
* Based on the LED handling in the r8187 driver, which is:
* Copyright (c) Realtek Semiconductor Corp. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#ifndef RTL8187_LED_H
diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/rfkill.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/rfkill.c
index 34116719974a..c57a4742b03e 100644
--- a/drivers/net/wireless/realtek/rtl818x/rtl8187/rfkill.c
+++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/rfkill.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Linux RFKILL support for RTL8187
*
@@ -7,10 +8,6 @@
* Copyright (c) Realtek Semiconductor Corp. All rights reserved.
*
* Thanks to Realtek for their support!
- *
- * 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.
*/
#include <linux/types.h>
diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8187.h b/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8187.h
index 324451df97f7..36f3460cc6c6 100644
--- a/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8187.h
+++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8187.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Definitions for RTL8187 hardware
*
@@ -6,10 +7,6 @@
*
* Based on the r8187 driver, which is:
* Copyright 2005 Andrea Merello <andrea.merello@gmail.com>, et al.
- *
- * 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.
*/
#ifndef RTL8187_H
diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8225.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8225.c
index ff0971f1e2c8..b2616d61b66d 100644
--- a/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8225.c
+++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8225.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Radio tuning for RTL8225 on RTL8187
*
@@ -10,10 +11,6 @@
* Magic delays, register offsets, and phy value tables below are
* taken from the original r8187 driver sources. Thanks to Realtek
* for their support!
- *
- * 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.
*/
#include <linux/usb.h>
diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8225.h b/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8225.h
index 141afb09a5b4..b9475e6ead23 100644
--- a/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8225.h
+++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8225.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Radio tuning definitions for RTL8225 on RTL8187
*
@@ -6,10 +7,6 @@
*
* Based on the r8187 driver, which is:
* Copyright 2005 Andrea Merello <andrea.merello@gmail.com>, et al.
- *
- * 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.
*/
#ifndef RTL8187_RTL8225_H
diff --git a/drivers/net/wireless/realtek/rtl818x/rtl818x.h b/drivers/net/wireless/realtek/rtl818x/rtl818x.h
index 7abef95d278b..597f41af899a 100644
--- a/drivers/net/wireless/realtek/rtl818x/rtl818x.h
+++ b/drivers/net/wireless/realtek/rtl818x/rtl818x.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Definitions for RTL818x hardware
*
@@ -6,10 +7,6 @@
*
* Based on the r8187 driver, which is:
* Copyright 2005 Andrea Merello <andrea.merello@gmail.com>, et al.
- *
- * 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.
*/
#ifndef RTL818X_H
diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c
index 2ac0481b29ef..152242ac0aa5 100644
--- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c
+++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c
@@ -1578,7 +1578,7 @@ void exhalbtc_scan_notify_wifi_only(struct wifi_only_cfg *wifionly_cfg,
void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action)
{
- u8 asso_type, asso_type_v2;
+ u8 asso_type;
bool wifi_under_5g;
if (!halbtc_is_bt_coexist_available(btcoexist))
@@ -1589,15 +1589,10 @@ void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action)
btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g);
- if (action) {
+ if (action)
asso_type = BTC_ASSOCIATE_START;
- asso_type_v2 = wifi_under_5g ? BTC_ASSOCIATE_5G_START :
- BTC_ASSOCIATE_START;
- } else {
+ else
asso_type = BTC_ASSOCIATE_FINISH;
- asso_type_v2 = wifi_under_5g ? BTC_ASSOCIATE_5G_FINISH :
- BTC_ASSOCIATE_FINISH;
- }
halbtc_leave_low_power(btcoexist);
@@ -1746,30 +1741,6 @@ void exhalbtc_rf_status_notify(struct btc_coexist *btcoexist, u8 type)
}
}
-void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type)
-{
- u8 stack_op_type;
-
- if (!halbtc_is_bt_coexist_available(btcoexist))
- return;
- btcoexist->statistics.cnt_stack_operation_notify++;
- if (btcoexist->manual_control)
- return;
-
- if ((type == HCI_BT_OP_INQUIRY_START) ||
- (type == HCI_BT_OP_PAGING_START) ||
- (type == HCI_BT_OP_PAIRING_START)) {
- stack_op_type = BTC_STACK_OP_INQ_PAGE_PAIR_START;
- } else if ((type == HCI_BT_OP_INQUIRY_FINISH) ||
- (type == HCI_BT_OP_PAGING_SUCCESS) ||
- (type == HCI_BT_OP_PAGING_UNSUCCESS) ||
- (type == HCI_BT_OP_PAIRING_FINISH)) {
- stack_op_type = BTC_STACK_OP_INQ_PAGE_PAIR_FINISH;
- } else {
- stack_op_type = BTC_STACK_OP_NONE;
- }
-}
-
void exhalbtc_halt_notify(struct btc_coexist *btcoexist)
{
if (!halbtc_is_bt_coexist_available(btcoexist))
diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h
index ee9aeddf1ebc..8c0a7fdbf200 100644
--- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h
+++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h
@@ -764,7 +764,6 @@ void exhalbtc_special_packet_notify(struct btc_coexist *btcoexist, u8 pkt_type);
void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist, u8 *tmp_buf,
u8 length);
void exhalbtc_rf_status_notify(struct btc_coexist *btcoexist, u8 type);
-void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type);
void exhalbtc_halt_notify(struct btc_coexist *btcoexist);
void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state);
void exhalbtc_coex_dm_switch(struct btc_coexist *btcoexist);
diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c
index 0e509c33e9e6..b8c4536af6c0 100644
--- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c
+++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c
@@ -316,7 +316,7 @@ void rtl_btc_btinfo_notify(struct rtl_priv *rtlpriv, u8 *tmp_buf, u8 length)
void rtl_btc_btmpinfo_notify(struct rtl_priv *rtlpriv, u8 *tmp_buf, u8 length)
{
struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv);
- u8 extid, seq, len;
+ u8 extid, seq;
u16 bt_real_fw_ver;
u8 bt_fw_ver;
u8 *data;
@@ -332,7 +332,6 @@ void rtl_btc_btmpinfo_notify(struct rtl_priv *rtlpriv, u8 *tmp_buf, u8 length)
if (extid != 1) /* C2H_TRIG_BY_BT_FW = 1 */
return;
- len = tmp_buf[1] >> 4;
seq = tmp_buf[2] >> 4;
data = &tmp_buf[3];
diff --git a/drivers/net/wireless/realtek/rtlwifi/efuse.c b/drivers/net/wireless/realtek/rtlwifi/efuse.c
index e68340dfd980..ea4fc53764de 100644
--- a/drivers/net/wireless/realtek/rtlwifi/efuse.c
+++ b/drivers/net/wireless/realtek/rtlwifi/efuse.c
@@ -117,10 +117,8 @@ u8 efuse_read_1byte(struct ieee80211_hw *hw, u16 address)
rtlpriv->cfg->
maps[EFUSE_CTRL] + 3);
k++;
- if (k == 1000) {
- k = 0;
+ if (k == 1000)
break;
- }
}
data = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]);
return data;
@@ -986,7 +984,6 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw,
} else if (write_state == PG_STATE_DATA) {
RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,
"efuse PG_STATE_DATA\n");
- badworden = 0x0f;
badworden =
enable_efuse_data_write(hw, efuse_addr + 1,
target_pkt.word_en,
diff --git a/drivers/net/wireless/realtek/rtlwifi/rc.c b/drivers/net/wireless/realtek/rtlwifi/rc.c
index cf8e42a01015..0c7d74902d33 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rc.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rc.c
@@ -173,9 +173,6 @@ static void rtl_get_rate(void *ppriv, struct ieee80211_sta *sta,
u8 try_per_rate, i, rix;
bool not_data = !ieee80211_is_data(fc);
- if (rate_control_send_low(sta, priv_sta, txrc))
- return;
-
rix = _rtl_rc_get_highest_rix(rtlpriv, sta, skb, not_data);
try_per_rate = 1;
_rtl_rc_rate_set_series(rtlpriv, sta, &rates[0], txrc,
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c
index 454bab38b165..f92e95f5494f 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c
@@ -1039,7 +1039,7 @@ int rtl88ee_hw_init(struct ieee80211_hw *hw)
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
- bool rtstatus = true;
+ bool rtstatus;
int err = 0;
u8 tmp_u1b, u1byte;
unsigned long flags;
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/dm.c
index 7cc86bb387a1..71f3b6b5d7bd 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/dm.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/dm.c
@@ -680,6 +680,7 @@ static void rtl92d_bandtype_2_4G(struct ieee80211_hw *hw, long *temp_cckg,
int i;
unsigned long flag = 0;
long temp_cck;
+ const u8 *cckswing;
/* Query CCK default setting From 0xa24 */
rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag);
@@ -687,28 +688,19 @@ static void rtl92d_bandtype_2_4G(struct ieee80211_hw *hw, long *temp_cckg,
MASKDWORD) & MASKCCK;
rtl92d_release_cckandrw_pagea_ctl(hw, &flag);
for (i = 0; i < CCK_TABLE_LENGTH; i++) {
- if (rtlpriv->dm.cck_inch14) {
- if (!memcmp((void *)&temp_cck,
- (void *)&cckswing_table_ch14[i][2], 4)) {
- *cck_index_old = (u8) i;
- RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
- "Initial reg0x%x = 0x%lx, cck_index=0x%x, ch 14 %d\n",
- RCCK0_TXFILTER2, temp_cck,
- *cck_index_old,
- rtlpriv->dm.cck_inch14);
- break;
- }
- } else {
- if (!memcmp((void *) &temp_cck,
- &cckswing_table_ch1ch13[i][2], 4)) {
- *cck_index_old = (u8) i;
- RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
- "Initial reg0x%x = 0x%lx, cck_index = 0x%x, ch14 %d\n",
- RCCK0_TXFILTER2, temp_cck,
- *cck_index_old,
- rtlpriv->dm.cck_inch14);
- break;
- }
+ if (rtlpriv->dm.cck_inch14)
+ cckswing = &cckswing_table_ch14[i][2];
+ else
+ cckswing = &cckswing_table_ch1ch13[i][2];
+
+ if (temp_cck == le32_to_cpu(*((__le32 *)cckswing))) {
+ *cck_index_old = (u8)i;
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "Initial reg0x%x = 0x%lx, cck_index = 0x%x, ch14 %d\n",
+ RCCK0_TXFILTER2, temp_cck,
+ *cck_index_old,
+ rtlpriv->dm.cck_inch14);
+ break;
}
}
*temp_cckg = temp_cck;
@@ -718,8 +710,8 @@ static void rtl92d_bandtype_5G(struct rtl_hal *rtlhal, u8 *ofdm_index,
bool *internal_pa, u8 thermalvalue, u8 delta,
u8 rf, struct rtl_efuse *rtlefuse,
struct rtl_priv *rtlpriv, struct rtl_phy *rtlphy,
- u8 index_mapping[5][INDEX_MAPPING_NUM],
- u8 index_mapping_pa[8][INDEX_MAPPING_NUM])
+ const u8 index_mapping[5][INDEX_MAPPING_NUM],
+ const u8 index_mapping_pa[8][INDEX_MAPPING_NUM])
{
int i;
u8 index;
@@ -787,9 +779,9 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter(
bool internal_pa = false;
long ele_a = 0, ele_d, temp_cck, val_x, value32;
long val_y, ele_c = 0;
- u8 ofdm_index[3];
+ u8 ofdm_index[2];
s8 cck_index = 0;
- u8 ofdm_index_old[3] = {0, 0, 0};
+ u8 ofdm_index_old[2] = {0, 0};
s8 cck_index_old = 0;
u8 index;
int i;
@@ -797,7 +789,7 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter(
u8 ofdm_min_index = 6, ofdm_min_index_internal_pa = 3, rf;
u8 indexforchannel =
rtl92d_get_rightchnlplace_for_iqk(rtlphy->current_channel);
- u8 index_mapping[5][INDEX_MAPPING_NUM] = {
+ static const u8 index_mapping[5][INDEX_MAPPING_NUM] = {
/* 5G, path A/MAC 0, decrease power */
{0, 1, 3, 6, 8, 9, 11, 13, 14, 16, 17, 18, 18},
/* 5G, path A/MAC 0, increase power */
@@ -809,7 +801,7 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter(
/* 2.4G, for decreas power */
{0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 9, 10, 10},
};
- u8 index_mapping_internal_pa[8][INDEX_MAPPING_NUM] = {
+ static const u8 index_mapping_internal_pa[8][INDEX_MAPPING_NUM] = {
/* 5G, path A/MAC 0, ch36-64, decrease power */
{0, 1, 2, 4, 6, 7, 9, 11, 12, 14, 15, 16, 16},
/* 5G, path A/MAC 0, ch36-64, increase power */
@@ -837,365 +829,338 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter(
rtlpriv->dm.thermalvalue, rtlefuse->eeprom_thermalmeter);
rtl92d_phy_ap_calibrate(hw, (thermalvalue -
rtlefuse->eeprom_thermalmeter));
+
+ if (!thermalvalue)
+ goto exit;
+
if (is2t)
rf = 2;
else
rf = 1;
- if (thermalvalue) {
- ele_d = rtl_get_bbreg(hw, ROFDM0_XATXIQIMBALANCE,
+
+ if (rtlpriv->dm.thermalvalue && !rtlhal->reloadtxpowerindex)
+ goto old_index_done;
+
+ ele_d = rtl_get_bbreg(hw, ROFDM0_XATXIQIMBALANCE, MASKDWORD) & MASKOFDM_D;
+ for (i = 0; i < OFDM_TABLE_SIZE_92D; i++) {
+ if (ele_d == (ofdmswing_table[i] & MASKOFDM_D)) {
+ ofdm_index_old[0] = (u8)i;
+
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "Initial pathA ele_d reg0x%x = 0x%lx, ofdm_index=0x%x\n",
+ ROFDM0_XATXIQIMBALANCE,
+ ele_d, ofdm_index_old[0]);
+ break;
+ }
+ }
+ if (is2t) {
+ ele_d = rtl_get_bbreg(hw, ROFDM0_XBTXIQIMBALANCE,
MASKDWORD) & MASKOFDM_D;
for (i = 0; i < OFDM_TABLE_SIZE_92D; i++) {
- if (ele_d == (ofdmswing_table[i] & MASKOFDM_D)) {
- ofdm_index_old[0] = (u8) i;
-
- RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
- "Initial pathA ele_d reg0x%x = 0x%lx, ofdm_index=0x%x\n",
- ROFDM0_XATXIQIMBALANCE,
- ele_d, ofdm_index_old[0]);
+ if (ele_d ==
+ (ofdmswing_table[i] & MASKOFDM_D)) {
+ ofdm_index_old[1] = (u8)i;
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING,
+ DBG_LOUD,
+ "Initial pathB ele_d reg 0x%x = 0x%lx, ofdm_index = 0x%x\n",
+ ROFDM0_XBTXIQIMBALANCE, ele_d,
+ ofdm_index_old[1]);
break;
}
}
- if (is2t) {
- ele_d = rtl_get_bbreg(hw, ROFDM0_XBTXIQIMBALANCE,
- MASKDWORD) & MASKOFDM_D;
- for (i = 0; i < OFDM_TABLE_SIZE_92D; i++) {
- if (ele_d ==
- (ofdmswing_table[i] & MASKOFDM_D)) {
- ofdm_index_old[1] = (u8) i;
- RT_TRACE(rtlpriv, COMP_POWER_TRACKING,
- DBG_LOUD,
- "Initial pathB ele_d reg 0x%x = 0x%lx, ofdm_index = 0x%x\n",
- ROFDM0_XBTXIQIMBALANCE, ele_d,
- ofdm_index_old[1]);
- break;
- }
- }
- }
- if (rtlhal->current_bandtype == BAND_ON_2_4G) {
- rtl92d_bandtype_2_4G(hw, &temp_cck, &cck_index_old);
- } else {
- temp_cck = 0x090e1317;
- cck_index_old = 12;
- }
+ }
+ if (rtlhal->current_bandtype == BAND_ON_2_4G) {
+ rtl92d_bandtype_2_4G(hw, &temp_cck, &cck_index_old);
+ } else {
+ temp_cck = 0x090e1317;
+ cck_index_old = 12;
+ }
- if (!rtlpriv->dm.thermalvalue) {
- rtlpriv->dm.thermalvalue =
- rtlefuse->eeprom_thermalmeter;
- rtlpriv->dm.thermalvalue_lck = thermalvalue;
- rtlpriv->dm.thermalvalue_iqk = thermalvalue;
- rtlpriv->dm.thermalvalue_rxgain =
- rtlefuse->eeprom_thermalmeter;
- for (i = 0; i < rf; i++)
- rtlpriv->dm.ofdm_index[i] = ofdm_index_old[i];
- rtlpriv->dm.cck_index = cck_index_old;
+ if (!rtlpriv->dm.thermalvalue) {
+ rtlpriv->dm.thermalvalue = rtlefuse->eeprom_thermalmeter;
+ rtlpriv->dm.thermalvalue_lck = thermalvalue;
+ rtlpriv->dm.thermalvalue_iqk = thermalvalue;
+ rtlpriv->dm.thermalvalue_rxgain = rtlefuse->eeprom_thermalmeter;
+ for (i = 0; i < rf; i++)
+ rtlpriv->dm.ofdm_index[i] = ofdm_index_old[i];
+ rtlpriv->dm.cck_index = cck_index_old;
+ }
+ if (rtlhal->reloadtxpowerindex) {
+ for (i = 0; i < rf; i++)
+ rtlpriv->dm.ofdm_index[i] = ofdm_index_old[i];
+ rtlpriv->dm.cck_index = cck_index_old;
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "reload ofdm index for band switch\n");
+ }
+old_index_done:
+ for (i = 0; i < rf; i++)
+ ofdm_index[i] = rtlpriv->dm.ofdm_index[i];
+
+ rtlpriv->dm.thermalvalue_avg
+ [rtlpriv->dm.thermalvalue_avg_index] = thermalvalue;
+ rtlpriv->dm.thermalvalue_avg_index++;
+ if (rtlpriv->dm.thermalvalue_avg_index == AVG_THERMAL_NUM)
+ rtlpriv->dm.thermalvalue_avg_index = 0;
+ for (i = 0; i < AVG_THERMAL_NUM; i++) {
+ if (rtlpriv->dm.thermalvalue_avg[i]) {
+ thermalvalue_avg += rtlpriv->dm.thermalvalue_avg[i];
+ thermalvalue_avg_count++;
}
- if (rtlhal->reloadtxpowerindex) {
+ }
+ if (thermalvalue_avg_count)
+ thermalvalue = (u8)(thermalvalue_avg / thermalvalue_avg_count);
+ if (rtlhal->reloadtxpowerindex) {
+ delta = (thermalvalue > rtlefuse->eeprom_thermalmeter) ?
+ (thermalvalue - rtlefuse->eeprom_thermalmeter) :
+ (rtlefuse->eeprom_thermalmeter - thermalvalue);
+ rtlhal->reloadtxpowerindex = false;
+ rtlpriv->dm.done_txpower = false;
+ } else if (rtlpriv->dm.done_txpower) {
+ delta = (thermalvalue > rtlpriv->dm.thermalvalue) ?
+ (thermalvalue - rtlpriv->dm.thermalvalue) :
+ (rtlpriv->dm.thermalvalue - thermalvalue);
+ } else {
+ delta = (thermalvalue > rtlefuse->eeprom_thermalmeter) ?
+ (thermalvalue - rtlefuse->eeprom_thermalmeter) :
+ (rtlefuse->eeprom_thermalmeter - thermalvalue);
+ }
+ delta_lck = (thermalvalue > rtlpriv->dm.thermalvalue_lck) ?
+ (thermalvalue - rtlpriv->dm.thermalvalue_lck) :
+ (rtlpriv->dm.thermalvalue_lck - thermalvalue);
+ delta_iqk = (thermalvalue > rtlpriv->dm.thermalvalue_iqk) ?
+ (thermalvalue - rtlpriv->dm.thermalvalue_iqk) :
+ (rtlpriv->dm.thermalvalue_iqk - thermalvalue);
+ delta_rxgain =
+ (thermalvalue > rtlpriv->dm.thermalvalue_rxgain) ?
+ (thermalvalue - rtlpriv->dm.thermalvalue_rxgain) :
+ (rtlpriv->dm.thermalvalue_rxgain - thermalvalue);
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "Readback Thermal Meter = 0x%x pre thermal meter 0x%x eeprom_thermalmeter 0x%x delta 0x%x delta_lck 0x%x delta_iqk 0x%x\n",
+ thermalvalue, rtlpriv->dm.thermalvalue,
+ rtlefuse->eeprom_thermalmeter, delta, delta_lck,
+ delta_iqk);
+ if (delta_lck > rtlefuse->delta_lck && rtlefuse->delta_lck != 0) {
+ rtlpriv->dm.thermalvalue_lck = thermalvalue;
+ rtl92d_phy_lc_calibrate(hw);
+ }
+
+ if (delta == 0 || !rtlpriv->dm.txpower_track_control)
+ goto check_delta;
+
+ rtlpriv->dm.done_txpower = true;
+ delta = (thermalvalue > rtlefuse->eeprom_thermalmeter) ?
+ (thermalvalue - rtlefuse->eeprom_thermalmeter) :
+ (rtlefuse->eeprom_thermalmeter - thermalvalue);
+ if (rtlhal->current_bandtype == BAND_ON_2_4G) {
+ offset = 4;
+ if (delta > INDEX_MAPPING_NUM - 1)
+ index = index_mapping[offset][INDEX_MAPPING_NUM - 1];
+ else
+ index = index_mapping[offset][delta];
+ if (thermalvalue > rtlpriv->dm.thermalvalue) {
for (i = 0; i < rf; i++)
- rtlpriv->dm.ofdm_index[i] = ofdm_index_old[i];
- rtlpriv->dm.cck_index = cck_index_old;
- RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
- "reload ofdm index for band switch\n");
- }
- rtlpriv->dm.thermalvalue_avg
- [rtlpriv->dm.thermalvalue_avg_index] = thermalvalue;
- rtlpriv->dm.thermalvalue_avg_index++;
- if (rtlpriv->dm.thermalvalue_avg_index == AVG_THERMAL_NUM)
- rtlpriv->dm.thermalvalue_avg_index = 0;
- for (i = 0; i < AVG_THERMAL_NUM; i++) {
- if (rtlpriv->dm.thermalvalue_avg[i]) {
- thermalvalue_avg +=
- rtlpriv->dm.thermalvalue_avg[i];
- thermalvalue_avg_count++;
- }
- }
- if (thermalvalue_avg_count)
- thermalvalue = (u8) (thermalvalue_avg /
- thermalvalue_avg_count);
- if (rtlhal->reloadtxpowerindex) {
- delta = (thermalvalue > rtlefuse->eeprom_thermalmeter) ?
- (thermalvalue - rtlefuse->eeprom_thermalmeter) :
- (rtlefuse->eeprom_thermalmeter - thermalvalue);
- rtlhal->reloadtxpowerindex = false;
- rtlpriv->dm.done_txpower = false;
- } else if (rtlpriv->dm.done_txpower) {
- delta = (thermalvalue > rtlpriv->dm.thermalvalue) ?
- (thermalvalue - rtlpriv->dm.thermalvalue) :
- (rtlpriv->dm.thermalvalue - thermalvalue);
+ ofdm_index[i] -= delta;
+ cck_index -= delta;
} else {
- delta = (thermalvalue > rtlefuse->eeprom_thermalmeter) ?
- (thermalvalue - rtlefuse->eeprom_thermalmeter) :
- (rtlefuse->eeprom_thermalmeter - thermalvalue);
+ for (i = 0; i < rf; i++)
+ ofdm_index[i] += index;
+ cck_index += index;
}
- delta_lck = (thermalvalue > rtlpriv->dm.thermalvalue_lck) ?
- (thermalvalue - rtlpriv->dm.thermalvalue_lck) :
- (rtlpriv->dm.thermalvalue_lck - thermalvalue);
- delta_iqk = (thermalvalue > rtlpriv->dm.thermalvalue_iqk) ?
- (thermalvalue - rtlpriv->dm.thermalvalue_iqk) :
- (rtlpriv->dm.thermalvalue_iqk - thermalvalue);
- delta_rxgain =
- (thermalvalue > rtlpriv->dm.thermalvalue_rxgain) ?
- (thermalvalue - rtlpriv->dm.thermalvalue_rxgain) :
- (rtlpriv->dm.thermalvalue_rxgain - thermalvalue);
+ } else if (rtlhal->current_bandtype == BAND_ON_5G) {
+ rtl92d_bandtype_5G(rtlhal, ofdm_index,
+ &internal_pa, thermalvalue,
+ delta, rf, rtlefuse, rtlpriv,
+ rtlphy, index_mapping,
+ index_mapping_internal_pa);
+ }
+ if (is2t) {
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
- "Readback Thermal Meter = 0x%x pre thermal meter 0x%x eeprom_thermalmeter 0x%x delta 0x%x delta_lck 0x%x delta_iqk 0x%x\n",
- thermalvalue, rtlpriv->dm.thermalvalue,
- rtlefuse->eeprom_thermalmeter, delta, delta_lck,
- delta_iqk);
- if ((delta_lck > rtlefuse->delta_lck) &&
- (rtlefuse->delta_lck != 0)) {
- rtlpriv->dm.thermalvalue_lck = thermalvalue;
- rtl92d_phy_lc_calibrate(hw);
+ "temp OFDM_A_index=0x%x, OFDM_B_index = 0x%x,cck_index=0x%x\n",
+ rtlpriv->dm.ofdm_index[0],
+ rtlpriv->dm.ofdm_index[1],
+ rtlpriv->dm.cck_index);
+ } else {
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "temp OFDM_A_index=0x%x,cck_index = 0x%x\n",
+ rtlpriv->dm.ofdm_index[0],
+ rtlpriv->dm.cck_index);
+ }
+ for (i = 0; i < rf; i++) {
+ if (ofdm_index[i] > OFDM_TABLE_SIZE_92D - 1)
+ ofdm_index[i] = OFDM_TABLE_SIZE_92D - 1;
+ else if (ofdm_index[i] < ofdm_min_index)
+ ofdm_index[i] = ofdm_min_index;
+ }
+ if (rtlhal->current_bandtype == BAND_ON_2_4G) {
+ if (cck_index > CCK_TABLE_SIZE - 1) {
+ cck_index = CCK_TABLE_SIZE - 1;
+ } else if (internal_pa ||
+ rtlhal->current_bandtype == BAND_ON_2_4G) {
+ if (ofdm_index[i] < ofdm_min_index_internal_pa)
+ ofdm_index[i] = ofdm_min_index_internal_pa;
+ } else if (cck_index < 0) {
+ cck_index = 0;
}
- if (delta > 0 && rtlpriv->dm.txpower_track_control) {
- rtlpriv->dm.done_txpower = true;
- delta = (thermalvalue > rtlefuse->eeprom_thermalmeter) ?
- (thermalvalue - rtlefuse->eeprom_thermalmeter) :
- (rtlefuse->eeprom_thermalmeter - thermalvalue);
- if (rtlhal->current_bandtype == BAND_ON_2_4G) {
- offset = 4;
- if (delta > INDEX_MAPPING_NUM - 1)
- index = index_mapping[offset]
- [INDEX_MAPPING_NUM - 1];
- else
- index = index_mapping[offset][delta];
- if (thermalvalue > rtlpriv->dm.thermalvalue) {
- for (i = 0; i < rf; i++)
- ofdm_index[i] -= delta;
- cck_index -= delta;
- } else {
- for (i = 0; i < rf; i++)
- ofdm_index[i] += index;
- cck_index += index;
- }
- } else if (rtlhal->current_bandtype == BAND_ON_5G) {
- rtl92d_bandtype_5G(rtlhal, ofdm_index,
- &internal_pa, thermalvalue,
- delta, rf, rtlefuse, rtlpriv,
- rtlphy, index_mapping,
- index_mapping_internal_pa);
- }
- if (is2t) {
- RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
- "temp OFDM_A_index=0x%x, OFDM_B_index = 0x%x,cck_index=0x%x\n",
- rtlpriv->dm.ofdm_index[0],
- rtlpriv->dm.ofdm_index[1],
- rtlpriv->dm.cck_index);
- } else {
- RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
- "temp OFDM_A_index=0x%x,cck_index = 0x%x\n",
- rtlpriv->dm.ofdm_index[0],
- rtlpriv->dm.cck_index);
- }
- for (i = 0; i < rf; i++) {
- if (ofdm_index[i] > OFDM_TABLE_SIZE_92D - 1)
- ofdm_index[i] = OFDM_TABLE_SIZE_92D - 1;
- else if (ofdm_index[i] < ofdm_min_index)
- ofdm_index[i] = ofdm_min_index;
- }
- if (rtlhal->current_bandtype == BAND_ON_2_4G) {
- if (cck_index > CCK_TABLE_SIZE - 1) {
- cck_index = CCK_TABLE_SIZE - 1;
- } else if (internal_pa ||
- rtlhal->current_bandtype ==
- BAND_ON_2_4G) {
- if (ofdm_index[i] <
- ofdm_min_index_internal_pa)
- ofdm_index[i] =
- ofdm_min_index_internal_pa;
- } else if (cck_index < 0) {
- cck_index = 0;
- }
- }
- if (is2t) {
- RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
- "new OFDM_A_index=0x%x, OFDM_B_index = 0x%x, cck_index=0x%x\n",
- ofdm_index[0], ofdm_index[1],
- cck_index);
- } else {
- RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
- "new OFDM_A_index=0x%x,cck_index = 0x%x\n",
- ofdm_index[0], cck_index);
- }
- ele_d = (ofdmswing_table[(u8) ofdm_index[0]] &
- 0xFFC00000) >> 22;
- val_x = rtlphy->iqk_matrix
- [indexforchannel].value[0][0];
- val_y = rtlphy->iqk_matrix
- [indexforchannel].value[0][1];
- if (val_x != 0) {
- if ((val_x & 0x00000200) != 0)
- val_x = val_x | 0xFFFFFC00;
- ele_a =
- ((val_x * ele_d) >> 8) & 0x000003FF;
-
- /* new element C = element D x Y */
- if ((val_y & 0x00000200) != 0)
- val_y = val_y | 0xFFFFFC00;
- ele_c = ((val_y * ele_d) >> 8) & 0x000003FF;
-
- /* wirte new elements A, C, D to regC80 and
- * regC94, element B is always 0 */
- value32 = (ele_d << 22) | ((ele_c & 0x3F) <<
- 16) | ele_a;
- rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE,
- MASKDWORD, value32);
-
- value32 = (ele_c & 0x000003C0) >> 6;
- rtl_set_bbreg(hw, ROFDM0_XCTXAFE, MASKH4BITS,
- value32);
-
- value32 = ((val_x * ele_d) >> 7) & 0x01;
- rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(24),
- value32);
+ }
+ if (is2t) {
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "new OFDM_A_index=0x%x, OFDM_B_index = 0x%x, cck_index=0x%x\n",
+ ofdm_index[0], ofdm_index[1],
+ cck_index);
+ } else {
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "new OFDM_A_index=0x%x,cck_index = 0x%x\n",
+ ofdm_index[0], cck_index);
+ }
+ ele_d = (ofdmswing_table[ofdm_index[0]] & 0xFFC00000) >> 22;
+ val_x = rtlphy->iqk_matrix[indexforchannel].value[0][0];
+ val_y = rtlphy->iqk_matrix[indexforchannel].value[0][1];
+ if (val_x != 0) {
+ if ((val_x & 0x00000200) != 0)
+ val_x = val_x | 0xFFFFFC00;
+ ele_a = ((val_x * ele_d) >> 8) & 0x000003FF;
+
+ /* new element C = element D x Y */
+ if ((val_y & 0x00000200) != 0)
+ val_y = val_y | 0xFFFFFC00;
+ ele_c = ((val_y * ele_d) >> 8) & 0x000003FF;
+
+ /* write new elements A, C, D to regC80 and
+ * regC94, element B is always 0
+ */
+ value32 = (ele_d << 22) | ((ele_c & 0x3F) << 16) | ele_a;
+ rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE,
+ MASKDWORD, value32);
+
+ value32 = (ele_c & 0x000003C0) >> 6;
+ rtl_set_bbreg(hw, ROFDM0_XCTXAFE, MASKH4BITS,
+ value32);
+
+ value32 = ((val_x * ele_d) >> 7) & 0x01;
+ rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(24),
+ value32);
- } else {
- rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE,
- MASKDWORD,
- ofdmswing_table
- [(u8)ofdm_index[0]]);
- rtl_set_bbreg(hw, ROFDM0_XCTXAFE, MASKH4BITS,
- 0x00);
- rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD,
- BIT(24), 0x00);
- }
+ } else {
+ rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE,
+ MASKDWORD,
+ ofdmswing_table[(u8)ofdm_index[0]]);
+ rtl_set_bbreg(hw, ROFDM0_XCTXAFE, MASKH4BITS,
+ 0x00);
+ rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD,
+ BIT(24), 0x00);
+ }
- RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
- "TxPwrTracking for interface %d path A: X = 0x%lx, Y = 0x%lx ele_A = 0x%lx ele_C = 0x%lx ele_D = 0x%lx 0xe94 = 0x%lx 0xe9c = 0x%lx\n",
- rtlhal->interfaceindex,
- val_x, val_y, ele_a, ele_c, ele_d,
- val_x, val_y);
-
- if (cck_index >= CCK_TABLE_SIZE)
- cck_index = CCK_TABLE_SIZE - 1;
- if (cck_index < 0)
- cck_index = 0;
- if (rtlhal->current_bandtype == BAND_ON_2_4G) {
- /* Adjust CCK according to IQK result */
- if (!rtlpriv->dm.cck_inch14) {
- rtl_write_byte(rtlpriv, 0xa22,
- cckswing_table_ch1ch13
- [(u8)cck_index][0]);
- rtl_write_byte(rtlpriv, 0xa23,
- cckswing_table_ch1ch13
- [(u8)cck_index][1]);
- rtl_write_byte(rtlpriv, 0xa24,
- cckswing_table_ch1ch13
- [(u8)cck_index][2]);
- rtl_write_byte(rtlpriv, 0xa25,
- cckswing_table_ch1ch13
- [(u8)cck_index][3]);
- rtl_write_byte(rtlpriv, 0xa26,
- cckswing_table_ch1ch13
- [(u8)cck_index][4]);
- rtl_write_byte(rtlpriv, 0xa27,
- cckswing_table_ch1ch13
- [(u8)cck_index][5]);
- rtl_write_byte(rtlpriv, 0xa28,
- cckswing_table_ch1ch13
- [(u8)cck_index][6]);
- rtl_write_byte(rtlpriv, 0xa29,
- cckswing_table_ch1ch13
- [(u8)cck_index][7]);
- } else {
- rtl_write_byte(rtlpriv, 0xa22,
- cckswing_table_ch14
- [(u8)cck_index][0]);
- rtl_write_byte(rtlpriv, 0xa23,
- cckswing_table_ch14
- [(u8)cck_index][1]);
- rtl_write_byte(rtlpriv, 0xa24,
- cckswing_table_ch14
- [(u8)cck_index][2]);
- rtl_write_byte(rtlpriv, 0xa25,
- cckswing_table_ch14
- [(u8)cck_index][3]);
- rtl_write_byte(rtlpriv, 0xa26,
- cckswing_table_ch14
- [(u8)cck_index][4]);
- rtl_write_byte(rtlpriv, 0xa27,
- cckswing_table_ch14
- [(u8)cck_index][5]);
- rtl_write_byte(rtlpriv, 0xa28,
- cckswing_table_ch14
- [(u8)cck_index][6]);
- rtl_write_byte(rtlpriv, 0xa29,
- cckswing_table_ch14
- [(u8)cck_index][7]);
- }
- }
- if (is2t) {
- ele_d = (ofdmswing_table[(u8) ofdm_index[1]] &
- 0xFFC00000) >> 22;
- val_x = rtlphy->iqk_matrix
- [indexforchannel].value[0][4];
- val_y = rtlphy->iqk_matrix
- [indexforchannel].value[0][5];
- if (val_x != 0) {
- if ((val_x & 0x00000200) != 0)
- /* consider minus */
- val_x = val_x | 0xFFFFFC00;
- ele_a = ((val_x * ele_d) >> 8) &
- 0x000003FF;
- /* new element C = element D x Y */
- if ((val_y & 0x00000200) != 0)
- val_y =
- val_y | 0xFFFFFC00;
- ele_c =
- ((val_y *
- ele_d) >> 8) & 0x00003FF;
- /* write new elements A, C, D to regC88
- * and regC9C, element B is always 0
- */
- value32 = (ele_d << 22) |
- ((ele_c & 0x3F) << 16) |
- ele_a;
- rtl_set_bbreg(hw,
- ROFDM0_XBTXIQIMBALANCE,
- MASKDWORD, value32);
- value32 = (ele_c & 0x000003C0) >> 6;
- rtl_set_bbreg(hw, ROFDM0_XDTXAFE,
- MASKH4BITS, value32);
- value32 = ((val_x * ele_d) >> 7) & 0x01;
- rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD,
- BIT(28), value32);
- } else {
- rtl_set_bbreg(hw,
- ROFDM0_XBTXIQIMBALANCE,
- MASKDWORD,
- ofdmswing_table
- [(u8) ofdm_index[1]]);
- rtl_set_bbreg(hw, ROFDM0_XDTXAFE,
- MASKH4BITS, 0x00);
- rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD,
- BIT(28), 0x00);
- }
- RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
- "TxPwrTracking path B: X = 0x%lx, Y = 0x%lx ele_A = 0x%lx ele_C = 0x%lx ele_D = 0x%lx 0xeb4 = 0x%lx 0xebc = 0x%lx\n",
- val_x, val_y, ele_a, ele_c,
- ele_d, val_x, val_y);
- }
- RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
- "TxPwrTracking 0xc80 = 0x%x, 0xc94 = 0x%x RF 0x24 = 0x%x\n",
- rtl_get_bbreg(hw, 0xc80, MASKDWORD),
- rtl_get_bbreg(hw, 0xc94, MASKDWORD),
- rtl_get_rfreg(hw, RF90_PATH_A, 0x24,
- RFREG_OFFSET_MASK));
- }
- if ((delta_iqk > rtlefuse->delta_iqk) &&
- (rtlefuse->delta_iqk != 0)) {
- rtl92d_phy_reset_iqk_result(hw);
- rtlpriv->dm.thermalvalue_iqk = thermalvalue;
- rtl92d_phy_iq_calibrate(hw);
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "TxPwrTracking for interface %d path A: X = 0x%lx, Y = 0x%lx ele_A = 0x%lx ele_C = 0x%lx ele_D = 0x%lx 0xe94 = 0x%lx 0xe9c = 0x%lx\n",
+ rtlhal->interfaceindex,
+ val_x, val_y, ele_a, ele_c, ele_d,
+ val_x, val_y);
+
+ if (cck_index >= CCK_TABLE_SIZE)
+ cck_index = CCK_TABLE_SIZE - 1;
+ if (cck_index < 0)
+ cck_index = 0;
+ if (rtlhal->current_bandtype == BAND_ON_2_4G) {
+ /* Adjust CCK according to IQK result */
+ if (!rtlpriv->dm.cck_inch14) {
+ rtl_write_byte(rtlpriv, 0xa22,
+ cckswing_table_ch1ch13[cck_index][0]);
+ rtl_write_byte(rtlpriv, 0xa23,
+ cckswing_table_ch1ch13[cck_index][1]);
+ rtl_write_byte(rtlpriv, 0xa24,
+ cckswing_table_ch1ch13[cck_index][2]);
+ rtl_write_byte(rtlpriv, 0xa25,
+ cckswing_table_ch1ch13[cck_index][3]);
+ rtl_write_byte(rtlpriv, 0xa26,
+ cckswing_table_ch1ch13[cck_index][4]);
+ rtl_write_byte(rtlpriv, 0xa27,
+ cckswing_table_ch1ch13[cck_index][5]);
+ rtl_write_byte(rtlpriv, 0xa28,
+ cckswing_table_ch1ch13[cck_index][6]);
+ rtl_write_byte(rtlpriv, 0xa29,
+ cckswing_table_ch1ch13[cck_index][7]);
+ } else {
+ rtl_write_byte(rtlpriv, 0xa22,
+ cckswing_table_ch14[cck_index][0]);
+ rtl_write_byte(rtlpriv, 0xa23,
+ cckswing_table_ch14[cck_index][1]);
+ rtl_write_byte(rtlpriv, 0xa24,
+ cckswing_table_ch14[cck_index][2]);
+ rtl_write_byte(rtlpriv, 0xa25,
+ cckswing_table_ch14[cck_index][3]);
+ rtl_write_byte(rtlpriv, 0xa26,
+ cckswing_table_ch14[cck_index][4]);
+ rtl_write_byte(rtlpriv, 0xa27,
+ cckswing_table_ch14[cck_index][5]);
+ rtl_write_byte(rtlpriv, 0xa28,
+ cckswing_table_ch14[cck_index][6]);
+ rtl_write_byte(rtlpriv, 0xa29,
+ cckswing_table_ch14[cck_index][7]);
}
- if (delta_rxgain > 0 && rtlhal->current_bandtype == BAND_ON_5G
- && thermalvalue <= rtlefuse->eeprom_thermalmeter) {
- rtlpriv->dm.thermalvalue_rxgain = thermalvalue;
- rtl92d_dm_rxgain_tracking_thermalmeter(hw);
+ }
+ if (is2t) {
+ ele_d = (ofdmswing_table[ofdm_index[1]] & 0xFFC00000) >> 22;
+ val_x = rtlphy->iqk_matrix[indexforchannel].value[0][4];
+ val_y = rtlphy->iqk_matrix[indexforchannel].value[0][5];
+ if (val_x != 0) {
+ if ((val_x & 0x00000200) != 0)
+ /* consider minus */
+ val_x = val_x | 0xFFFFFC00;
+ ele_a = ((val_x * ele_d) >> 8) & 0x000003FF;
+ /* new element C = element D x Y */
+ if ((val_y & 0x00000200) != 0)
+ val_y = val_y | 0xFFFFFC00;
+ ele_c = ((val_y * ele_d) >> 8) & 0x00003FF;
+ /* write new elements A, C, D to regC88
+ * and regC9C, element B is always 0
+ */
+ value32 = (ele_d << 22) | ((ele_c & 0x3F) << 16) | ele_a;
+ rtl_set_bbreg(hw,
+ ROFDM0_XBTXIQIMBALANCE,
+ MASKDWORD, value32);
+ value32 = (ele_c & 0x000003C0) >> 6;
+ rtl_set_bbreg(hw, ROFDM0_XDTXAFE,
+ MASKH4BITS, value32);
+ value32 = ((val_x * ele_d) >> 7) & 0x01;
+ rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD,
+ BIT(28), value32);
+ } else {
+ rtl_set_bbreg(hw,
+ ROFDM0_XBTXIQIMBALANCE,
+ MASKDWORD,
+ ofdmswing_table[ofdm_index[1]]);
+ rtl_set_bbreg(hw, ROFDM0_XDTXAFE,
+ MASKH4BITS, 0x00);
+ rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD,
+ BIT(28), 0x00);
}
- if (rtlpriv->dm.txpower_track_control)
- rtlpriv->dm.thermalvalue = thermalvalue;
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "TxPwrTracking path B: X = 0x%lx, Y = 0x%lx ele_A = 0x%lx ele_C = 0x%lx ele_D = 0x%lx 0xeb4 = 0x%lx 0xebc = 0x%lx\n",
+ val_x, val_y, ele_a, ele_c,
+ ele_d, val_x, val_y);
+ }
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "TxPwrTracking 0xc80 = 0x%x, 0xc94 = 0x%x RF 0x24 = 0x%x\n",
+ rtl_get_bbreg(hw, 0xc80, MASKDWORD),
+ rtl_get_bbreg(hw, 0xc94, MASKDWORD),
+ rtl_get_rfreg(hw, RF90_PATH_A, 0x24,
+ RFREG_OFFSET_MASK));
+
+check_delta:
+ if (delta_iqk > rtlefuse->delta_iqk && rtlefuse->delta_iqk != 0) {
+ rtl92d_phy_reset_iqk_result(hw);
+ rtlpriv->dm.thermalvalue_iqk = thermalvalue;
+ rtl92d_phy_iq_calibrate(hw);
}
+ if (delta_rxgain > 0 && rtlhal->current_bandtype == BAND_ON_5G &&
+ thermalvalue <= rtlefuse->eeprom_thermalmeter) {
+ rtlpriv->dm.thermalvalue_rxgain = thermalvalue;
+ rtl92d_dm_rxgain_tracking_thermalmeter(hw);
+ }
+ if (rtlpriv->dm.txpower_track_control)
+ rtlpriv->dm.thermalvalue = thermalvalue;
+exit:
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, "<===\n");
}
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c
index 49d05b631ba1..b54230433a6b 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c
@@ -655,10 +655,9 @@ static void rtl8821ae_dm_check_rssi_monitor(struct ieee80211_hw *hw)
u8 h2c_parameter[4] = { 0 };
long tmp_entry_max_pwdb = 0, tmp_entry_min_pwdb = 0xff;
u8 stbc_tx = 0;
- u64 cur_txokcnt = 0, cur_rxokcnt = 0;
+ u64 cur_rxokcnt = 0;
static u64 last_txokcnt = 0, last_rxokcnt;
- cur_txokcnt = rtlpriv->stats.txbytesunicast - last_txokcnt;
cur_rxokcnt = rtlpriv->stats.rxbytesunicast - last_rxokcnt;
last_txokcnt = rtlpriv->stats.txbytesunicast;
last_rxokcnt = rtlpriv->stats.rxbytesunicast;
@@ -2654,7 +2653,6 @@ static void rtl8821ae_dm_check_edca_turbo(struct ieee80211_hw *hw)
u32 edca_be = 0x5ea42b;
u8 iot_peer = 0;
bool *pb_is_cur_rdl_state = NULL;
- bool b_last_is_cur_rdl_state = false;
bool b_bias_on_rx = false;
bool b_edca_turbo_on = false;
@@ -2672,7 +2670,6 @@ static void rtl8821ae_dm_check_edca_turbo(struct ieee80211_hw *hw)
* list paramter for different platform
*===============================
*/
- b_last_is_cur_rdl_state = rtlpriv->dm.is_cur_rdlstate;
pb_is_cur_rdl_state = &rtlpriv->dm.is_cur_rdlstate;
cur_tx_ok_cnt = rtlpriv->stats.txbytesunicast - rtldm->last_tx_ok_cnt;
@@ -2958,10 +2955,11 @@ void rtl8821ae_dm_set_tx_ant_by_tx_info(struct ieee80211_hw *hw,
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
struct fast_ant_training *pfat_table = &rtldm->fat_table;
+ __le32 *pdesc32 = (__le32 *)pdesc;
if (rtlhal->hw_type != HARDWARE_TYPE_RTL8812AE)
return;
if (rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV)
- SET_TX_DESC_TX_ANT(pdesc, pfat_table->antsel_a[mac_id]);
+ set_tx_desc_tx_ant(pdesc32, pfat_table->antsel_a[mac_id]);
}
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c
index 7b6faf38e09c..cd809c992245 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c
@@ -56,7 +56,7 @@ static u8 _rtl8821ae_evm_dbm_jaguar(s8 value)
}
static void query_rxphystatus(struct ieee80211_hw *hw,
- struct rtl_stats *pstatus, u8 *pdesc,
+ struct rtl_stats *pstatus, __le32 *pdesc,
struct rx_fwinfo_8821ae *p_drvinfo,
bool bpacket_match_bssid,
bool bpacket_toself, bool packet_beacon)
@@ -274,7 +274,7 @@ static void query_rxphystatus(struct ieee80211_hw *hw,
static void translate_rx_signal_stuff(struct ieee80211_hw *hw,
struct sk_buff *skb,
- struct rtl_stats *pstatus, u8 *pdesc,
+ struct rtl_stats *pstatus, __le32 *pdesc,
struct rx_fwinfo_8821ae *p_drvinfo)
{
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
@@ -332,14 +332,14 @@ static void translate_rx_signal_stuff(struct ieee80211_hw *hw,
rtl_process_phyinfo(hw, tmp_buf, pstatus);
}
-static void _rtl8821ae_insert_emcontent(struct rtl_tcb_desc *ptcb_desc,
- u8 *virtualaddress)
+static void rtl8821ae_insert_emcontent(struct rtl_tcb_desc *ptcb_desc,
+ __le32 *virtualaddress)
{
u32 dwtmp = 0;
memset(virtualaddress, 0, 8);
- SET_EARLYMODE_PKTNUM(virtualaddress, ptcb_desc->empkt_num);
+ set_earlymode_pktnum(virtualaddress, ptcb_desc->empkt_num);
if (ptcb_desc->empkt_num == 1) {
dwtmp = ptcb_desc->empkt_len[0];
} else {
@@ -347,7 +347,7 @@ static void _rtl8821ae_insert_emcontent(struct rtl_tcb_desc *ptcb_desc,
dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0)+4;
dwtmp += ptcb_desc->empkt_len[1];
}
- SET_EARLYMODE_LEN0(virtualaddress, dwtmp);
+ set_earlymode_len0(virtualaddress, dwtmp);
if (ptcb_desc->empkt_num <= 3) {
dwtmp = ptcb_desc->empkt_len[2];
@@ -356,7 +356,7 @@ static void _rtl8821ae_insert_emcontent(struct rtl_tcb_desc *ptcb_desc,
dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0)+4;
dwtmp += ptcb_desc->empkt_len[3];
}
- SET_EARLYMODE_LEN1(virtualaddress, dwtmp);
+ set_earlymode_len1(virtualaddress, dwtmp);
if (ptcb_desc->empkt_num <= 5) {
dwtmp = ptcb_desc->empkt_len[4];
} else {
@@ -364,8 +364,8 @@ static void _rtl8821ae_insert_emcontent(struct rtl_tcb_desc *ptcb_desc,
dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0)+4;
dwtmp += ptcb_desc->empkt_len[5];
}
- SET_EARLYMODE_LEN2_1(virtualaddress, dwtmp & 0xF);
- SET_EARLYMODE_LEN2_2(virtualaddress, dwtmp >> 4);
+ set_earlymode_len2_1(virtualaddress, dwtmp & 0xF);
+ set_earlymode_len2_2(virtualaddress, dwtmp >> 4);
if (ptcb_desc->empkt_num <= 7) {
dwtmp = ptcb_desc->empkt_len[6];
} else {
@@ -373,7 +373,7 @@ static void _rtl8821ae_insert_emcontent(struct rtl_tcb_desc *ptcb_desc,
dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0)+4;
dwtmp += ptcb_desc->empkt_len[7];
}
- SET_EARLYMODE_LEN3(virtualaddress, dwtmp);
+ set_earlymode_len3(virtualaddress, dwtmp);
if (ptcb_desc->empkt_num <= 9) {
dwtmp = ptcb_desc->empkt_len[8];
} else {
@@ -381,15 +381,15 @@ static void _rtl8821ae_insert_emcontent(struct rtl_tcb_desc *ptcb_desc,
dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0)+4;
dwtmp += ptcb_desc->empkt_len[9];
}
- SET_EARLYMODE_LEN4(virtualaddress, dwtmp);
+ set_earlymode_len4(virtualaddress, dwtmp);
}
-static bool rtl8821ae_get_rxdesc_is_ht(struct ieee80211_hw *hw, u8 *pdesc)
+static bool rtl8821ae_get_rxdesc_is_ht(struct ieee80211_hw *hw, __le32 *pdesc)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u8 rx_rate = 0;
- rx_rate = GET_RX_DESC_RXMCS(pdesc);
+ rx_rate = get_rx_desc_rxmcs(pdesc);
RT_TRACE(rtlpriv, COMP_RXDESC, DBG_LOUD, "rx_rate=0x%02x.\n", rx_rate);
@@ -398,12 +398,12 @@ static bool rtl8821ae_get_rxdesc_is_ht(struct ieee80211_hw *hw, u8 *pdesc)
return false;
}
-static bool rtl8821ae_get_rxdesc_is_vht(struct ieee80211_hw *hw, u8 *pdesc)
+static bool rtl8821ae_get_rxdesc_is_vht(struct ieee80211_hw *hw, __le32 *pdesc)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u8 rx_rate = 0;
- rx_rate = GET_RX_DESC_RXMCS(pdesc);
+ rx_rate = get_rx_desc_rxmcs(pdesc);
RT_TRACE(rtlpriv, COMP_RXDESC, DBG_LOUD, "rx_rate=0x%02x.\n", rx_rate);
@@ -412,12 +412,12 @@ static bool rtl8821ae_get_rxdesc_is_vht(struct ieee80211_hw *hw, u8 *pdesc)
return false;
}
-static u8 rtl8821ae_get_rx_vht_nss(struct ieee80211_hw *hw, u8 *pdesc)
+static u8 rtl8821ae_get_rx_vht_nss(struct ieee80211_hw *hw, __le32 *pdesc)
{
u8 rx_rate = 0;
u8 vht_nss = 0;
- rx_rate = GET_RX_DESC_RXMCS(pdesc);
+ rx_rate = get_rx_desc_rxmcs(pdesc);
if ((rx_rate >= DESC_RATEVHT1SS_MCS0) &&
(rx_rate <= DESC_RATEVHT1SS_MCS9))
vht_nss = 1;
@@ -431,30 +431,31 @@ static u8 rtl8821ae_get_rx_vht_nss(struct ieee80211_hw *hw, u8 *pdesc)
bool rtl8821ae_rx_query_desc(struct ieee80211_hw *hw,
struct rtl_stats *status,
struct ieee80211_rx_status *rx_status,
- u8 *pdesc, struct sk_buff *skb)
+ u8 *pdesc8, struct sk_buff *skb)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rx_fwinfo_8821ae *p_drvinfo;
struct ieee80211_hdr *hdr;
u8 wake_match;
- u32 phystatus = GET_RX_DESC_PHYST(pdesc);
+ __le32 *pdesc = (__le32 *)pdesc8;
+ u32 phystatus = get_rx_desc_physt(pdesc);
- status->length = (u16)GET_RX_DESC_PKT_LEN(pdesc);
- status->rx_drvinfo_size = (u8)GET_RX_DESC_DRV_INFO_SIZE(pdesc) *
+ status->length = (u16)get_rx_desc_pkt_len(pdesc);
+ status->rx_drvinfo_size = (u8)get_rx_desc_drv_info_size(pdesc) *
RX_DRV_INFO_SIZE_UNIT;
- status->rx_bufshift = (u8)(GET_RX_DESC_SHIFT(pdesc) & 0x03);
- status->icv = (u16)GET_RX_DESC_ICV(pdesc);
- status->crc = (u16)GET_RX_DESC_CRC32(pdesc);
+ status->rx_bufshift = (u8)(get_rx_desc_shift(pdesc) & 0x03);
+ status->icv = (u16)get_rx_desc_icv(pdesc);
+ status->crc = (u16)get_rx_desc_crc32(pdesc);
status->hwerror = (status->crc | status->icv);
- status->decrypted = !GET_RX_DESC_SWDEC(pdesc);
- status->rate = (u8)GET_RX_DESC_RXMCS(pdesc);
- status->shortpreamble = (u16)GET_RX_DESC_SPLCP(pdesc);
- status->isampdu = (bool)(GET_RX_DESC_PAGGR(pdesc) == 1);
- status->isfirst_ampdu = (bool)(GET_RX_DESC_PAGGR(pdesc) == 1);
- status->timestamp_low = GET_RX_DESC_TSFL(pdesc);
- status->rx_packet_bw = GET_RX_DESC_BW(pdesc);
- status->macid = GET_RX_DESC_MACID(pdesc);
- status->is_short_gi = !(bool)GET_RX_DESC_SPLCP(pdesc);
+ status->decrypted = !get_rx_desc_swdec(pdesc);
+ status->rate = (u8)get_rx_desc_rxmcs(pdesc);
+ status->shortpreamble = (u16)get_rx_desc_splcp(pdesc);
+ status->isampdu = (bool)(get_rx_desc_paggr(pdesc) == 1);
+ status->isfirst_ampdu = (bool)(get_rx_desc_paggr(pdesc) == 1);
+ status->timestamp_low = get_rx_desc_tsfl(pdesc);
+ status->rx_packet_bw = get_rx_desc_bw(pdesc);
+ status->macid = get_rx_desc_macid(pdesc);
+ status->is_short_gi = !(bool)get_rx_desc_splcp(pdesc);
status->is_ht = rtl8821ae_get_rxdesc_is_ht(hw, pdesc);
status->is_vht = rtl8821ae_get_rxdesc_is_vht(hw, pdesc);
status->vht_nss = rtl8821ae_get_rx_vht_nss(hw, pdesc);
@@ -467,16 +468,16 @@ bool rtl8821ae_rx_query_desc(struct ieee80211_hw *hw,
status->is_ht, status->is_vht, status->vht_nss,
status->is_short_gi);
- if (GET_RX_STATUS_DESC_RPT_SEL(pdesc))
+ if (get_rx_status_desc_rpt_sel(pdesc))
status->packet_report_type = C2H_PACKET;
else
status->packet_report_type = NORMAL_RX;
- if (GET_RX_STATUS_DESC_PATTERN_MATCH(pdesc))
+ if (get_rx_status_desc_pattern_match(pdesc))
wake_match = BIT(2);
- else if (GET_RX_STATUS_DESC_MAGIC_MATCH(pdesc))
+ else if (get_rx_status_desc_magic_match(pdesc))
wake_match = BIT(1);
- else if (GET_RX_STATUS_DESC_UNICAST_MATCH(pdesc))
+ else if (get_rx_status_desc_unicast_match(pdesc))
wake_match = BIT(0);
else
wake_match = 0;
@@ -543,9 +544,9 @@ bool rtl8821ae_rx_query_desc(struct ieee80211_hw *hw,
rx_status->signal = status->recvsignalpower + 10;
if (status->packet_report_type == TX_REPORT2) {
status->macid_valid_entry[0] =
- GET_RX_RPT2_DESC_MACID_VALID_1(pdesc);
+ get_rx_rpt2_desc_macid_valid_1(pdesc);
status->macid_valid_entry[1] =
- GET_RX_RPT2_DESC_MACID_VALID_2(pdesc);
+ get_rx_rpt2_desc_macid_valid_2(pdesc);
}
return true;
}
@@ -656,7 +657,7 @@ static u8 rtl8821ae_sc_mapping(struct ieee80211_hw *hw,
}
void rtl8821ae_tx_fill_desc(struct ieee80211_hw *hw,
- struct ieee80211_hdr *hdr, u8 *pdesc_tx, u8 *txbd,
+ struct ieee80211_hdr *hdr, u8 *pdesc8, u8 *txbd,
struct ieee80211_tx_info *info,
struct ieee80211_sta *sta,
struct sk_buff *skb,
@@ -667,7 +668,6 @@ void rtl8821ae_tx_fill_desc(struct ieee80211_hw *hw,
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
struct rtlwifi_tx_info *tx_info = rtl_tx_skb_cb_info(skb);
- u8 *pdesc = (u8 *)pdesc_tx;
u16 seq_number;
__le16 fc = hdr->frame_control;
unsigned int buf_len = 0;
@@ -679,6 +679,8 @@ void rtl8821ae_tx_fill_desc(struct ieee80211_hw *hw,
cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) == 0);
dma_addr_t mapping;
u8 short_gi = 0;
+ bool tmp_bool;
+ __le32 *pdesc = (__le32 *)pdesc8;
seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc);
@@ -695,69 +697,70 @@ void rtl8821ae_tx_fill_desc(struct ieee80211_hw *hw,
"DMA mapping error\n");
return;
}
- CLEAR_PCI_TX_DESC_CONTENT(pdesc, sizeof(struct tx_desc_8821ae));
+ clear_pci_tx_desc_content(pdesc, sizeof(struct tx_desc_8821ae));
if (ieee80211_is_nullfunc(fc) || ieee80211_is_ctl(fc)) {
firstseg = true;
lastseg = true;
}
if (firstseg) {
if (rtlhal->earlymode_enable) {
- SET_TX_DESC_PKT_OFFSET(pdesc, 1);
- SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN +
+ set_tx_desc_pkt_offset(pdesc, 1);
+ set_tx_desc_offset(pdesc, USB_HWDESC_HEADER_LEN +
EM_HDR_LEN);
if (ptcb_desc->empkt_num) {
RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
"Insert 8 byte.pTcb->EMPktNum:%d\n",
ptcb_desc->empkt_num);
- _rtl8821ae_insert_emcontent(ptcb_desc,
- (u8 *)(skb->data));
+ rtl8821ae_insert_emcontent(ptcb_desc,
+ (__le32 *)skb->data);
}
} else {
- SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN);
+ set_tx_desc_offset(pdesc, USB_HWDESC_HEADER_LEN);
}
/* ptcb_desc->use_driver_rate = true; */
- SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate);
+ set_tx_desc_tx_rate(pdesc, ptcb_desc->hw_rate);
if (ptcb_desc->hw_rate > DESC_RATEMCS0)
short_gi = (ptcb_desc->use_shortgi) ? 1 : 0;
else
short_gi = (ptcb_desc->use_shortpreamble) ? 1 : 0;
- SET_TX_DESC_DATA_SHORTGI(pdesc, short_gi);
+ set_tx_desc_data_shortgi(pdesc, short_gi);
if (info->flags & IEEE80211_TX_CTL_AMPDU) {
- SET_TX_DESC_AGG_ENABLE(pdesc, 1);
- SET_TX_DESC_MAX_AGG_NUM(pdesc, 0x1f);
+ set_tx_desc_agg_enable(pdesc, 1);
+ set_tx_desc_max_agg_num(pdesc, 0x1f);
}
- SET_TX_DESC_SEQ(pdesc, seq_number);
- SET_TX_DESC_RTS_ENABLE(pdesc, ((ptcb_desc->rts_enable &&
+ set_tx_desc_seq(pdesc, seq_number);
+ set_tx_desc_rts_enable(pdesc,
+ ((ptcb_desc->rts_enable &&
!ptcb_desc->cts_enable) ? 1 : 0));
- SET_TX_DESC_HW_RTS_ENABLE(pdesc, 0);
- SET_TX_DESC_CTS2SELF(pdesc, ((ptcb_desc->cts_enable) ? 1 : 0));
+ set_tx_desc_hw_rts_enable(pdesc, 0);
+ set_tx_desc_cts2self(pdesc, ((ptcb_desc->cts_enable) ? 1 : 0));
- SET_TX_DESC_RTS_RATE(pdesc, ptcb_desc->rts_rate);
- SET_TX_DESC_RTS_SC(pdesc, ptcb_desc->rts_sc);
- SET_TX_DESC_RTS_SHORT(pdesc,
- ((ptcb_desc->rts_rate <= DESC_RATE54M) ?
- (ptcb_desc->rts_use_shortpreamble ? 1 : 0) :
- (ptcb_desc->rts_use_shortgi ? 1 : 0)));
+ set_tx_desc_rts_rate(pdesc, ptcb_desc->rts_rate);
+ set_tx_desc_rts_sc(pdesc, ptcb_desc->rts_sc);
+ tmp_bool = ((ptcb_desc->rts_rate <= DESC_RATE54M) ?
+ (ptcb_desc->rts_use_shortpreamble ? 1 : 0) :
+ (ptcb_desc->rts_use_shortgi ? 1 : 0));
+ set_tx_desc_rts_short(pdesc, tmp_bool);
if (ptcb_desc->tx_enable_sw_calc_duration)
- SET_TX_DESC_NAV_USE_HDR(pdesc, 1);
+ set_tx_desc_nav_use_hdr(pdesc, 1);
- SET_TX_DESC_DATA_BW(pdesc,
- rtl8821ae_bw_mapping(hw, ptcb_desc));
+ set_tx_desc_data_bw(pdesc,
+ rtl8821ae_bw_mapping(hw, ptcb_desc));
- SET_TX_DESC_TX_SUB_CARRIER(pdesc,
- rtl8821ae_sc_mapping(hw, ptcb_desc));
+ set_tx_desc_tx_sub_carrier(pdesc,
+ rtl8821ae_sc_mapping(hw, ptcb_desc));
- SET_TX_DESC_LINIP(pdesc, 0);
- SET_TX_DESC_PKT_SIZE(pdesc, (u16)skb_len);
+ set_tx_desc_linip(pdesc, 0);
+ set_tx_desc_pkt_size(pdesc, (u16)skb_len);
if (sta) {
u8 ampdu_density = sta->ht_cap.ampdu_density;
- SET_TX_DESC_AMPDU_DENSITY(pdesc, ampdu_density);
+ set_tx_desc_ampdu_density(pdesc, ampdu_density);
}
if (info->control.hw_key) {
struct ieee80211_key_conf *keyconf =
@@ -766,69 +769,70 @@ void rtl8821ae_tx_fill_desc(struct ieee80211_hw *hw,
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
case WLAN_CIPHER_SUITE_TKIP:
- SET_TX_DESC_SEC_TYPE(pdesc, 0x1);
+ set_tx_desc_sec_type(pdesc, 0x1);
break;
case WLAN_CIPHER_SUITE_CCMP:
- SET_TX_DESC_SEC_TYPE(pdesc, 0x3);
+ set_tx_desc_sec_type(pdesc, 0x3);
break;
default:
- SET_TX_DESC_SEC_TYPE(pdesc, 0x0);
+ set_tx_desc_sec_type(pdesc, 0x0);
break;
}
}
- SET_TX_DESC_QUEUE_SEL(pdesc, fw_qsel);
- SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F);
- SET_TX_DESC_RTS_RATE_FB_LIMIT(pdesc, 0xF);
- SET_TX_DESC_DISABLE_FB(pdesc, ptcb_desc->disable_ratefallback ?
+ set_tx_desc_queue_sel(pdesc, fw_qsel);
+ set_tx_desc_data_rate_fb_limit(pdesc, 0x1F);
+ set_tx_desc_rts_rate_fb_limit(pdesc, 0xF);
+ set_tx_desc_disable_fb(pdesc, ptcb_desc->disable_ratefallback ?
1 : 0);
- SET_TX_DESC_USE_RATE(pdesc, ptcb_desc->use_driver_rate ? 1 : 0);
+ set_tx_desc_use_rate(pdesc, ptcb_desc->use_driver_rate ? 1 : 0);
if (ieee80211_is_data_qos(fc)) {
if (mac->rdg_en) {
RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
"Enable RDG function.\n");
- SET_TX_DESC_RDG_ENABLE(pdesc, 1);
- SET_TX_DESC_HTC(pdesc, 1);
+ set_tx_desc_rdg_enable(pdesc, 1);
+ set_tx_desc_htc(pdesc, 1);
}
}
/* tx report */
- rtl_set_tx_report(ptcb_desc, pdesc, hw, tx_info);
+ rtl_set_tx_report(ptcb_desc, pdesc8, hw, tx_info);
}
- SET_TX_DESC_FIRST_SEG(pdesc, (firstseg ? 1 : 0));
- SET_TX_DESC_LAST_SEG(pdesc, (lastseg ? 1 : 0));
- SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)buf_len);
- SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping);
+ set_tx_desc_first_seg(pdesc, (firstseg ? 1 : 0));
+ set_tx_desc_last_seg(pdesc, (lastseg ? 1 : 0));
+ set_tx_desc_tx_buffer_size(pdesc, buf_len);
+ set_tx_desc_tx_buffer_address(pdesc, mapping);
/* if (rtlpriv->dm.useramask) { */
if (1) {
- SET_TX_DESC_RATE_ID(pdesc, ptcb_desc->ratr_index);
- SET_TX_DESC_MACID(pdesc, ptcb_desc->mac_id);
+ set_tx_desc_rate_id(pdesc, ptcb_desc->ratr_index);
+ set_tx_desc_macid(pdesc, ptcb_desc->mac_id);
} else {
- SET_TX_DESC_RATE_ID(pdesc, 0xC + ptcb_desc->ratr_index);
- SET_TX_DESC_MACID(pdesc, ptcb_desc->mac_id);
+ set_tx_desc_rate_id(pdesc, 0xC + ptcb_desc->ratr_index);
+ set_tx_desc_macid(pdesc, ptcb_desc->mac_id);
}
if (!ieee80211_is_data_qos(fc)) {
- SET_TX_DESC_HWSEQ_EN(pdesc, 1);
- SET_TX_DESC_HWSEQ_SEL(pdesc, 0);
+ set_tx_desc_hwseq_en(pdesc, 1);
+ set_tx_desc_hwseq_sel(pdesc, 0);
}
- SET_TX_DESC_MORE_FRAG(pdesc, (lastseg ? 0 : 1));
+ set_tx_desc_more_frag(pdesc, (lastseg ? 0 : 1));
if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) ||
is_broadcast_ether_addr(ieee80211_get_DA(hdr))) {
- SET_TX_DESC_BMC(pdesc, 1);
+ set_tx_desc_bmc(pdesc, 1);
}
- rtl8821ae_dm_set_tx_ant_by_tx_info(hw, pdesc, ptcb_desc->mac_id);
+ rtl8821ae_dm_set_tx_ant_by_tx_info(hw, pdesc8, ptcb_desc->mac_id);
RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, "\n");
}
void rtl8821ae_tx_fill_cmddesc(struct ieee80211_hw *hw,
- u8 *pdesc, bool firstseg,
+ u8 *pdesc8, bool firstseg,
bool lastseg, struct sk_buff *skb)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
u8 fw_queue = QSLT_BEACON;
+ __le32 *pdesc = (__le32 *)pdesc8;
dma_addr_t mapping = pci_map_single(rtlpci->pdev,
skb->data, skb->len,
@@ -839,48 +843,50 @@ void rtl8821ae_tx_fill_cmddesc(struct ieee80211_hw *hw,
"DMA mapping error\n");
return;
}
- CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE);
+ clear_pci_tx_desc_content(pdesc, TX_DESC_SIZE);
- SET_TX_DESC_FIRST_SEG(pdesc, 1);
- SET_TX_DESC_LAST_SEG(pdesc, 1);
+ set_tx_desc_first_seg(pdesc, 1);
+ set_tx_desc_last_seg(pdesc, 1);
- SET_TX_DESC_PKT_SIZE((u8 *)pdesc, (u16)(skb->len));
+ set_tx_desc_pkt_size(pdesc, (u16)(skb->len));
- SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN);
+ set_tx_desc_offset(pdesc, USB_HWDESC_HEADER_LEN);
- SET_TX_DESC_USE_RATE(pdesc, 1);
- SET_TX_DESC_TX_RATE(pdesc, DESC_RATE1M);
- SET_TX_DESC_DISABLE_FB(pdesc, 1);
+ set_tx_desc_use_rate(pdesc, 1);
+ set_tx_desc_tx_rate(pdesc, DESC_RATE1M);
+ set_tx_desc_disable_fb(pdesc, 1);
- SET_TX_DESC_DATA_BW(pdesc, 0);
+ set_tx_desc_data_bw(pdesc, 0);
- SET_TX_DESC_HWSEQ_EN(pdesc, 1);
+ set_tx_desc_hwseq_en(pdesc, 1);
- SET_TX_DESC_QUEUE_SEL(pdesc, fw_queue);
+ set_tx_desc_queue_sel(pdesc, fw_queue);
- SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len));
+ set_tx_desc_tx_buffer_size(pdesc, skb->len);
- SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping);
+ set_tx_desc_tx_buffer_address(pdesc, mapping);
- SET_TX_DESC_MACID(pdesc, 0);
+ set_tx_desc_macid(pdesc, 0);
- SET_TX_DESC_OWN(pdesc, 1);
+ set_tx_desc_own(pdesc, 1);
RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
"H2C Tx Cmd Content\n",
- pdesc, TX_DESC_SIZE);
+ pdesc8, TX_DESC_SIZE);
}
-void rtl8821ae_set_desc(struct ieee80211_hw *hw, u8 *pdesc,
+void rtl8821ae_set_desc(struct ieee80211_hw *hw, u8 *pdesc8,
bool istx, u8 desc_name, u8 *val)
{
+ __le32 *pdesc = (__le32 *)pdesc8;
+
if (istx) {
switch (desc_name) {
case HW_DESC_OWN:
- SET_TX_DESC_OWN(pdesc, 1);
+ set_tx_desc_own(pdesc, 1);
break;
case HW_DESC_TX_NEXTDESC_ADDR:
- SET_TX_DESC_NEXT_DESC_ADDRESS(pdesc, *(u32 *)val);
+ set_tx_desc_next_desc_address(pdesc, *(u32 *)val);
break;
default:
WARN_ONCE(true,
@@ -891,16 +897,16 @@ void rtl8821ae_set_desc(struct ieee80211_hw *hw, u8 *pdesc,
} else {
switch (desc_name) {
case HW_DESC_RXOWN:
- SET_RX_DESC_OWN(pdesc, 1);
+ set_rx_desc_own(pdesc, 1);
break;
case HW_DESC_RXBUFF_ADDR:
- SET_RX_DESC_BUFF_ADDR(pdesc, *(u32 *)val);
+ set_rx_desc_buff_addr(pdesc, *(u32 *)val);
break;
case HW_DESC_RXPKT_LEN:
- SET_RX_DESC_PKT_LEN(pdesc, *(u32 *)val);
+ set_rx_desc_pkt_len(pdesc, *(u32 *)val);
break;
case HW_DESC_RXERO:
- SET_RX_DESC_EOR(pdesc, 1);
+ set_rx_desc_eor(pdesc, 1);
break;
default:
WARN_ONCE(true,
@@ -912,17 +918,18 @@ void rtl8821ae_set_desc(struct ieee80211_hw *hw, u8 *pdesc,
}
u64 rtl8821ae_get_desc(struct ieee80211_hw *hw,
- u8 *pdesc, bool istx, u8 desc_name)
+ u8 *pdesc8, bool istx, u8 desc_name)
{
u32 ret = 0;
+ __le32 *pdesc = (__le32 *)pdesc8;
if (istx) {
switch (desc_name) {
case HW_DESC_OWN:
- ret = GET_TX_DESC_OWN(pdesc);
+ ret = get_tx_desc_own(pdesc);
break;
case HW_DESC_TXBUFF_ADDR:
- ret = GET_TX_DESC_TX_BUFFER_ADDRESS(pdesc);
+ ret = get_tx_desc_tx_buffer_address(pdesc);
break;
default:
WARN_ONCE(true,
@@ -933,13 +940,13 @@ u64 rtl8821ae_get_desc(struct ieee80211_hw *hw,
} else {
switch (desc_name) {
case HW_DESC_OWN:
- ret = GET_RX_DESC_OWN(pdesc);
+ ret = get_rx_desc_own(pdesc);
break;
case HW_DESC_RXPKT_LEN:
- ret = GET_RX_DESC_PKT_LEN(pdesc);
+ ret = get_rx_desc_pkt_len(pdesc);
break;
case HW_DESC_RXBUFF_ADDR:
- ret = GET_RX_DESC_BUFF_ADDR(pdesc);
+ ret = get_rx_desc_buff_addr(pdesc);
break;
default:
WARN_ONCE(true,
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.h b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.h
index a3feecad645d..81951f0c80b6 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.h
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.h
@@ -14,341 +14,385 @@
#define USB_HWDESC_HEADER_LEN 40
#define CRCLENGTH 4
-#define SET_TX_DESC_PKT_SIZE(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc, 0, 16, __val)
-#define SET_TX_DESC_OFFSET(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc, 16, 8, __val)
-#define SET_TX_DESC_BMC(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc, 24, 1, __val)
-#define SET_TX_DESC_HTC(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc, 25, 1, __val)
-#define SET_TX_DESC_LAST_SEG(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc, 26, 1, __val)
-#define SET_TX_DESC_FIRST_SEG(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc, 27, 1, __val)
-#define SET_TX_DESC_LINIP(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc, 28, 1, __val)
-#define SET_TX_DESC_NO_ACM(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc, 29, 1, __val)
-#define SET_TX_DESC_GF(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val)
-#define SET_TX_DESC_OWN(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val)
-
-#define GET_TX_DESC_PKT_SIZE(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc, 0, 16)
-#define GET_TX_DESC_OFFSET(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc, 16, 8)
-#define GET_TX_DESC_BMC(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc, 24, 1)
-#define GET_TX_DESC_HTC(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc, 25, 1)
-#define GET_TX_DESC_LAST_SEG(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc, 26, 1)
-#define GET_TX_DESC_FIRST_SEG(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc, 27, 1)
-#define GET_TX_DESC_LINIP(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc, 28, 1)
-#define GET_TX_DESC_NO_ACM(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc, 29, 1)
-#define GET_TX_DESC_GF(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc, 30, 1)
-#define GET_TX_DESC_OWN(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc, 31, 1)
-
-#define SET_TX_DESC_MACID(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+4, 0, 7, __val)
-#define SET_TX_DESC_QUEUE_SEL(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+4, 8, 5, __val)
-#define SET_TX_DESC_RDG_NAV_EXT(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+4, 13, 1, __val)
-#define SET_TX_DESC_LSIG_TXOP_EN(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+4, 14, 1, __val)
-#define SET_TX_DESC_PIFS(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+4, 15, 1, __val)
-#define SET_TX_DESC_RATE_ID(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+4, 16, 5, __val)
-#define SET_TX_DESC_EN_DESC_ID(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+4, 21, 1, __val)
-#define SET_TX_DESC_SEC_TYPE(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+4, 22, 2, __val)
-#define SET_TX_DESC_PKT_OFFSET(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+4, 24, 5, __val)
-
-#define SET_TX_DESC_PAID(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+8, 0, 9, __val)
-#define SET_TX_DESC_CCA_RTS(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+8, 10, 2, __val)
-#define SET_TX_DESC_AGG_ENABLE(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+8, 12, 1, __val)
-#define SET_TX_DESC_RDG_ENABLE(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+8, 13, 1, __val)
-#define SET_TX_DESC_BAR_RTY_TH(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+8, 14, 2, __val)
-#define SET_TX_DESC_AGG_BREAK(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+8, 16, 1, __val)
-#define SET_TX_DESC_MORE_FRAG(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+8, 17, 1, __val)
-#define SET_TX_DESC_RAW(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+8, 18, 1, __val)
-#define SET_TX_DESC_SPE_RPT(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE((__pdesc) + 8, 19, 1, __val)
-#define SET_TX_DESC_AMPDU_DENSITY(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+8, 20, 3, __val)
-#define SET_TX_DESC_BT_INT(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+8, 23, 1, __val)
-#define SET_TX_DESC_GID(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+8, 24, 6, __val)
-
-#define SET_TX_DESC_WHEADER_LEN(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+12, 0, 4, __val)
-#define SET_TX_DESC_CHK_EN(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+12, 4, 1, __val)
-#define SET_TX_DESC_EARLY_MODE(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+12, 5, 1, __val)
-#define SET_TX_DESC_HWSEQ_SEL(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+12, 6, 2, __val)
-#define SET_TX_DESC_USE_RATE(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+12, 8, 1, __val)
-#define SET_TX_DESC_DISABLE_RTS_FB(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+12, 9, 1, __val)
-#define SET_TX_DESC_DISABLE_FB(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+12, 10, 1, __val)
-#define SET_TX_DESC_CTS2SELF(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+12, 11, 1, __val)
-#define SET_TX_DESC_RTS_ENABLE(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+12, 12, 1, __val)
-#define SET_TX_DESC_HW_RTS_ENABLE(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+12, 13, 1, __val)
-#define SET_TX_DESC_NAV_USE_HDR(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+12, 15, 1, __val)
-#define SET_TX_DESC_USE_MAX_LEN(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+12, 16, 1, __val)
-#define SET_TX_DESC_MAX_AGG_NUM(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+12, 17, 5, __val)
-#define SET_TX_DESC_NDPA(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+12, 22, 2, __val)
-#define SET_TX_DESC_AMPDU_MAX_TIME(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+12, 24, 8, __val)
-#define SET_TX_DESC_TX_ANT(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+20, 24, 4, __val)
-
-#define SET_TX_DESC_TX_RATE(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+16, 0, 7, __val)
-#define SET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+16, 8, 5, __val)
-#define SET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+16, 13, 4, __val)
-#define SET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+16, 17, 1, __val)
-#define SET_TX_DESC_DATA_RETRY_LIMIT(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+16, 18, 6, __val)
-#define SET_TX_DESC_RTS_RATE(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+16, 24, 5, __val)
-
-#define SET_TX_DESC_TX_SUB_CARRIER(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+20, 0, 4, __val)
-#define SET_TX_DESC_DATA_SHORTGI(__pdesc, __val) \
- SET_BITS_TO_LE_1BYTE(__pdesc+20, 4, 1, __val)
-#define SET_TX_DESC_DATA_BW(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+20, 5, 2, __val)
-#define SET_TX_DESC_DATA_LDPC(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+20, 7, 1, __val)
-#define SET_TX_DESC_DATA_STBC(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+20, 8, 2, __val)
-#define SET_TX_DESC_CTROL_STBC(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+20, 10, 2, __val)
-#define SET_TX_DESC_RTS_SHORT(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+20, 12, 1, __val)
-#define SET_TX_DESC_RTS_SC(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+20, 13, 4, __val)
-
-#define SET_TX_DESC_SW_DEFINE(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 0, 12, __val)
-#define SET_TX_DESC_ANTSEL_A(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 16, 3, __val)
-#define SET_TX_DESC_ANTSEL_B(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 19, 3, __val)
-#define SET_TX_DESC_ANTSEL_C(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 22, 3, __val)
-#define SET_TX_DESC_ANTSEL_D(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 25, 3, __val)
-#define SET_TX_DESC_MBSSID(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(i(__pdesc) + 24, 12, 4, __val)
-
-#define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE((__pdesc) + 28, 0, 16, __val)
-
-#define GET_TX_DESC_TX_BUFFER_SIZE(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+28, 0, 16)
-
-#define SET_TX_DESC_HWSEQ_EN(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+32, 15, 1, __val)
-
-#define SET_TX_DESC_SEQ(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+36, 12, 12, __val)
-
-#define SET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+40, 0, 32, __val)
-
-#define GET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+40, 0, 32)
-
-#define SET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+48, 0, 32, __val)
-
-#define GET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+48, 0, 32)
-
-#define GET_RX_DESC_PKT_LEN(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc, 0, 14)
-#define GET_RX_DESC_CRC32(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc, 14, 1)
-#define GET_RX_DESC_ICV(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc, 15, 1)
-#define GET_RX_DESC_DRV_INFO_SIZE(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc, 16, 4)
-#define GET_RX_DESC_SECURITY(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc, 20, 3)
-#define GET_RX_DESC_QOS(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc, 23, 1)
-#define GET_RX_DESC_SHIFT(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc, 24, 2)
-#define GET_RX_DESC_PHYST(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc, 26, 1)
-#define GET_RX_DESC_SWDEC(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc, 27, 1)
-#define GET_RX_DESC_LS(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc, 28, 1)
-#define GET_RX_DESC_FS(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc, 29, 1)
-#define GET_RX_DESC_EOR(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc, 30, 1)
-#define GET_RX_DESC_OWN(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc, 31, 1)
-
-#define SET_RX_DESC_PKT_LEN(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc, 0, 14, __val)
-#define SET_RX_DESC_EOR(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val)
-#define SET_RX_DESC_OWN(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val)
-
-#define GET_RX_DESC_MACID(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+4, 0, 7)
-#define GET_RX_DESC_TID(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+4, 8, 4)
-#define GET_RX_DESC_AMSDU(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+4, 13, 1)
-#define GET_RX_STATUS_DESC_RXID_MATCH(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+4, 14, 1)
-#define GET_RX_DESC_PAGGR(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+4, 15, 1)
-#define GET_RX_DESC_A1_FIT(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+4, 16, 4)
-#define GET_RX_DESC_CHKERR(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+4, 20, 1)
-#define GET_RX_DESC_IPVER(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+4, 21, 1)
-#define GET_RX_STATUS_DESC_IS_TCPUDP(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+4, 22, 1)
-#define GET_RX_STATUS_DESC_CHK_VLD(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+4, 23, 1)
-#define GET_RX_DESC_PAM(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+4, 24, 1)
-#define GET_RX_DESC_PWR(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+4, 25, 1)
-#define GET_RX_DESC_MD(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+4, 26, 1)
-#define GET_RX_DESC_MF(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+4, 27, 1)
-#define GET_RX_DESC_TYPE(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+4, 28, 2)
-#define GET_RX_DESC_MC(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+4, 30, 1)
-#define GET_RX_DESC_BC(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+4, 31, 1)
-
-#define GET_RX_DESC_SEQ(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+8, 0, 12)
-#define GET_RX_DESC_FRAG(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+8, 12, 4)
-#define GET_RX_STATUS_DESC_RX_IS_QOS(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+8, 16, 1)
-#define GET_RX_STATUS_DESC_WLANHD_IV_LEN(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+8, 18, 6)
-#define GET_RX_STATUS_DESC_RPT_SEL(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+8, 28, 1)
-
-#define GET_RX_DESC_RXMCS(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+12, 0, 7)
-#define GET_RX_DESC_HTC(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+12, 10, 1)
-#define GET_RX_STATUS_DESC_EOSP(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+12, 11, 1)
-#define GET_RX_STATUS_DESC_BSSID_FIT(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+12, 12, 2)
-
-#define GET_RX_STATUS_DESC_PATTERN_MATCH(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+12, 29, 1)
-#define GET_RX_STATUS_DESC_UNICAST_MATCH(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+12, 30, 1)
-#define GET_RX_STATUS_DESC_MAGIC_MATCH(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+12, 31, 1)
-
-#define GET_RX_DESC_SPLCP(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+16, 0, 1)
-#define GET_RX_STATUS_DESC_LDPC(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+16, 1, 1)
-#define GET_RX_STATUS_DESC_STBC(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+16, 2, 1)
-#define GET_RX_DESC_BW(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+16, 4, 2)
-
-#define GET_RX_DESC_TSFL(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+20, 0, 32)
-
-#define GET_RX_DESC_BUFF_ADDR(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+24, 0, 32)
-#define GET_RX_DESC_BUFF_ADDR64(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+28, 0, 32)
-
-#define SET_RX_DESC_BUFF_ADDR(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+24, 0, 32, __val)
-#define SET_RX_DESC_BUFF_ADDR64(__pdesc, __val) \
- SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 32, __val)
+static inline void set_tx_desc_pkt_size(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc, __val, GENMASK(15, 0));
+}
+
+static inline void set_tx_desc_offset(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc, __val, GENMASK(23, 16));
+}
+
+static inline void set_tx_desc_bmc(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc, __val, BIT(24));
+}
+
+static inline void set_tx_desc_htc(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc, __val, BIT(25));
+}
+
+static inline void set_tx_desc_last_seg(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc, __val, BIT(26));
+}
+
+static inline void set_tx_desc_first_seg(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc, __val, BIT(27));
+}
+
+static inline void set_tx_desc_linip(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc, __val, BIT(28));
+}
+
+static inline void set_tx_desc_own(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc, __val, BIT(31));
+}
+
+static inline int get_tx_desc_own(__le32 *__pdesc)
+{
+ return le32_get_bits(*(__pdesc), BIT(31));
+}
+
+static inline void set_tx_desc_macid(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc + 1, __val, GENMASK(6, 0));
+}
+
+static inline void set_tx_desc_queue_sel(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc + 1, __val, GENMASK(12, 8));
+}
+
+static inline void set_tx_desc_rate_id(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc + 1, __val, GENMASK(20, 16));
+}
+
+static inline void set_tx_desc_sec_type(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc + 1, __val, GENMASK(23, 22));
+}
+
+static inline void set_tx_desc_pkt_offset(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc + 1, __val, GENMASK(28, 24));
+}
+
+static inline void set_tx_desc_agg_enable(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc + 2, __val, BIT(12));
+}
+
+static inline void set_tx_desc_rdg_enable(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc + 2, __val, BIT(13));
+}
+
+static inline void set_tx_desc_more_frag(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc + 2, __val, BIT(17));
+}
+
+static inline void set_tx_desc_ampdu_density(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc + 2, __val, GENMASK(22, 20));
+}
+
+static inline void set_tx_desc_hwseq_sel(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc + 3, __val, GENMASK(7, 6));
+}
+
+static inline void set_tx_desc_use_rate(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc + 3, __val, BIT(8));
+}
+
+static inline void set_tx_desc_disable_fb(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc + 3, __val, BIT(10));
+}
+
+static inline void set_tx_desc_cts2self(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc + 3, __val, BIT(11));
+}
+
+static inline void set_tx_desc_rts_enable(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc + 3, __val, BIT(12));
+}
+
+static inline void set_tx_desc_hw_rts_enable(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc + 3, __val, BIT(13));
+}
+
+static inline void set_tx_desc_nav_use_hdr(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc + 3, __val, BIT(15));
+}
+
+static inline void set_tx_desc_max_agg_num(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc + 3, __val, GENMASK(21, 17));
+}
+
+static inline void set_tx_desc_tx_ant(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc + 5, __val, GENMASK(27, 24));
+}
+
+static inline void set_tx_desc_tx_rate(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc + 4, __val, GENMASK(6, 0));
+}
+
+static inline void set_tx_desc_data_rate_fb_limit(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc + 4, __val, GENMASK(12, 8));
+}
+
+static inline void set_tx_desc_rts_rate_fb_limit(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc + 4, __val, GENMASK(16, 13));
+}
+
+static inline void set_tx_desc_rts_rate(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc + 4, __val, GENMASK(28, 24));
+}
+
+static inline void set_tx_desc_tx_sub_carrier(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc + 5, __val, GENMASK(3, 0));
+}
+
+static inline void set_tx_desc_data_shortgi(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc + 5, __val, BIT(4));
+}
+
+static inline void set_tx_desc_data_bw(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc + 5, __val, GENMASK(6, 5));
+}
+
+static inline void set_tx_desc_rts_short(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc + 5, __val, BIT(12));
+}
+
+static inline void set_tx_desc_rts_sc(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc + 5, __val, GENMASK(16, 13));
+}
+
+static inline void set_tx_desc_tx_buffer_size(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc + 7, __val, GENMASK(15, 0));
+}
+
+static inline void set_tx_desc_hwseq_en(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc + 8, __val, BIT(15));
+}
+
+static inline void set_tx_desc_seq(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc + 9, __val, GENMASK(23, 12));
+}
+
+static inline void set_tx_desc_tx_buffer_address(__le32 *__pdesc, u32 __val)
+{
+ *(__pdesc + 10) = cpu_to_le32(__val);
+}
+
+static inline int get_tx_desc_tx_buffer_address(__le32 *__pdesc)
+{
+ return le32_to_cpu(*(__pdesc + 10));
+}
+
+static inline void set_tx_desc_next_desc_address(__le32 *__pdesc, u32 __val)
+{
+ *(__pdesc + 12) = cpu_to_le32(__val);
+}
+
+static inline int get_rx_desc_pkt_len(__le32 *__pdesc)
+{
+ return le32_get_bits(*(__pdesc), GENMASK(13, 0));
+}
+
+static inline int get_rx_desc_crc32(__le32 *__pdesc)
+{
+ return le32_get_bits(*(__pdesc), BIT(14));
+}
+
+static inline int get_rx_desc_icv(__le32 *__pdesc)
+{
+ return le32_get_bits(*(__pdesc), BIT(15));
+}
+
+static inline int get_rx_desc_drv_info_size(__le32 *__pdesc)
+{
+ return le32_get_bits(*(__pdesc), GENMASK(19, 16));
+}
+
+static inline int get_rx_desc_shift(__le32 *__pdesc)
+{
+ return le32_get_bits(*(__pdesc), GENMASK(25, 24));
+}
+
+static inline int get_rx_desc_physt(__le32 *__pdesc)
+{
+ return le32_get_bits(*(__pdesc), BIT(26));
+}
+
+static inline int get_rx_desc_swdec(__le32 *__pdesc)
+{
+ return le32_get_bits(*(__pdesc), BIT(27));
+}
+
+static inline int get_rx_desc_own(__le32 *__pdesc)
+{
+ return le32_get_bits(*(__pdesc), BIT(31));
+}
+
+static inline void set_rx_desc_pkt_len(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc, __val, GENMASK(13, 0));
+}
+
+static inline void set_rx_desc_eor(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc, __val, BIT(30));
+}
+
+static inline void set_rx_desc_own(__le32 *__pdesc, u32 __val)
+{
+ le32p_replace_bits(__pdesc, __val, BIT(31));
+}
+
+static inline int get_rx_desc_macid(__le32 *__pdesc)
+{
+ return le32_get_bits(*(__pdesc + 1), GENMASK(6, 0));
+}
+
+static inline int get_rx_desc_paggr(__le32 *__pdesc)
+{
+ return le32_get_bits(*(__pdesc + 1), BIT(15));
+}
+
+static inline int get_rx_status_desc_rpt_sel(__le32 *__pdesc)
+{
+ return le32_get_bits(*(__pdesc + 1), BIT(28));
+}
+
+static inline int get_rx_desc_rxmcs(__le32 *__pdesc)
+{
+ return le32_get_bits(*(__pdesc + 3), GENMASK(6, 0));
+}
+
+static inline int get_rx_status_desc_pattern_match(__le32 *__pdesc)
+{
+ return le32_get_bits(*(__pdesc + 3), BIT(29));
+}
+
+static inline int get_rx_status_desc_unicast_match(__le32 *__pdesc)
+{
+ return le32_get_bits(*(__pdesc + 3), BIT(30));
+}
+
+static inline int get_rx_status_desc_magic_match(__le32 *__pdesc)
+{
+ return le32_get_bits(*(__pdesc + 3), BIT(31));
+}
+
+static inline int get_rx_desc_splcp(__le32 *__pdesc)
+{
+ return le32_get_bits(*(__pdesc + 4), BIT(0));
+}
+
+static inline int get_rx_desc_bw(__le32 *__pdesc)
+{
+ return le32_get_bits(*(__pdesc + 4), GENMASK(5, 4));
+}
+
+static inline int get_rx_desc_tsfl(__le32 *__pdesc)
+{
+ return le32_to_cpu(*(__pdesc + 5));
+}
+
+static inline int get_rx_desc_buff_addr(__le32 *__pdesc)
+{
+ return le32_to_cpu(*(__pdesc + 6));
+}
+
+static inline void set_rx_desc_buff_addr(__le32 *__pdesc, u32 __val)
+{
+ *(__pdesc + 6) = cpu_to_le32(__val);
+}
/* TX report 2 format in Rx desc*/
-#define GET_RX_RPT2_DESC_PKT_LEN(__status) \
- LE_BITS_TO_4BYTE(__status, 0, 9)
-#define GET_RX_RPT2_DESC_MACID_VALID_1(__status) \
- LE_BITS_TO_4BYTE(__status+16, 0, 32)
-#define GET_RX_RPT2_DESC_MACID_VALID_2(__status) \
- LE_BITS_TO_4BYTE(__status+20, 0, 32)
-
-#define SET_EARLYMODE_PKTNUM(__paddr, __value) \
- SET_BITS_TO_LE_4BYTE(__paddr, 0, 4, __value)
-#define SET_EARLYMODE_LEN0(__paddr, __value) \
- SET_BITS_TO_LE_4BYTE(__paddr, 4, 12, __value)
-#define SET_EARLYMODE_LEN1(__paddr, __value) \
- SET_BITS_TO_LE_4BYTE(__paddr, 16, 12, __value)
-#define SET_EARLYMODE_LEN2_1(__paddr, __value) \
- SET_BITS_TO_LE_4BYTE(__paddr, 28, 4, __value)
-#define SET_EARLYMODE_LEN2_2(__paddr, __value) \
- SET_BITS_TO_LE_4BYTE(__paddr+4, 0, 8, __value)
-#define SET_EARLYMODE_LEN3(__paddr, __value) \
- SET_BITS_TO_LE_4BYTE(__paddr+4, 8, 12, __value)
-#define SET_EARLYMODE_LEN4(__paddr, __value) \
- SET_BITS_TO_LE_4BYTE(__paddr+4, 20, 12, __value)
-
-#define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size) \
-do { \
- if (_size > TX_DESC_NEXT_DESC_OFFSET) \
- memset(__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET); \
- else \
- memset(__pdesc, 0, _size); \
-} while (0)
+static inline int get_rx_rpt2_desc_macid_valid_1(__le32 *__status)
+{
+ return le32_to_cpu(*(__status + 4));
+}
+
+static inline int get_rx_rpt2_desc_macid_valid_2(__le32 *__status)
+{
+ return le32_to_cpu(*(__status + 5));
+}
+
+static inline void set_earlymode_pktnum(__le32 *__paddr, u32 __value)
+{
+ le32p_replace_bits(__paddr, __value, GENMASK(3, 0));
+}
+
+static inline void set_earlymode_len0(__le32 *__paddr, u32 __value)
+{
+ le32p_replace_bits(__paddr, __value, GENMASK(15, 4));
+}
+
+static inline void set_earlymode_len1(__le32 *__paddr, u32 __value)
+{
+ le32p_replace_bits(__paddr, __value, GENMASK(27, 16));
+}
+
+static inline void set_earlymode_len2_1(__le32 *__paddr, u32 __value)
+{
+ le32p_replace_bits(__paddr, __value, GENMASK(31, 28));
+}
+
+static inline void set_earlymode_len2_2(__le32 *__paddr, u32 __value)
+{
+ le32p_replace_bits(__paddr, __value, GENMASK(7, 0));
+}
+
+static inline void set_earlymode_len3(__le32 *__paddr, u32 __value)
+{
+ le32p_replace_bits((__paddr + 1), __value, GENMASK(19, 8));
+}
+
+static inline void set_earlymode_len4(__le32 *__paddr, u32 __value)
+{
+ le32p_replace_bits((__paddr + 1), __value, GENMASK(31, 20));
+}
+
+static inline void clear_pci_tx_desc_content(__le32 *__pdesc, int _size)
+{
+ if (_size > TX_DESC_NEXT_DESC_OFFSET)
+ memset(__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET);
+ else
+ memset(__pdesc, 0, _size);
+}
#define RTL8821AE_RX_HAL_IS_CCK_RATE(rxmcs)\
(rxmcs == DESC_RATE1M ||\
diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.c b/drivers/net/wireless/realtek/rtlwifi/usb.c
index e24fda5e9087..34d68dbf4b4c 100644
--- a/drivers/net/wireless/realtek/rtlwifi/usb.c
+++ b/drivers/net/wireless/realtek/rtlwifi/usb.c
@@ -1064,13 +1064,13 @@ int rtl_usb_probe(struct usb_interface *intf,
rtlpriv->cfg->ops->read_eeprom_info(hw);
err = _rtl_usb_init(hw);
if (err)
- goto error_out;
+ goto error_out2;
rtl_usb_init_sw(hw);
/* Init mac80211 sw */
err = rtl_init_core(hw);
if (err) {
pr_err("Can't allocate sw for mac80211\n");
- goto error_out;
+ goto error_out2;
}
if (rtlpriv->cfg->ops->init_sw_vars(hw)) {
pr_err("Can't init_sw_vars\n");
@@ -1091,6 +1091,7 @@ int rtl_usb_probe(struct usb_interface *intf,
error_out:
rtl_deinit_core(hw);
+error_out2:
_rtl_usb_io_handler_release(hw);
usb_put_dev(udev);
complete(&rtlpriv->firmware_loading_complete);
diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h
index 518aaa875361..3bdda1c98339 100644
--- a/drivers/net/wireless/realtek/rtlwifi/wifi.h
+++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h
@@ -13,6 +13,7 @@
#include <linux/usb.h>
#include <net/mac80211.h>
#include <linux/completion.h>
+#include <linux/bitfield.h>
#include "debug.h"
#define MASKBYTE0 0xff
@@ -597,7 +598,7 @@ enum ht_channel_width {
HT_CHANNEL_WIDTH_MAX,
};
-/* Ref: 802.11i sepc D10.0 7.3.2.25.1
+/* Ref: 802.11i spec D10.0 7.3.2.25.1
* Cipher Suites Encryption Algorithms
*/
enum rt_enc_alg {
diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c
index cf4265cda224..628477971213 100644
--- a/drivers/net/wireless/realtek/rtw88/fw.c
+++ b/drivers/net/wireless/realtek/rtw88/fw.c
@@ -8,7 +8,8 @@
#include "reg.h"
#include "debug.h"
-void rtw_fw_c2h_cmd_handle_ext(struct rtw_dev *rtwdev, struct sk_buff *skb)
+static void rtw_fw_c2h_cmd_handle_ext(struct rtw_dev *rtwdev,
+ struct sk_buff *skb)
{
struct rtw_c2h_cmd *c2h;
u8 sub_cmd_id;
@@ -47,7 +48,8 @@ void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb)
}
}
-void rtw_fw_send_h2c_command(struct rtw_dev *rtwdev, u8 *h2c)
+static void rtw_fw_send_h2c_command(struct rtw_dev *rtwdev,
+ u8 *h2c)
{
u8 box;
u8 box_state;
diff --git a/drivers/net/wireless/realtek/rtw88/hci.h b/drivers/net/wireless/realtek/rtw88/hci.h
index 2676582a85a0..aba329c9d0cf 100644
--- a/drivers/net/wireless/realtek/rtw88/hci.h
+++ b/drivers/net/wireless/realtek/rtw88/hci.h
@@ -97,7 +97,7 @@ static inline void rtw_write8_set(struct rtw_dev *rtwdev, u32 addr, u8 bit)
rtw_write8(rtwdev, addr, val | bit);
}
-static inline void rtw_writ16_set(struct rtw_dev *rtwdev, u32 addr, u16 bit)
+static inline void rtw_write16_set(struct rtw_dev *rtwdev, u32 addr, u16 bit)
{
u16 val;
diff --git a/drivers/net/wireless/realtek/rtw88/mac.c b/drivers/net/wireless/realtek/rtw88/mac.c
index 25a923bc6366..fc14b37d927d 100644
--- a/drivers/net/wireless/realtek/rtw88/mac.c
+++ b/drivers/net/wireless/realtek/rtw88/mac.c
@@ -285,8 +285,14 @@ int rtw_mac_power_on(struct rtw_dev *rtwdev)
goto err;
ret = rtw_mac_power_switch(rtwdev, true);
- if (ret)
+ if (ret == -EALREADY) {
+ rtw_mac_power_switch(rtwdev, false);
+ ret = rtw_mac_power_switch(rtwdev, true);
+ if (ret)
+ goto err;
+ } else if (ret) {
goto err;
+ }
ret = rtw_mac_init_system_cfg(rtwdev);
if (ret)
diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c
index abded63f138d..abe6a148673b 100644
--- a/drivers/net/wireless/realtek/rtw88/mac80211.c
+++ b/drivers/net/wireless/realtek/rtw88/mac80211.c
@@ -85,30 +85,35 @@ static const struct rtw_vif_port rtw_vif_port[] = {
.bssid = {.addr = 0x0618},
.net_type = {.addr = 0x0100, .mask = 0x30000},
.aid = {.addr = 0x06a8, .mask = 0x7ff},
+ .bcn_ctrl = {.addr = 0x0550, .mask = 0xff},
},
[1] = {
.mac_addr = {.addr = 0x0700},
.bssid = {.addr = 0x0708},
.net_type = {.addr = 0x0100, .mask = 0xc0000},
.aid = {.addr = 0x0710, .mask = 0x7ff},
+ .bcn_ctrl = {.addr = 0x0551, .mask = 0xff},
},
[2] = {
.mac_addr = {.addr = 0x1620},
.bssid = {.addr = 0x1628},
.net_type = {.addr = 0x1100, .mask = 0x3},
.aid = {.addr = 0x1600, .mask = 0x7ff},
+ .bcn_ctrl = {.addr = 0x0578, .mask = 0xff},
},
[3] = {
.mac_addr = {.addr = 0x1630},
.bssid = {.addr = 0x1638},
.net_type = {.addr = 0x1100, .mask = 0xc},
.aid = {.addr = 0x1604, .mask = 0x7ff},
+ .bcn_ctrl = {.addr = 0x0579, .mask = 0xff},
},
[4] = {
.mac_addr = {.addr = 0x1640},
.bssid = {.addr = 0x1648},
.net_type = {.addr = 0x1100, .mask = 0x30},
.aid = {.addr = 0x1608, .mask = 0x7ff},
+ .bcn_ctrl = {.addr = 0x057a, .mask = 0xff},
},
};
@@ -120,6 +125,7 @@ static int rtw_ops_add_interface(struct ieee80211_hw *hw,
enum rtw_net_type net_type;
u32 config = 0;
u8 port = 0;
+ u8 bcn_ctrl = 0;
rtwvif->port = port;
rtwvif->vif = vif;
@@ -136,13 +142,16 @@ static int rtw_ops_add_interface(struct ieee80211_hw *hw,
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT:
net_type = RTW_NET_AP_MODE;
+ bcn_ctrl = BIT_EN_BCN_FUNCTION | BIT_DIS_TSF_UDT;
break;
case NL80211_IFTYPE_ADHOC:
net_type = RTW_NET_AD_HOC;
+ bcn_ctrl = BIT_EN_BCN_FUNCTION | BIT_DIS_TSF_UDT;
break;
case NL80211_IFTYPE_STATION:
default:
net_type = RTW_NET_NO_LINK;
+ bcn_ctrl = BIT_EN_BCN_FUNCTION;
break;
}
@@ -150,6 +159,8 @@ static int rtw_ops_add_interface(struct ieee80211_hw *hw,
config |= PORT_SET_MAC_ADDR;
rtwvif->net_type = net_type;
config |= PORT_SET_NET_TYPE;
+ rtwvif->bcn_ctrl = bcn_ctrl;
+ config |= PORT_SET_BCN_CTRL;
rtw_vif_port_config(rtwdev, rtwvif, config);
mutex_unlock(&rtwdev->mutex);
@@ -173,6 +184,8 @@ static void rtw_ops_remove_interface(struct ieee80211_hw *hw,
config |= PORT_SET_MAC_ADDR;
rtwvif->net_type = RTW_NET_NO_LINK;
config |= PORT_SET_NET_TYPE;
+ rtwvif->bcn_ctrl = 0;
+ config |= PORT_SET_BCN_CTRL;
rtw_vif_port_config(rtwdev, rtwvif, config);
mutex_unlock(&rtwdev->mutex);
@@ -446,20 +459,39 @@ static void rtw_ops_sw_scan_start(struct ieee80211_hw *hw,
{
struct rtw_dev *rtwdev = hw->priv;
struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
+ u32 config = 0;
rtw_leave_lps(rtwdev, rtwvif);
+ mutex_lock(&rtwdev->mutex);
+
+ ether_addr_copy(rtwvif->mac_addr, mac_addr);
+ config |= PORT_SET_MAC_ADDR;
+ rtw_vif_port_config(rtwdev, rtwvif, config);
+
rtw_flag_set(rtwdev, RTW_FLAG_DIG_DISABLE);
rtw_flag_set(rtwdev, RTW_FLAG_SCANNING);
+
+ mutex_unlock(&rtwdev->mutex);
}
static void rtw_ops_sw_scan_complete(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct rtw_dev *rtwdev = hw->priv;
+ struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
+ u32 config = 0;
+
+ mutex_lock(&rtwdev->mutex);
rtw_flag_clear(rtwdev, RTW_FLAG_SCANNING);
rtw_flag_clear(rtwdev, RTW_FLAG_DIG_DISABLE);
+
+ ether_addr_copy(rtwvif->mac_addr, vif->addr);
+ config |= PORT_SET_MAC_ADDR;
+ rtw_vif_port_config(rtwdev, rtwvif, config);
+
+ mutex_unlock(&rtwdev->mutex);
}
const struct ieee80211_ops rtw_ops = {
diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c
index f447361f7573..5a2c06267d07 100644
--- a/drivers/net/wireless/realtek/rtw88/main.c
+++ b/drivers/net/wireless/realtek/rtw88/main.c
@@ -20,7 +20,7 @@ EXPORT_SYMBOL(rtw_debug_mask);
module_param_named(support_lps, rtw_fw_support_lps, bool, 0644);
module_param_named(debug_mask, rtw_debug_mask, uint, 0644);
-MODULE_PARM_DESC(support_lps, "Set Y to enable LPS support");
+MODULE_PARM_DESC(support_lps, "Set Y to enable Leisure Power Save support, to turn radio off between beacons");
MODULE_PARM_DESC(debug_mask, "Debugging mask");
static struct ieee80211_channel rtw_channeltable_2g[] = {
@@ -162,7 +162,8 @@ static void rtw_watch_dog_work(struct work_struct *work)
rtwdev->stats.tx_cnt = 0;
rtwdev->stats.rx_cnt = 0;
- rtw_iterate_vifs(rtwdev, rtw_vif_watch_dog_iter, &data);
+ /* use atomic version to avoid taking local->iflist_mtx mutex */
+ rtw_iterate_vifs_atomic(rtwdev, rtw_vif_watch_dog_iter, &data);
/* fw supports only one station associated to enter lps, if there are
* more than two stations associated to the AP, then we can not enter
@@ -197,15 +198,20 @@ void rtw_get_channel_params(struct cfg80211_chan_def *chandef,
{
struct ieee80211_channel *channel = chandef->chan;
enum nl80211_chan_width width = chandef->width;
+ u8 *cch_by_bw = chan_params->cch_by_bw;
u32 primary_freq, center_freq;
u8 center_chan;
u8 bandwidth = RTW_CHANNEL_WIDTH_20;
u8 primary_chan_idx = 0;
+ u8 i;
center_chan = channel->hw_value;
primary_freq = channel->center_freq;
center_freq = chandef->center_freq1;
+ /* assign the center channel used while 20M bw is selected */
+ cch_by_bw[RTW_CHANNEL_WIDTH_20] = channel->hw_value;
+
switch (width) {
case NL80211_CHAN_WIDTH_20_NOHT:
case NL80211_CHAN_WIDTH_20:
@@ -232,6 +238,10 @@ void rtw_get_channel_params(struct cfg80211_chan_def *chandef,
primary_chan_idx = 3;
center_chan -= 6;
}
+ /* assign the center channel used
+ * while 40M bw is selected
+ */
+ cch_by_bw[RTW_CHANNEL_WIDTH_40] = center_chan + 4;
} else {
if (center_freq - primary_freq == 10) {
primary_chan_idx = 2;
@@ -240,6 +250,10 @@ void rtw_get_channel_params(struct cfg80211_chan_def *chandef,
primary_chan_idx = 4;
center_chan += 6;
}
+ /* assign the center channel used
+ * while 40M bw is selected
+ */
+ cch_by_bw[RTW_CHANNEL_WIDTH_40] = center_chan - 4;
}
break;
default:
@@ -250,6 +264,12 @@ void rtw_get_channel_params(struct cfg80211_chan_def *chandef,
chan_params->center_chan = center_chan;
chan_params->bandwidth = bandwidth;
chan_params->primary_chan_idx = primary_chan_idx;
+
+ /* assign the center channel used while current bw is selected */
+ cch_by_bw[bandwidth] = center_chan;
+
+ for (i = bandwidth + 1; i <= RTW_MAX_CHANNEL_WIDTH; i++)
+ cch_by_bw[i] = 0;
}
void rtw_set_channel(struct rtw_dev *rtwdev)
@@ -259,6 +279,7 @@ void rtw_set_channel(struct rtw_dev *rtwdev)
struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_channel_params ch_param;
u8 center_chan, bandwidth, primary_chan_idx;
+ u8 i;
rtw_get_channel_params(&hw->conf.chandef, &ch_param);
if (WARN(ch_param.center_chan == 0, "Invalid channel\n"))
@@ -271,6 +292,10 @@ void rtw_set_channel(struct rtw_dev *rtwdev)
hal->current_band_width = bandwidth;
hal->current_channel = center_chan;
hal->current_band_type = center_chan > 14 ? RTW_BAND_5G : RTW_BAND_2G;
+
+ for (i = RTW_CHANNEL_WIDTH_20; i <= RTW_MAX_CHANNEL_WIDTH; i++)
+ hal->cch_by_bw[i] = ch_param.cch_by_bw[i];
+
chip->ops->set_channel(rtwdev, center_chan, bandwidth, primary_chan_idx);
rtw_phy_set_tx_power_level(rtwdev, center_chan);
@@ -308,6 +333,11 @@ void rtw_vif_port_config(struct rtw_dev *rtwdev,
mask = rtwvif->conf->aid.mask;
rtw_write32_mask(rtwdev, addr, mask, rtwvif->aid);
}
+ if (config & PORT_SET_BCN_CTRL) {
+ addr = rtwvif->conf->bcn_ctrl.addr;
+ mask = rtwvif->conf->bcn_ctrl.mask;
+ rtw_write8_mask(rtwdev, addr, mask, rtwvif->bcn_ctrl);
+ }
}
static u8 hw_bw_cap_to_bitamp(u8 bw_cap)
@@ -1041,7 +1071,7 @@ static int rtw_chip_board_info_setup(struct rtw_dev *rtwdev)
rtw_phy_setup_phy_cond(rtwdev, 0);
- rtw_hw_init_tx_power(hal);
+ rtw_phy_init_tx_power(rtwdev);
rtw_load_table(rtwdev, rfe_def->phy_pg_tbl);
rtw_load_table(rtwdev, rfe_def->txpwr_lmt_tbl);
rtw_phy_tx_power_by_rate_config(hal);
@@ -1168,6 +1198,7 @@ int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw)
ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
ieee80211_hw_set(hw, SUPPORTS_PS);
ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
+ ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP) |
@@ -1177,6 +1208,8 @@ int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw)
hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
WIPHY_FLAG_TDLS_EXTERNAL_SETUP;
+ hw->wiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
+
rtw_set_supported_band(hw, rtwdev->chip);
SET_IEEE80211_PERM_ADDR(hw, rtwdev->efuse.addr);
diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h
index 00fc77fb9b54..8fa05751836b 100644
--- a/drivers/net/wireless/realtek/rtw88/main.h
+++ b/drivers/net/wireless/realtek/rtw88/main.h
@@ -62,6 +62,9 @@ enum rtw_supported_band {
RTW_BAND_MAX,
};
+/* now, support upto 80M bw */
+#define RTW_MAX_CHANNEL_WIDTH RTW_CHANNEL_WIDTH_80
+
enum rtw_bandwidth {
RTW_CHANNEL_WIDTH_20 = 0,
RTW_CHANNEL_WIDTH_40 = 1,
@@ -286,10 +289,16 @@ enum rtw_trx_desc_rate {
};
enum rtw_regulatory_domains {
- RTW_REGD_FCC = 0,
- RTW_REGD_MKK = 1,
- RTW_REGD_ETSI = 2,
- RTW_REGD_WW = 3,
+ RTW_REGD_FCC = 0,
+ RTW_REGD_MKK = 1,
+ RTW_REGD_ETSI = 2,
+ RTW_REGD_IC = 3,
+ RTW_REGD_KCC = 4,
+ RTW_REGD_ACMA = 5,
+ RTW_REGD_CHILE = 6,
+ RTW_REGD_UKRAINE = 7,
+ RTW_REGD_MEXICO = 8,
+ RTW_REGD_WW,
RTW_REGD_MAX
};
@@ -413,6 +422,10 @@ struct rtw_channel_params {
u8 center_chan;
u8 bandwidth;
u8 primary_chan_idx;
+ /* center channel by different available bandwidth,
+ * val of (bw > current bandwidth) is invalid
+ */
+ u8 cch_by_bw[RTW_MAX_CHANNEL_WIDTH + 1];
};
struct rtw_hw_reg {
@@ -431,6 +444,7 @@ enum rtw_vif_port_set {
PORT_SET_BSSID = BIT(1),
PORT_SET_NET_TYPE = BIT(2),
PORT_SET_AID = BIT(3),
+ PORT_SET_BCN_CTRL = BIT(4),
};
struct rtw_vif_port {
@@ -438,6 +452,7 @@ struct rtw_vif_port {
struct rtw_hw_reg bssid;
struct rtw_hw_reg net_type;
struct rtw_hw_reg aid;
+ struct rtw_hw_reg bcn_ctrl;
};
struct rtw_tx_pkt_info {
@@ -591,6 +606,7 @@ struct rtw_vif {
u8 mac_addr[ETH_ALEN];
u8 bssid[ETH_ALEN];
u8 port;
+ u8 bcn_ctrl;
const struct rtw_vif_port *conf;
struct rtw_traffic_stats stats;
@@ -838,6 +854,9 @@ struct rtw_chip_info {
u32 rfe_defs_size;
};
+#define DACK_MSBK_BACKUP_NUM 0xf
+#define DACK_DCK_BACKUP_NUM 0x2
+
struct rtw_dm_info {
u32 cck_fa_cnt;
u32 ofdm_fa_cnt;
@@ -853,6 +872,11 @@ struct rtw_dm_info {
u8 cck_gi_u_bnd;
u8 cck_gi_l_bnd;
+
+ /* backup dack results for each path and I/Q */
+ u32 dack_adck[RTW_RF_PATH_MAX];
+ u16 dack_msbk[RTW_RF_PATH_MAX][2][DACK_MSBK_BACKUP_NUM];
+ u8 dack_dck[RTW_RF_PATH_MAX][2][DACK_DCK_BACKUP_NUM];
};
struct rtw_efuse {
@@ -973,6 +997,12 @@ struct rtw_hal {
u8 current_channel;
u8 current_band_width;
u8 current_band_type;
+
+ /* center channel for different available bandwidth,
+ * val of (bw > current_band_width) is invalid
+ */
+ u8 cch_by_bw[RTW_MAX_CHANNEL_WIDTH + 1];
+
u8 sec_ch_offset;
u8 rf_type;
u8 rf_path_num;
diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c
index cfe05ba7280d..353871c27779 100644
--- a/drivers/net/wireless/realtek/rtw88/pci.c
+++ b/drivers/net/wireless/realtek/rtw88/pci.c
@@ -487,10 +487,10 @@ static void rtw_pci_stop(struct rtw_dev *rtwdev)
}
static u8 ac_to_hwq[] = {
- [0] = RTW_TX_QUEUE_VO,
- [1] = RTW_TX_QUEUE_VI,
- [2] = RTW_TX_QUEUE_BE,
- [3] = RTW_TX_QUEUE_BK,
+ [IEEE80211_AC_VO] = RTW_TX_QUEUE_VO,
+ [IEEE80211_AC_VI] = RTW_TX_QUEUE_VI,
+ [IEEE80211_AC_BE] = RTW_TX_QUEUE_BE,
+ [IEEE80211_AC_BK] = RTW_TX_QUEUE_BK,
};
static u8 rtw_hw_queue_mapping(struct sk_buff *skb)
@@ -504,6 +504,8 @@ static u8 rtw_hw_queue_mapping(struct sk_buff *skb)
queue = RTW_TX_QUEUE_BCN;
else if (unlikely(ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)))
queue = RTW_TX_QUEUE_MGMT;
+ else if (WARN_ON_ONCE(q_mapping >= ARRAY_SIZE(ac_to_hwq)))
+ queue = ac_to_hwq[IEEE80211_AC_BE];
else
queue = ac_to_hwq[q_mapping];
diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c
index 4381b360b5b5..4ec8dcf17361 100644
--- a/drivers/net/wireless/realtek/rtw88/phy.c
+++ b/drivers/net/wireless/realtek/rtw88/phy.c
@@ -65,6 +65,56 @@ static const u32 db_invert_table[12][8] = {
1995262315, 2511886432U, 3162277660U, 3981071706U}
};
+u8 rtw_cck_rates[] = { DESC_RATE1M, DESC_RATE2M, DESC_RATE5_5M, DESC_RATE11M };
+u8 rtw_ofdm_rates[] = {
+ DESC_RATE6M, DESC_RATE9M, DESC_RATE12M,
+ DESC_RATE18M, DESC_RATE24M, DESC_RATE36M,
+ DESC_RATE48M, DESC_RATE54M
+};
+u8 rtw_ht_1s_rates[] = {
+ DESC_RATEMCS0, DESC_RATEMCS1, DESC_RATEMCS2,
+ DESC_RATEMCS3, DESC_RATEMCS4, DESC_RATEMCS5,
+ DESC_RATEMCS6, DESC_RATEMCS7
+};
+u8 rtw_ht_2s_rates[] = {
+ DESC_RATEMCS8, DESC_RATEMCS9, DESC_RATEMCS10,
+ DESC_RATEMCS11, DESC_RATEMCS12, DESC_RATEMCS13,
+ DESC_RATEMCS14, DESC_RATEMCS15
+};
+u8 rtw_vht_1s_rates[] = {
+ DESC_RATEVHT1SS_MCS0, DESC_RATEVHT1SS_MCS1,
+ DESC_RATEVHT1SS_MCS2, DESC_RATEVHT1SS_MCS3,
+ DESC_RATEVHT1SS_MCS4, DESC_RATEVHT1SS_MCS5,
+ DESC_RATEVHT1SS_MCS6, DESC_RATEVHT1SS_MCS7,
+ DESC_RATEVHT1SS_MCS8, DESC_RATEVHT1SS_MCS9
+};
+u8 rtw_vht_2s_rates[] = {
+ DESC_RATEVHT2SS_MCS0, DESC_RATEVHT2SS_MCS1,
+ DESC_RATEVHT2SS_MCS2, DESC_RATEVHT2SS_MCS3,
+ DESC_RATEVHT2SS_MCS4, DESC_RATEVHT2SS_MCS5,
+ DESC_RATEVHT2SS_MCS6, DESC_RATEVHT2SS_MCS7,
+ DESC_RATEVHT2SS_MCS8, DESC_RATEVHT2SS_MCS9
+};
+u8 *rtw_rate_section[RTW_RATE_SECTION_MAX] = {
+ rtw_cck_rates, rtw_ofdm_rates,
+ rtw_ht_1s_rates, rtw_ht_2s_rates,
+ rtw_vht_1s_rates, rtw_vht_2s_rates
+};
+u8 rtw_rate_size[RTW_RATE_SECTION_MAX] = {
+ ARRAY_SIZE(rtw_cck_rates),
+ ARRAY_SIZE(rtw_ofdm_rates),
+ ARRAY_SIZE(rtw_ht_1s_rates),
+ ARRAY_SIZE(rtw_ht_2s_rates),
+ ARRAY_SIZE(rtw_vht_1s_rates),
+ ARRAY_SIZE(rtw_vht_2s_rates)
+};
+static const u8 rtw_cck_size = ARRAY_SIZE(rtw_cck_rates);
+static const u8 rtw_ofdm_size = ARRAY_SIZE(rtw_ofdm_rates);
+static const u8 rtw_ht_1s_size = ARRAY_SIZE(rtw_ht_1s_rates);
+static const u8 rtw_ht_2s_size = ARRAY_SIZE(rtw_ht_2s_rates);
+static const u8 rtw_vht_1s_size = ARRAY_SIZE(rtw_vht_1s_rates);
+static const u8 rtw_vht_2s_size = ARRAY_SIZE(rtw_vht_2s_rates);
+
enum rtw_phy_band_type {
PHY_BAND_2G = 0,
PHY_BAND_5G = 1,
@@ -144,10 +194,10 @@ static void rtw_phy_stat_rssi_iter(void *data, struct ieee80211_sta *sta)
struct rtw_phy_stat_iter_data *iter_data = data;
struct rtw_dev *rtwdev = iter_data->rtwdev;
struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv;
- u8 rssi, rssi_level;
+ u8 rssi;
rssi = ewma_rssi_read(&si->avg_rssi);
- rssi_level = rtw_phy_get_rssi_level(si->rssi_level, rssi);
+ si->rssi_level = rtw_phy_get_rssi_level(si->rssi_level, rssi);
rtw_fw_send_rssi_info(rtwdev, si);
@@ -423,6 +473,11 @@ static u64 rtw_phy_db_2_linear(u8 power_db)
u8 i, j;
u64 linear;
+ if (power_db > 96)
+ power_db = 96;
+ else if (power_db < 1)
+ return 1;
+
/* 1dB ~ 96dB */
i = (power_db - 1) >> 3;
j = (power_db - 1) - (i << 3);
@@ -596,14 +651,19 @@ bool rtw_phy_write_rf_reg(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
direct_addr = base_addr[rf_path] + (addr << 2);
mask &= RFREG_MASK;
- rtw_write32_mask(rtwdev, REG_RSV_CTRL, BITS_RFC_DIRECT, DISABLE_PI);
- rtw_write32_mask(rtwdev, REG_WLRF1, BITS_RFC_DIRECT, DISABLE_PI);
+ if (addr == RF_CFGCH) {
+ rtw_write32_mask(rtwdev, REG_RSV_CTRL, BITS_RFC_DIRECT, DISABLE_PI);
+ rtw_write32_mask(rtwdev, REG_WLRF1, BITS_RFC_DIRECT, DISABLE_PI);
+ }
+
rtw_write32_mask(rtwdev, direct_addr, mask, data);
udelay(1);
- rtw_write32_mask(rtwdev, REG_RSV_CTRL, BITS_RFC_DIRECT, ENABLE_PI);
- rtw_write32_mask(rtwdev, REG_WLRF1, BITS_RFC_DIRECT, ENABLE_PI);
+ if (addr == RF_CFGCH) {
+ rtw_write32_mask(rtwdev, REG_RSV_CTRL, BITS_RFC_DIRECT, ENABLE_PI);
+ rtw_write32_mask(rtwdev, REG_WLRF1, BITS_RFC_DIRECT, ENABLE_PI);
+ }
return true;
}
@@ -709,6 +769,353 @@ void rtw_parse_tbl_phy_cond(struct rtw_dev *rtwdev, const struct rtw_table *tbl)
}
}
+#define bcd_to_dec_pwr_by_rate(val, i) bcd2bin(val >> (i * 8))
+
+static u8 tbl_to_dec_pwr_by_rate(struct rtw_dev *rtwdev, u32 hex, u8 i)
+{
+ if (rtwdev->chip->is_pwr_by_rate_dec)
+ return bcd_to_dec_pwr_by_rate(hex, i);
+
+ return (hex >> (i * 8)) & 0xFF;
+}
+
+static void
+rtw_phy_get_rate_values_of_txpwr_by_rate(struct rtw_dev *rtwdev,
+ u32 addr, u32 mask, u32 val, u8 *rate,
+ u8 *pwr_by_rate, u8 *rate_num)
+{
+ int i;
+
+ switch (addr) {
+ case 0xE00:
+ case 0x830:
+ rate[0] = DESC_RATE6M;
+ rate[1] = DESC_RATE9M;
+ rate[2] = DESC_RATE12M;
+ rate[3] = DESC_RATE18M;
+ for (i = 0; i < 4; ++i)
+ pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
+ *rate_num = 4;
+ break;
+ case 0xE04:
+ case 0x834:
+ rate[0] = DESC_RATE24M;
+ rate[1] = DESC_RATE36M;
+ rate[2] = DESC_RATE48M;
+ rate[3] = DESC_RATE54M;
+ for (i = 0; i < 4; ++i)
+ pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
+ *rate_num = 4;
+ break;
+ case 0xE08:
+ rate[0] = DESC_RATE1M;
+ pwr_by_rate[0] = bcd_to_dec_pwr_by_rate(val, 1);
+ *rate_num = 1;
+ break;
+ case 0x86C:
+ if (mask == 0xffffff00) {
+ rate[0] = DESC_RATE2M;
+ rate[1] = DESC_RATE5_5M;
+ rate[2] = DESC_RATE11M;
+ for (i = 1; i < 4; ++i)
+ pwr_by_rate[i - 1] =
+ tbl_to_dec_pwr_by_rate(rtwdev, val, i);
+ *rate_num = 3;
+ } else if (mask == 0x000000ff) {
+ rate[0] = DESC_RATE11M;
+ pwr_by_rate[0] = bcd_to_dec_pwr_by_rate(val, 0);
+ *rate_num = 1;
+ }
+ break;
+ case 0xE10:
+ case 0x83C:
+ rate[0] = DESC_RATEMCS0;
+ rate[1] = DESC_RATEMCS1;
+ rate[2] = DESC_RATEMCS2;
+ rate[3] = DESC_RATEMCS3;
+ for (i = 0; i < 4; ++i)
+ pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
+ *rate_num = 4;
+ break;
+ case 0xE14:
+ case 0x848:
+ rate[0] = DESC_RATEMCS4;
+ rate[1] = DESC_RATEMCS5;
+ rate[2] = DESC_RATEMCS6;
+ rate[3] = DESC_RATEMCS7;
+ for (i = 0; i < 4; ++i)
+ pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
+ *rate_num = 4;
+ break;
+ case 0xE18:
+ case 0x84C:
+ rate[0] = DESC_RATEMCS8;
+ rate[1] = DESC_RATEMCS9;
+ rate[2] = DESC_RATEMCS10;
+ rate[3] = DESC_RATEMCS11;
+ for (i = 0; i < 4; ++i)
+ pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
+ *rate_num = 4;
+ break;
+ case 0xE1C:
+ case 0x868:
+ rate[0] = DESC_RATEMCS12;
+ rate[1] = DESC_RATEMCS13;
+ rate[2] = DESC_RATEMCS14;
+ rate[3] = DESC_RATEMCS15;
+ for (i = 0; i < 4; ++i)
+ pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
+ *rate_num = 4;
+ break;
+ case 0x838:
+ rate[0] = DESC_RATE1M;
+ rate[1] = DESC_RATE2M;
+ rate[2] = DESC_RATE5_5M;
+ for (i = 1; i < 4; ++i)
+ pwr_by_rate[i - 1] = tbl_to_dec_pwr_by_rate(rtwdev,
+ val, i);
+ *rate_num = 3;
+ break;
+ case 0xC20:
+ case 0xE20:
+ case 0x1820:
+ case 0x1A20:
+ rate[0] = DESC_RATE1M;
+ rate[1] = DESC_RATE2M;
+ rate[2] = DESC_RATE5_5M;
+ rate[3] = DESC_RATE11M;
+ for (i = 0; i < 4; ++i)
+ pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
+ *rate_num = 4;
+ break;
+ case 0xC24:
+ case 0xE24:
+ case 0x1824:
+ case 0x1A24:
+ rate[0] = DESC_RATE6M;
+ rate[1] = DESC_RATE9M;
+ rate[2] = DESC_RATE12M;
+ rate[3] = DESC_RATE18M;
+ for (i = 0; i < 4; ++i)
+ pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
+ *rate_num = 4;
+ break;
+ case 0xC28:
+ case 0xE28:
+ case 0x1828:
+ case 0x1A28:
+ rate[0] = DESC_RATE24M;
+ rate[1] = DESC_RATE36M;
+ rate[2] = DESC_RATE48M;
+ rate[3] = DESC_RATE54M;
+ for (i = 0; i < 4; ++i)
+ pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
+ *rate_num = 4;
+ break;
+ case 0xC2C:
+ case 0xE2C:
+ case 0x182C:
+ case 0x1A2C:
+ rate[0] = DESC_RATEMCS0;
+ rate[1] = DESC_RATEMCS1;
+ rate[2] = DESC_RATEMCS2;
+ rate[3] = DESC_RATEMCS3;
+ for (i = 0; i < 4; ++i)
+ pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
+ *rate_num = 4;
+ break;
+ case 0xC30:
+ case 0xE30:
+ case 0x1830:
+ case 0x1A30:
+ rate[0] = DESC_RATEMCS4;
+ rate[1] = DESC_RATEMCS5;
+ rate[2] = DESC_RATEMCS6;
+ rate[3] = DESC_RATEMCS7;
+ for (i = 0; i < 4; ++i)
+ pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
+ *rate_num = 4;
+ break;
+ case 0xC34:
+ case 0xE34:
+ case 0x1834:
+ case 0x1A34:
+ rate[0] = DESC_RATEMCS8;
+ rate[1] = DESC_RATEMCS9;
+ rate[2] = DESC_RATEMCS10;
+ rate[3] = DESC_RATEMCS11;
+ for (i = 0; i < 4; ++i)
+ pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
+ *rate_num = 4;
+ break;
+ case 0xC38:
+ case 0xE38:
+ case 0x1838:
+ case 0x1A38:
+ rate[0] = DESC_RATEMCS12;
+ rate[1] = DESC_RATEMCS13;
+ rate[2] = DESC_RATEMCS14;
+ rate[3] = DESC_RATEMCS15;
+ for (i = 0; i < 4; ++i)
+ pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
+ *rate_num = 4;
+ break;
+ case 0xC3C:
+ case 0xE3C:
+ case 0x183C:
+ case 0x1A3C:
+ rate[0] = DESC_RATEVHT1SS_MCS0;
+ rate[1] = DESC_RATEVHT1SS_MCS1;
+ rate[2] = DESC_RATEVHT1SS_MCS2;
+ rate[3] = DESC_RATEVHT1SS_MCS3;
+ for (i = 0; i < 4; ++i)
+ pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
+ *rate_num = 4;
+ break;
+ case 0xC40:
+ case 0xE40:
+ case 0x1840:
+ case 0x1A40:
+ rate[0] = DESC_RATEVHT1SS_MCS4;
+ rate[1] = DESC_RATEVHT1SS_MCS5;
+ rate[2] = DESC_RATEVHT1SS_MCS6;
+ rate[3] = DESC_RATEVHT1SS_MCS7;
+ for (i = 0; i < 4; ++i)
+ pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
+ *rate_num = 4;
+ break;
+ case 0xC44:
+ case 0xE44:
+ case 0x1844:
+ case 0x1A44:
+ rate[0] = DESC_RATEVHT1SS_MCS8;
+ rate[1] = DESC_RATEVHT1SS_MCS9;
+ rate[2] = DESC_RATEVHT2SS_MCS0;
+ rate[3] = DESC_RATEVHT2SS_MCS1;
+ for (i = 0; i < 4; ++i)
+ pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
+ *rate_num = 4;
+ break;
+ case 0xC48:
+ case 0xE48:
+ case 0x1848:
+ case 0x1A48:
+ rate[0] = DESC_RATEVHT2SS_MCS2;
+ rate[1] = DESC_RATEVHT2SS_MCS3;
+ rate[2] = DESC_RATEVHT2SS_MCS4;
+ rate[3] = DESC_RATEVHT2SS_MCS5;
+ for (i = 0; i < 4; ++i)
+ pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
+ *rate_num = 4;
+ break;
+ case 0xC4C:
+ case 0xE4C:
+ case 0x184C:
+ case 0x1A4C:
+ rate[0] = DESC_RATEVHT2SS_MCS6;
+ rate[1] = DESC_RATEVHT2SS_MCS7;
+ rate[2] = DESC_RATEVHT2SS_MCS8;
+ rate[3] = DESC_RATEVHT2SS_MCS9;
+ for (i = 0; i < 4; ++i)
+ pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
+ *rate_num = 4;
+ break;
+ case 0xCD8:
+ case 0xED8:
+ case 0x18D8:
+ case 0x1AD8:
+ rate[0] = DESC_RATEMCS16;
+ rate[1] = DESC_RATEMCS17;
+ rate[2] = DESC_RATEMCS18;
+ rate[3] = DESC_RATEMCS19;
+ for (i = 0; i < 4; ++i)
+ pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
+ *rate_num = 4;
+ break;
+ case 0xCDC:
+ case 0xEDC:
+ case 0x18DC:
+ case 0x1ADC:
+ rate[0] = DESC_RATEMCS20;
+ rate[1] = DESC_RATEMCS21;
+ rate[2] = DESC_RATEMCS22;
+ rate[3] = DESC_RATEMCS23;
+ for (i = 0; i < 4; ++i)
+ pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
+ *rate_num = 4;
+ break;
+ case 0xCE0:
+ case 0xEE0:
+ case 0x18E0:
+ case 0x1AE0:
+ rate[0] = DESC_RATEVHT3SS_MCS0;
+ rate[1] = DESC_RATEVHT3SS_MCS1;
+ rate[2] = DESC_RATEVHT3SS_MCS2;
+ rate[3] = DESC_RATEVHT3SS_MCS3;
+ for (i = 0; i < 4; ++i)
+ pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
+ *rate_num = 4;
+ break;
+ case 0xCE4:
+ case 0xEE4:
+ case 0x18E4:
+ case 0x1AE4:
+ rate[0] = DESC_RATEVHT3SS_MCS4;
+ rate[1] = DESC_RATEVHT3SS_MCS5;
+ rate[2] = DESC_RATEVHT3SS_MCS6;
+ rate[3] = DESC_RATEVHT3SS_MCS7;
+ for (i = 0; i < 4; ++i)
+ pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
+ *rate_num = 4;
+ break;
+ case 0xCE8:
+ case 0xEE8:
+ case 0x18E8:
+ case 0x1AE8:
+ rate[0] = DESC_RATEVHT3SS_MCS8;
+ rate[1] = DESC_RATEVHT3SS_MCS9;
+ for (i = 0; i < 2; ++i)
+ pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
+ *rate_num = 2;
+ break;
+ default:
+ rtw_warn(rtwdev, "invalid tx power index addr 0x%08x\n", addr);
+ break;
+ }
+}
+
+static void rtw_phy_store_tx_power_by_rate(struct rtw_dev *rtwdev,
+ u32 band, u32 rfpath, u32 txnum,
+ u32 regaddr, u32 bitmask, u32 data)
+{
+ struct rtw_hal *hal = &rtwdev->hal;
+ u8 rate_num = 0;
+ u8 rate;
+ u8 rates[RTW_RF_PATH_MAX] = {0};
+ s8 offset;
+ s8 pwr_by_rate[RTW_RF_PATH_MAX] = {0};
+ int i;
+
+ rtw_phy_get_rate_values_of_txpwr_by_rate(rtwdev, regaddr, bitmask, data,
+ rates, pwr_by_rate, &rate_num);
+
+ if (WARN_ON(rfpath >= RTW_RF_PATH_MAX ||
+ (band != PHY_BAND_2G && band != PHY_BAND_5G) ||
+ rate_num > RTW_RF_PATH_MAX))
+ return;
+
+ for (i = 0; i < rate_num; i++) {
+ offset = pwr_by_rate[i];
+ rate = rates[i];
+ if (band == PHY_BAND_2G)
+ hal->tx_pwr_by_rate_offset_2g[rfpath][rate] = offset;
+ else if (band == PHY_BAND_5G)
+ hal->tx_pwr_by_rate_offset_5g[rfpath][rate] = offset;
+ else
+ continue;
+ }
+}
+
void rtw_parse_tbl_bb_pg(struct rtw_dev *rtwdev, const struct rtw_table *tbl)
{
const struct phy_pg_cfg_pair *p = tbl->data;
@@ -721,12 +1128,142 @@ void rtw_parse_tbl_bb_pg(struct rtw_dev *rtwdev, const struct rtw_table *tbl)
msleep(50);
continue;
}
- phy_store_tx_power_by_rate(rtwdev, p->band, p->rf_path,
- p->tx_num, p->addr, p->bitmask,
- p->data);
+ rtw_phy_store_tx_power_by_rate(rtwdev, p->band, p->rf_path,
+ p->tx_num, p->addr, p->bitmask,
+ p->data);
+ }
+}
+
+static const u8 rtw_channel_idx_5g[RTW_MAX_CHANNEL_NUM_5G] = {
+ 36, 38, 40, 42, 44, 46, 48, /* Band 1 */
+ 52, 54, 56, 58, 60, 62, 64, /* Band 2 */
+ 100, 102, 104, 106, 108, 110, 112, /* Band 3 */
+ 116, 118, 120, 122, 124, 126, 128, /* Band 3 */
+ 132, 134, 136, 138, 140, 142, 144, /* Band 3 */
+ 149, 151, 153, 155, 157, 159, 161, /* Band 4 */
+ 165, 167, 169, 171, 173, 175, 177}; /* Band 4 */
+
+static int rtw_channel_to_idx(u8 band, u8 channel)
+{
+ int ch_idx;
+ u8 n_channel;
+
+ if (band == PHY_BAND_2G) {
+ ch_idx = channel - 1;
+ n_channel = RTW_MAX_CHANNEL_NUM_2G;
+ } else if (band == PHY_BAND_5G) {
+ n_channel = RTW_MAX_CHANNEL_NUM_5G;
+ for (ch_idx = 0; ch_idx < n_channel; ch_idx++)
+ if (rtw_channel_idx_5g[ch_idx] == channel)
+ break;
+ } else {
+ return -1;
+ }
+
+ if (ch_idx >= n_channel)
+ return -1;
+
+ return ch_idx;
+}
+
+static void rtw_phy_set_tx_power_limit(struct rtw_dev *rtwdev, u8 regd, u8 band,
+ u8 bw, u8 rs, u8 ch, s8 pwr_limit)
+{
+ struct rtw_hal *hal = &rtwdev->hal;
+ u8 max_power_index = rtwdev->chip->max_power_index;
+ s8 ww;
+ int ch_idx;
+
+ pwr_limit = clamp_t(s8, pwr_limit,
+ -max_power_index, max_power_index);
+ ch_idx = rtw_channel_to_idx(band, ch);
+
+ if (regd >= RTW_REGD_MAX || bw >= RTW_CHANNEL_WIDTH_MAX ||
+ rs >= RTW_RATE_SECTION_MAX || ch_idx < 0) {
+ WARN(1,
+ "wrong txpwr_lmt regd=%u, band=%u bw=%u, rs=%u, ch_idx=%u, pwr_limit=%d\n",
+ regd, band, bw, rs, ch_idx, pwr_limit);
+ return;
+ }
+
+ if (band == PHY_BAND_2G) {
+ hal->tx_pwr_limit_2g[regd][bw][rs][ch_idx] = pwr_limit;
+ ww = hal->tx_pwr_limit_2g[RTW_REGD_WW][bw][rs][ch_idx];
+ ww = min_t(s8, ww, pwr_limit);
+ hal->tx_pwr_limit_2g[RTW_REGD_WW][bw][rs][ch_idx] = ww;
+ } else if (band == PHY_BAND_5G) {
+ hal->tx_pwr_limit_5g[regd][bw][rs][ch_idx] = pwr_limit;
+ ww = hal->tx_pwr_limit_5g[RTW_REGD_WW][bw][rs][ch_idx];
+ ww = min_t(s8, ww, pwr_limit);
+ hal->tx_pwr_limit_5g[RTW_REGD_WW][bw][rs][ch_idx] = ww;
}
}
+/* cross-reference 5G power limits if values are not assigned */
+static void
+rtw_xref_5g_txpwr_lmt(struct rtw_dev *rtwdev, u8 regd,
+ u8 bw, u8 ch_idx, u8 rs_ht, u8 rs_vht)
+{
+ struct rtw_hal *hal = &rtwdev->hal;
+ u8 max_power_index = rtwdev->chip->max_power_index;
+ s8 lmt_ht = hal->tx_pwr_limit_5g[regd][bw][rs_ht][ch_idx];
+ s8 lmt_vht = hal->tx_pwr_limit_5g[regd][bw][rs_vht][ch_idx];
+
+ if (lmt_ht == lmt_vht)
+ return;
+
+ if (lmt_ht == max_power_index)
+ hal->tx_pwr_limit_5g[regd][bw][rs_ht][ch_idx] = lmt_vht;
+
+ else if (lmt_vht == max_power_index)
+ hal->tx_pwr_limit_5g[regd][bw][rs_vht][ch_idx] = lmt_ht;
+}
+
+/* cross-reference power limits for ht and vht */
+static void
+rtw_xref_txpwr_lmt_by_rs(struct rtw_dev *rtwdev, u8 regd, u8 bw, u8 ch_idx)
+{
+ u8 rs_idx, rs_ht, rs_vht;
+ u8 rs_cmp[2][2] = {{RTW_RATE_SECTION_HT_1S, RTW_RATE_SECTION_VHT_1S},
+ {RTW_RATE_SECTION_HT_2S, RTW_RATE_SECTION_VHT_2S} };
+
+ for (rs_idx = 0; rs_idx < 2; rs_idx++) {
+ rs_ht = rs_cmp[rs_idx][0];
+ rs_vht = rs_cmp[rs_idx][1];
+
+ rtw_xref_5g_txpwr_lmt(rtwdev, regd, bw, ch_idx, rs_ht, rs_vht);
+ }
+}
+
+/* cross-reference power limits for 5G channels */
+static void
+rtw_xref_5g_txpwr_lmt_by_ch(struct rtw_dev *rtwdev, u8 regd, u8 bw)
+{
+ u8 ch_idx;
+
+ for (ch_idx = 0; ch_idx < RTW_MAX_CHANNEL_NUM_5G; ch_idx++)
+ rtw_xref_txpwr_lmt_by_rs(rtwdev, regd, bw, ch_idx);
+}
+
+/* cross-reference power limits for 20/40M bandwidth */
+static void
+rtw_xref_txpwr_lmt_by_bw(struct rtw_dev *rtwdev, u8 regd)
+{
+ u8 bw;
+
+ for (bw = RTW_CHANNEL_WIDTH_20; bw <= RTW_CHANNEL_WIDTH_40; bw++)
+ rtw_xref_5g_txpwr_lmt_by_ch(rtwdev, regd, bw);
+}
+
+/* cross-reference power limits */
+static void rtw_xref_txpwr_lmt(struct rtw_dev *rtwdev)
+{
+ u8 regd;
+
+ for (regd = 0; regd < RTW_REGD_MAX; regd++)
+ rtw_xref_txpwr_lmt_by_bw(rtwdev, regd);
+}
+
void rtw_parse_tbl_txpwr_lmt(struct rtw_dev *rtwdev,
const struct rtw_table *tbl)
{
@@ -736,10 +1273,11 @@ void rtw_parse_tbl_txpwr_lmt(struct rtw_dev *rtwdev,
BUILD_BUG_ON(sizeof(struct txpwr_lmt_cfg_pair) != sizeof(u8) * 6);
for (; p < end; p++) {
- phy_set_tx_power_limit(rtwdev, p->regd, p->band,
- p->bw, p->rs,
- p->ch, p->txpwr_lmt);
+ rtw_phy_set_tx_power_limit(rtwdev, p->regd, p->band,
+ p->bw, p->rs, p->ch, p->txpwr_lmt);
}
+
+ rtw_xref_txpwr_lmt(rtwdev);
}
void rtw_phy_cfg_mac(struct rtw_dev *rtwdev, const struct rtw_table *tbl,
@@ -814,92 +1352,6 @@ void rtw_phy_load_tables(struct rtw_dev *rtwdev)
}
}
-#define bcd_to_dec_pwr_by_rate(val, i) bcd2bin(val >> (i * 8))
-
-#define RTW_MAX_POWER_INDEX 0x3F
-
-u8 rtw_cck_rates[] = { DESC_RATE1M, DESC_RATE2M, DESC_RATE5_5M, DESC_RATE11M };
-u8 rtw_ofdm_rates[] = {
- DESC_RATE6M, DESC_RATE9M, DESC_RATE12M,
- DESC_RATE18M, DESC_RATE24M, DESC_RATE36M,
- DESC_RATE48M, DESC_RATE54M
-};
-u8 rtw_ht_1s_rates[] = {
- DESC_RATEMCS0, DESC_RATEMCS1, DESC_RATEMCS2,
- DESC_RATEMCS3, DESC_RATEMCS4, DESC_RATEMCS5,
- DESC_RATEMCS6, DESC_RATEMCS7
-};
-u8 rtw_ht_2s_rates[] = {
- DESC_RATEMCS8, DESC_RATEMCS9, DESC_RATEMCS10,
- DESC_RATEMCS11, DESC_RATEMCS12, DESC_RATEMCS13,
- DESC_RATEMCS14, DESC_RATEMCS15
-};
-u8 rtw_vht_1s_rates[] = {
- DESC_RATEVHT1SS_MCS0, DESC_RATEVHT1SS_MCS1,
- DESC_RATEVHT1SS_MCS2, DESC_RATEVHT1SS_MCS3,
- DESC_RATEVHT1SS_MCS4, DESC_RATEVHT1SS_MCS5,
- DESC_RATEVHT1SS_MCS6, DESC_RATEVHT1SS_MCS7,
- DESC_RATEVHT1SS_MCS8, DESC_RATEVHT1SS_MCS9
-};
-u8 rtw_vht_2s_rates[] = {
- DESC_RATEVHT2SS_MCS0, DESC_RATEVHT2SS_MCS1,
- DESC_RATEVHT2SS_MCS2, DESC_RATEVHT2SS_MCS3,
- DESC_RATEVHT2SS_MCS4, DESC_RATEVHT2SS_MCS5,
- DESC_RATEVHT2SS_MCS6, DESC_RATEVHT2SS_MCS7,
- DESC_RATEVHT2SS_MCS8, DESC_RATEVHT2SS_MCS9
-};
-u8 rtw_cck_size = ARRAY_SIZE(rtw_cck_rates);
-u8 rtw_ofdm_size = ARRAY_SIZE(rtw_ofdm_rates);
-u8 rtw_ht_1s_size = ARRAY_SIZE(rtw_ht_1s_rates);
-u8 rtw_ht_2s_size = ARRAY_SIZE(rtw_ht_2s_rates);
-u8 rtw_vht_1s_size = ARRAY_SIZE(rtw_vht_1s_rates);
-u8 rtw_vht_2s_size = ARRAY_SIZE(rtw_vht_2s_rates);
-u8 *rtw_rate_section[RTW_RATE_SECTION_MAX] = {
- rtw_cck_rates, rtw_ofdm_rates,
- rtw_ht_1s_rates, rtw_ht_2s_rates,
- rtw_vht_1s_rates, rtw_vht_2s_rates
-};
-u8 rtw_rate_size[RTW_RATE_SECTION_MAX] = {
- ARRAY_SIZE(rtw_cck_rates),
- ARRAY_SIZE(rtw_ofdm_rates),
- ARRAY_SIZE(rtw_ht_1s_rates),
- ARRAY_SIZE(rtw_ht_2s_rates),
- ARRAY_SIZE(rtw_vht_1s_rates),
- ARRAY_SIZE(rtw_vht_2s_rates)
-};
-
-static const u8 rtw_channel_idx_5g[RTW_MAX_CHANNEL_NUM_5G] = {
- 36, 38, 40, 42, 44, 46, 48, /* Band 1 */
- 52, 54, 56, 58, 60, 62, 64, /* Band 2 */
- 100, 102, 104, 106, 108, 110, 112, /* Band 3 */
- 116, 118, 120, 122, 124, 126, 128, /* Band 3 */
- 132, 134, 136, 138, 140, 142, 144, /* Band 3 */
- 149, 151, 153, 155, 157, 159, 161, /* Band 4 */
- 165, 167, 169, 171, 173, 175, 177}; /* Band 4 */
-
-static int rtw_channel_to_idx(u8 band, u8 channel)
-{
- int ch_idx;
- u8 n_channel;
-
- if (band == PHY_BAND_2G) {
- ch_idx = channel - 1;
- n_channel = RTW_MAX_CHANNEL_NUM_2G;
- } else if (band == PHY_BAND_5G) {
- n_channel = RTW_MAX_CHANNEL_NUM_5G;
- for (ch_idx = 0; ch_idx < n_channel; ch_idx++)
- if (rtw_channel_idx_5g[ch_idx] == channel)
- break;
- } else {
- return -1;
- }
-
- if (ch_idx >= n_channel)
- return -1;
-
- return ch_idx;
-}
-
static u8 rtw_get_channel_group(u8 channel)
{
switch (channel) {
@@ -989,10 +1441,10 @@ static u8 rtw_get_channel_group(u8 channel)
}
}
-static u8 phy_get_2g_tx_power_index(struct rtw_dev *rtwdev,
- struct rtw_2g_txpwr_idx *pwr_idx_2g,
- enum rtw_bandwidth bandwidth,
- u8 rate, u8 group)
+static u8 rtw_phy_get_2g_tx_power_index(struct rtw_dev *rtwdev,
+ struct rtw_2g_txpwr_idx *pwr_idx_2g,
+ enum rtw_bandwidth bandwidth,
+ u8 rate, u8 group)
{
struct rtw_chip_info *chip = rtwdev->chip;
u8 tx_power;
@@ -1036,10 +1488,10 @@ static u8 phy_get_2g_tx_power_index(struct rtw_dev *rtwdev,
return tx_power;
}
-static u8 phy_get_5g_tx_power_index(struct rtw_dev *rtwdev,
- struct rtw_5g_txpwr_idx *pwr_idx_5g,
- enum rtw_bandwidth bandwidth,
- u8 rate, u8 group)
+static u8 rtw_phy_get_5g_tx_power_index(struct rtw_dev *rtwdev,
+ struct rtw_5g_txpwr_idx *pwr_idx_5g,
+ enum rtw_bandwidth bandwidth,
+ u8 rate, u8 group)
{
struct rtw_chip_info *chip = rtwdev->chip;
u8 tx_power;
@@ -1090,81 +1542,112 @@ static u8 phy_get_5g_tx_power_index(struct rtw_dev *rtwdev,
return tx_power;
}
-/* set tx power level by path for each rates, note that the order of the rates
- * are *very* important, bacause 8822B/8821C combines every four bytes of tx
- * power index into a four-byte power index register, and calls set_tx_agc to
- * write these values into hardware
- */
-static
-void phy_set_tx_power_level_by_path(struct rtw_dev *rtwdev, u8 ch, u8 path)
+static s8 rtw_phy_get_tx_power_limit(struct rtw_dev *rtwdev, u8 band,
+ enum rtw_bandwidth bw, u8 rf_path,
+ u8 rate, u8 channel, u8 regd)
{
struct rtw_hal *hal = &rtwdev->hal;
+ u8 *cch_by_bw = hal->cch_by_bw;
+ s8 power_limit = (s8)rtwdev->chip->max_power_index;
u8 rs;
+ int ch_idx;
+ u8 cur_bw, cur_ch;
+ s8 cur_lmt;
- /* do not need cck rates if we are not in 2.4G */
- if (hal->current_band_type == RTW_BAND_2G)
+ if (regd > RTW_REGD_WW)
+ return power_limit;
+
+ if (rate >= DESC_RATE1M && rate <= DESC_RATE11M)
rs = RTW_RATE_SECTION_CCK;
- else
+ else if (rate >= DESC_RATE6M && rate <= DESC_RATE54M)
rs = RTW_RATE_SECTION_OFDM;
+ else if (rate >= DESC_RATEMCS0 && rate <= DESC_RATEMCS7)
+ rs = RTW_RATE_SECTION_HT_1S;
+ else if (rate >= DESC_RATEMCS8 && rate <= DESC_RATEMCS15)
+ rs = RTW_RATE_SECTION_HT_2S;
+ else if (rate >= DESC_RATEVHT1SS_MCS0 && rate <= DESC_RATEVHT1SS_MCS9)
+ rs = RTW_RATE_SECTION_VHT_1S;
+ else if (rate >= DESC_RATEVHT2SS_MCS0 && rate <= DESC_RATEVHT2SS_MCS9)
+ rs = RTW_RATE_SECTION_VHT_2S;
+ else
+ goto err;
- for (; rs < RTW_RATE_SECTION_MAX; rs++)
- phy_set_tx_power_index_by_rs(rtwdev, ch, path, rs);
-}
+ /* only 20M BW with cck and ofdm */
+ if (rs == RTW_RATE_SECTION_CCK || rs == RTW_RATE_SECTION_OFDM)
+ bw = RTW_CHANNEL_WIDTH_20;
-void rtw_phy_set_tx_power_level(struct rtw_dev *rtwdev, u8 channel)
-{
- struct rtw_chip_info *chip = rtwdev->chip;
- struct rtw_hal *hal = &rtwdev->hal;
- u8 path;
+ /* only 20/40M BW with ht */
+ if (rs == RTW_RATE_SECTION_HT_1S || rs == RTW_RATE_SECTION_HT_2S)
+ bw = min_t(u8, bw, RTW_CHANNEL_WIDTH_40);
- mutex_lock(&hal->tx_power_mutex);
+ /* select min power limit among [20M BW ~ current BW] */
+ for (cur_bw = RTW_CHANNEL_WIDTH_20; cur_bw <= bw; cur_bw++) {
+ cur_ch = cch_by_bw[cur_bw];
- for (path = 0; path < hal->rf_path_num; path++)
- phy_set_tx_power_level_by_path(rtwdev, channel, path);
+ ch_idx = rtw_channel_to_idx(band, cur_ch);
+ if (ch_idx < 0)
+ goto err;
- chip->ops->set_tx_power_index(rtwdev);
- mutex_unlock(&hal->tx_power_mutex);
-}
+ cur_lmt = cur_ch <= RTW_MAX_CHANNEL_NUM_2G ?
+ hal->tx_pwr_limit_2g[regd][cur_bw][rs][ch_idx] :
+ hal->tx_pwr_limit_5g[regd][cur_bw][rs][ch_idx];
+
+ power_limit = min_t(s8, cur_lmt, power_limit);
+ }
+
+ return power_limit;
-s8 phy_get_tx_power_limit(struct rtw_dev *rtwdev, u8 band,
- enum rtw_bandwidth bandwidth, u8 rf_path,
- u8 rate, u8 channel, u8 regd);
+err:
+ WARN(1, "invalid arguments, band=%d, bw=%d, path=%d, rate=%d, ch=%d\n",
+ band, bw, rf_path, rate, channel);
+ return (s8)rtwdev->chip->max_power_index;
+}
-static
-u8 phy_get_tx_power_index(void *adapter, u8 rf_path, u8 rate,
- enum rtw_bandwidth bandwidth, u8 channel, u8 regd)
+void rtw_get_tx_power_params(struct rtw_dev *rtwdev, u8 path, u8 rate, u8 bw,
+ u8 ch, u8 regd, struct rtw_power_params *pwr_param)
{
- struct rtw_dev *rtwdev = adapter;
struct rtw_hal *hal = &rtwdev->hal;
struct rtw_txpwr_idx *pwr_idx;
- u8 tx_power;
- u8 group;
- u8 band;
- s8 offset, limit;
+ u8 group, band;
+ u8 *base = &pwr_param->pwr_base;
+ s8 *offset = &pwr_param->pwr_offset;
+ s8 *limit = &pwr_param->pwr_limit;
- pwr_idx = &rtwdev->efuse.txpwr_idx_table[rf_path];
- group = rtw_get_channel_group(channel);
+ pwr_idx = &rtwdev->efuse.txpwr_idx_table[path];
+ group = rtw_get_channel_group(ch);
/* base power index for 2.4G/5G */
- if (channel <= 14) {
+ if (ch <= 14) {
band = PHY_BAND_2G;
- tx_power = phy_get_2g_tx_power_index(rtwdev,
- &pwr_idx->pwr_idx_2g,
- bandwidth, rate, group);
- offset = hal->tx_pwr_by_rate_offset_2g[rf_path][rate];
+ *base = rtw_phy_get_2g_tx_power_index(rtwdev,
+ &pwr_idx->pwr_idx_2g,
+ bw, rate, group);
+ *offset = hal->tx_pwr_by_rate_offset_2g[path][rate];
} else {
band = PHY_BAND_5G;
- tx_power = phy_get_5g_tx_power_index(rtwdev,
- &pwr_idx->pwr_idx_5g,
- bandwidth, rate, group);
- offset = hal->tx_pwr_by_rate_offset_5g[rf_path][rate];
+ *base = rtw_phy_get_5g_tx_power_index(rtwdev,
+ &pwr_idx->pwr_idx_5g,
+ bw, rate, group);
+ *offset = hal->tx_pwr_by_rate_offset_5g[path][rate];
}
- limit = phy_get_tx_power_limit(rtwdev, band, bandwidth, rf_path,
- rate, channel, regd);
+ *limit = rtw_phy_get_tx_power_limit(rtwdev, band, bw, path,
+ rate, ch, regd);
+}
+
+u8
+rtw_phy_get_tx_power_index(struct rtw_dev *rtwdev, u8 rf_path, u8 rate,
+ enum rtw_bandwidth bandwidth, u8 channel, u8 regd)
+{
+ struct rtw_power_params pwr_param = {0};
+ u8 tx_power;
+ s8 offset;
+
+ rtw_get_tx_power_params(rtwdev, rf_path, rate, bandwidth,
+ channel, regd, &pwr_param);
- if (offset > limit)
- offset = limit;
+ tx_power = pwr_param.pwr_base;
+ offset = min_t(s8, pwr_param.pwr_offset, pwr_param.pwr_limit);
tx_power += offset;
@@ -1174,9 +1657,9 @@ u8 phy_get_tx_power_index(void *adapter, u8 rf_path, u8 rate,
return tx_power;
}
-void phy_set_tx_power_index_by_rs(void *adapter, u8 ch, u8 path, u8 rs)
+static void rtw_phy_set_tx_power_index_by_rs(struct rtw_dev *rtwdev,
+ u8 ch, u8 path, u8 rs)
{
- struct rtw_dev *rtwdev = adapter;
struct rtw_hal *hal = &rtwdev->hal;
u8 regd = rtwdev->regd.txpwr_regd;
u8 *rates;
@@ -1194,361 +1677,51 @@ void phy_set_tx_power_index_by_rs(void *adapter, u8 ch, u8 path, u8 rs)
bw = hal->current_band_width;
for (i = 0; i < size; i++) {
rate = rates[i];
- pwr_idx = phy_get_tx_power_index(adapter, path, rate, bw, ch,
- regd);
+ pwr_idx = rtw_phy_get_tx_power_index(rtwdev, path, rate,
+ bw, ch, regd);
hal->tx_pwr_tbl[path][rate] = pwr_idx;
}
}
-static u8 tbl_to_dec_pwr_by_rate(struct rtw_dev *rtwdev, u32 hex, u8 i)
-{
- if (rtwdev->chip->is_pwr_by_rate_dec)
- return bcd_to_dec_pwr_by_rate(hex, i);
- else
- return (hex >> (i * 8)) & 0xFF;
-}
-
-static void phy_get_rate_values_of_txpwr_by_rate(struct rtw_dev *rtwdev,
- u32 addr, u32 mask,
- u32 val, u8 *rate,
- u8 *pwr_by_rate, u8 *rate_num)
+/* set tx power level by path for each rates, note that the order of the rates
+ * are *very* important, bacause 8822B/8821C combines every four bytes of tx
+ * power index into a four-byte power index register, and calls set_tx_agc to
+ * write these values into hardware
+ */
+static void rtw_phy_set_tx_power_level_by_path(struct rtw_dev *rtwdev,
+ u8 ch, u8 path)
{
- int i;
+ struct rtw_hal *hal = &rtwdev->hal;
+ u8 rs;
- switch (addr) {
- case 0xE00:
- case 0x830:
- rate[0] = DESC_RATE6M;
- rate[1] = DESC_RATE9M;
- rate[2] = DESC_RATE12M;
- rate[3] = DESC_RATE18M;
- for (i = 0; i < 4; ++i)
- pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
- *rate_num = 4;
- break;
- case 0xE04:
- case 0x834:
- rate[0] = DESC_RATE24M;
- rate[1] = DESC_RATE36M;
- rate[2] = DESC_RATE48M;
- rate[3] = DESC_RATE54M;
- for (i = 0; i < 4; ++i)
- pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
- *rate_num = 4;
- break;
- case 0xE08:
- rate[0] = DESC_RATE1M;
- pwr_by_rate[0] = bcd_to_dec_pwr_by_rate(val, 1);
- *rate_num = 1;
- break;
- case 0x86C:
- if (mask == 0xffffff00) {
- rate[0] = DESC_RATE2M;
- rate[1] = DESC_RATE5_5M;
- rate[2] = DESC_RATE11M;
- for (i = 1; i < 4; ++i)
- pwr_by_rate[i - 1] =
- tbl_to_dec_pwr_by_rate(rtwdev, val, i);
- *rate_num = 3;
- } else if (mask == 0x000000ff) {
- rate[0] = DESC_RATE11M;
- pwr_by_rate[0] = bcd_to_dec_pwr_by_rate(val, 0);
- *rate_num = 1;
- }
- break;
- case 0xE10:
- case 0x83C:
- rate[0] = DESC_RATEMCS0;
- rate[1] = DESC_RATEMCS1;
- rate[2] = DESC_RATEMCS2;
- rate[3] = DESC_RATEMCS3;
- for (i = 0; i < 4; ++i)
- pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
- *rate_num = 4;
- break;
- case 0xE14:
- case 0x848:
- rate[0] = DESC_RATEMCS4;
- rate[1] = DESC_RATEMCS5;
- rate[2] = DESC_RATEMCS6;
- rate[3] = DESC_RATEMCS7;
- for (i = 0; i < 4; ++i)
- pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
- *rate_num = 4;
- break;
- case 0xE18:
- case 0x84C:
- rate[0] = DESC_RATEMCS8;
- rate[1] = DESC_RATEMCS9;
- rate[2] = DESC_RATEMCS10;
- rate[3] = DESC_RATEMCS11;
- for (i = 0; i < 4; ++i)
- pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
- *rate_num = 4;
- break;
- case 0xE1C:
- case 0x868:
- rate[0] = DESC_RATEMCS12;
- rate[1] = DESC_RATEMCS13;
- rate[2] = DESC_RATEMCS14;
- rate[3] = DESC_RATEMCS15;
- for (i = 0; i < 4; ++i)
- pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
- *rate_num = 4;
+ /* do not need cck rates if we are not in 2.4G */
+ if (hal->current_band_type == RTW_BAND_2G)
+ rs = RTW_RATE_SECTION_CCK;
+ else
+ rs = RTW_RATE_SECTION_OFDM;
- break;
- case 0x838:
- rate[0] = DESC_RATE1M;
- rate[1] = DESC_RATE2M;
- rate[2] = DESC_RATE5_5M;
- for (i = 1; i < 4; ++i)
- pwr_by_rate[i - 1] = tbl_to_dec_pwr_by_rate(rtwdev,
- val, i);
- *rate_num = 3;
- break;
- case 0xC20:
- case 0xE20:
- case 0x1820:
- case 0x1A20:
- rate[0] = DESC_RATE1M;
- rate[1] = DESC_RATE2M;
- rate[2] = DESC_RATE5_5M;
- rate[3] = DESC_RATE11M;
- for (i = 0; i < 4; ++i)
- pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
- *rate_num = 4;
- break;
- case 0xC24:
- case 0xE24:
- case 0x1824:
- case 0x1A24:
- rate[0] = DESC_RATE6M;
- rate[1] = DESC_RATE9M;
- rate[2] = DESC_RATE12M;
- rate[3] = DESC_RATE18M;
- for (i = 0; i < 4; ++i)
- pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
- *rate_num = 4;
- break;
- case 0xC28:
- case 0xE28:
- case 0x1828:
- case 0x1A28:
- rate[0] = DESC_RATE24M;
- rate[1] = DESC_RATE36M;
- rate[2] = DESC_RATE48M;
- rate[3] = DESC_RATE54M;
- for (i = 0; i < 4; ++i)
- pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
- *rate_num = 4;
- break;
- case 0xC2C:
- case 0xE2C:
- case 0x182C:
- case 0x1A2C:
- rate[0] = DESC_RATEMCS0;
- rate[1] = DESC_RATEMCS1;
- rate[2] = DESC_RATEMCS2;
- rate[3] = DESC_RATEMCS3;
- for (i = 0; i < 4; ++i)
- pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
- *rate_num = 4;
- break;
- case 0xC30:
- case 0xE30:
- case 0x1830:
- case 0x1A30:
- rate[0] = DESC_RATEMCS4;
- rate[1] = DESC_RATEMCS5;
- rate[2] = DESC_RATEMCS6;
- rate[3] = DESC_RATEMCS7;
- for (i = 0; i < 4; ++i)
- pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
- *rate_num = 4;
- break;
- case 0xC34:
- case 0xE34:
- case 0x1834:
- case 0x1A34:
- rate[0] = DESC_RATEMCS8;
- rate[1] = DESC_RATEMCS9;
- rate[2] = DESC_RATEMCS10;
- rate[3] = DESC_RATEMCS11;
- for (i = 0; i < 4; ++i)
- pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
- *rate_num = 4;
- break;
- case 0xC38:
- case 0xE38:
- case 0x1838:
- case 0x1A38:
- rate[0] = DESC_RATEMCS12;
- rate[1] = DESC_RATEMCS13;
- rate[2] = DESC_RATEMCS14;
- rate[3] = DESC_RATEMCS15;
- for (i = 0; i < 4; ++i)
- pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
- *rate_num = 4;
- break;
- case 0xC3C:
- case 0xE3C:
- case 0x183C:
- case 0x1A3C:
- rate[0] = DESC_RATEVHT1SS_MCS0;
- rate[1] = DESC_RATEVHT1SS_MCS1;
- rate[2] = DESC_RATEVHT1SS_MCS2;
- rate[3] = DESC_RATEVHT1SS_MCS3;
- for (i = 0; i < 4; ++i)
- pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
- *rate_num = 4;
- break;
- case 0xC40:
- case 0xE40:
- case 0x1840:
- case 0x1A40:
- rate[0] = DESC_RATEVHT1SS_MCS4;
- rate[1] = DESC_RATEVHT1SS_MCS5;
- rate[2] = DESC_RATEVHT1SS_MCS6;
- rate[3] = DESC_RATEVHT1SS_MCS7;
- for (i = 0; i < 4; ++i)
- pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
- *rate_num = 4;
- break;
- case 0xC44:
- case 0xE44:
- case 0x1844:
- case 0x1A44:
- rate[0] = DESC_RATEVHT1SS_MCS8;
- rate[1] = DESC_RATEVHT1SS_MCS9;
- rate[2] = DESC_RATEVHT2SS_MCS0;
- rate[3] = DESC_RATEVHT2SS_MCS1;
- for (i = 0; i < 4; ++i)
- pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
- *rate_num = 4;
- break;
- case 0xC48:
- case 0xE48:
- case 0x1848:
- case 0x1A48:
- rate[0] = DESC_RATEVHT2SS_MCS2;
- rate[1] = DESC_RATEVHT2SS_MCS3;
- rate[2] = DESC_RATEVHT2SS_MCS4;
- rate[3] = DESC_RATEVHT2SS_MCS5;
- for (i = 0; i < 4; ++i)
- pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
- *rate_num = 4;
- break;
- case 0xC4C:
- case 0xE4C:
- case 0x184C:
- case 0x1A4C:
- rate[0] = DESC_RATEVHT2SS_MCS6;
- rate[1] = DESC_RATEVHT2SS_MCS7;
- rate[2] = DESC_RATEVHT2SS_MCS8;
- rate[3] = DESC_RATEVHT2SS_MCS9;
- for (i = 0; i < 4; ++i)
- pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
- *rate_num = 4;
- break;
- case 0xCD8:
- case 0xED8:
- case 0x18D8:
- case 0x1AD8:
- rate[0] = DESC_RATEMCS16;
- rate[1] = DESC_RATEMCS17;
- rate[2] = DESC_RATEMCS18;
- rate[3] = DESC_RATEMCS19;
- for (i = 0; i < 4; ++i)
- pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
- *rate_num = 4;
- break;
- case 0xCDC:
- case 0xEDC:
- case 0x18DC:
- case 0x1ADC:
- rate[0] = DESC_RATEMCS20;
- rate[1] = DESC_RATEMCS21;
- rate[2] = DESC_RATEMCS22;
- rate[3] = DESC_RATEMCS23;
- for (i = 0; i < 4; ++i)
- pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
- *rate_num = 4;
- break;
- case 0xCE0:
- case 0xEE0:
- case 0x18E0:
- case 0x1AE0:
- rate[0] = DESC_RATEVHT3SS_MCS0;
- rate[1] = DESC_RATEVHT3SS_MCS1;
- rate[2] = DESC_RATEVHT3SS_MCS2;
- rate[3] = DESC_RATEVHT3SS_MCS3;
- for (i = 0; i < 4; ++i)
- pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
- *rate_num = 4;
- break;
- case 0xCE4:
- case 0xEE4:
- case 0x18E4:
- case 0x1AE4:
- rate[0] = DESC_RATEVHT3SS_MCS4;
- rate[1] = DESC_RATEVHT3SS_MCS5;
- rate[2] = DESC_RATEVHT3SS_MCS6;
- rate[3] = DESC_RATEVHT3SS_MCS7;
- for (i = 0; i < 4; ++i)
- pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
- *rate_num = 4;
- break;
- case 0xCE8:
- case 0xEE8:
- case 0x18E8:
- case 0x1AE8:
- rate[0] = DESC_RATEVHT3SS_MCS8;
- rate[1] = DESC_RATEVHT3SS_MCS9;
- for (i = 0; i < 2; ++i)
- pwr_by_rate[i] = tbl_to_dec_pwr_by_rate(rtwdev, val, i);
- *rate_num = 2;
- break;
- default:
- rtw_warn(rtwdev, "invalid tx power index addr 0x%08x\n", addr);
- break;
- }
+ for (; rs < RTW_RATE_SECTION_MAX; rs++)
+ rtw_phy_set_tx_power_index_by_rs(rtwdev, ch, path, rs);
}
-void phy_store_tx_power_by_rate(void *adapter, u32 band, u32 rfpath, u32 txnum,
- u32 regaddr, u32 bitmask, u32 data)
+void rtw_phy_set_tx_power_level(struct rtw_dev *rtwdev, u8 channel)
{
- struct rtw_dev *rtwdev = adapter;
+ struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_hal *hal = &rtwdev->hal;
- u8 rate_num = 0;
- u8 rate;
- u8 rates[RTW_RF_PATH_MAX] = {0};
- s8 offset;
- s8 pwr_by_rate[RTW_RF_PATH_MAX] = {0};
- int i;
+ u8 path;
- phy_get_rate_values_of_txpwr_by_rate(rtwdev, regaddr, bitmask, data,
- rates, pwr_by_rate, &rate_num);
+ mutex_lock(&hal->tx_power_mutex);
- if (WARN_ON(rfpath >= RTW_RF_PATH_MAX ||
- (band != PHY_BAND_2G && band != PHY_BAND_5G) ||
- rate_num > RTW_RF_PATH_MAX))
- return;
+ for (path = 0; path < hal->rf_path_num; path++)
+ rtw_phy_set_tx_power_level_by_path(rtwdev, channel, path);
- for (i = 0; i < rate_num; i++) {
- offset = pwr_by_rate[i];
- rate = rates[i];
- if (band == PHY_BAND_2G)
- hal->tx_pwr_by_rate_offset_2g[rfpath][rate] = offset;
- else if (band == PHY_BAND_5G)
- hal->tx_pwr_by_rate_offset_5g[rfpath][rate] = offset;
- else
- continue;
- }
+ chip->ops->set_tx_power_index(rtwdev);
+ mutex_unlock(&hal->tx_power_mutex);
}
-static
-void phy_tx_power_by_rate_config_by_path(struct rtw_hal *hal, u8 path,
- u8 rs, u8 size, u8 *rates)
+static void
+rtw_phy_tx_power_by_rate_config_by_path(struct rtw_hal *hal, u8 path,
+ u8 rs, u8 size, u8 *rates)
{
u8 rate;
u8 base_idx, rate_idx;
@@ -1574,36 +1747,35 @@ void rtw_phy_tx_power_by_rate_config(struct rtw_hal *hal)
u8 path;
for (path = 0; path < RTW_RF_PATH_MAX; path++) {
- phy_tx_power_by_rate_config_by_path(hal, path,
+ rtw_phy_tx_power_by_rate_config_by_path(hal, path,
RTW_RATE_SECTION_CCK,
rtw_cck_size, rtw_cck_rates);
- phy_tx_power_by_rate_config_by_path(hal, path,
+ rtw_phy_tx_power_by_rate_config_by_path(hal, path,
RTW_RATE_SECTION_OFDM,
rtw_ofdm_size, rtw_ofdm_rates);
- phy_tx_power_by_rate_config_by_path(hal, path,
+ rtw_phy_tx_power_by_rate_config_by_path(hal, path,
RTW_RATE_SECTION_HT_1S,
rtw_ht_1s_size, rtw_ht_1s_rates);
- phy_tx_power_by_rate_config_by_path(hal, path,
+ rtw_phy_tx_power_by_rate_config_by_path(hal, path,
RTW_RATE_SECTION_HT_2S,
rtw_ht_2s_size, rtw_ht_2s_rates);
- phy_tx_power_by_rate_config_by_path(hal, path,
+ rtw_phy_tx_power_by_rate_config_by_path(hal, path,
RTW_RATE_SECTION_VHT_1S,
rtw_vht_1s_size, rtw_vht_1s_rates);
- phy_tx_power_by_rate_config_by_path(hal, path,
+ rtw_phy_tx_power_by_rate_config_by_path(hal, path,
RTW_RATE_SECTION_VHT_2S,
rtw_vht_2s_size, rtw_vht_2s_rates);
}
}
static void
-phy_tx_power_limit_config(struct rtw_hal *hal, u8 regd, u8 bw, u8 rs)
+__rtw_phy_tx_power_limit_config(struct rtw_hal *hal, u8 regd, u8 bw, u8 rs)
{
- s8 base, orig;
+ s8 base;
u8 ch;
for (ch = 0; ch < RTW_MAX_CHANNEL_NUM_2G; ch++) {
base = hal->tx_pwr_by_rate_base_2g[0][rs];
- orig = hal->tx_pwr_limit_2g[regd][bw][rs][ch];
hal->tx_pwr_limit_2g[regd][bw][rs][ch] -= base;
}
@@ -1617,98 +1789,34 @@ void rtw_phy_tx_power_limit_config(struct rtw_hal *hal)
{
u8 regd, bw, rs;
+ /* default at channel 1 */
+ hal->cch_by_bw[RTW_CHANNEL_WIDTH_20] = 1;
+
for (regd = 0; regd < RTW_REGD_MAX; regd++)
for (bw = 0; bw < RTW_CHANNEL_WIDTH_MAX; bw++)
for (rs = 0; rs < RTW_RATE_SECTION_MAX; rs++)
- phy_tx_power_limit_config(hal, regd, bw, rs);
-}
-
-static s8 get_tx_power_limit(struct rtw_hal *hal, u8 bw, u8 rs, u8 ch, u8 regd)
-{
- if (regd > RTW_REGD_WW)
- return RTW_MAX_POWER_INDEX;
-
- return hal->tx_pwr_limit_2g[regd][bw][rs][ch];
-}
-
-s8 phy_get_tx_power_limit(struct rtw_dev *rtwdev, u8 band,
- enum rtw_bandwidth bw, u8 rf_path,
- u8 rate, u8 channel, u8 regd)
-{
- struct rtw_hal *hal = &rtwdev->hal;
- s8 power_limit;
- u8 rs;
- int ch_idx;
-
- if (rate >= DESC_RATE1M && rate <= DESC_RATE11M)
- rs = RTW_RATE_SECTION_CCK;
- else if (rate >= DESC_RATE6M && rate <= DESC_RATE54M)
- rs = RTW_RATE_SECTION_OFDM;
- else if (rate >= DESC_RATEMCS0 && rate <= DESC_RATEMCS7)
- rs = RTW_RATE_SECTION_HT_1S;
- else if (rate >= DESC_RATEMCS8 && rate <= DESC_RATEMCS15)
- rs = RTW_RATE_SECTION_HT_2S;
- else if (rate >= DESC_RATEVHT1SS_MCS0 && rate <= DESC_RATEVHT1SS_MCS9)
- rs = RTW_RATE_SECTION_VHT_1S;
- else if (rate >= DESC_RATEVHT2SS_MCS0 && rate <= DESC_RATEVHT2SS_MCS9)
- rs = RTW_RATE_SECTION_VHT_2S;
- else
- goto err;
-
- ch_idx = rtw_channel_to_idx(band, channel);
- if (ch_idx < 0)
- goto err;
-
- power_limit = get_tx_power_limit(hal, bw, rs, ch_idx, regd);
-
- return power_limit;
-
-err:
- WARN(1, "invalid arguments, band=%d, bw=%d, path=%d, rate=%d, ch=%d\n",
- band, bw, rf_path, rate, channel);
- return RTW_MAX_POWER_INDEX;
+ __rtw_phy_tx_power_limit_config(hal, regd, bw, rs);
}
-void phy_set_tx_power_limit(struct rtw_dev *rtwdev, u8 regd, u8 band,
- u8 bw, u8 rs, u8 ch, s8 pwr_limit)
+static void rtw_phy_init_tx_power_limit(struct rtw_dev *rtwdev,
+ u8 regd, u8 bw, u8 rs)
{
struct rtw_hal *hal = &rtwdev->hal;
- int ch_idx;
-
- pwr_limit = clamp_t(s8, pwr_limit,
- -RTW_MAX_POWER_INDEX, RTW_MAX_POWER_INDEX);
- ch_idx = rtw_channel_to_idx(band, ch);
-
- if (regd >= RTW_REGD_MAX || bw >= RTW_CHANNEL_WIDTH_MAX ||
- rs >= RTW_RATE_SECTION_MAX || ch_idx < 0) {
- WARN(1,
- "wrong txpwr_lmt regd=%u, band=%u bw=%u, rs=%u, ch_idx=%u, pwr_limit=%d\n",
- regd, band, bw, rs, ch_idx, pwr_limit);
- return;
- }
-
- if (band == PHY_BAND_2G)
- hal->tx_pwr_limit_2g[regd][bw][rs][ch_idx] = pwr_limit;
- else if (band == PHY_BAND_5G)
- hal->tx_pwr_limit_5g[regd][bw][rs][ch_idx] = pwr_limit;
-}
-
-static
-void rtw_hw_tx_power_limit_init(struct rtw_hal *hal, u8 regd, u8 bw, u8 rs)
-{
+ s8 max_power_index = (s8)rtwdev->chip->max_power_index;
u8 ch;
/* 2.4G channels */
for (ch = 0; ch < RTW_MAX_CHANNEL_NUM_2G; ch++)
- hal->tx_pwr_limit_2g[regd][bw][rs][ch] = RTW_MAX_POWER_INDEX;
+ hal->tx_pwr_limit_2g[regd][bw][rs][ch] = max_power_index;
/* 5G channels */
for (ch = 0; ch < RTW_MAX_CHANNEL_NUM_5G; ch++)
- hal->tx_pwr_limit_5g[regd][bw][rs][ch] = RTW_MAX_POWER_INDEX;
+ hal->tx_pwr_limit_5g[regd][bw][rs][ch] = max_power_index;
}
-void rtw_hw_init_tx_power(struct rtw_hal *hal)
+void rtw_phy_init_tx_power(struct rtw_dev *rtwdev)
{
+ struct rtw_hal *hal = &rtwdev->hal;
u8 regd, path, rate, rs, bw;
/* init tx power by rate offset */
@@ -1723,5 +1831,6 @@ void rtw_hw_init_tx_power(struct rtw_hal *hal)
for (regd = 0; regd < RTW_REGD_MAX; regd++)
for (bw = 0; bw < RTW_CHANNEL_WIDTH_MAX; bw++)
for (rs = 0; rs < RTW_RATE_SECTION_MAX; rs++)
- rtw_hw_tx_power_limit_init(hal, regd, bw, rs);
+ rtw_phy_init_tx_power_limit(rtwdev, regd, bw,
+ rs);
}
diff --git a/drivers/net/wireless/realtek/rtw88/phy.h b/drivers/net/wireless/realtek/rtw88/phy.h
index ec03a2051e52..7c8eb732b13c 100644
--- a/drivers/net/wireless/realtek/rtw88/phy.h
+++ b/drivers/net/wireless/realtek/rtw88/phy.h
@@ -27,11 +27,6 @@ bool rtw_phy_write_rf_reg(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
u32 addr, u32 mask, u32 data);
bool rtw_phy_write_rf_reg_mix(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
u32 addr, u32 mask, u32 data);
-void phy_store_tx_power_by_rate(void *adapter, u32 band, u32 rfpath, u32 txnum,
- u32 regaddr, u32 bitmask, u32 data);
-void phy_set_tx_power_limit(struct rtw_dev *rtwdev, u8 regd, u8 band,
- u8 bw, u8 rs, u8 ch, s8 pwr_limit);
-void phy_set_tx_power_index_by_rs(void *adapter, u8 ch, u8 path, u8 rs);
void rtw_phy_setup_phy_cond(struct rtw_dev *rtwdev, u32 pkg);
void rtw_parse_tbl_phy_cond(struct rtw_dev *rtwdev, const struct rtw_table *tbl);
void rtw_parse_tbl_bb_pg(struct rtw_dev *rtwdev, const struct rtw_table *tbl);
@@ -44,7 +39,7 @@ void rtw_phy_cfg_bb(struct rtw_dev *rtwdev, const struct rtw_table *tbl,
u32 addr, u32 data);
void rtw_phy_cfg_rf(struct rtw_dev *rtwdev, const struct rtw_table *tbl,
u32 addr, u32 data);
-void rtw_hw_init_tx_power(struct rtw_hal *hal);
+void rtw_phy_init_tx_power(struct rtw_dev *rtwdev);
void rtw_phy_load_tables(struct rtw_dev *rtwdev);
void rtw_phy_set_tx_power_level(struct rtw_dev *rtwdev, u8 channel);
void rtw_phy_tx_power_by_rate_config(struct rtw_hal *hal);
@@ -110,6 +105,17 @@ static inline int rtw_check_supported_rfe(struct rtw_dev *rtwdev)
void rtw_phy_dig_write(struct rtw_dev *rtwdev, u8 igi);
+struct rtw_power_params {
+ u8 pwr_base;
+ s8 pwr_offset;
+ s8 pwr_limit;
+};
+
+void
+rtw_get_tx_power_params(struct rtw_dev *rtwdev, u8 path,
+ u8 rate, u8 bw, u8 ch, u8 regd,
+ struct rtw_power_params *pwr_param);
+
#define MASKBYTE0 0xff
#define MASKBYTE1 0xff00
#define MASKBYTE2 0xff0000
diff --git a/drivers/net/wireless/realtek/rtw88/regd.c b/drivers/net/wireless/realtek/rtw88/regd.c
index e7750a833a8e..69744dd65968 100644
--- a/drivers/net/wireless/realtek/rtw88/regd.c
+++ b/drivers/net/wireless/realtek/rtw88/regd.c
@@ -21,19 +21,19 @@ static const struct rtw_regulatory rtw_defined_chplan =
static const struct rtw_regulatory all_chplan_map[] = {
COUNTRY_CHPLAN_ENT("AD", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
- COUNTRY_CHPLAN_ENT("AE", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("AE", RTW_CHPLAN_WORLD_ETSI2, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("AF", RTW_CHPLAN_ETSI1_ETSI4, RTW_REGD_ETSI),
- COUNTRY_CHPLAN_ENT("AG", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("AG", RTW_CHPLAN_FCC2_FCC11, RTW_REGD_FCC),
COUNTRY_CHPLAN_ENT("AI", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("AL", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("AM", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
- COUNTRY_CHPLAN_ENT("AN", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("AN", RTW_CHPLAN_FCC2_FCC11, RTW_REGD_FCC),
COUNTRY_CHPLAN_ENT("AO", RTW_CHPLAN_WORLD_ETSI6, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("AQ", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("AR", RTW_CHPLAN_FCC2_FCC7, RTW_REGD_FCC),
COUNTRY_CHPLAN_ENT("AS", RTW_CHPLAN_FCC2_FCC11, RTW_REGD_FCC),
COUNTRY_CHPLAN_ENT("AT", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
- COUNTRY_CHPLAN_ENT("AU", RTW_CHPLAN_WORLD_ACMA1, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("AU", RTW_CHPLAN_WORLD_ACMA1, RTW_REGD_ACMA),
COUNTRY_CHPLAN_ENT("AW", RTW_CHPLAN_FCC2_FCC11, RTW_REGD_FCC),
COUNTRY_CHPLAN_ENT("AZ", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("BA", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
@@ -42,31 +42,34 @@ static const struct rtw_regulatory all_chplan_map[] = {
COUNTRY_CHPLAN_ENT("BE", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("BF", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("BG", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
- COUNTRY_CHPLAN_ENT("BH", RTW_CHPLAN_WORLD_ETSI6, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("BH", RTW_CHPLAN_WORLD_ETSI7, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("BI", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("BJ", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("BM", RTW_CHPLAN_FCC2_FCC11, RTW_REGD_FCC),
COUNTRY_CHPLAN_ENT("BN", RTW_CHPLAN_WORLD_ETSI6, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("BO", RTW_CHPLAN_WORLD_FCC7, RTW_REGD_FCC),
COUNTRY_CHPLAN_ENT("BR", RTW_CHPLAN_FCC2_FCC1, RTW_REGD_FCC),
COUNTRY_CHPLAN_ENT("BS", RTW_CHPLAN_FCC2_FCC11, RTW_REGD_FCC),
- COUNTRY_CHPLAN_ENT("BW", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("BT", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("BV", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("BW", RTW_CHPLAN_WORLD_ETSI2, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("BY", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("BZ", RTW_CHPLAN_FCC2_FCC11, RTW_REGD_FCC),
- COUNTRY_CHPLAN_ENT("CA", RTW_CHPLAN_IC1_IC2, RTW_REGD_FCC),
+ COUNTRY_CHPLAN_ENT("CA", RTW_CHPLAN_IC1_IC2, RTW_REGD_IC),
COUNTRY_CHPLAN_ENT("CC", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("CD", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("CF", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("CG", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("CH", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
- COUNTRY_CHPLAN_ENT("CI", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("CI", RTW_CHPLAN_ETSI1_ETSI4, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("CK", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
- COUNTRY_CHPLAN_ENT("CL", RTW_CHPLAN_WORLD_CHILE1, RTW_REGD_FCC),
+ COUNTRY_CHPLAN_ENT("CL", RTW_CHPLAN_WORLD_CHILE1, RTW_REGD_CHILE),
COUNTRY_CHPLAN_ENT("CM", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("CN", RTW_CHPLAN_WORLD_ETSI7, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("CO", RTW_CHPLAN_FCC2_FCC11, RTW_REGD_FCC),
COUNTRY_CHPLAN_ENT("CR", RTW_CHPLAN_FCC2_FCC11, RTW_REGD_FCC),
COUNTRY_CHPLAN_ENT("CV", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
- COUNTRY_CHPLAN_ENT("CX", RTW_CHPLAN_WORLD_ACMA1, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("CX", RTW_CHPLAN_WORLD_ACMA1, RTW_REGD_ACMA),
COUNTRY_CHPLAN_ENT("CY", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("CZ", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("DE", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
@@ -90,7 +93,7 @@ static const struct rtw_regulatory all_chplan_map[] = {
COUNTRY_CHPLAN_ENT("FR", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("GA", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("GB", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
- COUNTRY_CHPLAN_ENT("GD", RTW_CHPLAN_FCC1_FCC7, RTW_REGD_FCC),
+ COUNTRY_CHPLAN_ENT("GD", RTW_CHPLAN_FCC2_FCC11, RTW_REGD_FCC),
COUNTRY_CHPLAN_ENT("GE", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("GF", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("GG", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
@@ -107,8 +110,8 @@ static const struct rtw_regulatory all_chplan_map[] = {
COUNTRY_CHPLAN_ENT("GU", RTW_CHPLAN_FCC2_FCC11, RTW_REGD_FCC),
COUNTRY_CHPLAN_ENT("GW", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("GY", RTW_CHPLAN_FCC1_NCC3, RTW_REGD_FCC),
- COUNTRY_CHPLAN_ENT("HK", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
- COUNTRY_CHPLAN_ENT("HM", RTW_CHPLAN_WORLD_ACMA1, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("HK", RTW_CHPLAN_WORLD_ETSI2, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("HM", RTW_CHPLAN_WORLD_ACMA1, RTW_REGD_ACMA),
COUNTRY_CHPLAN_ENT("HN", RTW_CHPLAN_WORLD_FCC5, RTW_REGD_FCC),
COUNTRY_CHPLAN_ENT("HR", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("HT", RTW_CHPLAN_FCC2_FCC11, RTW_REGD_FCC),
@@ -118,20 +121,22 @@ static const struct rtw_regulatory all_chplan_map[] = {
COUNTRY_CHPLAN_ENT("IL", RTW_CHPLAN_WORLD_ETSI6, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("IM", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("IN", RTW_CHPLAN_WORLD_ETSI7, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("IO", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("IQ", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("IR", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("IS", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("IT", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("JE", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
- COUNTRY_CHPLAN_ENT("JM", RTW_CHPLAN_WORLD_ETSI10, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("JM", RTW_CHPLAN_WORLD_FCC5, RTW_REGD_FCC),
COUNTRY_CHPLAN_ENT("JO", RTW_CHPLAN_WORLD_ETSI8, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("JP", RTW_CHPLAN_MKK1_MKK1, RTW_REGD_MKK),
COUNTRY_CHPLAN_ENT("KE", RTW_CHPLAN_WORLD_ETSI6, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("KG", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("KH", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("KI", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("KM", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("KN", RTW_CHPLAN_FCC2_FCC11, RTW_REGD_FCC),
- COUNTRY_CHPLAN_ENT("KR", RTW_CHPLAN_KCC1_KCC2, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("KR", RTW_CHPLAN_KCC1_KCC3, RTW_REGD_KCC),
COUNTRY_CHPLAN_ENT("KW", RTW_CHPLAN_WORLD_ETSI6, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("KY", RTW_CHPLAN_FCC2_FCC11, RTW_REGD_FCC),
COUNTRY_CHPLAN_ENT("KZ", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
@@ -157,7 +162,7 @@ static const struct rtw_regulatory all_chplan_map[] = {
COUNTRY_CHPLAN_ENT("ML", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("MM", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("MN", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
- COUNTRY_CHPLAN_ENT("MO", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("MO", RTW_CHPLAN_WORLD_ETSI2, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("MP", RTW_CHPLAN_FCC2_FCC11, RTW_REGD_FCC),
COUNTRY_CHPLAN_ENT("MQ", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("MR", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
@@ -167,26 +172,26 @@ static const struct rtw_regulatory all_chplan_map[] = {
COUNTRY_CHPLAN_ENT("MV", RTW_CHPLAN_WORLD_ETSI6, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("MW", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("MX", RTW_CHPLAN_FCC2_FCC7, RTW_REGD_FCC),
- COUNTRY_CHPLAN_ENT("MY", RTW_CHPLAN_WORLD_ETSI20, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("MY", RTW_CHPLAN_WORLD_ETSI15, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("MZ", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("NA", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("NC", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("NE", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
- COUNTRY_CHPLAN_ENT("NF", RTW_CHPLAN_WORLD_ACMA1, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("NF", RTW_CHPLAN_WORLD_ACMA1, RTW_REGD_ACMA),
COUNTRY_CHPLAN_ENT("NG", RTW_CHPLAN_WORLD_ETSI20, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("NI", RTW_CHPLAN_FCC2_FCC11, RTW_REGD_FCC),
COUNTRY_CHPLAN_ENT("NL", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("NO", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
- COUNTRY_CHPLAN_ENT("NP", RTW_CHPLAN_WORLD_ETSI6, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("NP", RTW_CHPLAN_WORLD_ETSI7, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("NR", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
- COUNTRY_CHPLAN_ENT("NU", RTW_CHPLAN_WORLD_ACMA1, RTW_REGD_ETSI),
- COUNTRY_CHPLAN_ENT("NZ", RTW_CHPLAN_WORLD_ACMA1, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("NU", RTW_CHPLAN_WORLD_ACMA1, RTW_REGD_ACMA),
+ COUNTRY_CHPLAN_ENT("NZ", RTW_CHPLAN_WORLD_ACMA1, RTW_REGD_ACMA),
COUNTRY_CHPLAN_ENT("OM", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("PA", RTW_CHPLAN_FCC2_FCC11, RTW_REGD_FCC),
COUNTRY_CHPLAN_ENT("PE", RTW_CHPLAN_FCC2_FCC11, RTW_REGD_FCC),
COUNTRY_CHPLAN_ENT("PF", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
- COUNTRY_CHPLAN_ENT("PG", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
- COUNTRY_CHPLAN_ENT("PH", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("PG", RTW_CHPLAN_WORLD_ETSI2, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("PH", RTW_CHPLAN_WORLD_ETSI2, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("PK", RTW_CHPLAN_WORLD_ETSI10, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("PL", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("PM", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
@@ -194,17 +199,17 @@ static const struct rtw_regulatory all_chplan_map[] = {
COUNTRY_CHPLAN_ENT("PT", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("PW", RTW_CHPLAN_FCC2_FCC11, RTW_REGD_FCC),
COUNTRY_CHPLAN_ENT("PY", RTW_CHPLAN_FCC2_FCC11, RTW_REGD_FCC),
- COUNTRY_CHPLAN_ENT("QA", RTW_CHPLAN_WORLD_ETSI10, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("QA", RTW_CHPLAN_WORLD_ETSI2, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("RE", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("RO", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("RS", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("RU", RTW_CHPLAN_WORLD_ETSI14, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("RW", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
- COUNTRY_CHPLAN_ENT("SA", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("SA", RTW_CHPLAN_WORLD_ETSI2, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("SB", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("SC", RTW_CHPLAN_FCC2_FCC11, RTW_REGD_FCC),
COUNTRY_CHPLAN_ENT("SE", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
- COUNTRY_CHPLAN_ENT("SG", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("SG", RTW_CHPLAN_WORLD_ETSI2, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("SH", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("SI", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("SJ", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
@@ -222,14 +227,15 @@ static const struct rtw_regulatory all_chplan_map[] = {
COUNTRY_CHPLAN_ENT("TD", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("TF", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("TG", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
- COUNTRY_CHPLAN_ENT("TH", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("TH", RTW_CHPLAN_WORLD_ETSI2, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("TJ", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
- COUNTRY_CHPLAN_ENT("TK", RTW_CHPLAN_WORLD_ACMA1, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("TK", RTW_CHPLAN_WORLD_ACMA1, RTW_REGD_ACMA),
COUNTRY_CHPLAN_ENT("TM", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("TN", RTW_CHPLAN_WORLD_ETSI6, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("TO", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("TR", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
- COUNTRY_CHPLAN_ENT("TT", RTW_CHPLAN_ETSI1_ETSI4, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("TT", RTW_CHPLAN_FCC2_FCC11, RTW_REGD_FCC),
+ COUNTRY_CHPLAN_ENT("TV", RTW_CHPLAN_ETSI1_NULL, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("TW", RTW_CHPLAN_FCC2_FCC11, RTW_REGD_FCC),
COUNTRY_CHPLAN_ENT("TZ", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("UA", RTW_CHPLAN_WORLD_ETSI3, RTW_REGD_ETSI),
@@ -240,14 +246,15 @@ static const struct rtw_regulatory all_chplan_map[] = {
COUNTRY_CHPLAN_ENT("VA", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("VC", RTW_CHPLAN_FCC2_FCC11, RTW_REGD_FCC),
COUNTRY_CHPLAN_ENT("VE", RTW_CHPLAN_WORLD_FCC3, RTW_REGD_FCC),
+ COUNTRY_CHPLAN_ENT("VG", RTW_CHPLAN_FCC2_FCC11, RTW_REGD_FCC),
COUNTRY_CHPLAN_ENT("VI", RTW_CHPLAN_FCC2_FCC11, RTW_REGD_FCC),
- COUNTRY_CHPLAN_ENT("VN", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("VN", RTW_CHPLAN_WORLD_ETSI2, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("VU", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("WF", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("WS", RTW_CHPLAN_FCC2_FCC11, RTW_REGD_FCC),
COUNTRY_CHPLAN_ENT("YE", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("YT", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
- COUNTRY_CHPLAN_ENT("ZA", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
+ COUNTRY_CHPLAN_ENT("ZA", RTW_CHPLAN_WORLD_ETSI2, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("ZM", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
COUNTRY_CHPLAN_ENT("ZW", RTW_CHPLAN_WORLD_ETSI1, RTW_REGD_ETSI),
};
diff --git a/drivers/net/wireless/realtek/rtw88/regd.h b/drivers/net/wireless/realtek/rtw88/regd.h
index 7784bb6d3ba7..5d4578331788 100644
--- a/drivers/net/wireless/realtek/rtw88/regd.h
+++ b/drivers/net/wireless/realtek/rtw88/regd.h
@@ -8,6 +8,7 @@
#define IEEE80211_CHAN_NO_IBSS IEEE80211_CHAN_NO_IR
#define IEEE80211_CHAN_PASSIVE_SCAN IEEE80211_CHAN_NO_IR
enum rtw_chplan_id {
+ RTW_CHPLAN_ETSI1_NULL = 0x21,
RTW_CHPLAN_WORLD_ETSI1 = 0x26,
RTW_CHPLAN_MKK1_MKK1 = 0x27,
RTW_CHPLAN_IC1_IC2 = 0x2B,
@@ -15,6 +16,7 @@ enum rtw_chplan_id {
RTW_CHPLAN_WORLD_FCC3 = 0x30,
RTW_CHPLAN_WORLD_FCC5 = 0x32,
RTW_CHPLAN_FCC1_FCC7 = 0x34,
+ RTW_CHPLAN_WORLD_ETSI2 = 0x35,
RTW_CHPLAN_WORLD_ETSI3 = 0x36,
RTW_CHPLAN_ETSI1_ETSI12 = 0x3D,
RTW_CHPLAN_KCC1_KCC2 = 0x3E,
@@ -24,10 +26,12 @@ enum rtw_chplan_id {
RTW_CHPLAN_WORLD_ETSI6 = 0x47,
RTW_CHPLAN_WORLD_ETSI7 = 0x48,
RTW_CHPLAN_WORLD_ETSI8 = 0x49,
+ RTW_CHPLAN_KCC1_KCC3 = 0x4B,
RTW_CHPLAN_WORLD_ETSI10 = 0x51,
RTW_CHPLAN_WORLD_ETSI14 = 0x59,
RTW_CHPLAN_FCC2_FCC7 = 0x61,
RTW_CHPLAN_FCC2_FCC1 = 0x62,
+ RTW_CHPLAN_WORLD_ETSI15 = 0x63,
RTW_CHPLAN_WORLD_FCC7 = 0x73,
RTW_CHPLAN_FCC2_FCC17 = 0x74,
RTW_CHPLAN_WORLD_ETSI20 = 0x75,
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
index b4f7242e5aa3..f6214ff20337 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
@@ -203,7 +203,7 @@ static void rtw8822c_dac_iq_offset(struct rtw_dev *rtwdev, u32 *vec, u32 *val)
*val = t;
}
-static u32 rtw8822c_get_path_base_addr(u8 path)
+static u32 rtw8822c_get_path_write_addr(u8 path)
{
u32 base_addr;
@@ -222,6 +222,25 @@ static u32 rtw8822c_get_path_base_addr(u8 path)
return base_addr;
}
+static u32 rtw8822c_get_path_read_addr(u8 path)
+{
+ u32 base_addr;
+
+ switch (path) {
+ case RF_PATH_A:
+ base_addr = 0x2800;
+ break;
+ case RF_PATH_B:
+ base_addr = 0x4500;
+ break;
+ default:
+ WARN_ON(1);
+ return -1;
+ }
+
+ return base_addr;
+}
+
static bool rtw8822c_dac_iq_check(struct rtw_dev *rtwdev, u32 value)
{
bool ret = true;
@@ -316,8 +335,6 @@ static void rtw8822c_dac_cal_rf_mode(struct rtw_dev *rtwdev,
u32 iv[DACK_SN_8822C], qv[DACK_SN_8822C];
u32 rf_a, rf_b;
- mdelay(10);
-
rf_a = rtw_read_rf(rtwdev, RF_PATH_A, 0x0, RFREG_MASK);
rf_b = rtw_read_rf(rtwdev, RF_PATH_B, 0x0, RFREG_MASK);
@@ -347,6 +364,7 @@ static void rtw8822c_dac_bb_setting(struct rtw_dev *rtwdev)
static void rtw8822c_dac_cal_adc(struct rtw_dev *rtwdev,
u8 path, u32 *adc_ic, u32 *adc_qc)
{
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
u32 ic = 0, qc = 0, temp = 0;
u32 base_addr;
u32 path_sel;
@@ -354,7 +372,7 @@ static void rtw8822c_dac_cal_adc(struct rtw_dev *rtwdev,
rtw_dbg(rtwdev, RTW_DBG_RFK, "[DACK] ADCK path(%d)\n", path);
- base_addr = rtw8822c_get_path_base_addr(path);
+ base_addr = rtw8822c_get_path_write_addr(path);
switch (path) {
case RF_PATH_A:
path_sel = 0xa0000;
@@ -396,6 +414,7 @@ static void rtw8822c_dac_cal_adc(struct rtw_dev *rtwdev,
}
temp = (ic & 0x3ff) | ((qc & 0x3ff) << 10);
rtw_write32(rtwdev, base_addr + 0x68, temp);
+ dm_info->dack_adck[path] = temp;
rtw_dbg(rtwdev, RTW_DBG_RFK, "[DACK] ADCK 0x%08x=0x08%x\n",
base_addr + 0x68, temp);
/* check ADC DC offset */
@@ -422,10 +441,14 @@ static void rtw8822c_dac_cal_adc(struct rtw_dev *rtwdev,
static void rtw8822c_dac_cal_step1(struct rtw_dev *rtwdev, u8 path)
{
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
u32 base_addr;
+ u32 read_addr;
- base_addr = rtw8822c_get_path_base_addr(path);
+ base_addr = rtw8822c_get_path_write_addr(path);
+ read_addr = rtw8822c_get_path_read_addr(path);
+ rtw_write32(rtwdev, base_addr + 0x68, dm_info->dack_adck[path]);
rtw_write32(rtwdev, base_addr + 0x0c, 0xdff00220);
if (path == RF_PATH_A) {
rtw_write32(rtwdev, base_addr + 0x60, 0xf0040ff0);
@@ -447,11 +470,13 @@ static void rtw8822c_dac_cal_step1(struct rtw_dev *rtwdev, u8 path)
rtw_write32(rtwdev, base_addr + 0xcc, 0x0a11fb89);
mdelay(1);
rtw_write32(rtwdev, base_addr + 0xb8, 0x62000000);
- mdelay(20);
rtw_write32(rtwdev, base_addr + 0xd4, 0x62000000);
mdelay(20);
+ if (!check_hw_ready(rtwdev, read_addr + 0x08, 0x7fff80, 0xffff) ||
+ !check_hw_ready(rtwdev, read_addr + 0x34, 0x7fff80, 0xffff))
+ rtw_err(rtwdev, "failed to wait for dack ready\n");
rtw_write32(rtwdev, base_addr + 0xb8, 0x02000000);
- mdelay(20);
+ mdelay(1);
rtw_write32(rtwdev, base_addr + 0xbc, 0x0008ff87);
rtw_write32(rtwdev, 0x9b4, 0xdb6db600);
rtw_write32(rtwdev, base_addr + 0x10, 0x02d508c5);
@@ -465,7 +490,7 @@ static void rtw8822c_dac_cal_step2(struct rtw_dev *rtwdev,
u32 base_addr;
u32 ic, qc, ic_in, qc_in;
- base_addr = rtw8822c_get_path_base_addr(path);
+ base_addr = rtw8822c_get_path_write_addr(path);
rtw_write32_mask(rtwdev, base_addr + 0xbc, 0xf0000000, 0x0);
rtw_write32_mask(rtwdev, base_addr + 0xc0, 0xf, 0x8);
rtw_write32_mask(rtwdev, base_addr + 0xd8, 0xf0000000, 0x0);
@@ -514,10 +539,12 @@ static void rtw8822c_dac_cal_step3(struct rtw_dev *rtwdev, u8 path,
u32 *i_out, u32 *q_out)
{
u32 base_addr;
+ u32 read_addr;
u32 ic, qc;
u32 temp;
- base_addr = rtw8822c_get_path_base_addr(path);
+ base_addr = rtw8822c_get_path_write_addr(path);
+ read_addr = rtw8822c_get_path_read_addr(path);
ic = *ic_in;
qc = *qc_in;
@@ -542,11 +569,13 @@ static void rtw8822c_dac_cal_step3(struct rtw_dev *rtwdev, u8 path,
rtw_write32(rtwdev, base_addr + 0xcc, 0x0a11fb89);
mdelay(1);
rtw_write32(rtwdev, base_addr + 0xb8, 0x62000000);
- mdelay(20);
rtw_write32(rtwdev, base_addr + 0xd4, 0x62000000);
mdelay(20);
+ if (!check_hw_ready(rtwdev, read_addr + 0x24, 0x07f80000, ic) ||
+ !check_hw_ready(rtwdev, read_addr + 0x50, 0x07f80000, qc))
+ rtw_err(rtwdev, "failed to write IQ vector to hardware\n");
rtw_write32(rtwdev, base_addr + 0xb8, 0x02000000);
- mdelay(20);
+ mdelay(1);
rtw_write32_mask(rtwdev, base_addr + 0xbc, 0xe, 0x3);
rtw_write32(rtwdev, 0x9b4, 0xdb6db600);
@@ -583,7 +612,7 @@ static void rtw8822c_dac_cal_step3(struct rtw_dev *rtwdev, u8 path,
static void rtw8822c_dac_cal_step4(struct rtw_dev *rtwdev, u8 path)
{
- u32 base_addr = rtw8822c_get_path_base_addr(path);
+ u32 base_addr = rtw8822c_get_path_write_addr(path);
rtw_write32(rtwdev, base_addr + 0x68, 0x0);
rtw_write32(rtwdev, base_addr + 0x10, 0x02d508c4);
@@ -591,6 +620,296 @@ static void rtw8822c_dac_cal_step4(struct rtw_dev *rtwdev, u8 path)
rtw_write32_mask(rtwdev, base_addr + 0x30, BIT(30), 0x1);
}
+static void rtw8822c_dac_cal_backup_vec(struct rtw_dev *rtwdev,
+ u8 path, u8 vec, u32 w_addr, u32 r_addr)
+{
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+ u16 val;
+ u32 i;
+
+ if (WARN_ON(vec >= 2))
+ return;
+
+ for (i = 0; i < DACK_MSBK_BACKUP_NUM; i++) {
+ rtw_write32_mask(rtwdev, w_addr, 0xf0000000, i);
+ val = (u16)rtw_read32_mask(rtwdev, r_addr, 0x7fc0000);
+ dm_info->dack_msbk[path][vec][i] = val;
+ }
+}
+
+static void rtw8822c_dac_cal_backup_path(struct rtw_dev *rtwdev, u8 path)
+{
+ u32 w_off = 0x1c;
+ u32 r_off = 0x2c;
+ u32 w_addr, r_addr;
+
+ if (WARN_ON(path >= 2))
+ return;
+
+ /* backup I vector */
+ w_addr = rtw8822c_get_path_write_addr(path) + 0xb0;
+ r_addr = rtw8822c_get_path_read_addr(path) + 0x10;
+ rtw8822c_dac_cal_backup_vec(rtwdev, path, 0, w_addr, r_addr);
+
+ /* backup Q vector */
+ w_addr = rtw8822c_get_path_write_addr(path) + 0xb0 + w_off;
+ r_addr = rtw8822c_get_path_read_addr(path) + 0x10 + r_off;
+ rtw8822c_dac_cal_backup_vec(rtwdev, path, 1, w_addr, r_addr);
+}
+
+static void rtw8822c_dac_cal_backup_dck(struct rtw_dev *rtwdev)
+{
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+ u8 val;
+
+ val = (u8)rtw_read32_mask(rtwdev, REG_DCKA_I_0, 0xf0000000);
+ dm_info->dack_dck[RF_PATH_A][0][0] = val;
+ val = (u8)rtw_read32_mask(rtwdev, REG_DCKA_I_1, 0xf);
+ dm_info->dack_dck[RF_PATH_A][0][1] = val;
+ val = (u8)rtw_read32_mask(rtwdev, REG_DCKA_Q_0, 0xf0000000);
+ dm_info->dack_dck[RF_PATH_A][1][0] = val;
+ val = (u8)rtw_read32_mask(rtwdev, REG_DCKA_Q_1, 0xf);
+ dm_info->dack_dck[RF_PATH_A][1][1] = val;
+
+ val = (u8)rtw_read32_mask(rtwdev, REG_DCKB_I_0, 0xf0000000);
+ dm_info->dack_dck[RF_PATH_B][0][0] = val;
+ val = (u8)rtw_read32_mask(rtwdev, REG_DCKB_I_1, 0xf);
+ dm_info->dack_dck[RF_PATH_B][1][0] = val;
+ val = (u8)rtw_read32_mask(rtwdev, REG_DCKB_Q_0, 0xf0000000);
+ dm_info->dack_dck[RF_PATH_B][0][1] = val;
+ val = (u8)rtw_read32_mask(rtwdev, REG_DCKB_Q_1, 0xf);
+ dm_info->dack_dck[RF_PATH_B][1][1] = val;
+}
+
+static void rtw8822c_dac_cal_backup(struct rtw_dev *rtwdev)
+{
+ u32 temp[3];
+
+ temp[0] = rtw_read32(rtwdev, 0x1860);
+ temp[1] = rtw_read32(rtwdev, 0x4160);
+ temp[2] = rtw_read32(rtwdev, 0x9b4);
+
+ /* set clock */
+ rtw_write32(rtwdev, 0x9b4, 0xdb66db00);
+
+ /* backup path-A I/Q */
+ rtw_write32_clr(rtwdev, 0x1830, BIT(30));
+ rtw_write32_mask(rtwdev, 0x1860, 0xfc000000, 0x3c);
+ rtw8822c_dac_cal_backup_path(rtwdev, RF_PATH_A);
+
+ /* backup path-B I/Q */
+ rtw_write32_clr(rtwdev, 0x4130, BIT(30));
+ rtw_write32_mask(rtwdev, 0x4160, 0xfc000000, 0x3c);
+ rtw8822c_dac_cal_backup_path(rtwdev, RF_PATH_B);
+
+ rtw8822c_dac_cal_backup_dck(rtwdev);
+ rtw_write32_set(rtwdev, 0x1830, BIT(30));
+ rtw_write32_set(rtwdev, 0x4130, BIT(30));
+
+ rtw_write32(rtwdev, 0x1860, temp[0]);
+ rtw_write32(rtwdev, 0x4160, temp[1]);
+ rtw_write32(rtwdev, 0x9b4, temp[2]);
+}
+
+static void rtw8822c_dac_cal_restore_dck(struct rtw_dev *rtwdev)
+{
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+ u8 val;
+
+ rtw_write32_set(rtwdev, REG_DCKA_I_0, BIT(19));
+ val = dm_info->dack_dck[RF_PATH_A][0][0];
+ rtw_write32_mask(rtwdev, REG_DCKA_I_0, 0xf0000000, val);
+ val = dm_info->dack_dck[RF_PATH_A][0][1];
+ rtw_write32_mask(rtwdev, REG_DCKA_I_1, 0xf, val);
+
+ rtw_write32_set(rtwdev, REG_DCKA_Q_0, BIT(19));
+ val = dm_info->dack_dck[RF_PATH_A][1][0];
+ rtw_write32_mask(rtwdev, REG_DCKA_Q_0, 0xf0000000, val);
+ val = dm_info->dack_dck[RF_PATH_A][1][1];
+ rtw_write32_mask(rtwdev, REG_DCKA_Q_1, 0xf, val);
+
+ rtw_write32_set(rtwdev, REG_DCKB_I_0, BIT(19));
+ val = dm_info->dack_dck[RF_PATH_B][0][0];
+ rtw_write32_mask(rtwdev, REG_DCKB_I_0, 0xf0000000, val);
+ val = dm_info->dack_dck[RF_PATH_B][0][1];
+ rtw_write32_mask(rtwdev, REG_DCKB_I_1, 0xf, val);
+
+ rtw_write32_set(rtwdev, REG_DCKB_Q_0, BIT(19));
+ val = dm_info->dack_dck[RF_PATH_B][1][0];
+ rtw_write32_mask(rtwdev, REG_DCKB_Q_0, 0xf0000000, val);
+ val = dm_info->dack_dck[RF_PATH_B][1][1];
+ rtw_write32_mask(rtwdev, REG_DCKB_Q_1, 0xf, val);
+}
+
+static void rtw8822c_dac_cal_restore_prepare(struct rtw_dev *rtwdev)
+{
+ rtw_write32(rtwdev, 0x9b4, 0xdb66db00);
+
+ rtw_write32_mask(rtwdev, 0x18b0, BIT(27), 0x0);
+ rtw_write32_mask(rtwdev, 0x18cc, BIT(27), 0x0);
+ rtw_write32_mask(rtwdev, 0x41b0, BIT(27), 0x0);
+ rtw_write32_mask(rtwdev, 0x41cc, BIT(27), 0x0);
+
+ rtw_write32_mask(rtwdev, 0x1830, BIT(30), 0x0);
+ rtw_write32_mask(rtwdev, 0x1860, 0xfc000000, 0x3c);
+ rtw_write32_mask(rtwdev, 0x18b4, BIT(0), 0x1);
+ rtw_write32_mask(rtwdev, 0x18d0, BIT(0), 0x1);
+
+ rtw_write32_mask(rtwdev, 0x4130, BIT(30), 0x0);
+ rtw_write32_mask(rtwdev, 0x4160, 0xfc000000, 0x3c);
+ rtw_write32_mask(rtwdev, 0x41b4, BIT(0), 0x1);
+ rtw_write32_mask(rtwdev, 0x41d0, BIT(0), 0x1);
+
+ rtw_write32_mask(rtwdev, 0x18b0, 0xf00, 0x0);
+ rtw_write32_mask(rtwdev, 0x18c0, BIT(14), 0x0);
+ rtw_write32_mask(rtwdev, 0x18cc, 0xf00, 0x0);
+ rtw_write32_mask(rtwdev, 0x18dc, BIT(14), 0x0);
+
+ rtw_write32_mask(rtwdev, 0x18b0, BIT(0), 0x0);
+ rtw_write32_mask(rtwdev, 0x18cc, BIT(0), 0x0);
+ rtw_write32_mask(rtwdev, 0x18b0, BIT(0), 0x1);
+ rtw_write32_mask(rtwdev, 0x18cc, BIT(0), 0x1);
+
+ rtw8822c_dac_cal_restore_dck(rtwdev);
+
+ rtw_write32_mask(rtwdev, 0x18c0, 0x38000, 0x7);
+ rtw_write32_mask(rtwdev, 0x18dc, 0x38000, 0x7);
+ rtw_write32_mask(rtwdev, 0x41c0, 0x38000, 0x7);
+ rtw_write32_mask(rtwdev, 0x41dc, 0x38000, 0x7);
+
+ rtw_write32_mask(rtwdev, 0x18b8, BIT(26) | BIT(25), 0x1);
+ rtw_write32_mask(rtwdev, 0x18d4, BIT(26) | BIT(25), 0x1);
+
+ rtw_write32_mask(rtwdev, 0x41b0, 0xf00, 0x0);
+ rtw_write32_mask(rtwdev, 0x41c0, BIT(14), 0x0);
+ rtw_write32_mask(rtwdev, 0x41cc, 0xf00, 0x0);
+ rtw_write32_mask(rtwdev, 0x41dc, BIT(14), 0x0);
+
+ rtw_write32_mask(rtwdev, 0x41b0, BIT(0), 0x0);
+ rtw_write32_mask(rtwdev, 0x41cc, BIT(0), 0x0);
+ rtw_write32_mask(rtwdev, 0x41b0, BIT(0), 0x1);
+ rtw_write32_mask(rtwdev, 0x41cc, BIT(0), 0x1);
+
+ rtw_write32_mask(rtwdev, 0x41b8, BIT(26) | BIT(25), 0x1);
+ rtw_write32_mask(rtwdev, 0x41d4, BIT(26) | BIT(25), 0x1);
+}
+
+static bool rtw8822c_dac_cal_restore_wait(struct rtw_dev *rtwdev,
+ u32 target_addr, u32 toggle_addr)
+{
+ u32 cnt = 0;
+
+ do {
+ rtw_write32_mask(rtwdev, toggle_addr, BIT(26) | BIT(25), 0x0);
+ rtw_write32_mask(rtwdev, toggle_addr, BIT(26) | BIT(25), 0x2);
+
+ if (rtw_read32_mask(rtwdev, target_addr, 0xf) == 0x6)
+ return true;
+
+ } while (cnt++ < 100);
+
+ return false;
+}
+
+static bool rtw8822c_dac_cal_restore_path(struct rtw_dev *rtwdev, u8 path)
+{
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+ u32 w_off = 0x1c;
+ u32 r_off = 0x2c;
+ u32 w_i, r_i, w_q, r_q;
+ u32 value;
+ u32 i;
+
+ w_i = rtw8822c_get_path_write_addr(path) + 0xb0;
+ r_i = rtw8822c_get_path_read_addr(path) + 0x08;
+ w_q = rtw8822c_get_path_write_addr(path) + 0xb0 + w_off;
+ r_q = rtw8822c_get_path_read_addr(path) + 0x08 + r_off;
+
+ if (!rtw8822c_dac_cal_restore_wait(rtwdev, r_i, w_i + 0x8))
+ return false;
+
+ for (i = 0; i < DACK_MSBK_BACKUP_NUM; i++) {
+ rtw_write32_mask(rtwdev, w_i + 0x4, BIT(2), 0x0);
+ value = dm_info->dack_msbk[path][0][i];
+ rtw_write32_mask(rtwdev, w_i + 0x4, 0xff8, value);
+ rtw_write32_mask(rtwdev, w_i, 0xf0000000, i);
+ rtw_write32_mask(rtwdev, w_i + 0x4, BIT(2), 0x1);
+ }
+
+ rtw_write32_mask(rtwdev, w_i + 0x4, BIT(2), 0x0);
+
+ if (!rtw8822c_dac_cal_restore_wait(rtwdev, r_q, w_q + 0x8))
+ return false;
+
+ for (i = 0; i < DACK_MSBK_BACKUP_NUM; i++) {
+ rtw_write32_mask(rtwdev, w_q + 0x4, BIT(2), 0x0);
+ value = dm_info->dack_msbk[path][1][i];
+ rtw_write32_mask(rtwdev, w_q + 0x4, 0xff8, value);
+ rtw_write32_mask(rtwdev, w_q, 0xf0000000, i);
+ rtw_write32_mask(rtwdev, w_q + 0x4, BIT(2), 0x1);
+ }
+ rtw_write32_mask(rtwdev, w_q + 0x4, BIT(2), 0x0);
+
+ rtw_write32_mask(rtwdev, w_i + 0x8, BIT(26) | BIT(25), 0x0);
+ rtw_write32_mask(rtwdev, w_q + 0x8, BIT(26) | BIT(25), 0x0);
+ rtw_write32_mask(rtwdev, w_i + 0x4, BIT(0), 0x0);
+ rtw_write32_mask(rtwdev, w_q + 0x4, BIT(0), 0x0);
+
+ return true;
+}
+
+static bool __rtw8822c_dac_cal_restore(struct rtw_dev *rtwdev)
+{
+ if (!rtw8822c_dac_cal_restore_path(rtwdev, RF_PATH_A))
+ return false;
+
+ if (!rtw8822c_dac_cal_restore_path(rtwdev, RF_PATH_B))
+ return false;
+
+ return true;
+}
+
+static bool rtw8822c_dac_cal_restore(struct rtw_dev *rtwdev)
+{
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+ u32 temp[3];
+
+ /* sample the first element for both path's IQ vector */
+ if (dm_info->dack_msbk[RF_PATH_A][0][0] == 0 &&
+ dm_info->dack_msbk[RF_PATH_A][1][0] == 0 &&
+ dm_info->dack_msbk[RF_PATH_B][0][0] == 0 &&
+ dm_info->dack_msbk[RF_PATH_B][1][0] == 0)
+ return false;
+
+ temp[0] = rtw_read32(rtwdev, 0x1860);
+ temp[1] = rtw_read32(rtwdev, 0x4160);
+ temp[2] = rtw_read32(rtwdev, 0x9b4);
+
+ rtw8822c_dac_cal_restore_prepare(rtwdev);
+ if (!check_hw_ready(rtwdev, 0x2808, 0x7fff80, 0xffff) ||
+ !check_hw_ready(rtwdev, 0x2834, 0x7fff80, 0xffff) ||
+ !check_hw_ready(rtwdev, 0x4508, 0x7fff80, 0xffff) ||
+ !check_hw_ready(rtwdev, 0x4534, 0x7fff80, 0xffff))
+ return false;
+
+ if (!__rtw8822c_dac_cal_restore(rtwdev)) {
+ rtw_err(rtwdev, "failed to restore dack vectors\n");
+ return false;
+ }
+
+ rtw_write32_mask(rtwdev, 0x1830, BIT(30), 0x1);
+ rtw_write32_mask(rtwdev, 0x4130, BIT(30), 0x1);
+ rtw_write32(rtwdev, 0x1860, temp[0]);
+ rtw_write32(rtwdev, 0x4160, temp[1]);
+ rtw_write32_mask(rtwdev, 0x18b0, BIT(27), 0x1);
+ rtw_write32_mask(rtwdev, 0x18cc, BIT(27), 0x1);
+ rtw_write32_mask(rtwdev, 0x41b0, BIT(27), 0x1);
+ rtw_write32_mask(rtwdev, 0x41cc, BIT(27), 0x1);
+ rtw_write32(rtwdev, 0x9b4, temp[2]);
+
+ return true;
+}
+
static void rtw8822c_rf_dac_cal(struct rtw_dev *rtwdev)
{
struct rtw_backup_info backup_rf[DACK_RF_8822C * DACK_PATH_8822C];
@@ -600,6 +919,11 @@ static void rtw8822c_rf_dac_cal(struct rtw_dev *rtwdev)
u32 ic_a = 0x0, qc_a = 0x0, ic_b = 0x0, qc_b = 0x0;
u32 adc_ic_a = 0x0, adc_qc_a = 0x0, adc_ic_b = 0x0, adc_qc_b = 0x0;
+ if (rtw8822c_dac_cal_restore(rtwdev))
+ return;
+
+ /* not able to restore, do it */
+
rtw8822c_dac_backup_reg(rtwdev, backup, backup_rf);
rtw8822c_dac_bb_setting(rtwdev);
@@ -644,6 +968,9 @@ static void rtw8822c_rf_dac_cal(struct rtw_dev *rtwdev)
rtw8822c_dac_restore_reg(rtwdev, backup, backup_rf);
+ /* backup results to restore, saving a lot of time */
+ rtw8822c_dac_cal_backup(rtwdev);
+
rtw_dbg(rtwdev, RTW_DBG_RFK, "[DACK] path A: ic=0x%x, qc=0x%x\n", ic_a, qc_a);
rtw_dbg(rtwdev, RTW_DBG_RFK, "[DACK] path B: ic=0x%x, qc=0x%x\n", ic_b, qc_b);
rtw_dbg(rtwdev, RTW_DBG_RFK, "[DACK] path A: i=0x%x, q=0x%x\n", i_a, q_a);
@@ -1015,8 +1342,28 @@ static void rtw8822c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw,
rtw_write32_clr(rtwdev, REG_CCKTXONLY, BIT_BB_CCK_CHECK_EN);
rtw_write32_mask(rtwdev, REG_CCAMSK, 0x3F000000, 0xF);
- rtw_write32_mask(rtwdev, REG_RXAGCCTL0, 0x1f0, 0x0);
- rtw_write32_mask(rtwdev, REG_RXAGCCTL, 0x1f0, 0x0);
+ switch (bw) {
+ case RTW_CHANNEL_WIDTH_20:
+ rtw_write32_mask(rtwdev, REG_RXAGCCTL0, BITS_RXAGC_CCK,
+ 0x5);
+ rtw_write32_mask(rtwdev, REG_RXAGCCTL, BITS_RXAGC_CCK,
+ 0x5);
+ rtw_write32_mask(rtwdev, REG_RXAGCCTL0, BITS_RXAGC_OFDM,
+ 0x6);
+ rtw_write32_mask(rtwdev, REG_RXAGCCTL, BITS_RXAGC_OFDM,
+ 0x6);
+ break;
+ case RTW_CHANNEL_WIDTH_40:
+ rtw_write32_mask(rtwdev, REG_RXAGCCTL0, BITS_RXAGC_CCK,
+ 0x4);
+ rtw_write32_mask(rtwdev, REG_RXAGCCTL, BITS_RXAGC_CCK,
+ 0x4);
+ rtw_write32_mask(rtwdev, REG_RXAGCCTL0, BITS_RXAGC_OFDM,
+ 0x0);
+ rtw_write32_mask(rtwdev, REG_RXAGCCTL, BITS_RXAGC_OFDM,
+ 0x0);
+ break;
+ }
if (channel == 13 || channel == 14)
rtw_write32_mask(rtwdev, REG_SCOTRK, 0xfff, 0x969);
else if (channel == 11 || channel == 12)
@@ -1061,14 +1408,20 @@ static void rtw8822c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw,
rtw_write32_mask(rtwdev, REG_CCAMSK, 0x3F000000, 0x22);
rtw_write32_mask(rtwdev, REG_TXDFIR0, 0x70, 0x3);
if (channel >= 36 && channel <= 64) {
- rtw_write32_mask(rtwdev, REG_RXAGCCTL0, 0x1f0, 0x1);
- rtw_write32_mask(rtwdev, REG_RXAGCCTL, 0x1f0, 0x1);
+ rtw_write32_mask(rtwdev, REG_RXAGCCTL0, BITS_RXAGC_OFDM,
+ 0x1);
+ rtw_write32_mask(rtwdev, REG_RXAGCCTL, BITS_RXAGC_OFDM,
+ 0x1);
} else if (channel >= 100 && channel <= 144) {
- rtw_write32_mask(rtwdev, REG_RXAGCCTL0, 0x1f0, 0x2);
- rtw_write32_mask(rtwdev, REG_RXAGCCTL, 0x1f0, 0x2);
+ rtw_write32_mask(rtwdev, REG_RXAGCCTL0, BITS_RXAGC_OFDM,
+ 0x2);
+ rtw_write32_mask(rtwdev, REG_RXAGCCTL, BITS_RXAGC_OFDM,
+ 0x2);
} else if (channel >= 149) {
- rtw_write32_mask(rtwdev, REG_RXAGCCTL0, 0x1f0, 0x3);
- rtw_write32_mask(rtwdev, REG_RXAGCCTL, 0x1f0, 0x3);
+ rtw_write32_mask(rtwdev, REG_RXAGCCTL0, BITS_RXAGC_OFDM,
+ 0x3);
+ rtw_write32_mask(rtwdev, REG_RXAGCCTL, BITS_RXAGC_OFDM,
+ 0x3);
}
if (channel >= 36 && channel <= 51)
@@ -1092,6 +1445,9 @@ static void rtw8822c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw,
rtw_write32_mask(rtwdev, REG_TXBWCTL, 0xffc0, 0x0);
rtw_write32_mask(rtwdev, REG_TXCLK, 0x700, 0x7);
rtw_write32_mask(rtwdev, REG_TXCLK, 0x700000, 0x6);
+ rtw_write32_mask(rtwdev, REG_CCK_SOURCE, BIT_NBI_EN, 0x0);
+ rtw_write32_mask(rtwdev, REG_SBD, BITS_SUBTUNE, 0x1);
+ rtw_write32_mask(rtwdev, REG_PT_CHSMO, BIT_PT_OPT, 0x0);
break;
case RTW_CHANNEL_WIDTH_40:
rtw_write32_mask(rtwdev, REG_CCKSB, BIT(4),
@@ -1100,12 +1456,17 @@ static void rtw8822c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw,
rtw_write32_mask(rtwdev, REG_TXBWCTL, 0xc0, 0x0);
rtw_write32_mask(rtwdev, REG_TXBWCTL, 0xff00,
(primary_ch_idx | (primary_ch_idx << 4)));
+ rtw_write32_mask(rtwdev, REG_CCK_SOURCE, BIT_NBI_EN, 0x1);
+ rtw_write32_mask(rtwdev, REG_SBD, BITS_SUBTUNE, 0x1);
+ rtw_write32_mask(rtwdev, REG_PT_CHSMO, BIT_PT_OPT, 0x1);
break;
case RTW_CHANNEL_WIDTH_80:
rtw_write32_mask(rtwdev, REG_TXBWCTL, 0xf, 0xa);
rtw_write32_mask(rtwdev, REG_TXBWCTL, 0xc0, 0x0);
rtw_write32_mask(rtwdev, REG_TXBWCTL, 0xff00,
(primary_ch_idx | (primary_ch_idx << 4)));
+ rtw_write32_mask(rtwdev, REG_SBD, BITS_SUBTUNE, 0x6);
+ rtw_write32_mask(rtwdev, REG_PT_CHSMO, BIT_PT_OPT, 0x1);
break;
case RTW_CHANNEL_WIDTH_5:
rtw_write32_mask(rtwdev, REG_DFIRBW, 0x3FF0, 0x2AB);
@@ -1113,6 +1474,9 @@ static void rtw8822c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw,
rtw_write32_mask(rtwdev, REG_TXBWCTL, 0xffc0, 0x1);
rtw_write32_mask(rtwdev, REG_TXCLK, 0x700, 0x4);
rtw_write32_mask(rtwdev, REG_TXCLK, 0x700000, 0x4);
+ rtw_write32_mask(rtwdev, REG_CCK_SOURCE, BIT_NBI_EN, 0x0);
+ rtw_write32_mask(rtwdev, REG_SBD, BITS_SUBTUNE, 0x1);
+ rtw_write32_mask(rtwdev, REG_PT_CHSMO, BIT_PT_OPT, 0x0);
break;
case RTW_CHANNEL_WIDTH_10:
rtw_write32_mask(rtwdev, REG_DFIRBW, 0x3FF0, 0x2AB);
@@ -1120,6 +1484,9 @@ static void rtw8822c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw,
rtw_write32_mask(rtwdev, REG_TXBWCTL, 0xffc0, 0x2);
rtw_write32_mask(rtwdev, REG_TXCLK, 0x700, 0x6);
rtw_write32_mask(rtwdev, REG_TXCLK, 0x700000, 0x5);
+ rtw_write32_mask(rtwdev, REG_CCK_SOURCE, BIT_NBI_EN, 0x0);
+ rtw_write32_mask(rtwdev, REG_SBD, BITS_SUBTUNE, 0x1);
+ rtw_write32_mask(rtwdev, REG_PT_CHSMO, BIT_PT_OPT, 0x0);
break;
}
}
@@ -1451,13 +1818,30 @@ static void rtw8822c_false_alarm_statistics(struct rtw_dev *rtwdev)
u32 cck_enable;
u32 cck_fa_cnt;
u32 ofdm_fa_cnt;
- u32 ofdm_tx_counter;
+ u32 ofdm_fa_cnt1, ofdm_fa_cnt2, ofdm_fa_cnt3, ofdm_fa_cnt4, ofdm_fa_cnt5;
+ u16 parity_fail, rate_illegal, crc8_fail, mcs_fail, sb_search_fail,
+ fast_fsync, crc8_fail_vhta, mcs_fail_vht;
cck_enable = rtw_read32(rtwdev, REG_ENCCK) & BIT_CCK_BLK_EN;
cck_fa_cnt = rtw_read16(rtwdev, REG_CCK_FACNT);
- ofdm_fa_cnt = rtw_read16(rtwdev, REG_OFDM_FACNT);
- ofdm_tx_counter = rtw_read16(rtwdev, REG_OFDM_TXCNT);
- ofdm_fa_cnt -= ofdm_tx_counter;
+
+ ofdm_fa_cnt1 = rtw_read32(rtwdev, REG_OFDM_FACNT1);
+ ofdm_fa_cnt2 = rtw_read32(rtwdev, REG_OFDM_FACNT2);
+ ofdm_fa_cnt3 = rtw_read32(rtwdev, REG_OFDM_FACNT3);
+ ofdm_fa_cnt4 = rtw_read32(rtwdev, REG_OFDM_FACNT4);
+ ofdm_fa_cnt5 = rtw_read32(rtwdev, REG_OFDM_FACNT5);
+
+ parity_fail = FIELD_GET(GENMASK(31, 16), ofdm_fa_cnt1);
+ rate_illegal = FIELD_GET(GENMASK(15, 0), ofdm_fa_cnt2);
+ crc8_fail = FIELD_GET(GENMASK(31, 16), ofdm_fa_cnt2);
+ crc8_fail_vhta = FIELD_GET(GENMASK(15, 0), ofdm_fa_cnt3);
+ mcs_fail = FIELD_GET(GENMASK(15, 0), ofdm_fa_cnt4);
+ mcs_fail_vht = FIELD_GET(GENMASK(31, 16), ofdm_fa_cnt4);
+ fast_fsync = FIELD_GET(GENMASK(15, 0), ofdm_fa_cnt5);
+ sb_search_fail = FIELD_GET(GENMASK(31, 16), ofdm_fa_cnt5);
+
+ ofdm_fa_cnt = parity_fail + rate_illegal + crc8_fail + crc8_fail_vhta +
+ mcs_fail + mcs_fail_vht + fast_fsync + sb_search_fail;
dm_info->cck_fa_cnt = cck_fa_cnt;
dm_info->ofdm_fa_cnt = ofdm_fa_cnt;
@@ -1468,8 +1852,12 @@ static void rtw8822c_false_alarm_statistics(struct rtw_dev *rtwdev)
rtw_write32_mask(rtwdev, REG_CCANRX, BIT_CCK_FA_RST, 2);
rtw_write32_mask(rtwdev, REG_CCANRX, BIT_OFDM_FA_RST, 0);
rtw_write32_mask(rtwdev, REG_CCANRX, BIT_OFDM_FA_RST, 2);
+
+ /* disable rx clk gating to reset counters */
+ rtw_write32_clr(rtwdev, REG_RX_BREAK, BIT_COM_RX_GCK_EN);
rtw_write32_set(rtwdev, REG_CNT_CTRL, BIT_ALL_CNT_RST);
rtw_write32_clr(rtwdev, REG_CNT_CTRL, BIT_ALL_CNT_RST);
+ rtw_write32_set(rtwdev, REG_RX_BREAK, BIT_COM_RX_GCK_EN);
}
static void rtw8822c_do_iqk(struct rtw_dev *rtwdev)
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.h b/drivers/net/wireless/realtek/rtw88/rtw8822c.h
index d3bd9850baa0..5ee1de41504d 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822c.h
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.h
@@ -133,6 +133,8 @@ struct rtw8822c_efuse {
#define REG_DYMPRITH 0x86c
#define REG_DYMENTH0 0x870
#define REG_DYMENTH 0x874
+#define REG_SBD 0x88c
+#define BITS_SUBTUNE GENMASK(15, 12)
#define REG_DYMTHMIN 0x8a4
#define REG_TXBWCTL 0x9b0
#define REG_TXCLK 0x9b4
@@ -140,12 +142,20 @@ struct rtw8822c_efuse {
#define REG_MRCM 0xc38
#define REG_AGCSWSH 0xc44
#define REG_ANTWTPD 0xc54
+#define REG_PT_CHSMO 0xcbc
+#define BIT_PT_OPT BIT(21)
#define REG_ORITXCODE 0x1800
#define REG_3WIRE 0x180c
#define BIT_3WIRE_TX_EN BIT(0)
#define BIT_3WIRE_RX_EN BIT(1)
#define BIT_3WIRE_PI_ON BIT(28)
#define REG_RXAGCCTL0 0x18ac
+#define BITS_RXAGC_CCK GENMASK(15, 12)
+#define BITS_RXAGC_OFDM GENMASK(8, 4)
+#define REG_DCKA_I_0 0x18bc
+#define REG_DCKA_I_1 0x18c0
+#define REG_DCKA_Q_0 0x18d8
+#define REG_DCKA_Q_1 0x18dc
#define REG_CCKSB 0x1a00
#define REG_RXCCKSEL 0x1a04
#define REG_BGCTRL 0x1a14
@@ -164,11 +174,15 @@ struct rtw8822c_efuse {
#define REG_TXF5 0x1aa0
#define REG_TXF6 0x1aac
#define REG_TXF7 0x1ab0
+#define REG_CCK_SOURCE 0x1abc
+#define BIT_NBI_EN BIT(30)
#define REG_TXANT 0x1c28
#define REG_ENCCK 0x1c3c
#define BIT_CCK_BLK_EN BIT(1)
#define BIT_CCK_OFDM_BLK_EN (BIT(0) | BIT(1))
#define REG_CCAMSK 0x1c80
+#define REG_RX_BREAK 0x1d2c
+#define BIT_COM_RX_GCK_EN BIT(31)
#define REG_RXFNCTL 0x1d30
#define REG_RXIGI 0x1d70
#define REG_ENFN 0x1e24
@@ -178,9 +192,18 @@ struct rtw8822c_efuse {
#define REG_CNT_CTRL 0x1eb4
#define BIT_ALL_CNT_RST BIT(25)
#define REG_OFDM_FACNT 0x2d00
+#define REG_OFDM_FACNT1 0x2d04
+#define REG_OFDM_FACNT2 0x2d08
+#define REG_OFDM_FACNT3 0x2d0c
+#define REG_OFDM_FACNT4 0x2d10
+#define REG_OFDM_FACNT5 0x2d20
#define REG_OFDM_TXCNT 0x2de0
#define REG_ORITXCODE2 0x4100
#define REG_3WIRE2 0x410c
#define REG_RXAGCCTL 0x41ac
+#define REG_DCKB_I_0 0x41bc
+#define REG_DCKB_I_1 0x41c0
+#define REG_DCKB_Q_0 0x41d8
+#define REG_DCKB_Q_1 0x41dc
#endif
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c_table.c b/drivers/net/wireless/realtek/rtw88/rtw8822c_table.c
index 49044f510c6c..18e609a69829 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822c_table.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822c_table.c
@@ -9489,55 +9489,55 @@ static const u8 rtw8822c_txpwr_lmt_type0[] = {
0, 0, 1, 3, 13, 127, 2, 0, 1, 3, 13, 127,
0, 0, 1, 3, 14, 127, 2, 0, 1, 3, 14, 127,
0, 1, 0, 1, 36, 74, 2, 1, 0, 1, 36, 62,
- 0, 1, 0, 1, 40, 80, 2, 1, 0, 1, 40, 62,
- 0, 1, 0, 1, 44, 80, 2, 1, 0, 1, 44, 62,
- 0, 1, 0, 1, 48, 80, 2, 1, 0, 1, 48, 62,
- 0, 1, 0, 1, 52, 80, 2, 1, 0, 1, 52, 62,
- 0, 1, 0, 1, 56, 80, 2, 1, 0, 1, 56, 62,
- 0, 1, 0, 1, 60, 80, 2, 1, 0, 1, 60, 62,
+ 0, 1, 0, 1, 40, 76, 2, 1, 0, 1, 40, 62,
+ 0, 1, 0, 1, 44, 76, 2, 1, 0, 1, 44, 62,
+ 0, 1, 0, 1, 48, 76, 2, 1, 0, 1, 48, 62,
+ 0, 1, 0, 1, 52, 76, 2, 1, 0, 1, 52, 62,
+ 0, 1, 0, 1, 56, 76, 2, 1, 0, 1, 56, 62,
+ 0, 1, 0, 1, 60, 76, 2, 1, 0, 1, 60, 62,
0, 1, 0, 1, 64, 74, 2, 1, 0, 1, 64, 62,
0, 1, 0, 1, 100, 72, 2, 1, 0, 1, 100, 62,
- 0, 1, 0, 1, 104, 80, 2, 1, 0, 1, 104, 62,
- 0, 1, 0, 1, 108, 80, 2, 1, 0, 1, 108, 62,
- 0, 1, 0, 1, 112, 80, 2, 1, 0, 1, 112, 62,
- 0, 1, 0, 1, 116, 80, 2, 1, 0, 1, 116, 62,
- 0, 1, 0, 1, 120, 80, 2, 1, 0, 1, 120, 62,
- 0, 1, 0, 1, 124, 80, 2, 1, 0, 1, 124, 62,
- 0, 1, 0, 1, 128, 80, 2, 1, 0, 1, 128, 62,
- 0, 1, 0, 1, 132, 80, 2, 1, 0, 1, 132, 62,
- 0, 1, 0, 1, 136, 80, 2, 1, 0, 1, 136, 62,
+ 0, 1, 0, 1, 104, 76, 2, 1, 0, 1, 104, 62,
+ 0, 1, 0, 1, 108, 76, 2, 1, 0, 1, 108, 62,
+ 0, 1, 0, 1, 112, 76, 2, 1, 0, 1, 112, 62,
+ 0, 1, 0, 1, 116, 76, 2, 1, 0, 1, 116, 62,
+ 0, 1, 0, 1, 120, 76, 2, 1, 0, 1, 120, 62,
+ 0, 1, 0, 1, 124, 76, 2, 1, 0, 1, 124, 62,
+ 0, 1, 0, 1, 128, 76, 2, 1, 0, 1, 128, 62,
+ 0, 1, 0, 1, 132, 76, 2, 1, 0, 1, 132, 62,
+ 0, 1, 0, 1, 136, 76, 2, 1, 0, 1, 136, 62,
0, 1, 0, 1, 140, 72, 2, 1, 0, 1, 140, 62,
- 0, 1, 0, 1, 144, 80, 2, 1, 0, 1, 144, 127,
- 0, 1, 0, 1, 149, 80, 2, 1, 0, 1, 149, 127,
- 0, 1, 0, 1, 153, 80, 2, 1, 0, 1, 153, 127,
- 0, 1, 0, 1, 157, 80, 2, 1, 0, 1, 157, 127,
- 0, 1, 0, 1, 161, 80, 2, 1, 0, 1, 161, 127,
- 0, 1, 0, 1, 165, 80, 2, 1, 0, 1, 165, 127,
+ 0, 1, 0, 1, 144, 76, 2, 1, 0, 1, 144, 127,
+ 0, 1, 0, 1, 149, 76, 2, 1, 0, 1, 149, -128,
+ 0, 1, 0, 1, 153, 76, 2, 1, 0, 1, 153, -128,
+ 0, 1, 0, 1, 157, 76, 2, 1, 0, 1, 157, -128,
+ 0, 1, 0, 1, 161, 76, 2, 1, 0, 1, 161, -128,
+ 0, 1, 0, 1, 165, 76, 2, 1, 0, 1, 165, -128,
0, 1, 0, 2, 36, 72, 2, 1, 0, 2, 36, 62,
- 0, 1, 0, 2, 40, 80, 2, 1, 0, 2, 40, 62,
- 0, 1, 0, 2, 44, 80, 2, 1, 0, 2, 44, 62,
- 0, 1, 0, 2, 48, 80, 2, 1, 0, 2, 48, 62,
- 0, 1, 0, 2, 52, 80, 2, 1, 0, 2, 52, 62,
- 0, 1, 0, 2, 56, 80, 2, 1, 0, 2, 56, 62,
- 0, 1, 0, 2, 60, 80, 2, 1, 0, 2, 60, 62,
+ 0, 1, 0, 2, 40, 76, 2, 1, 0, 2, 40, 62,
+ 0, 1, 0, 2, 44, 76, 2, 1, 0, 2, 44, 62,
+ 0, 1, 0, 2, 48, 76, 2, 1, 0, 2, 48, 62,
+ 0, 1, 0, 2, 52, 76, 2, 1, 0, 2, 52, 62,
+ 0, 1, 0, 2, 56, 76, 2, 1, 0, 2, 56, 62,
+ 0, 1, 0, 2, 60, 76, 2, 1, 0, 2, 60, 62,
0, 1, 0, 2, 64, 74, 2, 1, 0, 2, 64, 62,
0, 1, 0, 2, 100, 70, 2, 1, 0, 2, 100, 62,
- 0, 1, 0, 2, 104, 80, 2, 1, 0, 2, 104, 62,
- 0, 1, 0, 2, 108, 80, 2, 1, 0, 2, 108, 62,
- 0, 1, 0, 2, 112, 80, 2, 1, 0, 2, 112, 62,
- 0, 1, 0, 2, 116, 80, 2, 1, 0, 2, 116, 62,
- 0, 1, 0, 2, 120, 80, 2, 1, 0, 2, 120, 62,
- 0, 1, 0, 2, 124, 80, 2, 1, 0, 2, 124, 62,
- 0, 1, 0, 2, 128, 80, 2, 1, 0, 2, 128, 62,
- 0, 1, 0, 2, 132, 80, 2, 1, 0, 2, 132, 62,
- 0, 1, 0, 2, 136, 80, 2, 1, 0, 2, 136, 62,
+ 0, 1, 0, 2, 104, 76, 2, 1, 0, 2, 104, 62,
+ 0, 1, 0, 2, 108, 76, 2, 1, 0, 2, 108, 62,
+ 0, 1, 0, 2, 112, 76, 2, 1, 0, 2, 112, 62,
+ 0, 1, 0, 2, 116, 76, 2, 1, 0, 2, 116, 62,
+ 0, 1, 0, 2, 120, 76, 2, 1, 0, 2, 120, 62,
+ 0, 1, 0, 2, 124, 76, 2, 1, 0, 2, 124, 62,
+ 0, 1, 0, 2, 128, 76, 2, 1, 0, 2, 128, 62,
+ 0, 1, 0, 2, 132, 76, 2, 1, 0, 2, 132, 62,
+ 0, 1, 0, 2, 136, 76, 2, 1, 0, 2, 136, 62,
0, 1, 0, 2, 140, 70, 2, 1, 0, 2, 140, 62,
- 0, 1, 0, 2, 144, 80, 2, 1, 0, 2, 144, 127,
- 0, 1, 0, 2, 149, 80, 2, 1, 0, 2, 149, 127,
- 0, 1, 0, 2, 153, 80, 2, 1, 0, 2, 153, 127,
- 0, 1, 0, 2, 157, 80, 2, 1, 0, 2, 157, 127,
- 0, 1, 0, 2, 161, 80, 2, 1, 0, 2, 161, 127,
- 0, 1, 0, 2, 165, 80, 2, 1, 0, 2, 165, 127,
+ 0, 1, 0, 2, 144, 76, 2, 1, 0, 2, 144, 127,
+ 0, 1, 0, 2, 149, 76, 2, 1, 0, 2, 149, -128,
+ 0, 1, 0, 2, 153, 76, 2, 1, 0, 2, 153, -128,
+ 0, 1, 0, 2, 157, 76, 2, 1, 0, 2, 157, -128,
+ 0, 1, 0, 2, 161, 76, 2, 1, 0, 2, 161, -128,
+ 0, 1, 0, 2, 165, 76, 2, 1, 0, 2, 165, -128,
0, 1, 0, 3, 36, 68, 2, 1, 0, 3, 36, 38,
0, 1, 0, 3, 40, 68, 2, 1, 0, 3, 40, 38,
0, 1, 0, 3, 44, 68, 2, 1, 0, 3, 44, 38,
@@ -9558,23 +9558,23 @@ static const u8 rtw8822c_txpwr_lmt_type0[] = {
0, 1, 0, 3, 136, 68, 2, 1, 0, 3, 136, 38,
0, 1, 0, 3, 140, 60, 2, 1, 0, 3, 140, 38,
0, 1, 0, 3, 144, 68, 2, 1, 0, 3, 144, 127,
- 0, 1, 0, 3, 149, 80, 2, 1, 0, 3, 149, 127,
- 0, 1, 0, 3, 153, 80, 2, 1, 0, 3, 153, 127,
- 0, 1, 0, 3, 157, 80, 2, 1, 0, 3, 157, 127,
- 0, 1, 0, 3, 161, 80, 2, 1, 0, 3, 161, 127,
- 0, 1, 0, 3, 165, 80, 2, 1, 0, 3, 165, 127,
+ 0, 1, 0, 3, 149, 76, 2, 1, 0, 3, 149, -128,
+ 0, 1, 0, 3, 153, 76, 2, 1, 0, 3, 153, -128,
+ 0, 1, 0, 3, 157, 76, 2, 1, 0, 3, 157, -128,
+ 0, 1, 0, 3, 161, 76, 2, 1, 0, 3, 161, -128,
+ 0, 1, 0, 3, 165, 76, 2, 1, 0, 3, 165, -128,
0, 1, 1, 2, 38, 66, 2, 1, 1, 2, 38, 64,
0, 1, 1, 2, 46, 72, 2, 1, 1, 2, 46, 64,
0, 1, 1, 2, 54, 72, 2, 1, 1, 2, 54, 64,
0, 1, 1, 2, 62, 64, 2, 1, 1, 2, 62, 64,
0, 1, 1, 2, 102, 58, 2, 1, 1, 2, 102, 64,
- 0, 1, 1, 2, 110, 74, 2, 1, 1, 2, 110, 64,
- 0, 1, 1, 2, 118, 74, 2, 1, 1, 2, 118, 64,
- 0, 1, 1, 2, 126, 74, 2, 1, 1, 2, 126, 64,
- 0, 1, 1, 2, 134, 74, 2, 1, 1, 2, 134, 64,
- 0, 1, 1, 2, 142, 74, 2, 1, 1, 2, 142, 127,
- 0, 1, 1, 2, 151, 74, 2, 1, 1, 2, 151, 127,
- 0, 1, 1, 2, 159, 74, 2, 1, 1, 2, 159, 127,
+ 0, 1, 1, 2, 110, 72, 2, 1, 1, 2, 110, 64,
+ 0, 1, 1, 2, 118, 72, 2, 1, 1, 2, 118, 64,
+ 0, 1, 1, 2, 126, 72, 2, 1, 1, 2, 126, 64,
+ 0, 1, 1, 2, 134, 72, 2, 1, 1, 2, 134, 64,
+ 0, 1, 1, 2, 142, 72, 2, 1, 1, 2, 142, 127,
+ 0, 1, 1, 2, 151, 72, 2, 1, 1, 2, 151, -128,
+ 0, 1, 1, 2, 159, 72, 2, 1, 1, 2, 159, -128,
0, 1, 1, 3, 38, 60, 2, 1, 1, 3, 38, 40,
0, 1, 1, 3, 46, 68, 2, 1, 1, 3, 46, 40,
0, 1, 1, 3, 54, 68, 2, 1, 1, 3, 54, 40,
@@ -9585,20 +9585,703 @@ static const u8 rtw8822c_txpwr_lmt_type0[] = {
0, 1, 1, 3, 126, 68, 2, 1, 1, 3, 126, 40,
0, 1, 1, 3, 134, 68, 2, 1, 1, 3, 134, 40,
0, 1, 1, 3, 142, 68, 2, 1, 1, 3, 142, 127,
- 0, 1, 1, 3, 151, 74, 2, 1, 1, 3, 151, 127,
- 0, 1, 1, 3, 159, 74, 2, 1, 1, 3, 159, 127,
+ 0, 1, 1, 3, 151, 72, 2, 1, 1, 3, 151, -128,
+ 0, 1, 1, 3, 159, 72, 2, 1, 1, 3, 159, -128,
0, 1, 2, 4, 42, 64, 2, 1, 2, 4, 42, 64,
0, 1, 2, 4, 58, 62, 2, 1, 2, 4, 58, 64,
0, 1, 2, 4, 106, 58, 2, 1, 2, 4, 106, 64,
0, 1, 2, 4, 122, 72, 2, 1, 2, 4, 122, 64,
0, 1, 2, 4, 138, 72, 2, 1, 2, 4, 138, 127,
- 0, 1, 2, 4, 155, 72, 2, 1, 2, 4, 155, 127,
+ 0, 1, 2, 4, 155, 72, 2, 1, 2, 4, 155, -128,
0, 1, 2, 5, 42, 54, 2, 1, 2, 5, 42, 40,
0, 1, 2, 5, 58, 52, 2, 1, 2, 5, 58, 40,
0, 1, 2, 5, 106, 50, 2, 1, 2, 5, 106, 40,
0, 1, 2, 5, 122, 66, 2, 1, 2, 5, 122, 40,
0, 1, 2, 5, 138, 66, 2, 1, 2, 5, 138, 127,
- 0, 1, 2, 5, 155, 62, 2, 1, 2, 5, 155, 127
+ 0, 1, 2, 5, 155, 62, 2, 1, 2, 5, 155, -128,
+ 1, 0, 0, 0, 1, 68, 3, 0, 0, 0, 1, 72,
+ 4, 0, 0, 0, 1, 76, 5, 0, 0, 0, 1, 60,
+ 6, 0, 0, 0, 1, 72, 7, 0, 0, 0, 1, 60,
+ 8, 0, 0, 0, 1, 72, 1, 0, 0, 0, 2, 68,
+ 3, 0, 0, 0, 2, 72, 4, 0, 0, 0, 2, 76,
+ 5, 0, 0, 0, 2, 60, 6, 0, 0, 0, 2, 72,
+ 7, 0, 0, 0, 2, 60, 8, 0, 0, 0, 2, 72,
+ 1, 0, 0, 0, 3, 68, 3, 0, 0, 0, 3, 76,
+ 4, 0, 0, 0, 3, 76, 5, 0, 0, 0, 3, 60,
+ 6, 0, 0, 0, 3, 76, 7, 0, 0, 0, 3, 60,
+ 8, 0, 0, 0, 3, 76, 1, 0, 0, 0, 4, 68,
+ 3, 0, 0, 0, 4, 76, 4, 0, 0, 0, 4, 76,
+ 5, 0, 0, 0, 4, 60, 6, 0, 0, 0, 4, 76,
+ 7, 0, 0, 0, 4, 60, 8, 0, 0, 0, 4, 76,
+ 1, 0, 0, 0, 5, 68, 3, 0, 0, 0, 5, 76,
+ 4, 0, 0, 0, 5, 76, 5, 0, 0, 0, 5, 60,
+ 6, 0, 0, 0, 5, 76, 7, 0, 0, 0, 5, 60,
+ 8, 0, 0, 0, 5, 76, 1, 0, 0, 0, 6, 68,
+ 3, 0, 0, 0, 6, 76, 4, 0, 0, 0, 6, 76,
+ 5, 0, 0, 0, 6, 60, 6, 0, 0, 0, 6, 76,
+ 7, 0, 0, 0, 6, 60, 8, 0, 0, 0, 6, 76,
+ 1, 0, 0, 0, 7, 68, 3, 0, 0, 0, 7, 76,
+ 4, 0, 0, 0, 7, 76, 5, 0, 0, 0, 7, 60,
+ 6, 0, 0, 0, 7, 76, 7, 0, 0, 0, 7, 60,
+ 8, 0, 0, 0, 7, 76, 1, 0, 0, 0, 8, 68,
+ 3, 0, 0, 0, 8, 76, 4, 0, 0, 0, 8, 76,
+ 5, 0, 0, 0, 8, 60, 6, 0, 0, 0, 8, 76,
+ 7, 0, 0, 0, 8, 60, 8, 0, 0, 0, 8, 76,
+ 1, 0, 0, 0, 9, 68, 3, 0, 0, 0, 9, 76,
+ 4, 0, 0, 0, 9, 76, 5, 0, 0, 0, 9, 60,
+ 6, 0, 0, 0, 9, 76, 7, 0, 0, 0, 9, 60,
+ 8, 0, 0, 0, 9, 76, 1, 0, 0, 0, 10, 68,
+ 3, 0, 0, 0, 10, 72, 4, 0, 0, 0, 10, 76,
+ 5, 0, 0, 0, 10, 60, 6, 0, 0, 0, 10, 72,
+ 7, 0, 0, 0, 10, 60, 8, 0, 0, 0, 10, 72,
+ 1, 0, 0, 0, 11, 68, 3, 0, 0, 0, 11, 72,
+ 4, 0, 0, 0, 11, 76, 5, 0, 0, 0, 11, 60,
+ 6, 0, 0, 0, 11, 72, 7, 0, 0, 0, 11, 60,
+ 8, 0, 0, 0, 11, 72, 1, 0, 0, 0, 12, 68,
+ 3, 0, 0, 0, 12, 52, 4, 0, 0, 0, 12, 76,
+ 5, 0, 0, 0, 12, 60, 6, 0, 0, 0, 12, 52,
+ 7, 0, 0, 0, 12, 60, 8, 0, 0, 0, 12, 52,
+ 1, 0, 0, 0, 13, 68, 3, 0, 0, 0, 13, 48,
+ 4, 0, 0, 0, 13, 76, 5, 0, 0, 0, 13, 60,
+ 6, 0, 0, 0, 13, 48, 7, 0, 0, 0, 13, 60,
+ 8, 0, 0, 0, 13, 48, 1, 0, 0, 0, 14, 68,
+ 3, 0, 0, 0, 14, 127, 4, 0, 0, 0, 14, 127,
+ 5, 0, 0, 0, 14, 127, 6, 0, 0, 0, 14, 127,
+ 7, 0, 0, 0, 14, 127, 8, 0, 0, 0, 14, 127,
+ 1, 0, 0, 1, 1, 76, 3, 0, 0, 1, 1, 52,
+ 4, 0, 0, 1, 1, 76, 5, 0, 0, 1, 1, 60,
+ 6, 0, 0, 1, 1, 52, 7, 0, 0, 1, 1, 60,
+ 8, 0, 0, 1, 1, 52, 1, 0, 0, 1, 2, 76,
+ 3, 0, 0, 1, 2, 60, 4, 0, 0, 1, 2, 76,
+ 5, 0, 0, 1, 2, 60, 6, 0, 0, 1, 2, 60,
+ 7, 0, 0, 1, 2, 60, 8, 0, 0, 1, 2, 60,
+ 1, 0, 0, 1, 3, 76, 3, 0, 0, 1, 3, 64,
+ 4, 0, 0, 1, 3, 76, 5, 0, 0, 1, 3, 60,
+ 6, 0, 0, 1, 3, 64, 7, 0, 0, 1, 3, 60,
+ 8, 0, 0, 1, 3, 64, 1, 0, 0, 1, 4, 76,
+ 3, 0, 0, 1, 4, 68, 4, 0, 0, 1, 4, 76,
+ 5, 0, 0, 1, 4, 60, 6, 0, 0, 1, 4, 68,
+ 7, 0, 0, 1, 4, 60, 8, 0, 0, 1, 4, 68,
+ 1, 0, 0, 1, 5, 76, 3, 0, 0, 1, 5, 76,
+ 4, 0, 0, 1, 5, 76, 5, 0, 0, 1, 5, 60,
+ 6, 0, 0, 1, 5, 76, 7, 0, 0, 1, 5, 60,
+ 8, 0, 0, 1, 5, 76, 1, 0, 0, 1, 6, 76,
+ 3, 0, 0, 1, 6, 76, 4, 0, 0, 1, 6, 76,
+ 5, 0, 0, 1, 6, 60, 6, 0, 0, 1, 6, 76,
+ 7, 0, 0, 1, 6, 60, 8, 0, 0, 1, 6, 76,
+ 1, 0, 0, 1, 7, 76, 3, 0, 0, 1, 7, 76,
+ 4, 0, 0, 1, 7, 76, 5, 0, 0, 1, 7, 60,
+ 6, 0, 0, 1, 7, 76, 7, 0, 0, 1, 7, 60,
+ 8, 0, 0, 1, 7, 76, 1, 0, 0, 1, 8, 76,
+ 3, 0, 0, 1, 8, 68, 4, 0, 0, 1, 8, 76,
+ 5, 0, 0, 1, 8, 60, 6, 0, 0, 1, 8, 68,
+ 7, 0, 0, 1, 8, 60, 8, 0, 0, 1, 8, 68,
+ 1, 0, 0, 1, 9, 76, 3, 0, 0, 1, 9, 64,
+ 4, 0, 0, 1, 9, 76, 5, 0, 0, 1, 9, 60,
+ 6, 0, 0, 1, 9, 64, 7, 0, 0, 1, 9, 60,
+ 8, 0, 0, 1, 9, 64, 1, 0, 0, 1, 10, 76,
+ 3, 0, 0, 1, 10, 60, 4, 0, 0, 1, 10, 76,
+ 5, 0, 0, 1, 10, 60, 6, 0, 0, 1, 10, 60,
+ 7, 0, 0, 1, 10, 60, 8, 0, 0, 1, 10, 60,
+ 1, 0, 0, 1, 11, 76, 3, 0, 0, 1, 11, 52,
+ 4, 0, 0, 1, 11, 76, 5, 0, 0, 1, 11, 60,
+ 6, 0, 0, 1, 11, 52, 7, 0, 0, 1, 11, 60,
+ 8, 0, 0, 1, 11, 52, 1, 0, 0, 1, 12, 76,
+ 3, 0, 0, 1, 12, 40, 4, 0, 0, 1, 12, 76,
+ 5, 0, 0, 1, 12, 60, 6, 0, 0, 1, 12, 40,
+ 7, 0, 0, 1, 12, 60, 8, 0, 0, 1, 12, 40,
+ 1, 0, 0, 1, 13, 76, 3, 0, 0, 1, 13, 28,
+ 4, 0, 0, 1, 13, 70, 5, 0, 0, 1, 13, 60,
+ 6, 0, 0, 1, 13, 28, 7, 0, 0, 1, 13, 60,
+ 8, 0, 0, 1, 13, 28, 1, 0, 0, 1, 14, 127,
+ 3, 0, 0, 1, 14, 127, 4, 0, 0, 1, 14, 127,
+ 5, 0, 0, 1, 14, 127, 6, 0, 0, 1, 14, 127,
+ 7, 0, 0, 1, 14, 127, 8, 0, 0, 1, 14, 127,
+ 1, 0, 0, 2, 1, 76, 3, 0, 0, 2, 1, 52,
+ 4, 0, 0, 2, 1, 76, 5, 0, 0, 2, 1, 60,
+ 6, 0, 0, 2, 1, 52, 7, 0, 0, 2, 1, 60,
+ 8, 0, 0, 2, 1, 52, 1, 0, 0, 2, 2, 76,
+ 3, 0, 0, 2, 2, 60, 4, 0, 0, 2, 2, 76,
+ 5, 0, 0, 2, 2, 60, 6, 0, 0, 2, 2, 60,
+ 7, 0, 0, 2, 2, 60, 8, 0, 0, 2, 2, 60,
+ 1, 0, 0, 2, 3, 76, 3, 0, 0, 2, 3, 64,
+ 4, 0, 0, 2, 3, 76, 5, 0, 0, 2, 3, 60,
+ 6, 0, 0, 2, 3, 64, 7, 0, 0, 2, 3, 60,
+ 8, 0, 0, 2, 3, 64, 1, 0, 0, 2, 4, 76,
+ 3, 0, 0, 2, 4, 68, 4, 0, 0, 2, 4, 76,
+ 5, 0, 0, 2, 4, 60, 6, 0, 0, 2, 4, 68,
+ 7, 0, 0, 2, 4, 60, 8, 0, 0, 2, 4, 68,
+ 1, 0, 0, 2, 5, 76, 3, 0, 0, 2, 5, 76,
+ 4, 0, 0, 2, 5, 76, 5, 0, 0, 2, 5, 60,
+ 6, 0, 0, 2, 5, 76, 7, 0, 0, 2, 5, 60,
+ 8, 0, 0, 2, 5, 76, 1, 0, 0, 2, 6, 76,
+ 3, 0, 0, 2, 6, 76, 4, 0, 0, 2, 6, 76,
+ 5, 0, 0, 2, 6, 60, 6, 0, 0, 2, 6, 76,
+ 7, 0, 0, 2, 6, 60, 8, 0, 0, 2, 6, 76,
+ 1, 0, 0, 2, 7, 76, 3, 0, 0, 2, 7, 76,
+ 4, 0, 0, 2, 7, 76, 5, 0, 0, 2, 7, 60,
+ 6, 0, 0, 2, 7, 76, 7, 0, 0, 2, 7, 60,
+ 8, 0, 0, 2, 7, 76, 1, 0, 0, 2, 8, 76,
+ 3, 0, 0, 2, 8, 68, 4, 0, 0, 2, 8, 76,
+ 5, 0, 0, 2, 8, 60, 6, 0, 0, 2, 8, 68,
+ 7, 0, 0, 2, 8, 60, 8, 0, 0, 2, 8, 68,
+ 1, 0, 0, 2, 9, 76, 3, 0, 0, 2, 9, 64,
+ 4, 0, 0, 2, 9, 76, 5, 0, 0, 2, 9, 60,
+ 6, 0, 0, 2, 9, 64, 7, 0, 0, 2, 9, 60,
+ 8, 0, 0, 2, 9, 64, 1, 0, 0, 2, 10, 76,
+ 3, 0, 0, 2, 10, 60, 4, 0, 0, 2, 10, 76,
+ 5, 0, 0, 2, 10, 60, 6, 0, 0, 2, 10, 60,
+ 7, 0, 0, 2, 10, 60, 8, 0, 0, 2, 10, 60,
+ 1, 0, 0, 2, 11, 76, 3, 0, 0, 2, 11, 52,
+ 4, 0, 0, 2, 11, 76, 5, 0, 0, 2, 11, 60,
+ 6, 0, 0, 2, 11, 52, 7, 0, 0, 2, 11, 60,
+ 8, 0, 0, 2, 11, 52, 1, 0, 0, 2, 12, 76,
+ 3, 0, 0, 2, 12, 40, 4, 0, 0, 2, 12, 76,
+ 5, 0, 0, 2, 12, 60, 6, 0, 0, 2, 12, 40,
+ 7, 0, 0, 2, 12, 60, 8, 0, 0, 2, 12, 40,
+ 1, 0, 0, 2, 13, 76, 3, 0, 0, 2, 13, 28,
+ 4, 0, 0, 2, 13, 72, 5, 0, 0, 2, 13, 60,
+ 6, 0, 0, 2, 13, 28, 7, 0, 0, 2, 13, 60,
+ 8, 0, 0, 2, 13, 28, 1, 0, 0, 2, 14, 127,
+ 3, 0, 0, 2, 14, 127, 4, 0, 0, 2, 14, 127,
+ 5, 0, 0, 2, 14, 127, 6, 0, 0, 2, 14, 127,
+ 7, 0, 0, 2, 14, 127, 8, 0, 0, 2, 14, 127,
+ 1, 0, 0, 3, 1, 66, 3, 0, 0, 3, 1, 52,
+ 4, 0, 0, 3, 1, 68, 5, 0, 0, 3, 1, 36,
+ 6, 0, 0, 3, 1, 52, 7, 0, 0, 3, 1, 36,
+ 8, 0, 0, 3, 1, 52, 1, 0, 0, 3, 2, 66,
+ 3, 0, 0, 3, 2, 60, 4, 0, 0, 3, 2, 70,
+ 5, 0, 0, 3, 2, 36, 6, 0, 0, 3, 2, 60,
+ 7, 0, 0, 3, 2, 36, 8, 0, 0, 3, 2, 60,
+ 1, 0, 0, 3, 3, 66, 3, 0, 0, 3, 3, 64,
+ 4, 0, 0, 3, 3, 70, 5, 0, 0, 3, 3, 36,
+ 6, 0, 0, 3, 3, 64, 7, 0, 0, 3, 3, 36,
+ 8, 0, 0, 3, 3, 64, 1, 0, 0, 3, 4, 66,
+ 3, 0, 0, 3, 4, 68, 4, 0, 0, 3, 4, 70,
+ 5, 0, 0, 3, 4, 36, 6, 0, 0, 3, 4, 68,
+ 7, 0, 0, 3, 4, 36, 8, 0, 0, 3, 4, 68,
+ 1, 0, 0, 3, 5, 66, 3, 0, 0, 3, 5, 76,
+ 4, 0, 0, 3, 5, 70, 5, 0, 0, 3, 5, 36,
+ 6, 0, 0, 3, 5, 76, 7, 0, 0, 3, 5, 36,
+ 8, 0, 0, 3, 5, 76, 1, 0, 0, 3, 6, 66,
+ 3, 0, 0, 3, 6, 76, 4, 0, 0, 3, 6, 70,
+ 5, 0, 0, 3, 6, 36, 6, 0, 0, 3, 6, 76,
+ 7, 0, 0, 3, 6, 36, 8, 0, 0, 3, 6, 76,
+ 1, 0, 0, 3, 7, 66, 3, 0, 0, 3, 7, 76,
+ 4, 0, 0, 3, 7, 70, 5, 0, 0, 3, 7, 36,
+ 6, 0, 0, 3, 7, 76, 7, 0, 0, 3, 7, 36,
+ 8, 0, 0, 3, 7, 76, 1, 0, 0, 3, 8, 66,
+ 3, 0, 0, 3, 8, 68, 4, 0, 0, 3, 8, 70,
+ 5, 0, 0, 3, 8, 36, 6, 0, 0, 3, 8, 68,
+ 7, 0, 0, 3, 8, 36, 8, 0, 0, 3, 8, 68,
+ 1, 0, 0, 3, 9, 66, 3, 0, 0, 3, 9, 64,
+ 4, 0, 0, 3, 9, 70, 5, 0, 0, 3, 9, 36,
+ 6, 0, 0, 3, 9, 64, 7, 0, 0, 3, 9, 36,
+ 8, 0, 0, 3, 9, 64, 1, 0, 0, 3, 10, 66,
+ 3, 0, 0, 3, 10, 60, 4, 0, 0, 3, 10, 70,
+ 5, 0, 0, 3, 10, 36, 6, 0, 0, 3, 10, 60,
+ 7, 0, 0, 3, 10, 36, 8, 0, 0, 3, 10, 60,
+ 1, 0, 0, 3, 11, 66, 3, 0, 0, 3, 11, 52,
+ 4, 0, 0, 3, 11, 70, 5, 0, 0, 3, 11, 36,
+ 6, 0, 0, 3, 11, 52, 7, 0, 0, 3, 11, 36,
+ 8, 0, 0, 3, 11, 52, 1, 0, 0, 3, 12, 66,
+ 3, 0, 0, 3, 12, 40, 4, 0, 0, 3, 12, 70,
+ 5, 0, 0, 3, 12, 36, 6, 0, 0, 3, 12, 40,
+ 7, 0, 0, 3, 12, 36, 8, 0, 0, 3, 12, 40,
+ 1, 0, 0, 3, 13, 66, 3, 0, 0, 3, 13, 28,
+ 4, 0, 0, 3, 13, 62, 5, 0, 0, 3, 13, 36,
+ 6, 0, 0, 3, 13, 28, 7, 0, 0, 3, 13, 36,
+ 8, 0, 0, 3, 13, 28, 1, 0, 0, 3, 14, 127,
+ 3, 0, 0, 3, 14, 127, 4, 0, 0, 3, 14, 127,
+ 5, 0, 0, 3, 14, 127, 6, 0, 0, 3, 14, 127,
+ 7, 0, 0, 3, 14, 127, 8, 0, 0, 3, 14, 127,
+ 1, 0, 1, 2, 1, 127, 3, 0, 1, 2, 1, 127,
+ 4, 0, 1, 2, 1, 127, 5, 0, 1, 2, 1, 127,
+ 6, 0, 1, 2, 1, 127, 7, 0, 1, 2, 1, 127,
+ 8, 0, 1, 2, 1, 127, 1, 0, 1, 2, 2, 127,
+ 3, 0, 1, 2, 2, 127, 4, 0, 1, 2, 2, 127,
+ 5, 0, 1, 2, 2, 127, 6, 0, 1, 2, 2, 127,
+ 7, 0, 1, 2, 2, 127, 8, 0, 1, 2, 2, 127,
+ 1, 0, 1, 2, 3, 72, 3, 0, 1, 2, 3, 52,
+ 4, 0, 1, 2, 3, 72, 5, 0, 1, 2, 3, 60,
+ 6, 0, 1, 2, 3, 52, 7, 0, 1, 2, 3, 60,
+ 8, 0, 1, 2, 3, 52, 1, 0, 1, 2, 4, 72,
+ 3, 0, 1, 2, 4, 52, 4, 0, 1, 2, 4, 72,
+ 5, 0, 1, 2, 4, 60, 6, 0, 1, 2, 4, 52,
+ 7, 0, 1, 2, 4, 60, 8, 0, 1, 2, 4, 52,
+ 1, 0, 1, 2, 5, 72, 3, 0, 1, 2, 5, 60,
+ 4, 0, 1, 2, 5, 72, 5, 0, 1, 2, 5, 60,
+ 6, 0, 1, 2, 5, 60, 7, 0, 1, 2, 5, 60,
+ 8, 0, 1, 2, 5, 60, 1, 0, 1, 2, 6, 72,
+ 3, 0, 1, 2, 6, 64, 4, 0, 1, 2, 6, 72,
+ 5, 0, 1, 2, 6, 60, 6, 0, 1, 2, 6, 64,
+ 7, 0, 1, 2, 6, 60, 8, 0, 1, 2, 6, 64,
+ 1, 0, 1, 2, 7, 72, 3, 0, 1, 2, 7, 60,
+ 4, 0, 1, 2, 7, 72, 5, 0, 1, 2, 7, 60,
+ 6, 0, 1, 2, 7, 60, 7, 0, 1, 2, 7, 60,
+ 8, 0, 1, 2, 7, 60, 1, 0, 1, 2, 8, 72,
+ 3, 0, 1, 2, 8, 52, 4, 0, 1, 2, 8, 72,
+ 5, 0, 1, 2, 8, 60, 6, 0, 1, 2, 8, 52,
+ 7, 0, 1, 2, 8, 60, 8, 0, 1, 2, 8, 52,
+ 1, 0, 1, 2, 9, 72, 3, 0, 1, 2, 9, 52,
+ 4, 0, 1, 2, 9, 72, 5, 0, 1, 2, 9, 60,
+ 6, 0, 1, 2, 9, 52, 7, 0, 1, 2, 9, 60,
+ 8, 0, 1, 2, 9, 52, 1, 0, 1, 2, 10, 72,
+ 3, 0, 1, 2, 10, 40, 4, 0, 1, 2, 10, 72,
+ 5, 0, 1, 2, 10, 60, 6, 0, 1, 2, 10, 40,
+ 7, 0, 1, 2, 10, 60, 8, 0, 1, 2, 10, 40,
+ 1, 0, 1, 2, 11, 72, 3, 0, 1, 2, 11, 28,
+ 4, 0, 1, 2, 11, 70, 5, 0, 1, 2, 11, 60,
+ 6, 0, 1, 2, 11, 28, 7, 0, 1, 2, 11, 60,
+ 8, 0, 1, 2, 11, 28, 1, 0, 1, 2, 12, 127,
+ 3, 0, 1, 2, 12, 127, 4, 0, 1, 2, 12, 127,
+ 5, 0, 1, 2, 12, 127, 6, 0, 1, 2, 12, 127,
+ 7, 0, 1, 2, 12, 127, 8, 0, 1, 2, 12, 127,
+ 1, 0, 1, 2, 13, 127, 3, 0, 1, 2, 13, 127,
+ 4, 0, 1, 2, 13, 127, 5, 0, 1, 2, 13, 127,
+ 6, 0, 1, 2, 13, 127, 7, 0, 1, 2, 13, 127,
+ 8, 0, 1, 2, 13, 127, 1, 0, 1, 2, 14, 127,
+ 3, 0, 1, 2, 14, 127, 4, 0, 1, 2, 14, 127,
+ 5, 0, 1, 2, 14, 127, 6, 0, 1, 2, 14, 127,
+ 7, 0, 1, 2, 14, 127, 8, 0, 1, 2, 14, 127,
+ 1, 0, 1, 3, 1, 127, 3, 0, 1, 3, 1, 127,
+ 4, 0, 1, 3, 1, 127, 5, 0, 1, 3, 1, 127,
+ 6, 0, 1, 3, 1, 127, 7, 0, 1, 3, 1, 127,
+ 8, 0, 1, 3, 1, 127, 1, 0, 1, 3, 2, 127,
+ 3, 0, 1, 3, 2, 127, 4, 0, 1, 3, 2, 127,
+ 5, 0, 1, 3, 2, 127, 6, 0, 1, 3, 2, 127,
+ 7, 0, 1, 3, 2, 127, 8, 0, 1, 3, 2, 127,
+ 1, 0, 1, 3, 3, 66, 3, 0, 1, 3, 3, 48,
+ 4, 0, 1, 3, 3, 66, 5, 0, 1, 3, 3, 36,
+ 6, 0, 1, 3, 3, 48, 7, 0, 1, 3, 3, 36,
+ 8, 0, 1, 3, 3, 48, 1, 0, 1, 3, 4, 66,
+ 3, 0, 1, 3, 4, 48, 4, 0, 1, 3, 4, 70,
+ 5, 0, 1, 3, 4, 36, 6, 0, 1, 3, 4, 48,
+ 7, 0, 1, 3, 4, 36, 8, 0, 1, 3, 4, 48,
+ 1, 0, 1, 3, 5, 66, 3, 0, 1, 3, 5, 60,
+ 4, 0, 1, 3, 5, 70, 5, 0, 1, 3, 5, 36,
+ 6, 0, 1, 3, 5, 60, 7, 0, 1, 3, 5, 36,
+ 8, 0, 1, 3, 5, 60, 1, 0, 1, 3, 6, 66,
+ 3, 0, 1, 3, 6, 64, 4, 0, 1, 3, 6, 70,
+ 5, 0, 1, 3, 6, 36, 6, 0, 1, 3, 6, 64,
+ 7, 0, 1, 3, 6, 36, 8, 0, 1, 3, 6, 64,
+ 1, 0, 1, 3, 7, 66, 3, 0, 1, 3, 7, 60,
+ 4, 0, 1, 3, 7, 70, 5, 0, 1, 3, 7, 36,
+ 6, 0, 1, 3, 7, 60, 7, 0, 1, 3, 7, 36,
+ 8, 0, 1, 3, 7, 60, 1, 0, 1, 3, 8, 66,
+ 3, 0, 1, 3, 8, 52, 4, 0, 1, 3, 8, 70,
+ 5, 0, 1, 3, 8, 36, 6, 0, 1, 3, 8, 52,
+ 7, 0, 1, 3, 8, 36, 8, 0, 1, 3, 8, 52,
+ 1, 0, 1, 3, 9, 66, 3, 0, 1, 3, 9, 52,
+ 4, 0, 1, 3, 9, 70, 5, 0, 1, 3, 9, 36,
+ 6, 0, 1, 3, 9, 52, 7, 0, 1, 3, 9, 36,
+ 8, 0, 1, 3, 9, 52, 1, 0, 1, 3, 10, 66,
+ 3, 0, 1, 3, 10, 40, 4, 0, 1, 3, 10, 70,
+ 5, 0, 1, 3, 10, 36, 6, 0, 1, 3, 10, 40,
+ 7, 0, 1, 3, 10, 36, 8, 0, 1, 3, 10, 40,
+ 1, 0, 1, 3, 11, 66, 3, 0, 1, 3, 11, 26,
+ 4, 0, 1, 3, 11, 66, 5, 0, 1, 3, 11, 36,
+ 6, 0, 1, 3, 11, 26, 7, 0, 1, 3, 11, 36,
+ 8, 0, 1, 3, 11, 26, 1, 0, 1, 3, 12, 127,
+ 3, 0, 1, 3, 12, 127, 4, 0, 1, 3, 12, 127,
+ 5, 0, 1, 3, 12, 127, 6, 0, 1, 3, 12, 127,
+ 7, 0, 1, 3, 12, 127, 8, 0, 1, 3, 12, 127,
+ 1, 0, 1, 3, 13, 127, 3, 0, 1, 3, 13, 127,
+ 4, 0, 1, 3, 13, 127, 5, 0, 1, 3, 13, 127,
+ 6, 0, 1, 3, 13, 127, 7, 0, 1, 3, 13, 127,
+ 8, 0, 1, 3, 13, 127, 1, 0, 1, 3, 14, 127,
+ 3, 0, 1, 3, 14, 127, 4, 0, 1, 3, 14, 127,
+ 5, 0, 1, 3, 14, 127, 6, 0, 1, 3, 14, 127,
+ 7, 0, 1, 3, 14, 127, 8, 0, 1, 3, 14, 127,
+ 1, 1, 0, 1, 36, 60, 3, 1, 0, 1, 36, 62,
+ 4, 1, 0, 1, 36, 76, 5, 1, 0, 1, 36, 62,
+ 6, 1, 0, 1, 36, 64, 7, 1, 0, 1, 36, 54,
+ 8, 1, 0, 1, 36, 62, 1, 1, 0, 1, 40, 62,
+ 3, 1, 0, 1, 40, 62, 4, 1, 0, 1, 40, 76,
+ 5, 1, 0, 1, 40, 62, 6, 1, 0, 1, 40, 64,
+ 7, 1, 0, 1, 40, 54, 8, 1, 0, 1, 40, 62,
+ 1, 1, 0, 1, 44, 62, 3, 1, 0, 1, 44, 62,
+ 4, 1, 0, 1, 44, 76, 5, 1, 0, 1, 44, 62,
+ 6, 1, 0, 1, 44, 64, 7, 1, 0, 1, 44, 54,
+ 8, 1, 0, 1, 44, 62, 1, 1, 0, 1, 48, 62,
+ 3, 1, 0, 1, 48, 62, 4, 1, 0, 1, 48, 76,
+ 5, 1, 0, 1, 48, 62, 6, 1, 0, 1, 48, 64,
+ 7, 1, 0, 1, 48, 54, 8, 1, 0, 1, 48, 62,
+ 1, 1, 0, 1, 52, 62, 3, 1, 0, 1, 52, 64,
+ 4, 1, 0, 1, 52, 76, 5, 1, 0, 1, 52, 62,
+ 6, 1, 0, 1, 52, 76, 7, 1, 0, 1, 52, 54,
+ 8, 1, 0, 1, 52, 76, 1, 1, 0, 1, 56, 62,
+ 3, 1, 0, 1, 56, 64, 4, 1, 0, 1, 56, 76,
+ 5, 1, 0, 1, 56, 62, 6, 1, 0, 1, 56, 76,
+ 7, 1, 0, 1, 56, 54, 8, 1, 0, 1, 56, 76,
+ 1, 1, 0, 1, 60, 62, 3, 1, 0, 1, 60, 64,
+ 4, 1, 0, 1, 60, 76, 5, 1, 0, 1, 60, 62,
+ 6, 1, 0, 1, 60, 76, 7, 1, 0, 1, 60, 54,
+ 8, 1, 0, 1, 60, 76, 1, 1, 0, 1, 64, 60,
+ 3, 1, 0, 1, 64, 64, 4, 1, 0, 1, 64, 76,
+ 5, 1, 0, 1, 64, 62, 6, 1, 0, 1, 64, 74,
+ 7, 1, 0, 1, 64, 54, 8, 1, 0, 1, 64, 74,
+ 1, 1, 0, 1, 100, 76, 3, 1, 0, 1, 100, 72,
+ 4, 1, 0, 1, 100, 76, 5, 1, 0, 1, 100, 62,
+ 6, 1, 0, 1, 100, 72, 7, 1, 0, 1, 100, 54,
+ 8, 1, 0, 1, 100, 72, 1, 1, 0, 1, 104, 76,
+ 3, 1, 0, 1, 104, 76, 4, 1, 0, 1, 104, 76,
+ 5, 1, 0, 1, 104, 62, 6, 1, 0, 1, 104, 76,
+ 7, 1, 0, 1, 104, 54, 8, 1, 0, 1, 104, 76,
+ 1, 1, 0, 1, 108, 76, 3, 1, 0, 1, 108, 76,
+ 4, 1, 0, 1, 108, 76, 5, 1, 0, 1, 108, 62,
+ 6, 1, 0, 1, 108, 76, 7, 1, 0, 1, 108, 54,
+ 8, 1, 0, 1, 108, 76, 1, 1, 0, 1, 112, 76,
+ 3, 1, 0, 1, 112, 76, 4, 1, 0, 1, 112, 76,
+ 5, 1, 0, 1, 112, 62, 6, 1, 0, 1, 112, 76,
+ 7, 1, 0, 1, 112, 54, 8, 1, 0, 1, 112, 76,
+ 1, 1, 0, 1, 116, 76, 3, 1, 0, 1, 116, 76,
+ 4, 1, 0, 1, 116, 76, 5, 1, 0, 1, 116, 62,
+ 6, 1, 0, 1, 116, 76, 7, 1, 0, 1, 116, 54,
+ 8, 1, 0, 1, 116, 76, 1, 1, 0, 1, 120, 76,
+ 3, 1, 0, 1, 120, 127, 4, 1, 0, 1, 120, 76,
+ 5, 1, 0, 1, 120, 127, 6, 1, 0, 1, 120, 76,
+ 7, 1, 0, 1, 120, 54, 8, 1, 0, 1, 120, 76,
+ 1, 1, 0, 1, 124, 76, 3, 1, 0, 1, 124, 127,
+ 4, 1, 0, 1, 124, 76, 5, 1, 0, 1, 124, 127,
+ 6, 1, 0, 1, 124, 76, 7, 1, 0, 1, 124, 54,
+ 8, 1, 0, 1, 124, 76, 1, 1, 0, 1, 128, 76,
+ 3, 1, 0, 1, 128, 127, 4, 1, 0, 1, 128, 76,
+ 5, 1, 0, 1, 128, 127, 6, 1, 0, 1, 128, 76,
+ 7, 1, 0, 1, 128, 54, 8, 1, 0, 1, 128, 76,
+ 1, 1, 0, 1, 132, 76, 3, 1, 0, 1, 132, 76,
+ 4, 1, 0, 1, 132, 76, 5, 1, 0, 1, 132, 62,
+ 6, 1, 0, 1, 132, 76, 7, 1, 0, 1, 132, 54,
+ 8, 1, 0, 1, 132, 76, 1, 1, 0, 1, 136, 76,
+ 3, 1, 0, 1, 136, 76, 4, 1, 0, 1, 136, 76,
+ 5, 1, 0, 1, 136, 62, 6, 1, 0, 1, 136, 76,
+ 7, 1, 0, 1, 136, 127, 8, 1, 0, 1, 136, 76,
+ 1, 1, 0, 1, 140, 76, 3, 1, 0, 1, 140, 72,
+ 4, 1, 0, 1, 140, 76, 5, 1, 0, 1, 140, 62,
+ 6, 1, 0, 1, 140, 72, 7, 1, 0, 1, 140, 127,
+ 8, 1, 0, 1, 140, 72, 1, 1, 0, 1, 144, 127,
+ 3, 1, 0, 1, 144, 76, 4, 1, 0, 1, 144, 76,
+ 5, 1, 0, 1, 144, 127, 6, 1, 0, 1, 144, 76,
+ 7, 1, 0, 1, 144, 127, 8, 1, 0, 1, 144, 76,
+ 1, 1, 0, 1, 149, 127, 3, 1, 0, 1, 149, 76,
+ 4, 1, 0, 1, 149, 74, 5, 1, 0, 1, 149, 76,
+ 6, 1, 0, 1, 149, 76, 7, 1, 0, 1, 149, 54,
+ 8, 1, 0, 1, 149, 76, 1, 1, 0, 1, 153, 127,
+ 3, 1, 0, 1, 153, 76, 4, 1, 0, 1, 153, 74,
+ 5, 1, 0, 1, 153, 76, 6, 1, 0, 1, 153, 76,
+ 7, 1, 0, 1, 153, 54, 8, 1, 0, 1, 153, 76,
+ 1, 1, 0, 1, 157, 127, 3, 1, 0, 1, 157, 76,
+ 4, 1, 0, 1, 157, 74, 5, 1, 0, 1, 157, 76,
+ 6, 1, 0, 1, 157, 76, 7, 1, 0, 1, 157, 54,
+ 8, 1, 0, 1, 157, 76, 1, 1, 0, 1, 161, 127,
+ 3, 1, 0, 1, 161, 76, 4, 1, 0, 1, 161, 74,
+ 5, 1, 0, 1, 161, 76, 6, 1, 0, 1, 161, 76,
+ 7, 1, 0, 1, 161, 54, 8, 1, 0, 1, 161, 76,
+ 1, 1, 0, 1, 165, 127, 3, 1, 0, 1, 165, 76,
+ 4, 1, 0, 1, 165, 74, 5, 1, 0, 1, 165, 76,
+ 6, 1, 0, 1, 165, 76, 7, 1, 0, 1, 165, 54,
+ 8, 1, 0, 1, 165, 76, 1, 1, 0, 2, 36, 62,
+ 3, 1, 0, 2, 36, 62, 4, 1, 0, 2, 36, 76,
+ 5, 1, 0, 2, 36, 62, 6, 1, 0, 2, 36, 64,
+ 7, 1, 0, 2, 36, 54, 8, 1, 0, 2, 36, 62,
+ 1, 1, 0, 2, 40, 62, 3, 1, 0, 2, 40, 62,
+ 4, 1, 0, 2, 40, 76, 5, 1, 0, 2, 40, 62,
+ 6, 1, 0, 2, 40, 64, 7, 1, 0, 2, 40, 54,
+ 8, 1, 0, 2, 40, 62, 1, 1, 0, 2, 44, 62,
+ 3, 1, 0, 2, 44, 62, 4, 1, 0, 2, 44, 76,
+ 5, 1, 0, 2, 44, 62, 6, 1, 0, 2, 44, 64,
+ 7, 1, 0, 2, 44, 54, 8, 1, 0, 2, 44, 62,
+ 1, 1, 0, 2, 48, 62, 3, 1, 0, 2, 48, 62,
+ 4, 1, 0, 2, 48, 76, 5, 1, 0, 2, 48, 62,
+ 6, 1, 0, 2, 48, 64, 7, 1, 0, 2, 48, 54,
+ 8, 1, 0, 2, 48, 62, 1, 1, 0, 2, 52, 62,
+ 3, 1, 0, 2, 52, 64, 4, 1, 0, 2, 52, 76,
+ 5, 1, 0, 2, 52, 62, 6, 1, 0, 2, 52, 76,
+ 7, 1, 0, 2, 52, 54, 8, 1, 0, 2, 52, 76,
+ 1, 1, 0, 2, 56, 62, 3, 1, 0, 2, 56, 64,
+ 4, 1, 0, 2, 56, 76, 5, 1, 0, 2, 56, 62,
+ 6, 1, 0, 2, 56, 76, 7, 1, 0, 2, 56, 54,
+ 8, 1, 0, 2, 56, 76, 1, 1, 0, 2, 60, 62,
+ 3, 1, 0, 2, 60, 64, 4, 1, 0, 2, 60, 76,
+ 5, 1, 0, 2, 60, 62, 6, 1, 0, 2, 60, 76,
+ 7, 1, 0, 2, 60, 54, 8, 1, 0, 2, 60, 76,
+ 1, 1, 0, 2, 64, 60, 3, 1, 0, 2, 64, 64,
+ 4, 1, 0, 2, 64, 74, 5, 1, 0, 2, 64, 62,
+ 6, 1, 0, 2, 64, 74, 7, 1, 0, 2, 64, 54,
+ 8, 1, 0, 2, 64, 74, 1, 1, 0, 2, 100, 76,
+ 3, 1, 0, 2, 100, 70, 4, 1, 0, 2, 100, 76,
+ 5, 1, 0, 2, 100, 62, 6, 1, 0, 2, 100, 70,
+ 7, 1, 0, 2, 100, 54, 8, 1, 0, 2, 100, 70,
+ 1, 1, 0, 2, 104, 76, 3, 1, 0, 2, 104, 76,
+ 4, 1, 0, 2, 104, 76, 5, 1, 0, 2, 104, 62,
+ 6, 1, 0, 2, 104, 76, 7, 1, 0, 2, 104, 54,
+ 8, 1, 0, 2, 104, 76, 1, 1, 0, 2, 108, 76,
+ 3, 1, 0, 2, 108, 76, 4, 1, 0, 2, 108, 76,
+ 5, 1, 0, 2, 108, 62, 6, 1, 0, 2, 108, 76,
+ 7, 1, 0, 2, 108, 54, 8, 1, 0, 2, 108, 76,
+ 1, 1, 0, 2, 112, 76, 3, 1, 0, 2, 112, 76,
+ 4, 1, 0, 2, 112, 76, 5, 1, 0, 2, 112, 62,
+ 6, 1, 0, 2, 112, 76, 7, 1, 0, 2, 112, 54,
+ 8, 1, 0, 2, 112, 76, 1, 1, 0, 2, 116, 76,
+ 3, 1, 0, 2, 116, 76, 4, 1, 0, 2, 116, 76,
+ 5, 1, 0, 2, 116, 62, 6, 1, 0, 2, 116, 76,
+ 7, 1, 0, 2, 116, 54, 8, 1, 0, 2, 116, 76,
+ 1, 1, 0, 2, 120, 76, 3, 1, 0, 2, 120, 127,
+ 4, 1, 0, 2, 120, 76, 5, 1, 0, 2, 120, 127,
+ 6, 1, 0, 2, 120, 76, 7, 1, 0, 2, 120, 54,
+ 8, 1, 0, 2, 120, 76, 1, 1, 0, 2, 124, 76,
+ 3, 1, 0, 2, 124, 127, 4, 1, 0, 2, 124, 76,
+ 5, 1, 0, 2, 124, 127, 6, 1, 0, 2, 124, 76,
+ 7, 1, 0, 2, 124, 54, 8, 1, 0, 2, 124, 76,
+ 1, 1, 0, 2, 128, 76, 3, 1, 0, 2, 128, 127,
+ 4, 1, 0, 2, 128, 76, 5, 1, 0, 2, 128, 127,
+ 6, 1, 0, 2, 128, 76, 7, 1, 0, 2, 128, 54,
+ 8, 1, 0, 2, 128, 76, 1, 1, 0, 2, 132, 76,
+ 3, 1, 0, 2, 132, 76, 4, 1, 0, 2, 132, 76,
+ 5, 1, 0, 2, 132, 62, 6, 1, 0, 2, 132, 76,
+ 7, 1, 0, 2, 132, 54, 8, 1, 0, 2, 132, 76,
+ 1, 1, 0, 2, 136, 76, 3, 1, 0, 2, 136, 76,
+ 4, 1, 0, 2, 136, 76, 5, 1, 0, 2, 136, 62,
+ 6, 1, 0, 2, 136, 76, 7, 1, 0, 2, 136, 127,
+ 8, 1, 0, 2, 136, 76, 1, 1, 0, 2, 140, 76,
+ 3, 1, 0, 2, 140, 70, 4, 1, 0, 2, 140, 76,
+ 5, 1, 0, 2, 140, 62, 6, 1, 0, 2, 140, 70,
+ 7, 1, 0, 2, 140, 127, 8, 1, 0, 2, 140, 70,
+ 1, 1, 0, 2, 144, 127, 3, 1, 0, 2, 144, 76,
+ 4, 1, 0, 2, 144, 76, 5, 1, 0, 2, 144, 127,
+ 6, 1, 0, 2, 144, 76, 7, 1, 0, 2, 144, 127,
+ 8, 1, 0, 2, 144, 76, 1, 1, 0, 2, 149, 127,
+ 3, 1, 0, 2, 149, 76, 4, 1, 0, 2, 149, 74,
+ 5, 1, 0, 2, 149, 76, 6, 1, 0, 2, 149, 76,
+ 7, 1, 0, 2, 149, 54, 8, 1, 0, 2, 149, 76,
+ 1, 1, 0, 2, 153, 127, 3, 1, 0, 2, 153, 76,
+ 4, 1, 0, 2, 153, 74, 5, 1, 0, 2, 153, 76,
+ 6, 1, 0, 2, 153, 76, 7, 1, 0, 2, 153, 54,
+ 8, 1, 0, 2, 153, 76, 1, 1, 0, 2, 157, 127,
+ 3, 1, 0, 2, 157, 76, 4, 1, 0, 2, 157, 74,
+ 5, 1, 0, 2, 157, 76, 6, 1, 0, 2, 157, 76,
+ 7, 1, 0, 2, 157, 54, 8, 1, 0, 2, 157, 76,
+ 1, 1, 0, 2, 161, 127, 3, 1, 0, 2, 161, 76,
+ 4, 1, 0, 2, 161, 74, 5, 1, 0, 2, 161, 76,
+ 6, 1, 0, 2, 161, 76, 7, 1, 0, 2, 161, 54,
+ 8, 1, 0, 2, 161, 76, 1, 1, 0, 2, 165, 127,
+ 3, 1, 0, 2, 165, 76, 4, 1, 0, 2, 165, 74,
+ 5, 1, 0, 2, 165, 76, 6, 1, 0, 2, 165, 76,
+ 7, 1, 0, 2, 165, 54, 8, 1, 0, 2, 165, 76,
+ 1, 1, 0, 3, 36, 50, 3, 1, 0, 3, 36, 38,
+ 4, 1, 0, 3, 36, 66, 5, 1, 0, 3, 36, 38,
+ 6, 1, 0, 3, 36, 52, 7, 1, 0, 3, 36, 30,
+ 8, 1, 0, 3, 36, 50, 1, 1, 0, 3, 40, 50,
+ 3, 1, 0, 3, 40, 38, 4, 1, 0, 3, 40, 66,
+ 5, 1, 0, 3, 40, 38, 6, 1, 0, 3, 40, 52,
+ 7, 1, 0, 3, 40, 30, 8, 1, 0, 3, 40, 50,
+ 1, 1, 0, 3, 44, 50, 3, 1, 0, 3, 44, 38,
+ 4, 1, 0, 3, 44, 66, 5, 1, 0, 3, 44, 38,
+ 6, 1, 0, 3, 44, 52, 7, 1, 0, 3, 44, 30,
+ 8, 1, 0, 3, 44, 50, 1, 1, 0, 3, 48, 50,
+ 3, 1, 0, 3, 48, 38, 4, 1, 0, 3, 48, 66,
+ 5, 1, 0, 3, 48, 38, 6, 1, 0, 3, 48, 52,
+ 7, 1, 0, 3, 48, 30, 8, 1, 0, 3, 48, 50,
+ 1, 1, 0, 3, 52, 50, 3, 1, 0, 3, 52, 40,
+ 4, 1, 0, 3, 52, 66, 5, 1, 0, 3, 52, 38,
+ 6, 1, 0, 3, 52, 68, 7, 1, 0, 3, 52, 30,
+ 8, 1, 0, 3, 52, 68, 1, 1, 0, 3, 56, 50,
+ 3, 1, 0, 3, 56, 40, 4, 1, 0, 3, 56, 66,
+ 5, 1, 0, 3, 56, 38, 6, 1, 0, 3, 56, 68,
+ 7, 1, 0, 3, 56, 30, 8, 1, 0, 3, 56, 68,
+ 1, 1, 0, 3, 60, 50, 3, 1, 0, 3, 60, 40,
+ 4, 1, 0, 3, 60, 66, 5, 1, 0, 3, 60, 38,
+ 6, 1, 0, 3, 60, 66, 7, 1, 0, 3, 60, 30,
+ 8, 1, 0, 3, 60, 66, 1, 1, 0, 3, 64, 50,
+ 3, 1, 0, 3, 64, 40, 4, 1, 0, 3, 64, 66,
+ 5, 1, 0, 3, 64, 38, 6, 1, 0, 3, 64, 68,
+ 7, 1, 0, 3, 64, 30, 8, 1, 0, 3, 64, 68,
+ 1, 1, 0, 3, 100, 70, 3, 1, 0, 3, 100, 60,
+ 4, 1, 0, 3, 100, 64, 5, 1, 0, 3, 100, 38,
+ 6, 1, 0, 3, 100, 60, 7, 1, 0, 3, 100, 30,
+ 8, 1, 0, 3, 100, 60, 1, 1, 0, 3, 104, 70,
+ 3, 1, 0, 3, 104, 68, 4, 1, 0, 3, 104, 64,
+ 5, 1, 0, 3, 104, 38, 6, 1, 0, 3, 104, 68,
+ 7, 1, 0, 3, 104, 30, 8, 1, 0, 3, 104, 68,
+ 1, 1, 0, 3, 108, 70, 3, 1, 0, 3, 108, 68,
+ 4, 1, 0, 3, 108, 64, 5, 1, 0, 3, 108, 38,
+ 6, 1, 0, 3, 108, 68, 7, 1, 0, 3, 108, 30,
+ 8, 1, 0, 3, 108, 68, 1, 1, 0, 3, 112, 70,
+ 3, 1, 0, 3, 112, 68, 4, 1, 0, 3, 112, 64,
+ 5, 1, 0, 3, 112, 38, 6, 1, 0, 3, 112, 68,
+ 7, 1, 0, 3, 112, 30, 8, 1, 0, 3, 112, 68,
+ 1, 1, 0, 3, 116, 70, 3, 1, 0, 3, 116, 68,
+ 4, 1, 0, 3, 116, 64, 5, 1, 0, 3, 116, 38,
+ 6, 1, 0, 3, 116, 68, 7, 1, 0, 3, 116, 30,
+ 8, 1, 0, 3, 116, 68, 1, 1, 0, 3, 120, 70,
+ 3, 1, 0, 3, 120, 127, 4, 1, 0, 3, 120, 64,
+ 5, 1, 0, 3, 120, 127, 6, 1, 0, 3, 120, 68,
+ 7, 1, 0, 3, 120, 30, 8, 1, 0, 3, 120, 68,
+ 1, 1, 0, 3, 124, 70, 3, 1, 0, 3, 124, 127,
+ 4, 1, 0, 3, 124, 64, 5, 1, 0, 3, 124, 127,
+ 6, 1, 0, 3, 124, 68, 7, 1, 0, 3, 124, 30,
+ 8, 1, 0, 3, 124, 68, 1, 1, 0, 3, 128, 70,
+ 3, 1, 0, 3, 128, 127, 4, 1, 0, 3, 128, 64,
+ 5, 1, 0, 3, 128, 127, 6, 1, 0, 3, 128, 68,
+ 7, 1, 0, 3, 128, 30, 8, 1, 0, 3, 128, 68,
+ 1, 1, 0, 3, 132, 70, 3, 1, 0, 3, 132, 68,
+ 4, 1, 0, 3, 132, 64, 5, 1, 0, 3, 132, 38,
+ 6, 1, 0, 3, 132, 68, 7, 1, 0, 3, 132, 30,
+ 8, 1, 0, 3, 132, 68, 1, 1, 0, 3, 136, 70,
+ 3, 1, 0, 3, 136, 68, 4, 1, 0, 3, 136, 64,
+ 5, 1, 0, 3, 136, 38, 6, 1, 0, 3, 136, 68,
+ 7, 1, 0, 3, 136, 127, 8, 1, 0, 3, 136, 68,
+ 1, 1, 0, 3, 140, 70, 3, 1, 0, 3, 140, 60,
+ 4, 1, 0, 3, 140, 64, 5, 1, 0, 3, 140, 38,
+ 6, 1, 0, 3, 140, 60, 7, 1, 0, 3, 140, 127,
+ 8, 1, 0, 3, 140, 60, 1, 1, 0, 3, 144, 127,
+ 3, 1, 0, 3, 144, 68, 4, 1, 0, 3, 144, 64,
+ 5, 1, 0, 3, 144, 127, 6, 1, 0, 3, 144, 68,
+ 7, 1, 0, 3, 144, 127, 8, 1, 0, 3, 144, 68,
+ 1, 1, 0, 3, 149, 127, 3, 1, 0, 3, 149, 76,
+ 4, 1, 0, 3, 149, 60, 5, 1, 0, 3, 149, 76,
+ 6, 1, 0, 3, 149, 76, 7, 1, 0, 3, 149, 30,
+ 8, 1, 0, 3, 149, 72, 1, 1, 0, 3, 153, 127,
+ 3, 1, 0, 3, 153, 76, 4, 1, 0, 3, 153, 60,
+ 5, 1, 0, 3, 153, 76, 6, 1, 0, 3, 153, 76,
+ 7, 1, 0, 3, 153, 30, 8, 1, 0, 3, 153, 76,
+ 1, 1, 0, 3, 157, 127, 3, 1, 0, 3, 157, 76,
+ 4, 1, 0, 3, 157, 60, 5, 1, 0, 3, 157, 76,
+ 6, 1, 0, 3, 157, 76, 7, 1, 0, 3, 157, 30,
+ 8, 1, 0, 3, 157, 76, 1, 1, 0, 3, 161, 127,
+ 3, 1, 0, 3, 161, 76, 4, 1, 0, 3, 161, 60,
+ 5, 1, 0, 3, 161, 76, 6, 1, 0, 3, 161, 76,
+ 7, 1, 0, 3, 161, 30, 8, 1, 0, 3, 161, 76,
+ 1, 1, 0, 3, 165, 127, 3, 1, 0, 3, 165, 76,
+ 4, 1, 0, 3, 165, 60, 5, 1, 0, 3, 165, 76,
+ 6, 1, 0, 3, 165, 76, 7, 1, 0, 3, 165, 30,
+ 8, 1, 0, 3, 165, 76, 1, 1, 1, 2, 38, 62,
+ 3, 1, 1, 2, 38, 64, 4, 1, 1, 2, 38, 72,
+ 5, 1, 1, 2, 38, 64, 6, 1, 1, 2, 38, 64,
+ 7, 1, 1, 2, 38, 54, 8, 1, 1, 2, 38, 62,
+ 1, 1, 1, 2, 46, 62, 3, 1, 1, 2, 46, 64,
+ 4, 1, 1, 2, 46, 72, 5, 1, 1, 2, 46, 64,
+ 6, 1, 1, 2, 46, 64, 7, 1, 1, 2, 46, 54,
+ 8, 1, 1, 2, 46, 62, 1, 1, 1, 2, 54, 62,
+ 3, 1, 1, 2, 54, 64, 4, 1, 1, 2, 54, 72,
+ 5, 1, 1, 2, 54, 64, 6, 1, 1, 2, 54, 72,
+ 7, 1, 1, 2, 54, 54, 8, 1, 1, 2, 54, 72,
+ 1, 1, 1, 2, 62, 62, 3, 1, 1, 2, 62, 64,
+ 4, 1, 1, 2, 62, 70, 5, 1, 1, 2, 62, 64,
+ 6, 1, 1, 2, 62, 64, 7, 1, 1, 2, 62, 54,
+ 8, 1, 1, 2, 62, 64, 1, 1, 1, 2, 102, 72,
+ 3, 1, 1, 2, 102, 58, 4, 1, 1, 2, 102, 72,
+ 5, 1, 1, 2, 102, 64, 6, 1, 1, 2, 102, 58,
+ 7, 1, 1, 2, 102, 54, 8, 1, 1, 2, 102, 58,
+ 1, 1, 1, 2, 110, 72, 3, 1, 1, 2, 110, 72,
+ 4, 1, 1, 2, 110, 72, 5, 1, 1, 2, 110, 64,
+ 6, 1, 1, 2, 110, 72, 7, 1, 1, 2, 110, 54,
+ 8, 1, 1, 2, 110, 72, 1, 1, 1, 2, 118, 72,
+ 3, 1, 1, 2, 118, 127, 4, 1, 1, 2, 118, 72,
+ 5, 1, 1, 2, 118, 127, 6, 1, 1, 2, 118, 72,
+ 7, 1, 1, 2, 118, 54, 8, 1, 1, 2, 118, 72,
+ 1, 1, 1, 2, 126, 72, 3, 1, 1, 2, 126, 127,
+ 4, 1, 1, 2, 126, 72, 5, 1, 1, 2, 126, 127,
+ 6, 1, 1, 2, 126, 72, 7, 1, 1, 2, 126, 54,
+ 8, 1, 1, 2, 126, 72, 1, 1, 1, 2, 134, 72,
+ 3, 1, 1, 2, 134, 72, 4, 1, 1, 2, 134, 72,
+ 5, 1, 1, 2, 134, 64, 6, 1, 1, 2, 134, 72,
+ 7, 1, 1, 2, 134, 127, 8, 1, 1, 2, 134, 72,
+ 1, 1, 1, 2, 142, 127, 3, 1, 1, 2, 142, 72,
+ 4, 1, 1, 2, 142, 72, 5, 1, 1, 2, 142, 127,
+ 6, 1, 1, 2, 142, 72, 7, 1, 1, 2, 142, 127,
+ 8, 1, 1, 2, 142, 72, 1, 1, 1, 2, 151, 127,
+ 3, 1, 1, 2, 151, 72, 4, 1, 1, 2, 151, 72,
+ 5, 1, 1, 2, 151, 72, 6, 1, 1, 2, 151, 72,
+ 7, 1, 1, 2, 151, 54, 8, 1, 1, 2, 151, 72,
+ 1, 1, 1, 2, 159, 127, 3, 1, 1, 2, 159, 72,
+ 4, 1, 1, 2, 159, 72, 5, 1, 1, 2, 159, 72,
+ 6, 1, 1, 2, 159, 72, 7, 1, 1, 2, 159, 54,
+ 8, 1, 1, 2, 159, 72, 1, 1, 1, 3, 38, 50,
+ 3, 1, 1, 3, 38, 40, 4, 1, 1, 3, 38, 62,
+ 5, 1, 1, 3, 38, 40, 6, 1, 1, 3, 38, 52,
+ 7, 1, 1, 3, 38, 30, 8, 1, 1, 3, 38, 50,
+ 1, 1, 1, 3, 46, 50, 3, 1, 1, 3, 46, 40,
+ 4, 1, 1, 3, 46, 62, 5, 1, 1, 3, 46, 40,
+ 6, 1, 1, 3, 46, 52, 7, 1, 1, 3, 46, 30,
+ 8, 1, 1, 3, 46, 50, 1, 1, 1, 3, 54, 50,
+ 3, 1, 1, 3, 54, 40, 4, 1, 1, 3, 54, 62,
+ 5, 1, 1, 3, 54, 40, 6, 1, 1, 3, 54, 68,
+ 7, 1, 1, 3, 54, 30, 8, 1, 1, 3, 54, 68,
+ 1, 1, 1, 3, 62, 48, 3, 1, 1, 3, 62, 40,
+ 4, 1, 1, 3, 62, 58, 5, 1, 1, 3, 62, 40,
+ 6, 1, 1, 3, 62, 58, 7, 1, 1, 3, 62, 30,
+ 8, 1, 1, 3, 62, 58, 1, 1, 1, 3, 102, 70,
+ 3, 1, 1, 3, 102, 54, 4, 1, 1, 3, 102, 64,
+ 5, 1, 1, 3, 102, 40, 6, 1, 1, 3, 102, 54,
+ 7, 1, 1, 3, 102, 30, 8, 1, 1, 3, 102, 54,
+ 1, 1, 1, 3, 110, 70, 3, 1, 1, 3, 110, 68,
+ 4, 1, 1, 3, 110, 64, 5, 1, 1, 3, 110, 40,
+ 6, 1, 1, 3, 110, 68, 7, 1, 1, 3, 110, 30,
+ 8, 1, 1, 3, 110, 68, 1, 1, 1, 3, 118, 70,
+ 3, 1, 1, 3, 118, 127, 4, 1, 1, 3, 118, 64,
+ 5, 1, 1, 3, 118, 127, 6, 1, 1, 3, 118, 68,
+ 7, 1, 1, 3, 118, 30, 8, 1, 1, 3, 118, 68,
+ 1, 1, 1, 3, 126, 70, 3, 1, 1, 3, 126, 127,
+ 4, 1, 1, 3, 126, 64, 5, 1, 1, 3, 126, 127,
+ 6, 1, 1, 3, 126, 68, 7, 1, 1, 3, 126, 30,
+ 8, 1, 1, 3, 126, 68, 1, 1, 1, 3, 134, 70,
+ 3, 1, 1, 3, 134, 68, 4, 1, 1, 3, 134, 64,
+ 5, 1, 1, 3, 134, 40, 6, 1, 1, 3, 134, 68,
+ 7, 1, 1, 3, 134, 127, 8, 1, 1, 3, 134, 68,
+ 1, 1, 1, 3, 142, 127, 3, 1, 1, 3, 142, 68,
+ 4, 1, 1, 3, 142, 64, 5, 1, 1, 3, 142, 127,
+ 6, 1, 1, 3, 142, 68, 7, 1, 1, 3, 142, 127,
+ 8, 1, 1, 3, 142, 68, 1, 1, 1, 3, 151, 127,
+ 3, 1, 1, 3, 151, 72, 4, 1, 1, 3, 151, 66,
+ 5, 1, 1, 3, 151, 72, 6, 1, 1, 3, 151, 72,
+ 7, 1, 1, 3, 151, 30, 8, 1, 1, 3, 151, 68,
+ 1, 1, 1, 3, 159, 127, 3, 1, 1, 3, 159, 72,
+ 4, 1, 1, 3, 159, 66, 5, 1, 1, 3, 159, 72,
+ 6, 1, 1, 3, 159, 72, 7, 1, 1, 3, 159, 30,
+ 8, 1, 1, 3, 159, 72, 1, 1, 2, 4, 42, 64,
+ 3, 1, 2, 4, 42, 64, 4, 1, 2, 4, 42, 68,
+ 5, 1, 2, 4, 42, 64, 6, 1, 2, 4, 42, 64,
+ 7, 1, 2, 4, 42, 54, 8, 1, 2, 4, 42, 62,
+ 1, 1, 2, 4, 58, 64, 3, 1, 2, 4, 58, 62,
+ 4, 1, 2, 4, 58, 64, 5, 1, 2, 4, 58, 64,
+ 6, 1, 2, 4, 58, 62, 7, 1, 2, 4, 58, 54,
+ 8, 1, 2, 4, 58, 62, 1, 1, 2, 4, 106, 72,
+ 3, 1, 2, 4, 106, 58, 4, 1, 2, 4, 106, 66,
+ 5, 1, 2, 4, 106, 64, 6, 1, 2, 4, 106, 58,
+ 7, 1, 2, 4, 106, 54, 8, 1, 2, 4, 106, 58,
+ 1, 1, 2, 4, 122, 72, 3, 1, 2, 4, 122, 127,
+ 4, 1, 2, 4, 122, 68, 5, 1, 2, 4, 122, 127,
+ 6, 1, 2, 4, 122, 72, 7, 1, 2, 4, 122, 54,
+ 8, 1, 2, 4, 122, 72, 1, 1, 2, 4, 138, 127,
+ 3, 1, 2, 4, 138, 72, 4, 1, 2, 4, 138, 68,
+ 5, 1, 2, 4, 138, 127, 6, 1, 2, 4, 138, 72,
+ 7, 1, 2, 4, 138, 127, 8, 1, 2, 4, 138, 72,
+ 1, 1, 2, 4, 155, 127, 3, 1, 2, 4, 155, 72,
+ 4, 1, 2, 4, 155, 68, 5, 1, 2, 4, 155, 72,
+ 6, 1, 2, 4, 155, 72, 7, 1, 2, 4, 155, 54,
+ 8, 1, 2, 4, 155, 68, 1, 1, 2, 5, 42, 50,
+ 3, 1, 2, 5, 42, 40, 4, 1, 2, 5, 42, 58,
+ 5, 1, 2, 5, 42, 40, 6, 1, 2, 5, 42, 52,
+ 7, 1, 2, 5, 42, 30, 8, 1, 2, 5, 42, 50,
+ 1, 1, 2, 5, 58, 50, 3, 1, 2, 5, 58, 40,
+ 4, 1, 2, 5, 58, 56, 5, 1, 2, 5, 58, 40,
+ 6, 1, 2, 5, 58, 52, 7, 1, 2, 5, 58, 30,
+ 8, 1, 2, 5, 58, 52, 1, 1, 2, 5, 106, 72,
+ 3, 1, 2, 5, 106, 50, 4, 1, 2, 5, 106, 56,
+ 5, 1, 2, 5, 106, 40, 6, 1, 2, 5, 106, 50,
+ 7, 1, 2, 5, 106, 30, 8, 1, 2, 5, 106, 50,
+ 1, 1, 2, 5, 122, 72, 3, 1, 2, 5, 122, 127,
+ 4, 1, 2, 5, 122, 56, 5, 1, 2, 5, 122, 127,
+ 6, 1, 2, 5, 122, 66, 7, 1, 2, 5, 122, 30,
+ 8, 1, 2, 5, 122, 66, 1, 1, 2, 5, 138, 127,
+ 3, 1, 2, 5, 138, 66, 4, 1, 2, 5, 138, 58,
+ 5, 1, 2, 5, 138, 127, 6, 1, 2, 5, 138, 66,
+ 7, 1, 2, 5, 138, 127, 8, 1, 2, 5, 138, 66,
+ 1, 1, 2, 5, 155, 127, 3, 1, 2, 5, 155, 62,
+ 4, 1, 2, 5, 155, 58, 5, 1, 2, 5, 155, 72,
+ 6, 1, 2, 5, 155, 62, 7, 1, 2, 5, 155, 30,
+ 8, 1, 2, 5, 155, 62
};
RTW_DECL_TABLE_TXPWR_LMT(rtw8822c_txpwr_lmt_type0);
diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c
index e32faf8bead9..8eaa9809ca44 100644
--- a/drivers/net/wireless/realtek/rtw88/tx.c
+++ b/drivers/net/wireless/realtek/rtw88/tx.c
@@ -362,6 +362,6 @@ void rtw_rsvd_page_pkt_info_update(struct rtw_dev *rtwdev,
pkt_info->bmc = bmc;
pkt_info->tx_pkt_size = skb->len;
pkt_info->offset = chip->tx_pkt_desc_sz;
- pkt_info->qsel = skb->priority;
+ pkt_info->qsel = TX_DESC_QSEL_MGMT;
pkt_info->ls = true;
}
diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c
index f9c67ed473d1..b42cd50b837e 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c
@@ -929,11 +929,15 @@ static int rsi_sdio_ta_reset(struct rsi_hw *adapter)
u32 addr;
u8 *data;
+ data = kzalloc(RSI_9116_REG_SIZE, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
status = rsi_sdio_master_access_msword(adapter, TA_BASE_ADDR);
if (status < 0) {
rsi_dbg(ERR_ZONE,
"Unable to set ms word to common reg\n");
- return status;
+ goto err;
}
rsi_dbg(INIT_ZONE, "%s: Bring TA out of reset\n", __func__);
@@ -944,7 +948,7 @@ static int rsi_sdio_ta_reset(struct rsi_hw *adapter)
RSI_9116_REG_SIZE);
if (status < 0) {
rsi_dbg(ERR_ZONE, "Unable to hold TA threads\n");
- return status;
+ goto err;
}
put_unaligned_le32(TA_SOFT_RST_CLR, data);
@@ -954,7 +958,7 @@ static int rsi_sdio_ta_reset(struct rsi_hw *adapter)
RSI_9116_REG_SIZE);
if (status < 0) {
rsi_dbg(ERR_ZONE, "Unable to get TA out of reset\n");
- return status;
+ goto err;
}
put_unaligned_le32(TA_PC_ZERO, data);
@@ -964,7 +968,8 @@ static int rsi_sdio_ta_reset(struct rsi_hw *adapter)
RSI_9116_REG_SIZE);
if (status < 0) {
rsi_dbg(ERR_ZONE, "Unable to Reset TA PC value\n");
- return -EINVAL;
+ status = -EINVAL;
+ goto err;
}
put_unaligned_le32(TA_RELEASE_THREAD_VALUE, data);
@@ -974,17 +979,19 @@ static int rsi_sdio_ta_reset(struct rsi_hw *adapter)
RSI_9116_REG_SIZE);
if (status < 0) {
rsi_dbg(ERR_ZONE, "Unable to release TA threads\n");
- return status;
+ goto err;
}
status = rsi_sdio_master_access_msword(adapter, MISC_CFG_BASE_ADDR);
if (status < 0) {
rsi_dbg(ERR_ZONE, "Unable to set ms word to common reg\n");
- return status;
+ goto err;
}
rsi_dbg(INIT_ZONE, "***** TA Reset done *****\n");
- return 0;
+err:
+ kfree(data);
+ return status;
}
static struct rsi_host_intf_ops sdio_host_intf_ops = {
diff --git a/drivers/net/wireless/st/cw1200/bh.c b/drivers/net/wireless/st/cw1200/bh.c
index 92d299aa257c..02efe8483cba 100644
--- a/drivers/net/wireless/st/cw1200/bh.c
+++ b/drivers/net/wireless/st/cw1200/bh.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Device handling thread implementation for mac80211 ST-Ericsson CW1200 drivers
*
@@ -8,10 +9,6 @@
* ST-Ericsson UMAC CW1200 driver, which is
* Copyright (c) 2010, ST-Ericsson
* Author: Ajitpal Singh <ajitpal.singh@stericsson.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/net/wireless/st/cw1200/bh.h b/drivers/net/wireless/st/cw1200/bh.h
index af6a4853728f..a4ff6fd7624f 100644
--- a/drivers/net/wireless/st/cw1200/bh.h
+++ b/drivers/net/wireless/st/cw1200/bh.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Device handling thread interface for mac80211 ST-Ericsson CW1200 drivers
*
* Copyright (c) 2010, ST-Ericsson
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
- *
- * 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.
*/
#ifndef CW1200_BH_H
diff --git a/drivers/net/wireless/st/cw1200/cw1200.h b/drivers/net/wireless/st/cw1200/cw1200.h
index 1ad7d3602520..48f808cdc1cb 100644
--- a/drivers/net/wireless/st/cw1200/cw1200.h
+++ b/drivers/net/wireless/st/cw1200/cw1200.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Common private data for ST-Ericsson CW1200 drivers
*
@@ -9,10 +10,6 @@
*
* Based on the islsm (softmac prism54) driver, which is:
* Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
- *
- * 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.
*/
#ifndef CW1200_H
diff --git a/drivers/net/wireless/st/cw1200/cw1200_sdio.c b/drivers/net/wireless/st/cw1200/cw1200_sdio.c
index 1037ec62659d..43e012073dbf 100644
--- a/drivers/net/wireless/st/cw1200/cw1200_sdio.c
+++ b/drivers/net/wireless/st/cw1200/cw1200_sdio.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Mac80211 SDIO driver for ST-Ericsson CW1200 device
*
* Copyright (c) 2010, ST-Ericsson
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/net/wireless/st/cw1200/cw1200_spi.c b/drivers/net/wireless/st/cw1200/cw1200_spi.c
index 412fb6e49aed..ef01caac629c 100644
--- a/drivers/net/wireless/st/cw1200/cw1200_spi.c
+++ b/drivers/net/wireless/st/cw1200/cw1200_spi.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Mac80211 SPI driver for ST-Ericsson CW1200 device
*
@@ -7,10 +8,6 @@
* Based on cw1200_sdio.c
* Copyright (c) 2010, ST-Ericsson
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/net/wireless/st/cw1200/debug.c b/drivers/net/wireless/st/cw1200/debug.c
index d94266d9d0b8..8686929c70df 100644
--- a/drivers/net/wireless/st/cw1200/debug.c
+++ b/drivers/net/wireless/st/cw1200/debug.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* mac80211 glue code for mac80211 ST-Ericsson CW1200 drivers
* DebugFS code
*
* Copyright (c) 2010, ST-Ericsson
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/net/wireless/st/cw1200/debug.h b/drivers/net/wireless/st/cw1200/debug.h
index b525aba53bfc..80bc1567533a 100644
--- a/drivers/net/wireless/st/cw1200/debug.h
+++ b/drivers/net/wireless/st/cw1200/debug.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* DebugFS code for ST-Ericsson CW1200 mac80211 driver
*
* Copyright (c) 2011, ST-Ericsson
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
- *
- * 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.
*/
#ifndef CW1200_DEBUG_H_INCLUDED
diff --git a/drivers/net/wireless/st/cw1200/fwio.c b/drivers/net/wireless/st/cw1200/fwio.c
index b7881232499c..6574e78e05ea 100644
--- a/drivers/net/wireless/st/cw1200/fwio.c
+++ b/drivers/net/wireless/st/cw1200/fwio.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Firmware I/O code for mac80211 ST-Ericsson CW1200 drivers
*
@@ -8,10 +9,6 @@
* ST-Ericsson UMAC CW1200 driver which is
* Copyright (c) 2010, ST-Ericsson
* Author: Ajitpal Singh <ajitpal.singh@stericsson.com>
- *
- * 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.
*/
#include <linux/vmalloc.h>
diff --git a/drivers/net/wireless/st/cw1200/fwio.h b/drivers/net/wireless/st/cw1200/fwio.h
index ea3099362cdf..c287160a492e 100644
--- a/drivers/net/wireless/st/cw1200/fwio.h
+++ b/drivers/net/wireless/st/cw1200/fwio.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Firmware API for mac80211 ST-Ericsson CW1200 drivers
*
@@ -8,10 +9,6 @@
* ST-Ericsson UMAC CW1200 driver which is
* Copyright (c) 2010, ST-Ericsson
* Author: Ajitpal Singh <ajitpal.singh@stericsson.com>
- *
- * 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.
*/
#ifndef FWIO_H_INCLUDED
diff --git a/drivers/net/wireless/st/cw1200/hwbus.h b/drivers/net/wireless/st/cw1200/hwbus.h
index 8b2fc831c3de..bc8802d37b7b 100644
--- a/drivers/net/wireless/st/cw1200/hwbus.h
+++ b/drivers/net/wireless/st/cw1200/hwbus.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Common hwbus abstraction layer interface for cw1200 wireless driver
*
* Copyright (c) 2010, ST-Ericsson
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
- *
- * 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.
*/
#ifndef CW1200_HWBUS_H
diff --git a/drivers/net/wireless/st/cw1200/hwio.c b/drivers/net/wireless/st/cw1200/hwio.c
index ff230b7aeedd..3ba462de8e91 100644
--- a/drivers/net/wireless/st/cw1200/hwio.c
+++ b/drivers/net/wireless/st/cw1200/hwio.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Low-level device IO routines for ST-Ericsson CW1200 drivers
*
@@ -8,10 +9,6 @@
* ST-Ericsson UMAC CW1200 driver, which is
* Copyright (c) 2010, ST-Ericsson
* Author: Ajitpal Singh <ajitpal.singh@lockless.no>
- *
- * 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.
*/
#include <linux/types.h>
diff --git a/drivers/net/wireless/st/cw1200/hwio.h b/drivers/net/wireless/st/cw1200/hwio.h
index ddf52669dc5b..d1e629a566c2 100644
--- a/drivers/net/wireless/st/cw1200/hwio.h
+++ b/drivers/net/wireless/st/cw1200/hwio.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Low-level API for mac80211 ST-Ericsson CW1200 drivers
*
@@ -8,10 +9,6 @@
* ST-Ericsson UMAC CW1200 driver which is
* Copyright (c) 2010, ST-Ericsson
* Author: Ajitpal Singh <ajitpal.singh@stericsson.com>
- *
- * 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.
*/
#ifndef CW1200_HWIO_H_INCLUDED
diff --git a/drivers/net/wireless/st/cw1200/main.c b/drivers/net/wireless/st/cw1200/main.c
index c1608f0bf6d0..f7fe56affbcd 100644
--- a/drivers/net/wireless/st/cw1200/main.c
+++ b/drivers/net/wireless/st/cw1200/main.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* mac80211 glue code for mac80211 ST-Ericsson CW1200 drivers
*
@@ -14,10 +15,6 @@
* Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
* - stlc45xx driver
* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/net/wireless/st/cw1200/pm.c b/drivers/net/wireless/st/cw1200/pm.c
index ded23df1ac1d..a20ab577a364 100644
--- a/drivers/net/wireless/st/cw1200/pm.c
+++ b/drivers/net/wireless/st/cw1200/pm.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Mac80211 power management API for ST-Ericsson CW1200 drivers
*
* Copyright (c) 2011, ST-Ericsson
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/net/wireless/st/cw1200/pm.h b/drivers/net/wireless/st/cw1200/pm.h
index 534548470ebc..f516eedfe03c 100644
--- a/drivers/net/wireless/st/cw1200/pm.h
+++ b/drivers/net/wireless/st/cw1200/pm.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Mac80211 power management interface for ST-Ericsson CW1200 mac80211 drivers
*
* Copyright (c) 2011, ST-Ericsson
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
- *
- * 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.
*/
#ifndef PM_H_INCLUDED
diff --git a/drivers/net/wireless/st/cw1200/queue.c b/drivers/net/wireless/st/cw1200/queue.c
index 7895efefa95d..14133eedb3b6 100644
--- a/drivers/net/wireless/st/cw1200/queue.c
+++ b/drivers/net/wireless/st/cw1200/queue.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* O(1) TX queue with built-in allocator for ST-Ericsson CW1200 drivers
*
* Copyright (c) 2010, ST-Ericsson
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
- *
- * 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.
*/
#include <net/mac80211.h>
diff --git a/drivers/net/wireless/st/cw1200/queue.h b/drivers/net/wireless/st/cw1200/queue.h
index 119f9c79c14e..96ac69ae97de 100644
--- a/drivers/net/wireless/st/cw1200/queue.h
+++ b/drivers/net/wireless/st/cw1200/queue.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* O(1) TX queue with built-in allocator for ST-Ericsson CW1200 drivers
*
* Copyright (c) 2010, ST-Ericsson
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
- *
- * 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.
*/
#ifndef CW1200_QUEUE_H_INCLUDED
diff --git a/drivers/net/wireless/st/cw1200/scan.c b/drivers/net/wireless/st/cw1200/scan.c
index 71e9b91cf15b..c46b044b7f7b 100644
--- a/drivers/net/wireless/st/cw1200/scan.c
+++ b/drivers/net/wireless/st/cw1200/scan.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Scan implementation for ST-Ericsson CW1200 mac80211 drivers
*
* Copyright (c) 2010, ST-Ericsson
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
- *
- * 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.
*/
#include <linux/sched.h>
diff --git a/drivers/net/wireless/st/cw1200/scan.h b/drivers/net/wireless/st/cw1200/scan.h
index cc75459e5784..139a9f84c9bf 100644
--- a/drivers/net/wireless/st/cw1200/scan.h
+++ b/drivers/net/wireless/st/cw1200/scan.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Scan interface for ST-Ericsson CW1200 mac80211 drivers
*
* Copyright (c) 2010, ST-Ericsson
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
- *
- * 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.
*/
#ifndef SCAN_H_INCLUDED
diff --git a/drivers/net/wireless/st/cw1200/sta.c b/drivers/net/wireless/st/cw1200/sta.c
index 8dae92a79fe1..236022d4ae2a 100644
--- a/drivers/net/wireless/st/cw1200/sta.c
+++ b/drivers/net/wireless/st/cw1200/sta.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Mac80211 STA API for ST-Ericsson CW1200 drivers
*
* Copyright (c) 2010, ST-Ericsson
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
- *
- * 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.
*/
#include <linux/vmalloc.h>
diff --git a/drivers/net/wireless/st/cw1200/sta.h b/drivers/net/wireless/st/cw1200/sta.h
index 719de34dcbfe..706dab8e73bf 100644
--- a/drivers/net/wireless/st/cw1200/sta.h
+++ b/drivers/net/wireless/st/cw1200/sta.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Mac80211 STA interface for ST-Ericsson CW1200 mac80211 drivers
*
* Copyright (c) 2010, ST-Ericsson
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
- *
- * 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.
*/
#ifndef STA_H_INCLUDED
diff --git a/drivers/net/wireless/st/cw1200/txrx.c b/drivers/net/wireless/st/cw1200/txrx.c
index 8c800ef23159..2dfcdb145944 100644
--- a/drivers/net/wireless/st/cw1200/txrx.c
+++ b/drivers/net/wireless/st/cw1200/txrx.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Datapath implementation for ST-Ericsson CW1200 mac80211 drivers
*
* Copyright (c) 2010, ST-Ericsson
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
- *
- * 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.
*/
#include <net/mac80211.h>
diff --git a/drivers/net/wireless/st/cw1200/txrx.h b/drivers/net/wireless/st/cw1200/txrx.h
index 492a4e14213b..8b87e07465c7 100644
--- a/drivers/net/wireless/st/cw1200/txrx.h
+++ b/drivers/net/wireless/st/cw1200/txrx.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Datapath interface for ST-Ericsson CW1200 mac80211 drivers
*
* Copyright (c) 2010, ST-Ericsson
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
- *
- * 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.
*/
#ifndef CW1200_TXRX_H
diff --git a/drivers/net/wireless/st/cw1200/wsm.c b/drivers/net/wireless/st/cw1200/wsm.c
index be4c22e0d902..c86f31dcc981 100644
--- a/drivers/net/wireless/st/cw1200/wsm.c
+++ b/drivers/net/wireless/st/cw1200/wsm.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* WSM host interface (HI) implementation for
* ST-Ericsson CW1200 mac80211 drivers.
*
* Copyright (c) 2010, ST-Ericsson
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
- *
- * 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.
*/
#include <linux/skbuff.h>
diff --git a/drivers/net/wireless/st/cw1200/wsm.h b/drivers/net/wireless/st/cw1200/wsm.h
index 48086e849515..ddea57f8c8ab 100644
--- a/drivers/net/wireless/st/cw1200/wsm.h
+++ b/drivers/net/wireless/st/cw1200/wsm.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* WSM host interface (HI) interface for ST-Ericsson CW1200 mac80211 drivers
*
@@ -7,10 +8,6 @@
* Based on CW1200 UMAC WSM API, which is
* Copyright (C) ST-Ericsson SA 2010
* Author: Stewart Mathers <stewart.mathers@stericsson.com>
- *
- * 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.
*/
#ifndef CW1200_WSM_H_INCLUDED
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index a5e0604d3009..0b3cf8477c6c 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -1847,44 +1847,6 @@ static const struct ieee80211_iface_limit wl18xx_iface_ap_limits[] = {
},
};
-static const struct ieee80211_iface_limit wl18xx_iface_ap_cl_limits[] = {
- {
- .max = 1,
- .types = BIT(NL80211_IFTYPE_STATION),
- },
- {
- .max = 1,
- .types = BIT(NL80211_IFTYPE_AP),
- },
- {
- .max = 1,
- .types = BIT(NL80211_IFTYPE_P2P_CLIENT),
- },
- {
- .max = 1,
- .types = BIT(NL80211_IFTYPE_P2P_DEVICE),
- },
-};
-
-static const struct ieee80211_iface_limit wl18xx_iface_ap_go_limits[] = {
- {
- .max = 1,
- .types = BIT(NL80211_IFTYPE_STATION),
- },
- {
- .max = 1,
- .types = BIT(NL80211_IFTYPE_AP),
- },
- {
- .max = 1,
- .types = BIT(NL80211_IFTYPE_P2P_GO),
- },
- {
- .max = 1,
- .types = BIT(NL80211_IFTYPE_P2P_DEVICE),
- },
-};
-
static const struct ieee80211_iface_combination
wl18xx_iface_combinations[] = {
{
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index c9a485ecee7b..b74dc8bc9755 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -483,7 +483,7 @@ static int wlcore_fw_status(struct wl1271 *wl, struct wl_fw_status *status)
}
/* update the host-chipset time offset */
- wl->time_offset = (ktime_get_boot_ns() >> 10) -
+ wl->time_offset = (ktime_get_boottime_ns() >> 10) -
(s64)(status->fw_localtime);
wl->fw_fast_lnk_map = status->link_fast_bitmap;
diff --git a/drivers/net/wireless/ti/wlcore/rx.c b/drivers/net/wireless/ti/wlcore/rx.c
index d96bb602fae6..307fab21050b 100644
--- a/drivers/net/wireless/ti/wlcore/rx.c
+++ b/drivers/net/wireless/ti/wlcore/rx.c
@@ -93,7 +93,7 @@ static void wl1271_rx_status(struct wl1271 *wl,
}
if (beacon || probe_rsp)
- status->boottime_ns = ktime_get_boot_ns();
+ status->boottime_ns = ktime_get_boottime_ns();
if (beacon)
wlcore_set_pending_regdomain_ch(wl, (u16)desc->channel,
diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c
index 057c6be330e7..90e56d4c3df3 100644
--- a/drivers/net/wireless/ti/wlcore/tx.c
+++ b/drivers/net/wireless/ti/wlcore/tx.c
@@ -273,7 +273,7 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
}
/* configure packet life time */
- hosttime = (ktime_get_boot_ns() >> 10);
+ hosttime = (ktime_get_boottime_ns() >> 10);
desc->start_time = cpu_to_le32(hosttime - wl->time_offset);
is_dummy = wl12xx_is_dummy_packet(wl, skb);
diff --git a/drivers/net/wireless/ti/wlcore/vendor_cmd.c b/drivers/net/wireless/ti/wlcore/vendor_cmd.c
index 75756fb8e7b0..5cf0b32c413b 100644
--- a/drivers/net/wireless/ti/wlcore/vendor_cmd.c
+++ b/drivers/net/wireless/ti/wlcore/vendor_cmd.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* This file is part of wlcore
*
* Copyright (C) 2014 Texas Instruments. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
*/
#include <linux/pm_runtime.h>
diff --git a/drivers/net/wireless/ti/wlcore/vendor_cmd.h b/drivers/net/wireless/ti/wlcore/vendor_cmd.h
index 6e0c15e30f03..ebe815ea0316 100644
--- a/drivers/net/wireless/ti/wlcore/vendor_cmd.h
+++ b/drivers/net/wireless/ti/wlcore/vendor_cmd.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* This file is part of wlcore
*
* Copyright (C) 2014 Texas Instruments. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
*/
#ifndef __WLCORE_VENDOR_H__
diff --git a/drivers/net/wireless/virt_wifi.c b/drivers/net/wireless/virt_wifi.c
index 606999f102eb..be92e1220284 100644
--- a/drivers/net/wireless/virt_wifi.c
+++ b/drivers/net/wireless/virt_wifi.c
@@ -172,7 +172,7 @@ static void virt_wifi_scan_result(struct work_struct *work)
informed_bss = cfg80211_inform_bss(wiphy, &channel_5ghz,
CFG80211_BSS_FTYPE_PRESP,
fake_router_bssid,
- ktime_get_boot_ns(),
+ ktime_get_boottime_ns(),
WLAN_CAPABILITY_ESS, 0,
(void *)&ssid, sizeof(ssid),
DBM_TO_MBM(-50), GFP_KERNEL);
diff --git a/drivers/net/wireless/zydas/zd1201.c b/drivers/net/wireless/zydas/zd1201.c
index 22c70f1f568c..0db7362bedb4 100644
--- a/drivers/net/wireless/zydas/zd1201.c
+++ b/drivers/net/wireless/zydas/zd1201.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for ZyDAS zd1201 based wireless USB devices.
*
* Copyright (c) 2004, 2005 Jeroen Vreeken (pe1rxq@amsat.org)
*
- * 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.
- *
* Parts of this driver have been derived from a wlan-ng version
* modified by ZyDAS. They also made documentation available, thanks!
* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
diff --git a/drivers/net/wireless/zydas/zd1201.h b/drivers/net/wireless/zydas/zd1201.h
index dd7ea1f35bef..c46ac87550d1 100644
--- a/drivers/net/wireless/zydas/zd1201.h
+++ b/drivers/net/wireless/zydas/zd1201.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2004, 2005 Jeroen Vreeken (pe1rxq@amsat.org)
*
- * 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.
- *
* Parts of this driver have been derived from a wlan-ng version
* modified by ZyDAS.
* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
index 783198844dd7..240f762b3749 100644
--- a/drivers/net/xen-netback/interface.c
+++ b/drivers/net/xen-netback/interface.c
@@ -633,7 +633,7 @@ int xenvif_connect_data(struct xenvif_queue *queue,
unsigned int rx_evtchn)
{
struct task_struct *task;
- int err = -ENOMEM;
+ int err;
BUG_ON(queue->tx_irq);
BUG_ON(queue->task);
diff --git a/drivers/nfc/st-nci/i2c.c b/drivers/nfc/st-nci/i2c.c
index 67a685adfd44..55d600cd3861 100644
--- a/drivers/nfc/st-nci/i2c.c
+++ b/drivers/nfc/st-nci/i2c.c
@@ -72,7 +72,7 @@ static void st_nci_i2c_disable(void *phy_id)
*/
static int st_nci_i2c_write(void *phy_id, struct sk_buff *skb)
{
- int r = -1;
+ int r;
struct st_nci_i2c_phy *phy = phy_id;
struct i2c_client *client = phy->i2c_dev;
diff --git a/drivers/nvdimm/Kconfig b/drivers/nvdimm/Kconfig
index 54500798f23a..a5fde15e91d3 100644
--- a/drivers/nvdimm/Kconfig
+++ b/drivers/nvdimm/Kconfig
@@ -33,7 +33,7 @@ config BLK_DEV_PMEM
Documentation/admin-guide/kernel-parameters.rst). This driver converts
these persistent memory ranges into block devices that are
capable of DAX (direct-access) file system mappings. See
- Documentation/nvdimm/nvdimm.txt for more details.
+ Documentation/driver-api/nvdimm/nvdimm.rst for more details.
Say Y if you want to use an NVDIMM
diff --git a/drivers/nvdimm/Makefile b/drivers/nvdimm/Makefile
index 6f2a088afad6..cefe233e0b52 100644
--- a/drivers/nvdimm/Makefile
+++ b/drivers/nvdimm/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_ND_BTT) += nd_btt.o
obj-$(CONFIG_ND_BLK) += nd_blk.o
obj-$(CONFIG_X86_PMEM_LEGACY) += nd_e820.o
obj-$(CONFIG_OF_PMEM) += of_pmem.o
+obj-$(CONFIG_VIRTIO_PMEM) += virtio_pmem.o nd_virtio.o
nd_pmem-y := pmem.o
diff --git a/drivers/nvdimm/claim.c b/drivers/nvdimm/claim.c
index 26c1c7618891..2985ca949912 100644
--- a/drivers/nvdimm/claim.c
+++ b/drivers/nvdimm/claim.c
@@ -255,7 +255,7 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns,
struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
unsigned int sz_align = ALIGN(size + (offset & (512 - 1)), 512);
sector_t sector = offset >> 9;
- int rc = 0;
+ int rc = 0, ret = 0;
if (unlikely(!size))
return 0;
@@ -293,7 +293,9 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns,
}
memcpy_flushcache(nsio->addr + offset, buf, size);
- nvdimm_flush(to_nd_region(ndns->dev.parent));
+ ret = nvdimm_flush(to_nd_region(ndns->dev.parent), NULL);
+ if (ret)
+ rc = ret;
return rc;
}
diff --git a/drivers/nvdimm/dax_devs.c b/drivers/nvdimm/dax_devs.c
index 49fc18ee0565..6d22b0f83b3b 100644
--- a/drivers/nvdimm/dax_devs.c
+++ b/drivers/nvdimm/dax_devs.c
@@ -118,7 +118,7 @@ int nd_dax_probe(struct device *dev, struct nd_namespace_common *ndns)
nvdimm_bus_unlock(&ndns->dev);
if (!dax_dev)
return -ENOMEM;
- pfn_sb = devm_kzalloc(dev, sizeof(*pfn_sb), GFP_KERNEL);
+ pfn_sb = devm_kmalloc(dev, sizeof(*pfn_sb), GFP_KERNEL);
nd_pfn->pfn_sb = pfn_sb;
rc = nd_pfn_validate(nd_pfn, DAX_SIG);
dev_dbg(dev, "dax: %s\n", rc == 0 ? dev_name(dax_dev) : "<none>");
diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c
index a434a5964cb9..2d8d7e554877 100644
--- a/drivers/nvdimm/namespace_devs.c
+++ b/drivers/nvdimm/namespace_devs.c
@@ -1822,8 +1822,8 @@ static bool has_uuid_at_pos(struct nd_region *nd_region, u8 *uuid,
&& !guid_equal(&nd_set->type_guid,
&nd_label->type_guid)) {
dev_dbg(ndd->dev, "expect type_guid %pUb got %pUb\n",
- nd_set->type_guid.b,
- nd_label->type_guid.b);
+ &nd_set->type_guid,
+ &nd_label->type_guid);
continue;
}
@@ -2227,8 +2227,8 @@ static struct device *create_namespace_blk(struct nd_region *nd_region,
if (namespace_label_has(ndd, type_guid)) {
if (!guid_equal(&nd_set->type_guid, &nd_label->type_guid)) {
dev_dbg(ndd->dev, "expect type_guid %pUb got %pUb\n",
- nd_set->type_guid.b,
- nd_label->type_guid.b);
+ &nd_set->type_guid,
+ &nd_label->type_guid);
return ERR_PTR(-EAGAIN);
}
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index d24304c0e6d7..1b9955651379 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -155,6 +155,7 @@ struct nd_region {
struct badblocks bb;
struct nd_interleave_set *nd_set;
struct nd_percpu_lane __percpu *lane;
+ int (*flush)(struct nd_region *nd_region, struct bio *bio);
struct nd_mapping mapping[0];
};
diff --git a/drivers/nvdimm/nd_virtio.c b/drivers/nvdimm/nd_virtio.c
new file mode 100644
index 000000000000..10351d5b49fa
--- /dev/null
+++ b/drivers/nvdimm/nd_virtio.c
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * virtio_pmem.c: Virtio pmem Driver
+ *
+ * Discovers persistent memory range information
+ * from host and provides a virtio based flushing
+ * interface.
+ */
+#include "virtio_pmem.h"
+#include "nd.h"
+
+ /* The interrupt handler */
+void virtio_pmem_host_ack(struct virtqueue *vq)
+{
+ struct virtio_pmem *vpmem = vq->vdev->priv;
+ struct virtio_pmem_request *req_data, *req_buf;
+ unsigned long flags;
+ unsigned int len;
+
+ spin_lock_irqsave(&vpmem->pmem_lock, flags);
+ while ((req_data = virtqueue_get_buf(vq, &len)) != NULL) {
+ req_data->done = true;
+ wake_up(&req_data->host_acked);
+
+ if (!list_empty(&vpmem->req_list)) {
+ req_buf = list_first_entry(&vpmem->req_list,
+ struct virtio_pmem_request, list);
+ req_buf->wq_buf_avail = true;
+ wake_up(&req_buf->wq_buf);
+ list_del(&req_buf->list);
+ }
+ }
+ spin_unlock_irqrestore(&vpmem->pmem_lock, flags);
+}
+EXPORT_SYMBOL_GPL(virtio_pmem_host_ack);
+
+ /* The request submission function */
+static int virtio_pmem_flush(struct nd_region *nd_region)
+{
+ struct virtio_device *vdev = nd_region->provider_data;
+ struct virtio_pmem *vpmem = vdev->priv;
+ struct virtio_pmem_request *req_data;
+ struct scatterlist *sgs[2], sg, ret;
+ unsigned long flags;
+ int err, err1;
+
+ might_sleep();
+ req_data = kmalloc(sizeof(*req_data), GFP_KERNEL);
+ if (!req_data)
+ return -ENOMEM;
+
+ req_data->done = false;
+ init_waitqueue_head(&req_data->host_acked);
+ init_waitqueue_head(&req_data->wq_buf);
+ INIT_LIST_HEAD(&req_data->list);
+ req_data->req.type = cpu_to_le32(VIRTIO_PMEM_REQ_TYPE_FLUSH);
+ sg_init_one(&sg, &req_data->req, sizeof(req_data->req));
+ sgs[0] = &sg;
+ sg_init_one(&ret, &req_data->resp.ret, sizeof(req_data->resp));
+ sgs[1] = &ret;
+
+ spin_lock_irqsave(&vpmem->pmem_lock, flags);
+ /*
+ * If virtqueue_add_sgs returns -ENOSPC then req_vq virtual
+ * queue does not have free descriptor. We add the request
+ * to req_list and wait for host_ack to wake us up when free
+ * slots are available.
+ */
+ while ((err = virtqueue_add_sgs(vpmem->req_vq, sgs, 1, 1, req_data,
+ GFP_ATOMIC)) == -ENOSPC) {
+
+ dev_info(&vdev->dev, "failed to send command to virtio pmem device, no free slots in the virtqueue\n");
+ req_data->wq_buf_avail = false;
+ list_add_tail(&req_data->list, &vpmem->req_list);
+ spin_unlock_irqrestore(&vpmem->pmem_lock, flags);
+
+ /* A host response results in "host_ack" getting called */
+ wait_event(req_data->wq_buf, req_data->wq_buf_avail);
+ spin_lock_irqsave(&vpmem->pmem_lock, flags);
+ }
+ err1 = virtqueue_kick(vpmem->req_vq);
+ spin_unlock_irqrestore(&vpmem->pmem_lock, flags);
+ /*
+ * virtqueue_add_sgs failed with error different than -ENOSPC, we can't
+ * do anything about that.
+ */
+ if (err || !err1) {
+ dev_info(&vdev->dev, "failed to send command to virtio pmem device\n");
+ err = -EIO;
+ } else {
+ /* A host repsonse results in "host_ack" getting called */
+ wait_event(req_data->host_acked, req_data->done);
+ err = le32_to_cpu(req_data->resp.ret);
+ }
+
+ kfree(req_data);
+ return err;
+};
+
+/* The asynchronous flush callback function */
+int async_pmem_flush(struct nd_region *nd_region, struct bio *bio)
+{
+ /*
+ * Create child bio for asynchronous flush and chain with
+ * parent bio. Otherwise directly call nd_region flush.
+ */
+ if (bio && bio->bi_iter.bi_sector != -1) {
+ struct bio *child = bio_alloc(GFP_ATOMIC, 0);
+
+ if (!child)
+ return -ENOMEM;
+ bio_copy_dev(child, bio);
+ child->bi_opf = REQ_PREFLUSH;
+ child->bi_iter.bi_sector = -1;
+ bio_chain(child, bio);
+ submit_bio(child);
+ return 0;
+ }
+ if (virtio_pmem_flush(nd_region))
+ return -EIO;
+
+ return 0;
+};
+EXPORT_SYMBOL_GPL(async_pmem_flush);
+MODULE_LICENSE("GPL");
diff --git a/drivers/nvdimm/pfn.h b/drivers/nvdimm/pfn.h
index f58b849e455b..7381673b7b70 100644
--- a/drivers/nvdimm/pfn.h
+++ b/drivers/nvdimm/pfn.h
@@ -28,22 +28,9 @@ struct nd_pfn_sb {
__le32 end_trunc;
/* minor-version-2 record the base alignment of the mapping */
__le32 align;
+ /* minor-version-3 guarantee the padding and flags are zero */
u8 padding[4000];
__le64 checksum;
};
-#ifdef CONFIG_SPARSEMEM
-#define PFN_SECTION_ALIGN_DOWN(x) SECTION_ALIGN_DOWN(x)
-#define PFN_SECTION_ALIGN_UP(x) SECTION_ALIGN_UP(x)
-#else
-/*
- * In this case ZONE_DEVICE=n and we will disable 'pfn' device support,
- * but we still want pmem to compile.
- */
-#define PFN_SECTION_ALIGN_DOWN(x) (x)
-#define PFN_SECTION_ALIGN_UP(x) (x)
-#endif
-
-#define PHYS_SECTION_ALIGN_DOWN(x) PFN_PHYS(PFN_SECTION_ALIGN_DOWN(PHYS_PFN(x)))
-#define PHYS_SECTION_ALIGN_UP(x) PFN_PHYS(PFN_SECTION_ALIGN_UP(PHYS_PFN(x)))
#endif /* __NVDIMM_PFN_H */
diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c
index 0f81fc56bbfd..df2bdbd22450 100644
--- a/drivers/nvdimm/pfn_devs.c
+++ b/drivers/nvdimm/pfn_devs.c
@@ -412,6 +412,15 @@ static int nd_pfn_clear_memmap_errors(struct nd_pfn *nd_pfn)
return 0;
}
+/**
+ * nd_pfn_validate - read and validate info-block
+ * @nd_pfn: fsdax namespace runtime state / properties
+ * @sig: 'devdax' or 'fsdax' signature
+ *
+ * Upon return the info-block buffer contents (->pfn_sb) are
+ * indeterminate when validation fails, and a coherent info-block
+ * otherwise.
+ */
int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig)
{
u64 checksum, offset;
@@ -557,7 +566,7 @@ int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns)
nvdimm_bus_unlock(&ndns->dev);
if (!pfn_dev)
return -ENOMEM;
- pfn_sb = devm_kzalloc(dev, sizeof(*pfn_sb), GFP_KERNEL);
+ pfn_sb = devm_kmalloc(dev, sizeof(*pfn_sb), GFP_KERNEL);
nd_pfn = to_nd_pfn(pfn_dev);
nd_pfn->pfn_sb = pfn_sb;
rc = nd_pfn_validate(nd_pfn, PFN_SIG);
@@ -578,14 +587,14 @@ static u32 info_block_reserve(void)
}
/*
- * We hotplug memory at section granularity, pad the reserved area from
- * the previous section base to the namespace base address.
+ * We hotplug memory at sub-section granularity, pad the reserved area
+ * from the previous section base to the namespace base address.
*/
static unsigned long init_altmap_base(resource_size_t base)
{
unsigned long base_pfn = PHYS_PFN(base);
- return PFN_SECTION_ALIGN_DOWN(base_pfn);
+ return SUBSECTION_ALIGN_DOWN(base_pfn);
}
static unsigned long init_altmap_reserve(resource_size_t base)
@@ -593,7 +602,7 @@ static unsigned long init_altmap_reserve(resource_size_t base)
unsigned long reserve = info_block_reserve() >> PAGE_SHIFT;
unsigned long base_pfn = PHYS_PFN(base);
- reserve += base_pfn - PFN_SECTION_ALIGN_DOWN(base_pfn);
+ reserve += base_pfn - SUBSECTION_ALIGN_DOWN(base_pfn);
return reserve;
}
@@ -622,10 +631,8 @@ static int __nvdimm_setup_pfn(struct nd_pfn *nd_pfn, struct dev_pagemap *pgmap)
if (offset < reserve)
return -EINVAL;
nd_pfn->npfns = le64_to_cpu(pfn_sb->npfns);
- pgmap->altmap_valid = false;
} else if (nd_pfn->mode == PFN_MODE_PMEM) {
- nd_pfn->npfns = PFN_SECTION_ALIGN_UP((resource_size(res)
- - offset) / PAGE_SIZE);
+ nd_pfn->npfns = PHYS_PFN((resource_size(res) - offset));
if (le64_to_cpu(nd_pfn->pfn_sb->npfns) > nd_pfn->npfns)
dev_info(&nd_pfn->dev,
"number of pfns truncated from %lld to %ld\n",
@@ -634,67 +641,27 @@ static int __nvdimm_setup_pfn(struct nd_pfn *nd_pfn, struct dev_pagemap *pgmap)
memcpy(altmap, &__altmap, sizeof(*altmap));
altmap->free = PHYS_PFN(offset - reserve);
altmap->alloc = 0;
- pgmap->altmap_valid = true;
+ pgmap->flags |= PGMAP_ALTMAP_VALID;
} else
return -ENXIO;
return 0;
}
-static u64 phys_pmem_align_down(struct nd_pfn *nd_pfn, u64 phys)
-{
- return min_t(u64, PHYS_SECTION_ALIGN_DOWN(phys),
- ALIGN_DOWN(phys, nd_pfn->align));
-}
-
-/*
- * Check if pmem collides with 'System RAM', or other regions when
- * section aligned. Trim it accordingly.
- */
-static void trim_pfn_device(struct nd_pfn *nd_pfn, u32 *start_pad, u32 *end_trunc)
-{
- struct nd_namespace_common *ndns = nd_pfn->ndns;
- struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
- struct nd_region *nd_region = to_nd_region(nd_pfn->dev.parent);
- const resource_size_t start = nsio->res.start;
- const resource_size_t end = start + resource_size(&nsio->res);
- resource_size_t adjust, size;
-
- *start_pad = 0;
- *end_trunc = 0;
-
- adjust = start - PHYS_SECTION_ALIGN_DOWN(start);
- size = resource_size(&nsio->res) + adjust;
- if (region_intersects(start - adjust, size, IORESOURCE_SYSTEM_RAM,
- IORES_DESC_NONE) == REGION_MIXED
- || nd_region_conflict(nd_region, start - adjust, size))
- *start_pad = PHYS_SECTION_ALIGN_UP(start) - start;
-
- /* Now check that end of the range does not collide. */
- adjust = PHYS_SECTION_ALIGN_UP(end) - end;
- size = resource_size(&nsio->res) + adjust;
- if (region_intersects(start, size, IORESOURCE_SYSTEM_RAM,
- IORES_DESC_NONE) == REGION_MIXED
- || !IS_ALIGNED(end, nd_pfn->align)
- || nd_region_conflict(nd_region, start, size))
- *end_trunc = end - phys_pmem_align_down(nd_pfn, end);
-}
-
static int nd_pfn_init(struct nd_pfn *nd_pfn)
{
struct nd_namespace_common *ndns = nd_pfn->ndns;
struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
- u32 start_pad, end_trunc, reserve = info_block_reserve();
resource_size_t start, size;
struct nd_region *nd_region;
+ unsigned long npfns, align;
struct nd_pfn_sb *pfn_sb;
- unsigned long npfns;
phys_addr_t offset;
const char *sig;
u64 checksum;
int rc;
- pfn_sb = devm_kzalloc(&nd_pfn->dev, sizeof(*pfn_sb), GFP_KERNEL);
+ pfn_sb = devm_kmalloc(&nd_pfn->dev, sizeof(*pfn_sb), GFP_KERNEL);
if (!pfn_sb)
return -ENOMEM;
@@ -703,11 +670,14 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
sig = DAX_SIG;
else
sig = PFN_SIG;
+
rc = nd_pfn_validate(nd_pfn, sig);
if (rc != -ENODEV)
return rc;
/* no info block, do init */;
+ memset(pfn_sb, 0, sizeof(*pfn_sb));
+
nd_region = to_nd_region(nd_pfn->dev.parent);
if (nd_region->ro) {
dev_info(&nd_pfn->dev,
@@ -716,43 +686,35 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
return -ENXIO;
}
- memset(pfn_sb, 0, sizeof(*pfn_sb));
-
- trim_pfn_device(nd_pfn, &start_pad, &end_trunc);
- if (start_pad + end_trunc)
- dev_info(&nd_pfn->dev, "%s alignment collision, truncate %d bytes\n",
- dev_name(&ndns->dev), start_pad + end_trunc);
-
/*
* Note, we use 64 here for the standard size of struct page,
* debugging options may cause it to be larger in which case the
* implementation will limit the pfns advertised through
* ->direct_access() to those that are included in the memmap.
*/
- start = nsio->res.start + start_pad;
+ start = nsio->res.start;
size = resource_size(&nsio->res);
- npfns = PFN_SECTION_ALIGN_UP((size - start_pad - end_trunc - reserve)
- / PAGE_SIZE);
+ npfns = PHYS_PFN(size - SZ_8K);
+ align = max(nd_pfn->align, (1UL << SUBSECTION_SHIFT));
if (nd_pfn->mode == PFN_MODE_PMEM) {
/*
* The altmap should be padded out to the block size used
* when populating the vmemmap. This *should* be equal to
* PMD_SIZE for most architectures.
*/
- offset = ALIGN(start + reserve + 64 * npfns,
- max(nd_pfn->align, PMD_SIZE)) - start;
+ offset = ALIGN(start + SZ_8K + 64 * npfns, align) - start;
} else if (nd_pfn->mode == PFN_MODE_RAM)
- offset = ALIGN(start + reserve, nd_pfn->align) - start;
+ offset = ALIGN(start + SZ_8K, align) - start;
else
return -ENXIO;
- if (offset + start_pad + end_trunc >= size) {
+ if (offset >= size) {
dev_err(&nd_pfn->dev, "%s unable to satisfy requested alignment\n",
dev_name(&ndns->dev));
return -ENXIO;
}
- npfns = (size - offset - start_pad - end_trunc) / SZ_4K;
+ npfns = PHYS_PFN(size - offset);
pfn_sb->mode = cpu_to_le32(nd_pfn->mode);
pfn_sb->dataoff = cpu_to_le64(offset);
pfn_sb->npfns = cpu_to_le64(npfns);
@@ -760,9 +722,7 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
memcpy(pfn_sb->uuid, nd_pfn->uuid, 16);
memcpy(pfn_sb->parent_uuid, nd_dev_to_uuid(&ndns->dev), 16);
pfn_sb->version_major = cpu_to_le16(1);
- pfn_sb->version_minor = cpu_to_le16(2);
- pfn_sb->start_pad = cpu_to_le32(start_pad);
- pfn_sb->end_trunc = cpu_to_le32(end_trunc);
+ pfn_sb->version_minor = cpu_to_le16(3);
pfn_sb->align = cpu_to_le32(nd_pfn->align);
checksum = nd_sb_checksum((struct nd_gen_sb *) pfn_sb);
pfn_sb->checksum = cpu_to_le64(checksum);
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index 24d7fe7c74ed..2bf3acd69613 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -184,6 +184,7 @@ static blk_status_t pmem_do_bvec(struct pmem_device *pmem, struct page *page,
static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
{
+ int ret = 0;
blk_status_t rc = 0;
bool do_acct;
unsigned long start;
@@ -193,7 +194,7 @@ static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
struct nd_region *nd_region = to_region(pmem);
if (bio->bi_opf & REQ_PREFLUSH)
- nvdimm_flush(nd_region);
+ ret = nvdimm_flush(nd_region, bio);
do_acct = nd_iostat_start(bio, &start);
bio_for_each_segment(bvec, bio, iter) {
@@ -208,7 +209,10 @@ static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
nd_iostat_end(bio, start);
if (bio->bi_opf & REQ_FUA)
- nvdimm_flush(nd_region);
+ ret = nvdimm_flush(nd_region, bio);
+
+ if (ret)
+ bio->bi_status = errno_to_blk_status(ret);
bio_endio(bio);
return BLK_QC_T_NONE;
@@ -303,24 +307,24 @@ static const struct attribute_group *pmem_attribute_groups[] = {
NULL,
};
-static void __pmem_release_queue(struct percpu_ref *ref)
+static void pmem_pagemap_cleanup(struct dev_pagemap *pgmap)
{
- struct request_queue *q;
+ struct request_queue *q =
+ container_of(pgmap->ref, struct request_queue, q_usage_counter);
- q = container_of(ref, typeof(*q), q_usage_counter);
blk_cleanup_queue(q);
}
-static void pmem_release_queue(void *ref)
+static void pmem_release_queue(void *pgmap)
{
- __pmem_release_queue(ref);
+ pmem_pagemap_cleanup(pgmap);
}
-static void pmem_freeze_queue(struct percpu_ref *ref)
+static void pmem_pagemap_kill(struct dev_pagemap *pgmap)
{
- struct request_queue *q;
+ struct request_queue *q =
+ container_of(pgmap->ref, struct request_queue, q_usage_counter);
- q = container_of(ref, typeof(*q), q_usage_counter);
blk_freeze_queue_start(q);
}
@@ -334,26 +338,16 @@ static void pmem_release_disk(void *__pmem)
put_disk(pmem->disk);
}
-static void pmem_release_pgmap_ops(void *__pgmap)
-{
- dev_pagemap_put_ops();
-}
-
-static void fsdax_pagefree(struct page *page, void *data)
+static void pmem_pagemap_page_free(struct page *page)
{
wake_up_var(&page->_refcount);
}
-static int setup_pagemap_fsdax(struct device *dev, struct dev_pagemap *pgmap)
-{
- dev_pagemap_get_ops();
- if (devm_add_action_or_reset(dev, pmem_release_pgmap_ops, pgmap))
- return -ENOMEM;
- pgmap->type = MEMORY_DEVICE_FS_DAX;
- pgmap->page_free = fsdax_pagefree;
-
- return 0;
-}
+static const struct dev_pagemap_ops fsdax_pagemap_ops = {
+ .page_free = pmem_pagemap_page_free,
+ .kill = pmem_pagemap_kill,
+ .cleanup = pmem_pagemap_cleanup,
+};
static int pmem_attach_disk(struct device *dev,
struct nd_namespace_common *ndns)
@@ -372,6 +366,7 @@ static int pmem_attach_disk(struct device *dev,
struct gendisk *disk;
void *addr;
int rc;
+ unsigned long flags = 0UL;
pmem = devm_kzalloc(dev, sizeof(*pmem), GFP_KERNEL);
if (!pmem)
@@ -409,11 +404,9 @@ static int pmem_attach_disk(struct device *dev,
pmem->pfn_flags = PFN_DEV;
pmem->pgmap.ref = &q->q_usage_counter;
- pmem->pgmap.kill = pmem_freeze_queue;
- pmem->pgmap.cleanup = __pmem_release_queue;
if (is_nd_pfn(dev)) {
- if (setup_pagemap_fsdax(dev, &pmem->pgmap))
- return -ENOMEM;
+ pmem->pgmap.type = MEMORY_DEVICE_FS_DAX;
+ pmem->pgmap.ops = &fsdax_pagemap_ops;
addr = devm_memremap_pages(dev, &pmem->pgmap);
pfn_sb = nd_pfn->pfn_sb;
pmem->data_offset = le64_to_cpu(pfn_sb->dataoff);
@@ -424,15 +417,14 @@ static int pmem_attach_disk(struct device *dev,
bb_res.start += pmem->data_offset;
} else if (pmem_should_map_pages(dev)) {
memcpy(&pmem->pgmap.res, &nsio->res, sizeof(pmem->pgmap.res));
- pmem->pgmap.altmap_valid = false;
- if (setup_pagemap_fsdax(dev, &pmem->pgmap))
- return -ENOMEM;
+ pmem->pgmap.type = MEMORY_DEVICE_FS_DAX;
+ pmem->pgmap.ops = &fsdax_pagemap_ops;
addr = devm_memremap_pages(dev, &pmem->pgmap);
pmem->pfn_flags |= PFN_MAP;
memcpy(&bb_res, &pmem->pgmap.res, sizeof(bb_res));
} else {
if (devm_add_action_or_reset(dev, pmem_release_queue,
- &q->q_usage_counter))
+ &pmem->pgmap))
return -ENOMEM;
addr = devm_memremap(dev, pmem->phys_addr,
pmem->size, ARCH_MEMREMAP_PMEM);
@@ -470,14 +462,15 @@ static int pmem_attach_disk(struct device *dev,
nvdimm_badblocks_populate(nd_region, &pmem->bb, &bb_res);
disk->bb = &pmem->bb;
- dax_dev = alloc_dax(pmem, disk->disk_name, &pmem_dax_ops);
+ if (is_nvdimm_sync(nd_region))
+ flags = DAXDEV_F_SYNC;
+ dax_dev = alloc_dax(pmem, disk->disk_name, &pmem_dax_ops, flags);
if (!dax_dev) {
put_disk(disk);
return -ENOMEM;
}
dax_write_cache(dax_dev, nvdimm_has_cache(nd_region));
pmem->dax_dev = dax_dev;
-
gendev = disk_to_dev(disk);
gendev->groups = pmem_attribute_groups;
@@ -535,14 +528,14 @@ static int nd_pmem_remove(struct device *dev)
sysfs_put(pmem->bb_state);
pmem->bb_state = NULL;
}
- nvdimm_flush(to_nd_region(dev->parent));
+ nvdimm_flush(to_nd_region(dev->parent), NULL);
return 0;
}
static void nd_pmem_shutdown(struct device *dev)
{
- nvdimm_flush(to_nd_region(dev->parent));
+ nvdimm_flush(to_nd_region(dev->parent), NULL);
}
static void nd_pmem_notify(struct device *dev, enum nvdimm_event event)
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c
index 4fed9ce9c2fe..56f2227f192a 100644
--- a/drivers/nvdimm/region_devs.c
+++ b/drivers/nvdimm/region_devs.c
@@ -287,7 +287,9 @@ static ssize_t deep_flush_store(struct device *dev, struct device_attribute *att
return rc;
if (!flush)
return -EINVAL;
- nvdimm_flush(nd_region);
+ rc = nvdimm_flush(nd_region, NULL);
+ if (rc)
+ return rc;
return len;
}
@@ -1077,6 +1079,11 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus,
dev->of_node = ndr_desc->of_node;
nd_region->ndr_size = resource_size(ndr_desc->res);
nd_region->ndr_start = ndr_desc->res->start;
+ if (ndr_desc->flush)
+ nd_region->flush = ndr_desc->flush;
+ else
+ nd_region->flush = NULL;
+
nd_device_register(dev);
return nd_region;
@@ -1117,11 +1124,24 @@ struct nd_region *nvdimm_volatile_region_create(struct nvdimm_bus *nvdimm_bus,
}
EXPORT_SYMBOL_GPL(nvdimm_volatile_region_create);
+int nvdimm_flush(struct nd_region *nd_region, struct bio *bio)
+{
+ int rc = 0;
+
+ if (!nd_region->flush)
+ rc = generic_nvdimm_flush(nd_region);
+ else {
+ if (nd_region->flush(nd_region, bio))
+ rc = -EIO;
+ }
+
+ return rc;
+}
/**
* nvdimm_flush - flush any posted write queues between the cpu and pmem media
* @nd_region: blk or interleaved pmem region
*/
-void nvdimm_flush(struct nd_region *nd_region)
+int generic_nvdimm_flush(struct nd_region *nd_region)
{
struct nd_region_data *ndrd = dev_get_drvdata(&nd_region->dev);
int i, idx;
@@ -1145,6 +1165,8 @@ void nvdimm_flush(struct nd_region *nd_region)
if (ndrd_get_flush_wpq(ndrd, i, 0))
writeq(1, ndrd_get_flush_wpq(ndrd, i, idx));
wmb();
+
+ return 0;
}
EXPORT_SYMBOL_GPL(nvdimm_flush);
@@ -1189,6 +1211,13 @@ int nvdimm_has_cache(struct nd_region *nd_region)
}
EXPORT_SYMBOL_GPL(nvdimm_has_cache);
+bool is_nvdimm_sync(struct nd_region *nd_region)
+{
+ return is_nd_pmem(&nd_region->dev) &&
+ !test_bit(ND_REGION_ASYNC, &nd_region->flags);
+}
+EXPORT_SYMBOL_GPL(is_nvdimm_sync);
+
struct conflict_context {
struct nd_region *nd_region;
resource_size_t start, size;
diff --git a/drivers/nvdimm/virtio_pmem.c b/drivers/nvdimm/virtio_pmem.c
new file mode 100644
index 000000000000..5e3d07b47e0c
--- /dev/null
+++ b/drivers/nvdimm/virtio_pmem.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * virtio_pmem.c: Virtio pmem Driver
+ *
+ * Discovers persistent memory range information
+ * from host and registers the virtual pmem device
+ * with libnvdimm core.
+ */
+#include "virtio_pmem.h"
+#include "nd.h"
+
+static struct virtio_device_id id_table[] = {
+ { VIRTIO_ID_PMEM, VIRTIO_DEV_ANY_ID },
+ { 0 },
+};
+
+ /* Initialize virt queue */
+static int init_vq(struct virtio_pmem *vpmem)
+{
+ /* single vq */
+ vpmem->req_vq = virtio_find_single_vq(vpmem->vdev,
+ virtio_pmem_host_ack, "flush_queue");
+ if (IS_ERR(vpmem->req_vq))
+ return PTR_ERR(vpmem->req_vq);
+
+ spin_lock_init(&vpmem->pmem_lock);
+ INIT_LIST_HEAD(&vpmem->req_list);
+
+ return 0;
+};
+
+static int virtio_pmem_probe(struct virtio_device *vdev)
+{
+ struct nd_region_desc ndr_desc = {};
+ int nid = dev_to_node(&vdev->dev);
+ struct nd_region *nd_region;
+ struct virtio_pmem *vpmem;
+ struct resource res;
+ int err = 0;
+
+ if (!vdev->config->get) {
+ dev_err(&vdev->dev, "%s failure: config access disabled\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ vpmem = devm_kzalloc(&vdev->dev, sizeof(*vpmem), GFP_KERNEL);
+ if (!vpmem) {
+ err = -ENOMEM;
+ goto out_err;
+ }
+
+ vpmem->vdev = vdev;
+ vdev->priv = vpmem;
+ err = init_vq(vpmem);
+ if (err) {
+ dev_err(&vdev->dev, "failed to initialize virtio pmem vq's\n");
+ goto out_err;
+ }
+
+ virtio_cread(vpmem->vdev, struct virtio_pmem_config,
+ start, &vpmem->start);
+ virtio_cread(vpmem->vdev, struct virtio_pmem_config,
+ size, &vpmem->size);
+
+ res.start = vpmem->start;
+ res.end = vpmem->start + vpmem->size - 1;
+ vpmem->nd_desc.provider_name = "virtio-pmem";
+ vpmem->nd_desc.module = THIS_MODULE;
+
+ vpmem->nvdimm_bus = nvdimm_bus_register(&vdev->dev,
+ &vpmem->nd_desc);
+ if (!vpmem->nvdimm_bus) {
+ dev_err(&vdev->dev, "failed to register device with nvdimm_bus\n");
+ err = -ENXIO;
+ goto out_vq;
+ }
+
+ dev_set_drvdata(&vdev->dev, vpmem->nvdimm_bus);
+
+ ndr_desc.res = &res;
+ ndr_desc.numa_node = nid;
+ ndr_desc.flush = async_pmem_flush;
+ set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags);
+ set_bit(ND_REGION_ASYNC, &ndr_desc.flags);
+ nd_region = nvdimm_pmem_region_create(vpmem->nvdimm_bus, &ndr_desc);
+ if (!nd_region) {
+ dev_err(&vdev->dev, "failed to create nvdimm region\n");
+ err = -ENXIO;
+ goto out_nd;
+ }
+ nd_region->provider_data = dev_to_virtio(nd_region->dev.parent->parent);
+ return 0;
+out_nd:
+ nvdimm_bus_unregister(vpmem->nvdimm_bus);
+out_vq:
+ vdev->config->del_vqs(vdev);
+out_err:
+ return err;
+}
+
+static void virtio_pmem_remove(struct virtio_device *vdev)
+{
+ struct nvdimm_bus *nvdimm_bus = dev_get_drvdata(&vdev->dev);
+
+ nvdimm_bus_unregister(nvdimm_bus);
+ vdev->config->del_vqs(vdev);
+ vdev->config->reset(vdev);
+}
+
+static struct virtio_driver virtio_pmem_driver = {
+ .driver.name = KBUILD_MODNAME,
+ .driver.owner = THIS_MODULE,
+ .id_table = id_table,
+ .probe = virtio_pmem_probe,
+ .remove = virtio_pmem_remove,
+};
+
+module_virtio_driver(virtio_pmem_driver);
+MODULE_DEVICE_TABLE(virtio, id_table);
+MODULE_DESCRIPTION("Virtio pmem driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/nvdimm/virtio_pmem.h b/drivers/nvdimm/virtio_pmem.h
new file mode 100644
index 000000000000..0dddefe594c4
--- /dev/null
+++ b/drivers/nvdimm/virtio_pmem.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * virtio_pmem.h: virtio pmem Driver
+ *
+ * Discovers persistent memory range information
+ * from host and provides a virtio based flushing
+ * interface.
+ **/
+
+#ifndef _LINUX_VIRTIO_PMEM_H
+#define _LINUX_VIRTIO_PMEM_H
+
+#include <linux/module.h>
+#include <uapi/linux/virtio_pmem.h>
+#include <linux/libnvdimm.h>
+#include <linux/spinlock.h>
+
+struct virtio_pmem_request {
+ struct virtio_pmem_req req;
+ struct virtio_pmem_resp resp;
+
+ /* Wait queue to process deferred work after ack from host */
+ wait_queue_head_t host_acked;
+ bool done;
+
+ /* Wait queue to process deferred work after virt queue buffer avail */
+ wait_queue_head_t wq_buf;
+ bool wq_buf_avail;
+ struct list_head list;
+};
+
+struct virtio_pmem {
+ struct virtio_device *vdev;
+
+ /* Virtio pmem request queue */
+ struct virtqueue *req_vq;
+
+ /* nvdimm bus registers virtio pmem device */
+ struct nvdimm_bus *nvdimm_bus;
+ struct nvdimm_bus_descriptor nd_desc;
+
+ /* List to store deferred work if virtqueue is full */
+ struct list_head req_list;
+
+ /* Synchronize virtqueue data */
+ spinlock_t pmem_lock;
+
+ /* Memory region information */
+ __u64 start;
+ __u64 size;
+};
+
+void virtio_pmem_host_ack(struct virtqueue *vq);
+int async_pmem_flush(struct nd_region *nd_region, struct bio *bio);
+#endif
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 120fb593d1da..cc09b81fc7f4 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -11,6 +11,7 @@
#include <linux/hdreg.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/backing-dev.h>
#include <linux/list_sort.h>
#include <linux/slab.h>
#include <linux/types.h>
@@ -1113,15 +1114,15 @@ static struct nvme_id_ns *nvme_identify_ns(struct nvme_ctrl *ctrl,
return id;
}
-static int nvme_set_features(struct nvme_ctrl *dev, unsigned fid, unsigned dword11,
- void *buffer, size_t buflen, u32 *result)
+static int nvme_features(struct nvme_ctrl *dev, u8 op, unsigned int fid,
+ unsigned int dword11, void *buffer, size_t buflen, u32 *result)
{
struct nvme_command c;
union nvme_result res;
int ret;
memset(&c, 0, sizeof(c));
- c.features.opcode = nvme_admin_set_features;
+ c.features.opcode = op;
c.features.fid = cpu_to_le32(fid);
c.features.dword11 = cpu_to_le32(dword11);
@@ -1132,6 +1133,24 @@ static int nvme_set_features(struct nvme_ctrl *dev, unsigned fid, unsigned dword
return ret;
}
+int nvme_set_features(struct nvme_ctrl *dev, unsigned int fid,
+ unsigned int dword11, void *buffer, size_t buflen,
+ u32 *result)
+{
+ return nvme_features(dev, nvme_admin_set_features, fid, dword11, buffer,
+ buflen, result);
+}
+EXPORT_SYMBOL_GPL(nvme_set_features);
+
+int nvme_get_features(struct nvme_ctrl *dev, unsigned int fid,
+ unsigned int dword11, void *buffer, size_t buflen,
+ u32 *result)
+{
+ return nvme_features(dev, nvme_admin_get_features, fid, dword11, buffer,
+ buflen, result);
+}
+EXPORT_SYMBOL_GPL(nvme_get_features);
+
int nvme_set_queue_count(struct nvme_ctrl *ctrl, int *count)
{
u32 q_count = (*count - 1) | ((*count - 1) << 16);
@@ -1608,6 +1627,7 @@ static void nvme_update_disk_info(struct gendisk *disk,
{
sector_t capacity = le64_to_cpu(id->nsze) << (ns->lba_shift - 9);
unsigned short bs = 1 << ns->lba_shift;
+ u32 atomic_bs, phys_bs, io_opt;
if (ns->lba_shift > PAGE_SHIFT) {
/* unsupported block size, set capacity to 0 later */
@@ -1616,9 +1636,37 @@ static void nvme_update_disk_info(struct gendisk *disk,
blk_mq_freeze_queue(disk->queue);
blk_integrity_unregister(disk);
+ if (id->nabo == 0) {
+ /*
+ * Bit 1 indicates whether NAWUPF is defined for this namespace
+ * and whether it should be used instead of AWUPF. If NAWUPF ==
+ * 0 then AWUPF must be used instead.
+ */
+ if (id->nsfeat & (1 << 1) && id->nawupf)
+ atomic_bs = (1 + le16_to_cpu(id->nawupf)) * bs;
+ else
+ atomic_bs = (1 + ns->ctrl->subsys->awupf) * bs;
+ } else {
+ atomic_bs = bs;
+ }
+ phys_bs = bs;
+ io_opt = bs;
+ if (id->nsfeat & (1 << 4)) {
+ /* NPWG = Namespace Preferred Write Granularity */
+ phys_bs *= 1 + le16_to_cpu(id->npwg);
+ /* NOWS = Namespace Optimal Write Size */
+ io_opt *= 1 + le16_to_cpu(id->nows);
+ }
+
blk_queue_logical_block_size(disk->queue, bs);
- blk_queue_physical_block_size(disk->queue, bs);
- blk_queue_io_min(disk->queue, bs);
+ /*
+ * Linux filesystems assume writing a single physical block is
+ * an atomic operation. Hence limit the physical block size to the
+ * value of the Atomic Write Unit Power Fail parameter.
+ */
+ blk_queue_physical_block_size(disk->queue, min(phys_bs, atomic_bs));
+ blk_queue_io_min(disk->queue, phys_bs);
+ blk_queue_io_opt(disk->queue, io_opt);
if (ns->ms && !ns->ext &&
(ns->ctrl->ops->flags & NVME_F_METADATA_SUPPORTED))
@@ -2368,8 +2416,8 @@ static bool nvme_validate_cntlid(struct nvme_subsystem *subsys,
lockdep_assert_held(&nvme_subsystems_lock);
list_for_each_entry(tmp, &subsys->ctrls, subsys_entry) {
- if (ctrl->state == NVME_CTRL_DELETING ||
- ctrl->state == NVME_CTRL_DEAD)
+ if (tmp->state == NVME_CTRL_DELETING ||
+ tmp->state == NVME_CTRL_DEAD)
continue;
if (tmp->cntlid == ctrl->cntlid) {
@@ -2415,6 +2463,7 @@ static int nvme_init_subsystem(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
memcpy(subsys->firmware_rev, id->fr, sizeof(subsys->firmware_rev));
subsys->vendor_id = le16_to_cpu(id->vid);
subsys->cmic = id->cmic;
+ subsys->awupf = le16_to_cpu(id->awupf);
#ifdef CONFIG_NVME_MULTIPATH
subsys->iopolicy = NVME_IOPOLICY_NUMA;
#endif
@@ -3256,6 +3305,10 @@ static int nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
goto out_free_ns;
}
+ if (ctrl->opts && ctrl->opts->data_digest)
+ ns->queue->backing_dev_info->capabilities
+ |= BDI_CAP_STABLE_WRITES;
+
blk_queue_flag_set(QUEUE_FLAG_NONROT, ns->queue);
if (ctrl->ops->flags & NVME_F_PCI_P2PDMA)
blk_queue_flag_set(QUEUE_FLAG_PCI_P2PDMA, ns->queue);
@@ -3318,7 +3371,7 @@ static int nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
device_add_disk(ctrl->device, ns->disk, nvme_ns_id_attr_groups);
nvme_mpath_add_disk(ns, id);
- nvme_fault_inject_init(ns);
+ nvme_fault_inject_init(&ns->fault_inject, ns->disk->disk_name);
kfree(id);
return 0;
@@ -3343,7 +3396,15 @@ static void nvme_ns_remove(struct nvme_ns *ns)
if (test_and_set_bit(NVME_NS_REMOVING, &ns->flags))
return;
- nvme_fault_inject_fini(ns);
+ nvme_fault_inject_fini(&ns->fault_inject);
+
+ mutex_lock(&ns->ctrl->subsys->lock);
+ list_del_rcu(&ns->siblings);
+ mutex_unlock(&ns->ctrl->subsys->lock);
+ synchronize_rcu(); /* guarantee not available in head->list */
+ nvme_mpath_clear_current_path(ns);
+ synchronize_srcu(&ns->head->srcu); /* wait for concurrent submissions */
+
if (ns->disk && ns->disk->flags & GENHD_FL_UP) {
del_gendisk(ns->disk);
blk_cleanup_queue(ns->queue);
@@ -3351,16 +3412,10 @@ static void nvme_ns_remove(struct nvme_ns *ns)
blk_integrity_unregister(ns->disk);
}
- mutex_lock(&ns->ctrl->subsys->lock);
- list_del_rcu(&ns->siblings);
- nvme_mpath_clear_current_path(ns);
- mutex_unlock(&ns->ctrl->subsys->lock);
-
down_write(&ns->ctrl->namespaces_rwsem);
list_del_init(&ns->list);
up_write(&ns->ctrl->namespaces_rwsem);
- synchronize_srcu(&ns->head->srcu);
nvme_mpath_check_last_path(ns);
nvme_put_ns(ns);
}
@@ -3702,6 +3757,7 @@ EXPORT_SYMBOL_GPL(nvme_start_ctrl);
void nvme_uninit_ctrl(struct nvme_ctrl *ctrl)
{
+ nvme_fault_inject_fini(&ctrl->fault_inject);
dev_pm_qos_hide_latency_tolerance(ctrl->device);
cdev_device_del(&ctrl->cdev, ctrl->device);
}
@@ -3797,6 +3853,8 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev,
dev_pm_qos_update_user_latency_tolerance(ctrl->device,
min(default_ps_max_latency_us, (unsigned long)S32_MAX));
+ nvme_fault_inject_init(&ctrl->fault_inject, dev_name(ctrl->device));
+
return 0;
out_free_name:
kfree_const(ctrl->device->kobj.name);
diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c
index 5838f7cd53ac..1994d5b42f94 100644
--- a/drivers/nvme/host/fabrics.c
+++ b/drivers/nvme/host/fabrics.c
@@ -578,7 +578,7 @@ bool __nvmf_check_ready(struct nvme_ctrl *ctrl, struct request *rq,
switch (ctrl->state) {
case NVME_CTRL_NEW:
case NVME_CTRL_CONNECTING:
- if (req->cmd->common.opcode == nvme_fabrics_command &&
+ if (nvme_is_fabrics(req->cmd) &&
req->cmd->fabrics.fctype == nvme_fabrics_type_connect)
return true;
break;
diff --git a/drivers/nvme/host/fault_inject.c b/drivers/nvme/host/fault_inject.c
index 4cfd2c9222d4..1352159733b0 100644
--- a/drivers/nvme/host/fault_inject.c
+++ b/drivers/nvme/host/fault_inject.c
@@ -15,11 +15,10 @@ static DECLARE_FAULT_ATTR(fail_default_attr);
static char *fail_request;
module_param(fail_request, charp, 0000);
-void nvme_fault_inject_init(struct nvme_ns *ns)
+void nvme_fault_inject_init(struct nvme_fault_inject *fault_inj,
+ const char *dev_name)
{
struct dentry *dir, *parent;
- char *name = ns->disk->disk_name;
- struct nvme_fault_inject *fault_inj = &ns->fault_inject;
struct fault_attr *attr = &fault_inj->attr;
/* set default fault injection attribute */
@@ -27,20 +26,20 @@ void nvme_fault_inject_init(struct nvme_ns *ns)
setup_fault_attr(&fail_default_attr, fail_request);
/* create debugfs directory and attribute */
- parent = debugfs_create_dir(name, NULL);
+ parent = debugfs_create_dir(dev_name, NULL);
if (!parent) {
- pr_warn("%s: failed to create debugfs directory\n", name);
+ pr_warn("%s: failed to create debugfs directory\n", dev_name);
return;
}
*attr = fail_default_attr;
dir = fault_create_debugfs_attr("fault_inject", parent, attr);
if (IS_ERR(dir)) {
- pr_warn("%s: failed to create debugfs attr\n", name);
+ pr_warn("%s: failed to create debugfs attr\n", dev_name);
debugfs_remove_recursive(parent);
return;
}
- ns->fault_inject.parent = parent;
+ fault_inj->parent = parent;
/* create debugfs for status code and dont_retry */
fault_inj->status = NVME_SC_INVALID_OPCODE;
@@ -49,29 +48,33 @@ void nvme_fault_inject_init(struct nvme_ns *ns)
debugfs_create_bool("dont_retry", 0600, dir, &fault_inj->dont_retry);
}
-void nvme_fault_inject_fini(struct nvme_ns *ns)
+void nvme_fault_inject_fini(struct nvme_fault_inject *fault_inject)
{
/* remove debugfs directories */
- debugfs_remove_recursive(ns->fault_inject.parent);
+ debugfs_remove_recursive(fault_inject->parent);
}
void nvme_should_fail(struct request *req)
{
struct gendisk *disk = req->rq_disk;
- struct nvme_ns *ns = NULL;
+ struct nvme_fault_inject *fault_inject = NULL;
u16 status;
- /*
- * make sure this request is coming from a valid namespace
- */
- if (!disk)
- return;
+ if (disk) {
+ struct nvme_ns *ns = disk->private_data;
+
+ if (ns)
+ fault_inject = &ns->fault_inject;
+ else
+ WARN_ONCE(1, "No namespace found for request\n");
+ } else {
+ fault_inject = &nvme_req(req)->ctrl->fault_inject;
+ }
- ns = disk->private_data;
- if (ns && should_fail(&ns->fault_inject.attr, 1)) {
+ if (fault_inject && should_fail(&fault_inject->attr, 1)) {
/* inject status code and DNR bit */
- status = ns->fault_inject.status;
- if (ns->fault_inject.dont_retry)
+ status = fault_inject->status;
+ if (fault_inject->dont_retry)
status |= NVME_SC_DNR;
nvme_req(req)->status = status;
}
diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c
index dd8169bbf0d2..232d8094091b 100644
--- a/drivers/nvme/host/fc.c
+++ b/drivers/nvme/host/fc.c
@@ -204,6 +204,9 @@ static DEFINE_IDA(nvme_fc_ctrl_cnt);
static struct workqueue_struct *nvme_fc_wq;
+static bool nvme_fc_waiting_to_unload;
+static DECLARE_COMPLETION(nvme_fc_unload_proceed);
+
/*
* These items are short-term. They will eventually be moved into
* a generic FC class. See comments in module init.
@@ -229,6 +232,8 @@ nvme_fc_free_lport(struct kref *ref)
/* remove from transport list */
spin_lock_irqsave(&nvme_fc_lock, flags);
list_del(&lport->port_list);
+ if (nvme_fc_waiting_to_unload && list_empty(&nvme_fc_lport_list))
+ complete(&nvme_fc_unload_proceed);
spin_unlock_irqrestore(&nvme_fc_lock, flags);
ida_simple_remove(&nvme_fc_local_port_cnt, lport->localport.port_num);
@@ -2112,7 +2117,8 @@ nvme_fc_map_data(struct nvme_fc_ctrl *ctrl, struct request *rq,
freq->sg_table.sgl = freq->first_sgl;
ret = sg_alloc_table_chained(&freq->sg_table,
- blk_rq_nr_phys_segments(rq), freq->sg_table.sgl);
+ blk_rq_nr_phys_segments(rq), freq->sg_table.sgl,
+ SG_CHUNK_SIZE);
if (ret)
return -ENOMEM;
@@ -2122,7 +2128,7 @@ nvme_fc_map_data(struct nvme_fc_ctrl *ctrl, struct request *rq,
freq->sg_cnt = fc_dma_map_sg(ctrl->lport->dev, freq->sg_table.sgl,
op->nents, dir);
if (unlikely(freq->sg_cnt <= 0)) {
- sg_free_table_chained(&freq->sg_table, true);
+ sg_free_table_chained(&freq->sg_table, SG_CHUNK_SIZE);
freq->sg_cnt = 0;
return -EFAULT;
}
@@ -2148,7 +2154,7 @@ nvme_fc_unmap_data(struct nvme_fc_ctrl *ctrl, struct request *rq,
nvme_cleanup_cmd(rq);
- sg_free_table_chained(&freq->sg_table, true);
+ sg_free_table_chained(&freq->sg_table, SG_CHUNK_SIZE);
freq->sg_cnt = 0;
}
@@ -2607,6 +2613,12 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl)
if (nvme_fc_ctlr_active_on_rport(ctrl))
return -ENOTUNIQ;
+ dev_info(ctrl->ctrl.device,
+ "NVME-FC{%d}: create association : host wwpn 0x%016llx "
+ " rport wwpn 0x%016llx: NQN \"%s\"\n",
+ ctrl->cnum, ctrl->lport->localport.port_name,
+ ctrl->rport->remoteport.port_name, ctrl->ctrl.opts->subsysnqn);
+
/*
* Create the admin queue
*/
@@ -3450,11 +3462,51 @@ out_destroy_wq:
return ret;
}
+static void
+nvme_fc_delete_controllers(struct nvme_fc_rport *rport)
+{
+ struct nvme_fc_ctrl *ctrl;
+
+ spin_lock(&rport->lock);
+ list_for_each_entry(ctrl, &rport->ctrl_list, ctrl_list) {
+ dev_warn(ctrl->ctrl.device,
+ "NVME-FC{%d}: transport unloading: deleting ctrl\n",
+ ctrl->cnum);
+ nvme_delete_ctrl(&ctrl->ctrl);
+ }
+ spin_unlock(&rport->lock);
+}
+
+static void
+nvme_fc_cleanup_for_unload(void)
+{
+ struct nvme_fc_lport *lport;
+ struct nvme_fc_rport *rport;
+
+ list_for_each_entry(lport, &nvme_fc_lport_list, port_list) {
+ list_for_each_entry(rport, &lport->endp_list, endp_list) {
+ nvme_fc_delete_controllers(rport);
+ }
+ }
+}
+
static void __exit nvme_fc_exit_module(void)
{
- /* sanity check - all lports should be removed */
- if (!list_empty(&nvme_fc_lport_list))
- pr_warn("%s: localport list not empty\n", __func__);
+ unsigned long flags;
+ bool need_cleanup = false;
+
+ spin_lock_irqsave(&nvme_fc_lock, flags);
+ nvme_fc_waiting_to_unload = true;
+ if (!list_empty(&nvme_fc_lport_list)) {
+ need_cleanup = true;
+ nvme_fc_cleanup_for_unload();
+ }
+ spin_unlock_irqrestore(&nvme_fc_lock, flags);
+ if (need_cleanup) {
+ pr_info("%s: waiting for ctlr deletes\n", __func__);
+ wait_for_completion(&nvme_fc_unload_proceed);
+ pr_info("%s: ctrl deletes complete\n", __func__);
+ }
nvmf_unregister_transport(&nvme_fc_transport);
diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index 4f20a10b39d3..ba009d4c9dfa 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -660,7 +660,7 @@ static struct request *nvme_nvm_alloc_request(struct request_queue *q,
rq->cmd_flags &= ~REQ_FAILFAST_DRIVER;
if (rqd->bio)
- blk_init_request_from_bio(rq, rqd->bio);
+ blk_rq_append_bio(rq, &rqd->bio);
else
rq->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, IOPRIO_NORM);
diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
index 499acf07d61a..a9a927677970 100644
--- a/drivers/nvme/host/multipath.c
+++ b/drivers/nvme/host/multipath.c
@@ -123,14 +123,20 @@ void nvme_mpath_clear_current_path(struct nvme_ns *ns)
}
}
+static bool nvme_path_is_disabled(struct nvme_ns *ns)
+{
+ return ns->ctrl->state != NVME_CTRL_LIVE ||
+ test_bit(NVME_NS_ANA_PENDING, &ns->flags) ||
+ test_bit(NVME_NS_REMOVING, &ns->flags);
+}
+
static struct nvme_ns *__nvme_find_path(struct nvme_ns_head *head, int node)
{
int found_distance = INT_MAX, fallback_distance = INT_MAX, distance;
struct nvme_ns *found = NULL, *fallback = NULL, *ns;
list_for_each_entry_rcu(ns, &head->list, siblings) {
- if (ns->ctrl->state != NVME_CTRL_LIVE ||
- test_bit(NVME_NS_ANA_PENDING, &ns->flags))
+ if (nvme_path_is_disabled(ns))
continue;
if (READ_ONCE(head->subsys->iopolicy) == NVME_IOPOLICY_NUMA)
@@ -178,14 +184,16 @@ static struct nvme_ns *nvme_round_robin_path(struct nvme_ns_head *head,
{
struct nvme_ns *ns, *found, *fallback = NULL;
- if (list_is_singular(&head->list))
+ if (list_is_singular(&head->list)) {
+ if (nvme_path_is_disabled(old))
+ return NULL;
return old;
+ }
for (ns = nvme_next_ns(head, old);
ns != old;
ns = nvme_next_ns(head, ns)) {
- if (ns->ctrl->state != NVME_CTRL_LIVE ||
- test_bit(NVME_NS_ANA_PENDING, &ns->flags))
+ if (nvme_path_is_disabled(ns))
continue;
if (ns->ana_state == NVME_ANA_OPTIMIZED) {
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 55553d293a98..716a876119c8 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -146,6 +146,15 @@ enum nvme_ctrl_state {
NVME_CTRL_DEAD,
};
+struct nvme_fault_inject {
+#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
+ struct fault_attr attr;
+ struct dentry *parent;
+ bool dont_retry; /* DNR, do not retry */
+ u16 status; /* status code */
+#endif
+};
+
struct nvme_ctrl {
bool comp_seen;
enum nvme_ctrl_state state;
@@ -247,6 +256,8 @@ struct nvme_ctrl {
struct page *discard_page;
unsigned long discard_page_busy;
+
+ struct nvme_fault_inject fault_inject;
};
enum nvme_iopolicy {
@@ -272,6 +283,7 @@ struct nvme_subsystem {
char firmware_rev[8];
u8 cmic;
u16 vendor_id;
+ u16 awupf; /* 0's based awupf value. */
struct ida ns_ida;
#ifdef CONFIG_NVME_MULTIPATH
enum nvme_iopolicy iopolicy;
@@ -313,15 +325,6 @@ struct nvme_ns_head {
#endif
};
-#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
-struct nvme_fault_inject {
- struct fault_attr attr;
- struct dentry *parent;
- bool dont_retry; /* DNR, do not retry */
- u16 status; /* status code */
-};
-#endif
-
struct nvme_ns {
struct list_head list;
@@ -349,9 +352,7 @@ struct nvme_ns {
#define NVME_NS_ANA_PENDING 2
u16 noiob;
-#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
struct nvme_fault_inject fault_inject;
-#endif
};
@@ -372,12 +373,18 @@ struct nvme_ctrl_ops {
};
#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
-void nvme_fault_inject_init(struct nvme_ns *ns);
-void nvme_fault_inject_fini(struct nvme_ns *ns);
+void nvme_fault_inject_init(struct nvme_fault_inject *fault_inj,
+ const char *dev_name);
+void nvme_fault_inject_fini(struct nvme_fault_inject *fault_inject);
void nvme_should_fail(struct request *req);
#else
-static inline void nvme_fault_inject_init(struct nvme_ns *ns) {}
-static inline void nvme_fault_inject_fini(struct nvme_ns *ns) {}
+static inline void nvme_fault_inject_init(struct nvme_fault_inject *fault_inj,
+ const char *dev_name)
+{
+}
+static inline void nvme_fault_inject_fini(struct nvme_fault_inject *fault_inj)
+{
+}
static inline void nvme_should_fail(struct request *req) {}
#endif
@@ -459,6 +466,12 @@ int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
union nvme_result *result, void *buffer, unsigned bufflen,
unsigned timeout, int qid, int at_head,
blk_mq_req_flags_t flags, bool poll);
+int nvme_set_features(struct nvme_ctrl *dev, unsigned int fid,
+ unsigned int dword11, void *buffer, size_t buflen,
+ u32 *result);
+int nvme_get_features(struct nvme_ctrl *dev, unsigned int fid,
+ unsigned int dword11, void *buffer, size_t buflen,
+ u32 *result);
int nvme_set_queue_count(struct nvme_ctrl *ctrl, int *count);
void nvme_stop_keep_alive(struct nvme_ctrl *ctrl);
int nvme_reset_ctrl(struct nvme_ctrl *ctrl);
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 524d6bd6d095..bb970ca82517 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -18,6 +18,7 @@
#include <linux/mutex.h>
#include <linux/once.h>
#include <linux/pci.h>
+#include <linux/suspend.h>
#include <linux/t10-pi.h>
#include <linux/types.h>
#include <linux/io-64-nonatomic-lo-hi.h>
@@ -67,20 +68,14 @@ static int io_queue_depth = 1024;
module_param_cb(io_queue_depth, &io_queue_depth_ops, &io_queue_depth, 0644);
MODULE_PARM_DESC(io_queue_depth, "set io queue depth, should >= 2");
-static int queue_count_set(const char *val, const struct kernel_param *kp);
-static const struct kernel_param_ops queue_count_ops = {
- .set = queue_count_set,
- .get = param_get_int,
-};
-
static int write_queues;
-module_param_cb(write_queues, &queue_count_ops, &write_queues, 0644);
+module_param(write_queues, int, 0644);
MODULE_PARM_DESC(write_queues,
"Number of queues to use for writes. If not set, reads and writes "
"will share a queue set.");
-static int poll_queues = 0;
-module_param_cb(poll_queues, &queue_count_ops, &poll_queues, 0644);
+static int poll_queues;
+module_param(poll_queues, int, 0644);
MODULE_PARM_DESC(poll_queues, "Number of queues to use for polled IO.");
struct nvme_dev;
@@ -116,6 +111,7 @@ struct nvme_dev {
u32 cmbsz;
u32 cmbloc;
struct nvme_ctrl ctrl;
+ u32 last_ps;
mempool_t *iod_mempool;
@@ -144,19 +140,6 @@ static int io_queue_depth_set(const char *val, const struct kernel_param *kp)
return param_set_int(val, kp);
}
-static int queue_count_set(const char *val, const struct kernel_param *kp)
-{
- int n, ret;
-
- ret = kstrtoint(val, 10, &n);
- if (ret)
- return ret;
- if (n > num_possible_cpus())
- n = num_possible_cpus();
-
- return param_set_int(val, kp);
-}
-
static inline unsigned int sq_idx(unsigned int qid, u32 stride)
{
return qid * 2 * stride;
@@ -1456,11 +1439,15 @@ static int nvme_alloc_sq_cmds(struct nvme_dev *dev, struct nvme_queue *nvmeq,
if (qid && dev->cmb_use_sqes && (dev->cmbsz & NVME_CMBSZ_SQS)) {
nvmeq->sq_cmds = pci_alloc_p2pmem(pdev, SQ_SIZE(depth));
- nvmeq->sq_dma_addr = pci_p2pmem_virt_to_bus(pdev,
- nvmeq->sq_cmds);
- if (nvmeq->sq_dma_addr) {
- set_bit(NVMEQ_SQ_CMB, &nvmeq->flags);
- return 0;
+ if (nvmeq->sq_cmds) {
+ nvmeq->sq_dma_addr = pci_p2pmem_virt_to_bus(pdev,
+ nvmeq->sq_cmds);
+ if (nvmeq->sq_dma_addr) {
+ set_bit(NVMEQ_SQ_CMB, &nvmeq->flags);
+ return 0;
+ }
+
+ pci_free_p2pmem(pdev, nvmeq->sq_cmds, SQ_SIZE(depth));
}
}
@@ -2068,6 +2055,7 @@ static int nvme_setup_irqs(struct nvme_dev *dev, unsigned int nr_io_queues)
.priv = dev,
};
unsigned int irq_queues, this_p_queues;
+ unsigned int nr_cpus = num_possible_cpus();
/*
* Poll queues don't need interrupts, but we need at least one IO
@@ -2078,7 +2066,10 @@ static int nvme_setup_irqs(struct nvme_dev *dev, unsigned int nr_io_queues)
this_p_queues = nr_io_queues - 1;
irq_queues = 1;
} else {
- irq_queues = nr_io_queues - this_p_queues + 1;
+ if (nr_cpus < nr_io_queues - this_p_queues)
+ irq_queues = nr_cpus + 1;
+ else
+ irq_queues = nr_io_queues - this_p_queues + 1;
}
dev->io_queues[HCTX_TYPE_POLL] = this_p_queues;
@@ -2263,7 +2254,9 @@ static int nvme_dev_add(struct nvme_dev *dev)
if (!dev->ctrl.tagset) {
dev->tagset.ops = &nvme_mq_ops;
dev->tagset.nr_hw_queues = dev->online_queues - 1;
- dev->tagset.nr_maps = 2; /* default + read */
+ dev->tagset.nr_maps = 1; /* default */
+ if (dev->io_queues[HCTX_TYPE_READ])
+ dev->tagset.nr_maps++;
if (dev->io_queues[HCTX_TYPE_POLL])
dev->tagset.nr_maps++;
dev->tagset.timeout = NVME_IO_TIMEOUT;
@@ -2302,8 +2295,7 @@ static int nvme_pci_enable(struct nvme_dev *dev)
pci_set_master(pdev);
- if (dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(64)) &&
- dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(32)))
+ if (dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(64)))
goto disable;
if (readl(dev->bar + NVME_REG_CSTS) == -1) {
@@ -2464,10 +2456,8 @@ static void nvme_pci_free_ctrl(struct nvme_ctrl *ctrl)
kfree(dev);
}
-static void nvme_remove_dead_ctrl(struct nvme_dev *dev, int status)
+static void nvme_remove_dead_ctrl(struct nvme_dev *dev)
{
- dev_warn(dev->ctrl.device, "Removing after probe failure status: %d\n", status);
-
nvme_get_ctrl(&dev->ctrl);
nvme_dev_disable(dev, false);
nvme_kill_queues(&dev->ctrl);
@@ -2480,11 +2470,13 @@ static void nvme_reset_work(struct work_struct *work)
struct nvme_dev *dev =
container_of(work, struct nvme_dev, ctrl.reset_work);
bool was_suspend = !!(dev->ctrl.ctrl_config & NVME_CC_SHN_NORMAL);
- int result = -ENODEV;
+ int result;
enum nvme_ctrl_state new_state = NVME_CTRL_LIVE;
- if (WARN_ON(dev->ctrl.state != NVME_CTRL_RESETTING))
+ if (WARN_ON(dev->ctrl.state != NVME_CTRL_RESETTING)) {
+ result = -ENODEV;
goto out;
+ }
/*
* If we're called to reset a live controller first shut it down before
@@ -2511,7 +2503,8 @@ static void nvme_reset_work(struct work_struct *work)
* Limit the max command size to prevent iod->sg allocations going
* over a single page.
*/
- dev->ctrl.max_hw_sectors = NVME_MAX_KB_SZ << 1;
+ dev->ctrl.max_hw_sectors = min_t(u32,
+ NVME_MAX_KB_SZ << 1, dma_max_mapping_size(dev->dev) >> 9);
dev->ctrl.max_segments = NVME_MAX_SEGS;
/*
@@ -2528,6 +2521,7 @@ static void nvme_reset_work(struct work_struct *work)
if (!nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_CONNECTING)) {
dev_warn(dev->ctrl.device,
"failed to mark controller CONNECTING\n");
+ result = -EBUSY;
goto out;
}
@@ -2588,6 +2582,7 @@ static void nvme_reset_work(struct work_struct *work)
if (!nvme_change_ctrl_state(&dev->ctrl, new_state)) {
dev_warn(dev->ctrl.device,
"failed to mark controller state %d\n", new_state);
+ result = -ENODEV;
goto out;
}
@@ -2597,7 +2592,10 @@ static void nvme_reset_work(struct work_struct *work)
out_unlock:
mutex_unlock(&dev->shutdown_lock);
out:
- nvme_remove_dead_ctrl(dev, result);
+ if (result)
+ dev_warn(dev->ctrl.device,
+ "Removing after probe failure status: %d\n", result);
+ nvme_remove_dead_ctrl(dev);
}
static void nvme_remove_dead_ctrl_work(struct work_struct *work)
@@ -2835,16 +2833,94 @@ static void nvme_remove(struct pci_dev *pdev)
}
#ifdef CONFIG_PM_SLEEP
+static int nvme_get_power_state(struct nvme_ctrl *ctrl, u32 *ps)
+{
+ return nvme_get_features(ctrl, NVME_FEAT_POWER_MGMT, 0, NULL, 0, ps);
+}
+
+static int nvme_set_power_state(struct nvme_ctrl *ctrl, u32 ps)
+{
+ return nvme_set_features(ctrl, NVME_FEAT_POWER_MGMT, ps, NULL, 0, NULL);
+}
+
+static int nvme_resume(struct device *dev)
+{
+ struct nvme_dev *ndev = pci_get_drvdata(to_pci_dev(dev));
+ struct nvme_ctrl *ctrl = &ndev->ctrl;
+
+ if (pm_resume_via_firmware() || !ctrl->npss ||
+ nvme_set_power_state(ctrl, ndev->last_ps) != 0)
+ nvme_reset_ctrl(ctrl);
+ return 0;
+}
+
static int nvme_suspend(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct nvme_dev *ndev = pci_get_drvdata(pdev);
+ struct nvme_ctrl *ctrl = &ndev->ctrl;
+ int ret = -EBUSY;
+
+ /*
+ * The platform does not remove power for a kernel managed suspend so
+ * use host managed nvme power settings for lowest idle power if
+ * possible. This should have quicker resume latency than a full device
+ * shutdown. But if the firmware is involved after the suspend or the
+ * device does not support any non-default power states, shut down the
+ * device fully.
+ */
+ if (pm_suspend_via_firmware() || !ctrl->npss) {
+ nvme_dev_disable(ndev, true);
+ return 0;
+ }
+
+ nvme_start_freeze(ctrl);
+ nvme_wait_freeze(ctrl);
+ nvme_sync_queues(ctrl);
+
+ if (ctrl->state != NVME_CTRL_LIVE &&
+ ctrl->state != NVME_CTRL_ADMIN_ONLY)
+ goto unfreeze;
+
+ ndev->last_ps = 0;
+ ret = nvme_get_power_state(ctrl, &ndev->last_ps);
+ if (ret < 0)
+ goto unfreeze;
+
+ ret = nvme_set_power_state(ctrl, ctrl->npss);
+ if (ret < 0)
+ goto unfreeze;
+
+ if (ret) {
+ /*
+ * Clearing npss forces a controller reset on resume. The
+ * correct value will be resdicovered then.
+ */
+ nvme_dev_disable(ndev, true);
+ ctrl->npss = 0;
+ ret = 0;
+ goto unfreeze;
+ }
+ /*
+ * A saved state prevents pci pm from generically controlling the
+ * device's power. If we're using protocol specific settings, we don't
+ * want pci interfering.
+ */
+ pci_save_state(pdev);
+unfreeze:
+ nvme_unfreeze(ctrl);
+ return ret;
+}
+
+static int nvme_simple_suspend(struct device *dev)
+{
+ struct nvme_dev *ndev = pci_get_drvdata(to_pci_dev(dev));
nvme_dev_disable(ndev, true);
return 0;
}
-static int nvme_resume(struct device *dev)
+static int nvme_simple_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct nvme_dev *ndev = pci_get_drvdata(pdev);
@@ -2852,9 +2928,16 @@ static int nvme_resume(struct device *dev)
nvme_reset_ctrl(&ndev->ctrl);
return 0;
}
-#endif
-static SIMPLE_DEV_PM_OPS(nvme_dev_pm_ops, nvme_suspend, nvme_resume);
+static const struct dev_pm_ops nvme_dev_pm_ops = {
+ .suspend = nvme_suspend,
+ .resume = nvme_resume,
+ .freeze = nvme_simple_suspend,
+ .thaw = nvme_simple_resume,
+ .poweroff = nvme_simple_suspend,
+ .restore = nvme_simple_resume,
+};
+#endif /* CONFIG_PM_SLEEP */
static pci_ers_result_t nvme_error_detected(struct pci_dev *pdev,
pci_channel_state_t state)
@@ -2959,9 +3042,11 @@ static struct pci_driver nvme_driver = {
.probe = nvme_probe,
.remove = nvme_remove,
.shutdown = nvme_shutdown,
+#ifdef CONFIG_PM_SLEEP
.driver = {
.pm = &nvme_dev_pm_ops,
},
+#endif
.sriov_configure = pci_sriov_configure_simple,
.err_handler = &nvme_err_handler,
};
diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
index 97f668a39ae1..a249db528d54 100644
--- a/drivers/nvme/host/rdma.c
+++ b/drivers/nvme/host/rdma.c
@@ -482,7 +482,7 @@ static int nvme_rdma_create_queue_ib(struct nvme_rdma_queue *queue)
ret = ib_mr_pool_init(queue->qp, &queue->qp->rdma_mrs,
queue->queue_size,
IB_MR_TYPE_MEM_REG,
- nvme_rdma_get_max_fr_pages(ibdev));
+ nvme_rdma_get_max_fr_pages(ibdev), 0);
if (ret) {
dev_err(queue->ctrl->ctrl.device,
"failed to initialize MR pool sized %d for QID %d\n",
@@ -1144,7 +1144,7 @@ static void nvme_rdma_unmap_data(struct nvme_rdma_queue *queue,
WRITE ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
nvme_cleanup_cmd(rq);
- sg_free_table_chained(&req->sg_table, true);
+ sg_free_table_chained(&req->sg_table, SG_CHUNK_SIZE);
}
static int nvme_rdma_set_sg_null(struct nvme_command *c)
@@ -1259,7 +1259,8 @@ static int nvme_rdma_map_data(struct nvme_rdma_queue *queue,
req->sg_table.sgl = req->first_sgl;
ret = sg_alloc_table_chained(&req->sg_table,
- blk_rq_nr_phys_segments(rq), req->sg_table.sgl);
+ blk_rq_nr_phys_segments(rq), req->sg_table.sgl,
+ SG_CHUNK_SIZE);
if (ret)
return -ENOMEM;
@@ -1299,7 +1300,7 @@ out_unmap_sg:
req->nents, rq_data_dir(rq) ==
WRITE ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
out_free_table:
- sg_free_table_chained(&req->sg_table, true);
+ sg_free_table_chained(&req->sg_table, SG_CHUNK_SIZE);
return ret;
}
diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 08a2501b9357..606b13d35d16 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -860,7 +860,14 @@ static int nvme_tcp_try_send_data(struct nvme_tcp_request *req)
else
flags |= MSG_MORE;
- ret = kernel_sendpage(queue->sock, page, offset, len, flags);
+ /* can't zcopy slab pages */
+ if (unlikely(PageSlab(page))) {
+ ret = sock_no_sendpage(queue->sock, page, offset, len,
+ flags);
+ } else {
+ ret = kernel_sendpage(queue->sock, page, offset, len,
+ flags);
+ }
if (ret <= 0)
return ret;
diff --git a/drivers/nvme/host/trace.c b/drivers/nvme/host/trace.c
index 5f24ea7a28eb..9778eb0406b3 100644
--- a/drivers/nvme/host/trace.c
+++ b/drivers/nvme/host/trace.c
@@ -7,6 +7,17 @@
#include <asm/unaligned.h>
#include "trace.h"
+static const char *nvme_trace_delete_sq(struct trace_seq *p, u8 *cdw10)
+{
+ const char *ret = trace_seq_buffer_ptr(p);
+ u16 sqid = get_unaligned_le16(cdw10);
+
+ trace_seq_printf(p, "sqid=%u", sqid);
+ trace_seq_putc(p, 0);
+
+ return ret;
+}
+
static const char *nvme_trace_create_sq(struct trace_seq *p, u8 *cdw10)
{
const char *ret = trace_seq_buffer_ptr(p);
@@ -23,6 +34,17 @@ static const char *nvme_trace_create_sq(struct trace_seq *p, u8 *cdw10)
return ret;
}
+static const char *nvme_trace_delete_cq(struct trace_seq *p, u8 *cdw10)
+{
+ const char *ret = trace_seq_buffer_ptr(p);
+ u16 cqid = get_unaligned_le16(cdw10);
+
+ trace_seq_printf(p, "cqid=%u", cqid);
+ trace_seq_putc(p, 0);
+
+ return ret;
+}
+
static const char *nvme_trace_create_cq(struct trace_seq *p, u8 *cdw10)
{
const char *ret = trace_seq_buffer_ptr(p);
@@ -107,8 +129,12 @@ const char *nvme_trace_parse_admin_cmd(struct trace_seq *p,
u8 opcode, u8 *cdw10)
{
switch (opcode) {
+ case nvme_admin_delete_sq:
+ return nvme_trace_delete_sq(p, cdw10);
case nvme_admin_create_sq:
return nvme_trace_create_sq(p, cdw10);
+ case nvme_admin_delete_cq:
+ return nvme_trace_delete_cq(p, cdw10);
case nvme_admin_create_cq:
return nvme_trace_create_cq(p, cdw10);
case nvme_admin_identify:
@@ -135,6 +161,69 @@ const char *nvme_trace_parse_nvm_cmd(struct trace_seq *p,
}
}
+static const char *nvme_trace_fabrics_property_set(struct trace_seq *p, u8 *spc)
+{
+ const char *ret = trace_seq_buffer_ptr(p);
+ u8 attrib = spc[0];
+ u32 ofst = get_unaligned_le32(spc + 4);
+ u64 value = get_unaligned_le64(spc + 8);
+
+ trace_seq_printf(p, "attrib=%u, ofst=0x%x, value=0x%llx",
+ attrib, ofst, value);
+ trace_seq_putc(p, 0);
+ return ret;
+}
+
+static const char *nvme_trace_fabrics_connect(struct trace_seq *p, u8 *spc)
+{
+ const char *ret = trace_seq_buffer_ptr(p);
+ u16 recfmt = get_unaligned_le16(spc);
+ u16 qid = get_unaligned_le16(spc + 2);
+ u16 sqsize = get_unaligned_le16(spc + 4);
+ u8 cattr = spc[6];
+ u32 kato = get_unaligned_le32(spc + 8);
+
+ trace_seq_printf(p, "recfmt=%u, qid=%u, sqsize=%u, cattr=%u, kato=%u",
+ recfmt, qid, sqsize, cattr, kato);
+ trace_seq_putc(p, 0);
+ return ret;
+}
+
+static const char *nvme_trace_fabrics_property_get(struct trace_seq *p, u8 *spc)
+{
+ const char *ret = trace_seq_buffer_ptr(p);
+ u8 attrib = spc[0];
+ u32 ofst = get_unaligned_le32(spc + 4);
+
+ trace_seq_printf(p, "attrib=%u, ofst=0x%x", attrib, ofst);
+ trace_seq_putc(p, 0);
+ return ret;
+}
+
+static const char *nvme_trace_fabrics_common(struct trace_seq *p, u8 *spc)
+{
+ const char *ret = trace_seq_buffer_ptr(p);
+
+ trace_seq_printf(p, "specific=%*ph", 24, spc);
+ trace_seq_putc(p, 0);
+ return ret;
+}
+
+const char *nvme_trace_parse_fabrics_cmd(struct trace_seq *p,
+ u8 fctype, u8 *spc)
+{
+ switch (fctype) {
+ case nvme_fabrics_type_property_set:
+ return nvme_trace_fabrics_property_set(p, spc);
+ case nvme_fabrics_type_connect:
+ return nvme_trace_fabrics_connect(p, spc);
+ case nvme_fabrics_type_property_get:
+ return nvme_trace_fabrics_property_get(p, spc);
+ default:
+ return nvme_trace_fabrics_common(p, spc);
+ }
+}
+
const char *nvme_trace_disk_name(struct trace_seq *p, char *name)
{
const char *ret = trace_seq_buffer_ptr(p);
@@ -145,6 +234,5 @@ const char *nvme_trace_disk_name(struct trace_seq *p, char *name)
return ret;
}
-EXPORT_SYMBOL_GPL(nvme_trace_disk_name);
EXPORT_TRACEPOINT_SYMBOL_GPL(nvme_sq);
diff --git a/drivers/nvme/host/trace.h b/drivers/nvme/host/trace.h
index e71502d141ed..daaf700eae79 100644
--- a/drivers/nvme/host/trace.h
+++ b/drivers/nvme/host/trace.h
@@ -16,59 +16,19 @@
#include "nvme.h"
-#define nvme_admin_opcode_name(opcode) { opcode, #opcode }
-#define show_admin_opcode_name(val) \
- __print_symbolic(val, \
- nvme_admin_opcode_name(nvme_admin_delete_sq), \
- nvme_admin_opcode_name(nvme_admin_create_sq), \
- nvme_admin_opcode_name(nvme_admin_get_log_page), \
- nvme_admin_opcode_name(nvme_admin_delete_cq), \
- nvme_admin_opcode_name(nvme_admin_create_cq), \
- nvme_admin_opcode_name(nvme_admin_identify), \
- nvme_admin_opcode_name(nvme_admin_abort_cmd), \
- nvme_admin_opcode_name(nvme_admin_set_features), \
- nvme_admin_opcode_name(nvme_admin_get_features), \
- nvme_admin_opcode_name(nvme_admin_async_event), \
- nvme_admin_opcode_name(nvme_admin_ns_mgmt), \
- nvme_admin_opcode_name(nvme_admin_activate_fw), \
- nvme_admin_opcode_name(nvme_admin_download_fw), \
- nvme_admin_opcode_name(nvme_admin_ns_attach), \
- nvme_admin_opcode_name(nvme_admin_keep_alive), \
- nvme_admin_opcode_name(nvme_admin_directive_send), \
- nvme_admin_opcode_name(nvme_admin_directive_recv), \
- nvme_admin_opcode_name(nvme_admin_dbbuf), \
- nvme_admin_opcode_name(nvme_admin_format_nvm), \
- nvme_admin_opcode_name(nvme_admin_security_send), \
- nvme_admin_opcode_name(nvme_admin_security_recv), \
- nvme_admin_opcode_name(nvme_admin_sanitize_nvm))
-
-#define nvme_opcode_name(opcode) { opcode, #opcode }
-#define show_nvm_opcode_name(val) \
- __print_symbolic(val, \
- nvme_opcode_name(nvme_cmd_flush), \
- nvme_opcode_name(nvme_cmd_write), \
- nvme_opcode_name(nvme_cmd_read), \
- nvme_opcode_name(nvme_cmd_write_uncor), \
- nvme_opcode_name(nvme_cmd_compare), \
- nvme_opcode_name(nvme_cmd_write_zeroes), \
- nvme_opcode_name(nvme_cmd_dsm), \
- nvme_opcode_name(nvme_cmd_resv_register), \
- nvme_opcode_name(nvme_cmd_resv_report), \
- nvme_opcode_name(nvme_cmd_resv_acquire), \
- nvme_opcode_name(nvme_cmd_resv_release))
-
-#define show_opcode_name(qid, opcode) \
- (qid ? show_nvm_opcode_name(opcode) : show_admin_opcode_name(opcode))
-
const char *nvme_trace_parse_admin_cmd(struct trace_seq *p, u8 opcode,
u8 *cdw10);
const char *nvme_trace_parse_nvm_cmd(struct trace_seq *p, u8 opcode,
u8 *cdw10);
+const char *nvme_trace_parse_fabrics_cmd(struct trace_seq *p, u8 fctype,
+ u8 *spc);
-#define parse_nvme_cmd(qid, opcode, cdw10) \
- (qid ? \
- nvme_trace_parse_nvm_cmd(p, opcode, cdw10) : \
- nvme_trace_parse_admin_cmd(p, opcode, cdw10))
+#define parse_nvme_cmd(qid, opcode, fctype, cdw10) \
+ ((opcode) == nvme_fabrics_command ? \
+ nvme_trace_parse_fabrics_cmd(p, fctype, cdw10) : \
+ ((qid) ? \
+ nvme_trace_parse_nvm_cmd(p, opcode, cdw10) : \
+ nvme_trace_parse_admin_cmd(p, opcode, cdw10)))
const char *nvme_trace_disk_name(struct trace_seq *p, char *name);
#define __print_disk_name(name) \
@@ -93,6 +53,7 @@ TRACE_EVENT(nvme_setup_cmd,
__field(int, qid)
__field(u8, opcode)
__field(u8, flags)
+ __field(u8, fctype)
__field(u16, cid)
__field(u32, nsid)
__field(u64, metadata)
@@ -106,6 +67,7 @@ TRACE_EVENT(nvme_setup_cmd,
__entry->cid = cmd->common.command_id;
__entry->nsid = le32_to_cpu(cmd->common.nsid);
__entry->metadata = le64_to_cpu(cmd->common.metadata);
+ __entry->fctype = cmd->fabrics.fctype;
__assign_disk_name(__entry->disk, req->rq_disk);
memcpy(__entry->cdw10, &cmd->common.cdw10,
sizeof(__entry->cdw10));
@@ -114,8 +76,10 @@ TRACE_EVENT(nvme_setup_cmd,
__entry->ctrl_id, __print_disk_name(__entry->disk),
__entry->qid, __entry->cid, __entry->nsid,
__entry->flags, __entry->metadata,
- show_opcode_name(__entry->qid, __entry->opcode),
- parse_nvme_cmd(__entry->qid, __entry->opcode, __entry->cdw10))
+ show_opcode_name(__entry->qid, __entry->opcode,
+ __entry->fctype),
+ parse_nvme_cmd(__entry->qid, __entry->opcode,
+ __entry->fctype, __entry->cdw10))
);
TRACE_EVENT(nvme_complete_rq,
@@ -141,7 +105,7 @@ TRACE_EVENT(nvme_complete_rq,
__entry->status = nvme_req(req)->status;
__assign_disk_name(__entry->disk, req->rq_disk);
),
- TP_printk("nvme%d: %sqid=%d, cmdid=%u, res=%llu, retries=%u, flags=0x%x, status=%u",
+ TP_printk("nvme%d: %sqid=%d, cmdid=%u, res=%#llx, retries=%u, flags=0x%x, status=%#x",
__entry->ctrl_id, __print_disk_name(__entry->disk),
__entry->qid, __entry->cid, __entry->result,
__entry->retries, __entry->flags, __entry->status)
diff --git a/drivers/nvme/target/Makefile b/drivers/nvme/target/Makefile
index 8c3ad0fb6860..2b33836f3d3e 100644
--- a/drivers/nvme/target/Makefile
+++ b/drivers/nvme/target/Makefile
@@ -1,5 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
+ccflags-y += -I$(src)
+
obj-$(CONFIG_NVME_TARGET) += nvmet.o
obj-$(CONFIG_NVME_TARGET_LOOP) += nvme-loop.o
obj-$(CONFIG_NVME_TARGET_RDMA) += nvmet-rdma.o
@@ -14,3 +16,4 @@ nvmet-rdma-y += rdma.o
nvmet-fc-y += fc.o
nvme-fcloop-y += fcloop.o
nvmet-tcp-y += tcp.o
+nvmet-$(CONFIG_TRACING) += trace.o
diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index 9f72d515fc4b..4dc12ea52f23 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -442,6 +442,9 @@ static void nvmet_execute_identify_ns(struct nvmet_req *req)
break;
}
+ if (ns->bdev)
+ nvmet_bdev_set_limits(ns->bdev, id);
+
/*
* We just provide a single LBA format that matches what the
* underlying device reports.
diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c
index 08dd5af357f7..cd52b9f15376 100644
--- a/drivers/nvme/target/configfs.c
+++ b/drivers/nvme/target/configfs.c
@@ -588,8 +588,10 @@ static struct config_group *nvmet_ns_make(struct config_group *group,
goto out;
ret = -EINVAL;
- if (nsid == 0 || nsid == NVME_NSID_ALL)
+ if (nsid == 0 || nsid == NVME_NSID_ALL) {
+ pr_err("invalid nsid %#x", nsid);
goto out;
+ }
ret = -ENOMEM;
ns = nvmet_ns_alloc(subsys, nsid);
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index 7734a6acff85..dad0243c7c96 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -10,6 +10,9 @@
#include <linux/pci-p2pdma.h>
#include <linux/scatterlist.h>
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+
#include "nvmet.h"
struct workqueue_struct *buffered_io_wq;
@@ -311,6 +314,7 @@ int nvmet_enable_port(struct nvmet_port *port)
port->inline_data_size = 0;
port->enabled = true;
+ port->tr_ops = ops;
return 0;
}
@@ -321,6 +325,7 @@ void nvmet_disable_port(struct nvmet_port *port)
lockdep_assert_held(&nvmet_config_sem);
port->enabled = false;
+ port->tr_ops = NULL;
ops = nvmet_transports[port->disc_addr.trtype];
ops->remove_port(port);
@@ -689,6 +694,9 @@ static void __nvmet_req_complete(struct nvmet_req *req, u16 status)
if (unlikely(status))
nvmet_set_error(req, status);
+
+ trace_nvmet_req_complete(req);
+
if (req->ns)
nvmet_put_namespace(req->ns);
req->ops->queue_response(req);
@@ -848,6 +856,8 @@ bool nvmet_req_init(struct nvmet_req *req, struct nvmet_cq *cq,
req->error_loc = NVMET_NO_ERROR_LOC;
req->error_slba = 0;
+ trace_nvmet_req_init(req, req->cmd);
+
/* no support for fused commands yet */
if (unlikely(flags & (NVME_CMD_FUSE_FIRST | NVME_CMD_FUSE_SECOND))) {
req->error_loc = offsetof(struct nvme_common_command, flags);
@@ -871,7 +881,7 @@ bool nvmet_req_init(struct nvmet_req *req, struct nvmet_cq *cq,
status = nvmet_parse_connect_cmd(req);
else if (likely(req->sq->qid != 0))
status = nvmet_parse_io_cmd(req);
- else if (req->cmd->common.opcode == nvme_fabrics_command)
+ else if (nvme_is_fabrics(req->cmd))
status = nvmet_parse_fabrics_cmd(req);
else if (req->sq->ctrl->subsys->type == NVME_NQN_DISC)
status = nvmet_parse_discovery_cmd(req);
diff --git a/drivers/nvme/target/discovery.c b/drivers/nvme/target/discovery.c
index 5baf269f3f8a..8efca26b4776 100644
--- a/drivers/nvme/target/discovery.c
+++ b/drivers/nvme/target/discovery.c
@@ -41,6 +41,10 @@ void nvmet_port_disc_changed(struct nvmet_port *port,
__nvmet_disc_changed(port, ctrl);
}
mutex_unlock(&nvmet_disc_subsys->lock);
+
+ /* If transport can signal change, notify transport */
+ if (port->tr_ops && port->tr_ops->discovery_chg)
+ port->tr_ops->discovery_chg(port);
}
static void __nvmet_subsys_disc_changed(struct nvmet_port *port,
diff --git a/drivers/nvme/target/fabrics-cmd.c b/drivers/nvme/target/fabrics-cmd.c
index 3b9f79aba98f..d16b55ffe79f 100644
--- a/drivers/nvme/target/fabrics-cmd.c
+++ b/drivers/nvme/target/fabrics-cmd.c
@@ -268,7 +268,7 @@ u16 nvmet_parse_connect_cmd(struct nvmet_req *req)
{
struct nvme_command *cmd = req->cmd;
- if (cmd->common.opcode != nvme_fabrics_command) {
+ if (!nvme_is_fabrics(cmd)) {
pr_err("invalid command 0x%x on unconnected queue.\n",
cmd->fabrics.opcode);
req->error_loc = offsetof(struct nvme_common_command, opcode);
diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c
index 508661af0f50..ce8d819f86cc 100644
--- a/drivers/nvme/target/fc.c
+++ b/drivers/nvme/target/fc.c
@@ -1806,7 +1806,7 @@ nvmet_fc_prep_fcp_rsp(struct nvmet_fc_tgtport *tgtport,
*/
rspcnt = atomic_inc_return(&fod->queue->zrspcnt);
if (!(rspcnt % fod->queue->ersp_ratio) ||
- sqe->opcode == nvme_fabrics_command ||
+ nvme_is_fabrics((struct nvme_command *) sqe) ||
xfr_length != fod->req.transfer_len ||
(le16_to_cpu(cqe->status) & 0xFFFE) || cqewd[0] || cqewd[1] ||
(sqe->flags & (NVME_CMD_FUSE_FIRST | NVME_CMD_FUSE_SECOND)) ||
@@ -2549,6 +2549,16 @@ nvmet_fc_remove_port(struct nvmet_port *port)
kfree(pe);
}
+static void
+nvmet_fc_discovery_chg(struct nvmet_port *port)
+{
+ struct nvmet_fc_port_entry *pe = port->priv;
+ struct nvmet_fc_tgtport *tgtport = pe->tgtport;
+
+ if (tgtport && tgtport->ops->discovery_event)
+ tgtport->ops->discovery_event(&tgtport->fc_target_port);
+}
+
static const struct nvmet_fabrics_ops nvmet_fc_tgt_fcp_ops = {
.owner = THIS_MODULE,
.type = NVMF_TRTYPE_FC,
@@ -2557,6 +2567,7 @@ static const struct nvmet_fabrics_ops nvmet_fc_tgt_fcp_ops = {
.remove_port = nvmet_fc_remove_port,
.queue_response = nvmet_fc_fcp_nvme_cmd_done,
.delete_ctrl = nvmet_fc_delete_ctrl,
+ .discovery_chg = nvmet_fc_discovery_chg,
};
static int __init nvmet_fc_init_module(void)
diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c
index 381b5a90c48b..b50b53db3746 100644
--- a/drivers/nvme/target/fcloop.c
+++ b/drivers/nvme/target/fcloop.c
@@ -231,6 +231,11 @@ struct fcloop_lsreq {
int status;
};
+struct fcloop_rscn {
+ struct fcloop_tport *tport;
+ struct work_struct work;
+};
+
enum {
INI_IO_START = 0,
INI_IO_ACTIVE = 1,
@@ -348,6 +353,37 @@ fcloop_xmt_ls_rsp(struct nvmet_fc_target_port *tport,
return 0;
}
+/*
+ * Simulate reception of RSCN and converting it to a initiator transport
+ * call to rescan a remote port.
+ */
+static void
+fcloop_tgt_rscn_work(struct work_struct *work)
+{
+ struct fcloop_rscn *tgt_rscn =
+ container_of(work, struct fcloop_rscn, work);
+ struct fcloop_tport *tport = tgt_rscn->tport;
+
+ if (tport->remoteport)
+ nvme_fc_rescan_remoteport(tport->remoteport);
+ kfree(tgt_rscn);
+}
+
+static void
+fcloop_tgt_discovery_evt(struct nvmet_fc_target_port *tgtport)
+{
+ struct fcloop_rscn *tgt_rscn;
+
+ tgt_rscn = kzalloc(sizeof(*tgt_rscn), GFP_KERNEL);
+ if (!tgt_rscn)
+ return;
+
+ tgt_rscn->tport = tgtport->private;
+ INIT_WORK(&tgt_rscn->work, fcloop_tgt_rscn_work);
+
+ schedule_work(&tgt_rscn->work);
+}
+
static void
fcloop_tfcp_req_free(struct kref *ref)
{
@@ -398,7 +434,7 @@ fcloop_fcp_recv_work(struct work_struct *work)
int ret = 0;
bool aborted = false;
- spin_lock(&tfcp_req->reqlock);
+ spin_lock_irq(&tfcp_req->reqlock);
switch (tfcp_req->inistate) {
case INI_IO_START:
tfcp_req->inistate = INI_IO_ACTIVE;
@@ -407,11 +443,11 @@ fcloop_fcp_recv_work(struct work_struct *work)
aborted = true;
break;
default:
- spin_unlock(&tfcp_req->reqlock);
+ spin_unlock_irq(&tfcp_req->reqlock);
WARN_ON(1);
return;
}
- spin_unlock(&tfcp_req->reqlock);
+ spin_unlock_irq(&tfcp_req->reqlock);
if (unlikely(aborted))
ret = -ECANCELED;
@@ -433,7 +469,7 @@ fcloop_fcp_abort_recv_work(struct work_struct *work)
struct nvmefc_fcp_req *fcpreq;
bool completed = false;
- spin_lock(&tfcp_req->reqlock);
+ spin_lock_irq(&tfcp_req->reqlock);
fcpreq = tfcp_req->fcpreq;
switch (tfcp_req->inistate) {
case INI_IO_ABORTED:
@@ -442,11 +478,11 @@ fcloop_fcp_abort_recv_work(struct work_struct *work)
completed = true;
break;
default:
- spin_unlock(&tfcp_req->reqlock);
+ spin_unlock_irq(&tfcp_req->reqlock);
WARN_ON(1);
return;
}
- spin_unlock(&tfcp_req->reqlock);
+ spin_unlock_irq(&tfcp_req->reqlock);
if (unlikely(completed)) {
/* remove reference taken in original abort downcall */
@@ -458,9 +494,9 @@ fcloop_fcp_abort_recv_work(struct work_struct *work)
nvmet_fc_rcv_fcp_abort(tfcp_req->tport->targetport,
&tfcp_req->tgt_fcp_req);
- spin_lock(&tfcp_req->reqlock);
+ spin_lock_irq(&tfcp_req->reqlock);
tfcp_req->fcpreq = NULL;
- spin_unlock(&tfcp_req->reqlock);
+ spin_unlock_irq(&tfcp_req->reqlock);
fcloop_call_host_done(fcpreq, tfcp_req, -ECANCELED);
/* call_host_done releases reference for abort downcall */
@@ -477,10 +513,10 @@ fcloop_tgt_fcprqst_done_work(struct work_struct *work)
container_of(work, struct fcloop_fcpreq, tio_done_work);
struct nvmefc_fcp_req *fcpreq;
- spin_lock(&tfcp_req->reqlock);
+ spin_lock_irq(&tfcp_req->reqlock);
fcpreq = tfcp_req->fcpreq;
tfcp_req->inistate = INI_IO_COMPLETED;
- spin_unlock(&tfcp_req->reqlock);
+ spin_unlock_irq(&tfcp_req->reqlock);
fcloop_call_host_done(fcpreq, tfcp_req, tfcp_req->status);
}
@@ -499,7 +535,7 @@ fcloop_fcp_req(struct nvme_fc_local_port *localport,
if (!rport->targetport)
return -ECONNREFUSED;
- tfcp_req = kzalloc(sizeof(*tfcp_req), GFP_KERNEL);
+ tfcp_req = kzalloc(sizeof(*tfcp_req), GFP_ATOMIC);
if (!tfcp_req)
return -ENOMEM;
@@ -585,12 +621,12 @@ fcloop_fcp_op(struct nvmet_fc_target_port *tgtport,
int fcp_err = 0, active, aborted;
u8 op = tgt_fcpreq->op;
- spin_lock(&tfcp_req->reqlock);
+ spin_lock_irq(&tfcp_req->reqlock);
fcpreq = tfcp_req->fcpreq;
active = tfcp_req->active;
aborted = tfcp_req->aborted;
tfcp_req->active = true;
- spin_unlock(&tfcp_req->reqlock);
+ spin_unlock_irq(&tfcp_req->reqlock);
if (unlikely(active))
/* illegal - call while i/o active */
@@ -598,9 +634,9 @@ fcloop_fcp_op(struct nvmet_fc_target_port *tgtport,
if (unlikely(aborted)) {
/* target transport has aborted i/o prior */
- spin_lock(&tfcp_req->reqlock);
+ spin_lock_irq(&tfcp_req->reqlock);
tfcp_req->active = false;
- spin_unlock(&tfcp_req->reqlock);
+ spin_unlock_irq(&tfcp_req->reqlock);
tgt_fcpreq->transferred_length = 0;
tgt_fcpreq->fcp_error = -ECANCELED;
tgt_fcpreq->done(tgt_fcpreq);
@@ -657,9 +693,9 @@ fcloop_fcp_op(struct nvmet_fc_target_port *tgtport,
break;
}
- spin_lock(&tfcp_req->reqlock);
+ spin_lock_irq(&tfcp_req->reqlock);
tfcp_req->active = false;
- spin_unlock(&tfcp_req->reqlock);
+ spin_unlock_irq(&tfcp_req->reqlock);
tgt_fcpreq->transferred_length = xfrlen;
tgt_fcpreq->fcp_error = fcp_err;
@@ -679,9 +715,9 @@ fcloop_tgt_fcp_abort(struct nvmet_fc_target_port *tgtport,
* (one doing io, other doing abort) and only kills ops posted
* after the abort request
*/
- spin_lock(&tfcp_req->reqlock);
+ spin_lock_irq(&tfcp_req->reqlock);
tfcp_req->aborted = true;
- spin_unlock(&tfcp_req->reqlock);
+ spin_unlock_irq(&tfcp_req->reqlock);
tfcp_req->status = NVME_SC_INTERNAL;
@@ -729,7 +765,7 @@ fcloop_fcp_abort(struct nvme_fc_local_port *localport,
return;
/* break initiator/target relationship for io */
- spin_lock(&tfcp_req->reqlock);
+ spin_lock_irq(&tfcp_req->reqlock);
switch (tfcp_req->inistate) {
case INI_IO_START:
case INI_IO_ACTIVE:
@@ -739,11 +775,11 @@ fcloop_fcp_abort(struct nvme_fc_local_port *localport,
abortio = false;
break;
default:
- spin_unlock(&tfcp_req->reqlock);
+ spin_unlock_irq(&tfcp_req->reqlock);
WARN_ON(1);
return;
}
- spin_unlock(&tfcp_req->reqlock);
+ spin_unlock_irq(&tfcp_req->reqlock);
if (abortio)
/* leave the reference while the work item is scheduled */
@@ -839,6 +875,7 @@ static struct nvmet_fc_target_template tgttemplate = {
.fcp_op = fcloop_fcp_op,
.fcp_abort = fcloop_tgt_fcp_abort,
.fcp_req_release = fcloop_fcp_req_release,
+ .discovery_event = fcloop_tgt_discovery_evt,
.max_hw_queues = FCLOOP_HW_QUEUES,
.max_sgl_segments = FCLOOP_SGL_SEGS,
.max_dif_sgl_segments = FCLOOP_SGL_SEGS,
diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
index 7a1cf6437a6a..de0bff70ebb6 100644
--- a/drivers/nvme/target/io-cmd-bdev.c
+++ b/drivers/nvme/target/io-cmd-bdev.c
@@ -8,6 +8,45 @@
#include <linux/module.h>
#include "nvmet.h"
+void nvmet_bdev_set_limits(struct block_device *bdev, struct nvme_id_ns *id)
+{
+ const struct queue_limits *ql = &bdev_get_queue(bdev)->limits;
+ /* Number of physical blocks per logical block. */
+ const u32 ppl = ql->physical_block_size / ql->logical_block_size;
+ /* Physical blocks per logical block, 0's based. */
+ const __le16 ppl0b = to0based(ppl);
+
+ /*
+ * For NVMe 1.2 and later, bit 1 indicates that the fields NAWUN,
+ * NAWUPF, and NACWU are defined for this namespace and should be
+ * used by the host for this namespace instead of the AWUN, AWUPF,
+ * and ACWU fields in the Identify Controller data structure. If
+ * any of these fields are zero that means that the corresponding
+ * field from the identify controller data structure should be used.
+ */
+ id->nsfeat |= 1 << 1;
+ id->nawun = ppl0b;
+ id->nawupf = ppl0b;
+ id->nacwu = ppl0b;
+
+ /*
+ * Bit 4 indicates that the fields NPWG, NPWA, NPDG, NPDA, and
+ * NOWS are defined for this namespace and should be used by
+ * the host for I/O optimization.
+ */
+ id->nsfeat |= 1 << 4;
+ /* NPWG = Namespace Preferred Write Granularity. 0's based */
+ id->npwg = ppl0b;
+ /* NPWA = Namespace Preferred Write Alignment. 0's based */
+ id->npwa = id->npwg;
+ /* NPDG = Namespace Preferred Deallocate Granularity. 0's based */
+ id->npdg = to0based(ql->discard_granularity / ql->logical_block_size);
+ /* NPDG = Namespace Preferred Deallocate Alignment */
+ id->npda = id->npdg;
+ /* NOWS = Namespace Optimal Write Size */
+ id->nows = to0based(ql->io_opt / ql->logical_block_size);
+}
+
int nvmet_bdev_ns_enable(struct nvmet_ns *ns)
{
int ret;
diff --git a/drivers/nvme/target/loop.c b/drivers/nvme/target/loop.c
index 9e211ad6bdd3..b16dc3981c69 100644
--- a/drivers/nvme/target/loop.c
+++ b/drivers/nvme/target/loop.c
@@ -77,7 +77,7 @@ static void nvme_loop_complete_rq(struct request *req)
struct nvme_loop_iod *iod = blk_mq_rq_to_pdu(req);
nvme_cleanup_cmd(req);
- sg_free_table_chained(&iod->sg_table, true);
+ sg_free_table_chained(&iod->sg_table, SG_CHUNK_SIZE);
nvme_complete_rq(req);
}
@@ -157,7 +157,7 @@ static blk_status_t nvme_loop_queue_rq(struct blk_mq_hw_ctx *hctx,
iod->sg_table.sgl = iod->first_sgl;
if (sg_alloc_table_chained(&iod->sg_table,
blk_rq_nr_phys_segments(req),
- iod->sg_table.sgl))
+ iod->sg_table.sgl, SG_CHUNK_SIZE))
return BLK_STS_RESOURCE;
iod->req.sg = iod->sg_table.sgl;
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index c25d88fc9dec..6ee66c610739 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -140,6 +140,7 @@ struct nvmet_port {
void *priv;
bool enabled;
int inline_data_size;
+ const struct nvmet_fabrics_ops *tr_ops;
};
static inline struct nvmet_port *to_nvmet_port(struct config_item *item)
@@ -277,6 +278,7 @@ struct nvmet_fabrics_ops {
void (*disc_traddr)(struct nvmet_req *req,
struct nvmet_port *port, char *traddr);
u16 (*install_queue)(struct nvmet_sq *nvme_sq);
+ void (*discovery_chg)(struct nvmet_port *port);
};
#define NVMET_MAX_INLINE_BIOVEC 8
@@ -363,6 +365,7 @@ u16 nvmet_set_feat_async_event(struct nvmet_req *req, u32 mask);
void nvmet_execute_async_event(struct nvmet_req *req);
u16 nvmet_parse_connect_cmd(struct nvmet_req *req);
+void nvmet_bdev_set_limits(struct block_device *bdev, struct nvme_id_ns *id);
u16 nvmet_bdev_parse_io_cmd(struct nvmet_req *req);
u16 nvmet_file_parse_io_cmd(struct nvmet_req *req);
u16 nvmet_parse_admin_cmd(struct nvmet_req *req);
@@ -490,4 +493,11 @@ static inline u32 nvmet_rw_len(struct nvmet_req *req)
}
u16 errno_to_nvme_status(struct nvmet_req *req, int errno);
+
+/* Convert a 32-bit number to a 16-bit 0's based number */
+static inline __le16 to0based(u32 a)
+{
+ return cpu_to_le16(max(1U, min(1U << 16, a)) - 1);
+}
+
#endif /* _NVMET_H */
diff --git a/drivers/nvme/target/trace.c b/drivers/nvme/target/trace.c
new file mode 100644
index 000000000000..6af11d493271
--- /dev/null
+++ b/drivers/nvme/target/trace.c
@@ -0,0 +1,201 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * NVM Express target device driver tracepoints
+ * Copyright (c) 2018 Johannes Thumshirn, SUSE Linux GmbH
+ */
+
+#include <asm/unaligned.h>
+#include "trace.h"
+
+static const char *nvmet_trace_admin_identify(struct trace_seq *p, u8 *cdw10)
+{
+ const char *ret = trace_seq_buffer_ptr(p);
+ u8 cns = cdw10[0];
+ u16 ctrlid = get_unaligned_le16(cdw10 + 2);
+
+ trace_seq_printf(p, "cns=%u, ctrlid=%u", cns, ctrlid);
+ trace_seq_putc(p, 0);
+
+ return ret;
+}
+
+static const char *nvmet_trace_admin_get_features(struct trace_seq *p,
+ u8 *cdw10)
+{
+ const char *ret = trace_seq_buffer_ptr(p);
+ u8 fid = cdw10[0];
+ u8 sel = cdw10[1] & 0x7;
+ u32 cdw11 = get_unaligned_le32(cdw10 + 4);
+
+ trace_seq_printf(p, "fid=0x%x sel=0x%x cdw11=0x%x", fid, sel, cdw11);
+ trace_seq_putc(p, 0);
+
+ return ret;
+}
+
+static const char *nvmet_trace_read_write(struct trace_seq *p, u8 *cdw10)
+{
+ const char *ret = trace_seq_buffer_ptr(p);
+ u64 slba = get_unaligned_le64(cdw10);
+ u16 length = get_unaligned_le16(cdw10 + 8);
+ u16 control = get_unaligned_le16(cdw10 + 10);
+ u32 dsmgmt = get_unaligned_le32(cdw10 + 12);
+ u32 reftag = get_unaligned_le32(cdw10 + 16);
+
+ trace_seq_printf(p,
+ "slba=%llu, len=%u, ctrl=0x%x, dsmgmt=%u, reftag=%u",
+ slba, length, control, dsmgmt, reftag);
+ trace_seq_putc(p, 0);
+
+ return ret;
+}
+
+static const char *nvmet_trace_dsm(struct trace_seq *p, u8 *cdw10)
+{
+ const char *ret = trace_seq_buffer_ptr(p);
+
+ trace_seq_printf(p, "nr=%u, attributes=%u",
+ get_unaligned_le32(cdw10),
+ get_unaligned_le32(cdw10 + 4));
+ trace_seq_putc(p, 0);
+
+ return ret;
+}
+
+static const char *nvmet_trace_common(struct trace_seq *p, u8 *cdw10)
+{
+ const char *ret = trace_seq_buffer_ptr(p);
+
+ trace_seq_printf(p, "cdw10=%*ph", 24, cdw10);
+ trace_seq_putc(p, 0);
+
+ return ret;
+}
+
+const char *nvmet_trace_parse_admin_cmd(struct trace_seq *p,
+ u8 opcode, u8 *cdw10)
+{
+ switch (opcode) {
+ case nvme_admin_identify:
+ return nvmet_trace_admin_identify(p, cdw10);
+ case nvme_admin_get_features:
+ return nvmet_trace_admin_get_features(p, cdw10);
+ default:
+ return nvmet_trace_common(p, cdw10);
+ }
+}
+
+const char *nvmet_trace_parse_nvm_cmd(struct trace_seq *p,
+ u8 opcode, u8 *cdw10)
+{
+ switch (opcode) {
+ case nvme_cmd_read:
+ case nvme_cmd_write:
+ case nvme_cmd_write_zeroes:
+ return nvmet_trace_read_write(p, cdw10);
+ case nvme_cmd_dsm:
+ return nvmet_trace_dsm(p, cdw10);
+ default:
+ return nvmet_trace_common(p, cdw10);
+ }
+}
+
+static const char *nvmet_trace_fabrics_property_set(struct trace_seq *p,
+ u8 *spc)
+{
+ const char *ret = trace_seq_buffer_ptr(p);
+ u8 attrib = spc[0];
+ u32 ofst = get_unaligned_le32(spc + 4);
+ u64 value = get_unaligned_le64(spc + 8);
+
+ trace_seq_printf(p, "attrib=%u, ofst=0x%x, value=0x%llx",
+ attrib, ofst, value);
+ trace_seq_putc(p, 0);
+ return ret;
+}
+
+static const char *nvmet_trace_fabrics_connect(struct trace_seq *p,
+ u8 *spc)
+{
+ const char *ret = trace_seq_buffer_ptr(p);
+ u16 recfmt = get_unaligned_le16(spc);
+ u16 qid = get_unaligned_le16(spc + 2);
+ u16 sqsize = get_unaligned_le16(spc + 4);
+ u8 cattr = spc[6];
+ u32 kato = get_unaligned_le32(spc + 8);
+
+ trace_seq_printf(p, "recfmt=%u, qid=%u, sqsize=%u, cattr=%u, kato=%u",
+ recfmt, qid, sqsize, cattr, kato);
+ trace_seq_putc(p, 0);
+ return ret;
+}
+
+static const char *nvmet_trace_fabrics_property_get(struct trace_seq *p,
+ u8 *spc)
+{
+ const char *ret = trace_seq_buffer_ptr(p);
+ u8 attrib = spc[0];
+ u32 ofst = get_unaligned_le32(spc + 4);
+
+ trace_seq_printf(p, "attrib=%u, ofst=0x%x", attrib, ofst);
+ trace_seq_putc(p, 0);
+ return ret;
+}
+
+static const char *nvmet_trace_fabrics_common(struct trace_seq *p, u8 *spc)
+{
+ const char *ret = trace_seq_buffer_ptr(p);
+
+ trace_seq_printf(p, "specific=%*ph", 24, spc);
+ trace_seq_putc(p, 0);
+ return ret;
+}
+
+const char *nvmet_trace_parse_fabrics_cmd(struct trace_seq *p,
+ u8 fctype, u8 *spc)
+{
+ switch (fctype) {
+ case nvme_fabrics_type_property_set:
+ return nvmet_trace_fabrics_property_set(p, spc);
+ case nvme_fabrics_type_connect:
+ return nvmet_trace_fabrics_connect(p, spc);
+ case nvme_fabrics_type_property_get:
+ return nvmet_trace_fabrics_property_get(p, spc);
+ default:
+ return nvmet_trace_fabrics_common(p, spc);
+ }
+}
+
+const char *nvmet_trace_disk_name(struct trace_seq *p, char *name)
+{
+ const char *ret = trace_seq_buffer_ptr(p);
+
+ if (*name)
+ trace_seq_printf(p, "disk=%s, ", name);
+ trace_seq_putc(p, 0);
+
+ return ret;
+}
+
+const char *nvmet_trace_ctrl_name(struct trace_seq *p, struct nvmet_ctrl *ctrl)
+{
+ const char *ret = trace_seq_buffer_ptr(p);
+
+ /*
+ * XXX: We don't know the controller instance before executing the
+ * connect command itself because the connect command for the admin
+ * queue will not provide the cntlid which will be allocated in this
+ * command. In case of io queues, the controller instance will be
+ * mapped by the extra data of the connect command.
+ * If we can know the extra data of the connect command in this stage,
+ * we can update this print statement later.
+ */
+ if (ctrl)
+ trace_seq_printf(p, "%d", ctrl->cntlid);
+ else
+ trace_seq_printf(p, "_");
+ trace_seq_putc(p, 0);
+
+ return ret;
+}
+
diff --git a/drivers/nvme/target/trace.h b/drivers/nvme/target/trace.h
new file mode 100644
index 000000000000..e645caa882dd
--- /dev/null
+++ b/drivers/nvme/target/trace.h
@@ -0,0 +1,141 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * NVM Express target device driver tracepoints
+ * Copyright (c) 2018 Johannes Thumshirn, SUSE Linux GmbH
+ *
+ * This is entirely based on drivers/nvme/host/trace.h
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM nvmet
+
+#if !defined(_TRACE_NVMET_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_NVMET_H
+
+#include <linux/nvme.h>
+#include <linux/tracepoint.h>
+#include <linux/trace_seq.h>
+
+#include "nvmet.h"
+
+const char *nvmet_trace_parse_admin_cmd(struct trace_seq *p, u8 opcode,
+ u8 *cdw10);
+const char *nvmet_trace_parse_nvm_cmd(struct trace_seq *p, u8 opcode,
+ u8 *cdw10);
+const char *nvmet_trace_parse_fabrics_cmd(struct trace_seq *p, u8 fctype,
+ u8 *spc);
+
+#define parse_nvme_cmd(qid, opcode, fctype, cdw10) \
+ ((opcode) == nvme_fabrics_command ? \
+ nvmet_trace_parse_fabrics_cmd(p, fctype, cdw10) : \
+ (qid ? \
+ nvmet_trace_parse_nvm_cmd(p, opcode, cdw10) : \
+ nvmet_trace_parse_admin_cmd(p, opcode, cdw10)))
+
+const char *nvmet_trace_ctrl_name(struct trace_seq *p, struct nvmet_ctrl *ctrl);
+#define __print_ctrl_name(ctrl) \
+ nvmet_trace_ctrl_name(p, ctrl)
+
+const char *nvmet_trace_disk_name(struct trace_seq *p, char *name);
+#define __print_disk_name(name) \
+ nvmet_trace_disk_name(p, name)
+
+#ifndef TRACE_HEADER_MULTI_READ
+static inline struct nvmet_ctrl *nvmet_req_to_ctrl(struct nvmet_req *req)
+{
+ return req->sq->ctrl;
+}
+
+static inline void __assign_disk_name(char *name, struct nvmet_req *req,
+ bool init)
+{
+ struct nvmet_ctrl *ctrl = nvmet_req_to_ctrl(req);
+ struct nvmet_ns *ns;
+
+ if ((init && req->sq->qid) || (!init && req->cq->qid)) {
+ ns = nvmet_find_namespace(ctrl, req->cmd->rw.nsid);
+ strncpy(name, ns->device_path, DISK_NAME_LEN);
+ return;
+ }
+
+ memset(name, 0, DISK_NAME_LEN);
+}
+#endif
+
+TRACE_EVENT(nvmet_req_init,
+ TP_PROTO(struct nvmet_req *req, struct nvme_command *cmd),
+ TP_ARGS(req, cmd),
+ TP_STRUCT__entry(
+ __field(struct nvme_command *, cmd)
+ __field(struct nvmet_ctrl *, ctrl)
+ __array(char, disk, DISK_NAME_LEN)
+ __field(int, qid)
+ __field(u16, cid)
+ __field(u8, opcode)
+ __field(u8, fctype)
+ __field(u8, flags)
+ __field(u32, nsid)
+ __field(u64, metadata)
+ __array(u8, cdw10, 24)
+ ),
+ TP_fast_assign(
+ __entry->cmd = cmd;
+ __entry->ctrl = nvmet_req_to_ctrl(req);
+ __assign_disk_name(__entry->disk, req, true);
+ __entry->qid = req->sq->qid;
+ __entry->cid = cmd->common.command_id;
+ __entry->opcode = cmd->common.opcode;
+ __entry->fctype = cmd->fabrics.fctype;
+ __entry->flags = cmd->common.flags;
+ __entry->nsid = le32_to_cpu(cmd->common.nsid);
+ __entry->metadata = le64_to_cpu(cmd->common.metadata);
+ memcpy(__entry->cdw10, &cmd->common.cdw10,
+ sizeof(__entry->cdw10));
+ ),
+ TP_printk("nvmet%s: %sqid=%d, cmdid=%u, nsid=%u, flags=%#x, "
+ "meta=%#llx, cmd=(%s, %s)",
+ __print_ctrl_name(__entry->ctrl),
+ __print_disk_name(__entry->disk),
+ __entry->qid, __entry->cid, __entry->nsid,
+ __entry->flags, __entry->metadata,
+ show_opcode_name(__entry->qid, __entry->opcode,
+ __entry->fctype),
+ parse_nvme_cmd(__entry->qid, __entry->opcode,
+ __entry->fctype, __entry->cdw10))
+);
+
+TRACE_EVENT(nvmet_req_complete,
+ TP_PROTO(struct nvmet_req *req),
+ TP_ARGS(req),
+ TP_STRUCT__entry(
+ __field(struct nvmet_ctrl *, ctrl)
+ __array(char, disk, DISK_NAME_LEN)
+ __field(int, qid)
+ __field(int, cid)
+ __field(u64, result)
+ __field(u16, status)
+ ),
+ TP_fast_assign(
+ __entry->ctrl = nvmet_req_to_ctrl(req);
+ __entry->qid = req->cq->qid;
+ __entry->cid = req->cqe->command_id;
+ __entry->result = le64_to_cpu(req->cqe->result.u64);
+ __entry->status = le16_to_cpu(req->cqe->status) >> 1;
+ __assign_disk_name(__entry->disk, req, false);
+ ),
+ TP_printk("nvmet%s: %sqid=%d, cmdid=%u, res=%#llx, status=%#x",
+ __print_ctrl_name(__entry->ctrl),
+ __print_disk_name(__entry->disk),
+ __entry->qid, __entry->cid, __entry->result, __entry->status)
+
+);
+
+#endif /* _TRACE_NVMET_H */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index afa4335e0a20..c2ec750cae6e 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -47,6 +47,13 @@ config NVMEM_IMX_OCOTP
This driver can also be built as a module. If so, the module
will be called nvmem-imx-ocotp.
+config NVMEM_IMX_OCOTP_SCU
+ tristate "i.MX8 SCU On-Chip OTP Controller support"
+ depends on IMX_SCU
+ help
+ This is a driver for the SCU On-Chip OTP Controller (OCOTP)
+ available on i.MX8 SoCs.
+
config NVMEM_LPC18XX_EEPROM
tristate "NXP LPC18XX EEPROM Memory Support"
depends on ARCH_LPC18XX || COMPILE_TEST
@@ -188,7 +195,7 @@ config MESON_MX_EFUSE
config NVMEM_SNVS_LPGPR
tristate "Support for Low Power General Purpose Register"
- depends on SOC_IMX6 || SOC_IMX7D || COMPILE_TEST
+ depends on ARCH_MXC || COMPILE_TEST
help
This is a driver for Low Power General Purpose Register (LPGPR) available on
i.MX6 and i.MX7 SoCs in Secure Non-Volatile Storage (SNVS) of this chip.
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index c1fe4768dfef..e5c153d99a67 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -16,6 +16,8 @@ obj-$(CONFIG_NVMEM_IMX_IIM) += nvmem-imx-iim.o
nvmem-imx-iim-y := imx-iim.o
obj-$(CONFIG_NVMEM_IMX_OCOTP) += nvmem-imx-ocotp.o
nvmem-imx-ocotp-y := imx-ocotp.o
+obj-$(CONFIG_NVMEM_IMX_OCOTP_SCU) += nvmem-imx-ocotp-scu.o
+nvmem-imx-ocotp-scu-y := imx-ocotp-scu.o
obj-$(CONFIG_NVMEM_LPC18XX_EEPROM) += nvmem_lpc18xx_eeprom.o
nvmem_lpc18xx_eeprom-y := lpc18xx_eeprom.o
obj-$(CONFIG_NVMEM_LPC18XX_OTP) += nvmem_lpc18xx_otp.o
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index c7892c3da91f..ac5d945be88a 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -76,7 +76,7 @@ static struct bus_type nvmem_bus_type = {
.name = "nvmem",
};
-static int of_nvmem_match(struct device *dev, void *nvmem_np)
+static int of_nvmem_match(struct device *dev, const void *nvmem_np)
{
return dev->of_node == nvmem_np;
}
diff --git a/drivers/nvmem/imx-iim.c b/drivers/nvmem/imx-iim.c
index 34582293b985..701704b87dc9 100644
--- a/drivers/nvmem/imx-iim.c
+++ b/drivers/nvmem/imx-iim.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* i.MX IIM driver
*
@@ -6,13 +7,6 @@
* Based on the barebox iim driver,
* Copyright (c) 2010 Baruch Siach <baruch@tkos.co.il>,
* Orex Computed Radiography
- *
- * 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.
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
*/
#include <linux/device.h>
diff --git a/drivers/nvmem/imx-ocotp-scu.c b/drivers/nvmem/imx-ocotp-scu.c
new file mode 100644
index 000000000000..d9dc482ecb2f
--- /dev/null
+++ b/drivers/nvmem/imx-ocotp-scu.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * i.MX8 OCOTP fusebox driver
+ *
+ * Copyright 2019 NXP
+ *
+ * Peng Fan <peng.fan@nxp.com>
+ */
+
+#include <linux/firmware/imx/sci.h>
+#include <linux/module.h>
+#include <linux/nvmem-provider.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+enum ocotp_devtype {
+ IMX8QXP,
+};
+
+struct ocotp_devtype_data {
+ int devtype;
+ int nregs;
+};
+
+struct ocotp_priv {
+ struct device *dev;
+ const struct ocotp_devtype_data *data;
+ struct imx_sc_ipc *nvmem_ipc;
+};
+
+struct imx_sc_msg_misc_fuse_read {
+ struct imx_sc_rpc_msg hdr;
+ u32 word;
+} __packed;
+
+static struct ocotp_devtype_data imx8qxp_data = {
+ .devtype = IMX8QXP,
+ .nregs = 800,
+};
+
+static int imx_sc_misc_otp_fuse_read(struct imx_sc_ipc *ipc, u32 word,
+ u32 *val)
+{
+ struct imx_sc_msg_misc_fuse_read msg;
+ struct imx_sc_rpc_msg *hdr = &msg.hdr;
+ int ret;
+
+ hdr->ver = IMX_SC_RPC_VERSION;
+ hdr->svc = IMX_SC_RPC_SVC_MISC;
+ hdr->func = IMX_SC_MISC_FUNC_OTP_FUSE_READ;
+ hdr->size = 2;
+
+ msg.word = word;
+
+ ret = imx_scu_call_rpc(ipc, &msg, true);
+ if (ret)
+ return ret;
+
+ *val = msg.word;
+
+ return 0;
+}
+
+static int imx_scu_ocotp_read(void *context, unsigned int offset,
+ void *val, size_t bytes)
+{
+ struct ocotp_priv *priv = context;
+ u32 count, index, num_bytes;
+ u32 *buf;
+ void *p;
+ int i, ret;
+
+ index = offset >> 2;
+ num_bytes = round_up((offset % 4) + bytes, 4);
+ count = num_bytes >> 2;
+
+ if (count > (priv->data->nregs - index))
+ count = priv->data->nregs - index;
+
+ p = kzalloc(num_bytes, GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ buf = p;
+
+ for (i = index; i < (index + count); i++) {
+ if (priv->data->devtype == IMX8QXP) {
+ if ((i > 271) && (i < 544)) {
+ *buf++ = 0;
+ continue;
+ }
+ }
+
+ ret = imx_sc_misc_otp_fuse_read(priv->nvmem_ipc, i, buf);
+ if (ret) {
+ kfree(p);
+ return ret;
+ }
+ buf++;
+ }
+
+ memcpy(val, (u8 *)p + offset % 4, bytes);
+
+ kfree(p);
+
+ return 0;
+}
+
+static struct nvmem_config imx_scu_ocotp_nvmem_config = {
+ .name = "imx-scu-ocotp",
+ .read_only = true,
+ .word_size = 4,
+ .stride = 1,
+ .owner = THIS_MODULE,
+ .reg_read = imx_scu_ocotp_read,
+};
+
+static const struct of_device_id imx_scu_ocotp_dt_ids[] = {
+ { .compatible = "fsl,imx8qxp-scu-ocotp", (void *)&imx8qxp_data },
+ { },
+};
+MODULE_DEVICE_TABLE(of, imx_scu_ocotp_dt_ids);
+
+static int imx_scu_ocotp_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ocotp_priv *priv;
+ struct nvmem_device *nvmem;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ ret = imx_scu_get_handle(&priv->nvmem_ipc);
+ if (ret)
+ return ret;
+
+ priv->data = of_device_get_match_data(dev);
+ priv->dev = dev;
+ imx_scu_ocotp_nvmem_config.size = 4 * priv->data->nregs;
+ imx_scu_ocotp_nvmem_config.dev = dev;
+ imx_scu_ocotp_nvmem_config.priv = priv;
+ nvmem = devm_nvmem_register(dev, &imx_scu_ocotp_nvmem_config);
+
+ return PTR_ERR_OR_ZERO(nvmem);
+}
+
+static struct platform_driver imx_scu_ocotp_driver = {
+ .probe = imx_scu_ocotp_probe,
+ .driver = {
+ .name = "imx_scu_ocotp",
+ .of_match_table = imx_scu_ocotp_dt_ids,
+ },
+};
+module_platform_driver(imx_scu_ocotp_driver);
+
+MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
+MODULE_DESCRIPTION("i.MX8 SCU OCOTP fuse box driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
index 4cf7b61e4bf5..42d4451e7d67 100644
--- a/drivers/nvmem/imx-ocotp.c
+++ b/drivers/nvmem/imx-ocotp.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* i.MX6 OCOTP fusebox driver
*
@@ -9,13 +10,6 @@
*
* Write support based on the fsl_otp driver,
* Copyright (C) 2010-2013 Freescale Semiconductor, 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.
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
*/
#include <linux/clk.h>
@@ -45,12 +39,14 @@
#define IMX_OCOTP_ADDR_DATA2 0x0040
#define IMX_OCOTP_ADDR_DATA3 0x0050
-#define IMX_OCOTP_BM_CTRL_ADDR 0x0000007F
+#define IMX_OCOTP_BM_CTRL_ADDR 0x000000FF
#define IMX_OCOTP_BM_CTRL_BUSY 0x00000100
#define IMX_OCOTP_BM_CTRL_ERROR 0x00000200
#define IMX_OCOTP_BM_CTRL_REL_SHADOWS 0x00000400
-#define DEF_RELAX 20 /* > 16.5ns */
+#define TIMING_STROBE_PROG_US 10 /* Min time to blow a fuse */
+#define TIMING_STROBE_READ_NS 37 /* Min time before read */
+#define TIMING_RELAX_NS 17
#define DEF_FSOURCE 1001 /* > 1000 ns */
#define DEF_STROBE_PROG 10000 /* IPG clocks */
#define IMX_OCOTP_WR_UNLOCK 0x3E770000
@@ -182,14 +178,41 @@ static void imx_ocotp_set_imx6_timing(struct ocotp_priv *priv)
* fields with timing values to match the current frequency of the
* ipg_clk. OTP writes will work at maximum bus frequencies as long
* as the HW_OCOTP_TIMING parameters are set correctly.
+ *
+ * Note: there are minimum timings required to ensure an OTP fuse burns
+ * correctly that are independent of the ipg_clk. Those values are not
+ * formally documented anywhere however, working from the minimum
+ * timings given in u-boot we can say:
+ *
+ * - Minimum STROBE_PROG time is 10 microseconds. Intuitively 10
+ * microseconds feels about right as representative of a minimum time
+ * to physically burn out a fuse.
+ *
+ * - Minimum STROBE_READ i.e. the time to wait post OTP fuse burn before
+ * performing another read is 37 nanoseconds
+ *
+ * - Minimum RELAX timing is 17 nanoseconds. This final RELAX minimum
+ * timing is not entirely clear the documentation says "This
+ * count value specifies the time to add to all default timing
+ * parameters other than the Tpgm and Trd. It is given in number
+ * of ipg_clk periods." where Tpgm and Trd refer to STROBE_PROG
+ * and STROBE_READ respectively. What the other timing parameters
+ * are though, is not specified. Experience shows a zero RELAX
+ * value will mess up a re-load of the shadow registers post OTP
+ * burn.
*/
clk_rate = clk_get_rate(priv->clk);
- relax = clk_rate / (1000000000 / DEF_RELAX) - 1;
- strobe_prog = clk_rate / (1000000000 / 10000) + 2 * (DEF_RELAX + 1) - 1;
- strobe_read = clk_rate / (1000000000 / 40) + 2 * (DEF_RELAX + 1) - 1;
+ relax = DIV_ROUND_UP(clk_rate * TIMING_RELAX_NS, 1000000000) - 1;
+ strobe_read = DIV_ROUND_UP(clk_rate * TIMING_STROBE_READ_NS,
+ 1000000000);
+ strobe_read += 2 * (relax + 1) - 1;
+ strobe_prog = DIV_ROUND_CLOSEST(clk_rate * TIMING_STROBE_PROG_US,
+ 1000000);
+ strobe_prog += 2 * (relax + 1) - 1;
- timing = strobe_prog & 0x00000FFF;
+ timing = readl(priv->base + IMX_OCOTP_ADDR_TIMING) & 0x0FC00000;
+ timing |= strobe_prog & 0x00000FFF;
timing |= (relax << 12) & 0x0000F000;
timing |= (strobe_read << 16) & 0x003F0000;
@@ -446,8 +469,14 @@ static const struct ocotp_params imx7ulp_params = {
static const struct ocotp_params imx8mq_params = {
.nregs = 256,
- .bank_address_words = 4,
- .set_timing = imx_ocotp_set_imx7_timing,
+ .bank_address_words = 0,
+ .set_timing = imx_ocotp_set_imx6_timing,
+};
+
+static const struct ocotp_params imx8mm_params = {
+ .nregs = 256,
+ .bank_address_words = 0,
+ .set_timing = imx_ocotp_set_imx6_timing,
};
static const struct of_device_id imx_ocotp_dt_ids[] = {
@@ -460,6 +489,7 @@ static const struct of_device_id imx_ocotp_dt_ids[] = {
{ .compatible = "fsl,imx6sll-ocotp", .data = &imx6sll_params },
{ .compatible = "fsl,imx7ulp-ocotp", .data = &imx7ulp_params },
{ .compatible = "fsl,imx8mq-ocotp", .data = &imx8mq_params },
+ { .compatible = "fsl,imx8mm-ocotp", .data = &imx8mm_params },
{ },
};
MODULE_DEVICE_TABLE(of, imx_ocotp_dt_ids);
diff --git a/drivers/nvmem/lpc18xx_eeprom.c b/drivers/nvmem/lpc18xx_eeprom.c
index 66cff1e2147a..a0275b29afd5 100644
--- a/drivers/nvmem/lpc18xx_eeprom.c
+++ b/drivers/nvmem/lpc18xx_eeprom.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* NXP LPC18xx/LPC43xx EEPROM memory NVMEM driver
*
* Copyright (c) 2015 Ariel D'Alessandro <ariel@vanguardiasur.com>
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/nvmem/lpc18xx_otp.c b/drivers/nvmem/lpc18xx_otp.c
index 549b5298ac4c..16c92ea85d49 100644
--- a/drivers/nvmem/lpc18xx_otp.c
+++ b/drivers/nvmem/lpc18xx_otp.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* NXP LPC18xx/43xx OTP memory NVMEM driver
*
@@ -6,10 +7,6 @@
* Based on the imx ocotp driver,
* Copyright (c) 2015 Pengutronix, Philipp Zabel <p.zabel@pengutronix.de>
*
- * 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.
- *
* TODO: add support for writing OTP register via API in boot ROM.
*/
diff --git a/drivers/nvmem/snvs_lpgpr.c b/drivers/nvmem/snvs_lpgpr.c
index c050a23a9f2b..c527d26ca6ac 100644
--- a/drivers/nvmem/snvs_lpgpr.c
+++ b/drivers/nvmem/snvs_lpgpr.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2015 Pengutronix, Steffen Trumtrar <kernel@pengutronix.de>
* Copyright (c) 2017 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
- *
- * 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.
*/
#include <linux/mfd/syscon.h>
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 20e0e7ee4edf..55e7f5bb0549 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -2294,8 +2294,12 @@ int of_map_rid(struct device_node *np, u32 rid,
return 0;
}
- pr_err("%pOF: Invalid %s translation - no match for rid 0x%x on %pOF\n",
- np, map_name, rid, target && *target ? *target : NULL);
- return -EFAULT;
+ pr_info("%pOF: no %s translation for rid 0x%x on %pOF\n", np, map_name,
+ rid, target && *target ? *target : NULL);
+
+ /* Bypasses translation */
+ if (id_out)
+ *id_out = rid;
+ return 0;
}
EXPORT_SYMBOL_GPL(of_map_rid);
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index de893c9616a1..9cdf14b9aaab 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -38,7 +38,7 @@
* memory entries in the /memory node. This function may be called
* any time after initial_boot_param is set.
*/
-void of_fdt_limit_memory(int limit)
+void __init of_fdt_limit_memory(int limit)
{
int memory;
int len;
@@ -78,57 +78,6 @@ void of_fdt_limit_memory(int limit)
}
}
-/**
- * of_fdt_is_compatible - Return true if given node from the given blob has
- * compat in its compatible list
- * @blob: A device tree blob
- * @node: node to test
- * @compat: compatible string to compare with compatible list.
- *
- * On match, returns a non-zero value with smaller values returned for more
- * specific compatible values.
- */
-static int of_fdt_is_compatible(const void *blob,
- unsigned long node, const char *compat)
-{
- const char *cp;
- int cplen;
- unsigned long l, score = 0;
-
- cp = fdt_getprop(blob, node, "compatible", &cplen);
- if (cp == NULL)
- return 0;
- while (cplen > 0) {
- score++;
- if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
- return score;
- l = strlen(cp) + 1;
- cp += l;
- cplen -= l;
- }
-
- return 0;
-}
-
-/**
- * of_fdt_is_big_endian - Return true if given node needs BE MMIO accesses
- * @blob: A device tree blob
- * @node: node to test
- *
- * Returns true if the node has a "big-endian" property, or if the kernel
- * was compiled for BE *and* the node has a "native-endian" property.
- * Returns false otherwise.
- */
-bool of_fdt_is_big_endian(const void *blob, unsigned long node)
-{
- if (fdt_getprop(blob, node, "big-endian", NULL))
- return true;
- if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) &&
- fdt_getprop(blob, node, "native-endian", NULL))
- return true;
- return false;
-}
-
static bool of_fdt_device_is_available(const void *blob, unsigned long node)
{
const char *status = fdt_getprop(blob, node, "status", NULL);
@@ -142,27 +91,6 @@ static bool of_fdt_device_is_available(const void *blob, unsigned long node)
return false;
}
-/**
- * of_fdt_match - Return true if node matches a list of compatible values
- */
-int of_fdt_match(const void *blob, unsigned long node,
- const char *const *compat)
-{
- unsigned int tmp, score = 0;
-
- if (!compat)
- return 0;
-
- while (*compat) {
- tmp = of_fdt_is_compatible(blob, node, *compat);
- if (tmp && (score == 0 || (tmp < score)))
- score = tmp;
- compat++;
- }
-
- return score;
-}
-
static void *unflatten_dt_alloc(void **mem, unsigned long size,
unsigned long align)
{
@@ -535,7 +463,7 @@ EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree);
int __initdata dt_root_addr_cells;
int __initdata dt_root_size_cells;
-void *initial_boot_params;
+void *initial_boot_params __ro_after_init;
#ifdef CONFIG_OF_EARLY_FLATTREE
@@ -551,7 +479,8 @@ static int __init __reserved_mem_reserve_reg(unsigned long node,
phys_addr_t base, size;
int len;
const __be32 *prop;
- int nomap, first = 1;
+ int first = 1;
+ bool nomap;
prop = of_get_flat_dt_prop(node, "reg", &len);
if (!prop)
@@ -666,7 +595,7 @@ void __init early_init_fdt_scan_reserved_mem(void)
fdt_get_mem_rsv(initial_boot_params, n, &base, &size);
if (!size)
break;
- early_init_dt_reserve_memory_arch(base, size, 0);
+ early_init_dt_reserve_memory_arch(base, size, false);
}
of_scan_flat_dt(__fdt_scan_reserved_mem, NULL);
@@ -684,7 +613,7 @@ void __init early_init_fdt_reserve_self(void)
/* Reserve the dtb region */
early_init_dt_reserve_memory_arch(__pa(initial_boot_params),
fdt_totalsize(initial_boot_params),
- 0);
+ false);
}
/**
@@ -758,7 +687,7 @@ int __init of_scan_flat_dt_subnodes(unsigned long parent,
* @return offset of the subnode, or -FDT_ERR_NOTFOUND if there is none
*/
-int of_get_flat_dt_subnode_by_name(unsigned long node, const char *uname)
+int __init of_get_flat_dt_subnode_by_name(unsigned long node, const char *uname)
{
return fdt_subnode_offset(initial_boot_params, node, uname);
}
@@ -772,14 +701,6 @@ unsigned long __init of_get_flat_dt_root(void)
}
/**
- * of_get_flat_dt_size - Return the total size of the FDT
- */
-int __init of_get_flat_dt_size(void)
-{
- return fdt_totalsize(initial_boot_params);
-}
-
-/**
* of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr
*
* This function can be used within scan_flattened_dt callback to get
@@ -792,6 +713,38 @@ const void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
}
/**
+ * of_fdt_is_compatible - Return true if given node from the given blob has
+ * compat in its compatible list
+ * @blob: A device tree blob
+ * @node: node to test
+ * @compat: compatible string to compare with compatible list.
+ *
+ * On match, returns a non-zero value with smaller values returned for more
+ * specific compatible values.
+ */
+static int of_fdt_is_compatible(const void *blob,
+ unsigned long node, const char *compat)
+{
+ const char *cp;
+ int cplen;
+ unsigned long l, score = 0;
+
+ cp = fdt_getprop(blob, node, "compatible", &cplen);
+ if (cp == NULL)
+ return 0;
+ while (cplen > 0) {
+ score++;
+ if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
+ return score;
+ l = strlen(cp) + 1;
+ cp += l;
+ cplen -= l;
+ }
+
+ return 0;
+}
+
+/**
* of_flat_dt_is_compatible - Return true if given node has compat in compatible list
* @node: node to test
* @compat: compatible string to compare with compatible list.
@@ -804,9 +757,21 @@ int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
/**
* of_flat_dt_match - Return true if node matches a list of compatible values
*/
-int __init of_flat_dt_match(unsigned long node, const char *const *compat)
+static int __init of_flat_dt_match(unsigned long node, const char *const *compat)
{
- return of_fdt_match(initial_boot_params, node, compat);
+ unsigned int tmp, score = 0;
+
+ if (!compat)
+ return 0;
+
+ while (*compat) {
+ tmp = of_fdt_is_compatible(initial_boot_params, node, *compat);
+ if (tmp && (score == 0 || (tmp < score)))
+ score = tmp;
+ compat++;
+ }
+
+ return score;
}
/**
diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
index 3b67896d9d74..44f53496cab1 100644
--- a/drivers/of/of_mdio.c
+++ b/drivers/of/of_mdio.c
@@ -281,7 +281,7 @@ unregister:
EXPORT_SYMBOL(of_mdiobus_register);
/* Helper function for of_phy_find_device */
-static int of_phy_match(struct device *dev, void *phy_np)
+static int of_phy_match(struct device *dev, const void *phy_np)
{
return dev->of_node == phy_np;
}
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
index 89e190e94af7..7989703b883c 100644
--- a/drivers/of/of_reserved_mem.c
+++ b/drivers/of/of_reserved_mem.c
@@ -324,6 +324,9 @@ int of_reserved_mem_device_init_by_idx(struct device *dev,
if (!target)
return -ENODEV;
+ if (!of_device_is_available(target))
+ return 0;
+
rmem = __find_rmem(target);
of_node_put(target);
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 04ad312fd85b..7801e25e6895 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -37,7 +37,7 @@ static const struct of_device_id of_skipped_node_table[] = {
{} /* Empty terminated list */
};
-static int of_dev_node_match(struct device *dev, void *data)
+static int of_dev_node_match(struct device *dev, const void *data)
{
return dev->of_node == data;
}
@@ -92,8 +92,7 @@ static void of_device_make_bus_id(struct device *dev)
reg = of_get_property(node, "reg", NULL);
if (reg && (addr = of_translate_address(node, reg)) != OF_BAD_ADDR) {
dev_set_name(dev, dev_name(dev) ? "%llx.%pOFn:%s" : "%llx.%pOFn",
- (unsigned long long)addr, node,
- dev_name(dev));
+ addr, node, dev_name(dev));
return;
}
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index 3832a5de4602..e6b175370f2e 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -1946,7 +1946,7 @@ static int unittest_i2c_mux_probe(struct i2c_client *client,
{
int i, nchans;
struct device *dev = &client->dev;
- struct i2c_adapter *adap = to_i2c_adapter(dev->parent);
+ struct i2c_adapter *adap = client->adapter;
struct device_node *np = client->dev.of_node, *child;
struct i2c_mux_core *muxc;
u32 reg, max_reg;
diff --git a/drivers/opp/Kconfig b/drivers/opp/Kconfig
index fe54d349d2e1..35dfc7e80f92 100644
--- a/drivers/opp/Kconfig
+++ b/drivers/opp/Kconfig
@@ -11,4 +11,4 @@ config PM_OPP
OPP layer organizes the data internally using device pointers
representing individual voltage domains and provides SOC
implementations a ready to use framework to manage OPPs.
- For more information, read <file:Documentation/power/opp.txt>
+ For more information, read <file:Documentation/power/opp.rst>
diff --git a/drivers/opp/core.c b/drivers/opp/core.c
index 0e7703fe733f..c094d5d20fd7 100644
--- a/drivers/opp/core.c
+++ b/drivers/opp/core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic OPP Interface
*
@@ -5,10 +6,6 @@
* Nishanth Menon
* Romit Dasgupta
* Kevin Hilman
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -685,7 +682,7 @@ static int _set_opp_custom(const struct opp_table *opp_table,
data->old_opp.rate = old_freq;
size = sizeof(*old_supply) * opp_table->regulator_count;
- if (IS_ERR(old_supply))
+ if (!old_supply)
memset(data->old_opp.supplies, 0, size);
else
memcpy(data->old_opp.supplies, old_supply, size);
@@ -711,7 +708,7 @@ static int _set_required_opps(struct device *dev,
/* Single genpd case */
if (!genpd_virt_devs) {
- pstate = opp->required_opps[0]->pstate;
+ pstate = likely(opp) ? opp->required_opps[0]->pstate : 0;
ret = dev_pm_genpd_set_performance_state(dev, pstate);
if (ret) {
dev_err(dev, "Failed to set performance state of %s: %d (%d)\n",
@@ -729,7 +726,7 @@ static int _set_required_opps(struct device *dev,
mutex_lock(&opp_table->genpd_virt_dev_lock);
for (i = 0; i < opp_table->required_opp_count; i++) {
- pstate = opp->required_opps[i]->pstate;
+ pstate = likely(opp) ? opp->required_opps[i]->pstate : 0;
if (!genpd_virt_devs[i])
continue;
@@ -751,29 +748,37 @@ static int _set_required_opps(struct device *dev,
* @dev: device for which we do this operation
* @target_freq: frequency to achieve
*
- * This configures the power-supplies and clock source to the levels specified
- * by the OPP corresponding to the target_freq.
+ * This configures the power-supplies to the levels specified by the OPP
+ * corresponding to the target_freq, and programs the clock to a value <=
+ * target_freq, as rounded by clk_round_rate(). Device wanting to run at fmax
+ * provided by the opp, should have already rounded to the target OPP's
+ * frequency.
*/
int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
{
struct opp_table *opp_table;
- unsigned long freq, old_freq;
+ unsigned long freq, old_freq, temp_freq;
struct dev_pm_opp *old_opp, *opp;
struct clk *clk;
int ret;
- if (unlikely(!target_freq)) {
- dev_err(dev, "%s: Invalid target frequency %lu\n", __func__,
- target_freq);
- return -EINVAL;
- }
-
opp_table = _find_opp_table(dev);
if (IS_ERR(opp_table)) {
dev_err(dev, "%s: device opp doesn't exist\n", __func__);
return PTR_ERR(opp_table);
}
+ if (unlikely(!target_freq)) {
+ if (opp_table->required_opp_tables) {
+ ret = _set_required_opps(dev, opp_table, NULL);
+ } else {
+ dev_err(dev, "target frequency can't be 0\n");
+ ret = -EINVAL;
+ }
+
+ goto put_opp_table;
+ }
+
clk = opp_table->clk;
if (IS_ERR(clk)) {
dev_err(dev, "%s: No clock available for the device\n",
@@ -796,13 +801,15 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
goto put_opp_table;
}
- old_opp = _find_freq_ceil(opp_table, &old_freq);
+ temp_freq = old_freq;
+ old_opp = _find_freq_ceil(opp_table, &temp_freq);
if (IS_ERR(old_opp)) {
dev_err(dev, "%s: failed to find current OPP for freq %lu (%ld)\n",
__func__, old_freq, PTR_ERR(old_opp));
}
- opp = _find_freq_ceil(opp_table, &freq);
+ temp_freq = freq;
+ opp = _find_freq_ceil(opp_table, &temp_freq);
if (IS_ERR(opp)) {
ret = PTR_ERR(opp);
dev_err(dev, "%s: failed to find OPP for freq %lu (%d)\n",
@@ -1744,91 +1751,137 @@ void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table)
}
EXPORT_SYMBOL_GPL(dev_pm_opp_unregister_set_opp_helper);
+static void _opp_detach_genpd(struct opp_table *opp_table)
+{
+ int index;
+
+ for (index = 0; index < opp_table->required_opp_count; index++) {
+ if (!opp_table->genpd_virt_devs[index])
+ continue;
+
+ dev_pm_domain_detach(opp_table->genpd_virt_devs[index], false);
+ opp_table->genpd_virt_devs[index] = NULL;
+ }
+
+ kfree(opp_table->genpd_virt_devs);
+ opp_table->genpd_virt_devs = NULL;
+}
+
/**
- * dev_pm_opp_set_genpd_virt_dev - Set virtual genpd device for an index
- * @dev: Consumer device for which the genpd device is getting set.
- * @virt_dev: virtual genpd device.
- * @index: index.
+ * dev_pm_opp_attach_genpd - Attach genpd(s) for the device and save virtual device pointer
+ * @dev: Consumer device for which the genpd is getting attached.
+ * @names: Null terminated array of pointers containing names of genpd to attach.
*
* Multiple generic power domains for a device are supported with the help of
* virtual genpd devices, which are created for each consumer device - genpd
* pair. These are the device structures which are attached to the power domain
* and are required by the OPP core to set the performance state of the genpd.
+ * The same API also works for the case where single genpd is available and so
+ * we don't need to support that separately.
*
* This helper will normally be called by the consumer driver of the device
- * "dev", as only that has details of the genpd devices.
+ * "dev", as only that has details of the genpd names.
*
- * This helper needs to be called once for each of those virtual devices, but
- * only if multiple domains are available for a device. Otherwise the original
- * device structure will be used instead by the OPP core.
+ * This helper needs to be called once with a list of all genpd to attach.
+ * Otherwise the original device structure will be used instead by the OPP core.
*/
-struct opp_table *dev_pm_opp_set_genpd_virt_dev(struct device *dev,
- struct device *virt_dev,
- int index)
+struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char **names)
{
struct opp_table *opp_table;
+ struct device *virt_dev;
+ int index, ret = -EINVAL;
+ const char **name = names;
opp_table = dev_pm_opp_get_opp_table(dev);
if (!opp_table)
return ERR_PTR(-ENOMEM);
+ /*
+ * If the genpd's OPP table isn't already initialized, parsing of the
+ * required-opps fail for dev. We should retry this after genpd's OPP
+ * table is added.
+ */
+ if (!opp_table->required_opp_count) {
+ ret = -EPROBE_DEFER;
+ goto put_table;
+ }
+
mutex_lock(&opp_table->genpd_virt_dev_lock);
- if (unlikely(!opp_table->genpd_virt_devs ||
- index >= opp_table->required_opp_count ||
- opp_table->genpd_virt_devs[index])) {
+ opp_table->genpd_virt_devs = kcalloc(opp_table->required_opp_count,
+ sizeof(*opp_table->genpd_virt_devs),
+ GFP_KERNEL);
+ if (!opp_table->genpd_virt_devs)
+ goto unlock;
- dev_err(dev, "Invalid request to set required device\n");
- dev_pm_opp_put_opp_table(opp_table);
- mutex_unlock(&opp_table->genpd_virt_dev_lock);
+ while (*name) {
+ index = of_property_match_string(dev->of_node,
+ "power-domain-names", *name);
+ if (index < 0) {
+ dev_err(dev, "Failed to find power domain: %s (%d)\n",
+ *name, index);
+ goto err;
+ }
- return ERR_PTR(-EINVAL);
+ if (index >= opp_table->required_opp_count) {
+ dev_err(dev, "Index can't be greater than required-opp-count - 1, %s (%d : %d)\n",
+ *name, opp_table->required_opp_count, index);
+ goto err;
+ }
+
+ if (opp_table->genpd_virt_devs[index]) {
+ dev_err(dev, "Genpd virtual device already set %s\n",
+ *name);
+ goto err;
+ }
+
+ virt_dev = dev_pm_domain_attach_by_name(dev, *name);
+ if (IS_ERR(virt_dev)) {
+ ret = PTR_ERR(virt_dev);
+ dev_err(dev, "Couldn't attach to pm_domain: %d\n", ret);
+ goto err;
+ }
+
+ opp_table->genpd_virt_devs[index] = virt_dev;
+ name++;
}
- opp_table->genpd_virt_devs[index] = virt_dev;
mutex_unlock(&opp_table->genpd_virt_dev_lock);
return opp_table;
+
+err:
+ _opp_detach_genpd(opp_table);
+unlock:
+ mutex_unlock(&opp_table->genpd_virt_dev_lock);
+
+put_table:
+ dev_pm_opp_put_opp_table(opp_table);
+
+ return ERR_PTR(ret);
}
+EXPORT_SYMBOL_GPL(dev_pm_opp_attach_genpd);
/**
- * dev_pm_opp_put_genpd_virt_dev() - Releases resources blocked for genpd device.
- * @opp_table: OPP table returned by dev_pm_opp_set_genpd_virt_dev().
- * @virt_dev: virtual genpd device.
+ * dev_pm_opp_detach_genpd() - Detach genpd(s) from the device.
+ * @opp_table: OPP table returned by dev_pm_opp_attach_genpd().
*
- * This releases the resource previously acquired with a call to
- * dev_pm_opp_set_genpd_virt_dev(). The consumer driver shall call this helper
- * if it doesn't want OPP core to update performance state of a power domain
- * anymore.
+ * This detaches the genpd(s), resets the virtual device pointers, and puts the
+ * OPP table.
*/
-void dev_pm_opp_put_genpd_virt_dev(struct opp_table *opp_table,
- struct device *virt_dev)
+void dev_pm_opp_detach_genpd(struct opp_table *opp_table)
{
- int i;
-
/*
* Acquire genpd_virt_dev_lock to make sure virt_dev isn't getting
* used in parallel.
*/
mutex_lock(&opp_table->genpd_virt_dev_lock);
-
- for (i = 0; i < opp_table->required_opp_count; i++) {
- if (opp_table->genpd_virt_devs[i] != virt_dev)
- continue;
-
- opp_table->genpd_virt_devs[i] = NULL;
- dev_pm_opp_put_opp_table(opp_table);
-
- /* Drop the vote */
- dev_pm_genpd_set_performance_state(virt_dev, 0);
- break;
- }
-
+ _opp_detach_genpd(opp_table);
mutex_unlock(&opp_table->genpd_virt_dev_lock);
- if (unlikely(i == opp_table->required_opp_count))
- dev_err(virt_dev, "Failed to find required device entry\n");
+ dev_pm_opp_put_opp_table(opp_table);
}
+EXPORT_SYMBOL_GPL(dev_pm_opp_detach_genpd);
/**
* dev_pm_opp_xlate_performance_state() - Find required OPP's pstate for src_table.
diff --git a/drivers/opp/cpu.c b/drivers/opp/cpu.c
index ab6d07e78945..b5055cc886ef 100644
--- a/drivers/opp/cpu.c
+++ b/drivers/opp/cpu.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic OPP helper interface for CPU device
*
@@ -5,10 +6,6 @@
* Nishanth Menon
* Romit Dasgupta
* Kevin Hilman
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/opp/debugfs.c b/drivers/opp/debugfs.c
index a1c57fe14de4..609665e339b6 100644
--- a/drivers/opp/debugfs.c
+++ b/drivers/opp/debugfs.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic OPP debugfs interface
*
* Copyright (C) 2015-2016 Viresh Kumar <viresh.kumar@linaro.org>
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/opp/of.c b/drivers/opp/of.c
index c10c782d15aa..b313aca9894f 100644
--- a/drivers/opp/of.c
+++ b/drivers/opp/of.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic OPP OF helpers
*
@@ -5,10 +6,6 @@
* Nishanth Menon
* Romit Dasgupta
* Kevin Hilman
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -141,7 +138,6 @@ err:
static void _opp_table_free_required_tables(struct opp_table *opp_table)
{
struct opp_table **required_opp_tables = opp_table->required_opp_tables;
- struct device **genpd_virt_devs = opp_table->genpd_virt_devs;
int i;
if (!required_opp_tables)
@@ -155,10 +151,8 @@ static void _opp_table_free_required_tables(struct opp_table *opp_table)
}
kfree(required_opp_tables);
- kfree(genpd_virt_devs);
opp_table->required_opp_count = 0;
- opp_table->genpd_virt_devs = NULL;
opp_table->required_opp_tables = NULL;
}
@@ -171,9 +165,8 @@ static void _opp_table_alloc_required_tables(struct opp_table *opp_table,
struct device_node *opp_np)
{
struct opp_table **required_opp_tables;
- struct device **genpd_virt_devs = NULL;
struct device_node *required_np, *np;
- int count, count_pd, i;
+ int count, i;
/* Traversing the first OPP node is all we need */
np = of_get_next_available_child(opp_np, NULL);
@@ -186,33 +179,11 @@ static void _opp_table_alloc_required_tables(struct opp_table *opp_table,
if (!count)
goto put_np;
- /*
- * Check the number of power-domains to know if we need to deal
- * with virtual devices. In some cases we have devices with multiple
- * power domains but with only one of them being scalable, hence
- * 'count' could be 1, but we still have to deal with multiple genpds
- * and virtual devices.
- */
- count_pd = of_count_phandle_with_args(dev->of_node, "power-domains",
- "#power-domain-cells");
- if (!count_pd)
- goto put_np;
-
- if (count_pd > 1) {
- genpd_virt_devs = kcalloc(count, sizeof(*genpd_virt_devs),
- GFP_KERNEL);
- if (!genpd_virt_devs)
- goto put_np;
- }
-
required_opp_tables = kcalloc(count, sizeof(*required_opp_tables),
GFP_KERNEL);
- if (!required_opp_tables) {
- kfree(genpd_virt_devs);
+ if (!required_opp_tables)
goto put_np;
- }
- opp_table->genpd_virt_devs = genpd_virt_devs;
opp_table->required_opp_tables = required_opp_tables;
opp_table->required_opp_count = count;
diff --git a/drivers/opp/opp.h b/drivers/opp/opp.h
index 569b3525aa67..01a500e2c40a 100644
--- a/drivers/opp/opp.h
+++ b/drivers/opp/opp.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Generic OPP Interface
*
@@ -5,10 +6,6 @@
* Nishanth Menon
* Romit Dasgupta
* Kevin Hilman
- *
- * 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.
*/
#ifndef __DRIVER_OPP_H__
diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c
index 4ea08979312c..0875f2f122b3 100644
--- a/drivers/oprofile/oprofilefs.c
+++ b/drivers/oprofile/oprofilefs.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/oprofile.h>
#include <linux/fs.h>
+#include <linux/fs_context.h>
#include <linux/pagemap.h>
#include <linux/uaccess.h>
@@ -238,7 +239,7 @@ struct dentry *oprofilefs_mkdir(struct dentry *parent, char const *name)
}
-static int oprofilefs_fill_super(struct super_block *sb, void *data, int silent)
+static int oprofilefs_fill_super(struct super_block *sb, struct fs_context *fc)
{
struct inode *root_inode;
@@ -263,18 +264,25 @@ static int oprofilefs_fill_super(struct super_block *sb, void *data, int silent)
return 0;
}
-
-static struct dentry *oprofilefs_mount(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int oprofilefs_get_tree(struct fs_context *fc)
{
- return mount_single(fs_type, flags, data, oprofilefs_fill_super);
+ return get_tree_single(fc, oprofilefs_fill_super);
}
+static const struct fs_context_operations oprofilefs_context_ops = {
+ .get_tree = oprofilefs_get_tree,
+};
+
+static int oprofilefs_init_fs_context(struct fs_context *fc)
+{
+ fc->ops = &oprofilefs_context_ops;
+ return 0;
+}
static struct file_system_type oprofilefs_type = {
.owner = THIS_MODULE,
.name = "oprofilefs",
- .mount = oprofilefs_mount,
+ .init_fs_context = oprofilefs_init_fs_context,
.kill_sb = kill_litter_super,
};
MODULE_ALIAS_FS("oprofilefs");
diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig
index 24189c3399e0..1791830e7a71 100644
--- a/drivers/parport/Kconfig
+++ b/drivers/parport/Kconfig
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# For a description of the syntax of this configuration file,
-# see Documentation/kbuild/kconfig-language.txt.
+# see Documentation/kbuild/kconfig-language.rst.
#
# Parport configuration.
#
diff --git a/drivers/parport/parport_ax88796.c b/drivers/parport/parport_ax88796.c
index bfe97c2a8d4c..54b539809673 100644
--- a/drivers/parport/parport_ax88796.c
+++ b/drivers/parport/parport_ax88796.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* linux/drivers/parport/parport_ax88796.c
*
* (c) 2005,2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c
index 97c08146534a..e18499243f84 100644
--- a/drivers/pci/ats.c
+++ b/drivers/pci/ats.c
@@ -432,7 +432,7 @@ EXPORT_SYMBOL_GPL(pci_prg_resp_pasid_required);
* @pdev: PCI device structure
*
* Returns negative value when PASID capability is not present.
- * Otherwise it returns the numer of supported PASIDs.
+ * Otherwise it returns the number of supported PASIDs.
*/
int pci_max_pasids(struct pci_dev *pdev)
{
diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index 011c57cae4b0..fe9f9f13ce11 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -174,14 +174,14 @@ config PCIE_IPROC_MSI
PCIe controller
config PCIE_ALTERA
- bool "Altera PCIe controller"
+ tristate "Altera PCIe controller"
depends on ARM || NIOS2 || ARM64 || COMPILE_TEST
help
Say Y here if you want to enable PCIe controller support on Altera
FPGA.
config PCIE_ALTERA_MSI
- bool "Altera PCIe MSI feature"
+ tristate "Altera PCIe MSI feature"
depends on PCIE_ALTERA
depends on PCI_MSI_IRQ_DOMAIN
help
diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
index a6ce1ee51b4c..6ea778ae4877 100644
--- a/drivers/pci/controller/dwc/Kconfig
+++ b/drivers/pci/controller/dwc/Kconfig
@@ -90,7 +90,7 @@ config PCI_EXYNOS
config PCI_IMX6
bool "Freescale i.MX6/7/8 PCIe controller"
- depends on SOC_IMX6Q || SOC_IMX7D || (ARM64 && ARCH_MXC) || COMPILE_TEST
+ depends on ARCH_MXC || COMPILE_TEST
depends on PCI_MSI_IRQ_DOMAIN
select PCIE_DW_HOST
diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c
index 419451efd58c..4234ddb4722f 100644
--- a/drivers/pci/controller/dwc/pci-dra7xx.c
+++ b/drivers/pci/controller/dwc/pci-dra7xx.c
@@ -26,6 +26,7 @@
#include <linux/types.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
+#include <linux/gpio/consumer.h>
#include "../../pci.h"
#include "pcie-designware.h"
diff --git a/drivers/pci/controller/dwc/pcie-armada8k.c b/drivers/pci/controller/dwc/pcie-armada8k.c
index 0c389a30ef5d..3d55dc78d999 100644
--- a/drivers/pci/controller/dwc/pcie-armada8k.c
+++ b/drivers/pci/controller/dwc/pcie-armada8k.c
@@ -25,10 +25,14 @@
#include "pcie-designware.h"
+#define ARMADA8K_PCIE_MAX_LANES PCIE_LNK_X4
+
struct armada8k_pcie {
struct dw_pcie *pci;
struct clk *clk;
struct clk *clk_reg;
+ struct phy *phy[ARMADA8K_PCIE_MAX_LANES];
+ unsigned int phy_count;
};
#define PCIE_VENDOR_REGS_OFFSET 0x8000
@@ -55,7 +59,7 @@ struct armada8k_pcie {
#define PCIE_ARUSER_REG (PCIE_VENDOR_REGS_OFFSET + 0x5C)
#define PCIE_AWUSER_REG (PCIE_VENDOR_REGS_OFFSET + 0x60)
/*
- * AR/AW Cache defauls: Normal memory, Write-Back, Read / Write
+ * AR/AW Cache defaults: Normal memory, Write-Back, Read / Write
* allocate
*/
#define ARCACHE_DEFAULT_VALUE 0x3511
@@ -67,6 +71,76 @@ struct armada8k_pcie {
#define to_armada8k_pcie(x) dev_get_drvdata((x)->dev)
+static void armada8k_pcie_disable_phys(struct armada8k_pcie *pcie)
+{
+ int i;
+
+ for (i = 0; i < ARMADA8K_PCIE_MAX_LANES; i++) {
+ phy_power_off(pcie->phy[i]);
+ phy_exit(pcie->phy[i]);
+ }
+}
+
+static int armada8k_pcie_enable_phys(struct armada8k_pcie *pcie)
+{
+ int ret;
+ int i;
+
+ for (i = 0; i < ARMADA8K_PCIE_MAX_LANES; i++) {
+ ret = phy_init(pcie->phy[i]);
+ if (ret)
+ return ret;
+
+ ret = phy_set_mode_ext(pcie->phy[i], PHY_MODE_PCIE,
+ pcie->phy_count);
+ if (ret) {
+ phy_exit(pcie->phy[i]);
+ return ret;
+ }
+
+ ret = phy_power_on(pcie->phy[i]);
+ if (ret) {
+ phy_exit(pcie->phy[i]);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int armada8k_pcie_setup_phys(struct armada8k_pcie *pcie)
+{
+ struct dw_pcie *pci = pcie->pci;
+ struct device *dev = pci->dev;
+ struct device_node *node = dev->of_node;
+ int ret = 0;
+ int i;
+
+ for (i = 0; i < ARMADA8K_PCIE_MAX_LANES; i++) {
+ pcie->phy[i] = devm_of_phy_get_by_index(dev, node, i);
+ if (IS_ERR(pcie->phy[i]) &&
+ (PTR_ERR(pcie->phy[i]) == -EPROBE_DEFER))
+ return PTR_ERR(pcie->phy[i]);
+
+ if (IS_ERR(pcie->phy[i])) {
+ pcie->phy[i] = NULL;
+ continue;
+ }
+
+ pcie->phy_count++;
+ }
+
+ /* Old bindings miss the PHY handle, so just warn if there is no PHY */
+ if (!pcie->phy_count)
+ dev_warn(dev, "No available PHY\n");
+
+ ret = armada8k_pcie_enable_phys(pcie);
+ if (ret)
+ dev_err(dev, "Failed to initialize PHY(s) (%d)\n", ret);
+
+ return ret;
+}
+
static int armada8k_pcie_link_up(struct dw_pcie *pci)
{
u32 reg;
@@ -249,14 +323,20 @@ static int armada8k_pcie_probe(struct platform_device *pdev)
goto fail_clkreg;
}
+ ret = armada8k_pcie_setup_phys(pcie);
+ if (ret)
+ goto fail_clkreg;
+
platform_set_drvdata(pdev, pcie);
ret = armada8k_add_pcie_port(pcie, pdev);
if (ret)
- goto fail_clkreg;
+ goto disable_phy;
return 0;
+disable_phy:
+ armada8k_pcie_disable_phys(pcie);
fail_clkreg:
clk_disable_unprepare(pcie->clk_reg);
fail:
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index 77db32529319..f93252d0da5b 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -311,6 +311,7 @@ void dw_pcie_msi_init(struct pcie_port *pp)
dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_HI, 4,
upper_32_bits(msi_target));
}
+EXPORT_SYMBOL_GPL(dw_pcie_msi_init);
int dw_pcie_host_init(struct pcie_port *pp)
{
@@ -495,6 +496,16 @@ err_free_msi:
dw_pcie_free_msi(pp);
return ret;
}
+EXPORT_SYMBOL_GPL(dw_pcie_host_init);
+
+void dw_pcie_host_deinit(struct pcie_port *pp)
+{
+ pci_stop_root_bus(pp->root_bus);
+ pci_remove_root_bus(pp->root_bus);
+ if (pci_msi_enabled() && !pp->ops->msi_host_init)
+ dw_pcie_free_msi(pp);
+}
+EXPORT_SYMBOL_GPL(dw_pcie_host_deinit);
static int dw_pcie_access_other_conf(struct pcie_port *pp, struct pci_bus *bus,
u32 devfn, int where, int size, u32 *val,
@@ -687,3 +698,4 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
val |= PORT_LOGIC_SPEED_CHANGE;
dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
}
+EXPORT_SYMBOL_GPL(dw_pcie_setup_rc);
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index 9d7c51c32b3b..7d25102c304c 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -34,6 +34,7 @@ int dw_pcie_read(void __iomem *addr, int size, u32 *val)
return PCIBIOS_SUCCESSFUL;
}
+EXPORT_SYMBOL_GPL(dw_pcie_read);
int dw_pcie_write(void __iomem *addr, int size, u32 val)
{
@@ -51,69 +52,97 @@ int dw_pcie_write(void __iomem *addr, int size, u32 val)
return PCIBIOS_SUCCESSFUL;
}
+EXPORT_SYMBOL_GPL(dw_pcie_write);
-u32 __dw_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg,
- size_t size)
+u32 dw_pcie_read_dbi(struct dw_pcie *pci, u32 reg, size_t size)
{
int ret;
u32 val;
if (pci->ops->read_dbi)
- return pci->ops->read_dbi(pci, base, reg, size);
+ return pci->ops->read_dbi(pci, pci->dbi_base, reg, size);
- ret = dw_pcie_read(base + reg, size, &val);
+ ret = dw_pcie_read(pci->dbi_base + reg, size, &val);
if (ret)
dev_err(pci->dev, "Read DBI address failed\n");
return val;
}
+EXPORT_SYMBOL_GPL(dw_pcie_read_dbi);
-void __dw_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg,
- size_t size, u32 val)
+void dw_pcie_write_dbi(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
{
int ret;
if (pci->ops->write_dbi) {
- pci->ops->write_dbi(pci, base, reg, size, val);
+ pci->ops->write_dbi(pci, pci->dbi_base, reg, size, val);
return;
}
- ret = dw_pcie_write(base + reg, size, val);
+ ret = dw_pcie_write(pci->dbi_base + reg, size, val);
if (ret)
dev_err(pci->dev, "Write DBI address failed\n");
}
+EXPORT_SYMBOL_GPL(dw_pcie_write_dbi);
-u32 __dw_pcie_read_dbi2(struct dw_pcie *pci, void __iomem *base, u32 reg,
- size_t size)
+u32 dw_pcie_read_dbi2(struct dw_pcie *pci, u32 reg, size_t size)
{
int ret;
u32 val;
if (pci->ops->read_dbi2)
- return pci->ops->read_dbi2(pci, base, reg, size);
+ return pci->ops->read_dbi2(pci, pci->dbi_base2, reg, size);
- ret = dw_pcie_read(base + reg, size, &val);
+ ret = dw_pcie_read(pci->dbi_base2 + reg, size, &val);
if (ret)
dev_err(pci->dev, "read DBI address failed\n");
return val;
}
-void __dw_pcie_write_dbi2(struct dw_pcie *pci, void __iomem *base, u32 reg,
- size_t size, u32 val)
+void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
{
int ret;
if (pci->ops->write_dbi2) {
- pci->ops->write_dbi2(pci, base, reg, size, val);
+ pci->ops->write_dbi2(pci, pci->dbi_base2, reg, size, val);
return;
}
- ret = dw_pcie_write(base + reg, size, val);
+ ret = dw_pcie_write(pci->dbi_base2 + reg, size, val);
if (ret)
dev_err(pci->dev, "write DBI address failed\n");
}
+u32 dw_pcie_read_atu(struct dw_pcie *pci, u32 reg, size_t size)
+{
+ int ret;
+ u32 val;
+
+ if (pci->ops->read_dbi)
+ return pci->ops->read_dbi(pci, pci->atu_base, reg, size);
+
+ ret = dw_pcie_read(pci->atu_base + reg, size, &val);
+ if (ret)
+ dev_err(pci->dev, "Read ATU address failed\n");
+
+ return val;
+}
+
+void dw_pcie_write_atu(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
+{
+ int ret;
+
+ if (pci->ops->write_dbi) {
+ pci->ops->write_dbi(pci, pci->atu_base, reg, size, val);
+ return;
+ }
+
+ ret = dw_pcie_write(pci->atu_base + reg, size, val);
+ if (ret)
+ dev_err(pci->dev, "Write ATU address failed\n");
+}
+
static u32 dw_pcie_readl_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg)
{
u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index b8993f2b78df..ffed084a0b4f 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -254,14 +254,12 @@ struct dw_pcie {
int dw_pcie_read(void __iomem *addr, int size, u32 *val);
int dw_pcie_write(void __iomem *addr, int size, u32 val);
-u32 __dw_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg,
- size_t size);
-void __dw_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg,
- size_t size, u32 val);
-u32 __dw_pcie_read_dbi2(struct dw_pcie *pci, void __iomem *base, u32 reg,
- size_t size);
-void __dw_pcie_write_dbi2(struct dw_pcie *pci, void __iomem *base, u32 reg,
- size_t size, u32 val);
+u32 dw_pcie_read_dbi(struct dw_pcie *pci, u32 reg, size_t size);
+void dw_pcie_write_dbi(struct dw_pcie *pci, u32 reg, size_t size, u32 val);
+u32 dw_pcie_read_dbi2(struct dw_pcie *pci, u32 reg, size_t size);
+void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val);
+u32 dw_pcie_read_atu(struct dw_pcie *pci, u32 reg, size_t size);
+void dw_pcie_write_atu(struct dw_pcie *pci, u32 reg, size_t size, u32 val);
int dw_pcie_link_up(struct dw_pcie *pci);
int dw_pcie_wait_for_link(struct dw_pcie *pci);
void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index,
@@ -275,52 +273,52 @@ void dw_pcie_setup(struct dw_pcie *pci);
static inline void dw_pcie_writel_dbi(struct dw_pcie *pci, u32 reg, u32 val)
{
- __dw_pcie_write_dbi(pci, pci->dbi_base, reg, 0x4, val);
+ dw_pcie_write_dbi(pci, reg, 0x4, val);
}
static inline u32 dw_pcie_readl_dbi(struct dw_pcie *pci, u32 reg)
{
- return __dw_pcie_read_dbi(pci, pci->dbi_base, reg, 0x4);
+ return dw_pcie_read_dbi(pci, reg, 0x4);
}
static inline void dw_pcie_writew_dbi(struct dw_pcie *pci, u32 reg, u16 val)
{
- __dw_pcie_write_dbi(pci, pci->dbi_base, reg, 0x2, val);
+ dw_pcie_write_dbi(pci, reg, 0x2, val);
}
static inline u16 dw_pcie_readw_dbi(struct dw_pcie *pci, u32 reg)
{
- return __dw_pcie_read_dbi(pci, pci->dbi_base, reg, 0x2);
+ return dw_pcie_read_dbi(pci, reg, 0x2);
}
static inline void dw_pcie_writeb_dbi(struct dw_pcie *pci, u32 reg, u8 val)
{
- __dw_pcie_write_dbi(pci, pci->dbi_base, reg, 0x1, val);
+ dw_pcie_write_dbi(pci, reg, 0x1, val);
}
static inline u8 dw_pcie_readb_dbi(struct dw_pcie *pci, u32 reg)
{
- return __dw_pcie_read_dbi(pci, pci->dbi_base, reg, 0x1);
+ return dw_pcie_read_dbi(pci, reg, 0x1);
}
static inline void dw_pcie_writel_dbi2(struct dw_pcie *pci, u32 reg, u32 val)
{
- __dw_pcie_write_dbi2(pci, pci->dbi_base2, reg, 0x4, val);
+ dw_pcie_write_dbi2(pci, reg, 0x4, val);
}
static inline u32 dw_pcie_readl_dbi2(struct dw_pcie *pci, u32 reg)
{
- return __dw_pcie_read_dbi2(pci, pci->dbi_base2, reg, 0x4);
+ return dw_pcie_read_dbi2(pci, reg, 0x4);
}
static inline void dw_pcie_writel_atu(struct dw_pcie *pci, u32 reg, u32 val)
{
- __dw_pcie_write_dbi(pci, pci->atu_base, reg, 0x4, val);
+ dw_pcie_write_atu(pci, reg, 0x4, val);
}
static inline u32 dw_pcie_readl_atu(struct dw_pcie *pci, u32 reg)
{
- return __dw_pcie_read_dbi(pci, pci->atu_base, reg, 0x4);
+ return dw_pcie_read_atu(pci, reg, 0x4);
}
static inline void dw_pcie_dbi_ro_wr_en(struct dw_pcie *pci)
@@ -351,6 +349,7 @@ void dw_pcie_msi_init(struct pcie_port *pp);
void dw_pcie_free_msi(struct pcie_port *pp);
void dw_pcie_setup_rc(struct pcie_port *pp);
int dw_pcie_host_init(struct pcie_port *pp);
+void dw_pcie_host_deinit(struct pcie_port *pp);
int dw_pcie_allocate_domains(struct pcie_port *pp);
#else
static inline irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
@@ -375,6 +374,10 @@ static inline int dw_pcie_host_init(struct pcie_port *pp)
return 0;
}
+static inline void dw_pcie_host_deinit(struct pcie_port *pp)
+{
+}
+
static inline int dw_pcie_allocate_domains(struct pcie_port *pp)
{
return 0;
diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c
index 9b599296205d..8df1914226be 100644
--- a/drivers/pci/controller/dwc/pcie-kirin.c
+++ b/drivers/pci/controller/dwc/pcie-kirin.c
@@ -2,7 +2,7 @@
/*
* PCIe host controller driver for Kirin Phone SoCs
*
- * Copyright (C) 2017 Hilisicon Electronics Co., Ltd.
+ * Copyright (C) 2017 HiSilicon Electronics Co., Ltd.
* http://www.huawei.com
*
* Author: Xiaowei Song <songxiaowei@huawei.com>
diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
index 0ed235d560e3..7e581748ee9f 100644
--- a/drivers/pci/controller/dwc/pcie-qcom.c
+++ b/drivers/pci/controller/dwc/pcie-qcom.c
@@ -112,10 +112,10 @@ struct qcom_pcie_resources_2_3_2 {
struct regulator_bulk_data supplies[QCOM_PCIE_2_3_2_MAX_SUPPLY];
};
+#define QCOM_PCIE_2_4_0_MAX_CLOCKS 4
struct qcom_pcie_resources_2_4_0 {
- struct clk *aux_clk;
- struct clk *master_clk;
- struct clk *slave_clk;
+ struct clk_bulk_data clks[QCOM_PCIE_2_4_0_MAX_CLOCKS];
+ int num_clks;
struct reset_control *axi_m_reset;
struct reset_control *axi_s_reset;
struct reset_control *pipe_reset;
@@ -178,6 +178,8 @@ static void qcom_ep_reset_assert(struct qcom_pcie *pcie)
static void qcom_ep_reset_deassert(struct qcom_pcie *pcie)
{
+ /* Ensure that PERST has been asserted for at least 100 ms */
+ msleep(100);
gpiod_set_value_cansleep(pcie->reset, 0);
usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500);
}
@@ -638,18 +640,20 @@ static int qcom_pcie_get_resources_2_4_0(struct qcom_pcie *pcie)
struct qcom_pcie_resources_2_4_0 *res = &pcie->res.v2_4_0;
struct dw_pcie *pci = pcie->pci;
struct device *dev = pci->dev;
+ bool is_ipq = of_device_is_compatible(dev->of_node, "qcom,pcie-ipq4019");
+ int ret;
- res->aux_clk = devm_clk_get(dev, "aux");
- if (IS_ERR(res->aux_clk))
- return PTR_ERR(res->aux_clk);
+ res->clks[0].id = "aux";
+ res->clks[1].id = "master_bus";
+ res->clks[2].id = "slave_bus";
+ res->clks[3].id = "iface";
- res->master_clk = devm_clk_get(dev, "master_bus");
- if (IS_ERR(res->master_clk))
- return PTR_ERR(res->master_clk);
+ /* qcom,pcie-ipq4019 is defined without "iface" */
+ res->num_clks = is_ipq ? 3 : 4;
- res->slave_clk = devm_clk_get(dev, "slave_bus");
- if (IS_ERR(res->slave_clk))
- return PTR_ERR(res->slave_clk);
+ ret = devm_clk_bulk_get(dev, res->num_clks, res->clks);
+ if (ret < 0)
+ return ret;
res->axi_m_reset = devm_reset_control_get_exclusive(dev, "axi_m");
if (IS_ERR(res->axi_m_reset))
@@ -659,27 +663,33 @@ static int qcom_pcie_get_resources_2_4_0(struct qcom_pcie *pcie)
if (IS_ERR(res->axi_s_reset))
return PTR_ERR(res->axi_s_reset);
- res->pipe_reset = devm_reset_control_get_exclusive(dev, "pipe");
- if (IS_ERR(res->pipe_reset))
- return PTR_ERR(res->pipe_reset);
-
- res->axi_m_vmid_reset = devm_reset_control_get_exclusive(dev,
- "axi_m_vmid");
- if (IS_ERR(res->axi_m_vmid_reset))
- return PTR_ERR(res->axi_m_vmid_reset);
-
- res->axi_s_xpu_reset = devm_reset_control_get_exclusive(dev,
- "axi_s_xpu");
- if (IS_ERR(res->axi_s_xpu_reset))
- return PTR_ERR(res->axi_s_xpu_reset);
-
- res->parf_reset = devm_reset_control_get_exclusive(dev, "parf");
- if (IS_ERR(res->parf_reset))
- return PTR_ERR(res->parf_reset);
-
- res->phy_reset = devm_reset_control_get_exclusive(dev, "phy");
- if (IS_ERR(res->phy_reset))
- return PTR_ERR(res->phy_reset);
+ if (is_ipq) {
+ /*
+ * These resources relates to the PHY or are secure clocks, but
+ * are controlled here for IPQ4019
+ */
+ res->pipe_reset = devm_reset_control_get_exclusive(dev, "pipe");
+ if (IS_ERR(res->pipe_reset))
+ return PTR_ERR(res->pipe_reset);
+
+ res->axi_m_vmid_reset = devm_reset_control_get_exclusive(dev,
+ "axi_m_vmid");
+ if (IS_ERR(res->axi_m_vmid_reset))
+ return PTR_ERR(res->axi_m_vmid_reset);
+
+ res->axi_s_xpu_reset = devm_reset_control_get_exclusive(dev,
+ "axi_s_xpu");
+ if (IS_ERR(res->axi_s_xpu_reset))
+ return PTR_ERR(res->axi_s_xpu_reset);
+
+ res->parf_reset = devm_reset_control_get_exclusive(dev, "parf");
+ if (IS_ERR(res->parf_reset))
+ return PTR_ERR(res->parf_reset);
+
+ res->phy_reset = devm_reset_control_get_exclusive(dev, "phy");
+ if (IS_ERR(res->phy_reset))
+ return PTR_ERR(res->phy_reset);
+ }
res->axi_m_sticky_reset = devm_reset_control_get_exclusive(dev,
"axi_m_sticky");
@@ -699,9 +709,11 @@ static int qcom_pcie_get_resources_2_4_0(struct qcom_pcie *pcie)
if (IS_ERR(res->ahb_reset))
return PTR_ERR(res->ahb_reset);
- res->phy_ahb_reset = devm_reset_control_get_exclusive(dev, "phy_ahb");
- if (IS_ERR(res->phy_ahb_reset))
- return PTR_ERR(res->phy_ahb_reset);
+ if (is_ipq) {
+ res->phy_ahb_reset = devm_reset_control_get_exclusive(dev, "phy_ahb");
+ if (IS_ERR(res->phy_ahb_reset))
+ return PTR_ERR(res->phy_ahb_reset);
+ }
return 0;
}
@@ -719,9 +731,7 @@ static void qcom_pcie_deinit_2_4_0(struct qcom_pcie *pcie)
reset_control_assert(res->axi_m_sticky_reset);
reset_control_assert(res->pwr_reset);
reset_control_assert(res->ahb_reset);
- clk_disable_unprepare(res->aux_clk);
- clk_disable_unprepare(res->master_clk);
- clk_disable_unprepare(res->slave_clk);
+ clk_bulk_disable_unprepare(res->num_clks, res->clks);
}
static int qcom_pcie_init_2_4_0(struct qcom_pcie *pcie)
@@ -850,23 +860,9 @@ static int qcom_pcie_init_2_4_0(struct qcom_pcie *pcie)
usleep_range(10000, 12000);
- ret = clk_prepare_enable(res->aux_clk);
- if (ret) {
- dev_err(dev, "cannot prepare/enable iface clock\n");
- goto err_clk_aux;
- }
-
- ret = clk_prepare_enable(res->master_clk);
- if (ret) {
- dev_err(dev, "cannot prepare/enable core clock\n");
- goto err_clk_axi_m;
- }
-
- ret = clk_prepare_enable(res->slave_clk);
- if (ret) {
- dev_err(dev, "cannot prepare/enable phy clock\n");
- goto err_clk_axi_s;
- }
+ ret = clk_bulk_prepare_enable(res->num_clks, res->clks);
+ if (ret)
+ goto err_clks;
/* enable PCIe clocks and resets */
val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL);
@@ -891,11 +887,7 @@ static int qcom_pcie_init_2_4_0(struct qcom_pcie *pcie)
return 0;
-err_clk_axi_s:
- clk_disable_unprepare(res->master_clk);
-err_clk_axi_m:
- clk_disable_unprepare(res->aux_clk);
-err_clk_aux:
+err_clks:
reset_control_assert(res->ahb_reset);
err_rst_ahb:
reset_control_assert(res->pwr_reset);
@@ -1289,6 +1281,7 @@ static const struct of_device_id qcom_pcie_match[] = {
{ .compatible = "qcom,pcie-msm8996", .data = &ops_2_3_2 },
{ .compatible = "qcom,pcie-ipq8074", .data = &ops_2_3_3 },
{ .compatible = "qcom,pcie-ipq4019", .data = &ops_2_4_0 },
+ { .compatible = "qcom,pcie-qcs404", .data = &ops_2_4_0 },
{ }
};
diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c
index 134e0306ff00..fc0fe4d4de49 100644
--- a/drivers/pci/controller/pci-aardvark.c
+++ b/drivers/pci/controller/pci-aardvark.c
@@ -308,7 +308,7 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie)
advk_writel(pcie, PCIE_ISR1_ALL_MASK, PCIE_ISR1_MASK_REG);
- /* Unmask all MSI's */
+ /* Unmask all MSIs */
advk_writel(pcie, 0, PCIE_MSI_MASK_REG);
/* Enable summary interrupt for GIC SPI source */
diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c
index 82acd6155adf..40b625458afa 100644
--- a/drivers/pci/controller/pci-hyperv.c
+++ b/drivers/pci/controller/pci-hyperv.c
@@ -1875,6 +1875,7 @@ static void hv_pci_devices_present(struct hv_pcibus_device *hbus,
static void hv_eject_device_work(struct work_struct *work)
{
struct pci_eject_response *ejct_pkt;
+ struct hv_pcibus_device *hbus;
struct hv_pci_dev *hpdev;
struct pci_dev *pdev;
unsigned long flags;
@@ -1885,6 +1886,7 @@ static void hv_eject_device_work(struct work_struct *work)
} ctxt;
hpdev = container_of(work, struct hv_pci_dev, wrk);
+ hbus = hpdev->hbus;
WARN_ON(hpdev->state != hv_pcichild_ejecting);
@@ -1895,8 +1897,7 @@ static void hv_eject_device_work(struct work_struct *work)
* because hbus->pci_bus may not exist yet.
*/
wslot = wslot_to_devfn(hpdev->desc.win_slot.slot);
- pdev = pci_get_domain_bus_and_slot(hpdev->hbus->sysdata.domain, 0,
- wslot);
+ pdev = pci_get_domain_bus_and_slot(hbus->sysdata.domain, 0, wslot);
if (pdev) {
pci_lock_rescan_remove();
pci_stop_and_remove_bus_device(pdev);
@@ -1904,9 +1905,9 @@ static void hv_eject_device_work(struct work_struct *work)
pci_unlock_rescan_remove();
}
- spin_lock_irqsave(&hpdev->hbus->device_list_lock, flags);
+ spin_lock_irqsave(&hbus->device_list_lock, flags);
list_del(&hpdev->list_entry);
- spin_unlock_irqrestore(&hpdev->hbus->device_list_lock, flags);
+ spin_unlock_irqrestore(&hbus->device_list_lock, flags);
if (hpdev->pci_slot)
pci_destroy_slot(hpdev->pci_slot);
@@ -1915,7 +1916,7 @@ static void hv_eject_device_work(struct work_struct *work)
ejct_pkt = (struct pci_eject_response *)&ctxt.pkt.message;
ejct_pkt->message_type.type = PCI_EJECTION_COMPLETE;
ejct_pkt->wslot.slot = hpdev->desc.win_slot.slot;
- vmbus_sendpacket(hpdev->hbus->hdev->channel, ejct_pkt,
+ vmbus_sendpacket(hbus->hdev->channel, ejct_pkt,
sizeof(*ejct_pkt), (unsigned long)&ctxt.pkt,
VM_PKT_DATA_INBAND, 0);
@@ -1924,7 +1925,9 @@ static void hv_eject_device_work(struct work_struct *work)
/* For the two refs got in new_pcichild_device() */
put_pcichild(hpdev);
put_pcichild(hpdev);
- put_hvpcibus(hpdev->hbus);
+ /* hpdev has been freed. Do not use it any more. */
+
+ put_hvpcibus(hbus);
}
/**
diff --git a/drivers/pci/controller/pci-tegra.c b/drivers/pci/controller/pci-tegra.c
index 464ba2538d52..9a917b2456f6 100644
--- a/drivers/pci/controller/pci-tegra.c
+++ b/drivers/pci/controller/pci-tegra.c
@@ -17,6 +17,7 @@
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/export.h>
+#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/iopoll.h>
#include <linux/irq.h>
@@ -30,6 +31,7 @@
#include <linux/of_platform.h>
#include <linux/pci.h>
#include <linux/phy/phy.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/sizes.h>
@@ -95,7 +97,8 @@
#define AFI_MSI_EN_VEC7 0xa8
#define AFI_CONFIGURATION 0xac
-#define AFI_CONFIGURATION_EN_FPCI (1 << 0)
+#define AFI_CONFIGURATION_EN_FPCI (1 << 0)
+#define AFI_CONFIGURATION_CLKEN_OVERRIDE (1 << 31)
#define AFI_FPCI_ERROR_MASKS 0xb0
@@ -159,13 +162,14 @@
#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_211 (0x1 << 20)
#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411 (0x2 << 20)
#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_111 (0x2 << 20)
+#define AFI_PCIE_CONFIG_PCIE_CLKREQ_GPIO(x) (1 << ((x) + 29))
+#define AFI_PCIE_CONFIG_PCIE_CLKREQ_GPIO_ALL (0x7 << 29)
#define AFI_FUSE 0x104
#define AFI_FUSE_PCIE_T0_GEN2_DIS (1 << 2)
#define AFI_PEX0_CTRL 0x110
#define AFI_PEX1_CTRL 0x118
-#define AFI_PEX2_CTRL 0x128
#define AFI_PEX_CTRL_RST (1 << 0)
#define AFI_PEX_CTRL_CLKREQ_EN (1 << 1)
#define AFI_PEX_CTRL_REFCLK_EN (1 << 3)
@@ -177,20 +181,74 @@
#define AFI_PEXBIAS_CTRL_0 0x168
+#define RP_PRIV_XP_DL 0x00000494
+#define RP_PRIV_XP_DL_GEN2_UPD_FC_TSHOLD (0x1ff << 1)
+
+#define RP_RX_HDR_LIMIT 0x00000e00
+#define RP_RX_HDR_LIMIT_PW_MASK (0xff << 8)
+#define RP_RX_HDR_LIMIT_PW (0x0e << 8)
+
+#define RP_ECTL_2_R1 0x00000e84
+#define RP_ECTL_2_R1_RX_CTLE_1C_MASK 0xffff
+
+#define RP_ECTL_4_R1 0x00000e8c
+#define RP_ECTL_4_R1_RX_CDR_CTRL_1C_MASK (0xffff << 16)
+#define RP_ECTL_4_R1_RX_CDR_CTRL_1C_SHIFT 16
+
+#define RP_ECTL_5_R1 0x00000e90
+#define RP_ECTL_5_R1_RX_EQ_CTRL_L_1C_MASK 0xffffffff
+
+#define RP_ECTL_6_R1 0x00000e94
+#define RP_ECTL_6_R1_RX_EQ_CTRL_H_1C_MASK 0xffffffff
+
+#define RP_ECTL_2_R2 0x00000ea4
+#define RP_ECTL_2_R2_RX_CTLE_1C_MASK 0xffff
+
+#define RP_ECTL_4_R2 0x00000eac
+#define RP_ECTL_4_R2_RX_CDR_CTRL_1C_MASK (0xffff << 16)
+#define RP_ECTL_4_R2_RX_CDR_CTRL_1C_SHIFT 16
+
+#define RP_ECTL_5_R2 0x00000eb0
+#define RP_ECTL_5_R2_RX_EQ_CTRL_L_1C_MASK 0xffffffff
+
+#define RP_ECTL_6_R2 0x00000eb4
+#define RP_ECTL_6_R2_RX_EQ_CTRL_H_1C_MASK 0xffffffff
+
#define RP_VEND_XP 0x00000f00
-#define RP_VEND_XP_DL_UP (1 << 30)
+#define RP_VEND_XP_DL_UP (1 << 30)
+#define RP_VEND_XP_OPPORTUNISTIC_ACK (1 << 27)
+#define RP_VEND_XP_OPPORTUNISTIC_UPDATEFC (1 << 28)
+#define RP_VEND_XP_UPDATE_FC_THRESHOLD_MASK (0xff << 18)
+
+#define RP_VEND_CTL0 0x00000f44
+#define RP_VEND_CTL0_DSK_RST_PULSE_WIDTH_MASK (0xf << 12)
+#define RP_VEND_CTL0_DSK_RST_PULSE_WIDTH (0x9 << 12)
+
+#define RP_VEND_CTL1 0x00000f48
+#define RP_VEND_CTL1_ERPT (1 << 13)
+
+#define RP_VEND_XP_BIST 0x00000f4c
+#define RP_VEND_XP_BIST_GOTO_L1_L2_AFTER_DLLP_DONE (1 << 28)
#define RP_VEND_CTL2 0x00000fa8
#define RP_VEND_CTL2_PCA_ENABLE (1 << 7)
#define RP_PRIV_MISC 0x00000fe0
-#define RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT (0xe << 0)
-#define RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT (0xf << 0)
+#define RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT (0xe << 0)
+#define RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT (0xf << 0)
+#define RP_PRIV_MISC_CTLR_CLK_CLAMP_THRESHOLD_MASK (0x7f << 16)
+#define RP_PRIV_MISC_CTLR_CLK_CLAMP_THRESHOLD (0xf << 16)
+#define RP_PRIV_MISC_CTLR_CLK_CLAMP_ENABLE (1 << 23)
+#define RP_PRIV_MISC_TMS_CLK_CLAMP_THRESHOLD_MASK (0x7f << 24)
+#define RP_PRIV_MISC_TMS_CLK_CLAMP_THRESHOLD (0xf << 24)
+#define RP_PRIV_MISC_TMS_CLK_CLAMP_ENABLE (1 << 31)
#define RP_LINK_CONTROL_STATUS 0x00000090
#define RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE 0x20000000
#define RP_LINK_CONTROL_STATUS_LINKSTAT_MASK 0x3fff0000
+#define RP_LINK_CONTROL_STATUS_2 0x000000b0
+
#define PADS_CTL_SEL 0x0000009c
#define PADS_CTL 0x000000a0
@@ -226,6 +284,7 @@
#define PADS_REFCLK_CFG_DRVI_SHIFT 12 /* 15:12 */
#define PME_ACK_TIMEOUT 10000
+#define LINK_RETRAIN_TIMEOUT 100000 /* in usec */
struct tegra_msi {
struct msi_controller chip;
@@ -249,10 +308,12 @@ struct tegra_pcie_soc {
unsigned int num_ports;
const struct tegra_pcie_port_soc *ports;
unsigned int msi_base_shift;
+ unsigned long afi_pex2_ctrl;
u32 pads_pll_ctl;
u32 tx_ref_sel;
u32 pads_refclk_cfg0;
u32 pads_refclk_cfg1;
+ u32 update_fc_threshold;
bool has_pex_clkreq_en;
bool has_pex_bias_ctrl;
bool has_intr_prsnt_sense;
@@ -260,6 +321,24 @@ struct tegra_pcie_soc {
bool has_gen2;
bool force_pca_enable;
bool program_uphy;
+ bool update_clamp_threshold;
+ bool program_deskew_time;
+ bool raw_violation_fixup;
+ bool update_fc_timer;
+ bool has_cache_bars;
+ struct {
+ struct {
+ u32 rp_ectl_2_r1;
+ u32 rp_ectl_4_r1;
+ u32 rp_ectl_5_r1;
+ u32 rp_ectl_6_r1;
+ u32 rp_ectl_2_r2;
+ u32 rp_ectl_4_r2;
+ u32 rp_ectl_5_r2;
+ u32 rp_ectl_6_r2;
+ } regs;
+ bool enable;
+ } ectl;
};
static inline struct tegra_msi *to_tegra_msi(struct msi_controller *chip)
@@ -321,6 +400,8 @@ struct tegra_pcie_port {
unsigned int lanes;
struct phy **phys;
+
+ struct gpio_desc *reset_gpio;
};
struct tegra_pcie_bus {
@@ -440,6 +521,7 @@ static struct pci_ops tegra_pcie_ops = {
static unsigned long tegra_pcie_port_get_pex_ctrl(struct tegra_pcie_port *port)
{
+ const struct tegra_pcie_soc *soc = port->pcie->soc;
unsigned long ret = 0;
switch (port->index) {
@@ -452,7 +534,7 @@ static unsigned long tegra_pcie_port_get_pex_ctrl(struct tegra_pcie_port *port)
break;
case 2:
- ret = AFI_PEX2_CTRL;
+ ret = soc->afi_pex2_ctrl;
break;
}
@@ -465,15 +547,162 @@ static void tegra_pcie_port_reset(struct tegra_pcie_port *port)
unsigned long value;
/* pulse reset signal */
- value = afi_readl(port->pcie, ctrl);
- value &= ~AFI_PEX_CTRL_RST;
- afi_writel(port->pcie, value, ctrl);
+ if (port->reset_gpio) {
+ gpiod_set_value(port->reset_gpio, 1);
+ } else {
+ value = afi_readl(port->pcie, ctrl);
+ value &= ~AFI_PEX_CTRL_RST;
+ afi_writel(port->pcie, value, ctrl);
+ }
usleep_range(1000, 2000);
- value = afi_readl(port->pcie, ctrl);
- value |= AFI_PEX_CTRL_RST;
- afi_writel(port->pcie, value, ctrl);
+ if (port->reset_gpio) {
+ gpiod_set_value(port->reset_gpio, 0);
+ } else {
+ value = afi_readl(port->pcie, ctrl);
+ value |= AFI_PEX_CTRL_RST;
+ afi_writel(port->pcie, value, ctrl);
+ }
+}
+
+static void tegra_pcie_enable_rp_features(struct tegra_pcie_port *port)
+{
+ const struct tegra_pcie_soc *soc = port->pcie->soc;
+ u32 value;
+
+ /* Enable AER capability */
+ value = readl(port->base + RP_VEND_CTL1);
+ value |= RP_VEND_CTL1_ERPT;
+ writel(value, port->base + RP_VEND_CTL1);
+
+ /* Optimal settings to enhance bandwidth */
+ value = readl(port->base + RP_VEND_XP);
+ value |= RP_VEND_XP_OPPORTUNISTIC_ACK;
+ value |= RP_VEND_XP_OPPORTUNISTIC_UPDATEFC;
+ writel(value, port->base + RP_VEND_XP);
+
+ /*
+ * LTSSM will wait for DLLP to finish before entering L1 or L2,
+ * to avoid truncation of PM messages which results in receiver errors
+ */
+ value = readl(port->base + RP_VEND_XP_BIST);
+ value |= RP_VEND_XP_BIST_GOTO_L1_L2_AFTER_DLLP_DONE;
+ writel(value, port->base + RP_VEND_XP_BIST);
+
+ value = readl(port->base + RP_PRIV_MISC);
+ value |= RP_PRIV_MISC_CTLR_CLK_CLAMP_ENABLE;
+ value |= RP_PRIV_MISC_TMS_CLK_CLAMP_ENABLE;
+
+ if (soc->update_clamp_threshold) {
+ value &= ~(RP_PRIV_MISC_CTLR_CLK_CLAMP_THRESHOLD_MASK |
+ RP_PRIV_MISC_TMS_CLK_CLAMP_THRESHOLD_MASK);
+ value |= RP_PRIV_MISC_CTLR_CLK_CLAMP_THRESHOLD |
+ RP_PRIV_MISC_TMS_CLK_CLAMP_THRESHOLD;
+ }
+
+ writel(value, port->base + RP_PRIV_MISC);
+}
+
+static void tegra_pcie_program_ectl_settings(struct tegra_pcie_port *port)
+{
+ const struct tegra_pcie_soc *soc = port->pcie->soc;
+ u32 value;
+
+ value = readl(port->base + RP_ECTL_2_R1);
+ value &= ~RP_ECTL_2_R1_RX_CTLE_1C_MASK;
+ value |= soc->ectl.regs.rp_ectl_2_r1;
+ writel(value, port->base + RP_ECTL_2_R1);
+
+ value = readl(port->base + RP_ECTL_4_R1);
+ value &= ~RP_ECTL_4_R1_RX_CDR_CTRL_1C_MASK;
+ value |= soc->ectl.regs.rp_ectl_4_r1 <<
+ RP_ECTL_4_R1_RX_CDR_CTRL_1C_SHIFT;
+ writel(value, port->base + RP_ECTL_4_R1);
+
+ value = readl(port->base + RP_ECTL_5_R1);
+ value &= ~RP_ECTL_5_R1_RX_EQ_CTRL_L_1C_MASK;
+ value |= soc->ectl.regs.rp_ectl_5_r1;
+ writel(value, port->base + RP_ECTL_5_R1);
+
+ value = readl(port->base + RP_ECTL_6_R1);
+ value &= ~RP_ECTL_6_R1_RX_EQ_CTRL_H_1C_MASK;
+ value |= soc->ectl.regs.rp_ectl_6_r1;
+ writel(value, port->base + RP_ECTL_6_R1);
+
+ value = readl(port->base + RP_ECTL_2_R2);
+ value &= ~RP_ECTL_2_R2_RX_CTLE_1C_MASK;
+ value |= soc->ectl.regs.rp_ectl_2_r2;
+ writel(value, port->base + RP_ECTL_2_R2);
+
+ value = readl(port->base + RP_ECTL_4_R2);
+ value &= ~RP_ECTL_4_R2_RX_CDR_CTRL_1C_MASK;
+ value |= soc->ectl.regs.rp_ectl_4_r2 <<
+ RP_ECTL_4_R2_RX_CDR_CTRL_1C_SHIFT;
+ writel(value, port->base + RP_ECTL_4_R2);
+
+ value = readl(port->base + RP_ECTL_5_R2);
+ value &= ~RP_ECTL_5_R2_RX_EQ_CTRL_L_1C_MASK;
+ value |= soc->ectl.regs.rp_ectl_5_r2;
+ writel(value, port->base + RP_ECTL_5_R2);
+
+ value = readl(port->base + RP_ECTL_6_R2);
+ value &= ~RP_ECTL_6_R2_RX_EQ_CTRL_H_1C_MASK;
+ value |= soc->ectl.regs.rp_ectl_6_r2;
+ writel(value, port->base + RP_ECTL_6_R2);
+}
+
+static void tegra_pcie_apply_sw_fixup(struct tegra_pcie_port *port)
+{
+ const struct tegra_pcie_soc *soc = port->pcie->soc;
+ u32 value;
+
+ /*
+ * Sometimes link speed change from Gen2 to Gen1 fails due to
+ * instability in deskew logic on lane-0. Increase the deskew
+ * retry time to resolve this issue.
+ */
+ if (soc->program_deskew_time) {
+ value = readl(port->base + RP_VEND_CTL0);
+ value &= ~RP_VEND_CTL0_DSK_RST_PULSE_WIDTH_MASK;
+ value |= RP_VEND_CTL0_DSK_RST_PULSE_WIDTH;
+ writel(value, port->base + RP_VEND_CTL0);
+ }
+
+ /* Fixup for read after write violation. */
+ if (soc->raw_violation_fixup) {
+ value = readl(port->base + RP_RX_HDR_LIMIT);
+ value &= ~RP_RX_HDR_LIMIT_PW_MASK;
+ value |= RP_RX_HDR_LIMIT_PW;
+ writel(value, port->base + RP_RX_HDR_LIMIT);
+
+ value = readl(port->base + RP_PRIV_XP_DL);
+ value |= RP_PRIV_XP_DL_GEN2_UPD_FC_TSHOLD;
+ writel(value, port->base + RP_PRIV_XP_DL);
+
+ value = readl(port->base + RP_VEND_XP);
+ value &= ~RP_VEND_XP_UPDATE_FC_THRESHOLD_MASK;
+ value |= soc->update_fc_threshold;
+ writel(value, port->base + RP_VEND_XP);
+ }
+
+ if (soc->update_fc_timer) {
+ value = readl(port->base + RP_VEND_XP);
+ value &= ~RP_VEND_XP_UPDATE_FC_THRESHOLD_MASK;
+ value |= soc->update_fc_threshold;
+ writel(value, port->base + RP_VEND_XP);
+ }
+
+ /*
+ * PCIe link doesn't come up with few legacy PCIe endpoints if
+ * root port advertises both Gen-1 and Gen-2 speeds in Tegra.
+ * Hence, the strategy followed here is to initially advertise
+ * only Gen-1 and after link is up, retrain link to Gen-2 speed
+ */
+ value = readl(port->base + RP_LINK_CONTROL_STATUS_2);
+ value &= ~PCI_EXP_LNKSTA_CLS;
+ value |= PCI_EXP_LNKSTA_CLS_2_5GB;
+ writel(value, port->base + RP_LINK_CONTROL_STATUS_2);
}
static void tegra_pcie_port_enable(struct tegra_pcie_port *port)
@@ -500,6 +729,13 @@ static void tegra_pcie_port_enable(struct tegra_pcie_port *port)
value |= RP_VEND_CTL2_PCA_ENABLE;
writel(value, port->base + RP_VEND_CTL2);
}
+
+ tegra_pcie_enable_rp_features(port);
+
+ if (soc->ectl.enable)
+ tegra_pcie_program_ectl_settings(port);
+
+ tegra_pcie_apply_sw_fixup(port);
}
static void tegra_pcie_port_disable(struct tegra_pcie_port *port)
@@ -521,6 +757,12 @@ static void tegra_pcie_port_disable(struct tegra_pcie_port *port)
value &= ~AFI_PEX_CTRL_REFCLK_EN;
afi_writel(port->pcie, value, ctrl);
+
+ /* disable PCIe port and set CLKREQ# as GPIO to allow PLLE power down */
+ value = afi_readl(port->pcie, AFI_PCIE_CONFIG);
+ value |= AFI_PCIE_CONFIG_PCIE_DISABLE(port->index);
+ value |= AFI_PCIE_CONFIG_PCIE_CLKREQ_GPIO(port->index);
+ afi_writel(port->pcie, value, AFI_PCIE_CONFIG);
}
static void tegra_pcie_port_free(struct tegra_pcie_port *port)
@@ -545,12 +787,15 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0bf1, tegra_pcie_fixup_class);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0e1c, tegra_pcie_fixup_class);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0e1d, tegra_pcie_fixup_class);
-/* Tegra PCIE requires relaxed ordering */
+/* Tegra20 and Tegra30 PCIE requires relaxed ordering */
static void tegra_pcie_relax_enable(struct pci_dev *dev)
{
pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_RELAX_EN);
}
-DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_relax_enable);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0bf0, tegra_pcie_relax_enable);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0bf1, tegra_pcie_relax_enable);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0e1c, tegra_pcie_relax_enable);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0e1d, tegra_pcie_relax_enable);
static int tegra_pcie_request_resources(struct tegra_pcie *pcie)
{
@@ -635,7 +880,7 @@ static irqreturn_t tegra_pcie_isr(int irq, void *arg)
* do not pollute kernel log with master abort reports since they
* happen a lot during enumeration
*/
- if (code == AFI_INTR_MASTER_ABORT)
+ if (code == AFI_INTR_MASTER_ABORT || code == AFI_INTR_PE_PRSNT_SENSE)
dev_dbg(dev, "%s, signature: %08x\n", err_msg[code], signature);
else
dev_err(dev, "%s, signature: %08x\n", err_msg[code], signature);
@@ -704,11 +949,13 @@ static void tegra_pcie_setup_translations(struct tegra_pcie *pcie)
afi_writel(pcie, 0, AFI_AXI_BAR5_SZ);
afi_writel(pcie, 0, AFI_FPCI_BAR5);
- /* map all upstream transactions as uncached */
- afi_writel(pcie, 0, AFI_CACHE_BAR0_ST);
- afi_writel(pcie, 0, AFI_CACHE_BAR0_SZ);
- afi_writel(pcie, 0, AFI_CACHE_BAR1_ST);
- afi_writel(pcie, 0, AFI_CACHE_BAR1_SZ);
+ if (pcie->soc->has_cache_bars) {
+ /* map all upstream transactions as uncached */
+ afi_writel(pcie, 0, AFI_CACHE_BAR0_ST);
+ afi_writel(pcie, 0, AFI_CACHE_BAR0_SZ);
+ afi_writel(pcie, 0, AFI_CACHE_BAR1_ST);
+ afi_writel(pcie, 0, AFI_CACHE_BAR1_SZ);
+ }
/* MSI translations are setup only when needed */
afi_writel(pcie, 0, AFI_MSI_FPCI_BAR_ST);
@@ -852,7 +1099,6 @@ static int tegra_pcie_port_phy_power_off(struct tegra_pcie_port *port)
static int tegra_pcie_phy_power_on(struct tegra_pcie *pcie)
{
struct device *dev = pcie->dev;
- const struct tegra_pcie_soc *soc = pcie->soc;
struct tegra_pcie_port *port;
int err;
@@ -878,12 +1124,6 @@ static int tegra_pcie_phy_power_on(struct tegra_pcie *pcie)
}
}
- /* Configure the reference clock driver */
- pads_writel(pcie, soc->pads_refclk_cfg0, PADS_REFCLK_CFG0);
-
- if (soc->num_ports > 2)
- pads_writel(pcie, soc->pads_refclk_cfg1, PADS_REFCLK_CFG1);
-
return 0;
}
@@ -918,13 +1158,11 @@ static int tegra_pcie_phy_power_off(struct tegra_pcie *pcie)
return 0;
}
-static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
+static void tegra_pcie_enable_controller(struct tegra_pcie *pcie)
{
- struct device *dev = pcie->dev;
const struct tegra_pcie_soc *soc = pcie->soc;
struct tegra_pcie_port *port;
unsigned long value;
- int err;
/* enable PLL power down */
if (pcie->phy) {
@@ -942,9 +1180,12 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
value = afi_readl(pcie, AFI_PCIE_CONFIG);
value &= ~AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK;
value |= AFI_PCIE_CONFIG_PCIE_DISABLE_ALL | pcie->xbar_config;
+ value |= AFI_PCIE_CONFIG_PCIE_CLKREQ_GPIO_ALL;
- list_for_each_entry(port, &pcie->ports, list)
+ list_for_each_entry(port, &pcie->ports, list) {
value &= ~AFI_PCIE_CONFIG_PCIE_DISABLE(port->index);
+ value &= ~AFI_PCIE_CONFIG_PCIE_CLKREQ_GPIO(port->index);
+ }
afi_writel(pcie, value, AFI_PCIE_CONFIG);
@@ -958,20 +1199,10 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
afi_writel(pcie, value, AFI_FUSE);
}
- if (soc->program_uphy) {
- err = tegra_pcie_phy_power_on(pcie);
- if (err < 0) {
- dev_err(dev, "failed to power on PHY(s): %d\n", err);
- return err;
- }
- }
-
- /* take the PCIe interface module out of reset */
- reset_control_deassert(pcie->pcie_xrst);
-
- /* finally enable PCIe */
+ /* Disable AFI dynamic clock gating and enable PCIe */
value = afi_readl(pcie, AFI_CONFIGURATION);
value |= AFI_CONFIGURATION_EN_FPCI;
+ value |= AFI_CONFIGURATION_CLKEN_OVERRIDE;
afi_writel(pcie, value, AFI_CONFIGURATION);
value = AFI_INTR_EN_INI_SLVERR | AFI_INTR_EN_INI_DECERR |
@@ -989,22 +1220,6 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
/* disable all exceptions */
afi_writel(pcie, 0, AFI_FPCI_ERROR_MASKS);
-
- return 0;
-}
-
-static void tegra_pcie_disable_controller(struct tegra_pcie *pcie)
-{
- int err;
-
- reset_control_assert(pcie->pcie_xrst);
-
- if (pcie->soc->program_uphy) {
- err = tegra_pcie_phy_power_off(pcie);
- if (err < 0)
- dev_err(pcie->dev, "failed to power off PHY(s): %d\n",
- err);
- }
}
static void tegra_pcie_power_off(struct tegra_pcie *pcie)
@@ -1014,13 +1229,11 @@ static void tegra_pcie_power_off(struct tegra_pcie *pcie)
int err;
reset_control_assert(pcie->afi_rst);
- reset_control_assert(pcie->pex_rst);
clk_disable_unprepare(pcie->pll_e);
if (soc->has_cml_clk)
clk_disable_unprepare(pcie->cml_clk);
clk_disable_unprepare(pcie->afi_clk);
- clk_disable_unprepare(pcie->pex_clk);
if (!dev->pm_domain)
tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
@@ -1048,46 +1261,66 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie)
if (err < 0)
dev_err(dev, "failed to enable regulators: %d\n", err);
- if (dev->pm_domain) {
- err = clk_prepare_enable(pcie->pex_clk);
+ if (!dev->pm_domain) {
+ err = tegra_powergate_power_on(TEGRA_POWERGATE_PCIE);
if (err) {
- dev_err(dev, "failed to enable PEX clock: %d\n", err);
- return err;
+ dev_err(dev, "failed to power ungate: %d\n", err);
+ goto regulator_disable;
}
- reset_control_deassert(pcie->pex_rst);
- } else {
- err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE,
- pcie->pex_clk,
- pcie->pex_rst);
+ err = tegra_powergate_remove_clamping(TEGRA_POWERGATE_PCIE);
if (err) {
- dev_err(dev, "powerup sequence failed: %d\n", err);
- return err;
+ dev_err(dev, "failed to remove clamp: %d\n", err);
+ goto powergate;
}
}
- reset_control_deassert(pcie->afi_rst);
-
err = clk_prepare_enable(pcie->afi_clk);
if (err < 0) {
dev_err(dev, "failed to enable AFI clock: %d\n", err);
- return err;
+ goto powergate;
}
if (soc->has_cml_clk) {
err = clk_prepare_enable(pcie->cml_clk);
if (err < 0) {
dev_err(dev, "failed to enable CML clock: %d\n", err);
- return err;
+ goto disable_afi_clk;
}
}
err = clk_prepare_enable(pcie->pll_e);
if (err < 0) {
dev_err(dev, "failed to enable PLLE clock: %d\n", err);
- return err;
+ goto disable_cml_clk;
}
+ reset_control_deassert(pcie->afi_rst);
+
return 0;
+
+disable_cml_clk:
+ if (soc->has_cml_clk)
+ clk_disable_unprepare(pcie->cml_clk);
+disable_afi_clk:
+ clk_disable_unprepare(pcie->afi_clk);
+powergate:
+ if (!dev->pm_domain)
+ tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
+regulator_disable:
+ regulator_bulk_disable(pcie->num_supplies, pcie->supplies);
+
+ return err;
+}
+
+static void tegra_pcie_apply_pad_settings(struct tegra_pcie *pcie)
+{
+ const struct tegra_pcie_soc *soc = pcie->soc;
+
+ /* Configure the reference clock driver */
+ pads_writel(pcie, soc->pads_refclk_cfg0, PADS_REFCLK_CFG0);
+
+ if (soc->num_ports > 2)
+ pads_writel(pcie, soc->pads_refclk_cfg1, PADS_REFCLK_CFG1);
}
static int tegra_pcie_clocks_get(struct tegra_pcie *pcie)
@@ -1647,6 +1880,15 @@ static int tegra_pcie_disable_msi(struct tegra_pcie *pcie)
return 0;
}
+static void tegra_pcie_disable_interrupts(struct tegra_pcie *pcie)
+{
+ u32 value;
+
+ value = afi_readl(pcie, AFI_INTR_MASK);
+ value &= ~AFI_INTR_MASK_INT_MASK;
+ afi_writel(pcie, value, AFI_INTR_MASK);
+}
+
static int tegra_pcie_get_xbar_config(struct tegra_pcie *pcie, u32 lanes,
u32 *xbar)
{
@@ -1990,6 +2232,7 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
struct tegra_pcie_port *rp;
unsigned int index;
u32 value;
+ char *label;
err = of_pci_get_devfn(port);
if (err < 0) {
@@ -2048,6 +2291,31 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
if (IS_ERR(rp->base))
return PTR_ERR(rp->base);
+ label = devm_kasprintf(dev, GFP_KERNEL, "pex-reset-%u", index);
+ if (!label) {
+ dev_err(dev, "failed to create reset GPIO label\n");
+ return -ENOMEM;
+ }
+
+ /*
+ * Returns -ENOENT if reset-gpios property is not populated
+ * and in this case fall back to using AFI per port register
+ * to toggle PERST# SFIO line.
+ */
+ rp->reset_gpio = devm_gpiod_get_from_of_node(dev, port,
+ "reset-gpios", 0,
+ GPIOD_OUT_LOW,
+ label);
+ if (IS_ERR(rp->reset_gpio)) {
+ if (PTR_ERR(rp->reset_gpio) == -ENOENT) {
+ rp->reset_gpio = NULL;
+ } else {
+ dev_err(dev, "failed to get reset GPIO: %d\n",
+ err);
+ return PTR_ERR(rp->reset_gpio);
+ }
+ }
+
list_add_tail(&rp->list, &pcie->ports);
}
@@ -2095,7 +2363,7 @@ static bool tegra_pcie_port_check_link(struct tegra_pcie_port *port)
} while (--timeout);
if (!timeout) {
- dev_err(dev, "link %u down, retrying\n", port->index);
+ dev_dbg(dev, "link %u down, retrying\n", port->index);
goto retry;
}
@@ -2117,6 +2385,64 @@ retry:
return false;
}
+static void tegra_pcie_change_link_speed(struct tegra_pcie *pcie)
+{
+ struct device *dev = pcie->dev;
+ struct tegra_pcie_port *port;
+ ktime_t deadline;
+ u32 value;
+
+ list_for_each_entry(port, &pcie->ports, list) {
+ /*
+ * "Supported Link Speeds Vector" in "Link Capabilities 2"
+ * is not supported by Tegra. tegra_pcie_change_link_speed()
+ * is called only for Tegra chips which support Gen2.
+ * So there no harm if supported link speed is not verified.
+ */
+ value = readl(port->base + RP_LINK_CONTROL_STATUS_2);
+ value &= ~PCI_EXP_LNKSTA_CLS;
+ value |= PCI_EXP_LNKSTA_CLS_5_0GB;
+ writel(value, port->base + RP_LINK_CONTROL_STATUS_2);
+
+ /*
+ * Poll until link comes back from recovery to avoid race
+ * condition.
+ */
+ deadline = ktime_add_us(ktime_get(), LINK_RETRAIN_TIMEOUT);
+
+ while (ktime_before(ktime_get(), deadline)) {
+ value = readl(port->base + RP_LINK_CONTROL_STATUS);
+ if ((value & PCI_EXP_LNKSTA_LT) == 0)
+ break;
+
+ usleep_range(2000, 3000);
+ }
+
+ if (value & PCI_EXP_LNKSTA_LT)
+ dev_warn(dev, "PCIe port %u link is in recovery\n",
+ port->index);
+
+ /* Retrain the link */
+ value = readl(port->base + RP_LINK_CONTROL_STATUS);
+ value |= PCI_EXP_LNKCTL_RL;
+ writel(value, port->base + RP_LINK_CONTROL_STATUS);
+
+ deadline = ktime_add_us(ktime_get(), LINK_RETRAIN_TIMEOUT);
+
+ while (ktime_before(ktime_get(), deadline)) {
+ value = readl(port->base + RP_LINK_CONTROL_STATUS);
+ if ((value & PCI_EXP_LNKSTA_LT) == 0)
+ break;
+
+ usleep_range(2000, 3000);
+ }
+
+ if (value & PCI_EXP_LNKSTA_LT)
+ dev_err(dev, "failed to retrain link of port %u\n",
+ port->index);
+ }
+}
+
static void tegra_pcie_enable_ports(struct tegra_pcie *pcie)
{
struct device *dev = pcie->dev;
@@ -2127,7 +2453,12 @@ static void tegra_pcie_enable_ports(struct tegra_pcie *pcie)
port->index, port->lanes);
tegra_pcie_port_enable(port);
+ }
+ /* Start LTSSM from Tegra side */
+ reset_control_deassert(pcie->pcie_xrst);
+
+ list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
if (tegra_pcie_port_check_link(port))
continue;
@@ -2136,12 +2467,17 @@ static void tegra_pcie_enable_ports(struct tegra_pcie *pcie)
tegra_pcie_port_disable(port);
tegra_pcie_port_free(port);
}
+
+ if (pcie->soc->has_gen2)
+ tegra_pcie_change_link_speed(pcie);
}
static void tegra_pcie_disable_ports(struct tegra_pcie *pcie)
{
struct tegra_pcie_port *port, *tmp;
+ reset_control_assert(pcie->pcie_xrst);
+
list_for_each_entry_safe(port, tmp, &pcie->ports, list)
tegra_pcie_port_disable(port);
}
@@ -2155,6 +2491,7 @@ static const struct tegra_pcie_soc tegra20_pcie = {
.num_ports = 2,
.ports = tegra20_pcie_ports,
.msi_base_shift = 0,
+ .afi_pex2_ctrl = 0x128,
.pads_pll_ctl = PADS_PLL_CTL_TEGRA20,
.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_DIV10,
.pads_refclk_cfg0 = 0xfa5cfa5c,
@@ -2165,6 +2502,12 @@ static const struct tegra_pcie_soc tegra20_pcie = {
.has_gen2 = false,
.force_pca_enable = false,
.program_uphy = true,
+ .update_clamp_threshold = false,
+ .program_deskew_time = false,
+ .raw_violation_fixup = false,
+ .update_fc_timer = false,
+ .has_cache_bars = true,
+ .ectl.enable = false,
};
static const struct tegra_pcie_port_soc tegra30_pcie_ports[] = {
@@ -2188,6 +2531,12 @@ static const struct tegra_pcie_soc tegra30_pcie = {
.has_gen2 = false,
.force_pca_enable = false,
.program_uphy = true,
+ .update_clamp_threshold = false,
+ .program_deskew_time = false,
+ .raw_violation_fixup = false,
+ .update_fc_timer = false,
+ .has_cache_bars = false,
+ .ectl.enable = false,
};
static const struct tegra_pcie_soc tegra124_pcie = {
@@ -2197,6 +2546,8 @@ static const struct tegra_pcie_soc tegra124_pcie = {
.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
.pads_refclk_cfg0 = 0x44ac44ac,
+ /* FC threshold is bit[25:18] */
+ .update_fc_threshold = 0x03fc0000,
.has_pex_clkreq_en = true,
.has_pex_bias_ctrl = true,
.has_intr_prsnt_sense = true,
@@ -2204,6 +2555,12 @@ static const struct tegra_pcie_soc tegra124_pcie = {
.has_gen2 = true,
.force_pca_enable = false,
.program_uphy = true,
+ .update_clamp_threshold = true,
+ .program_deskew_time = false,
+ .raw_violation_fixup = true,
+ .update_fc_timer = false,
+ .has_cache_bars = false,
+ .ectl.enable = false,
};
static const struct tegra_pcie_soc tegra210_pcie = {
@@ -2213,6 +2570,8 @@ static const struct tegra_pcie_soc tegra210_pcie = {
.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
.pads_refclk_cfg0 = 0x90b890b8,
+ /* FC threshold is bit[25:18] */
+ .update_fc_threshold = 0x01800000,
.has_pex_clkreq_en = true,
.has_pex_bias_ctrl = true,
.has_intr_prsnt_sense = true,
@@ -2220,6 +2579,24 @@ static const struct tegra_pcie_soc tegra210_pcie = {
.has_gen2 = true,
.force_pca_enable = true,
.program_uphy = true,
+ .update_clamp_threshold = true,
+ .program_deskew_time = true,
+ .raw_violation_fixup = false,
+ .update_fc_timer = true,
+ .has_cache_bars = false,
+ .ectl = {
+ .regs = {
+ .rp_ectl_2_r1 = 0x0000000f,
+ .rp_ectl_4_r1 = 0x00000067,
+ .rp_ectl_5_r1 = 0x55010000,
+ .rp_ectl_6_r1 = 0x00000001,
+ .rp_ectl_2_r2 = 0x0000008f,
+ .rp_ectl_4_r2 = 0x000000c7,
+ .rp_ectl_5_r2 = 0x55010000,
+ .rp_ectl_6_r2 = 0x00000001,
+ },
+ .enable = true,
+ },
};
static const struct tegra_pcie_port_soc tegra186_pcie_ports[] = {
@@ -2232,6 +2609,7 @@ static const struct tegra_pcie_soc tegra186_pcie = {
.num_ports = 3,
.ports = tegra186_pcie_ports,
.msi_base_shift = 8,
+ .afi_pex2_ctrl = 0x19c,
.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
.pads_refclk_cfg0 = 0x80b880b8,
@@ -2243,6 +2621,12 @@ static const struct tegra_pcie_soc tegra186_pcie = {
.has_gen2 = true,
.force_pca_enable = false,
.program_uphy = false,
+ .update_clamp_threshold = false,
+ .program_deskew_time = false,
+ .raw_violation_fixup = false,
+ .update_fc_timer = false,
+ .has_cache_bars = false,
+ .ectl.enable = false,
};
static const struct of_device_id tegra_pcie_of_match[] = {
@@ -2485,16 +2869,32 @@ static int __maybe_unused tegra_pcie_pm_suspend(struct device *dev)
{
struct tegra_pcie *pcie = dev_get_drvdata(dev);
struct tegra_pcie_port *port;
+ int err;
list_for_each_entry(port, &pcie->ports, list)
tegra_pcie_pme_turnoff(port);
tegra_pcie_disable_ports(pcie);
+ /*
+ * AFI_INTR is unmasked in tegra_pcie_enable_controller(), mask it to
+ * avoid unwanted interrupts raised by AFI after pex_rst is asserted.
+ */
+ tegra_pcie_disable_interrupts(pcie);
+
+ if (pcie->soc->program_uphy) {
+ err = tegra_pcie_phy_power_off(pcie);
+ if (err < 0)
+ dev_err(dev, "failed to power off PHY(s): %d\n", err);
+ }
+
+ reset_control_assert(pcie->pex_rst);
+ clk_disable_unprepare(pcie->pex_clk);
+
if (IS_ENABLED(CONFIG_PCI_MSI))
tegra_pcie_disable_msi(pcie);
- tegra_pcie_disable_controller(pcie);
+ pinctrl_pm_select_idle_state(dev);
tegra_pcie_power_off(pcie);
return 0;
@@ -2510,20 +2910,45 @@ static int __maybe_unused tegra_pcie_pm_resume(struct device *dev)
dev_err(dev, "tegra pcie power on fail: %d\n", err);
return err;
}
- err = tegra_pcie_enable_controller(pcie);
- if (err) {
- dev_err(dev, "tegra pcie controller enable fail: %d\n", err);
+
+ err = pinctrl_pm_select_default_state(dev);
+ if (err < 0) {
+ dev_err(dev, "failed to disable PCIe IO DPD: %d\n", err);
goto poweroff;
}
+
+ tegra_pcie_enable_controller(pcie);
tegra_pcie_setup_translations(pcie);
if (IS_ENABLED(CONFIG_PCI_MSI))
tegra_pcie_enable_msi(pcie);
+ err = clk_prepare_enable(pcie->pex_clk);
+ if (err) {
+ dev_err(dev, "failed to enable PEX clock: %d\n", err);
+ goto pex_dpd_enable;
+ }
+
+ reset_control_deassert(pcie->pex_rst);
+
+ if (pcie->soc->program_uphy) {
+ err = tegra_pcie_phy_power_on(pcie);
+ if (err < 0) {
+ dev_err(dev, "failed to power on PHY(s): %d\n", err);
+ goto disable_pex_clk;
+ }
+ }
+
+ tegra_pcie_apply_pad_settings(pcie);
tegra_pcie_enable_ports(pcie);
return 0;
+disable_pex_clk:
+ reset_control_assert(pcie->pex_rst);
+ clk_disable_unprepare(pcie->pex_clk);
+pex_dpd_enable:
+ pinctrl_pm_select_idle_state(dev);
poweroff:
tegra_pcie_power_off(pcie);
diff --git a/drivers/pci/controller/pcie-altera-msi.c b/drivers/pci/controller/pcie-altera-msi.c
index 025ef7d9a046..16d938920ca5 100644
--- a/drivers/pci/controller/pcie-altera-msi.c
+++ b/drivers/pci/controller/pcie-altera-msi.c
@@ -10,6 +10,7 @@
#include <linux/interrupt.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/init.h>
+#include <linux/module.h>
#include <linux/msi.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
@@ -288,4 +289,13 @@ static int __init altera_msi_init(void)
{
return platform_driver_register(&altera_msi_driver);
}
+
+static void __exit altera_msi_exit(void)
+{
+ platform_driver_unregister(&altera_msi_driver);
+}
+
subsys_initcall(altera_msi_init);
+MODULE_DEVICE_TABLE(of, altera_msi_of_match);
+module_exit(altera_msi_exit);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/controller/pcie-altera.c b/drivers/pci/controller/pcie-altera.c
index 27edcebd1726..d2497ca43828 100644
--- a/drivers/pci/controller/pcie-altera.c
+++ b/drivers/pci/controller/pcie-altera.c
@@ -10,6 +10,7 @@
#include <linux/interrupt.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/init.h>
+#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
@@ -43,6 +44,8 @@
#define S10_RP_RXCPL_STATUS 0x200C
#define S10_RP_CFG_ADDR(pcie, reg) \
(((pcie)->hip_base) + (reg) + (1 << 20))
+#define S10_RP_SECONDARY(pcie) \
+ readb(S10_RP_CFG_ADDR(pcie, PCI_SECONDARY_BUS))
/* TLP configuration type 0 and 1 */
#define TLP_FMTTYPE_CFGRD0 0x04 /* Configuration Read Type 0 */
@@ -54,14 +57,9 @@
#define TLP_WRITE_TAG 0x10
#define RP_DEVFN 0
#define TLP_REQ_ID(bus, devfn) (((bus) << 8) | (devfn))
-#define TLP_CFGRD_DW0(pcie, bus) \
- ((((bus == pcie->root_bus_nr) ? pcie->pcie_data->cfgrd0 \
- : pcie->pcie_data->cfgrd1) << 24) | \
- TLP_PAYLOAD_SIZE)
-#define TLP_CFGWR_DW0(pcie, bus) \
- ((((bus == pcie->root_bus_nr) ? pcie->pcie_data->cfgwr0 \
- : pcie->pcie_data->cfgwr1) << 24) | \
- TLP_PAYLOAD_SIZE)
+#define TLP_CFG_DW0(pcie, cfg) \
+ (((cfg) << 24) | \
+ TLP_PAYLOAD_SIZE)
#define TLP_CFG_DW1(pcie, tag, be) \
(((TLP_REQ_ID(pcie->root_bus_nr, RP_DEVFN)) << 16) | (tag << 8) | (be))
#define TLP_CFG_DW2(bus, devfn, offset) \
@@ -321,14 +319,31 @@ static void s10_tlp_write_packet(struct altera_pcie *pcie, u32 *headers,
s10_tlp_write_tx(pcie, data, RP_TX_EOP);
}
+static void get_tlp_header(struct altera_pcie *pcie, u8 bus, u32 devfn,
+ int where, u8 byte_en, bool read, u32 *headers)
+{
+ u8 cfg;
+ u8 cfg0 = read ? pcie->pcie_data->cfgrd0 : pcie->pcie_data->cfgwr0;
+ u8 cfg1 = read ? pcie->pcie_data->cfgrd1 : pcie->pcie_data->cfgwr1;
+ u8 tag = read ? TLP_READ_TAG : TLP_WRITE_TAG;
+
+ if (pcie->pcie_data->version == ALTERA_PCIE_V1)
+ cfg = (bus == pcie->root_bus_nr) ? cfg0 : cfg1;
+ else
+ cfg = (bus > S10_RP_SECONDARY(pcie)) ? cfg0 : cfg1;
+
+ headers[0] = TLP_CFG_DW0(pcie, cfg);
+ headers[1] = TLP_CFG_DW1(pcie, tag, byte_en);
+ headers[2] = TLP_CFG_DW2(bus, devfn, where);
+}
+
static int tlp_cfg_dword_read(struct altera_pcie *pcie, u8 bus, u32 devfn,
int where, u8 byte_en, u32 *value)
{
u32 headers[TLP_HDR_SIZE];
- headers[0] = TLP_CFGRD_DW0(pcie, bus);
- headers[1] = TLP_CFG_DW1(pcie, TLP_READ_TAG, byte_en);
- headers[2] = TLP_CFG_DW2(bus, devfn, where);
+ get_tlp_header(pcie, bus, devfn, where, byte_en, true,
+ headers);
pcie->pcie_data->ops->tlp_write_pkt(pcie, headers, 0, false);
@@ -341,9 +356,8 @@ static int tlp_cfg_dword_write(struct altera_pcie *pcie, u8 bus, u32 devfn,
u32 headers[TLP_HDR_SIZE];
int ret;
- headers[0] = TLP_CFGWR_DW0(pcie, bus);
- headers[1] = TLP_CFG_DW1(pcie, TLP_WRITE_TAG, byte_en);
- headers[2] = TLP_CFG_DW2(bus, devfn, where);
+ get_tlp_header(pcie, bus, devfn, where, byte_en, false,
+ headers);
/* check alignment to Qword */
if ((where & 0x7) == 0)
@@ -705,6 +719,13 @@ static int altera_pcie_init_irq_domain(struct altera_pcie *pcie)
return 0;
}
+static void altera_pcie_irq_teardown(struct altera_pcie *pcie)
+{
+ irq_set_chained_handler_and_data(pcie->irq, NULL, NULL);
+ irq_domain_remove(pcie->irq_domain);
+ irq_dispose_mapping(pcie->irq);
+}
+
static int altera_pcie_parse_dt(struct altera_pcie *pcie)
{
struct device *dev = &pcie->pdev->dev;
@@ -798,6 +819,7 @@ static int altera_pcie_probe(struct platform_device *pdev)
pcie = pci_host_bridge_priv(bridge);
pcie->pdev = pdev;
+ platform_set_drvdata(pdev, pcie);
match = of_match_device(altera_pcie_of_match, &pdev->dev);
if (!match)
@@ -855,13 +877,28 @@ static int altera_pcie_probe(struct platform_device *pdev)
return ret;
}
+static int altera_pcie_remove(struct platform_device *pdev)
+{
+ struct altera_pcie *pcie = platform_get_drvdata(pdev);
+ struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie);
+
+ pci_stop_root_bus(bridge->bus);
+ pci_remove_root_bus(bridge->bus);
+ pci_free_resource_list(&pcie->resources);
+ altera_pcie_irq_teardown(pcie);
+
+ return 0;
+}
+
static struct platform_driver altera_pcie_driver = {
.probe = altera_pcie_probe,
+ .remove = altera_pcie_remove,
.driver = {
.name = "altera-pcie",
.of_match_table = altera_pcie_of_match,
- .suppress_bind_attrs = true,
},
};
-builtin_platform_driver(altera_pcie_driver);
+MODULE_DEVICE_TABLE(of, altera_pcie_of_match);
+module_platform_driver(altera_pcie_driver);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/controller/pcie-iproc-platform.c b/drivers/pci/controller/pcie-iproc-platform.c
index f30f5f3fb5c1..5a3550b6bb29 100644
--- a/drivers/pci/controller/pcie-iproc-platform.c
+++ b/drivers/pci/controller/pcie-iproc-platform.c
@@ -87,7 +87,7 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev)
/*
* DT nodes are not used by all platforms that use the iProc PCIe
- * core driver. For platforms that require explict inbound mapping
+ * core driver. For platforms that require explicit inbound mapping
* configuration, "dma-ranges" would have been present in DT
*/
pcie->need_ib_cfg = of_property_read_bool(np, "dma-ranges");
diff --git a/drivers/pci/controller/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c
index e3ca46497470..2d457bfdaf66 100644
--- a/drivers/pci/controller/pcie-iproc.c
+++ b/drivers/pci/controller/pcie-iproc.c
@@ -163,7 +163,7 @@ enum iproc_pcie_ib_map_type {
* @size_unit: inbound mapping region size unit, could be SZ_1K, SZ_1M, or
* SZ_1G
* @region_sizes: list of supported inbound mapping region sizes in KB, MB, or
- * GB, depedning on the size unit
+ * GB, depending on the size unit
* @nr_sizes: number of supported inbound mapping region sizes
* @nr_windows: number of supported inbound mapping windows for the region
* @imap_addr_offset: register offset between the upper and lower 32-bit
diff --git a/drivers/pci/controller/pcie-mobiveil.c b/drivers/pci/controller/pcie-mobiveil.c
index 77052a0712d0..672e633601c7 100644
--- a/drivers/pci/controller/pcie-mobiveil.c
+++ b/drivers/pci/controller/pcie-mobiveil.c
@@ -31,56 +31,61 @@
* translation tables are grouped into windows, each window registers are
* grouped into blocks of 4 or 16 registers each
*/
-#define PAB_REG_BLOCK_SIZE 16
-#define PAB_EXT_REG_BLOCK_SIZE 4
+#define PAB_REG_BLOCK_SIZE 16
+#define PAB_EXT_REG_BLOCK_SIZE 4
-#define PAB_REG_ADDR(offset, win) (offset + (win * PAB_REG_BLOCK_SIZE))
-#define PAB_EXT_REG_ADDR(offset, win) (offset + (win * PAB_EXT_REG_BLOCK_SIZE))
+#define PAB_REG_ADDR(offset, win) \
+ (offset + (win * PAB_REG_BLOCK_SIZE))
+#define PAB_EXT_REG_ADDR(offset, win) \
+ (offset + (win * PAB_EXT_REG_BLOCK_SIZE))
-#define LTSSM_STATUS 0x0404
-#define LTSSM_STATUS_L0_MASK 0x3f
-#define LTSSM_STATUS_L0 0x2d
+#define LTSSM_STATUS 0x0404
+#define LTSSM_STATUS_L0_MASK 0x3f
+#define LTSSM_STATUS_L0 0x2d
-#define PAB_CTRL 0x0808
-#define AMBA_PIO_ENABLE_SHIFT 0
-#define PEX_PIO_ENABLE_SHIFT 1
-#define PAGE_SEL_SHIFT 13
-#define PAGE_SEL_MASK 0x3f
-#define PAGE_LO_MASK 0x3ff
-#define PAGE_SEL_EN 0xc00
-#define PAGE_SEL_OFFSET_SHIFT 10
+#define PAB_CTRL 0x0808
+#define AMBA_PIO_ENABLE_SHIFT 0
+#define PEX_PIO_ENABLE_SHIFT 1
+#define PAGE_SEL_SHIFT 13
+#define PAGE_SEL_MASK 0x3f
+#define PAGE_LO_MASK 0x3ff
+#define PAGE_SEL_OFFSET_SHIFT 10
-#define PAB_AXI_PIO_CTRL 0x0840
-#define APIO_EN_MASK 0xf
+#define PAB_AXI_PIO_CTRL 0x0840
+#define APIO_EN_MASK 0xf
-#define PAB_PEX_PIO_CTRL 0x08c0
-#define PIO_ENABLE_SHIFT 0
+#define PAB_PEX_PIO_CTRL 0x08c0
+#define PIO_ENABLE_SHIFT 0
#define PAB_INTP_AMBA_MISC_ENB 0x0b0c
-#define PAB_INTP_AMBA_MISC_STAT 0x0b1c
+#define PAB_INTP_AMBA_MISC_STAT 0x0b1c
#define PAB_INTP_INTX_MASK 0x01e0
#define PAB_INTP_MSI_MASK 0x8
-#define PAB_AXI_AMAP_CTRL(win) PAB_REG_ADDR(0x0ba0, win)
-#define WIN_ENABLE_SHIFT 0
-#define WIN_TYPE_SHIFT 1
+#define PAB_AXI_AMAP_CTRL(win) PAB_REG_ADDR(0x0ba0, win)
+#define WIN_ENABLE_SHIFT 0
+#define WIN_TYPE_SHIFT 1
+#define WIN_TYPE_MASK 0x3
+#define WIN_SIZE_MASK 0xfffffc00
#define PAB_EXT_AXI_AMAP_SIZE(win) PAB_EXT_REG_ADDR(0xbaf0, win)
+#define PAB_EXT_AXI_AMAP_AXI_WIN(win) PAB_EXT_REG_ADDR(0x80a0, win)
#define PAB_AXI_AMAP_AXI_WIN(win) PAB_REG_ADDR(0x0ba4, win)
#define AXI_WINDOW_ALIGN_MASK 3
#define PAB_AXI_AMAP_PEX_WIN_L(win) PAB_REG_ADDR(0x0ba8, win)
-#define PAB_BUS_SHIFT 24
-#define PAB_DEVICE_SHIFT 19
-#define PAB_FUNCTION_SHIFT 16
+#define PAB_BUS_SHIFT 24
+#define PAB_DEVICE_SHIFT 19
+#define PAB_FUNCTION_SHIFT 16
#define PAB_AXI_AMAP_PEX_WIN_H(win) PAB_REG_ADDR(0x0bac, win)
#define PAB_INTP_AXI_PIO_CLASS 0x474
-#define PAB_PEX_AMAP_CTRL(win) PAB_REG_ADDR(0x4ba0, win)
-#define AMAP_CTRL_EN_SHIFT 0
-#define AMAP_CTRL_TYPE_SHIFT 1
+#define PAB_PEX_AMAP_CTRL(win) PAB_REG_ADDR(0x4ba0, win)
+#define AMAP_CTRL_EN_SHIFT 0
+#define AMAP_CTRL_TYPE_SHIFT 1
+#define AMAP_CTRL_TYPE_MASK 3
#define PAB_EXT_PEX_AMAP_SIZEN(win) PAB_EXT_REG_ADDR(0xbef0, win)
#define PAB_PEX_AMAP_AXI_WIN(win) PAB_REG_ADDR(0x4ba4, win)
@@ -88,34 +93,40 @@
#define PAB_PEX_AMAP_PEX_WIN_H(win) PAB_REG_ADDR(0x4bac, win)
/* starting offset of INTX bits in status register */
-#define PAB_INTX_START 5
+#define PAB_INTX_START 5
/* supported number of MSI interrupts */
-#define PCI_NUM_MSI 16
+#define PCI_NUM_MSI 16
/* MSI registers */
-#define MSI_BASE_LO_OFFSET 0x04
-#define MSI_BASE_HI_OFFSET 0x08
-#define MSI_SIZE_OFFSET 0x0c
-#define MSI_ENABLE_OFFSET 0x14
-#define MSI_STATUS_OFFSET 0x18
-#define MSI_DATA_OFFSET 0x20
-#define MSI_ADDR_L_OFFSET 0x24
-#define MSI_ADDR_H_OFFSET 0x28
+#define MSI_BASE_LO_OFFSET 0x04
+#define MSI_BASE_HI_OFFSET 0x08
+#define MSI_SIZE_OFFSET 0x0c
+#define MSI_ENABLE_OFFSET 0x14
+#define MSI_STATUS_OFFSET 0x18
+#define MSI_DATA_OFFSET 0x20
+#define MSI_ADDR_L_OFFSET 0x24
+#define MSI_ADDR_H_OFFSET 0x28
/* outbound and inbound window definitions */
-#define WIN_NUM_0 0
-#define WIN_NUM_1 1
-#define CFG_WINDOW_TYPE 0
-#define IO_WINDOW_TYPE 1
-#define MEM_WINDOW_TYPE 2
-#define IB_WIN_SIZE ((u64)256 * 1024 * 1024 * 1024)
-#define MAX_PIO_WINDOWS 8
+#define WIN_NUM_0 0
+#define WIN_NUM_1 1
+#define CFG_WINDOW_TYPE 0
+#define IO_WINDOW_TYPE 1
+#define MEM_WINDOW_TYPE 2
+#define IB_WIN_SIZE ((u64)256 * 1024 * 1024 * 1024)
+#define MAX_PIO_WINDOWS 8
/* Parameters for the waiting for link up routine */
-#define LINK_WAIT_MAX_RETRIES 10
-#define LINK_WAIT_MIN 90000
-#define LINK_WAIT_MAX 100000
+#define LINK_WAIT_MAX_RETRIES 10
+#define LINK_WAIT_MIN 90000
+#define LINK_WAIT_MAX 100000
+
+#define PAGED_ADDR_BNDRY 0xc00
+#define OFFSET_TO_PAGE_ADDR(off) \
+ ((off & PAGE_LO_MASK) | PAGED_ADDR_BNDRY)
+#define OFFSET_TO_PAGE_IDX(off) \
+ ((off >> PAGE_SEL_OFFSET_SHIFT) & PAGE_SEL_MASK)
struct mobiveil_msi { /* MSI information */
struct mutex lock; /* protect bitmap variable */
@@ -145,15 +156,119 @@ struct mobiveil_pcie {
struct mobiveil_msi msi;
};
-static inline void csr_writel(struct mobiveil_pcie *pcie, const u32 value,
- const u32 reg)
+/*
+ * mobiveil_pcie_sel_page - routine to access paged register
+ *
+ * Registers whose address greater than PAGED_ADDR_BNDRY (0xc00) are paged,
+ * for this scheme to work extracted higher 6 bits of the offset will be
+ * written to pg_sel field of PAB_CTRL register and rest of the lower 10
+ * bits enabled with PAGED_ADDR_BNDRY are used as offset of the register.
+ */
+static void mobiveil_pcie_sel_page(struct mobiveil_pcie *pcie, u8 pg_idx)
+{
+ u32 val;
+
+ val = readl(pcie->csr_axi_slave_base + PAB_CTRL);
+ val &= ~(PAGE_SEL_MASK << PAGE_SEL_SHIFT);
+ val |= (pg_idx & PAGE_SEL_MASK) << PAGE_SEL_SHIFT;
+
+ writel(val, pcie->csr_axi_slave_base + PAB_CTRL);
+}
+
+static void *mobiveil_pcie_comp_addr(struct mobiveil_pcie *pcie, u32 off)
+{
+ if (off < PAGED_ADDR_BNDRY) {
+ /* For directly accessed registers, clear the pg_sel field */
+ mobiveil_pcie_sel_page(pcie, 0);
+ return pcie->csr_axi_slave_base + off;
+ }
+
+ mobiveil_pcie_sel_page(pcie, OFFSET_TO_PAGE_IDX(off));
+ return pcie->csr_axi_slave_base + OFFSET_TO_PAGE_ADDR(off);
+}
+
+static int mobiveil_pcie_read(void __iomem *addr, int size, u32 *val)
{
- writel_relaxed(value, pcie->csr_axi_slave_base + reg);
+ if ((uintptr_t)addr & (size - 1)) {
+ *val = 0;
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ }
+
+ switch (size) {
+ case 4:
+ *val = readl(addr);
+ break;
+ case 2:
+ *val = readw(addr);
+ break;
+ case 1:
+ *val = readb(addr);
+ break;
+ default:
+ *val = 0;
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
}
-static inline u32 csr_readl(struct mobiveil_pcie *pcie, const u32 reg)
+static int mobiveil_pcie_write(void __iomem *addr, int size, u32 val)
{
- return readl_relaxed(pcie->csr_axi_slave_base + reg);
+ if ((uintptr_t)addr & (size - 1))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ switch (size) {
+ case 4:
+ writel(val, addr);
+ break;
+ case 2:
+ writew(val, addr);
+ break;
+ case 1:
+ writeb(val, addr);
+ break;
+ default:
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static u32 csr_read(struct mobiveil_pcie *pcie, u32 off, size_t size)
+{
+ void *addr;
+ u32 val;
+ int ret;
+
+ addr = mobiveil_pcie_comp_addr(pcie, off);
+
+ ret = mobiveil_pcie_read(addr, size, &val);
+ if (ret)
+ dev_err(&pcie->pdev->dev, "read CSR address failed\n");
+
+ return val;
+}
+
+static void csr_write(struct mobiveil_pcie *pcie, u32 val, u32 off, size_t size)
+{
+ void *addr;
+ int ret;
+
+ addr = mobiveil_pcie_comp_addr(pcie, off);
+
+ ret = mobiveil_pcie_write(addr, size, val);
+ if (ret)
+ dev_err(&pcie->pdev->dev, "write CSR address failed\n");
+}
+
+static u32 csr_readl(struct mobiveil_pcie *pcie, u32 off)
+{
+ return csr_read(pcie, off, 0x4);
+}
+
+static void csr_writel(struct mobiveil_pcie *pcie, u32 val, u32 off)
+{
+ csr_write(pcie, val, off, 0x4);
}
static bool mobiveil_pcie_link_up(struct mobiveil_pcie *pcie)
@@ -174,7 +289,7 @@ static bool mobiveil_pcie_valid_device(struct pci_bus *bus, unsigned int devfn)
* Do not read more than one device on the bus directly
* attached to RC
*/
- if ((bus->primary == pcie->root_bus_nr) && (devfn > 0))
+ if ((bus->primary == pcie->root_bus_nr) && (PCI_SLOT(devfn) > 0))
return false;
return true;
@@ -185,17 +300,17 @@ static bool mobiveil_pcie_valid_device(struct pci_bus *bus, unsigned int devfn)
* root port or endpoint
*/
static void __iomem *mobiveil_pcie_map_bus(struct pci_bus *bus,
- unsigned int devfn, int where)
+ unsigned int devfn, int where)
{
struct mobiveil_pcie *pcie = bus->sysdata;
+ u32 value;
if (!mobiveil_pcie_valid_device(bus, devfn))
return NULL;
- if (bus->number == pcie->root_bus_nr) {
- /* RC config access */
+ /* RC config access */
+ if (bus->number == pcie->root_bus_nr)
return pcie->csr_axi_slave_base + where;
- }
/*
* EP config access (in Config/APIO space)
@@ -203,10 +318,12 @@ static void __iomem *mobiveil_pcie_map_bus(struct pci_bus *bus,
* (BDF) in PAB_AXI_AMAP_PEX_WIN_L0 Register.
* Relies on pci_lock serialization
*/
- csr_writel(pcie, bus->number << PAB_BUS_SHIFT |
- PCI_SLOT(devfn) << PAB_DEVICE_SHIFT |
- PCI_FUNC(devfn) << PAB_FUNCTION_SHIFT,
- PAB_AXI_AMAP_PEX_WIN_L(WIN_NUM_0));
+ value = bus->number << PAB_BUS_SHIFT |
+ PCI_SLOT(devfn) << PAB_DEVICE_SHIFT |
+ PCI_FUNC(devfn) << PAB_FUNCTION_SHIFT;
+
+ csr_writel(pcie, value, PAB_AXI_AMAP_PEX_WIN_L(WIN_NUM_0));
+
return pcie->config_axi_slave_base + where;
}
@@ -241,24 +358,29 @@ static void mobiveil_pcie_isr(struct irq_desc *desc)
/* Handle INTx */
if (intr_status & PAB_INTP_INTX_MASK) {
- shifted_status = csr_readl(pcie, PAB_INTP_AMBA_MISC_STAT) >>
- PAB_INTX_START;
+ shifted_status = csr_readl(pcie, PAB_INTP_AMBA_MISC_STAT);
+ shifted_status &= PAB_INTP_INTX_MASK;
+ shifted_status >>= PAB_INTX_START;
do {
for_each_set_bit(bit, &shifted_status, PCI_NUM_INTX) {
virq = irq_find_mapping(pcie->intx_domain,
- bit + 1);
+ bit + 1);
if (virq)
generic_handle_irq(virq);
else
- dev_err_ratelimited(dev,
- "unexpected IRQ, INT%d\n", bit);
+ dev_err_ratelimited(dev, "unexpected IRQ, INT%d\n",
+ bit);
- /* clear interrupt */
- csr_writel(pcie,
- shifted_status << PAB_INTX_START,
- PAB_INTP_AMBA_MISC_STAT);
+ /* clear interrupt handled */
+ csr_writel(pcie, 1 << (PAB_INTX_START + bit),
+ PAB_INTP_AMBA_MISC_STAT);
}
- } while ((shifted_status >> PAB_INTX_START) != 0);
+
+ shifted_status = csr_readl(pcie,
+ PAB_INTP_AMBA_MISC_STAT);
+ shifted_status &= PAB_INTP_INTX_MASK;
+ shifted_status >>= PAB_INTX_START;
+ } while (shifted_status != 0);
}
/* read extra MSI status register */
@@ -266,8 +388,7 @@ static void mobiveil_pcie_isr(struct irq_desc *desc)
/* handle MSI interrupts */
while (msi_status & 1) {
- msi_data = readl_relaxed(pcie->apb_csr_base
- + MSI_DATA_OFFSET);
+ msi_data = readl_relaxed(pcie->apb_csr_base + MSI_DATA_OFFSET);
/*
* MSI_STATUS_OFFSET register gets updated to zero
@@ -276,18 +397,18 @@ static void mobiveil_pcie_isr(struct irq_desc *desc)
* two dummy reads.
*/
msi_addr_lo = readl_relaxed(pcie->apb_csr_base +
- MSI_ADDR_L_OFFSET);
+ MSI_ADDR_L_OFFSET);
msi_addr_hi = readl_relaxed(pcie->apb_csr_base +
- MSI_ADDR_H_OFFSET);
+ MSI_ADDR_H_OFFSET);
dev_dbg(dev, "MSI registers, data: %08x, addr: %08x:%08x\n",
- msi_data, msi_addr_hi, msi_addr_lo);
+ msi_data, msi_addr_hi, msi_addr_lo);
virq = irq_find_mapping(msi->dev_domain, msi_data);
if (virq)
generic_handle_irq(virq);
msi_status = readl_relaxed(pcie->apb_csr_base +
- MSI_STATUS_OFFSET);
+ MSI_STATUS_OFFSET);
}
/* Clear the interrupt status */
@@ -304,7 +425,7 @@ static int mobiveil_pcie_parse_dt(struct mobiveil_pcie *pcie)
/* map config resource */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- "config_axi_slave");
+ "config_axi_slave");
pcie->config_axi_slave_base = devm_pci_remap_cfg_resource(dev, res);
if (IS_ERR(pcie->config_axi_slave_base))
return PTR_ERR(pcie->config_axi_slave_base);
@@ -312,7 +433,7 @@ static int mobiveil_pcie_parse_dt(struct mobiveil_pcie *pcie)
/* map csr resource */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- "csr_axi_slave");
+ "csr_axi_slave");
pcie->csr_axi_slave_base = devm_pci_remap_cfg_resource(dev, res);
if (IS_ERR(pcie->csr_axi_slave_base))
return PTR_ERR(pcie->csr_axi_slave_base);
@@ -337,92 +458,50 @@ static int mobiveil_pcie_parse_dt(struct mobiveil_pcie *pcie)
return -ENODEV;
}
- irq_set_chained_handler_and_data(pcie->irq, mobiveil_pcie_isr, pcie);
-
return 0;
}
-/*
- * select_paged_register - routine to access paged register of root complex
- *
- * registers of RC are paged, for this scheme to work
- * extracted higher 6 bits of the offset will be written to pg_sel
- * field of PAB_CTRL register and rest of the lower 10 bits enabled with
- * PAGE_SEL_EN are used as offset of the register.
- */
-static void select_paged_register(struct mobiveil_pcie *pcie, u32 offset)
-{
- int pab_ctrl_dw, pg_sel;
-
- /* clear pg_sel field */
- pab_ctrl_dw = csr_readl(pcie, PAB_CTRL);
- pab_ctrl_dw = (pab_ctrl_dw & ~(PAGE_SEL_MASK << PAGE_SEL_SHIFT));
-
- /* set pg_sel field */
- pg_sel = (offset >> PAGE_SEL_OFFSET_SHIFT) & PAGE_SEL_MASK;
- pab_ctrl_dw |= ((pg_sel << PAGE_SEL_SHIFT));
- csr_writel(pcie, pab_ctrl_dw, PAB_CTRL);
-}
-
-static void write_paged_register(struct mobiveil_pcie *pcie,
- u32 val, u32 offset)
-{
- u32 off = (offset & PAGE_LO_MASK) | PAGE_SEL_EN;
-
- select_paged_register(pcie, offset);
- csr_writel(pcie, val, off);
-}
-
-static u32 read_paged_register(struct mobiveil_pcie *pcie, u32 offset)
-{
- u32 off = (offset & PAGE_LO_MASK) | PAGE_SEL_EN;
-
- select_paged_register(pcie, offset);
- return csr_readl(pcie, off);
-}
-
static void program_ib_windows(struct mobiveil_pcie *pcie, int win_num,
- int pci_addr, u32 type, u64 size)
+ u64 pci_addr, u32 type, u64 size)
{
- int pio_ctrl_val;
- int amap_ctrl_dw;
+ u32 value;
u64 size64 = ~(size - 1);
- if ((pcie->ib_wins_configured + 1) > pcie->ppio_wins) {
+ if (win_num >= pcie->ppio_wins) {
dev_err(&pcie->pdev->dev,
"ERROR: max inbound windows reached !\n");
return;
}
- pio_ctrl_val = csr_readl(pcie, PAB_PEX_PIO_CTRL);
- csr_writel(pcie,
- pio_ctrl_val | (1 << PIO_ENABLE_SHIFT), PAB_PEX_PIO_CTRL);
- amap_ctrl_dw = read_paged_register(pcie, PAB_PEX_AMAP_CTRL(win_num));
- amap_ctrl_dw = (amap_ctrl_dw | (type << AMAP_CTRL_TYPE_SHIFT));
- amap_ctrl_dw = (amap_ctrl_dw | (1 << AMAP_CTRL_EN_SHIFT));
+ value = csr_readl(pcie, PAB_PEX_AMAP_CTRL(win_num));
+ value &= ~(AMAP_CTRL_TYPE_MASK << AMAP_CTRL_TYPE_SHIFT | WIN_SIZE_MASK);
+ value |= type << AMAP_CTRL_TYPE_SHIFT | 1 << AMAP_CTRL_EN_SHIFT |
+ (lower_32_bits(size64) & WIN_SIZE_MASK);
+ csr_writel(pcie, value, PAB_PEX_AMAP_CTRL(win_num));
+
+ csr_writel(pcie, upper_32_bits(size64),
+ PAB_EXT_PEX_AMAP_SIZEN(win_num));
- write_paged_register(pcie, amap_ctrl_dw | lower_32_bits(size64),
- PAB_PEX_AMAP_CTRL(win_num));
+ csr_writel(pcie, pci_addr, PAB_PEX_AMAP_AXI_WIN(win_num));
- write_paged_register(pcie, upper_32_bits(size64),
- PAB_EXT_PEX_AMAP_SIZEN(win_num));
+ csr_writel(pcie, lower_32_bits(pci_addr),
+ PAB_PEX_AMAP_PEX_WIN_L(win_num));
+ csr_writel(pcie, upper_32_bits(pci_addr),
+ PAB_PEX_AMAP_PEX_WIN_H(win_num));
- write_paged_register(pcie, pci_addr, PAB_PEX_AMAP_AXI_WIN(win_num));
- write_paged_register(pcie, pci_addr, PAB_PEX_AMAP_PEX_WIN_L(win_num));
- write_paged_register(pcie, 0, PAB_PEX_AMAP_PEX_WIN_H(win_num));
+ pcie->ib_wins_configured++;
}
/*
* routine to program the outbound windows
*/
static void program_ob_windows(struct mobiveil_pcie *pcie, int win_num,
- u64 cpu_addr, u64 pci_addr, u32 config_io_bit, u64 size)
+ u64 cpu_addr, u64 pci_addr, u32 type, u64 size)
{
-
- u32 value, type;
+ u32 value;
u64 size64 = ~(size - 1);
- if ((pcie->ob_wins_configured + 1) > pcie->apio_wins) {
+ if (win_num >= pcie->apio_wins) {
dev_err(&pcie->pdev->dev,
"ERROR: max outbound windows reached !\n");
return;
@@ -432,28 +511,27 @@ static void program_ob_windows(struct mobiveil_pcie *pcie, int win_num,
* program Enable Bit to 1, Type Bit to (00) base 2, AXI Window Size Bit
* to 4 KB in PAB_AXI_AMAP_CTRL register
*/
- type = config_io_bit;
value = csr_readl(pcie, PAB_AXI_AMAP_CTRL(win_num));
- csr_writel(pcie, 1 << WIN_ENABLE_SHIFT | type << WIN_TYPE_SHIFT |
- lower_32_bits(size64), PAB_AXI_AMAP_CTRL(win_num));
+ value &= ~(WIN_TYPE_MASK << WIN_TYPE_SHIFT | WIN_SIZE_MASK);
+ value |= 1 << WIN_ENABLE_SHIFT | type << WIN_TYPE_SHIFT |
+ (lower_32_bits(size64) & WIN_SIZE_MASK);
+ csr_writel(pcie, value, PAB_AXI_AMAP_CTRL(win_num));
- write_paged_register(pcie, upper_32_bits(size64),
- PAB_EXT_AXI_AMAP_SIZE(win_num));
+ csr_writel(pcie, upper_32_bits(size64), PAB_EXT_AXI_AMAP_SIZE(win_num));
/*
* program AXI window base with appropriate value in
* PAB_AXI_AMAP_AXI_WIN0 register
*/
- value = csr_readl(pcie, PAB_AXI_AMAP_AXI_WIN(win_num));
- csr_writel(pcie, cpu_addr & (~AXI_WINDOW_ALIGN_MASK),
- PAB_AXI_AMAP_AXI_WIN(win_num));
-
- value = csr_readl(pcie, PAB_AXI_AMAP_PEX_WIN_H(win_num));
+ csr_writel(pcie, lower_32_bits(cpu_addr) & (~AXI_WINDOW_ALIGN_MASK),
+ PAB_AXI_AMAP_AXI_WIN(win_num));
+ csr_writel(pcie, upper_32_bits(cpu_addr),
+ PAB_EXT_AXI_AMAP_AXI_WIN(win_num));
csr_writel(pcie, lower_32_bits(pci_addr),
- PAB_AXI_AMAP_PEX_WIN_L(win_num));
+ PAB_AXI_AMAP_PEX_WIN_L(win_num));
csr_writel(pcie, upper_32_bits(pci_addr),
- PAB_AXI_AMAP_PEX_WIN_H(win_num));
+ PAB_AXI_AMAP_PEX_WIN_H(win_num));
pcie->ob_wins_configured++;
}
@@ -469,7 +547,9 @@ static int mobiveil_bringup_link(struct mobiveil_pcie *pcie)
usleep_range(LINK_WAIT_MIN, LINK_WAIT_MAX);
}
+
dev_err(&pcie->pdev->dev, "link never came up\n");
+
return -ETIMEDOUT;
}
@@ -482,50 +562,55 @@ static void mobiveil_pcie_enable_msi(struct mobiveil_pcie *pcie)
msi->msi_pages_phys = (phys_addr_t)msg_addr;
writel_relaxed(lower_32_bits(msg_addr),
- pcie->apb_csr_base + MSI_BASE_LO_OFFSET);
+ pcie->apb_csr_base + MSI_BASE_LO_OFFSET);
writel_relaxed(upper_32_bits(msg_addr),
- pcie->apb_csr_base + MSI_BASE_HI_OFFSET);
+ pcie->apb_csr_base + MSI_BASE_HI_OFFSET);
writel_relaxed(4096, pcie->apb_csr_base + MSI_SIZE_OFFSET);
writel_relaxed(1, pcie->apb_csr_base + MSI_ENABLE_OFFSET);
}
static int mobiveil_host_init(struct mobiveil_pcie *pcie)
{
- u32 value, pab_ctrl, type = 0;
- int err;
- struct resource_entry *win, *tmp;
-
- err = mobiveil_bringup_link(pcie);
- if (err) {
- dev_info(&pcie->pdev->dev, "link bring-up failed\n");
- return err;
- }
+ u32 value, pab_ctrl, type;
+ struct resource_entry *win;
+
+ /* setup bus numbers */
+ value = csr_readl(pcie, PCI_PRIMARY_BUS);
+ value &= 0xff000000;
+ value |= 0x00ff0100;
+ csr_writel(pcie, value, PCI_PRIMARY_BUS);
/*
* program Bus Master Enable Bit in Command Register in PAB Config
* Space
*/
value = csr_readl(pcie, PCI_COMMAND);
- csr_writel(pcie, value | PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
- PCI_COMMAND_MASTER, PCI_COMMAND);
+ value |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+ csr_writel(pcie, value, PCI_COMMAND);
/*
* program PIO Enable Bit to 1 (and PEX PIO Enable to 1) in PAB_CTRL
* register
*/
pab_ctrl = csr_readl(pcie, PAB_CTRL);
- csr_writel(pcie, pab_ctrl | (1 << AMBA_PIO_ENABLE_SHIFT) |
- (1 << PEX_PIO_ENABLE_SHIFT), PAB_CTRL);
+ pab_ctrl |= (1 << AMBA_PIO_ENABLE_SHIFT) | (1 << PEX_PIO_ENABLE_SHIFT);
+ csr_writel(pcie, pab_ctrl, PAB_CTRL);
csr_writel(pcie, (PAB_INTP_INTX_MASK | PAB_INTP_MSI_MASK),
- PAB_INTP_AMBA_MISC_ENB);
+ PAB_INTP_AMBA_MISC_ENB);
/*
* program PIO Enable Bit to 1 and Config Window Enable Bit to 1 in
* PAB_AXI_PIO_CTRL Register
*/
value = csr_readl(pcie, PAB_AXI_PIO_CTRL);
- csr_writel(pcie, value | APIO_EN_MASK, PAB_AXI_PIO_CTRL);
+ value |= APIO_EN_MASK;
+ csr_writel(pcie, value, PAB_AXI_PIO_CTRL);
+
+ /* Enable PCIe PIO master */
+ value = csr_readl(pcie, PAB_PEX_PIO_CTRL);
+ value |= 1 << PIO_ENABLE_SHIFT;
+ csr_writel(pcie, value, PAB_PEX_PIO_CTRL);
/*
* we'll program one outbound window for config reads and
@@ -535,32 +620,38 @@ static int mobiveil_host_init(struct mobiveil_pcie *pcie)
*/
/* config outbound translation window */
- program_ob_windows(pcie, pcie->ob_wins_configured,
- pcie->ob_io_res->start, 0, CFG_WINDOW_TYPE,
- resource_size(pcie->ob_io_res));
+ program_ob_windows(pcie, WIN_NUM_0, pcie->ob_io_res->start, 0,
+ CFG_WINDOW_TYPE, resource_size(pcie->ob_io_res));
/* memory inbound translation window */
- program_ib_windows(pcie, WIN_NUM_1, 0, MEM_WINDOW_TYPE, IB_WIN_SIZE);
+ program_ib_windows(pcie, WIN_NUM_0, 0, MEM_WINDOW_TYPE, IB_WIN_SIZE);
/* Get the I/O and memory ranges from DT */
- resource_list_for_each_entry_safe(win, tmp, &pcie->resources) {
- type = 0;
+ resource_list_for_each_entry(win, &pcie->resources) {
if (resource_type(win->res) == IORESOURCE_MEM)
type = MEM_WINDOW_TYPE;
- if (resource_type(win->res) == IORESOURCE_IO)
+ else if (resource_type(win->res) == IORESOURCE_IO)
type = IO_WINDOW_TYPE;
- if (type) {
- /* configure outbound translation window */
- program_ob_windows(pcie, pcie->ob_wins_configured,
- win->res->start, 0, type,
- resource_size(win->res));
- }
+ else
+ continue;
+
+ /* configure outbound translation window */
+ program_ob_windows(pcie, pcie->ob_wins_configured,
+ win->res->start,
+ win->res->start - win->offset,
+ type, resource_size(win->res));
}
+ /* fixup for PCIe class register */
+ value = csr_readl(pcie, PAB_INTP_AXI_PIO_CLASS);
+ value &= 0xff;
+ value |= (PCI_CLASS_BRIDGE_PCI << 16);
+ csr_writel(pcie, value, PAB_INTP_AXI_PIO_CLASS);
+
/* setup MSI hardware registers */
mobiveil_pcie_enable_msi(pcie);
- return err;
+ return 0;
}
static void mobiveil_mask_intx_irq(struct irq_data *data)
@@ -574,7 +665,8 @@ static void mobiveil_mask_intx_irq(struct irq_data *data)
mask = 1 << ((data->hwirq + PAB_INTX_START) - 1);
raw_spin_lock_irqsave(&pcie->intx_mask_lock, flags);
shifted_val = csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
- csr_writel(pcie, (shifted_val & (~mask)), PAB_INTP_AMBA_MISC_ENB);
+ shifted_val &= ~mask;
+ csr_writel(pcie, shifted_val, PAB_INTP_AMBA_MISC_ENB);
raw_spin_unlock_irqrestore(&pcie->intx_mask_lock, flags);
}
@@ -589,7 +681,8 @@ static void mobiveil_unmask_intx_irq(struct irq_data *data)
mask = 1 << ((data->hwirq + PAB_INTX_START) - 1);
raw_spin_lock_irqsave(&pcie->intx_mask_lock, flags);
shifted_val = csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
- csr_writel(pcie, (shifted_val | mask), PAB_INTP_AMBA_MISC_ENB);
+ shifted_val |= mask;
+ csr_writel(pcie, shifted_val, PAB_INTP_AMBA_MISC_ENB);
raw_spin_unlock_irqrestore(&pcie->intx_mask_lock, flags);
}
@@ -603,10 +696,11 @@ static struct irq_chip intx_irq_chip = {
/* routine to setup the INTx related data */
static int mobiveil_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
- irq_hw_number_t hwirq)
+ irq_hw_number_t hwirq)
{
irq_set_chip_and_handler(irq, &intx_irq_chip, handle_level_irq);
irq_set_chip_data(irq, domain->host_data);
+
return 0;
}
@@ -623,7 +717,7 @@ static struct irq_chip mobiveil_msi_irq_chip = {
static struct msi_domain_info mobiveil_msi_domain_info = {
.flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
- MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX),
+ MSI_FLAG_PCI_MSIX),
.chip = &mobiveil_msi_irq_chip,
};
@@ -641,7 +735,7 @@ static void mobiveil_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
}
static int mobiveil_msi_set_affinity(struct irq_data *irq_data,
- const struct cpumask *mask, bool force)
+ const struct cpumask *mask, bool force)
{
return -EINVAL;
}
@@ -653,7 +747,8 @@ static struct irq_chip mobiveil_msi_bottom_irq_chip = {
};
static int mobiveil_irq_msi_domain_alloc(struct irq_domain *domain,
- unsigned int virq, unsigned int nr_irqs, void *args)
+ unsigned int virq,
+ unsigned int nr_irqs, void *args)
{
struct mobiveil_pcie *pcie = domain->host_data;
struct mobiveil_msi *msi = &pcie->msi;
@@ -673,13 +768,13 @@ static int mobiveil_irq_msi_domain_alloc(struct irq_domain *domain,
mutex_unlock(&msi->lock);
irq_domain_set_info(domain, virq, bit, &mobiveil_msi_bottom_irq_chip,
- domain->host_data, handle_level_irq,
- NULL, NULL);
+ domain->host_data, handle_level_irq, NULL, NULL);
return 0;
}
static void mobiveil_irq_msi_domain_free(struct irq_domain *domain,
- unsigned int virq, unsigned int nr_irqs)
+ unsigned int virq,
+ unsigned int nr_irqs)
{
struct irq_data *d = irq_domain_get_irq_data(domain, virq);
struct mobiveil_pcie *pcie = irq_data_get_irq_chip_data(d);
@@ -687,12 +782,11 @@ static void mobiveil_irq_msi_domain_free(struct irq_domain *domain,
mutex_lock(&msi->lock);
- if (!test_bit(d->hwirq, msi->msi_irq_in_use)) {
+ if (!test_bit(d->hwirq, msi->msi_irq_in_use))
dev_err(&pcie->pdev->dev, "trying to free unused MSI#%lu\n",
d->hwirq);
- } else {
+ else
__clear_bit(d->hwirq, msi->msi_irq_in_use);
- }
mutex_unlock(&msi->lock);
}
@@ -716,12 +810,14 @@ static int mobiveil_allocate_msi_domains(struct mobiveil_pcie *pcie)
}
msi->msi_domain = pci_msi_create_irq_domain(fwnode,
- &mobiveil_msi_domain_info, msi->dev_domain);
+ &mobiveil_msi_domain_info,
+ msi->dev_domain);
if (!msi->msi_domain) {
dev_err(dev, "failed to create MSI domain\n");
irq_domain_remove(msi->dev_domain);
return -ENOMEM;
}
+
return 0;
}
@@ -732,12 +828,12 @@ static int mobiveil_pcie_init_irq_domain(struct mobiveil_pcie *pcie)
int ret;
/* setup INTx */
- pcie->intx_domain = irq_domain_add_linear(node,
- PCI_NUM_INTX, &intx_domain_ops, pcie);
+ pcie->intx_domain = irq_domain_add_linear(node, PCI_NUM_INTX,
+ &intx_domain_ops, pcie);
if (!pcie->intx_domain) {
dev_err(dev, "Failed to get a INTx IRQ domain\n");
- return -ENODEV;
+ return -ENOMEM;
}
raw_spin_lock_init(&pcie->intx_mask_lock);
@@ -763,11 +859,9 @@ static int mobiveil_pcie_probe(struct platform_device *pdev)
/* allocate the PCIe port */
bridge = devm_pci_alloc_host_bridge(dev, sizeof(*pcie));
if (!bridge)
- return -ENODEV;
+ return -ENOMEM;
pcie = pci_host_bridge_priv(bridge);
- if (!pcie)
- return -ENOMEM;
pcie->pdev = pdev;
@@ -784,7 +878,7 @@ static int mobiveil_pcie_probe(struct platform_device *pdev)
&pcie->resources, &iobase);
if (ret) {
dev_err(dev, "Getting bridge resources failed\n");
- return -ENOMEM;
+ return ret;
}
/*
@@ -797,9 +891,6 @@ static int mobiveil_pcie_probe(struct platform_device *pdev)
goto error;
}
- /* fixup for PCIe class register */
- csr_writel(pcie, 0x060402ab, PAB_INTP_AXI_PIO_CLASS);
-
/* initialize the IRQ domains */
ret = mobiveil_pcie_init_irq_domain(pcie);
if (ret) {
@@ -807,6 +898,8 @@ static int mobiveil_pcie_probe(struct platform_device *pdev)
goto error;
}
+ irq_set_chained_handler_and_data(pcie->irq, mobiveil_pcie_isr, pcie);
+
ret = devm_request_pci_bus_resources(dev, &pcie->resources);
if (ret)
goto error;
@@ -820,6 +913,12 @@ static int mobiveil_pcie_probe(struct platform_device *pdev)
bridge->map_irq = of_irq_parse_and_map_pci;
bridge->swizzle_irq = pci_common_swizzle;
+ ret = mobiveil_bringup_link(pcie);
+ if (ret) {
+ dev_info(dev, "link bring-up failed\n");
+ goto error;
+ }
+
/* setup the kernel resources for the newly added PCIe root bus */
ret = pci_scan_root_bus_bridge(bridge);
if (ret)
@@ -848,10 +947,10 @@ MODULE_DEVICE_TABLE(of, mobiveil_pcie_of_match);
static struct platform_driver mobiveil_pcie_driver = {
.probe = mobiveil_pcie_probe,
.driver = {
- .name = "mobiveil-pcie",
- .of_match_table = mobiveil_pcie_of_match,
- .suppress_bind_attrs = true,
- },
+ .name = "mobiveil-pcie",
+ .of_match_table = mobiveil_pcie_of_match,
+ .suppress_bind_attrs = true,
+ },
};
builtin_platform_driver(mobiveil_pcie_driver);
diff --git a/drivers/pci/controller/pcie-xilinx-nwl.c b/drivers/pci/controller/pcie-xilinx-nwl.c
index 3b031f00a94a..45c0f344ccd1 100644
--- a/drivers/pci/controller/pcie-xilinx-nwl.c
+++ b/drivers/pci/controller/pcie-xilinx-nwl.c
@@ -482,15 +482,13 @@ static int nwl_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
int i;
mutex_lock(&msi->lock);
- bit = bitmap_find_next_zero_area(msi->bitmap, INT_PCI_MSI_NR, 0,
- nr_irqs, 0);
- if (bit >= INT_PCI_MSI_NR) {
+ bit = bitmap_find_free_region(msi->bitmap, INT_PCI_MSI_NR,
+ get_count_order(nr_irqs));
+ if (bit < 0) {
mutex_unlock(&msi->lock);
return -ENOSPC;
}
- bitmap_set(msi->bitmap, bit, nr_irqs);
-
for (i = 0; i < nr_irqs; i++) {
irq_domain_set_info(domain, virq + i, bit + i, &nwl_irq_chip,
domain->host_data, handle_simple_irq,
@@ -508,7 +506,8 @@ static void nwl_irq_domain_free(struct irq_domain *domain, unsigned int virq,
struct nwl_msi *msi = &pcie->msi;
mutex_lock(&msi->lock);
- bitmap_clear(msi->bitmap, data->hwirq, nr_irqs);
+ bitmap_release_region(msi->bitmap, data->hwirq,
+ get_count_order(nr_irqs));
mutex_unlock(&msi->lock);
}
diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c
index 999a5509e57e..4575e0c6dc4b 100644
--- a/drivers/pci/controller/vmd.c
+++ b/drivers/pci/controller/vmd.c
@@ -627,7 +627,7 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
* 32-bit resources. __pci_assign_resource() enforces that
* artificial restriction to make sure everything will fit.
*
- * The only way we could use a 64-bit non-prefechable MEMBAR is
+ * The only way we could use a 64-bit non-prefetchable MEMBAR is
* if its address is <4GB so that we can convert it to a 32-bit
* resource. To be visible to the host OS, all VMD endpoints must
* be initially configured by platform BIOS, which includes setting
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index 27806987e93b..1cfe3687a211 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -381,15 +381,15 @@ static void pci_epf_test_unbind(struct pci_epf *epf)
epf_bar = &epf->bar[bar];
if (epf_test->reg[bar]) {
- pci_epf_free_space(epf, epf_test->reg[bar], bar);
pci_epc_clear_bar(epc, epf->func_no, epf_bar);
+ pci_epf_free_space(epf, epf_test->reg[bar], bar);
}
}
}
static int pci_epf_test_set_bar(struct pci_epf *epf)
{
- int bar;
+ int bar, add;
int ret;
struct pci_epf_bar *epf_bar;
struct pci_epc *epc = epf->epc;
@@ -400,8 +400,14 @@ static int pci_epf_test_set_bar(struct pci_epf *epf)
epc_features = epf_test->epc_features;
- for (bar = BAR_0; bar <= BAR_5; bar++) {
+ for (bar = BAR_0; bar <= BAR_5; bar += add) {
epf_bar = &epf->bar[bar];
+ /*
+ * pci_epc_set_bar() sets PCI_BASE_ADDRESS_MEM_TYPE_64
+ * if the specific implementation required a 64-bit BAR,
+ * even if we only requested a 32-bit BAR.
+ */
+ add = (epf_bar->flags & PCI_BASE_ADDRESS_MEM_TYPE_64) ? 2 : 1;
if (!!(epc_features->reserved_bar & (1 << bar)))
continue;
@@ -413,13 +419,6 @@ static int pci_epf_test_set_bar(struct pci_epf *epf)
if (bar == test_reg_bar)
return ret;
}
- /*
- * pci_epc_set_bar() sets PCI_BASE_ADDRESS_MEM_TYPE_64
- * if the specific implementation required a 64-bit BAR,
- * even if we only requested a 32-bit BAR.
- */
- if (epf_bar->flags & PCI_BASE_ADDRESS_MEM_TYPE_64)
- bar++;
}
return 0;
@@ -431,13 +430,19 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf)
struct device *dev = &epf->dev;
struct pci_epf_bar *epf_bar;
void *base;
- int bar;
+ int bar, add;
enum pci_barno test_reg_bar = epf_test->test_reg_bar;
const struct pci_epc_features *epc_features;
+ size_t test_reg_size;
epc_features = epf_test->epc_features;
- base = pci_epf_alloc_space(epf, sizeof(struct pci_epf_test_reg),
+ if (epc_features->bar_fixed_size[test_reg_bar])
+ test_reg_size = bar_size[test_reg_bar];
+ else
+ test_reg_size = sizeof(struct pci_epf_test_reg);
+
+ base = pci_epf_alloc_space(epf, test_reg_size,
test_reg_bar, epc_features->align);
if (!base) {
dev_err(dev, "Failed to allocated register space\n");
@@ -445,8 +450,10 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf)
}
epf_test->reg[test_reg_bar] = base;
- for (bar = BAR_0; bar <= BAR_5; bar++) {
+ for (bar = BAR_0; bar <= BAR_5; bar += add) {
epf_bar = &epf->bar[bar];
+ add = (epf_bar->flags & PCI_BASE_ADDRESS_MEM_TYPE_64) ? 2 : 1;
+
if (bar == test_reg_bar)
continue;
@@ -459,8 +466,6 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf)
dev_err(dev, "Failed to allocate space for BAR%d\n",
bar);
epf_test->reg[bar] = base;
- if (epf_bar->flags & PCI_BASE_ADDRESS_MEM_TYPE_64)
- bar++;
}
return 0;
diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
index e4712a0f249c..2091508c1620 100644
--- a/drivers/pci/endpoint/pci-epc-core.c
+++ b/drivers/pci/endpoint/pci-epc-core.c
@@ -519,11 +519,12 @@ void pci_epc_remove_epf(struct pci_epc *epc, struct pci_epf *epf)
{
unsigned long flags;
- if (!epc || IS_ERR(epc))
+ if (!epc || IS_ERR(epc) || !epf)
return;
spin_lock_irqsave(&epc->lock, flags);
list_del(&epf->list);
+ epf->epc = NULL;
spin_unlock_irqrestore(&epc->lock, flags);
}
EXPORT_SYMBOL_GPL(pci_epc_remove_epf);
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index 3aa115ed3a65..525fd3f272b3 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -132,8 +132,6 @@ static void pci_read_vf_config_common(struct pci_dev *virtfn)
&physfn->sriov->subsystem_vendor);
pci_read_config_word(virtfn, PCI_SUBSYSTEM_ID,
&physfn->sriov->subsystem_device);
-
- physfn->sriov->cfg_size = pci_cfg_space_size(virtfn);
}
int pci_iov_add_virtfn(struct pci_dev *dev, int id)
diff --git a/drivers/pci/mmap.c b/drivers/pci/mmap.c
index 24505b08de40..b8c9011987f4 100644
--- a/drivers/pci/mmap.c
+++ b/drivers/pci/mmap.c
@@ -73,7 +73,7 @@ int pci_mmap_resource_range(struct pci_dev *pdev, int bar,
#elif defined(HAVE_PCI_MMAP) /* && !ARCH_GENERIC_PCI_MMAP_RESOURCE */
/*
- * Legacy setup: Impement pci_mmap_resource_range() as a wrapper around
+ * Legacy setup: Implement pci_mmap_resource_range() as a wrapper around
* the architecture's pci_mmap_page_range(), converting to "user visible"
* addresses as necessary.
*/
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index e039b740fe74..59a6d232f77a 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -237,7 +237,7 @@ static void msi_set_mask_bit(struct irq_data *data, u32 flag)
}
/**
- * pci_msi_mask_irq - Generic irq chip callback to mask PCI/MSI interrupts
+ * pci_msi_mask_irq - Generic IRQ chip callback to mask PCI/MSI interrupts
* @data: pointer to irqdata associated to that interrupt
*/
void pci_msi_mask_irq(struct irq_data *data)
@@ -247,7 +247,7 @@ void pci_msi_mask_irq(struct irq_data *data)
EXPORT_SYMBOL_GPL(pci_msi_mask_irq);
/**
- * pci_msi_unmask_irq - Generic irq chip callback to unmask PCI/MSI interrupts
+ * pci_msi_unmask_irq - Generic IRQ chip callback to unmask PCI/MSI interrupts
* @data: pointer to irqdata associated to that interrupt
*/
void pci_msi_unmask_irq(struct irq_data *data)
@@ -588,11 +588,11 @@ static int msi_verify_entries(struct pci_dev *dev)
* msi_capability_init - configure device's MSI capability structure
* @dev: pointer to the pci_dev data structure of MSI device function
* @nvec: number of interrupts to allocate
- * @affd: description of automatic irq affinity assignments (may be %NULL)
+ * @affd: description of automatic IRQ affinity assignments (may be %NULL)
*
* Setup the MSI capability structure of the device with the requested
* number of interrupts. A return value of zero indicates the successful
- * setup of an entry with the new MSI irq. A negative return value indicates
+ * setup of an entry with the new MSI IRQ. A negative return value indicates
* an error, and a positive return value indicates the number of interrupts
* which could have been allocated.
*/
@@ -609,7 +609,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec,
if (!entry)
return -ENOMEM;
- /* All MSIs are unmasked by default, Mask them all */
+ /* All MSIs are unmasked by default; mask them all */
mask = msi_mask(entry->msi_attrib.multi_cap);
msi_mask_irq(entry, mask, mask);
@@ -637,7 +637,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec,
return ret;
}
- /* Set MSI enabled bits */
+ /* Set MSI enabled bits */
pci_intx_for_msi(dev, 0);
pci_msi_set_enable(dev, 1);
dev->msi_enabled = 1;
@@ -729,11 +729,11 @@ static void msix_program_entries(struct pci_dev *dev,
* @dev: pointer to the pci_dev data structure of MSI-X device function
* @entries: pointer to an array of struct msix_entry entries
* @nvec: number of @entries
- * @affd: Optional pointer to enable automatic affinity assignement
+ * @affd: Optional pointer to enable automatic affinity assignment
*
* Setup the MSI-X capability structure of device function with a
- * single MSI-X irq. A return of zero indicates the successful setup of
- * requested MSI-X entries with allocated irqs or non-zero for otherwise.
+ * single MSI-X IRQ. A return of zero indicates the successful setup of
+ * requested MSI-X entries with allocated IRQs or non-zero for otherwise.
**/
static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries,
int nvec, struct irq_affinity *affd)
@@ -789,7 +789,7 @@ static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries,
out_avail:
if (ret < 0) {
/*
- * If we had some success, report the number of irqs
+ * If we had some success, report the number of IRQs
* we succeeded in setting up.
*/
struct msi_desc *entry;
@@ -812,7 +812,7 @@ out_free:
/**
* pci_msi_supported - check whether MSI may be enabled on a device
* @dev: pointer to the pci_dev data structure of MSI device function
- * @nvec: how many MSIs have been requested ?
+ * @nvec: how many MSIs have been requested?
*
* Look at global flags, the device itself, and its parent buses
* to determine if MSI/-X are supported for the device. If MSI/-X is
@@ -896,7 +896,7 @@ static void pci_msi_shutdown(struct pci_dev *dev)
/* Keep cached state to be restored */
__pci_msi_desc_mask_irq(desc, mask, ~mask);
- /* Restore dev->irq to its default pin-assertion irq */
+ /* Restore dev->irq to its default pin-assertion IRQ */
dev->irq = desc->msi_attrib.default_irq;
pcibios_alloc_irq(dev);
}
@@ -958,7 +958,7 @@ static int __pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries,
}
}
- /* Check whether driver already requested for MSI irq */
+ /* Check whether driver already requested for MSI IRQ */
if (dev->msi_enabled) {
pci_info(dev, "can't enable MSI-X (MSI IRQ already assigned)\n");
return -EINVAL;
@@ -1026,7 +1026,7 @@ static int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec,
if (!pci_msi_supported(dev, minvec))
return -EINVAL;
- /* Check whether driver already requested MSI-X irqs */
+ /* Check whether driver already requested MSI-X IRQs */
if (dev->msix_enabled) {
pci_info(dev, "can't enable MSI (MSI-X already enabled)\n");
return -EINVAL;
@@ -1113,8 +1113,8 @@ static int __pci_enable_msix_range(struct pci_dev *dev,
* pci_enable_msix_range - configure device's MSI-X capability structure
* @dev: pointer to the pci_dev data structure of MSI-X device function
* @entries: pointer to an array of MSI-X entries
- * @minvec: minimum number of MSI-X irqs requested
- * @maxvec: maximum number of MSI-X irqs requested
+ * @minvec: minimum number of MSI-X IRQs requested
+ * @maxvec: maximum number of MSI-X IRQs requested
*
* Setup the MSI-X capability structure of device function with a maximum
* possible number of interrupts in the range between @minvec and @maxvec
@@ -1179,7 +1179,7 @@ int pci_alloc_irq_vectors_affinity(struct pci_dev *dev, unsigned int min_vecs,
return msi_vecs;
}
- /* use legacy irq if allowed */
+ /* use legacy IRQ if allowed */
if (flags & PCI_IRQ_LEGACY) {
if (min_vecs == 1 && dev->irq) {
/*
@@ -1248,7 +1248,7 @@ int pci_irq_vector(struct pci_dev *dev, unsigned int nr)
EXPORT_SYMBOL(pci_irq_vector);
/**
- * pci_irq_get_affinity - return the affinity of a particular msi vector
+ * pci_irq_get_affinity - return the affinity of a particular MSI vector
* @dev: PCI device to operate on
* @nr: device-relative interrupt vector index (0-based).
*/
@@ -1280,7 +1280,7 @@ const struct cpumask *pci_irq_get_affinity(struct pci_dev *dev, int nr)
EXPORT_SYMBOL(pci_irq_get_affinity);
/**
- * pci_irq_get_node - return the numa node of a particular msi vector
+ * pci_irq_get_node - return the NUMA node of a particular MSI vector
* @pdev: PCI device to operate on
* @vec: device-relative interrupt vector index (0-based).
*/
@@ -1330,7 +1330,7 @@ void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg)
/**
* pci_msi_domain_calc_hwirq - Generate a unique ID for an MSI source
* @dev: Pointer to the PCI device
- * @desc: Pointer to the msi descriptor
+ * @desc: Pointer to the MSI descriptor
*
* The ID number is only used within the irqdomain.
*/
@@ -1348,7 +1348,8 @@ static inline bool pci_msi_desc_is_multi_msi(struct msi_desc *desc)
}
/**
- * pci_msi_domain_check_cap - Verify that @domain supports the capabilities for @dev
+ * pci_msi_domain_check_cap - Verify that @domain supports the capabilities
+ * for @dev
* @domain: The interrupt domain to check
* @info: The domain info for verification
* @dev: The device to check
diff --git a/drivers/pci/of.c b/drivers/pci/of.c
index 73d5adec0a28..bc7b27a28795 100644
--- a/drivers/pci/of.c
+++ b/drivers/pci/of.c
@@ -22,12 +22,15 @@ void pci_set_of_node(struct pci_dev *dev)
return;
dev->dev.of_node = of_pci_find_child_device(dev->bus->dev.of_node,
dev->devfn);
+ if (dev->dev.of_node)
+ dev->dev.fwnode = &dev->dev.of_node->fwnode;
}
void pci_release_of_node(struct pci_dev *dev)
{
of_node_put(dev->dev.of_node);
dev->dev.of_node = NULL;
+ dev->dev.fwnode = NULL;
}
void pci_set_bus_of_node(struct pci_bus *bus)
@@ -41,13 +44,18 @@ void pci_set_bus_of_node(struct pci_bus *bus)
if (node && of_property_read_bool(node, "external-facing"))
bus->self->untrusted = true;
}
+
bus->dev.of_node = node;
+
+ if (bus->dev.of_node)
+ bus->dev.fwnode = &bus->dev.of_node->fwnode;
}
void pci_release_bus_of_node(struct pci_bus *bus)
{
of_node_put(bus->dev.of_node);
bus->dev.of_node = NULL;
+ bus->dev.fwnode = NULL;
}
struct device_node * __weak pcibios_get_phb_of_node(struct pci_bus *bus)
diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c
index a98126ad9c3a..234476226529 100644
--- a/drivers/pci/p2pdma.c
+++ b/drivers/pci/p2pdma.c
@@ -18,18 +18,13 @@
#include <linux/percpu-refcount.h>
#include <linux/random.h>
#include <linux/seq_buf.h>
+#include <linux/iommu.h>
struct pci_p2pdma {
struct gen_pool *pool;
bool p2pmem_published;
};
-struct p2pdma_pagemap {
- struct dev_pagemap pgmap;
- struct percpu_ref ref;
- struct completion ref_done;
-};
-
static ssize_t size_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -78,31 +73,6 @@ static const struct attribute_group p2pmem_group = {
.name = "p2pmem",
};
-static struct p2pdma_pagemap *to_p2p_pgmap(struct percpu_ref *ref)
-{
- return container_of(ref, struct p2pdma_pagemap, ref);
-}
-
-static void pci_p2pdma_percpu_release(struct percpu_ref *ref)
-{
- struct p2pdma_pagemap *p2p_pgmap = to_p2p_pgmap(ref);
-
- complete(&p2p_pgmap->ref_done);
-}
-
-static void pci_p2pdma_percpu_kill(struct percpu_ref *ref)
-{
- percpu_ref_kill(ref);
-}
-
-static void pci_p2pdma_percpu_cleanup(struct percpu_ref *ref)
-{
- struct p2pdma_pagemap *p2p_pgmap = to_p2p_pgmap(ref);
-
- wait_for_completion(&p2p_pgmap->ref_done);
- percpu_ref_exit(&p2p_pgmap->ref);
-}
-
static void pci_p2pdma_release(void *data)
{
struct pci_dev *pdev = data;
@@ -165,7 +135,6 @@ out:
int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, size_t size,
u64 offset)
{
- struct p2pdma_pagemap *p2p_pgmap;
struct dev_pagemap *pgmap;
void *addr;
int error;
@@ -188,27 +157,15 @@ int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, size_t size,
return error;
}
- p2p_pgmap = devm_kzalloc(&pdev->dev, sizeof(*p2p_pgmap), GFP_KERNEL);
- if (!p2p_pgmap)
+ pgmap = devm_kzalloc(&pdev->dev, sizeof(*pgmap), GFP_KERNEL);
+ if (!pgmap)
return -ENOMEM;
-
- init_completion(&p2p_pgmap->ref_done);
- error = percpu_ref_init(&p2p_pgmap->ref,
- pci_p2pdma_percpu_release, 0, GFP_KERNEL);
- if (error)
- goto pgmap_free;
-
- pgmap = &p2p_pgmap->pgmap;
-
pgmap->res.start = pci_resource_start(pdev, bar) + offset;
pgmap->res.end = pgmap->res.start + size - 1;
pgmap->res.flags = pci_resource_flags(pdev, bar);
- pgmap->ref = &p2p_pgmap->ref;
pgmap->type = MEMORY_DEVICE_PCI_P2PDMA;
pgmap->pci_p2pdma_bus_offset = pci_bus_address(pdev, bar) -
pci_resource_start(pdev, bar);
- pgmap->kill = pci_p2pdma_percpu_kill;
- pgmap->cleanup = pci_p2pdma_percpu_cleanup;
addr = devm_memremap_pages(&pdev->dev, pgmap);
if (IS_ERR(addr)) {
@@ -219,7 +176,7 @@ int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, size_t size,
error = gen_pool_add_owner(pdev->p2pdma->pool, (unsigned long)addr,
pci_bus_address(pdev, bar) + offset,
resource_size(&pgmap->res), dev_to_node(&pdev->dev),
- &p2p_pgmap->ref);
+ pgmap->ref);
if (error)
goto pages_free;
@@ -231,14 +188,14 @@ int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, size_t size,
pages_free:
devm_memunmap_pages(&pdev->dev, pgmap);
pgmap_free:
- devm_kfree(&pdev->dev, p2p_pgmap);
+ devm_kfree(&pdev->dev, pgmap);
return error;
}
EXPORT_SYMBOL_GPL(pci_p2pdma_add_resource);
/*
* Note this function returns the parent PCI device with a
- * reference taken. It is the caller's responsibily to drop
+ * reference taken. It is the caller's responsibility to drop
* the reference.
*/
static struct pci_dev *find_parent_pci_dev(struct device *dev)
@@ -299,6 +256,9 @@ static bool root_complex_whitelist(struct pci_dev *dev)
struct pci_dev *root = pci_get_slot(host->bus, PCI_DEVFN(0, 0));
unsigned short vendor, device;
+ if (iommu_present(dev->dev.bus))
+ return false;
+
if (!root)
return false;
@@ -395,7 +355,7 @@ static int upstream_bridge_distance(struct pci_dev *provider,
/*
* Allow the connection if both devices are on a whitelisted root
- * complex, but add an arbitary large value to the distance.
+ * complex, but add an arbitrary large value to the distance.
*/
if (root_complex_whitelist(provider) &&
root_complex_whitelist(client))
@@ -454,7 +414,7 @@ static int upstream_bridge_distance_warn(struct pci_dev *provider,
}
/**
- * pci_p2pdma_distance_many - Determive the cumulative distance between
+ * pci_p2pdma_distance_many - Determine the cumulative distance between
* a p2pdma provider and the clients in use.
* @provider: p2pdma provider to check against the client list
* @clients: array of devices to check (NULL-terminated)
@@ -483,6 +443,14 @@ int pci_p2pdma_distance_many(struct pci_dev *provider, struct device **clients,
return -1;
for (i = 0; i < num_clients; i++) {
+ if (IS_ENABLED(CONFIG_DMA_VIRT_OPS) &&
+ clients[i]->dma_ops == &dma_virt_ops) {
+ if (verbose)
+ dev_warn(clients[i],
+ "cannot be used for peer-to-peer DMA because the driver makes use of dma_virt_ops\n");
+ return -1;
+ }
+
pci_client = find_parent_pci_dev(clients[i]);
if (!pci_client) {
if (verbose)
@@ -761,7 +729,7 @@ int pci_p2pdma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
* p2pdma mappings are not compatible with devices that use
* dma_virt_ops. If the upper layers do the right thing
* this should never happen because it will be prevented
- * by the check in pci_p2pdma_add_client()
+ * by the check in pci_p2pdma_distance_many()
*/
if (WARN_ON_ONCE(IS_ENABLED(CONFIG_DMA_VIRT_OPS) &&
dev->dma_ops == &dma_virt_ops))
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 1897847ceb0c..45049f558860 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -685,12 +685,21 @@ static pci_power_t acpi_pci_get_power_state(struct pci_dev *dev)
if (!adev || !acpi_device_power_manageable(adev))
return PCI_UNKNOWN;
- if (acpi_device_get_power(adev, &state) || state == ACPI_STATE_UNKNOWN)
+ state = adev->power.state;
+ if (state == ACPI_STATE_UNKNOWN)
return PCI_UNKNOWN;
return state_conv[state];
}
+static void acpi_pci_refresh_power_state(struct pci_dev *dev)
+{
+ struct acpi_device *adev = ACPI_COMPANION(&dev->dev);
+
+ if (adev && acpi_device_power_manageable(adev))
+ acpi_device_update_power(adev, NULL);
+}
+
static int acpi_pci_propagate_wakeup(struct pci_bus *bus, bool enable)
{
while (bus->parent) {
@@ -748,6 +757,7 @@ static const struct pci_platform_pm_ops acpi_pci_platform_pm = {
.is_manageable = acpi_pci_power_manageable,
.set_state = acpi_pci_set_power_state,
.get_state = acpi_pci_get_power_state,
+ .refresh_state = acpi_pci_refresh_power_state,
.choose_state = acpi_pci_choose_state,
.set_wakeup = acpi_pci_wakeup,
.need_resume = acpi_pci_need_resume,
@@ -901,6 +911,7 @@ static void pci_acpi_setup(struct device *dev)
device_wakeup_enable(dev);
acpi_pci_wakeup(pci_dev, false);
+ acpi_device_power_add_dependent(adev, dev);
}
static void pci_acpi_cleanup(struct device *dev)
@@ -913,6 +924,7 @@ static void pci_acpi_cleanup(struct device *dev)
pci_acpi_remove_pm_notifier(adev);
if (adev->wakeup.flags.valid) {
+ acpi_device_power_remove_dependent(adev, dev);
if (pci_dev->bridge_d3)
device_wakeup_disable(dev);
diff --git a/drivers/pci/pci-bridge-emul.c b/drivers/pci/pci-bridge-emul.c
index 83fb077d0b41..06083b86d4f4 100644
--- a/drivers/pci/pci-bridge-emul.c
+++ b/drivers/pci/pci-bridge-emul.c
@@ -305,7 +305,7 @@ int pci_bridge_emul_init(struct pci_bridge_emul *bridge,
}
/*
- * Cleanup a pci_bridge_emul structure that was previously initilized
+ * Cleanup a pci_bridge_emul structure that was previously initialized
* using pci_bridge_emul_init().
*/
void pci_bridge_emul_cleanup(struct pci_bridge_emul *bridge)
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 5eadbc3d0969..a8124e47bf6e 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -399,7 +399,8 @@ void __weak pcibios_free_irq(struct pci_dev *dev)
#ifdef CONFIG_PCI_IOV
static inline bool pci_device_can_probe(struct pci_dev *pdev)
{
- return (!pdev->is_virtfn || pdev->physfn->sriov->drivers_autoprobe);
+ return (!pdev->is_virtfn || pdev->physfn->sriov->drivers_autoprobe ||
+ pdev->driver_override);
}
#else
static inline bool pci_device_can_probe(struct pci_dev *pdev)
@@ -414,6 +415,9 @@ static int pci_device_probe(struct device *dev)
struct pci_dev *pci_dev = to_pci_dev(dev);
struct pci_driver *drv = to_pci_driver(dev->driver);
+ if (!pci_device_can_probe(pci_dev))
+ return -ENODEV;
+
pci_assign_irq(pci_dev);
error = pcibios_alloc_irq(pci_dev);
@@ -421,12 +425,10 @@ static int pci_device_probe(struct device *dev)
return error;
pci_dev_get(pci_dev);
- if (pci_device_can_probe(pci_dev)) {
- error = __pci_device_probe(drv, pci_dev);
- if (error) {
- pcibios_free_irq(pci_dev);
- pci_dev_put(pci_dev);
- }
+ error = __pci_device_probe(drv, pci_dev);
+ if (error) {
+ pcibios_free_irq(pci_dev);
+ pci_dev_put(pci_dev);
}
return error;
@@ -524,7 +526,6 @@ static void pci_pm_default_resume_early(struct pci_dev *pci_dev)
pci_power_up(pci_dev);
pci_restore_state(pci_dev);
pci_pme_restore(pci_dev);
- pci_fixup_device(pci_fixup_resume_early, pci_dev);
}
/*
@@ -679,6 +680,7 @@ static bool pci_has_legacy_pm_support(struct pci_dev *pci_dev)
static int pci_pm_prepare(struct device *dev)
{
struct device_driver *drv = dev->driver;
+ struct pci_dev *pci_dev = to_pci_dev(dev);
if (drv && drv->pm && drv->pm->prepare) {
int error = drv->pm->prepare(dev);
@@ -688,7 +690,15 @@ static int pci_pm_prepare(struct device *dev)
if (!error && dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_PREPARE))
return 0;
}
- return pci_dev_keep_suspended(to_pci_dev(dev));
+ if (pci_dev_need_resume(pci_dev))
+ return 0;
+
+ /*
+ * The PME setting needs to be adjusted here in case the direct-complete
+ * optimization is used with respect to this device.
+ */
+ pci_dev_adjust_pme(pci_dev);
+ return 1;
}
static void pci_pm_complete(struct device *dev)
@@ -702,7 +712,14 @@ static void pci_pm_complete(struct device *dev)
if (pm_runtime_suspended(dev) && pm_resume_via_firmware()) {
pci_power_t pre_sleep_state = pci_dev->current_state;
- pci_update_current_state(pci_dev, pci_dev->current_state);
+ pci_refresh_power_state(pci_dev);
+ /*
+ * On platforms with ACPI this check may also trigger for
+ * devices sharing power resources if one of those power
+ * resources has been activated as a result of a change of the
+ * power state of another device sharing it. However, in that
+ * case it is also better to resume the device, in general.
+ */
if (pci_dev->current_state < pre_sleep_state)
pm_request_resume(dev);
}
@@ -758,9 +775,11 @@ static int pci_pm_suspend(struct device *dev)
* better to resume the device from runtime suspend here.
*/
if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) ||
- !pci_dev_keep_suspended(pci_dev)) {
+ pci_dev_need_resume(pci_dev)) {
pm_runtime_resume(dev);
pci_dev->state_saved = false;
+ } else {
+ pci_dev_adjust_pme(pci_dev);
}
if (pm->suspend) {
@@ -831,18 +850,16 @@ static int pci_pm_suspend_noirq(struct device *dev)
if (pci_dev->skip_bus_pm) {
/*
- * The function is running for the second time in a row without
+ * Either the device is a bridge with a child in D0 below it, or
+ * the function is running for the second time in a row without
* going through full resume, which is possible only during
- * suspend-to-idle in a spurious wakeup case. Moreover, the
- * device was originally left in D0, so its power state should
- * not be changed here and the device register values saved
- * originally should be restored on resume again.
+ * suspend-to-idle in a spurious wakeup case. The device should
+ * be in D0 at this point, but if it is a bridge, it may be
+ * necessary to save its state.
*/
- pci_dev->state_saved = true;
- } else if (pci_dev->state_saved) {
- if (pci_dev->current_state == PCI_D0)
- pci_dev->skip_bus_pm = true;
- } else {
+ if (!pci_dev->state_saved)
+ pci_save_state(pci_dev);
+ } else if (!pci_dev->state_saved) {
pci_save_state(pci_dev);
if (pci_power_manageable(pci_dev))
pci_prepare_to_sleep(pci_dev);
@@ -851,6 +868,22 @@ static int pci_pm_suspend_noirq(struct device *dev)
dev_dbg(dev, "PCI PM: Suspend power state: %s\n",
pci_power_name(pci_dev->current_state));
+ if (pci_dev->current_state == PCI_D0) {
+ pci_dev->skip_bus_pm = true;
+ /*
+ * Per PCI PM r1.2, table 6-1, a bridge must be in D0 if any
+ * downstream device is in D0, so avoid changing the power state
+ * of the parent bridge by setting the skip_bus_pm flag for it.
+ */
+ if (pci_dev->bus->self)
+ pci_dev->bus->self->skip_bus_pm = true;
+ }
+
+ if (pci_dev->skip_bus_pm && pm_suspend_no_platform()) {
+ dev_dbg(dev, "PCI PM: Skipped\n");
+ goto Fixup;
+ }
+
pci_pm_set_unknown_state(pci_dev);
/*
@@ -898,7 +931,16 @@ static int pci_pm_resume_noirq(struct device *dev)
if (dev_pm_smart_suspend_and_suspended(dev))
pm_runtime_set_active(dev);
- pci_pm_default_resume_early(pci_dev);
+ /*
+ * In the suspend-to-idle case, devices left in D0 during suspend will
+ * stay in D0, so it is not necessary to restore or update their
+ * configuration here and attempting to put them into D0 again is
+ * pointless, so avoid doing that.
+ */
+ if (!(pci_dev->skip_bus_pm && pm_suspend_no_platform()))
+ pci_pm_default_resume_early(pci_dev);
+
+ pci_fixup_device(pci_fixup_resume_early, pci_dev);
if (pci_has_legacy_pm_support(pci_dev))
return pci_legacy_resume_early(dev);
@@ -972,15 +1014,15 @@ static int pci_pm_freeze(struct device *dev)
}
/*
- * This used to be done in pci_pm_prepare() for all devices and some
- * drivers may depend on it, so do it here. Ideally, runtime-suspended
- * devices should not be touched during freeze/thaw transitions,
- * however.
+ * Resume all runtime-suspended devices before creating a snapshot
+ * image of system memory, because the restore kernel generally cannot
+ * be expected to always handle them consistently and they need to be
+ * put into the runtime-active metastate during system resume anyway,
+ * so it is better to ensure that the state saved in the image will be
+ * always consistent with that.
*/
- if (!dev_pm_smart_suspend_and_suspended(dev)) {
- pm_runtime_resume(dev);
- pci_dev->state_saved = false;
- }
+ pm_runtime_resume(dev);
+ pci_dev->state_saved = false;
if (pm->freeze) {
int error;
@@ -994,22 +1036,11 @@ static int pci_pm_freeze(struct device *dev)
return 0;
}
-static int pci_pm_freeze_late(struct device *dev)
-{
- if (dev_pm_smart_suspend_and_suspended(dev))
- return 0;
-
- return pm_generic_freeze_late(dev);
-}
-
static int pci_pm_freeze_noirq(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct device_driver *drv = dev->driver;
- if (dev_pm_smart_suspend_and_suspended(dev))
- return 0;
-
if (pci_has_legacy_pm_support(pci_dev))
return pci_legacy_suspend_late(dev, PMSG_FREEZE);
@@ -1039,16 +1070,6 @@ static int pci_pm_thaw_noirq(struct device *dev)
struct device_driver *drv = dev->driver;
int error = 0;
- /*
- * If the device is in runtime suspend, the code below may not work
- * correctly with it, so skip that code and make the PM core skip all of
- * the subsequent "thaw" callbacks for the device.
- */
- if (dev_pm_smart_suspend_and_suspended(dev)) {
- dev_pm_skip_next_resume_phases(dev);
- return 0;
- }
-
if (pcibios_pm_ops.thaw_noirq) {
error = pcibios_pm_ops.thaw_noirq(dev);
if (error)
@@ -1108,10 +1129,13 @@ static int pci_pm_poweroff(struct device *dev)
/* The reason to do that is the same as in pci_pm_suspend(). */
if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) ||
- !pci_dev_keep_suspended(pci_dev))
+ pci_dev_need_resume(pci_dev)) {
pm_runtime_resume(dev);
+ pci_dev->state_saved = false;
+ } else {
+ pci_dev_adjust_pme(pci_dev);
+ }
- pci_dev->state_saved = false;
if (pm->poweroff) {
int error;
@@ -1183,10 +1207,6 @@ static int pci_pm_restore_noirq(struct device *dev)
struct device_driver *drv = dev->driver;
int error = 0;
- /* This is analogous to the pci_pm_resume_noirq() case. */
- if (dev_pm_smart_suspend_and_suspended(dev))
- pm_runtime_set_active(dev);
-
if (pcibios_pm_ops.restore_noirq) {
error = pcibios_pm_ops.restore_noirq(dev);
if (error)
@@ -1194,6 +1214,7 @@ static int pci_pm_restore_noirq(struct device *dev)
}
pci_pm_default_resume_early(pci_dev);
+ pci_fixup_device(pci_fixup_resume_early, pci_dev);
if (pci_has_legacy_pm_support(pci_dev))
return pci_legacy_resume_early(dev);
@@ -1235,7 +1256,6 @@ static int pci_pm_restore(struct device *dev)
#else /* !CONFIG_HIBERNATE_CALLBACKS */
#define pci_pm_freeze NULL
-#define pci_pm_freeze_late NULL
#define pci_pm_freeze_noirq NULL
#define pci_pm_thaw NULL
#define pci_pm_thaw_noirq NULL
@@ -1361,7 +1381,6 @@ static const struct dev_pm_ops pci_dev_pm_ops = {
.suspend_late = pci_pm_suspend_late,
.resume = pci_pm_resume,
.freeze = pci_pm_freeze,
- .freeze_late = pci_pm_freeze_late,
.thaw = pci_pm_thaw,
.poweroff = pci_pm_poweroff,
.poweroff_late = pci_pm_poweroff_late,
diff --git a/drivers/pci/pci-pf-stub.c b/drivers/pci/pci-pf-stub.c
index 9795649fc6f9..ef293e735c55 100644
--- a/drivers/pci/pci-pf-stub.c
+++ b/drivers/pci/pci-pf-stub.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/* pci-pf-stub - simple stub driver for PCI SR-IOV PF device
*
- * This driver is meant to act as a "whitelist" for devices that provde
+ * This driver is meant to act as a "whitelist" for devices that provide
* SR-IOV functionality while at the same time not actually needing a
* driver of their own.
*/
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 6d27475e39b2..965c72104150 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -182,6 +182,9 @@ static ssize_t current_link_speed_show(struct device *dev,
return -EINVAL;
switch (linkstat & PCI_EXP_LNKSTA_CLS) {
+ case PCI_EXP_LNKSTA_CLS_32_0GB:
+ speed = "32 GT/s";
+ break;
case PCI_EXP_LNKSTA_CLS_16_0GB:
speed = "16 GT/s";
break;
@@ -477,7 +480,7 @@ static ssize_t remove_store(struct device *dev, struct device_attribute *attr,
pci_stop_and_remove_bus_device_locked(to_pci_dev(dev));
return count;
}
-static struct device_attribute dev_remove_attr = __ATTR(remove,
+static struct device_attribute dev_remove_attr = __ATTR_IGNORE_LOCKDEP(remove,
(S_IWUSR|S_IWGRP),
NULL, remove_store);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 8abc843b1615..29ed5ec1ac27 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -777,6 +777,12 @@ static inline pci_power_t platform_pci_get_power_state(struct pci_dev *dev)
return pci_platform_pm ? pci_platform_pm->get_state(dev) : PCI_UNKNOWN;
}
+static inline void platform_pci_refresh_power_state(struct pci_dev *dev)
+{
+ if (pci_platform_pm && pci_platform_pm->refresh_state)
+ pci_platform_pm->refresh_state(dev);
+}
+
static inline pci_power_t platform_pci_choose_state(struct pci_dev *dev)
{
return pci_platform_pm ?
@@ -938,6 +944,21 @@ void pci_update_current_state(struct pci_dev *dev, pci_power_t state)
}
/**
+ * pci_refresh_power_state - Refresh the given device's power state data
+ * @dev: Target PCI device.
+ *
+ * Ask the platform to refresh the devices power state information and invoke
+ * pci_update_current_state() to update its current PCI power state.
+ */
+void pci_refresh_power_state(struct pci_dev *dev)
+{
+ if (platform_pci_power_manageable(dev))
+ platform_pci_refresh_power_state(dev);
+
+ pci_update_current_state(dev, dev->current_state);
+}
+
+/**
* pci_power_up - Put the given device into D0 forcibly
* @dev: PCI device to power up
*/
@@ -1004,15 +1025,10 @@ static void __pci_start_power_transition(struct pci_dev *dev, pci_power_t state)
if (state == PCI_D0) {
pci_platform_power_transition(dev, PCI_D0);
/*
- * Mandatory power management transition delays, see
- * PCI Express Base Specification Revision 2.0 Section
- * 6.6.1: Conventional Reset. Do not delay for
- * devices powered on/off by corresponding bridge,
- * because have already delayed for the bridge.
+ * Mandatory power management transition delays are
+ * handled in the PCIe portdrv resume hooks.
*/
if (dev->runtime_d3cold) {
- if (dev->d3cold_delay && !dev->imm_ready)
- msleep(dev->d3cold_delay);
/*
* When powering on a bridge from D3cold, the
* whole hierarchy may be powered on into
@@ -2065,6 +2081,13 @@ static void pci_pme_list_scan(struct work_struct *work)
*/
if (bridge && bridge->current_state != PCI_D0)
continue;
+ /*
+ * If the device is in D3cold it should not be
+ * polled either.
+ */
+ if (pme_dev->dev->current_state == PCI_D3cold)
+ continue;
+
pci_pme_wakeup(pme_dev->dev, NULL);
} else {
list_del(&pme_dev->list);
@@ -2459,45 +2482,56 @@ bool pci_dev_run_wake(struct pci_dev *dev)
EXPORT_SYMBOL_GPL(pci_dev_run_wake);
/**
- * pci_dev_keep_suspended - Check if the device can stay in the suspended state.
+ * pci_dev_need_resume - Check if it is necessary to resume the device.
* @pci_dev: Device to check.
*
- * Return 'true' if the device is runtime-suspended, it doesn't have to be
+ * Return 'true' if the device is not runtime-suspended or it has to be
* reconfigured due to wakeup settings difference between system and runtime
- * suspend and the current power state of it is suitable for the upcoming
- * (system) transition.
- *
- * If the device is not configured for system wakeup, disable PME for it before
- * returning 'true' to prevent it from waking up the system unnecessarily.
+ * suspend, or the current power state of it is not suitable for the upcoming
+ * (system-wide) transition.
*/
-bool pci_dev_keep_suspended(struct pci_dev *pci_dev)
+bool pci_dev_need_resume(struct pci_dev *pci_dev)
{
struct device *dev = &pci_dev->dev;
- bool wakeup = device_may_wakeup(dev);
+ pci_power_t target_state;
- if (!pm_runtime_suspended(dev)
- || pci_target_state(pci_dev, wakeup) != pci_dev->current_state
- || platform_pci_need_resume(pci_dev))
- return false;
+ if (!pm_runtime_suspended(dev) || platform_pci_need_resume(pci_dev))
+ return true;
+
+ target_state = pci_target_state(pci_dev, device_may_wakeup(dev));
/*
- * At this point the device is good to go unless it's been configured
- * to generate PME at the runtime suspend time, but it is not supposed
- * to wake up the system. In that case, simply disable PME for it
- * (it will have to be re-enabled on exit from system resume).
- *
- * If the device's power state is D3cold and the platform check above
- * hasn't triggered, the device's configuration is suitable and we don't
- * need to manipulate it at all.
+ * If the earlier platform check has not triggered, D3cold is just power
+ * removal on top of D3hot, so no need to resume the device in that
+ * case.
*/
+ return target_state != pci_dev->current_state &&
+ target_state != PCI_D3cold &&
+ pci_dev->current_state != PCI_D3hot;
+}
+
+/**
+ * pci_dev_adjust_pme - Adjust PME setting for a suspended device.
+ * @pci_dev: Device to check.
+ *
+ * If the device is suspended and it is not configured for system wakeup,
+ * disable PME for it to prevent it from waking up the system unnecessarily.
+ *
+ * Note that if the device's power state is D3cold and the platform check in
+ * pci_dev_need_resume() has not triggered, the device's configuration need not
+ * be changed.
+ */
+void pci_dev_adjust_pme(struct pci_dev *pci_dev)
+{
+ struct device *dev = &pci_dev->dev;
+
spin_lock_irq(&dev->power.lock);
- if (pm_runtime_suspended(dev) && pci_dev->current_state < PCI_D3cold &&
- !wakeup)
+ if (pm_runtime_suspended(dev) && !device_may_wakeup(dev) &&
+ pci_dev->current_state < PCI_D3cold)
__pci_pme_active(pci_dev, false);
spin_unlock_irq(&dev->power.lock);
- return true;
}
/**
@@ -4501,7 +4535,7 @@ static int pci_af_flr(struct pci_dev *dev, int probe)
/*
* Wait for Transaction Pending bit to clear. A word-aligned test
- * is used, so we use the conrol offset rather than status and shift
+ * is used, so we use the control offset rather than status and shift
* the test bit to match.
*/
if (!pci_wait_for_pending(dev, pos + PCI_AF_CTRL,
@@ -4568,14 +4602,16 @@ static int pci_pm_reset(struct pci_dev *dev, int probe)
return pci_dev_wait(dev, "PM D3->D0", PCIE_RESET_READY_POLL_MS);
}
+
/**
- * pcie_wait_for_link - Wait until link is active or inactive
+ * pcie_wait_for_link_delay - Wait until link is active or inactive
* @pdev: Bridge device
* @active: waiting for active or inactive?
+ * @delay: Delay to wait after link has become active (in ms)
*
* Use this to wait till link becomes active or inactive.
*/
-bool pcie_wait_for_link(struct pci_dev *pdev, bool active)
+bool pcie_wait_for_link_delay(struct pci_dev *pdev, bool active, int delay)
{
int timeout = 1000;
bool ret;
@@ -4612,13 +4648,25 @@ bool pcie_wait_for_link(struct pci_dev *pdev, bool active)
timeout -= 10;
}
if (active && ret)
- msleep(100);
+ msleep(delay);
else if (ret != active)
pci_info(pdev, "Data Link Layer Link Active not %s in 1000 msec\n",
active ? "set" : "cleared");
return ret == active;
}
+/**
+ * pcie_wait_for_link - Wait until link is active or inactive
+ * @pdev: Bridge device
+ * @active: waiting for active or inactive?
+ *
+ * Use this to wait till link becomes active or inactive.
+ */
+bool pcie_wait_for_link(struct pci_dev *pdev, bool active)
+{
+ return pcie_wait_for_link_delay(pdev, active, 100);
+}
+
void pci_reset_secondary_bus(struct pci_dev *dev)
{
u16 ctrl;
@@ -5621,7 +5669,9 @@ enum pci_bus_speed pcie_get_speed_cap(struct pci_dev *dev)
*/
pcie_capability_read_dword(dev, PCI_EXP_LNKCAP2, &lnkcap2);
if (lnkcap2) { /* PCIe r3.0-compliant */
- if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_16_0GB)
+ if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_32_0GB)
+ return PCIE_SPEED_32_0GT;
+ else if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_16_0GB)
return PCIE_SPEED_16_0GT;
else if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_8_0GB)
return PCIE_SPEED_8_0GT;
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 9cb99380c61e..1be03a97cb92 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -51,6 +51,8 @@ int pci_bus_error_reset(struct pci_dev *dev);
*
* @get_state: queries the platform firmware for a device's current power state
*
+ * @refresh_state: asks the platform to refresh the device's power state data
+ *
* @choose_state: returns PCI power state of given device preferred by the
* platform; to be used during system-wide transitions from a
* sleeping state to the working state and vice versa
@@ -69,6 +71,7 @@ struct pci_platform_pm_ops {
bool (*is_manageable)(struct pci_dev *dev);
int (*set_state)(struct pci_dev *dev, pci_power_t state);
pci_power_t (*get_state)(struct pci_dev *dev);
+ void (*refresh_state)(struct pci_dev *dev);
pci_power_t (*choose_state)(struct pci_dev *dev);
int (*set_wakeup)(struct pci_dev *dev, bool enable);
bool (*need_resume)(struct pci_dev *dev);
@@ -76,13 +79,15 @@ struct pci_platform_pm_ops {
int pci_set_platform_pm(const struct pci_platform_pm_ops *ops);
void pci_update_current_state(struct pci_dev *dev, pci_power_t state);
+void pci_refresh_power_state(struct pci_dev *dev);
void pci_power_up(struct pci_dev *dev);
void pci_disable_enabled_device(struct pci_dev *dev);
int pci_finish_runtime_suspend(struct pci_dev *dev);
void pcie_clear_root_pme_status(struct pci_dev *dev);
int __pci_pme_wakeup(struct pci_dev *dev, void *ign);
void pci_pme_restore(struct pci_dev *dev);
-bool pci_dev_keep_suspended(struct pci_dev *dev);
+bool pci_dev_need_resume(struct pci_dev *dev);
+void pci_dev_adjust_pme(struct pci_dev *dev);
void pci_dev_complete_resume(struct pci_dev *pci_dev);
void pci_config_pm_runtime_get(struct pci_dev *dev);
void pci_config_pm_runtime_put(struct pci_dev *dev);
@@ -293,7 +298,6 @@ struct pci_sriov {
u16 driver_max_VFs; /* Max num VFs driver supports */
struct pci_dev *dev; /* Lowest numbered PF */
struct pci_dev *self; /* This PF */
- u32 cfg_size; /* VF config space size */
u32 class; /* VF device */
u8 hdr_type; /* VF header type */
u16 subsystem_vendor; /* VF subsystem vendor */
@@ -493,6 +497,7 @@ static inline int pci_dev_specific_disable_acs_redir(struct pci_dev *dev)
void pcie_do_recovery(struct pci_dev *dev, enum pci_channel_state state,
u32 service);
+bool pcie_wait_for_link_delay(struct pci_dev *pdev, bool active, int delay);
bool pcie_wait_for_link(struct pci_dev *pdev, bool active);
#ifdef CONFIG_PCIEASPM
void pcie_aspm_init_link_state(struct pci_dev *pdev);
diff --git a/drivers/pci/pcie/aer_inject.c b/drivers/pci/pcie/aer_inject.c
index 043b8b0cfcc5..6988fe7389b9 100644
--- a/drivers/pci/pcie/aer_inject.c
+++ b/drivers/pci/pcie/aer_inject.c
@@ -2,7 +2,7 @@
/*
* PCIe AER software error injection support.
*
- * Debuging PCIe AER code is quite difficult because it is hard to
+ * Debugging PCIe AER code is quite difficult because it is hard to
* trigger various real hardware errors. Software based error
* injection can fake almost all kinds of errors with the help of a
* user space helper tool aer-inject, which can be gotten from:
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index fd4cb75088f9..e44af7f4d37f 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -1062,18 +1062,18 @@ void pcie_aspm_powersave_config_link(struct pci_dev *pdev)
up_read(&pci_bus_sem);
}
-static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
+static int __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
{
struct pci_dev *parent = pdev->bus->self;
struct pcie_link_state *link;
if (!pci_is_pcie(pdev))
- return;
+ return 0;
if (pdev->has_secondary_link)
parent = pdev;
if (!parent || !parent->link_state)
- return;
+ return -EINVAL;
/*
* A driver requested that ASPM be disabled on this device, but
@@ -1085,7 +1085,7 @@ static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
*/
if (aspm_disabled) {
pci_warn(pdev, "can't disable ASPM; OS doesn't have ASPM control\n");
- return;
+ return -EPERM;
}
if (sem)
@@ -1105,11 +1105,13 @@ static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
mutex_unlock(&aspm_lock);
if (sem)
up_read(&pci_bus_sem);
+
+ return 0;
}
-void pci_disable_link_state_locked(struct pci_dev *pdev, int state)
+int pci_disable_link_state_locked(struct pci_dev *pdev, int state)
{
- __pci_disable_link_state(pdev, state, false);
+ return __pci_disable_link_state(pdev, state, false);
}
EXPORT_SYMBOL(pci_disable_link_state_locked);
@@ -1117,14 +1119,14 @@ EXPORT_SYMBOL(pci_disable_link_state_locked);
* pci_disable_link_state - Disable device's link state, so the link will
* never enter specific states. Note that if the BIOS didn't grant ASPM
* control to the OS, this does nothing because we can't touch the LNKCTL
- * register.
+ * register. Returns 0 or a negative errno.
*
* @pdev: PCI device
* @state: ASPM link state to disable
*/
-void pci_disable_link_state(struct pci_dev *pdev, int state)
+int pci_disable_link_state(struct pci_dev *pdev, int state)
{
- __pci_disable_link_state(pdev, state, true);
+ return __pci_disable_link_state(pdev, state, true);
}
EXPORT_SYMBOL(pci_disable_link_state);
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
index 1b330129089f..308c3e0c4a34 100644
--- a/drivers/pci/pcie/portdrv_core.c
+++ b/drivers/pci/pcie/portdrv_core.c
@@ -9,6 +9,7 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
+#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
@@ -378,6 +379,67 @@ static int pm_iter(struct device *dev, void *data)
return 0;
}
+static int get_downstream_delay(struct pci_bus *bus)
+{
+ struct pci_dev *pdev;
+ int min_delay = 100;
+ int max_delay = 0;
+
+ list_for_each_entry(pdev, &bus->devices, bus_list) {
+ if (!pdev->imm_ready)
+ min_delay = 0;
+ else if (pdev->d3cold_delay < min_delay)
+ min_delay = pdev->d3cold_delay;
+ if (pdev->d3cold_delay > max_delay)
+ max_delay = pdev->d3cold_delay;
+ }
+
+ return max(min_delay, max_delay);
+}
+
+/*
+ * wait_for_downstream_link - Wait for downstream link to establish
+ * @pdev: PCIe port whose downstream link is waited
+ *
+ * Handle delays according to PCIe 4.0 section 6.6.1 before configuration
+ * access to the downstream component is permitted.
+ *
+ * This blocks PCI core resume of the hierarchy below this port until the
+ * link is trained. Should be called before resuming port services to
+ * prevent pciehp from starting to tear-down the hierarchy too soon.
+ */
+static void wait_for_downstream_link(struct pci_dev *pdev)
+{
+ int delay;
+
+ if (pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT &&
+ pci_pcie_type(pdev) != PCI_EXP_TYPE_DOWNSTREAM)
+ return;
+
+ if (pci_dev_is_disconnected(pdev))
+ return;
+
+ if (!pdev->subordinate || list_empty(&pdev->subordinate->devices) ||
+ !pdev->bridge_d3)
+ return;
+
+ delay = get_downstream_delay(pdev->subordinate);
+ if (!delay)
+ return;
+
+ dev_dbg(&pdev->dev, "waiting downstream link for %d ms\n", delay);
+
+ /*
+ * If downstream port does not support speeds greater than 5 GT/s
+ * need to wait 100ms. For higher speeds (gen3) we need to wait
+ * first for the data link layer to become active.
+ */
+ if (pcie_get_speed_cap(pdev) <= PCIE_SPEED_5_0GT)
+ msleep(delay);
+ else
+ pcie_wait_for_link_delay(pdev, true, delay);
+}
+
/**
* pcie_port_device_suspend - suspend port services associated with a PCIe port
* @dev: PCI Express port to handle
@@ -391,6 +453,8 @@ int pcie_port_device_suspend(struct device *dev)
int pcie_port_device_resume_noirq(struct device *dev)
{
size_t off = offsetof(struct pcie_port_service_driver, resume_noirq);
+
+ wait_for_downstream_link(to_pci_dev(dev));
return device_for_each_child(dev, &off, pm_iter);
}
@@ -421,6 +485,8 @@ int pcie_port_device_runtime_suspend(struct device *dev)
int pcie_port_device_runtime_resume(struct device *dev)
{
size_t off = offsetof(struct pcie_port_service_driver, runtime_resume);
+
+ wait_for_downstream_link(to_pci_dev(dev));
return device_for_each_child(dev, &off, pm_iter);
}
#endif /* PM */
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 0e8e2c186f50..a3c7338fad86 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -64,7 +64,7 @@ static struct resource *get_pci_domain_busn_res(int domain_nr)
return &r->res;
}
-static int find_anything(struct device *dev, void *data)
+static int find_anything(struct device *dev, const void *data)
{
return 1;
}
@@ -668,7 +668,7 @@ const unsigned char pcie_link_speed[] = {
PCIE_SPEED_5_0GT, /* 2 */
PCIE_SPEED_8_0GT, /* 3 */
PCIE_SPEED_16_0GT, /* 4 */
- PCI_SPEED_UNKNOWN, /* 5 */
+ PCIE_SPEED_32_0GT, /* 5 */
PCI_SPEED_UNKNOWN, /* 6 */
PCI_SPEED_UNKNOWN, /* 7 */
PCI_SPEED_UNKNOWN, /* 8 */
@@ -1555,17 +1555,6 @@ static int pci_cfg_space_size_ext(struct pci_dev *dev)
return PCI_CFG_SPACE_EXP_SIZE;
}
-#ifdef CONFIG_PCI_IOV
-static bool is_vf0(struct pci_dev *dev)
-{
- if (pci_iov_virtfn_devfn(dev->physfn, 0) == dev->devfn &&
- pci_iov_virtfn_bus(dev->physfn, 0) == dev->bus->number)
- return true;
-
- return false;
-}
-#endif
-
int pci_cfg_space_size(struct pci_dev *dev)
{
int pos;
@@ -1573,9 +1562,18 @@ int pci_cfg_space_size(struct pci_dev *dev)
u16 class;
#ifdef CONFIG_PCI_IOV
- /* Read cached value for all VFs except for VF0 */
- if (dev->is_virtfn && !is_vf0(dev))
- return dev->physfn->sriov->cfg_size;
+ /*
+ * Per the SR-IOV specification (rev 1.1, sec 3.5), VFs are required to
+ * implement a PCIe capability and therefore must implement extended
+ * config space. We can skip the NO_EXTCFG test below and the
+ * reachability/aliasing test in pci_cfg_space_size_ext() by virtue of
+ * the fact that the SR-IOV capability on the PF resides in extended
+ * config space and must be accessible and non-aliased to have enabled
+ * support for this VF. This is a micro performance optimization for
+ * systems supporting many VFs.
+ */
+ if (dev->is_virtfn)
+ return PCI_CFG_SPACE_EXP_SIZE;
#endif
if (dev->bus->bus_flags & PCI_BUS_FLAGS_NO_EXTCFG)
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index 445b51db75b0..fe7fe678965b 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -377,7 +377,7 @@ static int show_device(struct seq_file *m, void *v)
}
seq_putc(m, '\t');
if (drv)
- seq_printf(m, "%s", drv->name);
+ seq_puts(m, drv->name);
seq_putc(m, '\n');
return 0;
}
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 0f16acc323c6..208aacf39329 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -4934,35 +4934,49 @@ static void quirk_fsl_no_msi(struct pci_dev *pdev)
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_FREESCALE, PCI_ANY_ID, quirk_fsl_no_msi);
/*
- * GPUs with integrated HDA controller for streaming audio to attached displays
- * need a device link from the HDA controller (consumer) to the GPU (supplier)
- * so that the GPU is powered up whenever the HDA controller is accessed.
- * The GPU and HDA controller are functions 0 and 1 of the same PCI device.
- * The device link stays in place until shutdown (or removal of the PCI device
- * if it's hotplugged). Runtime PM is allowed by default on the HDA controller
- * to prevent it from permanently keeping the GPU awake.
+ * Although not allowed by the spec, some multi-function devices have
+ * dependencies of one function (consumer) on another (supplier). For the
+ * consumer to work in D0, the supplier must also be in D0. Create a
+ * device link from the consumer to the supplier to enforce this
+ * dependency. Runtime PM is allowed by default on the consumer to prevent
+ * it from permanently keeping the supplier awake.
*/
-static void quirk_gpu_hda(struct pci_dev *hda)
+static void pci_create_device_link(struct pci_dev *pdev, unsigned int consumer,
+ unsigned int supplier, unsigned int class,
+ unsigned int class_shift)
{
- struct pci_dev *gpu;
+ struct pci_dev *supplier_pdev;
- if (PCI_FUNC(hda->devfn) != 1)
+ if (PCI_FUNC(pdev->devfn) != consumer)
return;
- gpu = pci_get_domain_bus_and_slot(pci_domain_nr(hda->bus),
- hda->bus->number,
- PCI_DEVFN(PCI_SLOT(hda->devfn), 0));
- if (!gpu || (gpu->class >> 16) != PCI_BASE_CLASS_DISPLAY) {
- pci_dev_put(gpu);
+ supplier_pdev = pci_get_domain_bus_and_slot(pci_domain_nr(pdev->bus),
+ pdev->bus->number,
+ PCI_DEVFN(PCI_SLOT(pdev->devfn), supplier));
+ if (!supplier_pdev || (supplier_pdev->class >> class_shift) != class) {
+ pci_dev_put(supplier_pdev);
return;
}
- if (!device_link_add(&hda->dev, &gpu->dev,
- DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME))
- pci_err(hda, "cannot link HDA to GPU %s\n", pci_name(gpu));
+ if (device_link_add(&pdev->dev, &supplier_pdev->dev,
+ DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME))
+ pci_info(pdev, "D0 power state depends on %s\n",
+ pci_name(supplier_pdev));
+ else
+ pci_err(pdev, "Cannot enforce power dependency on %s\n",
+ pci_name(supplier_pdev));
+
+ pm_runtime_allow(&pdev->dev);
+ pci_dev_put(supplier_pdev);
+}
- pm_runtime_allow(&hda->dev);
- pci_dev_put(gpu);
+/*
+ * Create device link for GPUs with integrated HDA controller for streaming
+ * audio to attached displays.
+ */
+static void quirk_gpu_hda(struct pci_dev *hda)
+{
+ pci_create_device_link(hda, 1, 0, PCI_BASE_CLASS_DISPLAY, 16);
}
DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_ATI, PCI_ANY_ID,
PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda);
@@ -4972,6 +4986,62 @@ DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda);
/*
+ * Create device link for NVIDIA GPU with integrated USB xHCI Host
+ * controller to VGA.
+ */
+static void quirk_gpu_usb(struct pci_dev *usb)
+{
+ pci_create_device_link(usb, 2, 0, PCI_BASE_CLASS_DISPLAY, 16);
+}
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
+ PCI_CLASS_SERIAL_USB, 8, quirk_gpu_usb);
+
+/*
+ * Create device link for NVIDIA GPU with integrated Type-C UCSI controller
+ * to VGA. Currently there is no class code defined for UCSI device over PCI
+ * so using UNKNOWN class for now and it will be updated when UCSI
+ * over PCI gets a class code.
+ */
+#define PCI_CLASS_SERIAL_UNKNOWN 0x0c80
+static void quirk_gpu_usb_typec_ucsi(struct pci_dev *ucsi)
+{
+ pci_create_device_link(ucsi, 3, 0, PCI_BASE_CLASS_DISPLAY, 16);
+}
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
+ PCI_CLASS_SERIAL_UNKNOWN, 8,
+ quirk_gpu_usb_typec_ucsi);
+
+/*
+ * Enable the NVIDIA GPU integrated HDA controller if the BIOS left it
+ * disabled. https://devtalk.nvidia.com/default/topic/1024022
+ */
+static void quirk_nvidia_hda(struct pci_dev *gpu)
+{
+ u8 hdr_type;
+ u32 val;
+
+ /* There was no integrated HDA controller before MCP89 */
+ if (gpu->device < PCI_DEVICE_ID_NVIDIA_GEFORCE_320M)
+ return;
+
+ /* Bit 25 at offset 0x488 enables the HDA controller */
+ pci_read_config_dword(gpu, 0x488, &val);
+ if (val & BIT(25))
+ return;
+
+ pci_info(gpu, "Enabling HDA controller\n");
+ pci_write_config_dword(gpu, 0x488, val | BIT(25));
+
+ /* The GPU becomes a multi-function device when the HDA is enabled */
+ pci_read_config_byte(gpu, PCI_HEADER_TYPE, &hdr_type);
+ gpu->multifunction = !!(hdr_type & 0x80);
+}
+DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
+ PCI_BASE_CLASS_DISPLAY, 16, quirk_nvidia_hda);
+DECLARE_PCI_FIXUP_CLASS_RESUME_EARLY(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
+ PCI_BASE_CLASS_DISPLAY, 16, quirk_nvidia_hda);
+
+/*
* Some IDT switches incorrectly flag an ACS Source Validation error on
* completions for config read requests even though PCIe r4.0, sec
* 6.12.1.1, says that completions are never affected by ACS Source
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index 5c7922612733..7f4e65872b8d 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -236,10 +236,10 @@ struct pci_dev *pci_get_domain_bus_and_slot(int domain, unsigned int bus,
}
EXPORT_SYMBOL(pci_get_domain_bus_and_slot);
-static int match_pci_dev_by_id(struct device *dev, void *data)
+static int match_pci_dev_by_id(struct device *dev, const void *data)
{
struct pci_dev *pdev = to_pci_dev(dev);
- struct pci_device_id *id = data;
+ const struct pci_device_id *id = data;
if (pci_match_one_device(id, pdev))
return 1;
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 0cdd5ff389de..79b1fa6519be 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -1684,10 +1684,15 @@ static enum enable_type pci_realloc_detect(struct pci_bus *bus,
enum enable_type enable_local)
{
bool unassigned = false;
+ struct pci_host_bridge *host;
if (enable_local != undefined)
return enable_local;
+ host = pci_find_host_bridge(bus);
+ if (host->preserve_config)
+ return auto_disabled;
+
pci_walk_bus(bus, iov_resources_unassigned, &unassigned);
if (unassigned)
return auto_enabled;
@@ -1861,16 +1866,6 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus,
available_mmio_pref);
/*
- * Calculate the total amount of extra resource space we can
- * pass to bridges below this one. This is basically the
- * extra space reduced by the minimal required space for the
- * non-hotplug bridges.
- */
- remaining_io = available_io;
- remaining_mmio = available_mmio;
- remaining_mmio_pref = available_mmio_pref;
-
- /*
* Calculate how many hotplug bridges and normal bridges there
* are on this bus. We will distribute the additional available
* resources between hotplug bridges.
@@ -1882,6 +1877,34 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus,
normal_bridges++;
}
+ /*
+ * There is only one bridge on the bus so it gets all available
+ * resources which it can then distribute to the possible hotplug
+ * bridges below.
+ */
+ if (hotplug_bridges + normal_bridges == 1) {
+ dev = list_first_entry(&bus->devices, struct pci_dev, bus_list);
+ if (dev->subordinate) {
+ pci_bus_distribute_available_resources(dev->subordinate,
+ add_list, available_io, available_mmio,
+ available_mmio_pref);
+ }
+ return;
+ }
+
+ if (hotplug_bridges == 0)
+ return;
+
+ /*
+ * Calculate the total amount of extra resource space we can
+ * pass to bridges below this one. This is basically the
+ * extra space reduced by the minimal required space for the
+ * non-hotplug bridges.
+ */
+ remaining_io = available_io;
+ remaining_mmio = available_mmio;
+ remaining_mmio_pref = available_mmio_pref;
+
for_each_pci_bridge(dev, bus) {
const struct resource *res;
@@ -1906,21 +1929,6 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus,
}
/*
- * There is only one bridge on the bus so it gets all available
- * resources which it can then distribute to the possible hotplug
- * bridges below.
- */
- if (hotplug_bridges + normal_bridges == 1) {
- dev = list_first_entry(&bus->devices, struct pci_dev, bus_list);
- if (dev->subordinate) {
- pci_bus_distribute_available_resources(dev->subordinate,
- add_list, available_io, available_mmio,
- available_mmio_pref);
- }
- return;
- }
-
- /*
* Go over devices on this bus and distribute the remaining
* resource space between hotplug bridges.
*/
@@ -1936,8 +1944,6 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus,
* Distribute available extra resources equally between
* hotplug-capable downstream ports taking alignment into
* account.
- *
- * Here hotplug_bridges is always != 0.
*/
align = pci_resource_alignment(bridge, io_res);
io = div64_ul(available_io, hotplug_bridges);
diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c
index f4d92b1afe7b..ae4aa0e1f2f4 100644
--- a/drivers/pci/slot.c
+++ b/drivers/pci/slot.c
@@ -75,6 +75,7 @@ static const char *pci_bus_speed_strings[] = {
"5.0 GT/s PCIe", /* 0x15 */
"8.0 GT/s PCIe", /* 0x16 */
"16.0 GT/s PCIe", /* 0x17 */
+ "32.0 GT/s PCIe", /* 0x18 */
};
static ssize_t bus_speed_read(enum pci_bus_speed speed, char *buf)
diff --git a/drivers/pci/switch/Kconfig b/drivers/pci/switch/Kconfig
index aee28a5bb98f..d370f4ce0492 100644
--- a/drivers/pci/switch/Kconfig
+++ b/drivers/pci/switch/Kconfig
@@ -9,7 +9,7 @@ config PCI_SW_SWITCHTEC
Enables support for the management interface for the MicroSemi
Switchtec series of PCIe switches. Supports userspace access
to submit MRPC commands to the switch via /dev/switchtecX
- devices. See <file:Documentation/switchtec.txt> for more
+ devices. See <file:Documentation/driver-api/switchtec.rst> for more
information.
endmenu
diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c
index 5c0170597037..c502dfbf66e3 100644
--- a/drivers/pcmcia/cardbus.c
+++ b/drivers/pcmcia/cardbus.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* cardbus.c -- 16-bit PCMCIA core support
*
- * 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.
- *
* The initial developer of the original code is David A. Hinds
* <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
* are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c
index ac0672b8dfca..abd029945cc8 100644
--- a/drivers/pcmcia/cistpl.c
+++ b/drivers/pcmcia/cistpl.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* cistpl.c -- 16-bit PCMCIA Card Information Structure parser
*
- * 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.
- *
* The initial developer of the original code is David A. Hinds
* <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
* are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index 8c8caec3a72c..e211e2619680 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* cs.c -- Kernel Card Services - core services
*
- * 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.
- *
* The initial developer of the original code is David A. Hinds
* <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
* are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
index 03ec43802909..33c9b6ea7364 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* cs_internal.h -- definitions internal to the PCMCIA core modules
*
- * 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.
- *
* The initial developer of the original code is David A. Hinds
* <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
* are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
@@ -12,7 +9,6 @@
* (C) 1999 David A. Hinds
* (C) 2003 - 2010 Dominik Brodowski
*
- *
* This file contains definitions _only_ needed by the PCMCIA core modules.
* It must not be included by PCMCIA socket drivers or by PCMCIA device
* drivers.
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index a9258f641cee..09d06b082f8b 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ds.c -- 16-bit PCMCIA core support
*
- * 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.
- *
* The initial developer of the original code is David A. Hinds
* <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
* are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
@@ -67,7 +64,7 @@ static void pcmcia_check_driver(struct pcmcia_driver *p_drv)
"be 0x%x\n", p_drv->name, did->prod_id[i],
did->prod_id_hash[i], hash);
printk(KERN_DEBUG "pcmcia: see "
- "Documentation/pcmcia/devicetable.txt for "
+ "Documentation/pcmcia/devicetable.rst for "
"details\n");
}
did++;
diff --git a/drivers/pcmcia/pcmcia_cis.c b/drivers/pcmcia/pcmcia_cis.c
index 1c05d74e850d..b553f7ab532f 100644
--- a/drivers/pcmcia/pcmcia_cis.c
+++ b/drivers/pcmcia/pcmcia_cis.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* PCMCIA high-level CIS access functions
*
@@ -7,11 +8,6 @@
*
* Copyright (C) 1999 David A. Hinds
* Copyright (C) 2004-2010 Dominik Brodowski
- *
- * 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.
- *
*/
#include <linux/slab.h>
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
index 41ce410f7f97..e3a6b6c8a5b0 100644
--- a/drivers/pcmcia/pcmcia_resource.c
+++ b/drivers/pcmcia/pcmcia_resource.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* PCMCIA 16-bit resource management functions
*
@@ -7,11 +8,6 @@
*
* Copyright (C) 1999 David A. Hinds
* Copyright (C) 2004-2010 Dominik Brodowski
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/pcmcia/pxa2xx_balloon3.c b/drivers/pcmcia/pxa2xx_balloon3.c
index 2ef576c5b69d..5fe1da7a50e4 100644
--- a/drivers/pcmcia/pxa2xx_balloon3.c
+++ b/drivers/pcmcia/pxa2xx_balloon3.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/pcmcia/pxa2xx_balloon3.c
*
@@ -9,10 +10,6 @@
* Derived from pxa2xx_mainstone.c, by Nico Pitre
*
* Various modification by Marek Vasut <marek.vasut@gmail.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/pcmcia/pxa2xx_cm_x255.c b/drivers/pcmcia/pxa2xx_cm_x255.c
index da40908b29dd..c0b6b846fbaa 100644
--- a/drivers/pcmcia/pxa2xx_cm_x255.c
+++ b/drivers/pcmcia/pxa2xx_cm_x255.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/pcmcia/pxa/pxa_cm_x255.c
*
- * 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.
- *
* Compulab Ltd., 2003, 2007, 2008
* Mike Rapoport <mike@compulab.co.il>
- *
*/
#include <linux/platform_device.h>
diff --git a/drivers/pcmcia/pxa2xx_cm_x270.c b/drivers/pcmcia/pxa2xx_cm_x270.c
index f59223f2307d..36e35da5f887 100644
--- a/drivers/pcmcia/pxa2xx_cm_x270.c
+++ b/drivers/pcmcia/pxa2xx_cm_x270.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/pcmcia/pxa/pxa_cm_x270.c
*
- * 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.
- *
* Compulab Ltd., 2003, 2007, 2008
* Mike Rapoport <mike@compulab.co.il>
- *
*/
#include <linux/platform_device.h>
diff --git a/drivers/pcmcia/pxa2xx_cm_x2xx.c b/drivers/pcmcia/pxa2xx_cm_x2xx.c
index 6e7dcfd22ede..14eae238131d 100644
--- a/drivers/pcmcia/pxa2xx_cm_x2xx.c
+++ b/drivers/pcmcia/pxa2xx_cm_x2xx.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/pcmcia/pxa/pxa_cm_x2xx.c
*
- * 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.
- *
* Compulab Ltd., 2003, 2007, 2008
* Mike Rapoport <mike@compulab.co.il>
- *
*/
#include <linux/module.h>
diff --git a/drivers/pcmcia/pxa2xx_colibri.c b/drivers/pcmcia/pxa2xx_colibri.c
index 4dee7b2a8032..f0f725e99604 100644
--- a/drivers/pcmcia/pxa2xx_colibri.c
+++ b/drivers/pcmcia/pxa2xx_colibri.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/pcmcia/pxa2xx_colibri.c
*
* Driver for Toradex Colibri PXA270 CF socket
*
* Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com>
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/pcmcia/pxa2xx_e740.c b/drivers/pcmcia/pxa2xx_e740.c
index 8751a323b448..72caa6d05ab9 100644
--- a/drivers/pcmcia/pxa2xx_e740.c
+++ b/drivers/pcmcia/pxa2xx_e740.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Toshiba e740 PCMCIA specific routines.
*
* (c) 2004 Ian Molton <spyro@f2s.com>
- *
- * 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.
*/
#include <linux/init.h>
diff --git a/drivers/pcmcia/pxa2xx_hx4700.c b/drivers/pcmcia/pxa2xx_hx4700.c
index 7dfef3ee5b53..87b6a1639d94 100644
--- a/drivers/pcmcia/pxa2xx_hx4700.c
+++ b/drivers/pcmcia/pxa2xx_hx4700.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Paul Parsons <lost.distance@yahoo.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c
index 770c7bf0171d..a076e4108452 100644
--- a/drivers/pcmcia/pxa2xx_mainstone.c
+++ b/drivers/pcmcia/pxa2xx_mainstone.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/pcmcia/pxa2xx_mainstone.c
*
@@ -6,10 +7,6 @@
* Created: May 12, 2004
* Author: Nicolas Pitre
* Copyright: MontaVista Software 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.
*/
#include <linux/gpio/consumer.h>
#include <linux/module.h>
diff --git a/drivers/pcmcia/pxa2xx_palmld.c b/drivers/pcmcia/pxa2xx_palmld.c
index ed7d4dbc39fa..cfff41ac9ca2 100644
--- a/drivers/pcmcia/pxa2xx_palmld.c
+++ b/drivers/pcmcia/pxa2xx_palmld.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/pcmcia/pxa2xx_palmld.c
*
@@ -5,11 +6,6 @@
*
* Copyright (C) 2006 Alex Osborne <ato@meshy.org>
* Copyright (C) 2007-2011 Marek Vasut <marek.vasut@gmail.com>
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/pcmcia/pxa2xx_palmtc.c b/drivers/pcmcia/pxa2xx_palmtc.c
index 81225a7a8cbb..8fe05613ed04 100644
--- a/drivers/pcmcia/pxa2xx_palmtc.c
+++ b/drivers/pcmcia/pxa2xx_palmtc.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/pcmcia/pxa2xx_palmtc.c
*
@@ -5,11 +6,6 @@
*
* Copyright (C) 2008 Alex Osborne <ato@meshy.org>
* Copyright (C) 2009-2011 Marek Vasut <marek.vasut@gmail.com>
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/pcmcia/pxa2xx_palmtx.c b/drivers/pcmcia/pxa2xx_palmtx.c
index 069b6bbcf319..c449ca72cb87 100644
--- a/drivers/pcmcia/pxa2xx_palmtx.c
+++ b/drivers/pcmcia/pxa2xx_palmtx.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/pcmcia/pxa2xx_palmtx.c
*
* Driver for Palm T|X PCMCIA
*
* Copyright (C) 2007-2011 Marek Vasut <marek.vasut@gmail.com>
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c
index 89ebd8c76636..5fdd25a9e28e 100644
--- a/drivers/pcmcia/pxa2xx_sharpsl.c
+++ b/drivers/pcmcia/pxa2xx_sharpsl.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Sharp SL-C7xx Series PCMCIA routines
*
* Copyright (c) 2004-2005 Richard Purdie
*
* Based on Sharp's 2.4 kernel patches and pxa2xx_mainstone.c
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/pcmcia/pxa2xx_stargate2.c b/drivers/pcmcia/pxa2xx_stargate2.c
index 1d73c4401fdd..6efb7f814b4a 100644
--- a/drivers/pcmcia/pxa2xx_stargate2.c
+++ b/drivers/pcmcia/pxa2xx_stargate2.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/pcmcia/pxa2xx_stargate2.c
*
@@ -7,10 +8,6 @@
* Author: Ed C. Epp
* Copyright: Intel Corp 2005
* Jonathan Cameron <jic23@cam.ac.uk> 2009
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/pcmcia/pxa2xx_trizeps4.c b/drivers/pcmcia/pxa2xx_trizeps4.c
index d326ba1fa1ce..6db8fe880ed4 100644
--- a/drivers/pcmcia/pxa2xx_trizeps4.c
+++ b/drivers/pcmcia/pxa2xx_trizeps4.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/pcmcia/pxa2xx_trizeps4.c
*
@@ -6,10 +7,6 @@
* Author: Jürgen Schindele
* Created: 20 02, 2006
* Copyright: Jürgen Schindele
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/pcmcia/pxa2xx_vpac270.c b/drivers/pcmcia/pxa2xx_vpac270.c
index 33c5b8823367..3565add03a5e 100644
--- a/drivers/pcmcia/pxa2xx_vpac270.c
+++ b/drivers/pcmcia/pxa2xx_vpac270.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/pcmcia/pxa2xx_vpac270.c
*
* Driver for Voipac PXA270 PCMCIA and CF sockets
*
* Copyright (C) 2010-2011 Marek Vasut <marek.vasut@gmail.com>
- *
- * 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.
- *
*/
#include <linux/gpio.h>
diff --git a/drivers/pcmcia/rsrc_iodyn.c b/drivers/pcmcia/rsrc_iodyn.c
index f53c237bda2f..b04b16496b0c 100644
--- a/drivers/pcmcia/rsrc_iodyn.c
+++ b/drivers/pcmcia/rsrc_iodyn.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* rsrc_iodyn.c -- Resource management routines for MEM-static sockets.
*
- * 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.
- *
* The initial developer of the original code is David A. Hinds
* <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
* are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c
index df2cb70aef5b..252893216e50 100644
--- a/drivers/pcmcia/rsrc_mgr.c
+++ b/drivers/pcmcia/rsrc_mgr.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* rsrc_mgr.c -- Resource management routines and/or wrappers
*
- * 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.
- *
* The initial developer of the original code is David A. Hinds
* <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
* are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c
index 49377d502b74..9e6922c08ef6 100644
--- a/drivers/pcmcia/rsrc_nonstatic.c
+++ b/drivers/pcmcia/rsrc_nonstatic.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* rsrc_nonstatic.c -- Resource management routines for !SS_CAP_STATIC_MAP sockets
*
- * 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.
- *
* The initial developer of the original code is David A. Hinds
* <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
* are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
diff --git a/drivers/pcmcia/sa1111_badge4.c b/drivers/pcmcia/sa1111_badge4.c
index 93a5c7423d80..e76d5ba921dd 100644
--- a/drivers/pcmcia/sa1111_badge4.c
+++ b/drivers/pcmcia/sa1111_badge4.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/pcmcia/sa1100_badge4.c
*
@@ -6,11 +7,6 @@
* Christopher Hoover <ch@hpl.hp.com>
*
* Copyright (C) 2002 Hewlett-Packard Company
- *
- * 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.
- *
*/
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/drivers/pcmcia/sa1111_lubbock.c b/drivers/pcmcia/sa1111_lubbock.c
index e3fc14cfb42b..7feb8d61c639 100644
--- a/drivers/pcmcia/sa1111_lubbock.c
+++ b/drivers/pcmcia/sa1111_lubbock.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/pcmcia/pxa2xx_lubbock.c
*
@@ -5,14 +6,9 @@
* Created: Jan 10, 2002
* Copyright: MontaVista Software 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.
- *
* Originally based upon linux/drivers/pcmcia/sa1100_neponset.c
*
* Lubbock PCMCIA specific routines.
- *
*/
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c
index d6881514d38e..d1b220a1e1ab 100644
--- a/drivers/pcmcia/socket_sysfs.c
+++ b/drivers/pcmcia/socket_sysfs.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* socket_sysfs.c -- most of socket-related sysfs output
*
- * 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.
- *
* (C) 2003 - 2004 Dominik Brodowski
*/
diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig
index e4221a107dca..09ae8a970880 100644
--- a/drivers/perf/Kconfig
+++ b/drivers/perf/Kconfig
@@ -71,6 +71,14 @@ config ARM_DSU_PMU
system, control logic. The PMU allows counting various events related
to DSU.
+config FSL_IMX8_DDR_PMU
+ tristate "Freescale i.MX8 DDR perf monitor"
+ depends on ARCH_MXC
+ help
+ Provides support for the DDR performance monitor in i.MX8, which
+ can give information about memory throughput and other related
+ events.
+
config HISI_PMU
bool "HiSilicon SoC PMU"
depends on ARM64 && ACPI
diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile
index 30489941f3d6..2ebb4de17815 100644
--- a/drivers/perf/Makefile
+++ b/drivers/perf/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_ARM_DSU_PMU) += arm_dsu_pmu.o
obj-$(CONFIG_ARM_PMU) += arm_pmu.o arm_pmu_platform.o
obj-$(CONFIG_ARM_PMU_ACPI) += arm_pmu_acpi.o
obj-$(CONFIG_ARM_SMMU_V3_PMU) += arm_smmuv3_pmu.o
+obj-$(CONFIG_FSL_IMX8_DDR_PMU) += fsl_imx8_ddr_perf.o
obj-$(CONFIG_HISI_PMU) += hisilicon/
obj-$(CONFIG_QCOM_L2_PMU) += qcom_l2_pmu.o
obj-$(CONFIG_QCOM_L3_PMU) += qcom_l3_pmu.o
diff --git a/drivers/perf/arm_dsu_pmu.c b/drivers/perf/arm_dsu_pmu.c
index 5851de56bbd0..70968c8c09d7 100644
--- a/drivers/perf/arm_dsu_pmu.c
+++ b/drivers/perf/arm_dsu_pmu.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ARM DynamIQ Shared Unit (DSU) PMU driver
*
* Copyright (C) ARM Limited, 2017.
*
* Based on ARM CCI-PMU, ARMv8 PMU-v3 drivers.
- *
- * 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.
*/
#define PMUNAME "arm_dsu"
diff --git a/drivers/perf/arm_pmu_acpi.c b/drivers/perf/arm_pmu_acpi.c
index 0f197516d708..acce8781c456 100644
--- a/drivers/perf/arm_pmu_acpi.c
+++ b/drivers/perf/arm_pmu_acpi.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ACPI probing code for ARM performance counters.
*
* Copyright (C) 2017 ARM Ltd.
- *
- * 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.
*/
#include <linux/acpi.h>
@@ -74,6 +71,76 @@ static void arm_pmu_acpi_unregister_irq(int cpu)
acpi_unregister_gsi(gsi);
}
+#if IS_ENABLED(CONFIG_ARM_SPE_PMU)
+static struct resource spe_resources[] = {
+ {
+ /* irq */
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device spe_dev = {
+ .name = ARMV8_SPE_PDEV_NAME,
+ .id = -1,
+ .resource = spe_resources,
+ .num_resources = ARRAY_SIZE(spe_resources)
+};
+
+/*
+ * For lack of a better place, hook the normal PMU MADT walk
+ * and create a SPE device if we detect a recent MADT with
+ * a homogeneous PPI mapping.
+ */
+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;
+
+ 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;
+ }
+ }
+
+ 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;
+ }
+
+ 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);
+ }
+}
+#else
+static inline void arm_spe_acpi_register_device(void)
+{
+}
+#endif /* CONFIG_ARM_SPE_PMU */
+
static int arm_pmu_acpi_parse_irqs(void)
{
int irq, cpu, irq_cpu, err;
@@ -279,6 +346,8 @@ static int arm_pmu_acpi_init(void)
if (acpi_disabled)
return 0;
+ arm_spe_acpi_register_device();
+
ret = arm_pmu_acpi_parse_irqs();
if (ret)
return ret;
diff --git a/drivers/perf/arm_spe_pmu.c b/drivers/perf/arm_spe_pmu.c
index e120f933412a..4e4984a55cd1 100644
--- a/drivers/perf/arm_spe_pmu.c
+++ b/drivers/perf/arm_spe_pmu.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Perf support for the Statistical Profiling Extension, introduced as
* part of ARMv8.2.
*
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
* Copyright (C) 2016 ARM Limited
*
* Author: Will Deacon <will.deacon@arm.com>
@@ -38,6 +27,7 @@
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/perf_event.h>
+#include <linux/perf/arm_pmu.h>
#include <linux/platform_device.h>
#include <linux/printk.h>
#include <linux/slab.h>
@@ -1168,7 +1158,13 @@ static const struct of_device_id arm_spe_pmu_of_match[] = {
};
MODULE_DEVICE_TABLE(of, arm_spe_pmu_of_match);
-static int arm_spe_pmu_device_dt_probe(struct platform_device *pdev)
+static const struct platform_device_id arm_spe_match[] = {
+ { ARMV8_SPE_PDEV_NAME, 0},
+ { }
+};
+MODULE_DEVICE_TABLE(platform, arm_spe_match);
+
+static int arm_spe_pmu_device_probe(struct platform_device *pdev)
{
int ret;
struct arm_spe_pmu *spe_pmu;
@@ -1228,11 +1224,12 @@ static int arm_spe_pmu_device_remove(struct platform_device *pdev)
}
static struct platform_driver arm_spe_pmu_driver = {
+ .id_table = arm_spe_match,
.driver = {
.name = DRVNAME,
.of_match_table = of_match_ptr(arm_spe_pmu_of_match),
},
- .probe = arm_spe_pmu_device_dt_probe,
+ .probe = arm_spe_pmu_device_probe,
.remove = arm_spe_pmu_device_remove,
};
diff --git a/drivers/perf/fsl_imx8_ddr_perf.c b/drivers/perf/fsl_imx8_ddr_perf.c
new file mode 100644
index 000000000000..63fe21600072
--- /dev/null
+++ b/drivers/perf/fsl_imx8_ddr_perf.c
@@ -0,0 +1,554 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2017 NXP
+ * Copyright 2016 Freescale Semiconductor, Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#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/slab.h>
+
+#define COUNTER_CNTL 0x0
+#define COUNTER_READ 0x20
+
+#define COUNTER_DPCR1 0x30
+
+#define CNTL_OVER 0x1
+#define CNTL_CLEAR 0x2
+#define CNTL_EN 0x4
+#define CNTL_EN_MASK 0xFFFFFFFB
+#define CNTL_CLEAR_MASK 0xFFFFFFFD
+#define CNTL_OVER_MASK 0xFFFFFFFE
+
+#define CNTL_CSV_SHIFT 24
+#define CNTL_CSV_MASK (0xFF << CNTL_CSV_SHIFT)
+
+#define EVENT_CYCLES_ID 0
+#define EVENT_CYCLES_COUNTER 0
+#define NUM_COUNTERS 4
+
+#define to_ddr_pmu(p) container_of(p, struct ddr_pmu, pmu)
+
+#define DDR_PERF_DEV_NAME "imx8_ddr"
+#define DDR_CPUHP_CB_NAME DDR_PERF_DEV_NAME "_perf_pmu"
+
+static DEFINE_IDA(ddr_ida);
+
+static const struct of_device_id imx_ddr_pmu_dt_ids[] = {
+ { .compatible = "fsl,imx8-ddr-pmu",},
+ { .compatible = "fsl,imx8m-ddr-pmu",},
+ { /* sentinel */ }
+};
+
+struct ddr_pmu {
+ struct pmu pmu;
+ void __iomem *base;
+ unsigned int cpu;
+ struct hlist_node node;
+ struct device *dev;
+ struct perf_event *events[NUM_COUNTERS];
+ int active_events;
+ enum cpuhp_state cpuhp_state;
+ int irq;
+ int id;
+};
+
+static ssize_t ddr_perf_cpumask_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ddr_pmu *pmu = dev_get_drvdata(dev);
+
+ return cpumap_print_to_pagebuf(true, buf, cpumask_of(pmu->cpu));
+}
+
+static struct device_attribute ddr_perf_cpumask_attr =
+ __ATTR(cpumask, 0444, ddr_perf_cpumask_show, NULL);
+
+static struct attribute *ddr_perf_cpumask_attrs[] = {
+ &ddr_perf_cpumask_attr.attr,
+ NULL,
+};
+
+static struct attribute_group ddr_perf_cpumask_attr_group = {
+ .attrs = ddr_perf_cpumask_attrs,
+};
+
+static ssize_t
+ddr_pmu_event_show(struct device *dev, struct device_attribute *attr,
+ char *page)
+{
+ struct perf_pmu_events_attr *pmu_attr;
+
+ pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr);
+ return sprintf(page, "event=0x%02llx\n", pmu_attr->id);
+}
+
+#define IMX8_DDR_PMU_EVENT_ATTR(_name, _id) \
+ (&((struct perf_pmu_events_attr[]) { \
+ { .attr = __ATTR(_name, 0444, ddr_pmu_event_show, NULL),\
+ .id = _id, } \
+ })[0].attr.attr)
+
+static struct attribute *ddr_perf_events_attrs[] = {
+ IMX8_DDR_PMU_EVENT_ATTR(cycles, EVENT_CYCLES_ID),
+ IMX8_DDR_PMU_EVENT_ATTR(selfresh, 0x01),
+ IMX8_DDR_PMU_EVENT_ATTR(read-accesses, 0x04),
+ IMX8_DDR_PMU_EVENT_ATTR(write-accesses, 0x05),
+ IMX8_DDR_PMU_EVENT_ATTR(read-queue-depth, 0x08),
+ IMX8_DDR_PMU_EVENT_ATTR(write-queue-depth, 0x09),
+ IMX8_DDR_PMU_EVENT_ATTR(lp-read-credit-cnt, 0x10),
+ IMX8_DDR_PMU_EVENT_ATTR(hp-read-credit-cnt, 0x11),
+ IMX8_DDR_PMU_EVENT_ATTR(write-credit-cnt, 0x12),
+ IMX8_DDR_PMU_EVENT_ATTR(read-command, 0x20),
+ IMX8_DDR_PMU_EVENT_ATTR(write-command, 0x21),
+ IMX8_DDR_PMU_EVENT_ATTR(read-modify-write-command, 0x22),
+ IMX8_DDR_PMU_EVENT_ATTR(hp-read, 0x23),
+ IMX8_DDR_PMU_EVENT_ATTR(hp-req-nocredit, 0x24),
+ IMX8_DDR_PMU_EVENT_ATTR(hp-xact-credit, 0x25),
+ IMX8_DDR_PMU_EVENT_ATTR(lp-req-nocredit, 0x26),
+ IMX8_DDR_PMU_EVENT_ATTR(lp-xact-credit, 0x27),
+ IMX8_DDR_PMU_EVENT_ATTR(wr-xact-credit, 0x29),
+ IMX8_DDR_PMU_EVENT_ATTR(read-cycles, 0x2a),
+ IMX8_DDR_PMU_EVENT_ATTR(write-cycles, 0x2b),
+ IMX8_DDR_PMU_EVENT_ATTR(read-write-transition, 0x30),
+ IMX8_DDR_PMU_EVENT_ATTR(precharge, 0x31),
+ IMX8_DDR_PMU_EVENT_ATTR(activate, 0x32),
+ IMX8_DDR_PMU_EVENT_ATTR(load-mode, 0x33),
+ IMX8_DDR_PMU_EVENT_ATTR(perf-mwr, 0x34),
+ IMX8_DDR_PMU_EVENT_ATTR(read, 0x35),
+ IMX8_DDR_PMU_EVENT_ATTR(read-activate, 0x36),
+ IMX8_DDR_PMU_EVENT_ATTR(refresh, 0x37),
+ IMX8_DDR_PMU_EVENT_ATTR(write, 0x38),
+ IMX8_DDR_PMU_EVENT_ATTR(raw-hazard, 0x39),
+ NULL,
+};
+
+static struct attribute_group ddr_perf_events_attr_group = {
+ .name = "events",
+ .attrs = ddr_perf_events_attrs,
+};
+
+PMU_FORMAT_ATTR(event, "config:0-7");
+
+static struct attribute *ddr_perf_format_attrs[] = {
+ &format_attr_event.attr,
+ NULL,
+};
+
+static struct attribute_group ddr_perf_format_attr_group = {
+ .name = "format",
+ .attrs = ddr_perf_format_attrs,
+};
+
+static const struct attribute_group *attr_groups[] = {
+ &ddr_perf_events_attr_group,
+ &ddr_perf_format_attr_group,
+ &ddr_perf_cpumask_attr_group,
+ NULL,
+};
+
+static u32 ddr_perf_alloc_counter(struct ddr_pmu *pmu, int event)
+{
+ int i;
+
+ /*
+ * Always map cycle event to counter 0
+ * Cycles counter is dedicated for cycle event
+ * can't used for the other events
+ */
+ if (event == EVENT_CYCLES_ID) {
+ if (pmu->events[EVENT_CYCLES_COUNTER] == NULL)
+ return EVENT_CYCLES_COUNTER;
+ else
+ return -ENOENT;
+ }
+
+ for (i = 1; i < NUM_COUNTERS; i++) {
+ if (pmu->events[i] == NULL)
+ return i;
+ }
+
+ return -ENOENT;
+}
+
+static void ddr_perf_free_counter(struct ddr_pmu *pmu, int counter)
+{
+ pmu->events[counter] = NULL;
+}
+
+static u32 ddr_perf_read_counter(struct ddr_pmu *pmu, int counter)
+{
+ return readl_relaxed(pmu->base + COUNTER_READ + counter * 4);
+}
+
+static int ddr_perf_event_init(struct perf_event *event)
+{
+ struct ddr_pmu *pmu = to_ddr_pmu(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ struct perf_event *sibling;
+
+ if (event->attr.type != event->pmu->type)
+ return -ENOENT;
+
+ if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK)
+ return -EOPNOTSUPP;
+
+ if (event->cpu < 0) {
+ dev_warn(pmu->dev, "Can't provide per-task data!\n");
+ return -EOPNOTSUPP;
+ }
+
+ /*
+ * We must NOT create groups containing mixed PMUs, although software
+ * events are acceptable (for example to create a CCN group
+ * periodically read when a hrtimer aka cpu-clock leader triggers).
+ */
+ if (event->group_leader->pmu != event->pmu &&
+ !is_software_event(event->group_leader))
+ return -EINVAL;
+
+ for_each_sibling_event(sibling, event->group_leader) {
+ if (sibling->pmu != event->pmu &&
+ !is_software_event(sibling))
+ return -EINVAL;
+ }
+
+ event->cpu = pmu->cpu;
+ hwc->idx = -1;
+
+ return 0;
+}
+
+
+static void ddr_perf_event_update(struct perf_event *event)
+{
+ struct ddr_pmu *pmu = to_ddr_pmu(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ u64 delta, prev_raw_count, new_raw_count;
+ int counter = hwc->idx;
+
+ do {
+ prev_raw_count = local64_read(&hwc->prev_count);
+ new_raw_count = ddr_perf_read_counter(pmu, counter);
+ } while (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
+ new_raw_count) != prev_raw_count);
+
+ delta = (new_raw_count - prev_raw_count) & 0xFFFFFFFF;
+
+ local64_add(delta, &event->count);
+}
+
+static void ddr_perf_counter_enable(struct ddr_pmu *pmu, int config,
+ int counter, bool enable)
+{
+ u8 reg = counter * 4 + COUNTER_CNTL;
+ int val;
+
+ if (enable) {
+ /*
+ * must disable first, then enable again
+ * otherwise, cycle counter will not work
+ * if previous state is enabled.
+ */
+ writel(0, pmu->base + reg);
+ val = CNTL_EN | CNTL_CLEAR;
+ val |= FIELD_PREP(CNTL_CSV_MASK, config);
+ writel(val, pmu->base + reg);
+ } else {
+ /* Disable counter */
+ writel(0, pmu->base + reg);
+ }
+}
+
+static void ddr_perf_event_start(struct perf_event *event, int flags)
+{
+ struct ddr_pmu *pmu = to_ddr_pmu(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ int counter = hwc->idx;
+
+ local64_set(&hwc->prev_count, 0);
+
+ ddr_perf_counter_enable(pmu, event->attr.config, counter, true);
+
+ hwc->state = 0;
+}
+
+static int ddr_perf_event_add(struct perf_event *event, int flags)
+{
+ struct ddr_pmu *pmu = to_ddr_pmu(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ int counter;
+ int cfg = event->attr.config;
+
+ counter = ddr_perf_alloc_counter(pmu, cfg);
+ if (counter < 0) {
+ dev_dbg(pmu->dev, "There are not enough counters\n");
+ return -EOPNOTSUPP;
+ }
+
+ pmu->events[counter] = event;
+ pmu->active_events++;
+ hwc->idx = counter;
+
+ hwc->state |= PERF_HES_STOPPED;
+
+ if (flags & PERF_EF_START)
+ ddr_perf_event_start(event, flags);
+
+ return 0;
+}
+
+static void ddr_perf_event_stop(struct perf_event *event, int flags)
+{
+ struct ddr_pmu *pmu = to_ddr_pmu(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ int counter = hwc->idx;
+
+ ddr_perf_counter_enable(pmu, event->attr.config, counter, false);
+ ddr_perf_event_update(event);
+
+ hwc->state |= PERF_HES_STOPPED;
+}
+
+static void ddr_perf_event_del(struct perf_event *event, int flags)
+{
+ struct ddr_pmu *pmu = to_ddr_pmu(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ int counter = hwc->idx;
+
+ ddr_perf_event_stop(event, PERF_EF_UPDATE);
+
+ ddr_perf_free_counter(pmu, counter);
+ pmu->active_events--;
+ hwc->idx = -1;
+}
+
+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,
+ struct device *dev)
+{
+ *pmu = (struct ddr_pmu) {
+ .pmu = (struct pmu) {
+ .capabilities = PERF_PMU_CAP_NO_EXCLUDE,
+ .task_ctx_nr = perf_invalid_context,
+ .attr_groups = attr_groups,
+ .event_init = ddr_perf_event_init,
+ .add = ddr_perf_event_add,
+ .del = ddr_perf_event_del,
+ .start = ddr_perf_event_start,
+ .stop = ddr_perf_event_stop,
+ .read = ddr_perf_event_update,
+ .pmu_enable = ddr_perf_pmu_enable,
+ .pmu_disable = ddr_perf_pmu_disable,
+ },
+ .base = base,
+ .dev = dev,
+ };
+
+ pmu->id = ida_simple_get(&ddr_ida, 0, 0, GFP_KERNEL);
+ return pmu->id;
+}
+
+static irqreturn_t ddr_perf_irq_handler(int irq, void *p)
+{
+ int i;
+ struct ddr_pmu *pmu = (struct ddr_pmu *) p;
+ struct perf_event *event, *cycle_event = NULL;
+
+ /* all counter will stop if cycle counter disabled */
+ ddr_perf_counter_enable(pmu,
+ EVENT_CYCLES_ID,
+ EVENT_CYCLES_COUNTER,
+ false);
+ /*
+ * When the cycle counter overflows, all counters are stopped,
+ * and an IRQ is raised. If any other counter overflows, it
+ * continues counting, and no IRQ is raised.
+ *
+ * Cycles occur at least 4 times as often as other events, so we
+ * can update all events on a cycle counter overflow and not
+ * lose events.
+ *
+ */
+ for (i = 0; i < NUM_COUNTERS; i++) {
+
+ if (!pmu->events[i])
+ continue;
+
+ event = pmu->events[i];
+
+ ddr_perf_event_update(event);
+
+ if (event->hw.idx == EVENT_CYCLES_COUNTER)
+ cycle_event = event;
+ }
+
+ ddr_perf_counter_enable(pmu,
+ EVENT_CYCLES_ID,
+ EVENT_CYCLES_COUNTER,
+ true);
+ if (cycle_event)
+ ddr_perf_event_update(cycle_event);
+
+ return IRQ_HANDLED;
+}
+
+static int ddr_perf_offline_cpu(unsigned int cpu, struct hlist_node *node)
+{
+ struct ddr_pmu *pmu = hlist_entry_safe(node, struct ddr_pmu, node);
+ int target;
+
+ if (cpu != pmu->cpu)
+ return 0;
+
+ target = cpumask_any_but(cpu_online_mask, cpu);
+ if (target >= nr_cpu_ids)
+ return 0;
+
+ perf_pmu_migrate_context(&pmu->pmu, cpu, target);
+ pmu->cpu = target;
+
+ WARN_ON(irq_set_affinity_hint(pmu->irq, cpumask_of(pmu->cpu)));
+
+ return 0;
+}
+
+static int ddr_perf_probe(struct platform_device *pdev)
+{
+ struct ddr_pmu *pmu;
+ struct device_node *np;
+ void __iomem *base;
+ char *name;
+ int num;
+ int ret;
+ int irq;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ np = pdev->dev.of_node;
+
+ pmu = devm_kzalloc(&pdev->dev, sizeof(*pmu), GFP_KERNEL);
+ if (!pmu)
+ return -ENOMEM;
+
+ num = ddr_perf_init(pmu, base, &pdev->dev);
+
+ platform_set_drvdata(pdev, pmu);
+
+ name = devm_kasprintf(&pdev->dev, GFP_KERNEL, DDR_PERF_DEV_NAME "%d",
+ num);
+ if (!name)
+ return -ENOMEM;
+
+ pmu->cpu = raw_smp_processor_id();
+ ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN,
+ DDR_CPUHP_CB_NAME,
+ NULL,
+ ddr_perf_offline_cpu);
+
+ if (ret < 0) {
+ dev_err(&pdev->dev, "cpuhp_setup_state_multi failed\n");
+ goto ddr_perf_err;
+ }
+
+ pmu->cpuhp_state = ret;
+
+ /* Register the pmu instance for cpu hotplug */
+ cpuhp_state_add_instance_nocalls(pmu->cpuhp_state, &pmu->node);
+
+ /* Request irq */
+ irq = of_irq_get(np, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "Failed to get irq: %d", irq);
+ ret = irq;
+ goto ddr_perf_err;
+ }
+
+ ret = devm_request_irq(&pdev->dev, irq,
+ ddr_perf_irq_handler,
+ IRQF_NOBALANCING | IRQF_NO_THREAD,
+ DDR_CPUHP_CB_NAME,
+ pmu);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Request irq failed: %d", ret);
+ goto ddr_perf_err;
+ }
+
+ pmu->irq = irq;
+ ret = irq_set_affinity_hint(pmu->irq, cpumask_of(pmu->cpu));
+ if (ret) {
+ dev_err(pmu->dev, "Failed to set interrupt affinity!\n");
+ goto ddr_perf_err;
+ }
+
+ ret = perf_pmu_register(&pmu->pmu, name, -1);
+ if (ret)
+ goto ddr_perf_err;
+
+ return 0;
+
+ddr_perf_err:
+ if (pmu->cpuhp_state)
+ cpuhp_state_remove_instance_nocalls(pmu->cpuhp_state, &pmu->node);
+
+ ida_simple_remove(&ddr_ida, pmu->id);
+ dev_warn(&pdev->dev, "i.MX8 DDR Perf PMU failed (%d), disabled\n", ret);
+ return ret;
+}
+
+static int ddr_perf_remove(struct platform_device *pdev)
+{
+ struct ddr_pmu *pmu = platform_get_drvdata(pdev);
+
+ cpuhp_state_remove_instance_nocalls(pmu->cpuhp_state, &pmu->node);
+ irq_set_affinity_hint(pmu->irq, NULL);
+
+ perf_pmu_unregister(&pmu->pmu);
+
+ ida_simple_remove(&ddr_ida, pmu->id);
+ return 0;
+}
+
+static struct platform_driver imx_ddr_pmu_driver = {
+ .driver = {
+ .name = "imx-ddr-pmu",
+ .of_match_table = imx_ddr_pmu_dt_ids,
+ },
+ .probe = ddr_perf_probe,
+ .remove = ddr_perf_remove,
+};
+
+module_platform_driver(imx_ddr_pmu_driver);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
index 0eba947c2ee9..6ad0823bcf23 100644
--- a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* HiSilicon SoC DDRC uncore Hardware event counters support
*
@@ -6,10 +7,6 @@
* Anurup M <anurup.m@huawei.com>
*
* This code is based on the uncore PMUs like arm-cci and arm-ccn.
- *
- * 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.
*/
#include <linux/acpi.h>
#include <linux/bug.h>
diff --git a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
index 2553a844ebf6..4f2917f3e25e 100644
--- a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* HiSilicon SoC HHA uncore Hardware event counters support
*
@@ -6,10 +7,6 @@
* Anurup M <anurup.m@huawei.com>
*
* This code is based on the uncore PMUs like arm-cci and arm-ccn.
- *
- * 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.
*/
#include <linux/acpi.h>
#include <linux/bug.h>
diff --git a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
index cf1cc34f402a..9153e093f9df 100644
--- a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* HiSilicon SoC L3C uncore Hardware event counters support
*
@@ -6,10 +7,6 @@
* Shaokun Zhang <zhangshaokun@hisilicon.com>
*
* This code is based on the uncore PMUs like arm-cci and arm-ccn.
- *
- * 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.
*/
#include <linux/acpi.h>
#include <linux/bug.h>
diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pmu.c
index f028cbc3443c..79f76f8dda8e 100644
--- a/drivers/perf/hisilicon/hisi_uncore_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_pmu.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* HiSilicon SoC Hardware event counters support
*
@@ -6,10 +7,6 @@
* Shaokun Zhang <zhangshaokun@hisilicon.com>
*
* This code is based on the uncore PMUs like arm-cci and arm-ccn.
- *
- * 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.
*/
#include <linux/bitmap.h>
#include <linux/bitops.h>
diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.h b/drivers/perf/hisilicon/hisi_uncore_pmu.h
index f21226a0e9c6..25b0c97b3eb0 100644
--- a/drivers/perf/hisilicon/hisi_uncore_pmu.h
+++ b/drivers/perf/hisilicon/hisi_uncore_pmu.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* HiSilicon SoC Hardware event counters support
*
@@ -6,10 +7,6 @@
* Shaokun Zhang <zhangshaokun@hisilicon.com>
*
* This code is based on the uncore PMUs like arm-cci and arm-ccn.
- *
- * 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.
*/
#ifndef __HISI_UNCORE_PMU_H__
#define __HISI_UNCORE_PMU_H__
diff --git a/drivers/perf/qcom_l3_pmu.c b/drivers/perf/qcom_l3_pmu.c
index 15b8c10c2b2b..656e830798d9 100644
--- a/drivers/perf/qcom_l3_pmu.c
+++ b/drivers/perf/qcom_l3_pmu.c
@@ -8,7 +8,7 @@
* the slices. User space needs to aggregate to individual counts to provide
* a global picture.
*
- * See Documentation/perf/qcom_l3_pmu.txt for more details.
+ * See Documentation/admin-guide/perf/qcom_l3_pmu.rst for more details.
*
* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*/
diff --git a/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c b/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c
index 6233a7979a93..ac322d643c7a 100644
--- a/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c
+++ b/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c
@@ -188,7 +188,7 @@ static const struct regmap_config phy_g12a_usb3_pcie_cr_regmap_conf = {
.reg_read = phy_g12a_usb3_pcie_cr_bus_read,
.reg_write = phy_g12a_usb3_pcie_cr_bus_write,
.max_register = 0xffff,
- .fast_io = true,
+ .disable_locking = true,
};
static int phy_g12a_usb3_init(struct phy *phy)
diff --git a/drivers/phy/broadcom/phy-bcm-ns-usb2.c b/drivers/phy/broadcom/phy-bcm-ns-usb2.c
index 58dff80e9386..9f2f84d65dcd 100644
--- a/drivers/phy/broadcom/phy-bcm-ns-usb2.c
+++ b/drivers/phy/broadcom/phy-bcm-ns-usb2.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Broadcom Northstar USB 2.0 PHY Driver
*
* Copyright (C) 2016 Rafał Miłecki <zajec5@gmail.com>
- *
- * 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.
- *
*/
#include <linux/bcma/bcma.h>
diff --git a/drivers/phy/broadcom/phy-bcm-ns-usb3.c b/drivers/phy/broadcom/phy-bcm-ns-usb3.c
index a53ae128eadf..14f45bc35cc5 100644
--- a/drivers/phy/broadcom/phy-bcm-ns-usb3.c
+++ b/drivers/phy/broadcom/phy-bcm-ns-usb3.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Broadcom Northstar USB 3.0 PHY Driver
*
@@ -7,10 +8,6 @@
* All magic values used for initialization (and related comments) were obtained
* from Broadcom's SDK:
* Copyright (c) Broadcom Corp, 2012
- *
- * 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.
*/
#include <linux/bcma/bcma.h>
diff --git a/drivers/phy/broadcom/phy-brcm-usb.c b/drivers/phy/broadcom/phy-brcm-usb.c
index 7a6a6dd3fced..f5c1f2983a1d 100644
--- a/drivers/phy/broadcom/phy-brcm-usb.c
+++ b/drivers/phy/broadcom/phy-brcm-usb.c
@@ -368,6 +368,13 @@ static int brcm_usb_phy_probe(struct platform_device *pdev)
return PTR_ERR_OR_ZERO(phy_provider);
}
+static int brcm_usb_phy_remove(struct platform_device *pdev)
+{
+ sysfs_remove_group(&pdev->dev.kobj, &brcm_usb_phy_group);
+
+ return 0;
+}
+
#ifdef CONFIG_PM_SLEEP
static int brcm_usb_phy_suspend(struct device *dev)
{
@@ -433,9 +440,9 @@ MODULE_DEVICE_TABLE(of, brcm_usb_dt_ids);
static struct platform_driver brcm_usb_driver = {
.probe = brcm_usb_phy_probe,
+ .remove = brcm_usb_phy_remove,
.driver = {
.name = "brcmstb-usb-phy",
- .owner = THIS_MODULE,
.pm = &brcm_usb_phy_pm_ops,
.of_match_table = brcm_usb_dt_ids,
},
diff --git a/drivers/phy/freescale/Kconfig b/drivers/phy/freescale/Kconfig
index f435d6406943..320630ffe3cd 100644
--- a/drivers/phy/freescale/Kconfig
+++ b/drivers/phy/freescale/Kconfig
@@ -4,3 +4,13 @@ config PHY_FSL_IMX8MQ_USB
depends on OF && HAS_IOMEM
select GENERIC_PHY
default ARCH_MXC && ARM64
+
+config PHY_MIXEL_MIPI_DPHY
+ tristate "Mixel MIPI DSI PHY support"
+ depends on OF && HAS_IOMEM
+ select GENERIC_PHY
+ select GENERIC_PHY_MIPI_DPHY
+ select REGMAP_MMIO
+ help
+ Enable this to add support for the Mixel DSI PHY as found
+ on NXP's i.MX8 family of SOCs.
diff --git a/drivers/phy/freescale/Makefile b/drivers/phy/freescale/Makefile
index a459a44f6ecd..1d02e3869b45 100644
--- a/drivers/phy/freescale/Makefile
+++ b/drivers/phy/freescale/Makefile
@@ -1,2 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_PHY_FSL_IMX8MQ_USB) += phy-fsl-imx8mq-usb.o
+obj-$(CONFIG_PHY_MIXEL_MIPI_DPHY) += phy-fsl-imx8-mipi-dphy.o
diff --git a/drivers/phy/freescale/phy-fsl-imx8-mipi-dphy.c b/drivers/phy/freescale/phy-fsl-imx8-mipi-dphy.c
new file mode 100644
index 000000000000..9f2c1da14f5a
--- /dev/null
+++ b/drivers/phy/freescale/phy-fsl-imx8-mipi-dphy.c
@@ -0,0 +1,497 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2017,2018 NXP
+ * Copyright 2019 Purism SPC
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+/* DPHY registers */
+#define DPHY_PD_DPHY 0x00
+#define DPHY_M_PRG_HS_PREPARE 0x04
+#define DPHY_MC_PRG_HS_PREPARE 0x08
+#define DPHY_M_PRG_HS_ZERO 0x0c
+#define DPHY_MC_PRG_HS_ZERO 0x10
+#define DPHY_M_PRG_HS_TRAIL 0x14
+#define DPHY_MC_PRG_HS_TRAIL 0x18
+#define DPHY_PD_PLL 0x1c
+#define DPHY_TST 0x20
+#define DPHY_CN 0x24
+#define DPHY_CM 0x28
+#define DPHY_CO 0x2c
+#define DPHY_LOCK 0x30
+#define DPHY_LOCK_BYP 0x34
+#define DPHY_REG_BYPASS_PLL 0x4C
+
+#define MBPS(x) ((x) * 1000000)
+
+#define DATA_RATE_MAX_SPEED MBPS(1500)
+#define DATA_RATE_MIN_SPEED MBPS(80)
+
+#define PLL_LOCK_SLEEP 10
+#define PLL_LOCK_TIMEOUT 1000
+
+#define CN_BUF 0xcb7a89c0
+#define CO_BUF 0x63
+#define CM(x) ( \
+ ((x) < 32) ? 0xe0 | ((x) - 16) : \
+ ((x) < 64) ? 0xc0 | ((x) - 32) : \
+ ((x) < 128) ? 0x80 | ((x) - 64) : \
+ ((x) - 128))
+#define CN(x) (((x) == 1) ? 0x1f : (((CN_BUF) >> ((x) - 1)) & 0x1f))
+#define CO(x) ((CO_BUF) >> (8 - (x)) & 0x03)
+
+/* PHY power on is active low */
+#define PWR_ON 0
+#define PWR_OFF 1
+
+enum mixel_dphy_devtype {
+ MIXEL_IMX8MQ,
+};
+
+struct mixel_dphy_devdata {
+ u8 reg_tx_rcal;
+ u8 reg_auto_pd_en;
+ u8 reg_rxlprp;
+ u8 reg_rxcdrp;
+ u8 reg_rxhs_settle;
+};
+
+static const struct mixel_dphy_devdata mixel_dphy_devdata[] = {
+ [MIXEL_IMX8MQ] = {
+ .reg_tx_rcal = 0x38,
+ .reg_auto_pd_en = 0x3c,
+ .reg_rxlprp = 0x40,
+ .reg_rxcdrp = 0x44,
+ .reg_rxhs_settle = 0x48,
+ },
+};
+
+struct mixel_dphy_cfg {
+ /* DPHY PLL parameters */
+ u32 cm;
+ u32 cn;
+ u32 co;
+ /* DPHY register values */
+ u8 mc_prg_hs_prepare;
+ u8 m_prg_hs_prepare;
+ u8 mc_prg_hs_zero;
+ u8 m_prg_hs_zero;
+ u8 mc_prg_hs_trail;
+ u8 m_prg_hs_trail;
+ u8 rxhs_settle;
+};
+
+struct mixel_dphy_priv {
+ struct mixel_dphy_cfg cfg;
+ struct regmap *regmap;
+ struct clk *phy_ref_clk;
+ const struct mixel_dphy_devdata *devdata;
+};
+
+static const struct regmap_config mixel_dphy_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = DPHY_REG_BYPASS_PLL,
+ .name = "mipi-dphy",
+};
+
+static int phy_write(struct phy *phy, u32 value, unsigned int reg)
+{
+ struct mixel_dphy_priv *priv = phy_get_drvdata(phy);
+ int ret;
+
+ ret = regmap_write(priv->regmap, reg, value);
+ if (ret < 0)
+ dev_err(&phy->dev, "Failed to write DPHY reg %d: %d\n", reg,
+ ret);
+ return ret;
+}
+
+/*
+ * Find a ratio close to the desired one using continued fraction
+ * approximation ending either at exact match or maximum allowed
+ * nominator, denominator.
+ */
+static void get_best_ratio(u32 *pnum, u32 *pdenom, u32 max_n, u32 max_d)
+{
+ u32 a = *pnum;
+ u32 b = *pdenom;
+ u32 c;
+ u32 n[] = {0, 1};
+ u32 d[] = {1, 0};
+ u32 whole;
+ unsigned int i = 1;
+
+ while (b) {
+ i ^= 1;
+ whole = a / b;
+ n[i] += (n[i ^ 1] * whole);
+ d[i] += (d[i ^ 1] * whole);
+ if ((n[i] > max_n) || (d[i] > max_d)) {
+ i ^= 1;
+ break;
+ }
+ c = a - (b * whole);
+ a = b;
+ b = c;
+ }
+ *pnum = n[i];
+ *pdenom = d[i];
+}
+
+static int mixel_dphy_config_from_opts(struct phy *phy,
+ struct phy_configure_opts_mipi_dphy *dphy_opts,
+ struct mixel_dphy_cfg *cfg)
+{
+ struct mixel_dphy_priv *priv = dev_get_drvdata(phy->dev.parent);
+ unsigned long ref_clk = clk_get_rate(priv->phy_ref_clk);
+ u32 lp_t, numerator, denominator;
+ unsigned long long tmp;
+ u32 n;
+ int i;
+
+ if (dphy_opts->hs_clk_rate > DATA_RATE_MAX_SPEED ||
+ dphy_opts->hs_clk_rate < DATA_RATE_MIN_SPEED)
+ return -EINVAL;
+
+ numerator = dphy_opts->hs_clk_rate;
+ denominator = ref_clk;
+ get_best_ratio(&numerator, &denominator, 255, 256);
+ if (!numerator || !denominator) {
+ dev_err(&phy->dev, "Invalid %d/%d for %ld/%ld\n",
+ numerator, denominator,
+ dphy_opts->hs_clk_rate, ref_clk);
+ return -EINVAL;
+ }
+
+ while ((numerator < 16) && (denominator <= 128)) {
+ numerator <<= 1;
+ denominator <<= 1;
+ }
+ /*
+ * CM ranges between 16 and 255
+ * CN ranges between 1 and 32
+ * CO is power of 2: 1, 2, 4, 8
+ */
+ i = __ffs(denominator);
+ if (i > 3)
+ i = 3;
+ cfg->cn = denominator >> i;
+ cfg->co = 1 << i;
+ cfg->cm = numerator;
+
+ if (cfg->cm < 16 || cfg->cm > 255 ||
+ cfg->cn < 1 || cfg->cn > 32 ||
+ cfg->co < 1 || cfg->co > 8) {
+ dev_err(&phy->dev, "Invalid CM/CN/CO values: %u/%u/%u\n",
+ cfg->cm, cfg->cn, cfg->co);
+ dev_err(&phy->dev, "for hs_clk/ref_clk=%ld/%ld ~ %d/%d\n",
+ dphy_opts->hs_clk_rate, ref_clk,
+ numerator, denominator);
+ return -EINVAL;
+ }
+
+ dev_dbg(&phy->dev, "hs_clk/ref_clk=%ld/%ld ~ %d/%d\n",
+ dphy_opts->hs_clk_rate, ref_clk, numerator, denominator);
+
+ /* LP clock period */
+ tmp = 1000000000000LL;
+ do_div(tmp, dphy_opts->lp_clk_rate); /* ps */
+ if (tmp > ULONG_MAX)
+ return -EINVAL;
+
+ lp_t = tmp;
+ dev_dbg(&phy->dev, "LP clock %lu, period: %u ps\n",
+ dphy_opts->lp_clk_rate, lp_t);
+
+ /* hs_prepare: in lp clock periods */
+ if (2 * dphy_opts->hs_prepare > 5 * lp_t) {
+ dev_err(&phy->dev,
+ "hs_prepare (%u) > 2.5 * lp clock period (%u)\n",
+ dphy_opts->hs_prepare, lp_t);
+ return -EINVAL;
+ }
+ /* 00: lp_t, 01: 1.5 * lp_t, 10: 2 * lp_t, 11: 2.5 * lp_t */
+ if (dphy_opts->hs_prepare < lp_t) {
+ n = 0;
+ } else {
+ tmp = 2 * (dphy_opts->hs_prepare - lp_t);
+ do_div(tmp, lp_t);
+ n = tmp;
+ }
+ cfg->m_prg_hs_prepare = n;
+
+ /* clk_prepare: in lp clock periods */
+ if (2 * dphy_opts->clk_prepare > 3 * lp_t) {
+ dev_err(&phy->dev,
+ "clk_prepare (%u) > 1.5 * lp clock period (%u)\n",
+ dphy_opts->clk_prepare, lp_t);
+ return -EINVAL;
+ }
+ /* 00: lp_t, 01: 1.5 * lp_t */
+ cfg->mc_prg_hs_prepare = dphy_opts->clk_prepare > lp_t ? 1 : 0;
+
+ /* hs_zero: formula from NXP BSP */
+ n = (144 * (dphy_opts->hs_clk_rate / 1000000) - 47500) / 10000;
+ cfg->m_prg_hs_zero = n < 1 ? 1 : n;
+
+ /* clk_zero: formula from NXP BSP */
+ n = (34 * (dphy_opts->hs_clk_rate / 1000000) - 2500) / 1000;
+ cfg->mc_prg_hs_zero = n < 1 ? 1 : n;
+
+ /* clk_trail, hs_trail: formula from NXP BSP */
+ n = (103 * (dphy_opts->hs_clk_rate / 1000000) + 10000) / 10000;
+ if (n > 15)
+ n = 15;
+ if (n < 1)
+ n = 1;
+ cfg->m_prg_hs_trail = n;
+ cfg->mc_prg_hs_trail = n;
+
+ /* rxhs_settle: formula from NXP BSP */
+ if (dphy_opts->hs_clk_rate < MBPS(80))
+ cfg->rxhs_settle = 0x0d;
+ else if (dphy_opts->hs_clk_rate < MBPS(90))
+ cfg->rxhs_settle = 0x0c;
+ else if (dphy_opts->hs_clk_rate < MBPS(125))
+ cfg->rxhs_settle = 0x0b;
+ else if (dphy_opts->hs_clk_rate < MBPS(150))
+ cfg->rxhs_settle = 0x0a;
+ else if (dphy_opts->hs_clk_rate < MBPS(225))
+ cfg->rxhs_settle = 0x09;
+ else if (dphy_opts->hs_clk_rate < MBPS(500))
+ cfg->rxhs_settle = 0x08;
+ else
+ cfg->rxhs_settle = 0x07;
+
+ dev_dbg(&phy->dev, "phy_config: %u %u %u %u %u %u %u\n",
+ cfg->m_prg_hs_prepare, cfg->mc_prg_hs_prepare,
+ cfg->m_prg_hs_zero, cfg->mc_prg_hs_zero,
+ cfg->m_prg_hs_trail, cfg->mc_prg_hs_trail,
+ cfg->rxhs_settle);
+
+ return 0;
+}
+
+static void mixel_phy_set_hs_timings(struct phy *phy)
+{
+ struct mixel_dphy_priv *priv = phy_get_drvdata(phy);
+
+ phy_write(phy, priv->cfg.m_prg_hs_prepare, DPHY_M_PRG_HS_PREPARE);
+ phy_write(phy, priv->cfg.mc_prg_hs_prepare, DPHY_MC_PRG_HS_PREPARE);
+ phy_write(phy, priv->cfg.m_prg_hs_zero, DPHY_M_PRG_HS_ZERO);
+ phy_write(phy, priv->cfg.mc_prg_hs_zero, DPHY_MC_PRG_HS_ZERO);
+ phy_write(phy, priv->cfg.m_prg_hs_trail, DPHY_M_PRG_HS_TRAIL);
+ phy_write(phy, priv->cfg.mc_prg_hs_trail, DPHY_MC_PRG_HS_TRAIL);
+ phy_write(phy, priv->cfg.rxhs_settle, priv->devdata->reg_rxhs_settle);
+}
+
+static int mixel_dphy_set_pll_params(struct phy *phy)
+{
+ struct mixel_dphy_priv *priv = dev_get_drvdata(phy->dev.parent);
+
+ if (priv->cfg.cm < 16 || priv->cfg.cm > 255 ||
+ priv->cfg.cn < 1 || priv->cfg.cn > 32 ||
+ priv->cfg.co < 1 || priv->cfg.co > 8) {
+ dev_err(&phy->dev, "Invalid CM/CN/CO values! (%u/%u/%u)\n",
+ priv->cfg.cm, priv->cfg.cn, priv->cfg.co);
+ return -EINVAL;
+ }
+ dev_dbg(&phy->dev, "Using CM:%u CN:%u CO:%u\n",
+ priv->cfg.cm, priv->cfg.cn, priv->cfg.co);
+ phy_write(phy, CM(priv->cfg.cm), DPHY_CM);
+ phy_write(phy, CN(priv->cfg.cn), DPHY_CN);
+ phy_write(phy, CO(priv->cfg.co), DPHY_CO);
+ return 0;
+}
+
+static int mixel_dphy_configure(struct phy *phy, union phy_configure_opts *opts)
+{
+ struct mixel_dphy_priv *priv = phy_get_drvdata(phy);
+ struct mixel_dphy_cfg cfg = { 0 };
+ int ret;
+
+ ret = mixel_dphy_config_from_opts(phy, &opts->mipi_dphy, &cfg);
+ if (ret)
+ return ret;
+
+ /* Update the configuration */
+ memcpy(&priv->cfg, &cfg, sizeof(struct mixel_dphy_cfg));
+
+ phy_write(phy, 0x00, DPHY_LOCK_BYP);
+ phy_write(phy, 0x01, priv->devdata->reg_tx_rcal);
+ phy_write(phy, 0x00, priv->devdata->reg_auto_pd_en);
+ phy_write(phy, 0x02, priv->devdata->reg_rxlprp);
+ phy_write(phy, 0x02, priv->devdata->reg_rxcdrp);
+ phy_write(phy, 0x25, DPHY_TST);
+
+ mixel_phy_set_hs_timings(phy);
+ ret = mixel_dphy_set_pll_params(phy);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int mixel_dphy_validate(struct phy *phy, enum phy_mode mode, int submode,
+ union phy_configure_opts *opts)
+{
+ struct mixel_dphy_cfg cfg = { 0 };
+
+ if (mode != PHY_MODE_MIPI_DPHY)
+ return -EINVAL;
+
+ return mixel_dphy_config_from_opts(phy, &opts->mipi_dphy, &cfg);
+}
+
+static int mixel_dphy_init(struct phy *phy)
+{
+ phy_write(phy, PWR_OFF, DPHY_PD_PLL);
+ phy_write(phy, PWR_OFF, DPHY_PD_DPHY);
+
+ return 0;
+}
+
+static int mixel_dphy_exit(struct phy *phy)
+{
+ phy_write(phy, 0, DPHY_CM);
+ phy_write(phy, 0, DPHY_CN);
+ phy_write(phy, 0, DPHY_CO);
+
+ return 0;
+}
+
+static int mixel_dphy_power_on(struct phy *phy)
+{
+ struct mixel_dphy_priv *priv = phy_get_drvdata(phy);
+ u32 locked;
+ int ret;
+
+ ret = clk_prepare_enable(priv->phy_ref_clk);
+ if (ret < 0)
+ return ret;
+
+ phy_write(phy, PWR_ON, DPHY_PD_PLL);
+ ret = regmap_read_poll_timeout(priv->regmap, DPHY_LOCK, locked,
+ locked, PLL_LOCK_SLEEP,
+ PLL_LOCK_TIMEOUT);
+ if (ret < 0) {
+ dev_err(&phy->dev, "Could not get DPHY lock (%d)!\n", ret);
+ goto clock_disable;
+ }
+ phy_write(phy, PWR_ON, DPHY_PD_DPHY);
+
+ return 0;
+clock_disable:
+ clk_disable_unprepare(priv->phy_ref_clk);
+ return ret;
+}
+
+static int mixel_dphy_power_off(struct phy *phy)
+{
+ struct mixel_dphy_priv *priv = phy_get_drvdata(phy);
+
+ phy_write(phy, PWR_OFF, DPHY_PD_PLL);
+ phy_write(phy, PWR_OFF, DPHY_PD_DPHY);
+
+ clk_disable_unprepare(priv->phy_ref_clk);
+
+ return 0;
+}
+
+static const struct phy_ops mixel_dphy_phy_ops = {
+ .init = mixel_dphy_init,
+ .exit = mixel_dphy_exit,
+ .power_on = mixel_dphy_power_on,
+ .power_off = mixel_dphy_power_off,
+ .configure = mixel_dphy_configure,
+ .validate = mixel_dphy_validate,
+ .owner = THIS_MODULE,
+};
+
+static const struct of_device_id mixel_dphy_of_match[] = {
+ { .compatible = "fsl,imx8mq-mipi-dphy",
+ .data = &mixel_dphy_devdata[MIXEL_IMX8MQ] },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, mixel_dphy_of_match);
+
+static int mixel_dphy_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct phy_provider *phy_provider;
+ struct mixel_dphy_priv *priv;
+ struct resource *res;
+ struct phy *phy;
+ void __iomem *base;
+
+ if (!np)
+ return -ENODEV;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->devdata = of_device_get_match_data(&pdev->dev);
+ if (!priv->devdata)
+ return -EINVAL;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ priv->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+ &mixel_dphy_regmap_config);
+ if (IS_ERR(priv->regmap)) {
+ dev_err(dev, "Couldn't create the DPHY regmap\n");
+ return PTR_ERR(priv->regmap);
+ }
+
+ priv->phy_ref_clk = devm_clk_get(&pdev->dev, "phy_ref");
+ if (IS_ERR(priv->phy_ref_clk)) {
+ dev_err(dev, "No phy_ref clock found\n");
+ return PTR_ERR(priv->phy_ref_clk);
+ }
+ dev_dbg(dev, "phy_ref clock rate: %lu\n",
+ clk_get_rate(priv->phy_ref_clk));
+
+ dev_set_drvdata(dev, priv);
+
+ phy = devm_phy_create(dev, np, &mixel_dphy_phy_ops);
+ if (IS_ERR(phy)) {
+ dev_err(dev, "Failed to create phy %ld\n", PTR_ERR(phy));
+ return PTR_ERR(phy);
+ }
+ phy_set_drvdata(phy, priv);
+
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static struct platform_driver mixel_dphy_driver = {
+ .probe = mixel_dphy_probe,
+ .driver = {
+ .name = "mixel-mipi-dphy",
+ .of_match_table = mixel_dphy_of_match,
+ }
+};
+module_platform_driver(mixel_dphy_driver);
+
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_DESCRIPTION("Mixel MIPI-DSI PHY driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/phy/hisilicon/phy-histb-combphy.c b/drivers/phy/hisilicon/phy-histb-combphy.c
index 5777b3120017..62d10ef20296 100644
--- a/drivers/phy/hisilicon/phy-histb-combphy.c
+++ b/drivers/phy/hisilicon/phy-histb-combphy.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* COMBPHY driver for HiSilicon STB SoCs
*
* Copyright (C) 2016-2017 HiSilicon Co., Ltd. http://www.hisilicon.com
*
* Authors: Jianguo Sun <sunjianguo1@huawei.com>
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/phy/lantiq/phy-lantiq-rcu-usb2.c b/drivers/phy/lantiq/phy-lantiq-rcu-usb2.c
index f9e0dd19ff26..be09b1530ae6 100644
--- a/drivers/phy/lantiq/phy-lantiq-rcu-usb2.c
+++ b/drivers/phy/lantiq/phy-lantiq-rcu-usb2.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Lantiq XWAY SoC RCU module based USB 1.1/2.0 PHY driver
*
* Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
* Copyright (C) 2017 Hauke Mehrtens <hauke@hauke-m.de>
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/phy/phy-lpc18xx-usb-otg.c b/drivers/phy/phy-lpc18xx-usb-otg.c
index 7de280a45421..f905d3c64584 100644
--- a/drivers/phy/phy-lpc18xx-usb-otg.c
+++ b/drivers/phy/phy-lpc18xx-usb-otg.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* PHY driver for NXP LPC18xx/43xx internal USB OTG PHY
*
* Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
- *
- * 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.
- *
*/
#include <linux/clk.h>
diff --git a/drivers/phy/qualcomm/Kconfig b/drivers/phy/qualcomm/Kconfig
index eb49864a6bad..e46824da29f6 100644
--- a/drivers/phy/qualcomm/Kconfig
+++ b/drivers/phy/qualcomm/Kconfig
@@ -25,6 +25,14 @@ config PHY_QCOM_IPQ806X_SATA
depends on OF
select GENERIC_PHY
+config PHY_QCOM_PCIE2
+ tristate "Qualcomm PCIe Gen2 PHY Driver"
+ depends on OF && COMMON_CLK && (ARCH_QCOM || COMPILE_TEST)
+ select GENERIC_PHY
+ help
+ Enable this to support the Qualcomm PCIe PHY, used with the Synopsys
+ based PCIe controller.
+
config PHY_QCOM_QMP
tristate "Qualcomm QMP PHY Driver"
depends on OF && COMMON_CLK && (ARCH_QCOM || COMPILE_TEST)
diff --git a/drivers/phy/qualcomm/Makefile b/drivers/phy/qualcomm/Makefile
index c56efd3af205..283251d6a5d9 100644
--- a/drivers/phy/qualcomm/Makefile
+++ b/drivers/phy/qualcomm/Makefile
@@ -2,6 +2,7 @@
obj-$(CONFIG_PHY_ATH79_USB) += phy-ath79-usb.o
obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) += phy-qcom-apq8064-sata.o
obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o
+obj-$(CONFIG_PHY_QCOM_PCIE2) += phy-qcom-pcie2.o
obj-$(CONFIG_PHY_QCOM_QMP) += phy-qcom-qmp.o
obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o
diff --git a/drivers/phy/qualcomm/phy-qcom-pcie2.c b/drivers/phy/qualcomm/phy-qcom-pcie2.c
new file mode 100644
index 000000000000..9dba3594e6d9
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-pcie2.c
@@ -0,0 +1,331 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2019, Linaro Ltd.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/phy/phy.h>
+
+#define PCIE20_PARF_PHY_STTS 0x3c
+#define PCIE2_PHY_RESET_CTRL 0x44
+#define PCIE20_PARF_PHY_REFCLK_CTRL2 0xa0
+#define PCIE20_PARF_PHY_REFCLK_CTRL3 0xa4
+#define PCIE20_PARF_PCS_SWING_CTRL1 0x88
+#define PCIE20_PARF_PCS_SWING_CTRL2 0x8c
+#define PCIE20_PARF_PCS_DEEMPH1 0x74
+#define PCIE20_PARF_PCS_DEEMPH2 0x78
+#define PCIE20_PARF_PCS_DEEMPH3 0x7c
+#define PCIE20_PARF_CONFIGBITS 0x84
+#define PCIE20_PARF_PHY_CTRL3 0x94
+#define PCIE20_PARF_PCS_CTRL 0x80
+
+#define TX_AMP_VAL 120
+#define PHY_RX0_EQ_GEN1_VAL 0
+#define PHY_RX0_EQ_GEN2_VAL 4
+#define TX_DEEMPH_GEN1_VAL 24
+#define TX_DEEMPH_GEN2_3_5DB_VAL 26
+#define TX_DEEMPH_GEN2_6DB_VAL 36
+#define PHY_TX0_TERM_OFFST_VAL 0
+
+struct qcom_phy {
+ struct device *dev;
+ void __iomem *base;
+
+ struct regulator_bulk_data vregs[2];
+
+ struct reset_control *phy_reset;
+ struct reset_control *pipe_reset;
+ struct clk *pipe_clk;
+};
+
+static int qcom_pcie2_phy_init(struct phy *phy)
+{
+ struct qcom_phy *qphy = phy_get_drvdata(phy);
+ int ret;
+
+ ret = reset_control_deassert(qphy->phy_reset);
+ if (ret) {
+ dev_err(qphy->dev, "cannot deassert pipe reset\n");
+ return ret;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(qphy->vregs), qphy->vregs);
+ if (ret)
+ reset_control_assert(qphy->phy_reset);
+
+ return ret;
+}
+
+static int qcom_pcie2_phy_power_on(struct phy *phy)
+{
+ struct qcom_phy *qphy = phy_get_drvdata(phy);
+ int ret;
+ u32 val;
+
+ /* Program REF_CLK source */
+ val = readl(qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL2);
+ val &= ~BIT(1);
+ writel(val, qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL2);
+
+ usleep_range(1000, 2000);
+
+ /* Don't use PAD for refclock */
+ val = readl(qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL2);
+ val &= ~BIT(0);
+ writel(val, qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL2);
+
+ /* Program SSP ENABLE */
+ val = readl(qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL3);
+ val |= BIT(0);
+ writel(val, qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL3);
+
+ usleep_range(1000, 2000);
+
+ /* Assert Phy SW Reset */
+ val = readl(qphy->base + PCIE2_PHY_RESET_CTRL);
+ val |= BIT(0);
+ writel(val, qphy->base + PCIE2_PHY_RESET_CTRL);
+
+ /* Program Tx Amplitude */
+ val = readl(qphy->base + PCIE20_PARF_PCS_SWING_CTRL1);
+ val &= ~0x7f;
+ val |= TX_AMP_VAL;
+ writel(val, qphy->base + PCIE20_PARF_PCS_SWING_CTRL1);
+
+ val = readl(qphy->base + PCIE20_PARF_PCS_SWING_CTRL2);
+ val &= ~0x7f;
+ val |= TX_AMP_VAL;
+ writel(val, qphy->base + PCIE20_PARF_PCS_SWING_CTRL2);
+
+ /* Program De-Emphasis */
+ val = readl(qphy->base + PCIE20_PARF_PCS_DEEMPH1);
+ val &= ~0x3f;
+ val |= TX_DEEMPH_GEN2_6DB_VAL;
+ writel(val, qphy->base + PCIE20_PARF_PCS_DEEMPH1);
+
+ val = readl(qphy->base + PCIE20_PARF_PCS_DEEMPH2);
+ val &= ~0x3f;
+ val |= TX_DEEMPH_GEN2_3_5DB_VAL;
+ writel(val, qphy->base + PCIE20_PARF_PCS_DEEMPH2);
+
+ val = readl(qphy->base + PCIE20_PARF_PCS_DEEMPH3);
+ val &= ~0x3f;
+ val |= TX_DEEMPH_GEN1_VAL;
+ writel(val, qphy->base + PCIE20_PARF_PCS_DEEMPH3);
+
+ /* Program Rx_Eq */
+ val = readl(qphy->base + PCIE20_PARF_CONFIGBITS);
+ val &= ~0x7;
+ val |= PHY_RX0_EQ_GEN2_VAL;
+ writel(val, qphy->base + PCIE20_PARF_CONFIGBITS);
+
+ /* Program Tx0_term_offset */
+ val = readl(qphy->base + PCIE20_PARF_PHY_CTRL3);
+ val &= ~0x1f;
+ val |= PHY_TX0_TERM_OFFST_VAL;
+ writel(val, qphy->base + PCIE20_PARF_PHY_CTRL3);
+
+ /* disable Tx2Rx Loopback */
+ val = readl(qphy->base + PCIE20_PARF_PCS_CTRL);
+ val &= ~BIT(1);
+ writel(val, qphy->base + PCIE20_PARF_PCS_CTRL);
+
+ /* De-assert Phy SW Reset */
+ val = readl(qphy->base + PCIE2_PHY_RESET_CTRL);
+ val &= ~BIT(0);
+ writel(val, qphy->base + PCIE2_PHY_RESET_CTRL);
+
+ usleep_range(1000, 2000);
+
+ ret = reset_control_deassert(qphy->pipe_reset);
+ if (ret) {
+ dev_err(qphy->dev, "cannot deassert pipe reset\n");
+ goto out;
+ }
+
+ clk_set_rate(qphy->pipe_clk, 250000000);
+
+ ret = clk_prepare_enable(qphy->pipe_clk);
+ if (ret) {
+ dev_err(qphy->dev, "failed to enable pipe clock\n");
+ goto out;
+ }
+
+ ret = readl_poll_timeout(qphy->base + PCIE20_PARF_PHY_STTS, val,
+ !(val & BIT(0)), 1000, 10);
+ if (ret)
+ dev_err(qphy->dev, "phy initialization failed\n");
+
+out:
+ return ret;
+}
+
+static int qcom_pcie2_phy_power_off(struct phy *phy)
+{
+ struct qcom_phy *qphy = phy_get_drvdata(phy);
+ u32 val;
+
+ val = readl(qphy->base + PCIE2_PHY_RESET_CTRL);
+ val |= BIT(0);
+ writel(val, qphy->base + PCIE2_PHY_RESET_CTRL);
+
+ clk_disable_unprepare(qphy->pipe_clk);
+ reset_control_assert(qphy->pipe_reset);
+
+ return 0;
+}
+
+static int qcom_pcie2_phy_exit(struct phy *phy)
+{
+ struct qcom_phy *qphy = phy_get_drvdata(phy);
+
+ regulator_bulk_disable(ARRAY_SIZE(qphy->vregs), qphy->vregs);
+ reset_control_assert(qphy->phy_reset);
+
+ return 0;
+}
+
+static const struct phy_ops qcom_pcie2_ops = {
+ .init = qcom_pcie2_phy_init,
+ .power_on = qcom_pcie2_phy_power_on,
+ .power_off = qcom_pcie2_phy_power_off,
+ .exit = qcom_pcie2_phy_exit,
+ .owner = THIS_MODULE,
+};
+
+/*
+ * Register a fixed rate pipe clock.
+ *
+ * The <s>_pipe_clksrc generated by PHY goes to the GCC that gate
+ * controls it. The <s>_pipe_clk coming out of the GCC is requested
+ * by the PHY driver for its operations.
+ * We register the <s>_pipe_clksrc here. The gcc driver takes care
+ * of assigning this <s>_pipe_clksrc as parent to <s>_pipe_clk.
+ * Below picture shows this relationship.
+ *
+ * +---------------+
+ * | PHY block |<<---------------------------------------+
+ * | | |
+ * | +-------+ | +-----+ |
+ * I/P---^-->| PLL |---^--->pipe_clksrc--->| GCC |--->pipe_clk---+
+ * clk | +-------+ | +-----+
+ * +---------------+
+ */
+static int phy_pipe_clksrc_register(struct qcom_phy *qphy)
+{
+ struct device_node *np = qphy->dev->of_node;
+ struct clk_fixed_rate *fixed;
+ struct clk_init_data init = { };
+ int ret;
+
+ ret = of_property_read_string(np, "clock-output-names", &init.name);
+ if (ret) {
+ dev_err(qphy->dev, "%s: No clock-output-names\n", np->name);
+ return ret;
+ }
+
+ fixed = devm_kzalloc(qphy->dev, sizeof(*fixed), GFP_KERNEL);
+ if (!fixed)
+ return -ENOMEM;
+
+ init.ops = &clk_fixed_rate_ops;
+
+ /* controllers using QMP phys use 250MHz pipe clock interface */
+ fixed->fixed_rate = 250000000;
+ fixed->hw.init = &init;
+
+ return devm_clk_hw_register(qphy->dev, &fixed->hw);
+}
+
+static int qcom_pcie2_phy_probe(struct platform_device *pdev)
+{
+ struct phy_provider *phy_provider;
+ struct qcom_phy *qphy;
+ struct resource *res;
+ struct device *dev = &pdev->dev;
+ struct phy *phy;
+ int ret;
+
+ qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL);
+ if (!qphy)
+ return -ENOMEM;
+
+ qphy->dev = dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ qphy->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(qphy->base))
+ return PTR_ERR(qphy->base);
+
+ ret = phy_pipe_clksrc_register(qphy);
+ if (ret) {
+ dev_err(dev, "failed to register pipe_clk\n");
+ return ret;
+ }
+
+ qphy->vregs[0].supply = "vdda-vp";
+ qphy->vregs[1].supply = "vdda-vph";
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(qphy->vregs), qphy->vregs);
+ if (ret < 0)
+ return ret;
+
+ qphy->pipe_clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(qphy->pipe_clk)) {
+ dev_err(dev, "failed to acquire pipe clock\n");
+ return PTR_ERR(qphy->pipe_clk);
+ }
+
+ qphy->phy_reset = devm_reset_control_get_exclusive(dev, "phy");
+ if (IS_ERR(qphy->phy_reset)) {
+ dev_err(dev, "failed to acquire phy reset\n");
+ return PTR_ERR(qphy->phy_reset);
+ }
+
+ qphy->pipe_reset = devm_reset_control_get_exclusive(dev, "pipe");
+ if (IS_ERR(qphy->pipe_reset)) {
+ dev_err(dev, "failed to acquire pipe reset\n");
+ return PTR_ERR(qphy->pipe_reset);
+ }
+
+ phy = devm_phy_create(dev, dev->of_node, &qcom_pcie2_ops);
+ if (IS_ERR(phy)) {
+ dev_err(dev, "failed to create phy\n");
+ return PTR_ERR(phy);
+ }
+
+ phy_set_drvdata(phy, qphy);
+
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+ if (IS_ERR(phy_provider))
+ dev_err(dev, "failed to register phy provider\n");
+
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct of_device_id qcom_pcie2_phy_match_table[] = {
+ { .compatible = "qcom,pcie2-phy" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, qcom_pcie2_phy_match_table);
+
+static struct platform_driver qcom_pcie2_phy_driver = {
+ .probe = qcom_pcie2_phy_probe,
+ .driver = {
+ .name = "phy-qcom-pcie2",
+ .of_match_table = qcom_pcie2_phy_match_table,
+ },
+};
+
+module_platform_driver(qcom_pcie2_phy_driver);
+
+MODULE_DESCRIPTION("Qualcomm PCIe PHY driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c
index cd91b4179b10..34ff6434da8f 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -1074,6 +1074,7 @@ static const struct qmp_phy_cfg msm8996_pciephy_cfg = {
.start_ctrl = PCS_START | PLL_READY_GATE_EN,
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
+ .mask_pcs_ready = PHYSTATUS,
.mask_com_pcs_ready = PCS_READY,
.has_phy_com_ctrl = true,
@@ -1253,7 +1254,7 @@ static const struct qmp_phy_cfg msm8998_pciephy_cfg = {
.start_ctrl = SERDES_START | PCS_START,
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
- .mask_com_pcs_ready = PCS_READY,
+ .mask_pcs_ready = PHYSTATUS,
};
static const struct qmp_phy_cfg msm8998_usb3phy_cfg = {
@@ -1547,7 +1548,7 @@ static int qcom_qmp_phy_enable(struct phy *phy)
status = pcs + cfg->regs[QPHY_PCS_READY_STATUS];
mask = cfg->mask_pcs_ready;
- ret = readl_poll_timeout(status, val, !(val & mask), 1,
+ ret = readl_poll_timeout(status, val, val & mask, 10,
PHY_INIT_COMPLETE_TIMEOUT);
if (ret) {
dev_err(qmp->dev, "phy initialization timed-out\n");
diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c b/drivers/phy/qualcomm/phy-qcom-qusb2.c
index 1cbf1d6f28ce..bf94a52d3087 100644
--- a/drivers/phy/qualcomm/phy-qcom-qusb2.c
+++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c
@@ -564,7 +564,7 @@ static int __maybe_unused qusb2_phy_runtime_resume(struct device *dev)
}
if (!qphy->has_se_clk_scheme) {
- clk_prepare_enable(qphy->ref_clk);
+ ret = clk_prepare_enable(qphy->ref_clk);
if (ret) {
dev_err(dev, "failed to enable ref clk, %d\n", ret);
goto disable_ahb_clk;
diff --git a/drivers/phy/qualcomm/phy-qcom-usb-hs.c b/drivers/phy/qualcomm/phy-qcom-usb-hs.c
index 04934f8dac91..b163b3a1558d 100644
--- a/drivers/phy/qualcomm/phy-qcom-usb-hs.c
+++ b/drivers/phy/qualcomm/phy-qcom-usb-hs.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/**
* Copyright (C) 2016 Linaro Ltd
- *
- * 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.
*/
#include <linux/module.h>
#include <linux/ulpi/driver.h>
diff --git a/drivers/phy/qualcomm/phy-qcom-usb-hsic.c b/drivers/phy/qualcomm/phy-qcom-usb-hsic.c
index c110563a73cb..04d18d52f700 100644
--- a/drivers/phy/qualcomm/phy-qcom-usb-hsic.c
+++ b/drivers/phy/qualcomm/phy-qcom-usb-hsic.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/**
* Copyright (C) 2016 Linaro Ltd
- *
- * 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.
*/
#include <linux/module.h>
#include <linux/ulpi/driver.h>
diff --git a/drivers/phy/renesas/phy-rcar-gen2.c b/drivers/phy/renesas/phy-rcar-gen2.c
index 8dc5710d9c98..2926e4937301 100644
--- a/drivers/phy/renesas/phy-rcar-gen2.c
+++ b/drivers/phy/renesas/phy-rcar-gen2.c
@@ -391,6 +391,7 @@ static int rcar_gen2_phy_probe(struct platform_device *pdev)
error = of_property_read_u32(np, "reg", &channel_num);
if (error || channel_num > 2) {
dev_err(dev, "Invalid \"reg\" property\n");
+ of_node_put(np);
return error;
}
channel->select_mask = select_mask[channel_num];
@@ -406,6 +407,7 @@ static int rcar_gen2_phy_probe(struct platform_device *pdev)
data->gen2_phy_ops);
if (IS_ERR(phy->phy)) {
dev_err(dev, "Failed to create PHY\n");
+ of_node_put(np);
return PTR_ERR(phy->phy);
}
phy_set_drvdata(phy->phy, phy);
diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
index 1322185a00a2..8ffba67568ec 100644
--- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c
+++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
@@ -13,6 +13,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
@@ -106,6 +107,7 @@ struct rcar_gen3_chan {
struct rcar_gen3_phy rphys[NUM_OF_PHYS];
struct regulator *vbus;
struct work_struct work;
+ struct mutex lock; /* protects rphys[...].powered */
enum usb_dr_mode dr_mode;
bool extcon_host;
bool is_otg_channel;
@@ -437,15 +439,16 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p)
struct rcar_gen3_chan *channel = rphy->ch;
void __iomem *usb2_base = channel->base;
u32 val;
- int ret;
+ int ret = 0;
+ mutex_lock(&channel->lock);
if (!rcar_gen3_are_all_rphys_power_off(channel))
- return 0;
+ goto out;
if (channel->vbus) {
ret = regulator_enable(channel->vbus);
if (ret)
- return ret;
+ goto out;
}
val = readl(usb2_base + USB2_USBCTR);
@@ -454,7 +457,10 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p)
val &= ~USB2_USBCTR_PLL_RST;
writel(val, usb2_base + USB2_USBCTR);
+out:
+ /* The powered flag should be set for any other phys anyway */
rphy->powered = true;
+ mutex_unlock(&channel->lock);
return 0;
}
@@ -465,14 +471,18 @@ static int rcar_gen3_phy_usb2_power_off(struct phy *p)
struct rcar_gen3_chan *channel = rphy->ch;
int ret = 0;
+ mutex_lock(&channel->lock);
rphy->powered = false;
if (!rcar_gen3_are_all_rphys_power_off(channel))
- return 0;
+ goto out;
if (channel->vbus)
ret = regulator_disable(channel->vbus);
+out:
+ mutex_unlock(&channel->lock);
+
return ret;
}
@@ -639,6 +649,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
if (!phy_usb2_ops)
return -EINVAL;
+ mutex_init(&channel->lock);
for (i = 0; i < NUM_OF_PHYS; i++) {
channel->rphys[i].phy = devm_phy_create(dev, NULL,
phy_usb2_ops);
diff --git a/drivers/phy/rockchip/phy-rockchip-emmc.c b/drivers/phy/rockchip/phy-rockchip-emmc.c
index b804c6bf4b55..2dc19ddd120f 100644
--- a/drivers/phy/rockchip/phy-rockchip-emmc.c
+++ b/drivers/phy/rockchip/phy-rockchip-emmc.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Rockchip emmc PHY driver
*
* Copyright (C) 2016 Shawn Lin <shawn.lin@rock-chips.com>
* Copyright (C) 2016 ROCKCHIP, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/clk.h>
diff --git a/drivers/phy/rockchip/phy-rockchip-pcie.c b/drivers/phy/rockchip/phy-rockchip-pcie.c
index 7cbdde029c0a..75216091d901 100644
--- a/drivers/phy/rockchip/phy-rockchip-pcie.c
+++ b/drivers/phy/rockchip/phy-rockchip-pcie.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Rockchip PCIe PHY driver
*
* Copyright (C) 2016 Shawn Lin <shawn.lin@rock-chips.com>
* Copyright (C) 2016 ROCKCHIP, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/clk.h>
diff --git a/drivers/phy/rockchip/phy-rockchip-usb.c b/drivers/phy/rockchip/phy-rockchip-usb.c
index b2899c744ad9..8454285977eb 100644
--- a/drivers/phy/rockchip/phy-rockchip-usb.c
+++ b/drivers/phy/rockchip/phy-rockchip-usb.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Rockchip usb PHY driver
*
* Copyright (C) 2014 Yunzhi Li <lyz@rock-chips.com>
* Copyright (C) 2014 ROCKCHIP, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/clk.h>
diff --git a/drivers/phy/samsung/phy-exynos-dp-video.c b/drivers/phy/samsung/phy-exynos-dp-video.c
index 2dd6dd1f37a8..aebd216dcf2f 100644
--- a/drivers/phy/samsung/phy-exynos-dp-video.c
+++ b/drivers/phy/samsung/phy-exynos-dp-video.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Samsung EXYNOS SoC series Display Port PHY driver
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* Author: Jingoo Han <jg1.han@samsung.com>
- *
- * 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.
*/
#include <linux/err.h>
diff --git a/drivers/phy/samsung/phy-exynos-mipi-video.c b/drivers/phy/samsung/phy-exynos-mipi-video.c
index 00d89599c67d..3784bf100b95 100644
--- a/drivers/phy/samsung/phy-exynos-mipi-video.c
+++ b/drivers/phy/samsung/phy-exynos-mipi-video.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Samsung S5P/EXYNOS SoC series MIPI CSIS/DSIM DPHY driver
*
* Copyright (C) 2013,2016 Samsung Electronics Co., Ltd.
* Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
- *
- * 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.
*/
#include <linux/err.h>
diff --git a/drivers/phy/samsung/phy-exynos-pcie.c b/drivers/phy/samsung/phy-exynos-pcie.c
index a89c12faff39..1b4ba8bdb43c 100644
--- a/drivers/phy/samsung/phy-exynos-pcie.c
+++ b/drivers/phy/samsung/phy-exynos-pcie.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Samsung EXYNOS SoC series PCIe PHY driver
*
@@ -5,10 +6,6 @@
*
* Copyright (C) 2017 Samsung Electronics Co., Ltd.
* Jaehoon Chung <jh80.chung@samsung.com>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/phy/samsung/phy-exynos4210-usb2.c b/drivers/phy/samsung/phy-exynos4210-usb2.c
index 1f50e1004828..3898a7f58217 100644
--- a/drivers/phy/samsung/phy-exynos4210-usb2.c
+++ b/drivers/phy/samsung/phy-exynos4210-usb2.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Samsung SoC USB 1.1/2.0 PHY driver - Exynos 4210 support
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* Author: Kamil Debski <k.debski@samsung.com>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/phy/samsung/phy-exynos4x12-usb2.c b/drivers/phy/samsung/phy-exynos4x12-usb2.c
index 7f27a91acf87..b528a5d037fe 100644
--- a/drivers/phy/samsung/phy-exynos4x12-usb2.c
+++ b/drivers/phy/samsung/phy-exynos4x12-usb2.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Samsung SoC USB 1.1/2.0 PHY driver - Exynos 4x12 support
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* Author: Kamil Debski <k.debski@samsung.com>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/phy/samsung/phy-exynos5-usbdrd.c b/drivers/phy/samsung/phy-exynos5-usbdrd.c
index b8b226a20014..646259bee909 100644
--- a/drivers/phy/samsung/phy-exynos5-usbdrd.c
+++ b/drivers/phy/samsung/phy-exynos5-usbdrd.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Samsung EXYNOS5 SoC series USB DRD PHY driver
*
@@ -5,10 +6,6 @@
*
* Copyright (C) 2014 Samsung Electronics Co., Ltd.
* Author: Vivek Gautam <gautam.vivek@samsung.com>
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/phy/samsung/phy-exynos5250-sata.c b/drivers/phy/samsung/phy-exynos5250-sata.c
index 60e13afcd9b8..9e5fc126032c 100644
--- a/drivers/phy/samsung/phy-exynos5250-sata.c
+++ b/drivers/phy/samsung/phy-exynos5250-sata.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Samsung SATA SerDes(PHY) driver
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* Authors: Girish K S <ks.giri@samsung.com>
* Yuvaraj Kumar C D <yuvaraj.cd@samsung.com>
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/phy/samsung/phy-exynos5250-usb2.c b/drivers/phy/samsung/phy-exynos5250-usb2.c
index aad806272305..4f53b711fd6f 100644
--- a/drivers/phy/samsung/phy-exynos5250-usb2.c
+++ b/drivers/phy/samsung/phy-exynos5250-usb2.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Samsung SoC USB 1.1/2.0 PHY driver - Exynos 5250 support
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* Author: Kamil Debski <k.debski@samsung.com>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/phy/samsung/phy-s5pv210-usb2.c b/drivers/phy/samsung/phy-s5pv210-usb2.c
index f6f72339bbc3..56a5083fe6f9 100644
--- a/drivers/phy/samsung/phy-s5pv210-usb2.c
+++ b/drivers/phy/samsung/phy-s5pv210-usb2.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Samsung SoC USB 1.1/2.0 PHY driver - S5PV210 support
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* Authors: Kamil Debski <k.debski@samsung.com>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/phy/samsung/phy-samsung-usb2.c b/drivers/phy/samsung/phy-samsung-usb2.c
index ea818866985a..6c82f4fbe8a2 100644
--- a/drivers/phy/samsung/phy-samsung-usb2.c
+++ b/drivers/phy/samsung/phy-samsung-usb2.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Samsung SoC USB 1.1/2.0 PHY driver
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* Author: Kamil Debski <k.debski@samsung.com>
- *
- * 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.
*/
#include <linux/clk.h>
@@ -159,9 +156,8 @@ static int samsung_usb2_phy_probe(struct platform_device *pdev)
if (!cfg)
return -EINVAL;
- drv = devm_kzalloc(dev, sizeof(struct samsung_usb2_phy_driver) +
- cfg->num_phys * sizeof(struct samsung_usb2_phy_instance),
- GFP_KERNEL);
+ drv = devm_kzalloc(dev, struct_size(drv, instances, cfg->num_phys),
+ GFP_KERNEL);
if (!drv)
return -ENOMEM;
diff --git a/drivers/phy/samsung/phy-samsung-usb2.h b/drivers/phy/samsung/phy-samsung-usb2.h
index 6563e7ca0ac4..2c1a7d71142b 100644
--- a/drivers/phy/samsung/phy-samsung-usb2.h
+++ b/drivers/phy/samsung/phy-samsung-usb2.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Samsung SoC USB 1.1/2.0 PHY driver
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* Author: Kamil Debski <k.debski@samsung.com>
- *
- * 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.
*/
#ifndef _PHY_EXYNOS_USB2_H
diff --git a/drivers/phy/st/phy-miphy28lp.c b/drivers/phy/st/phy-miphy28lp.c
index 213e2e15339c..068160a34f5c 100644
--- a/drivers/phy/st/phy-miphy28lp.c
+++ b/drivers/phy/st/phy-miphy28lp.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 STMicroelectronics
*
* STMicroelectronics PHY driver MiPHY28lp (for SoC STiH407).
*
* Author: Alexandre Torgue <alexandre.torgue@st.com>
- *
- * 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.
- *
*/
#include <linux/platform_device.h>
diff --git a/drivers/phy/st/phy-spear1310-miphy.c b/drivers/phy/st/phy-spear1310-miphy.c
index ed67e98e54ca..8871cd186304 100644
--- a/drivers/phy/st/phy-spear1310-miphy.c
+++ b/drivers/phy/st/phy-spear1310-miphy.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ST SPEAr1310-miphy driver
*
* Copyright (C) 2014 ST Microelectronics
* Pratyush Anand <pratyush.anand@gmail.com>
* Mohit Kumar <mohit.kumar.dhaka@gmail.com>
- *
- * 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.
- *
*/
#include <linux/bitops.h>
diff --git a/drivers/phy/st/phy-spear1340-miphy.c b/drivers/phy/st/phy-spear1340-miphy.c
index 97280c0cf612..ed4d0e2df053 100644
--- a/drivers/phy/st/phy-spear1340-miphy.c
+++ b/drivers/phy/st/phy-spear1340-miphy.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ST spear1340-miphy driver
*
* Copyright (C) 2014 ST Microelectronics
* Pratyush Anand <pratyush.anand@gmail.com>
* Mohit Kumar <mohit.kumar.dhaka@gmail.com>
- *
- * 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.
- *
*/
#include <linux/bitops.h>
diff --git a/drivers/phy/st/phy-stih407-usb.c b/drivers/phy/st/phy-stih407-usb.c
index b1f44ab669fb..a4ae2cca7f63 100644
--- a/drivers/phy/st/phy-stih407-usb.c
+++ b/drivers/phy/st/phy-stih407-usb.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 STMicroelectronics
*
* STMicroelectronics Generic PHY driver for STiH407 USB2.
*
* Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
- *
- * 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.
- *
*/
#include <linux/platform_device.h>
#include <linux/io.h>
diff --git a/drivers/phy/tegra/xusb-tegra124.c b/drivers/phy/tegra/xusb-tegra124.c
index e8a2ba6eabd5..98d84920c676 100644
--- a/drivers/phy/tegra/xusb-tegra124.c
+++ b/drivers/phy/tegra/xusb-tegra124.c
@@ -1713,6 +1713,13 @@ static const struct tegra_xusb_padctl_ops tegra124_xusb_padctl_ops = {
.hsic_set_idle = tegra124_hsic_set_idle,
};
+static const char * const tegra124_xusb_padctl_supply_names[] = {
+ "avdd-pll-utmip",
+ "avdd-pll-erefe",
+ "avdd-pex-pll",
+ "hvdd-pex-pll-e",
+};
+
const struct tegra_xusb_padctl_soc tegra124_xusb_padctl_soc = {
.num_pads = ARRAY_SIZE(tegra124_pads),
.pads = tegra124_pads,
@@ -1735,6 +1742,8 @@ const struct tegra_xusb_padctl_soc tegra124_xusb_padctl_soc = {
},
},
.ops = &tegra124_xusb_padctl_ops,
+ .supply_names = tegra124_xusb_padctl_supply_names,
+ .num_supplies = ARRAY_SIZE(tegra124_xusb_padctl_supply_names),
};
EXPORT_SYMBOL_GPL(tegra124_xusb_padctl_soc);
diff --git a/drivers/phy/tegra/xusb-tegra210.c b/drivers/phy/tegra/xusb-tegra210.c
index 18cea8311d22..0c0df6897a3b 100644
--- a/drivers/phy/tegra/xusb-tegra210.c
+++ b/drivers/phy/tegra/xusb-tegra210.c
@@ -2009,6 +2009,13 @@ static const struct tegra_xusb_padctl_ops tegra210_xusb_padctl_ops = {
.hsic_set_idle = tegra210_hsic_set_idle,
};
+static const char * const tegra210_xusb_padctl_supply_names[] = {
+ "avdd-pll-utmip",
+ "avdd-pll-uerefe",
+ "dvdd-pex-pll",
+ "hvdd-pex-pll-e",
+};
+
const struct tegra_xusb_padctl_soc tegra210_xusb_padctl_soc = {
.num_pads = ARRAY_SIZE(tegra210_pads),
.pads = tegra210_pads,
@@ -2027,6 +2034,8 @@ const struct tegra_xusb_padctl_soc tegra210_xusb_padctl_soc = {
},
},
.ops = &tegra210_xusb_padctl_ops,
+ .supply_names = tegra210_xusb_padctl_supply_names,
+ .num_supplies = ARRAY_SIZE(tegra210_xusb_padctl_supply_names),
};
EXPORT_SYMBOL_GPL(tegra210_xusb_padctl_soc);
diff --git a/drivers/phy/ti/phy-am654-serdes.c b/drivers/phy/ti/phy-am654-serdes.c
index d3769200cb9b..f8edd0840fa2 100644
--- a/drivers/phy/ti/phy-am654-serdes.c
+++ b/drivers/phy/ti/phy-am654-serdes.c
@@ -247,8 +247,8 @@ static void serdes_am654_release(struct phy *x)
mux_control_deselect(phy->control);
}
-struct phy *serdes_am654_xlate(struct device *dev, struct of_phandle_args
- *args)
+static struct phy *serdes_am654_xlate(struct device *dev,
+ struct of_phandle_args *args)
{
struct serdes_am654 *am654_phy;
struct phy *phy;
diff --git a/drivers/phy/ti/phy-tusb1210.c b/drivers/phy/ti/phy-tusb1210.c
index 329fb938099a..d8d0cc11d187 100644
--- a/drivers/phy/ti/phy-tusb1210.c
+++ b/drivers/phy/ti/phy-tusb1210.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/**
* tusb1210.c - TUSB1210 USB ULPI PHY driver
*
* Copyright (C) 2015 Intel Corporation
*
* Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
- *
- * 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.
*/
#include <linux/module.h>
#include <linux/ulpi/driver.h>
diff --git a/drivers/pinctrl/aspeed/Makefile b/drivers/pinctrl/aspeed/Makefile
index 068729bf4f86..ea8962645e49 100644
--- a/drivers/pinctrl/aspeed/Makefile
+++ b/drivers/pinctrl/aspeed/Makefile
@@ -2,6 +2,6 @@
# Aspeed pinctrl support
ccflags-y += $(call cc-option,-Woverride-init)
-obj-$(CONFIG_PINCTRL_ASPEED) += pinctrl-aspeed.o
+obj-$(CONFIG_PINCTRL_ASPEED) += pinctrl-aspeed.o pinmux-aspeed.o
obj-$(CONFIG_PINCTRL_ASPEED_G4) += pinctrl-aspeed-g4.o
obj-$(CONFIG_PINCTRL_ASPEED_G5) += pinctrl-aspeed-g5.o
diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c
index 73e2c9c0e549..384396cbb22d 100644
--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c
+++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c
@@ -18,9 +18,35 @@
#include "../core.h"
#include "../pinctrl-utils.h"
+#include "pinmux-aspeed.h"
#include "pinctrl-aspeed.h"
/*
+ * The "Multi-function Pins Mapping and Control" table in the SoC datasheet
+ * references registers by the device/offset mnemonic. The register macros
+ * below are named the same way to ease transcription and verification (as
+ * opposed to naming them e.g. PINMUX_CTRL_[0-9]). Further, signal expressions
+ * reference registers beyond those dedicated to pinmux, such as the system
+ * reset control and MAC clock configuration registers.
+ */
+#define SCU2C 0x2C /* Misc. Control Register */
+#define SCU3C 0x3C /* System Reset Control/Status Register */
+#define SCU48 0x48 /* MAC Interface Clock Delay Setting */
+#define HW_STRAP1 0x70 /* AST2400 strapping is 33 bits, is split */
+#define HW_REVISION_ID 0x7C /* Silicon revision ID register */
+#define SCU80 0x80 /* Multi-function Pin Control #1 */
+#define SCU84 0x84 /* Multi-function Pin Control #2 */
+#define SCU88 0x88 /* Multi-function Pin Control #3 */
+#define SCU8C 0x8C /* Multi-function Pin Control #4 */
+#define SCU90 0x90 /* Multi-function Pin Control #5 */
+#define SCU94 0x94 /* Multi-function Pin Control #6 */
+#define SCUA0 0xA0 /* Multi-function Pin Control #7 */
+#define SCUA4 0xA4 /* Multi-function Pin Control #8 */
+#define SCUA8 0xA8 /* Multi-function Pin Control #9 */
+#define SCUAC 0xAC /* Multi-function Pin Control #10 */
+#define HW_STRAP2 0xD0 /* Strapping */
+
+/*
* Uses undefined macros for symbol naming and references, eg GPIOA0, MAC1LINK,
* TIMER3 etc.
*
@@ -2386,13 +2412,73 @@ static const struct aspeed_pin_config aspeed_g4_configs[] = {
{ PIN_CONFIG_INPUT_DEBOUNCE, { C14, B14 }, SCUA8, 27 },
};
+static int aspeed_g4_sig_expr_set(const struct aspeed_pinmux_data *ctx,
+ const struct aspeed_sig_expr *expr,
+ bool enable)
+{
+ int ret;
+ int i;
+
+ for (i = 0; i < expr->ndescs; i++) {
+ const struct aspeed_sig_desc *desc = &expr->descs[i];
+ u32 pattern = enable ? desc->enable : desc->disable;
+ u32 val = (pattern << __ffs(desc->mask));
+
+ if (!ctx->maps[desc->ip])
+ return -ENODEV;
+
+ /*
+ * Strap registers are configured in hardware or by early-boot
+ * firmware. Treat them as read-only despite that we can write
+ * them. This may mean that certain functions cannot be
+ * deconfigured and is the reason we re-evaluate after writing
+ * all descriptor bits.
+ *
+ * Port D and port E GPIO loopback modes are the only exception
+ * as those are commonly used with front-panel buttons to allow
+ * normal operation of the host when the BMC is powered off or
+ * fails to boot. Once the BMC has booted, the loopback mode
+ * must be disabled for the BMC to control host power-on and
+ * reset.
+ */
+ if (desc->ip == ASPEED_IP_SCU && desc->reg == HW_STRAP1 &&
+ !(desc->mask & (BIT(21) | BIT(22))))
+ continue;
+
+ if (desc->ip == ASPEED_IP_SCU && desc->reg == HW_STRAP2)
+ continue;
+
+ ret = regmap_update_bits(ctx->maps[desc->ip], desc->reg,
+ desc->mask, val);
+
+ if (ret)
+ return ret;
+ }
+
+ ret = aspeed_sig_expr_eval(ctx, expr, enable);
+ if (ret < 0)
+ return ret;
+
+ if (!ret)
+ return -EPERM;
+
+ return 0;
+}
+
+static const struct aspeed_pinmux_ops aspeed_g4_ops = {
+ .set = aspeed_g4_sig_expr_set,
+};
+
static struct aspeed_pinctrl_data aspeed_g4_pinctrl_data = {
.pins = aspeed_g4_pins,
.npins = ARRAY_SIZE(aspeed_g4_pins),
- .groups = aspeed_g4_groups,
- .ngroups = ARRAY_SIZE(aspeed_g4_groups),
- .functions = aspeed_g4_functions,
- .nfunctions = ARRAY_SIZE(aspeed_g4_functions),
+ .pinmux = {
+ .ops = &aspeed_g4_ops,
+ .groups = aspeed_g4_groups,
+ .ngroups = ARRAY_SIZE(aspeed_g4_groups),
+ .functions = aspeed_g4_functions,
+ .nfunctions = ARRAY_SIZE(aspeed_g4_functions),
+ },
.configs = aspeed_g4_configs,
.nconfigs = ARRAY_SIZE(aspeed_g4_configs),
};
diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
index aa7e148b38bb..053101f795a2 100644
--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
+++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
@@ -21,6 +21,32 @@
#include "../pinctrl-utils.h"
#include "pinctrl-aspeed.h"
+/*
+ * The "Multi-function Pins Mapping and Control" table in the SoC datasheet
+ * references registers by the device/offset mnemonic. The register macros
+ * below are named the same way to ease transcription and verification (as
+ * opposed to naming them e.g. PINMUX_CTRL_[0-9]). Further, signal expressions
+ * reference registers beyond those dedicated to pinmux, such as the system
+ * reset control and MAC clock configuration registers. The AST2500 goes a step
+ * further and references registers in the graphics IP block.
+ */
+#define SCU2C 0x2C /* Misc. Control Register */
+#define SCU3C 0x3C /* System Reset Control/Status Register */
+#define SCU48 0x48 /* MAC Interface Clock Delay Setting */
+#define HW_STRAP1 0x70 /* AST2400 strapping is 33 bits, is split */
+#define HW_REVISION_ID 0x7C /* Silicon revision ID register */
+#define SCU80 0x80 /* Multi-function Pin Control #1 */
+#define SCU84 0x84 /* Multi-function Pin Control #2 */
+#define SCU88 0x88 /* Multi-function Pin Control #3 */
+#define SCU8C 0x8C /* Multi-function Pin Control #4 */
+#define SCU90 0x90 /* Multi-function Pin Control #5 */
+#define SCU94 0x94 /* Multi-function Pin Control #6 */
+#define SCUA0 0xA0 /* Multi-function Pin Control #7 */
+#define SCUA4 0xA4 /* Multi-function Pin Control #8 */
+#define SCUA8 0xA8 /* Multi-function Pin Control #9 */
+#define SCUAC 0xAC /* Multi-function Pin Control #10 */
+#define HW_STRAP2 0xD0 /* Strapping */
+
#define ASPEED_G5_NR_PINS 236
#define COND1 { ASPEED_IP_SCU, SCU90, BIT(6), 0, 0 }
@@ -573,6 +599,8 @@ SS_PIN_DECL(N3, GPIOJ2, SGPMO);
SIG_EXPR_LIST_DECL_SINGLE(SGPMI, SGPM, SIG_DESC_SET(SCU84, 11));
SS_PIN_DECL(N4, GPIOJ3, SGPMI);
+FUNC_GROUP_DECL(SGPM, R2, L2, N3, N4);
+
#define N5 76
SIG_EXPR_LIST_DECL_SINGLE(VGAHS, VGAHS, SIG_DESC_SET(SCU84, 12));
SIG_EXPR_LIST_DECL_SINGLE(DASHN5, DASHN5, SIG_DESC_SET(SCU94, 8));
@@ -2123,6 +2151,7 @@ static const struct aspeed_pin_group aspeed_g5_groups[] = {
ASPEED_PINCTRL_GROUP(SD2),
ASPEED_PINCTRL_GROUP(SDA1),
ASPEED_PINCTRL_GROUP(SDA2),
+ ASPEED_PINCTRL_GROUP(SGPM),
ASPEED_PINCTRL_GROUP(SGPS1),
ASPEED_PINCTRL_GROUP(SGPS2),
ASPEED_PINCTRL_GROUP(SIOONCTRL),
@@ -2292,6 +2321,7 @@ static const struct aspeed_pin_function aspeed_g5_functions[] = {
ASPEED_PINCTRL_FUNC(SD2),
ASPEED_PINCTRL_FUNC(SDA1),
ASPEED_PINCTRL_FUNC(SDA2),
+ ASPEED_PINCTRL_FUNC(SGPM),
ASPEED_PINCTRL_FUNC(SGPS1),
ASPEED_PINCTRL_FUNC(SGPS2),
ASPEED_PINCTRL_FUNC(SIOONCTRL),
@@ -2477,13 +2507,98 @@ static struct aspeed_pin_config aspeed_g5_configs[] = {
{ PIN_CONFIG_INPUT_DEBOUNCE, { A20, B19 }, SCUA8, 27 },
};
+/**
+ * Configure a pin's signal by applying an expression's descriptor state for
+ * all descriptors in the expression.
+ *
+ * @ctx: The pinmux context
+ * @expr: The expression associated with the function whose signal is to be
+ * configured
+ * @enable: true to enable an function's signal through a pin's signal
+ * expression, false to disable the function's signal
+ *
+ * Return: 0 if the expression is configured as requested and a negative error
+ * code otherwise
+ */
+static int aspeed_g5_sig_expr_set(const struct aspeed_pinmux_data *ctx,
+ const struct aspeed_sig_expr *expr,
+ bool enable)
+{
+ int ret;
+ int i;
+
+ for (i = 0; i < expr->ndescs; i++) {
+ const struct aspeed_sig_desc *desc = &expr->descs[i];
+ u32 pattern = enable ? desc->enable : desc->disable;
+ u32 val = (pattern << __ffs(desc->mask));
+
+ if (!ctx->maps[desc->ip])
+ return -ENODEV;
+
+ /*
+ * Strap registers are configured in hardware or by early-boot
+ * firmware. Treat them as read-only despite that we can write
+ * them. This may mean that certain functions cannot be
+ * deconfigured and is the reason we re-evaluate after writing
+ * all descriptor bits.
+ *
+ * Port D and port E GPIO loopback modes are the only exception
+ * as those are commonly used with front-panel buttons to allow
+ * normal operation of the host when the BMC is powered off or
+ * fails to boot. Once the BMC has booted, the loopback mode
+ * must be disabled for the BMC to control host power-on and
+ * reset.
+ */
+ if (desc->ip == ASPEED_IP_SCU && desc->reg == HW_STRAP1 &&
+ !(desc->mask & (BIT(21) | BIT(22))))
+ continue;
+
+ if (desc->ip == ASPEED_IP_SCU && desc->reg == HW_STRAP2)
+ continue;
+
+ /* On AST2500, Set bits in SCU70 are cleared from SCU7C */
+ if (desc->ip == ASPEED_IP_SCU && desc->reg == HW_STRAP1) {
+ u32 value = ~val & desc->mask;
+
+ if (value) {
+ ret = regmap_write(ctx->maps[desc->ip],
+ HW_REVISION_ID, value);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ ret = regmap_update_bits(ctx->maps[desc->ip], desc->reg,
+ desc->mask, val);
+
+ if (ret)
+ return ret;
+ }
+
+ ret = aspeed_sig_expr_eval(ctx, expr, enable);
+ if (ret < 0)
+ return ret;
+
+ if (!ret)
+ return -EPERM;
+
+ return 0;
+}
+
+static const struct aspeed_pinmux_ops aspeed_g5_ops = {
+ .set = aspeed_g5_sig_expr_set,
+};
+
static struct aspeed_pinctrl_data aspeed_g5_pinctrl_data = {
.pins = aspeed_g5_pins,
.npins = ARRAY_SIZE(aspeed_g5_pins),
- .groups = aspeed_g5_groups,
- .ngroups = ARRAY_SIZE(aspeed_g5_groups),
- .functions = aspeed_g5_functions,
- .nfunctions = ARRAY_SIZE(aspeed_g5_functions),
+ .pinmux = {
+ .ops = &aspeed_g5_ops,
+ .groups = aspeed_g5_groups,
+ .ngroups = ARRAY_SIZE(aspeed_g5_groups),
+ .functions = aspeed_g5_functions,
+ .nfunctions = ARRAY_SIZE(aspeed_g5_functions),
+ },
.configs = aspeed_g5_configs,
.nconfigs = ARRAY_SIZE(aspeed_g5_configs),
};
@@ -2539,7 +2654,7 @@ static int aspeed_g5_pinctrl_probe(struct platform_device *pdev)
dev_warn(&pdev->dev, "No GFX phandle found, some mux configurations may fail\n");
map = NULL;
}
- aspeed_g5_pinctrl_data.maps[ASPEED_IP_GFX] = map;
+ aspeed_g5_pinctrl_data.pinmux.maps[ASPEED_IP_GFX] = map;
node = of_parse_phandle(pdev->dev.of_node, "aspeed,external-nodes", 1);
if (node) {
@@ -2553,7 +2668,7 @@ static int aspeed_g5_pinctrl_probe(struct platform_device *pdev)
map = NULL;
}
of_node_put(node);
- aspeed_g5_pinctrl_data.maps[ASPEED_IP_LPC] = map;
+ aspeed_g5_pinctrl_data.pinmux.maps[ASPEED_IP_LPC] = map;
return aspeed_pinctrl_probe(pdev, &aspeed_g5_pinctrl_desc,
&aspeed_g5_pinctrl_data);
diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed.c b/drivers/pinctrl/aspeed/pinctrl-aspeed.c
index 4c775b8ffdc4..535db3de490b 100644
--- a/drivers/pinctrl/aspeed/pinctrl-aspeed.c
+++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.c
@@ -10,17 +10,11 @@
#include "../core.h"
#include "pinctrl-aspeed.h"
-static const char *const aspeed_pinmux_ips[] = {
- [ASPEED_IP_SCU] = "SCU",
- [ASPEED_IP_GFX] = "GFX",
- [ASPEED_IP_LPC] = "LPC",
-};
-
int aspeed_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
{
struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
- return pdata->ngroups;
+ return pdata->pinmux.ngroups;
}
const char *aspeed_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
@@ -28,7 +22,7 @@ const char *aspeed_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
{
struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
- return pdata->groups[group].name;
+ return pdata->pinmux.groups[group].name;
}
int aspeed_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
@@ -37,8 +31,8 @@ int aspeed_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
{
struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
- *pins = &pdata->groups[group].pins[0];
- *npins = pdata->groups[group].npins;
+ *pins = &pdata->pinmux.groups[group].pins[0];
+ *npins = pdata->pinmux.groups[group].npins;
return 0;
}
@@ -53,7 +47,7 @@ int aspeed_pinmux_get_fn_count(struct pinctrl_dev *pctldev)
{
struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
- return pdata->nfunctions;
+ return pdata->pinmux.nfunctions;
}
const char *aspeed_pinmux_get_fn_name(struct pinctrl_dev *pctldev,
@@ -61,7 +55,7 @@ const char *aspeed_pinmux_get_fn_name(struct pinctrl_dev *pctldev,
{
struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
- return pdata->functions[function].name;
+ return pdata->pinmux.functions[function].name;
}
int aspeed_pinmux_get_fn_groups(struct pinctrl_dev *pctldev,
@@ -71,208 +65,38 @@ int aspeed_pinmux_get_fn_groups(struct pinctrl_dev *pctldev,
{
struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
- *groups = pdata->functions[function].groups;
- *num_groups = pdata->functions[function].ngroups;
+ *groups = pdata->pinmux.functions[function].groups;
+ *num_groups = pdata->pinmux.functions[function].ngroups;
return 0;
}
-static inline void aspeed_sig_desc_print_val(
- const struct aspeed_sig_desc *desc, bool enable, u32 rv)
-{
- pr_debug("Want %s%X[0x%08X]=0x%X, got 0x%X from 0x%08X\n",
- aspeed_pinmux_ips[desc->ip], desc->reg,
- desc->mask, enable ? desc->enable : desc->disable,
- (rv & desc->mask) >> __ffs(desc->mask), rv);
-}
-
-/**
- * Query the enabled or disabled state of a signal descriptor
- *
- * @desc: The signal descriptor of interest
- * @enabled: True to query the enabled state, false to query disabled state
- * @map: The IP block's regmap instance
- *
- * Return: 1 if the descriptor's bitfield is configured to the state
- * selected by @enabled, 0 if not, and less than zero if an unrecoverable
- * failure occurred
- *
- * Evaluation of descriptor state is non-trivial in that it is not a binary
- * outcome: The bitfields can be greater than one bit in size and thus can take
- * a value that is neither the enabled nor disabled state recorded in the
- * descriptor (typically this means a different function to the one of interest
- * is enabled). Thus we must explicitly test for either condition as required.
- */
-static int aspeed_sig_desc_eval(const struct aspeed_sig_desc *desc,
- bool enabled, struct regmap *map)
+static int aspeed_sig_expr_enable(const struct aspeed_pinmux_data *ctx,
+ const struct aspeed_sig_expr *expr)
{
int ret;
- unsigned int raw;
- u32 want;
- if (!map)
- return -ENODEV;
-
- ret = regmap_read(map, desc->reg, &raw);
- if (ret)
- return ret;
-
- aspeed_sig_desc_print_val(desc, enabled, raw);
- want = enabled ? desc->enable : desc->disable;
-
- return ((raw & desc->mask) >> __ffs(desc->mask)) == want;
-}
-
-/**
- * Query the enabled or disabled state for a mux function's signal on a pin
- *
- * @expr: An expression controlling the signal for a mux function on a pin
- * @enabled: True to query the enabled state, false to query disabled state
- * @maps: The list of regmap instances
- *
- * Return: 1 if the expression composed by @enabled evaluates true, 0 if not,
- * and less than zero if an unrecoverable failure occurred.
- *
- * A mux function is enabled or disabled if the function's signal expression
- * for each pin in the function's pin group evaluates true for the desired
- * state. An signal expression evaluates true if all of its associated signal
- * descriptors evaluate true for the desired state.
- *
- * If an expression's state is described by more than one bit, either through
- * multi-bit bitfields in a single signal descriptor or through multiple signal
- * descriptors of a single bit then it is possible for the expression to be in
- * neither the enabled nor disabled state. Thus we must explicitly test for
- * either condition as required.
- */
-static int aspeed_sig_expr_eval(const struct aspeed_sig_expr *expr,
- bool enabled, struct regmap * const *maps)
-{
- int i;
- int ret;
-
- for (i = 0; i < expr->ndescs; i++) {
- const struct aspeed_sig_desc *desc = &expr->descs[i];
-
- ret = aspeed_sig_desc_eval(desc, enabled, maps[desc->ip]);
- if (ret <= 0)
- return ret;
- }
-
- return 1;
-}
-
-/**
- * Configure a pin's signal by applying an expression's descriptor state for
- * all descriptors in the expression.
- *
- * @expr: The expression associated with the function whose signal is to be
- * configured
- * @enable: true to enable an function's signal through a pin's signal
- * expression, false to disable the function's signal
- * @maps: The list of regmap instances for pinmux register access.
- *
- * Return: 0 if the expression is configured as requested and a negative error
- * code otherwise
- */
-static int aspeed_sig_expr_set(const struct aspeed_sig_expr *expr,
- bool enable, struct regmap * const *maps)
-{
- int ret;
- int i;
-
- for (i = 0; i < expr->ndescs; i++) {
- const struct aspeed_sig_desc *desc = &expr->descs[i];
- u32 pattern = enable ? desc->enable : desc->disable;
- u32 val = (pattern << __ffs(desc->mask));
-
- if (!maps[desc->ip])
- return -ENODEV;
-
- /*
- * Strap registers are configured in hardware or by early-boot
- * firmware. Treat them as read-only despite that we can write
- * them. This may mean that certain functions cannot be
- * deconfigured and is the reason we re-evaluate after writing
- * all descriptor bits.
- *
- * Port D and port E GPIO loopback modes are the only exception
- * as those are commonly used with front-panel buttons to allow
- * normal operation of the host when the BMC is powered off or
- * fails to boot. Once the BMC has booted, the loopback mode
- * must be disabled for the BMC to control host power-on and
- * reset.
- */
- if (desc->ip == ASPEED_IP_SCU && desc->reg == HW_STRAP1 &&
- !(desc->mask & (BIT(21) | BIT(22))))
- continue;
-
- if (desc->ip == ASPEED_IP_SCU && desc->reg == HW_STRAP2)
- continue;
-
- /* On AST2500, Set bits in SCU7C are cleared from SCU70 */
- if (desc->ip == ASPEED_IP_SCU && desc->reg == HW_STRAP1) {
- unsigned int rev_id;
-
- ret = regmap_read(maps[ASPEED_IP_SCU],
- HW_REVISION_ID, &rev_id);
- if (ret < 0)
- return ret;
-
- if (0x04 == (rev_id >> 24)) {
- u32 value = ~val & desc->mask;
-
- if (value) {
- ret = regmap_write(maps[desc->ip],
- HW_REVISION_ID, value);
- if (ret < 0)
- return ret;
- }
- }
- }
-
- ret = regmap_update_bits(maps[desc->ip], desc->reg,
- desc->mask, val);
-
- if (ret)
- return ret;
- }
-
- ret = aspeed_sig_expr_eval(expr, enable, maps);
- if (ret < 0)
- return ret;
-
- if (!ret)
- return -EPERM;
-
- return 0;
-}
-
-static int aspeed_sig_expr_enable(const struct aspeed_sig_expr *expr,
- struct regmap * const *maps)
-{
- int ret;
-
- ret = aspeed_sig_expr_eval(expr, true, maps);
+ ret = aspeed_sig_expr_eval(ctx, expr, true);
if (ret < 0)
return ret;
if (!ret)
- return aspeed_sig_expr_set(expr, true, maps);
+ return aspeed_sig_expr_set(ctx, expr, true);
return 0;
}
-static int aspeed_sig_expr_disable(const struct aspeed_sig_expr *expr,
- struct regmap * const *maps)
+static int aspeed_sig_expr_disable(const struct aspeed_pinmux_data *ctx,
+ const struct aspeed_sig_expr *expr)
{
int ret;
- ret = aspeed_sig_expr_eval(expr, true, maps);
+ ret = aspeed_sig_expr_eval(ctx, expr, true);
if (ret < 0)
return ret;
if (ret)
- return aspeed_sig_expr_set(expr, false, maps);
+ return aspeed_sig_expr_set(ctx, expr, false);
return 0;
}
@@ -280,13 +104,13 @@ static int aspeed_sig_expr_disable(const struct aspeed_sig_expr *expr,
/**
* Disable a signal on a pin by disabling all provided signal expressions.
*
+ * @ctx: The pinmux context
* @exprs: The list of signal expressions (from a priority level on a pin)
- * @maps: The list of regmap instances for pinmux register access.
*
* Return: 0 if all expressions are disabled, otherwise a negative error code
*/
-static int aspeed_disable_sig(const struct aspeed_sig_expr **exprs,
- struct regmap * const *maps)
+static int aspeed_disable_sig(const struct aspeed_pinmux_data *ctx,
+ const struct aspeed_sig_expr **exprs)
{
int ret = 0;
@@ -294,7 +118,7 @@ static int aspeed_disable_sig(const struct aspeed_sig_expr **exprs,
return true;
while (*exprs && !ret) {
- ret = aspeed_sig_expr_disable(*exprs, maps);
+ ret = aspeed_sig_expr_disable(ctx, *exprs);
exprs++;
}
@@ -395,9 +219,9 @@ int aspeed_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
int ret;
const struct aspeed_pinctrl_data *pdata =
pinctrl_dev_get_drvdata(pctldev);
- const struct aspeed_pin_group *pgroup = &pdata->groups[group];
+ const struct aspeed_pin_group *pgroup = &pdata->pinmux.groups[group];
const struct aspeed_pin_function *pfunc =
- &pdata->functions[function];
+ &pdata->pinmux.functions[function];
for (i = 0; i < pgroup->npins; i++) {
int pin = pgroup->pins[i];
@@ -423,7 +247,7 @@ int aspeed_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
if (expr)
break;
- ret = aspeed_disable_sig(funcs, pdata->maps);
+ ret = aspeed_disable_sig(&pdata->pinmux, funcs);
if (ret)
return ret;
@@ -443,7 +267,7 @@ int aspeed_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
return -ENXIO;
}
- ret = aspeed_sig_expr_enable(expr, pdata->maps);
+ ret = aspeed_sig_expr_enable(&pdata->pinmux, expr);
if (ret)
return ret;
}
@@ -500,7 +324,7 @@ int aspeed_gpio_request_enable(struct pinctrl_dev *pctldev,
if (aspeed_gpio_in_exprs(funcs))
break;
- ret = aspeed_disable_sig(funcs, pdata->maps);
+ ret = aspeed_disable_sig(&pdata->pinmux, funcs);
if (ret)
return ret;
@@ -531,7 +355,7 @@ int aspeed_gpio_request_enable(struct pinctrl_dev *pctldev,
* If GPIO is not the lowest priority signal type, assume there is only
* one expression defined to enable the GPIO function
*/
- return aspeed_sig_expr_enable(expr, pdata->maps);
+ return aspeed_sig_expr_enable(&pdata->pinmux, expr);
}
int aspeed_pinctrl_probe(struct platform_device *pdev,
@@ -547,12 +371,14 @@ int aspeed_pinctrl_probe(struct platform_device *pdev,
return -ENODEV;
}
- pdata->maps[ASPEED_IP_SCU] = syscon_node_to_regmap(parent->of_node);
- if (IS_ERR(pdata->maps[ASPEED_IP_SCU])) {
+ pdata->scu = syscon_node_to_regmap(parent->of_node);
+ if (IS_ERR(pdata->scu)) {
dev_err(&pdev->dev, "No regmap for syscon pincontroller parent\n");
- return PTR_ERR(pdata->maps[ASPEED_IP_SCU]);
+ return PTR_ERR(pdata->scu);
}
+ pdata->pinmux.maps[ASPEED_IP_SCU] = pdata->scu;
+
pctl = pinctrl_register(pdesc, &pdev->dev, pdata);
if (IS_ERR(pctl)) {
@@ -587,7 +413,9 @@ static inline const struct aspeed_pin_config *find_pinconf_config(
return NULL;
}
-/**
+/*
+ * Aspeed pin configuration description.
+ *
* @param: pinconf configuration parameter
* @arg: The supported argument for @param, or -1 if any value is supported
* @val: The register value to write to configure @arg for @param
@@ -661,7 +489,7 @@ int aspeed_pin_config_get(struct pinctrl_dev *pctldev, unsigned int offset,
if (!pconf)
return -ENOTSUPP;
- rc = regmap_read(pdata->maps[ASPEED_IP_SCU], pconf->reg, &val);
+ rc = regmap_read(pdata->scu, pconf->reg, &val);
if (rc < 0)
return rc;
@@ -716,8 +544,8 @@ int aspeed_pin_config_set(struct pinctrl_dev *pctldev, unsigned int offset,
val = pmap->val << pconf->bit;
- rc = regmap_update_bits(pdata->maps[ASPEED_IP_SCU], pconf->reg,
- BIT(pconf->bit), val);
+ rc = regmap_update_bits(pdata->scu, pconf->reg,
+ BIT(pconf->bit), val);
if (rc < 0)
return rc;
diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed.h b/drivers/pinctrl/aspeed/pinctrl-aspeed.h
index 4b06ddbc6aec..a5d83986f32e 100644
--- a/drivers/pinctrl/aspeed/pinctrl-aspeed.h
+++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.h
@@ -12,504 +12,7 @@
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/regmap.h>
-/*
- * The ASPEED SoCs provide typically more than 200 pins for GPIO and other
- * functions. The SoC function enabled on a pin is determined on a priority
- * basis where a given pin can provide a number of different signal types.
- *
- * The signal active on a pin is described by both a priority level and
- * compound logical expressions involving multiple operators, registers and
- * bits. Some difficulty arises as the pin's function bit masks for each
- * priority level are frequently not the same (i.e. cannot just flip a bit to
- * change from a high to low priority signal), or even in the same register.
- * Further, not all signals can be unmuxed, as some expressions depend on
- * values in the hardware strapping register (which is treated as read-only).
- *
- * SoC Multi-function Pin Expression Examples
- * ------------------------------------------
- *
- * Here are some sample mux configurations from the AST2400 and AST2500
- * datasheets to illustrate the corner cases, roughly in order of least to most
- * corner. The signal priorities are in decending order from P0 (highest).
- *
- * D6 is a pin with a single function (beside GPIO); a high priority signal
- * that participates in one function:
- *
- * Ball | Default | P0 Signal | P0 Expression | P1 Signal | P1 Expression | Other
- * -----+---------+-----------+-----------------------------+-----------+---------------+----------
- * D6 GPIOA0 MAC1LINK SCU80[0]=1 GPIOA0
- * -----+---------+-----------+-----------------------------+-----------+---------------+----------
- *
- * C5 is a multi-signal pin (high and low priority signals). Here we touch
- * different registers for the different functions that enable each signal:
- *
- * -----+---------+-----------+-----------------------------+-----------+---------------+----------
- * C5 GPIOA4 SCL9 SCU90[22]=1 TIMER5 SCU80[4]=1 GPIOA4
- * -----+---------+-----------+-----------------------------+-----------+---------------+----------
- *
- * E19 is a single-signal pin with two functions that influence the active
- * signal. In this case both bits have the same meaning - enable a dedicated
- * LPC reset pin. However it's not always the case that the bits in the
- * OR-relationship have the same meaning.
- *
- * -----+---------+-----------+-----------------------------+-----------+---------------+----------
- * E19 GPIOB4 LPCRST# SCU80[12]=1 | Strap[14]=1 GPIOB4
- * -----+---------+-----------+-----------------------------+-----------+---------------+----------
- *
- * For example, pin B19 has a low-priority signal that's enabled by two
- * distinct SoC functions: A specific SIOPBI bit in register SCUA4, and an ACPI
- * bit in the STRAP register. The ACPI bit configures signals on pins in
- * addition to B19. Both of the low priority functions as well as the high
- * priority function must be disabled for GPIOF1 to be used.
- *
- * Ball | Default | P0 Signal | P0 Expression | P1 Signal | P1 Expression | Other
- * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+----------
- * B19 GPIOF1 NDCD4 SCU80[25]=1 SIOPBI# SCUA4[12]=1 | Strap[19]=0 GPIOF1
- * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+----------
- *
- * For pin E18, the SoC ANDs the expected state of three bits to determine the
- * pin's active signal:
- *
- * * SCU3C[3]: Enable external SOC reset function
- * * SCU80[15]: Enable SPICS1# or EXTRST# function pin
- * * SCU90[31]: Select SPI interface CS# output
- *
- * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+----------
- * E18 GPIOB7 EXTRST# SCU3C[3]=1 & SCU80[15]=1 & SCU90[31]=0 SPICS1# SCU3C[3]=1 & SCU80[15]=1 & SCU90[31]=1 GPIOB7
- * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+----------
- *
- * (Bits SCU3C[3] and SCU80[15] appear to only be used in the expressions for
- * selecting the signals on pin E18)
- *
- * Pin T5 is a multi-signal pin with a more complex configuration:
- *
- * Ball | Default | P0 Signal | P0 Expression | P1 Signal | P1 Expression | Other
- * -----+---------+-----------+------------------------------+-----------+---------------+----------
- * T5 GPIOL1 VPIDE SCU90[5:4]!=0 & SCU84[17]=1 NDCD1 SCU84[17]=1 GPIOL1
- * -----+---------+-----------+------------------------------+-----------+---------------+----------
- *
- * The high priority signal configuration is best thought of in terms of its
- * exploded form, with reference to the SCU90[5:4] bits:
- *
- * * SCU90[5:4]=00: disable
- * * SCU90[5:4]=01: 18 bits (R6/G6/B6) video mode.
- * * SCU90[5:4]=10: 24 bits (R8/G8/B8) video mode.
- * * SCU90[5:4]=11: 30 bits (R10/G10/B10) video mode.
- *
- * Re-writing:
- *
- * -----+---------+-----------+------------------------------+-----------+---------------+----------
- * T5 GPIOL1 VPIDE (SCU90[5:4]=1 & SCU84[17]=1) NDCD1 SCU84[17]=1 GPIOL1
- * | (SCU90[5:4]=2 & SCU84[17]=1)
- * | (SCU90[5:4]=3 & SCU84[17]=1)
- * -----+---------+-----------+------------------------------+-----------+---------------+----------
- *
- * For reference the SCU84[17] bit configure the "UART1 NDCD1 or Video VPIDE
- * function pin", where the signal itself is determined by whether SCU94[5:4]
- * is disabled or in one of the 18, 24 or 30bit video modes.
- *
- * Other video-input-related pins require an explicit state in SCU90[5:4], e.g.
- * W1 and U5:
- *
- * -----+---------+-----------+------------------------------+-----------+---------------+----------
- * W1 GPIOL6 VPIB0 SCU90[5:4]=3 & SCU84[22]=1 TXD1 SCU84[22]=1 GPIOL6
- * U5 GPIOL7 VPIB1 SCU90[5:4]=3 & SCU84[23]=1 RXD1 SCU84[23]=1 GPIOL7
- * -----+---------+-----------+------------------------------+-----------+---------------+----------
- *
- * The examples of T5 and W1 are particularly fertile, as they also demonstrate
- * that despite operating as part of the video input bus each signal needs to
- * be enabled individually via it's own SCU84 (in the cases of T5 and W1)
- * register bit. This is a little crazy if the bus doesn't have optional
- * signals, but is used to decent effect with some of the UARTs where not all
- * signals are required. However, this isn't done consistently - UART1 is
- * enabled on a per-pin basis, and by contrast, all signals for UART6 are
- * enabled by a single bit.
- *
- * Further, the high and low priority signals listed in the table above share
- * a configuration bit. The VPI signals should operate in concert in a single
- * function, but the UART signals should retain the ability to be configured
- * independently. This pushes the implementation down the path of tagging a
- * signal's expressions with the function they participate in, rather than
- * defining masks affecting multiple signals per function. The latter approach
- * fails in this instance where applying the configuration for the UART pin of
- * interest will stomp on the state of other UART signals when disabling the
- * VPI functions on the current pin.
- *
- * Ball | Default | P0 Signal | P0 Expression | P1 Signal | P1 Expression | Other
- * -----+------------+-----------+---------------------------+-----------+---------------+------------
- * A12 RGMII1TXCK GPIOT0 SCUA0[0]=1 RMII1TXEN Strap[6]=0 RGMII1TXCK
- * B12 RGMII1TXCTL GPIOT1 SCUA0[1]=1 – Strap[6]=0 RGMII1TXCTL
- * -----+------------+-----------+---------------------------+-----------+---------------+------------
- *
- * A12 demonstrates that the "Other" signal isn't always GPIO - in this case
- * GPIOT0 is a high-priority signal and RGMII1TXCK is Other. Thus, GPIO
- * should be treated like any other signal type with full function expression
- * requirements, and not assumed to be the default case. Separately, GPIOT0 and
- * GPIOT1's signal descriptor bits are distinct, therefore we must iterate all
- * pins in the function's group to disable the higher-priority signals such
- * that the signal for the function of interest is correctly enabled.
- *
- * Finally, three priority levels aren't always enough; the AST2500 brings with
- * it 18 pins of five priority levels, however the 18 pins only use three of
- * the five priority levels.
- *
- * Ultimately the requirement to control pins in the examples above drive the
- * design:
- *
- * * Pins provide signals according to functions activated in the mux
- * configuration
- *
- * * Pins provide up to five signal types in a priority order
- *
- * * For priorities levels defined on a pin, each priority provides one signal
- *
- * * Enabling lower priority signals requires higher priority signals be
- * disabled
- *
- * * A function represents a set of signals; functions are distinct if their
- * sets of signals are not equal
- *
- * * Signals participate in one or more functions
- *
- * * A function is described by an expression of one or more signal
- * descriptors, which compare bit values in a register
- *
- * * A signal expression is the smallest set of signal descriptors whose
- * comparisons must evaluate 'true' for a signal to be enabled on a pin.
- *
- * * A function's signal is active on a pin if evaluating all signal
- * descriptors in the pin's signal expression for the function yields a 'true'
- * result
- *
- * * A signal at a given priority on a given pin is active if any of the
- * functions in which the signal participates are active, and no higher
- * priority signal on the pin is active
- *
- * * GPIO is configured per-pin
- *
- * And so:
- *
- * * To disable a signal, any function(s) activating the signal must be
- * disabled
- *
- * * Each pin must know the signal expressions of functions in which it
- * participates, for the purpose of enabling the Other function. This is done
- * by deactivating all functions that activate higher priority signals on the
- * pin.
- *
- * As a concrete example:
- *
- * * T5 provides three signals types: VPIDE, NDCD1 and GPIO
- *
- * * The VPIDE signal participates in 3 functions: VPI18, VPI24 and VPI30
- *
- * * The NDCD1 signal participates in just its own NDCD1 function
- *
- * * VPIDE is high priority, NDCD1 is low priority, and GPIOL1 is the least
- * prioritised
- *
- * * The prerequisit for activating the NDCD1 signal is that the VPI18, VPI24
- * and VPI30 functions all be disabled
- *
- * * Similarly, all of VPI18, VPI24, VPI30 and NDCD1 functions must be disabled
- * to provide GPIOL6
- *
- * Considerations
- * --------------
- *
- * If pinctrl allows us to allocate a pin we can configure a function without
- * concern for the function of already allocated pins, if pin groups are
- * created with respect to the SoC functions in which they participate. This is
- * intuitive, but it did not feel obvious from the bit/pin relationships.
- *
- * Conversely, failing to allocate all pins in a group indicates some bits (as
- * well as pins) required for the group's configuration will already be in use,
- * likely in a way that's inconsistent with the requirements of the failed
- * group.
- */
-
-#define ASPEED_IP_SCU 0
-#define ASPEED_IP_GFX 1
-#define ASPEED_IP_LPC 2
-#define ASPEED_NR_PINMUX_IPS 3
-
-/*
- * The "Multi-function Pins Mapping and Control" table in the SoC datasheet
- * references registers by the device/offset mnemonic. The register macros
- * below are named the same way to ease transcription and verification (as
- * opposed to naming them e.g. PINMUX_CTRL_[0-9]). Further, signal expressions
- * reference registers beyond those dedicated to pinmux, such as the system
- * reset control and MAC clock configuration registers. The AST2500 goes a step
- * further and references registers in the graphics IP block, but that isn't
- * handled yet.
- */
-#define SCU2C 0x2C /* Misc. Control Register */
-#define SCU3C 0x3C /* System Reset Control/Status Register */
-#define SCU48 0x48 /* MAC Interface Clock Delay Setting */
-#define HW_STRAP1 0x70 /* AST2400 strapping is 33 bits, is split */
-#define HW_REVISION_ID 0x7C /* Silicon revision ID register */
-#define SCU80 0x80 /* Multi-function Pin Control #1 */
-#define SCU84 0x84 /* Multi-function Pin Control #2 */
-#define SCU88 0x88 /* Multi-function Pin Control #3 */
-#define SCU8C 0x8C /* Multi-function Pin Control #4 */
-#define SCU90 0x90 /* Multi-function Pin Control #5 */
-#define SCU94 0x94 /* Multi-function Pin Control #6 */
-#define SCUA0 0xA0 /* Multi-function Pin Control #7 */
-#define SCUA4 0xA4 /* Multi-function Pin Control #8 */
-#define SCUA8 0xA8 /* Multi-function Pin Control #9 */
-#define SCUAC 0xAC /* Multi-function Pin Control #10 */
-#define HW_STRAP2 0xD0 /* Strapping */
-
- /**
- * A signal descriptor, which describes the register, bits and the
- * enable/disable values that should be compared or written.
- *
- * @ip: The IP block identifier, used as an index into the regmap array in
- * struct aspeed_pinctrl_data
- * @reg: The register offset with respect to the base address of the IP block
- * @mask: The mask to apply to the register. The lowest set bit of the mask is
- * used to derive the shift value.
- * @enable: The value that enables the function. Value should be in the LSBs,
- * not at the position of the mask.
- * @disable: The value that disables the function. Value should be in the
- * LSBs, not at the position of the mask.
- */
-struct aspeed_sig_desc {
- unsigned int ip;
- unsigned int reg;
- u32 mask;
- u32 enable;
- u32 disable;
-};
-
-/**
- * Describes a signal expression. The expression is evaluated by ANDing the
- * evaluation of the descriptors.
- *
- * @signal: The signal name for the priority level on the pin. If the signal
- * type is GPIO, then the signal name must begin with the string
- * "GPIO", e.g. GPIOA0, GPIOT4 etc.
- * @function: The name of the function the signal participates in for the
- * associated expression
- * @ndescs: The number of signal descriptors in the expression
- * @descs: Pointer to an array of signal descriptors that comprise the
- * function expression
- */
-struct aspeed_sig_expr {
- const char *signal;
- const char *function;
- int ndescs;
- const struct aspeed_sig_desc *descs;
-};
-
-/**
- * A struct capturing the list of expressions enabling signals at each priority
- * for a given pin. The signal configuration for a priority level is evaluated
- * by ORing the evaluation of the signal expressions in the respective
- * priority's list.
- *
- * @name: A name for the pin
- * @prios: A pointer to an array of expression list pointers
- *
- */
-struct aspeed_pin_desc {
- const char *name;
- const struct aspeed_sig_expr ***prios;
-};
-
-/* Macro hell */
-
-#define SIG_DESC_IP_BIT(ip, reg, idx, val) \
- { ip, reg, BIT_MASK(idx), val, (((val) + 1) & 1) }
-
-/**
- * Short-hand macro for describing an SCU descriptor enabled by the state of
- * one bit. The disable value is derived.
- *
- * @reg: The signal's associated register, offset from base
- * @idx: The signal's bit index in the register
- * @val: The value (0 or 1) that enables the function
- */
-#define SIG_DESC_BIT(reg, idx, val) \
- SIG_DESC_IP_BIT(ASPEED_IP_SCU, reg, idx, val)
-
-#define SIG_DESC_IP_SET(ip, reg, idx) SIG_DESC_IP_BIT(ip, reg, idx, 1)
-
-/**
- * A further short-hand macro expanding to an SCU descriptor enabled by a set
- * bit.
- *
- * @reg: The register, offset from base
- * @idx: The bit index in the register
- */
-#define SIG_DESC_SET(reg, idx) SIG_DESC_IP_BIT(ASPEED_IP_SCU, reg, idx, 1)
-
-#define SIG_DESC_LIST_SYM(sig, func) sig_descs_ ## sig ## _ ## func
-#define SIG_DESC_LIST_DECL(sig, func, ...) \
- static const struct aspeed_sig_desc SIG_DESC_LIST_SYM(sig, func)[] = \
- { __VA_ARGS__ }
-
-#define SIG_EXPR_SYM(sig, func) sig_expr_ ## sig ## _ ## func
-#define SIG_EXPR_DECL_(sig, func) \
- static const struct aspeed_sig_expr SIG_EXPR_SYM(sig, func) = \
- { \
- .signal = #sig, \
- .function = #func, \
- .ndescs = ARRAY_SIZE(SIG_DESC_LIST_SYM(sig, func)), \
- .descs = &(SIG_DESC_LIST_SYM(sig, func))[0], \
- }
-
-/**
- * Declare a signal expression.
- *
- * @sig: A macro symbol name for the signal (is subjected to stringification
- * and token pasting)
- * @func: The function in which the signal is participating
- * @...: Signal descriptors that define the signal expression
- *
- * For example, the following declares the ROMD8 signal for the ROM16 function:
- *
- * SIG_EXPR_DECL(ROMD8, ROM16, SIG_DESC_SET(SCU90, 6));
- *
- * And with multiple signal descriptors:
- *
- * SIG_EXPR_DECL(ROMD8, ROM16S, SIG_DESC_SET(HW_STRAP1, 4),
- * { HW_STRAP1, GENMASK(1, 0), 0, 0 });
- */
-#define SIG_EXPR_DECL(sig, func, ...) \
- SIG_DESC_LIST_DECL(sig, func, __VA_ARGS__); \
- SIG_EXPR_DECL_(sig, func)
-
-/**
- * Declare a pointer to a signal expression
- *
- * @sig: The macro symbol name for the signal (subjected to token pasting)
- * @func: The macro symbol name for the function (subjected to token pasting)
- */
-#define SIG_EXPR_PTR(sig, func) (&SIG_EXPR_SYM(sig, func))
-
-#define SIG_EXPR_LIST_SYM(sig) sig_exprs_ ## sig
-
-/**
- * Declare a signal expression list for reference in a struct aspeed_pin_prio.
- *
- * @sig: A macro symbol name for the signal (is subjected to token pasting)
- * @...: Signal expression structure pointers (use SIG_EXPR_PTR())
- *
- * For example, the 16-bit ROM bus can be enabled by one of two possible signal
- * expressions:
- *
- * SIG_EXPR_DECL(ROMD8, ROM16, SIG_DESC_SET(SCU90, 6));
- * SIG_EXPR_DECL(ROMD8, ROM16S, SIG_DESC_SET(HW_STRAP1, 4),
- * { HW_STRAP1, GENMASK(1, 0), 0, 0 });
- * SIG_EXPR_LIST_DECL(ROMD8, SIG_EXPR_PTR(ROMD8, ROM16),
- * SIG_EXPR_PTR(ROMD8, ROM16S));
- */
-#define SIG_EXPR_LIST_DECL(sig, ...) \
- static const struct aspeed_sig_expr *SIG_EXPR_LIST_SYM(sig)[] = \
- { __VA_ARGS__, NULL }
-
-/**
- * A short-hand macro for declaring a function expression and an expression
- * list with a single function.
- *
- * @func: A macro symbol name for the function (is subjected to token pasting)
- * @...: Function descriptors that define the function expression
- *
- * For example, signal NCTS6 participates in its own function with one group:
- *
- * SIG_EXPR_LIST_DECL_SINGLE(NCTS6, NCTS6, SIG_DESC_SET(SCU90, 7));
- */
-#define SIG_EXPR_LIST_DECL_SINGLE(sig, func, ...) \
- SIG_DESC_LIST_DECL(sig, func, __VA_ARGS__); \
- SIG_EXPR_DECL_(sig, func); \
- SIG_EXPR_LIST_DECL(sig, SIG_EXPR_PTR(sig, func))
-
-#define SIG_EXPR_LIST_DECL_DUAL(sig, f0, f1) \
- SIG_EXPR_LIST_DECL(sig, SIG_EXPR_PTR(sig, f0), SIG_EXPR_PTR(sig, f1))
-
-#define SIG_EXPR_LIST_PTR(sig) (&SIG_EXPR_LIST_SYM(sig)[0])
-
-#define PIN_EXPRS_SYM(pin) pin_exprs_ ## pin
-#define PIN_EXPRS_PTR(pin) (&PIN_EXPRS_SYM(pin)[0])
-#define PIN_SYM(pin) pin_ ## pin
-
-#define MS_PIN_DECL_(pin, ...) \
- static const struct aspeed_sig_expr **PIN_EXPRS_SYM(pin)[] = \
- { __VA_ARGS__, NULL }; \
- static const struct aspeed_pin_desc PIN_SYM(pin) = \
- { #pin, PIN_EXPRS_PTR(pin) }
-
-/**
- * Declare a multi-signal pin
- *
- * @pin: The pin number
- * @other: Macro name for "other" functionality (subjected to stringification)
- * @high: Macro name for the highest priority signal functions
- * @low: Macro name for the low signal functions
- *
- * For example:
- *
- * #define A8 56
- * SIG_EXPR_DECL(ROMD8, ROM16, SIG_DESC_SET(SCU90, 6));
- * SIG_EXPR_DECL(ROMD8, ROM16S, SIG_DESC_SET(HW_STRAP1, 4),
- * { HW_STRAP1, GENMASK(1, 0), 0, 0 });
- * SIG_EXPR_LIST_DECL(ROMD8, SIG_EXPR_PTR(ROMD8, ROM16),
- * SIG_EXPR_PTR(ROMD8, ROM16S));
- * SIG_EXPR_LIST_DECL_SINGLE(NCTS6, NCTS6, SIG_DESC_SET(SCU90, 7));
- * MS_PIN_DECL(A8, GPIOH0, ROMD8, NCTS6);
- */
-#define MS_PIN_DECL(pin, other, high, low) \
- SIG_EXPR_LIST_DECL_SINGLE(other, other); \
- MS_PIN_DECL_(pin, \
- SIG_EXPR_LIST_PTR(high), \
- SIG_EXPR_LIST_PTR(low), \
- SIG_EXPR_LIST_PTR(other))
-
-#define PIN_GROUP_SYM(func) pins_ ## func
-#define FUNC_GROUP_SYM(func) groups_ ## func
-#define FUNC_GROUP_DECL(func, ...) \
- static const int PIN_GROUP_SYM(func)[] = { __VA_ARGS__ }; \
- static const char *FUNC_GROUP_SYM(func)[] = { #func }
-
-/**
- * Declare a single signal pin
- *
- * @pin: The pin number
- * @other: Macro name for "other" functionality (subjected to stringification)
- * @sig: Macro name for the signal (subjected to stringification)
- *
- * For example:
- *
- * #define E3 80
- * SIG_EXPR_LIST_DECL_SINGLE(SCL5, I2C5, I2C5_DESC);
- * SS_PIN_DECL(E3, GPIOK0, SCL5);
- */
-#define SS_PIN_DECL(pin, other, sig) \
- SIG_EXPR_LIST_DECL_SINGLE(other, other); \
- MS_PIN_DECL_(pin, SIG_EXPR_LIST_PTR(sig), SIG_EXPR_LIST_PTR(other))
-
-/**
- * Single signal, single function pin declaration
- *
- * @pin: The pin number
- * @other: Macro name for "other" functionality (subjected to stringification)
- * @sig: Macro name for the signal (subjected to stringification)
- * @...: Signal descriptors that define the function expression
- *
- * For example:
- *
- * SSSF_PIN_DECL(A4, GPIOA2, TIMER3, SIG_DESC_SET(SCU80, 2));
- */
-#define SSSF_PIN_DECL(pin, other, sig, ...) \
- SIG_EXPR_LIST_DECL_SINGLE(sig, sig, __VA_ARGS__); \
- SIG_EXPR_LIST_DECL_SINGLE(other, other); \
- MS_PIN_DECL_(pin, SIG_EXPR_LIST_PTR(sig), SIG_EXPR_LIST_PTR(other)); \
- FUNC_GROUP_DECL(sig, pin)
-
-#define GPIO_PIN_DECL(pin, gpio) \
- SIG_EXPR_LIST_DECL_SINGLE(gpio, gpio); \
- MS_PIN_DECL_(pin, SIG_EXPR_LIST_PTR(gpio))
+#include "pinmux-aspeed.h"
/**
* @param The pinconf parameter type
@@ -525,22 +28,6 @@ struct aspeed_pin_config {
u8 value;
};
-struct aspeed_pinctrl_data {
- struct regmap *maps[ASPEED_NR_PINMUX_IPS];
-
- const struct pinctrl_pin_desc *pins;
- const unsigned int npins;
-
- const struct aspeed_pin_group *groups;
- const unsigned int ngroups;
-
- const struct aspeed_pin_function *functions;
- const unsigned int nfunctions;
-
- const struct aspeed_pin_config *configs;
- const unsigned int nconfigs;
-};
-
#define ASPEED_PINCTRL_PIN(name_) \
[name_] = { \
.number = name_, \
@@ -548,30 +35,19 @@ struct aspeed_pinctrl_data {
.drv_data = (void *) &(PIN_SYM(name_)) \
}
-struct aspeed_pin_group {
- const char *name;
- const unsigned int *pins;
+struct aspeed_pinctrl_data {
+ struct regmap *scu;
+
+ const struct pinctrl_pin_desc *pins;
const unsigned int npins;
-};
-#define ASPEED_PINCTRL_GROUP(name_) { \
- .name = #name_, \
- .pins = &(PIN_GROUP_SYM(name_))[0], \
- .npins = ARRAY_SIZE(PIN_GROUP_SYM(name_)), \
-}
+ const struct aspeed_pin_config *configs;
+ const unsigned int nconfigs;
-struct aspeed_pin_function {
- const char *name;
- const char *const *groups;
- unsigned int ngroups;
+ struct aspeed_pinmux_data pinmux;
};
-#define ASPEED_PINCTRL_FUNC(name_, ...) { \
- .name = #name_, \
- .groups = &FUNC_GROUP_SYM(name_)[0], \
- .ngroups = ARRAY_SIZE(FUNC_GROUP_SYM(name_)), \
-}
-
+/* Aspeed pinctrl helpers */
int aspeed_pinctrl_get_groups_count(struct pinctrl_dev *pctldev);
const char *aspeed_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
unsigned int group);
diff --git a/drivers/pinctrl/aspeed/pinmux-aspeed.c b/drivers/pinctrl/aspeed/pinmux-aspeed.c
new file mode 100644
index 000000000000..5b0fe178ccf2
--- /dev/null
+++ b/drivers/pinctrl/aspeed/pinmux-aspeed.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Copyright (C) 2019 IBM Corp. */
+
+/* Pieces to enable drivers to implement the .set callback */
+
+#include "pinmux-aspeed.h"
+
+const char *const aspeed_pinmux_ips[] = {
+ [ASPEED_IP_SCU] = "SCU",
+ [ASPEED_IP_GFX] = "GFX",
+ [ASPEED_IP_LPC] = "LPC",
+};
+
+static inline void aspeed_sig_desc_print_val(
+ const struct aspeed_sig_desc *desc, bool enable, u32 rv)
+{
+ pr_debug("Want %s%X[0x%08X]=0x%X, got 0x%X from 0x%08X\n",
+ aspeed_pinmux_ips[desc->ip], desc->reg,
+ desc->mask, enable ? desc->enable : desc->disable,
+ (rv & desc->mask) >> __ffs(desc->mask), rv);
+}
+
+/**
+ * Query the enabled or disabled state of a signal descriptor
+ *
+ * @desc: The signal descriptor of interest
+ * @enabled: True to query the enabled state, false to query disabled state
+ * @map: The IP block's regmap instance
+ *
+ * Return: 1 if the descriptor's bitfield is configured to the state
+ * selected by @enabled, 0 if not, and less than zero if an unrecoverable
+ * failure occurred
+ *
+ * Evaluation of descriptor state is non-trivial in that it is not a binary
+ * outcome: The bitfields can be greater than one bit in size and thus can take
+ * a value that is neither the enabled nor disabled state recorded in the
+ * descriptor (typically this means a different function to the one of interest
+ * is enabled). Thus we must explicitly test for either condition as required.
+ */
+int aspeed_sig_desc_eval(const struct aspeed_sig_desc *desc,
+ bool enabled, struct regmap *map)
+{
+ int ret;
+ unsigned int raw;
+ u32 want;
+
+ if (!map)
+ return -ENODEV;
+
+ ret = regmap_read(map, desc->reg, &raw);
+ if (ret)
+ return ret;
+
+ aspeed_sig_desc_print_val(desc, enabled, raw);
+ want = enabled ? desc->enable : desc->disable;
+
+ return ((raw & desc->mask) >> __ffs(desc->mask)) == want;
+}
+
+/**
+ * Query the enabled or disabled state for a mux function's signal on a pin
+ *
+ * @ctx: The driver context for the pinctrl IP
+ * @expr: An expression controlling the signal for a mux function on a pin
+ * @enabled: True to query the enabled state, false to query disabled state
+ *
+ * Return: 1 if the expression composed by @enabled evaluates true, 0 if not,
+ * and less than zero if an unrecoverable failure occurred.
+ *
+ * A mux function is enabled or disabled if the function's signal expression
+ * for each pin in the function's pin group evaluates true for the desired
+ * state. An signal expression evaluates true if all of its associated signal
+ * descriptors evaluate true for the desired state.
+ *
+ * If an expression's state is described by more than one bit, either through
+ * multi-bit bitfields in a single signal descriptor or through multiple signal
+ * descriptors of a single bit then it is possible for the expression to be in
+ * neither the enabled nor disabled state. Thus we must explicitly test for
+ * either condition as required.
+ */
+int aspeed_sig_expr_eval(const struct aspeed_pinmux_data *ctx,
+ const struct aspeed_sig_expr *expr, bool enabled)
+{
+ int i;
+ int ret;
+
+ for (i = 0; i < expr->ndescs; i++) {
+ const struct aspeed_sig_desc *desc = &expr->descs[i];
+
+ ret = aspeed_sig_desc_eval(desc, enabled, ctx->maps[desc->ip]);
+ if (ret <= 0)
+ return ret;
+ }
+
+ return 1;
+}
diff --git a/drivers/pinctrl/aspeed/pinmux-aspeed.h b/drivers/pinctrl/aspeed/pinmux-aspeed.h
new file mode 100644
index 000000000000..329d54d48667
--- /dev/null
+++ b/drivers/pinctrl/aspeed/pinmux-aspeed.h
@@ -0,0 +1,735 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* Copyright (C) 2019 IBM Corp. */
+
+#ifndef ASPEED_PINMUX_H
+#define ASPEED_PINMUX_H
+
+#include <linux/regmap.h>
+#include <stdbool.h>
+
+/*
+ * The ASPEED SoCs provide typically more than 200 pins for GPIO and other
+ * functions. The SoC function enabled on a pin is determined on a priority
+ * basis where a given pin can provide a number of different signal types.
+ *
+ * The signal active on a pin is described by both a priority level and
+ * compound logical expressions involving multiple operators, registers and
+ * bits. Some difficulty arises as the pin's function bit masks for each
+ * priority level are frequently not the same (i.e. cannot just flip a bit to
+ * change from a high to low priority signal), or even in the same register.
+ * Further, not all signals can be unmuxed, as some expressions depend on
+ * values in the hardware strapping register (which may be treated as
+ * read-only).
+ *
+ * SoC Multi-function Pin Expression Examples
+ * ------------------------------------------
+ *
+ * Here are some sample mux configurations from the AST2400 and AST2500
+ * datasheets to illustrate the corner cases, roughly in order of least to most
+ * corner. The signal priorities are in decending order from P0 (highest).
+ *
+ * D6 is a pin with a single function (beside GPIO); a high priority signal
+ * that participates in one function:
+ *
+ * Ball | Default | P0 Signal | P0 Expression | P1 Signal | P1 Expression | Other
+ * -----+---------+-----------+-----------------------------+-----------+---------------+----------
+ * D6 GPIOA0 MAC1LINK SCU80[0]=1 GPIOA0
+ * -----+---------+-----------+-----------------------------+-----------+---------------+----------
+ *
+ * C5 is a multi-signal pin (high and low priority signals). Here we touch
+ * different registers for the different functions that enable each signal:
+ *
+ * -----+---------+-----------+-----------------------------+-----------+---------------+----------
+ * C5 GPIOA4 SCL9 SCU90[22]=1 TIMER5 SCU80[4]=1 GPIOA4
+ * -----+---------+-----------+-----------------------------+-----------+---------------+----------
+ *
+ * E19 is a single-signal pin with two functions that influence the active
+ * signal. In this case both bits have the same meaning - enable a dedicated
+ * LPC reset pin. However it's not always the case that the bits in the
+ * OR-relationship have the same meaning.
+ *
+ * -----+---------+-----------+-----------------------------+-----------+---------------+----------
+ * E19 GPIOB4 LPCRST# SCU80[12]=1 | Strap[14]=1 GPIOB4
+ * -----+---------+-----------+-----------------------------+-----------+---------------+----------
+ *
+ * For example, pin B19 has a low-priority signal that's enabled by two
+ * distinct SoC functions: A specific SIOPBI bit in register SCUA4, and an ACPI
+ * bit in the STRAP register. The ACPI bit configures signals on pins in
+ * addition to B19. Both of the low priority functions as well as the high
+ * priority function must be disabled for GPIOF1 to be used.
+ *
+ * Ball | Default | P0 Signal | P0 Expression | P1 Signal | P1 Expression | Other
+ * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+----------
+ * B19 GPIOF1 NDCD4 SCU80[25]=1 SIOPBI# SCUA4[12]=1 | Strap[19]=0 GPIOF1
+ * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+----------
+ *
+ * For pin E18, the SoC ANDs the expected state of three bits to determine the
+ * pin's active signal:
+ *
+ * * SCU3C[3]: Enable external SOC reset function
+ * * SCU80[15]: Enable SPICS1# or EXTRST# function pin
+ * * SCU90[31]: Select SPI interface CS# output
+ *
+ * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+----------
+ * E18 GPIOB7 EXTRST# SCU3C[3]=1 & SCU80[15]=1 & SCU90[31]=0 SPICS1# SCU3C[3]=1 & SCU80[15]=1 & SCU90[31]=1 GPIOB7
+ * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+----------
+ *
+ * (Bits SCU3C[3] and SCU80[15] appear to only be used in the expressions for
+ * selecting the signals on pin E18)
+ *
+ * Pin T5 is a multi-signal pin with a more complex configuration:
+ *
+ * Ball | Default | P0 Signal | P0 Expression | P1 Signal | P1 Expression | Other
+ * -----+---------+-----------+------------------------------+-----------+---------------+----------
+ * T5 GPIOL1 VPIDE SCU90[5:4]!=0 & SCU84[17]=1 NDCD1 SCU84[17]=1 GPIOL1
+ * -----+---------+-----------+------------------------------+-----------+---------------+----------
+ *
+ * The high priority signal configuration is best thought of in terms of its
+ * exploded form, with reference to the SCU90[5:4] bits:
+ *
+ * * SCU90[5:4]=00: disable
+ * * SCU90[5:4]=01: 18 bits (R6/G6/B6) video mode.
+ * * SCU90[5:4]=10: 24 bits (R8/G8/B8) video mode.
+ * * SCU90[5:4]=11: 30 bits (R10/G10/B10) video mode.
+ *
+ * Re-writing:
+ *
+ * -----+---------+-----------+------------------------------+-----------+---------------+----------
+ * T5 GPIOL1 VPIDE (SCU90[5:4]=1 & SCU84[17]=1) NDCD1 SCU84[17]=1 GPIOL1
+ * | (SCU90[5:4]=2 & SCU84[17]=1)
+ * | (SCU90[5:4]=3 & SCU84[17]=1)
+ * -----+---------+-----------+------------------------------+-----------+---------------+----------
+ *
+ * For reference the SCU84[17] bit configure the "UART1 NDCD1 or Video VPIDE
+ * function pin", where the signal itself is determined by whether SCU94[5:4]
+ * is disabled or in one of the 18, 24 or 30bit video modes.
+ *
+ * Other video-input-related pins require an explicit state in SCU90[5:4], e.g.
+ * W1 and U5:
+ *
+ * -----+---------+-----------+------------------------------+-----------+---------------+----------
+ * W1 GPIOL6 VPIB0 SCU90[5:4]=3 & SCU84[22]=1 TXD1 SCU84[22]=1 GPIOL6
+ * U5 GPIOL7 VPIB1 SCU90[5:4]=3 & SCU84[23]=1 RXD1 SCU84[23]=1 GPIOL7
+ * -----+---------+-----------+------------------------------+-----------+---------------+----------
+ *
+ * The examples of T5 and W1 are particularly fertile, as they also demonstrate
+ * that despite operating as part of the video input bus each signal needs to
+ * be enabled individually via it's own SCU84 (in the cases of T5 and W1)
+ * register bit. This is a little crazy if the bus doesn't have optional
+ * signals, but is used to decent effect with some of the UARTs where not all
+ * signals are required. However, this isn't done consistently - UART1 is
+ * enabled on a per-pin basis, and by contrast, all signals for UART6 are
+ * enabled by a single bit.
+ *
+ * Further, the high and low priority signals listed in the table above share
+ * a configuration bit. The VPI signals should operate in concert in a single
+ * function, but the UART signals should retain the ability to be configured
+ * independently. This pushes the implementation down the path of tagging a
+ * signal's expressions with the function they participate in, rather than
+ * defining masks affecting multiple signals per function. The latter approach
+ * fails in this instance where applying the configuration for the UART pin of
+ * interest will stomp on the state of other UART signals when disabling the
+ * VPI functions on the current pin.
+ *
+ * Ball | Default | P0 Signal | P0 Expression | P1 Signal | P1 Expression | Other
+ * -----+------------+-----------+---------------------------+-----------+---------------+------------
+ * A12 RGMII1TXCK GPIOT0 SCUA0[0]=1 RMII1TXEN Strap[6]=0 RGMII1TXCK
+ * B12 RGMII1TXCTL GPIOT1 SCUA0[1]=1 – Strap[6]=0 RGMII1TXCTL
+ * -----+------------+-----------+---------------------------+-----------+---------------+------------
+ *
+ * A12 demonstrates that the "Other" signal isn't always GPIO - in this case
+ * GPIOT0 is a high-priority signal and RGMII1TXCK is Other. Thus, GPIO
+ * should be treated like any other signal type with full function expression
+ * requirements, and not assumed to be the default case. Separately, GPIOT0 and
+ * GPIOT1's signal descriptor bits are distinct, therefore we must iterate all
+ * pins in the function's group to disable the higher-priority signals such
+ * that the signal for the function of interest is correctly enabled.
+ *
+ * Finally, three priority levels aren't always enough; the AST2500 brings with
+ * it 18 pins of five priority levels, however the 18 pins only use three of
+ * the five priority levels.
+ *
+ * Ultimately the requirement to control pins in the examples above drive the
+ * design:
+ *
+ * * Pins provide signals according to functions activated in the mux
+ * configuration
+ *
+ * * Pins provide up to five signal types in a priority order
+ *
+ * * For priorities levels defined on a pin, each priority provides one signal
+ *
+ * * Enabling lower priority signals requires higher priority signals be
+ * disabled
+ *
+ * * A function represents a set of signals; functions are distinct if their
+ * sets of signals are not equal
+ *
+ * * Signals participate in one or more functions
+ *
+ * * A function is described by an expression of one or more signal
+ * descriptors, which compare bit values in a register
+ *
+ * * A signal expression is the smallest set of signal descriptors whose
+ * comparisons must evaluate 'true' for a signal to be enabled on a pin.
+ *
+ * * A signal participating in a function is active on a pin if evaluating all
+ * signal descriptors in the pin's signal expression for the function yields
+ * a 'true' result
+ *
+ * * A signal at a given priority on a given pin is active if any of the
+ * functions in which the signal participates are active, and no higher
+ * priority signal on the pin is active
+ *
+ * * GPIO is configured per-pin
+ *
+ * And so:
+ *
+ * * To disable a signal, any function(s) activating the signal must be
+ * disabled
+ *
+ * * Each pin must know the signal expressions of functions in which it
+ * participates, for the purpose of enabling the Other function. This is done
+ * by deactivating all functions that activate higher priority signals on the
+ * pin.
+ *
+ * As a concrete example:
+ *
+ * * T5 provides three signals types: VPIDE, NDCD1 and GPIO
+ *
+ * * The VPIDE signal participates in 3 functions: VPI18, VPI24 and VPI30
+ *
+ * * The NDCD1 signal participates in just its own NDCD1 function
+ *
+ * * VPIDE is high priority, NDCD1 is low priority, and GPIOL1 is the least
+ * prioritised
+ *
+ * * The prerequisit for activating the NDCD1 signal is that the VPI18, VPI24
+ * and VPI30 functions all be disabled
+ *
+ * * Similarly, all of VPI18, VPI24, VPI30 and NDCD1 functions must be disabled
+ * to provide GPIOL6
+ *
+ * Considerations
+ * --------------
+ *
+ * If pinctrl allows us to allocate a pin we can configure a function without
+ * concern for the function of already allocated pins, if pin groups are
+ * created with respect to the SoC functions in which they participate. This is
+ * intuitive, but it did not feel obvious from the bit/pin relationships.
+ *
+ * Conversely, failing to allocate all pins in a group indicates some bits (as
+ * well as pins) required for the group's configuration will already be in use,
+ * likely in a way that's inconsistent with the requirements of the failed
+ * group.
+ *
+ * Implementation
+ * --------------
+ *
+ * Beyond the documentation below the various structures and helper macros that
+ * allow the implementation to hang together are defined. The macros are fairly
+ * dense, so below we walk through some raw examples of the configuration
+ * tables in an effort to clarify the concepts.
+ *
+ * The complexity of configuring the mux combined with the scale of the pins
+ * and functions was a concern, so the table design along with the macro jungle
+ * is an attempt to address it. The rough principles of the approach are:
+ *
+ * 1. Use a data-driven solution rather than embedding state into code
+ * 2. Minimise editing to the specifics of the given mux configuration
+ * 3. Detect as many errors as possible at compile time
+ *
+ * Addressing point 3 leads to naming of symbols in terms of the four
+ * properties associated with a given mux configuration: The pin, the signal,
+ * the group and the function. In this way copy/paste errors cause duplicate
+ * symbols to be defined, which prevents successful compilation. Failing to
+ * properly parent the tables leads to unused symbol warnings, and use of
+ * designated initialisers and additional warnings ensures that there are
+ * no override errors in the pin, group and function arrays.
+ *
+ * Addressing point 2 drives the development of the macro jungle, as it
+ * centralises the definition noise at the cost of taking some time to
+ * understand.
+ *
+ * Here's a complete, concrete "pre-processed" example of the table structures
+ * used to describe the D6 ball from the examples above:
+ *
+ * ```
+ * static const struct aspeed_sig_desc sig_descs_MAC1LINK_MAC1LINK[] = {
+ * {
+ * .ip = ASPEED_IP_SCU,
+ * .reg = 0x80,
+ * .mask = BIT(0),
+ * .enable = 1,
+ * .disable = 0
+ * },
+ * };
+ *
+ * static const struct aspeed_sig_expr sig_expr_MAC1LINK_MAC1LINK = {
+ * .signal = "MAC1LINK",
+ * .function = "MAC1LINK",
+ * .ndescs = ARRAY_SIZE(sig_descs_MAC1LINK_MAC1LINK),
+ * .descs = &(sig_descs_MAC1LINK_MAC1LINK)[0],
+ * };
+ *
+ * static const struct aspeed_sig_expr *sig_exprs_MAC1LINK_MAC1LINK[] = {
+ * &sig_expr_MAC1LINK_MAC1LINK,
+ * NULL,
+ * };
+ *
+ * static const struct aspeed_sig_desc sig_descs_GPIOA0_GPIOA0[] = { };
+ *
+ * static const struct aspeed_sig_expr sig_expr_GPIOA0_GPIOA0 = {
+ * .signal = "GPIOA0",
+ * .function = "GPIOA0",
+ * .ndescs = ARRAY_SIZE(sig_descs_GPIOA0_GPIOA0),
+ * .descs = &(sig_descs_GPIOA0_GPIOA0)[0],
+ * };
+ *
+ * static const struct aspeed_sig_expr *sig_exprs_GPIOA0_GPIOA0[] = {
+ * &sig_expr_GPIOA0_GPIOA0,
+ * NULL
+ * };
+ *
+ * static const struct aspeed_sig_expr **pin_exprs_0[] = {
+ * sig_exprs_MAC1LINK_MAC1LINK,
+ * sig_exprs_GPIOA0_GPIOA0,
+ * NULL
+ * };
+ *
+ * static const struct aspeed_pin_desc pin_0 = { "0", (&pin_exprs_0[0]) };
+ * static const int group_pins_MAC1LINK[] = { 0 };
+ * static const char *func_groups_MAC1LINK[] = { "MAC1LINK" };
+ *
+ * static struct pinctrl_pin_desc aspeed_g4_pins[] = {
+ * [0] = { .number = 0, .name = "D6", .drv_data = &pin_0 },
+ * };
+ *
+ * static const struct aspeed_pin_group aspeed_g4_groups[] = {
+ * {
+ * .name = "MAC1LINK",
+ * .pins = &(group_pins_MAC1LINK)[0],
+ * .npins = ARRAY_SIZE(group_pins_MAC1LINK),
+ * },
+ * };
+ *
+ * static const struct aspeed_pin_function aspeed_g4_functions[] = {
+ * {
+ * .name = "MAC1LINK",
+ * .groups = &func_groups_MAC1LINK[0],
+ * .ngroups = ARRAY_SIZE(func_groups_MAC1LINK),
+ * },
+ * };
+ * ```
+ *
+ * At the end of the day much of the above code is compressed into the
+ * following two lines:
+ *
+ * ```
+ * #define D6 0
+ * SSSF_PIN_DECL(D6, GPIOA0, MAC1LINK, SIG_DESC_SET(SCU80, 0));
+ * ```
+ *
+ * The two examples below show just the differences from the example above.
+ *
+ * Ball E18 demonstrates a function, EXTRST, that requires multiple descriptors
+ * be set for it to be muxed:
+ *
+ * ```
+ * static const struct aspeed_sig_desc sig_descs_EXTRST_EXTRST[] = {
+ * {
+ * .ip = ASPEED_IP_SCU,
+ * .reg = 0x3C,
+ * .mask = BIT(3),
+ * .enable = 1,
+ * .disable = 0
+ * },
+ * {
+ * .ip = ASPEED_IP_SCU,
+ * .reg = 0x80,
+ * .mask = BIT(15),
+ * .enable = 1,
+ * .disable = 0
+ * },
+ * {
+ * .ip = ASPEED_IP_SCU,
+ * .reg = 0x90,
+ * .mask = BIT(31),
+ * .enable = 0,
+ * .disable = 1
+ * },
+ * };
+ *
+ * static const struct aspeed_sig_expr sig_expr_EXTRST_EXTRST = {
+ * .signal = "EXTRST",
+ * .function = "EXTRST",
+ * .ndescs = ARRAY_SIZE(sig_descs_EXTRST_EXTRST),
+ * .descs = &(sig_descs_EXTRST_EXTRST)[0],
+ * };
+ * ...
+ * ```
+ *
+ * For ball E19, we have multiple functions enabling a single signal, LPCRST#.
+ * The data structures look like:
+ *
+ * static const struct aspeed_sig_desc sig_descs_LPCRST_LPCRST[] = {
+ * {
+ * .ip = ASPEED_IP_SCU,
+ * .reg = 0x80,
+ * .mask = BIT(12),
+ * .enable = 1,
+ * .disable = 0
+ * },
+ * };
+ *
+ * static const struct aspeed_sig_expr sig_expr_LPCRST_LPCRST = {
+ * .signal = "LPCRST",
+ * .function = "LPCRST",
+ * .ndescs = ARRAY_SIZE(sig_descs_LPCRST_LPCRST),
+ * .descs = &(sig_descs_LPCRST_LPCRST)[0],
+ * };
+ *
+ * static const struct aspeed_sig_desc sig_descs_LPCRST_LPCRSTS[] = {
+ * {
+ * .ip = ASPEED_IP_SCU,
+ * .reg = 0x70,
+ * .mask = BIT(14),
+ * .enable = 1,
+ * .disable = 0
+ * },
+ * };
+ *
+ * static const struct aspeed_sig_expr sig_expr_LPCRST_LPCRSTS = {
+ * .signal = "LPCRST",
+ * .function = "LPCRSTS",
+ * .ndescs = ARRAY_SIZE(sig_descs_LPCRST_LPCRSTS),
+ * .descs = &(sig_descs_LPCRST_LPCRSTS)[0],
+ * };
+ *
+ * static const struct aspeed_sig_expr *sig_exprs_LPCRST_LPCRST[] = {
+ * &sig_expr_LPCRST_LPCRST,
+ * &sig_expr_LPCRST_LPCRSTS,
+ * NULL,
+ * };
+ * ...
+ * ```
+ *
+ * Both expressions listed in the sig_exprs_LPCRST_LPCRST array need to be set
+ * to disabled for the associated GPIO to be muxed.
+ *
+ */
+
+#define ASPEED_IP_SCU 0
+#define ASPEED_IP_GFX 1
+#define ASPEED_IP_LPC 2
+#define ASPEED_NR_PINMUX_IPS 3
+
+ /**
+ * A signal descriptor, which describes the register, bits and the
+ * enable/disable values that should be compared or written.
+ *
+ * @ip: The IP block identifier, used as an index into the regmap array in
+ * struct aspeed_pinctrl_data
+ * @reg: The register offset with respect to the base address of the IP block
+ * @mask: The mask to apply to the register. The lowest set bit of the mask is
+ * used to derive the shift value.
+ * @enable: The value that enables the function. Value should be in the LSBs,
+ * not at the position of the mask.
+ * @disable: The value that disables the function. Value should be in the
+ * LSBs, not at the position of the mask.
+ */
+struct aspeed_sig_desc {
+ unsigned int ip;
+ unsigned int reg;
+ u32 mask;
+ u32 enable;
+ u32 disable;
+};
+
+/**
+ * Describes a signal expression. The expression is evaluated by ANDing the
+ * evaluation of the descriptors.
+ *
+ * @signal: The signal name for the priority level on the pin. If the signal
+ * type is GPIO, then the signal name must begin with the string
+ * "GPIO", e.g. GPIOA0, GPIOT4 etc.
+ * @function: The name of the function the signal participates in for the
+ * associated expression
+ * @ndescs: The number of signal descriptors in the expression
+ * @descs: Pointer to an array of signal descriptors that comprise the
+ * function expression
+ */
+struct aspeed_sig_expr {
+ const char *signal;
+ const char *function;
+ int ndescs;
+ const struct aspeed_sig_desc *descs;
+};
+
+/**
+ * A struct capturing the list of expressions enabling signals at each priority
+ * for a given pin. The signal configuration for a priority level is evaluated
+ * by ORing the evaluation of the signal expressions in the respective
+ * priority's list.
+ *
+ * @name: A name for the pin
+ * @prios: A pointer to an array of expression list pointers
+ *
+ */
+struct aspeed_pin_desc {
+ const char *name;
+ const struct aspeed_sig_expr ***prios;
+};
+
+/* Macro hell */
+
+#define SIG_DESC_IP_BIT(ip, reg, idx, val) \
+ { ip, reg, BIT_MASK(idx), val, (((val) + 1) & 1) }
+
+/**
+ * Short-hand macro for describing an SCU descriptor enabled by the state of
+ * one bit. The disable value is derived.
+ *
+ * @reg: The signal's associated register, offset from base
+ * @idx: The signal's bit index in the register
+ * @val: The value (0 or 1) that enables the function
+ */
+#define SIG_DESC_BIT(reg, idx, val) \
+ SIG_DESC_IP_BIT(ASPEED_IP_SCU, reg, idx, val)
+
+#define SIG_DESC_IP_SET(ip, reg, idx) SIG_DESC_IP_BIT(ip, reg, idx, 1)
+
+/**
+ * A further short-hand macro expanding to an SCU descriptor enabled by a set
+ * bit.
+ *
+ * @reg: The register, offset from base
+ * @idx: The bit index in the register
+ */
+#define SIG_DESC_SET(reg, idx) SIG_DESC_IP_BIT(ASPEED_IP_SCU, reg, idx, 1)
+
+#define SIG_DESC_LIST_SYM(sig, func) sig_descs_ ## sig ## _ ## func
+#define SIG_DESC_LIST_DECL(sig, func, ...) \
+ static const struct aspeed_sig_desc SIG_DESC_LIST_SYM(sig, func)[] = \
+ { __VA_ARGS__ }
+
+#define SIG_EXPR_SYM(sig, func) sig_expr_ ## sig ## _ ## func
+#define SIG_EXPR_DECL_(sig, func) \
+ static const struct aspeed_sig_expr SIG_EXPR_SYM(sig, func) = \
+ { \
+ .signal = #sig, \
+ .function = #func, \
+ .ndescs = ARRAY_SIZE(SIG_DESC_LIST_SYM(sig, func)), \
+ .descs = &(SIG_DESC_LIST_SYM(sig, func))[0], \
+ }
+
+/**
+ * Declare a signal expression.
+ *
+ * @sig: A macro symbol name for the signal (is subjected to stringification
+ * and token pasting)
+ * @func: The function in which the signal is participating
+ * @...: Signal descriptors that define the signal expression
+ *
+ * For example, the following declares the ROMD8 signal for the ROM16 function:
+ *
+ * SIG_EXPR_DECL(ROMD8, ROM16, SIG_DESC_SET(SCU90, 6));
+ *
+ * And with multiple signal descriptors:
+ *
+ * SIG_EXPR_DECL(ROMD8, ROM16S, SIG_DESC_SET(HW_STRAP1, 4),
+ * { HW_STRAP1, GENMASK(1, 0), 0, 0 });
+ */
+#define SIG_EXPR_DECL(sig, func, ...) \
+ SIG_DESC_LIST_DECL(sig, func, __VA_ARGS__); \
+ SIG_EXPR_DECL_(sig, func)
+
+/**
+ * Declare a pointer to a signal expression
+ *
+ * @sig: The macro symbol name for the signal (subjected to token pasting)
+ * @func: The macro symbol name for the function (subjected to token pasting)
+ */
+#define SIG_EXPR_PTR(sig, func) (&SIG_EXPR_SYM(sig, func))
+
+#define SIG_EXPR_LIST_SYM(sig) sig_exprs_ ## sig
+
+/**
+ * Declare a signal expression list for reference in a struct aspeed_pin_prio.
+ *
+ * @sig: A macro symbol name for the signal (is subjected to token pasting)
+ * @...: Signal expression structure pointers (use SIG_EXPR_PTR())
+ *
+ * For example, the 16-bit ROM bus can be enabled by one of two possible signal
+ * expressions:
+ *
+ * SIG_EXPR_DECL(ROMD8, ROM16, SIG_DESC_SET(SCU90, 6));
+ * SIG_EXPR_DECL(ROMD8, ROM16S, SIG_DESC_SET(HW_STRAP1, 4),
+ * { HW_STRAP1, GENMASK(1, 0), 0, 0 });
+ * SIG_EXPR_LIST_DECL(ROMD8, SIG_EXPR_PTR(ROMD8, ROM16),
+ * SIG_EXPR_PTR(ROMD8, ROM16S));
+ */
+#define SIG_EXPR_LIST_DECL(sig, ...) \
+ static const struct aspeed_sig_expr *SIG_EXPR_LIST_SYM(sig)[] = \
+ { __VA_ARGS__, NULL }
+
+/**
+ * A short-hand macro for declaring a function expression and an expression
+ * list with a single function.
+ *
+ * @func: A macro symbol name for the function (is subjected to token pasting)
+ * @...: Function descriptors that define the function expression
+ *
+ * For example, signal NCTS6 participates in its own function with one group:
+ *
+ * SIG_EXPR_LIST_DECL_SINGLE(NCTS6, NCTS6, SIG_DESC_SET(SCU90, 7));
+ */
+#define SIG_EXPR_LIST_DECL_SINGLE(sig, func, ...) \
+ SIG_DESC_LIST_DECL(sig, func, __VA_ARGS__); \
+ SIG_EXPR_DECL_(sig, func); \
+ SIG_EXPR_LIST_DECL(sig, SIG_EXPR_PTR(sig, func))
+
+#define SIG_EXPR_LIST_DECL_DUAL(sig, f0, f1) \
+ SIG_EXPR_LIST_DECL(sig, SIG_EXPR_PTR(sig, f0), SIG_EXPR_PTR(sig, f1))
+
+#define SIG_EXPR_LIST_PTR(sig) (&SIG_EXPR_LIST_SYM(sig)[0])
+
+#define PIN_EXPRS_SYM(pin) pin_exprs_ ## pin
+#define PIN_EXPRS_PTR(pin) (&PIN_EXPRS_SYM(pin)[0])
+#define PIN_SYM(pin) pin_ ## pin
+
+#define MS_PIN_DECL_(pin, ...) \
+ static const struct aspeed_sig_expr **PIN_EXPRS_SYM(pin)[] = \
+ { __VA_ARGS__, NULL }; \
+ static const struct aspeed_pin_desc PIN_SYM(pin) = \
+ { #pin, PIN_EXPRS_PTR(pin) }
+
+/**
+ * Declare a multi-signal pin
+ *
+ * @pin: The pin number
+ * @other: Macro name for "other" functionality (subjected to stringification)
+ * @high: Macro name for the highest priority signal functions
+ * @low: Macro name for the low signal functions
+ *
+ * For example:
+ *
+ * #define A8 56
+ * SIG_EXPR_DECL(ROMD8, ROM16, SIG_DESC_SET(SCU90, 6));
+ * SIG_EXPR_DECL(ROMD8, ROM16S, SIG_DESC_SET(HW_STRAP1, 4),
+ * { HW_STRAP1, GENMASK(1, 0), 0, 0 });
+ * SIG_EXPR_LIST_DECL(ROMD8, SIG_EXPR_PTR(ROMD8, ROM16),
+ * SIG_EXPR_PTR(ROMD8, ROM16S));
+ * SIG_EXPR_LIST_DECL_SINGLE(NCTS6, NCTS6, SIG_DESC_SET(SCU90, 7));
+ * MS_PIN_DECL(A8, GPIOH0, ROMD8, NCTS6);
+ */
+#define MS_PIN_DECL(pin, other, high, low) \
+ SIG_EXPR_LIST_DECL_SINGLE(other, other); \
+ MS_PIN_DECL_(pin, \
+ SIG_EXPR_LIST_PTR(high), \
+ SIG_EXPR_LIST_PTR(low), \
+ SIG_EXPR_LIST_PTR(other))
+
+#define PIN_GROUP_SYM(func) pins_ ## func
+#define FUNC_GROUP_SYM(func) groups_ ## func
+#define FUNC_GROUP_DECL(func, ...) \
+ static const int PIN_GROUP_SYM(func)[] = { __VA_ARGS__ }; \
+ static const char *FUNC_GROUP_SYM(func)[] = { #func }
+
+/**
+ * Declare a single signal pin
+ *
+ * @pin: The pin number
+ * @other: Macro name for "other" functionality (subjected to stringification)
+ * @sig: Macro name for the signal (subjected to stringification)
+ *
+ * For example:
+ *
+ * #define E3 80
+ * SIG_EXPR_LIST_DECL_SINGLE(SCL5, I2C5, I2C5_DESC);
+ * SS_PIN_DECL(E3, GPIOK0, SCL5);
+ */
+#define SS_PIN_DECL(pin, other, sig) \
+ SIG_EXPR_LIST_DECL_SINGLE(other, other); \
+ MS_PIN_DECL_(pin, SIG_EXPR_LIST_PTR(sig), SIG_EXPR_LIST_PTR(other))
+
+/**
+ * Single signal, single function pin declaration
+ *
+ * @pin: The pin number
+ * @other: Macro name for "other" functionality (subjected to stringification)
+ * @sig: Macro name for the signal (subjected to stringification)
+ * @...: Signal descriptors that define the function expression
+ *
+ * For example:
+ *
+ * SSSF_PIN_DECL(A4, GPIOA2, TIMER3, SIG_DESC_SET(SCU80, 2));
+ */
+#define SSSF_PIN_DECL(pin, other, sig, ...) \
+ SIG_EXPR_LIST_DECL_SINGLE(sig, sig, __VA_ARGS__); \
+ SIG_EXPR_LIST_DECL_SINGLE(other, other); \
+ MS_PIN_DECL_(pin, SIG_EXPR_LIST_PTR(sig), SIG_EXPR_LIST_PTR(other)); \
+ FUNC_GROUP_DECL(sig, pin)
+
+#define GPIO_PIN_DECL(pin, gpio) \
+ SIG_EXPR_LIST_DECL_SINGLE(gpio, gpio); \
+ MS_PIN_DECL_(pin, SIG_EXPR_LIST_PTR(gpio))
+
+struct aspeed_pin_group {
+ const char *name;
+ const unsigned int *pins;
+ const unsigned int npins;
+};
+
+#define ASPEED_PINCTRL_GROUP(name_) { \
+ .name = #name_, \
+ .pins = &(PIN_GROUP_SYM(name_))[0], \
+ .npins = ARRAY_SIZE(PIN_GROUP_SYM(name_)), \
+}
+
+struct aspeed_pin_function {
+ const char *name;
+ const char *const *groups;
+ unsigned int ngroups;
+};
+
+#define ASPEED_PINCTRL_FUNC(name_, ...) { \
+ .name = #name_, \
+ .groups = &FUNC_GROUP_SYM(name_)[0], \
+ .ngroups = ARRAY_SIZE(FUNC_GROUP_SYM(name_)), \
+}
+
+struct aspeed_pinmux_data;
+
+struct aspeed_pinmux_ops {
+ int (*set)(const struct aspeed_pinmux_data *ctx,
+ const struct aspeed_sig_expr *expr, bool enabled);
+};
+
+struct aspeed_pinmux_data {
+ struct regmap *maps[ASPEED_NR_PINMUX_IPS];
+
+ const struct aspeed_pinmux_ops *ops;
+
+ const struct aspeed_pin_group *groups;
+ const unsigned int ngroups;
+
+ const struct aspeed_pin_function *functions;
+ const unsigned int nfunctions;
+};
+
+int aspeed_sig_desc_eval(const struct aspeed_sig_desc *desc, bool enabled,
+ struct regmap *map);
+
+int aspeed_sig_expr_eval(const struct aspeed_pinmux_data *ctx,
+ const struct aspeed_sig_expr *expr,
+ bool enabled);
+
+static inline int aspeed_sig_expr_set(const struct aspeed_pinmux_data *ctx,
+ const struct aspeed_sig_expr *expr,
+ bool enabled)
+{
+ return ctx->ops->set(ctx, expr, enabled);
+}
+
+#endif /* ASPEED_PINMUX_H */
diff --git a/drivers/pinctrl/bcm/Kconfig b/drivers/pinctrl/bcm/Kconfig
index 97284c3f9e83..dcf7df797af7 100644
--- a/drivers/pinctrl/bcm/Kconfig
+++ b/drivers/pinctrl/bcm/Kconfig
@@ -18,11 +18,15 @@ config PINCTRL_BCM281XX
framework. GPIO is provided by a separate GPIO driver.
config PINCTRL_BCM2835
- bool
+ bool "Broadcom BCM2835 GPIO (with PINCONF) driver"
+ depends on OF && (ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST)
select PINMUX
select PINCONF
select GENERIC_PINCONF
select GPIOLIB_IRQCHIP
+ default ARCH_BCM2835 || ARCH_BRCMSTB
+ help
+ Say Y here to enable the Broadcom BCM2835 GPIO driver.
config PINCTRL_IPROC_GPIO
bool "Broadcom iProc GPIO (with PINCONF) driver"
diff --git a/drivers/pinctrl/bcm/pinctrl-ns2-mux.c b/drivers/pinctrl/bcm/pinctrl-ns2-mux.c
index 4b5cf0e0f16e..2bf6af7df7d9 100644
--- a/drivers/pinctrl/bcm/pinctrl-ns2-mux.c
+++ b/drivers/pinctrl/bcm/pinctrl-ns2-mux.c
@@ -1048,6 +1048,8 @@ static int ns2_pinmux_probe(struct platform_device *pdev)
return PTR_ERR(pinctrl->base0);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res)
+ return -EINVAL;
pinctrl->base1 = devm_ioremap_nocache(&pdev->dev, res->start,
resource_size(res));
if (!pinctrl->base1) {
diff --git a/drivers/pinctrl/cirrus/pinctrl-cs47l35.c b/drivers/pinctrl/cirrus/pinctrl-cs47l35.c
index 06b59160783d..53a8eab19aad 100644
--- a/drivers/pinctrl/cirrus/pinctrl-cs47l35.c
+++ b/drivers/pinctrl/cirrus/pinctrl-cs47l35.c
@@ -1,12 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Pinctrl for Cirrus Logic CS47L35
*
* Copyright (C) 2016-2017 Cirrus Logic
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by the
- * Free Software Foundation; version 2.
*/
#include <linux/err.h>
diff --git a/drivers/pinctrl/cirrus/pinctrl-cs47l85.c b/drivers/pinctrl/cirrus/pinctrl-cs47l85.c
index 0a322e2a0fde..e08c7992d252 100644
--- a/drivers/pinctrl/cirrus/pinctrl-cs47l85.c
+++ b/drivers/pinctrl/cirrus/pinctrl-cs47l85.c
@@ -1,12 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Pinctrl for Cirrus Logic CS47L85
*
* Copyright (C) 2016-2017 Cirrus Logic
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by the
- * Free Software Foundation; version 2.
*/
#include <linux/err.h>
diff --git a/drivers/pinctrl/cirrus/pinctrl-cs47l90.c b/drivers/pinctrl/cirrus/pinctrl-cs47l90.c
index fc38f579f492..3151f107adc4 100644
--- a/drivers/pinctrl/cirrus/pinctrl-cs47l90.c
+++ b/drivers/pinctrl/cirrus/pinctrl-cs47l90.c
@@ -1,12 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Pinctrl for Cirrus Logic CS47L90
*
* Copyright (C) 2016-2017 Cirrus Logic
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by the
- * Free Software Foundation; version 2.
*/
#include <linux/err.h>
diff --git a/drivers/pinctrl/cirrus/pinctrl-madera-core.c b/drivers/pinctrl/cirrus/pinctrl-madera-core.c
index 7c9694593f79..c6b9f65f2362 100644
--- a/drivers/pinctrl/cirrus/pinctrl-madera-core.c
+++ b/drivers/pinctrl/cirrus/pinctrl-madera-core.c
@@ -1,12 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Pinctrl for Cirrus Logic Madera codecs
*
* Copyright (C) 2016-2018 Cirrus Logic
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by the
- * Free Software Foundation; version 2.
*/
#include <linux/err.h>
diff --git a/drivers/pinctrl/cirrus/pinctrl-madera.h b/drivers/pinctrl/cirrus/pinctrl-madera.h
index 8000f4f832a1..4ae13918316f 100644
--- a/drivers/pinctrl/cirrus/pinctrl-madera.h
+++ b/drivers/pinctrl/cirrus/pinctrl-madera.h
@@ -1,12 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Pinctrl for Cirrus Logic Madera codecs
*
* Copyright (C) 2016-2017 Cirrus Logic
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by the
- * Free Software Foundation; version 2.
*/
#ifndef PINCTRL_MADERA_H
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index a64849a9d1b0..b70df27874d1 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -98,7 +98,7 @@ EXPORT_SYMBOL_GPL(pinctrl_dev_get_drvdata);
*/
struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *devname)
{
- struct pinctrl_dev *pctldev = NULL;
+ struct pinctrl_dev *pctldev;
if (!devname)
return NULL;
@@ -177,29 +177,6 @@ const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin)
return desc->name;
}
-/**
- * pin_is_valid() - check if pin exists on controller
- * @pctldev: the pin control device to check the pin on
- * @pin: pin to check, use the local pin controller index number
- *
- * This tells us whether a certain pin exist on a certain pin controller or
- * not. Pin lists may be sparse, so some pins may not exist.
- */
-bool pin_is_valid(struct pinctrl_dev *pctldev, int pin)
-{
- struct pin_desc *pindesc;
-
- if (pin < 0)
- return false;
-
- mutex_lock(&pctldev->mutex);
- pindesc = pin_desc_get(pctldev, pin);
- mutex_unlock(&pctldev->mutex);
-
- return pindesc != NULL;
-}
-EXPORT_SYMBOL_GPL(pin_is_valid);
-
/* Deletes a range of pin descriptors */
static void pinctrl_free_pindescs(struct pinctrl_dev *pctldev,
const struct pinctrl_pin_desc *pins,
@@ -311,7 +288,7 @@ static inline int gpio_to_pin(struct pinctrl_gpio_range *range,
static struct pinctrl_gpio_range *
pinctrl_match_gpio_range(struct pinctrl_dev *pctldev, unsigned gpio)
{
- struct pinctrl_gpio_range *range = NULL;
+ struct pinctrl_gpio_range *range;
mutex_lock(&pctldev->mutex);
/* Loop over the ranges */
@@ -391,7 +368,7 @@ static int pinctrl_get_device_gpio_range(unsigned gpio,
struct pinctrl_dev **outdev,
struct pinctrl_gpio_range **outrange)
{
- struct pinctrl_dev *pctldev = NULL;
+ struct pinctrl_dev *pctldev;
mutex_lock(&pinctrldev_list_mutex);
@@ -1215,6 +1192,15 @@ struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p,
}
EXPORT_SYMBOL_GPL(pinctrl_lookup_state);
+static void pinctrl_link_add(struct pinctrl_dev *pctldev,
+ struct device *consumer)
+{
+ if (pctldev->desc->link_consumers)
+ device_link_add(consumer, pctldev->dev,
+ DL_FLAG_PM_RUNTIME |
+ DL_FLAG_AUTOREMOVE_CONSUMER);
+}
+
/**
* pinctrl_commit_state() - select/activate/program a pinctrl state to HW
* @p: the pinctrl handle for the device that requests configuration
@@ -1260,6 +1246,10 @@ static int pinctrl_commit_state(struct pinctrl *p, struct pinctrl_state *state)
if (ret < 0) {
goto unapply_new_state;
}
+
+ /* Do not link hogs (circular dependency) */
+ if (p != setting->pctldev->p)
+ pinctrl_link_add(setting->pctldev, p->dev);
}
p->state = state;
@@ -1665,7 +1655,7 @@ DEFINE_SHOW_ATTRIBUTE(pinctrl_groups);
static int pinctrl_gpioranges_show(struct seq_file *s, void *what)
{
struct pinctrl_dev *pctldev = s->private;
- struct pinctrl_gpio_range *range = NULL;
+ struct pinctrl_gpio_range *range;
seq_puts(s, "GPIO ranges handled:\n");
diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c
index f7e354f85518..88ddbb2e30de 100644
--- a/drivers/pinctrl/devicetree.c
+++ b/drivers/pinctrl/devicetree.c
@@ -112,12 +112,11 @@ static int dt_to_map_one_config(struct pinctrl *p,
np_pctldev = of_get_next_parent(np_pctldev);
if (!np_pctldev || of_node_is_root(np_pctldev)) {
of_node_put(np_pctldev);
- ret = driver_deferred_probe_check_state(p->dev);
/* keep deferring if modules are enabled unless we've timed out */
- if (IS_ENABLED(CONFIG_MODULES) && !allow_default && ret == -ENODEV)
- ret = -EPROBE_DEFER;
+ if (IS_ENABLED(CONFIG_MODULES) && !allow_default)
+ return driver_deferred_probe_check_state_continue(p->dev);
- return ret;
+ return driver_deferred_probe_check_state(p->dev);
}
/* If we're creating a hog we can use the passed pctldev */
if (hog_pctldev && (np_pctldev == p->dev->of_node)) {
diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig
index aeab0d9af23e..5f4058033ec6 100644
--- a/drivers/pinctrl/freescale/Kconfig
+++ b/drivers/pinctrl/freescale/Kconfig
@@ -130,6 +130,13 @@ config PINCTRL_IMX8MM
help
Say Y here to enable the imx8mm pinctrl driver
+config PINCTRL_IMX8MN
+ bool "IMX8MN pinctrl driver"
+ depends on ARCH_MXC && ARM64
+ select PINCTRL_IMX
+ help
+ Say Y here to enable the imx8mn pinctrl driver
+
config PINCTRL_IMX8MQ
bool "IMX8MQ pinctrl driver"
depends on ARCH_MXC && ARM64
diff --git a/drivers/pinctrl/freescale/Makefile b/drivers/pinctrl/freescale/Makefile
index 02020a76bd9c..78e9140c13e3 100644
--- a/drivers/pinctrl/freescale/Makefile
+++ b/drivers/pinctrl/freescale/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_PINCTRL_IMX6UL) += pinctrl-imx6ul.o
obj-$(CONFIG_PINCTRL_IMX7D) += pinctrl-imx7d.o
obj-$(CONFIG_PINCTRL_IMX7ULP) += pinctrl-imx7ulp.o
obj-$(CONFIG_PINCTRL_IMX8MM) += pinctrl-imx8mm.o
+obj-$(CONFIG_PINCTRL_IMX8MN) += pinctrl-imx8mn.o
obj-$(CONFIG_PINCTRL_IMX8MQ) += pinctrl-imx8mq.o
obj-$(CONFIG_PINCTRL_IMX8QM) += pinctrl-imx8qm.o
obj-$(CONFIG_PINCTRL_IMX8QXP) += pinctrl-imx8qxp.o
diff --git a/drivers/pinctrl/freescale/pinctrl-imx8mn.c b/drivers/pinctrl/freescale/pinctrl-imx8mn.c
new file mode 100644
index 000000000000..100ed8c1039a
--- /dev/null
+++ b/drivers/pinctrl/freescale/pinctrl-imx8mn.c
@@ -0,0 +1,348 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2018-2019 NXP
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-imx.h"
+
+enum imx8mn_pads {
+ MX8MN_PAD_RESERVE0 = 0,
+ MX8MN_PAD_RESERVE1 = 1,
+ MX8MN_PAD_RESERVE2 = 2,
+ MX8MN_PAD_RESERVE3 = 3,
+ MX8MN_PAD_RESERVE4 = 4,
+ MX8MN_PAD_RESERVE5 = 5,
+ MX8MN_PAD_RESERVE6 = 6,
+ MX8MN_PAD_RESERVE7 = 7,
+ MX8MN_IOMUXC_BOOT_MODE2 = 8,
+ MX8MN_IOMUXC_BOOT_MODE3 = 9,
+ MX8MN_IOMUXC_GPIO1_IO00 = 10,
+ MX8MN_IOMUXC_GPIO1_IO01 = 11,
+ MX8MN_IOMUXC_GPIO1_IO02 = 12,
+ MX8MN_IOMUXC_GPIO1_IO03 = 13,
+ MX8MN_IOMUXC_GPIO1_IO04 = 14,
+ MX8MN_IOMUXC_GPIO1_IO05 = 15,
+ MX8MN_IOMUXC_GPIO1_IO06 = 16,
+ MX8MN_IOMUXC_GPIO1_IO07 = 17,
+ MX8MN_IOMUXC_GPIO1_IO08 = 18,
+ MX8MN_IOMUXC_GPIO1_IO09 = 19,
+ MX8MN_IOMUXC_GPIO1_IO10 = 20,
+ MX8MN_IOMUXC_GPIO1_IO11 = 21,
+ MX8MN_IOMUXC_GPIO1_IO12 = 22,
+ MX8MN_IOMUXC_GPIO1_IO13 = 23,
+ MX8MN_IOMUXC_GPIO1_IO14 = 24,
+ MX8MN_IOMUXC_GPIO1_IO15 = 25,
+ MX8MN_IOMUXC_ENET_MDC = 26,
+ MX8MN_IOMUXC_ENET_MDIO = 27,
+ MX8MN_IOMUXC_ENET_TD3 = 28,
+ MX8MN_IOMUXC_ENET_TD2 = 29,
+ MX8MN_IOMUXC_ENET_TD1 = 30,
+ MX8MN_IOMUXC_ENET_TD0 = 31,
+ MX8MN_IOMUXC_ENET_TX_CTL = 32,
+ MX8MN_IOMUXC_ENET_TXC = 33,
+ MX8MN_IOMUXC_ENET_RX_CTL = 34,
+ MX8MN_IOMUXC_ENET_RXC = 35,
+ MX8MN_IOMUXC_ENET_RD0 = 36,
+ MX8MN_IOMUXC_ENET_RD1 = 37,
+ MX8MN_IOMUXC_ENET_RD2 = 38,
+ MX8MN_IOMUXC_ENET_RD3 = 39,
+ MX8MN_IOMUXC_SD1_CLK = 40,
+ MX8MN_IOMUXC_SD1_CMD = 41,
+ MX8MN_IOMUXC_SD1_DATA0 = 42,
+ MX8MN_IOMUXC_SD1_DATA1 = 43,
+ MX8MN_IOMUXC_SD1_DATA2 = 44,
+ MX8MN_IOMUXC_SD1_DATA3 = 45,
+ MX8MN_IOMUXC_SD1_DATA4 = 46,
+ MX8MN_IOMUXC_SD1_DATA5 = 47,
+ MX8MN_IOMUXC_SD1_DATA6 = 48,
+ MX8MN_IOMUXC_SD1_DATA7 = 49,
+ MX8MN_IOMUXC_SD1_RESET_B = 50,
+ MX8MN_IOMUXC_SD1_STROBE = 51,
+ MX8MN_IOMUXC_SD2_CD_B = 52,
+ MX8MN_IOMUXC_SD2_CLK = 53,
+ MX8MN_IOMUXC_SD2_CMD = 54,
+ MX8MN_IOMUXC_SD2_DATA0 = 55,
+ MX8MN_IOMUXC_SD2_DATA1 = 56,
+ MX8MN_IOMUXC_SD2_DATA2 = 57,
+ MX8MN_IOMUXC_SD2_DATA3 = 58,
+ MX8MN_IOMUXC_SD2_RESET_B = 59,
+ MX8MN_IOMUXC_SD2_WP = 60,
+ MX8MN_IOMUXC_NAND_ALE = 61,
+ MX8MN_IOMUXC_NAND_CE0 = 62,
+ MX8MN_IOMUXC_NAND_CE1 = 63,
+ MX8MN_IOMUXC_NAND_CE2 = 64,
+ MX8MN_IOMUXC_NAND_CE3 = 65,
+ MX8MN_IOMUXC_NAND_CLE = 66,
+ MX8MN_IOMUXC_NAND_DATA00 = 67,
+ MX8MN_IOMUXC_NAND_DATA01 = 68,
+ MX8MN_IOMUXC_NAND_DATA02 = 69,
+ MX8MN_IOMUXC_NAND_DATA03 = 70,
+ MX8MN_IOMUXC_NAND_DATA04 = 71,
+ MX8MN_IOMUXC_NAND_DATA05 = 72,
+ MX8MN_IOMUXC_NAND_DATA06 = 73,
+ MX8MN_IOMUXC_NAND_DATA07 = 74,
+ MX8MN_IOMUXC_NAND_DQS = 75,
+ MX8MN_IOMUXC_NAND_RE_B = 76,
+ MX8MN_IOMUXC_NAND_READY_B = 77,
+ MX8MN_IOMUXC_NAND_WE_B = 78,
+ MX8MN_IOMUXC_NAND_WP_B = 79,
+ MX8MN_IOMUXC_SAI5_RXFS = 80,
+ MX8MN_IOMUXC_SAI5_RXC = 81,
+ MX8MN_IOMUXC_SAI5_RXD0 = 82,
+ MX8MN_IOMUXC_SAI5_RXD1 = 83,
+ MX8MN_IOMUXC_SAI5_RXD2 = 84,
+ MX8MN_IOMUXC_SAI5_RXD3 = 85,
+ MX8MN_IOMUXC_SAI5_MCLK = 86,
+ MX8MN_IOMUXC_SAI1_RXFS = 87,
+ MX8MN_IOMUXC_SAI1_RXC = 88,
+ MX8MN_IOMUXC_SAI1_RXD0 = 89,
+ MX8MN_IOMUXC_SAI1_RXD1 = 90,
+ MX8MN_IOMUXC_SAI1_RXD2 = 91,
+ MX8MN_IOMUXC_SAI1_RXD3 = 92,
+ MX8MN_IOMUXC_SAI1_RXD4 = 93,
+ MX8MN_IOMUXC_SAI1_RXD5 = 94,
+ MX8MN_IOMUXC_SAI1_RXD6 = 95,
+ MX8MN_IOMUXC_SAI1_RXD7 = 96,
+ MX8MN_IOMUXC_SAI1_TXFS = 97,
+ MX8MN_IOMUXC_SAI1_TXC = 98,
+ MX8MN_IOMUXC_SAI1_TXD0 = 99,
+ MX8MN_IOMUXC_SAI1_TXD1 = 100,
+ MX8MN_IOMUXC_SAI1_TXD2 = 101,
+ MX8MN_IOMUXC_SAI1_TXD3 = 102,
+ MX8MN_IOMUXC_SAI1_TXD4 = 103,
+ MX8MN_IOMUXC_SAI1_TXD5 = 104,
+ MX8MN_IOMUXC_SAI1_TXD6 = 105,
+ MX8MN_IOMUXC_SAI1_TXD7 = 106,
+ MX8MN_IOMUXC_SAI1_MCLK = 107,
+ MX8MN_IOMUXC_SAI2_RXFS = 108,
+ MX8MN_IOMUXC_SAI2_RXC = 109,
+ MX8MN_IOMUXC_SAI2_RXD0 = 110,
+ MX8MN_IOMUXC_SAI2_TXFS = 111,
+ MX8MN_IOMUXC_SAI2_TXC = 112,
+ MX8MN_IOMUXC_SAI2_TXD0 = 113,
+ MX8MN_IOMUXC_SAI2_MCLK = 114,
+ MX8MN_IOMUXC_SAI3_RXFS = 115,
+ MX8MN_IOMUXC_SAI3_RXC = 116,
+ MX8MN_IOMUXC_SAI3_RXD = 117,
+ MX8MN_IOMUXC_SAI3_TXFS = 118,
+ MX8MN_IOMUXC_SAI3_TXC = 119,
+ MX8MN_IOMUXC_SAI3_TXD = 120,
+ MX8MN_IOMUXC_SAI3_MCLK = 121,
+ MX8MN_IOMUXC_SPDIF_TX = 122,
+ MX8MN_IOMUXC_SPDIF_RX = 123,
+ MX8MN_IOMUXC_SPDIF_EXT_CLK = 124,
+ MX8MN_IOMUXC_ECSPI1_SCLK = 125,
+ MX8MN_IOMUXC_ECSPI1_MOSI = 126,
+ MX8MN_IOMUXC_ECSPI1_MISO = 127,
+ MX8MN_IOMUXC_ECSPI1_SS0 = 128,
+ MX8MN_IOMUXC_ECSPI2_SCLK = 129,
+ MX8MN_IOMUXC_ECSPI2_MOSI = 130,
+ MX8MN_IOMUXC_ECSPI2_MISO = 131,
+ MX8MN_IOMUXC_ECSPI2_SS0 = 132,
+ MX8MN_IOMUXC_I2C1_SCL = 133,
+ MX8MN_IOMUXC_I2C1_SDA = 134,
+ MX8MN_IOMUXC_I2C2_SCL = 135,
+ MX8MN_IOMUXC_I2C2_SDA = 136,
+ MX8MN_IOMUXC_I2C3_SCL = 137,
+ MX8MN_IOMUXC_I2C3_SDA = 138,
+ MX8MN_IOMUXC_I2C4_SCL = 139,
+ MX8MN_IOMUXC_I2C4_SDA = 140,
+ MX8MN_IOMUXC_UART1_RXD = 141,
+ MX8MN_IOMUXC_UART1_TXD = 142,
+ MX8MN_IOMUXC_UART2_RXD = 143,
+ MX8MN_IOMUXC_UART2_TXD = 144,
+ MX8MN_IOMUXC_UART3_RXD = 145,
+ MX8MN_IOMUXC_UART3_TXD = 146,
+ MX8MN_IOMUXC_UART4_RXD = 147,
+ MX8MN_IOMUXC_UART4_TXD = 148,
+};
+
+/* Pad names for the pinmux subsystem */
+static const struct pinctrl_pin_desc imx8mn_pinctrl_pads[] = {
+ IMX_PINCTRL_PIN(MX8MN_PAD_RESERVE0),
+ IMX_PINCTRL_PIN(MX8MN_PAD_RESERVE1),
+ IMX_PINCTRL_PIN(MX8MN_PAD_RESERVE2),
+ IMX_PINCTRL_PIN(MX8MN_PAD_RESERVE3),
+ IMX_PINCTRL_PIN(MX8MN_PAD_RESERVE4),
+ IMX_PINCTRL_PIN(MX8MN_PAD_RESERVE5),
+ IMX_PINCTRL_PIN(MX8MN_PAD_RESERVE6),
+ IMX_PINCTRL_PIN(MX8MN_PAD_RESERVE7),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_BOOT_MODE2),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_BOOT_MODE3),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO00),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO01),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO02),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO03),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO04),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO05),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO06),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO07),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO08),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO09),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO10),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO11),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO12),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO13),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO14),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO15),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_MDC),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_MDIO),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_TD3),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_TD2),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_TD1),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_TD0),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_TX_CTL),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_TXC),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_RX_CTL),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_RXC),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_RD0),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_RD1),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_RD2),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_RD3),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_CLK),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_CMD),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_DATA0),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_DATA1),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_DATA2),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_DATA3),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_DATA4),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_DATA5),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_DATA6),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_DATA7),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_RESET_B),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_STROBE),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD2_CD_B),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD2_CLK),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD2_CMD),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD2_DATA0),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD2_DATA1),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD2_DATA2),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD2_DATA3),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD2_RESET_B),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD2_WP),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_ALE),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_CE0),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_CE1),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_CE2),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_CE3),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_CLE),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_DATA00),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_DATA01),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_DATA02),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_DATA03),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_DATA04),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_DATA05),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_DATA06),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_DATA07),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_DQS),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_RE_B),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_READY_B),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_WE_B),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_WP_B),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI5_RXFS),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI5_RXC),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI5_RXD0),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI5_RXD1),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI5_RXD2),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI5_RXD3),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI5_MCLK),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_RXFS),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_RXC),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_RXD0),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_RXD1),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_RXD2),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_RXD3),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_RXD4),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_RXD5),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_RXD6),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_RXD7),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_TXFS),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_TXC),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_TXD0),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_TXD1),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_TXD2),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_TXD3),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_TXD4),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_TXD5),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_TXD6),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_TXD7),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_MCLK),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI2_RXFS),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI2_RXC),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI2_RXD0),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI2_TXFS),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI2_TXC),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI2_TXD0),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI2_MCLK),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI3_RXFS),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI3_RXC),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI3_RXD),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI3_TXFS),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI3_TXC),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI3_TXD),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI3_MCLK),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SPDIF_TX),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SPDIF_RX),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_SPDIF_EXT_CLK),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_ECSPI1_SCLK),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_ECSPI1_MOSI),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_ECSPI1_MISO),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_ECSPI1_SS0),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_ECSPI2_SCLK),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_ECSPI2_MOSI),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_ECSPI2_MISO),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_ECSPI2_SS0),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_I2C1_SCL),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_I2C1_SDA),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_I2C2_SCL),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_I2C2_SDA),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_I2C3_SCL),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_I2C3_SDA),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_I2C4_SCL),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_I2C4_SDA),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_UART1_RXD),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_UART1_TXD),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_UART2_RXD),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_UART2_TXD),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_UART3_RXD),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_UART3_TXD),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_UART4_RXD),
+ IMX_PINCTRL_PIN(MX8MN_IOMUXC_UART4_TXD),
+};
+
+static struct imx_pinctrl_soc_info imx8mn_pinctrl_info = {
+ .pins = imx8mn_pinctrl_pads,
+ .npins = ARRAY_SIZE(imx8mn_pinctrl_pads),
+ .gpr_compatible = "fsl,imx8mn-iomuxc-gpr",
+};
+
+static const struct of_device_id imx8mn_pinctrl_of_match[] = {
+ { .compatible = "fsl,imx8mn-iomuxc", .data = &imx8mn_pinctrl_info, },
+ { /* sentinel */ }
+};
+
+static int imx8mn_pinctrl_probe(struct platform_device *pdev)
+{
+ return imx_pinctrl_probe(pdev, &imx8mn_pinctrl_info);
+}
+
+static struct platform_driver imx8mn_pinctrl_driver = {
+ .driver = {
+ .name = "imx8mn-pinctrl",
+ .of_match_table = of_match_ptr(imx8mn_pinctrl_of_match),
+ .suppress_bind_attrs = true,
+ },
+ .probe = imx8mn_pinctrl_probe,
+};
+
+static int __init imx8mn_pinctrl_init(void)
+{
+ return platform_driver_register(&imx8mn_pinctrl_driver);
+}
+arch_initcall(imx8mn_pinctrl_init);
diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c
index 18d9ad504194..e5a112a8e067 100644
--- a/drivers/pinctrl/intel/pinctrl-baytrail.c
+++ b/drivers/pinctrl/intel/pinctrl-baytrail.c
@@ -24,6 +24,8 @@
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinconf-generic.h>
+#include "pinctrl-intel.h"
+
/* memory mapped register offsets */
#define BYT_CONF0_REG 0x000
#define BYT_CONF1_REG 0x004
@@ -35,6 +37,7 @@
/* BYT_CONF0_REG register bits */
#define BYT_IODEN BIT(31)
#define BYT_DIRECT_IRQ_EN BIT(27)
+#define BYT_TRIG_MASK GENMASK(26, 24)
#define BYT_TRIG_NEG BIT(26)
#define BYT_TRIG_POS BIT(25)
#define BYT_TRIG_LVL BIT(24)
@@ -43,31 +46,28 @@
#define BYT_GLITCH_F_SLOW_CLK BIT(17)
#define BYT_GLITCH_F_FAST_CLK BIT(16)
#define BYT_PULL_STR_SHIFT 9
-#define BYT_PULL_STR_MASK (3 << BYT_PULL_STR_SHIFT)
+#define BYT_PULL_STR_MASK GENMASK(10, 9)
#define BYT_PULL_STR_2K (0 << BYT_PULL_STR_SHIFT)
#define BYT_PULL_STR_10K (1 << BYT_PULL_STR_SHIFT)
#define BYT_PULL_STR_20K (2 << BYT_PULL_STR_SHIFT)
#define BYT_PULL_STR_40K (3 << BYT_PULL_STR_SHIFT)
#define BYT_PULL_ASSIGN_SHIFT 7
-#define BYT_PULL_ASSIGN_MASK (3 << BYT_PULL_ASSIGN_SHIFT)
+#define BYT_PULL_ASSIGN_MASK GENMASK(8, 7)
#define BYT_PULL_ASSIGN_UP (1 << BYT_PULL_ASSIGN_SHIFT)
#define BYT_PULL_ASSIGN_DOWN (2 << BYT_PULL_ASSIGN_SHIFT)
-#define BYT_PIN_MUX 0x07
+#define BYT_PIN_MUX GENMASK(2, 0)
/* BYT_VAL_REG register bits */
+#define BYT_DIR_MASK GENMASK(2, 1)
#define BYT_INPUT_EN BIT(2) /* 0: input enabled (active low)*/
#define BYT_OUTPUT_EN BIT(1) /* 0: output enabled (active low)*/
#define BYT_LEVEL BIT(0)
-#define BYT_DIR_MASK (BIT(1) | BIT(2))
-#define BYT_TRIG_MASK (BIT(26) | BIT(25) | BIT(24))
-
-#define BYT_CONF0_RESTORE_MASK (BYT_DIRECT_IRQ_EN | BYT_TRIG_MASK | \
- BYT_PIN_MUX)
+#define BYT_CONF0_RESTORE_MASK (BYT_DIRECT_IRQ_EN | BYT_TRIG_MASK | BYT_PIN_MUX)
#define BYT_VAL_RESTORE_MASK (BYT_DIR_MASK | BYT_LEVEL)
/* BYT_DEBOUNCE_REG bits */
-#define BYT_DEBOUNCE_PULSE_MASK 0x7
+#define BYT_DEBOUNCE_PULSE_MASK GENMASK(2, 0)
#define BYT_DEBOUNCE_PULSE_375US 1
#define BYT_DEBOUNCE_PULSE_750US 2
#define BYT_DEBOUNCE_PULSE_1500US 3
@@ -91,40 +91,13 @@
* does not find a match for the requested function.
*/
#define BYT_DEFAULT_GPIO_MUX 0
+#define BYT_ALTER_GPIO_MUX 1
struct byt_gpio_pin_context {
u32 conf0;
u32 val;
};
-struct byt_simple_func_mux {
- const char *name;
- unsigned short func;
-};
-
-struct byt_mixed_func_mux {
- const char *name;
- const unsigned short *func_values;
-};
-
-struct byt_pingroup {
- const char *name;
- const unsigned int *pins;
- size_t npins;
- unsigned short has_simple_funcs;
- union {
- const struct byt_simple_func_mux *simple_funcs;
- const struct byt_mixed_func_mux *mixed_funcs;
- };
- size_t nfuncs;
-};
-
-struct byt_function {
- const char *name;
- const char * const *groups;
- size_t ngroups;
-};
-
struct byt_community {
unsigned int pin_base;
size_t npins;
@@ -132,47 +105,6 @@ struct byt_community {
void __iomem *reg_base;
};
-#define SIMPLE_FUNC(n, f) \
- { \
- .name = (n), \
- .func = (f), \
- }
-#define MIXED_FUNC(n, f) \
- { \
- .name = (n), \
- .func_values = (f), \
- }
-
-#define PIN_GROUP_SIMPLE(n, p, f) \
- { \
- .name = (n), \
- .pins = (p), \
- .npins = ARRAY_SIZE((p)), \
- .has_simple_funcs = 1, \
- { \
- .simple_funcs = (f), \
- }, \
- .nfuncs = ARRAY_SIZE((f)), \
- }
-#define PIN_GROUP_MIXED(n, p, f) \
- { \
- .name = (n), \
- .pins = (p), \
- .npins = ARRAY_SIZE((p)), \
- .has_simple_funcs = 0, \
- { \
- .mixed_funcs = (f), \
- }, \
- .nfuncs = ARRAY_SIZE((f)), \
- }
-
-#define FUNCTION(n, g) \
- { \
- .name = (n), \
- .groups = (g), \
- .ngroups = ARRAY_SIZE((g)), \
- }
-
#define COMMUNITY(p, n, map) \
{ \
.pin_base = (p), \
@@ -184,9 +116,9 @@ struct byt_pinctrl_soc_data {
const char *uid;
const struct pinctrl_pin_desc *pins;
size_t npins;
- const struct byt_pingroup *groups;
+ const struct intel_pingroup *groups;
size_t ngroups;
- const struct byt_function *functions;
+ const struct intel_function *functions;
size_t nfunctions;
const struct byt_community *communities;
size_t ncommunities;
@@ -326,20 +258,11 @@ static const unsigned int byt_score_pins_map[BYT_NGPIO_SCORE] = {
/* SCORE groups */
static const unsigned int byt_score_uart1_pins[] = { 70, 71, 72, 73 };
static const unsigned int byt_score_uart2_pins[] = { 74, 75, 76, 77 };
-static const struct byt_simple_func_mux byt_score_uart_mux[] = {
- SIMPLE_FUNC("uart", 1),
-};
static const unsigned int byt_score_pwm0_pins[] = { 94 };
static const unsigned int byt_score_pwm1_pins[] = { 95 };
-static const struct byt_simple_func_mux byt_score_pwm_mux[] = {
- SIMPLE_FUNC("pwm", 1),
-};
static const unsigned int byt_score_sio_spi_pins[] = { 66, 67, 68, 69 };
-static const struct byt_simple_func_mux byt_score_spi_mux[] = {
- SIMPLE_FUNC("spi", 1),
-};
static const unsigned int byt_score_i2c5_pins[] = { 88, 89 };
static const unsigned int byt_score_i2c6_pins[] = { 90, 91 };
@@ -348,50 +271,29 @@ static const unsigned int byt_score_i2c3_pins[] = { 84, 85 };
static const unsigned int byt_score_i2c2_pins[] = { 82, 83 };
static const unsigned int byt_score_i2c1_pins[] = { 80, 81 };
static const unsigned int byt_score_i2c0_pins[] = { 78, 79 };
-static const struct byt_simple_func_mux byt_score_i2c_mux[] = {
- SIMPLE_FUNC("i2c", 1),
-};
static const unsigned int byt_score_ssp0_pins[] = { 8, 9, 10, 11 };
static const unsigned int byt_score_ssp1_pins[] = { 12, 13, 14, 15 };
static const unsigned int byt_score_ssp2_pins[] = { 62, 63, 64, 65 };
-static const struct byt_simple_func_mux byt_score_ssp_mux[] = {
- SIMPLE_FUNC("ssp", 1),
-};
static const unsigned int byt_score_sdcard_pins[] = {
7, 33, 34, 35, 36, 37, 38, 39, 40, 41,
};
-static const unsigned short byt_score_sdcard_mux_values[] = {
+static const unsigned int byt_score_sdcard_mux_values[] = {
2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
};
-static const struct byt_mixed_func_mux byt_score_sdcard_mux[] = {
- MIXED_FUNC("sdcard", byt_score_sdcard_mux_values),
-};
static const unsigned int byt_score_sdio_pins[] = { 27, 28, 29, 30, 31, 32 };
-static const struct byt_simple_func_mux byt_score_sdio_mux[] = {
- SIMPLE_FUNC("sdio", 1),
-};
static const unsigned int byt_score_emmc_pins[] = {
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
};
-static const struct byt_simple_func_mux byt_score_emmc_mux[] = {
- SIMPLE_FUNC("emmc", 1),
-};
static const unsigned int byt_score_ilb_lpc_pins[] = {
42, 43, 44, 45, 46, 47, 48, 49, 50,
};
-static const struct byt_simple_func_mux byt_score_lpc_mux[] = {
- SIMPLE_FUNC("lpc", 1),
-};
static const unsigned int byt_score_sata_pins[] = { 0, 1, 2 };
-static const struct byt_simple_func_mux byt_score_sata_mux[] = {
- SIMPLE_FUNC("sata", 1),
-};
static const unsigned int byt_score_plt_clk0_pins[] = { 96 };
static const unsigned int byt_score_plt_clk1_pins[] = { 97 };
@@ -399,70 +301,37 @@ static const unsigned int byt_score_plt_clk2_pins[] = { 98 };
static const unsigned int byt_score_plt_clk3_pins[] = { 99 };
static const unsigned int byt_score_plt_clk4_pins[] = { 100 };
static const unsigned int byt_score_plt_clk5_pins[] = { 101 };
-static const struct byt_simple_func_mux byt_score_plt_clk_mux[] = {
- SIMPLE_FUNC("plt_clk", 1),
-};
static const unsigned int byt_score_smbus_pins[] = { 51, 52, 53 };
-static const struct byt_simple_func_mux byt_score_smbus_mux[] = {
- SIMPLE_FUNC("smbus", 1),
-};
-static const struct byt_pingroup byt_score_groups[] = {
- PIN_GROUP_SIMPLE("uart1_grp",
- byt_score_uart1_pins, byt_score_uart_mux),
- PIN_GROUP_SIMPLE("uart2_grp",
- byt_score_uart2_pins, byt_score_uart_mux),
- PIN_GROUP_SIMPLE("pwm0_grp",
- byt_score_pwm0_pins, byt_score_pwm_mux),
- PIN_GROUP_SIMPLE("pwm1_grp",
- byt_score_pwm1_pins, byt_score_pwm_mux),
- PIN_GROUP_SIMPLE("ssp2_grp",
- byt_score_ssp2_pins, byt_score_pwm_mux),
- PIN_GROUP_SIMPLE("sio_spi_grp",
- byt_score_sio_spi_pins, byt_score_spi_mux),
- PIN_GROUP_SIMPLE("i2c5_grp",
- byt_score_i2c5_pins, byt_score_i2c_mux),
- PIN_GROUP_SIMPLE("i2c6_grp",
- byt_score_i2c6_pins, byt_score_i2c_mux),
- PIN_GROUP_SIMPLE("i2c4_grp",
- byt_score_i2c4_pins, byt_score_i2c_mux),
- PIN_GROUP_SIMPLE("i2c3_grp",
- byt_score_i2c3_pins, byt_score_i2c_mux),
- PIN_GROUP_SIMPLE("i2c2_grp",
- byt_score_i2c2_pins, byt_score_i2c_mux),
- PIN_GROUP_SIMPLE("i2c1_grp",
- byt_score_i2c1_pins, byt_score_i2c_mux),
- PIN_GROUP_SIMPLE("i2c0_grp",
- byt_score_i2c0_pins, byt_score_i2c_mux),
- PIN_GROUP_SIMPLE("ssp0_grp",
- byt_score_ssp0_pins, byt_score_ssp_mux),
- PIN_GROUP_SIMPLE("ssp1_grp",
- byt_score_ssp1_pins, byt_score_ssp_mux),
- PIN_GROUP_MIXED("sdcard_grp",
- byt_score_sdcard_pins, byt_score_sdcard_mux),
- PIN_GROUP_SIMPLE("sdio_grp",
- byt_score_sdio_pins, byt_score_sdio_mux),
- PIN_GROUP_SIMPLE("emmc_grp",
- byt_score_emmc_pins, byt_score_emmc_mux),
- PIN_GROUP_SIMPLE("lpc_grp",
- byt_score_ilb_lpc_pins, byt_score_lpc_mux),
- PIN_GROUP_SIMPLE("sata_grp",
- byt_score_sata_pins, byt_score_sata_mux),
- PIN_GROUP_SIMPLE("plt_clk0_grp",
- byt_score_plt_clk0_pins, byt_score_plt_clk_mux),
- PIN_GROUP_SIMPLE("plt_clk1_grp",
- byt_score_plt_clk1_pins, byt_score_plt_clk_mux),
- PIN_GROUP_SIMPLE("plt_clk2_grp",
- byt_score_plt_clk2_pins, byt_score_plt_clk_mux),
- PIN_GROUP_SIMPLE("plt_clk3_grp",
- byt_score_plt_clk3_pins, byt_score_plt_clk_mux),
- PIN_GROUP_SIMPLE("plt_clk4_grp",
- byt_score_plt_clk4_pins, byt_score_plt_clk_mux),
- PIN_GROUP_SIMPLE("plt_clk5_grp",
- byt_score_plt_clk5_pins, byt_score_plt_clk_mux),
- PIN_GROUP_SIMPLE("smbus_grp",
- byt_score_smbus_pins, byt_score_smbus_mux),
+static const struct intel_pingroup byt_score_groups[] = {
+ PIN_GROUP("uart1_grp", byt_score_uart1_pins, 1),
+ PIN_GROUP("uart2_grp", byt_score_uart2_pins, 1),
+ PIN_GROUP("pwm0_grp", byt_score_pwm0_pins, 1),
+ PIN_GROUP("pwm1_grp", byt_score_pwm1_pins, 1),
+ PIN_GROUP("ssp2_grp", byt_score_ssp2_pins, 1),
+ PIN_GROUP("sio_spi_grp", byt_score_sio_spi_pins, 1),
+ PIN_GROUP("i2c5_grp", byt_score_i2c5_pins, 1),
+ PIN_GROUP("i2c6_grp", byt_score_i2c6_pins, 1),
+ PIN_GROUP("i2c4_grp", byt_score_i2c4_pins, 1),
+ PIN_GROUP("i2c3_grp", byt_score_i2c3_pins, 1),
+ PIN_GROUP("i2c2_grp", byt_score_i2c2_pins, 1),
+ PIN_GROUP("i2c1_grp", byt_score_i2c1_pins, 1),
+ PIN_GROUP("i2c0_grp", byt_score_i2c0_pins, 1),
+ PIN_GROUP("ssp0_grp", byt_score_ssp0_pins, 1),
+ PIN_GROUP("ssp1_grp", byt_score_ssp1_pins, 1),
+ PIN_GROUP("sdcard_grp", byt_score_sdcard_pins, byt_score_sdcard_mux_values),
+ PIN_GROUP("sdio_grp", byt_score_sdio_pins, 1),
+ PIN_GROUP("emmc_grp", byt_score_emmc_pins, 1),
+ PIN_GROUP("lpc_grp", byt_score_ilb_lpc_pins, 1),
+ PIN_GROUP("sata_grp", byt_score_sata_pins, 1),
+ PIN_GROUP("plt_clk0_grp", byt_score_plt_clk0_pins, 1),
+ PIN_GROUP("plt_clk1_grp", byt_score_plt_clk1_pins, 1),
+ PIN_GROUP("plt_clk2_grp", byt_score_plt_clk2_pins, 1),
+ PIN_GROUP("plt_clk3_grp", byt_score_plt_clk3_pins, 1),
+ PIN_GROUP("plt_clk4_grp", byt_score_plt_clk4_pins, 1),
+ PIN_GROUP("plt_clk5_grp", byt_score_plt_clk5_pins, 1),
+ PIN_GROUP("smbus_grp", byt_score_smbus_pins, 1),
};
static const char * const byt_score_uart_groups[] = {
@@ -496,10 +365,9 @@ static const char * const byt_score_gpio_groups[] = {
"sdcard_grp", "sdio_grp", "emmc_grp", "lpc_grp", "sata_grp",
"plt_clk0_grp", "plt_clk1_grp", "plt_clk2_grp", "plt_clk3_grp",
"plt_clk4_grp", "plt_clk5_grp", "smbus_grp",
-
};
-static const struct byt_function byt_score_functions[] = {
+static const struct intel_function byt_score_functions[] = {
FUNCTION("uart", byt_score_uart_groups),
FUNCTION("pwm", byt_score_pwm_groups),
FUNCTION("ssp", byt_score_ssp_groups),
@@ -588,38 +456,30 @@ static const unsigned int byt_sus_pins_map[BYT_NGPIO_SUS] = {
};
static const unsigned int byt_sus_usb_over_current_pins[] = { 19, 20 };
-static const struct byt_simple_func_mux byt_sus_usb_oc_mux[] = {
- SIMPLE_FUNC("usb", 0),
- SIMPLE_FUNC("gpio", 1),
-};
+static const unsigned int byt_sus_usb_over_current_mode_values[] = { 0, 0 };
+static const unsigned int byt_sus_usb_over_current_gpio_mode_values[] = { 1, 1 };
static const unsigned int byt_sus_usb_ulpi_pins[] = {
14, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
};
-static const unsigned short byt_sus_usb_ulpi_mode_values[] = {
+static const unsigned int byt_sus_usb_ulpi_mode_values[] = {
2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
};
-static const unsigned short byt_sus_usb_ulpi_gpio_mode_values[] = {
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-static const struct byt_mixed_func_mux byt_sus_usb_ulpi_mux[] = {
- MIXED_FUNC("usb", byt_sus_usb_ulpi_mode_values),
- MIXED_FUNC("gpio", byt_sus_usb_ulpi_gpio_mode_values),
+static const unsigned int byt_sus_usb_ulpi_gpio_mode_values[] = {
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
static const unsigned int byt_sus_pcu_spi_pins[] = { 21 };
-static const struct byt_simple_func_mux byt_sus_pcu_spi_mux[] = {
- SIMPLE_FUNC("spi", 0),
- SIMPLE_FUNC("gpio", 1),
-};
+static const unsigned int byt_sus_pcu_spi_mode_values[] = { 0 };
+static const unsigned int byt_sus_pcu_spi_gpio_mode_values[] = { 1 };
-static const struct byt_pingroup byt_sus_groups[] = {
- PIN_GROUP_SIMPLE("usb_oc_grp",
- byt_sus_usb_over_current_pins, byt_sus_usb_oc_mux),
- PIN_GROUP_MIXED("usb_ulpi_grp",
- byt_sus_usb_ulpi_pins, byt_sus_usb_ulpi_mux),
- PIN_GROUP_SIMPLE("pcu_spi_grp",
- byt_sus_pcu_spi_pins, byt_sus_pcu_spi_mux),
+static const struct intel_pingroup byt_sus_groups[] = {
+ PIN_GROUP("usb_oc_grp", byt_sus_usb_over_current_pins, byt_sus_usb_over_current_mode_values),
+ PIN_GROUP("usb_ulpi_grp", byt_sus_usb_ulpi_pins, byt_sus_usb_ulpi_mode_values),
+ PIN_GROUP("pcu_spi_grp", byt_sus_pcu_spi_pins, byt_sus_pcu_spi_mode_values),
+ PIN_GROUP("usb_oc_grp_gpio", byt_sus_usb_over_current_pins, byt_sus_usb_over_current_gpio_mode_values),
+ PIN_GROUP("usb_ulpi_grp_gpio", byt_sus_usb_ulpi_pins, byt_sus_usb_ulpi_gpio_mode_values),
+ PIN_GROUP("pcu_spi_grp_gpio", byt_sus_pcu_spi_pins, byt_sus_pcu_spi_gpio_mode_values),
};
static const char * const byt_sus_usb_groups[] = {
@@ -627,10 +487,10 @@ static const char * const byt_sus_usb_groups[] = {
};
static const char * const byt_sus_spi_groups[] = { "pcu_spi_grp" };
static const char * const byt_sus_gpio_groups[] = {
- "usb_oc_grp", "usb_ulpi_grp", "pcu_spi_grp",
+ "usb_oc_grp_gpio", "usb_ulpi_grp_gpio", "pcu_spi_grp_gpio",
};
-static const struct byt_function byt_sus_functions[] = {
+static const struct intel_function byt_sus_functions[] = {
FUNCTION("usb", byt_sus_usb_groups),
FUNCTION("spi", byt_sus_spi_groups),
FUNCTION("gpio", byt_sus_gpio_groups),
@@ -810,41 +670,9 @@ static int byt_get_function_groups(struct pinctrl_dev *pctldev,
return 0;
}
-static int byt_get_group_simple_mux(const struct byt_pingroup group,
- const char *func_name,
- unsigned short *func)
-{
- int i;
-
- for (i = 0; i < group.nfuncs; i++) {
- if (!strcmp(group.simple_funcs[i].name, func_name)) {
- *func = group.simple_funcs[i].func;
- return 0;
- }
- }
-
- return 1;
-}
-
-static int byt_get_group_mixed_mux(const struct byt_pingroup group,
- const char *func_name,
- const unsigned short **func)
-{
- int i;
-
- for (i = 0; i < group.nfuncs; i++) {
- if (!strcmp(group.mixed_funcs[i].name, func_name)) {
- *func = group.mixed_funcs[i].func_values;
- return 0;
- }
- }
-
- return 1;
-}
-
static void byt_set_group_simple_mux(struct byt_gpio *vg,
- const struct byt_pingroup group,
- unsigned short func)
+ const struct intel_pingroup group,
+ unsigned int func)
{
unsigned long flags;
int i;
@@ -873,8 +701,8 @@ static void byt_set_group_simple_mux(struct byt_gpio *vg,
}
static void byt_set_group_mixed_mux(struct byt_gpio *vg,
- const struct byt_pingroup group,
- const unsigned short *func)
+ const struct intel_pingroup group,
+ const unsigned int *func)
{
unsigned long flags;
int i;
@@ -906,23 +734,15 @@ static int byt_set_mux(struct pinctrl_dev *pctldev, unsigned int func_selector,
unsigned int group_selector)
{
struct byt_gpio *vg = pinctrl_dev_get_drvdata(pctldev);
- const struct byt_function func = vg->soc_data->functions[func_selector];
- const struct byt_pingroup group = vg->soc_data->groups[group_selector];
- const unsigned short *mixed_func;
- unsigned short simple_func;
- int ret = 1;
-
- if (group.has_simple_funcs)
- ret = byt_get_group_simple_mux(group, func.name, &simple_func);
- else
- ret = byt_get_group_mixed_mux(group, func.name, &mixed_func);
+ const struct intel_function func = vg->soc_data->functions[func_selector];
+ const struct intel_pingroup group = vg->soc_data->groups[group_selector];
- if (ret)
+ if (group.modes)
+ byt_set_group_mixed_mux(vg, group, group.modes);
+ else if (!strcmp(func.name, "gpio"))
byt_set_group_simple_mux(vg, group, BYT_DEFAULT_GPIO_MUX);
- else if (group.has_simple_funcs)
- byt_set_group_simple_mux(vg, group, simple_func);
else
- byt_set_group_mixed_mux(vg, group, mixed_func);
+ byt_set_group_simple_mux(vg, group, group.mode);
return 0;
}
@@ -932,14 +752,14 @@ static u32 byt_get_gpio_mux(struct byt_gpio *vg, unsigned int offset)
/* SCORE pin 92-93 */
if (!strcmp(vg->soc_data->uid, BYT_SCORE_ACPI_UID) &&
offset >= 92 && offset <= 93)
- return 1;
+ return BYT_ALTER_GPIO_MUX;
/* SUS pin 11-21 */
if (!strcmp(vg->soc_data->uid, BYT_SUS_ACPI_UID) &&
offset >= 11 && offset <= 21)
- return 1;
+ return BYT_ALTER_GPIO_MUX;
- return 0;
+ return BYT_DEFAULT_GPIO_MUX;
}
static void byt_gpio_clear_triggering(struct byt_gpio *vg, unsigned int offset)
diff --git a/drivers/pinctrl/mediatek/mtk-eint.c b/drivers/pinctrl/mediatek/mtk-eint.c
index f464f8cd274b..7e526bcf5e0b 100644
--- a/drivers/pinctrl/mediatek/mtk-eint.c
+++ b/drivers/pinctrl/mediatek/mtk-eint.c
@@ -113,6 +113,8 @@ static void mtk_eint_mask(struct irq_data *d)
void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq,
eint->regs->mask_set);
+ eint->cur_mask[d->hwirq >> 5] &= ~mask;
+
writel(mask, reg);
}
@@ -123,6 +125,8 @@ static void mtk_eint_unmask(struct irq_data *d)
void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq,
eint->regs->mask_clr);
+ eint->cur_mask[d->hwirq >> 5] |= mask;
+
writel(mask, reg);
if (eint->dual_edge[d->hwirq])
@@ -217,19 +221,6 @@ static void mtk_eint_chip_write_mask(const struct mtk_eint *eint,
}
}
-static void mtk_eint_chip_read_mask(const struct mtk_eint *eint,
- void __iomem *base, u32 *buf)
-{
- int port;
- void __iomem *reg;
-
- for (port = 0; port < eint->hw->ports; port++) {
- reg = base + eint->regs->mask + (port << 2);
- buf[port] = ~readl_relaxed(reg);
- /* Mask is 0 when irq is enabled, and 1 when disabled. */
- }
-}
-
static int mtk_eint_irq_request_resources(struct irq_data *d)
{
struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
@@ -318,7 +309,7 @@ static void mtk_eint_irq_handler(struct irq_desc *desc)
struct irq_chip *chip = irq_desc_get_chip(desc);
struct mtk_eint *eint = irq_desc_get_handler_data(desc);
unsigned int status, eint_num;
- int offset, index, virq;
+ int offset, mask_offset, index, virq;
void __iomem *reg = mtk_eint_get_offset(eint, 0, eint->regs->stat);
int dual_edge, start_level, curr_level;
@@ -328,10 +319,24 @@ static void mtk_eint_irq_handler(struct irq_desc *desc)
status = readl(reg);
while (status) {
offset = __ffs(status);
+ mask_offset = eint_num >> 5;
index = eint_num + offset;
virq = irq_find_mapping(eint->domain, index);
status &= ~BIT(offset);
+ /*
+ * If we get an interrupt on pin that was only required
+ * for wake (but no real interrupt requested), mask the
+ * interrupt (as would mtk_eint_resume do anyway later
+ * in the resume sequence).
+ */
+ if (eint->wake_mask[mask_offset] & BIT(offset) &&
+ !(eint->cur_mask[mask_offset] & BIT(offset))) {
+ writel_relaxed(BIT(offset), reg -
+ eint->regs->stat +
+ eint->regs->mask_set);
+ }
+
dual_edge = eint->dual_edge[index];
if (dual_edge) {
/*
@@ -370,7 +375,6 @@ static void mtk_eint_irq_handler(struct irq_desc *desc)
int mtk_eint_do_suspend(struct mtk_eint *eint)
{
- mtk_eint_chip_read_mask(eint, eint->base, eint->cur_mask);
mtk_eint_chip_write_mask(eint, eint->base, eint->wake_mask);
return 0;
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8183.c b/drivers/pinctrl/mediatek/pinctrl-mt8183.c
index 2c7409ed16fa..9a74d5025be6 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8183.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8183.c
@@ -583,6 +583,7 @@ static struct platform_driver mt8183_pinctrl_driver = {
.driver = {
.name = "mt8183-pinctrl",
.of_match_table = mt8183_pinctrl_of_match,
+ .pm = &mtk_paris_pinctrl_pm_ops,
},
.probe = mt8183_pinctrl_probe,
};
diff --git a/drivers/pinctrl/mediatek/pinctrl-paris.c b/drivers/pinctrl/mediatek/pinctrl-paris.c
index d3b34e9a7507..923264d0e9ef 100644
--- a/drivers/pinctrl/mediatek/pinctrl-paris.c
+++ b/drivers/pinctrl/mediatek/pinctrl-paris.c
@@ -926,3 +926,22 @@ int mtk_paris_pinctrl_probe(struct platform_device *pdev,
return 0;
}
+
+static int mtk_paris_pinctrl_suspend(struct device *device)
+{
+ struct mtk_pinctrl *pctl = dev_get_drvdata(device);
+
+ return mtk_eint_do_suspend(pctl->eint);
+}
+
+static int mtk_paris_pinctrl_resume(struct device *device)
+{
+ struct mtk_pinctrl *pctl = dev_get_drvdata(device);
+
+ return mtk_eint_do_resume(pctl->eint);
+}
+
+const struct dev_pm_ops mtk_paris_pinctrl_pm_ops = {
+ .suspend_noirq = mtk_paris_pinctrl_suspend,
+ .resume_noirq = mtk_paris_pinctrl_resume,
+};
diff --git a/drivers/pinctrl/mediatek/pinctrl-paris.h b/drivers/pinctrl/mediatek/pinctrl-paris.h
index 37146caa667d..3d43771074e6 100644
--- a/drivers/pinctrl/mediatek/pinctrl-paris.h
+++ b/drivers/pinctrl/mediatek/pinctrl-paris.h
@@ -60,4 +60,6 @@
int mtk_paris_pinctrl_probe(struct platform_device *pdev,
const struct mtk_pin_soc *soc);
+extern const struct dev_pm_ops mtk_paris_pinctrl_pm_ops;
+
#endif /* __PINCTRL_PARIS_H */
diff --git a/drivers/pinctrl/meson/pinctrl-meson-g12a.c b/drivers/pinctrl/meson/pinctrl-meson-g12a.c
index d494492e98e9..3475cd7bd2af 100644
--- a/drivers/pinctrl/meson/pinctrl-meson-g12a.c
+++ b/drivers/pinctrl/meson/pinctrl-meson-g12a.c
@@ -1304,28 +1304,28 @@ static struct meson_pmx_func meson_g12a_aobus_functions[] = {
};
static struct meson_bank meson_g12a_periphs_banks[] = {
- /* name first last irq pullen pull dir out in */
- BANK("Z", GPIOZ_0, GPIOZ_15, 12, 27,
- 4, 0, 4, 0, 12, 0, 13, 0, 14, 0),
- BANK("H", GPIOH_0, GPIOH_8, 28, 36,
- 3, 0, 3, 0, 9, 0, 10, 0, 11, 0),
- BANK("BOOT", BOOT_0, BOOT_15, 37, 52,
- 0, 0, 0, 0, 0, 0, 1, 0, 2, 0),
- BANK("C", GPIOC_0, GPIOC_7, 53, 60,
- 1, 0, 1, 0, 3, 0, 4, 0, 5, 0),
- BANK("A", GPIOA_0, GPIOA_15, 61, 76,
- 5, 0, 5, 0, 16, 0, 17, 0, 18, 0),
- BANK("X", GPIOX_0, GPIOX_19, 77, 96,
- 2, 0, 2, 0, 6, 0, 7, 0, 8, 0),
+ /* name first last irq pullen pull dir out in ds */
+ BANK_DS("Z", GPIOZ_0, GPIOZ_15, 12, 27,
+ 4, 0, 4, 0, 12, 0, 13, 0, 14, 0, 5, 0),
+ BANK_DS("H", GPIOH_0, GPIOH_8, 28, 36,
+ 3, 0, 3, 0, 9, 0, 10, 0, 11, 0, 4, 0),
+ BANK_DS("BOOT", BOOT_0, BOOT_15, 37, 52,
+ 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0),
+ BANK_DS("C", GPIOC_0, GPIOC_7, 53, 60,
+ 1, 0, 1, 0, 3, 0, 4, 0, 5, 0, 1, 0),
+ BANK_DS("A", GPIOA_0, GPIOA_15, 61, 76,
+ 5, 0, 5, 0, 16, 0, 17, 0, 18, 0, 6, 0),
+ BANK_DS("X", GPIOX_0, GPIOX_19, 77, 96,
+ 2, 0, 2, 0, 6, 0, 7, 0, 8, 0, 2, 0),
};
static struct meson_bank meson_g12a_aobus_banks[] = {
- /* name first last irq pullen pull dir out in */
- BANK("AO", GPIOAO_0, GPIOAO_11, 0, 11,
- 3, 0, 2, 0, 0, 0, 4, 0, 1, 0),
+ /* name first last irq pullen pull dir out in ds */
+ BANK_DS("AO", GPIOAO_0, GPIOAO_11, 0, 11, 3, 0, 2, 0, 0, 0, 4, 0, 1, 0,
+ 0, 0),
/* GPIOE actually located in the AO bank */
- BANK("E", GPIOE_0, GPIOE_2, 97, 99,
- 3, 16, 2, 16, 0, 16, 4, 16, 1, 16),
+ BANK_DS("E", GPIOE_0, GPIOE_2, 97, 99, 3, 16, 2, 16, 0, 16, 4, 16, 1,
+ 16, 1, 0),
};
static struct meson_pmx_bank meson_g12a_periphs_pmx_banks[] = {
diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c
index 077de5925783..596786926209 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.c
+++ b/drivers/pinctrl/meson/pinctrl-meson.c
@@ -168,68 +168,223 @@ int meson_pmx_get_groups(struct pinctrl_dev *pcdev, unsigned selector,
return 0;
}
-static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin,
- unsigned long *configs, unsigned num_configs)
+static int meson_pinconf_set_gpio_bit(struct meson_pinctrl *pc,
+ unsigned int pin,
+ unsigned int reg_type,
+ bool arg)
{
- struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
struct meson_bank *bank;
- enum pin_config_param param;
unsigned int reg, bit;
- int i, ret;
+ int ret;
+
+ ret = meson_get_bank(pc, pin, &bank);
+ if (ret)
+ return ret;
+
+ meson_calc_reg_and_bit(bank, pin, reg_type, &reg, &bit);
+ return regmap_update_bits(pc->reg_gpio, reg, BIT(bit),
+ arg ? BIT(bit) : 0);
+}
+
+static int meson_pinconf_get_gpio_bit(struct meson_pinctrl *pc,
+ unsigned int pin,
+ unsigned int reg_type)
+{
+ struct meson_bank *bank;
+ unsigned int reg, bit, val;
+ int ret;
ret = meson_get_bank(pc, pin, &bank);
if (ret)
return ret;
+ meson_calc_reg_and_bit(bank, pin, reg_type, &reg, &bit);
+ ret = regmap_read(pc->reg_gpio, reg, &val);
+ if (ret)
+ return ret;
+
+ return BIT(bit) & val ? 1 : 0;
+}
+
+static int meson_pinconf_set_output(struct meson_pinctrl *pc,
+ unsigned int pin,
+ bool out)
+{
+ return meson_pinconf_set_gpio_bit(pc, pin, REG_DIR, !out);
+}
+
+static int meson_pinconf_get_output(struct meson_pinctrl *pc,
+ unsigned int pin)
+{
+ int ret = meson_pinconf_get_gpio_bit(pc, pin, REG_DIR);
+
+ if (ret < 0)
+ return ret;
+
+ return !ret;
+}
+
+static int meson_pinconf_set_drive(struct meson_pinctrl *pc,
+ unsigned int pin,
+ bool high)
+{
+ return meson_pinconf_set_gpio_bit(pc, pin, REG_OUT, high);
+}
+
+static int meson_pinconf_get_drive(struct meson_pinctrl *pc,
+ unsigned int pin)
+{
+ return meson_pinconf_get_gpio_bit(pc, pin, REG_OUT);
+}
+
+static int meson_pinconf_set_output_drive(struct meson_pinctrl *pc,
+ unsigned int pin,
+ bool high)
+{
+ int ret;
+
+ ret = meson_pinconf_set_output(pc, pin, true);
+ if (ret)
+ return ret;
+
+ return meson_pinconf_set_drive(pc, pin, high);
+}
+
+static int meson_pinconf_disable_bias(struct meson_pinctrl *pc,
+ unsigned int pin)
+{
+ struct meson_bank *bank;
+ unsigned int reg, bit = 0;
+ int ret;
+
+ ret = meson_get_bank(pc, pin, &bank);
+ if (ret)
+ return ret;
+
+ meson_calc_reg_and_bit(bank, pin, REG_PULLEN, &reg, &bit);
+ ret = regmap_update_bits(pc->reg_pullen, reg, BIT(bit), 0);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int meson_pinconf_enable_bias(struct meson_pinctrl *pc, unsigned int pin,
+ bool pull_up)
+{
+ struct meson_bank *bank;
+ unsigned int reg, bit, val = 0;
+ int ret;
+
+ ret = meson_get_bank(pc, pin, &bank);
+ if (ret)
+ return ret;
+
+ meson_calc_reg_and_bit(bank, pin, REG_PULL, &reg, &bit);
+ if (pull_up)
+ val = BIT(bit);
+
+ ret = regmap_update_bits(pc->reg_pull, reg, BIT(bit), val);
+ if (ret)
+ return ret;
+
+ meson_calc_reg_and_bit(bank, pin, REG_PULLEN, &reg, &bit);
+ ret = regmap_update_bits(pc->reg_pullen, reg, BIT(bit), BIT(bit));
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int meson_pinconf_set_drive_strength(struct meson_pinctrl *pc,
+ unsigned int pin,
+ u16 drive_strength_ua)
+{
+ struct meson_bank *bank;
+ unsigned int reg, bit, ds_val;
+ int ret;
+
+ if (!pc->reg_ds) {
+ dev_err(pc->dev, "drive-strength not supported\n");
+ return -ENOTSUPP;
+ }
+
+ ret = meson_get_bank(pc, pin, &bank);
+ if (ret)
+ return ret;
+
+ meson_calc_reg_and_bit(bank, pin, REG_DS, &reg, &bit);
+ bit = bit << 1;
+
+ if (drive_strength_ua <= 500) {
+ ds_val = MESON_PINCONF_DRV_500UA;
+ } else if (drive_strength_ua <= 2500) {
+ ds_val = MESON_PINCONF_DRV_2500UA;
+ } else if (drive_strength_ua <= 3000) {
+ ds_val = MESON_PINCONF_DRV_3000UA;
+ } else if (drive_strength_ua <= 4000) {
+ ds_val = MESON_PINCONF_DRV_4000UA;
+ } else {
+ dev_warn_once(pc->dev,
+ "pin %u: invalid drive-strength : %d , default to 4mA\n",
+ pin, drive_strength_ua);
+ ds_val = MESON_PINCONF_DRV_4000UA;
+ }
+
+ ret = regmap_update_bits(pc->reg_ds, reg, 0x3 << bit, ds_val << bit);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin,
+ unsigned long *configs, unsigned num_configs)
+{
+ struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
+ enum pin_config_param param;
+ unsigned int arg = 0;
+ int i, ret;
+
for (i = 0; i < num_configs; i++) {
param = pinconf_to_config_param(configs[i]);
switch (param) {
+ case PIN_CONFIG_DRIVE_STRENGTH_UA:
+ case PIN_CONFIG_OUTPUT_ENABLE:
+ case PIN_CONFIG_OUTPUT:
+ arg = pinconf_to_config_argument(configs[i]);
+ break;
+
+ default:
+ break;
+ }
+
+ switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
- dev_dbg(pc->dev, "pin %u: disable bias\n", pin);
-
- meson_calc_reg_and_bit(bank, pin, REG_PULLEN, &reg,
- &bit);
- ret = regmap_update_bits(pc->reg_pullen, reg,
- BIT(bit), 0);
- if (ret)
- return ret;
+ ret = meson_pinconf_disable_bias(pc, pin);
break;
case PIN_CONFIG_BIAS_PULL_UP:
- dev_dbg(pc->dev, "pin %u: enable pull-up\n", pin);
-
- meson_calc_reg_and_bit(bank, pin, REG_PULLEN,
- &reg, &bit);
- ret = regmap_update_bits(pc->reg_pullen, reg,
- BIT(bit), BIT(bit));
- if (ret)
- return ret;
-
- meson_calc_reg_and_bit(bank, pin, REG_PULL, &reg, &bit);
- ret = regmap_update_bits(pc->reg_pull, reg,
- BIT(bit), BIT(bit));
- if (ret)
- return ret;
+ ret = meson_pinconf_enable_bias(pc, pin, true);
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
- dev_dbg(pc->dev, "pin %u: enable pull-down\n", pin);
-
- meson_calc_reg_and_bit(bank, pin, REG_PULLEN,
- &reg, &bit);
- ret = regmap_update_bits(pc->reg_pullen, reg,
- BIT(bit), BIT(bit));
- if (ret)
- return ret;
-
- meson_calc_reg_and_bit(bank, pin, REG_PULL, &reg, &bit);
- ret = regmap_update_bits(pc->reg_pull, reg,
- BIT(bit), 0);
- if (ret)
- return ret;
+ ret = meson_pinconf_enable_bias(pc, pin, false);
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH_UA:
+ ret = meson_pinconf_set_drive_strength(pc, pin, arg);
+ break;
+ case PIN_CONFIG_OUTPUT_ENABLE:
+ ret = meson_pinconf_set_output(pc, pin, arg);
+ break;
+ case PIN_CONFIG_OUTPUT:
+ ret = meson_pinconf_set_output_drive(pc, pin, arg);
break;
default:
- return -ENOTSUPP;
+ ret = -ENOTSUPP;
}
+
+ if (ret)
+ return ret;
}
return 0;
@@ -269,12 +424,55 @@ static int meson_pinconf_get_pull(struct meson_pinctrl *pc, unsigned int pin)
return conf;
}
+static int meson_pinconf_get_drive_strength(struct meson_pinctrl *pc,
+ unsigned int pin,
+ u16 *drive_strength_ua)
+{
+ struct meson_bank *bank;
+ unsigned int reg, bit;
+ unsigned int val;
+ int ret;
+
+ if (!pc->reg_ds)
+ return -ENOTSUPP;
+
+ ret = meson_get_bank(pc, pin, &bank);
+ if (ret)
+ return ret;
+
+ meson_calc_reg_and_bit(bank, pin, REG_DS, &reg, &bit);
+
+ ret = regmap_read(pc->reg_ds, reg, &val);
+ if (ret)
+ return ret;
+
+ switch ((val >> bit) & 0x3) {
+ case MESON_PINCONF_DRV_500UA:
+ *drive_strength_ua = 500;
+ break;
+ case MESON_PINCONF_DRV_2500UA:
+ *drive_strength_ua = 2500;
+ break;
+ case MESON_PINCONF_DRV_3000UA:
+ *drive_strength_ua = 3000;
+ break;
+ case MESON_PINCONF_DRV_4000UA:
+ *drive_strength_ua = 4000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int meson_pinconf_get(struct pinctrl_dev *pcdev, unsigned int pin,
unsigned long *config)
{
struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
enum pin_config_param param = pinconf_to_config_param(*config);
u16 arg;
+ int ret;
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
@@ -285,6 +483,29 @@ static int meson_pinconf_get(struct pinctrl_dev *pcdev, unsigned int pin,
else
return -EINVAL;
break;
+ case PIN_CONFIG_DRIVE_STRENGTH_UA:
+ ret = meson_pinconf_get_drive_strength(pc, pin, &arg);
+ if (ret)
+ return ret;
+ break;
+ case PIN_CONFIG_OUTPUT_ENABLE:
+ ret = meson_pinconf_get_output(pc, pin);
+ if (ret <= 0)
+ return -EINVAL;
+ arg = 1;
+ break;
+ case PIN_CONFIG_OUTPUT:
+ ret = meson_pinconf_get_output(pc, pin);
+ if (ret <= 0)
+ return -EINVAL;
+
+ ret = meson_pinconf_get_drive(pc, pin);
+ if (ret < 0)
+ return -EINVAL;
+
+ arg = ret;
+ break;
+
default:
return -ENOTSUPP;
}
@@ -329,56 +550,19 @@ static const struct pinconf_ops meson_pinconf_ops = {
static int meson_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
{
- struct meson_pinctrl *pc = gpiochip_get_data(chip);
- unsigned int reg, bit;
- struct meson_bank *bank;
- int ret;
-
- ret = meson_get_bank(pc, gpio, &bank);
- if (ret)
- return ret;
-
- meson_calc_reg_and_bit(bank, gpio, REG_DIR, &reg, &bit);
-
- return regmap_update_bits(pc->reg_gpio, reg, BIT(bit), BIT(bit));
+ return meson_pinconf_set_output(gpiochip_get_data(chip), gpio, false);
}
static int meson_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
int value)
{
- struct meson_pinctrl *pc = gpiochip_get_data(chip);
- unsigned int reg, bit;
- struct meson_bank *bank;
- int ret;
-
- ret = meson_get_bank(pc, gpio, &bank);
- if (ret)
- return ret;
-
- meson_calc_reg_and_bit(bank, gpio, REG_DIR, &reg, &bit);
- ret = regmap_update_bits(pc->reg_gpio, reg, BIT(bit), 0);
- if (ret)
- return ret;
-
- meson_calc_reg_and_bit(bank, gpio, REG_OUT, &reg, &bit);
- return regmap_update_bits(pc->reg_gpio, reg, BIT(bit),
- value ? BIT(bit) : 0);
+ return meson_pinconf_set_output_drive(gpiochip_get_data(chip),
+ gpio, value);
}
static void meson_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
{
- struct meson_pinctrl *pc = gpiochip_get_data(chip);
- unsigned int reg, bit;
- struct meson_bank *bank;
- int ret;
-
- ret = meson_get_bank(pc, gpio, &bank);
- if (ret)
- return;
-
- meson_calc_reg_and_bit(bank, gpio, REG_OUT, &reg, &bit);
- regmap_update_bits(pc->reg_gpio, reg, BIT(bit),
- value ? BIT(bit) : 0);
+ meson_pinconf_set_drive(gpiochip_get_data(chip), gpio, value);
}
static int meson_gpio_get(struct gpio_chip *chip, unsigned gpio)
diff --git a/drivers/pinctrl/meson/pinctrl-meson.h b/drivers/pinctrl/meson/pinctrl-meson.h
index adab4ea078f9..c696f3241a36 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.h
+++ b/drivers/pinctrl/meson/pinctrl-meson.h
@@ -65,10 +65,21 @@ enum meson_reg_type {
REG_DIR,
REG_OUT,
REG_IN,
+ REG_DS,
NUM_REG,
};
/**
+ * enum meson_pinconf_drv - value of drive-strength supported
+ */
+enum meson_pinconf_drv {
+ MESON_PINCONF_DRV_500UA,
+ MESON_PINCONF_DRV_2500UA,
+ MESON_PINCONF_DRV_3000UA,
+ MESON_PINCONF_DRV_4000UA,
+};
+
+/**
* struct meson bank
*
* @name: bank name
@@ -126,7 +137,8 @@ struct meson_pinctrl {
.num_groups = ARRAY_SIZE(fn ## _groups), \
}
-#define BANK(n, f, l, fi, li, per, peb, pr, pb, dr, db, or, ob, ir, ib) \
+#define BANK_DS(n, f, l, fi, li, per, peb, pr, pb, dr, db, or, ob, ir, ib, \
+ dsr, dsb) \
{ \
.name = n, \
.first = f, \
@@ -139,9 +151,13 @@ struct meson_pinctrl {
[REG_DIR] = { dr, db }, \
[REG_OUT] = { or, ob }, \
[REG_IN] = { ir, ib }, \
+ [REG_DS] = { dsr, dsb }, \
}, \
}
+#define BANK(n, f, l, fi, li, per, peb, pr, pb, dr, db, or, ob, ir, ib) \
+ BANK_DS(n, f, l, fi, li, per, peb, pr, pb, dr, db, or, ob, ir, ib, 0, 0)
+
#define MESON_PIN(x) PINCTRL_PIN(x, #x)
/* Common pmx functions */
diff --git a/drivers/pinctrl/mvebu/pinctrl-kirkwood.c b/drivers/pinctrl/mvebu/pinctrl-kirkwood.c
index 19e69701747d..d45c31f281c8 100644
--- a/drivers/pinctrl/mvebu/pinctrl-kirkwood.c
+++ b/drivers/pinctrl/mvebu/pinctrl-kirkwood.c
@@ -16,341 +16,347 @@
#include "pinctrl-mvebu.h"
-#define V(f6180, f6190, f6192, f6281, f6282, dx4122) \
+#define V(f6180, f6190, f6192, f6281, f6282, dx4122, dx1135) \
((f6180 << 0) | (f6190 << 1) | (f6192 << 2) | \
- (f6281 << 3) | (f6282 << 4) | (dx4122 << 5))
+ (f6281 << 3) | (f6282 << 4) | (dx4122 << 5) | \
+ (dx1135 << 6))
enum kirkwood_variant {
- VARIANT_MV88F6180 = V(1, 0, 0, 0, 0, 0),
- VARIANT_MV88F6190 = V(0, 1, 0, 0, 0, 0),
- VARIANT_MV88F6192 = V(0, 0, 1, 0, 0, 0),
- VARIANT_MV88F6281 = V(0, 0, 0, 1, 0, 0),
- VARIANT_MV88F6282 = V(0, 0, 0, 0, 1, 0),
- VARIANT_MV98DX4122 = V(0, 0, 0, 0, 0, 1),
+ VARIANT_MV88F6180 = V(1, 0, 0, 0, 0, 0, 0),
+ VARIANT_MV88F6190 = V(0, 1, 0, 0, 0, 0, 0),
+ VARIANT_MV88F6192 = V(0, 0, 1, 0, 0, 0, 0),
+ VARIANT_MV88F6281 = V(0, 0, 0, 1, 0, 0, 0),
+ VARIANT_MV88F6282 = V(0, 0, 0, 0, 1, 0, 0),
+ VARIANT_MV98DX4122 = V(0, 0, 0, 0, 0, 1, 0),
+ VARIANT_MV98DX1135 = V(0, 0, 0, 0, 0, 0, 1),
};
static struct mvebu_mpp_mode mv88f6xxx_mpp_modes[] = {
MPP_MODE(0,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x1, "nand", "io2", V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x2, "spi", "cs", V(1, 1, 1, 1, 1, 1))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x1, "nand", "io2", V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x2, "spi", "cs", V(1, 1, 1, 1, 1, 1, 1))),
MPP_MODE(1,
- MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x1, "nand", "io3", V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x2, "spi", "mosi", V(1, 1, 1, 1, 1, 1))),
+ MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x1, "nand", "io3", V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x2, "spi", "mosi", V(1, 1, 1, 1, 1, 1, 1))),
MPP_MODE(2,
- MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x1, "nand", "io4", V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x2, "spi", "sck", V(1, 1, 1, 1, 1, 1))),
+ MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x1, "nand", "io4", V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x2, "spi", "sck", V(1, 1, 1, 1, 1, 1, 1))),
MPP_MODE(3,
- MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x1, "nand", "io5", V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x2, "spi", "miso", V(1, 1, 1, 1, 1, 1))),
+ MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x1, "nand", "io5", V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x2, "spi", "miso", V(1, 1, 1, 1, 1, 1, 1))),
MPP_MODE(4,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x1, "nand", "io6", V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x2, "uart0", "rxd", V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x5, "sata1", "act", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "hsync", V(0, 0, 0, 0, 1, 0)),
- MPP_VAR_FUNCTION(0xd, "ptp", "clk", V(1, 1, 1, 1, 0, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x1, "nand", "io6", V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x2, "uart0", "rxd", V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x5, "sata1", "act", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "hsync", V(0, 0, 0, 0, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xd, "ptp", "clk", V(1, 1, 1, 1, 0, 0, 0))),
MPP_MODE(5,
- MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x1, "nand", "io7", V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x2, "uart0", "txd", V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x4, "ptp", "trig", V(1, 1, 1, 1, 0, 0)),
- MPP_VAR_FUNCTION(0x5, "sata0", "act", V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "vsync", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x1, "nand", "io7", V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x2, "uart0", "txd", V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x4, "ptp", "trig", V(1, 1, 1, 1, 0, 0, 0)),
+ MPP_VAR_FUNCTION(0x5, "sata0", "act", V(0, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "vsync", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(6,
- MPP_VAR_FUNCTION(0x1, "sysrst", "out", V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x2, "spi", "mosi", V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x3, "ptp", "trig", V(1, 1, 1, 1, 0, 0))),
+ MPP_VAR_FUNCTION(0x1, "sysrst", "out", V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x2, "spi", "mosi", V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x3, "ptp", "trig", V(1, 1, 1, 1, 0, 0, 0))),
MPP_MODE(7,
- MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x1, "pex", "rsto", V(1, 1, 1, 1, 0, 1)),
- MPP_VAR_FUNCTION(0x2, "spi", "cs", V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x3, "ptp", "trig", V(1, 1, 1, 1, 0, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "pwm", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x1, "pex", "rsto", V(1, 1, 1, 1, 0, 1, 1)),
+ MPP_VAR_FUNCTION(0x2, "spi", "cs", V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x3, "ptp", "trig", V(1, 1, 1, 1, 0, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "pwm", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(8,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x1, "twsi0", "sda", V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x2, "uart0", "rts", V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x3, "uart1", "rts", V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x4, "mii-1", "rxerr", V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x5, "sata1", "prsnt", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xc, "ptp", "clk", V(1, 1, 1, 1, 0, 0)),
- MPP_VAR_FUNCTION(0xd, "mii", "col", V(1, 1, 1, 1, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x1, "twsi0", "sda", V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x2, "uart0", "rts", V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x3, "uart1", "rts", V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x4, "mii-1", "rxerr", V(0, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x5, "sata1", "prsnt", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xc, "ptp", "clk", V(1, 1, 1, 1, 0, 0, 0)),
+ MPP_VAR_FUNCTION(0xd, "mii", "col", V(1, 1, 1, 1, 1, 0, 0))),
MPP_MODE(9,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x1, "twsi0", "sck", V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x2, "uart0", "cts", V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x3, "uart1", "cts", V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x5, "sata0", "prsnt", V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xc, "ptp", "evreq", V(1, 1, 1, 1, 0, 0)),
- MPP_VAR_FUNCTION(0xd, "mii", "crs", V(1, 1, 1, 1, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x1, "twsi0", "sck", V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x2, "uart0", "cts", V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x3, "uart1", "cts", V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x5, "sata0", "prsnt", V(0, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xc, "ptp", "evreq", V(1, 1, 1, 1, 0, 0, 0)),
+ MPP_VAR_FUNCTION(0xd, "mii", "crs", V(1, 1, 1, 1, 1, 0, 0))),
MPP_MODE(10,
- MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x2, "spi", "sck", V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0X3, "uart0", "txd", V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x5, "sata1", "act", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xc, "ptp", "trig", V(1, 1, 1, 1, 0, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x2, "spi", "sck", V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0X3, "uart0", "txd", V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x5, "sata1", "act", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xc, "ptp", "trig", V(1, 1, 1, 1, 0, 0, 0))),
MPP_MODE(11,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x2, "spi", "miso", V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x3, "uart0", "rxd", V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x4, "ptp-1", "evreq", V(1, 1, 1, 1, 0, 0)),
- MPP_VAR_FUNCTION(0xc, "ptp-2", "trig", V(1, 1, 1, 1, 0, 0)),
- MPP_VAR_FUNCTION(0xd, "ptp", "clk", V(1, 1, 1, 1, 0, 0)),
- MPP_VAR_FUNCTION(0x5, "sata0", "act", V(0, 1, 1, 1, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x2, "spi", "miso", V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x3, "uart0", "rxd", V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x4, "ptp-1", "evreq", V(1, 1, 1, 1, 0, 0, 0)),
+ MPP_VAR_FUNCTION(0xc, "ptp-2", "trig", V(1, 1, 1, 1, 0, 0, 0)),
+ MPP_VAR_FUNCTION(0xd, "ptp", "clk", V(1, 1, 1, 1, 0, 0, 0)),
+ MPP_VAR_FUNCTION(0x5, "sata0", "act", V(0, 1, 1, 1, 1, 0, 0))),
MPP_MODE(12,
- MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 0, 1, 0)),
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 0, 0)),
- MPP_VAR_FUNCTION(0x1, "sdio", "clk", V(1, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xa, "audio", "spdifo", V(0, 0, 0, 0, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "spi", "mosi", V(0, 0, 0, 0, 1, 0)),
- MPP_VAR_FUNCTION(0xd, "twsi1", "sda", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 0, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 0, 0, 0)),
+ MPP_VAR_FUNCTION(0x1, "sdio", "clk", V(1, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xa, "audio", "spdifo", V(0, 0, 0, 0, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "spi", "mosi", V(0, 0, 0, 0, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xd, "twsi1", "sda", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(13,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x1, "sdio", "cmd", V(1, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x3, "uart1", "txd", V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0xa, "audio", "rmclk", V(0, 0, 0, 0, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "pwm", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x1, "sdio", "cmd", V(1, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x3, "uart1", "txd", V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0xa, "audio", "rmclk", V(0, 0, 0, 0, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "pwm", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(14,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x1, "sdio", "d0", V(1, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x3, "uart1", "rxd", V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x4, "sata1", "prsnt", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xa, "audio", "spdifi", V(0, 0, 0, 0, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "audio-1", "sdi", V(0, 0, 0, 0, 1, 0)),
- MPP_VAR_FUNCTION(0xd, "mii", "col", V(1, 1, 1, 1, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x1, "sdio", "d0", V(1, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x3, "uart1", "rxd", V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x4, "sata1", "prsnt", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xa, "audio", "spdifi", V(0, 0, 0, 0, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "audio-1", "sdi", V(0, 0, 0, 0, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xd, "mii", "col", V(1, 1, 1, 1, 1, 0, 0))),
MPP_MODE(15,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x1, "sdio", "d1", V(1, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x2, "uart0", "rts", V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x3, "uart1", "txd", V(1, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x4, "sata0", "act", V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "spi", "cs", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x1, "sdio", "d1", V(1, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x2, "uart0", "rts", V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x3, "uart1", "txd", V(1, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x4, "sata0", "act", V(0, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "spi", "cs", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(16,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x1, "sdio", "d2", V(1, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x2, "uart0", "cts", V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x3, "uart1", "rxd", V(1, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x4, "sata1", "act", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "extclk", V(0, 0, 0, 0, 1, 0)),
- MPP_VAR_FUNCTION(0xd, "mii", "crs", V(1, 1, 1, 1, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x1, "sdio", "d2", V(1, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x2, "uart0", "cts", V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x3, "uart1", "rxd", V(1, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x4, "sata1", "act", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "extclk", V(0, 0, 0, 0, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xd, "mii", "crs", V(1, 1, 1, 1, 1, 0, 0))),
MPP_MODE(17,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x1, "sdio", "d3", V(1, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x4, "sata0", "prsnt", V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xa, "sata1", "act", V(0, 0, 0, 0, 1, 0)),
- MPP_VAR_FUNCTION(0xd, "twsi1", "sck", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x1, "sdio", "d3", V(1, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x4, "sata0", "prsnt", V(0, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xa, "sata1", "act", V(0, 0, 0, 0, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xd, "twsi1", "sck", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(18,
- MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x1, "nand", "io0", V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x2, "pex", "clkreq", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x1, "nand", "io0", V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x2, "pex", "clkreq", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(19,
- MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x1, "nand", "io1", V(1, 1, 1, 1, 1, 1))),
+ MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x1, "nand", "io1", V(1, 1, 1, 1, 1, 1, 1))),
MPP_MODE(20,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x1, "ts", "mp0", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x2, "tdm", "tx0ql", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x3, "ge1", "txd0", V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x5, "sata1", "act", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "d0", V(0, 0, 0, 0, 1, 0)),
- MPP_VAR_FUNCTION(0xc, "mii", "rxerr", V(0, 0, 0, 0, 0, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)),
+ MPP_VAR_FUNCTION(0x1, "ts", "mp0", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x2, "tdm", "tx0ql", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x3, "ge1", "txd0", V(0, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x5, "sata1", "act", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "d0", V(0, 0, 0, 0, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xc, "mii", "rxerr", V(0, 0, 0, 0, 0, 0, 0))),
MPP_MODE(21,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x1, "ts", "mp1", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x2, "tdm", "rx0ql", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x3, "ge1", "txd1", V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(0, 0, 0, 0, 0, 0)),
- MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x5, "sata0", "act", V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "d1", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)),
+ MPP_VAR_FUNCTION(0x1, "ts", "mp1", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x2, "tdm", "rx0ql", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x3, "ge1", "txd1", V(0, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(0, 0, 0, 0, 0, 0, 0)),
+ MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x5, "sata0", "act", V(0, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "d1", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(22,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x1, "ts", "mp2", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x2, "tdm", "tx2ql", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x3, "ge1", "txd2", V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(0, 0, 0, 0, 0, 0)),
- MPP_VAR_FUNCTION(0x4, "audio", "rmclk", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x5, "sata1", "prsnt", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "d2", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)),
+ MPP_VAR_FUNCTION(0x1, "ts", "mp2", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x2, "tdm", "tx2ql", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x3, "ge1", "txd2", V(0, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(0, 0, 0, 0, 0, 0, 0)),
+ MPP_VAR_FUNCTION(0x4, "audio", "rmclk", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x5, "sata1", "prsnt", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "d2", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(23,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x1, "ts", "mp3", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x2, "tdm", "rx2ql", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x3, "ge1", "txd3", V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x4, "audio", "rmclk", V(0, 0, 0, 0, 0, 0)),
- MPP_VAR_FUNCTION(0x4, "audio", "bclk", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x5, "sata0", "prsnt", V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "d3", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)),
+ MPP_VAR_FUNCTION(0x1, "ts", "mp3", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x2, "tdm", "rx2ql", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x3, "ge1", "txd3", V(0, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x4, "audio", "rmclk", V(0, 0, 0, 0, 0, 0, 0)),
+ MPP_VAR_FUNCTION(0x4, "audio", "bclk", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x5, "sata0", "prsnt", V(0, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "d3", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(24,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x1, "ts", "mp4", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs0", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x3, "ge1", "rxd0", V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x4, "audio", "bclk", V(0, 0, 0, 0, 0, 0)),
- MPP_VAR_FUNCTION(0x4, "audio", "sdo", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "d4", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)),
+ MPP_VAR_FUNCTION(0x1, "ts", "mp4", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs0", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x3, "ge1", "rxd0", V(0, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x4, "audio", "bclk", V(0, 0, 0, 0, 0, 0, 0)),
+ MPP_VAR_FUNCTION(0x4, "audio", "sdo", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "d4", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(25,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x1, "ts", "mp5", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x2, "tdm", "spi-sck", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x3, "ge1", "rxd1", V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x4, "audio", "sdo", V(0, 0, 0, 0, 0, 0)),
- MPP_VAR_FUNCTION(0x4, "audio", "lrclk", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "d5", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)),
+ MPP_VAR_FUNCTION(0x1, "ts", "mp5", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x2, "tdm", "spi-sck", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x3, "ge1", "rxd1", V(0, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x4, "audio", "sdo", V(0, 0, 0, 0, 0, 0, 0)),
+ MPP_VAR_FUNCTION(0x4, "audio", "lrclk", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "d5", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(26,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x1, "ts", "mp6", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x2, "tdm", "spi-miso", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x3, "ge1", "rxd2", V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x4, "audio", "lrclk", V(0, 0, 0, 0, 0, 0)),
- MPP_VAR_FUNCTION(0x4, "audio", "mclk", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "d6", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)),
+ MPP_VAR_FUNCTION(0x1, "ts", "mp6", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x2, "tdm", "spi-miso", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x3, "ge1", "rxd2", V(0, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x4, "audio", "lrclk", V(0, 0, 0, 0, 0, 0, 0)),
+ MPP_VAR_FUNCTION(0x4, "audio", "mclk", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "d6", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(27,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x1, "ts", "mp7", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x2, "tdm", "spi-mosi", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x3, "ge1", "rxd3", V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x4, "audio", "mclk", V(0, 0, 0, 0, 0, 0)),
- MPP_VAR_FUNCTION(0x4, "audio", "sdi", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "d7", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)),
+ MPP_VAR_FUNCTION(0x1, "ts", "mp7", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x2, "tdm", "spi-mosi", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x3, "ge1", "rxd3", V(0, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x4, "audio", "mclk", V(0, 0, 0, 0, 0, 0, 0)),
+ MPP_VAR_FUNCTION(0x4, "audio", "sdi", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "d7", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(28,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x1, "ts", "mp8", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x2, "tdm", "int", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x3, "ge1", "col", V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x4, "audio", "sdi", V(0, 0, 0, 0, 0, 0)),
- MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "d8", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x1, "ts", "mp8", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x2, "tdm", "int", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x3, "ge1", "col", V(0, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x4, "audio", "sdi", V(0, 0, 0, 0, 0, 0, 0)),
+ MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "d8", V(0, 0, 0, 0, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x1, "nand", "ren", V(0, 0, 0, 0, 0, 0, 1))),
MPP_MODE(29,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x1, "ts", "mp9", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x2, "tdm", "rst", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x3, "ge1", "txclk", V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(0, 0, 0, 0, 0, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "d9", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x1, "ts", "mp9", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x2, "tdm", "rst", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x3, "ge1", "txclk", V(0, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(0, 0, 0, 0, 0, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "d9", V(0, 0, 0, 0, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x1, "nand", "wen", V(0, 0, 0, 0, 0, 0, 1))),
MPP_MODE(30,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x1, "ts", "mp10", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x2, "tdm", "pclk", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x3, "ge1", "rxctl", V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "d10", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)),
+ MPP_VAR_FUNCTION(0x1, "ts", "mp10", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x2, "tdm", "pclk", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x3, "ge1", "rxctl", V(0, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "d10", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(31,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x1, "ts", "mp11", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x2, "tdm", "fs", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x3, "ge1", "rxclk", V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "d11", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)),
+ MPP_VAR_FUNCTION(0x1, "ts", "mp11", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x2, "tdm", "fs", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x3, "ge1", "rxclk", V(0, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "d11", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(32,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x1, "ts", "mp12", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x2, "tdm", "drx", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x3, "ge1", "txclko", V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "d12", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)),
+ MPP_VAR_FUNCTION(0x1, "ts", "mp12", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x2, "tdm", "drx", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x3, "ge1", "txclko", V(0, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "d12", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(33,
- MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x2, "tdm", "dtx", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x3, "ge1", "txctl", V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "d13", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(0, 1, 1, 1, 1, 0, 1)),
+ MPP_VAR_FUNCTION(0x2, "tdm", "dtx", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x3, "ge1", "txctl", V(0, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "d13", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(34,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs1", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x3, "ge1", "txen", V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x5, "sata1", "act", V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "d14", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs1", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x3, "ge1", "txen", V(0, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x5, "sata1", "act", V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "d14", V(0, 0, 0, 0, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x1, "nand", "ale", V(0, 0, 0, 0, 0, 0, 1))),
MPP_MODE(35,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x2, "tdm", "tx0ql", V(0, 0, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x3, "ge1", "rxerr", V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x5, "sata0", "act", V(0, 1, 1, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "d15", V(0, 0, 0, 0, 1, 0)),
- MPP_VAR_FUNCTION(0xc, "mii", "rxerr", V(1, 1, 1, 1, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x2, "tdm", "tx0ql", V(0, 0, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x3, "ge1", "rxerr", V(0, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x5, "sata0", "act", V(0, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "d15", V(0, 0, 0, 0, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xc, "mii", "rxerr", V(1, 1, 1, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x1, "nand", "cen", V(0, 0, 0, 0, 0, 0, 1))),
MPP_MODE(36,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x1, "ts", "mp0", V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs1", V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(1, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "twsi1", "sda", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x1, "ts", "mp0", V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs1", V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(1, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "twsi1", "sda", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(37,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x1, "ts", "mp1", V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x2, "tdm", "tx2ql", V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(1, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "twsi1", "sck", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x1, "ts", "mp1", V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x2, "tdm", "tx2ql", V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(1, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "twsi1", "sck", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(38,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x1, "ts", "mp2", V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x2, "tdm", "rx2ql", V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x4, "audio", "rmclk", V(1, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "d18", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x1, "ts", "mp2", V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x2, "tdm", "rx2ql", V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x4, "audio", "rmclk", V(1, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "d18", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(39,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x1, "ts", "mp3", V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs0", V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x4, "audio", "bclk", V(1, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "d19", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x1, "ts", "mp3", V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs0", V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x4, "audio", "bclk", V(1, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "d19", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(40,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x1, "ts", "mp4", V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x2, "tdm", "spi-sck", V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x4, "audio", "sdo", V(1, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "d20", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x1, "ts", "mp4", V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x2, "tdm", "spi-sck", V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x4, "audio", "sdo", V(1, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "d20", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(41,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x1, "ts", "mp5", V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x2, "tdm", "spi-miso", V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x4, "audio", "lrclk", V(1, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "d21", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x1, "ts", "mp5", V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x2, "tdm", "spi-miso", V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x4, "audio", "lrclk", V(1, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "d21", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(42,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x1, "ts", "mp6", V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x2, "tdm", "spi-mosi", V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x4, "audio", "mclk", V(1, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "d22", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x1, "ts", "mp6", V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x2, "tdm", "spi-mosi", V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x4, "audio", "mclk", V(1, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "d22", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(43,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x1, "ts", "mp7", V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x2, "tdm", "int", V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x4, "audio", "sdi", V(1, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "d23", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x1, "ts", "mp7", V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x2, "tdm", "int", V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x4, "audio", "sdi", V(1, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "d23", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(44,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x1, "ts", "mp8", V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x2, "tdm", "rst", V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(1, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "clk", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x1, "ts", "mp8", V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x2, "tdm", "rst", V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(1, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "clk", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(45,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 1)),
- MPP_VAR_FUNCTION(0x1, "ts", "mp9", V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x2, "tdm", "pclk", V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "e", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 1, 1)),
+ MPP_VAR_FUNCTION(0x1, "ts", "mp9", V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x2, "tdm", "pclk", V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "e", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(46,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x1, "ts", "mp10", V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x2, "tdm", "fs", V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "hsync", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x1, "ts", "mp10", V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x2, "tdm", "fs", V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "hsync", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(47,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x1, "ts", "mp11", V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x2, "tdm", "drx", V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "vsync", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x1, "ts", "mp11", V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x2, "tdm", "drx", V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "vsync", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(48,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x1, "ts", "mp12", V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x2, "tdm", "dtx", V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "d16", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x1, "ts", "mp12", V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x2, "tdm", "dtx", V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "d16", V(0, 0, 0, 0, 1, 0, 0))),
MPP_MODE(49,
- MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 0, 1)),
- MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(0, 0, 0, 0, 1, 0)),
- MPP_VAR_FUNCTION(0x1, "ts", "mp9", V(0, 0, 0, 1, 0, 0)),
- MPP_VAR_FUNCTION(0x2, "tdm", "rx0ql", V(0, 0, 0, 1, 1, 0)),
- MPP_VAR_FUNCTION(0x5, "ptp", "clk", V(0, 0, 0, 1, 0, 0)),
- MPP_VAR_FUNCTION(0xa, "pex", "clkreq", V(0, 0, 0, 0, 1, 0)),
- MPP_VAR_FUNCTION(0xb, "lcd", "d17", V(0, 0, 0, 0, 1, 0))),
+ MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 0, 1, 1)),
+ MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(0, 0, 0, 0, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x1, "ts", "mp9", V(0, 0, 0, 1, 0, 0, 0)),
+ MPP_VAR_FUNCTION(0x2, "tdm", "rx0ql", V(0, 0, 0, 1, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0x5, "ptp", "clk", V(0, 0, 0, 1, 0, 0, 0)),
+ MPP_VAR_FUNCTION(0xa, "pex", "clkreq", V(0, 0, 0, 0, 1, 0, 0)),
+ MPP_VAR_FUNCTION(0xb, "lcd", "d17", V(0, 0, 0, 0, 1, 0, 0))),
};
static const struct mvebu_mpp_ctrl mv88f6180_mpp_controls[] = {
@@ -440,6 +446,17 @@ static struct mvebu_pinctrl_soc_info mv98dx4122_info = {
.ngpioranges = ARRAY_SIZE(mv88f628x_gpio_ranges),
};
+static struct mvebu_pinctrl_soc_info mv98dx1135_info = {
+ .variant = VARIANT_MV98DX1135,
+ .controls = mv88f628x_mpp_controls,
+ .ncontrols = ARRAY_SIZE(mv88f628x_mpp_controls),
+ .modes = mv88f6xxx_mpp_modes,
+ .nmodes = ARRAY_SIZE(mv88f6xxx_mpp_modes),
+ .gpioranges = mv88f628x_gpio_ranges,
+ .ngpioranges = ARRAY_SIZE(mv88f628x_gpio_ranges),
+};
+
+
static const struct of_device_id kirkwood_pinctrl_of_match[] = {
{ .compatible = "marvell,88f6180-pinctrl", .data = &mv88f6180_info },
{ .compatible = "marvell,88f6190-pinctrl", .data = &mv88f6190_info },
@@ -447,6 +464,7 @@ static const struct of_device_id kirkwood_pinctrl_of_match[] = {
{ .compatible = "marvell,88f6281-pinctrl", .data = &mv88f6281_info },
{ .compatible = "marvell,88f6282-pinctrl", .data = &mv88f6282_info },
{ .compatible = "marvell,98dx4122-pinctrl", .data = &mv98dx4122_info },
+ { .compatible = "marvell,98dx1135-pinctrl", .data = &mv98dx1135_info },
{ }
};
diff --git a/drivers/pinctrl/nomadik/pinctrl-ab8500.c b/drivers/pinctrl/nomadik/pinctrl-ab8500.c
index 0723627c7bc2..3106a21cd277 100644
--- a/drivers/pinctrl/nomadik/pinctrl-ab8500.c
+++ b/drivers/pinctrl/nomadik/pinctrl-ab8500.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) ST-Ericsson SA 2012
*
* Author: Patrice Chotard <patrice.chotard@stericsson.com> for ST-Ericsson.
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/pinctrl/nomadik/pinctrl-ab8505.c b/drivers/pinctrl/nomadik/pinctrl-ab8505.c
index 2683509c1410..5e6e7d28390a 100644
--- a/drivers/pinctrl/nomadik/pinctrl-ab8505.c
+++ b/drivers/pinctrl/nomadik/pinctrl-ab8505.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) ST-Ericsson SA 2012
*
* Author: Patrice Chotard <patrice.chotard@stericsson.com> for ST-Ericsson.
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c
index ec02739bd21b..ddd1f466d302 100644
--- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c
+++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic GPIO driver for logic cells found in the Nomadik SoC
*
@@ -5,10 +6,6 @@
* Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it>
* Rewritten based on work by Prafulla WADASKAR <prafulla.wadaskar@st.com>
* Copyright (C) 2011-2013 Linus Walleij <linus.walleij@linaro.org>
- *
- * 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.
*/
#include <linux/kernel.h>
#include <linux/init.h>
diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c
index 4ccd71bbc72a..9eb86309c70b 100644
--- a/drivers/pinctrl/pinconf-generic.c
+++ b/drivers/pinctrl/pinconf-generic.c
@@ -38,6 +38,7 @@ static const struct pin_config_item conf_items[] = {
PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL, false),
PCONFDUMP(PIN_CONFIG_DRIVE_PUSH_PULL, "output drive push pull", NULL, false),
PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH, "output drive strength", "mA", true),
+ PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH_UA, "output drive strength", "uA", true),
PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "usec", true),
PCONFDUMP(PIN_CONFIG_INPUT_ENABLE, "input enabled", NULL, false),
PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL, false),
@@ -166,6 +167,7 @@ static const struct pinconf_generic_params dt_params[] = {
{ "drive-open-source", PIN_CONFIG_DRIVE_OPEN_SOURCE, 0 },
{ "drive-push-pull", PIN_CONFIG_DRIVE_PUSH_PULL, 0 },
{ "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
+ { "drive-strength-microamp", PIN_CONFIG_DRIVE_STRENGTH_UA, 0 },
{ "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 },
{ "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
{ "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 },
diff --git a/drivers/pinctrl/pinctrl-bm1880.c b/drivers/pinctrl/pinctrl-bm1880.c
index 446b07d8fbfc..63b130cb1ffb 100644
--- a/drivers/pinctrl/pinctrl-bm1880.c
+++ b/drivers/pinctrl/pinctrl-bm1880.c
@@ -27,6 +27,7 @@
* @ngroups: Number of @groups
* @funcs: Pinmux functions
* @nfuncs: Number of @funcs
+ * @pconf: Pinconf data
*/
struct bm1880_pinctrl {
void __iomem *base;
@@ -35,6 +36,7 @@ struct bm1880_pinctrl {
unsigned int ngroups;
const struct bm1880_pinmux_function *funcs;
unsigned int nfuncs;
+ const struct bm1880_pinconf_data *pinconf;
};
/**
@@ -55,7 +57,6 @@ struct bm1880_pctrl_group {
* @groups: List of pingroups for this function.
* @ngroups: Number of entries in @groups.
* @mux_val: Selector for this function
- * @mux_mask: Mask for function specific selector
* @mux: Offset of function specific mux
* @mux_shift: Shift for function specific selector
*/
@@ -64,11 +65,18 @@ struct bm1880_pinmux_function {
const char * const *groups;
unsigned int ngroups;
u32 mux_val;
- u32 mux_mask;
u32 mux;
u8 mux_shift;
};
+/**
+ * struct bm1880_pinconf_data - pinconf data
+ * @drv_bits: Drive strength bit width
+ */
+struct bm1880_pinconf_data {
+ u32 drv_bits;
+};
+
static const struct pinctrl_pin_desc bm1880_pins[] = {
PINCTRL_PIN(0, "MIO0"),
PINCTRL_PIN(1, "MIO1"),
@@ -636,165 +644,273 @@ static const char * const i2s1_group[] = { "i2s1_grp" };
static const char * const i2s1_mclkin_group[] = { "i2s1_mclkin_grp" };
static const char * const spi0_group[] = { "spi0_grp" };
-#define BM1880_PINMUX_FUNCTION(fname, mval, mask) \
+#define BM1880_PINMUX_FUNCTION(fname, mval) \
[F_##fname] = { \
.name = #fname, \
.groups = fname##_group, \
.ngroups = ARRAY_SIZE(fname##_group), \
.mux_val = mval, \
- .mux_mask = mask, \
}
-#define BM1880_PINMUX_FUNCTION_MUX(fname, mval, mask, offset, shift)\
- [F_##fname] = { \
- .name = #fname, \
- .groups = fname##_group, \
- .ngroups = ARRAY_SIZE(fname##_group), \
- .mux_val = mval, \
- .mux_mask = mask, \
- .mux = offset, \
- .mux_shift = shift, \
+static const struct bm1880_pinmux_function bm1880_pmux_functions[] = {
+ BM1880_PINMUX_FUNCTION(nand, 2),
+ BM1880_PINMUX_FUNCTION(spi, 0),
+ BM1880_PINMUX_FUNCTION(emmc, 1),
+ BM1880_PINMUX_FUNCTION(sdio, 0),
+ BM1880_PINMUX_FUNCTION(eth0, 0),
+ BM1880_PINMUX_FUNCTION(pwm0, 2),
+ BM1880_PINMUX_FUNCTION(pwm1, 2),
+ BM1880_PINMUX_FUNCTION(pwm2, 2),
+ BM1880_PINMUX_FUNCTION(pwm3, 2),
+ BM1880_PINMUX_FUNCTION(pwm4, 2),
+ BM1880_PINMUX_FUNCTION(pwm5, 2),
+ BM1880_PINMUX_FUNCTION(pwm6, 2),
+ BM1880_PINMUX_FUNCTION(pwm7, 2),
+ BM1880_PINMUX_FUNCTION(pwm8, 2),
+ BM1880_PINMUX_FUNCTION(pwm9, 2),
+ BM1880_PINMUX_FUNCTION(pwm10, 2),
+ BM1880_PINMUX_FUNCTION(pwm11, 2),
+ BM1880_PINMUX_FUNCTION(pwm12, 2),
+ BM1880_PINMUX_FUNCTION(pwm13, 2),
+ BM1880_PINMUX_FUNCTION(pwm14, 2),
+ BM1880_PINMUX_FUNCTION(pwm15, 2),
+ BM1880_PINMUX_FUNCTION(pwm16, 2),
+ BM1880_PINMUX_FUNCTION(pwm17, 2),
+ BM1880_PINMUX_FUNCTION(pwm18, 2),
+ BM1880_PINMUX_FUNCTION(pwm19, 2),
+ BM1880_PINMUX_FUNCTION(pwm20, 2),
+ BM1880_PINMUX_FUNCTION(pwm21, 2),
+ BM1880_PINMUX_FUNCTION(pwm22, 2),
+ BM1880_PINMUX_FUNCTION(pwm23, 2),
+ BM1880_PINMUX_FUNCTION(pwm24, 2),
+ BM1880_PINMUX_FUNCTION(pwm25, 2),
+ BM1880_PINMUX_FUNCTION(pwm26, 2),
+ BM1880_PINMUX_FUNCTION(pwm27, 2),
+ BM1880_PINMUX_FUNCTION(pwm28, 2),
+ BM1880_PINMUX_FUNCTION(pwm29, 2),
+ BM1880_PINMUX_FUNCTION(pwm30, 2),
+ BM1880_PINMUX_FUNCTION(pwm31, 2),
+ BM1880_PINMUX_FUNCTION(pwm32, 2),
+ BM1880_PINMUX_FUNCTION(pwm33, 2),
+ BM1880_PINMUX_FUNCTION(pwm34, 2),
+ BM1880_PINMUX_FUNCTION(pwm35, 2),
+ BM1880_PINMUX_FUNCTION(pwm36, 2),
+ BM1880_PINMUX_FUNCTION(pwm37, 2),
+ BM1880_PINMUX_FUNCTION(i2c0, 1),
+ BM1880_PINMUX_FUNCTION(i2c1, 1),
+ BM1880_PINMUX_FUNCTION(i2c2, 1),
+ BM1880_PINMUX_FUNCTION(i2c3, 1),
+ BM1880_PINMUX_FUNCTION(i2c4, 1),
+ BM1880_PINMUX_FUNCTION(uart0, 3),
+ BM1880_PINMUX_FUNCTION(uart1, 3),
+ BM1880_PINMUX_FUNCTION(uart2, 3),
+ BM1880_PINMUX_FUNCTION(uart3, 3),
+ BM1880_PINMUX_FUNCTION(uart4, 1),
+ BM1880_PINMUX_FUNCTION(uart5, 1),
+ BM1880_PINMUX_FUNCTION(uart6, 1),
+ BM1880_PINMUX_FUNCTION(uart7, 1),
+ BM1880_PINMUX_FUNCTION(uart8, 1),
+ BM1880_PINMUX_FUNCTION(uart9, 1),
+ BM1880_PINMUX_FUNCTION(uart10, 1),
+ BM1880_PINMUX_FUNCTION(uart11, 1),
+ BM1880_PINMUX_FUNCTION(uart12, 3),
+ BM1880_PINMUX_FUNCTION(uart13, 3),
+ BM1880_PINMUX_FUNCTION(uart14, 3),
+ BM1880_PINMUX_FUNCTION(uart15, 3),
+ BM1880_PINMUX_FUNCTION(gpio0, 0),
+ BM1880_PINMUX_FUNCTION(gpio1, 0),
+ BM1880_PINMUX_FUNCTION(gpio2, 0),
+ BM1880_PINMUX_FUNCTION(gpio3, 0),
+ BM1880_PINMUX_FUNCTION(gpio4, 0),
+ BM1880_PINMUX_FUNCTION(gpio5, 0),
+ BM1880_PINMUX_FUNCTION(gpio6, 0),
+ BM1880_PINMUX_FUNCTION(gpio7, 0),
+ BM1880_PINMUX_FUNCTION(gpio8, 0),
+ BM1880_PINMUX_FUNCTION(gpio9, 0),
+ BM1880_PINMUX_FUNCTION(gpio10, 0),
+ BM1880_PINMUX_FUNCTION(gpio11, 0),
+ BM1880_PINMUX_FUNCTION(gpio12, 1),
+ BM1880_PINMUX_FUNCTION(gpio13, 1),
+ BM1880_PINMUX_FUNCTION(gpio14, 0),
+ BM1880_PINMUX_FUNCTION(gpio15, 0),
+ BM1880_PINMUX_FUNCTION(gpio16, 0),
+ BM1880_PINMUX_FUNCTION(gpio17, 0),
+ BM1880_PINMUX_FUNCTION(gpio18, 0),
+ BM1880_PINMUX_FUNCTION(gpio19, 0),
+ BM1880_PINMUX_FUNCTION(gpio20, 0),
+ BM1880_PINMUX_FUNCTION(gpio21, 0),
+ BM1880_PINMUX_FUNCTION(gpio22, 0),
+ BM1880_PINMUX_FUNCTION(gpio23, 0),
+ BM1880_PINMUX_FUNCTION(gpio24, 0),
+ BM1880_PINMUX_FUNCTION(gpio25, 0),
+ BM1880_PINMUX_FUNCTION(gpio26, 0),
+ BM1880_PINMUX_FUNCTION(gpio27, 0),
+ BM1880_PINMUX_FUNCTION(gpio28, 0),
+ BM1880_PINMUX_FUNCTION(gpio29, 0),
+ BM1880_PINMUX_FUNCTION(gpio30, 0),
+ BM1880_PINMUX_FUNCTION(gpio31, 0),
+ BM1880_PINMUX_FUNCTION(gpio32, 0),
+ BM1880_PINMUX_FUNCTION(gpio33, 0),
+ BM1880_PINMUX_FUNCTION(gpio34, 0),
+ BM1880_PINMUX_FUNCTION(gpio35, 0),
+ BM1880_PINMUX_FUNCTION(gpio36, 0),
+ BM1880_PINMUX_FUNCTION(gpio37, 0),
+ BM1880_PINMUX_FUNCTION(gpio38, 0),
+ BM1880_PINMUX_FUNCTION(gpio39, 0),
+ BM1880_PINMUX_FUNCTION(gpio40, 0),
+ BM1880_PINMUX_FUNCTION(gpio41, 0),
+ BM1880_PINMUX_FUNCTION(gpio42, 0),
+ BM1880_PINMUX_FUNCTION(gpio43, 0),
+ BM1880_PINMUX_FUNCTION(gpio44, 0),
+ BM1880_PINMUX_FUNCTION(gpio45, 0),
+ BM1880_PINMUX_FUNCTION(gpio46, 0),
+ BM1880_PINMUX_FUNCTION(gpio47, 0),
+ BM1880_PINMUX_FUNCTION(gpio48, 0),
+ BM1880_PINMUX_FUNCTION(gpio49, 0),
+ BM1880_PINMUX_FUNCTION(gpio50, 0),
+ BM1880_PINMUX_FUNCTION(gpio51, 0),
+ BM1880_PINMUX_FUNCTION(gpio52, 0),
+ BM1880_PINMUX_FUNCTION(gpio53, 0),
+ BM1880_PINMUX_FUNCTION(gpio54, 0),
+ BM1880_PINMUX_FUNCTION(gpio55, 0),
+ BM1880_PINMUX_FUNCTION(gpio56, 0),
+ BM1880_PINMUX_FUNCTION(gpio57, 0),
+ BM1880_PINMUX_FUNCTION(gpio58, 0),
+ BM1880_PINMUX_FUNCTION(gpio59, 0),
+ BM1880_PINMUX_FUNCTION(gpio60, 0),
+ BM1880_PINMUX_FUNCTION(gpio61, 0),
+ BM1880_PINMUX_FUNCTION(gpio62, 0),
+ BM1880_PINMUX_FUNCTION(gpio63, 0),
+ BM1880_PINMUX_FUNCTION(gpio64, 0),
+ BM1880_PINMUX_FUNCTION(gpio65, 0),
+ BM1880_PINMUX_FUNCTION(gpio66, 0),
+ BM1880_PINMUX_FUNCTION(gpio67, 0),
+ BM1880_PINMUX_FUNCTION(eth1, 1),
+ BM1880_PINMUX_FUNCTION(i2s0, 2),
+ BM1880_PINMUX_FUNCTION(i2s0_mclkin, 1),
+ BM1880_PINMUX_FUNCTION(i2s1, 2),
+ BM1880_PINMUX_FUNCTION(i2s1_mclkin, 1),
+ BM1880_PINMUX_FUNCTION(spi0, 1),
+};
+
+#define BM1880_PINCONF_DAT(_width) \
+ { \
+ .drv_bits = _width, \
}
-static const struct bm1880_pinmux_function bm1880_pmux_functions[] = {
- BM1880_PINMUX_FUNCTION(nand, 2, 0x03),
- BM1880_PINMUX_FUNCTION(spi, 0, 0x03),
- BM1880_PINMUX_FUNCTION(emmc, 1, 0x03),
- BM1880_PINMUX_FUNCTION(sdio, 0, 0x03),
- BM1880_PINMUX_FUNCTION(eth0, 0, 0x03),
- BM1880_PINMUX_FUNCTION_MUX(pwm0, 2, 0x0F, 0x50, 0x00),
- BM1880_PINMUX_FUNCTION_MUX(pwm1, 2, 0x0F, 0x50, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(pwm2, 2, 0x0F, 0x50, 0x08),
- BM1880_PINMUX_FUNCTION_MUX(pwm3, 2, 0x0F, 0x50, 0x0C),
- BM1880_PINMUX_FUNCTION_MUX(pwm4, 2, 0x0F, 0x50, 0x10),
- BM1880_PINMUX_FUNCTION_MUX(pwm5, 2, 0x0F, 0x50, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(pwm6, 2, 0x0F, 0x50, 0x18),
- BM1880_PINMUX_FUNCTION_MUX(pwm7, 2, 0x0F, 0x50, 0x1C),
- BM1880_PINMUX_FUNCTION_MUX(pwm8, 2, 0x0F, 0x54, 0x00),
- BM1880_PINMUX_FUNCTION_MUX(pwm9, 2, 0x0F, 0x54, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(pwm10, 2, 0x0F, 0x54, 0x08),
- BM1880_PINMUX_FUNCTION_MUX(pwm11, 2, 0x0F, 0x54, 0x0C),
- BM1880_PINMUX_FUNCTION_MUX(pwm12, 2, 0x0F, 0x54, 0x10),
- BM1880_PINMUX_FUNCTION_MUX(pwm13, 2, 0x0F, 0x54, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(pwm14, 2, 0x0F, 0x54, 0x18),
- BM1880_PINMUX_FUNCTION_MUX(pwm15, 2, 0x0F, 0x54, 0x1C),
- BM1880_PINMUX_FUNCTION_MUX(pwm16, 2, 0x0F, 0x58, 0x00),
- BM1880_PINMUX_FUNCTION_MUX(pwm17, 2, 0x0F, 0x58, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(pwm18, 2, 0x0F, 0x58, 0x08),
- BM1880_PINMUX_FUNCTION_MUX(pwm19, 2, 0x0F, 0x58, 0x0C),
- BM1880_PINMUX_FUNCTION_MUX(pwm20, 2, 0x0F, 0x58, 0x10),
- BM1880_PINMUX_FUNCTION_MUX(pwm21, 2, 0x0F, 0x58, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(pwm22, 2, 0x0F, 0x58, 0x18),
- BM1880_PINMUX_FUNCTION_MUX(pwm23, 2, 0x0F, 0x58, 0x1C),
- BM1880_PINMUX_FUNCTION_MUX(pwm24, 2, 0x0F, 0x5C, 0x00),
- BM1880_PINMUX_FUNCTION_MUX(pwm25, 2, 0x0F, 0x5C, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(pwm26, 2, 0x0F, 0x5C, 0x08),
- BM1880_PINMUX_FUNCTION_MUX(pwm27, 2, 0x0F, 0x5C, 0x0C),
- BM1880_PINMUX_FUNCTION_MUX(pwm28, 2, 0x0F, 0x5C, 0x10),
- BM1880_PINMUX_FUNCTION_MUX(pwm29, 2, 0x0F, 0x5C, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(pwm30, 2, 0x0F, 0x5C, 0x18),
- BM1880_PINMUX_FUNCTION_MUX(pwm31, 2, 0x0F, 0x5C, 0x1C),
- BM1880_PINMUX_FUNCTION_MUX(pwm32, 2, 0x0F, 0x60, 0x00),
- BM1880_PINMUX_FUNCTION_MUX(pwm33, 2, 0x0F, 0x60, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(pwm34, 2, 0x0F, 0x60, 0x08),
- BM1880_PINMUX_FUNCTION_MUX(pwm35, 2, 0x0F, 0x60, 0x0C),
- BM1880_PINMUX_FUNCTION_MUX(pwm36, 2, 0x0F, 0x60, 0x10),
- BM1880_PINMUX_FUNCTION_MUX(pwm37, 2, 0x0F, 0x60, 0x1C),
- BM1880_PINMUX_FUNCTION(i2c0, 1, 0x03),
- BM1880_PINMUX_FUNCTION(i2c1, 1, 0x03),
- BM1880_PINMUX_FUNCTION(i2c2, 1, 0x03),
- BM1880_PINMUX_FUNCTION(i2c3, 1, 0x03),
- BM1880_PINMUX_FUNCTION(i2c4, 1, 0x03),
- BM1880_PINMUX_FUNCTION(uart0, 1, 0x03),
- BM1880_PINMUX_FUNCTION(uart1, 1, 0x03),
- BM1880_PINMUX_FUNCTION(uart2, 1, 0x03),
- BM1880_PINMUX_FUNCTION(uart3, 1, 0x03),
- BM1880_PINMUX_FUNCTION(uart4, 1, 0x03),
- BM1880_PINMUX_FUNCTION(uart5, 1, 0x03),
- BM1880_PINMUX_FUNCTION(uart6, 1, 0x03),
- BM1880_PINMUX_FUNCTION(uart7, 1, 0x03),
- BM1880_PINMUX_FUNCTION(uart8, 1, 0x03),
- BM1880_PINMUX_FUNCTION(uart9, 1, 0x03),
- BM1880_PINMUX_FUNCTION(uart10, 1, 0x03),
- BM1880_PINMUX_FUNCTION(uart11, 1, 0x03),
- BM1880_PINMUX_FUNCTION(uart12, 3, 0x03),
- BM1880_PINMUX_FUNCTION(uart13, 3, 0x03),
- BM1880_PINMUX_FUNCTION(uart14, 3, 0x03),
- BM1880_PINMUX_FUNCTION(uart15, 3, 0x03),
- BM1880_PINMUX_FUNCTION_MUX(gpio0, 0, 0x03, 0x4E0, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio1, 0, 0x03, 0x4E4, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio2, 0, 0x03, 0x4E4, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio3, 0, 0x03, 0x4E8, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio4, 0, 0x03, 0x4E8, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio5, 0, 0x03, 0x4EC, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio6, 0, 0x03, 0x4EC, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio7, 0, 0x03, 0x4F0, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio8, 0, 0x03, 0x4F0, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio9, 0, 0x03, 0x4F4, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio10, 0, 0x03, 0x4F4, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio11, 0, 0x03, 0x4F8, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio12, 1, 0x03, 0x4F8, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio13, 1, 0x03, 0x4FC, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio14, 0, 0x03, 0x474, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio15, 0, 0x03, 0x478, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio16, 0, 0x03, 0x478, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio17, 0, 0x03, 0x47C, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio18, 0, 0x03, 0x47C, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio19, 0, 0x03, 0x480, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio20, 0, 0x03, 0x480, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio21, 0, 0x03, 0x484, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio22, 0, 0x03, 0x484, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio23, 0, 0x03, 0x488, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio24, 0, 0x03, 0x488, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio25, 0, 0x03, 0x48C, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio26, 0, 0x03, 0x48C, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio27, 0, 0x03, 0x490, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio28, 0, 0x03, 0x490, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio29, 0, 0x03, 0x494, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio30, 0, 0x03, 0x494, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio31, 0, 0x03, 0x498, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio32, 0, 0x03, 0x498, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio33, 0, 0x03, 0x49C, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio34, 0, 0x03, 0x49C, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio35, 0, 0x03, 0x4A0, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio36, 0, 0x03, 0x4A0, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio37, 0, 0x03, 0x4A4, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio38, 0, 0x03, 0x4A4, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio39, 0, 0x03, 0x4A8, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio40, 0, 0x03, 0x4A8, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio41, 0, 0x03, 0x4AC, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio42, 0, 0x03, 0x4AC, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio43, 0, 0x03, 0x4B0, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio44, 0, 0x03, 0x4B0, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio45, 0, 0x03, 0x4B4, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio46, 0, 0x03, 0x4B4, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio47, 0, 0x03, 0x4B8, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio48, 0, 0x03, 0x4B8, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio49, 0, 0x03, 0x4BC, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio50, 0, 0x03, 0x4BC, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio51, 0, 0x03, 0x4C0, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio52, 0, 0x03, 0x4C0, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio53, 0, 0x03, 0x4C4, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio54, 0, 0x03, 0x4C4, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio55, 0, 0x03, 0x4C8, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio56, 0, 0x03, 0x4C8, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio57, 0, 0x03, 0x4CC, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio58, 0, 0x03, 0x4CC, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio59, 0, 0x03, 0x4D0, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio60, 0, 0x03, 0x4D0, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio61, 0, 0x03, 0x4D4, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio62, 0, 0x03, 0x4D4, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio63, 0, 0x03, 0x4D8, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio64, 0, 0x03, 0x4D8, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio65, 0, 0x03, 0x4DC, 0x04),
- BM1880_PINMUX_FUNCTION_MUX(gpio66, 0, 0x03, 0x4DC, 0x14),
- BM1880_PINMUX_FUNCTION_MUX(gpio67, 0, 0x03, 0x4E0, 0x04),
- BM1880_PINMUX_FUNCTION(eth1, 1, 0x03),
- BM1880_PINMUX_FUNCTION(i2s0, 2, 0x03),
- BM1880_PINMUX_FUNCTION(i2s0_mclkin, 1, 0x03),
- BM1880_PINMUX_FUNCTION(i2s1, 2, 0x03),
- BM1880_PINMUX_FUNCTION(i2s1_mclkin, 1, 0x03),
- BM1880_PINMUX_FUNCTION(spi0, 1, 0x03),
+static const struct bm1880_pinconf_data bm1880_pinconf[] = {
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x03),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
+ BM1880_PINCONF_DAT(0x02),
};
static int bm1880_pctrl_get_groups_count(struct pinctrl_dev *pctldev)
@@ -870,33 +986,308 @@ static int bm1880_pinmux_set_mux(struct pinctrl_dev *pctldev,
const struct bm1880_pinmux_function *func = &pctrl->funcs[function];
int i;
- if (func->mux) {
+ for (i = 0; i < pgrp->npins; i++) {
+ unsigned int pin = pgrp->pins[i];
+ u32 offset = (pin >> 1) << 2;
+ u32 mux_offset = ((!((pin + 1) & 1) << 4) + 4);
u32 regval = readl_relaxed(pctrl->base + BM1880_REG_MUX +
- func->mux);
+ offset);
+
+ regval &= ~(0x03 << mux_offset);
+ regval |= func->mux_val << mux_offset;
+
+ writel_relaxed(regval, pctrl->base + BM1880_REG_MUX + offset);
+ }
+
+ return 0;
+}
+
+#define BM1880_PINCONF(pin, idx) ((!((pin + 1) & 1) << 4) + idx)
+#define BM1880_PINCONF_PULLCTRL(pin) BM1880_PINCONF(pin, 0)
+#define BM1880_PINCONF_PULLUP(pin) BM1880_PINCONF(pin, 1)
+#define BM1880_PINCONF_PULLDOWN(pin) BM1880_PINCONF(pin, 2)
+#define BM1880_PINCONF_DRV(pin) BM1880_PINCONF(pin, 6)
+#define BM1880_PINCONF_SCHMITT(pin) BM1880_PINCONF(pin, 9)
+#define BM1880_PINCONF_SLEW(pin) BM1880_PINCONF(pin, 10)
+
+static int bm1880_pinconf_drv_set(unsigned int mA, u32 width,
+ u32 *regval, u32 bit_offset)
+{
+ u32 _regval;
+
+ _regval = *regval;
+
+ /*
+ * There are two sets of drive strength bit width exposed by the
+ * SoC at 4mA step, hence we need to handle them separately.
+ */
+ if (width == 0x03) {
+ switch (mA) {
+ case 4:
+ _regval &= ~(width << bit_offset);
+ _regval |= (0 << bit_offset);
+ break;
+ case 8:
+ _regval &= ~(width << bit_offset);
+ _regval |= (1 << bit_offset);
+ break;
+ case 12:
+ _regval &= ~(width << bit_offset);
+ _regval |= (2 << bit_offset);
+ break;
+ case 16:
+ _regval &= ~(width << bit_offset);
+ _regval |= (3 << bit_offset);
+ break;
+ case 20:
+ _regval &= ~(width << bit_offset);
+ _regval |= (4 << bit_offset);
+ break;
+ case 24:
+ _regval &= ~(width << bit_offset);
+ _regval |= (5 << bit_offset);
+ break;
+ case 28:
+ _regval &= ~(width << bit_offset);
+ _regval |= (6 << bit_offset);
+ break;
+ case 32:
+ _regval &= ~(width << bit_offset);
+ _regval |= (7 << bit_offset);
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ switch (mA) {
+ case 4:
+ _regval &= ~(width << bit_offset);
+ _regval |= (0 << bit_offset);
+ break;
+ case 8:
+ _regval &= ~(width << bit_offset);
+ _regval |= (1 << bit_offset);
+ break;
+ case 12:
+ _regval &= ~(width << bit_offset);
+ _regval |= (2 << bit_offset);
+ break;
+ case 16:
+ _regval &= ~(width << bit_offset);
+ _regval |= (3 << bit_offset);
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ *regval = _regval;
+
+ return 0;
+}
+
+static int bm1880_pinconf_drv_get(u32 width, u32 drv)
+{
+ int ret = -ENOTSUPP;
- regval &= ~(func->mux_mask << func->mux_shift);
- regval |= func->mux_val << func->mux_shift;
- writel_relaxed(regval, pctrl->base + BM1880_REG_MUX +
- func->mux);
+ /*
+ * There are two sets of drive strength bit width exposed by the
+ * SoC at 4mA step, hence we need to handle them separately.
+ */
+ if (width == 0x03) {
+ switch (drv) {
+ case 0:
+ ret = 4;
+ break;
+ case 1:
+ ret = 8;
+ break;
+ case 2:
+ ret = 12;
+ break;
+ case 3:
+ ret = 16;
+ break;
+ case 4:
+ ret = 20;
+ break;
+ case 5:
+ ret = 24;
+ break;
+ case 6:
+ ret = 28;
+ break;
+ case 7:
+ ret = 32;
+ break;
+ default:
+ break;
+ }
} else {
- for (i = 0; i < pgrp->npins; i++) {
- unsigned int pin = pgrp->pins[i];
- u32 offset = (pin >> 1) << 2;
- u32 mux_offset = ((!((pin + 1) & 1) << 4) + 4);
- u32 regval = readl_relaxed(pctrl->base +
- BM1880_REG_MUX + offset);
-
- regval &= ~(func->mux_mask << mux_offset);
- regval |= func->mux_val << mux_offset;
-
- writel_relaxed(regval, pctrl->base +
- BM1880_REG_MUX + offset);
+ switch (drv) {
+ case 0:
+ ret = 4;
+ break;
+ case 1:
+ ret = 8;
+ break;
+ case 2:
+ ret = 12;
+ break;
+ case 3:
+ ret = 16;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int bm1880_pinconf_cfg_get(struct pinctrl_dev *pctldev,
+ unsigned int pin,
+ unsigned long *config)
+{
+ struct bm1880_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ unsigned int param = pinconf_to_config_param(*config);
+ unsigned int arg = 0;
+ u32 regval, offset, bit_offset;
+ int ret;
+
+ offset = (pin >> 1) << 2;
+ regval = readl_relaxed(pctrl->base + BM1880_REG_MUX + offset);
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_PULL_UP:
+ bit_offset = BM1880_PINCONF_PULLUP(pin);
+ arg = !!(regval & BIT(bit_offset));
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ bit_offset = BM1880_PINCONF_PULLDOWN(pin);
+ arg = !!(regval & BIT(bit_offset));
+ break;
+ case PIN_CONFIG_BIAS_DISABLE:
+ bit_offset = BM1880_PINCONF_PULLCTRL(pin);
+ arg = !!(regval & BIT(bit_offset));
+ break;
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ bit_offset = BM1880_PINCONF_SCHMITT(pin);
+ arg = !!(regval & BIT(bit_offset));
+ break;
+ case PIN_CONFIG_SLEW_RATE:
+ bit_offset = BM1880_PINCONF_SLEW(pin);
+ arg = !!(regval & BIT(bit_offset));
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ bit_offset = BM1880_PINCONF_DRV(pin);
+ ret = bm1880_pinconf_drv_get(pctrl->pinconf[pin].drv_bits,
+ !!(regval & BIT(bit_offset)));
+ if (ret < 0)
+ return ret;
+
+ arg = ret;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ *config = pinconf_to_config_packed(param, arg);
+
+ return 0;
+}
+
+static int bm1880_pinconf_cfg_set(struct pinctrl_dev *pctldev,
+ unsigned int pin,
+ unsigned long *configs,
+ unsigned int num_configs)
+{
+ struct bm1880_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ u32 regval, offset, bit_offset;
+ int i, ret;
+
+ offset = (pin >> 1) << 2;
+ regval = readl_relaxed(pctrl->base + BM1880_REG_MUX + offset);
+
+ for (i = 0; i < num_configs; i++) {
+ unsigned int param = pinconf_to_config_param(configs[i]);
+ unsigned int arg = pinconf_to_config_argument(configs[i]);
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_PULL_UP:
+ bit_offset = BM1880_PINCONF_PULLUP(pin);
+ regval |= BIT(bit_offset);
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ bit_offset = BM1880_PINCONF_PULLDOWN(pin);
+ regval |= BIT(bit_offset);
+ break;
+ case PIN_CONFIG_BIAS_DISABLE:
+ bit_offset = BM1880_PINCONF_PULLCTRL(pin);
+ regval |= BIT(bit_offset);
+ break;
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ bit_offset = BM1880_PINCONF_SCHMITT(pin);
+ if (arg)
+ regval |= BIT(bit_offset);
+ else
+ regval &= ~BIT(bit_offset);
+ break;
+ case PIN_CONFIG_SLEW_RATE:
+ bit_offset = BM1880_PINCONF_SLEW(pin);
+ if (arg)
+ regval |= BIT(bit_offset);
+ else
+ regval &= ~BIT(bit_offset);
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ bit_offset = BM1880_PINCONF_DRV(pin);
+ ret = bm1880_pinconf_drv_set(arg,
+ pctrl->pinconf[pin].drv_bits,
+ &regval, bit_offset);
+ if (ret < 0)
+ return ret;
+
+ break;
+ default:
+ dev_warn(pctldev->dev,
+ "unsupported configuration parameter '%u'\n",
+ param);
+ continue;
}
+
+ writel_relaxed(regval, pctrl->base + BM1880_REG_MUX + offset);
}
return 0;
}
+static int bm1880_pinconf_group_set(struct pinctrl_dev *pctldev,
+ unsigned int selector,
+ unsigned long *configs,
+ unsigned int num_configs)
+{
+ int i, ret;
+ struct bm1880_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ const struct bm1880_pctrl_group *pgrp = &pctrl->groups[selector];
+
+ for (i = 0; i < pgrp->npins; i++) {
+ ret = bm1880_pinconf_cfg_set(pctldev, pgrp->pins[i], configs,
+ num_configs);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct pinconf_ops bm1880_pinconf_ops = {
+ .is_generic = true,
+ .pin_config_get = bm1880_pinconf_cfg_get,
+ .pin_config_set = bm1880_pinconf_cfg_set,
+ .pin_config_group_set = bm1880_pinconf_group_set,
+};
+
static const struct pinmux_ops bm1880_pinmux_ops = {
.get_functions_count = bm1880_pmux_get_functions_count,
.get_function_name = bm1880_pmux_get_function_name,
@@ -910,6 +1301,7 @@ static struct pinctrl_desc bm1880_desc = {
.npins = ARRAY_SIZE(bm1880_pins),
.pctlops = &bm1880_pctrl_ops,
.pmxops = &bm1880_pinmux_ops,
+ .confops = &bm1880_pinconf_ops,
.owner = THIS_MODULE,
};
@@ -932,6 +1324,7 @@ static int bm1880_pinctrl_probe(struct platform_device *pdev)
pctrl->ngroups = ARRAY_SIZE(bm1880_pctrl_groups);
pctrl->funcs = bm1880_pmux_functions;
pctrl->nfuncs = ARRAY_SIZE(bm1880_pmux_functions);
+ pctrl->pinconf = bm1880_pinconf;
pctrl->pctrldev = devm_pinctrl_register(&pdev->dev, &bm1880_desc,
pctrl);
diff --git a/drivers/pinctrl/pinctrl-falcon.c b/drivers/pinctrl/pinctrl-falcon.c
index 4d032e637f5c..ef133a82e612 100644
--- a/drivers/pinctrl/pinctrl-falcon.c
+++ b/drivers/pinctrl/pinctrl-falcon.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/pinctrl/pinmux-falcon.c
* based on linux/drivers/pinctrl/pinmux-pxa910.c
*
- * 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.
- *
* Copyright (C) 2012 Thomas Langer <thomas.langer@lantiq.com>
* Copyright (C) 2012 John Crispin <john@phrozen.org>
*/
diff --git a/drivers/pinctrl/pinctrl-mcp23s08.c b/drivers/pinctrl/pinctrl-mcp23s08.c
index 568ca96cdb6d..3a235487e38d 100644
--- a/drivers/pinctrl/pinctrl-mcp23s08.c
+++ b/drivers/pinctrl/pinctrl-mcp23s08.c
@@ -771,6 +771,10 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
if (ret < 0)
goto fail;
+ ret = devm_gpiochip_add_data(dev, &mcp->chip, mcp);
+ if (ret < 0)
+ goto fail;
+
mcp->irq_controller =
device_property_read_bool(dev, "interrupt-controller");
if (mcp->irq && mcp->irq_controller) {
@@ -812,10 +816,6 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
goto fail;
}
- ret = devm_gpiochip_add_data(dev, &mcp->chip, mcp);
- if (ret < 0)
- goto fail;
-
if (one_regmap_config) {
mcp->pinctrl_desc.name = devm_kasprintf(dev, GFP_KERNEL,
"mcp23xxx-pinctrl.%d", raw_chip_address);
diff --git a/drivers/pinctrl/pinctrl-ocelot.c b/drivers/pinctrl/pinctrl-ocelot.c
index 3b4ca52d2456..fb76fb2e9ea5 100644
--- a/drivers/pinctrl/pinctrl-ocelot.c
+++ b/drivers/pinctrl/pinctrl-ocelot.c
@@ -396,7 +396,7 @@ static int ocelot_pin_function_idx(struct ocelot_pinctrl *info,
return -1;
}
-#define REG(r, info, p) ((r) * (info)->stride + (4 * ((p) / 32)))
+#define REG_ALT(msb, info, p) (OCELOT_GPIO_ALT0 * (info)->stride + 4 * ((msb) + ((info)->stride * ((p) / 32))))
static int ocelot_pinmux_set_mux(struct pinctrl_dev *pctldev,
unsigned int selector, unsigned int group)
@@ -412,19 +412,21 @@ static int ocelot_pinmux_set_mux(struct pinctrl_dev *pctldev,
/*
* f is encoded on two bits.
- * bit 0 of f goes in BIT(pin) of ALT0, bit 1 of f goes in BIT(pin) of
- * ALT1
+ * bit 0 of f goes in BIT(pin) of ALT[0], bit 1 of f goes in BIT(pin) of
+ * ALT[1]
* This is racy because both registers can't be updated at the same time
* but it doesn't matter much for now.
*/
- regmap_update_bits(info->map, REG(OCELOT_GPIO_ALT0, info, pin->pin),
+ regmap_update_bits(info->map, REG_ALT(0, info, pin->pin),
BIT(p), f << p);
- regmap_update_bits(info->map, REG(OCELOT_GPIO_ALT1, info, pin->pin),
+ regmap_update_bits(info->map, REG_ALT(1, info, pin->pin),
BIT(p), f << (p - 1));
return 0;
}
+#define REG(r, info, p) ((r) * (info)->stride + (4 * ((p) / 32)))
+
static int ocelot_gpio_set_direction(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned int pin, bool input)
@@ -432,7 +434,7 @@ static int ocelot_gpio_set_direction(struct pinctrl_dev *pctldev,
struct ocelot_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
unsigned int p = pin % 32;
- regmap_update_bits(info->map, REG(OCELOT_GPIO_OE, info, p), BIT(p),
+ regmap_update_bits(info->map, REG(OCELOT_GPIO_OE, info, pin), BIT(p),
input ? 0 : BIT(p));
return 0;
@@ -445,9 +447,9 @@ static int ocelot_gpio_request_enable(struct pinctrl_dev *pctldev,
struct ocelot_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
unsigned int p = offset % 32;
- regmap_update_bits(info->map, REG(OCELOT_GPIO_ALT0, info, offset),
+ regmap_update_bits(info->map, REG_ALT(0, info, offset),
BIT(p), 0);
- regmap_update_bits(info->map, REG(OCELOT_GPIO_ALT1, info, offset),
+ regmap_update_bits(info->map, REG_ALT(1, info, offset),
BIT(p), 0);
return 0;
diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index 807a3263d849..62a622159006 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -3204,6 +3204,7 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank,
base,
&rockchip_regmap_config);
}
+ of_node_put(node);
}
bank->irq = irq_of_parse_and_map(bank->of_node, 0);
diff --git a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c
index 195b442a2343..b9688ea548da 100644
--- a/drivers/pinctrl/pinctrl-st.c
+++ b/drivers/pinctrl/pinctrl-st.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 STMicroelectronics (R&D) Limited.
* Authors:
* Srinivas Kandagatla <srinivas.kandagatla@st.com>
- *
- * 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.
*/
#include <linux/init.h>
diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c
index eba872ce4a7c..d3332da35637 100644
--- a/drivers/pinctrl/pinctrl-stmfx.c
+++ b/drivers/pinctrl/pinctrl-stmfx.c
@@ -622,6 +622,7 @@ static int stmfx_pinctrl_probe(struct platform_device *pdev)
pctl->pctl_desc.pins = stmfx_pins;
pctl->pctl_desc.npins = ARRAY_SIZE(stmfx_pins);
pctl->pctl_desc.owner = THIS_MODULE;
+ pctl->pctl_desc.link_consumers = true;
ret = devm_pinctrl_register_and_init(pctl->dev, &pctl->pctl_desc,
pctl, &pctl->pctl_dev);
diff --git a/drivers/pinctrl/pinctrl-tb10x.c b/drivers/pinctrl/pinctrl-tb10x.c
index 02b43f559e83..1f64e2e7efd9 100644
--- a/drivers/pinctrl/pinctrl-tb10x.c
+++ b/drivers/pinctrl/pinctrl-tb10x.c
@@ -471,22 +471,22 @@ struct tb10x_port {
* @base: register set base address.
* @pingroups: pointer to an array of the pin groups this driver manages.
* @pinfuncgrpcnt: number of pingroups in @pingroups.
- * @pinfuncs: pointer to an array of pin functions this driver manages.
* @pinfuncnt: number of pin functions in @pinfuncs.
* @mutex: mutex for exclusive access to a pin controller's state.
* @ports: current state of each port.
* @gpios: Indicates if a given pin is currently used as GPIO (1) or not (0).
+ * @pinfuncs: flexible array of pin functions this driver manages.
*/
struct tb10x_pinctrl {
struct pinctrl_dev *pctl;
void *base;
const struct tb10x_pinfuncgrp *pingroups;
unsigned int pinfuncgrpcnt;
- struct tb10x_of_pinfunc *pinfuncs;
unsigned int pinfuncnt;
struct mutex mutex;
struct tb10x_port ports[TB10X_PORTS];
DECLARE_BITMAP(gpios, MAX_PIN + 1);
+ struct tb10x_of_pinfunc pinfuncs[];
};
static inline void tb10x_pinctrl_set_config(struct tb10x_pinctrl *state,
@@ -759,15 +759,13 @@ static int tb10x_pinctrl_probe(struct platform_device *pdev)
return -EINVAL;
}
- state = devm_kzalloc(dev, sizeof(struct tb10x_pinctrl) +
- of_get_child_count(of_node)
- * sizeof(struct tb10x_of_pinfunc),
- GFP_KERNEL);
+ state = devm_kzalloc(dev, struct_size(state, pinfuncs,
+ of_get_child_count(of_node)),
+ GFP_KERNEL);
if (!state)
return -ENOMEM;
platform_set_drvdata(pdev, state);
- state->pinfuncs = (struct tb10x_of_pinfunc *)(state + 1);
mutex_init(&state->mutex);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig
index 890d0a3a790b..8e14a5f2e970 100644
--- a/drivers/pinctrl/qcom/Kconfig
+++ b/drivers/pinctrl/qcom/Kconfig
@@ -169,11 +169,20 @@ config PINCTRL_SDM660
config PINCTRL_SDM845
tristate "Qualcomm Technologies Inc SDM845 pin controller driver"
- depends on GPIOLIB && OF
+ depends on GPIOLIB && (OF || ACPI)
select PINCTRL_MSM
help
This is the pinctrl, pinmux, pinconf and gpiolib driver for the
Qualcomm Technologies Inc TLMM block found on the Qualcomm
Technologies Inc SDM845 platform.
+config PINCTRL_SM8150
+ tristate "Qualcomm Technologies Inc SM8150 pin controller driver"
+ depends on GPIOLIB && OF
+ select PINCTRL_MSM
+ help
+ This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+ Qualcomm Technologies Inc TLMM block found on the Qualcomm
+ Technologies Inc SM8150 platform.
+
endif
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index 344b4c6a6c6e..ebe906872272 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -22,3 +22,4 @@ obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-gpio.o
obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-mpp.o
obj-$(CONFIG_PINCTRL_SDM660) += pinctrl-sdm660.o
obj-$(CONFIG_PINCTRL_SDM845) += pinctrl-sdm845.o
+obj-$(CONFIG_PINCTRL_SM8150) += pinctrl-sm8150.o
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
index 6e319bcc2326..7f35c196bb3e 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -599,8 +599,23 @@ static int msm_gpio_init_valid_mask(struct gpio_chip *chip)
int ret;
unsigned int len, i;
unsigned int max_gpios = pctrl->soc->ngpios;
+ const int *reserved = pctrl->soc->reserved_gpios;
u16 *tmp;
+ /* Driver provided reserved list overrides DT and ACPI */
+ if (reserved) {
+ bitmap_fill(chip->valid_mask, max_gpios);
+ for (i = 0; reserved[i] >= 0; i++) {
+ if (i >= max_gpios || reserved[i] >= max_gpios) {
+ dev_err(pctrl->dev, "invalid list of reserved GPIOs\n");
+ return -EINVAL;
+ }
+ clear_bit(reserved[i], chip->valid_mask);
+ }
+
+ return 0;
+ }
+
/* The number of GPIOs in the ACPI tables */
len = ret = device_property_read_u16_array(pctrl->dev, "gpios", NULL,
0);
@@ -729,7 +744,7 @@ static void msm_gpio_irq_mask(struct irq_data *d)
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
}
-static void msm_gpio_irq_unmask(struct irq_data *d)
+static void msm_gpio_irq_clear_unmask(struct irq_data *d, bool status_clear)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
@@ -741,6 +756,17 @@ static void msm_gpio_irq_unmask(struct irq_data *d)
raw_spin_lock_irqsave(&pctrl->lock, flags);
+ if (status_clear) {
+ /*
+ * clear the interrupt status bit before unmask to avoid
+ * any erroneous interrupts that would have got latched
+ * when the interrupt is not in use.
+ */
+ val = msm_readl_intr_status(pctrl, g);
+ val &= ~BIT(g->intr_status_bit);
+ msm_writel_intr_status(val, pctrl, g);
+ }
+
val = msm_readl_intr_cfg(pctrl, g);
val |= BIT(g->intr_raw_status_bit);
val |= BIT(g->intr_enable_bit);
@@ -751,6 +777,17 @@ static void msm_gpio_irq_unmask(struct irq_data *d)
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
}
+static void msm_gpio_irq_enable(struct irq_data *d)
+{
+
+ msm_gpio_irq_clear_unmask(d, true);
+}
+
+static void msm_gpio_irq_unmask(struct irq_data *d)
+{
+ msm_gpio_irq_clear_unmask(d, false);
+}
+
static void msm_gpio_irq_ack(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
@@ -956,6 +993,9 @@ static void msm_gpio_irq_handler(struct irq_desc *desc)
static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl)
{
+ if (pctrl->soc->reserved_gpios)
+ return true;
+
return device_property_read_u16_array(pctrl->dev, "gpios", NULL, 0) > 0;
}
@@ -978,6 +1018,7 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
chip->need_valid_mask = msm_gpio_needs_valid_mask(pctrl);
pctrl->irq_chip.name = "msmgpio";
+ pctrl->irq_chip.irq_enable = msm_gpio_irq_enable;
pctrl->irq_chip.irq_mask = msm_gpio_irq_mask;
pctrl->irq_chip.irq_unmask = msm_gpio_irq_unmask;
pctrl->irq_chip.irq_ack = msm_gpio_irq_ack;
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.h b/drivers/pinctrl/qcom/pinctrl-msm.h
index b724581c605c..48569cda8471 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.h
+++ b/drivers/pinctrl/qcom/pinctrl-msm.h
@@ -113,6 +113,7 @@ struct msm_pinctrl_soc_data {
bool pull_no_keeper;
const char *const *tiles;
unsigned int ntiles;
+ const int *reserved_gpios;
};
extern const struct dev_pm_ops msm_pinctrl_dev_pm_ops;
diff --git a/drivers/pinctrl/qcom/pinctrl-sdm845.c b/drivers/pinctrl/qcom/pinctrl-sdm845.c
index c97f20fca5fd..39f498c09906 100644
--- a/drivers/pinctrl/qcom/pinctrl-sdm845.c
+++ b/drivers/pinctrl/qcom/pinctrl-sdm845.c
@@ -3,6 +3,7 @@
* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
*/
+#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
@@ -420,10 +421,10 @@ DECLARE_MSM_GPIO_PINS(147);
DECLARE_MSM_GPIO_PINS(148);
DECLARE_MSM_GPIO_PINS(149);
-static const unsigned int sdc2_clk_pins[] = { 150 };
-static const unsigned int sdc2_cmd_pins[] = { 151 };
-static const unsigned int sdc2_data_pins[] = { 152 };
-static const unsigned int ufs_reset_pins[] = { 153 };
+static const unsigned int ufs_reset_pins[] = { 150 };
+static const unsigned int sdc2_clk_pins[] = { 151 };
+static const unsigned int sdc2_cmd_pins[] = { 152 };
+static const unsigned int sdc2_data_pins[] = { 153 };
enum sdm845_functions {
msm_mux_gpio,
@@ -1271,10 +1272,14 @@ static const struct msm_pingroup sdm845_groups[] = {
PINGROUP(147, NORTH, _, _, _, _, _, _, _, _, _, _),
PINGROUP(148, NORTH, _, _, _, _, _, _, _, _, _, _),
PINGROUP(149, NORTH, _, _, _, _, _, _, _, _, _, _),
+ UFS_RESET(ufs_reset, 0x99f000),
SDC_QDSD_PINGROUP(sdc2_clk, 0x99a000, 14, 6),
SDC_QDSD_PINGROUP(sdc2_cmd, 0x99a000, 11, 3),
SDC_QDSD_PINGROUP(sdc2_data, 0x99a000, 9, 0),
- UFS_RESET(ufs_reset, 0x99f000),
+};
+
+static const int sdm845_acpi_reserved_gpios[] = {
+ 0, 1, 2, 3, 81, 82, 83, 84, -1
};
static const struct msm_pinctrl_soc_data sdm845_pinctrl = {
@@ -1284,14 +1289,42 @@ static const struct msm_pinctrl_soc_data sdm845_pinctrl = {
.nfunctions = ARRAY_SIZE(sdm845_functions),
.groups = sdm845_groups,
.ngroups = ARRAY_SIZE(sdm845_groups),
+ .ngpios = 151,
+};
+
+static const struct msm_pinctrl_soc_data sdm845_acpi_pinctrl = {
+ .pins = sdm845_pins,
+ .npins = ARRAY_SIZE(sdm845_pins),
+ .groups = sdm845_groups,
+ .ngroups = ARRAY_SIZE(sdm845_groups),
+ .reserved_gpios = sdm845_acpi_reserved_gpios,
.ngpios = 150,
};
static int sdm845_pinctrl_probe(struct platform_device *pdev)
{
- return msm_pinctrl_probe(pdev, &sdm845_pinctrl);
+ int ret;
+
+ if (pdev->dev.of_node) {
+ ret = msm_pinctrl_probe(pdev, &sdm845_pinctrl);
+ } else if (has_acpi_companion(&pdev->dev)) {
+ ret = msm_pinctrl_probe(pdev, &sdm845_acpi_pinctrl);
+ } else {
+ dev_err(&pdev->dev, "DT and ACPI disabled\n");
+ return -EINVAL;
+ }
+
+ return ret;
}
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id sdm845_pinctrl_acpi_match[] = {
+ { "QCOM0217"},
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, sdm845_pinctrl_acpi_match);
+#endif
+
static const struct of_device_id sdm845_pinctrl_of_match[] = {
{ .compatible = "qcom,sdm845-pinctrl", },
{ },
@@ -1302,6 +1335,7 @@ static struct platform_driver sdm845_pinctrl_driver = {
.name = "sdm845-pinctrl",
.pm = &msm_pinctrl_dev_pm_ops,
.of_match_table = sdm845_pinctrl_of_match,
+ .acpi_match_table = ACPI_PTR(sdm845_pinctrl_acpi_match),
},
.probe = sdm845_pinctrl_probe,
.remove = msm_pinctrl_remove,
diff --git a/drivers/pinctrl/qcom/pinctrl-sm8150.c b/drivers/pinctrl/qcom/pinctrl-sm8150.c
new file mode 100644
index 000000000000..7359bae68c69
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-sm8150.c
@@ -0,0 +1,1548 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-msm.h"
+
+static const char * const sm8150_tiles[] = {
+ "north",
+ "south",
+ "east",
+ "west"
+};
+
+enum {
+ NORTH,
+ SOUTH,
+ EAST,
+ WEST
+};
+
+#define FUNCTION(fname) \
+ [msm_mux_##fname] = { \
+ .name = #fname, \
+ .groups = fname##_groups, \
+ .ngroups = ARRAY_SIZE(fname##_groups), \
+ }
+
+#define PINGROUP(id, _tile, f1, f2, f3, f4, f5, f6, f7, f8, f9) \
+ { \
+ .name = "gpio" #id, \
+ .pins = gpio##id##_pins, \
+ .npins = (unsigned int)ARRAY_SIZE(gpio##id##_pins), \
+ .funcs = (int[]){ \
+ msm_mux_gpio, /* gpio mode */ \
+ msm_mux_##f1, \
+ msm_mux_##f2, \
+ msm_mux_##f3, \
+ msm_mux_##f4, \
+ msm_mux_##f5, \
+ msm_mux_##f6, \
+ msm_mux_##f7, \
+ msm_mux_##f8, \
+ msm_mux_##f9 \
+ }, \
+ .nfuncs = 10, \
+ .ctl_reg = 0x1000 * id, \
+ .io_reg = 0x1000 * id + 0x4, \
+ .intr_cfg_reg = 0x1000 * id + 0x8, \
+ .intr_status_reg = 0x1000 * id + 0xc, \
+ .intr_target_reg = 0x1000 * id + 0x8, \
+ .tile = _tile, \
+ .mux_bit = 2, \
+ .pull_bit = 0, \
+ .drv_bit = 6, \
+ .oe_bit = 9, \
+ .in_bit = 0, \
+ .out_bit = 1, \
+ .intr_enable_bit = 0, \
+ .intr_status_bit = 0, \
+ .intr_target_bit = 5, \
+ .intr_target_kpss_val = 3, \
+ .intr_raw_status_bit = 4, \
+ .intr_polarity_bit = 1, \
+ .intr_detection_bit = 2, \
+ .intr_detection_width = 2, \
+ }
+
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \
+ { \
+ .name = #pg_name, \
+ .pins = pg_name##_pins, \
+ .npins = (unsigned int)ARRAY_SIZE(pg_name##_pins), \
+ .ctl_reg = ctl, \
+ .io_reg = 0, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .intr_target_reg = 0, \
+ .tile = NORTH, \
+ .mux_bit = -1, \
+ .pull_bit = pull, \
+ .drv_bit = drv, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = -1, \
+ .intr_enable_bit = -1, \
+ .intr_status_bit = -1, \
+ .intr_target_bit = -1, \
+ .intr_raw_status_bit = -1, \
+ .intr_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
+
+#define UFS_RESET(pg_name, offset) \
+ { \
+ .name = #pg_name, \
+ .pins = pg_name##_pins, \
+ .npins = (unsigned int)ARRAY_SIZE(pg_name##_pins), \
+ .ctl_reg = offset, \
+ .io_reg = offset + 0x4, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .intr_target_reg = 0, \
+ .tile = SOUTH, \
+ .mux_bit = -1, \
+ .pull_bit = 3, \
+ .drv_bit = 0, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = 0, \
+ .intr_enable_bit = -1, \
+ .intr_status_bit = -1, \
+ .intr_target_bit = -1, \
+ .intr_raw_status_bit = -1, \
+ .intr_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
+
+static const struct pinctrl_pin_desc sm8150_pins[] = {
+ PINCTRL_PIN(0, "GPIO_0"),
+ PINCTRL_PIN(1, "GPIO_1"),
+ PINCTRL_PIN(2, "GPIO_2"),
+ PINCTRL_PIN(3, "GPIO_3"),
+ PINCTRL_PIN(4, "GPIO_4"),
+ PINCTRL_PIN(5, "GPIO_5"),
+ PINCTRL_PIN(6, "GPIO_6"),
+ PINCTRL_PIN(7, "GPIO_7"),
+ PINCTRL_PIN(8, "GPIO_8"),
+ PINCTRL_PIN(9, "GPIO_9"),
+ PINCTRL_PIN(10, "GPIO_10"),
+ PINCTRL_PIN(11, "GPIO_11"),
+ PINCTRL_PIN(12, "GPIO_12"),
+ PINCTRL_PIN(13, "GPIO_13"),
+ PINCTRL_PIN(14, "GPIO_14"),
+ PINCTRL_PIN(15, "GPIO_15"),
+ PINCTRL_PIN(16, "GPIO_16"),
+ PINCTRL_PIN(17, "GPIO_17"),
+ PINCTRL_PIN(18, "GPIO_18"),
+ PINCTRL_PIN(19, "GPIO_19"),
+ PINCTRL_PIN(20, "GPIO_20"),
+ PINCTRL_PIN(21, "GPIO_21"),
+ PINCTRL_PIN(22, "GPIO_22"),
+ PINCTRL_PIN(23, "GPIO_23"),
+ PINCTRL_PIN(24, "GPIO_24"),
+ PINCTRL_PIN(25, "GPIO_25"),
+ PINCTRL_PIN(26, "GPIO_26"),
+ PINCTRL_PIN(27, "GPIO_27"),
+ PINCTRL_PIN(28, "GPIO_28"),
+ PINCTRL_PIN(29, "GPIO_29"),
+ PINCTRL_PIN(30, "GPIO_30"),
+ PINCTRL_PIN(31, "GPIO_31"),
+ PINCTRL_PIN(32, "GPIO_32"),
+ PINCTRL_PIN(33, "GPIO_33"),
+ PINCTRL_PIN(34, "GPIO_34"),
+ PINCTRL_PIN(35, "GPIO_35"),
+ PINCTRL_PIN(36, "GPIO_36"),
+ PINCTRL_PIN(37, "GPIO_37"),
+ PINCTRL_PIN(38, "GPIO_38"),
+ PINCTRL_PIN(39, "GPIO_39"),
+ PINCTRL_PIN(40, "GPIO_40"),
+ PINCTRL_PIN(41, "GPIO_41"),
+ PINCTRL_PIN(42, "GPIO_42"),
+ PINCTRL_PIN(43, "GPIO_43"),
+ PINCTRL_PIN(44, "GPIO_44"),
+ PINCTRL_PIN(45, "GPIO_45"),
+ PINCTRL_PIN(46, "GPIO_46"),
+ PINCTRL_PIN(47, "GPIO_47"),
+ PINCTRL_PIN(48, "GPIO_48"),
+ PINCTRL_PIN(49, "GPIO_49"),
+ PINCTRL_PIN(50, "GPIO_50"),
+ PINCTRL_PIN(51, "GPIO_51"),
+ PINCTRL_PIN(52, "GPIO_52"),
+ PINCTRL_PIN(53, "GPIO_53"),
+ PINCTRL_PIN(54, "GPIO_54"),
+ PINCTRL_PIN(55, "GPIO_55"),
+ PINCTRL_PIN(56, "GPIO_56"),
+ PINCTRL_PIN(57, "GPIO_57"),
+ PINCTRL_PIN(58, "GPIO_58"),
+ PINCTRL_PIN(59, "GPIO_59"),
+ PINCTRL_PIN(60, "GPIO_60"),
+ PINCTRL_PIN(61, "GPIO_61"),
+ PINCTRL_PIN(62, "GPIO_62"),
+ PINCTRL_PIN(63, "GPIO_63"),
+ PINCTRL_PIN(64, "GPIO_64"),
+ PINCTRL_PIN(65, "GPIO_65"),
+ PINCTRL_PIN(66, "GPIO_66"),
+ PINCTRL_PIN(67, "GPIO_67"),
+ PINCTRL_PIN(68, "GPIO_68"),
+ PINCTRL_PIN(69, "GPIO_69"),
+ PINCTRL_PIN(70, "GPIO_70"),
+ PINCTRL_PIN(71, "GPIO_71"),
+ PINCTRL_PIN(72, "GPIO_72"),
+ PINCTRL_PIN(73, "GPIO_73"),
+ PINCTRL_PIN(74, "GPIO_74"),
+ PINCTRL_PIN(75, "GPIO_75"),
+ PINCTRL_PIN(76, "GPIO_76"),
+ PINCTRL_PIN(77, "GPIO_77"),
+ PINCTRL_PIN(78, "GPIO_78"),
+ PINCTRL_PIN(79, "GPIO_79"),
+ PINCTRL_PIN(80, "GPIO_80"),
+ PINCTRL_PIN(81, "GPIO_81"),
+ PINCTRL_PIN(82, "GPIO_82"),
+ PINCTRL_PIN(83, "GPIO_83"),
+ PINCTRL_PIN(84, "GPIO_84"),
+ PINCTRL_PIN(85, "GPIO_85"),
+ PINCTRL_PIN(86, "GPIO_86"),
+ PINCTRL_PIN(87, "GPIO_87"),
+ PINCTRL_PIN(88, "GPIO_88"),
+ PINCTRL_PIN(89, "GPIO_89"),
+ PINCTRL_PIN(90, "GPIO_90"),
+ PINCTRL_PIN(91, "GPIO_91"),
+ PINCTRL_PIN(92, "GPIO_92"),
+ PINCTRL_PIN(93, "GPIO_93"),
+ PINCTRL_PIN(94, "GPIO_94"),
+ PINCTRL_PIN(95, "GPIO_95"),
+ PINCTRL_PIN(96, "GPIO_96"),
+ PINCTRL_PIN(97, "GPIO_97"),
+ PINCTRL_PIN(98, "GPIO_98"),
+ PINCTRL_PIN(99, "GPIO_99"),
+ PINCTRL_PIN(100, "GPIO_100"),
+ PINCTRL_PIN(101, "GPIO_101"),
+ PINCTRL_PIN(102, "GPIO_102"),
+ PINCTRL_PIN(103, "GPIO_103"),
+ PINCTRL_PIN(104, "GPIO_104"),
+ PINCTRL_PIN(105, "GPIO_105"),
+ PINCTRL_PIN(106, "GPIO_106"),
+ PINCTRL_PIN(107, "GPIO_107"),
+ PINCTRL_PIN(108, "GPIO_108"),
+ PINCTRL_PIN(109, "GPIO_109"),
+ PINCTRL_PIN(110, "GPIO_110"),
+ PINCTRL_PIN(111, "GPIO_111"),
+ PINCTRL_PIN(112, "GPIO_112"),
+ PINCTRL_PIN(113, "GPIO_113"),
+ PINCTRL_PIN(114, "GPIO_114"),
+ PINCTRL_PIN(115, "GPIO_115"),
+ PINCTRL_PIN(116, "GPIO_116"),
+ PINCTRL_PIN(117, "GPIO_117"),
+ PINCTRL_PIN(118, "GPIO_118"),
+ PINCTRL_PIN(119, "GPIO_119"),
+ PINCTRL_PIN(120, "GPIO_120"),
+ PINCTRL_PIN(121, "GPIO_121"),
+ PINCTRL_PIN(122, "GPIO_122"),
+ PINCTRL_PIN(123, "GPIO_123"),
+ PINCTRL_PIN(124, "GPIO_124"),
+ PINCTRL_PIN(125, "GPIO_125"),
+ PINCTRL_PIN(126, "GPIO_126"),
+ PINCTRL_PIN(127, "GPIO_127"),
+ PINCTRL_PIN(128, "GPIO_128"),
+ PINCTRL_PIN(129, "GPIO_129"),
+ PINCTRL_PIN(130, "GPIO_130"),
+ PINCTRL_PIN(131, "GPIO_131"),
+ PINCTRL_PIN(132, "GPIO_132"),
+ PINCTRL_PIN(133, "GPIO_133"),
+ PINCTRL_PIN(134, "GPIO_134"),
+ PINCTRL_PIN(135, "GPIO_135"),
+ PINCTRL_PIN(136, "GPIO_136"),
+ PINCTRL_PIN(137, "GPIO_137"),
+ PINCTRL_PIN(138, "GPIO_138"),
+ PINCTRL_PIN(139, "GPIO_139"),
+ PINCTRL_PIN(140, "GPIO_140"),
+ PINCTRL_PIN(141, "GPIO_141"),
+ PINCTRL_PIN(142, "GPIO_142"),
+ PINCTRL_PIN(143, "GPIO_143"),
+ PINCTRL_PIN(144, "GPIO_144"),
+ PINCTRL_PIN(145, "GPIO_145"),
+ PINCTRL_PIN(146, "GPIO_146"),
+ PINCTRL_PIN(147, "GPIO_147"),
+ PINCTRL_PIN(148, "GPIO_148"),
+ PINCTRL_PIN(149, "GPIO_149"),
+ PINCTRL_PIN(150, "GPIO_150"),
+ PINCTRL_PIN(151, "GPIO_151"),
+ PINCTRL_PIN(152, "GPIO_152"),
+ PINCTRL_PIN(153, "GPIO_153"),
+ PINCTRL_PIN(154, "GPIO_154"),
+ PINCTRL_PIN(155, "GPIO_155"),
+ PINCTRL_PIN(156, "GPIO_156"),
+ PINCTRL_PIN(157, "GPIO_157"),
+ PINCTRL_PIN(158, "GPIO_158"),
+ PINCTRL_PIN(159, "GPIO_159"),
+ PINCTRL_PIN(160, "GPIO_160"),
+ PINCTRL_PIN(161, "GPIO_161"),
+ PINCTRL_PIN(162, "GPIO_162"),
+ PINCTRL_PIN(163, "GPIO_163"),
+ PINCTRL_PIN(164, "GPIO_164"),
+ PINCTRL_PIN(165, "GPIO_165"),
+ PINCTRL_PIN(166, "GPIO_166"),
+ PINCTRL_PIN(167, "GPIO_167"),
+ PINCTRL_PIN(168, "GPIO_168"),
+ PINCTRL_PIN(169, "GPIO_169"),
+ PINCTRL_PIN(170, "GPIO_170"),
+ PINCTRL_PIN(171, "GPIO_171"),
+ PINCTRL_PIN(172, "GPIO_172"),
+ PINCTRL_PIN(173, "GPIO_173"),
+ PINCTRL_PIN(174, "GPIO_174"),
+ PINCTRL_PIN(175, "UFS_RESET"),
+ PINCTRL_PIN(176, "SDC2_CLK"),
+ PINCTRL_PIN(177, "SDC2_CMD"),
+ PINCTRL_PIN(178, "SDC2_DATA"),
+};
+
+#define DECLARE_MSM_GPIO_PINS(pin) \
+ static const unsigned int gpio##pin##_pins[] = { pin }
+DECLARE_MSM_GPIO_PINS(0);
+DECLARE_MSM_GPIO_PINS(1);
+DECLARE_MSM_GPIO_PINS(2);
+DECLARE_MSM_GPIO_PINS(3);
+DECLARE_MSM_GPIO_PINS(4);
+DECLARE_MSM_GPIO_PINS(5);
+DECLARE_MSM_GPIO_PINS(6);
+DECLARE_MSM_GPIO_PINS(7);
+DECLARE_MSM_GPIO_PINS(8);
+DECLARE_MSM_GPIO_PINS(9);
+DECLARE_MSM_GPIO_PINS(10);
+DECLARE_MSM_GPIO_PINS(11);
+DECLARE_MSM_GPIO_PINS(12);
+DECLARE_MSM_GPIO_PINS(13);
+DECLARE_MSM_GPIO_PINS(14);
+DECLARE_MSM_GPIO_PINS(15);
+DECLARE_MSM_GPIO_PINS(16);
+DECLARE_MSM_GPIO_PINS(17);
+DECLARE_MSM_GPIO_PINS(18);
+DECLARE_MSM_GPIO_PINS(19);
+DECLARE_MSM_GPIO_PINS(20);
+DECLARE_MSM_GPIO_PINS(21);
+DECLARE_MSM_GPIO_PINS(22);
+DECLARE_MSM_GPIO_PINS(23);
+DECLARE_MSM_GPIO_PINS(24);
+DECLARE_MSM_GPIO_PINS(25);
+DECLARE_MSM_GPIO_PINS(26);
+DECLARE_MSM_GPIO_PINS(27);
+DECLARE_MSM_GPIO_PINS(28);
+DECLARE_MSM_GPIO_PINS(29);
+DECLARE_MSM_GPIO_PINS(30);
+DECLARE_MSM_GPIO_PINS(31);
+DECLARE_MSM_GPIO_PINS(32);
+DECLARE_MSM_GPIO_PINS(33);
+DECLARE_MSM_GPIO_PINS(34);
+DECLARE_MSM_GPIO_PINS(35);
+DECLARE_MSM_GPIO_PINS(36);
+DECLARE_MSM_GPIO_PINS(37);
+DECLARE_MSM_GPIO_PINS(38);
+DECLARE_MSM_GPIO_PINS(39);
+DECLARE_MSM_GPIO_PINS(40);
+DECLARE_MSM_GPIO_PINS(41);
+DECLARE_MSM_GPIO_PINS(42);
+DECLARE_MSM_GPIO_PINS(43);
+DECLARE_MSM_GPIO_PINS(44);
+DECLARE_MSM_GPIO_PINS(45);
+DECLARE_MSM_GPIO_PINS(46);
+DECLARE_MSM_GPIO_PINS(47);
+DECLARE_MSM_GPIO_PINS(48);
+DECLARE_MSM_GPIO_PINS(49);
+DECLARE_MSM_GPIO_PINS(50);
+DECLARE_MSM_GPIO_PINS(51);
+DECLARE_MSM_GPIO_PINS(52);
+DECLARE_MSM_GPIO_PINS(53);
+DECLARE_MSM_GPIO_PINS(54);
+DECLARE_MSM_GPIO_PINS(55);
+DECLARE_MSM_GPIO_PINS(56);
+DECLARE_MSM_GPIO_PINS(57);
+DECLARE_MSM_GPIO_PINS(58);
+DECLARE_MSM_GPIO_PINS(59);
+DECLARE_MSM_GPIO_PINS(60);
+DECLARE_MSM_GPIO_PINS(61);
+DECLARE_MSM_GPIO_PINS(62);
+DECLARE_MSM_GPIO_PINS(63);
+DECLARE_MSM_GPIO_PINS(64);
+DECLARE_MSM_GPIO_PINS(65);
+DECLARE_MSM_GPIO_PINS(66);
+DECLARE_MSM_GPIO_PINS(67);
+DECLARE_MSM_GPIO_PINS(68);
+DECLARE_MSM_GPIO_PINS(69);
+DECLARE_MSM_GPIO_PINS(70);
+DECLARE_MSM_GPIO_PINS(71);
+DECLARE_MSM_GPIO_PINS(72);
+DECLARE_MSM_GPIO_PINS(73);
+DECLARE_MSM_GPIO_PINS(74);
+DECLARE_MSM_GPIO_PINS(75);
+DECLARE_MSM_GPIO_PINS(76);
+DECLARE_MSM_GPIO_PINS(77);
+DECLARE_MSM_GPIO_PINS(78);
+DECLARE_MSM_GPIO_PINS(79);
+DECLARE_MSM_GPIO_PINS(80);
+DECLARE_MSM_GPIO_PINS(81);
+DECLARE_MSM_GPIO_PINS(82);
+DECLARE_MSM_GPIO_PINS(83);
+DECLARE_MSM_GPIO_PINS(84);
+DECLARE_MSM_GPIO_PINS(85);
+DECLARE_MSM_GPIO_PINS(86);
+DECLARE_MSM_GPIO_PINS(87);
+DECLARE_MSM_GPIO_PINS(88);
+DECLARE_MSM_GPIO_PINS(89);
+DECLARE_MSM_GPIO_PINS(90);
+DECLARE_MSM_GPIO_PINS(91);
+DECLARE_MSM_GPIO_PINS(92);
+DECLARE_MSM_GPIO_PINS(93);
+DECLARE_MSM_GPIO_PINS(94);
+DECLARE_MSM_GPIO_PINS(95);
+DECLARE_MSM_GPIO_PINS(96);
+DECLARE_MSM_GPIO_PINS(97);
+DECLARE_MSM_GPIO_PINS(98);
+DECLARE_MSM_GPIO_PINS(99);
+DECLARE_MSM_GPIO_PINS(100);
+DECLARE_MSM_GPIO_PINS(101);
+DECLARE_MSM_GPIO_PINS(102);
+DECLARE_MSM_GPIO_PINS(103);
+DECLARE_MSM_GPIO_PINS(104);
+DECLARE_MSM_GPIO_PINS(105);
+DECLARE_MSM_GPIO_PINS(106);
+DECLARE_MSM_GPIO_PINS(107);
+DECLARE_MSM_GPIO_PINS(108);
+DECLARE_MSM_GPIO_PINS(109);
+DECLARE_MSM_GPIO_PINS(110);
+DECLARE_MSM_GPIO_PINS(111);
+DECLARE_MSM_GPIO_PINS(112);
+DECLARE_MSM_GPIO_PINS(113);
+DECLARE_MSM_GPIO_PINS(114);
+DECLARE_MSM_GPIO_PINS(115);
+DECLARE_MSM_GPIO_PINS(116);
+DECLARE_MSM_GPIO_PINS(117);
+DECLARE_MSM_GPIO_PINS(118);
+DECLARE_MSM_GPIO_PINS(119);
+DECLARE_MSM_GPIO_PINS(120);
+DECLARE_MSM_GPIO_PINS(121);
+DECLARE_MSM_GPIO_PINS(122);
+DECLARE_MSM_GPIO_PINS(123);
+DECLARE_MSM_GPIO_PINS(124);
+DECLARE_MSM_GPIO_PINS(125);
+DECLARE_MSM_GPIO_PINS(126);
+DECLARE_MSM_GPIO_PINS(127);
+DECLARE_MSM_GPIO_PINS(128);
+DECLARE_MSM_GPIO_PINS(129);
+DECLARE_MSM_GPIO_PINS(130);
+DECLARE_MSM_GPIO_PINS(131);
+DECLARE_MSM_GPIO_PINS(132);
+DECLARE_MSM_GPIO_PINS(133);
+DECLARE_MSM_GPIO_PINS(134);
+DECLARE_MSM_GPIO_PINS(135);
+DECLARE_MSM_GPIO_PINS(136);
+DECLARE_MSM_GPIO_PINS(137);
+DECLARE_MSM_GPIO_PINS(138);
+DECLARE_MSM_GPIO_PINS(139);
+DECLARE_MSM_GPIO_PINS(140);
+DECLARE_MSM_GPIO_PINS(141);
+DECLARE_MSM_GPIO_PINS(142);
+DECLARE_MSM_GPIO_PINS(143);
+DECLARE_MSM_GPIO_PINS(144);
+DECLARE_MSM_GPIO_PINS(145);
+DECLARE_MSM_GPIO_PINS(146);
+DECLARE_MSM_GPIO_PINS(147);
+DECLARE_MSM_GPIO_PINS(148);
+DECLARE_MSM_GPIO_PINS(149);
+DECLARE_MSM_GPIO_PINS(150);
+DECLARE_MSM_GPIO_PINS(151);
+DECLARE_MSM_GPIO_PINS(152);
+DECLARE_MSM_GPIO_PINS(153);
+DECLARE_MSM_GPIO_PINS(154);
+DECLARE_MSM_GPIO_PINS(155);
+DECLARE_MSM_GPIO_PINS(156);
+DECLARE_MSM_GPIO_PINS(157);
+DECLARE_MSM_GPIO_PINS(158);
+DECLARE_MSM_GPIO_PINS(159);
+DECLARE_MSM_GPIO_PINS(160);
+DECLARE_MSM_GPIO_PINS(161);
+DECLARE_MSM_GPIO_PINS(162);
+DECLARE_MSM_GPIO_PINS(163);
+DECLARE_MSM_GPIO_PINS(164);
+DECLARE_MSM_GPIO_PINS(165);
+DECLARE_MSM_GPIO_PINS(166);
+DECLARE_MSM_GPIO_PINS(167);
+DECLARE_MSM_GPIO_PINS(168);
+DECLARE_MSM_GPIO_PINS(169);
+DECLARE_MSM_GPIO_PINS(170);
+DECLARE_MSM_GPIO_PINS(171);
+DECLARE_MSM_GPIO_PINS(172);
+DECLARE_MSM_GPIO_PINS(173);
+DECLARE_MSM_GPIO_PINS(174);
+
+static const unsigned int ufs_reset_pins[] = { 175 };
+static const unsigned int sdc2_clk_pins[] = { 176 };
+static const unsigned int sdc2_cmd_pins[] = { 177 };
+static const unsigned int sdc2_data_pins[] = { 178 };
+
+enum sm8150_functions {
+ msm_mux_adsp_ext,
+ msm_mux_agera_pll,
+ msm_mux_aoss_cti,
+ msm_mux_atest_char,
+ msm_mux_atest_char0,
+ msm_mux_atest_char1,
+ msm_mux_atest_char2,
+ msm_mux_atest_char3,
+ msm_mux_atest_usb1,
+ msm_mux_atest_usb2,
+ msm_mux_atest_usb10,
+ msm_mux_atest_usb11,
+ msm_mux_atest_usb12,
+ msm_mux_atest_usb13,
+ msm_mux_atest_usb20,
+ msm_mux_atest_usb21,
+ msm_mux_atest_usb22,
+ msm_mux_atest_usb23,
+ msm_mux_audio_ref,
+ msm_mux_btfm_slimbus,
+ msm_mux_cam_mclk,
+ msm_mux_cci_async,
+ msm_mux_cci_i2c,
+ msm_mux_cci_timer0,
+ msm_mux_cci_timer1,
+ msm_mux_cci_timer2,
+ msm_mux_cci_timer3,
+ msm_mux_cci_timer4,
+ msm_mux_cri_trng,
+ msm_mux_cri_trng0,
+ msm_mux_cri_trng1,
+ msm_mux_dbg_out,
+ msm_mux_ddr_bist,
+ msm_mux_ddr_pxi0,
+ msm_mux_ddr_pxi1,
+ msm_mux_ddr_pxi2,
+ msm_mux_ddr_pxi3,
+ msm_mux_edp_hot,
+ msm_mux_edp_lcd,
+ msm_mux_emac_phy,
+ msm_mux_emac_pps,
+ msm_mux_gcc_gp1,
+ msm_mux_gcc_gp2,
+ msm_mux_gcc_gp3,
+ msm_mux_gpio,
+ msm_mux_jitter_bist,
+ msm_mux_hs1_mi2s,
+ msm_mux_hs2_mi2s,
+ msm_mux_hs3_mi2s,
+ msm_mux_lpass_slimbus,
+ msm_mux_mdp_vsync,
+ msm_mux_mdp_vsync0,
+ msm_mux_mdp_vsync1,
+ msm_mux_mdp_vsync2,
+ msm_mux_mdp_vsync3,
+ msm_mux_mss_lte,
+ msm_mux_m_voc,
+ msm_mux_nav_pps,
+ msm_mux_pa_indicator,
+ msm_mux_pci_e0,
+ msm_mux_pci_e1,
+ msm_mux_phase_flag,
+ msm_mux_pll_bist,
+ msm_mux_pll_bypassnl,
+ msm_mux_pll_reset,
+ msm_mux_pri_mi2s,
+ msm_mux_pri_mi2s_ws,
+ msm_mux_prng_rosc,
+ msm_mux_qdss,
+ msm_mux_qdss_cti,
+ msm_mux_qlink_enable,
+ msm_mux_qlink_request,
+ msm_mux_qspi0,
+ msm_mux_qspi1,
+ msm_mux_qspi2,
+ msm_mux_qspi3,
+ msm_mux_qspi_clk,
+ msm_mux_qspi_cs,
+ msm_mux_qua_mi2s,
+ msm_mux_qup0,
+ msm_mux_qup1,
+ msm_mux_qup2,
+ msm_mux_qup3,
+ msm_mux_qup4,
+ msm_mux_qup5,
+ msm_mux_qup6,
+ msm_mux_qup7,
+ msm_mux_qup8,
+ msm_mux_qup9,
+ msm_mux_qup10,
+ msm_mux_qup11,
+ msm_mux_qup12,
+ msm_mux_qup13,
+ msm_mux_qup14,
+ msm_mux_qup15,
+ msm_mux_qup16,
+ msm_mux_qup17,
+ msm_mux_qup18,
+ msm_mux_qup19,
+ msm_mux_qup_l4,
+ msm_mux_qup_l5,
+ msm_mux_qup_l6,
+ msm_mux_rgmii,
+ msm_mux_sdc4,
+ msm_mux_sd_write,
+ msm_mux_sec_mi2s,
+ msm_mux_spkr_i2s,
+ msm_mux_sp_cmu,
+ msm_mux_ter_mi2s,
+ msm_mux_tgu_ch0,
+ msm_mux_tgu_ch2,
+ msm_mux_tgu_ch1,
+ msm_mux_tgu_ch3,
+ msm_mux_tsense_pwm1,
+ msm_mux_tsense_pwm2,
+ msm_mux_tsif1,
+ msm_mux_tsif2,
+ msm_mux_uim1,
+ msm_mux_uim2,
+ msm_mux_uim_batt,
+ msm_mux_usb2phy_ac,
+ msm_mux_usb_phy,
+ msm_mux_vfr_1,
+ msm_mux_vsense_trigger,
+ msm_mux_wlan1_adc1,
+ msm_mux_wlan1_adc0,
+ msm_mux_wlan2_adc1,
+ msm_mux_wlan2_adc0,
+ msm_mux_wmss_reset,
+ msm_mux__,
+};
+
+static const char * const phase_flag_groups[] = {
+ "gpio18", "gpio19", "gpio20", "gpio55", "gpio56",
+ "gpio57", "gpio59", "gpio64", "gpio68", "gpio76",
+ "gpio79", "gpio80", "gpio90", "gpio91", "gpio92",
+ "gpio93", "gpio94", "gpio96", "gpio114", "gpio115",
+ "gpio116", "gpio117", "gpio118", "gpio119", "gpio120",
+ "gpio121", "gpio122", "gpio126", "gpio127", "gpio128",
+ "gpio144", "gpio145",
+};
+
+static const char * const emac_pps_groups[] = {
+ "gpio81",
+};
+
+static const char * const qup12_groups[] = {
+ "gpio83", "gpio84", "gpio85", "gpio86",
+};
+
+static const char * const qup16_groups[] = {
+ "gpio83", "gpio84", "gpio85", "gpio86",
+};
+
+static const char * const tsif1_groups[] = {
+ "gpio88", "gpio89", "gpio90", "gpio91", "gpio97",
+};
+
+static const char * const qup8_groups[] = {
+ "gpio88", "gpio89", "gpio90", "gpio91",
+};
+
+static const char * const qspi_cs_groups[] = {
+ "gpio88", "gpio94",
+};
+
+static const char * const tgu_ch3_groups[] = {
+ "gpio88",
+};
+
+static const char * const qspi0_groups[] = {
+ "gpio89",
+};
+
+static const char * const mdp_vsync0_groups[] = {
+ "gpio89",
+};
+
+static const char * const mdp_vsync1_groups[] = {
+ "gpio89",
+};
+
+static const char * const mdp_vsync2_groups[] = {
+ "gpio89",
+};
+
+static const char * const mdp_vsync3_groups[] = {
+ "gpio89",
+};
+
+static const char * const tgu_ch0_groups[] = {
+ "gpio89",
+};
+
+static const char * const qspi1_groups[] = {
+ "gpio90",
+};
+
+static const char * const sdc4_groups[] = {
+ "gpio90", "gpio91", "gpio92", "gpio93", "gpio94", "gpio95",
+};
+
+static const char * const tgu_ch1_groups[] = {
+ "gpio90",
+};
+
+static const char * const wlan1_adc1_groups[] = {
+ "gpio90",
+};
+
+static const char * const qspi2_groups[] = {
+ "gpio91",
+};
+
+static const char * const vfr_1_groups[] = {
+ "gpio91",
+};
+
+static const char * const tgu_ch2_groups[] = {
+ "gpio91",
+};
+
+static const char * const wlan1_adc0_groups[] = {
+ "gpio91",
+};
+
+static const char * const tsif2_groups[] = {
+ "gpio92", "gpio93", "gpio94", "gpio95", "gpio96",
+};
+
+static const char * const qup11_groups[] = {
+ "gpio92", "gpio93", "gpio94", "gpio95",
+};
+
+static const char * const qspi_clk_groups[] = {
+ "gpio92",
+};
+
+static const char * const wlan2_adc1_groups[] = {
+ "gpio92",
+};
+
+static const char * const qspi3_groups[] = {
+ "gpio93",
+};
+
+static const char * const wlan2_adc0_groups[] = {
+ "gpio93",
+};
+
+static const char * const sd_write_groups[] = {
+ "gpio97",
+};
+
+static const char * const qup7_groups[] = {
+ "gpio98", "gpio99", "gpio100", "gpio101",
+};
+
+static const char * const ddr_bist_groups[] = {
+ "gpio98", "gpio99", "gpio145", "gpio146",
+};
+
+static const char * const ddr_pxi3_groups[] = {
+ "gpio98", "gpio101",
+};
+
+static const char * const atest_usb13_groups[] = {
+ "gpio99",
+};
+
+static const char * const ddr_pxi1_groups[] = {
+ "gpio99", "gpio100",
+};
+
+static const char * const pll_bypassnl_groups[] = {
+ "gpio100",
+};
+
+static const char * const atest_usb12_groups[] = {
+ "gpio100",
+};
+
+static const char * const pll_reset_groups[] = {
+ "gpio101",
+};
+
+static const char * const pci_e1_groups[] = {
+ "gpio102", "gpio103",
+};
+
+static const char * const uim2_groups[] = {
+ "gpio105", "gpio106", "gpio107", "gpio108",
+};
+
+static const char * const uim1_groups[] = {
+ "gpio109", "gpio110", "gpio111", "gpio112",
+};
+
+static const char * const uim_batt_groups[] = {
+ "gpio113",
+};
+
+static const char * const usb2phy_ac_groups[] = {
+ "gpio113", "gpio123",
+};
+
+static const char * const aoss_cti_groups[] = {
+ "gpio113",
+};
+
+static const char * const qup1_groups[] = {
+ "gpio114", "gpio115", "gpio116", "gpio117",
+};
+
+static const char * const rgmii_groups[] = {
+ "gpio4", "gpio5", "gpio6", "gpio7", "gpio59",
+ "gpio114", "gpio115", "gpio116", "gpio117",
+ "gpio118", "gpio119", "gpio120", "gpio121", "gpio122",
+};
+
+static const char * const adsp_ext_groups[] = {
+ "gpio115",
+};
+
+static const char * const qup5_groups[] = {
+ "gpio119", "gpio120", "gpio121", "gpio122",
+};
+
+static const char * const atest_usb22_groups[] = {
+ "gpio123",
+};
+
+static const char * const emac_phy_groups[] = {
+ "gpio124",
+};
+
+static const char * const hs3_mi2s_groups[] = {
+ "gpio125", "gpio165", "gpio166", "gpio167", "gpio168",
+};
+
+static const char * const sec_mi2s_groups[] = {
+ "gpio126", "gpio127", "gpio128", "gpio129", "gpio130",
+};
+
+static const char * const qup2_groups[] = {
+ "gpio126", "gpio127", "gpio128", "gpio129",
+};
+
+static const char * const jitter_bist_groups[] = {
+ "gpio129",
+};
+
+static const char * const atest_usb21_groups[] = {
+ "gpio129",
+};
+
+static const char * const pll_bist_groups[] = {
+ "gpio130",
+};
+
+static const char * const atest_usb20_groups[] = {
+ "gpio130",
+};
+
+static const char * const atest_char0_groups[] = {
+ "gpio130",
+};
+
+static const char * const ter_mi2s_groups[] = {
+ "gpio131", "gpio132", "gpio133", "gpio134", "gpio135",
+};
+
+static const char * const gcc_gp1_groups[] = {
+ "gpio131", "gpio136",
+};
+
+static const char * const atest_char1_groups[] = {
+ "gpio133",
+};
+
+static const char * const atest_char2_groups[] = {
+ "gpio134",
+};
+
+static const char * const atest_char3_groups[] = {
+ "gpio135",
+};
+
+static const char * const qua_mi2s_groups[] = {
+ "gpio136", "gpio137", "gpio138", "gpio139", "gpio140", "gpio141",
+ "gpio142",
+};
+
+static const char * const pri_mi2s_groups[] = {
+ "gpio143", "gpio144", "gpio146", "gpio147",
+};
+
+static const char * const qup3_groups[] = {
+ "gpio144", "gpio145", "gpio146", "gpio147",
+};
+
+static const char * const ddr_pxi0_groups[] = {
+ "gpio144", "gpio145",
+};
+
+static const char * const pri_mi2s_ws_groups[] = {
+ "gpio145",
+};
+
+static const char * const vsense_trigger_groups[] = {
+ "gpio145",
+};
+
+static const char * const atest_usb1_groups[] = {
+ "gpio145",
+};
+
+static const char * const atest_usb11_groups[] = {
+ "gpio146",
+};
+
+static const char * const ddr_pxi2_groups[] = {
+ "gpio146", "gpio147",
+};
+
+static const char * const dbg_out_groups[] = {
+ "gpio147",
+};
+
+static const char * const atest_usb10_groups[] = {
+ "gpio147",
+};
+
+static const char * const spkr_i2s_groups[] = {
+ "gpio148", "gpio149", "gpio150", "gpio151", "gpio152",
+};
+
+static const char * const audio_ref_groups[] = {
+ "gpio148",
+};
+
+static const char * const lpass_slimbus_groups[] = {
+ "gpio149", "gpio150", "gpio151", "gpio152",
+};
+
+static const char * const tsense_pwm1_groups[] = {
+ "gpio150",
+};
+
+static const char * const tsense_pwm2_groups[] = {
+ "gpio150",
+};
+
+static const char * const btfm_slimbus_groups[] = {
+ "gpio153", "gpio154",
+};
+
+static const char * const hs1_mi2s_groups[] = {
+ "gpio155", "gpio156", "gpio157", "gpio158", "gpio159",
+};
+
+static const char * const cri_trng0_groups[] = {
+ "gpio159",
+};
+
+static const char * const hs2_mi2s_groups[] = {
+ "gpio160", "gpio161", "gpio162", "gpio163", "gpio164",
+};
+
+static const char * const cri_trng1_groups[] = {
+ "gpio160",
+};
+
+static const char * const cri_trng_groups[] = {
+ "gpio161",
+};
+
+static const char * const sp_cmu_groups[] = {
+ "gpio162",
+};
+
+static const char * const prng_rosc_groups[] = {
+ "gpio163",
+};
+
+static const char * const qup0_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3",
+};
+
+static const char * const gpio_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+ "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+ "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
+ "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28",
+ "gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35",
+ "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42",
+ "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49",
+ "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56",
+ "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
+ "gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70",
+ "gpio71", "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77",
+ "gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84",
+ "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", "gpio91",
+ "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98",
+ "gpio99", "gpio100", "gpio101", "gpio102", "gpio103", "gpio104",
+ "gpio105", "gpio106", "gpio107", "gpio108", "gpio109", "gpio110",
+ "gpio111", "gpio112", "gpio113", "gpio114", "gpio115", "gpio116",
+ "gpio117", "gpio118", "gpio119", "gpio120", "gpio121", "gpio122",
+ "gpio123", "gpio124", "gpio125", "gpio126", "gpio127", "gpio128",
+ "gpio129", "gpio130", "gpio131", "gpio132", "gpio133", "gpio134",
+ "gpio135", "gpio136", "gpio137", "gpio138", "gpio139", "gpio140",
+ "gpio141", "gpio142", "gpio143", "gpio144", "gpio145", "gpio146",
+ "gpio147", "gpio148", "gpio149", "gpio150", "gpio151", "gpio152",
+ "gpio153", "gpio154", "gpio155", "gpio156", "gpio157", "gpio158",
+ "gpio159", "gpio160", "gpio161", "gpio162", "gpio163", "gpio164",
+ "gpio165", "gpio166", "gpio167", "gpio168", "gpio169", "gpio170",
+ "gpio171", "gpio172", "gpio173", "gpio174",
+};
+
+static const char * const qup6_groups[] = {
+ "gpio4", "gpio5", "gpio6", "gpio7",
+};
+
+static const char * const qup_l6_groups[] = {
+ "gpio6", "gpio34", "gpio97", "gpio123",
+};
+
+static const char * const qup_l5_groups[] = {
+ "gpio7", "gpio33", "gpio82", "gpio96",
+};
+
+static const char * const mdp_vsync_groups[] = {
+ "gpio8", "gpio9", "gpio10", "gpio81", "gpio82",
+};
+
+static const char * const edp_lcd_groups[] = {
+ "gpio9",
+};
+
+static const char * const qup10_groups[] = {
+ "gpio9", "gpio10", "gpio11", "gpio12",
+};
+
+static const char * const m_voc_groups[] = {
+ "gpio10",
+};
+
+static const char * const edp_hot_groups[] = {
+ "gpio10",
+};
+
+static const char * const cam_mclk_groups[] = {
+ "gpio13", "gpio14", "gpio15", "gpio16",
+};
+
+static const char * const qdss_groups[] = {
+ "gpio13", "gpio14", "gpio15", "gpio16", "gpio17",
+ "gpio18", "gpio19", "gpio20", "gpio21", "gpio22",
+ "gpio23", "gpio24", "gpio25", "gpio26", "gpio27",
+ "gpio28", "gpio29", "gpio30", "gpio31", "gpio32",
+ "gpio33", "gpio39", "gpio40", "gpio41", "gpio42",
+ "gpio47", "gpio48", "gpio83", "gpio117", "gpio118",
+ "gpio119", "gpio120", "gpio121", "gpio132",
+ "gpio133", "gpio134",
+};
+
+static const char * const cci_i2c_groups[] = {
+ "gpio17", "gpio18", "gpio19", "gpio20", "gpio31", "gpio32", "gpio33",
+ "gpio34",
+};
+
+static const char * const cci_timer0_groups[] = {
+ "gpio21",
+};
+
+static const char * const gcc_gp2_groups[] = {
+ "gpio21", "gpio137",
+};
+
+static const char * const cci_timer1_groups[] = {
+ "gpio22",
+};
+
+static const char * const gcc_gp3_groups[] = {
+ "gpio22", "gpio138",
+};
+
+static const char * const cci_timer2_groups[] = {
+ "gpio23",
+};
+
+static const char * const qup18_groups[] = {
+ "gpio23", "gpio24", "gpio25", "gpio26",
+};
+
+static const char * const cci_timer3_groups[] = {
+ "gpio24",
+};
+
+static const char * const cci_async_groups[] = {
+ "gpio24", "gpio25", "gpio26",
+};
+
+static const char * const cci_timer4_groups[] = {
+ "gpio25",
+};
+
+static const char * const qup15_groups[] = {
+ "gpio27", "gpio28", "gpio29", "gpio30",
+};
+
+static const char * const pci_e0_groups[] = {
+ "gpio35", "gpio36",
+};
+
+static const char * const qup_l4_groups[] = {
+ "gpio37", "gpio59", "gpio81", "gpio95",
+};
+
+static const char * const agera_pll_groups[] = {
+ "gpio37",
+};
+
+static const char * const usb_phy_groups[] = {
+ "gpio38",
+};
+
+static const char * const qup9_groups[] = {
+ "gpio39", "gpio40", "gpio41", "gpio42",
+};
+
+static const char * const qup13_groups[] = {
+ "gpio43", "gpio44", "gpio45", "gpio46",
+};
+
+static const char * const qdss_cti_groups[] = {
+ "gpio45", "gpio46", "gpio49", "gpio50", "gpio56", "gpio57", "gpio58",
+ "gpio58",
+};
+
+static const char * const qup14_groups[] = {
+ "gpio47", "gpio48", "gpio49", "gpio50",
+};
+
+static const char * const qup4_groups[] = {
+ "gpio51", "gpio52", "gpio53", "gpio54",
+};
+
+static const char * const qup17_groups[] = {
+ "gpio55", "gpio56", "gpio57", "gpio58",
+};
+
+static const char * const qup19_groups[] = {
+ "gpio55", "gpio56", "gpio57", "gpio58",
+};
+
+static const char * const atest_char_groups[] = {
+ "gpio59",
+};
+
+static const char * const nav_pps_groups[] = {
+ "gpio60", "gpio60", "gpio76", "gpio76", "gpio77", "gpio77", "gpio81",
+ "gpio81", "gpio82", "gpio82",
+};
+
+static const char * const atest_usb2_groups[] = {
+ "gpio60",
+};
+
+static const char * const qlink_request_groups[] = {
+ "gpio61",
+};
+
+static const char * const qlink_enable_groups[] = {
+ "gpio62",
+};
+
+static const char * const wmss_reset_groups[] = {
+ "gpio63",
+};
+
+static const char * const atest_usb23_groups[] = {
+ "gpio63",
+};
+
+static const char * const pa_indicator_groups[] = {
+ "gpio68",
+};
+
+static const char * const mss_lte_groups[] = {
+ "gpio69", "gpio70",
+};
+
+static const struct msm_function sm8150_functions[] = {
+ FUNCTION(adsp_ext),
+ FUNCTION(agera_pll),
+ FUNCTION(aoss_cti),
+ FUNCTION(ddr_pxi2),
+ FUNCTION(atest_char),
+ FUNCTION(atest_char0),
+ FUNCTION(atest_char1),
+ FUNCTION(atest_char2),
+ FUNCTION(atest_char3),
+ FUNCTION(audio_ref),
+ FUNCTION(atest_usb1),
+ FUNCTION(atest_usb2),
+ FUNCTION(atest_usb10),
+ FUNCTION(atest_usb11),
+ FUNCTION(atest_usb12),
+ FUNCTION(atest_usb13),
+ FUNCTION(atest_usb20),
+ FUNCTION(atest_usb21),
+ FUNCTION(atest_usb22),
+ FUNCTION(atest_usb23),
+ FUNCTION(btfm_slimbus),
+ FUNCTION(cam_mclk),
+ FUNCTION(cci_async),
+ FUNCTION(cci_i2c),
+ FUNCTION(cci_timer0),
+ FUNCTION(cci_timer1),
+ FUNCTION(cci_timer2),
+ FUNCTION(cci_timer3),
+ FUNCTION(cci_timer4),
+ FUNCTION(cri_trng),
+ FUNCTION(cri_trng0),
+ FUNCTION(cri_trng1),
+ FUNCTION(dbg_out),
+ FUNCTION(ddr_bist),
+ FUNCTION(ddr_pxi0),
+ FUNCTION(ddr_pxi1),
+ FUNCTION(ddr_pxi3),
+ FUNCTION(edp_hot),
+ FUNCTION(edp_lcd),
+ FUNCTION(emac_phy),
+ FUNCTION(emac_pps),
+ FUNCTION(gcc_gp1),
+ FUNCTION(gcc_gp2),
+ FUNCTION(gcc_gp3),
+ FUNCTION(gpio),
+ FUNCTION(hs1_mi2s),
+ FUNCTION(hs2_mi2s),
+ FUNCTION(hs3_mi2s),
+ FUNCTION(jitter_bist),
+ FUNCTION(lpass_slimbus),
+ FUNCTION(mdp_vsync),
+ FUNCTION(mdp_vsync0),
+ FUNCTION(mdp_vsync1),
+ FUNCTION(mdp_vsync2),
+ FUNCTION(mdp_vsync3),
+ FUNCTION(mss_lte),
+ FUNCTION(m_voc),
+ FUNCTION(nav_pps),
+ FUNCTION(pa_indicator),
+ FUNCTION(pci_e0),
+ FUNCTION(phase_flag),
+ FUNCTION(pll_bypassnl),
+ FUNCTION(pll_bist),
+ FUNCTION(pci_e1),
+ FUNCTION(pll_reset),
+ FUNCTION(pri_mi2s),
+ FUNCTION(pri_mi2s_ws),
+ FUNCTION(prng_rosc),
+ FUNCTION(qdss),
+ FUNCTION(qdss_cti),
+ FUNCTION(qlink_request),
+ FUNCTION(qlink_enable),
+ FUNCTION(qspi0),
+ FUNCTION(qspi1),
+ FUNCTION(qspi2),
+ FUNCTION(qspi3),
+ FUNCTION(qspi_clk),
+ FUNCTION(qspi_cs),
+ FUNCTION(qua_mi2s),
+ FUNCTION(qup0),
+ FUNCTION(qup1),
+ FUNCTION(qup2),
+ FUNCTION(qup3),
+ FUNCTION(qup4),
+ FUNCTION(qup5),
+ FUNCTION(qup6),
+ FUNCTION(qup7),
+ FUNCTION(qup8),
+ FUNCTION(qup9),
+ FUNCTION(qup10),
+ FUNCTION(qup11),
+ FUNCTION(qup12),
+ FUNCTION(qup13),
+ FUNCTION(qup14),
+ FUNCTION(qup15),
+ FUNCTION(qup16),
+ FUNCTION(qup17),
+ FUNCTION(qup18),
+ FUNCTION(qup19),
+ FUNCTION(qup_l4),
+ FUNCTION(qup_l5),
+ FUNCTION(qup_l6),
+ FUNCTION(rgmii),
+ FUNCTION(sdc4),
+ FUNCTION(sd_write),
+ FUNCTION(sec_mi2s),
+ FUNCTION(spkr_i2s),
+ FUNCTION(sp_cmu),
+ FUNCTION(ter_mi2s),
+ FUNCTION(tgu_ch0),
+ FUNCTION(tgu_ch1),
+ FUNCTION(tgu_ch2),
+ FUNCTION(tgu_ch3),
+ FUNCTION(tsense_pwm1),
+ FUNCTION(tsense_pwm2),
+ FUNCTION(tsif1),
+ FUNCTION(tsif2),
+ FUNCTION(uim1),
+ FUNCTION(uim2),
+ FUNCTION(uim_batt),
+ FUNCTION(usb2phy_ac),
+ FUNCTION(usb_phy),
+ FUNCTION(vfr_1),
+ FUNCTION(vsense_trigger),
+ FUNCTION(wlan1_adc0),
+ FUNCTION(wlan1_adc1),
+ FUNCTION(wlan2_adc0),
+ FUNCTION(wlan2_adc1),
+ FUNCTION(wmss_reset),
+};
+
+/*
+ * Every pin is maintained as a single group, and missing or non-existing pin
+ * would be maintained as dummy group to synchronize pin group index with
+ * pin descriptor registered with pinctrl core.
+ * Clients would not be able to request these dummy pin groups.
+ */
+static const struct msm_pingroup sm8150_groups[] = {
+ [0] = PINGROUP(0, SOUTH, qup0, _, _, _, _, _, _, _, _),
+ [1] = PINGROUP(1, SOUTH, qup0, _, _, _, _, _, _, _, _),
+ [2] = PINGROUP(2, SOUTH, qup0, _, _, _, _, _, _, _, _),
+ [3] = PINGROUP(3, SOUTH, qup0, _, _, _, _, _, _, _, _),
+ [4] = PINGROUP(4, SOUTH, qup6, rgmii, _, _, _, _, _, _, _),
+ [5] = PINGROUP(5, SOUTH, qup6, rgmii, _, _, _, _, _, _, _),
+ [6] = PINGROUP(6, SOUTH, qup6, rgmii, qup_l6, _, _, _, _, _, _),
+ [7] = PINGROUP(7, SOUTH, qup6, rgmii, qup_l5, _, _, _, _, _, _),
+ [8] = PINGROUP(8, NORTH, mdp_vsync, _, _, _, _, _, _, _, _),
+ [9] = PINGROUP(9, NORTH, mdp_vsync, edp_lcd, qup10, _, _, _, _, _, _),
+ [10] = PINGROUP(10, NORTH, mdp_vsync, m_voc, edp_hot, qup10, _, _, _, _, _),
+ [11] = PINGROUP(11, NORTH, qup10, _, _, _, _, _, _, _, _),
+ [12] = PINGROUP(12, NORTH, qup10, _, _, _, _, _, _, _, _),
+ [13] = PINGROUP(13, NORTH, cam_mclk, qdss, _, _, _, _, _, _, _),
+ [14] = PINGROUP(14, NORTH, cam_mclk, qdss, _, _, _, _, _, _, _),
+ [15] = PINGROUP(15, NORTH, cam_mclk, qdss, _, _, _, _, _, _, _),
+ [16] = PINGROUP(16, NORTH, cam_mclk, qdss, _, _, _, _, _, _, _),
+ [17] = PINGROUP(17, NORTH, cci_i2c, qdss, _, _, _, _, _, _, _),
+ [18] = PINGROUP(18, NORTH, cci_i2c, phase_flag, _, qdss, _, _, _, _, _),
+ [19] = PINGROUP(19, NORTH, cci_i2c, phase_flag, _, qdss, _, _, _, _, _),
+ [20] = PINGROUP(20, NORTH, cci_i2c, phase_flag, _, qdss, _, _, _, _, _),
+ [21] = PINGROUP(21, EAST, cci_timer0, gcc_gp2, qdss, _, _, _, _, _, _),
+ [22] = PINGROUP(22, EAST, cci_timer1, gcc_gp3, qdss, _, _, _, _, _, _),
+ [23] = PINGROUP(23, EAST, cci_timer2, qup18, qdss, _, _, _, _, _, _),
+ [24] = PINGROUP(24, EAST, cci_timer3, cci_async, qup18, qdss, _, _, _, _, _),
+ [25] = PINGROUP(25, EAST, cci_timer4, cci_async, qup18, qdss, _, _, _, _, _),
+ [26] = PINGROUP(26, EAST, cci_async, qup18, qdss, _, _, _, _, _, _),
+ [27] = PINGROUP(27, EAST, qup15, _, qdss, _, _, _, _, _, _),
+ [28] = PINGROUP(28, EAST, qup15, qdss, _, _, _, _, _, _, _),
+ [29] = PINGROUP(29, EAST, qup15, qdss, _, _, _, _, _, _, _),
+ [30] = PINGROUP(30, EAST, qup15, qdss, _, _, _, _, _, _, _),
+ [31] = PINGROUP(31, NORTH, cci_i2c, qdss, _, _, _, _, _, _, _),
+ [32] = PINGROUP(32, NORTH, cci_i2c, qdss, _, _, _, _, _, _, _),
+ [33] = PINGROUP(33, NORTH, cci_i2c, qup_l5, qdss, _, _, _, _, _, _),
+ [34] = PINGROUP(34, NORTH, cci_i2c, qup_l6, _, _, _, _, _, _, _),
+ [35] = PINGROUP(35, NORTH, pci_e0, _, _, _, _, _, _, _, _),
+ [36] = PINGROUP(36, NORTH, pci_e0, _, _, _, _, _, _, _, _),
+ [37] = PINGROUP(37, NORTH, qup_l4, agera_pll, _, _, _, _, _, _, _),
+ [38] = PINGROUP(38, SOUTH, usb_phy, _, _, _, _, _, _, _, _),
+ [39] = PINGROUP(39, NORTH, qup9, qdss, _, _, _, _, _, _, _),
+ [40] = PINGROUP(40, NORTH, qup9, qdss, _, _, _, _, _, _, _),
+ [41] = PINGROUP(41, NORTH, qup9, qdss, _, _, _, _, _, _, _),
+ [42] = PINGROUP(42, NORTH, qup9, qdss, _, _, _, _, _, _, _),
+ [43] = PINGROUP(43, EAST, qup13, _, _, _, _, _, _, _, _),
+ [44] = PINGROUP(44, EAST, qup13, _, _, _, _, _, _, _, _),
+ [45] = PINGROUP(45, EAST, qup13, qdss_cti, _, _, _, _, _, _, _),
+ [46] = PINGROUP(46, EAST, qup13, qdss_cti, _, _, _, _, _, _, _),
+ [47] = PINGROUP(47, EAST, qup14, qdss, _, _, _, _, _, _, _),
+ [48] = PINGROUP(48, EAST, qup14, qdss, _, _, _, _, _, _, _),
+ [49] = PINGROUP(49, EAST, qup14, _, qdss_cti, _, _, _, _, _, _),
+ [50] = PINGROUP(50, EAST, qup14, qdss_cti, _, _, _, _, _, _, _),
+ [51] = PINGROUP(51, SOUTH, qup4, _, _, _, _, _, _, _, _),
+ [52] = PINGROUP(52, SOUTH, qup4, _, _, _, _, _, _, _, _),
+ [53] = PINGROUP(53, SOUTH, qup4, _, _, _, _, _, _, _, _),
+ [54] = PINGROUP(54, SOUTH, qup4, _, _, _, _, _, _, _, _),
+ [55] = PINGROUP(55, SOUTH, qup17, qup19, phase_flag, _, _, _, _, _, _),
+ [56] = PINGROUP(56, SOUTH, qup17, qup19, qdss_cti, phase_flag, _, _, _, _, _),
+ [57] = PINGROUP(57, SOUTH, qup17, qup19, qdss_cti, phase_flag, _, _, _, _, _),
+ [58] = PINGROUP(58, SOUTH, qup17, qup19, qdss_cti, phase_flag, _, _, _, _, _),
+ [59] = PINGROUP(59, SOUTH, rgmii, qup_l4, phase_flag, _, atest_char, _, _, _, _),
+ [60] = PINGROUP(60, SOUTH, _, nav_pps, nav_pps, atest_usb2, _, _, _, _, _),
+ [61] = PINGROUP(61, SOUTH, qlink_request, _, _, _, _, _, _, _, _),
+ [62] = PINGROUP(62, SOUTH, qlink_enable, _, _, _, _, _, _, _, _),
+ [63] = PINGROUP(63, SOUTH, wmss_reset, atest_usb23, _, _, _, _, _, _, _),
+ [64] = PINGROUP(64, SOUTH, _, phase_flag, _, _, _, _, _, _, _),
+ [65] = PINGROUP(65, SOUTH, _, _, _, _, _, _, _, _, _),
+ [66] = PINGROUP(66, SOUTH, _, _, _, _, _, _, _, _, _),
+ [67] = PINGROUP(67, SOUTH, _, _, _, _, _, _, _, _, _),
+ [68] = PINGROUP(68, SOUTH, _, pa_indicator, phase_flag, _, _, _, _, _, _),
+ [69] = PINGROUP(69, SOUTH, mss_lte, _, _, _, _, _, _, _, _),
+ [70] = PINGROUP(70, SOUTH, mss_lte, _, _, _, _, _, _, _, _),
+ [71] = PINGROUP(71, SOUTH, _, _, _, _, _, _, _, _, _),
+ [72] = PINGROUP(72, SOUTH, _, _, _, _, _, _, _, _, _),
+ [73] = PINGROUP(73, SOUTH, _, _, _, _, _, _, _, _, _),
+ [74] = PINGROUP(74, SOUTH, _, _, _, _, _, _, _, _, _),
+ [75] = PINGROUP(75, SOUTH, _, _, _, _, _, _, _, _, _),
+ [76] = PINGROUP(76, SOUTH, _, _, _, nav_pps, nav_pps, phase_flag, _, _, _),
+ [77] = PINGROUP(77, SOUTH, _, _, _, nav_pps, nav_pps, _, _, _, _),
+ [78] = PINGROUP(78, SOUTH, _, _, _, _, _, _, _, _, _),
+ [79] = PINGROUP(79, SOUTH, _, _, phase_flag, _, _, _, _, _, _),
+ [80] = PINGROUP(80, SOUTH, _, _, phase_flag, _, _, _, _, _, _),
+ [81] = PINGROUP(81, SOUTH, _, _, _, nav_pps, nav_pps, qup_l4, mdp_vsync, emac_pps, _),
+ [82] = PINGROUP(82, SOUTH, _, _, _, nav_pps, nav_pps, qup_l5, mdp_vsync, _, _),
+ [83] = PINGROUP(83, NORTH, qup12, qup16, _, qdss, _, _, _, _, _),
+ [84] = PINGROUP(84, NORTH, qup12, qup16, _, _, _, _, _, _, _),
+ [85] = PINGROUP(85, NORTH, qup12, qup16, _, _, _, _, _, _, _),
+ [86] = PINGROUP(86, NORTH, qup12, qup16, _, _, _, _, _, _, _),
+ [87] = PINGROUP(87, EAST, _, _, _, _, _, _, _, _, _),
+ [88] = PINGROUP(88, NORTH, tsif1, qup8, qspi_cs, tgu_ch3, _, _, _, _, _),
+ [89] = PINGROUP(89, NORTH, tsif1, qup8, qspi0, mdp_vsync0, mdp_vsync1, mdp_vsync2, mdp_vsync3, tgu_ch0, _),
+ [90] = PINGROUP(90, NORTH, tsif1, qup8, qspi1, sdc4, phase_flag, tgu_ch1, _, _, wlan1_adc1),
+ [91] = PINGROUP(91, NORTH, tsif1, qup8, qspi2, sdc4, vfr_1, phase_flag, tgu_ch2, _, _),
+ [92] = PINGROUP(92, NORTH, tsif2, qup11, qspi_clk, sdc4, phase_flag, _, wlan2_adc1, _, _),
+ [93] = PINGROUP(93, NORTH, tsif2, qup11, qspi3, sdc4, phase_flag, _, wlan2_adc0, _, _),
+ [94] = PINGROUP(94, NORTH, tsif2, qup11, qspi_cs, sdc4, phase_flag, _, _, _, _),
+ [95] = PINGROUP(95, NORTH, tsif2, qup11, sdc4, qup_l4, _, _, _, _, _),
+ [96] = PINGROUP(96, NORTH, tsif2, qup_l5, phase_flag, _, _, _, _, _, _),
+ [97] = PINGROUP(97, NORTH, sd_write, tsif1, qup_l6, _, _, _, _, _, _),
+ [98] = PINGROUP(98, SOUTH, qup7, ddr_bist, ddr_pxi3, _, _, _, _, _, _),
+ [99] = PINGROUP(99, SOUTH, qup7, ddr_bist, atest_usb13, ddr_pxi1, _, _, _, _, _),
+ [100] = PINGROUP(100, SOUTH, qup7, pll_bypassnl, atest_usb12, ddr_pxi1, _, _, _, _, _),
+ [101] = PINGROUP(101, SOUTH, qup7, pll_reset, ddr_pxi3, _, _, _, _, _, _),
+ [102] = PINGROUP(102, NORTH, pci_e1, _, _, _, _, _, _, _, _),
+ [103] = PINGROUP(103, NORTH, pci_e1, _, _, _, _, _, _, _, _),
+ [104] = PINGROUP(104, NORTH, _, _, _, _, _, _, _, _, _),
+ [105] = PINGROUP(105, WEST, uim2, _, _, _, _, _, _, _, _),
+ [106] = PINGROUP(106, WEST, uim2, _, _, _, _, _, _, _, _),
+ [107] = PINGROUP(107, WEST, uim2, _, _, _, _, _, _, _, _),
+ [108] = PINGROUP(108, WEST, uim2, _, _, _, _, _, _, _, _),
+ [109] = PINGROUP(109, WEST, uim1, _, _, _, _, _, _, _, _),
+ [110] = PINGROUP(110, WEST, uim1, _, _, _, _, _, _, _, _),
+ [111] = PINGROUP(111, WEST, uim1, _, _, _, _, _, _, _, _),
+ [112] = PINGROUP(112, WEST, uim1, _, _, _, _, _, _, _, _),
+ [113] = PINGROUP(113, WEST, uim_batt, usb2phy_ac, aoss_cti, _, _, _, _, _, _),
+ [114] = PINGROUP(114, SOUTH, qup1, rgmii, phase_flag, _, _, _, _, _, _),
+ [115] = PINGROUP(115, SOUTH, qup1, rgmii, phase_flag, adsp_ext, _, _, _, _, _),
+ [116] = PINGROUP(116, SOUTH, qup1, rgmii, phase_flag, _, _, _, _, _, _),
+ [117] = PINGROUP(117, SOUTH, qup1, rgmii, phase_flag, _, qdss, _, _, _, _),
+ [118] = PINGROUP(118, SOUTH, rgmii, phase_flag, _, qdss, _, _, _, _, _),
+ [119] = PINGROUP(119, SOUTH, qup5, rgmii, phase_flag, _, qdss, _, _, _, _),
+ [120] = PINGROUP(120, SOUTH, qup5, rgmii, phase_flag, _, qdss, _, _, _, _),
+ [121] = PINGROUP(121, SOUTH, qup5, rgmii, phase_flag, _, qdss, _, _, _, _),
+ [122] = PINGROUP(122, SOUTH, qup5, rgmii, phase_flag, _, _, _, _, _, _),
+ [123] = PINGROUP(123, SOUTH, usb2phy_ac, qup_l6, atest_usb22, _, _, _, _, _, _),
+ [124] = PINGROUP(124, SOUTH, emac_phy, _, _, _, _, _, _, _, _),
+ [125] = PINGROUP(125, WEST, hs3_mi2s, _, _, _, _, _, _, _, _),
+ [126] = PINGROUP(126, SOUTH, sec_mi2s, qup2, phase_flag, _, _, _, _, _, _),
+ [127] = PINGROUP(127, SOUTH, sec_mi2s, qup2, phase_flag, _, _, _, _, _, _),
+ [128] = PINGROUP(128, SOUTH, sec_mi2s, qup2, phase_flag, _, _, _, _, _, _),
+ [129] = PINGROUP(129, SOUTH, sec_mi2s, qup2, jitter_bist, atest_usb21, _, _, _, _, _),
+ [130] = PINGROUP(130, SOUTH, sec_mi2s, pll_bist, atest_usb20, atest_char0, _, _, _, _, _),
+ [131] = PINGROUP(131, SOUTH, ter_mi2s, gcc_gp1, _, _, _, _, _, _, _),
+ [132] = PINGROUP(132, SOUTH, ter_mi2s, _, qdss, _, _, _, _, _, _),
+ [133] = PINGROUP(133, SOUTH, ter_mi2s, qdss, atest_char1, _, _, _, _, _, _),
+ [134] = PINGROUP(134, SOUTH, ter_mi2s, qdss, atest_char2, _, _, _, _, _, _),
+ [135] = PINGROUP(135, SOUTH, ter_mi2s, atest_char3, _, _, _, _, _, _, _),
+ [136] = PINGROUP(136, SOUTH, qua_mi2s, gcc_gp1, _, _, _, _, _, _, _),
+ [137] = PINGROUP(137, SOUTH, qua_mi2s, gcc_gp2, _, _, _, _, _, _, _),
+ [138] = PINGROUP(138, SOUTH, qua_mi2s, gcc_gp3, _, _, _, _, _, _, _),
+ [139] = PINGROUP(139, SOUTH, qua_mi2s, _, _, _, _, _, _, _, _),
+ [140] = PINGROUP(140, SOUTH, qua_mi2s, _, _, _, _, _, _, _, _),
+ [141] = PINGROUP(141, SOUTH, qua_mi2s, _, _, _, _, _, _, _, _),
+ [142] = PINGROUP(142, SOUTH, qua_mi2s, _, _, _, _, _, _, _, _),
+ [143] = PINGROUP(143, SOUTH, pri_mi2s, _, _, _, _, _, _, _, _),
+ [144] = PINGROUP(144, SOUTH, pri_mi2s, qup3, phase_flag, _, ddr_pxi0, _, _, _, _),
+ [145] = PINGROUP(145, SOUTH, pri_mi2s_ws, qup3, phase_flag, ddr_bist, _, vsense_trigger, atest_usb1, ddr_pxi0, _),
+ [146] = PINGROUP(146, SOUTH, pri_mi2s, qup3, ddr_bist, atest_usb11, ddr_pxi2, _, _, _, _),
+ [147] = PINGROUP(147, SOUTH, pri_mi2s, qup3, dbg_out, atest_usb10, ddr_pxi2, _, _, _, _),
+ [148] = PINGROUP(148, SOUTH, spkr_i2s, audio_ref, _, _, _, _, _, _, _),
+ [149] = PINGROUP(149, SOUTH, lpass_slimbus, spkr_i2s, _, _, _, _, _, _, _),
+ [150] = PINGROUP(150, SOUTH, lpass_slimbus, spkr_i2s, tsense_pwm1, tsense_pwm2, _, _, _, _, _),
+ [151] = PINGROUP(151, SOUTH, lpass_slimbus, spkr_i2s, _, _, _, _, _, _, _),
+ [152] = PINGROUP(152, SOUTH, lpass_slimbus, spkr_i2s, _, _, _, _, _, _, _),
+ [153] = PINGROUP(153, SOUTH, btfm_slimbus, _, _, _, _, _, _, _, _),
+ [154] = PINGROUP(154, SOUTH, btfm_slimbus, _, _, _, _, _, _, _, _),
+ [155] = PINGROUP(155, WEST, hs1_mi2s, _, _, _, _, _, _, _, _),
+ [156] = PINGROUP(156, WEST, hs1_mi2s, _, _, _, _, _, _, _, _),
+ [157] = PINGROUP(157, WEST, hs1_mi2s, _, _, _, _, _, _, _, _),
+ [158] = PINGROUP(158, WEST, hs1_mi2s, _, _, _, _, _, _, _, _),
+ [159] = PINGROUP(159, WEST, hs1_mi2s, cri_trng0, _, _, _, _, _, _, _),
+ [160] = PINGROUP(160, WEST, hs2_mi2s, cri_trng1, _, _, _, _, _, _, _),
+ [161] = PINGROUP(161, WEST, hs2_mi2s, cri_trng, _, _, _, _, _, _, _),
+ [162] = PINGROUP(162, WEST, hs2_mi2s, sp_cmu, _, _, _, _, _, _, _),
+ [163] = PINGROUP(163, WEST, hs2_mi2s, prng_rosc, _, _, _, _, _, _, _),
+ [164] = PINGROUP(164, WEST, hs2_mi2s, _, _, _, _, _, _, _, _),
+ [165] = PINGROUP(165, WEST, hs3_mi2s, _, _, _, _, _, _, _, _),
+ [166] = PINGROUP(166, WEST, hs3_mi2s, _, _, _, _, _, _, _, _),
+ [167] = PINGROUP(167, WEST, hs3_mi2s, _, _, _, _, _, _, _, _),
+ [168] = PINGROUP(168, WEST, hs3_mi2s, _, _, _, _, _, _, _, _),
+ [169] = PINGROUP(169, NORTH, _, _, _, _, _, _, _, _, _),
+ [170] = PINGROUP(170, NORTH, _, _, _, _, _, _, _, _, _),
+ [171] = PINGROUP(171, NORTH, _, _, _, _, _, _, _, _, _),
+ [172] = PINGROUP(172, NORTH, _, _, _, _, _, _, _, _, _),
+ [173] = PINGROUP(173, NORTH, _, _, _, _, _, _, _, _, _),
+ [174] = PINGROUP(174, NORTH, _, _, _, _, _, _, _, _, _),
+ [175] = UFS_RESET(ufs_reset, 0xB6000),
+ [176] = SDC_QDSD_PINGROUP(sdc2_clk, 0xB2000, 14, 6),
+ [177] = SDC_QDSD_PINGROUP(sdc2_cmd, 0xB2000, 11, 3),
+ [178] = SDC_QDSD_PINGROUP(sdc2_data, 0xB2000, 9, 0),
+};
+
+static const struct msm_pinctrl_soc_data sm8150_pinctrl = {
+ .pins = sm8150_pins,
+ .npins = ARRAY_SIZE(sm8150_pins),
+ .functions = sm8150_functions,
+ .nfunctions = ARRAY_SIZE(sm8150_functions),
+ .groups = sm8150_groups,
+ .ngroups = ARRAY_SIZE(sm8150_groups),
+ .ngpios = 176,
+ .tiles = sm8150_tiles,
+ .ntiles = ARRAY_SIZE(sm8150_tiles),
+};
+
+static int sm8150_pinctrl_probe(struct platform_device *pdev)
+{
+ return msm_pinctrl_probe(pdev, &sm8150_pinctrl);
+}
+
+static const struct of_device_id sm8150_pinctrl_of_match[] = {
+ { .compatible = "qcom,sm8150-pinctrl", },
+ { },
+};
+
+static struct platform_driver sm8150_pinctrl_driver = {
+ .driver = {
+ .name = "sm8150-pinctrl",
+ .of_match_table = sm8150_pinctrl_of_match,
+ },
+ .probe = sm8150_pinctrl_probe,
+ .remove = msm_pinctrl_remove,
+};
+
+static int __init sm8150_pinctrl_init(void)
+{
+ return platform_driver_register(&sm8150_pinctrl_driver);
+}
+arch_initcall(sm8150_pinctrl_init);
+
+static void __exit sm8150_pinctrl_exit(void)
+{
+ platform_driver_unregister(&sm8150_pinctrl_driver);
+}
+module_exit(sm8150_pinctrl_exit);
+
+MODULE_DESCRIPTION("QTI sm8150 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, sm8150_pinctrl_of_match);
diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c
index 3f989f5cb021..b8640ad41bef 100644
--- a/drivers/pinctrl/sh-pfc/core.c
+++ b/drivers/pinctrl/sh-pfc/core.c
@@ -717,7 +717,7 @@ static int sh_pfc_suspend_init(struct sh_pfc *pfc) { return 0; }
#endif /* CONFIG_PM_SLEEP && CONFIG_ARM_PSCI_FW */
#ifdef DEBUG
-static bool is0s(const u16 *enum_ids, unsigned int n)
+static bool __init is0s(const u16 *enum_ids, unsigned int n)
{
unsigned int i;
@@ -728,11 +728,11 @@ static bool is0s(const u16 *enum_ids, unsigned int n)
return true;
}
-static unsigned int sh_pfc_errors;
-static unsigned int sh_pfc_warnings;
+static unsigned int sh_pfc_errors __initdata = 0;
+static unsigned int sh_pfc_warnings __initdata = 0;
-static void sh_pfc_check_cfg_reg(const char *drvname,
- const struct pinmux_cfg_reg *cfg_reg)
+static void __init sh_pfc_check_cfg_reg(const char *drvname,
+ const struct pinmux_cfg_reg *cfg_reg)
{
unsigned int i, n, rw, fw;
@@ -764,7 +764,7 @@ static void sh_pfc_check_cfg_reg(const char *drvname,
}
}
-static void sh_pfc_check_info(const struct sh_pfc_soc_info *info)
+static void __init sh_pfc_check_info(const struct sh_pfc_soc_info *info)
{
const struct sh_pfc_function *func;
const char *drvname = info->name;
@@ -773,6 +773,35 @@ static void sh_pfc_check_info(const struct sh_pfc_soc_info *info)
pr_info("Checking %s\n", drvname);
+ /* Check pins */
+ for (i = 0; i < info->nr_pins; i++) {
+ for (j = 0; j < i; j++) {
+ if (!strcmp(info->pins[i].name, info->pins[j].name)) {
+ pr_err("%s: pin %s/%s: name conflict\n",
+ drvname, info->pins[i].name,
+ info->pins[j].name);
+ sh_pfc_errors++;
+ }
+
+ if (info->pins[i].pin != (u16)-1 &&
+ info->pins[i].pin == info->pins[j].pin) {
+ pr_err("%s: pin %s/%s: pin %u conflict\n",
+ drvname, info->pins[i].name,
+ info->pins[j].name, info->pins[i].pin);
+ sh_pfc_errors++;
+ }
+
+ if (info->pins[i].enum_id &&
+ info->pins[i].enum_id == info->pins[j].enum_id) {
+ pr_err("%s: pin %s/%s: enum_id %u conflict\n",
+ drvname, info->pins[i].name,
+ info->pins[j].name,
+ info->pins[i].enum_id);
+ sh_pfc_errors++;
+ }
+ }
+ }
+
/* Check groups and functions */
refcnts = kcalloc(info->nr_groups, sizeof(*refcnts), GFP_KERNEL);
if (!refcnts)
@@ -780,9 +809,15 @@ static void sh_pfc_check_info(const struct sh_pfc_soc_info *info)
for (i = 0; i < info->nr_functions; i++) {
func = &info->functions[i];
+ if (!func->name) {
+ pr_err("%s: empty function %u\n", drvname, i);
+ sh_pfc_errors++;
+ continue;
+ }
for (j = 0; j < func->nr_groups; j++) {
for (k = 0; k < info->nr_groups; k++) {
- if (!strcmp(func->groups[j],
+ if (info->groups[k].name &&
+ !strcmp(func->groups[j],
info->groups[k].name)) {
refcnts[k]++;
break;
@@ -798,13 +833,18 @@ static void sh_pfc_check_info(const struct sh_pfc_soc_info *info)
}
for (i = 0; i < info->nr_groups; i++) {
+ if (!info->groups[i].name) {
+ pr_err("%s: empty group %u\n", drvname, i);
+ sh_pfc_errors++;
+ continue;
+ }
if (!refcnts[i]) {
pr_err("%s: orphan group %s\n", drvname,
info->groups[i].name);
sh_pfc_errors++;
} else if (refcnts[i] > 1) {
- pr_err("%s: group %s referred by %u functions\n",
- drvname, info->groups[i].name, refcnts[i]);
+ pr_warn("%s: group %s referenced by %u functions\n",
+ drvname, info->groups[i].name, refcnts[i]);
sh_pfc_warnings++;
}
}
@@ -816,7 +856,7 @@ static void sh_pfc_check_info(const struct sh_pfc_soc_info *info)
sh_pfc_check_cfg_reg(drvname, &info->cfg_regs[i]);
}
-static void sh_pfc_check_driver(const struct platform_driver *pdrv)
+static void __init sh_pfc_check_driver(const struct platform_driver *pdrv)
{
unsigned int i;
diff --git a/drivers/pinctrl/sh-pfc/pfc-emev2.c b/drivers/pinctrl/sh-pfc/pfc-emev2.c
index 0af1ef82a1a8..6c66fc335d2f 100644
--- a/drivers/pinctrl/sh-pfc/pfc-emev2.c
+++ b/drivers/pinctrl/sh-pfc/pfc-emev2.c
@@ -19,6 +19,20 @@
PORT_1(155, fn, pfx##155, sfx), PORT_1(156, fn, pfx##156, sfx), \
PORT_1(157, fn, pfx##157, sfx), PORT_1(158, fn, pfx##158, sfx)
+#define CPU_ALL_NOGP(fn) \
+ PIN_NOGP(LCD3_B2, "B15", fn), \
+ PIN_NOGP(LCD3_B3, "C15", fn), \
+ PIN_NOGP(LCD3_B4, "D15", fn), \
+ PIN_NOGP(LCD3_B5, "B14", fn), \
+ PIN_NOGP(LCD3_B6, "C14", fn), \
+ PIN_NOGP(LCD3_B7, "D14", fn), \
+ PIN_NOGP(LCD3_G2, "B17", fn), \
+ PIN_NOGP(LCD3_G3, "C17", fn), \
+ PIN_NOGP(LCD3_G4, "D17", fn), \
+ PIN_NOGP(LCD3_G5, "B16", fn), \
+ PIN_NOGP(LCD3_G6, "C16", fn), \
+ PIN_NOGP(LCD3_G7, "D16", fn)
+
enum {
PINMUX_RESERVED = 0,
@@ -218,10 +232,13 @@ enum {
PINMUX_MARK_END,
};
-/* Pin numbers for pins without a corresponding GPIO port number are computed
- * from the row and column numbers with a 1000 offset to avoid collisions with
- * GPIO port numbers. */
-#define PIN_NUMBER(row, col) (1000+((row)-1)*23+(col)-1)
+/*
+ * Pins not associated with a GPIO port.
+ */
+enum {
+ PORT_ASSIGN_LAST(),
+ NOGP_ALL(),
+};
/* Expand to a list of sh_pfc_pin entries (named PORT#).
* NOTE: No config are recorded since the driver do not handle pinconf. */
@@ -230,20 +247,7 @@ enum {
static const struct sh_pfc_pin pinmux_pins[] = {
PINMUX_EMEV_GPIO_ALL(),
-
- /* Pins not associated with a GPIO port */
- SH_PFC_PIN_NAMED(2, 14, B14),
- SH_PFC_PIN_NAMED(2, 15, B15),
- SH_PFC_PIN_NAMED(2, 16, B16),
- SH_PFC_PIN_NAMED(2, 17, B17),
- SH_PFC_PIN_NAMED(3, 14, C14),
- SH_PFC_PIN_NAMED(3, 15, C15),
- SH_PFC_PIN_NAMED(3, 16, C16),
- SH_PFC_PIN_NAMED(3, 17, C17),
- SH_PFC_PIN_NAMED(4, 14, D14),
- SH_PFC_PIN_NAMED(4, 15, D15),
- SH_PFC_PIN_NAMED(4, 16, D16),
- SH_PFC_PIN_NAMED(4, 17, D17),
+ PINMUX_NOGP_ALL(),
};
/* Expand to a list of name_DATA, name_FN marks */
@@ -829,12 +833,10 @@ static const unsigned int lcd3_rgb888_pins[] = {
/* R[0:7], G[0:7], B[0:7] */
32, 33, 34, 35,
36, 37, 38, 39,
- 40, 41, PIN_NUMBER(2, 17), PIN_NUMBER(3, 17),
- PIN_NUMBER(4, 17), PIN_NUMBER(2, 16), PIN_NUMBER(3, 16),
- PIN_NUMBER(4, 16),
- 42, 43, PIN_NUMBER(2, 15), PIN_NUMBER(3, 15),
- PIN_NUMBER(4, 15), PIN_NUMBER(2, 14), PIN_NUMBER(3, 14),
- PIN_NUMBER(4, 14)
+ 40, 41, PIN_LCD3_G2, PIN_LCD3_G3,
+ PIN_LCD3_G4, PIN_LCD3_G5, PIN_LCD3_G6, PIN_LCD3_G7,
+ 42, 43, PIN_LCD3_B2, PIN_LCD3_B3,
+ PIN_LCD3_B4, PIN_LCD3_B5, PIN_LCD3_B6, PIN_LCD3_B7
};
static const unsigned int lcd3_rgb888_mux[] = {
LCD3_R0_MARK, LCD3_R1_MARK, LCD3_R2_MARK, LCD3_R3_MARK,
@@ -850,12 +852,10 @@ static const unsigned int yuv3_pins[] = {
/* CLK_O, HS, VS, DE */
18, 21, 22, 23,
/* YUV3_D[0:15] */
- 40, 41, PIN_NUMBER(2, 17), PIN_NUMBER(3, 17),
- PIN_NUMBER(4, 17), PIN_NUMBER(2, 16), PIN_NUMBER(3, 16),
- PIN_NUMBER(4, 16),
- 42, 43, PIN_NUMBER(2, 15), PIN_NUMBER(3, 15),
- PIN_NUMBER(4, 15), PIN_NUMBER(2, 14), PIN_NUMBER(3, 14),
- PIN_NUMBER(4, 14),
+ 40, 41, PIN_LCD3_G2, PIN_LCD3_G3,
+ PIN_LCD3_G4, PIN_LCD3_G5, PIN_LCD3_G6, PIN_LCD3_G7,
+ 42, 43, PIN_LCD3_B2, PIN_LCD3_B3,
+ PIN_LCD3_B4, PIN_LCD3_B5, PIN_LCD3_B6, PIN_LCD3_B7,
};
static const unsigned int yuv3_mux[] = {
YUV3_CLK_O_MARK, YUV3_HS_MARK, YUV3_VS_MARK, YUV3_DE_MARK,
@@ -972,12 +972,10 @@ static const unsigned int tp33_pins[] = {
/* CLK, CTRL */
38, 39,
/* TP33_DATA[0:15] */
- 40, 41, PIN_NUMBER(2, 17), PIN_NUMBER(3, 17),
- PIN_NUMBER(4, 17), PIN_NUMBER(2, 16), PIN_NUMBER(3, 16),
- PIN_NUMBER(4, 16),
- 42, 43, PIN_NUMBER(2, 15), PIN_NUMBER(3, 15),
- PIN_NUMBER(4, 15), PIN_NUMBER(2, 14), PIN_NUMBER(3, 14),
- PIN_NUMBER(4, 14),
+ 40, 41, PIN_LCD3_G2, PIN_LCD3_G3,
+ PIN_LCD3_G4, PIN_LCD3_G5, PIN_LCD3_G6, PIN_LCD3_G7,
+ 42, 43, PIN_LCD3_B2, PIN_LCD3_B3,
+ PIN_LCD3_B4, PIN_LCD3_B5, PIN_LCD3_B6, PIN_LCD3_B7,
};
static const unsigned int tp33_mux[] = {
TP33_CLK_MARK, TP33_CTRL_MARK,
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a73a4.c b/drivers/pinctrl/sh-pfc/pfc-r8a73a4.c
index bf12849defdb..b21f5afe610f 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a73a4.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a73a4.c
@@ -1252,7 +1252,7 @@ static const u16 pinmux_data[] = {
#define __O (SH_PFC_PIN_CFG_OUTPUT)
#define __IO (SH_PFC_PIN_CFG_INPUT | SH_PFC_PIN_CFG_OUTPUT)
-#define __PUD (SH_PFC_PIN_CFG_PULL_DOWN | SH_PFC_PIN_CFG_PULL_UP)
+#define __PUD (SH_PFC_PIN_CFG_PULL_UP_DOWN)
#define R8A73A4_PIN_IO_PU_PD(pin) SH_PFC_PIN_CFG(pin, __IO | __PUD)
#define R8A73A4_PIN_O(pin) SH_PFC_PIN_CFG(pin, __O)
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7740.c b/drivers/pinctrl/sh-pfc/pfc-r8a7740.c
index 696a0f6fc1da..fdf1b0f09f57 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7740.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7740.c
@@ -1515,7 +1515,7 @@ static const u16 pinmux_data[] = {
#define __IO (SH_PFC_PIN_CFG_INPUT | SH_PFC_PIN_CFG_OUTPUT)
#define __PD (SH_PFC_PIN_CFG_PULL_DOWN)
#define __PU (SH_PFC_PIN_CFG_PULL_UP)
-#define __PUD (SH_PFC_PIN_CFG_PULL_DOWN | SH_PFC_PIN_CFG_PULL_UP)
+#define __PUD (SH_PFC_PIN_CFG_PULL_UP_DOWN)
#define R8A7740_PIN_I_PD(pin) SH_PFC_PIN_CFG(pin, __I | __PD)
#define R8A7740_PIN_I_PU(pin) SH_PFC_PIN_CFG(pin, __I | __PU)
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a77470.c b/drivers/pinctrl/sh-pfc/pfc-r8a77470.c
index c05dc1490486..b3b116da1bb0 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a77470.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a77470.c
@@ -10,7 +10,7 @@
#include "sh_pfc.h"
-#define CPU_ALL_PORT(fn, sfx) \
+#define CPU_ALL_GP(fn, sfx) \
PORT_GP_4(0, fn, sfx), \
PORT_GP_1(0, 4, fn, sfx), \
PORT_GP_CFG_1(0, 5, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7778.c b/drivers/pinctrl/sh-pfc/pfc-r8a7778.c
index 49fe52d35f30..24866a5958ae 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7778.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7778.c
@@ -22,28 +22,17 @@
#define PORT_GP_PUP_1(bank, pin, fn, sfx) \
PORT_GP_CFG_1(bank, pin, fn, sfx, SH_PFC_PIN_CFG_PULL_UP)
-#define PORT_GP_PUP_27(bank, fn, sfx) \
- PORT_GP_PUP_1(bank, 0, fn, sfx), PORT_GP_PUP_1(bank, 1, fn, sfx), \
- PORT_GP_PUP_1(bank, 2, fn, sfx), PORT_GP_PUP_1(bank, 3, fn, sfx), \
- PORT_GP_PUP_1(bank, 4, fn, sfx), PORT_GP_PUP_1(bank, 5, fn, sfx), \
- PORT_GP_PUP_1(bank, 6, fn, sfx), PORT_GP_PUP_1(bank, 7, fn, sfx), \
- PORT_GP_PUP_1(bank, 8, fn, sfx), PORT_GP_PUP_1(bank, 9, fn, sfx), \
- PORT_GP_PUP_1(bank, 10, fn, sfx), PORT_GP_PUP_1(bank, 11, fn, sfx), \
- PORT_GP_PUP_1(bank, 12, fn, sfx), PORT_GP_PUP_1(bank, 13, fn, sfx), \
- PORT_GP_PUP_1(bank, 14, fn, sfx), PORT_GP_PUP_1(bank, 15, fn, sfx), \
- PORT_GP_PUP_1(bank, 16, fn, sfx), PORT_GP_PUP_1(bank, 17, fn, sfx), \
- PORT_GP_PUP_1(bank, 18, fn, sfx), PORT_GP_PUP_1(bank, 19, fn, sfx), \
- PORT_GP_PUP_1(bank, 20, fn, sfx), PORT_GP_PUP_1(bank, 21, fn, sfx), \
- PORT_GP_PUP_1(bank, 22, fn, sfx), PORT_GP_PUP_1(bank, 23, fn, sfx), \
- PORT_GP_PUP_1(bank, 24, fn, sfx), PORT_GP_PUP_1(bank, 25, fn, sfx), \
- PORT_GP_PUP_1(bank, 26, fn, sfx)
-
-#define CPU_ALL_PORT(fn, sfx) \
+#define CPU_ALL_GP(fn, sfx) \
PORT_GP_CFG_32(0, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
PORT_GP_CFG_32(1, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
PORT_GP_CFG_32(2, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
PORT_GP_CFG_32(3, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
- PORT_GP_PUP_27(4, fn, sfx)
+ PORT_GP_CFG_27(4, fn, sfx, SH_PFC_PIN_CFG_PULL_UP)
+
+#define CPU_ALL_NOGP(fn) \
+ PIN_NOGP(CLKOUT, "B25", fn), \
+ PIN_NOGP(CS0, "A20", fn), \
+ PIN_NOGP(CS1_A26, "C20", fn)
enum {
PINMUX_RESERVED = 0,
@@ -1253,19 +1242,17 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP10_24_22, CAN_CLK_C, SEL_CANCLK_C),
};
-/* Pin numbers for pins without a corresponding GPIO port number are computed
- * from the row and column numbers with a 1000 offset to avoid collisions with
- * GPIO port numbers.
+/*
+ * Pins not associated with a GPIO port.
*/
-#define PIN_NUMBER(row, col) (1000+((row)-1)*25+(col)-1)
+enum {
+ GP_ASSIGN_LAST(),
+ NOGP_ALL(),
+};
static const struct sh_pfc_pin pinmux_pins[] = {
PINMUX_GPIO_GP_ALL(),
-
- /* Pins not associated with a GPIO port */
- SH_PFC_PIN_NAMED(3, 20, C20),
- SH_PFC_PIN_NAMED(1, 20, A20),
- SH_PFC_PIN_NAMED(2, 25, B25),
+ PINMUX_NOGP_ALL(),
};
/* - macro */
@@ -1400,7 +1387,7 @@ HSPI_PFC_DAT(hspi1_a, HSPI_CLK1_A, HSPI_CS1_A,
HSPI_RX1_A, HSPI_TX1_A);
HSPI_PFC_PIN(hspi1_b, RCAR_GP_PIN(0, 27), RCAR_GP_PIN(0, 26),
- PIN_NUMBER(1, 20), PIN_NUMBER(2, 25));
+ PIN_CS0, PIN_CLKOUT);
HSPI_PFC_DAT(hspi1_b, HSPI_CLK1_B, HSPI_CS1_B,
HSPI_RX1_B, HSPI_TX1_B);
@@ -1426,7 +1413,7 @@ I2C_PFC_PIN(i2c1_b, RCAR_GP_PIN(4, 17), RCAR_GP_PIN(4, 18));
I2C_PFC_MUX(i2c1_b, SDA1_B, SCL1_B);
/* - I2C2 ------------------------------------------------------------------ */
-I2C_PFC_PIN(i2c2_a, PIN_NUMBER(3, 20), RCAR_GP_PIN(1, 3));
+I2C_PFC_PIN(i2c2_a, PIN_CS1_A26, RCAR_GP_PIN(1, 3));
I2C_PFC_MUX(i2c2_a, SDA2_A, SCL2_A);
I2C_PFC_PIN(i2c2_b, RCAR_GP_PIN(0, 3), RCAR_GP_PIN(0, 4));
I2C_PFC_MUX(i2c2_b, SDA2_B, SCL2_B);
@@ -1516,7 +1503,7 @@ SCIF_PFC_PIN(scif2_data_e, RCAR_GP_PIN(0, 3), RCAR_GP_PIN(0, 4));
SCIF_PFC_DAT(scif2_data_e, TX2_E, RX2_E);
SCIF_PFC_PIN(scif2_clk_a, RCAR_GP_PIN(3, 9));
SCIF_PFC_CLK(scif2_clk_a, SCK2_A);
-SCIF_PFC_PIN(scif2_clk_b, PIN_NUMBER(3, 20));
+SCIF_PFC_PIN(scif2_clk_b, PIN_CS1_A26);
SCIF_PFC_CLK(scif2_clk_b, SCK2_B);
SCIF_PFC_PIN(scif2_clk_c, RCAR_GP_PIN(4, 12));
SCIF_PFC_CLK(scif2_clk_c, SCK2_C);
@@ -1631,7 +1618,7 @@ SSI_PFC_PINS(ssi0_data, RCAR_GP_PIN(3, 10));
SSI_PFC_DATA(ssi0_data, SSI_SDATA0);
SSI_PFC_PINS(ssi1_a_ctrl, RCAR_GP_PIN(2, 20), RCAR_GP_PIN(2, 21));
SSI_PFC_CTRL(ssi1_a_ctrl, SSI_SCK1_A, SSI_WS1_A);
-SSI_PFC_PINS(ssi1_b_ctrl, PIN_NUMBER(3, 20), RCAR_GP_PIN(1, 3));
+SSI_PFC_PINS(ssi1_b_ctrl, PIN_CS1_A26, RCAR_GP_PIN(1, 3));
SSI_PFC_CTRL(ssi1_b_ctrl, SSI_SCK1_B, SSI_WS1_B);
SSI_PFC_PINS(ssi1_data, RCAR_GP_PIN(3, 9));
SSI_PFC_DATA(ssi1_data, SSI_SDATA1);
@@ -2921,8 +2908,6 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
{ },
};
-#define PIN_NONE U16_MAX
-
static const struct pinmux_bias_reg pinmux_bias_regs[] = {
{ PINMUX_BIAS_REG("PUPR0", 0x100, "N/A", 0) {
[ 0] = RCAR_GP_PIN(0, 6), /* A0 */
@@ -2969,28 +2954,28 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
[ 7] = RCAR_GP_PIN(1, 10), /* DACK0 */
[ 8] = RCAR_GP_PIN(1, 12), /* IRQ0 */
[ 9] = RCAR_GP_PIN(1, 13), /* IRQ1 */
- [10] = PIN_NONE,
- [11] = PIN_NONE,
- [12] = PIN_NONE,
- [13] = PIN_NONE,
- [14] = PIN_NONE,
- [15] = PIN_NONE,
- [16] = PIN_NONE,
- [17] = PIN_NONE,
- [18] = PIN_NONE,
- [19] = PIN_NONE,
- [20] = PIN_NONE,
- [21] = PIN_NONE,
- [22] = PIN_NONE,
- [23] = PIN_NONE,
- [24] = PIN_NONE,
- [25] = PIN_NONE,
- [26] = PIN_NONE,
- [27] = PIN_NONE,
- [28] = PIN_NONE,
- [29] = PIN_NONE,
- [30] = PIN_NONE,
- [31] = PIN_NONE,
+ [10] = SH_PFC_PIN_NONE,
+ [11] = SH_PFC_PIN_NONE,
+ [12] = SH_PFC_PIN_NONE,
+ [13] = SH_PFC_PIN_NONE,
+ [14] = SH_PFC_PIN_NONE,
+ [15] = SH_PFC_PIN_NONE,
+ [16] = SH_PFC_PIN_NONE,
+ [17] = SH_PFC_PIN_NONE,
+ [18] = SH_PFC_PIN_NONE,
+ [19] = SH_PFC_PIN_NONE,
+ [20] = SH_PFC_PIN_NONE,
+ [21] = SH_PFC_PIN_NONE,
+ [22] = SH_PFC_PIN_NONE,
+ [23] = SH_PFC_PIN_NONE,
+ [24] = SH_PFC_PIN_NONE,
+ [25] = SH_PFC_PIN_NONE,
+ [26] = SH_PFC_PIN_NONE,
+ [27] = SH_PFC_PIN_NONE,
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
} },
{ PINMUX_BIAS_REG("PUPR2", 0x108, "N/A", 0) {
[ 0] = RCAR_GP_PIN(1, 22), /* DU0_DR0 */
@@ -3112,21 +3097,21 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
[14] = RCAR_GP_PIN(4, 20), /* ETH_MAGIC */
[15] = RCAR_GP_PIN(4, 25), /* AVS1 */
[16] = RCAR_GP_PIN(4, 26), /* AVS2 */
- [17] = PIN_NONE,
- [18] = PIN_NONE,
- [19] = PIN_NONE,
- [20] = PIN_NONE,
- [21] = PIN_NONE,
- [22] = PIN_NONE,
- [23] = PIN_NONE,
- [24] = PIN_NONE,
- [25] = PIN_NONE,
- [26] = PIN_NONE,
- [27] = PIN_NONE,
- [28] = PIN_NONE,
- [29] = PIN_NONE,
- [30] = PIN_NONE,
- [31] = PIN_NONE,
+ [17] = SH_PFC_PIN_NONE,
+ [18] = SH_PFC_PIN_NONE,
+ [19] = SH_PFC_PIN_NONE,
+ [20] = SH_PFC_PIN_NONE,
+ [21] = SH_PFC_PIN_NONE,
+ [22] = SH_PFC_PIN_NONE,
+ [23] = SH_PFC_PIN_NONE,
+ [24] = SH_PFC_PIN_NONE,
+ [25] = SH_PFC_PIN_NONE,
+ [26] = SH_PFC_PIN_NONE,
+ [27] = SH_PFC_PIN_NONE,
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
} },
{ /* sentinel */ },
};
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7779.c b/drivers/pinctrl/sh-pfc/pfc-r8a7779.c
index 0c121b28ec3f..3e47cdc1411d 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7779.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7779.c
@@ -11,7 +11,7 @@
#include "sh_pfc.h"
-#define CPU_ALL_PORT(fn, sfx) \
+#define CPU_ALL_GP(fn, sfx) \
PORT_GP_32(0, fn, sfx), \
PORT_GP_32(1, fn, sfx), \
PORT_GP_32(2, fn, sfx), \
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c
index c41a6761cf9d..3366ed561cce 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c
@@ -20,7 +20,7 @@
* All pins assigned to GPIO bank 3 can be used for SD interfaces in
* which case they support both 3.3V and 1.8V signalling.
*/
-#define CPU_ALL_PORT(fn, sfx) \
+#define CPU_ALL_GP(fn, sfx) \
PORT_GP_32(0, fn, sfx), \
PORT_GP_30(1, fn, sfx), \
PORT_GP_30(2, fn, sfx), \
@@ -28,6 +28,12 @@
PORT_GP_32(4, fn, sfx), \
PORT_GP_32(5, fn, sfx)
+#define CPU_ALL_NOGP(fn) \
+ PIN_NOGP(IIC0_SDA, "AF15", fn), \
+ PIN_NOGP(IIC0_SCL, "AG15", fn), \
+ PIN_NOGP(IIC3_SDA, "AH15", fn), \
+ PIN_NOGP(IIC3_SCL, "AJ15", fn)
+
enum {
PINMUX_RESERVED = 0,
@@ -1727,19 +1733,17 @@ static const u16 pinmux_data[] = {
PINMUX_DATA(I2C3_SDA_MARK, FN_SEL_IICDVFS_1),
};
-/* R8A7790 has 6 banks with 32 GPIOs in each = 192 GPIOs */
-#define ROW_GROUP_A(r) ('Z' - 'A' + 1 + (r))
-#define PIN_NUMBER(r, c) (((r) - 'A') * 31 + (c) + 200)
-#define PIN_A_NUMBER(r, c) PIN_NUMBER(ROW_GROUP_A(r), c)
+/*
+ * Pins not associated with a GPIO port.
+ */
+enum {
+ GP_ASSIGN_LAST(),
+ NOGP_ALL(),
+};
static const struct sh_pfc_pin pinmux_pins[] = {
PINMUX_GPIO_GP_ALL(),
-
- /* Pins not associated with a GPIO port */
- SH_PFC_PIN_NAMED(ROW_GROUP_A('F'), 15, AF15),
- SH_PFC_PIN_NAMED(ROW_GROUP_A('G'), 15, AG15),
- SH_PFC_PIN_NAMED(ROW_GROUP_A('H'), 15, AH15),
- SH_PFC_PIN_NAMED(ROW_GROUP_A('J'), 15, AJ15),
+ PINMUX_NOGP_ALL(),
};
/* - AUDIO CLOCK ------------------------------------------------------------ */
@@ -2135,7 +2139,7 @@ static const unsigned int hscif1_ctrl_b_mux[] = {
/* - I2C0 ------------------------------------------------------------------- */
static const unsigned int i2c0_pins[] = {
/* SCL, SDA */
- PIN_A_NUMBER('G', 15), PIN_A_NUMBER('F', 15),
+ PIN_IIC0_SCL, PIN_IIC0_SDA,
};
static const unsigned int i2c0_mux[] = {
I2C0_SCL_MARK, I2C0_SDA_MARK,
@@ -2201,7 +2205,7 @@ static const unsigned int i2c2_e_mux[] = {
/* - I2C3 ------------------------------------------------------------------- */
static const unsigned int i2c3_pins[] = {
/* SCL, SDA */
- PIN_A_NUMBER('J', 15), PIN_A_NUMBER('H', 15),
+ PIN_IIC3_SCL, PIN_IIC3_SDA,
};
static const unsigned int i2c3_mux[] = {
I2C3_SCL_MARK, I2C3_SDA_MARK,
@@ -2209,7 +2213,7 @@ static const unsigned int i2c3_mux[] = {
/* - IIC0 (I2C4) ------------------------------------------------------------ */
static const unsigned int iic0_pins[] = {
/* SCL, SDA */
- PIN_A_NUMBER('G', 15), PIN_A_NUMBER('F', 15),
+ PIN_IIC0_SCL, PIN_IIC0_SDA,
};
static const unsigned int iic0_mux[] = {
IIC0_SCL_MARK, IIC0_SDA_MARK,
@@ -2274,8 +2278,8 @@ static const unsigned int iic2_e_mux[] = {
};
/* - IIC3 (I2C7) ------------------------------------------------------------ */
static const unsigned int iic3_pins[] = {
-/* SCL, SDA */
- PIN_A_NUMBER('J', 15), PIN_A_NUMBER('H', 15),
+ /* SCL, SDA */
+ PIN_IIC3_SCL, PIN_IIC3_SDA,
};
static const unsigned int iic3_mux[] = {
IIC3_SCL_MARK, IIC3_SDA_MARK,
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c
index 1292ec8d268f..bc9caf812fc1 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c
@@ -15,7 +15,7 @@
* Pins 0-23 assigned to GPIO bank 6 can be used for SD interfaces in
* which case they support both 3.3V and 1.8V signalling.
*/
-#define CPU_ALL_PORT(fn, sfx) \
+#define CPU_ALL_GP(fn, sfx) \
PORT_GP_32(0, fn, sfx), \
PORT_GP_26(1, fn, sfx), \
PORT_GP_32(2, fn, sfx), \
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7792.c b/drivers/pinctrl/sh-pfc/pfc-r8a7792.c
index bbace1478613..258f82fb31c0 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7792.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7792.c
@@ -11,7 +11,7 @@
#include "core.h"
#include "sh_pfc.h"
-#define CPU_ALL_PORT(fn, sfx) \
+#define CPU_ALL_GP(fn, sfx) \
PORT_GP_29(0, fn, sfx), \
PORT_GP_23(1, fn, sfx), \
PORT_GP_32(2, fn, sfx), \
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c
index 1ff4969d8381..34481b6c4328 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c
@@ -14,7 +14,7 @@
#include "core.h"
#include "sh_pfc.h"
-#define CPU_ALL_PORT(fn, sfx) \
+#define CPU_ALL_GP(fn, sfx) \
PORT_GP_32(0, fn, sfx), \
PORT_GP_26(1, fn, sfx), \
PORT_GP_32(2, fn, sfx), \
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7795-es1.c b/drivers/pinctrl/sh-pfc/pfc-r8a7795-es1.c
index f16dfbad3f17..95f9aae3bfba 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7795-es1.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7795-es1.c
@@ -11,11 +11,9 @@
#include "core.h"
#include "sh_pfc.h"
-#define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | \
- SH_PFC_PIN_CFG_PULL_UP | \
- SH_PFC_PIN_CFG_PULL_DOWN)
+#define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | SH_PFC_PIN_CFG_PULL_UP_DOWN)
-#define CPU_ALL_PORT(fn, sfx) \
+#define CPU_ALL_GP(fn, sfx) \
PORT_GP_CFG_16(0, fn, sfx, CFG_FLAGS), \
PORT_GP_CFG_28(1, fn, sfx, CFG_FLAGS), \
PORT_GP_CFG_15(2, fn, sfx, CFG_FLAGS), \
@@ -28,6 +26,53 @@
PORT_GP_CFG_26(5, fn, sfx, CFG_FLAGS), \
PORT_GP_CFG_32(6, fn, sfx, CFG_FLAGS), \
PORT_GP_CFG_4(7, fn, sfx, CFG_FLAGS)
+
+#define CPU_ALL_NOGP(fn) \
+ PIN_NOGP_CFG(ASEBRK, "ASEBRK", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_MDIO, "AVB_MDIO", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_RD0, "AVB_RD0", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_RD1, "AVB_RD1", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_RD2, "AVB_RD2", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_RD3, "AVB_RD3", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_RXC, "AVB_RXC", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_RX_CTL, "AVB_RX_CTL", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TD0, "AVB_TD0", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TD1, "AVB_TD1", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TD2, "AVB_TD2", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TD3, "AVB_TD3", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TXC, "AVB_TXC", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TXCREFCLK, "AVB_TXCREFCLK", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TX_CTL, "AVB_TX_CTL", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(CLKOUT, "CLKOUT", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(DU_DOTCLKIN0, "DU_DOTCLKIN0", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(DU_DOTCLKIN1, "DU_DOTCLKIN1", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(DU_DOTCLKIN2, "DU_DOTCLKIN2", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(DU_DOTCLKIN3, "DU_DOTCLKIN3", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(EXTALR, "EXTALR", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN),\
+ PIN_NOGP_CFG(FSCLKST_N, "FSCLKST#", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(MLB_REF, "MLB_REF", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(PRESETOUT_N, "PRESETOUT#", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI0_IO2, "QSPI0_IO2", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI0_IO3, "QSPI0_IO3", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI0_MISO_IO1, "QSPI0_MISO_IO1", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI0_MOSI_IO0, "QSPI0_MOSI_IO0", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI0_SPCLK, "QSPI0_SPCLK", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI0_SSL, "QSPI0_SSL", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI1_IO2, "QSPI1_IO2", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI1_IO3, "QSPI1_IO3", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI1_MISO_IO1, "QSPI1_MISO_IO1", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI1_MOSI_IO0, "QSPI1_MOSI_IO0", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI1_SPCLK, "QSPI1_SPCLK", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI1_SSL, "QSPI1_SSL", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(RPC_INT_N, "RPC_INT#", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(RPC_RESET_N, "RPC_RESET#", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(RPC_WP_N, "RPC_WP#", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(TCK, "TCK", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \
+ PIN_NOGP_CFG(TDI, "TDI", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \
+ PIN_NOGP_CFG(TDO, "TDO", fn, SH_PFC_PIN_CFG_DRIVE_STRENGTH), \
+ PIN_NOGP_CFG(TMS, "TMS", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(TRST_N, "TRST#", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN)
+
/*
* F_() : just information
* FM() : macro for FN_xxx / xxx_MARK
@@ -1447,69 +1492,16 @@ static const u16 pinmux_data[] = {
};
/*
- * R8A7795 has 8 banks with 32 GPIOs in each => 256 GPIOs.
- * Physical layout rows: A - AW, cols: 1 - 39.
+ * Pins not associated with a GPIO port.
*/
-#define ROW_GROUP_A(r) ('Z' - 'A' + 1 + (r))
-#define PIN_NUMBER(r, c) (((r) - 'A') * 39 + (c) + 300)
-#define PIN_A_NUMBER(r, c) PIN_NUMBER(ROW_GROUP_A(r), c)
-#define PIN_NONE U16_MAX
+enum {
+ GP_ASSIGN_LAST(),
+ NOGP_ALL(),
+};
static const struct sh_pfc_pin pinmux_pins[] = {
PINMUX_GPIO_GP_ALL(),
-
- /*
- * Pins not associated with a GPIO port.
- *
- * The pin positions are different between different r8a7795
- * packages, all that is needed for the pfc driver is a unique
- * number for each pin. To this end use the pin layout from
- * R-Car H3SiP to calculate a unique number for each pin.
- */
- SH_PFC_PIN_NAMED_CFG('A', 8, AVB_TX_CTL, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 9, AVB_MDIO, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 12, AVB_TXCREFCLK, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 13, AVB_RD0, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 14, AVB_RD2, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 16, AVB_RX_CTL, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 17, AVB_TD2, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 18, AVB_TD0, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 19, AVB_TXC, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('B', 13, AVB_RD1, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('B', 14, AVB_RD3, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('B', 17, AVB_TD3, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('B', 18, AVB_TD1, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('B', 19, AVB_RXC, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('C', 1, PRESETOUT#, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('F', 1, CLKOUT, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('H', 37, MLB_REF, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('V', 3, QSPI1_SPCLK, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('V', 5, QSPI1_SSL, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('V', 6, RPC_WP#, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('V', 7, RPC_RESET#, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('W', 3, QSPI0_SPCLK, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('Y', 3, QSPI0_SSL, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('Y', 6, QSPI0_IO2, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('Y', 7, RPC_INT#, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'), 4, QSPI0_MISO_IO1, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'), 6, QSPI0_IO3, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 3, QSPI1_IO3, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 5, QSPI0_MOSI_IO0, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 7, QSPI1_MOSI_IO0, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 38, FSCLKST#, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 39, EXTALR, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'), 4, QSPI1_IO2, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'), 5, QSPI1_MISO_IO1, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'), 7, DU_DOTCLKIN0, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'), 8, DU_DOTCLKIN1, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 7, DU_DOTCLKIN2, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 8, DU_DOTCLKIN3, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 26, TRST#, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 29, TDI, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 30, TMS, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 27, TCK, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 28, TDO, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 30, ASEBRK, CFG_FLAGS),
+ PINMUX_NOGP_ALL(),
};
/* - AUDIO CLOCK ------------------------------------------------------------ */
@@ -1658,7 +1650,7 @@ static const unsigned int avb_phy_int_mux[] = {
};
static const unsigned int avb_mdio_pins[] = {
/* AVB_MDC, AVB_MDIO */
- RCAR_GP_PIN(2, 9), PIN_NUMBER('A', 9),
+ RCAR_GP_PIN(2, 9), PIN_AVB_MDIO,
};
static const unsigned int avb_mdio_mux[] = {
AVB_MDC_MARK, AVB_MDIO_MARK,
@@ -1671,11 +1663,11 @@ static const unsigned int avb_mii_pins[] = {
* AVB_RD1, AVB_RD2, AVB_RD3,
* AVB_TXCREFCLK
*/
- PIN_NUMBER('A', 8), PIN_NUMBER('A', 19), PIN_NUMBER('A', 18),
- PIN_NUMBER('B', 18), PIN_NUMBER('A', 17), PIN_NUMBER('B', 17),
- PIN_NUMBER('A', 16), PIN_NUMBER('B', 19), PIN_NUMBER('A', 13),
- PIN_NUMBER('B', 13), PIN_NUMBER('A', 14), PIN_NUMBER('B', 14),
- PIN_NUMBER('A', 12),
+ PIN_AVB_TX_CTL, PIN_AVB_TXC, PIN_AVB_TD0,
+ PIN_AVB_TD1, PIN_AVB_TD2, PIN_AVB_TD3,
+ PIN_AVB_RX_CTL, PIN_AVB_RXC, PIN_AVB_RD0,
+ PIN_AVB_RD1, PIN_AVB_RD2, PIN_AVB_RD3,
+ PIN_AVB_TXCREFCLK,
};
static const unsigned int avb_mii_mux[] = {
@@ -3137,22 +3129,21 @@ static const unsigned int pwm6_b_mux[] = {
/* - QSPI0 ------------------------------------------------------------------ */
static const unsigned int qspi0_ctrl_pins[] = {
/* QSPI0_SPCLK, QSPI0_SSL */
- PIN_NUMBER('W', 3), PIN_NUMBER('Y', 3),
+ PIN_QSPI0_SPCLK, PIN_QSPI0_SSL,
};
static const unsigned int qspi0_ctrl_mux[] = {
QSPI0_SPCLK_MARK, QSPI0_SSL_MARK,
};
static const unsigned int qspi0_data2_pins[] = {
/* QSPI0_MOSI_IO0, QSPI0_MISO_IO1 */
- PIN_A_NUMBER('C', 5), PIN_A_NUMBER('B', 4),
+ PIN_QSPI0_MOSI_IO0, PIN_QSPI0_MISO_IO1,
};
static const unsigned int qspi0_data2_mux[] = {
QSPI0_MOSI_IO0_MARK, QSPI0_MISO_IO1_MARK,
};
static const unsigned int qspi0_data4_pins[] = {
/* QSPI0_MOSI_IO0, QSPI0_MISO_IO1, QSPI0_IO2, QSPI0_IO3 */
- PIN_A_NUMBER('C', 5), PIN_A_NUMBER('B', 4),
- PIN_NUMBER('Y', 6), PIN_A_NUMBER('B', 6),
+ PIN_QSPI0_MOSI_IO0, PIN_QSPI0_MISO_IO1, PIN_QSPI0_IO2, PIN_QSPI0_IO3,
};
static const unsigned int qspi0_data4_mux[] = {
QSPI0_MOSI_IO0_MARK, QSPI0_MISO_IO1_MARK,
@@ -3161,22 +3152,21 @@ static const unsigned int qspi0_data4_mux[] = {
/* - QSPI1 ------------------------------------------------------------------ */
static const unsigned int qspi1_ctrl_pins[] = {
/* QSPI1_SPCLK, QSPI1_SSL */
- PIN_NUMBER('V', 3), PIN_NUMBER('V', 5),
+ PIN_QSPI1_SPCLK, PIN_QSPI1_SSL,
};
static const unsigned int qspi1_ctrl_mux[] = {
QSPI1_SPCLK_MARK, QSPI1_SSL_MARK,
};
static const unsigned int qspi1_data2_pins[] = {
/* QSPI1_MOSI_IO0, QSPI1_MISO_IO1 */
- PIN_A_NUMBER('C', 7), PIN_A_NUMBER('E', 5),
+ PIN_QSPI1_MOSI_IO0, PIN_QSPI1_MISO_IO1,
};
static const unsigned int qspi1_data2_mux[] = {
QSPI1_MOSI_IO0_MARK, QSPI1_MISO_IO1_MARK,
};
static const unsigned int qspi1_data4_pins[] = {
/* QSPI1_MOSI_IO0, QSPI1_MISO_IO1, QSPI1_IO2, QSPI1_IO3 */
- PIN_A_NUMBER('C', 7), PIN_A_NUMBER('E', 5),
- PIN_A_NUMBER('E', 4), PIN_A_NUMBER('C', 3),
+ PIN_QSPI1_MOSI_IO0, PIN_QSPI1_MISO_IO1, PIN_QSPI1_IO2, PIN_QSPI1_IO3,
};
static const unsigned int qspi1_data4_mux[] = {
QSPI1_MOSI_IO0_MARK, QSPI1_MISO_IO1_MARK,
@@ -3812,6 +3802,36 @@ static const unsigned int tmu_tclk2_b_mux[] = {
TCLK2_B_MARK,
};
+/* - TPU ------------------------------------------------------------------- */
+static const unsigned int tpu_to0_pins[] = {
+ /* TPU0TO0 */
+ RCAR_GP_PIN(6, 28),
+};
+static const unsigned int tpu_to0_mux[] = {
+ TPU0TO0_MARK,
+};
+static const unsigned int tpu_to1_pins[] = {
+ /* TPU0TO1 */
+ RCAR_GP_PIN(6, 29),
+};
+static const unsigned int tpu_to1_mux[] = {
+ TPU0TO1_MARK,
+};
+static const unsigned int tpu_to2_pins[] = {
+ /* TPU0TO2 */
+ RCAR_GP_PIN(6, 30),
+};
+static const unsigned int tpu_to2_mux[] = {
+ TPU0TO2_MARK,
+};
+static const unsigned int tpu_to3_pins[] = {
+ /* TPU0TO3 */
+ RCAR_GP_PIN(6, 31),
+};
+static const unsigned int tpu_to3_mux[] = {
+ TPU0TO3_MARK,
+};
+
/* - USB0 ------------------------------------------------------------------- */
static const unsigned int usb0_pins[] = {
/* PWEN, OVC */
@@ -4165,6 +4185,10 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(tmu_tclk1_b),
SH_PFC_PIN_GROUP(tmu_tclk2_a),
SH_PFC_PIN_GROUP(tmu_tclk2_b),
+ SH_PFC_PIN_GROUP(tpu_to0),
+ SH_PFC_PIN_GROUP(tpu_to1),
+ SH_PFC_PIN_GROUP(tpu_to2),
+ SH_PFC_PIN_GROUP(tpu_to3),
SH_PFC_PIN_GROUP(usb0),
SH_PFC_PIN_GROUP(usb1),
SH_PFC_PIN_GROUP(usb2),
@@ -4635,6 +4659,13 @@ static const char * const tmu_groups[] = {
"tmu_tclk2_b",
};
+static const char * const tpu_groups[] = {
+ "tpu_to0",
+ "tpu_to1",
+ "tpu_to2",
+ "tpu_to3",
+};
+
static const char * const usb0_groups[] = {
"usb0",
};
@@ -4707,6 +4738,7 @@ static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(sdhi3),
SH_PFC_FUNCTION(ssi),
SH_PFC_FUNCTION(tmu),
+ SH_PFC_FUNCTION(tpu),
SH_PFC_FUNCTION(usb0),
SH_PFC_FUNCTION(usb1),
SH_PFC_FUNCTION(usb2),
@@ -5272,44 +5304,44 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
static const struct pinmux_drive_reg pinmux_drive_regs[] = {
{ PINMUX_DRIVE_REG("DRVCTRL0", 0xe6060300) {
- { PIN_NUMBER('W', 3), 28, 2 }, /* QSPI0_SPCLK */
- { PIN_A_NUMBER('C', 5), 24, 2 }, /* QSPI0_MOSI_IO0 */
- { PIN_A_NUMBER('B', 4), 20, 2 }, /* QSPI0_MISO_IO1 */
- { PIN_NUMBER('Y', 6), 16, 2 }, /* QSPI0_IO2 */
- { PIN_A_NUMBER('B', 6), 12, 2 }, /* QSPI0_IO3 */
- { PIN_NUMBER('Y', 3), 8, 2 }, /* QSPI0_SSL */
- { PIN_NUMBER('V', 3), 4, 2 }, /* QSPI1_SPCLK */
- { PIN_A_NUMBER('C', 7), 0, 2 }, /* QSPI1_MOSI_IO0 */
+ { PIN_QSPI0_SPCLK, 28, 2 }, /* QSPI0_SPCLK */
+ { PIN_QSPI0_MOSI_IO0, 24, 2 }, /* QSPI0_MOSI_IO0 */
+ { PIN_QSPI0_MISO_IO1, 20, 2 }, /* QSPI0_MISO_IO1 */
+ { PIN_QSPI0_IO2, 16, 2 }, /* QSPI0_IO2 */
+ { PIN_QSPI0_IO3, 12, 2 }, /* QSPI0_IO3 */
+ { PIN_QSPI0_SSL, 8, 2 }, /* QSPI0_SSL */
+ { PIN_QSPI1_SPCLK, 4, 2 }, /* QSPI1_SPCLK */
+ { PIN_QSPI1_MOSI_IO0, 0, 2 }, /* QSPI1_MOSI_IO0 */
} },
{ PINMUX_DRIVE_REG("DRVCTRL1", 0xe6060304) {
- { PIN_A_NUMBER('E', 5), 28, 2 }, /* QSPI1_MISO_IO1 */
- { PIN_A_NUMBER('E', 4), 24, 2 }, /* QSPI1_IO2 */
- { PIN_A_NUMBER('C', 3), 20, 2 }, /* QSPI1_IO3 */
- { PIN_NUMBER('V', 5), 16, 2 }, /* QSPI1_SSL */
- { PIN_NUMBER('Y', 7), 12, 2 }, /* RPC_INT# */
- { PIN_NUMBER('V', 6), 8, 2 }, /* RPC_WP# */
- { PIN_NUMBER('V', 7), 4, 2 }, /* RPC_RESET# */
- { PIN_NUMBER('A', 16), 0, 3 }, /* AVB_RX_CTL */
+ { PIN_QSPI1_MISO_IO1, 28, 2 }, /* QSPI1_MISO_IO1 */
+ { PIN_QSPI1_IO2, 24, 2 }, /* QSPI1_IO2 */
+ { PIN_QSPI1_IO3, 20, 2 }, /* QSPI1_IO3 */
+ { PIN_QSPI1_SSL, 16, 2 }, /* QSPI1_SSL */
+ { PIN_RPC_INT_N, 12, 2 }, /* RPC_INT# */
+ { PIN_RPC_WP_N, 8, 2 }, /* RPC_WP# */
+ { PIN_RPC_RESET_N, 4, 2 }, /* RPC_RESET# */
+ { PIN_AVB_RX_CTL, 0, 3 }, /* AVB_RX_CTL */
} },
{ PINMUX_DRIVE_REG("DRVCTRL2", 0xe6060308) {
- { PIN_NUMBER('B', 19), 28, 3 }, /* AVB_RXC */
- { PIN_NUMBER('A', 13), 24, 3 }, /* AVB_RD0 */
- { PIN_NUMBER('B', 13), 20, 3 }, /* AVB_RD1 */
- { PIN_NUMBER('A', 14), 16, 3 }, /* AVB_RD2 */
- { PIN_NUMBER('B', 14), 12, 3 }, /* AVB_RD3 */
- { PIN_NUMBER('A', 8), 8, 3 }, /* AVB_TX_CTL */
- { PIN_NUMBER('A', 19), 4, 3 }, /* AVB_TXC */
- { PIN_NUMBER('A', 18), 0, 3 }, /* AVB_TD0 */
+ { PIN_AVB_RXC, 28, 3 }, /* AVB_RXC */
+ { PIN_AVB_RD0, 24, 3 }, /* AVB_RD0 */
+ { PIN_AVB_RD1, 20, 3 }, /* AVB_RD1 */
+ { PIN_AVB_RD2, 16, 3 }, /* AVB_RD2 */
+ { PIN_AVB_RD3, 12, 3 }, /* AVB_RD3 */
+ { PIN_AVB_TX_CTL, 8, 3 }, /* AVB_TX_CTL */
+ { PIN_AVB_TXC, 4, 3 }, /* AVB_TXC */
+ { PIN_AVB_TD0, 0, 3 }, /* AVB_TD0 */
} },
{ PINMUX_DRIVE_REG("DRVCTRL3", 0xe606030c) {
- { PIN_NUMBER('B', 18), 28, 3 }, /* AVB_TD1 */
- { PIN_NUMBER('A', 17), 24, 3 }, /* AVB_TD2 */
- { PIN_NUMBER('B', 17), 20, 3 }, /* AVB_TD3 */
- { PIN_NUMBER('A', 12), 16, 3 }, /* AVB_TXCREFCLK */
- { PIN_NUMBER('A', 9), 12, 3 }, /* AVB_MDIO */
- { RCAR_GP_PIN(2, 9), 8, 3 }, /* AVB_MDC */
- { RCAR_GP_PIN(2, 10), 4, 3 }, /* AVB_MAGIC */
- { RCAR_GP_PIN(2, 11), 0, 3 }, /* AVB_PHY_INT */
+ { PIN_AVB_TD1, 28, 3 }, /* AVB_TD1 */
+ { PIN_AVB_TD2, 24, 3 }, /* AVB_TD2 */
+ { PIN_AVB_TD3, 20, 3 }, /* AVB_TD3 */
+ { PIN_AVB_TXCREFCLK, 16, 3 }, /* AVB_TXCREFCLK */
+ { PIN_AVB_MDIO, 12, 3 }, /* AVB_MDIO */
+ { RCAR_GP_PIN(2, 9), 8, 3 }, /* AVB_MDC */
+ { RCAR_GP_PIN(2, 10), 4, 3 }, /* AVB_MAGIC */
+ { RCAR_GP_PIN(2, 11), 0, 3 }, /* AVB_PHY_INT */
} },
{ PINMUX_DRIVE_REG("DRVCTRL4", 0xe6060310) {
{ RCAR_GP_PIN(2, 12), 28, 3 }, /* AVB_LINK */
@@ -5352,7 +5384,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = {
{ RCAR_GP_PIN(1, 19), 0, 3 }, /* A19 */
} },
{ PINMUX_DRIVE_REG("DRVCTRL8", 0xe6060320) {
- { PIN_NUMBER('F', 1), 28, 3 }, /* CLKOUT */
+ { PIN_CLKOUT, 28, 3 }, /* CLKOUT */
{ RCAR_GP_PIN(1, 20), 24, 3 }, /* CS0 */
{ RCAR_GP_PIN(1, 21), 20, 3 }, /* CS1_A26 */
{ RCAR_GP_PIN(1, 22), 16, 3 }, /* BS */
@@ -5363,7 +5395,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = {
} },
{ PINMUX_DRIVE_REG("DRVCTRL9", 0xe6060324) {
{ RCAR_GP_PIN(1, 27), 28, 3 }, /* EX_WAIT0 */
- { PIN_NUMBER('C', 1), 24, 3 }, /* PRESETOUT# */
+ { PIN_PRESETOUT_N, 24, 3 }, /* PRESETOUT# */
{ RCAR_GP_PIN(0, 0), 20, 3 }, /* D0 */
{ RCAR_GP_PIN(0, 1), 16, 3 }, /* D1 */
{ RCAR_GP_PIN(0, 2), 12, 3 }, /* D2 */
@@ -5382,30 +5414,30 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = {
{ RCAR_GP_PIN(0, 13), 0, 3 }, /* D13 */
} },
{ PINMUX_DRIVE_REG("DRVCTRL11", 0xe606032c) {
- { RCAR_GP_PIN(0, 14), 28, 3 }, /* D14 */
- { RCAR_GP_PIN(0, 15), 24, 3 }, /* D15 */
- { RCAR_GP_PIN(7, 0), 20, 3 }, /* AVS1 */
- { RCAR_GP_PIN(7, 1), 16, 3 }, /* AVS2 */
- { RCAR_GP_PIN(7, 2), 12, 3 }, /* GP7_02 */
- { RCAR_GP_PIN(7, 3), 8, 3 }, /* GP7_03 */
- { PIN_A_NUMBER('P', 7), 4, 2 }, /* DU_DOTCLKIN0 */
- { PIN_A_NUMBER('P', 8), 0, 2 }, /* DU_DOTCLKIN1 */
+ { RCAR_GP_PIN(0, 14), 28, 3 }, /* D14 */
+ { RCAR_GP_PIN(0, 15), 24, 3 }, /* D15 */
+ { RCAR_GP_PIN(7, 0), 20, 3 }, /* AVS1 */
+ { RCAR_GP_PIN(7, 1), 16, 3 }, /* AVS2 */
+ { RCAR_GP_PIN(7, 2), 12, 3 }, /* GP7_02 */
+ { RCAR_GP_PIN(7, 3), 8, 3 }, /* GP7_03 */
+ { PIN_DU_DOTCLKIN0, 4, 2 }, /* DU_DOTCLKIN0 */
+ { PIN_DU_DOTCLKIN1, 0, 2 }, /* DU_DOTCLKIN1 */
} },
{ PINMUX_DRIVE_REG("DRVCTRL12", 0xe6060330) {
- { PIN_A_NUMBER('R', 7), 28, 2 }, /* DU_DOTCLKIN2 */
- { PIN_A_NUMBER('R', 8), 24, 2 }, /* DU_DOTCLKIN3 */
- { PIN_A_NUMBER('D', 38), 20, 2 }, /* FSCLKST# */
- { PIN_A_NUMBER('R', 30), 4, 2 }, /* TMS */
+ { PIN_DU_DOTCLKIN2, 28, 2 }, /* DU_DOTCLKIN2 */
+ { PIN_DU_DOTCLKIN3, 24, 2 }, /* DU_DOTCLKIN3 */
+ { PIN_FSCLKST_N, 20, 2 }, /* FSCLKST# */
+ { PIN_TMS, 4, 2 }, /* TMS */
} },
{ PINMUX_DRIVE_REG("DRVCTRL13", 0xe6060334) {
- { PIN_A_NUMBER('T', 28), 28, 2 }, /* TDO */
- { PIN_A_NUMBER('T', 30), 24, 2 }, /* ASEBRK */
- { RCAR_GP_PIN(3, 0), 20, 3 }, /* SD0_CLK */
- { RCAR_GP_PIN(3, 1), 16, 3 }, /* SD0_CMD */
- { RCAR_GP_PIN(3, 2), 12, 3 }, /* SD0_DAT0 */
- { RCAR_GP_PIN(3, 3), 8, 3 }, /* SD0_DAT1 */
- { RCAR_GP_PIN(3, 4), 4, 3 }, /* SD0_DAT2 */
- { RCAR_GP_PIN(3, 5), 0, 3 }, /* SD0_DAT3 */
+ { PIN_TDO, 28, 2 }, /* TDO */
+ { PIN_ASEBRK, 24, 2 }, /* ASEBRK */
+ { RCAR_GP_PIN(3, 0), 20, 3 }, /* SD0_CLK */
+ { RCAR_GP_PIN(3, 1), 16, 3 }, /* SD0_CMD */
+ { RCAR_GP_PIN(3, 2), 12, 3 }, /* SD0_DAT0 */
+ { RCAR_GP_PIN(3, 3), 8, 3 }, /* SD0_DAT1 */
+ { RCAR_GP_PIN(3, 4), 4, 3 }, /* SD0_DAT2 */
+ { RCAR_GP_PIN(3, 5), 0, 3 }, /* SD0_DAT3 */
} },
{ PINMUX_DRIVE_REG("DRVCTRL14", 0xe6060338) {
{ RCAR_GP_PIN(3, 6), 28, 3 }, /* SD1_CLK */
@@ -5474,7 +5506,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = {
{ RCAR_GP_PIN(5, 23), 16, 3 }, /* MLB_CLK */
{ RCAR_GP_PIN(5, 24), 12, 3 }, /* MLB_SIG */
{ RCAR_GP_PIN(5, 25), 8, 3 }, /* MLB_DAT */
- { PIN_NUMBER('H', 37), 4, 3 }, /* MLB_REF */
+ { PIN_MLB_REF, 4, 3 }, /* MLB_REF */
{ RCAR_GP_PIN(6, 0), 0, 3 }, /* SSI_SCK01239 */
} },
{ PINMUX_DRIVE_REG("DRVCTRL21", 0xe6060354) {
@@ -5548,35 +5580,35 @@ static int r8a7795es1_pin_to_pocctrl(struct sh_pfc *pfc, unsigned int pin,
static const struct pinmux_bias_reg pinmux_bias_regs[] = {
{ PINMUX_BIAS_REG("PUEN0", 0xe6060400, "PUD0", 0xe6060440) {
- [ 0] = PIN_NUMBER('W', 3), /* QSPI0_SPCLK */
- [ 1] = PIN_A_NUMBER('C', 5), /* QSPI0_MOSI_IO0 */
- [ 2] = PIN_A_NUMBER('B', 4), /* QSPI0_MISO_IO1 */
- [ 3] = PIN_NUMBER('Y', 6), /* QSPI0_IO2 */
- [ 4] = PIN_A_NUMBER('B', 6), /* QSPI0_IO3 */
- [ 5] = PIN_NUMBER('Y', 3), /* QSPI0_SSL */
- [ 6] = PIN_NUMBER('V', 3), /* QSPI1_SPCLK */
- [ 7] = PIN_A_NUMBER('C', 7), /* QSPI1_MOSI_IO0 */
- [ 8] = PIN_A_NUMBER('E', 5), /* QSPI1_MISO_IO1 */
- [ 9] = PIN_A_NUMBER('E', 4), /* QSPI1_IO2 */
- [10] = PIN_A_NUMBER('C', 3), /* QSPI1_IO3 */
- [11] = PIN_NUMBER('V', 5), /* QSPI1_SSL */
- [12] = PIN_NUMBER('Y', 7), /* RPC_INT# */
- [13] = PIN_NUMBER('V', 6), /* RPC_WP# */
- [14] = PIN_NUMBER('V', 7), /* RPC_RESET# */
- [15] = PIN_NUMBER('A', 16), /* AVB_RX_CTL */
- [16] = PIN_NUMBER('B', 19), /* AVB_RXC */
- [17] = PIN_NUMBER('A', 13), /* AVB_RD0 */
- [18] = PIN_NUMBER('B', 13), /* AVB_RD1 */
- [19] = PIN_NUMBER('A', 14), /* AVB_RD2 */
- [20] = PIN_NUMBER('B', 14), /* AVB_RD3 */
- [21] = PIN_NUMBER('A', 8), /* AVB_TX_CTL */
- [22] = PIN_NUMBER('A', 19), /* AVB_TXC */
- [23] = PIN_NUMBER('A', 18), /* AVB_TD0 */
- [24] = PIN_NUMBER('B', 18), /* AVB_TD1 */
- [25] = PIN_NUMBER('A', 17), /* AVB_TD2 */
- [26] = PIN_NUMBER('B', 17), /* AVB_TD3 */
- [27] = PIN_NUMBER('A', 12), /* AVB_TXCREFCLK */
- [28] = PIN_NUMBER('A', 9), /* AVB_MDIO */
+ [ 0] = PIN_QSPI0_SPCLK, /* QSPI0_SPCLK */
+ [ 1] = PIN_QSPI0_MOSI_IO0, /* QSPI0_MOSI_IO0 */
+ [ 2] = PIN_QSPI0_MISO_IO1, /* QSPI0_MISO_IO1 */
+ [ 3] = PIN_QSPI0_IO2, /* QSPI0_IO2 */
+ [ 4] = PIN_QSPI0_IO3, /* QSPI0_IO3 */
+ [ 5] = PIN_QSPI0_SSL, /* QSPI0_SSL */
+ [ 6] = PIN_QSPI1_SPCLK, /* QSPI1_SPCLK */
+ [ 7] = PIN_QSPI1_MOSI_IO0, /* QSPI1_MOSI_IO0 */
+ [ 8] = PIN_QSPI1_MISO_IO1, /* QSPI1_MISO_IO1 */
+ [ 9] = PIN_QSPI1_IO2, /* QSPI1_IO2 */
+ [10] = PIN_QSPI1_IO3, /* QSPI1_IO3 */
+ [11] = PIN_QSPI1_SSL, /* QSPI1_SSL */
+ [12] = PIN_RPC_INT_N, /* RPC_INT# */
+ [13] = PIN_RPC_WP_N, /* RPC_WP# */
+ [14] = PIN_RPC_RESET_N, /* RPC_RESET# */
+ [15] = PIN_AVB_RX_CTL, /* AVB_RX_CTL */
+ [16] = PIN_AVB_RXC, /* AVB_RXC */
+ [17] = PIN_AVB_RD0, /* AVB_RD0 */
+ [18] = PIN_AVB_RD1, /* AVB_RD1 */
+ [19] = PIN_AVB_RD2, /* AVB_RD2 */
+ [20] = PIN_AVB_RD3, /* AVB_RD3 */
+ [21] = PIN_AVB_TX_CTL, /* AVB_TX_CTL */
+ [22] = PIN_AVB_TXC, /* AVB_TXC */
+ [23] = PIN_AVB_TD0, /* AVB_TD0 */
+ [24] = PIN_AVB_TD1, /* AVB_TD1 */
+ [25] = PIN_AVB_TD2, /* AVB_TD2 */
+ [26] = PIN_AVB_TD3, /* AVB_TD3 */
+ [27] = PIN_AVB_TXCREFCLK, /* AVB_TXCREFCLK */
+ [28] = PIN_AVB_MDIO, /* AVB_MDIO */
[29] = RCAR_GP_PIN(2, 9), /* AVB_MDC */
[30] = RCAR_GP_PIN(2, 10), /* AVB_MAGIC */
[31] = RCAR_GP_PIN(2, 11), /* AVB_PHY_INT */
@@ -5616,7 +5648,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
[31] = RCAR_GP_PIN(1, 19), /* A19 */
} },
{ PINMUX_BIAS_REG("PUEN2", 0xe6060408, "PUD2", 0xe6060448) {
- [ 0] = PIN_NUMBER('F', 1), /* CLKOUT */
+ [ 0] = PIN_CLKOUT, /* CLKOUT */
[ 1] = RCAR_GP_PIN(1, 20), /* CS0_N */
[ 2] = RCAR_GP_PIN(1, 21), /* CS1_N_A26 */
[ 3] = RCAR_GP_PIN(1, 22), /* BS_N */
@@ -5625,7 +5657,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
[ 6] = RCAR_GP_PIN(1, 25), /* WE0_N */
[ 7] = RCAR_GP_PIN(1, 26), /* WE1_N */
[ 8] = RCAR_GP_PIN(1, 27), /* EX_WAIT0_A */
- [ 9] = PIN_NUMBER('C', 1), /* PRESETOUT# */
+ [ 9] = PIN_PRESETOUT_N, /* PRESETOUT# */
[10] = RCAR_GP_PIN(0, 0), /* D0 */
[11] = RCAR_GP_PIN(0, 1), /* D1 */
[12] = RCAR_GP_PIN(0, 2), /* D2 */
@@ -5646,20 +5678,20 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
[27] = RCAR_GP_PIN(7, 1), /* AVS2 */
[28] = RCAR_GP_PIN(7, 2), /* GP7_02 */
[29] = RCAR_GP_PIN(7, 3), /* GP7_03 */
- [30] = PIN_A_NUMBER('P', 7), /* DU_DOTCLKIN0 */
- [31] = PIN_A_NUMBER('P', 8), /* DU_DOTCLKIN1 */
+ [30] = PIN_DU_DOTCLKIN0, /* DU_DOTCLKIN0 */
+ [31] = PIN_DU_DOTCLKIN1, /* DU_DOTCLKIN1 */
} },
{ PINMUX_BIAS_REG("PUEN3", 0xe606040c, "PUD3", 0xe606044c) {
- [ 0] = PIN_A_NUMBER('R', 7), /* DU_DOTCLKIN2 */
- [ 1] = PIN_A_NUMBER('R', 8), /* DU_DOTCLKIN3 */
- [ 2] = PIN_A_NUMBER('D', 38), /* FSCLKST# */
- [ 3] = PIN_A_NUMBER('D', 39), /* EXTALR*/
- [ 4] = PIN_A_NUMBER('R', 26), /* TRST# */
- [ 5] = PIN_A_NUMBER('T', 27), /* TCK */
- [ 6] = PIN_A_NUMBER('R', 30), /* TMS */
- [ 7] = PIN_A_NUMBER('R', 29), /* TDI */
- [ 8] = PIN_NONE,
- [ 9] = PIN_A_NUMBER('T', 30), /* ASEBRK */
+ [ 0] = PIN_DU_DOTCLKIN2, /* DU_DOTCLKIN2 */
+ [ 1] = PIN_DU_DOTCLKIN3, /* DU_DOTCLKIN3 */
+ [ 2] = PIN_FSCLKST_N, /* FSCLKST# */
+ [ 3] = PIN_EXTALR, /* EXTALR*/
+ [ 4] = PIN_TRST_N, /* TRST# */
+ [ 5] = PIN_TCK, /* TCK */
+ [ 6] = PIN_TMS, /* TMS */
+ [ 7] = PIN_TDI, /* TDI */
+ [ 8] = SH_PFC_PIN_NONE,
+ [ 9] = PIN_ASEBRK, /* ASEBRK */
[10] = RCAR_GP_PIN(3, 0), /* SD0_CLK */
[11] = RCAR_GP_PIN(3, 1), /* SD0_CMD */
[12] = RCAR_GP_PIN(3, 2), /* SD0_DAT0 */
@@ -5724,7 +5756,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
[ 3] = RCAR_GP_PIN(5, 23), /* MLB_CLK */
[ 4] = RCAR_GP_PIN(5, 24), /* MLB_SIG */
[ 5] = RCAR_GP_PIN(5, 25), /* MLB_DAT */
- [ 6] = PIN_NUMBER('H', 37), /* MLB_REF */
+ [ 6] = PIN_MLB_REF, /* MLB_REF */
[ 7] = RCAR_GP_PIN(6, 0), /* SSI_SCK01239 */
[ 8] = RCAR_GP_PIN(6, 1), /* SSI_WS01239 */
[ 9] = RCAR_GP_PIN(6, 2), /* SSI_SDATA0 */
@@ -5759,31 +5791,31 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
[ 4] = RCAR_GP_PIN(6, 29), /* USB30_OVC */
[ 5] = RCAR_GP_PIN(6, 30), /* USB31_PWEN */
[ 6] = RCAR_GP_PIN(6, 31), /* USB31_OVC */
- [ 7] = PIN_NONE,
- [ 8] = PIN_NONE,
- [ 9] = PIN_NONE,
- [10] = PIN_NONE,
- [11] = PIN_NONE,
- [12] = PIN_NONE,
- [13] = PIN_NONE,
- [14] = PIN_NONE,
- [15] = PIN_NONE,
- [16] = PIN_NONE,
- [17] = PIN_NONE,
- [18] = PIN_NONE,
- [19] = PIN_NONE,
- [20] = PIN_NONE,
- [21] = PIN_NONE,
- [22] = PIN_NONE,
- [23] = PIN_NONE,
- [24] = PIN_NONE,
- [25] = PIN_NONE,
- [26] = PIN_NONE,
- [27] = PIN_NONE,
- [28] = PIN_NONE,
- [29] = PIN_NONE,
- [30] = PIN_NONE,
- [31] = PIN_NONE,
+ [ 7] = SH_PFC_PIN_NONE,
+ [ 8] = SH_PFC_PIN_NONE,
+ [ 9] = SH_PFC_PIN_NONE,
+ [10] = SH_PFC_PIN_NONE,
+ [11] = SH_PFC_PIN_NONE,
+ [12] = SH_PFC_PIN_NONE,
+ [13] = SH_PFC_PIN_NONE,
+ [14] = SH_PFC_PIN_NONE,
+ [15] = SH_PFC_PIN_NONE,
+ [16] = SH_PFC_PIN_NONE,
+ [17] = SH_PFC_PIN_NONE,
+ [18] = SH_PFC_PIN_NONE,
+ [19] = SH_PFC_PIN_NONE,
+ [20] = SH_PFC_PIN_NONE,
+ [21] = SH_PFC_PIN_NONE,
+ [22] = SH_PFC_PIN_NONE,
+ [23] = SH_PFC_PIN_NONE,
+ [24] = SH_PFC_PIN_NONE,
+ [25] = SH_PFC_PIN_NONE,
+ [26] = SH_PFC_PIN_NONE,
+ [27] = SH_PFC_PIN_NONE,
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
} },
{ /* sentinel */ },
};
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7795.c b/drivers/pinctrl/sh-pfc/pfc-r8a7795.c
index 68bcb8980b16..7df010f757b1 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7795.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7795.c
@@ -12,11 +12,9 @@
#include "core.h"
#include "sh_pfc.h"
-#define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | \
- SH_PFC_PIN_CFG_PULL_UP | \
- SH_PFC_PIN_CFG_PULL_DOWN)
+#define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | SH_PFC_PIN_CFG_PULL_UP_DOWN)
-#define CPU_ALL_PORT(fn, sfx) \
+#define CPU_ALL_GP(fn, sfx) \
PORT_GP_CFG_16(0, fn, sfx, CFG_FLAGS), \
PORT_GP_CFG_29(1, fn, sfx, CFG_FLAGS), \
PORT_GP_CFG_15(2, fn, sfx, CFG_FLAGS), \
@@ -29,6 +27,52 @@
PORT_GP_CFG_26(5, fn, sfx, CFG_FLAGS), \
PORT_GP_CFG_32(6, fn, sfx, CFG_FLAGS), \
PORT_GP_CFG_4(7, fn, sfx, CFG_FLAGS)
+
+#define CPU_ALL_NOGP(fn) \
+ PIN_NOGP_CFG(ASEBRK, "ASEBRK", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_MDIO, "AVB_MDIO", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_RD0, "AVB_RD0", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_RD1, "AVB_RD1", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_RD2, "AVB_RD2", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_RD3, "AVB_RD3", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_RXC, "AVB_RXC", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_RX_CTL, "AVB_RX_CTL", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TD0, "AVB_TD0", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TD1, "AVB_TD1", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TD2, "AVB_TD2", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TD3, "AVB_TD3", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TXC, "AVB_TXC", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TXCREFCLK, "AVB_TXCREFCLK", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TX_CTL, "AVB_TX_CTL", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(DU_DOTCLKIN0, "DU_DOTCLKIN0", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(DU_DOTCLKIN1, "DU_DOTCLKIN1", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(DU_DOTCLKIN2, "DU_DOTCLKIN2", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(DU_DOTCLKIN3, "DU_DOTCLKIN3", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(EXTALR, "EXTALR", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN),\
+ PIN_NOGP_CFG(FSCLKST_N, "FSCLKST#", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(MLB_REF, "MLB_REF", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(PRESETOUT_N, "PRESETOUT#", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI0_IO2, "QSPI0_IO2", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI0_IO3, "QSPI0_IO3", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI0_MISO_IO1, "QSPI0_MISO_IO1", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI0_MOSI_IO0, "QSPI0_MOSI_IO0", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI0_SPCLK, "QSPI0_SPCLK", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI0_SSL, "QSPI0_SSL", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI1_IO2, "QSPI1_IO2", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI1_IO3, "QSPI1_IO3", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI1_MISO_IO1, "QSPI1_MISO_IO1", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI1_MOSI_IO0, "QSPI1_MOSI_IO0", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI1_SPCLK, "QSPI1_SPCLK", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI1_SSL, "QSPI1_SSL", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(RPC_INT_N, "RPC_INT#", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(RPC_RESET_N, "RPC_RESET#", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(RPC_WP_N, "RPC_WP#", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(TCK, "TCK", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \
+ PIN_NOGP_CFG(TDI, "TDI", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \
+ PIN_NOGP_CFG(TDO, "TDO", fn, SH_PFC_PIN_CFG_DRIVE_STRENGTH), \
+ PIN_NOGP_CFG(TMS, "TMS", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(TRST_N, "TRST#", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN)
+
/*
* F_() : just information
* FM() : macro for FN_xxx / xxx_MARK
@@ -1508,68 +1552,16 @@ static const u16 pinmux_data[] = {
};
/*
- * R8A7795 has 8 banks with 32 GPIOs in each => 256 GPIOs.
- * Physical layout rows: A - AW, cols: 1 - 39.
+ * Pins not associated with a GPIO port.
*/
-#define ROW_GROUP_A(r) ('Z' - 'A' + 1 + (r))
-#define PIN_NUMBER(r, c) (((r) - 'A') * 39 + (c) + 300)
-#define PIN_A_NUMBER(r, c) PIN_NUMBER(ROW_GROUP_A(r), c)
-#define PIN_NONE U16_MAX
+enum {
+ GP_ASSIGN_LAST(),
+ NOGP_ALL(),
+};
static const struct sh_pfc_pin pinmux_pins[] = {
PINMUX_GPIO_GP_ALL(),
-
- /*
- * Pins not associated with a GPIO port.
- *
- * The pin positions are different between different r8a7795
- * packages, all that is needed for the pfc driver is a unique
- * number for each pin. To this end use the pin layout from
- * R-Car H3SiP to calculate a unique number for each pin.
- */
- SH_PFC_PIN_NAMED_CFG('A', 8, AVB_TX_CTL, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 9, AVB_MDIO, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 12, AVB_TXCREFCLK, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 13, AVB_RD0, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 14, AVB_RD2, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 16, AVB_RX_CTL, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 17, AVB_TD2, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 18, AVB_TD0, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 19, AVB_TXC, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('B', 13, AVB_RD1, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('B', 14, AVB_RD3, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('B', 17, AVB_TD3, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('B', 18, AVB_TD1, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('B', 19, AVB_RXC, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('C', 1, PRESETOUT#, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('H', 37, MLB_REF, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('V', 3, QSPI1_SPCLK, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('V', 5, QSPI1_SSL, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('V', 6, RPC_WP#, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('V', 7, RPC_RESET#, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('W', 3, QSPI0_SPCLK, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('Y', 3, QSPI0_SSL, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('Y', 6, QSPI0_IO2, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('Y', 7, RPC_INT#, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'), 4, QSPI0_MISO_IO1, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'), 6, QSPI0_IO3, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 3, QSPI1_IO3, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 5, QSPI0_MOSI_IO0, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 7, QSPI1_MOSI_IO0, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 38, FSCLKST#, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 39, EXTALR, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'), 4, QSPI1_IO2, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'), 5, QSPI1_MISO_IO1, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'), 7, DU_DOTCLKIN0, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'), 8, DU_DOTCLKIN1, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 7, DU_DOTCLKIN2, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 8, DU_DOTCLKIN3, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 26, TRST#, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 29, TDI, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 30, TMS, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 27, TCK, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 28, TDO, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 30, ASEBRK, CFG_FLAGS),
+ PINMUX_NOGP_ALL(),
};
/* - AUDIO CLOCK ------------------------------------------------------------ */
@@ -1717,7 +1709,7 @@ static const unsigned int avb_phy_int_mux[] = {
};
static const unsigned int avb_mdio_pins[] = {
/* AVB_MDC, AVB_MDIO */
- RCAR_GP_PIN(2, 9), PIN_NUMBER('A', 9),
+ RCAR_GP_PIN(2, 9), PIN_AVB_MDIO,
};
static const unsigned int avb_mdio_mux[] = {
AVB_MDC_MARK, AVB_MDIO_MARK,
@@ -1730,11 +1722,11 @@ static const unsigned int avb_mii_pins[] = {
* AVB_RD1, AVB_RD2, AVB_RD3,
* AVB_TXCREFCLK
*/
- PIN_NUMBER('A', 8), PIN_NUMBER('A', 19), PIN_NUMBER('A', 18),
- PIN_NUMBER('B', 18), PIN_NUMBER('A', 17), PIN_NUMBER('B', 17),
- PIN_NUMBER('A', 16), PIN_NUMBER('B', 19), PIN_NUMBER('A', 13),
- PIN_NUMBER('B', 13), PIN_NUMBER('A', 14), PIN_NUMBER('B', 14),
- PIN_NUMBER('A', 12),
+ PIN_AVB_TX_CTL, PIN_AVB_TXC, PIN_AVB_TD0,
+ PIN_AVB_TD1, PIN_AVB_TD2, PIN_AVB_TD3,
+ PIN_AVB_RX_CTL, PIN_AVB_RXC, PIN_AVB_RD0,
+ PIN_AVB_RD1, PIN_AVB_RD2, PIN_AVB_RD3,
+ PIN_AVB_TXCREFCLK,
};
static const unsigned int avb_mii_mux[] = {
@@ -3901,6 +3893,36 @@ static const unsigned int tmu_tclk2_b_mux[] = {
TCLK2_B_MARK,
};
+/* - TPU ------------------------------------------------------------------- */
+static const unsigned int tpu_to0_pins[] = {
+ /* TPU0TO0 */
+ RCAR_GP_PIN(6, 28),
+};
+static const unsigned int tpu_to0_mux[] = {
+ TPU0TO0_MARK,
+};
+static const unsigned int tpu_to1_pins[] = {
+ /* TPU0TO1 */
+ RCAR_GP_PIN(6, 29),
+};
+static const unsigned int tpu_to1_mux[] = {
+ TPU0TO1_MARK,
+};
+static const unsigned int tpu_to2_pins[] = {
+ /* TPU0TO2 */
+ RCAR_GP_PIN(6, 30),
+};
+static const unsigned int tpu_to2_mux[] = {
+ TPU0TO2_MARK,
+};
+static const unsigned int tpu_to3_pins[] = {
+ /* TPU0TO3 */
+ RCAR_GP_PIN(6, 31),
+};
+static const unsigned int tpu_to3_mux[] = {
+ TPU0TO3_MARK,
+};
+
/* - USB0 ------------------------------------------------------------------- */
static const unsigned int usb0_pins[] = {
/* PWEN, OVC */
@@ -4451,6 +4473,10 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(tmu_tclk1_b),
SH_PFC_PIN_GROUP(tmu_tclk2_a),
SH_PFC_PIN_GROUP(tmu_tclk2_b),
+ SH_PFC_PIN_GROUP(tpu_to0),
+ SH_PFC_PIN_GROUP(tpu_to1),
+ SH_PFC_PIN_GROUP(tpu_to2),
+ SH_PFC_PIN_GROUP(tpu_to3),
SH_PFC_PIN_GROUP(usb0),
SH_PFC_PIN_GROUP(usb1),
SH_PFC_PIN_GROUP(usb2),
@@ -4946,6 +4972,13 @@ static const char * const tmu_groups[] = {
"tmu_tclk2_b",
};
+static const char * const tpu_groups[] = {
+ "tpu_to0",
+ "tpu_to1",
+ "tpu_to2",
+ "tpu_to3",
+};
+
static const char * const usb0_groups[] = {
"usb0",
};
@@ -5048,6 +5081,7 @@ static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(sdhi3),
SH_PFC_FUNCTION(ssi),
SH_PFC_FUNCTION(tmu),
+ SH_PFC_FUNCTION(tpu),
SH_PFC_FUNCTION(usb0),
SH_PFC_FUNCTION(usb1),
SH_PFC_FUNCTION(usb2),
@@ -5623,44 +5657,44 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
static const struct pinmux_drive_reg pinmux_drive_regs[] = {
{ PINMUX_DRIVE_REG("DRVCTRL0", 0xe6060300) {
- { PIN_NUMBER('W', 3), 28, 2 }, /* QSPI0_SPCLK */
- { PIN_A_NUMBER('C', 5), 24, 2 }, /* QSPI0_MOSI_IO0 */
- { PIN_A_NUMBER('B', 4), 20, 2 }, /* QSPI0_MISO_IO1 */
- { PIN_NUMBER('Y', 6), 16, 2 }, /* QSPI0_IO2 */
- { PIN_A_NUMBER('B', 6), 12, 2 }, /* QSPI0_IO3 */
- { PIN_NUMBER('Y', 3), 8, 2 }, /* QSPI0_SSL */
- { PIN_NUMBER('V', 3), 4, 2 }, /* QSPI1_SPCLK */
- { PIN_A_NUMBER('C', 7), 0, 2 }, /* QSPI1_MOSI_IO0 */
+ { PIN_QSPI0_SPCLK, 28, 2 }, /* QSPI0_SPCLK */
+ { PIN_QSPI0_MOSI_IO0, 24, 2 }, /* QSPI0_MOSI_IO0 */
+ { PIN_QSPI0_MISO_IO1, 20, 2 }, /* QSPI0_MISO_IO1 */
+ { PIN_QSPI0_IO2, 16, 2 }, /* QSPI0_IO2 */
+ { PIN_QSPI0_IO3, 12, 2 }, /* QSPI0_IO3 */
+ { PIN_QSPI0_SSL, 8, 2 }, /* QSPI0_SSL */
+ { PIN_QSPI1_SPCLK, 4, 2 }, /* QSPI1_SPCLK */
+ { PIN_QSPI1_MOSI_IO0, 0, 2 }, /* QSPI1_MOSI_IO0 */
} },
{ PINMUX_DRIVE_REG("DRVCTRL1", 0xe6060304) {
- { PIN_A_NUMBER('E', 5), 28, 2 }, /* QSPI1_MISO_IO1 */
- { PIN_A_NUMBER('E', 4), 24, 2 }, /* QSPI1_IO2 */
- { PIN_A_NUMBER('C', 3), 20, 2 }, /* QSPI1_IO3 */
- { PIN_NUMBER('V', 5), 16, 2 }, /* QSPI1_SSL */
- { PIN_NUMBER('Y', 7), 12, 2 }, /* RPC_INT# */
- { PIN_NUMBER('V', 6), 8, 2 }, /* RPC_WP# */
- { PIN_NUMBER('V', 7), 4, 2 }, /* RPC_RESET# */
- { PIN_NUMBER('A', 16), 0, 3 }, /* AVB_RX_CTL */
+ { PIN_QSPI1_MISO_IO1, 28, 2 }, /* QSPI1_MISO_IO1 */
+ { PIN_QSPI1_IO2, 24, 2 }, /* QSPI1_IO2 */
+ { PIN_QSPI1_IO3, 20, 2 }, /* QSPI1_IO3 */
+ { PIN_QSPI1_SSL, 16, 2 }, /* QSPI1_SSL */
+ { PIN_RPC_INT_N, 12, 2 }, /* RPC_INT# */
+ { PIN_RPC_WP_N, 8, 2 }, /* RPC_WP# */
+ { PIN_RPC_RESET_N, 4, 2 }, /* RPC_RESET# */
+ { PIN_AVB_RX_CTL, 0, 3 }, /* AVB_RX_CTL */
} },
{ PINMUX_DRIVE_REG("DRVCTRL2", 0xe6060308) {
- { PIN_NUMBER('B', 19), 28, 3 }, /* AVB_RXC */
- { PIN_NUMBER('A', 13), 24, 3 }, /* AVB_RD0 */
- { PIN_NUMBER('B', 13), 20, 3 }, /* AVB_RD1 */
- { PIN_NUMBER('A', 14), 16, 3 }, /* AVB_RD2 */
- { PIN_NUMBER('B', 14), 12, 3 }, /* AVB_RD3 */
- { PIN_NUMBER('A', 8), 8, 3 }, /* AVB_TX_CTL */
- { PIN_NUMBER('A', 19), 4, 3 }, /* AVB_TXC */
- { PIN_NUMBER('A', 18), 0, 3 }, /* AVB_TD0 */
+ { PIN_AVB_RXC, 28, 3 }, /* AVB_RXC */
+ { PIN_AVB_RD0, 24, 3 }, /* AVB_RD0 */
+ { PIN_AVB_RD1, 20, 3 }, /* AVB_RD1 */
+ { PIN_AVB_RD2, 16, 3 }, /* AVB_RD2 */
+ { PIN_AVB_RD3, 12, 3 }, /* AVB_RD3 */
+ { PIN_AVB_TX_CTL, 8, 3 }, /* AVB_TX_CTL */
+ { PIN_AVB_TXC, 4, 3 }, /* AVB_TXC */
+ { PIN_AVB_TD0, 0, 3 }, /* AVB_TD0 */
} },
{ PINMUX_DRIVE_REG("DRVCTRL3", 0xe606030c) {
- { PIN_NUMBER('B', 18), 28, 3 }, /* AVB_TD1 */
- { PIN_NUMBER('A', 17), 24, 3 }, /* AVB_TD2 */
- { PIN_NUMBER('B', 17), 20, 3 }, /* AVB_TD3 */
- { PIN_NUMBER('A', 12), 16, 3 }, /* AVB_TXCREFCLK */
- { PIN_NUMBER('A', 9), 12, 3 }, /* AVB_MDIO */
- { RCAR_GP_PIN(2, 9), 8, 3 }, /* AVB_MDC */
- { RCAR_GP_PIN(2, 10), 4, 3 }, /* AVB_MAGIC */
- { RCAR_GP_PIN(2, 11), 0, 3 }, /* AVB_PHY_INT */
+ { PIN_AVB_TD1, 28, 3 }, /* AVB_TD1 */
+ { PIN_AVB_TD2, 24, 3 }, /* AVB_TD2 */
+ { PIN_AVB_TD3, 20, 3 }, /* AVB_TD3 */
+ { PIN_AVB_TXCREFCLK, 16, 3 }, /* AVB_TXCREFCLK */
+ { PIN_AVB_MDIO, 12, 3 }, /* AVB_MDIO */
+ { RCAR_GP_PIN(2, 9), 8, 3 }, /* AVB_MDC */
+ { RCAR_GP_PIN(2, 10), 4, 3 }, /* AVB_MAGIC */
+ { RCAR_GP_PIN(2, 11), 0, 3 }, /* AVB_PHY_INT */
} },
{ PINMUX_DRIVE_REG("DRVCTRL4", 0xe6060310) {
{ RCAR_GP_PIN(2, 12), 28, 3 }, /* AVB_LINK */
@@ -5714,7 +5748,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = {
} },
{ PINMUX_DRIVE_REG("DRVCTRL9", 0xe6060324) {
{ RCAR_GP_PIN(1, 27), 28, 3 }, /* EX_WAIT0 */
- { PIN_NUMBER('C', 1), 24, 3 }, /* PRESETOUT# */
+ { PIN_PRESETOUT_N, 24, 3 }, /* PRESETOUT# */
{ RCAR_GP_PIN(0, 0), 20, 3 }, /* D0 */
{ RCAR_GP_PIN(0, 1), 16, 3 }, /* D1 */
{ RCAR_GP_PIN(0, 2), 12, 3 }, /* D2 */
@@ -5733,30 +5767,30 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = {
{ RCAR_GP_PIN(0, 13), 0, 3 }, /* D13 */
} },
{ PINMUX_DRIVE_REG("DRVCTRL11", 0xe606032c) {
- { RCAR_GP_PIN(0, 14), 28, 3 }, /* D14 */
- { RCAR_GP_PIN(0, 15), 24, 3 }, /* D15 */
- { RCAR_GP_PIN(7, 0), 20, 3 }, /* AVS1 */
- { RCAR_GP_PIN(7, 1), 16, 3 }, /* AVS2 */
- { RCAR_GP_PIN(7, 2), 12, 3 }, /* GP7_02 */
- { RCAR_GP_PIN(7, 3), 8, 3 }, /* GP7_03 */
- { PIN_A_NUMBER('P', 7), 4, 2 }, /* DU_DOTCLKIN0 */
- { PIN_A_NUMBER('P', 8), 0, 2 }, /* DU_DOTCLKIN1 */
+ { RCAR_GP_PIN(0, 14), 28, 3 }, /* D14 */
+ { RCAR_GP_PIN(0, 15), 24, 3 }, /* D15 */
+ { RCAR_GP_PIN(7, 0), 20, 3 }, /* AVS1 */
+ { RCAR_GP_PIN(7, 1), 16, 3 }, /* AVS2 */
+ { RCAR_GP_PIN(7, 2), 12, 3 }, /* GP7_02 */
+ { RCAR_GP_PIN(7, 3), 8, 3 }, /* GP7_03 */
+ { PIN_DU_DOTCLKIN0, 4, 2 }, /* DU_DOTCLKIN0 */
+ { PIN_DU_DOTCLKIN1, 0, 2 }, /* DU_DOTCLKIN1 */
} },
{ PINMUX_DRIVE_REG("DRVCTRL12", 0xe6060330) {
- { PIN_A_NUMBER('R', 7), 28, 2 }, /* DU_DOTCLKIN2 */
- { PIN_A_NUMBER('R', 8), 24, 2 }, /* DU_DOTCLKIN3 */
- { PIN_A_NUMBER('D', 38), 20, 2 }, /* FSCLKST# */
- { PIN_A_NUMBER('R', 30), 4, 2 }, /* TMS */
+ { PIN_DU_DOTCLKIN2, 28, 2 }, /* DU_DOTCLKIN2 */
+ { PIN_DU_DOTCLKIN3, 24, 2 }, /* DU_DOTCLKIN3 */
+ { PIN_FSCLKST_N, 20, 2 }, /* FSCLKST# */
+ { PIN_TMS, 4, 2 }, /* TMS */
} },
{ PINMUX_DRIVE_REG("DRVCTRL13", 0xe6060334) {
- { PIN_A_NUMBER('T', 28), 28, 2 }, /* TDO */
- { PIN_A_NUMBER('T', 30), 24, 2 }, /* ASEBRK */
- { RCAR_GP_PIN(3, 0), 20, 3 }, /* SD0_CLK */
- { RCAR_GP_PIN(3, 1), 16, 3 }, /* SD0_CMD */
- { RCAR_GP_PIN(3, 2), 12, 3 }, /* SD0_DAT0 */
- { RCAR_GP_PIN(3, 3), 8, 3 }, /* SD0_DAT1 */
- { RCAR_GP_PIN(3, 4), 4, 3 }, /* SD0_DAT2 */
- { RCAR_GP_PIN(3, 5), 0, 3 }, /* SD0_DAT3 */
+ { PIN_TDO, 28, 2 }, /* TDO */
+ { PIN_ASEBRK, 24, 2 }, /* ASEBRK */
+ { RCAR_GP_PIN(3, 0), 20, 3 }, /* SD0_CLK */
+ { RCAR_GP_PIN(3, 1), 16, 3 }, /* SD0_CMD */
+ { RCAR_GP_PIN(3, 2), 12, 3 }, /* SD0_DAT0 */
+ { RCAR_GP_PIN(3, 3), 8, 3 }, /* SD0_DAT1 */
+ { RCAR_GP_PIN(3, 4), 4, 3 }, /* SD0_DAT2 */
+ { RCAR_GP_PIN(3, 5), 0, 3 }, /* SD0_DAT3 */
} },
{ PINMUX_DRIVE_REG("DRVCTRL14", 0xe6060338) {
{ RCAR_GP_PIN(3, 6), 28, 3 }, /* SD1_CLK */
@@ -5825,7 +5859,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = {
{ RCAR_GP_PIN(5, 23), 16, 3 }, /* MLB_CLK */
{ RCAR_GP_PIN(5, 24), 12, 3 }, /* MLB_SIG */
{ RCAR_GP_PIN(5, 25), 8, 3 }, /* MLB_DAT */
- { PIN_NUMBER('H', 37), 4, 3 }, /* MLB_REF */
+ { PIN_MLB_REF, 4, 3 }, /* MLB_REF */
{ RCAR_GP_PIN(6, 0), 0, 3 }, /* SSI_SCK01239 */
} },
{ PINMUX_DRIVE_REG("DRVCTRL21", 0xe6060354) {
@@ -5898,35 +5932,35 @@ static int r8a7795_pin_to_pocctrl(struct sh_pfc *pfc, unsigned int pin, u32 *poc
static const struct pinmux_bias_reg pinmux_bias_regs[] = {
{ PINMUX_BIAS_REG("PUEN0", 0xe6060400, "PUD0", 0xe6060440) {
- [ 0] = PIN_NUMBER('W', 3), /* QSPI0_SPCLK */
- [ 1] = PIN_A_NUMBER('C', 5), /* QSPI0_MOSI_IO0 */
- [ 2] = PIN_A_NUMBER('B', 4), /* QSPI0_MISO_IO1 */
- [ 3] = PIN_NUMBER('Y', 6), /* QSPI0_IO2 */
- [ 4] = PIN_A_NUMBER('B', 6), /* QSPI0_IO3 */
- [ 5] = PIN_NUMBER('Y', 3), /* QSPI0_SSL */
- [ 6] = PIN_NUMBER('V', 3), /* QSPI1_SPCLK */
- [ 7] = PIN_A_NUMBER('C', 7), /* QSPI1_MOSI_IO0 */
- [ 8] = PIN_A_NUMBER('E', 5), /* QSPI1_MISO_IO1 */
- [ 9] = PIN_A_NUMBER('E', 4), /* QSPI1_IO2 */
- [10] = PIN_A_NUMBER('C', 3), /* QSPI1_IO3 */
- [11] = PIN_NUMBER('V', 5), /* QSPI1_SSL */
- [12] = PIN_NUMBER('Y', 7), /* RPC_INT# */
- [13] = PIN_NUMBER('V', 6), /* RPC_WP# */
- [14] = PIN_NUMBER('V', 7), /* RPC_RESET# */
- [15] = PIN_NUMBER('A', 16), /* AVB_RX_CTL */
- [16] = PIN_NUMBER('B', 19), /* AVB_RXC */
- [17] = PIN_NUMBER('A', 13), /* AVB_RD0 */
- [18] = PIN_NUMBER('B', 13), /* AVB_RD1 */
- [19] = PIN_NUMBER('A', 14), /* AVB_RD2 */
- [20] = PIN_NUMBER('B', 14), /* AVB_RD3 */
- [21] = PIN_NUMBER('A', 8), /* AVB_TX_CTL */
- [22] = PIN_NUMBER('A', 19), /* AVB_TXC */
- [23] = PIN_NUMBER('A', 18), /* AVB_TD0 */
- [24] = PIN_NUMBER('B', 18), /* AVB_TD1 */
- [25] = PIN_NUMBER('A', 17), /* AVB_TD2 */
- [26] = PIN_NUMBER('B', 17), /* AVB_TD3 */
- [27] = PIN_NUMBER('A', 12), /* AVB_TXCREFCLK */
- [28] = PIN_NUMBER('A', 9), /* AVB_MDIO */
+ [ 0] = PIN_QSPI0_SPCLK, /* QSPI0_SPCLK */
+ [ 1] = PIN_QSPI0_MOSI_IO0, /* QSPI0_MOSI_IO0 */
+ [ 2] = PIN_QSPI0_MISO_IO1, /* QSPI0_MISO_IO1 */
+ [ 3] = PIN_QSPI0_IO2, /* QSPI0_IO2 */
+ [ 4] = PIN_QSPI0_IO3, /* QSPI0_IO3 */
+ [ 5] = PIN_QSPI0_SSL, /* QSPI0_SSL */
+ [ 6] = PIN_QSPI1_SPCLK, /* QSPI1_SPCLK */
+ [ 7] = PIN_QSPI1_MOSI_IO0, /* QSPI1_MOSI_IO0 */
+ [ 8] = PIN_QSPI1_MISO_IO1, /* QSPI1_MISO_IO1 */
+ [ 9] = PIN_QSPI1_IO2, /* QSPI1_IO2 */
+ [10] = PIN_QSPI1_IO3, /* QSPI1_IO3 */
+ [11] = PIN_QSPI1_SSL, /* QSPI1_SSL */
+ [12] = PIN_RPC_INT_N, /* RPC_INT# */
+ [13] = PIN_RPC_WP_N, /* RPC_WP# */
+ [14] = PIN_RPC_RESET_N, /* RPC_RESET# */
+ [15] = PIN_AVB_RX_CTL, /* AVB_RX_CTL */
+ [16] = PIN_AVB_RXC, /* AVB_RXC */
+ [17] = PIN_AVB_RD0, /* AVB_RD0 */
+ [18] = PIN_AVB_RD1, /* AVB_RD1 */
+ [19] = PIN_AVB_RD2, /* AVB_RD2 */
+ [20] = PIN_AVB_RD3, /* AVB_RD3 */
+ [21] = PIN_AVB_TX_CTL, /* AVB_TX_CTL */
+ [22] = PIN_AVB_TXC, /* AVB_TXC */
+ [23] = PIN_AVB_TD0, /* AVB_TD0 */
+ [24] = PIN_AVB_TD1, /* AVB_TD1 */
+ [25] = PIN_AVB_TD2, /* AVB_TD2 */
+ [26] = PIN_AVB_TD3, /* AVB_TD3 */
+ [27] = PIN_AVB_TXCREFCLK, /* AVB_TXCREFCLK */
+ [28] = PIN_AVB_MDIO, /* AVB_MDIO */
[29] = RCAR_GP_PIN(2, 9), /* AVB_MDC */
[30] = RCAR_GP_PIN(2, 10), /* AVB_MAGIC */
[31] = RCAR_GP_PIN(2, 11), /* AVB_PHY_INT */
@@ -5975,7 +6009,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
[ 6] = RCAR_GP_PIN(1, 25), /* WE0_N */
[ 7] = RCAR_GP_PIN(1, 26), /* WE1_N */
[ 8] = RCAR_GP_PIN(1, 27), /* EX_WAIT0_A */
- [ 9] = PIN_NUMBER('C', 1), /* PRESETOUT# */
+ [ 9] = PIN_PRESETOUT_N, /* PRESETOUT# */
[10] = RCAR_GP_PIN(0, 0), /* D0 */
[11] = RCAR_GP_PIN(0, 1), /* D1 */
[12] = RCAR_GP_PIN(0, 2), /* D2 */
@@ -5996,20 +6030,20 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
[27] = RCAR_GP_PIN(7, 1), /* AVS2 */
[28] = RCAR_GP_PIN(7, 2), /* GP7_02 */
[29] = RCAR_GP_PIN(7, 3), /* GP7_03 */
- [30] = PIN_A_NUMBER('P', 7), /* DU_DOTCLKIN0 */
- [31] = PIN_A_NUMBER('P', 8), /* DU_DOTCLKIN1 */
+ [30] = PIN_DU_DOTCLKIN0, /* DU_DOTCLKIN0 */
+ [31] = PIN_DU_DOTCLKIN1, /* DU_DOTCLKIN1 */
} },
{ PINMUX_BIAS_REG("PUEN3", 0xe606040c, "PUD3", 0xe606044c) {
- [ 0] = PIN_A_NUMBER('R', 7), /* DU_DOTCLKIN2 */
- [ 1] = PIN_A_NUMBER('R', 8), /* DU_DOTCLKIN3 */
- [ 2] = PIN_A_NUMBER('D', 38), /* FSCLKST# */
- [ 3] = PIN_A_NUMBER('D', 39), /* EXTALR*/
- [ 4] = PIN_A_NUMBER('R', 26), /* TRST# */
- [ 5] = PIN_A_NUMBER('T', 27), /* TCK */
- [ 6] = PIN_A_NUMBER('R', 30), /* TMS */
- [ 7] = PIN_A_NUMBER('R', 29), /* TDI */
- [ 8] = PIN_NONE,
- [ 9] = PIN_A_NUMBER('T', 30), /* ASEBRK */
+ [ 0] = PIN_DU_DOTCLKIN2, /* DU_DOTCLKIN2 */
+ [ 1] = PIN_DU_DOTCLKIN3, /* DU_DOTCLKIN3 */
+ [ 2] = PIN_FSCLKST_N, /* FSCLKST# */
+ [ 3] = PIN_EXTALR, /* EXTALR*/
+ [ 4] = PIN_TRST_N, /* TRST# */
+ [ 5] = PIN_TCK, /* TCK */
+ [ 6] = PIN_TMS, /* TMS */
+ [ 7] = PIN_TDI, /* TDI */
+ [ 8] = SH_PFC_PIN_NONE,
+ [ 9] = PIN_ASEBRK, /* ASEBRK */
[10] = RCAR_GP_PIN(3, 0), /* SD0_CLK */
[11] = RCAR_GP_PIN(3, 1), /* SD0_CMD */
[12] = RCAR_GP_PIN(3, 2), /* SD0_DAT0 */
@@ -6074,7 +6108,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
[ 3] = RCAR_GP_PIN(5, 23), /* MLB_CLK */
[ 4] = RCAR_GP_PIN(5, 24), /* MLB_SIG */
[ 5] = RCAR_GP_PIN(5, 25), /* MLB_DAT */
- [ 6] = PIN_NUMBER('H', 37), /* MLB_REF */
+ [ 6] = PIN_MLB_REF, /* MLB_REF */
[ 7] = RCAR_GP_PIN(6, 0), /* SSI_SCK01239 */
[ 8] = RCAR_GP_PIN(6, 1), /* SSI_WS01239 */
[ 9] = RCAR_GP_PIN(6, 2), /* SSI_SDATA0 */
@@ -6109,31 +6143,31 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
[ 4] = RCAR_GP_PIN(6, 29), /* USB30_OVC */
[ 5] = RCAR_GP_PIN(6, 30), /* USB2_CH3_PWEN */
[ 6] = RCAR_GP_PIN(6, 31), /* USB2_CH3_OVC */
- [ 7] = PIN_NONE,
- [ 8] = PIN_NONE,
- [ 9] = PIN_NONE,
- [10] = PIN_NONE,
- [11] = PIN_NONE,
- [12] = PIN_NONE,
- [13] = PIN_NONE,
- [14] = PIN_NONE,
- [15] = PIN_NONE,
- [16] = PIN_NONE,
- [17] = PIN_NONE,
- [18] = PIN_NONE,
- [19] = PIN_NONE,
- [20] = PIN_NONE,
- [21] = PIN_NONE,
- [22] = PIN_NONE,
- [23] = PIN_NONE,
- [24] = PIN_NONE,
- [25] = PIN_NONE,
- [26] = PIN_NONE,
- [27] = PIN_NONE,
- [28] = PIN_NONE,
- [29] = PIN_NONE,
- [30] = PIN_NONE,
- [31] = PIN_NONE,
+ [ 7] = SH_PFC_PIN_NONE,
+ [ 8] = SH_PFC_PIN_NONE,
+ [ 9] = SH_PFC_PIN_NONE,
+ [10] = SH_PFC_PIN_NONE,
+ [11] = SH_PFC_PIN_NONE,
+ [12] = SH_PFC_PIN_NONE,
+ [13] = SH_PFC_PIN_NONE,
+ [14] = SH_PFC_PIN_NONE,
+ [15] = SH_PFC_PIN_NONE,
+ [16] = SH_PFC_PIN_NONE,
+ [17] = SH_PFC_PIN_NONE,
+ [18] = SH_PFC_PIN_NONE,
+ [19] = SH_PFC_PIN_NONE,
+ [20] = SH_PFC_PIN_NONE,
+ [21] = SH_PFC_PIN_NONE,
+ [22] = SH_PFC_PIN_NONE,
+ [23] = SH_PFC_PIN_NONE,
+ [24] = SH_PFC_PIN_NONE,
+ [25] = SH_PFC_PIN_NONE,
+ [26] = SH_PFC_PIN_NONE,
+ [27] = SH_PFC_PIN_NONE,
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
} },
{ /* sentinel */ },
};
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7796.c b/drivers/pinctrl/sh-pfc/pfc-r8a7796.c
index 38cce690db70..61db7c7a35ec 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7796.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7796.c
@@ -17,11 +17,9 @@
#include "core.h"
#include "sh_pfc.h"
-#define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | \
- SH_PFC_PIN_CFG_PULL_UP | \
- SH_PFC_PIN_CFG_PULL_DOWN)
+#define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | SH_PFC_PIN_CFG_PULL_UP_DOWN)
-#define CPU_ALL_PORT(fn, sfx) \
+#define CPU_ALL_GP(fn, sfx) \
PORT_GP_CFG_16(0, fn, sfx, CFG_FLAGS), \
PORT_GP_CFG_29(1, fn, sfx, CFG_FLAGS), \
PORT_GP_CFG_15(2, fn, sfx, CFG_FLAGS), \
@@ -34,6 +32,51 @@
PORT_GP_CFG_26(5, fn, sfx, CFG_FLAGS), \
PORT_GP_CFG_32(6, fn, sfx, CFG_FLAGS), \
PORT_GP_CFG_4(7, fn, sfx, CFG_FLAGS)
+
+#define CPU_ALL_NOGP(fn) \
+ PIN_NOGP_CFG(ASEBRK, "ASEBRK", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_MDIO, "AVB_MDIO", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_RD0, "AVB_RD0", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_RD1, "AVB_RD1", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_RD2, "AVB_RD2", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_RD3, "AVB_RD3", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_RXC, "AVB_RXC", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_RX_CTL, "AVB_RX_CTL", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TD0, "AVB_TD0", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TD1, "AVB_TD1", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TD2, "AVB_TD2", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TD3, "AVB_TD3", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TXC, "AVB_TXC", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TXCREFCLK, "AVB_TXCREFCLK", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TX_CTL, "AVB_TX_CTL", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(DU_DOTCLKIN0, "DU_DOTCLKIN0", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(DU_DOTCLKIN1, "DU_DOTCLKIN1", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(DU_DOTCLKIN2, "DU_DOTCLKIN2", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(EXTALR, "EXTALR", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN),\
+ PIN_NOGP_CFG(FSCLKST, "FSCLKST", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(MLB_REF, "MLB_REF", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(PRESETOUT_N, "PRESETOUT#", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI0_IO2, "QSPI0_IO2", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI0_IO3, "QSPI0_IO3", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI0_MISO_IO1, "QSPI0_MISO_IO1", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI0_MOSI_IO0, "QSPI0_MOSI_IO0", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI0_SPCLK, "QSPI0_SPCLK", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI0_SSL, "QSPI0_SSL", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI1_IO2, "QSPI1_IO2", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI1_IO3, "QSPI1_IO3", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI1_MISO_IO1, "QSPI1_MISO_IO1", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI1_MOSI_IO0, "QSPI1_MOSI_IO0", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI1_SPCLK, "QSPI1_SPCLK", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI1_SSL, "QSPI1_SSL", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(RPC_INT_N, "RPC_INT#", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(RPC_RESET_N, "RPC_RESET#", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(RPC_WP_N, "RPC_WP#", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(TCK, "TCK", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \
+ PIN_NOGP_CFG(TDI, "TDI", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \
+ PIN_NOGP_CFG(TDO, "TDO", fn, SH_PFC_PIN_CFG_DRIVE_STRENGTH), \
+ PIN_NOGP_CFG(TMS, "TMS", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(TRST_N, "TRST#", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN)
+
/*
* F_() : just information
* FM() : macro for FN_xxx / xxx_MARK
@@ -1512,67 +1555,16 @@ static const u16 pinmux_data[] = {
};
/*
- * R8A7796 has 8 banks with 32 GPIOs in each => 256 GPIOs.
- * Physical layout rows: A - AW, cols: 1 - 39.
+ * Pins not associated with a GPIO port.
*/
-#define ROW_GROUP_A(r) ('Z' - 'A' + 1 + (r))
-#define PIN_NUMBER(r, c) (((r) - 'A') * 39 + (c) + 300)
-#define PIN_A_NUMBER(r, c) PIN_NUMBER(ROW_GROUP_A(r), c)
-#define PIN_NONE U16_MAX
+enum {
+ GP_ASSIGN_LAST(),
+ NOGP_ALL(),
+};
static const struct sh_pfc_pin pinmux_pins[] = {
PINMUX_GPIO_GP_ALL(),
-
- /*
- * Pins not associated with a GPIO port.
- *
- * The pin positions are different between different r8a7796
- * packages, all that is needed for the pfc driver is a unique
- * number for each pin. To this end use the pin layout from
- * R-Car M3SiP to calculate a unique number for each pin.
- */
- SH_PFC_PIN_NAMED_CFG('A', 8, AVB_TX_CTL, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 9, AVB_MDIO, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 12, AVB_TXCREFCLK, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 13, AVB_RD0, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 14, AVB_RD2, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 16, AVB_RX_CTL, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 17, AVB_TD2, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 18, AVB_TD0, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 19, AVB_TXC, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('B', 13, AVB_RD1, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('B', 14, AVB_RD3, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('B', 17, AVB_TD3, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('B', 18, AVB_TD1, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('B', 19, AVB_RXC, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('C', 1, PRESETOUT#, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('H', 37, MLB_REF, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('V', 3, QSPI1_SPCLK, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('V', 5, QSPI1_SSL, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('V', 6, RPC_WP#, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('V', 7, RPC_RESET#, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('W', 3, QSPI0_SPCLK, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('Y', 3, QSPI0_SSL, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('Y', 6, QSPI0_IO2, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('Y', 7, RPC_INT#, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'), 4, QSPI0_MISO_IO1, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'), 6, QSPI0_IO3, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 3, QSPI1_IO3, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 5, QSPI0_MOSI_IO0, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 7, QSPI1_MOSI_IO0, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 38, FSCLKST, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 39, EXTALR, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'), 4, QSPI1_IO2, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'), 5, QSPI1_MISO_IO1, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'), 7, DU_DOTCLKIN0, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'), 8, DU_DOTCLKIN1, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 8, DU_DOTCLKIN2, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 26, TRST#, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 29, TDI, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 30, TMS, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 27, TCK, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 28, TDO, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 30, ASEBRK, CFG_FLAGS),
+ PINMUX_NOGP_ALL(),
};
/* - AUDIO CLOCK ------------------------------------------------------------ */
@@ -1721,7 +1713,7 @@ static const unsigned int avb_phy_int_mux[] = {
};
static const unsigned int avb_mdio_pins[] = {
/* AVB_MDC, AVB_MDIO */
- RCAR_GP_PIN(2, 9), PIN_NUMBER('A', 9),
+ RCAR_GP_PIN(2, 9), PIN_AVB_MDIO,
};
static const unsigned int avb_mdio_mux[] = {
AVB_MDC_MARK, AVB_MDIO_MARK,
@@ -1734,11 +1726,11 @@ static const unsigned int avb_mii_pins[] = {
* AVB_RD1, AVB_RD2, AVB_RD3,
* AVB_TXCREFCLK
*/
- PIN_NUMBER('A', 8), PIN_NUMBER('A', 19), PIN_NUMBER('A', 18),
- PIN_NUMBER('B', 18), PIN_NUMBER('A', 17), PIN_NUMBER('B', 17),
- PIN_NUMBER('A', 16), PIN_NUMBER('B', 19), PIN_NUMBER('A', 13),
- PIN_NUMBER('B', 13), PIN_NUMBER('A', 14), PIN_NUMBER('B', 14),
- PIN_NUMBER('A', 12),
+ PIN_AVB_TX_CTL, PIN_AVB_TXC, PIN_AVB_TD0,
+ PIN_AVB_TD1, PIN_AVB_TD2, PIN_AVB_TD3,
+ PIN_AVB_RX_CTL, PIN_AVB_RXC, PIN_AVB_RD0,
+ PIN_AVB_RD1, PIN_AVB_RD2, PIN_AVB_RD3,
+ PIN_AVB_TXCREFCLK,
};
static const unsigned int avb_mii_mux[] = {
@@ -3891,6 +3883,36 @@ static const unsigned int tmu_tclk2_b_mux[] = {
TCLK2_B_MARK,
};
+/* - TPU ------------------------------------------------------------------- */
+static const unsigned int tpu_to0_pins[] = {
+ /* TPU0TO0 */
+ RCAR_GP_PIN(6, 28),
+};
+static const unsigned int tpu_to0_mux[] = {
+ TPU0TO0_MARK,
+};
+static const unsigned int tpu_to1_pins[] = {
+ /* TPU0TO1 */
+ RCAR_GP_PIN(6, 29),
+};
+static const unsigned int tpu_to1_mux[] = {
+ TPU0TO1_MARK,
+};
+static const unsigned int tpu_to2_pins[] = {
+ /* TPU0TO2 */
+ RCAR_GP_PIN(6, 30),
+};
+static const unsigned int tpu_to2_mux[] = {
+ TPU0TO2_MARK,
+};
+static const unsigned int tpu_to3_pins[] = {
+ /* TPU0TO3 */
+ RCAR_GP_PIN(6, 31),
+};
+static const unsigned int tpu_to3_mux[] = {
+ TPU0TO3_MARK,
+};
+
/* - USB0 ------------------------------------------------------------------- */
static const unsigned int usb0_pins[] = {
/* PWEN, OVC */
@@ -4110,7 +4132,7 @@ static const unsigned int vin5_clk_mux[] = {
};
static const struct {
- struct sh_pfc_pin_group common[312];
+ struct sh_pfc_pin_group common[316];
struct sh_pfc_pin_group automotive[30];
} pinmux_groups = {
.common = {
@@ -4397,6 +4419,10 @@ static const struct {
SH_PFC_PIN_GROUP(tmu_tclk1_b),
SH_PFC_PIN_GROUP(tmu_tclk2_a),
SH_PFC_PIN_GROUP(tmu_tclk2_b),
+ SH_PFC_PIN_GROUP(tpu_to0),
+ SH_PFC_PIN_GROUP(tpu_to1),
+ SH_PFC_PIN_GROUP(tpu_to2),
+ SH_PFC_PIN_GROUP(tpu_to3),
SH_PFC_PIN_GROUP(usb0),
SH_PFC_PIN_GROUP(usb1),
SH_PFC_PIN_GROUP(usb30),
@@ -4918,6 +4944,13 @@ static const char * const tmu_groups[] = {
"tmu_tclk2_b",
};
+static const char * const tpu_groups[] = {
+ "tpu_to0",
+ "tpu_to1",
+ "tpu_to2",
+ "tpu_to3",
+};
+
static const char * const usb0_groups[] = {
"usb0",
};
@@ -4963,7 +4996,7 @@ static const char * const vin5_groups[] = {
};
static const struct {
- struct sh_pfc_function common[49];
+ struct sh_pfc_function common[50];
struct sh_pfc_function automotive[4];
} pinmux_functions = {
.common = {
@@ -5011,6 +5044,7 @@ static const struct {
SH_PFC_FUNCTION(sdhi3),
SH_PFC_FUNCTION(ssi),
SH_PFC_FUNCTION(tmu),
+ SH_PFC_FUNCTION(tpu),
SH_PFC_FUNCTION(usb0),
SH_PFC_FUNCTION(usb1),
SH_PFC_FUNCTION(usb30),
@@ -5590,44 +5624,44 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
static const struct pinmux_drive_reg pinmux_drive_regs[] = {
{ PINMUX_DRIVE_REG("DRVCTRL0", 0xe6060300) {
- { PIN_NUMBER('W', 3), 28, 2 }, /* QSPI0_SPCLK */
- { PIN_A_NUMBER('C', 5), 24, 2 }, /* QSPI0_MOSI_IO0 */
- { PIN_A_NUMBER('B', 4), 20, 2 }, /* QSPI0_MISO_IO1 */
- { PIN_NUMBER('Y', 6), 16, 2 }, /* QSPI0_IO2 */
- { PIN_A_NUMBER('B', 6), 12, 2 }, /* QSPI0_IO3 */
- { PIN_NUMBER('Y', 3), 8, 2 }, /* QSPI0_SSL */
- { PIN_NUMBER('V', 3), 4, 2 }, /* QSPI1_SPCLK */
- { PIN_A_NUMBER('C', 7), 0, 2 }, /* QSPI1_MOSI_IO0 */
+ { PIN_QSPI0_SPCLK, 28, 2 }, /* QSPI0_SPCLK */
+ { PIN_QSPI0_MOSI_IO0, 24, 2 }, /* QSPI0_MOSI_IO0 */
+ { PIN_QSPI0_MISO_IO1, 20, 2 }, /* QSPI0_MISO_IO1 */
+ { PIN_QSPI0_IO2, 16, 2 }, /* QSPI0_IO2 */
+ { PIN_QSPI0_IO3, 12, 2 }, /* QSPI0_IO3 */
+ { PIN_QSPI0_SSL, 8, 2 }, /* QSPI0_SSL */
+ { PIN_QSPI1_SPCLK, 4, 2 }, /* QSPI1_SPCLK */
+ { PIN_QSPI1_MOSI_IO0, 0, 2 }, /* QSPI1_MOSI_IO0 */
} },
{ PINMUX_DRIVE_REG("DRVCTRL1", 0xe6060304) {
- { PIN_A_NUMBER('E', 5), 28, 2 }, /* QSPI1_MISO_IO1 */
- { PIN_A_NUMBER('E', 4), 24, 2 }, /* QSPI1_IO2 */
- { PIN_A_NUMBER('C', 3), 20, 2 }, /* QSPI1_IO3 */
- { PIN_NUMBER('V', 5), 16, 2 }, /* QSPI1_SSL */
- { PIN_NUMBER('Y', 7), 12, 2 }, /* RPC_INT# */
- { PIN_NUMBER('V', 6), 8, 2 }, /* RPC_WP# */
- { PIN_NUMBER('V', 7), 4, 2 }, /* RPC_RESET# */
- { PIN_NUMBER('A', 16), 0, 3 }, /* AVB_RX_CTL */
+ { PIN_QSPI1_MISO_IO1, 28, 2 }, /* QSPI1_MISO_IO1 */
+ { PIN_QSPI1_IO2, 24, 2 }, /* QSPI1_IO2 */
+ { PIN_QSPI1_IO3, 20, 2 }, /* QSPI1_IO3 */
+ { PIN_QSPI1_SSL, 16, 2 }, /* QSPI1_SSL */
+ { PIN_RPC_INT_N, 12, 2 }, /* RPC_INT# */
+ { PIN_RPC_WP_N, 8, 2 }, /* RPC_WP# */
+ { PIN_RPC_RESET_N, 4, 2 }, /* RPC_RESET# */
+ { PIN_AVB_RX_CTL, 0, 3 }, /* AVB_RX_CTL */
} },
{ PINMUX_DRIVE_REG("DRVCTRL2", 0xe6060308) {
- { PIN_NUMBER('B', 19), 28, 3 }, /* AVB_RXC */
- { PIN_NUMBER('A', 13), 24, 3 }, /* AVB_RD0 */
- { PIN_NUMBER('B', 13), 20, 3 }, /* AVB_RD1 */
- { PIN_NUMBER('A', 14), 16, 3 }, /* AVB_RD2 */
- { PIN_NUMBER('B', 14), 12, 3 }, /* AVB_RD3 */
- { PIN_NUMBER('A', 8), 8, 3 }, /* AVB_TX_CTL */
- { PIN_NUMBER('A', 19), 4, 3 }, /* AVB_TXC */
- { PIN_NUMBER('A', 18), 0, 3 }, /* AVB_TD0 */
+ { PIN_AVB_RXC, 28, 3 }, /* AVB_RXC */
+ { PIN_AVB_RD0, 24, 3 }, /* AVB_RD0 */
+ { PIN_AVB_RD1, 20, 3 }, /* AVB_RD1 */
+ { PIN_AVB_RD2, 16, 3 }, /* AVB_RD2 */
+ { PIN_AVB_RD3, 12, 3 }, /* AVB_RD3 */
+ { PIN_AVB_TX_CTL, 8, 3 }, /* AVB_TX_CTL */
+ { PIN_AVB_TXC, 4, 3 }, /* AVB_TXC */
+ { PIN_AVB_TD0, 0, 3 }, /* AVB_TD0 */
} },
{ PINMUX_DRIVE_REG("DRVCTRL3", 0xe606030c) {
- { PIN_NUMBER('B', 18), 28, 3 }, /* AVB_TD1 */
- { PIN_NUMBER('A', 17), 24, 3 }, /* AVB_TD2 */
- { PIN_NUMBER('B', 17), 20, 3 }, /* AVB_TD3 */
- { PIN_NUMBER('A', 12), 16, 3 }, /* AVB_TXCREFCLK */
- { PIN_NUMBER('A', 9), 12, 3 }, /* AVB_MDIO */
- { RCAR_GP_PIN(2, 9), 8, 3 }, /* AVB_MDC */
- { RCAR_GP_PIN(2, 10), 4, 3 }, /* AVB_MAGIC */
- { RCAR_GP_PIN(2, 11), 0, 3 }, /* AVB_PHY_INT */
+ { PIN_AVB_TD1, 28, 3 }, /* AVB_TD1 */
+ { PIN_AVB_TD2, 24, 3 }, /* AVB_TD2 */
+ { PIN_AVB_TD3, 20, 3 }, /* AVB_TD3 */
+ { PIN_AVB_TXCREFCLK, 16, 3 }, /* AVB_TXCREFCLK */
+ { PIN_AVB_MDIO, 12, 3 }, /* AVB_MDIO */
+ { RCAR_GP_PIN(2, 9), 8, 3 }, /* AVB_MDC */
+ { RCAR_GP_PIN(2, 10), 4, 3 }, /* AVB_MAGIC */
+ { RCAR_GP_PIN(2, 11), 0, 3 }, /* AVB_PHY_INT */
} },
{ PINMUX_DRIVE_REG("DRVCTRL4", 0xe6060310) {
{ RCAR_GP_PIN(2, 12), 28, 3 }, /* AVB_LINK */
@@ -5681,7 +5715,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = {
} },
{ PINMUX_DRIVE_REG("DRVCTRL9", 0xe6060324) {
{ RCAR_GP_PIN(1, 27), 28, 3 }, /* EX_WAIT0 */
- { PIN_NUMBER('C', 1), 24, 3 }, /* PRESETOUT# */
+ { PIN_PRESETOUT_N, 24, 3 }, /* PRESETOUT# */
{ RCAR_GP_PIN(0, 0), 20, 3 }, /* D0 */
{ RCAR_GP_PIN(0, 1), 16, 3 }, /* D1 */
{ RCAR_GP_PIN(0, 2), 12, 3 }, /* D2 */
@@ -5700,29 +5734,29 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = {
{ RCAR_GP_PIN(0, 13), 0, 3 }, /* D13 */
} },
{ PINMUX_DRIVE_REG("DRVCTRL11", 0xe606032c) {
- { RCAR_GP_PIN(0, 14), 28, 3 }, /* D14 */
- { RCAR_GP_PIN(0, 15), 24, 3 }, /* D15 */
- { RCAR_GP_PIN(7, 0), 20, 3 }, /* AVS1 */
- { RCAR_GP_PIN(7, 1), 16, 3 }, /* AVS2 */
- { RCAR_GP_PIN(7, 2), 12, 3 }, /* GP7_02 */
- { RCAR_GP_PIN(7, 3), 8, 3 }, /* GP7_03 */
- { PIN_A_NUMBER('P', 7), 4, 2 }, /* DU_DOTCLKIN0 */
- { PIN_A_NUMBER('P', 8), 0, 2 }, /* DU_DOTCLKIN1 */
+ { RCAR_GP_PIN(0, 14), 28, 3 }, /* D14 */
+ { RCAR_GP_PIN(0, 15), 24, 3 }, /* D15 */
+ { RCAR_GP_PIN(7, 0), 20, 3 }, /* AVS1 */
+ { RCAR_GP_PIN(7, 1), 16, 3 }, /* AVS2 */
+ { RCAR_GP_PIN(7, 2), 12, 3 }, /* GP7_02 */
+ { RCAR_GP_PIN(7, 3), 8, 3 }, /* GP7_03 */
+ { PIN_DU_DOTCLKIN0, 4, 2 }, /* DU_DOTCLKIN0 */
+ { PIN_DU_DOTCLKIN1, 0, 2 }, /* DU_DOTCLKIN1 */
} },
{ PINMUX_DRIVE_REG("DRVCTRL12", 0xe6060330) {
- { PIN_A_NUMBER('R', 8), 28, 2 }, /* DU_DOTCLKIN2 */
- { PIN_A_NUMBER('D', 38), 20, 2 }, /* FSCLKST */
- { PIN_A_NUMBER('R', 30), 4, 2 }, /* TMS */
+ { PIN_DU_DOTCLKIN2, 28, 2 }, /* DU_DOTCLKIN2 */
+ { PIN_FSCLKST, 20, 2 }, /* FSCLKST */
+ { PIN_TMS, 4, 2 }, /* TMS */
} },
{ PINMUX_DRIVE_REG("DRVCTRL13", 0xe6060334) {
- { PIN_A_NUMBER('T', 28), 28, 2 }, /* TDO */
- { PIN_A_NUMBER('T', 30), 24, 2 }, /* ASEBRK */
- { RCAR_GP_PIN(3, 0), 20, 3 }, /* SD0_CLK */
- { RCAR_GP_PIN(3, 1), 16, 3 }, /* SD0_CMD */
- { RCAR_GP_PIN(3, 2), 12, 3 }, /* SD0_DAT0 */
- { RCAR_GP_PIN(3, 3), 8, 3 }, /* SD0_DAT1 */
- { RCAR_GP_PIN(3, 4), 4, 3 }, /* SD0_DAT2 */
- { RCAR_GP_PIN(3, 5), 0, 3 }, /* SD0_DAT3 */
+ { PIN_TDO, 28, 2 }, /* TDO */
+ { PIN_ASEBRK, 24, 2 }, /* ASEBRK */
+ { RCAR_GP_PIN(3, 0), 20, 3 }, /* SD0_CLK */
+ { RCAR_GP_PIN(3, 1), 16, 3 }, /* SD0_CMD */
+ { RCAR_GP_PIN(3, 2), 12, 3 }, /* SD0_DAT0 */
+ { RCAR_GP_PIN(3, 3), 8, 3 }, /* SD0_DAT1 */
+ { RCAR_GP_PIN(3, 4), 4, 3 }, /* SD0_DAT2 */
+ { RCAR_GP_PIN(3, 5), 0, 3 }, /* SD0_DAT3 */
} },
{ PINMUX_DRIVE_REG("DRVCTRL14", 0xe6060338) {
{ RCAR_GP_PIN(3, 6), 28, 3 }, /* SD1_CLK */
@@ -5791,7 +5825,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = {
{ RCAR_GP_PIN(5, 23), 16, 3 }, /* MLB_CLK */
{ RCAR_GP_PIN(5, 24), 12, 3 }, /* MLB_SIG */
{ RCAR_GP_PIN(5, 25), 8, 3 }, /* MLB_DAT */
- { PIN_NUMBER('H', 37), 4, 3 }, /* MLB_REF */
+ { PIN_MLB_REF, 4, 3 }, /* MLB_REF */
{ RCAR_GP_PIN(6, 0), 0, 3 }, /* SSI_SCK01239 */
} },
{ PINMUX_DRIVE_REG("DRVCTRL21", 0xe6060354) {
@@ -5864,35 +5898,35 @@ static int r8a7796_pin_to_pocctrl(struct sh_pfc *pfc, unsigned int pin, u32 *poc
static const struct pinmux_bias_reg pinmux_bias_regs[] = {
{ PINMUX_BIAS_REG("PUEN0", 0xe6060400, "PUD0", 0xe6060440) {
- [ 0] = PIN_NUMBER('W', 3), /* QSPI0_SPCLK */
- [ 1] = PIN_A_NUMBER('C', 5), /* QSPI0_MOSI_IO0 */
- [ 2] = PIN_A_NUMBER('B', 4), /* QSPI0_MISO_IO1 */
- [ 3] = PIN_NUMBER('Y', 6), /* QSPI0_IO2 */
- [ 4] = PIN_A_NUMBER('B', 6), /* QSPI0_IO3 */
- [ 5] = PIN_NUMBER('Y', 3), /* QSPI0_SSL */
- [ 6] = PIN_NUMBER('V', 3), /* QSPI1_SPCLK */
- [ 7] = PIN_A_NUMBER('C', 7), /* QSPI1_MOSI_IO0 */
- [ 8] = PIN_A_NUMBER('E', 5), /* QSPI1_MISO_IO1 */
- [ 9] = PIN_A_NUMBER('E', 4), /* QSPI1_IO2 */
- [10] = PIN_A_NUMBER('C', 3), /* QSPI1_IO3 */
- [11] = PIN_NUMBER('V', 5), /* QSPI1_SSL */
- [12] = PIN_NUMBER('Y', 7), /* RPC_INT# */
- [13] = PIN_NUMBER('V', 6), /* RPC_WP# */
- [14] = PIN_NUMBER('V', 7), /* RPC_RESET# */
- [15] = PIN_NUMBER('A', 16), /* AVB_RX_CTL */
- [16] = PIN_NUMBER('B', 19), /* AVB_RXC */
- [17] = PIN_NUMBER('A', 13), /* AVB_RD0 */
- [18] = PIN_NUMBER('B', 13), /* AVB_RD1 */
- [19] = PIN_NUMBER('A', 14), /* AVB_RD2 */
- [20] = PIN_NUMBER('B', 14), /* AVB_RD3 */
- [21] = PIN_NUMBER('A', 8), /* AVB_TX_CTL */
- [22] = PIN_NUMBER('A', 19), /* AVB_TXC */
- [23] = PIN_NUMBER('A', 18), /* AVB_TD0 */
- [24] = PIN_NUMBER('B', 18), /* AVB_TD1 */
- [25] = PIN_NUMBER('A', 17), /* AVB_TD2 */
- [26] = PIN_NUMBER('B', 17), /* AVB_TD3 */
- [27] = PIN_NUMBER('A', 12), /* AVB_TXCREFCLK */
- [28] = PIN_NUMBER('A', 9), /* AVB_MDIO */
+ [ 0] = PIN_QSPI0_SPCLK, /* QSPI0_SPCLK */
+ [ 1] = PIN_QSPI0_MOSI_IO0, /* QSPI0_MOSI_IO0 */
+ [ 2] = PIN_QSPI0_MISO_IO1, /* QSPI0_MISO_IO1 */
+ [ 3] = PIN_QSPI0_IO2, /* QSPI0_IO2 */
+ [ 4] = PIN_QSPI0_IO3, /* QSPI0_IO3 */
+ [ 5] = PIN_QSPI0_SSL, /* QSPI0_SSL */
+ [ 6] = PIN_QSPI1_SPCLK, /* QSPI1_SPCLK */
+ [ 7] = PIN_QSPI1_MOSI_IO0, /* QSPI1_MOSI_IO0 */
+ [ 8] = PIN_QSPI1_MISO_IO1, /* QSPI1_MISO_IO1 */
+ [ 9] = PIN_QSPI1_IO2, /* QSPI1_IO2 */
+ [10] = PIN_QSPI1_IO3, /* QSPI1_IO3 */
+ [11] = PIN_QSPI1_SSL, /* QSPI1_SSL */
+ [12] = PIN_RPC_INT_N, /* RPC_INT# */
+ [13] = PIN_RPC_WP_N, /* RPC_WP# */
+ [14] = PIN_RPC_RESET_N, /* RPC_RESET# */
+ [15] = PIN_AVB_RX_CTL, /* AVB_RX_CTL */
+ [16] = PIN_AVB_RXC, /* AVB_RXC */
+ [17] = PIN_AVB_RD0, /* AVB_RD0 */
+ [18] = PIN_AVB_RD1, /* AVB_RD1 */
+ [19] = PIN_AVB_RD2, /* AVB_RD2 */
+ [20] = PIN_AVB_RD3, /* AVB_RD3 */
+ [21] = PIN_AVB_TX_CTL, /* AVB_TX_CTL */
+ [22] = PIN_AVB_TXC, /* AVB_TXC */
+ [23] = PIN_AVB_TD0, /* AVB_TD0 */
+ [24] = PIN_AVB_TD1, /* AVB_TD1 */
+ [25] = PIN_AVB_TD2, /* AVB_TD2 */
+ [26] = PIN_AVB_TD3, /* AVB_TD3 */
+ [27] = PIN_AVB_TXCREFCLK, /* AVB_TXCREFCLK */
+ [28] = PIN_AVB_MDIO, /* AVB_MDIO */
[29] = RCAR_GP_PIN(2, 9), /* AVB_MDC */
[30] = RCAR_GP_PIN(2, 10), /* AVB_MAGIC */
[31] = RCAR_GP_PIN(2, 11), /* AVB_PHY_INT */
@@ -5941,7 +5975,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
[ 6] = RCAR_GP_PIN(1, 25), /* WE0_N */
[ 7] = RCAR_GP_PIN(1, 26), /* WE1_N */
[ 8] = RCAR_GP_PIN(1, 27), /* EX_WAIT0_A */
- [ 9] = PIN_NUMBER('C', 1), /* PRESETOUT# */
+ [ 9] = PIN_PRESETOUT_N, /* PRESETOUT# */
[10] = RCAR_GP_PIN(0, 0), /* D0 */
[11] = RCAR_GP_PIN(0, 1), /* D1 */
[12] = RCAR_GP_PIN(0, 2), /* D2 */
@@ -5962,20 +5996,20 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
[27] = RCAR_GP_PIN(7, 1), /* AVS2 */
[28] = RCAR_GP_PIN(7, 2), /* GP7_02 */
[29] = RCAR_GP_PIN(7, 3), /* GP7_03 */
- [30] = PIN_A_NUMBER('P', 7), /* DU_DOTCLKIN0 */
- [31] = PIN_A_NUMBER('P', 8), /* DU_DOTCLKIN1 */
+ [30] = PIN_DU_DOTCLKIN0, /* DU_DOTCLKIN0 */
+ [31] = PIN_DU_DOTCLKIN1, /* DU_DOTCLKIN1 */
} },
{ PINMUX_BIAS_REG("PUEN3", 0xe606040c, "PUD3", 0xe606044c) {
- [ 0] = PIN_A_NUMBER('R', 8), /* DU_DOTCLKIN2 */
- [ 1] = PIN_NONE,
- [ 2] = PIN_A_NUMBER('D', 38), /* FSCLKST */
- [ 3] = PIN_A_NUMBER('D', 39), /* EXTALR*/
- [ 4] = PIN_A_NUMBER('R', 26), /* TRST# */
- [ 5] = PIN_A_NUMBER('T', 27), /* TCK */
- [ 6] = PIN_A_NUMBER('R', 30), /* TMS */
- [ 7] = PIN_A_NUMBER('R', 29), /* TDI */
- [ 8] = PIN_NONE,
- [ 9] = PIN_A_NUMBER('T', 30), /* ASEBRK */
+ [ 0] = PIN_DU_DOTCLKIN2, /* DU_DOTCLKIN2 */
+ [ 1] = SH_PFC_PIN_NONE,
+ [ 2] = PIN_FSCLKST, /* FSCLKST */
+ [ 3] = PIN_EXTALR, /* EXTALR*/
+ [ 4] = PIN_TRST_N, /* TRST# */
+ [ 5] = PIN_TCK, /* TCK */
+ [ 6] = PIN_TMS, /* TMS */
+ [ 7] = PIN_TDI, /* TDI */
+ [ 8] = SH_PFC_PIN_NONE,
+ [ 9] = PIN_ASEBRK, /* ASEBRK */
[10] = RCAR_GP_PIN(3, 0), /* SD0_CLK */
[11] = RCAR_GP_PIN(3, 1), /* SD0_CMD */
[12] = RCAR_GP_PIN(3, 2), /* SD0_DAT0 */
@@ -6040,7 +6074,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
[ 3] = RCAR_GP_PIN(5, 23), /* MLB_CLK */
[ 4] = RCAR_GP_PIN(5, 24), /* MLB_SIG */
[ 5] = RCAR_GP_PIN(5, 25), /* MLB_DAT */
- [ 6] = PIN_NUMBER('H', 37), /* MLB_REF */
+ [ 6] = PIN_MLB_REF, /* MLB_REF */
[ 7] = RCAR_GP_PIN(6, 0), /* SSI_SCK01239 */
[ 8] = RCAR_GP_PIN(6, 1), /* SSI_WS01239 */
[ 9] = RCAR_GP_PIN(6, 2), /* SSI_SDATA0 */
@@ -6075,31 +6109,31 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
[ 4] = RCAR_GP_PIN(6, 29), /* USB30_OVC */
[ 5] = RCAR_GP_PIN(6, 30), /* GP6_30 */
[ 6] = RCAR_GP_PIN(6, 31), /* GP6_31 */
- [ 7] = PIN_NONE,
- [ 8] = PIN_NONE,
- [ 9] = PIN_NONE,
- [10] = PIN_NONE,
- [11] = PIN_NONE,
- [12] = PIN_NONE,
- [13] = PIN_NONE,
- [14] = PIN_NONE,
- [15] = PIN_NONE,
- [16] = PIN_NONE,
- [17] = PIN_NONE,
- [18] = PIN_NONE,
- [19] = PIN_NONE,
- [20] = PIN_NONE,
- [21] = PIN_NONE,
- [22] = PIN_NONE,
- [23] = PIN_NONE,
- [24] = PIN_NONE,
- [25] = PIN_NONE,
- [26] = PIN_NONE,
- [27] = PIN_NONE,
- [28] = PIN_NONE,
- [29] = PIN_NONE,
- [30] = PIN_NONE,
- [31] = PIN_NONE,
+ [ 7] = SH_PFC_PIN_NONE,
+ [ 8] = SH_PFC_PIN_NONE,
+ [ 9] = SH_PFC_PIN_NONE,
+ [10] = SH_PFC_PIN_NONE,
+ [11] = SH_PFC_PIN_NONE,
+ [12] = SH_PFC_PIN_NONE,
+ [13] = SH_PFC_PIN_NONE,
+ [14] = SH_PFC_PIN_NONE,
+ [15] = SH_PFC_PIN_NONE,
+ [16] = SH_PFC_PIN_NONE,
+ [17] = SH_PFC_PIN_NONE,
+ [18] = SH_PFC_PIN_NONE,
+ [19] = SH_PFC_PIN_NONE,
+ [20] = SH_PFC_PIN_NONE,
+ [21] = SH_PFC_PIN_NONE,
+ [22] = SH_PFC_PIN_NONE,
+ [23] = SH_PFC_PIN_NONE,
+ [24] = SH_PFC_PIN_NONE,
+ [25] = SH_PFC_PIN_NONE,
+ [26] = SH_PFC_PIN_NONE,
+ [27] = SH_PFC_PIN_NONE,
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
} },
{ /* sentinel */ },
};
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a77965.c b/drivers/pinctrl/sh-pfc/pfc-r8a77965.c
index 090024355eba..697c77a4ea95 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a77965.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a77965.c
@@ -18,11 +18,9 @@
#include "core.h"
#include "sh_pfc.h"
-#define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | \
- SH_PFC_PIN_CFG_PULL_UP | \
- SH_PFC_PIN_CFG_PULL_DOWN)
+#define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | SH_PFC_PIN_CFG_PULL_UP_DOWN)
-#define CPU_ALL_PORT(fn, sfx) \
+#define CPU_ALL_GP(fn, sfx) \
PORT_GP_CFG_16(0, fn, sfx, CFG_FLAGS), \
PORT_GP_CFG_29(1, fn, sfx, CFG_FLAGS), \
PORT_GP_CFG_15(2, fn, sfx, CFG_FLAGS), \
@@ -35,6 +33,51 @@
PORT_GP_CFG_26(5, fn, sfx, CFG_FLAGS), \
PORT_GP_CFG_32(6, fn, sfx, CFG_FLAGS), \
PORT_GP_CFG_4(7, fn, sfx, CFG_FLAGS)
+
+#define CPU_ALL_NOGP(fn) \
+ PIN_NOGP_CFG(ASEBRK, "ASEBRK", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_MDIO, "AVB_MDIO", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_RD0, "AVB_RD0", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_RD1, "AVB_RD1", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_RD2, "AVB_RD2", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_RD3, "AVB_RD3", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_RXC, "AVB_RXC", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_RX_CTL, "AVB_RX_CTL", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TD0, "AVB_TD0", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TD1, "AVB_TD1", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TD2, "AVB_TD2", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TD3, "AVB_TD3", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TXC, "AVB_TXC", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TXCREFCLK, "AVB_TXCREFCLK", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TX_CTL, "AVB_TX_CTL", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(DU_DOTCLKIN0, "DU_DOTCLKIN0", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(DU_DOTCLKIN1, "DU_DOTCLKIN1", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(DU_DOTCLKIN3, "DU_DOTCLKIN3", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(EXTALR, "EXTALR", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN),\
+ PIN_NOGP_CFG(FSCLKST, "FSCLKST", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(MLB_REF, "MLB_REF", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(PRESETOUT_N, "PRESETOUT#", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI0_IO2, "QSPI0_IO2", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI0_IO3, "QSPI0_IO3", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI0_MISO_IO1, "QSPI0_MISO_IO1", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI0_MOSI_IO0, "QSPI0_MOSI_IO0", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI0_SPCLK, "QSPI0_SPCLK", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI0_SSL, "QSPI0_SSL", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI1_IO2, "QSPI1_IO2", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI1_IO3, "QSPI1_IO3", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI1_MISO_IO1, "QSPI1_MISO_IO1", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI1_MOSI_IO0, "QSPI1_MOSI_IO0", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI1_SPCLK, "QSPI1_SPCLK", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(QSPI1_SSL, "QSPI1_SSL", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(RPC_INT_N, "RPC_INT#", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(RPC_RESET_N, "RPC_RESET#", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(RPC_WP_N, "RPC_WP#", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(TCK, "TCK", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \
+ PIN_NOGP_CFG(TDI, "TDI", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \
+ PIN_NOGP_CFG(TDO, "TDO", fn, SH_PFC_PIN_CFG_DRIVE_STRENGTH), \
+ PIN_NOGP_CFG(TMS, "TMS", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(TRST_N, "TRST#", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN)
+
/*
* F_() : just information
* FM() : macro for FN_xxx / xxx_MARK
@@ -1517,67 +1560,16 @@ static const u16 pinmux_data[] = {
};
/*
- * R8A77965 has 8 banks with 32 GPIOs in each => 256 GPIOs.
- * Physical layout rows: A - AW, cols: 1 - 39.
+ * Pins not associated with a GPIO port.
*/
-#define ROW_GROUP_A(r) ('Z' - 'A' + 1 + (r))
-#define PIN_NUMBER(r, c) (((r) - 'A') * 39 + (c) + 300)
-#define PIN_A_NUMBER(r, c) PIN_NUMBER(ROW_GROUP_A(r), c)
-#define PIN_NONE U16_MAX
+enum {
+ GP_ASSIGN_LAST(),
+ NOGP_ALL(),
+};
static const struct sh_pfc_pin pinmux_pins[] = {
PINMUX_GPIO_GP_ALL(),
-
- /*
- * Pins not associated with a GPIO port.
- *
- * The pin positions are different between different r8a77965
- * packages, all that is needed for the pfc driver is a unique
- * number for each pin. To this end use the pin layout from
- * R-Car M3SiP to calculate a unique number for each pin.
- */
- SH_PFC_PIN_NAMED_CFG('A', 8, AVB_TX_CTL, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 9, AVB_MDIO, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 12, AVB_TXCREFCLK, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 13, AVB_RD0, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 14, AVB_RD2, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 16, AVB_RX_CTL, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 17, AVB_TD2, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 18, AVB_TD0, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('A', 19, AVB_TXC, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('B', 13, AVB_RD1, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('B', 14, AVB_RD3, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('B', 17, AVB_TD3, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('B', 18, AVB_TD1, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('B', 19, AVB_RXC, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('C', 1, PRESETOUT#, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('H', 37, MLB_REF, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('V', 3, QSPI1_SPCLK, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('V', 5, QSPI1_SSL, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('V', 6, RPC_WP#, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('V', 7, RPC_RESET#, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('W', 3, QSPI0_SPCLK, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('Y', 3, QSPI0_SSL, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('Y', 6, QSPI0_IO2, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('Y', 7, RPC_INT#, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'), 4, QSPI0_MISO_IO1, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'), 6, QSPI0_IO3, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 3, QSPI1_IO3, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 5, QSPI0_MOSI_IO0, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 7, QSPI1_MOSI_IO0, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 38, FSCLKST, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 39, EXTALR, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'), 4, QSPI1_IO2, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'), 5, QSPI1_MISO_IO1, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'), 7, DU_DOTCLKIN0, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'), 8, DU_DOTCLKIN1, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 8, DU_DOTCLKIN3, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 26, TRST#, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 29, TDI, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 30, TMS, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 27, TCK, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 28, TDO, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 30, ASEBRK, CFG_FLAGS),
+ PINMUX_NOGP_ALL(),
};
/* - AUDIO CLOCK ------------------------------------------------------------ */
@@ -1726,7 +1718,7 @@ static const unsigned int avb_phy_int_mux[] = {
};
static const unsigned int avb_mdio_pins[] = {
/* AVB_MDC, AVB_MDIO */
- RCAR_GP_PIN(2, 9), PIN_NUMBER('A', 9),
+ RCAR_GP_PIN(2, 9), PIN_AVB_MDIO,
};
static const unsigned int avb_mdio_mux[] = {
AVB_MDC_MARK, AVB_MDIO_MARK,
@@ -1739,11 +1731,11 @@ static const unsigned int avb_mii_pins[] = {
* AVB_RD1, AVB_RD2, AVB_RD3,
* AVB_TXCREFCLK
*/
- PIN_NUMBER('A', 8), PIN_NUMBER('A', 19), PIN_NUMBER('A', 18),
- PIN_NUMBER('B', 18), PIN_NUMBER('A', 17), PIN_NUMBER('B', 17),
- PIN_NUMBER('A', 16), PIN_NUMBER('B', 19), PIN_NUMBER('A', 13),
- PIN_NUMBER('B', 13), PIN_NUMBER('A', 14), PIN_NUMBER('B', 14),
- PIN_NUMBER('A', 12),
+ PIN_AVB_TX_CTL, PIN_AVB_TXC, PIN_AVB_TD0,
+ PIN_AVB_TD1, PIN_AVB_TD2, PIN_AVB_TD3,
+ PIN_AVB_RX_CTL, PIN_AVB_RXC, PIN_AVB_RD0,
+ PIN_AVB_RD1, PIN_AVB_RD2, PIN_AVB_RD3,
+ PIN_AVB_TXCREFCLK,
};
static const unsigned int avb_mii_mux[] = {
@@ -4116,6 +4108,36 @@ static const unsigned int tmu_tclk2_b_mux[] = {
TCLK2_B_MARK,
};
+/* - TPU ------------------------------------------------------------------- */
+static const unsigned int tpu_to0_pins[] = {
+ /* TPU0TO0 */
+ RCAR_GP_PIN(6, 28),
+};
+static const unsigned int tpu_to0_mux[] = {
+ TPU0TO0_MARK,
+};
+static const unsigned int tpu_to1_pins[] = {
+ /* TPU0TO1 */
+ RCAR_GP_PIN(6, 29),
+};
+static const unsigned int tpu_to1_mux[] = {
+ TPU0TO1_MARK,
+};
+static const unsigned int tpu_to2_pins[] = {
+ /* TPU0TO2 */
+ RCAR_GP_PIN(6, 30),
+};
+static const unsigned int tpu_to2_mux[] = {
+ TPU0TO2_MARK,
+};
+static const unsigned int tpu_to3_pins[] = {
+ /* TPU0TO3 */
+ RCAR_GP_PIN(6, 31),
+};
+static const unsigned int tpu_to3_mux[] = {
+ TPU0TO3_MARK,
+};
+
/* - USB0 ------------------------------------------------------------------- */
static const unsigned int usb0_pins[] = {
/* PWEN, OVC */
@@ -4672,6 +4694,10 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(tmu_tclk1_b),
SH_PFC_PIN_GROUP(tmu_tclk2_a),
SH_PFC_PIN_GROUP(tmu_tclk2_b),
+ SH_PFC_PIN_GROUP(tpu_to0),
+ SH_PFC_PIN_GROUP(tpu_to1),
+ SH_PFC_PIN_GROUP(tpu_to2),
+ SH_PFC_PIN_GROUP(tpu_to3),
SH_PFC_PIN_GROUP(usb0),
SH_PFC_PIN_GROUP(usb1),
SH_PFC_PIN_GROUP(usb30),
@@ -5164,6 +5190,13 @@ static const char * const tmu_groups[] = {
"tmu_tclk2_b",
};
+static const char * const tpu_groups[] = {
+ "tpu_to0",
+ "tpu_to1",
+ "tpu_to2",
+ "tpu_to3",
+};
+
static const char * const usb0_groups[] = {
"usb0",
};
@@ -5258,6 +5291,7 @@ static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(sdhi3),
SH_PFC_FUNCTION(ssi),
SH_PFC_FUNCTION(tmu),
+ SH_PFC_FUNCTION(tpu),
SH_PFC_FUNCTION(usb0),
SH_PFC_FUNCTION(usb1),
SH_PFC_FUNCTION(usb30),
@@ -5830,44 +5864,44 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
static const struct pinmux_drive_reg pinmux_drive_regs[] = {
{ PINMUX_DRIVE_REG("DRVCTRL0", 0xe6060300) {
- { PIN_NUMBER('W', 3), 28, 2 }, /* QSPI0_SPCLK */
- { PIN_A_NUMBER('C', 5), 24, 2 }, /* QSPI0_MOSI_IO0 */
- { PIN_A_NUMBER('B', 4), 20, 2 }, /* QSPI0_MISO_IO1 */
- { PIN_NUMBER('Y', 6), 16, 2 }, /* QSPI0_IO2 */
- { PIN_A_NUMBER('B', 6), 12, 2 }, /* QSPI0_IO3 */
- { PIN_NUMBER('Y', 3), 8, 2 }, /* QSPI0_SSL */
- { PIN_NUMBER('V', 3), 4, 2 }, /* QSPI1_SPCLK */
- { PIN_A_NUMBER('C', 7), 0, 2 }, /* QSPI1_MOSI_IO0 */
+ { PIN_QSPI0_SPCLK, 28, 2 }, /* QSPI0_SPCLK */
+ { PIN_QSPI0_MOSI_IO0, 24, 2 }, /* QSPI0_MOSI_IO0 */
+ { PIN_QSPI0_MISO_IO1, 20, 2 }, /* QSPI0_MISO_IO1 */
+ { PIN_QSPI0_IO2, 16, 2 }, /* QSPI0_IO2 */
+ { PIN_QSPI0_IO3, 12, 2 }, /* QSPI0_IO3 */
+ { PIN_QSPI0_SSL, 8, 2 }, /* QSPI0_SSL */
+ { PIN_QSPI1_SPCLK, 4, 2 }, /* QSPI1_SPCLK */
+ { PIN_QSPI1_MOSI_IO0, 0, 2 }, /* QSPI1_MOSI_IO0 */
} },
{ PINMUX_DRIVE_REG("DRVCTRL1", 0xe6060304) {
- { PIN_A_NUMBER('E', 5), 28, 2 }, /* QSPI1_MISO_IO1 */
- { PIN_A_NUMBER('E', 4), 24, 2 }, /* QSPI1_IO2 */
- { PIN_A_NUMBER('C', 3), 20, 2 }, /* QSPI1_IO3 */
- { PIN_NUMBER('V', 5), 16, 2 }, /* QSPI1_SSL */
- { PIN_NUMBER('Y', 7), 12, 2 }, /* RPC_INT# */
- { PIN_NUMBER('V', 6), 8, 2 }, /* RPC_WP# */
- { PIN_NUMBER('V', 7), 4, 2 }, /* RPC_RESET# */
- { PIN_NUMBER('A', 16), 0, 3 }, /* AVB_RX_CTL */
+ { PIN_QSPI1_MISO_IO1, 28, 2 }, /* QSPI1_MISO_IO1 */
+ { PIN_QSPI1_IO2, 24, 2 }, /* QSPI1_IO2 */
+ { PIN_QSPI1_IO3, 20, 2 }, /* QSPI1_IO3 */
+ { PIN_QSPI1_SSL, 16, 2 }, /* QSPI1_SSL */
+ { PIN_RPC_INT_N, 12, 2 }, /* RPC_INT# */
+ { PIN_RPC_WP_N, 8, 2 }, /* RPC_WP# */
+ { PIN_RPC_RESET_N, 4, 2 }, /* RPC_RESET# */
+ { PIN_AVB_RX_CTL, 0, 3 }, /* AVB_RX_CTL */
} },
{ PINMUX_DRIVE_REG("DRVCTRL2", 0xe6060308) {
- { PIN_NUMBER('B', 19), 28, 3 }, /* AVB_RXC */
- { PIN_NUMBER('A', 13), 24, 3 }, /* AVB_RD0 */
- { PIN_NUMBER('B', 13), 20, 3 }, /* AVB_RD1 */
- { PIN_NUMBER('A', 14), 16, 3 }, /* AVB_RD2 */
- { PIN_NUMBER('B', 14), 12, 3 }, /* AVB_RD3 */
- { PIN_NUMBER('A', 8), 8, 3 }, /* AVB_TX_CTL */
- { PIN_NUMBER('A', 19), 4, 3 }, /* AVB_TXC */
- { PIN_NUMBER('A', 18), 0, 3 }, /* AVB_TD0 */
+ { PIN_AVB_RXC, 28, 3 }, /* AVB_RXC */
+ { PIN_AVB_RD0, 24, 3 }, /* AVB_RD0 */
+ { PIN_AVB_RD1, 20, 3 }, /* AVB_RD1 */
+ { PIN_AVB_RD2, 16, 3 }, /* AVB_RD2 */
+ { PIN_AVB_RD3, 12, 3 }, /* AVB_RD3 */
+ { PIN_AVB_TX_CTL, 8, 3 }, /* AVB_TX_CTL */
+ { PIN_AVB_TXC, 4, 3 }, /* AVB_TXC */
+ { PIN_AVB_TD0, 0, 3 }, /* AVB_TD0 */
} },
{ PINMUX_DRIVE_REG("DRVCTRL3", 0xe606030c) {
- { PIN_NUMBER('B', 18), 28, 3 }, /* AVB_TD1 */
- { PIN_NUMBER('A', 17), 24, 3 }, /* AVB_TD2 */
- { PIN_NUMBER('B', 17), 20, 3 }, /* AVB_TD3 */
- { PIN_NUMBER('A', 12), 16, 3 }, /* AVB_TXCREFCLK */
- { PIN_NUMBER('A', 9), 12, 3 }, /* AVB_MDIO */
- { RCAR_GP_PIN(2, 9), 8, 3 }, /* AVB_MDC */
- { RCAR_GP_PIN(2, 10), 4, 3 }, /* AVB_MAGIC */
- { RCAR_GP_PIN(2, 11), 0, 3 }, /* AVB_PHY_INT */
+ { PIN_AVB_TD1, 28, 3 }, /* AVB_TD1 */
+ { PIN_AVB_TD2, 24, 3 }, /* AVB_TD2 */
+ { PIN_AVB_TD3, 20, 3 }, /* AVB_TD3 */
+ { PIN_AVB_TXCREFCLK, 16, 3 }, /* AVB_TXCREFCLK */
+ { PIN_AVB_MDIO, 12, 3 }, /* AVB_MDIO */
+ { RCAR_GP_PIN(2, 9), 8, 3 }, /* AVB_MDC */
+ { RCAR_GP_PIN(2, 10), 4, 3 }, /* AVB_MAGIC */
+ { RCAR_GP_PIN(2, 11), 0, 3 }, /* AVB_PHY_INT */
} },
{ PINMUX_DRIVE_REG("DRVCTRL4", 0xe6060310) {
{ RCAR_GP_PIN(2, 12), 28, 3 }, /* AVB_LINK */
@@ -5921,7 +5955,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = {
} },
{ PINMUX_DRIVE_REG("DRVCTRL9", 0xe6060324) {
{ RCAR_GP_PIN(1, 27), 28, 3 }, /* EX_WAIT0 */
- { PIN_NUMBER('C', 1), 24, 3 }, /* PRESETOUT# */
+ { PIN_PRESETOUT_N, 24, 3 }, /* PRESETOUT# */
{ RCAR_GP_PIN(0, 0), 20, 3 }, /* D0 */
{ RCAR_GP_PIN(0, 1), 16, 3 }, /* D1 */
{ RCAR_GP_PIN(0, 2), 12, 3 }, /* D2 */
@@ -5940,29 +5974,29 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = {
{ RCAR_GP_PIN(0, 13), 0, 3 }, /* D13 */
} },
{ PINMUX_DRIVE_REG("DRVCTRL11", 0xe606032c) {
- { RCAR_GP_PIN(0, 14), 28, 3 }, /* D14 */
- { RCAR_GP_PIN(0, 15), 24, 3 }, /* D15 */
- { RCAR_GP_PIN(7, 0), 20, 3 }, /* AVS1 */
- { RCAR_GP_PIN(7, 1), 16, 3 }, /* AVS2 */
- { RCAR_GP_PIN(7, 2), 12, 3 }, /* GP7_02 */
- { RCAR_GP_PIN(7, 3), 8, 3 }, /* GP7_03 */
- { PIN_A_NUMBER('P', 7), 4, 2 }, /* DU_DOTCLKIN0 */
- { PIN_A_NUMBER('P', 8), 0, 2 }, /* DU_DOTCLKIN1 */
+ { RCAR_GP_PIN(0, 14), 28, 3 }, /* D14 */
+ { RCAR_GP_PIN(0, 15), 24, 3 }, /* D15 */
+ { RCAR_GP_PIN(7, 0), 20, 3 }, /* AVS1 */
+ { RCAR_GP_PIN(7, 1), 16, 3 }, /* AVS2 */
+ { RCAR_GP_PIN(7, 2), 12, 3 }, /* GP7_02 */
+ { RCAR_GP_PIN(7, 3), 8, 3 }, /* GP7_03 */
+ { PIN_DU_DOTCLKIN0, 4, 2 }, /* DU_DOTCLKIN0 */
+ { PIN_DU_DOTCLKIN1, 0, 2 }, /* DU_DOTCLKIN1 */
} },
{ PINMUX_DRIVE_REG("DRVCTRL12", 0xe6060330) {
- { PIN_A_NUMBER('R', 8), 28, 2 }, /* DU_DOTCLKIN3 */
- { PIN_A_NUMBER('D', 38), 20, 2 }, /* FSCLKST */
- { PIN_A_NUMBER('R', 30), 4, 2 }, /* TMS */
+ { PIN_DU_DOTCLKIN3, 28, 2 }, /* DU_DOTCLKIN3 */
+ { PIN_FSCLKST, 20, 2 }, /* FSCLKST */
+ { PIN_TMS, 4, 2 }, /* TMS */
} },
{ PINMUX_DRIVE_REG("DRVCTRL13", 0xe6060334) {
- { PIN_A_NUMBER('T', 28), 28, 2 }, /* TDO */
- { PIN_A_NUMBER('T', 30), 24, 2 }, /* ASEBRK */
- { RCAR_GP_PIN(3, 0), 20, 3 }, /* SD0_CLK */
- { RCAR_GP_PIN(3, 1), 16, 3 }, /* SD0_CMD */
- { RCAR_GP_PIN(3, 2), 12, 3 }, /* SD0_DAT0 */
- { RCAR_GP_PIN(3, 3), 8, 3 }, /* SD0_DAT1 */
- { RCAR_GP_PIN(3, 4), 4, 3 }, /* SD0_DAT2 */
- { RCAR_GP_PIN(3, 5), 0, 3 }, /* SD0_DAT3 */
+ { PIN_TDO, 28, 2 }, /* TDO */
+ { PIN_ASEBRK, 24, 2 }, /* ASEBRK */
+ { RCAR_GP_PIN(3, 0), 20, 3 }, /* SD0_CLK */
+ { RCAR_GP_PIN(3, 1), 16, 3 }, /* SD0_CMD */
+ { RCAR_GP_PIN(3, 2), 12, 3 }, /* SD0_DAT0 */
+ { RCAR_GP_PIN(3, 3), 8, 3 }, /* SD0_DAT1 */
+ { RCAR_GP_PIN(3, 4), 4, 3 }, /* SD0_DAT2 */
+ { RCAR_GP_PIN(3, 5), 0, 3 }, /* SD0_DAT3 */
} },
{ PINMUX_DRIVE_REG("DRVCTRL14", 0xe6060338) {
{ RCAR_GP_PIN(3, 6), 28, 3 }, /* SD1_CLK */
@@ -6031,7 +6065,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = {
{ RCAR_GP_PIN(5, 23), 16, 3 }, /* MLB_CLK */
{ RCAR_GP_PIN(5, 24), 12, 3 }, /* MLB_SIG */
{ RCAR_GP_PIN(5, 25), 8, 3 }, /* MLB_DAT */
- { PIN_NUMBER('H', 37), 4, 3 }, /* MLB_REF */
+ { PIN_MLB_REF, 4, 3 }, /* MLB_REF */
{ RCAR_GP_PIN(6, 0), 0, 3 }, /* SSI_SCK01239 */
} },
{ PINMUX_DRIVE_REG("DRVCTRL21", 0xe6060354) {
@@ -6104,35 +6138,35 @@ static int r8a77965_pin_to_pocctrl(struct sh_pfc *pfc, unsigned int pin, u32 *po
static const struct pinmux_bias_reg pinmux_bias_regs[] = {
{ PINMUX_BIAS_REG("PUEN0", 0xe6060400, "PUD0", 0xe6060440) {
- [ 0] = PIN_NUMBER('W', 3), /* QSPI0_SPCLK */
- [ 1] = PIN_A_NUMBER('C', 5), /* QSPI0_MOSI_IO0 */
- [ 2] = PIN_A_NUMBER('B', 4), /* QSPI0_MISO_IO1 */
- [ 3] = PIN_NUMBER('Y', 6), /* QSPI0_IO2 */
- [ 4] = PIN_A_NUMBER('B', 6), /* QSPI0_IO3 */
- [ 5] = PIN_NUMBER('Y', 3), /* QSPI0_SSL */
- [ 6] = PIN_NUMBER('V', 3), /* QSPI1_SPCLK */
- [ 7] = PIN_A_NUMBER('C', 7), /* QSPI1_MOSI_IO0 */
- [ 8] = PIN_A_NUMBER('E', 5), /* QSPI1_MISO_IO1 */
- [ 9] = PIN_A_NUMBER('E', 4), /* QSPI1_IO2 */
- [10] = PIN_A_NUMBER('C', 3), /* QSPI1_IO3 */
- [11] = PIN_NUMBER('V', 5), /* QSPI1_SSL */
- [12] = PIN_NUMBER('Y', 7), /* RPC_INT# */
- [13] = PIN_NUMBER('V', 6), /* RPC_WP# */
- [14] = PIN_NUMBER('V', 7), /* RPC_RESET# */
- [15] = PIN_NUMBER('A', 16), /* AVB_RX_CTL */
- [16] = PIN_NUMBER('B', 19), /* AVB_RXC */
- [17] = PIN_NUMBER('A', 13), /* AVB_RD0 */
- [18] = PIN_NUMBER('B', 13), /* AVB_RD1 */
- [19] = PIN_NUMBER('A', 14), /* AVB_RD2 */
- [20] = PIN_NUMBER('B', 14), /* AVB_RD3 */
- [21] = PIN_NUMBER('A', 8), /* AVB_TX_CTL */
- [22] = PIN_NUMBER('A', 19), /* AVB_TXC */
- [23] = PIN_NUMBER('A', 18), /* AVB_TD0 */
- [24] = PIN_NUMBER('B', 18), /* AVB_TD1 */
- [25] = PIN_NUMBER('A', 17), /* AVB_TD2 */
- [26] = PIN_NUMBER('B', 17), /* AVB_TD3 */
- [27] = PIN_NUMBER('A', 12), /* AVB_TXCREFCLK */
- [28] = PIN_NUMBER('A', 9), /* AVB_MDIO */
+ [ 0] = PIN_QSPI0_SPCLK, /* QSPI0_SPCLK */
+ [ 1] = PIN_QSPI0_MOSI_IO0, /* QSPI0_MOSI_IO0 */
+ [ 2] = PIN_QSPI0_MISO_IO1, /* QSPI0_MISO_IO1 */
+ [ 3] = PIN_QSPI0_IO2, /* QSPI0_IO2 */
+ [ 4] = PIN_QSPI0_IO3, /* QSPI0_IO3 */
+ [ 5] = PIN_QSPI0_SSL, /* QSPI0_SSL */
+ [ 6] = PIN_QSPI1_SPCLK, /* QSPI1_SPCLK */
+ [ 7] = PIN_QSPI1_MOSI_IO0, /* QSPI1_MOSI_IO0 */
+ [ 8] = PIN_QSPI1_MISO_IO1, /* QSPI1_MISO_IO1 */
+ [ 9] = PIN_QSPI1_IO2, /* QSPI1_IO2 */
+ [10] = PIN_QSPI1_IO3, /* QSPI1_IO3 */
+ [11] = PIN_QSPI1_SSL, /* QSPI1_SSL */
+ [12] = PIN_RPC_INT_N, /* RPC_INT# */
+ [13] = PIN_RPC_WP_N, /* RPC_WP# */
+ [14] = PIN_RPC_RESET_N, /* RPC_RESET# */
+ [15] = PIN_AVB_RX_CTL, /* AVB_RX_CTL */
+ [16] = PIN_AVB_RXC, /* AVB_RXC */
+ [17] = PIN_AVB_RD0, /* AVB_RD0 */
+ [18] = PIN_AVB_RD1, /* AVB_RD1 */
+ [19] = PIN_AVB_RD2, /* AVB_RD2 */
+ [20] = PIN_AVB_RD3, /* AVB_RD3 */
+ [21] = PIN_AVB_TX_CTL, /* AVB_TX_CTL */
+ [22] = PIN_AVB_TXC, /* AVB_TXC */
+ [23] = PIN_AVB_TD0, /* AVB_TD0 */
+ [24] = PIN_AVB_TD1, /* AVB_TD1 */
+ [25] = PIN_AVB_TD2, /* AVB_TD2 */
+ [26] = PIN_AVB_TD3, /* AVB_TD3 */
+ [27] = PIN_AVB_TXCREFCLK, /* AVB_TXCREFCLK */
+ [28] = PIN_AVB_MDIO, /* AVB_MDIO */
[29] = RCAR_GP_PIN(2, 9), /* AVB_MDC */
[30] = RCAR_GP_PIN(2, 10), /* AVB_MAGIC */
[31] = RCAR_GP_PIN(2, 11), /* AVB_PHY_INT */
@@ -6181,7 +6215,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
[ 6] = RCAR_GP_PIN(1, 25), /* WE0_N */
[ 7] = RCAR_GP_PIN(1, 26), /* WE1_N */
[ 8] = RCAR_GP_PIN(1, 27), /* EX_WAIT0_A */
- [ 9] = PIN_NUMBER('C', 1), /* PRESETOUT# */
+ [ 9] = PIN_PRESETOUT_N, /* PRESETOUT# */
[10] = RCAR_GP_PIN(0, 0), /* D0 */
[11] = RCAR_GP_PIN(0, 1), /* D1 */
[12] = RCAR_GP_PIN(0, 2), /* D2 */
@@ -6202,20 +6236,20 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
[27] = RCAR_GP_PIN(7, 1), /* AVS2 */
[28] = RCAR_GP_PIN(7, 2), /* GP7_02 */
[29] = RCAR_GP_PIN(7, 3), /* GP7_03 */
- [30] = PIN_A_NUMBER('P', 7), /* DU_DOTCLKIN0 */
- [31] = PIN_A_NUMBER('P', 8), /* DU_DOTCLKIN1 */
+ [30] = PIN_DU_DOTCLKIN0, /* DU_DOTCLKIN0 */
+ [31] = PIN_DU_DOTCLKIN1, /* DU_DOTCLKIN1 */
} },
{ PINMUX_BIAS_REG("PUEN3", 0xe606040c, "PUD3", 0xe606044c) {
- [ 0] = PIN_A_NUMBER('R', 8), /* DU_DOTCLKIN3 */
- [ 1] = PIN_NONE,
- [ 2] = PIN_A_NUMBER('D', 38), /* FSCLKST */
- [ 3] = PIN_A_NUMBER('D', 39), /* EXTALR*/
- [ 4] = PIN_A_NUMBER('R', 26), /* TRST# */
- [ 5] = PIN_A_NUMBER('T', 27), /* TCK */
- [ 6] = PIN_A_NUMBER('R', 30), /* TMS */
- [ 7] = PIN_A_NUMBER('R', 29), /* TDI */
- [ 8] = PIN_NONE,
- [ 9] = PIN_A_NUMBER('T', 30), /* ASEBRK */
+ [ 0] = PIN_DU_DOTCLKIN3, /* DU_DOTCLKIN3 */
+ [ 1] = SH_PFC_PIN_NONE,
+ [ 2] = PIN_FSCLKST, /* FSCLKST */
+ [ 3] = PIN_EXTALR, /* EXTALR*/
+ [ 4] = PIN_TRST_N, /* TRST# */
+ [ 5] = PIN_TCK, /* TCK */
+ [ 6] = PIN_TMS, /* TMS */
+ [ 7] = PIN_TDI, /* TDI */
+ [ 8] = SH_PFC_PIN_NONE,
+ [ 9] = PIN_ASEBRK, /* ASEBRK */
[10] = RCAR_GP_PIN(3, 0), /* SD0_CLK */
[11] = RCAR_GP_PIN(3, 1), /* SD0_CMD */
[12] = RCAR_GP_PIN(3, 2), /* SD0_DAT0 */
@@ -6280,7 +6314,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
[ 3] = RCAR_GP_PIN(5, 23), /* MLB_CLK */
[ 4] = RCAR_GP_PIN(5, 24), /* MLB_SIG */
[ 5] = RCAR_GP_PIN(5, 25), /* MLB_DAT */
- [ 6] = PIN_NUMBER('H', 37), /* MLB_REF */
+ [ 6] = PIN_MLB_REF, /* MLB_REF */
[ 7] = RCAR_GP_PIN(6, 0), /* SSI_SCK01239 */
[ 8] = RCAR_GP_PIN(6, 1), /* SSI_WS01239 */
[ 9] = RCAR_GP_PIN(6, 2), /* SSI_SDATA0 */
@@ -6315,31 +6349,31 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
[ 4] = RCAR_GP_PIN(6, 29), /* USB30_OVC */
[ 5] = RCAR_GP_PIN(6, 30), /* GP6_30 */
[ 6] = RCAR_GP_PIN(6, 31), /* GP6_31 */
- [ 7] = PIN_NONE,
- [ 8] = PIN_NONE,
- [ 9] = PIN_NONE,
- [10] = PIN_NONE,
- [11] = PIN_NONE,
- [12] = PIN_NONE,
- [13] = PIN_NONE,
- [14] = PIN_NONE,
- [15] = PIN_NONE,
- [16] = PIN_NONE,
- [17] = PIN_NONE,
- [18] = PIN_NONE,
- [19] = PIN_NONE,
- [20] = PIN_NONE,
- [21] = PIN_NONE,
- [22] = PIN_NONE,
- [23] = PIN_NONE,
- [24] = PIN_NONE,
- [25] = PIN_NONE,
- [26] = PIN_NONE,
- [27] = PIN_NONE,
- [28] = PIN_NONE,
- [29] = PIN_NONE,
- [30] = PIN_NONE,
- [31] = PIN_NONE,
+ [ 7] = SH_PFC_PIN_NONE,
+ [ 8] = SH_PFC_PIN_NONE,
+ [ 9] = SH_PFC_PIN_NONE,
+ [10] = SH_PFC_PIN_NONE,
+ [11] = SH_PFC_PIN_NONE,
+ [12] = SH_PFC_PIN_NONE,
+ [13] = SH_PFC_PIN_NONE,
+ [14] = SH_PFC_PIN_NONE,
+ [15] = SH_PFC_PIN_NONE,
+ [16] = SH_PFC_PIN_NONE,
+ [17] = SH_PFC_PIN_NONE,
+ [18] = SH_PFC_PIN_NONE,
+ [19] = SH_PFC_PIN_NONE,
+ [20] = SH_PFC_PIN_NONE,
+ [21] = SH_PFC_PIN_NONE,
+ [22] = SH_PFC_PIN_NONE,
+ [23] = SH_PFC_PIN_NONE,
+ [24] = SH_PFC_PIN_NONE,
+ [25] = SH_PFC_PIN_NONE,
+ [26] = SH_PFC_PIN_NONE,
+ [27] = SH_PFC_PIN_NONE,
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
} },
{ /* sentinel */ },
};
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a77970.c b/drivers/pinctrl/sh-pfc/pfc-r8a77970.c
index 2d76b548b942..25e27b6bee89 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a77970.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a77970.c
@@ -19,7 +19,7 @@
#include "core.h"
#include "sh_pfc.h"
-#define CPU_ALL_PORT(fn, sfx) \
+#define CPU_ALL_GP(fn, sfx) \
PORT_GP_CFG_22(0, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
PORT_GP_28(1, fn, sfx), \
PORT_GP_CFG_17(2, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
@@ -205,8 +205,8 @@
#define IP6_19_16 FM(VI1_DATA8) F_(0, 0) FM(CTS4_N) FM(D11) FM(MMC_D5) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP6_23_20 FM(VI1_DATA9) F_(0, 0) FM(RTS4_N) FM(D12) FM(MMC_D6) FM(SCL3_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP6_27_24 FM(VI1_DATA10) F_(0, 0) F_(0, 0) FM(D13) FM(MMC_D7) FM(SDA3_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP6_31_28 FM(VI1_DATA11) FM(SCL4) FM(IRQ4) FM(D14) FM(MMC_WP) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP7_3_0 FM(VI1_FIELD) FM(SDA4) FM(IRQ5) FM(D15) FM(MMC_CD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP6_31_28 FM(VI1_DATA11) FM(SCL4) FM(IRQ4) FM(D14) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP7_3_0 FM(VI1_FIELD) FM(SDA4) FM(IRQ5) FM(D15) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP7_7_4 FM(SCL0) FM(DU_DR0) FM(TPU0TO0) FM(CLKOUT) F_(0, 0) FM(MSIOF0_RXD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP7_11_8 FM(SDA0) FM(DU_DR1) FM(TPU0TO1) FM(BS_N) FM(SCK0) FM(MSIOF0_TXD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP7_15_12 FM(SCL1) FM(DU_DG0) FM(TPU0TO2) FM(RD_N) FM(CTS0_N) FM(MSIOF0_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
@@ -631,14 +631,12 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_GPSR(IP6_31_28, SCL4),
PINMUX_IPSR_GPSR(IP6_31_28, IRQ4),
PINMUX_IPSR_GPSR(IP6_31_28, D14),
- PINMUX_IPSR_GPSR(IP6_31_28, MMC_WP),
/* IPSR7 */
PINMUX_IPSR_GPSR(IP7_3_0, VI1_FIELD),
PINMUX_IPSR_GPSR(IP7_3_0, SDA4),
PINMUX_IPSR_GPSR(IP7_3_0, IRQ5),
PINMUX_IPSR_GPSR(IP7_3_0, D15),
- PINMUX_IPSR_GPSR(IP7_3_0, MMC_CD),
PINMUX_IPSR_GPSR(IP7_7_4, SCL0),
PINMUX_IPSR_GPSR(IP7_7_4, DU_DR0),
@@ -1121,20 +1119,6 @@ static const unsigned int mmc_ctrl_pins[] = {
static const unsigned int mmc_ctrl_mux[] = {
MMC_CLK_MARK, MMC_CMD_MARK,
};
-static const unsigned int mmc_cd_pins[] = {
- /* CD */
- RCAR_GP_PIN(3, 16),
-};
-static const unsigned int mmc_cd_mux[] = {
- MMC_CD_MARK,
-};
-static const unsigned int mmc_wp_pins[] = {
- /* WP */
- RCAR_GP_PIN(3, 15),
-};
-static const unsigned int mmc_wp_mux[] = {
- MMC_WP_MARK,
-};
/* - MSIOF0 ----------------------------------------------------------------- */
static const unsigned int msiof0_clk_pins[] = {
@@ -1726,8 +1710,6 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(mmc_data4),
SH_PFC_PIN_GROUP(mmc_data8),
SH_PFC_PIN_GROUP(mmc_ctrl),
- SH_PFC_PIN_GROUP(mmc_cd),
- SH_PFC_PIN_GROUP(mmc_wp),
SH_PFC_PIN_GROUP(msiof0_clk),
SH_PFC_PIN_GROUP(msiof0_sync),
SH_PFC_PIN_GROUP(msiof0_ss1),
@@ -1897,8 +1879,6 @@ static const char * const mmc_groups[] = {
"mmc_data4",
"mmc_data8",
"mmc_ctrl",
- "mmc_cd",
- "mmc_wp",
};
static const char * const msiof0_groups[] = {
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a77980.c b/drivers/pinctrl/sh-pfc/pfc-r8a77980.c
index 9ed4ead2dafb..14fe4032a52d 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a77980.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a77980.c
@@ -19,7 +19,7 @@
#include "core.h"
#include "sh_pfc.h"
-#define CPU_ALL_PORT(fn, sfx) \
+#define CPU_ALL_GP(fn, sfx) \
PORT_GP_CFG_22(0, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
PORT_GP_28(1, fn, sfx), \
PORT_GP_CFG_30(2, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a77990.c b/drivers/pinctrl/sh-pfc/pfc-r8a77990.c
index 91a837b02a36..2dfb8d9cfda1 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a77990.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a77990.c
@@ -17,10 +17,9 @@
#include "core.h"
#include "sh_pfc.h"
-#define CFG_FLAGS (SH_PFC_PIN_CFG_PULL_UP | \
- SH_PFC_PIN_CFG_PULL_DOWN)
+#define CFG_FLAGS (SH_PFC_PIN_CFG_PULL_UP_DOWN)
-#define CPU_ALL_PORT(fn, sfx) \
+#define CPU_ALL_GP(fn, sfx) \
PORT_GP_CFG_18(0, fn, sfx, CFG_FLAGS), \
PORT_GP_CFG_23(1, fn, sfx, CFG_FLAGS), \
PORT_GP_CFG_26(2, fn, sfx, CFG_FLAGS), \
@@ -41,6 +40,25 @@
PORT_GP_CFG_1(6, 15, fn, sfx, CFG_FLAGS), \
PORT_GP_CFG_1(6, 16, fn, sfx, CFG_FLAGS), \
PORT_GP_CFG_1(6, 17, fn, sfx, CFG_FLAGS)
+
+#define CPU_ALL_NOGP(fn) \
+ PIN_NOGP_CFG(ASEBRK, "ASEBRK", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_MDC, "AVB_MDC", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_MDIO, "AVB_MDIO", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TD0, "AVB_TD0", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TD1, "AVB_TD1", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TD2, "AVB_TD2", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TD3, "AVB_TD3", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TXC, "AVB_TXC", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(AVB_TX_CTL, "AVB_TX_CTL", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(FSCLKST_N, "FSCLKST_N", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(MLB_REF, "MLB_REF", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(PRESETOUT_N, "PRESETOUT_N", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(TCK, "TCK", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(TDI, "TDI", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(TMS, "TMS", fn, CFG_FLAGS), \
+ PIN_NOGP_CFG(TRST_N, "TRST_N", fn, CFG_FLAGS)
+
/*
* F_() : just information
* FM() : macro for FN_xxx / xxx_MARK
@@ -1277,41 +1295,16 @@ static const u16 pinmux_data[] = {
};
/*
- * R8A77990 has 7 banks with 32 GPIOs in each => 224 GPIOs.
- * Physical layout rows: A - AE, cols: 1 - 25.
+ * Pins not associated with a GPIO port.
*/
-#define ROW_GROUP_A(r) ('Z' - 'A' + 1 + (r))
-#define PIN_NUMBER(r, c) (((r) - 'A') * 25 + (c) + 300)
-#define PIN_A_NUMBER(r, c) PIN_NUMBER(ROW_GROUP_A(r), c)
-#define PIN_NONE U16_MAX
+enum {
+ GP_ASSIGN_LAST(),
+ NOGP_ALL(),
+};
static const struct sh_pfc_pin pinmux_pins[] = {
PINMUX_GPIO_GP_ALL(),
-
- /*
- * Pins not associated with a GPIO port.
- *
- * The pin positions are different between different R8A77990
- * packages, all that is needed for the pfc driver is a unique
- * number for each pin. To this end use the pin layout from
- * R8A77990 to calculate a unique number for each pin.
- */
- SH_PFC_PIN_NAMED_CFG('F', 1, TRST_N, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('F', 3, TMS, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('F', 4, TCK, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('G', 2, TDI, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('G', 3, FSCLKST_N, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('H', 1, ASEBRK, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('N', 1, AVB_TXC, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('N', 2, AVB_TD0, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('N', 3, AVB_TD1, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('N', 5, AVB_TD2, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('N', 6, AVB_TD3, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('P', 3, AVB_TX_CTL, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('P', 4, AVB_MDIO, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('P', 5, AVB_MDC, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG('T', 21, MLB_REF, CFG_FLAGS),
- SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 3, PRESETOUT_N, CFG_FLAGS),
+ PINMUX_NOGP_ALL(),
};
/* - AUDIO CLOCK ------------------------------------------------------------ */
@@ -5026,15 +5019,15 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
[0] = RCAR_GP_PIN(2, 23), /* RD# */
[1] = RCAR_GP_PIN(2, 22), /* BS# */
[2] = RCAR_GP_PIN(2, 21), /* AVB_PHY_INT */
- [3] = PIN_NUMBER('P', 5), /* AVB_MDC */
- [4] = PIN_NUMBER('P', 4), /* AVB_MDIO */
+ [3] = PIN_AVB_MDC, /* AVB_MDC */
+ [4] = PIN_AVB_MDIO, /* AVB_MDIO */
[5] = RCAR_GP_PIN(2, 20), /* AVB_TXCREFCLK */
- [6] = PIN_NUMBER('N', 6), /* AVB_TD3 */
- [7] = PIN_NUMBER('N', 5), /* AVB_TD2 */
- [8] = PIN_NUMBER('N', 3), /* AVB_TD1 */
- [9] = PIN_NUMBER('N', 2), /* AVB_TD0 */
- [10] = PIN_NUMBER('N', 1), /* AVB_TXC */
- [11] = PIN_NUMBER('P', 3), /* AVB_TX_CTL */
+ [6] = PIN_AVB_TD3, /* AVB_TD3 */
+ [7] = PIN_AVB_TD2, /* AVB_TD2 */
+ [8] = PIN_AVB_TD1, /* AVB_TD1 */
+ [9] = PIN_AVB_TD0, /* AVB_TD0 */
+ [10] = PIN_AVB_TXC, /* AVB_TXC */
+ [11] = PIN_AVB_TX_CTL, /* AVB_TX_CTL */
[12] = RCAR_GP_PIN(2, 19), /* AVB_RD3 */
[13] = RCAR_GP_PIN(2, 18), /* AVB_RD2 */
[14] = RCAR_GP_PIN(2, 17), /* AVB_RD1 */
@@ -5085,33 +5078,33 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
[25] = RCAR_GP_PIN(1, 2), /* A2 */
[26] = RCAR_GP_PIN(1, 1), /* A1 */
[27] = RCAR_GP_PIN(1, 0), /* A0 */
- [28] = PIN_NONE,
- [29] = PIN_NONE,
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
[30] = RCAR_GP_PIN(2, 25), /* PUEN_EX_WAIT0 */
[31] = RCAR_GP_PIN(2, 24), /* PUEN_RD/WR# */
} },
{ PINMUX_BIAS_REG("PUEN2", 0xe6060408, "PUD2", 0xe6060448) {
[0] = RCAR_GP_PIN(3, 1), /* SD0_CMD */
[1] = RCAR_GP_PIN(3, 0), /* SD0_CLK */
- [2] = PIN_NUMBER('H', 1), /* ASEBRK */
- [3] = PIN_NONE,
- [4] = PIN_NUMBER('G', 2), /* TDI */
- [5] = PIN_NUMBER('F', 3), /* TMS */
- [6] = PIN_NUMBER('F', 4), /* TCK */
- [7] = PIN_NUMBER('F', 1), /* TRST# */
- [8] = PIN_NONE,
- [9] = PIN_NONE,
- [10] = PIN_NONE,
- [11] = PIN_NONE,
- [12] = PIN_NONE,
- [13] = PIN_NONE,
- [14] = PIN_NONE,
- [15] = PIN_NUMBER('G', 3), /* FSCLKST# */
+ [2] = PIN_ASEBRK, /* ASEBRK */
+ [3] = SH_PFC_PIN_NONE,
+ [4] = PIN_TDI, /* TDI */
+ [5] = PIN_TMS, /* TMS */
+ [6] = PIN_TCK, /* TCK */
+ [7] = PIN_TRST_N, /* TRST# */
+ [8] = SH_PFC_PIN_NONE,
+ [9] = SH_PFC_PIN_NONE,
+ [10] = SH_PFC_PIN_NONE,
+ [11] = SH_PFC_PIN_NONE,
+ [12] = SH_PFC_PIN_NONE,
+ [13] = SH_PFC_PIN_NONE,
+ [14] = SH_PFC_PIN_NONE,
+ [15] = PIN_FSCLKST_N, /* FSCLKST# */
[16] = RCAR_GP_PIN(0, 17), /* SDA4 */
[17] = RCAR_GP_PIN(0, 16), /* SCL4 */
- [18] = PIN_NONE,
- [19] = PIN_NONE,
- [20] = PIN_A_NUMBER('D', 3), /* PRESETOUT# */
+ [18] = SH_PFC_PIN_NONE,
+ [19] = SH_PFC_PIN_NONE,
+ [20] = PIN_PRESETOUT_N, /* PRESETOUT# */
[21] = RCAR_GP_PIN(0, 15), /* D15 */
[22] = RCAR_GP_PIN(0, 14), /* D14 */
[23] = RCAR_GP_PIN(0, 13), /* D13 */
@@ -5130,8 +5123,8 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
[2] = RCAR_GP_PIN(5, 3), /* CTS0#_A */
[3] = RCAR_GP_PIN(5, 2), /* TX0_A */
[4] = RCAR_GP_PIN(5, 1), /* RX0_A */
- [5] = PIN_NONE,
- [6] = PIN_NONE,
+ [5] = SH_PFC_PIN_NONE,
+ [6] = SH_PFC_PIN_NONE,
[7] = RCAR_GP_PIN(3, 15), /* SD1_WP */
[8] = RCAR_GP_PIN(3, 14), /* SD1_CD */
[9] = RCAR_GP_PIN(3, 13), /* SD0_WP */
@@ -5175,7 +5168,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
[13] = RCAR_GP_PIN(6, 2), /* SSI_SDATA0 */
[14] = RCAR_GP_PIN(6, 1), /* SSI_WS01239 */
[15] = RCAR_GP_PIN(6, 0), /* SSI_SCK01239 */
- [16] = PIN_NUMBER('T', 21), /* MLB_REF */
+ [16] = PIN_MLB_REF, /* MLB_REF */
[17] = RCAR_GP_PIN(5, 19), /* MLB_DAT */
[18] = RCAR_GP_PIN(5, 18), /* MLB_SIG */
[19] = RCAR_GP_PIN(5, 17), /* MLB_CLK */
@@ -5193,36 +5186,36 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
[31] = RCAR_GP_PIN(5, 5), /* RX1 */
} },
{ PINMUX_BIAS_REG("PUEN5", 0xe6060414, "PUD5", 0xe6060454) {
- [0] = PIN_NONE,
- [1] = PIN_NONE,
- [2] = PIN_NONE,
- [3] = PIN_NONE,
- [4] = PIN_NONE,
- [5] = PIN_NONE,
- [6] = PIN_NONE,
- [7] = PIN_NONE,
- [8] = PIN_NONE,
- [9] = PIN_NONE,
- [10] = PIN_NONE,
- [11] = PIN_NONE,
- [12] = PIN_NONE,
- [13] = PIN_NONE,
- [14] = PIN_NONE,
- [15] = PIN_NONE,
- [16] = PIN_NONE,
- [17] = PIN_NONE,
- [18] = PIN_NONE,
- [19] = PIN_NONE,
- [20] = PIN_NONE,
- [21] = PIN_NONE,
- [22] = PIN_NONE,
- [23] = PIN_NONE,
- [24] = PIN_NONE,
- [25] = PIN_NONE,
- [26] = PIN_NONE,
- [27] = PIN_NONE,
- [28] = PIN_NONE,
- [29] = PIN_NONE,
+ [0] = SH_PFC_PIN_NONE,
+ [1] = SH_PFC_PIN_NONE,
+ [2] = SH_PFC_PIN_NONE,
+ [3] = SH_PFC_PIN_NONE,
+ [4] = SH_PFC_PIN_NONE,
+ [5] = SH_PFC_PIN_NONE,
+ [6] = SH_PFC_PIN_NONE,
+ [7] = SH_PFC_PIN_NONE,
+ [8] = SH_PFC_PIN_NONE,
+ [9] = SH_PFC_PIN_NONE,
+ [10] = SH_PFC_PIN_NONE,
+ [11] = SH_PFC_PIN_NONE,
+ [12] = SH_PFC_PIN_NONE,
+ [13] = SH_PFC_PIN_NONE,
+ [14] = SH_PFC_PIN_NONE,
+ [15] = SH_PFC_PIN_NONE,
+ [16] = SH_PFC_PIN_NONE,
+ [17] = SH_PFC_PIN_NONE,
+ [18] = SH_PFC_PIN_NONE,
+ [19] = SH_PFC_PIN_NONE,
+ [20] = SH_PFC_PIN_NONE,
+ [21] = SH_PFC_PIN_NONE,
+ [22] = SH_PFC_PIN_NONE,
+ [23] = SH_PFC_PIN_NONE,
+ [24] = SH_PFC_PIN_NONE,
+ [25] = SH_PFC_PIN_NONE,
+ [26] = SH_PFC_PIN_NONE,
+ [27] = SH_PFC_PIN_NONE,
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
[30] = RCAR_GP_PIN(6, 9), /* PUEN_USB30_OVC */
[31] = RCAR_GP_PIN(6, 17), /* PUEN_USB30_PWEN */
} },
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a77995.c b/drivers/pinctrl/sh-pfc/pfc-r8a77995.c
index dd87085d48cb..c10b756476b1 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a77995.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a77995.c
@@ -17,7 +17,7 @@
#include "core.h"
#include "sh_pfc.h"
-#define CPU_ALL_PORT(fn, sfx) \
+#define CPU_ALL_GP(fn, sfx) \
PORT_GP_9(0, fn, sfx), \
PORT_GP_32(1, fn, sfx), \
PORT_GP_32(2, fn, sfx), \
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c
index e1276d143117..afabd95105d5 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c
@@ -43,6 +43,9 @@
PORT_1(288, fn, pfx##288, sfx), PORT_1(289, fn, pfx##289, sfx), \
PORT_10(290, fn, pfx##29, sfx), PORT_10(300, fn, pfx##30, sfx)
+#define CPU_ALL_NOGP(fn) \
+ PIN_NOGP(A11, "F26", fn)
+
enum {
PINMUX_RESERVED = 0,
@@ -1147,7 +1150,7 @@ static const u16 pinmux_data[] = {
#define __IO (SH_PFC_PIN_CFG_INPUT | SH_PFC_PIN_CFG_OUTPUT)
#define __PD (SH_PFC_PIN_CFG_PULL_DOWN)
#define __PU (SH_PFC_PIN_CFG_PULL_UP)
-#define __PUD (SH_PFC_PIN_CFG_PULL_DOWN | SH_PFC_PIN_CFG_PULL_UP)
+#define __PUD (SH_PFC_PIN_CFG_PULL_UP_DOWN)
#define SH73A0_PIN_I_PD(pin) SH_PFC_PIN_CFG(pin, __I | __PD)
#define SH73A0_PIN_I_PU(pin) SH_PFC_PIN_CFG(pin, __I | __PU)
@@ -1158,11 +1161,13 @@ static const u16 pinmux_data[] = {
#define SH73A0_PIN_IO_PU_PD(pin) SH_PFC_PIN_CFG(pin, __IO | __PUD)
#define SH73A0_PIN_O(pin) SH_PFC_PIN_CFG(pin, __O)
-/* Pin numbers for pins without a corresponding GPIO port number are computed
- * from the row and column numbers with a 1000 offset to avoid collisions with
- * GPIO port numbers.
+/*
+ * Pins not associated with a GPIO port.
*/
-#define PIN_NUMBER(row, col) (1000+((row)-1)*34+(col)-1)
+enum {
+ PORT_ASSIGN_LAST(),
+ NOGP_ALL(),
+};
static const struct sh_pfc_pin pinmux_pins[] = {
/* Table 25-1 (I/O and Pull U/D) */
@@ -1437,7 +1442,7 @@ static const struct sh_pfc_pin pinmux_pins[] = {
SH73A0_PIN_O(309),
/* Pins not associated with a GPIO port */
- SH_PFC_PIN_NAMED(6, 26, F26),
+ PINMUX_NOGP_ALL(),
};
/* - BSC -------------------------------------------------------------------- */
@@ -1863,7 +1868,7 @@ static const unsigned int keysc_out7_2_mux[] = {
};
static const unsigned int keysc_out8_0_pins[] = {
/* KEYOUT8 */
- PIN_NUMBER(6, 26),
+ PIN_A11,
};
static const unsigned int keysc_out8_0_mux[] = {
KEYOUT8_MARK,
@@ -3073,7 +3078,7 @@ static const unsigned int tpu4_to2_mux[] = {
};
static const unsigned int tpu4_to3_pins[] = {
/* TO */
- PIN_NUMBER(6, 26),
+ PIN_A11,
};
static const unsigned int tpu4_to3_mux[] = {
TPU4TO3_MARK,
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7734.c b/drivers/pinctrl/sh-pfc/pfc-sh7734.c
index fac7b4699121..5dfd991ffdaa 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh7734.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7734.c
@@ -11,7 +11,7 @@
#include "sh_pfc.h"
-#define CPU_ALL_PORT(fn, sfx) \
+#define CPU_ALL_GP(fn, sfx) \
PORT_GP_32(0, fn, sfx), \
PORT_GP_32(1, fn, sfx), \
PORT_GP_32(2, fn, sfx), \
diff --git a/drivers/pinctrl/sh-pfc/pinctrl.c b/drivers/pinctrl/sh-pfc/pinctrl.c
index c97d2ba7677c..2824be4eb887 100644
--- a/drivers/pinctrl/sh-pfc/pinctrl.c
+++ b/drivers/pinctrl/sh-pfc/pinctrl.c
@@ -569,8 +569,7 @@ static bool sh_pfc_pinconf_validate(struct sh_pfc *pfc, unsigned int _pin,
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
- return pin->configs &
- (SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN);
+ return pin->configs & SH_PFC_PIN_CFG_PULL_UP_DOWN;
case PIN_CONFIG_BIAS_PULL_UP:
return pin->configs & SH_PFC_PIN_CFG_PULL_UP;
diff --git a/drivers/pinctrl/sh-pfc/sh_pfc.h b/drivers/pinctrl/sh-pfc/sh_pfc.h
index 7db5819eea7e..835148fc0f28 100644
--- a/drivers/pinctrl/sh-pfc/sh_pfc.h
+++ b/drivers/pinctrl/sh-pfc/sh_pfc.h
@@ -21,10 +21,14 @@ enum {
PINMUX_TYPE_INPUT,
};
+#define SH_PFC_PIN_NONE U16_MAX
+
#define SH_PFC_PIN_CFG_INPUT (1 << 0)
#define SH_PFC_PIN_CFG_OUTPUT (1 << 1)
#define SH_PFC_PIN_CFG_PULL_UP (1 << 2)
#define SH_PFC_PIN_CFG_PULL_DOWN (1 << 3)
+#define SH_PFC_PIN_CFG_PULL_UP_DOWN (SH_PFC_PIN_CFG_PULL_UP | \
+ SH_PFC_PIN_CFG_PULL_DOWN)
#define SH_PFC_PIN_CFG_IO_VOLTAGE (1 << 4)
#define SH_PFC_PIN_CFG_DRIVE_STRENGTH (1 << 5)
#define SH_PFC_PIN_CFG_NO_GPIO (1 << 31)
@@ -542,9 +546,13 @@ extern const struct sh_pfc_soc_info shx3_pinmux_info;
PORT_GP_CFG_1(bank, 25, fn, sfx, cfg)
#define PORT_GP_26(bank, fn, sfx) PORT_GP_CFG_26(bank, fn, sfx, 0)
-#define PORT_GP_CFG_28(bank, fn, sfx, cfg) \
+#define PORT_GP_CFG_27(bank, fn, sfx, cfg) \
PORT_GP_CFG_26(bank, fn, sfx, cfg), \
- PORT_GP_CFG_1(bank, 26, fn, sfx, cfg), \
+ PORT_GP_CFG_1(bank, 26, fn, sfx, cfg)
+#define PORT_GP_27(bank, fn, sfx) PORT_GP_CFG_27(bank, fn, sfx, 0)
+
+#define PORT_GP_CFG_28(bank, fn, sfx, cfg) \
+ PORT_GP_CFG_27(bank, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 27, fn, sfx, cfg)
#define PORT_GP_28(bank, fn, sfx) PORT_GP_CFG_28(bank, fn, sfx, 0)
@@ -584,7 +592,7 @@ extern const struct sh_pfc_soc_info shx3_pinmux_info;
/* GP_ALL(suffix) - Expand to a list of GP_#_#_suffix */
#define _GP_ALL(bank, pin, name, sfx, cfg) name##_##sfx
-#define GP_ALL(str) CPU_ALL_PORT(_GP_ALL, str)
+#define GP_ALL(str) CPU_ALL_GP(_GP_ALL, str)
/* PINMUX_GPIO_GP_ALL - Expand to a list of sh_pfc_pin entries */
#define _GP_GPIO(bank, _pin, _name, sfx, cfg) \
@@ -594,11 +602,29 @@ extern const struct sh_pfc_soc_info shx3_pinmux_info;
.enum_id = _name##_DATA, \
.configs = cfg, \
}
-#define PINMUX_GPIO_GP_ALL() CPU_ALL_PORT(_GP_GPIO, unused)
+#define PINMUX_GPIO_GP_ALL() CPU_ALL_GP(_GP_GPIO, unused)
/* PINMUX_DATA_GP_ALL - Expand to a list of name_DATA, name_FN marks */
#define _GP_DATA(bank, pin, name, sfx, cfg) PINMUX_DATA(name##_DATA, name##_FN)
-#define PINMUX_DATA_GP_ALL() CPU_ALL_PORT(_GP_DATA, unused)
+#define PINMUX_DATA_GP_ALL() CPU_ALL_GP(_GP_DATA, unused)
+
+/*
+ * GP_ASSIGN_LAST() - Expand to an enum definition for the last GP pin
+ *
+ * The largest GP pin index is obtained by taking the size of a union,
+ * containing one array per GP pin, sized by the corresponding pin index.
+ * As the fields in the CPU_ALL_GP() macro definition are separated by commas,
+ * while the members of a union must be terminated by semicolons, the commas
+ * are absorbed by wrapping them inside dummy attributes.
+ */
+#define _GP_ENTRY(bank, pin, name, sfx, cfg) \
+ deprecated)); char name[(bank * 32) + pin] __attribute__((deprecated
+#define GP_ASSIGN_LAST() \
+ GP_LAST = sizeof(union { \
+ char dummy[0] __attribute__((deprecated, \
+ CPU_ALL_GP(_GP_ENTRY, unused), \
+ deprecated)); \
+ })
/*
* PORT style (linear pin space)
@@ -641,22 +667,6 @@ extern const struct sh_pfc_soc_info shx3_pinmux_info;
.configs = cfgs, \
}
-/* SH_PFC_PIN_NAMED - Expand to a sh_pfc_pin entry with the given name */
-#define SH_PFC_PIN_NAMED(row, col, _name) \
- { \
- .pin = PIN_NUMBER(row, col), \
- .name = __stringify(PIN_##_name), \
- .configs = SH_PFC_PIN_CFG_NO_GPIO, \
- }
-
-/* SH_PFC_PIN_NAMED_CFG - Expand to a sh_pfc_pin entry with the given name */
-#define SH_PFC_PIN_NAMED_CFG(row, col, _name, cfgs) \
- { \
- .pin = PIN_NUMBER(row, col), \
- .name = __stringify(PIN_##_name), \
- .configs = SH_PFC_PIN_CFG_NO_GPIO | cfgs, \
- }
-
/* PINMUX_DATA_ALL - Expand to a list of PORT_name_DATA, PORT_name_FN0,
* PORT_name_OUT, PORT_name_IN marks
*/
@@ -665,6 +675,24 @@ extern const struct sh_pfc_soc_info shx3_pinmux_info;
PORT##pfx##_OUT, PORT##pfx##_IN)
#define PINMUX_DATA_ALL() CPU_ALL_PORT(_PORT_DATA, , unused)
+/*
+ * PORT_ASSIGN_LAST() - Expand to an enum definition for the last PORT pin
+ *
+ * The largest PORT pin index is obtained by taking the size of a union,
+ * containing one array per PORT pin, sized by the corresponding pin index.
+ * As the fields in the CPU_ALL_PORT() macro definition are separated by
+ * commas, while the members of a union must be terminated by semicolons, the
+ * commas are absorbed by wrapping them inside dummy attributes.
+ */
+#define _PORT_ENTRY(pn, pfx, sfx) \
+ deprecated)); char pfx[pn] __attribute__((deprecated
+#define PORT_ASSIGN_LAST() \
+ PORT_LAST = sizeof(union { \
+ char dummy[0] __attribute__((deprecated, \
+ CPU_ALL_PORT(_PORT_ENTRY, PORT, unused), \
+ deprecated)); \
+ })
+
/* GPIO_FN(name) - Expand to a sh_pfc_pin entry for a function GPIO */
#define PINMUX_GPIO_FN(gpio, base, data_or_mark) \
[gpio - (base)] = { \
@@ -675,6 +703,26 @@ extern const struct sh_pfc_soc_info shx3_pinmux_info;
PINMUX_GPIO_FN(GPIO_FN_##str, PINMUX_FN_BASE, str##_MARK)
/*
+ * Pins not associated with a GPIO port
+ */
+
+#define PIN_NOGP_CFG(pin, name, fn, cfg) fn(pin, name, cfg)
+#define PIN_NOGP(pin, name, fn) fn(pin, name, 0)
+
+/* NOGP_ALL - Expand to a list of PIN_id */
+#define _NOGP_ALL(pin, name, cfg) PIN_##pin
+#define NOGP_ALL() CPU_ALL_NOGP(_NOGP_ALL)
+
+/* PINMUX_NOGP_ALL - Expand to a list of sh_pfc_pin entries */
+#define _NOGP_PINMUX(_pin, _name, cfg) \
+ { \
+ .pin = PIN_##_pin, \
+ .name = "PIN_" _name, \
+ .configs = SH_PFC_PIN_CFG_NO_GPIO | cfg, \
+ }
+#define PINMUX_NOGP_ALL() CPU_ALL_NOGP(_NOGP_PINMUX)
+
+/*
* PORTnCR helper macro for SH-Mobile/R-Mobile
*/
#define PORTCR(nr, reg) \
diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c
index 2317ccf63321..b453aed1bbeb 100644
--- a/drivers/pinctrl/stm32/pinctrl-stm32.c
+++ b/drivers/pinctrl/stm32/pinctrl-stm32.c
@@ -44,6 +44,18 @@
#define STM32_GPIO_AFRL 0x20
#define STM32_GPIO_AFRH 0x24
+/* custom bitfield to backup pin status */
+#define STM32_GPIO_BKP_MODE_SHIFT 0
+#define STM32_GPIO_BKP_MODE_MASK GENMASK(1, 0)
+#define STM32_GPIO_BKP_ALT_SHIFT 2
+#define STM32_GPIO_BKP_ALT_MASK GENMASK(5, 2)
+#define STM32_GPIO_BKP_SPEED_SHIFT 6
+#define STM32_GPIO_BKP_SPEED_MASK GENMASK(7, 6)
+#define STM32_GPIO_BKP_PUPD_SHIFT 8
+#define STM32_GPIO_BKP_PUPD_MASK GENMASK(9, 8)
+#define STM32_GPIO_BKP_TYPE 10
+#define STM32_GPIO_BKP_VAL 11
+
#define STM32_GPIO_PINS_PER_BANK 16
#define STM32_GPIO_IRQ_LINE 16
@@ -79,6 +91,7 @@ struct stm32_gpio_bank {
struct irq_domain *domain;
u32 bank_nr;
u32 bank_ioport_nr;
+ u32 pin_backup[STM32_GPIO_PINS_PER_BANK];
};
struct stm32_pinctrl {
@@ -98,6 +111,8 @@ struct stm32_pinctrl {
struct stm32_desc_pin *pins;
u32 npins;
u32 pkg;
+ u16 irqmux_map;
+ spinlock_t irqmux_lock;
};
static inline int stm32_gpio_pin(int gpio)
@@ -133,11 +148,50 @@ static inline u32 stm32_gpio_get_alt(u32 function)
return 0;
}
+static void stm32_gpio_backup_value(struct stm32_gpio_bank *bank,
+ u32 offset, u32 value)
+{
+ bank->pin_backup[offset] &= ~BIT(STM32_GPIO_BKP_VAL);
+ bank->pin_backup[offset] |= value << STM32_GPIO_BKP_VAL;
+}
+
+static void stm32_gpio_backup_mode(struct stm32_gpio_bank *bank, u32 offset,
+ u32 mode, u32 alt)
+{
+ bank->pin_backup[offset] &= ~(STM32_GPIO_BKP_MODE_MASK |
+ STM32_GPIO_BKP_ALT_MASK);
+ bank->pin_backup[offset] |= mode << STM32_GPIO_BKP_MODE_SHIFT;
+ bank->pin_backup[offset] |= alt << STM32_GPIO_BKP_ALT_SHIFT;
+}
+
+static void stm32_gpio_backup_driving(struct stm32_gpio_bank *bank, u32 offset,
+ u32 drive)
+{
+ bank->pin_backup[offset] &= ~BIT(STM32_GPIO_BKP_TYPE);
+ bank->pin_backup[offset] |= drive << STM32_GPIO_BKP_TYPE;
+}
+
+static void stm32_gpio_backup_speed(struct stm32_gpio_bank *bank, u32 offset,
+ u32 speed)
+{
+ bank->pin_backup[offset] &= ~STM32_GPIO_BKP_SPEED_MASK;
+ bank->pin_backup[offset] |= speed << STM32_GPIO_BKP_SPEED_SHIFT;
+}
+
+static void stm32_gpio_backup_bias(struct stm32_gpio_bank *bank, u32 offset,
+ u32 bias)
+{
+ bank->pin_backup[offset] &= ~STM32_GPIO_BKP_PUPD_MASK;
+ bank->pin_backup[offset] |= bias << STM32_GPIO_BKP_PUPD_SHIFT;
+}
+
/* GPIO functions */
static inline void __stm32_gpio_set(struct stm32_gpio_bank *bank,
unsigned offset, int value)
{
+ stm32_gpio_backup_value(bank, offset, value);
+
if (!value)
offset += STM32_GPIO_PINS_PER_BANK;
@@ -307,9 +361,53 @@ static int stm32_gpio_domain_activate(struct irq_domain *d,
{
struct stm32_gpio_bank *bank = d->host_data;
struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
+ unsigned long flags;
+ int ret = 0;
+
+ /*
+ * gpio irq mux is shared between several banks, a lock has to be done
+ * to avoid overriding.
+ */
+ spin_lock_irqsave(&pctl->irqmux_lock, flags);
+ if (pctl->hwlock)
+ ret = hwspin_lock_timeout(pctl->hwlock, HWSPINLOCK_TIMEOUT);
+
+ if (ret) {
+ dev_err(pctl->dev, "Can't get hwspinlock\n");
+ goto unlock;
+ }
+
+ if (pctl->irqmux_map & BIT(irq_data->hwirq)) {
+ dev_err(pctl->dev, "irq line %ld already requested.\n",
+ irq_data->hwirq);
+ ret = -EBUSY;
+ if (pctl->hwlock)
+ hwspin_unlock(pctl->hwlock);
+ goto unlock;
+ } else {
+ pctl->irqmux_map |= BIT(irq_data->hwirq);
+ }
regmap_field_write(pctl->irqmux[irq_data->hwirq], bank->bank_ioport_nr);
- return 0;
+
+ if (pctl->hwlock)
+ hwspin_unlock(pctl->hwlock);
+
+unlock:
+ spin_unlock_irqrestore(&pctl->irqmux_lock, flags);
+ return ret;
+}
+
+static void stm32_gpio_domain_deactivate(struct irq_domain *d,
+ struct irq_data *irq_data)
+{
+ struct stm32_gpio_bank *bank = d->host_data;
+ struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
+ unsigned long flags;
+
+ spin_lock_irqsave(&pctl->irqmux_lock, flags);
+ pctl->irqmux_map &= ~BIT(irq_data->hwirq);
+ spin_unlock_irqrestore(&pctl->irqmux_lock, flags);
}
static int stm32_gpio_domain_alloc(struct irq_domain *d,
@@ -338,6 +436,7 @@ static const struct irq_domain_ops stm32_gpio_domain_ops = {
.alloc = stm32_gpio_domain_alloc,
.free = irq_domain_free_irqs_common,
.activate = stm32_gpio_domain_activate,
+ .deactivate = stm32_gpio_domain_deactivate,
};
/* Pinctrl functions */
@@ -620,6 +719,8 @@ static int stm32_pmx_set_mode(struct stm32_gpio_bank *bank,
if (pctl->hwlock)
hwspin_unlock(pctl->hwlock);
+ stm32_gpio_backup_mode(bank, pin, mode, alt);
+
unlock:
spin_unlock_irqrestore(&bank->lock, flags);
clk_disable(bank->clk);
@@ -732,6 +833,8 @@ static int stm32_pconf_set_driving(struct stm32_gpio_bank *bank,
if (pctl->hwlock)
hwspin_unlock(pctl->hwlock);
+ stm32_gpio_backup_driving(bank, offset, drive);
+
unlock:
spin_unlock_irqrestore(&bank->lock, flags);
clk_disable(bank->clk);
@@ -784,6 +887,8 @@ static int stm32_pconf_set_speed(struct stm32_gpio_bank *bank,
if (pctl->hwlock)
hwspin_unlock(pctl->hwlock);
+ stm32_gpio_backup_speed(bank, offset, speed);
+
unlock:
spin_unlock_irqrestore(&bank->lock, flags);
clk_disable(bank->clk);
@@ -836,6 +941,8 @@ static int stm32_pconf_set_bias(struct stm32_gpio_bank *bank,
if (pctl->hwlock)
hwspin_unlock(pctl->hwlock);
+ stm32_gpio_backup_bias(bank, offset, bias);
+
unlock:
spin_unlock_irqrestore(&bank->lock, flags);
clk_disable(bank->clk);
@@ -1290,6 +1397,8 @@ int stm32_pctl_probe(struct platform_device *pdev)
pctl->hwlock = hwspin_lock_request_specific(hwlock_id);
}
+ spin_lock_init(&pctl->irqmux_lock);
+
pctl->dev = dev;
pctl->match_data = match->data;
@@ -1329,6 +1438,7 @@ int stm32_pctl_probe(struct platform_device *pdev)
pctl->pctl_desc.owner = THIS_MODULE;
pctl->pctl_desc.pins = pins;
pctl->pctl_desc.npins = pctl->npins;
+ pctl->pctl_desc.link_consumers = true;
pctl->pctl_desc.confops = &stm32_pconf_ops;
pctl->pctl_desc.pctlops = &stm32_pctrl_ops;
pctl->pctl_desc.pmxops = &stm32_pmx_ops;
@@ -1369,3 +1479,75 @@ int stm32_pctl_probe(struct platform_device *pdev)
return 0;
}
+
+static int __maybe_unused stm32_pinctrl_restore_gpio_regs(
+ struct stm32_pinctrl *pctl, u32 pin)
+{
+ const struct pin_desc *desc = pin_desc_get(pctl->pctl_dev, pin);
+ u32 val, alt, mode, offset = stm32_gpio_pin(pin);
+ struct pinctrl_gpio_range *range;
+ struct stm32_gpio_bank *bank;
+ bool pin_is_irq;
+ int ret;
+
+ range = pinctrl_find_gpio_range_from_pin(pctl->pctl_dev, pin);
+ if (!range)
+ return 0;
+
+ pin_is_irq = gpiochip_line_is_irq(range->gc, offset);
+
+ if (!desc || (!pin_is_irq && !desc->gpio_owner))
+ return 0;
+
+ bank = gpiochip_get_data(range->gc);
+
+ alt = bank->pin_backup[offset] & STM32_GPIO_BKP_ALT_MASK;
+ alt >>= STM32_GPIO_BKP_ALT_SHIFT;
+ mode = bank->pin_backup[offset] & STM32_GPIO_BKP_MODE_MASK;
+ mode >>= STM32_GPIO_BKP_MODE_SHIFT;
+
+ ret = stm32_pmx_set_mode(bank, offset, mode, alt);
+ if (ret)
+ return ret;
+
+ if (mode == 1) {
+ val = bank->pin_backup[offset] & BIT(STM32_GPIO_BKP_VAL);
+ val = val >> STM32_GPIO_BKP_VAL;
+ __stm32_gpio_set(bank, offset, val);
+ }
+
+ val = bank->pin_backup[offset] & BIT(STM32_GPIO_BKP_TYPE);
+ val >>= STM32_GPIO_BKP_TYPE;
+ ret = stm32_pconf_set_driving(bank, offset, val);
+ if (ret)
+ return ret;
+
+ val = bank->pin_backup[offset] & STM32_GPIO_BKP_SPEED_MASK;
+ val >>= STM32_GPIO_BKP_SPEED_SHIFT;
+ ret = stm32_pconf_set_speed(bank, offset, val);
+ if (ret)
+ return ret;
+
+ val = bank->pin_backup[offset] & STM32_GPIO_BKP_PUPD_MASK;
+ val >>= STM32_GPIO_BKP_PUPD_SHIFT;
+ ret = stm32_pconf_set_bias(bank, offset, val);
+ if (ret)
+ return ret;
+
+ if (pin_is_irq)
+ regmap_field_write(pctl->irqmux[offset], bank->bank_ioport_nr);
+
+ return 0;
+}
+
+int __maybe_unused stm32_pinctrl_resume(struct device *dev)
+{
+ struct stm32_pinctrl *pctl = dev_get_drvdata(dev);
+ struct stm32_pinctrl_group *g = pctl->groups;
+ int i;
+
+ for (i = g->pin; i < g->pin + pctl->ngroups; i++)
+ stm32_pinctrl_restore_gpio_regs(pctl, i);
+
+ return 0;
+}
diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.h b/drivers/pinctrl/stm32/pinctrl-stm32.h
index de5e7012ca03..ec0d34c33903 100644
--- a/drivers/pinctrl/stm32/pinctrl-stm32.h
+++ b/drivers/pinctrl/stm32/pinctrl-stm32.h
@@ -65,5 +65,7 @@ struct stm32_gpio_bank;
int stm32_pctl_probe(struct platform_device *pdev);
void stm32_pmx_get_mode(struct stm32_gpio_bank *bank,
int pin, u32 *mode, u32 *alt);
+int stm32_pinctrl_resume(struct device *dev);
+
#endif /* __PINCTRL_STM32_H */
diff --git a/drivers/pinctrl/stm32/pinctrl-stm32mp157.c b/drivers/pinctrl/stm32/pinctrl-stm32mp157.c
index 320544f69e57..2ccb99d64df8 100644
--- a/drivers/pinctrl/stm32/pinctrl-stm32mp157.c
+++ b/drivers/pinctrl/stm32/pinctrl-stm32mp157.c
@@ -2342,11 +2342,16 @@ static const struct of_device_id stm32mp157_pctrl_match[] = {
{ }
};
+static const struct dev_pm_ops stm32_pinctrl_dev_pm_ops = {
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(NULL, stm32_pinctrl_resume)
+};
+
static struct platform_driver stm32mp157_pinctrl_driver = {
.probe = stm32_pctl_probe,
.driver = {
.name = "stm32mp157-pinctrl",
.of_match_table = stm32mp157_pctrl_match,
+ .pm = &stm32_pinctrl_dev_pm_ops,
},
};
diff --git a/drivers/pinctrl/tegra/Kconfig b/drivers/pinctrl/tegra/Kconfig
index 5906a856be38..a67d0d9ae8cd 100644
--- a/drivers/pinctrl/tegra/Kconfig
+++ b/drivers/pinctrl/tegra/Kconfig
@@ -24,6 +24,10 @@ config PINCTRL_TEGRA210
bool
select PINCTRL_TEGRA
+config PINCTRL_TEGRA194
+ bool
+ select PINCTRL_TEGRA
+
config PINCTRL_TEGRA_XUSB
def_bool y if ARCH_TEGRA
select GENERIC_PHY
diff --git a/drivers/pinctrl/tegra/Makefile b/drivers/pinctrl/tegra/Makefile
index bbcb043c34a2..ead4e10097d0 100644
--- a/drivers/pinctrl/tegra/Makefile
+++ b/drivers/pinctrl/tegra/Makefile
@@ -5,4 +5,5 @@ obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o
obj-$(CONFIG_PINCTRL_TEGRA114) += pinctrl-tegra114.o
obj-$(CONFIG_PINCTRL_TEGRA124) += pinctrl-tegra124.o
obj-$(CONFIG_PINCTRL_TEGRA210) += pinctrl-tegra210.o
+obj-$(CONFIG_PINCTRL_TEGRA194) += pinctrl-tegra194.o
obj-$(CONFIG_PINCTRL_TEGRA_XUSB) += pinctrl-tegra-xusb.o
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
index abcfbad94f00..186ef98e7b2b 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
@@ -284,7 +284,7 @@ static int tegra_pinconf_reg(struct tegra_pmx *pmx,
const struct tegra_pingroup *g,
enum tegra_pinconf_param param,
bool report_err,
- s8 *bank, s16 *reg, s8 *bit, s8 *width)
+ s8 *bank, s32 *reg, s8 *bit, s8 *width)
{
switch (param) {
case TEGRA_PINCONF_PARAM_PULL:
@@ -443,7 +443,7 @@ static int tegra_pinconf_group_get(struct pinctrl_dev *pctldev,
const struct tegra_pingroup *g;
int ret;
s8 bank, bit, width;
- s16 reg;
+ s32 reg;
u32 val, mask;
g = &pmx->soc->groups[group];
@@ -472,7 +472,7 @@ static int tegra_pinconf_group_set(struct pinctrl_dev *pctldev,
const struct tegra_pingroup *g;
int ret, i;
s8 bank, bit, width;
- s16 reg;
+ s32 reg;
u32 val, mask;
g = &pmx->soc->groups[group];
@@ -540,7 +540,7 @@ static void tegra_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
const struct tegra_pingroup *g;
int i, ret;
s8 bank, bit, width;
- s16 reg;
+ s32 reg;
u32 val;
g = &pmx->soc->groups[group];
@@ -613,10 +613,20 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)
for (i = 0; i < pmx->soc->ngroups; ++i) {
g = &pmx->soc->groups[i];
- if (g->parked_bit >= 0) {
- val = pmx_readl(pmx, g->mux_bank, g->mux_reg);
- val &= ~(1 << g->parked_bit);
- pmx_writel(pmx, val, g->mux_bank, g->mux_reg);
+ if (g->parked_bitmask > 0) {
+ unsigned int bank, reg;
+
+ if (g->mux_reg != -1) {
+ bank = g->mux_bank;
+ reg = g->mux_reg;
+ } else {
+ bank = g->drv_bank;
+ reg = g->drv_reg;
+ }
+
+ val = pmx_readl(pmx, bank, reg);
+ val &= ~g->parked_bitmask;
+ pmx_writel(pmx, val, bank, reg);
}
}
}
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.h b/drivers/pinctrl/tegra/pinctrl-tegra.h
index 9b5a71624fd0..105309774079 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra.h
+++ b/drivers/pinctrl/tegra/pinctrl-tegra.h
@@ -96,7 +96,6 @@ struct tegra_function {
* @tri_reg: Tri-state register offset.
* @tri_bank: Tri-state register bank.
* @tri_bit: Tri-state register bit.
- * @parked_bit: Parked register bit. -1 if unsupported.
* @einput_bit: Enable-input register bit.
* @odrain_bit: Open-drain register bit.
* @lock_bit: Lock register bit.
@@ -118,6 +117,7 @@ struct tegra_function {
* @slwf_bit: Slew Falling register bit.
* @slwf_width: Slew Falling field width.
* @drvtype_bit: Drive type register bit.
+ * @parked_bitmask: Parked register mask. 0 if unsupported.
*
* -1 in a *_reg field means that feature is unsupported for this group.
* *_bank and *_reg values are irrelevant when *_reg is -1.
@@ -135,10 +135,10 @@ struct tegra_pingroup {
const unsigned *pins;
u8 npins;
u8 funcs[4];
- s16 mux_reg;
- s16 pupd_reg;
- s16 tri_reg;
- s16 drv_reg;
+ s32 mux_reg;
+ s32 pupd_reg;
+ s32 tri_reg;
+ s32 drv_reg;
u32 mux_bank:2;
u32 pupd_bank:2;
u32 tri_bank:2;
@@ -146,7 +146,6 @@ struct tegra_pingroup {
s32 mux_bit:6;
s32 pupd_bit:6;
s32 tri_bit:6;
- s32 parked_bit:6;
s32 einput_bit:6;
s32 odrain_bit:6;
s32 lock_bit:6;
@@ -164,6 +163,7 @@ struct tegra_pingroup {
s32 drvup_width:6;
s32 slwr_width:6;
s32 slwf_width:6;
+ u32 parked_bitmask;
};
/**
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra114.c b/drivers/pinctrl/tegra/pinctrl-tegra114.c
index 762151f17a88..e72ab1eb2398 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra114.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra114.c
@@ -1572,8 +1572,8 @@ static struct tegra_function tegra114_functions[] = {
.lock_bit = 7, \
.ioreset_bit = PINGROUP_BIT_##ior(8), \
.rcv_sel_bit = PINGROUP_BIT_##rcv_sel(9), \
- .parked_bit = -1, \
.drv_reg = -1, \
+ .parked_bitmask = 0, \
}
#define DRV_PINGROUP(pg_name, r, hsm_b, schmitt_b, lpmd_b, drvdn_b, \
@@ -1593,7 +1593,6 @@ static struct tegra_function tegra114_functions[] = {
.rcv_sel_bit = -1, \
.drv_reg = DRV_PINGROUP_REG(r), \
.drv_bank = 0, \
- .parked_bit = -1, \
.hsm_bit = hsm_b, \
.schmitt_bit = schmitt_b, \
.lpmd_bit = lpmd_b, \
@@ -1606,6 +1605,7 @@ static struct tegra_function tegra114_functions[] = {
.slwf_bit = slwf_b, \
.slwf_width = slwf_w, \
.drvtype_bit = PINGROUP_BIT_##drvtype(6), \
+ .parked_bitmask = 0, \
}
static const struct tegra_pingroup tegra114_groups[] = {
@@ -1831,7 +1831,7 @@ static const struct tegra_pingroup tegra114_groups[] = {
static const struct tegra_pinctrl_soc_data tegra114_pinctrl = {
.ngpios = NUM_GPIOS,
- .gpio_compatible = "nvidia,tegra30-gpio",
+ .gpio_compatible = "nvidia,tegra114-gpio",
.pins = tegra114_pins,
.npins = ARRAY_SIZE(tegra114_pins),
.functions = tegra114_functions,
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra124.c b/drivers/pinctrl/tegra/pinctrl-tegra124.c
index 930c43758c92..26096c6b967e 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra124.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra124.c
@@ -1741,8 +1741,8 @@ static struct tegra_function tegra124_functions[] = {
.lock_bit = 7, \
.ioreset_bit = PINGROUP_BIT_##ior(8), \
.rcv_sel_bit = PINGROUP_BIT_##rcv_sel(9), \
- .parked_bit = -1, \
.drv_reg = -1, \
+ .parked_bitmask = 0, \
}
#define DRV_PINGROUP(pg_name, r, hsm_b, schmitt_b, lpmd_b, drvdn_b, \
@@ -1762,7 +1762,6 @@ static struct tegra_function tegra124_functions[] = {
.rcv_sel_bit = -1, \
.drv_reg = DRV_PINGROUP_REG(r), \
.drv_bank = 0, \
- .parked_bit = -1, \
.hsm_bit = hsm_b, \
.schmitt_bit = schmitt_b, \
.lpmd_bit = lpmd_b, \
@@ -1775,6 +1774,7 @@ static struct tegra_function tegra124_functions[] = {
.slwf_bit = slwf_b, \
.slwf_width = slwf_w, \
.drvtype_bit = PINGROUP_BIT_##drvtype(6), \
+ .parked_bitmask = 0, \
}
#define MIPI_PAD_CTRL_PINGROUP(pg_name, r, b, f0, f1) \
@@ -2043,7 +2043,7 @@ static const struct tegra_pingroup tegra124_groups[] = {
static const struct tegra_pinctrl_soc_data tegra124_pinctrl = {
.ngpios = NUM_GPIOS,
- .gpio_compatible = "nvidia,tegra30-gpio",
+ .gpio_compatible = "nvidia,tegra124-gpio",
.pins = tegra124_pins,
.npins = ARRAY_SIZE(tegra124_pins),
.functions = tegra124_functions,
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra194.c b/drivers/pinctrl/tegra/pinctrl-tegra194.c
new file mode 100644
index 000000000000..daf44cf240c9
--- /dev/null
+++ b/drivers/pinctrl/tegra/pinctrl-tegra194.c
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Pinctrl data for the NVIDIA Tegra194 pinmux
+ *
+ * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+
+#include "pinctrl-tegra.h"
+
+/* Define unique ID for each pins */
+enum pin_id {
+ TEGRA_PIN_PEX_L5_CLKREQ_N_PGG0 = 256,
+ TEGRA_PIN_PEX_L5_RST_N_PGG1 = 257,
+ TEGRA_PIN_NUM_GPIOS = 258,
+};
+
+/* Table for pin descriptor */
+static const struct pinctrl_pin_desc tegra194_pins[] = {
+ PINCTRL_PIN(TEGRA_PIN_PEX_L5_CLKREQ_N_PGG0,
+ "TEGRA_PIN_PEX_L5_CLKREQ_N_PGG0"),
+ PINCTRL_PIN(TEGRA_PIN_PEX_L5_RST_N_PGG1,
+ "TEGRA_PIN_PEX_L5_RST_N_PGG1"),
+};
+
+static const unsigned int pex_l5_clkreq_n_pgg0_pins[] = {
+ TEGRA_PIN_PEX_L5_CLKREQ_N_PGG0,
+};
+
+static const unsigned int pex_l5_rst_n_pgg1_pins[] = {
+ TEGRA_PIN_PEX_L5_RST_N_PGG1,
+};
+
+/* Define unique ID for each function */
+enum tegra_mux_dt {
+ TEGRA_MUX_RSVD0,
+ TEGRA_MUX_RSVD1,
+ TEGRA_MUX_RSVD2,
+ TEGRA_MUX_RSVD3,
+ TEGRA_MUX_PE5,
+};
+
+/* Make list of each function name */
+#define TEGRA_PIN_FUNCTION(lid) \
+ { \
+ .name = #lid, \
+ }
+static struct tegra_function tegra194_functions[] = {
+ TEGRA_PIN_FUNCTION(rsvd0),
+ TEGRA_PIN_FUNCTION(rsvd1),
+ TEGRA_PIN_FUNCTION(rsvd2),
+ TEGRA_PIN_FUNCTION(rsvd3),
+ TEGRA_PIN_FUNCTION(pe5),
+};
+
+#define DRV_PINGROUP_ENTRY_Y(r, drvdn_b, drvdn_w, drvup_b, \
+ drvup_w, slwr_b, slwr_w, slwf_b, \
+ slwf_w, bank) \
+ .drv_reg = ((r)), \
+ .drv_bank = bank, \
+ .drvdn_bit = drvdn_b, \
+ .drvdn_width = drvdn_w, \
+ .drvup_bit = drvup_b, \
+ .drvup_width = drvup_w, \
+ .slwr_bit = slwr_b, \
+ .slwr_width = slwr_w, \
+ .slwf_bit = slwf_b, \
+ .slwf_width = slwf_w
+
+#define PIN_PINGROUP_ENTRY_Y(r, bank, pupd, e_lpbk, e_input, \
+ e_od, schmitt_b, drvtype) \
+ .mux_reg = ((r)), \
+ .lpmd_bit = -1, \
+ .lock_bit = -1, \
+ .hsm_bit = -1, \
+ .mux_bank = bank, \
+ .mux_bit = 0, \
+ .pupd_reg = ((r)), \
+ .pupd_bank = bank, \
+ .pupd_bit = 2, \
+ .tri_reg = ((r)), \
+ .tri_bank = bank, \
+ .tri_bit = 4, \
+ .einput_bit = e_input, \
+ .odrain_bit = e_od, \
+ .schmitt_bit = schmitt_b, \
+ .drvtype_bit = 13, \
+ .drv_reg = -1, \
+ .parked_bitmask = 0
+
+#define drive_pex_l5_clkreq_n_pgg0 \
+ DRV_PINGROUP_ENTRY_Y(0x14004, 12, 5, 20, 5, -1, -1, -1, -1, 0)
+#define drive_pex_l5_rst_n_pgg1 \
+ DRV_PINGROUP_ENTRY_Y(0x1400c, 12, 5, 20, 5, -1, -1, -1, -1, 0)
+
+#define PINGROUP(pg_name, f0, f1, f2, f3, r, bank, pupd, e_lpbk, \
+ e_input, e_lpdr, e_od, schmitt_b, drvtype, io_rail) \
+ { \
+ .name = #pg_name, \
+ .pins = pg_name##_pins, \
+ .npins = ARRAY_SIZE(pg_name##_pins), \
+ .funcs = { \
+ TEGRA_MUX_##f0, \
+ TEGRA_MUX_##f1, \
+ TEGRA_MUX_##f2, \
+ TEGRA_MUX_##f3, \
+ }, \
+ PIN_PINGROUP_ENTRY_Y(r, bank, pupd, e_lpbk, \
+ e_input, e_od, \
+ schmitt_b, drvtype), \
+ drive_##pg_name, \
+ }
+
+static const struct tegra_pingroup tegra194_groups[] = {
+ PINGROUP(pex_l5_clkreq_n_pgg0, PE5, RSVD1, RSVD2, RSVD3, 0x14000, 0,
+ Y, -1, 6, 8, 11, 12, N, "vddio_pex_ctl_2"),
+ PINGROUP(pex_l5_rst_n_pgg1, PE5, RSVD1, RSVD2, RSVD3, 0x14008, 0,
+ Y, -1, 6, 8, 11, 12, N, "vddio_pex_ctl_2"),
+};
+
+static const struct tegra_pinctrl_soc_data tegra194_pinctrl = {
+ .ngpios = TEGRA_PIN_NUM_GPIOS,
+ .pins = tegra194_pins,
+ .npins = ARRAY_SIZE(tegra194_pins),
+ .functions = tegra194_functions,
+ .nfunctions = ARRAY_SIZE(tegra194_functions),
+ .groups = tegra194_groups,
+ .ngroups = ARRAY_SIZE(tegra194_groups),
+ .hsm_in_mux = true,
+ .schmitt_in_mux = true,
+ .drvtype_in_mux = true,
+};
+
+static int tegra194_pinctrl_probe(struct platform_device *pdev)
+{
+ return tegra_pinctrl_probe(pdev, &tegra194_pinctrl);
+}
+
+static const struct of_device_id tegra194_pinctrl_of_match[] = {
+ { .compatible = "nvidia,tegra194-pinmux", },
+ { },
+};
+
+static struct platform_driver tegra194_pinctrl_driver = {
+ .driver = {
+ .name = "tegra194-pinctrl",
+ .of_match_table = tegra194_pinctrl_of_match,
+ },
+ .probe = tegra194_pinctrl_probe,
+};
+
+static int __init tegra194_pinctrl_init(void)
+{
+ return platform_driver_register(&tegra194_pinctrl_driver);
+}
+arch_initcall(tegra194_pinctrl_init);
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra20.c b/drivers/pinctrl/tegra/pinctrl-tegra20.c
index 4b7837e38fb5..0dc2cf0d05b1 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra20.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra20.c
@@ -1989,13 +1989,13 @@ static struct tegra_function tegra20_functions[] = {
.tri_reg = ((tri_r) - TRISTATE_REG_A), \
.tri_bank = 0, \
.tri_bit = tri_b, \
- .parked_bit = -1, \
.einput_bit = -1, \
.odrain_bit = -1, \
.lock_bit = -1, \
.ioreset_bit = -1, \
.rcv_sel_bit = -1, \
.drv_reg = -1, \
+ .parked_bitmask = 0, \
}
/* Pin groups with only pull up and pull down control */
@@ -2009,7 +2009,7 @@ static struct tegra_function tegra20_functions[] = {
.pupd_bank = 2, \
.pupd_bit = pupd_b, \
.drv_reg = -1, \
- .parked_bit = -1, \
+ .parked_bitmask = 0, \
}
/* Pin groups for drive strength registers (configurable version) */
@@ -2025,7 +2025,7 @@ static struct tegra_function tegra20_functions[] = {
.tri_reg = -1, \
.drv_reg = ((r) - PINGROUP_REG_A), \
.drv_bank = 3, \
- .parked_bit = -1, \
+ .parked_bitmask = 0, \
.hsm_bit = hsm_b, \
.schmitt_bit = schmitt_b, \
.lpmd_bit = lpmd_b, \
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra210.c b/drivers/pinctrl/tegra/pinctrl-tegra210.c
index 0b56ad5c9c1c..39ab6480a941 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra210.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra210.c
@@ -1302,7 +1302,6 @@ static struct tegra_function tegra210_functions[] = {
.lock_bit = 7, \
.ioreset_bit = -1, \
.rcv_sel_bit = PINGROUP_BIT_##e_io_hv(10), \
- .parked_bit = 5, \
.hsm_bit = PINGROUP_BIT_##hsm(9), \
.schmitt_bit = 12, \
.drvtype_bit = PINGROUP_BIT_##drvtype(13), \
@@ -1317,10 +1316,11 @@ static struct tegra_function tegra210_functions[] = {
.slwr_width = slwr_w, \
.slwf_bit = slwf_b, \
.slwf_width = slwf_w, \
+ .parked_bitmask = BIT(5), \
}
-#define DRV_PINGROUP(pg_name, r, drvdn_b, drvdn_w, drvup_b, drvup_w, \
- slwr_b, slwr_w, slwf_b, slwf_w) \
+#define DRV_PINGROUP(pg_name, r, prk_mask, drvdn_b, drvdn_w, drvup_b, \
+ drvup_w, slwr_b, slwr_w, slwf_b, slwf_w) \
{ \
.name = "drive_" #pg_name, \
.pins = drive_##pg_name##_pins, \
@@ -1335,7 +1335,6 @@ static struct tegra_function tegra210_functions[] = {
.rcv_sel_bit = -1, \
.drv_reg = DRV_PINGROUP_REG(r), \
.drv_bank = 0, \
- .parked_bit = -1, \
.hsm_bit = -1, \
.schmitt_bit = -1, \
.lpmd_bit = -1, \
@@ -1348,6 +1347,7 @@ static struct tegra_function tegra210_functions[] = {
.slwf_bit = slwf_b, \
.slwf_width = slwf_w, \
.drvtype_bit = -1, \
+ .parked_bitmask = prk_mask, \
}
static const struct tegra_pingroup tegra210_groups[] = {
@@ -1515,37 +1515,37 @@ static const struct tegra_pingroup tegra210_groups[] = {
PINGROUP(pz4, SDMMC1, RSVD1, RSVD2, RSVD3, 0x328c, N, N, N, -1, -1, -1, -1, -1, -1, -1, -1, -1),
PINGROUP(pz5, SOC, RSVD1, RSVD2, RSVD3, 0x3290, N, N, N, -1, -1, -1, -1, -1, -1, -1, -1, -1),
- /* pg_name, r, drvdn_b, drvdn_w, drvup_b, drvup_w, slwr_b, slwr_w, slwf_b, slwf_w */
- DRV_PINGROUP(pa6, 0x9c0, 12, 5, 20, 5, -1, -1, -1, -1),
- DRV_PINGROUP(pcc7, 0x9c4, 12, 5, 20, 5, -1, -1, -1, -1),
- DRV_PINGROUP(pe6, 0x9c8, 12, 5, 20, 5, -1, -1, -1, -1),
- DRV_PINGROUP(pe7, 0x9cc, 12, 5, 20, 5, -1, -1, -1, -1),
- DRV_PINGROUP(ph6, 0x9d0, 12, 5, 20, 5, -1, -1, -1, -1),
- DRV_PINGROUP(pk0, 0x9d4, -1, -1, -1, -1, 28, 2, 30, 2),
- DRV_PINGROUP(pk1, 0x9d8, -1, -1, -1, -1, 28, 2, 30, 2),
- DRV_PINGROUP(pk2, 0x9dc, -1, -1, -1, -1, 28, 2, 30, 2),
- DRV_PINGROUP(pk3, 0x9e0, -1, -1, -1, -1, 28, 2, 30, 2),
- DRV_PINGROUP(pk4, 0x9e4, -1, -1, -1, -1, 28, 2, 30, 2),
- DRV_PINGROUP(pk5, 0x9e8, -1, -1, -1, -1, 28, 2, 30, 2),
- DRV_PINGROUP(pk6, 0x9ec, -1, -1, -1, -1, 28, 2, 30, 2),
- DRV_PINGROUP(pk7, 0x9f0, -1, -1, -1, -1, 28, 2, 30, 2),
- DRV_PINGROUP(pl0, 0x9f4, -1, -1, -1, -1, 28, 2, 30, 2),
- DRV_PINGROUP(pl1, 0x9f8, -1, -1, -1, -1, 28, 2, 30, 2),
- DRV_PINGROUP(pz0, 0x9fc, 12, 7, 20, 7, -1, -1, -1, -1),
- DRV_PINGROUP(pz1, 0xa00, 12, 7, 20, 7, -1, -1, -1, -1),
- DRV_PINGROUP(pz2, 0xa04, 12, 7, 20, 7, -1, -1, -1, -1),
- DRV_PINGROUP(pz3, 0xa08, 12, 7, 20, 7, -1, -1, -1, -1),
- DRV_PINGROUP(pz4, 0xa0c, 12, 7, 20, 7, -1, -1, -1, -1),
- DRV_PINGROUP(pz5, 0xa10, 12, 7, 20, 7, -1, -1, -1, -1),
- DRV_PINGROUP(sdmmc1, 0xa98, 12, 7, 20, 7, 28, 2, 30, 2),
- DRV_PINGROUP(sdmmc2, 0xa9c, 2, 6, 8, 6, 28, 2, 30, 2),
- DRV_PINGROUP(sdmmc3, 0xab0, 12, 7, 20, 7, 28, 2, 30, 2),
- DRV_PINGROUP(sdmmc4, 0xab4, 2, 6, 8, 6, 28, 2, 30, 2),
+ /* pg_name, r, prk_mask, drvdn_b, drvdn_w, drvup_b, drvup_w, slwr_b, slwr_w, slwf_b, slwf_w */
+ DRV_PINGROUP(pa6, 0x9c0, 0x0, 12, 5, 20, 5, -1, -1, -1, -1),
+ DRV_PINGROUP(pcc7, 0x9c4, 0x0, 12, 5, 20, 5, -1, -1, -1, -1),
+ DRV_PINGROUP(pe6, 0x9c8, 0x0, 12, 5, 20, 5, -1, -1, -1, -1),
+ DRV_PINGROUP(pe7, 0x9cc, 0x0, 12, 5, 20, 5, -1, -1, -1, -1),
+ DRV_PINGROUP(ph6, 0x9d0, 0x0, 12, 5, 20, 5, -1, -1, -1, -1),
+ DRV_PINGROUP(pk0, 0x9d4, 0x0, -1, -1, -1, -1, 28, 2, 30, 2),
+ DRV_PINGROUP(pk1, 0x9d8, 0x0, -1, -1, -1, -1, 28, 2, 30, 2),
+ DRV_PINGROUP(pk2, 0x9dc, 0x0, -1, -1, -1, -1, 28, 2, 30, 2),
+ DRV_PINGROUP(pk3, 0x9e0, 0x0, -1, -1, -1, -1, 28, 2, 30, 2),
+ DRV_PINGROUP(pk4, 0x9e4, 0x0, -1, -1, -1, -1, 28, 2, 30, 2),
+ DRV_PINGROUP(pk5, 0x9e8, 0x0, -1, -1, -1, -1, 28, 2, 30, 2),
+ DRV_PINGROUP(pk6, 0x9ec, 0x0, -1, -1, -1, -1, 28, 2, 30, 2),
+ DRV_PINGROUP(pk7, 0x9f0, 0x0, -1, -1, -1, -1, 28, 2, 30, 2),
+ DRV_PINGROUP(pl0, 0x9f4, 0x0, -1, -1, -1, -1, 28, 2, 30, 2),
+ DRV_PINGROUP(pl1, 0x9f8, 0x0, -1, -1, -1, -1, 28, 2, 30, 2),
+ DRV_PINGROUP(pz0, 0x9fc, 0x0, 12, 7, 20, 7, -1, -1, -1, -1),
+ DRV_PINGROUP(pz1, 0xa00, 0x0, 12, 7, 20, 7, -1, -1, -1, -1),
+ DRV_PINGROUP(pz2, 0xa04, 0x0, 12, 7, 20, 7, -1, -1, -1, -1),
+ DRV_PINGROUP(pz3, 0xa08, 0x0, 12, 7, 20, 7, -1, -1, -1, -1),
+ DRV_PINGROUP(pz4, 0xa0c, 0x0, 12, 7, 20, 7, -1, -1, -1, -1),
+ DRV_PINGROUP(pz5, 0xa10, 0x0, 12, 7, 20, 7, -1, -1, -1, -1),
+ DRV_PINGROUP(sdmmc1, 0xa98, 0x0, 12, 7, 20, 7, 28, 2, 30, 2),
+ DRV_PINGROUP(sdmmc2, 0xa9c, 0x7ffc000, 2, 6, 8, 6, 28, 2, 30, 2),
+ DRV_PINGROUP(sdmmc3, 0xab0, 0x0, 12, 7, 20, 7, 28, 2, 30, 2),
+ DRV_PINGROUP(sdmmc4, 0xab4, 0x7ffc000, 2, 6, 8, 6, 28, 2, 30, 2),
};
static const struct tegra_pinctrl_soc_data tegra210_pinctrl = {
.ngpios = NUM_GPIOS,
- .gpio_compatible = "nvidia,tegra30-gpio",
+ .gpio_compatible = "nvidia,tegra210-gpio",
.pins = tegra210_pins,
.npins = ARRAY_SIZE(tegra210_pins),
.functions = tegra210_functions,
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra30.c b/drivers/pinctrl/tegra/pinctrl-tegra30.c
index 610124c3d192..7299a371827f 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra30.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra30.c
@@ -2133,8 +2133,8 @@ static struct tegra_function tegra30_functions[] = {
.lock_bit = 7, \
.ioreset_bit = PINGROUP_BIT_##ior(8), \
.rcv_sel_bit = -1, \
- .parked_bit = -1, \
.drv_reg = -1, \
+ .parked_bitmask = 0, \
}
#define DRV_PINGROUP(pg_name, r, hsm_b, schmitt_b, lpmd_b, drvdn_b, \
@@ -2154,7 +2154,6 @@ static struct tegra_function tegra30_functions[] = {
.rcv_sel_bit = -1, \
.drv_reg = DRV_PINGROUP_REG(r), \
.drv_bank = 0, \
- .parked_bit = -1, \
.hsm_bit = hsm_b, \
.schmitt_bit = schmitt_b, \
.lpmd_bit = lpmd_b, \
@@ -2167,6 +2166,7 @@ static struct tegra_function tegra30_functions[] = {
.slwf_bit = slwf_b, \
.slwf_width = slwf_w, \
.drvtype_bit = -1, \
+ .parked_bitmask = 0, \
}
static const struct tegra_pingroup tegra30_groups[] = {
diff --git a/drivers/pinctrl/zte/pinctrl-zx.c b/drivers/pinctrl/zte/pinctrl-zx.c
index 3cb69309912b..9512045420ec 100644
--- a/drivers/pinctrl/zte/pinctrl-zx.c
+++ b/drivers/pinctrl/zte/pinctrl-zx.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2017 Sanechips Technology Co., Ltd.
* Copyright 2017 Linaro Ltd.
- *
- * 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.
*/
#include <linux/io.h>
diff --git a/drivers/pinctrl/zte/pinctrl-zx.h b/drivers/pinctrl/zte/pinctrl-zx.h
index bc67e2be0503..a0692e2e9012 100644
--- a/drivers/pinctrl/zte/pinctrl-zx.h
+++ b/drivers/pinctrl/zte/pinctrl-zx.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2017 Sanechips Technology Co., Ltd.
* Copyright 2017 Linaro Ltd.
- *
- * 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.
*/
#ifndef __PINCTRL_ZX_H
diff --git a/drivers/pinctrl/zte/pinctrl-zx296718.c b/drivers/pinctrl/zte/pinctrl-zx296718.c
index 71efec17ee7e..c980aecb6f2f 100644
--- a/drivers/pinctrl/zte/pinctrl-zx296718.c
+++ b/drivers/pinctrl/zte/pinctrl-zx296718.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2017 Sanechips Technology Co., Ltd.
* Copyright 2017 Linaro Ltd.
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig
index 0b3a906b3bf5..971426bb4302 100644
--- a/drivers/platform/Kconfig
+++ b/drivers/platform/Kconfig
@@ -11,3 +11,5 @@ source "drivers/platform/goldfish/Kconfig"
source "drivers/platform/chrome/Kconfig"
source "drivers/platform/mellanox/Kconfig"
+
+source "drivers/platform/olpc/Kconfig"
diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile
index 4b2ce58bcd9c..6fda58c021ca 100644
--- a/drivers/platform/Makefile
+++ b/drivers/platform/Makefile
@@ -6,6 +6,6 @@
obj-$(CONFIG_X86) += x86/
obj-$(CONFIG_MELLANOX_PLATFORM) += mellanox/
obj-$(CONFIG_MIPS) += mips/
-obj-$(CONFIG_OLPC) += olpc/
+obj-$(CONFIG_OLPC_EC) += olpc/
obj-$(CONFIG_GOLDFISH) += goldfish/
obj-$(CONFIG_CHROME_PLATFORMS) += chrome/
diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig
index 2826f7136f65..970679d0b6f6 100644
--- a/drivers/platform/chrome/Kconfig
+++ b/drivers/platform/chrome/Kconfig
@@ -72,6 +72,19 @@ config CROS_EC_RPMSG
To compile this driver as a module, choose M here: the
module will be called cros_ec_rpmsg.
+config CROS_EC_ISHTP
+ tristate "ChromeOS Embedded Controller (ISHTP)"
+ depends on MFD_CROS_EC
+ depends on INTEL_ISH_HID
+ help
+ If you say Y here, you get support for talking to the ChromeOS EC
+ firmware running on Intel Integrated Sensor Hub (ISH), using the
+ ISH Transport protocol (ISH-TP). This uses a simple byte-level
+ protocol with a checksum.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cros_ec_ishtp.
+
config CROS_EC_SPI
tristate "ChromeOS Embedded Controller (SPI)"
depends on MFD_CROS_EC && SPI
@@ -83,28 +96,17 @@ config CROS_EC_SPI
'pre-amble' bytes before the response actually starts.
config CROS_EC_LPC
- tristate "ChromeOS Embedded Controller (LPC)"
- depends on MFD_CROS_EC && ACPI && (X86 || COMPILE_TEST)
- help
- If you say Y here, you get support for talking to the ChromeOS EC
- over an LPC bus. This uses a simple byte-level protocol with a
- checksum. This is used for userspace access only. The kernel
- typically has its own communication methods.
-
- To compile this driver as a module, choose M here: the
- module will be called cros_ec_lpc.
-
-config CROS_EC_LPC_MEC
- bool "ChromeOS Embedded Controller LPC Microchip EC (MEC) variant"
- depends on CROS_EC_LPC
- default n
+ tristate "ChromeOS Embedded Controller (LPC)"
+ depends on MFD_CROS_EC && ACPI && (X86 || COMPILE_TEST)
help
- If you say Y here, a variant LPC protocol for the Microchip EC
- will be used. Note that this variant is not backward compatible
- with non-Microchip ECs.
+ If you say Y here, you get support for talking to the ChromeOS EC
+ over an LPC bus, including the LPC Microchip EC (MEC) variant.
+ This uses a simple byte-level protocol with a checksum. This is
+ used for userspace access only. The kernel typically has its own
+ communication methods.
- If you have a ChromeOS Embedded Controller Microchip EC variant
- choose Y here.
+ To compile this driver as a module, choose M here: the
+ module will be called cros_ec_lpcs.
config CROS_EC_PROTO
bool
diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile
index 1b2f1dcfcd5c..fd0af05cc14c 100644
--- a/drivers/platform/chrome/Makefile
+++ b/drivers/platform/chrome/Makefile
@@ -7,10 +7,10 @@ obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o
obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o
obj-$(CONFIG_CHROMEOS_TBMC) += chromeos_tbmc.o
obj-$(CONFIG_CROS_EC_I2C) += cros_ec_i2c.o
+obj-$(CONFIG_CROS_EC_ISHTP) += cros_ec_ishtp.o
obj-$(CONFIG_CROS_EC_RPMSG) += cros_ec_rpmsg.o
obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o
-cros_ec_lpcs-objs := cros_ec_lpc.o cros_ec_lpc_reg.o
-cros_ec_lpcs-$(CONFIG_CROS_EC_LPC_MEC) += cros_ec_lpc_mec.o
+cros_ec_lpcs-objs := cros_ec_lpc.o cros_ec_lpc_mec.o
obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpcs.o
obj-$(CONFIG_CROS_EC_PROTO) += cros_ec_proto.o cros_ec_trace.o
obj-$(CONFIG_CROS_KBD_LED_BACKLIGHT) += cros_kbd_led_backlight.o
diff --git a/drivers/platform/chrome/cros_ec_debugfs.c b/drivers/platform/chrome/cros_ec_debugfs.c
index 4c2a27f6a6d0..8ec1cc2889f2 100644
--- a/drivers/platform/chrome/cros_ec_debugfs.c
+++ b/drivers/platform/chrome/cros_ec_debugfs.c
@@ -25,7 +25,8 @@
#define CIRC_ADD(idx, size, value) (((idx) + (value)) & ((size) - 1))
-/* struct cros_ec_debugfs - ChromeOS EC debugging information
+/**
+ * struct cros_ec_debugfs - EC debugging information.
*
* @ec: EC device this debugfs information belongs to
* @dir: dentry for debugfs files
@@ -241,7 +242,35 @@ static ssize_t cros_ec_pdinfo_read(struct file *file,
read_buf, p - read_buf);
}
-const struct file_operations cros_ec_console_log_fops = {
+static ssize_t cros_ec_uptime_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct cros_ec_debugfs *debug_info = file->private_data;
+ struct cros_ec_device *ec_dev = debug_info->ec->ec_dev;
+ struct {
+ struct cros_ec_command cmd;
+ struct ec_response_uptime_info resp;
+ } __packed msg = {};
+ struct ec_response_uptime_info *resp;
+ char read_buf[32];
+ int ret;
+
+ resp = (struct ec_response_uptime_info *)&msg.resp;
+
+ msg.cmd.command = EC_CMD_GET_UPTIME_INFO;
+ msg.cmd.insize = sizeof(*resp);
+
+ ret = cros_ec_cmd_xfer_status(ec_dev, &msg.cmd);
+ if (ret < 0)
+ return ret;
+
+ ret = scnprintf(read_buf, sizeof(read_buf), "%u\n",
+ resp->time_since_ec_boot_ms);
+
+ return simple_read_from_buffer(user_buf, count, ppos, read_buf, ret);
+}
+
+static const struct file_operations cros_ec_console_log_fops = {
.owner = THIS_MODULE,
.open = cros_ec_console_log_open,
.read = cros_ec_console_log_read,
@@ -250,13 +279,20 @@ const struct file_operations cros_ec_console_log_fops = {
.release = cros_ec_console_log_release,
};
-const struct file_operations cros_ec_pdinfo_fops = {
+static const struct file_operations cros_ec_pdinfo_fops = {
.owner = THIS_MODULE,
.open = simple_open,
.read = cros_ec_pdinfo_read,
.llseek = default_llseek,
};
+static const struct file_operations cros_ec_uptime_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .read = cros_ec_uptime_read,
+ .llseek = default_llseek,
+};
+
static int ec_read_version_supported(struct cros_ec_dev *ec)
{
struct ec_params_get_cmd_versions_v1 *params;
@@ -408,6 +444,12 @@ static int cros_ec_debugfs_probe(struct platform_device *pd)
debugfs_create_file("pdinfo", 0444, debug_info->dir, debug_info,
&cros_ec_pdinfo_fops);
+ debugfs_create_file("uptime", 0444, debug_info->dir, debug_info,
+ &cros_ec_uptime_fops);
+
+ debugfs_create_x32("last_resume_result", 0444, debug_info->dir,
+ &ec->ec_dev->last_resume_result);
+
ec->debug_info = debug_info;
dev_set_drvdata(&pd->dev, ec);
diff --git a/drivers/platform/chrome/cros_ec_ishtp.c b/drivers/platform/chrome/cros_ec_ishtp.c
new file mode 100644
index 000000000000..e504d255d5ce
--- /dev/null
+++ b/drivers/platform/chrome/cros_ec_ishtp.c
@@ -0,0 +1,763 @@
+// SPDX-License-Identifier: GPL-2.0
+// ISHTP interface for ChromeOS Embedded Controller
+//
+// Copyright (c) 2019, Intel Corporation.
+//
+// ISHTP client driver for talking to the Chrome OS EC firmware running
+// on Intel Integrated Sensor Hub (ISH) using the ISH Transport protocol
+// (ISH-TP).
+
+#include <linux/delay.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/cros_ec.h>
+#include <linux/mfd/cros_ec_commands.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/intel-ish-client-if.h>
+
+/*
+ * ISH TX/RX ring buffer pool size
+ *
+ * The AP->ISH messages and corresponding ISH->AP responses are
+ * serialized. We need 1 TX and 1 RX buffer for these.
+ *
+ * The MKBP ISH->AP events are serialized. We need one additional RX
+ * buffer for them.
+ */
+#define CROS_ISH_CL_TX_RING_SIZE 8
+#define CROS_ISH_CL_RX_RING_SIZE 8
+
+/* ISH CrOS EC Host Commands */
+enum cros_ec_ish_channel {
+ CROS_EC_COMMAND = 1, /* AP->ISH message */
+ CROS_MKBP_EVENT = 2, /* ISH->AP events */
+};
+
+/*
+ * ISH firmware timeout for 1 message send failure is 1Hz, and the
+ * firmware will retry 2 times, so 3Hz is used for timeout.
+ */
+#define ISHTP_SEND_TIMEOUT (3 * HZ)
+
+/* ISH Transport CrOS EC ISH client unique GUID */
+static const guid_t cros_ish_guid =
+ GUID_INIT(0x7b7154d0, 0x56f4, 0x4bdc,
+ 0xb0, 0xd8, 0x9e, 0x7c, 0xda, 0xe0, 0xd6, 0xa0);
+
+struct header {
+ u8 channel;
+ u8 status;
+ u8 reserved[2];
+} __packed;
+
+struct cros_ish_out_msg {
+ struct header hdr;
+ struct ec_host_request ec_request;
+} __packed;
+
+struct cros_ish_in_msg {
+ struct header hdr;
+ struct ec_host_response ec_response;
+} __packed;
+
+#define IN_MSG_EC_RESPONSE_PREAMBLE \
+ offsetof(struct cros_ish_in_msg, ec_response)
+
+#define OUT_MSG_EC_REQUEST_PREAMBLE \
+ offsetof(struct cros_ish_out_msg, ec_request)
+
+#define cl_data_to_dev(client_data) ishtp_device((client_data)->cl_device)
+
+/*
+ * The Read-Write Semaphore is used to prevent message TX or RX while
+ * the ishtp client is being initialized or undergoing reset.
+ *
+ * The readers are the kernel function calls responsible for IA->ISH
+ * and ISH->AP messaging.
+ *
+ * The writers are .reset() and .probe() function.
+ */
+DECLARE_RWSEM(init_lock);
+
+/**
+ * struct response_info - Encapsulate firmware response related
+ * information for passing between function ish_send() and
+ * process_recv() callback.
+ *
+ * @data: Copy the data received from firmware here.
+ * @max_size: Max size allocated for the @data buffer. If the received
+ * data exceeds this value, we log an error.
+ * @size: Actual size of data received from firmware.
+ * @error: 0 for success, negative error code for a failure in process_recv().
+ * @received: Set to true on receiving a valid firmware response to host command
+ * @wait_queue: Wait queue for host to wait for firmware response.
+ */
+struct response_info {
+ void *data;
+ size_t max_size;
+ size_t size;
+ int error;
+ bool received;
+ wait_queue_head_t wait_queue;
+};
+
+/**
+ * struct ishtp_cl_data - Encapsulate per ISH TP Client.
+ *
+ * @cros_ish_cl: ISHTP firmware client instance.
+ * @cl_device: ISHTP client device instance.
+ * @response: Response info passing between ish_send() and process_recv().
+ * @work_ishtp_reset: Work queue reset handling.
+ * @work_ec_evt: Work queue for EC events.
+ * @ec_dev: CrOS EC MFD device.
+ *
+ * This structure is used to store per client data.
+ */
+struct ishtp_cl_data {
+ struct ishtp_cl *cros_ish_cl;
+ struct ishtp_cl_device *cl_device;
+
+ /*
+ * Used for passing firmware response information between
+ * ish_send() and process_recv() callback.
+ */
+ struct response_info response;
+
+ struct work_struct work_ishtp_reset;
+ struct work_struct work_ec_evt;
+ struct cros_ec_device *ec_dev;
+};
+
+/**
+ * ish_evt_handler - ISH to AP event handler
+ * @work: Work struct
+ */
+static void ish_evt_handler(struct work_struct *work)
+{
+ struct ishtp_cl_data *client_data =
+ container_of(work, struct ishtp_cl_data, work_ec_evt);
+ struct cros_ec_device *ec_dev = client_data->ec_dev;
+
+ if (cros_ec_get_next_event(ec_dev, NULL) > 0) {
+ blocking_notifier_call_chain(&ec_dev->event_notifier,
+ 0, ec_dev);
+ }
+}
+
+/**
+ * ish_send() - Send message from host to firmware
+ *
+ * @client_data: Client data instance
+ * @out_msg: Message buffer to be sent to firmware
+ * @out_size: Size of out going message
+ * @in_msg: Message buffer where the incoming data is copied. This buffer
+ * is allocated by calling
+ * @in_size: Max size of incoming message
+ *
+ * Return: Number of bytes copied in the in_msg on success, negative
+ * error code on failure.
+ */
+static int ish_send(struct ishtp_cl_data *client_data,
+ u8 *out_msg, size_t out_size,
+ u8 *in_msg, size_t in_size)
+{
+ int rv;
+ struct header *out_hdr = (struct header *)out_msg;
+ struct ishtp_cl *cros_ish_cl = client_data->cros_ish_cl;
+
+ dev_dbg(cl_data_to_dev(client_data),
+ "%s: channel=%02u status=%02u\n",
+ __func__, out_hdr->channel, out_hdr->status);
+
+ /* Setup for incoming response */
+ client_data->response.data = in_msg;
+ client_data->response.max_size = in_size;
+ client_data->response.error = 0;
+ client_data->response.received = false;
+
+ rv = ishtp_cl_send(cros_ish_cl, out_msg, out_size);
+ if (rv) {
+ dev_err(cl_data_to_dev(client_data),
+ "ishtp_cl_send error %d\n", rv);
+ return rv;
+ }
+
+ wait_event_interruptible_timeout(client_data->response.wait_queue,
+ client_data->response.received,
+ ISHTP_SEND_TIMEOUT);
+ if (!client_data->response.received) {
+ dev_err(cl_data_to_dev(client_data),
+ "Timed out for response to host message\n");
+ return -ETIMEDOUT;
+ }
+
+ if (client_data->response.error < 0)
+ return client_data->response.error;
+
+ return client_data->response.size;
+}
+
+/**
+ * process_recv() - Received and parse incoming packet
+ * @cros_ish_cl: Client instance to get stats
+ * @rb_in_proc: Host interface message buffer
+ *
+ * Parse the incoming packet. If it is a response packet then it will
+ * update per instance flags and wake up the caller waiting to for the
+ * response. If it is an event packet then it will schedule event work.
+ */
+static void process_recv(struct ishtp_cl *cros_ish_cl,
+ struct ishtp_cl_rb *rb_in_proc)
+{
+ size_t data_len = rb_in_proc->buf_idx;
+ struct ishtp_cl_data *client_data =
+ ishtp_get_client_data(cros_ish_cl);
+ struct device *dev = cl_data_to_dev(client_data);
+ struct cros_ish_in_msg *in_msg =
+ (struct cros_ish_in_msg *)rb_in_proc->buffer.data;
+
+ /* Proceed only if reset or init is not in progress */
+ if (!down_read_trylock(&init_lock)) {
+ /* Free the buffer */
+ ishtp_cl_io_rb_recycle(rb_in_proc);
+ dev_warn(dev,
+ "Host is not ready to receive incoming messages\n");
+ return;
+ }
+
+ /*
+ * All firmware messages contain a header. Check the buffer size
+ * before accessing elements inside.
+ */
+ if (!rb_in_proc->buffer.data) {
+ dev_warn(dev, "rb_in_proc->buffer.data returned null");
+ client_data->response.error = -EBADMSG;
+ goto end_error;
+ }
+
+ if (data_len < sizeof(struct header)) {
+ dev_err(dev, "data size %zu is less than header %zu\n",
+ data_len, sizeof(struct header));
+ client_data->response.error = -EMSGSIZE;
+ goto end_error;
+ }
+
+ dev_dbg(dev, "channel=%02u status=%02u\n",
+ in_msg->hdr.channel, in_msg->hdr.status);
+
+ switch (in_msg->hdr.channel) {
+ case CROS_EC_COMMAND:
+ /* Sanity check */
+ if (!client_data->response.data) {
+ dev_err(dev,
+ "Receiving buffer is null. Should be allocated by calling function\n");
+ client_data->response.error = -EINVAL;
+ goto error_wake_up;
+ }
+
+ if (client_data->response.received) {
+ dev_err(dev,
+ "Previous firmware message not yet processed\n");
+ client_data->response.error = -EINVAL;
+ goto error_wake_up;
+ }
+
+ if (data_len > client_data->response.max_size) {
+ dev_err(dev,
+ "Received buffer size %zu is larger than allocated buffer %zu\n",
+ data_len, client_data->response.max_size);
+ client_data->response.error = -EMSGSIZE;
+ goto error_wake_up;
+ }
+
+ if (in_msg->hdr.status) {
+ dev_err(dev, "firmware returned status %d\n",
+ in_msg->hdr.status);
+ client_data->response.error = -EIO;
+ goto error_wake_up;
+ }
+
+ /* Update the actual received buffer size */
+ client_data->response.size = data_len;
+
+ /*
+ * Copy the buffer received in firmware response for the
+ * calling thread.
+ */
+ memcpy(client_data->response.data,
+ rb_in_proc->buffer.data, data_len);
+
+ /* Set flag before waking up the caller */
+ client_data->response.received = true;
+error_wake_up:
+ /* Wake the calling thread */
+ wake_up_interruptible(&client_data->response.wait_queue);
+
+ break;
+
+ case CROS_MKBP_EVENT:
+ /* The event system doesn't send any data in buffer */
+ schedule_work(&client_data->work_ec_evt);
+
+ break;
+
+ default:
+ dev_err(dev, "Invalid channel=%02d\n", in_msg->hdr.channel);
+ }
+
+end_error:
+ /* Free the buffer */
+ ishtp_cl_io_rb_recycle(rb_in_proc);
+
+ up_read(&init_lock);
+}
+
+/**
+ * ish_event_cb() - bus driver callback for incoming message
+ * @cl_device: ISHTP client device for which this message is targeted.
+ *
+ * Remove the packet from the list and process the message by calling
+ * process_recv.
+ */
+static void ish_event_cb(struct ishtp_cl_device *cl_device)
+{
+ struct ishtp_cl_rb *rb_in_proc;
+ struct ishtp_cl *cros_ish_cl = ishtp_get_drvdata(cl_device);
+
+ while ((rb_in_proc = ishtp_cl_rx_get_rb(cros_ish_cl)) != NULL) {
+ /* Decide what to do with received data */
+ process_recv(cros_ish_cl, rb_in_proc);
+ }
+}
+
+/**
+ * cros_ish_init() - Init function for ISHTP client
+ * @cros_ish_cl: ISHTP client instance
+ *
+ * This function complete the initializtion of the client.
+ *
+ * Return: 0 for success, negative error code for failure.
+ */
+static int cros_ish_init(struct ishtp_cl *cros_ish_cl)
+{
+ int rv;
+ struct ishtp_device *dev;
+ struct ishtp_fw_client *fw_client;
+ struct ishtp_cl_data *client_data = ishtp_get_client_data(cros_ish_cl);
+
+ rv = ishtp_cl_link(cros_ish_cl);
+ if (rv) {
+ dev_err(cl_data_to_dev(client_data),
+ "ishtp_cl_link failed\n");
+ return rv;
+ }
+
+ dev = ishtp_get_ishtp_device(cros_ish_cl);
+
+ /* Connect to firmware client */
+ ishtp_set_tx_ring_size(cros_ish_cl, CROS_ISH_CL_TX_RING_SIZE);
+ ishtp_set_rx_ring_size(cros_ish_cl, CROS_ISH_CL_RX_RING_SIZE);
+
+ fw_client = ishtp_fw_cl_get_client(dev, &cros_ish_guid);
+ if (!fw_client) {
+ dev_err(cl_data_to_dev(client_data),
+ "ish client uuid not found\n");
+ rv = -ENOENT;
+ goto err_cl_unlink;
+ }
+
+ ishtp_cl_set_fw_client_id(cros_ish_cl,
+ ishtp_get_fw_client_id(fw_client));
+ ishtp_set_connection_state(cros_ish_cl, ISHTP_CL_CONNECTING);
+
+ rv = ishtp_cl_connect(cros_ish_cl);
+ if (rv) {
+ dev_err(cl_data_to_dev(client_data),
+ "client connect fail\n");
+ goto err_cl_unlink;
+ }
+
+ ishtp_register_event_cb(client_data->cl_device, ish_event_cb);
+ return 0;
+
+err_cl_unlink:
+ ishtp_cl_unlink(cros_ish_cl);
+ return rv;
+}
+
+/**
+ * cros_ish_deinit() - Deinit function for ISHTP client
+ * @cros_ish_cl: ISHTP client instance
+ *
+ * Unlink and free cros_ec client
+ */
+static void cros_ish_deinit(struct ishtp_cl *cros_ish_cl)
+{
+ ishtp_set_connection_state(cros_ish_cl, ISHTP_CL_DISCONNECTING);
+ ishtp_cl_disconnect(cros_ish_cl);
+ ishtp_cl_unlink(cros_ish_cl);
+ ishtp_cl_flush_queues(cros_ish_cl);
+
+ /* Disband and free all Tx and Rx client-level rings */
+ ishtp_cl_free(cros_ish_cl);
+}
+
+/**
+ * prepare_cros_ec_rx() - Check & prepare receive buffer
+ * @ec_dev: CrOS EC MFD device.
+ * @in_msg: Incoming message buffer
+ * @msg: cros_ec command used to send & receive data
+ *
+ * Return: 0 for success, negative error code for failure.
+ *
+ * Check the received buffer. Convert to cros_ec_command format.
+ */
+static int prepare_cros_ec_rx(struct cros_ec_device *ec_dev,
+ const struct cros_ish_in_msg *in_msg,
+ struct cros_ec_command *msg)
+{
+ u8 sum = 0;
+ int i, rv, offset;
+
+ /* Check response error code */
+ msg->result = in_msg->ec_response.result;
+ rv = cros_ec_check_result(ec_dev, msg);
+ if (rv < 0)
+ return rv;
+
+ if (in_msg->ec_response.data_len > msg->insize) {
+ dev_err(ec_dev->dev, "Packet too long (%d bytes, expected %d)",
+ in_msg->ec_response.data_len, msg->insize);
+ return -ENOSPC;
+ }
+
+ /* Copy response packet payload and compute checksum */
+ for (i = 0; i < sizeof(struct ec_host_response); i++)
+ sum += ((u8 *)in_msg)[IN_MSG_EC_RESPONSE_PREAMBLE + i];
+
+ offset = sizeof(struct cros_ish_in_msg);
+ for (i = 0; i < in_msg->ec_response.data_len; i++)
+ sum += msg->data[i] = ((u8 *)in_msg)[offset + i];
+
+ if (sum) {
+ dev_dbg(ec_dev->dev, "Bad received packet checksum %d\n", sum);
+ return -EBADMSG;
+ }
+
+ return 0;
+}
+
+static int cros_ec_pkt_xfer_ish(struct cros_ec_device *ec_dev,
+ struct cros_ec_command *msg)
+{
+ int rv;
+ struct ishtp_cl *cros_ish_cl = ec_dev->priv;
+ struct ishtp_cl_data *client_data = ishtp_get_client_data(cros_ish_cl);
+ struct device *dev = cl_data_to_dev(client_data);
+ struct cros_ish_in_msg *in_msg = (struct cros_ish_in_msg *)ec_dev->din;
+ struct cros_ish_out_msg *out_msg =
+ (struct cros_ish_out_msg *)ec_dev->dout;
+ size_t in_size = sizeof(struct cros_ish_in_msg) + msg->insize;
+ size_t out_size = sizeof(struct cros_ish_out_msg) + msg->outsize;
+
+ /* Sanity checks */
+ if (in_size > ec_dev->din_size) {
+ dev_err(dev,
+ "Incoming payload size %zu is too large for ec_dev->din_size %d\n",
+ in_size, ec_dev->din_size);
+ return -EMSGSIZE;
+ }
+
+ if (out_size > ec_dev->dout_size) {
+ dev_err(dev,
+ "Outgoing payload size %zu is too large for ec_dev->dout_size %d\n",
+ out_size, ec_dev->dout_size);
+ return -EMSGSIZE;
+ }
+
+ /* Proceed only if reset-init is not in progress */
+ if (!down_read_trylock(&init_lock)) {
+ dev_warn(dev,
+ "Host is not ready to send messages to ISH. Try again\n");
+ return -EAGAIN;
+ }
+
+ /* Prepare the package to be sent over ISH TP */
+ out_msg->hdr.channel = CROS_EC_COMMAND;
+ out_msg->hdr.status = 0;
+
+ ec_dev->dout += OUT_MSG_EC_REQUEST_PREAMBLE;
+ cros_ec_prepare_tx(ec_dev, msg);
+ ec_dev->dout -= OUT_MSG_EC_REQUEST_PREAMBLE;
+
+ dev_dbg(dev,
+ "out_msg: struct_ver=0x%x checksum=0x%x command=0x%x command_ver=0x%x data_len=0x%x\n",
+ out_msg->ec_request.struct_version,
+ out_msg->ec_request.checksum,
+ out_msg->ec_request.command,
+ out_msg->ec_request.command_version,
+ out_msg->ec_request.data_len);
+
+ /* Send command to ISH EC firmware and read response */
+ rv = ish_send(client_data,
+ (u8 *)out_msg, out_size,
+ (u8 *)in_msg, in_size);
+ if (rv < 0)
+ goto end_error;
+
+ rv = prepare_cros_ec_rx(ec_dev, in_msg, msg);
+ if (rv)
+ goto end_error;
+
+ rv = in_msg->ec_response.data_len;
+
+ dev_dbg(dev,
+ "in_msg: struct_ver=0x%x checksum=0x%x result=0x%x data_len=0x%x\n",
+ in_msg->ec_response.struct_version,
+ in_msg->ec_response.checksum,
+ in_msg->ec_response.result,
+ in_msg->ec_response.data_len);
+
+end_error:
+ if (msg->command == EC_CMD_REBOOT_EC)
+ msleep(EC_REBOOT_DELAY_MS);
+
+ up_read(&init_lock);
+
+ return rv;
+}
+
+static int cros_ec_dev_init(struct ishtp_cl_data *client_data)
+{
+ struct cros_ec_device *ec_dev;
+ struct device *dev = cl_data_to_dev(client_data);
+
+ ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL);
+ if (!ec_dev)
+ return -ENOMEM;
+
+ client_data->ec_dev = ec_dev;
+ dev->driver_data = ec_dev;
+
+ ec_dev->dev = dev;
+ ec_dev->priv = client_data->cros_ish_cl;
+ ec_dev->cmd_xfer = NULL;
+ ec_dev->pkt_xfer = cros_ec_pkt_xfer_ish;
+ ec_dev->phys_name = dev_name(dev);
+ ec_dev->din_size = sizeof(struct cros_ish_in_msg) +
+ sizeof(struct ec_response_get_protocol_info);
+ ec_dev->dout_size = sizeof(struct cros_ish_out_msg);
+
+ return cros_ec_register(ec_dev);
+}
+
+static void reset_handler(struct work_struct *work)
+{
+ int rv;
+ struct device *dev;
+ struct ishtp_cl *cros_ish_cl;
+ struct ishtp_cl_device *cl_device;
+ struct ishtp_cl_data *client_data =
+ container_of(work, struct ishtp_cl_data, work_ishtp_reset);
+
+ /* Lock for reset to complete */
+ down_write(&init_lock);
+
+ cros_ish_cl = client_data->cros_ish_cl;
+ cl_device = client_data->cl_device;
+
+ /* Unlink, flush queues & start again */
+ ishtp_cl_unlink(cros_ish_cl);
+ ishtp_cl_flush_queues(cros_ish_cl);
+ ishtp_cl_free(cros_ish_cl);
+
+ cros_ish_cl = ishtp_cl_allocate(cl_device);
+ if (!cros_ish_cl) {
+ up_write(&init_lock);
+ return;
+ }
+
+ ishtp_set_drvdata(cl_device, cros_ish_cl);
+ ishtp_set_client_data(cros_ish_cl, client_data);
+ client_data->cros_ish_cl = cros_ish_cl;
+
+ rv = cros_ish_init(cros_ish_cl);
+ if (rv) {
+ ishtp_cl_free(cros_ish_cl);
+ dev_err(cl_data_to_dev(client_data), "Reset Failed\n");
+ up_write(&init_lock);
+ return;
+ }
+
+ /* Refresh ec_dev device pointers */
+ client_data->ec_dev->priv = client_data->cros_ish_cl;
+ dev = cl_data_to_dev(client_data);
+ dev->driver_data = client_data->ec_dev;
+
+ dev_info(cl_data_to_dev(client_data), "Chrome EC ISH reset done\n");
+
+ up_write(&init_lock);
+}
+
+/**
+ * cros_ec_ishtp_probe() - ISHTP client driver probe callback
+ * @cl_device: ISHTP client device instance
+ *
+ * Return: 0 for success, negative error code for failure.
+ */
+static int cros_ec_ishtp_probe(struct ishtp_cl_device *cl_device)
+{
+ int rv;
+ struct ishtp_cl *cros_ish_cl;
+ struct ishtp_cl_data *client_data =
+ devm_kzalloc(ishtp_device(cl_device),
+ sizeof(*client_data), GFP_KERNEL);
+ if (!client_data)
+ return -ENOMEM;
+
+ /* Lock for initialization to complete */
+ down_write(&init_lock);
+
+ cros_ish_cl = ishtp_cl_allocate(cl_device);
+ if (!cros_ish_cl) {
+ rv = -ENOMEM;
+ goto end_ishtp_cl_alloc_error;
+ }
+
+ ishtp_set_drvdata(cl_device, cros_ish_cl);
+ ishtp_set_client_data(cros_ish_cl, client_data);
+ client_data->cros_ish_cl = cros_ish_cl;
+ client_data->cl_device = cl_device;
+
+ init_waitqueue_head(&client_data->response.wait_queue);
+
+ INIT_WORK(&client_data->work_ishtp_reset,
+ reset_handler);
+ INIT_WORK(&client_data->work_ec_evt,
+ ish_evt_handler);
+
+ rv = cros_ish_init(cros_ish_cl);
+ if (rv)
+ goto end_ishtp_cl_init_error;
+
+ ishtp_get_device(cl_device);
+
+ up_write(&init_lock);
+
+ /* Register croc_ec_dev mfd */
+ rv = cros_ec_dev_init(client_data);
+ if (rv)
+ goto end_cros_ec_dev_init_error;
+
+ return 0;
+
+end_cros_ec_dev_init_error:
+ ishtp_set_connection_state(cros_ish_cl, ISHTP_CL_DISCONNECTING);
+ ishtp_cl_disconnect(cros_ish_cl);
+ ishtp_cl_unlink(cros_ish_cl);
+ ishtp_cl_flush_queues(cros_ish_cl);
+ ishtp_put_device(cl_device);
+end_ishtp_cl_init_error:
+ ishtp_cl_free(cros_ish_cl);
+end_ishtp_cl_alloc_error:
+ up_write(&init_lock);
+ return rv;
+}
+
+/**
+ * cros_ec_ishtp_remove() - ISHTP client driver remove callback
+ * @cl_device: ISHTP client device instance
+ *
+ * Return: 0
+ */
+static int cros_ec_ishtp_remove(struct ishtp_cl_device *cl_device)
+{
+ struct ishtp_cl *cros_ish_cl = ishtp_get_drvdata(cl_device);
+ struct ishtp_cl_data *client_data = ishtp_get_client_data(cros_ish_cl);
+
+ cancel_work_sync(&client_data->work_ishtp_reset);
+ cancel_work_sync(&client_data->work_ec_evt);
+ cros_ish_deinit(cros_ish_cl);
+ ishtp_put_device(cl_device);
+
+ return 0;
+}
+
+/**
+ * cros_ec_ishtp_reset() - ISHTP client driver reset callback
+ * @cl_device: ISHTP client device instance
+ *
+ * Return: 0
+ */
+static int cros_ec_ishtp_reset(struct ishtp_cl_device *cl_device)
+{
+ struct ishtp_cl *cros_ish_cl = ishtp_get_drvdata(cl_device);
+ struct ishtp_cl_data *client_data = ishtp_get_client_data(cros_ish_cl);
+
+ schedule_work(&client_data->work_ishtp_reset);
+
+ return 0;
+}
+
+/**
+ * cros_ec_ishtp_suspend() - ISHTP client driver suspend callback
+ * @device: device instance
+ *
+ * Return: 0 for success, negative error code for failure.
+ */
+static int __maybe_unused cros_ec_ishtp_suspend(struct device *device)
+{
+ struct ishtp_cl_device *cl_device = dev_get_drvdata(device);
+ struct ishtp_cl *cros_ish_cl = ishtp_get_drvdata(cl_device);
+ struct ishtp_cl_data *client_data = ishtp_get_client_data(cros_ish_cl);
+
+ return cros_ec_suspend(client_data->ec_dev);
+}
+
+/**
+ * cros_ec_ishtp_resume() - ISHTP client driver resume callback
+ * @device: device instance
+ *
+ * Return: 0 for success, negative error code for failure.
+ */
+static int __maybe_unused cros_ec_ishtp_resume(struct device *device)
+{
+ struct ishtp_cl_device *cl_device = dev_get_drvdata(device);
+ struct ishtp_cl *cros_ish_cl = ishtp_get_drvdata(cl_device);
+ struct ishtp_cl_data *client_data = ishtp_get_client_data(cros_ish_cl);
+
+ return cros_ec_resume(client_data->ec_dev);
+}
+
+static SIMPLE_DEV_PM_OPS(cros_ec_ishtp_pm_ops, cros_ec_ishtp_suspend,
+ cros_ec_ishtp_resume);
+
+static struct ishtp_cl_driver cros_ec_ishtp_driver = {
+ .name = "cros_ec_ishtp",
+ .guid = &cros_ish_guid,
+ .probe = cros_ec_ishtp_probe,
+ .remove = cros_ec_ishtp_remove,
+ .reset = cros_ec_ishtp_reset,
+ .driver = {
+ .pm = &cros_ec_ishtp_pm_ops,
+ },
+};
+
+static int __init cros_ec_ishtp_mod_init(void)
+{
+ return ishtp_cl_driver_register(&cros_ec_ishtp_driver, THIS_MODULE);
+}
+
+static void __exit cros_ec_ishtp_mod_exit(void)
+{
+ ishtp_cl_driver_unregister(&cros_ec_ishtp_driver);
+}
+
+module_init(cros_ec_ishtp_mod_init);
+module_exit(cros_ec_ishtp_mod_exit);
+
+MODULE_DESCRIPTION("ChromeOS EC ISHTP Client Driver");
+MODULE_AUTHOR("Rushikesh S Kadam <rushikesh.s.kadam@intel.com>");
+
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("ishtp:*");
diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c
index d30a6650b0b5..609598bbb6c3 100644
--- a/drivers/platform/chrome/cros_ec_lightbar.c
+++ b/drivers/platform/chrome/cros_ec_lightbar.c
@@ -547,7 +547,7 @@ static struct attribute *__lb_cmds_attrs[] = {
NULL,
};
-struct attribute_group cros_ec_lightbar_attr_group = {
+static struct attribute_group cros_ec_lightbar_attr_group = {
.name = "lightbar",
.attrs = __lb_cmds_attrs,
};
@@ -600,7 +600,7 @@ static int cros_ec_lightbar_remove(struct platform_device *pd)
static int __maybe_unused cros_ec_lightbar_resume(struct device *dev)
{
- struct cros_ec_dev *ec_dev = dev_get_drvdata(dev);
+ struct cros_ec_dev *ec_dev = dev_get_drvdata(dev->parent);
if (userspace_control)
return 0;
@@ -610,7 +610,7 @@ static int __maybe_unused cros_ec_lightbar_resume(struct device *dev)
static int __maybe_unused cros_ec_lightbar_suspend(struct device *dev)
{
- struct cros_ec_dev *ec_dev = dev_get_drvdata(dev);
+ struct cros_ec_dev *ec_dev = dev_get_drvdata(dev->parent);
if (userspace_control)
return 0;
diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c
index c9c240fbe7c6..2c44c7f3322a 100644
--- a/drivers/platform/chrome/cros_ec_lpc.c
+++ b/drivers/platform/chrome/cros_ec_lpc.c
@@ -23,7 +23,7 @@
#include <linux/printk.h>
#include <linux/suspend.h>
-#include "cros_ec_lpc_reg.h"
+#include "cros_ec_lpc_mec.h"
#define DRV_NAME "cros_ec_lpcs"
#define ACPI_DRV_NAME "GOOG0004"
@@ -31,6 +31,96 @@
/* True if ACPI device is present */
static bool cros_ec_lpc_acpi_device_found;
+/**
+ * struct lpc_driver_ops - LPC driver operations
+ * @read: Copy length bytes from EC address offset into buffer dest. Returns
+ * the 8-bit checksum of all bytes read.
+ * @write: Copy length bytes from buffer msg into EC address offset. Returns
+ * the 8-bit checksum of all bytes written.
+ */
+struct lpc_driver_ops {
+ u8 (*read)(unsigned int offset, unsigned int length, u8 *dest);
+ u8 (*write)(unsigned int offset, unsigned int length, const u8 *msg);
+};
+
+static struct lpc_driver_ops cros_ec_lpc_ops = { };
+
+/*
+ * A generic instance of the read function of struct lpc_driver_ops, used for
+ * the LPC EC.
+ */
+static u8 cros_ec_lpc_read_bytes(unsigned int offset, unsigned int length,
+ u8 *dest)
+{
+ int sum = 0;
+ int i;
+
+ for (i = 0; i < length; ++i) {
+ dest[i] = inb(offset + i);
+ sum += dest[i];
+ }
+
+ /* Return checksum of all bytes read */
+ return sum;
+}
+
+/*
+ * A generic instance of the write function of struct lpc_driver_ops, used for
+ * the LPC EC.
+ */
+static u8 cros_ec_lpc_write_bytes(unsigned int offset, unsigned int length,
+ const u8 *msg)
+{
+ int sum = 0;
+ int i;
+
+ for (i = 0; i < length; ++i) {
+ outb(msg[i], offset + i);
+ sum += msg[i];
+ }
+
+ /* Return checksum of all bytes written */
+ return sum;
+}
+
+/*
+ * An instance of the read function of struct lpc_driver_ops, used for the
+ * MEC variant of LPC EC.
+ */
+static u8 cros_ec_lpc_mec_read_bytes(unsigned int offset, unsigned int length,
+ u8 *dest)
+{
+ int in_range = cros_ec_lpc_mec_in_range(offset, length);
+
+ if (in_range < 0)
+ return 0;
+
+ return in_range ?
+ cros_ec_lpc_io_bytes_mec(MEC_IO_READ,
+ offset - EC_HOST_CMD_REGION0,
+ length, dest) :
+ cros_ec_lpc_read_bytes(offset, length, dest);
+}
+
+/*
+ * An instance of the write function of struct lpc_driver_ops, used for the
+ * MEC variant of LPC EC.
+ */
+static u8 cros_ec_lpc_mec_write_bytes(unsigned int offset, unsigned int length,
+ const u8 *msg)
+{
+ int in_range = cros_ec_lpc_mec_in_range(offset, length);
+
+ if (in_range < 0)
+ return 0;
+
+ return in_range ?
+ cros_ec_lpc_io_bytes_mec(MEC_IO_WRITE,
+ offset - EC_HOST_CMD_REGION0,
+ length, (u8 *)msg) :
+ cros_ec_lpc_write_bytes(offset, length, msg);
+}
+
static int ec_response_timed_out(void)
{
unsigned long one_second = jiffies + HZ;
@@ -38,7 +128,7 @@ static int ec_response_timed_out(void)
usleep_range(200, 300);
do {
- if (!(cros_ec_lpc_read_bytes(EC_LPC_ADDR_HOST_CMD, 1, &data) &
+ if (!(cros_ec_lpc_ops.read(EC_LPC_ADDR_HOST_CMD, 1, &data) &
EC_LPC_STATUS_BUSY_MASK))
return 0;
usleep_range(100, 200);
@@ -58,11 +148,11 @@ static int cros_ec_pkt_xfer_lpc(struct cros_ec_device *ec,
ret = cros_ec_prepare_tx(ec, msg);
/* Write buffer */
- cros_ec_lpc_write_bytes(EC_LPC_ADDR_HOST_PACKET, ret, ec->dout);
+ cros_ec_lpc_ops.write(EC_LPC_ADDR_HOST_PACKET, ret, ec->dout);
/* Here we go */
sum = EC_COMMAND_PROTOCOL_3;
- cros_ec_lpc_write_bytes(EC_LPC_ADDR_HOST_CMD, 1, &sum);
+ cros_ec_lpc_ops.write(EC_LPC_ADDR_HOST_CMD, 1, &sum);
if (ec_response_timed_out()) {
dev_warn(ec->dev, "EC responsed timed out\n");
@@ -71,15 +161,15 @@ static int cros_ec_pkt_xfer_lpc(struct cros_ec_device *ec,
}
/* Check result */
- msg->result = cros_ec_lpc_read_bytes(EC_LPC_ADDR_HOST_DATA, 1, &sum);
+ msg->result = cros_ec_lpc_ops.read(EC_LPC_ADDR_HOST_DATA, 1, &sum);
ret = cros_ec_check_result(ec, msg);
if (ret)
goto done;
/* Read back response */
dout = (u8 *)&response;
- sum = cros_ec_lpc_read_bytes(EC_LPC_ADDR_HOST_PACKET, sizeof(response),
- dout);
+ sum = cros_ec_lpc_ops.read(EC_LPC_ADDR_HOST_PACKET, sizeof(response),
+ dout);
msg->result = response.result;
@@ -92,9 +182,9 @@ static int cros_ec_pkt_xfer_lpc(struct cros_ec_device *ec,
}
/* Read response and process checksum */
- sum += cros_ec_lpc_read_bytes(EC_LPC_ADDR_HOST_PACKET +
- sizeof(response), response.data_len,
- msg->data);
+ sum += cros_ec_lpc_ops.read(EC_LPC_ADDR_HOST_PACKET +
+ sizeof(response), response.data_len,
+ msg->data);
if (sum) {
dev_err(ec->dev,
@@ -134,17 +224,17 @@ static int cros_ec_cmd_xfer_lpc(struct cros_ec_device *ec,
sum = msg->command + args.flags + args.command_version + args.data_size;
/* Copy data and update checksum */
- sum += cros_ec_lpc_write_bytes(EC_LPC_ADDR_HOST_PARAM, msg->outsize,
- msg->data);
+ sum += cros_ec_lpc_ops.write(EC_LPC_ADDR_HOST_PARAM, msg->outsize,
+ msg->data);
/* Finalize checksum and write args */
args.checksum = sum;
- cros_ec_lpc_write_bytes(EC_LPC_ADDR_HOST_ARGS, sizeof(args),
- (u8 *)&args);
+ cros_ec_lpc_ops.write(EC_LPC_ADDR_HOST_ARGS, sizeof(args),
+ (u8 *)&args);
/* Here we go */
sum = msg->command;
- cros_ec_lpc_write_bytes(EC_LPC_ADDR_HOST_CMD, 1, &sum);
+ cros_ec_lpc_ops.write(EC_LPC_ADDR_HOST_CMD, 1, &sum);
if (ec_response_timed_out()) {
dev_warn(ec->dev, "EC responsed timed out\n");
@@ -153,14 +243,13 @@ static int cros_ec_cmd_xfer_lpc(struct cros_ec_device *ec,
}
/* Check result */
- msg->result = cros_ec_lpc_read_bytes(EC_LPC_ADDR_HOST_DATA, 1, &sum);
+ msg->result = cros_ec_lpc_ops.read(EC_LPC_ADDR_HOST_DATA, 1, &sum);
ret = cros_ec_check_result(ec, msg);
if (ret)
goto done;
/* Read back args */
- cros_ec_lpc_read_bytes(EC_LPC_ADDR_HOST_ARGS, sizeof(args),
- (u8 *)&args);
+ cros_ec_lpc_ops.read(EC_LPC_ADDR_HOST_ARGS, sizeof(args), (u8 *)&args);
if (args.data_size > msg->insize) {
dev_err(ec->dev,
@@ -174,8 +263,8 @@ static int cros_ec_cmd_xfer_lpc(struct cros_ec_device *ec,
sum = msg->command + args.flags + args.command_version + args.data_size;
/* Read response and update checksum */
- sum += cros_ec_lpc_read_bytes(EC_LPC_ADDR_HOST_PARAM, args.data_size,
- msg->data);
+ sum += cros_ec_lpc_ops.read(EC_LPC_ADDR_HOST_PARAM, args.data_size,
+ msg->data);
/* Verify checksum */
if (args.checksum != sum) {
@@ -205,13 +294,13 @@ static int cros_ec_lpc_readmem(struct cros_ec_device *ec, unsigned int offset,
/* fixed length */
if (bytes) {
- cros_ec_lpc_read_bytes(EC_LPC_ADDR_MEMMAP + offset, bytes, s);
+ cros_ec_lpc_ops.read(EC_LPC_ADDR_MEMMAP + offset, bytes, s);
return bytes;
}
/* string */
for (; i < EC_MEMMAP_SIZE; i++, s++) {
- cros_ec_lpc_read_bytes(EC_LPC_ADDR_MEMMAP + i, 1, s);
+ cros_ec_lpc_ops.read(EC_LPC_ADDR_MEMMAP + i, 1, s);
cnt++;
if (!*s)
break;
@@ -248,10 +337,25 @@ static int cros_ec_lpc_probe(struct platform_device *pdev)
return -EBUSY;
}
- cros_ec_lpc_read_bytes(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID, 2, buf);
+ /*
+ * Read the mapped ID twice, the first one is assuming the
+ * EC is a Microchip Embedded Controller (MEC) variant, if the
+ * protocol fails, fallback to the non MEC variant and try to
+ * read again the ID.
+ */
+ cros_ec_lpc_ops.read = cros_ec_lpc_mec_read_bytes;
+ cros_ec_lpc_ops.write = cros_ec_lpc_mec_write_bytes;
+ cros_ec_lpc_ops.read(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID, 2, buf);
if (buf[0] != 'E' || buf[1] != 'C') {
- dev_err(dev, "EC ID not detected\n");
- return -ENODEV;
+ /* Re-assign read/write operations for the non MEC variant */
+ cros_ec_lpc_ops.read = cros_ec_lpc_read_bytes;
+ cros_ec_lpc_ops.write = cros_ec_lpc_write_bytes;
+ cros_ec_lpc_ops.read(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID, 2,
+ buf);
+ if (buf[0] != 'E' || buf[1] != 'C') {
+ dev_err(dev, "EC ID not detected\n");
+ return -ENODEV;
+ }
}
if (!devm_request_region(dev, EC_HOST_CMD_REGION0,
@@ -405,7 +509,7 @@ static int cros_ec_lpc_resume(struct device *dev)
}
#endif
-const struct dev_pm_ops cros_ec_lpc_pm_ops = {
+static const struct dev_pm_ops cros_ec_lpc_pm_ops = {
SET_LATE_SYSTEM_SLEEP_PM_OPS(cros_ec_lpc_suspend, cros_ec_lpc_resume)
};
@@ -446,13 +550,14 @@ static int __init cros_ec_lpc_init(void)
return -ENODEV;
}
- cros_ec_lpc_reg_init();
+ cros_ec_lpc_mec_init(EC_HOST_CMD_REGION0,
+ EC_LPC_ADDR_MEMMAP + EC_MEMMAP_SIZE);
/* Register the driver */
ret = platform_driver_register(&cros_ec_lpc_driver);
if (ret) {
pr_err(DRV_NAME ": can't register driver: %d\n", ret);
- cros_ec_lpc_reg_destroy();
+ cros_ec_lpc_mec_destroy();
return ret;
}
@@ -462,7 +567,7 @@ static int __init cros_ec_lpc_init(void)
if (ret) {
pr_err(DRV_NAME ": can't register device: %d\n", ret);
platform_driver_unregister(&cros_ec_lpc_driver);
- cros_ec_lpc_reg_destroy();
+ cros_ec_lpc_mec_destroy();
}
}
@@ -474,7 +579,7 @@ static void __exit cros_ec_lpc_exit(void)
if (!cros_ec_lpc_acpi_device_found)
platform_device_unregister(&cros_ec_lpc_device);
platform_driver_unregister(&cros_ec_lpc_driver);
- cros_ec_lpc_reg_destroy();
+ cros_ec_lpc_mec_destroy();
}
module_init(cros_ec_lpc_init);
diff --git a/drivers/platform/chrome/cros_ec_lpc_mec.c b/drivers/platform/chrome/cros_ec_lpc_mec.c
index d8890bafb55d..9035b17e8c86 100644
--- a/drivers/platform/chrome/cros_ec_lpc_mec.c
+++ b/drivers/platform/chrome/cros_ec_lpc_mec.c
@@ -17,12 +17,10 @@
static struct mutex io_mutex;
static u16 mec_emi_base, mec_emi_end;
-/*
- * cros_ec_lpc_mec_emi_write_address
- *
- * Initialize EMI read / write at a given address.
+/**
+ * cros_ec_lpc_mec_emi_write_address() - Initialize EMI at a given address.
*
- * @addr: Starting read / write address
+ * @addr: Starting read / write address
* @access_type: Type of access, typically 32-bit auto-increment
*/
static void cros_ec_lpc_mec_emi_write_address(u16 addr,
@@ -61,15 +59,15 @@ int cros_ec_lpc_mec_in_range(unsigned int offset, unsigned int length)
return 0;
}
-/*
- * cros_ec_lpc_io_bytes_mec - Read / write bytes to MEC EMI port
+/**
+ * cros_ec_lpc_io_bytes_mec() - Read / write bytes to MEC EMI port.
*
* @io_type: MEC_IO_READ or MEC_IO_WRITE, depending on request
* @offset: Base read / write address
* @length: Number of bytes to read / write
* @buf: Destination / source buffer
*
- * @return 8-bit checksum of all bytes read / written
+ * Return: 8-bit checksum of all bytes read / written
*/
u8 cros_ec_lpc_io_bytes_mec(enum cros_ec_lpc_mec_io_type io_type,
unsigned int offset, unsigned int length,
diff --git a/drivers/platform/chrome/cros_ec_lpc_reg.c b/drivers/platform/chrome/cros_ec_lpc_reg.c
deleted file mode 100644
index 0f5cd0ac8b49..000000000000
--- a/drivers/platform/chrome/cros_ec_lpc_reg.c
+++ /dev/null
@@ -1,101 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-// LPC interface for ChromeOS Embedded Controller
-//
-// Copyright (C) 2016 Google, Inc
-
-#include <linux/io.h>
-#include <linux/mfd/cros_ec.h>
-#include <linux/mfd/cros_ec_commands.h>
-
-#include "cros_ec_lpc_mec.h"
-
-static u8 lpc_read_bytes(unsigned int offset, unsigned int length, u8 *dest)
-{
- int i;
- int sum = 0;
-
- for (i = 0; i < length; ++i) {
- dest[i] = inb(offset + i);
- sum += dest[i];
- }
-
- /* Return checksum of all bytes read */
- return sum;
-}
-
-static u8 lpc_write_bytes(unsigned int offset, unsigned int length, u8 *msg)
-{
- int i;
- int sum = 0;
-
- for (i = 0; i < length; ++i) {
- outb(msg[i], offset + i);
- sum += msg[i];
- }
-
- /* Return checksum of all bytes written */
- return sum;
-}
-
-#ifdef CONFIG_CROS_EC_LPC_MEC
-
-u8 cros_ec_lpc_read_bytes(unsigned int offset, unsigned int length, u8 *dest)
-{
- int in_range = cros_ec_lpc_mec_in_range(offset, length);
-
- if (in_range < 0)
- return 0;
-
- return in_range ?
- cros_ec_lpc_io_bytes_mec(MEC_IO_READ,
- offset - EC_HOST_CMD_REGION0,
- length, dest) :
- lpc_read_bytes(offset, length, dest);
-}
-
-u8 cros_ec_lpc_write_bytes(unsigned int offset, unsigned int length, u8 *msg)
-{
- int in_range = cros_ec_lpc_mec_in_range(offset, length);
-
- if (in_range < 0)
- return 0;
-
- return in_range ?
- cros_ec_lpc_io_bytes_mec(MEC_IO_WRITE,
- offset - EC_HOST_CMD_REGION0,
- length, msg) :
- lpc_write_bytes(offset, length, msg);
-}
-
-void cros_ec_lpc_reg_init(void)
-{
- cros_ec_lpc_mec_init(EC_HOST_CMD_REGION0,
- EC_LPC_ADDR_MEMMAP + EC_MEMMAP_SIZE);
-}
-
-void cros_ec_lpc_reg_destroy(void)
-{
- cros_ec_lpc_mec_destroy();
-}
-
-#else /* CONFIG_CROS_EC_LPC_MEC */
-
-u8 cros_ec_lpc_read_bytes(unsigned int offset, unsigned int length, u8 *dest)
-{
- return lpc_read_bytes(offset, length, dest);
-}
-
-u8 cros_ec_lpc_write_bytes(unsigned int offset, unsigned int length, u8 *msg)
-{
- return lpc_write_bytes(offset, length, msg);
-}
-
-void cros_ec_lpc_reg_init(void)
-{
-}
-
-void cros_ec_lpc_reg_destroy(void)
-{
-}
-
-#endif /* CONFIG_CROS_EC_LPC_MEC */
diff --git a/drivers/platform/chrome/cros_ec_lpc_reg.h b/drivers/platform/chrome/cros_ec_lpc_reg.h
deleted file mode 100644
index 416fd2572182..000000000000
--- a/drivers/platform/chrome/cros_ec_lpc_reg.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * LPC interface for ChromeOS Embedded Controller
- *
- * Copyright (C) 2016 Google, Inc
- */
-
-#ifndef __CROS_EC_LPC_REG_H
-#define __CROS_EC_LPC_REG_H
-
-/**
- * cros_ec_lpc_read_bytes - Read bytes from a given LPC-mapped address.
- * Returns 8-bit checksum of all bytes read.
- *
- * @offset: Base read address
- * @length: Number of bytes to read
- * @dest: Destination buffer
- */
-u8 cros_ec_lpc_read_bytes(unsigned int offset, unsigned int length, u8 *dest);
-
-/**
- * cros_ec_lpc_write_bytes - Write bytes to a given LPC-mapped address.
- * Returns 8-bit checksum of all bytes written.
- *
- * @offset: Base write address
- * @length: Number of bytes to write
- * @msg: Write data buffer
- */
-u8 cros_ec_lpc_write_bytes(unsigned int offset, unsigned int length, u8 *msg);
-
-/**
- * cros_ec_lpc_reg_init
- *
- * Initialize register I/O.
- */
-void cros_ec_lpc_reg_init(void);
-
-/**
- * cros_ec_lpc_reg_destroy
- *
- * Cleanup reg I/O.
- */
-void cros_ec_lpc_reg_destroy(void);
-
-#endif /* __CROS_EC_LPC_REG_H */
diff --git a/drivers/platform/chrome/cros_ec_spi.c b/drivers/platform/chrome/cros_ec_spi.c
index 8e9451720e73..006a8ff64057 100644
--- a/drivers/platform/chrome/cros_ec_spi.c
+++ b/drivers/platform/chrome/cros_ec_spi.c
@@ -12,7 +12,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
-
+#include <uapi/linux/sched/types.h>
/* The header byte, which follows the preamble */
#define EC_MSG_HEADER 0xec
@@ -67,12 +67,14 @@
* is sent when we want to turn on CS at the start of a transaction.
* @end_of_msg_delay: used to set the delay_usecs on the spi_transfer that
* is sent when we want to turn off CS at the end of a transaction.
+ * @high_pri_worker: Used to schedule high priority work.
*/
struct cros_ec_spi {
struct spi_device *spi;
s64 last_transfer_ns;
unsigned int start_of_msg_delay;
unsigned int end_of_msg_delay;
+ struct kthread_worker *high_pri_worker;
};
typedef int (*cros_ec_xfer_fn_t) (struct cros_ec_device *ec_dev,
@@ -89,7 +91,7 @@ typedef int (*cros_ec_xfer_fn_t) (struct cros_ec_device *ec_dev,
*/
struct cros_ec_xfer_work_params {
- struct work_struct work;
+ struct kthread_work work;
cros_ec_xfer_fn_t fn;
struct cros_ec_device *ec_dev;
struct cros_ec_command *ec_msg;
@@ -632,7 +634,7 @@ exit:
return ret;
}
-static void cros_ec_xfer_high_pri_work(struct work_struct *work)
+static void cros_ec_xfer_high_pri_work(struct kthread_work *work)
{
struct cros_ec_xfer_work_params *params;
@@ -644,12 +646,14 @@ static int cros_ec_xfer_high_pri(struct cros_ec_device *ec_dev,
struct cros_ec_command *ec_msg,
cros_ec_xfer_fn_t fn)
{
- struct cros_ec_xfer_work_params params;
-
- INIT_WORK_ONSTACK(&params.work, cros_ec_xfer_high_pri_work);
- params.ec_dev = ec_dev;
- params.ec_msg = ec_msg;
- params.fn = fn;
+ struct cros_ec_spi *ec_spi = ec_dev->priv;
+ struct cros_ec_xfer_work_params params = {
+ .work = KTHREAD_WORK_INIT(params.work,
+ cros_ec_xfer_high_pri_work),
+ .ec_dev = ec_dev,
+ .ec_msg = ec_msg,
+ .fn = fn,
+ };
/*
* This looks a bit ridiculous. Why do the work on a
@@ -660,9 +664,8 @@ static int cros_ec_xfer_high_pri(struct cros_ec_device *ec_dev,
* context switched out for too long and the EC giving up on
* the transfer.
*/
- queue_work(system_highpri_wq, &params.work);
- flush_work(&params.work);
- destroy_work_on_stack(&params.work);
+ kthread_queue_work(ec_spi->high_pri_worker, &params.work);
+ kthread_flush_work(&params.work);
return params.ret;
}
@@ -694,6 +697,40 @@ static void cros_ec_spi_dt_probe(struct cros_ec_spi *ec_spi, struct device *dev)
ec_spi->end_of_msg_delay = val;
}
+static void cros_ec_spi_high_pri_release(void *worker)
+{
+ kthread_destroy_worker(worker);
+}
+
+static int cros_ec_spi_devm_high_pri_alloc(struct device *dev,
+ struct cros_ec_spi *ec_spi)
+{
+ struct sched_param sched_priority = {
+ .sched_priority = MAX_RT_PRIO - 1,
+ };
+ int err;
+
+ ec_spi->high_pri_worker =
+ kthread_create_worker(0, "cros_ec_spi_high_pri");
+
+ if (IS_ERR(ec_spi->high_pri_worker)) {
+ err = PTR_ERR(ec_spi->high_pri_worker);
+ dev_err(dev, "Can't create cros_ec high pri worker: %d\n", err);
+ return err;
+ }
+
+ err = devm_add_action_or_reset(dev, cros_ec_spi_high_pri_release,
+ ec_spi->high_pri_worker);
+ if (err)
+ return err;
+
+ err = sched_setscheduler_nocheck(ec_spi->high_pri_worker->task,
+ SCHED_FIFO, &sched_priority);
+ if (err)
+ dev_err(dev, "Can't set cros_ec high pri priority: %d\n", err);
+ return err;
+}
+
static int cros_ec_spi_probe(struct spi_device *spi)
{
struct device *dev = &spi->dev;
@@ -703,6 +740,7 @@ static int cros_ec_spi_probe(struct spi_device *spi)
spi->bits_per_word = 8;
spi->mode = SPI_MODE_0;
+ spi->rt = true;
err = spi_setup(spi);
if (err < 0)
return err;
@@ -732,6 +770,10 @@ static int cros_ec_spi_probe(struct spi_device *spi)
ec_spi->last_transfer_ns = ktime_get_ns();
+ err = cros_ec_spi_devm_high_pri_alloc(dev, ec_spi);
+ if (err)
+ return err;
+
err = cros_ec_register(ec_dev);
if (err) {
dev_err(dev, "cannot register EC\n");
@@ -777,7 +819,7 @@ MODULE_DEVICE_TABLE(spi, cros_ec_spi_id);
static struct spi_driver cros_ec_driver_spi = {
.driver = {
.name = "cros-ec-spi",
- .of_match_table = of_match_ptr(cros_ec_spi_of_match),
+ .of_match_table = cros_ec_spi_of_match,
.pm = &cros_ec_spi_pm_ops,
},
.probe = cros_ec_spi_probe,
diff --git a/drivers/platform/chrome/cros_ec_sysfs.c b/drivers/platform/chrome/cros_ec_sysfs.c
index fe0b7614ae1b..3edb237bf8ed 100644
--- a/drivers/platform/chrome/cros_ec_sysfs.c
+++ b/drivers/platform/chrome/cros_ec_sysfs.c
@@ -335,7 +335,7 @@ static umode_t cros_ec_ctrl_visible(struct kobject *kobj,
return a->mode;
}
-struct attribute_group cros_ec_attr_group = {
+static struct attribute_group cros_ec_attr_group = {
.attrs = __ec_attrs,
.is_visible = cros_ec_ctrl_visible,
};
diff --git a/drivers/platform/chrome/cros_ec_vbc.c b/drivers/platform/chrome/cros_ec_vbc.c
index 8392a1ec33a7..2aaefed87eb4 100644
--- a/drivers/platform/chrome/cros_ec_vbc.c
+++ b/drivers/platform/chrome/cros_ec_vbc.c
@@ -101,7 +101,7 @@ static struct bin_attribute *cros_ec_vbc_bin_attrs[] = {
NULL
};
-struct attribute_group cros_ec_vbc_attr_group = {
+static struct attribute_group cros_ec_vbc_attr_group = {
.name = "vbc",
.bin_attrs = cros_ec_vbc_bin_attrs,
};
diff --git a/drivers/platform/chrome/wilco_ec/Kconfig b/drivers/platform/chrome/wilco_ec/Kconfig
index fd29cbfd3d5d..89007b0bc743 100644
--- a/drivers/platform/chrome/wilco_ec/Kconfig
+++ b/drivers/platform/chrome/wilco_ec/Kconfig
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
config WILCO_EC
tristate "ChromeOS Wilco Embedded Controller"
- depends on ACPI && X86 && CROS_EC_LPC && CROS_EC_LPC_MEC
+ depends on ACPI && X86 && CROS_EC_LPC
help
If you say Y here, you get support for talking to the ChromeOS
Wilco EC over an eSPI bus. This uses a simple byte-level protocol
@@ -19,3 +19,19 @@ config WILCO_EC_DEBUGFS
manipulation and allow for testing arbitrary commands. This
interface is intended for debug only and will not be present
on production devices.
+
+config WILCO_EC_EVENTS
+ tristate "Enable event forwarding from EC to userspace"
+ depends on WILCO_EC
+ help
+ If you say Y here, you get support for the EC to send events
+ (such as power state changes) to userspace. The EC sends the events
+ over ACPI, and a driver queues up the events to be read by a
+ userspace daemon from /dev/wilco_event using read() and poll().
+
+config WILCO_EC_TELEMETRY
+ tristate "Enable querying telemetry data from EC"
+ depends on WILCO_EC
+ help
+ If you say Y here, you get support to query EC telemetry data from
+ /dev/wilco_telem0 using write() and then read().
diff --git a/drivers/platform/chrome/wilco_ec/Makefile b/drivers/platform/chrome/wilco_ec/Makefile
index 063e7fb4ea17..bc817164596e 100644
--- a/drivers/platform/chrome/wilco_ec/Makefile
+++ b/drivers/platform/chrome/wilco_ec/Makefile
@@ -1,6 +1,10 @@
# SPDX-License-Identifier: GPL-2.0
-wilco_ec-objs := core.o mailbox.o
+wilco_ec-objs := core.o mailbox.o properties.o sysfs.o
obj-$(CONFIG_WILCO_EC) += wilco_ec.o
wilco_ec_debugfs-objs := debugfs.o
obj-$(CONFIG_WILCO_EC_DEBUGFS) += wilco_ec_debugfs.o
+wilco_ec_events-objs := event.o
+obj-$(CONFIG_WILCO_EC_EVENTS) += wilco_ec_events.o
+wilco_ec_telem-objs := telemetry.o
+obj-$(CONFIG_WILCO_EC_TELEMETRY) += wilco_ec_telem.o
diff --git a/drivers/platform/chrome/wilco_ec/core.c b/drivers/platform/chrome/wilco_ec/core.c
index 05e1e2be1c91..3724bf4b77c6 100644
--- a/drivers/platform/chrome/wilco_ec/core.c
+++ b/drivers/platform/chrome/wilco_ec/core.c
@@ -52,9 +52,7 @@ static int wilco_ec_probe(struct platform_device *pdev)
ec->dev = dev;
mutex_init(&ec->mailbox_lock);
- /* Largest data buffer size requirement is extended data response */
- ec->data_size = sizeof(struct wilco_ec_response) +
- EC_MAILBOX_DATA_SIZE_EXTENDED;
+ ec->data_size = sizeof(struct wilco_ec_response) + EC_MAILBOX_DATA_SIZE;
ec->data_buffer = devm_kzalloc(dev, ec->data_size, GFP_KERNEL);
if (!ec->data_buffer)
return -ENOMEM;
@@ -89,8 +87,28 @@ static int wilco_ec_probe(struct platform_device *pdev)
goto unregister_debugfs;
}
+ ret = wilco_ec_add_sysfs(ec);
+ if (ret < 0) {
+ dev_err(dev, "Failed to create sysfs entries: %d", ret);
+ goto unregister_rtc;
+ }
+
+ /* Register child device that will be found by the telemetry driver. */
+ ec->telem_pdev = platform_device_register_data(dev, "wilco_telem",
+ PLATFORM_DEVID_AUTO,
+ ec, sizeof(*ec));
+ if (IS_ERR(ec->telem_pdev)) {
+ dev_err(dev, "Failed to create telemetry platform device\n");
+ ret = PTR_ERR(ec->telem_pdev);
+ goto remove_sysfs;
+ }
+
return 0;
+remove_sysfs:
+ wilco_ec_remove_sysfs(ec);
+unregister_rtc:
+ platform_device_unregister(ec->rtc_pdev);
unregister_debugfs:
if (ec->debugfs_pdev)
platform_device_unregister(ec->debugfs_pdev);
@@ -102,6 +120,8 @@ static int wilco_ec_remove(struct platform_device *pdev)
{
struct wilco_ec_device *ec = platform_get_drvdata(pdev);
+ wilco_ec_remove_sysfs(ec);
+ platform_device_unregister(ec->telem_pdev);
platform_device_unregister(ec->rtc_pdev);
if (ec->debugfs_pdev)
platform_device_unregister(ec->debugfs_pdev);
diff --git a/drivers/platform/chrome/wilco_ec/debugfs.c b/drivers/platform/chrome/wilco_ec/debugfs.c
index f163476d080d..8d65a1e2f1a3 100644
--- a/drivers/platform/chrome/wilco_ec/debugfs.c
+++ b/drivers/platform/chrome/wilco_ec/debugfs.c
@@ -16,14 +16,14 @@
#define DRV_NAME "wilco-ec-debugfs"
-/* The 256 raw bytes will take up more space when represented as a hex string */
-#define FORMATTED_BUFFER_SIZE (EC_MAILBOX_DATA_SIZE_EXTENDED * 4)
+/* The raw bytes will take up more space when represented as a hex string */
+#define FORMATTED_BUFFER_SIZE (EC_MAILBOX_DATA_SIZE * 4)
struct wilco_ec_debugfs {
struct wilco_ec_device *ec;
struct dentry *dir;
size_t response_size;
- u8 raw_data[EC_MAILBOX_DATA_SIZE_EXTENDED];
+ u8 raw_data[EC_MAILBOX_DATA_SIZE];
u8 formatted_data[FORMATTED_BUFFER_SIZE];
};
static struct wilco_ec_debugfs *debug_info;
@@ -124,12 +124,6 @@ static ssize_t raw_write(struct file *file, const char __user *user_buf,
msg.response_data = debug_info->raw_data;
msg.response_size = EC_MAILBOX_DATA_SIZE;
- /* Telemetry commands use extended response data */
- if (msg.type == WILCO_EC_MSG_TELEMETRY_LONG) {
- msg.flags |= WILCO_EC_FLAG_EXTENDED_DATA;
- msg.response_size = EC_MAILBOX_DATA_SIZE_EXTENDED;
- }
-
ret = wilco_ec_mailbox(debug_info->ec, &msg);
if (ret < 0)
return ret;
diff --git a/drivers/platform/chrome/wilco_ec/event.c b/drivers/platform/chrome/wilco_ec/event.c
new file mode 100644
index 000000000000..dba3d445623f
--- /dev/null
+++ b/drivers/platform/chrome/wilco_ec/event.c
@@ -0,0 +1,581 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ACPI event handling for Wilco Embedded Controller
+ *
+ * Copyright 2019 Google LLC
+ *
+ * The Wilco Embedded Controller can create custom events that
+ * are not handled as standard ACPI objects. These events can
+ * contain information about changes in EC controlled features,
+ * such as errors and events in the dock or display. For example,
+ * an event is triggered if the dock is plugged into a display
+ * incorrectly. These events are needed for telemetry and
+ * diagnostics reasons, and for possibly alerting the user.
+
+ * These events are triggered by the EC with an ACPI Notify(0x90),
+ * and then the BIOS reads the event buffer from EC RAM via an
+ * ACPI method. When the OS receives these events via ACPI,
+ * it passes them along to this driver. The events are put into
+ * a queue which can be read by a userspace daemon via a char device
+ * that implements read() and poll(). The event queue acts as a
+ * circular buffer of size 64, so if there are no userspace consumers
+ * the kernel will not run out of memory. The char device will appear at
+ * /dev/wilco_event{n}, where n is some small non-negative integer,
+ * starting from 0. Standard ACPI events such as the battery getting
+ * plugged/unplugged can also come through this path, but they are
+ * dealt with via other paths, and are ignored here.
+
+ * To test, you can tail the binary data with
+ * $ cat /dev/wilco_event0 | hexdump -ve '1/1 "%x\n"'
+ * and then create an event by plugging/unplugging the battery.
+ */
+
+#include <linux/acpi.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/idr.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+
+/* ACPI Notify event code indicating event data is available. */
+#define EC_ACPI_NOTIFY_EVENT 0x90
+/* ACPI Method to execute to retrieve event data buffer from the EC. */
+#define EC_ACPI_GET_EVENT "QSET"
+/* Maximum number of words in event data returned by the EC. */
+#define EC_ACPI_MAX_EVENT_WORDS 6
+#define EC_ACPI_MAX_EVENT_SIZE \
+ (sizeof(struct ec_event) + (EC_ACPI_MAX_EVENT_WORDS) * sizeof(u16))
+
+/* Node will appear in /dev/EVENT_DEV_NAME */
+#define EVENT_DEV_NAME "wilco_event"
+#define EVENT_CLASS_NAME EVENT_DEV_NAME
+#define DRV_NAME EVENT_DEV_NAME
+#define EVENT_DEV_NAME_FMT (EVENT_DEV_NAME "%d")
+static struct class event_class = {
+ .owner = THIS_MODULE,
+ .name = EVENT_CLASS_NAME,
+};
+
+/* Keep track of all the device numbers used. */
+#define EVENT_MAX_DEV 128
+static int event_major;
+static DEFINE_IDA(event_ida);
+
+/* Size of circular queue of events. */
+#define MAX_NUM_EVENTS 64
+
+/**
+ * struct ec_event - Extended event returned by the EC.
+ * @size: Number of 16bit words in structure after the size word.
+ * @type: Extended event type, meaningless for us.
+ * @event: Event data words. Max count is %EC_ACPI_MAX_EVENT_WORDS.
+ */
+struct ec_event {
+ u16 size;
+ u16 type;
+ u16 event[0];
+} __packed;
+
+#define ec_event_num_words(ev) (ev->size - 1)
+#define ec_event_size(ev) (sizeof(*ev) + (ec_event_num_words(ev) * sizeof(u16)))
+
+/**
+ * struct ec_event_queue - Circular queue for events.
+ * @capacity: Number of elements the queue can hold.
+ * @head: Next index to write to.
+ * @tail: Next index to read from.
+ * @entries: Array of events.
+ */
+struct ec_event_queue {
+ int capacity;
+ int head;
+ int tail;
+ struct ec_event *entries[0];
+};
+
+/* Maximum number of events to store in ec_event_queue */
+static int queue_size = 64;
+module_param(queue_size, int, 0644);
+
+static struct ec_event_queue *event_queue_new(int capacity)
+{
+ struct ec_event_queue *q;
+
+ q = kzalloc(struct_size(q, entries, capacity), GFP_KERNEL);
+ if (!q)
+ return NULL;
+
+ q->capacity = capacity;
+
+ return q;
+}
+
+static inline bool event_queue_empty(struct ec_event_queue *q)
+{
+ /* head==tail when both full and empty, but head==NULL when empty */
+ return q->head == q->tail && !q->entries[q->head];
+}
+
+static inline bool event_queue_full(struct ec_event_queue *q)
+{
+ /* head==tail when both full and empty, but head!=NULL when full */
+ return q->head == q->tail && q->entries[q->head];
+}
+
+static struct ec_event *event_queue_pop(struct ec_event_queue *q)
+{
+ struct ec_event *ev;
+
+ if (event_queue_empty(q))
+ return NULL;
+
+ ev = q->entries[q->tail];
+ q->entries[q->tail] = NULL;
+ q->tail = (q->tail + 1) % q->capacity;
+
+ return ev;
+}
+
+/*
+ * If full, overwrite the oldest event and return it so the caller
+ * can kfree it. If not full, return NULL.
+ */
+static struct ec_event *event_queue_push(struct ec_event_queue *q,
+ struct ec_event *ev)
+{
+ struct ec_event *popped = NULL;
+
+ if (event_queue_full(q))
+ popped = event_queue_pop(q);
+ q->entries[q->head] = ev;
+ q->head = (q->head + 1) % q->capacity;
+
+ return popped;
+}
+
+static void event_queue_free(struct ec_event_queue *q)
+{
+ struct ec_event *event;
+
+ while ((event = event_queue_pop(q)) != NULL)
+ kfree(event);
+
+ kfree(q);
+}
+
+/**
+ * struct event_device_data - Data for a Wilco EC device that responds to ACPI.
+ * @events: Circular queue of EC events to be provided to userspace.
+ * @queue_lock: Protect the queue from simultaneous read/writes.
+ * @wq: Wait queue to notify processes when events are available or the
+ * device has been removed.
+ * @cdev: Char dev that userspace reads() and polls() from.
+ * @dev: Device associated with the %cdev.
+ * @exist: Has the device been not been removed? Once a device has been removed,
+ * writes, reads, and new opens will fail.
+ * @available: Guarantee only one client can open() file and read from queue.
+ *
+ * There will be one of these structs for each ACPI device registered. This data
+ * is the queue of events received from ACPI that still need to be read from
+ * userspace, the device and char device that userspace is using, a wait queue
+ * used to notify different threads when something has changed, plus a flag
+ * on whether the ACPI device has been removed.
+ */
+struct event_device_data {
+ struct ec_event_queue *events;
+ spinlock_t queue_lock;
+ wait_queue_head_t wq;
+ struct device dev;
+ struct cdev cdev;
+ bool exist;
+ atomic_t available;
+};
+
+/**
+ * enqueue_events() - Place EC events in queue to be read by userspace.
+ * @adev: Device the events came from.
+ * @buf: Buffer of event data.
+ * @length: Length of event data buffer.
+ *
+ * %buf contains a number of ec_event's, packed one after the other.
+ * Each ec_event is of variable length. Start with the first event, copy it
+ * into a persistent ec_event, store that entry in the queue, move on
+ * to the next ec_event in buf, and repeat.
+ *
+ * Return: 0 on success or negative error code on failure.
+ */
+static int enqueue_events(struct acpi_device *adev, const u8 *buf, u32 length)
+{
+ struct event_device_data *dev_data = adev->driver_data;
+ struct ec_event *event, *queue_event, *old_event;
+ size_t num_words, event_size;
+ u32 offset = 0;
+
+ while (offset < length) {
+ event = (struct ec_event *)(buf + offset);
+
+ num_words = ec_event_num_words(event);
+ event_size = ec_event_size(event);
+ if (num_words > EC_ACPI_MAX_EVENT_WORDS) {
+ dev_err(&adev->dev, "Too many event words: %zu > %d\n",
+ num_words, EC_ACPI_MAX_EVENT_WORDS);
+ return -EOVERFLOW;
+ }
+
+ /* Ensure event does not overflow the available buffer */
+ if ((offset + event_size) > length) {
+ dev_err(&adev->dev, "Event exceeds buffer: %zu > %d\n",
+ offset + event_size, length);
+ return -EOVERFLOW;
+ }
+
+ /* Point to the next event in the buffer */
+ offset += event_size;
+
+ /* Copy event into the queue */
+ queue_event = kmemdup(event, event_size, GFP_KERNEL);
+ if (!queue_event)
+ return -ENOMEM;
+ spin_lock(&dev_data->queue_lock);
+ old_event = event_queue_push(dev_data->events, queue_event);
+ spin_unlock(&dev_data->queue_lock);
+ kfree(old_event);
+ wake_up_interruptible(&dev_data->wq);
+ }
+
+ return 0;
+}
+
+/**
+ * event_device_notify() - Callback when EC generates an event over ACPI.
+ * @adev: The device that the event is coming from.
+ * @value: Value passed to Notify() in ACPI.
+ *
+ * This function will read the events from the device and enqueue them.
+ */
+static void event_device_notify(struct acpi_device *adev, u32 value)
+{
+ struct acpi_buffer event_buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj;
+ acpi_status status;
+
+ if (value != EC_ACPI_NOTIFY_EVENT) {
+ dev_err(&adev->dev, "Invalid event: 0x%08x\n", value);
+ return;
+ }
+
+ /* Execute ACPI method to get event data buffer. */
+ status = acpi_evaluate_object(adev->handle, EC_ACPI_GET_EVENT,
+ NULL, &event_buffer);
+ if (ACPI_FAILURE(status)) {
+ dev_err(&adev->dev, "Error executing ACPI method %s()\n",
+ EC_ACPI_GET_EVENT);
+ return;
+ }
+
+ obj = (union acpi_object *)event_buffer.pointer;
+ if (!obj) {
+ dev_err(&adev->dev, "Nothing returned from %s()\n",
+ EC_ACPI_GET_EVENT);
+ return;
+ }
+ if (obj->type != ACPI_TYPE_BUFFER) {
+ dev_err(&adev->dev, "Invalid object returned from %s()\n",
+ EC_ACPI_GET_EVENT);
+ kfree(obj);
+ return;
+ }
+ if (obj->buffer.length < sizeof(struct ec_event)) {
+ dev_err(&adev->dev, "Invalid buffer length %d from %s()\n",
+ obj->buffer.length, EC_ACPI_GET_EVENT);
+ kfree(obj);
+ return;
+ }
+
+ enqueue_events(adev, obj->buffer.pointer, obj->buffer.length);
+ kfree(obj);
+}
+
+static int event_open(struct inode *inode, struct file *filp)
+{
+ struct event_device_data *dev_data;
+
+ dev_data = container_of(inode->i_cdev, struct event_device_data, cdev);
+ if (!dev_data->exist)
+ return -ENODEV;
+
+ if (atomic_cmpxchg(&dev_data->available, 1, 0) == 0)
+ return -EBUSY;
+
+ /* Increase refcount on device so dev_data is not freed */
+ get_device(&dev_data->dev);
+ stream_open(inode, filp);
+ filp->private_data = dev_data;
+
+ return 0;
+}
+
+static __poll_t event_poll(struct file *filp, poll_table *wait)
+{
+ struct event_device_data *dev_data = filp->private_data;
+ __poll_t mask = 0;
+
+ poll_wait(filp, &dev_data->wq, wait);
+ if (!dev_data->exist)
+ return EPOLLHUP;
+ if (!event_queue_empty(dev_data->events))
+ mask |= EPOLLIN | EPOLLRDNORM | EPOLLPRI;
+ return mask;
+}
+
+/**
+ * event_read() - Callback for passing event data to userspace via read().
+ * @filp: The file we are reading from.
+ * @buf: Pointer to userspace buffer to fill with one event.
+ * @count: Number of bytes requested. Must be at least EC_ACPI_MAX_EVENT_SIZE.
+ * @pos: File position pointer, irrelevant since we don't support seeking.
+ *
+ * Removes the first event from the queue, places it in the passed buffer.
+ *
+ * If there are no events in the the queue, then one of two things happens,
+ * depending on if the file was opened in nonblocking mode: If in nonblocking
+ * mode, then return -EAGAIN to say there's no data. If in blocking mode, then
+ * block until an event is available.
+ *
+ * Return: Number of bytes placed in buffer, negative error code on failure.
+ */
+static ssize_t event_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *pos)
+{
+ struct event_device_data *dev_data = filp->private_data;
+ struct ec_event *event;
+ ssize_t n_bytes_written = 0;
+ int err;
+
+ /* We only will give them the entire event at once */
+ if (count != 0 && count < EC_ACPI_MAX_EVENT_SIZE)
+ return -EINVAL;
+
+ spin_lock(&dev_data->queue_lock);
+ while (event_queue_empty(dev_data->events)) {
+ spin_unlock(&dev_data->queue_lock);
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ err = wait_event_interruptible(dev_data->wq,
+ !event_queue_empty(dev_data->events) ||
+ !dev_data->exist);
+ if (err)
+ return err;
+
+ /* Device was removed as we waited? */
+ if (!dev_data->exist)
+ return -ENODEV;
+ spin_lock(&dev_data->queue_lock);
+ }
+ event = event_queue_pop(dev_data->events);
+ spin_unlock(&dev_data->queue_lock);
+ n_bytes_written = ec_event_size(event);
+ if (copy_to_user(buf, event, n_bytes_written))
+ n_bytes_written = -EFAULT;
+ kfree(event);
+
+ return n_bytes_written;
+}
+
+static int event_release(struct inode *inode, struct file *filp)
+{
+ struct event_device_data *dev_data = filp->private_data;
+
+ atomic_set(&dev_data->available, 1);
+ put_device(&dev_data->dev);
+
+ return 0;
+}
+
+static const struct file_operations event_fops = {
+ .open = event_open,
+ .poll = event_poll,
+ .read = event_read,
+ .release = event_release,
+ .llseek = no_llseek,
+ .owner = THIS_MODULE,
+};
+
+/**
+ * free_device_data() - Callback to free the event_device_data structure.
+ * @d: The device embedded in our device data, which we have been ref counting.
+ *
+ * This is called only after event_device_remove() has been called and all
+ * userspace programs have called event_release() on all the open file
+ * descriptors.
+ */
+static void free_device_data(struct device *d)
+{
+ struct event_device_data *dev_data;
+
+ dev_data = container_of(d, struct event_device_data, dev);
+ event_queue_free(dev_data->events);
+ kfree(dev_data);
+}
+
+static void hangup_device(struct event_device_data *dev_data)
+{
+ dev_data->exist = false;
+ /* Wake up the waiting processes so they can close. */
+ wake_up_interruptible(&dev_data->wq);
+ put_device(&dev_data->dev);
+}
+
+/**
+ * event_device_add() - Callback when creating a new device.
+ * @adev: ACPI device that we will be receiving events from.
+ *
+ * This finds a free minor number for the device, allocates and initializes
+ * some device data, and creates a new device and char dev node.
+ *
+ * The device data is freed in free_device_data(), which is called when
+ * %dev_data->dev is release()ed. This happens after all references to
+ * %dev_data->dev are dropped, which happens once both event_device_remove()
+ * has been called and every open()ed file descriptor has been release()ed.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+static int event_device_add(struct acpi_device *adev)
+{
+ struct event_device_data *dev_data;
+ int error, minor;
+
+ minor = ida_alloc_max(&event_ida, EVENT_MAX_DEV-1, GFP_KERNEL);
+ if (minor < 0) {
+ error = minor;
+ dev_err(&adev->dev, "Failed to find minor number: %d\n", error);
+ return error;
+ }
+
+ dev_data = kzalloc(sizeof(*dev_data), GFP_KERNEL);
+ if (!dev_data) {
+ error = -ENOMEM;
+ goto free_minor;
+ }
+
+ /* Initialize the device data. */
+ adev->driver_data = dev_data;
+ dev_data->events = event_queue_new(queue_size);
+ if (!dev_data->events) {
+ kfree(dev_data);
+ error = -ENOMEM;
+ goto free_minor;
+ }
+ spin_lock_init(&dev_data->queue_lock);
+ init_waitqueue_head(&dev_data->wq);
+ dev_data->exist = true;
+ atomic_set(&dev_data->available, 1);
+
+ /* Initialize the device. */
+ dev_data->dev.devt = MKDEV(event_major, minor);
+ dev_data->dev.class = &event_class;
+ dev_data->dev.release = free_device_data;
+ dev_set_name(&dev_data->dev, EVENT_DEV_NAME_FMT, minor);
+ device_initialize(&dev_data->dev);
+
+ /* Initialize the character device, and add it to userspace. */
+ cdev_init(&dev_data->cdev, &event_fops);
+ error = cdev_device_add(&dev_data->cdev, &dev_data->dev);
+ if (error)
+ goto free_dev_data;
+
+ return 0;
+
+free_dev_data:
+ hangup_device(dev_data);
+free_minor:
+ ida_simple_remove(&event_ida, minor);
+ return error;
+}
+
+static int event_device_remove(struct acpi_device *adev)
+{
+ struct event_device_data *dev_data = adev->driver_data;
+
+ cdev_device_del(&dev_data->cdev, &dev_data->dev);
+ ida_simple_remove(&event_ida, MINOR(dev_data->dev.devt));
+ hangup_device(dev_data);
+
+ return 0;
+}
+
+static const struct acpi_device_id event_acpi_ids[] = {
+ { "GOOG000D", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, event_acpi_ids);
+
+static struct acpi_driver event_driver = {
+ .name = DRV_NAME,
+ .class = DRV_NAME,
+ .ids = event_acpi_ids,
+ .ops = {
+ .add = event_device_add,
+ .notify = event_device_notify,
+ .remove = event_device_remove,
+ },
+ .owner = THIS_MODULE,
+};
+
+static int __init event_module_init(void)
+{
+ dev_t dev_num = 0;
+ int ret;
+
+ ret = class_register(&event_class);
+ if (ret) {
+ pr_err(DRV_NAME ": Failed registering class: %d\n", ret);
+ return ret;
+ }
+
+ /* Request device numbers, starting with minor=0. Save the major num. */
+ ret = alloc_chrdev_region(&dev_num, 0, EVENT_MAX_DEV, EVENT_DEV_NAME);
+ if (ret) {
+ pr_err(DRV_NAME ": Failed allocating dev numbers: %d\n", ret);
+ goto destroy_class;
+ }
+ event_major = MAJOR(dev_num);
+
+ ret = acpi_bus_register_driver(&event_driver);
+ if (ret < 0) {
+ pr_err(DRV_NAME ": Failed registering driver: %d\n", ret);
+ goto unregister_region;
+ }
+
+ return 0;
+
+unregister_region:
+ unregister_chrdev_region(MKDEV(event_major, 0), EVENT_MAX_DEV);
+destroy_class:
+ class_unregister(&event_class);
+ ida_destroy(&event_ida);
+ return ret;
+}
+
+static void __exit event_module_exit(void)
+{
+ acpi_bus_unregister_driver(&event_driver);
+ unregister_chrdev_region(MKDEV(event_major, 0), EVENT_MAX_DEV);
+ class_unregister(&event_class);
+ ida_destroy(&event_ida);
+}
+
+module_init(event_module_init);
+module_exit(event_module_exit);
+
+MODULE_AUTHOR("Nick Crews <ncrews@chromium.org>");
+MODULE_DESCRIPTION("Wilco EC ACPI event driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/platform/chrome/wilco_ec/mailbox.c b/drivers/platform/chrome/wilco_ec/mailbox.c
index 7fb58b487963..ced1f9f3dcee 100644
--- a/drivers/platform/chrome/wilco_ec/mailbox.c
+++ b/drivers/platform/chrome/wilco_ec/mailbox.c
@@ -119,7 +119,6 @@ static int wilco_ec_transfer(struct wilco_ec_device *ec,
struct wilco_ec_response *rs;
u8 checksum;
u8 flag;
- size_t size;
/* Write request header, then data */
cros_ec_lpc_io_bytes_mec(MEC_IO_WRITE, 0, sizeof(*rq), (u8 *)rq);
@@ -148,21 +147,11 @@ static int wilco_ec_transfer(struct wilco_ec_device *ec,
return -EIO;
}
- /*
- * The EC always returns either EC_MAILBOX_DATA_SIZE or
- * EC_MAILBOX_DATA_SIZE_EXTENDED bytes of data, so we need to
- * calculate the checksum on **all** of this data, even if we
- * won't use all of it.
- */
- if (msg->flags & WILCO_EC_FLAG_EXTENDED_DATA)
- size = EC_MAILBOX_DATA_SIZE_EXTENDED;
- else
- size = EC_MAILBOX_DATA_SIZE;
-
/* Read back response */
rs = ec->data_buffer;
checksum = cros_ec_lpc_io_bytes_mec(MEC_IO_READ, 0,
- sizeof(*rs) + size, (u8 *)rs);
+ sizeof(*rs) + EC_MAILBOX_DATA_SIZE,
+ (u8 *)rs);
if (checksum) {
dev_dbg(ec->dev, "bad packet checksum 0x%02x\n", rs->checksum);
return -EBADMSG;
@@ -173,9 +162,9 @@ static int wilco_ec_transfer(struct wilco_ec_device *ec,
return -EBADMSG;
}
- if (rs->data_size != size) {
- dev_dbg(ec->dev, "unexpected packet size (%u != %zu)",
- rs->data_size, size);
+ if (rs->data_size != EC_MAILBOX_DATA_SIZE) {
+ dev_dbg(ec->dev, "unexpected packet size (%u != %u)",
+ rs->data_size, EC_MAILBOX_DATA_SIZE);
return -EMSGSIZE;
}
diff --git a/drivers/platform/chrome/wilco_ec/properties.c b/drivers/platform/chrome/wilco_ec/properties.c
new file mode 100644
index 000000000000..e69682c95ea2
--- /dev/null
+++ b/drivers/platform/chrome/wilco_ec/properties.c
@@ -0,0 +1,132 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#include <linux/platform_data/wilco-ec.h>
+#include <linux/string.h>
+#include <linux/unaligned/le_memmove.h>
+
+/* Operation code; what the EC should do with the property */
+enum ec_property_op {
+ EC_OP_GET = 0,
+ EC_OP_SET = 1,
+};
+
+struct ec_property_request {
+ u8 op; /* One of enum ec_property_op */
+ u8 property_id[4]; /* The 32 bit PID is stored Little Endian */
+ u8 length;
+ u8 data[WILCO_EC_PROPERTY_MAX_SIZE];
+} __packed;
+
+struct ec_property_response {
+ u8 reserved[2];
+ u8 op; /* One of enum ec_property_op */
+ u8 property_id[4]; /* The 32 bit PID is stored Little Endian */
+ u8 length;
+ u8 data[WILCO_EC_PROPERTY_MAX_SIZE];
+} __packed;
+
+static int send_property_msg(struct wilco_ec_device *ec,
+ struct ec_property_request *rq,
+ struct ec_property_response *rs)
+{
+ struct wilco_ec_message ec_msg;
+ int ret;
+
+ memset(&ec_msg, 0, sizeof(ec_msg));
+ ec_msg.type = WILCO_EC_MSG_PROPERTY;
+ ec_msg.request_data = rq;
+ ec_msg.request_size = sizeof(*rq);
+ ec_msg.response_data = rs;
+ ec_msg.response_size = sizeof(*rs);
+
+ ret = wilco_ec_mailbox(ec, &ec_msg);
+ if (ret < 0)
+ return ret;
+ if (rs->op != rq->op)
+ return -EBADMSG;
+ if (memcmp(rq->property_id, rs->property_id, sizeof(rs->property_id)))
+ return -EBADMSG;
+
+ return 0;
+}
+
+int wilco_ec_get_property(struct wilco_ec_device *ec,
+ struct wilco_ec_property_msg *prop_msg)
+{
+ struct ec_property_request rq;
+ struct ec_property_response rs;
+ int ret;
+
+ memset(&rq, 0, sizeof(rq));
+ rq.op = EC_OP_GET;
+ put_unaligned_le32(prop_msg->property_id, rq.property_id);
+
+ ret = send_property_msg(ec, &rq, &rs);
+ if (ret < 0)
+ return ret;
+
+ prop_msg->length = rs.length;
+ memcpy(prop_msg->data, rs.data, rs.length);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wilco_ec_get_property);
+
+int wilco_ec_set_property(struct wilco_ec_device *ec,
+ struct wilco_ec_property_msg *prop_msg)
+{
+ struct ec_property_request rq;
+ struct ec_property_response rs;
+ int ret;
+
+ memset(&rq, 0, sizeof(rq));
+ rq.op = EC_OP_SET;
+ put_unaligned_le32(prop_msg->property_id, rq.property_id);
+ rq.length = prop_msg->length;
+ memcpy(rq.data, prop_msg->data, prop_msg->length);
+
+ ret = send_property_msg(ec, &rq, &rs);
+ if (ret < 0)
+ return ret;
+ if (rs.length != prop_msg->length)
+ return -EBADMSG;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wilco_ec_set_property);
+
+int wilco_ec_get_byte_property(struct wilco_ec_device *ec, u32 property_id,
+ u8 *val)
+{
+ struct wilco_ec_property_msg msg;
+ int ret;
+
+ msg.property_id = property_id;
+
+ ret = wilco_ec_get_property(ec, &msg);
+ if (ret < 0)
+ return ret;
+ if (msg.length != 1)
+ return -EBADMSG;
+
+ *val = msg.data[0];
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wilco_ec_get_byte_property);
+
+int wilco_ec_set_byte_property(struct wilco_ec_device *ec, u32 property_id,
+ u8 val)
+{
+ struct wilco_ec_property_msg msg;
+
+ msg.property_id = property_id;
+ msg.data[0] = val;
+ msg.length = 1;
+
+ return wilco_ec_set_property(ec, &msg);
+}
+EXPORT_SYMBOL_GPL(wilco_ec_set_byte_property);
diff --git a/drivers/platform/chrome/wilco_ec/sysfs.c b/drivers/platform/chrome/wilco_ec/sysfs.c
new file mode 100644
index 000000000000..3b86a21005d3
--- /dev/null
+++ b/drivers/platform/chrome/wilco_ec/sysfs.c
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Sysfs properties to view and modify EC-controlled features on Wilco devices.
+ * The entries will appear under /sys/bus/platform/devices/GOOG000C:00/
+ *
+ * See Documentation/ABI/testing/sysfs-platform-wilco-ec for more information.
+ */
+
+#include <linux/platform_data/wilco-ec.h>
+#include <linux/sysfs.h>
+
+#define CMD_KB_CMOS 0x7C
+#define SUB_CMD_KB_CMOS_AUTO_ON 0x03
+
+struct boot_on_ac_request {
+ u8 cmd; /* Always CMD_KB_CMOS */
+ u8 reserved1;
+ u8 sub_cmd; /* Always SUB_CMD_KB_CMOS_AUTO_ON */
+ u8 reserved3to5[3];
+ u8 val; /* Either 0 or 1 */
+ u8 reserved7;
+} __packed;
+
+#define CMD_EC_INFO 0x38
+enum get_ec_info_op {
+ CMD_GET_EC_LABEL = 0,
+ CMD_GET_EC_REV = 1,
+ CMD_GET_EC_MODEL = 2,
+ CMD_GET_EC_BUILD_DATE = 3,
+};
+
+struct get_ec_info_req {
+ u8 cmd; /* Always CMD_EC_INFO */
+ u8 reserved;
+ u8 op; /* One of enum get_ec_info_op */
+} __packed;
+
+struct get_ec_info_resp {
+ u8 reserved[2];
+ char value[9]; /* __nonstring: might not be null terminated */
+} __packed;
+
+static ssize_t boot_on_ac_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct wilco_ec_device *ec = dev_get_drvdata(dev);
+ struct boot_on_ac_request rq;
+ struct wilco_ec_message msg;
+ int ret;
+ u8 val;
+
+ ret = kstrtou8(buf, 10, &val);
+ if (ret < 0)
+ return ret;
+ if (val > 1)
+ return -EINVAL;
+
+ memset(&rq, 0, sizeof(rq));
+ rq.cmd = CMD_KB_CMOS;
+ rq.sub_cmd = SUB_CMD_KB_CMOS_AUTO_ON;
+ rq.val = val;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.type = WILCO_EC_MSG_LEGACY;
+ msg.request_data = &rq;
+ msg.request_size = sizeof(rq);
+ ret = wilco_ec_mailbox(ec, &msg);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static DEVICE_ATTR_WO(boot_on_ac);
+
+static ssize_t get_info(struct device *dev, char *buf, enum get_ec_info_op op)
+{
+ struct wilco_ec_device *ec = dev_get_drvdata(dev);
+ struct get_ec_info_req req = { .cmd = CMD_EC_INFO, .op = op };
+ struct get_ec_info_resp resp;
+ int ret;
+
+ struct wilco_ec_message msg = {
+ .type = WILCO_EC_MSG_LEGACY,
+ .request_data = &req,
+ .request_size = sizeof(req),
+ .response_data = &resp,
+ .response_size = sizeof(resp),
+ };
+
+ ret = wilco_ec_mailbox(ec, &msg);
+ if (ret < 0)
+ return ret;
+
+ return scnprintf(buf, PAGE_SIZE, "%.*s\n", (int)sizeof(resp.value),
+ (char *)&resp.value);
+}
+
+static ssize_t version_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return get_info(dev, buf, CMD_GET_EC_LABEL);
+}
+
+static DEVICE_ATTR_RO(version);
+
+static ssize_t build_revision_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return get_info(dev, buf, CMD_GET_EC_REV);
+}
+
+static DEVICE_ATTR_RO(build_revision);
+
+static ssize_t build_date_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return get_info(dev, buf, CMD_GET_EC_BUILD_DATE);
+}
+
+static DEVICE_ATTR_RO(build_date);
+
+static ssize_t model_number_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return get_info(dev, buf, CMD_GET_EC_MODEL);
+}
+
+static DEVICE_ATTR_RO(model_number);
+
+
+static struct attribute *wilco_dev_attrs[] = {
+ &dev_attr_boot_on_ac.attr,
+ &dev_attr_build_date.attr,
+ &dev_attr_build_revision.attr,
+ &dev_attr_model_number.attr,
+ &dev_attr_version.attr,
+ NULL,
+};
+
+static struct attribute_group wilco_dev_attr_group = {
+ .attrs = wilco_dev_attrs,
+};
+
+int wilco_ec_add_sysfs(struct wilco_ec_device *ec)
+{
+ return sysfs_create_group(&ec->dev->kobj, &wilco_dev_attr_group);
+}
+
+void wilco_ec_remove_sysfs(struct wilco_ec_device *ec)
+{
+ sysfs_remove_group(&ec->dev->kobj, &wilco_dev_attr_group);
+}
diff --git a/drivers/platform/chrome/wilco_ec/telemetry.c b/drivers/platform/chrome/wilco_ec/telemetry.c
new file mode 100644
index 000000000000..94cdc166c840
--- /dev/null
+++ b/drivers/platform/chrome/wilco_ec/telemetry.c
@@ -0,0 +1,450 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Telemetry communication for Wilco EC
+ *
+ * Copyright 2019 Google LLC
+ *
+ * The Wilco Embedded Controller is able to send telemetry data
+ * which is useful for enterprise applications. A daemon running on
+ * the OS sends a command to the EC via a write() to a char device,
+ * and can read the response with a read(). The write() request is
+ * verified by the driver to ensure that it is performing only one
+ * of the whitelisted commands, and that no extraneous data is
+ * being transmitted to the EC. The response is passed directly
+ * back to the reader with no modification.
+ *
+ * The character device will appear as /dev/wilco_telemN, where N
+ * is some small non-negative integer, starting with 0. Only one
+ * process may have the file descriptor open at a time. The calling
+ * userspace program needs to keep the device file descriptor open
+ * between the calls to write() and read() in order to preserve the
+ * response. Up to 32 bytes will be available for reading.
+ *
+ * For testing purposes, try requesting the EC's firmware build
+ * date, by sending the WILCO_EC_TELEM_GET_VERSION command with
+ * argument index=3. i.e. write [0x38, 0x00, 0x03]
+ * to the device node. An ASCII string of the build date is
+ * returned.
+ */
+
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/platform_data/wilco-ec.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+
+#define TELEM_DEV_NAME "wilco_telem"
+#define TELEM_CLASS_NAME TELEM_DEV_NAME
+#define DRV_NAME TELEM_DEV_NAME
+#define TELEM_DEV_NAME_FMT (TELEM_DEV_NAME "%d")
+static struct class telem_class = {
+ .owner = THIS_MODULE,
+ .name = TELEM_CLASS_NAME,
+};
+
+/* Keep track of all the device numbers used. */
+#define TELEM_MAX_DEV 128
+static int telem_major;
+static DEFINE_IDA(telem_ida);
+
+/* EC telemetry command codes */
+#define WILCO_EC_TELEM_GET_LOG 0x99
+#define WILCO_EC_TELEM_GET_VERSION 0x38
+#define WILCO_EC_TELEM_GET_FAN_INFO 0x2E
+#define WILCO_EC_TELEM_GET_DIAG_INFO 0xFA
+#define WILCO_EC_TELEM_GET_TEMP_INFO 0x95
+#define WILCO_EC_TELEM_GET_TEMP_READ 0x2C
+#define WILCO_EC_TELEM_GET_BATT_EXT_INFO 0x07
+
+#define TELEM_ARGS_SIZE_MAX 30
+
+/**
+ * struct wilco_ec_telem_request - Telemetry command and arguments sent to EC.
+ * @command: One of WILCO_EC_TELEM_GET_* command codes.
+ * @reserved: Must be 0.
+ * @args: The first N bytes are one of telem_args_get_* structs, the rest is 0.
+ */
+struct wilco_ec_telem_request {
+ u8 command;
+ u8 reserved;
+ u8 args[TELEM_ARGS_SIZE_MAX];
+} __packed;
+
+/*
+ * The following telem_args_get_* structs are embedded within the |args| field
+ * of wilco_ec_telem_request.
+ */
+
+struct telem_args_get_log {
+ u8 log_type;
+ u8 log_index;
+} __packed;
+
+/*
+ * Get a piece of info about the EC firmware version:
+ * 0 = label
+ * 1 = svn_rev
+ * 2 = model_no
+ * 3 = build_date
+ * 4 = frio_version
+ */
+struct telem_args_get_version {
+ u8 index;
+} __packed;
+
+struct telem_args_get_fan_info {
+ u8 command;
+ u8 fan_number;
+ u8 arg;
+} __packed;
+
+struct telem_args_get_diag_info {
+ u8 type;
+ u8 sub_type;
+} __packed;
+
+struct telem_args_get_temp_info {
+ u8 command;
+ u8 index;
+ u8 field;
+ u8 zone;
+} __packed;
+
+struct telem_args_get_temp_read {
+ u8 sensor_index;
+} __packed;
+
+struct telem_args_get_batt_ext_info {
+ u8 var_args[5];
+} __packed;
+
+/**
+ * check_telem_request() - Ensure that a request from userspace is valid.
+ * @rq: Request buffer copied from userspace.
+ * @size: Number of bytes copied from userspace.
+ *
+ * Return: 0 if valid, -EINVAL if bad command or reserved byte is non-zero,
+ * -EMSGSIZE if the request is too long.
+ *
+ * We do not want to allow userspace to send arbitrary telemetry commands to
+ * the EC. Therefore we check to ensure that
+ * 1. The request follows the format of struct wilco_ec_telem_request.
+ * 2. The supplied command code is one of the whitelisted commands.
+ * 3. The request only contains the necessary data for the header and arguments.
+ */
+static int check_telem_request(struct wilco_ec_telem_request *rq,
+ size_t size)
+{
+ size_t max_size = offsetof(struct wilco_ec_telem_request, args);
+
+ if (rq->reserved)
+ return -EINVAL;
+
+ switch (rq->command) {
+ case WILCO_EC_TELEM_GET_LOG:
+ max_size += sizeof(struct telem_args_get_log);
+ break;
+ case WILCO_EC_TELEM_GET_VERSION:
+ max_size += sizeof(struct telem_args_get_version);
+ break;
+ case WILCO_EC_TELEM_GET_FAN_INFO:
+ max_size += sizeof(struct telem_args_get_fan_info);
+ break;
+ case WILCO_EC_TELEM_GET_DIAG_INFO:
+ max_size += sizeof(struct telem_args_get_diag_info);
+ break;
+ case WILCO_EC_TELEM_GET_TEMP_INFO:
+ max_size += sizeof(struct telem_args_get_temp_info);
+ break;
+ case WILCO_EC_TELEM_GET_TEMP_READ:
+ max_size += sizeof(struct telem_args_get_temp_read);
+ break;
+ case WILCO_EC_TELEM_GET_BATT_EXT_INFO:
+ max_size += sizeof(struct telem_args_get_batt_ext_info);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return (size <= max_size) ? 0 : -EMSGSIZE;
+}
+
+/**
+ * struct telem_device_data - Data for a Wilco EC device that queries telemetry.
+ * @cdev: Char dev that userspace reads and polls from.
+ * @dev: Device associated with the %cdev.
+ * @ec: Wilco EC that we will be communicating with using the mailbox interface.
+ * @available: Boolean of if the device can be opened.
+ */
+struct telem_device_data {
+ struct device dev;
+ struct cdev cdev;
+ struct wilco_ec_device *ec;
+ atomic_t available;
+};
+
+#define TELEM_RESPONSE_SIZE EC_MAILBOX_DATA_SIZE
+
+/**
+ * struct telem_session_data - Data that exists between open() and release().
+ * @dev_data: Pointer to get back to the device data and EC.
+ * @request: Command and arguments sent to EC.
+ * @response: Response buffer of data from EC.
+ * @has_msg: Is there data available to read from a previous write?
+ */
+struct telem_session_data {
+ struct telem_device_data *dev_data;
+ struct wilco_ec_telem_request request;
+ u8 response[TELEM_RESPONSE_SIZE];
+ bool has_msg;
+};
+
+/**
+ * telem_open() - Callback for when the device node is opened.
+ * @inode: inode for this char device node.
+ * @filp: file for this char device node.
+ *
+ * We need to ensure that after writing a command to the device,
+ * the same userspace process reads the corresponding result.
+ * Therefore, we increment a refcount on opening the device, so that
+ * only one process can communicate with the EC at a time.
+ *
+ * Return: 0 on success, or negative error code on failure.
+ */
+static int telem_open(struct inode *inode, struct file *filp)
+{
+ struct telem_device_data *dev_data;
+ struct telem_session_data *sess_data;
+
+ /* Ensure device isn't already open */
+ dev_data = container_of(inode->i_cdev, struct telem_device_data, cdev);
+ if (atomic_cmpxchg(&dev_data->available, 1, 0) == 0)
+ return -EBUSY;
+
+ get_device(&dev_data->dev);
+
+ sess_data = kzalloc(sizeof(*sess_data), GFP_KERNEL);
+ if (!sess_data) {
+ atomic_set(&dev_data->available, 1);
+ return -ENOMEM;
+ }
+ sess_data->dev_data = dev_data;
+ sess_data->has_msg = false;
+
+ nonseekable_open(inode, filp);
+ filp->private_data = sess_data;
+
+ return 0;
+}
+
+static ssize_t telem_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct telem_session_data *sess_data = filp->private_data;
+ struct wilco_ec_message msg = {};
+ int ret;
+
+ if (count > sizeof(sess_data->request))
+ return -EMSGSIZE;
+ if (copy_from_user(&sess_data->request, buf, count))
+ return -EFAULT;
+ ret = check_telem_request(&sess_data->request, count);
+ if (ret < 0)
+ return ret;
+
+ memset(sess_data->response, 0, sizeof(sess_data->response));
+ msg.type = WILCO_EC_MSG_TELEMETRY;
+ msg.request_data = &sess_data->request;
+ msg.request_size = sizeof(sess_data->request);
+ msg.response_data = sess_data->response;
+ msg.response_size = sizeof(sess_data->response);
+
+ ret = wilco_ec_mailbox(sess_data->dev_data->ec, &msg);
+ if (ret < 0)
+ return ret;
+ if (ret != sizeof(sess_data->response))
+ return -EMSGSIZE;
+
+ sess_data->has_msg = true;
+
+ return count;
+}
+
+static ssize_t telem_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *pos)
+{
+ struct telem_session_data *sess_data = filp->private_data;
+
+ if (!sess_data->has_msg)
+ return -ENODATA;
+ if (count > sizeof(sess_data->response))
+ return -EINVAL;
+
+ if (copy_to_user(buf, sess_data->response, count))
+ return -EFAULT;
+
+ sess_data->has_msg = false;
+
+ return count;
+}
+
+static int telem_release(struct inode *inode, struct file *filp)
+{
+ struct telem_session_data *sess_data = filp->private_data;
+
+ atomic_set(&sess_data->dev_data->available, 1);
+ put_device(&sess_data->dev_data->dev);
+ kfree(sess_data);
+
+ return 0;
+}
+
+static const struct file_operations telem_fops = {
+ .open = telem_open,
+ .write = telem_write,
+ .read = telem_read,
+ .release = telem_release,
+ .llseek = no_llseek,
+ .owner = THIS_MODULE,
+};
+
+/**
+ * telem_device_free() - Callback to free the telem_device_data structure.
+ * @d: The device embedded in our device data, which we have been ref counting.
+ *
+ * Once all open file descriptors are closed and the device has been removed,
+ * the refcount of the device will fall to 0 and this will be called.
+ */
+static void telem_device_free(struct device *d)
+{
+ struct telem_device_data *dev_data;
+
+ dev_data = container_of(d, struct telem_device_data, dev);
+ kfree(dev_data);
+}
+
+/**
+ * telem_device_probe() - Callback when creating a new device.
+ * @pdev: platform device that we will be receiving telems from.
+ *
+ * This finds a free minor number for the device, allocates and initializes
+ * some device data, and creates a new device and char dev node.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+static int telem_device_probe(struct platform_device *pdev)
+{
+ struct telem_device_data *dev_data;
+ int error, minor;
+
+ /* Get the next available device number */
+ minor = ida_alloc_max(&telem_ida, TELEM_MAX_DEV-1, GFP_KERNEL);
+ if (minor < 0) {
+ error = minor;
+ dev_err(&pdev->dev, "Failed to find minor number: %d", error);
+ return error;
+ }
+
+ dev_data = kzalloc(sizeof(*dev_data), GFP_KERNEL);
+ if (!dev_data) {
+ ida_simple_remove(&telem_ida, minor);
+ return -ENOMEM;
+ }
+
+ /* Initialize the device data */
+ dev_data->ec = dev_get_platdata(&pdev->dev);
+ atomic_set(&dev_data->available, 1);
+ platform_set_drvdata(pdev, dev_data);
+
+ /* Initialize the device */
+ dev_data->dev.devt = MKDEV(telem_major, minor);
+ dev_data->dev.class = &telem_class;
+ dev_data->dev.release = telem_device_free;
+ dev_set_name(&dev_data->dev, TELEM_DEV_NAME_FMT, minor);
+ device_initialize(&dev_data->dev);
+
+ /* Initialize the character device and add it to userspace */;
+ cdev_init(&dev_data->cdev, &telem_fops);
+ error = cdev_device_add(&dev_data->cdev, &dev_data->dev);
+ if (error) {
+ put_device(&dev_data->dev);
+ ida_simple_remove(&telem_ida, minor);
+ return error;
+ }
+
+ return 0;
+}
+
+static int telem_device_remove(struct platform_device *pdev)
+{
+ struct telem_device_data *dev_data = platform_get_drvdata(pdev);
+
+ cdev_device_del(&dev_data->cdev, &dev_data->dev);
+ put_device(&dev_data->dev);
+ ida_simple_remove(&telem_ida, MINOR(dev_data->dev.devt));
+
+ return 0;
+}
+
+static struct platform_driver telem_driver = {
+ .probe = telem_device_probe,
+ .remove = telem_device_remove,
+ .driver = {
+ .name = DRV_NAME,
+ },
+};
+
+static int __init telem_module_init(void)
+{
+ dev_t dev_num = 0;
+ int ret;
+
+ ret = class_register(&telem_class);
+ if (ret) {
+ pr_err(DRV_NAME ": Failed registering class: %d", ret);
+ return ret;
+ }
+
+ /* Request the kernel for device numbers, starting with minor=0 */
+ ret = alloc_chrdev_region(&dev_num, 0, TELEM_MAX_DEV, TELEM_DEV_NAME);
+ if (ret) {
+ pr_err(DRV_NAME ": Failed allocating dev numbers: %d", ret);
+ goto destroy_class;
+ }
+ telem_major = MAJOR(dev_num);
+
+ ret = platform_driver_register(&telem_driver);
+ if (ret < 0) {
+ pr_err(DRV_NAME ": Failed registering driver: %d\n", ret);
+ goto unregister_region;
+ }
+
+ return 0;
+
+unregister_region:
+ unregister_chrdev_region(MKDEV(telem_major, 0), TELEM_MAX_DEV);
+destroy_class:
+ class_unregister(&telem_class);
+ ida_destroy(&telem_ida);
+ return ret;
+}
+
+static void __exit telem_module_exit(void)
+{
+ platform_driver_unregister(&telem_driver);
+ unregister_chrdev_region(MKDEV(telem_major, 0), TELEM_MAX_DEV);
+ class_unregister(&telem_class);
+ ida_destroy(&telem_ida);
+}
+
+module_init(telem_module_init);
+module_exit(telem_module_exit);
+
+MODULE_AUTHOR("Nick Crews <ncrews@chromium.org>");
+MODULE_DESCRIPTION("Wilco EC telemetry driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/platform/olpc/Kconfig b/drivers/platform/olpc/Kconfig
new file mode 100644
index 000000000000..919b489e24e8
--- /dev/null
+++ b/drivers/platform/olpc/Kconfig
@@ -0,0 +1,29 @@
+config OLPC_EC
+ select REGULATOR
+ bool
+
+menuconfig OLPC_XO175
+ bool "Platform support for OLPC XO 1.75 hardware"
+ depends on ARCH_MMP || COMPILE_TEST
+ help
+ Say Y here to get to see options for the ARM-based OLPC platform.
+ This option alone does not add any kernel code.
+
+ Unless you have an OLPC XO laptop, you will want to say N.
+
+if OLPC_XO175
+
+config OLPC_XO175_EC
+ tristate "OLPC XO 1.75 Embedded Controller"
+ depends on SPI_SLAVE
+ depends on INPUT
+ depends on POWER_SUPPLY
+ select OLPC_EC
+ help
+ Include support for the OLPC XO Embedded Controller (EC). The EC
+ provides various platform services, including support for the power,
+ button, restart, shutdown and battery charging status.
+
+ Unless you have an OLPC XO laptop, you will want to say N.
+
+endif # OLPC_XO175
diff --git a/drivers/platform/olpc/Makefile b/drivers/platform/olpc/Makefile
index cee085c6532d..e9b67000cbcb 100644
--- a/drivers/platform/olpc/Makefile
+++ b/drivers/platform/olpc/Makefile
@@ -2,4 +2,5 @@
#
# OLPC XO platform-specific drivers
#
-obj-$(CONFIG_OLPC) += olpc-ec.o
+obj-$(CONFIG_OLPC_EC) += olpc-ec.o
+obj-$(CONFIG_OLPC_XO175_EC) += olpc-xo175-ec.o
diff --git a/drivers/platform/olpc/olpc-ec.c b/drivers/platform/olpc/olpc-ec.c
index 7f25d6c66149..190e4a6186ef 100644
--- a/drivers/platform/olpc/olpc-ec.c
+++ b/drivers/platform/olpc/olpc-ec.c
@@ -15,8 +15,8 @@
#include <linux/workqueue.h>
#include <linux/init.h>
#include <linux/list.h>
+#include <linux/regulator/driver.h>
#include <linux/olpc-ec.h>
-#include <asm/olpc.h>
struct ec_cmd_desc {
u8 cmd;
@@ -32,9 +32,14 @@ struct ec_cmd_desc {
struct olpc_ec_priv {
struct olpc_ec_driver *drv;
+ u8 version;
struct work_struct worker;
struct mutex cmd_lock;
+ /* DCON regulator */
+ struct regulator_dev *dcon_rdev;
+ bool dcon_enabled;
+
/* Pending EC commands */
struct list_head cmd_q;
spinlock_t cmd_q_lock;
@@ -42,6 +47,12 @@ struct olpc_ec_priv {
struct dentry *dbgfs_dir;
/*
+ * EC event mask to be applied during suspend (defining wakeup
+ * sources).
+ */
+ u16 ec_wakeup_mask;
+
+ /*
* Running an EC command while suspending means we don't always finish
* the command before the machine suspends. This means that the EC
* is expecting the command protocol to finish, but we after a period
@@ -118,8 +129,11 @@ int olpc_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *outbuf, size_t outlen)
struct olpc_ec_priv *ec = ec_priv;
struct ec_cmd_desc desc;
- /* Ensure a driver and ec hook have been registered */
- if (WARN_ON(!ec_driver || !ec_driver->ec_cmd))
+ /* Driver not yet registered. */
+ if (!ec_driver)
+ return -EPROBE_DEFER;
+
+ if (WARN_ON(!ec_driver->ec_cmd))
return -ENODEV;
if (!ec)
@@ -149,6 +163,88 @@ int olpc_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *outbuf, size_t outlen)
}
EXPORT_SYMBOL_GPL(olpc_ec_cmd);
+void olpc_ec_wakeup_set(u16 value)
+{
+ struct olpc_ec_priv *ec = ec_priv;
+
+ if (WARN_ON(!ec))
+ return;
+
+ ec->ec_wakeup_mask |= value;
+}
+EXPORT_SYMBOL_GPL(olpc_ec_wakeup_set);
+
+void olpc_ec_wakeup_clear(u16 value)
+{
+ struct olpc_ec_priv *ec = ec_priv;
+
+ if (WARN_ON(!ec))
+ return;
+
+ ec->ec_wakeup_mask &= ~value;
+}
+EXPORT_SYMBOL_GPL(olpc_ec_wakeup_clear);
+
+int olpc_ec_mask_write(u16 bits)
+{
+ struct olpc_ec_priv *ec = ec_priv;
+
+ if (WARN_ON(!ec))
+ return -ENODEV;
+
+ /* EC version 0x5f adds support for wide SCI mask */
+ if (ec->version >= 0x5f) {
+ __be16 ec_word = cpu_to_be16(bits);
+
+ return olpc_ec_cmd(EC_WRITE_EXT_SCI_MASK, (void *)&ec_word, 2, NULL, 0);
+ } else {
+ u8 ec_byte = bits & 0xff;
+
+ return olpc_ec_cmd(EC_WRITE_SCI_MASK, &ec_byte, 1, NULL, 0);
+ }
+}
+EXPORT_SYMBOL_GPL(olpc_ec_mask_write);
+
+/*
+ * Returns true if the compile and runtime configurations allow for EC events
+ * to wake the system.
+ */
+bool olpc_ec_wakeup_available(void)
+{
+ if (WARN_ON(!ec_driver))
+ return false;
+
+ return ec_driver->wakeup_available;
+}
+EXPORT_SYMBOL_GPL(olpc_ec_wakeup_available);
+
+int olpc_ec_sci_query(u16 *sci_value)
+{
+ struct olpc_ec_priv *ec = ec_priv;
+ int ret;
+
+ if (WARN_ON(!ec))
+ return -ENODEV;
+
+ /* EC version 0x5f adds support for wide SCI mask */
+ if (ec->version >= 0x5f) {
+ __be16 ec_word;
+
+ ret = olpc_ec_cmd(EC_EXT_SCI_QUERY, NULL, 0, (void *)&ec_word, 2);
+ if (ret == 0)
+ *sci_value = be16_to_cpu(ec_word);
+ } else {
+ u8 ec_byte;
+
+ ret = olpc_ec_cmd(EC_SCI_QUERY, NULL, 0, &ec_byte, 1);
+ if (ret == 0)
+ *sci_value = ec_byte;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(olpc_ec_sci_query);
+
#ifdef CONFIG_DEBUG_FS
/*
@@ -254,9 +350,61 @@ static struct dentry *olpc_ec_setup_debugfs(void)
#endif /* CONFIG_DEBUG_FS */
+static int olpc_ec_set_dcon_power(struct olpc_ec_priv *ec, bool state)
+{
+ unsigned char ec_byte = state;
+ int ret;
+
+ if (ec->dcon_enabled == state)
+ return 0;
+
+ ret = olpc_ec_cmd(EC_DCON_POWER_MODE, &ec_byte, 1, NULL, 0);
+ if (ret)
+ return ret;
+
+ ec->dcon_enabled = state;
+ return 0;
+}
+
+static int dcon_regulator_enable(struct regulator_dev *rdev)
+{
+ struct olpc_ec_priv *ec = rdev_get_drvdata(rdev);
+
+ return olpc_ec_set_dcon_power(ec, true);
+}
+
+static int dcon_regulator_disable(struct regulator_dev *rdev)
+{
+ struct olpc_ec_priv *ec = rdev_get_drvdata(rdev);
+
+ return olpc_ec_set_dcon_power(ec, false);
+}
+
+static int dcon_regulator_is_enabled(struct regulator_dev *rdev)
+{
+ struct olpc_ec_priv *ec = rdev_get_drvdata(rdev);
+
+ return ec->dcon_enabled ? 1 : 0;
+}
+
+static struct regulator_ops dcon_regulator_ops = {
+ .enable = dcon_regulator_enable,
+ .disable = dcon_regulator_disable,
+ .is_enabled = dcon_regulator_is_enabled,
+};
+
+static const struct regulator_desc dcon_desc = {
+ .name = "dcon",
+ .id = 0,
+ .ops = &dcon_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+};
+
static int olpc_ec_probe(struct platform_device *pdev)
{
struct olpc_ec_priv *ec;
+ struct regulator_config config = { };
int err;
if (!ec_driver)
@@ -276,14 +424,26 @@ static int olpc_ec_probe(struct platform_device *pdev)
ec_priv = ec;
platform_set_drvdata(pdev, ec);
- err = ec_driver->probe ? ec_driver->probe(pdev) : 0;
+ /* get the EC revision */
+ err = olpc_ec_cmd(EC_FIRMWARE_REV, NULL, 0, &ec->version, 1);
if (err) {
ec_priv = NULL;
kfree(ec);
- } else {
- ec->dbgfs_dir = olpc_ec_setup_debugfs();
+ return err;
}
+ config.dev = pdev->dev.parent;
+ config.driver_data = ec;
+ ec->dcon_enabled = true;
+ ec->dcon_rdev = devm_regulator_register(&pdev->dev, &dcon_desc,
+ &config);
+ if (IS_ERR(ec->dcon_rdev)) {
+ dev_err(&pdev->dev, "failed to register DCON regulator\n");
+ return PTR_ERR(ec->dcon_rdev);
+ }
+
+ ec->dbgfs_dir = olpc_ec_setup_debugfs();
+
return err;
}
@@ -293,6 +453,8 @@ static int olpc_ec_suspend(struct device *dev)
struct olpc_ec_priv *ec = platform_get_drvdata(pdev);
int err = 0;
+ olpc_ec_mask_write(ec->ec_wakeup_mask);
+
if (ec_driver->suspend)
err = ec_driver->suspend(pdev);
if (!err)
diff --git a/drivers/platform/olpc/olpc-xo175-ec.c b/drivers/platform/olpc/olpc-xo175-ec.c
new file mode 100644
index 000000000000..48d6f0d87583
--- /dev/null
+++ b/drivers/platform/olpc/olpc-xo175-ec.c
@@ -0,0 +1,753 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for the OLPC XO-1.75 Embedded Controller.
+ *
+ * The EC protocol is documented at:
+ * http://wiki.laptop.org/go/XO_1.75_HOST_to_EC_Protocol
+ *
+ * Copyright (C) 2010 One Laptop per Child Foundation.
+ * Copyright (C) 2018 Lubomir Rintel <lkundrak@v3.sk>
+ */
+
+#include <linux/completion.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/input.h>
+#include <linux/kfifo.h>
+#include <linux/module.h>
+#include <linux/olpc-ec.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/reboot.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/spi/spi.h>
+
+struct ec_cmd_t {
+ u8 cmd;
+ u8 bytes_returned;
+};
+
+enum ec_chan_t {
+ CHAN_NONE = 0,
+ CHAN_SWITCH,
+ CHAN_CMD_RESP,
+ CHAN_KEYBOARD,
+ CHAN_TOUCHPAD,
+ CHAN_EVENT,
+ CHAN_DEBUG,
+ CHAN_CMD_ERROR,
+};
+
+/*
+ * EC events
+ */
+#define EVENT_AC_CHANGE 1 /* AC plugged/unplugged */
+#define EVENT_BATTERY_STATUS 2 /* Battery low/full/error/gone */
+#define EVENT_BATTERY_CRITICAL 3 /* Battery critical voltage */
+#define EVENT_BATTERY_SOC_CHANGE 4 /* 1% SOC Change */
+#define EVENT_BATTERY_ERROR 5 /* Abnormal error, query for cause */
+#define EVENT_POWER_PRESSED 6 /* Power button was pressed */
+#define EVENT_POWER_PRESS_WAKE 7 /* Woken up with a power button */
+#define EVENT_TIMED_HOST_WAKE 8 /* Host wake timer */
+#define EVENT_OLS_HIGH_LIMIT 9 /* OLS crossed dark threshold */
+#define EVENT_OLS_LOW_LIMIT 10 /* OLS crossed light threshold */
+
+/*
+ * EC commands
+ * (from http://dev.laptop.org/git/users/rsmith/ec-1.75/tree/ec_cmd.h)
+ */
+#define CMD_GET_API_VERSION 0x08 /* out: u8 */
+#define CMD_READ_VOLTAGE 0x10 /* out: u16, *9.76/32, mV */
+#define CMD_READ_CURRENT 0x11 /* out: s16, *15.625/120, mA */
+#define CMD_READ_ACR 0x12 /* out: s16, *6250/15, uAh */
+#define CMD_READ_BATT_TEMPERATURE 0x13 /* out: u16, *100/256, deg C */
+#define CMD_READ_AMBIENT_TEMPERATURE 0x14 /* unimplemented, no hardware */
+#define CMD_READ_BATTERY_STATUS 0x15 /* out: u8, bitmask */
+#define CMD_READ_SOC 0x16 /* out: u8, percentage */
+#define CMD_READ_GAUGE_ID 0x17 /* out: u8 * 8 */
+#define CMD_READ_GAUGE_DATA 0x18 /* in: u8 addr, out: u8 data */
+#define CMD_READ_BOARD_ID 0x19 /* out: u16 (platform id) */
+#define CMD_READ_BATT_ERR_CODE 0x1f /* out: u8, error bitmask */
+#define CMD_SET_DCON_POWER 0x26 /* in: u8 */
+#define CMD_RESET_EC 0x28 /* none */
+#define CMD_READ_BATTERY_TYPE 0x2c /* out: u8 */
+#define CMD_SET_AUTOWAK 0x33 /* out: u8 */
+#define CMD_SET_EC_WAKEUP_TIMER 0x36 /* in: u32, out: ? */
+#define CMD_READ_EXT_SCI_MASK 0x37 /* ? */
+#define CMD_WRITE_EXT_SCI_MASK 0x38 /* ? */
+#define CMD_CLEAR_EC_WAKEUP_TIMER 0x39 /* none */
+#define CMD_ENABLE_RUNIN_DISCHARGE 0x3B /* none */
+#define CMD_DISABLE_RUNIN_DISCHARGE 0x3C /* none */
+#define CMD_READ_MPPT_ACTIVE 0x3d /* out: u8 */
+#define CMD_READ_MPPT_LIMIT 0x3e /* out: u8 */
+#define CMD_SET_MPPT_LIMIT 0x3f /* in: u8 */
+#define CMD_DISABLE_MPPT 0x40 /* none */
+#define CMD_ENABLE_MPPT 0x41 /* none */
+#define CMD_READ_VIN 0x42 /* out: u16 */
+#define CMD_EXT_SCI_QUERY 0x43 /* ? */
+#define RSP_KEYBOARD_DATA 0x48 /* ? */
+#define RSP_TOUCHPAD_DATA 0x49 /* ? */
+#define CMD_GET_FW_VERSION 0x4a /* out: u8 * 16 */
+#define CMD_POWER_CYCLE 0x4b /* none */
+#define CMD_POWER_OFF 0x4c /* none */
+#define CMD_RESET_EC_SOFT 0x4d /* none */
+#define CMD_READ_GAUGE_U16 0x4e /* ? */
+#define CMD_ENABLE_MOUSE 0x4f /* ? */
+#define CMD_ECHO 0x52 /* in: u8 * 5, out: u8 * 5 */
+#define CMD_GET_FW_DATE 0x53 /* out: u8 * 16 */
+#define CMD_GET_FW_USER 0x54 /* out: u8 * 16 */
+#define CMD_TURN_OFF_POWER 0x55 /* none (same as 0x4c) */
+#define CMD_READ_OLS 0x56 /* out: u16 */
+#define CMD_OLS_SMT_LEDON 0x57 /* none */
+#define CMD_OLS_SMT_LEDOFF 0x58 /* none */
+#define CMD_START_OLS_ASSY 0x59 /* none */
+#define CMD_STOP_OLS_ASSY 0x5a /* none */
+#define CMD_OLS_SMTTEST_STOP 0x5b /* none */
+#define CMD_READ_VIN_SCALED 0x5c /* out: u16 */
+#define CMD_READ_BAT_MIN_W 0x5d /* out: u16 */
+#define CMD_READ_BAR_MAX_W 0x5e /* out: u16 */
+#define CMD_RESET_BAT_MINMAX_W 0x5f /* none */
+#define CMD_READ_LOCATION 0x60 /* in: u16 addr, out: u8 data */
+#define CMD_WRITE_LOCATION 0x61 /* in: u16 addr, u8 data */
+#define CMD_KEYBOARD_CMD 0x62 /* in: u8, out: ? */
+#define CMD_TOUCHPAD_CMD 0x63 /* in: u8, out: ? */
+#define CMD_GET_FW_HASH 0x64 /* out: u8 * 16 */
+#define CMD_SUSPEND_HINT 0x65 /* in: u8 */
+#define CMD_ENABLE_WAKE_TIMER 0x66 /* in: u8 */
+#define CMD_SET_WAKE_TIMER 0x67 /* in: 32 */
+#define CMD_ENABLE_WAKE_AUTORESET 0x68 /* in: u8 */
+#define CMD_OLS_SET_LIMITS 0x69 /* in: u16, u16 */
+#define CMD_OLS_GET_LIMITS 0x6a /* out: u16, u16 */
+#define CMD_OLS_SET_CEILING 0x6b /* in: u16 */
+#define CMD_OLS_GET_CEILING 0x6c /* out: u16 */
+
+/*
+ * Accepted EC commands, and how many bytes they return. There are plenty
+ * of EC commands that are no longer implemented, or are implemented only on
+ * certain older boards.
+ */
+static const struct ec_cmd_t olpc_xo175_ec_cmds[] = {
+ { CMD_GET_API_VERSION, 1 },
+ { CMD_READ_VOLTAGE, 2 },
+ { CMD_READ_CURRENT, 2 },
+ { CMD_READ_ACR, 2 },
+ { CMD_READ_BATT_TEMPERATURE, 2 },
+ { CMD_READ_BATTERY_STATUS, 1 },
+ { CMD_READ_SOC, 1 },
+ { CMD_READ_GAUGE_ID, 8 },
+ { CMD_READ_GAUGE_DATA, 1 },
+ { CMD_READ_BOARD_ID, 2 },
+ { CMD_READ_BATT_ERR_CODE, 1 },
+ { CMD_SET_DCON_POWER, 0 },
+ { CMD_RESET_EC, 0 },
+ { CMD_READ_BATTERY_TYPE, 1 },
+ { CMD_ENABLE_RUNIN_DISCHARGE, 0 },
+ { CMD_DISABLE_RUNIN_DISCHARGE, 0 },
+ { CMD_READ_MPPT_ACTIVE, 1 },
+ { CMD_READ_MPPT_LIMIT, 1 },
+ { CMD_SET_MPPT_LIMIT, 0 },
+ { CMD_DISABLE_MPPT, 0 },
+ { CMD_ENABLE_MPPT, 0 },
+ { CMD_READ_VIN, 2 },
+ { CMD_GET_FW_VERSION, 16 },
+ { CMD_POWER_CYCLE, 0 },
+ { CMD_POWER_OFF, 0 },
+ { CMD_RESET_EC_SOFT, 0 },
+ { CMD_ECHO, 5 },
+ { CMD_GET_FW_DATE, 16 },
+ { CMD_GET_FW_USER, 16 },
+ { CMD_TURN_OFF_POWER, 0 },
+ { CMD_READ_OLS, 2 },
+ { CMD_OLS_SMT_LEDON, 0 },
+ { CMD_OLS_SMT_LEDOFF, 0 },
+ { CMD_START_OLS_ASSY, 0 },
+ { CMD_STOP_OLS_ASSY, 0 },
+ { CMD_OLS_SMTTEST_STOP, 0 },
+ { CMD_READ_VIN_SCALED, 2 },
+ { CMD_READ_BAT_MIN_W, 2 },
+ { CMD_READ_BAR_MAX_W, 2 },
+ { CMD_RESET_BAT_MINMAX_W, 0 },
+ { CMD_READ_LOCATION, 1 },
+ { CMD_WRITE_LOCATION, 0 },
+ { CMD_GET_FW_HASH, 16 },
+ { CMD_SUSPEND_HINT, 0 },
+ { CMD_ENABLE_WAKE_TIMER, 0 },
+ { CMD_SET_WAKE_TIMER, 0 },
+ { CMD_ENABLE_WAKE_AUTORESET, 0 },
+ { CMD_OLS_SET_LIMITS, 0 },
+ { CMD_OLS_GET_LIMITS, 4 },
+ { CMD_OLS_SET_CEILING, 0 },
+ { CMD_OLS_GET_CEILING, 2 },
+ { CMD_READ_EXT_SCI_MASK, 2 },
+ { CMD_WRITE_EXT_SCI_MASK, 0 },
+
+ { }
+};
+
+#define EC_MAX_CMD_DATA_LEN 5
+#define EC_MAX_RESP_LEN 16
+
+#define LOG_BUF_SIZE 128
+
+#define PM_WAKEUP_TIME 1000
+
+#define EC_ALL_EVENTS GENMASK(15, 0)
+
+enum ec_state_t {
+ CMD_STATE_IDLE = 0,
+ CMD_STATE_WAITING_FOR_SWITCH,
+ CMD_STATE_CMD_IN_TX_FIFO,
+ CMD_STATE_CMD_SENT,
+ CMD_STATE_RESP_RECEIVED,
+ CMD_STATE_ERROR_RECEIVED,
+};
+
+struct olpc_xo175_ec_cmd {
+ u8 command;
+ u8 nr_args;
+ u8 data_len;
+ u8 args[EC_MAX_CMD_DATA_LEN];
+};
+
+struct olpc_xo175_ec_resp {
+ u8 channel;
+ u8 byte;
+};
+
+struct olpc_xo175_ec {
+ bool suspended;
+
+ /* SPI related stuff. */
+ struct spi_device *spi;
+ struct spi_transfer xfer;
+ struct spi_message msg;
+ union {
+ struct olpc_xo175_ec_cmd cmd;
+ struct olpc_xo175_ec_resp resp;
+ } tx_buf, rx_buf;
+
+ /* GPIO for the CMD signals. */
+ struct gpio_desc *gpio_cmd;
+
+ /* Command handling related state. */
+ spinlock_t cmd_state_lock;
+ int cmd_state;
+ bool cmd_running;
+ struct completion cmd_done;
+ struct olpc_xo175_ec_cmd cmd;
+ u8 resp_data[EC_MAX_RESP_LEN];
+ int expected_resp_len;
+ int resp_len;
+
+ /* Power button. */
+ struct input_dev *pwrbtn;
+
+ /* Debug handling. */
+ char logbuf[LOG_BUF_SIZE];
+ int logbuf_len;
+};
+
+static struct platform_device *olpc_ec;
+
+static int olpc_xo175_ec_resp_len(u8 cmd)
+{
+ const struct ec_cmd_t *p;
+
+ for (p = olpc_xo175_ec_cmds; p->cmd; p++) {
+ if (p->cmd == cmd)
+ return p->bytes_returned;
+ }
+
+ return -EINVAL;
+}
+
+static void olpc_xo175_ec_flush_logbuf(struct olpc_xo175_ec *priv)
+{
+ dev_dbg(&priv->spi->dev, "got debug string [%*pE]\n",
+ priv->logbuf_len, priv->logbuf);
+ priv->logbuf_len = 0;
+}
+
+static void olpc_xo175_ec_complete(void *arg);
+
+static void olpc_xo175_ec_send_command(struct olpc_xo175_ec *priv, void *cmd,
+ size_t cmdlen)
+{
+ int ret;
+
+ memcpy(&priv->tx_buf, cmd, cmdlen);
+ priv->xfer.len = cmdlen;
+
+ spi_message_init_with_transfers(&priv->msg, &priv->xfer, 1);
+
+ priv->msg.complete = olpc_xo175_ec_complete;
+ priv->msg.context = priv;
+
+ ret = spi_async(priv->spi, &priv->msg);
+ if (ret)
+ dev_err(&priv->spi->dev, "spi_async() failed %d\n", ret);
+}
+
+static void olpc_xo175_ec_read_packet(struct olpc_xo175_ec *priv)
+{
+ u8 nonce[] = {0xA5, 0x5A};
+
+ olpc_xo175_ec_send_command(priv, nonce, sizeof(nonce));
+}
+
+static void olpc_xo175_ec_complete(void *arg)
+{
+ struct olpc_xo175_ec *priv = arg;
+ struct device *dev = &priv->spi->dev;
+ struct power_supply *psy;
+ unsigned long flags;
+ u8 channel;
+ u8 byte;
+ int ret;
+
+ ret = priv->msg.status;
+ if (ret) {
+ dev_err(dev, "SPI transfer failed: %d\n", ret);
+
+ spin_lock_irqsave(&priv->cmd_state_lock, flags);
+ if (priv->cmd_running) {
+ priv->resp_len = 0;
+ priv->cmd_state = CMD_STATE_ERROR_RECEIVED;
+ complete(&priv->cmd_done);
+ }
+ spin_unlock_irqrestore(&priv->cmd_state_lock, flags);
+
+ if (ret != -EINTR)
+ olpc_xo175_ec_read_packet(priv);
+
+ return;
+ }
+
+ channel = priv->rx_buf.resp.channel;
+ byte = priv->rx_buf.resp.byte;
+
+ switch (channel) {
+ case CHAN_NONE:
+ spin_lock_irqsave(&priv->cmd_state_lock, flags);
+
+ if (!priv->cmd_running) {
+ /* We can safely ignore these */
+ dev_err(dev, "spurious FIFO read packet\n");
+ spin_unlock_irqrestore(&priv->cmd_state_lock, flags);
+ return;
+ }
+
+ priv->cmd_state = CMD_STATE_CMD_SENT;
+ if (!priv->expected_resp_len)
+ complete(&priv->cmd_done);
+ olpc_xo175_ec_read_packet(priv);
+
+ spin_unlock_irqrestore(&priv->cmd_state_lock, flags);
+ return;
+
+ case CHAN_SWITCH:
+ spin_lock_irqsave(&priv->cmd_state_lock, flags);
+
+ if (!priv->cmd_running) {
+ /* Just go with the flow */
+ dev_err(dev, "spurious SWITCH packet\n");
+ memset(&priv->cmd, 0, sizeof(priv->cmd));
+ priv->cmd.command = CMD_ECHO;
+ }
+
+ priv->cmd_state = CMD_STATE_CMD_IN_TX_FIFO;
+
+ /* Throw command into TxFIFO */
+ gpiod_set_value_cansleep(priv->gpio_cmd, 0);
+ olpc_xo175_ec_send_command(priv, &priv->cmd, sizeof(priv->cmd));
+
+ spin_unlock_irqrestore(&priv->cmd_state_lock, flags);
+ return;
+
+ case CHAN_CMD_RESP:
+ spin_lock_irqsave(&priv->cmd_state_lock, flags);
+
+ if (!priv->cmd_running) {
+ dev_err(dev, "spurious response packet\n");
+ } else if (priv->resp_len >= priv->expected_resp_len) {
+ dev_err(dev, "too many response packets\n");
+ } else {
+ priv->resp_data[priv->resp_len++] = byte;
+ if (priv->resp_len == priv->expected_resp_len) {
+ priv->cmd_state = CMD_STATE_RESP_RECEIVED;
+ complete(&priv->cmd_done);
+ }
+ }
+
+ spin_unlock_irqrestore(&priv->cmd_state_lock, flags);
+ break;
+
+ case CHAN_CMD_ERROR:
+ spin_lock_irqsave(&priv->cmd_state_lock, flags);
+
+ if (!priv->cmd_running) {
+ dev_err(dev, "spurious cmd error packet\n");
+ } else {
+ priv->resp_data[0] = byte;
+ priv->resp_len = 1;
+ priv->cmd_state = CMD_STATE_ERROR_RECEIVED;
+ complete(&priv->cmd_done);
+ }
+ spin_unlock_irqrestore(&priv->cmd_state_lock, flags);
+ break;
+
+ case CHAN_KEYBOARD:
+ dev_warn(dev, "keyboard is not supported\n");
+ break;
+
+ case CHAN_TOUCHPAD:
+ dev_warn(dev, "touchpad is not supported\n");
+ break;
+
+ case CHAN_EVENT:
+ dev_dbg(dev, "got event %.2x\n", byte);
+ switch (byte) {
+ case EVENT_AC_CHANGE:
+ psy = power_supply_get_by_name("olpc-ac");
+ if (psy) {
+ power_supply_changed(psy);
+ power_supply_put(psy);
+ }
+ break;
+ case EVENT_BATTERY_STATUS:
+ case EVENT_BATTERY_CRITICAL:
+ case EVENT_BATTERY_SOC_CHANGE:
+ case EVENT_BATTERY_ERROR:
+ psy = power_supply_get_by_name("olpc-battery");
+ if (psy) {
+ power_supply_changed(psy);
+ power_supply_put(psy);
+ }
+ break;
+ case EVENT_POWER_PRESSED:
+ input_report_key(priv->pwrbtn, KEY_POWER, 1);
+ input_sync(priv->pwrbtn);
+ input_report_key(priv->pwrbtn, KEY_POWER, 0);
+ input_sync(priv->pwrbtn);
+ /* fall through */
+ case EVENT_POWER_PRESS_WAKE:
+ case EVENT_TIMED_HOST_WAKE:
+ pm_wakeup_event(priv->pwrbtn->dev.parent,
+ PM_WAKEUP_TIME);
+ break;
+ default:
+ dev_dbg(dev, "ignored unknown event %.2x\n", byte);
+ break;
+ }
+ break;
+
+ case CHAN_DEBUG:
+ if (byte == '\n') {
+ olpc_xo175_ec_flush_logbuf(priv);
+ } else if (isprint(byte)) {
+ priv->logbuf[priv->logbuf_len++] = byte;
+ if (priv->logbuf_len == LOG_BUF_SIZE)
+ olpc_xo175_ec_flush_logbuf(priv);
+ }
+ break;
+
+ default:
+ dev_warn(dev, "unknown channel: %d, %.2x\n", channel, byte);
+ break;
+ }
+
+ /* Most non-command packets get the TxFIFO refilled and an ACK. */
+ olpc_xo175_ec_read_packet(priv);
+}
+
+/*
+ * This function is protected with a mutex. We can safely assume that
+ * there will be only one instance of this function running at a time.
+ * One of the ways in which we enforce this is by waiting until we get
+ * all response bytes back from the EC, rather than just the number that
+ * the caller requests (otherwise, we might start a new command while an
+ * old command's response bytes are still incoming).
+ */
+static int olpc_xo175_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *resp,
+ size_t resp_len, void *ec_cb_arg)
+{
+ struct olpc_xo175_ec *priv = ec_cb_arg;
+ struct device *dev = &priv->spi->dev;
+ unsigned long flags;
+ size_t nr_bytes;
+ int ret = 0;
+
+ dev_dbg(dev, "CMD %x, %zd bytes expected\n", cmd, resp_len);
+
+ if (inlen > 5) {
+ dev_err(dev, "command len %zd too big!\n", resp_len);
+ return -EOVERFLOW;
+ }
+
+ /* Suspending in the middle of an EC command hoses things badly! */
+ if (WARN_ON(priv->suspended))
+ return -EBUSY;
+
+ /* Ensure a valid command and return bytes */
+ ret = olpc_xo175_ec_resp_len(cmd);
+ if (ret < 0) {
+ dev_err_ratelimited(dev, "unknown command 0x%x\n", cmd);
+
+ /*
+ * Assume the best in our callers, and allow unknown commands
+ * through. I'm not the charitable type, but it was beaten
+ * into me. Just maintain a minimum standard of sanity.
+ */
+ if (resp_len > sizeof(priv->resp_data)) {
+ dev_err(dev, "response too big: %zd!\n", resp_len);
+ return -EOVERFLOW;
+ }
+ nr_bytes = resp_len;
+ } else {
+ nr_bytes = (size_t)ret;
+ ret = 0;
+ }
+ resp_len = min(resp_len, nr_bytes);
+
+ spin_lock_irqsave(&priv->cmd_state_lock, flags);
+
+ /* Initialize the state machine */
+ init_completion(&priv->cmd_done);
+ priv->cmd_running = true;
+ priv->cmd_state = CMD_STATE_WAITING_FOR_SWITCH;
+ memset(&priv->cmd, 0, sizeof(priv->cmd));
+ priv->cmd.command = cmd;
+ priv->cmd.nr_args = inlen;
+ priv->cmd.data_len = 0;
+ memcpy(priv->cmd.args, inbuf, inlen);
+ priv->expected_resp_len = nr_bytes;
+ priv->resp_len = 0;
+
+ /* Tickle the cmd gpio to get things started */
+ gpiod_set_value_cansleep(priv->gpio_cmd, 1);
+
+ spin_unlock_irqrestore(&priv->cmd_state_lock, flags);
+
+ /* The irq handler should do the rest */
+ if (!wait_for_completion_timeout(&priv->cmd_done,
+ msecs_to_jiffies(4000))) {
+ dev_err(dev, "EC cmd error: timeout in STATE %d\n",
+ priv->cmd_state);
+ gpiod_set_value_cansleep(priv->gpio_cmd, 0);
+ spi_slave_abort(priv->spi);
+ olpc_xo175_ec_read_packet(priv);
+ return -ETIMEDOUT;
+ }
+
+ spin_lock_irqsave(&priv->cmd_state_lock, flags);
+
+ /* Deal with the results. */
+ if (priv->cmd_state == CMD_STATE_ERROR_RECEIVED) {
+ /* EC-provided error is in the single response byte */
+ dev_err(dev, "command 0x%x returned error 0x%x\n",
+ cmd, priv->resp_data[0]);
+ ret = -EREMOTEIO;
+ } else if (priv->resp_len != nr_bytes) {
+ dev_err(dev, "command 0x%x returned %d bytes, expected %zd bytes\n",
+ cmd, priv->resp_len, nr_bytes);
+ ret = -EREMOTEIO;
+ } else {
+ /*
+ * We may have 8 bytes in priv->resp, but we only care about
+ * what we've been asked for. If the caller asked for only 2
+ * bytes, give them that. We've guaranteed that
+ * resp_len <= priv->resp_len and priv->resp_len == nr_bytes.
+ */
+ memcpy(resp, priv->resp_data, resp_len);
+ }
+
+ /* This should already be low, but just in case. */
+ gpiod_set_value_cansleep(priv->gpio_cmd, 0);
+ priv->cmd_running = false;
+
+ spin_unlock_irqrestore(&priv->cmd_state_lock, flags);
+
+ return ret;
+}
+
+static int olpc_xo175_ec_set_event_mask(unsigned int mask)
+{
+ u8 args[2];
+
+ args[0] = mask >> 0;
+ args[1] = mask >> 8;
+ return olpc_ec_cmd(CMD_WRITE_EXT_SCI_MASK, args, 2, NULL, 0);
+}
+
+static void olpc_xo175_ec_power_off(void)
+{
+ while (1) {
+ olpc_ec_cmd(CMD_POWER_OFF, NULL, 0, NULL, 0);
+ mdelay(1000);
+ }
+}
+
+static int __maybe_unused olpc_xo175_ec_suspend(struct device *dev)
+{
+ struct olpc_xo175_ec *priv = dev_get_drvdata(dev);
+ static struct {
+ u8 suspend;
+ u32 suspend_count;
+ } __packed hintargs;
+ static unsigned int suspend_count;
+
+ /*
+ * SOC_SLEEP is not wired to the EC on B3 and earlier boards.
+ * This command lets the EC know instead. The suspend count doesn't seem
+ * to be used anywhere but in the EC debug output.
+ */
+ hintargs.suspend = 1;
+ hintargs.suspend_count = suspend_count++;
+ olpc_ec_cmd(CMD_SUSPEND_HINT, (void *)&hintargs, sizeof(hintargs),
+ NULL, 0);
+
+ /*
+ * After we've sent the suspend hint, don't allow further EC commands
+ * to be run until we've resumed. Userspace tasks should be frozen,
+ * but kernel threads and interrupts could still schedule EC commands.
+ */
+ priv->suspended = true;
+
+ return 0;
+}
+
+static int __maybe_unused olpc_xo175_ec_resume_noirq(struct device *dev)
+{
+ struct olpc_xo175_ec *priv = dev_get_drvdata(dev);
+
+ priv->suspended = false;
+
+ return 0;
+}
+
+static int __maybe_unused olpc_xo175_ec_resume(struct device *dev)
+{
+ u8 x = 0;
+
+ /*
+ * The resume hint is only needed if no other commands are
+ * being sent during resume. all it does is tell the EC
+ * the SoC is definitely awake.
+ */
+ olpc_ec_cmd(CMD_SUSPEND_HINT, &x, 1, NULL, 0);
+
+ /* Enable all EC events while we're awake */
+ olpc_xo175_ec_set_event_mask(EC_ALL_EVENTS);
+
+ return 0;
+}
+
+static struct olpc_ec_driver olpc_xo175_ec_driver = {
+ .ec_cmd = olpc_xo175_ec_cmd,
+};
+
+static int olpc_xo175_ec_remove(struct spi_device *spi)
+{
+ if (pm_power_off == olpc_xo175_ec_power_off)
+ pm_power_off = NULL;
+
+ spi_slave_abort(spi);
+
+ platform_device_unregister(olpc_ec);
+ olpc_ec = NULL;
+
+ return 0;
+}
+
+static int olpc_xo175_ec_probe(struct spi_device *spi)
+{
+ struct olpc_xo175_ec *priv;
+ int ret;
+
+ if (olpc_ec) {
+ dev_err(&spi->dev, "OLPC EC already registered.\n");
+ return -EBUSY;
+ }
+
+ priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->gpio_cmd = devm_gpiod_get(&spi->dev, "cmd", GPIOD_OUT_LOW);
+ if (IS_ERR(priv->gpio_cmd)) {
+ dev_err(&spi->dev, "failed to get cmd gpio: %ld\n",
+ PTR_ERR(priv->gpio_cmd));
+ return PTR_ERR(priv->gpio_cmd);
+ }
+
+ priv->spi = spi;
+
+ spin_lock_init(&priv->cmd_state_lock);
+ priv->cmd_state = CMD_STATE_IDLE;
+ init_completion(&priv->cmd_done);
+
+ priv->logbuf_len = 0;
+
+ /* Set up power button input device */
+ priv->pwrbtn = devm_input_allocate_device(&spi->dev);
+ if (!priv->pwrbtn)
+ return -ENOMEM;
+ priv->pwrbtn->name = "Power Button";
+ priv->pwrbtn->dev.parent = &spi->dev;
+ input_set_capability(priv->pwrbtn, EV_KEY, KEY_POWER);
+ ret = input_register_device(priv->pwrbtn);
+ if (ret) {
+ dev_err(&spi->dev, "error registering input device: %d\n", ret);
+ return ret;
+ }
+
+ spi_set_drvdata(spi, priv);
+
+ priv->xfer.rx_buf = &priv->rx_buf;
+ priv->xfer.tx_buf = &priv->tx_buf;
+
+ olpc_xo175_ec_read_packet(priv);
+
+ olpc_ec_driver_register(&olpc_xo175_ec_driver, priv);
+ olpc_ec = platform_device_register_resndata(&spi->dev, "olpc-ec", -1,
+ NULL, 0, NULL, 0);
+
+ /* Enable all EC events while we're awake */
+ olpc_xo175_ec_set_event_mask(EC_ALL_EVENTS);
+
+ if (pm_power_off == NULL)
+ pm_power_off = olpc_xo175_ec_power_off;
+
+ dev_info(&spi->dev, "OLPC XO-1.75 Embedded Controller driver\n");
+
+ return 0;
+}
+
+static const struct dev_pm_ops olpc_xo175_ec_pm_ops = {
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, olpc_xo175_ec_resume_noirq)
+ SET_RUNTIME_PM_OPS(olpc_xo175_ec_suspend, olpc_xo175_ec_resume, NULL)
+};
+
+static const struct of_device_id olpc_xo175_ec_of_match[] = {
+ { .compatible = "olpc,xo1.75-ec" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, olpc_xo175_ec_of_match);
+
+static struct spi_driver olpc_xo175_ec_spi_driver = {
+ .driver = {
+ .name = "olpc-xo175-ec",
+ .of_match_table = olpc_xo175_ec_of_match,
+ .pm = &olpc_xo175_ec_pm_ops,
+ },
+ .probe = olpc_xo175_ec_probe,
+ .remove = olpc_xo175_ec_remove,
+};
+module_spi_driver(olpc_xo175_ec_spi_driver);
+
+MODULE_DESCRIPTION("OLPC XO-1.75 Embedded Controller driver");
+MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>"); /* Functionality */
+MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>"); /* Bugs */
+MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 5d5cc6111081..1b67bb578f9f 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -118,7 +118,7 @@ config DCDBAS
Interrupts (SMIs) and Host Control Actions (system power cycle or
power off after OS shutdown) on certain Dell systems.
- See <file:Documentation/dcdbas.txt> for more details on the driver
+ See <file:Documentation/driver-api/dcdbas.rst> for more details on the driver
and the Dell systems on which Dell systems management software makes
use of this driver.
@@ -259,7 +259,7 @@ config DELL_RBU
DELL system. Note you need a Dell OpenManage or Dell Update package (DUP)
supporting application to communicate with the BIOS regarding the new
image for the image update to take effect.
- See <file:Documentation/dell_rbu.txt> for more details on the driver.
+ See <file:Documentation/driver-api/dell_rbu.rst> for more details on the driver.
config FUJITSU_LAPTOP
@@ -341,7 +341,7 @@ config HP_ACCEL
Support for a led indicating disk protection will be provided as
hp::hddprotect. For more information on the feature, refer to
- Documentation/misc-devices/lis3lv02d.
+ Documentation/misc-devices/lis3lv02d.rst.
To compile this driver as a module, choose M here: the module will
be called hp_accel.
@@ -433,9 +433,6 @@ config COMPAL_LAPTOP
It adds support for rfkill, Bluetooth, WLAN, LCD brightness, hwmon
and battery charging level control.
- For a (possibly incomplete) list of supported laptops, please refer
- to: Documentation/platform/x86-laptop-drivers.txt
-
config SONY_LAPTOP
tristate "Sony Laptop Extras"
depends on ACPI
@@ -451,7 +448,7 @@ config SONY_LAPTOP
screen brightness control, Fn keys and allows powering on/off some
devices.
- Read <file:Documentation/laptops/sony-laptop.txt> for more information.
+ Read <file:Documentation/admin-guide/laptops/sony-laptop.rst> for more information.
config SONYPI_COMPAT
bool "Sonypi compatibility"
@@ -503,7 +500,7 @@ config THINKPAD_ACPI
support for Fn-Fx key combinations, Bluetooth control, video
output switching, ThinkLight control, UltraBay eject and more.
For more information about this driver see
- <file:Documentation/laptops/thinkpad-acpi.txt> and
+ <file:Documentation/admin-guide/laptops/thinkpad-acpi.rst> and
<http://ibm-acpi.sf.net/> .
This driver was formerly known as ibm-acpi.
@@ -781,6 +778,16 @@ config INTEL_WMI_THUNDERBOLT
To compile this driver as a module, choose M here: the module will
be called intel-wmi-thunderbolt.
+config XIAOMI_WMI
+ tristate "Xiaomi WMI key driver"
+ depends on ACPI_WMI
+ depends on INPUT
+ help
+ Say Y here if you want to support WMI-based keys on Xiaomi notebooks.
+
+ To compile this driver as a module, choose M here: the module will
+ be called xiaomi-wmi.
+
config MSI_WMI
tristate "MSI WMI extras"
depends on ACPI_WMI
@@ -906,7 +913,6 @@ config TOSHIBA_WMI
config ACPI_CMPC
tristate "CMPC Laptop Extras"
depends on ACPI && INPUT
- depends on BACKLIGHT_LCD_SUPPORT
depends on RFKILL || RFKILL=n
select BACKLIGHT_CLASS_DEVICE
help
@@ -1130,7 +1136,6 @@ config INTEL_OAKTRAIL
config SAMSUNG_Q10
tristate "Samsung Q10 Extras"
depends on ACPI
- depends on BACKLIGHT_LCD_SUPPORT
select BACKLIGHT_CLASS_DEVICE
---help---
This driver provides support for backlight control on Samsung Q10
@@ -1317,7 +1322,7 @@ config HUAWEI_WMI
config PCENGINES_APU2
tristate "PC Engines APUv2/3 front button and LEDs driver"
- depends on INPUT && INPUT_KEYBOARD
+ depends on INPUT && INPUT_KEYBOARD && GPIOLIB
depends on LEDS_CLASS
select GPIO_AMD_FCH
select KEYBOARD_GPIO_POLLED
@@ -1329,6 +1334,8 @@ config PCENGINES_APU2
To compile this driver as a module, choose M here: the module
will be called pcengines-apuv2.
+source "drivers/platform/x86/intel_speed_select_if/Kconfig"
+
endif # X86_PLATFORM_DEVICES
config PMC_ATOM
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 87b0069bd781..415104033060 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_SURFACE3_WMI) += surface3-wmi.o
obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o
obj-$(CONFIG_WMI_BMOF) += wmi-bmof.o
obj-$(CONFIG_INTEL_WMI_THUNDERBOLT) += intel-wmi-thunderbolt.o
+obj-$(CONFIG_XIAOMI_WMI) += xiaomi-wmi.o
# toshiba_acpi must link after wmi to ensure that wmi devices are found
# before toshiba_acpi initializes
@@ -89,7 +90,7 @@ obj-$(CONFIG_INTEL_BXTWC_PMIC_TMU) += intel_bxtwc_tmu.o
obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o \
intel_telemetry_pltdrv.o \
intel_telemetry_debugfs.o
-obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o
+obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o intel_pmc_core_pltdrv.o
obj-$(CONFIG_PMC_ATOM) += pmc_atom.o
obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o
obj-$(CONFIG_INTEL_TURBO_MAX_3) += intel_turbo_max_3.o
@@ -98,3 +99,4 @@ obj-$(CONFIG_INTEL_MRFLD_PWRBTN) += intel_mrfld_pwrbtn.o
obj-$(CONFIG_I2C_MULTI_INSTANTIATE) += i2c-multi-instantiate.o
obj-$(CONFIG_INTEL_ATOMISP2_PM) += intel_atomisp2_pm.o
obj-$(CONFIG_PCENGINES_APU2) += pcengines-apuv2.o
+obj-$(CONFIG_INTEL_SPEED_SELECT_INTERFACE) += intel_speed_select_if/
diff --git a/drivers/platform/x86/acer-wireless.c b/drivers/platform/x86/acer-wireless.c
index 858037987b33..e0976180532a 100644
--- a/drivers/platform/x86/acer-wireless.c
+++ b/drivers/platform/x86/acer-wireless.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Acer Wireless Radio Control Driver
*
* Copyright (C) 2017 Endless Mobile, 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.
*/
#include <linux/acpi.h>
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index 521b526cd467..62b54e137231 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -259,7 +259,6 @@ struct acer_data {
struct acer_debug {
struct dentry *root;
- struct dentry *devices;
u32 wmid_devices;
};
@@ -1002,6 +1001,7 @@ static acpi_status WMID_get_u32(u32 *value, u32 cap)
*value = tmp & 0x1;
return 0;
}
+ /* fall through */
default:
return AE_ERROR;
}
@@ -1328,6 +1328,7 @@ static acpi_status get_u32(u32 *value, u32 cap)
status = AMW0_get_u32(value, cap);
break;
}
+ /* fall through */
case ACER_WMID:
status = WMID_get_u32(value, cap);
break;
@@ -1370,6 +1371,7 @@ static acpi_status set_u32(u32 value, u32 cap)
return AMW0_set_u32(value, cap);
}
+ /* fall through */
case ACER_WMID:
return WMID_set_u32(value, cap);
case ACER_WMID_v2:
@@ -1379,6 +1381,7 @@ static acpi_status set_u32(u32 value, u32 cap)
return wmid_v2_set_u32(value, cap);
else if (wmi_has_guid(WMID_GUID2))
return WMID_set_u32(value, cap);
+ /* fall through */
default:
return AE_BAD_PARAMETER;
}
@@ -2148,29 +2151,15 @@ static struct platform_device *acer_platform_device;
static void remove_debugfs(void)
{
- debugfs_remove(interface->debug.devices);
- debugfs_remove(interface->debug.root);
+ debugfs_remove_recursive(interface->debug.root);
}
-static int __init create_debugfs(void)
+static void __init create_debugfs(void)
{
interface->debug.root = debugfs_create_dir("acer-wmi", NULL);
- if (!interface->debug.root) {
- pr_err("Failed to create debugfs directory");
- return -ENOMEM;
- }
- interface->debug.devices = debugfs_create_u32("devices", S_IRUGO,
- interface->debug.root,
- &interface->debug.wmid_devices);
- if (!interface->debug.devices)
- goto error_debugfs;
-
- return 0;
-
-error_debugfs:
- remove_debugfs();
- return -ENOMEM;
+ debugfs_create_u32("devices", S_IRUGO, interface->debug.root,
+ &interface->debug.wmid_devices);
}
static int __init acer_wmi_init(void)
@@ -2300,9 +2289,7 @@ static int __init acer_wmi_init(void)
if (wmi_has_guid(WMID_GUID2)) {
interface->debug.wmid_devices = get_wmid_devices();
- err = create_debugfs();
- if (err)
- goto error_create_debugfs;
+ create_debugfs();
}
/* Override any initial settings with values from the commandline */
@@ -2310,8 +2297,6 @@ static int __init acer_wmi_init(void)
return 0;
-error_create_debugfs:
- platform_device_del(acer_platform_device);
error_device_add:
platform_device_put(acer_platform_device);
error_device_alloc:
diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
index fd2ffebc868f..7e3083deb1c5 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Gmux driver for Apple laptops
*
* Copyright (C) Canonical Ltd. <seth.forshee@canonical.com>
* Copyright (C) 2010-2012 Andreas Heider <andreas@meetr.de>
* Copyright (C) 2015 Lukas Wunner <lukas@wunner.de>
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c
index 8d9e30dbb5af..2ebde0174937 100644
--- a/drivers/platform/x86/asus-nb-wmi.c
+++ b/drivers/platform/x86/asus-nb-wmi.c
@@ -463,6 +463,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
{ KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } },
{ KE_IGNORE, 0x6E, }, /* Low Battery notification */
{ KE_KEY, 0x7a, { KEY_ALS_TOGGLE } }, /* Ambient Light Sensor Toggle */
+ { KE_KEY, 0x7c, { KEY_MICMUTE } },
{ KE_KEY, 0x7D, { KEY_BLUETOOTH } }, /* Bluetooth Enable */
{ KE_KEY, 0x7E, { KEY_BLUETOOTH } }, /* Bluetooth Disable */
{ KE_KEY, 0x82, { KEY_CAMERA } },
@@ -477,7 +478,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
{ KE_KEY, 0x92, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + DVI */
{ KE_KEY, 0x93, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + DVI */
{ KE_KEY, 0x95, { KEY_MEDIA } },
- { KE_KEY, 0x99, { KEY_PHONE } },
+ { KE_KEY, 0x99, { KEY_PHONE } }, /* Conflicts with fan mode switch */
{ KE_KEY, 0xA0, { KEY_SWITCHVIDEOMODE } }, /* SDSP HDMI only */
{ KE_KEY, 0xA1, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + HDMI */
{ KE_KEY, 0xA2, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + HDMI */
diff --git a/drivers/platform/x86/asus-wireless.c b/drivers/platform/x86/asus-wireless.c
index 7458f7602d5e..d3e7171928e5 100644
--- a/drivers/platform/x86/asus-wireless.c
+++ b/drivers/platform/x86/asus-wireless.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Asus Wireless Radio Control Driver
*
* Copyright (C) 2015-2016 Endless Mobile, 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 9b18a184e0aa..ca28d27dae63 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -57,6 +57,7 @@ MODULE_LICENSE("GPL");
#define NOTIFY_KBD_BRTUP 0xc4
#define NOTIFY_KBD_BRTDWN 0xc5
#define NOTIFY_KBD_BRTTOGGLE 0xc7
+#define NOTIFY_KBD_FBM 0x99
#define ASUS_WMI_FNLOCK_BIOS_DISABLED BIT(0)
@@ -67,9 +68,27 @@ MODULE_LICENSE("GPL");
#define ASUS_FAN_CTRL_MANUAL 1
#define ASUS_FAN_CTRL_AUTO 2
+#define ASUS_FAN_BOOST_MODE_NORMAL 0
+#define ASUS_FAN_BOOST_MODE_OVERBOOST 1
+#define ASUS_FAN_BOOST_MODE_OVERBOOST_MASK 0x01
+#define ASUS_FAN_BOOST_MODE_SILENT 2
+#define ASUS_FAN_BOOST_MODE_SILENT_MASK 0x02
+#define ASUS_FAN_BOOST_MODES_MASK 0x03
+
#define USB_INTEL_XUSB2PR 0xD0
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31
+#define ASUS_ACPI_UID_ASUSWMI "ASUSWMI"
+#define ASUS_ACPI_UID_ATK "ATK"
+
+#define WMI_EVENT_QUEUE_SIZE 0x10
+#define WMI_EVENT_QUEUE_END 0x1
+#define WMI_EVENT_MASK 0xFFFF
+/* The WMI hotkey event value is always the same. */
+#define WMI_EVENT_VALUE_ATK 0xFF
+
+#define WMI_EVENT_MASK 0xFFFF
+
static const char * const ashs_ids[] = { "ATK4001", "ATK4002", NULL };
static bool ashs_present(void)
@@ -85,6 +104,7 @@ static bool ashs_present(void)
struct bios_args {
u32 arg0;
u32 arg1;
+ u32 arg2; /* At least TUF Gaming series uses 3 dword input buffer. */
} __packed;
/*
@@ -132,6 +152,7 @@ struct asus_wmi {
int dsts_id;
int spec;
int sfun;
+ bool wmi_event_queue;
struct input_dev *inputdev;
struct backlight_device *backlight_device;
@@ -161,6 +182,10 @@ struct asus_wmi {
int asus_hwmon_num_fans;
int asus_hwmon_pwm;
+ bool fan_boost_mode_available;
+ u8 fan_boost_mode_mask;
+ u8 fan_boost_mode;
+
struct hotplug_slot hotplug_slot;
struct mutex hotplug_lock;
struct mutex wmi_lock;
@@ -174,6 +199,8 @@ struct asus_wmi {
struct asus_wmi_driver *driver;
};
+/* Input **********************************************************************/
+
static int asus_wmi_input_init(struct asus_wmi *asus)
{
int err;
@@ -211,11 +238,15 @@ static void asus_wmi_input_exit(struct asus_wmi *asus)
asus->inputdev = NULL;
}
-int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval)
+/* WMI ************************************************************************/
+
+static int asus_wmi_evaluate_method3(u32 method_id,
+ u32 arg0, u32 arg1, u32 arg2, u32 *retval)
{
struct bios_args args = {
.arg0 = arg0,
.arg1 = arg1,
+ .arg2 = arg2,
};
struct acpi_buffer input = { (acpi_size) sizeof(args), &args };
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -227,7 +258,7 @@ int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval)
&input, &output);
if (ACPI_FAILURE(status))
- goto exit;
+ return -EIO;
obj = (union acpi_object *)output.pointer;
if (obj && obj->type == ACPI_TYPE_INTEGER)
@@ -238,15 +269,16 @@ int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval)
kfree(obj);
-exit:
- if (ACPI_FAILURE(status))
- return -EIO;
-
if (tmp == ASUS_WMI_UNSUPPORTED_METHOD)
return -ENODEV;
return 0;
}
+
+int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval)
+{
+ return asus_wmi_evaluate_method3(method_id, arg0, arg1, 0, retval);
+}
EXPORT_SYMBOL_GPL(asus_wmi_evaluate_method);
static int asus_wmi_evaluate_method_agfn(const struct acpi_buffer args)
@@ -320,9 +352,8 @@ static int asus_wmi_get_devstate_simple(struct asus_wmi *asus, u32 dev_id)
ASUS_WMI_DSTS_STATUS_BIT);
}
-/*
- * LEDs
- */
+/* LEDs ***********************************************************************/
+
/*
* These functions actually update the LED's, and are called from a
* workqueue. By doing this as separate work rather than when the LED
@@ -427,6 +458,10 @@ static void do_kbd_led_set(struct led_classdev *led_cdev, int value)
static void kbd_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
+ /* Prevent disabling keyboard backlight on module unregister */
+ if (led_cdev->flags & LED_UNREGISTERING)
+ return;
+
do_kbd_led_set(led_cdev, value);
}
@@ -582,8 +617,7 @@ static int asus_wmi_led_init(struct asus_wmi *asus)
goto error;
}
- led_val = kbd_led_read(asus, NULL, NULL);
- if (led_val >= 0) {
+ if (!kbd_led_read(asus, &led_val, NULL)) {
asus->kbd_led_wk = led_val;
asus->kbd_led.name = "asus::kbd_backlight";
asus->kbd_led.flags = LED_BRIGHT_HW_CHANGED;
@@ -633,6 +667,7 @@ error:
return rv;
}
+/* RF *************************************************************************/
/*
* PCI hotplug (for wlan rfkill)
@@ -1055,6 +1090,8 @@ exit:
return result;
}
+/* Quirks *********************************************************************/
+
static void asus_wmi_set_xusb2pr(struct asus_wmi *asus)
{
struct pci_dev *xhci_pdev;
@@ -1087,9 +1124,8 @@ static void asus_wmi_set_als(void)
asus_wmi_set_devstate(ASUS_WMI_DEVID_ALS_ENABLE, 1, NULL);
}
-/*
- * Hwmon device
- */
+/* Hwmon device ***************************************************************/
+
static int asus_hwmon_agfn_fan_speed_read(struct asus_wmi *asus, int fan,
int *speed)
{
@@ -1353,8 +1389,7 @@ static umode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj,
struct attribute *attr, int idx)
{
struct device *dev = container_of(kobj, struct device, kobj);
- struct platform_device *pdev = to_platform_device(dev->parent);
- struct asus_wmi *asus = platform_get_drvdata(pdev);
+ struct asus_wmi *asus = dev_get_drvdata(dev->parent);
int dev_id = -1;
int fan_attr = -1;
u32 value = ASUS_WMI_UNSUPPORTED_METHOD;
@@ -1395,8 +1430,11 @@ static umode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj,
else
ok = fan_attr <= asus->asus_hwmon_num_fans;
} else if (dev_id == ASUS_WMI_DEVID_THERMAL_CTRL) {
- /* If value is zero, something is clearly wrong */
- if (!value)
+ /*
+ * If the temperature value in deci-Kelvin is near the absolute
+ * zero temperature, something is clearly wrong
+ */
+ if (value == 0 || value == 1)
ok = false;
} else if (fan_attr <= asus->asus_hwmon_num_fans && fan_attr != -1) {
ok = true;
@@ -1415,11 +1453,12 @@ __ATTRIBUTE_GROUPS(hwmon_attribute);
static int asus_wmi_hwmon_init(struct asus_wmi *asus)
{
+ struct device *dev = &asus->platform_device->dev;
struct device *hwmon;
- hwmon = hwmon_device_register_with_groups(&asus->platform_device->dev,
- "asus", asus,
- hwmon_attribute_groups);
+ hwmon = devm_hwmon_device_register_with_groups(dev, "asus", asus,
+ hwmon_attribute_groups);
+
if (IS_ERR(hwmon)) {
pr_err("Could not register asus hwmon device\n");
return PTR_ERR(hwmon);
@@ -1427,9 +1466,143 @@ static int asus_wmi_hwmon_init(struct asus_wmi *asus)
return 0;
}
-/*
- * Backlight
- */
+static int asus_wmi_fan_init(struct asus_wmi *asus)
+{
+ int status;
+
+ asus->asus_hwmon_pwm = -1;
+ asus->asus_hwmon_num_fans = -1;
+ asus->asus_hwmon_fan_manual_mode = false;
+
+ status = asus_hwmon_get_fan_number(asus, &asus->asus_hwmon_num_fans);
+ if (status) {
+ asus->asus_hwmon_num_fans = 0;
+ pr_warn("Could not determine number of fans: %d\n", status);
+ return -ENXIO;
+ }
+
+ pr_info("Number of fans: %d\n", asus->asus_hwmon_num_fans);
+ return 0;
+}
+
+/* Fan mode *******************************************************************/
+
+static int fan_boost_mode_check_present(struct asus_wmi *asus)
+{
+ u32 result;
+ int err;
+
+ asus->fan_boost_mode_available = false;
+
+ err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FAN_BOOST_MODE,
+ &result);
+ if (err) {
+ if (err == -ENODEV)
+ return 0;
+ else
+ return err;
+ }
+
+ if ((result & ASUS_WMI_DSTS_PRESENCE_BIT) &&
+ (result & ASUS_FAN_BOOST_MODES_MASK)) {
+ asus->fan_boost_mode_available = true;
+ asus->fan_boost_mode_mask = result & ASUS_FAN_BOOST_MODES_MASK;
+ }
+
+ return 0;
+}
+
+static int fan_boost_mode_write(struct asus_wmi *asus)
+{
+ int err;
+ u8 value;
+ u32 retval;
+
+ value = asus->fan_boost_mode;
+
+ pr_info("Set fan boost mode: %u\n", value);
+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_FAN_BOOST_MODE, value,
+ &retval);
+
+ if (err) {
+ pr_warn("Failed to set fan boost mode: %d\n", err);
+ return err;
+ }
+
+ if (retval != 1) {
+ pr_warn("Failed to set fan boost mode (retval): 0x%x\n",
+ retval);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int fan_boost_mode_switch_next(struct asus_wmi *asus)
+{
+ u8 mask = asus->fan_boost_mode_mask;
+
+ if (asus->fan_boost_mode == ASUS_FAN_BOOST_MODE_NORMAL) {
+ if (mask & ASUS_FAN_BOOST_MODE_OVERBOOST_MASK)
+ asus->fan_boost_mode = ASUS_FAN_BOOST_MODE_OVERBOOST;
+ else if (mask & ASUS_FAN_BOOST_MODE_SILENT_MASK)
+ asus->fan_boost_mode = ASUS_FAN_BOOST_MODE_SILENT;
+ } else if (asus->fan_boost_mode == ASUS_FAN_BOOST_MODE_OVERBOOST) {
+ if (mask & ASUS_FAN_BOOST_MODE_SILENT_MASK)
+ asus->fan_boost_mode = ASUS_FAN_BOOST_MODE_SILENT;
+ else
+ asus->fan_boost_mode = ASUS_FAN_BOOST_MODE_NORMAL;
+ } else {
+ asus->fan_boost_mode = ASUS_FAN_BOOST_MODE_NORMAL;
+ }
+
+ return fan_boost_mode_write(asus);
+}
+
+static ssize_t fan_boost_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", asus->fan_boost_mode);
+}
+
+static ssize_t fan_boost_mode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int result;
+ u8 new_mode;
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+ u8 mask = asus->fan_boost_mode_mask;
+
+ result = kstrtou8(buf, 10, &new_mode);
+ if (result < 0) {
+ pr_warn("Trying to store invalid value\n");
+ return result;
+ }
+
+ if (new_mode == ASUS_FAN_BOOST_MODE_OVERBOOST) {
+ if (!(mask & ASUS_FAN_BOOST_MODE_OVERBOOST_MASK))
+ return -EINVAL;
+ } else if (new_mode == ASUS_FAN_BOOST_MODE_SILENT) {
+ if (!(mask & ASUS_FAN_BOOST_MODE_SILENT_MASK))
+ return -EINVAL;
+ } else if (new_mode != ASUS_FAN_BOOST_MODE_NORMAL) {
+ return -EINVAL;
+ }
+
+ asus->fan_boost_mode = new_mode;
+ fan_boost_mode_write(asus);
+
+ return result;
+}
+
+// Fan boost mode: 0 - normal, 1 - overboost, 2 - silent
+static DEVICE_ATTR_RW(fan_boost_mode);
+
+/* Backlight ******************************************************************/
+
static int read_backlight_power(struct asus_wmi *asus)
{
int ret;
@@ -1611,6 +1784,8 @@ static int is_display_toggle(int code)
return 0;
}
+/* Fn-lock ********************************************************************/
+
static bool asus_wmi_has_fnlock_key(struct asus_wmi *asus)
{
u32 result;
@@ -1628,88 +1803,148 @@ static void asus_wmi_fnlock_update(struct asus_wmi *asus)
asus_wmi_set_devstate(ASUS_WMI_DEVID_FNLOCK, mode, NULL);
}
-static void asus_wmi_notify(u32 value, void *context)
+/* WMI events *****************************************************************/
+
+static int asus_wmi_get_event_code(u32 value)
{
- struct asus_wmi *asus = context;
struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *obj;
acpi_status status;
int code;
- int orig_code;
- unsigned int key_value = 1;
- bool autorelease = 1;
status = wmi_get_event_data(value, &response);
- if (status != AE_OK) {
- pr_err("bad event status 0x%x\n", status);
- return;
+ if (ACPI_FAILURE(status)) {
+ pr_warn("Failed to get WMI notify code: %s\n",
+ acpi_format_exception(status));
+ return -EIO;
}
obj = (union acpi_object *)response.pointer;
- if (!obj || obj->type != ACPI_TYPE_INTEGER)
- goto exit;
+ if (obj && obj->type == ACPI_TYPE_INTEGER)
+ code = (int)(obj->integer.value & WMI_EVENT_MASK);
+ else
+ code = -EIO;
+
+ kfree(obj);
+ return code;
+}
+
+static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)
+{
+ int orig_code;
+ unsigned int key_value = 1;
+ bool autorelease = 1;
- code = obj->integer.value;
orig_code = code;
if (asus->driver->key_filter) {
asus->driver->key_filter(asus->driver, &code, &key_value,
&autorelease);
if (code == ASUS_WMI_KEY_IGNORE)
- goto exit;
+ return;
}
if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX)
code = ASUS_WMI_BRN_UP;
- else if (code >= NOTIFY_BRNDOWN_MIN &&
- code <= NOTIFY_BRNDOWN_MAX)
+ else if (code >= NOTIFY_BRNDOWN_MIN && code <= NOTIFY_BRNDOWN_MAX)
code = ASUS_WMI_BRN_DOWN;
if (code == ASUS_WMI_BRN_DOWN || code == ASUS_WMI_BRN_UP) {
if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
asus_wmi_backlight_notify(asus, orig_code);
- goto exit;
+ return;
}
}
if (code == NOTIFY_KBD_BRTUP) {
kbd_led_set_by_kbd(asus, asus->kbd_led_wk + 1);
- goto exit;
+ return;
}
if (code == NOTIFY_KBD_BRTDWN) {
kbd_led_set_by_kbd(asus, asus->kbd_led_wk - 1);
- goto exit;
+ return;
}
if (code == NOTIFY_KBD_BRTTOGGLE) {
if (asus->kbd_led_wk == asus->kbd_led.max_brightness)
kbd_led_set_by_kbd(asus, 0);
else
kbd_led_set_by_kbd(asus, asus->kbd_led_wk + 1);
- goto exit;
+ return;
}
if (code == NOTIFY_FNLOCK_TOGGLE) {
asus->fnlock_locked = !asus->fnlock_locked;
asus_wmi_fnlock_update(asus);
- goto exit;
+ return;
}
- if (is_display_toggle(code) &&
- asus->driver->quirks->no_display_toggle)
- goto exit;
+ if (asus->fan_boost_mode_available && code == NOTIFY_KBD_FBM) {
+ fan_boost_mode_switch_next(asus);
+ return;
+ }
+
+ if (is_display_toggle(code) && asus->driver->quirks->no_display_toggle)
+ return;
if (!sparse_keymap_report_event(asus->inputdev, code,
key_value, autorelease))
pr_info("Unknown key %x pressed\n", code);
+}
-exit:
- kfree(obj);
+static void asus_wmi_notify(u32 value, void *context)
+{
+ struct asus_wmi *asus = context;
+ int code;
+ int i;
+
+ for (i = 0; i < WMI_EVENT_QUEUE_SIZE + 1; i++) {
+ code = asus_wmi_get_event_code(value);
+
+ if (code < 0) {
+ pr_warn("Failed to get notify code: %d\n", code);
+ return;
+ }
+
+ if (code == WMI_EVENT_QUEUE_END || code == WMI_EVENT_MASK)
+ return;
+
+ asus_wmi_handle_event_code(code, asus);
+
+ /*
+ * Double check that queue is present:
+ * ATK (with queue) uses 0xff, ASUSWMI (without) 0xd2.
+ */
+ if (!asus->wmi_event_queue || value != WMI_EVENT_VALUE_ATK)
+ return;
+ }
+
+ pr_warn("Failed to process event queue, last code: 0x%x\n", code);
}
-/*
- * Sys helpers
- */
+static int asus_wmi_notify_queue_flush(struct asus_wmi *asus)
+{
+ int code;
+ int i;
+
+ for (i = 0; i < WMI_EVENT_QUEUE_SIZE + 1; i++) {
+ code = asus_wmi_get_event_code(WMI_EVENT_VALUE_ATK);
+
+ if (code < 0) {
+ pr_warn("Failed to get event during flush: %d\n", code);
+ return code;
+ }
+
+ if (code == WMI_EVENT_QUEUE_END || code == WMI_EVENT_MASK)
+ return 0;
+ }
+
+ pr_warn("Failed to flush event queue\n");
+ return -EIO;
+}
+
+/* Sysfs **********************************************************************/
+
static int parse_arg(const char *buf, unsigned long count, int *val)
{
if (!count)
@@ -1805,6 +2040,7 @@ static struct attribute *platform_attributes[] = {
&dev_attr_touchpad.attr,
&dev_attr_lid_resume.attr,
&dev_attr_als_enable.attr,
+ &dev_attr_fan_boost_mode.attr,
NULL
};
@@ -1826,6 +2062,8 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
devid = ASUS_WMI_DEVID_LID_RESUME;
else if (attr == &dev_attr_als_enable.attr)
devid = ASUS_WMI_DEVID_ALS_ENABLE;
+ else if (attr == &dev_attr_fan_boost_mode.attr)
+ ok = asus->fan_boost_mode_available;
if (devid != -1)
ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0);
@@ -1848,11 +2086,12 @@ static int asus_wmi_sysfs_init(struct platform_device *device)
return sysfs_create_group(&device->dev.kobj, &platform_attribute_group);
}
-/*
- * Platform device
- */
+/* Platform device ************************************************************/
+
static int asus_wmi_platform_init(struct asus_wmi *asus)
{
+ struct device *dev = &asus->platform_device->dev;
+ char *wmi_uid;
int rv;
/* INIT enable hotkeys on some models */
@@ -1882,11 +2121,41 @@ static int asus_wmi_platform_init(struct asus_wmi *asus)
* Note, on most Eeepc, there is no way to check if a method exist
* or note, while on notebooks, they returns 0xFFFFFFFE on failure,
* but once again, SPEC may probably be used for that kind of things.
+ *
+ * Additionally at least TUF Gaming series laptops return nothing for
+ * unknown methods, so the detection in this way is not possible.
+ *
+ * There is strong indication that only ACPI WMI devices that have _UID
+ * equal to "ASUSWMI" use DCTS whereas those with "ATK" use DSTS.
*/
- if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, 0, 0, NULL))
+ wmi_uid = wmi_get_acpi_device_uid(ASUS_WMI_MGMT_GUID);
+ if (!wmi_uid)
+ return -ENODEV;
+
+ if (!strcmp(wmi_uid, ASUS_ACPI_UID_ASUSWMI)) {
+ dev_info(dev, "Detected ASUSWMI, use DCTS\n");
+ asus->dsts_id = ASUS_WMI_METHODID_DCTS;
+ } else {
+ dev_info(dev, "Detected %s, not ASUSWMI, use DSTS\n", wmi_uid);
asus->dsts_id = ASUS_WMI_METHODID_DSTS;
- else
- asus->dsts_id = ASUS_WMI_METHODID_DSTS2;
+ }
+
+ /*
+ * Some devices can have multiple event codes stored in a queue before
+ * the module load if it was unloaded intermittently after calling
+ * the INIT method (enables event handling). The WMI notify handler is
+ * expected to retrieve all event codes until a retrieved code equals
+ * queue end marker (One or Ones). Old codes are flushed from the queue
+ * upon module load. Not enabling this when it should be has minimal
+ * visible impact so fall back if anything goes wrong.
+ */
+ wmi_uid = wmi_get_acpi_device_uid(asus->driver->event_guid);
+ if (wmi_uid && !strcmp(wmi_uid, ASUS_ACPI_UID_ATK)) {
+ dev_info(dev, "Detected ATK, enable event queue\n");
+
+ if (!asus_wmi_notify_queue_flush(asus))
+ asus->wmi_event_queue = true;
+ }
/* CWAP allow to define the behavior of the Fn+F2 key,
* this method doesn't seems to be present on Eee PCs */
@@ -1894,17 +2163,11 @@ static int asus_wmi_platform_init(struct asus_wmi *asus)
asus_wmi_set_devstate(ASUS_WMI_DEVID_CWAP,
asus->driver->quirks->wapf, NULL);
- return asus_wmi_sysfs_init(asus->platform_device);
+ return 0;
}
-static void asus_wmi_platform_exit(struct asus_wmi *asus)
-{
- asus_wmi_sysfs_exit(asus->platform_device);
-}
+/* debugfs ********************************************************************/
-/*
- * debugfs
- */
struct asus_wmi_debugfs_node {
struct asus_wmi *asus;
char *name;
@@ -2005,74 +2268,33 @@ static void asus_wmi_debugfs_exit(struct asus_wmi *asus)
debugfs_remove_recursive(asus->debug.root);
}
-static int asus_wmi_debugfs_init(struct asus_wmi *asus)
+static void asus_wmi_debugfs_init(struct asus_wmi *asus)
{
- struct dentry *dent;
int i;
asus->debug.root = debugfs_create_dir(asus->driver->name, NULL);
- if (!asus->debug.root) {
- pr_err("failed to create debugfs directory\n");
- goto error_debugfs;
- }
- dent = debugfs_create_x32("method_id", S_IRUGO | S_IWUSR,
- asus->debug.root, &asus->debug.method_id);
- if (!dent)
- goto error_debugfs;
+ debugfs_create_x32("method_id", S_IRUGO | S_IWUSR, asus->debug.root,
+ &asus->debug.method_id);
- dent = debugfs_create_x32("dev_id", S_IRUGO | S_IWUSR,
- asus->debug.root, &asus->debug.dev_id);
- if (!dent)
- goto error_debugfs;
+ debugfs_create_x32("dev_id", S_IRUGO | S_IWUSR, asus->debug.root,
+ &asus->debug.dev_id);
- dent = debugfs_create_x32("ctrl_param", S_IRUGO | S_IWUSR,
- asus->debug.root, &asus->debug.ctrl_param);
- if (!dent)
- goto error_debugfs;
+ debugfs_create_x32("ctrl_param", S_IRUGO | S_IWUSR, asus->debug.root,
+ &asus->debug.ctrl_param);
for (i = 0; i < ARRAY_SIZE(asus_wmi_debug_files); i++) {
struct asus_wmi_debugfs_node *node = &asus_wmi_debug_files[i];
node->asus = asus;
- dent = debugfs_create_file(node->name, S_IFREG | S_IRUGO,
- asus->debug.root, node,
- &asus_wmi_debugfs_io_ops);
- if (!dent) {
- pr_err("failed to create debug file: %s\n", node->name);
- goto error_debugfs;
- }
+ debugfs_create_file(node->name, S_IFREG | S_IRUGO,
+ asus->debug.root, node,
+ &asus_wmi_debugfs_io_ops);
}
-
- return 0;
-
-error_debugfs:
- asus_wmi_debugfs_exit(asus);
- return -ENOMEM;
}
-static int asus_wmi_fan_init(struct asus_wmi *asus)
-{
- int status;
-
- asus->asus_hwmon_pwm = -1;
- asus->asus_hwmon_num_fans = -1;
- asus->asus_hwmon_fan_manual_mode = false;
-
- status = asus_hwmon_get_fan_number(asus, &asus->asus_hwmon_num_fans);
- if (status) {
- asus->asus_hwmon_num_fans = 0;
- pr_warn("Could not determine number of fans: %d\n", status);
- return -ENXIO;
- }
-
- pr_info("Number of fans: %d\n", asus->asus_hwmon_num_fans);
- return 0;
-}
+/* Init / exit ****************************************************************/
-/*
- * WMI Driver
- */
static int asus_wmi_add(struct platform_device *pdev)
{
struct platform_driver *pdrv = to_platform_driver(pdev->dev.driver);
@@ -2099,6 +2321,14 @@ static int asus_wmi_add(struct platform_device *pdev)
if (err)
goto fail_platform;
+ err = fan_boost_mode_check_present(asus);
+ if (err)
+ goto fail_fan_boost_mode;
+
+ err = asus_wmi_sysfs_init(asus->platform_device);
+ if (err)
+ goto fail_sysfs;
+
err = asus_wmi_input_init(asus);
if (err)
goto fail_input;
@@ -2162,14 +2392,10 @@ static int asus_wmi_add(struct platform_device *pdev)
goto fail_wmi_handler;
}
- err = asus_wmi_debugfs_init(asus);
- if (err)
- goto fail_debugfs;
+ asus_wmi_debugfs_init(asus);
return 0;
-fail_debugfs:
- wmi_remove_notify_handler(asus->driver->event_guid);
fail_wmi_handler:
asus_wmi_backlight_exit(asus);
fail_backlight:
@@ -2180,7 +2406,9 @@ fail_leds:
fail_hwmon:
asus_wmi_input_exit(asus);
fail_input:
- asus_wmi_platform_exit(asus);
+ asus_wmi_sysfs_exit(asus->platform_device);
+fail_sysfs:
+fail_fan_boost_mode:
fail_platform:
kfree(asus);
return err;
@@ -2197,16 +2425,15 @@ static int asus_wmi_remove(struct platform_device *device)
asus_wmi_led_exit(asus);
asus_wmi_rfkill_exit(asus);
asus_wmi_debugfs_exit(asus);
- asus_wmi_platform_exit(asus);
+ asus_wmi_sysfs_exit(asus->platform_device);
asus_hwmon_fan_set_auto(asus);
kfree(asus);
return 0;
}
-/*
- * Platform driver - hibernate/resume callbacks
- */
+/* Platform driver - hibernate/resume callbacks *******************************/
+
static int asus_hotk_thaw(struct device *device)
{
struct asus_wmi *asus = dev_get_drvdata(device);
@@ -2282,6 +2509,8 @@ static const struct dev_pm_ops asus_pm_ops = {
.resume = asus_hotk_resume,
};
+/* Registration ***************************************************************/
+
static int asus_wmi_probe(struct platform_device *pdev)
{
struct platform_driver *pdrv = to_platform_driver(pdev->dev.driver);
diff --git a/drivers/platform/x86/dcdbas.c b/drivers/platform/x86/dcdbas.c
index 12cf9475ac85..84f4cc839cc3 100644
--- a/drivers/platform/x86/dcdbas.c
+++ b/drivers/platform/x86/dcdbas.c
@@ -7,7 +7,7 @@
* and Host Control Actions (power cycle or power off after OS shutdown) on
* Dell systems.
*
- * See Documentation/dcdbas.txt for more information.
+ * See Documentation/driver-api/dcdbas.rst for more information.
*
* Copyright (C) 1995-2006 Dell Inc.
*/
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
index a561f653cf13..d27be2836bc2 100644
--- a/drivers/platform/x86/dell-laptop.c
+++ b/drivers/platform/x86/dell-laptop.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for Dell laptop extras
*
@@ -7,10 +8,6 @@
*
* Based on documentation in the libsmbios package:
* Copyright (C) 2005-2014 Dell 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -2176,9 +2173,8 @@ static int __init dell_init(void)
kbd_led_init(&platform_device->dev);
dell_laptop_dir = debugfs_create_dir("dell_laptop", NULL);
- if (dell_laptop_dir != NULL)
- debugfs_create_file("rfkill", 0444, dell_laptop_dir, NULL,
- &dell_debugfs_fops);
+ debugfs_create_file("rfkill", 0444, dell_laptop_dir, NULL,
+ &dell_debugfs_fops);
dell_laptop_register_notifier(&dell_laptop_notifier);
diff --git a/drivers/platform/x86/dell-smbios-base.c b/drivers/platform/x86/dell-smbios-base.c
index 0537d44d45a6..fe59b0ebff31 100644
--- a/drivers/platform/x86/dell-smbios-base.c
+++ b/drivers/platform/x86/dell-smbios-base.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Common functions for kernel modules using Dell SMBIOS
*
@@ -7,10 +8,6 @@
*
* Based on documentation in the libsmbios package:
* Copyright (C) 2005-2014 Dell 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/platform/x86/dell-smbios-smm.c b/drivers/platform/x86/dell-smbios-smm.c
index ab9b822a6dfe..d6854d1c4119 100644
--- a/drivers/platform/x86/dell-smbios-smm.c
+++ b/drivers/platform/x86/dell-smbios-smm.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* SMI methods for use with dell-smbios
*
@@ -5,10 +6,6 @@
* Copyright (c) 2014 Gabriele Mazzotta <gabriele.mzt@gmail.com>
* Copyright (c) 2014 Pali Rohár <pali.rohar@gmail.com>
* Copyright (c) 2017 Dell 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/platform/x86/dell-smbios-wmi.c b/drivers/platform/x86/dell-smbios-wmi.c
index c3ed3c8c17b9..27a298b7c541 100644
--- a/drivers/platform/x86/dell-smbios-wmi.c
+++ b/drivers/platform/x86/dell-smbios-wmi.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* WMI methods for use with dell-smbios
*
* Copyright (c) 2017 Dell 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -146,7 +143,7 @@ fail_smbios_cmd:
return ret;
}
-static int dell_smbios_wmi_probe(struct wmi_device *wdev)
+static int dell_smbios_wmi_probe(struct wmi_device *wdev, const void *context)
{
struct wmi_driver *wdriver =
container_of(wdev->dev.driver, struct wmi_driver, driver);
diff --git a/drivers/platform/x86/dell-smbios.h b/drivers/platform/x86/dell-smbios.h
index d8adaf959740..a7ff9803f41a 100644
--- a/drivers/platform/x86/dell-smbios.h
+++ b/drivers/platform/x86/dell-smbios.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Common functions for kernel modules using Dell SMBIOS
*
@@ -7,10 +8,6 @@
*
* Based on documentation in the libsmbios package:
* Copyright (C) 2005-2014 Dell 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.
*/
#ifndef _DELL_SMBIOS_H_
diff --git a/drivers/platform/x86/dell-smo8800.c b/drivers/platform/x86/dell-smo8800.c
index 5cdb09cba077..bfcc1d1b9b96 100644
--- a/drivers/platform/x86/dell-smo8800.c
+++ b/drivers/platform/x86/dell-smo8800.c
@@ -198,6 +198,7 @@ static int smo8800_remove(struct acpi_device *device)
return 0;
}
+/* NOTE: Keep this list in sync with drivers/i2c/busses/i2c-i801.c */
static const struct acpi_device_id smo8800_ids[] = {
{ "SMO8800", 0 },
{ "SMO8801", 0 },
diff --git a/drivers/platform/x86/dell-wmi-descriptor.c b/drivers/platform/x86/dell-wmi-descriptor.c
index f0df49e3f8c9..a068900ae8a1 100644
--- a/drivers/platform/x86/dell-wmi-descriptor.c
+++ b/drivers/platform/x86/dell-wmi-descriptor.c
@@ -98,7 +98,8 @@ EXPORT_SYMBOL_GPL(dell_wmi_get_hotfix);
* WMI buffer length 12 4 <length>
* WMI hotfix number 16 4 <hotfix>
*/
-static int dell_wmi_descriptor_probe(struct wmi_device *wdev)
+static int dell_wmi_descriptor_probe(struct wmi_device *wdev,
+ const void *context)
{
union acpi_object *obj = NULL;
struct descriptor_priv *priv;
diff --git a/drivers/platform/x86/dell-wmi-descriptor.h b/drivers/platform/x86/dell-wmi-descriptor.h
index a6123a4d06a7..1f469fef1535 100644
--- a/drivers/platform/x86/dell-wmi-descriptor.h
+++ b/drivers/platform/x86/dell-wmi-descriptor.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Dell WMI descriptor driver
*
* Copyright (c) 2017 Dell 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.
*/
#ifndef _DELL_WMI_DESCRIPTOR_H_
diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c
index 1f565fb69098..acc653f9c16f 100644
--- a/drivers/platform/x86/dell-wmi.c
+++ b/drivers/platform/x86/dell-wmi.c
@@ -659,7 +659,7 @@ static int dell_wmi_events_set_enabled(bool enable)
return dell_smbios_error(ret);
}
-static int dell_wmi_probe(struct wmi_device *wdev)
+static int dell_wmi_probe(struct wmi_device *wdev, const void *context)
{
struct dell_wmi_priv *priv;
int ret;
diff --git a/drivers/platform/x86/dell_rbu.c b/drivers/platform/x86/dell_rbu.c
index a58fc10293ee..3691391fea6b 100644
--- a/drivers/platform/x86/dell_rbu.c
+++ b/drivers/platform/x86/dell_rbu.c
@@ -24,7 +24,7 @@
* on every time the packet data is written. This driver requires an
* application to break the BIOS image in to fixed sized packet chunks.
*
- * See Documentation/dell_rbu.txt for more info.
+ * See Documentation/driver-api/dell_rbu.rst for more info.
*/
#include <linux/init.h>
#include <linux/module.h>
diff --git a/drivers/platform/x86/hp_accel.c b/drivers/platform/x86/hp_accel.c
index f61b8a176e20..7a2747455237 100644
--- a/drivers/platform/x86/hp_accel.c
+++ b/drivers/platform/x86/hp_accel.c
@@ -229,6 +229,7 @@ static const struct dmi_system_id lis3lv02d_dmi_ids[] = {
AXIS_DMI_MATCH("HPB440G3", "HP ProBook 440 G3", x_inverted_usd),
AXIS_DMI_MATCH("HPB440G4", "HP ProBook 440 G4", x_inverted),
AXIS_DMI_MATCH("HPB442x", "HP ProBook 442", xy_rotated_left),
+ AXIS_DMI_MATCH("HPB450G0", "HP ProBook 450 G0", x_inverted),
AXIS_DMI_MATCH("HPB452x", "HP ProBook 452", y_inverted),
AXIS_DMI_MATCH("HPB522x", "HP ProBook 522", xy_swap),
AXIS_DMI_MATCH("HPB532x", "HP ProBook 532", y_inverted),
diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c
index 52fcac5b393a..195a7f3638cb 100644
--- a/drivers/platform/x86/huawei-wmi.c
+++ b/drivers/platform/x86/huawei-wmi.c
@@ -166,7 +166,7 @@ static int huawei_wmi_input_setup(struct wmi_device *wdev)
return input_register_device(priv->idev);
}
-static int huawei_wmi_probe(struct wmi_device *wdev)
+static int huawei_wmi_probe(struct wmi_device *wdev, const void *context)
{
struct huawei_wmi_priv *priv;
int err;
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
index 5fb9bfdf1019..7598cd46cf60 100644
--- a/drivers/platform/x86/ideapad-laptop.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -316,34 +316,15 @@ static int debugfs_cfg_show(struct seq_file *s, void *data)
}
DEFINE_SHOW_ATTRIBUTE(debugfs_cfg);
-static int ideapad_debugfs_init(struct ideapad_private *priv)
+static void ideapad_debugfs_init(struct ideapad_private *priv)
{
- struct dentry *node;
+ struct dentry *dir;
- priv->debug = debugfs_create_dir("ideapad", NULL);
- if (priv->debug == NULL) {
- pr_err("failed to create debugfs directory");
- goto errout;
- }
-
- node = debugfs_create_file("cfg", S_IRUGO, priv->debug, priv,
- &debugfs_cfg_fops);
- if (!node) {
- pr_err("failed to create cfg in debugfs");
- goto errout;
- }
-
- node = debugfs_create_file("status", S_IRUGO, priv->debug, priv,
- &debugfs_status_fops);
- if (!node) {
- pr_err("failed to create status in debugfs");
- goto errout;
- }
-
- return 0;
+ dir = debugfs_create_dir("ideapad", NULL);
+ priv->debug = dir;
-errout:
- return -ENOMEM;
+ debugfs_create_file("cfg", S_IRUGO, dir, priv, &debugfs_cfg_fops);
+ debugfs_create_file("status", S_IRUGO, dir, priv, &debugfs_status_fops);
}
static void ideapad_debugfs_exit(struct ideapad_private *priv)
@@ -1012,9 +993,7 @@ static int ideapad_acpi_add(struct platform_device *pdev)
if (ret)
return ret;
- ret = ideapad_debugfs_init(priv);
- if (ret)
- goto debugfs_failed;
+ ideapad_debugfs_init(priv);
ret = ideapad_input_init(priv);
if (ret)
@@ -1071,7 +1050,6 @@ backlight_failed:
ideapad_input_exit(priv);
input_failed:
ideapad_debugfs_exit(priv);
-debugfs_failed:
ideapad_sysfs_exit(priv);
return ret;
}
diff --git a/drivers/platform/x86/intel-wmi-thunderbolt.c b/drivers/platform/x86/intel-wmi-thunderbolt.c
index 4dfa61434a76..974c22a7ff61 100644
--- a/drivers/platform/x86/intel-wmi-thunderbolt.c
+++ b/drivers/platform/x86/intel-wmi-thunderbolt.c
@@ -56,7 +56,8 @@ static const struct attribute_group tbt_attribute_group = {
.attrs = tbt_attrs,
};
-static int intel_wmi_thunderbolt_probe(struct wmi_device *wdev)
+static int intel_wmi_thunderbolt_probe(struct wmi_device *wdev,
+ const void *context)
{
int ret;
diff --git a/drivers/platform/x86/intel_cht_int33fe.c b/drivers/platform/x86/intel_cht_int33fe.c
index 6fa3cced6f8e..4fbdff48a4b5 100644
--- a/drivers/platform/x86/intel_cht_int33fe.c
+++ b/drivers/platform/x86/intel_cht_int33fe.c
@@ -21,18 +21,55 @@
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/module.h>
+#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
+#include <linux/usb/pd.h>
#define EXPECTED_PTYPE 4
+enum {
+ INT33FE_NODE_FUSB302,
+ INT33FE_NODE_MAX17047,
+ INT33FE_NODE_PI3USB30532,
+ INT33FE_NODE_DISPLAYPORT,
+ INT33FE_NODE_ROLE_SWITCH,
+ INT33FE_NODE_USB_CONNECTOR,
+ INT33FE_NODE_MAX,
+};
+
struct cht_int33fe_data {
struct i2c_client *max17047;
struct i2c_client *fusb302;
struct i2c_client *pi3usb30532;
- /* Contain a list-head must be per device */
- struct device_connection connections[4];
+
+ struct fwnode_handle *dp;
+ struct fwnode_handle *mux;
+};
+
+static const struct software_node nodes[];
+
+static const struct software_node_ref_args pi3usb30532_ref = {
+ &nodes[INT33FE_NODE_PI3USB30532]
+};
+
+static const struct software_node_ref_args dp_ref = {
+ &nodes[INT33FE_NODE_DISPLAYPORT]
+};
+
+static struct software_node_ref_args mux_ref;
+
+static const struct software_node_reference usb_connector_refs[] = {
+ { "orientation-switch", 1, &pi3usb30532_ref},
+ { "mode-switch", 1, &pi3usb30532_ref},
+ { "displayport", 1, &dp_ref},
+ { }
+};
+
+static const struct software_node_reference fusb302_refs[] = {
+ { "usb-role-switch", 1, &mux_ref},
+ { }
};
/*
@@ -63,14 +100,6 @@ static int cht_int33fe_check_for_max17047(struct device *dev, void *data)
return 1;
}
-static struct i2c_client *cht_int33fe_find_max17047(void)
-{
- struct i2c_client *max17047 = NULL;
-
- i2c_for_each_dev(&max17047, cht_int33fe_check_for_max17047);
- return max17047;
-}
-
static const char * const max17047_suppliers[] = { "bq24190-charger" };
static const struct property_entry max17047_props[] = {
@@ -80,18 +109,196 @@ static const struct property_entry max17047_props[] = {
static const struct property_entry fusb302_props[] = {
PROPERTY_ENTRY_STRING("linux,extcon-name", "cht_wcove_pwrsrc"),
- PROPERTY_ENTRY_U32("fcs,max-sink-microvolt", 12000000),
- PROPERTY_ENTRY_U32("fcs,max-sink-microamp", 3000000),
- PROPERTY_ENTRY_U32("fcs,max-sink-microwatt", 36000000),
{ }
};
+#define PDO_FIXED_FLAGS \
+ (PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP | PDO_FIXED_USB_COMM)
+
+static const u32 src_pdo[] = {
+ PDO_FIXED(5000, 1500, PDO_FIXED_FLAGS),
+};
+
+static const u32 snk_pdo[] = {
+ PDO_FIXED(5000, 400, PDO_FIXED_FLAGS),
+ PDO_VAR(5000, 12000, 3000),
+};
+
+static const struct property_entry usb_connector_props[] = {
+ PROPERTY_ENTRY_STRING("data-role", "dual"),
+ PROPERTY_ENTRY_STRING("power-role", "dual"),
+ PROPERTY_ENTRY_STRING("try-power-role", "sink"),
+ PROPERTY_ENTRY_U32_ARRAY("source-pdos", src_pdo),
+ PROPERTY_ENTRY_U32_ARRAY("sink-pdos", snk_pdo),
+ PROPERTY_ENTRY_U32("op-sink-microwatt", 2500000),
+ { }
+};
+
+static const struct software_node nodes[] = {
+ { "fusb302", NULL, fusb302_props, fusb302_refs },
+ { "max17047", NULL, max17047_props },
+ { "pi3usb30532" },
+ { "displayport" },
+ { "usb-role-switch" },
+ { "connector", &nodes[0], usb_connector_props, usb_connector_refs },
+ { }
+};
+
+static int cht_int33fe_setup_mux(struct cht_int33fe_data *data)
+{
+ struct fwnode_handle *fwnode;
+ struct device *dev;
+ struct device *p;
+
+ fwnode = software_node_fwnode(&nodes[INT33FE_NODE_ROLE_SWITCH]);
+ if (!fwnode)
+ return -ENODEV;
+
+ /* First finding the platform device */
+ p = bus_find_device_by_name(&platform_bus_type, NULL,
+ "intel_xhci_usb_sw");
+ if (!p)
+ return -EPROBE_DEFER;
+
+ /* Then the mux child device */
+ dev = device_find_child_by_name(p, "intel_xhci_usb_sw-role-switch");
+ put_device(p);
+ if (!dev)
+ return -EPROBE_DEFER;
+
+ /* If there already is a node for the mux, using that one. */
+ if (dev->fwnode)
+ fwnode_remove_software_node(fwnode);
+ else
+ dev->fwnode = fwnode;
+
+ data->mux = fwnode_handle_get(dev->fwnode);
+ put_device(dev);
+ mux_ref.node = to_software_node(data->mux);
+
+ return 0;
+}
+
+static int cht_int33fe_setup_dp(struct cht_int33fe_data *data)
+{
+ struct fwnode_handle *fwnode;
+ struct pci_dev *pdev;
+
+ fwnode = software_node_fwnode(&nodes[INT33FE_NODE_DISPLAYPORT]);
+ if (!fwnode)
+ return -ENODEV;
+
+ /* First let's find the GPU PCI device */
+ pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, NULL);
+ if (!pdev || pdev->vendor != PCI_VENDOR_ID_INTEL) {
+ pci_dev_put(pdev);
+ return -ENODEV;
+ }
+
+ /* Then the DP child device node */
+ data->dp = device_get_named_child_node(&pdev->dev, "DD02");
+ pci_dev_put(pdev);
+ if (!data->dp)
+ return -ENODEV;
+
+ fwnode->secondary = ERR_PTR(-ENODEV);
+ data->dp->secondary = fwnode;
+
+ return 0;
+}
+
+static void cht_int33fe_remove_nodes(struct cht_int33fe_data *data)
+{
+ software_node_unregister_nodes(nodes);
+
+ if (data->mux) {
+ fwnode_handle_put(data->mux);
+ mux_ref.node = NULL;
+ data->mux = NULL;
+ }
+
+ if (data->dp) {
+ data->dp->secondary = NULL;
+ fwnode_handle_put(data->dp);
+ data->dp = NULL;
+ }
+}
+
+static int cht_int33fe_add_nodes(struct cht_int33fe_data *data)
+{
+ int ret;
+
+ ret = software_node_register_nodes(nodes);
+ if (ret)
+ return ret;
+
+ /* The devices that are not created in this driver need extra steps. */
+
+ /*
+ * There is no ACPI device node for the USB role mux, so we need to find
+ * the mux device and assign our node directly to it. That means we
+ * depend on the mux driver. This function will return -PROBE_DEFER
+ * until the mux device is registered.
+ */
+ ret = cht_int33fe_setup_mux(data);
+ if (ret)
+ goto err_remove_nodes;
+
+ /*
+ * The DP connector does have ACPI device node. In this case we can just
+ * find that ACPI node and assign our node as the secondary node to it.
+ */
+ ret = cht_int33fe_setup_dp(data);
+ if (ret)
+ goto err_remove_nodes;
+
+ return 0;
+
+err_remove_nodes:
+ cht_int33fe_remove_nodes(data);
+
+ return ret;
+}
+
+static int
+cht_int33fe_register_max17047(struct device *dev, struct cht_int33fe_data *data)
+{
+ struct i2c_client *max17047 = NULL;
+ struct i2c_board_info board_info;
+ struct fwnode_handle *fwnode;
+ int ret;
+
+ fwnode = software_node_fwnode(&nodes[INT33FE_NODE_MAX17047]);
+ if (!fwnode)
+ return -ENODEV;
+
+ i2c_for_each_dev(&max17047, cht_int33fe_check_for_max17047);
+ if (max17047) {
+ /* Pre-existing i2c-client for the max17047, add device-props */
+ fwnode->secondary = ERR_PTR(-ENODEV);
+ max17047->dev.fwnode->secondary = fwnode;
+ /* And re-probe to get the new device-props applied. */
+ ret = device_reprobe(&max17047->dev);
+ if (ret)
+ dev_warn(dev, "Reprobing max17047 error: %d\n", ret);
+ return 0;
+ }
+
+ memset(&board_info, 0, sizeof(board_info));
+ strlcpy(board_info.type, "max17047", I2C_NAME_SIZE);
+ board_info.dev_name = "max17047";
+ board_info.fwnode = fwnode;
+ data->max17047 = i2c_acpi_new_device(dev, 1, &board_info);
+
+ return PTR_ERR_OR_ZERO(data->max17047);
+}
+
static int cht_int33fe_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct i2c_board_info board_info;
struct cht_int33fe_data *data;
- struct i2c_client *max17047;
+ struct fwnode_handle *fwnode;
struct regulator *regulator;
unsigned long long ptyp;
acpi_status status;
@@ -151,43 +358,25 @@ static int cht_int33fe_probe(struct platform_device *pdev)
if (!data)
return -ENOMEM;
- /* Work around BIOS bug, see comment on cht_int33fe_find_max17047 */
- max17047 = cht_int33fe_find_max17047();
- if (max17047) {
- /* Pre-existing i2c-client for the max17047, add device-props */
- ret = device_add_properties(&max17047->dev, max17047_props);
- if (ret)
- return ret;
- /* And re-probe to get the new device-props applied. */
- ret = device_reprobe(&max17047->dev);
- if (ret)
- dev_warn(dev, "Reprobing max17047 error: %d\n", ret);
- } else {
- memset(&board_info, 0, sizeof(board_info));
- strlcpy(board_info.type, "max17047", I2C_NAME_SIZE);
- board_info.dev_name = "max17047";
- board_info.properties = max17047_props;
- data->max17047 = i2c_acpi_new_device(dev, 1, &board_info);
- if (IS_ERR(data->max17047))
- return PTR_ERR(data->max17047);
- }
+ ret = cht_int33fe_add_nodes(data);
+ if (ret)
+ return ret;
- data->connections[0].endpoint[0] = "port0";
- data->connections[0].endpoint[1] = "i2c-pi3usb30532";
- data->connections[0].id = "orientation-switch";
- data->connections[1].endpoint[0] = "port0";
- data->connections[1].endpoint[1] = "i2c-pi3usb30532";
- data->connections[1].id = "mode-switch";
- data->connections[2].endpoint[0] = "i2c-fusb302";
- data->connections[2].endpoint[1] = "intel_xhci_usb_sw-role-switch";
- data->connections[2].id = "usb-role-switch";
+ /* Work around BIOS bug, see comment on cht_int33fe_check_for_max17047 */
+ ret = cht_int33fe_register_max17047(dev, data);
+ if (ret)
+ goto out_remove_nodes;
- device_connections_add(data->connections);
+ fwnode = software_node_fwnode(&nodes[INT33FE_NODE_FUSB302]);
+ if (!fwnode) {
+ ret = -ENODEV;
+ goto out_unregister_max17047;
+ }
memset(&board_info, 0, sizeof(board_info));
strlcpy(board_info.type, "typec_fusb302", I2C_NAME_SIZE);
board_info.dev_name = "fusb302";
- board_info.properties = fusb302_props;
+ board_info.fwnode = fwnode;
board_info.irq = fusb302_irq;
data->fusb302 = i2c_acpi_new_device(dev, 2, &board_info);
@@ -196,8 +385,15 @@ static int cht_int33fe_probe(struct platform_device *pdev)
goto out_unregister_max17047;
}
+ fwnode = software_node_fwnode(&nodes[INT33FE_NODE_PI3USB30532]);
+ if (!fwnode) {
+ ret = -ENODEV;
+ goto out_unregister_fusb302;
+ }
+
memset(&board_info, 0, sizeof(board_info));
board_info.dev_name = "pi3usb30532";
+ board_info.fwnode = fwnode;
strlcpy(board_info.type, "pi3usb30532", I2C_NAME_SIZE);
data->pi3usb30532 = i2c_acpi_new_device(dev, 3, &board_info);
@@ -216,7 +412,8 @@ out_unregister_fusb302:
out_unregister_max17047:
i2c_unregister_device(data->max17047);
- device_connections_remove(data->connections);
+out_remove_nodes:
+ cht_int33fe_remove_nodes(data);
return ret;
}
@@ -229,7 +426,7 @@ static int cht_int33fe_remove(struct platform_device *pdev)
i2c_unregister_device(data->fusb302);
i2c_unregister_device(data->max17047);
- device_connections_remove(data->connections);
+ cht_int33fe_remove_nodes(data);
return 0;
}
diff --git a/drivers/platform/x86/intel_int0002_vgpio.c b/drivers/platform/x86/intel_int0002_vgpio.c
index 1694a9aec77c..d9542c661ddc 100644
--- a/drivers/platform/x86/intel_int0002_vgpio.c
+++ b/drivers/platform/x86/intel_int0002_vgpio.c
@@ -51,17 +51,6 @@
#define GPE0A_STS_PORT 0x420
#define GPE0A_EN_PORT 0x428
-#define BAYTRAIL 0x01
-#define CHERRYTRAIL 0x02
-
-#define ICPU(model, data) { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, data }
-
-static const struct x86_cpu_id int0002_cpu_ids[] = {
- ICPU(INTEL_FAM6_ATOM_SILVERMONT, BAYTRAIL), /* Valleyview, Bay Trail */
- ICPU(INTEL_FAM6_ATOM_AIRMONT, CHERRYTRAIL), /* Braswell, Cherry Trail */
- {}
-};
-
/*
* As this is not a real GPIO at all, but just a hack to model an event in
* ACPI the get / set functions are dummy functions.
@@ -157,6 +146,12 @@ static struct irq_chip int0002_cht_irqchip = {
*/
};
+static const struct x86_cpu_id int0002_cpu_ids[] = {
+ INTEL_CPU_FAM6(ATOM_SILVERMONT, int0002_byt_irqchip), /* Valleyview, Bay Trail */
+ INTEL_CPU_FAM6(ATOM_AIRMONT, int0002_cht_irqchip), /* Braswell, Cherry Trail */
+ {}
+};
+
static int int0002_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -210,10 +205,7 @@ static int int0002_probe(struct platform_device *pdev)
return ret;
}
- if (cpu_id->driver_data == BAYTRAIL)
- irq_chip = &int0002_byt_irqchip;
- else
- irq_chip = &int0002_cht_irqchip;
+ irq_chip = (struct irq_chip *)cpu_id->driver_data;
ret = gpiochip_irqchip_add(chip, irq_chip, 0, handle_edge_irq,
IRQ_TYPE_NONE);
diff --git a/drivers/platform/x86/intel_menlow.c b/drivers/platform/x86/intel_menlow.c
index 77eb8709c931..b102f6dd5693 100644
--- a/drivers/platform/x86/intel_menlow.c
+++ b/drivers/platform/x86/intel_menlow.c
@@ -180,9 +180,13 @@ static int intel_menlow_memory_add(struct acpi_device *device)
static int intel_menlow_memory_remove(struct acpi_device *device)
{
- struct thermal_cooling_device *cdev = acpi_driver_data(device);
+ struct thermal_cooling_device *cdev;
+
+ if (!device)
+ return -EINVAL;
- if (!device || !cdev)
+ cdev = acpi_driver_data(device);
+ if (!cdev)
return -EINVAL;
sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c
index 1d902230ba61..235c0b89f824 100644
--- a/drivers/platform/x86/intel_pmc_core.c
+++ b/drivers/platform/x86/intel_pmc_core.c
@@ -26,6 +26,7 @@
#include <asm/cpu_device_id.h>
#include <asm/intel-family.h>
#include <asm/msr.h>
+#include <asm/tsc.h>
#include "intel_pmc_core.h"
@@ -740,7 +741,9 @@ static int pmc_core_pkgc_show(struct seq_file *s, void *unused)
if (rdmsrl_safe(map[index].bit_mask, &pcstate_count))
continue;
- seq_printf(s, "%-8s : 0x%llx\n", map[index].name,
+ pcstate_count *= 1000;
+ do_div(pcstate_count, tsc_khz);
+ seq_printf(s, "%-8s : %llu\n", map[index].name,
pcstate_count);
}
@@ -753,14 +756,11 @@ static void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev)
debugfs_remove_recursive(pmcdev->dbgfs_dir);
}
-static int pmc_core_dbgfs_register(struct pmc_dev *pmcdev)
+static void pmc_core_dbgfs_register(struct pmc_dev *pmcdev)
{
struct dentry *dir;
dir = debugfs_create_dir("pmc_core", NULL);
- if (!dir)
- return -ENOMEM;
-
pmcdev->dbgfs_dir = dir;
debugfs_create_file("slp_s0_residency_usec", 0444, dir, pmcdev,
@@ -794,13 +794,10 @@ static int pmc_core_dbgfs_register(struct pmc_dev *pmcdev)
debugfs_create_bool("slp_s0_dbg_latch", 0644,
dir, &slps0_dbg_latch);
}
-
- return 0;
}
#else
-static inline int pmc_core_dbgfs_register(struct pmc_dev *pmcdev)
+static inline void pmc_core_dbgfs_register(struct pmc_dev *pmcdev)
{
- return 0;
}
static inline void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev)
@@ -862,7 +859,6 @@ static int pmc_core_probe(struct platform_device *pdev)
struct pmc_dev *pmcdev = &pmc;
const struct x86_cpu_id *cpu_id;
u64 slp_s0_addr;
- int err;
if (device_initialized)
return -ENODEV;
@@ -896,12 +892,7 @@ static int pmc_core_probe(struct platform_device *pdev)
pmcdev->pmc_xram_read_bit = pmc_core_check_read_lock_bit();
dmi_check_system(pmc_core_dmi_table);
- err = pmc_core_dbgfs_register(pmcdev);
- if (err < 0) {
- dev_warn(&pdev->dev, "debugfs register failed.\n");
- iounmap(pmcdev->regbase);
- return err;
- }
+ pmc_core_dbgfs_register(pmcdev);
device_initialized = true;
dev_info(&pdev->dev, " initialized\n");
@@ -1023,47 +1014,23 @@ static const struct dev_pm_ops pmc_core_pm_ops = {
SET_LATE_SYSTEM_SLEEP_PM_OPS(pmc_core_suspend, pmc_core_resume)
};
+static const struct acpi_device_id pmc_core_acpi_ids[] = {
+ {"INT33A1", 0}, /* _HID for Intel Power Engine, _CID PNP0D80*/
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, pmc_core_acpi_ids);
+
static struct platform_driver pmc_core_driver = {
.driver = {
.name = "intel_pmc_core",
+ .acpi_match_table = ACPI_PTR(pmc_core_acpi_ids),
.pm = &pmc_core_pm_ops,
},
.probe = pmc_core_probe,
.remove = pmc_core_remove,
};
-static struct platform_device pmc_core_device = {
- .name = "intel_pmc_core",
-};
-
-static int __init pmc_core_init(void)
-{
- int ret;
-
- if (!x86_match_cpu(intel_pmc_core_ids))
- return -ENODEV;
-
- ret = platform_driver_register(&pmc_core_driver);
- if (ret)
- return ret;
-
- ret = platform_device_register(&pmc_core_device);
- if (ret) {
- platform_driver_unregister(&pmc_core_driver);
- return ret;
- }
-
- return 0;
-}
-
-static void __exit pmc_core_exit(void)
-{
- platform_device_unregister(&pmc_core_device);
- platform_driver_unregister(&pmc_core_driver);
-}
-
-module_init(pmc_core_init)
-module_exit(pmc_core_exit)
+module_platform_driver(pmc_core_driver);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Intel PMC Core Driver");
diff --git a/drivers/platform/x86/intel_pmc_core_pltdrv.c b/drivers/platform/x86/intel_pmc_core_pltdrv.c
new file mode 100644
index 000000000000..a8754a6db1b8
--- /dev/null
+++ b/drivers/platform/x86/intel_pmc_core_pltdrv.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Intel PMC Core platform init
+ * Copyright (c) 2019, Google Inc.
+ * Author - Rajat Jain
+ *
+ * This code instantiates platform devices for intel_pmc_core driver, only
+ * on supported platforms that may not have the ACPI devices in the ACPI tables.
+ * No new platforms should be added here, because we expect that new platforms
+ * should all have the ACPI device, which is the preferred way of enumeration.
+ */
+
+#include <linux/acpi.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/cpu_device_id.h>
+#include <asm/intel-family.h>
+
+static struct platform_device pmc_core_device = {
+ .name = "intel_pmc_core",
+};
+
+/*
+ * intel_pmc_core_platform_ids is the list of platforms where we want to
+ * instantiate the platform_device if not already instantiated. This is
+ * different than intel_pmc_core_ids in intel_pmc_core.c which is the
+ * list of platforms that the driver supports for pmc_core device. The
+ * other list may grow, but this list should not.
+ */
+static const struct x86_cpu_id intel_pmc_core_platform_ids[] = {
+ INTEL_CPU_FAM6(SKYLAKE_MOBILE, pmc_core_device),
+ INTEL_CPU_FAM6(SKYLAKE_DESKTOP, pmc_core_device),
+ INTEL_CPU_FAM6(KABYLAKE_MOBILE, pmc_core_device),
+ INTEL_CPU_FAM6(KABYLAKE_DESKTOP, pmc_core_device),
+ INTEL_CPU_FAM6(CANNONLAKE_MOBILE, pmc_core_device),
+ INTEL_CPU_FAM6(ICELAKE_MOBILE, pmc_core_device),
+ {}
+};
+MODULE_DEVICE_TABLE(x86cpu, intel_pmc_core_platform_ids);
+
+static int __init pmc_core_platform_init(void)
+{
+ /* Skip creating the platform device if ACPI already has a device */
+ if (acpi_dev_present("INT33A1", NULL, -1))
+ return -ENODEV;
+
+ if (!x86_match_cpu(intel_pmc_core_platform_ids))
+ return -ENODEV;
+
+ return platform_device_register(&pmc_core_device);
+}
+
+static void __exit pmc_core_platform_exit(void)
+{
+ platform_device_unregister(&pmc_core_device);
+}
+
+module_init(pmc_core_platform_init);
+module_exit(pmc_core_platform_exit);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/x86/intel_speed_select_if/Kconfig b/drivers/platform/x86/intel_speed_select_if/Kconfig
new file mode 100644
index 000000000000..ce3e3dc076d2
--- /dev/null
+++ b/drivers/platform/x86/intel_speed_select_if/Kconfig
@@ -0,0 +1,17 @@
+menu "Intel Speed Select Technology interface support"
+ depends on PCI
+ depends on X86_64 || COMPILE_TEST
+
+config INTEL_SPEED_SELECT_INTERFACE
+ tristate "Intel(R) Speed Select Technology interface drivers"
+ help
+ This config enables the Intel(R) Speed Select Technology interface
+ drivers. The Intel(R) speed select technology features are non
+ architectural and only supported on specific Xeon(R) servers.
+ These drivers provide interface to directly communicate with hardware
+ via MMIO and Mail boxes to enumerate and control all the speed select
+ features.
+
+ Enable this config, if there is a need to enable and control the
+ Intel(R) Speed Select Technology features from the user space.
+endmenu
diff --git a/drivers/platform/x86/intel_speed_select_if/Makefile b/drivers/platform/x86/intel_speed_select_if/Makefile
new file mode 100644
index 000000000000..856076206f35
--- /dev/null
+++ b/drivers/platform/x86/intel_speed_select_if/Makefile
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile - Intel Speed Select Interface drivers
+# Copyright (c) 2019, Intel Corporation.
+#
+
+obj-$(CONFIG_INTEL_SPEED_SELECT_INTERFACE) += isst_if_common.o
+obj-$(CONFIG_INTEL_SPEED_SELECT_INTERFACE) += isst_if_mmio.o
+obj-$(CONFIG_INTEL_SPEED_SELECT_INTERFACE) += isst_if_mbox_pci.o
+obj-$(CONFIG_INTEL_SPEED_SELECT_INTERFACE) += isst_if_mbox_msr.o
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
new file mode 100644
index 000000000000..68d75391db57
--- /dev/null
+++ b/drivers/platform/x86/intel_speed_select_if/isst_if_common.c
@@ -0,0 +1,672 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel Speed Select Interface: Common functions
+ * Copyright (c) 2019, Intel Corporation.
+ * All rights reserved.
+ *
+ * Author: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
+ */
+
+#include <linux/cpufeature.h>
+#include <linux/cpuhotplug.h>
+#include <linux/fs.h>
+#include <linux/hashtable.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/sched/signal.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <uapi/linux/isst_if.h>
+
+#include "isst_if_common.h"
+
+#define MSR_THREAD_ID_INFO 0x53
+#define MSR_CPU_BUS_NUMBER 0x128
+
+static struct isst_if_cmd_cb punit_callbacks[ISST_IF_DEV_MAX];
+
+static int punit_msr_white_list[] = {
+ MSR_TURBO_RATIO_LIMIT,
+ MSR_CONFIG_TDP_CONTROL,
+};
+
+struct isst_valid_cmd_ranges {
+ u16 cmd;
+ u16 sub_cmd_beg;
+ u16 sub_cmd_end;
+};
+
+struct isst_cmd_set_req_type {
+ u16 cmd;
+ u16 sub_cmd;
+ u16 param;
+};
+
+static const struct isst_valid_cmd_ranges isst_valid_cmds[] = {
+ {0xD0, 0x00, 0x03},
+ {0x7F, 0x00, 0x0B},
+ {0x7F, 0x10, 0x12},
+ {0x7F, 0x20, 0x23},
+};
+
+static const struct isst_cmd_set_req_type isst_cmd_set_reqs[] = {
+ {0xD0, 0x00, 0x08},
+ {0xD0, 0x01, 0x08},
+ {0xD0, 0x02, 0x08},
+ {0xD0, 0x03, 0x08},
+ {0x7F, 0x02, 0x00},
+ {0x7F, 0x08, 0x00},
+};
+
+struct isst_cmd {
+ struct hlist_node hnode;
+ u64 data;
+ u32 cmd;
+ int cpu;
+ int mbox_cmd_type;
+ u32 param;
+};
+
+static DECLARE_HASHTABLE(isst_hash, 8);
+static DEFINE_MUTEX(isst_hash_lock);
+
+static int isst_store_new_cmd(int cmd, u32 cpu, int mbox_cmd_type, u32 param,
+ u32 data)
+{
+ struct isst_cmd *sst_cmd;
+
+ sst_cmd = kmalloc(sizeof(*sst_cmd), GFP_KERNEL);
+ if (!sst_cmd)
+ return -ENOMEM;
+
+ sst_cmd->cpu = cpu;
+ sst_cmd->cmd = cmd;
+ sst_cmd->mbox_cmd_type = mbox_cmd_type;
+ sst_cmd->param = param;
+ sst_cmd->data = data;
+
+ hash_add(isst_hash, &sst_cmd->hnode, sst_cmd->cmd);
+
+ return 0;
+}
+
+static void isst_delete_hash(void)
+{
+ struct isst_cmd *sst_cmd;
+ struct hlist_node *tmp;
+ int i;
+
+ hash_for_each_safe(isst_hash, i, tmp, sst_cmd, hnode) {
+ hash_del(&sst_cmd->hnode);
+ kfree(sst_cmd);
+ }
+}
+
+/**
+ * isst_store_cmd() - Store command to a hash table
+ * @cmd: Mailbox command.
+ * @sub_cmd: Mailbox sub-command or MSR id.
+ * @mbox_cmd_type: Mailbox or MSR command.
+ * @param: Mailbox parameter.
+ * @data: Mailbox request data or MSR data.
+ *
+ * Stores the command to a hash table if there is no such command already
+ * stored. If already stored update the latest parameter and data for the
+ * command.
+ *
+ * Return: Return result of store to hash table, 0 for success, others for
+ * failure.
+ */
+int isst_store_cmd(int cmd, int sub_cmd, u32 cpu, int mbox_cmd_type,
+ u32 param, u64 data)
+{
+ struct isst_cmd *sst_cmd;
+ int full_cmd, ret;
+
+ full_cmd = (cmd & GENMASK_ULL(15, 0)) << 16;
+ full_cmd |= (sub_cmd & GENMASK_ULL(15, 0));
+ mutex_lock(&isst_hash_lock);
+ hash_for_each_possible(isst_hash, sst_cmd, hnode, full_cmd) {
+ if (sst_cmd->cmd == full_cmd && sst_cmd->cpu == cpu &&
+ sst_cmd->mbox_cmd_type == mbox_cmd_type) {
+ sst_cmd->param = param;
+ sst_cmd->data = data;
+ mutex_unlock(&isst_hash_lock);
+ return 0;
+ }
+ }
+
+ ret = isst_store_new_cmd(full_cmd, cpu, mbox_cmd_type, param, data);
+ mutex_unlock(&isst_hash_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(isst_store_cmd);
+
+static void isst_mbox_resume_command(struct isst_if_cmd_cb *cb,
+ struct isst_cmd *sst_cmd)
+{
+ struct isst_if_mbox_cmd mbox_cmd;
+ int wr_only;
+
+ mbox_cmd.command = (sst_cmd->cmd & GENMASK_ULL(31, 16)) >> 16;
+ mbox_cmd.sub_command = sst_cmd->cmd & GENMASK_ULL(15, 0);
+ mbox_cmd.parameter = sst_cmd->param;
+ mbox_cmd.req_data = sst_cmd->data;
+ mbox_cmd.logical_cpu = sst_cmd->cpu;
+ (cb->cmd_callback)((u8 *)&mbox_cmd, &wr_only, 1);
+}
+
+/**
+ * isst_resume_common() - Process Resume request
+ *
+ * On resume replay all mailbox commands and MSRs.
+ *
+ * Return: None.
+ */
+void isst_resume_common(void)
+{
+ struct isst_cmd *sst_cmd;
+ int i;
+
+ hash_for_each(isst_hash, i, sst_cmd, hnode) {
+ struct isst_if_cmd_cb *cb;
+
+ if (sst_cmd->mbox_cmd_type) {
+ cb = &punit_callbacks[ISST_IF_DEV_MBOX];
+ if (cb->registered)
+ isst_mbox_resume_command(cb, sst_cmd);
+ } else {
+ wrmsrl_safe_on_cpu(sst_cmd->cpu, sst_cmd->cmd,
+ sst_cmd->data);
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(isst_resume_common);
+
+static void isst_restore_msr_local(int cpu)
+{
+ struct isst_cmd *sst_cmd;
+ int i;
+
+ mutex_lock(&isst_hash_lock);
+ for (i = 0; i < ARRAY_SIZE(punit_msr_white_list); ++i) {
+ if (!punit_msr_white_list[i])
+ break;
+
+ hash_for_each_possible(isst_hash, sst_cmd, hnode,
+ punit_msr_white_list[i]) {
+ if (!sst_cmd->mbox_cmd_type && sst_cmd->cpu == cpu)
+ wrmsrl_safe(sst_cmd->cmd, sst_cmd->data);
+ }
+ }
+ mutex_unlock(&isst_hash_lock);
+}
+
+/**
+ * isst_if_mbox_cmd_invalid() - Check invalid mailbox commands
+ * @cmd: Pointer to the command structure to verify.
+ *
+ * Invalid command to PUNIT to may result in instability of the platform.
+ * This function has a whitelist of commands, which are allowed.
+ *
+ * Return: Return true if the command is invalid, else false.
+ */
+bool isst_if_mbox_cmd_invalid(struct isst_if_mbox_cmd *cmd)
+{
+ int i;
+
+ if (cmd->logical_cpu >= nr_cpu_ids)
+ return true;
+
+ for (i = 0; i < ARRAY_SIZE(isst_valid_cmds); ++i) {
+ if (cmd->command == isst_valid_cmds[i].cmd &&
+ (cmd->sub_command >= isst_valid_cmds[i].sub_cmd_beg &&
+ cmd->sub_command <= isst_valid_cmds[i].sub_cmd_end)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(isst_if_mbox_cmd_invalid);
+
+/**
+ * isst_if_mbox_cmd_set_req() - Check mailbox command is a set request
+ * @cmd: Pointer to the command structure to verify.
+ *
+ * Check if the given mail box level is set request and not a get request.
+ *
+ * Return: Return true if the command is set_req, else false.
+ */
+bool isst_if_mbox_cmd_set_req(struct isst_if_mbox_cmd *cmd)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(isst_cmd_set_reqs); ++i) {
+ if (cmd->command == isst_cmd_set_reqs[i].cmd &&
+ cmd->sub_command == isst_cmd_set_reqs[i].sub_cmd &&
+ cmd->parameter == isst_cmd_set_reqs[i].param) {
+ return true;
+ }
+ }
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(isst_if_mbox_cmd_set_req);
+
+static int isst_if_get_platform_info(void __user *argp)
+{
+ struct isst_if_platform_info info;
+
+ info.api_version = ISST_IF_API_VERSION,
+ info.driver_version = ISST_IF_DRIVER_VERSION,
+ info.max_cmds_per_ioctl = ISST_IF_CMD_LIMIT,
+ info.mbox_supported = punit_callbacks[ISST_IF_DEV_MBOX].registered;
+ info.mmio_supported = punit_callbacks[ISST_IF_DEV_MMIO].registered;
+
+ if (copy_to_user(argp, &info, sizeof(info)))
+ return -EFAULT;
+
+ return 0;
+}
+
+
+struct isst_if_cpu_info {
+ /* For BUS 0 and BUS 1 only, which we need for PUNIT interface */
+ int bus_info[2];
+ int punit_cpu_id;
+};
+
+static struct isst_if_cpu_info *isst_cpu_info;
+
+/**
+ * isst_if_get_pci_dev() - Get the PCI device instance for a CPU
+ * @cpu: Logical CPU number.
+ * @bus_number: The bus number assigned by the hardware.
+ * @dev: The device number assigned by the hardware.
+ * @fn: The function number assigned by the hardware.
+ *
+ * Using cached bus information, find out the PCI device for a bus number,
+ * device and function.
+ *
+ * Return: Return pci_dev pointer or NULL.
+ */
+struct pci_dev *isst_if_get_pci_dev(int cpu, int bus_no, int dev, int fn)
+{
+ int bus_number;
+
+ if (bus_no < 0 || bus_no > 1 || cpu < 0 || cpu >= nr_cpu_ids ||
+ cpu >= num_possible_cpus())
+ return NULL;
+
+ bus_number = isst_cpu_info[cpu].bus_info[bus_no];
+ if (bus_number < 0)
+ return NULL;
+
+ return pci_get_domain_bus_and_slot(0, bus_number, PCI_DEVFN(dev, fn));
+}
+EXPORT_SYMBOL_GPL(isst_if_get_pci_dev);
+
+static int isst_if_cpu_online(unsigned int cpu)
+{
+ u64 data;
+ int ret;
+
+ ret = rdmsrl_safe(MSR_CPU_BUS_NUMBER, &data);
+ if (ret) {
+ /* This is not a fatal error on MSR mailbox only I/F */
+ isst_cpu_info[cpu].bus_info[0] = -1;
+ isst_cpu_info[cpu].bus_info[1] = -1;
+ } else {
+ isst_cpu_info[cpu].bus_info[0] = data & 0xff;
+ isst_cpu_info[cpu].bus_info[1] = (data >> 8) & 0xff;
+ }
+
+ ret = rdmsrl_safe(MSR_THREAD_ID_INFO, &data);
+ if (ret) {
+ isst_cpu_info[cpu].punit_cpu_id = -1;
+ return ret;
+ }
+ isst_cpu_info[cpu].punit_cpu_id = data;
+
+ isst_restore_msr_local(cpu);
+
+ return 0;
+}
+
+static int isst_if_online_id;
+
+static int isst_if_cpu_info_init(void)
+{
+ int ret;
+
+ isst_cpu_info = kcalloc(num_possible_cpus(),
+ sizeof(*isst_cpu_info),
+ GFP_KERNEL);
+ if (!isst_cpu_info)
+ return -ENOMEM;
+
+ ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
+ "platform/x86/isst-if:online",
+ isst_if_cpu_online, NULL);
+ if (ret < 0) {
+ kfree(isst_cpu_info);
+ return ret;
+ }
+
+ isst_if_online_id = ret;
+
+ return 0;
+}
+
+static void isst_if_cpu_info_exit(void)
+{
+ cpuhp_remove_state(isst_if_online_id);
+ kfree(isst_cpu_info);
+};
+
+static long isst_if_proc_phyid_req(u8 *cmd_ptr, int *write_only, int resume)
+{
+ struct isst_if_cpu_map *cpu_map;
+
+ cpu_map = (struct isst_if_cpu_map *)cmd_ptr;
+ if (cpu_map->logical_cpu >= nr_cpu_ids ||
+ cpu_map->logical_cpu >= num_possible_cpus())
+ return -EINVAL;
+
+ *write_only = 0;
+ cpu_map->physical_cpu = isst_cpu_info[cpu_map->logical_cpu].punit_cpu_id;
+
+ return 0;
+}
+
+static bool match_punit_msr_white_list(int msr)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(punit_msr_white_list); ++i) {
+ if (punit_msr_white_list[i] == msr)
+ return true;
+ }
+
+ return false;
+}
+
+static long isst_if_msr_cmd_req(u8 *cmd_ptr, int *write_only, int resume)
+{
+ struct isst_if_msr_cmd *msr_cmd;
+ int ret;
+
+ msr_cmd = (struct isst_if_msr_cmd *)cmd_ptr;
+
+ if (!match_punit_msr_white_list(msr_cmd->msr))
+ return -EINVAL;
+
+ if (msr_cmd->logical_cpu >= nr_cpu_ids)
+ return -EINVAL;
+
+ if (msr_cmd->read_write) {
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ ret = wrmsrl_safe_on_cpu(msr_cmd->logical_cpu,
+ msr_cmd->msr,
+ msr_cmd->data);
+ *write_only = 1;
+ if (!ret && !resume)
+ ret = isst_store_cmd(0, msr_cmd->msr,
+ msr_cmd->logical_cpu,
+ 0, 0, msr_cmd->data);
+ } else {
+ u64 data;
+
+ ret = rdmsrl_safe_on_cpu(msr_cmd->logical_cpu,
+ msr_cmd->msr, &data);
+ if (!ret) {
+ msr_cmd->data = data;
+ *write_only = 0;
+ }
+ }
+
+
+ return ret;
+}
+
+static long isst_if_exec_multi_cmd(void __user *argp, struct isst_if_cmd_cb *cb)
+{
+ unsigned char __user *ptr;
+ u32 cmd_count;
+ u8 *cmd_ptr;
+ long ret;
+ int i;
+
+ /* Each multi command has u32 command count as the first field */
+ if (copy_from_user(&cmd_count, argp, sizeof(cmd_count)))
+ return -EFAULT;
+
+ if (!cmd_count || cmd_count > ISST_IF_CMD_LIMIT)
+ return -EINVAL;
+
+ cmd_ptr = kmalloc(cb->cmd_size, GFP_KERNEL);
+ if (!cmd_ptr)
+ return -ENOMEM;
+
+ /* cb->offset points to start of the command after the command count */
+ ptr = argp + cb->offset;
+
+ for (i = 0; i < cmd_count; ++i) {
+ int wr_only;
+
+ if (signal_pending(current)) {
+ ret = -EINTR;
+ break;
+ }
+
+ if (copy_from_user(cmd_ptr, ptr, cb->cmd_size)) {
+ ret = -EFAULT;
+ break;
+ }
+
+ ret = cb->cmd_callback(cmd_ptr, &wr_only, 0);
+ if (ret)
+ break;
+
+ if (!wr_only && copy_to_user(ptr, cmd_ptr, cb->cmd_size)) {
+ ret = -EFAULT;
+ break;
+ }
+
+ ptr += cb->cmd_size;
+ }
+
+ kfree(cmd_ptr);
+
+ return i ? i : ret;
+}
+
+static long isst_if_def_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ struct isst_if_cmd_cb cmd_cb;
+ struct isst_if_cmd_cb *cb;
+ long ret = -ENOTTY;
+
+ switch (cmd) {
+ case ISST_IF_GET_PLATFORM_INFO:
+ ret = isst_if_get_platform_info(argp);
+ break;
+ case ISST_IF_GET_PHY_ID:
+ cmd_cb.cmd_size = sizeof(struct isst_if_cpu_map);
+ cmd_cb.offset = offsetof(struct isst_if_cpu_maps, cpu_map);
+ cmd_cb.cmd_callback = isst_if_proc_phyid_req;
+ ret = isst_if_exec_multi_cmd(argp, &cmd_cb);
+ break;
+ case ISST_IF_IO_CMD:
+ cb = &punit_callbacks[ISST_IF_DEV_MMIO];
+ if (cb->registered)
+ ret = isst_if_exec_multi_cmd(argp, cb);
+ break;
+ case ISST_IF_MBOX_COMMAND:
+ cb = &punit_callbacks[ISST_IF_DEV_MBOX];
+ if (cb->registered)
+ ret = isst_if_exec_multi_cmd(argp, cb);
+ break;
+ case ISST_IF_MSR_COMMAND:
+ cmd_cb.cmd_size = sizeof(struct isst_if_msr_cmd);
+ cmd_cb.offset = offsetof(struct isst_if_msr_cmds, msr_cmd);
+ cmd_cb.cmd_callback = isst_if_msr_cmd_req;
+ ret = isst_if_exec_multi_cmd(argp, &cmd_cb);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static DEFINE_MUTEX(punit_misc_dev_lock);
+static int misc_usage_count;
+static int misc_device_ret;
+static int misc_device_open;
+
+static int isst_if_open(struct inode *inode, struct file *file)
+{
+ int i, ret = 0;
+
+ /* Fail open, if a module is going away */
+ mutex_lock(&punit_misc_dev_lock);
+ for (i = 0; i < ISST_IF_DEV_MAX; ++i) {
+ struct isst_if_cmd_cb *cb = &punit_callbacks[i];
+
+ if (cb->registered && !try_module_get(cb->owner)) {
+ ret = -ENODEV;
+ break;
+ }
+ }
+ if (ret) {
+ int j;
+
+ for (j = 0; j < i; ++j) {
+ struct isst_if_cmd_cb *cb;
+
+ cb = &punit_callbacks[j];
+ if (cb->registered)
+ module_put(cb->owner);
+ }
+ } else {
+ misc_device_open++;
+ }
+ mutex_unlock(&punit_misc_dev_lock);
+
+ return ret;
+}
+
+static int isst_if_relase(struct inode *inode, struct file *f)
+{
+ int i;
+
+ mutex_lock(&punit_misc_dev_lock);
+ misc_device_open--;
+ for (i = 0; i < ISST_IF_DEV_MAX; ++i) {
+ struct isst_if_cmd_cb *cb = &punit_callbacks[i];
+
+ if (cb->registered)
+ module_put(cb->owner);
+ }
+ mutex_unlock(&punit_misc_dev_lock);
+
+ return 0;
+}
+
+static const struct file_operations isst_if_char_driver_ops = {
+ .open = isst_if_open,
+ .unlocked_ioctl = isst_if_def_ioctl,
+ .release = isst_if_relase,
+};
+
+static struct miscdevice isst_if_char_driver = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "isst_interface",
+ .fops = &isst_if_char_driver_ops,
+};
+
+/**
+ * isst_if_cdev_register() - Register callback for IOCTL
+ * @device_type: The device type this callback handling.
+ * @cb: Callback structure.
+ *
+ * This function registers a callback to device type. On very first call
+ * it will register a misc device, which is used for user kernel interface.
+ * Other calls simply increment ref count. Registry will fail, if the user
+ * already opened misc device for operation. Also if the misc device
+ * creation failed, then it will not try again and all callers will get
+ * failure code.
+ *
+ * Return: Return the return value from the misc creation device or -EINVAL
+ * for unsupported device type.
+ */
+int isst_if_cdev_register(int device_type, struct isst_if_cmd_cb *cb)
+{
+ if (misc_device_ret)
+ return misc_device_ret;
+
+ if (device_type >= ISST_IF_DEV_MAX)
+ return -EINVAL;
+
+ mutex_lock(&punit_misc_dev_lock);
+ if (misc_device_open) {
+ mutex_unlock(&punit_misc_dev_lock);
+ return -EAGAIN;
+ }
+ if (!misc_usage_count) {
+ int ret;
+
+ misc_device_ret = misc_register(&isst_if_char_driver);
+ if (misc_device_ret)
+ goto unlock_exit;
+
+ ret = isst_if_cpu_info_init();
+ if (ret) {
+ misc_deregister(&isst_if_char_driver);
+ misc_device_ret = ret;
+ goto unlock_exit;
+ }
+ }
+ memcpy(&punit_callbacks[device_type], cb, sizeof(*cb));
+ punit_callbacks[device_type].registered = 1;
+ misc_usage_count++;
+unlock_exit:
+ mutex_unlock(&punit_misc_dev_lock);
+
+ return misc_device_ret;
+}
+EXPORT_SYMBOL_GPL(isst_if_cdev_register);
+
+/**
+ * isst_if_cdev_unregister() - Unregister callback for IOCTL
+ * @device_type: The device type to unregister.
+ *
+ * This function unregisters the previously registered callback. If this
+ * is the last callback unregistering, then misc device is removed.
+ *
+ * Return: None.
+ */
+void isst_if_cdev_unregister(int device_type)
+{
+ mutex_lock(&punit_misc_dev_lock);
+ misc_usage_count--;
+ punit_callbacks[device_type].registered = 0;
+ if (device_type == ISST_IF_DEV_MBOX)
+ isst_delete_hash();
+ if (!misc_usage_count && !misc_device_ret) {
+ misc_deregister(&isst_if_char_driver);
+ isst_if_cpu_info_exit();
+ }
+ mutex_unlock(&punit_misc_dev_lock);
+}
+EXPORT_SYMBOL_GPL(isst_if_cdev_unregister);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/x86/intel_speed_select_if/isst_if_common.h b/drivers/platform/x86/intel_speed_select_if/isst_if_common.h
new file mode 100644
index 000000000000..1409a5bb5582
--- /dev/null
+++ b/drivers/platform/x86/intel_speed_select_if/isst_if_common.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Intel Speed Select Interface: Drivers Internal defines
+ * Copyright (c) 2019, Intel Corporation.
+ * All rights reserved.
+ *
+ * Author: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
+ */
+
+#ifndef __ISST_IF_COMMON_H
+#define __ISST_IF_COMMON_H
+
+#define INTEL_RAPL_PRIO_DEVID_0 0x3451
+#define INTEL_CFG_MBOX_DEVID_0 0x3459
+
+/*
+ * Validate maximum commands in a single request.
+ * This is enough to handle command to every core in one ioctl, or all
+ * possible message id to one CPU. Limit is also helpful for resonse time
+ * per IOCTL request, as PUNIT may take different times to process each
+ * request and may hold for long for too many commands.
+ */
+#define ISST_IF_CMD_LIMIT 64
+
+#define ISST_IF_API_VERSION 0x01
+#define ISST_IF_DRIVER_VERSION 0x01
+
+#define ISST_IF_DEV_MBOX 0
+#define ISST_IF_DEV_MMIO 1
+#define ISST_IF_DEV_MAX 2
+
+/**
+ * struct isst_if_cmd_cb - Used to register a IOCTL handler
+ * @registered: Used by the common code to store registry. Caller don't
+ * to touch this field
+ * @cmd_size: The command size of the individual command in IOCTL
+ * @offset: Offset to the first valid member in command structure.
+ * This will be the offset of the start of the command
+ * after command count field
+ * @cmd_callback: Callback function to handle IOCTL. The callback has the
+ * command pointer with data for command. There is a pointer
+ * called write_only, which when set, will not copy the
+ * response to user ioctl buffer. The "resume" argument
+ * can be used to avoid storing the command for replay
+ * during system resume
+ *
+ * This structure is used to register an handler for IOCTL. To avoid
+ * code duplication common code handles all the IOCTL command read/write
+ * including handling multiple command in single IOCTL. The caller just
+ * need to execute a command via the registered callback.
+ */
+struct isst_if_cmd_cb {
+ int registered;
+ int cmd_size;
+ int offset;
+ struct module *owner;
+ long (*cmd_callback)(u8 *ptr, int *write_only, int resume);
+};
+
+/* Internal interface functions */
+int isst_if_cdev_register(int type, struct isst_if_cmd_cb *cb);
+void isst_if_cdev_unregister(int type);
+struct pci_dev *isst_if_get_pci_dev(int cpu, int bus, int dev, int fn);
+bool isst_if_mbox_cmd_set_req(struct isst_if_mbox_cmd *mbox_cmd);
+bool isst_if_mbox_cmd_invalid(struct isst_if_mbox_cmd *cmd);
+int isst_store_cmd(int cmd, int sub_command, u32 cpu, int mbox_cmd,
+ u32 param, u64 data);
+void isst_resume_common(void);
+#endif
diff --git a/drivers/platform/x86/intel_speed_select_if/isst_if_mbox_msr.c b/drivers/platform/x86/intel_speed_select_if/isst_if_mbox_msr.c
new file mode 100644
index 000000000000..89b042aecef3
--- /dev/null
+++ b/drivers/platform/x86/intel_speed_select_if/isst_if_mbox_msr.c
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel Speed Select Interface: Mbox via MSR Interface
+ * Copyright (c) 2019, Intel Corporation.
+ * All rights reserved.
+ *
+ * Author: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
+ */
+
+#include <linux/module.h>
+#include <linux/cpuhotplug.h>
+#include <linux/pci.h>
+#include <linux/sched/signal.h>
+#include <linux/slab.h>
+#include <linux/suspend.h>
+#include <linux/topology.h>
+#include <linux/uaccess.h>
+#include <uapi/linux/isst_if.h>
+#include <asm/cpu_device_id.h>
+#include <asm/intel-family.h>
+
+#include "isst_if_common.h"
+
+#define MSR_OS_MAILBOX_INTERFACE 0xB0
+#define MSR_OS_MAILBOX_DATA 0xB1
+#define MSR_OS_MAILBOX_BUSY_BIT 31
+
+/*
+ * Based on experiments count is never more than 1, as the MSR overhead
+ * is enough to finish the command. So here this is the worst case number.
+ */
+#define OS_MAILBOX_RETRY_COUNT 3
+
+static int isst_if_send_mbox_cmd(u8 command, u8 sub_command, u32 parameter,
+ u32 command_data, u32 *response_data)
+{
+ u32 retries;
+ u64 data;
+ int ret;
+
+ /* Poll for rb bit == 0 */
+ retries = OS_MAILBOX_RETRY_COUNT;
+ do {
+ rdmsrl(MSR_OS_MAILBOX_INTERFACE, data);
+ if (data & BIT_ULL(MSR_OS_MAILBOX_BUSY_BIT)) {
+ ret = -EBUSY;
+ continue;
+ }
+ ret = 0;
+ break;
+ } while (--retries);
+
+ if (ret)
+ return ret;
+
+ /* Write DATA register */
+ wrmsrl(MSR_OS_MAILBOX_DATA, command_data);
+
+ /* Write command register */
+ data = BIT_ULL(MSR_OS_MAILBOX_BUSY_BIT) |
+ (parameter & GENMASK_ULL(13, 0)) << 16 |
+ (sub_command << 8) |
+ command;
+ wrmsrl(MSR_OS_MAILBOX_INTERFACE, data);
+
+ /* Poll for rb bit == 0 */
+ retries = OS_MAILBOX_RETRY_COUNT;
+ do {
+ rdmsrl(MSR_OS_MAILBOX_INTERFACE, data);
+ if (data & BIT_ULL(MSR_OS_MAILBOX_BUSY_BIT)) {
+ ret = -EBUSY;
+ continue;
+ }
+
+ if (data & 0xff)
+ return -ENXIO;
+
+ if (response_data) {
+ rdmsrl(MSR_OS_MAILBOX_DATA, data);
+ *response_data = data;
+ }
+ ret = 0;
+ break;
+ } while (--retries);
+
+ return ret;
+}
+
+struct msrl_action {
+ int err;
+ struct isst_if_mbox_cmd *mbox_cmd;
+};
+
+/* revisit, smp_call_function_single should be enough for atomic mailbox! */
+static void msrl_update_func(void *info)
+{
+ struct msrl_action *act = info;
+
+ act->err = isst_if_send_mbox_cmd(act->mbox_cmd->command,
+ act->mbox_cmd->sub_command,
+ act->mbox_cmd->parameter,
+ act->mbox_cmd->req_data,
+ &act->mbox_cmd->resp_data);
+}
+
+static long isst_if_mbox_proc_cmd(u8 *cmd_ptr, int *write_only, int resume)
+{
+ struct msrl_action action;
+ int ret;
+
+ action.mbox_cmd = (struct isst_if_mbox_cmd *)cmd_ptr;
+
+ if (isst_if_mbox_cmd_invalid(action.mbox_cmd))
+ return -EINVAL;
+
+ if (isst_if_mbox_cmd_set_req(action.mbox_cmd) &&
+ !capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ /*
+ * To complete mailbox command, we need to access two MSRs.
+ * So we don't want race to complete a mailbox transcation.
+ * Here smp_call ensures that msrl_update_func() has no race
+ * and also with wait flag, wait for completion.
+ * smp_call_function_single is using get_cpu() and put_cpu().
+ */
+ ret = smp_call_function_single(action.mbox_cmd->logical_cpu,
+ msrl_update_func, &action, 1);
+ if (ret)
+ return ret;
+
+ if (!action.err && !resume && isst_if_mbox_cmd_set_req(action.mbox_cmd))
+ action.err = isst_store_cmd(action.mbox_cmd->command,
+ action.mbox_cmd->sub_command,
+ action.mbox_cmd->logical_cpu, 1,
+ action.mbox_cmd->parameter,
+ action.mbox_cmd->req_data);
+ *write_only = 0;
+
+ return action.err;
+}
+
+
+static int isst_pm_notify(struct notifier_block *nb,
+ unsigned long mode, void *_unused)
+{
+ switch (mode) {
+ case PM_POST_HIBERNATION:
+ case PM_POST_RESTORE:
+ case PM_POST_SUSPEND:
+ isst_resume_common();
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static struct notifier_block isst_pm_nb = {
+ .notifier_call = isst_pm_notify,
+};
+
+#define ICPU(model) { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, }
+
+static const struct x86_cpu_id isst_if_cpu_ids[] = {
+ ICPU(INTEL_FAM6_SKYLAKE_X),
+ {}
+};
+MODULE_DEVICE_TABLE(x86cpu, isst_if_cpu_ids);
+
+static int __init isst_if_mbox_init(void)
+{
+ struct isst_if_cmd_cb cb;
+ const struct x86_cpu_id *id;
+ u64 data;
+ int ret;
+
+ id = x86_match_cpu(isst_if_cpu_ids);
+ if (!id)
+ return -ENODEV;
+
+ /* Check presence of mailbox MSRs */
+ ret = rdmsrl_safe(MSR_OS_MAILBOX_INTERFACE, &data);
+ if (ret)
+ return ret;
+
+ ret = rdmsrl_safe(MSR_OS_MAILBOX_DATA, &data);
+ if (ret)
+ return ret;
+
+ memset(&cb, 0, sizeof(cb));
+ cb.cmd_size = sizeof(struct isst_if_mbox_cmd);
+ cb.offset = offsetof(struct isst_if_mbox_cmds, mbox_cmd);
+ cb.cmd_callback = isst_if_mbox_proc_cmd;
+ cb.owner = THIS_MODULE;
+ ret = isst_if_cdev_register(ISST_IF_DEV_MBOX, &cb);
+ if (ret)
+ return ret;
+
+ ret = register_pm_notifier(&isst_pm_nb);
+ if (ret)
+ isst_if_cdev_unregister(ISST_IF_DEV_MBOX);
+
+ return ret;
+}
+module_init(isst_if_mbox_init)
+
+static void __exit isst_if_mbox_exit(void)
+{
+ unregister_pm_notifier(&isst_pm_nb);
+ isst_if_cdev_unregister(ISST_IF_DEV_MBOX);
+}
+module_exit(isst_if_mbox_exit)
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel speed select interface mailbox driver");
diff --git a/drivers/platform/x86/intel_speed_select_if/isst_if_mbox_pci.c b/drivers/platform/x86/intel_speed_select_if/isst_if_mbox_pci.c
new file mode 100644
index 000000000000..de4169d0796b
--- /dev/null
+++ b/drivers/platform/x86/intel_speed_select_if/isst_if_mbox_pci.c
@@ -0,0 +1,214 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel Speed Select Interface: Mbox via PCI Interface
+ * Copyright (c) 2019, Intel Corporation.
+ * All rights reserved.
+ *
+ * Author: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
+ */
+
+#include <linux/cpufeature.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/sched/signal.h>
+#include <linux/uaccess.h>
+#include <uapi/linux/isst_if.h>
+
+#include "isst_if_common.h"
+
+#define PUNIT_MAILBOX_DATA 0xA0
+#define PUNIT_MAILBOX_INTERFACE 0xA4
+#define PUNIT_MAILBOX_BUSY_BIT 31
+
+/*
+ * Commands has variable amount of processing time. Most of the commands will
+ * be done in 0-3 tries, but some takes up to 50.
+ * The real processing time was observed as 25us for the most of the commands
+ * at 2GHz. It is possible to optimize this count taking samples on customer
+ * systems.
+ */
+#define OS_MAILBOX_RETRY_COUNT 50
+
+struct isst_if_device {
+ struct mutex mutex;
+};
+
+static int isst_if_mbox_cmd(struct pci_dev *pdev,
+ struct isst_if_mbox_cmd *mbox_cmd)
+{
+ u32 retries, data;
+ int ret;
+
+ /* Poll for rb bit == 0 */
+ retries = OS_MAILBOX_RETRY_COUNT;
+ do {
+ ret = pci_read_config_dword(pdev, PUNIT_MAILBOX_INTERFACE,
+ &data);
+ if (ret)
+ return ret;
+
+ if (data & BIT_ULL(PUNIT_MAILBOX_BUSY_BIT)) {
+ ret = -EBUSY;
+ continue;
+ }
+ ret = 0;
+ break;
+ } while (--retries);
+
+ if (ret)
+ return ret;
+
+ /* Write DATA register */
+ ret = pci_write_config_dword(pdev, PUNIT_MAILBOX_DATA,
+ mbox_cmd->req_data);
+ if (ret)
+ return ret;
+
+ /* Write command register */
+ data = BIT_ULL(PUNIT_MAILBOX_BUSY_BIT) |
+ (mbox_cmd->parameter & GENMASK_ULL(13, 0)) << 16 |
+ (mbox_cmd->sub_command << 8) |
+ mbox_cmd->command;
+
+ ret = pci_write_config_dword(pdev, PUNIT_MAILBOX_INTERFACE, data);
+ if (ret)
+ return ret;
+
+ /* Poll for rb bit == 0 */
+ retries = OS_MAILBOX_RETRY_COUNT;
+ do {
+ ret = pci_read_config_dword(pdev, PUNIT_MAILBOX_INTERFACE,
+ &data);
+ if (ret)
+ return ret;
+
+ if (data & BIT_ULL(PUNIT_MAILBOX_BUSY_BIT)) {
+ ret = -EBUSY;
+ continue;
+ }
+
+ if (data & 0xff)
+ return -ENXIO;
+
+ ret = pci_read_config_dword(pdev, PUNIT_MAILBOX_DATA, &data);
+ if (ret)
+ return ret;
+
+ mbox_cmd->resp_data = data;
+ ret = 0;
+ break;
+ } while (--retries);
+
+ return ret;
+}
+
+static long isst_if_mbox_proc_cmd(u8 *cmd_ptr, int *write_only, int resume)
+{
+ struct isst_if_mbox_cmd *mbox_cmd;
+ struct isst_if_device *punit_dev;
+ struct pci_dev *pdev;
+ int ret;
+
+ mbox_cmd = (struct isst_if_mbox_cmd *)cmd_ptr;
+
+ if (isst_if_mbox_cmd_invalid(mbox_cmd))
+ return -EINVAL;
+
+ if (isst_if_mbox_cmd_set_req(mbox_cmd) && !capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ pdev = isst_if_get_pci_dev(mbox_cmd->logical_cpu, 1, 30, 1);
+ if (!pdev)
+ return -EINVAL;
+
+ punit_dev = pci_get_drvdata(pdev);
+ if (!punit_dev)
+ return -EINVAL;
+
+ /*
+ * Basically we are allowing one complete mailbox transaction on
+ * a mapped PCI device at a time.
+ */
+ mutex_lock(&punit_dev->mutex);
+ ret = isst_if_mbox_cmd(pdev, mbox_cmd);
+ if (!ret && !resume && isst_if_mbox_cmd_set_req(mbox_cmd))
+ ret = isst_store_cmd(mbox_cmd->command,
+ mbox_cmd->sub_command,
+ mbox_cmd->logical_cpu, 1,
+ mbox_cmd->parameter,
+ mbox_cmd->req_data);
+ mutex_unlock(&punit_dev->mutex);
+ if (ret)
+ return ret;
+
+ *write_only = 0;
+
+ return 0;
+}
+
+static const struct pci_device_id isst_if_mbox_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, INTEL_CFG_MBOX_DEVID_0)},
+ { 0 },
+};
+MODULE_DEVICE_TABLE(pci, isst_if_mbox_ids);
+
+static int isst_if_mbox_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct isst_if_device *punit_dev;
+ struct isst_if_cmd_cb cb;
+ int ret;
+
+ punit_dev = devm_kzalloc(&pdev->dev, sizeof(*punit_dev), GFP_KERNEL);
+ if (!punit_dev)
+ return -ENOMEM;
+
+ ret = pcim_enable_device(pdev);
+ if (ret)
+ return ret;
+
+ mutex_init(&punit_dev->mutex);
+ pci_set_drvdata(pdev, punit_dev);
+
+ memset(&cb, 0, sizeof(cb));
+ cb.cmd_size = sizeof(struct isst_if_mbox_cmd);
+ cb.offset = offsetof(struct isst_if_mbox_cmds, mbox_cmd);
+ cb.cmd_callback = isst_if_mbox_proc_cmd;
+ cb.owner = THIS_MODULE;
+ ret = isst_if_cdev_register(ISST_IF_DEV_MBOX, &cb);
+
+ if (ret)
+ mutex_destroy(&punit_dev->mutex);
+
+ return ret;
+}
+
+static void isst_if_mbox_remove(struct pci_dev *pdev)
+{
+ struct isst_if_device *punit_dev;
+
+ punit_dev = pci_get_drvdata(pdev);
+ isst_if_cdev_unregister(ISST_IF_DEV_MBOX);
+ mutex_destroy(&punit_dev->mutex);
+}
+
+static int __maybe_unused isst_if_resume(struct device *device)
+{
+ isst_resume_common();
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(isst_if_pm_ops, NULL, isst_if_resume);
+
+static struct pci_driver isst_if_pci_driver = {
+ .name = "isst_if_mbox_pci",
+ .id_table = isst_if_mbox_ids,
+ .probe = isst_if_mbox_probe,
+ .remove = isst_if_mbox_remove,
+ .driver.pm = &isst_if_pm_ops,
+};
+
+module_pci_driver(isst_if_pci_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel speed select interface pci mailbox driver");
diff --git a/drivers/platform/x86/intel_speed_select_if/isst_if_mmio.c b/drivers/platform/x86/intel_speed_select_if/isst_if_mmio.c
new file mode 100644
index 000000000000..f7266a115a08
--- /dev/null
+++ b/drivers/platform/x86/intel_speed_select_if/isst_if_mmio.c
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel Speed Select Interface: MMIO Interface
+ * Copyright (c) 2019, Intel Corporation.
+ * All rights reserved.
+ *
+ * Author: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/sched/signal.h>
+#include <linux/uaccess.h>
+#include <uapi/linux/isst_if.h>
+
+#include "isst_if_common.h"
+
+struct isst_mmio_range {
+ int beg;
+ int end;
+};
+
+struct isst_mmio_range mmio_range[] = {
+ {0x04, 0x14},
+ {0x20, 0xD0},
+};
+
+struct isst_if_device {
+ void __iomem *punit_mmio;
+ u32 range_0[5];
+ u32 range_1[45];
+ struct mutex mutex;
+};
+
+static long isst_if_mmio_rd_wr(u8 *cmd_ptr, int *write_only, int resume)
+{
+ struct isst_if_device *punit_dev;
+ struct isst_if_io_reg *io_reg;
+ struct pci_dev *pdev;
+
+ io_reg = (struct isst_if_io_reg *)cmd_ptr;
+ if (io_reg->reg < 0x04 || io_reg->reg > 0xD0)
+ return -EINVAL;
+
+ if (io_reg->read_write && !capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ pdev = isst_if_get_pci_dev(io_reg->logical_cpu, 0, 0, 1);
+ if (!pdev)
+ return -EINVAL;
+
+ punit_dev = pci_get_drvdata(pdev);
+ if (!punit_dev)
+ return -EINVAL;
+
+ /*
+ * Ensure that operation is complete on a PCI device to avoid read
+ * write race by using per PCI device mutex.
+ */
+ mutex_lock(&punit_dev->mutex);
+ if (io_reg->read_write) {
+ writel(io_reg->value, punit_dev->punit_mmio+io_reg->reg);
+ *write_only = 1;
+ } else {
+ io_reg->value = readl(punit_dev->punit_mmio+io_reg->reg);
+ *write_only = 0;
+ }
+ mutex_unlock(&punit_dev->mutex);
+
+ return 0;
+}
+
+static const struct pci_device_id isst_if_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, INTEL_RAPL_PRIO_DEVID_0)},
+ { 0 },
+};
+MODULE_DEVICE_TABLE(pci, isst_if_ids);
+
+static int isst_if_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct isst_if_device *punit_dev;
+ struct isst_if_cmd_cb cb;
+ u32 mmio_base, pcu_base;
+ u64 base_addr;
+ int ret;
+
+ punit_dev = devm_kzalloc(&pdev->dev, sizeof(*punit_dev), GFP_KERNEL);
+ if (!punit_dev)
+ return -ENOMEM;
+
+ ret = pcim_enable_device(pdev);
+ if (ret)
+ return ret;
+
+ ret = pci_read_config_dword(pdev, 0xD0, &mmio_base);
+ if (ret)
+ return ret;
+
+ ret = pci_read_config_dword(pdev, 0xFC, &pcu_base);
+ if (ret)
+ return ret;
+
+ pcu_base &= GENMASK(10, 0);
+ base_addr = (u64)mmio_base << 23 | (u64) pcu_base << 12;
+ punit_dev->punit_mmio = devm_ioremap(&pdev->dev, base_addr, 256);
+ if (!punit_dev->punit_mmio)
+ return -ENOMEM;
+
+ mutex_init(&punit_dev->mutex);
+ pci_set_drvdata(pdev, punit_dev);
+
+ memset(&cb, 0, sizeof(cb));
+ cb.cmd_size = sizeof(struct isst_if_io_reg);
+ cb.offset = offsetof(struct isst_if_io_regs, io_reg);
+ cb.cmd_callback = isst_if_mmio_rd_wr;
+ cb.owner = THIS_MODULE;
+ ret = isst_if_cdev_register(ISST_IF_DEV_MMIO, &cb);
+ if (ret)
+ mutex_destroy(&punit_dev->mutex);
+
+ return ret;
+}
+
+static void isst_if_remove(struct pci_dev *pdev)
+{
+ struct isst_if_device *punit_dev;
+
+ punit_dev = pci_get_drvdata(pdev);
+ isst_if_cdev_unregister(ISST_IF_DEV_MBOX);
+ mutex_destroy(&punit_dev->mutex);
+}
+
+static int __maybe_unused isst_if_suspend(struct device *device)
+{
+ struct pci_dev *pdev = to_pci_dev(device);
+ struct isst_if_device *punit_dev;
+ int i;
+
+ punit_dev = pci_get_drvdata(pdev);
+ for (i = 0; i < ARRAY_SIZE(punit_dev->range_0); ++i)
+ punit_dev->range_0[i] = readl(punit_dev->punit_mmio +
+ mmio_range[0].beg + 4 * i);
+ for (i = 0; i < ARRAY_SIZE(punit_dev->range_1); ++i)
+ punit_dev->range_1[i] = readl(punit_dev->punit_mmio +
+ mmio_range[1].beg + 4 * i);
+
+ return 0;
+}
+
+static int __maybe_unused isst_if_resume(struct device *device)
+{
+ struct pci_dev *pdev = to_pci_dev(device);
+ struct isst_if_device *punit_dev;
+ int i;
+
+ punit_dev = pci_get_drvdata(pdev);
+ for (i = 0; i < ARRAY_SIZE(punit_dev->range_0); ++i)
+ writel(punit_dev->range_0[i], punit_dev->punit_mmio +
+ mmio_range[0].beg + 4 * i);
+ for (i = 0; i < ARRAY_SIZE(punit_dev->range_1); ++i)
+ writel(punit_dev->range_1[i], punit_dev->punit_mmio +
+ mmio_range[1].beg + 4 * i);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(isst_if_pm_ops, isst_if_suspend, isst_if_resume);
+
+static struct pci_driver isst_if_pci_driver = {
+ .name = "isst_if_pci",
+ .id_table = isst_if_ids,
+ .probe = isst_if_probe,
+ .remove = isst_if_remove,
+ .driver.pm = &isst_if_pm_ops,
+};
+
+module_pci_driver(isst_if_pci_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel speed select interface mmio driver");
diff --git a/drivers/platform/x86/intel_telemetry_debugfs.c b/drivers/platform/x86/intel_telemetry_debugfs.c
index 98ba9185a27b..e84d3e983e0c 100644
--- a/drivers/platform/x86/intel_telemetry_debugfs.c
+++ b/drivers/platform/x86/intel_telemetry_debugfs.c
@@ -900,7 +900,7 @@ static int __init telemetry_debugfs_init(void)
{
const struct x86_cpu_id *id;
int err;
- struct dentry *f;
+ struct dentry *dir;
/* Only APL supported for now */
id = x86_match_cpu(telemetry_debugfs_cpu_ids);
@@ -923,68 +923,22 @@ static int __init telemetry_debugfs_init(void)
register_pm_notifier(&pm_notifier);
- err = -ENOMEM;
- debugfs_conf->telemetry_dbg_dir = debugfs_create_dir("telemetry", NULL);
- if (!debugfs_conf->telemetry_dbg_dir)
- goto out_pm;
-
- f = debugfs_create_file("pss_info", S_IFREG | S_IRUGO,
- debugfs_conf->telemetry_dbg_dir, NULL,
- &telem_pss_states_fops);
- if (!f) {
- pr_err("pss_sample_info debugfs register failed\n");
- goto out;
- }
-
- f = debugfs_create_file("ioss_info", S_IFREG | S_IRUGO,
- debugfs_conf->telemetry_dbg_dir, NULL,
- &telem_ioss_states_fops);
- if (!f) {
- pr_err("ioss_sample_info debugfs register failed\n");
- goto out;
- }
-
- f = debugfs_create_file("soc_states", S_IFREG | S_IRUGO,
- debugfs_conf->telemetry_dbg_dir,
- NULL, &telem_soc_states_fops);
- if (!f) {
- pr_err("ioss_sample_info debugfs register failed\n");
- goto out;
- }
-
- f = debugfs_create_file("s0ix_residency_usec", S_IFREG | S_IRUGO,
- debugfs_conf->telemetry_dbg_dir,
- NULL, &telem_s0ix_fops);
- if (!f) {
- pr_err("s0ix_residency_usec debugfs register failed\n");
- goto out;
- }
-
- f = debugfs_create_file("pss_trace_verbosity", S_IFREG | S_IRUGO,
- debugfs_conf->telemetry_dbg_dir, NULL,
- &telem_pss_trc_verb_ops);
- if (!f) {
- pr_err("pss_trace_verbosity debugfs register failed\n");
- goto out;
- }
-
- f = debugfs_create_file("ioss_trace_verbosity", S_IFREG | S_IRUGO,
- debugfs_conf->telemetry_dbg_dir, NULL,
- &telem_ioss_trc_verb_ops);
- if (!f) {
- pr_err("ioss_trace_verbosity debugfs register failed\n");
- goto out;
- }
-
+ dir = debugfs_create_dir("telemetry", NULL);
+ debugfs_conf->telemetry_dbg_dir = dir;
+
+ debugfs_create_file("pss_info", S_IFREG | S_IRUGO, dir, NULL,
+ &telem_pss_states_fops);
+ debugfs_create_file("ioss_info", S_IFREG | S_IRUGO, dir, NULL,
+ &telem_ioss_states_fops);
+ debugfs_create_file("soc_states", S_IFREG | S_IRUGO, dir, NULL,
+ &telem_soc_states_fops);
+ debugfs_create_file("s0ix_residency_usec", S_IFREG | S_IRUGO, dir, NULL,
+ &telem_s0ix_fops);
+ debugfs_create_file("pss_trace_verbosity", S_IFREG | S_IRUGO, dir, NULL,
+ &telem_pss_trc_verb_ops);
+ debugfs_create_file("ioss_trace_verbosity", S_IFREG | S_IRUGO, dir,
+ NULL, &telem_ioss_trc_verb_ops);
return 0;
-
-out:
- debugfs_remove_recursive(debugfs_conf->telemetry_dbg_dir);
- debugfs_conf->telemetry_dbg_dir = NULL;
-out_pm:
- unregister_pm_notifier(&pm_notifier);
-
- return err;
}
static void __exit telemetry_debugfs_exit(void)
diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c
index 983f02b5b106..8fe51e43f1bc 100644
--- a/drivers/platform/x86/mlx-platform.c
+++ b/drivers/platform/x86/mlx-platform.c
@@ -44,6 +44,8 @@
#define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET 0x3b
#define MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET 0x40
#define MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET 0x41
+#define MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET 0x42
+#define MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET 0x43
#define MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET 0x50
#define MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET 0x51
#define MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET 0x52
@@ -105,7 +107,9 @@
MLXPLAT_CPLD_AGGR_FAN_MASK_DEF)
#define MLXPLAT_CPLD_AGGR_ASIC_MASK_NG 0x01
#define MLXPLAT_CPLD_AGGR_MASK_NG_DEF 0x04
+#define MLXPLAT_CPLD_AGGR_MASK_COMEX BIT(0)
#define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xc1
+#define MLXPLAT_CPLD_LOW_AGGR_MASK_I2C BIT(6)
#define MLXPLAT_CPLD_PSU_MASK GENMASK(1, 0)
#define MLXPLAT_CPLD_PWR_MASK GENMASK(1, 0)
#define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0)
@@ -159,6 +163,7 @@
* @pdev_io_regs - register access platform devices
* @pdev_fan - FAN platform devices
* @pdev_wd - array of watchdog platform devices
+ * @regmap: device register map
*/
struct mlxplat_priv {
struct platform_device *pdev_i2c;
@@ -168,6 +173,7 @@ struct mlxplat_priv {
struct platform_device *pdev_io_regs;
struct platform_device *pdev_fan;
struct platform_device *pdev_wd[MLXPLAT_CPLD_WD_MAX_DEVS];
+ void *regmap;
};
/* Regions for LPC I2C controller and LPC base register space */
@@ -181,6 +187,14 @@ static const struct resource mlxplat_lpc_resources[] = {
IORESOURCE_IO),
};
+/* Platform next generation systems i2c data */
+static struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_i2c_ng_data = {
+ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
+ .mask = MLXPLAT_CPLD_AGGR_MASK_COMEX,
+ .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET,
+ .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_I2C,
+};
+
/* Platform default channels */
static const int mlxplat_default_channels[][MLXPLAT_CPLD_GRP_CHNL_NUM] = {
{
@@ -704,7 +718,7 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_ng_data = {
.items = mlxplat_mlxcpld_default_ng_items,
.counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_items),
.cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
- .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
+ .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF | MLXPLAT_CPLD_AGGR_MASK_COMEX,
.cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET,
.mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
};
@@ -1113,6 +1127,12 @@ static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_regs_io_data[] = {
.mode = 0444,
},
{
+ .label = "reset_sff_wd",
+ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET,
+ .mask = GENMASK(7, 0) & ~BIT(6),
+ .mode = 0444,
+ },
+ {
.label = "psu1_on",
.reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET,
.mask = GENMASK(7, 0) & ~BIT(0),
@@ -1201,6 +1221,18 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = {
.mode = 0444,
},
{
+ .label = "reset_from_asic",
+ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET,
+ .mask = GENMASK(7, 0) & ~BIT(5),
+ .mode = 0444,
+ },
+ {
+ .label = "reset_swb_wd",
+ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET,
+ .mask = GENMASK(7, 0) & ~BIT(6),
+ .mode = 0444,
+ },
+ {
.label = "reset_asic_thermal",
.reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET,
.mask = GENMASK(7, 0) & ~BIT(7),
@@ -1213,6 +1245,12 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = {
.mode = 0444,
},
{
+ .label = "reset_comex_wd",
+ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET,
+ .mask = GENMASK(7, 0) & ~BIT(6),
+ .mode = 0444,
+ },
+ {
.label = "reset_voltmon_upgrade_fail",
.reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET,
.mask = GENMASK(7, 0) & ~BIT(0),
@@ -1225,6 +1263,18 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = {
.mode = 0444,
},
{
+ .label = "reset_comex_thermal",
+ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET,
+ .mask = GENMASK(7, 0) & ~BIT(3),
+ .mode = 0444,
+ },
+ {
+ .label = "reset_reload_bios",
+ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET,
+ .mask = GENMASK(7, 0) & ~BIT(5),
+ .mode = 0444,
+ },
+ {
.label = "psu1_on",
.reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET,
.mask = GENMASK(7, 0) & ~BIT(0),
@@ -1531,6 +1581,7 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_REG_WP2_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
@@ -1578,6 +1629,8 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET:
case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET:
@@ -1645,6 +1698,8 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET:
case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET:
@@ -1691,6 +1746,11 @@ static const struct reg_default mlxplat_mlxcpld_regmap_default[] = {
{ MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET, 0x00 },
};
+static const struct reg_default mlxplat_mlxcpld_regmap_ng[] = {
+ { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 },
+ { MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET, 0x00 },
+};
+
struct mlxplat_mlxcpld_regmap_context {
void __iomem *base;
};
@@ -1729,17 +1789,33 @@ static const struct regmap_config mlxplat_mlxcpld_regmap_config = {
.reg_write = mlxplat_mlxcpld_reg_write,
};
+static const struct regmap_config mlxplat_mlxcpld_regmap_config_ng = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 255,
+ .cache_type = REGCACHE_FLAT,
+ .writeable_reg = mlxplat_mlxcpld_writeable_reg,
+ .readable_reg = mlxplat_mlxcpld_readable_reg,
+ .volatile_reg = mlxplat_mlxcpld_volatile_reg,
+ .reg_defaults = mlxplat_mlxcpld_regmap_ng,
+ .num_reg_defaults = ARRAY_SIZE(mlxplat_mlxcpld_regmap_ng),
+ .reg_read = mlxplat_mlxcpld_reg_read,
+ .reg_write = mlxplat_mlxcpld_reg_write,
+};
+
static struct resource mlxplat_mlxcpld_resources[] = {
[0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"),
};
static struct platform_device *mlxplat_dev;
+static struct mlxreg_core_hotplug_platform_data *mlxplat_i2c;
static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug;
static struct mlxreg_core_platform_data *mlxplat_led;
static struct mlxreg_core_platform_data *mlxplat_regs_io;
static struct mlxreg_core_platform_data *mlxplat_fan;
static struct mlxreg_core_platform_data
*mlxplat_wd_data[MLXPLAT_CPLD_WD_MAX_DEVS];
+static const struct regmap_config *mlxplat_regmap_config;
static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
{
@@ -1834,12 +1910,50 @@ static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi)
mlxplat_fan = &mlxplat_default_fan_data;
for (i = 0; i < ARRAY_SIZE(mlxplat_mlxcpld_wd_set_type2); i++)
mlxplat_wd_data[i] = &mlxplat_mlxcpld_wd_set_type2[i];
+ mlxplat_i2c = &mlxplat_mlxcpld_i2c_ng_data;
+ mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_ng;
return 1;
};
static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
{
+ .callback = mlxplat_dmi_default_matched,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "VMOD0001"),
+ },
+ },
+ {
+ .callback = mlxplat_dmi_msn21xx_matched,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "VMOD0002"),
+ },
+ },
+ {
+ .callback = mlxplat_dmi_msn274x_matched,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "VMOD0003"),
+ },
+ },
+ {
+ .callback = mlxplat_dmi_msn201x_matched,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "VMOD0004"),
+ },
+ },
+ {
+ .callback = mlxplat_dmi_qmb7xx_matched,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "VMOD0005"),
+ },
+ },
+ {
+ .callback = mlxplat_dmi_qmb7xx_matched,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "VMOD0007"),
+ },
+ },
+ {
.callback = mlxplat_dmi_msn274x_matched,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
@@ -1916,42 +2030,6 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
DMI_MATCH(DMI_PRODUCT_NAME, "MSN38"),
},
},
- {
- .callback = mlxplat_dmi_default_matched,
- .matches = {
- DMI_MATCH(DMI_BOARD_NAME, "VMOD0001"),
- },
- },
- {
- .callback = mlxplat_dmi_msn21xx_matched,
- .matches = {
- DMI_MATCH(DMI_BOARD_NAME, "VMOD0002"),
- },
- },
- {
- .callback = mlxplat_dmi_msn274x_matched,
- .matches = {
- DMI_MATCH(DMI_BOARD_NAME, "VMOD0003"),
- },
- },
- {
- .callback = mlxplat_dmi_msn201x_matched,
- .matches = {
- DMI_MATCH(DMI_BOARD_NAME, "VMOD0004"),
- },
- },
- {
- .callback = mlxplat_dmi_qmb7xx_matched,
- .matches = {
- DMI_MATCH(DMI_BOARD_NAME, "VMOD0005"),
- },
- },
- {
- .callback = mlxplat_dmi_qmb7xx_matched,
- .matches = {
- DMI_MATCH(DMI_BOARD_NAME, "VMOD0007"),
- },
- },
{ }
};
@@ -2018,13 +2096,36 @@ static int __init mlxplat_init(void)
}
platform_set_drvdata(mlxplat_dev, priv);
+ mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev,
+ mlxplat_lpc_resources[1].start, 1);
+ if (!mlxplat_mlxcpld_regmap_ctx.base) {
+ err = -ENOMEM;
+ goto fail_alloc;
+ }
+
+ if (!mlxplat_regmap_config)
+ mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config;
+
+ priv->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL,
+ &mlxplat_mlxcpld_regmap_ctx,
+ mlxplat_regmap_config);
+ if (IS_ERR(priv->regmap)) {
+ err = PTR_ERR(priv->regmap);
+ goto fail_alloc;
+ }
+
err = mlxplat_mlxcpld_verify_bus_topology(&nr);
if (nr < 0)
goto fail_alloc;
nr = (nr == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM) ? -1 : nr;
- priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", nr,
- NULL, 0);
+ if (mlxplat_i2c)
+ mlxplat_i2c->regmap = priv->regmap;
+ priv->pdev_i2c = platform_device_register_resndata(
+ &mlxplat_dev->dev, "i2c_mlxcpld",
+ nr, mlxplat_mlxcpld_resources,
+ ARRAY_SIZE(mlxplat_mlxcpld_resources),
+ mlxplat_i2c, sizeof(*mlxplat_i2c));
if (IS_ERR(priv->pdev_i2c)) {
err = PTR_ERR(priv->pdev_i2c);
goto fail_alloc;
@@ -2042,21 +2143,8 @@ static int __init mlxplat_init(void)
}
}
- mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev,
- mlxplat_lpc_resources[1].start, 1);
- if (!mlxplat_mlxcpld_regmap_ctx.base) {
- err = -ENOMEM;
- goto fail_platform_mux_register;
- }
-
- mlxplat_hotplug->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL,
- &mlxplat_mlxcpld_regmap_ctx,
- &mlxplat_mlxcpld_regmap_config);
- if (IS_ERR(mlxplat_hotplug->regmap)) {
- err = PTR_ERR(mlxplat_hotplug->regmap);
- goto fail_platform_mux_register;
- }
-
+ /* Add hotplug driver */
+ mlxplat_hotplug->regmap = priv->regmap;
priv->pdev_hotplug = platform_device_register_resndata(
&mlxplat_dev->dev, "mlxreg-hotplug",
PLATFORM_DEVID_NONE,
@@ -2069,16 +2157,16 @@ static int __init mlxplat_init(void)
}
/* Set default registers. */
- for (j = 0; j < mlxplat_mlxcpld_regmap_config.num_reg_defaults; j++) {
- err = regmap_write(mlxplat_hotplug->regmap,
- mlxplat_mlxcpld_regmap_default[j].reg,
- mlxplat_mlxcpld_regmap_default[j].def);
+ for (j = 0; j < mlxplat_regmap_config->num_reg_defaults; j++) {
+ err = regmap_write(priv->regmap,
+ mlxplat_regmap_config->reg_defaults[j].reg,
+ mlxplat_regmap_config->reg_defaults[j].def);
if (err)
goto fail_platform_mux_register;
}
/* Add LED driver. */
- mlxplat_led->regmap = mlxplat_hotplug->regmap;
+ mlxplat_led->regmap = priv->regmap;
priv->pdev_led = platform_device_register_resndata(
&mlxplat_dev->dev, "leds-mlxreg",
PLATFORM_DEVID_NONE, NULL, 0,
@@ -2090,7 +2178,7 @@ static int __init mlxplat_init(void)
/* Add registers io access driver. */
if (mlxplat_regs_io) {
- mlxplat_regs_io->regmap = mlxplat_hotplug->regmap;
+ mlxplat_regs_io->regmap = priv->regmap;
priv->pdev_io_regs = platform_device_register_resndata(
&mlxplat_dev->dev, "mlxreg-io",
PLATFORM_DEVID_NONE, NULL, 0,
@@ -2104,7 +2192,7 @@ static int __init mlxplat_init(void)
/* Add FAN driver. */
if (mlxplat_fan) {
- mlxplat_fan->regmap = mlxplat_hotplug->regmap;
+ mlxplat_fan->regmap = priv->regmap;
priv->pdev_fan = platform_device_register_resndata(
&mlxplat_dev->dev, "mlxreg-fan",
PLATFORM_DEVID_NONE, NULL, 0,
@@ -2119,7 +2207,7 @@ static int __init mlxplat_init(void)
/* Add WD drivers. */
for (j = 0; j < MLXPLAT_CPLD_WD_MAX_DEVS; j++) {
if (mlxplat_wd_data[j]) {
- mlxplat_wd_data[j]->regmap = mlxplat_hotplug->regmap;
+ mlxplat_wd_data[j]->regmap = priv->regmap;
priv->pdev_wd[j] = platform_device_register_resndata(
&mlxplat_dev->dev, "mlx-wdt",
j, NULL, 0,
@@ -2133,8 +2221,8 @@ static int __init mlxplat_init(void)
}
/* Sync registers with hardware. */
- regcache_mark_dirty(mlxplat_hotplug->regmap);
- err = regcache_sync(mlxplat_hotplug->regmap);
+ regcache_mark_dirty(priv->regmap);
+ err = regcache_sync(priv->regmap);
if (err)
goto fail_platform_wd_register;
diff --git a/drivers/platform/x86/pcengines-apuv2.c b/drivers/platform/x86/pcengines-apuv2.c
index c1ca931e1fab..b0d3110ae378 100644
--- a/drivers/platform/x86/pcengines-apuv2.c
+++ b/drivers/platform/x86/pcengines-apuv2.c
@@ -77,7 +77,7 @@ static const struct gpio_led_platform_data apu2_leds_pdata = {
.leds = apu2_leds,
};
-struct gpiod_lookup_table gpios_led_table = {
+static struct gpiod_lookup_table gpios_led_table = {
.dev_id = "leds-gpio",
.table = {
GPIO_LOOKUP_IDX(AMD_FCH_GPIO_DRIVER_NAME, APU2_GPIO_LINE_LED1,
@@ -110,7 +110,7 @@ static const struct gpio_keys_platform_data apu2_keys_pdata = {
.name = "apu2-keys",
};
-struct gpiod_lookup_table gpios_key_table = {
+static struct gpiod_lookup_table gpios_key_table = {
.dev_id = "gpio-keys-polled",
.table = {
GPIO_LOOKUP_IDX(AMD_FCH_GPIO_DRIVER_NAME, APU2_GPIO_LINE_MODESW,
diff --git a/drivers/platform/x86/peaq-wmi.c b/drivers/platform/x86/peaq-wmi.c
index 9b9e1f39bbfb..fdeb3624c529 100644
--- a/drivers/platform/x86/peaq-wmi.c
+++ b/drivers/platform/x86/peaq-wmi.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* PEAQ 2-in-1 WMI hotkey driver
* Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
- *
- * 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.
*/
#include <linux/acpi.h>
diff --git a/drivers/platform/x86/pmc_atom.c b/drivers/platform/x86/pmc_atom.c
index be802fd2182d..aa53648a2214 100644
--- a/drivers/platform/x86/pmc_atom.c
+++ b/drivers/platform/x86/pmc_atom.c
@@ -341,45 +341,24 @@ static int pmc_sleep_tmr_show(struct seq_file *s, void *unused)
DEFINE_SHOW_ATTRIBUTE(pmc_sleep_tmr);
-static void pmc_dbgfs_unregister(struct pmc_dev *pmc)
+static void pmc_dbgfs_register(struct pmc_dev *pmc)
{
- debugfs_remove_recursive(pmc->dbgfs_dir);
-}
-
-static int pmc_dbgfs_register(struct pmc_dev *pmc)
-{
- struct dentry *dir, *f;
+ struct dentry *dir;
dir = debugfs_create_dir("pmc_atom", NULL);
- if (!dir)
- return -ENOMEM;
pmc->dbgfs_dir = dir;
- f = debugfs_create_file("dev_state", S_IFREG | S_IRUGO,
- dir, pmc, &pmc_dev_state_fops);
- if (!f)
- goto err;
-
- f = debugfs_create_file("pss_state", S_IFREG | S_IRUGO,
- dir, pmc, &pmc_pss_state_fops);
- if (!f)
- goto err;
-
- f = debugfs_create_file("sleep_state", S_IFREG | S_IRUGO,
- dir, pmc, &pmc_sleep_tmr_fops);
- if (!f)
- goto err;
-
- return 0;
-err:
- pmc_dbgfs_unregister(pmc);
- return -ENODEV;
+ debugfs_create_file("dev_state", S_IFREG | S_IRUGO, dir, pmc,
+ &pmc_dev_state_fops);
+ debugfs_create_file("pss_state", S_IFREG | S_IRUGO, dir, pmc,
+ &pmc_pss_state_fops);
+ debugfs_create_file("sleep_state", S_IFREG | S_IRUGO, dir, pmc,
+ &pmc_sleep_tmr_fops);
}
#else
-static int pmc_dbgfs_register(struct pmc_dev *pmc)
+static void pmc_dbgfs_register(struct pmc_dev *pmc)
{
- return 0;
}
#endif /* CONFIG_DEBUG_FS */
@@ -414,6 +393,14 @@ static const struct dmi_system_id critclk_systems[] = {
},
{
/* pmc_plt_clk* - are used for ethernet controllers */
+ .ident = "Beckhoff CB4063",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Beckhoff Automation"),
+ DMI_MATCH(DMI_BOARD_NAME, "CB4063"),
+ },
+ },
+ {
+ /* pmc_plt_clk* - are used for ethernet controllers */
.ident = "Beckhoff CB6263",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Beckhoff Automation"),
@@ -491,9 +478,7 @@ static int pmc_setup_dev(struct pci_dev *pdev, const struct pci_device_id *ent)
/* PMC hardware registers setup */
pmc_hw_reg_setup(pmc);
- ret = pmc_dbgfs_register(pmc);
- if (ret)
- dev_warn(&pdev->dev, "debugfs register failed\n");
+ pmc_dbgfs_register(pmc);
/* Register platform clocks - PMC_PLT_CLK [0..5] */
ret = pmc_setup_clks(pdev, pmc->regmap, data);
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c
index 7b160ee98115..9b6a93ff41ff 100644
--- a/drivers/platform/x86/samsung-laptop.c
+++ b/drivers/platform/x86/samsung-laptop.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Samsung Laptop driver
*
* Copyright (C) 2009,2011 Greg Kroah-Hartman (gregkh@suse.de)
* Copyright (C) 2009,2011 Novell 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.
- *
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -1280,15 +1276,12 @@ static void samsung_debugfs_exit(struct samsung_laptop *samsung)
debugfs_remove_recursive(samsung->debug.root);
}
-static int samsung_debugfs_init(struct samsung_laptop *samsung)
+static void samsung_debugfs_init(struct samsung_laptop *samsung)
{
- struct dentry *dent;
+ struct dentry *root;
- samsung->debug.root = debugfs_create_dir("samsung-laptop", NULL);
- if (!samsung->debug.root) {
- pr_err("failed to create debugfs directory");
- goto error_debugfs;
- }
+ root = debugfs_create_dir("samsung-laptop", NULL);
+ samsung->debug.root = root;
samsung->debug.f0000_wrapper.data = samsung->f0000_segment;
samsung->debug.f0000_wrapper.size = 0xffff;
@@ -1299,60 +1292,24 @@ static int samsung_debugfs_init(struct samsung_laptop *samsung)
samsung->debug.sdiag_wrapper.data = samsung->sdiag;
samsung->debug.sdiag_wrapper.size = strlen(samsung->sdiag);
- dent = debugfs_create_u16("command", S_IRUGO | S_IWUSR,
- samsung->debug.root, &samsung->debug.command);
- if (!dent)
- goto error_debugfs;
-
- dent = debugfs_create_u32("d0", S_IRUGO | S_IWUSR, samsung->debug.root,
- &samsung->debug.data.d0);
- if (!dent)
- goto error_debugfs;
-
- dent = debugfs_create_u32("d1", S_IRUGO | S_IWUSR, samsung->debug.root,
- &samsung->debug.data.d1);
- if (!dent)
- goto error_debugfs;
-
- dent = debugfs_create_u16("d2", S_IRUGO | S_IWUSR, samsung->debug.root,
- &samsung->debug.data.d2);
- if (!dent)
- goto error_debugfs;
-
- dent = debugfs_create_u8("d3", S_IRUGO | S_IWUSR, samsung->debug.root,
- &samsung->debug.data.d3);
- if (!dent)
- goto error_debugfs;
-
- dent = debugfs_create_blob("data", S_IRUGO | S_IWUSR,
- samsung->debug.root,
- &samsung->debug.data_wrapper);
- if (!dent)
- goto error_debugfs;
-
- dent = debugfs_create_blob("f0000_segment", S_IRUSR | S_IWUSR,
- samsung->debug.root,
- &samsung->debug.f0000_wrapper);
- if (!dent)
- goto error_debugfs;
-
- dent = debugfs_create_file("call", S_IFREG | S_IRUGO,
- samsung->debug.root, samsung,
- &samsung_laptop_call_fops);
- if (!dent)
- goto error_debugfs;
-
- dent = debugfs_create_blob("sdiag", S_IRUGO | S_IWUSR,
- samsung->debug.root,
- &samsung->debug.sdiag_wrapper);
- if (!dent)
- goto error_debugfs;
-
- return 0;
-
-error_debugfs:
- samsung_debugfs_exit(samsung);
- return -ENOMEM;
+ debugfs_create_u16("command", S_IRUGO | S_IWUSR, root,
+ &samsung->debug.command);
+ debugfs_create_u32("d0", S_IRUGO | S_IWUSR, root,
+ &samsung->debug.data.d0);
+ debugfs_create_u32("d1", S_IRUGO | S_IWUSR, root,
+ &samsung->debug.data.d1);
+ debugfs_create_u16("d2", S_IRUGO | S_IWUSR, root,
+ &samsung->debug.data.d2);
+ debugfs_create_u8("d3", S_IRUGO | S_IWUSR, root,
+ &samsung->debug.data.d3);
+ debugfs_create_blob("data", S_IRUGO | S_IWUSR, root,
+ &samsung->debug.data_wrapper);
+ debugfs_create_blob("f0000_segment", S_IRUSR | S_IWUSR, root,
+ &samsung->debug.f0000_wrapper);
+ debugfs_create_file("call", S_IFREG | S_IRUGO, root, samsung,
+ &samsung_laptop_call_fops);
+ debugfs_create_blob("sdiag", S_IRUGO | S_IWUSR, root,
+ &samsung->debug.sdiag_wrapper);
}
static void samsung_sabi_exit(struct samsung_laptop *samsung)
@@ -1745,9 +1702,7 @@ static int __init samsung_init(void)
if (ret)
goto error_lid_handling;
- ret = samsung_debugfs_init(samsung);
- if (ret)
- goto error_debugfs;
+ samsung_debugfs_init(samsung);
samsung->pm_nb.notifier_call = samsung_pm_notification;
register_pm_notifier(&samsung->pm_nb);
@@ -1755,8 +1710,6 @@ static int __init samsung_init(void)
samsung_platform_device = samsung->platform_device;
return ret;
-error_debugfs:
- samsung_lid_handling_exit(samsung);
error_lid_handling:
samsung_leds_exit(samsung);
error_leds:
diff --git a/drivers/platform/x86/samsung-q10.c b/drivers/platform/x86/samsung-q10.c
index a2fb7fbc3273..6eb08b539311 100644
--- a/drivers/platform/x86/samsung-q10.c
+++ b/drivers/platform/x86/samsung-q10.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for Samsung Q10 and related laptops: controls the backlight
*
* Copyright (c) 2011 Frederick van der Wyck <fvanderwyck@gmail.com>
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/platform/x86/toshiba_bluetooth.c b/drivers/platform/x86/toshiba_bluetooth.c
index be1d137c6079..57a5dc60c58a 100644
--- a/drivers/platform/x86/toshiba_bluetooth.c
+++ b/drivers/platform/x86/toshiba_bluetooth.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Toshiba Bluetooth Enable Driver
*
@@ -6,10 +7,6 @@
*
* Thanks to Matthew Garrett for background info on ACPI innards which
* normal people aren't meant to understand :-)
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c
index b662cb2d7cd5..4370e4add83a 100644
--- a/drivers/platform/x86/touchscreen_dmi.c
+++ b/drivers/platform/x86/touchscreen_dmi.c
@@ -87,6 +87,22 @@ static const struct ts_dmi_data chuwi_hi10_air_data = {
.properties = chuwi_hi10_air_props,
};
+static const struct property_entry chuwi_hi10_plus_props[] = {
+ PROPERTY_ENTRY_U32("touchscreen-min-x", 0),
+ PROPERTY_ENTRY_U32("touchscreen-min-y", 5),
+ PROPERTY_ENTRY_U32("touchscreen-size-x", 1914),
+ PROPERTY_ENTRY_U32("touchscreen-size-y", 1283),
+ PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-chuwi-hi10plus.fw"),
+ PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+ PROPERTY_ENTRY_BOOL("silead,home-button"),
+ { }
+};
+
+static const struct ts_dmi_data chuwi_hi10_plus_data = {
+ .acpi_name = "MSSL0017:00",
+ .properties = chuwi_hi10_plus_props,
+};
+
static const struct property_entry chuwi_vi8_props[] = {
PROPERTY_ENTRY_U32("touchscreen-min-x", 4),
PROPERTY_ENTRY_U32("touchscreen-min-y", 6),
@@ -597,11 +613,21 @@ static const struct dmi_system_id touchscreen_dmi_table[] = {
/* Chuwi Hi10 Air */
.driver_data = (void *)&chuwi_hi10_air_data,
.matches = {
- DMI_MATCH(DMI_BOARD_VENDOR, "Hampoo"),
+ DMI_MATCH(DMI_SYS_VENDOR, "CHUWI INNOVATION AND TECHNOLOGY(SHENZHEN)CO.LTD"),
+ DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"),
DMI_MATCH(DMI_PRODUCT_SKU, "P1W6_C109D_B"),
},
},
{
+ /* Chuwi Hi10 Plus (CWI527) */
+ .driver_data = (void *)&chuwi_hi10_plus_data,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Hampoo"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Hi10 plus tablet"),
+ DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"),
+ },
+ },
+ {
/* Chuwi Vi8 (CWI506) */
.driver_data = (void *)&chuwi_vi8_data,
.matches = {
diff --git a/drivers/platform/x86/wmi-bmof.c b/drivers/platform/x86/wmi-bmof.c
index c3f63411f9ab..66b434d6307f 100644
--- a/drivers/platform/x86/wmi-bmof.c
+++ b/drivers/platform/x86/wmi-bmof.c
@@ -46,7 +46,7 @@ read_bmof(struct file *filp, struct kobject *kobj,
return count;
}
-static int wmi_bmof_probe(struct wmi_device *wdev)
+static int wmi_bmof_probe(struct wmi_device *wdev, const void *context)
{
struct bmof_priv *priv;
int ret;
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index 22f4b92c5da4..784cea8572c2 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -129,6 +129,28 @@ static bool find_guid(const char *guid_string, struct wmi_block **out)
return false;
}
+static const void *find_guid_context(struct wmi_block *wblock,
+ struct wmi_driver *wdriver)
+{
+ const struct wmi_device_id *id;
+ uuid_le guid_input;
+
+ if (wblock == NULL || wdriver == NULL)
+ return NULL;
+ if (wdriver->id_table == NULL)
+ return NULL;
+
+ id = wdriver->id_table;
+ while (*id->guid_string) {
+ if (uuid_le_to_bin(id->guid_string, &guid_input))
+ continue;
+ if (!memcmp(wblock->gblock.guid, &guid_input, 16))
+ return id->context;
+ id++;
+ }
+ return NULL;
+}
+
static int get_subobj_info(acpi_handle handle, const char *pathname,
struct acpi_device_info **info)
{
@@ -618,6 +640,25 @@ bool wmi_has_guid(const char *guid_string)
}
EXPORT_SYMBOL_GPL(wmi_has_guid);
+/**
+ * wmi_get_acpi_device_uid() - Get _UID name of ACPI device that defines GUID
+ * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
+ *
+ * Find the _UID of ACPI device associated with this WMI GUID.
+ *
+ * Return: The ACPI _UID field value or NULL if the WMI GUID was not found
+ */
+char *wmi_get_acpi_device_uid(const char *guid_string)
+{
+ struct wmi_block *wblock = NULL;
+
+ if (!find_guid(guid_string, &wblock))
+ return NULL;
+
+ return acpi_device_uid(wblock->acpi_device);
+}
+EXPORT_SYMBOL_GPL(wmi_get_acpi_device_uid);
+
static struct wmi_block *dev_to_wblock(struct device *dev)
{
return container_of(dev, struct wmi_block, dev.dev);
@@ -887,7 +928,8 @@ static int wmi_dev_probe(struct device *dev)
dev_warn(dev, "failed to enable device -- probing anyway\n");
if (wdriver->probe) {
- ret = wdriver->probe(dev_to_wdev(dev));
+ ret = wdriver->probe(dev_to_wdev(dev),
+ find_guid_context(wblock, wdriver));
if (ret != 0)
goto probe_failure;
}
diff --git a/drivers/platform/x86/xiaomi-wmi.c b/drivers/platform/x86/xiaomi-wmi.c
new file mode 100644
index 000000000000..601cbb282f54
--- /dev/null
+++ b/drivers/platform/x86/xiaomi-wmi.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0
+/* WMI driver for Xiaomi Laptops */
+
+#include <linux/acpi.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/wmi.h>
+
+#include <uapi/linux/input-event-codes.h>
+
+#define XIAOMI_KEY_FN_ESC_0 "A2095CCE-0491-44E7-BA27-F8ED8F88AA86"
+#define XIAOMI_KEY_FN_ESC_1 "7BBE8E39-B486-473D-BA13-66F75C5805CD"
+#define XIAOMI_KEY_FN_FN "409B028D-F06B-4C7C-8BBB-EE133A6BD87E"
+#define XIAOMI_KEY_CAPSLOCK "83FE7607-053A-4644-822A-21532C621FC7"
+#define XIAOMI_KEY_FN_F7 "76E9027C-95D0-4180-8692-DA6747DD1C2D"
+
+#define XIAOMI_DEVICE(guid, key) \
+ .guid_string = (guid), \
+ .context = &(const unsigned int){key}
+
+struct xiaomi_wmi {
+ struct input_dev *input_dev;
+ unsigned int key_code;
+};
+
+int xiaomi_wmi_probe(struct wmi_device *wdev, const void *context)
+{
+ struct xiaomi_wmi *data;
+
+ if (wdev == NULL || context == NULL)
+ return -EINVAL;
+
+ data = devm_kzalloc(&wdev->dev, sizeof(struct xiaomi_wmi), GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+ dev_set_drvdata(&wdev->dev, data);
+
+ data->input_dev = devm_input_allocate_device(&wdev->dev);
+ if (data->input_dev == NULL)
+ return -ENOMEM;
+ data->input_dev->name = "Xiaomi WMI keys";
+ data->input_dev->phys = "wmi/input0";
+
+ data->key_code = *((const unsigned int *)context);
+ set_bit(EV_KEY, data->input_dev->evbit);
+ set_bit(data->key_code, data->input_dev->keybit);
+
+ return input_register_device(data->input_dev);
+}
+
+void xiaomi_wmi_notify(struct wmi_device *wdev, union acpi_object *dummy)
+{
+ struct xiaomi_wmi *data;
+
+ if (wdev == NULL)
+ return;
+
+ data = dev_get_drvdata(&wdev->dev);
+ if (data == NULL)
+ return;
+
+ input_report_key(data->input_dev, data->key_code, 1);
+ input_sync(data->input_dev);
+ input_report_key(data->input_dev, data->key_code, 0);
+ input_sync(data->input_dev);
+}
+
+static const struct wmi_device_id xiaomi_wmi_id_table[] = {
+ // { XIAOMI_DEVICE(XIAOMI_KEY_FN_ESC_0, KEY_FN_ESC) },
+ // { XIAOMI_DEVICE(XIAOMI_KEY_FN_ESC_1, KEY_FN_ESC) },
+ { XIAOMI_DEVICE(XIAOMI_KEY_FN_FN, KEY_PROG1) },
+ // { XIAOMI_DEVICE(XIAOMI_KEY_CAPSLOCK, KEY_CAPSLOCK) },
+ { XIAOMI_DEVICE(XIAOMI_KEY_FN_F7, KEY_CUT) },
+
+ /* Terminating entry */
+ { }
+};
+
+static struct wmi_driver xiaomi_wmi_driver = {
+ .driver = {
+ .name = "xiaomi-wmi",
+ },
+ .id_table = xiaomi_wmi_id_table,
+ .probe = xiaomi_wmi_probe,
+ .notify = xiaomi_wmi_notify,
+};
+module_wmi_driver(xiaomi_wmi_driver);
+
+MODULE_DEVICE_TABLE(wmi, xiaomi_wmi_id_table);
+MODULE_AUTHOR("Mattias Jacobsson");
+MODULE_DESCRIPTION("Xiaomi WMI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pnp/isapnp/Kconfig b/drivers/pnp/isapnp/Kconfig
index 4b58a3dcb52b..d0479a563123 100644
--- a/drivers/pnp/isapnp/Kconfig
+++ b/drivers/pnp/isapnp/Kconfig
@@ -7,6 +7,6 @@ config ISAPNP
depends on ISA || COMPILE_TEST
help
Say Y here if you would like support for ISA Plug and Play devices.
- Some information is in <file:Documentation/isapnp.txt>.
+ Some information is in <file:Documentation/driver-api/isapnp.rst>.
If unsure, say Y.
diff --git a/drivers/power/avs/smartreflex.c b/drivers/power/avs/smartreflex.c
index c96c01e09740..4684e7df833a 100644
--- a/drivers/power/avs/smartreflex.c
+++ b/drivers/power/avs/smartreflex.c
@@ -899,38 +899,19 @@ static int omap_sr_probe(struct platform_device *pdev)
}
dev_info(&pdev->dev, "%s: SmartReflex driver initialized\n", __func__);
- if (!sr_dbg_dir) {
+ if (!sr_dbg_dir)
sr_dbg_dir = debugfs_create_dir("smartreflex", NULL);
- if (IS_ERR_OR_NULL(sr_dbg_dir)) {
- ret = PTR_ERR(sr_dbg_dir);
- pr_err("%s:sr debugfs dir creation failed(%d)\n",
- __func__, ret);
- goto err_list_del;
- }
- }
sr_info->dbg_dir = debugfs_create_dir(sr_info->name, sr_dbg_dir);
- if (IS_ERR_OR_NULL(sr_info->dbg_dir)) {
- dev_err(&pdev->dev, "%s: Unable to create debugfs directory\n",
- __func__);
- ret = PTR_ERR(sr_info->dbg_dir);
- goto err_debugfs;
- }
- (void) debugfs_create_file("autocomp", S_IRUGO | S_IWUSR,
- sr_info->dbg_dir, (void *)sr_info, &pm_sr_fops);
- (void) debugfs_create_x32("errweight", S_IRUGO, sr_info->dbg_dir,
- &sr_info->err_weight);
- (void) debugfs_create_x32("errmaxlimit", S_IRUGO, sr_info->dbg_dir,
- &sr_info->err_maxlimit);
+ debugfs_create_file("autocomp", S_IRUGO | S_IWUSR, sr_info->dbg_dir,
+ (void *)sr_info, &pm_sr_fops);
+ debugfs_create_x32("errweight", S_IRUGO, sr_info->dbg_dir,
+ &sr_info->err_weight);
+ debugfs_create_x32("errmaxlimit", S_IRUGO, sr_info->dbg_dir,
+ &sr_info->err_maxlimit);
nvalue_dir = debugfs_create_dir("nvalue", sr_info->dbg_dir);
- if (IS_ERR_OR_NULL(nvalue_dir)) {
- dev_err(&pdev->dev, "%s: Unable to create debugfs directory for n-values\n",
- __func__);
- ret = PTR_ERR(nvalue_dir);
- goto err_debugfs;
- }
if (sr_info->nvalue_count == 0 || !sr_info->nvalue_table) {
dev_warn(&pdev->dev, "%s: %s: No Voltage table for the corresponding vdd. Cannot create debugfs entries for n-values\n",
@@ -945,12 +926,12 @@ static int omap_sr_probe(struct platform_device *pdev)
snprintf(name, sizeof(name), "volt_%lu",
sr_info->nvalue_table[i].volt_nominal);
- (void) debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir,
- &(sr_info->nvalue_table[i].nvalue));
+ debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir,
+ &(sr_info->nvalue_table[i].nvalue));
snprintf(name, sizeof(name), "errminlimit_%lu",
sr_info->nvalue_table[i].volt_nominal);
- (void) debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir,
- &(sr_info->nvalue_table[i].errminlimit));
+ debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir,
+ &(sr_info->nvalue_table[i].errminlimit));
}
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index 980951dff834..a564237278ff 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -246,5 +246,15 @@ config POWER_RESET_SC27XX
PMICs includes the SC2720, SC2721, SC2723, SC2730
and SC2731 chips.
+config NVMEM_REBOOT_MODE
+ tristate "Generic NVMEM reboot mode driver"
+ depends on OF
+ select REBOOT_MODE
+ help
+ Say y here will enable reboot mode driver. This will
+ get reboot mode arguments and store it in a NVMEM cell,
+ then the bootloader can read it and take different
+ action according to the mode.
+
endif
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index 0aebee954ac1..85da3198e4e0 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -29,3 +29,4 @@ obj-$(CONFIG_POWER_RESET_ZX) += zx-reboot.o
obj-$(CONFIG_REBOOT_MODE) += reboot-mode.o
obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o
obj-$(CONFIG_POWER_RESET_SC27XX) += sc27xx-poweroff.o
+obj-$(CONFIG_NVMEM_REBOOT_MODE) += nvmem-reboot-mode.o
diff --git a/drivers/power/reset/arm-versatile-reboot.c b/drivers/power/reset/arm-versatile-reboot.c
index 06d34ab47df5..08d0a07b58ef 100644
--- a/drivers/power/reset/arm-versatile-reboot.c
+++ b/drivers/power/reset/arm-versatile-reboot.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 Linaro Ltd.
*
* Author: Linus Walleij <linus.walleij@linaro.org>
- *
- * 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.
- *
*/
#include <linux/init.h>
#include <linux/mfd/syscon.h>
diff --git a/drivers/power/reset/gpio-poweroff.c b/drivers/power/reset/gpio-poweroff.c
index 52525b6c18db..6a4bbb506551 100644
--- a/drivers/power/reset/gpio-poweroff.c
+++ b/drivers/power/reset/gpio-poweroff.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Toggles a GPIO pin to power down a device
*
@@ -5,11 +6,6 @@
* Andrew Lunn <andrew@lunn.ch>
*
* Copyright (C) 2012 Jamie Lentin
- *
- * 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.
- *
*/
#include <linux/kernel.h>
#include <linux/init.h>
diff --git a/drivers/power/reset/hisi-reboot.c b/drivers/power/reset/hisi-reboot.c
index f69387e12c1e..0ba5fdce186f 100644
--- a/drivers/power/reset/hisi-reboot.c
+++ b/drivers/power/reset/hisi-reboot.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Hisilicon SoC reset code
*
@@ -5,10 +6,6 @@
* Copyright (c) 2014 Linaro Ltd.
*
* Author: Haojian Zhuang <haojian.zhuang@linaro.org>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/power/reset/keystone-reset.c b/drivers/power/reset/keystone-reset.c
index 09380857a1c5..ad11faae19c5 100644
--- a/drivers/power/reset/keystone-reset.c
+++ b/drivers/power/reset/keystone-reset.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TI keystone reboot driver
*
* Copyright (C) 2014 Texas Instruments Incorporated. http://www.ti.com/
*
* Author: Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>
- *
- * 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.
*/
#include <linux/io.h>
diff --git a/drivers/power/reset/nvmem-reboot-mode.c b/drivers/power/reset/nvmem-reboot-mode.c
new file mode 100644
index 000000000000..e229308d43e2
--- /dev/null
+++ b/drivers/power/reset/nvmem-reboot-mode.c
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) Vaisala Oyj. All rights reserved.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/platform_device.h>
+#include <linux/reboot-mode.h>
+
+struct nvmem_reboot_mode {
+ struct reboot_mode_driver reboot;
+ struct nvmem_cell *cell;
+};
+
+static int nvmem_reboot_mode_write(struct reboot_mode_driver *reboot,
+ unsigned int magic)
+{
+ int ret;
+ struct nvmem_reboot_mode *nvmem_rbm;
+
+ nvmem_rbm = container_of(reboot, struct nvmem_reboot_mode, reboot);
+
+ ret = nvmem_cell_write(nvmem_rbm->cell, &magic, sizeof(magic));
+ if (ret < 0)
+ dev_err(reboot->dev, "update reboot mode bits failed\n");
+
+ return ret;
+}
+
+static int nvmem_reboot_mode_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct nvmem_reboot_mode *nvmem_rbm;
+
+ nvmem_rbm = devm_kzalloc(&pdev->dev, sizeof(*nvmem_rbm), GFP_KERNEL);
+ if (!nvmem_rbm)
+ return -ENOMEM;
+
+ nvmem_rbm->reboot.dev = &pdev->dev;
+ nvmem_rbm->reboot.write = nvmem_reboot_mode_write;
+
+ nvmem_rbm->cell = devm_nvmem_cell_get(&pdev->dev, "reboot-mode");
+ if (IS_ERR(nvmem_rbm->cell)) {
+ dev_err(&pdev->dev, "failed to get the nvmem cell reboot-mode\n");
+ return PTR_ERR(nvmem_rbm->cell);
+ }
+
+ ret = devm_reboot_mode_register(&pdev->dev, &nvmem_rbm->reboot);
+ if (ret)
+ dev_err(&pdev->dev, "can't register reboot mode\n");
+
+ return ret;
+}
+
+static const struct of_device_id nvmem_reboot_mode_of_match[] = {
+ { .compatible = "nvmem-reboot-mode" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, nvmem_reboot_mode_of_match);
+
+static struct platform_driver nvmem_reboot_mode_driver = {
+ .probe = nvmem_reboot_mode_probe,
+ .driver = {
+ .name = "nvmem-reboot-mode",
+ .of_match_table = nvmem_reboot_mode_of_match,
+ },
+};
+module_platform_driver(nvmem_reboot_mode_driver);
+
+MODULE_AUTHOR("Nandor Han <nandor.han@vaisala.com>");
+MODULE_DESCRIPTION("NVMEM reboot mode driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/reset/qcom-pon.c b/drivers/power/reset/qcom-pon.c
index 3fa1642d4c54..22a743a0bf28 100644
--- a/drivers/power/reset/qcom-pon.c
+++ b/drivers/power/reset/qcom-pon.c
@@ -14,11 +14,15 @@
#define PON_SOFT_RB_SPARE 0x8f
+#define GEN1_REASON_SHIFT 2
+#define GEN2_REASON_SHIFT 1
+
struct pm8916_pon {
struct device *dev;
struct regmap *regmap;
u32 baseaddr;
struct reboot_mode_driver reboot_mode;
+ long reason_shift;
};
static int pm8916_reboot_mode_write(struct reboot_mode_driver *reboot,
@@ -30,7 +34,7 @@ static int pm8916_reboot_mode_write(struct reboot_mode_driver *reboot,
ret = regmap_update_bits(pon->regmap,
pon->baseaddr + PON_SOFT_RB_SPARE,
- 0xfc, magic << 2);
+ 0xfc, magic << pon->reason_shift);
if (ret < 0)
dev_err(pon->dev, "update reboot mode bits failed\n");
@@ -60,6 +64,7 @@ static int pm8916_pon_probe(struct platform_device *pdev)
return error;
pon->reboot_mode.dev = &pdev->dev;
+ pon->reason_shift = (long)of_device_get_match_data(&pdev->dev);
pon->reboot_mode.write = pm8916_reboot_mode_write;
error = devm_reboot_mode_register(&pdev->dev, &pon->reboot_mode);
if (error) {
@@ -73,8 +78,9 @@ static int pm8916_pon_probe(struct platform_device *pdev)
}
static const struct of_device_id pm8916_pon_id_table[] = {
- { .compatible = "qcom,pm8916-pon" },
- { .compatible = "qcom,pms405-pon" },
+ { .compatible = "qcom,pm8916-pon", .data = (void *)GEN1_REASON_SHIFT },
+ { .compatible = "qcom,pms405-pon", .data = (void *)GEN1_REASON_SHIFT },
+ { .compatible = "qcom,pm8998-pon", .data = (void *)GEN2_REASON_SHIFT },
{ }
};
MODULE_DEVICE_TABLE(of, pm8916_pon_id_table);
diff --git a/drivers/power/reset/restart-poweroff.c b/drivers/power/reset/restart-poweroff.c
index 41b22c4d5236..d233daa5835b 100644
--- a/drivers/power/reset/restart-poweroff.c
+++ b/drivers/power/reset/restart-poweroff.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Power off by restarting and let u-boot keep hold of the machine
* until the user presses a button for example.
@@ -5,10 +6,6 @@
* Andrew Lunn <andrew@lunn.ch>
*
* Copyright (C) 2012 Andrew Lunn
- *
- * 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.
*/
#include <linux/kernel.h>
#include <linux/init.h>
diff --git a/drivers/power/reset/st-poweroff.c b/drivers/power/reset/st-poweroff.c
index 2046b31232f7..5ccaacffab54 100644
--- a/drivers/power/reset/st-poweroff.c
+++ b/drivers/power/reset/st-poweroff.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 STMicroelectronics
*
* Power off Restart driver, used in STMicroelectronics devices.
*
* Author: Christophe Kerello <christophe.kerello@st.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/power/reset/zx-reboot.c b/drivers/power/reset/zx-reboot.c
index 186901c96c01..457950833dba 100644
--- a/drivers/power/reset/zx-reboot.c
+++ b/drivers/power/reset/zx-reboot.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ZTE zx296702 SoC reset code
*
* Copyright (c) 2015 Linaro Ltd.
*
* Author: Jun Nie <jun.nie@linaro.org>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/power/supply/88pm860x_battery.c b/drivers/power/supply/88pm860x_battery.c
index 63c57dc82ac1..5ca047b3f58f 100644
--- a/drivers/power/supply/88pm860x_battery.c
+++ b/drivers/power/supply/88pm860x_battery.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Battery driver for Marvell 88PM860x PMIC
*
* Copyright (c) 2012 Marvell International Ltd.
* Author: Jett Zhou <jtzhou@marvell.com>
* Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/power/supply/88pm860x_charger.c b/drivers/power/supply/88pm860x_charger.c
index 2b82e44d9027..f21ce52fbc04 100644
--- a/drivers/power/supply/88pm860x_charger.c
+++ b/drivers/power/supply/88pm860x_charger.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Battery driver for Marvell 88PM860x PMIC
*
* Copyright (c) 2012 Marvell International Ltd.
* Author: Jett Zhou <jtzhou@marvell.com>
* Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index dd7da41f230c..5d91b5160b41 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -15,6 +15,20 @@ config POWER_SUPPLY_DEBUG
Say Y here to enable debugging messages for power supply class
and drivers.
+config POWER_SUPPLY_HWMON
+ bool
+ prompt "Expose power supply sensors as hwmon device"
+ depends on HWMON=y || HWMON=POWER_SUPPLY
+ default y
+ help
+ This options enables API that allows sensors found on a
+ power supply device (current, voltage, temperature) to be
+ exposed as a hwmon device.
+
+ Say 'Y' here if you want power supplies to
+ have hwmon sysfs interface too.
+
+
config PDA_POWER
tristate "Generic PDA/phone power driver"
depends on !S390
@@ -152,7 +166,7 @@ config BATTERY_PMU
config BATTERY_OLPC
tristate "One Laptop Per Child battery"
- depends on X86_32 && OLPC
+ depends on OLPC_EC
help
Say Y to enable support for the battery on the OLPC laptop.
@@ -689,4 +703,22 @@ config CHARGER_UCS1002
Say Y to enable support for Microchip UCS1002 Programmable
USB Port Power Controller with Charger Emulation.
+config CHARGER_BD70528
+ tristate "ROHM bd70528 charger driver"
+ depends on MFD_ROHM_BD70528
+ default n
+ help
+ Say Y here to enable support for getting battery status
+ information and altering charger configurations from charger
+ block of the ROHM BD70528 Power Management IC.
+
+config CHARGER_WILCO
+ tristate "Wilco EC based charger for ChromeOS"
+ depends on WILCO_EC
+ help
+ Say Y here to enable control of the charging routines performed
+ by the Embedded Controller on the Chromebook named Wilco. Further
+ information can be found in
+ Documentation/ABI/testing/sysfs-class-power-wilco
+
endif # POWER_SUPPLY
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index f208273f9686..96c2b74b36bf 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -6,6 +6,7 @@ power_supply-$(CONFIG_SYSFS) += power_supply_sysfs.o
power_supply-$(CONFIG_LEDS_TRIGGERS) += power_supply_leds.o
obj-$(CONFIG_POWER_SUPPLY) += power_supply.o
+obj-$(CONFIG_POWER_SUPPLY_HWMON) += power_supply_hwmon.o
obj-$(CONFIG_GENERIC_ADC_BATTERY) += generic-adc-battery.o
obj-$(CONFIG_PDA_POWER) += pda_power.o
@@ -90,3 +91,5 @@ obj-$(CONFIG_CHARGER_CROS_USBPD) += cros_usbpd-charger.o
obj-$(CONFIG_CHARGER_SC2731) += sc2731_charger.o
obj-$(CONFIG_FUEL_GAUGE_SC27XX) += sc27xx_fuel_gauge.o
obj-$(CONFIG_CHARGER_UCS1002) += ucs1002_power.o
+obj-$(CONFIG_CHARGER_BD70528) += bd70528-charger.o
+obj-$(CONFIG_CHARGER_WILCO) += wilco-charger.o
diff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c
index 8e117b31ba79..5f3eb6941d05 100644
--- a/drivers/power/supply/act8945a_charger.c
+++ b/drivers/power/supply/act8945a_charger.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Power supply driver for the Active-semi ACT8945A PMIC
*
* Copyright (C) 2015 Atmel Corporation
*
* Author: Wenyou Yang <wenyou.yang@atmel.com>
- *
- * 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.
- *
*/
#include <linux/interrupt.h>
#include <linux/module.h>
diff --git a/drivers/power/supply/bd70528-charger.c b/drivers/power/supply/bd70528-charger.c
new file mode 100644
index 000000000000..1bb32b7226d7
--- /dev/null
+++ b/drivers/power/supply/bd70528-charger.c
@@ -0,0 +1,743 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Copyright (C) 2018 ROHM Semiconductors
+//
+// power-supply driver for ROHM BD70528 PMIC
+
+/*
+ * BD70528 charger HW state machine.
+ *
+ * The thermal shutdown state is not drawn. From any other state but
+ * battery error and suspend it is possible to go to TSD/TMP states
+ * if temperature is out of bounds.
+ *
+ * CHG_RST = H
+ * or CHG_EN=L
+ * or (DCIN2_UVLO=L && DCIN1_UVLO=L)
+ * or (DCIN2_OVLO=H & DCIN1_UVKLO=L)
+ *
+ * +--------------+ +--------------+
+ * | | | |
+ * | Any state +-------> | Suspend |
+ * | | | |
+ * +--------------+ +------+-------+
+ * |
+ * CHG_EN = H && BAT_DET = H && |
+ * No errors (temp, bat_ov, UVLO, |
+ * OVLO...) |
+ * |
+ * BAT_OV or +---------v----------+
+ * (DBAT && TTRI) | |
+ * +-----------------+ Trickle Charge | <---------------+
+ * | | | |
+ * | +-------+------------+ |
+ * | | |
+ * | | ^ |
+ * | V_BAT > VTRI_TH | | VBAT < VTRI_TH - 50mV |
+ * | | | |
+ * | v | |
+ * | | |
+ * | BAT_OV or +----------+----+ |
+ * | (DBAT && TFST) | | |
+ * | +----------------+ Fast Charge | |
+ * | | | | |
+ * v v +----+----------+ |
+ * | |
+ *+----------------+ ILIM_DET=L | ^ ILIM_DET |
+ *| | & CV_DET=H | | or CV_DET=L |
+ *| Battery Error | & VBAT > | | or VBAT < VRECHG_TH |
+ *| | VRECHG_TH | | or IBAT > IFST/x |
+ *+----------------+ & IBAT < | | |
+ * IFST/x v | |
+ * ^ | |
+ * | +---------+-+ |
+ * | | | |
+ * +-------------------+ Top OFF | |
+ * BAT_OV = H or | | |
+ * (DBAT && TFST) +-----+-----+ |
+ * | |
+ * Stay top-off for 15s | |
+ * v |
+ * |
+ * +--------+ |
+ * | | |
+ * | Done +-------------------------+
+ * | |
+ * +--------+ VBAT < VRECHG_TH
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/rohm-bd70528.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+
+#define CHG_STAT_SUSPEND 0x0
+#define CHG_STAT_TRICKLE 0x1
+#define CHG_STAT_FAST 0x3
+#define CHG_STAT_TOPOFF 0xe
+#define CHG_STAT_DONE 0xf
+#define CHG_STAT_OTP_TRICKLE 0x10
+#define CHG_STAT_OTP_FAST 0x11
+#define CHG_STAT_OTP_DONE 0x12
+#define CHG_STAT_TSD_TRICKLE 0x20
+#define CHG_STAT_TSD_FAST 0x21
+#define CHG_STAT_TSD_TOPOFF 0x22
+#define CHG_STAT_BAT_ERR 0x7f
+
+static const char *bd70528_charger_model = "BD70528";
+static const char *bd70528_charger_manufacturer = "ROHM Semiconductors";
+
+#define BD_ERR_IRQ_HND(_name_, _wrn_) \
+static irqreturn_t bd0528_##_name_##_interrupt(int irq, void *arg) \
+{ \
+ struct power_supply *psy = (struct power_supply *)arg; \
+ \
+ power_supply_changed(psy); \
+ dev_err(&psy->dev, (_wrn_)); \
+ \
+ return IRQ_HANDLED; \
+}
+
+#define BD_INFO_IRQ_HND(_name_, _wrn_) \
+static irqreturn_t bd0528_##_name_##_interrupt(int irq, void *arg) \
+{ \
+ struct power_supply *psy = (struct power_supply *)arg; \
+ \
+ power_supply_changed(psy); \
+ dev_dbg(&psy->dev, (_wrn_)); \
+ \
+ return IRQ_HANDLED; \
+}
+
+#define BD_IRQ_HND(_name_) bd0528_##_name_##_interrupt
+
+struct bd70528_psy {
+ struct regmap *regmap;
+ struct device *dev;
+ struct power_supply *psy;
+};
+
+BD_ERR_IRQ_HND(BAT_OV_DET, "Battery overvoltage detected\n");
+BD_ERR_IRQ_HND(DBAT_DET, "Dead battery detected\n");
+BD_ERR_IRQ_HND(COLD_DET, "Battery cold\n");
+BD_ERR_IRQ_HND(HOT_DET, "Battery hot\n");
+BD_ERR_IRQ_HND(CHG_TSD, "Charger thermal shutdown\n");
+BD_ERR_IRQ_HND(DCIN2_OV_DET, "DCIN2 overvoltage detected\n");
+
+BD_INFO_IRQ_HND(BAT_OV_RES, "Battery voltage back to normal\n");
+BD_INFO_IRQ_HND(COLD_RES, "Battery temperature back to normal\n");
+BD_INFO_IRQ_HND(HOT_RES, "Battery temperature back to normal\n");
+BD_INFO_IRQ_HND(BAT_RMV, "Battery removed\n");
+BD_INFO_IRQ_HND(BAT_DET, "Battery detected\n");
+BD_INFO_IRQ_HND(DCIN2_OV_RES, "DCIN2 voltage back to normal\n");
+BD_INFO_IRQ_HND(DCIN2_RMV, "DCIN2 removed\n");
+BD_INFO_IRQ_HND(DCIN2_DET, "DCIN2 detected\n");
+BD_INFO_IRQ_HND(DCIN1_RMV, "DCIN1 removed\n");
+BD_INFO_IRQ_HND(DCIN1_DET, "DCIN1 detected\n");
+
+struct irq_name_pair {
+ const char *n;
+ irqreturn_t (*h)(int irq, void *arg);
+};
+
+static int bd70528_get_irqs(struct platform_device *pdev,
+ struct bd70528_psy *bdpsy)
+{
+ int irq, i, ret;
+ unsigned int mask;
+ static const struct irq_name_pair bd70528_chg_irqs[] = {
+ { .n = "bd70528-bat-ov-res", .h = BD_IRQ_HND(BAT_OV_RES) },
+ { .n = "bd70528-bat-ov-det", .h = BD_IRQ_HND(BAT_OV_DET) },
+ { .n = "bd70528-bat-dead", .h = BD_IRQ_HND(DBAT_DET) },
+ { .n = "bd70528-bat-warmed", .h = BD_IRQ_HND(COLD_RES) },
+ { .n = "bd70528-bat-cold", .h = BD_IRQ_HND(COLD_DET) },
+ { .n = "bd70528-bat-cooled", .h = BD_IRQ_HND(HOT_RES) },
+ { .n = "bd70528-bat-hot", .h = BD_IRQ_HND(HOT_DET) },
+ { .n = "bd70528-chg-tshd", .h = BD_IRQ_HND(CHG_TSD) },
+ { .n = "bd70528-bat-removed", .h = BD_IRQ_HND(BAT_RMV) },
+ { .n = "bd70528-bat-detected", .h = BD_IRQ_HND(BAT_DET) },
+ { .n = "bd70528-dcin2-ov-res", .h = BD_IRQ_HND(DCIN2_OV_RES) },
+ { .n = "bd70528-dcin2-ov-det", .h = BD_IRQ_HND(DCIN2_OV_DET) },
+ { .n = "bd70528-dcin2-removed", .h = BD_IRQ_HND(DCIN2_RMV) },
+ { .n = "bd70528-dcin2-detected", .h = BD_IRQ_HND(DCIN2_DET) },
+ { .n = "bd70528-dcin1-removed", .h = BD_IRQ_HND(DCIN1_RMV) },
+ { .n = "bd70528-dcin1-detected", .h = BD_IRQ_HND(DCIN1_DET) },
+ };
+
+ for (i = 0; i < ARRAY_SIZE(bd70528_chg_irqs); i++) {
+ irq = platform_get_irq_byname(pdev, bd70528_chg_irqs[i].n);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "Bad IRQ information for %s (%d)\n",
+ bd70528_chg_irqs[i].n, irq);
+ return irq;
+ }
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ bd70528_chg_irqs[i].h,
+ IRQF_ONESHOT,
+ bd70528_chg_irqs[i].n,
+ bdpsy->psy);
+
+ if (ret)
+ return ret;
+ }
+ /*
+ * BD70528 irq controller is not touching the main mask register.
+ * So enable the charger block interrupts at main level. We can just
+ * leave them enabled as irq-controller should disable irqs
+ * from sub-registers when IRQ is disabled or freed.
+ */
+ mask = BD70528_REG_INT_BAT1_MASK | BD70528_REG_INT_BAT2_MASK;
+ ret = regmap_update_bits(bdpsy->regmap,
+ BD70528_REG_INT_MAIN_MASK, mask, 0);
+ if (ret)
+ dev_err(&pdev->dev, "Failed to enable charger IRQs\n");
+
+ return ret;
+}
+
+static int bd70528_get_charger_status(struct bd70528_psy *bdpsy, int *val)
+{
+ int ret;
+ unsigned int v;
+
+ ret = regmap_read(bdpsy->regmap, BD70528_REG_CHG_CURR_STAT, &v);
+ if (ret) {
+ dev_err(bdpsy->dev, "Charger state read failure %d\n",
+ ret);
+ return ret;
+ }
+
+ switch (v & BD70528_MASK_CHG_STAT) {
+ case CHG_STAT_SUSPEND:
+ /* Maybe we should check the CHG_TTRI_EN? */
+ case CHG_STAT_OTP_TRICKLE:
+ case CHG_STAT_OTP_FAST:
+ case CHG_STAT_OTP_DONE:
+ case CHG_STAT_TSD_TRICKLE:
+ case CHG_STAT_TSD_FAST:
+ case CHG_STAT_TSD_TOPOFF:
+ case CHG_STAT_BAT_ERR:
+ *val = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+ case CHG_STAT_DONE:
+ *val = POWER_SUPPLY_STATUS_FULL;
+ break;
+ case CHG_STAT_TRICKLE:
+ case CHG_STAT_FAST:
+ case CHG_STAT_TOPOFF:
+ *val = POWER_SUPPLY_STATUS_CHARGING;
+ break;
+ default:
+ *val = POWER_SUPPLY_STATUS_UNKNOWN;
+ break;
+ }
+
+ return 0;
+}
+
+static int bd70528_get_charge_type(struct bd70528_psy *bdpsy, int *val)
+{
+ int ret;
+ unsigned int v;
+
+ ret = regmap_read(bdpsy->regmap, BD70528_REG_CHG_CURR_STAT, &v);
+ if (ret) {
+ dev_err(bdpsy->dev, "Charger state read failure %d\n",
+ ret);
+ return ret;
+ }
+
+ switch (v & BD70528_MASK_CHG_STAT) {
+ case CHG_STAT_TRICKLE:
+ *val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+ break;
+ case CHG_STAT_FAST:
+ case CHG_STAT_TOPOFF:
+ *val = POWER_SUPPLY_CHARGE_TYPE_FAST;
+ break;
+ case CHG_STAT_DONE:
+ case CHG_STAT_SUSPEND:
+ /* Maybe we should check the CHG_TTRI_EN? */
+ case CHG_STAT_OTP_TRICKLE:
+ case CHG_STAT_OTP_FAST:
+ case CHG_STAT_OTP_DONE:
+ case CHG_STAT_TSD_TRICKLE:
+ case CHG_STAT_TSD_FAST:
+ case CHG_STAT_TSD_TOPOFF:
+ case CHG_STAT_BAT_ERR:
+ *val = POWER_SUPPLY_CHARGE_TYPE_NONE;
+ break;
+ default:
+ *val = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+ break;
+ }
+
+ return 0;
+}
+
+static int bd70528_get_battery_health(struct bd70528_psy *bdpsy, int *val)
+{
+ int ret;
+ unsigned int v;
+
+ ret = regmap_read(bdpsy->regmap, BD70528_REG_CHG_BAT_STAT, &v);
+ if (ret) {
+ dev_err(bdpsy->dev, "Battery state read failure %d\n",
+ ret);
+ return ret;
+ }
+ /* No battery? */
+ if (!(v & BD70528_MASK_CHG_BAT_DETECT))
+ *val = POWER_SUPPLY_HEALTH_DEAD;
+ else if (v & BD70528_MASK_CHG_BAT_OVERVOLT)
+ *val = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+ else if (v & BD70528_MASK_CHG_BAT_TIMER)
+ *val = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
+ else
+ *val = POWER_SUPPLY_HEALTH_GOOD;
+
+ return 0;
+}
+
+static int bd70528_get_online(struct bd70528_psy *bdpsy, int *val)
+{
+ int ret;
+ unsigned int v;
+
+ ret = regmap_read(bdpsy->regmap, BD70528_REG_CHG_IN_STAT, &v);
+ if (ret) {
+ dev_err(bdpsy->dev, "DC1 IN state read failure %d\n",
+ ret);
+ return ret;
+ }
+
+ *val = (v & BD70528_MASK_CHG_DCIN1_UVLO) ? 1 : 0;
+
+ return 0;
+}
+
+static int bd70528_get_present(struct bd70528_psy *bdpsy, int *val)
+{
+ int ret;
+ unsigned int v;
+
+ ret = regmap_read(bdpsy->regmap, BD70528_REG_CHG_BAT_STAT, &v);
+ if (ret) {
+ dev_err(bdpsy->dev, "Battery state read failure %d\n",
+ ret);
+ return ret;
+ }
+
+ *val = (v & BD70528_MASK_CHG_BAT_DETECT) ? 1 : 0;
+
+ return 0;
+}
+
+struct linear_range {
+ int min;
+ int step;
+ int vals;
+ int low_sel;
+};
+
+static const struct linear_range current_limit_ranges[] = {
+ {
+ .min = 5,
+ .step = 1,
+ .vals = 36,
+ .low_sel = 0,
+ },
+ {
+ .min = 40,
+ .step = 5,
+ .vals = 5,
+ .low_sel = 0x23,
+ },
+ {
+ .min = 60,
+ .step = 20,
+ .vals = 8,
+ .low_sel = 0x27,
+ },
+ {
+ .min = 200,
+ .step = 50,
+ .vals = 7,
+ .low_sel = 0x2e,
+ }
+};
+
+/*
+ * BD70528 would support setting and getting own charge current/
+ * voltage for low temperatures. The driver currently only reads
+ * the charge current at room temperature. We do set both though.
+ */
+static const struct linear_range warm_charge_curr[] = {
+ {
+ .min = 10,
+ .step = 10,
+ .vals = 20,
+ .low_sel = 0,
+ },
+ {
+ .min = 200,
+ .step = 25,
+ .vals = 13,
+ .low_sel = 0x13,
+ },
+};
+
+/*
+ * Cold charge current selectors are identical to warm charge current
+ * selectors. The difference is that only smaller currents are available
+ * at cold charge range.
+ */
+#define MAX_COLD_CHG_CURR_SEL 0x15
+#define MAX_WARM_CHG_CURR_SEL 0x1f
+#define MIN_CHG_CURR_SEL 0x0
+
+static int find_value_for_selector_low(const struct linear_range *r,
+ int selectors, unsigned int sel,
+ unsigned int *val)
+{
+ int i;
+
+ for (i = 0; i < selectors; i++) {
+ if (r[i].low_sel <= sel && r[i].low_sel + r[i].vals >= sel) {
+ *val = r[i].min + (sel - r[i].low_sel) * r[i].step;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+/*
+ * For BD70528 voltage/current limits we happily accept any value which
+ * belongs the range. We could check if value matching the selector is
+ * desired by computing the range min + (sel - sel_low) * range step - but
+ * I guess it is enough if we use voltage/current which is closest (below)
+ * the requested?
+ */
+static int find_selector_for_value_low(const struct linear_range *r,
+ int selectors, unsigned int val,
+ unsigned int *sel, bool *found)
+{
+ int i;
+ int ret = -EINVAL;
+
+ *found = false;
+ for (i = 0; i < selectors; i++) {
+ if (r[i].min <= val) {
+ if (r[i].min + r[i].step * r[i].vals >= val) {
+ *found = true;
+ *sel = r[i].low_sel + (val - r[i].min) /
+ r[i].step;
+ ret = 0;
+ break;
+ }
+ /*
+ * If the range max is smaller than requested
+ * we can set the max supported value from range
+ */
+ *sel = r[i].low_sel + r[i].vals;
+ ret = 0;
+ }
+ }
+ return ret;
+}
+
+static int get_charge_current(struct bd70528_psy *bdpsy, int *ma)
+{
+ unsigned int sel;
+ int ret;
+
+ ret = regmap_read(bdpsy->regmap, BD70528_REG_CHG_CHG_CURR_WARM,
+ &sel);
+ if (ret) {
+ dev_err(bdpsy->dev,
+ "Charge current reading failed (%d)\n", ret);
+ return ret;
+ }
+
+ sel &= BD70528_MASK_CHG_CHG_CURR;
+
+ ret = find_value_for_selector_low(&warm_charge_curr[0],
+ ARRAY_SIZE(warm_charge_curr), sel,
+ ma);
+ if (ret) {
+ dev_err(bdpsy->dev,
+ "Unknown charge current value 0x%x\n",
+ sel);
+ }
+
+ return ret;
+}
+
+static int get_current_limit(struct bd70528_psy *bdpsy, int *ma)
+{
+ unsigned int sel;
+ int ret;
+
+ ret = regmap_read(bdpsy->regmap, BD70528_REG_CHG_DCIN_ILIM,
+ &sel);
+
+ if (ret) {
+ dev_err(bdpsy->dev,
+ "Input current limit reading failed (%d)\n", ret);
+ return ret;
+ }
+
+ sel &= BD70528_MASK_CHG_DCIN_ILIM;
+
+ ret = find_value_for_selector_low(&current_limit_ranges[0],
+ ARRAY_SIZE(current_limit_ranges), sel,
+ ma);
+
+ if (ret) {
+ /* Unspecified values mean 500 mA */
+ *ma = 500;
+ }
+ return 0;
+}
+
+static enum power_supply_property bd70528_charger_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_CHARGE_TYPE,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
+ POWER_SUPPLY_PROP_MODEL_NAME,
+ POWER_SUPPLY_PROP_MANUFACTURER,
+};
+
+static int bd70528_charger_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct bd70528_psy *bdpsy = power_supply_get_drvdata(psy);
+ int ret = 0;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ return bd70528_get_charger_status(bdpsy, &val->intval);
+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ return bd70528_get_charge_type(bdpsy, &val->intval);
+ case POWER_SUPPLY_PROP_HEALTH:
+ return bd70528_get_battery_health(bdpsy, &val->intval);
+ case POWER_SUPPLY_PROP_PRESENT:
+ return bd70528_get_present(bdpsy, &val->intval);
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+ ret = get_current_limit(bdpsy, &val->intval);
+ val->intval *= 1000;
+ return ret;
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+ ret = get_charge_current(bdpsy, &val->intval);
+ val->intval *= 1000;
+ return ret;
+ case POWER_SUPPLY_PROP_ONLINE:
+ return bd70528_get_online(bdpsy, &val->intval);
+ case POWER_SUPPLY_PROP_MODEL_NAME:
+ val->strval = bd70528_charger_model;
+ return 0;
+ case POWER_SUPPLY_PROP_MANUFACTURER:
+ val->strval = bd70528_charger_manufacturer;
+ return 0;
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int bd70528_prop_is_writable(struct power_supply *psy,
+ enum power_supply_property psp)
+{
+ switch (psp) {
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+ return 1;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int set_charge_current(struct bd70528_psy *bdpsy, int ma)
+{
+ unsigned int reg;
+ int ret = 0, tmpret;
+ bool found;
+
+ if (ma > 500) {
+ dev_warn(bdpsy->dev,
+ "Requested charge current %u exceed maximum (500mA)\n",
+ ma);
+ reg = MAX_WARM_CHG_CURR_SEL;
+ goto set;
+ }
+ if (ma < 10) {
+ dev_err(bdpsy->dev,
+ "Requested charge current %u smaller than min (10mA)\n",
+ ma);
+ reg = MIN_CHG_CURR_SEL;
+ ret = -EINVAL;
+ goto set;
+ }
+
+ ret = find_selector_for_value_low(&warm_charge_curr[0],
+ ARRAY_SIZE(warm_charge_curr), ma,
+ &reg, &found);
+ if (ret) {
+ reg = MIN_CHG_CURR_SEL;
+ goto set;
+ }
+ if (!found) {
+ /* There was a gap in supported values and we hit it */
+ dev_warn(bdpsy->dev,
+ "Unsupported charge current %u mA\n", ma);
+ }
+set:
+
+ tmpret = regmap_update_bits(bdpsy->regmap,
+ BD70528_REG_CHG_CHG_CURR_WARM,
+ BD70528_MASK_CHG_CHG_CURR, reg);
+ if (tmpret)
+ dev_err(bdpsy->dev,
+ "Charge current write failure (%d)\n", tmpret);
+
+ if (reg > MAX_COLD_CHG_CURR_SEL)
+ reg = MAX_COLD_CHG_CURR_SEL;
+
+ if (!tmpret)
+ tmpret = regmap_update_bits(bdpsy->regmap,
+ BD70528_REG_CHG_CHG_CURR_COLD,
+ BD70528_MASK_CHG_CHG_CURR, reg);
+
+ if (!ret)
+ ret = tmpret;
+
+ return ret;
+}
+
+#define MAX_CURR_LIMIT_SEL 0x34
+#define MIN_CURR_LIMIT_SEL 0x0
+
+static int set_current_limit(struct bd70528_psy *bdpsy, int ma)
+{
+ unsigned int reg;
+ int ret = 0, tmpret;
+ bool found;
+
+ if (ma > 500) {
+ dev_warn(bdpsy->dev,
+ "Requested current limit %u exceed maximum (500mA)\n",
+ ma);
+ reg = MAX_CURR_LIMIT_SEL;
+ goto set;
+ }
+ if (ma < 5) {
+ dev_err(bdpsy->dev,
+ "Requested current limit %u smaller than min (5mA)\n",
+ ma);
+ reg = MIN_CURR_LIMIT_SEL;
+ ret = -EINVAL;
+ goto set;
+ }
+
+ ret = find_selector_for_value_low(&current_limit_ranges[0],
+ ARRAY_SIZE(current_limit_ranges), ma,
+ &reg, &found);
+ if (ret) {
+ reg = MIN_CURR_LIMIT_SEL;
+ goto set;
+ }
+ if (!found) {
+ /* There was a gap in supported values and we hit it ?*/
+ dev_warn(bdpsy->dev, "Unsupported current limit %umA\n",
+ ma);
+ }
+
+set:
+ tmpret = regmap_update_bits(bdpsy->regmap,
+ BD70528_REG_CHG_DCIN_ILIM,
+ BD70528_MASK_CHG_DCIN_ILIM, reg);
+
+ if (!ret)
+ ret = tmpret;
+
+ return ret;
+}
+
+static int bd70528_charger_set_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ struct bd70528_psy *bdpsy = power_supply_get_drvdata(psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+ return set_current_limit(bdpsy, val->intval / 1000);
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+ return set_charge_current(bdpsy, val->intval / 1000);
+ default:
+ break;
+ }
+ return -EINVAL;
+}
+
+static const struct power_supply_desc bd70528_charger_desc = {
+ .name = "bd70528-charger",
+ .type = POWER_SUPPLY_TYPE_MAINS,
+ .properties = bd70528_charger_props,
+ .num_properties = ARRAY_SIZE(bd70528_charger_props),
+ .get_property = bd70528_charger_get_property,
+ .set_property = bd70528_charger_set_property,
+ .property_is_writeable = bd70528_prop_is_writable,
+};
+
+static int bd70528_power_probe(struct platform_device *pdev)
+{
+ struct bd70528_psy *bdpsy;
+ struct power_supply_config cfg = {};
+
+ bdpsy = devm_kzalloc(&pdev->dev, sizeof(*bdpsy), GFP_KERNEL);
+ if (!bdpsy)
+ return -ENOMEM;
+
+ bdpsy->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!bdpsy->regmap) {
+ dev_err(&pdev->dev, "No regmap found for chip\n");
+ return -EINVAL;
+ }
+ bdpsy->dev = &pdev->dev;
+
+ platform_set_drvdata(pdev, bdpsy);
+ cfg.drv_data = bdpsy;
+ cfg.of_node = pdev->dev.parent->of_node;
+
+ bdpsy->psy = devm_power_supply_register(&pdev->dev,
+ &bd70528_charger_desc, &cfg);
+ if (IS_ERR(bdpsy->psy)) {
+ dev_err(&pdev->dev, "failed: power supply register\n");
+ return PTR_ERR(bdpsy->psy);
+ }
+
+ return bd70528_get_irqs(pdev, bdpsy);
+}
+
+static struct platform_driver bd70528_power = {
+ .driver = {
+ .name = "bd70528-power"
+ },
+ .probe = bd70528_power_probe,
+};
+
+module_platform_driver(bd70528_power);
+
+MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
+MODULE_DESCRIPTION("BD70528 power-supply driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c
index cc0dfdc9e85a..453d6332d43a 100644
--- a/drivers/power/supply/bq24190_charger.c
+++ b/drivers/power/supply/bq24190_charger.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for the TI bq24190 battery charger.
*
* Author: Mark A. Greer <mgreer@animalcreek.com>
- *
- * 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.
*/
#include <linux/module.h>
@@ -1700,7 +1697,7 @@ static int bq24190_get_config(struct bq24190_dev_info *bdi)
static int bq24190_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adapter = client->adapter;
struct device *dev = &client->dev;
struct power_supply_config charger_cfg = {}, battery_cfg = {};
struct bq24190_dev_info *bdi;
diff --git a/drivers/power/supply/bq24257_charger.c b/drivers/power/supply/bq24257_charger.c
index 7eb58f10e092..eb151687beb3 100644
--- a/drivers/power/supply/bq24257_charger.c
+++ b/drivers/power/supply/bq24257_charger.c
@@ -950,7 +950,7 @@ static int bq24257_fw_probe(struct bq24257_device *bq)
static int bq24257_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adapter = client->adapter;
struct device *dev = &client->dev;
const struct acpi_device_id *acpi_id;
struct bq24257_device *bq;
diff --git a/drivers/power/supply/bq25890_charger.c b/drivers/power/supply/bq25890_charger.c
index b2ff82b4707a..d333f2b321b9 100644
--- a/drivers/power/supply/bq25890_charger.c
+++ b/drivers/power/supply/bq25890_charger.c
@@ -817,7 +817,7 @@ static int bq25890_fw_probe(struct bq25890_device *bq)
static int bq25890_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adapter = client->adapter;
struct device *dev = &client->dev;
struct bq25890_device *bq;
int ret;
diff --git a/drivers/power/supply/charger-manager.c b/drivers/power/supply/charger-manager.c
index a6900aa0d2ed..a21e1a2673f8 100644
--- a/drivers/power/supply/charger-manager.c
+++ b/drivers/power/supply/charger-manager.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Samsung Electronics Co., Ltd.
* MyungJoo Ham <myungjoo.ham@samsung.com>
@@ -7,9 +8,6 @@
* Charger manager depends on other devices. Register this later than
* the depending devices.
*
- * 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.
**/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/power/supply/collie_battery.c b/drivers/power/supply/collie_battery.c
index 3a0bc608d4b5..cbd588e9e233 100644
--- a/drivers/power/supply/collie_battery.c
+++ b/drivers/power/supply/collie_battery.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Battery and Power Management code for the Sharp SL-5x00
*
* Copyright (C) 2009 Thomas Kunze
*
* based on tosa_battery.c
- *
- * 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.
- *
*/
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/power/supply/cros_usbpd-charger.c b/drivers/power/supply/cros_usbpd-charger.c
index 7e9c3984ef6a..3a9ea94c3de3 100644
--- a/drivers/power/supply/cros_usbpd-charger.c
+++ b/drivers/power/supply/cros_usbpd-charger.c
@@ -53,6 +53,8 @@ struct charger_data {
};
static enum power_supply_property cros_usbpd_charger_props[] = {
+ POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
+ POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_CURRENT_MAX,
@@ -80,6 +82,10 @@ static enum power_supply_usb_type cros_usbpd_charger_usb_types[] = {
POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID
};
+/* Input voltage/current limit in mV/mA. Default to none. */
+static u16 input_voltage_limit = EC_POWER_LIMIT_NONE;
+static u16 input_current_limit = EC_POWER_LIMIT_NONE;
+
static bool cros_usbpd_charger_port_is_dedicated(struct port_data *port)
{
return port->port_number >= port->charger->num_usbpd_ports;
@@ -324,6 +330,26 @@ static int cros_usbpd_charger_get_port_status(struct port_data *port,
return ret;
}
+static int cros_usbpd_charger_set_ext_power_limit(struct charger_data *charger,
+ u16 current_lim,
+ u16 voltage_lim)
+{
+ struct ec_params_external_power_limit_v1 req;
+ int ret;
+
+ req.current_lim = current_lim;
+ req.voltage_lim = voltage_lim;
+
+ ret = cros_usbpd_charger_ec_command(charger, 0,
+ EC_CMD_EXTERNAL_POWER_LIMIT,
+ &req, sizeof(req), NULL, 0);
+ if (ret < 0)
+ dev_err(charger->dev,
+ "Unable to set the 'External Power Limit': %d\n", ret);
+
+ return ret;
+}
+
static void cros_usbpd_charger_power_changed(struct power_supply *psy)
{
struct port_data *port = power_supply_get_drvdata(psy);
@@ -396,6 +422,18 @@ static int cros_usbpd_charger_get_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_USB_TYPE:
val->intval = port->psy_usb_type;
break;
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+ if (input_current_limit == EC_POWER_LIMIT_NONE)
+ val->intval = -1;
+ else
+ val->intval = input_current_limit * 1000;
+ break;
+ case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
+ if (input_voltage_limit == EC_POWER_LIMIT_NONE)
+ val->intval = -1;
+ else
+ val->intval = input_voltage_limit * 1000;
+ break;
case POWER_SUPPLY_PROP_MODEL_NAME:
val->strval = port->model_name;
break;
@@ -409,6 +447,81 @@ static int cros_usbpd_charger_get_prop(struct power_supply *psy,
return 0;
}
+static int cros_usbpd_charger_set_prop(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ struct port_data *port = power_supply_get_drvdata(psy);
+ struct charger_data *charger = port->charger;
+ struct device *dev = charger->dev;
+ u16 intval;
+ int ret;
+
+ /* U16_MAX in mV/mA is the maximum supported value */
+ if (val->intval >= U16_MAX * 1000)
+ return -EINVAL;
+ /* A negative number is used to clear the limit */
+ if (val->intval < 0)
+ intval = EC_POWER_LIMIT_NONE;
+ else /* Convert from uA/uV to mA/mV */
+ intval = val->intval / 1000;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+ ret = cros_usbpd_charger_set_ext_power_limit(charger, intval,
+ input_voltage_limit);
+ if (ret < 0)
+ break;
+
+ input_current_limit = intval;
+ if (input_current_limit == EC_POWER_LIMIT_NONE)
+ dev_info(dev,
+ "External Current Limit cleared for all ports\n");
+ else
+ dev_info(dev,
+ "External Current Limit set to %dmA for all ports\n",
+ input_current_limit);
+ break;
+ case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
+ ret = cros_usbpd_charger_set_ext_power_limit(charger,
+ input_current_limit,
+ intval);
+ if (ret < 0)
+ break;
+
+ input_voltage_limit = intval;
+ if (input_voltage_limit == EC_POWER_LIMIT_NONE)
+ dev_info(dev,
+ "External Voltage Limit cleared for all ports\n");
+ else
+ dev_info(dev,
+ "External Voltage Limit set to %dmV for all ports\n",
+ input_voltage_limit);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int cros_usbpd_charger_property_is_writeable(struct power_supply *psy,
+ enum power_supply_property psp)
+{
+ int ret;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+ case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
+ ret = 1;
+ break;
+ default:
+ ret = 0;
+ }
+
+ return ret;
+}
+
static int cros_usbpd_charger_ec_event(struct notifier_block *nb,
unsigned long queued_during_suspend,
void *_notify)
@@ -525,6 +638,9 @@ static int cros_usbpd_charger_probe(struct platform_device *pd)
psy_desc = &port->psy_desc;
psy_desc->get_property = cros_usbpd_charger_get_prop;
+ psy_desc->set_property = cros_usbpd_charger_set_prop;
+ psy_desc->property_is_writeable =
+ cros_usbpd_charger_property_is_writeable;
psy_desc->external_power_changed =
cros_usbpd_charger_power_changed;
psy_cfg.drv_data = port;
diff --git a/drivers/power/supply/da9030_battery.c b/drivers/power/supply/da9030_battery.c
index 5ca0f4d90792..88582423b87d 100644
--- a/drivers/power/supply/da9030_battery.c
+++ b/drivers/power/supply/da9030_battery.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Battery charger driver for Dialog Semiconductor DA9030
*
* Copyright (C) 2008 Compulab, Ltd.
* Mike Rapoport <mike@compulab.co.il>
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/power/supply/ds2780_battery.c b/drivers/power/supply/ds2780_battery.c
index 5bf7c714a6ee..db3a25404c9f 100644
--- a/drivers/power/supply/ds2780_battery.c
+++ b/drivers/power/supply/ds2780_battery.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* 1-wire client/driver for the Maxim/Dallas DS2780 Stand-Alone Fuel Gauge IC
*
@@ -6,11 +7,6 @@
* Author: Clifton Barnes <cabarnes@indesign-llc.com>
*
* Based on ds2760_battery and ds2782_battery drivers
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/power/supply/ds2781_battery.c b/drivers/power/supply/ds2781_battery.c
index 166a8bd58811..130cbdfc14eb 100644
--- a/drivers/power/supply/ds2781_battery.c
+++ b/drivers/power/supply/ds2781_battery.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* 1-wire client/driver for the Maxim/Dallas DS2781 Stand-Alone Fuel Gauge IC
*
* Author: Renata Sayakhova <renata@oktetlabs.ru>
*
* Based on ds2780_battery drivers
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/power/supply/ds2782_battery.c b/drivers/power/supply/ds2782_battery.c
index 04b0fe7d7d62..9ae273fde7a2 100644
--- a/drivers/power/supply/ds2782_battery.c
+++ b/drivers/power/supply/ds2782_battery.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* I2C client/driver for the Maxim/Dallas DS2782 Stand-Alone Fuel Gauge IC
*
@@ -8,11 +9,6 @@
* DS2786 added by Yulia Vilensky <vilensky@compulab.co.il>
*
* UEvent sending added by Evgeny Romanov <romanov@neurosoft.ru>
- *
- * 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.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/power/supply/ipaq_micro_battery.c b/drivers/power/supply/ipaq_micro_battery.c
index 2fa6edd6e8b1..03592ceaca88 100644
--- a/drivers/power/supply/ipaq_micro_battery.c
+++ b/drivers/power/supply/ipaq_micro_battery.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
- * 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.
*
* h3xxx atmel micro companion support, battery subdevice
* based on previous kernel 2.4 version
* Author : Alessandro Gardich <gremlin@gremlin.it>
* Author : Linus Walleij <linus.walleij@linaro.org>
- *
*/
#include <linux/module.h>
diff --git a/drivers/power/supply/jz4740-battery.c b/drivers/power/supply/jz4740-battery.c
index 88f04f4d1a70..6366bd61ea9f 100644
--- a/drivers/power/supply/jz4740-battery.c
+++ b/drivers/power/supply/jz4740-battery.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Battery measurement code for Ingenic JZ SOC.
*
@@ -7,11 +8,6 @@
* based on tosa_battery.c
*
* Copyright (C) 2008 Marek Vasut <marek.vasut@gmail.com>
-*
- * 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.
- *
*/
#include <linux/interrupt.h>
diff --git a/drivers/power/supply/lp8727_charger.c b/drivers/power/supply/lp8727_charger.c
index 042fb3dacb46..9ee54e397754 100644
--- a/drivers/power/supply/lp8727_charger.c
+++ b/drivers/power/supply/lp8727_charger.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for LP8727 Micro/Mini USB IC with integrated charger
*
* Copyright (C) 2011 Texas Instruments
* Copyright (C) 2011 National Semiconductor
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/power/supply/lp8788-charger.c b/drivers/power/supply/lp8788-charger.c
index 309e6efbb8ef..84a206f42a8e 100644
--- a/drivers/power/supply/lp8788-charger.c
+++ b/drivers/power/supply/lp8788-charger.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TI LP8788 MFD - battery charger driver
*
* Copyright 2012 Texas Instruments
*
* Author: Milo(Woogyom) Kim <milo.kim@ti.com>
- *
- * 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.
- *
*/
#include <linux/err.h>
diff --git a/drivers/power/supply/max14656_charger_detector.c b/drivers/power/supply/max14656_charger_detector.c
index 9e6472834e37..3bbb8b4c8ae7 100644
--- a/drivers/power/supply/max14656_charger_detector.c
+++ b/drivers/power/supply/max14656_charger_detector.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Maxim MAX14656 / AL32 USB Charger Detector driver
*
@@ -7,11 +8,6 @@
* Components from Maxim AL32 Charger detection Driver for MX50 Yoshi Board
* Copyright (C) Amazon Technologies Inc. All rights reserved.
* Manish Lachwani (lachwani@lab126.com)
- *
- * This package is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
*/
#include <linux/module.h>
#include <linux/init.h>
@@ -251,7 +247,7 @@ static void stop_irq_work(void *data)
static int max14656_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adapter = client->adapter;
struct device *dev = &client->dev;
struct power_supply_config psy_cfg = {};
struct max14656_chip *chip;
diff --git a/drivers/power/supply/max17040_battery.c b/drivers/power/supply/max17040_battery.c
index 91cafc7bed30..62499018e68b 100644
--- a/drivers/power/supply/max17040_battery.c
+++ b/drivers/power/supply/max17040_battery.c
@@ -193,7 +193,7 @@ static const struct power_supply_desc max17040_battery_desc = {
static int max17040_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adapter = client->adapter;
struct power_supply_config psy_cfg = {};
struct max17040_chip *chip;
diff --git a/drivers/power/supply/max17042_battery.c b/drivers/power/supply/max17042_battery.c
index 581c6bd23388..64f3358eaa3c 100644
--- a/drivers/power/supply/max17042_battery.c
+++ b/drivers/power/supply/max17042_battery.c
@@ -1005,7 +1005,7 @@ static void max17042_stop_work(void *data)
static int max17042_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adapter = client->adapter;
const struct power_supply_desc *max17042_desc = &max17042_psy_desc;
struct power_supply_config psy_cfg = {};
const struct acpi_device_id *acpi_id = NULL;
diff --git a/drivers/power/supply/max8925_power.c b/drivers/power/supply/max8925_power.c
index 39b4d5b6ac39..5fca4960f440 100644
--- a/drivers/power/supply/max8925_power.c
+++ b/drivers/power/supply/max8925_power.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Battery driver for Maxim MAX8925
*
* Copyright (c) 2009-2010 Marvell International Ltd.
* Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/power/supply/olpc_battery.c b/drivers/power/supply/olpc_battery.c
index 7720e4c2ac0b..ad0e9e0edb3f 100644
--- a/drivers/power/supply/olpc_battery.c
+++ b/drivers/power/supply/olpc_battery.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Battery driver for One Laptop Per Child board.
*
* Copyright © 2006-2010 David Woodhouse <dwmw2@infradead.org>
- *
- * 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.
*/
#include <linux/kernel.h>
@@ -20,7 +17,6 @@
#include <linux/jiffies.h>
#include <linux/sched.h>
#include <linux/olpc-ec.h>
-#include <asm/olpc.h>
#define EC_BAT_VOLTAGE 0x10 /* uint16_t, *9.76/32, mV */
diff --git a/drivers/power/supply/pda_power.c b/drivers/power/supply/pda_power.c
index 922a86787c5c..3ae5707d39fa 100644
--- a/drivers/power/supply/pda_power.c
+++ b/drivers/power/supply/pda_power.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Common power driver for PDAs and phones with one or two external
* power supplies (AC/USB) connected to main and backup batteries,
* and optional builtin charger.
*
* Copyright © 2007 Anton Vorontsov <cbou@mail.ru>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/power/supply/pm2301_charger.c b/drivers/power/supply/pm2301_charger.c
index 78561b6884fc..17749fc90e16 100644
--- a/drivers/power/supply/pm2301_charger.c
+++ b/drivers/power/supply/pm2301_charger.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2012 ST Ericsson.
*
* Power supply driver for ST Ericsson pm2xxx_charger charger
- *
- * 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.
*/
#include <linux/init.h>
diff --git a/drivers/power/supply/pmu_battery.c b/drivers/power/supply/pmu_battery.c
index 9c8d5253812c..eaab7500d99b 100644
--- a/drivers/power/supply/pmu_battery.c
+++ b/drivers/power/supply/pmu_battery.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Battery class driver for Apple PMU
*
* Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c
index 136e8f64848a..82e84801264c 100644
--- a/drivers/power/supply/power_supply_core.c
+++ b/drivers/power/supply/power_supply_core.c
@@ -606,7 +606,7 @@ int power_supply_get_battery_info(struct power_supply *psy,
/* The property and field names below must correspond to elements
* in enum power_supply_property. For reasoning, see
- * Documentation/power/power_supply_class.txt.
+ * Documentation/power/power_supply_class.rst.
*/
of_property_read_u32(battery_np, "energy-full-design-microwatt-hours",
@@ -1071,6 +1071,10 @@ __power_supply_register(struct device *parent,
if (rc)
goto create_triggers_failed;
+ rc = power_supply_add_hwmon_sysfs(psy);
+ if (rc)
+ goto add_hwmon_sysfs_failed;
+
/*
* Update use_cnt after any uevents (most notably from device_add()).
* We are here still during driver's probe but
@@ -1089,6 +1093,8 @@ __power_supply_register(struct device *parent,
return psy;
+add_hwmon_sysfs_failed:
+ power_supply_remove_triggers(psy);
create_triggers_failed:
psy_unregister_cooler(psy);
register_cooler_failed:
@@ -1241,6 +1247,7 @@ void power_supply_unregister(struct power_supply *psy)
cancel_work_sync(&psy->changed_work);
cancel_delayed_work_sync(&psy->deferred_register_work);
sysfs_remove_link(&psy->dev.kobj, "powers");
+ power_supply_remove_hwmon_sysfs(psy);
power_supply_remove_triggers(psy);
psy_unregister_cooler(psy);
psy_unregister_thermal(psy);
diff --git a/drivers/power/supply/power_supply_hwmon.c b/drivers/power/supply/power_supply_hwmon.c
new file mode 100644
index 000000000000..51fe60440d12
--- /dev/null
+++ b/drivers/power/supply/power_supply_hwmon.c
@@ -0,0 +1,355 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * power_supply_hwmon.c - power supply hwmon support.
+ */
+
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/power_supply.h>
+#include <linux/slab.h>
+
+struct power_supply_hwmon {
+ struct power_supply *psy;
+ unsigned long *props;
+};
+
+static int power_supply_hwmon_in_to_property(u32 attr)
+{
+ switch (attr) {
+ case hwmon_in_average:
+ return POWER_SUPPLY_PROP_VOLTAGE_AVG;
+ case hwmon_in_min:
+ return POWER_SUPPLY_PROP_VOLTAGE_MIN;
+ case hwmon_in_max:
+ return POWER_SUPPLY_PROP_VOLTAGE_MAX;
+ case hwmon_in_input:
+ return POWER_SUPPLY_PROP_VOLTAGE_NOW;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int power_supply_hwmon_curr_to_property(u32 attr)
+{
+ switch (attr) {
+ case hwmon_curr_average:
+ return POWER_SUPPLY_PROP_CURRENT_AVG;
+ case hwmon_curr_max:
+ return POWER_SUPPLY_PROP_CURRENT_MAX;
+ case hwmon_curr_input:
+ return POWER_SUPPLY_PROP_CURRENT_NOW;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int power_supply_hwmon_temp_to_property(u32 attr, int channel)
+{
+ if (channel) {
+ switch (attr) {
+ case hwmon_temp_input:
+ return POWER_SUPPLY_PROP_TEMP_AMBIENT;
+ case hwmon_temp_min_alarm:
+ return POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN;
+ case hwmon_temp_max_alarm:
+ return POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX;
+ default:
+ break;
+ }
+ } else {
+ switch (attr) {
+ case hwmon_temp_input:
+ return POWER_SUPPLY_PROP_TEMP;
+ case hwmon_temp_max:
+ return POWER_SUPPLY_PROP_TEMP_MAX;
+ case hwmon_temp_min:
+ return POWER_SUPPLY_PROP_TEMP_MIN;
+ case hwmon_temp_min_alarm:
+ return POWER_SUPPLY_PROP_TEMP_ALERT_MIN;
+ case hwmon_temp_max_alarm:
+ return POWER_SUPPLY_PROP_TEMP_ALERT_MAX;
+ default:
+ break;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int
+power_supply_hwmon_to_property(enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ switch (type) {
+ case hwmon_in:
+ return power_supply_hwmon_in_to_property(attr);
+ case hwmon_curr:
+ return power_supply_hwmon_curr_to_property(attr);
+ case hwmon_temp:
+ return power_supply_hwmon_temp_to_property(attr, channel);
+ default:
+ return -EINVAL;
+ }
+}
+
+static bool power_supply_hwmon_is_a_label(enum hwmon_sensor_types type,
+ u32 attr)
+{
+ return type == hwmon_temp && attr == hwmon_temp_label;
+}
+
+static bool power_supply_hwmon_is_writable(enum hwmon_sensor_types type,
+ u32 attr)
+{
+ switch (type) {
+ case hwmon_in:
+ return attr == hwmon_in_min ||
+ attr == hwmon_in_max;
+ case hwmon_curr:
+ return attr == hwmon_curr_max;
+ case hwmon_temp:
+ return attr == hwmon_temp_max ||
+ attr == hwmon_temp_min ||
+ attr == hwmon_temp_min_alarm ||
+ attr == hwmon_temp_max_alarm;
+ default:
+ return false;
+ }
+}
+
+static umode_t power_supply_hwmon_is_visible(const void *data,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ const struct power_supply_hwmon *psyhw = data;
+ int prop;
+
+
+ if (power_supply_hwmon_is_a_label(type, attr))
+ return 0444;
+
+ prop = power_supply_hwmon_to_property(type, attr, channel);
+ if (prop < 0 || !test_bit(prop, psyhw->props))
+ return 0;
+
+ if (power_supply_property_is_writeable(psyhw->psy, prop) > 0 &&
+ power_supply_hwmon_is_writable(type, attr))
+ return 0644;
+
+ return 0444;
+}
+
+static int power_supply_hwmon_read_string(struct device *dev,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel,
+ const char **str)
+{
+ *str = channel ? "temp" : "temp ambient";
+ return 0;
+}
+
+static int
+power_supply_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct power_supply_hwmon *psyhw = dev_get_drvdata(dev);
+ struct power_supply *psy = psyhw->psy;
+ union power_supply_propval pspval;
+ int ret, prop;
+
+ prop = power_supply_hwmon_to_property(type, attr, channel);
+ if (prop < 0)
+ return prop;
+
+ ret = power_supply_get_property(psy, prop, &pspval);
+ if (ret)
+ return ret;
+
+ switch (type) {
+ /*
+ * Both voltage and current is reported in units of
+ * microvolts/microamps, so we need to adjust it to
+ * milliamps(volts)
+ */
+ case hwmon_curr:
+ case hwmon_in:
+ pspval.intval = DIV_ROUND_CLOSEST(pspval.intval, 1000);
+ break;
+ /*
+ * Temp needs to be converted from 1/10 C to milli-C
+ */
+ case hwmon_temp:
+ if (check_mul_overflow(pspval.intval, 100,
+ &pspval.intval))
+ return -EOVERFLOW;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ *val = pspval.intval;
+
+ return 0;
+}
+
+static int
+power_supply_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long val)
+{
+ struct power_supply_hwmon *psyhw = dev_get_drvdata(dev);
+ struct power_supply *psy = psyhw->psy;
+ union power_supply_propval pspval;
+ int prop;
+
+ prop = power_supply_hwmon_to_property(type, attr, channel);
+ if (prop < 0)
+ return prop;
+
+ pspval.intval = val;
+
+ switch (type) {
+ /*
+ * Both voltage and current is reported in units of
+ * microvolts/microamps, so we need to adjust it to
+ * milliamps(volts)
+ */
+ case hwmon_curr:
+ case hwmon_in:
+ if (check_mul_overflow(pspval.intval, 1000,
+ &pspval.intval))
+ return -EOVERFLOW;
+ break;
+ /*
+ * Temp needs to be converted from 1/10 C to milli-C
+ */
+ case hwmon_temp:
+ pspval.intval = DIV_ROUND_CLOSEST(pspval.intval, 100);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return power_supply_set_property(psy, prop, &pspval);
+}
+
+static const struct hwmon_ops power_supply_hwmon_ops = {
+ .is_visible = power_supply_hwmon_is_visible,
+ .read = power_supply_hwmon_read,
+ .write = power_supply_hwmon_write,
+ .read_string = power_supply_hwmon_read_string,
+};
+
+static const struct hwmon_channel_info *power_supply_hwmon_info[] = {
+ HWMON_CHANNEL_INFO(temp,
+ HWMON_T_LABEL |
+ HWMON_T_INPUT |
+ HWMON_T_MAX |
+ HWMON_T_MIN |
+ HWMON_T_MIN_ALARM |
+ HWMON_T_MIN_ALARM,
+
+ HWMON_T_LABEL |
+ HWMON_T_INPUT |
+ HWMON_T_MIN_ALARM |
+ HWMON_T_LABEL |
+ HWMON_T_MAX_ALARM),
+
+ HWMON_CHANNEL_INFO(curr,
+ HWMON_C_AVERAGE |
+ HWMON_C_MAX |
+ HWMON_C_INPUT),
+
+ HWMON_CHANNEL_INFO(in,
+ HWMON_I_AVERAGE |
+ HWMON_I_MIN |
+ HWMON_I_MAX |
+ HWMON_I_INPUT),
+ NULL
+};
+
+static const struct hwmon_chip_info power_supply_hwmon_chip_info = {
+ .ops = &power_supply_hwmon_ops,
+ .info = power_supply_hwmon_info,
+};
+
+static void power_supply_hwmon_bitmap_free(void *data)
+{
+ bitmap_free(data);
+}
+
+int power_supply_add_hwmon_sysfs(struct power_supply *psy)
+{
+ const struct power_supply_desc *desc = psy->desc;
+ struct power_supply_hwmon *psyhw;
+ struct device *dev = &psy->dev;
+ struct device *hwmon;
+ int ret, i;
+
+ if (!devres_open_group(dev, power_supply_add_hwmon_sysfs,
+ GFP_KERNEL))
+ return -ENOMEM;
+
+ psyhw = devm_kzalloc(dev, sizeof(*psyhw), GFP_KERNEL);
+ if (!psyhw) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ psyhw->psy = psy;
+ psyhw->props = bitmap_zalloc(POWER_SUPPLY_PROP_TIME_TO_FULL_AVG + 1,
+ GFP_KERNEL);
+ if (!psyhw->props) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ret = devm_add_action(dev, power_supply_hwmon_bitmap_free,
+ psyhw->props);
+ if (ret)
+ goto error;
+
+ for (i = 0; i < desc->num_properties; i++) {
+ const enum power_supply_property prop = desc->properties[i];
+
+ switch (prop) {
+ case POWER_SUPPLY_PROP_CURRENT_AVG:
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ case POWER_SUPPLY_PROP_TEMP:
+ case POWER_SUPPLY_PROP_TEMP_MAX:
+ case POWER_SUPPLY_PROP_TEMP_MIN:
+ case POWER_SUPPLY_PROP_TEMP_ALERT_MIN:
+ case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
+ case POWER_SUPPLY_PROP_TEMP_AMBIENT:
+ case POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN:
+ case POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX:
+ case POWER_SUPPLY_PROP_VOLTAGE_AVG:
+ case POWER_SUPPLY_PROP_VOLTAGE_MIN:
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ set_bit(prop, psyhw->props);
+ break;
+ default:
+ break;
+ }
+ }
+
+ hwmon = devm_hwmon_device_register_with_info(dev, psy->desc->name,
+ psyhw,
+ &power_supply_hwmon_chip_info,
+ NULL);
+ ret = PTR_ERR_OR_ZERO(hwmon);
+ if (ret)
+ goto error;
+
+ devres_close_group(dev, power_supply_add_hwmon_sysfs);
+ return 0;
+error:
+ devres_release_group(dev, NULL);
+ return ret;
+}
+
+void power_supply_remove_hwmon_sysfs(struct power_supply *psy)
+{
+ devres_release_group(&psy->dev, power_supply_add_hwmon_sysfs);
+}
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index 61430ae878d3..f37ad4eae60b 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -276,6 +276,8 @@ static struct device_attribute power_supply_attrs[] = {
POWER_SUPPLY_ATTR(charge_control_start_threshold),
POWER_SUPPLY_ATTR(charge_control_end_threshold),
POWER_SUPPLY_ATTR(input_current_limit),
+ POWER_SUPPLY_ATTR(input_voltage_limit),
+ POWER_SUPPLY_ATTR(input_power_limit),
POWER_SUPPLY_ATTR(energy_full_design),
POWER_SUPPLY_ATTR(energy_empty_design),
POWER_SUPPLY_ATTR(energy_full),
diff --git a/drivers/power/supply/rt5033_battery.c b/drivers/power/supply/rt5033_battery.c
index 9f0d70648e41..d8667a9fc49b 100644
--- a/drivers/power/supply/rt5033_battery.c
+++ b/drivers/power/supply/rt5033_battery.c
@@ -115,7 +115,7 @@ static const struct power_supply_desc rt5033_battery_desc = {
static int rt5033_battery_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adapter = client->adapter;
struct power_supply_config psy_cfg = {};
struct rt5033_battery *battery;
u32 ret;
diff --git a/drivers/power/supply/rt9455_charger.c b/drivers/power/supply/rt9455_charger.c
index 40a9d329418a..29161ae90245 100644
--- a/drivers/power/supply/rt9455_charger.c
+++ b/drivers/power/supply/rt9455_charger.c
@@ -1584,7 +1584,7 @@ static const struct regmap_config rt9455_regmap_config = {
static int rt9455_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adapter = client->adapter;
struct device *dev = &client->dev;
struct rt9455_info *info;
struct power_supply_config rt9455_charger_config = {};
diff --git a/drivers/power/supply/sbs-manager.c b/drivers/power/supply/sbs-manager.c
index cb6e8f66c7a2..666243d9dd59 100644
--- a/drivers/power/supply/sbs-manager.c
+++ b/drivers/power/supply/sbs-manager.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for SBS compliant Smart Battery System Managers
*
@@ -10,10 +11,6 @@
* Datasheet LTC1760: http://cds.linear.com/docs/en/datasheet/1760fb.pdf
*
* Karl-Heinz Schneider <karl-heinz@schneider-inet.de>
- *
- * 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.
*/
#include <linux/gpio.h>
@@ -317,7 +314,7 @@ static const struct power_supply_desc sbsm_default_psy_desc = {
static int sbsm_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adapter = client->adapter;
struct sbsm_data *data;
struct device *dev = &client->dev;
struct power_supply_desc *psy_desc;
diff --git a/drivers/power/supply/smb347-charger.c b/drivers/power/supply/smb347-charger.c
index 072c5189bd6d..c1d124b8be0c 100644
--- a/drivers/power/supply/smb347-charger.c
+++ b/drivers/power/supply/smb347-charger.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Summit Microelectronics SMB347 Battery Charger Driver
*
@@ -5,10 +6,6 @@
*
* Authors: Bruce E. Robertson <bruce.e.robertson@intel.com>
* Mika Westerberg <mika.westerberg@linux.intel.com>
- *
- * 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.
*/
#include <linux/err.h>
diff --git a/drivers/power/supply/test_power.c b/drivers/power/supply/test_power.c
index 57246cdbd042..c3cad2b6daba 100644
--- a/drivers/power/supply/test_power.c
+++ b/drivers/power/supply/test_power.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Power supply driver for testing.
*
@@ -8,10 +9,6 @@
* By: Masashi YOKOTA <yokota@pylone.jp>
* Originally found here:
* http://downloads.pylone.jp/src/virtual_battery/virtual_battery-0.0.1.tar.bz2
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/power/supply/tosa_battery.c b/drivers/power/supply/tosa_battery.c
index 6e88c1b37945..32cc31cd4761 100644
--- a/drivers/power/supply/tosa_battery.c
+++ b/drivers/power/supply/tosa_battery.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Battery and Power Management code for the Sharp SL-6000x
*
* Copyright (c) 2005 Dirk Opfer
* Copyright (c) 2008 Dmitry Baryshkov
- *
- * 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.
- *
*/
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/power/supply/ucs1002_power.c b/drivers/power/supply/ucs1002_power.c
index 1c89d030c045..1b80ae479e7d 100644
--- a/drivers/power/supply/ucs1002_power.c
+++ b/drivers/power/supply/ucs1002_power.c
@@ -336,7 +336,7 @@ static int ucs1002_get_usb_type(struct ucs1002_info *info,
case F_ACTIVE_MODE_BC12_CDP:
type = POWER_SUPPLY_USB_TYPE_CDP;
break;
- };
+ }
val->intval = type;
diff --git a/drivers/power/supply/wilco-charger.c b/drivers/power/supply/wilco-charger.c
new file mode 100644
index 000000000000..b3c6d7cdd731
--- /dev/null
+++ b/drivers/power/supply/wilco-charger.c
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Charging control driver for the Wilco EC
+ *
+ * Copyright 2019 Google LLC
+ *
+ * See Documentation/ABI/testing/sysfs-class-power and
+ * Documentation/ABI/testing/sysfs-class-power-wilco for userspace interface
+ * and other info.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/wilco-ec.h>
+#include <linux/power_supply.h>
+
+#define DRV_NAME "wilco-charger"
+
+/* Property IDs and related EC constants */
+#define PID_CHARGE_MODE 0x0710
+#define PID_CHARGE_LOWER_LIMIT 0x0711
+#define PID_CHARGE_UPPER_LIMIT 0x0712
+
+enum charge_mode {
+ CHARGE_MODE_STD = 1, /* Used for Standard */
+ CHARGE_MODE_EXP = 2, /* Express Charge, used for Fast */
+ CHARGE_MODE_AC = 3, /* Mostly AC use, used for Trickle */
+ CHARGE_MODE_AUTO = 4, /* Used for Adaptive */
+ CHARGE_MODE_CUSTOM = 5, /* Used for Custom */
+};
+
+#define CHARGE_LOWER_LIMIT_MIN 50
+#define CHARGE_LOWER_LIMIT_MAX 95
+#define CHARGE_UPPER_LIMIT_MIN 55
+#define CHARGE_UPPER_LIMIT_MAX 100
+
+/* Convert from POWER_SUPPLY_PROP_CHARGE_TYPE value to the EC's charge mode */
+static int psp_val_to_charge_mode(int psp_val)
+{
+ switch (psp_val) {
+ case POWER_SUPPLY_CHARGE_TYPE_TRICKLE:
+ return CHARGE_MODE_AC;
+ case POWER_SUPPLY_CHARGE_TYPE_FAST:
+ return CHARGE_MODE_EXP;
+ case POWER_SUPPLY_CHARGE_TYPE_STANDARD:
+ return CHARGE_MODE_STD;
+ case POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE:
+ return CHARGE_MODE_AUTO;
+ case POWER_SUPPLY_CHARGE_TYPE_CUSTOM:
+ return CHARGE_MODE_CUSTOM;
+ default:
+ return -EINVAL;
+ }
+}
+
+/* Convert from EC's charge mode to POWER_SUPPLY_PROP_CHARGE_TYPE value */
+static int charge_mode_to_psp_val(enum charge_mode mode)
+{
+ switch (mode) {
+ case CHARGE_MODE_AC:
+ return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+ case CHARGE_MODE_EXP:
+ return POWER_SUPPLY_CHARGE_TYPE_FAST;
+ case CHARGE_MODE_STD:
+ return POWER_SUPPLY_CHARGE_TYPE_STANDARD;
+ case CHARGE_MODE_AUTO:
+ return POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE;
+ case CHARGE_MODE_CUSTOM:
+ return POWER_SUPPLY_CHARGE_TYPE_CUSTOM;
+ default:
+ return -EINVAL;
+ }
+}
+
+static enum power_supply_property wilco_charge_props[] = {
+ POWER_SUPPLY_PROP_CHARGE_TYPE,
+ POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD,
+ POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD,
+};
+
+static int wilco_charge_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct wilco_ec_device *ec = power_supply_get_drvdata(psy);
+ u32 property_id;
+ int ret;
+ u8 raw;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ property_id = PID_CHARGE_MODE;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD:
+ property_id = PID_CHARGE_LOWER_LIMIT;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
+ property_id = PID_CHARGE_UPPER_LIMIT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = wilco_ec_get_byte_property(ec, property_id, &raw);
+ if (ret < 0)
+ return ret;
+ if (property_id == PID_CHARGE_MODE) {
+ ret = charge_mode_to_psp_val(raw);
+ if (ret < 0)
+ return -EBADMSG;
+ raw = ret;
+ }
+ val->intval = raw;
+
+ return 0;
+}
+
+static int wilco_charge_set_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ struct wilco_ec_device *ec = power_supply_get_drvdata(psy);
+ int mode;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ mode = psp_val_to_charge_mode(val->intval);
+ if (mode < 0)
+ return -EINVAL;
+ return wilco_ec_set_byte_property(ec, PID_CHARGE_MODE, mode);
+ case POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD:
+ if (val->intval < CHARGE_LOWER_LIMIT_MIN ||
+ val->intval > CHARGE_LOWER_LIMIT_MAX)
+ return -EINVAL;
+ return wilco_ec_set_byte_property(ec, PID_CHARGE_LOWER_LIMIT,
+ val->intval);
+ case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
+ if (val->intval < CHARGE_UPPER_LIMIT_MIN ||
+ val->intval > CHARGE_UPPER_LIMIT_MAX)
+ return -EINVAL;
+ return wilco_ec_set_byte_property(ec, PID_CHARGE_UPPER_LIMIT,
+ val->intval);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int wilco_charge_property_is_writeable(struct power_supply *psy,
+ enum power_supply_property psp)
+{
+ return 1;
+}
+
+static const struct power_supply_desc wilco_ps_desc = {
+ .properties = wilco_charge_props,
+ .num_properties = ARRAY_SIZE(wilco_charge_props),
+ .get_property = wilco_charge_get_property,
+ .set_property = wilco_charge_set_property,
+ .property_is_writeable = wilco_charge_property_is_writeable,
+ .name = DRV_NAME,
+ .type = POWER_SUPPLY_TYPE_MAINS,
+};
+
+static int wilco_charge_probe(struct platform_device *pdev)
+{
+ struct wilco_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
+ struct power_supply_config psy_cfg = {};
+ struct power_supply *psy;
+
+ psy_cfg.drv_data = ec;
+ psy = devm_power_supply_register(&pdev->dev, &wilco_ps_desc, &psy_cfg);
+
+ return PTR_ERR_OR_ZERO(psy);
+}
+
+static struct platform_driver wilco_charge_driver = {
+ .probe = wilco_charge_probe,
+ .driver = {
+ .name = DRV_NAME,
+ }
+};
+module_platform_driver(wilco_charge_driver);
+
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_AUTHOR("Nick Crews <ncrews@chromium.org>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Wilco EC charge control driver");
diff --git a/drivers/power/supply/wm831x_backup.c b/drivers/power/supply/wm831x_backup.c
index 2e33109ca8c7..ffb265b8526d 100644
--- a/drivers/power/supply/wm831x_backup.c
+++ b/drivers/power/supply/wm831x_backup.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Backup battery driver for Wolfson Microelectronics wm831x PMICs
*
* Copyright 2009 Wolfson Microelectronics PLC.
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/power/supply/wm831x_power.c b/drivers/power/supply/wm831x_power.c
index 927050d4444d..65832bc229f6 100644
--- a/drivers/power/supply/wm831x_power.c
+++ b/drivers/power/supply/wm831x_power.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* PMU driver for Wolfson Microelectronics wm831x PMICs
*
* Copyright 2009 Wolfson Microelectronics PLC.
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/power/supply/wm8350_power.c b/drivers/power/supply/wm8350_power.c
index 15c0ca15e2aa..26923af574f4 100644
--- a/drivers/power/supply/wm8350_power.c
+++ b/drivers/power/supply/wm8350_power.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Battery driver for wm8350 PMIC
*
@@ -6,10 +7,6 @@
* Based on OLPC Battery Driver
*
* Copyright 2006 David Woodhouse <dwmw2@infradead.org>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/power/supply/wm97xx_battery.c b/drivers/power/supply/wm97xx_battery.c
index 6754e761778a..58f01659daa5 100644
--- a/drivers/power/supply/wm97xx_battery.c
+++ b/drivers/power/supply/wm97xx_battery.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Battery measurement code for WM97xx
*
* based on tosa_battery.c
*
* Copyright (C) 2008 Marek Vasut <marek.vasut@gmail.com>
- *
- * 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.
- *
*/
#include <linux/init.h>
diff --git a/drivers/power/supply/z2_battery.c b/drivers/power/supply/z2_battery.c
index bcc2d1a9b0a7..ebd2e42a4457 100644
--- a/drivers/power/supply/z2_battery.c
+++ b/drivers/power/supply/z2_battery.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Battery measurement code for Zipit Z2
*
* Copyright (C) 2009 Peter Edwards <sweetlilmre@gmail.com>
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/powercap/Kconfig b/drivers/powercap/Kconfig
index 42d3798c88f0..dc1c1381d7fa 100644
--- a/drivers/powercap/Kconfig
+++ b/drivers/powercap/Kconfig
@@ -16,14 +16,17 @@ menuconfig POWERCAP
if POWERCAP
# Client driver configurations go here.
+config INTEL_RAPL_CORE
+ tristate
+
config INTEL_RAPL
- tristate "Intel RAPL Support"
+ tristate "Intel RAPL Support via MSR Interface"
depends on X86 && IOSF_MBI
- default n
+ select INTEL_RAPL_CORE
---help---
This enables support for the Intel Running Average Power Limit (RAPL)
- technology which allows power limits to be enforced and monitored on
- modern Intel processors (Sandy Bridge and later).
+ technology via MSR interface, which allows power limits to be enforced
+ and monitored on modern Intel processors (Sandy Bridge and later).
In RAPL, the platform level settings are divided into domains for
fine grained control. These domains include processor package, DRAM
diff --git a/drivers/powercap/Makefile b/drivers/powercap/Makefile
index 81c8ccaba6e7..7255c94ec61c 100644
--- a/drivers/powercap/Makefile
+++ b/drivers/powercap/Makefile
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_POWERCAP) += powercap_sys.o
-obj-$(CONFIG_INTEL_RAPL) += intel_rapl.o
+obj-$(CONFIG_INTEL_RAPL_CORE) += intel_rapl_common.o
+obj-$(CONFIG_INTEL_RAPL) += intel_rapl_msr.o
obj-$(CONFIG_IDLE_INJECT) += idle_inject.o
diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl_common.c
index f888117b0efc..9fd6dd342169 100644
--- a/drivers/powercap/intel_rapl.c
+++ b/drivers/powercap/intel_rapl_common.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Intel Running Average Power Limit (RAPL) Driver
- * Copyright (c) 2013, Intel Corporation.
+ * Common code for Intel Running Average Power Limit (RAPL) support.
+ * Copyright (c) 2019, Intel Corporation.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -18,9 +18,11 @@
#include <linux/cpu.h>
#include <linux/powercap.h>
#include <linux/suspend.h>
-#include <asm/iosf_mbi.h>
+#include <linux/intel_rapl.h>
+#include <linux/processor.h>
+#include <linux/platform_device.h>
-#include <asm/processor.h>
+#include <asm/iosf_mbi.h>
#include <asm/cpu_device_id.h>
#include <asm/intel-family.h>
@@ -37,8 +39,8 @@
#define POWER_LIMIT2_MASK (0x7FFFULL<<32)
#define POWER_LIMIT2_ENABLE BIT_ULL(47)
#define POWER_LIMIT2_CLAMP BIT_ULL(48)
-#define POWER_PACKAGE_LOCK BIT_ULL(63)
-#define POWER_PP_LOCK BIT(31)
+#define POWER_HIGH_LOCK BIT_ULL(63)
+#define POWER_LOW_LOCK BIT(31)
#define TIME_WINDOW1_MASK (0x7FULL<<17)
#define TIME_WINDOW2_MASK (0x7FULL<<49)
@@ -61,139 +63,38 @@
#define PP_POLICY_MASK 0x1F
/* Non HW constants */
-#define RAPL_PRIMITIVE_DERIVED BIT(1) /* not from raw data */
+#define RAPL_PRIMITIVE_DERIVED BIT(1) /* not from raw data */
#define RAPL_PRIMITIVE_DUMMY BIT(2)
#define TIME_WINDOW_MAX_MSEC 40000
#define TIME_WINDOW_MIN_MSEC 250
-#define ENERGY_UNIT_SCALE 1000 /* scale from driver unit to powercap unit */
+#define ENERGY_UNIT_SCALE 1000 /* scale from driver unit to powercap unit */
enum unit_type {
- ARBITRARY_UNIT, /* no translation */
+ ARBITRARY_UNIT, /* no translation */
POWER_UNIT,
ENERGY_UNIT,
TIME_UNIT,
};
-enum rapl_domain_type {
- RAPL_DOMAIN_PACKAGE, /* entire package/socket */
- RAPL_DOMAIN_PP0, /* core power plane */
- RAPL_DOMAIN_PP1, /* graphics uncore */
- RAPL_DOMAIN_DRAM,/* DRAM control_type */
- RAPL_DOMAIN_PLATFORM, /* PSys control_type */
- RAPL_DOMAIN_MAX,
-};
-
-enum rapl_domain_msr_id {
- RAPL_DOMAIN_MSR_LIMIT,
- RAPL_DOMAIN_MSR_STATUS,
- RAPL_DOMAIN_MSR_PERF,
- RAPL_DOMAIN_MSR_POLICY,
- RAPL_DOMAIN_MSR_INFO,
- RAPL_DOMAIN_MSR_MAX,
-};
-
/* per domain data, some are optional */
-enum rapl_primitives {
- ENERGY_COUNTER,
- POWER_LIMIT1,
- POWER_LIMIT2,
- FW_LOCK,
-
- PL1_ENABLE, /* power limit 1, aka long term */
- PL1_CLAMP, /* allow frequency to go below OS request */
- PL2_ENABLE, /* power limit 2, aka short term, instantaneous */
- PL2_CLAMP,
-
- TIME_WINDOW1, /* long term */
- TIME_WINDOW2, /* short term */
- THERMAL_SPEC_POWER,
- MAX_POWER,
-
- MIN_POWER,
- MAX_TIME_WINDOW,
- THROTTLED_TIME,
- PRIORITY_LEVEL,
-
- /* below are not raw primitive data */
- AVERAGE_POWER,
- NR_RAPL_PRIMITIVES,
-};
-
#define NR_RAW_PRIMITIVES (NR_RAPL_PRIMITIVES - 2)
-/* Can be expanded to include events, etc.*/
-struct rapl_domain_data {
- u64 primitives[NR_RAPL_PRIMITIVES];
- unsigned long timestamp;
-};
-
-struct msrl_action {
- u32 msr_no;
- u64 clear_mask;
- u64 set_mask;
- int err;
-};
-
#define DOMAIN_STATE_INACTIVE BIT(0)
#define DOMAIN_STATE_POWER_LIMIT_SET BIT(1)
#define DOMAIN_STATE_BIOS_LOCKED BIT(2)
-#define NR_POWER_LIMITS (2)
-struct rapl_power_limit {
- struct powercap_zone_constraint *constraint;
- int prim_id; /* primitive ID used to enable */
- struct rapl_domain *domain;
- const char *name;
- u64 last_power_limit;
-};
-
static const char pl1_name[] = "long_term";
static const char pl2_name[] = "short_term";
-struct rapl_package;
-struct rapl_domain {
- const char *name;
- enum rapl_domain_type id;
- int msrs[RAPL_DOMAIN_MSR_MAX];
- struct powercap_zone power_zone;
- struct rapl_domain_data rdd;
- struct rapl_power_limit rpl[NR_POWER_LIMITS];
- u64 attr_map; /* track capabilities */
- unsigned int state;
- unsigned int domain_energy_unit;
- struct rapl_package *rp;
-};
#define power_zone_to_rapl_domain(_zone) \
container_of(_zone, struct rapl_domain, power_zone)
-
-/* Each physical package contains multiple domains, these are the common
- * data across RAPL domains within a package.
- */
-struct rapl_package {
- unsigned int id; /* physical package/socket id */
- unsigned int nr_domains;
- unsigned long domain_map; /* bit map of active domains */
- unsigned int power_unit;
- unsigned int energy_unit;
- unsigned int time_unit;
- struct rapl_domain *domains; /* array of domains, sized at runtime */
- struct powercap_zone *power_zone; /* keep track of parent zone */
- unsigned long power_limit_irq; /* keep track of package power limit
- * notify interrupt enable status.
- */
- struct list_head plist;
- int lead_cpu; /* one active cpu per package for access */
- /* Track active cpus */
- struct cpumask cpumask;
-};
-
struct rapl_defaults {
u8 floor_freq_reg_addr;
int (*check_unit)(struct rapl_package *rp, int cpu);
void (*set_floor_freq)(struct rapl_domain *rd, bool mode);
u64 (*compute_time_window)(struct rapl_package *rp, u64 val,
- bool to_raw);
+ bool to_raw);
unsigned int dram_domain_energy_unit;
};
static struct rapl_defaults *rapl_defaults;
@@ -212,7 +113,7 @@ struct rapl_primitive_info {
const char *name;
u64 mask;
int shift;
- enum rapl_domain_msr_id id;
+ enum rapl_domain_reg_id id;
enum unit_type unit;
u32 flag;
};
@@ -228,19 +129,18 @@ struct rapl_primitive_info {
static void rapl_init_domains(struct rapl_package *rp);
static int rapl_read_data_raw(struct rapl_domain *rd,
- enum rapl_primitives prim,
- bool xlate, u64 *data);
+ enum rapl_primitives prim,
+ bool xlate, u64 *data);
static int rapl_write_data_raw(struct rapl_domain *rd,
- enum rapl_primitives prim,
- unsigned long long value);
+ enum rapl_primitives prim,
+ unsigned long long value);
static u64 rapl_unit_xlate(struct rapl_domain *rd,
- enum unit_type type, u64 value,
- int to_raw);
+ enum unit_type type, u64 value, int to_raw);
static void package_power_limit_irq_save(struct rapl_package *rp);
-static LIST_HEAD(rapl_packages); /* guarded by CPU hotplug lock */
+static LIST_HEAD(rapl_packages); /* guarded by CPU hotplug lock */
-static const char * const rapl_domain_names[] = {
+static const char *const rapl_domain_names[] = {
"package",
"core",
"uncore",
@@ -248,23 +148,8 @@ static const char * const rapl_domain_names[] = {
"psys",
};
-static struct powercap_control_type *control_type; /* PowerCap Controller */
-static struct rapl_domain *platform_rapl_domain; /* Platform (PSys) domain */
-
-/* caller to ensure CPU hotplug lock is held */
-static struct rapl_package *find_package_by_id(int id)
-{
- struct rapl_package *rp;
-
- list_for_each_entry(rp, &rapl_packages, plist) {
- if (rp->id == id)
- return rp;
- }
-
- return NULL;
-}
-
-static int get_energy_counter(struct powercap_zone *power_zone, u64 *energy_raw)
+static int get_energy_counter(struct powercap_zone *power_zone,
+ u64 *energy_raw)
{
struct rapl_domain *rd;
u64 energy_now;
@@ -363,50 +248,49 @@ static int get_domain_enable(struct powercap_zone *power_zone, bool *mode)
static const struct powercap_zone_ops zone_ops[] = {
/* RAPL_DOMAIN_PACKAGE */
{
- .get_energy_uj = get_energy_counter,
- .get_max_energy_range_uj = get_max_energy_counter,
- .release = release_zone,
- .set_enable = set_domain_enable,
- .get_enable = get_domain_enable,
- },
+ .get_energy_uj = get_energy_counter,
+ .get_max_energy_range_uj = get_max_energy_counter,
+ .release = release_zone,
+ .set_enable = set_domain_enable,
+ .get_enable = get_domain_enable,
+ },
/* RAPL_DOMAIN_PP0 */
{
- .get_energy_uj = get_energy_counter,
- .get_max_energy_range_uj = get_max_energy_counter,
- .release = release_zone,
- .set_enable = set_domain_enable,
- .get_enable = get_domain_enable,
- },
+ .get_energy_uj = get_energy_counter,
+ .get_max_energy_range_uj = get_max_energy_counter,
+ .release = release_zone,
+ .set_enable = set_domain_enable,
+ .get_enable = get_domain_enable,
+ },
/* RAPL_DOMAIN_PP1 */
{
- .get_energy_uj = get_energy_counter,
- .get_max_energy_range_uj = get_max_energy_counter,
- .release = release_zone,
- .set_enable = set_domain_enable,
- .get_enable = get_domain_enable,
- },
+ .get_energy_uj = get_energy_counter,
+ .get_max_energy_range_uj = get_max_energy_counter,
+ .release = release_zone,
+ .set_enable = set_domain_enable,
+ .get_enable = get_domain_enable,
+ },
/* RAPL_DOMAIN_DRAM */
{
- .get_energy_uj = get_energy_counter,
- .get_max_energy_range_uj = get_max_energy_counter,
- .release = release_zone,
- .set_enable = set_domain_enable,
- .get_enable = get_domain_enable,
- },
+ .get_energy_uj = get_energy_counter,
+ .get_max_energy_range_uj = get_max_energy_counter,
+ .release = release_zone,
+ .set_enable = set_domain_enable,
+ .get_enable = get_domain_enable,
+ },
/* RAPL_DOMAIN_PLATFORM */
{
- .get_energy_uj = get_energy_counter,
- .get_max_energy_range_uj = get_max_energy_counter,
- .release = release_zone,
- .set_enable = set_domain_enable,
- .get_enable = get_domain_enable,
- },
+ .get_energy_uj = get_energy_counter,
+ .get_max_energy_range_uj = get_max_energy_counter,
+ .release = release_zone,
+ .set_enable = set_domain_enable,
+ .get_enable = get_domain_enable,
+ },
};
-
/*
* Constraint index used by powercap can be different than power limit (PL)
- * index in that some PLs maybe missing due to non-existant MSRs. So we
+ * index in that some PLs maybe missing due to non-existent MSRs. So we
* need to convert here by finding the valid PLs only (name populated).
*/
static int contraint_to_pl(struct rapl_domain *rd, int cid)
@@ -425,7 +309,7 @@ static int contraint_to_pl(struct rapl_domain *rd, int cid)
}
static int set_power_limit(struct powercap_zone *power_zone, int cid,
- u64 power_limit)
+ u64 power_limit)
{
struct rapl_domain *rd;
struct rapl_package *rp;
@@ -443,8 +327,8 @@ static int set_power_limit(struct powercap_zone *power_zone, int cid,
rp = rd->rp;
if (rd->state & DOMAIN_STATE_BIOS_LOCKED) {
- dev_warn(&power_zone->dev, "%s locked by BIOS, monitoring only\n",
- rd->name);
+ dev_warn(&power_zone->dev,
+ "%s locked by BIOS, monitoring only\n", rd->name);
ret = -EACCES;
goto set_exit;
}
@@ -467,7 +351,7 @@ set_exit:
}
static int get_current_power_limit(struct powercap_zone *power_zone, int cid,
- u64 *data)
+ u64 *data)
{
struct rapl_domain *rd;
u64 val;
@@ -506,7 +390,7 @@ get_exit:
}
static int set_time_window(struct powercap_zone *power_zone, int cid,
- u64 window)
+ u64 window)
{
struct rapl_domain *rd;
int ret = 0;
@@ -536,7 +420,8 @@ set_time_exit:
return ret;
}
-static int get_time_window(struct powercap_zone *power_zone, int cid, u64 *data)
+static int get_time_window(struct powercap_zone *power_zone, int cid,
+ u64 *data)
{
struct rapl_domain *rd;
u64 val;
@@ -571,7 +456,8 @@ get_time_exit:
return ret;
}
-static const char *get_constraint_name(struct powercap_zone *power_zone, int cid)
+static const char *get_constraint_name(struct powercap_zone *power_zone,
+ int cid)
{
struct rapl_domain *rd;
int id;
@@ -584,9 +470,7 @@ static const char *get_constraint_name(struct powercap_zone *power_zone, int cid
return NULL;
}
-
-static int get_max_power(struct powercap_zone *power_zone, int id,
- u64 *data)
+static int get_max_power(struct powercap_zone *power_zone, int id, u64 *data)
{
struct rapl_domain *rd;
u64 val;
@@ -628,73 +512,43 @@ static const struct powercap_zone_constraint_ops constraint_ops = {
/* called after domain detection and package level data are set */
static void rapl_init_domains(struct rapl_package *rp)
{
- int i;
+ enum rapl_domain_type i;
+ enum rapl_domain_reg_id j;
struct rapl_domain *rd = rp->domains;
for (i = 0; i < RAPL_DOMAIN_MAX; i++) {
unsigned int mask = rp->domain_map & (1 << i);
- switch (mask) {
- case BIT(RAPL_DOMAIN_PACKAGE):
- rd->name = rapl_domain_names[RAPL_DOMAIN_PACKAGE];
- rd->id = RAPL_DOMAIN_PACKAGE;
- rd->msrs[0] = MSR_PKG_POWER_LIMIT;
- rd->msrs[1] = MSR_PKG_ENERGY_STATUS;
- rd->msrs[2] = MSR_PKG_PERF_STATUS;
- rd->msrs[3] = 0;
- rd->msrs[4] = MSR_PKG_POWER_INFO;
- rd->rpl[0].prim_id = PL1_ENABLE;
- rd->rpl[0].name = pl1_name;
+
+ if (!mask)
+ continue;
+
+ rd->rp = rp;
+ rd->name = rapl_domain_names[i];
+ rd->id = i;
+ rd->rpl[0].prim_id = PL1_ENABLE;
+ rd->rpl[0].name = pl1_name;
+ /* some domain may support two power limits */
+ if (rp->priv->limits[i] == 2) {
rd->rpl[1].prim_id = PL2_ENABLE;
rd->rpl[1].name = pl2_name;
- break;
- case BIT(RAPL_DOMAIN_PP0):
- rd->name = rapl_domain_names[RAPL_DOMAIN_PP0];
- rd->id = RAPL_DOMAIN_PP0;
- rd->msrs[0] = MSR_PP0_POWER_LIMIT;
- rd->msrs[1] = MSR_PP0_ENERGY_STATUS;
- rd->msrs[2] = 0;
- rd->msrs[3] = MSR_PP0_POLICY;
- rd->msrs[4] = 0;
- rd->rpl[0].prim_id = PL1_ENABLE;
- rd->rpl[0].name = pl1_name;
- break;
- case BIT(RAPL_DOMAIN_PP1):
- rd->name = rapl_domain_names[RAPL_DOMAIN_PP1];
- rd->id = RAPL_DOMAIN_PP1;
- rd->msrs[0] = MSR_PP1_POWER_LIMIT;
- rd->msrs[1] = MSR_PP1_ENERGY_STATUS;
- rd->msrs[2] = 0;
- rd->msrs[3] = MSR_PP1_POLICY;
- rd->msrs[4] = 0;
- rd->rpl[0].prim_id = PL1_ENABLE;
- rd->rpl[0].name = pl1_name;
- break;
- case BIT(RAPL_DOMAIN_DRAM):
- rd->name = rapl_domain_names[RAPL_DOMAIN_DRAM];
- rd->id = RAPL_DOMAIN_DRAM;
- rd->msrs[0] = MSR_DRAM_POWER_LIMIT;
- rd->msrs[1] = MSR_DRAM_ENERGY_STATUS;
- rd->msrs[2] = MSR_DRAM_PERF_STATUS;
- rd->msrs[3] = 0;
- rd->msrs[4] = MSR_DRAM_POWER_INFO;
- rd->rpl[0].prim_id = PL1_ENABLE;
- rd->rpl[0].name = pl1_name;
+ }
+
+ for (j = 0; j < RAPL_DOMAIN_REG_MAX; j++)
+ rd->regs[j] = rp->priv->regs[i][j];
+
+ if (i == RAPL_DOMAIN_DRAM) {
rd->domain_energy_unit =
- rapl_defaults->dram_domain_energy_unit;
+ rapl_defaults->dram_domain_energy_unit;
if (rd->domain_energy_unit)
pr_info("DRAM domain energy unit %dpj\n",
rd->domain_energy_unit);
- break;
- }
- if (mask) {
- rd->rp = rp;
- rd++;
}
+ rd++;
}
}
static u64 rapl_unit_xlate(struct rapl_domain *rd, enum unit_type type,
- u64 value, int to_raw)
+ u64 value, int to_raw)
{
u64 units = 1;
struct rapl_package *rp = rd->rp;
@@ -731,40 +585,40 @@ static u64 rapl_unit_xlate(struct rapl_domain *rd, enum unit_type type,
static struct rapl_primitive_info rpi[] = {
/* name, mask, shift, msr index, unit divisor */
PRIMITIVE_INFO_INIT(ENERGY_COUNTER, ENERGY_STATUS_MASK, 0,
- RAPL_DOMAIN_MSR_STATUS, ENERGY_UNIT, 0),
+ RAPL_DOMAIN_REG_STATUS, ENERGY_UNIT, 0),
PRIMITIVE_INFO_INIT(POWER_LIMIT1, POWER_LIMIT1_MASK, 0,
- RAPL_DOMAIN_MSR_LIMIT, POWER_UNIT, 0),
+ RAPL_DOMAIN_REG_LIMIT, POWER_UNIT, 0),
PRIMITIVE_INFO_INIT(POWER_LIMIT2, POWER_LIMIT2_MASK, 32,
- RAPL_DOMAIN_MSR_LIMIT, POWER_UNIT, 0),
- PRIMITIVE_INFO_INIT(FW_LOCK, POWER_PP_LOCK, 31,
- RAPL_DOMAIN_MSR_LIMIT, ARBITRARY_UNIT, 0),
+ RAPL_DOMAIN_REG_LIMIT, POWER_UNIT, 0),
+ PRIMITIVE_INFO_INIT(FW_LOCK, POWER_LOW_LOCK, 31,
+ RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0),
PRIMITIVE_INFO_INIT(PL1_ENABLE, POWER_LIMIT1_ENABLE, 15,
- RAPL_DOMAIN_MSR_LIMIT, ARBITRARY_UNIT, 0),
+ RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0),
PRIMITIVE_INFO_INIT(PL1_CLAMP, POWER_LIMIT1_CLAMP, 16,
- RAPL_DOMAIN_MSR_LIMIT, ARBITRARY_UNIT, 0),
+ RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0),
PRIMITIVE_INFO_INIT(PL2_ENABLE, POWER_LIMIT2_ENABLE, 47,
- RAPL_DOMAIN_MSR_LIMIT, ARBITRARY_UNIT, 0),
+ RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0),
PRIMITIVE_INFO_INIT(PL2_CLAMP, POWER_LIMIT2_CLAMP, 48,
- RAPL_DOMAIN_MSR_LIMIT, ARBITRARY_UNIT, 0),
+ RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0),
PRIMITIVE_INFO_INIT(TIME_WINDOW1, TIME_WINDOW1_MASK, 17,
- RAPL_DOMAIN_MSR_LIMIT, TIME_UNIT, 0),
+ RAPL_DOMAIN_REG_LIMIT, TIME_UNIT, 0),
PRIMITIVE_INFO_INIT(TIME_WINDOW2, TIME_WINDOW2_MASK, 49,
- RAPL_DOMAIN_MSR_LIMIT, TIME_UNIT, 0),
+ RAPL_DOMAIN_REG_LIMIT, TIME_UNIT, 0),
PRIMITIVE_INFO_INIT(THERMAL_SPEC_POWER, POWER_INFO_THERMAL_SPEC_MASK,
- 0, RAPL_DOMAIN_MSR_INFO, POWER_UNIT, 0),
+ 0, RAPL_DOMAIN_REG_INFO, POWER_UNIT, 0),
PRIMITIVE_INFO_INIT(MAX_POWER, POWER_INFO_MAX_MASK, 32,
- RAPL_DOMAIN_MSR_INFO, POWER_UNIT, 0),
+ RAPL_DOMAIN_REG_INFO, POWER_UNIT, 0),
PRIMITIVE_INFO_INIT(MIN_POWER, POWER_INFO_MIN_MASK, 16,
- RAPL_DOMAIN_MSR_INFO, POWER_UNIT, 0),
+ RAPL_DOMAIN_REG_INFO, POWER_UNIT, 0),
PRIMITIVE_INFO_INIT(MAX_TIME_WINDOW, POWER_INFO_MAX_TIME_WIN_MASK, 48,
- RAPL_DOMAIN_MSR_INFO, TIME_UNIT, 0),
+ RAPL_DOMAIN_REG_INFO, TIME_UNIT, 0),
PRIMITIVE_INFO_INIT(THROTTLED_TIME, PERF_STATUS_THROTTLE_TIME_MASK, 0,
- RAPL_DOMAIN_MSR_PERF, TIME_UNIT, 0),
+ RAPL_DOMAIN_REG_PERF, TIME_UNIT, 0),
PRIMITIVE_INFO_INIT(PRIORITY_LEVEL, PP_POLICY_MASK, 0,
- RAPL_DOMAIN_MSR_POLICY, ARBITRARY_UNIT, 0),
+ RAPL_DOMAIN_REG_POLICY, ARBITRARY_UNIT, 0),
/* non-hardware */
PRIMITIVE_INFO_INIT(AVERAGE_POWER, 0, 0, 0, POWER_UNIT,
- RAPL_PRIMITIVE_DERIVED),
+ RAPL_PRIMITIVE_DERIVED),
{NULL, 0, 0, 0},
};
@@ -782,26 +636,25 @@ static struct rapl_primitive_info rpi[] = {
* 63-------------------------- 31--------------------------- 0
*/
static int rapl_read_data_raw(struct rapl_domain *rd,
- enum rapl_primitives prim,
- bool xlate, u64 *data)
+ enum rapl_primitives prim, bool xlate, u64 *data)
{
- u64 value, final;
- u32 msr;
+ u64 value;
struct rapl_primitive_info *rp = &rpi[prim];
+ struct reg_action ra;
int cpu;
if (!rp->name || rp->flag & RAPL_PRIMITIVE_DUMMY)
return -EINVAL;
- msr = rd->msrs[rp->id];
- if (!msr)
+ ra.reg = rd->regs[rp->id];
+ if (!ra.reg)
return -EINVAL;
cpu = rd->rp->lead_cpu;
- /* special-case package domain, which uses a different bit*/
- if (prim == FW_LOCK && rd->id == RAPL_DOMAIN_PACKAGE) {
- rp->mask = POWER_PACKAGE_LOCK;
+ /* domain with 2 limits has different bit */
+ if (prim == FW_LOCK && rd->rp->priv->limits[rd->id] == 2) {
+ rp->mask = POWER_HIGH_LOCK;
rp->shift = 63;
}
/* non-hardware data are collected by the polling thread */
@@ -810,56 +663,32 @@ static int rapl_read_data_raw(struct rapl_domain *rd,
return 0;
}
- if (rdmsrl_safe_on_cpu(cpu, msr, &value)) {
- pr_debug("failed to read msr 0x%x on cpu %d\n", msr, cpu);
+ ra.mask = rp->mask;
+
+ if (rd->rp->priv->read_raw(cpu, &ra)) {
+ pr_debug("failed to read reg 0x%llx on cpu %d\n", ra.reg, cpu);
return -EIO;
}
- final = value & rp->mask;
- final = final >> rp->shift;
+ value = ra.value >> rp->shift;
+
if (xlate)
- *data = rapl_unit_xlate(rd, rp->unit, final, 0);
+ *data = rapl_unit_xlate(rd, rp->unit, value, 0);
else
- *data = final;
+ *data = value;
return 0;
}
-
-static int msrl_update_safe(u32 msr_no, u64 clear_mask, u64 set_mask)
-{
- int err;
- u64 val;
-
- err = rdmsrl_safe(msr_no, &val);
- if (err)
- goto out;
-
- val &= ~clear_mask;
- val |= set_mask;
-
- err = wrmsrl_safe(msr_no, val);
-
-out:
- return err;
-}
-
-static void msrl_update_func(void *info)
-{
- struct msrl_action *ma = info;
-
- ma->err = msrl_update_safe(ma->msr_no, ma->clear_mask, ma->set_mask);
-}
-
/* Similar use of primitive info in the read counterpart */
static int rapl_write_data_raw(struct rapl_domain *rd,
- enum rapl_primitives prim,
- unsigned long long value)
+ enum rapl_primitives prim,
+ unsigned long long value)
{
struct rapl_primitive_info *rp = &rpi[prim];
int cpu;
u64 bits;
- struct msrl_action ma;
+ struct reg_action ra;
int ret;
cpu = rd->rp->lead_cpu;
@@ -867,17 +696,13 @@ static int rapl_write_data_raw(struct rapl_domain *rd,
bits <<= rp->shift;
bits &= rp->mask;
- memset(&ma, 0, sizeof(ma));
+ memset(&ra, 0, sizeof(ra));
- ma.msr_no = rd->msrs[rp->id];
- ma.clear_mask = rp->mask;
- ma.set_mask = bits;
+ ra.reg = rd->regs[rp->id];
+ ra.mask = rp->mask;
+ ra.value = bits;
- ret = smp_call_function_single(cpu, msrl_update_func, &ma, 1);
- if (ret)
- WARN_ON_ONCE(ret);
- else
- ret = ma.err;
+ ret = rd->rp->priv->write_raw(cpu, &ra);
return ret;
}
@@ -895,51 +720,56 @@ static int rapl_write_data_raw(struct rapl_domain *rd,
*/
static int rapl_check_unit_core(struct rapl_package *rp, int cpu)
{
- u64 msr_val;
+ struct reg_action ra;
u32 value;
- if (rdmsrl_safe_on_cpu(cpu, MSR_RAPL_POWER_UNIT, &msr_val)) {
- pr_err("Failed to read power unit MSR 0x%x on CPU %d, exit.\n",
- MSR_RAPL_POWER_UNIT, cpu);
+ ra.reg = rp->priv->reg_unit;
+ ra.mask = ~0;
+ if (rp->priv->read_raw(cpu, &ra)) {
+ pr_err("Failed to read power unit REG 0x%llx on CPU %d, exit.\n",
+ rp->priv->reg_unit, cpu);
return -ENODEV;
}
- value = (msr_val & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET;
+ value = (ra.value & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET;
rp->energy_unit = ENERGY_UNIT_SCALE * 1000000 / (1 << value);
- value = (msr_val & POWER_UNIT_MASK) >> POWER_UNIT_OFFSET;
+ value = (ra.value & POWER_UNIT_MASK) >> POWER_UNIT_OFFSET;
rp->power_unit = 1000000 / (1 << value);
- value = (msr_val & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET;
+ value = (ra.value & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET;
rp->time_unit = 1000000 / (1 << value);
- pr_debug("Core CPU package %d energy=%dpJ, time=%dus, power=%duW\n",
- rp->id, rp->energy_unit, rp->time_unit, rp->power_unit);
+ pr_debug("Core CPU %s energy=%dpJ, time=%dus, power=%duW\n",
+ rp->name, rp->energy_unit, rp->time_unit, rp->power_unit);
return 0;
}
static int rapl_check_unit_atom(struct rapl_package *rp, int cpu)
{
- u64 msr_val;
+ struct reg_action ra;
u32 value;
- if (rdmsrl_safe_on_cpu(cpu, MSR_RAPL_POWER_UNIT, &msr_val)) {
- pr_err("Failed to read power unit MSR 0x%x on CPU %d, exit.\n",
- MSR_RAPL_POWER_UNIT, cpu);
+ ra.reg = rp->priv->reg_unit;
+ ra.mask = ~0;
+ if (rp->priv->read_raw(cpu, &ra)) {
+ pr_err("Failed to read power unit REG 0x%llx on CPU %d, exit.\n",
+ rp->priv->reg_unit, cpu);
return -ENODEV;
}
- value = (msr_val & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET;
+
+ value = (ra.value & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET;
rp->energy_unit = ENERGY_UNIT_SCALE * 1 << value;
- value = (msr_val & POWER_UNIT_MASK) >> POWER_UNIT_OFFSET;
+ value = (ra.value & POWER_UNIT_MASK) >> POWER_UNIT_OFFSET;
rp->power_unit = (1 << value) * 1000;
- value = (msr_val & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET;
+ value = (ra.value & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET;
rp->time_unit = 1000000 / (1 << value);
- pr_debug("Atom package %d energy=%dpJ, time=%dus, power=%duW\n",
- rp->id, rp->energy_unit, rp->time_unit, rp->power_unit);
+ pr_debug("Atom %s energy=%dpJ, time=%dus, power=%duW\n",
+ rp->name, rp->energy_unit, rp->time_unit, rp->power_unit);
return 0;
}
@@ -959,7 +789,6 @@ static void power_limit_irq_save_cpu(void *info)
wrmsr_safe(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
}
-
/* REVISIT:
* When package power limit is set artificially low by RAPL, LVT
* thermal interrupt for package power limit should be ignored
@@ -1043,9 +872,9 @@ static void set_floor_freq_atom(struct rapl_domain *rd, bool enable)
}
static u64 rapl_compute_time_window_core(struct rapl_package *rp, u64 value,
- bool to_raw)
+ bool to_raw)
{
- u64 f, y; /* fraction and exp. used for time unit */
+ u64 f, y; /* fraction and exp. used for time unit */
/*
* Special processing based on 2^Y*(1+F/4), refer
@@ -1065,7 +894,7 @@ static u64 rapl_compute_time_window_core(struct rapl_package *rp, u64 value,
}
static u64 rapl_compute_time_window_atom(struct rapl_package *rp, u64 value,
- bool to_raw)
+ bool to_raw)
{
/*
* Atom time unit encoding is straight forward val * time_unit,
@@ -1073,8 +902,8 @@ static u64 rapl_compute_time_window_atom(struct rapl_package *rp, u64 value,
*/
if (!to_raw)
return (value) ? value *= rp->time_unit : rp->time_unit;
- else
- value = div64_u64(value, rp->time_unit);
+
+ value = div64_u64(value, rp->time_unit);
return value;
}
@@ -1122,43 +951,48 @@ static const struct rapl_defaults rapl_defaults_cht = {
};
static const struct x86_cpu_id rapl_ids[] __initconst = {
- INTEL_CPU_FAM6(SANDYBRIDGE, rapl_defaults_core),
- INTEL_CPU_FAM6(SANDYBRIDGE_X, rapl_defaults_core),
-
- INTEL_CPU_FAM6(IVYBRIDGE, rapl_defaults_core),
- INTEL_CPU_FAM6(IVYBRIDGE_X, rapl_defaults_core),
-
- INTEL_CPU_FAM6(HASWELL_CORE, rapl_defaults_core),
- INTEL_CPU_FAM6(HASWELL_ULT, rapl_defaults_core),
- INTEL_CPU_FAM6(HASWELL_GT3E, rapl_defaults_core),
- INTEL_CPU_FAM6(HASWELL_X, rapl_defaults_hsw_server),
-
- INTEL_CPU_FAM6(BROADWELL_CORE, rapl_defaults_core),
- INTEL_CPU_FAM6(BROADWELL_GT3E, rapl_defaults_core),
- INTEL_CPU_FAM6(BROADWELL_XEON_D, rapl_defaults_core),
- INTEL_CPU_FAM6(BROADWELL_X, rapl_defaults_hsw_server),
-
- INTEL_CPU_FAM6(SKYLAKE_DESKTOP, rapl_defaults_core),
- INTEL_CPU_FAM6(SKYLAKE_MOBILE, rapl_defaults_core),
- INTEL_CPU_FAM6(SKYLAKE_X, rapl_defaults_hsw_server),
- INTEL_CPU_FAM6(KABYLAKE_MOBILE, rapl_defaults_core),
- INTEL_CPU_FAM6(KABYLAKE_DESKTOP, rapl_defaults_core),
- INTEL_CPU_FAM6(CANNONLAKE_MOBILE, rapl_defaults_core),
- INTEL_CPU_FAM6(ICELAKE_MOBILE, rapl_defaults_core),
-
- INTEL_CPU_FAM6(ATOM_SILVERMONT, rapl_defaults_byt),
- INTEL_CPU_FAM6(ATOM_AIRMONT, rapl_defaults_cht),
- INTEL_CPU_FAM6(ATOM_SILVERMONT_MID, rapl_defaults_tng),
- INTEL_CPU_FAM6(ATOM_AIRMONT_MID, rapl_defaults_ann),
- INTEL_CPU_FAM6(ATOM_GOLDMONT, rapl_defaults_core),
- INTEL_CPU_FAM6(ATOM_GOLDMONT_PLUS, rapl_defaults_core),
- INTEL_CPU_FAM6(ATOM_GOLDMONT_X, rapl_defaults_core),
- INTEL_CPU_FAM6(ATOM_TREMONT_X, rapl_defaults_core),
-
- INTEL_CPU_FAM6(XEON_PHI_KNL, rapl_defaults_hsw_server),
- INTEL_CPU_FAM6(XEON_PHI_KNM, rapl_defaults_hsw_server),
+ INTEL_CPU_FAM6(SANDYBRIDGE, rapl_defaults_core),
+ INTEL_CPU_FAM6(SANDYBRIDGE_X, rapl_defaults_core),
+
+ INTEL_CPU_FAM6(IVYBRIDGE, rapl_defaults_core),
+ INTEL_CPU_FAM6(IVYBRIDGE_X, rapl_defaults_core),
+
+ INTEL_CPU_FAM6(HASWELL_CORE, rapl_defaults_core),
+ INTEL_CPU_FAM6(HASWELL_ULT, rapl_defaults_core),
+ INTEL_CPU_FAM6(HASWELL_GT3E, rapl_defaults_core),
+ INTEL_CPU_FAM6(HASWELL_X, rapl_defaults_hsw_server),
+
+ INTEL_CPU_FAM6(BROADWELL_CORE, rapl_defaults_core),
+ INTEL_CPU_FAM6(BROADWELL_GT3E, rapl_defaults_core),
+ INTEL_CPU_FAM6(BROADWELL_XEON_D, rapl_defaults_core),
+ INTEL_CPU_FAM6(BROADWELL_X, rapl_defaults_hsw_server),
+
+ INTEL_CPU_FAM6(SKYLAKE_DESKTOP, rapl_defaults_core),
+ INTEL_CPU_FAM6(SKYLAKE_MOBILE, rapl_defaults_core),
+ INTEL_CPU_FAM6(SKYLAKE_X, rapl_defaults_hsw_server),
+ INTEL_CPU_FAM6(KABYLAKE_MOBILE, rapl_defaults_core),
+ INTEL_CPU_FAM6(KABYLAKE_DESKTOP, rapl_defaults_core),
+ INTEL_CPU_FAM6(CANNONLAKE_MOBILE, rapl_defaults_core),
+ INTEL_CPU_FAM6(ICELAKE_MOBILE, rapl_defaults_core),
+ INTEL_CPU_FAM6(ICELAKE_DESKTOP, rapl_defaults_core),
+ INTEL_CPU_FAM6(ICELAKE_NNPI, rapl_defaults_core),
+ INTEL_CPU_FAM6(ICELAKE_X, rapl_defaults_hsw_server),
+ INTEL_CPU_FAM6(ICELAKE_XEON_D, rapl_defaults_hsw_server),
+
+ INTEL_CPU_FAM6(ATOM_SILVERMONT, rapl_defaults_byt),
+ INTEL_CPU_FAM6(ATOM_AIRMONT, rapl_defaults_cht),
+ INTEL_CPU_FAM6(ATOM_SILVERMONT_MID, rapl_defaults_tng),
+ INTEL_CPU_FAM6(ATOM_AIRMONT_MID, rapl_defaults_ann),
+ INTEL_CPU_FAM6(ATOM_GOLDMONT, rapl_defaults_core),
+ INTEL_CPU_FAM6(ATOM_GOLDMONT_PLUS, rapl_defaults_core),
+ INTEL_CPU_FAM6(ATOM_GOLDMONT_X, rapl_defaults_core),
+ INTEL_CPU_FAM6(ATOM_TREMONT_X, rapl_defaults_core),
+
+ INTEL_CPU_FAM6(XEON_PHI_KNL, rapl_defaults_hsw_server),
+ INTEL_CPU_FAM6(XEON_PHI_KNM, rapl_defaults_hsw_server),
{}
};
+
MODULE_DEVICE_TABLE(x86cpu, rapl_ids);
/* Read once for all raw primitive data for domains */
@@ -1168,56 +1002,39 @@ static void rapl_update_domain_data(struct rapl_package *rp)
u64 val;
for (dmn = 0; dmn < rp->nr_domains; dmn++) {
- pr_debug("update package %d domain %s data\n", rp->id,
+ pr_debug("update %s domain %s data\n", rp->name,
rp->domains[dmn].name);
/* exclude non-raw primitives */
for (prim = 0; prim < NR_RAW_PRIMITIVES; prim++) {
if (!rapl_read_data_raw(&rp->domains[dmn], prim,
rpi[prim].unit, &val))
- rp->domains[dmn].rdd.primitives[prim] = val;
+ rp->domains[dmn].rdd.primitives[prim] = val;
}
}
}
-static void rapl_unregister_powercap(void)
-{
- if (platform_rapl_domain) {
- powercap_unregister_zone(control_type,
- &platform_rapl_domain->power_zone);
- kfree(platform_rapl_domain);
- }
- powercap_unregister_control_type(control_type);
-}
-
static int rapl_package_register_powercap(struct rapl_package *rp)
{
struct rapl_domain *rd;
- char dev_name[17]; /* max domain name = 7 + 1 + 8 for int + 1 for null*/
struct powercap_zone *power_zone = NULL;
int nr_pl, ret;
/* Update the domain data of the new package */
rapl_update_domain_data(rp);
- /* first we register package domain as the parent zone*/
+ /* first we register package domain as the parent zone */
for (rd = rp->domains; rd < rp->domains + rp->nr_domains; rd++) {
if (rd->id == RAPL_DOMAIN_PACKAGE) {
nr_pl = find_nr_power_limit(rd);
- pr_debug("register socket %d package domain %s\n",
- rp->id, rd->name);
- memset(dev_name, 0, sizeof(dev_name));
- snprintf(dev_name, sizeof(dev_name), "%s-%d",
- rd->name, rp->id);
+ pr_debug("register package domain %s\n", rp->name);
power_zone = powercap_register_zone(&rd->power_zone,
- control_type,
- dev_name, NULL,
- &zone_ops[rd->id],
- nr_pl,
- &constraint_ops);
+ rp->priv->control_type, rp->name,
+ NULL, &zone_ops[rd->id], nr_pl,
+ &constraint_ops);
if (IS_ERR(power_zone)) {
- pr_debug("failed to register package, %d\n",
- rp->id);
+ pr_debug("failed to register power zone %s\n",
+ rp->name);
return PTR_ERR(power_zone);
}
/* track parent zone in per package/socket data */
@@ -1230,21 +1047,21 @@ static int rapl_package_register_powercap(struct rapl_package *rp)
pr_err("no package domain found, unknown topology!\n");
return -ENODEV;
}
- /* now register domains as children of the socket/package*/
+ /* now register domains as children of the socket/package */
for (rd = rp->domains; rd < rp->domains + rp->nr_domains; rd++) {
if (rd->id == RAPL_DOMAIN_PACKAGE)
continue;
/* number of power limits per domain varies */
nr_pl = find_nr_power_limit(rd);
power_zone = powercap_register_zone(&rd->power_zone,
- control_type, rd->name,
- rp->power_zone,
- &zone_ops[rd->id], nr_pl,
- &constraint_ops);
+ rp->priv->control_type,
+ rd->name, rp->power_zone,
+ &zone_ops[rd->id], nr_pl,
+ &constraint_ops);
if (IS_ERR(power_zone)) {
- pr_debug("failed to register power_zone, %d:%s:%s\n",
- rp->id, rd->name, dev_name);
+ pr_debug("failed to register power_zone, %s:%s\n",
+ rp->name, rd->name);
ret = PTR_ERR(power_zone);
goto err_cleanup;
}
@@ -1257,23 +1074,31 @@ err_cleanup:
* failed after the first domain setup.
*/
while (--rd >= rp->domains) {
- pr_debug("unregister package %d domain %s\n", rp->id, rd->name);
- powercap_unregister_zone(control_type, &rd->power_zone);
+ pr_debug("unregister %s domain %s\n", rp->name, rd->name);
+ powercap_unregister_zone(rp->priv->control_type,
+ &rd->power_zone);
}
return ret;
}
-static int __init rapl_register_psys(void)
+int rapl_add_platform_domain(struct rapl_if_priv *priv)
{
struct rapl_domain *rd;
struct powercap_zone *power_zone;
- u64 val;
+ struct reg_action ra;
+ int ret;
- if (rdmsrl_safe_on_cpu(0, MSR_PLATFORM_ENERGY_STATUS, &val) || !val)
+ ra.reg = priv->regs[RAPL_DOMAIN_PLATFORM][RAPL_DOMAIN_REG_STATUS];
+ ra.mask = ~0;
+ ret = priv->read_raw(0, &ra);
+ if (ret || !ra.value)
return -ENODEV;
- if (rdmsrl_safe_on_cpu(0, MSR_PLATFORM_POWER_LIMIT, &val) || !val)
+ ra.reg = priv->regs[RAPL_DOMAIN_PLATFORM][RAPL_DOMAIN_REG_LIMIT];
+ ra.mask = ~0;
+ ret = priv->read_raw(0, &ra);
+ if (ret || !ra.value)
return -ENODEV;
rd = kzalloc(sizeof(*rd), GFP_KERNEL);
@@ -1282,15 +1107,17 @@ static int __init rapl_register_psys(void)
rd->name = rapl_domain_names[RAPL_DOMAIN_PLATFORM];
rd->id = RAPL_DOMAIN_PLATFORM;
- rd->msrs[0] = MSR_PLATFORM_POWER_LIMIT;
- rd->msrs[1] = MSR_PLATFORM_ENERGY_STATUS;
+ rd->regs[RAPL_DOMAIN_REG_LIMIT] =
+ priv->regs[RAPL_DOMAIN_PLATFORM][RAPL_DOMAIN_REG_LIMIT];
+ rd->regs[RAPL_DOMAIN_REG_STATUS] =
+ priv->regs[RAPL_DOMAIN_PLATFORM][RAPL_DOMAIN_REG_STATUS];
rd->rpl[0].prim_id = PL1_ENABLE;
rd->rpl[0].name = pl1_name;
rd->rpl[1].prim_id = PL2_ENABLE;
rd->rpl[1].name = pl2_name;
- rd->rp = find_package_by_id(0);
+ rd->rp = rapl_find_package_domain(0, priv);
- power_zone = powercap_register_zone(&rd->power_zone, control_type,
+ power_zone = powercap_register_zone(&rd->power_zone, priv->control_type,
"psys", NULL,
&zone_ops[RAPL_DOMAIN_PLATFORM],
2, &constraint_ops);
@@ -1300,38 +1127,32 @@ static int __init rapl_register_psys(void)
return PTR_ERR(power_zone);
}
- platform_rapl_domain = rd;
+ priv->platform_rapl_domain = rd;
return 0;
}
+EXPORT_SYMBOL_GPL(rapl_add_platform_domain);
-static int __init rapl_register_powercap(void)
+void rapl_remove_platform_domain(struct rapl_if_priv *priv)
{
- control_type = powercap_register_control_type(NULL, "intel-rapl", NULL);
- if (IS_ERR(control_type)) {
- pr_debug("failed to register powercap control_type.\n");
- return PTR_ERR(control_type);
+ if (priv->platform_rapl_domain) {
+ powercap_unregister_zone(priv->control_type,
+ &priv->platform_rapl_domain->power_zone);
+ kfree(priv->platform_rapl_domain);
}
- return 0;
}
+EXPORT_SYMBOL_GPL(rapl_remove_platform_domain);
-static int rapl_check_domain(int cpu, int domain)
+static int rapl_check_domain(int cpu, int domain, struct rapl_package *rp)
{
- unsigned msr;
- u64 val = 0;
+ struct reg_action ra;
switch (domain) {
case RAPL_DOMAIN_PACKAGE:
- msr = MSR_PKG_ENERGY_STATUS;
- break;
case RAPL_DOMAIN_PP0:
- msr = MSR_PP0_ENERGY_STATUS;
- break;
case RAPL_DOMAIN_PP1:
- msr = MSR_PP1_ENERGY_STATUS;
- break;
case RAPL_DOMAIN_DRAM:
- msr = MSR_DRAM_ENERGY_STATUS;
+ ra.reg = rp->priv->regs[domain][RAPL_DOMAIN_REG_STATUS];
break;
case RAPL_DOMAIN_PLATFORM:
/* PSYS(PLATFORM) is not a CPU domain, so avoid printng error */
@@ -1343,19 +1164,20 @@ static int rapl_check_domain(int cpu, int domain)
/* make sure domain counters are available and contains non-zero
* values, otherwise skip it.
*/
- if (rdmsrl_safe_on_cpu(cpu, msr, &val) || !val)
+
+ ra.mask = ~0;
+ if (rp->priv->read_raw(cpu, &ra) || !ra.value)
return -ENODEV;
return 0;
}
-
/*
* Check if power limits are available. Two cases when they are not available:
* 1. Locked by BIOS, in this case we still provide read-only access so that
* users can see what limit is set by the BIOS.
* 2. Some CPUs make some domains monitoring only which means PLx MSRs may not
- * exist at all. In this case, we do not show the contraints in powercap.
+ * exist at all. In this case, we do not show the constraints in powercap.
*
* Called after domains are detected and initialized.
*/
@@ -1367,14 +1189,15 @@ static void rapl_detect_powerlimit(struct rapl_domain *rd)
/* check if the domain is locked by BIOS, ignore if MSR doesn't exist */
if (!rapl_read_data_raw(rd, FW_LOCK, false, &val64)) {
if (val64) {
- pr_info("RAPL package %d domain %s locked by BIOS\n",
- rd->rp->id, rd->name);
+ pr_info("RAPL %s domain %s locked by BIOS\n",
+ rd->rp->name, rd->name);
rd->state |= DOMAIN_STATE_BIOS_LOCKED;
}
}
- /* check if power limit MSRs exists, otherwise domain is monitoring only */
+ /* check if power limit MSR exists, otherwise domain is monitoring only */
for (i = 0; i < NR_POWER_LIMITS; i++) {
int prim = rd->rpl[i].prim_id;
+
if (rapl_read_data_raw(rd, prim, false, &val64))
rd->rpl[i].name = NULL;
}
@@ -1390,20 +1213,20 @@ static int rapl_detect_domains(struct rapl_package *rp, int cpu)
for (i = 0; i < RAPL_DOMAIN_MAX; i++) {
/* use physical package id to read counters */
- if (!rapl_check_domain(cpu, i)) {
+ if (!rapl_check_domain(cpu, i, rp)) {
rp->domain_map |= 1 << i;
pr_info("Found RAPL domain %s\n", rapl_domain_names[i]);
}
}
- rp->nr_domains = bitmap_weight(&rp->domain_map, RAPL_DOMAIN_MAX);
+ rp->nr_domains = bitmap_weight(&rp->domain_map, RAPL_DOMAIN_MAX);
if (!rp->nr_domains) {
- pr_debug("no valid rapl domains found in package %d\n", rp->id);
+ pr_debug("no valid rapl domains found in %s\n", rp->name);
return -ENODEV;
}
- pr_debug("found %d domains on package %d\n", rp->nr_domains, rp->id);
+ pr_debug("found %d domains on %s\n", rp->nr_domains, rp->name);
rp->domains = kcalloc(rp->nr_domains + 1, sizeof(struct rapl_domain),
- GFP_KERNEL);
+ GFP_KERNEL);
if (!rp->domains)
return -ENOMEM;
@@ -1416,7 +1239,7 @@ static int rapl_detect_domains(struct rapl_package *rp, int cpu)
}
/* called from CPU hotplug notifier, hotplug lock held */
-static void rapl_remove_package(struct rapl_package *rp)
+void rapl_remove_package(struct rapl_package *rp)
{
struct rapl_domain *rd, *rd_package = NULL;
@@ -1433,20 +1256,41 @@ static void rapl_remove_package(struct rapl_package *rp)
rd_package = rd;
continue;
}
- pr_debug("remove package, undo power limit on %d: %s\n",
- rp->id, rd->name);
- powercap_unregister_zone(control_type, &rd->power_zone);
+ pr_debug("remove package, undo power limit on %s: %s\n",
+ rp->name, rd->name);
+ powercap_unregister_zone(rp->priv->control_type,
+ &rd->power_zone);
}
/* do parent zone last */
- powercap_unregister_zone(control_type, &rd_package->power_zone);
+ powercap_unregister_zone(rp->priv->control_type,
+ &rd_package->power_zone);
list_del(&rp->plist);
kfree(rp);
}
+EXPORT_SYMBOL_GPL(rapl_remove_package);
+
+/* caller to ensure CPU hotplug lock is held */
+struct rapl_package *rapl_find_package_domain(int cpu, struct rapl_if_priv *priv)
+{
+ int id = topology_logical_die_id(cpu);
+ struct rapl_package *rp;
+
+ list_for_each_entry(rp, &rapl_packages, plist) {
+ if (rp->id == id
+ && rp->priv->control_type == priv->control_type)
+ return rp;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(rapl_find_package_domain);
/* called from CPU hotplug notifier, hotplug lock held */
-static struct rapl_package *rapl_add_package(int cpu, int pkgid)
+struct rapl_package *rapl_add_package(int cpu, struct rapl_if_priv *priv)
{
+ int id = topology_logical_die_id(cpu);
struct rapl_package *rp;
+ struct cpuinfo_x86 *c = &cpu_data(cpu);
int ret;
rp = kzalloc(sizeof(struct rapl_package), GFP_KERNEL);
@@ -1454,12 +1298,19 @@ static struct rapl_package *rapl_add_package(int cpu, int pkgid)
return ERR_PTR(-ENOMEM);
/* add the new package to the list */
- rp->id = pkgid;
+ rp->id = id;
rp->lead_cpu = cpu;
+ rp->priv = priv;
+
+ if (topology_max_die_per_package() > 1)
+ snprintf(rp->name, PACKAGE_DOMAIN_NAME_LENGTH,
+ "package-%d-die-%d", c->phys_proc_id, c->cpu_die_id);
+ else
+ snprintf(rp->name, PACKAGE_DOMAIN_NAME_LENGTH, "package-%d",
+ c->phys_proc_id);
/* check if the package contains valid domains */
- if (rapl_detect_domains(rp, cpu) ||
- rapl_defaults->check_unit(rp, cpu)) {
+ if (rapl_detect_domains(rp, cpu) || rapl_defaults->check_unit(rp, cpu)) {
ret = -ENODEV;
goto err_free_package;
}
@@ -1475,49 +1326,7 @@ err_free_package:
kfree(rp);
return ERR_PTR(ret);
}
-
-/* Handles CPU hotplug on multi-socket systems.
- * If a CPU goes online as the first CPU of the physical package
- * we add the RAPL package to the system. Similarly, when the last
- * CPU of the package is removed, we remove the RAPL package and its
- * associated domains. Cooling devices are handled accordingly at
- * per-domain level.
- */
-static int rapl_cpu_online(unsigned int cpu)
-{
- int pkgid = topology_physical_package_id(cpu);
- struct rapl_package *rp;
-
- rp = find_package_by_id(pkgid);
- if (!rp) {
- rp = rapl_add_package(cpu, pkgid);
- if (IS_ERR(rp))
- return PTR_ERR(rp);
- }
- cpumask_set_cpu(cpu, &rp->cpumask);
- return 0;
-}
-
-static int rapl_cpu_down_prep(unsigned int cpu)
-{
- int pkgid = topology_physical_package_id(cpu);
- struct rapl_package *rp;
- int lead_cpu;
-
- rp = find_package_by_id(pkgid);
- if (!rp)
- return 0;
-
- cpumask_clear_cpu(cpu, &rp->cpumask);
- lead_cpu = cpumask_first(&rp->cpumask);
- if (lead_cpu >= nr_cpu_ids)
- rapl_remove_package(rp);
- else if (rp->lead_cpu == cpu)
- rp->lead_cpu = lead_cpu;
- return 0;
-}
-
-static enum cpuhp_state pcap_rapl_online;
+EXPORT_SYMBOL_GPL(rapl_add_package);
static void power_limit_state_save(void)
{
@@ -1535,17 +1344,15 @@ static void power_limit_state_save(void)
switch (rd->rpl[i].prim_id) {
case PL1_ENABLE:
ret = rapl_read_data_raw(rd,
- POWER_LIMIT1,
- true,
- &rd->rpl[i].last_power_limit);
+ POWER_LIMIT1, true,
+ &rd->rpl[i].last_power_limit);
if (ret)
rd->rpl[i].last_power_limit = 0;
break;
case PL2_ENABLE:
ret = rapl_read_data_raw(rd,
- POWER_LIMIT2,
- true,
- &rd->rpl[i].last_power_limit);
+ POWER_LIMIT2, true,
+ &rd->rpl[i].last_power_limit);
if (ret)
rd->rpl[i].last_power_limit = 0;
break;
@@ -1571,15 +1378,13 @@ static void power_limit_state_restore(void)
switch (rd->rpl[i].prim_id) {
case PL1_ENABLE:
if (rd->rpl[i].last_power_limit)
- rapl_write_data_raw(rd,
- POWER_LIMIT1,
- rd->rpl[i].last_power_limit);
+ rapl_write_data_raw(rd, POWER_LIMIT1,
+ rd->rpl[i].last_power_limit);
break;
case PL2_ENABLE:
if (rd->rpl[i].last_power_limit)
- rapl_write_data_raw(rd,
- POWER_LIMIT2,
- rd->rpl[i].last_power_limit);
+ rapl_write_data_raw(rd, POWER_LIMIT2,
+ rd->rpl[i].last_power_limit);
break;
}
}
@@ -1588,7 +1393,7 @@ static void power_limit_state_restore(void)
}
static int rapl_pm_callback(struct notifier_block *nb,
- unsigned long mode, void *_unused)
+ unsigned long mode, void *_unused)
{
switch (mode) {
case PM_SUSPEND_PREPARE:
@@ -1605,6 +1410,8 @@ static struct notifier_block rapl_pm_notifier = {
.notifier_call = rapl_pm_callback,
};
+static struct platform_device *rapl_msr_platdev;
+
static int __init rapl_init(void)
{
const struct x86_cpu_id *id;
@@ -1613,50 +1420,43 @@ static int __init rapl_init(void)
id = x86_match_cpu(rapl_ids);
if (!id) {
pr_err("driver does not support CPU family %d model %d\n",
- boot_cpu_data.x86, boot_cpu_data.x86_model);
+ boot_cpu_data.x86, boot_cpu_data.x86_model);
return -ENODEV;
}
rapl_defaults = (struct rapl_defaults *)id->driver_data;
- ret = rapl_register_powercap();
+ ret = register_pm_notifier(&rapl_pm_notifier);
if (ret)
return ret;
- ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "powercap/rapl:online",
- rapl_cpu_online, rapl_cpu_down_prep);
- if (ret < 0)
- goto err_unreg;
- pcap_rapl_online = ret;
-
- /* Don't bail out if PSys is not supported */
- rapl_register_psys();
+ rapl_msr_platdev = platform_device_alloc("intel_rapl_msr", 0);
+ if (!rapl_msr_platdev) {
+ ret = -ENOMEM;
+ goto end;
+ }
- ret = register_pm_notifier(&rapl_pm_notifier);
+ ret = platform_device_add(rapl_msr_platdev);
if (ret)
- goto err_unreg_all;
+ platform_device_put(rapl_msr_platdev);
- return 0;
-
-err_unreg_all:
- cpuhp_remove_state(pcap_rapl_online);
+end:
+ if (ret)
+ unregister_pm_notifier(&rapl_pm_notifier);
-err_unreg:
- rapl_unregister_powercap();
return ret;
}
static void __exit rapl_exit(void)
{
+ platform_device_unregister(rapl_msr_platdev);
unregister_pm_notifier(&rapl_pm_notifier);
- cpuhp_remove_state(pcap_rapl_online);
- rapl_unregister_powercap();
}
module_init(rapl_init);
module_exit(rapl_exit);
-MODULE_DESCRIPTION("Driver for Intel RAPL (Running Average Power Limit)");
+MODULE_DESCRIPTION("Intel Runtime Average Power Limit (RAPL) common code");
MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@intel.com>");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/powercap/intel_rapl_msr.c b/drivers/powercap/intel_rapl_msr.c
new file mode 100644
index 000000000000..d5487965bdfe
--- /dev/null
+++ b/drivers/powercap/intel_rapl_msr.c
@@ -0,0 +1,183 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Intel Running Average Power Limit (RAPL) Driver via MSR interface
+ * Copyright (c) 2019, Intel Corporation.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/log2.h>
+#include <linux/bitmap.h>
+#include <linux/delay.h>
+#include <linux/sysfs.h>
+#include <linux/cpu.h>
+#include <linux/powercap.h>
+#include <linux/suspend.h>
+#include <linux/intel_rapl.h>
+#include <linux/processor.h>
+#include <linux/platform_device.h>
+
+#include <asm/iosf_mbi.h>
+#include <asm/cpu_device_id.h>
+#include <asm/intel-family.h>
+
+/* Local defines */
+#define MSR_PLATFORM_POWER_LIMIT 0x0000065C
+
+/* private data for RAPL MSR Interface */
+static struct rapl_if_priv rapl_msr_priv = {
+ .reg_unit = MSR_RAPL_POWER_UNIT,
+ .regs[RAPL_DOMAIN_PACKAGE] = {
+ MSR_PKG_POWER_LIMIT, MSR_PKG_ENERGY_STATUS, MSR_PKG_PERF_STATUS, 0, MSR_PKG_POWER_INFO },
+ .regs[RAPL_DOMAIN_PP0] = {
+ MSR_PP0_POWER_LIMIT, MSR_PP0_ENERGY_STATUS, 0, MSR_PP0_POLICY, 0 },
+ .regs[RAPL_DOMAIN_PP1] = {
+ MSR_PP1_POWER_LIMIT, MSR_PP1_ENERGY_STATUS, 0, MSR_PP1_POLICY, 0 },
+ .regs[RAPL_DOMAIN_DRAM] = {
+ MSR_DRAM_POWER_LIMIT, MSR_DRAM_ENERGY_STATUS, MSR_DRAM_PERF_STATUS, 0, MSR_DRAM_POWER_INFO },
+ .regs[RAPL_DOMAIN_PLATFORM] = {
+ MSR_PLATFORM_POWER_LIMIT, MSR_PLATFORM_ENERGY_STATUS, 0, 0, 0},
+ .limits[RAPL_DOMAIN_PACKAGE] = 2,
+};
+
+/* Handles CPU hotplug on multi-socket systems.
+ * If a CPU goes online as the first CPU of the physical package
+ * we add the RAPL package to the system. Similarly, when the last
+ * CPU of the package is removed, we remove the RAPL package and its
+ * associated domains. Cooling devices are handled accordingly at
+ * per-domain level.
+ */
+static int rapl_cpu_online(unsigned int cpu)
+{
+ struct rapl_package *rp;
+
+ rp = rapl_find_package_domain(cpu, &rapl_msr_priv);
+ if (!rp) {
+ rp = rapl_add_package(cpu, &rapl_msr_priv);
+ if (IS_ERR(rp))
+ return PTR_ERR(rp);
+ }
+ cpumask_set_cpu(cpu, &rp->cpumask);
+ return 0;
+}
+
+static int rapl_cpu_down_prep(unsigned int cpu)
+{
+ struct rapl_package *rp;
+ int lead_cpu;
+
+ rp = rapl_find_package_domain(cpu, &rapl_msr_priv);
+ if (!rp)
+ return 0;
+
+ cpumask_clear_cpu(cpu, &rp->cpumask);
+ lead_cpu = cpumask_first(&rp->cpumask);
+ if (lead_cpu >= nr_cpu_ids)
+ rapl_remove_package(rp);
+ else if (rp->lead_cpu == cpu)
+ rp->lead_cpu = lead_cpu;
+ return 0;
+}
+
+static int rapl_msr_read_raw(int cpu, struct reg_action *ra)
+{
+ u32 msr = (u32)ra->reg;
+
+ if (rdmsrl_safe_on_cpu(cpu, msr, &ra->value)) {
+ pr_debug("failed to read msr 0x%x on cpu %d\n", msr, cpu);
+ return -EIO;
+ }
+ ra->value &= ra->mask;
+ return 0;
+}
+
+static void rapl_msr_update_func(void *info)
+{
+ struct reg_action *ra = info;
+ u32 msr = (u32)ra->reg;
+ u64 val;
+
+ ra->err = rdmsrl_safe(msr, &val);
+ if (ra->err)
+ return;
+
+ val &= ~ra->mask;
+ val |= ra->value;
+
+ ra->err = wrmsrl_safe(msr, val);
+}
+
+static int rapl_msr_write_raw(int cpu, struct reg_action *ra)
+{
+ int ret;
+
+ ret = smp_call_function_single(cpu, rapl_msr_update_func, ra, 1);
+ if (WARN_ON_ONCE(ret))
+ return ret;
+
+ return ra->err;
+}
+
+static int rapl_msr_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ rapl_msr_priv.read_raw = rapl_msr_read_raw;
+ rapl_msr_priv.write_raw = rapl_msr_write_raw;
+
+ rapl_msr_priv.control_type = powercap_register_control_type(NULL, "intel-rapl", NULL);
+ if (IS_ERR(rapl_msr_priv.control_type)) {
+ pr_debug("failed to register powercap control_type.\n");
+ return PTR_ERR(rapl_msr_priv.control_type);
+ }
+
+ ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "powercap/rapl:online",
+ rapl_cpu_online, rapl_cpu_down_prep);
+ if (ret < 0)
+ goto out;
+ rapl_msr_priv.pcap_rapl_online = ret;
+
+ /* Don't bail out if PSys is not supported */
+ rapl_add_platform_domain(&rapl_msr_priv);
+
+ return 0;
+
+out:
+ if (ret)
+ powercap_unregister_control_type(rapl_msr_priv.control_type);
+ return ret;
+}
+
+static int rapl_msr_remove(struct platform_device *pdev)
+{
+ cpuhp_remove_state(rapl_msr_priv.pcap_rapl_online);
+ rapl_remove_platform_domain(&rapl_msr_priv);
+ powercap_unregister_control_type(rapl_msr_priv.control_type);
+ return 0;
+}
+
+static const struct platform_device_id rapl_msr_ids[] = {
+ { .name = "intel_rapl_msr", },
+ {}
+};
+MODULE_DEVICE_TABLE(platform, rapl_msr_ids);
+
+static struct platform_driver intel_rapl_msr_driver = {
+ .probe = rapl_msr_probe,
+ .remove = rapl_msr_remove,
+ .id_table = rapl_msr_ids,
+ .driver = {
+ .name = "intel_rapl_msr",
+ },
+};
+
+module_platform_driver(intel_rapl_msr_driver);
+
+MODULE_DESCRIPTION("Driver for Intel RAPL (Running Average Power Limit) control via MSR interface");
+MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c
index 3a546ec10d90..22a65ad4e46e 100644
--- a/drivers/pps/pps.c
+++ b/drivers/pps/pps.c
@@ -152,6 +152,14 @@ static long pps_cdev_ioctl(struct file *file,
pps->params.mode |= PPS_CANWAIT;
pps->params.api_version = PPS_API_VERS;
+ /*
+ * Clear unused fields of pps_kparams to avoid leaking
+ * uninitialized data of the PPS_SETPARAMS caller via
+ * PPS_GETPARAMS
+ */
+ pps->params.assert_off_tu.flags = 0;
+ pps->params.clear_off_tu.flags = 0;
+
spin_unlock_irq(&pps->lock);
break;
diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig
index 9b8fee5178e8..960961fb0d7c 100644
--- a/drivers/ptp/Kconfig
+++ b/drivers/ptp/Kconfig
@@ -44,7 +44,7 @@ config PTP_1588_CLOCK_DTE
config PTP_1588_CLOCK_QORIQ
tristate "Freescale QorIQ 1588 timer as PTP clock"
- depends on GIANFAR || FSL_DPAA_ETH || FSL_ENETC || FSL_ENETC_VF
+ depends on GIANFAR || FSL_DPAA_ETH || FSL_DPAA2_ETH || FSL_ENETC || FSL_ENETC_VF || COMPILE_TEST
depends on PTP_1588_CLOCK
default y
help
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
index e189fa1be21e..e60eab7f8a61 100644
--- a/drivers/ptp/ptp_clock.c
+++ b/drivers/ptp/ptp_clock.c
@@ -63,7 +63,7 @@ static void enqueue_external_timestamp(struct timestamp_event_queue *queue,
spin_unlock_irqrestore(&queue->lock, flags);
}
-static s32 scaled_ppm_to_ppb(long ppm)
+s32 scaled_ppm_to_ppb(long ppm)
{
/*
* The 'freq' field in the 'struct timex' is in parts per
@@ -82,6 +82,7 @@ static s32 scaled_ppm_to_ppb(long ppm)
ppb >>= 13;
return (s32) ppb;
}
+EXPORT_SYMBOL(scaled_ppm_to_ppb);
/* posix clock implementation */
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index dff5a93f7daa..a7e57516959e 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -401,6 +401,17 @@ config PWM_SAMSUNG
To compile this driver as a module, choose M here: the module
will be called pwm-samsung.
+config PWM_SIFIVE
+ tristate "SiFive PWM support"
+ depends on OF
+ depends on COMMON_CLK
+ depends on RISCV || COMPILE_TEST
+ help
+ Generic PWM framework driver for SiFive SoCs.
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-sifive.
+
config PWM_SPEAR
tristate "STMicroelectronics SPEAr PWM support"
depends on PLAT_SPEAR
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index c368599d36c0..76b555b51887 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_PWM_RCAR) += pwm-rcar.o
obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o
obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o
obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
+obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o
obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o
obj-$(CONFIG_PWM_STI) += pwm-sti.o
obj-$(CONFIG_PWM_STM32) += pwm-stm32.o
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index 275b5f399a1a..c3ab07ab31a9 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -6,6 +6,7 @@
* Copyright (C) 2011-2012 Avionic Design GmbH
*/
+#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/pwm.h>
#include <linux/radix-tree.h>
@@ -626,8 +627,35 @@ static struct pwm_chip *of_node_to_pwmchip(struct device_node *np)
return ERR_PTR(-EPROBE_DEFER);
}
+static struct device_link *pwm_device_link_add(struct device *dev,
+ struct pwm_device *pwm)
+{
+ struct device_link *dl;
+
+ if (!dev) {
+ /*
+ * No device for the PWM consumer has been provided. It may
+ * impact the PM sequence ordering: the PWM supplier may get
+ * suspended before the consumer.
+ */
+ dev_warn(pwm->chip->dev,
+ "No consumer device specified to create a link to\n");
+ return NULL;
+ }
+
+ dl = device_link_add(dev, pwm->chip->dev, DL_FLAG_AUTOREMOVE_CONSUMER);
+ if (!dl) {
+ dev_err(dev, "failed to create device link to %s\n",
+ dev_name(pwm->chip->dev));
+ return ERR_PTR(-EINVAL);
+ }
+
+ return dl;
+}
+
/**
* of_pwm_get() - request a PWM via the PWM framework
+ * @dev: device for PWM consumer
* @np: device node to get the PWM from
* @con_id: consumer name
*
@@ -645,10 +673,12 @@ static struct pwm_chip *of_node_to_pwmchip(struct device_node *np)
* Returns: A pointer to the requested PWM device or an ERR_PTR()-encoded
* error code on failure.
*/
-struct pwm_device *of_pwm_get(struct device_node *np, const char *con_id)
+struct pwm_device *of_pwm_get(struct device *dev, struct device_node *np,
+ const char *con_id)
{
struct pwm_device *pwm = NULL;
struct of_phandle_args args;
+ struct device_link *dl;
struct pwm_chip *pc;
int index = 0;
int err;
@@ -679,6 +709,14 @@ struct pwm_device *of_pwm_get(struct device_node *np, const char *con_id)
if (IS_ERR(pwm))
goto put;
+ dl = pwm_device_link_add(dev, pwm);
+ if (IS_ERR(dl)) {
+ /* of_xlate ended up calling pwm_request_from_chip() */
+ pwm_free(pwm);
+ pwm = ERR_CAST(dl);
+ goto put;
+ }
+
/*
* If a consumer name was not given, try to look it up from the
* "pwm-names" property if it exists. Otherwise use the name of
@@ -700,6 +738,85 @@ put:
}
EXPORT_SYMBOL_GPL(of_pwm_get);
+#if IS_ENABLED(CONFIG_ACPI)
+static struct pwm_chip *device_to_pwmchip(struct device *dev)
+{
+ struct pwm_chip *chip;
+
+ mutex_lock(&pwm_lock);
+
+ list_for_each_entry(chip, &pwm_chips, list) {
+ struct acpi_device *adev = ACPI_COMPANION(chip->dev);
+
+ if ((chip->dev == dev) || (adev && &adev->dev == dev)) {
+ mutex_unlock(&pwm_lock);
+ return chip;
+ }
+ }
+
+ mutex_unlock(&pwm_lock);
+
+ return ERR_PTR(-EPROBE_DEFER);
+}
+#endif
+
+/**
+ * acpi_pwm_get() - request a PWM via parsing "pwms" property in ACPI
+ * @fwnode: firmware node to get the "pwm" property from
+ *
+ * Returns the PWM device parsed from the fwnode and index specified in the
+ * "pwms" property or a negative error-code on failure.
+ * Values parsed from the device tree are stored in the returned PWM device
+ * object.
+ *
+ * This is analogous to of_pwm_get() except con_id is not yet supported.
+ * ACPI entries must look like
+ * Package () {"pwms", Package ()
+ * { <PWM device reference>, <PWM index>, <PWM period> [, <PWM flags>]}}
+ *
+ * Returns: A pointer to the requested PWM device or an ERR_PTR()-encoded
+ * error code on failure.
+ */
+static struct pwm_device *acpi_pwm_get(struct fwnode_handle *fwnode)
+{
+ struct pwm_device *pwm = ERR_PTR(-ENODEV);
+#if IS_ENABLED(CONFIG_ACPI)
+ struct fwnode_reference_args args;
+ struct acpi_device *acpi;
+ struct pwm_chip *chip;
+ int ret;
+
+ memset(&args, 0, sizeof(args));
+
+ ret = __acpi_node_get_property_reference(fwnode, "pwms", 0, 3, &args);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ acpi = to_acpi_device_node(args.fwnode);
+ if (!acpi)
+ return ERR_PTR(-EINVAL);
+
+ if (args.nargs < 2)
+ return ERR_PTR(-EPROTO);
+
+ chip = device_to_pwmchip(&acpi->dev);
+ if (IS_ERR(chip))
+ return ERR_CAST(chip);
+
+ pwm = pwm_request_from_chip(chip, args.args[0], NULL);
+ if (IS_ERR(pwm))
+ return pwm;
+
+ pwm->args.period = args.args[1];
+ pwm->args.polarity = PWM_POLARITY_NORMAL;
+
+ if (args.nargs > 2 && args.args[2] & PWM_POLARITY_INVERTED)
+ pwm->args.polarity = PWM_POLARITY_INVERSED;
+#endif
+
+ return pwm;
+}
+
/**
* pwm_add_table() - register PWM device consumers
* @table: array of consumers to register
@@ -754,6 +871,7 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id)
const char *dev_id = dev ? dev_name(dev) : NULL;
struct pwm_device *pwm;
struct pwm_chip *chip;
+ struct device_link *dl;
unsigned int best = 0;
struct pwm_lookup *p, *chosen = NULL;
unsigned int match;
@@ -761,7 +879,11 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id)
/* look up via DT first */
if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node)
- return of_pwm_get(dev->of_node, con_id);
+ return of_pwm_get(dev, dev->of_node, con_id);
+
+ /* then lookup via ACPI */
+ if (dev && is_acpi_node(dev->fwnode))
+ return acpi_pwm_get(dev->fwnode);
/*
* We look up the provider in the static table typically provided by
@@ -838,6 +960,12 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id)
if (IS_ERR(pwm))
return pwm;
+ dl = pwm_device_link_add(dev, pwm);
+ if (IS_ERR(dl)) {
+ pwm_free(pwm);
+ return ERR_CAST(dl);
+ }
+
pwm->args.period = chosen->period;
pwm->args.polarity = chosen->polarity;
@@ -930,7 +1058,7 @@ struct pwm_device *devm_of_pwm_get(struct device *dev, struct device_node *np,
if (!ptr)
return ERR_PTR(-ENOMEM);
- pwm = of_pwm_get(np, con_id);
+ pwm = of_pwm_get(dev, np, con_id);
if (!IS_ERR(pwm)) {
*ptr = pwm;
devres_add(dev, ptr);
@@ -942,6 +1070,44 @@ struct pwm_device *devm_of_pwm_get(struct device *dev, struct device_node *np,
}
EXPORT_SYMBOL_GPL(devm_of_pwm_get);
+/**
+ * devm_fwnode_pwm_get() - request a resource managed PWM from firmware node
+ * @dev: device for PWM consumer
+ * @fwnode: firmware node to get the PWM from
+ * @con_id: consumer name
+ *
+ * Returns the PWM device parsed from the firmware node. See of_pwm_get() and
+ * acpi_pwm_get() for a detailed description.
+ *
+ * Returns: A pointer to the requested PWM device or an ERR_PTR()-encoded
+ * error code on failure.
+ */
+struct pwm_device *devm_fwnode_pwm_get(struct device *dev,
+ struct fwnode_handle *fwnode,
+ const char *con_id)
+{
+ struct pwm_device **ptr, *pwm = ERR_PTR(-ENODEV);
+
+ ptr = devres_alloc(devm_pwm_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ if (is_of_node(fwnode))
+ pwm = of_pwm_get(dev, to_of_node(fwnode), con_id);
+ else if (is_acpi_node(fwnode))
+ pwm = acpi_pwm_get(fwnode);
+
+ if (!IS_ERR(pwm)) {
+ *ptr = pwm;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return pwm;
+}
+EXPORT_SYMBOL_GPL(devm_fwnode_pwm_get);
+
static int devm_pwm_match(struct device *dev, void *res, void *data)
{
struct pwm_device **p = res;
diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c
index 54c6633d9b5d..d13a83f430ac 100644
--- a/drivers/pwm/pwm-atmel-hlcdc.c
+++ b/drivers/pwm/pwm-atmel-hlcdc.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 Free Electrons
* Copyright (C) 2014 Atmel
*
* Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/clk.h>
@@ -246,6 +235,7 @@ static const struct of_device_id atmel_hlcdc_dt_ids[] = {
.compatible = "atmel,sama5d4-hlcdc",
.data = &atmel_hlcdc_pwm_sama5d3_errata,
},
+ { .compatible = "microchip,sam9x60-hlcdc", },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, atmel_hlcdc_dt_ids);
diff --git a/drivers/pwm/pwm-bcm2835.c b/drivers/pwm/pwm-bcm2835.c
index 5652f461d994..f6fe0b922e1e 100644
--- a/drivers/pwm/pwm-bcm2835.c
+++ b/drivers/pwm/pwm-bcm2835.c
@@ -70,7 +70,7 @@ static int bcm2835_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
return -EINVAL;
}
- scaler = NSEC_PER_SEC / rate;
+ scaler = DIV_ROUND_CLOSEST(NSEC_PER_SEC, rate);
if (period_ns <= MIN_PERIOD) {
dev_err(pc->dev, "period %d not supported, minimum %d\n",
@@ -78,8 +78,10 @@ static int bcm2835_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
return -EINVAL;
}
- writel(duty_ns / scaler, pc->base + DUTY(pwm->hwpwm));
- writel(period_ns / scaler, pc->base + PERIOD(pwm->hwpwm));
+ writel(DIV_ROUND_CLOSEST(duty_ns, scaler),
+ pc->base + DUTY(pwm->hwpwm));
+ writel(DIV_ROUND_CLOSEST(period_ns, scaler),
+ pc->base + PERIOD(pwm->hwpwm));
return 0;
}
diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c
index a39b48839df7..9d31a217111d 100644
--- a/drivers/pwm/pwm-fsl-ftm.c
+++ b/drivers/pwm/pwm-fsl-ftm.c
@@ -34,17 +34,19 @@ struct fsl_ftm_soc {
bool has_enable_bits;
};
+struct fsl_pwm_periodcfg {
+ enum fsl_pwm_clk clk_select;
+ unsigned int clk_ps;
+ unsigned int mod_period;
+};
+
struct fsl_pwm_chip {
struct pwm_chip chip;
-
struct mutex lock;
-
- unsigned int cnt_select;
- unsigned int clk_ps;
-
struct regmap *regmap;
- int period_ns;
+ /* This value is valid iff a pwm is running */
+ struct fsl_pwm_periodcfg period;
struct clk *ipg_clk;
struct clk *clk[FSL_PWM_CLK_MAX];
@@ -57,6 +59,33 @@ static inline struct fsl_pwm_chip *to_fsl_chip(struct pwm_chip *chip)
return container_of(chip, struct fsl_pwm_chip, chip);
}
+static void ftm_clear_write_protection(struct fsl_pwm_chip *fpc)
+{
+ u32 val;
+
+ regmap_read(fpc->regmap, FTM_FMS, &val);
+ if (val & FTM_FMS_WPEN)
+ regmap_update_bits(fpc->regmap, FTM_MODE, FTM_MODE_WPDIS,
+ FTM_MODE_WPDIS);
+}
+
+static void ftm_set_write_protection(struct fsl_pwm_chip *fpc)
+{
+ regmap_update_bits(fpc->regmap, FTM_FMS, FTM_FMS_WPEN, FTM_FMS_WPEN);
+}
+
+static bool fsl_pwm_periodcfg_are_equal(const struct fsl_pwm_periodcfg *a,
+ const struct fsl_pwm_periodcfg *b)
+{
+ if (a->clk_select != b->clk_select)
+ return false;
+ if (a->clk_ps != b->clk_ps)
+ return false;
+ if (a->mod_period != b->mod_period)
+ return false;
+ return true;
+}
+
static int fsl_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
{
int ret;
@@ -87,89 +116,58 @@ static void fsl_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
clk_disable_unprepare(fpc->ipg_clk);
}
-static int fsl_pwm_calculate_default_ps(struct fsl_pwm_chip *fpc,
- enum fsl_pwm_clk index)
+static unsigned int fsl_pwm_ticks_to_ns(struct fsl_pwm_chip *fpc,
+ unsigned int ticks)
{
- unsigned long sys_rate, cnt_rate;
- unsigned long long ratio;
-
- sys_rate = clk_get_rate(fpc->clk[FSL_PWM_CLK_SYS]);
- if (!sys_rate)
- return -EINVAL;
-
- cnt_rate = clk_get_rate(fpc->clk[fpc->cnt_select]);
- if (!cnt_rate)
- return -EINVAL;
-
- switch (index) {
- case FSL_PWM_CLK_SYS:
- fpc->clk_ps = 1;
- break;
- case FSL_PWM_CLK_FIX:
- ratio = 2 * cnt_rate - 1;
- do_div(ratio, sys_rate);
- fpc->clk_ps = ratio;
- break;
- case FSL_PWM_CLK_EXT:
- ratio = 4 * cnt_rate - 1;
- do_div(ratio, sys_rate);
- fpc->clk_ps = ratio;
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
+ unsigned long rate;
+ unsigned long long exval;
+
+ rate = clk_get_rate(fpc->clk[fpc->period.clk_select]);
+ exval = ticks;
+ exval *= 1000000000UL;
+ do_div(exval, rate >> fpc->period.clk_ps);
+ return exval;
}
-static unsigned long fsl_pwm_calculate_cycles(struct fsl_pwm_chip *fpc,
- unsigned long period_ns)
+static bool fsl_pwm_calculate_period_clk(struct fsl_pwm_chip *fpc,
+ unsigned int period_ns,
+ enum fsl_pwm_clk index,
+ struct fsl_pwm_periodcfg *periodcfg
+ )
{
- unsigned long long c, c0;
+ unsigned long long c;
+ unsigned int ps;
- c = clk_get_rate(fpc->clk[fpc->cnt_select]);
+ c = clk_get_rate(fpc->clk[index]);
c = c * period_ns;
do_div(c, 1000000000UL);
- do {
- c0 = c;
- do_div(c0, (1 << fpc->clk_ps));
- if (c0 <= 0xFFFF)
- return (unsigned long)c0;
- } while (++fpc->clk_ps < 8);
-
- return 0;
-}
-
-static unsigned long fsl_pwm_calculate_period_cycles(struct fsl_pwm_chip *fpc,
- unsigned long period_ns,
- enum fsl_pwm_clk index)
-{
- int ret;
+ if (c == 0)
+ return false;
- ret = fsl_pwm_calculate_default_ps(fpc, index);
- if (ret) {
- dev_err(fpc->chip.dev,
- "failed to calculate default prescaler: %d\n",
- ret);
- return 0;
+ for (ps = 0; ps < 8 ; ++ps, c >>= 1) {
+ if (c <= 0x10000) {
+ periodcfg->clk_select = index;
+ periodcfg->clk_ps = ps;
+ periodcfg->mod_period = c - 1;
+ return true;
+ }
}
-
- return fsl_pwm_calculate_cycles(fpc, period_ns);
+ return false;
}
-static unsigned long fsl_pwm_calculate_period(struct fsl_pwm_chip *fpc,
- unsigned long period_ns)
+static bool fsl_pwm_calculate_period(struct fsl_pwm_chip *fpc,
+ unsigned int period_ns,
+ struct fsl_pwm_periodcfg *periodcfg)
{
enum fsl_pwm_clk m0, m1;
- unsigned long fix_rate, ext_rate, cycles;
+ unsigned long fix_rate, ext_rate;
+ bool ret;
- cycles = fsl_pwm_calculate_period_cycles(fpc, period_ns,
- FSL_PWM_CLK_SYS);
- if (cycles) {
- fpc->cnt_select = FSL_PWM_CLK_SYS;
- return cycles;
- }
+ ret = fsl_pwm_calculate_period_clk(fpc, period_ns, FSL_PWM_CLK_SYS,
+ periodcfg);
+ if (ret)
+ return true;
fix_rate = clk_get_rate(fpc->clk[FSL_PWM_CLK_FIX]);
ext_rate = clk_get_rate(fpc->clk[FSL_PWM_CLK_EXT]);
@@ -182,158 +180,185 @@ static unsigned long fsl_pwm_calculate_period(struct fsl_pwm_chip *fpc,
m1 = FSL_PWM_CLK_FIX;
}
- cycles = fsl_pwm_calculate_period_cycles(fpc, period_ns, m0);
- if (cycles) {
- fpc->cnt_select = m0;
- return cycles;
- }
-
- fpc->cnt_select = m1;
+ ret = fsl_pwm_calculate_period_clk(fpc, period_ns, m0, periodcfg);
+ if (ret)
+ return true;
- return fsl_pwm_calculate_period_cycles(fpc, period_ns, m1);
+ return fsl_pwm_calculate_period_clk(fpc, period_ns, m1, periodcfg);
}
-static unsigned long fsl_pwm_calculate_duty(struct fsl_pwm_chip *fpc,
- unsigned long period_ns,
- unsigned long duty_ns)
+static unsigned int fsl_pwm_calculate_duty(struct fsl_pwm_chip *fpc,
+ unsigned int duty_ns)
{
unsigned long long duty;
- u32 val;
- regmap_read(fpc->regmap, FTM_MOD, &val);
- duty = (unsigned long long)duty_ns * (val + 1);
+ unsigned int period = fpc->period.mod_period + 1;
+ unsigned int period_ns = fsl_pwm_ticks_to_ns(fpc, period);
+
+ duty = (unsigned long long)duty_ns * period;
do_div(duty, period_ns);
- return (unsigned long)duty;
+ return (unsigned int)duty;
}
-static int fsl_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
- int duty_ns, int period_ns)
+static bool fsl_pwm_is_any_pwm_enabled(struct fsl_pwm_chip *fpc,
+ struct pwm_device *pwm)
{
- struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
- u32 period, duty;
+ u32 val;
- mutex_lock(&fpc->lock);
+ regmap_read(fpc->regmap, FTM_OUTMASK, &val);
+ if (~val & 0xFF)
+ return true;
+ else
+ return false;
+}
+
+static bool fsl_pwm_is_other_pwm_enabled(struct fsl_pwm_chip *fpc,
+ struct pwm_device *pwm)
+{
+ u32 val;
+ regmap_read(fpc->regmap, FTM_OUTMASK, &val);
+ if (~(val | BIT(pwm->hwpwm)) & 0xFF)
+ return true;
+ else
+ return false;
+}
+
+static int fsl_pwm_apply_config(struct fsl_pwm_chip *fpc,
+ struct pwm_device *pwm,
+ struct pwm_state *newstate)
+{
+ unsigned int duty;
+ u32 reg_polarity;
+
+ struct fsl_pwm_periodcfg periodcfg;
+ bool do_write_period = false;
+
+ if (!fsl_pwm_calculate_period(fpc, newstate->period, &periodcfg)) {
+ dev_err(fpc->chip.dev, "failed to calculate new period\n");
+ return -EINVAL;
+ }
+
+ if (!fsl_pwm_is_any_pwm_enabled(fpc, pwm))
+ do_write_period = true;
/*
* The Freescale FTM controller supports only a single period for
- * all PWM channels, therefore incompatible changes need to be
- * refused.
+ * all PWM channels, therefore verify if the newly computed period
+ * is different than the current period being used. In such case
+ * we allow to change the period only if no other pwm is running.
*/
- if (fpc->period_ns && fpc->period_ns != period_ns) {
- dev_err(fpc->chip.dev,
- "conflicting period requested for PWM %u\n",
- pwm->hwpwm);
- mutex_unlock(&fpc->lock);
- return -EBUSY;
+ else if (!fsl_pwm_periodcfg_are_equal(&fpc->period, &periodcfg)) {
+ if (fsl_pwm_is_other_pwm_enabled(fpc, pwm)) {
+ dev_err(fpc->chip.dev,
+ "Cannot change period for PWM %u, disable other PWMs first\n",
+ pwm->hwpwm);
+ return -EBUSY;
+ }
+ if (fpc->period.clk_select != periodcfg.clk_select) {
+ int ret;
+ enum fsl_pwm_clk oldclk = fpc->period.clk_select;
+ enum fsl_pwm_clk newclk = periodcfg.clk_select;
+
+ ret = clk_prepare_enable(fpc->clk[newclk]);
+ if (ret)
+ return ret;
+ clk_disable_unprepare(fpc->clk[oldclk]);
+ }
+ do_write_period = true;
}
- if (!fpc->period_ns && duty_ns) {
- period = fsl_pwm_calculate_period(fpc, period_ns);
- if (!period) {
- dev_err(fpc->chip.dev, "failed to calculate period\n");
- mutex_unlock(&fpc->lock);
- return -EINVAL;
- }
+ ftm_clear_write_protection(fpc);
+ if (do_write_period) {
+ regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_CLK_MASK,
+ FTM_SC_CLK(periodcfg.clk_select));
regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_PS_MASK,
- fpc->clk_ps);
- regmap_write(fpc->regmap, FTM_MOD, period - 1);
+ periodcfg.clk_ps);
+ regmap_write(fpc->regmap, FTM_MOD, periodcfg.mod_period);
- fpc->period_ns = period_ns;
+ fpc->period = periodcfg;
}
- mutex_unlock(&fpc->lock);
-
- duty = fsl_pwm_calculate_duty(fpc, period_ns, duty_ns);
+ duty = fsl_pwm_calculate_duty(fpc, newstate->duty_cycle);
regmap_write(fpc->regmap, FTM_CSC(pwm->hwpwm),
FTM_CSC_MSB | FTM_CSC_ELSB);
regmap_write(fpc->regmap, FTM_CV(pwm->hwpwm), duty);
- return 0;
-}
-
-static int fsl_pwm_set_polarity(struct pwm_chip *chip,
- struct pwm_device *pwm,
- enum pwm_polarity polarity)
-{
- struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
- u32 val;
+ reg_polarity = 0;
+ if (newstate->polarity == PWM_POLARITY_INVERSED)
+ reg_polarity = BIT(pwm->hwpwm);
- regmap_read(fpc->regmap, FTM_POL, &val);
+ regmap_update_bits(fpc->regmap, FTM_POL, BIT(pwm->hwpwm), reg_polarity);
- if (polarity == PWM_POLARITY_INVERSED)
- val |= BIT(pwm->hwpwm);
- else
- val &= ~BIT(pwm->hwpwm);
+ newstate->period = fsl_pwm_ticks_to_ns(fpc,
+ fpc->period.mod_period + 1);
+ newstate->duty_cycle = fsl_pwm_ticks_to_ns(fpc, duty);
- regmap_write(fpc->regmap, FTM_POL, val);
+ ftm_set_write_protection(fpc);
return 0;
}
-static int fsl_counter_clock_enable(struct fsl_pwm_chip *fpc)
-{
- int ret;
-
- /* select counter clock source */
- regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_CLK_MASK,
- FTM_SC_CLK(fpc->cnt_select));
-
- ret = clk_prepare_enable(fpc->clk[fpc->cnt_select]);
- if (ret)
- return ret;
-
- ret = clk_prepare_enable(fpc->clk[FSL_PWM_CLK_CNTEN]);
- if (ret) {
- clk_disable_unprepare(fpc->clk[fpc->cnt_select]);
- return ret;
- }
-
- return 0;
-}
-
-static int fsl_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+static int fsl_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+ struct pwm_state *newstate)
{
struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
- int ret;
-
- mutex_lock(&fpc->lock);
- regmap_update_bits(fpc->regmap, FTM_OUTMASK, BIT(pwm->hwpwm), 0);
+ struct pwm_state *oldstate = &pwm->state;
+ int ret = 0;
- ret = fsl_counter_clock_enable(fpc);
- mutex_unlock(&fpc->lock);
+ /*
+ * oldstate to newstate : action
+ *
+ * disabled to disabled : ignore
+ * enabled to disabled : disable
+ * enabled to enabled : update settings
+ * disabled to enabled : update settings + enable
+ */
- return ret;
-}
+ mutex_lock(&fpc->lock);
-static void fsl_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
-{
- struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
- u32 val;
+ if (!newstate->enabled) {
+ if (oldstate->enabled) {
+ regmap_update_bits(fpc->regmap, FTM_OUTMASK,
+ BIT(pwm->hwpwm), BIT(pwm->hwpwm));
+ clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]);
+ clk_disable_unprepare(fpc->clk[fpc->period.clk_select]);
+ }
- mutex_lock(&fpc->lock);
- regmap_update_bits(fpc->regmap, FTM_OUTMASK, BIT(pwm->hwpwm),
- BIT(pwm->hwpwm));
+ goto end_mutex;
+ }
- clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]);
- clk_disable_unprepare(fpc->clk[fpc->cnt_select]);
+ ret = fsl_pwm_apply_config(fpc, pwm, newstate);
+ if (ret)
+ goto end_mutex;
+
+ /* check if need to enable */
+ if (!oldstate->enabled) {
+ ret = clk_prepare_enable(fpc->clk[fpc->period.clk_select]);
+ if (ret)
+ goto end_mutex;
+
+ ret = clk_prepare_enable(fpc->clk[FSL_PWM_CLK_CNTEN]);
+ if (ret) {
+ clk_disable_unprepare(fpc->clk[fpc->period.clk_select]);
+ goto end_mutex;
+ }
- regmap_read(fpc->regmap, FTM_OUTMASK, &val);
- if ((val & 0xFF) == 0xFF)
- fpc->period_ns = 0;
+ regmap_update_bits(fpc->regmap, FTM_OUTMASK, BIT(pwm->hwpwm),
+ 0);
+ }
+end_mutex:
mutex_unlock(&fpc->lock);
+ return ret;
}
static const struct pwm_ops fsl_pwm_ops = {
.request = fsl_pwm_request,
.free = fsl_pwm_free,
- .config = fsl_pwm_config,
- .set_polarity = fsl_pwm_set_polarity,
- .enable = fsl_pwm_enable,
- .disable = fsl_pwm_disable,
+ .apply = fsl_pwm_apply,
.owner = THIS_MODULE,
};
@@ -357,6 +382,8 @@ static int fsl_pwm_init(struct fsl_pwm_chip *fpc)
static bool fsl_pwm_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
+ case FTM_FMS:
+ case FTM_MODE:
case FTM_CNT:
return true;
}
@@ -474,7 +501,7 @@ static int fsl_pwm_suspend(struct device *dev)
continue;
clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]);
- clk_disable_unprepare(fpc->clk[fpc->cnt_select]);
+ clk_disable_unprepare(fpc->clk[fpc->period.clk_select]);
}
return 0;
@@ -496,7 +523,7 @@ static int fsl_pwm_resume(struct device *dev)
if (!pwm_is_enabled(pwm))
continue;
- clk_prepare_enable(fpc->clk[fpc->cnt_select]);
+ clk_prepare_enable(fpc->clk[fpc->period.clk_select]);
clk_prepare_enable(fpc->clk[FSL_PWM_CLK_CNTEN]);
}
diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c
index 88a51a40e695..f901e8a0d33d 100644
--- a/drivers/pwm/pwm-jz4740.c
+++ b/drivers/pwm/pwm-jz4740.c
@@ -63,7 +63,15 @@ static void jz4740_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
{
uint32_t ctrl = jz4740_timer_get_ctrl(pwm->hwpwm);
- /* Disable PWM output.
+ /*
+ * Set duty > period. This trick allows the TCU channels in TCU2 mode to
+ * properly return to their init level.
+ */
+ jz4740_timer_set_duty(pwm->hwpwm, 0xffff);
+ jz4740_timer_set_period(pwm->hwpwm, 0x0);
+
+ /*
+ * Disable PWM output.
* In TCU2 mode (channel 1/2 on JZ4750+), this must be done before the
* counter is stopped, while in TCU1 mode the order does not matter.
*/
@@ -74,17 +82,16 @@ static void jz4740_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
jz4740_timer_disable(pwm->hwpwm);
}
-static int jz4740_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
- int duty_ns, int period_ns)
+static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+ struct pwm_state *state)
{
struct jz4740_pwm_chip *jz4740 = to_jz4740(pwm->chip);
unsigned long long tmp;
unsigned long period, duty;
unsigned int prescaler = 0;
uint16_t ctrl;
- bool is_enabled;
- tmp = (unsigned long long)clk_get_rate(jz4740->clk) * period_ns;
+ tmp = (unsigned long long)clk_get_rate(jz4740->clk) * state->period;
do_div(tmp, 1000000000);
period = tmp;
@@ -96,16 +103,14 @@ static int jz4740_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
if (prescaler == 6)
return -EINVAL;
- tmp = (unsigned long long)period * duty_ns;
- do_div(tmp, period_ns);
+ tmp = (unsigned long long)period * state->duty_cycle;
+ do_div(tmp, state->period);
duty = period - tmp;
if (duty >= period)
duty = period - 1;
- is_enabled = jz4740_timer_is_enabled(pwm->hwpwm);
- if (is_enabled)
- jz4740_pwm_disable(chip, pwm);
+ jz4740_pwm_disable(chip, pwm);
jz4740_timer_set_count(pwm->hwpwm, 0);
jz4740_timer_set_duty(pwm->hwpwm, duty);
@@ -116,18 +121,7 @@ static int jz4740_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
jz4740_timer_set_ctrl(pwm->hwpwm, ctrl);
- if (is_enabled)
- jz4740_pwm_enable(chip, pwm);
-
- return 0;
-}
-
-static int jz4740_pwm_set_polarity(struct pwm_chip *chip,
- struct pwm_device *pwm, enum pwm_polarity polarity)
-{
- uint32_t ctrl = jz4740_timer_get_ctrl(pwm->pwm);
-
- switch (polarity) {
+ switch (state->polarity) {
case PWM_POLARITY_NORMAL:
ctrl &= ~JZ_TIMER_CTRL_PWM_ACTIVE_LOW;
break;
@@ -137,16 +131,17 @@ static int jz4740_pwm_set_polarity(struct pwm_chip *chip,
}
jz4740_timer_set_ctrl(pwm->hwpwm, ctrl);
+
+ if (state->enabled)
+ jz4740_pwm_enable(chip, pwm);
+
return 0;
}
static const struct pwm_ops jz4740_pwm_ops = {
.request = jz4740_pwm_request,
.free = jz4740_pwm_free,
- .config = jz4740_pwm_config,
- .set_polarity = jz4740_pwm_set_polarity,
- .enable = jz4740_pwm_enable,
- .disable = jz4740_pwm_disable,
+ .apply = jz4740_pwm_apply,
.owner = THIS_MODULE,
};
@@ -184,8 +179,6 @@ static int jz4740_pwm_remove(struct platform_device *pdev)
#ifdef CONFIG_OF
static const struct of_device_id jz4740_pwm_dt_ids[] = {
{ .compatible = "ingenic,jz4740-pwm", },
- { .compatible = "ingenic,jz4770-pwm", },
- { .compatible = "ingenic,jz4780-pwm", },
{},
};
MODULE_DEVICE_TABLE(of, jz4740_pwm_dt_ids);
diff --git a/drivers/pwm/pwm-lpss-pci.c b/drivers/pwm/pwm-lpss-pci.c
index c1527cb645be..cf749ea0de9f 100644
--- a/drivers/pwm/pwm-lpss-pci.c
+++ b/drivers/pwm/pwm-lpss-pci.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Intel Low Power Subsystem PWM controller PCI driver
*
* Copyright (C) 2014, Intel Corporation
*
* Derived from the original pwm-lpss.c
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/pwm/pwm-lpss-platform.c b/drivers/pwm/pwm-lpss-platform.c
index 757230e1f575..48f34d20aecd 100644
--- a/drivers/pwm/pwm-lpss-platform.c
+++ b/drivers/pwm/pwm-lpss-platform.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Intel Low Power Subsystem PWM controller driver
*
* Copyright (C) 2014, Intel Corporation
*
* Derived from the original pwm-lpss.c
- *
- * 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.
*/
#include <linux/acpi.h>
diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
index 2ac3a2aa9e53..4098a4601691 100644
--- a/drivers/pwm/pwm-lpss.c
+++ b/drivers/pwm/pwm-lpss.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Intel Low Power Subsystem PWM controller driver
*
@@ -7,10 +8,6 @@
* Author: Chang Rebecca Swee Fun <rebecca.swee.fun.chang@intel.com>
* Author: Chew Chiau Ee <chiau.ee.chew@intel.com>
* Author: Alan Cox <alan@linux.intel.com>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/pwm/pwm-lpss.h b/drivers/pwm/pwm-lpss.h
index 3236be835bd9..7909fa12fca2 100644
--- a/drivers/pwm/pwm-lpss.h
+++ b/drivers/pwm/pwm-lpss.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Intel Low Power Subsystem PWM controller driver
*
* Copyright (C) 2014, Intel Corporation
*
* Derived from the original pwm-lpss.c
- *
- * 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.
*/
#ifndef __PWM_LPSS_H
diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c
index fb5a369b1a8d..3cbff5cbb789 100644
--- a/drivers/pwm/pwm-meson.c
+++ b/drivers/pwm/pwm-meson.c
@@ -1,65 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * This file is provided under a dual BSD/GPLv2 license. When using or
- * redistributing this file, you may do so under either license.
+ * PWM controller driver for Amlogic Meson SoCs.
*
- * GPL LICENSE SUMMARY
+ * This PWM is only a set of Gates, Dividers and Counters:
+ * PWM output is achieved by calculating a clock that permits calculating
+ * two periods (low and high). The counter then has to be set to switch after
+ * N cycles for the first half period.
+ * The hardware has no "polarity" setting. This driver reverses the period
+ * cycles (the low length is inverted with the high length) for
+ * PWM_POLARITY_INVERSED. This means that .get_state cannot read the polarity
+ * from the hardware.
+ * Setting the duty cycle will disable and re-enable the PWM output.
+ * Disabling the PWM stops the output immediately (without waiting for the
+ * current period to complete first).
*
- * Copyright (c) 2016 BayLibre, SAS.
- * Author: Neil Armstrong <narmstrong@baylibre.com>
- * Copyright (C) 2014 Amlogic, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- * The full GNU General Public License is included in this distribution
- * in the file called COPYING.
- *
- * BSD LICENSE
+ * The public S912 (GXM) datasheet contains some documentation for this PWM
+ * controller starting on page 543:
+ * https://dl.khadas.com/Hardware/VIM2/Datasheet/S912_Datasheet_V0.220170314publicversion-Wesion.pdf
+ * An updated version of this IP block is found in S922X (G12B) SoCs. The
+ * datasheet contains the description for this IP block revision starting at
+ * page 1084:
+ * https://dn.odroid.com/S922X/ODROID-N2/Datasheet/S922X_Public_Datasheet_V0.2.pdf
*
* Copyright (c) 2016 BayLibre, SAS.
* Author: Neil Armstrong <narmstrong@baylibre.com>
* Copyright (C) 2014 Amlogic, Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Intel Corporation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include <linux/bitfield.h>
+#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/kernel.h>
+#include <linux/math64.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -70,7 +45,8 @@
#define REG_PWM_A 0x0
#define REG_PWM_B 0x4
-#define PWM_HIGH_SHIFT 16
+#define PWM_LOW_MASK GENMASK(15, 0)
+#define PWM_HIGH_MASK GENMASK(31, 16)
#define REG_MISC_AB 0x8
#define MISC_B_CLK_EN BIT(23)
@@ -80,13 +56,33 @@
#define MISC_A_CLK_DIV_SHIFT 8
#define MISC_B_CLK_SEL_SHIFT 6
#define MISC_A_CLK_SEL_SHIFT 4
-#define MISC_CLK_SEL_WIDTH 2
+#define MISC_CLK_SEL_MASK 0x3
#define MISC_B_EN BIT(1)
#define MISC_A_EN BIT(0)
-static const unsigned int mux_reg_shifts[] = {
- MISC_A_CLK_SEL_SHIFT,
- MISC_B_CLK_SEL_SHIFT
+#define MESON_NUM_PWMS 2
+
+static struct meson_pwm_channel_data {
+ u8 reg_offset;
+ u8 clk_sel_shift;
+ u8 clk_div_shift;
+ u32 clk_en_mask;
+ u32 pwm_en_mask;
+} meson_pwm_per_channel_data[MESON_NUM_PWMS] = {
+ {
+ .reg_offset = REG_PWM_A,
+ .clk_sel_shift = MISC_A_CLK_SEL_SHIFT,
+ .clk_div_shift = MISC_A_CLK_DIV_SHIFT,
+ .clk_en_mask = MISC_A_CLK_EN,
+ .pwm_en_mask = MISC_A_EN,
+ },
+ {
+ .reg_offset = REG_PWM_B,
+ .clk_sel_shift = MISC_B_CLK_SEL_SHIFT,
+ .clk_div_shift = MISC_B_CLK_DIV_SHIFT,
+ .clk_en_mask = MISC_B_CLK_EN,
+ .pwm_en_mask = MISC_B_EN,
+ }
};
struct meson_pwm_channel {
@@ -94,8 +90,6 @@ struct meson_pwm_channel {
unsigned int lo;
u8 pre_div;
- struct pwm_state state;
-
struct clk *clk_parent;
struct clk_mux mux;
struct clk *clk;
@@ -109,8 +103,8 @@ struct meson_pwm_data {
struct meson_pwm {
struct pwm_chip chip;
const struct meson_pwm_data *data;
+ struct meson_pwm_channel channels[MESON_NUM_PWMS];
void __iomem *base;
- u8 inverter_mask;
/*
* Protects register (write) access to the REG_MISC_AB register
* that is shared between the two PWMs.
@@ -125,12 +119,16 @@ static inline struct meson_pwm *to_meson_pwm(struct pwm_chip *chip)
static int meson_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
{
- struct meson_pwm_channel *channel = pwm_get_chip_data(pwm);
+ struct meson_pwm *meson = to_meson_pwm(chip);
+ struct meson_pwm_channel *channel;
struct device *dev = chip->dev;
int err;
- if (!channel)
- return -ENODEV;
+ channel = pwm_get_chip_data(pwm);
+ if (channel)
+ return 0;
+
+ channel = &meson->channels[pwm->hwpwm];
if (channel->clk_parent) {
err = clk_set_parent(channel->clk, channel->clk_parent);
@@ -149,9 +147,7 @@ static int meson_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
return err;
}
- chip->ops->get_state(chip, pwm, &channel->state);
-
- return 0;
+ return pwm_set_chip_data(pwm, channel);
}
static void meson_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
@@ -162,20 +158,18 @@ static void meson_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
clk_disable_unprepare(channel->clk);
}
-static int meson_pwm_calc(struct meson_pwm *meson,
- struct meson_pwm_channel *channel, unsigned int id,
- unsigned int duty, unsigned int period)
+static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm,
+ struct pwm_state *state)
{
- unsigned int pre_div, cnt, duty_cnt;
+ struct meson_pwm_channel *channel = pwm_get_chip_data(pwm);
+ unsigned int duty, period, pre_div, cnt, duty_cnt;
unsigned long fin_freq = -1;
- u64 fin_ps;
- if (~(meson->inverter_mask >> id) & 0x1)
- duty = period - duty;
+ duty = state->duty_cycle;
+ period = state->period;
- if (period == channel->state.period &&
- duty == channel->state.duty_cycle)
- return 0;
+ if (state->polarity == PWM_POLARITY_INVERSED)
+ duty = period - duty;
fin_freq = clk_get_rate(channel->clk);
if (fin_freq == 0) {
@@ -184,24 +178,19 @@ static int meson_pwm_calc(struct meson_pwm *meson,
}
dev_dbg(meson->chip.dev, "fin_freq: %lu Hz\n", fin_freq);
- fin_ps = (u64)NSEC_PER_SEC * 1000;
- do_div(fin_ps, fin_freq);
-
- /* Calc pre_div with the period */
- for (pre_div = 0; pre_div <= MISC_CLK_DIV_MASK; pre_div++) {
- cnt = DIV_ROUND_CLOSEST_ULL((u64)period * 1000,
- fin_ps * (pre_div + 1));
- dev_dbg(meson->chip.dev, "fin_ps=%llu pre_div=%u cnt=%u\n",
- fin_ps, pre_div, cnt);
- if (cnt <= 0xffff)
- break;
- }
+ pre_div = div64_u64(fin_freq * (u64)period, NSEC_PER_SEC * 0xffffLL);
if (pre_div > MISC_CLK_DIV_MASK) {
dev_err(meson->chip.dev, "unable to get period pre_div\n");
return -EINVAL;
}
+ cnt = div64_u64(fin_freq * (u64)period, NSEC_PER_SEC * (pre_div + 1));
+ if (cnt > 0xffff) {
+ dev_err(meson->chip.dev, "unable to get period cnt\n");
+ return -EINVAL;
+ }
+
dev_dbg(meson->chip.dev, "period=%u pre_div=%u cnt=%u\n", period,
pre_div, cnt);
@@ -215,8 +204,8 @@ static int meson_pwm_calc(struct meson_pwm *meson,
channel->lo = cnt;
} else {
/* Then check is we can have the duty with the same pre_div */
- duty_cnt = DIV_ROUND_CLOSEST_ULL((u64)duty * 1000,
- fin_ps * (pre_div + 1));
+ duty_cnt = div64_u64(fin_freq * (u64)duty,
+ NSEC_PER_SEC * (pre_div + 1));
if (duty_cnt > 0xffff) {
dev_err(meson->chip.dev, "unable to get duty cycle\n");
return -EINVAL;
@@ -233,73 +222,43 @@ static int meson_pwm_calc(struct meson_pwm *meson,
return 0;
}
-static void meson_pwm_enable(struct meson_pwm *meson,
- struct meson_pwm_channel *channel,
- unsigned int id)
+static void meson_pwm_enable(struct meson_pwm *meson, struct pwm_device *pwm)
{
- u32 value, clk_shift, clk_enable, enable;
- unsigned int offset;
+ struct meson_pwm_channel *channel = pwm_get_chip_data(pwm);
+ struct meson_pwm_channel_data *channel_data;
unsigned long flags;
+ u32 value;
- switch (id) {
- case 0:
- clk_shift = MISC_A_CLK_DIV_SHIFT;
- clk_enable = MISC_A_CLK_EN;
- enable = MISC_A_EN;
- offset = REG_PWM_A;
- break;
-
- case 1:
- clk_shift = MISC_B_CLK_DIV_SHIFT;
- clk_enable = MISC_B_CLK_EN;
- enable = MISC_B_EN;
- offset = REG_PWM_B;
- break;
-
- default:
- return;
- }
+ channel_data = &meson_pwm_per_channel_data[pwm->hwpwm];
spin_lock_irqsave(&meson->lock, flags);
value = readl(meson->base + REG_MISC_AB);
- value &= ~(MISC_CLK_DIV_MASK << clk_shift);
- value |= channel->pre_div << clk_shift;
- value |= clk_enable;
+ value &= ~(MISC_CLK_DIV_MASK << channel_data->clk_div_shift);
+ value |= channel->pre_div << channel_data->clk_div_shift;
+ value |= channel_data->clk_en_mask;
writel(value, meson->base + REG_MISC_AB);
- value = (channel->hi << PWM_HIGH_SHIFT) | channel->lo;
- writel(value, meson->base + offset);
+ value = FIELD_PREP(PWM_HIGH_MASK, channel->hi) |
+ FIELD_PREP(PWM_LOW_MASK, channel->lo);
+ writel(value, meson->base + channel_data->reg_offset);
value = readl(meson->base + REG_MISC_AB);
- value |= enable;
+ value |= channel_data->pwm_en_mask;
writel(value, meson->base + REG_MISC_AB);
spin_unlock_irqrestore(&meson->lock, flags);
}
-static void meson_pwm_disable(struct meson_pwm *meson, unsigned int id)
+static void meson_pwm_disable(struct meson_pwm *meson, struct pwm_device *pwm)
{
- u32 value, enable;
unsigned long flags;
-
- switch (id) {
- case 0:
- enable = MISC_A_EN;
- break;
-
- case 1:
- enable = MISC_B_EN;
- break;
-
- default:
- return;
- }
+ u32 value;
spin_lock_irqsave(&meson->lock, flags);
value = readl(meson->base + REG_MISC_AB);
- value &= ~enable;
+ value &= ~meson_pwm_per_channel_data[pwm->hwpwm].pwm_en_mask;
writel(value, meson->base + REG_MISC_AB);
spin_unlock_irqrestore(&meson->lock, flags);
@@ -316,64 +275,97 @@ static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return -EINVAL;
if (!state->enabled) {
- meson_pwm_disable(meson, pwm->hwpwm);
- channel->state.enabled = false;
-
- return 0;
- }
-
- if (state->period != channel->state.period ||
- state->duty_cycle != channel->state.duty_cycle ||
- state->polarity != channel->state.polarity) {
- if (state->polarity != channel->state.polarity) {
- if (state->polarity == PWM_POLARITY_NORMAL)
- meson->inverter_mask |= BIT(pwm->hwpwm);
- else
- meson->inverter_mask &= ~BIT(pwm->hwpwm);
+ if (state->polarity == PWM_POLARITY_INVERSED) {
+ /*
+ * This IP block revision doesn't have an "always high"
+ * setting which we can use for "inverted disabled".
+ * Instead we achieve this using the same settings
+ * that we use a pre_div of 0 (to get the shortest
+ * possible duration for one "count") and
+ * "period == duty_cycle". This results in a signal
+ * which is LOW for one "count", while being HIGH for
+ * the rest of the (so the signal is HIGH for slightly
+ * less than 100% of the period, but this is the best
+ * we can achieve).
+ */
+ channel->pre_div = 0;
+ channel->hi = ~0;
+ channel->lo = 0;
+
+ meson_pwm_enable(meson, pwm);
+ } else {
+ meson_pwm_disable(meson, pwm);
}
-
- err = meson_pwm_calc(meson, channel, pwm->hwpwm,
- state->duty_cycle, state->period);
+ } else {
+ err = meson_pwm_calc(meson, pwm, state);
if (err < 0)
return err;
- channel->state.polarity = state->polarity;
- channel->state.period = state->period;
- channel->state.duty_cycle = state->duty_cycle;
- }
-
- if (state->enabled && !channel->state.enabled) {
- meson_pwm_enable(meson, channel, pwm->hwpwm);
- channel->state.enabled = true;
+ meson_pwm_enable(meson, pwm);
}
return 0;
}
+static unsigned int meson_pwm_cnt_to_ns(struct pwm_chip *chip,
+ struct pwm_device *pwm, u32 cnt)
+{
+ struct meson_pwm *meson = to_meson_pwm(chip);
+ struct meson_pwm_channel *channel;
+ unsigned long fin_freq;
+ u32 fin_ns;
+
+ /* to_meson_pwm() can only be used after .get_state() is called */
+ channel = &meson->channels[pwm->hwpwm];
+
+ fin_freq = clk_get_rate(channel->clk);
+ if (fin_freq == 0)
+ return 0;
+
+ fin_ns = div_u64(NSEC_PER_SEC, fin_freq);
+
+ return cnt * fin_ns * (channel->pre_div + 1);
+}
+
static void meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
struct pwm_state *state)
{
struct meson_pwm *meson = to_meson_pwm(chip);
- u32 value, mask;
+ struct meson_pwm_channel_data *channel_data;
+ struct meson_pwm_channel *channel;
+ u32 value, tmp;
if (!state)
return;
- switch (pwm->hwpwm) {
- case 0:
- mask = MISC_A_EN;
- break;
+ channel = &meson->channels[pwm->hwpwm];
+ channel_data = &meson_pwm_per_channel_data[pwm->hwpwm];
- case 1:
- mask = MISC_B_EN;
- break;
+ value = readl(meson->base + REG_MISC_AB);
- default:
- return;
- }
+ tmp = channel_data->pwm_en_mask | channel_data->clk_en_mask;
+ state->enabled = (value & tmp) == tmp;
- value = readl(meson->base + REG_MISC_AB);
- state->enabled = (value & mask) != 0;
+ tmp = value >> channel_data->clk_div_shift;
+ channel->pre_div = FIELD_GET(MISC_CLK_DIV_MASK, tmp);
+
+ value = readl(meson->base + channel_data->reg_offset);
+
+ channel->lo = FIELD_GET(PWM_LOW_MASK, value);
+ channel->hi = FIELD_GET(PWM_HIGH_MASK, value);
+
+ if (channel->lo == 0) {
+ state->period = meson_pwm_cnt_to_ns(chip, pwm, channel->hi);
+ state->duty_cycle = state->period;
+ } else if (channel->lo >= channel->hi) {
+ state->period = meson_pwm_cnt_to_ns(chip, pwm,
+ channel->lo + channel->hi);
+ state->duty_cycle = meson_pwm_cnt_to_ns(chip, pwm,
+ channel->hi);
+ } else {
+ state->period = 0;
+ state->duty_cycle = 0;
+ }
}
static const struct pwm_ops meson_pwm_ops = {
@@ -433,8 +425,17 @@ static const struct meson_pwm_data pwm_axg_ao_data = {
.num_parents = ARRAY_SIZE(pwm_axg_ao_parent_names),
};
+static const char * const pwm_g12a_ao_ab_parent_names[] = {
+ "xtal", "aoclk81", "fclk_div4", "fclk_div5"
+};
+
+static const struct meson_pwm_data pwm_g12a_ao_ab_data = {
+ .parent_names = pwm_g12a_ao_ab_parent_names,
+ .num_parents = ARRAY_SIZE(pwm_g12a_ao_ab_parent_names),
+};
+
static const char * const pwm_g12a_ao_cd_parent_names[] = {
- "aoclk81", "xtal",
+ "xtal", "aoclk81",
};
static const struct meson_pwm_data pwm_g12a_ao_cd_data = {
@@ -478,7 +479,7 @@ static const struct of_device_id meson_pwm_matches[] = {
},
{
.compatible = "amlogic,meson-g12a-ao-pwm-ab",
- .data = &pwm_axg_ao_data
+ .data = &pwm_g12a_ao_ab_data
},
{
.compatible = "amlogic,meson-g12a-ao-pwm-cd",
@@ -488,8 +489,7 @@ static const struct of_device_id meson_pwm_matches[] = {
};
MODULE_DEVICE_TABLE(of, meson_pwm_matches);
-static int meson_pwm_init_channels(struct meson_pwm *meson,
- struct meson_pwm_channel *channels)
+static int meson_pwm_init_channels(struct meson_pwm *meson)
{
struct device *dev = meson->chip.dev;
struct clk_init_data init;
@@ -498,7 +498,7 @@ static int meson_pwm_init_channels(struct meson_pwm *meson,
int err;
for (i = 0; i < meson->chip.npwm; i++) {
- struct meson_pwm_channel *channel = &channels[i];
+ struct meson_pwm_channel *channel = &meson->channels[i];
snprintf(name, sizeof(name), "%s#mux%u", dev_name(dev), i);
@@ -509,8 +509,9 @@ static int meson_pwm_init_channels(struct meson_pwm *meson,
init.num_parents = meson->data->num_parents;
channel->mux.reg = meson->base + REG_MISC_AB;
- channel->mux.shift = mux_reg_shifts[i];
- channel->mux.mask = BIT(MISC_CLK_SEL_WIDTH) - 1;
+ channel->mux.shift =
+ meson_pwm_per_channel_data[i].clk_sel_shift;
+ channel->mux.mask = MISC_CLK_SEL_MASK;
channel->mux.flags = 0;
channel->mux.lock = &meson->lock;
channel->mux.table = NULL;
@@ -525,31 +526,16 @@ static int meson_pwm_init_channels(struct meson_pwm *meson,
snprintf(name, sizeof(name), "clkin%u", i);
- channel->clk_parent = devm_clk_get(dev, name);
- if (IS_ERR(channel->clk_parent)) {
- err = PTR_ERR(channel->clk_parent);
- if (err == -EPROBE_DEFER)
- return err;
-
- channel->clk_parent = NULL;
- }
+ channel->clk_parent = devm_clk_get_optional(dev, name);
+ if (IS_ERR(channel->clk_parent))
+ return PTR_ERR(channel->clk_parent);
}
return 0;
}
-static void meson_pwm_add_channels(struct meson_pwm *meson,
- struct meson_pwm_channel *channels)
-{
- unsigned int i;
-
- for (i = 0; i < meson->chip.npwm; i++)
- pwm_set_chip_data(&meson->chip.pwms[i], &channels[i]);
-}
-
static int meson_pwm_probe(struct platform_device *pdev)
{
- struct meson_pwm_channel *channels;
struct meson_pwm *meson;
struct resource *regs;
int err;
@@ -567,19 +553,13 @@ static int meson_pwm_probe(struct platform_device *pdev)
meson->chip.dev = &pdev->dev;
meson->chip.ops = &meson_pwm_ops;
meson->chip.base = -1;
- meson->chip.npwm = 2;
+ meson->chip.npwm = MESON_NUM_PWMS;
meson->chip.of_xlate = of_pwm_xlate_with_flags;
meson->chip.of_pwm_n_cells = 3;
meson->data = of_device_get_match_data(&pdev->dev);
- meson->inverter_mask = BIT(meson->chip.npwm) - 1;
- channels = devm_kcalloc(&pdev->dev, meson->chip.npwm,
- sizeof(*channels), GFP_KERNEL);
- if (!channels)
- return -ENOMEM;
-
- err = meson_pwm_init_channels(meson, channels);
+ err = meson_pwm_init_channels(meson);
if (err < 0)
return err;
@@ -589,8 +569,6 @@ static int meson_pwm_probe(struct platform_device *pdev)
return err;
}
- meson_pwm_add_channels(meson, channels);
-
platform_set_drvdata(pdev, meson);
return 0;
diff --git a/drivers/pwm/pwm-omap-dmtimer.c b/drivers/pwm/pwm-omap-dmtimer.c
index f45798679e3c..00772fc53490 100644
--- a/drivers/pwm/pwm-omap-dmtimer.c
+++ b/drivers/pwm/pwm-omap-dmtimer.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2015 Neil Armstrong <narmstrong@baylibre.com>
* Copyright (c) 2014 Joachim Eastwood <manabian@gmail.com>
@@ -7,10 +8,6 @@
*
* Also based on pwm-samsung.c
*
- * 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.
- *
* Description:
* This file is the core OMAP support for the generic, Linux
* PWM driver / controller, using the OMAP's dual-mode timers.
diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index 567f5e2771c4..168684b02ebc 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for PCA9685 16-channel 12-bit PWM LED controller
*
@@ -5,18 +6,6 @@
* Copyright (C) 2015 Clemens Gruber <clemens.gruber@pqgruber.com>
*
* based on the pwm-twl-led.c driver
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/acpi.h>
diff --git a/drivers/pwm/pwm-puv3.c b/drivers/pwm/pwm-puv3.c
index 754fd9a98f6b..9d0bd87a425e 100644
--- a/drivers/pwm/pwm-puv3.c
+++ b/drivers/pwm/pwm-puv3.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/arch/unicore32/kernel/pwm.c
*
@@ -5,10 +6,6 @@
*
* Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
* Copyright (C) 2001-2010 Guan Xuetao
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c
index 4143a46684d2..a2a0912c2dcd 100644
--- a/drivers/pwm/pwm-pxa.c
+++ b/drivers/pwm/pwm-pxa.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/pwm/pwm-pxa.c
*
* simple driver for PWM (Pulse Width Modulator) controller
*
- * 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.
- *
* 2008-02-13 initial version
* eric miao <eric.miao@marvell.com>
*/
diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c
index cfe7dd1b448e..5b2b8ecc354c 100644
--- a/drivers/pwm/pwm-rcar.c
+++ b/drivers/pwm/pwm-rcar.c
@@ -254,50 +254,11 @@ static const struct of_device_id rcar_pwm_of_table[] = {
};
MODULE_DEVICE_TABLE(of, rcar_pwm_of_table);
-#ifdef CONFIG_PM_SLEEP
-static struct pwm_device *rcar_pwm_dev_to_pwm_dev(struct device *dev)
-{
- struct rcar_pwm_chip *rcar_pwm = dev_get_drvdata(dev);
- struct pwm_chip *chip = &rcar_pwm->chip;
-
- return &chip->pwms[0];
-}
-
-static int rcar_pwm_suspend(struct device *dev)
-{
- struct pwm_device *pwm = rcar_pwm_dev_to_pwm_dev(dev);
-
- if (!test_bit(PWMF_REQUESTED, &pwm->flags))
- return 0;
-
- pm_runtime_put(dev);
-
- return 0;
-}
-
-static int rcar_pwm_resume(struct device *dev)
-{
- struct pwm_device *pwm = rcar_pwm_dev_to_pwm_dev(dev);
- struct pwm_state state;
-
- if (!test_bit(PWMF_REQUESTED, &pwm->flags))
- return 0;
-
- pm_runtime_get_sync(dev);
-
- pwm_get_state(pwm, &state);
-
- return rcar_pwm_apply(pwm->chip, pwm, &state);
-}
-#endif /* CONFIG_PM_SLEEP */
-static SIMPLE_DEV_PM_OPS(rcar_pwm_pm_ops, rcar_pwm_suspend, rcar_pwm_resume);
-
static struct platform_driver rcar_pwm_driver = {
.probe = rcar_pwm_probe,
.remove = rcar_pwm_remove,
.driver = {
.name = "pwm-rcar",
- .pm = &rcar_pwm_pm_ops,
.of_match_table = of_match_ptr(rcar_pwm_of_table),
}
};
diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c
index 4d99d468df09..51b96cb7dd25 100644
--- a/drivers/pwm/pwm-rockchip.c
+++ b/drivers/pwm/pwm-rockchip.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* PWM driver for Rockchip SoCs
*
* Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
* Copyright (C) 2014 ROCKCHIP, 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.
*/
#include <linux/clk.h>
diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c
new file mode 100644
index 000000000000..a7c107f19e66
--- /dev/null
+++ b/drivers/pwm/pwm-sifive.c
@@ -0,0 +1,339 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017-2018 SiFive
+ * For SiFive's PWM IP block documentation please refer Chapter 14 of
+ * Reference Manual : https://static.dev.sifive.com/FU540-C000-v1.0.pdf
+ *
+ * Limitations:
+ * - When changing both duty cycle and period, we cannot prevent in
+ * software that the output might produce a period with mixed
+ * settings (new period length and old duty cycle).
+ * - The hardware cannot generate a 100% duty cycle.
+ * - The hardware generates only inverted output.
+ */
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+#include <linux/bitfield.h>
+
+/* Register offsets */
+#define PWM_SIFIVE_PWMCFG 0x0
+#define PWM_SIFIVE_PWMCOUNT 0x8
+#define PWM_SIFIVE_PWMS 0x10
+#define PWM_SIFIVE_PWMCMP0 0x20
+
+/* PWMCFG fields */
+#define PWM_SIFIVE_PWMCFG_SCALE GENMASK(3, 0)
+#define PWM_SIFIVE_PWMCFG_STICKY BIT(8)
+#define PWM_SIFIVE_PWMCFG_ZERO_CMP BIT(9)
+#define PWM_SIFIVE_PWMCFG_DEGLITCH BIT(10)
+#define PWM_SIFIVE_PWMCFG_EN_ALWAYS BIT(12)
+#define PWM_SIFIVE_PWMCFG_EN_ONCE BIT(13)
+#define PWM_SIFIVE_PWMCFG_CENTER BIT(16)
+#define PWM_SIFIVE_PWMCFG_GANG BIT(24)
+#define PWM_SIFIVE_PWMCFG_IP BIT(28)
+
+/* PWM_SIFIVE_SIZE_PWMCMP is used to calculate offset for pwmcmpX registers */
+#define PWM_SIFIVE_SIZE_PWMCMP 4
+#define PWM_SIFIVE_CMPWIDTH 16
+#define PWM_SIFIVE_DEFAULT_PERIOD 10000000
+
+struct pwm_sifive_ddata {
+ struct pwm_chip chip;
+ struct mutex lock; /* lock to protect user_count */
+ struct notifier_block notifier;
+ struct clk *clk;
+ void __iomem *regs;
+ unsigned int real_period;
+ unsigned int approx_period;
+ int user_count;
+};
+
+static inline
+struct pwm_sifive_ddata *pwm_sifive_chip_to_ddata(struct pwm_chip *c)
+{
+ return container_of(c, struct pwm_sifive_ddata, chip);
+}
+
+static int pwm_sifive_request(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip);
+
+ mutex_lock(&ddata->lock);
+ ddata->user_count++;
+ mutex_unlock(&ddata->lock);
+
+ return 0;
+}
+
+static void pwm_sifive_free(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip);
+
+ mutex_lock(&ddata->lock);
+ ddata->user_count--;
+ mutex_unlock(&ddata->lock);
+}
+
+static void pwm_sifive_update_clock(struct pwm_sifive_ddata *ddata,
+ unsigned long rate)
+{
+ unsigned long long num;
+ unsigned long scale_pow;
+ int scale;
+ u32 val;
+ /*
+ * The PWM unit is used with pwmzerocmp=0, so the only way to modify the
+ * period length is using pwmscale which provides the number of bits the
+ * counter is shifted before being feed to the comparators. A period
+ * lasts (1 << (PWM_SIFIVE_CMPWIDTH + pwmscale)) clock ticks.
+ * (1 << (PWM_SIFIVE_CMPWIDTH + scale)) * 10^9/rate = period
+ */
+ scale_pow = div64_ul(ddata->approx_period * (u64)rate, NSEC_PER_SEC);
+ scale = clamp(ilog2(scale_pow) - PWM_SIFIVE_CMPWIDTH, 0, 0xf);
+
+ val = PWM_SIFIVE_PWMCFG_EN_ALWAYS |
+ FIELD_PREP(PWM_SIFIVE_PWMCFG_SCALE, scale);
+ writel(val, ddata->regs + PWM_SIFIVE_PWMCFG);
+
+ /* As scale <= 15 the shift operation cannot overflow. */
+ num = (unsigned long long)NSEC_PER_SEC << (PWM_SIFIVE_CMPWIDTH + scale);
+ ddata->real_period = div64_ul(num, rate);
+ dev_dbg(ddata->chip.dev,
+ "New real_period = %u ns\n", ddata->real_period);
+}
+
+static void pwm_sifive_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
+ struct pwm_state *state)
+{
+ struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip);
+ u32 duty, val;
+
+ duty = readl(ddata->regs + PWM_SIFIVE_PWMCMP0 +
+ pwm->hwpwm * PWM_SIFIVE_SIZE_PWMCMP);
+
+ state->enabled = duty > 0;
+
+ val = readl(ddata->regs + PWM_SIFIVE_PWMCFG);
+ if (!(val & PWM_SIFIVE_PWMCFG_EN_ALWAYS))
+ state->enabled = false;
+
+ state->period = ddata->real_period;
+ state->duty_cycle =
+ (u64)duty * ddata->real_period >> PWM_SIFIVE_CMPWIDTH;
+ state->polarity = PWM_POLARITY_INVERSED;
+}
+
+static int pwm_sifive_enable(struct pwm_chip *chip, bool enable)
+{
+ struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip);
+ int ret;
+
+ if (enable) {
+ ret = clk_enable(ddata->clk);
+ if (ret) {
+ dev_err(ddata->chip.dev, "Enable clk failed\n");
+ return ret;
+ }
+ }
+
+ if (!enable)
+ clk_disable(ddata->clk);
+
+ return 0;
+}
+
+static int pwm_sifive_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+ struct pwm_state *state)
+{
+ struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip);
+ struct pwm_state cur_state;
+ unsigned int duty_cycle;
+ unsigned long long num;
+ bool enabled;
+ int ret = 0;
+ u32 frac;
+
+ if (state->polarity != PWM_POLARITY_INVERSED)
+ return -EINVAL;
+
+ ret = clk_enable(ddata->clk);
+ if (ret) {
+ dev_err(ddata->chip.dev, "Enable clk failed\n");
+ return ret;
+ }
+
+ mutex_lock(&ddata->lock);
+ cur_state = pwm->state;
+ enabled = cur_state.enabled;
+
+ duty_cycle = state->duty_cycle;
+ if (!state->enabled)
+ duty_cycle = 0;
+
+ /*
+ * The problem of output producing mixed setting as mentioned at top,
+ * occurs here. To minimize the window for this problem, we are
+ * calculating the register values first and then writing them
+ * consecutively
+ */
+ num = (u64)duty_cycle * (1U << PWM_SIFIVE_CMPWIDTH);
+ frac = DIV_ROUND_CLOSEST_ULL(num, state->period);
+ /* The hardware cannot generate a 100% duty cycle */
+ frac = min(frac, (1U << PWM_SIFIVE_CMPWIDTH) - 1);
+
+ if (state->period != ddata->approx_period) {
+ if (ddata->user_count != 1) {
+ ret = -EBUSY;
+ goto exit;
+ }
+ ddata->approx_period = state->period;
+ pwm_sifive_update_clock(ddata, clk_get_rate(ddata->clk));
+ }
+
+ writel(frac, ddata->regs + PWM_SIFIVE_PWMCMP0 +
+ pwm->hwpwm * PWM_SIFIVE_SIZE_PWMCMP);
+
+ if (state->enabled != enabled)
+ pwm_sifive_enable(chip, state->enabled);
+
+exit:
+ clk_disable(ddata->clk);
+ mutex_unlock(&ddata->lock);
+ return ret;
+}
+
+static const struct pwm_ops pwm_sifive_ops = {
+ .request = pwm_sifive_request,
+ .free = pwm_sifive_free,
+ .get_state = pwm_sifive_get_state,
+ .apply = pwm_sifive_apply,
+ .owner = THIS_MODULE,
+};
+
+static int pwm_sifive_clock_notifier(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct clk_notifier_data *ndata = data;
+ struct pwm_sifive_ddata *ddata =
+ container_of(nb, struct pwm_sifive_ddata, notifier);
+
+ if (event == POST_RATE_CHANGE)
+ pwm_sifive_update_clock(ddata, ndata->new_rate);
+
+ return NOTIFY_OK;
+}
+
+static int pwm_sifive_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct pwm_sifive_ddata *ddata;
+ struct pwm_chip *chip;
+ struct resource *res;
+ int ret;
+
+ ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
+ if (!ddata)
+ return -ENOMEM;
+
+ mutex_init(&ddata->lock);
+ chip = &ddata->chip;
+ chip->dev = dev;
+ chip->ops = &pwm_sifive_ops;
+ chip->of_xlate = of_pwm_xlate_with_flags;
+ chip->of_pwm_n_cells = 3;
+ chip->base = -1;
+ chip->npwm = 4;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ddata->regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(ddata->regs)) {
+ dev_err(dev, "Unable to map IO resources\n");
+ return PTR_ERR(ddata->regs);
+ }
+
+ ddata->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(ddata->clk)) {
+ if (PTR_ERR(ddata->clk) != -EPROBE_DEFER)
+ dev_err(dev, "Unable to find controller clock\n");
+ return PTR_ERR(ddata->clk);
+ }
+
+ ret = clk_prepare_enable(ddata->clk);
+ if (ret) {
+ dev_err(dev, "failed to enable clock for pwm: %d\n", ret);
+ return ret;
+ }
+
+ /* Watch for changes to underlying clock frequency */
+ ddata->notifier.notifier_call = pwm_sifive_clock_notifier;
+ ret = clk_notifier_register(ddata->clk, &ddata->notifier);
+ if (ret) {
+ dev_err(dev, "failed to register clock notifier: %d\n", ret);
+ goto disable_clk;
+ }
+
+ ret = pwmchip_add(chip);
+ if (ret < 0) {
+ dev_err(dev, "cannot register PWM: %d\n", ret);
+ goto unregister_clk;
+ }
+
+ platform_set_drvdata(pdev, ddata);
+ dev_dbg(dev, "SiFive PWM chip registered %d PWMs\n", chip->npwm);
+
+ return 0;
+
+unregister_clk:
+ clk_notifier_unregister(ddata->clk, &ddata->notifier);
+disable_clk:
+ clk_disable_unprepare(ddata->clk);
+
+ return ret;
+}
+
+static int pwm_sifive_remove(struct platform_device *dev)
+{
+ struct pwm_sifive_ddata *ddata = platform_get_drvdata(dev);
+ bool is_enabled = false;
+ struct pwm_device *pwm;
+ int ret, ch;
+
+ for (ch = 0; ch < ddata->chip.npwm; ch++) {
+ pwm = &ddata->chip.pwms[ch];
+ if (pwm->state.enabled) {
+ is_enabled = true;
+ break;
+ }
+ }
+ if (is_enabled)
+ clk_disable(ddata->clk);
+
+ clk_disable_unprepare(ddata->clk);
+ ret = pwmchip_remove(&ddata->chip);
+ clk_notifier_unregister(ddata->clk, &ddata->notifier);
+
+ return ret;
+}
+
+static const struct of_device_id pwm_sifive_of_match[] = {
+ { .compatible = "sifive,pwm0" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, pwm_sifive_of_match);
+
+static struct platform_driver pwm_sifive_driver = {
+ .probe = pwm_sifive_probe,
+ .remove = pwm_sifive_remove,
+ .driver = {
+ .name = "pwm-sifive",
+ .of_match_table = pwm_sifive_of_match,
+ },
+};
+module_platform_driver(pwm_sifive_driver);
+
+MODULE_DESCRIPTION("SiFive PWM driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pwm/pwm-stm32-lp.c b/drivers/pwm/pwm-stm32-lp.c
index 0059b24cfdc3..2211a642066d 100644
--- a/drivers/pwm/pwm-stm32-lp.c
+++ b/drivers/pwm/pwm-stm32-lp.c
@@ -13,6 +13,7 @@
#include <linux/mfd/stm32-lptimer.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/pwm.h>
@@ -223,6 +224,29 @@ static int stm32_pwm_lp_remove(struct platform_device *pdev)
return pwmchip_remove(&priv->chip);
}
+static int __maybe_unused stm32_pwm_lp_suspend(struct device *dev)
+{
+ struct stm32_pwm_lp *priv = dev_get_drvdata(dev);
+ struct pwm_state state;
+
+ pwm_get_state(&priv->chip.pwms[0], &state);
+ if (state.enabled) {
+ dev_err(dev, "The consumer didn't stop us (%s)\n",
+ priv->chip.pwms[0].label);
+ return -EBUSY;
+ }
+
+ return pinctrl_pm_select_sleep_state(dev);
+}
+
+static int __maybe_unused stm32_pwm_lp_resume(struct device *dev)
+{
+ return pinctrl_pm_select_default_state(dev);
+}
+
+static SIMPLE_DEV_PM_OPS(stm32_pwm_lp_pm_ops, stm32_pwm_lp_suspend,
+ stm32_pwm_lp_resume);
+
static const struct of_device_id stm32_pwm_lp_of_match[] = {
{ .compatible = "st,stm32-pwm-lp", },
{},
@@ -235,6 +259,7 @@ static struct platform_driver stm32_pwm_lp_driver = {
.driver = {
.name = "stm32-pwm-lp",
.of_match_table = of_match_ptr(stm32_pwm_lp_of_match),
+ .pm = &stm32_pwm_lp_pm_ops,
},
};
module_platform_driver(stm32_pwm_lp_driver);
diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c
index 4f842550fbd1..740e2dec8313 100644
--- a/drivers/pwm/pwm-stm32.c
+++ b/drivers/pwm/pwm-stm32.c
@@ -608,6 +608,8 @@ static int stm32_pwm_probe(struct platform_device *pdev)
priv->regmap = ddata->regmap;
priv->clk = ddata->clk;
priv->max_arr = ddata->max_arr;
+ priv->chip.of_xlate = of_pwm_xlate_with_flags;
+ priv->chip.of_pwm_n_cells = 3;
if (!priv->regmap || !priv->clk)
return -EINVAL;
diff --git a/drivers/pwm/pwm-stmpe.c b/drivers/pwm/pwm-stmpe.c
index 3439f1e902cb..be5f6d7359d4 100644
--- a/drivers/pwm/pwm-stmpe.c
+++ b/drivers/pwm/pwm-stmpe.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2016 Linaro Ltd.
*
* Author: Linus Walleij <linus.walleij@linaro.org>
- *
- * 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.
- *
*/
#include <linux/bitops.h>
diff --git a/drivers/pwm/pwm-twl-led.c b/drivers/pwm/pwm-twl-led.c
index 01153622778b..630b9a578820 100644
--- a/drivers/pwm/pwm-twl-led.c
+++ b/drivers/pwm/pwm-twl-led.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for TWL4030/6030 Pulse Width Modulator used as LED driver
*
@@ -6,18 +7,6 @@
*
* This driver is a complete rewrite of the former pwm-twl6030.c authorded by:
* Hemanth V <hemanthv@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
diff --git a/drivers/pwm/pwm-twl.c b/drivers/pwm/pwm-twl.c
index b7a45be99815..aee67974f353 100644
--- a/drivers/pwm/pwm-twl.c
+++ b/drivers/pwm/pwm-twl.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for TWL4030/6030 Generic Pulse Width Modulator
*
* Copyright (C) 2012 Texas Instruments
* Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
diff --git a/drivers/pwm/pwm-zx.c b/drivers/pwm/pwm-zx.c
index 5d27c16edfb1..e24f4be35316 100644
--- a/drivers/pwm/pwm-zx.c
+++ b/drivers/pwm/pwm-zx.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2017 Sanechips Technology Co., Ltd.
* Copyright 2017 Linaro Ltd.
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c
index bf6823fe0812..2389b8669846 100644
--- a/drivers/pwm/sysfs.c
+++ b/drivers/pwm/sysfs.c
@@ -18,6 +18,7 @@ struct pwm_export {
struct device child;
struct pwm_device *pwm;
struct mutex lock;
+ struct pwm_state suspend;
};
static struct pwm_export *child_to_pwm_export(struct device *child)
@@ -372,10 +373,111 @@ static struct attribute *pwm_chip_attrs[] = {
};
ATTRIBUTE_GROUPS(pwm_chip);
+/* takes export->lock on success */
+static struct pwm_export *pwm_class_get_state(struct device *parent,
+ struct pwm_device *pwm,
+ struct pwm_state *state)
+{
+ struct device *child;
+ struct pwm_export *export;
+
+ if (!test_bit(PWMF_EXPORTED, &pwm->flags))
+ return NULL;
+
+ child = device_find_child(parent, pwm, pwm_unexport_match);
+ if (!child)
+ return NULL;
+
+ export = child_to_pwm_export(child);
+ put_device(child); /* for device_find_child() */
+
+ mutex_lock(&export->lock);
+ pwm_get_state(pwm, state);
+
+ return export;
+}
+
+static int pwm_class_apply_state(struct pwm_export *export,
+ struct pwm_device *pwm,
+ struct pwm_state *state)
+{
+ int ret = pwm_apply_state(pwm, state);
+
+ /* release lock taken in pwm_class_get_state */
+ mutex_unlock(&export->lock);
+
+ return ret;
+}
+
+static int pwm_class_resume_npwm(struct device *parent, unsigned int npwm)
+{
+ struct pwm_chip *chip = dev_get_drvdata(parent);
+ unsigned int i;
+ int ret = 0;
+
+ for (i = 0; i < npwm; i++) {
+ struct pwm_device *pwm = &chip->pwms[i];
+ struct pwm_state state;
+ struct pwm_export *export;
+
+ export = pwm_class_get_state(parent, pwm, &state);
+ if (!export)
+ continue;
+
+ state.enabled = export->suspend.enabled;
+ ret = pwm_class_apply_state(export, pwm, &state);
+ if (ret < 0)
+ break;
+ }
+
+ return ret;
+}
+
+static int __maybe_unused pwm_class_suspend(struct device *parent)
+{
+ struct pwm_chip *chip = dev_get_drvdata(parent);
+ unsigned int i;
+ int ret = 0;
+
+ for (i = 0; i < chip->npwm; i++) {
+ struct pwm_device *pwm = &chip->pwms[i];
+ struct pwm_state state;
+ struct pwm_export *export;
+
+ export = pwm_class_get_state(parent, pwm, &state);
+ if (!export)
+ continue;
+
+ export->suspend = state;
+ state.enabled = false;
+ ret = pwm_class_apply_state(export, pwm, &state);
+ if (ret < 0) {
+ /*
+ * roll back the PWM devices that were disabled by
+ * this suspend function.
+ */
+ pwm_class_resume_npwm(parent, i);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int __maybe_unused pwm_class_resume(struct device *parent)
+{
+ struct pwm_chip *chip = dev_get_drvdata(parent);
+
+ return pwm_class_resume_npwm(parent, chip->npwm);
+}
+
+static SIMPLE_DEV_PM_OPS(pwm_class_pm_ops, pwm_class_suspend, pwm_class_resume);
+
static struct class pwm_class = {
.name = "pwm",
.owner = THIS_MODULE,
.dev_groups = pwm_chip_groups,
+ .pm = &pwm_class_pm_ops,
};
static int pwmchip_sysfs_match(struct device *parent, const void *data)
diff --git a/drivers/rapidio/Kconfig b/drivers/rapidio/Kconfig
index fadafc64705f..677d1aff61b7 100644
--- a/drivers/rapidio/Kconfig
+++ b/drivers/rapidio/Kconfig
@@ -86,7 +86,7 @@ config RAPIDIO_CHMAN
This option includes RapidIO channelized messaging driver which
provides socket-like interface to allow sharing of single RapidIO
messaging mailbox between multiple user-space applications.
- See "Documentation/rapidio/rio_cm.txt" for driver description.
+ See "Documentation/driver-api/rapidio/rio_cm.rst" for driver description.
config RAPIDIO_MPORT_CDEV
tristate "RapidIO /dev mport device driver"
diff --git a/drivers/rapidio/devices/rio_mport_cdev.c b/drivers/rapidio/devices/rio_mport_cdev.c
index ce7a90e68042..8155f59ece38 100644
--- a/drivers/rapidio/devices/rio_mport_cdev.c
+++ b/drivers/rapidio/devices/rio_mport_cdev.c
@@ -1686,6 +1686,7 @@ static int rio_mport_add_riodev(struct mport_cdev_priv *priv,
if (copy_from_user(&dev_info, arg, sizeof(dev_info)))
return -EFAULT;
+ dev_info.name[sizeof(dev_info.name) - 1] = '\0';
rmcd_debug(RDEV, "name:%s ct:0x%x did:0x%x hc:0x%x", dev_info.name,
dev_info.comptag, dev_info.destid, dev_info.hopcount);
@@ -1817,6 +1818,7 @@ static int rio_mport_del_riodev(struct mport_cdev_priv *priv, void __user *arg)
if (copy_from_user(&dev_info, arg, sizeof(dev_info)))
return -EFAULT;
+ dev_info.name[sizeof(dev_info.name) - 1] = '\0';
mport = priv->md->mport;
diff --git a/drivers/ras/cec.c b/drivers/ras/cec.c
index 673f8a128397..5d545806d930 100644
--- a/drivers/ras/cec.c
+++ b/drivers/ras/cec.c
@@ -1,4 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2017-2019 Borislav Petkov, SUSE Labs.
+ */
#include <linux/mm.h>
#include <linux/gfp.h>
#include <linux/kernel.h>
@@ -37,9 +40,9 @@
* thus emulate an an LRU-like behavior when deleting elements to free up space
* in the page.
*
- * When an element reaches it's max count of count_threshold, we try to poison
- * it by assuming that errors triggered count_threshold times in a single page
- * are excessive and that page shouldn't be used anymore. count_threshold is
+ * When an element reaches it's max count of action_threshold, we try to poison
+ * it by assuming that errors triggered action_threshold times in a single page
+ * are excessive and that page shouldn't be used anymore. action_threshold is
* initialized to COUNT_MASK which is the maximum.
*
* That error event entry causes cec_add_elem() to return !0 value and thus
@@ -122,7 +125,7 @@ static DEFINE_MUTEX(ce_mutex);
static u64 dfs_pfn;
/* Amount of errors after which we offline */
-static unsigned int count_threshold = COUNT_MASK;
+static u64 action_threshold = COUNT_MASK;
/* Each element "decays" each decay_interval which is 24hrs by default. */
#define CEC_DECAY_DEFAULT_INTERVAL 24 * 60 * 60 /* 24 hrs */
@@ -276,11 +279,39 @@ static u64 __maybe_unused del_lru_elem(void)
return pfn;
}
+static bool sanity_check(struct ce_array *ca)
+{
+ bool ret = false;
+ u64 prev = 0;
+ int i;
+
+ for (i = 0; i < ca->n; i++) {
+ u64 this = PFN(ca->array[i]);
+
+ if (WARN(prev > this, "prev: 0x%016llx <-> this: 0x%016llx\n", prev, this))
+ ret = true;
+
+ prev = this;
+ }
+
+ if (!ret)
+ return ret;
+
+ pr_info("Sanity check dump:\n{ n: %d\n", ca->n);
+ for (i = 0; i < ca->n; i++) {
+ u64 this = PFN(ca->array[i]);
+
+ pr_info(" %03d: [%016llx|%03llx]\n", i, this, FULL_COUNT(ca->array[i]));
+ }
+ pr_info("}\n");
+
+ return ret;
+}
int cec_add_elem(u64 pfn)
{
struct ce_array *ca = &ce_arr;
- unsigned int to;
+ unsigned int to = 0;
int count, ret = 0;
/*
@@ -294,6 +325,7 @@ int cec_add_elem(u64 pfn)
ca->ces_entered++;
+ /* Array full, free the LRU slot. */
if (ca->n == MAX_ELEMS)
WARN_ON(!del_lru_elem_unlocked(ca));
@@ -306,24 +338,17 @@ int cec_add_elem(u64 pfn)
(void *)&ca->array[to],
(ca->n - to) * sizeof(u64));
- ca->array[to] = (pfn << PAGE_SHIFT) |
- (DECAY_MASK << COUNT_BITS) | 1;
-
+ ca->array[to] = pfn << PAGE_SHIFT;
ca->n++;
-
- ret = 0;
-
- goto decay;
}
- count = COUNT(ca->array[to]);
-
- if (count < count_threshold) {
- ca->array[to] |= (DECAY_MASK << COUNT_BITS);
- ca->array[to]++;
+ /* Add/refresh element generation and increment count */
+ ca->array[to] |= DECAY_MASK << COUNT_BITS;
+ ca->array[to]++;
- ret = 0;
- } else {
+ /* Check action threshold and soft-offline, if reached. */
+ count = COUNT(ca->array[to]);
+ if (count >= action_threshold) {
u64 pfn = ca->array[to] >> PAGE_SHIFT;
if (!pfn_valid(pfn)) {
@@ -338,20 +363,21 @@ int cec_add_elem(u64 pfn)
del_elem(ca, to);
/*
- * Return a >0 value to denote that we've reached the offlining
- * threshold.
+ * Return a >0 value to callers, to denote that we've reached
+ * the offlining threshold.
*/
ret = 1;
goto unlock;
}
-decay:
ca->decay_count++;
if (ca->decay_count >= CLEAN_ELEMS)
do_spring_cleaning(ca);
+ WARN_ON_ONCE(sanity_check(ca));
+
unlock:
mutex_unlock(&ce_mutex);
@@ -369,45 +395,48 @@ static int pfn_set(void *data, u64 val)
{
*(u64 *)data = val;
- return cec_add_elem(val);
+ cec_add_elem(val);
+
+ return 0;
}
DEFINE_DEBUGFS_ATTRIBUTE(pfn_ops, u64_get, pfn_set, "0x%llx\n");
static int decay_interval_set(void *data, u64 val)
{
- *(u64 *)data = val;
-
if (val < CEC_DECAY_MIN_INTERVAL)
return -EINVAL;
if (val > CEC_DECAY_MAX_INTERVAL)
return -EINVAL;
+ *(u64 *)data = val;
decay_interval = val;
cec_mod_work(decay_interval);
+
return 0;
}
DEFINE_DEBUGFS_ATTRIBUTE(decay_interval_ops, u64_get, decay_interval_set, "%lld\n");
-static int count_threshold_set(void *data, u64 val)
+static int action_threshold_set(void *data, u64 val)
{
*(u64 *)data = val;
if (val > COUNT_MASK)
val = COUNT_MASK;
- count_threshold = val;
+ action_threshold = val;
return 0;
}
-DEFINE_DEBUGFS_ATTRIBUTE(count_threshold_ops, u64_get, count_threshold_set, "%lld\n");
+DEFINE_DEBUGFS_ATTRIBUTE(action_threshold_ops, u64_get, action_threshold_set, "%lld\n");
+
+static const char * const bins[] = { "00", "01", "10", "11" };
static int array_dump(struct seq_file *m, void *v)
{
struct ce_array *ca = &ce_arr;
- u64 prev = 0;
int i;
mutex_lock(&ce_mutex);
@@ -416,11 +445,8 @@ static int array_dump(struct seq_file *m, void *v)
for (i = 0; i < ca->n; i++) {
u64 this = PFN(ca->array[i]);
- seq_printf(m, " %03d: [%016llx|%03llx]\n", i, this, FULL_COUNT(ca->array[i]));
-
- WARN_ON(prev > this);
-
- prev = this;
+ seq_printf(m, " %3d: [%016llx|%s|%03llx]\n",
+ i, this, bins[DECAY(ca->array[i])], COUNT(ca->array[i]));
}
seq_printf(m, "}\n");
@@ -433,7 +459,7 @@ static int array_dump(struct seq_file *m, void *v)
seq_printf(m, "Decay interval: %lld seconds\n", decay_interval);
seq_printf(m, "Decays: %lld\n", ca->decays_done);
- seq_printf(m, "Action threshold: %d\n", count_threshold);
+ seq_printf(m, "Action threshold: %lld\n", action_threshold);
mutex_unlock(&ce_mutex);
@@ -463,18 +489,6 @@ static int __init create_debugfs_nodes(void)
return -1;
}
- pfn = debugfs_create_file("pfn", S_IRUSR | S_IWUSR, d, &dfs_pfn, &pfn_ops);
- if (!pfn) {
- pr_warn("Error creating pfn debugfs node!\n");
- goto err;
- }
-
- array = debugfs_create_file("array", S_IRUSR, d, NULL, &array_ops);
- if (!array) {
- pr_warn("Error creating array debugfs node!\n");
- goto err;
- }
-
decay = debugfs_create_file("decay_interval", S_IRUSR | S_IWUSR, d,
&decay_interval, &decay_interval_ops);
if (!decay) {
@@ -482,13 +496,27 @@ static int __init create_debugfs_nodes(void)
goto err;
}
- count = debugfs_create_file("count_threshold", S_IRUSR | S_IWUSR, d,
- &count_threshold, &count_threshold_ops);
+ count = debugfs_create_file("action_threshold", S_IRUSR | S_IWUSR, d,
+ &action_threshold, &action_threshold_ops);
if (!count) {
- pr_warn("Error creating count_threshold debugfs node!\n");
+ pr_warn("Error creating action_threshold debugfs node!\n");
+ goto err;
+ }
+
+ if (!IS_ENABLED(CONFIG_RAS_CEC_DEBUG))
+ return 0;
+
+ pfn = debugfs_create_file("pfn", S_IRUSR | S_IWUSR, d, &dfs_pfn, &pfn_ops);
+ if (!pfn) {
+ pr_warn("Error creating pfn debugfs node!\n");
goto err;
}
+ array = debugfs_create_file("array", S_IRUSR, d, NULL, &array_ops);
+ if (!array) {
+ pr_warn("Error creating array debugfs node!\n");
+ goto err;
+ }
return 0;
@@ -509,8 +537,10 @@ void __init cec_init(void)
return;
}
- if (create_debugfs_nodes())
+ if (create_debugfs_nodes()) {
+ free_page((unsigned long)ce_arr.array);
return;
+ }
INIT_DELAYED_WORK(&cec_work, cec_work_fn);
schedule_delayed_work(&cec_work, CEC_DECAY_DEFAULT_INTERVAL);
diff --git a/drivers/regulator/88pm800.c b/drivers/regulator/88pm800-regulator.c
index 9fd379732d18..69ae25886181 100644
--- a/drivers/regulator/88pm800.c
+++ b/drivers/regulator/88pm800-regulator.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Regulators driver for Marvell 88PM800
*
* Copyright (C) 2012 Marvell International Ltd.
* Joseph(Yossi) Hanin <yhanin@marvell.com>
* Yi Zhang <yizhang@marvell.com>
- *
- * 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.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c
index 35d767aeeb57..1d1c4a7ec3e2 100644
--- a/drivers/regulator/88pm8607.c
+++ b/drivers/regulator/88pm8607.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Regulators driver for Marvell 88PM8607
*
* Copyright (C) 2009 Marvell International Ltd.
* Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- * 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.
*/
#include <linux/kernel.h>
#include <linux/init.h>
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 8553bdf87c1d..b57093d7c01f 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -136,19 +136,20 @@ config REGULATOR_AB8500
signal AB8500 PMIC
config REGULATOR_ARIZONA_LDO1
- tristate "Wolfson Arizona class devices LDO1"
- depends on MFD_ARIZONA
+ tristate "Cirrus Madera and Wolfson Arizona class devices LDO1"
+ depends on MFD_ARIZONA || MFD_MADERA
depends on SND_SOC
help
- Support for the LDO1 regulators found on Wolfson Arizona class
- devices.
+ Support for the LDO1 regulators found on Cirrus Logic Madera codecs
+ and Wolfson Microelectronic Arizona codecs.
config REGULATOR_ARIZONA_MICSUPP
- tristate "Wolfson Arizona class devices MICSUPP"
- depends on MFD_ARIZONA
+ tristate "Cirrus Madera and Wolfson Arizona class devices MICSUPP"
+ depends on MFD_ARIZONA || MFD_MADERA
depends on SND_SOC
help
- Support for the MICSUPP regulators found on Wolfson Arizona class
+ Support for the MICSUPP regulators found on Cirrus Logic Madera codecs
+ and Wolfson Microelectronic Arizona codecs
devices.
config REGULATOR_AS3711
@@ -258,7 +259,7 @@ config REGULATOR_DA9062
config REGULATOR_DA9063
tristate "Dialog Semiconductor DA9063 regulators"
- depends on MFD_DA9063
+ depends on MFD_DA9063 && OF
help
Say y here to support the BUCKs and LDOs regulators found on
DA9063 PMICs.
@@ -364,7 +365,7 @@ config REGULATOR_LM363X
tristate "TI LM363X voltage regulators"
depends on MFD_TI_LMU
help
- This driver supports LM3631 and LM3632 voltage regulators for
+ This driver supports LM3631, LM3632 and LM36274 voltage regulators for
the LCD bias.
One boost output voltage is configurable and always on.
Other LDOs are used for the display module.
@@ -763,11 +764,11 @@ config REGULATOR_RC5T583
outputs which can be controlled by i2c communication.
config REGULATOR_RK808
- tristate "Rockchip RK805/RK808/RK818 Power regulators"
+ tristate "Rockchip RK805/RK808/RK809/RK817/RK818 Power regulators"
depends on MFD_RK808
help
Select this option to enable the power regulator of ROCKCHIP
- PMIC RK805,RK808 and RK818.
+ PMIC RK805,RK809&RK817,RK808 and RK818.
This driver supports the control of different power rails of device
through regulator interface. The device supports multiple DCDC/LDO
outputs which can be controlled by i2c communication.
@@ -829,6 +830,26 @@ config REGULATOR_SKY81452
This driver can also be built as a module. If so, the module
will be called sky81452-regulator.
+config REGULATOR_SLG51000
+ tristate "Dialog Semiconductor SLG51000 regulators"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Say y here to support for the Dialog Semiconductor SLG51000.
+ The SLG51000 is seven compact and customizable low dropout
+ regulators.
+
+config REGULATOR_STM32_BOOSTER
+ tristate "STMicroelectronics STM32 BOOSTER"
+ depends on ARCH_STM32 || COMPILE_TEST
+ help
+ This driver supports internal booster (3V3) embedded in some
+ STMicroelectronics STM32 chips. It can be used to supply ADC analog
+ input switches when vdda supply is below 2.7V.
+
+ This driver can also be built as a module. If so, the module
+ will be called stm32-booster.
+
config REGULATOR_STM32_VREFBUF
tristate "STMicroelectronics STM32 VREFBUF"
depends on ARCH_STM32 || COMPILE_TEST
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 93f53840e8f1..eef73b5a35a4 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -11,7 +11,7 @@ obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o
obj-$(CONFIG_REGULATOR_88PG86X) += 88pg86x.o
-obj-$(CONFIG_REGULATOR_88PM800) += 88pm800.o
+obj-$(CONFIG_REGULATOR_88PM800) += 88pm800-regulator.o
obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o
obj-$(CONFIG_REGULATOR_CPCAP) += cpcap-regulator.o
obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o
@@ -104,6 +104,8 @@ obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
obj-$(CONFIG_REGULATOR_SC2731) += sc2731-regulator.o
obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o
+obj-$(CONFIG_REGULATOR_SLG51000) += slg51000-regulator.o
+obj-$(CONFIG_REGULATOR_STM32_BOOSTER) += stm32-booster.o
obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
obj-$(CONFIG_REGULATOR_STM32_PWR) += stm32-pwr.o
obj-$(CONFIG_REGULATOR_STPMIC1) += stpmic1_regulator.o
diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c
index e4bc7b1e5ccd..1a3d7b720f5e 100644
--- a/drivers/regulator/arizona-ldo1.c
+++ b/drivers/regulator/arizona-ldo1.c
@@ -25,6 +25,10 @@
#include <linux/mfd/arizona/pdata.h>
#include <linux/mfd/arizona/registers.h>
+#include <linux/mfd/madera/core.h>
+#include <linux/mfd/madera/pdata.h>
+#include <linux/mfd/madera/registers.h>
+
struct arizona_ldo1 {
struct regulator_dev *regulator;
struct regmap *regmap;
@@ -158,6 +162,31 @@ static const struct regulator_init_data arizona_ldo1_wm5110 = {
.num_consumer_supplies = 1,
};
+static const struct regulator_desc madera_ldo1 = {
+ .name = "LDO1",
+ .supply_name = "LDOVDD",
+ .type = REGULATOR_VOLTAGE,
+ .ops = &arizona_ldo1_ops,
+
+ .vsel_reg = MADERA_LDO1_CONTROL_1,
+ .vsel_mask = MADERA_LDO1_VSEL_MASK,
+ .min_uV = 900000,
+ .uV_step = 25000,
+ .n_voltages = 13,
+ .enable_time = 3000,
+
+ .owner = THIS_MODULE,
+};
+
+static const struct regulator_init_data madera_ldo1_default = {
+ .constraints = {
+ .min_uV = 1200000,
+ .max_uV = 1200000,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+};
+
static int arizona_ldo1_of_get_pdata(struct arizona_ldo1_pdata *pdata,
struct regulator_config *config,
const struct regulator_desc *desc,
@@ -320,6 +349,32 @@ static int arizona_ldo1_remove(struct platform_device *pdev)
return 0;
}
+static int madera_ldo1_probe(struct platform_device *pdev)
+{
+ struct madera *madera = dev_get_drvdata(pdev->dev.parent);
+ struct arizona_ldo1 *ldo1;
+ bool external_dcvdd;
+ int ret;
+
+ ldo1 = devm_kzalloc(&pdev->dev, sizeof(*ldo1), GFP_KERNEL);
+ if (!ldo1)
+ return -ENOMEM;
+
+ ldo1->regmap = madera->regmap;
+
+ ldo1->init_data = madera_ldo1_default;
+
+ ret = arizona_ldo1_common_init(pdev, ldo1, &madera_ldo1,
+ &madera->pdata.ldo1,
+ &external_dcvdd);
+ if (ret)
+ return ret;
+
+ madera->internal_dcvdd = !external_dcvdd;
+
+ return 0;
+}
+
static struct platform_driver arizona_ldo1_driver = {
.probe = arizona_ldo1_probe,
.remove = arizona_ldo1_remove,
@@ -328,10 +383,36 @@ static struct platform_driver arizona_ldo1_driver = {
},
};
-module_platform_driver(arizona_ldo1_driver);
+static struct platform_driver madera_ldo1_driver = {
+ .probe = madera_ldo1_probe,
+ .remove = arizona_ldo1_remove,
+ .driver = {
+ .name = "madera-ldo1",
+ },
+};
+
+static struct platform_driver * const madera_ldo1_drivers[] = {
+ &arizona_ldo1_driver,
+ &madera_ldo1_driver,
+};
+
+static int __init arizona_ldo1_init(void)
+{
+ return platform_register_drivers(madera_ldo1_drivers,
+ ARRAY_SIZE(madera_ldo1_drivers));
+}
+module_init(arizona_ldo1_init);
+
+static void __exit madera_ldo1_exit(void)
+{
+ platform_unregister_drivers(madera_ldo1_drivers,
+ ARRAY_SIZE(madera_ldo1_drivers));
+}
+module_exit(madera_ldo1_exit);
/* Module information */
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_DESCRIPTION("Arizona LDO1 driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:arizona-ldo1");
+MODULE_ALIAS("platform:madera-ldo1");
diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c
index be0d46da51a1..ae1a5de3e57d 100644
--- a/drivers/regulator/arizona-micsupp.c
+++ b/drivers/regulator/arizona-micsupp.c
@@ -16,7 +16,6 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
-#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <sound/soc.h>
@@ -25,6 +24,10 @@
#include <linux/mfd/arizona/pdata.h>
#include <linux/mfd/arizona/registers.h>
+#include <linux/mfd/madera/core.h>
+#include <linux/mfd/madera/pdata.h>
+#include <linux/mfd/madera/registers.h>
+
#include <linux/regulator/arizona-micsupp.h>
struct arizona_micsupp {
@@ -200,6 +203,28 @@ static const struct regulator_init_data arizona_micsupp_ext_default = {
.num_consumer_supplies = 1,
};
+static const struct regulator_desc madera_micsupp = {
+ .name = "MICVDD",
+ .supply_name = "CPVDD1",
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = 40,
+ .ops = &arizona_micsupp_ops,
+
+ .vsel_reg = MADERA_LDO2_CONTROL_1,
+ .vsel_mask = MADERA_LDO2_VSEL_MASK,
+ .enable_reg = MADERA_MIC_CHARGE_PUMP_1,
+ .enable_mask = MADERA_CPMIC_ENA,
+ .bypass_reg = MADERA_MIC_CHARGE_PUMP_1,
+ .bypass_mask = MADERA_CPMIC_BYPASS,
+
+ .linear_ranges = arizona_micsupp_ext_ranges,
+ .n_linear_ranges = ARRAY_SIZE(arizona_micsupp_ext_ranges),
+
+ .enable_time = 3000,
+
+ .owner = THIS_MODULE,
+};
+
static int arizona_micsupp_of_get_pdata(struct arizona_micsupp_pdata *pdata,
struct regulator_config *config,
const struct regulator_desc *desc)
@@ -316,6 +341,24 @@ static int arizona_micsupp_probe(struct platform_device *pdev)
&arizona->pdata.micvdd);
}
+static int madera_micsupp_probe(struct platform_device *pdev)
+{
+ struct madera *madera = dev_get_drvdata(pdev->dev.parent);
+ struct arizona_micsupp *micsupp;
+
+ micsupp = devm_kzalloc(&pdev->dev, sizeof(*micsupp), GFP_KERNEL);
+ if (!micsupp)
+ return -ENOMEM;
+
+ micsupp->regmap = madera->regmap;
+ micsupp->dapm = &madera->dapm;
+ micsupp->dev = madera->dev;
+ micsupp->init_data = arizona_micsupp_ext_default;
+
+ return arizona_micsupp_common_init(pdev, micsupp, &madera_micsupp,
+ &madera->pdata.micvdd);
+}
+
static struct platform_driver arizona_micsupp_driver = {
.probe = arizona_micsupp_probe,
.driver = {
@@ -323,10 +366,35 @@ static struct platform_driver arizona_micsupp_driver = {
},
};
-module_platform_driver(arizona_micsupp_driver);
+static struct platform_driver madera_micsupp_driver = {
+ .probe = madera_micsupp_probe,
+ .driver = {
+ .name = "madera-micsupp",
+ },
+};
+
+static struct platform_driver * const arizona_micsupp_drivers[] = {
+ &arizona_micsupp_driver,
+ &madera_micsupp_driver,
+};
+
+static int __init arizona_micsupp_init(void)
+{
+ return platform_register_drivers(arizona_micsupp_drivers,
+ ARRAY_SIZE(arizona_micsupp_drivers));
+}
+module_init(arizona_micsupp_init);
+
+static void __exit arizona_micsupp_exit(void)
+{
+ platform_unregister_drivers(arizona_micsupp_drivers,
+ ARRAY_SIZE(arizona_micsupp_drivers));
+}
+module_exit(arizona_micsupp_exit);
/* Module information */
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_DESCRIPTION("Arizona microphone supply driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:arizona-micsupp");
+MODULE_ALIAS("platform:madera-micsupp");
diff --git a/drivers/regulator/bd70528-regulator.c b/drivers/regulator/bd70528-regulator.c
index 30e3ed430a8a..0248a61f1006 100644
--- a/drivers/regulator/bd70528-regulator.c
+++ b/drivers/regulator/bd70528-regulator.c
@@ -4,7 +4,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-bd70528.h>
diff --git a/drivers/regulator/bd718x7-regulator.c b/drivers/regulator/bd718x7-regulator.c
index fde4264da6ff..bdab46a5c461 100644
--- a/drivers/regulator/bd718x7-regulator.c
+++ b/drivers/regulator/bd718x7-regulator.c
@@ -4,7 +4,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-bd718x7.h>
@@ -1152,12 +1151,12 @@ static int bd718xx_probe(struct platform_device *pdev)
{
struct bd718xx *mfd;
struct regulator_config config = { 0 };
- struct bd718xx_pmic_inits pmic_regulators[] = {
- [BD718XX_TYPE_BD71837] = {
+ struct bd718xx_pmic_inits pmic_regulators[ROHM_CHIP_TYPE_AMOUNT] = {
+ [ROHM_CHIP_TYPE_BD71837] = {
.r_datas = bd71837_regulators,
.r_amount = ARRAY_SIZE(bd71837_regulators),
},
- [BD718XX_TYPE_BD71847] = {
+ [ROHM_CHIP_TYPE_BD71847] = {
.r_datas = bd71847_regulators,
.r_amount = ARRAY_SIZE(bd71847_regulators),
},
@@ -1173,15 +1172,15 @@ static int bd718xx_probe(struct platform_device *pdev)
goto err;
}
- if (mfd->chip_type >= BD718XX_TYPE_AMOUNT ||
- !pmic_regulators[mfd->chip_type].r_datas) {
+ if (mfd->chip.chip_type >= ROHM_CHIP_TYPE_AMOUNT ||
+ !pmic_regulators[mfd->chip.chip_type].r_datas) {
dev_err(&pdev->dev, "Unsupported chip type\n");
err = -EINVAL;
goto err;
}
/* Register LOCK release */
- err = regmap_update_bits(mfd->regmap, BD718XX_REG_REGLOCK,
+ err = regmap_update_bits(mfd->chip.regmap, BD718XX_REG_REGLOCK,
(REGLOCK_PWRSEQ | REGLOCK_VREG), 0);
if (err) {
dev_err(&pdev->dev, "Failed to unlock PMIC (%d)\n", err);
@@ -1200,7 +1199,8 @@ static int bd718xx_probe(struct platform_device *pdev)
* bit allowing HW defaults for power rails to be used
*/
if (!use_snvs) {
- err = regmap_update_bits(mfd->regmap, BD718XX_REG_TRANS_COND1,
+ err = regmap_update_bits(mfd->chip.regmap,
+ BD718XX_REG_TRANS_COND1,
BD718XX_ON_REQ_POWEROFF_MASK |
BD718XX_SWRESET_POWEROFF_MASK |
BD718XX_WDOG_POWEROFF_MASK |
@@ -1215,17 +1215,17 @@ static int bd718xx_probe(struct platform_device *pdev)
}
}
- for (i = 0; i < pmic_regulators[mfd->chip_type].r_amount; i++) {
+ for (i = 0; i < pmic_regulators[mfd->chip.chip_type].r_amount; i++) {
const struct regulator_desc *desc;
struct regulator_dev *rdev;
const struct bd718xx_regulator_data *r;
- r = &pmic_regulators[mfd->chip_type].r_datas[i];
+ r = &pmic_regulators[mfd->chip.chip_type].r_datas[i];
desc = &r->desc;
config.dev = pdev->dev.parent;
- config.regmap = mfd->regmap;
+ config.regmap = mfd->chip.regmap;
rdev = devm_regulator_register(&pdev->dev, desc, &config);
if (IS_ERR(rdev)) {
@@ -1254,7 +1254,7 @@ static int bd718xx_probe(struct platform_device *pdev)
*/
if (!use_snvs || !rdev->constraints->always_on ||
!rdev->constraints->boot_on) {
- err = regmap_update_bits(mfd->regmap, r->init.reg,
+ err = regmap_update_bits(mfd->chip.regmap, r->init.reg,
r->init.mask, r->init.val);
if (err) {
dev_err(&pdev->dev,
@@ -1264,7 +1264,7 @@ static int bd718xx_probe(struct platform_device *pdev)
}
}
for (j = 0; j < r->additional_init_amnt; j++) {
- err = regmap_update_bits(mfd->regmap,
+ err = regmap_update_bits(mfd->chip.regmap,
r->additional_inits[j].reg,
r->additional_inits[j].mask,
r->additional_inits[j].val);
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index c894cf0d8a28..e0c0cf462004 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1,12 +1,11 @@
// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * core.c -- Voltage/Current Regulator framework.
- *
- * Copyright 2007, 2008 Wolfson Microelectronics PLC.
- * Copyright 2008 SlimLogic Ltd.
- *
- * Author: Liam Girdwood <lrg@slimlogic.co.uk>
- */
+//
+// core.c -- Voltage/Current Regulator framework.
+//
+// Copyright 2007, 2008 Wolfson Microelectronics PLC.
+// Copyright 2008 SlimLogic Ltd.
+//
+// Author: Liam Girdwood <lrg@slimlogic.co.uk>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -23,6 +22,7 @@
#include <linux/regmap.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/consumer.h>
+#include <linux/regulator/coupler.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/module.h>
@@ -50,6 +50,7 @@ static DEFINE_MUTEX(regulator_list_mutex);
static LIST_HEAD(regulator_map_list);
static LIST_HEAD(regulator_ena_gpio_list);
static LIST_HEAD(regulator_supply_alias_list);
+static LIST_HEAD(regulator_coupler_list);
static bool has_full_constraints;
static struct dentry *debugfs_root;
@@ -93,7 +94,6 @@ struct regulator_supply_alias {
static int _regulator_is_enabled(struct regulator_dev *rdev);
static int _regulator_disable(struct regulator *regulator);
-static int _regulator_get_voltage(struct regulator_dev *rdev);
static int _regulator_get_current_limit(struct regulator_dev *rdev);
static unsigned int _regulator_get_mode(struct regulator_dev *rdev);
static int _notifier_call_chain(struct regulator_dev *rdev,
@@ -102,15 +102,12 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV);
static int regulator_balance_voltage(struct regulator_dev *rdev,
suspend_state_t state);
-static int regulator_set_voltage_rdev(struct regulator_dev *rdev,
- int min_uV, int max_uV,
- suspend_state_t state);
static struct regulator *create_regulator(struct regulator_dev *rdev,
struct device *dev,
const char *supply_name);
static void _regulator_put(struct regulator *regulator);
-static const char *rdev_get_name(struct regulator_dev *rdev)
+const char *rdev_get_name(struct regulator_dev *rdev)
{
if (rdev->constraints && rdev->constraints->name)
return rdev->constraints->name;
@@ -424,8 +421,8 @@ static struct device_node *of_get_regulator(struct device *dev, const char *supp
}
/* Platform voltage constraint check */
-static int regulator_check_voltage(struct regulator_dev *rdev,
- int *min_uV, int *max_uV)
+int regulator_check_voltage(struct regulator_dev *rdev,
+ int *min_uV, int *max_uV)
{
BUG_ON(*min_uV > *max_uV);
@@ -457,9 +454,9 @@ static int regulator_check_states(suspend_state_t state)
/* Make sure we select a voltage that suits the needs of all
* regulator consumers
*/
-static int regulator_check_consumers(struct regulator_dev *rdev,
- int *min_uV, int *max_uV,
- suspend_state_t state)
+int regulator_check_consumers(struct regulator_dev *rdev,
+ int *min_uV, int *max_uV,
+ suspend_state_t state)
{
struct regulator *regulator;
struct regulator_voltage *voltage;
@@ -570,7 +567,7 @@ static ssize_t regulator_uV_show(struct device *dev,
ssize_t ret;
regulator_lock(rdev);
- ret = sprintf(buf, "%d\n", _regulator_get_voltage(rdev));
+ ret = sprintf(buf, "%d\n", regulator_get_voltage_rdev(rdev));
regulator_unlock(rdev);
return ret;
@@ -941,7 +938,7 @@ static int drms_uA_update(struct regulator_dev *rdev)
rdev_err(rdev, "failed to set load %d\n", current_uA);
} else {
/* get output voltage */
- output_uV = _regulator_get_voltage(rdev);
+ output_uV = regulator_get_voltage_rdev(rdev);
if (output_uV <= 0) {
rdev_err(rdev, "invalid output voltage found\n");
return -EINVAL;
@@ -1054,7 +1051,7 @@ static void print_constraints(struct regulator_dev *rdev)
if (!constraints->min_uV ||
constraints->min_uV != constraints->max_uV) {
- ret = _regulator_get_voltage(rdev);
+ ret = regulator_get_voltage_rdev(rdev);
if (ret > 0)
count += scnprintf(buf + count, len - count,
"at %d mV ", ret / 1000);
@@ -1113,7 +1110,7 @@ static int machine_constraints_voltage(struct regulator_dev *rdev,
if (rdev->constraints->apply_uV &&
rdev->constraints->min_uV && rdev->constraints->max_uV) {
int target_min, target_max;
- int current_uV = _regulator_get_voltage(rdev);
+ int current_uV = regulator_get_voltage_rdev(rdev);
if (current_uV == -ENOTRECOVERABLE) {
/* This regulator can't be read and must be initialized */
@@ -1123,7 +1120,7 @@ static int machine_constraints_voltage(struct regulator_dev *rdev,
_regulator_do_set_voltage(rdev,
rdev->constraints->min_uV,
rdev->constraints->max_uV);
- current_uV = _regulator_get_voltage(rdev);
+ current_uV = regulator_get_voltage_rdev(rdev);
}
if (current_uV < 0) {
@@ -1645,9 +1642,9 @@ static int _regulator_get_enable_time(struct regulator_dev *rdev)
{
if (rdev->constraints && rdev->constraints->enable_time)
return rdev->constraints->enable_time;
- if (!rdev->desc->ops->enable_time)
- return rdev->desc->enable_time;
- return rdev->desc->ops->enable_time(rdev);
+ if (rdev->desc->ops->enable_time)
+ return rdev->desc->ops->enable_time(rdev);
+ return rdev->desc->enable_time;
}
static struct regulator_supply_alias *regulator_find_supply_alias(
@@ -2304,7 +2301,7 @@ static int regulator_ena_gpio_ctrl(struct regulator_dev *rdev, bool enable)
*
* Delay for the requested amount of time as per the guidelines in:
*
- * Documentation/timers/timers-howto.txt
+ * Documentation/timers/timers-howto.rst
*
* The assumption here is that regulators will never be enabled in
* atomic context and therefore sleeping functions can be used.
@@ -3065,7 +3062,7 @@ static int _regulator_call_set_voltage(struct regulator_dev *rdev,
struct pre_voltage_change_data data;
int ret;
- data.old_uV = _regulator_get_voltage(rdev);
+ data.old_uV = regulator_get_voltage_rdev(rdev);
data.min_uV = min_uV;
data.max_uV = max_uV;
ret = _notifier_call_chain(rdev, REGULATOR_EVENT_PRE_VOLTAGE_CHANGE,
@@ -3089,7 +3086,7 @@ static int _regulator_call_set_voltage_sel(struct regulator_dev *rdev,
struct pre_voltage_change_data data;
int ret;
- data.old_uV = _regulator_get_voltage(rdev);
+ data.old_uV = regulator_get_voltage_rdev(rdev);
data.min_uV = uV;
data.max_uV = uV;
ret = _notifier_call_chain(rdev, REGULATOR_EVENT_PRE_VOLTAGE_CHANGE,
@@ -3107,6 +3104,66 @@ static int _regulator_call_set_voltage_sel(struct regulator_dev *rdev,
return ret;
}
+static int _regulator_set_voltage_sel_step(struct regulator_dev *rdev,
+ int uV, int new_selector)
+{
+ const struct regulator_ops *ops = rdev->desc->ops;
+ int diff, old_sel, curr_sel, ret;
+
+ /* Stepping is only needed if the regulator is enabled. */
+ if (!_regulator_is_enabled(rdev))
+ goto final_set;
+
+ if (!ops->get_voltage_sel)
+ return -EINVAL;
+
+ old_sel = ops->get_voltage_sel(rdev);
+ if (old_sel < 0)
+ return old_sel;
+
+ diff = new_selector - old_sel;
+ if (diff == 0)
+ return 0; /* No change needed. */
+
+ if (diff > 0) {
+ /* Stepping up. */
+ for (curr_sel = old_sel + rdev->desc->vsel_step;
+ curr_sel < new_selector;
+ curr_sel += rdev->desc->vsel_step) {
+ /*
+ * Call the callback directly instead of using
+ * _regulator_call_set_voltage_sel() as we don't
+ * want to notify anyone yet. Same in the branch
+ * below.
+ */
+ ret = ops->set_voltage_sel(rdev, curr_sel);
+ if (ret)
+ goto try_revert;
+ }
+ } else {
+ /* Stepping down. */
+ for (curr_sel = old_sel - rdev->desc->vsel_step;
+ curr_sel > new_selector;
+ curr_sel -= rdev->desc->vsel_step) {
+ ret = ops->set_voltage_sel(rdev, curr_sel);
+ if (ret)
+ goto try_revert;
+ }
+ }
+
+final_set:
+ /* The final selector will trigger the notifiers. */
+ return _regulator_call_set_voltage_sel(rdev, uV, new_selector);
+
+try_revert:
+ /*
+ * At least try to return to the previous voltage if setting a new
+ * one failed.
+ */
+ (void)ops->set_voltage_sel(rdev, old_sel);
+ return ret;
+}
+
static int _regulator_set_voltage_time(struct regulator_dev *rdev,
int old_uV, int new_uV)
{
@@ -3142,7 +3199,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
unsigned int selector;
int old_selector = -1;
const struct regulator_ops *ops = rdev->desc->ops;
- int old_uV = _regulator_get_voltage(rdev);
+ int old_uV = regulator_get_voltage_rdev(rdev);
trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV);
@@ -3169,7 +3226,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
best_val = ops->list_voltage(rdev,
selector);
else
- best_val = _regulator_get_voltage(rdev);
+ best_val = regulator_get_voltage_rdev(rdev);
}
} else if (ops->set_voltage_sel) {
@@ -3180,6 +3237,9 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
selector = ret;
if (old_selector == selector)
ret = 0;
+ else if (rdev->desc->vsel_step)
+ ret = _regulator_set_voltage_sel_step(
+ rdev, best_val, selector);
else
ret = _regulator_call_set_voltage_sel(
rdev, best_val, selector);
@@ -3288,7 +3348,7 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
* changing the voltage.
*/
if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) {
- current_uV = _regulator_get_voltage(rdev);
+ current_uV = regulator_get_voltage_rdev(rdev);
if (min_uV <= current_uV && current_uV <= max_uV) {
voltage->min_uV = min_uV;
voltage->max_uV = max_uV;
@@ -3325,8 +3385,8 @@ out:
return ret;
}
-static int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV,
- int max_uV, suspend_state_t state)
+int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV,
+ int max_uV, suspend_state_t state)
{
int best_supply_uV = 0;
int supply_change_uV = 0;
@@ -3354,7 +3414,7 @@ static int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV,
best_supply_uV += rdev->desc->min_dropout_uV;
- current_supply_uV = _regulator_get_voltage(rdev->supply->rdev);
+ current_supply_uV = regulator_get_voltage_rdev(rdev->supply->rdev);
if (current_supply_uV < 0) {
ret = current_supply_uV;
goto out;
@@ -3405,7 +3465,7 @@ static int regulator_limit_voltage_step(struct regulator_dev *rdev,
return 1;
if (*current_uV < 0) {
- *current_uV = _regulator_get_voltage(rdev);
+ *current_uV = regulator_get_voltage_rdev(rdev);
if (*current_uV < 0)
return *current_uV;
@@ -3434,11 +3494,10 @@ static int regulator_get_optimal_voltage(struct regulator_dev *rdev,
struct coupling_desc *c_desc = &rdev->coupling_desc;
struct regulator_dev **c_rdevs = c_desc->coupled_rdevs;
struct regulation_constraints *constraints = rdev->constraints;
- int max_spread = constraints->max_spread;
int desired_min_uV = 0, desired_max_uV = INT_MAX;
int max_current_uV = 0, min_current_uV = INT_MAX;
int highest_min_uV = 0, target_uV, possible_uV;
- int i, ret;
+ int i, ret, max_spread;
bool done;
*current_uV = -1;
@@ -3492,6 +3551,8 @@ static int regulator_get_optimal_voltage(struct regulator_dev *rdev,
}
}
+ max_spread = constraints->max_spread[0];
+
/*
* Let target_uV be equal to the desired one if possible.
* If not, set it to minimum voltage, allowed by other coupled
@@ -3509,7 +3570,7 @@ static int regulator_get_optimal_voltage(struct regulator_dev *rdev,
if (!_regulator_is_enabled(c_rdevs[i]))
continue;
- tmp_act = _regulator_get_voltage(c_rdevs[i]);
+ tmp_act = regulator_get_voltage_rdev(c_rdevs[i]);
if (tmp_act < 0)
return tmp_act;
@@ -3551,7 +3612,7 @@ finish:
if (n_coupled > 1 && *current_uV == -1) {
if (_regulator_is_enabled(rdev)) {
- ret = _regulator_get_voltage(rdev);
+ ret = regulator_get_voltage_rdev(rdev);
if (ret < 0)
return ret;
@@ -3573,9 +3634,11 @@ static int regulator_balance_voltage(struct regulator_dev *rdev,
struct regulator_dev **c_rdevs;
struct regulator_dev *best_rdev;
struct coupling_desc *c_desc = &rdev->coupling_desc;
+ struct regulator_coupler *coupler = c_desc->coupler;
int i, ret, n_coupled, best_min_uV, best_max_uV, best_c_rdev;
- bool best_c_rdev_done, c_rdev_done[MAX_COUPLED];
unsigned int delta, best_delta;
+ unsigned long c_rdev_done = 0;
+ bool best_c_rdev_done;
c_rdevs = c_desc->coupled_rdevs;
n_coupled = c_desc->n_coupled;
@@ -3592,8 +3655,9 @@ static int regulator_balance_voltage(struct regulator_dev *rdev,
return -EPERM;
}
- for (i = 0; i < n_coupled; i++)
- c_rdev_done[i] = false;
+ /* Invoke custom balancer for customized couplers */
+ if (coupler && coupler->balance_voltage)
+ return coupler->balance_voltage(coupler, rdev, state);
/*
* Find the best possible voltage change on each loop. Leave the loop
@@ -3620,7 +3684,7 @@ static int regulator_balance_voltage(struct regulator_dev *rdev,
*/
int optimal_uV = 0, optimal_max_uV = 0, current_uV = 0;
- if (c_rdev_done[i])
+ if (test_bit(i, &c_rdev_done))
continue;
ret = regulator_get_optimal_voltage(c_rdevs[i],
@@ -3655,7 +3719,8 @@ static int regulator_balance_voltage(struct regulator_dev *rdev,
if (ret < 0)
goto out;
- c_rdev_done[best_c_rdev] = best_c_rdev_done;
+ if (best_c_rdev_done)
+ set_bit(best_c_rdev, &c_rdev_done);
} while (n_coupled > 1);
@@ -3911,7 +3976,7 @@ out:
}
EXPORT_SYMBOL_GPL(regulator_sync_voltage);
-static int _regulator_get_voltage(struct regulator_dev *rdev)
+int regulator_get_voltage_rdev(struct regulator_dev *rdev)
{
int sel, ret;
bool bypassed;
@@ -3928,7 +3993,7 @@ static int _regulator_get_voltage(struct regulator_dev *rdev)
return -EPROBE_DEFER;
}
- return _regulator_get_voltage(rdev->supply->rdev);
+ return regulator_get_voltage_rdev(rdev->supply->rdev);
}
}
@@ -3944,7 +4009,7 @@ static int _regulator_get_voltage(struct regulator_dev *rdev)
} else if (rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1)) {
ret = rdev->desc->fixed_uV;
} else if (rdev->supply) {
- ret = _regulator_get_voltage(rdev->supply->rdev);
+ ret = regulator_get_voltage_rdev(rdev->supply->rdev);
} else {
return -EINVAL;
}
@@ -3969,7 +4034,7 @@ int regulator_get_voltage(struct regulator *regulator)
int ret;
regulator_lock_dependent(regulator->rdev, &ww_ctx);
- ret = _regulator_get_voltage(regulator->rdev);
+ ret = regulator_get_voltage_rdev(regulator->rdev);
regulator_unlock_dependent(regulator->rdev, &ww_ctx);
return ret;
@@ -4707,8 +4772,60 @@ static int regulator_register_resolve_supply(struct device *dev, void *data)
return 0;
}
+int regulator_coupler_register(struct regulator_coupler *coupler)
+{
+ mutex_lock(&regulator_list_mutex);
+ list_add_tail(&coupler->list, &regulator_coupler_list);
+ mutex_unlock(&regulator_list_mutex);
+
+ return 0;
+}
+
+static struct regulator_coupler *
+regulator_find_coupler(struct regulator_dev *rdev)
+{
+ struct regulator_coupler *coupler;
+ int err;
+
+ /*
+ * Note that regulators are appended to the list and the generic
+ * coupler is registered first, hence it will be attached at last
+ * if nobody cared.
+ */
+ list_for_each_entry_reverse(coupler, &regulator_coupler_list, list) {
+ err = coupler->attach_regulator(coupler, rdev);
+ if (!err) {
+ if (!coupler->balance_voltage &&
+ rdev->coupling_desc.n_coupled > 2)
+ goto err_unsupported;
+
+ return coupler;
+ }
+
+ if (err < 0)
+ return ERR_PTR(err);
+
+ if (err == 1)
+ continue;
+
+ break;
+ }
+
+ return ERR_PTR(-EINVAL);
+
+err_unsupported:
+ if (coupler->detach_regulator)
+ coupler->detach_regulator(coupler, rdev);
+
+ rdev_err(rdev,
+ "Voltage balancing for multiple regulator couples is unimplemented\n");
+
+ return ERR_PTR(-EPERM);
+}
+
static void regulator_resolve_coupling(struct regulator_dev *rdev)
{
+ struct regulator_coupler *coupler = rdev->coupling_desc.coupler;
struct coupling_desc *c_desc = &rdev->coupling_desc;
int n_coupled = c_desc->n_coupled;
struct regulator_dev *c_rdev;
@@ -4724,6 +4841,12 @@ static void regulator_resolve_coupling(struct regulator_dev *rdev)
if (!c_rdev)
continue;
+ if (c_rdev->coupling_desc.coupler != coupler) {
+ rdev_err(rdev, "coupler mismatch with %s\n",
+ rdev_get_name(c_rdev));
+ return;
+ }
+
regulator_lock(c_rdev);
c_desc->coupled_rdevs[i] = c_rdev;
@@ -4737,10 +4860,12 @@ static void regulator_resolve_coupling(struct regulator_dev *rdev)
static void regulator_remove_coupling(struct regulator_dev *rdev)
{
+ struct regulator_coupler *coupler = rdev->coupling_desc.coupler;
struct coupling_desc *__c_desc, *c_desc = &rdev->coupling_desc;
struct regulator_dev *__c_rdev, *c_rdev;
unsigned int __n_coupled, n_coupled;
int i, k;
+ int err;
n_coupled = c_desc->n_coupled;
@@ -4770,21 +4895,33 @@ static void regulator_remove_coupling(struct regulator_dev *rdev)
c_desc->coupled_rdevs[i] = NULL;
c_desc->n_resolved--;
}
+
+ if (coupler && coupler->detach_regulator) {
+ err = coupler->detach_regulator(coupler, rdev);
+ if (err)
+ rdev_err(rdev, "failed to detach from coupler: %d\n",
+ err);
+ }
+
+ kfree(rdev->coupling_desc.coupled_rdevs);
+ rdev->coupling_desc.coupled_rdevs = NULL;
}
static int regulator_init_coupling(struct regulator_dev *rdev)
{
- int n_phandles;
+ int err, n_phandles;
+ size_t alloc_size;
if (!IS_ENABLED(CONFIG_OF))
n_phandles = 0;
else
n_phandles = of_get_n_coupled(rdev);
- if (n_phandles + 1 > MAX_COUPLED) {
- rdev_err(rdev, "too many regulators coupled\n");
- return -EPERM;
- }
+ alloc_size = sizeof(*rdev) * (n_phandles + 1);
+
+ rdev->coupling_desc.coupled_rdevs = kzalloc(alloc_size, GFP_KERNEL);
+ if (!rdev->coupling_desc.coupled_rdevs)
+ return -ENOMEM;
/*
* Every regulator should always have coupling descriptor filled with
@@ -4798,23 +4935,35 @@ static int regulator_init_coupling(struct regulator_dev *rdev)
if (n_phandles == 0)
return 0;
- /* regulator, which can't change its voltage, can't be coupled */
- if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) {
- rdev_err(rdev, "voltage operation not allowed\n");
+ if (!of_check_coupling_data(rdev))
return -EPERM;
- }
- if (rdev->constraints->max_spread <= 0) {
- rdev_err(rdev, "wrong max_spread value\n");
- return -EPERM;
+ rdev->coupling_desc.coupler = regulator_find_coupler(rdev);
+ if (IS_ERR(rdev->coupling_desc.coupler)) {
+ err = PTR_ERR(rdev->coupling_desc.coupler);
+ rdev_err(rdev, "failed to get coupler: %d\n", err);
+ return err;
}
- if (!of_check_coupling_data(rdev))
+ return 0;
+}
+
+static int generic_coupler_attach(struct regulator_coupler *coupler,
+ struct regulator_dev *rdev)
+{
+ if (rdev->coupling_desc.n_coupled > 2) {
+ rdev_err(rdev,
+ "Voltage balancing for multiple regulator couples is unimplemented\n");
return -EPERM;
+ }
return 0;
}
+static struct regulator_coupler generic_regulator_coupler = {
+ .attach_regulator = generic_coupler_attach,
+};
+
/**
* regulator_register - register regulator
* @regulator_desc: regulator to register
@@ -4976,7 +5125,9 @@ regulator_register(const struct regulator_desc *regulator_desc,
if (ret < 0)
goto wash;
+ mutex_lock(&regulator_list_mutex);
ret = regulator_init_coupling(rdev);
+ mutex_unlock(&regulator_list_mutex);
if (ret < 0)
goto wash;
@@ -5025,6 +5176,7 @@ regulator_register(const struct regulator_desc *regulator_desc,
unset_supplies:
mutex_lock(&regulator_list_mutex);
unset_regulator_supplies(rdev);
+ regulator_remove_coupling(rdev);
mutex_unlock(&regulator_list_mutex);
wash:
kfree(rdev->constraints);
@@ -5278,7 +5430,7 @@ static void regulator_summary_show_subtree(struct seq_file *s,
rdev->use_count, rdev->open_count, rdev->bypass_count,
regulator_opmode_to_str(opmode));
- seq_printf(s, "%5dmV ", _regulator_get_voltage(rdev) / 1000);
+ seq_printf(s, "%5dmV ", regulator_get_voltage_rdev(rdev) / 1000);
seq_printf(s, "%5dmA ",
_regulator_get_current_limit_unlocked(rdev) / 1000);
@@ -5480,6 +5632,8 @@ static int __init regulator_init(void)
#endif
regulator_dummy_init();
+ regulator_coupler_register(&generic_regulator_coupler);
+
return ret;
}
diff --git a/drivers/regulator/cpcap-regulator.c b/drivers/regulator/cpcap-regulator.c
index d3284361e594..f80781d58a28 100644
--- a/drivers/regulator/cpcap-regulator.c
+++ b/drivers/regulator/cpcap-regulator.c
@@ -90,7 +90,7 @@
#define CPCAP_REG_OFF_MODE_SEC BIT(15)
/**
- * SoC specific configuraion for CPCAP regulator. There are at least three
+ * SoC specific configuration for CPCAP regulator. There are at least three
* different SoCs each with their own parameters: omap3, omap4 and tegra2.
*
* The assign_reg and assign_mask seem to allow toggling between primary
diff --git a/drivers/regulator/da9062-regulator.c b/drivers/regulator/da9062-regulator.c
index a02e0488410f..2ffc64622451 100644
--- a/drivers/regulator/da9062-regulator.c
+++ b/drivers/regulator/da9062-regulator.c
@@ -493,12 +493,13 @@ static const struct da9062_regulator_info local_da9061_regulator_info[] = {
.desc.ops = &da9062_ldo_ops,
.desc.min_uV = (900) * 1000,
.desc.uV_step = (50) * 1000,
- .desc.n_voltages = ((3600) - (900))/(50) + 1,
+ .desc.n_voltages = ((3600) - (900))/(50) + 1
+ + DA9062AA_VLDO_A_MIN_SEL,
.desc.enable_reg = DA9062AA_LDO1_CONT,
.desc.enable_mask = DA9062AA_LDO1_EN_MASK,
.desc.vsel_reg = DA9062AA_VLDO1_A,
.desc.vsel_mask = DA9062AA_VLDO1_A_MASK,
- .desc.linear_min_sel = 0,
+ .desc.linear_min_sel = DA9062AA_VLDO_A_MIN_SEL,
.sleep = REG_FIELD(DA9062AA_VLDO1_A,
__builtin_ffs((int)DA9062AA_LDO1_SL_A_MASK) - 1,
sizeof(unsigned int) * 8 -
@@ -525,12 +526,13 @@ static const struct da9062_regulator_info local_da9061_regulator_info[] = {
.desc.ops = &da9062_ldo_ops,
.desc.min_uV = (900) * 1000,
.desc.uV_step = (50) * 1000,
- .desc.n_voltages = ((3600) - (600))/(50) + 1,
+ .desc.n_voltages = ((3600) - (900))/(50) + 1
+ + DA9062AA_VLDO_A_MIN_SEL,
.desc.enable_reg = DA9062AA_LDO2_CONT,
.desc.enable_mask = DA9062AA_LDO2_EN_MASK,
.desc.vsel_reg = DA9062AA_VLDO2_A,
.desc.vsel_mask = DA9062AA_VLDO2_A_MASK,
- .desc.linear_min_sel = 0,
+ .desc.linear_min_sel = DA9062AA_VLDO_A_MIN_SEL,
.sleep = REG_FIELD(DA9062AA_VLDO2_A,
__builtin_ffs((int)DA9062AA_LDO2_SL_A_MASK) - 1,
sizeof(unsigned int) * 8 -
@@ -557,12 +559,13 @@ static const struct da9062_regulator_info local_da9061_regulator_info[] = {
.desc.ops = &da9062_ldo_ops,
.desc.min_uV = (900) * 1000,
.desc.uV_step = (50) * 1000,
- .desc.n_voltages = ((3600) - (900))/(50) + 1,
+ .desc.n_voltages = ((3600) - (900))/(50) + 1
+ + DA9062AA_VLDO_A_MIN_SEL,
.desc.enable_reg = DA9062AA_LDO3_CONT,
.desc.enable_mask = DA9062AA_LDO3_EN_MASK,
.desc.vsel_reg = DA9062AA_VLDO3_A,
.desc.vsel_mask = DA9062AA_VLDO3_A_MASK,
- .desc.linear_min_sel = 0,
+ .desc.linear_min_sel = DA9062AA_VLDO_A_MIN_SEL,
.sleep = REG_FIELD(DA9062AA_VLDO3_A,
__builtin_ffs((int)DA9062AA_LDO3_SL_A_MASK) - 1,
sizeof(unsigned int) * 8 -
@@ -589,12 +592,13 @@ static const struct da9062_regulator_info local_da9061_regulator_info[] = {
.desc.ops = &da9062_ldo_ops,
.desc.min_uV = (900) * 1000,
.desc.uV_step = (50) * 1000,
- .desc.n_voltages = ((3600) - (900))/(50) + 1,
+ .desc.n_voltages = ((3600) - (900))/(50) + 1
+ + DA9062AA_VLDO_A_MIN_SEL,
.desc.enable_reg = DA9062AA_LDO4_CONT,
.desc.enable_mask = DA9062AA_LDO4_EN_MASK,
.desc.vsel_reg = DA9062AA_VLDO4_A,
.desc.vsel_mask = DA9062AA_VLDO4_A_MASK,
- .desc.linear_min_sel = 0,
+ .desc.linear_min_sel = DA9062AA_VLDO_A_MIN_SEL,
.sleep = REG_FIELD(DA9062AA_VLDO4_A,
__builtin_ffs((int)DA9062AA_LDO4_SL_A_MASK) - 1,
sizeof(unsigned int) * 8 -
@@ -769,12 +773,13 @@ static const struct da9062_regulator_info local_da9062_regulator_info[] = {
.desc.ops = &da9062_ldo_ops,
.desc.min_uV = (900) * 1000,
.desc.uV_step = (50) * 1000,
- .desc.n_voltages = ((3600) - (900))/(50) + 1,
+ .desc.n_voltages = ((3600) - (900))/(50) + 1
+ + DA9062AA_VLDO_A_MIN_SEL,
.desc.enable_reg = DA9062AA_LDO1_CONT,
.desc.enable_mask = DA9062AA_LDO1_EN_MASK,
.desc.vsel_reg = DA9062AA_VLDO1_A,
.desc.vsel_mask = DA9062AA_VLDO1_A_MASK,
- .desc.linear_min_sel = 0,
+ .desc.linear_min_sel = DA9062AA_VLDO_A_MIN_SEL,
.sleep = REG_FIELD(DA9062AA_VLDO1_A,
__builtin_ffs((int)DA9062AA_LDO1_SL_A_MASK) - 1,
sizeof(unsigned int) * 8 -
@@ -801,12 +806,13 @@ static const struct da9062_regulator_info local_da9062_regulator_info[] = {
.desc.ops = &da9062_ldo_ops,
.desc.min_uV = (900) * 1000,
.desc.uV_step = (50) * 1000,
- .desc.n_voltages = ((3600) - (600))/(50) + 1,
+ .desc.n_voltages = ((3600) - (900))/(50) + 1
+ + DA9062AA_VLDO_A_MIN_SEL,
.desc.enable_reg = DA9062AA_LDO2_CONT,
.desc.enable_mask = DA9062AA_LDO2_EN_MASK,
.desc.vsel_reg = DA9062AA_VLDO2_A,
.desc.vsel_mask = DA9062AA_VLDO2_A_MASK,
- .desc.linear_min_sel = 0,
+ .desc.linear_min_sel = DA9062AA_VLDO_A_MIN_SEL,
.sleep = REG_FIELD(DA9062AA_VLDO2_A,
__builtin_ffs((int)DA9062AA_LDO2_SL_A_MASK) - 1,
sizeof(unsigned int) * 8 -
@@ -833,12 +839,13 @@ static const struct da9062_regulator_info local_da9062_regulator_info[] = {
.desc.ops = &da9062_ldo_ops,
.desc.min_uV = (900) * 1000,
.desc.uV_step = (50) * 1000,
- .desc.n_voltages = ((3600) - (900))/(50) + 1,
+ .desc.n_voltages = ((3600) - (900))/(50) + 1
+ + DA9062AA_VLDO_A_MIN_SEL,
.desc.enable_reg = DA9062AA_LDO3_CONT,
.desc.enable_mask = DA9062AA_LDO3_EN_MASK,
.desc.vsel_reg = DA9062AA_VLDO3_A,
.desc.vsel_mask = DA9062AA_VLDO3_A_MASK,
- .desc.linear_min_sel = 0,
+ .desc.linear_min_sel = DA9062AA_VLDO_A_MIN_SEL,
.sleep = REG_FIELD(DA9062AA_VLDO3_A,
__builtin_ffs((int)DA9062AA_LDO3_SL_A_MASK) - 1,
sizeof(unsigned int) * 8 -
@@ -865,12 +872,13 @@ static const struct da9062_regulator_info local_da9062_regulator_info[] = {
.desc.ops = &da9062_ldo_ops,
.desc.min_uV = (900) * 1000,
.desc.uV_step = (50) * 1000,
- .desc.n_voltages = ((3600) - (900))/(50) + 1,
+ .desc.n_voltages = ((3600) - (900))/(50) + 1
+ + DA9062AA_VLDO_A_MIN_SEL,
.desc.enable_reg = DA9062AA_LDO4_CONT,
.desc.enable_mask = DA9062AA_LDO4_EN_MASK,
.desc.vsel_reg = DA9062AA_VLDO4_A,
.desc.vsel_mask = DA9062AA_VLDO4_A_MASK,
- .desc.linear_min_sel = 0,
+ .desc.linear_min_sel = DA9062AA_VLDO_A_MIN_SEL,
.sleep = REG_FIELD(DA9062AA_VLDO4_A,
__builtin_ffs((int)DA9062AA_LDO4_SL_A_MASK) - 1,
sizeof(unsigned int) * 8 -
diff --git a/drivers/regulator/da9063-regulator.c b/drivers/regulator/da9063-regulator.c
index 6f9ce1a6e44d..02f816318fba 100644
--- a/drivers/regulator/da9063-regulator.c
+++ b/drivers/regulator/da9063-regulator.c
@@ -19,7 +19,6 @@
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#include <linux/mfd/da9063/core.h>
-#include <linux/mfd/da9063/pdata.h>
#include <linux/mfd/da9063/registers.h>
@@ -28,6 +27,49 @@
REG_FIELD(_reg, __builtin_ffs((int)_mask) - 1, \
sizeof(unsigned int) * 8 - __builtin_clz((_mask)) - 1)
+/* DA9063 and DA9063L regulator IDs */
+enum {
+ /* BUCKs */
+ DA9063_ID_BCORE1,
+ DA9063_ID_BCORE2,
+ DA9063_ID_BPRO,
+ DA9063_ID_BMEM,
+ DA9063_ID_BIO,
+ DA9063_ID_BPERI,
+
+ /* BCORE1 and BCORE2 in merged mode */
+ DA9063_ID_BCORES_MERGED,
+ /* BMEM and BIO in merged mode */
+ DA9063_ID_BMEM_BIO_MERGED,
+ /* When two BUCKs are merged, they cannot be reused separately */
+
+ /* LDOs on both DA9063 and DA9063L */
+ DA9063_ID_LDO3,
+ DA9063_ID_LDO7,
+ DA9063_ID_LDO8,
+ DA9063_ID_LDO9,
+ DA9063_ID_LDO11,
+
+ /* DA9063-only LDOs */
+ DA9063_ID_LDO1,
+ DA9063_ID_LDO2,
+ DA9063_ID_LDO4,
+ DA9063_ID_LDO5,
+ DA9063_ID_LDO6,
+ DA9063_ID_LDO10,
+};
+
+/* Old regulator platform data */
+struct da9063_regulator_data {
+ int id;
+ struct regulator_init_data *initdata;
+};
+
+struct da9063_regulators_pdata {
+ unsigned n_regulators;
+ struct da9063_regulator_data *regulator_data;
+};
+
/* Regulator capabilities and registers description */
struct da9063_regulator_info {
struct regulator_desc desc;
@@ -592,7 +634,6 @@ static const struct regulator_init_data *da9063_get_regulator_initdata(
return NULL;
}
-#ifdef CONFIG_OF
static struct of_regulator_match da9063_matches[] = {
[DA9063_ID_BCORE1] = { .name = "bcore1" },
[DA9063_ID_BCORE2] = { .name = "bcore2" },
@@ -670,20 +711,10 @@ static struct da9063_regulators_pdata *da9063_parse_regulators_dt(
*da9063_reg_matches = da9063_matches;
return pdata;
}
-#else
-static struct da9063_regulators_pdata *da9063_parse_regulators_dt(
- struct platform_device *pdev,
- struct of_regulator_match **da9063_reg_matches)
-{
- *da9063_reg_matches = NULL;
- return ERR_PTR(-ENODEV);
-}
-#endif
static int da9063_regulator_probe(struct platform_device *pdev)
{
struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent);
- struct da9063_pdata *da9063_pdata = dev_get_platdata(da9063->dev);
struct of_regulator_match *da9063_reg_matches = NULL;
struct da9063_regulators_pdata *regl_pdata;
const struct da9063_dev_model *model;
@@ -693,11 +724,7 @@ static int da9063_regulator_probe(struct platform_device *pdev)
bool bcores_merged, bmem_bio_merged;
int id, irq, n, n_regulators, ret, val;
- regl_pdata = da9063_pdata ? da9063_pdata->regulators_pdata : NULL;
-
- if (!regl_pdata)
- regl_pdata = da9063_parse_regulators_dt(pdev,
- &da9063_reg_matches);
+ regl_pdata = da9063_parse_regulators_dt(pdev, &da9063_reg_matches);
if (IS_ERR(regl_pdata) || regl_pdata->n_regulators == 0) {
dev_err(&pdev->dev,
diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c
index da37b4ccd834..0309823d2c72 100644
--- a/drivers/regulator/da9211-regulator.c
+++ b/drivers/regulator/da9211-regulator.c
@@ -289,6 +289,8 @@ static struct da9211_pdata *da9211_parse_regulators_dt(
0,
GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE,
"da9211-enable");
+ if (IS_ERR(pdata->gpiod_ren[n]))
+ pdata->gpiod_ren[n] = NULL;
n++;
}
diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c
index b9ae45d2d199..4986cc5064a1 100644
--- a/drivers/regulator/helpers.c
+++ b/drivers/regulator/helpers.c
@@ -1,10 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * helpers.c -- Voltage/Current Regulator framework helper functions.
- *
- * Copyright 2007, 2008 Wolfson Microelectronics PLC.
- * Copyright 2008 SlimLogic Ltd.
- */
+//
+// helpers.c -- Voltage/Current Regulator framework helper functions.
+//
+// Copyright 2007, 2008 Wolfson Microelectronics PLC.
+// Copyright 2008 SlimLogic Ltd.
#include <linux/kernel.h>
#include <linux/err.h>
diff --git a/drivers/regulator/lm363x-regulator.c b/drivers/regulator/lm363x-regulator.c
index e02fdd1dd092..5647e2f97ff8 100644
--- a/drivers/regulator/lm363x-regulator.c
+++ b/drivers/regulator/lm363x-regulator.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TI LM363X Regulator Driver
*
* Copyright 2015 Texas Instruments
*
* Author: Milo Kim <milo.kim@ti.com>
- *
- * 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.
*/
#include <linux/err.h>
@@ -37,6 +34,11 @@
#define LM3632_VBOOST_MIN 4500000
#define LM3632_VLDO_MIN 4000000
+/* LM36274 */
+#define LM36274_BOOST_VSEL_MAX 0x3f
+#define LM36274_LDO_VSEL_MAX 0x34
+#define LM36274_VOLTAGE_MIN 4000000
+
/* Common */
#define LM363X_STEP_50mV 50000
#define LM363X_STEP_500mV 500000
@@ -217,6 +219,51 @@ static const struct regulator_desc lm363x_regulator_desc[] = {
.enable_reg = LM3632_REG_BIAS_CONFIG,
.enable_mask = LM3632_EN_VNEG_MASK,
},
+
+ /* LM36274 */
+ {
+ .name = "vboost",
+ .of_match = "vboost",
+ .id = LM36274_BOOST,
+ .ops = &lm363x_boost_voltage_table_ops,
+ .n_voltages = LM36274_BOOST_VSEL_MAX,
+ .min_uV = LM36274_VOLTAGE_MIN,
+ .uV_step = LM363X_STEP_50mV,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LM36274_REG_VOUT_BOOST,
+ .vsel_mask = LM36274_VOUT_MASK,
+ },
+ {
+ .name = "ldo_vpos",
+ .of_match = "vpos",
+ .id = LM36274_LDO_POS,
+ .ops = &lm363x_regulator_voltage_table_ops,
+ .n_voltages = LM36274_LDO_VSEL_MAX,
+ .min_uV = LM36274_VOLTAGE_MIN,
+ .uV_step = LM363X_STEP_50mV,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LM36274_REG_VOUT_POS,
+ .vsel_mask = LM36274_VOUT_MASK,
+ .enable_reg = LM36274_REG_BIAS_CONFIG_1,
+ .enable_mask = LM36274_EN_VPOS_MASK,
+ },
+ {
+ .name = "ldo_vneg",
+ .of_match = "vneg",
+ .id = LM36274_LDO_NEG,
+ .ops = &lm363x_regulator_voltage_table_ops,
+ .n_voltages = LM36274_LDO_VSEL_MAX,
+ .min_uV = LM36274_VOLTAGE_MIN,
+ .uV_step = LM363X_STEP_50mV,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LM36274_REG_VOUT_NEG,
+ .vsel_mask = LM36274_VOUT_MASK,
+ .enable_reg = LM36274_REG_BIAS_CONFIG_1,
+ .enable_mask = LM36274_EN_VNEG_MASK,
+ },
};
static struct gpio_desc *lm363x_regulator_of_get_enable_gpio(struct device *dev, int id)
@@ -229,9 +276,11 @@ static struct gpio_desc *lm363x_regulator_of_get_enable_gpio(struct device *dev,
*/
switch (id) {
case LM3632_LDO_POS:
+ case LM36274_LDO_POS:
return gpiod_get_index_optional(dev, "enable", 0,
GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
case LM3632_LDO_NEG:
+ case LM36274_LDO_NEG:
return gpiod_get_index_optional(dev, "enable", 1,
GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
default:
@@ -239,6 +288,27 @@ static struct gpio_desc *lm363x_regulator_of_get_enable_gpio(struct device *dev,
}
}
+static int lm363x_regulator_set_ext_en(struct regmap *regmap, int id)
+{
+ int ext_en_mask = 0;
+
+ switch (id) {
+ case LM3632_LDO_POS:
+ case LM3632_LDO_NEG:
+ ext_en_mask = LM3632_EXT_EN_MASK;
+ break;
+ case LM36274_LDO_POS:
+ case LM36274_LDO_NEG:
+ ext_en_mask = LM36274_EXT_EN_MASK;
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ return regmap_update_bits(regmap, lm363x_regulator_desc[id].enable_reg,
+ ext_en_mask, ext_en_mask);
+}
+
static int lm363x_regulator_probe(struct platform_device *pdev)
{
struct ti_lmu *lmu = dev_get_drvdata(pdev->dev.parent);
@@ -263,10 +333,7 @@ static int lm363x_regulator_probe(struct platform_device *pdev)
if (gpiod) {
cfg.ena_gpiod = gpiod;
-
- ret = regmap_update_bits(regmap, LM3632_REG_BIAS_CONFIG,
- LM3632_EXT_EN_MASK,
- LM3632_EXT_EN_MASK);
+ ret = lm363x_regulator_set_ext_en(regmap, id);
if (ret) {
gpiod_put(gpiod);
dev_err(dev, "External pin err: %d\n", ret);
diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c
index 9e45112658ba..bc96e65ef7c0 100644
--- a/drivers/regulator/lp3971.c
+++ b/drivers/regulator/lp3971.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Regulator driver for National Semiconductors LP3971 PMIC chip
*
@@ -5,11 +6,6 @@
* Author: Marek Szyprowski <m.szyprowski@samsung.com>
*
* Based on wm8350.c
- *
- * 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.
- *
*/
#include <linux/bug.h>
diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c
index fb098198b688..2d276bbeedf2 100644
--- a/drivers/regulator/lp3972.c
+++ b/drivers/regulator/lp3972.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Regulator driver for National Semiconductors LP3972 PMIC chip
*
* Based on lp3971.c
- *
- * 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.
- *
*/
#include <linux/bug.h>
diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c
index ca95257ce252..303d7e2dc838 100644
--- a/drivers/regulator/lp872x.c
+++ b/drivers/regulator/lp872x.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2012 Texas Instruments
*
* Author: Milo(Woogyom) Kim <milo.kim@ti.com>
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/regulator/lp8755.c b/drivers/regulator/lp8755.c
index 2e16a6ab491d..4291df077c39 100644
--- a/drivers/regulator/lp8755.c
+++ b/drivers/regulator/lp8755.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LP8755 High Performance Power Management Unit : System Interface Driver
* (based on rev. 0.26)
* Copyright 2012 Texas Instruments
*
* Author: Daniel(Geon Si) Jeong <daniel.jeong@ti.com>
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/regulator/lp87565-regulator.c b/drivers/regulator/lp87565-regulator.c
index 225e5448c926..5d067f7c2116 100644
--- a/drivers/regulator/lp87565-regulator.c
+++ b/drivers/regulator/lp87565-regulator.c
@@ -150,6 +150,12 @@ static const struct lp87565_regulator regulators[] = {
LP87565_REG_BUCK2_CTRL_1,
LP87565_BUCK_CTRL_1_EN, 3230,
buck0_1_2_3_ranges, LP87565_REG_BUCK2_CTRL_2),
+ LP87565_REGULATOR("BUCK3210", LP87565_BUCK_3210, "buck3210",
+ lp87565_buck_ops, 256, LP87565_REG_BUCK0_VOUT,
+ LP87565_BUCK_VSET, LP87565_REG_BUCK0_CTRL_1,
+ LP87565_BUCK_CTRL_1_EN |
+ LP87565_BUCK_CTRL_1_FPWM_MP_0_2, 3230,
+ buck0_1_2_3_ranges, LP87565_REG_BUCK0_CTRL_2),
};
static int lp87565_regulator_probe(struct platform_device *pdev)
@@ -166,9 +172,19 @@ static int lp87565_regulator_probe(struct platform_device *pdev)
config.driver_data = lp87565;
config.regmap = lp87565->regmap;
- if (lp87565->dev_type == LP87565_DEVICE_TYPE_LP87565_Q1) {
+ switch (lp87565->dev_type) {
+ case LP87565_DEVICE_TYPE_LP87565_Q1:
min_idx = LP87565_BUCK_10;
max_idx = LP87565_BUCK_23;
+ break;
+ case LP87565_DEVICE_TYPE_LP87561_Q1:
+ min_idx = LP87565_BUCK_3210;
+ max_idx = LP87565_BUCK_3210;
+ break;
+ default:
+ dev_err(lp87565->dev, "Invalid lp config %d\n",
+ lp87565->dev_type);
+ return -EINVAL;
}
for (i = min_idx; i <= max_idx; i++) {
diff --git a/drivers/regulator/lp8788-buck.c b/drivers/regulator/lp8788-buck.c
index a7d30550bb5f..222502a29658 100644
--- a/drivers/regulator/lp8788-buck.c
+++ b/drivers/regulator/lp8788-buck.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TI LP8788 MFD - buck regulator driver
*
* Copyright 2012 Texas Instruments
*
* Author: Milo(Woogyom) Kim <milo.kim@ti.com>
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/regulator/lp8788-ldo.c b/drivers/regulator/lp8788-ldo.c
index a2ef146e6b3a..1b00f3638996 100644
--- a/drivers/regulator/lp8788-ldo.c
+++ b/drivers/regulator/lp8788-ldo.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TI LP8788 MFD - ldo regulator driver
*
* Copyright 2012 Texas Instruments
*
* Author: Milo(Woogyom) Kim <milo.kim@ti.com>
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/regulator/max77620-regulator.c b/drivers/regulator/max77620-regulator.c
index 0db367b54ae7..8d9731e4052b 100644
--- a/drivers/regulator/max77620-regulator.c
+++ b/drivers/regulator/max77620-regulator.c
@@ -467,7 +467,7 @@ static int max77620_regulator_is_enabled(struct regulator_dev *rdev)
{
struct max77620_regulator *pmic = rdev_get_drvdata(rdev);
int id = rdev_get_id(rdev);
- int ret = 1;
+ int ret;
if (pmic->active_fps_src[id] != MAX77620_FPS_SRC_NONE)
return 1;
@@ -758,6 +758,24 @@ static struct max77620_regulator_info max20024_regs_info[MAX77620_NUM_REGS] = {
RAIL_LDO(LDO8, ldo8, "in-ldo7-8", N, 800000, 3950000, 50000),
};
+static struct max77620_regulator_info max77663_regs_info[MAX77620_NUM_REGS] = {
+ RAIL_SD(SD0, sd0, "in-sd0", SD0, 600000, 3387500, 12500, 0xFF, NONE),
+ RAIL_SD(SD1, sd1, "in-sd1", SD1, 800000, 1587500, 12500, 0xFF, NONE),
+ RAIL_SD(SD2, sd2, "in-sd2", SDX, 600000, 3787500, 12500, 0xFF, NONE),
+ RAIL_SD(SD3, sd3, "in-sd3", SDX, 600000, 3787500, 12500, 0xFF, NONE),
+ RAIL_SD(SD4, sd4, "in-sd4", SDX, 600000, 3787500, 12500, 0xFF, NONE),
+
+ RAIL_LDO(LDO0, ldo0, "in-ldo0-1", N, 800000, 2375000, 25000),
+ RAIL_LDO(LDO1, ldo1, "in-ldo0-1", N, 800000, 2375000, 25000),
+ RAIL_LDO(LDO2, ldo2, "in-ldo2", P, 800000, 3950000, 50000),
+ RAIL_LDO(LDO3, ldo3, "in-ldo3-5", P, 800000, 3950000, 50000),
+ RAIL_LDO(LDO4, ldo4, "in-ldo4-6", P, 800000, 1587500, 12500),
+ RAIL_LDO(LDO5, ldo5, "in-ldo3-5", P, 800000, 3950000, 50000),
+ RAIL_LDO(LDO6, ldo6, "in-ldo4-6", P, 800000, 3950000, 50000),
+ RAIL_LDO(LDO7, ldo7, "in-ldo7-8", N, 800000, 3950000, 50000),
+ RAIL_LDO(LDO8, ldo8, "in-ldo7-8", N, 800000, 3950000, 50000),
+};
+
static int max77620_regulator_probe(struct platform_device *pdev)
{
struct max77620_chip *max77620_chip = dev_get_drvdata(pdev->dev.parent);
@@ -782,9 +800,14 @@ static int max77620_regulator_probe(struct platform_device *pdev)
case MAX77620:
rinfo = max77620_regs_info;
break;
- default:
+ case MAX20024:
rinfo = max20024_regs_info;
break;
+ case MAX77663:
+ rinfo = max77663_regs_info;
+ break;
+ default:
+ return -EINVAL;
}
config.regmap = pmic->rmap;
@@ -878,6 +901,7 @@ static const struct dev_pm_ops max77620_regulator_pm_ops = {
static const struct platform_device_id max77620_regulator_devtype[] = {
{ .name = "max77620-pmic", },
{ .name = "max20024-pmic", },
+ { .name = "max77663-pmic", },
{},
};
MODULE_DEVICE_TABLE(platform, max77620_regulator_devtype);
diff --git a/drivers/regulator/max77650-regulator.c b/drivers/regulator/max77650-regulator.c
index 5c4f86c98510..e57fc9197d62 100644
--- a/drivers/regulator/max77650-regulator.c
+++ b/drivers/regulator/max77650-regulator.c
@@ -20,6 +20,8 @@
#define MAX77650_REGULATOR_V_LDO_MASK GENMASK(6, 0)
#define MAX77650_REGULATOR_V_SBB_MASK GENMASK(5, 0)
+#define MAX77651_REGULATOR_V_SBB1_MASK GENMASK(5, 2)
+#define MAX77651_REGULATOR_V_SBB1_RANGE_MASK GENMASK(1, 0)
#define MAX77650_REGULATOR_AD_MASK BIT(3)
#define MAX77650_REGULATOR_AD_DISABLED 0x00
@@ -41,43 +43,22 @@ struct max77650_regulator_desc {
unsigned int regB;
};
-static const unsigned int max77651_sbb1_regulator_volt_table[] = {
- 2400000, 3200000, 4000000, 4800000,
- 2450000, 3250000, 4050000, 4850000,
- 2500000, 3300000, 4100000, 4900000,
- 2550000, 3350000, 4150000, 4950000,
- 2600000, 3400000, 4200000, 5000000,
- 2650000, 3450000, 4250000, 5050000,
- 2700000, 3500000, 4300000, 5100000,
- 2750000, 3550000, 4350000, 5150000,
- 2800000, 3600000, 4400000, 5200000,
- 2850000, 3650000, 4450000, 5250000,
- 2900000, 3700000, 4500000, 0,
- 2950000, 3750000, 4550000, 0,
- 3000000, 3800000, 4600000, 0,
- 3050000, 3850000, 4650000, 0,
- 3100000, 3900000, 4700000, 0,
- 3150000, 3950000, 4750000, 0,
+static struct max77650_regulator_desc max77651_SBB1_desc;
+
+static const unsigned int max77651_sbb1_volt_range_sel[] = {
+ 0x0, 0x1, 0x2, 0x3
};
-#define MAX77651_REGULATOR_SBB1_SEL_DEC(_val) \
- (((_val & 0x3c) >> 2) | ((_val & 0x03) << 4))
-#define MAX77651_REGULATOR_SBB1_SEL_ENC(_val) \
- (((_val & 0x30) >> 4) | ((_val & 0x0f) << 2))
-
-#define MAX77650_REGULATOR_SBB1_SEL_DECR(_val) \
- do { \
- _val = MAX77651_REGULATOR_SBB1_SEL_DEC(_val); \
- _val--; \
- _val = MAX77651_REGULATOR_SBB1_SEL_ENC(_val); \
- } while (0)
-
-#define MAX77650_REGULATOR_SBB1_SEL_INCR(_val) \
- do { \
- _val = MAX77651_REGULATOR_SBB1_SEL_DEC(_val); \
- _val++; \
- _val = MAX77651_REGULATOR_SBB1_SEL_ENC(_val); \
- } while (0)
+static const struct regulator_linear_range max77651_sbb1_volt_ranges[] = {
+ /* range index 0 */
+ REGULATOR_LINEAR_RANGE(2400000, 0x00, 0x0f, 50000),
+ /* range index 1 */
+ REGULATOR_LINEAR_RANGE(3200000, 0x00, 0x0f, 50000),
+ /* range index 2 */
+ REGULATOR_LINEAR_RANGE(4000000, 0x00, 0x0f, 50000),
+ /* range index 3 */
+ REGULATOR_LINEAR_RANGE(4800000, 0x00, 0x09, 50000),
+};
static const unsigned int max77650_current_limit_table[] = {
1000000, 866000, 707000, 500000,
@@ -127,96 +108,6 @@ static int max77650_regulator_disable(struct regulator_dev *rdev)
MAX77650_REGULATOR_DISABLED);
}
-static int max77650_regulator_set_voltage_sel(struct regulator_dev *rdev,
- unsigned int sel)
-{
- int rv = 0, curr, diff;
- bool ascending;
-
- /*
- * If the regulator is disabled, we can program the desired
- * voltage right away.
- */
- if (!max77650_regulator_is_enabled(rdev))
- return regulator_set_voltage_sel_regmap(rdev, sel);
-
- /*
- * Otherwise we need to manually ramp the output voltage up/down
- * one step at a time.
- */
-
- curr = regulator_get_voltage_sel_regmap(rdev);
- if (curr < 0)
- return curr;
-
- diff = curr - sel;
- if (diff == 0)
- return 0; /* Already there. */
- else if (diff > 0)
- ascending = false;
- else
- ascending = true;
-
- /*
- * Make sure we'll get to the right voltage and break the loop even if
- * the selector equals 0.
- */
- for (ascending ? curr++ : curr--;; ascending ? curr++ : curr--) {
- rv = regulator_set_voltage_sel_regmap(rdev, curr);
- if (rv)
- return rv;
-
- if (curr == sel)
- break;
- }
-
- return 0;
-}
-
-/*
- * Special case: non-linear voltage table for max77651 SBB1 - software
- * must ensure the voltage is ramped in 50mV increments.
- */
-static int max77651_regulator_sbb1_set_voltage_sel(struct regulator_dev *rdev,
- unsigned int sel)
-{
- int rv = 0, curr, vcurr, vdest, vdiff;
-
- /*
- * If the regulator is disabled, we can program the desired
- * voltage right away.
- */
- if (!max77650_regulator_is_enabled(rdev))
- return regulator_set_voltage_sel_regmap(rdev, sel);
-
- curr = regulator_get_voltage_sel_regmap(rdev);
- if (curr < 0)
- return curr;
-
- if (curr == sel)
- return 0; /* Already there. */
-
- vcurr = max77651_sbb1_regulator_volt_table[curr];
- vdest = max77651_sbb1_regulator_volt_table[sel];
- vdiff = vcurr - vdest;
-
- for (;;) {
- if (vdiff > 0)
- MAX77650_REGULATOR_SBB1_SEL_DECR(curr);
- else
- MAX77650_REGULATOR_SBB1_SEL_INCR(curr);
-
- rv = regulator_set_voltage_sel_regmap(rdev, curr);
- if (rv)
- return rv;
-
- if (curr == sel)
- break;
- };
-
- return 0;
-}
-
static const struct regulator_ops max77650_regulator_LDO_ops = {
.is_enabled = max77650_regulator_is_enabled,
.enable = max77650_regulator_enable,
@@ -224,7 +115,7 @@ static const struct regulator_ops max77650_regulator_LDO_ops = {
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
- .set_voltage_sel = max77650_regulator_set_voltage_sel,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
.set_active_discharge = regulator_set_active_discharge_regmap,
};
@@ -235,20 +126,20 @@ static const struct regulator_ops max77650_regulator_SBB_ops = {
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
- .set_voltage_sel = max77650_regulator_set_voltage_sel,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_current_limit = regulator_get_current_limit_regmap,
.set_current_limit = regulator_set_current_limit_regmap,
.set_active_discharge = regulator_set_active_discharge_regmap,
};
-/* Special case for max77651 SBB1 - non-linear voltage mapping. */
+/* Special case for max77651 SBB1 - pickable linear-range voltage mapping. */
static const struct regulator_ops max77651_SBB1_regulator_ops = {
.is_enabled = max77650_regulator_is_enabled,
.enable = max77650_regulator_enable,
.disable = max77650_regulator_disable,
- .list_voltage = regulator_list_voltage_table,
- .get_voltage_sel = regulator_get_voltage_sel_regmap,
- .set_voltage_sel = max77651_regulator_sbb1_set_voltage_sel,
+ .list_voltage = regulator_list_voltage_pickable_linear_range,
+ .get_voltage_sel = regulator_get_voltage_sel_pickable_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_pickable_regmap,
.get_current_limit = regulator_get_current_limit_regmap,
.set_current_limit = regulator_set_current_limit_regmap,
.set_active_discharge = regulator_set_active_discharge_regmap,
@@ -265,6 +156,7 @@ static struct max77650_regulator_desc max77650_LDO_desc = {
.min_uV = 1350000,
.uV_step = 12500,
.n_voltages = 128,
+ .vsel_step = 1,
.vsel_mask = MAX77650_REGULATOR_V_LDO_MASK,
.vsel_reg = MAX77650_REG_CNFG_LDO_A,
.active_discharge_off = MAX77650_REGULATOR_AD_DISABLED,
@@ -290,6 +182,7 @@ static struct max77650_regulator_desc max77650_SBB0_desc = {
.min_uV = 800000,
.uV_step = 25000,
.n_voltages = 64,
+ .vsel_step = 1,
.vsel_mask = MAX77650_REGULATOR_V_SBB_MASK,
.vsel_reg = MAX77650_REG_CNFG_SBB0_A,
.active_discharge_off = MAX77650_REGULATOR_AD_DISABLED,
@@ -319,6 +212,7 @@ static struct max77650_regulator_desc max77650_SBB1_desc = {
.min_uV = 800000,
.uV_step = 12500,
.n_voltages = 64,
+ .vsel_step = 1,
.vsel_mask = MAX77650_REGULATOR_V_SBB_MASK,
.vsel_reg = MAX77650_REG_CNFG_SBB1_A,
.active_discharge_off = MAX77650_REGULATOR_AD_DISABLED,
@@ -345,9 +239,14 @@ static struct max77650_regulator_desc max77651_SBB1_desc = {
.supply_name = "in-sbb1",
.id = MAX77650_REGULATOR_ID_SBB1,
.ops = &max77651_SBB1_regulator_ops,
- .volt_table = max77651_sbb1_regulator_volt_table,
- .n_voltages = ARRAY_SIZE(max77651_sbb1_regulator_volt_table),
- .vsel_mask = MAX77650_REGULATOR_V_SBB_MASK,
+ .linear_range_selectors = max77651_sbb1_volt_range_sel,
+ .linear_ranges = max77651_sbb1_volt_ranges,
+ .n_linear_ranges = ARRAY_SIZE(max77651_sbb1_volt_ranges),
+ .n_voltages = 58,
+ .vsel_step = 1,
+ .vsel_range_mask = MAX77651_REGULATOR_V_SBB1_RANGE_MASK,
+ .vsel_range_reg = MAX77650_REG_CNFG_SBB1_A,
+ .vsel_mask = MAX77651_REGULATOR_V_SBB1_MASK,
.vsel_reg = MAX77650_REG_CNFG_SBB1_A,
.active_discharge_off = MAX77650_REGULATOR_AD_DISABLED,
.active_discharge_on = MAX77650_REGULATOR_AD_ENABLED,
@@ -376,6 +275,7 @@ static struct max77650_regulator_desc max77650_SBB2_desc = {
.min_uV = 800000,
.uV_step = 50000,
.n_voltages = 64,
+ .vsel_step = 1,
.vsel_mask = MAX77650_REGULATOR_V_SBB_MASK,
.vsel_reg = MAX77650_REG_CNFG_SBB2_A,
.active_discharge_off = MAX77650_REGULATOR_AD_DISABLED,
@@ -405,6 +305,7 @@ static struct max77650_regulator_desc max77651_SBB2_desc = {
.min_uV = 2400000,
.uV_step = 50000,
.n_voltages = 64,
+ .vsel_step = 1,
.vsel_mask = MAX77650_REGULATOR_V_SBB_MASK,
.vsel_reg = MAX77650_REG_CNFG_SBB2_A,
.active_discharge_off = MAX77650_REGULATOR_AD_DISABLED,
@@ -496,3 +397,4 @@ module_platform_driver(max77650_regulator_driver);
MODULE_DESCRIPTION("MAXIM 77650/77651 regulator driver");
MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:max77650-regulator");
diff --git a/drivers/regulator/max77802-regulator.c b/drivers/regulator/max77802-regulator.c
index ea7b50397300..7b8ec8c0bd15 100644
--- a/drivers/regulator/max77802-regulator.c
+++ b/drivers/regulator/max77802-regulator.c
@@ -14,9 +14,7 @@
#include <linux/kernel.h>
#include <linux/bug.h>
#include <linux/err.h>
-#include <linux/gpio.h>
#include <linux/slab.h>
-#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c
index 81229579ece9..e86d8bd25fdc 100644
--- a/drivers/regulator/max8649.c
+++ b/drivers/regulator/max8649.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Regulators driver for Maxim max8649
*
* Copyright (C) 2009-2010 Marvell International Ltd.
* Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- * 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.
*/
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/regulator/max8907-regulator.c b/drivers/regulator/max8907-regulator.c
index 860400d2cd85..76152aaa330b 100644
--- a/drivers/regulator/max8907-regulator.c
+++ b/drivers/regulator/max8907-regulator.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* max8907-regulator.c -- support regulators in max8907
*
@@ -8,10 +9,6 @@
* Copyright 2010 Texas Instruments Inc.
* Author: Graeme Gregory <gg@slimlogic.co.uk>
* Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
- *
- * 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.
*/
#include <linux/err.h>
diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c
index aed6727982cd..d953b6b0db77 100644
--- a/drivers/regulator/max8925-regulator.c
+++ b/drivers/regulator/max8925-regulator.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Regulators driver for Maxim max8925
*
* Copyright (C) 2009 Marvell International Ltd.
* Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- * 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.
*/
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c
index 2a123b87d9f2..ccd5da63cdf2 100644
--- a/drivers/regulator/max8952.c
+++ b/drivers/regulator/max8952.c
@@ -13,11 +13,9 @@
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/max8952.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/io.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/regulator/of_regulator.h>
#include <linux/slab.h>
@@ -37,7 +35,8 @@ enum {
struct max8952_data {
struct i2c_client *client;
struct max8952_platform_data *pdata;
-
+ struct gpio_desc *vid0_gpiod;
+ struct gpio_desc *vid1_gpiod;
bool vid0;
bool vid1;
};
@@ -87,16 +86,15 @@ static int max8952_set_voltage_sel(struct regulator_dev *rdev,
{
struct max8952_data *max8952 = rdev_get_drvdata(rdev);
- if (!gpio_is_valid(max8952->pdata->gpio_vid0) ||
- !gpio_is_valid(max8952->pdata->gpio_vid1)) {
+ if (!max8952->vid0_gpiod || !max8952->vid1_gpiod) {
/* DVS not supported */
return -EPERM;
}
max8952->vid0 = selector & 0x1;
max8952->vid1 = (selector >> 1) & 0x1;
- gpio_set_value(max8952->pdata->gpio_vid0, max8952->vid0);
- gpio_set_value(max8952->pdata->gpio_vid1, max8952->vid1);
+ gpiod_set_value(max8952->vid0_gpiod, max8952->vid0);
+ gpiod_set_value(max8952->vid1_gpiod, max8952->vid1);
return 0;
}
@@ -134,9 +132,6 @@ static struct max8952_platform_data *max8952_parse_dt(struct device *dev)
if (!pd)
return NULL;
- pd->gpio_vid0 = of_get_named_gpio(np, "max8952,vid-gpios", 0);
- pd->gpio_vid1 = of_get_named_gpio(np, "max8952,vid-gpios", 1);
-
if (of_property_read_u32(np, "max8952,default-mode", &pd->default_mode))
dev_warn(dev, "Default mode not specified, assuming 0\n");
@@ -179,7 +174,7 @@ static struct max8952_platform_data *max8952_parse_dt(struct device *dev)
static int max8952_pmic_probe(struct i2c_client *client,
const struct i2c_device_id *i2c_id)
{
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adapter = client->adapter;
struct max8952_platform_data *pdata = dev_get_platdata(&client->dev);
struct regulator_config config = { };
struct max8952_data *max8952;
@@ -187,7 +182,7 @@ static int max8952_pmic_probe(struct i2c_client *client,
struct gpio_desc *gpiod;
enum gpiod_flags gflags;
- int ret = 0, err = 0;
+ int ret = 0;
if (client->dev.of_node)
pdata = max8952_parse_dt(&client->dev);
@@ -240,32 +235,31 @@ static int max8952_pmic_probe(struct i2c_client *client,
max8952->vid0 = pdata->default_mode & 0x1;
max8952->vid1 = (pdata->default_mode >> 1) & 0x1;
- if (gpio_is_valid(pdata->gpio_vid0) &&
- gpio_is_valid(pdata->gpio_vid1)) {
- unsigned long gpio_flags;
-
- gpio_flags = max8952->vid0 ?
- GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
- if (devm_gpio_request_one(&client->dev, pdata->gpio_vid0,
- gpio_flags, "MAX8952 VID0"))
- err = 1;
-
- gpio_flags = max8952->vid1 ?
- GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
- if (devm_gpio_request_one(&client->dev, pdata->gpio_vid1,
- gpio_flags, "MAX8952 VID1"))
- err = 2;
- } else
- err = 3;
-
- if (err) {
+ /* Fetch vid0 and vid1 GPIOs if available */
+ gflags = max8952->vid0 ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
+ max8952->vid0_gpiod = devm_gpiod_get_index_optional(&client->dev,
+ "max8952,vid",
+ 0, gflags);
+ if (IS_ERR(max8952->vid0_gpiod))
+ return PTR_ERR(max8952->vid0_gpiod);
+ gflags = max8952->vid1 ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
+ max8952->vid1_gpiod = devm_gpiod_get_index_optional(&client->dev,
+ "max8952,vid",
+ 1, gflags);
+ if (IS_ERR(max8952->vid1_gpiod))
+ return PTR_ERR(max8952->vid1_gpiod);
+
+ /* If either VID GPIO is missing just disable this */
+ if (!max8952->vid0_gpiod || !max8952->vid1_gpiod) {
dev_warn(&client->dev, "VID0/1 gpio invalid: "
- "DVS not available.\n");
+ "DVS not available.\n");
max8952->vid0 = 0;
max8952->vid1 = 0;
- /* Mark invalid */
- pdata->gpio_vid0 = -1;
- pdata->gpio_vid1 = -1;
+ /* Make sure if we have any descriptors they get set to low */
+ if (max8952->vid0_gpiod)
+ gpiod_set_value(max8952->vid0_gpiod, 0);
+ if (max8952->vid1_gpiod)
+ gpiod_set_value(max8952->vid1_gpiod, 0);
/* Disable Pulldown of EN only */
max8952_write_reg(max8952, MAX8952_REG_CONTROL, 0x60);
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index 0ead1164e4d6..397918ebba55 100644
--- a/drivers/regulator/of_regulator.c
+++ b/drivers/regulator/of_regulator.c
@@ -21,7 +21,8 @@ static const char *const regulator_states[PM_SUSPEND_MAX + 1] = {
[PM_SUSPEND_MAX] = "regulator-state-disk",
};
-static void of_get_regulation_constraints(struct device_node *np,
+static int of_get_regulation_constraints(struct device *dev,
+ struct device_node *np,
struct regulator_init_data **init_data,
const struct regulator_desc *desc)
{
@@ -30,8 +31,13 @@ static void of_get_regulation_constraints(struct device_node *np,
struct device_node *suspend_np;
unsigned int mode;
int ret, i, len;
+ int n_phandles;
u32 pval;
+ n_phandles = of_count_phandle_with_args(np, "regulator-coupled-with",
+ NULL);
+ n_phandles = max(n_phandles, 0);
+
constraints->name = of_get_property(np, "regulator-name", NULL);
if (!of_property_read_u32(np, "regulator-min-microvolt", &pval))
@@ -163,9 +169,17 @@ static void of_get_regulation_constraints(struct device_node *np,
if (!of_property_read_u32(np, "regulator-system-load", &pval))
constraints->system_load = pval;
- if (!of_property_read_u32(np, "regulator-coupled-max-spread",
- &pval))
- constraints->max_spread = pval;
+ if (n_phandles) {
+ constraints->max_spread = devm_kzalloc(dev,
+ sizeof(*constraints->max_spread) * n_phandles,
+ GFP_KERNEL);
+
+ if (!constraints->max_spread)
+ return -ENOMEM;
+
+ of_property_read_u32_array(np, "regulator-coupled-max-spread",
+ constraints->max_spread, n_phandles);
+ }
if (!of_property_read_u32(np, "regulator-max-step-microvolt",
&pval))
@@ -242,6 +256,8 @@ static void of_get_regulation_constraints(struct device_node *np,
suspend_state = NULL;
suspend_np = NULL;
}
+
+ return 0;
}
/**
@@ -267,7 +283,9 @@ struct regulator_init_data *of_get_regulator_init_data(struct device *dev,
if (!init_data)
return NULL; /* Out of memory? */
- of_get_regulation_constraints(node, &init_data, desc);
+ if (of_get_regulation_constraints(dev, node, &init_data, desc))
+ return NULL;
+
return init_data;
}
EXPORT_SYMBOL_GPL(of_get_regulator_init_data);
@@ -473,7 +491,8 @@ int of_get_n_coupled(struct regulator_dev *rdev)
/* Looks for "to_find" device_node in src's "regulator-coupled-with" property */
static bool of_coupling_find_node(struct device_node *src,
- struct device_node *to_find)
+ struct device_node *to_find,
+ int *index)
{
int n_phandles, i;
bool found = false;
@@ -495,8 +514,10 @@ static bool of_coupling_find_node(struct device_node *src,
of_node_put(tmp);
- if (found)
+ if (found) {
+ *index = i;
break;
+ }
}
return found;
@@ -517,22 +538,23 @@ static bool of_coupling_find_node(struct device_node *src,
*/
bool of_check_coupling_data(struct regulator_dev *rdev)
{
- int max_spread = rdev->constraints->max_spread;
struct device_node *node = rdev->dev.of_node;
int n_phandles = of_get_n_coupled(rdev);
struct device_node *c_node;
+ int index;
int i;
bool ret = true;
- if (max_spread <= 0) {
- dev_err(&rdev->dev, "max_spread value invalid\n");
- return false;
- }
-
/* iterate over rdev's phandles */
for (i = 0; i < n_phandles; i++) {
+ int max_spread = rdev->constraints->max_spread[i];
int c_max_spread, c_n_phandles;
+ if (max_spread <= 0) {
+ dev_err(&rdev->dev, "max_spread value invalid\n");
+ return false;
+ }
+
c_node = of_parse_phandle(node,
"regulator-coupled-with", i);
@@ -549,22 +571,23 @@ bool of_check_coupling_data(struct regulator_dev *rdev)
goto clean;
}
- if (of_property_read_u32(c_node, "regulator-coupled-max-spread",
- &c_max_spread)) {
+ if (!of_coupling_find_node(c_node, node, &index)) {
+ dev_err(&rdev->dev, "missing 2-way linking for coupled regulators\n");
ret = false;
goto clean;
}
- if (c_max_spread != max_spread) {
- dev_err(&rdev->dev,
- "coupled regulators max_spread mismatch\n");
+ if (of_property_read_u32_index(c_node, "regulator-coupled-max-spread",
+ index, &c_max_spread)) {
ret = false;
goto clean;
}
- if (!of_coupling_find_node(c_node, node)) {
- dev_err(&rdev->dev, "missing 2-way linking for coupled regulators\n");
+ if (c_max_spread != max_spread) {
+ dev_err(&rdev->dev,
+ "coupled regulators max_spread mismatch\n");
ret = false;
+ goto clean;
}
clean:
diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c
index 3f53f9134b32..e74e11101fc1 100644
--- a/drivers/regulator/pwm-regulator.c
+++ b/drivers/regulator/pwm-regulator.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Regulator driver for PWM Regulators
*
* Copyright (C) 2014 - STMicroelectronics Inc.
*
* Author: Lee Jones <lee.jones@linaro.org>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c
index 6dfc9e176360..7f51c5fc8194 100644
--- a/drivers/regulator/qcom_spmi-regulator.c
+++ b/drivers/regulator/qcom_spmi-regulator.c
@@ -96,6 +96,8 @@ enum spmi_regulator_logical_type {
SPMI_REGULATOR_LOGICAL_TYPE_ULT_LO_SMPS,
SPMI_REGULATOR_LOGICAL_TYPE_ULT_HO_SMPS,
SPMI_REGULATOR_LOGICAL_TYPE_ULT_LDO,
+ SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS426,
+ SPMI_REGULATOR_LOGICAL_TYPE_HFS430,
};
enum spmi_regulator_type {
@@ -142,11 +144,13 @@ enum spmi_regulator_subtype {
SPMI_REGULATOR_SUBTYPE_5V_BOOST = 0x01,
SPMI_REGULATOR_SUBTYPE_FTS_CTL = 0x08,
SPMI_REGULATOR_SUBTYPE_FTS2p5_CTL = 0x09,
+ SPMI_REGULATOR_SUBTYPE_FTS426_CTL = 0x0a,
SPMI_REGULATOR_SUBTYPE_BB_2A = 0x01,
SPMI_REGULATOR_SUBTYPE_ULT_HF_CTL1 = 0x0d,
SPMI_REGULATOR_SUBTYPE_ULT_HF_CTL2 = 0x0e,
SPMI_REGULATOR_SUBTYPE_ULT_HF_CTL3 = 0x0f,
SPMI_REGULATOR_SUBTYPE_ULT_HF_CTL4 = 0x10,
+ SPMI_REGULATOR_SUBTYPE_HFS430 = 0x0a,
};
enum spmi_common_regulator_registers {
@@ -162,6 +166,18 @@ enum spmi_common_regulator_registers {
SPMI_COMMON_REG_STEP_CTRL = 0x61,
};
+/*
+ * Second common register layout used by newer devices starting with ftsmps426
+ * Note that some of the registers from the first common layout remain
+ * unchanged and their definition is not duplicated.
+ */
+enum spmi_ftsmps426_regulator_registers {
+ SPMI_FTSMPS426_REG_VOLTAGE_LSB = 0x40,
+ SPMI_FTSMPS426_REG_VOLTAGE_MSB = 0x41,
+ SPMI_FTSMPS426_REG_VOLTAGE_ULS_LSB = 0x68,
+ SPMI_FTSMPS426_REG_VOLTAGE_ULS_MSB = 0x69,
+};
+
enum spmi_vs_registers {
SPMI_VS_REG_OCP = 0x4a,
SPMI_VS_REG_SOFT_START = 0x4c,
@@ -221,6 +237,14 @@ enum spmi_common_control_register_index {
#define SPMI_COMMON_MODE_FOLLOW_HW_EN0_MASK 0x01
#define SPMI_COMMON_MODE_FOLLOW_ALL_MASK 0x1f
+#define SPMI_FTSMPS426_MODE_BYPASS_MASK 3
+#define SPMI_FTSMPS426_MODE_RETENTION_MASK 4
+#define SPMI_FTSMPS426_MODE_LPM_MASK 5
+#define SPMI_FTSMPS426_MODE_AUTO_MASK 6
+#define SPMI_FTSMPS426_MODE_HPM_MASK 7
+
+#define SPMI_FTSMPS426_MODE_MASK 0x07
+
/* Common regulator pull down control register layout */
#define SPMI_COMMON_PULL_DOWN_ENABLE_MASK 0x80
@@ -266,6 +290,25 @@ enum spmi_common_control_register_index {
#define SPMI_FTSMPS_STEP_MARGIN_NUM 4
#define SPMI_FTSMPS_STEP_MARGIN_DEN 5
+#define SPMI_FTSMPS426_STEP_CTRL_DELAY_MASK 0x03
+#define SPMI_FTSMPS426_STEP_CTRL_DELAY_SHIFT 0
+
+/* Clock rate in kHz of the FTSMPS426 regulator reference clock. */
+#define SPMI_FTSMPS426_CLOCK_RATE 4800
+
+#define SPMI_HFS430_CLOCK_RATE 1600
+
+/* Minimum voltage stepper delay for each step. */
+#define SPMI_FTSMPS426_STEP_DELAY 2
+
+/*
+ * The ratio SPMI_FTSMPS426_STEP_MARGIN_NUM/SPMI_FTSMPS426_STEP_MARGIN_DEN is
+ * used to adjust the step rate in order to account for oscillator variance.
+ */
+#define SPMI_FTSMPS426_STEP_MARGIN_NUM 10
+#define SPMI_FTSMPS426_STEP_MARGIN_DEN 11
+
+
/* VSET value to decide the range of ULT SMPS */
#define ULT_SMPS_RANGE_SPLIT 0x60
@@ -439,6 +482,10 @@ static struct spmi_voltage_range ftsmps2p5_ranges[] = {
SPMI_VOLTAGE_RANGE(1, 160000, 1360000, 2200000, 2200000, 10000),
};
+static struct spmi_voltage_range ftsmps426_ranges[] = {
+ SPMI_VOLTAGE_RANGE(0, 0, 320000, 1352000, 1352000, 4000),
+};
+
static struct spmi_voltage_range boost_ranges[] = {
SPMI_VOLTAGE_RANGE(0, 4000000, 4000000, 5550000, 5550000, 50000),
};
@@ -464,6 +511,10 @@ static struct spmi_voltage_range ult_pldo_ranges[] = {
SPMI_VOLTAGE_RANGE(0, 1750000, 1750000, 3337500, 3337500, 12500),
};
+static struct spmi_voltage_range hfs430_ranges[] = {
+ SPMI_VOLTAGE_RANGE(0, 320000, 320000, 2040000, 2040000, 8000),
+};
+
static DEFINE_SPMI_SET_POINTS(pldo);
static DEFINE_SPMI_SET_POINTS(nldo1);
static DEFINE_SPMI_SET_POINTS(nldo2);
@@ -472,12 +523,14 @@ static DEFINE_SPMI_SET_POINTS(ln_ldo);
static DEFINE_SPMI_SET_POINTS(smps);
static DEFINE_SPMI_SET_POINTS(ftsmps);
static DEFINE_SPMI_SET_POINTS(ftsmps2p5);
+static DEFINE_SPMI_SET_POINTS(ftsmps426);
static DEFINE_SPMI_SET_POINTS(boost);
static DEFINE_SPMI_SET_POINTS(boost_byp);
static DEFINE_SPMI_SET_POINTS(ult_lo_smps);
static DEFINE_SPMI_SET_POINTS(ult_ho_smps);
static DEFINE_SPMI_SET_POINTS(ult_nldo);
static DEFINE_SPMI_SET_POINTS(ult_pldo);
+static DEFINE_SPMI_SET_POINTS(hfs430);
static inline int spmi_vreg_read(struct spmi_regulator *vreg, u16 addr, u8 *buf,
int len)
@@ -739,18 +792,31 @@ spmi_regulator_common_set_voltage(struct regulator_dev *rdev, unsigned selector)
return spmi_vreg_write(vreg, SPMI_COMMON_REG_VOLTAGE_RANGE, buf, 2);
}
+static int spmi_regulator_common_list_voltage(struct regulator_dev *rdev,
+ unsigned selector);
+
+static int spmi_regulator_ftsmps426_set_voltage(struct regulator_dev *rdev,
+ unsigned selector)
+{
+ struct spmi_regulator *vreg = rdev_get_drvdata(rdev);
+ u8 buf[2];
+ int mV;
+
+ mV = spmi_regulator_common_list_voltage(rdev, selector) / 1000;
+
+ buf[0] = mV & 0xff;
+ buf[1] = mV >> 8;
+ return spmi_vreg_write(vreg, SPMI_FTSMPS426_REG_VOLTAGE_LSB, buf, 2);
+}
+
static int spmi_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
unsigned int old_selector, unsigned int new_selector)
{
struct spmi_regulator *vreg = rdev_get_drvdata(rdev);
- const struct spmi_voltage_range *range;
int diff_uV;
- range = spmi_regulator_find_range(vreg);
- if (!range)
- return -EINVAL;
-
- diff_uV = abs(new_selector - old_selector) * range->step_uV;
+ diff_uV = abs(spmi_regulator_common_list_voltage(rdev, new_selector) -
+ spmi_regulator_common_list_voltage(rdev, old_selector));
return DIV_ROUND_UP(diff_uV, vreg->slew_rate);
}
@@ -770,6 +836,21 @@ static int spmi_regulator_common_get_voltage(struct regulator_dev *rdev)
return spmi_hw_selector_to_sw(vreg, voltage_sel, range);
}
+static int spmi_regulator_ftsmps426_get_voltage(struct regulator_dev *rdev)
+{
+ struct spmi_regulator *vreg = rdev_get_drvdata(rdev);
+ const struct spmi_voltage_range *range;
+ u8 buf[2];
+ int uV;
+
+ spmi_vreg_read(vreg, SPMI_FTSMPS426_REG_VOLTAGE_LSB, buf, 2);
+
+ uV = (((unsigned int)buf[1] << 8) | (unsigned int)buf[0]) * 1000;
+ range = vreg->set_points->range;
+
+ return (uV - range->set_point_min_uV) / range->step_uV;
+}
+
static int spmi_regulator_single_map_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV)
{
@@ -903,13 +984,33 @@ static unsigned int spmi_regulator_common_get_mode(struct regulator_dev *rdev)
spmi_vreg_read(vreg, SPMI_COMMON_REG_MODE, &reg, 1);
- if (reg & SPMI_COMMON_MODE_HPM_MASK)
- return REGULATOR_MODE_NORMAL;
+ reg &= SPMI_COMMON_MODE_HPM_MASK | SPMI_COMMON_MODE_AUTO_MASK;
- if (reg & SPMI_COMMON_MODE_AUTO_MASK)
+ switch (reg) {
+ case SPMI_COMMON_MODE_HPM_MASK:
+ return REGULATOR_MODE_NORMAL;
+ case SPMI_COMMON_MODE_AUTO_MASK:
return REGULATOR_MODE_FAST;
+ default:
+ return REGULATOR_MODE_IDLE;
+ }
+}
- return REGULATOR_MODE_IDLE;
+static unsigned int spmi_regulator_ftsmps426_get_mode(struct regulator_dev *rdev)
+{
+ struct spmi_regulator *vreg = rdev_get_drvdata(rdev);
+ u8 reg;
+
+ spmi_vreg_read(vreg, SPMI_COMMON_REG_MODE, &reg, 1);
+
+ switch (reg) {
+ case SPMI_FTSMPS426_MODE_HPM_MASK:
+ return REGULATOR_MODE_NORMAL;
+ case SPMI_FTSMPS426_MODE_AUTO_MASK:
+ return REGULATOR_MODE_FAST;
+ default:
+ return REGULATOR_MODE_IDLE;
+ }
}
static int
@@ -917,12 +1018,43 @@ spmi_regulator_common_set_mode(struct regulator_dev *rdev, unsigned int mode)
{
struct spmi_regulator *vreg = rdev_get_drvdata(rdev);
u8 mask = SPMI_COMMON_MODE_HPM_MASK | SPMI_COMMON_MODE_AUTO_MASK;
- u8 val = 0;
+ u8 val;
- if (mode == REGULATOR_MODE_NORMAL)
+ switch (mode) {
+ case REGULATOR_MODE_NORMAL:
val = SPMI_COMMON_MODE_HPM_MASK;
- else if (mode == REGULATOR_MODE_FAST)
+ break;
+ case REGULATOR_MODE_FAST:
val = SPMI_COMMON_MODE_AUTO_MASK;
+ break;
+ default:
+ val = 0;
+ break;
+ }
+
+ return spmi_vreg_update_bits(vreg, SPMI_COMMON_REG_MODE, val, mask);
+}
+
+static int
+spmi_regulator_ftsmps426_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ struct spmi_regulator *vreg = rdev_get_drvdata(rdev);
+ u8 mask = SPMI_FTSMPS426_MODE_MASK;
+ u8 val;
+
+ switch (mode) {
+ case REGULATOR_MODE_NORMAL:
+ val = SPMI_FTSMPS426_MODE_HPM_MASK;
+ break;
+ case REGULATOR_MODE_FAST:
+ val = SPMI_FTSMPS426_MODE_AUTO_MASK;
+ break;
+ case REGULATOR_MODE_IDLE:
+ val = SPMI_FTSMPS426_MODE_LPM_MASK;
+ break;
+ default:
+ return -EINVAL;
+ }
return spmi_vreg_update_bits(vreg, SPMI_COMMON_REG_MODE, val, mask);
}
@@ -1256,12 +1388,41 @@ static struct regulator_ops spmi_ult_ldo_ops = {
.set_soft_start = spmi_regulator_common_set_soft_start,
};
+static struct regulator_ops spmi_ftsmps426_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .set_voltage_sel = spmi_regulator_ftsmps426_set_voltage,
+ .set_voltage_time_sel = spmi_regulator_set_voltage_time_sel,
+ .get_voltage_sel = spmi_regulator_ftsmps426_get_voltage,
+ .map_voltage = spmi_regulator_single_map_voltage,
+ .list_voltage = spmi_regulator_common_list_voltage,
+ .set_mode = spmi_regulator_ftsmps426_set_mode,
+ .get_mode = spmi_regulator_ftsmps426_get_mode,
+ .set_load = spmi_regulator_common_set_load,
+ .set_pull_down = spmi_regulator_common_set_pull_down,
+};
+
+static struct regulator_ops spmi_hfs430_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .set_voltage_sel = spmi_regulator_ftsmps426_set_voltage,
+ .set_voltage_time_sel = spmi_regulator_set_voltage_time_sel,
+ .get_voltage_sel = spmi_regulator_ftsmps426_get_voltage,
+ .map_voltage = spmi_regulator_single_map_voltage,
+ .list_voltage = spmi_regulator_common_list_voltage,
+ .set_mode = spmi_regulator_ftsmps426_set_mode,
+ .get_mode = spmi_regulator_ftsmps426_get_mode,
+};
+
/* Maximum possible digital major revision value */
#define INF 0xFF
static const struct spmi_regulator_mapping supported_regulators[] = {
/* type subtype dig_min dig_max ltype ops setpoints hpm_min */
SPMI_VREG(BUCK, GP_CTL, 0, INF, SMPS, smps, smps, 100000),
+ SPMI_VREG(BUCK, HFS430, 0, INF, HFS430, hfs430, hfs430, 10000),
SPMI_VREG(LDO, N300, 0, INF, LDO, ldo, nldo1, 10000),
SPMI_VREG(LDO, N600, 0, 0, LDO, ldo, nldo2, 10000),
SPMI_VREG(LDO, N1200, 0, 0, LDO, ldo, nldo2, 10000),
@@ -1291,6 +1452,7 @@ static const struct spmi_regulator_mapping supported_regulators[] = {
SPMI_VREG(BOOST, 5V_BOOST, 0, INF, BOOST, boost, boost, 0),
SPMI_VREG(FTS, FTS_CTL, 0, INF, FTSMPS, ftsmps, ftsmps, 100000),
SPMI_VREG(FTS, FTS2p5_CTL, 0, INF, FTSMPS, ftsmps, ftsmps2p5, 100000),
+ SPMI_VREG(FTS, FTS426_CTL, 0, INF, FTSMPS426, ftsmps426, ftsmps426, 100000),
SPMI_VREG(BOOST_BYP, BB_2A, 0, INF, BOOST_BYP, boost, boost_byp, 0),
SPMI_VREG(ULT_BUCK, ULT_HF_CTL1, 0, INF, ULT_LO_SMPS, ult_lo_smps,
ult_lo_smps, 100000),
@@ -1428,6 +1590,35 @@ static int spmi_regulator_init_slew_rate(struct spmi_regulator *vreg)
return ret;
}
+static int spmi_regulator_init_slew_rate_ftsmps426(struct spmi_regulator *vreg,
+ int clock_rate)
+{
+ int ret;
+ u8 reg = 0;
+ int delay, slew_rate;
+ const struct spmi_voltage_range *range = &vreg->set_points->range[0];
+
+ ret = spmi_vreg_read(vreg, SPMI_COMMON_REG_STEP_CTRL, &reg, 1);
+ if (ret) {
+ dev_err(vreg->dev, "spmi read failed, ret=%d\n", ret);
+ return ret;
+ }
+
+ delay = reg & SPMI_FTSMPS426_STEP_CTRL_DELAY_MASK;
+ delay >>= SPMI_FTSMPS426_STEP_CTRL_DELAY_SHIFT;
+
+ /* slew_rate has units of uV/us */
+ slew_rate = clock_rate * range->step_uV;
+ slew_rate /= 1000 * (SPMI_FTSMPS426_STEP_DELAY << delay);
+ slew_rate *= SPMI_FTSMPS426_STEP_MARGIN_NUM;
+ slew_rate /= SPMI_FTSMPS426_STEP_MARGIN_DEN;
+
+ /* Ensure that the slew rate is greater than 0 */
+ vreg->slew_rate = max(slew_rate, 1);
+
+ return ret;
+}
+
static int spmi_regulator_init_registers(struct spmi_regulator *vreg,
const struct spmi_regulator_init_data *data)
{
@@ -1567,6 +1758,19 @@ static int spmi_regulator_of_parse(struct device_node *node,
ret = spmi_regulator_init_slew_rate(vreg);
if (ret)
return ret;
+ break;
+ case SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS426:
+ ret = spmi_regulator_init_slew_rate_ftsmps426(vreg,
+ SPMI_FTSMPS426_CLOCK_RATE);
+ if (ret)
+ return ret;
+ break;
+ case SPMI_REGULATOR_LOGICAL_TYPE_HFS430:
+ ret = spmi_regulator_init_slew_rate_ftsmps426(vreg,
+ SPMI_HFS430_CLOCK_RATE);
+ if (ret)
+ return ret;
+ break;
default:
break;
}
@@ -1723,12 +1927,27 @@ static const struct spmi_regulator_data pmi8994_regulators[] = {
{ }
};
+static const struct spmi_regulator_data pm8005_regulators[] = {
+ { "s1", 0x1400, "vdd_s1", },
+ { "s2", 0x1700, "vdd_s2", },
+ { "s3", 0x1a00, "vdd_s3", },
+ { "s4", 0x1d00, "vdd_s4", },
+ { }
+};
+
+static const struct spmi_regulator_data pms405_regulators[] = {
+ { "s3", 0x1a00, "vdd_s3"},
+ { }
+};
+
static const struct of_device_id qcom_spmi_regulator_match[] = {
+ { .compatible = "qcom,pm8005-regulators", .data = &pm8005_regulators },
{ .compatible = "qcom,pm8841-regulators", .data = &pm8841_regulators },
{ .compatible = "qcom,pm8916-regulators", .data = &pm8916_regulators },
{ .compatible = "qcom,pm8941-regulators", .data = &pm8941_regulators },
{ .compatible = "qcom,pm8994-regulators", .data = &pm8994_regulators },
{ .compatible = "qcom,pmi8994-regulators", .data = &pmi8994_regulators },
+ { .compatible = "qcom,pms405-regulators", .data = &pms405_regulators },
{ }
};
MODULE_DEVICE_TABLE(of, qcom_spmi_regulator_match);
@@ -1736,6 +1955,7 @@ MODULE_DEVICE_TABLE(of, qcom_spmi_regulator_match);
static int qcom_spmi_regulator_probe(struct platform_device *pdev)
{
const struct spmi_regulator_data *reg;
+ const struct spmi_voltage_range *range;
const struct of_device_id *match;
struct regulator_config config = { };
struct regulator_dev *rdev;
@@ -1825,6 +2045,12 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev)
}
}
+ if (vreg->set_points && vreg->set_points->count == 1) {
+ /* since there is only one range */
+ range = vreg->set_points->range;
+ vreg->desc.uV_step = range->step_uV;
+ }
+
config.dev = dev;
config.driver_data = vreg;
config.regmap = regmap;
diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c
index 061ebc4b3477..e7af0c53d449 100644
--- a/drivers/regulator/rk808-regulator.c
+++ b/drivers/regulator/rk808-regulator.c
@@ -28,6 +28,12 @@
#define RK808_BUCK4_VSEL_MASK 0xf
#define RK808_LDO_VSEL_MASK 0x1f
+#define RK809_BUCK5_VSEL_MASK 0x7
+
+#define RK817_LDO_VSEL_MASK 0x7f
+#define RK817_BOOST_VSEL_MASK 0x7
+#define RK817_BUCK_VSEL_MASK 0x7f
+
#define RK818_BUCK_VSEL_MASK 0x3f
#define RK818_BUCK4_VSEL_MASK 0x1f
#define RK818_LDO_VSEL_MASK 0x1f
@@ -57,30 +63,36 @@
/* max steps for increase voltage of Buck1/2, equal 100mv*/
#define MAX_STEPS_ONE_TIME 8
-#define RK805_DESC(_id, _match, _supply, _min, _max, _step, _vreg, \
- _vmask, _ereg, _emask, _etime) \
- [_id] = { \
- .name = (_match), \
- .supply_name = (_supply), \
- .of_match = of_match_ptr(_match), \
- .regulators_node = of_match_ptr("regulators"), \
- .type = REGULATOR_VOLTAGE, \
- .id = (_id), \
- .n_voltages = (((_max) - (_min)) / (_step) + 1), \
- .owner = THIS_MODULE, \
- .min_uV = (_min) * 1000, \
- .uV_step = (_step) * 1000, \
- .vsel_reg = (_vreg), \
- .vsel_mask = (_vmask), \
- .enable_reg = (_ereg), \
- .enable_mask = (_emask), \
- .enable_time = (_etime), \
- .ops = &rk805_reg_ops, \
+#define ENABLE_MASK(id) (BIT(id) | BIT(4 + (id)))
+#define DISABLE_VAL(id) (BIT(4 + (id)))
+
+#define RK817_BOOST_DESC(_id, _match, _supply, _min, _max, _step, _vreg,\
+ _vmask, _ereg, _emask, _enval, _disval, _etime, m_drop) \
+ { \
+ .name = (_match), \
+ .supply_name = (_supply), \
+ .of_match = of_match_ptr(_match), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .type = REGULATOR_VOLTAGE, \
+ .id = (_id), \
+ .n_voltages = (((_max) - (_min)) / (_step) + 1), \
+ .owner = THIS_MODULE, \
+ .min_uV = (_min) * 1000, \
+ .uV_step = (_step) * 1000, \
+ .vsel_reg = (_vreg), \
+ .vsel_mask = (_vmask), \
+ .enable_reg = (_ereg), \
+ .enable_mask = (_emask), \
+ .enable_val = (_enval), \
+ .disable_val = (_disval), \
+ .enable_time = (_etime), \
+ .min_dropout_uV = (m_drop) * 1000, \
+ .ops = &rk817_boost_ops, \
}
-#define RK8XX_DESC(_id, _match, _supply, _min, _max, _step, _vreg, \
- _vmask, _ereg, _emask, _etime) \
- [_id] = { \
+#define RK8XX_DESC_COM(_id, _match, _supply, _min, _max, _step, _vreg, \
+ _vmask, _ereg, _emask, _enval, _disval, _etime, _ops) \
+ { \
.name = (_match), \
.supply_name = (_supply), \
.of_match = of_match_ptr(_match), \
@@ -95,12 +107,30 @@
.vsel_mask = (_vmask), \
.enable_reg = (_ereg), \
.enable_mask = (_emask), \
+ .enable_val = (_enval), \
+ .disable_val = (_disval), \
.enable_time = (_etime), \
- .ops = &rk808_reg_ops, \
+ .ops = _ops, \
}
-#define RK8XX_DESC_SWITCH(_id, _match, _supply, _ereg, _emask) \
- [_id] = { \
+#define RK805_DESC(_id, _match, _supply, _min, _max, _step, _vreg, \
+ _vmask, _ereg, _emask, _etime) \
+ RK8XX_DESC_COM(_id, _match, _supply, _min, _max, _step, _vreg, \
+ _vmask, _ereg, _emask, 0, 0, _etime, &rk805_reg_ops)
+
+#define RK8XX_DESC(_id, _match, _supply, _min, _max, _step, _vreg, \
+ _vmask, _ereg, _emask, _etime) \
+ RK8XX_DESC_COM(_id, _match, _supply, _min, _max, _step, _vreg, \
+ _vmask, _ereg, _emask, 0, 0, _etime, &rk808_reg_ops)
+
+#define RK817_DESC(_id, _match, _supply, _min, _max, _step, _vreg, \
+ _vmask, _ereg, _emask, _disval, _etime) \
+ RK8XX_DESC_COM(_id, _match, _supply, _min, _max, _step, _vreg, \
+ _vmask, _ereg, _emask, _emask, _disval, _etime, &rk817_reg_ops)
+
+#define RKXX_DESC_SWITCH_COM(_id, _match, _supply, _ereg, _emask, \
+ _enval, _disval, _ops) \
+ { \
.name = (_match), \
.supply_name = (_supply), \
.of_match = of_match_ptr(_match), \
@@ -109,10 +139,20 @@
.id = (_id), \
.enable_reg = (_ereg), \
.enable_mask = (_emask), \
+ .enable_val = (_enval), \
+ .disable_val = (_disval), \
.owner = THIS_MODULE, \
- .ops = &rk808_switch_ops \
+ .ops = _ops \
}
+#define RK817_DESC_SWITCH(_id, _match, _supply, _ereg, _emask, \
+ _disval) \
+ RKXX_DESC_SWITCH_COM(_id, _match, _supply, _ereg, _emask, \
+ _emask, _disval, &rk817_switch_ops)
+
+#define RK8XX_DESC_SWITCH(_id, _match, _supply, _ereg, _emask) \
+ RKXX_DESC_SWITCH_COM(_id, _match, _supply, _ereg, _emask, \
+ 0, 0, &rk808_switch_ops)
struct rk808_regulator_data {
struct gpio_desc *dvs_gpio[2];
@@ -130,6 +170,51 @@ static const struct regulator_linear_range rk808_ldo3_voltage_ranges[] = {
REGULATOR_LINEAR_RANGE(2500000, 15, 15, 0),
};
+#define RK809_BUCK5_SEL_CNT (8)
+
+static const struct regulator_linear_range rk809_buck5_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1500000, 0, 0, 0),
+ REGULATOR_LINEAR_RANGE(1800000, 1, 3, 200000),
+ REGULATOR_LINEAR_RANGE(2800000, 4, 5, 200000),
+ REGULATOR_LINEAR_RANGE(3300000, 6, 7, 300000),
+};
+
+#define RK817_BUCK1_MIN0 500000
+#define RK817_BUCK1_MAX0 1500000
+
+#define RK817_BUCK1_MIN1 1600000
+#define RK817_BUCK1_MAX1 2400000
+
+#define RK817_BUCK3_MAX1 3400000
+
+#define RK817_BUCK1_STP0 12500
+#define RK817_BUCK1_STP1 100000
+
+#define RK817_BUCK1_SEL0 ((RK817_BUCK1_MAX0 - RK817_BUCK1_MIN0) /\
+ RK817_BUCK1_STP0)
+#define RK817_BUCK1_SEL1 ((RK817_BUCK1_MAX1 - RK817_BUCK1_MIN1) /\
+ RK817_BUCK1_STP1)
+
+#define RK817_BUCK3_SEL1 ((RK817_BUCK3_MAX1 - RK817_BUCK1_MIN1) /\
+ RK817_BUCK1_STP1)
+
+#define RK817_BUCK1_SEL_CNT (RK817_BUCK1_SEL0 + RK817_BUCK1_SEL1 + 1)
+#define RK817_BUCK3_SEL_CNT (RK817_BUCK1_SEL0 + RK817_BUCK3_SEL1 + 1)
+
+static const struct regulator_linear_range rk817_buck1_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(RK817_BUCK1_MIN0, 0,
+ RK817_BUCK1_SEL0, RK817_BUCK1_STP0),
+ REGULATOR_LINEAR_RANGE(RK817_BUCK1_MIN1, RK817_BUCK1_SEL0 + 1,
+ RK817_BUCK1_SEL_CNT, RK817_BUCK1_STP1),
+};
+
+static const struct regulator_linear_range rk817_buck3_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(RK817_BUCK1_MIN0, 0,
+ RK817_BUCK1_SEL0, RK817_BUCK1_STP0),
+ REGULATOR_LINEAR_RANGE(RK817_BUCK1_MIN1, RK817_BUCK1_SEL0 + 1,
+ RK817_BUCK3_SEL_CNT, RK817_BUCK1_STP1),
+};
+
static int rk808_buck1_2_get_voltage_sel_regmap(struct regulator_dev *rdev)
{
struct rk808_regulator_data *pdata = rdev_get_drvdata(rdev);
@@ -281,6 +366,36 @@ static int rk808_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
RK808_RAMP_RATE_MASK, ramp_value);
}
+/*
+ * RK817 RK809
+ */
+static int rk817_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
+{
+ unsigned int ramp_value = RK817_RAMP_RATE_25MV_PER_US;
+ unsigned int reg = RK817_BUCK_CONFIG_REG(rdev_get_id(rdev));
+
+ switch (ramp_delay) {
+ case 0 ... 3000:
+ ramp_value = RK817_RAMP_RATE_3MV_PER_US;
+ break;
+ case 3001 ... 6300:
+ ramp_value = RK817_RAMP_RATE_6_3MV_PER_US;
+ break;
+ case 6301 ... 12500:
+ ramp_value = RK817_RAMP_RATE_12_5MV_PER_US;
+ break;
+ case 12501 ... 25000:
+ break;
+ default:
+ dev_warn(&rdev->dev,
+ "%s ramp_delay: %d not supported, setting 10000\n",
+ rdev->desc->name, ramp_delay);
+ }
+
+ return regmap_update_bits(rdev->regmap, reg,
+ RK817_RAMP_RATE_MASK, ramp_value);
+}
+
static int rk808_set_suspend_voltage(struct regulator_dev *rdev, int uv)
{
unsigned int reg;
@@ -296,6 +411,21 @@ static int rk808_set_suspend_voltage(struct regulator_dev *rdev, int uv)
sel);
}
+static int rk817_set_suspend_voltage(struct regulator_dev *rdev, int uv)
+{
+ unsigned int reg;
+ int sel = regulator_map_voltage_linear(rdev, uv, uv);
+ /* only ldo1~ldo9 */
+ if (sel < 0)
+ return -EINVAL;
+
+ reg = rdev->desc->vsel_reg + RK808_SLP_REG_OFFSET;
+
+ return regmap_update_bits(rdev->regmap, reg,
+ rdev->desc->vsel_mask,
+ sel);
+}
+
static int rk808_set_suspend_voltage_range(struct regulator_dev *rdev, int uv)
{
unsigned int reg;
@@ -355,6 +485,131 @@ static int rk808_set_suspend_disable(struct regulator_dev *rdev)
rdev->desc->enable_mask);
}
+static int rk817_set_suspend_enable_ctrl(struct regulator_dev *rdev,
+ unsigned int en)
+{
+ unsigned int reg;
+ int id = rdev_get_id(rdev);
+ unsigned int id_slp, msk, val;
+
+ if (id >= RK817_ID_DCDC1 && id <= RK817_ID_DCDC4)
+ id_slp = id;
+ else if (id >= RK817_ID_LDO1 && id <= RK817_ID_LDO8)
+ id_slp = 8 + (id - RK817_ID_LDO1);
+ else if (id >= RK817_ID_LDO9 && id <= RK809_ID_SW2)
+ id_slp = 4 + (id - RK817_ID_LDO9);
+ else
+ return -EINVAL;
+
+ reg = RK817_POWER_SLP_EN_REG(id_slp / 8);
+
+ msk = BIT(id_slp % 8);
+ if (en)
+ val = msk;
+ else
+ val = 0;
+
+ return regmap_update_bits(rdev->regmap, reg, msk, val);
+}
+
+static int rk817_set_suspend_enable(struct regulator_dev *rdev)
+{
+ return rk817_set_suspend_enable_ctrl(rdev, 1);
+}
+
+static int rk817_set_suspend_disable(struct regulator_dev *rdev)
+{
+ return rk817_set_suspend_enable_ctrl(rdev, 0);
+}
+
+static int rk8xx_set_suspend_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ unsigned int reg;
+
+ reg = rdev->desc->vsel_reg + RK808_SLP_REG_OFFSET;
+
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ return regmap_update_bits(rdev->regmap, reg,
+ PWM_MODE_MSK, FPWM_MODE);
+ case REGULATOR_MODE_NORMAL:
+ return regmap_update_bits(rdev->regmap, reg,
+ PWM_MODE_MSK, AUTO_PWM_MODE);
+ default:
+ dev_err(&rdev->dev, "do not support this mode\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rk8xx_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ return regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,
+ PWM_MODE_MSK, FPWM_MODE);
+ case REGULATOR_MODE_NORMAL:
+ return regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,
+ PWM_MODE_MSK, AUTO_PWM_MODE);
+ default:
+ dev_err(&rdev->dev, "do not support this mode\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static unsigned int rk8xx_get_mode(struct regulator_dev *rdev)
+{
+ unsigned int val;
+ int err;
+
+ err = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val);
+ if (err)
+ return err;
+
+ if (val & FPWM_MODE)
+ return REGULATOR_MODE_FAST;
+ else
+ return REGULATOR_MODE_NORMAL;
+}
+
+static int rk8xx_is_enabled_wmsk_regmap(struct regulator_dev *rdev)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, &val);
+ if (ret != 0)
+ return ret;
+
+ /* add write mask bit */
+ val |= (rdev->desc->enable_mask & 0xf0);
+ val &= rdev->desc->enable_mask;
+
+ if (rdev->desc->enable_is_inverted) {
+ if (rdev->desc->enable_val)
+ return val != rdev->desc->enable_val;
+ return (val == 0);
+ }
+ if (rdev->desc->enable_val)
+ return val == rdev->desc->enable_val;
+ return val != 0;
+}
+
+static unsigned int rk8xx_regulator_of_map_mode(unsigned int mode)
+{
+ switch (mode) {
+ case 1:
+ return REGULATOR_MODE_FAST;
+ case 2:
+ return REGULATOR_MODE_NORMAL;
+ default:
+ return -EINVAL;
+ }
+}
+
static const struct regulator_ops rk805_reg_ops = {
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
@@ -431,6 +686,71 @@ static const struct regulator_linear_range rk805_buck_1_2_voltage_ranges[] = {
REGULATOR_LINEAR_RANGE(2300000, 63, 63, 0),
};
+static struct regulator_ops rk809_buck5_ops_range = {
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = rk8xx_is_enabled_wmsk_regmap,
+ .set_suspend_voltage = rk808_set_suspend_voltage_range,
+ .set_suspend_enable = rk817_set_suspend_enable,
+ .set_suspend_disable = rk817_set_suspend_disable,
+};
+
+static struct regulator_ops rk817_reg_ops = {
+ .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,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = rk8xx_is_enabled_wmsk_regmap,
+ .set_suspend_voltage = rk817_set_suspend_voltage,
+ .set_suspend_enable = rk817_set_suspend_enable,
+ .set_suspend_disable = rk817_set_suspend_disable,
+};
+
+static struct regulator_ops rk817_boost_ops = {
+ .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,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = rk8xx_is_enabled_wmsk_regmap,
+ .set_suspend_enable = rk817_set_suspend_enable,
+ .set_suspend_disable = rk817_set_suspend_disable,
+};
+
+static struct regulator_ops rk817_buck_ops_range = {
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = rk8xx_is_enabled_wmsk_regmap,
+ .set_mode = rk8xx_set_mode,
+ .get_mode = rk8xx_get_mode,
+ .set_suspend_mode = rk8xx_set_suspend_mode,
+ .set_ramp_delay = rk817_set_ramp_delay,
+ .set_suspend_voltage = rk808_set_suspend_voltage_range,
+ .set_suspend_enable = rk817_set_suspend_enable,
+ .set_suspend_disable = rk817_set_suspend_disable,
+};
+
+static struct regulator_ops rk817_switch_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = rk8xx_is_enabled_wmsk_regmap,
+ .set_suspend_enable = rk817_set_suspend_enable,
+ .set_suspend_disable = rk817_set_suspend_disable,
+};
+
static const struct regulator_desc rk805_reg[] = {
{
.name = "DCDC_REG1",
@@ -587,6 +907,271 @@ static const struct regulator_desc rk808_reg[] = {
RK808_DCDC_EN_REG, BIT(6)),
};
+static const struct regulator_desc rk809_reg[] = {
+ {
+ .name = "DCDC_REG1",
+ .supply_name = "vcc1",
+ .of_match = of_match_ptr("DCDC_REG1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = RK817_ID_DCDC1,
+ .ops = &rk817_buck_ops_range,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = RK817_BUCK1_SEL_CNT + 1,
+ .linear_ranges = rk817_buck1_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk817_buck1_voltage_ranges),
+ .vsel_reg = RK817_BUCK1_ON_VSEL_REG,
+ .vsel_mask = RK817_BUCK_VSEL_MASK,
+ .enable_reg = RK817_POWER_EN_REG(0),
+ .enable_mask = ENABLE_MASK(RK817_ID_DCDC1),
+ .enable_val = ENABLE_MASK(RK817_ID_DCDC1),
+ .disable_val = DISABLE_VAL(RK817_ID_DCDC1),
+ .of_map_mode = rk8xx_regulator_of_map_mode,
+ .owner = THIS_MODULE,
+ }, {
+ .name = "DCDC_REG2",
+ .supply_name = "vcc2",
+ .of_match = of_match_ptr("DCDC_REG2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = RK817_ID_DCDC2,
+ .ops = &rk817_buck_ops_range,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = RK817_BUCK1_SEL_CNT + 1,
+ .linear_ranges = rk817_buck1_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk817_buck1_voltage_ranges),
+ .vsel_reg = RK817_BUCK2_ON_VSEL_REG,
+ .vsel_mask = RK817_BUCK_VSEL_MASK,
+ .enable_reg = RK817_POWER_EN_REG(0),
+ .enable_mask = ENABLE_MASK(RK817_ID_DCDC2),
+ .enable_val = ENABLE_MASK(RK817_ID_DCDC2),
+ .disable_val = DISABLE_VAL(RK817_ID_DCDC2),
+ .of_map_mode = rk8xx_regulator_of_map_mode,
+ .owner = THIS_MODULE,
+ }, {
+ .name = "DCDC_REG3",
+ .supply_name = "vcc3",
+ .of_match = of_match_ptr("DCDC_REG3"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = RK817_ID_DCDC3,
+ .ops = &rk817_buck_ops_range,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = RK817_BUCK1_SEL_CNT + 1,
+ .linear_ranges = rk817_buck1_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk817_buck1_voltage_ranges),
+ .vsel_reg = RK817_BUCK3_ON_VSEL_REG,
+ .vsel_mask = RK817_BUCK_VSEL_MASK,
+ .enable_reg = RK817_POWER_EN_REG(0),
+ .enable_mask = ENABLE_MASK(RK817_ID_DCDC3),
+ .enable_val = ENABLE_MASK(RK817_ID_DCDC3),
+ .disable_val = DISABLE_VAL(RK817_ID_DCDC3),
+ .of_map_mode = rk8xx_regulator_of_map_mode,
+ .owner = THIS_MODULE,
+ }, {
+ .name = "DCDC_REG4",
+ .supply_name = "vcc4",
+ .of_match = of_match_ptr("DCDC_REG4"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = RK817_ID_DCDC4,
+ .ops = &rk817_buck_ops_range,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = RK817_BUCK3_SEL_CNT + 1,
+ .linear_ranges = rk817_buck3_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk817_buck3_voltage_ranges),
+ .vsel_reg = RK817_BUCK4_ON_VSEL_REG,
+ .vsel_mask = RK817_BUCK_VSEL_MASK,
+ .enable_reg = RK817_POWER_EN_REG(0),
+ .enable_mask = ENABLE_MASK(RK817_ID_DCDC4),
+ .enable_val = ENABLE_MASK(RK817_ID_DCDC4),
+ .disable_val = DISABLE_VAL(RK817_ID_DCDC4),
+ .of_map_mode = rk8xx_regulator_of_map_mode,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "DCDC_REG5",
+ .supply_name = "vcc9",
+ .of_match = of_match_ptr("DCDC_REG5"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = RK809_ID_DCDC5,
+ .ops = &rk809_buck5_ops_range,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = RK809_BUCK5_SEL_CNT,
+ .linear_ranges = rk809_buck5_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk809_buck5_voltage_ranges),
+ .vsel_reg = RK809_BUCK5_CONFIG(0),
+ .vsel_mask = RK809_BUCK5_VSEL_MASK,
+ .enable_reg = RK817_POWER_EN_REG(3),
+ .enable_mask = ENABLE_MASK(1),
+ .enable_val = ENABLE_MASK(1),
+ .disable_val = DISABLE_VAL(1),
+ .of_map_mode = rk8xx_regulator_of_map_mode,
+ .owner = THIS_MODULE,
+ },
+ RK817_DESC(RK817_ID_LDO1, "LDO_REG1", "vcc5", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(0), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(1), ENABLE_MASK(0),
+ DISABLE_VAL(0), 400),
+ RK817_DESC(RK817_ID_LDO2, "LDO_REG2", "vcc5", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(1), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(1), ENABLE_MASK(1),
+ DISABLE_VAL(1), 400),
+ RK817_DESC(RK817_ID_LDO3, "LDO_REG3", "vcc5", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(2), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(1), ENABLE_MASK(2),
+ DISABLE_VAL(2), 400),
+ RK817_DESC(RK817_ID_LDO4, "LDO_REG4", "vcc6", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(3), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(1), ENABLE_MASK(3),
+ DISABLE_VAL(3), 400),
+ RK817_DESC(RK817_ID_LDO5, "LDO_REG5", "vcc6", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(4), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(2), ENABLE_MASK(0),
+ DISABLE_VAL(0), 400),
+ RK817_DESC(RK817_ID_LDO6, "LDO_REG6", "vcc6", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(5), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(2), ENABLE_MASK(1),
+ DISABLE_VAL(1), 400),
+ RK817_DESC(RK817_ID_LDO7, "LDO_REG7", "vcc7", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(6), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(2), ENABLE_MASK(2),
+ DISABLE_VAL(2), 400),
+ RK817_DESC(RK817_ID_LDO8, "LDO_REG8", "vcc7", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(7), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(2), ENABLE_MASK(3),
+ DISABLE_VAL(3), 400),
+ RK817_DESC(RK817_ID_LDO9, "LDO_REG9", "vcc7", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(8), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(3), ENABLE_MASK(0),
+ DISABLE_VAL(0), 400),
+ RK817_DESC_SWITCH(RK809_ID_SW1, "SWITCH_REG1", "vcc9",
+ RK817_POWER_EN_REG(3), ENABLE_MASK(2),
+ DISABLE_VAL(2)),
+ RK817_DESC_SWITCH(RK809_ID_SW2, "SWITCH_REG2", "vcc8",
+ RK817_POWER_EN_REG(3), ENABLE_MASK(3),
+ DISABLE_VAL(3)),
+};
+
+static const struct regulator_desc rk817_reg[] = {
+ {
+ .name = "DCDC_REG1",
+ .supply_name = "vcc1",
+ .of_match = of_match_ptr("DCDC_REG1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = RK817_ID_DCDC1,
+ .ops = &rk817_buck_ops_range,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = RK817_BUCK1_SEL_CNT + 1,
+ .linear_ranges = rk817_buck1_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk817_buck1_voltage_ranges),
+ .vsel_reg = RK817_BUCK1_ON_VSEL_REG,
+ .vsel_mask = RK817_BUCK_VSEL_MASK,
+ .enable_reg = RK817_POWER_EN_REG(0),
+ .enable_mask = ENABLE_MASK(RK817_ID_DCDC1),
+ .enable_val = ENABLE_MASK(RK817_ID_DCDC1),
+ .disable_val = DISABLE_VAL(RK817_ID_DCDC1),
+ .of_map_mode = rk8xx_regulator_of_map_mode,
+ .owner = THIS_MODULE,
+ }, {
+ .name = "DCDC_REG2",
+ .supply_name = "vcc2",
+ .of_match = of_match_ptr("DCDC_REG2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = RK817_ID_DCDC2,
+ .ops = &rk817_buck_ops_range,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = RK817_BUCK1_SEL_CNT + 1,
+ .linear_ranges = rk817_buck1_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk817_buck1_voltage_ranges),
+ .vsel_reg = RK817_BUCK2_ON_VSEL_REG,
+ .vsel_mask = RK817_BUCK_VSEL_MASK,
+ .enable_reg = RK817_POWER_EN_REG(0),
+ .enable_mask = ENABLE_MASK(RK817_ID_DCDC2),
+ .enable_val = ENABLE_MASK(RK817_ID_DCDC2),
+ .disable_val = DISABLE_VAL(RK817_ID_DCDC2),
+ .of_map_mode = rk8xx_regulator_of_map_mode,
+ .owner = THIS_MODULE,
+ }, {
+ .name = "DCDC_REG3",
+ .supply_name = "vcc3",
+ .of_match = of_match_ptr("DCDC_REG3"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = RK817_ID_DCDC3,
+ .ops = &rk817_buck_ops_range,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = RK817_BUCK1_SEL_CNT + 1,
+ .linear_ranges = rk817_buck1_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk817_buck1_voltage_ranges),
+ .vsel_reg = RK817_BUCK3_ON_VSEL_REG,
+ .vsel_mask = RK817_BUCK_VSEL_MASK,
+ .enable_reg = RK817_POWER_EN_REG(0),
+ .enable_mask = ENABLE_MASK(RK817_ID_DCDC3),
+ .enable_val = ENABLE_MASK(RK817_ID_DCDC3),
+ .disable_val = DISABLE_VAL(RK817_ID_DCDC3),
+ .of_map_mode = rk8xx_regulator_of_map_mode,
+ .owner = THIS_MODULE,
+ }, {
+ .name = "DCDC_REG4",
+ .supply_name = "vcc4",
+ .of_match = of_match_ptr("DCDC_REG4"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = RK817_ID_DCDC4,
+ .ops = &rk817_buck_ops_range,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = RK817_BUCK3_SEL_CNT + 1,
+ .linear_ranges = rk817_buck3_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk817_buck3_voltage_ranges),
+ .vsel_reg = RK817_BUCK4_ON_VSEL_REG,
+ .vsel_mask = RK817_BUCK_VSEL_MASK,
+ .enable_reg = RK817_POWER_EN_REG(0),
+ .enable_mask = ENABLE_MASK(RK817_ID_DCDC4),
+ .enable_val = ENABLE_MASK(RK817_ID_DCDC4),
+ .disable_val = DISABLE_VAL(RK817_ID_DCDC4),
+ .of_map_mode = rk8xx_regulator_of_map_mode,
+ .owner = THIS_MODULE,
+ },
+ RK817_DESC(RK817_ID_LDO1, "LDO_REG1", "vcc5", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(0), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(1), ENABLE_MASK(0),
+ DISABLE_VAL(0), 400),
+ RK817_DESC(RK817_ID_LDO2, "LDO_REG2", "vcc5", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(1), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(1), ENABLE_MASK(1),
+ DISABLE_VAL(1), 400),
+ RK817_DESC(RK817_ID_LDO3, "LDO_REG3", "vcc5", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(2), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(1), ENABLE_MASK(2),
+ DISABLE_VAL(2), 400),
+ RK817_DESC(RK817_ID_LDO4, "LDO_REG4", "vcc6", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(3), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(1), ENABLE_MASK(3),
+ DISABLE_VAL(3), 400),
+ RK817_DESC(RK817_ID_LDO5, "LDO_REG5", "vcc6", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(4), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(2), ENABLE_MASK(0),
+ DISABLE_VAL(0), 400),
+ RK817_DESC(RK817_ID_LDO6, "LDO_REG6", "vcc6", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(5), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(2), ENABLE_MASK(1),
+ DISABLE_VAL(1), 400),
+ RK817_DESC(RK817_ID_LDO7, "LDO_REG7", "vcc7", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(6), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(2), ENABLE_MASK(2),
+ DISABLE_VAL(2), 400),
+ RK817_DESC(RK817_ID_LDO8, "LDO_REG8", "vcc7", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(7), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(2), ENABLE_MASK(3),
+ DISABLE_VAL(3), 400),
+ RK817_DESC(RK817_ID_LDO9, "LDO_REG9", "vcc7", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(8), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(3), ENABLE_MASK(0),
+ DISABLE_VAL(0), 400),
+ RK817_BOOST_DESC(RK817_ID_BOOST, "BOOST", "vcc8", 4700, 5400, 100,
+ RK817_BOOST_OTG_CFG, RK817_BOOST_VSEL_MASK,
+ RK817_POWER_EN_REG(3), ENABLE_MASK(1), ENABLE_MASK(1),
+ DISABLE_VAL(1), 400, 3500 - 5400),
+ RK817_DESC_SWITCH(RK817_ID_BOOST_OTG_SW, "OTG_SWITCH", "vcc9",
+ RK817_POWER_EN_REG(3), ENABLE_MASK(2),
+ DISABLE_VAL(2)),
+};
+
static const struct regulator_desc rk818_reg[] = {
{
.name = "DCDC_REG1",
@@ -757,6 +1342,14 @@ static int rk808_regulator_probe(struct platform_device *pdev)
regulators = rk808_reg;
nregulators = RK808_NUM_REGULATORS;
break;
+ case RK809_ID:
+ regulators = rk809_reg;
+ nregulators = RK809_NUM_REGULATORS;
+ break;
+ case RK817_ID:
+ regulators = rk817_reg;
+ nregulators = RK817_NUM_REGULATORS;
+ break;
case RK818_ID:
regulators = rk818_reg;
nregulators = RK818_NUM_REGULATORS;
@@ -795,6 +1388,7 @@ static struct platform_driver rk808_regulator_driver = {
module_platform_driver(rk808_regulator_driver);
MODULE_DESCRIPTION("regulator driver for the RK805/RK808/RK818 series PMICs");
+MODULE_AUTHOR("Tony xie <tony.xie@rock-chips.com>");
MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>");
MODULE_AUTHOR("Zhang Qing <zhangqing@rock-chips.com>");
MODULE_AUTHOR("Wadim Egorov <w.egorov@phytec.de>");
diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c
index 134c62db36c5..054baaadfdfd 100644
--- a/drivers/regulator/s2mps11.c
+++ b/drivers/regulator/s2mps11.c
@@ -34,7 +34,7 @@ struct s2mps11_info {
enum sec_device_type dev_type;
/*
- * One bit for each S2MPS13/S2MPS14/S2MPU02 regulator whether
+ * One bit for each S2MPS11/S2MPS13/S2MPS14/S2MPU02 regulator whether
* the suspend mode was enabled.
*/
DECLARE_BITMAP(suspend_state, S2MPS_REGULATOR_MAX);
@@ -70,10 +70,11 @@ static int s2mps11_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
unsigned int new_selector)
{
struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev);
+ int rdev_id = rdev_get_id(rdev);
unsigned int ramp_delay = 0;
int old_volt, new_volt;
- switch (rdev_get_id(rdev)) {
+ switch (rdev_id) {
case S2MPS11_BUCK2:
ramp_delay = s2mps11->ramp_delay2;
break;
@@ -111,9 +112,10 @@ static int s2mps11_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev);
unsigned int ramp_val, ramp_shift, ramp_reg = S2MPS11_REG_RAMP_BUCK;
unsigned int ramp_enable = 1, enable_shift = 0;
+ int rdev_id = rdev_get_id(rdev);
int ret;
- switch (rdev_get_id(rdev)) {
+ switch (rdev_id) {
case S2MPS11_BUCK1:
if (ramp_delay > s2mps11->ramp_delay16)
s2mps11->ramp_delay16 = ramp_delay;
@@ -203,9 +205,8 @@ static int s2mps11_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
goto ramp_disable;
/* Ramp delay can be enabled/disabled only for buck[2346] */
- if ((rdev_get_id(rdev) >= S2MPS11_BUCK2 &&
- rdev_get_id(rdev) <= S2MPS11_BUCK4) ||
- rdev_get_id(rdev) == S2MPS11_BUCK6) {
+ if ((rdev_id >= S2MPS11_BUCK2 && rdev_id <= S2MPS11_BUCK4) ||
+ rdev_id == S2MPS11_BUCK6) {
ret = regmap_update_bits(rdev->regmap, S2MPS11_REG_RAMP,
1 << enable_shift, 1 << enable_shift);
if (ret) {
@@ -224,27 +225,133 @@ ramp_disable:
1 << enable_shift, 0);
}
+static int s2mps11_regulator_enable(struct regulator_dev *rdev)
+{
+ struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev);
+ int rdev_id = rdev_get_id(rdev);
+ unsigned int val;
+
+ switch (s2mps11->dev_type) {
+ case S2MPS11X:
+ if (test_bit(rdev_id, s2mps11->suspend_state))
+ val = S2MPS14_ENABLE_SUSPEND;
+ else
+ val = rdev->desc->enable_mask;
+ break;
+ case S2MPS13X:
+ case S2MPS14X:
+ if (test_bit(rdev_id, s2mps11->suspend_state))
+ val = S2MPS14_ENABLE_SUSPEND;
+ else if (s2mps11->ext_control_gpiod[rdev_id])
+ val = S2MPS14_ENABLE_EXT_CONTROL;
+ else
+ val = rdev->desc->enable_mask;
+ break;
+ case S2MPU02:
+ if (test_bit(rdev_id, s2mps11->suspend_state))
+ val = S2MPU02_ENABLE_SUSPEND;
+ else
+ val = rdev->desc->enable_mask;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+ rdev->desc->enable_mask, val);
+}
+
+static int s2mps11_regulator_set_suspend_disable(struct regulator_dev *rdev)
+{
+ int ret;
+ unsigned int val, state;
+ struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev);
+ int rdev_id = rdev_get_id(rdev);
+
+ /* Below LDO should be always on or does not support suspend mode. */
+ switch (s2mps11->dev_type) {
+ case S2MPS11X:
+ switch (rdev_id) {
+ case S2MPS11_LDO2:
+ case S2MPS11_LDO36:
+ case S2MPS11_LDO37:
+ case S2MPS11_LDO38:
+ return 0;
+ default:
+ state = S2MPS14_ENABLE_SUSPEND;
+ break;
+ }
+ break;
+ case S2MPS13X:
+ case S2MPS14X:
+ switch (rdev_id) {
+ case S2MPS14_LDO3:
+ return 0;
+ default:
+ state = S2MPS14_ENABLE_SUSPEND;
+ break;
+ }
+ break;
+ case S2MPU02:
+ switch (rdev_id) {
+ case S2MPU02_LDO13:
+ case S2MPU02_LDO14:
+ case S2MPU02_LDO15:
+ case S2MPU02_LDO17:
+ case S2MPU02_BUCK7:
+ state = S2MPU02_DISABLE_SUSPEND;
+ break;
+ default:
+ state = S2MPU02_ENABLE_SUSPEND;
+ break;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, &val);
+ if (ret < 0)
+ return ret;
+
+ set_bit(rdev_id, s2mps11->suspend_state);
+ /*
+ * Don't enable suspend mode if regulator is already disabled because
+ * this would effectively for a short time turn on the regulator after
+ * resuming.
+ * However we still want to toggle the suspend_state bit for regulator
+ * in case if it got enabled before suspending the system.
+ */
+ if (!(val & rdev->desc->enable_mask))
+ return 0;
+
+ return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+ rdev->desc->enable_mask, state);
+}
+
static const struct regulator_ops s2mps11_ldo_ops = {
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
.is_enabled = regulator_is_enabled_regmap,
- .enable = regulator_enable_regmap,
+ .enable = s2mps11_regulator_enable,
.disable = regulator_disable_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .set_suspend_disable = s2mps11_regulator_set_suspend_disable,
};
static const struct regulator_ops s2mps11_buck_ops = {
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
.is_enabled = regulator_is_enabled_regmap,
- .enable = regulator_enable_regmap,
+ .enable = s2mps11_regulator_enable,
.disable = regulator_disable_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.set_voltage_time_sel = s2mps11_regulator_set_voltage_time_sel,
.set_ramp_delay = s2mps11_set_ramp_delay,
+ .set_suspend_disable = s2mps11_regulator_set_suspend_disable,
};
#define regulator_desc_s2mps11_ldo(num, step) { \
@@ -269,9 +376,10 @@ static const struct regulator_ops s2mps11_buck_ops = {
.ops = &s2mps11_buck_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
- .min_uV = MIN_600_MV, \
+ .min_uV = MIN_650_MV, \
.uV_step = STEP_6_25_MV, \
- .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \
+ .linear_min_sel = 8, \
+ .n_voltages = S2MPS11_BUCK12346_N_VOLTAGES, \
.ramp_delay = S2MPS11_RAMP_DELAY, \
.vsel_reg = S2MPS11_REG_B1CTRL2 + (num - 1) * 2, \
.vsel_mask = S2MPS11_BUCK_VSEL_MASK, \
@@ -285,9 +393,10 @@ static const struct regulator_ops s2mps11_buck_ops = {
.ops = &s2mps11_buck_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
- .min_uV = MIN_600_MV, \
+ .min_uV = MIN_650_MV, \
.uV_step = STEP_6_25_MV, \
- .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \
+ .linear_min_sel = 8, \
+ .n_voltages = S2MPS11_BUCK5_N_VOLTAGES, \
.ramp_delay = S2MPS11_RAMP_DELAY, \
.vsel_reg = S2MPS11_REG_B5CTRL2, \
.vsel_mask = S2MPS11_BUCK_VSEL_MASK, \
@@ -295,7 +404,7 @@ static const struct regulator_ops s2mps11_buck_ops = {
.enable_mask = S2MPS11_ENABLE_MASK \
}
-#define regulator_desc_s2mps11_buck67810(num, min, step) { \
+#define regulator_desc_s2mps11_buck67810(num, min, step, min_sel, voltages) { \
.name = "BUCK"#num, \
.id = S2MPS11_BUCK##num, \
.ops = &s2mps11_buck_ops, \
@@ -303,7 +412,8 @@ static const struct regulator_ops s2mps11_buck_ops = {
.owner = THIS_MODULE, \
.min_uV = min, \
.uV_step = step, \
- .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \
+ .linear_min_sel = min_sel, \
+ .n_voltages = voltages, \
.ramp_delay = S2MPS11_RAMP_DELAY, \
.vsel_reg = S2MPS11_REG_B6CTRL2 + (num - 6) * 2, \
.vsel_mask = S2MPS11_BUCK_VSEL_MASK, \
@@ -371,11 +481,15 @@ static const struct regulator_desc s2mps11_regulators[] = {
regulator_desc_s2mps11_buck1_4(3),
regulator_desc_s2mps11_buck1_4(4),
regulator_desc_s2mps11_buck5,
- regulator_desc_s2mps11_buck67810(6, MIN_600_MV, STEP_6_25_MV),
- regulator_desc_s2mps11_buck67810(7, MIN_600_MV, STEP_12_5_MV),
- regulator_desc_s2mps11_buck67810(8, MIN_600_MV, STEP_12_5_MV),
+ regulator_desc_s2mps11_buck67810(6, MIN_650_MV, STEP_6_25_MV, 8,
+ S2MPS11_BUCK12346_N_VOLTAGES),
+ regulator_desc_s2mps11_buck67810(7, MIN_750_MV, STEP_12_5_MV, 0,
+ S2MPS11_BUCK7810_N_VOLTAGES),
+ regulator_desc_s2mps11_buck67810(8, MIN_750_MV, STEP_12_5_MV, 0,
+ S2MPS11_BUCK7810_N_VOLTAGES),
regulator_desc_s2mps11_buck9,
- regulator_desc_s2mps11_buck67810(10, MIN_750_MV, STEP_12_5_MV),
+ regulator_desc_s2mps11_buck67810(10, MIN_750_MV, STEP_12_5_MV, 0,
+ S2MPS11_BUCK7810_N_VOLTAGES),
};
static const struct regulator_ops s2mps14_reg_ops;
@@ -500,101 +614,16 @@ static const struct regulator_desc s2mps13_regulators[] = {
regulator_desc_s2mps13_buck8_10(10, MIN_500_MV, STEP_6_25_MV, 0x10),
};
-static int s2mps14_regulator_enable(struct regulator_dev *rdev)
-{
- struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev);
- unsigned int val;
-
- switch (s2mps11->dev_type) {
- case S2MPS13X:
- case S2MPS14X:
- if (test_bit(rdev_get_id(rdev), s2mps11->suspend_state))
- val = S2MPS14_ENABLE_SUSPEND;
- else if (s2mps11->ext_control_gpiod[rdev_get_id(rdev)])
- val = S2MPS14_ENABLE_EXT_CONTROL;
- else
- val = rdev->desc->enable_mask;
- break;
- case S2MPU02:
- if (test_bit(rdev_get_id(rdev), s2mps11->suspend_state))
- val = S2MPU02_ENABLE_SUSPEND;
- else
- val = rdev->desc->enable_mask;
- break;
- default:
- return -EINVAL;
- }
-
- return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
- rdev->desc->enable_mask, val);
-}
-
-static int s2mps14_regulator_set_suspend_disable(struct regulator_dev *rdev)
-{
- int ret;
- unsigned int val, state;
- struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev);
- int rdev_id = rdev_get_id(rdev);
-
- /* Below LDO should be always on or does not support suspend mode. */
- switch (s2mps11->dev_type) {
- case S2MPS13X:
- case S2MPS14X:
- switch (rdev_id) {
- case S2MPS14_LDO3:
- return 0;
- default:
- state = S2MPS14_ENABLE_SUSPEND;
- break;
- }
- break;
- case S2MPU02:
- switch (rdev_id) {
- case S2MPU02_LDO13:
- case S2MPU02_LDO14:
- case S2MPU02_LDO15:
- case S2MPU02_LDO17:
- case S2MPU02_BUCK7:
- state = S2MPU02_DISABLE_SUSPEND;
- break;
- default:
- state = S2MPU02_ENABLE_SUSPEND;
- break;
- }
- break;
- default:
- return -EINVAL;
- }
-
- ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, &val);
- if (ret < 0)
- return ret;
-
- set_bit(rdev_get_id(rdev), s2mps11->suspend_state);
- /*
- * Don't enable suspend mode if regulator is already disabled because
- * this would effectively for a short time turn on the regulator after
- * resuming.
- * However we still want to toggle the suspend_state bit for regulator
- * in case if it got enabled before suspending the system.
- */
- if (!(val & rdev->desc->enable_mask))
- return 0;
-
- return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
- rdev->desc->enable_mask, state);
-}
-
static const struct regulator_ops s2mps14_reg_ops = {
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
.is_enabled = regulator_is_enabled_regmap,
- .enable = s2mps14_regulator_enable,
+ .enable = s2mps11_regulator_enable,
.disable = regulator_disable_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
- .set_suspend_disable = s2mps14_regulator_set_suspend_disable,
+ .set_suspend_disable = s2mps11_regulator_set_suspend_disable,
};
#define regulator_desc_s2mps14_ldo(num, min, step) { \
@@ -821,9 +850,12 @@ static void s2mps14_pmic_dt_parse_ext_control_gpio(struct platform_device *pdev,
0,
GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE,
"s2mps11-regulator");
- if (IS_ERR(gpio[reg])) {
+ if (PTR_ERR(gpio[reg]) == -ENOENT)
+ gpio[reg] = NULL;
+ else if (IS_ERR(gpio[reg])) {
dev_err(&pdev->dev, "Failed to get control GPIO for %d/%s\n",
reg, rdata[reg].name);
+ gpio[reg] = NULL;
continue;
}
if (gpio[reg])
@@ -856,8 +888,9 @@ static int s2mps11_pmic_dt_parse(struct platform_device *pdev,
static int s2mpu02_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
{
unsigned int ramp_val, ramp_shift, ramp_reg;
+ int rdev_id = rdev_get_id(rdev);
- switch (rdev_get_id(rdev)) {
+ switch (rdev_id) {
case S2MPU02_BUCK1:
ramp_shift = S2MPU02_BUCK1_RAMP_SHIFT;
break;
@@ -885,24 +918,24 @@ static const struct regulator_ops s2mpu02_ldo_ops = {
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
.is_enabled = regulator_is_enabled_regmap,
- .enable = s2mps14_regulator_enable,
+ .enable = s2mps11_regulator_enable,
.disable = regulator_disable_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
- .set_suspend_disable = s2mps14_regulator_set_suspend_disable,
+ .set_suspend_disable = s2mps11_regulator_set_suspend_disable,
};
static const struct regulator_ops s2mpu02_buck_ops = {
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
.is_enabled = regulator_is_enabled_regmap,
- .enable = s2mps14_regulator_enable,
+ .enable = s2mps11_regulator_enable,
.disable = regulator_disable_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
- .set_suspend_disable = s2mps14_regulator_set_suspend_disable,
+ .set_suspend_disable = s2mps11_regulator_set_suspend_disable,
.set_ramp_delay = s2mpu02_set_ramp_delay,
};
diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c
index bb9d1a083299..6ca27e9d5ef7 100644
--- a/drivers/regulator/s5m8767.c
+++ b/drivers/regulator/s5m8767.c
@@ -574,7 +574,9 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
0,
GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE,
"s5m8767");
- if (IS_ERR(rdata->ext_control_gpiod))
+ if (PTR_ERR(rdata->ext_control_gpiod) == -ENOENT)
+ rdata->ext_control_gpiod = NULL;
+ else if (IS_ERR(rdata->ext_control_gpiod))
return PTR_ERR(rdata->ext_control_gpiod);
rdata->id = i;
diff --git a/drivers/regulator/slg51000-regulator.c b/drivers/regulator/slg51000-regulator.c
new file mode 100644
index 000000000000..04b732991d69
--- /dev/null
+++ b/drivers/regulator/slg51000-regulator.c
@@ -0,0 +1,523 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// SLG51000 High PSRR, Multi-Output Regulators
+// Copyright (C) 2019 Dialog Semiconductor
+//
+// Author: Eric Jeong <eric.jeong.opensource@diasemi.com>
+
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include "slg51000-regulator.h"
+
+#define SLG51000_SCTL_EVT 7
+#define SLG51000_MAX_EVT_REGISTER 8
+#define SLG51000_LDOHP_LV_MIN 1200000
+#define SLG51000_LDOHP_HV_MIN 2400000
+
+enum slg51000_regulators {
+ SLG51000_REGULATOR_LDO1 = 0,
+ SLG51000_REGULATOR_LDO2,
+ SLG51000_REGULATOR_LDO3,
+ SLG51000_REGULATOR_LDO4,
+ SLG51000_REGULATOR_LDO5,
+ SLG51000_REGULATOR_LDO6,
+ SLG51000_REGULATOR_LDO7,
+ SLG51000_MAX_REGULATORS,
+};
+
+struct slg51000 {
+ struct device *dev;
+ struct regmap *regmap;
+ struct regulator_desc *rdesc[SLG51000_MAX_REGULATORS];
+ struct regulator_dev *rdev[SLG51000_MAX_REGULATORS];
+ struct gpio_desc *cs_gpiod;
+ int chip_irq;
+};
+
+struct slg51000_evt_sta {
+ unsigned int ereg;
+ unsigned int sreg;
+};
+
+static const struct slg51000_evt_sta es_reg[SLG51000_MAX_EVT_REGISTER] = {
+ {SLG51000_LDO1_EVENT, SLG51000_LDO1_STATUS},
+ {SLG51000_LDO2_EVENT, SLG51000_LDO2_STATUS},
+ {SLG51000_LDO3_EVENT, SLG51000_LDO3_STATUS},
+ {SLG51000_LDO4_EVENT, SLG51000_LDO4_STATUS},
+ {SLG51000_LDO5_EVENT, SLG51000_LDO5_STATUS},
+ {SLG51000_LDO6_EVENT, SLG51000_LDO6_STATUS},
+ {SLG51000_LDO7_EVENT, SLG51000_LDO7_STATUS},
+ {SLG51000_SYSCTL_EVENT, SLG51000_SYSCTL_STATUS},
+};
+
+static const struct regmap_range slg51000_writeable_ranges[] = {
+ regmap_reg_range(SLG51000_SYSCTL_MATRIX_CONF_A,
+ SLG51000_SYSCTL_MATRIX_CONF_A),
+ regmap_reg_range(SLG51000_LDO1_VSEL, SLG51000_LDO1_VSEL),
+ regmap_reg_range(SLG51000_LDO1_MINV, SLG51000_LDO1_MAXV),
+ regmap_reg_range(SLG51000_LDO1_IRQ_MASK, SLG51000_LDO1_IRQ_MASK),
+ regmap_reg_range(SLG51000_LDO2_VSEL, SLG51000_LDO2_VSEL),
+ regmap_reg_range(SLG51000_LDO2_MINV, SLG51000_LDO2_MAXV),
+ regmap_reg_range(SLG51000_LDO2_IRQ_MASK, SLG51000_LDO2_IRQ_MASK),
+ regmap_reg_range(SLG51000_LDO3_VSEL, SLG51000_LDO3_VSEL),
+ regmap_reg_range(SLG51000_LDO3_MINV, SLG51000_LDO3_MAXV),
+ regmap_reg_range(SLG51000_LDO3_IRQ_MASK, SLG51000_LDO3_IRQ_MASK),
+ regmap_reg_range(SLG51000_LDO4_VSEL, SLG51000_LDO4_VSEL),
+ regmap_reg_range(SLG51000_LDO4_MINV, SLG51000_LDO4_MAXV),
+ regmap_reg_range(SLG51000_LDO4_IRQ_MASK, SLG51000_LDO4_IRQ_MASK),
+ regmap_reg_range(SLG51000_LDO5_VSEL, SLG51000_LDO5_VSEL),
+ regmap_reg_range(SLG51000_LDO5_MINV, SLG51000_LDO5_MAXV),
+ regmap_reg_range(SLG51000_LDO5_IRQ_MASK, SLG51000_LDO5_IRQ_MASK),
+ regmap_reg_range(SLG51000_LDO6_VSEL, SLG51000_LDO6_VSEL),
+ regmap_reg_range(SLG51000_LDO6_MINV, SLG51000_LDO6_MAXV),
+ regmap_reg_range(SLG51000_LDO6_IRQ_MASK, SLG51000_LDO6_IRQ_MASK),
+ regmap_reg_range(SLG51000_LDO7_VSEL, SLG51000_LDO7_VSEL),
+ regmap_reg_range(SLG51000_LDO7_MINV, SLG51000_LDO7_MAXV),
+ regmap_reg_range(SLG51000_LDO7_IRQ_MASK, SLG51000_LDO7_IRQ_MASK),
+ regmap_reg_range(SLG51000_OTP_IRQ_MASK, SLG51000_OTP_IRQ_MASK),
+};
+
+static const struct regmap_range slg51000_readable_ranges[] = {
+ regmap_reg_range(SLG51000_SYSCTL_PATN_ID_B0,
+ SLG51000_SYSCTL_PATN_ID_B2),
+ regmap_reg_range(SLG51000_SYSCTL_SYS_CONF_A,
+ SLG51000_SYSCTL_SYS_CONF_A),
+ regmap_reg_range(SLG51000_SYSCTL_SYS_CONF_D,
+ SLG51000_SYSCTL_MATRIX_CONF_B),
+ regmap_reg_range(SLG51000_SYSCTL_REFGEN_CONF_C,
+ SLG51000_SYSCTL_UVLO_CONF_A),
+ regmap_reg_range(SLG51000_SYSCTL_FAULT_LOG1, SLG51000_SYSCTL_IRQ_MASK),
+ regmap_reg_range(SLG51000_IO_GPIO1_CONF, SLG51000_IO_GPIO_STATUS),
+ regmap_reg_range(SLG51000_LUTARRAY_LUT_VAL_0,
+ SLG51000_LUTARRAY_LUT_VAL_11),
+ regmap_reg_range(SLG51000_MUXARRAY_INPUT_SEL_0,
+ SLG51000_MUXARRAY_INPUT_SEL_63),
+ regmap_reg_range(SLG51000_PWRSEQ_RESOURCE_EN_0,
+ SLG51000_PWRSEQ_INPUT_SENSE_CONF_B),
+ regmap_reg_range(SLG51000_LDO1_VSEL, SLG51000_LDO1_VSEL),
+ regmap_reg_range(SLG51000_LDO1_MINV, SLG51000_LDO1_MAXV),
+ regmap_reg_range(SLG51000_LDO1_MISC1, SLG51000_LDO1_VSEL_ACTUAL),
+ regmap_reg_range(SLG51000_LDO1_EVENT, SLG51000_LDO1_IRQ_MASK),
+ regmap_reg_range(SLG51000_LDO2_VSEL, SLG51000_LDO2_VSEL),
+ regmap_reg_range(SLG51000_LDO2_MINV, SLG51000_LDO2_MAXV),
+ regmap_reg_range(SLG51000_LDO2_MISC1, SLG51000_LDO2_VSEL_ACTUAL),
+ regmap_reg_range(SLG51000_LDO2_EVENT, SLG51000_LDO2_IRQ_MASK),
+ regmap_reg_range(SLG51000_LDO3_VSEL, SLG51000_LDO3_VSEL),
+ regmap_reg_range(SLG51000_LDO3_MINV, SLG51000_LDO3_MAXV),
+ regmap_reg_range(SLG51000_LDO3_CONF1, SLG51000_LDO3_VSEL_ACTUAL),
+ regmap_reg_range(SLG51000_LDO3_EVENT, SLG51000_LDO3_IRQ_MASK),
+ regmap_reg_range(SLG51000_LDO4_VSEL, SLG51000_LDO4_VSEL),
+ regmap_reg_range(SLG51000_LDO4_MINV, SLG51000_LDO4_MAXV),
+ regmap_reg_range(SLG51000_LDO4_CONF1, SLG51000_LDO4_VSEL_ACTUAL),
+ regmap_reg_range(SLG51000_LDO4_EVENT, SLG51000_LDO4_IRQ_MASK),
+ regmap_reg_range(SLG51000_LDO5_VSEL, SLG51000_LDO5_VSEL),
+ regmap_reg_range(SLG51000_LDO5_MINV, SLG51000_LDO5_MAXV),
+ regmap_reg_range(SLG51000_LDO5_TRIM2, SLG51000_LDO5_TRIM2),
+ regmap_reg_range(SLG51000_LDO5_CONF1, SLG51000_LDO5_VSEL_ACTUAL),
+ regmap_reg_range(SLG51000_LDO5_EVENT, SLG51000_LDO5_IRQ_MASK),
+ regmap_reg_range(SLG51000_LDO6_VSEL, SLG51000_LDO6_VSEL),
+ regmap_reg_range(SLG51000_LDO6_MINV, SLG51000_LDO6_MAXV),
+ regmap_reg_range(SLG51000_LDO6_TRIM2, SLG51000_LDO6_TRIM2),
+ regmap_reg_range(SLG51000_LDO6_CONF1, SLG51000_LDO6_VSEL_ACTUAL),
+ regmap_reg_range(SLG51000_LDO6_EVENT, SLG51000_LDO6_IRQ_MASK),
+ regmap_reg_range(SLG51000_LDO7_VSEL, SLG51000_LDO7_VSEL),
+ regmap_reg_range(SLG51000_LDO7_MINV, SLG51000_LDO7_MAXV),
+ regmap_reg_range(SLG51000_LDO7_CONF1, SLG51000_LDO7_VSEL_ACTUAL),
+ regmap_reg_range(SLG51000_LDO7_EVENT, SLG51000_LDO7_IRQ_MASK),
+ regmap_reg_range(SLG51000_OTP_EVENT, SLG51000_OTP_EVENT),
+ regmap_reg_range(SLG51000_OTP_IRQ_MASK, SLG51000_OTP_IRQ_MASK),
+ regmap_reg_range(SLG51000_OTP_LOCK_OTP_PROG, SLG51000_OTP_LOCK_CTRL),
+ regmap_reg_range(SLG51000_LOCK_GLOBAL_LOCK_CTRL1,
+ SLG51000_LOCK_GLOBAL_LOCK_CTRL1),
+};
+
+static const struct regmap_range slg51000_volatile_ranges[] = {
+ regmap_reg_range(SLG51000_SYSCTL_FAULT_LOG1, SLG51000_SYSCTL_STATUS),
+ regmap_reg_range(SLG51000_IO_GPIO_STATUS, SLG51000_IO_GPIO_STATUS),
+ regmap_reg_range(SLG51000_LDO1_EVENT, SLG51000_LDO1_STATUS),
+ regmap_reg_range(SLG51000_LDO2_EVENT, SLG51000_LDO2_STATUS),
+ regmap_reg_range(SLG51000_LDO3_EVENT, SLG51000_LDO3_STATUS),
+ regmap_reg_range(SLG51000_LDO4_EVENT, SLG51000_LDO4_STATUS),
+ regmap_reg_range(SLG51000_LDO5_EVENT, SLG51000_LDO5_STATUS),
+ regmap_reg_range(SLG51000_LDO6_EVENT, SLG51000_LDO6_STATUS),
+ regmap_reg_range(SLG51000_LDO7_EVENT, SLG51000_LDO7_STATUS),
+ regmap_reg_range(SLG51000_OTP_EVENT, SLG51000_OTP_EVENT),
+};
+
+static const struct regmap_access_table slg51000_writeable_table = {
+ .yes_ranges = slg51000_writeable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(slg51000_writeable_ranges),
+};
+
+static const struct regmap_access_table slg51000_readable_table = {
+ .yes_ranges = slg51000_readable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(slg51000_readable_ranges),
+};
+
+static const struct regmap_access_table slg51000_volatile_table = {
+ .yes_ranges = slg51000_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(slg51000_volatile_ranges),
+};
+
+static const struct regmap_config slg51000_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = 0x8000,
+ .wr_table = &slg51000_writeable_table,
+ .rd_table = &slg51000_readable_table,
+ .volatile_table = &slg51000_volatile_table,
+};
+
+static const struct regulator_ops slg51000_regl_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .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,
+};
+
+static const struct regulator_ops slg51000_switch_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+};
+
+static int slg51000_of_parse_cb(struct device_node *np,
+ const struct regulator_desc *desc,
+ struct regulator_config *config)
+{
+ struct slg51000 *chip = config->driver_data;
+ struct gpio_desc *ena_gpiod;
+ enum gpiod_flags gflags = GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE;
+
+ ena_gpiod = devm_gpiod_get_from_of_node(chip->dev, np,
+ "enable-gpios", 0,
+ gflags, "gpio-en-ldo");
+ if (ena_gpiod) {
+ config->ena_gpiod = ena_gpiod;
+ devm_gpiod_unhinge(chip->dev, config->ena_gpiod);
+ }
+
+ return 0;
+}
+
+#define SLG51000_REGL_DESC(_id, _name, _s_name, _min, _step) \
+ [SLG51000_REGULATOR_##_id] = { \
+ .name = #_name, \
+ .supply_name = _s_name, \
+ .id = SLG51000_REGULATOR_##_id, \
+ .of_match = of_match_ptr(#_name), \
+ .of_parse_cb = slg51000_of_parse_cb, \
+ .ops = &slg51000_regl_ops, \
+ .regulators_node = of_match_ptr("regulators"), \
+ .n_voltages = 256, \
+ .min_uV = _min, \
+ .uV_step = _step, \
+ .linear_min_sel = 0, \
+ .vsel_mask = SLG51000_VSEL_MASK, \
+ .vsel_reg = SLG51000_##_id##_VSEL, \
+ .enable_reg = SLG51000_SYSCTL_MATRIX_CONF_A, \
+ .enable_mask = BIT(SLG51000_REGULATOR_##_id), \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ }
+
+static struct regulator_desc regls_desc[SLG51000_MAX_REGULATORS] = {
+ SLG51000_REGL_DESC(LDO1, ldo1, NULL, 2400000, 5000),
+ SLG51000_REGL_DESC(LDO2, ldo2, NULL, 2400000, 5000),
+ SLG51000_REGL_DESC(LDO3, ldo3, "vin3", 1200000, 10000),
+ SLG51000_REGL_DESC(LDO4, ldo4, "vin4", 1200000, 10000),
+ SLG51000_REGL_DESC(LDO5, ldo5, "vin5", 400000, 5000),
+ SLG51000_REGL_DESC(LDO6, ldo6, "vin6", 400000, 5000),
+ SLG51000_REGL_DESC(LDO7, ldo7, "vin7", 1200000, 10000),
+};
+
+static int slg51000_regulator_init(struct slg51000 *chip)
+{
+ struct regulator_config config = { };
+ struct regulator_desc *rdesc;
+ unsigned int reg, val;
+ u8 vsel_range[2];
+ int id, ret = 0;
+ const unsigned int min_regs[SLG51000_MAX_REGULATORS] = {
+ SLG51000_LDO1_MINV, SLG51000_LDO2_MINV, SLG51000_LDO3_MINV,
+ SLG51000_LDO4_MINV, SLG51000_LDO5_MINV, SLG51000_LDO6_MINV,
+ SLG51000_LDO7_MINV,
+ };
+
+ for (id = 0; id < SLG51000_MAX_REGULATORS; id++) {
+ chip->rdesc[id] = &regls_desc[id];
+ rdesc = chip->rdesc[id];
+ config.regmap = chip->regmap;
+ config.dev = chip->dev;
+ config.driver_data = chip;
+
+ ret = regmap_bulk_read(chip->regmap, min_regs[id],
+ vsel_range, 2);
+ if (ret < 0) {
+ dev_err(chip->dev,
+ "Failed to read the MIN register\n");
+ return ret;
+ }
+
+ switch (id) {
+ case SLG51000_REGULATOR_LDO1:
+ case SLG51000_REGULATOR_LDO2:
+ if (id == SLG51000_REGULATOR_LDO1)
+ reg = SLG51000_LDO1_MISC1;
+ else
+ reg = SLG51000_LDO2_MISC1;
+
+ ret = regmap_read(chip->regmap, reg, &val);
+ if (ret < 0) {
+ dev_err(chip->dev,
+ "Failed to read voltage range of ldo%d\n",
+ id + 1);
+ return ret;
+ }
+
+ rdesc->linear_min_sel = vsel_range[0];
+ rdesc->n_voltages = vsel_range[1] + 1;
+ if (val & SLG51000_SEL_VRANGE_MASK)
+ rdesc->min_uV = SLG51000_LDOHP_HV_MIN
+ + (vsel_range[0]
+ * rdesc->uV_step);
+ else
+ rdesc->min_uV = SLG51000_LDOHP_LV_MIN
+ + (vsel_range[0]
+ * rdesc->uV_step);
+ break;
+
+ case SLG51000_REGULATOR_LDO5:
+ case SLG51000_REGULATOR_LDO6:
+ if (id == SLG51000_REGULATOR_LDO5)
+ reg = SLG51000_LDO5_TRIM2;
+ else
+ reg = SLG51000_LDO6_TRIM2;
+
+ ret = regmap_read(chip->regmap, reg, &val);
+ if (ret < 0) {
+ dev_err(chip->dev,
+ "Failed to read LDO mode register\n");
+ return ret;
+ }
+
+ if (val & SLG51000_SEL_BYP_MODE_MASK) {
+ rdesc->ops = &slg51000_switch_ops;
+ rdesc->n_voltages = 0;
+ rdesc->min_uV = 0;
+ rdesc->uV_step = 0;
+ rdesc->linear_min_sel = 0;
+ break;
+ }
+ /* Fall through - to the check below.*/
+
+ default:
+ rdesc->linear_min_sel = vsel_range[0];
+ rdesc->n_voltages = vsel_range[1] + 1;
+ rdesc->min_uV = rdesc->min_uV
+ + (vsel_range[0] * rdesc->uV_step);
+ break;
+ }
+
+ chip->rdev[id] = devm_regulator_register(chip->dev, rdesc,
+ &config);
+ if (IS_ERR(chip->rdev[id])) {
+ ret = PTR_ERR(chip->rdev[id]);
+ dev_err(chip->dev,
+ "Failed to register regulator(%s):%d\n",
+ chip->rdesc[id]->name, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static irqreturn_t slg51000_irq_handler(int irq, void *data)
+{
+ struct slg51000 *chip = data;
+ struct regmap *regmap = chip->regmap;
+ enum { R0 = 0, R1, R2, REG_MAX };
+ u8 evt[SLG51000_MAX_EVT_REGISTER][REG_MAX];
+ int ret, i, handled = IRQ_NONE;
+ unsigned int evt_otp, mask_otp;
+
+ /* Read event[R0], status[R1] and mask[R2] register */
+ for (i = 0; i < SLG51000_MAX_EVT_REGISTER; i++) {
+ ret = regmap_bulk_read(regmap, es_reg[i].ereg, evt[i], REG_MAX);
+ if (ret < 0) {
+ dev_err(chip->dev,
+ "Failed to read event registers(%d)\n", ret);
+ return IRQ_NONE;
+ }
+ }
+
+ ret = regmap_read(regmap, SLG51000_OTP_EVENT, &evt_otp);
+ if (ret < 0) {
+ dev_err(chip->dev,
+ "Failed to read otp event registers(%d)\n", ret);
+ return IRQ_NONE;
+ }
+
+ ret = regmap_read(regmap, SLG51000_OTP_IRQ_MASK, &mask_otp);
+ if (ret < 0) {
+ dev_err(chip->dev,
+ "Failed to read otp mask register(%d)\n", ret);
+ return IRQ_NONE;
+ }
+
+ if ((evt_otp & SLG51000_EVT_CRC_MASK) &&
+ !(mask_otp & SLG51000_IRQ_CRC_MASK)) {
+ dev_info(chip->dev,
+ "OTP has been read or OTP crc is not zero\n");
+ handled = IRQ_HANDLED;
+ }
+
+ for (i = 0; i < SLG51000_MAX_REGULATORS; i++) {
+ if (!(evt[i][R2] & SLG51000_IRQ_ILIM_FLAG_MASK) &&
+ (evt[i][R0] & SLG51000_EVT_ILIM_FLAG_MASK)) {
+ regulator_lock(chip->rdev[i]);
+ regulator_notifier_call_chain(chip->rdev[i],
+ REGULATOR_EVENT_OVER_CURRENT, NULL);
+ regulator_unlock(chip->rdev[i]);
+
+ if (evt[i][R1] & SLG51000_STA_ILIM_FLAG_MASK)
+ dev_warn(chip->dev,
+ "Over-current limit(ldo%d)\n", i + 1);
+ handled = IRQ_HANDLED;
+ }
+ }
+
+ if (!(evt[SLG51000_SCTL_EVT][R2] & SLG51000_IRQ_HIGH_TEMP_WARN_MASK) &&
+ (evt[SLG51000_SCTL_EVT][R0] & SLG51000_EVT_HIGH_TEMP_WARN_MASK)) {
+ for (i = 0; i < SLG51000_MAX_REGULATORS; i++) {
+ if (!(evt[i][R1] & SLG51000_STA_ILIM_FLAG_MASK) &&
+ (evt[i][R1] & SLG51000_STA_VOUT_OK_FLAG_MASK)) {
+ regulator_lock(chip->rdev[i]);
+ regulator_notifier_call_chain(chip->rdev[i],
+ REGULATOR_EVENT_OVER_TEMP, NULL);
+ regulator_unlock(chip->rdev[i]);
+ }
+ }
+ handled = IRQ_HANDLED;
+ if (evt[SLG51000_SCTL_EVT][R1] &
+ SLG51000_STA_HIGH_TEMP_WARN_MASK)
+ dev_warn(chip->dev, "High temperature warning!\n");
+ }
+
+ return handled;
+}
+
+static void slg51000_clear_fault_log(struct slg51000 *chip)
+{
+ unsigned int val = 0;
+ int ret = 0;
+
+ ret = regmap_read(chip->regmap, SLG51000_SYSCTL_FAULT_LOG1, &val);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to read Fault log register\n");
+ return;
+ }
+
+ if (val & SLG51000_FLT_OVER_TEMP_MASK)
+ dev_dbg(chip->dev, "Fault log: FLT_OVER_TEMP\n");
+ if (val & SLG51000_FLT_POWER_SEQ_CRASH_REQ_MASK)
+ dev_dbg(chip->dev, "Fault log: FLT_POWER_SEQ_CRASH_REQ\n");
+ if (val & SLG51000_FLT_RST_MASK)
+ dev_dbg(chip->dev, "Fault log: FLT_RST\n");
+ if (val & SLG51000_FLT_POR_MASK)
+ dev_dbg(chip->dev, "Fault log: FLT_POR\n");
+}
+
+static int slg51000_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct slg51000 *chip;
+ struct gpio_desc *cs_gpiod = NULL;
+ int error, ret;
+
+ chip = devm_kzalloc(dev, sizeof(struct slg51000), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ cs_gpiod = devm_gpiod_get_from_of_node(dev, dev->of_node,
+ "dlg,cs-gpios", 0,
+ GPIOD_OUT_HIGH
+ | GPIOD_FLAGS_BIT_NONEXCLUSIVE,
+ "slg51000-cs");
+ if (cs_gpiod) {
+ dev_info(dev, "Found chip selector property\n");
+ chip->cs_gpiod = cs_gpiod;
+ }
+
+ i2c_set_clientdata(client, chip);
+ chip->chip_irq = client->irq;
+ chip->dev = dev;
+ chip->regmap = devm_regmap_init_i2c(client, &slg51000_regmap_config);
+ if (IS_ERR(chip->regmap)) {
+ error = PTR_ERR(chip->regmap);
+ dev_err(dev, "Failed to allocate register map: %d\n",
+ error);
+ return error;
+ }
+
+ ret = slg51000_regulator_init(chip);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to init regulator(%d)\n", ret);
+ return ret;
+ }
+
+ slg51000_clear_fault_log(chip);
+
+ if (chip->chip_irq) {
+ ret = devm_request_threaded_irq(dev, chip->chip_irq, NULL,
+ slg51000_irq_handler,
+ (IRQF_TRIGGER_HIGH |
+ IRQF_ONESHOT),
+ "slg51000-irq", chip);
+ if (ret != 0) {
+ dev_err(dev, "Failed to request IRQ: %d\n",
+ chip->chip_irq);
+ return ret;
+ }
+ } else {
+ dev_info(dev, "No IRQ configured\n");
+ }
+
+ return ret;
+}
+
+static const struct i2c_device_id slg51000_i2c_id[] = {
+ {"slg51000", 0},
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, slg51000_i2c_id);
+
+static struct i2c_driver slg51000_regulator_driver = {
+ .driver = {
+ .name = "slg51000-regulator",
+ },
+ .probe = slg51000_i2c_probe,
+ .id_table = slg51000_i2c_id,
+};
+
+module_i2c_driver(slg51000_regulator_driver);
+
+MODULE_AUTHOR("Eric Jeong <eric.jeong.opensource@diasemi.com>");
+MODULE_DESCRIPTION("SLG51000 regulator driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/regulator/slg51000-regulator.h b/drivers/regulator/slg51000-regulator.h
new file mode 100644
index 000000000000..20feb7f91942
--- /dev/null
+++ b/drivers/regulator/slg51000-regulator.h
@@ -0,0 +1,505 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * SLG51000 High PSRR, Multi-Output Regulators
+ * Copyright (C) 2019 Dialog Semiconductor
+ *
+ * Author: Eric Jeong <eric.jeong.opensource@diasemi.com>
+ */
+
+#ifndef __SLG51000_REGISTERS_H__
+#define __SLG51000_REGISTERS_H__
+
+/* Registers */
+
+#define SLG51000_SYSCTL_PATN_ID_B0 0x1105
+#define SLG51000_SYSCTL_PATN_ID_B1 0x1106
+#define SLG51000_SYSCTL_PATN_ID_B2 0x1107
+#define SLG51000_SYSCTL_SYS_CONF_A 0x1109
+#define SLG51000_SYSCTL_SYS_CONF_D 0x110c
+#define SLG51000_SYSCTL_MATRIX_CONF_A 0x110d
+#define SLG51000_SYSCTL_MATRIX_CONF_B 0x110e
+#define SLG51000_SYSCTL_REFGEN_CONF_C 0x1111
+#define SLG51000_SYSCTL_UVLO_CONF_A 0x1112
+#define SLG51000_SYSCTL_FAULT_LOG1 0x1115
+#define SLG51000_SYSCTL_EVENT 0x1116
+#define SLG51000_SYSCTL_STATUS 0x1117
+#define SLG51000_SYSCTL_IRQ_MASK 0x1118
+#define SLG51000_IO_GPIO1_CONF 0x1500
+#define SLG51000_IO_GPIO2_CONF 0x1501
+#define SLG51000_IO_GPIO3_CONF 0x1502
+#define SLG51000_IO_GPIO4_CONF 0x1503
+#define SLG51000_IO_GPIO5_CONF 0x1504
+#define SLG51000_IO_GPIO6_CONF 0x1505
+#define SLG51000_IO_GPIO_STATUS 0x1506
+#define SLG51000_LUTARRAY_LUT_VAL_0 0x1600
+#define SLG51000_LUTARRAY_LUT_VAL_1 0x1601
+#define SLG51000_LUTARRAY_LUT_VAL_2 0x1602
+#define SLG51000_LUTARRAY_LUT_VAL_3 0x1603
+#define SLG51000_LUTARRAY_LUT_VAL_4 0x1604
+#define SLG51000_LUTARRAY_LUT_VAL_5 0x1605
+#define SLG51000_LUTARRAY_LUT_VAL_6 0x1606
+#define SLG51000_LUTARRAY_LUT_VAL_7 0x1607
+#define SLG51000_LUTARRAY_LUT_VAL_8 0x1608
+#define SLG51000_LUTARRAY_LUT_VAL_9 0x1609
+#define SLG51000_LUTARRAY_LUT_VAL_10 0x160a
+#define SLG51000_LUTARRAY_LUT_VAL_11 0x160b
+#define SLG51000_MUXARRAY_INPUT_SEL_0 0x1700
+#define SLG51000_MUXARRAY_INPUT_SEL_1 0x1701
+#define SLG51000_MUXARRAY_INPUT_SEL_2 0x1702
+#define SLG51000_MUXARRAY_INPUT_SEL_3 0x1703
+#define SLG51000_MUXARRAY_INPUT_SEL_4 0x1704
+#define SLG51000_MUXARRAY_INPUT_SEL_5 0x1705
+#define SLG51000_MUXARRAY_INPUT_SEL_6 0x1706
+#define SLG51000_MUXARRAY_INPUT_SEL_7 0x1707
+#define SLG51000_MUXARRAY_INPUT_SEL_8 0x1708
+#define SLG51000_MUXARRAY_INPUT_SEL_9 0x1709
+#define SLG51000_MUXARRAY_INPUT_SEL_10 0x170a
+#define SLG51000_MUXARRAY_INPUT_SEL_11 0x170b
+#define SLG51000_MUXARRAY_INPUT_SEL_12 0x170c
+#define SLG51000_MUXARRAY_INPUT_SEL_13 0x170d
+#define SLG51000_MUXARRAY_INPUT_SEL_14 0x170e
+#define SLG51000_MUXARRAY_INPUT_SEL_15 0x170f
+#define SLG51000_MUXARRAY_INPUT_SEL_16 0x1710
+#define SLG51000_MUXARRAY_INPUT_SEL_17 0x1711
+#define SLG51000_MUXARRAY_INPUT_SEL_18 0x1712
+#define SLG51000_MUXARRAY_INPUT_SEL_19 0x1713
+#define SLG51000_MUXARRAY_INPUT_SEL_20 0x1714
+#define SLG51000_MUXARRAY_INPUT_SEL_21 0x1715
+#define SLG51000_MUXARRAY_INPUT_SEL_22 0x1716
+#define SLG51000_MUXARRAY_INPUT_SEL_23 0x1717
+#define SLG51000_MUXARRAY_INPUT_SEL_24 0x1718
+#define SLG51000_MUXARRAY_INPUT_SEL_25 0x1719
+#define SLG51000_MUXARRAY_INPUT_SEL_26 0x171a
+#define SLG51000_MUXARRAY_INPUT_SEL_27 0x171b
+#define SLG51000_MUXARRAY_INPUT_SEL_28 0x171c
+#define SLG51000_MUXARRAY_INPUT_SEL_29 0x171d
+#define SLG51000_MUXARRAY_INPUT_SEL_30 0x171e
+#define SLG51000_MUXARRAY_INPUT_SEL_31 0x171f
+#define SLG51000_MUXARRAY_INPUT_SEL_32 0x1720
+#define SLG51000_MUXARRAY_INPUT_SEL_33 0x1721
+#define SLG51000_MUXARRAY_INPUT_SEL_34 0x1722
+#define SLG51000_MUXARRAY_INPUT_SEL_35 0x1723
+#define SLG51000_MUXARRAY_INPUT_SEL_36 0x1724
+#define SLG51000_MUXARRAY_INPUT_SEL_37 0x1725
+#define SLG51000_MUXARRAY_INPUT_SEL_38 0x1726
+#define SLG51000_MUXARRAY_INPUT_SEL_39 0x1727
+#define SLG51000_MUXARRAY_INPUT_SEL_40 0x1728
+#define SLG51000_MUXARRAY_INPUT_SEL_41 0x1729
+#define SLG51000_MUXARRAY_INPUT_SEL_42 0x172a
+#define SLG51000_MUXARRAY_INPUT_SEL_43 0x172b
+#define SLG51000_MUXARRAY_INPUT_SEL_44 0x172c
+#define SLG51000_MUXARRAY_INPUT_SEL_45 0x172d
+#define SLG51000_MUXARRAY_INPUT_SEL_46 0x172e
+#define SLG51000_MUXARRAY_INPUT_SEL_47 0x172f
+#define SLG51000_MUXARRAY_INPUT_SEL_48 0x1730
+#define SLG51000_MUXARRAY_INPUT_SEL_49 0x1731
+#define SLG51000_MUXARRAY_INPUT_SEL_50 0x1732
+#define SLG51000_MUXARRAY_INPUT_SEL_51 0x1733
+#define SLG51000_MUXARRAY_INPUT_SEL_52 0x1734
+#define SLG51000_MUXARRAY_INPUT_SEL_53 0x1735
+#define SLG51000_MUXARRAY_INPUT_SEL_54 0x1736
+#define SLG51000_MUXARRAY_INPUT_SEL_55 0x1737
+#define SLG51000_MUXARRAY_INPUT_SEL_56 0x1738
+#define SLG51000_MUXARRAY_INPUT_SEL_57 0x1739
+#define SLG51000_MUXARRAY_INPUT_SEL_58 0x173a
+#define SLG51000_MUXARRAY_INPUT_SEL_59 0x173b
+#define SLG51000_MUXARRAY_INPUT_SEL_60 0x173c
+#define SLG51000_MUXARRAY_INPUT_SEL_61 0x173d
+#define SLG51000_MUXARRAY_INPUT_SEL_62 0x173e
+#define SLG51000_MUXARRAY_INPUT_SEL_63 0x173f
+#define SLG51000_PWRSEQ_RESOURCE_EN_0 0x1900
+#define SLG51000_PWRSEQ_RESOURCE_EN_1 0x1901
+#define SLG51000_PWRSEQ_RESOURCE_EN_2 0x1902
+#define SLG51000_PWRSEQ_RESOURCE_EN_3 0x1903
+#define SLG51000_PWRSEQ_RESOURCE_EN_4 0x1904
+#define SLG51000_PWRSEQ_RESOURCE_EN_5 0x1905
+#define SLG51000_PWRSEQ_SLOT_TIME_MIN_UP0 0x1906
+#define SLG51000_PWRSEQ_SLOT_TIME_MIN_DOWN0 0x1907
+#define SLG51000_PWRSEQ_SLOT_TIME_MIN_UP1 0x1908
+#define SLG51000_PWRSEQ_SLOT_TIME_MIN_DOWN1 0x1909
+#define SLG51000_PWRSEQ_SLOT_TIME_MIN_UP2 0x190a
+#define SLG51000_PWRSEQ_SLOT_TIME_MIN_DOWN2 0x190b
+#define SLG51000_PWRSEQ_SLOT_TIME_MIN_UP3 0x190c
+#define SLG51000_PWRSEQ_SLOT_TIME_MIN_DOWN3 0x190d
+#define SLG51000_PWRSEQ_SLOT_TIME_MIN_UP4 0x190e
+#define SLG51000_PWRSEQ_SLOT_TIME_MIN_DOWN4 0x190f
+#define SLG51000_PWRSEQ_SLOT_TIME_MIN_UP5 0x1910
+#define SLG51000_PWRSEQ_SLOT_TIME_MIN_DOWN5 0x1911
+#define SLG51000_PWRSEQ_SLOT_TIME_MAX_CONF_A 0x1912
+#define SLG51000_PWRSEQ_SLOT_TIME_MAX_CONF_B 0x1913
+#define SLG51000_PWRSEQ_SLOT_TIME_MAX_CONF_C 0x1914
+#define SLG51000_PWRSEQ_INPUT_SENSE_CONF_A 0x1915
+#define SLG51000_PWRSEQ_INPUT_SENSE_CONF_B 0x1916
+#define SLG51000_LDO1_VSEL 0x2000
+#define SLG51000_LDO1_MINV 0x2060
+#define SLG51000_LDO1_MAXV 0x2061
+#define SLG51000_LDO1_MISC1 0x2064
+#define SLG51000_LDO1_VSEL_ACTUAL 0x2065
+#define SLG51000_LDO1_EVENT 0x20c0
+#define SLG51000_LDO1_STATUS 0x20c1
+#define SLG51000_LDO1_IRQ_MASK 0x20c2
+#define SLG51000_LDO2_VSEL 0x2200
+#define SLG51000_LDO2_MINV 0x2260
+#define SLG51000_LDO2_MAXV 0x2261
+#define SLG51000_LDO2_MISC1 0x2264
+#define SLG51000_LDO2_VSEL_ACTUAL 0x2265
+#define SLG51000_LDO2_EVENT 0x22c0
+#define SLG51000_LDO2_STATUS 0x22c1
+#define SLG51000_LDO2_IRQ_MASK 0x22c2
+#define SLG51000_LDO3_VSEL 0x2300
+#define SLG51000_LDO3_MINV 0x2360
+#define SLG51000_LDO3_MAXV 0x2361
+#define SLG51000_LDO3_CONF1 0x2364
+#define SLG51000_LDO3_CONF2 0x2365
+#define SLG51000_LDO3_VSEL_ACTUAL 0x2366
+#define SLG51000_LDO3_EVENT 0x23c0
+#define SLG51000_LDO3_STATUS 0x23c1
+#define SLG51000_LDO3_IRQ_MASK 0x23c2
+#define SLG51000_LDO4_VSEL 0x2500
+#define SLG51000_LDO4_MINV 0x2560
+#define SLG51000_LDO4_MAXV 0x2561
+#define SLG51000_LDO4_CONF1 0x2564
+#define SLG51000_LDO4_CONF2 0x2565
+#define SLG51000_LDO4_VSEL_ACTUAL 0x2566
+#define SLG51000_LDO4_EVENT 0x25c0
+#define SLG51000_LDO4_STATUS 0x25c1
+#define SLG51000_LDO4_IRQ_MASK 0x25c2
+#define SLG51000_LDO5_VSEL 0x2700
+#define SLG51000_LDO5_MINV 0x2760
+#define SLG51000_LDO5_MAXV 0x2761
+#define SLG51000_LDO5_TRIM2 0x2763
+#define SLG51000_LDO5_CONF1 0x2765
+#define SLG51000_LDO5_CONF2 0x2766
+#define SLG51000_LDO5_VSEL_ACTUAL 0x2767
+#define SLG51000_LDO5_EVENT 0x27c0
+#define SLG51000_LDO5_STATUS 0x27c1
+#define SLG51000_LDO5_IRQ_MASK 0x27c2
+#define SLG51000_LDO6_VSEL 0x2900
+#define SLG51000_LDO6_MINV 0x2960
+#define SLG51000_LDO6_MAXV 0x2961
+#define SLG51000_LDO6_TRIM2 0x2963
+#define SLG51000_LDO6_CONF1 0x2965
+#define SLG51000_LDO6_CONF2 0x2966
+#define SLG51000_LDO6_VSEL_ACTUAL 0x2967
+#define SLG51000_LDO6_EVENT 0x29c0
+#define SLG51000_LDO6_STATUS 0x29c1
+#define SLG51000_LDO6_IRQ_MASK 0x29c2
+#define SLG51000_LDO7_VSEL 0x3100
+#define SLG51000_LDO7_MINV 0x3160
+#define SLG51000_LDO7_MAXV 0x3161
+#define SLG51000_LDO7_CONF1 0x3164
+#define SLG51000_LDO7_CONF2 0x3165
+#define SLG51000_LDO7_VSEL_ACTUAL 0x3166
+#define SLG51000_LDO7_EVENT 0x31c0
+#define SLG51000_LDO7_STATUS 0x31c1
+#define SLG51000_LDO7_IRQ_MASK 0x31c2
+#define SLG51000_OTP_EVENT 0x782b
+#define SLG51000_OTP_IRQ_MASK 0x782d
+#define SLG51000_OTP_LOCK_OTP_PROG 0x78fe
+#define SLG51000_OTP_LOCK_CTRL 0x78ff
+#define SLG51000_LOCK_GLOBAL_LOCK_CTRL1 0x8000
+
+/* Register Bit Fields */
+
+/* SLG51000_SYSCTL_PATTERN_ID_BYTE0 = 0x1105 */
+#define SLG51000_PATTERN_ID_BYTE0_SHIFT 0
+#define SLG51000_PATTERN_ID_BYTE0_MASK (0xff << 0)
+
+/* SLG51000_SYSCTL_PATTERN_ID_BYTE1 = 0x1106 */
+#define SLG51000_PATTERN_ID_BYTE1_SHIFT 0
+#define SLG51000_PATTERN_ID_BYTE1_MASK (0xff << 0)
+
+/* SLG51000_SYSCTL_PATTERN_ID_BYTE2 = 0x1107 */
+#define SLG51000_PATTERN_ID_BYTE2_SHIFT 0
+#define SLG51000_PATTERN_ID_BYTE2_MASK (0xff << 0)
+
+/* SLG51000_SYSCTL_SYS_CONF_A = 0x1109 */
+#define SLG51000_I2C_ADDRESS_SHIFT 0
+#define SLG51000_I2C_ADDRESS_MASK (0x7f << 0)
+#define SLG51000_I2C_DISABLE_SHIFT 7
+#define SLG51000_I2C_DISABLE_MASK (0x01 << 7)
+
+/* SLG51000_SYSCTL_SYS_CONF_D = 0x110c */
+#define SLG51000_CS_T_DEB_SHIFT 6
+#define SLG51000_CS_T_DEB_MASK (0x03 << 6)
+#define SLG51000_I2C_CLR_MODE_SHIFT 5
+#define SLG51000_I2C_CLR_MODE_MASK (0x01 << 5)
+
+/* SLG51000_SYSCTL_MATRIX_CTRL_CONF_A = 0x110d */
+#define SLG51000_RESOURCE_CTRL_SHIFT 0
+#define SLG51000_RESOURCE_CTRL_MASK (0xff << 0)
+
+/* SLG51000_SYSCTL_MATRIX_CTRL_CONF_B = 0x110e */
+#define SLG51000_MATRIX_EVENT_SENSE_SHIFT 0
+#define SLG51000_MATRIX_EVENT_SENSE_MASK (0x07 << 0)
+
+/* SLG51000_SYSCTL_REFGEN_CONF_C = 0x1111 */
+#define SLG51000_REFGEN_SEL_TEMP_WARN_DEBOUNCE_SHIFT 2
+#define SLG51000_REFGEN_SEL_TEMP_WARN_DEBOUNCE_MASK (0x03 << 2)
+#define SLG51000_REFGEN_SEL_TEMP_WARN_THR_SHIFT 0
+#define SLG51000_REFGEN_SEL_TEMP_WARN_THR_MASK (0x03 << 0)
+
+/* SLG51000_SYSCTL_UVLO_CONF_A = 0x1112 */
+#define SLG51000_VMON_UVLO_SEL_THR_SHIFT 0
+#define SLG51000_VMON_UVLO_SEL_THR_MASK (0x1f << 0)
+
+/* SLG51000_SYSCTL_FAULT_LOG1 = 0x1115 */
+#define SLG51000_FLT_POR_SHIFT 5
+#define SLG51000_FLT_POR_MASK (0x01 << 5)
+#define SLG51000_FLT_RST_SHIFT 4
+#define SLG51000_FLT_RST_MASK (0x01 << 4)
+#define SLG51000_FLT_POWER_SEQ_CRASH_REQ_SHIFT 2
+#define SLG51000_FLT_POWER_SEQ_CRASH_REQ_MASK (0x01 << 2)
+#define SLG51000_FLT_OVER_TEMP_SHIFT 1
+#define SLG51000_FLT_OVER_TEMP_MASK (0x01 << 1)
+
+/* SLG51000_SYSCTL_EVENT = 0x1116 */
+#define SLG51000_EVT_MATRIX_SHIFT 1
+#define SLG51000_EVT_MATRIX_MASK (0x01 << 1)
+#define SLG51000_EVT_HIGH_TEMP_WARN_SHIFT 0
+#define SLG51000_EVT_HIGH_TEMP_WARN_MASK (0x01 << 0)
+
+/* SLG51000_SYSCTL_STATUS = 0x1117 */
+#define SLG51000_STA_MATRIX_SHIFT 1
+#define SLG51000_STA_MATRIX_MASK (0x01 << 1)
+#define SLG51000_STA_HIGH_TEMP_WARN_SHIFT 0
+#define SLG51000_STA_HIGH_TEMP_WARN_MASK (0x01 << 0)
+
+/* SLG51000_SYSCTL_IRQ_MASK = 0x1118 */
+#define SLG51000_IRQ_MATRIX_SHIFT 1
+#define SLG51000_IRQ_MATRIX_MASK (0x01 << 1)
+#define SLG51000_IRQ_HIGH_TEMP_WARN_SHIFT 0
+#define SLG51000_IRQ_HIGH_TEMP_WARN_MASK (0x01 << 0)
+
+/* SLG51000_IO_GPIO1_CONF ~ SLG51000_IO_GPIO5_CONF =
+ * 0x1500, 0x1501, 0x1502, 0x1503, 0x1504
+ */
+#define SLG51000_GPIO_DIR_SHIFT 7
+#define SLG51000_GPIO_DIR_MASK (0x01 << 7)
+#define SLG51000_GPIO_SENS_SHIFT 5
+#define SLG51000_GPIO_SENS_MASK (0x03 << 5)
+#define SLG51000_GPIO_INVERT_SHIFT 4
+#define SLG51000_GPIO_INVERT_MASK (0x01 << 4)
+#define SLG51000_GPIO_BYP_SHIFT 3
+#define SLG51000_GPIO_BYP_MASK (0x01 << 3)
+#define SLG51000_GPIO_T_DEB_SHIFT 1
+#define SLG51000_GPIO_T_DEB_MASK (0x03 << 1)
+#define SLG51000_GPIO_LEVEL_SHIFT 0
+#define SLG51000_GPIO_LEVEL_MASK (0x01 << 0)
+
+/* SLG51000_IO_GPIO6_CONF = 0x1505 */
+#define SLG51000_GPIO6_SENS_SHIFT 5
+#define SLG51000_GPIO6_SENS_MASK (0x03 << 5)
+#define SLG51000_GPIO6_INVERT_SHIFT 4
+#define SLG51000_GPIO6_INVERT_MASK (0x01 << 4)
+#define SLG51000_GPIO6_T_DEB_SHIFT 1
+#define SLG51000_GPIO6_T_DEB_MASK (0x03 << 1)
+#define SLG51000_GPIO6_LEVEL_SHIFT 0
+#define SLG51000_GPIO6_LEVEL_MASK (0x01 << 0)
+
+/* SLG51000_IO_GPIO_STATUS = 0x1506 */
+#define SLG51000_GPIO6_STATUS_SHIFT 5
+#define SLG51000_GPIO6_STATUS_MASK (0x01 << 5)
+#define SLG51000_GPIO5_STATUS_SHIFT 4
+#define SLG51000_GPIO5_STATUS_MASK (0x01 << 4)
+#define SLG51000_GPIO4_STATUS_SHIFT 3
+#define SLG51000_GPIO4_STATUS_MASK (0x01 << 3)
+#define SLG51000_GPIO3_STATUS_SHIFT 2
+#define SLG51000_GPIO3_STATUS_MASK (0x01 << 2)
+#define SLG51000_GPIO2_STATUS_SHIFT 1
+#define SLG51000_GPIO2_STATUS_MASK (0x01 << 1)
+#define SLG51000_GPIO1_STATUS_SHIFT 0
+#define SLG51000_GPIO1_STATUS_MASK (0x01 << 0)
+
+/* SLG51000_LUTARRAY_LUT_VAL_0 ~ SLG51000_LUTARRAY_LUT_VAL_11
+ * 0x1600, 0x1601, 0x1602, 0x1603, 0x1604, 0x1605,
+ * 0x1606, 0x1607, 0x1608, 0x1609, 0x160a, 0x160b
+ */
+#define SLG51000_LUT_VAL_SHIFT 0
+#define SLG51000_LUT_VAL_MASK (0xff << 0)
+
+/* SLG51000_MUXARRAY_INPUT_SEL_0 ~ SLG51000_MUXARRAY_INPUT_SEL_63
+ * 0x1700, 0x1701, 0x1702, 0x1703, 0x1704, 0x1705,
+ * 0x1706, 0x1707, 0x1708, 0x1709, 0x170a, 0x170b,
+ * 0x170c, 0x170d, 0x170e, 0x170f, 0x1710, 0x1711,
+ * 0x1712, 0x1713, 0x1714, 0x1715, 0x1716, 0x1717,
+ * 0x1718, 0x1719, 0x171a, 0x171b, 0x171c, 0x171d,
+ * 0x171e, 0x171f, 0x1720, 0x1721, 0x1722, 0x1723,
+ * 0x1724, 0x1725, 0x1726, 0x1727, 0x1728, 0x1729,
+ * 0x173a, 0x173b, 0x173c, 0x173d, 0x173e, 0x173f,
+ */
+#define SLG51000_INPUT_SEL_SHIFT 0
+#define SLG51000_INPUT_SEL_MASK (0x3f << 0)
+
+/* SLG51000_PWRSEQ_RESOURCE_EN_0 ~ SLG51000_PWRSEQ_RESOURCE_EN_5
+ * 0x1900, 0x1901, 0x1902, 0x1903, 0x1904, 0x1905
+ */
+#define SLG51000_RESOURCE_EN_DOWN0_SHIFT 4
+#define SLG51000_RESOURCE_EN_DOWN0_MASK (0x07 << 4)
+#define SLG51000_RESOURCE_EN_UP0_SHIFT 0
+#define SLG51000_RESOURCE_EN_UP0_MASK (0x07 << 0)
+
+/* SLG51000_PWRSEQ_SLOT_TIME_MIN_UP0 ~ SLG51000_PWRSEQ_SLOT_TIME_MIN_UP5
+ * 0x1906, 0x1908, 0x190a, 0x190c, 0x190e, 0x1910
+ */
+#define SLG51000_SLOT_TIME_MIN_UP_SHIFT 0
+#define SLG51000_SLOT_TIME_MIN_UP_MASK (0xff << 0)
+
+/* SLG51000_PWRSEQ_SLOT_TIME_MIN_DOWN0 ~ SLG51000_PWRSEQ_SLOT_TIME_MIN_DOWN5
+ * 0x1907, 0x1909, 0x190b, 0x190d, 0x190f, 0x1911
+ */
+#define SLG51000_SLOT_TIME_MIN_DOWN_SHIFT 0
+#define SLG51000_SLOT_TIME_MIN_DOWN_MASK (0xff << 0)
+
+/* SLG51000_PWRSEQ_SLOT_TIME_MAX_CONF_A ~ SLG51000_PWRSEQ_SLOT_TIME_MAX_CONF_C
+ * 0x1912, 0x1913, 0x1914
+ */
+#define SLG51000_SLOT_TIME_MAX_DOWN1_SHIFT 6
+#define SLG51000_SLOT_TIME_MAX_DOWN1_MASK (0x03 << 6)
+#define SLG51000_SLOT_TIME_MAX_UP1_SHIFT 4
+#define SLG51000_SLOT_TIME_MAX_UP1_MASK (0x03 << 4)
+#define SLG51000_SLOT_TIME_MAX_DOWN0_SHIFT 2
+#define SLG51000_SLOT_TIME_MAX_DOWN0_MASK (0x03 << 2)
+#define SLG51000_SLOT_TIME_MAX_UP0_SHIFT 0
+#define SLG51000_SLOT_TIME_MAX_UP0_MASK (0x03 << 0)
+
+/* SLG51000_PWRSEQ_INPUT_SENSE_CONF_A = 0x1915 */
+#define SLG51000_TRIG_UP_SENSE_SHIFT 6
+#define SLG51000_TRIG_UP_SENSE_MASK (0x01 << 6)
+#define SLG51000_UP_EN_SENSE5_SHIFT 5
+#define SLG51000_UP_EN_SENSE5_MASK (0x01 << 5)
+#define SLG51000_UP_EN_SENSE4_SHIFT 4
+#define SLG51000_UP_EN_SENSE4_MASK (0x01 << 4)
+#define SLG51000_UP_EN_SENSE3_SHIFT 3
+#define SLG51000_UP_EN_SENSE3_MASK (0x01 << 3)
+#define SLG51000_UP_EN_SENSE2_SHIFT 2
+#define SLG51000_UP_EN_SENSE2_MASK (0x01 << 2)
+#define SLG51000_UP_EN_SENSE1_SHIFT 1
+#define SLG51000_UP_EN_SENSE1_MASK (0x01 << 1)
+#define SLG51000_UP_EN_SENSE0_SHIFT 0
+#define SLG51000_UP_EN_SENSE0_MASK (0x01 << 0)
+
+/* SLG51000_PWRSEQ_INPUT_SENSE_CONF_B = 0x1916 */
+#define SLG51000_CRASH_DETECT_SENSE_SHIFT 7
+#define SLG51000_CRASH_DETECT_SENSE_MASK (0x01 << 7)
+#define SLG51000_TRIG_DOWN_SENSE_SHIFT 6
+#define SLG51000_TRIG_DOWN_SENSE_MASK (0x01 << 6)
+#define SLG51000_DOWN_EN_SENSE5_SHIFT 5
+#define SLG51000_DOWN_EN_SENSE5_MASK (0x01 << 5)
+#define SLG51000_DOWN_EN_SENSE4_SHIFT 4
+#define SLG51000_DOWN_EN_SENSE4_MASK (0x01 << 4)
+#define SLG51000_DOWN_EN_SENSE3_SHIFT 3
+#define SLG51000_DOWN_EN_SENSE3_MASK (0x01 << 3)
+#define SLG51000_DOWN_EN_SENSE2_SHIFT 2
+#define SLG51000_DOWN_EN_SENSE2_MASK (0x01 << 2)
+#define SLG51000_DOWN_EN_SENSE1_SHIFT 1
+#define SLG51000_DOWN_EN_SENSE1_MASK (0x01 << 1)
+#define SLG51000_DOWN_EN_SENSE0_SHIFT 0
+#define SLG51000_DOWN_EN_SENSE0_MASK (0x01 << 0)
+
+/* SLG51000_LDO1_VSEL ~ SLG51000_LDO7_VSEL =
+ * 0x2000, 0x2200, 0x2300, 0x2500, 0x2700, 0x2900, 0x3100
+ */
+#define SLG51000_VSEL_SHIFT 0
+#define SLG51000_VSEL_MASK (0xff << 0)
+
+/* SLG51000_LDO1_MINV ~ SLG51000_LDO7_MINV =
+ * 0x2060, 0x2260, 0x2360, 0x2560, 0x2760, 0x2960, 0x3160
+ */
+#define SLG51000_MINV_SHIFT 0
+#define SLG51000_MINV_MASK (0xff << 0)
+
+/* SLG51000_LDO1_MAXV ~ SLG51000_LDO7_MAXV =
+ * 0x2061, 0x2261, 0x2361, 0x2561, 0x2761, 0x2961, 0x3161
+ */
+#define SLG51000_MAXV_SHIFT 0
+#define SLG51000_MAXV_MASK (0xff << 0)
+
+/* SLG51000_LDO1_MISC1 = 0x2064, SLG51000_LDO2_MISC1 = 0x2264 */
+#define SLG51000_SEL_VRANGE_SHIFT 0
+#define SLG51000_SEL_VRANGE_MASK (0x01 << 0)
+
+/* SLG51000_LDO1_VSEL_ACTUAL ~ SLG51000_LDO7_VSEL_ACTUAL =
+ * 0x2065, 0x2265, 0x2366, 0x2566, 0x2767, 0x2967, 0x3166
+ */
+#define SLG51000_VSEL_ACTUAL_SHIFT 0
+#define SLG51000_VSEL_ACTUAL_MASK (0xff << 0)
+
+/* SLG51000_LDO1_EVENT ~ SLG51000_LDO7_EVENT =
+ * 0x20c0, 0x22c0, 0x23c0, 0x25c0, 0x27c0, 0x29c0, 0x31c0
+ */
+#define SLG51000_EVT_ILIM_FLAG_SHIFT 0
+#define SLG51000_EVT_ILIM_FLAG_MASK (0x01 << 0)
+#define SLG51000_EVT_VOUT_OK_FLAG_SHIFT 1
+#define SLG51000_EVT_VOUT_OK_FLAG_MASK (0x01 << 1)
+
+/* SLG51000_LDO1_STATUS ~ SLG51000_LDO7_STATUS =
+ * 0x20c1, 0x22c1, 0x23c1, 0x25c1, 0x27c1, 0x29c1, 0x31c1
+ */
+#define SLG51000_STA_ILIM_FLAG_SHIFT 0
+#define SLG51000_STA_ILIM_FLAG_MASK (0x01 << 0)
+#define SLG51000_STA_VOUT_OK_FLAG_SHIFT 1
+#define SLG51000_STA_VOUT_OK_FLAG_MASK (0x01 << 1)
+
+/* SLG51000_LDO1_IRQ_MASK ~ SLG51000_LDO7_IRQ_MASK =
+ * 0x20c2, 0x22c2, 0x23c2, 0x25c2, 0x27c2, 0x29c2, 0x31c2
+ */
+#define SLG51000_IRQ_ILIM_FLAG_SHIFT 0
+#define SLG51000_IRQ_ILIM_FLAG_MASK (0x01 << 0)
+
+/* SLG51000_LDO3_CONF1 ~ SLG51000_LDO7_CONF1 =
+ * 0x2364, 0x2564, 0x2765, 0x2965, 0x3164
+ */
+#define SLG51000_SEL_START_ILIM_SHIFT 0
+#define SLG51000_SEL_START_ILIM_MASK (0x7f << 0)
+
+/* SLG51000_LDO3_CONF2 ~ SLG51000_LDO7_CONF2 =
+ * 0x2365, 0x2565, 0x2766, 0x2966, 0x3165
+ */
+#define SLG51000_SEL_FUNC_ILIM_SHIFT 0
+#define SLG51000_SEL_FUNC_ILIM_MASK (0x7f << 0)
+
+/* SLG51000_LDO5_TRIM2 = 0x2763, SLG51000_LDO6_TRIM2 = 0x2963 */
+#define SLG51000_SEL_BYP_SLEW_RATE_SHIFT 2
+#define SLG51000_SEL_BYP_SLEW_RATE_MASK (0x03 << 2)
+#define SLG51000_SEL_BYP_VGATE_SHIFT 1
+#define SLG51000_SEL_BYP_VGATE_MASK (0x01 << 1)
+#define SLG51000_SEL_BYP_MODE_SHIFT 0
+#define SLG51000_SEL_BYP_MODE_MASK (0x01 << 0)
+
+/* SLG51000_OTP_EVENT = 0x782b */
+#define SLG51000_EVT_CRC_SHIFT 0
+#define SLG51000_EVT_CRC_MASK (0x01 << 0)
+
+/* SLG51000_OTP_IRQ_MASK = 0x782d */
+#define SLG51000_IRQ_CRC_SHIFT 0
+#define SLG51000_IRQ_CRC_MASK (0x01 << 0)
+
+/* SLG51000_OTP_LOCK_OTP_PROG = 0x78fe */
+#define SLG51000_LOCK_OTP_PROG_SHIFT 0
+#define SLG51000_LOCK_OTP_PROG_MASK (0x01 << 0)
+
+/* SLG51000_OTP_LOCK_CTRL = 0x78ff */
+#define SLG51000_LOCK_DFT_SHIFT 1
+#define SLG51000_LOCK_DFT_MASK (0x01 << 1)
+#define SLG51000_LOCK_RWT_SHIFT 0
+#define SLG51000_LOCK_RWT_MASK (0x01 << 0)
+
+/* SLG51000_LOCK_GLOBAL_LOCK_CTRL1 = 0x8000 */
+#define SLG51000_LDO7_LOCK_SHIFT 7
+#define SLG51000_LDO7_LOCK_MASK (0x01 << 7)
+#define SLG51000_LDO6_LOCK_SHIFT 6
+#define SLG51000_LDO6_LOCK_MASK (0x01 << 6)
+#define SLG51000_LDO5_LOCK_SHIFT 5
+#define SLG51000_LDO5_LOCK_MASK (0x01 << 5)
+#define SLG51000_LDO4_LOCK_SHIFT 4
+#define SLG51000_LDO4_LOCK_MASK (0x01 << 4)
+#define SLG51000_LDO3_LOCK_SHIFT 3
+#define SLG51000_LDO3_LOCK_MASK (0x01 << 3)
+#define SLG51000_LDO2_LOCK_SHIFT 2
+#define SLG51000_LDO2_LOCK_MASK (0x01 << 2)
+#define SLG51000_LDO1_LOCK_SHIFT 1
+#define SLG51000_LDO1_LOCK_MASK (0x01 << 1)
+
+#endif /* __SLG51000_REGISTERS_H__ */
+
diff --git a/drivers/regulator/stm32-booster.c b/drivers/regulator/stm32-booster.c
new file mode 100644
index 000000000000..2a897666c650
--- /dev/null
+++ b/drivers/regulator/stm32-booster.c
@@ -0,0 +1,132 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) STMicroelectronics 2019
+// Author(s): Fabrice Gasnier <fabrice.gasnier@st.com>.
+
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+
+/* STM32H7 SYSCFG register */
+#define STM32H7_SYSCFG_PMCR 0x04
+#define STM32H7_SYSCFG_BOOSTE_MASK BIT(8)
+
+/* STM32MP1 SYSCFG has set and clear registers */
+#define STM32MP1_SYSCFG_PMCSETR 0x04
+#define STM32MP1_SYSCFG_PMCCLRR 0x44
+#define STM32MP1_SYSCFG_EN_BOOSTER_MASK BIT(8)
+
+static const struct regulator_ops stm32h7_booster_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+};
+
+static const struct regulator_desc stm32h7_booster_desc = {
+ .name = "booster",
+ .supply_name = "vdda",
+ .n_voltages = 1,
+ .type = REGULATOR_VOLTAGE,
+ .min_uV = 3300000,
+ .fixed_uV = 3300000,
+ .ramp_delay = 66000, /* up to 50us to stabilize */
+ .ops = &stm32h7_booster_ops,
+ .enable_reg = STM32H7_SYSCFG_PMCR,
+ .enable_mask = STM32H7_SYSCFG_BOOSTE_MASK,
+ .owner = THIS_MODULE,
+};
+
+static int stm32mp1_booster_enable(struct regulator_dev *rdev)
+{
+ return regmap_write(rdev->regmap, STM32MP1_SYSCFG_PMCSETR,
+ STM32MP1_SYSCFG_EN_BOOSTER_MASK);
+}
+
+static int stm32mp1_booster_disable(struct regulator_dev *rdev)
+{
+ return regmap_write(rdev->regmap, STM32MP1_SYSCFG_PMCCLRR,
+ STM32MP1_SYSCFG_EN_BOOSTER_MASK);
+}
+
+static const struct regulator_ops stm32mp1_booster_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .enable = stm32mp1_booster_enable,
+ .disable = stm32mp1_booster_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+};
+
+static const struct regulator_desc stm32mp1_booster_desc = {
+ .name = "booster",
+ .supply_name = "vdda",
+ .n_voltages = 1,
+ .type = REGULATOR_VOLTAGE,
+ .min_uV = 3300000,
+ .fixed_uV = 3300000,
+ .ramp_delay = 66000,
+ .ops = &stm32mp1_booster_ops,
+ .enable_reg = STM32MP1_SYSCFG_PMCSETR,
+ .enable_mask = STM32MP1_SYSCFG_EN_BOOSTER_MASK,
+ .owner = THIS_MODULE,
+};
+
+static int stm32_booster_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = pdev->dev.of_node;
+ struct regulator_config config = { };
+ const struct regulator_desc *desc;
+ struct regulator_dev *rdev;
+ struct regmap *regmap;
+ int ret;
+
+ regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ desc = (const struct regulator_desc *)
+ of_match_device(dev->driver->of_match_table, dev)->data;
+
+ config.regmap = regmap;
+ config.dev = dev;
+ config.of_node = np;
+ config.init_data = of_get_regulator_init_data(dev, np, desc);
+
+ rdev = devm_regulator_register(dev, desc, &config);
+ if (IS_ERR(rdev)) {
+ ret = PTR_ERR(rdev);
+ dev_err(dev, "register failed with error %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id stm32_booster_of_match[] = {
+ {
+ .compatible = "st,stm32h7-booster",
+ .data = (void *)&stm32h7_booster_desc
+ }, {
+ .compatible = "st,stm32mp1-booster",
+ .data = (void *)&stm32mp1_booster_desc
+ }, {
+ },
+};
+MODULE_DEVICE_TABLE(of, stm32_booster_of_match);
+
+static struct platform_driver stm32_booster_driver = {
+ .probe = stm32_booster_probe,
+ .driver = {
+ .name = "stm32-booster",
+ .of_match_table = of_match_ptr(stm32_booster_of_match),
+ },
+};
+module_platform_driver(stm32_booster_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics STM32 booster regulator driver");
+MODULE_ALIAS("platform:stm32-booster");
diff --git a/drivers/regulator/tps65090-regulator.c b/drivers/regulator/tps65090-regulator.c
index ca39b3d55123..10ea4b5a0f55 100644
--- a/drivers/regulator/tps65090-regulator.c
+++ b/drivers/regulator/tps65090-regulator.c
@@ -371,11 +371,12 @@ static struct tps65090_platform_data *tps65090_parse_dt_reg_data(
"dcdc-ext-control-gpios", 0,
gflags,
"tps65090");
- if (IS_ERR(rpdata->gpiod))
- return ERR_CAST(rpdata->gpiod);
- if (!rpdata->gpiod)
+ if (PTR_ERR(rpdata->gpiod) == -ENOENT) {
dev_err(&pdev->dev,
"could not find DCDC external control GPIO\n");
+ rpdata->gpiod = NULL;
+ } else if (IS_ERR(rpdata->gpiod))
+ return ERR_CAST(rpdata->gpiod);
}
if (of_property_read_u32(tps65090_matches[idx].of_node,
diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c
index ba3dae7b2d2d..09e994e1f9a9 100644
--- a/drivers/regulator/tps6586x-regulator.c
+++ b/drivers/regulator/tps6586x-regulator.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Regulator driver for TI TPS6586x
*
@@ -7,10 +8,6 @@
* Based on da903x
* Copyright (C) 2006-2008 Marvell International Ltd.
* Copyright (C) 2008 Compulab Ltd.
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c
index b422eef97b77..018dbbd96771 100644
--- a/drivers/regulator/wm831x-dcdc.c
+++ b/drivers/regulator/wm831x-dcdc.c
@@ -15,7 +15,7 @@
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/slab.h>
#include <linux/mfd/wm831x/core.h>
@@ -50,7 +50,7 @@ struct wm831x_dcdc {
int base;
struct wm831x *wm831x;
struct regulator_dev *regulator;
- int dvs_gpio;
+ struct gpio_desc *dvs_gpiod;
int dvs_gpio_state;
int on_vsel;
int dvs_vsel;
@@ -217,7 +217,7 @@ static int wm831x_buckv_set_dvs(struct regulator_dev *rdev, int state)
return 0;
dcdc->dvs_gpio_state = state;
- gpio_set_value(dcdc->dvs_gpio, state);
+ gpiod_set_value(dcdc->dvs_gpiod, state);
/* Should wait for DVS state change to be asserted if we have
* a GPIO for it, for now assume the device is configured
@@ -237,10 +237,10 @@ static int wm831x_buckv_set_voltage_sel(struct regulator_dev *rdev,
int ret;
/* If this value is already set then do a GPIO update if we can */
- if (dcdc->dvs_gpio && dcdc->on_vsel == vsel)
+ if (dcdc->dvs_gpiod && dcdc->on_vsel == vsel)
return wm831x_buckv_set_dvs(rdev, 0);
- if (dcdc->dvs_gpio && dcdc->dvs_vsel == vsel)
+ if (dcdc->dvs_gpiod && dcdc->dvs_vsel == vsel)
return wm831x_buckv_set_dvs(rdev, 1);
/* Always set the ON status to the minimum voltage */
@@ -249,7 +249,7 @@ static int wm831x_buckv_set_voltage_sel(struct regulator_dev *rdev,
return ret;
dcdc->on_vsel = vsel;
- if (!dcdc->dvs_gpio)
+ if (!dcdc->dvs_gpiod)
return ret;
/* Kick the voltage transition now */
@@ -296,7 +296,7 @@ static int wm831x_buckv_get_voltage_sel(struct regulator_dev *rdev)
{
struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
- if (dcdc->dvs_gpio && dcdc->dvs_gpio_state)
+ if (dcdc->dvs_gpiod && dcdc->dvs_gpio_state)
return dcdc->dvs_vsel;
else
return dcdc->on_vsel;
@@ -337,7 +337,7 @@ static void wm831x_buckv_dvs_init(struct platform_device *pdev,
int ret;
u16 ctrl;
- if (!pdata || !pdata->dvs_gpio)
+ if (!pdata)
return;
/* gpiolib won't let us read the GPIO status so pick the higher
@@ -345,17 +345,14 @@ static void wm831x_buckv_dvs_init(struct platform_device *pdev,
*/
dcdc->dvs_gpio_state = pdata->dvs_init_state;
- ret = devm_gpio_request_one(&pdev->dev, pdata->dvs_gpio,
- dcdc->dvs_gpio_state ? GPIOF_INIT_HIGH : 0,
- "DCDC DVS");
- if (ret < 0) {
- dev_err(wm831x->dev, "Failed to get %s DVS GPIO: %d\n",
- dcdc->name, ret);
+ dcdc->dvs_gpiod = devm_gpiod_get(&pdev->dev, "dvs",
+ dcdc->dvs_gpio_state ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW);
+ if (IS_ERR(dcdc->dvs_gpiod)) {
+ dev_err(wm831x->dev, "Failed to get %s DVS GPIO: %ld\n",
+ dcdc->name, PTR_ERR(dcdc->dvs_gpiod));
return;
}
- dcdc->dvs_gpio = pdata->dvs_gpio;
-
switch (pdata->dvs_control_src) {
case 1:
ctrl = 2 << WM831X_DC1_DVS_SRC_SHIFT;
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 18be41b8aa7e..28ed306982f7 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -16,7 +16,7 @@ if REMOTEPROC
config IMX_REMOTEPROC
tristate "IMX6/7 remoteproc support"
- depends on SOC_IMX6SX || SOC_IMX7D
+ depends on ARCH_MXC
help
Say y here to support iMX's remote processors (Cortex M4
on iMX7D) via the remote processor framework.
@@ -116,6 +116,7 @@ config QCOM_Q6V5_MSS
depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n
depends on QCOM_SYSMON || QCOM_SYSMON=n
select MFD_SYSCON
+ select QCOM_MDT_LOADER
select QCOM_Q6V5_COMMON
select QCOM_RPROC_COMMON
select QCOM_SCM
@@ -198,6 +199,21 @@ config ST_REMOTEPROC
config ST_SLIM_REMOTEPROC
tristate
+config STM32_RPROC
+ tristate "STM32 remoteproc support"
+ depends on ARCH_STM32
+ depends on REMOTEPROC
+ select MAILBOX
+ help
+ Say y here to support STM32 MCU processors via the
+ remote processor framework.
+
+ You want to say y here in order to enable AMP
+ use-cases to run on your platform (dedicated firmware could be
+ offloaded to remote MCU processors using this framework).
+
+ This can be either built-in or a loadable module.
+
endif # REMOTEPROC
endmenu
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index ce5d061e92be..00f09e658cb3 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -26,3 +26,4 @@ qcom_wcnss_pil-y += qcom_wcnss.o
qcom_wcnss_pil-y += qcom_wcnss_iris.o
obj-$(CONFIG_ST_REMOTEPROC) += st_remoteproc.o
obj-$(CONFIG_ST_SLIM_REMOTEPROC) += st_slim_rproc.o
+obj-$(CONFIG_STM32_RPROC) += stm32_rproc.o
diff --git a/drivers/remoteproc/da8xx_remoteproc.c b/drivers/remoteproc/da8xx_remoteproc.c
index d200334577f6..b2c7af323ed1 100644
--- a/drivers/remoteproc/da8xx_remoteproc.c
+++ b/drivers/remoteproc/da8xx_remoteproc.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Remote processor machine-specific module for DA8XX
*
* Copyright (C) 2013 Texas Instruments, 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.
*/
#include <linux/bitops.h>
diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index 54c07fd3f204..3e72b6f38d4b 100644
--- a/drivers/remoteproc/imx_rproc.c
+++ b/drivers/remoteproc/imx_rproc.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2017 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
- *
- * 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.
*/
#include <linux/clk.h>
@@ -168,7 +165,7 @@ static int imx_rproc_start(struct rproc *rproc)
ret = regmap_update_bits(priv->regmap, dcfg->src_reg,
dcfg->src_mask, dcfg->src_start);
if (ret)
- dev_err(dev, "Filed to enable M4!\n");
+ dev_err(dev, "Failed to enable M4!\n");
return ret;
}
@@ -183,7 +180,7 @@ static int imx_rproc_stop(struct rproc *rproc)
ret = regmap_update_bits(priv->regmap, dcfg->src_reg,
dcfg->src_mask, dcfg->src_stop);
if (ret)
- dev_err(dev, "Filed to stop M4!\n");
+ dev_err(dev, "Failed to stop M4!\n");
return ret;
}
@@ -206,7 +203,7 @@ static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
}
}
- dev_warn(priv->dev, "Translation filed: da = 0x%llx len = 0x%x\n",
+ dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%x\n",
da, len);
return -ENOENT;
}
@@ -352,7 +349,7 @@ static int imx_rproc_probe(struct platform_device *pdev)
ret = imx_rproc_addr_init(priv, pdev);
if (ret) {
- dev_err(dev, "filed on imx_rproc_addr_init\n");
+ dev_err(dev, "failed on imx_rproc_addr_init\n");
goto err_put_rproc;
}
diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c
index 1f3ef9ee493c..e953886b2eb7 100644
--- a/drivers/remoteproc/qcom_q6v5_adsp.c
+++ b/drivers/remoteproc/qcom_q6v5_adsp.c
@@ -46,11 +46,9 @@
#define LPASS_PWR_ON_REG 0x10
#define LPASS_HALTREQ_REG 0x0
-/* list of clocks required by ADSP PIL */
-static const char * const adsp_clk_id[] = {
- "sway_cbcr", "lpass_ahbs_aon_cbcr", "lpass_ahbm_aon_cbcr",
- "qdsp6ss_xo", "qdsp6ss_sleep", "qdsp6ss_core",
-};
+#define QDSP6SS_XO_CBCR 0x38
+#define QDSP6SS_CORE_CBCR 0x20
+#define QDSP6SS_SLEEP_CBCR 0x3c
struct adsp_pil_data {
int crash_reason_smem;
@@ -59,6 +57,9 @@ struct adsp_pil_data {
const char *ssr_name;
const char *sysmon_name;
int ssctl_id;
+
+ const char **clk_ids;
+ int num_clks;
};
struct qcom_adsp {
@@ -75,7 +76,7 @@ struct qcom_adsp {
void __iomem *qdsp6ss_base;
struct reset_control *pdc_sync_reset;
- struct reset_control *cc_lpass_restart;
+ struct reset_control *restart;
struct regmap *halt_map;
unsigned int halt_lpass;
@@ -143,7 +144,7 @@ reset:
/* Assert the LPASS PDC Reset */
reset_control_assert(adsp->pdc_sync_reset);
/* Place the LPASS processor into reset */
- reset_control_assert(adsp->cc_lpass_restart);
+ reset_control_assert(adsp->restart);
/* wait after asserting subsystem restart from AOSS */
usleep_range(200, 300);
@@ -153,7 +154,7 @@ reset:
/* De-assert the LPASS PDC Reset */
reset_control_deassert(adsp->pdc_sync_reset);
/* Remove the LPASS reset */
- reset_control_deassert(adsp->cc_lpass_restart);
+ reset_control_deassert(adsp->restart);
/* wait after de-asserting subsystem restart from AOSS */
usleep_range(200, 300);
@@ -192,6 +193,15 @@ static int adsp_start(struct rproc *rproc)
goto disable_power_domain;
}
+ /* Enable the XO clock */
+ writel(1, adsp->qdsp6ss_base + QDSP6SS_XO_CBCR);
+
+ /* Enable the QDSP6SS sleep clock */
+ writel(1, adsp->qdsp6ss_base + QDSP6SS_SLEEP_CBCR);
+
+ /* Enable the QDSP6 core clock */
+ writel(1, adsp->qdsp6ss_base + QDSP6SS_CORE_CBCR);
+
/* Program boot address */
writel(adsp->mem_phys >> 4, adsp->qdsp6ss_base + RST_EVB_REG);
@@ -280,8 +290,9 @@ static const struct rproc_ops adsp_ops = {
.load = adsp_load,
};
-static int adsp_init_clock(struct qcom_adsp *adsp)
+static int adsp_init_clock(struct qcom_adsp *adsp, const char **clk_ids)
{
+ int num_clks = 0;
int i, ret;
adsp->xo = devm_clk_get(adsp->dev, "xo");
@@ -292,32 +303,39 @@ static int adsp_init_clock(struct qcom_adsp *adsp)
return ret;
}
- adsp->num_clks = ARRAY_SIZE(adsp_clk_id);
+ for (i = 0; clk_ids[i]; i++)
+ num_clks++;
+
+ adsp->num_clks = num_clks;
adsp->clks = devm_kcalloc(adsp->dev, adsp->num_clks,
sizeof(*adsp->clks), GFP_KERNEL);
if (!adsp->clks)
return -ENOMEM;
for (i = 0; i < adsp->num_clks; i++)
- adsp->clks[i].id = adsp_clk_id[i];
+ adsp->clks[i].id = clk_ids[i];
return devm_clk_bulk_get(adsp->dev, adsp->num_clks, adsp->clks);
}
static int adsp_init_reset(struct qcom_adsp *adsp)
{
- adsp->pdc_sync_reset = devm_reset_control_get_exclusive(adsp->dev,
+ adsp->pdc_sync_reset = devm_reset_control_get_optional_exclusive(adsp->dev,
"pdc_sync");
if (IS_ERR(adsp->pdc_sync_reset)) {
dev_err(adsp->dev, "failed to acquire pdc_sync reset\n");
return PTR_ERR(adsp->pdc_sync_reset);
}
- adsp->cc_lpass_restart = devm_reset_control_get_exclusive(adsp->dev,
- "cc_lpass");
- if (IS_ERR(adsp->cc_lpass_restart)) {
- dev_err(adsp->dev, "failed to acquire cc_lpass restart\n");
- return PTR_ERR(adsp->cc_lpass_restart);
+ adsp->restart = devm_reset_control_get_optional_exclusive(adsp->dev, "restart");
+
+ /* Fall back to the old "cc_lpass" if "restart" is absent */
+ if (!adsp->restart)
+ adsp->restart = devm_reset_control_get_exclusive(adsp->dev, "cc_lpass");
+
+ if (IS_ERR(adsp->restart)) {
+ dev_err(adsp->dev, "failed to acquire restart\n");
+ return PTR_ERR(adsp->restart);
}
return 0;
@@ -415,7 +433,7 @@ static int adsp_probe(struct platform_device *pdev)
if (ret)
goto free_rproc;
- ret = adsp_init_clock(adsp);
+ ret = adsp_init_clock(adsp, desc->clk_ids);
if (ret)
goto free_rproc;
@@ -479,9 +497,28 @@ static const struct adsp_pil_data adsp_resource_init = {
.ssr_name = "lpass",
.sysmon_name = "adsp",
.ssctl_id = 0x14,
+ .clk_ids = (const char*[]) {
+ "sway_cbcr", "lpass_ahbs_aon_cbcr", "lpass_ahbm_aon_cbcr",
+ "qdsp6ss_xo", "qdsp6ss_sleep", "qdsp6ss_core", NULL
+ },
+ .num_clks = 7,
+};
+
+static const struct adsp_pil_data cdsp_resource_init = {
+ .crash_reason_smem = 601,
+ .firmware_name = "cdsp.mdt",
+ .ssr_name = "cdsp",
+ .sysmon_name = "cdsp",
+ .ssctl_id = 0x17,
+ .clk_ids = (const char*[]) {
+ "sway", "tbu", "bimc", "ahb_aon", "q6ss_slave", "q6ss_master",
+ "q6_axim", NULL
+ },
+ .num_clks = 7,
};
static const struct of_device_id adsp_of_match[] = {
+ { .compatible = "qcom,qcs404-cdsp-pil", .data = &cdsp_resource_init },
{ .compatible = "qcom,sdm845-adsp-pil", .data = &adsp_resource_init },
{ },
};
diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c
index 981581bcdd56..8fcf9d28dd73 100644
--- a/drivers/remoteproc/qcom_q6v5_mss.c
+++ b/drivers/remoteproc/qcom_q6v5_mss.c
@@ -659,23 +659,29 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
{
unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS;
dma_addr_t phys;
+ void *metadata;
int mdata_perm;
int xferop_ret;
+ size_t size;
void *ptr;
int ret;
- ptr = dma_alloc_attrs(qproc->dev, fw->size, &phys, GFP_KERNEL, dma_attrs);
+ metadata = qcom_mdt_read_metadata(fw, &size);
+ if (IS_ERR(metadata))
+ return PTR_ERR(metadata);
+
+ ptr = dma_alloc_attrs(qproc->dev, size, &phys, GFP_KERNEL, dma_attrs);
if (!ptr) {
+ kfree(metadata);
dev_err(qproc->dev, "failed to allocate mdt buffer\n");
return -ENOMEM;
}
- memcpy(ptr, fw->data, fw->size);
+ memcpy(ptr, metadata, size);
/* Hypervisor mapping to access metadata by modem */
mdata_perm = BIT(QCOM_SCM_VMID_HLOS);
- ret = q6v5_xfer_mem_ownership(qproc, &mdata_perm,
- true, phys, fw->size);
+ ret = q6v5_xfer_mem_ownership(qproc, &mdata_perm, true, phys, size);
if (ret) {
dev_err(qproc->dev,
"assigning Q6 access to metadata failed: %d\n", ret);
@@ -693,14 +699,14 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
dev_err(qproc->dev, "MPSS header authentication failed: %d\n", ret);
/* Metadata authentication done, remove modem access */
- xferop_ret = q6v5_xfer_mem_ownership(qproc, &mdata_perm,
- false, phys, fw->size);
+ xferop_ret = q6v5_xfer_mem_ownership(qproc, &mdata_perm, false, phys, size);
if (xferop_ret)
dev_warn(qproc->dev,
"mdt buffer not reclaimed system may become unstable\n");
free_dma_attrs:
- dma_free_attrs(qproc->dev, fw->size, ptr, phys, dma_attrs);
+ dma_free_attrs(qproc->dev, size, ptr, phys, dma_attrs);
+ kfree(metadata);
return ret < 0 ? ret : 0;
}
@@ -981,7 +987,18 @@ static int q6v5_mpss_load(struct q6v5 *qproc)
ptr = qproc->mpss_region + offset;
- if (phdr->p_filesz) {
+ if (phdr->p_filesz && phdr->p_offset < fw->size) {
+ /* Firmware is large enough to be non-split */
+ if (phdr->p_offset + phdr->p_filesz > fw->size) {
+ dev_err(qproc->dev,
+ "failed to load segment %d from truncated file %s\n",
+ i, fw_name);
+ ret = -EINVAL;
+ goto release_firmware;
+ }
+
+ memcpy(ptr, fw->data + phdr->p_offset, phdr->p_filesz);
+ } else if (phdr->p_filesz) {
/* Replace "xxx.xxx" with "xxx.bxx" */
sprintf(fw_name + fw_name_len - 3, "b%02d", i);
ret = request_firmware(&seg_fw, fw_name, qproc->dev);
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 8b5363223eaa..3c5fbbbfb0f1 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -512,6 +512,7 @@ static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc,
/* Initialise vdev subdevice */
snprintf(name, sizeof(name), "vdev%dbuffer", rvdev->index);
rvdev->dev.parent = rproc->dev.parent;
+ rvdev->dev.dma_pfn_offset = rproc->dev.parent->dma_pfn_offset;
rvdev->dev.release = rproc_rvdev_release;
dev_set_name(&rvdev->dev, "%s#%s", dev_name(rvdev->dev.parent), name);
dev_set_drvdata(&rvdev->dev, rvdev);
@@ -1058,6 +1059,20 @@ static int rproc_handle_resources(struct rproc *rproc,
dev_dbg(dev, "rsc: type %d\n", hdr->type);
+ if (hdr->type >= RSC_VENDOR_START &&
+ hdr->type <= RSC_VENDOR_END) {
+ ret = rproc_handle_rsc(rproc, hdr->type, rsc,
+ offset + sizeof(*hdr), avail);
+ if (ret == RSC_HANDLED)
+ continue;
+ else if (ret < 0)
+ break;
+
+ dev_warn(dev, "unsupported vendor resource %d\n",
+ hdr->type);
+ continue;
+ }
+
if (hdr->type >= RSC_LAST) {
dev_warn(dev, "unsupported resource %d\n", hdr->type);
continue;
diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
index 215a4400f21e..606aae166eba 100644
--- a/drivers/remoteproc/remoteproc_elf_loader.c
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -247,8 +247,7 @@ find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
}
/* make sure the offsets array isn't truncated */
- if (table->num * sizeof(table->offset[0]) +
- sizeof(struct resource_table) > size) {
+ if (struct_size(table, offset, table->num) > size) {
dev_err(dev, "resource table incomplete\n");
return NULL;
}
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index a87750903785..493ef9262411 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -99,6 +99,17 @@ static inline int rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
}
static inline
+int rproc_handle_rsc(struct rproc *rproc, u32 rsc_type, void *rsc, int offset,
+ int avail)
+{
+ if (rproc->ops->handle_rsc)
+ return rproc->ops->handle_rsc(rproc, rsc_type, rsc, offset,
+ avail);
+
+ return RSC_IGNORED;
+}
+
+static inline
struct resource_table *rproc_find_loaded_rsc_table(struct rproc *rproc,
const struct firmware *fw)
{
diff --git a/drivers/remoteproc/st_remoteproc.c b/drivers/remoteproc/st_remoteproc.c
index 51049d17b1e5..ee13d23b43a9 100644
--- a/drivers/remoteproc/st_remoteproc.c
+++ b/drivers/remoteproc/st_remoteproc.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ST's Remote Processor Control Driver
*
* Copyright (C) 2015 STMicroelectronics - All Rights Reserved
*
* Author: Ludovic Barre <ludovic.barre@st.com>
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c
new file mode 100644
index 000000000000..e2da7198b65f
--- /dev/null
+++ b/drivers/remoteproc/stm32_rproc.c
@@ -0,0 +1,628 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Authors: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
+ * Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mailbox_client.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/regmap.h>
+#include <linux/remoteproc.h>
+#include <linux/reset.h>
+
+#include "remoteproc_internal.h"
+
+#define HOLD_BOOT 0
+#define RELEASE_BOOT 1
+
+#define MBOX_NB_VQ 2
+#define MBOX_NB_MBX 3
+
+#define STM32_SMC_RCC 0x82001000
+#define STM32_SMC_REG_WRITE 0x1
+
+#define STM32_MBX_VQ0 "vq0"
+#define STM32_MBX_VQ1 "vq1"
+#define STM32_MBX_SHUTDOWN "shutdown"
+
+struct stm32_syscon {
+ struct regmap *map;
+ u32 reg;
+ u32 mask;
+};
+
+struct stm32_rproc_mem {
+ char name[20];
+ void __iomem *cpu_addr;
+ phys_addr_t bus_addr;
+ u32 dev_addr;
+ size_t size;
+};
+
+struct stm32_rproc_mem_ranges {
+ u32 dev_addr;
+ u32 bus_addr;
+ u32 size;
+};
+
+struct stm32_mbox {
+ const unsigned char name[10];
+ struct mbox_chan *chan;
+ struct mbox_client client;
+ int vq_id;
+};
+
+struct stm32_rproc {
+ struct reset_control *rst;
+ struct stm32_syscon hold_boot;
+ struct stm32_syscon pdds;
+ u32 nb_rmems;
+ struct stm32_rproc_mem *rmems;
+ struct stm32_mbox mb[MBOX_NB_MBX];
+ bool secured_soc;
+};
+
+static int stm32_rproc_pa_to_da(struct rproc *rproc, phys_addr_t pa, u64 *da)
+{
+ unsigned int i;
+ struct stm32_rproc *ddata = rproc->priv;
+ struct stm32_rproc_mem *p_mem;
+
+ for (i = 0; i < ddata->nb_rmems; i++) {
+ p_mem = &ddata->rmems[i];
+
+ if (pa < p_mem->bus_addr ||
+ pa >= p_mem->bus_addr + p_mem->size)
+ continue;
+ *da = pa - p_mem->bus_addr + p_mem->dev_addr;
+ dev_dbg(rproc->dev.parent, "pa %pa to da %llx\n", &pa, *da);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int stm32_rproc_mem_alloc(struct rproc *rproc,
+ struct rproc_mem_entry *mem)
+{
+ struct device *dev = rproc->dev.parent;
+ void *va;
+
+ dev_dbg(dev, "map memory: %pa+%x\n", &mem->dma, mem->len);
+ va = ioremap_wc(mem->dma, mem->len);
+ if (IS_ERR_OR_NULL(va)) {
+ dev_err(dev, "Unable to map memory region: %pa+%x\n",
+ &mem->dma, mem->len);
+ return -ENOMEM;
+ }
+
+ /* Update memory entry va */
+ mem->va = va;
+
+ return 0;
+}
+
+static int stm32_rproc_mem_release(struct rproc *rproc,
+ struct rproc_mem_entry *mem)
+{
+ dev_dbg(rproc->dev.parent, "unmap memory: %pa\n", &mem->dma);
+ iounmap(mem->va);
+
+ return 0;
+}
+
+static int stm32_rproc_of_memory_translations(struct rproc *rproc)
+{
+ struct device *parent, *dev = rproc->dev.parent;
+ struct stm32_rproc *ddata = rproc->priv;
+ struct device_node *np;
+ struct stm32_rproc_mem *p_mems;
+ struct stm32_rproc_mem_ranges *mem_range;
+ int cnt, array_size, i, ret = 0;
+
+ parent = dev->parent;
+ np = parent->of_node;
+
+ cnt = of_property_count_elems_of_size(np, "dma-ranges",
+ sizeof(*mem_range));
+ if (cnt <= 0) {
+ dev_err(dev, "%s: dma-ranges property not defined\n", __func__);
+ return -EINVAL;
+ }
+
+ p_mems = devm_kcalloc(dev, cnt, sizeof(*p_mems), GFP_KERNEL);
+ if (!p_mems)
+ return -ENOMEM;
+ mem_range = kcalloc(cnt, sizeof(*mem_range), GFP_KERNEL);
+ if (!mem_range)
+ return -ENOMEM;
+
+ array_size = cnt * sizeof(struct stm32_rproc_mem_ranges) / sizeof(u32);
+
+ ret = of_property_read_u32_array(np, "dma-ranges",
+ (u32 *)mem_range, array_size);
+ if (ret) {
+ dev_err(dev, "error while get dma-ranges property: %x\n", ret);
+ goto free_mem;
+ }
+
+ for (i = 0; i < cnt; i++) {
+ p_mems[i].bus_addr = mem_range[i].bus_addr;
+ p_mems[i].dev_addr = mem_range[i].dev_addr;
+ p_mems[i].size = mem_range[i].size;
+
+ dev_dbg(dev, "memory range[%i]: da %#x, pa %pa, size %#zx:\n",
+ i, p_mems[i].dev_addr, &p_mems[i].bus_addr,
+ p_mems[i].size);
+ }
+
+ ddata->rmems = p_mems;
+ ddata->nb_rmems = cnt;
+
+free_mem:
+ kfree(mem_range);
+ return ret;
+}
+
+static int stm32_rproc_mbox_idx(struct rproc *rproc, const unsigned char *name)
+{
+ struct stm32_rproc *ddata = rproc->priv;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ddata->mb); i++) {
+ if (!strncmp(ddata->mb[i].name, name, strlen(name)))
+ return i;
+ }
+ dev_err(&rproc->dev, "mailbox %s not found\n", name);
+
+ return -EINVAL;
+}
+
+static int stm32_rproc_elf_load_rsc_table(struct rproc *rproc,
+ const struct firmware *fw)
+{
+ if (rproc_elf_load_rsc_table(rproc, fw))
+ dev_warn(&rproc->dev, "no resource table found for this firmware\n");
+
+ return 0;
+}
+
+static int stm32_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
+{
+ struct device *dev = rproc->dev.parent;
+ struct device_node *np = dev->of_node;
+ struct of_phandle_iterator it;
+ struct rproc_mem_entry *mem;
+ struct reserved_mem *rmem;
+ u64 da;
+ int index = 0;
+
+ /* Register associated reserved memory regions */
+ of_phandle_iterator_init(&it, np, "memory-region", NULL, 0);
+ while (of_phandle_iterator_next(&it) == 0) {
+ rmem = of_reserved_mem_lookup(it.node);
+ if (!rmem) {
+ dev_err(dev, "unable to acquire memory-region\n");
+ return -EINVAL;
+ }
+
+ if (stm32_rproc_pa_to_da(rproc, rmem->base, &da) < 0) {
+ dev_err(dev, "memory region not valid %pa\n",
+ &rmem->base);
+ return -EINVAL;
+ }
+
+ /* No need to map vdev buffer */
+ if (strcmp(it.node->name, "vdev0buffer")) {
+ /* Register memory region */
+ mem = rproc_mem_entry_init(dev, NULL,
+ (dma_addr_t)rmem->base,
+ rmem->size, da,
+ stm32_rproc_mem_alloc,
+ stm32_rproc_mem_release,
+ it.node->name);
+
+ if (mem)
+ rproc_coredump_add_segment(rproc, da,
+ rmem->size);
+ } else {
+ /* Register reserved memory for vdev buffer alloc */
+ mem = rproc_of_resm_mem_entry_init(dev, index,
+ rmem->size,
+ rmem->base,
+ it.node->name);
+ }
+
+ if (!mem)
+ return -ENOMEM;
+
+ rproc_add_carveout(rproc, mem);
+ index++;
+ }
+
+ return stm32_rproc_elf_load_rsc_table(rproc, fw);
+}
+
+static irqreturn_t stm32_rproc_wdg(int irq, void *data)
+{
+ struct rproc *rproc = data;
+
+ rproc_report_crash(rproc, RPROC_WATCHDOG);
+
+ return IRQ_HANDLED;
+}
+
+static void stm32_rproc_mb_callback(struct mbox_client *cl, void *data)
+{
+ struct rproc *rproc = dev_get_drvdata(cl->dev);
+ struct stm32_mbox *mb = container_of(cl, struct stm32_mbox, client);
+
+ if (rproc_vq_interrupt(rproc, mb->vq_id) == IRQ_NONE)
+ dev_dbg(&rproc->dev, "no message found in vq%d\n", mb->vq_id);
+}
+
+static void stm32_rproc_free_mbox(struct rproc *rproc)
+{
+ struct stm32_rproc *ddata = rproc->priv;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(ddata->mb); i++) {
+ if (ddata->mb[i].chan)
+ mbox_free_channel(ddata->mb[i].chan);
+ ddata->mb[i].chan = NULL;
+ }
+}
+
+static const struct stm32_mbox stm32_rproc_mbox[MBOX_NB_MBX] = {
+ {
+ .name = STM32_MBX_VQ0,
+ .vq_id = 0,
+ .client = {
+ .rx_callback = stm32_rproc_mb_callback,
+ .tx_block = false,
+ },
+ },
+ {
+ .name = STM32_MBX_VQ1,
+ .vq_id = 1,
+ .client = {
+ .rx_callback = stm32_rproc_mb_callback,
+ .tx_block = false,
+ },
+ },
+ {
+ .name = STM32_MBX_SHUTDOWN,
+ .vq_id = -1,
+ .client = {
+ .tx_block = true,
+ .tx_done = NULL,
+ .tx_tout = 500, /* 500 ms time out */
+ },
+ }
+};
+
+static void stm32_rproc_request_mbox(struct rproc *rproc)
+{
+ struct stm32_rproc *ddata = rproc->priv;
+ struct device *dev = &rproc->dev;
+ unsigned int i;
+ const unsigned char *name;
+ struct mbox_client *cl;
+
+ /* Initialise mailbox structure table */
+ memcpy(ddata->mb, stm32_rproc_mbox, sizeof(stm32_rproc_mbox));
+
+ for (i = 0; i < MBOX_NB_MBX; i++) {
+ name = ddata->mb[i].name;
+
+ cl = &ddata->mb[i].client;
+ cl->dev = dev->parent;
+
+ ddata->mb[i].chan = mbox_request_channel_byname(cl, name);
+ if (IS_ERR(ddata->mb[i].chan)) {
+ dev_warn(dev, "cannot get %s mbox\n", name);
+ ddata->mb[i].chan = NULL;
+ }
+ }
+}
+
+static int stm32_rproc_set_hold_boot(struct rproc *rproc, bool hold)
+{
+ struct stm32_rproc *ddata = rproc->priv;
+ struct stm32_syscon hold_boot = ddata->hold_boot;
+ struct arm_smccc_res smc_res;
+ int val, err;
+
+ val = hold ? HOLD_BOOT : RELEASE_BOOT;
+
+ if (IS_ENABLED(CONFIG_HAVE_ARM_SMCCC) && ddata->secured_soc) {
+ arm_smccc_smc(STM32_SMC_RCC, STM32_SMC_REG_WRITE,
+ hold_boot.reg, val, 0, 0, 0, 0, &smc_res);
+ err = smc_res.a0;
+ } else {
+ err = regmap_update_bits(hold_boot.map, hold_boot.reg,
+ hold_boot.mask, val);
+ }
+
+ if (err)
+ dev_err(&rproc->dev, "failed to set hold boot\n");
+
+ return err;
+}
+
+static void stm32_rproc_add_coredump_trace(struct rproc *rproc)
+{
+ struct rproc_debug_trace *trace;
+ struct rproc_dump_segment *segment;
+ bool already_added;
+
+ list_for_each_entry(trace, &rproc->traces, node) {
+ already_added = false;
+
+ list_for_each_entry(segment, &rproc->dump_segments, node) {
+ if (segment->da == trace->trace_mem.da) {
+ already_added = true;
+ break;
+ }
+ }
+
+ if (!already_added)
+ rproc_coredump_add_segment(rproc, trace->trace_mem.da,
+ trace->trace_mem.len);
+ }
+}
+
+static int stm32_rproc_start(struct rproc *rproc)
+{
+ int err;
+
+ stm32_rproc_add_coredump_trace(rproc);
+
+ err = stm32_rproc_set_hold_boot(rproc, false);
+ if (err)
+ return err;
+
+ return stm32_rproc_set_hold_boot(rproc, true);
+}
+
+static int stm32_rproc_stop(struct rproc *rproc)
+{
+ struct stm32_rproc *ddata = rproc->priv;
+ int err, dummy_data, idx;
+
+ /* request shutdown of the remote processor */
+ if (rproc->state != RPROC_OFFLINE) {
+ idx = stm32_rproc_mbox_idx(rproc, STM32_MBX_SHUTDOWN);
+ if (idx >= 0 && ddata->mb[idx].chan) {
+ /* a dummy data is sent to allow to block on transmit */
+ err = mbox_send_message(ddata->mb[idx].chan,
+ &dummy_data);
+ if (err < 0)
+ dev_warn(&rproc->dev, "warning: remote FW shutdown without ack\n");
+ }
+ }
+
+ err = stm32_rproc_set_hold_boot(rproc, true);
+ if (err)
+ return err;
+
+ err = reset_control_assert(ddata->rst);
+ if (err) {
+ dev_err(&rproc->dev, "failed to assert the reset\n");
+ return err;
+ }
+
+ /* to allow platform Standby power mode, set remote proc Deep Sleep */
+ if (ddata->pdds.map) {
+ err = regmap_update_bits(ddata->pdds.map, ddata->pdds.reg,
+ ddata->pdds.mask, 1);
+ if (err) {
+ dev_err(&rproc->dev, "failed to set pdds\n");
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static void stm32_rproc_kick(struct rproc *rproc, int vqid)
+{
+ struct stm32_rproc *ddata = rproc->priv;
+ unsigned int i;
+ int err;
+
+ if (WARN_ON(vqid >= MBOX_NB_VQ))
+ return;
+
+ for (i = 0; i < MBOX_NB_MBX; i++) {
+ if (vqid != ddata->mb[i].vq_id)
+ continue;
+ if (!ddata->mb[i].chan)
+ return;
+ err = mbox_send_message(ddata->mb[i].chan, (void *)(long)vqid);
+ if (err < 0)
+ dev_err(&rproc->dev, "%s: failed (%s, err:%d)\n",
+ __func__, ddata->mb[i].name, err);
+ return;
+ }
+}
+
+static struct rproc_ops st_rproc_ops = {
+ .start = stm32_rproc_start,
+ .stop = stm32_rproc_stop,
+ .kick = stm32_rproc_kick,
+ .load = rproc_elf_load_segments,
+ .parse_fw = stm32_rproc_parse_fw,
+ .find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table,
+ .sanity_check = rproc_elf_sanity_check,
+ .get_boot_addr = rproc_elf_get_boot_addr,
+};
+
+static const struct of_device_id stm32_rproc_match[] = {
+ { .compatible = "st,stm32mp1-m4" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, stm32_rproc_match);
+
+static int stm32_rproc_get_syscon(struct device_node *np, const char *prop,
+ struct stm32_syscon *syscon)
+{
+ int err = 0;
+
+ syscon->map = syscon_regmap_lookup_by_phandle(np, prop);
+ if (IS_ERR(syscon->map)) {
+ err = PTR_ERR(syscon->map);
+ syscon->map = NULL;
+ goto out;
+ }
+
+ err = of_property_read_u32_index(np, prop, 1, &syscon->reg);
+ if (err)
+ goto out;
+
+ err = of_property_read_u32_index(np, prop, 2, &syscon->mask);
+
+out:
+ return err;
+}
+
+static int stm32_rproc_parse_dt(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct rproc *rproc = platform_get_drvdata(pdev);
+ struct stm32_rproc *ddata = rproc->priv;
+ struct stm32_syscon tz;
+ unsigned int tzen;
+ int err, irq;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq > 0) {
+ err = devm_request_irq(dev, irq, stm32_rproc_wdg, 0,
+ dev_name(dev), rproc);
+ if (err) {
+ dev_err(dev, "failed to request wdg irq\n");
+ return err;
+ }
+
+ dev_info(dev, "wdg irq registered\n");
+ }
+
+ ddata->rst = devm_reset_control_get_by_index(dev, 0);
+ if (IS_ERR(ddata->rst)) {
+ dev_err(dev, "failed to get mcu reset\n");
+ return PTR_ERR(ddata->rst);
+ }
+
+ /*
+ * if platform is secured the hold boot bit must be written by
+ * smc call and read normally.
+ * if not secure the hold boot bit could be read/write normally
+ */
+ err = stm32_rproc_get_syscon(np, "st,syscfg-tz", &tz);
+ if (err) {
+ dev_err(dev, "failed to get tz syscfg\n");
+ return err;
+ }
+
+ err = regmap_read(tz.map, tz.reg, &tzen);
+ if (err) {
+ dev_err(&rproc->dev, "failed to read tzen\n");
+ return err;
+ }
+ ddata->secured_soc = tzen & tz.mask;
+
+ err = stm32_rproc_get_syscon(np, "st,syscfg-holdboot",
+ &ddata->hold_boot);
+ if (err) {
+ dev_err(dev, "failed to get hold boot\n");
+ return err;
+ }
+
+ err = stm32_rproc_get_syscon(np, "st,syscfg-pdds", &ddata->pdds);
+ if (err)
+ dev_warn(dev, "failed to get pdds\n");
+
+ rproc->auto_boot = of_property_read_bool(np, "st,auto-boot");
+
+ return stm32_rproc_of_memory_translations(rproc);
+}
+
+static int stm32_rproc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct stm32_rproc *ddata;
+ struct device_node *np = dev->of_node;
+ struct rproc *rproc;
+ int ret;
+
+ ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
+
+ rproc = rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata));
+ if (!rproc)
+ return -ENOMEM;
+
+ rproc->has_iommu = false;
+ ddata = rproc->priv;
+
+ platform_set_drvdata(pdev, rproc);
+
+ ret = stm32_rproc_parse_dt(pdev);
+ if (ret)
+ goto free_rproc;
+
+ stm32_rproc_request_mbox(rproc);
+
+ ret = rproc_add(rproc);
+ if (ret)
+ goto free_mb;
+
+ return 0;
+
+free_mb:
+ stm32_rproc_free_mbox(rproc);
+free_rproc:
+ rproc_free(rproc);
+ return ret;
+}
+
+static int stm32_rproc_remove(struct platform_device *pdev)
+{
+ struct rproc *rproc = platform_get_drvdata(pdev);
+
+ if (atomic_read(&rproc->power) > 0)
+ rproc_shutdown(rproc);
+
+ rproc_del(rproc);
+ stm32_rproc_free_mbox(rproc);
+ rproc_free(rproc);
+
+ return 0;
+}
+
+static struct platform_driver stm32_rproc_driver = {
+ .probe = stm32_rproc_probe,
+ .remove = stm32_rproc_remove,
+ .driver = {
+ .name = "stm32-rproc",
+ .of_match_table = of_match_ptr(stm32_rproc_match),
+ },
+};
+module_platform_driver(stm32_rproc_driver);
+
+MODULE_DESCRIPTION("STM32 Remote Processor Control Driver");
+MODULE_AUTHOR("Ludovic Barre <ludovic.barre@st.com>");
+MODULE_AUTHOR("Fabien Dessenne <fabien.dessenne@st.com>");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/reset/hisilicon/hi6220_reset.c b/drivers/reset/hisilicon/hi6220_reset.c
index d5e5229308f2..24e6d420b26b 100644
--- a/drivers/reset/hisilicon/hi6220_reset.c
+++ b/drivers/reset/hisilicon/hi6220_reset.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Hisilicon Hi6220 reset controller driver
*
@@ -5,10 +6,6 @@
* Copyright (c) 2015-2016 Hisilicon Limited.
*
* Author: Feng Chen <puck.chen@hisilicon.com>
- *
- * 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.
*/
#include <linux/io.h>
diff --git a/drivers/reset/reset-lantiq.c b/drivers/reset/reset-lantiq.c
index 11a582e50d30..ac41d093de13 100644
--- a/drivers/reset/reset-lantiq.c
+++ b/drivers/reset/reset-lantiq.c
@@ -1,7 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
- * 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.
*
* Copyright (C) 2010 John Crispin <blogic@phrozen.org>
* Copyright (C) 2013-2015 Lantiq Beteiligungs-GmbH & Co.KG
diff --git a/drivers/reset/reset-lpc18xx.c b/drivers/reset/reset-lpc18xx.c
index a62ad52e262b..35d8dd4cccfc 100644
--- a/drivers/reset/reset-lpc18xx.c
+++ b/drivers/reset/reset-lpc18xx.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Reset driver for NXP LPC18xx/43xx Reset Generation Unit (RGU).
*
* Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
- *
- * 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.
- *
*/
#include <linux/clk.h>
diff --git a/drivers/reset/tegra/reset-bpmp.c b/drivers/reset/tegra/reset-bpmp.c
index 5daf2ee1a396..24d3395964cc 100644
--- a/drivers/reset/tegra/reset-bpmp.c
+++ b/drivers/reset/tegra/reset-bpmp.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2016 NVIDIA Corporation
- *
- * 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.
*/
#include <linux/reset-controller.h>
diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c
index 8122807db380..ea88fd4e2a6e 100644
--- a/drivers/rpmsg/rpmsg_core.c
+++ b/drivers/rpmsg/rpmsg_core.c
@@ -493,7 +493,8 @@ static int rpmsg_dev_remove(struct device *dev)
if (rpdev->ops->announce_destroy)
err = rpdev->ops->announce_destroy(rpdev);
- rpdrv->remove(rpdev);
+ if (rpdrv->remove)
+ rpdrv->remove(rpdev);
dev_pm_domain_detach(dev, true);
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 5c0790eed656..e72f65b61176 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -374,11 +374,11 @@ config RTC_DRV_MAX77686
will be called rtc-max77686.
config RTC_DRV_RK808
- tristate "Rockchip RK805/RK808/RK818 RTC"
+ tristate "Rockchip RK805/RK808/RK809/RK817/RK818 RTC"
depends on MFD_RK808
help
If you say yes here you will get support for the
- RTC of RK805, RK808 and RK818 PMIC.
+ RTC of RK805, RK809 and RK817, RK808 and RK818 PMIC.
This driver can also be built as a module. If so, the module
will be called rk808-rtc.
@@ -498,6 +498,14 @@ config RTC_DRV_M41T80_WDT
help
If you say Y here you will get support for the
watchdog timer in the ST M41T60 and M41T80 RTC chips series.
+config RTC_DRV_BD70528
+ tristate "ROHM BD70528 PMIC RTC"
+ help
+ If you say Y here you will get support for the RTC
+ on ROHM BD70528 Power Management IC.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-bd70528.
config RTC_DRV_BQ32K
tristate "TI BQ32000"
@@ -554,7 +562,7 @@ config RTC_DRV_TPS6586X
config RTC_DRV_TPS65910
tristate "TI TPS65910 RTC driver"
- depends on RTC_CLASS && MFD_TPS65910
+ depends on MFD_TPS65910
help
If you say yes here you get support for the RTC on the
TPS65910 chips.
@@ -812,6 +820,7 @@ config RTC_DRV_MAX6902
config RTC_DRV_PCF2123
tristate "NXP PCF2123"
+ select REGMAP_SPI
help
If you say yes here you get support for the NXP PCF2123
RTC chip.
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 9d997faa2c26..6b09c21dc1b6 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_RTC_DRV_ASPEED) += rtc-aspeed.o
obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o
obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o
+obj-$(CONFIG_RTC_DRV_BD70528) += rtc-bd70528.o
obj-$(CONFIG_RTC_DRV_BQ32K) += rtc-bq32k.o
obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o
obj-$(CONFIG_RTC_DRV_BRCMSTB) += rtc-brcmstb-waketimer.o
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index 4124f4dd376b..72b7ddc43116 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -633,7 +633,7 @@ enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer)
{
struct rtc_device *rtc;
ktime_t period;
- int count;
+ u64 count;
rtc = container_of(timer, struct rtc_device, pie_timer);
diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c
index 73697e4b18a9..434285f495e0 100644
--- a/drivers/rtc/rtc-88pm860x.c
+++ b/drivers/rtc/rtc-88pm860x.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Real Time Clock driver for Marvell 88PM860x PMIC
*
* Copyright (c) 2010 Marvell International Ltd.
* Author: Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/rtc/rtc-bd70528.c b/drivers/rtc/rtc-bd70528.c
new file mode 100644
index 000000000000..f9bdd555e1a2
--- /dev/null
+++ b/drivers/rtc/rtc-bd70528.c
@@ -0,0 +1,500 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Copyright (C) 2018 ROHM Semiconductors
+//
+// RTC driver for ROHM BD70528 PMIC
+
+#include <linux/bcd.h>
+#include <linux/mfd/rohm-bd70528.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+
+/*
+ * We read regs RTC_SEC => RTC_YEAR
+ * this struct is ordered according to chip registers.
+ * Keep it u8 only to avoid padding issues.
+ */
+struct bd70528_rtc_day {
+ u8 sec;
+ u8 min;
+ u8 hour;
+} __packed;
+
+struct bd70528_rtc_data {
+ struct bd70528_rtc_day time;
+ u8 week;
+ u8 day;
+ u8 month;
+ u8 year;
+} __packed;
+
+struct bd70528_rtc_wake {
+ struct bd70528_rtc_day time;
+ u8 ctrl;
+} __packed;
+
+struct bd70528_rtc_alm {
+ struct bd70528_rtc_data data;
+ u8 alm_mask;
+ u8 alm_repeat;
+} __packed;
+
+struct bd70528_rtc {
+ struct rohm_regmap_dev *mfd;
+ struct device *dev;
+};
+
+static int bd70528_set_wake(struct rohm_regmap_dev *bd70528,
+ int enable, int *old_state)
+{
+ int ret;
+ unsigned int ctrl_reg;
+
+ ret = regmap_read(bd70528->regmap, BD70528_REG_WAKE_EN, &ctrl_reg);
+ if (ret)
+ return ret;
+
+ if (old_state) {
+ if (ctrl_reg & BD70528_MASK_WAKE_EN)
+ *old_state |= BD70528_WAKE_STATE_BIT;
+ else
+ *old_state &= ~BD70528_WAKE_STATE_BIT;
+
+ if (!enable == !(*old_state & BD70528_WAKE_STATE_BIT))
+ return 0;
+ }
+
+ if (enable)
+ ctrl_reg |= BD70528_MASK_WAKE_EN;
+ else
+ ctrl_reg &= ~BD70528_MASK_WAKE_EN;
+
+ return regmap_write(bd70528->regmap, BD70528_REG_WAKE_EN,
+ ctrl_reg);
+}
+
+static int bd70528_set_elapsed_tmr(struct rohm_regmap_dev *bd70528,
+ int enable, int *old_state)
+{
+ int ret;
+ unsigned int ctrl_reg;
+
+ /*
+ * TBD
+ * What is the purpose of elapsed timer ?
+ * Is the timeout registers counting down, or is the disable - re-enable
+ * going to restart the elapsed-time counting? If counting is restarted
+ * the timeout should be decreased by the amount of time that has
+ * elapsed since starting the timer. Maybe we should store the monotonic
+ * clock value when timer is started so that if RTC is set while timer
+ * is armed we could do the compensation. This is a hack if RTC/system
+ * clk are drifting. OTOH, RTC controlled via I2C is in any case
+ * inaccurate...
+ */
+ ret = regmap_read(bd70528->regmap, BD70528_REG_ELAPSED_TIMER_EN,
+ &ctrl_reg);
+ if (ret)
+ return ret;
+
+ if (old_state) {
+ if (ctrl_reg & BD70528_MASK_ELAPSED_TIMER_EN)
+ *old_state |= BD70528_ELAPSED_STATE_BIT;
+ else
+ *old_state &= ~BD70528_ELAPSED_STATE_BIT;
+
+ if ((!enable) == (!(*old_state & BD70528_ELAPSED_STATE_BIT)))
+ return 0;
+ }
+
+ if (enable)
+ ctrl_reg |= BD70528_MASK_ELAPSED_TIMER_EN;
+ else
+ ctrl_reg &= ~BD70528_MASK_ELAPSED_TIMER_EN;
+
+ return regmap_write(bd70528->regmap, BD70528_REG_ELAPSED_TIMER_EN,
+ ctrl_reg);
+}
+
+static int bd70528_set_rtc_based_timers(struct bd70528_rtc *r, int new_state,
+ int *old_state)
+{
+ int ret;
+
+ ret = bd70528_wdt_set(r->mfd, new_state & BD70528_WDT_STATE_BIT,
+ old_state);
+ if (ret) {
+ dev_err(r->dev,
+ "Failed to disable WDG for RTC setting (%d)\n", ret);
+ return ret;
+ }
+ ret = bd70528_set_elapsed_tmr(r->mfd,
+ new_state & BD70528_ELAPSED_STATE_BIT,
+ old_state);
+ if (ret) {
+ dev_err(r->dev,
+ "Failed to disable 'elapsed timer' for RTC setting\n");
+ return ret;
+ }
+ ret = bd70528_set_wake(r->mfd, new_state & BD70528_WAKE_STATE_BIT,
+ old_state);
+ if (ret) {
+ dev_err(r->dev,
+ "Failed to disable 'wake timer' for RTC setting\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static int bd70528_re_enable_rtc_based_timers(struct bd70528_rtc *r,
+ int old_state)
+{
+ return bd70528_set_rtc_based_timers(r, old_state, NULL);
+}
+
+static int bd70528_disable_rtc_based_timers(struct bd70528_rtc *r,
+ int *old_state)
+{
+ return bd70528_set_rtc_based_timers(r, 0, old_state);
+}
+
+static inline void tmday2rtc(struct rtc_time *t, struct bd70528_rtc_day *d)
+{
+ d->sec &= ~BD70528_MASK_RTC_SEC;
+ d->min &= ~BD70528_MASK_RTC_MINUTE;
+ d->hour &= ~BD70528_MASK_RTC_HOUR;
+ d->sec |= bin2bcd(t->tm_sec);
+ d->min |= bin2bcd(t->tm_min);
+ d->hour |= bin2bcd(t->tm_hour);
+}
+
+static inline void tm2rtc(struct rtc_time *t, struct bd70528_rtc_data *r)
+{
+ r->day &= ~BD70528_MASK_RTC_DAY;
+ r->week &= ~BD70528_MASK_RTC_WEEK;
+ r->month &= ~BD70528_MASK_RTC_MONTH;
+ /*
+ * PM and 24H bits are not used by Wake - thus we clear them
+ * here and not in tmday2rtc() which is also used by wake.
+ */
+ r->time.hour &= ~(BD70528_MASK_RTC_HOUR_PM | BD70528_MASK_RTC_HOUR_24H);
+
+ tmday2rtc(t, &r->time);
+ /*
+ * We do always set time in 24H mode.
+ */
+ r->time.hour |= BD70528_MASK_RTC_HOUR_24H;
+ r->day |= bin2bcd(t->tm_mday);
+ r->week |= bin2bcd(t->tm_wday);
+ r->month |= bin2bcd(t->tm_mon + 1);
+ r->year = bin2bcd(t->tm_year - 100);
+}
+
+static inline void rtc2tm(struct bd70528_rtc_data *r, struct rtc_time *t)
+{
+ t->tm_sec = bcd2bin(r->time.sec & BD70528_MASK_RTC_SEC);
+ t->tm_min = bcd2bin(r->time.min & BD70528_MASK_RTC_MINUTE);
+ t->tm_hour = bcd2bin(r->time.hour & BD70528_MASK_RTC_HOUR);
+ /*
+ * If RTC is in 12H mode, then bit BD70528_MASK_RTC_HOUR_PM
+ * is not BCD value but tells whether it is AM or PM
+ */
+ if (!(r->time.hour & BD70528_MASK_RTC_HOUR_24H)) {
+ t->tm_hour %= 12;
+ if (r->time.hour & BD70528_MASK_RTC_HOUR_PM)
+ t->tm_hour += 12;
+ }
+ t->tm_mday = bcd2bin(r->day & BD70528_MASK_RTC_DAY);
+ t->tm_mon = bcd2bin(r->month & BD70528_MASK_RTC_MONTH) - 1;
+ t->tm_year = 100 + bcd2bin(r->year & BD70528_MASK_RTC_YEAR);
+ t->tm_wday = bcd2bin(r->week & BD70528_MASK_RTC_WEEK);
+}
+
+static int bd70528_set_alarm(struct device *dev, struct rtc_wkalrm *a)
+{
+ struct bd70528_rtc_wake wake;
+ struct bd70528_rtc_alm alm;
+ int ret;
+ struct bd70528_rtc *r = dev_get_drvdata(dev);
+ struct rohm_regmap_dev *bd70528 = r->mfd;
+
+ ret = regmap_bulk_read(bd70528->regmap, BD70528_REG_RTC_WAKE_START,
+ &wake, sizeof(wake));
+ if (ret) {
+ dev_err(dev, "Failed to read wake regs\n");
+ return ret;
+ }
+
+ ret = regmap_bulk_read(bd70528->regmap, BD70528_REG_RTC_ALM_START,
+ &alm, sizeof(alm));
+ if (ret) {
+ dev_err(dev, "Failed to read alarm regs\n");
+ return ret;
+ }
+
+ tm2rtc(&a->time, &alm.data);
+ tmday2rtc(&a->time, &wake.time);
+
+ if (a->enabled) {
+ alm.alm_mask &= ~BD70528_MASK_ALM_EN;
+ wake.ctrl |= BD70528_MASK_WAKE_EN;
+ } else {
+ alm.alm_mask |= BD70528_MASK_ALM_EN;
+ wake.ctrl &= ~BD70528_MASK_WAKE_EN;
+ }
+
+ ret = regmap_bulk_write(bd70528->regmap,
+ BD70528_REG_RTC_WAKE_START, &wake,
+ sizeof(wake));
+ if (ret) {
+ dev_err(dev, "Failed to set wake time\n");
+ return ret;
+ }
+ ret = regmap_bulk_write(bd70528->regmap, BD70528_REG_RTC_ALM_START,
+ &alm, sizeof(alm));
+ if (ret)
+ dev_err(dev, "Failed to set alarm time\n");
+
+ return ret;
+}
+
+static int bd70528_read_alarm(struct device *dev, struct rtc_wkalrm *a)
+{
+ struct bd70528_rtc_alm alm;
+ int ret;
+ struct bd70528_rtc *r = dev_get_drvdata(dev);
+ struct rohm_regmap_dev *bd70528 = r->mfd;
+
+ ret = regmap_bulk_read(bd70528->regmap, BD70528_REG_RTC_ALM_START,
+ &alm, sizeof(alm));
+ if (ret) {
+ dev_err(dev, "Failed to read alarm regs\n");
+ return ret;
+ }
+
+ rtc2tm(&alm.data, &a->time);
+ a->time.tm_mday = -1;
+ a->time.tm_mon = -1;
+ a->time.tm_year = -1;
+ a->enabled = !(alm.alm_mask & BD70528_MASK_ALM_EN);
+ a->pending = 0;
+
+ return 0;
+}
+
+static int bd70528_set_time_locked(struct device *dev, struct rtc_time *t)
+{
+ int ret, tmpret, old_states;
+ struct bd70528_rtc_data rtc_data;
+ struct bd70528_rtc *r = dev_get_drvdata(dev);
+ struct rohm_regmap_dev *bd70528 = r->mfd;
+
+ ret = bd70528_disable_rtc_based_timers(r, &old_states);
+ if (ret)
+ return ret;
+
+ tmpret = regmap_bulk_read(bd70528->regmap,
+ BD70528_REG_RTC_START, &rtc_data,
+ sizeof(rtc_data));
+ if (tmpret) {
+ dev_err(dev, "Failed to read RTC time registers\n");
+ goto renable_out;
+ }
+ tm2rtc(t, &rtc_data);
+
+ tmpret = regmap_bulk_write(bd70528->regmap,
+ BD70528_REG_RTC_START, &rtc_data,
+ sizeof(rtc_data));
+ if (tmpret) {
+ dev_err(dev, "Failed to set RTC time\n");
+ goto renable_out;
+ }
+
+renable_out:
+ ret = bd70528_re_enable_rtc_based_timers(r, old_states);
+ if (tmpret)
+ ret = tmpret;
+
+ return ret;
+}
+
+static int bd70528_set_time(struct device *dev, struct rtc_time *t)
+{
+ int ret;
+ struct bd70528_rtc *r = dev_get_drvdata(dev);
+
+ bd70528_wdt_lock(r->mfd);
+ ret = bd70528_set_time_locked(dev, t);
+ bd70528_wdt_unlock(r->mfd);
+ return ret;
+}
+
+static int bd70528_get_time(struct device *dev, struct rtc_time *t)
+{
+ struct bd70528_rtc *r = dev_get_drvdata(dev);
+ struct rohm_regmap_dev *bd70528 = r->mfd;
+ struct bd70528_rtc_data rtc_data;
+ int ret;
+
+ /* read the RTC date and time registers all at once */
+ ret = regmap_bulk_read(bd70528->regmap,
+ BD70528_REG_RTC_START, &rtc_data,
+ sizeof(rtc_data));
+ if (ret) {
+ dev_err(dev, "Failed to read RTC time (err %d)\n", ret);
+ return ret;
+ }
+
+ rtc2tm(&rtc_data, t);
+
+ return 0;
+}
+
+static int bd70528_alm_enable(struct device *dev, unsigned int enabled)
+{
+ int ret;
+ unsigned int enableval = BD70528_MASK_ALM_EN;
+ struct bd70528_rtc *r = dev_get_drvdata(dev);
+
+ if (enabled)
+ enableval = 0;
+
+ bd70528_wdt_lock(r->mfd);
+ ret = bd70528_set_wake(r->mfd, enabled, NULL);
+ if (ret) {
+ dev_err(dev, "Failed to change wake state\n");
+ goto out_unlock;
+ }
+ ret = regmap_update_bits(r->mfd->regmap, BD70528_REG_RTC_ALM_MASK,
+ BD70528_MASK_ALM_EN, enableval);
+ if (ret)
+ dev_err(dev, "Failed to change alarm state\n");
+
+out_unlock:
+ bd70528_wdt_unlock(r->mfd);
+ return ret;
+}
+
+static const struct rtc_class_ops bd70528_rtc_ops = {
+ .read_time = bd70528_get_time,
+ .set_time = bd70528_set_time,
+ .read_alarm = bd70528_read_alarm,
+ .set_alarm = bd70528_set_alarm,
+ .alarm_irq_enable = bd70528_alm_enable,
+};
+
+static irqreturn_t alm_hndlr(int irq, void *data)
+{
+ struct rtc_device *rtc = data;
+
+ rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF | RTC_PF);
+ return IRQ_HANDLED;
+}
+
+static int bd70528_probe(struct platform_device *pdev)
+{
+ struct bd70528_rtc *bd_rtc;
+ struct rohm_regmap_dev *mfd;
+ int ret;
+ struct rtc_device *rtc;
+ int irq;
+ unsigned int hr;
+
+ mfd = dev_get_drvdata(pdev->dev.parent);
+ if (!mfd) {
+ dev_err(&pdev->dev, "No MFD driver data\n");
+ return -EINVAL;
+ }
+ bd_rtc = devm_kzalloc(&pdev->dev, sizeof(*bd_rtc), GFP_KERNEL);
+ if (!bd_rtc)
+ return -ENOMEM;
+
+ bd_rtc->mfd = mfd;
+ bd_rtc->dev = &pdev->dev;
+
+ irq = platform_get_irq_byname(pdev, "bd70528-rtc-alm");
+
+ if (irq < 0) {
+ dev_err(&pdev->dev, "Failed to get irq\n");
+ return irq;
+ }
+
+ platform_set_drvdata(pdev, bd_rtc);
+
+ ret = regmap_read(mfd->regmap, BD70528_REG_RTC_HOUR, &hr);
+
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to reag RTC clock\n");
+ return ret;
+ }
+
+ if (!(hr & BD70528_MASK_RTC_HOUR_24H)) {
+ struct rtc_time t;
+
+ ret = bd70528_get_time(&pdev->dev, &t);
+
+ if (!ret)
+ ret = bd70528_set_time(&pdev->dev, &t);
+
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Setting 24H clock for RTC failed\n");
+ return ret;
+ }
+ }
+
+ device_set_wakeup_capable(&pdev->dev, true);
+ device_wakeup_enable(&pdev->dev);
+
+ rtc = devm_rtc_allocate_device(&pdev->dev);
+ if (IS_ERR(rtc)) {
+ dev_err(&pdev->dev, "RTC device creation failed\n");
+ return PTR_ERR(rtc);
+ }
+
+ rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
+ rtc->range_max = RTC_TIMESTAMP_END_2099;
+ rtc->ops = &bd70528_rtc_ops;
+
+ /* Request alarm IRQ prior to registerig the RTC */
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, &alm_hndlr,
+ IRQF_ONESHOT, "bd70528-rtc", rtc);
+ if (ret)
+ return ret;
+
+ /*
+ * BD70528 irq controller is not touching the main mask register.
+ * So enable the RTC block interrupts at main level. We can just
+ * leave them enabled as irq-controller should disable irqs
+ * from sub-registers when IRQ is disabled or freed.
+ */
+ ret = regmap_update_bits(mfd->regmap,
+ BD70528_REG_INT_MAIN_MASK,
+ BD70528_INT_RTC_MASK, 0);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to enable RTC interrupts\n");
+ return ret;
+ }
+
+ ret = rtc_register_device(rtc);
+ if (ret)
+ dev_err(&pdev->dev, "Registering RTC failed\n");
+
+ return ret;
+}
+
+static struct platform_driver bd70528_rtc = {
+ .driver = {
+ .name = "bd70528-rtc"
+ },
+ .probe = bd70528_probe,
+};
+
+module_platform_driver(bd70528_rtc);
+
+MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
+MODULE_DESCRIPTION("BD70528 RTC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-bq32k.c b/drivers/rtc/rtc-bq32k.c
index ef52741000a8..4a63f0cd2321 100644
--- a/drivers/rtc/rtc-bq32k.c
+++ b/drivers/rtc/rtc-bq32k.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for TI BQ32000 RTC.
*
* Copyright (C) 2009 Semihalf.
* Copyright (C) 2014 Pavel Machek <pavel@denx.de>
*
- * 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.
- *
* You can get hardware description at
* http://www.ti.com/lit/ds/symlink/bq32000.pdf
*/
diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c
index 2d502fc85698..e04d6e862c42 100644
--- a/drivers/rtc/rtc-ds1305.c
+++ b/drivers/rtc/rtc-ds1305.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* rtc-ds1305.c -- driver for DS1305 and DS1306 SPI RTC chips
*
* Copyright (C) 2008 David Brownell
- *
- * 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.
- *
*/
#include <linux/kernel.h>
#include <linux/init.h>
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index 07530fe1da2a..1f7e8aefc1eb 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* rtc-ds1307.c - RTC driver for some mostly-compatible I2C chips.
*
@@ -5,10 +6,6 @@
* Copyright (C) 2006 David Brownell
* Copyright (C) 2009 Matthias Fuchs (rx8025 support)
* Copyright (C) 2012 Bertrand Achard (nvram access fixes)
- *
- * 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.
*/
#include <linux/acpi.h>
@@ -225,6 +222,45 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)
return -EINVAL;
}
+ tmp = regs[DS1307_REG_SECS];
+ switch (ds1307->type) {
+ case ds_1307:
+ case m41t0:
+ case m41t00:
+ case m41t11:
+ if (tmp & DS1307_BIT_CH)
+ return -EINVAL;
+ break;
+ case ds_1308:
+ case ds_1338:
+ if (tmp & DS1307_BIT_CH)
+ return -EINVAL;
+
+ ret = regmap_read(ds1307->regmap, DS1307_REG_CONTROL, &tmp);
+ if (ret)
+ return ret;
+ if (tmp & DS1338_BIT_OSF)
+ return -EINVAL;
+ break;
+ case ds_1340:
+ if (tmp & DS1340_BIT_nEOSC)
+ return -EINVAL;
+
+ ret = regmap_read(ds1307->regmap, DS1340_REG_FLAG, &tmp);
+ if (ret)
+ return ret;
+ if (tmp & DS1340_BIT_OSF)
+ return -EINVAL;
+ break;
+ case mcp794xx:
+ if (!(tmp & MCP794XX_BIT_ST))
+ return -EINVAL;
+
+ break;
+ default:
+ break;
+ }
+
t->tm_sec = bcd2bin(regs[DS1307_REG_SECS] & 0x7f);
t->tm_min = bcd2bin(regs[DS1307_REG_MIN] & 0x7f);
tmp = regs[DS1307_REG_HOUR] & 0x3f;
@@ -289,7 +325,17 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
if (t->tm_year > 199 && chip->century_bit)
regs[chip->century_reg] |= chip->century_bit;
- if (ds1307->type == mcp794xx) {
+ switch (ds1307->type) {
+ case ds_1308:
+ case ds_1338:
+ regmap_update_bits(ds1307->regmap, DS1307_REG_CONTROL,
+ DS1338_BIT_OSF, 0);
+ break;
+ case ds_1340:
+ regmap_update_bits(ds1307->regmap, DS1340_REG_FLAG,
+ DS1340_BIT_OSF, 0);
+ break;
+ case mcp794xx:
/*
* these bits were cleared when preparing the date/time
* values and need to be set again before writing the
@@ -297,6 +343,9 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
*/
regs[DS1307_REG_SECS] |= MCP794XX_BIT_ST;
regs[DS1307_REG_WDAY] |= MCP794XX_BIT_VBATEN;
+ break;
+ default:
+ break;
}
dev_dbg(dev, "%s: %7ph\n", "write", regs);
@@ -1705,7 +1754,6 @@ static int ds1307_probe(struct i2c_client *client,
break;
}
-read_rtc:
/* read RTC registers */
err = regmap_bulk_read(ds1307->regmap, chip->offset, regs,
sizeof(regs));
@@ -1714,75 +1762,11 @@ read_rtc:
goto exit;
}
- /*
- * minimal sanity checking; some chips (like DS1340) don't
- * specify the extra bits as must-be-zero, but there are
- * still a few values that are clearly out-of-range.
- */
- tmp = regs[DS1307_REG_SECS];
- switch (ds1307->type) {
- case ds_1307:
- case m41t0:
- case m41t00:
- case m41t11:
- /* clock halted? turn it on, so clock can tick. */
- if (tmp & DS1307_BIT_CH) {
- regmap_write(ds1307->regmap, DS1307_REG_SECS, 0);
- dev_warn(ds1307->dev, "SET TIME!\n");
- goto read_rtc;
- }
- break;
- case ds_1308:
- case ds_1338:
- /* clock halted? turn it on, so clock can tick. */
- if (tmp & DS1307_BIT_CH)
- regmap_write(ds1307->regmap, DS1307_REG_SECS, 0);
-
- /* oscillator fault? clear flag, and warn */
- if (regs[DS1307_REG_CONTROL] & DS1338_BIT_OSF) {
- regmap_write(ds1307->regmap, DS1307_REG_CONTROL,
- regs[DS1307_REG_CONTROL] &
- ~DS1338_BIT_OSF);
- dev_warn(ds1307->dev, "SET TIME!\n");
- goto read_rtc;
- }
- break;
- case ds_1340:
- /* clock halted? turn it on, so clock can tick. */
- if (tmp & DS1340_BIT_nEOSC)
- regmap_write(ds1307->regmap, DS1307_REG_SECS, 0);
-
- err = regmap_read(ds1307->regmap, DS1340_REG_FLAG, &tmp);
- if (err) {
- dev_dbg(ds1307->dev, "read error %d\n", err);
- goto exit;
- }
-
- /* oscillator fault? clear flag, and warn */
- if (tmp & DS1340_BIT_OSF) {
- regmap_write(ds1307->regmap, DS1340_REG_FLAG, 0);
- dev_warn(ds1307->dev, "SET TIME!\n");
- }
- break;
- case mcp794xx:
- /* make sure that the backup battery is enabled */
- if (!(regs[DS1307_REG_WDAY] & MCP794XX_BIT_VBATEN)) {
- regmap_write(ds1307->regmap, DS1307_REG_WDAY,
- regs[DS1307_REG_WDAY] |
- MCP794XX_BIT_VBATEN);
- }
-
- /* clock halted? turn it on, so clock can tick. */
- if (!(tmp & MCP794XX_BIT_ST)) {
- regmap_write(ds1307->regmap, DS1307_REG_SECS,
- MCP794XX_BIT_ST);
- dev_warn(ds1307->dev, "SET TIME!\n");
- goto read_rtc;
- }
-
- break;
- default:
- break;
+ if (ds1307->type == mcp794xx &&
+ !(regs[DS1307_REG_WDAY] & MCP794XX_BIT_VBATEN)) {
+ regmap_write(ds1307->regmap, DS1307_REG_WDAY,
+ regs[DS1307_REG_WDAY] |
+ MCP794XX_BIT_VBATEN);
}
tmp = regs[DS1307_REG_HOUR];
diff --git a/drivers/rtc/rtc-ds1343.c b/drivers/rtc/rtc-ds1343.c
index 5208da4cf94a..fa6de31d5793 100644
--- a/drivers/rtc/rtc-ds1343.c
+++ b/drivers/rtc/rtc-ds1343.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* rtc-ds1343.c
*
* Driver for Dallas Semiconductor DS1343 Low Current, SPI Compatible
@@ -5,11 +6,6 @@
*
* Author : Raghavendra Chandra Ganiga <ravi23ganiga@gmail.com>
* Ankur Srivastava <sankurece@gmail.com> : DS1343 Nvram Support
- *
- * 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.
- *
*/
#include <linux/init.h>
diff --git a/drivers/rtc/rtc-ds1347.c b/drivers/rtc/rtc-ds1347.c
index 938512c676ee..d392a7bfdd1c 100644
--- a/drivers/rtc/rtc-ds1347.c
+++ b/drivers/rtc/rtc-ds1347.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* rtc-ds1347.c
*
* Driver for Dallas Semiconductor DS1347 Low Current, SPI Compatible
* Real Time Clock
*
* Author : Raghavendra Chandra Ganiga <ravi23ganiga@gmail.com>
- *
- * 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.
- *
*/
#include <linux/init.h>
diff --git a/drivers/rtc/rtc-ds1390.c b/drivers/rtc/rtc-ds1390.c
index 3b095401f848..66fc8617d07e 100644
--- a/drivers/rtc/rtc-ds1390.c
+++ b/drivers/rtc/rtc-ds1390.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* rtc-ds1390.c -- driver for the Dallas/Maxim DS1390/93/94 SPI RTC
*
* Copyright (C) 2008 Mercury IMC Ltd
* Written by Mark Jackson <mpfj@mimc.co.uk>
*
- * 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.
- *
* NOTE: Currently this driver only supports the bare minimum for read
* and write the RTC. The extra features provided by the chip family
* (alarms, trickle charger, different control registers) are unavailable.
diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c
index b8b6e51c0461..b6a477519280 100644
--- a/drivers/rtc/rtc-ds1511.c
+++ b/drivers/rtc/rtc-ds1511.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* An rtc driver for the Dallas DS1511
*
* Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
* Copyright (C) 2007 Andrew Sharp <andy.sharp@lsi.com>
*
- * 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.
- *
* Real time clock driver for the Dallas 1511 chip, which also
* contains a watchdog timer. There is a tiny amount of code that
* platform code could use to mess with the watchdog device a little
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c
index 34af7a802f43..219d6b520a69 100644
--- a/drivers/rtc/rtc-ds1553.c
+++ b/drivers/rtc/rtc-ds1553.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* An rtc driver for the Dallas DS1553
*
* Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
- *
- * 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.
*/
#include <linux/bcd.h>
diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c
index 5f4328524183..184e4a3e2bef 100644
--- a/drivers/rtc/rtc-ds1685.c
+++ b/drivers/rtc/rtc-ds1685.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* An rtc driver for the Dallas/Maxim DS1685/DS1687 and related real-time
* chips.
@@ -10,10 +11,6 @@
* DS17x85/DS17x87 3V/5V Real-Time Clocks, 19-5222, Rev 4/10.
* DS1689/DS1693 3V/5V Serialized Real-Time Clocks, Rev 112105.
* Application Note 90, Using the Multiplex Bus RTC Extended Features.
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c
index 5a4c2c5e86fe..2b949f0dbaa9 100644
--- a/drivers/rtc/rtc-ds1742.c
+++ b/drivers/rtc/rtc-ds1742.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* An rtc driver for the Dallas DS1742
*
* Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
*
- * 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.
- *
* Copyright (C) 2006 Torsten Ertbjerg Rasmussen <tr@newtec.dk>
* - nvram size determined from resource
* - this ds1742 driver now supports ds1743.
diff --git a/drivers/rtc/rtc-ds2404.c b/drivers/rtc/rtc-ds2404.c
index 1e9f429ada64..9df0c44512b8 100644
--- a/drivers/rtc/rtc-ds2404.c
+++ b/drivers/rtc/rtc-ds2404.c
@@ -182,9 +182,10 @@ static void ds2404_enable_osc(struct device *dev)
static int ds2404_read_time(struct device *dev, struct rtc_time *dt)
{
unsigned long time = 0;
+ __le32 hw_time = 0;
- ds2404_read_memory(dev, 0x203, 4, (u8 *)&time);
- time = le32_to_cpu(time);
+ ds2404_read_memory(dev, 0x203, 4, (u8 *)&hw_time);
+ time = le32_to_cpu(hw_time);
rtc_time64_to_tm(time, dt);
return 0;
diff --git a/drivers/rtc/rtc-em3027.c b/drivers/rtc/rtc-em3027.c
index b0ef8cfe742d..77cca1392253 100644
--- a/drivers/rtc/rtc-em3027.c
+++ b/drivers/rtc/rtc-em3027.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* An rtc/i2c driver for the EM Microelectronic EM3027
* Copyright 2011 CompuLab, Ltd.
@@ -5,10 +6,6 @@
* Author: Mike Rapoport <mike@compulab.co.il>
*
* Based on rtc-ds1672.c by Alessandro Zummo <a.zummo@towertech.it>
- *
- * 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.
*/
#include <linux/i2c.h>
diff --git a/drivers/rtc/rtc-fm3130.c b/drivers/rtc/rtc-fm3130.c
index e1137670d4d2..677ec2da13d8 100644
--- a/drivers/rtc/rtc-fm3130.c
+++ b/drivers/rtc/rtc-fm3130.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* rtc-fm3130.c - RTC driver for Ramtron FM3130 I2C chip.
*
* Copyright (C) 2008 Sergey Lapin
* Based on ds1307 driver by James Chapman and David Brownell
- *
- * 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.
*/
#include <linux/module.h>
@@ -107,8 +104,7 @@ static int fm3130_get_time(struct device *dev, struct rtc_time *t)
fm3130_rtc_mode(dev, FM3130_MODE_READ);
/* read the RTC date and time registers all at once */
- tmp = i2c_transfer(to_i2c_adapter(fm3130->client->dev.parent),
- fm3130->msg, 2);
+ tmp = i2c_transfer(fm3130->client->adapter, fm3130->msg, 2);
if (tmp != 2) {
dev_err(dev, "%s error %d\n", "read", tmp);
return -EIO;
@@ -200,8 +196,7 @@ static int fm3130_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
}
/* read the RTC alarm registers all at once */
- tmp = i2c_transfer(to_i2c_adapter(fm3130->client->dev.parent),
- &fm3130->msg[2], 2);
+ tmp = i2c_transfer(fm3130->client->adapter, &fm3130->msg[2], 2);
if (tmp != 2) {
dev_err(dev, "%s error %d\n", "read", tmp);
return -EIO;
@@ -351,7 +346,7 @@ static int fm3130_probe(struct i2c_client *client,
struct fm3130 *fm3130;
int err = -ENODEV;
int tmp;
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adapter = client->adapter;
if (!i2c_check_functionality(adapter,
I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
diff --git a/drivers/rtc/rtc-imx-sc.c b/drivers/rtc/rtc-imx-sc.c
index 19642bfd913a..c933045fe04b 100644
--- a/drivers/rtc/rtc-imx-sc.c
+++ b/drivers/rtc/rtc-imx-sc.c
@@ -3,6 +3,7 @@
* Copyright 2018 NXP.
*/
+#include <dt-bindings/firmware/imx/rsrc.h>
#include <linux/arm-smccc.h>
#include <linux/firmware/imx/sci.h>
#include <linux/module.h>
@@ -11,11 +12,15 @@
#include <linux/rtc.h>
#define IMX_SC_TIMER_FUNC_GET_RTC_SEC1970 9
+#define IMX_SC_TIMER_FUNC_SET_RTC_ALARM 8
#define IMX_SC_TIMER_FUNC_SET_RTC_TIME 6
#define IMX_SIP_SRTC 0xC2000002
#define IMX_SIP_SRTC_SET_TIME 0x0
+#define SC_IRQ_GROUP_RTC 2
+#define SC_IRQ_RTC 1
+
static struct imx_sc_ipc *rtc_ipc_handle;
static struct rtc_device *imx_sc_rtc;
@@ -24,6 +29,16 @@ struct imx_sc_msg_timer_get_rtc_time {
u32 time;
} __packed;
+struct imx_sc_msg_timer_rtc_set_alarm {
+ struct imx_sc_rpc_msg hdr;
+ u16 year;
+ u8 mon;
+ u8 day;
+ u8 hour;
+ u8 min;
+ u8 sec;
+} __packed;
+
static int imx_sc_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct imx_sc_msg_timer_get_rtc_time msg;
@@ -60,9 +75,77 @@ static int imx_sc_rtc_set_time(struct device *dev, struct rtc_time *tm)
return res.a0;
}
+static int imx_sc_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
+{
+ return imx_scu_irq_group_enable(SC_IRQ_GROUP_RTC, SC_IRQ_RTC, enable);
+}
+
+static int imx_sc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ /*
+ * SCU firmware does NOT provide read alarm API, but .read_alarm
+ * callback is required by RTC framework to support alarm function,
+ * so just return here.
+ */
+ return 0;
+}
+
+static int imx_sc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct imx_sc_msg_timer_rtc_set_alarm msg;
+ struct imx_sc_rpc_msg *hdr = &msg.hdr;
+ int ret;
+ struct rtc_time *alrm_tm = &alrm->time;
+
+ hdr->ver = IMX_SC_RPC_VERSION;
+ hdr->svc = IMX_SC_RPC_SVC_TIMER;
+ hdr->func = IMX_SC_TIMER_FUNC_SET_RTC_ALARM;
+ hdr->size = 3;
+
+ msg.year = alrm_tm->tm_year + 1900;
+ msg.mon = alrm_tm->tm_mon + 1;
+ msg.day = alrm_tm->tm_mday;
+ msg.hour = alrm_tm->tm_hour;
+ msg.min = alrm_tm->tm_min;
+ msg.sec = alrm_tm->tm_sec;
+
+ ret = imx_scu_call_rpc(rtc_ipc_handle, &msg, true);
+ if (ret) {
+ dev_err(dev, "set rtc alarm failed, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = imx_sc_rtc_alarm_irq_enable(dev, alrm->enabled);
+ if (ret) {
+ dev_err(dev, "enable rtc alarm failed, ret %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
static const struct rtc_class_ops imx_sc_rtc_ops = {
.read_time = imx_sc_rtc_read_time,
.set_time = imx_sc_rtc_set_time,
+ .read_alarm = imx_sc_rtc_read_alarm,
+ .set_alarm = imx_sc_rtc_set_alarm,
+ .alarm_irq_enable = imx_sc_rtc_alarm_irq_enable,
+};
+
+static int imx_sc_rtc_alarm_notify(struct notifier_block *nb,
+ unsigned long event, void *group)
+{
+ /* ignore non-rtc irq */
+ if (!((event & SC_IRQ_RTC) && (*(u8 *)group == SC_IRQ_GROUP_RTC)))
+ return 0;
+
+ rtc_update_irq(imx_sc_rtc, 1, RTC_IRQF | RTC_AF);
+
+ return 0;
+}
+
+static struct notifier_block imx_sc_rtc_alarm_sc_notifier = {
+ .notifier_call = imx_sc_rtc_alarm_notify,
};
static int imx_sc_rtc_probe(struct platform_device *pdev)
@@ -73,6 +156,8 @@ static int imx_sc_rtc_probe(struct platform_device *pdev)
if (ret)
return ret;
+ device_init_wakeup(&pdev->dev, true);
+
imx_sc_rtc = devm_rtc_allocate_device(&pdev->dev);
if (IS_ERR(imx_sc_rtc))
return PTR_ERR(imx_sc_rtc);
@@ -87,6 +172,8 @@ static int imx_sc_rtc_probe(struct platform_device *pdev)
return ret;
}
+ imx_scu_irq_register_notifier(&imx_sc_rtc_alarm_sc_notifier);
+
return 0;
}
diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c
index 890ccfc9e5aa..961bd5d1d109 100644
--- a/drivers/rtc/rtc-isl12022.c
+++ b/drivers/rtc/rtc-isl12022.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* An I2C driver for the Intersil ISL 12022
*
@@ -5,10 +6,6 @@
*
* Based on the Philips PCF8563 RTC
* by Alessandro Zummo <a.zummo@towertech.it>.
- *
- * 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.
*/
#include <linux/i2c.h>
diff --git a/drivers/rtc/rtc-lp8788.c b/drivers/rtc/rtc-lp8788.c
index e20e7bd822e0..c0b8fbce1082 100644
--- a/drivers/rtc/rtc-lp8788.c
+++ b/drivers/rtc/rtc-lp8788.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TI LP8788 MFD - rtc driver
*
* Copyright 2012 Texas Instruments
*
* Author: Milo(Woogyom) Kim <milo.kim@ti.com>
- *
- * 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.
- *
*/
#include <linux/err.h>
diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c
index dd5a8991f75b..5f46f85f814b 100644
--- a/drivers/rtc/rtc-m41t80.c
+++ b/drivers/rtc/rtc-m41t80.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* I2C client/driver for the ST M41T80 family of i2c rtc chips.
*
@@ -6,11 +7,6 @@
* Based on m41t00.c by Mark A. Greer <mgreer@mvista.com>
*
* 2006 (c) mycable GmbH
- *
- * 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.
- *
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -876,7 +872,7 @@ static struct notifier_block wdt_notifier = {
static int m41t80_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adapter = client->adapter;
int rc = 0;
struct rtc_time tm;
struct m41t80_data *m41t80_data = NULL;
diff --git a/drivers/rtc/rtc-m41t93.c b/drivers/rtc/rtc-m41t93.c
index 4a08a9dabc82..9444cb5f5190 100644
--- a/drivers/rtc/rtc-m41t93.c
+++ b/drivers/rtc/rtc-m41t93.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
*
* Driver for ST M41T93 SPI RTC
*
* (c) 2010 Nikolaus Voss, Weinmann Medical GmbH
- *
- * 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.
*/
#include <linux/bcd.h>
diff --git a/drivers/rtc/rtc-m41t94.c b/drivers/rtc/rtc-m41t94.c
index bab82b4be356..6803b0273302 100644
--- a/drivers/rtc/rtc-m41t94.c
+++ b/drivers/rtc/rtc-m41t94.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for ST M41T94 SPI RTC
*
* Copyright (C) 2008 Kim B. Heino
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c
index 3c8ad1cdfd7c..67e218758a8b 100644
--- a/drivers/rtc/rtc-m48t59.c
+++ b/drivers/rtc/rtc-m48t59.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ST M48T59 RTC driver
*
* Copyright (c) 2007 Wind River Systems, Inc.
*
* Author: Mark Zhan <rongkai.zhan@windriver.com>
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c
index a9533535c3b7..59b54ed9b841 100644
--- a/drivers/rtc/rtc-m48t86.c
+++ b/drivers/rtc/rtc-m48t86.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ST M48T86 / Dallas DS12887 RTC driver
* Copyright (c) 2006 Tower Technologies
*
* Author: Alessandro Zummo <a.zummo@towertech.it>
*
- * 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.
- *
* This drivers only supports the clock running in BCD and 24H mode.
* If it will be ever adapted to binary and 12H mode, care must be taken
* to not introduce bugs.
diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c
index 745827463367..daaeb6fb6c2d 100644
--- a/drivers/rtc/rtc-max6902.c
+++ b/drivers/rtc/rtc-max6902.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* drivers/rtc/rtc-max6902.c
*
* Copyright (C) 2006 8D Technologies inc.
* Copyright (C) 2004 Compulab Ltd.
*
- * 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.
- *
* Driver for MAX6902 spi RTC
- *
*/
#include <linux/module.h>
diff --git a/drivers/rtc/rtc-max6916.c b/drivers/rtc/rtc-max6916.c
index 9d4b407cc4b8..e72e768ab8ff 100644
--- a/drivers/rtc/rtc-max6916.c
+++ b/drivers/rtc/rtc-max6916.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* rtc-max6916.c
*
* Driver for MAXIM max6916 Low Current, SPI Compatible
* Real Time Clock
*
* Author : Venkat Prashanth B U <venkat.prashanth2498@gmail.com>
- *
- * 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.
- *
*/
#include <linux/init.h>
diff --git a/drivers/rtc/rtc-max8907.c b/drivers/rtc/rtc-max8907.c
index 19c29b72598d..db3495d10274 100644
--- a/drivers/rtc/rtc-max8907.c
+++ b/drivers/rtc/rtc-max8907.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* RTC driver for Maxim MAX8907
*
@@ -5,10 +6,6 @@
*
* Based on drivers/rtc/rtc-max8925.c,
* Copyright (C) 2009-2010 Marvell International Ltd.
- *
- * 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.
*/
#include <linux/bcd.h>
diff --git a/drivers/rtc/rtc-max8925.c b/drivers/rtc/rtc-max8925.c
index 67d6fc2d23e6..64bb8ac6ef62 100644
--- a/drivers/rtc/rtc-max8925.c
+++ b/drivers/rtc/rtc-max8925.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* RTC driver for Maxim MAX8925
*
* Copyright (C) 2009-2010 Marvell International Ltd.
* Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/rtc/rtc-mcp795.c b/drivers/rtc/rtc-mcp795.c
index f22a945a3794..1660d5e79582 100644
--- a/drivers/rtc/rtc-mcp795.c
+++ b/drivers/rtc/rtc-mcp795.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* SPI Driver for Microchip MCP795 RTC
*
@@ -7,11 +8,6 @@
*
* Device datasheet:
* http://ww1.microchip.com/downloads/en/DeviceDoc/22280A.pdf
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c
index dd0364293bc0..15a9d0278778 100644
--- a/drivers/rtc/rtc-mpc5121.c
+++ b/drivers/rtc/rtc-mpc5121.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Real-time clock driver for MPC5121
*
* Copyright 2007, Domen Puncer <domen.puncer@telargo.com>
* Copyright 2008, Freescale Semiconductor, Inc. All rights reserved.
* Copyright 2011, Dmitry Eremin-Solenikov
- *
- * 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.
*/
#include <linux/init.h>
diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c
index 39da8b214275..fb542a930bf0 100644
--- a/drivers/rtc/rtc-pcf2123.c
+++ b/drivers/rtc/rtc-pcf2123.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* An SPI driver for the Philips PCF2123 RTC
* Copyright 2009 Cyber Switching, Inc.
@@ -10,10 +11,6 @@
* Thanks to Christian Pellegrin <chripell@fsfe.org> for
* the sysfs contributions to this driver.
*
- * 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.
- *
* Please note that the CS is active high, so platform data
* should look something like:
*
@@ -29,7 +26,6 @@
* },
* ...
*};
- *
*/
#include <linux/bcd.h>
@@ -44,7 +40,7 @@
#include <linux/rtc.h>
#include <linux/spi/spi.h>
#include <linux/module.h>
-#include <linux/sysfs.h>
+#include <linux/regmap.h>
/* REGISTERS */
#define PCF2123_REG_CTRL1 (0x00) /* Control Register 1 */
@@ -99,6 +95,7 @@
#define OFFSET_SIGN_BIT 6 /* 2's complement sign bit */
#define OFFSET_COARSE BIT(7) /* Coarse mode offset */
#define OFFSET_STEP (2170) /* Offset step in parts per billion */
+#define OFFSET_MASK GENMASK(6, 0) /* Offset value */
/* READ/WRITE ADDRESS BITS */
#define PCF2123_WRITE BIT(4)
@@ -107,120 +104,35 @@
static struct spi_driver pcf2123_driver;
-struct pcf2123_sysfs_reg {
- struct device_attribute attr;
- char name[2];
-};
-
struct pcf2123_plat_data {
struct rtc_device *rtc;
- struct pcf2123_sysfs_reg regs[16];
+ struct regmap *map;
};
-/*
- * Causes a 30 nanosecond delay to ensure that the PCF2123 chip select
- * is released properly after an SPI write. This function should be
- * called after EVERY read/write call over SPI.
- */
-static inline void pcf2123_delay_trec(void)
-{
- ndelay(30);
-}
-
-static int pcf2123_read(struct device *dev, u8 reg, u8 *rxbuf, size_t size)
-{
- struct spi_device *spi = to_spi_device(dev);
- int ret;
-
- reg |= PCF2123_READ;
- ret = spi_write_then_read(spi, &reg, 1, rxbuf, size);
- pcf2123_delay_trec();
-
- return ret;
-}
-
-static int pcf2123_write(struct device *dev, u8 *txbuf, size_t size)
-{
- struct spi_device *spi = to_spi_device(dev);
- int ret;
-
- txbuf[0] |= PCF2123_WRITE;
- ret = spi_write(spi, txbuf, size);
- pcf2123_delay_trec();
-
- return ret;
-}
-
-static int pcf2123_write_reg(struct device *dev, u8 reg, u8 val)
-{
- u8 txbuf[2];
-
- txbuf[0] = reg;
- txbuf[1] = val;
- return pcf2123_write(dev, txbuf, sizeof(txbuf));
-}
-
-static ssize_t pcf2123_show(struct device *dev, struct device_attribute *attr,
- char *buffer)
-{
- struct pcf2123_sysfs_reg *r;
- u8 rxbuf[1];
- unsigned long reg;
- int ret;
-
- r = container_of(attr, struct pcf2123_sysfs_reg, attr);
-
- ret = kstrtoul(r->name, 16, &reg);
- if (ret)
- return ret;
-
- ret = pcf2123_read(dev, reg, rxbuf, 1);
- if (ret < 0)
- return -EIO;
-
- return sprintf(buffer, "0x%x\n", rxbuf[0]);
-}
+static const struct regmap_config pcf2123_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .read_flag_mask = PCF2123_READ,
+ .write_flag_mask = PCF2123_WRITE,
+ .max_register = PCF2123_REG_CTDWN_TMR,
+};
-static ssize_t pcf2123_store(struct device *dev, struct device_attribute *attr,
- const char *buffer, size_t count)
+static int pcf2123_read_offset(struct device *dev, long *offset)
{
- struct pcf2123_sysfs_reg *r;
- unsigned long reg;
- unsigned long val;
+ struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
+ int ret, val;
+ unsigned int reg;
- int ret;
-
- r = container_of(attr, struct pcf2123_sysfs_reg, attr);
-
- ret = kstrtoul(r->name, 16, &reg);
+ ret = regmap_read(pdata->map, PCF2123_REG_OFFSET, &reg);
if (ret)
return ret;
- ret = kstrtoul(buffer, 10, &val);
- if (ret)
- return ret;
-
- ret = pcf2123_write_reg(dev, reg, val);
- if (ret < 0)
- return -EIO;
- return count;
-}
-
-static int pcf2123_read_offset(struct device *dev, long *offset)
-{
- int ret;
- s8 reg;
-
- ret = pcf2123_read(dev, PCF2123_REG_OFFSET, &reg, 1);
- if (ret < 0)
- return ret;
+ val = sign_extend32((reg & OFFSET_MASK), OFFSET_SIGN_BIT);
if (reg & OFFSET_COARSE)
- reg <<= 1; /* multiply by 2 and sign extend */
- else
- reg = sign_extend32(reg, OFFSET_SIGN_BIT);
+ val *= 2;
- *offset = ((long)reg) * OFFSET_STEP;
+ *offset = ((long)val) * OFFSET_STEP;
return 0;
}
@@ -237,6 +149,7 @@ static int pcf2123_read_offset(struct device *dev, long *offset)
*/
static int pcf2123_set_offset(struct device *dev, long offset)
{
+ struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
s8 reg;
if (offset > OFFSET_STEP * 127)
@@ -244,7 +157,7 @@ static int pcf2123_set_offset(struct device *dev, long offset)
else if (offset < OFFSET_STEP * -128)
reg = -128;
else
- reg = (s8)((offset + (OFFSET_STEP >> 1)) / OFFSET_STEP);
+ reg = DIV_ROUND_CLOSEST(offset, OFFSET_STEP);
/* choose fine offset only for odd values in the normal range */
if (reg & 1 && reg <= 63 && reg >= -64) {
@@ -256,16 +169,18 @@ static int pcf2123_set_offset(struct device *dev, long offset)
reg |= OFFSET_COARSE;
}
- return pcf2123_write_reg(dev, PCF2123_REG_OFFSET, reg);
+ return regmap_write(pdata->map, PCF2123_REG_OFFSET, (unsigned int)reg);
}
static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
+ struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
u8 rxbuf[7];
int ret;
- ret = pcf2123_read(dev, PCF2123_REG_SC, rxbuf, sizeof(rxbuf));
- if (ret < 0)
+ ret = regmap_bulk_read(pdata->map, PCF2123_REG_SC, rxbuf,
+ sizeof(rxbuf));
+ if (ret)
return ret;
if (rxbuf[0] & OSC_HAS_STOPPED) {
@@ -283,82 +198,168 @@ static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm)
if (tm->tm_year < 70)
tm->tm_year += 100; /* assume we are in 1970...2069 */
- dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
- "mday=%d, mon=%d, year=%d, wday=%d\n",
- __func__,
- tm->tm_sec, tm->tm_min, tm->tm_hour,
- tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+ dev_dbg(dev, "%s: tm is %ptR\n", __func__, tm);
return 0;
}
static int pcf2123_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
- u8 txbuf[8];
+ struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
+ u8 txbuf[7];
int ret;
- dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
- "mday=%d, mon=%d, year=%d, wday=%d\n",
- __func__,
- tm->tm_sec, tm->tm_min, tm->tm_hour,
- tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+ dev_dbg(dev, "%s: tm is %ptR\n", __func__, tm);
/* Stop the counter first */
- ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_STOP);
- if (ret < 0)
+ ret = regmap_write(pdata->map, PCF2123_REG_CTRL1, CTRL1_STOP);
+ if (ret)
return ret;
/* Set the new time */
- txbuf[0] = PCF2123_REG_SC;
- txbuf[1] = bin2bcd(tm->tm_sec & 0x7F);
- txbuf[2] = bin2bcd(tm->tm_min & 0x7F);
- txbuf[3] = bin2bcd(tm->tm_hour & 0x3F);
- txbuf[4] = bin2bcd(tm->tm_mday & 0x3F);
- txbuf[5] = tm->tm_wday & 0x07;
- txbuf[6] = bin2bcd((tm->tm_mon + 1) & 0x1F); /* rtc mn 1-12 */
- txbuf[7] = bin2bcd(tm->tm_year < 100 ? tm->tm_year : tm->tm_year - 100);
-
- ret = pcf2123_write(dev, txbuf, sizeof(txbuf));
- if (ret < 0)
+ txbuf[0] = bin2bcd(tm->tm_sec & 0x7F);
+ txbuf[1] = bin2bcd(tm->tm_min & 0x7F);
+ txbuf[2] = bin2bcd(tm->tm_hour & 0x3F);
+ txbuf[3] = bin2bcd(tm->tm_mday & 0x3F);
+ txbuf[4] = tm->tm_wday & 0x07;
+ txbuf[5] = bin2bcd((tm->tm_mon + 1) & 0x1F); /* rtc mn 1-12 */
+ txbuf[6] = bin2bcd(tm->tm_year < 100 ? tm->tm_year : tm->tm_year - 100);
+
+ ret = regmap_bulk_write(pdata->map, PCF2123_REG_SC, txbuf,
+ sizeof(txbuf));
+ if (ret)
return ret;
/* Start the counter */
- ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_CLEAR);
- if (ret < 0)
+ ret = regmap_write(pdata->map, PCF2123_REG_CTRL1, CTRL1_CLEAR);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int pcf2123_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+ struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
+ u8 rxbuf[4];
+ int ret;
+ unsigned int val = 0;
+
+ ret = regmap_bulk_read(pdata->map, PCF2123_REG_ALRM_MN, rxbuf,
+ sizeof(rxbuf));
+ if (ret)
+ return ret;
+
+ alm->time.tm_min = bcd2bin(rxbuf[0] & 0x7F);
+ alm->time.tm_hour = bcd2bin(rxbuf[1] & 0x3F);
+ alm->time.tm_mday = bcd2bin(rxbuf[2] & 0x3F);
+ alm->time.tm_wday = bcd2bin(rxbuf[3] & 0x07);
+
+ dev_dbg(dev, "%s: alm is %ptR\n", __func__, &alm->time);
+
+ ret = regmap_read(pdata->map, PCF2123_REG_CTRL2, &val);
+ if (ret)
+ return ret;
+
+ alm->enabled = !!(val & CTRL2_AIE);
+
+ return 0;
+}
+
+static int pcf2123_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+ struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
+ u8 txbuf[4];
+ int ret;
+
+ dev_dbg(dev, "%s: alm is %ptR\n", __func__, &alm->time);
+
+ /* Ensure alarm flag is clear */
+ ret = regmap_update_bits(pdata->map, PCF2123_REG_CTRL2, CTRL2_AF, 0);
+ if (ret)
return ret;
+ /* Disable alarm interrupt */
+ ret = regmap_update_bits(pdata->map, PCF2123_REG_CTRL2, CTRL2_AIE, 0);
+ if (ret)
+ return ret;
+
+ /* Set new alarm */
+ txbuf[0] = bin2bcd(alm->time.tm_min & 0x7F);
+ txbuf[1] = bin2bcd(alm->time.tm_hour & 0x3F);
+ txbuf[2] = bin2bcd(alm->time.tm_mday & 0x3F);
+ txbuf[3] = bin2bcd(alm->time.tm_wday & 0x07);
+
+ ret = regmap_bulk_write(pdata->map, PCF2123_REG_ALRM_MN, txbuf,
+ sizeof(txbuf));
+ if (ret)
+ return ret;
+
+ /* Enable alarm interrupt */
+ if (alm->enabled) {
+ ret = regmap_update_bits(pdata->map, PCF2123_REG_CTRL2,
+ CTRL2_AIE, CTRL2_AIE);
+ if (ret)
+ return ret;
+ }
+
return 0;
}
+static irqreturn_t pcf2123_rtc_irq(int irq, void *dev)
+{
+ struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
+ struct mutex *lock = &pdata->rtc->ops_lock;
+ unsigned int val = 0;
+ int ret = IRQ_NONE;
+
+ mutex_lock(lock);
+ regmap_read(pdata->map, PCF2123_REG_CTRL2, &val);
+
+ /* Alarm? */
+ if (val & CTRL2_AF) {
+ ret = IRQ_HANDLED;
+
+ /* Clear alarm flag */
+ regmap_update_bits(pdata->map, PCF2123_REG_CTRL2, CTRL2_AF, 0);
+
+ rtc_update_irq(pdata->rtc, 1, RTC_IRQF | RTC_AF);
+ }
+
+ mutex_unlock(lock);
+
+ return ret;
+}
+
static int pcf2123_reset(struct device *dev)
{
+ struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
int ret;
- u8 rxbuf[2];
+ unsigned int val = 0;
- ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_SW_RESET);
- if (ret < 0)
+ ret = regmap_write(pdata->map, PCF2123_REG_CTRL1, CTRL1_SW_RESET);
+ if (ret)
return ret;
/* Stop the counter */
dev_dbg(dev, "stopping RTC\n");
- ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_STOP);
- if (ret < 0)
+ ret = regmap_write(pdata->map, PCF2123_REG_CTRL1, CTRL1_STOP);
+ if (ret)
return ret;
/* See if the counter was actually stopped */
dev_dbg(dev, "checking for presence of RTC\n");
- ret = pcf2123_read(dev, PCF2123_REG_CTRL1, rxbuf, sizeof(rxbuf));
- if (ret < 0)
+ ret = regmap_read(pdata->map, PCF2123_REG_CTRL1, &val);
+ if (ret)
return ret;
- dev_dbg(dev, "received data from RTC (0x%02X 0x%02X)\n",
- rxbuf[0], rxbuf[1]);
- if (!(rxbuf[0] & CTRL1_STOP))
+ dev_dbg(dev, "received data from RTC (0x%08X)\n", val);
+ if (!(val & CTRL1_STOP))
return -ENODEV;
/* Start the counter */
- ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_CLEAR);
- if (ret < 0)
+ ret = regmap_write(pdata->map, PCF2123_REG_CTRL1, CTRL1_CLEAR);
+ if (ret)
return ret;
return 0;
@@ -369,7 +370,8 @@ static const struct rtc_class_ops pcf2123_rtc_ops = {
.set_time = pcf2123_rtc_set_time,
.read_offset = pcf2123_read_offset,
.set_offset = pcf2123_set_offset,
-
+ .read_alarm = pcf2123_rtc_read_alarm,
+ .set_alarm = pcf2123_rtc_set_alarm,
};
static int pcf2123_probe(struct spi_device *spi)
@@ -377,7 +379,7 @@ static int pcf2123_probe(struct spi_device *spi)
struct rtc_device *rtc;
struct rtc_time tm;
struct pcf2123_plat_data *pdata;
- int ret, i;
+ int ret = 0;
pdata = devm_kzalloc(&spi->dev, sizeof(struct pcf2123_plat_data),
GFP_KERNEL);
@@ -385,6 +387,13 @@ static int pcf2123_probe(struct spi_device *spi)
return -ENOMEM;
spi->dev.platform_data = pdata;
+ pdata->map = devm_regmap_init_spi(spi, &pcf2123_regmap_config);
+
+ if (IS_ERR(pdata->map)) {
+ dev_err(&spi->dev, "regmap init failed.\n");
+ goto kfree_exit;
+ }
+
ret = pcf2123_rtc_read_time(&spi->dev, &tm);
if (ret < 0) {
ret = pcf2123_reset(&spi->dev);
@@ -409,47 +418,31 @@ static int pcf2123_probe(struct spi_device *spi)
pdata->rtc = rtc;
- for (i = 0; i < 16; i++) {
- sysfs_attr_init(&pdata->regs[i].attr.attr);
- sprintf(pdata->regs[i].name, "%1x", i);
- pdata->regs[i].attr.attr.mode = S_IRUGO | S_IWUSR;
- pdata->regs[i].attr.attr.name = pdata->regs[i].name;
- pdata->regs[i].attr.show = pcf2123_show;
- pdata->regs[i].attr.store = pcf2123_store;
- ret = device_create_file(&spi->dev, &pdata->regs[i].attr);
- if (ret) {
- dev_err(&spi->dev, "Unable to create sysfs %s\n",
- pdata->regs[i].name);
- goto sysfs_exit;
- }
+ /* Register alarm irq */
+ if (spi->irq > 0) {
+ ret = devm_request_threaded_irq(&spi->dev, spi->irq, NULL,
+ pcf2123_rtc_irq,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ pcf2123_driver.driver.name, &spi->dev);
+ if (!ret)
+ device_init_wakeup(&spi->dev, true);
+ else
+ dev_err(&spi->dev, "could not request irq.\n");
}
- return 0;
+ /* The PCF2123's alarm only has minute accuracy. Must add timer
+ * support to this driver to generate interrupts more than once
+ * per minute.
+ */
+ pdata->rtc->uie_unsupported = 1;
-sysfs_exit:
- for (i--; i >= 0; i--)
- device_remove_file(&spi->dev, &pdata->regs[i].attr);
+ return 0;
kfree_exit:
spi->dev.platform_data = NULL;
return ret;
}
-static int pcf2123_remove(struct spi_device *spi)
-{
- struct pcf2123_plat_data *pdata = dev_get_platdata(&spi->dev);
- int i;
-
- if (pdata) {
- for (i = 0; i < 16; i++)
- if (pdata->regs[i].name[0])
- device_remove_file(&spi->dev,
- &pdata->regs[i].attr);
- }
-
- return 0;
-}
-
#ifdef CONFIG_OF
static const struct of_device_id pcf2123_dt_ids[] = {
{ .compatible = "nxp,rtc-pcf2123", },
@@ -465,7 +458,6 @@ static struct spi_driver pcf2123_driver = {
.of_match_table = of_match_ptr(pcf2123_dt_ids),
},
.probe = pcf2123_probe,
- .remove = pcf2123_remove,
};
module_spi_driver(pcf2123_driver);
diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c
index 7cb786d76e3c..8632f58fed43 100644
--- a/drivers/rtc/rtc-pcf2127.c
+++ b/drivers/rtc/rtc-pcf2127.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* An I2C and SPI driver for the NXP PCF2127/29 RTC
* Copyright 2013 Til-Technologies
@@ -7,10 +8,6 @@
* based on the other drivers in this same directory.
*
* Datasheet: http://cache.nxp.com/documents/data_sheet/PCF2127.pdf
- *
- * 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.
*/
#include <linux/i2c.h>
diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c
index b5c61a70b5df..2f435e533b10 100644
--- a/drivers/rtc/rtc-pcf8523.c
+++ b/drivers/rtc/rtc-pcf8523.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Avionic Design GmbH
- *
- * 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.
*/
#include <linux/bcd.h>
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index 3efc86c25d27..ac159d24286d 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* An I2C driver for the Philips PCF8563 RTC
* Copyright 2005-06 Tower Technologies
@@ -8,10 +9,6 @@
* based on the other drivers in this same directory.
*
* http://www.semiconductors.philips.com/acrobat/datasheets/PCF8563-04.pdf
- *
- * 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.
*/
#include <linux/clk-provider.h>
@@ -563,7 +560,6 @@ static int pcf8563_probe(struct i2c_client *client,
struct pcf8563 *pcf8563;
int err;
unsigned char buf;
- unsigned char alm_pending;
dev_dbg(&client->dev, "%s\n", __func__);
@@ -587,13 +583,13 @@ static int pcf8563_probe(struct i2c_client *client,
return err;
}
- err = pcf8563_get_alarm_mode(client, NULL, &alm_pending);
- if (err) {
- dev_err(&client->dev, "%s: read error\n", __func__);
+ /* Clear flags and disable interrupts */
+ buf = 0;
+ err = pcf8563_write_block_data(client, PCF8563_REG_ST2, 1, &buf);
+ if (err < 0) {
+ dev_err(&client->dev, "%s: write error\n", __func__);
return err;
}
- if (alm_pending)
- pcf8563_set_alarm_mode(client, 0);
pcf8563->rtc = devm_rtc_device_register(&client->dev,
pcf8563_driver.driver.name,
@@ -605,7 +601,7 @@ static int pcf8563_probe(struct i2c_client *client,
if (client->irq > 0) {
err = devm_request_threaded_irq(&client->dev, client->irq,
NULL, pcf8563_irq,
- IRQF_SHARED|IRQF_ONESHOT|IRQF_TRIGGER_FALLING,
+ IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_LOW,
pcf8563_driver.driver.name, client);
if (err) {
dev_err(&client->dev, "unable to request IRQ %d\n",
diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c
index 7ca9e8871d77..c80ca20e5d8d 100644
--- a/drivers/rtc/rtc-pcf8583.c
+++ b/drivers/rtc/rtc-pcf8583.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/rtc/rtc-pcf8583.c
*
* Copyright (C) 2000 Russell King
* Copyright (C) 2008 Wolfram Sang & Juergen Beisert, Pengutronix
*
- * 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.
- *
* Driver for PCF8583 RTC & RAM chip
*
* Converted to the generic RTC susbsystem by G. Liakhovetski (2006)
diff --git a/drivers/rtc/rtc-pl030.c b/drivers/rtc/rtc-pl030.c
index 343bb6ed1783..d4a5f8afafbc 100644
--- a/drivers/rtc/rtc-pl030.c
+++ b/drivers/rtc/rtc-pl030.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/rtc/rtc-pl030.c
*
* Copyright (C) 2000-2001 Deep Blue Solutions Ltd.
- *
- * 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.
*/
#include <linux/module.h>
#include <linux/rtc.h>
diff --git a/drivers/rtc/rtc-puv3.c b/drivers/rtc/rtc-puv3.c
index f77ef282f013..63b9e73fb97d 100644
--- a/drivers/rtc/rtc-puv3.c
+++ b/drivers/rtc/rtc-puv3.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* RTC driver code specific to PKUnity SoC and UniCore ISA
*
* Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
* Copyright (C) 2001-2010 Guan Xuetao
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/rtc/rtc-r9701.c b/drivers/rtc/rtc-r9701.c
index a39ccd1cf6e8..84f0d25259ae 100644
--- a/drivers/rtc/rtc-r9701.c
+++ b/drivers/rtc/rtc-r9701.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for Epson RTC-9701JE
*
@@ -7,10 +8,6 @@
*
* Copyright (C) 2006 8D Technologies inc.
* Copyright (C) 2004 Compulab Ltd.
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/rtc/rtc-rk808.c b/drivers/rtc/rtc-rk808.c
index 2316b0343b03..c34540baa12a 100644
--- a/drivers/rtc/rtc-rk808.c
+++ b/drivers/rtc/rtc-rk808.c
@@ -42,9 +42,18 @@
#define NUM_TIME_REGS (RK808_WEEKS_REG - RK808_SECONDS_REG + 1)
#define NUM_ALARM_REGS (RK808_ALARM_YEARS_REG - RK808_ALARM_SECONDS_REG + 1)
+struct rk_rtc_compat_reg {
+ unsigned int ctrl_reg;
+ unsigned int status_reg;
+ unsigned int alarm_seconds_reg;
+ unsigned int int_reg;
+ unsigned int seconds_reg;
+};
+
struct rk808_rtc {
struct rk808 *rk808;
struct rtc_device *rtc;
+ struct rk_rtc_compat_reg *creg;
int irq;
};
@@ -93,7 +102,7 @@ static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm)
int ret;
/* Force an update of the shadowed registers right now */
- ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG,
+ ret = regmap_update_bits(rk808->regmap, rk808_rtc->creg->ctrl_reg,
BIT_RTC_CTRL_REG_RTC_GET_TIME,
BIT_RTC_CTRL_REG_RTC_GET_TIME);
if (ret) {
@@ -107,7 +116,7 @@ static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm)
* 32khz. If we clear the GET_TIME bit here, the time of i2c transfer
* certainly more than 31.25us: 16 * 2.5us at 400kHz bus frequency.
*/
- ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG,
+ ret = regmap_update_bits(rk808->regmap, rk808_rtc->creg->ctrl_reg,
BIT_RTC_CTRL_REG_RTC_GET_TIME,
0);
if (ret) {
@@ -115,7 +124,7 @@ static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm)
return ret;
}
- ret = regmap_bulk_read(rk808->regmap, RK808_SECONDS_REG,
+ ret = regmap_bulk_read(rk808->regmap, rk808_rtc->creg->seconds_reg,
rtc_data, NUM_TIME_REGS);
if (ret) {
dev_err(dev, "Failed to bulk read rtc_data: %d\n", ret);
@@ -154,7 +163,7 @@ static int rk808_rtc_set_time(struct device *dev, struct rtc_time *tm)
rtc_data[6] = bin2bcd(tm->tm_wday);
/* Stop RTC while updating the RTC registers */
- ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG,
+ ret = regmap_update_bits(rk808->regmap, rk808_rtc->creg->ctrl_reg,
BIT_RTC_CTRL_REG_STOP_RTC_M,
BIT_RTC_CTRL_REG_STOP_RTC_M);
if (ret) {
@@ -162,14 +171,14 @@ static int rk808_rtc_set_time(struct device *dev, struct rtc_time *tm)
return ret;
}
- ret = regmap_bulk_write(rk808->regmap, RK808_SECONDS_REG,
+ ret = regmap_bulk_write(rk808->regmap, rk808_rtc->creg->seconds_reg,
rtc_data, NUM_TIME_REGS);
if (ret) {
dev_err(dev, "Failed to bull write rtc_data: %d\n", ret);
return ret;
}
/* Start RTC again */
- ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG,
+ ret = regmap_update_bits(rk808->regmap, rk808_rtc->creg->ctrl_reg,
BIT_RTC_CTRL_REG_STOP_RTC_M, 0);
if (ret) {
dev_err(dev, "Failed to update RTC control: %d\n", ret);
@@ -187,8 +196,13 @@ static int rk808_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
uint32_t int_reg;
int ret;
- ret = regmap_bulk_read(rk808->regmap, RK808_ALARM_SECONDS_REG,
+ ret = regmap_bulk_read(rk808->regmap,
+ rk808_rtc->creg->alarm_seconds_reg,
alrm_data, NUM_ALARM_REGS);
+ if (ret) {
+ dev_err(dev, "Failed to read RTC alarm date REG: %d\n", ret);
+ return ret;
+ }
alrm->time.tm_sec = bcd2bin(alrm_data[0] & SECONDS_REG_MSK);
alrm->time.tm_min = bcd2bin(alrm_data[1] & MINUTES_REG_MAK);
@@ -198,7 +212,7 @@ static int rk808_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
alrm->time.tm_year = (bcd2bin(alrm_data[5] & YEARS_REG_MSK)) + 100;
rockchip_to_gregorian(&alrm->time);
- ret = regmap_read(rk808->regmap, RK808_RTC_INT_REG, &int_reg);
+ ret = regmap_read(rk808->regmap, rk808_rtc->creg->int_reg, &int_reg);
if (ret) {
dev_err(dev, "Failed to read RTC INT REG: %d\n", ret);
return ret;
@@ -217,7 +231,7 @@ static int rk808_rtc_stop_alarm(struct rk808_rtc *rk808_rtc)
struct rk808 *rk808 = rk808_rtc->rk808;
int ret;
- ret = regmap_update_bits(rk808->regmap, RK808_RTC_INT_REG,
+ ret = regmap_update_bits(rk808->regmap, rk808_rtc->creg->int_reg,
BIT_RTC_INTERRUPTS_REG_IT_ALARM_M, 0);
return ret;
@@ -228,7 +242,7 @@ static int rk808_rtc_start_alarm(struct rk808_rtc *rk808_rtc)
struct rk808 *rk808 = rk808_rtc->rk808;
int ret;
- ret = regmap_update_bits(rk808->regmap, RK808_RTC_INT_REG,
+ ret = regmap_update_bits(rk808->regmap, rk808_rtc->creg->int_reg,
BIT_RTC_INTERRUPTS_REG_IT_ALARM_M,
BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
@@ -258,7 +272,8 @@ static int rk808_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
alrm_data[4] = bin2bcd(alrm->time.tm_mon + 1);
alrm_data[5] = bin2bcd(alrm->time.tm_year - 100);
- ret = regmap_bulk_write(rk808->regmap, RK808_ALARM_SECONDS_REG,
+ ret = regmap_bulk_write(rk808->regmap,
+ rk808_rtc->creg->alarm_seconds_reg,
alrm_data, NUM_ALARM_REGS);
if (ret) {
dev_err(dev, "Failed to bulk write: %d\n", ret);
@@ -302,7 +317,7 @@ static irqreturn_t rk808_alarm_irq(int irq, void *data)
struct i2c_client *client = rk808->i2c;
int ret;
- ret = regmap_write(rk808->regmap, RK808_RTC_STATUS_REG,
+ ret = regmap_write(rk808->regmap, rk808_rtc->creg->status_reg,
RTC_STATUS_MASK);
if (ret) {
dev_err(&client->dev,
@@ -353,6 +368,22 @@ static int rk808_rtc_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(rk808_rtc_pm_ops,
rk808_rtc_suspend, rk808_rtc_resume);
+static struct rk_rtc_compat_reg rk808_creg = {
+ .ctrl_reg = RK808_RTC_CTRL_REG,
+ .status_reg = RK808_RTC_STATUS_REG,
+ .alarm_seconds_reg = RK808_ALARM_SECONDS_REG,
+ .int_reg = RK808_RTC_INT_REG,
+ .seconds_reg = RK808_SECONDS_REG,
+};
+
+static struct rk_rtc_compat_reg rk817_creg = {
+ .ctrl_reg = RK817_RTC_CTRL_REG,
+ .status_reg = RK817_RTC_STATUS_REG,
+ .alarm_seconds_reg = RK817_ALARM_SECONDS_REG,
+ .int_reg = RK817_RTC_INT_REG,
+ .seconds_reg = RK817_SECONDS_REG,
+};
+
static int rk808_rtc_probe(struct platform_device *pdev)
{
struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent);
@@ -363,11 +394,20 @@ static int rk808_rtc_probe(struct platform_device *pdev)
if (rk808_rtc == NULL)
return -ENOMEM;
+ switch (rk808->variant) {
+ case RK809_ID:
+ case RK817_ID:
+ rk808_rtc->creg = &rk817_creg;
+ break;
+ default:
+ rk808_rtc->creg = &rk808_creg;
+ break;
+ }
platform_set_drvdata(pdev, rk808_rtc);
rk808_rtc->rk808 = rk808;
/* start rtc running by default, and use shadowed timer. */
- ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG,
+ ret = regmap_update_bits(rk808->regmap, rk808_rtc->creg->ctrl_reg,
BIT_RTC_CTRL_REG_STOP_RTC_M |
BIT_RTC_CTRL_REG_RTC_READSEL_M,
BIT_RTC_CTRL_REG_RTC_READSEL_M);
@@ -377,7 +417,7 @@ static int rk808_rtc_probe(struct platform_device *pdev)
return ret;
}
- ret = regmap_write(rk808->regmap, RK808_RTC_STATUS_REG,
+ ret = regmap_write(rk808->regmap, rk808_rtc->creg->status_reg,
RTC_STATUS_MASK);
if (ret) {
dev_err(&pdev->dev,
diff --git a/drivers/rtc/rtc-rs5c348.c b/drivers/rtc/rtc-rs5c348.c
index 6582be707bd0..47c13678449e 100644
--- a/drivers/rtc/rtc-rs5c348.c
+++ b/drivers/rtc/rtc-rs5c348.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* A SPI driver for the Ricoh RS5C348 RTC
*
* Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
*
- * 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.
- *
* The board specific init code should provide characteristics of this
* device:
* Mode 1 (High-Active, Shift-Then-Sample), High Avtive CS
diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
index 66a473a3c3fe..3bd6eaa0dcf6 100644
--- a/drivers/rtc/rtc-rs5c372.c
+++ b/drivers/rtc/rtc-rs5c372.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* An I2C driver for Ricoh RS5C372, R2025S/D and RV5C38[67] RTCs
*
* Copyright (C) 2005 Pavel Mironchik <pmironchik@optifacio.net>
* Copyright (C) 2006 Tower Technologies
* Copyright (C) 2008 Paul Mundt
- *
- * 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.
*/
#include <linux/i2c.h>
diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c
index 3d6174eb32f6..4a0e8ec015cc 100644
--- a/drivers/rtc/rtc-rv3029c2.c
+++ b/drivers/rtc/rtc-rv3029c2.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Micro Crystal RV-3029 / RV-3049 rtc class driver
*
@@ -5,11 +6,6 @@
* Michael Buesch <m@bues.ch>
*
* based on previously existing rtc class drivers
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c
index 0b102c3cf5a4..fc5243400108 100644
--- a/drivers/rtc/rtc-rv8803.c
+++ b/drivers/rtc/rtc-rv8803.c
@@ -517,7 +517,7 @@ static int rx8900_trickle_charger_init(struct rv8803_data *rv8803)
static int rv8803_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adapter = client->adapter;
struct rv8803_data *rv8803;
int err, flags;
struct nvmem_config nvmem_cfg = {
diff --git a/drivers/rtc/rtc-rx4581.c b/drivers/rtc/rtc-rx4581.c
index c59a218bdd87..c092e0452347 100644
--- a/drivers/rtc/rtc-rx4581.c
+++ b/drivers/rtc/rtc-rx4581.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* drivers/rtc/rtc-rx4581.c
*
* written by Torben Hohn <torbenh@linutronix.de>
@@ -8,10 +9,6 @@
* Copyright (C) 2006 8D Technologies inc.
* Copyright (C) 2004 Compulab Ltd.
*
- * 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.
- *
* Driver for MAX6902 spi RTC
*
* and based on:
@@ -22,13 +19,8 @@
* Author: Martyn Welch <martyn.welch@ge.com>
* Copyright 2008 GE Intelligent Platforms Embedded Systems, 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.
- *
* Based on: rtc-pcf8563.c (An I2C driver for the Philips PCF8563 RTC)
* Copyright 2005-06 Tower Technologies
- *
*/
#include <linux/module.h>
diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c
index 7ddc22eb5b0f..8102469e27c0 100644
--- a/drivers/rtc/rtc-rx8010.c
+++ b/drivers/rtc/rtc-rx8010.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for the Epson RTC module RX-8010 SJ
*
* Copyright(C) Timesys Corporation 2015
* Copyright(C) General Electric Company 2015
- *
- * 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.
- *
*/
#include <linux/bcd.h>
@@ -437,7 +433,7 @@ static struct rtc_class_ops rx8010_rtc_ops = {
static int rx8010_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adapter = client->adapter;
struct rx8010_data *rx8010;
int err = 0;
diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c
index fddc996cb38d..b9bda10589e0 100644
--- a/drivers/rtc/rtc-rx8025.c
+++ b/drivers/rtc/rtc-rx8025.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for Epson's RTC module RX-8025 SA/NB
*
@@ -13,10 +14,6 @@
* Code cleanup by Sergei Poselenov, <sposelenov@emcraft.com>
* Converted to new style by Wolfgang Grandegger <wg@grandegger.com>
* Alarm and periodic interrupt added by Dmitry Rakhchev <rda@emcraft.com>
- *
- * 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.
*/
#include <linux/bcd.h>
#include <linux/bitops.h>
@@ -504,7 +501,7 @@ static void rx8025_sysfs_unregister(struct device *dev)
static int rx8025_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adapter = client->adapter;
struct rx8025_data *rx8025;
int err = 0;
diff --git a/drivers/rtc/rtc-rx8581.c b/drivers/rtc/rtc-rx8581.c
index 776e3a2b89e8..490f70f57636 100644
--- a/drivers/rtc/rtc-rx8581.c
+++ b/drivers/rtc/rtc-rx8581.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* An I2C driver for the Epson RX8581 RTC
*
* Author: Martyn Welch <martyn.welch@ge.com>
* Copyright 2008 GE Intelligent Platforms Embedded Systems, 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.
- *
* Based on: rtc-pcf8563.c (An I2C driver for the Philips PCF8563 RTC)
* Copyright 2005-06 Tower Technologies
*/
diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c
index 8c37acb4a007..84806ff763cf 100644
--- a/drivers/rtc/rtc-s35390a.c
+++ b/drivers/rtc/rtc-s35390a.c
@@ -32,21 +32,22 @@
#define S35390A_ALRM_BYTE_MINS 2
/* flags for STATUS1 */
-#define S35390A_FLAG_POC 0x01
-#define S35390A_FLAG_BLD 0x02
-#define S35390A_FLAG_INT2 0x04
-#define S35390A_FLAG_24H 0x40
-#define S35390A_FLAG_RESET 0x80
+#define S35390A_FLAG_POC BIT(0)
+#define S35390A_FLAG_BLD BIT(1)
+#define S35390A_FLAG_INT2 BIT(2)
+#define S35390A_FLAG_24H BIT(6)
+#define S35390A_FLAG_RESET BIT(7)
/* flag for STATUS2 */
-#define S35390A_FLAG_TEST 0x01
-
-#define S35390A_INT2_MODE_MASK 0xF0
+#define S35390A_FLAG_TEST BIT(0)
+/* INT2 pin output mode */
+#define S35390A_INT2_MODE_MASK 0x0E
#define S35390A_INT2_MODE_NOINTR 0x00
-#define S35390A_INT2_MODE_FREQ 0x10
-#define S35390A_INT2_MODE_ALARM 0x40
-#define S35390A_INT2_MODE_PMIN_EDG 0x20
+#define S35390A_INT2_MODE_ALARM BIT(1) /* INT2AE */
+#define S35390A_INT2_MODE_PMIN_EDG BIT(2) /* INT2ME */
+#define S35390A_INT2_MODE_FREQ BIT(3) /* INT2FE */
+#define S35390A_INT2_MODE_PMIN (BIT(3) | BIT(2)) /* INT2FE | INT2ME */
static const struct i2c_device_id s35390a_id[] = {
{ "s35390a", 0 },
@@ -284,6 +285,9 @@ static int s35390a_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
alm->time.tm_min, alm->time.tm_hour, alm->time.tm_mday,
alm->time.tm_mon, alm->time.tm_year, alm->time.tm_wday);
+ if (alm->time.tm_sec != 0)
+ dev_warn(&client->dev, "Alarms are only supported on a per minute basis!\n");
+
/* disable interrupt (which deasserts the irq line) */
err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts));
if (err < 0)
@@ -299,9 +303,6 @@ static int s35390a_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
else
sts = S35390A_INT2_MODE_NOINTR;
- /* This chip expects the bits of each byte to be in reverse order */
- sts = bitrev8(sts);
-
/* set interupt mode*/
err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts));
if (err < 0)
@@ -339,7 +340,7 @@ static int s35390a_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
if (err < 0)
return err;
- if ((bitrev8(sts) & S35390A_INT2_MODE_MASK) != S35390A_INT2_MODE_ALARM) {
+ if ((sts & S35390A_INT2_MODE_MASK) != S35390A_INT2_MODE_ALARM) {
/*
* When the alarm isn't enabled, the register to configure
* the alarm time isn't accessible.
@@ -431,14 +432,14 @@ static int s35390a_probe(struct i2c_client *client,
unsigned int i;
struct s35390a *s35390a;
char buf, status1;
+ struct device *dev = &client->dev;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
err = -ENODEV;
goto exit;
}
- s35390a = devm_kzalloc(&client->dev, sizeof(struct s35390a),
- GFP_KERNEL);
+ s35390a = devm_kzalloc(dev, sizeof(struct s35390a), GFP_KERNEL);
if (!s35390a) {
err = -ENOMEM;
goto exit;
@@ -452,8 +453,8 @@ static int s35390a_probe(struct i2c_client *client,
s35390a->client[i] = i2c_new_dummy(client->adapter,
client->addr + i);
if (!s35390a->client[i]) {
- dev_err(&client->dev, "Address %02x unavailable\n",
- client->addr + i);
+ dev_err(dev, "Address %02x unavailable\n",
+ client->addr + i);
err = -EBUSY;
goto exit_dummy;
}
@@ -462,7 +463,7 @@ static int s35390a_probe(struct i2c_client *client,
err_read = s35390a_read_status(s35390a, &status1);
if (err_read < 0) {
err = err_read;
- dev_err(&client->dev, "error resetting chip\n");
+ dev_err(dev, "error resetting chip\n");
goto exit_dummy;
}
@@ -476,28 +477,30 @@ static int s35390a_probe(struct i2c_client *client,
buf = 0;
err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &buf, 1);
if (err < 0) {
- dev_err(&client->dev, "error disabling alarm");
+ dev_err(dev, "error disabling alarm");
goto exit_dummy;
}
} else {
err = s35390a_disable_test_mode(s35390a);
if (err < 0) {
- dev_err(&client->dev, "error disabling test mode\n");
+ dev_err(dev, "error disabling test mode\n");
goto exit_dummy;
}
}
- device_set_wakeup_capable(&client->dev, 1);
+ device_set_wakeup_capable(dev, 1);
- s35390a->rtc = devm_rtc_device_register(&client->dev,
- s35390a_driver.driver.name,
- &s35390a_rtc_ops, THIS_MODULE);
+ s35390a->rtc = devm_rtc_device_register(dev, s35390a_driver.driver.name,
+ &s35390a_rtc_ops, THIS_MODULE);
if (IS_ERR(s35390a->rtc)) {
err = PTR_ERR(s35390a->rtc);
goto exit_dummy;
}
+ /* supports per-minute alarms only, therefore set uie_unsupported */
+ s35390a->rtc->uie_unsupported = 1;
+
if (status1 & S35390A_FLAG_INT2)
rtc_update_irq(s35390a->rtc, 1, RTC_AF);
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index e81a2b22a5c3..74bf6473a05d 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* drivers/rtc/rtc-s3c.c
*
* Copyright (c) 2010 Samsung Electronics Co., Ltd.
@@ -7,10 +8,6 @@
* Ben Dooks, <ben@simtec.co.uk>
* http://armlinux.simtec.co.uk/
*
- * 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.
- *
* S3C2410/S3C2440/S3C24XX Internal RTC Driver
*/
diff --git a/drivers/rtc/rtc-s3c.h b/drivers/rtc/rtc-s3c.h
index 004b61a8343f..3552914aa611 100644
--- a/drivers/rtc/rtc-s3c.h
+++ b/drivers/rtc/rtc-s3c.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
* http://www.simtec.co.uk/products/SWLINUX/
*
- * 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.
- *
* S3C2410 Internal RTC register definition
*/
diff --git a/drivers/rtc/rtc-st-lpc.c b/drivers/rtc/rtc-st-lpc.c
index 5fe021821831..49474a31c66d 100644
--- a/drivers/rtc/rtc-st-lpc.c
+++ b/drivers/rtc/rtc-st-lpc.c
@@ -162,10 +162,6 @@ static int st_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t)
now_secs = rtc_tm_to_time64(&now);
alarm_secs = rtc_tm_to_time64(&t->time);
- /* Invalid alarm time */
- if (now_secs > alarm_secs)
- return -EINVAL;
-
memcpy(&rtc->alarm, t, sizeof(struct rtc_wkalrm));
/* Now many secs to fire */
diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c
index fccbecbb2c98..a833ebc4ecb9 100644
--- a/drivers/rtc/rtc-stk17ta8.c
+++ b/drivers/rtc/rtc-stk17ta8.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* A RTC driver for the Simtek STK17TA8
*
@@ -5,10 +6,6 @@
*
* Based on the DS1553 driver from
* Atsushi Nemoto <anemo@mba.ocn.ne.jp>
- *
- * 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.
*/
#include <linux/bcd.h>
diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c
index 8e6c9b3bcc29..773a1990b93f 100644
--- a/drivers/rtc/rtc-stm32.c
+++ b/drivers/rtc/rtc-stm32.c
@@ -519,11 +519,7 @@ static int stm32_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
/* Write to Alarm register */
writel_relaxed(alrmar, rtc->base + regs->alrmar);
- if (alrm->enabled)
- stm32_rtc_alarm_irq_enable(dev, 1);
- else
- stm32_rtc_alarm_irq_enable(dev, 0);
-
+ stm32_rtc_alarm_irq_enable(dev, alrm->enabled);
end:
stm32_rtc_wpr_lock(rtc);
diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c
index 8128ec200ba2..c0e75c373605 100644
--- a/drivers/rtc/rtc-sun6i.c
+++ b/drivers/rtc/rtc-sun6i.c
@@ -672,6 +672,7 @@ static const struct of_device_id sun6i_rtc_dt_ids[] = {
{ .compatible = "allwinner,sun6i-a31-rtc" },
{ .compatible = "allwinner,sun8i-a23-rtc" },
{ .compatible = "allwinner,sun8i-h3-rtc" },
+ { .compatible = "allwinner,sun8i-r40-rtc" },
{ .compatible = "allwinner,sun8i-v3-rtc" },
{ .compatible = "allwinner,sun50i-h5-rtc" },
{ /* sentinel */ },
diff --git a/drivers/rtc/rtc-tegra.c b/drivers/rtc/rtc-tegra.c
index f0ce76865434..8fa1b3febf69 100644
--- a/drivers/rtc/rtc-tegra.c
+++ b/drivers/rtc/rtc-tegra.c
@@ -2,7 +2,7 @@
/*
* An RTC driver for the NVIDIA Tegra 200 series internal RTC.
*
- * Copyright (c) 2010, NVIDIA Corporation.
+ * Copyright (c) 2010-2019, NVIDIA Corporation.
*/
#include <linux/clk.h>
@@ -18,10 +18,10 @@
#include <linux/rtc.h>
#include <linux/slab.h>
-/* set to 1 = busy every eight 32kHz clocks during copy of sec+msec to AHB */
+/* Set to 1 = busy every eight 32 kHz clocks during copy of sec+msec to AHB. */
#define TEGRA_RTC_REG_BUSY 0x004
#define TEGRA_RTC_REG_SECONDS 0x008
-/* when msec is read, the seconds are buffered into shadow seconds. */
+/* When msec is read, the seconds are buffered into shadow seconds. */
#define TEGRA_RTC_REG_SHADOW_SECONDS 0x00c
#define TEGRA_RTC_REG_MILLI_SECONDS 0x010
#define TEGRA_RTC_REG_SECONDS_ALARM0 0x014
@@ -46,44 +46,48 @@
#define TEGRA_RTC_INTR_STATUS_SEC_ALARM0 (1<<0)
struct tegra_rtc_info {
- struct platform_device *pdev;
- struct rtc_device *rtc_dev;
- void __iomem *rtc_base; /* NULL if not initialized. */
- struct clk *clk;
- int tegra_rtc_irq; /* alarm and periodic irq */
- spinlock_t tegra_rtc_lock;
+ struct platform_device *pdev;
+ struct rtc_device *rtc;
+ void __iomem *base; /* NULL if not initialized */
+ struct clk *clk;
+ int irq; /* alarm and periodic IRQ */
+ spinlock_t lock;
};
-/* RTC hardware is busy when it is updating its values over AHB once
- * every eight 32kHz clocks (~250uS).
- * outside of these updates the CPU is free to write.
- * CPU is always free to read.
+/*
+ * RTC hardware is busy when it is updating its values over AHB once every
+ * eight 32 kHz clocks (~250 us). Outside of these updates the CPU is free to
+ * write. CPU is always free to read.
*/
static inline u32 tegra_rtc_check_busy(struct tegra_rtc_info *info)
{
- return readl(info->rtc_base + TEGRA_RTC_REG_BUSY) & 1;
+ return readl(info->base + TEGRA_RTC_REG_BUSY) & 1;
}
-/* Wait for hardware to be ready for writing.
- * This function tries to maximize the amount of time before the next update.
- * It does this by waiting for the RTC to become busy with its periodic update,
- * then returning once the RTC first becomes not busy.
+/*
+ * Wait for hardware to be ready for writing. This function tries to maximize
+ * the amount of time before the next update. It does this by waiting for the
+ * RTC to become busy with its periodic update, then returning once the RTC
+ * first becomes not busy.
+ *
* This periodic update (where the seconds and milliseconds are copied to the
- * AHB side) occurs every eight 32kHz clocks (~250uS).
- * The behavior of this function allows us to make some assumptions without
- * introducing a race, because 250uS is plenty of time to read/write a value.
+ * AHB side) occurs every eight 32 kHz clocks (~250 us). The behavior of this
+ * function allows us to make some assumptions without introducing a race,
+ * because 250 us is plenty of time to read/write a value.
*/
static int tegra_rtc_wait_while_busy(struct device *dev)
{
struct tegra_rtc_info *info = dev_get_drvdata(dev);
+ int retries = 500; /* ~490 us is the worst case, ~250 us is best */
- int retries = 500; /* ~490 us is the worst case, ~250 us is best. */
-
- /* first wait for the RTC to become busy. this is when it
- * posts its updated seconds+msec registers to AHB side. */
+ /*
+ * First wait for the RTC to become busy. This is when it posts its
+ * updated seconds+msec registers to AHB side.
+ */
while (tegra_rtc_check_busy(info)) {
if (!retries--)
goto retry_failed;
+
udelay(1);
}
@@ -91,28 +95,30 @@ static int tegra_rtc_wait_while_busy(struct device *dev)
return 0;
retry_failed:
- dev_err(dev, "write failed:retry count exceeded.\n");
+ dev_err(dev, "write failed: retry count exceeded\n");
return -ETIMEDOUT;
}
static int tegra_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct tegra_rtc_info *info = dev_get_drvdata(dev);
- unsigned long sec, msec;
- unsigned long sl_irq_flags;
+ unsigned long flags;
+ u32 sec, msec;
- /* RTC hardware copies seconds to shadow seconds when a read
- * of milliseconds occurs. use a lock to keep other threads out. */
- spin_lock_irqsave(&info->tegra_rtc_lock, sl_irq_flags);
+ /*
+ * RTC hardware copies seconds to shadow seconds when a read of
+ * milliseconds occurs. use a lock to keep other threads out.
+ */
+ spin_lock_irqsave(&info->lock, flags);
- msec = readl(info->rtc_base + TEGRA_RTC_REG_MILLI_SECONDS);
- sec = readl(info->rtc_base + TEGRA_RTC_REG_SHADOW_SECONDS);
+ msec = readl(info->base + TEGRA_RTC_REG_MILLI_SECONDS);
+ sec = readl(info->base + TEGRA_RTC_REG_SHADOW_SECONDS);
- spin_unlock_irqrestore(&info->tegra_rtc_lock, sl_irq_flags);
+ spin_unlock_irqrestore(&info->lock, flags);
rtc_time64_to_tm(sec, tm);
- dev_vdbg(dev, "time read as %lu. %ptR\n", sec, tm);
+ dev_vdbg(dev, "time read as %u, %ptR\n", sec, tm);
return 0;
}
@@ -120,21 +126,21 @@ static int tegra_rtc_read_time(struct device *dev, struct rtc_time *tm)
static int tegra_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct tegra_rtc_info *info = dev_get_drvdata(dev);
- unsigned long sec;
+ u32 sec;
int ret;
- /* convert tm to seconds. */
+ /* convert tm to seconds */
sec = rtc_tm_to_time64(tm);
- dev_vdbg(dev, "time set to %lu. %ptR\n", sec, tm);
+ dev_vdbg(dev, "time set to %u, %ptR\n", sec, tm);
- /* seconds only written if wait succeeded. */
+ /* seconds only written if wait succeeded */
ret = tegra_rtc_wait_while_busy(dev);
if (!ret)
- writel(sec, info->rtc_base + TEGRA_RTC_REG_SECONDS);
+ writel(sec, info->base + TEGRA_RTC_REG_SECONDS);
dev_vdbg(dev, "time read back as %d\n",
- readl(info->rtc_base + TEGRA_RTC_REG_SECONDS));
+ readl(info->base + TEGRA_RTC_REG_SECONDS));
return ret;
}
@@ -142,22 +148,21 @@ static int tegra_rtc_set_time(struct device *dev, struct rtc_time *tm)
static int tegra_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
struct tegra_rtc_info *info = dev_get_drvdata(dev);
- unsigned long sec;
- unsigned tmp;
+ u32 sec, value;
- sec = readl(info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0);
+ sec = readl(info->base + TEGRA_RTC_REG_SECONDS_ALARM0);
if (sec == 0) {
- /* alarm is disabled. */
+ /* alarm is disabled */
alarm->enabled = 0;
} else {
- /* alarm is enabled. */
+ /* alarm is enabled */
alarm->enabled = 1;
rtc_time64_to_tm(sec, &alarm->time);
}
- tmp = readl(info->rtc_base + TEGRA_RTC_REG_INTR_STATUS);
- alarm->pending = (tmp & TEGRA_RTC_INTR_STATUS_SEC_ALARM0) != 0;
+ value = readl(info->base + TEGRA_RTC_REG_INTR_STATUS);
+ alarm->pending = (value & TEGRA_RTC_INTR_STATUS_SEC_ALARM0) != 0;
return 0;
}
@@ -165,22 +170,22 @@ static int tegra_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
static int tegra_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
struct tegra_rtc_info *info = dev_get_drvdata(dev);
- unsigned status;
- unsigned long sl_irq_flags;
+ unsigned long flags;
+ u32 status;
tegra_rtc_wait_while_busy(dev);
- spin_lock_irqsave(&info->tegra_rtc_lock, sl_irq_flags);
+ spin_lock_irqsave(&info->lock, flags);
- /* read the original value, and OR in the flag. */
- status = readl(info->rtc_base + TEGRA_RTC_REG_INTR_MASK);
+ /* read the original value, and OR in the flag */
+ status = readl(info->base + TEGRA_RTC_REG_INTR_MASK);
if (enabled)
status |= TEGRA_RTC_INTR_MASK_SEC_ALARM0; /* set it */
else
status &= ~TEGRA_RTC_INTR_MASK_SEC_ALARM0; /* clear it */
- writel(status, info->rtc_base + TEGRA_RTC_REG_INTR_MASK);
+ writel(status, info->base + TEGRA_RTC_REG_INTR_MASK);
- spin_unlock_irqrestore(&info->tegra_rtc_lock, sl_irq_flags);
+ spin_unlock_irqrestore(&info->lock, flags);
return 0;
}
@@ -188,7 +193,7 @@ static int tegra_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
static int tegra_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
struct tegra_rtc_info *info = dev_get_drvdata(dev);
- unsigned long sec;
+ u32 sec;
if (alarm->enabled)
sec = rtc_tm_to_time64(&alarm->time);
@@ -196,16 +201,16 @@ static int tegra_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
sec = 0;
tegra_rtc_wait_while_busy(dev);
- writel(sec, info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0);
+ writel(sec, info->base + TEGRA_RTC_REG_SECONDS_ALARM0);
dev_vdbg(dev, "alarm read back as %d\n",
- readl(info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0));
+ readl(info->base + TEGRA_RTC_REG_SECONDS_ALARM0));
/* if successfully written and alarm is enabled ... */
if (sec) {
tegra_rtc_alarm_irq_enable(dev, 1);
- dev_vdbg(dev, "alarm set as %lu. %ptR\n", sec, &alarm->time);
+ dev_vdbg(dev, "alarm set as %u, %ptR\n", sec, &alarm->time);
} else {
- /* disable alarm if 0 or write error. */
+ /* disable alarm if 0 or write error */
dev_vdbg(dev, "alarm disabled\n");
tegra_rtc_alarm_irq_enable(dev, 0);
}
@@ -227,39 +232,39 @@ static irqreturn_t tegra_rtc_irq_handler(int irq, void *data)
{
struct device *dev = data;
struct tegra_rtc_info *info = dev_get_drvdata(dev);
- unsigned long events = 0;
- unsigned status;
- unsigned long sl_irq_flags;
+ unsigned long events = 0, flags;
+ u32 status;
- status = readl(info->rtc_base + TEGRA_RTC_REG_INTR_STATUS);
+ status = readl(info->base + TEGRA_RTC_REG_INTR_STATUS);
if (status) {
- /* clear the interrupt masks and status on any irq. */
+ /* clear the interrupt masks and status on any IRQ */
tegra_rtc_wait_while_busy(dev);
- spin_lock_irqsave(&info->tegra_rtc_lock, sl_irq_flags);
- writel(0, info->rtc_base + TEGRA_RTC_REG_INTR_MASK);
- writel(status, info->rtc_base + TEGRA_RTC_REG_INTR_STATUS);
- spin_unlock_irqrestore(&info->tegra_rtc_lock, sl_irq_flags);
+
+ spin_lock_irqsave(&info->lock, flags);
+ writel(0, info->base + TEGRA_RTC_REG_INTR_MASK);
+ writel(status, info->base + TEGRA_RTC_REG_INTR_STATUS);
+ spin_unlock_irqrestore(&info->lock, flags);
}
- /* check if Alarm */
- if ((status & TEGRA_RTC_INTR_STATUS_SEC_ALARM0))
+ /* check if alarm */
+ if (status & TEGRA_RTC_INTR_STATUS_SEC_ALARM0)
events |= RTC_IRQF | RTC_AF;
- /* check if Periodic */
- if ((status & TEGRA_RTC_INTR_STATUS_SEC_CDN_ALARM))
+ /* check if periodic */
+ if (status & TEGRA_RTC_INTR_STATUS_SEC_CDN_ALARM)
events |= RTC_IRQF | RTC_PF;
- rtc_update_irq(info->rtc_dev, 1, events);
+ rtc_update_irq(info->rtc, 1, events);
return IRQ_HANDLED;
}
static const struct rtc_class_ops tegra_rtc_ops = {
- .read_time = tegra_rtc_read_time,
- .set_time = tegra_rtc_set_time,
- .read_alarm = tegra_rtc_read_alarm,
- .set_alarm = tegra_rtc_set_alarm,
- .proc = tegra_rtc_proc,
+ .read_time = tegra_rtc_read_time,
+ .set_time = tegra_rtc_set_time,
+ .read_alarm = tegra_rtc_read_alarm,
+ .set_alarm = tegra_rtc_set_alarm,
+ .proc = tegra_rtc_proc,
.alarm_irq_enable = tegra_rtc_alarm_irq_enable,
};
@@ -269,21 +274,20 @@ static const struct of_device_id tegra_rtc_dt_match[] = {
};
MODULE_DEVICE_TABLE(of, tegra_rtc_dt_match);
-static int __init tegra_rtc_probe(struct platform_device *pdev)
+static int tegra_rtc_probe(struct platform_device *pdev)
{
struct tegra_rtc_info *info;
struct resource *res;
int ret;
- info = devm_kzalloc(&pdev->dev, sizeof(struct tegra_rtc_info),
- GFP_KERNEL);
+ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- info->rtc_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(info->rtc_base))
- return PTR_ERR(info->rtc_base);
+ info->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(info->base))
+ return PTR_ERR(info->base);
ret = platform_get_irq(pdev, 0);
if (ret <= 0) {
@@ -291,14 +295,14 @@ static int __init tegra_rtc_probe(struct platform_device *pdev)
return ret;
}
- info->tegra_rtc_irq = ret;
+ info->irq = ret;
- info->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
- if (IS_ERR(info->rtc_dev))
- return PTR_ERR(info->rtc_dev);
+ info->rtc = devm_rtc_allocate_device(&pdev->dev);
+ if (IS_ERR(info->rtc))
+ return PTR_ERR(info->rtc);
- info->rtc_dev->ops = &tegra_rtc_ops;
- info->rtc_dev->range_max = U32_MAX;
+ info->rtc->ops = &tegra_rtc_ops;
+ info->rtc->range_max = U32_MAX;
info->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(info->clk))
@@ -308,33 +312,30 @@ static int __init tegra_rtc_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
- /* set context info. */
+ /* set context info */
info->pdev = pdev;
- spin_lock_init(&info->tegra_rtc_lock);
+ spin_lock_init(&info->lock);
platform_set_drvdata(pdev, info);
- /* clear out the hardware. */
- writel(0, info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0);
- writel(0xffffffff, info->rtc_base + TEGRA_RTC_REG_INTR_STATUS);
- writel(0, info->rtc_base + TEGRA_RTC_REG_INTR_MASK);
+ /* clear out the hardware */
+ writel(0, info->base + TEGRA_RTC_REG_SECONDS_ALARM0);
+ writel(0xffffffff, info->base + TEGRA_RTC_REG_INTR_STATUS);
+ writel(0, info->base + TEGRA_RTC_REG_INTR_MASK);
device_init_wakeup(&pdev->dev, 1);
- ret = devm_request_irq(&pdev->dev, info->tegra_rtc_irq,
- tegra_rtc_irq_handler, IRQF_TRIGGER_HIGH,
- dev_name(&pdev->dev), &pdev->dev);
+ ret = devm_request_irq(&pdev->dev, info->irq, tegra_rtc_irq_handler,
+ IRQF_TRIGGER_HIGH, dev_name(&pdev->dev),
+ &pdev->dev);
if (ret) {
- dev_err(&pdev->dev,
- "Unable to request interrupt for device (err=%d).\n",
- ret);
+ dev_err(&pdev->dev, "failed to request interrupt: %d\n", ret);
goto disable_clk;
}
- ret = rtc_register_device(info->rtc_dev);
+ ret = rtc_register_device(info->rtc);
if (ret) {
- dev_err(&pdev->dev, "Unable to register device (err=%d).\n",
- ret);
+ dev_err(&pdev->dev, "failed to register device: %d\n", ret);
goto disable_clk;
}
@@ -363,20 +364,20 @@ static int tegra_rtc_suspend(struct device *dev)
tegra_rtc_wait_while_busy(dev);
- /* only use ALARM0 as a wake source. */
- writel(0xffffffff, info->rtc_base + TEGRA_RTC_REG_INTR_STATUS);
+ /* only use ALARM0 as a wake source */
+ writel(0xffffffff, info->base + TEGRA_RTC_REG_INTR_STATUS);
writel(TEGRA_RTC_INTR_STATUS_SEC_ALARM0,
- info->rtc_base + TEGRA_RTC_REG_INTR_MASK);
+ info->base + TEGRA_RTC_REG_INTR_MASK);
dev_vdbg(dev, "alarm sec = %d\n",
- readl(info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0));
+ readl(info->base + TEGRA_RTC_REG_SECONDS_ALARM0));
- dev_vdbg(dev, "Suspend (device_may_wakeup=%d) irq:%d\n",
- device_may_wakeup(dev), info->tegra_rtc_irq);
+ dev_vdbg(dev, "Suspend (device_may_wakeup=%d) IRQ:%d\n",
+ device_may_wakeup(dev), info->irq);
- /* leave the alarms on as a wake source. */
+ /* leave the alarms on as a wake source */
if (device_may_wakeup(dev))
- enable_irq_wake(info->tegra_rtc_irq);
+ enable_irq_wake(info->irq);
return 0;
}
@@ -386,10 +387,11 @@ static int tegra_rtc_resume(struct device *dev)
struct tegra_rtc_info *info = dev_get_drvdata(dev);
dev_vdbg(dev, "Resume (device_may_wakeup=%d)\n",
- device_may_wakeup(dev));
- /* alarms were left on as a wake source, turn them off. */
+ device_may_wakeup(dev));
+
+ /* alarms were left on as a wake source, turn them off */
if (device_may_wakeup(dev))
- disable_irq_wake(info->tegra_rtc_irq);
+ disable_irq_wake(info->irq);
return 0;
}
@@ -399,22 +401,21 @@ static SIMPLE_DEV_PM_OPS(tegra_rtc_pm_ops, tegra_rtc_suspend, tegra_rtc_resume);
static void tegra_rtc_shutdown(struct platform_device *pdev)
{
- dev_vdbg(&pdev->dev, "disabling interrupts.\n");
+ dev_vdbg(&pdev->dev, "disabling interrupts\n");
tegra_rtc_alarm_irq_enable(&pdev->dev, 0);
}
-MODULE_ALIAS("platform:tegra_rtc");
static struct platform_driver tegra_rtc_driver = {
- .remove = tegra_rtc_remove,
- .shutdown = tegra_rtc_shutdown,
- .driver = {
- .name = "tegra_rtc",
+ .probe = tegra_rtc_probe,
+ .remove = tegra_rtc_remove,
+ .shutdown = tegra_rtc_shutdown,
+ .driver = {
+ .name = "tegra_rtc",
.of_match_table = tegra_rtc_dt_match,
- .pm = &tegra_rtc_pm_ops,
+ .pm = &tegra_rtc_pm_ops,
},
};
-
-module_platform_driver_probe(tegra_rtc_driver, tegra_rtc_probe);
+module_platform_driver(tegra_rtc_driver);
MODULE_AUTHOR("Jon Mayo <jmayo@nvidia.com>");
MODULE_DESCRIPTION("driver for Tegra internal RTC");
diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c
index b298e9902f45..74b3a0603b73 100644
--- a/drivers/rtc/rtc-test.c
+++ b/drivers/rtc/rtc-test.c
@@ -133,6 +133,7 @@ static int test_probe(struct platform_device *plat_dev)
break;
default:
rtd->rtc->ops = &test_rtc_ops;
+ device_init_wakeup(&plat_dev->dev, 1);
}
timer_setup(&rtd->alarm, test_rtc_alarm_handler, 0);
diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c
index 8556d925e52a..7078f6da1cbc 100644
--- a/drivers/rtc/rtc-tps65910.c
+++ b/drivers/rtc/rtc-tps65910.c
@@ -143,7 +143,7 @@ static int tps65910_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
struct tps65910 *tps = dev_get_drvdata(dev->parent);
int ret;
- ret = regmap_bulk_read(tps->regmap, TPS65910_SECONDS, alarm_data,
+ ret = regmap_bulk_read(tps->regmap, TPS65910_ALARM_SECONDS, alarm_data,
NUM_TIME_REGS);
if (ret < 0) {
dev_err(dev, "rtc_read_alarm error %d\n", ret);
diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c
index 1f3117b5a83c..63ffba21397b 100644
--- a/drivers/rtc/rtc-v3020.c
+++ b/drivers/rtc/rtc-v3020.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* drivers/rtc/rtc-v3020.c
*
* Copyright (C) 2006 8D Technologies inc.
* Copyright (C) 2004 Compulab Ltd.
*
- * 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.
- *
* Driver for the V3020 RTC
*
* Changelog:
@@ -17,7 +14,6 @@
*
* ??-???-2004: Someone at Compulab
* - Initial driver creation.
- *
*/
#include <linux/platform_device.h>
#include <linux/module.h>
diff --git a/drivers/rtc/rtc-wm831x.c b/drivers/rtc/rtc-wm831x.c
index d2e8b21c90c4..ccef887d2690 100644
--- a/drivers/rtc/rtc-wm831x.c
+++ b/drivers/rtc/rtc-wm831x.c
@@ -435,7 +435,8 @@ static int wm831x_rtc_probe(struct platform_device *pdev)
ret = devm_request_threaded_irq(&pdev->dev, alm_irq, NULL,
wm831x_alm_irq,
- IRQF_TRIGGER_RISING, "RTC alarm",
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ "RTC alarm",
wm831x_rtc);
if (ret != 0) {
dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n",
diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c
index ad2ae2f0536e..d1d5a44d9122 100644
--- a/drivers/rtc/rtc-x1205.c
+++ b/drivers/rtc/rtc-x1205.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* An i2c driver for the Xicor/Intersil X1205 RTC
* Copyright 2004 Karen Spearel
@@ -11,10 +12,6 @@
*
* Information and datasheet:
* http://www.intersil.com/cda/deviceinfo/0,1477,X1205,00.html
- *
- * 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.
*/
#include <linux/i2c.h>
diff --git a/drivers/s390/block/Kconfig b/drivers/s390/block/Kconfig
index 9ac7574e3cfb..a8682f69effc 100644
--- a/drivers/s390/block/Kconfig
+++ b/drivers/s390/block/Kconfig
@@ -38,7 +38,7 @@ config DASD_PROFILE
depends on DASD
help
Enable this option if you want to see profiling information
- in /proc/dasd/statistics.
+ in /proc/dasd/statistics.
config DASD_ECKD
def_tristate y
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index e03304fe25bb..6cca72782af6 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -70,7 +70,6 @@ MODULE_LICENSE("GPL");
* SECTION: prototypes for static functions of dasd.c
*/
static int dasd_alloc_queue(struct dasd_block *);
-static void dasd_setup_queue(struct dasd_block *);
static void dasd_free_queue(struct dasd_block *);
static int dasd_flush_block_queue(struct dasd_block *);
static void dasd_device_tasklet(unsigned long);
@@ -120,9 +119,18 @@ struct dasd_device *dasd_alloc_device(void)
kfree(device);
return ERR_PTR(-ENOMEM);
}
+ /* Get two pages for ese format. */
+ device->ese_mem = (void *)__get_free_pages(GFP_ATOMIC | GFP_DMA, 1);
+ if (!device->ese_mem) {
+ free_page((unsigned long) device->erp_mem);
+ free_pages((unsigned long) device->ccw_mem, 1);
+ kfree(device);
+ return ERR_PTR(-ENOMEM);
+ }
dasd_init_chunklist(&device->ccw_chunks, device->ccw_mem, PAGE_SIZE*2);
dasd_init_chunklist(&device->erp_chunks, device->erp_mem, PAGE_SIZE);
+ dasd_init_chunklist(&device->ese_chunks, device->ese_mem, PAGE_SIZE * 2);
spin_lock_init(&device->mem_lock);
atomic_set(&device->tasklet_scheduled, 0);
tasklet_init(&device->tasklet, dasd_device_tasklet,
@@ -146,6 +154,7 @@ struct dasd_device *dasd_alloc_device(void)
void dasd_free_device(struct dasd_device *device)
{
kfree(device->private);
+ free_pages((unsigned long) device->ese_mem, 1);
free_page((unsigned long) device->erp_mem);
free_pages((unsigned long) device->ccw_mem, 1);
kfree(device);
@@ -348,7 +357,8 @@ static int dasd_state_basic_to_ready(struct dasd_device *device)
}
return rc;
}
- dasd_setup_queue(block);
+ if (device->discipline->setup_blk_queue)
+ device->discipline->setup_blk_queue(block);
set_capacity(block->gdp,
block->blocks << block->s2b_shift);
device->state = DASD_STATE_READY;
@@ -1258,6 +1268,49 @@ struct dasd_ccw_req *dasd_smalloc_request(int magic, int cplength, int datasize,
}
EXPORT_SYMBOL(dasd_smalloc_request);
+struct dasd_ccw_req *dasd_fmalloc_request(int magic, int cplength,
+ int datasize,
+ struct dasd_device *device)
+{
+ struct dasd_ccw_req *cqr;
+ unsigned long flags;
+ int size, cqr_size;
+ char *data;
+
+ cqr_size = (sizeof(*cqr) + 7L) & -8L;
+ size = cqr_size;
+ if (cplength > 0)
+ size += cplength * sizeof(struct ccw1);
+ if (datasize > 0)
+ size += datasize;
+
+ spin_lock_irqsave(&device->mem_lock, flags);
+ cqr = dasd_alloc_chunk(&device->ese_chunks, size);
+ spin_unlock_irqrestore(&device->mem_lock, flags);
+ if (!cqr)
+ return ERR_PTR(-ENOMEM);
+ memset(cqr, 0, sizeof(*cqr));
+ data = (char *)cqr + cqr_size;
+ cqr->cpaddr = NULL;
+ if (cplength > 0) {
+ cqr->cpaddr = data;
+ data += cplength * sizeof(struct ccw1);
+ memset(cqr->cpaddr, 0, cplength * sizeof(struct ccw1));
+ }
+ cqr->data = NULL;
+ if (datasize > 0) {
+ cqr->data = data;
+ memset(cqr->data, 0, datasize);
+ }
+
+ cqr->magic = magic;
+ set_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+ dasd_get_device(device);
+
+ return cqr;
+}
+EXPORT_SYMBOL(dasd_fmalloc_request);
+
void dasd_sfree_request(struct dasd_ccw_req *cqr, struct dasd_device *device)
{
unsigned long flags;
@@ -1269,6 +1322,17 @@ void dasd_sfree_request(struct dasd_ccw_req *cqr, struct dasd_device *device)
}
EXPORT_SYMBOL(dasd_sfree_request);
+void dasd_ffree_request(struct dasd_ccw_req *cqr, struct dasd_device *device)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&device->mem_lock, flags);
+ dasd_free_chunk(&device->ese_chunks, cqr);
+ spin_unlock_irqrestore(&device->mem_lock, flags);
+ dasd_put_device(device);
+}
+EXPORT_SYMBOL(dasd_ffree_request);
+
/*
* Check discipline magic in cqr.
*/
@@ -1573,13 +1637,43 @@ static int dasd_check_hpf_error(struct irb *irb)
irb->scsw.tm.sesq == SCSW_SESQ_PATH_NOFCX));
}
+static int dasd_ese_needs_format(struct dasd_block *block, struct irb *irb)
+{
+ struct dasd_device *device = NULL;
+ u8 *sense = NULL;
+
+ if (!block)
+ return 0;
+ device = block->base;
+ if (!device || !device->discipline->is_ese)
+ return 0;
+ if (!device->discipline->is_ese(device))
+ return 0;
+
+ sense = dasd_get_sense(irb);
+ if (!sense)
+ return 0;
+
+ return !!(sense[1] & SNS1_NO_REC_FOUND) ||
+ !!(sense[1] & SNS1_FILE_PROTECTED) ||
+ scsw_cstat(&irb->scsw) == SCHN_STAT_INCORR_LEN;
+}
+
+static int dasd_ese_oos_cond(u8 *sense)
+{
+ return sense[0] & SNS0_EQUIPMENT_CHECK &&
+ sense[1] & SNS1_PERM_ERR &&
+ sense[1] & SNS1_WRITE_INHIBITED &&
+ sense[25] == 0x01;
+}
+
/*
* Interrupt handler for "normal" ssch-io based dasd devices.
*/
void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
struct irb *irb)
{
- struct dasd_ccw_req *cqr, *next;
+ struct dasd_ccw_req *cqr, *next, *fcqr;
struct dasd_device *device;
unsigned long now;
int nrf_suppressed = 0;
@@ -1641,6 +1735,17 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
test_bit(DASD_CQR_SUPPRESS_FP, &cqr->flags);
nrf_suppressed = (sense[1] & SNS1_NO_REC_FOUND) &&
test_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags);
+
+ /*
+ * Extent pool probably out-of-space.
+ * Stop device and check exhaust level.
+ */
+ if (dasd_ese_oos_cond(sense)) {
+ dasd_generic_space_exhaust(device, cqr);
+ device->discipline->ext_pool_exhaust(device, cqr);
+ dasd_put_device(device);
+ return;
+ }
}
if (!(fp_suppressed || nrf_suppressed))
device->discipline->dump_sense_dbf(device, irb, "int");
@@ -1672,6 +1777,31 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
return;
}
+ if (dasd_ese_needs_format(cqr->block, irb)) {
+ if (rq_data_dir((struct request *)cqr->callback_data) == READ) {
+ device->discipline->ese_read(cqr);
+ cqr->status = DASD_CQR_SUCCESS;
+ cqr->stopclk = now;
+ dasd_device_clear_timer(device);
+ dasd_schedule_device_bh(device);
+ return;
+ }
+ fcqr = device->discipline->ese_format(device, cqr);
+ if (IS_ERR(fcqr)) {
+ /*
+ * If we can't format now, let the request go
+ * one extra round. Maybe we can format later.
+ */
+ cqr->status = DASD_CQR_QUEUED;
+ } else {
+ fcqr->status = DASD_CQR_QUEUED;
+ cqr->status = DASD_CQR_QUEUED;
+ list_add(&fcqr->devlist, &device->ccw_queue);
+ dasd_schedule_device_bh(device);
+ return;
+ }
+ }
+
/* Check for clear pending */
if (cqr->status == DASD_CQR_CLEAR_PENDING &&
scsw_fctl(&irb->scsw) & SCSW_FCTL_CLEAR_FUNC) {
@@ -1910,7 +2040,7 @@ static void __dasd_device_check_expire(struct dasd_device *device)
static int __dasd_device_is_unusable(struct dasd_device *device,
struct dasd_ccw_req *cqr)
{
- int mask = ~(DASD_STOPPED_DC_WAIT | DASD_UNRESUMED_PM);
+ int mask = ~(DASD_STOPPED_DC_WAIT | DASD_UNRESUMED_PM | DASD_STOPPED_NOSPC);
if (test_bit(DASD_FLAG_OFFLINE, &device->flags) &&
!test_bit(DASD_FLAG_SAFE_OFFLINE_RUNNING, &device->flags)) {
@@ -2412,6 +2542,15 @@ int dasd_sleep_on_queue(struct list_head *ccw_queue)
EXPORT_SYMBOL(dasd_sleep_on_queue);
/*
+ * Start requests from a ccw_queue and wait interruptible for their completion.
+ */
+int dasd_sleep_on_queue_interruptible(struct list_head *ccw_queue)
+{
+ return _dasd_sleep_on_queue(ccw_queue, 1);
+}
+EXPORT_SYMBOL(dasd_sleep_on_queue_interruptible);
+
+/*
* Queue a request to the tail of the device ccw_queue and wait
* interruptible for it's completion.
*/
@@ -3130,55 +3269,6 @@ static int dasd_alloc_queue(struct dasd_block *block)
}
/*
- * Allocate and initialize request queue.
- */
-static void dasd_setup_queue(struct dasd_block *block)
-{
- unsigned int logical_block_size = block->bp_block;
- struct request_queue *q = block->request_queue;
- unsigned int max_bytes, max_discard_sectors;
- int max;
-
- if (block->base->features & DASD_FEATURE_USERAW) {
- /*
- * the max_blocks value for raw_track access is 256
- * it is higher than the native ECKD value because we
- * only need one ccw per track
- * so the max_hw_sectors are
- * 2048 x 512B = 1024kB = 16 tracks
- */
- max = 2048;
- } else {
- max = block->base->discipline->max_blocks << block->s2b_shift;
- }
- blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
- q->limits.max_dev_sectors = max;
- blk_queue_logical_block_size(q, logical_block_size);
- blk_queue_max_hw_sectors(q, max);
- blk_queue_max_segments(q, USHRT_MAX);
- /* with page sized segments we can translate each segement into
- * one idaw/tidaw
- */
- blk_queue_max_segment_size(q, PAGE_SIZE);
- blk_queue_segment_boundary(q, PAGE_SIZE - 1);
-
- /* Only activate blocklayer discard support for devices that support it */
- if (block->base->features & DASD_FEATURE_DISCARD) {
- q->limits.discard_granularity = logical_block_size;
- q->limits.discard_alignment = PAGE_SIZE;
-
- /* Calculate max_discard_sectors and make it PAGE aligned */
- max_bytes = USHRT_MAX * logical_block_size;
- max_bytes = ALIGN(max_bytes, PAGE_SIZE) - PAGE_SIZE;
- max_discard_sectors = max_bytes / logical_block_size;
-
- blk_queue_max_discard_sectors(q, max_discard_sectors);
- blk_queue_max_write_zeroes_sectors(q, max_discard_sectors);
- blk_queue_flag_set(QUEUE_FLAG_DISCARD, q);
- }
-}
-
-/*
* Deactivate and free request queue.
*/
static void dasd_free_queue(struct dasd_block *block)
@@ -3806,6 +3896,43 @@ int dasd_generic_verify_path(struct dasd_device *device, __u8 lpm)
}
EXPORT_SYMBOL_GPL(dasd_generic_verify_path);
+void dasd_generic_space_exhaust(struct dasd_device *device,
+ struct dasd_ccw_req *cqr)
+{
+ dasd_eer_write(device, NULL, DASD_EER_NOSPC);
+
+ if (device->state < DASD_STATE_BASIC)
+ return;
+
+ if (cqr->status == DASD_CQR_IN_IO ||
+ cqr->status == DASD_CQR_CLEAR_PENDING) {
+ cqr->status = DASD_CQR_QUEUED;
+ cqr->retries++;
+ }
+ dasd_device_set_stop_bits(device, DASD_STOPPED_NOSPC);
+ dasd_device_clear_timer(device);
+ dasd_schedule_device_bh(device);
+}
+EXPORT_SYMBOL_GPL(dasd_generic_space_exhaust);
+
+void dasd_generic_space_avail(struct dasd_device *device)
+{
+ dev_info(&device->cdev->dev, "Extent pool space is available\n");
+ DBF_DEV_EVENT(DBF_WARNING, device, "%s", "space available");
+
+ dasd_device_remove_stop_bits(device, DASD_STOPPED_NOSPC);
+ dasd_schedule_device_bh(device);
+
+ if (device->block) {
+ dasd_schedule_block_bh(device->block);
+ if (device->block->request_queue)
+ blk_mq_run_hw_queues(device->block->request_queue, true);
+ }
+ if (!device->stopped)
+ wake_up(&generic_waitq);
+}
+EXPORT_SYMBOL_GPL(dasd_generic_space_avail);
+
/*
* clear active requests and requeue them to block layer if possible
*/
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index fab35c6170cc..32fc51341d99 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -203,7 +203,7 @@ static int __init dasd_feature_list(char *str)
else if (len == 8 && !strncmp(str, "failfast", 8))
features |= DASD_FEATURE_FAILFAST;
else {
- pr_warn("%*s is not a supported device option\n",
+ pr_warn("%.*s is not a supported device option\n",
len, str);
rc = -EINVAL;
}
@@ -1642,6 +1642,35 @@ static DEVICE_ATTR(path_interval, 0644, dasd_path_interval_show,
dasd_path_interval_store);
+#define DASD_DEFINE_ATTR(_name, _func) \
+static ssize_t dasd_##_name##_show(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct ccw_device *cdev = to_ccwdev(dev); \
+ struct dasd_device *device = dasd_device_from_cdev(cdev); \
+ int val = 0; \
+ \
+ if (IS_ERR(device)) \
+ return -ENODEV; \
+ if (device->discipline && _func) \
+ val = _func(device); \
+ dasd_put_device(device); \
+ \
+ return snprintf(buf, PAGE_SIZE, "%d\n", val); \
+} \
+static DEVICE_ATTR(_name, 0444, dasd_##_name##_show, NULL); \
+
+DASD_DEFINE_ATTR(ese, device->discipline->is_ese);
+DASD_DEFINE_ATTR(extent_size, device->discipline->ext_size);
+DASD_DEFINE_ATTR(pool_id, device->discipline->ext_pool_id);
+DASD_DEFINE_ATTR(space_configured, device->discipline->space_configured);
+DASD_DEFINE_ATTR(space_allocated, device->discipline->space_allocated);
+DASD_DEFINE_ATTR(logical_capacity, device->discipline->logical_capacity);
+DASD_DEFINE_ATTR(warn_threshold, device->discipline->ext_pool_warn_thrshld);
+DASD_DEFINE_ATTR(cap_at_warnlevel, device->discipline->ext_pool_cap_at_warnlevel);
+DASD_DEFINE_ATTR(pool_oos, device->discipline->ext_pool_oos);
+
static struct attribute * dasd_attrs[] = {
&dev_attr_readonly.attr,
&dev_attr_discipline.attr,
@@ -1667,6 +1696,7 @@ static struct attribute * dasd_attrs[] = {
&dev_attr_path_interval.attr,
&dev_attr_path_reset.attr,
&dev_attr_hpf.attr,
+ &dev_attr_ese.attr,
NULL,
};
@@ -1674,6 +1704,39 @@ static const struct attribute_group dasd_attr_group = {
.attrs = dasd_attrs,
};
+static struct attribute *capacity_attrs[] = {
+ &dev_attr_space_configured.attr,
+ &dev_attr_space_allocated.attr,
+ &dev_attr_logical_capacity.attr,
+ NULL,
+};
+
+static const struct attribute_group capacity_attr_group = {
+ .name = "capacity",
+ .attrs = capacity_attrs,
+};
+
+static struct attribute *ext_pool_attrs[] = {
+ &dev_attr_pool_id.attr,
+ &dev_attr_extent_size.attr,
+ &dev_attr_warn_threshold.attr,
+ &dev_attr_cap_at_warnlevel.attr,
+ &dev_attr_pool_oos.attr,
+ NULL,
+};
+
+static const struct attribute_group ext_pool_attr_group = {
+ .name = "extent_pool",
+ .attrs = ext_pool_attrs,
+};
+
+static const struct attribute_group *dasd_attr_groups[] = {
+ &dasd_attr_group,
+ &capacity_attr_group,
+ &ext_pool_attr_group,
+ NULL,
+};
+
/*
* Return value of the specified feature.
*/
@@ -1715,16 +1778,15 @@ dasd_set_feature(struct ccw_device *cdev, int feature, int flag)
EXPORT_SYMBOL(dasd_set_feature);
-int
-dasd_add_sysfs_files(struct ccw_device *cdev)
+int dasd_add_sysfs_files(struct ccw_device *cdev)
{
- return sysfs_create_group(&cdev->dev.kobj, &dasd_attr_group);
+ return sysfs_create_groups(&cdev->dev.kobj, dasd_attr_groups);
}
void
dasd_remove_sysfs_files(struct ccw_device *cdev)
{
- sysfs_remove_group(&cdev->dev.kobj, &dasd_attr_group);
+ sysfs_remove_groups(&cdev->dev.kobj, dasd_attr_groups);
}
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index e1fe02477ea8..8d4971645cf1 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -615,14 +615,34 @@ dasd_diag_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
"dump sense not available for DIAG data");
}
+/*
+ * Initialize block layer request queue.
+ */
+static void dasd_diag_setup_blk_queue(struct dasd_block *block)
+{
+ unsigned int logical_block_size = block->bp_block;
+ struct request_queue *q = block->request_queue;
+ int max;
+
+ max = DIAG_MAX_BLOCKS << block->s2b_shift;
+ blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
+ q->limits.max_dev_sectors = max;
+ blk_queue_logical_block_size(q, logical_block_size);
+ blk_queue_max_hw_sectors(q, max);
+ blk_queue_max_segments(q, USHRT_MAX);
+ /* With page sized segments each segment can be translated into one idaw/tidaw */
+ blk_queue_max_segment_size(q, PAGE_SIZE);
+ blk_queue_segment_boundary(q, PAGE_SIZE - 1);
+}
+
static struct dasd_discipline dasd_diag_discipline = {
.owner = THIS_MODULE,
.name = "DIAG",
.ebcname = "DIAG",
- .max_blocks = DIAG_MAX_BLOCKS,
.check_device = dasd_diag_check_device,
.verify_path = dasd_generic_verify_path,
.fill_geometry = dasd_diag_fill_geometry,
+ .setup_blk_queue = dasd_diag_setup_blk_queue,
.start_IO = dasd_start_diag,
.term_IO = dasd_diag_term_IO,
.handle_terminated_request = dasd_diag_handle_terminated_request,
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index c09039eea707..fc53e1e221f0 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -42,20 +42,6 @@
#endif /* PRINTK_HEADER */
#define PRINTK_HEADER "dasd(eckd):"
-#define ECKD_C0(i) (i->home_bytes)
-#define ECKD_F(i) (i->formula)
-#define ECKD_F1(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f1):\
- (i->factors.f_0x02.f1))
-#define ECKD_F2(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f2):\
- (i->factors.f_0x02.f2))
-#define ECKD_F3(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f3):\
- (i->factors.f_0x02.f3))
-#define ECKD_F4(i) (ECKD_F(i)==0x02?(i->factors.f_0x02.f4):0)
-#define ECKD_F5(i) (ECKD_F(i)==0x02?(i->factors.f_0x02.f5):0)
-#define ECKD_F6(i) (i->factor6)
-#define ECKD_F7(i) (i->factor7)
-#define ECKD_F8(i) (i->factor8)
-
/*
* raw track access always map to 64k in memory
* so it maps to 16 blocks of 4k per track
@@ -103,6 +89,19 @@ static struct {
} *dasd_reserve_req;
static DEFINE_MUTEX(dasd_reserve_mutex);
+static struct {
+ struct dasd_ccw_req cqr;
+ struct ccw1 ccw[2];
+ char data[40];
+} *dasd_vol_info_req;
+static DEFINE_MUTEX(dasd_vol_info_mutex);
+
+struct ext_pool_exhaust_work_data {
+ struct work_struct worker;
+ struct dasd_device *device;
+ struct dasd_device *base;
+};
+
/* definitions for the path verification worker */
struct path_verification_work_data {
struct work_struct worker;
@@ -122,6 +121,7 @@ struct check_attention_work_data {
__u8 lpum;
};
+static int dasd_eckd_ext_pool_id(struct dasd_device *);
static int prepare_itcw(struct itcw *, unsigned int, unsigned int, int,
struct dasd_device *, struct dasd_device *,
unsigned int, int, unsigned int, unsigned int,
@@ -157,17 +157,10 @@ static const int sizes_trk0[] = { 28, 148, 84 };
#define LABEL_SIZE 140
/* head and record addresses of count_area read in analysis ccw */
-static const int count_area_head[] = { 0, 0, 0, 0, 2 };
+static const int count_area_head[] = { 0, 0, 0, 0, 1 };
static const int count_area_rec[] = { 1, 2, 3, 4, 1 };
static inline unsigned int
-round_up_multiple(unsigned int no, unsigned int mult)
-{
- int rem = no % mult;
- return (rem ? no - rem + mult : no);
-}
-
-static inline unsigned int
ceil_quot(unsigned int d1, unsigned int d2)
{
return (d1 + (d2 - 1)) / d2;
@@ -1491,6 +1484,311 @@ static int dasd_eckd_read_features(struct dasd_device *device)
return rc;
}
+/* Read Volume Information - Volume Storage Query */
+static int dasd_eckd_read_vol_info(struct dasd_device *device)
+{
+ struct dasd_eckd_private *private = device->private;
+ struct dasd_psf_prssd_data *prssdp;
+ struct dasd_rssd_vsq *vsq;
+ struct dasd_ccw_req *cqr;
+ struct ccw1 *ccw;
+ int useglobal;
+ int rc;
+
+ /* This command cannot be executed on an alias device */
+ if (private->uid.type == UA_BASE_PAV_ALIAS ||
+ private->uid.type == UA_HYPER_PAV_ALIAS)
+ return 0;
+
+ useglobal = 0;
+ cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 2 /* PSF + RSSD */,
+ sizeof(*prssdp) + sizeof(*vsq), device, NULL);
+ if (IS_ERR(cqr)) {
+ DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s",
+ "Could not allocate initialization request");
+ mutex_lock(&dasd_vol_info_mutex);
+ useglobal = 1;
+ cqr = &dasd_vol_info_req->cqr;
+ memset(cqr, 0, sizeof(*cqr));
+ memset(dasd_vol_info_req, 0, sizeof(*dasd_vol_info_req));
+ cqr->cpaddr = &dasd_vol_info_req->ccw;
+ cqr->data = &dasd_vol_info_req->data;
+ cqr->magic = DASD_ECKD_MAGIC;
+ }
+
+ /* Prepare for Read Subsystem Data */
+ prssdp = cqr->data;
+ prssdp->order = PSF_ORDER_PRSSD;
+ prssdp->suborder = PSF_SUBORDER_VSQ; /* Volume Storage Query */
+ prssdp->lss = private->ned->ID;
+ prssdp->volume = private->ned->unit_addr;
+
+ ccw = cqr->cpaddr;
+ ccw->cmd_code = DASD_ECKD_CCW_PSF;
+ ccw->count = sizeof(*prssdp);
+ ccw->flags |= CCW_FLAG_CC;
+ ccw->cda = (__u32)(addr_t)prssdp;
+
+ /* Read Subsystem Data - Volume Storage Query */
+ vsq = (struct dasd_rssd_vsq *)(prssdp + 1);
+ memset(vsq, 0, sizeof(*vsq));
+
+ ccw++;
+ ccw->cmd_code = DASD_ECKD_CCW_RSSD;
+ ccw->count = sizeof(*vsq);
+ ccw->flags |= CCW_FLAG_SLI;
+ ccw->cda = (__u32)(addr_t)vsq;
+
+ cqr->buildclk = get_tod_clock();
+ cqr->status = DASD_CQR_FILLED;
+ cqr->startdev = device;
+ cqr->memdev = device;
+ cqr->block = NULL;
+ cqr->retries = 256;
+ cqr->expires = device->default_expires * HZ;
+ /* The command might not be supported. Suppress the error output */
+ __set_bit(DASD_CQR_SUPPRESS_CR, &cqr->flags);
+
+ rc = dasd_sleep_on_interruptible(cqr);
+ if (rc == 0) {
+ memcpy(&private->vsq, vsq, sizeof(*vsq));
+ } else {
+ dev_warn(&device->cdev->dev,
+ "Reading the volume storage information failed with rc=%d\n", rc);
+ }
+
+ if (useglobal)
+ mutex_unlock(&dasd_vol_info_mutex);
+ else
+ dasd_sfree_request(cqr, cqr->memdev);
+
+ return rc;
+}
+
+static int dasd_eckd_is_ese(struct dasd_device *device)
+{
+ struct dasd_eckd_private *private = device->private;
+
+ return private->vsq.vol_info.ese;
+}
+
+static int dasd_eckd_ext_pool_id(struct dasd_device *device)
+{
+ struct dasd_eckd_private *private = device->private;
+
+ return private->vsq.extent_pool_id;
+}
+
+/*
+ * This value represents the total amount of available space. As more space is
+ * allocated by ESE volumes, this value will decrease.
+ * The data for this value is therefore updated on any call.
+ */
+static int dasd_eckd_space_configured(struct dasd_device *device)
+{
+ struct dasd_eckd_private *private = device->private;
+ int rc;
+
+ rc = dasd_eckd_read_vol_info(device);
+
+ return rc ? : private->vsq.space_configured;
+}
+
+/*
+ * The value of space allocated by an ESE volume may have changed and is
+ * therefore updated on any call.
+ */
+static int dasd_eckd_space_allocated(struct dasd_device *device)
+{
+ struct dasd_eckd_private *private = device->private;
+ int rc;
+
+ rc = dasd_eckd_read_vol_info(device);
+
+ return rc ? : private->vsq.space_allocated;
+}
+
+static int dasd_eckd_logical_capacity(struct dasd_device *device)
+{
+ struct dasd_eckd_private *private = device->private;
+
+ return private->vsq.logical_capacity;
+}
+
+static void dasd_eckd_ext_pool_exhaust_work(struct work_struct *work)
+{
+ struct ext_pool_exhaust_work_data *data;
+ struct dasd_device *device;
+ struct dasd_device *base;
+
+ data = container_of(work, struct ext_pool_exhaust_work_data, worker);
+ device = data->device;
+ base = data->base;
+
+ if (!base)
+ base = device;
+ if (dasd_eckd_space_configured(base) != 0) {
+ dasd_generic_space_avail(device);
+ } else {
+ dev_warn(&device->cdev->dev, "No space left in the extent pool\n");
+ DBF_DEV_EVENT(DBF_WARNING, device, "%s", "out of space");
+ }
+
+ dasd_put_device(device);
+ kfree(data);
+}
+
+static int dasd_eckd_ext_pool_exhaust(struct dasd_device *device,
+ struct dasd_ccw_req *cqr)
+{
+ struct ext_pool_exhaust_work_data *data;
+
+ data = kzalloc(sizeof(*data), GFP_ATOMIC);
+ if (!data)
+ return -ENOMEM;
+ INIT_WORK(&data->worker, dasd_eckd_ext_pool_exhaust_work);
+ dasd_get_device(device);
+ data->device = device;
+
+ if (cqr->block)
+ data->base = cqr->block->base;
+ else if (cqr->basedev)
+ data->base = cqr->basedev;
+ else
+ data->base = NULL;
+
+ schedule_work(&data->worker);
+
+ return 0;
+}
+
+static void dasd_eckd_cpy_ext_pool_data(struct dasd_device *device,
+ struct dasd_rssd_lcq *lcq)
+{
+ struct dasd_eckd_private *private = device->private;
+ int pool_id = dasd_eckd_ext_pool_id(device);
+ struct dasd_ext_pool_sum eps;
+ int i;
+
+ for (i = 0; i < lcq->pool_count; i++) {
+ eps = lcq->ext_pool_sum[i];
+ if (eps.pool_id == pool_id) {
+ memcpy(&private->eps, &eps,
+ sizeof(struct dasd_ext_pool_sum));
+ }
+ }
+}
+
+/* Read Extent Pool Information - Logical Configuration Query */
+static int dasd_eckd_read_ext_pool_info(struct dasd_device *device)
+{
+ struct dasd_eckd_private *private = device->private;
+ struct dasd_psf_prssd_data *prssdp;
+ struct dasd_rssd_lcq *lcq;
+ struct dasd_ccw_req *cqr;
+ struct ccw1 *ccw;
+ int rc;
+
+ /* This command cannot be executed on an alias device */
+ if (private->uid.type == UA_BASE_PAV_ALIAS ||
+ private->uid.type == UA_HYPER_PAV_ALIAS)
+ return 0;
+
+ cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 2 /* PSF + RSSD */,
+ sizeof(*prssdp) + sizeof(*lcq), device, NULL);
+ if (IS_ERR(cqr)) {
+ DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s",
+ "Could not allocate initialization request");
+ return PTR_ERR(cqr);
+ }
+
+ /* Prepare for Read Subsystem Data */
+ prssdp = cqr->data;
+ memset(prssdp, 0, sizeof(*prssdp));
+ prssdp->order = PSF_ORDER_PRSSD;
+ prssdp->suborder = PSF_SUBORDER_LCQ; /* Logical Configuration Query */
+
+ ccw = cqr->cpaddr;
+ ccw->cmd_code = DASD_ECKD_CCW_PSF;
+ ccw->count = sizeof(*prssdp);
+ ccw->flags |= CCW_FLAG_CC;
+ ccw->cda = (__u32)(addr_t)prssdp;
+
+ lcq = (struct dasd_rssd_lcq *)(prssdp + 1);
+ memset(lcq, 0, sizeof(*lcq));
+
+ ccw++;
+ ccw->cmd_code = DASD_ECKD_CCW_RSSD;
+ ccw->count = sizeof(*lcq);
+ ccw->flags |= CCW_FLAG_SLI;
+ ccw->cda = (__u32)(addr_t)lcq;
+
+ cqr->buildclk = get_tod_clock();
+ cqr->status = DASD_CQR_FILLED;
+ cqr->startdev = device;
+ cqr->memdev = device;
+ cqr->block = NULL;
+ cqr->retries = 256;
+ cqr->expires = device->default_expires * HZ;
+ /* The command might not be supported. Suppress the error output */
+ __set_bit(DASD_CQR_SUPPRESS_CR, &cqr->flags);
+
+ rc = dasd_sleep_on_interruptible(cqr);
+ if (rc == 0) {
+ dasd_eckd_cpy_ext_pool_data(device, lcq);
+ } else {
+ dev_warn(&device->cdev->dev,
+ "Reading the logical configuration failed with rc=%d\n", rc);
+ }
+
+ dasd_sfree_request(cqr, cqr->memdev);
+
+ return rc;
+}
+
+/*
+ * Depending on the device type, the extent size is specified either as
+ * cylinders per extent (CKD) or size per extent (FBA)
+ * A 1GB size corresponds to 1113cyl, and 16MB to 21cyl.
+ */
+static int dasd_eckd_ext_size(struct dasd_device *device)
+{
+ struct dasd_eckd_private *private = device->private;
+ struct dasd_ext_pool_sum eps = private->eps;
+
+ if (!eps.flags.extent_size_valid)
+ return 0;
+ if (eps.extent_size.size_1G)
+ return 1113;
+ if (eps.extent_size.size_16M)
+ return 21;
+
+ return 0;
+}
+
+static int dasd_eckd_ext_pool_warn_thrshld(struct dasd_device *device)
+{
+ struct dasd_eckd_private *private = device->private;
+
+ return private->eps.warn_thrshld;
+}
+
+static int dasd_eckd_ext_pool_cap_at_warnlevel(struct dasd_device *device)
+{
+ struct dasd_eckd_private *private = device->private;
+
+ return private->eps.flags.capacity_at_warnlevel;
+}
+
+/*
+ * Extent Pool out of space
+ */
+static int dasd_eckd_ext_pool_oos(struct dasd_device *device)
+{
+ struct dasd_eckd_private *private = device->private;
+
+ return private->eps.flags.pool_oos;
+}
/*
* Build CP for Perform Subsystem Function - SSC.
@@ -1721,6 +2019,16 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
/* Read Feature Codes */
dasd_eckd_read_features(device);
+ /* Read Volume Information */
+ rc = dasd_eckd_read_vol_info(device);
+ if (rc)
+ goto out_err3;
+
+ /* Read Extent Pool Information */
+ rc = dasd_eckd_read_ext_pool_info(device);
+ if (rc)
+ goto out_err3;
+
/* Read Device Characteristics */
rc = dasd_generic_read_dev_chars(device, DASD_ECKD_MAGIC,
&private->rdc_data, 64);
@@ -1751,6 +2059,9 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
if (readonly)
set_bit(DASD_FLAG_DEVICE_RO, &device->flags);
+ if (dasd_eckd_is_ese(device))
+ dasd_set_feature(device->cdev, DASD_FEATURE_DISCARD, 1);
+
dev_info(&device->cdev->dev, "New DASD %04X/%02X (CU %04X/%02X) "
"with %d cylinders, %d heads, %d sectors%s\n",
private->rdc_data.dev_type,
@@ -1823,8 +2134,8 @@ dasd_eckd_analysis_ccw(struct dasd_device *device)
if (IS_ERR(cqr))
return cqr;
ccw = cqr->cpaddr;
- /* Define extent for the first 3 tracks. */
- define_extent(ccw++, cqr->data, 0, 2,
+ /* Define extent for the first 2 tracks. */
+ define_extent(ccw++, cqr->data, 0, 1,
DASD_ECKD_CCW_READ_COUNT, device, 0);
LO_data = cqr->data + sizeof(struct DE_eckd_data);
/* Locate record for the first 4 records on track 0. */
@@ -1843,9 +2154,9 @@ dasd_eckd_analysis_ccw(struct dasd_device *device)
count_data++;
}
- /* Locate record for the first record on track 2. */
+ /* Locate record for the first record on track 1. */
ccw[-1].flags |= CCW_FLAG_CC;
- locate_record(ccw++, LO_data++, 2, 0, 1,
+ locate_record(ccw++, LO_data++, 1, 0, 1,
DASD_ECKD_CCW_READ_COUNT, device, 0);
/* Read count ccw. */
ccw[-1].flags |= CCW_FLAG_CC;
@@ -1860,6 +2171,9 @@ dasd_eckd_analysis_ccw(struct dasd_device *device)
cqr->retries = 255;
cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED;
+ /* Set flags to suppress output for expected errors */
+ set_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags);
+
return cqr;
}
@@ -1967,7 +2281,7 @@ static int dasd_eckd_end_analysis(struct dasd_block *block)
}
}
if (i == 3)
- count_area = &private->count_area[4];
+ count_area = &private->count_area[3];
if (private->uses_cdl == 0) {
for (i = 0; i < 5; i++) {
@@ -2099,8 +2413,7 @@ dasd_eckd_build_check_tcw(struct dasd_device *base, struct format_data_t *fdata,
*/
itcw_size = itcw_calc_size(0, count, 0);
- cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 0, itcw_size, startdev,
- NULL);
+ cqr = dasd_fmalloc_request(DASD_ECKD_MAGIC, 0, itcw_size, startdev);
if (IS_ERR(cqr))
return cqr;
@@ -2193,8 +2506,7 @@ dasd_eckd_build_check(struct dasd_device *base, struct format_data_t *fdata,
}
cplength += count;
- cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize,
- startdev, NULL);
+ cqr = dasd_fmalloc_request(DASD_ECKD_MAGIC, cplength, datasize, startdev);
if (IS_ERR(cqr))
return cqr;
@@ -2241,13 +2553,11 @@ dasd_eckd_build_check(struct dasd_device *base, struct format_data_t *fdata,
}
static struct dasd_ccw_req *
-dasd_eckd_build_format(struct dasd_device *base,
- struct format_data_t *fdata,
- int enable_pav)
+dasd_eckd_build_format(struct dasd_device *base, struct dasd_device *startdev,
+ struct format_data_t *fdata, int enable_pav)
{
struct dasd_eckd_private *base_priv;
struct dasd_eckd_private *start_priv;
- struct dasd_device *startdev = NULL;
struct dasd_ccw_req *fcp;
struct eckd_count *ect;
struct ch_t address;
@@ -2338,9 +2648,8 @@ dasd_eckd_build_format(struct dasd_device *base,
fdata->intensity);
return ERR_PTR(-EINVAL);
}
- /* Allocate the format ccw request. */
- fcp = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength,
- datasize, startdev, NULL);
+
+ fcp = dasd_fmalloc_request(DASD_ECKD_MAGIC, cplength, datasize, startdev);
if (IS_ERR(fcp))
return fcp;
@@ -2513,7 +2822,7 @@ dasd_eckd_format_build_ccw_req(struct dasd_device *base,
struct dasd_ccw_req *ccw_req;
if (!fmt_buffer) {
- ccw_req = dasd_eckd_build_format(base, fdata, enable_pav);
+ ccw_req = dasd_eckd_build_format(base, NULL, fdata, enable_pav);
} else {
if (tpm)
ccw_req = dasd_eckd_build_check_tcw(base, fdata,
@@ -2659,7 +2968,7 @@ out_err:
rc = -EIO;
}
list_del_init(&cqr->blocklist);
- dasd_sfree_request(cqr, device);
+ dasd_ffree_request(cqr, device);
private->count--;
}
@@ -2699,6 +3008,96 @@ static int dasd_eckd_format_device(struct dasd_device *base,
}
/*
+ * Callback function to free ESE format requests.
+ */
+static void dasd_eckd_ese_format_cb(struct dasd_ccw_req *cqr, void *data)
+{
+ struct dasd_device *device = cqr->startdev;
+ struct dasd_eckd_private *private = device->private;
+
+ private->count--;
+ dasd_ffree_request(cqr, device);
+}
+
+static struct dasd_ccw_req *
+dasd_eckd_ese_format(struct dasd_device *startdev, struct dasd_ccw_req *cqr)
+{
+ struct dasd_eckd_private *private;
+ struct format_data_t fdata;
+ unsigned int recs_per_trk;
+ struct dasd_ccw_req *fcqr;
+ struct dasd_device *base;
+ struct dasd_block *block;
+ unsigned int blksize;
+ struct request *req;
+ sector_t first_trk;
+ sector_t last_trk;
+ int rc;
+
+ req = cqr->callback_data;
+ base = cqr->block->base;
+ private = base->private;
+ block = base->block;
+ blksize = block->bp_block;
+ recs_per_trk = recs_per_track(&private->rdc_data, 0, blksize);
+
+ first_trk = blk_rq_pos(req) >> block->s2b_shift;
+ sector_div(first_trk, recs_per_trk);
+ last_trk =
+ (blk_rq_pos(req) + blk_rq_sectors(req) - 1) >> block->s2b_shift;
+ sector_div(last_trk, recs_per_trk);
+
+ fdata.start_unit = first_trk;
+ fdata.stop_unit = last_trk;
+ fdata.blksize = blksize;
+ fdata.intensity = private->uses_cdl ? DASD_FMT_INT_COMPAT : 0;
+
+ rc = dasd_eckd_format_sanity_checks(base, &fdata);
+ if (rc)
+ return ERR_PTR(-EINVAL);
+
+ /*
+ * We're building the request with PAV disabled as we're reusing
+ * the former startdev.
+ */
+ fcqr = dasd_eckd_build_format(base, startdev, &fdata, 0);
+ if (IS_ERR(fcqr))
+ return fcqr;
+
+ fcqr->callback = dasd_eckd_ese_format_cb;
+
+ return fcqr;
+}
+
+/*
+ * When data is read from an unformatted area of an ESE volume, this function
+ * returns zeroed data and thereby mimics a read of zero data.
+ */
+static void dasd_eckd_ese_read(struct dasd_ccw_req *cqr)
+{
+ unsigned int blksize, off;
+ struct dasd_device *base;
+ struct req_iterator iter;
+ struct request *req;
+ struct bio_vec bv;
+ char *dst;
+
+ req = (struct request *) cqr->callback_data;
+ base = cqr->block->base;
+ blksize = base->block->bp_block;
+
+ rq_for_each_segment(bv, req, iter) {
+ dst = page_address(bv.bv_page) + bv.bv_offset;
+ for (off = 0; off < bv.bv_len; off += blksize) {
+ if (dst && rq_data_dir(req) == READ) {
+ dst += off;
+ memset(dst, 0, blksize);
+ }
+ }
+ }
+}
+
+/*
* Helper function to count consecutive records of a single track.
*/
static int dasd_eckd_count_records(struct eckd_count *fmt_buffer, int start,
@@ -3033,6 +3432,277 @@ static void dasd_eckd_check_for_device_change(struct dasd_device *device,
}
}
+static int dasd_eckd_ras_sanity_checks(struct dasd_device *device,
+ unsigned int first_trk,
+ unsigned int last_trk)
+{
+ struct dasd_eckd_private *private = device->private;
+ unsigned int trks_per_vol;
+ int rc = 0;
+
+ trks_per_vol = private->real_cyl * private->rdc_data.trk_per_cyl;
+
+ if (first_trk >= trks_per_vol) {
+ dev_warn(&device->cdev->dev,
+ "Start track number %u used in the space release command is too big\n",
+ first_trk);
+ rc = -EINVAL;
+ } else if (last_trk >= trks_per_vol) {
+ dev_warn(&device->cdev->dev,
+ "Stop track number %u used in the space release command is too big\n",
+ last_trk);
+ rc = -EINVAL;
+ } else if (first_trk > last_trk) {
+ dev_warn(&device->cdev->dev,
+ "Start track %u used in the space release command exceeds the end track\n",
+ first_trk);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+/*
+ * Helper function to count the amount of involved extents within a given range
+ * with extent alignment in mind.
+ */
+static int count_exts(unsigned int from, unsigned int to, int trks_per_ext)
+{
+ int cur_pos = 0;
+ int count = 0;
+ int tmp;
+
+ if (from == to)
+ return 1;
+
+ /* Count first partial extent */
+ if (from % trks_per_ext != 0) {
+ tmp = from + trks_per_ext - (from % trks_per_ext) - 1;
+ if (tmp > to)
+ tmp = to;
+ cur_pos = tmp - from + 1;
+ count++;
+ }
+ /* Count full extents */
+ if (to - (from + cur_pos) + 1 >= trks_per_ext) {
+ tmp = to - ((to - trks_per_ext + 1) % trks_per_ext);
+ count += (tmp - (from + cur_pos) + 1) / trks_per_ext;
+ cur_pos = tmp;
+ }
+ /* Count last partial extent */
+ if (cur_pos < to)
+ count++;
+
+ return count;
+}
+
+/*
+ * Release allocated space for a given range or an entire volume.
+ */
+static struct dasd_ccw_req *
+dasd_eckd_dso_ras(struct dasd_device *device, struct dasd_block *block,
+ struct request *req, unsigned int first_trk,
+ unsigned int last_trk, int by_extent)
+{
+ struct dasd_eckd_private *private = device->private;
+ struct dasd_dso_ras_ext_range *ras_range;
+ struct dasd_rssd_features *features;
+ struct dasd_dso_ras_data *ras_data;
+ u16 heads, beg_head, end_head;
+ int cur_to_trk, cur_from_trk;
+ struct dasd_ccw_req *cqr;
+ u32 beg_cyl, end_cyl;
+ struct ccw1 *ccw;
+ int trks_per_ext;
+ size_t ras_size;
+ size_t size;
+ int nr_exts;
+ void *rq;
+ int i;
+
+ if (dasd_eckd_ras_sanity_checks(device, first_trk, last_trk))
+ return ERR_PTR(-EINVAL);
+
+ rq = req ? blk_mq_rq_to_pdu(req) : NULL;
+
+ features = &private->features;
+
+ trks_per_ext = dasd_eckd_ext_size(device) * private->rdc_data.trk_per_cyl;
+ nr_exts = 0;
+ if (by_extent)
+ nr_exts = count_exts(first_trk, last_trk, trks_per_ext);
+ ras_size = sizeof(*ras_data);
+ size = ras_size + (nr_exts * sizeof(*ras_range));
+
+ cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, size, device, rq);
+ if (IS_ERR(cqr)) {
+ DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s",
+ "Could not allocate RAS request");
+ return cqr;
+ }
+
+ ras_data = cqr->data;
+ memset(ras_data, 0, size);
+
+ ras_data->order = DSO_ORDER_RAS;
+ ras_data->flags.vol_type = 0; /* CKD volume */
+ /* Release specified extents or entire volume */
+ ras_data->op_flags.by_extent = by_extent;
+ /*
+ * This bit guarantees initialisation of tracks within an extent that is
+ * not fully specified, but is only supported with a certain feature
+ * subset.
+ */
+ ras_data->op_flags.guarantee_init = !!(features->feature[56] & 0x01);
+ ras_data->lss = private->ned->ID;
+ ras_data->dev_addr = private->ned->unit_addr;
+ ras_data->nr_exts = nr_exts;
+
+ if (by_extent) {
+ heads = private->rdc_data.trk_per_cyl;
+ cur_from_trk = first_trk;
+ cur_to_trk = first_trk + trks_per_ext -
+ (first_trk % trks_per_ext) - 1;
+ if (cur_to_trk > last_trk)
+ cur_to_trk = last_trk;
+ ras_range = (struct dasd_dso_ras_ext_range *)(cqr->data + ras_size);
+
+ for (i = 0; i < nr_exts; i++) {
+ beg_cyl = cur_from_trk / heads;
+ beg_head = cur_from_trk % heads;
+ end_cyl = cur_to_trk / heads;
+ end_head = cur_to_trk % heads;
+
+ set_ch_t(&ras_range->beg_ext, beg_cyl, beg_head);
+ set_ch_t(&ras_range->end_ext, end_cyl, end_head);
+
+ cur_from_trk = cur_to_trk + 1;
+ cur_to_trk = cur_from_trk + trks_per_ext - 1;
+ if (cur_to_trk > last_trk)
+ cur_to_trk = last_trk;
+ ras_range++;
+ }
+ }
+
+ ccw = cqr->cpaddr;
+ ccw->cda = (__u32)(addr_t)cqr->data;
+ ccw->cmd_code = DASD_ECKD_CCW_DSO;
+ ccw->count = size;
+
+ cqr->startdev = device;
+ cqr->memdev = device;
+ cqr->block = block;
+ cqr->retries = 256;
+ cqr->expires = device->default_expires * HZ;
+ cqr->buildclk = get_tod_clock();
+ cqr->status = DASD_CQR_FILLED;
+
+ return cqr;
+}
+
+static int dasd_eckd_release_space_full(struct dasd_device *device)
+{
+ struct dasd_ccw_req *cqr;
+ int rc;
+
+ cqr = dasd_eckd_dso_ras(device, NULL, NULL, 0, 0, 0);
+ if (IS_ERR(cqr))
+ return PTR_ERR(cqr);
+
+ rc = dasd_sleep_on_interruptible(cqr);
+
+ dasd_sfree_request(cqr, cqr->memdev);
+
+ return rc;
+}
+
+static int dasd_eckd_release_space_trks(struct dasd_device *device,
+ unsigned int from, unsigned int to)
+{
+ struct dasd_eckd_private *private = device->private;
+ struct dasd_block *block = device->block;
+ struct dasd_ccw_req *cqr, *n;
+ struct list_head ras_queue;
+ unsigned int device_exts;
+ int trks_per_ext;
+ int stop, step;
+ int cur_pos;
+ int rc = 0;
+ int retry;
+
+ INIT_LIST_HEAD(&ras_queue);
+
+ device_exts = private->real_cyl / dasd_eckd_ext_size(device);
+ trks_per_ext = dasd_eckd_ext_size(device) * private->rdc_data.trk_per_cyl;
+
+ /* Make sure device limits are not exceeded */
+ step = trks_per_ext * min(device_exts, DASD_ECKD_RAS_EXTS_MAX);
+ cur_pos = from;
+
+ do {
+ retry = 0;
+ while (cur_pos < to) {
+ stop = cur_pos + step -
+ ((cur_pos + step) % trks_per_ext) - 1;
+ if (stop > to)
+ stop = to;
+
+ cqr = dasd_eckd_dso_ras(device, NULL, NULL, cur_pos, stop, 1);
+ if (IS_ERR(cqr)) {
+ rc = PTR_ERR(cqr);
+ if (rc == -ENOMEM) {
+ if (list_empty(&ras_queue))
+ goto out;
+ retry = 1;
+ break;
+ }
+ goto err_out;
+ }
+
+ spin_lock_irq(&block->queue_lock);
+ list_add_tail(&cqr->blocklist, &ras_queue);
+ spin_unlock_irq(&block->queue_lock);
+ cur_pos = stop + 1;
+ }
+
+ rc = dasd_sleep_on_queue_interruptible(&ras_queue);
+
+err_out:
+ list_for_each_entry_safe(cqr, n, &ras_queue, blocklist) {
+ device = cqr->startdev;
+ private = device->private;
+
+ spin_lock_irq(&block->queue_lock);
+ list_del_init(&cqr->blocklist);
+ spin_unlock_irq(&block->queue_lock);
+ dasd_sfree_request(cqr, device);
+ private->count--;
+ }
+ } while (retry);
+
+out:
+ return rc;
+}
+
+static int dasd_eckd_release_space(struct dasd_device *device,
+ struct format_data_t *rdata)
+{
+ if (rdata->intensity & DASD_FMT_INT_ESE_FULL)
+ return dasd_eckd_release_space_full(device);
+ else if (rdata->intensity == 0)
+ return dasd_eckd_release_space_trks(device, rdata->start_unit,
+ rdata->stop_unit);
+ else
+ return -EINVAL;
+}
+
+static struct dasd_ccw_req *
+dasd_eckd_build_cp_discard(struct dasd_device *device, struct dasd_block *block,
+ struct request *req, sector_t first_trk,
+ sector_t last_trk)
+{
+ return dasd_eckd_dso_ras(device, block, req, first_trk, last_trk, 1);
+}
+
static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
struct dasd_device *startdev,
struct dasd_block *block,
@@ -3214,6 +3884,14 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
cqr->retries = startdev->default_retries;
cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED;
+
+ /* Set flags to suppress output for expected errors */
+ if (dasd_eckd_is_ese(basedev)) {
+ set_bit(DASD_CQR_SUPPRESS_FP, &cqr->flags);
+ set_bit(DASD_CQR_SUPPRESS_IL, &cqr->flags);
+ set_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags);
+ }
+
return cqr;
}
@@ -3385,6 +4063,11 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track(
cqr->retries = startdev->default_retries;
cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED;
+
+ /* Set flags to suppress output for expected errors */
+ if (dasd_eckd_is_ese(basedev))
+ set_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags);
+
return cqr;
}
@@ -3704,6 +4387,14 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
cqr->retries = startdev->default_retries;
cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED;
+
+ /* Set flags to suppress output for expected errors */
+ if (dasd_eckd_is_ese(basedev)) {
+ set_bit(DASD_CQR_SUPPRESS_FP, &cqr->flags);
+ set_bit(DASD_CQR_SUPPRESS_IL, &cqr->flags);
+ set_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags);
+ }
+
return cqr;
out_error:
dasd_sfree_request(cqr, startdev);
@@ -3756,6 +4447,10 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,
cmdwtd = private->features.feature[12] & 0x40;
use_prefix = private->features.feature[8] & 0x01;
+ if (req_op(req) == REQ_OP_DISCARD)
+ return dasd_eckd_build_cp_discard(startdev, block, req,
+ first_trk, last_trk);
+
cqr = NULL;
if (cdlspecial || dasd_page_cache) {
/* do nothing, just fall through to the cmd mode single case */
@@ -4034,12 +4729,14 @@ static struct dasd_ccw_req *dasd_eckd_build_alias_cp(struct dasd_device *base,
struct dasd_block *block,
struct request *req)
{
+ struct dasd_device *startdev = NULL;
struct dasd_eckd_private *private;
- struct dasd_device *startdev;
- unsigned long flags;
struct dasd_ccw_req *cqr;
+ unsigned long flags;
- startdev = dasd_alias_get_start_dev(base);
+ /* Discard requests can only be processed on base devices */
+ if (req_op(req) != REQ_OP_DISCARD)
+ startdev = dasd_alias_get_start_dev(base);
if (!startdev)
startdev = base;
private = startdev->private;
@@ -4965,6 +5662,16 @@ static int dasd_eckd_restore_device(struct dasd_device *device)
/* Read Feature Codes */
dasd_eckd_read_features(device);
+ /* Read Volume Information */
+ rc = dasd_eckd_read_vol_info(device);
+ if (rc)
+ goto out_err2;
+
+ /* Read Extent Pool Information */
+ rc = dasd_eckd_read_ext_pool_info(device);
+ if (rc)
+ goto out_err2;
+
/* Read Device Characteristics */
rc = dasd_generic_read_dev_chars(device, DASD_ECKD_MAGIC,
&temp_rdc_data, 64);
@@ -5635,6 +6342,73 @@ static void dasd_eckd_handle_cuir(struct dasd_device *device, void *messages,
device->discipline->check_attention(device, lpum);
}
+static void dasd_eckd_oos_resume(struct dasd_device *device)
+{
+ struct dasd_eckd_private *private = device->private;
+ struct alias_pav_group *pavgroup, *tempgroup;
+ struct dasd_device *dev, *n;
+ unsigned long flags;
+
+ spin_lock_irqsave(&private->lcu->lock, flags);
+ list_for_each_entry_safe(dev, n, &private->lcu->active_devices,
+ alias_list) {
+ if (dev->stopped & DASD_STOPPED_NOSPC)
+ dasd_generic_space_avail(dev);
+ }
+ list_for_each_entry_safe(dev, n, &private->lcu->inactive_devices,
+ alias_list) {
+ if (dev->stopped & DASD_STOPPED_NOSPC)
+ dasd_generic_space_avail(dev);
+ }
+ /* devices in PAV groups */
+ list_for_each_entry_safe(pavgroup, tempgroup,
+ &private->lcu->grouplist,
+ group) {
+ list_for_each_entry_safe(dev, n, &pavgroup->baselist,
+ alias_list) {
+ if (dev->stopped & DASD_STOPPED_NOSPC)
+ dasd_generic_space_avail(dev);
+ }
+ list_for_each_entry_safe(dev, n, &pavgroup->aliaslist,
+ alias_list) {
+ if (dev->stopped & DASD_STOPPED_NOSPC)
+ dasd_generic_space_avail(dev);
+ }
+ }
+ spin_unlock_irqrestore(&private->lcu->lock, flags);
+}
+
+static void dasd_eckd_handle_oos(struct dasd_device *device, void *messages,
+ __u8 lpum)
+{
+ struct dasd_oos_message *oos = messages;
+
+ switch (oos->code) {
+ case REPO_WARN:
+ case POOL_WARN:
+ dev_warn(&device->cdev->dev,
+ "Extent pool usage has reached a critical value\n");
+ dasd_eckd_oos_resume(device);
+ break;
+ case REPO_EXHAUST:
+ case POOL_EXHAUST:
+ dev_warn(&device->cdev->dev,
+ "Extent pool is exhausted\n");
+ break;
+ case REPO_RELIEVE:
+ case POOL_RELIEVE:
+ dev_info(&device->cdev->dev,
+ "Extent pool physical space constraint has been relieved\n");
+ break;
+ }
+
+ /* In any case, update related data */
+ dasd_eckd_read_ext_pool_info(device);
+
+ /* to make sure there is no attention left schedule work again */
+ device->discipline->check_attention(device, lpum);
+}
+
static void dasd_eckd_check_attention_work(struct work_struct *work)
{
struct check_attention_work_data *data;
@@ -5653,9 +6427,14 @@ static void dasd_eckd_check_attention_work(struct work_struct *work)
rc = dasd_eckd_read_message_buffer(device, messages, data->lpum);
if (rc)
goto out;
+
if (messages->length == ATTENTION_LENGTH_CUIR &&
messages->format == ATTENTION_FORMAT_CUIR)
dasd_eckd_handle_cuir(device, messages, data->lpum);
+ if (messages->length == ATTENTION_LENGTH_OOS &&
+ messages->format == ATTENTION_FORMAT_OOS)
+ dasd_eckd_handle_oos(device, messages, data->lpum);
+
out:
dasd_put_device(device);
kfree(messages);
@@ -5734,6 +6513,72 @@ static void dasd_eckd_handle_hpf_error(struct dasd_device *device,
dasd_schedule_requeue(device);
}
+/*
+ * Initialize block layer request queue.
+ */
+static void dasd_eckd_setup_blk_queue(struct dasd_block *block)
+{
+ unsigned int logical_block_size = block->bp_block;
+ struct request_queue *q = block->request_queue;
+ struct dasd_device *device = block->base;
+ struct dasd_eckd_private *private;
+ unsigned int max_discard_sectors;
+ unsigned int max_bytes;
+ unsigned int ext_bytes; /* Extent Size in Bytes */
+ int recs_per_trk;
+ int trks_per_cyl;
+ int ext_limit;
+ int ext_size; /* Extent Size in Cylinders */
+ int max;
+
+ private = device->private;
+ trks_per_cyl = private->rdc_data.trk_per_cyl;
+ recs_per_trk = recs_per_track(&private->rdc_data, 0, logical_block_size);
+
+ if (device->features & DASD_FEATURE_USERAW) {
+ /*
+ * the max_blocks value for raw_track access is 256
+ * it is higher than the native ECKD value because we
+ * only need one ccw per track
+ * so the max_hw_sectors are
+ * 2048 x 512B = 1024kB = 16 tracks
+ */
+ max = DASD_ECKD_MAX_BLOCKS_RAW << block->s2b_shift;
+ } else {
+ max = DASD_ECKD_MAX_BLOCKS << block->s2b_shift;
+ }
+ blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
+ q->limits.max_dev_sectors = max;
+ blk_queue_logical_block_size(q, logical_block_size);
+ blk_queue_max_hw_sectors(q, max);
+ blk_queue_max_segments(q, USHRT_MAX);
+ /* With page sized segments each segment can be translated into one idaw/tidaw */
+ blk_queue_max_segment_size(q, PAGE_SIZE);
+ blk_queue_segment_boundary(q, PAGE_SIZE - 1);
+
+ if (dasd_eckd_is_ese(device)) {
+ /*
+ * Depending on the extent size, up to UINT_MAX bytes can be
+ * accepted. However, neither DASD_ECKD_RAS_EXTS_MAX nor the
+ * device limits should be exceeded.
+ */
+ ext_size = dasd_eckd_ext_size(device);
+ ext_limit = min(private->real_cyl / ext_size, DASD_ECKD_RAS_EXTS_MAX);
+ ext_bytes = ext_size * trks_per_cyl * recs_per_trk *
+ logical_block_size;
+ max_bytes = UINT_MAX - (UINT_MAX % ext_bytes);
+ if (max_bytes / ext_bytes > ext_limit)
+ max_bytes = ext_bytes * ext_limit;
+
+ max_discard_sectors = max_bytes / 512;
+
+ blk_queue_max_discard_sectors(q, max_discard_sectors);
+ blk_queue_flag_set(QUEUE_FLAG_DISCARD, q);
+ q->limits.discard_granularity = ext_bytes;
+ q->limits.discard_alignment = ext_bytes;
+ }
+}
+
static struct ccw_driver dasd_eckd_driver = {
.driver = {
.name = "dasd-eckd",
@@ -5754,24 +6599,10 @@ static struct ccw_driver dasd_eckd_driver = {
.int_class = IRQIO_DAS,
};
-/*
- * max_blocks is dependent on the amount of storage that is available
- * in the static io buffer for each device. Currently each device has
- * 8192 bytes (=2 pages). For 64 bit one dasd_mchunkt_t structure has
- * 24 bytes, the struct dasd_ccw_req has 136 bytes and each block can use
- * up to 16 bytes (8 for the ccw and 8 for the idal pointer). In
- * addition we have one define extent ccw + 16 bytes of data and one
- * locate record ccw + 16 bytes of data. That makes:
- * (8192 - 24 - 136 - 8 - 16 - 8 - 16) / 16 = 499 blocks at maximum.
- * We want to fit two into the available memory so that we can immediately
- * start the next request if one finishes off. That makes 249.5 blocks
- * for one request. Give a little safety and the result is 240.
- */
static struct dasd_discipline dasd_eckd_discipline = {
.owner = THIS_MODULE,
.name = "ECKD",
.ebcname = "ECKD",
- .max_blocks = 190,
.check_device = dasd_eckd_check_characteristics,
.uncheck_device = dasd_eckd_uncheck_device,
.do_analysis = dasd_eckd_do_analysis,
@@ -5779,6 +6610,7 @@ static struct dasd_discipline dasd_eckd_discipline = {
.basic_to_ready = dasd_eckd_basic_to_ready,
.online_to_ready = dasd_eckd_online_to_ready,
.basic_to_known = dasd_eckd_basic_to_known,
+ .setup_blk_queue = dasd_eckd_setup_blk_queue,
.fill_geometry = dasd_eckd_fill_geometry,
.start_IO = dasd_start_IO,
.term_IO = dasd_term_IO,
@@ -5806,6 +6638,19 @@ static struct dasd_discipline dasd_eckd_discipline = {
.disable_hpf = dasd_eckd_disable_hpf_device,
.hpf_enabled = dasd_eckd_hpf_enabled,
.reset_path = dasd_eckd_reset_path,
+ .is_ese = dasd_eckd_is_ese,
+ .space_allocated = dasd_eckd_space_allocated,
+ .space_configured = dasd_eckd_space_configured,
+ .logical_capacity = dasd_eckd_logical_capacity,
+ .release_space = dasd_eckd_release_space,
+ .ext_pool_id = dasd_eckd_ext_pool_id,
+ .ext_size = dasd_eckd_ext_size,
+ .ext_pool_cap_at_warnlevel = dasd_eckd_ext_pool_cap_at_warnlevel,
+ .ext_pool_warn_thrshld = dasd_eckd_ext_pool_warn_thrshld,
+ .ext_pool_oos = dasd_eckd_ext_pool_oos,
+ .ext_pool_exhaust = dasd_eckd_ext_pool_exhaust,
+ .ese_format = dasd_eckd_ese_format,
+ .ese_read = dasd_eckd_ese_read,
};
static int __init
@@ -5818,16 +6663,22 @@ dasd_eckd_init(void)
GFP_KERNEL | GFP_DMA);
if (!dasd_reserve_req)
return -ENOMEM;
+ dasd_vol_info_req = kmalloc(sizeof(*dasd_vol_info_req),
+ GFP_KERNEL | GFP_DMA);
+ if (!dasd_vol_info_req)
+ return -ENOMEM;
path_verification_worker = kmalloc(sizeof(*path_verification_worker),
GFP_KERNEL | GFP_DMA);
if (!path_verification_worker) {
kfree(dasd_reserve_req);
+ kfree(dasd_vol_info_req);
return -ENOMEM;
}
rawpadpage = (void *)__get_free_page(GFP_KERNEL);
if (!rawpadpage) {
kfree(path_verification_worker);
kfree(dasd_reserve_req);
+ kfree(dasd_vol_info_req);
return -ENOMEM;
}
ret = ccw_driver_register(&dasd_eckd_driver);
@@ -5836,6 +6687,7 @@ dasd_eckd_init(void)
else {
kfree(path_verification_worker);
kfree(dasd_reserve_req);
+ kfree(dasd_vol_info_req);
free_page((unsigned long)rawpadpage);
}
return ret;
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h
index 5869d2fede35..6943508d0f1d 100644
--- a/drivers/s390/block/dasd_eckd.h
+++ b/drivers/s390/block/dasd_eckd.h
@@ -50,16 +50,26 @@
#define DASD_ECKD_CCW_PFX_READ 0xEA
#define DASD_ECKD_CCW_RSCK 0xF9
#define DASD_ECKD_CCW_RCD 0xFA
+#define DASD_ECKD_CCW_DSO 0xF7
+
+/* Define Subssystem Function / Orders */
+#define DSO_ORDER_RAS 0x81
/*
- * Perform Subsystem Function / Sub-Orders
+ * Perform Subsystem Function / Orders
*/
#define PSF_ORDER_PRSSD 0x18
#define PSF_ORDER_CUIR_RESPONSE 0x1A
-#define PSF_SUBORDER_QHA 0x1C
#define PSF_ORDER_SSC 0x1D
/*
+ * Perform Subsystem Function / Sub-Orders
+ */
+#define PSF_SUBORDER_QHA 0x1C /* Query Host Access */
+#define PSF_SUBORDER_VSQ 0x52 /* Volume Storage Query */
+#define PSF_SUBORDER_LCQ 0x53 /* Logical Configuration Query */
+
+/*
* CUIR response condition codes
*/
#define PSF_CUIR_INVALID 0x00
@@ -80,10 +90,22 @@
#define CUIR_RESUME 0x02
/*
+ * Out-of-space (OOS) Codes
+ */
+#define REPO_WARN 0x01
+#define REPO_EXHAUST 0x02
+#define POOL_WARN 0x03
+#define POOL_EXHAUST 0x04
+#define REPO_RELIEVE 0x05
+#define POOL_RELIEVE 0x06
+
+/*
* attention message definitions
*/
#define ATTENTION_LENGTH_CUIR 0x0e
#define ATTENTION_FORMAT_CUIR 0x01
+#define ATTENTION_LENGTH_OOS 0x10
+#define ATTENTION_FORMAT_OOS 0x06
#define DASD_ECKD_PG_GROUPED 0x10
@@ -99,6 +121,12 @@
#define DASD_ECKD_PATH_THRHLD 256
#define DASD_ECKD_PATH_INTERVAL 300
+/*
+ * Maximum number of blocks to be chained
+ */
+#define DASD_ECKD_MAX_BLOCKS 190
+#define DASD_ECKD_MAX_BLOCKS_RAW 256
+
/*****************************************************************************
* SECTION: Type Definitions
****************************************************************************/
@@ -116,35 +144,12 @@ struct ch_t {
__u16 head;
} __attribute__ ((packed));
-struct chs_t {
- __u16 cyl;
- __u16 head;
- __u32 sector;
-} __attribute__ ((packed));
-
struct chr_t {
__u16 cyl;
__u16 head;
__u8 record;
} __attribute__ ((packed));
-struct geom_t {
- __u16 cyl;
- __u16 head;
- __u32 sector;
-} __attribute__ ((packed));
-
-struct eckd_home {
- __u8 skip_control[14];
- __u16 cell_number;
- __u8 physical_addr[3];
- __u8 flag;
- struct ch_t track_addr;
- __u8 reserved;
- __u8 key_length;
- __u8 reserved2[2];
-} __attribute__ ((packed));
-
struct DE_eckd_data {
struct {
unsigned char perm:2; /* Permissions on this extent */
@@ -387,6 +392,86 @@ struct dasd_rssd_messages {
char messages[4087];
} __packed;
+/*
+ * Read Subsystem Data - Volume Storage Query
+ */
+struct dasd_rssd_vsq {
+ struct {
+ __u8 tse:1;
+ __u8 space_not_available:1;
+ __u8 ese:1;
+ __u8 unused:5;
+ } __packed vol_info;
+ __u8 unused1;
+ __u16 extent_pool_id;
+ __u8 warn_cap_limit;
+ __u8 warn_cap_guaranteed;
+ __u16 unused2;
+ __u32 limit_capacity;
+ __u32 guaranteed_capacity;
+ __u32 space_allocated;
+ __u32 space_configured;
+ __u32 logical_capacity;
+} __packed;
+
+/*
+ * Extent Pool Summary
+ */
+struct dasd_ext_pool_sum {
+ __u16 pool_id;
+ __u8 repo_warn_thrshld;
+ __u8 warn_thrshld;
+ struct {
+ __u8 type:1; /* 0 - CKD / 1 - FB */
+ __u8 track_space_efficient:1;
+ __u8 extent_space_efficient:1;
+ __u8 standard_volume:1;
+ __u8 extent_size_valid:1;
+ __u8 capacity_at_warnlevel:1;
+ __u8 pool_oos:1;
+ __u8 unused0:1;
+ __u8 unused1;
+ } __packed flags;
+ struct {
+ __u8 reserved0:1;
+ __u8 size_1G:1;
+ __u8 reserved1:5;
+ __u8 size_16M:1;
+ } __packed extent_size;
+ __u8 unused;
+} __packed;
+
+/*
+ * Read Subsystem Data-Response - Logical Configuration Query - Header
+ */
+struct dasd_rssd_lcq {
+ __u16 data_length; /* Length of data returned */
+ __u16 pool_count; /* Count of extent pools returned - Max: 448 */
+ struct {
+ __u8 pool_info_valid:1; /* Detailed Information valid */
+ __u8 pool_id_volume:1;
+ __u8 pool_id_cec:1;
+ __u8 unused0:5;
+ __u8 unused1;
+ } __packed header_flags;
+ char sfi_type[6]; /* Storage Facility Image Type (EBCDIC) */
+ char sfi_model[3]; /* Storage Facility Image Model (EBCDIC) */
+ __u8 sfi_seq_num[10]; /* Storage Facility Image Sequence Number */
+ __u8 reserved[7];
+ struct dasd_ext_pool_sum ext_pool_sum[448];
+} __packed;
+
+struct dasd_oos_message {
+ __u16 length;
+ __u8 format;
+ __u8 code;
+ __u8 percentage_empty;
+ __u8 reserved;
+ __u16 ext_pool_id;
+ __u16 token;
+ __u8 unused[6];
+} __packed;
+
struct dasd_cuir_message {
__u16 length;
__u8 format;
@@ -461,6 +546,42 @@ struct dasd_psf_ssc_data {
unsigned char reserved[59];
} __attribute__((packed));
+/* Maximum number of extents for a single Release Allocated Space command */
+#define DASD_ECKD_RAS_EXTS_MAX 110U
+
+struct dasd_dso_ras_ext_range {
+ struct ch_t beg_ext;
+ struct ch_t end_ext;
+} __packed;
+
+/*
+ * Define Subsytem Operation - Release Allocated Space
+ */
+struct dasd_dso_ras_data {
+ __u8 order;
+ struct {
+ __u8 message:1; /* Must be zero */
+ __u8 reserved1:2;
+ __u8 vol_type:1; /* 0 - CKD/FBA, 1 - FB */
+ __u8 reserved2:4;
+ } __packed flags;
+ /* Operation Flags to specify scope */
+ struct {
+ __u8 reserved1:2;
+ /* Release Space by Extent */
+ __u8 by_extent:1; /* 0 - entire volume, 1 - specified extents */
+ __u8 guarantee_init:1;
+ __u8 force_release:1; /* Internal - will be ignored */
+ __u16 reserved2:11;
+ } __packed op_flags;
+ __u8 lss;
+ __u8 dev_addr;
+ __u32 reserved1;
+ __u8 reserved2[10];
+ __u16 nr_exts; /* Defines number of ext_scope - max 110 */
+ __u16 reserved3;
+} __packed;
+
/*
* some structures and definitions for alias handling
@@ -551,6 +672,8 @@ struct dasd_eckd_private {
int uses_cdl;
struct attrib_data_t attrib; /* e.g. cache operations */
struct dasd_rssd_features features;
+ struct dasd_rssd_vsq vsq;
+ struct dasd_ext_pool_sum eps;
u32 real_cyl;
/* alias managemnet */
@@ -572,7 +695,5 @@ int dasd_alias_remove_device(struct dasd_device *);
struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *);
void dasd_alias_handle_summary_unit_check(struct work_struct *);
void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *);
-void dasd_alias_lcu_setup_complete(struct dasd_device *);
-void dasd_alias_wait_for_lcu_setup(struct dasd_device *);
int dasd_alias_update_add_device(struct dasd_device *);
#endif /* DASD_ECKD_H */
diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c
index 93bb09da7fdc..5ae64af9ccea 100644
--- a/drivers/s390/block/dasd_eer.c
+++ b/drivers/s390/block/dasd_eer.c
@@ -386,6 +386,7 @@ void dasd_eer_write(struct dasd_device *device, struct dasd_ccw_req *cqr,
dasd_eer_write_standard_trigger(device, cqr, id);
break;
case DASD_EER_NOPATH:
+ case DASD_EER_NOSPC:
dasd_eer_write_standard_trigger(device, NULL, id);
break;
case DASD_EER_STATECHANGE:
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index 56007a3e7f11..cbb770824226 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -770,27 +770,46 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
}
/*
- * max_blocks is dependent on the amount of storage that is available
- * in the static io buffer for each device. Currently each device has
- * 8192 bytes (=2 pages). For 64 bit one dasd_mchunkt_t structure has
- * 24 bytes, the struct dasd_ccw_req has 136 bytes and each block can use
- * up to 16 bytes (8 for the ccw and 8 for the idal pointer). In
- * addition we have one define extent ccw + 16 bytes of data and a
- * locate record ccw for each block (stupid devices!) + 16 bytes of data.
- * That makes:
- * (8192 - 24 - 136 - 8 - 16) / 40 = 200.2 blocks at maximum.
- * We want to fit two into the available memory so that we can immediately
- * start the next request if one finishes off. That makes 100.1 blocks
- * for one request. Give a little safety and the result is 96.
+ * Initialize block layer request queue.
*/
+static void dasd_fba_setup_blk_queue(struct dasd_block *block)
+{
+ unsigned int logical_block_size = block->bp_block;
+ struct request_queue *q = block->request_queue;
+ unsigned int max_bytes, max_discard_sectors;
+ int max;
+
+ max = DASD_FBA_MAX_BLOCKS << block->s2b_shift;
+ blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
+ q->limits.max_dev_sectors = max;
+ blk_queue_logical_block_size(q, logical_block_size);
+ blk_queue_max_hw_sectors(q, max);
+ blk_queue_max_segments(q, USHRT_MAX);
+ /* With page sized segments each segment can be translated into one idaw/tidaw */
+ blk_queue_max_segment_size(q, PAGE_SIZE);
+ blk_queue_segment_boundary(q, PAGE_SIZE - 1);
+
+ q->limits.discard_granularity = logical_block_size;
+ q->limits.discard_alignment = PAGE_SIZE;
+
+ /* Calculate max_discard_sectors and make it PAGE aligned */
+ max_bytes = USHRT_MAX * logical_block_size;
+ max_bytes = ALIGN_DOWN(max_bytes, PAGE_SIZE);
+ max_discard_sectors = max_bytes / logical_block_size;
+
+ blk_queue_max_discard_sectors(q, max_discard_sectors);
+ blk_queue_max_write_zeroes_sectors(q, max_discard_sectors);
+ blk_queue_flag_set(QUEUE_FLAG_DISCARD, q);
+}
+
static struct dasd_discipline dasd_fba_discipline = {
.owner = THIS_MODULE,
.name = "FBA ",
.ebcname = "FBA ",
- .max_blocks = 96,
.check_device = dasd_fba_check_characteristics,
.do_analysis = dasd_fba_do_analysis,
.verify_path = dasd_generic_verify_path,
+ .setup_blk_queue = dasd_fba_setup_blk_queue,
.fill_geometry = dasd_fba_fill_geometry,
.start_IO = dasd_start_IO,
.term_IO = dasd_term_IO,
diff --git a/drivers/s390/block/dasd_fba.h b/drivers/s390/block/dasd_fba.h
index b14bf1b2c691..8f75df06e893 100644
--- a/drivers/s390/block/dasd_fba.h
+++ b/drivers/s390/block/dasd_fba.h
@@ -9,6 +9,11 @@
#ifndef DASD_FBA_H
#define DASD_FBA_H
+/*
+ * Maximum number of blocks to be chained
+ */
+#define DASD_FBA_MAX_BLOCKS 96
+
struct DE_fba_data {
struct {
unsigned char perm:2; /* Permissions on this extent */
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index de6b96036aa4..91c9f9586e0f 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -268,7 +268,6 @@ struct dasd_discipline {
struct module *owner;
char ebcname[8]; /* a name used for tagging and printks */
char name[8]; /* a name used for tagging and printks */
- int max_blocks; /* maximum number of blocks to be chained */
struct list_head list; /* used for list of disciplines */
@@ -307,6 +306,10 @@ struct dasd_discipline {
int (*online_to_ready) (struct dasd_device *);
int (*basic_to_known)(struct dasd_device *);
+ /*
+ * Initialize block layer request queue.
+ */
+ void (*setup_blk_queue)(struct dasd_block *);
/* (struct dasd_device *);
* Device operation functions. build_cp creates a ccw chain for
* a block device request, start_io starts the request and
@@ -367,6 +370,25 @@ struct dasd_discipline {
void (*disable_hpf)(struct dasd_device *);
int (*hpf_enabled)(struct dasd_device *);
void (*reset_path)(struct dasd_device *, __u8);
+
+ /*
+ * Extent Space Efficient (ESE) relevant functions
+ */
+ int (*is_ese)(struct dasd_device *);
+ /* Capacity */
+ int (*space_allocated)(struct dasd_device *);
+ int (*space_configured)(struct dasd_device *);
+ int (*logical_capacity)(struct dasd_device *);
+ int (*release_space)(struct dasd_device *, struct format_data_t *);
+ /* Extent Pool */
+ int (*ext_pool_id)(struct dasd_device *);
+ int (*ext_size)(struct dasd_device *);
+ int (*ext_pool_cap_at_warnlevel)(struct dasd_device *);
+ int (*ext_pool_warn_thrshld)(struct dasd_device *);
+ int (*ext_pool_oos)(struct dasd_device *);
+ int (*ext_pool_exhaust)(struct dasd_device *, struct dasd_ccw_req *);
+ struct dasd_ccw_req *(*ese_format)(struct dasd_device *, struct dasd_ccw_req *);
+ void (*ese_read)(struct dasd_ccw_req *);
};
extern struct dasd_discipline *dasd_diag_discipline_pointer;
@@ -386,6 +408,7 @@ extern struct dasd_discipline *dasd_diag_discipline_pointer;
#define DASD_EER_NOPATH 2
#define DASD_EER_STATECHANGE 3
#define DASD_EER_PPRCSUSPEND 4
+#define DASD_EER_NOSPC 5
/* DASD path handling */
@@ -482,8 +505,10 @@ struct dasd_device {
spinlock_t mem_lock;
void *ccw_mem;
void *erp_mem;
+ void *ese_mem;
struct list_head ccw_chunks;
struct list_head erp_chunks;
+ struct list_head ese_chunks;
atomic_t tasklet_scheduled;
struct tasklet_struct tasklet;
@@ -558,6 +583,7 @@ struct dasd_queue {
#define DASD_STOPPED_SU 16 /* summary unit check handling */
#define DASD_STOPPED_PM 32 /* pm state transition */
#define DASD_UNRESUMED_PM 64 /* pm resume failed state */
+#define DASD_STOPPED_NOSPC 128 /* no space left */
/* per device flags */
#define DASD_FLAG_OFFLINE 3 /* device is in offline processing */
@@ -700,7 +726,9 @@ extern struct kmem_cache *dasd_page_cache;
struct dasd_ccw_req *
dasd_smalloc_request(int, int, int, struct dasd_device *, struct dasd_ccw_req *);
+struct dasd_ccw_req *dasd_fmalloc_request(int, int, int, struct dasd_device *);
void dasd_sfree_request(struct dasd_ccw_req *, struct dasd_device *);
+void dasd_ffree_request(struct dasd_ccw_req *, struct dasd_device *);
void dasd_wakeup_cb(struct dasd_ccw_req *, void *);
struct dasd_device *dasd_alloc_device(void);
@@ -727,6 +755,7 @@ void dasd_schedule_block_bh(struct dasd_block *);
int dasd_sleep_on(struct dasd_ccw_req *);
int dasd_sleep_on_queue(struct list_head *);
int dasd_sleep_on_immediatly(struct dasd_ccw_req *);
+int dasd_sleep_on_queue_interruptible(struct list_head *);
int dasd_sleep_on_interruptible(struct dasd_ccw_req *);
void dasd_device_set_timer(struct dasd_device *, int);
void dasd_device_clear_timer(struct dasd_device *);
@@ -750,6 +779,8 @@ int dasd_generic_restore_device(struct ccw_device *);
enum uc_todo dasd_generic_uc_handler(struct ccw_device *, struct irb *);
void dasd_generic_path_event(struct ccw_device *, int *);
int dasd_generic_verify_path(struct dasd_device *, __u8);
+void dasd_generic_space_exhaust(struct dasd_device *, struct dasd_ccw_req *);
+void dasd_generic_space_avail(struct dasd_device *);
int dasd_generic_read_dev_chars(struct dasd_device *, int, void *, int);
char *dasd_get_sense(struct irb *);
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
index 8e26001dc11c..9a5f3add325f 100644
--- a/drivers/s390/block/dasd_ioctl.c
+++ b/drivers/s390/block/dasd_ioctl.c
@@ -333,6 +333,59 @@ out_err:
return rc;
}
+static int dasd_release_space(struct dasd_device *device,
+ struct format_data_t *rdata)
+{
+ if (!device->discipline->is_ese && !device->discipline->is_ese(device))
+ return -ENOTSUPP;
+ if (!device->discipline->release_space)
+ return -ENOTSUPP;
+
+ return device->discipline->release_space(device, rdata);
+}
+
+/*
+ * Release allocated space
+ */
+static int dasd_ioctl_release_space(struct block_device *bdev, void __user *argp)
+{
+ struct format_data_t rdata;
+ struct dasd_device *base;
+ int rc = 0;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ if (!argp)
+ return -EINVAL;
+
+ base = dasd_device_from_gendisk(bdev->bd_disk);
+ if (!base)
+ return -ENODEV;
+ if (base->features & DASD_FEATURE_READONLY ||
+ test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) {
+ rc = -EROFS;
+ goto out_err;
+ }
+ if (bdev != bdev->bd_contains) {
+ pr_warn("%s: The specified DASD is a partition and tracks cannot be released\n",
+ dev_name(&base->cdev->dev));
+ rc = -EINVAL;
+ goto out_err;
+ }
+
+ if (copy_from_user(&rdata, argp, sizeof(rdata))) {
+ rc = -EFAULT;
+ goto out_err;
+ }
+
+ rc = dasd_release_space(base, &rdata);
+
+out_err:
+ dasd_put_device(base);
+
+ return rc;
+}
+
#ifdef CONFIG_DASD_PROFILE
/*
* Reset device profile information
@@ -595,6 +648,9 @@ int dasd_ioctl(struct block_device *bdev, fmode_t mode,
case BIODASDREADALLCMB:
rc = dasd_ioctl_readall_cmb(block, cmd, argp);
break;
+ case BIODASDRAS:
+ rc = dasd_ioctl_release_space(bdev, argp);
+ break;
default:
/* if the discipline has an ioctl method try it. */
rc = -ENOTTY;
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index d04d4378ca50..63502ca537eb 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -679,7 +679,7 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
goto put_dev;
dev_info->dax_dev = alloc_dax(dev_info, dev_info->gd->disk_name,
- &dcssblk_dax_ops);
+ &dcssblk_dax_ops, DAXDEV_F_SYNC);
if (!dev_info->dax_dev) {
rc = -ENOMEM;
goto put_dev;
diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig
index ab0b243a947d..6cc4b19acf85 100644
--- a/drivers/s390/char/Kconfig
+++ b/drivers/s390/char/Kconfig
@@ -79,27 +79,6 @@ config SCLP_VT220_CONSOLE
Include support for using an IBM SCLP VT220-compatible terminal as a
Linux system console.
-config SCLP_ASYNC
- def_tristate m
- prompt "Support for Call Home via Asynchronous SCLP Records"
- depends on S390
- help
- This option enables the call home function, which is able to inform
- the service element and connected organisations about a kernel panic.
- You should only select this option if you know what you are doing,
- want for inform other people about your kernel panics,
- need this feature and intend to run your kernel in LPAR.
-
-config SCLP_ASYNC_ID
- string "Component ID for Call Home"
- depends on SCLP_ASYNC
- default "000000000"
- help
- The Component ID for Call Home is used to identify the correct
- problem reporting queue the call home records should be sent to.
-
- If your are unsure, please use the default value "000000000".
-
config HMC_DRV
def_tristate m
prompt "Support for file transfers from HMC drive CD/DVD-ROM"
@@ -205,4 +184,3 @@ config S390_VMUR
depends on S390
help
Character device driver for z/VM reader, puncher and printer.
-
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
index 3072b89785dd..b8a8816d94e7 100644
--- a/drivers/s390/char/Makefile
+++ b/drivers/s390/char/Makefile
@@ -31,7 +31,6 @@ obj-$(CONFIG_TN3215) += con3215.o
obj-$(CONFIG_SCLP_TTY) += sclp_tty.o
obj-$(CONFIG_SCLP_CONSOLE) += sclp_con.o
obj-$(CONFIG_SCLP_VT220_TTY) += sclp_vt220.o
-obj-$(CONFIG_SCLP_ASYNC) += sclp_async.o
obj-$(CONFIG_PCI) += sclp_pci.o
diff --git a/drivers/s390/char/sclp_async.c b/drivers/s390/char/sclp_async.c
deleted file mode 100644
index e69b12a40636..000000000000
--- a/drivers/s390/char/sclp_async.c
+++ /dev/null
@@ -1,189 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Enable Asynchronous Notification via SCLP.
- *
- * Copyright IBM Corp. 2009
- * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com>
- *
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/stat.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/ctype.h>
-#include <linux/kmod.h>
-#include <linux/err.h>
-#include <linux/errno.h>
-#include <linux/proc_fs.h>
-#include <linux/sysctl.h>
-#include <linux/utsname.h>
-#include "sclp.h"
-
-static int callhome_enabled;
-static struct sclp_req *request;
-static struct sclp_async_sccb *sccb;
-static int sclp_async_send_wait(char *message);
-static struct ctl_table_header *callhome_sysctl_header;
-static DEFINE_SPINLOCK(sclp_async_lock);
-#define SCLP_NORMAL_WRITE 0x00
-
-struct async_evbuf {
- struct evbuf_header header;
- u64 reserved;
- u8 rflags;
- u8 empty;
- u8 rtype;
- u8 otype;
- char comp_id[12];
- char data[3000]; /* there is still some space left */
-} __attribute__((packed));
-
-struct sclp_async_sccb {
- struct sccb_header header;
- struct async_evbuf evbuf;
-} __attribute__((packed));
-
-static struct sclp_register sclp_async_register = {
- .send_mask = EVTYP_ASYNC_MASK,
-};
-
-static int call_home_on_panic(struct notifier_block *self,
- unsigned long event, void *data)
-{
- strncat(data, init_utsname()->nodename,
- sizeof(init_utsname()->nodename));
- sclp_async_send_wait(data);
- return NOTIFY_DONE;
-}
-
-static struct notifier_block call_home_panic_nb = {
- .notifier_call = call_home_on_panic,
- .priority = INT_MAX,
-};
-
-static int zero;
-static int one = 1;
-
-static struct ctl_table callhome_table[] = {
- {
- .procname = "callhome",
- .data = &callhome_enabled,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &zero,
- .extra2 = &one,
- },
- {}
-};
-
-static struct ctl_table kern_dir_table[] = {
- {
- .procname = "kernel",
- .maxlen = 0,
- .mode = 0555,
- .child = callhome_table,
- },
- {}
-};
-
-/*
- * Function used to transfer asynchronous notification
- * records which waits for send completion
- */
-static int sclp_async_send_wait(char *message)
-{
- struct async_evbuf *evb;
- int rc;
- unsigned long flags;
-
- if (!callhome_enabled)
- return 0;
- sccb->evbuf.header.type = EVTYP_ASYNC;
- sccb->evbuf.rtype = 0xA5;
- sccb->evbuf.otype = 0x00;
- evb = &sccb->evbuf;
- request->command = SCLP_CMDW_WRITE_EVENT_DATA;
- request->sccb = sccb;
- request->status = SCLP_REQ_FILLED;
- strncpy(sccb->evbuf.data, message, sizeof(sccb->evbuf.data));
- /*
- * Retain Queue
- * e.g. 5639CC140 500 Red Hat RHEL5 Linux for zSeries (RHEL AS)
- */
- strncpy(sccb->evbuf.comp_id, CONFIG_SCLP_ASYNC_ID,
- sizeof(sccb->evbuf.comp_id));
- sccb->evbuf.header.length = sizeof(sccb->evbuf);
- sccb->header.length = sizeof(sccb->evbuf) + sizeof(sccb->header);
- sccb->header.function_code = SCLP_NORMAL_WRITE;
- rc = sclp_add_request(request);
- if (rc)
- return rc;
- spin_lock_irqsave(&sclp_async_lock, flags);
- while (request->status != SCLP_REQ_DONE &&
- request->status != SCLP_REQ_FAILED) {
- sclp_sync_wait();
- }
- spin_unlock_irqrestore(&sclp_async_lock, flags);
- if (request->status != SCLP_REQ_DONE)
- return -EIO;
- rc = ((struct sclp_async_sccb *)
- request->sccb)->header.response_code;
- if (rc != 0x0020)
- return -EIO;
- if (evb->header.flags != 0x80)
- return -EIO;
- return rc;
-}
-
-static int __init sclp_async_init(void)
-{
- int rc;
-
- rc = sclp_register(&sclp_async_register);
- if (rc)
- return rc;
- rc = -EOPNOTSUPP;
- if (!(sclp_async_register.sclp_receive_mask & EVTYP_ASYNC_MASK))
- goto out_sclp;
- rc = -ENOMEM;
- callhome_sysctl_header = register_sysctl_table(kern_dir_table);
- if (!callhome_sysctl_header)
- goto out_sclp;
- request = kzalloc(sizeof(struct sclp_req), GFP_KERNEL);
- sccb = (struct sclp_async_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
- if (!request || !sccb)
- goto out_mem;
- rc = atomic_notifier_chain_register(&panic_notifier_list,
- &call_home_panic_nb);
- if (!rc)
- goto out;
-out_mem:
- kfree(request);
- free_page((unsigned long) sccb);
- unregister_sysctl_table(callhome_sysctl_header);
-out_sclp:
- sclp_unregister(&sclp_async_register);
-out:
- return rc;
-}
-module_init(sclp_async_init);
-
-static void __exit sclp_async_exit(void)
-{
- atomic_notifier_chain_unregister(&panic_notifier_list,
- &call_home_panic_nb);
- unregister_sysctl_table(callhome_sysctl_header);
- sclp_unregister(&sclp_async_register);
- free_page((unsigned long) sccb);
- kfree(request);
-}
-module_exit(sclp_async_exit);
-
-MODULE_AUTHOR("Copyright IBM Corp. 2009");
-MODULE_AUTHOR("Hans-Joachim Picht <hans@linux.vnet.ibm.com>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SCLP Asynchronous Notification Records");
diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c
index 6c90aa725f23..e71992a3c55f 100644
--- a/drivers/s390/char/sclp_early.c
+++ b/drivers/s390/char/sclp_early.c
@@ -41,7 +41,6 @@ static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb)
sclp.has_hvs = !!(sccb->fac119 & 0x80);
sclp.has_kss = !!(sccb->fac98 & 0x01);
sclp.has_sipl = !!(sccb->cbl & 0x02);
- sclp.has_sipl_g2 = !!(sccb->cbl & 0x04);
if (sccb->fac85 & 0x02)
S390_lowcore.machine_flags |= MACHINE_FLAG_ESOP;
if (sccb->fac91 & 0x40)
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c
index 405a60538630..08f812475f5e 100644
--- a/drivers/s390/char/zcore.c
+++ b/drivers/s390/char/zcore.c
@@ -4,7 +4,7 @@
* dumps on SCSI disks (zfcpdump). The "zcore/mem" debugfs file shows the same
* dump format as s390 standalone dumps.
*
- * For more information please refer to Documentation/s390/zfcpdump.txt
+ * For more information please refer to Documentation/s390/zfcpdump.rst
*
* Copyright IBM Corp. 2003, 2008
* Author(s): Michael Holzheu
diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c
index 4534afc63591..427b2e24a8ce 100644
--- a/drivers/s390/cio/airq.c
+++ b/drivers/s390/cio/airq.c
@@ -16,9 +16,11 @@
#include <linux/mutex.h>
#include <linux/rculist.h>
#include <linux/slab.h>
+#include <linux/dmapool.h>
#include <asm/airq.h>
#include <asm/isc.h>
+#include <asm/cio.h>
#include "cio.h"
#include "cio_debug.h"
@@ -27,7 +29,7 @@
static DEFINE_SPINLOCK(airq_lists_lock);
static struct hlist_head airq_lists[MAX_ISC+1];
-static struct kmem_cache *airq_iv_cache;
+static struct dma_pool *airq_iv_cache;
/**
* register_adapter_interrupt() - register adapter interrupt handler
@@ -115,6 +117,11 @@ void __init init_airq_interrupts(void)
setup_irq(THIN_INTERRUPT, &airq_interrupt);
}
+static inline unsigned long iv_size(unsigned long bits)
+{
+ return BITS_TO_LONGS(bits) * sizeof(unsigned long);
+}
+
/**
* airq_iv_create - create an interrupt vector
* @bits: number of bits in the interrupt vector
@@ -132,17 +139,19 @@ struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags)
goto out;
iv->bits = bits;
iv->flags = flags;
- size = BITS_TO_LONGS(bits) * sizeof(unsigned long);
+ size = iv_size(bits);
if (flags & AIRQ_IV_CACHELINE) {
- if ((cache_line_size() * BITS_PER_BYTE) < bits)
+ if ((cache_line_size() * BITS_PER_BYTE) < bits
+ || !airq_iv_cache)
goto out_free;
- iv->vector = kmem_cache_zalloc(airq_iv_cache, GFP_KERNEL);
+ iv->vector = dma_pool_zalloc(airq_iv_cache, GFP_KERNEL,
+ &iv->vector_dma);
if (!iv->vector)
goto out_free;
} else {
- iv->vector = kzalloc(size, GFP_KERNEL);
+ iv->vector = cio_dma_zalloc(size);
if (!iv->vector)
goto out_free;
}
@@ -178,10 +187,10 @@ out_free:
kfree(iv->ptr);
kfree(iv->bitlock);
kfree(iv->avail);
- if (iv->flags & AIRQ_IV_CACHELINE)
- kmem_cache_free(airq_iv_cache, iv->vector);
+ if (iv->flags & AIRQ_IV_CACHELINE && iv->vector)
+ dma_pool_free(airq_iv_cache, iv->vector, iv->vector_dma);
else
- kfree(iv->vector);
+ cio_dma_free(iv->vector, size);
kfree(iv);
out:
return NULL;
@@ -198,9 +207,9 @@ void airq_iv_release(struct airq_iv *iv)
kfree(iv->ptr);
kfree(iv->bitlock);
if (iv->flags & AIRQ_IV_CACHELINE)
- kmem_cache_free(airq_iv_cache, iv->vector);
+ dma_pool_free(airq_iv_cache, iv->vector, iv->vector_dma);
else
- kfree(iv->vector);
+ cio_dma_free(iv->vector, iv_size(iv->bits));
kfree(iv->avail);
kfree(iv);
}
@@ -295,12 +304,12 @@ unsigned long airq_iv_scan(struct airq_iv *iv, unsigned long start,
}
EXPORT_SYMBOL(airq_iv_scan);
-static int __init airq_init(void)
+int __init airq_init(void)
{
- airq_iv_cache = kmem_cache_create("airq_iv_cache", cache_line_size(),
- cache_line_size(), 0, NULL);
+ airq_iv_cache = dma_pool_create("airq_iv_cache", cio_get_dma_css_dev(),
+ cache_line_size(),
+ cache_line_size(), PAGE_SIZE);
if (!airq_iv_cache)
return -ENOMEM;
return 0;
}
-subsys_initcall(airq_init);
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index 4ebf6d4fc66c..c522e9313c50 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -581,7 +581,7 @@ int ccwgroup_driver_register(struct ccwgroup_driver *cdriver)
}
EXPORT_SYMBOL(ccwgroup_driver_register);
-static int __ccwgroup_match_all(struct device *dev, void *data)
+static int __ccwgroup_match_all(struct device *dev, const void *data)
{
return 1;
}
@@ -608,9 +608,9 @@ void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver)
}
EXPORT_SYMBOL(ccwgroup_driver_unregister);
-static int __ccwgroupdev_check_busid(struct device *dev, void *id)
+static int __ccwgroupdev_check_busid(struct device *dev, const void *id)
{
- char *bus_id = id;
+ const char *bus_id = id;
return (strcmp(bus_id, dev_name(dev)) == 0);
}
diff --git a/drivers/s390/cio/ccwreq.c b/drivers/s390/cio/ccwreq.c
index 603268a33ea1..73582a0a2622 100644
--- a/drivers/s390/cio/ccwreq.c
+++ b/drivers/s390/cio/ccwreq.c
@@ -63,7 +63,7 @@ static void ccwreq_stop(struct ccw_device *cdev, int rc)
return;
req->done = 1;
ccw_device_set_timeout(cdev, 0);
- memset(&cdev->private->irb, 0, sizeof(struct irb));
+ memset(&cdev->private->dma_area->irb, 0, sizeof(struct irb));
if (rc && rc != -ENODEV && req->drc)
rc = req->drc;
req->callback(cdev, req->data, rc);
@@ -86,7 +86,7 @@ static void ccwreq_do(struct ccw_device *cdev)
continue;
}
/* Perform start function. */
- memset(&cdev->private->irb, 0, sizeof(struct irb));
+ memset(&cdev->private->dma_area->irb, 0, sizeof(struct irb));
rc = cio_start(sch, cp, (u8) req->mask);
if (rc == 0) {
/* I/O started successfully. */
@@ -169,7 +169,7 @@ int ccw_request_cancel(struct ccw_device *cdev)
*/
static enum io_status ccwreq_status(struct ccw_device *cdev, struct irb *lcirb)
{
- struct irb *irb = &cdev->private->irb;
+ struct irb *irb = &cdev->private->dma_area->irb;
struct cmd_scsw *scsw = &irb->scsw.cmd;
enum uc_todo todo;
@@ -187,7 +187,8 @@ static enum io_status ccwreq_status(struct ccw_device *cdev, struct irb *lcirb)
CIO_TRACE_EVENT(2, "sensedata");
CIO_HEX_EVENT(2, &cdev->private->dev_id,
sizeof(struct ccw_dev_id));
- CIO_HEX_EVENT(2, &cdev->private->irb.ecw, SENSE_MAX_COUNT);
+ CIO_HEX_EVENT(2, &cdev->private->dma_area->irb.ecw,
+ SENSE_MAX_COUNT);
/* Check for command reject. */
if (irb->ecw[0] & SNS0_CMD_REJECT)
return IO_REJECTED;
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index a835b31aad99..6392a1b95b02 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -323,36 +323,6 @@ struct chsc_sei {
} __packed __aligned(PAGE_SIZE);
/*
- * Node Descriptor as defined in SA22-7204, "Common I/O-Device Commands"
- */
-
-#define ND_VALIDITY_VALID 0
-#define ND_VALIDITY_OUTDATED 1
-#define ND_VALIDITY_INVALID 2
-
-struct node_descriptor {
- /* Flags. */
- union {
- struct {
- u32 validity:3;
- u32 reserved:5;
- } __packed;
- u8 byte0;
- } __packed;
-
- /* Node parameters. */
- u32 params:24;
-
- /* Node ID. */
- char type[6];
- char model[3];
- char manufacturer[3];
- char plant[2];
- char seq[12];
- u16 tag;
-} __packed;
-
-/*
* Link Incident Record as defined in SA22-7202, "ESCON I/O Interface"
*/
diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c
index 8d9f36625ba5..8f080d3fd380 100644
--- a/drivers/s390/cio/chsc_sch.c
+++ b/drivers/s390/cio/chsc_sch.c
@@ -203,7 +203,7 @@ static void chsc_cleanup_sch_driver(void)
static DEFINE_SPINLOCK(chsc_lock);
-static int chsc_subchannel_match_next_free(struct device *dev, void *data)
+static int chsc_subchannel_match_next_free(struct device *dev, const void *data)
{
struct subchannel *sch = to_subchannel(dev);
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index 06a91743335a..ba7d2480613b 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -113,6 +113,7 @@ struct subchannel {
enum sch_todo todo;
struct work_struct todo_work;
struct schib_config config;
+ char *driver_override; /* Driver name to force a match */
} __attribute__ ((aligned(8)));
DECLARE_PER_CPU_ALIGNED(struct irb, cio_irb);
@@ -135,6 +136,8 @@ extern int cio_commit_config(struct subchannel *sch);
int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key);
int cio_tm_intrg(struct subchannel *sch);
+extern int __init airq_init(void);
+
/* Use with care. */
#ifdef CONFIG_CCW_CONSOLE
extern struct subchannel *cio_probe_console(void);
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index aea502922646..22c55816100b 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -20,6 +20,8 @@
#include <linux/reboot.h>
#include <linux/suspend.h>
#include <linux/proc_fs.h>
+#include <linux/genalloc.h>
+#include <linux/dma-mapping.h>
#include <asm/isc.h>
#include <asm/crw.h>
@@ -165,6 +167,7 @@ static void css_subchannel_release(struct device *dev)
sch->config.intparm = 0;
cio_commit_config(sch);
+ kfree(sch->driver_override);
kfree(sch->lock);
kfree(sch);
}
@@ -224,6 +227,12 @@ struct subchannel *css_alloc_subchannel(struct subchannel_id schid,
INIT_WORK(&sch->todo_work, css_sch_todo);
sch->dev.release = &css_subchannel_release;
device_initialize(&sch->dev);
+ /*
+ * The physical addresses of some the dma structures that can
+ * belong to a subchannel need to fit 31 bit width (e.g. ccw).
+ */
+ sch->dev.coherent_dma_mask = DMA_BIT_MASK(31);
+ sch->dev.dma_mask = &sch->dev.coherent_dma_mask;
return sch;
err:
@@ -315,9 +324,57 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR_RO(modalias);
+static ssize_t driver_override_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct subchannel *sch = to_subchannel(dev);
+ char *driver_override, *old, *cp;
+
+ /* We need to keep extra room for a newline */
+ if (count >= (PAGE_SIZE - 1))
+ return -EINVAL;
+
+ driver_override = kstrndup(buf, count, GFP_KERNEL);
+ if (!driver_override)
+ return -ENOMEM;
+
+ cp = strchr(driver_override, '\n');
+ if (cp)
+ *cp = '\0';
+
+ device_lock(dev);
+ old = sch->driver_override;
+ if (strlen(driver_override)) {
+ sch->driver_override = driver_override;
+ } else {
+ kfree(driver_override);
+ sch->driver_override = NULL;
+ }
+ device_unlock(dev);
+
+ kfree(old);
+
+ return count;
+}
+
+static ssize_t driver_override_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct subchannel *sch = to_subchannel(dev);
+ ssize_t len;
+
+ device_lock(dev);
+ len = snprintf(buf, PAGE_SIZE, "%s\n", sch->driver_override);
+ device_unlock(dev);
+ return len;
+}
+static DEVICE_ATTR_RW(driver_override);
+
static struct attribute *subch_attrs[] = {
&dev_attr_type.attr,
&dev_attr_modalias.attr,
+ &dev_attr_driver_override.attr,
NULL,
};
@@ -434,10 +491,10 @@ static int css_probe_device(struct subchannel_id schid, struct schib *schib)
}
static int
-check_subchannel(struct device * dev, void * data)
+check_subchannel(struct device *dev, const void *data)
{
struct subchannel *sch;
- struct subchannel_id *schid = data;
+ struct subchannel_id *schid = (void *)data;
sch = to_subchannel(dev);
return schid_equal(&sch->schid, schid);
@@ -899,6 +956,13 @@ static int __init setup_css(int nr)
dev_set_name(&css->device, "css%x", nr);
css->device.groups = cssdev_attr_groups;
css->device.release = channel_subsystem_release;
+ /*
+ * We currently allocate notifier bits with this (using
+ * css->device as the device argument with the DMA API)
+ * and are fine with 64 bit addresses.
+ */
+ css->device.coherent_dma_mask = DMA_BIT_MASK(64);
+ css->device.dma_mask = &css->device.coherent_dma_mask;
mutex_init(&css->mutex);
css->cssid = chsc_get_cssid(nr);
@@ -1018,6 +1082,111 @@ static struct notifier_block css_power_notifier = {
.notifier_call = css_power_event,
};
+#define CIO_DMA_GFP (GFP_KERNEL | __GFP_ZERO)
+static struct gen_pool *cio_dma_pool;
+
+/* Currently cio supports only a single css */
+struct device *cio_get_dma_css_dev(void)
+{
+ return &channel_subsystems[0]->device;
+}
+
+struct gen_pool *cio_gp_dma_create(struct device *dma_dev, int nr_pages)
+{
+ struct gen_pool *gp_dma;
+ void *cpu_addr;
+ dma_addr_t dma_addr;
+ int i;
+
+ gp_dma = gen_pool_create(3, -1);
+ if (!gp_dma)
+ return NULL;
+ for (i = 0; i < nr_pages; ++i) {
+ cpu_addr = dma_alloc_coherent(dma_dev, PAGE_SIZE, &dma_addr,
+ CIO_DMA_GFP);
+ if (!cpu_addr)
+ return gp_dma;
+ gen_pool_add_virt(gp_dma, (unsigned long) cpu_addr,
+ dma_addr, PAGE_SIZE, -1);
+ }
+ return gp_dma;
+}
+
+static void __gp_dma_free_dma(struct gen_pool *pool,
+ struct gen_pool_chunk *chunk, void *data)
+{
+ size_t chunk_size = chunk->end_addr - chunk->start_addr + 1;
+
+ dma_free_coherent((struct device *) data, chunk_size,
+ (void *) chunk->start_addr,
+ (dma_addr_t) chunk->phys_addr);
+}
+
+void cio_gp_dma_destroy(struct gen_pool *gp_dma, struct device *dma_dev)
+{
+ if (!gp_dma)
+ return;
+ /* this is quite ugly but no better idea */
+ gen_pool_for_each_chunk(gp_dma, __gp_dma_free_dma, dma_dev);
+ gen_pool_destroy(gp_dma);
+}
+
+static int cio_dma_pool_init(void)
+{
+ /* No need to free up the resources: compiled in */
+ cio_dma_pool = cio_gp_dma_create(cio_get_dma_css_dev(), 1);
+ if (!cio_dma_pool)
+ return -ENOMEM;
+ return 0;
+}
+
+void *cio_gp_dma_zalloc(struct gen_pool *gp_dma, struct device *dma_dev,
+ size_t size)
+{
+ dma_addr_t dma_addr;
+ unsigned long addr;
+ size_t chunk_size;
+
+ if (!gp_dma)
+ return NULL;
+ addr = gen_pool_alloc(gp_dma, size);
+ while (!addr) {
+ chunk_size = round_up(size, PAGE_SIZE);
+ addr = (unsigned long) dma_alloc_coherent(dma_dev,
+ chunk_size, &dma_addr, CIO_DMA_GFP);
+ if (!addr)
+ return NULL;
+ gen_pool_add_virt(gp_dma, addr, dma_addr, chunk_size, -1);
+ addr = gen_pool_alloc(gp_dma, size);
+ }
+ return (void *) addr;
+}
+
+void cio_gp_dma_free(struct gen_pool *gp_dma, void *cpu_addr, size_t size)
+{
+ if (!cpu_addr)
+ return;
+ memset(cpu_addr, 0, size);
+ gen_pool_free(gp_dma, (unsigned long) cpu_addr, size);
+}
+
+/*
+ * Allocate dma memory from the css global pool. Intended for memory not
+ * specific to any single device within the css. The allocated memory
+ * is not guaranteed to be 31-bit addressable.
+ *
+ * Caution: Not suitable for early stuff like console.
+ */
+void *cio_dma_zalloc(size_t size)
+{
+ return cio_gp_dma_zalloc(cio_dma_pool, cio_get_dma_css_dev(), size);
+}
+
+void cio_dma_free(void *cpu_addr, size_t size)
+{
+ cio_gp_dma_free(cio_dma_pool, cpu_addr, size);
+}
+
/*
* Now that the driver core is running, we can setup our channel subsystem.
* The struct subchannel's are created during probing.
@@ -1059,16 +1228,22 @@ static int __init css_bus_init(void)
if (ret)
goto out_unregister;
ret = register_pm_notifier(&css_power_notifier);
- if (ret) {
- unregister_reboot_notifier(&css_reboot_notifier);
- goto out_unregister;
- }
+ if (ret)
+ goto out_unregister_rn;
+ ret = cio_dma_pool_init();
+ if (ret)
+ goto out_unregister_pmn;
+ airq_init();
css_init_done = 1;
/* Enable default isc for I/O subchannels. */
isc_register(IO_SCH_ISC);
return 0;
+out_unregister_pmn:
+ unregister_pm_notifier(&css_power_notifier);
+out_unregister_rn:
+ unregister_reboot_notifier(&css_reboot_notifier);
out_unregister:
while (i-- > 0) {
struct channel_subsystem *css = channel_subsystems[i];
@@ -1222,6 +1397,10 @@ static int css_bus_match(struct device *dev, struct device_driver *drv)
struct css_driver *driver = to_cssdriver(drv);
struct css_device_id *id;
+ /* When driver_override is set, only bind to the matching driver */
+ if (sch->driver_override && strcmp(sch->driver_override, drv->name))
+ return 0;
+
for (id = driver->subchannel_type; id->match_flags; id++) {
if (sch->st == id->type)
return 1;
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 1540229a37bb..c421899be20f 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -24,6 +24,7 @@
#include <linux/timer.h>
#include <linux/kernel_stat.h>
#include <linux/sched/signal.h>
+#include <linux/dma-mapping.h>
#include <asm/ccwdev.h>
#include <asm/cio.h>
@@ -642,10 +643,10 @@ static int ccw_device_add(struct ccw_device *cdev)
return device_add(dev);
}
-static int match_dev_id(struct device *dev, void *data)
+static int match_dev_id(struct device *dev, const void *data)
{
struct ccw_device *cdev = to_ccwdev(dev);
- struct ccw_dev_id *dev_id = data;
+ struct ccw_dev_id *dev_id = (void *)data;
return ccw_dev_id_is_equal(&cdev->private->dev_id, dev_id);
}
@@ -687,6 +688,9 @@ ccw_device_release(struct device *dev)
struct ccw_device *cdev;
cdev = to_ccwdev(dev);
+ cio_gp_dma_free(cdev->private->dma_pool, cdev->private->dma_area,
+ sizeof(*cdev->private->dma_area));
+ cio_gp_dma_destroy(cdev->private->dma_pool, &cdev->dev);
/* Release reference of parent subchannel. */
put_device(cdev->dev.parent);
kfree(cdev->private);
@@ -696,15 +700,33 @@ ccw_device_release(struct device *dev)
static struct ccw_device * io_subchannel_allocate_dev(struct subchannel *sch)
{
struct ccw_device *cdev;
+ struct gen_pool *dma_pool;
cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
- if (cdev) {
- cdev->private = kzalloc(sizeof(struct ccw_device_private),
- GFP_KERNEL | GFP_DMA);
- if (cdev->private)
- return cdev;
- }
+ if (!cdev)
+ goto err_cdev;
+ cdev->private = kzalloc(sizeof(struct ccw_device_private),
+ GFP_KERNEL | GFP_DMA);
+ if (!cdev->private)
+ goto err_priv;
+ cdev->dev.coherent_dma_mask = sch->dev.coherent_dma_mask;
+ cdev->dev.dma_mask = &cdev->dev.coherent_dma_mask;
+ dma_pool = cio_gp_dma_create(&cdev->dev, 1);
+ if (!dma_pool)
+ goto err_dma_pool;
+ cdev->private->dma_pool = dma_pool;
+ cdev->private->dma_area = cio_gp_dma_zalloc(dma_pool, &cdev->dev,
+ sizeof(*cdev->private->dma_area));
+ if (!cdev->private->dma_area)
+ goto err_dma_area;
+ return cdev;
+err_dma_area:
+ cio_gp_dma_destroy(dma_pool, &cdev->dev);
+err_dma_pool:
+ kfree(cdev->private);
+err_priv:
kfree(cdev);
+err_cdev:
return ERR_PTR(-ENOMEM);
}
@@ -884,7 +906,7 @@ io_subchannel_recog_done(struct ccw_device *cdev)
wake_up(&ccw_device_init_wq);
break;
case DEV_STATE_OFFLINE:
- /*
+ /*
* We can't register the device in interrupt context so
* we schedule a work item.
*/
@@ -1062,6 +1084,14 @@ static int io_subchannel_probe(struct subchannel *sch)
if (!io_priv)
goto out_schedule;
+ io_priv->dma_area = dma_alloc_coherent(&sch->dev,
+ sizeof(*io_priv->dma_area),
+ &io_priv->dma_area_dma, GFP_KERNEL);
+ if (!io_priv->dma_area) {
+ kfree(io_priv);
+ goto out_schedule;
+ }
+
set_io_private(sch, io_priv);
css_schedule_eval(sch->schid);
return 0;
@@ -1088,6 +1118,8 @@ static int io_subchannel_remove(struct subchannel *sch)
set_io_private(sch, NULL);
spin_unlock_irq(sch->lock);
out_free:
+ dma_free_coherent(&sch->dev, sizeof(*io_priv->dma_area),
+ io_priv->dma_area, io_priv->dma_area_dma);
kfree(io_priv);
sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group);
return 0;
@@ -1593,13 +1625,19 @@ struct ccw_device * __init ccw_device_create_console(struct ccw_driver *drv)
return ERR_CAST(sch);
io_priv = kzalloc(sizeof(*io_priv), GFP_KERNEL | GFP_DMA);
- if (!io_priv) {
- put_device(&sch->dev);
- return ERR_PTR(-ENOMEM);
- }
+ if (!io_priv)
+ goto err_priv;
+ io_priv->dma_area = dma_alloc_coherent(&sch->dev,
+ sizeof(*io_priv->dma_area),
+ &io_priv->dma_area_dma, GFP_KERNEL);
+ if (!io_priv->dma_area)
+ goto err_dma_area;
set_io_private(sch, io_priv);
cdev = io_subchannel_create_ccwdev(sch);
if (IS_ERR(cdev)) {
+ dma_free_coherent(&sch->dev, sizeof(*io_priv->dma_area),
+ io_priv->dma_area, io_priv->dma_area_dma);
+ set_io_private(sch, NULL);
put_device(&sch->dev);
kfree(io_priv);
return cdev;
@@ -1607,6 +1645,12 @@ struct ccw_device * __init ccw_device_create_console(struct ccw_driver *drv)
cdev->drv = drv;
ccw_device_set_int_class(cdev);
return cdev;
+
+err_dma_area:
+ kfree(io_priv);
+err_priv:
+ put_device(&sch->dev);
+ return ERR_PTR(-ENOMEM);
}
void __init ccw_device_destroy_console(struct ccw_device *cdev)
@@ -1617,6 +1661,8 @@ void __init ccw_device_destroy_console(struct ccw_device *cdev)
set_io_private(sch, NULL);
put_device(&sch->dev);
put_device(&cdev->dev);
+ dma_free_coherent(&sch->dev, sizeof(*io_priv->dma_area),
+ io_priv->dma_area, io_priv->dma_area_dma);
kfree(io_priv);
}
@@ -1653,11 +1699,9 @@ EXPORT_SYMBOL_GPL(ccw_device_force_console);
* get ccw_device matching the busid, but only if owned by cdrv
*/
static int
-__ccwdev_check_busid(struct device *dev, void *id)
+__ccwdev_check_busid(struct device *dev, const void *id)
{
- char *bus_id;
-
- bus_id = id;
+ const char *bus_id = id;
return (strcmp(bus_id, dev_name(dev)) == 0);
}
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 9169af7dbb43..8fc267324ebb 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -67,8 +67,10 @@ static void ccw_timeout_log(struct ccw_device *cdev)
sizeof(struct tcw), 0);
} else {
printk(KERN_WARNING "cio: orb indicates command mode\n");
- if ((void *)(addr_t)orb->cmd.cpa == &private->sense_ccw ||
- (void *)(addr_t)orb->cmd.cpa == cdev->private->iccws)
+ if ((void *)(addr_t)orb->cmd.cpa ==
+ &private->dma_area->sense_ccw ||
+ (void *)(addr_t)orb->cmd.cpa ==
+ cdev->private->dma_area->iccws)
printk(KERN_WARNING "cio: last channel program "
"(intern):\n");
else
@@ -143,18 +145,22 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev)
void ccw_device_update_sense_data(struct ccw_device *cdev)
{
memset(&cdev->id, 0, sizeof(cdev->id));
- cdev->id.cu_type = cdev->private->senseid.cu_type;
- cdev->id.cu_model = cdev->private->senseid.cu_model;
- cdev->id.dev_type = cdev->private->senseid.dev_type;
- cdev->id.dev_model = cdev->private->senseid.dev_model;
+ cdev->id.cu_type = cdev->private->dma_area->senseid.cu_type;
+ cdev->id.cu_model = cdev->private->dma_area->senseid.cu_model;
+ cdev->id.dev_type = cdev->private->dma_area->senseid.dev_type;
+ cdev->id.dev_model = cdev->private->dma_area->senseid.dev_model;
}
int ccw_device_test_sense_data(struct ccw_device *cdev)
{
- return cdev->id.cu_type == cdev->private->senseid.cu_type &&
- cdev->id.cu_model == cdev->private->senseid.cu_model &&
- cdev->id.dev_type == cdev->private->senseid.dev_type &&
- cdev->id.dev_model == cdev->private->senseid.dev_model;
+ return cdev->id.cu_type ==
+ cdev->private->dma_area->senseid.cu_type &&
+ cdev->id.cu_model ==
+ cdev->private->dma_area->senseid.cu_model &&
+ cdev->id.dev_type ==
+ cdev->private->dma_area->senseid.dev_type &&
+ cdev->id.dev_model ==
+ cdev->private->dma_area->senseid.dev_model;
}
/*
@@ -342,7 +348,7 @@ ccw_device_done(struct ccw_device *cdev, int state)
cio_disable_subchannel(sch);
/* Reset device status. */
- memset(&cdev->private->irb, 0, sizeof(struct irb));
+ memset(&cdev->private->dma_area->irb, 0, sizeof(struct irb));
cdev->private->state = state;
@@ -509,13 +515,14 @@ callback:
ccw_device_done(cdev, DEV_STATE_ONLINE);
/* Deliver fake irb to device driver, if needed. */
if (cdev->private->flags.fake_irb) {
- create_fake_irb(&cdev->private->irb,
+ create_fake_irb(&cdev->private->dma_area->irb,
cdev->private->flags.fake_irb);
cdev->private->flags.fake_irb = 0;
if (cdev->handler)
cdev->handler(cdev, cdev->private->intparm,
- &cdev->private->irb);
- memset(&cdev->private->irb, 0, sizeof(struct irb));
+ &cdev->private->dma_area->irb);
+ memset(&cdev->private->dma_area->irb, 0,
+ sizeof(struct irb));
}
ccw_device_report_path_events(cdev);
ccw_device_handle_broken_paths(cdev);
@@ -672,7 +679,8 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event)
if (scsw_actl(&sch->schib.scsw) != 0 ||
(scsw_stctl(&sch->schib.scsw) & SCSW_STCTL_STATUS_PEND) ||
- (scsw_stctl(&cdev->private->irb.scsw) & SCSW_STCTL_STATUS_PEND)) {
+ (scsw_stctl(&cdev->private->dma_area->irb.scsw) &
+ SCSW_STCTL_STATUS_PEND)) {
/*
* No final status yet or final status not yet delivered
* to the device driver. Can't do path verification now,
@@ -719,7 +727,7 @@ static int ccw_device_call_handler(struct ccw_device *cdev)
* - fast notification was requested (primary status)
* - unsolicited interrupts
*/
- stctl = scsw_stctl(&cdev->private->irb.scsw);
+ stctl = scsw_stctl(&cdev->private->dma_area->irb.scsw);
ending_status = (stctl & SCSW_STCTL_SEC_STATUS) ||
(stctl == (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)) ||
(stctl == SCSW_STCTL_STATUS_PEND);
@@ -735,9 +743,9 @@ static int ccw_device_call_handler(struct ccw_device *cdev)
if (cdev->handler)
cdev->handler(cdev, cdev->private->intparm,
- &cdev->private->irb);
+ &cdev->private->dma_area->irb);
- memset(&cdev->private->irb, 0, sizeof(struct irb));
+ memset(&cdev->private->dma_area->irb, 0, sizeof(struct irb));
return 1;
}
@@ -759,7 +767,8 @@ ccw_device_irq(struct ccw_device *cdev, enum dev_event dev_event)
/* Unit check but no sense data. Need basic sense. */
if (ccw_device_do_sense(cdev, irb) != 0)
goto call_handler_unsol;
- memcpy(&cdev->private->irb, irb, sizeof(struct irb));
+ memcpy(&cdev->private->dma_area->irb, irb,
+ sizeof(struct irb));
cdev->private->state = DEV_STATE_W4SENSE;
cdev->private->intparm = 0;
return;
@@ -842,7 +851,7 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event)
if (scsw_fctl(&irb->scsw) &
(SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_HALT_FUNC)) {
cdev->private->flags.dosense = 0;
- memset(&cdev->private->irb, 0, sizeof(struct irb));
+ memset(&cdev->private->dma_area->irb, 0, sizeof(struct irb));
ccw_device_accumulate_irb(cdev, irb);
goto call_handler;
}
diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c
index f6df83a9dfbb..740996d0dc8c 100644
--- a/drivers/s390/cio/device_id.c
+++ b/drivers/s390/cio/device_id.c
@@ -99,7 +99,7 @@ static int diag210_to_senseid(struct senseid *senseid, struct diag210 *diag)
static int diag210_get_dev_info(struct ccw_device *cdev)
{
struct ccw_dev_id *dev_id = &cdev->private->dev_id;
- struct senseid *senseid = &cdev->private->senseid;
+ struct senseid *senseid = &cdev->private->dma_area->senseid;
struct diag210 diag_data;
int rc;
@@ -134,8 +134,10 @@ err_failed:
static void snsid_init(struct ccw_device *cdev)
{
cdev->private->flags.esid = 0;
- memset(&cdev->private->senseid, 0, sizeof(cdev->private->senseid));
- cdev->private->senseid.cu_type = 0xffff;
+
+ memset(&cdev->private->dma_area->senseid, 0,
+ sizeof(cdev->private->dma_area->senseid));
+ cdev->private->dma_area->senseid.cu_type = 0xffff;
}
/*
@@ -143,16 +145,16 @@ static void snsid_init(struct ccw_device *cdev)
*/
static int snsid_check(struct ccw_device *cdev, void *data)
{
- struct cmd_scsw *scsw = &cdev->private->irb.scsw.cmd;
+ struct cmd_scsw *scsw = &cdev->private->dma_area->irb.scsw.cmd;
int len = sizeof(struct senseid) - scsw->count;
/* Check for incomplete SENSE ID data. */
if (len < SENSE_ID_MIN_LEN)
goto out_restart;
- if (cdev->private->senseid.cu_type == 0xffff)
+ if (cdev->private->dma_area->senseid.cu_type == 0xffff)
goto out_restart;
/* Check for incompatible SENSE ID data. */
- if (cdev->private->senseid.reserved != 0xff)
+ if (cdev->private->dma_area->senseid.reserved != 0xff)
return -EOPNOTSUPP;
/* Check for extended-identification information. */
if (len > SENSE_ID_BASIC_LEN)
@@ -170,7 +172,7 @@ out_restart:
static void snsid_callback(struct ccw_device *cdev, void *data, int rc)
{
struct ccw_dev_id *id = &cdev->private->dev_id;
- struct senseid *senseid = &cdev->private->senseid;
+ struct senseid *senseid = &cdev->private->dma_area->senseid;
int vm = 0;
if (rc && MACHINE_IS_VM) {
@@ -200,7 +202,7 @@ void ccw_device_sense_id_start(struct ccw_device *cdev)
{
struct subchannel *sch = to_subchannel(cdev->dev.parent);
struct ccw_request *req = &cdev->private->req;
- struct ccw1 *cp = cdev->private->iccws;
+ struct ccw1 *cp = cdev->private->dma_area->iccws;
CIO_TRACE_EVENT(4, "snsid");
CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id));
@@ -208,7 +210,7 @@ void ccw_device_sense_id_start(struct ccw_device *cdev)
snsid_init(cdev);
/* Channel program setup. */
cp->cmd_code = CCW_CMD_SENSE_ID;
- cp->cda = (u32) (addr_t) &cdev->private->senseid;
+ cp->cda = (u32) (addr_t) &cdev->private->dma_area->senseid;
cp->count = sizeof(struct senseid);
cp->flags = CCW_FLAG_SLI;
/* Request setup. */
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index 4435ae0b3027..d722458c5928 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -429,8 +429,8 @@ struct ciw *ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct)
if (cdev->private->flags.esid == 0)
return NULL;
for (ciw_cnt = 0; ciw_cnt < MAX_CIWS; ciw_cnt++)
- if (cdev->private->senseid.ciw[ciw_cnt].ct == ct)
- return cdev->private->senseid.ciw + ciw_cnt;
+ if (cdev->private->dma_area->senseid.ciw[ciw_cnt].ct == ct)
+ return cdev->private->dma_area->senseid.ciw + ciw_cnt;
return NULL;
}
@@ -699,6 +699,23 @@ void ccw_device_get_schid(struct ccw_device *cdev, struct subchannel_id *schid)
}
EXPORT_SYMBOL_GPL(ccw_device_get_schid);
+/*
+ * Allocate zeroed dma coherent 31 bit addressable memory using
+ * the subchannels dma pool. Maximal size of allocation supported
+ * is PAGE_SIZE.
+ */
+void *ccw_device_dma_zalloc(struct ccw_device *cdev, size_t size)
+{
+ return cio_gp_dma_zalloc(cdev->private->dma_pool, &cdev->dev, size);
+}
+EXPORT_SYMBOL(ccw_device_dma_zalloc);
+
+void ccw_device_dma_free(struct ccw_device *cdev, void *cpu_addr, size_t size)
+{
+ cio_gp_dma_free(cdev->private->dma_pool, cpu_addr, size);
+}
+EXPORT_SYMBOL(ccw_device_dma_free);
+
EXPORT_SYMBOL(ccw_device_set_options_mask);
EXPORT_SYMBOL(ccw_device_set_options);
EXPORT_SYMBOL(ccw_device_clear_options);
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c
index d30a3babf176..767a85635a0f 100644
--- a/drivers/s390/cio/device_pgid.c
+++ b/drivers/s390/cio/device_pgid.c
@@ -57,7 +57,7 @@ out:
static void nop_build_cp(struct ccw_device *cdev)
{
struct ccw_request *req = &cdev->private->req;
- struct ccw1 *cp = cdev->private->iccws;
+ struct ccw1 *cp = cdev->private->dma_area->iccws;
cp->cmd_code = CCW_CMD_NOOP;
cp->cda = 0;
@@ -134,9 +134,9 @@ err:
static void spid_build_cp(struct ccw_device *cdev, u8 fn)
{
struct ccw_request *req = &cdev->private->req;
- struct ccw1 *cp = cdev->private->iccws;
+ struct ccw1 *cp = cdev->private->dma_area->iccws;
int i = pathmask_to_pos(req->lpm);
- struct pgid *pgid = &cdev->private->pgid[i];
+ struct pgid *pgid = &cdev->private->dma_area->pgid[i];
pgid->inf.fc = fn;
cp->cmd_code = CCW_CMD_SET_PGID;
@@ -300,7 +300,7 @@ static int pgid_cmp(struct pgid *p1, struct pgid *p2)
static void pgid_analyze(struct ccw_device *cdev, struct pgid **p,
int *mismatch, u8 *reserved, u8 *reset)
{
- struct pgid *pgid = &cdev->private->pgid[0];
+ struct pgid *pgid = &cdev->private->dma_area->pgid[0];
struct pgid *first = NULL;
int lpm;
int i;
@@ -342,7 +342,7 @@ static u8 pgid_to_donepm(struct ccw_device *cdev)
lpm = 0x80 >> i;
if ((cdev->private->pgid_valid_mask & lpm) == 0)
continue;
- pgid = &cdev->private->pgid[i];
+ pgid = &cdev->private->dma_area->pgid[i];
if (sch->opm & lpm) {
if (pgid->inf.ps.state1 != SNID_STATE1_GROUPED)
continue;
@@ -368,7 +368,8 @@ static void pgid_fill(struct ccw_device *cdev, struct pgid *pgid)
int i;
for (i = 0; i < 8; i++)
- memcpy(&cdev->private->pgid[i], pgid, sizeof(struct pgid));
+ memcpy(&cdev->private->dma_area->pgid[i], pgid,
+ sizeof(struct pgid));
}
/*
@@ -435,12 +436,12 @@ out:
static void snid_build_cp(struct ccw_device *cdev)
{
struct ccw_request *req = &cdev->private->req;
- struct ccw1 *cp = cdev->private->iccws;
+ struct ccw1 *cp = cdev->private->dma_area->iccws;
int i = pathmask_to_pos(req->lpm);
/* Channel program setup. */
cp->cmd_code = CCW_CMD_SENSE_PGID;
- cp->cda = (u32) (addr_t) &cdev->private->pgid[i];
+ cp->cda = (u32) (addr_t) &cdev->private->dma_area->pgid[i];
cp->count = sizeof(struct pgid);
cp->flags = CCW_FLAG_SLI;
req->cp = cp;
@@ -516,7 +517,8 @@ static void verify_start(struct ccw_device *cdev)
sch->lpm = sch->schib.pmcw.pam;
/* Initialize PGID data. */
- memset(cdev->private->pgid, 0, sizeof(cdev->private->pgid));
+ memset(cdev->private->dma_area->pgid, 0,
+ sizeof(cdev->private->dma_area->pgid));
cdev->private->pgid_valid_mask = 0;
cdev->private->pgid_todo_mask = sch->schib.pmcw.pam;
cdev->private->path_notoper_mask = 0;
@@ -626,7 +628,7 @@ struct stlck_data {
static void stlck_build_cp(struct ccw_device *cdev, void *buf1, void *buf2)
{
struct ccw_request *req = &cdev->private->req;
- struct ccw1 *cp = cdev->private->iccws;
+ struct ccw1 *cp = cdev->private->dma_area->iccws;
cp[0].cmd_code = CCW_CMD_STLCK;
cp[0].cda = (u32) (addr_t) buf1;
diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c
index 7d5c7892b2c4..0bd8f2642732 100644
--- a/drivers/s390/cio/device_status.c
+++ b/drivers/s390/cio/device_status.c
@@ -79,15 +79,15 @@ ccw_device_accumulate_ecw(struct ccw_device *cdev, struct irb *irb)
* are condition that have to be met for the extended control
* bit to have meaning. Sick.
*/
- cdev->private->irb.scsw.cmd.ectl = 0;
+ cdev->private->dma_area->irb.scsw.cmd.ectl = 0;
if ((irb->scsw.cmd.stctl & SCSW_STCTL_ALERT_STATUS) &&
!(irb->scsw.cmd.stctl & SCSW_STCTL_INTER_STATUS))
- cdev->private->irb.scsw.cmd.ectl = irb->scsw.cmd.ectl;
+ cdev->private->dma_area->irb.scsw.cmd.ectl = irb->scsw.cmd.ectl;
/* Check if extended control word is valid. */
- if (!cdev->private->irb.scsw.cmd.ectl)
+ if (!cdev->private->dma_area->irb.scsw.cmd.ectl)
return;
/* Copy concurrent sense / model dependent information. */
- memcpy (&cdev->private->irb.ecw, irb->ecw, sizeof (irb->ecw));
+ memcpy(&cdev->private->dma_area->irb.ecw, irb->ecw, sizeof(irb->ecw));
}
/*
@@ -118,7 +118,7 @@ ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb)
if (!ccw_device_accumulate_esw_valid(irb))
return;
- cdev_irb = &cdev->private->irb;
+ cdev_irb = &cdev->private->dma_area->irb;
/* Copy last path used mask. */
cdev_irb->esw.esw1.lpum = irb->esw.esw1.lpum;
@@ -210,7 +210,7 @@ ccw_device_accumulate_irb(struct ccw_device *cdev, struct irb *irb)
ccw_device_path_notoper(cdev);
/* No irb accumulation for transport mode irbs. */
if (scsw_is_tm(&irb->scsw)) {
- memcpy(&cdev->private->irb, irb, sizeof(struct irb));
+ memcpy(&cdev->private->dma_area->irb, irb, sizeof(struct irb));
return;
}
/*
@@ -219,7 +219,7 @@ ccw_device_accumulate_irb(struct ccw_device *cdev, struct irb *irb)
if (!scsw_is_solicited(&irb->scsw))
return;
- cdev_irb = &cdev->private->irb;
+ cdev_irb = &cdev->private->dma_area->irb;
/*
* If the clear function had been performed, all formerly pending
@@ -227,7 +227,7 @@ ccw_device_accumulate_irb(struct ccw_device *cdev, struct irb *irb)
* intermediate accumulated status to the device driver.
*/
if (irb->scsw.cmd.fctl & SCSW_FCTL_CLEAR_FUNC)
- memset(&cdev->private->irb, 0, sizeof(struct irb));
+ memset(&cdev->private->dma_area->irb, 0, sizeof(struct irb));
/* Copy bits which are valid only for the start function. */
if (irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC) {
@@ -329,9 +329,9 @@ ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb)
/*
* We have ending status but no sense information. Do a basic sense.
*/
- sense_ccw = &to_io_private(sch)->sense_ccw;
+ sense_ccw = &to_io_private(sch)->dma_area->sense_ccw;
sense_ccw->cmd_code = CCW_CMD_BASIC_SENSE;
- sense_ccw->cda = (__u32) __pa(cdev->private->irb.ecw);
+ sense_ccw->cda = (__u32) __pa(cdev->private->dma_area->irb.ecw);
sense_ccw->count = SENSE_MAX_COUNT;
sense_ccw->flags = CCW_FLAG_SLI;
@@ -364,7 +364,7 @@ ccw_device_accumulate_basic_sense(struct ccw_device *cdev, struct irb *irb)
if (!(irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) &&
(irb->scsw.cmd.dstat & DEV_STAT_CHN_END)) {
- cdev->private->irb.esw.esw0.erw.cons = 1;
+ cdev->private->dma_area->irb.esw.esw0.erw.cons = 1;
cdev->private->flags.dosense = 0;
}
/* Check if path verification is required. */
@@ -386,7 +386,7 @@ ccw_device_accumulate_and_sense(struct ccw_device *cdev, struct irb *irb)
/* Check for basic sense. */
if (cdev->private->flags.dosense &&
!(irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK)) {
- cdev->private->irb.esw.esw0.erw.cons = 1;
+ cdev->private->dma_area->irb.esw.esw0.erw.cons = 1;
cdev->private->flags.dosense = 0;
return 0;
}
diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h
index 90e4e3a7841b..c03b4a19974e 100644
--- a/drivers/s390/cio/io_sch.h
+++ b/drivers/s390/cio/io_sch.h
@@ -9,15 +9,20 @@
#include "css.h"
#include "orb.h"
+struct io_subchannel_dma_area {
+ struct ccw1 sense_ccw; /* static ccw for sense command */
+};
+
struct io_subchannel_private {
union orb orb; /* operation request block */
- struct ccw1 sense_ccw; /* static ccw for sense command */
struct ccw_device *cdev;/* pointer to the child ccw device */
struct {
unsigned int suspend:1; /* allow suspend */
unsigned int prefetch:1;/* deny prefetch */
unsigned int inter:1; /* suppress intermediate interrupts */
} __packed options;
+ struct io_subchannel_dma_area *dma_area;
+ dma_addr_t dma_area_dma;
} __aligned(8);
#define to_io_private(n) ((struct io_subchannel_private *) \
@@ -115,6 +120,13 @@ enum cdev_todo {
#define FAKE_CMD_IRB 1
#define FAKE_TM_IRB 2
+struct ccw_device_dma_area {
+ struct senseid senseid; /* SenseID info */
+ struct ccw1 iccws[2]; /* ccws for SNID/SID/SPGID commands */
+ struct irb irb; /* device status */
+ struct pgid pgid[8]; /* path group IDs per chpid*/
+};
+
struct ccw_device_private {
struct ccw_device *cdev;
struct subchannel *sch;
@@ -156,11 +168,7 @@ struct ccw_device_private {
} __attribute__((packed)) flags;
unsigned long intparm; /* user interruption parameter */
struct qdio_irq *qdio_data;
- struct irb irb; /* device status */
int async_kill_io_rc;
- struct senseid senseid; /* SenseID info */
- struct pgid pgid[8]; /* path group IDs per chpid*/
- struct ccw1 iccws[2]; /* ccws for SNID/SID/SPGID commands */
struct work_struct todo_work;
enum cdev_todo todo;
wait_queue_head_t wait_q;
@@ -169,6 +177,8 @@ struct ccw_device_private {
struct list_head cmb_list; /* list of measured devices */
u64 cmb_start_time; /* clock value of cmb reset */
void *cmb_wait; /* deferred cmb enable/disable */
+ struct gen_pool *dma_pool;
+ struct ccw_device_dma_area *dma_area;
enum interruption_class int_class;
};
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index 7b7620de2acd..730c4e68094b 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -736,6 +736,7 @@ static int get_outbound_buffer_frontier(struct qdio_q *q, unsigned int start)
switch (state) {
case SLSB_P_OUTPUT_EMPTY:
+ case SLSB_P_OUTPUT_PENDING:
/* the adapter got it */
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr,
"out empty:%1d %02x", q->nr, count);
diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c
index 99d7d2566a3a..d4101cecdc8d 100644
--- a/drivers/s390/cio/qdio_setup.c
+++ b/drivers/s390/cio/qdio_setup.c
@@ -150,6 +150,7 @@ static int __qdio_allocate_qs(struct qdio_q **irq_ptr_qs, int nr_queues)
return -ENOMEM;
}
irq_ptr_qs[i] = q;
+ INIT_LIST_HEAD(&q->entry);
}
return 0;
}
@@ -178,6 +179,7 @@ static void setup_queues_misc(struct qdio_q *q, struct qdio_irq *irq_ptr,
q->mask = 1 << (31 - i);
q->nr = i;
q->handler = handler;
+ INIT_LIST_HEAD(&q->entry);
}
static void setup_storage_lists(struct qdio_q *q, struct qdio_irq *irq_ptr,
diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c
index 28d59ac2204c..93ee067c10ca 100644
--- a/drivers/s390/cio/qdio_thinint.c
+++ b/drivers/s390/cio/qdio_thinint.c
@@ -79,7 +79,6 @@ void tiqdio_add_input_queues(struct qdio_irq *irq_ptr)
mutex_lock(&tiq_list_lock);
list_add_rcu(&irq_ptr->input_qs[0]->entry, &tiq_list);
mutex_unlock(&tiq_list_lock);
- xchg(irq_ptr->dsci, 1 << 7);
}
void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr)
@@ -87,14 +86,14 @@ void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr)
struct qdio_q *q;
q = irq_ptr->input_qs[0];
- /* if establish triggered an error */
- if (!q || !q->entry.prev || !q->entry.next)
+ if (!q)
return;
mutex_lock(&tiq_list_lock);
list_del_rcu(&q->entry);
mutex_unlock(&tiq_list_lock);
synchronize_rcu();
+ INIT_LIST_HEAD(&q->entry);
}
static inline int has_multiple_inq_on_dsci(struct qdio_irq *irq_ptr)
@@ -178,6 +177,7 @@ static inline void tiqdio_call_inq_handlers(struct qdio_irq *irq)
/**
* tiqdio_thinint_handler - thin interrupt handler for qdio
* @airq: pointer to adapter interrupt descriptor
+ * @floating: flag to recognize floating vs. directed interrupts (unused)
*/
static void tiqdio_thinint_handler(struct airq_struct *airq, bool floating)
{
diff --git a/drivers/s390/cio/scm.c b/drivers/s390/cio/scm.c
index 6bca1d5455d4..9f26d4310bb3 100644
--- a/drivers/s390/cio/scm.c
+++ b/drivers/s390/cio/scm.c
@@ -174,10 +174,10 @@ out:
kobject_uevent(&scmdev->dev.kobj, KOBJ_CHANGE);
}
-static int check_address(struct device *dev, void *data)
+static int check_address(struct device *dev, const void *data)
{
struct scm_device *scmdev = to_scm_dev(dev);
- struct sale *sale = data;
+ const struct sale *sale = data;
return scmdev->address == sale->sa;
}
diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c
index 0e79799e9a71..1d4c893ead23 100644
--- a/drivers/s390/cio/vfio_ccw_cp.c
+++ b/drivers/s390/cio/vfio_ccw_cp.c
@@ -16,12 +16,6 @@
#include "vfio_ccw_cp.h"
-/*
- * Max length for ccw chain.
- * XXX: Limit to 256, need to check more?
- */
-#define CCWCHAIN_LEN_MAX 256
-
struct pfn_array {
/* Starting guest physical I/O address. */
unsigned long pa_iova;
@@ -33,11 +27,6 @@ struct pfn_array {
int pa_nr;
};
-struct pfn_array_table {
- struct pfn_array *pat_pa;
- int pat_nr;
-};
-
struct ccwchain {
struct list_head next;
struct ccw1 *ch_ccw;
@@ -46,35 +35,29 @@ struct ccwchain {
/* Count of the valid ccws in chain. */
int ch_len;
/* Pinned PAGEs for the original data. */
- struct pfn_array_table *ch_pat;
+ struct pfn_array *ch_pa;
};
/*
- * pfn_array_alloc_pin() - alloc memory for PFNs, then pin user pages in memory
+ * pfn_array_alloc() - alloc memory for PFNs
* @pa: pfn_array on which to perform the operation
- * @mdev: the mediated device to perform pin/unpin operations
* @iova: target guest physical address
* @len: number of bytes that should be pinned from @iova
*
- * Attempt to allocate memory for PFNs, and pin user pages in memory.
+ * Attempt to allocate memory for PFNs.
*
* Usage of pfn_array:
* We expect (pa_nr == 0) and (pa_iova_pfn == NULL), any field in
* this structure will be filled in by this function.
*
* Returns:
- * Number of pages pinned on success.
- * If @pa->pa_nr is not 0, or @pa->pa_iova_pfn is not NULL initially,
- * returns -EINVAL.
- * If no pages were pinned, returns -errno.
+ * 0 if PFNs are allocated
+ * -EINVAL if pa->pa_nr is not initially zero, or pa->pa_iova_pfn is not NULL
+ * -ENOMEM if alloc failed
*/
-static int pfn_array_alloc_pin(struct pfn_array *pa, struct device *mdev,
- u64 iova, unsigned int len)
+static int pfn_array_alloc(struct pfn_array *pa, u64 iova, unsigned int len)
{
- int i, ret = 0;
-
- if (!len)
- return 0;
+ int i;
if (pa->pa_nr || pa->pa_iova_pfn)
return -EINVAL;
@@ -94,8 +77,27 @@ static int pfn_array_alloc_pin(struct pfn_array *pa, struct device *mdev,
pa->pa_pfn = pa->pa_iova_pfn + pa->pa_nr;
pa->pa_iova_pfn[0] = pa->pa_iova >> PAGE_SHIFT;
- for (i = 1; i < pa->pa_nr; i++)
+ pa->pa_pfn[0] = -1ULL;
+ for (i = 1; i < pa->pa_nr; i++) {
pa->pa_iova_pfn[i] = pa->pa_iova_pfn[i - 1] + 1;
+ pa->pa_pfn[i] = -1ULL;
+ }
+
+ return 0;
+}
+
+/*
+ * pfn_array_pin() - Pin user pages in memory
+ * @pa: pfn_array on which to perform the operation
+ * @mdev: the mediated device to perform pin operations
+ *
+ * Returns number of pages pinned upon success.
+ * If the pin request partially succeeds, or fails completely,
+ * all pages are left unpinned and a negative error value is returned.
+ */
+static int pfn_array_pin(struct pfn_array *pa, struct device *mdev)
+{
+ int ret = 0;
ret = vfio_pin_pages(mdev, pa->pa_iova_pfn, pa->pa_nr,
IOMMU_READ | IOMMU_WRITE, pa->pa_pfn);
@@ -112,8 +114,6 @@ static int pfn_array_alloc_pin(struct pfn_array *pa, struct device *mdev,
err_out:
pa->pa_nr = 0;
- kfree(pa->pa_iova_pfn);
- pa->pa_iova_pfn = NULL;
return ret;
}
@@ -121,60 +121,30 @@ err_out:
/* Unpin the pages before releasing the memory. */
static void pfn_array_unpin_free(struct pfn_array *pa, struct device *mdev)
{
- vfio_unpin_pages(mdev, pa->pa_iova_pfn, pa->pa_nr);
+ /* Only unpin if any pages were pinned to begin with */
+ if (pa->pa_nr)
+ vfio_unpin_pages(mdev, pa->pa_iova_pfn, pa->pa_nr);
pa->pa_nr = 0;
kfree(pa->pa_iova_pfn);
}
-static int pfn_array_table_init(struct pfn_array_table *pat, int nr)
-{
- pat->pat_pa = kcalloc(nr, sizeof(*pat->pat_pa), GFP_KERNEL);
- if (unlikely(ZERO_OR_NULL_PTR(pat->pat_pa))) {
- pat->pat_nr = 0;
- return -ENOMEM;
- }
-
- pat->pat_nr = nr;
-
- return 0;
-}
-
-static void pfn_array_table_unpin_free(struct pfn_array_table *pat,
- struct device *mdev)
+static bool pfn_array_iova_pinned(struct pfn_array *pa, unsigned long iova)
{
- int i;
-
- for (i = 0; i < pat->pat_nr; i++)
- pfn_array_unpin_free(pat->pat_pa + i, mdev);
-
- if (pat->pat_nr) {
- kfree(pat->pat_pa);
- pat->pat_pa = NULL;
- pat->pat_nr = 0;
- }
-}
-
-static bool pfn_array_table_iova_pinned(struct pfn_array_table *pat,
- unsigned long iova)
-{
- struct pfn_array *pa = pat->pat_pa;
unsigned long iova_pfn = iova >> PAGE_SHIFT;
- int i, j;
+ int i;
- for (i = 0; i < pat->pat_nr; i++, pa++)
- for (j = 0; j < pa->pa_nr; j++)
- if (pa->pa_iova_pfn[j] == iova_pfn)
- return true;
+ for (i = 0; i < pa->pa_nr; i++)
+ if (pa->pa_iova_pfn[i] == iova_pfn)
+ return true;
return false;
}
-/* Create the list idal words for a pfn_array_table. */
-static inline void pfn_array_table_idal_create_words(
- struct pfn_array_table *pat,
+/* Create the list of IDAL words for a pfn_array. */
+static inline void pfn_array_idal_create_words(
+ struct pfn_array *pa,
unsigned long *idaws)
{
- struct pfn_array *pa;
- int i, j, k;
+ int i;
/*
* Idal words (execept the first one) rely on the memory being 4k
@@ -183,19 +153,36 @@ static inline void pfn_array_table_idal_create_words(
* there will be no problem here to simply use the phys to create an
* idaw.
*/
- k = 0;
- for (i = 0; i < pat->pat_nr; i++) {
- pa = pat->pat_pa + i;
- for (j = 0; j < pa->pa_nr; j++) {
- idaws[k] = pa->pa_pfn[j] << PAGE_SHIFT;
- if (k == 0)
- idaws[k] += pa->pa_iova & (PAGE_SIZE - 1);
- k++;
+
+ for (i = 0; i < pa->pa_nr; i++)
+ idaws[i] = pa->pa_pfn[i] << PAGE_SHIFT;
+
+ /* Adjust the first IDAW, since it may not start on a page boundary */
+ idaws[0] += pa->pa_iova & (PAGE_SIZE - 1);
+}
+
+static void convert_ccw0_to_ccw1(struct ccw1 *source, unsigned long len)
+{
+ struct ccw0 ccw0;
+ struct ccw1 *pccw1 = source;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ ccw0 = *(struct ccw0 *)pccw1;
+ if ((pccw1->cmd_code & 0x0f) == CCW_CMD_TIC) {
+ pccw1->cmd_code = CCW_CMD_TIC;
+ pccw1->flags = 0;
+ pccw1->count = 0;
+ } else {
+ pccw1->cmd_code = ccw0.cmd_code;
+ pccw1->flags = ccw0.flags;
+ pccw1->count = ccw0.count;
}
+ pccw1->cda = ccw0.cda;
+ pccw1++;
}
}
-
/*
* Within the domain (@mdev), copy @n bytes from a guest physical
* address (@iova) to a host physical address (@to).
@@ -209,9 +196,15 @@ static long copy_from_iova(struct device *mdev,
int i, ret;
unsigned long l, m;
- ret = pfn_array_alloc_pin(&pa, mdev, iova, n);
- if (ret <= 0)
+ ret = pfn_array_alloc(&pa, iova, n);
+ if (ret < 0)
+ return ret;
+
+ ret = pfn_array_pin(&pa, mdev);
+ if (ret < 0) {
+ pfn_array_unpin_free(&pa, mdev);
return ret;
+ }
l = n;
for (i = 0; i < pa.pa_nr; i++) {
@@ -235,55 +228,60 @@ static long copy_from_iova(struct device *mdev,
return l;
}
-static long copy_ccw_from_iova(struct channel_program *cp,
- struct ccw1 *to, u64 iova,
- unsigned long len)
-{
- struct ccw0 ccw0;
- struct ccw1 *pccw1;
- int ret;
- int i;
-
- ret = copy_from_iova(cp->mdev, to, iova, len * sizeof(struct ccw1));
- if (ret)
- return ret;
-
- if (!cp->orb.cmd.fmt) {
- pccw1 = to;
- for (i = 0; i < len; i++) {
- ccw0 = *(struct ccw0 *)pccw1;
- if ((pccw1->cmd_code & 0x0f) == CCW_CMD_TIC) {
- pccw1->cmd_code = CCW_CMD_TIC;
- pccw1->flags = 0;
- pccw1->count = 0;
- } else {
- pccw1->cmd_code = ccw0.cmd_code;
- pccw1->flags = ccw0.flags;
- pccw1->count = ccw0.count;
- }
- pccw1->cda = ccw0.cda;
- pccw1++;
- }
- }
-
- return ret;
-}
-
/*
* Helpers to operate ccwchain.
*/
-#define ccw_is_test(_ccw) (((_ccw)->cmd_code & 0x0F) == 0)
+#define ccw_is_read(_ccw) (((_ccw)->cmd_code & 0x03) == 0x02)
+#define ccw_is_read_backward(_ccw) (((_ccw)->cmd_code & 0x0F) == 0x0C)
+#define ccw_is_sense(_ccw) (((_ccw)->cmd_code & 0x0F) == CCW_CMD_BASIC_SENSE)
#define ccw_is_noop(_ccw) ((_ccw)->cmd_code == CCW_CMD_NOOP)
#define ccw_is_tic(_ccw) ((_ccw)->cmd_code == CCW_CMD_TIC)
#define ccw_is_idal(_ccw) ((_ccw)->flags & CCW_FLAG_IDA)
-
+#define ccw_is_skip(_ccw) ((_ccw)->flags & CCW_FLAG_SKIP)
#define ccw_is_chain(_ccw) ((_ccw)->flags & (CCW_FLAG_CC | CCW_FLAG_DC))
/*
+ * ccw_does_data_transfer()
+ *
+ * Determine whether a CCW will move any data, such that the guest pages
+ * would need to be pinned before performing the I/O.
+ *
+ * Returns 1 if yes, 0 if no.
+ */
+static inline int ccw_does_data_transfer(struct ccw1 *ccw)
+{
+ /* If the count field is zero, then no data will be transferred */
+ if (ccw->count == 0)
+ return 0;
+
+ /* If the command is a NOP, then no data will be transferred */
+ if (ccw_is_noop(ccw))
+ return 0;
+
+ /* If the skip flag is off, then data will be transferred */
+ if (!ccw_is_skip(ccw))
+ return 1;
+
+ /*
+ * If the skip flag is on, it is only meaningful if the command
+ * code is a read, read backward, sense, or sense ID. In those
+ * cases, no data will be transferred.
+ */
+ if (ccw_is_read(ccw) || ccw_is_read_backward(ccw))
+ return 0;
+
+ if (ccw_is_sense(ccw))
+ return 0;
+
+ /* The skip flag is on, but it is ignored for this command code. */
+ return 1;
+}
+
+/*
* is_cpa_within_range()
*
* @cpa: channel program address being questioned
@@ -319,7 +317,7 @@ static struct ccwchain *ccwchain_alloc(struct channel_program *cp, int len)
/* Make ccw address aligned to 8. */
size = ((sizeof(*chain) + 7L) & -8L) +
sizeof(*chain->ch_ccw) * len +
- sizeof(*chain->ch_pat) * len;
+ sizeof(*chain->ch_pa) * len;
chain = kzalloc(size, GFP_DMA | GFP_KERNEL);
if (!chain)
return NULL;
@@ -328,7 +326,7 @@ static struct ccwchain *ccwchain_alloc(struct channel_program *cp, int len)
chain->ch_ccw = (struct ccw1 *)data;
data = (u8 *)(chain->ch_ccw) + sizeof(*chain->ch_ccw) * len;
- chain->ch_pat = (struct pfn_array_table *)data;
+ chain->ch_pa = (struct pfn_array *)data;
chain->ch_len = len;
@@ -348,31 +346,12 @@ static void ccwchain_cda_free(struct ccwchain *chain, int idx)
{
struct ccw1 *ccw = chain->ch_ccw + idx;
- if (ccw_is_test(ccw) || ccw_is_noop(ccw) || ccw_is_tic(ccw))
- return;
- if (!ccw->count)
+ if (ccw_is_tic(ccw))
return;
kfree((void *)(u64)ccw->cda);
}
-/* Unpin the pages then free the memory resources. */
-static void cp_unpin_free(struct channel_program *cp)
-{
- struct ccwchain *chain, *temp;
- int i;
-
- cp->initialized = false;
- list_for_each_entry_safe(chain, temp, &cp->ccwchain_list, next) {
- for (i = 0; i < chain->ch_len; i++) {
- pfn_array_table_unpin_free(chain->ch_pat + i,
- cp->mdev);
- ccwchain_cda_free(chain, i);
- }
- ccwchain_free(chain);
- }
-}
-
/**
* ccwchain_calc_length - calculate the length of the ccw chain.
* @iova: guest physical address of the target ccw chain
@@ -388,25 +367,9 @@ static void cp_unpin_free(struct channel_program *cp)
*/
static int ccwchain_calc_length(u64 iova, struct channel_program *cp)
{
- struct ccw1 *ccw, *p;
- int cnt;
-
- /*
- * Copy current chain from guest to host kernel.
- * Currently the chain length is limited to CCWCHAIN_LEN_MAX (256).
- * So copying 2K is enough (safe).
- */
- p = ccw = kcalloc(CCWCHAIN_LEN_MAX, sizeof(*ccw), GFP_KERNEL);
- if (!ccw)
- return -ENOMEM;
-
- cnt = copy_ccw_from_iova(cp, ccw, iova, CCWCHAIN_LEN_MAX);
- if (cnt) {
- kfree(ccw);
- return cnt;
- }
+ struct ccw1 *ccw = cp->guest_cp;
+ int cnt = 0;
- cnt = 0;
do {
cnt++;
@@ -415,10 +378,8 @@ static int ccwchain_calc_length(u64 iova, struct channel_program *cp)
* orb specified one of the unsupported formats, we defer
* checking for IDAWs in unsupported formats to here.
*/
- if ((!cp->orb.cmd.c64 || cp->orb.cmd.i2k) && ccw_is_idal(ccw)) {
- kfree(p);
+ if ((!cp->orb.cmd.c64 || cp->orb.cmd.i2k) && ccw_is_idal(ccw))
return -EOPNOTSUPP;
- }
/*
* We want to keep counting if the current CCW has the
@@ -437,7 +398,6 @@ static int ccwchain_calc_length(u64 iova, struct channel_program *cp)
if (cnt == CCWCHAIN_LEN_MAX + 1)
cnt = -EINVAL;
- kfree(p);
return cnt;
}
@@ -458,17 +418,23 @@ static int tic_target_chain_exists(struct ccw1 *tic, struct channel_program *cp)
static int ccwchain_loop_tic(struct ccwchain *chain,
struct channel_program *cp);
-static int ccwchain_handle_tic(struct ccw1 *tic, struct channel_program *cp)
+static int ccwchain_handle_ccw(u32 cda, struct channel_program *cp)
{
struct ccwchain *chain;
- int len, ret;
+ int len;
- /* May transfer to an existing chain. */
- if (tic_target_chain_exists(tic, cp))
- return 0;
+ /* Copy 2K (the most we support today) of possible CCWs */
+ len = copy_from_iova(cp->mdev, cp->guest_cp, cda,
+ CCWCHAIN_LEN_MAX * sizeof(struct ccw1));
+ if (len)
+ return len;
- /* Get chain length. */
- len = ccwchain_calc_length(tic->cda, cp);
+ /* Convert any Format-0 CCWs to Format-1 */
+ if (!cp->orb.cmd.fmt)
+ convert_ccw0_to_ccw1(cp->guest_cp, CCWCHAIN_LEN_MAX);
+
+ /* Count the CCWs in the current chain */
+ len = ccwchain_calc_length(cda, cp);
if (len < 0)
return len;
@@ -476,14 +442,10 @@ static int ccwchain_handle_tic(struct ccw1 *tic, struct channel_program *cp)
chain = ccwchain_alloc(cp, len);
if (!chain)
return -ENOMEM;
- chain->ch_iova = tic->cda;
+ chain->ch_iova = cda;
- /* Copy the new chain from user. */
- ret = copy_ccw_from_iova(cp, chain->ch_ccw, tic->cda, len);
- if (ret) {
- ccwchain_free(chain);
- return ret;
- }
+ /* Copy the actual CCWs into the new chain */
+ memcpy(chain->ch_ccw, cp->guest_cp, len * sizeof(struct ccw1));
/* Loop for tics on this new chain. */
return ccwchain_loop_tic(chain, cp);
@@ -501,7 +463,12 @@ static int ccwchain_loop_tic(struct ccwchain *chain, struct channel_program *cp)
if (!ccw_is_tic(tic))
continue;
- ret = ccwchain_handle_tic(tic, cp);
+ /* May transfer to an existing chain. */
+ if (tic_target_chain_exists(tic, cp))
+ continue;
+
+ /* Build a ccwchain for the next segment */
+ ret = ccwchain_handle_ccw(tic->cda, cp);
if (ret)
return ret;
}
@@ -534,115 +501,90 @@ static int ccwchain_fetch_direct(struct ccwchain *chain,
struct channel_program *cp)
{
struct ccw1 *ccw;
- struct pfn_array_table *pat;
+ struct pfn_array *pa;
+ u64 iova;
unsigned long *idaws;
int ret;
+ int bytes = 1;
+ int idaw_nr, idal_len;
+ int i;
ccw = chain->ch_ccw + idx;
- if (!ccw->count) {
- /*
- * We just want the translation result of any direct ccw
- * to be an IDA ccw, so let's add the IDA flag for it.
- * Although the flag will be ignored by firmware.
- */
- ccw->flags |= CCW_FLAG_IDA;
- return 0;
- }
-
- /*
- * Pin data page(s) in memory.
- * The number of pages actually is the count of the idaws which will be
- * needed when translating a direct ccw to a idal ccw.
- */
- pat = chain->ch_pat + idx;
- ret = pfn_array_table_init(pat, 1);
- if (ret)
- goto out_init;
-
- ret = pfn_array_alloc_pin(pat->pat_pa, cp->mdev, ccw->cda, ccw->count);
- if (ret < 0)
- goto out_unpin;
+ if (ccw->count)
+ bytes = ccw->count;
- /* Translate this direct ccw to a idal ccw. */
- idaws = kcalloc(ret, sizeof(*idaws), GFP_DMA | GFP_KERNEL);
- if (!idaws) {
- ret = -ENOMEM;
- goto out_unpin;
+ /* Calculate size of IDAL */
+ if (ccw_is_idal(ccw)) {
+ /* Read first IDAW to see if it's 4K-aligned or not. */
+ /* All subsequent IDAws will be 4K-aligned. */
+ ret = copy_from_iova(cp->mdev, &iova, ccw->cda, sizeof(iova));
+ if (ret)
+ return ret;
+ } else {
+ iova = ccw->cda;
}
- ccw->cda = (__u32) virt_to_phys(idaws);
- ccw->flags |= CCW_FLAG_IDA;
-
- pfn_array_table_idal_create_words(pat, idaws);
-
- return 0;
-
-out_unpin:
- pfn_array_table_unpin_free(pat, cp->mdev);
-out_init:
- ccw->cda = 0;
- return ret;
-}
-
-static int ccwchain_fetch_idal(struct ccwchain *chain,
- int idx,
- struct channel_program *cp)
-{
- struct ccw1 *ccw;
- struct pfn_array_table *pat;
- unsigned long *idaws;
- u64 idaw_iova;
- unsigned int idaw_nr, idaw_len;
- int i, ret;
-
- ccw = chain->ch_ccw + idx;
-
- if (!ccw->count)
- return 0;
-
- /* Calculate size of idaws. */
- ret = copy_from_iova(cp->mdev, &idaw_iova, ccw->cda, sizeof(idaw_iova));
- if (ret)
- return ret;
- idaw_nr = idal_nr_words((void *)(idaw_iova), ccw->count);
- idaw_len = idaw_nr * sizeof(*idaws);
-
- /* Pin data page(s) in memory. */
- pat = chain->ch_pat + idx;
- ret = pfn_array_table_init(pat, idaw_nr);
- if (ret)
- goto out_init;
+ idaw_nr = idal_nr_words((void *)iova, bytes);
+ idal_len = idaw_nr * sizeof(*idaws);
- /* Translate idal ccw to use new allocated idaws. */
- idaws = kzalloc(idaw_len, GFP_DMA | GFP_KERNEL);
+ /* Allocate an IDAL from host storage */
+ idaws = kcalloc(idaw_nr, sizeof(*idaws), GFP_DMA | GFP_KERNEL);
if (!idaws) {
ret = -ENOMEM;
- goto out_unpin;
+ goto out_init;
}
- ret = copy_from_iova(cp->mdev, idaws, ccw->cda, idaw_len);
- if (ret)
+ /*
+ * Allocate an array of pfn's for pages to pin/translate.
+ * The number of pages is actually the count of the idaws
+ * required for the data transfer, since we only only support
+ * 4K IDAWs today.
+ */
+ pa = chain->ch_pa + idx;
+ ret = pfn_array_alloc(pa, iova, bytes);
+ if (ret < 0)
goto out_free_idaws;
- ccw->cda = virt_to_phys(idaws);
+ if (ccw_is_idal(ccw)) {
+ /* Copy guest IDAL into host IDAL */
+ ret = copy_from_iova(cp->mdev, idaws, ccw->cda, idal_len);
+ if (ret)
+ goto out_unpin;
- for (i = 0; i < idaw_nr; i++) {
- idaw_iova = *(idaws + i);
+ /*
+ * Copy guest IDAWs into pfn_array, in case the memory they
+ * occupy is not contiguous.
+ */
+ for (i = 0; i < idaw_nr; i++)
+ pa->pa_iova_pfn[i] = idaws[i] >> PAGE_SHIFT;
+ } else {
+ /*
+ * No action is required here; the iova addresses in pfn_array
+ * were initialized sequentially in pfn_array_alloc() beginning
+ * with the contents of ccw->cda.
+ */
+ }
- ret = pfn_array_alloc_pin(pat->pat_pa + i, cp->mdev,
- idaw_iova, 1);
+ if (ccw_does_data_transfer(ccw)) {
+ ret = pfn_array_pin(pa, cp->mdev);
if (ret < 0)
- goto out_free_idaws;
+ goto out_unpin;
+ } else {
+ pa->pa_nr = 0;
}
- pfn_array_table_idal_create_words(pat, idaws);
+ ccw->cda = (__u32) virt_to_phys(idaws);
+ ccw->flags |= CCW_FLAG_IDA;
+
+ /* Populate the IDAL with pinned/translated addresses from pfn */
+ pfn_array_idal_create_words(pa, idaws);
return 0;
+out_unpin:
+ pfn_array_unpin_free(pa, cp->mdev);
out_free_idaws:
kfree(idaws);
-out_unpin:
- pfn_array_table_unpin_free(pat, cp->mdev);
out_init:
ccw->cda = 0;
return ret;
@@ -660,15 +602,9 @@ static int ccwchain_fetch_one(struct ccwchain *chain,
{
struct ccw1 *ccw = chain->ch_ccw + idx;
- if (ccw_is_test(ccw) || ccw_is_noop(ccw))
- return 0;
-
if (ccw_is_tic(ccw))
return ccwchain_fetch_tic(chain, idx, cp);
- if (ccw_is_idal(ccw))
- return ccwchain_fetch_idal(chain, idx, cp);
-
return ccwchain_fetch_direct(chain, idx, cp);
}
@@ -691,9 +627,7 @@ static int ccwchain_fetch_one(struct ccwchain *chain,
*/
int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb)
{
- u64 iova = orb->cmd.cpa;
- struct ccwchain *chain;
- int len, ret;
+ int ret;
/*
* XXX:
@@ -706,28 +640,11 @@ int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb)
memcpy(&cp->orb, orb, sizeof(*orb));
cp->mdev = mdev;
- /* Get chain length. */
- len = ccwchain_calc_length(iova, cp);
- if (len < 0)
- return len;
-
- /* Alloc mem for the head chain. */
- chain = ccwchain_alloc(cp, len);
- if (!chain)
- return -ENOMEM;
- chain->ch_iova = iova;
-
- /* Copy the head chain from guest. */
- ret = copy_ccw_from_iova(cp, chain->ch_ccw, iova, len);
- if (ret) {
- ccwchain_free(chain);
- return ret;
- }
-
- /* Now loop for its TICs. */
- ret = ccwchain_loop_tic(chain, cp);
+ /* Build a ccwchain for the first CCW segment */
+ ret = ccwchain_handle_ccw(orb->cmd.cpa, cp);
if (ret)
- cp_unpin_free(cp);
+ cp_free(cp);
+
/* It is safe to force: if not set but idals used
* ccwchain_calc_length returns an error.
*/
@@ -750,8 +667,20 @@ int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb)
*/
void cp_free(struct channel_program *cp)
{
- if (cp->initialized)
- cp_unpin_free(cp);
+ struct ccwchain *chain, *temp;
+ int i;
+
+ if (!cp->initialized)
+ return;
+
+ cp->initialized = false;
+ list_for_each_entry_safe(chain, temp, &cp->ccwchain_list, next) {
+ for (i = 0; i < chain->ch_len; i++) {
+ pfn_array_unpin_free(chain->ch_pa + i, cp->mdev);
+ ccwchain_cda_free(chain, i);
+ }
+ ccwchain_free(chain);
+ }
}
/**
@@ -886,7 +815,11 @@ void cp_update_scsw(struct channel_program *cp, union scsw *scsw)
*/
list_for_each_entry(chain, &cp->ccwchain_list, next) {
ccw_head = (u32)(u64)chain->ch_ccw;
- if (is_cpa_within_range(cpa, ccw_head, chain->ch_len)) {
+ /*
+ * On successful execution, cpa points just beyond the end
+ * of the chain.
+ */
+ if (is_cpa_within_range(cpa, ccw_head, chain->ch_len + 1)) {
/*
* (cpa - ccw_head) is the offset value of the host
* physical ccw to its chain head.
@@ -919,8 +852,7 @@ bool cp_iova_pinned(struct channel_program *cp, u64 iova)
list_for_each_entry(chain, &cp->ccwchain_list, next) {
for (i = 0; i < chain->ch_len; i++)
- if (pfn_array_table_iova_pinned(chain->ch_pat + i,
- iova))
+ if (pfn_array_iova_pinned(chain->ch_pa + i, iova))
return true;
}
diff --git a/drivers/s390/cio/vfio_ccw_cp.h b/drivers/s390/cio/vfio_ccw_cp.h
index 3c20cd208da5..7cdc38049033 100644
--- a/drivers/s390/cio/vfio_ccw_cp.h
+++ b/drivers/s390/cio/vfio_ccw_cp.h
@@ -16,6 +16,12 @@
#include "orb.h"
+/*
+ * Max length for ccw chain.
+ * XXX: Limit to 256, need to check more?
+ */
+#define CCWCHAIN_LEN_MAX 256
+
/**
* struct channel_program - manage information for channel program
* @ccwchain_list: list head of ccwchains
@@ -32,6 +38,7 @@ struct channel_program {
union orb orb;
struct device *mdev;
bool initialized;
+ struct ccw1 *guest_cp;
};
extern int cp_init(struct channel_program *cp, struct device *mdev,
diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c
index ee8767f5845a..2b90a5ecaeb9 100644
--- a/drivers/s390/cio/vfio_ccw_drv.c
+++ b/drivers/s390/cio/vfio_ccw_drv.c
@@ -95,11 +95,11 @@ static void vfio_ccw_sch_io_todo(struct work_struct *work)
memcpy(private->io_region->irb_area, irb, sizeof(*irb));
mutex_unlock(&private->io_mutex);
- if (private->io_trigger)
- eventfd_signal(private->io_trigger, 1);
-
if (private->mdev && is_final)
private->state = VFIO_CCW_STATE_IDLE;
+
+ if (private->io_trigger)
+ eventfd_signal(private->io_trigger, 1);
}
/*
@@ -129,6 +129,11 @@ static int vfio_ccw_sch_probe(struct subchannel *sch)
if (!private)
return -ENOMEM;
+ private->cp.guest_cp = kcalloc(CCWCHAIN_LEN_MAX, sizeof(struct ccw1),
+ GFP_KERNEL);
+ if (!private->cp.guest_cp)
+ goto out_free;
+
private->io_region = kmem_cache_zalloc(vfio_ccw_io_region,
GFP_KERNEL | GFP_DMA);
if (!private->io_region)
@@ -169,6 +174,7 @@ out_free:
kmem_cache_free(vfio_ccw_cmd_region, private->cmd_region);
if (private->io_region)
kmem_cache_free(vfio_ccw_io_region, private->io_region);
+ kfree(private->cp.guest_cp);
kfree(private);
return ret;
}
@@ -185,6 +191,7 @@ static int vfio_ccw_sch_remove(struct subchannel *sch)
kmem_cache_free(vfio_ccw_cmd_region, private->cmd_region);
kmem_cache_free(vfio_ccw_io_region, private->io_region);
+ kfree(private->cp.guest_cp);
kfree(private);
return 0;
@@ -299,6 +306,7 @@ static void __exit vfio_ccw_sch_exit(void)
css_driver_unregister(&vfio_ccw_sch_driver);
isc_unregister(VFIO_CCW_ISC);
kmem_cache_destroy(vfio_ccw_io_region);
+ kmem_cache_destroy(vfio_ccw_cmd_region);
destroy_workqueue(vfio_ccw_work_q);
}
module_init(vfio_ccw_sch_init);
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index b9fc502c58c2..a76b8a8bcbbb 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -208,7 +208,6 @@ static inline int ap_query_configuration(struct ap_config_info *info)
return -EINVAL;
return ap_qci(info);
}
-EXPORT_SYMBOL(ap_query_configuration);
/**
* ap_init_configuration(): Allocate and query configuration array.
@@ -1356,16 +1355,16 @@ static int ap_get_compatible_type(ap_qid_t qid, int rawtype, unsigned int func)
* Helper function to be used with bus_find_dev
* matches for the card device with the given id
*/
-static int __match_card_device_with_id(struct device *dev, void *data)
+static int __match_card_device_with_id(struct device *dev, const void *data)
{
- return is_card_dev(dev) && to_ap_card(dev)->id == (int)(long) data;
+ return is_card_dev(dev) && to_ap_card(dev)->id == (int)(long)(void *) data;
}
/*
* Helper function to be used with bus_find_dev
* matches for the queue device with a given qid
*/
-static int __match_queue_device_with_qid(struct device *dev, void *data)
+static int __match_queue_device_with_qid(struct device *dev, const void *data)
{
return is_queue_dev(dev) && to_ap_queue(dev)->qid == (int)(long) data;
}
@@ -1374,7 +1373,7 @@ static int __match_queue_device_with_qid(struct device *dev, void *data)
* Helper function to be used with bus_find_dev
* matches any queue device with given queue id
*/
-static int __match_queue_device_with_queue_id(struct device *dev, void *data)
+static int __match_queue_device_with_queue_id(struct device *dev, const void *data)
{
return is_queue_dev(dev)
&& AP_QID_QUEUE(to_ap_queue(dev)->qid) == (int)(long) data;
diff --git a/drivers/s390/crypto/pkey_api.c b/drivers/s390/crypto/pkey_api.c
index 45eb0c14b880..7f418d2d8cdf 100644
--- a/drivers/s390/crypto/pkey_api.c
+++ b/drivers/s390/crypto/pkey_api.c
@@ -690,7 +690,7 @@ int pkey_clr2protkey(u32 keytype,
*/
if (!cpacf_test_func(&pckmo_functions, fc)) {
DEBUG_ERR("%s pckmo functions not available\n", __func__);
- return -EOPNOTSUPP;
+ return -ENODEV;
}
/* prepare param block */
@@ -1695,15 +1695,15 @@ static int __init pkey_init(void)
* are able to work with protected keys.
*/
if (!cpacf_query(CPACF_PCKMO, &pckmo_functions))
- return -EOPNOTSUPP;
+ return -ENODEV;
/* check for kmc instructions available */
if (!cpacf_query(CPACF_KMC, &kmc_functions))
- return -EOPNOTSUPP;
+ return -ENODEV;
if (!cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_128) ||
!cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_192) ||
!cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_256))
- return -EOPNOTSUPP;
+ return -ENODEV;
pkey_debug_init();
diff --git a/drivers/s390/crypto/vfio_ap_drv.c b/drivers/s390/crypto/vfio_ap_drv.c
index e9824c35c34f..003662aa8060 100644
--- a/drivers/s390/crypto/vfio_ap_drv.c
+++ b/drivers/s390/crypto/vfio_ap_drv.c
@@ -5,6 +5,7 @@
* Copyright IBM Corp. 2018
*
* Author(s): Tony Krowiak <akrowiak@linux.ibm.com>
+ * Pierre Morel <pmorel@linux.ibm.com>
*/
#include <linux/module.h>
@@ -40,14 +41,45 @@ static struct ap_device_id ap_queue_ids[] = {
MODULE_DEVICE_TABLE(vfio_ap, ap_queue_ids);
+/**
+ * vfio_ap_queue_dev_probe:
+ *
+ * Allocate a vfio_ap_queue structure and associate it
+ * with the device as driver_data.
+ */
static int vfio_ap_queue_dev_probe(struct ap_device *apdev)
{
+ struct vfio_ap_queue *q;
+
+ q = kzalloc(sizeof(*q), GFP_KERNEL);
+ if (!q)
+ return -ENOMEM;
+ dev_set_drvdata(&apdev->device, q);
+ q->apqn = to_ap_queue(&apdev->device)->qid;
+ q->saved_isc = VFIO_AP_ISC_INVALID;
return 0;
}
+/**
+ * vfio_ap_queue_dev_remove:
+ *
+ * Takes the matrix lock to avoid actions on this device while removing
+ * Free the associated vfio_ap_queue structure
+ */
static void vfio_ap_queue_dev_remove(struct ap_device *apdev)
{
- /* Nothing to do yet */
+ struct vfio_ap_queue *q;
+ int apid, apqi;
+
+ mutex_lock(&matrix_dev->lock);
+ q = dev_get_drvdata(&apdev->device);
+ dev_set_drvdata(&apdev->device, NULL);
+ apid = AP_QID_CARD(q->apqn);
+ apqi = AP_QID_QUEUE(q->apqn);
+ vfio_ap_mdev_reset_queue(apid, apqi, 1);
+ vfio_ap_irq_disable(q);
+ kfree(q);
+ mutex_unlock(&matrix_dev->lock);
}
static void vfio_ap_matrix_dev_release(struct device *dev)
diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c
index 900b9cf20ca5..0604b49a4d32 100644
--- a/drivers/s390/crypto/vfio_ap_ops.c
+++ b/drivers/s390/crypto/vfio_ap_ops.c
@@ -24,6 +24,295 @@
#define VFIO_AP_MDEV_TYPE_HWVIRT "passthrough"
#define VFIO_AP_MDEV_NAME_HWVIRT "VFIO AP Passthrough Device"
+static int vfio_ap_mdev_reset_queues(struct mdev_device *mdev);
+
+static int match_apqn(struct device *dev, const void *data)
+{
+ struct vfio_ap_queue *q = dev_get_drvdata(dev);
+
+ return (q->apqn == *(int *)(data)) ? 1 : 0;
+}
+
+/**
+ * vfio_ap_get_queue: Retrieve a queue with a specific APQN from a list
+ * @matrix_mdev: the associated mediated matrix
+ * @apqn: The queue APQN
+ *
+ * Retrieve a queue with a specific APQN from the list of the
+ * devices of the vfio_ap_drv.
+ * Verify that the APID and the APQI are set in the matrix.
+ *
+ * Returns the pointer to the associated vfio_ap_queue
+ */
+static struct vfio_ap_queue *vfio_ap_get_queue(
+ struct ap_matrix_mdev *matrix_mdev,
+ int apqn)
+{
+ struct vfio_ap_queue *q;
+ struct device *dev;
+
+ if (!test_bit_inv(AP_QID_CARD(apqn), matrix_mdev->matrix.apm))
+ return NULL;
+ if (!test_bit_inv(AP_QID_QUEUE(apqn), matrix_mdev->matrix.aqm))
+ return NULL;
+
+ dev = driver_find_device(&matrix_dev->vfio_ap_drv->driver, NULL,
+ &apqn, match_apqn);
+ if (!dev)
+ return NULL;
+ q = dev_get_drvdata(dev);
+ q->matrix_mdev = matrix_mdev;
+ put_device(dev);
+
+ return q;
+}
+
+/**
+ * vfio_ap_wait_for_irqclear
+ * @apqn: The AP Queue number
+ *
+ * Checks the IRQ bit for the status of this APQN using ap_tapq.
+ * Returns if the ap_tapq function succeeded and the bit is clear.
+ * Returns if ap_tapq function failed with invalid, deconfigured or
+ * checkstopped AP.
+ * Otherwise retries up to 5 times after waiting 20ms.
+ *
+ */
+static void vfio_ap_wait_for_irqclear(int apqn)
+{
+ struct ap_queue_status status;
+ int retry = 5;
+
+ do {
+ status = ap_tapq(apqn, NULL);
+ switch (status.response_code) {
+ case AP_RESPONSE_NORMAL:
+ case AP_RESPONSE_RESET_IN_PROGRESS:
+ if (!status.irq_enabled)
+ return;
+ /* Fall through */
+ case AP_RESPONSE_BUSY:
+ msleep(20);
+ break;
+ case AP_RESPONSE_Q_NOT_AVAIL:
+ case AP_RESPONSE_DECONFIGURED:
+ case AP_RESPONSE_CHECKSTOPPED:
+ default:
+ WARN_ONCE(1, "%s: tapq rc %02x: %04x\n", __func__,
+ status.response_code, apqn);
+ return;
+ }
+ } while (--retry);
+
+ WARN_ONCE(1, "%s: tapq rc %02x: %04x could not clear IR bit\n",
+ __func__, status.response_code, apqn);
+}
+
+/**
+ * vfio_ap_free_aqic_resources
+ * @q: The vfio_ap_queue
+ *
+ * Unregisters the ISC in the GIB when the saved ISC not invalid.
+ * Unpin the guest's page holding the NIB when it exist.
+ * Reset the saved_pfn and saved_isc to invalid values.
+ *
+ */
+static void vfio_ap_free_aqic_resources(struct vfio_ap_queue *q)
+{
+ if (q->saved_isc != VFIO_AP_ISC_INVALID && q->matrix_mdev)
+ kvm_s390_gisc_unregister(q->matrix_mdev->kvm, q->saved_isc);
+ if (q->saved_pfn && q->matrix_mdev)
+ vfio_unpin_pages(mdev_dev(q->matrix_mdev->mdev),
+ &q->saved_pfn, 1);
+ q->saved_pfn = 0;
+ q->saved_isc = VFIO_AP_ISC_INVALID;
+}
+
+/**
+ * vfio_ap_irq_disable
+ * @q: The vfio_ap_queue
+ *
+ * Uses ap_aqic to disable the interruption and in case of success, reset
+ * in progress or IRQ disable command already proceeded: calls
+ * vfio_ap_wait_for_irqclear() to check for the IRQ bit to be clear
+ * and calls vfio_ap_free_aqic_resources() to free the resources associated
+ * with the AP interrupt handling.
+ *
+ * In the case the AP is busy, or a reset is in progress,
+ * retries after 20ms, up to 5 times.
+ *
+ * Returns if ap_aqic function failed with invalid, deconfigured or
+ * checkstopped AP.
+ */
+struct ap_queue_status vfio_ap_irq_disable(struct vfio_ap_queue *q)
+{
+ struct ap_qirq_ctrl aqic_gisa = {};
+ struct ap_queue_status status;
+ int retries = 5;
+
+ do {
+ status = ap_aqic(q->apqn, aqic_gisa, NULL);
+ switch (status.response_code) {
+ case AP_RESPONSE_OTHERWISE_CHANGED:
+ case AP_RESPONSE_NORMAL:
+ vfio_ap_wait_for_irqclear(q->apqn);
+ goto end_free;
+ case AP_RESPONSE_RESET_IN_PROGRESS:
+ case AP_RESPONSE_BUSY:
+ msleep(20);
+ break;
+ case AP_RESPONSE_Q_NOT_AVAIL:
+ case AP_RESPONSE_DECONFIGURED:
+ case AP_RESPONSE_CHECKSTOPPED:
+ case AP_RESPONSE_INVALID_ADDRESS:
+ default:
+ /* All cases in default means AP not operational */
+ WARN_ONCE(1, "%s: ap_aqic status %d\n", __func__,
+ status.response_code);
+ goto end_free;
+ }
+ } while (retries--);
+
+ WARN_ONCE(1, "%s: ap_aqic status %d\n", __func__,
+ status.response_code);
+end_free:
+ vfio_ap_free_aqic_resources(q);
+ q->matrix_mdev = NULL;
+ return status;
+}
+
+/**
+ * vfio_ap_setirq: Enable Interruption for a APQN
+ *
+ * @dev: the device associated with the ap_queue
+ * @q: the vfio_ap_queue holding AQIC parameters
+ *
+ * Pin the NIB saved in *q
+ * Register the guest ISC to GIB interface and retrieve the
+ * host ISC to issue the host side PQAP/AQIC
+ *
+ * Response.status may be set to AP_RESPONSE_INVALID_ADDRESS in case the
+ * vfio_pin_pages failed.
+ *
+ * Otherwise return the ap_queue_status returned by the ap_aqic(),
+ * all retry handling will be done by the guest.
+ */
+static struct ap_queue_status vfio_ap_irq_enable(struct vfio_ap_queue *q,
+ int isc,
+ unsigned long nib)
+{
+ struct ap_qirq_ctrl aqic_gisa = {};
+ struct ap_queue_status status = {};
+ struct kvm_s390_gisa *gisa;
+ struct kvm *kvm;
+ unsigned long h_nib, g_pfn, h_pfn;
+ int ret;
+
+ g_pfn = nib >> PAGE_SHIFT;
+ ret = vfio_pin_pages(mdev_dev(q->matrix_mdev->mdev), &g_pfn, 1,
+ IOMMU_READ | IOMMU_WRITE, &h_pfn);
+ switch (ret) {
+ case 1:
+ break;
+ default:
+ status.response_code = AP_RESPONSE_INVALID_ADDRESS;
+ return status;
+ }
+
+ kvm = q->matrix_mdev->kvm;
+ gisa = kvm->arch.gisa_int.origin;
+
+ h_nib = (h_pfn << PAGE_SHIFT) | (nib & ~PAGE_MASK);
+ aqic_gisa.gisc = isc;
+ aqic_gisa.isc = kvm_s390_gisc_register(kvm, isc);
+ aqic_gisa.ir = 1;
+ aqic_gisa.gisa = (uint64_t)gisa >> 4;
+
+ status = ap_aqic(q->apqn, aqic_gisa, (void *)h_nib);
+ switch (status.response_code) {
+ case AP_RESPONSE_NORMAL:
+ /* See if we did clear older IRQ configuration */
+ vfio_ap_free_aqic_resources(q);
+ q->saved_pfn = g_pfn;
+ q->saved_isc = isc;
+ break;
+ case AP_RESPONSE_OTHERWISE_CHANGED:
+ /* We could not modify IRQ setings: clear new configuration */
+ vfio_unpin_pages(mdev_dev(q->matrix_mdev->mdev), &g_pfn, 1);
+ kvm_s390_gisc_unregister(kvm, isc);
+ break;
+ default:
+ pr_warn("%s: apqn %04x: response: %02x\n", __func__, q->apqn,
+ status.response_code);
+ vfio_ap_irq_disable(q);
+ break;
+ }
+
+ return status;
+}
+
+/**
+ * handle_pqap: PQAP instruction callback
+ *
+ * @vcpu: The vcpu on which we received the PQAP instruction
+ *
+ * Get the general register contents to initialize internal variables.
+ * REG[0]: APQN
+ * REG[1]: IR and ISC
+ * REG[2]: NIB
+ *
+ * Response.status may be set to following Response Code:
+ * - AP_RESPONSE_Q_NOT_AVAIL: if the queue is not available
+ * - AP_RESPONSE_DECONFIGURED: if the queue is not configured
+ * - AP_RESPONSE_NORMAL (0) : in case of successs
+ * Check vfio_ap_setirq() and vfio_ap_clrirq() for other possible RC.
+ * We take the matrix_dev lock to ensure serialization on queues and
+ * mediated device access.
+ *
+ * Return 0 if we could handle the request inside KVM.
+ * otherwise, returns -EOPNOTSUPP to let QEMU handle the fault.
+ */
+static int handle_pqap(struct kvm_vcpu *vcpu)
+{
+ uint64_t status;
+ uint16_t apqn;
+ struct vfio_ap_queue *q;
+ struct ap_queue_status qstatus = {
+ .response_code = AP_RESPONSE_Q_NOT_AVAIL, };
+ struct ap_matrix_mdev *matrix_mdev;
+
+ /* If we do not use the AIV facility just go to userland */
+ if (!(vcpu->arch.sie_block->eca & ECA_AIV))
+ return -EOPNOTSUPP;
+
+ apqn = vcpu->run->s.regs.gprs[0] & 0xffff;
+ mutex_lock(&matrix_dev->lock);
+
+ if (!vcpu->kvm->arch.crypto.pqap_hook)
+ goto out_unlock;
+ matrix_mdev = container_of(vcpu->kvm->arch.crypto.pqap_hook,
+ struct ap_matrix_mdev, pqap_hook);
+
+ q = vfio_ap_get_queue(matrix_mdev, apqn);
+ if (!q)
+ goto out_unlock;
+
+ status = vcpu->run->s.regs.gprs[1];
+
+ /* If IR bit(16) is set we enable the interrupt */
+ if ((status >> (63 - 16)) & 0x01)
+ qstatus = vfio_ap_irq_enable(q, status & 0x07,
+ vcpu->run->s.regs.gprs[2]);
+ else
+ qstatus = vfio_ap_irq_disable(q);
+
+out_unlock:
+ memcpy(&vcpu->run->s.regs.gprs[1], &qstatus, sizeof(qstatus));
+ vcpu->run->s.regs.gprs[1] >>= 32;
+ mutex_unlock(&matrix_dev->lock);
+ return 0;
+}
+
static void vfio_ap_matrix_init(struct ap_config_info *info,
struct ap_matrix *matrix)
{
@@ -45,8 +334,11 @@ static int vfio_ap_mdev_create(struct kobject *kobj, struct mdev_device *mdev)
return -ENOMEM;
}
+ matrix_mdev->mdev = mdev;
vfio_ap_matrix_init(&matrix_dev->info, &matrix_mdev->matrix);
mdev_set_drvdata(mdev, matrix_mdev);
+ matrix_mdev->pqap_hook.hook = handle_pqap;
+ matrix_mdev->pqap_hook.owner = THIS_MODULE;
mutex_lock(&matrix_dev->lock);
list_add(&matrix_mdev->node, &matrix_dev->mdev_list);
mutex_unlock(&matrix_dev->lock);
@@ -62,6 +354,7 @@ static int vfio_ap_mdev_remove(struct mdev_device *mdev)
return -EBUSY;
mutex_lock(&matrix_dev->lock);
+ vfio_ap_mdev_reset_queues(mdev);
list_del(&matrix_mdev->node);
mutex_unlock(&matrix_dev->lock);
@@ -754,11 +1047,42 @@ static int vfio_ap_mdev_set_kvm(struct ap_matrix_mdev *matrix_mdev,
}
matrix_mdev->kvm = kvm;
+ kvm_get_kvm(kvm);
+ kvm->arch.crypto.pqap_hook = &matrix_mdev->pqap_hook;
mutex_unlock(&matrix_dev->lock);
return 0;
}
+/*
+ * vfio_ap_mdev_iommu_notifier: IOMMU notifier callback
+ *
+ * @nb: The notifier block
+ * @action: Action to be taken
+ * @data: data associated with the request
+ *
+ * For an UNMAP request, unpin the guest IOVA (the NIB guest address we
+ * pinned before). Other requests are ignored.
+ *
+ */
+static int vfio_ap_mdev_iommu_notifier(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct ap_matrix_mdev *matrix_mdev;
+
+ matrix_mdev = container_of(nb, struct ap_matrix_mdev, iommu_notifier);
+
+ if (action == VFIO_IOMMU_NOTIFY_DMA_UNMAP) {
+ struct vfio_iommu_type1_dma_unmap *unmap = data;
+ unsigned long g_pfn = unmap->iova >> PAGE_SHIFT;
+
+ vfio_unpin_pages(mdev_dev(matrix_mdev->mdev), &g_pfn, 1);
+ return NOTIFY_OK;
+ }
+
+ return NOTIFY_DONE;
+}
+
static int vfio_ap_mdev_group_notifier(struct notifier_block *nb,
unsigned long action, void *data)
{
@@ -790,15 +1114,36 @@ static int vfio_ap_mdev_group_notifier(struct notifier_block *nb,
return NOTIFY_OK;
}
-static int vfio_ap_mdev_reset_queue(unsigned int apid, unsigned int apqi,
- unsigned int retry)
+static void vfio_ap_irq_disable_apqn(int apqn)
+{
+ struct device *dev;
+ struct vfio_ap_queue *q;
+
+ dev = driver_find_device(&matrix_dev->vfio_ap_drv->driver, NULL,
+ &apqn, match_apqn);
+ if (dev) {
+ q = dev_get_drvdata(dev);
+ vfio_ap_irq_disable(q);
+ put_device(dev);
+ }
+}
+
+int vfio_ap_mdev_reset_queue(unsigned int apid, unsigned int apqi,
+ unsigned int retry)
{
struct ap_queue_status status;
+ int retry2 = 2;
+ int apqn = AP_MKQID(apid, apqi);
do {
- status = ap_zapq(AP_MKQID(apid, apqi));
+ status = ap_zapq(apqn);
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
+ while (!status.queue_empty && retry2--) {
+ msleep(20);
+ status = ap_tapq(apqn, NULL);
+ }
+ WARN_ON_ONCE(retry <= 0);
return 0;
case AP_RESPONSE_RESET_IN_PROGRESS:
case AP_RESPONSE_BUSY:
@@ -832,6 +1177,7 @@ static int vfio_ap_mdev_reset_queues(struct mdev_device *mdev)
*/
if (ret)
rc = ret;
+ vfio_ap_irq_disable_apqn(AP_MKQID(apid, apqi));
}
}
@@ -858,20 +1204,37 @@ static int vfio_ap_mdev_open(struct mdev_device *mdev)
return ret;
}
- return 0;
+ matrix_mdev->iommu_notifier.notifier_call = vfio_ap_mdev_iommu_notifier;
+ events = VFIO_IOMMU_NOTIFY_DMA_UNMAP;
+ ret = vfio_register_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY,
+ &events, &matrix_mdev->iommu_notifier);
+ if (!ret)
+ return ret;
+
+ vfio_unregister_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY,
+ &matrix_mdev->group_notifier);
+ module_put(THIS_MODULE);
+ return ret;
}
static void vfio_ap_mdev_release(struct mdev_device *mdev)
{
struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev);
- if (matrix_mdev->kvm)
+ mutex_lock(&matrix_dev->lock);
+ if (matrix_mdev->kvm) {
kvm_arch_crypto_clear_masks(matrix_mdev->kvm);
+ matrix_mdev->kvm->arch.crypto.pqap_hook = NULL;
+ vfio_ap_mdev_reset_queues(mdev);
+ kvm_put_kvm(matrix_mdev->kvm);
+ matrix_mdev->kvm = NULL;
+ }
+ mutex_unlock(&matrix_dev->lock);
- vfio_ap_mdev_reset_queues(mdev);
+ vfio_unregister_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY,
+ &matrix_mdev->iommu_notifier);
vfio_unregister_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY,
&matrix_mdev->group_notifier);
- matrix_mdev->kvm = NULL;
module_put(THIS_MODULE);
}
@@ -900,6 +1263,7 @@ static ssize_t vfio_ap_mdev_ioctl(struct mdev_device *mdev,
{
int ret;
+ mutex_lock(&matrix_dev->lock);
switch (cmd) {
case VFIO_DEVICE_GET_INFO:
ret = vfio_ap_mdev_get_device_info(arg);
@@ -911,6 +1275,7 @@ static ssize_t vfio_ap_mdev_ioctl(struct mdev_device *mdev,
ret = -EOPNOTSUPP;
break;
}
+ mutex_unlock(&matrix_dev->lock);
return ret;
}
diff --git a/drivers/s390/crypto/vfio_ap_private.h b/drivers/s390/crypto/vfio_ap_private.h
index 76b7f98e47e9..f46dde56b464 100644
--- a/drivers/s390/crypto/vfio_ap_private.h
+++ b/drivers/s390/crypto/vfio_ap_private.h
@@ -4,6 +4,7 @@
*
* Author(s): Tony Krowiak <akrowiak@linux.ibm.com>
* Halil Pasic <pasic@linux.ibm.com>
+ * Pierre Morel <pmorel@linux.ibm.com>
*
* Copyright IBM Corp. 2018
*/
@@ -16,6 +17,7 @@
#include <linux/mdev.h>
#include <linux/delay.h>
#include <linux/mutex.h>
+#include <linux/kvm_host.h>
#include "ap_bus.h"
@@ -80,10 +82,23 @@ struct ap_matrix_mdev {
struct list_head node;
struct ap_matrix matrix;
struct notifier_block group_notifier;
+ struct notifier_block iommu_notifier;
struct kvm *kvm;
+ struct kvm_s390_module_hook pqap_hook;
+ struct mdev_device *mdev;
};
extern int vfio_ap_mdev_register(void);
extern void vfio_ap_mdev_unregister(void);
+int vfio_ap_mdev_reset_queue(unsigned int apid, unsigned int apqi,
+ unsigned int retry);
+struct vfio_ap_queue {
+ struct ap_matrix_mdev *matrix_mdev;
+ unsigned long saved_pfn;
+ int apqn;
+#define VFIO_AP_ISC_INVALID 0xff
+ unsigned char saved_isc;
+};
+struct ap_queue_status vfio_ap_irq_disable(struct vfio_ap_queue *q);
#endif /* _VFIO_AP_PRIVATE_H_ */
diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c
index 0cbcc238ef98..12fe9deb265e 100644
--- a/drivers/s390/crypto/zcrypt_msgtype6.c
+++ b/drivers/s390/crypto/zcrypt_msgtype6.c
@@ -567,6 +567,10 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(struct ap_message *ap_msg,
payload_hdr = (struct pld_hdr *)((&(msg->pld_lenfmt))+lfmt);
*fcode = payload_hdr->func_val & 0xFFFF;
+ /* enable special processing based on the cprbs flags special bit */
+ if (msg->cprbx.flags & 0x20)
+ ap_msg->special = 1;
+
return 0;
}
diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig
index 7c5a25ddf832..ced896d1534a 100644
--- a/drivers/s390/net/Kconfig
+++ b/drivers/s390/net/Kconfig
@@ -7,10 +7,10 @@ config LCS
prompt "Lan Channel Station Interface"
depends on CCW && NETDEVICES && (ETHERNET || FDDI)
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.
+ 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.
config CTCM
def_tristate m
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index 784a2e76a1b0..c7ee07ce3615 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -25,6 +25,8 @@
#include <linux/wait.h>
#include <linux/workqueue.h>
+#include <net/dst.h>
+#include <net/ip6_fib.h>
#include <net/ipv6.h>
#include <net/if_inet6.h>
#include <net/addrconf.h>
@@ -60,7 +62,7 @@ struct qeth_dbf_info {
debug_info_t *id;
};
-#define QETH_DBF_CTRL_LEN 256
+#define QETH_DBF_CTRL_LEN 256U
#define QETH_DBF_TEXT(name, level, text) \
debug_text_event(qeth_dbf[QETH_DBF_##name].id, level, text)
@@ -525,11 +527,6 @@ struct qeth_qdio_info {
};
/**
- * buffer stuff for read channel
- */
-#define QETH_CMD_BUFFER_NO 8
-
-/**
* channel state machine
*/
enum qeth_channel_states {
@@ -537,8 +534,6 @@ enum qeth_channel_states {
CH_STATE_DOWN,
CH_STATE_HALTED,
CH_STATE_STOPPED,
- CH_STATE_RCD,
- CH_STATE_RCD_DONE,
};
/**
* card state machine
@@ -553,15 +548,11 @@ enum qeth_card_states {
* Protocol versions
*/
enum qeth_prot_versions {
+ QETH_PROT_NONE = 0x0000,
QETH_PROT_IPV4 = 0x0004,
QETH_PROT_IPV6 = 0x0006,
};
-enum qeth_cmd_buffer_state {
- BUF_STATE_FREE,
- BUF_STATE_LOCKED,
-};
-
enum qeth_cq {
QETH_CQ_DISABLED = 0,
QETH_CQ_ENABLED = 1,
@@ -575,39 +566,37 @@ struct qeth_ipato {
struct list_head entries;
};
-struct qeth_channel;
+struct qeth_channel {
+ struct ccw_device *ccwdev;
+ enum qeth_channel_states state;
+ atomic_t irq_pending;
+};
struct qeth_cmd_buffer {
- enum qeth_cmd_buffer_state state;
+ unsigned int length;
+ refcount_t ref_count;
struct qeth_channel *channel;
struct qeth_reply *reply;
long timeout;
unsigned char *data;
- void (*finalize)(struct qeth_card *card, struct qeth_cmd_buffer *iob,
- unsigned int length);
- void (*callback)(struct qeth_card *card, struct qeth_channel *channel,
- struct qeth_cmd_buffer *iob);
+ void (*finalize)(struct qeth_card *card, struct qeth_cmd_buffer *iob);
+ void (*callback)(struct qeth_card *card, struct qeth_cmd_buffer *iob);
};
+static inline void qeth_get_cmd(struct qeth_cmd_buffer *iob)
+{
+ refcount_inc(&iob->ref_count);
+}
+
static inline struct qeth_ipa_cmd *__ipa_cmd(struct qeth_cmd_buffer *iob)
{
return (struct qeth_ipa_cmd *)(iob->data + IPA_PDU_HEADER_SIZE);
}
-/**
- * definition of a qeth channel, used for read and write
- */
-struct qeth_channel {
- enum qeth_channel_states state;
- struct ccw1 *ccw;
- spinlock_t iob_lock;
- wait_queue_head_t wait_q;
- struct ccw_device *ccwdev;
-/*command buffer for control data*/
- struct qeth_cmd_buffer iob[QETH_CMD_BUFFER_NO];
- atomic_t irq_pending;
- int io_buf_no;
-};
+static inline struct ccw1 *__ccw_from_cmd(struct qeth_cmd_buffer *iob)
+{
+ return (struct ccw1 *)(iob->data + ALIGN(iob->length, 8));
+}
static inline bool qeth_trylock_channel(struct qeth_channel *channel)
{
@@ -665,6 +654,7 @@ struct qeth_card_info {
__u16 func_level;
char mcl_level[QETH_MCL_LENGTH + 1];
u8 open_when_online:1;
+ u8 use_v1_blkt:1;
u8 is_vm_nic:1;
int mac_bits;
enum qeth_card_types type;
@@ -725,9 +715,6 @@ struct qeth_discipline {
void (*remove) (struct ccwgroup_device *);
int (*set_online) (struct ccwgroup_device *);
int (*set_offline) (struct ccwgroup_device *);
- int (*freeze)(struct ccwgroup_device *);
- int (*thaw) (struct ccwgroup_device *);
- int (*restore)(struct ccwgroup_device *);
int (*do_ioctl)(struct net_device *dev, struct ifreq *rq, int cmd);
int (*control_event_handler)(struct qeth_card *card,
struct qeth_ipa_cmd *cmd);
@@ -764,6 +751,7 @@ struct qeth_card {
enum qeth_card_states state;
spinlock_t lock;
struct ccwgroup_device *gdev;
+ struct qeth_cmd_buffer *read_cmd;
struct qeth_channel read;
struct qeth_channel write;
struct qeth_channel data;
@@ -891,6 +879,17 @@ static inline int qeth_get_ether_cast_type(struct sk_buff *skb)
return RTN_UNICAST;
}
+static inline struct dst_entry *qeth_dst_check_rcu(struct sk_buff *skb, int ipv)
+{
+ struct dst_entry *dst = skb_dst(skb);
+ struct rt6_info *rt;
+
+ rt = (struct rt6_info *) dst;
+ if (dst)
+ dst = dst_check(dst, (ipv == 6) ? rt6_get_cookie(rt) : 0);
+ return dst;
+}
+
static inline void qeth_rx_csum(struct qeth_card *card, struct sk_buff *skb,
u8 flags)
{
@@ -925,12 +924,12 @@ static inline int qeth_is_diagass_supported(struct qeth_card *card,
int qeth_send_simple_setassparms_prot(struct qeth_card *card,
enum qeth_ipa_funcs ipa_func,
- u16 cmd_code, long data,
+ u16 cmd_code, u32 *data,
enum qeth_prot_versions prot);
/* IPv4 variant */
static inline int qeth_send_simple_setassparms(struct qeth_card *card,
enum qeth_ipa_funcs ipa_func,
- u16 cmd_code, long data)
+ u16 cmd_code, u32 *data)
{
return qeth_send_simple_setassparms_prot(card, ipa_func, cmd_code,
data, QETH_PROT_IPV4);
@@ -938,7 +937,7 @@ static inline int qeth_send_simple_setassparms(struct qeth_card *card,
static inline int qeth_send_simple_setassparms_v6(struct qeth_card *card,
enum qeth_ipa_funcs ipa_func,
- u16 cmd_code, long data)
+ u16 cmd_code, u32 *data)
{
return qeth_send_simple_setassparms_prot(card, ipa_func, cmd_code,
data, QETH_PROT_IPV6);
@@ -979,8 +978,23 @@ int qeth_send_ipa_cmd(struct qeth_card *, struct qeth_cmd_buffer *,
int (*reply_cb)
(struct qeth_card *, struct qeth_reply *, unsigned long),
void *);
-struct qeth_cmd_buffer *qeth_get_ipacmd_buffer(struct qeth_card *,
- enum qeth_ipa_cmds, enum qeth_prot_versions);
+struct qeth_cmd_buffer *qeth_ipa_alloc_cmd(struct qeth_card *card,
+ enum qeth_ipa_cmds cmd_code,
+ enum qeth_prot_versions prot,
+ unsigned int data_length);
+struct qeth_cmd_buffer *qeth_alloc_cmd(struct qeth_channel *channel,
+ unsigned int length, unsigned int ccws,
+ long timeout);
+struct qeth_cmd_buffer *qeth_get_setassparms_cmd(struct qeth_card *card,
+ enum qeth_ipa_funcs ipa_func,
+ u16 cmd_code,
+ unsigned int data_length,
+ enum qeth_prot_versions prot);
+struct qeth_cmd_buffer *qeth_get_diag_cmd(struct qeth_card *card,
+ enum qeth_diags_cmds sub_cmd,
+ unsigned int data_length);
+void qeth_put_cmd(struct qeth_cmd_buffer *iob);
+
struct sk_buff *qeth_core_get_next_skb(struct qeth_card *,
struct qeth_qdio_buffer *, struct qdio_buffer_element **, int *,
struct qeth_hdr **);
@@ -989,15 +1003,13 @@ int qeth_poll(struct napi_struct *napi, int budget);
void qeth_clear_ipacmd_list(struct qeth_card *);
int qeth_qdio_clear_card(struct qeth_card *, int);
void qeth_clear_working_pool_list(struct qeth_card *);
-void qeth_clear_cmd_buffers(struct qeth_channel *);
void qeth_drain_output_queues(struct qeth_card *card);
void qeth_setadp_promisc_mode(struct qeth_card *);
int qeth_setadpparms_change_macaddr(struct qeth_card *);
void qeth_tx_timeout(struct net_device *);
-void qeth_release_buffer(struct qeth_channel *, struct qeth_cmd_buffer *);
+void qeth_notify_reply(struct qeth_reply *reply, int reason);
void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,
u16 cmd_length);
-struct qeth_cmd_buffer *qeth_wait_for_buffer(struct qeth_channel *);
int qeth_query_switch_attributes(struct qeth_card *card,
struct qeth_switch_info *sw_info);
int qeth_query_card_info(struct qeth_card *card,
@@ -1014,10 +1026,6 @@ int qeth_configure_cq(struct qeth_card *, enum qeth_cq);
int qeth_hw_trap(struct qeth_card *, enum qeth_diags_trap_action);
void qeth_trace_features(struct qeth_card *);
int qeth_setassparms_cb(struct qeth_card *, struct qeth_reply *, unsigned long);
-struct qeth_cmd_buffer *qeth_get_setassparms_cmd(struct qeth_card *,
- enum qeth_ipa_funcs,
- __u16, __u16,
- enum qeth_prot_versions);
int qeth_set_features(struct net_device *, netdev_features_t);
void qeth_enable_hw_features(struct net_device *dev);
netdev_features_t qeth_fix_features(struct net_device *, netdev_features_t);
@@ -1032,11 +1040,10 @@ int qeth_stop(struct net_device *dev);
int qeth_vm_request_mac(struct qeth_card *card);
int qeth_xmit(struct qeth_card *card, struct sk_buff *skb,
- struct qeth_qdio_out_q *queue, int ipv, int cast_type,
+ struct qeth_qdio_out_q *queue, int ipv,
void (*fill_header)(struct qeth_qdio_out_q *queue,
struct qeth_hdr *hdr, struct sk_buff *skb,
- int ipv, int cast_type,
- unsigned int data_len));
+ int ipv, unsigned int data_len));
/* exports for OSN */
int qeth_osn_assist(struct net_device *, void *, int);
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index b1823d75dd35..4d0caeebc802 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -20,6 +20,7 @@
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/mii.h>
+#include <linux/mm.h>
#include <linux/kthread.h>
#include <linux/slab.h>
#include <linux/if_vlan.h>
@@ -62,9 +63,7 @@ static struct device *qeth_core_root_dev;
static struct lock_class_key qdio_out_skb_queue_key;
static void qeth_issue_next_read_cb(struct qeth_card *card,
- struct qeth_channel *channel,
struct qeth_cmd_buffer *iob);
-static struct qeth_cmd_buffer *qeth_get_buffer(struct qeth_channel *);
static void qeth_free_buffer_pool(struct qeth_card *);
static int qeth_qdio_establish(struct qeth_card *);
static void qeth_free_qdio_queues(struct qeth_card *card);
@@ -292,7 +291,7 @@ static int qeth_cq_init(struct qeth_card *card)
int rc;
if (card->options.cq == QETH_CQ_ENABLED) {
- QETH_DBF_TEXT(SETUP, 2, "cqinit");
+ QETH_CARD_TEXT(card, 2, "cqinit");
qdio_reset_buffers(card->qdio.c_q->qdio_bufs,
QDIO_MAX_BUFFERS_PER_Q);
card->qdio.c_q->next_buf_to_init = 127;
@@ -300,7 +299,7 @@ static int qeth_cq_init(struct qeth_card *card)
card->qdio.no_in_queues - 1, 0,
127);
if (rc) {
- QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
+ QETH_CARD_TEXT_(card, 2, "1err%d", rc);
goto out;
}
}
@@ -317,7 +316,7 @@ static int qeth_alloc_cq(struct qeth_card *card)
int i;
struct qdio_outbuf_state *outbuf_states;
- QETH_DBF_TEXT(SETUP, 2, "cqon");
+ QETH_CARD_TEXT(card, 2, "cqon");
card->qdio.c_q = qeth_alloc_qdio_queue();
if (!card->qdio.c_q) {
rc = -1;
@@ -339,11 +338,11 @@ static int qeth_alloc_cq(struct qeth_card *card)
outbuf_states += QDIO_MAX_BUFFERS_PER_Q;
}
} else {
- QETH_DBF_TEXT(SETUP, 2, "nocq");
+ QETH_CARD_TEXT(card, 2, "nocq");
card->qdio.c_q = NULL;
card->qdio.no_in_queues = 1;
}
- QETH_DBF_TEXT_(SETUP, 2, "iqc%d", card->qdio.no_in_queues);
+ QETH_CARD_TEXT_(card, 2, "iqc%d", card->qdio.no_in_queues);
rc = 0;
out:
return rc;
@@ -486,42 +485,39 @@ static inline int qeth_is_cq(struct qeth_card *card, unsigned int queue)
queue == card->qdio.no_in_queues - 1;
}
-static void qeth_setup_ccw(struct ccw1 *ccw, u8 cmd_code, u32 len, void *data)
+static void qeth_setup_ccw(struct ccw1 *ccw, u8 cmd_code, u8 flags, u32 len,
+ void *data)
{
ccw->cmd_code = cmd_code;
- ccw->flags = CCW_FLAG_SLI;
+ ccw->flags = flags | CCW_FLAG_SLI;
ccw->count = len;
ccw->cda = (__u32) __pa(data);
}
static int __qeth_issue_next_read(struct qeth_card *card)
{
- struct qeth_channel *channel = &card->read;
- struct qeth_cmd_buffer *iob;
+ struct qeth_cmd_buffer *iob = card->read_cmd;
+ struct qeth_channel *channel = iob->channel;
+ struct ccw1 *ccw = __ccw_from_cmd(iob);
int rc;
QETH_CARD_TEXT(card, 5, "issnxrd");
if (channel->state != CH_STATE_UP)
return -EIO;
- iob = qeth_get_buffer(channel);
- if (!iob) {
- dev_warn(&card->gdev->dev, "The qeth device driver "
- "failed to recover an error on the device\n");
- QETH_DBF_MESSAGE(2, "issue_next_read on device %x failed: no iob available\n",
- CARD_DEVID(card));
- return -ENOMEM;
- }
- qeth_setup_ccw(channel->ccw, CCW_CMD_READ, QETH_BUFSIZE, iob->data);
+ memset(iob->data, 0, iob->length);
+ qeth_setup_ccw(ccw, CCW_CMD_READ, 0, iob->length, iob->data);
iob->callback = qeth_issue_next_read_cb;
+ /* keep the cmd alive after completion: */
+ qeth_get_cmd(iob);
+
QETH_CARD_TEXT(card, 6, "noirqpnd");
- rc = ccw_device_start(channel->ccwdev, channel->ccw,
- (addr_t) iob, 0, 0);
+ rc = ccw_device_start(channel->ccwdev, ccw, (addr_t) iob, 0, 0);
if (rc) {
QETH_DBF_MESSAGE(2, "error %i on device %x when starting next read ccw!\n",
rc, CARD_DEVID(card));
atomic_set(&channel->irq_pending, 0);
- qeth_release_buffer(channel, iob);
+ qeth_put_cmd(iob);
card->read_or_write_problem = 1;
qeth_schedule_recovery(card);
wake_up(&card->wait_q);
@@ -577,11 +573,12 @@ static void qeth_dequeue_reply(struct qeth_card *card, struct qeth_reply *reply)
spin_unlock_irq(&card->lock);
}
-static void qeth_notify_reply(struct qeth_reply *reply, int reason)
+void qeth_notify_reply(struct qeth_reply *reply, int reason)
{
reply->rc = reason;
complete(&reply->received);
}
+EXPORT_SYMBOL_GPL(qeth_notify_reply);
static void qeth_issue_ipa_msg(struct qeth_ipa_cmd *cmd, int rc,
struct qeth_card *card)
@@ -692,48 +689,21 @@ static int qeth_check_idx_response(struct qeth_card *card,
return 0;
}
-static struct qeth_cmd_buffer *__qeth_get_buffer(struct qeth_channel *channel)
-{
- __u8 index;
-
- index = channel->io_buf_no;
- do {
- if (channel->iob[index].state == BUF_STATE_FREE) {
- channel->iob[index].state = BUF_STATE_LOCKED;
- channel->iob[index].timeout = QETH_TIMEOUT;
- channel->io_buf_no = (channel->io_buf_no + 1) %
- QETH_CMD_BUFFER_NO;
- memset(channel->iob[index].data, 0, QETH_BUFSIZE);
- return channel->iob + index;
- }
- index = (index + 1) % QETH_CMD_BUFFER_NO;
- } while (index != channel->io_buf_no);
-
- return NULL;
-}
-
-void qeth_release_buffer(struct qeth_channel *channel,
- struct qeth_cmd_buffer *iob)
+void qeth_put_cmd(struct qeth_cmd_buffer *iob)
{
- unsigned long flags;
-
- spin_lock_irqsave(&channel->iob_lock, flags);
- iob->state = BUF_STATE_FREE;
- iob->callback = NULL;
- if (iob->reply) {
- qeth_put_reply(iob->reply);
- iob->reply = NULL;
+ if (refcount_dec_and_test(&iob->ref_count)) {
+ if (iob->reply)
+ qeth_put_reply(iob->reply);
+ kfree(iob->data);
+ kfree(iob);
}
- spin_unlock_irqrestore(&channel->iob_lock, flags);
- wake_up(&channel->wait_q);
}
-EXPORT_SYMBOL_GPL(qeth_release_buffer);
+EXPORT_SYMBOL_GPL(qeth_put_cmd);
static void qeth_release_buffer_cb(struct qeth_card *card,
- struct qeth_channel *channel,
struct qeth_cmd_buffer *iob)
{
- qeth_release_buffer(channel, iob);
+ qeth_put_cmd(iob);
}
static void qeth_cancel_cmd(struct qeth_cmd_buffer *iob, int rc)
@@ -742,41 +712,38 @@ static void qeth_cancel_cmd(struct qeth_cmd_buffer *iob, int rc)
if (reply)
qeth_notify_reply(reply, rc);
- qeth_release_buffer(iob->channel, iob);
+ qeth_put_cmd(iob);
}
-static struct qeth_cmd_buffer *qeth_get_buffer(struct qeth_channel *channel)
+struct qeth_cmd_buffer *qeth_alloc_cmd(struct qeth_channel *channel,
+ unsigned int length, unsigned int ccws,
+ long timeout)
{
- struct qeth_cmd_buffer *buffer = NULL;
- unsigned long flags;
+ struct qeth_cmd_buffer *iob;
- spin_lock_irqsave(&channel->iob_lock, flags);
- buffer = __qeth_get_buffer(channel);
- spin_unlock_irqrestore(&channel->iob_lock, flags);
- return buffer;
-}
+ if (length > QETH_BUFSIZE)
+ return NULL;
-struct qeth_cmd_buffer *qeth_wait_for_buffer(struct qeth_channel *channel)
-{
- struct qeth_cmd_buffer *buffer;
- wait_event(channel->wait_q,
- ((buffer = qeth_get_buffer(channel)) != NULL));
- return buffer;
-}
-EXPORT_SYMBOL_GPL(qeth_wait_for_buffer);
+ iob = kzalloc(sizeof(*iob), GFP_KERNEL);
+ if (!iob)
+ return NULL;
-void qeth_clear_cmd_buffers(struct qeth_channel *channel)
-{
- int cnt;
+ iob->data = kzalloc(ALIGN(length, 8) + ccws * sizeof(struct ccw1),
+ GFP_KERNEL | GFP_DMA);
+ if (!iob->data) {
+ kfree(iob);
+ return NULL;
+ }
- for (cnt = 0; cnt < QETH_CMD_BUFFER_NO; cnt++)
- qeth_release_buffer(channel, &channel->iob[cnt]);
- channel->io_buf_no = 0;
+ refcount_set(&iob->ref_count, 1);
+ iob->channel = channel;
+ iob->timeout = timeout;
+ iob->length = length;
+ return iob;
}
-EXPORT_SYMBOL_GPL(qeth_clear_cmd_buffers);
+EXPORT_SYMBOL_GPL(qeth_alloc_cmd);
static void qeth_issue_next_read_cb(struct qeth_card *card,
- struct qeth_channel *channel,
struct qeth_cmd_buffer *iob)
{
struct qeth_ipa_cmd *cmd = NULL;
@@ -849,7 +816,8 @@ out:
memcpy(&card->seqno.pdu_hdr_ack,
QETH_PDU_HEADER_SEQ_NO(iob->data),
QETH_SEQ_NO_LENGTH);
- qeth_release_buffer(channel, iob);
+ qeth_put_cmd(iob);
+ __qeth_issue_next_read(card);
}
static int qeth_set_thread_start_bit(struct qeth_card *card,
@@ -976,7 +944,7 @@ static int qeth_get_problem(struct qeth_card *card, struct ccw_device *cdev,
}
static int qeth_check_irb_error(struct qeth_card *card, struct ccw_device *cdev,
- unsigned long intparm, struct irb *irb)
+ struct irb *irb)
{
if (!IS_ERR(irb))
return 0;
@@ -993,12 +961,6 @@ static int qeth_check_irb_error(struct qeth_card *card, struct ccw_device *cdev,
" on the device\n");
QETH_CARD_TEXT(card, 2, "ckirberr");
QETH_CARD_TEXT_(card, 2, " rc%d", -ETIMEDOUT);
- if (intparm == QETH_RCD_PARM) {
- if (card->data.ccwdev == cdev) {
- card->data.state = CH_STATE_DOWN;
- wake_up(&card->wait_q);
- }
- }
return -ETIMEDOUT;
default:
QETH_DBF_MESSAGE(2, "unknown error %ld on channel %x\n",
@@ -1041,7 +1003,7 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
if (qeth_intparm_is_iob(intparm))
iob = (struct qeth_cmd_buffer *) __va((addr_t)intparm);
- rc = qeth_check_irb_error(card, cdev, intparm, irb);
+ rc = qeth_check_irb_error(card, cdev, irb);
if (rc) {
/* IO was terminated, free its resources. */
if (iob)
@@ -1059,11 +1021,6 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
if (irb->scsw.cmd.fctl & (SCSW_FCTL_HALT_FUNC))
channel->state = CH_STATE_HALTED;
- /*let's wake up immediately on data channel*/
- if ((channel == &card->data) && (intparm != 0) &&
- (intparm != QETH_RCD_PARM))
- goto out;
-
if (intparm == QETH_CLEAR_CHANNEL_PARM) {
QETH_CARD_TEXT(card, 6, "clrchpar");
/* we don't have to handle this further */
@@ -1093,10 +1050,7 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
print_hex_dump(KERN_WARNING, "qeth: sense data ",
DUMP_PREFIX_OFFSET, 16, 1, irb->ecw, 32, 1);
}
- if (intparm == QETH_RCD_PARM) {
- channel->state = CH_STATE_DOWN;
- goto out;
- }
+
rc = qeth_get_problem(card, cdev, irb);
if (rc) {
card->read_or_write_problem = 1;
@@ -1108,18 +1062,8 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
}
}
- if (intparm == QETH_RCD_PARM) {
- channel->state = CH_STATE_RCD_DONE;
- goto out;
- }
- if (channel == &card->data)
- return;
- if (channel == &card->read &&
- channel->state == CH_STATE_UP)
- __qeth_issue_next_read(card);
-
if (iob && iob->callback)
- iob->callback(card, iob->channel, iob);
+ iob->callback(card, iob);
out:
wake_up(&card->wait_q);
@@ -1222,56 +1166,26 @@ static void qeth_free_buffer_pool(struct qeth_card *card)
static void qeth_clean_channel(struct qeth_channel *channel)
{
struct ccw_device *cdev = channel->ccwdev;
- int cnt;
QETH_DBF_TEXT(SETUP, 2, "freech");
spin_lock_irq(get_ccwdev_lock(cdev));
cdev->handler = NULL;
spin_unlock_irq(get_ccwdev_lock(cdev));
-
- for (cnt = 0; cnt < QETH_CMD_BUFFER_NO; cnt++)
- kfree(channel->iob[cnt].data);
- kfree(channel->ccw);
}
-static int qeth_setup_channel(struct qeth_channel *channel, bool alloc_buffers)
+static void qeth_setup_channel(struct qeth_channel *channel)
{
struct ccw_device *cdev = channel->ccwdev;
- int cnt;
QETH_DBF_TEXT(SETUP, 2, "setupch");
- channel->ccw = kmalloc(sizeof(struct ccw1), GFP_KERNEL | GFP_DMA);
- if (!channel->ccw)
- return -ENOMEM;
channel->state = CH_STATE_DOWN;
atomic_set(&channel->irq_pending, 0);
- init_waitqueue_head(&channel->wait_q);
spin_lock_irq(get_ccwdev_lock(cdev));
cdev->handler = qeth_irq;
spin_unlock_irq(get_ccwdev_lock(cdev));
-
- if (!alloc_buffers)
- return 0;
-
- for (cnt = 0; cnt < QETH_CMD_BUFFER_NO; cnt++) {
- channel->iob[cnt].data = kmalloc(QETH_BUFSIZE,
- GFP_KERNEL | GFP_DMA);
- if (channel->iob[cnt].data == NULL)
- break;
- channel->iob[cnt].state = BUF_STATE_FREE;
- channel->iob[cnt].channel = channel;
- }
- if (cnt < QETH_CMD_BUFFER_NO) {
- qeth_clean_channel(channel);
- return -ENOMEM;
- }
- channel->io_buf_no = 0;
- spin_lock_init(&channel->iob_lock);
-
- return 0;
}
static int qeth_osa_set_output_queues(struct qeth_card *card, bool single)
@@ -1306,7 +1220,7 @@ static int qeth_update_from_chp_desc(struct qeth_card *card)
struct channel_path_desc_fmt0 *chp_dsc;
int rc = 0;
- QETH_DBF_TEXT(SETUP, 2, "chp_desc");
+ QETH_CARD_TEXT(card, 2, "chp_desc");
ccwdev = card->data.ccwdev;
chp_dsc = ccw_device_get_chp_desc(ccwdev, 0);
@@ -1320,14 +1234,14 @@ static int qeth_update_from_chp_desc(struct qeth_card *card)
rc = qeth_osa_set_output_queues(card, chp_dsc->chpp & 0x02);
kfree(chp_dsc);
- QETH_DBF_TEXT_(SETUP, 2, "nr:%x", card->qdio.no_out_queues);
- QETH_DBF_TEXT_(SETUP, 2, "lvl:%02x", card->info.func_level);
+ QETH_CARD_TEXT_(card, 2, "nr:%x", card->qdio.no_out_queues);
+ QETH_CARD_TEXT_(card, 2, "lvl:%02x", card->info.func_level);
return rc;
}
static void qeth_init_qdio_info(struct qeth_card *card)
{
- QETH_DBF_TEXT(SETUP, 4, "intqdinf");
+ QETH_CARD_TEXT(card, 4, "intqdinf");
atomic_set(&card->qdio.state, QETH_QDIO_UNINITIALIZED);
card->qdio.do_prio_queueing = QETH_PRIOQ_DEFAULT;
card->qdio.default_out_queue = QETH_DEFAULT_QUEUE;
@@ -1393,8 +1307,7 @@ static void qeth_start_kernel_thread(struct work_struct *work)
static void qeth_buffer_reclaim_work(struct work_struct *);
static void qeth_setup_card(struct qeth_card *card)
{
- QETH_DBF_TEXT(SETUP, 2, "setupcrd");
- QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
+ QETH_CARD_TEXT(card, 2, "setupcrd");
card->info.type = CARD_RDEV(card)->id.driver_info;
card->state = CARD_STATE_DOWN;
@@ -1442,21 +1355,19 @@ static struct qeth_card *qeth_alloc_card(struct ccwgroup_device *gdev)
dev_name(&gdev->dev));
if (!card->event_wq)
goto out_wq;
- if (qeth_setup_channel(&card->read, true))
- goto out_ip;
- if (qeth_setup_channel(&card->write, true))
- goto out_channel;
- if (qeth_setup_channel(&card->data, false))
- goto out_data;
+
+ card->read_cmd = qeth_alloc_cmd(&card->read, QETH_BUFSIZE, 1, 0);
+ if (!card->read_cmd)
+ goto out_read_cmd;
+
+ qeth_setup_channel(&card->read);
+ qeth_setup_channel(&card->write);
+ qeth_setup_channel(&card->data);
card->qeth_service_level.seq_print = qeth_core_sl_print;
register_service_level(&card->qeth_service_level);
return card;
-out_data:
- qeth_clean_channel(&card->write);
-out_channel:
- qeth_clean_channel(&card->read);
-out_ip:
+out_read_cmd:
destroy_workqueue(card->event_wq);
out_wq:
dev_set_drvdata(&gdev->dev, NULL);
@@ -1582,60 +1493,6 @@ int qeth_qdio_clear_card(struct qeth_card *card, int use_halt)
}
EXPORT_SYMBOL_GPL(qeth_qdio_clear_card);
-static int qeth_read_conf_data(struct qeth_card *card, void **buffer,
- int *length)
-{
- struct ciw *ciw;
- char *rcd_buf;
- int ret;
- struct qeth_channel *channel = &card->data;
-
- /*
- * scan for RCD command in extended SenseID data
- */
- ciw = ccw_device_get_ciw(channel->ccwdev, CIW_TYPE_RCD);
- if (!ciw || ciw->cmd == 0)
- return -EOPNOTSUPP;
- rcd_buf = kzalloc(ciw->count, GFP_KERNEL | GFP_DMA);
- if (!rcd_buf)
- return -ENOMEM;
-
- qeth_setup_ccw(channel->ccw, ciw->cmd, ciw->count, rcd_buf);
- channel->state = CH_STATE_RCD;
- spin_lock_irq(get_ccwdev_lock(channel->ccwdev));
- ret = ccw_device_start_timeout(channel->ccwdev, channel->ccw,
- QETH_RCD_PARM, LPM_ANYPATH, 0,
- QETH_RCD_TIMEOUT);
- spin_unlock_irq(get_ccwdev_lock(channel->ccwdev));
- if (!ret)
- wait_event(card->wait_q,
- (channel->state == CH_STATE_RCD_DONE ||
- channel->state == CH_STATE_DOWN));
- if (channel->state == CH_STATE_DOWN)
- ret = -EIO;
- else
- channel->state = CH_STATE_DOWN;
- if (ret) {
- kfree(rcd_buf);
- *buffer = NULL;
- *length = 0;
- } else {
- *length = ciw->count;
- *buffer = rcd_buf;
- }
- return ret;
-}
-
-static void qeth_configure_unitaddr(struct qeth_card *card, char *prcd)
-{
- QETH_DBF_TEXT(SETUP, 2, "cfgunit");
- card->info.chpid = prcd[30];
- card->info.unit_addr2 = prcd[31];
- card->info.cula = prcd[63];
- card->info.is_vm_nic = ((prcd[0x10] == _ascebc['V']) &&
- (prcd[0x11] == _ascebc['M']));
-}
-
static enum qeth_discipline_id qeth_vm_detect_layer(struct qeth_card *card)
{
enum qeth_discipline_id disc = QETH_DISCIPLINE_UNDETERMINED;
@@ -1645,7 +1502,7 @@ static enum qeth_discipline_id qeth_vm_detect_layer(struct qeth_card *card)
char userid[80];
int rc = 0;
- QETH_DBF_TEXT(SETUP, 2, "vmlayer");
+ QETH_CARD_TEXT(card, 2, "vmlayer");
cpcmd("QUERY USERID", userid, sizeof(userid), &rc);
if (rc)
@@ -1688,7 +1545,7 @@ out:
kfree(response);
kfree(request);
if (rc)
- QETH_DBF_TEXT_(SETUP, 2, "err%x", rc);
+ QETH_CARD_TEXT_(card, 2, "err%x", rc);
return disc;
}
@@ -1705,24 +1562,23 @@ static enum qeth_discipline_id qeth_enforce_discipline(struct qeth_card *card)
switch (disc) {
case QETH_DISCIPLINE_LAYER2:
- QETH_DBF_TEXT(SETUP, 3, "force l2");
+ QETH_CARD_TEXT(card, 3, "force l2");
break;
case QETH_DISCIPLINE_LAYER3:
- QETH_DBF_TEXT(SETUP, 3, "force l3");
+ QETH_CARD_TEXT(card, 3, "force l3");
break;
default:
- QETH_DBF_TEXT(SETUP, 3, "force no");
+ QETH_CARD_TEXT(card, 3, "force no");
}
return disc;
}
-static void qeth_configure_blkt_default(struct qeth_card *card, char *prcd)
+static void qeth_set_blkt_defaults(struct qeth_card *card)
{
- QETH_DBF_TEXT(SETUP, 2, "cfgblkt");
+ QETH_CARD_TEXT(card, 2, "cfgblkt");
- if (prcd[74] == 0xF0 && prcd[75] == 0xF0 &&
- prcd[76] >= 0xF1 && prcd[76] <= 0xF4) {
+ if (card->info.use_v1_blkt) {
card->info.blkt.time_total = 0;
card->info.blkt.inter_packet = 0;
card->info.blkt.inter_packet_jumbo = 0;
@@ -1758,11 +1614,8 @@ static void qeth_init_func_level(struct qeth_card *card)
}
static void qeth_idx_finalize_cmd(struct qeth_card *card,
- struct qeth_cmd_buffer *iob,
- unsigned int length)
+ struct qeth_cmd_buffer *iob)
{
- qeth_setup_ccw(iob->channel->ccw, CCW_CMD_WRITE, length, iob->data);
-
memcpy(QETH_TRANSPORT_HEADER_SEQ_NO(iob->data), &card->seqno.trans_hdr,
QETH_SEQ_NO_LENGTH);
if (iob->channel == &card->write)
@@ -1779,10 +1632,9 @@ static int qeth_peer_func_level(int level)
}
static void qeth_mpc_finalize_cmd(struct qeth_card *card,
- struct qeth_cmd_buffer *iob,
- unsigned int length)
+ struct qeth_cmd_buffer *iob)
{
- qeth_idx_finalize_cmd(card, iob, length);
+ qeth_idx_finalize_cmd(card, iob);
memcpy(QETH_PDU_HEADER_SEQ_NO(iob->data),
&card->seqno.pdu_hdr, QETH_SEQ_NO_LENGTH);
@@ -1794,10 +1646,26 @@ static void qeth_mpc_finalize_cmd(struct qeth_card *card,
iob->callback = qeth_release_buffer_cb;
}
+static struct qeth_cmd_buffer *qeth_mpc_alloc_cmd(struct qeth_card *card,
+ void *data,
+ unsigned int data_length)
+{
+ struct qeth_cmd_buffer *iob;
+
+ iob = qeth_alloc_cmd(&card->write, data_length, 1, QETH_TIMEOUT);
+ if (!iob)
+ return NULL;
+
+ memcpy(iob->data, data, data_length);
+ qeth_setup_ccw(__ccw_from_cmd(iob), CCW_CMD_WRITE, 0, data_length,
+ iob->data);
+ iob->finalize = qeth_mpc_finalize_cmd;
+ return iob;
+}
+
/**
* qeth_send_control_data() - send control command to the card
* @card: qeth_card structure pointer
- * @len: size of the command buffer
* @iob: qeth_cmd_buffer pointer
* @reply_cb: callback function pointer
* @cb_card: pointer to the qeth_card structure
@@ -1817,7 +1685,7 @@ static void qeth_mpc_finalize_cmd(struct qeth_card *card,
* field 'param' of the structure qeth_reply.
*/
-static int qeth_send_control_data(struct qeth_card *card, int len,
+static int qeth_send_control_data(struct qeth_card *card,
struct qeth_cmd_buffer *iob,
int (*reply_cb)(struct qeth_card *cb_card,
struct qeth_reply *cb_reply,
@@ -1833,13 +1701,13 @@ static int qeth_send_control_data(struct qeth_card *card, int len,
reply = qeth_alloc_reply(card);
if (!reply) {
- qeth_release_buffer(channel, iob);
+ qeth_put_cmd(iob);
return -ENOMEM;
}
reply->callback = reply_cb;
reply->param = reply_param;
- /* pairs with qeth_release_buffer(): */
+ /* pairs with qeth_put_cmd(): */
qeth_get_reply(reply);
iob->reply = reply;
@@ -1848,18 +1716,19 @@ static int qeth_send_control_data(struct qeth_card *card, int len,
timeout);
if (timeout <= 0) {
qeth_put_reply(reply);
- qeth_release_buffer(channel, iob);
+ qeth_put_cmd(iob);
return (timeout == -ERESTARTSYS) ? -EINTR : -ETIME;
}
- iob->finalize(card, iob, len);
- QETH_DBF_HEX(CTRL, 2, iob->data, min(len, QETH_DBF_CTRL_LEN));
+ if (iob->finalize)
+ iob->finalize(card, iob);
+ QETH_DBF_HEX(CTRL, 2, iob->data, min(iob->length, QETH_DBF_CTRL_LEN));
qeth_enqueue_reply(card, reply);
QETH_CARD_TEXT(card, 6, "noirqpnd");
spin_lock_irq(get_ccwdev_lock(channel->ccwdev));
- rc = ccw_device_start_timeout(channel->ccwdev, channel->ccw,
+ rc = ccw_device_start_timeout(channel->ccwdev, __ccw_from_cmd(iob),
(addr_t) iob, 0, 0, timeout);
spin_unlock_irq(get_ccwdev_lock(channel->ccwdev));
if (rc) {
@@ -1868,7 +1737,7 @@ static int qeth_send_control_data(struct qeth_card *card, int len,
QETH_CARD_TEXT_(card, 2, " err%d", rc);
qeth_dequeue_reply(card, reply);
qeth_put_reply(reply);
- qeth_release_buffer(channel, iob);
+ qeth_put_cmd(iob);
atomic_set(&channel->irq_pending, 0);
wake_up(&card->wait_q);
return rc;
@@ -1886,6 +1755,46 @@ static int qeth_send_control_data(struct qeth_card *card, int len,
return rc;
}
+static void qeth_read_conf_data_cb(struct qeth_card *card,
+ struct qeth_cmd_buffer *iob)
+{
+ unsigned char *prcd = iob->data;
+
+ QETH_CARD_TEXT(card, 2, "cfgunit");
+ card->info.chpid = prcd[30];
+ card->info.unit_addr2 = prcd[31];
+ card->info.cula = prcd[63];
+ card->info.is_vm_nic = ((prcd[0x10] == _ascebc['V']) &&
+ (prcd[0x11] == _ascebc['M']));
+ card->info.use_v1_blkt = prcd[74] == 0xF0 && prcd[75] == 0xF0 &&
+ prcd[76] >= 0xF1 && prcd[76] <= 0xF4;
+
+ qeth_notify_reply(iob->reply, 0);
+ qeth_put_cmd(iob);
+}
+
+static int qeth_read_conf_data(struct qeth_card *card)
+{
+ struct qeth_channel *channel = &card->data;
+ struct qeth_cmd_buffer *iob;
+ struct ciw *ciw;
+
+ /* scan for RCD command in extended SenseID data */
+ ciw = ccw_device_get_ciw(channel->ccwdev, CIW_TYPE_RCD);
+ if (!ciw || ciw->cmd == 0)
+ return -EOPNOTSUPP;
+
+ iob = qeth_alloc_cmd(channel, ciw->count, 1, QETH_RCD_TIMEOUT);
+ if (!iob)
+ return -ENOMEM;
+
+ iob->callback = qeth_read_conf_data_cb;
+ qeth_setup_ccw(__ccw_from_cmd(iob), ciw->cmd, 0, iob->length,
+ iob->data);
+
+ return qeth_send_control_data(card, iob, NULL, NULL);
+}
+
static int qeth_idx_check_activate_response(struct qeth_card *card,
struct qeth_channel *channel,
struct qeth_cmd_buffer *iob)
@@ -1900,8 +1809,8 @@ static int qeth_idx_check_activate_response(struct qeth_card *card,
return 0;
/* negative reply: */
- QETH_DBF_TEXT_(SETUP, 2, "idxneg%c",
- QETH_IDX_ACT_CAUSE_CODE(iob->data));
+ QETH_CARD_TEXT_(card, 2, "idxneg%c",
+ QETH_IDX_ACT_CAUSE_CODE(iob->data));
switch (QETH_IDX_ACT_CAUSE_CODE(iob->data)) {
case QETH_IDX_ACT_ERR_EXCL:
@@ -1920,14 +1829,14 @@ static int qeth_idx_check_activate_response(struct qeth_card *card,
}
}
-static void qeth_idx_query_read_cb(struct qeth_card *card,
- struct qeth_channel *channel,
- struct qeth_cmd_buffer *iob)
+static void qeth_idx_activate_read_channel_cb(struct qeth_card *card,
+ struct qeth_cmd_buffer *iob)
{
+ struct qeth_channel *channel = iob->channel;
u16 peer_level;
int rc;
- QETH_DBF_TEXT(SETUP, 2, "idxrdcb");
+ QETH_CARD_TEXT(card, 2, "idxrdcb");
rc = qeth_idx_check_activate_response(card, channel, iob);
if (rc)
@@ -1950,17 +1859,17 @@ static void qeth_idx_query_read_cb(struct qeth_card *card,
out:
qeth_notify_reply(iob->reply, rc);
- qeth_release_buffer(channel, iob);
+ qeth_put_cmd(iob);
}
-static void qeth_idx_query_write_cb(struct qeth_card *card,
- struct qeth_channel *channel,
- struct qeth_cmd_buffer *iob)
+static void qeth_idx_activate_write_channel_cb(struct qeth_card *card,
+ struct qeth_cmd_buffer *iob)
{
+ struct qeth_channel *channel = iob->channel;
u16 peer_level;
int rc;
- QETH_DBF_TEXT(SETUP, 2, "idxwrcb");
+ QETH_CARD_TEXT(card, 2, "idxwrcb");
rc = qeth_idx_check_activate_response(card, channel, iob);
if (rc)
@@ -1977,22 +1886,7 @@ static void qeth_idx_query_write_cb(struct qeth_card *card,
out:
qeth_notify_reply(iob->reply, rc);
- qeth_release_buffer(channel, iob);
-}
-
-static void qeth_idx_finalize_query_cmd(struct qeth_card *card,
- struct qeth_cmd_buffer *iob,
- unsigned int length)
-{
- qeth_setup_ccw(iob->channel->ccw, CCW_CMD_READ, length, iob->data);
-}
-
-static void qeth_idx_activate_cb(struct qeth_card *card,
- struct qeth_channel *channel,
- struct qeth_cmd_buffer *iob)
-{
- qeth_notify_reply(iob->reply, 0);
- qeth_release_buffer(channel, iob);
+ qeth_put_cmd(iob);
}
static void qeth_idx_setup_activate_cmd(struct qeth_card *card,
@@ -2000,11 +1894,14 @@ static void qeth_idx_setup_activate_cmd(struct qeth_card *card,
{
u16 addr = (card->info.cula << 8) + card->info.unit_addr2;
u8 port = ((u8)card->dev->dev_port) | 0x80;
+ struct ccw1 *ccw = __ccw_from_cmd(iob);
struct ccw_dev_id dev_id;
+ qeth_setup_ccw(&ccw[0], CCW_CMD_WRITE, CCW_FLAG_CC, IDX_ACTIVATE_SIZE,
+ iob->data);
+ qeth_setup_ccw(&ccw[1], CCW_CMD_READ, 0, iob->length, iob->data);
ccw_device_get_id(CARD_DDEV(card), &dev_id);
iob->finalize = qeth_idx_finalize_cmd;
- iob->callback = qeth_idx_activate_cb;
memcpy(QETH_IDX_ACT_PNO(iob->data), &port, 1);
memcpy(QETH_IDX_ACT_ISSUER_RM_TOKEN(iob->data),
@@ -2021,26 +1918,17 @@ static int qeth_idx_activate_read_channel(struct qeth_card *card)
struct qeth_cmd_buffer *iob;
int rc;
- QETH_DBF_TEXT(SETUP, 2, "idxread");
+ QETH_CARD_TEXT(card, 2, "idxread");
- iob = qeth_get_buffer(channel);
+ iob = qeth_alloc_cmd(channel, QETH_BUFSIZE, 2, QETH_TIMEOUT);
if (!iob)
return -ENOMEM;
memcpy(iob->data, IDX_ACTIVATE_READ, IDX_ACTIVATE_SIZE);
qeth_idx_setup_activate_cmd(card, iob);
+ iob->callback = qeth_idx_activate_read_channel_cb;
- rc = qeth_send_control_data(card, IDX_ACTIVATE_SIZE, iob, NULL, NULL);
- if (rc)
- return rc;
-
- iob = qeth_get_buffer(channel);
- if (!iob)
- return -ENOMEM;
-
- iob->finalize = qeth_idx_finalize_query_cmd;
- iob->callback = qeth_idx_query_read_cb;
- rc = qeth_send_control_data(card, QETH_BUFSIZE, iob, NULL, NULL);
+ rc = qeth_send_control_data(card, iob, NULL, NULL);
if (rc)
return rc;
@@ -2054,26 +1942,17 @@ static int qeth_idx_activate_write_channel(struct qeth_card *card)
struct qeth_cmd_buffer *iob;
int rc;
- QETH_DBF_TEXT(SETUP, 2, "idxwrite");
+ QETH_CARD_TEXT(card, 2, "idxwrite");
- iob = qeth_get_buffer(channel);
+ iob = qeth_alloc_cmd(channel, QETH_BUFSIZE, 2, QETH_TIMEOUT);
if (!iob)
return -ENOMEM;
memcpy(iob->data, IDX_ACTIVATE_WRITE, IDX_ACTIVATE_SIZE);
qeth_idx_setup_activate_cmd(card, iob);
+ iob->callback = qeth_idx_activate_write_channel_cb;
- rc = qeth_send_control_data(card, IDX_ACTIVATE_SIZE, iob, NULL, NULL);
- if (rc)
- return rc;
-
- iob = qeth_get_buffer(channel);
- if (!iob)
- return -ENOMEM;
-
- iob->finalize = qeth_idx_finalize_query_cmd;
- iob->callback = qeth_idx_query_write_cb;
- rc = qeth_send_control_data(card, QETH_BUFSIZE, iob, NULL, NULL);
+ rc = qeth_send_control_data(card, iob, NULL, NULL);
if (rc)
return rc;
@@ -2086,7 +1965,7 @@ static int qeth_cm_enable_cb(struct qeth_card *card, struct qeth_reply *reply,
{
struct qeth_cmd_buffer *iob;
- QETH_DBF_TEXT(SETUP, 2, "cmenblcb");
+ QETH_CARD_TEXT(card, 2, "cmenblcb");
iob = (struct qeth_cmd_buffer *) data;
memcpy(&card->token.cm_filter_r,
@@ -2097,23 +1976,20 @@ static int qeth_cm_enable_cb(struct qeth_card *card, struct qeth_reply *reply,
static int qeth_cm_enable(struct qeth_card *card)
{
- int rc;
struct qeth_cmd_buffer *iob;
- QETH_DBF_TEXT(SETUP, 2, "cmenable");
+ QETH_CARD_TEXT(card, 2, "cmenable");
- iob = qeth_wait_for_buffer(&card->write);
- iob->finalize = qeth_mpc_finalize_cmd;
- memcpy(iob->data, CM_ENABLE, CM_ENABLE_SIZE);
+ iob = qeth_mpc_alloc_cmd(card, CM_ENABLE, CM_ENABLE_SIZE);
+ if (!iob)
+ return -ENOMEM;
memcpy(QETH_CM_ENABLE_ISSUER_RM_TOKEN(iob->data),
&card->token.issuer_rm_r, QETH_MPC_TOKEN_LENGTH);
memcpy(QETH_CM_ENABLE_FILTER_TOKEN(iob->data),
&card->token.cm_filter_w, QETH_MPC_TOKEN_LENGTH);
- rc = qeth_send_control_data(card, CM_ENABLE_SIZE, iob,
- qeth_cm_enable_cb, NULL);
- return rc;
+ return qeth_send_control_data(card, iob, qeth_cm_enable_cb, NULL);
}
static int qeth_cm_setup_cb(struct qeth_card *card, struct qeth_reply *reply,
@@ -2121,7 +1997,7 @@ static int qeth_cm_setup_cb(struct qeth_card *card, struct qeth_reply *reply,
{
struct qeth_cmd_buffer *iob;
- QETH_DBF_TEXT(SETUP, 2, "cmsetpcb");
+ QETH_CARD_TEXT(card, 2, "cmsetpcb");
iob = (struct qeth_cmd_buffer *) data;
memcpy(&card->token.cm_connection_r,
@@ -2132,14 +2008,13 @@ static int qeth_cm_setup_cb(struct qeth_card *card, struct qeth_reply *reply,
static int qeth_cm_setup(struct qeth_card *card)
{
- int rc;
struct qeth_cmd_buffer *iob;
- QETH_DBF_TEXT(SETUP, 2, "cmsetup");
+ QETH_CARD_TEXT(card, 2, "cmsetup");
- iob = qeth_wait_for_buffer(&card->write);
- iob->finalize = qeth_mpc_finalize_cmd;
- memcpy(iob->data, CM_SETUP, CM_SETUP_SIZE);
+ iob = qeth_mpc_alloc_cmd(card, CM_SETUP, CM_SETUP_SIZE);
+ if (!iob)
+ return -ENOMEM;
memcpy(QETH_CM_SETUP_DEST_ADDR(iob->data),
&card->token.issuer_rm_r, QETH_MPC_TOKEN_LENGTH);
@@ -2147,9 +2022,7 @@ static int qeth_cm_setup(struct qeth_card *card)
&card->token.cm_connection_w, QETH_MPC_TOKEN_LENGTH);
memcpy(QETH_CM_SETUP_FILTER_TOKEN(iob->data),
&card->token.cm_filter_r, QETH_MPC_TOKEN_LENGTH);
- rc = qeth_send_control_data(card, CM_SETUP_SIZE, iob,
- qeth_cm_setup_cb, NULL);
- return rc;
+ return qeth_send_control_data(card, iob, qeth_cm_setup_cb, NULL);
}
static int qeth_update_max_mtu(struct qeth_card *card, unsigned int max_mtu)
@@ -2214,7 +2087,7 @@ static int qeth_ulp_enable_cb(struct qeth_card *card, struct qeth_reply *reply,
__u8 link_type;
struct qeth_cmd_buffer *iob;
- QETH_DBF_TEXT(SETUP, 2, "ulpenacb");
+ QETH_CARD_TEXT(card, 2, "ulpenacb");
iob = (struct qeth_cmd_buffer *) data;
memcpy(&card->token.ulp_filter_r,
@@ -2235,7 +2108,7 @@ static int qeth_ulp_enable_cb(struct qeth_card *card, struct qeth_reply *reply,
card->info.link_type = link_type;
} else
card->info.link_type = 0;
- QETH_DBF_TEXT_(SETUP, 2, "link%d", card->info.link_type);
+ QETH_CARD_TEXT_(card, 2, "link%d", card->info.link_type);
return 0;
}
@@ -2253,12 +2126,11 @@ static int qeth_ulp_enable(struct qeth_card *card)
u16 max_mtu;
int rc;
- /*FIXME: trace view callbacks*/
- QETH_DBF_TEXT(SETUP, 2, "ulpenabl");
+ QETH_CARD_TEXT(card, 2, "ulpenabl");
- iob = qeth_wait_for_buffer(&card->write);
- iob->finalize = qeth_mpc_finalize_cmd;
- memcpy(iob->data, ULP_ENABLE, ULP_ENABLE_SIZE);
+ iob = qeth_mpc_alloc_cmd(card, ULP_ENABLE, ULP_ENABLE_SIZE);
+ if (!iob)
+ return -ENOMEM;
*(QETH_ULP_ENABLE_LINKNUM(iob->data)) = (u8) card->dev->dev_port;
memcpy(QETH_ULP_ENABLE_PROT_TYPE(iob->data), &prot_type, 1);
@@ -2266,8 +2138,7 @@ static int qeth_ulp_enable(struct qeth_card *card)
&card->token.cm_connection_r, QETH_MPC_TOKEN_LENGTH);
memcpy(QETH_ULP_ENABLE_FILTER_TOKEN(iob->data),
&card->token.ulp_filter_w, QETH_MPC_TOKEN_LENGTH);
- rc = qeth_send_control_data(card, ULP_ENABLE_SIZE, iob,
- qeth_ulp_enable_cb, &max_mtu);
+ rc = qeth_send_control_data(card, iob, qeth_ulp_enable_cb, &max_mtu);
if (rc)
return rc;
return qeth_update_max_mtu(card, max_mtu);
@@ -2278,7 +2149,7 @@ static int qeth_ulp_setup_cb(struct qeth_card *card, struct qeth_reply *reply,
{
struct qeth_cmd_buffer *iob;
- QETH_DBF_TEXT(SETUP, 2, "ulpstpcb");
+ QETH_CARD_TEXT(card, 2, "ulpstpcb");
iob = (struct qeth_cmd_buffer *) data;
memcpy(&card->token.ulp_connection_r,
@@ -2286,7 +2157,7 @@ static int qeth_ulp_setup_cb(struct qeth_card *card, struct qeth_reply *reply,
QETH_MPC_TOKEN_LENGTH);
if (!strncmp("00S", QETH_ULP_SETUP_RESP_CONNECTION_TOKEN(iob->data),
3)) {
- QETH_DBF_TEXT(SETUP, 2, "olmlimit");
+ QETH_CARD_TEXT(card, 2, "olmlimit");
dev_err(&card->gdev->dev, "A connection could not be "
"established because of an OLM limit\n");
return -EMLINK;
@@ -2296,16 +2167,15 @@ static int qeth_ulp_setup_cb(struct qeth_card *card, struct qeth_reply *reply,
static int qeth_ulp_setup(struct qeth_card *card)
{
- int rc;
__u16 temp;
struct qeth_cmd_buffer *iob;
struct ccw_dev_id dev_id;
- QETH_DBF_TEXT(SETUP, 2, "ulpsetup");
+ QETH_CARD_TEXT(card, 2, "ulpsetup");
- iob = qeth_wait_for_buffer(&card->write);
- iob->finalize = qeth_mpc_finalize_cmd;
- memcpy(iob->data, ULP_SETUP, ULP_SETUP_SIZE);
+ iob = qeth_mpc_alloc_cmd(card, ULP_SETUP, ULP_SETUP_SIZE);
+ if (!iob)
+ return -ENOMEM;
memcpy(QETH_ULP_SETUP_DEST_ADDR(iob->data),
&card->token.cm_connection_r, QETH_MPC_TOKEN_LENGTH);
@@ -2318,9 +2188,7 @@ static int qeth_ulp_setup(struct qeth_card *card)
memcpy(QETH_ULP_SETUP_CUA(iob->data), &dev_id.devno, 2);
temp = (card->info.cula << 8) + card->info.unit_addr2;
memcpy(QETH_ULP_SETUP_REAL_DEVADDR(iob->data), &temp, 2);
- rc = qeth_send_control_data(card, ULP_SETUP_SIZE, iob,
- qeth_ulp_setup_cb, NULL);
- return rc;
+ return qeth_send_control_data(card, iob, qeth_ulp_setup_cb, NULL);
}
static int qeth_init_qdio_out_buf(struct qeth_qdio_out_q *q, int bidx)
@@ -2369,13 +2237,13 @@ static int qeth_alloc_qdio_queues(struct qeth_card *card)
{
int i, j;
- QETH_DBF_TEXT(SETUP, 2, "allcqdbf");
+ QETH_CARD_TEXT(card, 2, "allcqdbf");
if (atomic_cmpxchg(&card->qdio.state, QETH_QDIO_UNINITIALIZED,
QETH_QDIO_ALLOCATED) != QETH_QDIO_UNINITIALIZED)
return 0;
- QETH_DBF_TEXT(SETUP, 2, "inq");
+ QETH_CARD_TEXT(card, 2, "inq");
card->qdio.in_q = qeth_alloc_qdio_queue();
if (!card->qdio.in_q)
goto out_nomem;
@@ -2389,8 +2257,8 @@ static int qeth_alloc_qdio_queues(struct qeth_card *card)
card->qdio.out_qs[i] = qeth_alloc_output_queue();
if (!card->qdio.out_qs[i])
goto out_freeoutq;
- QETH_DBF_TEXT_(SETUP, 2, "outq %i", i);
- QETH_DBF_HEX(SETUP, 2, &card->qdio.out_qs[i], sizeof(void *));
+ QETH_CARD_TEXT_(card, 2, "outq %i", i);
+ QETH_CARD_HEX(card, 2, &card->qdio.out_qs[i], sizeof(void *));
card->qdio.out_qs[i]->card = card;
card->qdio.out_qs[i]->queue_no = i;
/* give outbound qeth_qdio_buffers their qdio_buffers */
@@ -2481,79 +2349,77 @@ static void qeth_create_qib_param_field_blkt(struct qeth_card *card,
static int qeth_qdio_activate(struct qeth_card *card)
{
- QETH_DBF_TEXT(SETUP, 3, "qdioact");
+ QETH_CARD_TEXT(card, 3, "qdioact");
return qdio_activate(CARD_DDEV(card));
}
static int qeth_dm_act(struct qeth_card *card)
{
- int rc;
struct qeth_cmd_buffer *iob;
- QETH_DBF_TEXT(SETUP, 2, "dmact");
+ QETH_CARD_TEXT(card, 2, "dmact");
- iob = qeth_wait_for_buffer(&card->write);
- iob->finalize = qeth_mpc_finalize_cmd;
- memcpy(iob->data, DM_ACT, DM_ACT_SIZE);
+ iob = qeth_mpc_alloc_cmd(card, DM_ACT, DM_ACT_SIZE);
+ if (!iob)
+ return -ENOMEM;
memcpy(QETH_DM_ACT_DEST_ADDR(iob->data),
&card->token.cm_connection_r, QETH_MPC_TOKEN_LENGTH);
memcpy(QETH_DM_ACT_CONNECTION_TOKEN(iob->data),
&card->token.ulp_connection_r, QETH_MPC_TOKEN_LENGTH);
- rc = qeth_send_control_data(card, DM_ACT_SIZE, iob, NULL, NULL);
- return rc;
+ return qeth_send_control_data(card, iob, NULL, NULL);
}
static int qeth_mpc_initialize(struct qeth_card *card)
{
int rc;
- QETH_DBF_TEXT(SETUP, 2, "mpcinit");
+ QETH_CARD_TEXT(card, 2, "mpcinit");
rc = qeth_issue_next_read(card);
if (rc) {
- QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
+ QETH_CARD_TEXT_(card, 2, "1err%d", rc);
return rc;
}
rc = qeth_cm_enable(card);
if (rc) {
- QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc);
+ QETH_CARD_TEXT_(card, 2, "2err%d", rc);
goto out_qdio;
}
rc = qeth_cm_setup(card);
if (rc) {
- QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
+ QETH_CARD_TEXT_(card, 2, "3err%d", rc);
goto out_qdio;
}
rc = qeth_ulp_enable(card);
if (rc) {
- QETH_DBF_TEXT_(SETUP, 2, "4err%d", rc);
+ QETH_CARD_TEXT_(card, 2, "4err%d", rc);
goto out_qdio;
}
rc = qeth_ulp_setup(card);
if (rc) {
- QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc);
+ QETH_CARD_TEXT_(card, 2, "5err%d", rc);
goto out_qdio;
}
rc = qeth_alloc_qdio_queues(card);
if (rc) {
- QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc);
+ QETH_CARD_TEXT_(card, 2, "5err%d", rc);
goto out_qdio;
}
rc = qeth_qdio_establish(card);
if (rc) {
- QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc);
+ QETH_CARD_TEXT_(card, 2, "6err%d", rc);
qeth_free_qdio_queues(card);
goto out_qdio;
}
rc = qeth_qdio_activate(card);
if (rc) {
- QETH_DBF_TEXT_(SETUP, 2, "7err%d", rc);
+ QETH_CARD_TEXT_(card, 2, "7err%d", rc);
goto out_qdio;
}
rc = qeth_dm_act(card);
if (rc) {
- QETH_DBF_TEXT_(SETUP, 2, "8err%d", rc);
+ QETH_CARD_TEXT_(card, 2, "8err%d", rc);
goto out_qdio;
}
@@ -2706,7 +2572,7 @@ int qeth_init_qdio_queues(struct qeth_card *card)
unsigned int i;
int rc;
- QETH_DBF_TEXT(SETUP, 2, "initqdqs");
+ QETH_CARD_TEXT(card, 2, "initqdqs");
/* inbound queue */
qdio_reset_buffers(card->qdio.in_q->qdio_bufs, QDIO_MAX_BUFFERS_PER_Q);
@@ -2720,7 +2586,7 @@ int qeth_init_qdio_queues(struct qeth_card *card)
rc = do_QDIO(CARD_DDEV(card), QDIO_FLAG_SYNC_INPUT, 0, 0,
card->qdio.in_buf_pool.buf_count - 1);
if (rc) {
- QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
+ QETH_CARD_TEXT_(card, 2, "1err%d", rc);
return rc;
}
@@ -2746,36 +2612,10 @@ int qeth_init_qdio_queues(struct qeth_card *card)
}
EXPORT_SYMBOL_GPL(qeth_init_qdio_queues);
-static __u8 qeth_get_ipa_adp_type(enum qeth_link_types link_type)
-{
- switch (link_type) {
- case QETH_LINK_TYPE_HSTR:
- return 2;
- default:
- return 1;
- }
-}
-
-static void qeth_fill_ipacmd_header(struct qeth_card *card,
- struct qeth_ipa_cmd *cmd,
- enum qeth_ipa_cmds command,
- enum qeth_prot_versions prot)
-{
- cmd->hdr.command = command;
- cmd->hdr.initiator = IPA_CMD_INITIATOR_HOST;
- /* cmd->hdr.seqno is set by qeth_send_control_data() */
- cmd->hdr.adapter_type = qeth_get_ipa_adp_type(card->info.link_type);
- cmd->hdr.rel_adapter_no = (u8) card->dev->dev_port;
- cmd->hdr.prim_version_no = IS_LAYER2(card) ? 2 : 1;
- cmd->hdr.param_count = 1;
- cmd->hdr.prot_version = prot;
-}
-
static void qeth_ipa_finalize_cmd(struct qeth_card *card,
- struct qeth_cmd_buffer *iob,
- unsigned int length)
+ struct qeth_cmd_buffer *iob)
{
- qeth_mpc_finalize_cmd(card, iob, length);
+ qeth_mpc_finalize_cmd(card, iob);
/* override with IPA-specific values: */
__ipa_cmd(iob)->hdr.seqno = card->seqno.ipa;
@@ -2785,11 +2625,12 @@ static void qeth_ipa_finalize_cmd(struct qeth_card *card,
void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,
u16 cmd_length)
{
- u16 total_length = IPA_PDU_HEADER_SIZE + cmd_length;
u8 prot_type = qeth_mpc_select_prot_type(card);
+ u16 total_length = iob->length;
+ qeth_setup_ccw(__ccw_from_cmd(iob), CCW_CMD_WRITE, 0, total_length,
+ iob->data);
iob->finalize = qeth_ipa_finalize_cmd;
- iob->timeout = QETH_IPA_TIMEOUT;
memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE);
memcpy(QETH_IPA_PDU_LEN_TOTAL(iob->data), &total_length, 2);
@@ -2802,25 +2643,35 @@ void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,
}
EXPORT_SYMBOL_GPL(qeth_prepare_ipa_cmd);
-struct qeth_cmd_buffer *qeth_get_ipacmd_buffer(struct qeth_card *card,
- enum qeth_ipa_cmds ipacmd, enum qeth_prot_versions prot)
+struct qeth_cmd_buffer *qeth_ipa_alloc_cmd(struct qeth_card *card,
+ enum qeth_ipa_cmds cmd_code,
+ enum qeth_prot_versions prot,
+ unsigned int data_length)
{
+ enum qeth_link_types link_type = card->info.link_type;
struct qeth_cmd_buffer *iob;
+ struct qeth_ipacmd_hdr *hdr;
- iob = qeth_get_buffer(&card->write);
- if (iob) {
- qeth_prepare_ipa_cmd(card, iob, sizeof(struct qeth_ipa_cmd));
- qeth_fill_ipacmd_header(card, __ipa_cmd(iob), ipacmd, prot);
- } else {
- dev_warn(&card->gdev->dev,
- "The qeth driver ran out of channel command buffers\n");
- QETH_DBF_MESSAGE(1, "device %x ran out of channel command buffers",
- CARD_DEVID(card));
- }
+ data_length += offsetof(struct qeth_ipa_cmd, data);
+ iob = qeth_alloc_cmd(&card->write, IPA_PDU_HEADER_SIZE + data_length, 1,
+ QETH_IPA_TIMEOUT);
+ if (!iob)
+ return NULL;
+ qeth_prepare_ipa_cmd(card, iob, data_length);
+
+ hdr = &__ipa_cmd(iob)->hdr;
+ hdr->command = cmd_code;
+ hdr->initiator = IPA_CMD_INITIATOR_HOST;
+ /* hdr->seqno is set by qeth_send_control_data() */
+ hdr->adapter_type = (link_type == QETH_LINK_TYPE_HSTR) ? 2 : 1;
+ hdr->rel_adapter_no = (u8) card->dev->dev_port;
+ hdr->prim_version_no = IS_LAYER2(card) ? 2 : 1;
+ hdr->param_count = 1;
+ hdr->prot_version = prot;
return iob;
}
-EXPORT_SYMBOL_GPL(qeth_get_ipacmd_buffer);
+EXPORT_SYMBOL_GPL(qeth_ipa_alloc_cmd);
static int qeth_send_ipa_cmd_cb(struct qeth_card *card,
struct qeth_reply *reply, unsigned long data)
@@ -2841,20 +2692,18 @@ int qeth_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,
unsigned long),
void *reply_param)
{
- u16 length;
int rc;
QETH_CARD_TEXT(card, 4, "sendipa");
if (card->read_or_write_problem) {
- qeth_release_buffer(iob->channel, iob);
+ qeth_put_cmd(iob);
return -EIO;
}
if (reply_cb == NULL)
reply_cb = qeth_send_ipa_cmd_cb;
- memcpy(&length, QETH_IPA_PDU_LEN_TOTAL(iob->data), 2);
- rc = qeth_send_control_data(card, length, iob, reply_cb, reply_param);
+ rc = qeth_send_control_data(card, iob, reply_cb, reply_param);
if (rc == -ETIME) {
qeth_clear_ipacmd_list(card);
qeth_schedule_recovery(card);
@@ -2878,9 +2727,9 @@ static int qeth_send_startlan(struct qeth_card *card)
{
struct qeth_cmd_buffer *iob;
- QETH_DBF_TEXT(SETUP, 2, "strtlan");
+ QETH_CARD_TEXT(card, 2, "strtlan");
- iob = qeth_get_ipacmd_buffer(card, IPA_CMD_STARTLAN, 0);
+ iob = qeth_ipa_alloc_cmd(card, IPA_CMD_STARTLAN, QETH_PROT_NONE, 0);
if (!iob)
return -ENOMEM;
return qeth_send_ipa_cmd(card, iob, qeth_send_startlan_cb, NULL);
@@ -2906,7 +2755,7 @@ static int qeth_query_setadapterparms_cb(struct qeth_card *card,
if (cmd->data.setadapterparms.data.query_cmds_supp.lan_type & 0x7f) {
card->info.link_type =
cmd->data.setadapterparms.data.query_cmds_supp.lan_type;
- QETH_DBF_TEXT_(SETUP, 2, "lnk %d", card->info.link_type);
+ QETH_CARD_TEXT_(card, 2, "lnk %d", card->info.link_type);
}
card->options.adp.supported_funcs =
cmd->data.setadapterparms.data.query_cmds_supp.supported_cmds;
@@ -2914,21 +2763,24 @@ static int qeth_query_setadapterparms_cb(struct qeth_card *card,
}
static struct qeth_cmd_buffer *qeth_get_adapter_cmd(struct qeth_card *card,
- __u32 command, __u32 cmdlen)
+ enum qeth_ipa_setadp_cmd adp_cmd,
+ unsigned int data_length)
{
+ struct qeth_ipacmd_setadpparms_hdr *hdr;
struct qeth_cmd_buffer *iob;
- struct qeth_ipa_cmd *cmd;
- iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETADAPTERPARMS,
- QETH_PROT_IPV4);
- if (iob) {
- cmd = __ipa_cmd(iob);
- cmd->data.setadapterparms.hdr.cmdlength = cmdlen;
- cmd->data.setadapterparms.hdr.command_code = command;
- cmd->data.setadapterparms.hdr.used_total = 1;
- cmd->data.setadapterparms.hdr.seq_no = 1;
- }
+ iob = qeth_ipa_alloc_cmd(card, IPA_CMD_SETADAPTERPARMS, QETH_PROT_IPV4,
+ data_length +
+ offsetof(struct qeth_ipacmd_setadpparms,
+ data));
+ if (!iob)
+ return NULL;
+ hdr = &__ipa_cmd(iob)->data.setadapterparms.hdr;
+ hdr->cmdlength = sizeof(*hdr) + data_length;
+ hdr->command_code = adp_cmd;
+ hdr->used_total = 1;
+ hdr->seq_no = 1;
return iob;
}
@@ -2939,7 +2791,7 @@ static int qeth_query_setadapterparms(struct qeth_card *card)
QETH_CARD_TEXT(card, 3, "queryadp");
iob = qeth_get_adapter_cmd(card, IPA_SETADP_QUERY_COMMANDS_SUPPORTED,
- sizeof(struct qeth_ipacmd_setadpparms));
+ SETADP_DATA_SIZEOF(query_cmds_supp));
if (!iob)
return -ENOMEM;
rc = qeth_send_ipa_cmd(card, iob, qeth_query_setadapterparms_cb, NULL);
@@ -2951,7 +2803,7 @@ static int qeth_query_ipassists_cb(struct qeth_card *card,
{
struct qeth_ipa_cmd *cmd;
- QETH_DBF_TEXT(SETUP, 2, "qipasscb");
+ QETH_CARD_TEXT(card, 2, "qipasscb");
cmd = (struct qeth_ipa_cmd *) data;
@@ -2960,7 +2812,7 @@ static int qeth_query_ipassists_cb(struct qeth_card *card,
break;
case IPA_RC_NOTSUPP:
case IPA_RC_L2_UNSUPPORTED_CMD:
- QETH_DBF_TEXT(SETUP, 2, "ipaunsup");
+ QETH_CARD_TEXT(card, 2, "ipaunsup");
card->options.ipa4.supported_funcs |= IPA_SETADAPTERPARMS;
card->options.ipa6.supported_funcs |= IPA_SETADAPTERPARMS;
return -EOPNOTSUPP;
@@ -2988,8 +2840,8 @@ static int qeth_query_ipassists(struct qeth_card *card,
int rc;
struct qeth_cmd_buffer *iob;
- QETH_DBF_TEXT_(SETUP, 2, "qipassi%i", prot);
- iob = qeth_get_ipacmd_buffer(card, IPA_CMD_QIPASSIST, prot);
+ QETH_CARD_TEXT_(card, 2, "qipassi%i", prot);
+ iob = qeth_ipa_alloc_cmd(card, IPA_CMD_QIPASSIST, prot, 0);
if (!iob)
return -ENOMEM;
rc = qeth_send_ipa_cmd(card, iob, qeth_query_ipassists_cb, NULL);
@@ -3026,14 +2878,32 @@ int qeth_query_switch_attributes(struct qeth_card *card,
return -EOPNOTSUPP;
if (!netif_carrier_ok(card->dev))
return -ENOMEDIUM;
- iob = qeth_get_adapter_cmd(card, IPA_SETADP_QUERY_SWITCH_ATTRIBUTES,
- sizeof(struct qeth_ipacmd_setadpparms_hdr));
+ iob = qeth_get_adapter_cmd(card, IPA_SETADP_QUERY_SWITCH_ATTRIBUTES, 0);
if (!iob)
return -ENOMEM;
return qeth_send_ipa_cmd(card, iob,
qeth_query_switch_attributes_cb, sw_info);
}
+struct qeth_cmd_buffer *qeth_get_diag_cmd(struct qeth_card *card,
+ enum qeth_diags_cmds sub_cmd,
+ unsigned int data_length)
+{
+ struct qeth_ipacmd_diagass *cmd;
+ struct qeth_cmd_buffer *iob;
+
+ iob = qeth_ipa_alloc_cmd(card, IPA_CMD_SET_DIAG_ASS, QETH_PROT_NONE,
+ DIAG_HDR_LEN + data_length);
+ if (!iob)
+ return NULL;
+
+ cmd = &__ipa_cmd(iob)->data.diagass;
+ cmd->subcmd_len = DIAG_SUB_HDR_LEN + data_length;
+ cmd->subcmd = sub_cmd;
+ return iob;
+}
+EXPORT_SYMBOL_GPL(qeth_get_diag_cmd);
+
static int qeth_query_setdiagass_cb(struct qeth_card *card,
struct qeth_reply *reply, unsigned long data)
{
@@ -3052,15 +2922,11 @@ static int qeth_query_setdiagass_cb(struct qeth_card *card,
static int qeth_query_setdiagass(struct qeth_card *card)
{
struct qeth_cmd_buffer *iob;
- struct qeth_ipa_cmd *cmd;
- QETH_DBF_TEXT(SETUP, 2, "qdiagass");
- iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SET_DIAG_ASS, 0);
+ QETH_CARD_TEXT(card, 2, "qdiagass");
+ iob = qeth_get_diag_cmd(card, QETH_DIAGS_CMD_QUERY, 0);
if (!iob)
return -ENOMEM;
- cmd = __ipa_cmd(iob);
- cmd->data.diagass.subcmd_len = 16;
- cmd->data.diagass.subcmd = QETH_DIAGS_CMD_QUERY;
return qeth_send_ipa_cmd(card, iob, qeth_query_setdiagass_cb, NULL);
}
@@ -3107,13 +2973,11 @@ int qeth_hw_trap(struct qeth_card *card, enum qeth_diags_trap_action action)
struct qeth_cmd_buffer *iob;
struct qeth_ipa_cmd *cmd;
- QETH_DBF_TEXT(SETUP, 2, "diagtrap");
- iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SET_DIAG_ASS, 0);
+ QETH_CARD_TEXT(card, 2, "diagtrap");
+ iob = qeth_get_diag_cmd(card, QETH_DIAGS_CMD_TRAP, 64);
if (!iob)
return -ENOMEM;
cmd = __ipa_cmd(iob);
- cmd->data.diagass.subcmd_len = 80;
- cmd->data.diagass.subcmd = QETH_DIAGS_CMD_TRAP;
cmd->data.diagass.type = 1;
cmd->data.diagass.action = action;
switch (action) {
@@ -3236,13 +3100,6 @@ static void qeth_handle_send_error(struct qeth_card *card,
int sbalf15 = buffer->buffer->element[15].sflags;
QETH_CARD_TEXT(card, 6, "hdsnderr");
- if (IS_IQD(card)) {
- if (sbalf15 == 0) {
- qdio_err = 0;
- } else {
- qdio_err = 1;
- }
- }
qeth_check_qdio_errors(card, buffer->buffer, qdio_err, "qouterr");
if (!qdio_err)
@@ -3730,8 +3587,8 @@ check_layout:
__elements = 1 + qeth_count_elements(skb, proto_len);
else
__elements = qeth_count_elements(skb, 0);
- } else if (!proto_len && qeth_get_elements_for_range(start, end) == 1) {
- /* Push HW header into a new page. */
+ } else if (!proto_len && PAGE_ALIGNED(skb->data)) {
+ /* Push HW header into preceding page, flush with skb->data. */
push_ok = true;
__elements = 1 + qeth_count_elements(skb, 0);
} else {
@@ -3785,18 +3642,16 @@ static void __qeth_fill_buffer(struct sk_buff *skb,
int element = buf->next_element_to_fill;
int length = skb_headlen(skb) - offset;
char *data = skb->data + offset;
- int length_here, cnt;
+ unsigned int elem_length, cnt;
/* map linear part into buffer element(s) */
while (length > 0) {
- /* length_here is the remaining amount of data in this page */
- length_here = PAGE_SIZE - ((unsigned long) data % PAGE_SIZE);
- if (length < length_here)
- length_here = length;
+ elem_length = min_t(unsigned int, length,
+ PAGE_SIZE - offset_in_page(data));
buffer->element[element].addr = data;
- buffer->element[element].length = length_here;
- length -= length_here;
+ buffer->element[element].length = elem_length;
+ length -= elem_length;
if (is_first_elem) {
is_first_elem = false;
if (length || skb_is_nonlinear(skb))
@@ -3809,7 +3664,8 @@ static void __qeth_fill_buffer(struct sk_buff *skb,
buffer->element[element].eflags =
SBAL_EFLAGS_MIDDLE_FRAG;
}
- data += length_here;
+
+ data += elem_length;
element++;
}
@@ -3820,17 +3676,16 @@ static void __qeth_fill_buffer(struct sk_buff *skb,
data = skb_frag_address(frag);
length = skb_frag_size(frag);
while (length > 0) {
- length_here = PAGE_SIZE -
- ((unsigned long) data % PAGE_SIZE);
- if (length < length_here)
- length_here = length;
+ elem_length = min_t(unsigned int, length,
+ PAGE_SIZE - offset_in_page(data));
buffer->element[element].addr = data;
- buffer->element[element].length = length_here;
+ buffer->element[element].length = elem_length;
buffer->element[element].eflags =
SBAL_EFLAGS_MIDDLE_FRAG;
- length -= length_here;
- data += length_here;
+
+ length -= elem_length;
+ data += elem_length;
element++;
}
}
@@ -4053,11 +3908,10 @@ static void qeth_fill_tso_ext(struct qeth_hdr_tso *hdr,
}
int qeth_xmit(struct qeth_card *card, struct sk_buff *skb,
- struct qeth_qdio_out_q *queue, int ipv, int cast_type,
+ struct qeth_qdio_out_q *queue, int ipv,
void (*fill_header)(struct qeth_qdio_out_q *queue,
struct qeth_hdr *hdr, struct sk_buff *skb,
- int ipv, int cast_type,
- unsigned int data_len))
+ int ipv, unsigned int data_len))
{
unsigned int proto_len, hw_hdr_len;
unsigned int frame_len = skb->len;
@@ -4091,7 +3945,7 @@ int qeth_xmit(struct qeth_card *card, struct sk_buff *skb,
data_offset = push_len + proto_len;
}
memset(hdr, 0, hw_hdr_len);
- fill_header(queue, hdr, skb, ipv, cast_type, frame_len);
+ fill_header(queue, hdr, skb, ipv, frame_len);
if (is_tso)
qeth_fill_tso_ext((struct qeth_hdr_tso *) hdr,
frame_len - proto_len, skb, proto_len);
@@ -4160,7 +4014,7 @@ void qeth_setadp_promisc_mode(struct qeth_card *card)
QETH_CARD_TEXT_(card, 4, "mode:%x", mode);
iob = qeth_get_adapter_cmd(card, IPA_SETADP_SET_PROMISC_MODE,
- sizeof(struct qeth_ipacmd_setadpparms_hdr) + 8);
+ SETADP_DATA_SIZEOF(mode));
if (!iob)
return;
cmd = __ipa_cmd(iob);
@@ -4200,8 +4054,7 @@ int qeth_setadpparms_change_macaddr(struct qeth_card *card)
QETH_CARD_TEXT(card, 4, "chgmac");
iob = qeth_get_adapter_cmd(card, IPA_SETADP_ALTER_MAC_ADDRESS,
- sizeof(struct qeth_ipacmd_setadpparms_hdr) +
- sizeof(struct qeth_change_addr));
+ SETADP_DATA_SIZEOF(change_addr));
if (!iob)
return -ENOMEM;
cmd = __ipa_cmd(iob);
@@ -4228,10 +4081,8 @@ static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card,
qeth_setadpparms_inspect_rc(cmd);
access_ctrl_req = &cmd->data.setadapterparms.data.set_access_ctrl;
- QETH_DBF_TEXT_(SETUP, 2, "setaccb");
- QETH_DBF_TEXT_(SETUP, 2, "%s", card->gdev->dev.kobj.name);
- QETH_DBF_TEXT_(SETUP, 2, "rc=%d",
- cmd->data.setadapterparms.hdr.return_code);
+ QETH_CARD_TEXT_(card, 2, "rc=%d",
+ cmd->data.setadapterparms.hdr.return_code);
if (cmd->data.setadapterparms.hdr.return_code !=
SET_ACCESS_CTRL_RC_SUCCESS)
QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_CTRL(%#x) on device %x: %#x\n",
@@ -4311,12 +4162,8 @@ static int qeth_setadpparms_set_access_ctrl(struct qeth_card *card,
QETH_CARD_TEXT(card, 4, "setacctl");
- QETH_DBF_TEXT_(SETUP, 2, "setacctl");
- QETH_DBF_TEXT_(SETUP, 2, "%s", card->gdev->dev.kobj.name);
-
iob = qeth_get_adapter_cmd(card, IPA_SETADP_SET_ACCESS_CONTROL,
- sizeof(struct qeth_ipacmd_setadpparms_hdr) +
- sizeof(struct qeth_set_access_ctrl));
+ SETADP_DATA_SIZEOF(set_access_ctrl));
if (!iob)
return -ENOMEM;
cmd = __ipa_cmd(iob);
@@ -4325,7 +4172,7 @@ static int qeth_setadpparms_set_access_ctrl(struct qeth_card *card,
rc = qeth_send_ipa_cmd(card, iob, qeth_setadpparms_set_access_ctrl_cb,
&fallback);
- QETH_DBF_TEXT_(SETUP, 2, "rc=%d", rc);
+ QETH_CARD_TEXT_(card, 2, "rc=%d", rc);
return rc;
}
@@ -4472,18 +4319,13 @@ static int qeth_snmp_command_cb(struct qeth_card *card,
return -ENOSPC;
}
QETH_CARD_TEXT_(card, 4, "snore%i",
- cmd->data.setadapterparms.hdr.used_total);
+ cmd->data.setadapterparms.hdr.used_total);
QETH_CARD_TEXT_(card, 4, "sseqn%i",
- cmd->data.setadapterparms.hdr.seq_no);
+ cmd->data.setadapterparms.hdr.seq_no);
/*copy entries to user buffer*/
memcpy(qinfo->udata + qinfo->udata_offset, snmp_data, data_len);
qinfo->udata_offset += data_len;
- /* check if all replies received ... */
- QETH_CARD_TEXT_(card, 4, "srtot%i",
- cmd->data.setadapterparms.hdr.used_total);
- QETH_CARD_TEXT_(card, 4, "srseq%i",
- cmd->data.setadapterparms.hdr.seq_no);
if (cmd->data.setadapterparms.hdr.seq_no <
cmd->data.setadapterparms.hdr.used_total)
return 1;
@@ -4492,9 +4334,8 @@ static int qeth_snmp_command_cb(struct qeth_card *card,
static int qeth_snmp_command(struct qeth_card *card, char __user *udata)
{
+ struct qeth_snmp_ureq __user *ureq;
struct qeth_cmd_buffer *iob;
- struct qeth_ipa_cmd *cmd;
- struct qeth_snmp_ureq *ureq;
unsigned int req_len;
struct qeth_arp_query_info qinfo = {0, };
int rc = 0;
@@ -4508,38 +4349,28 @@ static int qeth_snmp_command(struct qeth_card *card, char __user *udata)
IS_LAYER3(card))
return -EOPNOTSUPP;
- /* skip 4 bytes (data_len struct member) to get req_len */
- if (copy_from_user(&req_len, udata + sizeof(int), sizeof(int)))
+ ureq = (struct qeth_snmp_ureq __user *) udata;
+ if (get_user(qinfo.udata_len, &ureq->hdr.data_len) ||
+ get_user(req_len, &ureq->hdr.req_len))
+ return -EFAULT;
+
+ iob = qeth_get_adapter_cmd(card, IPA_SETADP_SET_SNMP_CONTROL, req_len);
+ if (!iob)
+ return -ENOMEM;
+
+ if (copy_from_user(&__ipa_cmd(iob)->data.setadapterparms.data.snmp,
+ &ureq->cmd, req_len)) {
+ qeth_put_cmd(iob);
return -EFAULT;
- if (req_len > (QETH_BUFSIZE - IPA_PDU_HEADER_SIZE -
- sizeof(struct qeth_ipacmd_hdr) -
- sizeof(struct qeth_ipacmd_setadpparms_hdr)))
- return -EINVAL;
- ureq = memdup_user(udata, req_len + sizeof(struct qeth_snmp_ureq_hdr));
- if (IS_ERR(ureq)) {
- QETH_CARD_TEXT(card, 2, "snmpnome");
- return PTR_ERR(ureq);
}
- qinfo.udata_len = ureq->hdr.data_len;
+
qinfo.udata = kzalloc(qinfo.udata_len, GFP_KERNEL);
if (!qinfo.udata) {
- kfree(ureq);
+ qeth_put_cmd(iob);
return -ENOMEM;
}
qinfo.udata_offset = sizeof(struct qeth_snmp_ureq_hdr);
- iob = qeth_get_adapter_cmd(card, IPA_SETADP_SET_SNMP_CONTROL,
- QETH_SNMP_SETADP_CMDLENGTH + req_len);
- if (!iob) {
- rc = -ENOMEM;
- goto out;
- }
-
- /* for large requests, fix-up the length fields: */
- qeth_prepare_ipa_cmd(card, iob, QETH_SETADP_BASE_LEN + req_len);
-
- cmd = __ipa_cmd(iob);
- memcpy(&cmd->data.setadapterparms.data.snmp, &ureq->cmd, req_len);
rc = qeth_send_ipa_cmd(card, iob, qeth_snmp_command_cb, &qinfo);
if (rc)
QETH_DBF_MESSAGE(2, "SNMP command failed on device %x: (%#x)\n",
@@ -4548,8 +4379,7 @@ static int qeth_snmp_command(struct qeth_card *card, char __user *udata)
if (copy_to_user(udata, qinfo.udata, qinfo.udata_len))
rc = -EFAULT;
}
-out:
- kfree(ureq);
+
kfree(qinfo.udata);
return rc;
}
@@ -4615,8 +4445,7 @@ static int qeth_query_oat_command(struct qeth_card *card, char __user *udata)
}
iob = qeth_get_adapter_cmd(card, IPA_SETADP_QUERY_OAT,
- sizeof(struct qeth_ipacmd_setadpparms_hdr) +
- sizeof(struct qeth_query_oat));
+ SETADP_DATA_SIZEOF(query_oat));
if (!iob) {
rc = -ENOMEM;
goto out_free;
@@ -4678,8 +4507,7 @@ int qeth_query_card_info(struct qeth_card *card,
QETH_CARD_TEXT(card, 2, "qcrdinfo");
if (!qeth_adp_supported(card, IPA_SETADP_QUERY_CARD_INFO))
return -EOPNOTSUPP;
- iob = qeth_get_adapter_cmd(card, IPA_SETADP_QUERY_CARD_INFO,
- sizeof(struct qeth_ipacmd_setadpparms_hdr));
+ iob = qeth_get_adapter_cmd(card, IPA_SETADP_QUERY_CARD_INFO, 0);
if (!iob)
return -ENOMEM;
return qeth_send_ipa_cmd(card, iob, qeth_query_card_info_cb,
@@ -4701,7 +4529,7 @@ int qeth_vm_request_mac(struct qeth_card *card)
struct ccw_dev_id id;
int rc;
- QETH_DBF_TEXT(SETUP, 2, "vmreqmac");
+ QETH_CARD_TEXT(card, 2, "vmreqmac");
request = kzalloc(sizeof(*request), GFP_KERNEL | GFP_DMA);
response = kzalloc(sizeof(*response), GFP_KERNEL | GFP_DMA);
@@ -4726,13 +4554,13 @@ int qeth_vm_request_mac(struct qeth_card *card)
if (request->resp_buf_len < sizeof(*response) ||
response->version != request->resp_version) {
rc = -EIO;
- QETH_DBF_TEXT(SETUP, 2, "badresp");
- QETH_DBF_HEX(SETUP, 2, &request->resp_buf_len,
- sizeof(request->resp_buf_len));
+ QETH_CARD_TEXT(card, 2, "badresp");
+ QETH_CARD_HEX(card, 2, &request->resp_buf_len,
+ sizeof(request->resp_buf_len));
} else if (!is_valid_ether_addr(response->mac)) {
rc = -EINVAL;
- QETH_DBF_TEXT(SETUP, 2, "badmac");
- QETH_DBF_HEX(SETUP, 2, response->mac, ETH_ALEN);
+ QETH_CARD_TEXT(card, 2, "badmac");
+ QETH_CARD_HEX(card, 2, response->mac, ETH_ALEN);
} else {
ether_addr_copy(card->dev->dev_addr, response->mac);
}
@@ -4747,43 +4575,37 @@ EXPORT_SYMBOL_GPL(qeth_vm_request_mac);
static void qeth_determine_capabilities(struct qeth_card *card)
{
int rc;
- int length;
- char *prcd;
struct ccw_device *ddev;
int ddev_offline = 0;
- QETH_DBF_TEXT(SETUP, 2, "detcapab");
+ QETH_CARD_TEXT(card, 2, "detcapab");
ddev = CARD_DDEV(card);
if (!ddev->online) {
ddev_offline = 1;
rc = ccw_device_set_online(ddev);
if (rc) {
- QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
+ QETH_CARD_TEXT_(card, 2, "3err%d", rc);
goto out;
}
}
- rc = qeth_read_conf_data(card, (void **) &prcd, &length);
+ rc = qeth_read_conf_data(card);
if (rc) {
QETH_DBF_MESSAGE(2, "qeth_read_conf_data on device %x returned %i\n",
CARD_DEVID(card), rc);
- QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc);
+ QETH_CARD_TEXT_(card, 2, "5err%d", rc);
goto out_offline;
}
- qeth_configure_unitaddr(card, prcd);
- if (ddev_offline)
- qeth_configure_blkt_default(card, prcd);
- kfree(prcd);
rc = qdio_get_ssqd_desc(ddev, &card->ssqd);
if (rc)
- QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc);
+ QETH_CARD_TEXT_(card, 2, "6err%d", rc);
- QETH_DBF_TEXT_(SETUP, 2, "qfmt%d", card->ssqd.qfmt);
- QETH_DBF_TEXT_(SETUP, 2, "ac1:%02x", card->ssqd.qdioac1);
- QETH_DBF_TEXT_(SETUP, 2, "ac2:%04x", card->ssqd.qdioac2);
- QETH_DBF_TEXT_(SETUP, 2, "ac3:%04x", card->ssqd.qdioac3);
- QETH_DBF_TEXT_(SETUP, 2, "icnt%d", card->ssqd.icnt);
+ QETH_CARD_TEXT_(card, 2, "qfmt%d", card->ssqd.qfmt);
+ QETH_CARD_TEXT_(card, 2, "ac1:%02x", card->ssqd.qdioac1);
+ QETH_CARD_TEXT_(card, 2, "ac2:%04x", card->ssqd.qdioac2);
+ QETH_CARD_TEXT_(card, 2, "ac3:%04x", card->ssqd.qdioac3);
+ QETH_CARD_TEXT_(card, 2, "icnt%d", card->ssqd.icnt);
if (!((card->ssqd.qfmt != QDIO_IQDIO_QFMT) ||
((card->ssqd.qdioac1 & CHSC_AC1_INITIATE_INPUTQ) == 0) ||
((card->ssqd.qdioac3 & CHSC_AC3_FORMAT2_CQ_AVAILABLE) == 0))) {
@@ -4831,7 +4653,7 @@ static int qeth_qdio_establish(struct qeth_card *card)
int i, j, k;
int rc = 0;
- QETH_DBF_TEXT(SETUP, 2, "qdioest");
+ QETH_CARD_TEXT(card, 2, "qdioest");
qib_param_field = kzalloc(QDIO_MAX_BUFFERS_PER_Q,
GFP_KERNEL);
@@ -4935,11 +4757,11 @@ out_free_nothing:
static void qeth_core_free_card(struct qeth_card *card)
{
- QETH_DBF_TEXT(SETUP, 2, "freecrd");
- QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
+ QETH_CARD_TEXT(card, 2, "freecrd");
qeth_clean_channel(&card->read);
qeth_clean_channel(&card->write);
qeth_clean_channel(&card->data);
+ qeth_put_cmd(card->read_cmd);
destroy_workqueue(card->event_wq);
qeth_free_qdio_queues(card);
unregister_service_level(&card->qeth_service_level);
@@ -4988,7 +4810,7 @@ int qeth_core_hardsetup_card(struct qeth_card *card, bool *carrier_ok)
int retries = 3;
int rc;
- QETH_DBF_TEXT(SETUP, 2, "hrdsetup");
+ QETH_CARD_TEXT(card, 2, "hrdsetup");
atomic_set(&card->force_alloc_skb, 0);
rc = qeth_update_from_chp_desc(card);
if (rc)
@@ -5013,10 +4835,10 @@ retry:
goto retriable;
retriable:
if (rc == -ERESTARTSYS) {
- QETH_DBF_TEXT(SETUP, 2, "break1");
+ QETH_CARD_TEXT(card, 2, "break1");
return rc;
} else if (rc) {
- QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
+ QETH_CARD_TEXT_(card, 2, "1err%d", rc);
if (--retries < 0)
goto out;
else
@@ -5028,10 +4850,10 @@ retriable:
rc = qeth_idx_activate_read_channel(card);
if (rc == -EINTR) {
- QETH_DBF_TEXT(SETUP, 2, "break2");
+ QETH_CARD_TEXT(card, 2, "break2");
return rc;
} else if (rc) {
- QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
+ QETH_CARD_TEXT_(card, 2, "3err%d", rc);
if (--retries < 0)
goto out;
else
@@ -5040,10 +4862,10 @@ retriable:
rc = qeth_idx_activate_write_channel(card);
if (rc == -EINTR) {
- QETH_DBF_TEXT(SETUP, 2, "break3");
+ QETH_CARD_TEXT(card, 2, "break3");
return rc;
} else if (rc) {
- QETH_DBF_TEXT_(SETUP, 2, "4err%d", rc);
+ QETH_CARD_TEXT_(card, 2, "4err%d", rc);
if (--retries < 0)
goto out;
else
@@ -5052,13 +4874,13 @@ retriable:
card->read_or_write_problem = 0;
rc = qeth_mpc_initialize(card);
if (rc) {
- QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc);
+ QETH_CARD_TEXT_(card, 2, "5err%d", rc);
goto out;
}
rc = qeth_send_startlan(card);
if (rc) {
- QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc);
+ QETH_CARD_TEXT_(card, 2, "6err%d", rc);
if (rc == -ENETDOWN) {
dev_warn(&card->gdev->dev, "The LAN is offline\n");
*carrier_ok = false;
@@ -5085,14 +4907,14 @@ retriable:
if (qeth_is_supported(card, IPA_SETADAPTERPARMS)) {
rc = qeth_query_setadapterparms(card);
if (rc < 0) {
- QETH_DBF_TEXT_(SETUP, 2, "7err%d", rc);
+ QETH_CARD_TEXT_(card, 2, "7err%d", rc);
goto out;
}
}
if (qeth_adp_supported(card, IPA_SETADP_SET_DIAG_ASSIST)) {
rc = qeth_query_setdiagass(card);
if (rc < 0) {
- QETH_DBF_TEXT_(SETUP, 2, "8err%d", rc);
+ QETH_CARD_TEXT_(card, 2, "8err%d", rc);
goto out;
}
}
@@ -5352,42 +5174,47 @@ EXPORT_SYMBOL_GPL(qeth_setassparms_cb);
struct qeth_cmd_buffer *qeth_get_setassparms_cmd(struct qeth_card *card,
enum qeth_ipa_funcs ipa_func,
- __u16 cmd_code, __u16 len,
+ u16 cmd_code,
+ unsigned int data_length,
enum qeth_prot_versions prot)
{
+ struct qeth_ipacmd_setassparms *setassparms;
+ struct qeth_ipacmd_setassparms_hdr *hdr;
struct qeth_cmd_buffer *iob;
- struct qeth_ipa_cmd *cmd;
QETH_CARD_TEXT(card, 4, "getasscm");
- iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETASSPARMS, prot);
+ iob = qeth_ipa_alloc_cmd(card, IPA_CMD_SETASSPARMS, prot,
+ data_length +
+ offsetof(struct qeth_ipacmd_setassparms,
+ data));
+ if (!iob)
+ return NULL;
- if (iob) {
- cmd = __ipa_cmd(iob);
- cmd->data.setassparms.hdr.assist_no = ipa_func;
- cmd->data.setassparms.hdr.length = 8 + len;
- cmd->data.setassparms.hdr.command_code = cmd_code;
- }
+ setassparms = &__ipa_cmd(iob)->data.setassparms;
+ setassparms->assist_no = ipa_func;
+ hdr = &setassparms->hdr;
+ hdr->length = sizeof(*hdr) + data_length;
+ hdr->command_code = cmd_code;
return iob;
}
EXPORT_SYMBOL_GPL(qeth_get_setassparms_cmd);
int qeth_send_simple_setassparms_prot(struct qeth_card *card,
enum qeth_ipa_funcs ipa_func,
- u16 cmd_code, long data,
+ u16 cmd_code, u32 *data,
enum qeth_prot_versions prot)
{
- int length = 0;
+ unsigned int length = data ? SETASS_DATA_SIZEOF(flags_32bit) : 0;
struct qeth_cmd_buffer *iob;
QETH_CARD_TEXT_(card, 4, "simassp%i", prot);
- if (data)
- length = sizeof(__u32);
iob = qeth_get_setassparms_cmd(card, ipa_func, cmd_code, length, prot);
if (!iob)
return -ENOMEM;
- __ipa_cmd(iob)->data.setassparms.data.flags_32bit = (__u32) data;
+ if (data)
+ __ipa_cmd(iob)->data.setassparms.data.flags_32bit = *data;
return qeth_send_ipa_cmd(card, iob, qeth_setassparms_cb, NULL);
}
EXPORT_SYMBOL_GPL(qeth_send_simple_setassparms_prot);
@@ -5670,6 +5497,8 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
if (rc)
goto err_chp_desc;
qeth_determine_capabilities(card);
+ qeth_set_blkt_defaults(card);
+
enforced_disc = qeth_enforce_discipline(card);
switch (enforced_disc) {
case QETH_DISCIPLINE_UNDETERMINED:
@@ -5707,7 +5536,7 @@ static void qeth_core_remove_device(struct ccwgroup_device *gdev)
{
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
- QETH_DBF_TEXT(SETUP, 2, "removedv");
+ QETH_CARD_TEXT(card, 2, "removedv");
if (card->discipline) {
card->discipline->remove(gdev);
@@ -5759,28 +5588,30 @@ static void qeth_core_shutdown(struct ccwgroup_device *gdev)
qdio_free(CARD_DDEV(card));
}
-static int qeth_core_freeze(struct ccwgroup_device *gdev)
+static int qeth_suspend(struct ccwgroup_device *gdev)
{
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
- if (card->discipline && card->discipline->freeze)
- return card->discipline->freeze(gdev);
- return 0;
-}
-static int qeth_core_thaw(struct ccwgroup_device *gdev)
-{
- struct qeth_card *card = dev_get_drvdata(&gdev->dev);
- if (card->discipline && card->discipline->thaw)
- return card->discipline->thaw(gdev);
+ qeth_set_allowed_threads(card, 0, 1);
+ wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
+ if (gdev->state == CCWGROUP_OFFLINE)
+ return 0;
+
+ card->discipline->set_offline(gdev);
return 0;
}
-static int qeth_core_restore(struct ccwgroup_device *gdev)
+static int qeth_resume(struct ccwgroup_device *gdev)
{
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
- if (card->discipline && card->discipline->restore)
- return card->discipline->restore(gdev);
- return 0;
+ int rc;
+
+ rc = card->discipline->set_online(gdev);
+
+ qeth_set_allowed_threads(card, 0xffffffff, 0);
+ if (rc)
+ dev_warn(&card->gdev->dev, "The qeth device driver failed to recover an error on the device\n");
+ return rc;
}
static ssize_t group_store(struct device_driver *ddrv, const char *buf,
@@ -5821,9 +5652,9 @@ static struct ccwgroup_driver qeth_core_ccwgroup_driver = {
.shutdown = qeth_core_shutdown,
.prepare = NULL,
.complete = NULL,
- .freeze = qeth_core_freeze,
- .thaw = qeth_core_thaw,
- .restore = qeth_core_restore,
+ .freeze = qeth_suspend,
+ .thaw = qeth_resume,
+ .restore = qeth_resume,
};
struct qeth_card *qeth_get_card_by_busid(char *bus_id)
@@ -5902,8 +5733,8 @@ static int qeth_start_csum_cb(struct qeth_card *card, struct qeth_reply *reply,
static int qeth_set_csum_off(struct qeth_card *card, enum qeth_ipa_funcs cstype,
enum qeth_prot_versions prot)
{
- return qeth_send_simple_setassparms_prot(card, cstype,
- IPA_CMD_ASS_STOP, 0, prot);
+ return qeth_send_simple_setassparms_prot(card, cstype, IPA_CMD_ASS_STOP,
+ NULL, prot);
}
static int qeth_set_csum_on(struct qeth_card *card, enum qeth_ipa_funcs cstype,
@@ -5934,7 +5765,8 @@ static int qeth_set_csum_on(struct qeth_card *card, enum qeth_ipa_funcs cstype,
return -EOPNOTSUPP;
}
- iob = qeth_get_setassparms_cmd(card, cstype, IPA_CMD_ASS_ENABLE, 4,
+ iob = qeth_get_setassparms_cmd(card, cstype, IPA_CMD_ASS_ENABLE,
+ SETASS_DATA_SIZEOF(flags_32bit),
prot);
if (!iob) {
qeth_set_csum_off(card, cstype, prot);
@@ -5991,7 +5823,7 @@ static int qeth_set_tso_off(struct qeth_card *card,
enum qeth_prot_versions prot)
{
return qeth_send_simple_setassparms_prot(card, IPA_OUTBOUND_TSO,
- IPA_CMD_ASS_STOP, 0, prot);
+ IPA_CMD_ASS_STOP, NULL, prot);
}
static int qeth_set_tso_on(struct qeth_card *card,
@@ -6017,7 +5849,8 @@ static int qeth_set_tso_on(struct qeth_card *card,
}
iob = qeth_get_setassparms_cmd(card, IPA_OUTBOUND_TSO,
- IPA_CMD_ASS_ENABLE, sizeof(caps), prot);
+ IPA_CMD_ASS_ENABLE,
+ SETASS_DATA_SIZEOF(caps), prot);
if (!iob) {
qeth_set_tso_off(card, prot);
return -ENOMEM;
@@ -6104,8 +5937,8 @@ int qeth_set_features(struct net_device *dev, netdev_features_t features)
netdev_features_t changed = dev->features ^ features;
int rc = 0;
- QETH_DBF_TEXT(SETUP, 2, "setfeat");
- QETH_DBF_HEX(SETUP, 2, &features, sizeof(features));
+ QETH_CARD_TEXT(card, 2, "setfeat");
+ QETH_CARD_HEX(card, 2, &features, sizeof(features));
if ((changed & NETIF_F_IP_CSUM)) {
rc = qeth_set_ipa_csum(card, features & NETIF_F_IP_CSUM,
@@ -6151,7 +5984,7 @@ netdev_features_t qeth_fix_features(struct net_device *dev,
{
struct qeth_card *card = dev->ml_priv;
- QETH_DBF_TEXT(SETUP, 2, "fixfeat");
+ QETH_CARD_TEXT(card, 2, "fixfeat");
if (!qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM))
features &= ~NETIF_F_IP_CSUM;
if (!qeth_is_supported6(card, IPA_OUTBOUND_CHECKSUM_V6))
@@ -6164,7 +5997,7 @@ netdev_features_t qeth_fix_features(struct net_device *dev,
if (!qeth_is_supported6(card, IPA_OUTBOUND_TSO))
features &= ~NETIF_F_TSO6;
- QETH_DBF_HEX(SETUP, 2, &features, sizeof(features));
+ QETH_CARD_HEX(card, 2, &features, sizeof(features));
return features;
}
EXPORT_SYMBOL_GPL(qeth_fix_features);
diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h
index f5237b7c14c4..75b5834ed28d 100644
--- a/drivers/s390/net/qeth_core_mpc.h
+++ b/drivers/s390/net/qeth_core_mpc.h
@@ -31,14 +31,12 @@ extern unsigned char IPA_PDU_HEADER[];
#define QETH_CLEAR_CHANNEL_PARM -10
#define QETH_HALT_CHANNEL_PARM -11
-#define QETH_RCD_PARM -12
static inline bool qeth_intparm_is_iob(unsigned long intparm)
{
switch (intparm) {
case QETH_CLEAR_CHANNEL_PARM:
case QETH_HALT_CHANNEL_PARM:
- case QETH_RCD_PARM:
case 0:
return false;
}
@@ -381,9 +379,7 @@ struct qeth_ipacmd_layer2setdelvlan {
__u16 vlan_id;
} __attribute__ ((packed));
-
struct qeth_ipacmd_setassparms_hdr {
- __u32 assist_no;
__u16 length;
__u16 command_code;
__u16 return_code;
@@ -428,6 +424,7 @@ struct qeth_tso_start_data {
/* SETASSPARMS IPA Command: */
struct qeth_ipacmd_setassparms {
+ u32 assist_no;
struct qeth_ipacmd_setassparms_hdr hdr;
union {
__u32 flags_32bit;
@@ -439,6 +436,8 @@ struct qeth_ipacmd_setassparms {
} data;
} __attribute__ ((packed));
+#define SETASS_DATA_SIZEOF(field) FIELD_SIZEOF(struct qeth_ipacmd_setassparms,\
+ data.field)
/* SETRTG IPA Command: ****************************************************/
struct qeth_set_routing {
@@ -526,8 +525,6 @@ struct qeth_query_switch_attributes {
#define QETH_SETADP_FLAGS_VIRTUAL_MAC 0x80 /* for CHANGE_ADDR_READ_MAC */
struct qeth_ipacmd_setadpparms_hdr {
- u32 supp_hw_cmds;
- u32 reserved1;
u16 cmdlength;
u16 reserved2;
u32 command_code;
@@ -539,6 +536,7 @@ struct qeth_ipacmd_setadpparms_hdr {
};
struct qeth_ipacmd_setadpparms {
+ struct qeth_ipa_caps hw_cmds;
struct qeth_ipacmd_setadpparms_hdr hdr;
union {
struct qeth_query_cmds_supp query_cmds_supp;
@@ -552,6 +550,9 @@ struct qeth_ipacmd_setadpparms {
} data;
} __attribute__ ((packed));
+#define SETADP_DATA_SIZEOF(field) FIELD_SIZEOF(struct qeth_ipacmd_setadpparms,\
+ data.field)
+
/* CREATE_ADDR IPA Command: ***********************************************/
struct qeth_create_destroy_address {
__u8 unique_id[8];
@@ -598,6 +599,11 @@ struct qeth_ipacmd_diagass {
__u8 cdata[64];
} __attribute__ ((packed));
+#define DIAG_HDR_LEN offsetofend(struct qeth_ipacmd_diagass, ext)
+#define DIAG_SUB_HDR_LEN (offsetofend(struct qeth_ipacmd_diagass, ext) -\
+ offsetof(struct qeth_ipacmd_diagass, \
+ subcmd_len))
+
/* VNIC Characteristics IPA Command: *****************************************/
/* IPA commands/sub commands for VNICC */
#define IPA_VNICC_QUERY_CHARS 0x00000000L
@@ -624,12 +630,6 @@ struct qeth_ipacmd_diagass {
/* VNICC header */
struct qeth_ipacmd_vnicc_hdr {
- u32 sup;
- u32 cur;
-};
-
-/* VNICC sub command header */
-struct qeth_vnicc_sub_hdr {
u16 data_length;
u16 reserved;
u32 sub_command;
@@ -654,15 +654,18 @@ struct qeth_vnicc_getset_timeout {
/* complete VNICC IPA command message */
struct qeth_ipacmd_vnicc {
+ struct qeth_ipa_caps vnicc_cmds;
struct qeth_ipacmd_vnicc_hdr hdr;
- struct qeth_vnicc_sub_hdr sub_hdr;
union {
struct qeth_vnicc_query_cmds query_cmds;
struct qeth_vnicc_set_char set_char;
struct qeth_vnicc_getset_timeout getset_timeout;
- };
+ } data;
};
+#define VNICC_DATA_SIZEOF(field) FIELD_SIZEOF(struct qeth_ipacmd_vnicc,\
+ data.field)
+
/* SETBRIDGEPORT IPA Command: *********************************************/
enum qeth_ipa_sbp_cmd {
IPA_SBP_QUERY_COMMANDS_SUPPORTED = 0x00000000L,
@@ -688,8 +691,6 @@ struct mac_addr_lnid {
} __packed;
struct qeth_ipacmd_sbp_hdr {
- __u32 supported_sbp_cmds;
- __u32 enabled_sbp_cmds;
__u16 cmdlength;
__u16 reserved1;
__u32 command_code;
@@ -704,16 +705,10 @@ struct qeth_sbp_query_cmds_supp {
__u32 reserved;
} __packed;
-struct qeth_sbp_reset_role {
-} __packed;
-
struct qeth_sbp_set_primary {
struct net_if_token token;
} __packed;
-struct qeth_sbp_set_secondary {
-} __packed;
-
struct qeth_sbp_port_entry {
__u8 role;
__u8 state;
@@ -739,17 +734,19 @@ struct qeth_sbp_state_change {
} __packed;
struct qeth_ipacmd_setbridgeport {
+ struct qeth_ipa_caps sbp_cmds;
struct qeth_ipacmd_sbp_hdr hdr;
union {
struct qeth_sbp_query_cmds_supp query_cmds_supp;
- struct qeth_sbp_reset_role reset_role;
struct qeth_sbp_set_primary set_primary;
- struct qeth_sbp_set_secondary set_secondary;
struct qeth_sbp_query_ports query_ports;
struct qeth_sbp_state_change state_change;
} data;
} __packed;
+#define SBP_DATA_SIZEOF(field) FIELD_SIZEOF(struct qeth_ipacmd_setbridgeport,\
+ data.field)
+
/* ADDRESS_CHANGE_NOTIFICATION adapter-initiated "command" *******************/
/* Bitmask for entry->change_code. Both bits may be raised. */
enum qeth_ipa_addr_change_code {
@@ -808,6 +805,8 @@ struct qeth_ipa_cmd {
} data;
} __attribute__ ((packed));
+#define IPA_DATA_SIZEOF(field) FIELD_SIZEOF(struct qeth_ipa_cmd, data.field)
+
/*
* special command for ARP processing.
* this is not included in setassparms command before, because we get
@@ -825,10 +824,6 @@ enum qeth_ipa_arp_return_codes {
extern const char *qeth_get_ipa_msg(enum qeth_ipa_return_codes rc);
extern const char *qeth_get_ipa_cmd_name(enum qeth_ipa_cmds cmd);
-#define QETH_SETADP_BASE_LEN (sizeof(struct qeth_ipacmd_hdr) + \
- sizeof(struct qeth_ipacmd_setadpparms_hdr))
-#define QETH_SNMP_SETADP_CMDLENGTH 16
-
/* Helper functions */
#define IS_IPA_REPLY(cmd) ((cmd->hdr.initiator == IPA_CMD_INITIATOR_HOST) || \
(cmd->hdr.initiator == IPA_CMD_INITIATOR_OSA_REPLY))
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index ff8a6cd790b1..fd64bc3f4062 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -85,7 +85,8 @@ static int qeth_l2_send_setdelmac(struct qeth_card *card, __u8 *mac,
struct qeth_cmd_buffer *iob;
QETH_CARD_TEXT(card, 2, "L2sdmac");
- iob = qeth_get_ipacmd_buffer(card, ipacmd, QETH_PROT_IPV4);
+ iob = qeth_ipa_alloc_cmd(card, ipacmd, QETH_PROT_IPV4,
+ IPA_DATA_SIZEOF(setdelmac));
if (!iob)
return -ENOMEM;
cmd = __ipa_cmd(iob);
@@ -163,8 +164,9 @@ static void qeth_l2_drain_rx_mode_cache(struct qeth_card *card)
static void qeth_l2_fill_header(struct qeth_qdio_out_q *queue,
struct qeth_hdr *hdr, struct sk_buff *skb,
- int ipv, int cast_type, unsigned int data_len)
+ int ipv, unsigned int data_len)
{
+ int cast_type = qeth_get_ether_cast_type(skb);
struct vlan_ethhdr *veth = vlan_eth_hdr(skb);
hdr->hdr.l2.pkt_length = data_len;
@@ -240,7 +242,8 @@ static int qeth_l2_send_setdelvlan(struct qeth_card *card, __u16 i,
struct qeth_cmd_buffer *iob;
QETH_CARD_TEXT_(card, 4, "L2sdv%x", ipacmd);
- iob = qeth_get_ipacmd_buffer(card, ipacmd, QETH_PROT_IPV4);
+ iob = qeth_ipa_alloc_cmd(card, ipacmd, QETH_PROT_IPV4,
+ IPA_DATA_SIZEOF(setdelvlan));
if (!iob)
return -ENOMEM;
cmd = __ipa_cmd(iob);
@@ -274,8 +277,7 @@ static int qeth_l2_vlan_rx_kill_vid(struct net_device *dev,
static void qeth_l2_stop_card(struct qeth_card *card)
{
- QETH_DBF_TEXT(SETUP , 2, "stopcard");
- QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
+ QETH_CARD_TEXT(card, 2, "stopcard");
qeth_set_allowed_threads(card, 0, 1);
@@ -292,10 +294,6 @@ static void qeth_l2_stop_card(struct qeth_card *card)
qeth_clear_working_pool_list(card);
card->state = CARD_STATE_DOWN;
}
- if (card->state == CARD_STATE_DOWN) {
- qeth_clear_cmd_buffers(&card->read);
- qeth_clear_cmd_buffers(&card->write);
- }
flush_workqueue(card->event_wq);
card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED;
@@ -354,8 +352,7 @@ static int qeth_l2_request_initial_mac(struct qeth_card *card)
{
int rc = 0;
- QETH_DBF_TEXT(SETUP, 2, "l2reqmac");
- QETH_DBF_TEXT_(SETUP, 2, "doL2%s", CARD_BUS_ID(card));
+ QETH_CARD_TEXT(card, 2, "l2reqmac");
if (MACHINE_IS_VM) {
rc = qeth_vm_request_mac(card);
@@ -363,7 +360,7 @@ static int qeth_l2_request_initial_mac(struct qeth_card *card)
goto out;
QETH_DBF_MESSAGE(2, "z/VM MAC Service failed on device %x: %#x\n",
CARD_DEVID(card), rc);
- QETH_DBF_TEXT_(SETUP, 2, "err%04x", rc);
+ QETH_CARD_TEXT_(card, 2, "err%04x", rc);
/* fall back to alternative mechanism: */
}
@@ -373,7 +370,7 @@ static int qeth_l2_request_initial_mac(struct qeth_card *card)
goto out;
QETH_DBF_MESSAGE(2, "READ_MAC Assist failed on device %x: %#x\n",
CARD_DEVID(card), rc);
- QETH_DBF_TEXT_(SETUP, 2, "1err%04x", rc);
+ QETH_CARD_TEXT_(card, 2, "1err%04x", rc);
/* fall back once more: */
}
@@ -383,7 +380,7 @@ static int qeth_l2_request_initial_mac(struct qeth_card *card)
eth_hw_addr_random(card->dev);
out:
- QETH_DBF_HEX(SETUP, 2, card->dev->dev_addr, card->dev->addr_len);
+ QETH_CARD_HEX(card, 2, card->dev->dev_addr, card->dev->addr_len);
return 0;
}
@@ -467,7 +464,7 @@ static void qeth_promisc_to_bridge(struct qeth_card *card)
role = QETH_SBP_ROLE_NONE;
rc = qeth_bridgeport_setrole(card, role);
- QETH_DBF_TEXT_(SETUP, 2, "bpm%c%04x",
+ QETH_CARD_TEXT_(card, 2, "bpm%c%04x",
(promisc_mode == SET_PROMISC_MODE_ON) ? '+' : '-', rc);
if (!rc) {
card->options.sbp.role = role;
@@ -602,7 +599,6 @@ static netdev_tx_t qeth_l2_hard_start_xmit(struct sk_buff *skb,
rc = qeth_l2_xmit_osn(card, skb, queue);
else
rc = qeth_xmit(card, skb, queue, qeth_get_ip_version(skb),
- qeth_get_ether_cast_type(skb),
qeth_l2_fill_header);
if (!rc) {
@@ -796,12 +792,11 @@ static int qeth_l2_set_online(struct ccwgroup_device *gdev)
mutex_lock(&card->discipline_mutex);
mutex_lock(&card->conf_mutex);
- QETH_DBF_TEXT(SETUP, 2, "setonlin");
- QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
+ QETH_CARD_TEXT(card, 2, "setonlin");
rc = qeth_core_hardsetup_card(card, &carrier_ok);
if (rc) {
- QETH_DBF_TEXT_(SETUP, 2, "2err%04x", rc);
+ QETH_CARD_TEXT_(card, 2, "2err%04x", rc);
rc = -ENODEV;
goto out_remove;
}
@@ -832,7 +827,7 @@ static int qeth_l2_set_online(struct ccwgroup_device *gdev)
qeth_print_status_message(card);
/* softsetup */
- QETH_DBF_TEXT(SETUP, 2, "softsetp");
+ QETH_CARD_TEXT(card, 2, "softsetp");
if (IS_OSD(card) || IS_OSX(card)) {
rc = qeth_l2_start_ipassists(card);
@@ -842,7 +837,7 @@ static int qeth_l2_set_online(struct ccwgroup_device *gdev)
rc = qeth_init_qdio_queues(card);
if (rc) {
- QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc);
+ QETH_CARD_TEXT_(card, 2, "6err%d", rc);
rc = -ENODEV;
goto out_remove;
}
@@ -882,7 +877,6 @@ out_remove:
ccw_device_set_offline(CARD_WDEV(card));
ccw_device_set_offline(CARD_RDEV(card));
qdio_free(CARD_DDEV(card));
- card->state = CARD_STATE_DOWN;
mutex_unlock(&card->conf_mutex);
mutex_unlock(&card->discipline_mutex);
@@ -897,8 +891,7 @@ static int __qeth_l2_set_offline(struct ccwgroup_device *cgdev,
mutex_lock(&card->discipline_mutex);
mutex_lock(&card->conf_mutex);
- QETH_DBF_TEXT(SETUP, 3, "setoffl");
- QETH_DBF_HEX(SETUP, 3, &card, sizeof(void *));
+ QETH_CARD_TEXT(card, 3, "setoffl");
if ((!recovery_mode && card->info.hwtrap) || card->info.hwtrap == 2) {
qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
@@ -919,7 +912,7 @@ static int __qeth_l2_set_offline(struct ccwgroup_device *cgdev,
if (!rc)
rc = (rc2) ? rc2 : rc3;
if (rc)
- QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
+ QETH_CARD_TEXT_(card, 2, "1err%d", rc);
qdio_free(CARD_DDEV(card));
/* let user_space know that device is offline */
@@ -972,33 +965,6 @@ static void __exit qeth_l2_exit(void)
pr_info("unregister layer 2 discipline\n");
}
-static int qeth_l2_pm_suspend(struct ccwgroup_device *gdev)
-{
- struct qeth_card *card = dev_get_drvdata(&gdev->dev);
-
- qeth_set_allowed_threads(card, 0, 1);
- wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
- if (gdev->state == CCWGROUP_OFFLINE)
- return 0;
-
- qeth_l2_set_offline(gdev);
- return 0;
-}
-
-static int qeth_l2_pm_resume(struct ccwgroup_device *gdev)
-{
- struct qeth_card *card = dev_get_drvdata(&gdev->dev);
- int rc;
-
- rc = qeth_l2_set_online(gdev);
-
- qeth_set_allowed_threads(card, 0xffffffff, 0);
- if (rc)
- dev_warn(&card->gdev->dev, "The qeth device driver "
- "failed to recover an error on the device\n");
- return rc;
-}
-
/* Returns zero if the command is successfully "consumed" */
static int qeth_l2_control_event(struct qeth_card *card,
struct qeth_ipa_cmd *cmd)
@@ -1028,50 +994,16 @@ struct qeth_discipline qeth_l2_discipline = {
.remove = qeth_l2_remove_device,
.set_online = qeth_l2_set_online,
.set_offline = qeth_l2_set_offline,
- .freeze = qeth_l2_pm_suspend,
- .thaw = qeth_l2_pm_resume,
- .restore = qeth_l2_pm_resume,
.do_ioctl = NULL,
.control_event_handler = qeth_l2_control_event,
};
EXPORT_SYMBOL_GPL(qeth_l2_discipline);
-static int qeth_osn_send_control_data(struct qeth_card *card, int len,
- struct qeth_cmd_buffer *iob)
+static void qeth_osn_assist_cb(struct qeth_card *card,
+ struct qeth_cmd_buffer *iob)
{
- struct qeth_channel *channel = iob->channel;
- int rc = 0;
-
- QETH_CARD_TEXT(card, 5, "osndctrd");
-
- wait_event(card->wait_q, qeth_trylock_channel(channel));
- iob->finalize(card, iob, len);
- QETH_DBF_HEX(CTRL, 2, iob->data, min(len, QETH_DBF_CTRL_LEN));
- QETH_CARD_TEXT(card, 6, "osnoirqp");
- spin_lock_irq(get_ccwdev_lock(channel->ccwdev));
- rc = ccw_device_start_timeout(channel->ccwdev, channel->ccw,
- (addr_t) iob, 0, 0, iob->timeout);
- spin_unlock_irq(get_ccwdev_lock(channel->ccwdev));
- if (rc) {
- QETH_DBF_MESSAGE(2, "qeth_osn_send_control_data: "
- "ccw_device_start rc = %i\n", rc);
- QETH_CARD_TEXT_(card, 2, " err%d", rc);
- qeth_release_buffer(channel, iob);
- atomic_set(&channel->irq_pending, 0);
- wake_up(&card->wait_q);
- }
- return rc;
-}
-
-static int qeth_osn_send_ipa_cmd(struct qeth_card *card,
- struct qeth_cmd_buffer *iob)
-{
- u16 length;
-
- QETH_CARD_TEXT(card, 4, "osndipa");
-
- memcpy(&length, QETH_IPA_PDU_LEN_TOTAL(iob->data), 2);
- return qeth_osn_send_control_data(card, length, iob);
+ qeth_notify_reply(iob->reply, 0);
+ qeth_put_cmd(iob);
}
int qeth_osn_assist(struct net_device *dev, void *data, int data_len)
@@ -1079,6 +1011,8 @@ int qeth_osn_assist(struct net_device *dev, void *data, int data_len)
struct qeth_cmd_buffer *iob;
struct qeth_card *card;
+ if (data_len < 0)
+ return -EINVAL;
if (!dev)
return -ENODEV;
card = dev->ml_priv;
@@ -1087,10 +1021,16 @@ int qeth_osn_assist(struct net_device *dev, void *data, int data_len)
QETH_CARD_TEXT(card, 2, "osnsdmc");
if (!qeth_card_hw_is_reachable(card))
return -ENODEV;
- iob = qeth_wait_for_buffer(&card->write);
+
+ iob = qeth_alloc_cmd(&card->write, IPA_PDU_HEADER_SIZE + data_len, 1,
+ QETH_IPA_TIMEOUT);
+ if (!iob)
+ return -ENOMEM;
+
qeth_prepare_ipa_cmd(card, iob, (u16) data_len);
memcpy(__ipa_cmd(iob), data, data_len);
- return qeth_osn_send_ipa_cmd(card, iob);
+ iob->callback = qeth_osn_assist_cb;
+ return qeth_send_ipa_cmd(card, iob, NULL, NULL);
}
EXPORT_SYMBOL(qeth_osn_assist);
@@ -1456,22 +1396,25 @@ static int qeth_bridgeport_makerc(struct qeth_card *card,
static struct qeth_cmd_buffer *qeth_sbp_build_cmd(struct qeth_card *card,
enum qeth_ipa_sbp_cmd sbp_cmd,
- unsigned int cmd_length)
+ unsigned int data_length)
{
enum qeth_ipa_cmds ipa_cmd = IS_IQD(card) ? IPA_CMD_SETBRIDGEPORT_IQD :
IPA_CMD_SETBRIDGEPORT_OSA;
+ struct qeth_ipacmd_sbp_hdr *hdr;
struct qeth_cmd_buffer *iob;
- struct qeth_ipa_cmd *cmd;
- iob = qeth_get_ipacmd_buffer(card, ipa_cmd, 0);
+ iob = qeth_ipa_alloc_cmd(card, ipa_cmd, QETH_PROT_NONE,
+ data_length +
+ offsetof(struct qeth_ipacmd_setbridgeport,
+ data));
if (!iob)
return iob;
- cmd = __ipa_cmd(iob);
- cmd->data.sbp.hdr.cmdlength = sizeof(struct qeth_ipacmd_sbp_hdr) +
- cmd_length;
- cmd->data.sbp.hdr.command_code = sbp_cmd;
- cmd->data.sbp.hdr.used_total = 1;
- cmd->data.sbp.hdr.seq_no = 1;
+
+ hdr = &__ipa_cmd(iob)->data.sbp.hdr;
+ hdr->cmdlength = sizeof(*hdr) + data_length;
+ hdr->command_code = sbp_cmd;
+ hdr->used_total = 1;
+ hdr->seq_no = 1;
return iob;
}
@@ -1506,7 +1449,7 @@ static void qeth_bridgeport_query_support(struct qeth_card *card)
QETH_CARD_TEXT(card, 2, "brqsuppo");
iob = qeth_sbp_build_cmd(card, IPA_SBP_QUERY_COMMANDS_SUPPORTED,
- sizeof(struct qeth_sbp_query_cmds_supp));
+ SBP_DATA_SIZEOF(query_cmds_supp));
if (!iob)
return;
@@ -1598,23 +1541,21 @@ static int qeth_bridgeport_set_cb(struct qeth_card *card,
*/
int qeth_bridgeport_setrole(struct qeth_card *card, enum qeth_sbp_roles role)
{
- int cmdlength;
struct qeth_cmd_buffer *iob;
enum qeth_ipa_sbp_cmd setcmd;
+ unsigned int cmdlength = 0;
QETH_CARD_TEXT(card, 2, "brsetrol");
switch (role) {
case QETH_SBP_ROLE_NONE:
setcmd = IPA_SBP_RESET_BRIDGE_PORT_ROLE;
- cmdlength = sizeof(struct qeth_sbp_reset_role);
break;
case QETH_SBP_ROLE_PRIMARY:
setcmd = IPA_SBP_SET_PRIMARY_BRIDGE_PORT;
- cmdlength = sizeof(struct qeth_sbp_set_primary);
+ cmdlength = SBP_DATA_SIZEOF(set_primary);
break;
case QETH_SBP_ROLE_SECONDARY:
setcmd = IPA_SBP_SET_SECONDARY_BRIDGE_PORT;
- cmdlength = sizeof(struct qeth_sbp_set_secondary);
break;
default:
return -EINVAL;
@@ -1764,10 +1705,6 @@ static int qeth_l2_vnicc_makerc(struct qeth_card *card, u16 ipa_rc)
struct _qeth_l2_vnicc_request_cbctl {
u32 sub_cmd;
struct {
- u32 vnic_char;
- u32 timeout;
- } param;
- struct {
union{
u32 *sup_cmds;
u32 *timeout;
@@ -1789,80 +1726,52 @@ static int qeth_l2_vnicc_request_cb(struct qeth_card *card,
if (cmd->hdr.return_code)
return qeth_l2_vnicc_makerc(card, cmd->hdr.return_code);
/* return results to caller */
- card->options.vnicc.sup_chars = rep->hdr.sup;
- card->options.vnicc.cur_chars = rep->hdr.cur;
+ card->options.vnicc.sup_chars = rep->vnicc_cmds.supported;
+ card->options.vnicc.cur_chars = rep->vnicc_cmds.enabled;
if (cbctl->sub_cmd == IPA_VNICC_QUERY_CMDS)
- *cbctl->result.sup_cmds = rep->query_cmds.sup_cmds;
+ *cbctl->result.sup_cmds = rep->data.query_cmds.sup_cmds;
if (cbctl->sub_cmd == IPA_VNICC_GET_TIMEOUT)
- *cbctl->result.timeout = rep->getset_timeout.timeout;
+ *cbctl->result.timeout = rep->data.getset_timeout.timeout;
return 0;
}
-/* generic VNICC request */
-static int qeth_l2_vnicc_request(struct qeth_card *card,
- struct _qeth_l2_vnicc_request_cbctl *cbctl)
+static struct qeth_cmd_buffer *qeth_l2_vnicc_build_cmd(struct qeth_card *card,
+ u32 vnicc_cmd,
+ unsigned int data_length)
{
- struct qeth_ipacmd_vnicc *req;
+ struct qeth_ipacmd_vnicc_hdr *hdr;
struct qeth_cmd_buffer *iob;
- struct qeth_ipa_cmd *cmd;
-
- QETH_CARD_TEXT(card, 2, "vniccreq");
- /* get new buffer for request */
- iob = qeth_get_ipacmd_buffer(card, IPA_CMD_VNICC, 0);
+ iob = qeth_ipa_alloc_cmd(card, IPA_CMD_VNICC, QETH_PROT_NONE,
+ data_length +
+ offsetof(struct qeth_ipacmd_vnicc, data));
if (!iob)
- return -ENOMEM;
-
- /* create header for request */
- cmd = __ipa_cmd(iob);
- req = &cmd->data.vnicc;
-
- /* create sub command header for request */
- req->sub_hdr.data_length = sizeof(req->sub_hdr);
- req->sub_hdr.sub_command = cbctl->sub_cmd;
-
- /* create sub command specific request fields */
- switch (cbctl->sub_cmd) {
- case IPA_VNICC_QUERY_CHARS:
- break;
- case IPA_VNICC_QUERY_CMDS:
- req->sub_hdr.data_length += sizeof(req->query_cmds);
- req->query_cmds.vnic_char = cbctl->param.vnic_char;
- break;
- case IPA_VNICC_ENABLE:
- case IPA_VNICC_DISABLE:
- req->sub_hdr.data_length += sizeof(req->set_char);
- req->set_char.vnic_char = cbctl->param.vnic_char;
- break;
- case IPA_VNICC_SET_TIMEOUT:
- req->getset_timeout.timeout = cbctl->param.timeout;
- /* fallthrough */
- case IPA_VNICC_GET_TIMEOUT:
- req->sub_hdr.data_length += sizeof(req->getset_timeout);
- req->getset_timeout.vnic_char = cbctl->param.vnic_char;
- break;
- default:
- qeth_release_buffer(iob->channel, iob);
- return -EOPNOTSUPP;
- }
+ return NULL;
- /* send request */
- return qeth_send_ipa_cmd(card, iob, qeth_l2_vnicc_request_cb, cbctl);
+ hdr = &__ipa_cmd(iob)->data.vnicc.hdr;
+ hdr->data_length = sizeof(*hdr) + data_length;
+ hdr->sub_command = vnicc_cmd;
+ return iob;
}
/* VNICC query VNIC characteristics request */
static int qeth_l2_vnicc_query_chars(struct qeth_card *card)
{
struct _qeth_l2_vnicc_request_cbctl cbctl;
+ struct qeth_cmd_buffer *iob;
+
+ QETH_CARD_TEXT(card, 2, "vniccqch");
+ iob = qeth_l2_vnicc_build_cmd(card, IPA_VNICC_QUERY_CHARS, 0);
+ if (!iob)
+ return -ENOMEM;
/* prepare callback control */
cbctl.sub_cmd = IPA_VNICC_QUERY_CHARS;
- QETH_CARD_TEXT(card, 2, "vniccqch");
- return qeth_l2_vnicc_request(card, &cbctl);
+ return qeth_send_ipa_cmd(card, iob, qeth_l2_vnicc_request_cb, &cbctl);
}
/* VNICC query sub commands request */
@@ -1870,14 +1779,21 @@ static int qeth_l2_vnicc_query_cmds(struct qeth_card *card, u32 vnic_char,
u32 *sup_cmds)
{
struct _qeth_l2_vnicc_request_cbctl cbctl;
+ struct qeth_cmd_buffer *iob;
+
+ QETH_CARD_TEXT(card, 2, "vniccqcm");
+ iob = qeth_l2_vnicc_build_cmd(card, IPA_VNICC_QUERY_CMDS,
+ VNICC_DATA_SIZEOF(query_cmds));
+ if (!iob)
+ return -ENOMEM;
+
+ __ipa_cmd(iob)->data.vnicc.data.query_cmds.vnic_char = vnic_char;
/* prepare callback control */
cbctl.sub_cmd = IPA_VNICC_QUERY_CMDS;
- cbctl.param.vnic_char = vnic_char;
cbctl.result.sup_cmds = sup_cmds;
- QETH_CARD_TEXT(card, 2, "vniccqcm");
- return qeth_l2_vnicc_request(card, &cbctl);
+ return qeth_send_ipa_cmd(card, iob, qeth_l2_vnicc_request_cb, &cbctl);
}
/* VNICC enable/disable characteristic request */
@@ -1885,31 +1801,47 @@ static int qeth_l2_vnicc_set_char(struct qeth_card *card, u32 vnic_char,
u32 cmd)
{
struct _qeth_l2_vnicc_request_cbctl cbctl;
+ struct qeth_cmd_buffer *iob;
+
+ QETH_CARD_TEXT(card, 2, "vniccedc");
+ iob = qeth_l2_vnicc_build_cmd(card, cmd, VNICC_DATA_SIZEOF(set_char));
+ if (!iob)
+ return -ENOMEM;
+
+ __ipa_cmd(iob)->data.vnicc.data.set_char.vnic_char = vnic_char;
/* prepare callback control */
cbctl.sub_cmd = cmd;
- cbctl.param.vnic_char = vnic_char;
- QETH_CARD_TEXT(card, 2, "vniccedc");
- return qeth_l2_vnicc_request(card, &cbctl);
+ return qeth_send_ipa_cmd(card, iob, qeth_l2_vnicc_request_cb, &cbctl);
}
/* VNICC get/set timeout for characteristic request */
static int qeth_l2_vnicc_getset_timeout(struct qeth_card *card, u32 vnicc,
u32 cmd, u32 *timeout)
{
+ struct qeth_vnicc_getset_timeout *getset_timeout;
struct _qeth_l2_vnicc_request_cbctl cbctl;
+ struct qeth_cmd_buffer *iob;
+
+ QETH_CARD_TEXT(card, 2, "vniccgst");
+ iob = qeth_l2_vnicc_build_cmd(card, cmd,
+ VNICC_DATA_SIZEOF(getset_timeout));
+ if (!iob)
+ return -ENOMEM;
+
+ getset_timeout = &__ipa_cmd(iob)->data.vnicc.data.getset_timeout;
+ getset_timeout->vnic_char = vnicc;
+
+ if (cmd == IPA_VNICC_SET_TIMEOUT)
+ getset_timeout->timeout = *timeout;
/* prepare callback control */
cbctl.sub_cmd = cmd;
- cbctl.param.vnic_char = vnicc;
- if (cmd == IPA_VNICC_SET_TIMEOUT)
- cbctl.param.timeout = *timeout;
if (cmd == IPA_VNICC_GET_TIMEOUT)
cbctl.result.timeout = timeout;
- QETH_CARD_TEXT(card, 2, "vniccgst");
- return qeth_l2_vnicc_request(card, &cbctl);
+ return qeth_send_ipa_cmd(card, iob, qeth_l2_vnicc_request_cb, &cbctl);
}
/* set current VNICC flag state; called from sysfs store function */
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index 13bf3e2e9cea..2dd99f103671 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -32,7 +32,6 @@
#include <net/route.h>
#include <net/ipv6.h>
#include <net/ip6_route.h>
-#include <net/ip6_fib.h>
#include <net/iucv/af_iucv.h>
#include <linux/hashtable.h>
@@ -377,7 +376,8 @@ static int qeth_l3_send_setdelmc(struct qeth_card *card,
QETH_CARD_TEXT(card, 4, "setdelmc");
- iob = qeth_get_ipacmd_buffer(card, ipacmd, addr->proto);
+ iob = qeth_ipa_alloc_cmd(card, ipacmd, addr->proto,
+ IPA_DATA_SIZEOF(setdelipm));
if (!iob)
return -ENOMEM;
cmd = __ipa_cmd(iob);
@@ -429,7 +429,8 @@ static int qeth_l3_send_setdelip(struct qeth_card *card,
QETH_CARD_TEXT(card, 4, "setdelip");
- iob = qeth_get_ipacmd_buffer(card, ipacmd, addr->proto);
+ iob = qeth_ipa_alloc_cmd(card, ipacmd, addr->proto,
+ IPA_DATA_SIZEOF(setdelip6));
if (!iob)
return -ENOMEM;
cmd = __ipa_cmd(iob);
@@ -461,7 +462,8 @@ static int qeth_l3_send_setrouting(struct qeth_card *card,
struct qeth_cmd_buffer *iob;
QETH_CARD_TEXT(card, 4, "setroutg");
- iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETRTG, prot);
+ iob = qeth_ipa_alloc_cmd(card, IPA_CMD_SETRTG, prot,
+ IPA_DATA_SIZEOF(setrtg));
if (!iob)
return -ENOMEM;
cmd = __ipa_cmd(iob);
@@ -742,7 +744,7 @@ static int qeth_l3_setadapter_parms(struct qeth_card *card)
{
int rc = 0;
- QETH_DBF_TEXT(SETUP, 2, "setadprm");
+ QETH_CARD_TEXT(card, 2, "setadprm");
if (qeth_adp_supported(card, IPA_SETADP_ALTER_MAC_ADDRESS)) {
rc = qeth_setadpparms_change_macaddr(card);
@@ -767,7 +769,7 @@ static int qeth_l3_start_ipa_arp_processing(struct qeth_card *card)
return 0;
}
rc = qeth_send_simple_setassparms(card, IPA_ARP_PROCESSING,
- IPA_CMD_ASS_START, 0);
+ IPA_CMD_ASS_START, NULL);
if (rc) {
dev_warn(&card->gdev->dev,
"Starting ARP processing support for %s failed\n",
@@ -790,7 +792,7 @@ static int qeth_l3_start_ipa_source_mac(struct qeth_card *card)
}
rc = qeth_send_simple_setassparms(card, IPA_SOURCE_MAC,
- IPA_CMD_ASS_START, 0);
+ IPA_CMD_ASS_START, NULL);
if (rc)
dev_warn(&card->gdev->dev,
"Starting source MAC-address support for %s failed\n",
@@ -811,7 +813,7 @@ static int qeth_l3_start_ipa_vlan(struct qeth_card *card)
}
rc = qeth_send_simple_setassparms(card, IPA_VLAN_PRIO,
- IPA_CMD_ASS_START, 0);
+ IPA_CMD_ASS_START, NULL);
if (rc) {
dev_warn(&card->gdev->dev,
"Starting VLAN support for %s failed\n",
@@ -836,7 +838,7 @@ static int qeth_l3_start_ipa_multicast(struct qeth_card *card)
}
rc = qeth_send_simple_setassparms(card, IPA_MULTICASTING,
- IPA_CMD_ASS_START, 0);
+ IPA_CMD_ASS_START, NULL);
if (rc) {
dev_warn(&card->gdev->dev,
"Starting multicast support for %s failed\n",
@@ -850,6 +852,7 @@ static int qeth_l3_start_ipa_multicast(struct qeth_card *card)
static int qeth_l3_softsetup_ipv6(struct qeth_card *card)
{
+ u32 ipv6_data = 3;
int rc;
QETH_CARD_TEXT(card, 3, "softipv6");
@@ -857,16 +860,16 @@ static int qeth_l3_softsetup_ipv6(struct qeth_card *card)
if (IS_IQD(card))
goto out;
- rc = qeth_send_simple_setassparms(card, IPA_IPV6,
- IPA_CMD_ASS_START, 3);
+ rc = qeth_send_simple_setassparms(card, IPA_IPV6, IPA_CMD_ASS_START,
+ &ipv6_data);
if (rc) {
dev_err(&card->gdev->dev,
"Activating IPv6 support for %s failed\n",
QETH_CARD_IFNAME(card));
return rc;
}
- rc = qeth_send_simple_setassparms_v6(card, IPA_IPV6,
- IPA_CMD_ASS_START, 0);
+ rc = qeth_send_simple_setassparms_v6(card, IPA_IPV6, IPA_CMD_ASS_START,
+ NULL);
if (rc) {
dev_err(&card->gdev->dev,
"Activating IPv6 support for %s failed\n",
@@ -874,7 +877,7 @@ static int qeth_l3_softsetup_ipv6(struct qeth_card *card)
return rc;
}
rc = qeth_send_simple_setassparms_v6(card, IPA_PASSTHRU,
- IPA_CMD_ASS_START, 0);
+ IPA_CMD_ASS_START, NULL);
if (rc) {
dev_warn(&card->gdev->dev,
"Enabling the passthrough mode for %s failed\n",
@@ -900,6 +903,7 @@ static int qeth_l3_start_ipa_ipv6(struct qeth_card *card)
static int qeth_l3_start_ipa_broadcast(struct qeth_card *card)
{
+ u32 filter_data = 1;
int rc;
QETH_CARD_TEXT(card, 3, "stbrdcst");
@@ -912,7 +916,7 @@ static int qeth_l3_start_ipa_broadcast(struct qeth_card *card)
goto out;
}
rc = qeth_send_simple_setassparms(card, IPA_FILTERING,
- IPA_CMD_ASS_START, 0);
+ IPA_CMD_ASS_START, NULL);
if (rc) {
dev_warn(&card->gdev->dev, "Enabling broadcast filtering for "
"%s failed\n", QETH_CARD_IFNAME(card));
@@ -920,7 +924,7 @@ static int qeth_l3_start_ipa_broadcast(struct qeth_card *card)
}
rc = qeth_send_simple_setassparms(card, IPA_FILTERING,
- IPA_CMD_ASS_CONFIGURE, 1);
+ IPA_CMD_ASS_CONFIGURE, &filter_data);
if (rc) {
dev_warn(&card->gdev->dev,
"Setting up broadcast filtering for %s failed\n",
@@ -930,7 +934,7 @@ static int qeth_l3_start_ipa_broadcast(struct qeth_card *card)
card->info.broadcast_capable = QETH_BROADCAST_WITH_ECHO;
dev_info(&card->gdev->dev, "Broadcast enabled\n");
rc = qeth_send_simple_setassparms(card, IPA_FILTERING,
- IPA_CMD_ASS_ENABLE, 1);
+ IPA_CMD_ASS_ENABLE, &filter_data);
if (rc) {
dev_warn(&card->gdev->dev, "Setting up broadcast echo "
"filtering for %s failed\n", QETH_CARD_IFNAME(card));
@@ -979,10 +983,10 @@ static int qeth_l3_iqd_read_initial_mac(struct qeth_card *card)
struct qeth_cmd_buffer *iob;
struct qeth_ipa_cmd *cmd;
- QETH_DBF_TEXT(SETUP, 2, "hsrmac");
+ QETH_CARD_TEXT(card, 2, "hsrmac");
- iob = qeth_get_ipacmd_buffer(card, IPA_CMD_CREATE_ADDR,
- QETH_PROT_IPV6);
+ iob = qeth_ipa_alloc_cmd(card, IPA_CMD_CREATE_ADDR, QETH_PROT_IPV6,
+ IPA_DATA_SIZEOF(create_destroy_addr));
if (!iob)
return -ENOMEM;
cmd = __ipa_cmd(iob);
@@ -1017,7 +1021,7 @@ static int qeth_l3_get_unique_id(struct qeth_card *card)
struct qeth_cmd_buffer *iob;
struct qeth_ipa_cmd *cmd;
- QETH_DBF_TEXT(SETUP, 2, "guniqeid");
+ QETH_CARD_TEXT(card, 2, "guniqeid");
if (!qeth_is_supported(card, IPA_IPV6)) {
card->info.unique_id = UNIQUE_ID_IF_CREATE_ADDR_FAILED |
@@ -1025,8 +1029,8 @@ static int qeth_l3_get_unique_id(struct qeth_card *card)
return 0;
}
- iob = qeth_get_ipacmd_buffer(card, IPA_CMD_CREATE_ADDR,
- QETH_PROT_IPV6);
+ iob = qeth_ipa_alloc_cmd(card, IPA_CMD_CREATE_ADDR, QETH_PROT_IPV6,
+ IPA_DATA_SIZEOF(create_destroy_addr));
if (!iob)
return -ENOMEM;
cmd = __ipa_cmd(iob);
@@ -1044,7 +1048,7 @@ qeth_diags_trace_cb(struct qeth_card *card, struct qeth_reply *reply,
struct qeth_ipa_cmd *cmd;
__u16 rc;
- QETH_DBF_TEXT(SETUP, 2, "diastrcb");
+ QETH_CARD_TEXT(card, 2, "diastrcb");
cmd = (struct qeth_ipa_cmd *)data;
rc = cmd->hdr.return_code;
@@ -1100,14 +1104,12 @@ qeth_diags_trace(struct qeth_card *card, enum qeth_diags_trace_cmds diags_cmd)
struct qeth_cmd_buffer *iob;
struct qeth_ipa_cmd *cmd;
- QETH_DBF_TEXT(SETUP, 2, "diagtrac");
+ QETH_CARD_TEXT(card, 2, "diagtrac");
- iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SET_DIAG_ASS, 0);
+ iob = qeth_get_diag_cmd(card, QETH_DIAGS_CMD_TRACE, 0);
if (!iob)
return -ENOMEM;
cmd = __ipa_cmd(iob);
- cmd->data.diagass.subcmd_len = 16;
- cmd->data.diagass.subcmd = QETH_DIAGS_CMD_TRACE;
cmd->data.diagass.type = QETH_DIAGS_TYPE_HIPERSOCKET;
cmd->data.diagass.action = diags_cmd;
return qeth_send_ipa_cmd(card, iob, qeth_diags_trace_cb, NULL);
@@ -1309,6 +1311,15 @@ static int qeth_l3_vlan_rx_kill_vid(struct net_device *dev,
static void qeth_l3_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *hdr)
{
+ struct af_iucv_trans_hdr *iucv = (struct af_iucv_trans_hdr *) skb->data;
+ struct net_device *dev = skb->dev;
+
+ if (IS_IQD(card) && iucv->magic == ETH_P_AF_IUCV) {
+ dev_hard_header(skb, dev, ETH_P_AF_IUCV, dev->dev_addr,
+ "FAKELL", skb->len);
+ return;
+ }
+
if (!(hdr->hdr.l3.flags & QETH_HDR_PASSTHRU)) {
u16 prot = (hdr->hdr.l3.flags & QETH_HDR_IPV6) ? ETH_P_IPV6 :
ETH_P_IP;
@@ -1342,8 +1353,6 @@ static void qeth_l3_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
tg_addr, "FAKELL", skb->len);
}
- skb->protocol = eth_type_trans(skb, card->dev);
-
/* copy VLAN tag from hdr into skb */
if (!card->options.sniffer &&
(hdr->hdr.l3.ext_flags & (QETH_HDR_EXT_VLAN_FRAME |
@@ -1360,12 +1369,10 @@ static void qeth_l3_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
static int qeth_l3_process_inbound_buffer(struct qeth_card *card,
int budget, int *done)
{
- struct net_device *dev = card->dev;
int work_done = 0;
struct sk_buff *skb;
struct qeth_hdr *hdr;
unsigned int len;
- __u16 magic;
*done = 0;
WARN_ON_ONCE(!budget);
@@ -1379,23 +1386,12 @@ static int qeth_l3_process_inbound_buffer(struct qeth_card *card,
}
switch (hdr->hdr.l3.id) {
case QETH_HEADER_TYPE_LAYER3:
- magic = *(__u16 *)skb->data;
- if (IS_IQD(card) && magic == ETH_P_AF_IUCV) {
- len = skb->len;
- dev_hard_header(skb, dev, ETH_P_AF_IUCV,
- dev->dev_addr, "FAKELL", len);
- skb->protocol = eth_type_trans(skb, dev);
- netif_receive_skb(skb);
- } else {
- qeth_l3_rebuild_skb(card, skb, hdr);
- len = skb->len;
- napi_gro_receive(&card->napi, skb);
- }
- break;
+ qeth_l3_rebuild_skb(card, skb, hdr);
+ /* fall through */
case QETH_HEADER_TYPE_LAYER2: /* for HiperSockets sniffer */
skb->protocol = eth_type_trans(skb, skb->dev);
len = skb->len;
- netif_receive_skb(skb);
+ napi_gro_receive(&card->napi, skb);
break;
default:
dev_kfree_skb_any(skb);
@@ -1413,8 +1409,7 @@ static int qeth_l3_process_inbound_buffer(struct qeth_card *card,
static void qeth_l3_stop_card(struct qeth_card *card)
{
- QETH_DBF_TEXT(SETUP, 2, "stopcard");
- QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
+ QETH_CARD_TEXT(card, 2, "stopcard");
qeth_set_allowed_threads(card, 0, 1);
@@ -1436,10 +1431,6 @@ static void qeth_l3_stop_card(struct qeth_card *card)
qeth_clear_working_pool_list(card);
card->state = CARD_STATE_DOWN;
}
- if (card->state == CARD_STATE_DOWN) {
- qeth_clear_cmd_buffers(&card->read);
- qeth_clear_cmd_buffers(&card->write);
- }
flush_workqueue(card->event_wq);
}
@@ -1563,7 +1554,8 @@ static int qeth_l3_arp_set_no_entries(struct qeth_card *card, int no_entries)
}
iob = qeth_get_setassparms_cmd(card, IPA_ARP_PROCESSING,
- IPA_CMD_ASS_ARP_SET_NO_ENTRIES, 4,
+ IPA_CMD_ASS_ARP_SET_NO_ENTRIES,
+ SETASS_DATA_SIZEOF(flags_32bit),
QETH_PROT_IPV4);
if (!iob)
return -ENOMEM;
@@ -1709,9 +1701,7 @@ static int qeth_l3_query_arp_cache_info(struct qeth_card *card,
iob = qeth_get_setassparms_cmd(card, IPA_ARP_PROCESSING,
IPA_CMD_ASS_ARP_QUERY_INFO,
- sizeof(struct qeth_arp_query_data)
- - sizeof(char),
- prot);
+ SETASS_DATA_SIZEOF(query_arp), prot);
if (!iob)
return -ENOMEM;
cmd = __ipa_cmd(iob);
@@ -1795,7 +1785,8 @@ static int qeth_l3_arp_modify_entry(struct qeth_card *card,
}
iob = qeth_get_setassparms_cmd(card, IPA_ARP_PROCESSING, arp_cmd,
- sizeof(*cmd_entry), QETH_PROT_IPV4);
+ SETASS_DATA_SIZEOF(arp_entry),
+ QETH_PROT_IPV4);
if (!iob)
return -ENOMEM;
@@ -1886,26 +1877,17 @@ static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return rc;
}
-static int qeth_l3_get_cast_type(struct sk_buff *skb)
+static int qeth_l3_get_cast_type_rcu(struct sk_buff *skb, struct dst_entry *dst,
+ int ipv)
{
- int ipv = qeth_get_ip_version(skb);
struct neighbour *n = NULL;
- struct dst_entry *dst;
-
- rcu_read_lock();
- dst = skb_dst(skb);
- if (dst) {
- struct rt6_info *rt = (struct rt6_info *) dst;
- dst = dst_check(dst, (ipv == 6) ? rt6_get_cookie(rt) : 0);
- if (dst)
- n = dst_neigh_lookup_skb(dst, skb);
- }
+ if (dst)
+ n = dst_neigh_lookup_skb(dst, skb);
if (n) {
int cast_type = n->type;
- rcu_read_unlock();
neigh_release(n);
if ((cast_type == RTN_BROADCAST) ||
(cast_type == RTN_MULTICAST) ||
@@ -1913,7 +1895,6 @@ static int qeth_l3_get_cast_type(struct sk_buff *skb)
return cast_type;
return RTN_UNICAST;
}
- rcu_read_unlock();
/* no neighbour (eg AF_PACKET), fall back to target's IP address ... */
switch (ipv) {
@@ -1931,6 +1912,20 @@ static int qeth_l3_get_cast_type(struct sk_buff *skb)
}
}
+static int qeth_l3_get_cast_type(struct sk_buff *skb)
+{
+ int ipv = qeth_get_ip_version(skb);
+ struct dst_entry *dst;
+ int cast_type;
+
+ rcu_read_lock();
+ dst = qeth_dst_check_rcu(skb, ipv);
+ cast_type = qeth_l3_get_cast_type_rcu(skb, dst, ipv);
+ rcu_read_unlock();
+
+ return cast_type;
+}
+
static u8 qeth_l3_cast_type_to_flag(int cast_type)
{
if (cast_type == RTN_MULTICAST)
@@ -1944,12 +1939,13 @@ static u8 qeth_l3_cast_type_to_flag(int cast_type)
static void qeth_l3_fill_header(struct qeth_qdio_out_q *queue,
struct qeth_hdr *hdr, struct sk_buff *skb,
- int ipv, int cast_type, unsigned int data_len)
+ int ipv, unsigned int data_len)
{
struct qeth_hdr_layer3 *l3_hdr = &hdr->hdr.l3;
struct vlan_ethhdr *veth = vlan_eth_hdr(skb);
struct qeth_card *card = queue->card;
struct dst_entry *dst;
+ int cast_type;
hdr->hdr.l3.length = data_len;
@@ -1986,36 +1982,23 @@ static void qeth_l3_fill_header(struct qeth_qdio_out_q *queue,
hdr->hdr.l3.vlan_id = ntohs(veth->h_vlan_TCI);
}
- l3_hdr->flags = qeth_l3_cast_type_to_flag(cast_type);
-
- /* OSA only: */
- if (!ipv) {
- l3_hdr->flags |= QETH_HDR_PASSTHRU;
- return;
- }
-
rcu_read_lock();
- dst = skb_dst(skb);
+ dst = qeth_dst_check_rcu(skb, ipv);
- if (ipv == 4) {
- struct rtable *rt;
+ if (IS_IQD(card) && skb_get_queue_mapping(skb) != QETH_IQD_MCAST_TXQ)
+ cast_type = RTN_UNICAST;
+ else
+ cast_type = qeth_l3_get_cast_type_rcu(skb, dst, ipv);
+ l3_hdr->flags |= qeth_l3_cast_type_to_flag(cast_type);
- if (dst)
- dst = dst_check(dst, 0);
- rt = (struct rtable *) dst;
+ if (ipv == 4) {
+ struct rtable *rt = (struct rtable *) dst;
*((__be32 *) &hdr->hdr.l3.next_hop.ipv4.addr) = (rt) ?
rt_nexthop(rt, ip_hdr(skb)->daddr) :
ip_hdr(skb)->daddr;
- } else {
- /* IPv6 */
- struct rt6_info *rt;
-
- if (dst) {
- rt = (struct rt6_info *) dst;
- dst = dst_check(dst, rt6_get_cookie(rt));
- }
- rt = (struct rt6_info *) dst;
+ } else if (ipv == 6) {
+ struct rt6_info *rt = (struct rt6_info *) dst;
if (rt && !ipv6_addr_any(&rt->rt6i_gateway))
l3_hdr->next_hop.ipv6_addr = rt->rt6i_gateway;
@@ -2025,6 +2008,9 @@ static void qeth_l3_fill_header(struct qeth_qdio_out_q *queue,
hdr->hdr.l3.flags |= QETH_HDR_IPV6;
if (!IS_IQD(card))
hdr->hdr.l3.flags |= QETH_HDR_PASSTHRU;
+ } else {
+ /* OSA only: */
+ l3_hdr->flags |= QETH_HDR_PASSTHRU;
}
rcu_read_unlock();
}
@@ -2044,7 +2030,7 @@ static void qeth_l3_fixup_headers(struct sk_buff *skb)
}
static int qeth_l3_xmit(struct qeth_card *card, struct sk_buff *skb,
- struct qeth_qdio_out_q *queue, int ipv, int cast_type)
+ struct qeth_qdio_out_q *queue, int ipv)
{
unsigned int hw_hdr_len;
int rc;
@@ -2058,7 +2044,7 @@ static int qeth_l3_xmit(struct qeth_card *card, struct sk_buff *skb,
skb_pull(skb, ETH_HLEN);
qeth_l3_fixup_headers(skb);
- return qeth_xmit(card, skb, queue, ipv, cast_type, qeth_l3_fill_header);
+ return qeth_xmit(card, skb, queue, ipv, qeth_l3_fill_header);
}
static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb,
@@ -2069,7 +2055,7 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb,
int ipv = qeth_get_ip_version(skb);
struct qeth_qdio_out_q *queue;
int tx_bytes = skb->len;
- int cast_type, rc;
+ int rc;
if (IS_IQD(card)) {
queue = card->qdio.out_qs[qeth_iqd_translate_txq(dev, txq)];
@@ -2080,24 +2066,18 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb,
(card->options.cq == QETH_CQ_ENABLED &&
skb->protocol != htons(ETH_P_AF_IUCV)))
goto tx_drop;
-
- if (txq == QETH_IQD_MCAST_TXQ)
- cast_type = qeth_l3_get_cast_type(skb);
- else
- cast_type = RTN_UNICAST;
} else {
queue = card->qdio.out_qs[txq];
- cast_type = qeth_l3_get_cast_type(skb);
}
- if (cast_type == RTN_BROADCAST && !card->info.broadcast_capable)
+ if (!(dev->flags & IFF_BROADCAST) &&
+ qeth_l3_get_cast_type(skb) == RTN_BROADCAST)
goto tx_drop;
if (ipv == 4 || IS_IQD(card))
- rc = qeth_l3_xmit(card, skb, queue, ipv, cast_type);
+ rc = qeth_l3_xmit(card, skb, queue, ipv);
else
- rc = qeth_xmit(card, skb, queue, ipv, cast_type,
- qeth_l3_fill_header);
+ rc = qeth_xmit(card, skb, queue, ipv, qeth_l3_fill_header);
if (!rc) {
QETH_TXQ_STAT_INC(queue, tx_packets);
@@ -2337,12 +2317,11 @@ static int qeth_l3_set_online(struct ccwgroup_device *gdev)
mutex_lock(&card->discipline_mutex);
mutex_lock(&card->conf_mutex);
- QETH_DBF_TEXT(SETUP, 2, "setonlin");
- QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
+ QETH_CARD_TEXT(card, 2, "setonlin");
rc = qeth_core_hardsetup_card(card, &carrier_ok);
if (rc) {
- QETH_DBF_TEXT_(SETUP, 2, "2err%04x", rc);
+ QETH_CARD_TEXT_(card, 2, "2err%04x", rc);
rc = -ENODEV;
goto out_remove;
}
@@ -2358,28 +2337,28 @@ static int qeth_l3_set_online(struct ccwgroup_device *gdev)
qeth_print_status_message(card);
/* softsetup */
- QETH_DBF_TEXT(SETUP, 2, "softsetp");
+ QETH_CARD_TEXT(card, 2, "softsetp");
rc = qeth_l3_setadapter_parms(card);
if (rc)
- QETH_DBF_TEXT_(SETUP, 2, "2err%04x", rc);
+ QETH_CARD_TEXT_(card, 2, "2err%04x", rc);
if (!card->options.sniffer) {
rc = qeth_l3_start_ipassists(card);
if (rc) {
- QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
+ QETH_CARD_TEXT_(card, 2, "3err%d", rc);
goto out_remove;
}
rc = qeth_l3_setrouting_v4(card);
if (rc)
- QETH_DBF_TEXT_(SETUP, 2, "4err%04x", rc);
+ QETH_CARD_TEXT_(card, 2, "4err%04x", rc);
rc = qeth_l3_setrouting_v6(card);
if (rc)
- QETH_DBF_TEXT_(SETUP, 2, "5err%04x", rc);
+ QETH_CARD_TEXT_(card, 2, "5err%04x", rc);
}
rc = qeth_init_qdio_queues(card);
if (rc) {
- QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc);
+ QETH_CARD_TEXT_(card, 2, "6err%d", rc);
rc = -ENODEV;
goto out_remove;
}
@@ -2420,7 +2399,6 @@ out_remove:
ccw_device_set_offline(CARD_WDEV(card));
ccw_device_set_offline(CARD_RDEV(card));
qdio_free(CARD_DDEV(card));
- card->state = CARD_STATE_DOWN;
mutex_unlock(&card->conf_mutex);
mutex_unlock(&card->discipline_mutex);
@@ -2435,8 +2413,7 @@ static int __qeth_l3_set_offline(struct ccwgroup_device *cgdev,
mutex_lock(&card->discipline_mutex);
mutex_lock(&card->conf_mutex);
- QETH_DBF_TEXT(SETUP, 3, "setoffl");
- QETH_DBF_HEX(SETUP, 3, &card, sizeof(void *));
+ QETH_CARD_TEXT(card, 3, "setoffl");
if ((!recovery_mode && card->info.hwtrap) || card->info.hwtrap == 2) {
qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
@@ -2462,7 +2439,7 @@ static int __qeth_l3_set_offline(struct ccwgroup_device *cgdev,
if (!rc)
rc = (rc2) ? rc2 : rc3;
if (rc)
- QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
+ QETH_CARD_TEXT_(card, 2, "1err%d", rc);
qdio_free(CARD_DDEV(card));
/* let user_space know that device is offline */
@@ -2505,33 +2482,6 @@ static int qeth_l3_recover(void *ptr)
return 0;
}
-static int qeth_l3_pm_suspend(struct ccwgroup_device *gdev)
-{
- struct qeth_card *card = dev_get_drvdata(&gdev->dev);
-
- qeth_set_allowed_threads(card, 0, 1);
- wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
- if (gdev->state == CCWGROUP_OFFLINE)
- return 0;
-
- qeth_l3_set_offline(gdev);
- return 0;
-}
-
-static int qeth_l3_pm_resume(struct ccwgroup_device *gdev)
-{
- struct qeth_card *card = dev_get_drvdata(&gdev->dev);
- int rc;
-
- rc = qeth_l3_set_online(gdev);
-
- qeth_set_allowed_threads(card, 0xffffffff, 0);
- if (rc)
- dev_warn(&card->gdev->dev, "The qeth device driver "
- "failed to recover an error on the device\n");
- return rc;
-}
-
/* Returns zero if the command is successfully "consumed" */
static int qeth_l3_control_event(struct qeth_card *card,
struct qeth_ipa_cmd *cmd)
@@ -2547,9 +2497,6 @@ struct qeth_discipline qeth_l3_discipline = {
.remove = qeth_l3_remove_device,
.set_online = qeth_l3_set_online,
.set_offline = qeth_l3_set_offline,
- .freeze = qeth_l3_pm_suspend,
- .thaw = qeth_l3_pm_resume,
- .restore = qeth_l3_pm_resume,
.do_ioctl = qeth_l3_do_ioctl,
.control_event_handler = qeth_l3_control_event,
};
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c
index 33eddb02ee30..b018b61bd168 100644
--- a/drivers/s390/scsi/zfcp_fc.c
+++ b/drivers/s390/scsi/zfcp_fc.c
@@ -620,7 +620,7 @@ static void zfcp_fc_sg_free_table(struct scatterlist *sg, int count)
{
int i;
- for (i = 0; i < count; i++, sg++)
+ for (i = 0; i < count; i++, sg = sg_next(sg))
if (sg)
free_page((unsigned long) sg_virt(sg));
else
@@ -641,7 +641,7 @@ static int zfcp_fc_sg_setup_table(struct scatterlist *sg, int count)
int i;
sg_init_table(sg, count);
- for (i = 0; i < count; i++, sg++) {
+ for (i = 0; i < count; i++, sg = sg_next(sg)) {
addr = (void *) get_zeroed_page(GFP_KERNEL);
if (!addr) {
zfcp_fc_sg_free_table(sg, i);
diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c
index 6a3076881321..1a55e5942d36 100644
--- a/drivers/s390/virtio/virtio_ccw.c
+++ b/drivers/s390/virtio/virtio_ccw.c
@@ -46,9 +46,15 @@ struct vq_config_block {
#define VIRTIO_CCW_CONFIG_SIZE 0x100
/* same as PCI config space size, should be enough for all drivers */
+struct vcdev_dma_area {
+ unsigned long indicators;
+ unsigned long indicators2;
+ struct vq_config_block config_block;
+ __u8 status;
+};
+
struct virtio_ccw_device {
struct virtio_device vdev;
- __u8 *status;
__u8 config[VIRTIO_CCW_CONFIG_SIZE];
struct ccw_device *cdev;
__u32 curr_io;
@@ -58,17 +64,24 @@ struct virtio_ccw_device {
spinlock_t lock;
struct mutex io_lock; /* Serializes I/O requests */
struct list_head virtqueues;
- unsigned long indicators;
- unsigned long indicators2;
- struct vq_config_block *config_block;
bool is_thinint;
bool going_away;
bool device_lost;
unsigned int config_ready;
void *airq_info;
- u64 dma_mask;
+ struct vcdev_dma_area *dma_area;
};
+static inline unsigned long *indicators(struct virtio_ccw_device *vcdev)
+{
+ return &vcdev->dma_area->indicators;
+}
+
+static inline unsigned long *indicators2(struct virtio_ccw_device *vcdev)
+{
+ return &vcdev->dma_area->indicators2;
+}
+
struct vq_info_block_legacy {
__u64 queue;
__u32 align;
@@ -127,11 +140,17 @@ static int virtio_ccw_use_airq = 1;
struct airq_info {
rwlock_t lock;
- u8 summary_indicator;
+ u8 summary_indicator_idx;
struct airq_struct airq;
struct airq_iv *aiv;
};
static struct airq_info *airq_areas[MAX_AIRQ_AREAS];
+static u8 *summary_indicators;
+
+static inline u8 *get_summary_indicator(struct airq_info *info)
+{
+ return summary_indicators + info->summary_indicator_idx;
+}
#define CCW_CMD_SET_VQ 0x13
#define CCW_CMD_VDEV_RESET 0x33
@@ -196,7 +215,7 @@ static void virtio_airq_handler(struct airq_struct *airq, bool floating)
break;
vring_interrupt(0, (void *)airq_iv_get_ptr(info->aiv, ai));
}
- info->summary_indicator = 0;
+ *(get_summary_indicator(info)) = 0;
smp_wmb();
/* Walk through indicators field, summary indicator not active. */
for (ai = 0;;) {
@@ -208,7 +227,7 @@ static void virtio_airq_handler(struct airq_struct *airq, bool floating)
read_unlock(&info->lock);
}
-static struct airq_info *new_airq_info(void)
+static struct airq_info *new_airq_info(int index)
{
struct airq_info *info;
int rc;
@@ -217,13 +236,15 @@ static struct airq_info *new_airq_info(void)
if (!info)
return NULL;
rwlock_init(&info->lock);
- info->aiv = airq_iv_create(VIRTIO_IV_BITS, AIRQ_IV_ALLOC | AIRQ_IV_PTR);
+ info->aiv = airq_iv_create(VIRTIO_IV_BITS, AIRQ_IV_ALLOC | AIRQ_IV_PTR
+ | AIRQ_IV_CACHELINE);
if (!info->aiv) {
kfree(info);
return NULL;
}
info->airq.handler = virtio_airq_handler;
- info->airq.lsi_ptr = &info->summary_indicator;
+ info->summary_indicator_idx = index;
+ info->airq.lsi_ptr = get_summary_indicator(info);
info->airq.lsi_mask = 0xff;
info->airq.isc = VIRTIO_AIRQ_ISC;
rc = register_adapter_interrupt(&info->airq);
@@ -245,7 +266,7 @@ static unsigned long get_airq_indicator(struct virtqueue *vqs[], int nvqs,
for (i = 0; i < MAX_AIRQ_AREAS && !indicator_addr; i++) {
if (!airq_areas[i])
- airq_areas[i] = new_airq_info();
+ airq_areas[i] = new_airq_info(i);
info = airq_areas[i];
if (!info)
return 0;
@@ -326,29 +347,29 @@ static void virtio_ccw_drop_indicator(struct virtio_ccw_device *vcdev,
struct airq_info *airq_info = vcdev->airq_info;
if (vcdev->is_thinint) {
- thinint_area = kzalloc(sizeof(*thinint_area),
- GFP_DMA | GFP_KERNEL);
+ thinint_area = ccw_device_dma_zalloc(vcdev->cdev,
+ sizeof(*thinint_area));
if (!thinint_area)
return;
thinint_area->summary_indicator =
- (unsigned long) &airq_info->summary_indicator;
+ (unsigned long) get_summary_indicator(airq_info);
thinint_area->isc = VIRTIO_AIRQ_ISC;
ccw->cmd_code = CCW_CMD_SET_IND_ADAPTER;
ccw->count = sizeof(*thinint_area);
ccw->cda = (__u32)(unsigned long) thinint_area;
} else {
/* payload is the address of the indicators */
- indicatorp = kmalloc(sizeof(&vcdev->indicators),
- GFP_DMA | GFP_KERNEL);
+ indicatorp = ccw_device_dma_zalloc(vcdev->cdev,
+ sizeof(indicators(vcdev)));
if (!indicatorp)
return;
*indicatorp = 0;
ccw->cmd_code = CCW_CMD_SET_IND;
- ccw->count = sizeof(&vcdev->indicators);
+ ccw->count = sizeof(indicators(vcdev));
ccw->cda = (__u32)(unsigned long) indicatorp;
}
/* Deregister indicators from host. */
- vcdev->indicators = 0;
+ *indicators(vcdev) = 0;
ccw->flags = 0;
ret = ccw_io_helper(vcdev, ccw,
vcdev->is_thinint ?
@@ -359,8 +380,8 @@ static void virtio_ccw_drop_indicator(struct virtio_ccw_device *vcdev,
"Failed to deregister indicators (%d)\n", ret);
else if (vcdev->is_thinint)
virtio_ccw_drop_indicators(vcdev);
- kfree(indicatorp);
- kfree(thinint_area);
+ ccw_device_dma_free(vcdev->cdev, indicatorp, sizeof(indicators(vcdev)));
+ ccw_device_dma_free(vcdev->cdev, thinint_area, sizeof(*thinint_area));
}
static inline long __do_kvm_notify(struct subchannel_id schid,
@@ -407,15 +428,15 @@ static int virtio_ccw_read_vq_conf(struct virtio_ccw_device *vcdev,
{
int ret;
- vcdev->config_block->index = index;
+ vcdev->dma_area->config_block.index = index;
ccw->cmd_code = CCW_CMD_READ_VQ_CONF;
ccw->flags = 0;
ccw->count = sizeof(struct vq_config_block);
- ccw->cda = (__u32)(unsigned long)(vcdev->config_block);
+ ccw->cda = (__u32)(unsigned long)(&vcdev->dma_area->config_block);
ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_VQ_CONF);
if (ret)
return ret;
- return vcdev->config_block->num ?: -ENOENT;
+ return vcdev->dma_area->config_block.num ?: -ENOENT;
}
static void virtio_ccw_del_vq(struct virtqueue *vq, struct ccw1 *ccw)
@@ -460,7 +481,8 @@ static void virtio_ccw_del_vq(struct virtqueue *vq, struct ccw1 *ccw)
ret, index);
vring_del_virtqueue(vq);
- kfree(info->info_block);
+ ccw_device_dma_free(vcdev->cdev, info->info_block,
+ sizeof(*info->info_block));
kfree(info);
}
@@ -470,7 +492,7 @@ static void virtio_ccw_del_vqs(struct virtio_device *vdev)
struct ccw1 *ccw;
struct virtio_ccw_device *vcdev = to_vc_device(vdev);
- ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
+ ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw));
if (!ccw)
return;
@@ -479,7 +501,7 @@ static void virtio_ccw_del_vqs(struct virtio_device *vdev)
list_for_each_entry_safe(vq, n, &vdev->vqs, list)
virtio_ccw_del_vq(vq, ccw);
- kfree(ccw);
+ ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw));
}
static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev,
@@ -502,8 +524,8 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev,
err = -ENOMEM;
goto out_err;
}
- info->info_block = kzalloc(sizeof(*info->info_block),
- GFP_DMA | GFP_KERNEL);
+ info->info_block = ccw_device_dma_zalloc(vcdev->cdev,
+ sizeof(*info->info_block));
if (!info->info_block) {
dev_warn(&vcdev->cdev->dev, "no info block\n");
err = -ENOMEM;
@@ -567,7 +589,8 @@ out_err:
if (vq)
vring_del_virtqueue(vq);
if (info) {
- kfree(info->info_block);
+ ccw_device_dma_free(vcdev->cdev, info->info_block,
+ sizeof(*info->info_block));
}
kfree(info);
return ERR_PTR(err);
@@ -581,7 +604,8 @@ static int virtio_ccw_register_adapter_ind(struct virtio_ccw_device *vcdev,
struct virtio_thinint_area *thinint_area = NULL;
struct airq_info *info;
- thinint_area = kzalloc(sizeof(*thinint_area), GFP_DMA | GFP_KERNEL);
+ thinint_area = ccw_device_dma_zalloc(vcdev->cdev,
+ sizeof(*thinint_area));
if (!thinint_area) {
ret = -ENOMEM;
goto out;
@@ -596,7 +620,7 @@ static int virtio_ccw_register_adapter_ind(struct virtio_ccw_device *vcdev,
}
info = vcdev->airq_info;
thinint_area->summary_indicator =
- (unsigned long) &info->summary_indicator;
+ (unsigned long) get_summary_indicator(info);
thinint_area->isc = VIRTIO_AIRQ_ISC;
ccw->cmd_code = CCW_CMD_SET_IND_ADAPTER;
ccw->flags = CCW_FLAG_SLI;
@@ -617,7 +641,7 @@ static int virtio_ccw_register_adapter_ind(struct virtio_ccw_device *vcdev,
virtio_ccw_drop_indicators(vcdev);
}
out:
- kfree(thinint_area);
+ ccw_device_dma_free(vcdev->cdev, thinint_area, sizeof(*thinint_area));
return ret;
}
@@ -633,7 +657,7 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
int ret, i, queue_idx = 0;
struct ccw1 *ccw;
- ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
+ ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw));
if (!ccw)
return -ENOMEM;
@@ -657,10 +681,11 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
* We need a data area under 2G to communicate. Our payload is
* the address of the indicators.
*/
- indicatorp = kmalloc(sizeof(&vcdev->indicators), GFP_DMA | GFP_KERNEL);
+ indicatorp = ccw_device_dma_zalloc(vcdev->cdev,
+ sizeof(indicators(vcdev)));
if (!indicatorp)
goto out;
- *indicatorp = (unsigned long) &vcdev->indicators;
+ *indicatorp = (unsigned long) indicators(vcdev);
if (vcdev->is_thinint) {
ret = virtio_ccw_register_adapter_ind(vcdev, vqs, nvqs, ccw);
if (ret)
@@ -669,32 +694,36 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
}
if (!vcdev->is_thinint) {
/* Register queue indicators with host. */
- vcdev->indicators = 0;
+ *indicators(vcdev) = 0;
ccw->cmd_code = CCW_CMD_SET_IND;
ccw->flags = 0;
- ccw->count = sizeof(&vcdev->indicators);
+ ccw->count = sizeof(indicators(vcdev));
ccw->cda = (__u32)(unsigned long) indicatorp;
ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_IND);
if (ret)
goto out;
}
/* Register indicators2 with host for config changes */
- *indicatorp = (unsigned long) &vcdev->indicators2;
- vcdev->indicators2 = 0;
+ *indicatorp = (unsigned long) indicators2(vcdev);
+ *indicators2(vcdev) = 0;
ccw->cmd_code = CCW_CMD_SET_CONF_IND;
ccw->flags = 0;
- ccw->count = sizeof(&vcdev->indicators2);
+ ccw->count = sizeof(indicators2(vcdev));
ccw->cda = (__u32)(unsigned long) indicatorp;
ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_CONF_IND);
if (ret)
goto out;
- kfree(indicatorp);
- kfree(ccw);
+ if (indicatorp)
+ ccw_device_dma_free(vcdev->cdev, indicatorp,
+ sizeof(indicators(vcdev)));
+ ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw));
return 0;
out:
- kfree(indicatorp);
- kfree(ccw);
+ if (indicatorp)
+ ccw_device_dma_free(vcdev->cdev, indicatorp,
+ sizeof(indicators(vcdev)));
+ ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw));
virtio_ccw_del_vqs(vdev);
return ret;
}
@@ -704,12 +733,12 @@ static void virtio_ccw_reset(struct virtio_device *vdev)
struct virtio_ccw_device *vcdev = to_vc_device(vdev);
struct ccw1 *ccw;
- ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
+ ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw));
if (!ccw)
return;
/* Zero status bits. */
- *vcdev->status = 0;
+ vcdev->dma_area->status = 0;
/* Send a reset ccw on device. */
ccw->cmd_code = CCW_CMD_VDEV_RESET;
@@ -717,7 +746,7 @@ static void virtio_ccw_reset(struct virtio_device *vdev)
ccw->count = 0;
ccw->cda = 0;
ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_RESET);
- kfree(ccw);
+ ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw));
}
static u64 virtio_ccw_get_features(struct virtio_device *vdev)
@@ -728,11 +757,11 @@ static u64 virtio_ccw_get_features(struct virtio_device *vdev)
u64 rc;
struct ccw1 *ccw;
- ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
+ ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw));
if (!ccw)
return 0;
- features = kzalloc(sizeof(*features), GFP_DMA | GFP_KERNEL);
+ features = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*features));
if (!features) {
rc = 0;
goto out_free;
@@ -765,8 +794,8 @@ static u64 virtio_ccw_get_features(struct virtio_device *vdev)
rc |= (u64)le32_to_cpu(features->features) << 32;
out_free:
- kfree(features);
- kfree(ccw);
+ ccw_device_dma_free(vcdev->cdev, features, sizeof(*features));
+ ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw));
return rc;
}
@@ -791,11 +820,11 @@ static int virtio_ccw_finalize_features(struct virtio_device *vdev)
return -EINVAL;
}
- ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
+ ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw));
if (!ccw)
return -ENOMEM;
- features = kzalloc(sizeof(*features), GFP_DMA | GFP_KERNEL);
+ features = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*features));
if (!features) {
ret = -ENOMEM;
goto out_free;
@@ -830,8 +859,8 @@ static int virtio_ccw_finalize_features(struct virtio_device *vdev)
ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_FEAT);
out_free:
- kfree(features);
- kfree(ccw);
+ ccw_device_dma_free(vcdev->cdev, features, sizeof(*features));
+ ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw));
return ret;
}
@@ -845,11 +874,12 @@ static void virtio_ccw_get_config(struct virtio_device *vdev,
void *config_area;
unsigned long flags;
- ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
+ ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw));
if (!ccw)
return;
- config_area = kzalloc(VIRTIO_CCW_CONFIG_SIZE, GFP_DMA | GFP_KERNEL);
+ config_area = ccw_device_dma_zalloc(vcdev->cdev,
+ VIRTIO_CCW_CONFIG_SIZE);
if (!config_area)
goto out_free;
@@ -871,8 +901,8 @@ static void virtio_ccw_get_config(struct virtio_device *vdev,
memcpy(buf, config_area + offset, len);
out_free:
- kfree(config_area);
- kfree(ccw);
+ ccw_device_dma_free(vcdev->cdev, config_area, VIRTIO_CCW_CONFIG_SIZE);
+ ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw));
}
static void virtio_ccw_set_config(struct virtio_device *vdev,
@@ -884,11 +914,12 @@ static void virtio_ccw_set_config(struct virtio_device *vdev,
void *config_area;
unsigned long flags;
- ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
+ ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw));
if (!ccw)
return;
- config_area = kzalloc(VIRTIO_CCW_CONFIG_SIZE, GFP_DMA | GFP_KERNEL);
+ config_area = ccw_device_dma_zalloc(vcdev->cdev,
+ VIRTIO_CCW_CONFIG_SIZE);
if (!config_area)
goto out_free;
@@ -907,61 +938,61 @@ static void virtio_ccw_set_config(struct virtio_device *vdev,
ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_CONFIG);
out_free:
- kfree(config_area);
- kfree(ccw);
+ ccw_device_dma_free(vcdev->cdev, config_area, VIRTIO_CCW_CONFIG_SIZE);
+ ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw));
}
static u8 virtio_ccw_get_status(struct virtio_device *vdev)
{
struct virtio_ccw_device *vcdev = to_vc_device(vdev);
- u8 old_status = *vcdev->status;
+ u8 old_status = vcdev->dma_area->status;
struct ccw1 *ccw;
if (vcdev->revision < 1)
- return *vcdev->status;
+ return vcdev->dma_area->status;
- ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
+ ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw));
if (!ccw)
return old_status;
ccw->cmd_code = CCW_CMD_READ_STATUS;
ccw->flags = 0;
- ccw->count = sizeof(*vcdev->status);
- ccw->cda = (__u32)(unsigned long)vcdev->status;
+ ccw->count = sizeof(vcdev->dma_area->status);
+ ccw->cda = (__u32)(unsigned long)&vcdev->dma_area->status;
ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_STATUS);
/*
* If the channel program failed (should only happen if the device
* was hotunplugged, and then we clean up via the machine check
- * handler anyway), vcdev->status was not overwritten and we just
+ * handler anyway), vcdev->dma_area->status was not overwritten and we just
* return the old status, which is fine.
*/
- kfree(ccw);
+ ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw));
- return *vcdev->status;
+ return vcdev->dma_area->status;
}
static void virtio_ccw_set_status(struct virtio_device *vdev, u8 status)
{
struct virtio_ccw_device *vcdev = to_vc_device(vdev);
- u8 old_status = *vcdev->status;
+ u8 old_status = vcdev->dma_area->status;
struct ccw1 *ccw;
int ret;
- ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
+ ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw));
if (!ccw)
return;
/* Write the status to the host. */
- *vcdev->status = status;
+ vcdev->dma_area->status = status;
ccw->cmd_code = CCW_CMD_WRITE_STATUS;
ccw->flags = 0;
ccw->count = sizeof(status);
- ccw->cda = (__u32)(unsigned long)vcdev->status;
+ ccw->cda = (__u32)(unsigned long)&vcdev->dma_area->status;
ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_STATUS);
/* Write failed? We assume status is unchanged. */
if (ret)
- *vcdev->status = old_status;
- kfree(ccw);
+ vcdev->dma_area->status = old_status;
+ ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw));
}
static const char *virtio_ccw_bus_name(struct virtio_device *vdev)
@@ -994,8 +1025,8 @@ static void virtio_ccw_release_dev(struct device *_d)
struct virtio_device *dev = dev_to_virtio(_d);
struct virtio_ccw_device *vcdev = to_vc_device(dev);
- kfree(vcdev->status);
- kfree(vcdev->config_block);
+ ccw_device_dma_free(vcdev->cdev, vcdev->dma_area,
+ sizeof(*vcdev->dma_area));
kfree(vcdev);
}
@@ -1093,17 +1124,17 @@ static void virtio_ccw_int_handler(struct ccw_device *cdev,
vcdev->err = -EIO;
}
virtio_ccw_check_activity(vcdev, activity);
- for_each_set_bit(i, &vcdev->indicators,
- sizeof(vcdev->indicators) * BITS_PER_BYTE) {
+ for_each_set_bit(i, indicators(vcdev),
+ sizeof(*indicators(vcdev)) * BITS_PER_BYTE) {
/* The bit clear must happen before the vring kick. */
- clear_bit(i, &vcdev->indicators);
+ clear_bit(i, indicators(vcdev));
barrier();
vq = virtio_ccw_vq_by_ind(vcdev, i);
vring_interrupt(0, vq);
}
- if (test_bit(0, &vcdev->indicators2)) {
+ if (test_bit(0, indicators2(vcdev))) {
virtio_config_changed(&vcdev->vdev);
- clear_bit(0, &vcdev->indicators2);
+ clear_bit(0, indicators2(vcdev));
}
}
@@ -1203,12 +1234,12 @@ static int virtio_ccw_set_transport_rev(struct virtio_ccw_device *vcdev)
struct ccw1 *ccw;
int ret;
- ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
+ ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw));
if (!ccw)
return -ENOMEM;
- rev = kzalloc(sizeof(*rev), GFP_DMA | GFP_KERNEL);
+ rev = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*rev));
if (!rev) {
- kfree(ccw);
+ ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw));
return -ENOMEM;
}
@@ -1238,8 +1269,8 @@ static int virtio_ccw_set_transport_rev(struct virtio_ccw_device *vcdev)
}
} while (ret == -EOPNOTSUPP);
- kfree(ccw);
- kfree(rev);
+ ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw));
+ ccw_device_dma_free(vcdev->cdev, rev, sizeof(*rev));
return ret;
}
@@ -1255,24 +1286,11 @@ static int virtio_ccw_online(struct ccw_device *cdev)
ret = -ENOMEM;
goto out_free;
}
-
vcdev->vdev.dev.parent = &cdev->dev;
- cdev->dev.dma_mask = &vcdev->dma_mask;
- /* we are fine with common virtio infrastructure using 64 bit DMA */
- ret = dma_set_mask_and_coherent(&cdev->dev, DMA_BIT_MASK(64));
- if (ret) {
- dev_warn(&cdev->dev, "Failed to enable 64-bit DMA.\n");
- goto out_free;
- }
-
- vcdev->config_block = kzalloc(sizeof(*vcdev->config_block),
- GFP_DMA | GFP_KERNEL);
- if (!vcdev->config_block) {
- ret = -ENOMEM;
- goto out_free;
- }
- vcdev->status = kzalloc(sizeof(*vcdev->status), GFP_DMA | GFP_KERNEL);
- if (!vcdev->status) {
+ vcdev->cdev = cdev;
+ vcdev->dma_area = ccw_device_dma_zalloc(vcdev->cdev,
+ sizeof(*vcdev->dma_area));
+ if (!vcdev->dma_area) {
ret = -ENOMEM;
goto out_free;
}
@@ -1281,7 +1299,6 @@ static int virtio_ccw_online(struct ccw_device *cdev)
vcdev->vdev.dev.release = virtio_ccw_release_dev;
vcdev->vdev.config = &virtio_ccw_config_ops;
- vcdev->cdev = cdev;
init_waitqueue_head(&vcdev->wait_q);
INIT_LIST_HEAD(&vcdev->virtqueues);
spin_lock_init(&vcdev->lock);
@@ -1312,8 +1329,8 @@ out_put:
return ret;
out_free:
if (vcdev) {
- kfree(vcdev->status);
- kfree(vcdev->config_block);
+ ccw_device_dma_free(vcdev->cdev, vcdev->dma_area,
+ sizeof(*vcdev->dma_area));
}
kfree(vcdev);
return ret;
@@ -1483,8 +1500,17 @@ static void __init no_auto_parse(void)
static int __init virtio_ccw_init(void)
{
+ int rc;
+
/* parse no_auto string before we do anything further */
no_auto_parse();
- return ccw_driver_register(&virtio_ccw_driver);
+
+ summary_indicators = cio_dma_zalloc(MAX_AIRQ_AREAS);
+ if (!summary_indicators)
+ return -ENOMEM;
+ rc = ccw_driver_register(&virtio_ccw_driver);
+ if (rc)
+ cio_dma_free(summary_indicators, MAX_AIRQ_AREAS);
+ return rc;
}
device_initcall(virtio_ccw_init);
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 61da513fc0ed..75f66f8ad3ea 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -99,28 +99,6 @@ config CHR_DEV_ST
To compile this driver as a module, choose M here and read
<file:Documentation/scsi/scsi.txt>. The module will be called st.
-config CHR_DEV_OSST
- tristate "SCSI OnStream SC-x0 tape support"
- depends on SCSI
- ---help---
- The OnStream SC-x0 SCSI tape drives cannot be driven by the
- standard st driver, but instead need this special osst driver and
- use the /dev/osstX char device nodes (major 206). Via usb-storage,
- you may be able to drive the USB-x0 and DI-x0 drives as well.
- Note that there is also a second generation of OnStream
- tape drives (ADR-x0) that supports the standard SCSI-2 commands for
- tapes (QIC-157) and can be driven by the standard driver st.
- For more information, you may have a look at the SCSI-HOWTO
- <http://www.tldp.org/docs.html#howto> and
- <file:Documentation/scsi/osst.txt> in the kernel source.
- More info on the OnStream driver may be found on
- <http://sourceforge.net/projects/osst/>
- Please also have a look at the standard st docu, as most of it
- applies to osst as well.
-
- To compile this driver as a module, choose M here and read
- <file:Documentation/scsi/scsi.txt>. The module will be called osst.
-
config BLK_DEV_SR
tristate "SCSI CDROM support"
depends on SCSI && BLK_DEV
@@ -183,7 +161,7 @@ config CHR_DEV_SCH
If you want to compile this as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
- say M here and read <file:Documentation/kbuild/modules.txt> and
+ say M here and read <file:Documentation/kbuild/modules.rst> and
<file:Documentation/scsi/scsi.txt>. The module will be called ch.o.
If unsure, say N.
@@ -664,6 +642,41 @@ config SCSI_DMX3191D
To compile this driver as a module, choose M here: the
module will be called dmx3191d.
+config SCSI_FDOMAIN
+ tristate
+ depends on SCSI
+
+config SCSI_FDOMAIN_PCI
+ tristate "Future Domain TMC-3260/AHA-2920A PCI SCSI support"
+ depends on PCI && SCSI
+ select SCSI_FDOMAIN
+ help
+ This is support for Future Domain's PCI SCSI host adapters (TMC-3260)
+ and other adapters with PCI bus based on the Future Domain chipsets
+ (Adaptec AHA-2920A).
+
+ NOTE: Newer Adaptec AHA-2920C boards use the Adaptec AIC-7850 chip
+ and should use the aic7xxx driver ("Adaptec AIC7xxx chipset SCSI
+ controller support"). This Future Domain driver works with the older
+ Adaptec AHA-2920A boards with a Future Domain chip on them.
+
+ To compile this driver as a module, choose M here: the
+ module will be called fdomain_pci.
+
+config SCSI_FDOMAIN_ISA
+ tristate "Future Domain 16xx ISA SCSI support"
+ depends on ISA && SCSI
+ select CHECK_SIGNATURE
+ select SCSI_FDOMAIN
+ help
+ This is support for Future Domain's 16-bit SCSI host adapters
+ (TMC-1660/1680, TMC-1650/1670, TMC-1610M/MER/MEX) and other adapters
+ with ISA bus based on the Future Domain chipsets (Quantum ISA-200S,
+ ISA-250MG; and at least one IBM board).
+
+ To compile this driver as a module, choose M here: the
+ module will be called fdomain_isa.
+
config SCSI_GDTH
tristate "Intel/ICP (former GDT SCSI Disk Array) RAID Controller support"
depends on PCI && SCSI
@@ -1474,7 +1487,7 @@ config ZFCP
This driver is also available as a module. This module will be
called zfcp. If you want to compile it as a module, say M here
- and read <file:Documentation/kbuild/modules.txt>.
+ and read <file:Documentation/kbuild/modules.rst>.
config SCSI_PMCRAID
tristate "PMC SIERRA Linux MaxRAID adapter support"
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 8826111fdf4a..aeda53901064 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -76,6 +76,9 @@ obj-$(CONFIG_SCSI_AIC94XX) += aic94xx/
obj-$(CONFIG_SCSI_PM8001) += pm8001/
obj-$(CONFIG_SCSI_ISCI) += isci/
obj-$(CONFIG_SCSI_IPS) += ips.o
+obj-$(CONFIG_SCSI_FDOMAIN) += fdomain.o
+obj-$(CONFIG_SCSI_FDOMAIN_PCI) += fdomain_pci.o
+obj-$(CONFIG_SCSI_FDOMAIN_ISA) += fdomain_isa.o
obj-$(CONFIG_SCSI_GENERIC_NCR5380) += g_NCR5380.o
obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicfas408.o qlogicfas.o
obj-$(CONFIG_PCMCIA_QLOGIC) += qlogicfas408.o
@@ -143,7 +146,6 @@ obj-$(CONFIG_SCSI_WD719X) += wd719x.o
obj-$(CONFIG_ARM) += arm/
obj-$(CONFIG_CHR_DEV_ST) += st.o
-obj-$(CONFIG_CHR_DEV_OSST) += osst.o
obj-$(CONFIG_BLK_DEV_SD) += sd_mod.o
obj-$(CONFIG_BLK_DEV_SR) += sr_mod.o
obj-$(CONFIG_CHR_DEV_SG) += sg.o
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index fe0535affc14..536426f25e86 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -149,12 +149,10 @@ static inline void initialize_SCp(struct scsi_cmnd *cmd)
if (scsi_bufflen(cmd)) {
cmd->SCp.buffer = scsi_sglist(cmd);
- cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
cmd->SCp.this_residual = cmd->SCp.buffer->length;
} else {
cmd->SCp.buffer = NULL;
- cmd->SCp.buffers_residual = 0;
cmd->SCp.ptr = NULL;
cmd->SCp.this_residual = 0;
}
@@ -163,6 +161,17 @@ static inline void initialize_SCp(struct scsi_cmnd *cmd)
cmd->SCp.Message = 0;
}
+static inline void advance_sg_buffer(struct scsi_cmnd *cmd)
+{
+ struct scatterlist *s = cmd->SCp.buffer;
+
+ if (!cmd->SCp.this_residual && s && !sg_is_last(s)) {
+ cmd->SCp.buffer = sg_next(s);
+ cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
+ cmd->SCp.this_residual = cmd->SCp.buffer->length;
+ }
+}
+
/**
* NCR5380_poll_politely2 - wait for two chip register values
* @hostdata: host private data
@@ -709,6 +718,8 @@ static void NCR5380_main(struct work_struct *work)
NCR5380_information_transfer(instance);
done = 0;
}
+ if (!hostdata->connected)
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
spin_unlock_irq(&hostdata->lock);
if (!done)
cond_resched();
@@ -1110,8 +1121,6 @@ static bool NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
spin_lock_irq(&hostdata->lock);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
NCR5380_reselect(instance);
- if (!hostdata->connected)
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
shost_printk(KERN_ERR, instance, "reselection after won arbitration?\n");
goto out;
}
@@ -1119,7 +1128,6 @@ static bool NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
if (err < 0) {
spin_lock_irq(&hostdata->lock);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
/* Can't touch cmd if it has been reclaimed by the scsi ML */
if (!hostdata->selecting)
@@ -1157,7 +1165,6 @@ static bool NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
if (err < 0) {
shost_printk(KERN_ERR, instance, "select: REQ timeout\n");
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
goto out;
}
if (!hostdata->selecting) {
@@ -1672,12 +1679,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
sun3_dma_setup_done != cmd) {
int count;
- if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
- ++cmd->SCp.buffer;
- --cmd->SCp.buffers_residual;
- cmd->SCp.this_residual = cmd->SCp.buffer->length;
- cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
- }
+ advance_sg_buffer(cmd);
count = sun3scsi_dma_xfer_len(hostdata, cmd);
@@ -1727,15 +1729,11 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
* scatter-gather list, move onto the next one.
*/
- if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
- ++cmd->SCp.buffer;
- --cmd->SCp.buffers_residual;
- cmd->SCp.this_residual = cmd->SCp.buffer->length;
- cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
- dsprintk(NDEBUG_INFORMATION, instance, "%d bytes and %d buffers left\n",
- cmd->SCp.this_residual,
- cmd->SCp.buffers_residual);
- }
+ advance_sg_buffer(cmd);
+ dsprintk(NDEBUG_INFORMATION, instance,
+ "this residual %d, sg ents %d\n",
+ cmd->SCp.this_residual,
+ sg_nents(cmd->SCp.buffer));
/*
* The preferred transfer method is going to be
@@ -1763,10 +1761,8 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
scmd_printk(KERN_INFO, cmd,
"switching to slow handshake\n");
cmd->device->borken = 1;
- sink = 1;
- do_abort(instance);
- cmd->result = DID_ERROR << 16;
- /* XXX - need to source or sink data here, as appropriate */
+ do_reset(instance);
+ bus_reset_cleanup(instance);
}
} else {
/* Transfer a small chunk so that the
@@ -1826,9 +1822,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
*/
NCR5380_write(TARGET_COMMAND_REG, 0);
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-
maybe_release_dma_irq(instance);
return;
case MESSAGE_REJECT:
@@ -1860,8 +1853,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
*/
NCR5380_write(TARGET_COMMAND_REG, 0);
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
#ifdef SUN3_SCSI_VME
dregs->csr |= CSR_DMA_ENABLE;
#endif
@@ -1964,7 +1955,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
cmd->result = DID_ERROR << 16;
complete_cmd(instance, cmd);
maybe_release_dma_irq(instance);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
return;
}
msgout = NOP;
@@ -2136,12 +2126,7 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
if (sun3_dma_setup_done != tmp) {
int count;
- if (!tmp->SCp.this_residual && tmp->SCp.buffers_residual) {
- ++tmp->SCp.buffer;
- --tmp->SCp.buffers_residual;
- tmp->SCp.this_residual = tmp->SCp.buffer->length;
- tmp->SCp.ptr = sg_virt(tmp->SCp.buffer);
- }
+ advance_sg_buffer(tmp);
count = sun3scsi_dma_xfer_len(hostdata, tmp);
diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h
index efca509b92b0..5935fd6d1a05 100644
--- a/drivers/scsi/NCR5380.h
+++ b/drivers/scsi/NCR5380.h
@@ -235,7 +235,7 @@ struct NCR5380_cmd {
#define NCR5380_PIO_CHUNK_SIZE 256
/* Time limit (ms) to poll registers when IRQs are disabled, e.g. during PDMA */
-#define NCR5380_REG_POLL_TIME 15
+#define NCR5380_REG_POLL_TIME 10
static inline struct scsi_cmnd *NCR5380_to_scmd(struct NCR5380_cmd *ncmd_ptr)
{
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 926311c792d5..a242a62caaa1 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -7710,7 +7710,7 @@ adv_get_sglist(struct asc_board *boardp, adv_req_t *reqp,
sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */
return ADV_SUCCESS;
}
- slp++;
+ slp = sg_next(slp);
}
sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
prev_sg_block = sg_block;
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index 88c649b3ef61..eb466c2e1839 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -937,7 +937,6 @@ static int aha152x_internal_queue(struct scsi_cmnd *SCpnt,
SCp.ptr : buffer pointer
SCp.this_residual : buffer length
SCp.buffer : next buffer
- SCp.buffers_residual : left buffers in list
SCp.phase : current state of the command */
if ((phase & resetting) || !scsi_sglist(SCpnt)) {
@@ -945,13 +944,11 @@ static int aha152x_internal_queue(struct scsi_cmnd *SCpnt,
SCpnt->SCp.this_residual = 0;
scsi_set_resid(SCpnt, 0);
SCpnt->SCp.buffer = NULL;
- SCpnt->SCp.buffers_residual = 0;
} else {
scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
SCpnt->SCp.buffer = scsi_sglist(SCpnt);
SCpnt->SCp.ptr = SG_ADDRESS(SCpnt->SCp.buffer);
SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
- SCpnt->SCp.buffers_residual = scsi_sg_count(SCpnt) - 1;
}
DO_LOCK(flags);
@@ -2019,10 +2016,9 @@ static void datai_run(struct Scsi_Host *shpnt)
}
if (CURRENT_SC->SCp.this_residual == 0 &&
- CURRENT_SC->SCp.buffers_residual > 0) {
+ !sg_is_last(CURRENT_SC->SCp.buffer)) {
/* advance to next buffer */
- CURRENT_SC->SCp.buffers_residual--;
- CURRENT_SC->SCp.buffer++;
+ CURRENT_SC->SCp.buffer = sg_next(CURRENT_SC->SCp.buffer);
CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer);
CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
}
@@ -2125,10 +2121,10 @@ static void datao_run(struct Scsi_Host *shpnt)
CMD_INC_RESID(CURRENT_SC, -2 * data_count);
}
- if(CURRENT_SC->SCp.this_residual==0 && CURRENT_SC->SCp.buffers_residual>0) {
+ if (CURRENT_SC->SCp.this_residual == 0 &&
+ !sg_is_last(CURRENT_SC->SCp.buffer)) {
/* advance to next buffer */
- CURRENT_SC->SCp.buffers_residual--;
- CURRENT_SC->SCp.buffer++;
+ CURRENT_SC->SCp.buffer = sg_next(CURRENT_SC->SCp.buffer);
CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer);
CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
}
@@ -2147,22 +2143,26 @@ static void datao_run(struct Scsi_Host *shpnt)
static void datao_end(struct Scsi_Host *shpnt)
{
if(TESTLO(DMASTAT, DFIFOEMP)) {
- int data_count = (DATA_LEN - scsi_get_resid(CURRENT_SC)) -
- GETSTCNT();
+ u32 datao_cnt = GETSTCNT();
+ int datao_out = DATA_LEN - scsi_get_resid(CURRENT_SC);
+ int done;
+ struct scatterlist *sg = scsi_sglist(CURRENT_SC);
- CMD_INC_RESID(CURRENT_SC, data_count);
+ CMD_INC_RESID(CURRENT_SC, datao_out - datao_cnt);
- data_count -= CURRENT_SC->SCp.ptr -
- SG_ADDRESS(CURRENT_SC->SCp.buffer);
- while(data_count>0) {
- CURRENT_SC->SCp.buffer--;
- CURRENT_SC->SCp.buffers_residual++;
- data_count -= CURRENT_SC->SCp.buffer->length;
+ done = scsi_bufflen(CURRENT_SC) - scsi_get_resid(CURRENT_SC);
+ /* Locate the first SG entry not yet sent */
+ while (done > 0 && !sg_is_last(sg)) {
+ if (done < sg->length)
+ break;
+ done -= sg->length;
+ sg = sg_next(sg);
}
- CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer) -
- data_count;
- CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length +
- data_count;
+
+ CURRENT_SC->SCp.buffer = sg;
+ CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer) + done;
+ CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length -
+ done;
}
SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
@@ -2490,7 +2490,7 @@ static void get_command(struct seq_file *m, struct scsi_cmnd * ptr)
seq_printf(m, "); resid=%d; residual=%d; buffers=%d; phase |",
scsi_get_resid(ptr), ptr->SCp.this_residual,
- ptr->SCp.buffers_residual);
+ sg_nents(ptr->SCp.buffer) - 1);
if (ptr->SCp.phase & not_issued)
seq_puts(m, "not issued|");
diff --git a/drivers/scsi/aic7xxx/aic7xxx.reg b/drivers/scsi/aic7xxx/aic7xxx.reg
index ba0b411d03e2..00fde2243e48 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.reg
+++ b/drivers/scsi/aic7xxx/aic7xxx.reg
@@ -1666,7 +1666,7 @@ scratch_ram {
size 6
/*
* These are reserved registers in the card's scratch ram on the 2742.
- * The EISA configuraiton chip is mapped here. On Rev E. of the
+ * The EISA configuration chip is mapped here. On Rev E. of the
* aic7770, the sequencer can use this area for scratch, but the
* host cannot directly access these registers. On later chips, this
* area can be read and written by both the host and the sequencer.
diff --git a/drivers/scsi/aic94xx/Kconfig b/drivers/scsi/aic94xx/Kconfig
index c83fe751d0bb..71931c371b1c 100644
--- a/drivers/scsi/aic94xx/Kconfig
+++ b/drivers/scsi/aic94xx/Kconfig
@@ -1,28 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# Kernel configuration file for aic94xx SAS/SATA driver.
#
# Copyright (c) 2005 Adaptec, Inc. All rights reserved.
# Copyright (c) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
#
-# This file is licensed under GPLv2.
-#
-# This file is part of the aic94xx driver.
-#
-# The aic94xx driver is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License as
-# published by the Free Software Foundation; version 2 of the
-# License.
-#
-# The aic94xx driver is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Aic94xx Driver; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-#
-#
config SCSI_AIC94XX
tristate "Adaptec AIC94xx SAS/SATA support"
diff --git a/drivers/scsi/aic94xx/aic94xx_dev.c b/drivers/scsi/aic94xx/aic94xx_dev.c
index 730b35e7c1ba..604a5331f639 100644
--- a/drivers/scsi/aic94xx/aic94xx_dev.c
+++ b/drivers/scsi/aic94xx/aic94xx_dev.c
@@ -170,9 +170,7 @@ static int asd_init_target_ddb(struct domain_device *dev)
}
} else {
flags |= CONCURRENT_CONN_SUPP;
- if (!dev->parent &&
- (dev->dev_type == SAS_EDGE_EXPANDER_DEVICE ||
- dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE))
+ if (!dev->parent && dev_is_expander(dev->dev_type))
asd_ddbsite_write_byte(asd_ha, ddb, MAX_CCONN,
4);
else
diff --git a/drivers/scsi/arm/acornscsi-io.S b/drivers/scsi/arm/acornscsi-io.S
index 22171b2110a8..fdd7237bb829 100644
--- a/drivers/scsi/arm/acornscsi-io.S
+++ b/drivers/scsi/arm/acornscsi-io.S
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/drivers/acorn/scsi/acornscsi-io.S: Acorn SCSI card IO
- *
- * 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.
*/
#include <linux/linkage.h>
diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c
index d7509859dc00..d12dd89538df 100644
--- a/drivers/scsi/arm/acornscsi.c
+++ b/drivers/scsi/arm/acornscsi.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/acorn/scsi/acornscsi.c
*
* Acorn SCSI 3 driver
* By R.M.King.
*
- * 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.
- *
* Abandoned using the Select and Transfer command since there were
* some nasty races between our software and the target devices that
* were not easy to solve, and the device errata had a lot of entries
diff --git a/drivers/scsi/arm/acornscsi.h b/drivers/scsi/arm/acornscsi.h
index 01bc715a3aec..376c76bc2aca 100644
--- a/drivers/scsi/arm/acornscsi.h
+++ b/drivers/scsi/arm/acornscsi.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/drivers/acorn/scsi/acornscsi.h
*
* Copyright (C) 1997 Russell King
*
- * 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.
- *
* Acorn SCSI driver
*/
#ifndef ACORNSCSI_H
diff --git a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c
index 40afcbd8de61..a1f3e9ee4e63 100644
--- a/drivers/scsi/arm/cumana_2.c
+++ b/drivers/scsi/arm/cumana_2.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/acorn/scsi/cumana_2.c
*
* Copyright (C) 1997-2005 Russell King
*
- * 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.
- *
* Changelog:
* 30-08-1997 RMK 0.0.0 Created, READONLY version.
* 22-01-1998 RMK 0.0.1 Updated to 2.1.80.
diff --git a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c
index 8f64c370a8a7..134f040d58e2 100644
--- a/drivers/scsi/arm/eesox.c
+++ b/drivers/scsi/arm/eesox.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/acorn/scsi/eesox.c
*
* Copyright (C) 1997-2005 Russell King
*
- * 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.
- *
* This driver is based on experimentation. Hence, it may have made
* assumptions about the particular card that I have available, and
* may not be reliable!
diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c
index 27bda2b05de6..aea4fd73c862 100644
--- a/drivers/scsi/arm/fas216.c
+++ b/drivers/scsi/arm/fas216.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/acorn/scsi/fas216.c
*
* Copyright (C) 1997-2003 Russell King
*
- * 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.
- *
* Based on information in qlogicfas.c by Tom Zerucha, Michael Griffith, and
* other sources, including:
* the AMD Am53CF94 data sheet
diff --git a/drivers/scsi/arm/fas216.h b/drivers/scsi/arm/fas216.h
index c57c16ef8193..847413ce14cf 100644
--- a/drivers/scsi/arm/fas216.h
+++ b/drivers/scsi/arm/fas216.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/drivers/acorn/scsi/fas216.h
*
* Copyright (C) 1997-2000 Russell King
*
- * 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.
- *
* FAS216 generic driver
*/
#ifndef FAS216_H
diff --git a/drivers/scsi/arm/msgqueue.c b/drivers/scsi/arm/msgqueue.c
index 7c95c7582b29..58115831362f 100644
--- a/drivers/scsi/arm/msgqueue.c
+++ b/drivers/scsi/arm/msgqueue.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/acorn/scsi/msgqueue.c
*
* Copyright (C) 1997-1998 Russell King
*
- * 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.
- *
* message queue handling
*/
#include <linux/module.h>
diff --git a/drivers/scsi/arm/msgqueue.h b/drivers/scsi/arm/msgqueue.h
index 41c7333df3e3..4bcc400f556b 100644
--- a/drivers/scsi/arm/msgqueue.h
+++ b/drivers/scsi/arm/msgqueue.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/drivers/acorn/scsi/msgqueue.h
*
* Copyright (C) 1997 Russell King
*
- * 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.
- *
* message queue handling
*/
#ifndef MSGQUEUE_H
diff --git a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c
index 759f95ba993c..c795537a671c 100644
--- a/drivers/scsi/arm/powertec.c
+++ b/drivers/scsi/arm/powertec.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/acorn/scsi/powertec.c
*
* Copyright (C) 1997-2005 Russell King
- *
- * 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.
*/
#include <linux/module.h>
#include <linux/blkdev.h>
diff --git a/drivers/scsi/arm/queue.c b/drivers/scsi/arm/queue.c
index 996dfe903928..e5559f27669d 100644
--- a/drivers/scsi/arm/queue.c
+++ b/drivers/scsi/arm/queue.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/acorn/scsi/queue.c: queue handling primitives
*
* Copyright (C) 1997-2000 Russell King
*
- * 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.
- *
* Changelog:
* 15-Sep-1997 RMK Created.
* 11-Oct-1997 RMK Corrected problem with queue_remove_exclude
diff --git a/drivers/scsi/arm/queue.h b/drivers/scsi/arm/queue.h
index 3c519c9237b2..cb51379dce94 100644
--- a/drivers/scsi/arm/queue.h
+++ b/drivers/scsi/arm/queue.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/drivers/acorn/scsi/queue.h: queue handling
*
* Copyright (C) 1997 Russell King
- *
- * 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.
*/
#ifndef QUEUE_H
#define QUEUE_H
diff --git a/drivers/scsi/arm/scsi.h b/drivers/scsi/arm/scsi.h
index 138a521ba1a8..4d5ff7b4e864 100644
--- a/drivers/scsi/arm/scsi.h
+++ b/drivers/scsi/arm/scsi.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/drivers/acorn/scsi/scsi.h
*
* Copyright (C) 2002 Russell King
*
- * 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.
- *
* Commonly used scsi driver functions.
*/
diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h
index 901a31632493..3b84db8d13a9 100644
--- a/drivers/scsi/bnx2fc/bnx2fc.h
+++ b/drivers/scsi/bnx2fc/bnx2fc.h
@@ -66,7 +66,7 @@
#include "bnx2fc_constants.h"
#define BNX2FC_NAME "bnx2fc"
-#define BNX2FC_VERSION "2.11.8"
+#define BNX2FC_VERSION "2.12.10"
#define PFX "bnx2fc: "
@@ -75,8 +75,9 @@
#define BNX2X_DOORBELL_PCI_BAR 2
#define BNX2FC_MAX_BD_LEN 0xffff
-#define BNX2FC_BD_SPLIT_SZ 0x8000
-#define BNX2FC_MAX_BDS_PER_CMD 256
+#define BNX2FC_BD_SPLIT_SZ 0xffff
+#define BNX2FC_MAX_BDS_PER_CMD 255
+#define BNX2FC_FW_MAX_BDS_PER_CMD 255
#define BNX2FC_SQ_WQES_MAX 256
@@ -433,8 +434,10 @@ struct bnx2fc_cmd {
void (*cb_func)(struct bnx2fc_els_cb_arg *cb_arg);
struct bnx2fc_els_cb_arg *cb_arg;
struct delayed_work timeout_work; /* timer for ULP timeouts */
- struct completion tm_done;
- int wait_for_comp;
+ struct completion abts_done;
+ struct completion cleanup_done;
+ int wait_for_abts_comp;
+ int wait_for_cleanup_comp;
u16 xid;
struct fcoe_err_report_entry err_entry;
struct fcoe_task_ctx_entry *task;
@@ -455,6 +458,7 @@ struct bnx2fc_cmd {
#define BNX2FC_FLAG_ELS_TIMEOUT 0xb
#define BNX2FC_FLAG_CMD_LOST 0xc
#define BNX2FC_FLAG_SRR_SENT 0xd
+#define BNX2FC_FLAG_ISSUE_CLEANUP_REQ 0xe
u8 rec_retry;
u8 srr_retry;
u32 srr_offset;
diff --git a/drivers/scsi/bnx2fc/bnx2fc_els.c b/drivers/scsi/bnx2fc/bnx2fc_els.c
index 76e65a32f38c..754f2e82d955 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_els.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_els.c
@@ -610,7 +610,6 @@ int bnx2fc_send_rec(struct bnx2fc_cmd *orig_io_req)
rc = bnx2fc_initiate_els(tgt, ELS_REC, &rec, sizeof(rec),
bnx2fc_rec_compl, cb_arg,
r_a_tov);
-rec_err:
if (rc) {
BNX2FC_IO_DBG(orig_io_req, "REC failed - release\n");
spin_lock_bh(&tgt->tgt_lock);
@@ -618,6 +617,7 @@ rec_err:
spin_unlock_bh(&tgt->tgt_lock);
kfree(cb_arg);
}
+rec_err:
return rc;
}
@@ -654,7 +654,6 @@ int bnx2fc_send_srr(struct bnx2fc_cmd *orig_io_req, u32 offset, u8 r_ctl)
rc = bnx2fc_initiate_els(tgt, ELS_SRR, &srr, sizeof(srr),
bnx2fc_srr_compl, cb_arg,
r_a_tov);
-srr_err:
if (rc) {
BNX2FC_IO_DBG(orig_io_req, "SRR failed - release\n");
spin_lock_bh(&tgt->tgt_lock);
@@ -664,6 +663,7 @@ srr_err:
} else
set_bit(BNX2FC_FLAG_SRR_SENT, &orig_io_req->req_flags);
+srr_err:
return rc;
}
@@ -854,33 +854,57 @@ void bnx2fc_process_els_compl(struct bnx2fc_cmd *els_req,
kref_put(&els_req->refcount, bnx2fc_cmd_release);
}
+#define BNX2FC_FCOE_MAC_METHOD_GRANGED_MAC 1
+#define BNX2FC_FCOE_MAC_METHOD_FCF_MAP 2
+#define BNX2FC_FCOE_MAC_METHOD_FCOE_SET_MAC 3
static void bnx2fc_flogi_resp(struct fc_seq *seq, struct fc_frame *fp,
void *arg)
{
struct fcoe_ctlr *fip = arg;
struct fc_exch *exch = fc_seq_exch(seq);
struct fc_lport *lport = exch->lp;
- u8 *mac;
- u8 op;
+
+ struct fc_frame_header *fh;
+ u8 *granted_mac;
+ u8 fcoe_mac[6];
+ u8 fc_map[3];
+ int method;
if (IS_ERR(fp))
goto done;
- mac = fr_cb(fp)->granted_mac;
- if (is_zero_ether_addr(mac)) {
- op = fc_frame_payload_op(fp);
- if (lport->vport) {
- if (op == ELS_LS_RJT) {
- printk(KERN_ERR PFX "bnx2fc_flogi_resp is LS_RJT\n");
- fc_vport_terminate(lport->vport);
- fc_frame_free(fp);
- return;
- }
- }
- fcoe_ctlr_recv_flogi(fip, lport, fp);
+ fh = fc_frame_header_get(fp);
+ granted_mac = fr_cb(fp)->granted_mac;
+
+ /*
+ * We set the source MAC for FCoE traffic based on the Granted MAC
+ * address from the switch.
+ *
+ * If granted_mac is non-zero, we use that.
+ * If the granted_mac is zeroed out, create the FCoE MAC based on
+ * the sel_fcf->fc_map and the d_id fo the FLOGI frame.
+ * If sel_fcf->fc_map is 0, then we use the default FCF-MAC plus the
+ * d_id of the FLOGI frame.
+ */
+ if (!is_zero_ether_addr(granted_mac)) {
+ ether_addr_copy(fcoe_mac, granted_mac);
+ method = BNX2FC_FCOE_MAC_METHOD_GRANGED_MAC;
+ } else if (fip->sel_fcf && fip->sel_fcf->fc_map != 0) {
+ hton24(fc_map, fip->sel_fcf->fc_map);
+ fcoe_mac[0] = fc_map[0];
+ fcoe_mac[1] = fc_map[1];
+ fcoe_mac[2] = fc_map[2];
+ fcoe_mac[3] = fh->fh_d_id[0];
+ fcoe_mac[4] = fh->fh_d_id[1];
+ fcoe_mac[5] = fh->fh_d_id[2];
+ method = BNX2FC_FCOE_MAC_METHOD_FCF_MAP;
+ } else {
+ fc_fcoe_set_mac(fcoe_mac, fh->fh_d_id);
+ method = BNX2FC_FCOE_MAC_METHOD_FCOE_SET_MAC;
}
- if (!is_zero_ether_addr(mac))
- fip->update_mac(lport, mac);
+
+ BNX2FC_HBA_DBG(lport, "fcoe_mac=%pM method=%d\n", fcoe_mac, method);
+ fip->update_mac(lport, fcoe_mac);
done:
fc_lport_flogi_resp(seq, fp, lport);
}
diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
index a75e74ad1698..7796799bf04a 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
@@ -2971,7 +2971,8 @@ static struct scsi_host_template bnx2fc_shost_template = {
.this_id = -1,
.cmd_per_lun = 3,
.sg_tablesize = BNX2FC_MAX_BDS_PER_CMD,
- .max_sectors = 1024,
+ .dma_boundary = 0x7fff,
+ .max_sectors = 0x3fbf,
.track_queue_depth = 1,
.slave_configure = bnx2fc_slave_configure,
.shost_attrs = bnx2fc_host_attrs,
diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c
index 8def63c0755f..9e50e5b53763 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_io.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_io.c
@@ -70,7 +70,7 @@ static void bnx2fc_cmd_timeout(struct work_struct *work)
&io_req->req_flags)) {
/* Handle eh_abort timeout */
BNX2FC_IO_DBG(io_req, "eh_abort timed out\n");
- complete(&io_req->tm_done);
+ complete(&io_req->abts_done);
} else if (test_bit(BNX2FC_FLAG_ISSUE_ABTS,
&io_req->req_flags)) {
/* Handle internally generated ABTS timeout */
@@ -775,31 +775,32 @@ retry_tmf:
io_req->on_tmf_queue = 1;
list_add_tail(&io_req->link, &tgt->active_tm_queue);
- init_completion(&io_req->tm_done);
- io_req->wait_for_comp = 1;
+ init_completion(&io_req->abts_done);
+ io_req->wait_for_abts_comp = 1;
/* Ring doorbell */
bnx2fc_ring_doorbell(tgt);
spin_unlock_bh(&tgt->tgt_lock);
- rc = wait_for_completion_timeout(&io_req->tm_done,
+ rc = wait_for_completion_timeout(&io_req->abts_done,
interface->tm_timeout * HZ);
spin_lock_bh(&tgt->tgt_lock);
- io_req->wait_for_comp = 0;
+ io_req->wait_for_abts_comp = 0;
if (!(test_bit(BNX2FC_FLAG_TM_COMPL, &io_req->req_flags))) {
set_bit(BNX2FC_FLAG_TM_TIMEOUT, &io_req->req_flags);
if (io_req->on_tmf_queue) {
list_del_init(&io_req->link);
io_req->on_tmf_queue = 0;
}
- io_req->wait_for_comp = 1;
+ io_req->wait_for_cleanup_comp = 1;
+ init_completion(&io_req->cleanup_done);
bnx2fc_initiate_cleanup(io_req);
spin_unlock_bh(&tgt->tgt_lock);
- rc = wait_for_completion_timeout(&io_req->tm_done,
+ rc = wait_for_completion_timeout(&io_req->cleanup_done,
BNX2FC_FW_TIMEOUT);
spin_lock_bh(&tgt->tgt_lock);
- io_req->wait_for_comp = 0;
+ io_req->wait_for_cleanup_comp = 0;
if (!rc)
kref_put(&io_req->refcount, bnx2fc_cmd_release);
}
@@ -1047,6 +1048,9 @@ int bnx2fc_initiate_cleanup(struct bnx2fc_cmd *io_req)
/* Obtain free SQ entry */
bnx2fc_add_2_sq(tgt, xid);
+ /* Set flag that cleanup request is pending with the firmware */
+ set_bit(BNX2FC_FLAG_ISSUE_CLEANUP_REQ, &io_req->req_flags);
+
/* Ring doorbell */
bnx2fc_ring_doorbell(tgt);
@@ -1085,7 +1089,8 @@ static int bnx2fc_abts_cleanup(struct bnx2fc_cmd *io_req)
struct bnx2fc_rport *tgt = io_req->tgt;
unsigned int time_left;
- io_req->wait_for_comp = 1;
+ init_completion(&io_req->cleanup_done);
+ io_req->wait_for_cleanup_comp = 1;
bnx2fc_initiate_cleanup(io_req);
spin_unlock_bh(&tgt->tgt_lock);
@@ -1094,21 +1099,21 @@ static int bnx2fc_abts_cleanup(struct bnx2fc_cmd *io_req)
* Can't wait forever on cleanup response lest we let the SCSI error
* handler wait forever
*/
- time_left = wait_for_completion_timeout(&io_req->tm_done,
+ time_left = wait_for_completion_timeout(&io_req->cleanup_done,
BNX2FC_FW_TIMEOUT);
- io_req->wait_for_comp = 0;
- if (!time_left)
+ if (!time_left) {
BNX2FC_IO_DBG(io_req, "%s(): Wait for cleanup timed out.\n",
__func__);
- /*
- * Release reference held by SCSI command the cleanup completion
- * hits the BNX2FC_CLEANUP case in bnx2fc_process_cq_compl() and
- * thus the SCSI command is not returnedi by bnx2fc_scsi_done().
- */
- kref_put(&io_req->refcount, bnx2fc_cmd_release);
+ /*
+ * Put the extra reference to the SCSI command since it would
+ * not have been returned in this case.
+ */
+ kref_put(&io_req->refcount, bnx2fc_cmd_release);
+ }
spin_lock_bh(&tgt->tgt_lock);
+ io_req->wait_for_cleanup_comp = 0;
return SUCCESS;
}
@@ -1197,7 +1202,8 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
/* Move IO req to retire queue */
list_add_tail(&io_req->link, &tgt->io_retire_queue);
- init_completion(&io_req->tm_done);
+ init_completion(&io_req->abts_done);
+ init_completion(&io_req->cleanup_done);
if (test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) {
printk(KERN_ERR PFX "eh_abort: io_req (xid = 0x%x) "
@@ -1225,26 +1231,28 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
kref_put(&io_req->refcount,
bnx2fc_cmd_release); /* drop timer hold */
set_bit(BNX2FC_FLAG_EH_ABORT, &io_req->req_flags);
- io_req->wait_for_comp = 1;
+ io_req->wait_for_abts_comp = 1;
rc = bnx2fc_initiate_abts(io_req);
if (rc == FAILED) {
+ io_req->wait_for_cleanup_comp = 1;
bnx2fc_initiate_cleanup(io_req);
spin_unlock_bh(&tgt->tgt_lock);
- wait_for_completion(&io_req->tm_done);
+ wait_for_completion(&io_req->cleanup_done);
spin_lock_bh(&tgt->tgt_lock);
- io_req->wait_for_comp = 0;
+ io_req->wait_for_cleanup_comp = 0;
goto done;
}
spin_unlock_bh(&tgt->tgt_lock);
/* Wait 2 * RA_TOV + 1 to be sure timeout function hasn't fired */
- time_left = wait_for_completion_timeout(&io_req->tm_done,
- (2 * rp->r_a_tov + 1) * HZ);
+ time_left = wait_for_completion_timeout(&io_req->abts_done,
+ (2 * rp->r_a_tov + 1) * HZ);
if (time_left)
- BNX2FC_IO_DBG(io_req, "Timed out in eh_abort waiting for tm_done");
+ BNX2FC_IO_DBG(io_req,
+ "Timed out in eh_abort waiting for abts_done");
spin_lock_bh(&tgt->tgt_lock);
- io_req->wait_for_comp = 0;
+ io_req->wait_for_abts_comp = 0;
if (test_bit(BNX2FC_FLAG_IO_COMPL, &io_req->req_flags)) {
BNX2FC_IO_DBG(io_req, "IO completed in a different context\n");
rc = SUCCESS;
@@ -1319,10 +1327,29 @@ void bnx2fc_process_cleanup_compl(struct bnx2fc_cmd *io_req,
BNX2FC_IO_DBG(io_req, "Entered process_cleanup_compl "
"refcnt = %d, cmd_type = %d\n",
kref_read(&io_req->refcount), io_req->cmd_type);
+ /*
+ * Test whether there is a cleanup request pending. If not just
+ * exit.
+ */
+ if (!test_and_clear_bit(BNX2FC_FLAG_ISSUE_CLEANUP_REQ,
+ &io_req->req_flags))
+ return;
+ /*
+ * If we receive a cleanup completion for this request then the
+ * firmware will not give us an abort completion for this request
+ * so clear any ABTS pending flags.
+ */
+ if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags) &&
+ !test_bit(BNX2FC_FLAG_ABTS_DONE, &io_req->req_flags)) {
+ set_bit(BNX2FC_FLAG_ABTS_DONE, &io_req->req_flags);
+ if (io_req->wait_for_abts_comp)
+ complete(&io_req->abts_done);
+ }
+
bnx2fc_scsi_done(io_req, DID_ERROR);
kref_put(&io_req->refcount, bnx2fc_cmd_release);
- if (io_req->wait_for_comp)
- complete(&io_req->tm_done);
+ if (io_req->wait_for_cleanup_comp)
+ complete(&io_req->cleanup_done);
}
void bnx2fc_process_abts_compl(struct bnx2fc_cmd *io_req,
@@ -1346,6 +1373,16 @@ void bnx2fc_process_abts_compl(struct bnx2fc_cmd *io_req,
return;
}
+ /*
+ * If we receive an ABTS completion here then we will not receive
+ * a cleanup completion so clear any cleanup pending flags.
+ */
+ if (test_bit(BNX2FC_FLAG_ISSUE_CLEANUP_REQ, &io_req->req_flags)) {
+ clear_bit(BNX2FC_FLAG_ISSUE_CLEANUP_REQ, &io_req->req_flags);
+ if (io_req->wait_for_cleanup_comp)
+ complete(&io_req->cleanup_done);
+ }
+
/* Do not issue RRQ as this IO is already cleanedup */
if (test_and_set_bit(BNX2FC_FLAG_IO_CLEANUP,
&io_req->req_flags))
@@ -1390,10 +1427,10 @@ void bnx2fc_process_abts_compl(struct bnx2fc_cmd *io_req,
bnx2fc_cmd_timer_set(io_req, r_a_tov);
io_compl:
- if (io_req->wait_for_comp) {
+ if (io_req->wait_for_abts_comp) {
if (test_and_clear_bit(BNX2FC_FLAG_EH_ABORT,
&io_req->req_flags))
- complete(&io_req->tm_done);
+ complete(&io_req->abts_done);
} else {
/*
* We end up here when ABTS is issued as
@@ -1577,9 +1614,9 @@ void bnx2fc_process_tm_compl(struct bnx2fc_cmd *io_req,
sc_cmd->scsi_done(sc_cmd);
kref_put(&io_req->refcount, bnx2fc_cmd_release);
- if (io_req->wait_for_comp) {
+ if (io_req->wait_for_abts_comp) {
BNX2FC_IO_DBG(io_req, "tm_compl - wake up the waiter\n");
- complete(&io_req->tm_done);
+ complete(&io_req->abts_done);
}
}
@@ -1623,6 +1660,7 @@ static int bnx2fc_map_sg(struct bnx2fc_cmd *io_req)
u64 addr;
int i;
+ WARN_ON(scsi_sg_count(sc) > BNX2FC_MAX_BDS_PER_CMD);
/*
* Use dma_map_sg directly to ensure we're using the correct
* dev struct off of pcidev.
@@ -1670,6 +1708,16 @@ static int bnx2fc_build_bd_list_from_sg(struct bnx2fc_cmd *io_req)
}
io_req->bd_tbl->bd_valid = bd_count;
+ /*
+ * Return the command to ML if BD count exceeds the max number
+ * that can be handled by FW.
+ */
+ if (bd_count > BNX2FC_FW_MAX_BDS_PER_CMD) {
+ pr_err("bd_count = %d exceeded FW supported max BD(255), task_id = 0x%x\n",
+ bd_count, io_req->xid);
+ return -ENOMEM;
+ }
+
return 0;
}
@@ -1926,10 +1974,10 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req,
* between command abort and (late) completion.
*/
BNX2FC_IO_DBG(io_req, "xid not on active_cmd_queue\n");
- if (io_req->wait_for_comp)
+ if (io_req->wait_for_abts_comp)
if (test_and_clear_bit(BNX2FC_FLAG_EH_ABORT,
&io_req->req_flags))
- complete(&io_req->tm_done);
+ complete(&io_req->abts_done);
}
bnx2fc_unmap_sg_list(io_req);
diff --git a/drivers/scsi/bnx2fc/bnx2fc_tgt.c b/drivers/scsi/bnx2fc/bnx2fc_tgt.c
index d735e87e416a..50384b4a817c 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_tgt.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_tgt.c
@@ -187,7 +187,7 @@ void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt)
/* Handle eh_abort timeout */
BNX2FC_IO_DBG(io_req, "eh_abort for IO "
"cleaned up\n");
- complete(&io_req->tm_done);
+ complete(&io_req->abts_done);
}
kref_put(&io_req->refcount,
bnx2fc_cmd_release); /* drop timer hold */
@@ -210,8 +210,8 @@ void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt)
list_del_init(&io_req->link);
io_req->on_tmf_queue = 0;
BNX2FC_IO_DBG(io_req, "tm_queue cleanup\n");
- if (io_req->wait_for_comp)
- complete(&io_req->tm_done);
+ if (io_req->wait_for_abts_comp)
+ complete(&io_req->abts_done);
}
list_for_each_entry_safe(io_req, tmp, &tgt->els_queue, link) {
@@ -251,8 +251,8 @@ void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt)
/* Handle eh_abort timeout */
BNX2FC_IO_DBG(io_req, "eh_abort for IO "
"in retire_q\n");
- if (io_req->wait_for_comp)
- complete(&io_req->tm_done);
+ if (io_req->wait_for_abts_comp)
+ complete(&io_req->abts_done);
}
kref_put(&io_req->refcount, bnx2fc_cmd_release);
}
diff --git a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
index b8dd9e648dd0..524cdbcd29aa 100644
--- a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
+++ b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
@@ -1243,8 +1243,12 @@ static int cxgb3i_ddp_init(struct cxgbi_device *cdev)
tformat.pgsz_order[i] = uinfo.pgsz_factor[i];
cxgbi_tagmask_check(tagmask, &tformat);
- cxgbi_ddp_ppm_setup(&tdev->ulp_iscsi, cdev, &tformat, ppmax,
- uinfo.llimit, uinfo.llimit, 0);
+ err = cxgbi_ddp_ppm_setup(&tdev->ulp_iscsi, cdev, &tformat,
+ (uinfo.ulimit - uinfo.llimit + 1),
+ uinfo.llimit, uinfo.llimit, 0, 0, 0);
+ if (err)
+ return err;
+
if (!(cdev->flags & CXGBI_FLAG_DDP_OFF)) {
uinfo.tagmask = tagmask;
uinfo.ulimit = uinfo.llimit + (ppmax << PPOD_SIZE_SHIFT);
@@ -1318,7 +1322,7 @@ static void cxgb3i_dev_open(struct t3cdev *t3dev)
err = cxgb3i_ddp_init(cdev);
if (err) {
- pr_info("0x%p ddp init failed\n", cdev);
+ pr_info("0x%p ddp init failed %d\n", cdev, err);
goto err_out;
}
diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
index 124f3345420f..da50e87921bc 100644
--- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
+++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
@@ -1665,8 +1665,12 @@ static u8 get_iscsi_dcb_priority(struct net_device *ndev)
return 0;
if (caps & DCB_CAP_DCBX_VER_IEEE) {
- iscsi_dcb_app.selector = IEEE_8021QAZ_APP_SEL_ANY;
+ iscsi_dcb_app.selector = IEEE_8021QAZ_APP_SEL_STREAM;
rv = dcb_ieee_getapp_mask(ndev, &iscsi_dcb_app);
+ if (!rv) {
+ iscsi_dcb_app.selector = IEEE_8021QAZ_APP_SEL_ANY;
+ rv = dcb_ieee_getapp_mask(ndev, &iscsi_dcb_app);
+ }
} else if (caps & DCB_CAP_DCBX_VER_CEE) {
iscsi_dcb_app.selector = DCB_APP_IDTYPE_PORTNUM;
rv = dcb_getapp(ndev, &iscsi_dcb_app);
@@ -2070,7 +2074,7 @@ static int cxgb4i_ddp_init(struct cxgbi_device *cdev)
struct net_device *ndev = cdev->ports[0];
struct cxgbi_tag_format tformat;
unsigned int ppmax;
- int i;
+ int i, err;
if (!lldi->vr->iscsi.size) {
pr_warn("%s, iscsi NOT enabled, check config!\n", ndev->name);
@@ -2086,8 +2090,17 @@ static int cxgb4i_ddp_init(struct cxgbi_device *cdev)
& 0xF;
cxgbi_tagmask_check(lldi->iscsi_tagmask, &tformat);
- cxgbi_ddp_ppm_setup(lldi->iscsi_ppm, cdev, &tformat, ppmax,
- lldi->iscsi_llimit, lldi->vr->iscsi.start, 2);
+ pr_info("iscsi_edram.start 0x%x iscsi_edram.size 0x%x",
+ lldi->vr->ppod_edram.start, lldi->vr->ppod_edram.size);
+
+ err = cxgbi_ddp_ppm_setup(lldi->iscsi_ppm, cdev, &tformat,
+ lldi->vr->iscsi.size, lldi->iscsi_llimit,
+ lldi->vr->iscsi.start, 2,
+ lldi->vr->ppod_edram.start,
+ lldi->vr->ppod_edram.size);
+
+ if (err < 0)
+ return err;
cdev->csk_ddp_setup_digest = ddp_setup_conn_digest;
cdev->csk_ddp_setup_pgidx = ddp_setup_conn_pgidx;
@@ -2141,7 +2154,7 @@ static void *t4_uld_add(const struct cxgb4_lld_info *lldi)
rc = cxgb4i_ddp_init(cdev);
if (rc) {
- pr_info("t4 0x%p ddp init failed.\n", cdev);
+ pr_info("t4 0x%p ddp init failed %d.\n", cdev, rc);
goto err_out;
}
rc = cxgb4i_ofld_init(cdev);
@@ -2251,7 +2264,8 @@ cxgb4_dcb_change_notify(struct notifier_block *self, unsigned long val,
u8 priority;
if (iscsi_app->dcbx & DCB_CAP_DCBX_VER_IEEE) {
- if (iscsi_app->app.selector != IEEE_8021QAZ_APP_SEL_ANY)
+ if ((iscsi_app->app.selector != IEEE_8021QAZ_APP_SEL_STREAM) &&
+ (iscsi_app->app.selector != IEEE_8021QAZ_APP_SEL_ANY))
return NOTIFY_DONE;
priority = iscsi_app->app.priority;
diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c
index 7d43e014bd21..3e17af8aedeb 100644
--- a/drivers/scsi/cxgbi/libcxgbi.c
+++ b/drivers/scsi/cxgbi/libcxgbi.c
@@ -1285,14 +1285,15 @@ EXPORT_SYMBOL_GPL(cxgbi_ddp_set_one_ppod);
static unsigned char padding[4];
-void cxgbi_ddp_ppm_setup(void **ppm_pp, struct cxgbi_device *cdev,
- struct cxgbi_tag_format *tformat, unsigned int ppmax,
- unsigned int llimit, unsigned int start,
- unsigned int rsvd_factor)
+int cxgbi_ddp_ppm_setup(void **ppm_pp, struct cxgbi_device *cdev,
+ struct cxgbi_tag_format *tformat,
+ unsigned int iscsi_size, unsigned int llimit,
+ unsigned int start, unsigned int rsvd_factor,
+ unsigned int edram_start, unsigned int edram_size)
{
int err = cxgbi_ppm_init(ppm_pp, cdev->ports[0], cdev->pdev,
- cdev->lldev, tformat, ppmax, llimit, start,
- rsvd_factor);
+ cdev->lldev, tformat, iscsi_size, llimit, start,
+ rsvd_factor, edram_start, edram_size);
if (err >= 0) {
struct cxgbi_ppm *ppm = (struct cxgbi_ppm *)(*ppm_pp);
@@ -1304,6 +1305,8 @@ void cxgbi_ddp_ppm_setup(void **ppm_pp, struct cxgbi_device *cdev,
} else {
cdev->flags |= CXGBI_FLAG_DDP_OFF;
}
+
+ return err;
}
EXPORT_SYMBOL_GPL(cxgbi_ddp_ppm_setup);
diff --git a/drivers/scsi/cxgbi/libcxgbi.h b/drivers/scsi/cxgbi/libcxgbi.h
index 1917ff57651d..84b96af52655 100644
--- a/drivers/scsi/cxgbi/libcxgbi.h
+++ b/drivers/scsi/cxgbi/libcxgbi.h
@@ -617,8 +617,9 @@ void cxgbi_ddp_page_size_factor(int *);
void cxgbi_ddp_set_one_ppod(struct cxgbi_pagepod *,
struct cxgbi_task_tag_info *,
struct scatterlist **sg_pp, unsigned int *sg_off);
-void cxgbi_ddp_ppm_setup(void **ppm_pp, struct cxgbi_device *,
- struct cxgbi_tag_format *, unsigned int ppmax,
- unsigned int llimit, unsigned int start,
- unsigned int rsvd_factor);
+int cxgbi_ddp_ppm_setup(void **ppm_pp, struct cxgbi_device *cdev,
+ struct cxgbi_tag_format *tformat,
+ unsigned int iscsi_size, unsigned int llimit,
+ unsigned int start, unsigned int rsvd_factor,
+ unsigned int edram_start, unsigned int edram_size);
#endif /*__LIBCXGBI_H__*/
diff --git a/drivers/scsi/cxlflash/ocxl_hw.c b/drivers/scsi/cxlflash/ocxl_hw.c
index 96740c6fcd92..7018cd802569 100644
--- a/drivers/scsi/cxlflash/ocxl_hw.c
+++ b/drivers/scsi/cxlflash/ocxl_hw.c
@@ -12,6 +12,7 @@
#include <linux/idr.h>
#include <linux/module.h>
#include <linux/mount.h>
+#include <linux/pseudo_fs.h>
#include <linux/poll.h>
#include <linux/sched/signal.h>
@@ -31,31 +32,15 @@
static int ocxlflash_fs_cnt;
static struct vfsmount *ocxlflash_vfs_mount;
-static const struct dentry_operations ocxlflash_fs_dops = {
- .d_dname = simple_dname,
-};
-
-/*
- * ocxlflash_fs_mount() - mount the pseudo-filesystem
- * @fs_type: File system type.
- * @flags: Flags for the filesystem.
- * @dev_name: Device name associated with the filesystem.
- * @data: Data pointer.
- *
- * Return: pointer to the directory entry structure
- */
-static struct dentry *ocxlflash_fs_mount(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *data)
+static int ocxlflash_fs_init_fs_context(struct fs_context *fc)
{
- return mount_pseudo(fs_type, "ocxlflash:", NULL, &ocxlflash_fs_dops,
- OCXLFLASH_FS_MAGIC);
+ return init_pseudo(fc, OCXLFLASH_FS_MAGIC) ? 0 : -ENOMEM;
}
static struct file_system_type ocxlflash_fs_type = {
.name = "ocxlflash",
.owner = THIS_MODULE,
- .mount = ocxlflash_fs_mount,
+ .init_fs_context = ocxlflash_fs_init_fs_context,
.kill_sb = kill_anon_super,
};
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c
index 76e7ca864d6a..bb88995a12c7 100644
--- a/drivers/scsi/esp_scsi.c
+++ b/drivers/scsi/esp_scsi.c
@@ -371,6 +371,7 @@ static void esp_map_dma(struct esp *esp, struct scsi_cmnd *cmd)
struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd);
struct scatterlist *sg = scsi_sglist(cmd);
int total = 0, i;
+ struct scatterlist *s;
if (cmd->sc_data_direction == DMA_NONE)
return;
@@ -381,16 +382,18 @@ static void esp_map_dma(struct esp *esp, struct scsi_cmnd *cmd)
* a dma address, so perform an identity mapping.
*/
spriv->num_sg = scsi_sg_count(cmd);
- for (i = 0; i < spriv->num_sg; i++) {
- sg[i].dma_address = (uintptr_t)sg_virt(&sg[i]);
- total += sg_dma_len(&sg[i]);
+
+ scsi_for_each_sg(cmd, s, spriv->num_sg, i) {
+ s->dma_address = (uintptr_t)sg_virt(s);
+ total += sg_dma_len(s);
}
} else {
spriv->num_sg = scsi_dma_map(cmd);
- for (i = 0; i < spriv->num_sg; i++)
- total += sg_dma_len(&sg[i]);
+ scsi_for_each_sg(cmd, s, spriv->num_sg, i)
+ total += sg_dma_len(s);
}
spriv->cur_residue = sg_dma_len(sg);
+ spriv->prv_sg = NULL;
spriv->cur_sg = sg;
spriv->tot_residue = total;
}
@@ -444,7 +447,8 @@ static void esp_advance_dma(struct esp *esp, struct esp_cmd_entry *ent,
p->tot_residue = 0;
}
if (!p->cur_residue && p->tot_residue) {
- p->cur_sg++;
+ p->prv_sg = p->cur_sg;
+ p->cur_sg = sg_next(p->cur_sg);
p->cur_residue = sg_dma_len(p->cur_sg);
}
}
@@ -465,6 +469,7 @@ static void esp_save_pointers(struct esp *esp, struct esp_cmd_entry *ent)
return;
}
ent->saved_cur_residue = spriv->cur_residue;
+ ent->saved_prv_sg = spriv->prv_sg;
ent->saved_cur_sg = spriv->cur_sg;
ent->saved_tot_residue = spriv->tot_residue;
}
@@ -479,6 +484,7 @@ static void esp_restore_pointers(struct esp *esp, struct esp_cmd_entry *ent)
return;
}
spriv->cur_residue = ent->saved_cur_residue;
+ spriv->prv_sg = ent->saved_prv_sg;
spriv->cur_sg = ent->saved_cur_sg;
spriv->tot_residue = ent->saved_tot_residue;
}
@@ -1647,7 +1653,7 @@ static int esp_msgin_process(struct esp *esp)
spriv = ESP_CMD_PRIV(ent->cmd);
if (spriv->cur_residue == sg_dma_len(spriv->cur_sg)) {
- spriv->cur_sg--;
+ spriv->cur_sg = spriv->prv_sg;
spriv->cur_residue = 1;
} else
spriv->cur_residue++;
diff --git a/drivers/scsi/esp_scsi.h b/drivers/scsi/esp_scsi.h
index aa87a6b72dcc..91b32f2a1a1b 100644
--- a/drivers/scsi/esp_scsi.h
+++ b/drivers/scsi/esp_scsi.h
@@ -251,6 +251,7 @@
struct esp_cmd_priv {
int num_sg;
int cur_residue;
+ struct scatterlist *prv_sg;
struct scatterlist *cur_sg;
int tot_residue;
};
@@ -273,6 +274,7 @@ struct esp_cmd_entry {
struct scsi_cmnd *cmd;
unsigned int saved_cur_residue;
+ struct scatterlist *saved_prv_sg;
struct scatterlist *saved_cur_sg;
unsigned int saved_tot_residue;
diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
new file mode 100644
index 000000000000..b5e66971b6d9
--- /dev/null
+++ b/drivers/scsi/fdomain.c
@@ -0,0 +1,597 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Future Domain TMC-16x0 and TMC-3260 SCSI host adapters
+ * Copyright 2019 Ondrej Zary
+ *
+ * Original driver by
+ * Rickard E. Faith, faith@cs.unc.edu
+ *
+ * Future Domain BIOS versions supported for autodetect:
+ * 2.0, 3.0, 3.2, 3.4 (1.0), 3.5 (2.0), 3.6, 3.61
+ * Chips supported:
+ * TMC-1800, TMC-18C50, TMC-18C30, TMC-36C70
+ * Boards supported:
+ * Future Domain TMC-1650, TMC-1660, TMC-1670, TMC-1680, TMC-1610M/MER/MEX
+ * Future Domain TMC-3260 (PCI)
+ * Quantum ISA-200S, ISA-250MG
+ * Adaptec AHA-2920A (PCI) [BUT *NOT* AHA-2920C -- use aic7xxx instead]
+ * IBM ?
+ *
+ * NOTE:
+ *
+ * The Adaptec AHA-2920C has an Adaptec AIC-7850 chip on it.
+ * Use the aic7xxx driver for this board.
+ *
+ * The Adaptec AHA-2920A has a Future Domain chip on it, so this is the right
+ * driver for that card. Unfortunately, the boxes will probably just say
+ * "2920", so you'll have to look on the card for a Future Domain logo, or a
+ * letter after the 2920.
+ *
+ * If you have a TMC-8xx or TMC-9xx board, then this is not the driver for
+ * your board.
+ *
+ * DESCRIPTION:
+ *
+ * This is the Linux low-level SCSI driver for Future Domain TMC-1660/1680
+ * TMC-1650/1670, and TMC-3260 SCSI host adapters. The 1650 and 1670 have a
+ * 25-pin external connector, whereas the 1660 and 1680 have a SCSI-2 50-pin
+ * high-density external connector. The 1670 and 1680 have floppy disk
+ * controllers built in. The TMC-3260 is a PCI bus card.
+ *
+ * Future Domain's older boards are based on the TMC-1800 chip, and this
+ * driver was originally written for a TMC-1680 board with the TMC-1800 chip.
+ * More recently, boards are being produced with the TMC-18C50 and TMC-18C30
+ * chips.
+ *
+ * Please note that the drive ordering that Future Domain implemented in BIOS
+ * versions 3.4 and 3.5 is the opposite of the order (currently) used by the
+ * rest of the SCSI industry.
+ *
+ *
+ * REFERENCES USED:
+ *
+ * "TMC-1800 SCSI Chip Specification (FDC-1800T)", Future Domain Corporation,
+ * 1990.
+ *
+ * "Technical Reference Manual: 18C50 SCSI Host Adapter Chip", Future Domain
+ * Corporation, January 1992.
+ *
+ * "LXT SCSI Products: Specifications and OEM Technical Manual (Revision
+ * B/September 1991)", Maxtor Corporation, 1991.
+ *
+ * "7213S product Manual (Revision P3)", Maxtor Corporation, 1992.
+ *
+ * "Draft Proposed American National Standard: Small Computer System
+ * Interface - 2 (SCSI-2)", Global Engineering Documents. (X3T9.2/86-109,
+ * revision 10h, October 17, 1991)
+ *
+ * Private communications, Drew Eckhardt (drew@cs.colorado.edu) and Eric
+ * Youngdale (ericy@cais.com), 1992.
+ *
+ * Private communication, Tuong Le (Future Domain Engineering department),
+ * 1994. (Disk geometry computations for Future Domain BIOS version 3.4, and
+ * TMC-18C30 detection.)
+ *
+ * Hogan, Thom. The Programmer's PC Sourcebook. Microsoft Press, 1988. Page
+ * 60 (2.39: Disk Partition Table Layout).
+ *
+ * "18C30 Technical Reference Manual", Future Domain Corporation, 1993, page
+ * 6-1.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/workqueue.h>
+#include <scsi/scsicam.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include "fdomain.h"
+
+/*
+ * FIFO_COUNT: The host adapter has an 8K cache (host adapters based on the
+ * 18C30 chip have a 2k cache). When this many 512 byte blocks are filled by
+ * the SCSI device, an interrupt will be raised. Therefore, this could be as
+ * low as 0, or as high as 16. Note, however, that values which are too high
+ * or too low seem to prevent any interrupts from occurring, and thereby lock
+ * up the machine.
+ */
+#define FIFO_COUNT 2 /* Number of 512 byte blocks before INTR */
+#define PARITY_MASK ACTL_PAREN /* Parity enabled, 0 = disabled */
+
+enum chip_type {
+ unknown = 0x00,
+ tmc1800 = 0x01,
+ tmc18c50 = 0x02,
+ tmc18c30 = 0x03,
+};
+
+struct fdomain {
+ int base;
+ struct scsi_cmnd *cur_cmd;
+ enum chip_type chip;
+ struct work_struct work;
+};
+
+static inline void fdomain_make_bus_idle(struct fdomain *fd)
+{
+ outb(0, fd->base + REG_BCTL);
+ outb(0, fd->base + REG_MCTL);
+ if (fd->chip == tmc18c50 || fd->chip == tmc18c30)
+ /* Clear forced intr. */
+ outb(ACTL_RESET | ACTL_CLRFIRQ | PARITY_MASK,
+ fd->base + REG_ACTL);
+ else
+ outb(ACTL_RESET | PARITY_MASK, fd->base + REG_ACTL);
+}
+
+static enum chip_type fdomain_identify(int port)
+{
+ u16 id = inb(port + REG_ID_LSB) | inb(port + REG_ID_MSB) << 8;
+
+ switch (id) {
+ case 0x6127:
+ return tmc1800;
+ case 0x60e9: /* 18c50 or 18c30 */
+ break;
+ default:
+ return unknown;
+ }
+
+ /* Try to toggle 32-bit mode. This only works on an 18c30 chip. */
+ outb(CFG2_32BIT, port + REG_CFG2);
+ if ((inb(port + REG_CFG2) & CFG2_32BIT)) {
+ outb(0, port + REG_CFG2);
+ if ((inb(port + REG_CFG2) & CFG2_32BIT) == 0)
+ return tmc18c30;
+ }
+ /* If that failed, we are an 18c50. */
+ return tmc18c50;
+}
+
+static int fdomain_test_loopback(int base)
+{
+ int i;
+
+ for (i = 0; i < 255; i++) {
+ outb(i, base + REG_LOOPBACK);
+ if (inb(base + REG_LOOPBACK) != i)
+ return 1;
+ }
+
+ return 0;
+}
+
+static void fdomain_reset(int base)
+{
+ outb(1, base + REG_BCTL);
+ mdelay(20);
+ outb(0, base + REG_BCTL);
+ mdelay(1150);
+ outb(0, base + REG_MCTL);
+ outb(PARITY_MASK, base + REG_ACTL);
+}
+
+static int fdomain_select(struct Scsi_Host *sh, int target)
+{
+ int status;
+ unsigned long timeout;
+ struct fdomain *fd = shost_priv(sh);
+
+ outb(BCTL_BUSEN | BCTL_SEL, fd->base + REG_BCTL);
+ outb(BIT(sh->this_id) | BIT(target), fd->base + REG_SCSI_DATA_NOACK);
+
+ /* Stop arbitration and enable parity */
+ outb(PARITY_MASK, fd->base + REG_ACTL);
+
+ timeout = 350; /* 350 msec */
+
+ do {
+ status = inb(fd->base + REG_BSTAT);
+ if (status & BSTAT_BSY) {
+ /* Enable SCSI Bus */
+ /* (on error, should make bus idle with 0) */
+ outb(BCTL_BUSEN, fd->base + REG_BCTL);
+ return 0;
+ }
+ mdelay(1);
+ } while (--timeout);
+ fdomain_make_bus_idle(fd);
+ return 1;
+}
+
+static void fdomain_finish_cmd(struct fdomain *fd, int result)
+{
+ outb(0, fd->base + REG_ICTL);
+ fdomain_make_bus_idle(fd);
+ fd->cur_cmd->result = result;
+ fd->cur_cmd->scsi_done(fd->cur_cmd);
+ fd->cur_cmd = NULL;
+}
+
+static void fdomain_read_data(struct scsi_cmnd *cmd)
+{
+ struct fdomain *fd = shost_priv(cmd->device->host);
+ unsigned char *virt, *ptr;
+ size_t offset, len;
+
+ while ((len = inw(fd->base + REG_FIFO_COUNT)) > 0) {
+ offset = scsi_bufflen(cmd) - scsi_get_resid(cmd);
+ virt = scsi_kmap_atomic_sg(scsi_sglist(cmd), scsi_sg_count(cmd),
+ &offset, &len);
+ ptr = virt + offset;
+ if (len & 1)
+ *ptr++ = inb(fd->base + REG_FIFO);
+ if (len > 1)
+ insw(fd->base + REG_FIFO, ptr, len >> 1);
+ scsi_set_resid(cmd, scsi_get_resid(cmd) - len);
+ scsi_kunmap_atomic_sg(virt);
+ }
+}
+
+static void fdomain_write_data(struct scsi_cmnd *cmd)
+{
+ struct fdomain *fd = shost_priv(cmd->device->host);
+ /* 8k FIFO for pre-tmc18c30 chips, 2k FIFO for tmc18c30 */
+ int FIFO_Size = fd->chip == tmc18c30 ? 0x800 : 0x2000;
+ unsigned char *virt, *ptr;
+ size_t offset, len;
+
+ while ((len = FIFO_Size - inw(fd->base + REG_FIFO_COUNT)) > 512) {
+ offset = scsi_bufflen(cmd) - scsi_get_resid(cmd);
+ if (len + offset > scsi_bufflen(cmd)) {
+ len = scsi_bufflen(cmd) - offset;
+ if (len == 0)
+ break;
+ }
+ virt = scsi_kmap_atomic_sg(scsi_sglist(cmd), scsi_sg_count(cmd),
+ &offset, &len);
+ ptr = virt + offset;
+ if (len & 1)
+ outb(*ptr++, fd->base + REG_FIFO);
+ if (len > 1)
+ outsw(fd->base + REG_FIFO, ptr, len >> 1);
+ scsi_set_resid(cmd, scsi_get_resid(cmd) - len);
+ scsi_kunmap_atomic_sg(virt);
+ }
+}
+
+static void fdomain_work(struct work_struct *work)
+{
+ struct fdomain *fd = container_of(work, struct fdomain, work);
+ struct Scsi_Host *sh = container_of((void *)fd, struct Scsi_Host,
+ hostdata);
+ struct scsi_cmnd *cmd = fd->cur_cmd;
+ unsigned long flags;
+ int status;
+ int done = 0;
+
+ spin_lock_irqsave(sh->host_lock, flags);
+
+ if (cmd->SCp.phase & in_arbitration) {
+ status = inb(fd->base + REG_ASTAT);
+ if (!(status & ASTAT_ARB)) {
+ fdomain_finish_cmd(fd, DID_BUS_BUSY << 16);
+ goto out;
+ }
+ cmd->SCp.phase = in_selection;
+
+ outb(ICTL_SEL | FIFO_COUNT, fd->base + REG_ICTL);
+ outb(BCTL_BUSEN | BCTL_SEL, fd->base + REG_BCTL);
+ outb(BIT(cmd->device->host->this_id) | BIT(scmd_id(cmd)),
+ fd->base + REG_SCSI_DATA_NOACK);
+ /* Stop arbitration and enable parity */
+ outb(ACTL_IRQEN | PARITY_MASK, fd->base + REG_ACTL);
+ goto out;
+ } else if (cmd->SCp.phase & in_selection) {
+ status = inb(fd->base + REG_BSTAT);
+ if (!(status & BSTAT_BSY)) {
+ /* Try again, for slow devices */
+ if (fdomain_select(cmd->device->host, scmd_id(cmd))) {
+ fdomain_finish_cmd(fd, DID_NO_CONNECT << 16);
+ goto out;
+ }
+ /* Stop arbitration and enable parity */
+ outb(ACTL_IRQEN | PARITY_MASK, fd->base + REG_ACTL);
+ }
+ cmd->SCp.phase = in_other;
+ outb(ICTL_FIFO | ICTL_REQ | FIFO_COUNT, fd->base + REG_ICTL);
+ outb(BCTL_BUSEN, fd->base + REG_BCTL);
+ goto out;
+ }
+
+ /* cur_cmd->SCp.phase == in_other: this is the body of the routine */
+ status = inb(fd->base + REG_BSTAT);
+
+ if (status & BSTAT_REQ) {
+ switch (status & 0x0e) {
+ case BSTAT_CMD: /* COMMAND OUT */
+ outb(cmd->cmnd[cmd->SCp.sent_command++],
+ fd->base + REG_SCSI_DATA);
+ break;
+ case 0: /* DATA OUT -- tmc18c50/tmc18c30 only */
+ if (fd->chip != tmc1800 && !cmd->SCp.have_data_in) {
+ cmd->SCp.have_data_in = -1;
+ outb(ACTL_IRQEN | ACTL_FIFOWR | ACTL_FIFOEN |
+ PARITY_MASK, fd->base + REG_ACTL);
+ }
+ break;
+ case BSTAT_IO: /* DATA IN -- tmc18c50/tmc18c30 only */
+ if (fd->chip != tmc1800 && !cmd->SCp.have_data_in) {
+ cmd->SCp.have_data_in = 1;
+ outb(ACTL_IRQEN | ACTL_FIFOEN | PARITY_MASK,
+ fd->base + REG_ACTL);
+ }
+ break;
+ case BSTAT_CMD | BSTAT_IO: /* STATUS IN */
+ cmd->SCp.Status = inb(fd->base + REG_SCSI_DATA);
+ break;
+ case BSTAT_MSG | BSTAT_CMD: /* MESSAGE OUT */
+ outb(MESSAGE_REJECT, fd->base + REG_SCSI_DATA);
+ break;
+ case BSTAT_MSG | BSTAT_IO | BSTAT_CMD: /* MESSAGE IN */
+ cmd->SCp.Message = inb(fd->base + REG_SCSI_DATA);
+ if (!cmd->SCp.Message)
+ ++done;
+ break;
+ }
+ }
+
+ if (fd->chip == tmc1800 && !cmd->SCp.have_data_in &&
+ cmd->SCp.sent_command >= cmd->cmd_len) {
+ if (cmd->sc_data_direction == DMA_TO_DEVICE) {
+ cmd->SCp.have_data_in = -1;
+ outb(ACTL_IRQEN | ACTL_FIFOWR | ACTL_FIFOEN |
+ PARITY_MASK, fd->base + REG_ACTL);
+ } else {
+ cmd->SCp.have_data_in = 1;
+ outb(ACTL_IRQEN | ACTL_FIFOEN | PARITY_MASK,
+ fd->base + REG_ACTL);
+ }
+ }
+
+ if (cmd->SCp.have_data_in == -1) /* DATA OUT */
+ fdomain_write_data(cmd);
+
+ if (cmd->SCp.have_data_in == 1) /* DATA IN */
+ fdomain_read_data(cmd);
+
+ if (done) {
+ fdomain_finish_cmd(fd, (cmd->SCp.Status & 0xff) |
+ ((cmd->SCp.Message & 0xff) << 8) |
+ (DID_OK << 16));
+ } else {
+ if (cmd->SCp.phase & disconnect) {
+ outb(ICTL_FIFO | ICTL_SEL | ICTL_REQ | FIFO_COUNT,
+ fd->base + REG_ICTL);
+ outb(0, fd->base + REG_BCTL);
+ } else
+ outb(ICTL_FIFO | ICTL_REQ | FIFO_COUNT,
+ fd->base + REG_ICTL);
+ }
+out:
+ spin_unlock_irqrestore(sh->host_lock, flags);
+}
+
+static irqreturn_t fdomain_irq(int irq, void *dev_id)
+{
+ struct fdomain *fd = dev_id;
+
+ /* Is it our IRQ? */
+ if ((inb(fd->base + REG_ASTAT) & ASTAT_IRQ) == 0)
+ return IRQ_NONE;
+
+ outb(0, fd->base + REG_ICTL);
+
+ /* We usually have one spurious interrupt after each command. */
+ if (!fd->cur_cmd) /* Spurious interrupt */
+ return IRQ_NONE;
+
+ schedule_work(&fd->work);
+
+ return IRQ_HANDLED;
+}
+
+static int fdomain_queue(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
+{
+ struct fdomain *fd = shost_priv(cmd->device->host);
+ unsigned long flags;
+
+ cmd->SCp.Status = 0;
+ cmd->SCp.Message = 0;
+ cmd->SCp.have_data_in = 0;
+ cmd->SCp.sent_command = 0;
+ cmd->SCp.phase = in_arbitration;
+ scsi_set_resid(cmd, scsi_bufflen(cmd));
+
+ spin_lock_irqsave(sh->host_lock, flags);
+
+ fd->cur_cmd = cmd;
+
+ fdomain_make_bus_idle(fd);
+
+ /* Start arbitration */
+ outb(0, fd->base + REG_ICTL);
+ outb(0, fd->base + REG_BCTL); /* Disable data drivers */
+ /* Set our id bit */
+ outb(BIT(cmd->device->host->this_id), fd->base + REG_SCSI_DATA_NOACK);
+ outb(ICTL_ARB, fd->base + REG_ICTL);
+ /* Start arbitration */
+ outb(ACTL_ARB | ACTL_IRQEN | PARITY_MASK, fd->base + REG_ACTL);
+
+ spin_unlock_irqrestore(sh->host_lock, flags);
+
+ return 0;
+}
+
+static int fdomain_abort(struct scsi_cmnd *cmd)
+{
+ struct Scsi_Host *sh = cmd->device->host;
+ struct fdomain *fd = shost_priv(sh);
+ unsigned long flags;
+
+ if (!fd->cur_cmd)
+ return FAILED;
+
+ spin_lock_irqsave(sh->host_lock, flags);
+
+ fdomain_make_bus_idle(fd);
+ fd->cur_cmd->SCp.phase |= aborted;
+ fd->cur_cmd->result = DID_ABORT << 16;
+
+ /* Aborts are not done well. . . */
+ fdomain_finish_cmd(fd, DID_ABORT << 16);
+ spin_unlock_irqrestore(sh->host_lock, flags);
+ return SUCCESS;
+}
+
+static int fdomain_host_reset(struct scsi_cmnd *cmd)
+{
+ struct Scsi_Host *sh = cmd->device->host;
+ struct fdomain *fd = shost_priv(sh);
+ unsigned long flags;
+
+ spin_lock_irqsave(sh->host_lock, flags);
+ fdomain_reset(fd->base);
+ spin_unlock_irqrestore(sh->host_lock, flags);
+ return SUCCESS;
+}
+
+static int fdomain_biosparam(struct scsi_device *sdev,
+ struct block_device *bdev, sector_t capacity,
+ int geom[])
+{
+ unsigned char *p = scsi_bios_ptable(bdev);
+
+ if (p && p[65] == 0xaa && p[64] == 0x55 /* Partition table valid */
+ && p[4]) { /* Partition type */
+ geom[0] = p[5] + 1; /* heads */
+ geom[1] = p[6] & 0x3f; /* sectors */
+ } else {
+ if (capacity >= 0x7e0000) {
+ geom[0] = 255; /* heads */
+ geom[1] = 63; /* sectors */
+ } else if (capacity >= 0x200000) {
+ geom[0] = 128; /* heads */
+ geom[1] = 63; /* sectors */
+ } else {
+ geom[0] = 64; /* heads */
+ geom[1] = 32; /* sectors */
+ }
+ }
+ geom[2] = sector_div(capacity, geom[0] * geom[1]);
+ kfree(p);
+
+ return 0;
+}
+
+static struct scsi_host_template fdomain_template = {
+ .module = THIS_MODULE,
+ .name = "Future Domain TMC-16x0",
+ .proc_name = "fdomain",
+ .queuecommand = fdomain_queue,
+ .eh_abort_handler = fdomain_abort,
+ .eh_host_reset_handler = fdomain_host_reset,
+ .bios_param = fdomain_biosparam,
+ .can_queue = 1,
+ .this_id = 7,
+ .sg_tablesize = 64,
+ .dma_boundary = PAGE_SIZE - 1,
+};
+
+struct Scsi_Host *fdomain_create(int base, int irq, int this_id,
+ struct device *dev)
+{
+ struct Scsi_Host *sh;
+ struct fdomain *fd;
+ enum chip_type chip;
+ static const char * const chip_names[] = {
+ "Unknown", "TMC-1800", "TMC-18C50", "TMC-18C30"
+ };
+ unsigned long irq_flags = 0;
+
+ chip = fdomain_identify(base);
+ if (!chip)
+ return NULL;
+
+ fdomain_reset(base);
+
+ if (fdomain_test_loopback(base))
+ return NULL;
+
+ if (!irq) {
+ dev_err(dev, "card has no IRQ assigned");
+ return NULL;
+ }
+
+ sh = scsi_host_alloc(&fdomain_template, sizeof(struct fdomain));
+ if (!sh)
+ return NULL;
+
+ if (this_id)
+ sh->this_id = this_id & 0x07;
+
+ sh->irq = irq;
+ sh->io_port = base;
+ sh->n_io_port = FDOMAIN_REGION_SIZE;
+
+ fd = shost_priv(sh);
+ fd->base = base;
+ fd->chip = chip;
+ INIT_WORK(&fd->work, fdomain_work);
+
+ if (dev_is_pci(dev) || !strcmp(dev->bus->name, "pcmcia"))
+ irq_flags = IRQF_SHARED;
+
+ if (request_irq(irq, fdomain_irq, irq_flags, "fdomain", fd))
+ goto fail_put;
+
+ shost_printk(KERN_INFO, sh, "%s chip at 0x%x irq %d SCSI ID %d\n",
+ dev_is_pci(dev) ? "TMC-36C70 (PCI bus)" : chip_names[chip],
+ base, irq, sh->this_id);
+
+ if (scsi_add_host(sh, dev))
+ goto fail_free_irq;
+
+ scsi_scan_host(sh);
+
+ return sh;
+
+fail_free_irq:
+ free_irq(irq, fd);
+fail_put:
+ scsi_host_put(sh);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(fdomain_create);
+
+int fdomain_destroy(struct Scsi_Host *sh)
+{
+ struct fdomain *fd = shost_priv(sh);
+
+ cancel_work_sync(&fd->work);
+ scsi_remove_host(sh);
+ if (sh->irq)
+ free_irq(sh->irq, fd);
+ scsi_host_put(sh);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fdomain_destroy);
+
+#ifdef CONFIG_PM_SLEEP
+static int fdomain_resume(struct device *dev)
+{
+ struct fdomain *fd = shost_priv(dev_get_drvdata(dev));
+
+ fdomain_reset(fd->base);
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(fdomain_pm_ops, NULL, fdomain_resume);
+#endif /* CONFIG_PM_SLEEP */
+
+MODULE_AUTHOR("Ondrej Zary, Rickard E. Faith");
+MODULE_DESCRIPTION("Future Domain TMC-16x0/TMC-3260 SCSI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/fdomain.h b/drivers/scsi/fdomain.h
new file mode 100644
index 000000000000..6f63fc6b0d12
--- /dev/null
+++ b/drivers/scsi/fdomain.h
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#define FDOMAIN_REGION_SIZE 0x10
+#define FDOMAIN_BIOS_SIZE 0x2000
+
+enum {
+ in_arbitration = 0x02,
+ in_selection = 0x04,
+ in_other = 0x08,
+ disconnect = 0x10,
+ aborted = 0x20,
+ sent_ident = 0x40,
+};
+
+/* (@) = not present on TMC1800, (#) = not present on TMC1800 and TMC18C50 */
+#define REG_SCSI_DATA 0 /* R/W: SCSI Data (with ACK) */
+#define REG_BSTAT 1 /* R: SCSI Bus Status */
+#define BSTAT_BSY BIT(0) /* Busy */
+#define BSTAT_MSG BIT(1) /* Message */
+#define BSTAT_IO BIT(2) /* Input/Output */
+#define BSTAT_CMD BIT(3) /* Command/Data */
+#define BSTAT_REQ BIT(4) /* Request and Not Ack */
+#define BSTAT_SEL BIT(5) /* Select */
+#define BSTAT_ACK BIT(6) /* Acknowledge and Request */
+#define BSTAT_ATN BIT(7) /* Attention */
+#define REG_BCTL 1 /* W: SCSI Bus Control */
+#define BCTL_RST BIT(0) /* Bus Reset */
+#define BCTL_SEL BIT(1) /* Select */
+#define BCTL_BSY BIT(2) /* Busy */
+#define BCTL_ATN BIT(3) /* Attention */
+#define BCTL_IO BIT(4) /* Input/Output */
+#define BCTL_CMD BIT(5) /* Command/Data */
+#define BCTL_MSG BIT(6) /* Message */
+#define BCTL_BUSEN BIT(7) /* Enable bus drivers */
+#define REG_ASTAT 2 /* R: Adapter Status 1 */
+#define ASTAT_IRQ BIT(0) /* Interrupt active */
+#define ASTAT_ARB BIT(1) /* Arbitration complete */
+#define ASTAT_PARERR BIT(2) /* Parity error */
+#define ASTAT_RST BIT(3) /* SCSI reset occurred */
+#define ASTAT_FIFODIR BIT(4) /* FIFO direction */
+#define ASTAT_FIFOEN BIT(5) /* FIFO enabled */
+#define ASTAT_PAREN BIT(6) /* Parity enabled */
+#define ASTAT_BUSEN BIT(7) /* Bus drivers enabled */
+#define REG_ICTL 2 /* W: Interrupt Control */
+#define ICTL_FIFO_MASK 0x0f /* FIFO threshold, 1/16 FIFO size */
+#define ICTL_FIFO BIT(4) /* Int. on FIFO count */
+#define ICTL_ARB BIT(5) /* Int. on Arbitration complete */
+#define ICTL_SEL BIT(6) /* Int. on SCSI Select */
+#define ICTL_REQ BIT(7) /* Int. on SCSI Request */
+#define REG_FSTAT 3 /* R: Adapter Status 2 (FIFO) - (@) */
+#define FSTAT_ONOTEMPTY BIT(0) /* Output FIFO not empty */
+#define FSTAT_INOTEMPTY BIT(1) /* Input FIFO not empty */
+#define FSTAT_NOTEMPTY BIT(2) /* Main FIFO not empty */
+#define FSTAT_NOTFULL BIT(3) /* Main FIFO not full */
+#define REG_MCTL 3 /* W: SCSI Data Mode Control */
+#define MCTL_ACK_MASK 0x0f /* Acknowledge period */
+#define MCTL_ACTDEASS BIT(4) /* Active deassert of REQ and ACK */
+#define MCTL_TARGET BIT(5) /* Enable target mode */
+#define MCTL_FASTSYNC BIT(6) /* Enable Fast Synchronous */
+#define MCTL_SYNC BIT(7) /* Enable Synchronous */
+#define REG_INTCOND 4 /* R: Interrupt Condition - (@) */
+#define IRQ_FIFO BIT(1) /* FIFO interrupt */
+#define IRQ_REQ BIT(2) /* SCSI Request interrupt */
+#define IRQ_SEL BIT(3) /* SCSI Select interrupt */
+#define IRQ_ARB BIT(4) /* SCSI Arbitration interrupt */
+#define IRQ_RST BIT(5) /* SCSI Reset interrupt */
+#define IRQ_FORCED BIT(6) /* Forced interrupt */
+#define IRQ_TIMEOUT BIT(7) /* Bus timeout */
+#define REG_ACTL 4 /* W: Adapter Control 1 */
+#define ACTL_RESET BIT(0) /* Reset FIFO, parity, reset int. */
+#define ACTL_FIRQ BIT(1) /* Set Forced interrupt */
+#define ACTL_ARB BIT(2) /* Initiate Bus Arbitration */
+#define ACTL_PAREN BIT(3) /* Enable SCSI Parity */
+#define ACTL_IRQEN BIT(4) /* Enable interrupts */
+#define ACTL_CLRFIRQ BIT(5) /* Clear Forced interrupt */
+#define ACTL_FIFOWR BIT(6) /* FIFO Direction (1=write) */
+#define ACTL_FIFOEN BIT(7) /* Enable FIFO */
+#define REG_ID_LSB 5 /* R: ID Code (LSB) */
+#define REG_ACTL2 5 /* Adapter Control 2 - (@) */
+#define ACTL2_RAMOVRLY BIT(0) /* Enable RAM overlay */
+#define ACTL2_SLEEP BIT(7) /* Sleep mode */
+#define REG_ID_MSB 6 /* R: ID Code (MSB) */
+#define REG_LOOPBACK 7 /* R/W: Loopback */
+#define REG_SCSI_DATA_NOACK 8 /* R/W: SCSI Data (no ACK) */
+#define REG_ASTAT3 9 /* R: Adapter Status 3 */
+#define ASTAT3_ACTDEASS BIT(0) /* Active deassert enabled */
+#define ASTAT3_RAMOVRLY BIT(1) /* RAM overlay enabled */
+#define ASTAT3_TARGERR BIT(2) /* Target error */
+#define ASTAT3_IRQEN BIT(3) /* Interrupts enabled */
+#define ASTAT3_IRQMASK 0xf0 /* Enabled interrupts mask */
+#define REG_CFG1 10 /* R: Configuration Register 1 */
+#define CFG1_BUS BIT(0) /* 0 = ISA */
+#define CFG1_IRQ_MASK 0x0e /* IRQ jumpers */
+#define CFG1_IO_MASK 0x30 /* I/O base jumpers */
+#define CFG1_BIOS_MASK 0xc0 /* BIOS base jumpers */
+#define REG_CFG2 11 /* R/W: Configuration Register 2 (@) */
+#define CFG2_ROMDIS BIT(0) /* ROM disabled */
+#define CFG2_RAMDIS BIT(1) /* RAM disabled */
+#define CFG2_IRQEDGE BIT(2) /* Edge-triggered interrupts */
+#define CFG2_NOWS BIT(3) /* No wait states */
+#define CFG2_32BIT BIT(7) /* 32-bit mode */
+#define REG_FIFO 12 /* R/W: FIFO */
+#define REG_FIFO_COUNT 14 /* R: FIFO Data Count */
+
+#ifdef CONFIG_PM_SLEEP
+static const struct dev_pm_ops fdomain_pm_ops;
+#define FDOMAIN_PM_OPS (&fdomain_pm_ops)
+#else
+#define FDOMAIN_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
+struct Scsi_Host *fdomain_create(int base, int irq, int this_id,
+ struct device *dev);
+int fdomain_destroy(struct Scsi_Host *sh);
diff --git a/drivers/scsi/fdomain_isa.c b/drivers/scsi/fdomain_isa.c
new file mode 100644
index 000000000000..28639adf8219
--- /dev/null
+++ b/drivers/scsi/fdomain_isa.c
@@ -0,0 +1,222 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/isa.h>
+#include <scsi/scsi_host.h>
+#include "fdomain.h"
+
+#define MAXBOARDS_PARAM 4
+static int io[MAXBOARDS_PARAM] = { 0, 0, 0, 0 };
+module_param_hw_array(io, int, ioport, NULL, 0);
+MODULE_PARM_DESC(io, "base I/O address of controller (0x140, 0x150, 0x160, 0x170)");
+
+static int irq[MAXBOARDS_PARAM] = { 0, 0, 0, 0 };
+module_param_hw_array(irq, int, irq, NULL, 0);
+MODULE_PARM_DESC(irq, "IRQ of controller (0=auto [default])");
+
+static int scsi_id[MAXBOARDS_PARAM] = { 0, 0, 0, 0 };
+module_param_hw_array(scsi_id, int, other, NULL, 0);
+MODULE_PARM_DESC(scsi_id, "SCSI ID of controller (default = 7)");
+
+static unsigned long addresses[] = {
+ 0xc8000,
+ 0xca000,
+ 0xce000,
+ 0xde000,
+};
+#define ADDRESS_COUNT ARRAY_SIZE(addresses)
+
+static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 };
+#define PORT_COUNT ARRAY_SIZE(ports)
+
+static unsigned short irqs[] = { 3, 5, 10, 11, 12, 14, 15, 0 };
+
+/* This driver works *ONLY* for Future Domain cards using the TMC-1800,
+ * TMC-18C50, or TMC-18C30 chip. This includes models TMC-1650, 1660, 1670,
+ * and 1680. These are all 16-bit cards.
+ * BIOS versions prior to 3.2 assigned SCSI ID 6 to SCSI adapter.
+ *
+ * The following BIOS signature signatures are for boards which do *NOT*
+ * work with this driver (these TMC-8xx and TMC-9xx boards may work with the
+ * Seagate driver):
+ *
+ * FUTURE DOMAIN CORP. (C) 1986-1988 V4.0I 03/16/88
+ * FUTURE DOMAIN CORP. (C) 1986-1989 V5.0C2/14/89
+ * FUTURE DOMAIN CORP. (C) 1986-1989 V6.0A7/28/89
+ * FUTURE DOMAIN CORP. (C) 1986-1990 V6.0105/31/90
+ * FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90
+ * FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90
+ * FUTURE DOMAIN CORP. (C) 1992 V8.00.004/02/92
+ *
+ * (The cards which do *NOT* work are all 8-bit cards -- although some of
+ * them have a 16-bit form-factor, the upper 8-bits are used only for IRQs
+ * and are *NOT* used for data. You can tell the difference by following
+ * the tracings on the circuit board -- if only the IRQ lines are involved,
+ * you have a "8-bit" card, and should *NOT* use this driver.)
+ */
+
+static struct signature {
+ const char *signature;
+ int offset;
+ int length;
+ int this_id;
+ int base_offset;
+} signatures[] = {
+/* 1 2 3 4 5 6 */
+/* 123456789012345678901234567890123456789012345678901234567890 */
+{ "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89", 5, 50, 6, 0x1fcc },
+{ "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V1.07/28/89", 5, 50, 6, 0x1fcc },
+{ "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89", 72, 50, 6, 0x1fa2 },
+{ "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.0", 73, 43, 6, 0x1fa2 },
+{ "FUTURE DOMAIN CORP. (C) 1991 1800-V2.0.", 72, 39, 6, 0x1fa3 },
+{ "FUTURE DOMAIN CORP. (C) 1992 V3.00.004/02/92", 5, 44, 6, 0 },
+{ "FUTURE DOMAIN TMC-18XX (C) 1993 V3.203/12/93", 5, 44, 7, 0 },
+{ "IBM F1 P2 BIOS v1.0011/09/92", 5, 28, 7, 0x1ff3 },
+{ "IBM F1 P2 BIOS v1.0104/29/93", 5, 28, 7, 0 },
+{ "Future Domain Corp. V1.0008/18/93", 5, 33, 7, 0 },
+{ "Future Domain Corp. V2.0108/18/93", 5, 33, 7, 0 },
+{ "FUTURE DOMAIN CORP. V3.5008/18/93", 5, 34, 7, 0 },
+{ "FUTURE DOMAIN 18c30/18c50/1800 (C) 1994 V3.5", 5, 44, 7, 0 },
+{ "FUTURE DOMAIN CORP. V3.6008/18/93", 5, 34, 7, 0 },
+{ "FUTURE DOMAIN CORP. V3.6108/18/93", 5, 34, 7, 0 },
+};
+#define SIGNATURE_COUNT ARRAY_SIZE(signatures)
+
+static int fdomain_isa_match(struct device *dev, unsigned int ndev)
+{
+ struct Scsi_Host *sh;
+ int i, base = 0, irq = 0;
+ unsigned long bios_base = 0;
+ struct signature *sig = NULL;
+ void __iomem *p;
+ static struct signature *saved_sig;
+ int this_id = 7;
+
+ if (ndev < ADDRESS_COUNT) { /* scan supported ISA BIOS addresses */
+ p = ioremap(addresses[ndev], FDOMAIN_BIOS_SIZE);
+ if (!p)
+ return 0;
+ for (i = 0; i < SIGNATURE_COUNT; i++)
+ if (check_signature(p + signatures[i].offset,
+ signatures[i].signature,
+ signatures[i].length))
+ break;
+ if (i == SIGNATURE_COUNT) /* no signature found */
+ goto fail_unmap;
+ sig = &signatures[i];
+ bios_base = addresses[ndev];
+ /* read I/O base from BIOS area */
+ if (sig->base_offset)
+ base = readb(p + sig->base_offset) +
+ (readb(p + sig->base_offset + 1) << 8);
+ iounmap(p);
+ if (base)
+ dev_info(dev, "BIOS at 0x%lx specifies I/O base 0x%x\n",
+ bios_base, base);
+ else
+ dev_info(dev, "BIOS at 0x%lx\n", bios_base);
+ if (!base) { /* no I/O base in BIOS area */
+ /* save BIOS signature for later use in port probing */
+ saved_sig = sig;
+ return 0;
+ }
+ } else /* scan supported I/O ports */
+ base = ports[ndev - ADDRESS_COUNT];
+
+ /* use saved BIOS signature if present */
+ if (!sig && saved_sig)
+ sig = saved_sig;
+
+ if (!request_region(base, FDOMAIN_REGION_SIZE, "fdomain_isa"))
+ return 0;
+
+ irq = irqs[(inb(base + REG_CFG1) & 0x0e) >> 1];
+
+
+ if (sig)
+ this_id = sig->this_id;
+
+ sh = fdomain_create(base, irq, this_id, dev);
+ if (!sh) {
+ release_region(base, FDOMAIN_REGION_SIZE);
+ return 0;
+ }
+
+ dev_set_drvdata(dev, sh);
+ return 1;
+fail_unmap:
+ iounmap(p);
+ return 0;
+}
+
+static int fdomain_isa_param_match(struct device *dev, unsigned int ndev)
+{
+ struct Scsi_Host *sh;
+ int irq_ = irq[ndev];
+
+ if (!io[ndev])
+ return 0;
+
+ if (!request_region(io[ndev], FDOMAIN_REGION_SIZE, "fdomain_isa")) {
+ dev_err(dev, "base 0x%x already in use", io[ndev]);
+ return 0;
+ }
+
+ if (irq_ <= 0)
+ irq_ = irqs[(inb(io[ndev] + REG_CFG1) & 0x0e) >> 1];
+
+ sh = fdomain_create(io[ndev], irq_, scsi_id[ndev], dev);
+ if (!sh) {
+ dev_err(dev, "controller not found at base 0x%x", io[ndev]);
+ release_region(io[ndev], FDOMAIN_REGION_SIZE);
+ return 0;
+ }
+
+ dev_set_drvdata(dev, sh);
+ return 1;
+}
+
+static int fdomain_isa_remove(struct device *dev, unsigned int ndev)
+{
+ struct Scsi_Host *sh = dev_get_drvdata(dev);
+ int base = sh->io_port;
+
+ fdomain_destroy(sh);
+ release_region(base, FDOMAIN_REGION_SIZE);
+ dev_set_drvdata(dev, NULL);
+ return 0;
+}
+
+static struct isa_driver fdomain_isa_driver = {
+ .match = fdomain_isa_match,
+ .remove = fdomain_isa_remove,
+ .driver = {
+ .name = "fdomain_isa",
+ .pm = FDOMAIN_PM_OPS,
+ },
+};
+
+static int __init fdomain_isa_init(void)
+{
+ int isa_probe_count = ADDRESS_COUNT + PORT_COUNT;
+
+ if (io[0]) { /* use module parameters if present */
+ fdomain_isa_driver.match = fdomain_isa_param_match;
+ isa_probe_count = MAXBOARDS_PARAM;
+ }
+
+ return isa_register_driver(&fdomain_isa_driver, isa_probe_count);
+}
+
+static void __exit fdomain_isa_exit(void)
+{
+ isa_unregister_driver(&fdomain_isa_driver);
+}
+
+module_init(fdomain_isa_init);
+module_exit(fdomain_isa_exit);
+
+MODULE_AUTHOR("Ondrej Zary, Rickard E. Faith");
+MODULE_DESCRIPTION("Future Domain TMC-16x0 ISA SCSI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/fdomain_pci.c b/drivers/scsi/fdomain_pci.c
new file mode 100644
index 000000000000..3e05ce7b89e5
--- /dev/null
+++ b/drivers/scsi/fdomain_pci.c
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include "fdomain.h"
+
+static int fdomain_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *d)
+{
+ int err;
+ struct Scsi_Host *sh;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ goto fail;
+
+ err = pci_request_regions(pdev, "fdomain_pci");
+ if (err)
+ goto disable_device;
+
+ err = -ENODEV;
+ if (pci_resource_len(pdev, 0) == 0)
+ goto release_region;
+
+ sh = fdomain_create(pci_resource_start(pdev, 0), pdev->irq, 7,
+ &pdev->dev);
+ if (!sh)
+ goto release_region;
+
+ pci_set_drvdata(pdev, sh);
+ return 0;
+
+release_region:
+ pci_release_regions(pdev);
+disable_device:
+ pci_disable_device(pdev);
+fail:
+ return err;
+}
+
+static void fdomain_pci_remove(struct pci_dev *pdev)
+{
+ struct Scsi_Host *sh = pci_get_drvdata(pdev);
+
+ fdomain_destroy(sh);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+}
+
+static struct pci_device_id fdomain_pci_table[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70) },
+ {}
+};
+MODULE_DEVICE_TABLE(pci, fdomain_pci_table);
+
+static struct pci_driver fdomain_pci_driver = {
+ .name = "fdomain_pci",
+ .id_table = fdomain_pci_table,
+ .probe = fdomain_pci_probe,
+ .remove = fdomain_pci_remove,
+ .driver.pm = FDOMAIN_PM_OPS,
+};
+
+module_pci_driver(fdomain_pci_driver);
+
+MODULE_AUTHOR("Ondrej Zary, Rickard E. Faith");
+MODULE_DESCRIPTION("Future Domain TMC-3260 PCI SCSI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index 8d9a8fb2dd32..42a02cc47a60 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -61,10 +61,6 @@
#define HISI_SAS_MAX_SMP_RESP_SZ 1028
#define HISI_SAS_MAX_STP_RESP_SZ 28
-#define DEV_IS_EXPANDER(type) \
- ((type == SAS_EDGE_EXPANDER_DEVICE) || \
- (type == SAS_FANOUT_EXPANDER_DEVICE))
-
#define HISI_SAS_SATA_PROTOCOL_NONDATA 0x1
#define HISI_SAS_SATA_PROTOCOL_PIO 0x2
#define HISI_SAS_SATA_PROTOCOL_DMA 0x4
@@ -479,12 +475,12 @@ struct hisi_sas_command_table_stp {
u8 atapi_cdb[ATAPI_CDB_LEN];
};
-#define HISI_SAS_SGE_PAGE_CNT SG_CHUNK_SIZE
+#define HISI_SAS_SGE_PAGE_CNT (124)
struct hisi_sas_sge_page {
struct hisi_sas_sge sge[HISI_SAS_SGE_PAGE_CNT];
} __aligned(16);
-#define HISI_SAS_SGE_DIF_PAGE_CNT SG_CHUNK_SIZE
+#define HISI_SAS_SGE_DIF_PAGE_CNT HISI_SAS_SGE_PAGE_CNT
struct hisi_sas_sge_dif_page {
struct hisi_sas_sge sge[HISI_SAS_SGE_DIF_PAGE_CNT];
} __aligned(16);
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 5879771d82b2..cb746cfc2fa8 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -803,7 +803,7 @@ static int hisi_sas_dev_found(struct domain_device *device)
device->lldd_dev = sas_dev;
hisi_hba->hw->setup_itct(hisi_hba, sas_dev);
- if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) {
+ if (parent_dev && dev_is_expander(parent_dev->dev_type)) {
int phy_no;
u8 phy_num = parent_dev->ex_dev.num_phys;
struct ex_phy *phy;
@@ -1446,7 +1446,7 @@ static void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 old_state,
_sas_port = sas_port;
- if (DEV_IS_EXPANDER(dev->dev_type))
+ if (dev_is_expander(dev->dev_type))
sas_ha->notify_port_event(sas_phy,
PORTE_BROADCAST_RCVD);
}
@@ -1533,7 +1533,7 @@ static void hisi_sas_terminate_stp_reject(struct hisi_hba *hisi_hba)
struct domain_device *port_dev = sas_port->port_dev;
struct domain_device *device;
- if (!port_dev || !DEV_IS_EXPANDER(port_dev->dev_type))
+ if (!port_dev || !dev_is_expander(port_dev->dev_type))
continue;
/* Try to find a SATA device */
@@ -1903,7 +1903,7 @@ static int hisi_sas_clear_nexus_ha(struct sas_ha_struct *sas_ha)
struct domain_device *device = sas_dev->sas_device;
if ((sas_dev->dev_type == SAS_PHY_UNUSED) || !device ||
- DEV_IS_EXPANDER(device->dev_type))
+ dev_is_expander(device->dev_type))
continue;
rc = hisi_sas_debug_I_T_nexus_reset(device);
@@ -2475,6 +2475,14 @@ EXPORT_SYMBOL_GPL(hisi_sas_alloc);
void hisi_sas_free(struct hisi_hba *hisi_hba)
{
+ int i;
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ struct hisi_sas_phy *phy = &hisi_hba->phy[i];
+
+ del_timer_sync(&phy->timer);
+ }
+
if (hisi_hba->wq)
destroy_workqueue(hisi_hba->wq);
}
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index d99086ef6244..e9b15d45f98f 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -422,70 +422,70 @@ static const struct hisi_sas_hw_error one_bit_ecc_errors[] = {
.irq_msk = BIT(SAS_ECC_INTR_DQE_ECC_1B_OFF),
.msk = HGC_DQE_ECC_1B_ADDR_MSK,
.shift = HGC_DQE_ECC_1B_ADDR_OFF,
- .msg = "hgc_dqe_acc1b_intr found: Ram address is 0x%08X\n",
+ .msg = "hgc_dqe_ecc1b_intr",
.reg = HGC_DQE_ECC_ADDR,
},
{
.irq_msk = BIT(SAS_ECC_INTR_IOST_ECC_1B_OFF),
.msk = HGC_IOST_ECC_1B_ADDR_MSK,
.shift = HGC_IOST_ECC_1B_ADDR_OFF,
- .msg = "hgc_iost_acc1b_intr found: Ram address is 0x%08X\n",
+ .msg = "hgc_iost_ecc1b_intr",
.reg = HGC_IOST_ECC_ADDR,
},
{
.irq_msk = BIT(SAS_ECC_INTR_ITCT_ECC_1B_OFF),
.msk = HGC_ITCT_ECC_1B_ADDR_MSK,
.shift = HGC_ITCT_ECC_1B_ADDR_OFF,
- .msg = "hgc_itct_acc1b_intr found: am address is 0x%08X\n",
+ .msg = "hgc_itct_ecc1b_intr",
.reg = HGC_ITCT_ECC_ADDR,
},
{
.irq_msk = BIT(SAS_ECC_INTR_IOSTLIST_ECC_1B_OFF),
.msk = HGC_LM_DFX_STATUS2_IOSTLIST_MSK,
.shift = HGC_LM_DFX_STATUS2_IOSTLIST_OFF,
- .msg = "hgc_iostl_acc1b_intr found: memory address is 0x%08X\n",
+ .msg = "hgc_iostl_ecc1b_intr",
.reg = HGC_LM_DFX_STATUS2,
},
{
.irq_msk = BIT(SAS_ECC_INTR_ITCTLIST_ECC_1B_OFF),
.msk = HGC_LM_DFX_STATUS2_ITCTLIST_MSK,
.shift = HGC_LM_DFX_STATUS2_ITCTLIST_OFF,
- .msg = "hgc_itctl_acc1b_intr found: memory address is 0x%08X\n",
+ .msg = "hgc_itctl_ecc1b_intr",
.reg = HGC_LM_DFX_STATUS2,
},
{
.irq_msk = BIT(SAS_ECC_INTR_CQE_ECC_1B_OFF),
.msk = HGC_CQE_ECC_1B_ADDR_MSK,
.shift = HGC_CQE_ECC_1B_ADDR_OFF,
- .msg = "hgc_cqe_acc1b_intr found: Ram address is 0x%08X\n",
+ .msg = "hgc_cqe_ecc1b_intr",
.reg = HGC_CQE_ECC_ADDR,
},
{
.irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM0_ECC_1B_OFF),
.msk = HGC_RXM_DFX_STATUS14_MEM0_MSK,
.shift = HGC_RXM_DFX_STATUS14_MEM0_OFF,
- .msg = "rxm_mem0_acc1b_intr found: memory address is 0x%08X\n",
+ .msg = "rxm_mem0_ecc1b_intr",
.reg = HGC_RXM_DFX_STATUS14,
},
{
.irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM1_ECC_1B_OFF),
.msk = HGC_RXM_DFX_STATUS14_MEM1_MSK,
.shift = HGC_RXM_DFX_STATUS14_MEM1_OFF,
- .msg = "rxm_mem1_acc1b_intr found: memory address is 0x%08X\n",
+ .msg = "rxm_mem1_ecc1b_intr",
.reg = HGC_RXM_DFX_STATUS14,
},
{
.irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM2_ECC_1B_OFF),
.msk = HGC_RXM_DFX_STATUS14_MEM2_MSK,
.shift = HGC_RXM_DFX_STATUS14_MEM2_OFF,
- .msg = "rxm_mem2_acc1b_intr found: memory address is 0x%08X\n",
+ .msg = "rxm_mem2_ecc1b_intr",
.reg = HGC_RXM_DFX_STATUS14,
},
{
.irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM3_ECC_1B_OFF),
.msk = HGC_RXM_DFX_STATUS15_MEM3_MSK,
.shift = HGC_RXM_DFX_STATUS15_MEM3_OFF,
- .msg = "rxm_mem3_acc1b_intr found: memory address is 0x%08X\n",
+ .msg = "rxm_mem3_ecc1b_intr",
.reg = HGC_RXM_DFX_STATUS15,
},
};
@@ -495,70 +495,70 @@ static const struct hisi_sas_hw_error multi_bit_ecc_errors[] = {
.irq_msk = BIT(SAS_ECC_INTR_DQE_ECC_MB_OFF),
.msk = HGC_DQE_ECC_MB_ADDR_MSK,
.shift = HGC_DQE_ECC_MB_ADDR_OFF,
- .msg = "hgc_dqe_accbad_intr (0x%x) found: Ram address is 0x%08X\n",
+ .msg = "hgc_dqe_eccbad_intr",
.reg = HGC_DQE_ECC_ADDR,
},
{
.irq_msk = BIT(SAS_ECC_INTR_IOST_ECC_MB_OFF),
.msk = HGC_IOST_ECC_MB_ADDR_MSK,
.shift = HGC_IOST_ECC_MB_ADDR_OFF,
- .msg = "hgc_iost_accbad_intr (0x%x) found: Ram address is 0x%08X\n",
+ .msg = "hgc_iost_eccbad_intr",
.reg = HGC_IOST_ECC_ADDR,
},
{
.irq_msk = BIT(SAS_ECC_INTR_ITCT_ECC_MB_OFF),
.msk = HGC_ITCT_ECC_MB_ADDR_MSK,
.shift = HGC_ITCT_ECC_MB_ADDR_OFF,
- .msg = "hgc_itct_accbad_intr (0x%x) found: Ram address is 0x%08X\n",
+ .msg = "hgc_itct_eccbad_intr",
.reg = HGC_ITCT_ECC_ADDR,
},
{
.irq_msk = BIT(SAS_ECC_INTR_IOSTLIST_ECC_MB_OFF),
.msk = HGC_LM_DFX_STATUS2_IOSTLIST_MSK,
.shift = HGC_LM_DFX_STATUS2_IOSTLIST_OFF,
- .msg = "hgc_iostl_accbad_intr (0x%x) found: memory address is 0x%08X\n",
+ .msg = "hgc_iostl_eccbad_intr",
.reg = HGC_LM_DFX_STATUS2,
},
{
.irq_msk = BIT(SAS_ECC_INTR_ITCTLIST_ECC_MB_OFF),
.msk = HGC_LM_DFX_STATUS2_ITCTLIST_MSK,
.shift = HGC_LM_DFX_STATUS2_ITCTLIST_OFF,
- .msg = "hgc_itctl_accbad_intr (0x%x) found: memory address is 0x%08X\n",
+ .msg = "hgc_itctl_eccbad_intr",
.reg = HGC_LM_DFX_STATUS2,
},
{
.irq_msk = BIT(SAS_ECC_INTR_CQE_ECC_MB_OFF),
.msk = HGC_CQE_ECC_MB_ADDR_MSK,
.shift = HGC_CQE_ECC_MB_ADDR_OFF,
- .msg = "hgc_cqe_accbad_intr (0x%x) found: Ram address is 0x%08X\n",
+ .msg = "hgc_cqe_eccbad_intr",
.reg = HGC_CQE_ECC_ADDR,
},
{
.irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM0_ECC_MB_OFF),
.msk = HGC_RXM_DFX_STATUS14_MEM0_MSK,
.shift = HGC_RXM_DFX_STATUS14_MEM0_OFF,
- .msg = "rxm_mem0_accbad_intr (0x%x) found: memory address is 0x%08X\n",
+ .msg = "rxm_mem0_eccbad_intr",
.reg = HGC_RXM_DFX_STATUS14,
},
{
.irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM1_ECC_MB_OFF),
.msk = HGC_RXM_DFX_STATUS14_MEM1_MSK,
.shift = HGC_RXM_DFX_STATUS14_MEM1_OFF,
- .msg = "rxm_mem1_accbad_intr (0x%x) found: memory address is 0x%08X\n",
+ .msg = "rxm_mem1_eccbad_intr",
.reg = HGC_RXM_DFX_STATUS14,
},
{
.irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM2_ECC_MB_OFF),
.msk = HGC_RXM_DFX_STATUS14_MEM2_MSK,
.shift = HGC_RXM_DFX_STATUS14_MEM2_OFF,
- .msg = "rxm_mem2_accbad_intr (0x%x) found: memory address is 0x%08X\n",
+ .msg = "rxm_mem2_eccbad_intr",
.reg = HGC_RXM_DFX_STATUS14,
},
{
.irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM3_ECC_MB_OFF),
.msk = HGC_RXM_DFX_STATUS15_MEM3_MSK,
.shift = HGC_RXM_DFX_STATUS15_MEM3_OFF,
- .msg = "rxm_mem3_accbad_intr (0x%x) found: memory address is 0x%08X\n",
+ .msg = "rxm_mem3_eccbad_intr",
.reg = HGC_RXM_DFX_STATUS15,
},
};
@@ -944,7 +944,7 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba,
break;
case SAS_SATA_DEV:
case SAS_SATA_PENDING:
- if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
+ if (parent_dev && dev_is_expander(parent_dev->dev_type))
qw0 = HISI_SAS_DEV_TYPE_STP << ITCT_HDR_DEV_TYPE_OFF;
else
qw0 = HISI_SAS_DEV_TYPE_SATA << ITCT_HDR_DEV_TYPE_OFF;
@@ -2526,7 +2526,7 @@ static void prep_ata_v2_hw(struct hisi_hba *hisi_hba,
/* create header */
/* dw0 */
dw0 = port->id << CMD_HDR_PORT_OFF;
- if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
+ if (parent_dev && dev_is_expander(parent_dev->dev_type))
dw0 |= 3 << CMD_HDR_CMD_OFF;
else
dw0 |= 4 << CMD_HDR_CMD_OFF;
@@ -2973,7 +2973,8 @@ one_bit_ecc_error_process_v2_hw(struct hisi_hba *hisi_hba, u32 irq_value)
val = hisi_sas_read32(hisi_hba, ecc_error->reg);
val &= ecc_error->msk;
val >>= ecc_error->shift;
- dev_warn(dev, ecc_error->msg, val);
+ dev_warn(dev, "%s found: mem addr is 0x%08X\n",
+ ecc_error->msg, val);
}
}
}
@@ -2992,7 +2993,8 @@ static void multi_bit_ecc_error_process_v2_hw(struct hisi_hba *hisi_hba,
val = hisi_sas_read32(hisi_hba, ecc_error->reg);
val &= ecc_error->msk;
val >>= ecc_error->shift;
- dev_err(dev, ecc_error->msg, irq_value, val);
+ dev_err(dev, "%s (0x%x) found: mem addr is 0x%08X\n",
+ ecc_error->msg, irq_value, val);
queue_work(hisi_hba->wq, &hisi_hba->rst_work);
}
}
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 0efd55baacd3..5f0f6df11adf 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -23,6 +23,7 @@
#define ITCT_CLR_EN_MSK (0x1 << ITCT_CLR_EN_OFF)
#define ITCT_DEV_OFF 0
#define ITCT_DEV_MSK (0x7ff << ITCT_DEV_OFF)
+#define SAS_AXI_USER3 0x50
#define IO_SATA_BROKEN_MSG_ADDR_LO 0x58
#define IO_SATA_BROKEN_MSG_ADDR_HI 0x5c
#define SATA_INITI_D2H_STORE_ADDR_LO 0x60
@@ -549,6 +550,7 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
/* Global registers init */
hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE,
(u32)((1ULL << hisi_hba->queue_count) - 1));
+ hisi_sas_write32(hisi_hba, SAS_AXI_USER3, 0);
hisi_sas_write32(hisi_hba, CFG_MAX_TAG, 0xfff0400);
hisi_sas_write32(hisi_hba, HGC_SAS_TXFAIL_RETRY_CTRL, 0x108);
hisi_sas_write32(hisi_hba, CFG_AGING_TIME, 0x1);
@@ -752,7 +754,7 @@ static void setup_itct_v3_hw(struct hisi_hba *hisi_hba,
break;
case SAS_SATA_DEV:
case SAS_SATA_PENDING:
- if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
+ if (parent_dev && dev_is_expander(parent_dev->dev_type))
qw0 = HISI_SAS_DEV_TYPE_STP << ITCT_HDR_DEV_TYPE_OFF;
else
qw0 = HISI_SAS_DEV_TYPE_SATA << ITCT_HDR_DEV_TYPE_OFF;
@@ -906,8 +908,14 @@ static void enable_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
static void disable_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
{
u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
+ u32 irq_msk = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT2_MSK);
+ static const u32 msk = BIT(CHL_INT2_RX_DISP_ERR_OFF) |
+ BIT(CHL_INT2_RX_CODE_ERR_OFF) |
+ BIT(CHL_INT2_RX_INVLD_DW_OFF);
u32 state;
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2_MSK, msk | irq_msk);
+
cfg &= ~PHY_CFG_ENA_MSK;
hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
@@ -918,6 +926,15 @@ static void disable_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
cfg |= PHY_CFG_PHY_RST_MSK;
hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
}
+
+ udelay(1);
+
+ hisi_sas_phy_read32(hisi_hba, phy_no, ERR_CNT_INVLD_DW);
+ hisi_sas_phy_read32(hisi_hba, phy_no, ERR_CNT_DISP_ERR);
+ hisi_sas_phy_read32(hisi_hba, phy_no, ERR_CNT_CODE_ERR);
+
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2, msk);
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2_MSK, irq_msk);
}
static void start_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
@@ -1336,10 +1353,10 @@ static void prep_ata_v3_hw(struct hisi_hba *hisi_hba,
u32 dw1 = 0, dw2 = 0;
hdr->dw0 = cpu_to_le32(port->id << CMD_HDR_PORT_OFF);
- if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
+ if (parent_dev && dev_is_expander(parent_dev->dev_type))
hdr->dw0 |= cpu_to_le32(3 << CMD_HDR_CMD_OFF);
else
- hdr->dw0 |= cpu_to_le32(4 << CMD_HDR_CMD_OFF);
+ hdr->dw0 |= cpu_to_le32(4U << CMD_HDR_CMD_OFF);
switch (task->data_dir) {
case DMA_TO_DEVICE:
@@ -1407,7 +1424,7 @@ static void prep_abort_v3_hw(struct hisi_hba *hisi_hba,
struct hisi_sas_port *port = slot->port;
/* dw0 */
- hdr->dw0 = cpu_to_le32((5 << CMD_HDR_CMD_OFF) | /*abort*/
+ hdr->dw0 = cpu_to_le32((5U << CMD_HDR_CMD_OFF) | /*abort*/
(port->id << CMD_HDR_PORT_OFF) |
(dev_is_sata(dev)
<< CMD_HDR_ABORT_DEVICE_TYPE_OFF) |
@@ -1826,77 +1843,77 @@ static const struct hisi_sas_hw_error multi_bit_ecc_errors[] = {
.irq_msk = BIT(SAS_ECC_INTR_DQE_ECC_MB_OFF),
.msk = HGC_DQE_ECC_MB_ADDR_MSK,
.shift = HGC_DQE_ECC_MB_ADDR_OFF,
- .msg = "hgc_dqe_eccbad_intr found: ram addr is 0x%08X\n",
+ .msg = "hgc_dqe_eccbad_intr",
.reg = HGC_DQE_ECC_ADDR,
},
{
.irq_msk = BIT(SAS_ECC_INTR_IOST_ECC_MB_OFF),
.msk = HGC_IOST_ECC_MB_ADDR_MSK,
.shift = HGC_IOST_ECC_MB_ADDR_OFF,
- .msg = "hgc_iost_eccbad_intr found: ram addr is 0x%08X\n",
+ .msg = "hgc_iost_eccbad_intr",
.reg = HGC_IOST_ECC_ADDR,
},
{
.irq_msk = BIT(SAS_ECC_INTR_ITCT_ECC_MB_OFF),
.msk = HGC_ITCT_ECC_MB_ADDR_MSK,
.shift = HGC_ITCT_ECC_MB_ADDR_OFF,
- .msg = "hgc_itct_eccbad_intr found: ram addr is 0x%08X\n",
+ .msg = "hgc_itct_eccbad_intr",
.reg = HGC_ITCT_ECC_ADDR,
},
{
.irq_msk = BIT(SAS_ECC_INTR_IOSTLIST_ECC_MB_OFF),
.msk = HGC_LM_DFX_STATUS2_IOSTLIST_MSK,
.shift = HGC_LM_DFX_STATUS2_IOSTLIST_OFF,
- .msg = "hgc_iostl_eccbad_intr found: mem addr is 0x%08X\n",
+ .msg = "hgc_iostl_eccbad_intr",
.reg = HGC_LM_DFX_STATUS2,
},
{
.irq_msk = BIT(SAS_ECC_INTR_ITCTLIST_ECC_MB_OFF),
.msk = HGC_LM_DFX_STATUS2_ITCTLIST_MSK,
.shift = HGC_LM_DFX_STATUS2_ITCTLIST_OFF,
- .msg = "hgc_itctl_eccbad_intr found: mem addr is 0x%08X\n",
+ .msg = "hgc_itctl_eccbad_intr",
.reg = HGC_LM_DFX_STATUS2,
},
{
.irq_msk = BIT(SAS_ECC_INTR_CQE_ECC_MB_OFF),
.msk = HGC_CQE_ECC_MB_ADDR_MSK,
.shift = HGC_CQE_ECC_MB_ADDR_OFF,
- .msg = "hgc_cqe_eccbad_intr found: ram address is 0x%08X\n",
+ .msg = "hgc_cqe_eccbad_intr",
.reg = HGC_CQE_ECC_ADDR,
},
{
.irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM0_ECC_MB_OFF),
.msk = HGC_RXM_DFX_STATUS14_MEM0_MSK,
.shift = HGC_RXM_DFX_STATUS14_MEM0_OFF,
- .msg = "rxm_mem0_eccbad_intr found: mem addr is 0x%08X\n",
+ .msg = "rxm_mem0_eccbad_intr",
.reg = HGC_RXM_DFX_STATUS14,
},
{
.irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM1_ECC_MB_OFF),
.msk = HGC_RXM_DFX_STATUS14_MEM1_MSK,
.shift = HGC_RXM_DFX_STATUS14_MEM1_OFF,
- .msg = "rxm_mem1_eccbad_intr found: mem addr is 0x%08X\n",
+ .msg = "rxm_mem1_eccbad_intr",
.reg = HGC_RXM_DFX_STATUS14,
},
{
.irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM2_ECC_MB_OFF),
.msk = HGC_RXM_DFX_STATUS14_MEM2_MSK,
.shift = HGC_RXM_DFX_STATUS14_MEM2_OFF,
- .msg = "rxm_mem2_eccbad_intr found: mem addr is 0x%08X\n",
+ .msg = "rxm_mem2_eccbad_intr",
.reg = HGC_RXM_DFX_STATUS14,
},
{
.irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM3_ECC_MB_OFF),
.msk = HGC_RXM_DFX_STATUS15_MEM3_MSK,
.shift = HGC_RXM_DFX_STATUS15_MEM3_OFF,
- .msg = "rxm_mem3_eccbad_intr found: mem addr is 0x%08X\n",
+ .msg = "rxm_mem3_eccbad_intr",
.reg = HGC_RXM_DFX_STATUS15,
},
{
.irq_msk = BIT(SAS_ECC_INTR_OOO_RAM_ECC_MB_OFF),
.msk = AM_ROB_ECC_ERR_ADDR_MSK,
.shift = AM_ROB_ECC_ERR_ADDR_OFF,
- .msg = "ooo_ram_eccbad_intr found: ROB_ECC_ERR_ADDR=0x%08X\n",
+ .msg = "ooo_ram_eccbad_intr",
.reg = AM_ROB_ECC_ERR_ADDR,
},
};
@@ -1915,7 +1932,8 @@ static void multi_bit_ecc_error_process_v3_hw(struct hisi_hba *hisi_hba,
val = hisi_sas_read32(hisi_hba, ecc_error->reg);
val &= ecc_error->msk;
val >>= ecc_error->shift;
- dev_err(dev, ecc_error->msg, irq_value, val);
+ dev_err(dev, "%s (0x%x) found: mem addr is 0x%08X\n",
+ ecc_error->msg, irq_value, val);
queue_work(hisi_hba->wq, &hisi_hba->rst_work);
}
}
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 8068520cf89e..43a6b5350775 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -60,7 +60,7 @@
* HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.'
* with an optional trailing '-' followed by a byte value (0-255).
*/
-#define HPSA_DRIVER_VERSION "3.4.20-160"
+#define HPSA_DRIVER_VERSION "3.4.20-170"
#define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")"
#define HPSA "hpsa"
@@ -73,6 +73,8 @@
/*define how many times we will try a command because of bus resets */
#define MAX_CMD_RETRIES 3
+/* How long to wait before giving up on a command */
+#define HPSA_EH_PTRAID_TIMEOUT (240 * HZ)
/* Embedded module documentation macros - see modules.h */
MODULE_AUTHOR("Hewlett-Packard Company");
@@ -344,11 +346,6 @@ static inline bool hpsa_is_cmd_idle(struct CommandList *c)
return c->scsi_cmd == SCSI_CMD_IDLE;
}
-static inline bool hpsa_is_pending_event(struct CommandList *c)
-{
- return c->reset_pending;
-}
-
/* extract sense key, asc, and ascq from sense data. -1 means invalid. */
static void decode_sense_data(const u8 *sense_data, int sense_data_len,
u8 *sense_key, u8 *asc, u8 *ascq)
@@ -1144,6 +1141,8 @@ static void __enqueue_cmd_and_start_io(struct ctlr_info *h,
{
dial_down_lockup_detection_during_fw_flash(h, c);
atomic_inc(&h->commands_outstanding);
+ if (c->device)
+ atomic_inc(&c->device->commands_outstanding);
reply_queue = h->reply_map[raw_smp_processor_id()];
switch (c->cmd_type) {
@@ -1167,9 +1166,6 @@ static void __enqueue_cmd_and_start_io(struct ctlr_info *h,
static void enqueue_cmd_and_start_io(struct ctlr_info *h, struct CommandList *c)
{
- if (unlikely(hpsa_is_pending_event(c)))
- return finish_cmd(c);
-
__enqueue_cmd_and_start_io(h, c, DEFAULT_REPLY_QUEUE);
}
@@ -1842,25 +1838,33 @@ static int hpsa_find_outstanding_commands_for_dev(struct ctlr_info *h,
return count;
}
+#define NUM_WAIT 20
static void hpsa_wait_for_outstanding_commands_for_dev(struct ctlr_info *h,
struct hpsa_scsi_dev_t *device)
{
int cmds = 0;
int waits = 0;
+ int num_wait = NUM_WAIT;
+
+ if (device->external)
+ num_wait = HPSA_EH_PTRAID_TIMEOUT;
while (1) {
cmds = hpsa_find_outstanding_commands_for_dev(h, device);
if (cmds == 0)
break;
- if (++waits > 20)
+ if (++waits > num_wait)
break;
msleep(1000);
}
- if (waits > 20)
+ if (waits > num_wait) {
dev_warn(&h->pdev->dev,
- "%s: removing device with %d outstanding commands!\n",
- __func__, cmds);
+ "%s: removing device [%d:%d:%d:%d] with %d outstanding commands!\n",
+ __func__,
+ h->scsi_host->host_no,
+ device->bus, device->target, device->lun, cmds);
+ }
}
static void hpsa_remove_device(struct ctlr_info *h,
@@ -2131,11 +2135,16 @@ static int hpsa_slave_configure(struct scsi_device *sdev)
sdev->no_uld_attach = !sd || !sd->expose_device;
if (sd) {
- if (sd->external)
+ sd->was_removed = 0;
+ if (sd->external) {
queue_depth = EXTERNAL_QD;
- else
+ sdev->eh_timeout = HPSA_EH_PTRAID_TIMEOUT;
+ blk_queue_rq_timeout(sdev->request_queue,
+ HPSA_EH_PTRAID_TIMEOUT);
+ } else {
queue_depth = sd->queue_depth != 0 ?
sd->queue_depth : sdev->host->can_queue;
+ }
} else
queue_depth = sdev->host->can_queue;
@@ -2146,7 +2155,12 @@ static int hpsa_slave_configure(struct scsi_device *sdev)
static void hpsa_slave_destroy(struct scsi_device *sdev)
{
- /* nothing to do. */
+ struct hpsa_scsi_dev_t *hdev = NULL;
+
+ hdev = sdev->hostdata;
+
+ if (hdev)
+ hdev->was_removed = 1;
}
static void hpsa_free_ioaccel2_sg_chain_blocks(struct ctlr_info *h)
@@ -2414,13 +2428,16 @@ static int handle_ioaccel_mode2_error(struct ctlr_info *h,
break;
}
+ if (dev->in_reset)
+ retry = 0;
+
return retry; /* retry on raid path? */
}
static void hpsa_cmd_resolve_events(struct ctlr_info *h,
struct CommandList *c)
{
- bool do_wake = false;
+ struct hpsa_scsi_dev_t *dev = c->device;
/*
* Reset c->scsi_cmd here so that the reset handler will know
@@ -2429,25 +2446,12 @@ static void hpsa_cmd_resolve_events(struct ctlr_info *h,
*/
c->scsi_cmd = SCSI_CMD_IDLE;
mb(); /* Declare command idle before checking for pending events. */
- if (c->reset_pending) {
- unsigned long flags;
- struct hpsa_scsi_dev_t *dev;
-
- /*
- * There appears to be a reset pending; lock the lock and
- * reconfirm. If so, then decrement the count of outstanding
- * commands and wake the reset command if this is the last one.
- */
- spin_lock_irqsave(&h->lock, flags);
- dev = c->reset_pending; /* Re-fetch under the lock. */
- if (dev && atomic_dec_and_test(&dev->reset_cmds_out))
- do_wake = true;
- c->reset_pending = NULL;
- spin_unlock_irqrestore(&h->lock, flags);
+ if (dev) {
+ atomic_dec(&dev->commands_outstanding);
+ if (dev->in_reset &&
+ atomic_read(&dev->commands_outstanding) <= 0)
+ wake_up_all(&h->event_sync_wait_queue);
}
-
- if (do_wake)
- wake_up_all(&h->event_sync_wait_queue);
}
static void hpsa_cmd_resolve_and_free(struct ctlr_info *h,
@@ -2496,6 +2500,11 @@ static void process_ioaccel2_completion(struct ctlr_info *h,
dev->offload_to_be_enabled = 0;
}
+ if (dev->in_reset) {
+ cmd->result = DID_RESET << 16;
+ return hpsa_cmd_free_and_done(h, c, cmd);
+ }
+
return hpsa_retry_cmd(h, c);
}
@@ -2574,6 +2583,12 @@ static void complete_scsi_command(struct CommandList *cp)
cmd->result = (DID_OK << 16); /* host byte */
cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */
+ /* SCSI command has already been cleaned up in SML */
+ if (dev->was_removed) {
+ hpsa_cmd_resolve_and_free(h, cp);
+ return;
+ }
+
if (cp->cmd_type == CMD_IOACCEL2 || cp->cmd_type == CMD_IOACCEL1) {
if (dev->physical_device && dev->expose_device &&
dev->removed) {
@@ -2595,10 +2610,6 @@ static void complete_scsi_command(struct CommandList *cp)
return hpsa_cmd_free_and_done(h, cp, cmd);
}
- if ((unlikely(hpsa_is_pending_event(cp))))
- if (cp->reset_pending)
- return hpsa_cmd_free_and_done(h, cp, cmd);
-
if (cp->cmd_type == CMD_IOACCEL2)
return process_ioaccel2_completion(h, cp, cmd, dev);
@@ -3048,7 +3059,7 @@ out:
return rc;
}
-static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr,
+static int hpsa_send_reset(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev,
u8 reset_type, int reply_queue)
{
int rc = IO_OK;
@@ -3056,11 +3067,10 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr,
struct ErrorInfo *ei;
c = cmd_alloc(h);
-
+ c->device = dev;
/* fill_cmd can't fail here, no data buffer to map. */
- (void) fill_cmd(c, reset_type, h, NULL, 0, 0,
- scsi3addr, TYPE_MSG);
+ (void) fill_cmd(c, reset_type, h, NULL, 0, 0, dev->scsi3addr, TYPE_MSG);
rc = hpsa_scsi_do_simple_cmd(h, c, reply_queue, NO_TIMEOUT);
if (rc) {
dev_warn(&h->pdev->dev, "Failed to send reset command\n");
@@ -3138,9 +3148,8 @@ static bool hpsa_cmd_dev_match(struct ctlr_info *h, struct CommandList *c,
}
static int hpsa_do_reset(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev,
- unsigned char *scsi3addr, u8 reset_type, int reply_queue)
+ u8 reset_type, int reply_queue)
{
- int i;
int rc = 0;
/* We can really only handle one reset at a time */
@@ -3149,38 +3158,14 @@ static int hpsa_do_reset(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev,
return -EINTR;
}
- BUG_ON(atomic_read(&dev->reset_cmds_out) != 0);
-
- for (i = 0; i < h->nr_cmds; i++) {
- struct CommandList *c = h->cmd_pool + i;
- int refcount = atomic_inc_return(&c->refcount);
-
- if (refcount > 1 && hpsa_cmd_dev_match(h, c, dev, scsi3addr)) {
- unsigned long flags;
-
- /*
- * Mark the target command as having a reset pending,
- * then lock a lock so that the command cannot complete
- * while we're considering it. If the command is not
- * idle then count it; otherwise revoke the event.
- */
- c->reset_pending = dev;
- spin_lock_irqsave(&h->lock, flags); /* Implied MB */
- if (!hpsa_is_cmd_idle(c))
- atomic_inc(&dev->reset_cmds_out);
- else
- c->reset_pending = NULL;
- spin_unlock_irqrestore(&h->lock, flags);
- }
-
- cmd_free(h, c);
- }
-
- rc = hpsa_send_reset(h, scsi3addr, reset_type, reply_queue);
- if (!rc)
+ rc = hpsa_send_reset(h, dev, reset_type, reply_queue);
+ if (!rc) {
+ /* incremented by sending the reset request */
+ atomic_dec(&dev->commands_outstanding);
wait_event(h->event_sync_wait_queue,
- atomic_read(&dev->reset_cmds_out) == 0 ||
+ atomic_read(&dev->commands_outstanding) <= 0 ||
lockup_detected(h));
+ }
if (unlikely(lockup_detected(h))) {
dev_warn(&h->pdev->dev,
@@ -3188,10 +3173,8 @@ static int hpsa_do_reset(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev,
rc = -ENODEV;
}
- if (unlikely(rc))
- atomic_set(&dev->reset_cmds_out, 0);
- else
- rc = wait_for_device_to_become_ready(h, scsi3addr, 0);
+ if (!rc)
+ rc = wait_for_device_to_become_ready(h, dev->scsi3addr, 0);
mutex_unlock(&h->reset_mutex);
return rc;
@@ -4820,6 +4803,9 @@ static int hpsa_scsi_ioaccel_direct_map(struct ctlr_info *h,
c->phys_disk = dev;
+ if (dev->in_reset)
+ return -1;
+
return hpsa_scsi_ioaccel_queue_command(h, c, dev->ioaccel_handle,
cmd->cmnd, cmd->cmd_len, dev->scsi3addr, dev);
}
@@ -5010,6 +4996,11 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h,
} else
cp->sg_count = (u8) use_sg;
+ if (phys_disk->in_reset) {
+ cmd->result = DID_RESET << 16;
+ return -1;
+ }
+
enqueue_cmd_and_start_io(h, c);
return 0;
}
@@ -5027,6 +5018,9 @@ static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h,
if (!c->scsi_cmd->device->hostdata)
return -1;
+ if (phys_disk->in_reset)
+ return -1;
+
/* Try to honor the device's queue depth */
if (atomic_inc_return(&phys_disk->ioaccel_cmds_out) >
phys_disk->queue_depth) {
@@ -5110,6 +5104,9 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
if (!dev)
return -1;
+ if (dev->in_reset)
+ return -1;
+
/* check for valid opcode, get LBA and block count */
switch (cmd->cmnd[0]) {
case WRITE_6:
@@ -5414,13 +5411,13 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
*/
static int hpsa_ciss_submit(struct ctlr_info *h,
struct CommandList *c, struct scsi_cmnd *cmd,
- unsigned char scsi3addr[])
+ struct hpsa_scsi_dev_t *dev)
{
cmd->host_scribble = (unsigned char *) c;
c->cmd_type = CMD_SCSI;
c->scsi_cmd = cmd;
c->Header.ReplyQueue = 0; /* unused in simple mode */
- memcpy(&c->Header.LUN.LunAddrBytes[0], &scsi3addr[0], 8);
+ memcpy(&c->Header.LUN.LunAddrBytes[0], &dev->scsi3addr[0], 8);
c->Header.tag = cpu_to_le64((c->cmdindex << DIRECT_LOOKUP_SHIFT));
/* Fill in the request block... */
@@ -5471,6 +5468,12 @@ static int hpsa_ciss_submit(struct ctlr_info *h,
hpsa_cmd_resolve_and_free(h, c);
return SCSI_MLQUEUE_HOST_BUSY;
}
+
+ if (dev->in_reset) {
+ hpsa_cmd_resolve_and_free(h, c);
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+
enqueue_cmd_and_start_io(h, c);
/* the cmd'll come back via intr handler in complete_scsi_command() */
return 0;
@@ -5522,8 +5525,7 @@ static inline void hpsa_cmd_partial_init(struct ctlr_info *h, int index,
}
static int hpsa_ioaccel_submit(struct ctlr_info *h,
- struct CommandList *c, struct scsi_cmnd *cmd,
- unsigned char *scsi3addr)
+ struct CommandList *c, struct scsi_cmnd *cmd)
{
struct hpsa_scsi_dev_t *dev = cmd->device->hostdata;
int rc = IO_ACCEL_INELIGIBLE;
@@ -5531,6 +5533,12 @@ static int hpsa_ioaccel_submit(struct ctlr_info *h,
if (!dev)
return SCSI_MLQUEUE_HOST_BUSY;
+ if (dev->in_reset)
+ return SCSI_MLQUEUE_HOST_BUSY;
+
+ if (hpsa_simple_mode)
+ return IO_ACCEL_INELIGIBLE;
+
cmd->host_scribble = (unsigned char *) c;
if (dev->offload_enabled) {
@@ -5563,8 +5571,12 @@ static void hpsa_command_resubmit_worker(struct work_struct *work)
cmd->result = DID_NO_CONNECT << 16;
return hpsa_cmd_free_and_done(c->h, c, cmd);
}
- if (c->reset_pending)
+
+ if (dev->in_reset) {
+ cmd->result = DID_RESET << 16;
return hpsa_cmd_free_and_done(c->h, c, cmd);
+ }
+
if (c->cmd_type == CMD_IOACCEL2) {
struct ctlr_info *h = c->h;
struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex];
@@ -5572,7 +5584,7 @@ static void hpsa_command_resubmit_worker(struct work_struct *work)
if (c2->error_data.serv_response ==
IOACCEL2_STATUS_SR_TASK_COMP_SET_FULL) {
- rc = hpsa_ioaccel_submit(h, c, cmd, dev->scsi3addr);
+ rc = hpsa_ioaccel_submit(h, c, cmd);
if (rc == 0)
return;
if (rc == SCSI_MLQUEUE_HOST_BUSY) {
@@ -5588,7 +5600,7 @@ static void hpsa_command_resubmit_worker(struct work_struct *work)
}
}
hpsa_cmd_partial_init(c->h, c->cmdindex, c);
- if (hpsa_ciss_submit(c->h, c, cmd, dev->scsi3addr)) {
+ if (hpsa_ciss_submit(c->h, c, cmd, dev)) {
/*
* If we get here, it means dma mapping failed. Try
* again via scsi mid layer, which will then get
@@ -5607,7 +5619,6 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
{
struct ctlr_info *h;
struct hpsa_scsi_dev_t *dev;
- unsigned char scsi3addr[8];
struct CommandList *c;
int rc = 0;
@@ -5629,14 +5640,18 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
return 0;
}
- memcpy(scsi3addr, dev->scsi3addr, sizeof(scsi3addr));
-
if (unlikely(lockup_detected(h))) {
cmd->result = DID_NO_CONNECT << 16;
cmd->scsi_done(cmd);
return 0;
}
+
+ if (dev->in_reset)
+ return SCSI_MLQUEUE_DEVICE_BUSY;
+
c = cmd_tagged_alloc(h, cmd);
+ if (c == NULL)
+ return SCSI_MLQUEUE_DEVICE_BUSY;
/*
* Call alternate submit routine for I/O accelerated commands.
@@ -5645,7 +5660,7 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
if (likely(cmd->retries == 0 &&
!blk_rq_is_passthrough(cmd->request) &&
h->acciopath_status)) {
- rc = hpsa_ioaccel_submit(h, c, cmd, scsi3addr);
+ rc = hpsa_ioaccel_submit(h, c, cmd);
if (rc == 0)
return 0;
if (rc == SCSI_MLQUEUE_HOST_BUSY) {
@@ -5653,7 +5668,7 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
return SCSI_MLQUEUE_HOST_BUSY;
}
}
- return hpsa_ciss_submit(h, c, cmd, scsi3addr);
+ return hpsa_ciss_submit(h, c, cmd, dev);
}
static void hpsa_scan_complete(struct ctlr_info *h)
@@ -5935,8 +5950,9 @@ static int wait_for_device_to_become_ready(struct ctlr_info *h,
static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
{
int rc = SUCCESS;
+ int i;
struct ctlr_info *h;
- struct hpsa_scsi_dev_t *dev;
+ struct hpsa_scsi_dev_t *dev = NULL;
u8 reset_type;
char msg[48];
unsigned long flags;
@@ -6002,9 +6018,19 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
reset_type == HPSA_DEVICE_RESET_MSG ? "logical " : "physical ");
hpsa_show_dev_msg(KERN_WARNING, h, dev, msg);
+ /*
+ * wait to see if any commands will complete before sending reset
+ */
+ dev->in_reset = true; /* block any new cmds from OS for this device */
+ for (i = 0; i < 10; i++) {
+ if (atomic_read(&dev->commands_outstanding) > 0)
+ msleep(1000);
+ else
+ break;
+ }
+
/* send a reset to the SCSI LUN which the command was sent to */
- rc = hpsa_do_reset(h, dev, dev->scsi3addr, reset_type,
- DEFAULT_REPLY_QUEUE);
+ rc = hpsa_do_reset(h, dev, reset_type, DEFAULT_REPLY_QUEUE);
if (rc == 0)
rc = SUCCESS;
else
@@ -6018,6 +6044,8 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
return_reset_status:
spin_lock_irqsave(&h->reset_lock, flags);
h->reset_in_progress = 0;
+ if (dev)
+ dev->in_reset = false;
spin_unlock_irqrestore(&h->reset_lock, flags);
return rc;
}
@@ -6043,7 +6071,6 @@ static struct CommandList *cmd_tagged_alloc(struct ctlr_info *h,
BUG();
}
- atomic_inc(&c->refcount);
if (unlikely(!hpsa_is_cmd_idle(c))) {
/*
* We expect that the SCSI layer will hand us a unique tag
@@ -6051,14 +6078,20 @@ static struct CommandList *cmd_tagged_alloc(struct ctlr_info *h,
* two requests...because if the selected command isn't idle
* then someone is going to be very disappointed.
*/
- dev_err(&h->pdev->dev,
- "tag collision (tag=%d) in cmd_tagged_alloc().\n",
- idx);
- if (c->scsi_cmd != NULL)
- scsi_print_command(c->scsi_cmd);
- scsi_print_command(scmd);
+ if (idx != h->last_collision_tag) { /* Print once per tag */
+ dev_warn(&h->pdev->dev,
+ "%s: tag collision (tag=%d)\n", __func__, idx);
+ if (c->scsi_cmd != NULL)
+ scsi_print_command(c->scsi_cmd);
+ if (scmd)
+ scsi_print_command(scmd);
+ h->last_collision_tag = idx;
+ }
+ return NULL;
}
+ atomic_inc(&c->refcount);
+
hpsa_cmd_partial_init(h, idx, c);
return c;
}
@@ -6126,6 +6159,7 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h)
break; /* it's ours now. */
}
hpsa_cmd_partial_init(h, i, c);
+ c->device = NULL;
return c;
}
@@ -6579,8 +6613,7 @@ static int hpsa_ioctl(struct scsi_device *dev, unsigned int cmd,
}
}
-static void hpsa_send_host_reset(struct ctlr_info *h, unsigned char *scsi3addr,
- u8 reset_type)
+static void hpsa_send_host_reset(struct ctlr_info *h, u8 reset_type)
{
struct CommandList *c;
@@ -7765,7 +7798,7 @@ static void hpsa_free_pci_init(struct ctlr_info *h)
hpsa_disable_interrupt_mode(h); /* pci_init 2 */
/*
* call pci_disable_device before pci_release_regions per
- * Documentation/PCI/pci.txt
+ * Documentation/PCI/pci.rst
*/
pci_disable_device(h->pdev); /* pci_init 1 */
pci_release_regions(h->pdev); /* pci_init 2 */
@@ -7848,7 +7881,7 @@ clean2: /* intmode+region, pci */
clean1:
/*
* call pci_disable_device before pci_release_regions per
- * Documentation/PCI/pci.txt
+ * Documentation/PCI/pci.rst
*/
pci_disable_device(h->pdev);
pci_release_regions(h->pdev);
@@ -7983,10 +8016,15 @@ clean_up:
static void hpsa_free_irqs(struct ctlr_info *h)
{
int i;
+ int irq_vector = 0;
+
+ if (hpsa_simple_mode)
+ irq_vector = h->intr_mode;
if (!h->msix_vectors || h->intr_mode != PERF_MODE_INT) {
/* Single reply queue, only one irq to free */
- free_irq(pci_irq_vector(h->pdev, 0), &h->q[h->intr_mode]);
+ free_irq(pci_irq_vector(h->pdev, irq_vector),
+ &h->q[h->intr_mode]);
h->q[h->intr_mode] = 0;
return;
}
@@ -8005,6 +8043,10 @@ static int hpsa_request_irqs(struct ctlr_info *h,
irqreturn_t (*intxhandler)(int, void *))
{
int rc, i;
+ int irq_vector = 0;
+
+ if (hpsa_simple_mode)
+ irq_vector = h->intr_mode;
/*
* initialize h->q[x] = x so that interrupt handlers know which
@@ -8040,14 +8082,14 @@ static int hpsa_request_irqs(struct ctlr_info *h,
if (h->msix_vectors > 0 || h->pdev->msi_enabled) {
sprintf(h->intrname[0], "%s-msi%s", h->devname,
h->msix_vectors ? "x" : "");
- rc = request_irq(pci_irq_vector(h->pdev, 0),
+ rc = request_irq(pci_irq_vector(h->pdev, irq_vector),
msixhandler, 0,
h->intrname[0],
&h->q[h->intr_mode]);
} else {
sprintf(h->intrname[h->intr_mode],
"%s-intx", h->devname);
- rc = request_irq(pci_irq_vector(h->pdev, 0),
+ rc = request_irq(pci_irq_vector(h->pdev, irq_vector),
intxhandler, IRQF_SHARED,
h->intrname[0],
&h->q[h->intr_mode]);
@@ -8055,7 +8097,7 @@ static int hpsa_request_irqs(struct ctlr_info *h,
}
if (rc) {
dev_err(&h->pdev->dev, "failed to get irq %d for %s\n",
- pci_irq_vector(h->pdev, 0), h->devname);
+ pci_irq_vector(h->pdev, irq_vector), h->devname);
hpsa_free_irqs(h);
return -ENODEV;
}
@@ -8065,7 +8107,7 @@ static int hpsa_request_irqs(struct ctlr_info *h,
static int hpsa_kdump_soft_reset(struct ctlr_info *h)
{
int rc;
- hpsa_send_host_reset(h, RAID_CTLR_LUNID, HPSA_RESET_TYPE_CONTROLLER);
+ hpsa_send_host_reset(h, HPSA_RESET_TYPE_CONTROLLER);
dev_info(&h->pdev->dev, "Waiting for board to soft reset.\n");
rc = hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_NOT_READY);
@@ -8121,6 +8163,11 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h)
destroy_workqueue(h->rescan_ctlr_wq);
h->rescan_ctlr_wq = NULL;
}
+ if (h->monitor_ctlr_wq) {
+ destroy_workqueue(h->monitor_ctlr_wq);
+ h->monitor_ctlr_wq = NULL;
+ }
+
kfree(h); /* init_one 1 */
}
@@ -8456,8 +8503,8 @@ static void hpsa_event_monitor_worker(struct work_struct *work)
spin_lock_irqsave(&h->lock, flags);
if (!h->remove_in_progress)
- schedule_delayed_work(&h->event_monitor_work,
- HPSA_EVENT_MONITOR_INTERVAL);
+ queue_delayed_work(h->monitor_ctlr_wq, &h->event_monitor_work,
+ HPSA_EVENT_MONITOR_INTERVAL);
spin_unlock_irqrestore(&h->lock, flags);
}
@@ -8502,7 +8549,7 @@ static void hpsa_monitor_ctlr_worker(struct work_struct *work)
spin_lock_irqsave(&h->lock, flags);
if (!h->remove_in_progress)
- schedule_delayed_work(&h->monitor_ctlr_work,
+ queue_delayed_work(h->monitor_ctlr_wq, &h->monitor_ctlr_work,
h->heartbeat_sample_interval);
spin_unlock_irqrestore(&h->lock, flags);
}
@@ -8670,6 +8717,12 @@ reinit_after_soft_reset:
goto clean7; /* aer/h */
}
+ h->monitor_ctlr_wq = hpsa_create_controller_wq(h, "monitor");
+ if (!h->monitor_ctlr_wq) {
+ rc = -ENOMEM;
+ goto clean7;
+ }
+
/*
* At this point, the controller is ready to take commands.
* Now, if reset_devices and the hard reset didn't work, try
@@ -8799,6 +8852,10 @@ clean1: /* wq/aer/h */
destroy_workqueue(h->rescan_ctlr_wq);
h->rescan_ctlr_wq = NULL;
}
+ if (h->monitor_ctlr_wq) {
+ destroy_workqueue(h->monitor_ctlr_wq);
+ h->monitor_ctlr_wq = NULL;
+ }
kfree(h);
return rc;
}
@@ -8946,6 +9003,7 @@ static void hpsa_remove_one(struct pci_dev *pdev)
cancel_delayed_work_sync(&h->event_monitor_work);
destroy_workqueue(h->rescan_ctlr_wq);
destroy_workqueue(h->resubmit_wq);
+ destroy_workqueue(h->monitor_ctlr_wq);
hpsa_delete_sas_host(h);
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 59e023696fff..f8c88fc7b80a 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -65,6 +65,7 @@ struct hpsa_scsi_dev_t {
u8 physical_device : 1;
u8 expose_device;
u8 removed : 1; /* device is marked for death */
+ u8 was_removed : 1; /* device actually removed */
#define RAID_CTLR_LUNID "\0\0\0\0\0\0\0\0"
unsigned char device_id[16]; /* from inquiry pg. 0x83 */
u64 sas_address;
@@ -75,11 +76,12 @@ struct hpsa_scsi_dev_t {
unsigned char raid_level; /* from inquiry page 0xC1 */
unsigned char volume_offline; /* discovered via TUR or VPD */
u16 queue_depth; /* max queue_depth for this device */
- atomic_t reset_cmds_out; /* Count of commands to-be affected */
+ atomic_t commands_outstanding; /* track commands sent to device */
atomic_t ioaccel_cmds_out; /* Only used for physical devices
* counts commands sent to physical
* device via "ioaccel" path.
*/
+ bool in_reset;
u32 ioaccel_handle;
u8 active_path_index;
u8 path_map;
@@ -174,6 +176,7 @@ struct ctlr_info {
struct CfgTable __iomem *cfgtable;
int interrupts_enabled;
int max_commands;
+ int last_collision_tag; /* tags are global */
atomic_t commands_outstanding;
# define PERF_MODE_INT 0
# define DOORBELL_INT 1
@@ -300,6 +303,7 @@ struct ctlr_info {
int needs_abort_tags_swizzled;
struct workqueue_struct *resubmit_wq;
struct workqueue_struct *rescan_ctlr_wq;
+ struct workqueue_struct *monitor_ctlr_wq;
atomic_t abort_cmds_available;
wait_queue_head_t event_sync_wait_queue;
struct mutex reset_mutex;
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index f6afca4b2319..7825cbfea4dc 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -448,7 +448,7 @@ struct CommandList {
struct hpsa_scsi_dev_t *phys_disk;
int abort_pending;
- struct hpsa_scsi_dev_t *reset_pending;
+ struct hpsa_scsi_dev_t *device;
atomic_t refcount; /* Must be last to avoid memset in hpsa_cmd_init() */
} __aligned(COMMANDLIST_ALIGNMENT);
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index 4aea97ee4b24..7f66a7783209 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -814,7 +814,7 @@ static void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata)
atomic_set(&hostdata->request_limit, 0);
purge_requests(hostdata, DID_ERROR);
- hostdata->reset_crq = 1;
+ hostdata->action = IBMVSCSI_HOST_ACTION_RESET;
wake_up(&hostdata->work_wait_q);
}
@@ -1165,7 +1165,8 @@ static void login_rsp(struct srp_event_struct *evt_struct)
be32_to_cpu(evt_struct->xfer_iu->srp.login_rsp.req_lim_delta));
/* If we had any pending I/Os, kick them */
- scsi_unblock_requests(hostdata->host);
+ hostdata->action = IBMVSCSI_HOST_ACTION_UNBLOCK;
+ wake_up(&hostdata->work_wait_q);
}
/**
@@ -1783,7 +1784,7 @@ static void ibmvscsi_handle_crq(struct viosrp_crq *crq,
/* We need to re-setup the interpartition connection */
dev_info(hostdata->dev, "Re-enabling adapter!\n");
hostdata->client_migrated = 1;
- hostdata->reenable_crq = 1;
+ hostdata->action = IBMVSCSI_HOST_ACTION_REENABLE;
purge_requests(hostdata, DID_REQUEUE);
wake_up(&hostdata->work_wait_q);
} else {
@@ -2036,6 +2037,16 @@ static struct device_attribute ibmvscsi_host_config = {
.show = show_host_config,
};
+static int ibmvscsi_host_reset(struct Scsi_Host *shost, int reset_type)
+{
+ struct ibmvscsi_host_data *hostdata = shost_priv(shost);
+
+ dev_info(hostdata->dev, "Initiating adapter reset!\n");
+ ibmvscsi_reset_host(hostdata);
+
+ return 0;
+}
+
static struct device_attribute *ibmvscsi_attrs[] = {
&ibmvscsi_host_vhost_loc,
&ibmvscsi_host_vhost_name,
@@ -2062,6 +2073,7 @@ static struct scsi_host_template driver_template = {
.eh_host_reset_handler = ibmvscsi_eh_host_reset_handler,
.slave_configure = ibmvscsi_slave_configure,
.change_queue_depth = ibmvscsi_change_queue_depth,
+ .host_reset = ibmvscsi_host_reset,
.cmd_per_lun = IBMVSCSI_CMDS_PER_LUN_DEFAULT,
.can_queue = IBMVSCSI_MAX_REQUESTS_DEFAULT,
.this_id = -1,
@@ -2091,48 +2103,75 @@ static unsigned long ibmvscsi_get_desired_dma(struct vio_dev *vdev)
static void ibmvscsi_do_work(struct ibmvscsi_host_data *hostdata)
{
+ unsigned long flags;
int rc;
char *action = "reset";
- if (hostdata->reset_crq) {
- smp_rmb();
- hostdata->reset_crq = 0;
-
+ spin_lock_irqsave(hostdata->host->host_lock, flags);
+ switch (hostdata->action) {
+ case IBMVSCSI_HOST_ACTION_UNBLOCK:
+ rc = 0;
+ break;
+ case IBMVSCSI_HOST_ACTION_RESET:
+ spin_unlock_irqrestore(hostdata->host->host_lock, flags);
rc = ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata);
+ spin_lock_irqsave(hostdata->host->host_lock, flags);
if (!rc)
rc = ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0);
vio_enable_interrupts(to_vio_dev(hostdata->dev));
- } else if (hostdata->reenable_crq) {
- smp_rmb();
+ break;
+ case IBMVSCSI_HOST_ACTION_REENABLE:
action = "enable";
+ spin_unlock_irqrestore(hostdata->host->host_lock, flags);
rc = ibmvscsi_reenable_crq_queue(&hostdata->queue, hostdata);
- hostdata->reenable_crq = 0;
+ spin_lock_irqsave(hostdata->host->host_lock, flags);
if (!rc)
rc = ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0);
- } else
+ break;
+ case IBMVSCSI_HOST_ACTION_NONE:
+ default:
+ spin_unlock_irqrestore(hostdata->host->host_lock, flags);
return;
+ }
+
+ hostdata->action = IBMVSCSI_HOST_ACTION_NONE;
if (rc) {
atomic_set(&hostdata->request_limit, -1);
dev_err(hostdata->dev, "error after %s\n", action);
}
+ spin_unlock_irqrestore(hostdata->host->host_lock, flags);
scsi_unblock_requests(hostdata->host);
}
-static int ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata)
+static int __ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata)
{
if (kthread_should_stop())
return 1;
- else if (hostdata->reset_crq) {
- smp_rmb();
- return 1;
- } else if (hostdata->reenable_crq) {
- smp_rmb();
- return 1;
+ switch (hostdata->action) {
+ case IBMVSCSI_HOST_ACTION_NONE:
+ return 0;
+ case IBMVSCSI_HOST_ACTION_RESET:
+ case IBMVSCSI_HOST_ACTION_REENABLE:
+ case IBMVSCSI_HOST_ACTION_UNBLOCK:
+ default:
+ break;
}
- return 0;
+ return 1;
+}
+
+static int ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata)
+{
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(hostdata->host->host_lock, flags);
+ rc = __ibmvscsi_work_to_do(hostdata);
+ spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+
+ return rc;
}
static int ibmvscsi_work(void *data)
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h
index 6ebd1410488d..e60916ef7a49 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.h
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.h
@@ -74,13 +74,19 @@ struct event_pool {
dma_addr_t iu_token;
};
+enum ibmvscsi_host_action {
+ IBMVSCSI_HOST_ACTION_NONE = 0,
+ IBMVSCSI_HOST_ACTION_RESET,
+ IBMVSCSI_HOST_ACTION_REENABLE,
+ IBMVSCSI_HOST_ACTION_UNBLOCK,
+};
+
/* all driver data associated with a host adapter */
struct ibmvscsi_host_data {
struct list_head host_list;
atomic_t request_limit;
int client_migrated;
- int reset_crq;
- int reenable_crq;
+ enum ibmvscsi_host_action action;
struct device *dev;
struct event_pool pool;
struct crq_queue queue;
diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c
index 9751309f8b8c..2519fb7aee51 100644
--- a/drivers/scsi/imm.c
+++ b/drivers/scsi/imm.c
@@ -687,7 +687,7 @@ static int imm_completion(struct scsi_cmnd *cmd)
if (cmd->SCp.buffer && !cmd->SCp.this_residual) {
/* if scatter/gather, advance to the next segment */
if (cmd->SCp.buffers_residual--) {
- cmd->SCp.buffer++;
+ cmd->SCp.buffer = sg_next(cmd->SCp.buffer);
cmd->SCp.this_residual =
cmd->SCp.buffer->length;
cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index d06bc1a817a1..079c04bc448a 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -3901,22 +3901,23 @@ static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist,
u8 *buffer, u32 len)
{
int bsize_elem, i, result = 0;
- struct scatterlist *scatterlist;
+ struct scatterlist *sg;
void *kaddr;
/* Determine the actual number of bytes per element */
bsize_elem = PAGE_SIZE * (1 << sglist->order);
- scatterlist = sglist->scatterlist;
+ sg = sglist->scatterlist;
- for (i = 0; i < (len / bsize_elem); i++, buffer += bsize_elem) {
- struct page *page = sg_page(&scatterlist[i]);
+ for (i = 0; i < (len / bsize_elem); i++, sg = sg_next(sg),
+ buffer += bsize_elem) {
+ struct page *page = sg_page(sg);
kaddr = kmap(page);
memcpy(kaddr, buffer, bsize_elem);
kunmap(page);
- scatterlist[i].length = bsize_elem;
+ sg->length = bsize_elem;
if (result != 0) {
ipr_trace;
@@ -3925,13 +3926,13 @@ static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist,
}
if (len % bsize_elem) {
- struct page *page = sg_page(&scatterlist[i]);
+ struct page *page = sg_page(sg);
kaddr = kmap(page);
memcpy(kaddr, buffer, len % bsize_elem);
kunmap(page);
- scatterlist[i].length = len % bsize_elem;
+ sg->length = len % bsize_elem;
}
sglist->buffer_len = len;
@@ -3952,6 +3953,7 @@ static void ipr_build_ucode_ioadl64(struct ipr_cmnd *ipr_cmd,
struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
struct ipr_ioadl64_desc *ioadl64 = ipr_cmd->i.ioadl64;
struct scatterlist *scatterlist = sglist->scatterlist;
+ struct scatterlist *sg;
int i;
ipr_cmd->dma_use_sg = sglist->num_dma_sg;
@@ -3960,10 +3962,10 @@ static void ipr_build_ucode_ioadl64(struct ipr_cmnd *ipr_cmd,
ioarcb->ioadl_len =
cpu_to_be32(sizeof(struct ipr_ioadl64_desc) * ipr_cmd->dma_use_sg);
- for (i = 0; i < ipr_cmd->dma_use_sg; i++) {
+ for_each_sg(scatterlist, sg, ipr_cmd->dma_use_sg, i) {
ioadl64[i].flags = cpu_to_be32(IPR_IOADL_FLAGS_WRITE);
- ioadl64[i].data_len = cpu_to_be32(sg_dma_len(&scatterlist[i]));
- ioadl64[i].address = cpu_to_be64(sg_dma_address(&scatterlist[i]));
+ ioadl64[i].data_len = cpu_to_be32(sg_dma_len(sg));
+ ioadl64[i].address = cpu_to_be64(sg_dma_address(sg));
}
ioadl64[i-1].flags |= cpu_to_be32(IPR_IOADL_FLAGS_LAST);
@@ -3983,6 +3985,7 @@ static void ipr_build_ucode_ioadl(struct ipr_cmnd *ipr_cmd,
struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
struct ipr_ioadl_desc *ioadl = ipr_cmd->i.ioadl;
struct scatterlist *scatterlist = sglist->scatterlist;
+ struct scatterlist *sg;
int i;
ipr_cmd->dma_use_sg = sglist->num_dma_sg;
@@ -3992,11 +3995,11 @@ static void ipr_build_ucode_ioadl(struct ipr_cmnd *ipr_cmd,
ioarcb->ioadl_len =
cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
- for (i = 0; i < ipr_cmd->dma_use_sg; i++) {
+ for_each_sg(scatterlist, sg, ipr_cmd->dma_use_sg, i) {
ioadl[i].flags_and_data_len =
- cpu_to_be32(IPR_IOADL_FLAGS_WRITE | sg_dma_len(&scatterlist[i]));
+ cpu_to_be32(IPR_IOADL_FLAGS_WRITE | sg_dma_len(sg));
ioadl[i].address =
- cpu_to_be32(sg_dma_address(&scatterlist[i]));
+ cpu_to_be32(sg_dma_address(sg));
}
ioadl[i-1].flags_and_data_len |=
diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index 9d29edb9f590..49aa4e657c44 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -1087,7 +1087,7 @@ static void sci_remote_device_ready_state_enter(struct sci_base_state_machine *s
if (dev->dev_type == SAS_SATA_DEV || (dev->tproto & SAS_PROTOCOL_SATA)) {
sci_change_state(&idev->sm, SCI_STP_DEV_IDLE);
- } else if (dev_is_expander(dev)) {
+ } else if (dev_is_expander(dev->dev_type)) {
sci_change_state(&idev->sm, SCI_SMP_DEV_IDLE);
} else
isci_remote_device_ready(ihost, idev);
@@ -1478,7 +1478,7 @@ static enum sci_status isci_remote_device_construct(struct isci_port *iport,
struct domain_device *dev = idev->domain_dev;
enum sci_status status;
- if (dev->parent && dev_is_expander(dev->parent))
+ if (dev->parent && dev_is_expander(dev->parent->dev_type))
status = sci_remote_device_ea_construct(iport, idev);
else
status = sci_remote_device_da_construct(iport, idev);
diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h
index 47a013fffae7..3ad681c4c20a 100644
--- a/drivers/scsi/isci/remote_device.h
+++ b/drivers/scsi/isci/remote_device.h
@@ -295,11 +295,6 @@ static inline struct isci_remote_device *rnc_to_dev(struct sci_remote_node_conte
return idev;
}
-static inline bool dev_is_expander(struct domain_device *dev)
-{
- return dev->dev_type == SAS_EDGE_EXPANDER_DEVICE || dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE;
-}
-
static inline void sci_remote_device_decrement_request_count(struct isci_remote_device *idev)
{
/* XXX delete this voodoo when converting to the top-level device
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index 1b18cf55167e..343d24c7e788 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -224,7 +224,7 @@ static void scu_ssp_request_construct_task_context(
idev = ireq->target_device;
iport = idev->owning_port;
- /* Fill in the TC with the its required data */
+ /* Fill in the TC with its required data */
task_context->abort = 0;
task_context->priority = 0;
task_context->initiator_request = 1;
@@ -506,7 +506,7 @@ static void scu_sata_request_construct_task_context(
idev = ireq->target_device;
iport = idev->owning_port;
- /* Fill in the TC with the its required data */
+ /* Fill in the TC with its required data */
task_context->abort = 0;
task_context->priority = SCU_TASK_PRIORITY_NORMAL;
task_context->initiator_request = 1;
@@ -3101,7 +3101,7 @@ sci_io_request_construct(struct isci_host *ihost,
/* pass */;
else if (dev_is_sata(dev))
memset(&ireq->stp.cmd, 0, sizeof(ireq->stp.cmd));
- else if (dev_is_expander(dev))
+ else if (dev_is_expander(dev->dev_type))
/* pass */;
else
return SCI_FAILURE_UNSUPPORTED_PROTOCOL;
@@ -3235,7 +3235,7 @@ sci_io_request_construct_smp(struct device *dev,
iport = idev->owning_port;
/*
- * Fill in the TC with the its required data
+ * Fill in the TC with its required data
* 00h
*/
task_context->priority = 0;
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c
index fb6eba331ac6..26fa1a4d1e6b 100644
--- a/drivers/scsi/isci/task.c
+++ b/drivers/scsi/isci/task.c
@@ -511,7 +511,7 @@ int isci_task_abort_task(struct sas_task *task)
"%s: dev = %p (%s%s), task = %p, old_request == %p\n",
__func__, idev,
(dev_is_sata(task->dev) ? "STP/SATA"
- : ((dev_is_expander(task->dev))
+ : ((dev_is_expander(task->dev->dev_type))
? "SMP"
: "SSP")),
((idev) ? ((test_bit(IDEV_GONE, &idev->flags))
diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c
index 719e57685dd5..6ef93c7af954 100644
--- a/drivers/scsi/libiscsi_tcp.c
+++ b/drivers/scsi/libiscsi_tcp.c
@@ -8,8 +8,6 @@
* Copyright (C) 2006 Red Hat, Inc. All rights reserved.
* maintained by open-iscsi@googlegroups.com
*
- * See the file COPYING included with this distribution for more details.
- *
* Credits:
* Christoph Hellwig
* FUJITA Tomonori
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
index 726ada9b8c79..abcad097ff2f 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -1,25 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Serial Attached SCSI (SAS) Discover process
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
- *
- * This file is licensed under GPLv2.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#include <linux/scatterlist.h>
@@ -309,7 +293,7 @@ void sas_free_device(struct kref *kref)
dev->phy = NULL;
/* remove the phys and ports, everything else should be gone */
- if (dev->dev_type == SAS_EDGE_EXPANDER_DEVICE || dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE)
+ if (dev_is_expander(dev->dev_type))
kfree(dev->ex_dev.ex_phy);
if (dev_is_sata(dev) && dev->sata_dev.ap) {
@@ -519,8 +503,7 @@ static void sas_revalidate_domain(struct work_struct *work)
pr_debug("REVALIDATING DOMAIN on port %d, pid:%d\n", port->id,
task_pid_nr(current));
- if (ddev && (ddev->dev_type == SAS_FANOUT_EXPANDER_DEVICE ||
- ddev->dev_type == SAS_EDGE_EXPANDER_DEVICE))
+ if (ddev && dev_is_expander(ddev->dev_type))
res = sas_ex_revalidate_domain(ddev);
pr_debug("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n",
diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c
index b1e0f7d2b396..a1852f6c042b 100644
--- a/drivers/scsi/libsas/sas_event.c
+++ b/drivers/scsi/libsas/sas_event.c
@@ -1,25 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Serial Attached SCSI (SAS) Event processing
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
- *
- * This file is licensed under GPLv2.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#include <linux/export.h>
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 9f7e2457360e..9fdb9c9fbda4 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Serial Attached SCSI (SAS) Expander discovery and configuration
*
@@ -5,21 +6,6 @@
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
*
* This file is licensed under GPLv2.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#include <linux/scatterlist.h>
@@ -1106,7 +1092,7 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id)
SAS_ADDR(dev->sas_addr),
phy_id);
sas_ex_disable_phy(dev, phy_id);
- break;
+ return res;
} else
memcpy(dev->port->disc.fanout_sas_addr,
ex_phy->attached_sas_addr, SAS_ADDR_SIZE);
@@ -1118,27 +1104,9 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id)
break;
}
- if (child) {
- int i;
-
- for (i = 0; i < ex->num_phys; i++) {
- if (ex->ex_phy[i].phy_state == PHY_VACANT ||
- ex->ex_phy[i].phy_state == PHY_NOT_PRESENT)
- continue;
- /*
- * Due to races, the phy might not get added to the
- * wide port, so we add the phy to the wide port here.
- */
- if (SAS_ADDR(ex->ex_phy[i].attached_sas_addr) ==
- SAS_ADDR(child->sas_addr)) {
- ex->ex_phy[i].phy_state= PHY_DEVICE_DISCOVERED;
- if (sas_ex_join_wide_port(dev, i))
- pr_debug("Attaching ex phy%02d to wide port %016llx\n",
- i, SAS_ADDR(ex->ex_phy[i].attached_sas_addr));
- }
- }
- }
-
+ if (!child)
+ pr_notice("ex %016llx phy%02d failed to discover\n",
+ SAS_ADDR(dev->sas_addr), phy_id);
return res;
}
@@ -1154,8 +1122,7 @@ static int sas_find_sub_addr(struct domain_device *dev, u8 *sub_addr)
phy->phy_state == PHY_NOT_PRESENT)
continue;
- if ((phy->attached_dev_type == SAS_EDGE_EXPANDER_DEVICE ||
- phy->attached_dev_type == SAS_FANOUT_EXPANDER_DEVICE) &&
+ if (dev_is_expander(phy->attached_dev_type) &&
phy->routing_attr == SUBTRACTIVE_ROUTING) {
memcpy(sub_addr, phy->attached_sas_addr, SAS_ADDR_SIZE);
@@ -1173,8 +1140,7 @@ static int sas_check_level_subtractive_boundary(struct domain_device *dev)
u8 sub_addr[SAS_ADDR_SIZE] = {0, };
list_for_each_entry(child, &ex->children, siblings) {
- if (child->dev_type != SAS_EDGE_EXPANDER_DEVICE &&
- child->dev_type != SAS_FANOUT_EXPANDER_DEVICE)
+ if (!dev_is_expander(child->dev_type))
continue;
if (sub_addr[0] == 0) {
sas_find_sub_addr(child, sub_addr);
@@ -1259,8 +1225,7 @@ static int sas_check_ex_subtractive_boundary(struct domain_device *dev)
phy->phy_state == PHY_NOT_PRESENT)
continue;
- if ((phy->attached_dev_type == SAS_FANOUT_EXPANDER_DEVICE ||
- phy->attached_dev_type == SAS_EDGE_EXPANDER_DEVICE) &&
+ if (dev_is_expander(phy->attached_dev_type) &&
phy->routing_attr == SUBTRACTIVE_ROUTING) {
if (!sub_sas_addr)
@@ -1356,8 +1321,7 @@ static int sas_check_parent_topology(struct domain_device *child)
if (!child->parent)
return 0;
- if (child->parent->dev_type != SAS_EDGE_EXPANDER_DEVICE &&
- child->parent->dev_type != SAS_FANOUT_EXPANDER_DEVICE)
+ if (!dev_is_expander(child->parent->dev_type))
return 0;
parent_ex = &child->parent->ex_dev;
@@ -1653,8 +1617,7 @@ static int sas_ex_level_discovery(struct asd_sas_port *port, const int level)
struct domain_device *dev;
list_for_each_entry(dev, &port->dev_list, dev_list_node) {
- if (dev->dev_type == SAS_EDGE_EXPANDER_DEVICE ||
- dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE) {
+ if (dev_is_expander(dev->dev_type)) {
struct sas_expander_device *ex =
rphy_to_expander_device(dev->rphy);
@@ -1886,7 +1849,7 @@ static int sas_find_bcast_dev(struct domain_device *dev,
SAS_ADDR(dev->sas_addr));
}
list_for_each_entry(ch, &ex->children, siblings) {
- if (ch->dev_type == SAS_EDGE_EXPANDER_DEVICE || ch->dev_type == SAS_FANOUT_EXPANDER_DEVICE) {
+ if (dev_is_expander(ch->dev_type)) {
res = sas_find_bcast_dev(ch, src_dev);
if (*src_dev)
return res;
@@ -1903,8 +1866,7 @@ static void sas_unregister_ex_tree(struct asd_sas_port *port, struct domain_devi
list_for_each_entry_safe(child, n, &ex->children, siblings) {
set_bit(SAS_DEV_GONE, &child->state);
- if (child->dev_type == SAS_EDGE_EXPANDER_DEVICE ||
- child->dev_type == SAS_FANOUT_EXPANDER_DEVICE)
+ if (dev_is_expander(child->dev_type))
sas_unregister_ex_tree(port, child);
else
sas_unregister_dev(port, child);
@@ -1924,8 +1886,7 @@ static void sas_unregister_devs_sas_addr(struct domain_device *parent,
if (SAS_ADDR(child->sas_addr) ==
SAS_ADDR(phy->attached_sas_addr)) {
set_bit(SAS_DEV_GONE, &child->state);
- if (child->dev_type == SAS_EDGE_EXPANDER_DEVICE ||
- child->dev_type == SAS_FANOUT_EXPANDER_DEVICE)
+ if (dev_is_expander(child->dev_type))
sas_unregister_ex_tree(parent->port, child);
else
sas_unregister_dev(parent->port, child);
@@ -1954,8 +1915,7 @@ static int sas_discover_bfs_by_root_level(struct domain_device *root,
int res = 0;
list_for_each_entry(child, &ex_root->children, siblings) {
- if (child->dev_type == SAS_EDGE_EXPANDER_DEVICE ||
- child->dev_type == SAS_FANOUT_EXPANDER_DEVICE) {
+ if (dev_is_expander(child->dev_type)) {
struct sas_expander_device *ex =
rphy_to_expander_device(child->rphy);
@@ -2008,8 +1968,7 @@ static int sas_discover_new(struct domain_device *dev, int phy_id)
list_for_each_entry(child, &dev->ex_dev.children, siblings) {
if (SAS_ADDR(child->sas_addr) ==
SAS_ADDR(ex_phy->attached_sas_addr)) {
- if (child->dev_type == SAS_EDGE_EXPANDER_DEVICE ||
- child->dev_type == SAS_FANOUT_EXPANDER_DEVICE)
+ if (dev_is_expander(child->dev_type))
res = sas_discover_bfs_by_root(child);
break;
}
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
index d50810da53a9..21c43b18d5d5 100644
--- a/drivers/scsi/libsas/sas_init.c
+++ b/drivers/scsi/libsas/sas_init.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Serial Attached SCSI (SAS) Transport Layer initialization
*
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index 1f1e07e98477..01f1738ce6df 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Serial Attached SCSI (SAS) class internal header file
*
diff --git a/drivers/scsi/libsas/sas_phy.c b/drivers/scsi/libsas/sas_phy.c
index b71f5ac6c7dc..4ca4b1f30bd0 100644
--- a/drivers/scsi/libsas/sas_phy.c
+++ b/drivers/scsi/libsas/sas_phy.c
@@ -1,25 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Serial Attached SCSI (SAS) Phy class
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
- *
- * This file is licensed under GPLv2.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#include "sas_internal.h"
diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c
index 38a10478605c..7c86fd248129 100644
--- a/drivers/scsi/libsas/sas_port.c
+++ b/drivers/scsi/libsas/sas_port.c
@@ -1,25 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Serial Attached SCSI (SAS) Port class
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
- *
- * This file is licensed under GPLv2.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#include "sas_internal.h"
@@ -70,7 +54,7 @@ static void sas_resume_port(struct asd_sas_phy *phy)
continue;
}
- if (dev->dev_type == SAS_EDGE_EXPANDER_DEVICE || dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE) {
+ if (dev_is_expander(dev->dev_type)) {
dev->ex_dev.ex_change_count = -1;
for (i = 0; i < dev->ex_dev.num_phys; i++) {
struct ex_phy *phy = &dev->ex_dev.ex_phy[i];
@@ -195,7 +179,7 @@ static void sas_form_port(struct asd_sas_phy *phy)
sas_discover_event(phy->port, DISCE_DISCOVER_DOMAIN);
/* Only insert a revalidate event after initial discovery */
- if (port_dev && sas_dev_type_is_expander(port_dev->dev_type)) {
+ if (port_dev && dev_is_expander(port_dev->dev_type)) {
struct expander_device *ex_dev = &port_dev->ex_dev;
ex_dev->ex_change_count = -1;
@@ -264,7 +248,7 @@ void sas_deform_port(struct asd_sas_phy *phy, int gone)
spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags);
/* Only insert revalidate event if the port still has members */
- if (port->port && dev && sas_dev_type_is_expander(dev->dev_type)) {
+ if (port->port && dev && dev_is_expander(dev->dev_type)) {
struct expander_device *ex_dev = &dev->ex_dev;
ex_dev->ex_change_count = -1;
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index ede0674d8399..4f339f939a51 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Serial Attached SCSI (SAS) class SCSI Host glue.
*
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index aafcffaa25f7..2c3bb8a966e5 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -274,6 +274,7 @@ struct lpfc_stats {
uint32_t elsXmitADISC;
uint32_t elsXmitLOGO;
uint32_t elsXmitSCR;
+ uint32_t elsXmitRSCN;
uint32_t elsXmitRNID;
uint32_t elsXmitFARP;
uint32_t elsXmitFARPR;
@@ -819,6 +820,7 @@ struct lpfc_hba {
uint32_t cfg_use_msi;
uint32_t cfg_auto_imax;
uint32_t cfg_fcp_imax;
+ uint32_t cfg_force_rscn;
uint32_t cfg_cq_poll_threshold;
uint32_t cfg_cq_max_proc_limit;
uint32_t cfg_fcp_cpu_map;
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index d4c65e2109e2..ea62322ffe2b 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -4097,9 +4097,9 @@ lpfc_topology_store(struct device *dev, struct device_attribute *attr,
}
if ((phba->pcidev->device == PCI_DEVICE_ID_LANCER_G6_FC ||
phba->pcidev->device == PCI_DEVICE_ID_LANCER_G7_FC) &&
- val != FLAGS_TOPOLOGY_MODE_PT_PT) {
+ val == 4) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
- "3114 Only non-FC-AL mode is supported\n");
+ "3114 Loop mode not supported\n");
return -EINVAL;
}
phba->cfg_topology = val;
@@ -4959,6 +4959,64 @@ static DEVICE_ATTR(lpfc_req_fw_upgrade, S_IRUGO | S_IWUSR,
lpfc_request_firmware_upgrade_store);
/**
+ * lpfc_force_rscn_store
+ *
+ * @dev: class device that is converted into a Scsi_host.
+ * @attr: device attribute, not used.
+ * @buf: unused string
+ * @count: unused variable.
+ *
+ * Description:
+ * Force the switch to send a RSCN to all other NPorts in our zone
+ * If we are direct connect pt2pt, build the RSCN command ourself
+ * and send to the other NPort. Not supported for private loop.
+ *
+ * Returns:
+ * 0 - on success
+ * -EIO - if command is not sent
+ **/
+static ssize_t
+lpfc_force_rscn_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata;
+ int i;
+
+ i = lpfc_issue_els_rscn(vport, 0);
+ if (i)
+ return -EIO;
+ return strlen(buf);
+}
+
+/*
+ * lpfc_force_rscn: Force an RSCN to be sent to all remote NPorts
+ * connected to the HBA.
+ *
+ * Value range is any ascii value
+ */
+static int lpfc_force_rscn;
+module_param(lpfc_force_rscn, int, 0644);
+MODULE_PARM_DESC(lpfc_force_rscn,
+ "Force an RSCN to be sent to all remote NPorts");
+lpfc_param_show(force_rscn)
+
+/**
+ * lpfc_force_rscn_init - Force an RSCN to be sent to all remote NPorts
+ * @phba: lpfc_hba pointer.
+ * @val: unused value.
+ *
+ * Returns:
+ * zero if val saved.
+ **/
+static int
+lpfc_force_rscn_init(struct lpfc_hba *phba, int val)
+{
+ return 0;
+}
+static DEVICE_ATTR_RW(lpfc_force_rscn);
+
+/**
* lpfc_fcp_imax_store
*
* @dev: class device that is converted into a Scsi_host.
@@ -5122,7 +5180,8 @@ lpfc_cq_max_proc_limit_store(struct device *dev, struct device_attribute *attr,
/* set the values on the cq's */
for (i = 0; i < phba->cfg_irq_chann; i++) {
- eq = phba->sli4_hba.hdwq[i].hba_eq;
+ /* Get the EQ corresponding to the IRQ vector */
+ eq = phba->sli4_hba.hba_eq_hdl[i].eq;
if (!eq)
continue;
@@ -5243,35 +5302,44 @@ lpfc_fcp_cpu_map_show(struct device *dev, struct device_attribute *attr,
len += scnprintf(
buf + len, PAGE_SIZE - len,
"CPU %02d hdwq None "
- "physid %d coreid %d ht %d\n",
+ "physid %d coreid %d ht %d ua %d\n",
phba->sli4_hba.curr_disp_cpu,
- cpup->phys_id,
- cpup->core_id, cpup->hyper);
+ cpup->phys_id, cpup->core_id,
+ (cpup->flag & LPFC_CPU_MAP_HYPER),
+ (cpup->flag & LPFC_CPU_MAP_UNASSIGN));
else
len += scnprintf(
buf + len, PAGE_SIZE - len,
"CPU %02d EQ %04d hdwq %04d "
- "physid %d coreid %d ht %d\n",
+ "physid %d coreid %d ht %d ua %d\n",
phba->sli4_hba.curr_disp_cpu,
cpup->eq, cpup->hdwq, cpup->phys_id,
- cpup->core_id, cpup->hyper);
+ cpup->core_id,
+ (cpup->flag & LPFC_CPU_MAP_HYPER),
+ (cpup->flag & LPFC_CPU_MAP_UNASSIGN));
} else {
if (cpup->hdwq == LPFC_VECTOR_MAP_EMPTY)
len += scnprintf(
buf + len, PAGE_SIZE - len,
"CPU %02d hdwq None "
- "physid %d coreid %d ht %d IRQ %d\n",
+ "physid %d coreid %d ht %d ua %d IRQ %d\n",
phba->sli4_hba.curr_disp_cpu,
cpup->phys_id,
- cpup->core_id, cpup->hyper, cpup->irq);
+ cpup->core_id,
+ (cpup->flag & LPFC_CPU_MAP_HYPER),
+ (cpup->flag & LPFC_CPU_MAP_UNASSIGN),
+ cpup->irq);
else
len += scnprintf(
buf + len, PAGE_SIZE - len,
"CPU %02d EQ %04d hdwq %04d "
- "physid %d coreid %d ht %d IRQ %d\n",
+ "physid %d coreid %d ht %d ua %d IRQ %d\n",
phba->sli4_hba.curr_disp_cpu,
cpup->eq, cpup->hdwq, cpup->phys_id,
- cpup->core_id, cpup->hyper, cpup->irq);
+ cpup->core_id,
+ (cpup->flag & LPFC_CPU_MAP_HYPER),
+ (cpup->flag & LPFC_CPU_MAP_UNASSIGN),
+ cpup->irq);
}
phba->sli4_hba.curr_disp_cpu++;
@@ -5958,6 +6026,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_lpfc_nvme_oas,
&dev_attr_lpfc_nvme_embed_cmd,
&dev_attr_lpfc_fcp_imax,
+ &dev_attr_lpfc_force_rscn,
&dev_attr_lpfc_cq_poll_threshold,
&dev_attr_lpfc_cq_max_proc_limit,
&dev_attr_lpfc_fcp_cpu_map,
@@ -7005,6 +7074,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_nvme_oas_init(phba, lpfc_nvme_oas);
lpfc_nvme_embed_cmd_init(phba, lpfc_nvme_embed_cmd);
lpfc_fcp_imax_init(phba, lpfc_fcp_imax);
+ lpfc_force_rscn_init(phba, lpfc_force_rscn);
lpfc_cq_poll_threshold_init(phba, lpfc_cq_poll_threshold);
lpfc_cq_max_proc_limit_init(phba, lpfc_cq_max_proc_limit);
lpfc_fcp_cpu_map_init(phba, lpfc_fcp_cpu_map);
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c
index b0202bc0aa62..b7216d694bff 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.c
+++ b/drivers/scsi/lpfc/lpfc_bsg.c
@@ -5741,7 +5741,7 @@ lpfc_get_trunk_info(struct bsg_job *job)
event_reply->port_speed = phba->sli4_hba.link_state.speed / 1000;
event_reply->logical_speed =
- phba->sli4_hba.link_state.logical_speed / 100;
+ phba->sli4_hba.link_state.logical_speed / 1000;
job_error:
bsg_reply->result = rc;
bsg_job_done(job, bsg_reply->result,
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index e0b14d791b8c..68e9f96242d3 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -141,6 +141,7 @@ int lpfc_issue_els_adisc(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
int lpfc_issue_els_logo(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
int lpfc_issue_els_npiv_logo(struct lpfc_vport *, struct lpfc_nodelist *);
int lpfc_issue_els_scr(struct lpfc_vport *, uint32_t, uint8_t);
+int lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry);
int lpfc_issue_fabric_reglogin(struct lpfc_vport *);
int lpfc_els_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
int lpfc_ct_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
@@ -355,6 +356,7 @@ void lpfc_mbox_timeout_handler(struct lpfc_hba *);
struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_vport *, uint32_t);
struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_vport *,
struct lpfc_name *);
+struct lpfc_nodelist *lpfc_findnode_mapped(struct lpfc_vport *vport);
int lpfc_sli_issue_mbox_wait(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
@@ -555,6 +557,8 @@ void lpfc_ras_stop_fwlog(struct lpfc_hba *phba);
int lpfc_check_fwlog_support(struct lpfc_hba *phba);
/* NVME interfaces. */
+void lpfc_nvme_rescan_port(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp);
void lpfc_nvme_unregister_port(struct lpfc_vport *vport,
struct lpfc_nodelist *ndlp);
int lpfc_nvme_register_port(struct lpfc_vport *vport,
@@ -568,7 +572,8 @@ void lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba);
void lpfc_nvmet_unsol_ls_event(struct lpfc_hba *phba,
struct lpfc_sli_ring *pring, struct lpfc_iocbq *piocb);
void lpfc_nvmet_unsol_fcp_event(struct lpfc_hba *phba, uint32_t idx,
- struct rqb_dmabuf *nvmebuf, uint64_t isr_ts);
+ struct rqb_dmabuf *nvmebuf, uint64_t isr_ts,
+ uint8_t cqflag);
void lpfc_nvme_mod_param_dep(struct lpfc_hba *phba);
void lpfc_nvme_abort_fcreq_cmpl(struct lpfc_hba *phba,
struct lpfc_iocbq *cmdiocb,
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index 4812bbbf43cc..ec72c39997d2 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -2358,6 +2358,7 @@ static int
lpfc_fdmi_port_attr_fc4type(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_fdmi_attr_entry *ae;
uint32_t size;
@@ -2366,9 +2367,13 @@ lpfc_fdmi_port_attr_fc4type(struct lpfc_vport *vport,
ae->un.AttrTypes[3] = 0x02; /* Type 0x1 - ELS */
ae->un.AttrTypes[2] = 0x01; /* Type 0x8 - FCP */
- if (vport->nvmei_support || vport->phba->nvmet_support)
- ae->un.AttrTypes[6] = 0x01; /* Type 0x28 - NVME */
ae->un.AttrTypes[7] = 0x01; /* Type 0x20 - CT */
+
+ /* Check to see if Firmware supports NVME and on physical port */
+ if ((phba->sli_rev == LPFC_SLI_REV4) && (vport == phba->pport) &&
+ phba->sli4_hba.pc_sli4_params.nvme)
+ ae->un.AttrTypes[6] = 0x01; /* Type 0x28 - NVME */
+
size = FOURBYTES + 32;
ad->AttrLen = cpu_to_be16(size);
ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_FC4_TYPES);
@@ -2680,9 +2685,12 @@ lpfc_fdmi_port_attr_active_fc4type(struct lpfc_vport *vport,
ae->un.AttrTypes[3] = 0x02; /* Type 0x1 - ELS */
ae->un.AttrTypes[2] = 0x01; /* Type 0x8 - FCP */
+ ae->un.AttrTypes[7] = 0x01; /* Type 0x20 - CT */
+
+ /* Check to see if NVME is configured or not */
if (vport->phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME)
ae->un.AttrTypes[6] = 0x1; /* Type 0x28 - NVME */
- ae->un.AttrTypes[7] = 0x01; /* Type 0x20 - CT */
+
size = FOURBYTES + 32;
ad->AttrLen = cpu_to_be16(size);
ad->AttrType = cpu_to_be16(RPRT_ACTIVE_FC4_TYPES);
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 5ac4f8d76b91..f12780f4cfbb 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -30,6 +30,8 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport_fc.h>
+#include <uapi/scsi/fc/fc_fs.h>
+#include <uapi/scsi/fc/fc_els.h>
#include "lpfc_hw4.h"
#include "lpfc_hw.h"
@@ -3079,6 +3081,116 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
}
/**
+ * lpfc_issue_els_rscn - Issue an RSCN to the Fabric Controller (Fabric)
+ * or the other nport (pt2pt).
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @retry: number of retries to the command IOCB.
+ *
+ * This routine issues a RSCN to the Fabric Controller (DID 0xFFFFFD)
+ * when connected to a fabric, or to the remote port when connected
+ * in point-to-point mode. When sent to the Fabric Controller, it will
+ * replay the RSCN to registered recipients.
+ *
+ * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp
+ * will be incremented by 1 for holding the ndlp and the reference to ndlp
+ * will be stored into the context1 field of the IOCB for the completion
+ * callback function to the RSCN ELS command.
+ *
+ * Return code
+ * 0 - Successfully issued RSCN command
+ * 1 - Failed to issue RSCN command
+ **/
+int
+lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_iocbq *elsiocb;
+ struct lpfc_nodelist *ndlp;
+ struct {
+ struct fc_els_rscn rscn;
+ struct fc_els_rscn_page portid;
+ } *event;
+ uint32_t nportid;
+ uint16_t cmdsize = sizeof(*event);
+
+ /* Not supported for private loop */
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP &&
+ !(vport->fc_flag & FC_PUBLIC_LOOP))
+ return 1;
+
+ if (vport->fc_flag & FC_PT2PT) {
+ /* find any mapped nport - that would be the other nport */
+ ndlp = lpfc_findnode_mapped(vport);
+ if (!ndlp)
+ return 1;
+ } else {
+ nportid = FC_FID_FCTRL;
+ /* find the fabric controller node */
+ ndlp = lpfc_findnode_did(vport, nportid);
+ if (!ndlp) {
+ /* if one didn't exist, make one */
+ ndlp = lpfc_nlp_init(vport, nportid);
+ if (!ndlp)
+ return 1;
+ lpfc_enqueue_node(vport, ndlp);
+ } else if (!NLP_CHK_NODE_ACT(ndlp)) {
+ ndlp = lpfc_enable_node(vport, ndlp,
+ NLP_STE_UNUSED_NODE);
+ if (!ndlp)
+ return 1;
+ }
+ }
+
+ elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
+ ndlp->nlp_DID, ELS_CMD_RSCN_XMT);
+
+ if (!elsiocb) {
+ /* This will trigger the release of the node just
+ * allocated
+ */
+ lpfc_nlp_put(ndlp);
+ return 1;
+ }
+
+ event = ((struct lpfc_dmabuf *)elsiocb->context2)->virt;
+
+ event->rscn.rscn_cmd = ELS_RSCN;
+ event->rscn.rscn_page_len = sizeof(struct fc_els_rscn_page);
+ event->rscn.rscn_plen = cpu_to_be16(cmdsize);
+
+ nportid = vport->fc_myDID;
+ /* appears that page flags must be 0 for fabric to broadcast RSCN */
+ event->portid.rscn_page_flags = 0;
+ event->portid.rscn_fid[0] = (nportid & 0x00FF0000) >> 16;
+ event->portid.rscn_fid[1] = (nportid & 0x0000FF00) >> 8;
+ event->portid.rscn_fid[2] = nportid & 0x000000FF;
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "Issue RSCN: did:x%x",
+ ndlp->nlp_DID, 0, 0);
+
+ phba->fc_stat.elsXmitRSCN++;
+ elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
+ if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) ==
+ IOCB_ERROR) {
+ /* The additional lpfc_nlp_put will cause the following
+ * lpfc_els_free_iocb routine to trigger the rlease of
+ * the node.
+ */
+ lpfc_nlp_put(ndlp);
+ lpfc_els_free_iocb(phba, elsiocb);
+ return 1;
+ }
+ /* This will cause the callback-function lpfc_cmpl_els_cmd to
+ * trigger the release of node.
+ */
+ if (!(vport->fc_flag & FC_PT2PT))
+ lpfc_nlp_put(ndlp);
+
+ return 0;
+}
+
+/**
* lpfc_issue_els_farpr - Issue a farp to an node on a vport
* @vport: pointer to a host virtual N_Port data structure.
* @nportid: N_Port identifier to the remote node.
@@ -4196,6 +4308,7 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
if ((rspiocb->iocb.ulpStatus == 0)
&& (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) {
if (!lpfc_unreg_rpi(vport, ndlp) &&
+ (!(vport->fc_flag & FC_PT2PT)) &&
(ndlp->nlp_state == NLP_STE_PLOGI_ISSUE ||
ndlp->nlp_state == NLP_STE_REG_LOGIN_ISSUE)) {
lpfc_printf_vlog(vport, KERN_INFO,
@@ -6214,6 +6327,8 @@ lpfc_rscn_recovery_check(struct lpfc_vport *vport)
continue;
}
+ if (ndlp->nlp_fc4_type & NLP_FC4_NVME)
+ lpfc_nvme_rescan_port(vport, ndlp);
lpfc_disc_state_machine(vport, ndlp, NULL,
NLP_EVT_DEVICE_RECOVERY);
@@ -6318,6 +6433,19 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
fc_host_post_event(shost, fc_get_event_number(),
FCH_EVT_RSCN, lp[i]);
+ /* Check if RSCN is coming from a direct-connected remote NPort */
+ if (vport->fc_flag & FC_PT2PT) {
+ /* If so, just ACC it, no other action needed for now */
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "2024 pt2pt RSCN %08x Data: x%x x%x\n",
+ *lp, vport->fc_flag, payload_len);
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
+
+ if (ndlp->nlp_fc4_type & NLP_FC4_NVME)
+ lpfc_nvme_rescan_port(vport, ndlp);
+ return 0;
+ }
+
/* If we are about to begin discovery, just ACC the RSCN.
* Discovery processing will satisfy it.
*/
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index c43852f97f25..28ecaa7fc715 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -5277,6 +5277,41 @@ lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did)
}
struct lpfc_nodelist *
+lpfc_findnode_mapped(struct lpfc_vport *vport)
+{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_nodelist *ndlp;
+ uint32_t data1;
+ unsigned long iflags;
+
+ spin_lock_irqsave(shost->host_lock, iflags);
+
+ list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
+ if (ndlp->nlp_state == NLP_STE_UNMAPPED_NODE ||
+ ndlp->nlp_state == NLP_STE_MAPPED_NODE) {
+ data1 = (((uint32_t)ndlp->nlp_state << 24) |
+ ((uint32_t)ndlp->nlp_xri << 16) |
+ ((uint32_t)ndlp->nlp_type << 8) |
+ ((uint32_t)ndlp->nlp_rpi & 0xff));
+ spin_unlock_irqrestore(shost->host_lock, iflags);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
+ "2025 FIND node DID "
+ "Data: x%p x%x x%x x%x %p\n",
+ ndlp, ndlp->nlp_DID,
+ ndlp->nlp_flag, data1,
+ ndlp->active_rrqs_xri_bitmap);
+ return ndlp;
+ }
+ }
+ spin_unlock_irqrestore(shost->host_lock, iflags);
+
+ /* FIND node did <did> NOT FOUND */
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
+ "2026 FIND mapped did NOT FOUND.\n");
+ return NULL;
+}
+
+struct lpfc_nodelist *
lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did)
{
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index edd8f3982023..5b439a6dcde1 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -601,6 +601,7 @@ struct fc_vft_header {
#define ELS_CMD_RPL 0x57000000
#define ELS_CMD_FAN 0x60000000
#define ELS_CMD_RSCN 0x61040000
+#define ELS_CMD_RSCN_XMT 0x61040008
#define ELS_CMD_SCR 0x62000000
#define ELS_CMD_RNID 0x78000000
#define ELS_CMD_LIRR 0x7A000000
@@ -642,6 +643,7 @@ struct fc_vft_header {
#define ELS_CMD_RPL 0x57
#define ELS_CMD_FAN 0x60
#define ELS_CMD_RSCN 0x0461
+#define ELS_CMD_RSCN_XMT 0x08000461
#define ELS_CMD_SCR 0x62
#define ELS_CMD_RNID 0x78
#define ELS_CMD_LIRR 0x7A
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index eaaef682de25..faf43b1d3dbe 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -72,7 +72,7 @@ unsigned long _dump_buf_dif_order;
spinlock_t _dump_buf_lock;
/* Used when mapping IRQ vectors in a driver centric manner */
-uint32_t lpfc_present_cpu;
+static uint32_t lpfc_present_cpu;
static void lpfc_get_hba_model_desc(struct lpfc_hba *, uint8_t *, uint8_t *);
static int lpfc_post_rcv_buf(struct lpfc_hba *);
@@ -93,8 +93,8 @@ static void lpfc_sli4_cq_event_release_all(struct lpfc_hba *);
static void lpfc_sli4_disable_intr(struct lpfc_hba *);
static uint32_t lpfc_sli4_enable_intr(struct lpfc_hba *, uint32_t);
static void lpfc_sli4_oas_verify(struct lpfc_hba *phba);
-static uint16_t lpfc_find_eq_handle(struct lpfc_hba *, uint16_t);
static uint16_t lpfc_find_cpu_handle(struct lpfc_hba *, uint16_t, int);
+static void lpfc_setup_bg(struct lpfc_hba *, struct Scsi_Host *);
static struct scsi_transport_template *lpfc_transport_template = NULL;
static struct scsi_transport_template *lpfc_vport_transport_template = NULL;
@@ -1274,8 +1274,10 @@ lpfc_hb_eq_delay_work(struct work_struct *work)
if (!eqcnt)
goto requeue;
+ /* Loop thru all IRQ vectors */
for (i = 0; i < phba->cfg_irq_chann; i++) {
- eq = phba->sli4_hba.hdwq[i].hba_eq;
+ /* Get the EQ corresponding to the IRQ vector */
+ eq = phba->sli4_hba.hba_eq_hdl[i].eq;
if (eq && eqcnt[eq->last_cpu] < 2)
eqcnt[eq->last_cpu]++;
continue;
@@ -2963,7 +2965,7 @@ lpfc_stop_hba_timers(struct lpfc_hba *phba)
del_timer_sync(&phba->fcp_poll_timer);
break;
case LPFC_PCI_DEV_OC:
- /* Stop any OneConnect device sepcific driver timers */
+ /* Stop any OneConnect device specific driver timers */
lpfc_sli4_stop_fcf_redisc_wait_timer(phba);
break;
default:
@@ -4114,14 +4116,13 @@ lpfc_new_io_buf(struct lpfc_hba *phba, int num_to_alloc)
* pci bus space for an I/O. The DMA buffer includes the
* number of SGE's necessary to support the sg_tablesize.
*/
- lpfc_ncmd->data = dma_pool_alloc(phba->lpfc_sg_dma_buf_pool,
- GFP_KERNEL,
- &lpfc_ncmd->dma_handle);
+ lpfc_ncmd->data = dma_pool_zalloc(phba->lpfc_sg_dma_buf_pool,
+ GFP_KERNEL,
+ &lpfc_ncmd->dma_handle);
if (!lpfc_ncmd->data) {
kfree(lpfc_ncmd);
break;
}
- memset(lpfc_ncmd->data, 0, phba->cfg_sg_dma_buf_size);
/*
* 4K Page alignment is CRITICAL to BlockGuard, double check
@@ -4347,6 +4348,9 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
timer_setup(&vport->delayed_disc_tmo, lpfc_delayed_disc_tmo, 0);
+ if (phba->sli3_options & LPFC_SLI3_BG_ENABLED)
+ lpfc_setup_bg(phba, shost);
+
error = scsi_add_host_with_dma(shost, dev, &phba->pcidev->dev);
if (error)
goto out_put_shost;
@@ -5055,7 +5059,7 @@ lpfc_update_trunk_link_status(struct lpfc_hba *phba,
bf_get(lpfc_acqe_fc_la_speed, acqe_fc));
phba->sli4_hba.link_state.logical_speed =
- bf_get(lpfc_acqe_fc_la_llink_spd, acqe_fc);
+ bf_get(lpfc_acqe_fc_la_llink_spd, acqe_fc) * 10;
/* We got FC link speed, convert to fc_linkspeed (READ_TOPOLOGY) */
phba->fc_linkspeed =
lpfc_async_link_speed_to_read_top(
@@ -5158,8 +5162,14 @@ lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc)
bf_get(lpfc_acqe_fc_la_port_number, acqe_fc);
phba->sli4_hba.link_state.fault =
bf_get(lpfc_acqe_link_fault, acqe_fc);
- phba->sli4_hba.link_state.logical_speed =
+
+ if (bf_get(lpfc_acqe_fc_la_att_type, acqe_fc) ==
+ LPFC_FC_LA_TYPE_LINK_DOWN)
+ phba->sli4_hba.link_state.logical_speed = 0;
+ else if (!phba->sli4_hba.conf_trunk)
+ phba->sli4_hba.link_state.logical_speed =
bf_get(lpfc_acqe_fc_la_llink_spd, acqe_fc) * 10;
+
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
"2896 Async FC event - Speed:%dGBaud Topology:x%x "
"LA Type:x%x Port Type:%d Port Number:%d Logical speed:"
@@ -6551,6 +6561,8 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
spin_lock_init(&phba->sli4_hba.abts_nvmet_buf_list_lock);
INIT_LIST_HEAD(&phba->sli4_hba.lpfc_abts_nvmet_ctx_list);
INIT_LIST_HEAD(&phba->sli4_hba.lpfc_nvmet_io_wait_list);
+ spin_lock_init(&phba->sli4_hba.t_active_list_lock);
+ INIT_LIST_HEAD(&phba->sli4_hba.t_active_ctx_list);
}
/* This abort list used by worker thread */
@@ -7660,8 +7672,6 @@ lpfc_post_init_setup(struct lpfc_hba *phba)
*/
shost = pci_get_drvdata(phba->pcidev);
shost->can_queue = phba->cfg_hba_queue_depth - 10;
- if (phba->sli3_options & LPFC_SLI3_BG_ENABLED)
- lpfc_setup_bg(phba, shost);
lpfc_host_attrib_init(shost);
@@ -8740,8 +8750,10 @@ int
lpfc_sli4_queue_create(struct lpfc_hba *phba)
{
struct lpfc_queue *qdesc;
- int idx, eqidx, cpu;
+ int idx, cpu, eqcpu;
struct lpfc_sli4_hdw_queue *qp;
+ struct lpfc_vector_map_info *cpup;
+ struct lpfc_vector_map_info *eqcpup;
struct lpfc_eq_intr_info *eqi;
/*
@@ -8826,40 +8838,60 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
INIT_LIST_HEAD(&phba->sli4_hba.lpfc_wq_list);
/* Create HBA Event Queues (EQs) */
- for (idx = 0; idx < phba->cfg_hdw_queue; idx++) {
- /* determine EQ affinity */
- eqidx = lpfc_find_eq_handle(phba, idx);
- cpu = lpfc_find_cpu_handle(phba, eqidx, LPFC_FIND_BY_EQ);
- /*
- * If there are more Hardware Queues than available
- * EQs, multiple Hardware Queues may share a common EQ.
+ for_each_present_cpu(cpu) {
+ /* We only want to create 1 EQ per vector, even though
+ * multiple CPUs might be using that vector. so only
+ * selects the CPUs that are LPFC_CPU_FIRST_IRQ.
*/
- if (idx >= phba->cfg_irq_chann) {
- /* Share an existing EQ */
- phba->sli4_hba.hdwq[idx].hba_eq =
- phba->sli4_hba.hdwq[eqidx].hba_eq;
+ cpup = &phba->sli4_hba.cpu_map[cpu];
+ if (!(cpup->flag & LPFC_CPU_FIRST_IRQ))
continue;
- }
- /* Create an EQ */
+
+ /* Get a ptr to the Hardware Queue associated with this CPU */
+ qp = &phba->sli4_hba.hdwq[cpup->hdwq];
+
+ /* Allocate an EQ */
qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE,
phba->sli4_hba.eq_esize,
phba->sli4_hba.eq_ecount, cpu);
if (!qdesc) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0497 Failed allocate EQ (%d)\n", idx);
+ "0497 Failed allocate EQ (%d)\n",
+ cpup->hdwq);
goto out_error;
}
qdesc->qe_valid = 1;
- qdesc->hdwq = idx;
-
- /* Save the CPU this EQ is affinitised to */
- qdesc->chann = cpu;
- phba->sli4_hba.hdwq[idx].hba_eq = qdesc;
+ qdesc->hdwq = cpup->hdwq;
+ qdesc->chann = cpu; /* First CPU this EQ is affinitised to */
qdesc->last_cpu = qdesc->chann;
+
+ /* Save the allocated EQ in the Hardware Queue */
+ qp->hba_eq = qdesc;
+
eqi = per_cpu_ptr(phba->sli4_hba.eq_info, qdesc->last_cpu);
list_add(&qdesc->cpu_list, &eqi->list);
}
+ /* Now we need to populate the other Hardware Queues, that share
+ * an IRQ vector, with the associated EQ ptr.
+ */
+ for_each_present_cpu(cpu) {
+ cpup = &phba->sli4_hba.cpu_map[cpu];
+
+ /* Check for EQ already allocated in previous loop */
+ if (cpup->flag & LPFC_CPU_FIRST_IRQ)
+ continue;
+
+ /* Check for multiple CPUs per hdwq */
+ qp = &phba->sli4_hba.hdwq[cpup->hdwq];
+ if (qp->hba_eq)
+ continue;
+
+ /* We need to share an EQ for this hdwq */
+ eqcpu = lpfc_find_cpu_handle(phba, cpup->eq, LPFC_FIND_BY_EQ);
+ eqcpup = &phba->sli4_hba.cpu_map[eqcpu];
+ qp->hba_eq = phba->sli4_hba.hdwq[eqcpup->hdwq].hba_eq;
+ }
/* Allocate SCSI SLI4 CQ/WQs */
for (idx = 0; idx < phba->cfg_hdw_queue; idx++) {
@@ -9122,23 +9154,31 @@ static inline void
lpfc_sli4_release_hdwq(struct lpfc_hba *phba)
{
struct lpfc_sli4_hdw_queue *hdwq;
+ struct lpfc_queue *eq;
uint32_t idx;
hdwq = phba->sli4_hba.hdwq;
- for (idx = 0; idx < phba->cfg_hdw_queue; idx++) {
- if (idx < phba->cfg_irq_chann)
- lpfc_sli4_queue_free(hdwq[idx].hba_eq);
- hdwq[idx].hba_eq = NULL;
+ /* Loop thru all Hardware Queues */
+ for (idx = 0; idx < phba->cfg_hdw_queue; idx++) {
+ /* Free the CQ/WQ corresponding to the Hardware Queue */
lpfc_sli4_queue_free(hdwq[idx].fcp_cq);
lpfc_sli4_queue_free(hdwq[idx].nvme_cq);
lpfc_sli4_queue_free(hdwq[idx].fcp_wq);
lpfc_sli4_queue_free(hdwq[idx].nvme_wq);
+ hdwq[idx].hba_eq = NULL;
hdwq[idx].fcp_cq = NULL;
hdwq[idx].nvme_cq = NULL;
hdwq[idx].fcp_wq = NULL;
hdwq[idx].nvme_wq = NULL;
}
+ /* Loop thru all IRQ vectors */
+ for (idx = 0; idx < phba->cfg_irq_chann; idx++) {
+ /* Free the EQ corresponding to the IRQ vector */
+ eq = phba->sli4_hba.hba_eq_hdl[idx].eq;
+ lpfc_sli4_queue_free(eq);
+ phba->sli4_hba.hba_eq_hdl[idx].eq = NULL;
+ }
}
/**
@@ -9316,16 +9356,17 @@ static void
lpfc_setup_cq_lookup(struct lpfc_hba *phba)
{
struct lpfc_queue *eq, *childq;
- struct lpfc_sli4_hdw_queue *qp;
int qidx;
- qp = phba->sli4_hba.hdwq;
memset(phba->sli4_hba.cq_lookup, 0,
(sizeof(struct lpfc_queue *) * (phba->sli4_hba.cq_max + 1)));
+ /* Loop thru all IRQ vectors */
for (qidx = 0; qidx < phba->cfg_irq_chann; qidx++) {
- eq = qp[qidx].hba_eq;
+ /* Get the EQ corresponding to the IRQ vector */
+ eq = phba->sli4_hba.hba_eq_hdl[qidx].eq;
if (!eq)
continue;
+ /* Loop through all CQs associated with that EQ */
list_for_each_entry(childq, &eq->child_list, list) {
if (childq->queue_id > phba->sli4_hba.cq_max)
continue;
@@ -9354,9 +9395,10 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba)
{
uint32_t shdr_status, shdr_add_status;
union lpfc_sli4_cfg_shdr *shdr;
+ struct lpfc_vector_map_info *cpup;
struct lpfc_sli4_hdw_queue *qp;
LPFC_MBOXQ_t *mboxq;
- int qidx;
+ int qidx, cpu;
uint32_t length, usdelay;
int rc = -ENOMEM;
@@ -9417,32 +9459,55 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba)
rc = -ENOMEM;
goto out_error;
}
+
+ /* Loop thru all IRQ vectors */
for (qidx = 0; qidx < phba->cfg_irq_chann; qidx++) {
- if (!qp[qidx].hba_eq) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0522 Fast-path EQ (%d) not "
- "allocated\n", qidx);
- rc = -ENOMEM;
- goto out_destroy;
- }
- rc = lpfc_eq_create(phba, qp[qidx].hba_eq,
- phba->cfg_fcp_imax);
- if (rc) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0523 Failed setup of fast-path EQ "
- "(%d), rc = 0x%x\n", qidx,
- (uint32_t)rc);
- goto out_destroy;
+ /* Create HBA Event Queues (EQs) in order */
+ for_each_present_cpu(cpu) {
+ cpup = &phba->sli4_hba.cpu_map[cpu];
+
+ /* Look for the CPU thats using that vector with
+ * LPFC_CPU_FIRST_IRQ set.
+ */
+ if (!(cpup->flag & LPFC_CPU_FIRST_IRQ))
+ continue;
+ if (qidx != cpup->eq)
+ continue;
+
+ /* Create an EQ for that vector */
+ rc = lpfc_eq_create(phba, qp[cpup->hdwq].hba_eq,
+ phba->cfg_fcp_imax);
+ if (rc) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "0523 Failed setup of fast-path"
+ " EQ (%d), rc = 0x%x\n",
+ cpup->eq, (uint32_t)rc);
+ goto out_destroy;
+ }
+
+ /* Save the EQ for that vector in the hba_eq_hdl */
+ phba->sli4_hba.hba_eq_hdl[cpup->eq].eq =
+ qp[cpup->hdwq].hba_eq;
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "2584 HBA EQ setup: queue[%d]-id=%d\n",
+ cpup->eq,
+ qp[cpup->hdwq].hba_eq->queue_id);
}
- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
- "2584 HBA EQ setup: queue[%d]-id=%d\n", qidx,
- qp[qidx].hba_eq->queue_id);
}
+ /* Loop thru all Hardware Queues */
if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) {
for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) {
+ cpu = lpfc_find_cpu_handle(phba, qidx,
+ LPFC_FIND_BY_HDWQ);
+ cpup = &phba->sli4_hba.cpu_map[cpu];
+
+ /* Create the CQ/WQ corresponding to the
+ * Hardware Queue
+ */
rc = lpfc_create_wq_cq(phba,
- qp[qidx].hba_eq,
+ phba->sli4_hba.hdwq[cpup->hdwq].hba_eq,
qp[qidx].nvme_cq,
qp[qidx].nvme_wq,
&phba->sli4_hba.hdwq[qidx].nvme_cq_map,
@@ -9458,8 +9523,12 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba)
}
for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) {
+ cpu = lpfc_find_cpu_handle(phba, qidx, LPFC_FIND_BY_HDWQ);
+ cpup = &phba->sli4_hba.cpu_map[cpu];
+
+ /* Create the CQ/WQ corresponding to the Hardware Queue */
rc = lpfc_create_wq_cq(phba,
- qp[qidx].hba_eq,
+ phba->sli4_hba.hdwq[cpup->hdwq].hba_eq,
qp[qidx].fcp_cq,
qp[qidx].fcp_wq,
&phba->sli4_hba.hdwq[qidx].fcp_cq_map,
@@ -9711,6 +9780,7 @@ void
lpfc_sli4_queue_unset(struct lpfc_hba *phba)
{
struct lpfc_sli4_hdw_queue *qp;
+ struct lpfc_queue *eq;
int qidx;
/* Unset mailbox command work queue */
@@ -9762,14 +9832,20 @@ lpfc_sli4_queue_unset(struct lpfc_hba *phba)
/* Unset fast-path SLI4 queues */
if (phba->sli4_hba.hdwq) {
+ /* Loop thru all Hardware Queues */
for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) {
+ /* Destroy the CQ/WQ corresponding to Hardware Queue */
qp = &phba->sli4_hba.hdwq[qidx];
lpfc_wq_destroy(phba, qp->fcp_wq);
lpfc_wq_destroy(phba, qp->nvme_wq);
lpfc_cq_destroy(phba, qp->fcp_cq);
lpfc_cq_destroy(phba, qp->nvme_cq);
- if (qidx < phba->cfg_irq_chann)
- lpfc_eq_destroy(phba, qp->hba_eq);
+ }
+ /* Loop thru all IRQ vectors */
+ for (qidx = 0; qidx < phba->cfg_irq_chann; qidx++) {
+ /* Destroy the EQ corresponding to the IRQ vector */
+ eq = phba->sli4_hba.hba_eq_hdl[qidx].eq;
+ lpfc_eq_destroy(phba, eq);
}
}
@@ -10559,11 +10635,12 @@ lpfc_sli_disable_intr(struct lpfc_hba *phba)
}
/**
- * lpfc_find_cpu_handle - Find the CPU that corresponds to the specified EQ
+ * lpfc_find_cpu_handle - Find the CPU that corresponds to the specified Queue
* @phba: pointer to lpfc hba data structure.
* @id: EQ vector index or Hardware Queue index
* @match: LPFC_FIND_BY_EQ = match by EQ
* LPFC_FIND_BY_HDWQ = match by Hardware Queue
+ * Return the CPU that matches the selection criteria
*/
static uint16_t
lpfc_find_cpu_handle(struct lpfc_hba *phba, uint16_t id, int match)
@@ -10571,40 +10648,27 @@ lpfc_find_cpu_handle(struct lpfc_hba *phba, uint16_t id, int match)
struct lpfc_vector_map_info *cpup;
int cpu;
- /* Find the desired phys_id for the specified EQ */
+ /* Loop through all CPUs */
for_each_present_cpu(cpu) {
cpup = &phba->sli4_hba.cpu_map[cpu];
+
+ /* If we are matching by EQ, there may be multiple CPUs using
+ * using the same vector, so select the one with
+ * LPFC_CPU_FIRST_IRQ set.
+ */
if ((match == LPFC_FIND_BY_EQ) &&
+ (cpup->flag & LPFC_CPU_FIRST_IRQ) &&
(cpup->irq != LPFC_VECTOR_MAP_EMPTY) &&
(cpup->eq == id))
return cpu;
+
+ /* If matching by HDWQ, select the first CPU that matches */
if ((match == LPFC_FIND_BY_HDWQ) && (cpup->hdwq == id))
return cpu;
}
return 0;
}
-/**
- * lpfc_find_eq_handle - Find the EQ that corresponds to the specified
- * Hardware Queue
- * @phba: pointer to lpfc hba data structure.
- * @hdwq: Hardware Queue index
- */
-static uint16_t
-lpfc_find_eq_handle(struct lpfc_hba *phba, uint16_t hdwq)
-{
- struct lpfc_vector_map_info *cpup;
- int cpu;
-
- /* Find the desired phys_id for the specified EQ */
- for_each_present_cpu(cpu) {
- cpup = &phba->sli4_hba.cpu_map[cpu];
- if (cpup->hdwq == hdwq)
- return cpup->eq;
- }
- return 0;
-}
-
#ifdef CONFIG_X86
/**
* lpfc_find_hyper - Determine if the CPU map entry is hyper-threaded
@@ -10645,24 +10709,31 @@ lpfc_find_hyper(struct lpfc_hba *phba, int cpu,
static void
lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors)
{
- int i, cpu, idx;
+ int i, cpu, idx, new_cpu, start_cpu, first_cpu;
int max_phys_id, min_phys_id;
int max_core_id, min_core_id;
struct lpfc_vector_map_info *cpup;
+ struct lpfc_vector_map_info *new_cpup;
const struct cpumask *maskp;
#ifdef CONFIG_X86
struct cpuinfo_x86 *cpuinfo;
#endif
/* Init cpu_map array */
- memset(phba->sli4_hba.cpu_map, 0xff,
- (sizeof(struct lpfc_vector_map_info) *
- phba->sli4_hba.num_possible_cpu));
+ for_each_possible_cpu(cpu) {
+ cpup = &phba->sli4_hba.cpu_map[cpu];
+ cpup->phys_id = LPFC_VECTOR_MAP_EMPTY;
+ cpup->core_id = LPFC_VECTOR_MAP_EMPTY;
+ cpup->hdwq = LPFC_VECTOR_MAP_EMPTY;
+ cpup->eq = LPFC_VECTOR_MAP_EMPTY;
+ cpup->irq = LPFC_VECTOR_MAP_EMPTY;
+ cpup->flag = 0;
+ }
max_phys_id = 0;
- min_phys_id = 0xffff;
+ min_phys_id = LPFC_VECTOR_MAP_EMPTY;
max_core_id = 0;
- min_core_id = 0xffff;
+ min_core_id = LPFC_VECTOR_MAP_EMPTY;
/* Update CPU map with physical id and core id of each CPU */
for_each_present_cpu(cpu) {
@@ -10671,13 +10742,12 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors)
cpuinfo = &cpu_data(cpu);
cpup->phys_id = cpuinfo->phys_proc_id;
cpup->core_id = cpuinfo->cpu_core_id;
- cpup->hyper = lpfc_find_hyper(phba, cpu,
- cpup->phys_id, cpup->core_id);
+ if (lpfc_find_hyper(phba, cpu, cpup->phys_id, cpup->core_id))
+ cpup->flag |= LPFC_CPU_MAP_HYPER;
#else
/* No distinction between CPUs for other platforms */
cpup->phys_id = 0;
cpup->core_id = cpu;
- cpup->hyper = 0;
#endif
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
@@ -10703,23 +10773,216 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors)
eqi->icnt = 0;
}
+ /* This loop sets up all CPUs that are affinitized with a
+ * irq vector assigned to the driver. All affinitized CPUs
+ * will get a link to that vectors IRQ and EQ.
+ */
for (idx = 0; idx < phba->cfg_irq_chann; idx++) {
+ /* Get a CPU mask for all CPUs affinitized to this vector */
maskp = pci_irq_get_affinity(phba->pcidev, idx);
if (!maskp)
continue;
+ i = 0;
+ /* Loop through all CPUs associated with vector idx */
for_each_cpu_and(cpu, maskp, cpu_present_mask) {
+ /* Set the EQ index and IRQ for that vector */
cpup = &phba->sli4_hba.cpu_map[cpu];
cpup->eq = idx;
- cpup->hdwq = idx;
cpup->irq = pci_irq_vector(phba->pcidev, idx);
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
"3336 Set Affinity: CPU %d "
- "hdwq %d irq %d\n",
- cpu, cpup->hdwq, cpup->irq);
+ "irq %d eq %d\n",
+ cpu, cpup->irq, cpup->eq);
+
+ /* If this is the first CPU thats assigned to this
+ * vector, set LPFC_CPU_FIRST_IRQ.
+ */
+ if (!i)
+ cpup->flag |= LPFC_CPU_FIRST_IRQ;
+ i++;
}
}
+
+ /* After looking at each irq vector assigned to this pcidev, its
+ * possible to see that not ALL CPUs have been accounted for.
+ * Next we will set any unassigned (unaffinitized) cpu map
+ * entries to a IRQ on the same phys_id.
+ */
+ first_cpu = cpumask_first(cpu_present_mask);
+ start_cpu = first_cpu;
+
+ for_each_present_cpu(cpu) {
+ cpup = &phba->sli4_hba.cpu_map[cpu];
+
+ /* Is this CPU entry unassigned */
+ if (cpup->eq == LPFC_VECTOR_MAP_EMPTY) {
+ /* Mark CPU as IRQ not assigned by the kernel */
+ cpup->flag |= LPFC_CPU_MAP_UNASSIGN;
+
+ /* If so, find a new_cpup thats on the the SAME
+ * phys_id as cpup. start_cpu will start where we
+ * left off so all unassigned entries don't get assgined
+ * the IRQ of the first entry.
+ */
+ new_cpu = start_cpu;
+ for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) {
+ new_cpup = &phba->sli4_hba.cpu_map[new_cpu];
+ if (!(new_cpup->flag & LPFC_CPU_MAP_UNASSIGN) &&
+ (new_cpup->irq != LPFC_VECTOR_MAP_EMPTY) &&
+ (new_cpup->phys_id == cpup->phys_id))
+ goto found_same;
+ new_cpu = cpumask_next(
+ new_cpu, cpu_present_mask);
+ if (new_cpu == nr_cpumask_bits)
+ new_cpu = first_cpu;
+ }
+ /* At this point, we leave the CPU as unassigned */
+ continue;
+found_same:
+ /* We found a matching phys_id, so copy the IRQ info */
+ cpup->eq = new_cpup->eq;
+ cpup->irq = new_cpup->irq;
+
+ /* Bump start_cpu to the next slot to minmize the
+ * chance of having multiple unassigned CPU entries
+ * selecting the same IRQ.
+ */
+ start_cpu = cpumask_next(new_cpu, cpu_present_mask);
+ if (start_cpu == nr_cpumask_bits)
+ start_cpu = first_cpu;
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "3337 Set Affinity: CPU %d "
+ "irq %d from id %d same "
+ "phys_id (%d)\n",
+ cpu, cpup->irq, new_cpu, cpup->phys_id);
+ }
+ }
+
+ /* Set any unassigned cpu map entries to a IRQ on any phys_id */
+ start_cpu = first_cpu;
+
+ for_each_present_cpu(cpu) {
+ cpup = &phba->sli4_hba.cpu_map[cpu];
+
+ /* Is this entry unassigned */
+ if (cpup->eq == LPFC_VECTOR_MAP_EMPTY) {
+ /* Mark it as IRQ not assigned by the kernel */
+ cpup->flag |= LPFC_CPU_MAP_UNASSIGN;
+
+ /* If so, find a new_cpup thats on ANY phys_id
+ * as the cpup. start_cpu will start where we
+ * left off so all unassigned entries don't get
+ * assigned the IRQ of the first entry.
+ */
+ new_cpu = start_cpu;
+ for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) {
+ new_cpup = &phba->sli4_hba.cpu_map[new_cpu];
+ if (!(new_cpup->flag & LPFC_CPU_MAP_UNASSIGN) &&
+ (new_cpup->irq != LPFC_VECTOR_MAP_EMPTY))
+ goto found_any;
+ new_cpu = cpumask_next(
+ new_cpu, cpu_present_mask);
+ if (new_cpu == nr_cpumask_bits)
+ new_cpu = first_cpu;
+ }
+ /* We should never leave an entry unassigned */
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "3339 Set Affinity: CPU %d "
+ "irq %d UNASSIGNED\n",
+ cpup->hdwq, cpup->irq);
+ continue;
+found_any:
+ /* We found an available entry, copy the IRQ info */
+ cpup->eq = new_cpup->eq;
+ cpup->irq = new_cpup->irq;
+
+ /* Bump start_cpu to the next slot to minmize the
+ * chance of having multiple unassigned CPU entries
+ * selecting the same IRQ.
+ */
+ start_cpu = cpumask_next(new_cpu, cpu_present_mask);
+ if (start_cpu == nr_cpumask_bits)
+ start_cpu = first_cpu;
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "3338 Set Affinity: CPU %d "
+ "irq %d from id %d (%d/%d)\n",
+ cpu, cpup->irq, new_cpu,
+ new_cpup->phys_id, new_cpup->core_id);
+ }
+ }
+
+ /* Finally we need to associate a hdwq with each cpu_map entry
+ * This will be 1 to 1 - hdwq to cpu, unless there are less
+ * hardware queues then CPUs. For that case we will just round-robin
+ * the available hardware queues as they get assigned to CPUs.
+ */
+ idx = 0;
+ start_cpu = 0;
+ for_each_present_cpu(cpu) {
+ cpup = &phba->sli4_hba.cpu_map[cpu];
+ if (idx >= phba->cfg_hdw_queue) {
+ /* We need to reuse a Hardware Queue for another CPU,
+ * so be smart about it and pick one that has its
+ * IRQ/EQ mapped to the same phys_id (CPU package).
+ * and core_id.
+ */
+ new_cpu = start_cpu;
+ for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) {
+ new_cpup = &phba->sli4_hba.cpu_map[new_cpu];
+ if ((new_cpup->hdwq != LPFC_VECTOR_MAP_EMPTY) &&
+ (new_cpup->phys_id == cpup->phys_id) &&
+ (new_cpup->core_id == cpup->core_id))
+ goto found_hdwq;
+ new_cpu = cpumask_next(
+ new_cpu, cpu_present_mask);
+ if (new_cpu == nr_cpumask_bits)
+ new_cpu = first_cpu;
+ }
+
+ /* If we can't match both phys_id and core_id,
+ * settle for just a phys_id match.
+ */
+ new_cpu = start_cpu;
+ for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) {
+ new_cpup = &phba->sli4_hba.cpu_map[new_cpu];
+ if ((new_cpup->hdwq != LPFC_VECTOR_MAP_EMPTY) &&
+ (new_cpup->phys_id == cpup->phys_id))
+ goto found_hdwq;
+ new_cpu = cpumask_next(
+ new_cpu, cpu_present_mask);
+ if (new_cpu == nr_cpumask_bits)
+ new_cpu = first_cpu;
+ }
+
+ /* Otherwise just round robin on cfg_hdw_queue */
+ cpup->hdwq = idx % phba->cfg_hdw_queue;
+ goto logit;
+found_hdwq:
+ /* We found an available entry, copy the IRQ info */
+ start_cpu = cpumask_next(new_cpu, cpu_present_mask);
+ if (start_cpu == nr_cpumask_bits)
+ start_cpu = first_cpu;
+ cpup->hdwq = new_cpup->hdwq;
+ } else {
+ /* 1 to 1, CPU to hdwq */
+ cpup->hdwq = idx;
+ }
+logit:
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "3335 Set Affinity: CPU %d (phys %d core %d): "
+ "hdwq %d eq %d irq %d flg x%x\n",
+ cpu, cpup->phys_id, cpup->core_id,
+ cpup->hdwq, cpup->eq, cpup->irq, cpup->flag);
+ idx++;
+ }
+
+ /* The cpu_map array will be used later during initialization
+ * when EQ / CQ / WQs are allocated and configured.
+ */
return;
}
@@ -11331,24 +11594,43 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
mbx_sli4_parameters);
phba->sli4_hba.extents_in_use = bf_get(cfg_ext, mbx_sli4_parameters);
phba->sli4_hba.rpi_hdrs_in_use = bf_get(cfg_hdrr, mbx_sli4_parameters);
- phba->nvme_support = (bf_get(cfg_nvme, mbx_sli4_parameters) &&
- bf_get(cfg_xib, mbx_sli4_parameters));
-
- if ((phba->cfg_enable_fc4_type == LPFC_ENABLE_FCP) ||
- !phba->nvme_support) {
- phba->nvme_support = 0;
- phba->nvmet_support = 0;
- phba->cfg_nvmet_mrq = 0;
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_NVME,
- "6101 Disabling NVME support: "
- "Not supported by firmware: %d %d\n",
- bf_get(cfg_nvme, mbx_sli4_parameters),
- bf_get(cfg_xib, mbx_sli4_parameters));
-
- /* If firmware doesn't support NVME, just use SCSI support */
- if (!(phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP))
- return -ENODEV;
- phba->cfg_enable_fc4_type = LPFC_ENABLE_FCP;
+
+ /* Check for firmware nvme support */
+ rc = (bf_get(cfg_nvme, mbx_sli4_parameters) &&
+ bf_get(cfg_xib, mbx_sli4_parameters));
+
+ if (rc) {
+ /* Save this to indicate the Firmware supports NVME */
+ sli4_params->nvme = 1;
+
+ /* Firmware NVME support, check driver FC4 NVME support */
+ if (phba->cfg_enable_fc4_type == LPFC_ENABLE_FCP) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_NVME,
+ "6133 Disabling NVME support: "
+ "FC4 type not supported: x%x\n",
+ phba->cfg_enable_fc4_type);
+ goto fcponly;
+ }
+ } else {
+ /* No firmware NVME support, check driver FC4 NVME support */
+ sli4_params->nvme = 0;
+ if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_NVME,
+ "6101 Disabling NVME support: Not "
+ "supported by firmware (%d %d) x%x\n",
+ bf_get(cfg_nvme, mbx_sli4_parameters),
+ bf_get(cfg_xib, mbx_sli4_parameters),
+ phba->cfg_enable_fc4_type);
+fcponly:
+ phba->nvme_support = 0;
+ phba->nvmet_support = 0;
+ phba->cfg_nvmet_mrq = 0;
+
+ /* If no FC4 type support, move to just SCSI support */
+ if (!(phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP))
+ return -ENODEV;
+ phba->cfg_enable_fc4_type = LPFC_ENABLE_FCP;
+ }
}
/* Only embed PBDE for if_type 6, PBDE support requires xib be set */
diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c
index 9d99cb915390..946642cee3df 100644
--- a/drivers/scsi/lpfc/lpfc_nvme.c
+++ b/drivers/scsi/lpfc/lpfc_nvme.c
@@ -2143,7 +2143,9 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport,
struct completion *lport_unreg_cmp)
{
u32 wait_tmo;
- int ret;
+ int ret, i, pending = 0;
+ struct lpfc_sli_ring *pring;
+ struct lpfc_hba *phba = vport->phba;
/* Host transport has to clean up and confirm requiring an indefinite
* wait. Print a message if a 10 second wait expires and renew the
@@ -2153,10 +2155,18 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport,
while (true) {
ret = wait_for_completion_timeout(lport_unreg_cmp, wait_tmo);
if (unlikely(!ret)) {
+ pending = 0;
+ for (i = 0; i < phba->cfg_hdw_queue; i++) {
+ pring = phba->sli4_hba.hdwq[i].nvme_wq->pring;
+ if (!pring)
+ continue;
+ if (pring->txcmplq_cnt)
+ pending += pring->txcmplq_cnt;
+ }
lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_IOERR,
"6176 Lport %p Localport %p wait "
- "timed out. Renewing.\n",
- lport, vport->localport);
+ "timed out. Pending %d. Renewing.\n",
+ lport, vport->localport, pending);
continue;
}
break;
@@ -2402,6 +2412,50 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
#endif
}
+/**
+ * lpfc_nvme_rescan_port - Check to see if we should rescan this remoteport
+ *
+ * If the ndlp represents an NVME Target, that we are logged into,
+ * ping the NVME FC Transport layer to initiate a device rescan
+ * on this remote NPort.
+ */
+void
+lpfc_nvme_rescan_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
+{
+#if (IS_ENABLED(CONFIG_NVME_FC))
+ struct lpfc_nvme_rport *rport;
+ struct nvme_fc_remote_port *remoteport;
+
+ rport = ndlp->nrport;
+
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC,
+ "6170 Rescan NPort DID x%06x type x%x "
+ "state x%x rport %p\n",
+ ndlp->nlp_DID, ndlp->nlp_type, ndlp->nlp_state, rport);
+ if (!rport)
+ goto input_err;
+ remoteport = rport->remoteport;
+ if (!remoteport)
+ goto input_err;
+
+ /* Only rescan if we are an NVME target in the MAPPED state */
+ if (remoteport->port_role & FC_PORT_ROLE_NVME_DISCOVERY &&
+ ndlp->nlp_state == NLP_STE_MAPPED_NODE) {
+ nvme_fc_rescan_remoteport(remoteport);
+
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC,
+ "6172 NVME rescanned DID x%06x "
+ "port_state x%x\n",
+ ndlp->nlp_DID, remoteport->port_state);
+ }
+ return;
+input_err:
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC,
+ "6169 State error: lport %p, rport%p FCID x%06x\n",
+ vport->localport, ndlp->rport, ndlp->nlp_DID);
+#endif
+}
+
/* lpfc_nvme_unregister_port - unbind the DID and port_role from this rport.
*
* There is no notion of Devloss or rport recovery from the current
diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c
index d74bfd264495..faa596f9e861 100644
--- a/drivers/scsi/lpfc/lpfc_nvmet.c
+++ b/drivers/scsi/lpfc/lpfc_nvmet.c
@@ -220,19 +220,68 @@ lpfc_nvmet_cmd_template(void)
/* Word 12, 13, 14, 15 - is zero */
}
+#if (IS_ENABLED(CONFIG_NVME_TARGET_FC))
+static struct lpfc_nvmet_rcv_ctx *
+lpfc_nvmet_get_ctx_for_xri(struct lpfc_hba *phba, u16 xri)
+{
+ struct lpfc_nvmet_rcv_ctx *ctxp;
+ unsigned long iflag;
+ bool found = false;
+
+ spin_lock_irqsave(&phba->sli4_hba.t_active_list_lock, iflag);
+ list_for_each_entry(ctxp, &phba->sli4_hba.t_active_ctx_list, list) {
+ if (ctxp->ctxbuf->sglq->sli4_xritag != xri)
+ continue;
+
+ found = true;
+ break;
+ }
+ spin_unlock_irqrestore(&phba->sli4_hba.t_active_list_lock, iflag);
+ if (found)
+ return ctxp;
+
+ return NULL;
+}
+
+static struct lpfc_nvmet_rcv_ctx *
+lpfc_nvmet_get_ctx_for_oxid(struct lpfc_hba *phba, u16 oxid, u32 sid)
+{
+ struct lpfc_nvmet_rcv_ctx *ctxp;
+ unsigned long iflag;
+ bool found = false;
+
+ spin_lock_irqsave(&phba->sli4_hba.t_active_list_lock, iflag);
+ list_for_each_entry(ctxp, &phba->sli4_hba.t_active_ctx_list, list) {
+ if (ctxp->oxid != oxid || ctxp->sid != sid)
+ continue;
+
+ found = true;
+ break;
+ }
+ spin_unlock_irqrestore(&phba->sli4_hba.t_active_list_lock, iflag);
+ if (found)
+ return ctxp;
+
+ return NULL;
+}
+#endif
+
static void
lpfc_nvmet_defer_release(struct lpfc_hba *phba, struct lpfc_nvmet_rcv_ctx *ctxp)
{
lockdep_assert_held(&ctxp->ctxlock);
lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
- "6313 NVMET Defer ctx release xri x%x flg x%x\n",
+ "6313 NVMET Defer ctx release oxid x%x flg x%x\n",
ctxp->oxid, ctxp->flag);
if (ctxp->flag & LPFC_NVMET_CTX_RLS)
return;
ctxp->flag |= LPFC_NVMET_CTX_RLS;
+ spin_lock(&phba->sli4_hba.t_active_list_lock);
+ list_del(&ctxp->list);
+ spin_unlock(&phba->sli4_hba.t_active_list_lock);
spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
list_add_tail(&ctxp->list, &phba->sli4_hba.lpfc_abts_nvmet_ctx_list);
spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
@@ -343,16 +392,23 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf)
}
if (ctxp->rqb_buffer) {
- nvmebuf = ctxp->rqb_buffer;
spin_lock_irqsave(&ctxp->ctxlock, iflag);
- ctxp->rqb_buffer = NULL;
- if (ctxp->flag & LPFC_NVMET_CTX_REUSE_WQ) {
- ctxp->flag &= ~LPFC_NVMET_CTX_REUSE_WQ;
- spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
- nvmebuf->hrq->rqbp->rqb_free_buffer(phba, nvmebuf);
+ nvmebuf = ctxp->rqb_buffer;
+ /* check if freed in another path whilst acquiring lock */
+ if (nvmebuf) {
+ ctxp->rqb_buffer = NULL;
+ if (ctxp->flag & LPFC_NVMET_CTX_REUSE_WQ) {
+ ctxp->flag &= ~LPFC_NVMET_CTX_REUSE_WQ;
+ spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
+ nvmebuf->hrq->rqbp->rqb_free_buffer(phba,
+ nvmebuf);
+ } else {
+ spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
+ /* repost */
+ lpfc_rq_buf_free(phba, &nvmebuf->hbuf);
+ }
} else {
spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
- lpfc_rq_buf_free(phba, &nvmebuf->hbuf); /* repost */
}
}
ctxp->state = LPFC_NVMET_STE_FREE;
@@ -388,8 +444,9 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf)
spin_lock_init(&ctxp->ctxlock);
#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
- if (ctxp->ts_cmd_nvme) {
- ctxp->ts_cmd_nvme = ktime_get_ns();
+ /* NOTE: isr time stamp is stale when context is re-assigned*/
+ if (ctxp->ts_isr_cmd) {
+ ctxp->ts_cmd_nvme = 0;
ctxp->ts_nvme_data = 0;
ctxp->ts_data_wqput = 0;
ctxp->ts_isr_data = 0;
@@ -402,9 +459,7 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf)
#endif
atomic_inc(&tgtp->rcv_fcp_cmd_in);
- /* flag new work queued, replacement buffer has already
- * been reposted
- */
+ /* Indicate that a replacement buffer has been posted */
spin_lock_irqsave(&ctxp->ctxlock, iflag);
ctxp->flag |= LPFC_NVMET_CTX_REUSE_WQ;
spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
@@ -433,6 +488,9 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf)
* Use the CPU context list, from the MRQ the IO was received on
* (ctxp->idx), to save context structure.
*/
+ spin_lock_irqsave(&phba->sli4_hba.t_active_list_lock, iflag);
+ list_del_init(&ctxp->list);
+ spin_unlock_irqrestore(&phba->sli4_hba.t_active_list_lock, iflag);
cpu = raw_smp_processor_id();
infop = lpfc_get_ctx_list(phba, cpu, ctxp->idx);
spin_lock_irqsave(&infop->nvmet_ctx_list_lock, iflag);
@@ -700,8 +758,10 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
}
lpfc_printf_log(phba, KERN_INFO, logerr,
- "6315 IO Error Cmpl xri x%x: %x/%x XBUSY:x%x\n",
- ctxp->oxid, status, result, ctxp->flag);
+ "6315 IO Error Cmpl oxid: x%x xri: x%x %x/%x "
+ "XBUSY:x%x\n",
+ ctxp->oxid, ctxp->ctxbuf->sglq->sli4_xritag,
+ status, result, ctxp->flag);
} else {
rsp->fcp_error = NVME_SC_SUCCESS;
@@ -849,7 +909,6 @@ lpfc_nvmet_xmt_ls_rsp(struct nvmet_fc_target_port *tgtport,
* before freeing ctxp and iocbq.
*/
lpfc_in_buf_free(phba, &nvmebuf->dbuf);
- ctxp->rqb_buffer = 0;
atomic_inc(&nvmep->xmt_ls_rsp);
return 0;
}
@@ -922,7 +981,7 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport,
(ctxp->state == LPFC_NVMET_STE_ABORT)) {
atomic_inc(&lpfc_nvmep->xmt_fcp_drop);
lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR,
- "6102 IO xri x%x aborted\n",
+ "6102 IO oxid x%x aborted\n",
ctxp->oxid);
rc = -ENXIO;
goto aerr;
@@ -1022,7 +1081,7 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport,
ctxp->hdwq = &phba->sli4_hba.hdwq[0];
lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
- "6103 NVMET Abort op: oxri x%x flg x%x ste %d\n",
+ "6103 NVMET Abort op: oxid x%x flg x%x ste %d\n",
ctxp->oxid, ctxp->flag, ctxp->state);
lpfc_nvmeio_data(phba, "NVMET FCP ABRT: xri x%x flg x%x ste x%x\n",
@@ -1035,7 +1094,7 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport,
/* Since iaab/iaar are NOT set, we need to check
* if the firmware is in process of aborting IO
*/
- if (ctxp->flag & LPFC_NVMET_XBUSY) {
+ if (ctxp->flag & (LPFC_NVMET_XBUSY | LPFC_NVMET_ABORT_OP)) {
spin_unlock_irqrestore(&ctxp->ctxlock, flags);
return;
}
@@ -1098,6 +1157,7 @@ lpfc_nvmet_xmt_fcp_release(struct nvmet_fc_target_port *tgtport,
ctxp->state, aborting);
atomic_inc(&lpfc_nvmep->xmt_fcp_release);
+ ctxp->flag &= ~LPFC_NVMET_TNOTIFY;
if (aborting)
return;
@@ -1122,7 +1182,7 @@ lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport,
if (!nvmebuf) {
lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR,
- "6425 Defer rcv: no buffer xri x%x: "
+ "6425 Defer rcv: no buffer oxid x%x: "
"flg %x ste %x\n",
ctxp->oxid, ctxp->flag, ctxp->state);
return;
@@ -1139,6 +1199,22 @@ lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport,
spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
}
+static void
+lpfc_nvmet_discovery_event(struct nvmet_fc_target_port *tgtport)
+{
+ struct lpfc_nvmet_tgtport *tgtp;
+ struct lpfc_hba *phba;
+ uint32_t rc;
+
+ tgtp = tgtport->private;
+ phba = tgtp->phba;
+
+ rc = lpfc_issue_els_rscn(phba->pport, 0);
+ lpfc_printf_log(phba, KERN_ERR, LOG_NVME,
+ "6420 NVMET subsystem change: Notification %s\n",
+ (rc) ? "Failed" : "Sent");
+}
+
static struct nvmet_fc_target_template lpfc_tgttemplate = {
.targetport_delete = lpfc_nvmet_targetport_delete,
.xmt_ls_rsp = lpfc_nvmet_xmt_ls_rsp,
@@ -1146,6 +1222,7 @@ static struct nvmet_fc_target_template lpfc_tgttemplate = {
.fcp_abort = lpfc_nvmet_xmt_fcp_abort,
.fcp_req_release = lpfc_nvmet_xmt_fcp_release,
.defer_rcv = lpfc_nvmet_defer_rcv,
+ .discovery_event = lpfc_nvmet_discovery_event,
.max_hw_queues = 1,
.max_sgl_segments = LPFC_NVMET_DEFAULT_SEGS,
@@ -1497,10 +1574,12 @@ void
lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba,
struct sli4_wcqe_xri_aborted *axri)
{
+#if (IS_ENABLED(CONFIG_NVME_TARGET_FC))
uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri);
uint16_t rxid = bf_get(lpfc_wcqe_xa_remote_xid, axri);
struct lpfc_nvmet_rcv_ctx *ctxp, *next_ctxp;
struct lpfc_nvmet_tgtport *tgtp;
+ struct nvmefc_tgt_fcp_req *req = NULL;
struct lpfc_nodelist *ndlp;
unsigned long iflag = 0;
int rrq_empty = 0;
@@ -1531,7 +1610,7 @@ lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba,
*/
if (ctxp->flag & LPFC_NVMET_CTX_RLS &&
!(ctxp->flag & LPFC_NVMET_ABORT_OP)) {
- list_del(&ctxp->list);
+ list_del_init(&ctxp->list);
released = true;
}
ctxp->flag &= ~LPFC_NVMET_XBUSY;
@@ -1551,7 +1630,7 @@ lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba,
}
lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
- "6318 XB aborted oxid %x flg x%x (%x)\n",
+ "6318 XB aborted oxid x%x flg x%x (%x)\n",
ctxp->oxid, ctxp->flag, released);
if (released)
lpfc_nvmet_ctxbuf_post(phba, ctxp->ctxbuf);
@@ -1562,6 +1641,33 @@ lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba,
}
spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
spin_unlock_irqrestore(&phba->hbalock, iflag);
+
+ ctxp = lpfc_nvmet_get_ctx_for_xri(phba, xri);
+ if (ctxp) {
+ /*
+ * Abort already done by FW, so BA_ACC sent.
+ * However, the transport may be unaware.
+ */
+ lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
+ "6323 NVMET Rcv ABTS xri x%x ctxp state x%x "
+ "flag x%x oxid x%x rxid x%x\n",
+ xri, ctxp->state, ctxp->flag, ctxp->oxid,
+ rxid);
+
+ spin_lock_irqsave(&ctxp->ctxlock, iflag);
+ ctxp->flag |= LPFC_NVMET_ABTS_RCV;
+ ctxp->state = LPFC_NVMET_STE_ABORT;
+ spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
+
+ lpfc_nvmeio_data(phba,
+ "NVMET ABTS RCV: xri x%x CPU %02x rjt %d\n",
+ xri, raw_smp_processor_id(), 0);
+
+ req = &ctxp->ctx.fcp_req;
+ if (req)
+ nvmet_fc_rcv_fcp_abort(phba->targetport, req);
+ }
+#endif
}
int
@@ -1572,19 +1678,23 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport,
struct lpfc_hba *phba = vport->phba;
struct lpfc_nvmet_rcv_ctx *ctxp, *next_ctxp;
struct nvmefc_tgt_fcp_req *rsp;
- uint16_t xri;
+ uint32_t sid;
+ uint16_t oxid, xri;
unsigned long iflag = 0;
- xri = be16_to_cpu(fc_hdr->fh_ox_id);
+ sid = sli4_sid_from_fc_hdr(fc_hdr);
+ oxid = be16_to_cpu(fc_hdr->fh_ox_id);
spin_lock_irqsave(&phba->hbalock, iflag);
spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
list_for_each_entry_safe(ctxp, next_ctxp,
&phba->sli4_hba.lpfc_abts_nvmet_ctx_list,
list) {
- if (ctxp->ctxbuf->sglq->sli4_xritag != xri)
+ if (ctxp->oxid != oxid || ctxp->sid != sid)
continue;
+ xri = ctxp->ctxbuf->sglq->sli4_xritag;
+
spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
spin_unlock_irqrestore(&phba->hbalock, iflag);
@@ -1609,11 +1719,93 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport,
spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
spin_unlock_irqrestore(&phba->hbalock, iflag);
- lpfc_nvmeio_data(phba, "NVMET ABTS RCV: xri x%x CPU %02x rjt %d\n",
- xri, raw_smp_processor_id(), 1);
+ /* check the wait list */
+ if (phba->sli4_hba.nvmet_io_wait_cnt) {
+ struct rqb_dmabuf *nvmebuf;
+ struct fc_frame_header *fc_hdr_tmp;
+ u32 sid_tmp;
+ u16 oxid_tmp;
+ bool found = false;
+
+ spin_lock_irqsave(&phba->sli4_hba.nvmet_io_wait_lock, iflag);
+
+ /* match by oxid and s_id */
+ list_for_each_entry(nvmebuf,
+ &phba->sli4_hba.lpfc_nvmet_io_wait_list,
+ hbuf.list) {
+ fc_hdr_tmp = (struct fc_frame_header *)
+ (nvmebuf->hbuf.virt);
+ oxid_tmp = be16_to_cpu(fc_hdr_tmp->fh_ox_id);
+ sid_tmp = sli4_sid_from_fc_hdr(fc_hdr_tmp);
+ if (oxid_tmp != oxid || sid_tmp != sid)
+ continue;
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
+ "6321 NVMET Rcv ABTS oxid x%x from x%x "
+ "is waiting for a ctxp\n",
+ oxid, sid);
+
+ list_del_init(&nvmebuf->hbuf.list);
+ phba->sli4_hba.nvmet_io_wait_cnt--;
+ found = true;
+ break;
+ }
+ spin_unlock_irqrestore(&phba->sli4_hba.nvmet_io_wait_lock,
+ iflag);
+
+ /* free buffer since already posted a new DMA buffer to RQ */
+ if (found) {
+ nvmebuf->hrq->rqbp->rqb_free_buffer(phba, nvmebuf);
+ /* Respond with BA_ACC accordingly */
+ lpfc_sli4_seq_abort_rsp(vport, fc_hdr, 1);
+ return 0;
+ }
+ }
+
+ /* check active list */
+ ctxp = lpfc_nvmet_get_ctx_for_oxid(phba, oxid, sid);
+ if (ctxp) {
+ xri = ctxp->ctxbuf->sglq->sli4_xritag;
+
+ spin_lock_irqsave(&ctxp->ctxlock, iflag);
+ ctxp->flag |= (LPFC_NVMET_ABTS_RCV | LPFC_NVMET_ABORT_OP);
+ spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
+
+ lpfc_nvmeio_data(phba,
+ "NVMET ABTS RCV: xri x%x CPU %02x rjt %d\n",
+ xri, raw_smp_processor_id(), 0);
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
+ "6322 NVMET Rcv ABTS:acc oxid x%x xri x%x "
+ "flag x%x state x%x\n",
+ ctxp->oxid, xri, ctxp->flag, ctxp->state);
+
+ if (ctxp->flag & LPFC_NVMET_TNOTIFY) {
+ /* Notify the transport */
+ nvmet_fc_rcv_fcp_abort(phba->targetport,
+ &ctxp->ctx.fcp_req);
+ } else {
+ cancel_work_sync(&ctxp->ctxbuf->defer_work);
+ spin_lock_irqsave(&ctxp->ctxlock, iflag);
+ lpfc_nvmet_defer_release(phba, ctxp);
+ spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
+ }
+ if (ctxp->state == LPFC_NVMET_STE_RCV)
+ lpfc_nvmet_unsol_fcp_issue_abort(phba, ctxp, ctxp->sid,
+ ctxp->oxid);
+ else
+ lpfc_nvmet_sol_fcp_issue_abort(phba, ctxp, ctxp->sid,
+ ctxp->oxid);
+
+ lpfc_sli4_seq_abort_rsp(vport, fc_hdr, 1);
+ return 0;
+ }
+
+ lpfc_nvmeio_data(phba, "NVMET ABTS RCV: oxid x%x CPU %02x rjt %d\n",
+ oxid, raw_smp_processor_id(), 1);
lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
- "6320 NVMET Rcv ABTS:rjt xri x%x\n", xri);
+ "6320 NVMET Rcv ABTS:rjt oxid x%x\n", oxid);
/* Respond with BA_RJT accordingly */
lpfc_sli4_seq_abort_rsp(vport, fc_hdr, 0);
@@ -1697,6 +1889,18 @@ lpfc_nvmet_wqfull_process(struct lpfc_hba *phba,
spin_unlock_irqrestore(&pring->ring_lock, iflags);
return;
}
+ if (rc == WQE_SUCCESS) {
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+ if (ctxp->ts_cmd_nvme) {
+ if (ctxp->ctx.fcp_req.op == NVMET_FCOP_RSP)
+ ctxp->ts_status_wqput = ktime_get_ns();
+ else
+ ctxp->ts_data_wqput = ktime_get_ns();
+ }
+#endif
+ } else {
+ WARN_ON(rc);
+ }
}
wq->q_flag &= ~HBA_NVMET_WQFULL;
spin_unlock_irqrestore(&pring->ring_lock, iflags);
@@ -1862,8 +2066,20 @@ lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf)
return;
}
+ if (ctxp->flag & LPFC_NVMET_ABTS_RCV) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR,
+ "6324 IO oxid x%x aborted\n",
+ ctxp->oxid);
+ return;
+ }
+
payload = (uint32_t *)(nvmebuf->dbuf.virt);
tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
+ ctxp->flag |= LPFC_NVMET_TNOTIFY;
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+ if (ctxp->ts_isr_cmd)
+ ctxp->ts_cmd_nvme = ktime_get_ns();
+#endif
/*
* The calling sequence should be:
* nvmet_fc_rcv_fcp_req->lpfc_nvmet_xmt_fcp_op/cmp- req->done
@@ -1913,6 +2129,7 @@ lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf)
phba->sli4_hba.nvmet_mrq_data[qno], 1, qno);
return;
}
+ ctxp->flag &= ~LPFC_NVMET_TNOTIFY;
atomic_inc(&tgtp->rcv_fcp_cmd_drop);
lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR,
"2582 FCP Drop IO x%x: err x%x: x%x x%x x%x\n",
@@ -2002,6 +2219,8 @@ lpfc_nvmet_replenish_context(struct lpfc_hba *phba,
* @phba: pointer to lpfc hba data structure.
* @idx: relative index of MRQ vector
* @nvmebuf: pointer to lpfc nvme command HBQ data structure.
+ * @isr_timestamp: in jiffies.
+ * @cqflag: cq processing information regarding workload.
*
* This routine is used for processing the WQE associated with a unsolicited
* event. It first determines whether there is an existing ndlp that matches
@@ -2014,7 +2233,8 @@ static void
lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba,
uint32_t idx,
struct rqb_dmabuf *nvmebuf,
- uint64_t isr_timestamp)
+ uint64_t isr_timestamp,
+ uint8_t cqflag)
{
struct lpfc_nvmet_rcv_ctx *ctxp;
struct lpfc_nvmet_tgtport *tgtp;
@@ -2101,6 +2321,9 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba,
sid = sli4_sid_from_fc_hdr(fc_hdr);
ctxp = (struct lpfc_nvmet_rcv_ctx *)ctx_buf->context;
+ spin_lock_irqsave(&phba->sli4_hba.t_active_list_lock, iflag);
+ list_add_tail(&ctxp->list, &phba->sli4_hba.t_active_ctx_list);
+ spin_unlock_irqrestore(&phba->sli4_hba.t_active_list_lock, iflag);
if (ctxp->state != LPFC_NVMET_STE_FREE) {
lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR,
"6414 NVMET Context corrupt %d %d oxid x%x\n",
@@ -2123,24 +2346,41 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba,
spin_lock_init(&ctxp->ctxlock);
#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
- if (isr_timestamp) {
+ if (isr_timestamp)
ctxp->ts_isr_cmd = isr_timestamp;
- ctxp->ts_cmd_nvme = ktime_get_ns();
- ctxp->ts_nvme_data = 0;
- ctxp->ts_data_wqput = 0;
- ctxp->ts_isr_data = 0;
- ctxp->ts_data_nvme = 0;
- ctxp->ts_nvme_status = 0;
- ctxp->ts_status_wqput = 0;
- ctxp->ts_isr_status = 0;
- ctxp->ts_status_nvme = 0;
- } else {
- ctxp->ts_cmd_nvme = 0;
- }
+ ctxp->ts_cmd_nvme = 0;
+ ctxp->ts_nvme_data = 0;
+ ctxp->ts_data_wqput = 0;
+ ctxp->ts_isr_data = 0;
+ ctxp->ts_data_nvme = 0;
+ ctxp->ts_nvme_status = 0;
+ ctxp->ts_status_wqput = 0;
+ ctxp->ts_isr_status = 0;
+ ctxp->ts_status_nvme = 0;
#endif
atomic_inc(&tgtp->rcv_fcp_cmd_in);
- lpfc_nvmet_process_rcv_fcp_req(ctx_buf);
+ /* check for cq processing load */
+ if (!cqflag) {
+ lpfc_nvmet_process_rcv_fcp_req(ctx_buf);
+ return;
+ }
+
+ if (!queue_work(phba->wq, &ctx_buf->defer_work)) {
+ atomic_inc(&tgtp->rcv_fcp_cmd_drop);
+ lpfc_printf_log(phba, KERN_ERR, LOG_NVME,
+ "6325 Unable to queue work for oxid x%x. "
+ "FCP Drop IO [x%x x%x x%x]\n",
+ ctxp->oxid,
+ atomic_read(&tgtp->rcv_fcp_cmd_in),
+ atomic_read(&tgtp->rcv_fcp_cmd_out),
+ atomic_read(&tgtp->xmt_fcp_release));
+
+ spin_lock_irqsave(&ctxp->ctxlock, iflag);
+ lpfc_nvmet_defer_release(phba, ctxp);
+ spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
+ lpfc_nvmet_unsol_fcp_issue_abort(phba, ctxp, sid, oxid);
+ }
}
/**
@@ -2177,6 +2417,8 @@ lpfc_nvmet_unsol_ls_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
* @phba: pointer to lpfc hba data structure.
* @idx: relative index of MRQ vector
* @nvmebuf: pointer to received nvme data structure.
+ * @isr_timestamp: in jiffies.
+ * @cqflag: cq processing information regarding workload.
*
* This routine is used to process an unsolicited event received from a SLI
* (Service Level Interface) ring. The actual processing of the data buffer
@@ -2188,14 +2430,14 @@ void
lpfc_nvmet_unsol_fcp_event(struct lpfc_hba *phba,
uint32_t idx,
struct rqb_dmabuf *nvmebuf,
- uint64_t isr_timestamp)
+ uint64_t isr_timestamp,
+ uint8_t cqflag)
{
if (phba->nvmet_support == 0) {
lpfc_rq_buf_free(phba, &nvmebuf->hbuf);
return;
}
- lpfc_nvmet_unsol_fcp_buffer(phba, idx, nvmebuf,
- isr_timestamp);
+ lpfc_nvmet_unsol_fcp_buffer(phba, idx, nvmebuf, isr_timestamp, cqflag);
}
/**
@@ -2662,8 +2904,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
nvmewqe->drvrTimeout = (phba->fc_ratov * 3) + LPFC_DRVR_TIMEOUT;
nvmewqe->context1 = ndlp;
- for (i = 0; i < rsp->sg_cnt; i++) {
- sgel = &rsp->sg[i];
+ for_each_sg(rsp->sg, sgel, rsp->sg_cnt, i) {
physaddr = sg_dma_address(sgel);
cnt = sg_dma_len(sgel);
sgl->addr_hi = putPaddrHigh(physaddr);
@@ -2733,7 +2974,7 @@ lpfc_nvmet_sol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
if ((ctxp->flag & LPFC_NVMET_CTX_RLS) &&
!(ctxp->flag & LPFC_NVMET_XBUSY)) {
spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
- list_del(&ctxp->list);
+ list_del_init(&ctxp->list);
spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
released = true;
}
@@ -2742,7 +2983,7 @@ lpfc_nvmet_sol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
atomic_inc(&tgtp->xmt_abort_rsp);
lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
- "6165 ABORT cmpl: xri x%x flg x%x (%d) "
+ "6165 ABORT cmpl: oxid x%x flg x%x (%d) "
"WCQE: %08x %08x %08x %08x\n",
ctxp->oxid, ctxp->flag, released,
wcqe->word0, wcqe->total_data_placed,
@@ -2817,7 +3058,7 @@ lpfc_nvmet_unsol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
if ((ctxp->flag & LPFC_NVMET_CTX_RLS) &&
!(ctxp->flag & LPFC_NVMET_XBUSY)) {
spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
- list_del(&ctxp->list);
+ list_del_init(&ctxp->list);
spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
released = true;
}
@@ -2826,7 +3067,7 @@ lpfc_nvmet_unsol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
atomic_inc(&tgtp->xmt_abort_rsp);
lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
- "6316 ABTS cmpl xri x%x flg x%x (%x) "
+ "6316 ABTS cmpl oxid x%x flg x%x (%x) "
"WCQE: %08x %08x %08x %08x\n",
ctxp->oxid, ctxp->flag, released,
wcqe->word0, wcqe->total_data_placed,
@@ -3197,7 +3438,7 @@ aerr:
spin_lock_irqsave(&ctxp->ctxlock, flags);
if (ctxp->flag & LPFC_NVMET_CTX_RLS) {
spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
- list_del(&ctxp->list);
+ list_del_init(&ctxp->list);
spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
released = true;
}
@@ -3206,8 +3447,9 @@ aerr:
atomic_inc(&tgtp->xmt_abort_rsp_error);
lpfc_printf_log(phba, KERN_ERR, LOG_NVME_ABTS,
- "6135 Failed to Issue ABTS for oxid x%x. Status x%x\n",
- ctxp->oxid, rc);
+ "6135 Failed to Issue ABTS for oxid x%x. Status x%x "
+ "(%x)\n",
+ ctxp->oxid, rc, released);
if (released)
lpfc_nvmet_ctxbuf_post(phba, ctxp->ctxbuf);
return 1;
diff --git a/drivers/scsi/lpfc/lpfc_nvmet.h b/drivers/scsi/lpfc/lpfc_nvmet.h
index 2f3f603d94c4..8ff67deac10a 100644
--- a/drivers/scsi/lpfc/lpfc_nvmet.h
+++ b/drivers/scsi/lpfc/lpfc_nvmet.h
@@ -140,6 +140,7 @@ struct lpfc_nvmet_rcv_ctx {
#define LPFC_NVMET_ABTS_RCV 0x10 /* ABTS received on exchange */
#define LPFC_NVMET_CTX_REUSE_WQ 0x20 /* ctx reused via WQ */
#define LPFC_NVMET_DEFER_WQFULL 0x40 /* Waiting on a free WQE */
+#define LPFC_NVMET_TNOTIFY 0x80 /* notify transport of abts */
struct rqb_dmabuf *rqb_buffer;
struct lpfc_nvmet_ctxbuf *ctxbuf;
struct lpfc_sli4_hdw_queue *hdwq;
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index ba996fbde89b..f9df800e7067 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -3879,10 +3879,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
*/
spin_lock(&lpfc_cmd->buf_lock);
lpfc_cmd->cur_iocbq.iocb_flag &= ~LPFC_DRIVER_ABORTED;
- if (lpfc_cmd->waitq) {
+ if (lpfc_cmd->waitq)
wake_up(lpfc_cmd->waitq);
- lpfc_cmd->waitq = NULL;
- }
spin_unlock(&lpfc_cmd->buf_lock);
lpfc_release_scsi_buf(phba, lpfc_cmd);
@@ -4718,6 +4716,9 @@ wait_for_cmpl:
iocb->sli4_xritag, ret,
cmnd->device->id, cmnd->device->lun);
}
+
+ lpfc_cmd->waitq = NULL;
+
spin_unlock(&lpfc_cmd->buf_lock);
goto out;
@@ -4797,7 +4798,12 @@ lpfc_check_fcp_rsp(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd)
rsp_info,
rsp_len, rsp_info_code);
- if ((fcprsp->rspStatus2&RSP_LEN_VALID) && (rsp_len == 8)) {
+ /* If FCP_RSP_LEN_VALID bit is one, then the FCP_RSP_LEN
+ * field specifies the number of valid bytes of FCP_RSP_INFO.
+ * The FCP_RSP_LEN field shall be set to 0x04 or 0x08
+ */
+ if ((fcprsp->rspStatus2 & RSP_LEN_VALID) &&
+ ((rsp_len == 8) || (rsp_len == 4))) {
switch (rsp_info_code) {
case RSP_NO_FAILURE:
lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
@@ -5741,7 +5747,7 @@ lpfc_enable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,
/* Create an lun info structure and add to list of luns */
lun_info = lpfc_create_device_data(phba, vport_wwpn, target_wwpn, lun,
- pri, false);
+ pri, true);
if (lun_info) {
lun_info->oas_enabled = true;
lun_info->priority = pri;
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index d1512e4f9791..f9e6a135d656 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -108,7 +108,7 @@ lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq)
* endianness. This function can be called with or without
* lock.
**/
-void
+static void
lpfc_sli4_pcimem_bcopy(void *srcp, void *destp, uint32_t cnt)
{
uint64_t *src = srcp;
@@ -5571,6 +5571,7 @@ lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba)
int qidx;
struct lpfc_sli4_hba *sli4_hba = &phba->sli4_hba;
struct lpfc_sli4_hdw_queue *qp;
+ struct lpfc_queue *eq;
sli4_hba->sli4_write_cq_db(phba, sli4_hba->mbx_cq, 0, LPFC_QUEUE_REARM);
sli4_hba->sli4_write_cq_db(phba, sli4_hba->els_cq, 0, LPFC_QUEUE_REARM);
@@ -5578,18 +5579,24 @@ lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba)
sli4_hba->sli4_write_cq_db(phba, sli4_hba->nvmels_cq, 0,
LPFC_QUEUE_REARM);
- qp = sli4_hba->hdwq;
if (sli4_hba->hdwq) {
+ /* Loop thru all Hardware Queues */
for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) {
- sli4_hba->sli4_write_cq_db(phba, qp[qidx].fcp_cq, 0,
+ qp = &sli4_hba->hdwq[qidx];
+ /* ARM the corresponding CQ */
+ sli4_hba->sli4_write_cq_db(phba, qp->fcp_cq, 0,
LPFC_QUEUE_REARM);
- sli4_hba->sli4_write_cq_db(phba, qp[qidx].nvme_cq, 0,
+ sli4_hba->sli4_write_cq_db(phba, qp->nvme_cq, 0,
LPFC_QUEUE_REARM);
}
- for (qidx = 0; qidx < phba->cfg_irq_chann; qidx++)
- sli4_hba->sli4_write_eq_db(phba, qp[qidx].hba_eq,
- 0, LPFC_QUEUE_REARM);
+ /* Loop thru all IRQ vectors */
+ for (qidx = 0; qidx < phba->cfg_irq_chann; qidx++) {
+ eq = sli4_hba->hba_eq_hdl[qidx].eq;
+ /* ARM the corresponding EQ */
+ sli4_hba->sli4_write_eq_db(phba, eq,
+ 0, LPFC_QUEUE_REARM);
+ }
}
if (phba->nvmet_support) {
@@ -7875,26 +7882,28 @@ lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba)
* and will process all the completions associated with the eq for the
* mailbox completion queue.
**/
-bool
+static bool
lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba)
{
struct lpfc_sli4_hba *sli4_hba = &phba->sli4_hba;
uint32_t eqidx;
struct lpfc_queue *fpeq = NULL;
+ struct lpfc_queue *eq;
bool mbox_pending;
if (unlikely(!phba) || (phba->sli_rev != LPFC_SLI_REV4))
return false;
- /* Find the eq associated with the mcq */
-
- if (sli4_hba->hdwq)
- for (eqidx = 0; eqidx < phba->cfg_irq_chann; eqidx++)
- if (sli4_hba->hdwq[eqidx].hba_eq->queue_id ==
- sli4_hba->mbx_cq->assoc_qid) {
- fpeq = sli4_hba->hdwq[eqidx].hba_eq;
+ /* Find the EQ associated with the mbox CQ */
+ if (sli4_hba->hdwq) {
+ for (eqidx = 0; eqidx < phba->cfg_irq_chann; eqidx++) {
+ eq = phba->sli4_hba.hba_eq_hdl[eqidx].eq;
+ if (eq->queue_id == sli4_hba->mbx_cq->assoc_qid) {
+ fpeq = eq;
break;
}
+ }
+ }
if (!fpeq)
return false;
@@ -9398,6 +9407,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
if (if_type >= LPFC_SLI_INTF_IF_TYPE_2) {
if (pcmd && (*pcmd == ELS_CMD_FLOGI ||
*pcmd == ELS_CMD_SCR ||
+ *pcmd == ELS_CMD_RSCN_XMT ||
*pcmd == ELS_CMD_FDISC ||
*pcmd == ELS_CMD_LOGO ||
*pcmd == ELS_CMD_PLOGI)) {
@@ -13604,14 +13614,9 @@ __lpfc_sli4_process_cq(struct lpfc_hba *phba, struct lpfc_queue *cq,
goto rearm_and_exit;
/* Process all the entries to the CQ */
+ cq->q_flag = 0;
cqe = lpfc_sli4_cq_get(cq);
while (cqe) {
-#if defined(CONFIG_SCSI_LPFC_DEBUG_FS) && defined(BUILD_NVME)
- if (phba->ktime_on)
- cq->isr_timestamp = ktime_get_ns();
- else
- cq->isr_timestamp = 0;
-#endif
workposted |= handler(phba, cq, cqe);
__lpfc_sli4_consume_cqe(phba, cq, cqe);
@@ -13625,6 +13630,9 @@ __lpfc_sli4_process_cq(struct lpfc_hba *phba, struct lpfc_queue *cq,
consumed = 0;
}
+ if (count == LPFC_NVMET_CQ_NOTIFY)
+ cq->q_flag |= HBA_NVMET_CQ_NOTIFY;
+
cqe = lpfc_sli4_cq_get(cq);
}
if (count >= phba->cfg_cq_poll_threshold) {
@@ -13940,10 +13948,10 @@ lpfc_sli4_nvmet_handle_rcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
goto drop;
if (fc_hdr->fh_type == FC_TYPE_FCP) {
- dma_buf->bytes_recv = bf_get(lpfc_rcqe_length, rcqe);
+ dma_buf->bytes_recv = bf_get(lpfc_rcqe_length, rcqe);
lpfc_nvmet_unsol_fcp_event(
- phba, idx, dma_buf,
- cq->isr_timestamp);
+ phba, idx, dma_buf, cq->isr_timestamp,
+ cq->q_flag & HBA_NVMET_CQ_NOTIFY);
return false;
}
drop:
@@ -14109,6 +14117,12 @@ process_cq:
}
work_cq:
+#if defined(CONFIG_SCSI_LPFC_DEBUG_FS)
+ if (phba->ktime_on)
+ cq->isr_timestamp = ktime_get_ns();
+ else
+ cq->isr_timestamp = 0;
+#endif
if (!queue_work_on(cq->chann, phba->wq, &cq->irqwork))
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"0363 Cannot schedule soft IRQ "
@@ -14235,7 +14249,7 @@ lpfc_sli4_hba_intr_handler(int irq, void *dev_id)
return IRQ_NONE;
/* Get to the EQ struct associated with this vector */
- fpeq = phba->sli4_hba.hdwq[hba_eqidx].hba_eq;
+ fpeq = phba->sli4_hba.hba_eq_hdl[hba_eqidx].eq;
if (unlikely(!fpeq))
return IRQ_NONE;
@@ -14520,7 +14534,7 @@ lpfc_modify_hba_eq_delay(struct lpfc_hba *phba, uint32_t startq,
/* set values by EQ_DELAY register if supported */
if (phba->sli.sli_flag & LPFC_SLI_USE_EQDR) {
for (qidx = startq; qidx < phba->cfg_irq_chann; qidx++) {
- eq = phba->sli4_hba.hdwq[qidx].hba_eq;
+ eq = phba->sli4_hba.hba_eq_hdl[qidx].eq;
if (!eq)
continue;
@@ -14529,7 +14543,6 @@ lpfc_modify_hba_eq_delay(struct lpfc_hba *phba, uint32_t startq,
if (++cnt >= numq)
break;
}
-
return;
}
@@ -14557,7 +14570,7 @@ lpfc_modify_hba_eq_delay(struct lpfc_hba *phba, uint32_t startq,
dmult = LPFC_DMULT_MAX;
for (qidx = startq; qidx < phba->cfg_irq_chann; qidx++) {
- eq = phba->sli4_hba.hdwq[qidx].hba_eq;
+ eq = phba->sli4_hba.hba_eq_hdl[qidx].eq;
if (!eq)
continue;
eq->q_mode = usdelay;
@@ -14659,8 +14672,10 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint32_t imax)
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"0360 Unsupported EQ count. (%d)\n",
eq->entry_count);
- if (eq->entry_count < 256)
- return -EINVAL;
+ if (eq->entry_count < 256) {
+ status = -EINVAL;
+ goto out;
+ }
/* fall through - otherwise default to smallest count */
case 256:
bf_set(lpfc_eq_context_count, &eq_create->u.request.context,
@@ -14712,7 +14727,7 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint32_t imax)
eq->host_index = 0;
eq->notify_interval = LPFC_EQ_NOTIFY_INTRVL;
eq->max_proc_limit = LPFC_EQ_MAX_PROC_LIMIT;
-
+out:
mempool_free(mbox, phba->mbox_mem_pool);
return status;
}
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index 8e4fd1a98023..3aeca387b22a 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -197,6 +197,8 @@ struct lpfc_queue {
#define LPFC_DB_LIST_FORMAT 0x02
uint8_t q_flag;
#define HBA_NVMET_WQFULL 0x1 /* We hit WQ Full condition for NVMET */
+#define HBA_NVMET_CQ_NOTIFY 0x1 /* LPFC_NVMET_CQ_NOTIFY CQEs this EQE */
+#define LPFC_NVMET_CQ_NOTIFY 4
void __iomem *db_regaddr;
uint16_t dpp_enable;
uint16_t dpp_id;
@@ -450,6 +452,7 @@ struct lpfc_hba_eq_hdl {
uint32_t idx;
char handler_name[LPFC_SLI4_HANDLER_NAME_SZ];
struct lpfc_hba *phba;
+ struct lpfc_queue *eq;
};
/*BB Credit recovery value*/
@@ -512,6 +515,7 @@ struct lpfc_pc_sli4_params {
#define LPFC_WQ_SZ64_SUPPORT 1
#define LPFC_WQ_SZ128_SUPPORT 2
uint8_t wqpcnt;
+ uint8_t nvme;
};
#define LPFC_CQ_4K_PAGE_SZ 0x1
@@ -546,7 +550,10 @@ struct lpfc_vector_map_info {
uint16_t irq;
uint16_t eq;
uint16_t hdwq;
- uint16_t hyper;
+ uint16_t flag;
+#define LPFC_CPU_MAP_HYPER 0x1
+#define LPFC_CPU_MAP_UNASSIGN 0x2
+#define LPFC_CPU_FIRST_IRQ 0x4
};
#define LPFC_VECTOR_MAP_EMPTY 0xffff
@@ -843,6 +850,8 @@ struct lpfc_sli4_hba {
struct list_head lpfc_nvmet_sgl_list;
spinlock_t abts_nvmet_buf_list_lock; /* list of aborted NVMET IOs */
struct list_head lpfc_abts_nvmet_ctx_list;
+ spinlock_t t_active_list_lock; /* list of active NVMET IOs */
+ struct list_head t_active_ctx_list;
struct list_head lpfc_nvmet_io_wait_list;
struct lpfc_nvmet_ctx_info *nvmet_ctx_info;
struct lpfc_sglq **lpfc_sglq_active_list;
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index 220a932fe943..f7e93aaf1e00 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -20,7 +20,7 @@
* included with this package. *
*******************************************************************/
-#define LPFC_DRIVER_VERSION "12.2.0.2"
+#define LPFC_DRIVER_VERSION "12.2.0.3"
#define LPFC_DRIVER_NAME "lpfc"
/* Used for SLI 2/3 */
diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c
index dba9517d9553..9c5566217ef6 100644
--- a/drivers/scsi/mac_scsi.c
+++ b/drivers/scsi/mac_scsi.c
@@ -4,6 +4,8 @@
*
* Copyright 1998, Michael Schmitz <mschmitz@lbl.gov>
*
+ * Copyright 2019 Finn Thain
+ *
* derived in part from:
*/
/*
@@ -12,6 +14,7 @@
* Copyright 1995, Russell King
*/
+#include <linux/delay.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/ioport.h>
@@ -22,6 +25,7 @@
#include <asm/hwtest.h>
#include <asm/io.h>
+#include <asm/macintosh.h>
#include <asm/macints.h>
#include <asm/setup.h>
@@ -53,7 +57,7 @@ static int setup_cmd_per_lun = -1;
module_param(setup_cmd_per_lun, int, 0);
static int setup_sg_tablesize = -1;
module_param(setup_sg_tablesize, int, 0);
-static int setup_use_pdma = -1;
+static int setup_use_pdma = 512;
module_param(setup_use_pdma, int, 0);
static int setup_hostid = -1;
module_param(setup_hostid, int, 0);
@@ -90,223 +94,318 @@ static int __init mac_scsi_setup(char *str)
__setup("mac5380=", mac_scsi_setup);
#endif /* !MODULE */
-/* Pseudo DMA asm originally by Ove Edlund */
-
-#define CP_IO_TO_MEM(s,d,n) \
-__asm__ __volatile__ \
- (" cmp.w #4,%2\n" \
- " bls 8f\n" \
- " move.w %1,%%d0\n" \
- " neg.b %%d0\n" \
- " and.w #3,%%d0\n" \
- " sub.w %%d0,%2\n" \
- " bra 2f\n" \
- " 1: move.b (%0),(%1)+\n" \
- " 2: dbf %%d0,1b\n" \
- " move.w %2,%%d0\n" \
- " lsr.w #5,%%d0\n" \
- " bra 4f\n" \
- " 3: move.l (%0),(%1)+\n" \
- "31: move.l (%0),(%1)+\n" \
- "32: move.l (%0),(%1)+\n" \
- "33: move.l (%0),(%1)+\n" \
- "34: move.l (%0),(%1)+\n" \
- "35: move.l (%0),(%1)+\n" \
- "36: move.l (%0),(%1)+\n" \
- "37: move.l (%0),(%1)+\n" \
- " 4: dbf %%d0,3b\n" \
- " move.w %2,%%d0\n" \
- " lsr.w #2,%%d0\n" \
- " and.w #7,%%d0\n" \
- " bra 6f\n" \
- " 5: move.l (%0),(%1)+\n" \
- " 6: dbf %%d0,5b\n" \
- " and.w #3,%2\n" \
- " bra 8f\n" \
- " 7: move.b (%0),(%1)+\n" \
- " 8: dbf %2,7b\n" \
- " moveq.l #0, %2\n" \
- " 9: \n" \
- ".section .fixup,\"ax\"\n" \
- " .even\n" \
- "91: moveq.l #1, %2\n" \
- " jra 9b\n" \
- "94: moveq.l #4, %2\n" \
- " jra 9b\n" \
- ".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 4\n" \
- " .long 1b,91b\n" \
- " .long 3b,94b\n" \
- " .long 31b,94b\n" \
- " .long 32b,94b\n" \
- " .long 33b,94b\n" \
- " .long 34b,94b\n" \
- " .long 35b,94b\n" \
- " .long 36b,94b\n" \
- " .long 37b,94b\n" \
- " .long 5b,94b\n" \
- " .long 7b,91b\n" \
- ".previous" \
- : "=a"(s), "=a"(d), "=d"(n) \
- : "0"(s), "1"(d), "2"(n) \
- : "d0")
+/*
+ * According to "Inside Macintosh: Devices", Mac OS requires disk drivers to
+ * specify the number of bytes between the delays expected from a SCSI target.
+ * This allows the operating system to "prevent bus errors when a target fails
+ * to deliver the next byte within the processor bus error timeout period."
+ * Linux SCSI drivers lack knowledge of the timing behaviour of SCSI targets
+ * so bus errors are unavoidable.
+ *
+ * If a MOVE.B instruction faults, we assume that zero bytes were transferred
+ * and simply retry. That assumption probably depends on target behaviour but
+ * seems to hold up okay. The NOP provides synchronization: without it the
+ * fault can sometimes occur after the program counter has moved past the
+ * offending instruction. Post-increment addressing can't be used.
+ */
+
+#define MOVE_BYTE(operands) \
+ asm volatile ( \
+ "1: moveb " operands " \n" \
+ "11: nop \n" \
+ " addq #1,%0 \n" \
+ " subq #1,%1 \n" \
+ "40: \n" \
+ " \n" \
+ ".section .fixup,\"ax\" \n" \
+ ".even \n" \
+ "90: movel #1, %2 \n" \
+ " jra 40b \n" \
+ ".previous \n" \
+ " \n" \
+ ".section __ex_table,\"a\" \n" \
+ ".align 4 \n" \
+ ".long 1b,90b \n" \
+ ".long 11b,90b \n" \
+ ".previous \n" \
+ : "+a" (addr), "+r" (n), "+r" (result) : "a" (io))
+
+/*
+ * If a MOVE.W (or MOVE.L) instruction faults, it cannot be retried because
+ * the residual byte count would be uncertain. In that situation the MOVE_WORD
+ * macro clears n in the fixup section to abort the transfer.
+ */
+
+#define MOVE_WORD(operands) \
+ asm volatile ( \
+ "1: movew " operands " \n" \
+ "11: nop \n" \
+ " subq #2,%1 \n" \
+ "40: \n" \
+ " \n" \
+ ".section .fixup,\"ax\" \n" \
+ ".even \n" \
+ "90: movel #0, %1 \n" \
+ " movel #2, %2 \n" \
+ " jra 40b \n" \
+ ".previous \n" \
+ " \n" \
+ ".section __ex_table,\"a\" \n" \
+ ".align 4 \n" \
+ ".long 1b,90b \n" \
+ ".long 11b,90b \n" \
+ ".previous \n" \
+ : "+a" (addr), "+r" (n), "+r" (result) : "a" (io))
+
+#define MOVE_16_WORDS(operands) \
+ asm volatile ( \
+ "1: movew " operands " \n" \
+ "2: movew " operands " \n" \
+ "3: movew " operands " \n" \
+ "4: movew " operands " \n" \
+ "5: movew " operands " \n" \
+ "6: movew " operands " \n" \
+ "7: movew " operands " \n" \
+ "8: movew " operands " \n" \
+ "9: movew " operands " \n" \
+ "10: movew " operands " \n" \
+ "11: movew " operands " \n" \
+ "12: movew " operands " \n" \
+ "13: movew " operands " \n" \
+ "14: movew " operands " \n" \
+ "15: movew " operands " \n" \
+ "16: movew " operands " \n" \
+ "17: nop \n" \
+ " subl #32,%1 \n" \
+ "40: \n" \
+ " \n" \
+ ".section .fixup,\"ax\" \n" \
+ ".even \n" \
+ "90: movel #0, %1 \n" \
+ " movel #2, %2 \n" \
+ " jra 40b \n" \
+ ".previous \n" \
+ " \n" \
+ ".section __ex_table,\"a\" \n" \
+ ".align 4 \n" \
+ ".long 1b,90b \n" \
+ ".long 2b,90b \n" \
+ ".long 3b,90b \n" \
+ ".long 4b,90b \n" \
+ ".long 5b,90b \n" \
+ ".long 6b,90b \n" \
+ ".long 7b,90b \n" \
+ ".long 8b,90b \n" \
+ ".long 9b,90b \n" \
+ ".long 10b,90b \n" \
+ ".long 11b,90b \n" \
+ ".long 12b,90b \n" \
+ ".long 13b,90b \n" \
+ ".long 14b,90b \n" \
+ ".long 15b,90b \n" \
+ ".long 16b,90b \n" \
+ ".long 17b,90b \n" \
+ ".previous \n" \
+ : "+a" (addr), "+r" (n), "+r" (result) : "a" (io))
+
+#define MAC_PDMA_DELAY 32
+
+static inline int mac_pdma_recv(void __iomem *io, unsigned char *start, int n)
+{
+ unsigned char *addr = start;
+ int result = 0;
+
+ if (n >= 1) {
+ MOVE_BYTE("%3@,%0@");
+ if (result)
+ goto out;
+ }
+ if (n >= 1 && ((unsigned long)addr & 1)) {
+ MOVE_BYTE("%3@,%0@");
+ if (result)
+ goto out;
+ }
+ while (n >= 32)
+ MOVE_16_WORDS("%3@,%0@+");
+ while (n >= 2)
+ MOVE_WORD("%3@,%0@+");
+ if (result)
+ return start - addr; /* Negated to indicate uncertain length */
+ if (n == 1)
+ MOVE_BYTE("%3@,%0@");
+out:
+ return addr - start;
+}
+
+static inline int mac_pdma_send(unsigned char *start, void __iomem *io, int n)
+{
+ unsigned char *addr = start;
+ int result = 0;
+
+ if (n >= 1) {
+ MOVE_BYTE("%0@,%3@");
+ if (result)
+ goto out;
+ }
+ if (n >= 1 && ((unsigned long)addr & 1)) {
+ MOVE_BYTE("%0@,%3@");
+ if (result)
+ goto out;
+ }
+ while (n >= 32)
+ MOVE_16_WORDS("%0@+,%3@");
+ while (n >= 2)
+ MOVE_WORD("%0@+,%3@");
+ if (result)
+ return start - addr; /* Negated to indicate uncertain length */
+ if (n == 1)
+ MOVE_BYTE("%0@,%3@");
+out:
+ return addr - start;
+}
+
+/* The "SCSI DMA" chip on the IIfx implements this register. */
+#define CTRL_REG 0x8
+#define CTRL_INTERRUPTS_ENABLE BIT(1)
+#define CTRL_HANDSHAKE_MODE BIT(3)
+
+static inline void write_ctrl_reg(struct NCR5380_hostdata *hostdata, u32 value)
+{
+ out_be32(hostdata->io + (CTRL_REG << 4), value);
+}
static inline int macscsi_pread(struct NCR5380_hostdata *hostdata,
unsigned char *dst, int len)
{
u8 __iomem *s = hostdata->pdma_io + (INPUT_DATA_REG << 4);
unsigned char *d = dst;
- int n = len;
- int transferred;
+ int result = 0;
+
+ hostdata->pdma_residual = len;
while (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG,
BASR_DRQ | BASR_PHASE_MATCH,
BASR_DRQ | BASR_PHASE_MATCH, HZ / 64)) {
- CP_IO_TO_MEM(s, d, n);
+ int bytes;
+
+ if (macintosh_config->ident == MAC_MODEL_IIFX)
+ write_ctrl_reg(hostdata, CTRL_HANDSHAKE_MODE |
+ CTRL_INTERRUPTS_ENABLE);
- transferred = d - dst - n;
- hostdata->pdma_residual = len - transferred;
+ bytes = mac_pdma_recv(s, d, min(hostdata->pdma_residual, 512));
- /* No bus error. */
- if (n == 0)
- return 0;
+ if (bytes > 0) {
+ d += bytes;
+ hostdata->pdma_residual -= bytes;
+ }
+
+ if (hostdata->pdma_residual == 0)
+ goto out;
- /* Target changed phase early? */
if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ,
- BUS_AND_STATUS_REG, BASR_ACK, BASR_ACK, HZ / 64) < 0)
- scmd_printk(KERN_ERR, hostdata->connected,
+ BUS_AND_STATUS_REG, BASR_ACK,
+ BASR_ACK, HZ / 64) < 0)
+ scmd_printk(KERN_DEBUG, hostdata->connected,
"%s: !REQ and !ACK\n", __func__);
if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH))
- return 0;
+ goto out;
+
+ if (bytes == 0)
+ udelay(MAC_PDMA_DELAY);
+
+ if (bytes >= 0)
+ continue;
dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host,
- "%s: bus error (%d/%d)\n", __func__, transferred, len);
+ "%s: bus error (%d/%d)\n", __func__, d - dst, len);
NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
- d = dst + transferred;
- n = len - transferred;
+ result = -1;
+ goto out;
}
scmd_printk(KERN_ERR, hostdata->connected,
"%s: phase mismatch or !DRQ\n", __func__);
NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
- return -1;
+ result = -1;
+out:
+ if (macintosh_config->ident == MAC_MODEL_IIFX)
+ write_ctrl_reg(hostdata, CTRL_INTERRUPTS_ENABLE);
+ return result;
}
-
-#define CP_MEM_TO_IO(s,d,n) \
-__asm__ __volatile__ \
- (" cmp.w #4,%2\n" \
- " bls 8f\n" \
- " move.w %0,%%d0\n" \
- " neg.b %%d0\n" \
- " and.w #3,%%d0\n" \
- " sub.w %%d0,%2\n" \
- " bra 2f\n" \
- " 1: move.b (%0)+,(%1)\n" \
- " 2: dbf %%d0,1b\n" \
- " move.w %2,%%d0\n" \
- " lsr.w #5,%%d0\n" \
- " bra 4f\n" \
- " 3: move.l (%0)+,(%1)\n" \
- "31: move.l (%0)+,(%1)\n" \
- "32: move.l (%0)+,(%1)\n" \
- "33: move.l (%0)+,(%1)\n" \
- "34: move.l (%0)+,(%1)\n" \
- "35: move.l (%0)+,(%1)\n" \
- "36: move.l (%0)+,(%1)\n" \
- "37: move.l (%0)+,(%1)\n" \
- " 4: dbf %%d0,3b\n" \
- " move.w %2,%%d0\n" \
- " lsr.w #2,%%d0\n" \
- " and.w #7,%%d0\n" \
- " bra 6f\n" \
- " 5: move.l (%0)+,(%1)\n" \
- " 6: dbf %%d0,5b\n" \
- " and.w #3,%2\n" \
- " bra 8f\n" \
- " 7: move.b (%0)+,(%1)\n" \
- " 8: dbf %2,7b\n" \
- " moveq.l #0, %2\n" \
- " 9: \n" \
- ".section .fixup,\"ax\"\n" \
- " .even\n" \
- "91: moveq.l #1, %2\n" \
- " jra 9b\n" \
- "94: moveq.l #4, %2\n" \
- " jra 9b\n" \
- ".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 4\n" \
- " .long 1b,91b\n" \
- " .long 3b,94b\n" \
- " .long 31b,94b\n" \
- " .long 32b,94b\n" \
- " .long 33b,94b\n" \
- " .long 34b,94b\n" \
- " .long 35b,94b\n" \
- " .long 36b,94b\n" \
- " .long 37b,94b\n" \
- " .long 5b,94b\n" \
- " .long 7b,91b\n" \
- ".previous" \
- : "=a"(s), "=a"(d), "=d"(n) \
- : "0"(s), "1"(d), "2"(n) \
- : "d0")
-
static inline int macscsi_pwrite(struct NCR5380_hostdata *hostdata,
unsigned char *src, int len)
{
unsigned char *s = src;
u8 __iomem *d = hostdata->pdma_io + (OUTPUT_DATA_REG << 4);
- int n = len;
- int transferred;
+ int result = 0;
+
+ hostdata->pdma_residual = len;
while (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG,
BASR_DRQ | BASR_PHASE_MATCH,
BASR_DRQ | BASR_PHASE_MATCH, HZ / 64)) {
- CP_MEM_TO_IO(s, d, n);
+ int bytes;
- transferred = s - src - n;
- hostdata->pdma_residual = len - transferred;
+ if (macintosh_config->ident == MAC_MODEL_IIFX)
+ write_ctrl_reg(hostdata, CTRL_HANDSHAKE_MODE |
+ CTRL_INTERRUPTS_ENABLE);
- /* Target changed phase early? */
- if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ,
- BUS_AND_STATUS_REG, BASR_ACK, BASR_ACK, HZ / 64) < 0)
- scmd_printk(KERN_ERR, hostdata->connected,
- "%s: !REQ and !ACK\n", __func__);
- if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH))
- return 0;
+ bytes = mac_pdma_send(s, d, min(hostdata->pdma_residual, 512));
+
+ if (bytes > 0) {
+ s += bytes;
+ hostdata->pdma_residual -= bytes;
+ }
- /* No bus error. */
- if (n == 0) {
+ if (hostdata->pdma_residual == 0) {
if (NCR5380_poll_politely(hostdata, TARGET_COMMAND_REG,
TCR_LAST_BYTE_SENT,
- TCR_LAST_BYTE_SENT, HZ / 64) < 0)
+ TCR_LAST_BYTE_SENT,
+ HZ / 64) < 0) {
scmd_printk(KERN_ERR, hostdata->connected,
"%s: Last Byte Sent timeout\n", __func__);
- return 0;
+ result = -1;
+ }
+ goto out;
}
+ if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ,
+ BUS_AND_STATUS_REG, BASR_ACK,
+ BASR_ACK, HZ / 64) < 0)
+ scmd_printk(KERN_DEBUG, hostdata->connected,
+ "%s: !REQ and !ACK\n", __func__);
+ if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH))
+ goto out;
+
+ if (bytes == 0)
+ udelay(MAC_PDMA_DELAY);
+
+ if (bytes >= 0)
+ continue;
+
dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host,
- "%s: bus error (%d/%d)\n", __func__, transferred, len);
+ "%s: bus error (%d/%d)\n", __func__, s - src, len);
NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
- s = src + transferred;
- n = len - transferred;
+ result = -1;
+ goto out;
}
scmd_printk(KERN_ERR, hostdata->connected,
"%s: phase mismatch or !DRQ\n", __func__);
NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
-
- return -1;
+ result = -1;
+out:
+ if (macintosh_config->ident == MAC_MODEL_IIFX)
+ write_ctrl_reg(hostdata, CTRL_INTERRUPTS_ENABLE);
+ return result;
}
static int macscsi_dma_xfer_len(struct NCR5380_hostdata *hostdata,
struct scsi_cmnd *cmd)
{
if (hostdata->flags & FLAG_NO_PSEUDO_DMA ||
- cmd->SCp.this_residual < 16)
+ cmd->SCp.this_residual < setup_use_pdma)
return 0;
return cmd->SCp.this_residual;
diff --git a/drivers/scsi/megaraid/Kconfig.megaraid b/drivers/scsi/megaraid/Kconfig.megaraid
index e630e41dc843..2adc2afd9f91 100644
--- a/drivers/scsi/megaraid/Kconfig.megaraid
+++ b/drivers/scsi/megaraid/Kconfig.megaraid
@@ -79,6 +79,7 @@ config MEGARAID_LEGACY
config MEGARAID_SAS
tristate "LSI Logic MegaRAID SAS RAID Module"
depends on PCI && SCSI
+ select IRQ_POLL
help
Module for LSI Logic's SAS based RAID controllers.
To compile this driver as a module, choose 'm' here.
diff --git a/drivers/scsi/megaraid/Makefile b/drivers/scsi/megaraid/Makefile
index 6e74d21227a5..12177e4cae65 100644
--- a/drivers/scsi/megaraid/Makefile
+++ b/drivers/scsi/megaraid/Makefile
@@ -3,4 +3,4 @@ obj-$(CONFIG_MEGARAID_MM) += megaraid_mm.o
obj-$(CONFIG_MEGARAID_MAILBOX) += megaraid_mbox.o
obj-$(CONFIG_MEGARAID_SAS) += megaraid_sas.o
megaraid_sas-objs := megaraid_sas_base.o megaraid_sas_fusion.o \
- megaraid_sas_fp.o
+ megaraid_sas_fp.o megaraid_sas_debugfs.o
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index fe9a785b7b6f..ca724fe91b8d 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -21,8 +21,8 @@
/*
* MegaRAID SAS Driver meta data
*/
-#define MEGASAS_VERSION "07.707.51.00-rc1"
-#define MEGASAS_RELDATE "February 7, 2019"
+#define MEGASAS_VERSION "07.710.06.00-rc1"
+#define MEGASAS_RELDATE "June 18, 2019"
/*
* Device IDs
@@ -52,6 +52,10 @@
#define PCI_DEVICE_ID_LSI_AERO_10E2 0x10e2
#define PCI_DEVICE_ID_LSI_AERO_10E5 0x10e5
#define PCI_DEVICE_ID_LSI_AERO_10E6 0x10e6
+#define PCI_DEVICE_ID_LSI_AERO_10E0 0x10e0
+#define PCI_DEVICE_ID_LSI_AERO_10E3 0x10e3
+#define PCI_DEVICE_ID_LSI_AERO_10E4 0x10e4
+#define PCI_DEVICE_ID_LSI_AERO_10E7 0x10e7
/*
* Intel HBA SSDIDs
@@ -123,6 +127,8 @@
#define MFI_RESET_ADAPTER 0x00000002
#define MEGAMFI_FRAME_SIZE 64
+#define MFI_STATE_FAULT_CODE 0x0FFF0000
+#define MFI_STATE_FAULT_SUBCODE 0x0000FF00
/*
* During FW init, clear pending cmds & reset state using inbound_msg_0
*
@@ -190,6 +196,7 @@ enum MFI_CMD_OP {
MFI_CMD_SMP = 0x7,
MFI_CMD_STP = 0x8,
MFI_CMD_NVME = 0x9,
+ MFI_CMD_TOOLBOX = 0xa,
MFI_CMD_OP_COUNT,
MFI_CMD_INVALID = 0xff
};
@@ -1449,7 +1456,39 @@ struct megasas_ctrl_info {
u8 reserved6[64];
- u32 rsvdForAdptOp[64];
+ struct {
+ #if defined(__BIG_ENDIAN_BITFIELD)
+ u32 reserved:19;
+ u32 support_pci_lane_margining: 1;
+ u32 support_psoc_update:1;
+ u32 support_force_personality_change:1;
+ u32 support_fde_type_mix:1;
+ u32 support_snap_dump:1;
+ u32 support_nvme_tm:1;
+ u32 support_oce_only:1;
+ u32 support_ext_mfg_vpd:1;
+ u32 support_pcie:1;
+ u32 support_cvhealth_info:1;
+ u32 support_profile_change:2;
+ u32 mr_config_ext2_supported:1;
+ #else
+ u32 mr_config_ext2_supported:1;
+ u32 support_profile_change:2;
+ u32 support_cvhealth_info:1;
+ u32 support_pcie:1;
+ u32 support_ext_mfg_vpd:1;
+ u32 support_oce_only:1;
+ u32 support_nvme_tm:1;
+ u32 support_snap_dump:1;
+ u32 support_fde_type_mix:1;
+ u32 support_force_personality_change:1;
+ u32 support_psoc_update:1;
+ u32 support_pci_lane_margining: 1;
+ u32 reserved:19;
+ #endif
+ } adapter_operations5;
+
+ u32 rsvdForAdptOp[63];
u8 reserved7[3];
@@ -1483,7 +1522,9 @@ struct megasas_ctrl_info {
#define MEGASAS_FW_BUSY 1
/* Driver's internal Logging levels*/
-#define OCR_LOGS (1 << 0)
+#define OCR_DEBUG (1 << 0)
+#define TM_DEBUG (1 << 1)
+#define LD_PD_DEBUG (1 << 2)
#define SCAN_PD_CHANNEL 0x1
#define SCAN_VD_CHANNEL 0x2
@@ -1559,6 +1600,7 @@ enum FW_BOOT_CONTEXT {
#define MFI_IO_TIMEOUT_SECS 180
#define MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF (5 * HZ)
#define MEGASAS_OCR_SETTLE_TIME_VF (1000 * 30)
+#define MEGASAS_SRIOV_MAX_RESET_TRIES_VF 1
#define MEGASAS_ROUTINE_WAIT_TIME_VF 300
#define MFI_REPLY_1078_MESSAGE_INTERRUPT 0x80000000
#define MFI_REPLY_GEN2_MESSAGE_INTERRUPT 0x00000001
@@ -1583,7 +1625,10 @@ enum FW_BOOT_CONTEXT {
#define MR_CAN_HANDLE_SYNC_CACHE_OFFSET 0X01000000
+#define MR_ATOMIC_DESCRIPTOR_SUPPORT_OFFSET (1 << 24)
+
#define MR_CAN_HANDLE_64_BIT_DMA_OFFSET (1 << 25)
+#define MR_INTR_COALESCING_SUPPORT_OFFSET (1 << 26)
#define MEGASAS_WATCHDOG_THREAD_INTERVAL 1000
#define MEGASAS_WAIT_FOR_NEXT_DMA_MSECS 20
@@ -1762,7 +1807,7 @@ struct megasas_init_frame {
__le32 pad_0; /*0Ch */
__le16 flags; /*10h */
- __le16 reserved_3; /*12h */
+ __le16 replyqueue_mask; /*12h */
__le32 data_xfer_len; /*14h */
__le32 queue_info_new_phys_addr_lo; /*18h */
@@ -2160,6 +2205,10 @@ struct megasas_aen_event {
struct megasas_irq_context {
struct megasas_instance *instance;
u32 MSIxIndex;
+ u32 os_irq;
+ struct irq_poll irqpoll;
+ bool irq_poll_scheduled;
+ bool irq_line_enable;
};
struct MR_DRV_SYSTEM_INFO {
@@ -2190,6 +2239,23 @@ enum MR_PD_TYPE {
#define MR_DEFAULT_NVME_MDTS_KB 128
#define MR_NVME_PAGE_SIZE_MASK 0x000000FF
+/*Aero performance parameters*/
+#define MR_HIGH_IOPS_QUEUE_COUNT 8
+#define MR_DEVICE_HIGH_IOPS_DEPTH 8
+#define MR_HIGH_IOPS_BATCH_COUNT 16
+
+enum MR_PERF_MODE {
+ MR_BALANCED_PERF_MODE = 0,
+ MR_IOPS_PERF_MODE = 1,
+ MR_LATENCY_PERF_MODE = 2,
+};
+
+#define MEGASAS_PERF_MODE_2STR(mode) \
+ ((mode) == MR_BALANCED_PERF_MODE ? "Balanced" : \
+ (mode) == MR_IOPS_PERF_MODE ? "IOPS" : \
+ (mode) == MR_LATENCY_PERF_MODE ? "Latency" : \
+ "Unknown")
+
struct megasas_instance {
unsigned int *reply_map;
@@ -2246,6 +2312,7 @@ struct megasas_instance {
u32 secure_jbod_support;
u32 support_morethan256jbod; /* FW support for more than 256 PD/JBOD */
bool use_seqnum_jbod_fp; /* Added for PD sequence */
+ bool smp_affinity_enable;
spinlock_t crashdump_lock;
struct megasas_register_set __iomem *reg_set;
@@ -2263,6 +2330,7 @@ struct megasas_instance {
u16 ldio_threshold;
u16 cur_can_queue;
u32 max_sectors_per_req;
+ bool msix_load_balance;
struct megasas_aen_event *ev;
struct megasas_cmd **cmd_list;
@@ -2290,15 +2358,13 @@ struct megasas_instance {
struct pci_dev *pdev;
u32 unique_id;
u32 fw_support_ieee;
+ u32 threshold_reply_count;
atomic_t fw_outstanding;
atomic_t ldio_outstanding;
atomic_t fw_reset_no_pci_access;
- atomic_t ieee_sgl;
- atomic_t prp_sgl;
- atomic_t sge_holes_type1;
- atomic_t sge_holes_type2;
- atomic_t sge_holes_type3;
+ atomic64_t total_io_count;
+ atomic64_t high_iops_outstanding;
struct megasas_instance_template *instancet;
struct tasklet_struct isr_tasklet;
@@ -2366,8 +2432,18 @@ struct megasas_instance {
u8 task_abort_tmo;
u8 max_reset_tmo;
u8 snapdump_wait_time;
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *debugfs_root;
+ struct dentry *raidmap_dump;
+#endif
u8 enable_fw_dev_list;
+ bool atomic_desc_support;
+ bool support_seqnum_jbod_fp;
+ bool support_pci_lane_margining;
+ u8 low_latency_index_start;
+ int perf_mode;
};
+
struct MR_LD_VF_MAP {
u32 size;
union MR_LD_REF ref;
@@ -2623,4 +2699,9 @@ void megasas_fusion_stop_watchdog(struct megasas_instance *instance);
void megasas_set_dma_settings(struct megasas_instance *instance,
struct megasas_dcmd_frame *dcmd,
dma_addr_t dma_addr, u32 dma_len);
+int megasas_adp_reset_wait_for_ready(struct megasas_instance *instance,
+ bool do_adp_reset,
+ int ocr_context);
+int megasas_irqpoll(struct irq_poll *irqpoll, int budget);
+void megasas_dump_fusion_io(struct scsi_cmnd *scmd);
#endif /*LSI_MEGARAID_SAS_H */
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index 3dd1df472dc6..80ab9700f1de 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -36,12 +36,14 @@
#include <linux/mutex.h>
#include <linux/poll.h>
#include <linux/vmalloc.h>
+#include <linux/irq_poll.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_dbg.h>
#include "megaraid_sas_fusion.h"
#include "megaraid_sas.h"
@@ -50,47 +52,59 @@
* Will be set in megasas_init_mfi if user does not provide
*/
static unsigned int max_sectors;
-module_param_named(max_sectors, max_sectors, int, 0);
+module_param_named(max_sectors, max_sectors, int, 0444);
MODULE_PARM_DESC(max_sectors,
"Maximum number of sectors per IO command");
static int msix_disable;
-module_param(msix_disable, int, S_IRUGO);
+module_param(msix_disable, int, 0444);
MODULE_PARM_DESC(msix_disable, "Disable MSI-X interrupt handling. Default: 0");
static unsigned int msix_vectors;
-module_param(msix_vectors, int, S_IRUGO);
+module_param(msix_vectors, int, 0444);
MODULE_PARM_DESC(msix_vectors, "MSI-X max vector count. Default: Set by FW");
static int allow_vf_ioctls;
-module_param(allow_vf_ioctls, int, S_IRUGO);
+module_param(allow_vf_ioctls, int, 0444);
MODULE_PARM_DESC(allow_vf_ioctls, "Allow ioctls in SR-IOV VF mode. Default: 0");
static unsigned int throttlequeuedepth = MEGASAS_THROTTLE_QUEUE_DEPTH;
-module_param(throttlequeuedepth, int, S_IRUGO);
+module_param(throttlequeuedepth, int, 0444);
MODULE_PARM_DESC(throttlequeuedepth,
"Adapter queue depth when throttled due to I/O timeout. Default: 16");
unsigned int resetwaittime = MEGASAS_RESET_WAIT_TIME;
-module_param(resetwaittime, int, S_IRUGO);
+module_param(resetwaittime, int, 0444);
MODULE_PARM_DESC(resetwaittime, "Wait time in (1-180s) after I/O timeout before resetting adapter. Default: 180s");
int smp_affinity_enable = 1;
-module_param(smp_affinity_enable, int, S_IRUGO);
+module_param(smp_affinity_enable, int, 0444);
MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disable Default: enable(1)");
int rdpq_enable = 1;
-module_param(rdpq_enable, int, S_IRUGO);
+module_param(rdpq_enable, int, 0444);
MODULE_PARM_DESC(rdpq_enable, "Allocate reply queue in chunks for large queue depth enable/disable Default: enable(1)");
unsigned int dual_qdepth_disable;
-module_param(dual_qdepth_disable, int, S_IRUGO);
+module_param(dual_qdepth_disable, int, 0444);
MODULE_PARM_DESC(dual_qdepth_disable, "Disable dual queue depth feature. Default: 0");
unsigned int scmd_timeout = MEGASAS_DEFAULT_CMD_TIMEOUT;
-module_param(scmd_timeout, int, S_IRUGO);
+module_param(scmd_timeout, int, 0444);
MODULE_PARM_DESC(scmd_timeout, "scsi command timeout (10-90s), default 90s. See megasas_reset_timer.");
+int perf_mode = -1;
+module_param(perf_mode, int, 0444);
+MODULE_PARM_DESC(perf_mode, "Performance mode (only for Aero adapters), options:\n\t\t"
+ "0 - balanced: High iops and low latency queues are allocated &\n\t\t"
+ "interrupt coalescing is enabled only on high iops queues\n\t\t"
+ "1 - iops: High iops queues are not allocated &\n\t\t"
+ "interrupt coalescing is enabled on all queues\n\t\t"
+ "2 - latency: High iops queues are not allocated &\n\t\t"
+ "interrupt coalescing is disabled on all queues\n\t\t"
+ "default mode is 'balanced'"
+ );
+
MODULE_LICENSE("GPL");
MODULE_VERSION(MEGASAS_VERSION);
MODULE_AUTHOR("megaraidlinux.pdl@broadcom.com");
@@ -154,6 +168,10 @@ static struct pci_device_id megasas_pci_table[] = {
{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E2)},
{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E5)},
{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E6)},
+ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E0)},
+ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E3)},
+ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E4)},
+ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E7)},
{}
};
@@ -170,10 +188,17 @@ static u32 support_poll_for_event;
u32 megasas_dbg_lvl;
static u32 support_device_change;
static bool support_nvme_encapsulation;
+static bool support_pci_lane_margining;
/* define lock for aen poll */
spinlock_t poll_aen_lock;
+extern struct dentry *megasas_debugfs_root;
+extern void megasas_init_debugfs(void);
+extern void megasas_exit_debugfs(void);
+extern void megasas_setup_debugfs(struct megasas_instance *instance);
+extern void megasas_destroy_debugfs(struct megasas_instance *instance);
+
void
megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
u8 alt_status);
@@ -1098,8 +1123,9 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
ret = wait_event_timeout(instance->int_cmd_wait_q,
cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS, timeout * HZ);
if (!ret) {
- dev_err(&instance->pdev->dev, "Failed from %s %d DCMD Timed out\n",
- __func__, __LINE__);
+ dev_err(&instance->pdev->dev,
+ "DCMD(opcode: 0x%x) is timed out, func:%s\n",
+ cmd->frame->dcmd.opcode, __func__);
return DCMD_TIMEOUT;
}
} else
@@ -1128,6 +1154,7 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
struct megasas_cmd *cmd;
struct megasas_abort_frame *abort_fr;
int ret = 0;
+ u32 opcode;
cmd = megasas_get_cmd(instance);
@@ -1163,8 +1190,10 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
ret = wait_event_timeout(instance->abort_cmd_wait_q,
cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS, timeout * HZ);
if (!ret) {
- dev_err(&instance->pdev->dev, "Failed from %s %d Abort Timed out\n",
- __func__, __LINE__);
+ opcode = cmd_to_abort->frame->dcmd.opcode;
+ dev_err(&instance->pdev->dev,
+ "Abort(to be aborted DCMD opcode: 0x%x) is timed out func:%s\n",
+ opcode, __func__);
return DCMD_TIMEOUT;
}
} else
@@ -1918,7 +1947,6 @@ megasas_set_nvme_device_properties(struct scsi_device *sdev, u32 max_io_size)
static void megasas_set_static_target_properties(struct scsi_device *sdev,
bool is_target_prop)
{
- u16 target_index = 0;
u8 interface_type;
u32 device_qd = MEGASAS_DEFAULT_CMD_PER_LUN;
u32 max_io_size_kb = MR_DEFAULT_NVME_MDTS_KB;
@@ -1935,8 +1963,6 @@ static void megasas_set_static_target_properties(struct scsi_device *sdev,
*/
blk_queue_rq_timeout(sdev->request_queue, scmd_timeout * HZ);
- target_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + sdev->id;
-
switch (interface_type) {
case SAS_PD:
device_qd = MEGASAS_SAS_QD;
@@ -2822,21 +2848,108 @@ blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
}
/**
- * megasas_dump_frame - This function will dump MPT/MFI frame
+ * megasas_dump - This function will print hexdump of provided buffer.
+ * @buf: Buffer to be dumped
+ * @sz: Size in bytes
+ * @format: Different formats of dumping e.g. format=n will
+ * cause only 'n' 32 bit words to be dumped in a single
+ * line.
*/
-static inline void
-megasas_dump_frame(void *mpi_request, int sz)
+inline void
+megasas_dump(void *buf, int sz, int format)
{
int i;
- __le32 *mfp = (__le32 *)mpi_request;
+ __le32 *buf_loc = (__le32 *)buf;
+
+ for (i = 0; i < (sz / sizeof(__le32)); i++) {
+ if ((i % format) == 0) {
+ if (i != 0)
+ printk(KERN_CONT "\n");
+ printk(KERN_CONT "%08x: ", (i * 4));
+ }
+ printk(KERN_CONT "%08x ", le32_to_cpu(buf_loc[i]));
+ }
+ printk(KERN_CONT "\n");
+}
+
+/**
+ * megasas_dump_reg_set - This function will print hexdump of register set
+ * @buf: Buffer to be dumped
+ * @sz: Size in bytes
+ * @format: Different formats of dumping e.g. format=n will
+ * cause only 'n' 32 bit words to be dumped in a
+ * single line.
+ */
+inline void
+megasas_dump_reg_set(void __iomem *reg_set)
+{
+ unsigned int i, sz = 256;
+ u32 __iomem *reg = (u32 __iomem *)reg_set;
+
+ for (i = 0; i < (sz / sizeof(u32)); i++)
+ printk("%08x: %08x\n", (i * 4), readl(&reg[i]));
+}
+
+/**
+ * megasas_dump_fusion_io - This function will print key details
+ * of SCSI IO
+ * @scmd: SCSI command pointer of SCSI IO
+ */
+void
+megasas_dump_fusion_io(struct scsi_cmnd *scmd)
+{
+ struct megasas_cmd_fusion *cmd;
+ union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
+ struct megasas_instance *instance;
+
+ cmd = (struct megasas_cmd_fusion *)scmd->SCp.ptr;
+ instance = (struct megasas_instance *)scmd->device->host->hostdata;
+
+ scmd_printk(KERN_INFO, scmd,
+ "scmd: (0x%p) retries: 0x%x allowed: 0x%x\n",
+ scmd, scmd->retries, scmd->allowed);
+ scsi_print_command(scmd);
+
+ if (cmd) {
+ req_desc = (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)cmd->request_desc;
+ scmd_printk(KERN_INFO, scmd, "Request descriptor details:\n");
+ scmd_printk(KERN_INFO, scmd,
+ "RequestFlags:0x%x MSIxIndex:0x%x SMID:0x%x LMID:0x%x DevHandle:0x%x\n",
+ req_desc->SCSIIO.RequestFlags,
+ req_desc->SCSIIO.MSIxIndex, req_desc->SCSIIO.SMID,
+ req_desc->SCSIIO.LMID, req_desc->SCSIIO.DevHandle);
+
+ printk(KERN_INFO "IO request frame:\n");
+ megasas_dump(cmd->io_request,
+ MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE, 8);
+ printk(KERN_INFO "Chain frame:\n");
+ megasas_dump(cmd->sg_frame,
+ instance->max_chain_frame_sz, 8);
+ }
+
+}
+
+/*
+ * megasas_dump_sys_regs - This function will dump system registers through
+ * sysfs.
+ * @reg_set: Pointer to System register set.
+ * @buf: Buffer to which output is to be written.
+ * @return: Number of bytes written to buffer.
+ */
+static inline ssize_t
+megasas_dump_sys_regs(void __iomem *reg_set, char *buf)
+{
+ unsigned int i, sz = 256;
+ int bytes_wrote = 0;
+ char *loc = (char *)buf;
+ u32 __iomem *reg = (u32 __iomem *)reg_set;
- printk(KERN_INFO "IO request frame:\n\t");
- for (i = 0; i < sz / sizeof(__le32); i++) {
- if (i && ((i % 8) == 0))
- printk("\n\t");
- printk("%08x ", le32_to_cpu(mfp[i]));
+ for (i = 0; i < sz / sizeof(u32); i++) {
+ bytes_wrote += snprintf(loc + bytes_wrote, PAGE_SIZE,
+ "%08x: %08x\n", (i * 4),
+ readl(&reg[i]));
}
- printk("\n");
+ return bytes_wrote;
}
/**
@@ -2850,24 +2963,20 @@ static int megasas_reset_bus_host(struct scsi_cmnd *scmd)
instance = (struct megasas_instance *)scmd->device->host->hostdata;
scmd_printk(KERN_INFO, scmd,
- "Controller reset is requested due to IO timeout\n"
- "SCSI command pointer: (%p)\t SCSI host state: %d\t"
- " SCSI host busy: %d\t FW outstanding: %d\n",
- scmd, scmd->device->host->shost_state,
+ "OCR is requested due to IO timeout!!\n");
+
+ scmd_printk(KERN_INFO, scmd,
+ "SCSI host state: %d SCSI host busy: %d FW outstanding: %d\n",
+ scmd->device->host->shost_state,
scsi_host_busy(scmd->device->host),
atomic_read(&instance->fw_outstanding));
-
/*
* First wait for all commands to complete
*/
if (instance->adapter_type == MFI_SERIES) {
ret = megasas_generic_reset(scmd);
} else {
- struct megasas_cmd_fusion *cmd;
- cmd = (struct megasas_cmd_fusion *)scmd->SCp.ptr;
- if (cmd)
- megasas_dump_frame(cmd->io_request,
- MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE);
+ megasas_dump_fusion_io(scmd);
ret = megasas_reset_fusion(scmd->device->host,
SCSIIO_TIMEOUT_OCR);
}
@@ -3017,7 +3126,7 @@ megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd)
}
static ssize_t
-megasas_fw_crash_buffer_store(struct device *cdev,
+fw_crash_buffer_store(struct device *cdev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3036,14 +3145,13 @@ megasas_fw_crash_buffer_store(struct device *cdev,
}
static ssize_t
-megasas_fw_crash_buffer_show(struct device *cdev,
+fw_crash_buffer_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
struct megasas_instance *instance =
(struct megasas_instance *) shost->hostdata;
u32 size;
- unsigned long buff_addr;
unsigned long dmachunk = CRASH_DMA_BUF_SIZE;
unsigned long src_addr;
unsigned long flags;
@@ -3060,8 +3168,6 @@ megasas_fw_crash_buffer_show(struct device *cdev,
return -EINVAL;
}
- buff_addr = (unsigned long) buf;
-
if (buff_offset > (instance->fw_crash_buffer_size * dmachunk)) {
dev_err(&instance->pdev->dev,
"Firmware crash dump offset is out of range\n");
@@ -3081,7 +3187,7 @@ megasas_fw_crash_buffer_show(struct device *cdev,
}
static ssize_t
-megasas_fw_crash_buffer_size_show(struct device *cdev,
+fw_crash_buffer_size_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3093,7 +3199,7 @@ megasas_fw_crash_buffer_size_show(struct device *cdev,
}
static ssize_t
-megasas_fw_crash_state_store(struct device *cdev,
+fw_crash_state_store(struct device *cdev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3128,7 +3234,7 @@ megasas_fw_crash_state_store(struct device *cdev,
}
static ssize_t
-megasas_fw_crash_state_show(struct device *cdev,
+fw_crash_state_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3139,14 +3245,14 @@ megasas_fw_crash_state_show(struct device *cdev,
}
static ssize_t
-megasas_page_size_show(struct device *cdev,
+page_size_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%ld\n", (unsigned long)PAGE_SIZE - 1);
}
static ssize_t
-megasas_ldio_outstanding_show(struct device *cdev, struct device_attribute *attr,
+ldio_outstanding_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3156,7 +3262,7 @@ megasas_ldio_outstanding_show(struct device *cdev, struct device_attribute *attr
}
static ssize_t
-megasas_fw_cmds_outstanding_show(struct device *cdev,
+fw_cmds_outstanding_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3165,18 +3271,37 @@ megasas_fw_cmds_outstanding_show(struct device *cdev,
return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&instance->fw_outstanding));
}
-static DEVICE_ATTR(fw_crash_buffer, S_IRUGO | S_IWUSR,
- megasas_fw_crash_buffer_show, megasas_fw_crash_buffer_store);
-static DEVICE_ATTR(fw_crash_buffer_size, S_IRUGO,
- megasas_fw_crash_buffer_size_show, NULL);
-static DEVICE_ATTR(fw_crash_state, S_IRUGO | S_IWUSR,
- megasas_fw_crash_state_show, megasas_fw_crash_state_store);
-static DEVICE_ATTR(page_size, S_IRUGO,
- megasas_page_size_show, NULL);
-static DEVICE_ATTR(ldio_outstanding, S_IRUGO,
- megasas_ldio_outstanding_show, NULL);
-static DEVICE_ATTR(fw_cmds_outstanding, S_IRUGO,
- megasas_fw_cmds_outstanding_show, NULL);
+static ssize_t
+dump_system_regs_show(struct device *cdev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct megasas_instance *instance =
+ (struct megasas_instance *)shost->hostdata;
+
+ return megasas_dump_sys_regs(instance->reg_set, buf);
+}
+
+static ssize_t
+raid_map_id_show(struct device *cdev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct megasas_instance *instance =
+ (struct megasas_instance *)shost->hostdata;
+
+ return snprintf(buf, PAGE_SIZE, "%ld\n",
+ (unsigned long)instance->map_id);
+}
+
+static DEVICE_ATTR_RW(fw_crash_buffer);
+static DEVICE_ATTR_RO(fw_crash_buffer_size);
+static DEVICE_ATTR_RW(fw_crash_state);
+static DEVICE_ATTR_RO(page_size);
+static DEVICE_ATTR_RO(ldio_outstanding);
+static DEVICE_ATTR_RO(fw_cmds_outstanding);
+static DEVICE_ATTR_RO(dump_system_regs);
+static DEVICE_ATTR_RO(raid_map_id);
struct device_attribute *megaraid_host_attrs[] = {
&dev_attr_fw_crash_buffer_size,
@@ -3185,6 +3310,8 @@ struct device_attribute *megaraid_host_attrs[] = {
&dev_attr_page_size,
&dev_attr_ldio_outstanding,
&dev_attr_fw_cmds_outstanding,
+ &dev_attr_dump_system_regs,
+ &dev_attr_raid_map_id,
NULL,
};
@@ -3368,6 +3495,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
case MFI_CMD_SMP:
case MFI_CMD_STP:
case MFI_CMD_NVME:
+ case MFI_CMD_TOOLBOX:
megasas_complete_int_cmd(instance, cmd);
break;
@@ -3776,7 +3904,6 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
int i;
u8 max_wait;
u32 fw_state;
- u32 cur_state;
u32 abs_state, curr_abs_state;
abs_state = instance->instancet->read_fw_status_reg(instance);
@@ -3791,13 +3918,18 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
switch (fw_state) {
case MFI_STATE_FAULT:
- dev_printk(KERN_DEBUG, &instance->pdev->dev, "FW in FAULT state!!\n");
+ dev_printk(KERN_ERR, &instance->pdev->dev,
+ "FW in FAULT state, Fault code:0x%x subcode:0x%x func:%s\n",
+ abs_state & MFI_STATE_FAULT_CODE,
+ abs_state & MFI_STATE_FAULT_SUBCODE, __func__);
if (ocr) {
max_wait = MEGASAS_RESET_WAIT_TIME;
- cur_state = MFI_STATE_FAULT;
break;
- } else
+ } else {
+ dev_printk(KERN_DEBUG, &instance->pdev->dev, "System Register set:\n");
+ megasas_dump_reg_set(instance->reg_set);
return -ENODEV;
+ }
case MFI_STATE_WAIT_HANDSHAKE:
/*
@@ -3817,7 +3949,6 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
&instance->reg_set->inbound_doorbell);
max_wait = MEGASAS_RESET_WAIT_TIME;
- cur_state = MFI_STATE_WAIT_HANDSHAKE;
break;
case MFI_STATE_BOOT_MESSAGE_PENDING:
@@ -3833,7 +3964,6 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
&instance->reg_set->inbound_doorbell);
max_wait = MEGASAS_RESET_WAIT_TIME;
- cur_state = MFI_STATE_BOOT_MESSAGE_PENDING;
break;
case MFI_STATE_OPERATIONAL:
@@ -3866,7 +3996,6 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
&instance->reg_set->inbound_doorbell);
max_wait = MEGASAS_RESET_WAIT_TIME;
- cur_state = MFI_STATE_OPERATIONAL;
break;
case MFI_STATE_UNDEFINED:
@@ -3874,37 +4003,33 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
* This state should not last for more than 2 seconds
*/
max_wait = MEGASAS_RESET_WAIT_TIME;
- cur_state = MFI_STATE_UNDEFINED;
break;
case MFI_STATE_BB_INIT:
max_wait = MEGASAS_RESET_WAIT_TIME;
- cur_state = MFI_STATE_BB_INIT;
break;
case MFI_STATE_FW_INIT:
max_wait = MEGASAS_RESET_WAIT_TIME;
- cur_state = MFI_STATE_FW_INIT;
break;
case MFI_STATE_FW_INIT_2:
max_wait = MEGASAS_RESET_WAIT_TIME;
- cur_state = MFI_STATE_FW_INIT_2;
break;
case MFI_STATE_DEVICE_SCAN:
max_wait = MEGASAS_RESET_WAIT_TIME;
- cur_state = MFI_STATE_DEVICE_SCAN;
break;
case MFI_STATE_FLUSH_CACHE:
max_wait = MEGASAS_RESET_WAIT_TIME;
- cur_state = MFI_STATE_FLUSH_CACHE;
break;
default:
dev_printk(KERN_DEBUG, &instance->pdev->dev, "Unknown state 0x%x\n",
fw_state);
+ dev_printk(KERN_DEBUG, &instance->pdev->dev, "System Register set:\n");
+ megasas_dump_reg_set(instance->reg_set);
return -ENODEV;
}
@@ -3927,6 +4052,8 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
if (curr_abs_state == abs_state) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "FW state [%d] hasn't changed "
"in %d secs\n", fw_state, max_wait);
+ dev_printk(KERN_DEBUG, &instance->pdev->dev, "System Register set:\n");
+ megasas_dump_reg_set(instance->reg_set);
return -ENODEV;
}
@@ -3990,23 +4117,12 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
{
int i;
u16 max_cmd;
- u32 sge_sz;
u32 frame_count;
struct megasas_cmd *cmd;
max_cmd = instance->max_mfi_cmds;
/*
- * Size of our frame is 64 bytes for MFI frame, followed by max SG
- * elements and finally SCSI_SENSE_BUFFERSIZE bytes for sense buffer
- */
- sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
- sizeof(struct megasas_sge32);
-
- if (instance->flag_ieee)
- sge_sz = sizeof(struct megasas_sge_skinny);
-
- /*
* For MFI controllers.
* max_num_sge = 60
* max_sge_sz = 16 byte (sizeof megasas_sge_skinny)
@@ -4255,8 +4371,10 @@ megasas_get_pd_info(struct megasas_instance *instance, struct scsi_device *sdev)
switch (dcmd_timeout_ocr_possible(instance)) {
case INITIATE_OCR:
cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+ mutex_unlock(&instance->reset_mutex);
megasas_reset_fusion(instance->host,
MFI_IO_TIMEOUT_OCR);
+ mutex_lock(&instance->reset_mutex);
break;
case KILL_ADAPTER:
megaraid_sas_kill_hba(instance);
@@ -4292,7 +4410,6 @@ megasas_get_pd_list(struct megasas_instance *instance)
struct megasas_dcmd_frame *dcmd;
struct MR_PD_LIST *ci;
struct MR_PD_ADDRESS *pd_addr;
- dma_addr_t ci_h = 0;
if (instance->pd_list_not_supported) {
dev_info(&instance->pdev->dev, "MR_DCMD_PD_LIST_QUERY "
@@ -4301,7 +4418,6 @@ megasas_get_pd_list(struct megasas_instance *instance)
}
ci = instance->pd_list_buf;
- ci_h = instance->pd_list_buf_h;
cmd = megasas_get_cmd(instance);
@@ -4374,6 +4490,9 @@ megasas_get_pd_list(struct megasas_instance *instance)
case DCMD_SUCCESS:
pd_addr = ci->addr;
+ if (megasas_dbg_lvl & LD_PD_DEBUG)
+ dev_info(&instance->pdev->dev, "%s, sysPD count: 0x%x\n",
+ __func__, le32_to_cpu(ci->count));
if ((le32_to_cpu(ci->count) >
(MEGASAS_MAX_PD_CHANNELS * MEGASAS_MAX_DEV_PER_CHANNEL)))
@@ -4389,6 +4508,11 @@ megasas_get_pd_list(struct megasas_instance *instance)
pd_addr->scsiDevType;
instance->local_pd_list[le16_to_cpu(pd_addr->deviceId)].driveState =
MR_PD_STATE_SYSTEM;
+ if (megasas_dbg_lvl & LD_PD_DEBUG)
+ dev_info(&instance->pdev->dev,
+ "PD%d: targetID: 0x%03x deviceType:0x%x\n",
+ pd_index, le16_to_cpu(pd_addr->deviceId),
+ pd_addr->scsiDevType);
pd_addr++;
}
@@ -4492,6 +4616,10 @@ megasas_get_ld_list(struct megasas_instance *instance)
break;
case DCMD_SUCCESS:
+ if (megasas_dbg_lvl & LD_PD_DEBUG)
+ dev_info(&instance->pdev->dev, "%s, LD count: 0x%x\n",
+ __func__, ld_count);
+
if (ld_count > instance->fw_supported_vd_count)
break;
@@ -4501,6 +4629,10 @@ megasas_get_ld_list(struct megasas_instance *instance)
if (ci->ldList[ld_index].state != 0) {
ids = ci->ldList[ld_index].ref.targetId;
instance->ld_ids[ids] = ci->ldList[ld_index].ref.targetId;
+ if (megasas_dbg_lvl & LD_PD_DEBUG)
+ dev_info(&instance->pdev->dev,
+ "LD%d: targetID: 0x%03x\n",
+ ld_index, ids);
}
}
@@ -4604,6 +4736,10 @@ megasas_ld_list_query(struct megasas_instance *instance, u8 query_type)
case DCMD_SUCCESS:
tgtid_count = le32_to_cpu(ci->count);
+ if (megasas_dbg_lvl & LD_PD_DEBUG)
+ dev_info(&instance->pdev->dev, "%s, LD count: 0x%x\n",
+ __func__, tgtid_count);
+
if ((tgtid_count > (instance->fw_supported_vd_count)))
break;
@@ -4611,6 +4747,9 @@ megasas_ld_list_query(struct megasas_instance *instance, u8 query_type)
for (ld_index = 0; ld_index < tgtid_count; ld_index++) {
ids = ci->targetId[ld_index];
instance->ld_ids[ids] = ci->targetId[ld_index];
+ if (megasas_dbg_lvl & LD_PD_DEBUG)
+ dev_info(&instance->pdev->dev, "LD%d: targetID: 0x%03x\n",
+ ld_index, ci->targetId[ld_index]);
}
break;
@@ -4690,6 +4829,13 @@ megasas_host_device_list_query(struct megasas_instance *instance,
*/
count = le32_to_cpu(ci->count);
+ if (count > (MEGASAS_MAX_PD + MAX_LOGICAL_DRIVES_EXT))
+ break;
+
+ if (megasas_dbg_lvl & LD_PD_DEBUG)
+ dev_info(&instance->pdev->dev, "%s, Device count: 0x%x\n",
+ __func__, count);
+
memset(instance->local_pd_list, 0,
MEGASAS_MAX_PD * sizeof(struct megasas_pd_list));
memset(instance->ld_ids, 0xff, MAX_LOGICAL_DRIVES_EXT);
@@ -4701,8 +4847,16 @@ megasas_host_device_list_query(struct megasas_instance *instance,
ci->host_device_list[i].scsi_type;
instance->local_pd_list[target_id].driveState =
MR_PD_STATE_SYSTEM;
+ if (megasas_dbg_lvl & LD_PD_DEBUG)
+ dev_info(&instance->pdev->dev,
+ "Device %d: PD targetID: 0x%03x deviceType:0x%x\n",
+ i, target_id, ci->host_device_list[i].scsi_type);
} else {
instance->ld_ids[target_id] = target_id;
+ if (megasas_dbg_lvl & LD_PD_DEBUG)
+ dev_info(&instance->pdev->dev,
+ "Device %d: LD targetID: 0x%03x\n",
+ i, target_id);
}
}
@@ -4714,8 +4868,10 @@ megasas_host_device_list_query(struct megasas_instance *instance,
switch (dcmd_timeout_ocr_possible(instance)) {
case INITIATE_OCR:
cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+ mutex_unlock(&instance->reset_mutex);
megasas_reset_fusion(instance->host,
MFI_IO_TIMEOUT_OCR);
+ mutex_lock(&instance->reset_mutex);
break;
case KILL_ADAPTER:
megaraid_sas_kill_hba(instance);
@@ -4863,8 +5019,10 @@ void megasas_get_snapdump_properties(struct megasas_instance *instance)
switch (dcmd_timeout_ocr_possible(instance)) {
case INITIATE_OCR:
cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+ mutex_unlock(&instance->reset_mutex);
megasas_reset_fusion(instance->host,
MFI_IO_TIMEOUT_OCR);
+ mutex_lock(&instance->reset_mutex);
break;
case KILL_ADAPTER:
megaraid_sas_kill_hba(instance);
@@ -4943,6 +5101,7 @@ megasas_get_ctrl_info(struct megasas_instance *instance)
le32_to_cpus((u32 *)&ci->adapterOperations2);
le32_to_cpus((u32 *)&ci->adapterOperations3);
le16_to_cpus((u16 *)&ci->adapter_operations4);
+ le32_to_cpus((u32 *)&ci->adapter_operations5);
/* Update the latest Ext VD info.
* From Init path, store current firmware details.
@@ -4950,12 +5109,14 @@ megasas_get_ctrl_info(struct megasas_instance *instance)
* in case of Firmware upgrade without system reboot.
*/
megasas_update_ext_vd_details(instance);
- instance->use_seqnum_jbod_fp =
+ instance->support_seqnum_jbod_fp =
ci->adapterOperations3.useSeqNumJbodFP;
instance->support_morethan256jbod =
ci->adapter_operations4.support_pd_map_target_id;
instance->support_nvme_passthru =
ci->adapter_operations4.support_nvme_passthru;
+ instance->support_pci_lane_margining =
+ ci->adapter_operations5.support_pci_lane_margining;
instance->task_abort_tmo = ci->TaskAbortTO;
instance->max_reset_tmo = ci->MaxResetTO;
@@ -4987,6 +5148,10 @@ megasas_get_ctrl_info(struct megasas_instance *instance)
dev_info(&instance->pdev->dev,
"FW provided TM TaskAbort/Reset timeout\t: %d secs/%d secs\n",
instance->task_abort_tmo, instance->max_reset_tmo);
+ dev_info(&instance->pdev->dev, "JBOD sequence map support\t: %s\n",
+ instance->support_seqnum_jbod_fp ? "Yes" : "No");
+ dev_info(&instance->pdev->dev, "PCI Lane Margining support\t: %s\n",
+ instance->support_pci_lane_margining ? "Yes" : "No");
break;
@@ -4994,8 +5159,10 @@ megasas_get_ctrl_info(struct megasas_instance *instance)
switch (dcmd_timeout_ocr_possible(instance)) {
case INITIATE_OCR:
cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+ mutex_unlock(&instance->reset_mutex);
megasas_reset_fusion(instance->host,
MFI_IO_TIMEOUT_OCR);
+ mutex_lock(&instance->reset_mutex);
break;
case KILL_ADAPTER:
megaraid_sas_kill_hba(instance);
@@ -5262,6 +5429,25 @@ fail_alloc_cmds:
return 1;
}
+static
+void megasas_setup_irq_poll(struct megasas_instance *instance)
+{
+ struct megasas_irq_context *irq_ctx;
+ u32 count, i;
+
+ count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
+
+ /* Initialize IRQ poll */
+ for (i = 0; i < count; i++) {
+ irq_ctx = &instance->irq_context[i];
+ irq_ctx->os_irq = pci_irq_vector(instance->pdev, i);
+ irq_ctx->irq_poll_scheduled = false;
+ irq_poll_init(&irq_ctx->irqpoll,
+ instance->threshold_reply_count,
+ megasas_irqpoll);
+ }
+}
+
/*
* megasas_setup_irqs_ioapic - register legacy interrupts.
* @instance: Adapter soft state
@@ -5286,6 +5472,8 @@ megasas_setup_irqs_ioapic(struct megasas_instance *instance)
__func__, __LINE__);
return -1;
}
+ instance->perf_mode = MR_LATENCY_PERF_MODE;
+ instance->low_latency_index_start = 0;
return 0;
}
@@ -5320,6 +5508,7 @@ megasas_setup_irqs_msix(struct megasas_instance *instance, u8 is_probe)
&instance->irq_context[j]);
/* Retry irq register for IO_APIC*/
instance->msix_vectors = 0;
+ instance->msix_load_balance = false;
if (is_probe) {
pci_free_irq_vectors(instance->pdev);
return megasas_setup_irqs_ioapic(instance);
@@ -5328,6 +5517,7 @@ megasas_setup_irqs_msix(struct megasas_instance *instance, u8 is_probe)
}
}
}
+
return 0;
}
@@ -5340,6 +5530,16 @@ static void
megasas_destroy_irqs(struct megasas_instance *instance) {
int i;
+ int count;
+ struct megasas_irq_context *irq_ctx;
+
+ count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
+ if (instance->adapter_type != MFI_SERIES) {
+ for (i = 0; i < count; i++) {
+ irq_ctx = &instance->irq_context[i];
+ irq_poll_disable(&irq_ctx->irqpoll);
+ }
+ }
if (instance->msix_vectors)
for (i = 0; i < instance->msix_vectors; i++) {
@@ -5368,10 +5568,12 @@ megasas_setup_jbod_map(struct megasas_instance *instance)
pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) +
(sizeof(struct MR_PD_CFG_SEQ) * (MAX_PHYSICAL_DEVICES - 1));
+ instance->use_seqnum_jbod_fp =
+ instance->support_seqnum_jbod_fp;
if (reset_devices || !fusion ||
- !instance->ctrl_info_buf->adapterOperations3.useSeqNumJbodFP) {
+ !instance->support_seqnum_jbod_fp) {
dev_info(&instance->pdev->dev,
- "Jbod map is not supported %s %d\n",
+ "JBOD sequence map is disabled %s %d\n",
__func__, __LINE__);
instance->use_seqnum_jbod_fp = false;
return;
@@ -5410,9 +5612,11 @@ skip_alloc:
static void megasas_setup_reply_map(struct megasas_instance *instance)
{
const struct cpumask *mask;
- unsigned int queue, cpu;
+ unsigned int queue, cpu, low_latency_index_start;
- for (queue = 0; queue < instance->msix_vectors; queue++) {
+ low_latency_index_start = instance->low_latency_index_start;
+
+ for (queue = low_latency_index_start; queue < instance->msix_vectors; queue++) {
mask = pci_irq_get_affinity(instance->pdev, queue);
if (!mask)
goto fallback;
@@ -5423,8 +5627,14 @@ static void megasas_setup_reply_map(struct megasas_instance *instance)
return;
fallback:
- for_each_possible_cpu(cpu)
- instance->reply_map[cpu] = cpu % instance->msix_vectors;
+ queue = low_latency_index_start;
+ for_each_possible_cpu(cpu) {
+ instance->reply_map[cpu] = queue;
+ if (queue == (instance->msix_vectors - 1))
+ queue = low_latency_index_start;
+ else
+ queue++;
+ }
}
/**
@@ -5461,6 +5671,89 @@ int megasas_get_device_list(struct megasas_instance *instance)
return SUCCESS;
}
+
+/**
+ * megasas_set_high_iops_queue_affinity_hint - Set affinity hint for high IOPS queues
+ * @instance: Adapter soft state
+ * return: void
+ */
+static inline void
+megasas_set_high_iops_queue_affinity_hint(struct megasas_instance *instance)
+{
+ int i;
+ int local_numa_node;
+
+ if (instance->perf_mode == MR_BALANCED_PERF_MODE) {
+ local_numa_node = dev_to_node(&instance->pdev->dev);
+
+ for (i = 0; i < instance->low_latency_index_start; i++)
+ irq_set_affinity_hint(pci_irq_vector(instance->pdev, i),
+ cpumask_of_node(local_numa_node));
+ }
+}
+
+static int
+__megasas_alloc_irq_vectors(struct megasas_instance *instance)
+{
+ int i, irq_flags;
+ struct irq_affinity desc = { .pre_vectors = instance->low_latency_index_start };
+ struct irq_affinity *descp = &desc;
+
+ irq_flags = PCI_IRQ_MSIX;
+
+ if (instance->smp_affinity_enable)
+ irq_flags |= PCI_IRQ_AFFINITY;
+ else
+ descp = NULL;
+
+ i = pci_alloc_irq_vectors_affinity(instance->pdev,
+ instance->low_latency_index_start,
+ instance->msix_vectors, irq_flags, descp);
+
+ return i;
+}
+
+/**
+ * megasas_alloc_irq_vectors - Allocate IRQ vectors/enable MSI-x vectors
+ * @instance: Adapter soft state
+ * return: void
+ */
+static void
+megasas_alloc_irq_vectors(struct megasas_instance *instance)
+{
+ int i;
+ unsigned int num_msix_req;
+
+ i = __megasas_alloc_irq_vectors(instance);
+
+ if ((instance->perf_mode == MR_BALANCED_PERF_MODE) &&
+ (i != instance->msix_vectors)) {
+ if (instance->msix_vectors)
+ pci_free_irq_vectors(instance->pdev);
+ /* Disable Balanced IOPS mode and try realloc vectors */
+ instance->perf_mode = MR_LATENCY_PERF_MODE;
+ instance->low_latency_index_start = 1;
+ num_msix_req = num_online_cpus() + instance->low_latency_index_start;
+
+ instance->msix_vectors = min(num_msix_req,
+ instance->msix_vectors);
+
+ i = __megasas_alloc_irq_vectors(instance);
+
+ }
+
+ dev_info(&instance->pdev->dev,
+ "requested/available msix %d/%d\n", instance->msix_vectors, i);
+
+ if (i > 0)
+ instance->msix_vectors = i;
+ else
+ instance->msix_vectors = 0;
+
+ if (instance->smp_affinity_enable)
+ megasas_set_high_iops_queue_affinity_hint(instance);
+}
+
/**
* megasas_init_fw - Initializes the FW
* @instance: Adapter soft state
@@ -5474,12 +5767,15 @@ static int megasas_init_fw(struct megasas_instance *instance)
u32 max_sectors_2, tmp_sectors, msix_enable;
u32 scratch_pad_1, scratch_pad_2, scratch_pad_3, status_reg;
resource_size_t base_addr;
+ void *base_addr_phys;
struct megasas_ctrl_info *ctrl_info = NULL;
unsigned long bar_list;
- int i, j, loop, fw_msix_count = 0;
+ int i, j, loop;
struct IOV_111 *iovPtr;
struct fusion_context *fusion;
- bool do_adp_reset = true;
+ bool intr_coalescing;
+ unsigned int num_msix_req;
+ u16 lnksta, speed;
fusion = instance->ctrl_context;
@@ -5500,6 +5796,11 @@ static int megasas_init_fw(struct megasas_instance *instance)
goto fail_ioremap;
}
+ base_addr_phys = &base_addr;
+ dev_printk(KERN_DEBUG, &instance->pdev->dev,
+ "BAR:0x%lx BAR's base_addr(phys):%pa mapped virt_addr:0x%p\n",
+ instance->bar, base_addr_phys, instance->reg_set);
+
if (instance->adapter_type != MFI_SERIES)
instance->instancet = &megasas_instance_template_fusion;
else {
@@ -5526,29 +5827,35 @@ static int megasas_init_fw(struct megasas_instance *instance)
}
if (megasas_transition_to_ready(instance, 0)) {
- if (instance->adapter_type >= INVADER_SERIES) {
+ dev_info(&instance->pdev->dev,
+ "Failed to transition controller to ready from %s!\n",
+ __func__);
+ if (instance->adapter_type != MFI_SERIES) {
status_reg = instance->instancet->read_fw_status_reg(
instance);
- do_adp_reset = status_reg & MFI_RESET_ADAPTER;
- }
-
- if (do_adp_reset) {
+ if (status_reg & MFI_RESET_ADAPTER) {
+ if (megasas_adp_reset_wait_for_ready
+ (instance, true, 0) == FAILED)
+ goto fail_ready_state;
+ } else {
+ goto fail_ready_state;
+ }
+ } else {
atomic_set(&instance->fw_reset_no_pci_access, 1);
instance->instancet->adp_reset
(instance, instance->reg_set);
atomic_set(&instance->fw_reset_no_pci_access, 0);
- dev_info(&instance->pdev->dev,
- "FW restarted successfully from %s!\n",
- __func__);
/*waiting for about 30 second before retry*/
ssleep(30);
if (megasas_transition_to_ready(instance, 0))
goto fail_ready_state;
- } else {
- goto fail_ready_state;
}
+
+ dev_info(&instance->pdev->dev,
+ "FW restarted successfully from %s!\n",
+ __func__);
}
megasas_init_ctrl_params(instance);
@@ -5573,11 +5880,21 @@ static int megasas_init_fw(struct megasas_instance *instance)
MR_MAX_RAID_MAP_SIZE_MASK);
}
+ switch (instance->adapter_type) {
+ case VENTURA_SERIES:
+ fusion->pcie_bw_limitation = true;
+ break;
+ case AERO_SERIES:
+ fusion->r56_div_offload = true;
+ break;
+ default:
+ break;
+ }
+
/* Check if MSI-X is supported while in ready state */
msix_enable = (instance->instancet->read_fw_status_reg(instance) &
0x4000000) >> 0x1a;
if (msix_enable && !msix_disable) {
- int irq_flags = PCI_IRQ_MSIX;
scratch_pad_1 = megasas_readl
(instance, &instance->reg_set->outbound_scratch_pad_1);
@@ -5587,7 +5904,6 @@ static int megasas_init_fw(struct megasas_instance *instance)
/* Thunderbolt Series*/
instance->msix_vectors = (scratch_pad_1
& MR_MAX_REPLY_QUEUES_OFFSET) + 1;
- fw_msix_count = instance->msix_vectors;
} else {
instance->msix_vectors = ((scratch_pad_1
& MR_MAX_REPLY_QUEUES_EXT_OFFSET)
@@ -5616,7 +5932,12 @@ static int megasas_init_fw(struct megasas_instance *instance)
if (rdpq_enable)
instance->is_rdpq = (scratch_pad_1 & MR_RDPQ_MODE_OFFSET) ?
1 : 0;
- fw_msix_count = instance->msix_vectors;
+
+ if (!instance->msix_combined) {
+ instance->msix_load_balance = true;
+ instance->smp_affinity_enable = false;
+ }
+
/* Save 1-15 reply post index address to local memory
* Index 0 is already saved from reg offset
* MPI2_REPLY_POST_HOST_INDEX_OFFSET
@@ -5629,22 +5950,91 @@ static int megasas_init_fw(struct megasas_instance *instance)
+ (loop * 0x10));
}
}
+
+ dev_info(&instance->pdev->dev,
+ "firmware supports msix\t: (%d)",
+ instance->msix_vectors);
if (msix_vectors)
instance->msix_vectors = min(msix_vectors,
instance->msix_vectors);
} else /* MFI adapters */
instance->msix_vectors = 1;
- /* Don't bother allocating more MSI-X vectors than cpus */
- instance->msix_vectors = min(instance->msix_vectors,
- (unsigned int)num_online_cpus());
- if (smp_affinity_enable)
- irq_flags |= PCI_IRQ_AFFINITY;
- i = pci_alloc_irq_vectors(instance->pdev, 1,
- instance->msix_vectors, irq_flags);
- if (i > 0)
- instance->msix_vectors = i;
+
+
+ /*
+ * For Aero (if some conditions are met), driver will configure a
+ * few additional reply queues with interrupt coalescing enabled.
+ * These queues with interrupt coalescing enabled are called
+ * High IOPS queues and rest of reply queues (based on number of
+ * logical CPUs) are termed as Low latency queues.
+ *
+ * Total Number of reply queues = High IOPS queues + low latency queues
+ *
+ * For rest of fusion adapters, 1 additional reply queue will be
+ * reserved for management commands, rest of reply queues
+ * (based on number of logical CPUs) will be used for IOs and
+ * referenced as IO queues.
+ * Total Number of reply queues = 1 + IO queues
+ *
+ * MFI adapters supports single MSI-x so single reply queue
+ * will be used for IO and management commands.
+ */
+
+ intr_coalescing = (scratch_pad_1 & MR_INTR_COALESCING_SUPPORT_OFFSET) ?
+ true : false;
+ if (intr_coalescing &&
+ (num_online_cpus() >= MR_HIGH_IOPS_QUEUE_COUNT) &&
+ (instance->msix_vectors == MEGASAS_MAX_MSIX_QUEUES))
+ instance->perf_mode = MR_BALANCED_PERF_MODE;
else
- instance->msix_vectors = 0;
+ instance->perf_mode = MR_LATENCY_PERF_MODE;
+
+
+ if (instance->adapter_type == AERO_SERIES) {
+ pcie_capability_read_word(instance->pdev, PCI_EXP_LNKSTA, &lnksta);
+ speed = lnksta & PCI_EXP_LNKSTA_CLS;
+
+ /*
+ * For Aero, if PCIe link speed is <16 GT/s, then driver should operate
+ * in latency perf mode and enable R1 PCI bandwidth algorithm
+ */
+ if (speed < 0x4) {
+ instance->perf_mode = MR_LATENCY_PERF_MODE;
+ fusion->pcie_bw_limitation = true;
+ }
+
+ /*
+ * Performance mode settings provided through module parameter-perf_mode will
+ * take affect only for:
+ * 1. Aero family of adapters.
+ * 2. When user sets module parameter- perf_mode in range of 0-2.
+ */
+ if ((perf_mode >= MR_BALANCED_PERF_MODE) &&
+ (perf_mode <= MR_LATENCY_PERF_MODE))
+ instance->perf_mode = perf_mode;
+ /*
+ * If intr coalescing is not supported by controller FW, then IOPS
+ * and Balanced modes are not feasible.
+ */
+ if (!intr_coalescing)
+ instance->perf_mode = MR_LATENCY_PERF_MODE;
+
+ }
+
+ if (instance->perf_mode == MR_BALANCED_PERF_MODE)
+ instance->low_latency_index_start =
+ MR_HIGH_IOPS_QUEUE_COUNT;
+ else
+ instance->low_latency_index_start = 1;
+
+ num_msix_req = num_online_cpus() + instance->low_latency_index_start;
+
+ instance->msix_vectors = min(num_msix_req,
+ instance->msix_vectors);
+
+ megasas_alloc_irq_vectors(instance);
+ if (!instance->msix_vectors)
+ instance->msix_load_balance = false;
}
/*
* MSI-X host index 0 is common for all adapter.
@@ -5669,8 +6059,6 @@ static int megasas_init_fw(struct megasas_instance *instance)
megasas_setup_reply_map(instance);
dev_info(&instance->pdev->dev,
- "firmware supports msix\t: (%d)", fw_msix_count);
- dev_info(&instance->pdev->dev,
"current msix/online cpus\t: (%d/%d)\n",
instance->msix_vectors, (unsigned int)num_online_cpus());
dev_info(&instance->pdev->dev,
@@ -5707,6 +6095,9 @@ static int megasas_init_fw(struct megasas_instance *instance)
megasas_setup_irqs_ioapic(instance))
goto fail_init_adapter;
+ if (instance->adapter_type != MFI_SERIES)
+ megasas_setup_irq_poll(instance);
+
instance->instancet->enable_intr(instance);
dev_info(&instance->pdev->dev, "INIT adapter done\n");
@@ -5833,8 +6224,8 @@ static int megasas_init_fw(struct megasas_instance *instance)
instance->UnevenSpanSupport ? "yes" : "no");
dev_info(&instance->pdev->dev, "firmware crash dump : %s\n",
instance->crash_dump_drv_support ? "yes" : "no");
- dev_info(&instance->pdev->dev, "jbod sync map : %s\n",
- instance->use_seqnum_jbod_fp ? "yes" : "no");
+ dev_info(&instance->pdev->dev, "JBOD sequence map : %s\n",
+ instance->use_seqnum_jbod_fp ? "enabled" : "disabled");
instance->max_sectors_per_req = instance->max_num_sge *
SGE_BUFFER_SIZE / 512;
@@ -6197,8 +6588,10 @@ megasas_get_target_prop(struct megasas_instance *instance,
switch (dcmd_timeout_ocr_possible(instance)) {
case INITIATE_OCR:
cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+ mutex_unlock(&instance->reset_mutex);
megasas_reset_fusion(instance->host,
MFI_IO_TIMEOUT_OCR);
+ mutex_lock(&instance->reset_mutex);
break;
case KILL_ADAPTER:
megaraid_sas_kill_hba(instance);
@@ -6748,6 +7141,7 @@ static inline void megasas_init_ctrl_params(struct megasas_instance *instance)
INIT_LIST_HEAD(&instance->internal_reset_pending_q);
atomic_set(&instance->fw_outstanding, 0);
+ atomic64_set(&instance->total_io_count, 0);
init_waitqueue_head(&instance->int_cmd_wait_q);
init_waitqueue_head(&instance->abort_cmd_wait_q);
@@ -6770,6 +7164,8 @@ static inline void megasas_init_ctrl_params(struct megasas_instance *instance)
instance->last_time = 0;
instance->disableOnlineCtrlReset = 1;
instance->UnevenSpanSupport = 0;
+ instance->smp_affinity_enable = smp_affinity_enable ? true : false;
+ instance->msix_load_balance = false;
if (instance->adapter_type != MFI_SERIES)
INIT_WORK(&instance->work_init, megasas_fusion_ocr_wq);
@@ -6791,6 +7187,12 @@ static int megasas_probe_one(struct pci_dev *pdev,
u16 control = 0;
switch (pdev->device) {
+ case PCI_DEVICE_ID_LSI_AERO_10E0:
+ case PCI_DEVICE_ID_LSI_AERO_10E3:
+ case PCI_DEVICE_ID_LSI_AERO_10E4:
+ case PCI_DEVICE_ID_LSI_AERO_10E7:
+ dev_err(&pdev->dev, "Adapter is in non secure mode\n");
+ return 1;
case PCI_DEVICE_ID_LSI_AERO_10E1:
case PCI_DEVICE_ID_LSI_AERO_10E5:
dev_info(&pdev->dev, "Adapter is in configurable secure mode\n");
@@ -6910,6 +7312,8 @@ static int megasas_probe_one(struct pci_dev *pdev,
goto fail_start_aen;
}
+ megasas_setup_debugfs(instance);
+
/* Get current SR-IOV LD/VF affiliation */
if (instance->requestorId)
megasas_get_ld_vf_affiliation(instance, 1);
@@ -7041,13 +7445,17 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
static int
megasas_suspend(struct pci_dev *pdev, pm_message_t state)
{
- struct Scsi_Host *host;
struct megasas_instance *instance;
instance = pci_get_drvdata(pdev);
- host = instance->host;
+
+ if (!instance)
+ return 0;
+
instance->unload = 1;
+ dev_info(&pdev->dev, "%s is called\n", __func__);
+
/* Shutdown SR-IOV heartbeat timer */
if (instance->requestorId && !instance->skip_heartbeat_timer_del)
del_timer_sync(&instance->sriov_heartbeat_timer);
@@ -7097,11 +7505,16 @@ megasas_resume(struct pci_dev *pdev)
int irq_flags = PCI_IRQ_LEGACY;
instance = pci_get_drvdata(pdev);
+
+ if (!instance)
+ return 0;
+
host = instance->host;
pci_set_power_state(pdev, PCI_D0);
pci_enable_wake(pdev, PCI_D0, 0);
pci_restore_state(pdev);
+ dev_info(&pdev->dev, "%s is called\n", __func__);
/*
* PCI prepping: enable device set bus mastering and dma mask
*/
@@ -7133,7 +7546,7 @@ megasas_resume(struct pci_dev *pdev)
/* Now re-enable MSI-X */
if (instance->msix_vectors) {
irq_flags = PCI_IRQ_MSIX;
- if (smp_affinity_enable)
+ if (instance->smp_affinity_enable)
irq_flags |= PCI_IRQ_AFFINITY;
}
rval = pci_alloc_irq_vectors(instance->pdev, 1,
@@ -7171,6 +7584,9 @@ megasas_resume(struct pci_dev *pdev)
megasas_setup_irqs_ioapic(instance))
goto fail_init_mfi;
+ if (instance->adapter_type != MFI_SERIES)
+ megasas_setup_irq_poll(instance);
+
/* Re-launch SR-IOV heartbeat timer */
if (instance->requestorId) {
if (!megasas_sriov_start_heartbeat(instance, 0))
@@ -7261,6 +7677,10 @@ static void megasas_detach_one(struct pci_dev *pdev)
u32 pd_seq_map_sz;
instance = pci_get_drvdata(pdev);
+
+ if (!instance)
+ return;
+
host = instance->host;
fusion = instance->ctrl_context;
@@ -7374,6 +7794,8 @@ skip_firing_dcmds:
megasas_free_ctrl_mem(instance);
+ megasas_destroy_debugfs(instance);
+
scsi_host_put(host);
pci_disable_device(pdev);
@@ -7387,6 +7809,9 @@ static void megasas_shutdown(struct pci_dev *pdev)
{
struct megasas_instance *instance = pci_get_drvdata(pdev);
+ if (!instance)
+ return;
+
instance->unload = 1;
if (megasas_wait_for_adapter_operational(instance))
@@ -7532,7 +7957,9 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
if ((ioc->frame.hdr.cmd >= MFI_CMD_OP_COUNT) ||
((ioc->frame.hdr.cmd == MFI_CMD_NVME) &&
- !instance->support_nvme_passthru)) {
+ !instance->support_nvme_passthru) ||
+ ((ioc->frame.hdr.cmd == MFI_CMD_TOOLBOX) &&
+ !instance->support_pci_lane_margining)) {
dev_err(&instance->pdev->dev,
"Received invalid ioctl command 0x%x\n",
ioc->frame.hdr.cmd);
@@ -7568,10 +7995,13 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
opcode = le32_to_cpu(cmd->frame->dcmd.opcode);
if (opcode == MR_DCMD_CTRL_SHUTDOWN) {
+ mutex_lock(&instance->reset_mutex);
if (megasas_get_ctrl_info(instance) != DCMD_SUCCESS) {
megasas_return_cmd(instance, cmd);
+ mutex_unlock(&instance->reset_mutex);
return -1;
}
+ mutex_unlock(&instance->reset_mutex);
}
if (opcode == MR_DRIVER_SET_APP_CRASHDUMP_MODE) {
@@ -8013,6 +8443,14 @@ support_nvme_encapsulation_show(struct device_driver *dd, char *buf)
static DRIVER_ATTR_RO(support_nvme_encapsulation);
+static ssize_t
+support_pci_lane_margining_show(struct device_driver *dd, char *buf)
+{
+ return sprintf(buf, "%u\n", support_pci_lane_margining);
+}
+
+static DRIVER_ATTR_RO(support_pci_lane_margining);
+
static inline void megasas_remove_scsi_device(struct scsi_device *sdev)
{
sdev_printk(KERN_INFO, sdev, "SCSI device is removed\n");
@@ -8161,7 +8599,7 @@ megasas_aen_polling(struct work_struct *work)
struct megasas_instance *instance = ev->instance;
union megasas_evt_class_locale class_locale;
int event_type = 0;
- u32 seq_num, wait_time = MEGASAS_RESET_WAIT_TIME;
+ u32 seq_num;
int error;
u8 dcmd_ret = DCMD_SUCCESS;
@@ -8171,10 +8609,6 @@ megasas_aen_polling(struct work_struct *work)
return;
}
- /* Adjust event workqueue thread wait time for VF mode */
- if (instance->requestorId)
- wait_time = MEGASAS_ROUTINE_WAIT_TIME_VF;
-
/* Don't run the event workqueue thread if OCR is running */
mutex_lock(&instance->reset_mutex);
@@ -8286,6 +8720,7 @@ static int __init megasas_init(void)
support_poll_for_event = 2;
support_device_change = 1;
support_nvme_encapsulation = true;
+ support_pci_lane_margining = true;
memset(&megasas_mgmt_info, 0, sizeof(megasas_mgmt_info));
@@ -8301,6 +8736,8 @@ static int __init megasas_init(void)
megasas_mgmt_majorno = rval;
+ megasas_init_debugfs();
+
/*
* Register ourselves as PCI hotplug module
*/
@@ -8340,8 +8777,17 @@ static int __init megasas_init(void)
if (rval)
goto err_dcf_support_nvme_encapsulation;
+ rval = driver_create_file(&megasas_pci_driver.driver,
+ &driver_attr_support_pci_lane_margining);
+ if (rval)
+ goto err_dcf_support_pci_lane_margining;
+
return rval;
+err_dcf_support_pci_lane_margining:
+ driver_remove_file(&megasas_pci_driver.driver,
+ &driver_attr_support_nvme_encapsulation);
+
err_dcf_support_nvme_encapsulation:
driver_remove_file(&megasas_pci_driver.driver,
&driver_attr_support_device_change);
@@ -8360,6 +8806,7 @@ err_dcf_rel_date:
err_dcf_attr_ver:
pci_unregister_driver(&megasas_pci_driver);
err_pcidrv:
+ megasas_exit_debugfs();
unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
return rval;
}
@@ -8380,8 +8827,11 @@ static void __exit megasas_exit(void)
driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
driver_remove_file(&megasas_pci_driver.driver,
&driver_attr_support_nvme_encapsulation);
+ driver_remove_file(&megasas_pci_driver.driver,
+ &driver_attr_support_pci_lane_margining);
pci_unregister_driver(&megasas_pci_driver);
+ megasas_exit_debugfs();
unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
}
diff --git a/drivers/scsi/megaraid/megaraid_sas_debugfs.c b/drivers/scsi/megaraid/megaraid_sas_debugfs.c
new file mode 100644
index 000000000000..c69760775efa
--- /dev/null
+++ b/drivers/scsi/megaraid/megaraid_sas_debugfs.c
@@ -0,0 +1,179 @@
+/*
+ * Linux MegaRAID driver for SAS based RAID controllers
+ *
+ * Copyright (c) 2003-2018 LSI Corporation.
+ * Copyright (c) 2003-2018 Avago Technologies.
+ * Copyright (c) 2003-2018 Broadcom Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Broadcom Inc.
+ * Kashyap Desai <kashyap.desai@broadcom.com>
+ * Sumit Saxena <sumit.saxena@broadcom.com>
+ * Shivasharan S <shivasharan.srikanteshwara@broadcom.com>
+ *
+ * Send feedback to: megaraidlinux.pdl@broadcom.com
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/compat.h>
+#include <linux/irq_poll.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#include "megaraid_sas_fusion.h"
+#include "megaraid_sas.h"
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+
+struct dentry *megasas_debugfs_root;
+
+static ssize_t
+megasas_debugfs_read(struct file *filp, char __user *ubuf, size_t cnt,
+ loff_t *ppos)
+{
+ struct megasas_debugfs_buffer *debug = filp->private_data;
+
+ if (!debug || !debug->buf)
+ return 0;
+
+ return simple_read_from_buffer(ubuf, cnt, ppos, debug->buf, debug->len);
+}
+
+static int
+megasas_debugfs_raidmap_open(struct inode *inode, struct file *file)
+{
+ struct megasas_instance *instance = inode->i_private;
+ struct megasas_debugfs_buffer *debug;
+ struct fusion_context *fusion;
+
+ fusion = instance->ctrl_context;
+
+ debug = kzalloc(sizeof(struct megasas_debugfs_buffer), GFP_KERNEL);
+ if (!debug)
+ return -ENOMEM;
+
+ debug->buf = (void *)fusion->ld_drv_map[(instance->map_id & 1)];
+ debug->len = fusion->drv_map_sz;
+ file->private_data = debug;
+
+ return 0;
+}
+
+static int
+megasas_debugfs_release(struct inode *inode, struct file *file)
+{
+ struct megasas_debug_buffer *debug = file->private_data;
+
+ if (!debug)
+ return 0;
+
+ file->private_data = NULL;
+ kfree(debug);
+ return 0;
+}
+
+static const struct file_operations megasas_debugfs_raidmap_fops = {
+ .owner = THIS_MODULE,
+ .open = megasas_debugfs_raidmap_open,
+ .read = megasas_debugfs_read,
+ .release = megasas_debugfs_release,
+};
+
+/*
+ * megasas_init_debugfs : Create debugfs root for megaraid_sas driver
+ */
+void megasas_init_debugfs(void)
+{
+ megasas_debugfs_root = debugfs_create_dir("megaraid_sas", NULL);
+ if (!megasas_debugfs_root)
+ pr_info("Cannot create debugfs root\n");
+}
+
+/*
+ * megasas_exit_debugfs : Remove debugfs root for megaraid_sas driver
+ */
+void megasas_exit_debugfs(void)
+{
+ debugfs_remove_recursive(megasas_debugfs_root);
+}
+
+/*
+ * megasas_setup_debugfs : Setup debugfs per Fusion adapter
+ * instance: Soft instance of adapter
+ */
+void
+megasas_setup_debugfs(struct megasas_instance *instance)
+{
+ char name[64];
+ struct fusion_context *fusion;
+
+ fusion = instance->ctrl_context;
+
+ if (fusion) {
+ snprintf(name, sizeof(name),
+ "scsi_host%d", instance->host->host_no);
+ if (!instance->debugfs_root) {
+ instance->debugfs_root =
+ debugfs_create_dir(name, megasas_debugfs_root);
+ if (!instance->debugfs_root) {
+ dev_err(&instance->pdev->dev,
+ "Cannot create per adapter debugfs directory\n");
+ return;
+ }
+ }
+
+ snprintf(name, sizeof(name), "raidmap_dump");
+ instance->raidmap_dump =
+ debugfs_create_file(name, S_IRUGO,
+ instance->debugfs_root, instance,
+ &megasas_debugfs_raidmap_fops);
+ if (!instance->raidmap_dump) {
+ dev_err(&instance->pdev->dev,
+ "Cannot create raidmap debugfs file\n");
+ debugfs_remove(instance->debugfs_root);
+ return;
+ }
+ }
+
+}
+
+/*
+ * megasas_destroy_debugfs : Destroy debugfs per Fusion adapter
+ * instance: Soft instance of adapter
+ */
+void megasas_destroy_debugfs(struct megasas_instance *instance)
+{
+ debugfs_remove_recursive(instance->debugfs_root);
+}
+
+#else
+void megasas_init_debugfs(void)
+{
+}
+void megasas_exit_debugfs(void)
+{
+}
+void megasas_setup_debugfs(struct megasas_instance *instance)
+{
+}
+void megasas_destroy_debugfs(struct megasas_instance *instance)
+{
+}
+#endif /*CONFIG_DEBUG_FS*/
diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c
index 12637606c46d..50b8c1b12767 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fp.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fp.c
@@ -33,6 +33,7 @@
#include <linux/compat.h>
#include <linux/blkdev.h>
#include <linux/poll.h>
+#include <linux/irq_poll.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -45,7 +46,7 @@
#define LB_PENDING_CMDS_DEFAULT 4
static unsigned int lb_pending_cmds = LB_PENDING_CMDS_DEFAULT;
-module_param(lb_pending_cmds, int, S_IRUGO);
+module_param(lb_pending_cmds, int, 0444);
MODULE_PARM_DESC(lb_pending_cmds, "Change raid-1 load balancing outstanding "
"threshold. Valid Values are 1-128. Default: 4");
@@ -889,6 +890,77 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow,
}
/*
+ * mr_get_phy_params_r56_rmw - Calculate parameters for R56 CTIO write operation
+ * @instance: Adapter soft state
+ * @ld: LD index
+ * @stripNo: Strip Number
+ * @io_info: IO info structure pointer
+ * pRAID_Context: RAID context pointer
+ * map: RAID map pointer
+ *
+ * This routine calculates the logical arm, data Arm, row number and parity arm
+ * for R56 CTIO write operation.
+ */
+static void mr_get_phy_params_r56_rmw(struct megasas_instance *instance,
+ u32 ld, u64 stripNo,
+ struct IO_REQUEST_INFO *io_info,
+ struct RAID_CONTEXT_G35 *pRAID_Context,
+ struct MR_DRV_RAID_MAP_ALL *map)
+{
+ struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map);
+ u8 span, dataArms, arms, dataArm, logArm;
+ s8 rightmostParityArm, PParityArm;
+ u64 rowNum;
+ u64 *pdBlock = &io_info->pdBlock;
+
+ dataArms = raid->rowDataSize;
+ arms = raid->rowSize;
+
+ rowNum = mega_div64_32(stripNo, dataArms);
+ /* parity disk arm, first arm is 0 */
+ rightmostParityArm = (arms - 1) - mega_mod64(rowNum, arms);
+
+ /* logical arm within row */
+ logArm = mega_mod64(stripNo, dataArms);
+ /* physical arm for data */
+ dataArm = mega_mod64((rightmostParityArm + 1 + logArm), arms);
+
+ if (raid->spanDepth == 1) {
+ span = 0;
+ } else {
+ span = (u8)MR_GetSpanBlock(ld, rowNum, pdBlock, map);
+ if (span == SPAN_INVALID)
+ return;
+ }
+
+ if (raid->level == 6) {
+ /* P Parity arm, note this can go negative adjust if negative */
+ PParityArm = (arms - 2) - mega_mod64(rowNum, arms);
+
+ if (PParityArm < 0)
+ PParityArm += arms;
+
+ /* rightmostParityArm is P-Parity for RAID 5 and Q-Parity for RAID */
+ pRAID_Context->flow_specific.r56_arm_map = rightmostParityArm;
+ pRAID_Context->flow_specific.r56_arm_map |=
+ (u16)(PParityArm << RAID_CTX_R56_P_ARM_SHIFT);
+ } else {
+ pRAID_Context->flow_specific.r56_arm_map |=
+ (u16)(rightmostParityArm << RAID_CTX_R56_P_ARM_SHIFT);
+ }
+
+ pRAID_Context->reg_lock_row_lba = cpu_to_le64(rowNum);
+ pRAID_Context->flow_specific.r56_arm_map |=
+ (u16)(logArm << RAID_CTX_R56_LOG_ARM_SHIFT);
+ cpu_to_le16s(&pRAID_Context->flow_specific.r56_arm_map);
+ pRAID_Context->span_arm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | dataArm;
+ pRAID_Context->raid_flags = (MR_RAID_FLAGS_IO_SUB_TYPE_R56_DIV_OFFLOAD <<
+ MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT);
+
+ return;
+}
+
+/*
******************************************************************************
*
* MR_BuildRaidContext function
@@ -954,6 +1026,7 @@ MR_BuildRaidContext(struct megasas_instance *instance,
stripSize = 1 << raid->stripeShift;
stripe_mask = stripSize-1;
+ io_info->data_arms = raid->rowDataSize;
/*
* calculate starting row and stripe, and number of strips and rows
@@ -1095,6 +1168,13 @@ MR_BuildRaidContext(struct megasas_instance *instance,
/* save pointer to raid->LUN array */
*raidLUN = raid->LUN;
+ /* Aero R5/6 Division Offload for WRITE */
+ if (fusion->r56_div_offload && (raid->level >= 5) && !isRead) {
+ mr_get_phy_params_r56_rmw(instance, ld, start_strip, io_info,
+ (struct RAID_CONTEXT_G35 *)pRAID_Context,
+ map);
+ return true;
+ }
/*Get Phy Params only if FP capable, or else leave it to MR firmware
to do the calculation.*/
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index 4dfa0685a86c..a32b3f0fcd15 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -35,6 +35,7 @@
#include <linux/poll.h>
#include <linux/vmalloc.h>
#include <linux/workqueue.h>
+#include <linux/irq_poll.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -87,6 +88,62 @@ extern u32 megasas_readl(struct megasas_instance *instance,
const volatile void __iomem *addr);
/**
+ * megasas_adp_reset_wait_for_ready - initiate chip reset and wait for
+ * controller to come to ready state
+ * @instance - adapter's soft state
+ * @do_adp_reset - If true, do a chip reset
+ * @ocr_context - If called from OCR context this will
+ * be set to 1, else 0
+ *
+ * This function initates a chip reset followed by a wait for controller to
+ * transition to ready state.
+ * During this, driver will block all access to PCI config space from userspace
+ */
+int
+megasas_adp_reset_wait_for_ready(struct megasas_instance *instance,
+ bool do_adp_reset,
+ int ocr_context)
+{
+ int ret = FAILED;
+
+ /*
+ * Block access to PCI config space from userspace
+ * when diag reset is initiated from driver
+ */
+ if (megasas_dbg_lvl & OCR_DEBUG)
+ dev_info(&instance->pdev->dev,
+ "Block access to PCI config space %s %d\n",
+ __func__, __LINE__);
+
+ pci_cfg_access_lock(instance->pdev);
+
+ if (do_adp_reset) {
+ if (instance->instancet->adp_reset
+ (instance, instance->reg_set))
+ goto out;
+ }
+
+ /* Wait for FW to become ready */
+ if (megasas_transition_to_ready(instance, ocr_context)) {
+ dev_warn(&instance->pdev->dev,
+ "Failed to transition controller to ready for scsi%d.\n",
+ instance->host->host_no);
+ goto out;
+ }
+
+ ret = SUCCESS;
+out:
+ if (megasas_dbg_lvl & OCR_DEBUG)
+ dev_info(&instance->pdev->dev,
+ "Unlock access to PCI config space %s %d\n",
+ __func__, __LINE__);
+
+ pci_cfg_access_unlock(instance->pdev);
+
+ return ret;
+}
+
+/**
* megasas_check_same_4gb_region - check if allocation
* crosses same 4GB boundary or not
* @instance - adapter's soft instance
@@ -133,7 +190,8 @@ megasas_enable_intr_fusion(struct megasas_instance *instance)
writel(~MFI_FUSION_ENABLE_INTERRUPT_MASK, &(regs)->outbound_intr_mask);
/* Dummy readl to force pci flush */
- readl(&regs->outbound_intr_mask);
+ dev_info(&instance->pdev->dev, "%s is called outbound_intr_mask:0x%08x\n",
+ __func__, readl(&regs->outbound_intr_mask));
}
/**
@@ -144,14 +202,14 @@ void
megasas_disable_intr_fusion(struct megasas_instance *instance)
{
u32 mask = 0xFFFFFFFF;
- u32 status;
struct megasas_register_set __iomem *regs;
regs = instance->reg_set;
instance->mask_interrupts = 1;
writel(mask, &regs->outbound_intr_mask);
/* Dummy readl to force pci flush */
- status = readl(&regs->outbound_intr_mask);
+ dev_info(&instance->pdev->dev, "%s is called outbound_intr_mask:0x%08x\n",
+ __func__, readl(&regs->outbound_intr_mask));
}
int
@@ -207,21 +265,17 @@ inline void megasas_return_cmd_fusion(struct megasas_instance *instance,
}
/**
- * megasas_fire_cmd_fusion - Sends command to the FW
- * @instance: Adapter soft state
- * @req_desc: 64bit Request descriptor
- *
- * Perform PCI Write.
+ * megasas_write_64bit_req_desc - PCI writes 64bit request descriptor
+ * @instance: Adapter soft state
+ * @req_desc: 64bit Request descriptor
*/
-
static void
-megasas_fire_cmd_fusion(struct megasas_instance *instance,
+megasas_write_64bit_req_desc(struct megasas_instance *instance,
union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc)
{
#if defined(writeq) && defined(CONFIG_64BIT)
u64 req_data = (((u64)le32_to_cpu(req_desc->u.high) << 32) |
le32_to_cpu(req_desc->u.low));
-
writeq(req_data, &instance->reg_set->inbound_low_queue_port);
#else
unsigned long flags;
@@ -235,6 +289,25 @@ megasas_fire_cmd_fusion(struct megasas_instance *instance,
}
/**
+ * megasas_fire_cmd_fusion - Sends command to the FW
+ * @instance: Adapter soft state
+ * @req_desc: 32bit or 64bit Request descriptor
+ *
+ * Perform PCI Write. AERO SERIES supports 32 bit Descriptor.
+ * Prior to AERO_SERIES support 64 bit Descriptor.
+ */
+static void
+megasas_fire_cmd_fusion(struct megasas_instance *instance,
+ union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc)
+{
+ if (instance->atomic_desc_support)
+ writel(le32_to_cpu(req_desc->u.low),
+ &instance->reg_set->inbound_single_queue_port);
+ else
+ megasas_write_64bit_req_desc(instance, req_desc);
+}
+
+/**
* megasas_fusion_update_can_queue - Do all Adapter Queue depth related calculations here
* @instance: Adapter soft state
* fw_boot_context: Whether this function called during probe or after OCR
@@ -924,6 +997,7 @@ wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
{
int i;
struct megasas_header *frame_hdr = &cmd->frame->hdr;
+ u32 status_reg;
u32 msecs = seconds * 1000;
@@ -933,6 +1007,12 @@ wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
for (i = 0; (i < msecs) && (frame_hdr->cmd_status == 0xff); i += 20) {
rmb();
msleep(20);
+ if (!(i % 5000)) {
+ status_reg = instance->instancet->read_fw_status_reg(instance)
+ & MFI_STATE_MASK;
+ if (status_reg == MFI_STATE_FAULT)
+ break;
+ }
}
if (frame_hdr->cmd_status == MFI_STAT_INVALID_STATUS)
@@ -966,6 +1046,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
u32 scratch_pad_1;
ktime_t time;
bool cur_fw_64bit_dma_capable;
+ bool cur_intr_coalescing;
fusion = instance->ctrl_context;
@@ -999,6 +1080,16 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
goto fail_fw_init;
}
+ cur_intr_coalescing = (scratch_pad_1 & MR_INTR_COALESCING_SUPPORT_OFFSET) ?
+ true : false;
+
+ if ((instance->low_latency_index_start ==
+ MR_HIGH_IOPS_QUEUE_COUNT) && cur_intr_coalescing)
+ instance->perf_mode = MR_BALANCED_PERF_MODE;
+
+ dev_info(&instance->pdev->dev, "Performance mode :%s\n",
+ MEGASAS_PERF_MODE_2STR(instance->perf_mode));
+
instance->fw_sync_cache_support = (scratch_pad_1 &
MR_CAN_HANDLE_SYNC_CACHE_OFFSET) ? 1 : 0;
dev_info(&instance->pdev->dev, "FW supports sync cache\t: %s\n",
@@ -1083,6 +1174,22 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
cpu_to_le32(lower_32_bits(ioc_init_handle));
init_frame->data_xfer_len = cpu_to_le32(sizeof(struct MPI2_IOC_INIT_REQUEST));
+ /*
+ * Each bit in replyqueue_mask represents one group of MSI-x vectors
+ * (each group has 8 vectors)
+ */
+ switch (instance->perf_mode) {
+ case MR_BALANCED_PERF_MODE:
+ init_frame->replyqueue_mask =
+ cpu_to_le16(~(~0 << instance->low_latency_index_start/8));
+ break;
+ case MR_IOPS_PERF_MODE:
+ init_frame->replyqueue_mask =
+ cpu_to_le16(~(~0 << instance->msix_vectors/8));
+ break;
+ }
+
+
req_desc.u.low = cpu_to_le32(lower_32_bits(cmd->frame_phys_addr));
req_desc.u.high = cpu_to_le32(upper_32_bits(cmd->frame_phys_addr));
req_desc.MFAIo.RequestFlags =
@@ -1101,7 +1208,8 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
break;
}
- megasas_fire_cmd_fusion(instance, &req_desc);
+ /* For AERO also, IOC_INIT requires 64 bit descriptor write */
+ megasas_write_64bit_req_desc(instance, &req_desc);
wait_and_poll(instance, cmd, MFI_IO_TIMEOUT_SECS);
@@ -1111,6 +1219,17 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
goto fail_fw_init;
}
+ if (instance->adapter_type >= AERO_SERIES) {
+ scratch_pad_1 = megasas_readl
+ (instance, &instance->reg_set->outbound_scratch_pad_1);
+
+ instance->atomic_desc_support =
+ (scratch_pad_1 & MR_ATOMIC_DESCRIPTOR_SUPPORT_OFFSET) ? 1 : 0;
+
+ dev_info(&instance->pdev->dev, "FW supports atomic descriptor\t: %s\n",
+ instance->atomic_desc_support ? "Yes" : "No");
+ }
+
return 0;
fail_fw_init:
@@ -1133,7 +1252,7 @@ fail_fw_init:
int
megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend) {
int ret = 0;
- u32 pd_seq_map_sz;
+ size_t pd_seq_map_sz;
struct megasas_cmd *cmd;
struct megasas_dcmd_frame *dcmd;
struct fusion_context *fusion = instance->ctrl_context;
@@ -1142,9 +1261,7 @@ megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend) {
pd_sync = (void *)fusion->pd_seq_sync[(instance->pd_seq_map_id & 1)];
pd_seq_h = fusion->pd_seq_phys[(instance->pd_seq_map_id & 1)];
- pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) +
- (sizeof(struct MR_PD_CFG_SEQ) *
- (MAX_PHYSICAL_DEVICES - 1));
+ pd_seq_map_sz = struct_size(pd_sync, seq, MAX_PHYSICAL_DEVICES - 1);
cmd = megasas_get_cmd(instance);
if (!cmd) {
@@ -1625,6 +1742,7 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
struct fusion_context *fusion;
u32 scratch_pad_1;
int i = 0, count;
+ u32 status_reg;
fusion = instance->ctrl_context;
@@ -1707,8 +1825,21 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
if (megasas_alloc_cmds_fusion(instance))
goto fail_alloc_cmds;
- if (megasas_ioc_init_fusion(instance))
- goto fail_ioc_init;
+ if (megasas_ioc_init_fusion(instance)) {
+ status_reg = instance->instancet->read_fw_status_reg(instance);
+ if (((status_reg & MFI_STATE_MASK) == MFI_STATE_FAULT) &&
+ (status_reg & MFI_RESET_ADAPTER)) {
+ /* Do a chip reset and then retry IOC INIT once */
+ if (megasas_adp_reset_wait_for_ready
+ (instance, true, 0) == FAILED)
+ goto fail_ioc_init;
+
+ if (megasas_ioc_init_fusion(instance))
+ goto fail_ioc_init;
+ } else {
+ goto fail_ioc_init;
+ }
+ }
megasas_display_intel_branding(instance);
if (megasas_get_ctrl_info(instance)) {
@@ -1720,6 +1851,7 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
instance->flag_ieee = 1;
instance->r1_ldio_hint_default = MR_R1_LDIO_PIGGYBACK_DEFAULT;
+ instance->threshold_reply_count = instance->max_fw_cmds / 4;
fusion->fast_path_io = 0;
if (megasas_allocate_raid_maps(instance))
@@ -1970,7 +2102,6 @@ megasas_is_prp_possible(struct megasas_instance *instance,
mega_mod64(sg_dma_address(sg_scmd),
mr_nvme_pg_size)) {
build_prp = false;
- atomic_inc(&instance->sge_holes_type1);
break;
}
}
@@ -1980,7 +2111,6 @@ megasas_is_prp_possible(struct megasas_instance *instance,
sg_dma_len(sg_scmd)),
mr_nvme_pg_size))) {
build_prp = false;
- atomic_inc(&instance->sge_holes_type2);
break;
}
}
@@ -1989,7 +2119,6 @@ megasas_is_prp_possible(struct megasas_instance *instance,
if (mega_mod64(sg_dma_address(sg_scmd),
mr_nvme_pg_size)) {
build_prp = false;
- atomic_inc(&instance->sge_holes_type3);
break;
}
}
@@ -2122,7 +2251,6 @@ megasas_make_prp_nvme(struct megasas_instance *instance, struct scsi_cmnd *scmd,
main_chain_element->Length =
cpu_to_le32(num_prp_in_chain * sizeof(u64));
- atomic_inc(&instance->prp_sgl);
return build_prp;
}
@@ -2197,7 +2325,6 @@ megasas_make_sgl_fusion(struct megasas_instance *instance,
memset(sgl_ptr, 0, instance->max_chain_frame_sz);
}
}
- atomic_inc(&instance->ieee_sgl);
}
/**
@@ -2509,9 +2636,10 @@ static void megasas_stream_detect(struct megasas_instance *instance,
*
*/
static void
-megasas_set_raidflag_cpu_affinity(union RAID_CONTEXT_UNION *praid_context,
- struct MR_LD_RAID *raid, bool fp_possible,
- u8 is_read, u32 scsi_buff_len)
+megasas_set_raidflag_cpu_affinity(struct fusion_context *fusion,
+ union RAID_CONTEXT_UNION *praid_context,
+ struct MR_LD_RAID *raid, bool fp_possible,
+ u8 is_read, u32 scsi_buff_len)
{
u8 cpu_sel = MR_RAID_CTX_CPUSEL_0;
struct RAID_CONTEXT_G35 *rctx_g35;
@@ -2569,11 +2697,11 @@ megasas_set_raidflag_cpu_affinity(union RAID_CONTEXT_UNION *praid_context,
* vs MR_RAID_FLAGS_IO_SUB_TYPE_CACHE_BYPASS.
* IO Subtype is not bitmap.
*/
- if ((raid->level == 1) && (!is_read)) {
- if (scsi_buff_len > MR_LARGE_IO_MIN_SIZE)
- praid_context->raid_context_g35.raid_flags =
- (MR_RAID_FLAGS_IO_SUB_TYPE_LDIO_BW_LIMIT
- << MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT);
+ if ((fusion->pcie_bw_limitation) && (raid->level == 1) && (!is_read) &&
+ (scsi_buff_len > MR_LARGE_IO_MIN_SIZE)) {
+ praid_context->raid_context_g35.raid_flags =
+ (MR_RAID_FLAGS_IO_SUB_TYPE_LDIO_BW_LIMIT
+ << MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT);
}
}
@@ -2679,6 +2807,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
io_info.r1_alt_dev_handle = MR_DEVHANDLE_INVALID;
scsi_buff_len = scsi_bufflen(scp);
io_request->DataLength = cpu_to_le32(scsi_buff_len);
+ io_info.data_arms = 1;
if (scp->sc_data_direction == DMA_FROM_DEVICE)
io_info.isRead = 1;
@@ -2698,8 +2827,19 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
fp_possible = (io_info.fpOkForIo > 0) ? true : false;
}
- cmd->request_desc->SCSIIO.MSIxIndex =
- instance->reply_map[raw_smp_processor_id()];
+ if ((instance->perf_mode == MR_BALANCED_PERF_MODE) &&
+ atomic_read(&scp->device->device_busy) >
+ (io_info.data_arms * MR_DEVICE_HIGH_IOPS_DEPTH))
+ cmd->request_desc->SCSIIO.MSIxIndex =
+ mega_mod64((atomic64_add_return(1, &instance->high_iops_outstanding) /
+ MR_HIGH_IOPS_BATCH_COUNT), instance->low_latency_index_start);
+ else if (instance->msix_load_balance)
+ cmd->request_desc->SCSIIO.MSIxIndex =
+ (mega_mod64(atomic64_add_return(1, &instance->total_io_count),
+ instance->msix_vectors));
+ else
+ cmd->request_desc->SCSIIO.MSIxIndex =
+ instance->reply_map[raw_smp_processor_id()];
if (instance->adapter_type >= VENTURA_SERIES) {
/* FP for Optimal raid level 1.
@@ -2717,8 +2857,9 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
(instance->host->can_queue)) {
fp_possible = false;
atomic_dec(&instance->fw_outstanding);
- } else if ((scsi_buff_len > MR_LARGE_IO_MIN_SIZE) ||
- (atomic_dec_if_positive(&mrdev_priv->r1_ldio_hint) > 0)) {
+ } else if (fusion->pcie_bw_limitation &&
+ ((scsi_buff_len > MR_LARGE_IO_MIN_SIZE) ||
+ (atomic_dec_if_positive(&mrdev_priv->r1_ldio_hint) > 0))) {
fp_possible = false;
atomic_dec(&instance->fw_outstanding);
if (scsi_buff_len > MR_LARGE_IO_MIN_SIZE)
@@ -2743,7 +2884,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
/* If raid is NULL, set CPU affinity to default CPU0 */
if (raid)
- megasas_set_raidflag_cpu_affinity(&io_request->RaidContext,
+ megasas_set_raidflag_cpu_affinity(fusion, &io_request->RaidContext,
raid, fp_possible, io_info.isRead,
scsi_buff_len);
else
@@ -2759,10 +2900,6 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
(MPI2_REQ_DESCRIPT_FLAGS_FP_IO
<< MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
if (instance->adapter_type == INVADER_SERIES) {
- if (rctx->reg_lock_flags == REGION_TYPE_UNUSED)
- cmd->request_desc->SCSIIO.RequestFlags =
- (MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK <<
- MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
rctx->type = MPI2_TYPE_CUDA;
rctx->nseg = 0x1;
io_request->IoFlags |= cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH);
@@ -2970,50 +3107,71 @@ megasas_build_syspd_fusion(struct megasas_instance *instance,
<< MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT;
/* If FW supports PD sequence number */
- if (instance->use_seqnum_jbod_fp &&
- instance->pd_list[pd_index].driveType == TYPE_DISK) {
- /* TgtId must be incremented by 255 as jbod seq number is index
- * below raid map
- */
- /* More than 256 PD/JBOD support for Ventura */
- if (instance->support_morethan256jbod)
- pRAID_Context->virtual_disk_tgt_id =
- pd_sync->seq[pd_index].pd_target_id;
- else
- pRAID_Context->virtual_disk_tgt_id =
- cpu_to_le16(device_id + (MAX_PHYSICAL_DEVICES - 1));
- pRAID_Context->config_seq_num = pd_sync->seq[pd_index].seqNum;
- io_request->DevHandle = pd_sync->seq[pd_index].devHandle;
- if (instance->adapter_type >= VENTURA_SERIES) {
- io_request->RaidContext.raid_context_g35.routing_flags |=
- (1 << MR_RAID_CTX_ROUTINGFLAGS_SQN_SHIFT);
- io_request->RaidContext.raid_context_g35.nseg_type |=
- (1 << RAID_CONTEXT_NSEG_SHIFT);
- io_request->RaidContext.raid_context_g35.nseg_type |=
- (MPI2_TYPE_CUDA << RAID_CONTEXT_TYPE_SHIFT);
+ if (instance->support_seqnum_jbod_fp) {
+ if (instance->use_seqnum_jbod_fp &&
+ instance->pd_list[pd_index].driveType == TYPE_DISK) {
+
+ /* More than 256 PD/JBOD support for Ventura */
+ if (instance->support_morethan256jbod)
+ pRAID_Context->virtual_disk_tgt_id =
+ pd_sync->seq[pd_index].pd_target_id;
+ else
+ pRAID_Context->virtual_disk_tgt_id =
+ cpu_to_le16(device_id +
+ (MAX_PHYSICAL_DEVICES - 1));
+ pRAID_Context->config_seq_num =
+ pd_sync->seq[pd_index].seqNum;
+ io_request->DevHandle =
+ pd_sync->seq[pd_index].devHandle;
+ if (instance->adapter_type >= VENTURA_SERIES) {
+ io_request->RaidContext.raid_context_g35.routing_flags |=
+ (1 << MR_RAID_CTX_ROUTINGFLAGS_SQN_SHIFT);
+ io_request->RaidContext.raid_context_g35.nseg_type |=
+ (1 << RAID_CONTEXT_NSEG_SHIFT);
+ io_request->RaidContext.raid_context_g35.nseg_type |=
+ (MPI2_TYPE_CUDA << RAID_CONTEXT_TYPE_SHIFT);
+ } else {
+ pRAID_Context->type = MPI2_TYPE_CUDA;
+ pRAID_Context->nseg = 0x1;
+ pRAID_Context->reg_lock_flags |=
+ (MR_RL_FLAGS_SEQ_NUM_ENABLE |
+ MR_RL_FLAGS_GRANT_DESTINATION_CUDA);
+ }
} else {
- pRAID_Context->type = MPI2_TYPE_CUDA;
- pRAID_Context->nseg = 0x1;
- pRAID_Context->reg_lock_flags |=
- (MR_RL_FLAGS_SEQ_NUM_ENABLE|MR_RL_FLAGS_GRANT_DESTINATION_CUDA);
+ pRAID_Context->virtual_disk_tgt_id =
+ cpu_to_le16(device_id +
+ (MAX_PHYSICAL_DEVICES - 1));
+ pRAID_Context->config_seq_num = 0;
+ io_request->DevHandle = cpu_to_le16(0xFFFF);
}
- } else if (fusion->fast_path_io) {
- pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id);
- pRAID_Context->config_seq_num = 0;
- local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)];
- io_request->DevHandle =
- local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl;
} else {
- /* Want to send all IO via FW path */
pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id);
pRAID_Context->config_seq_num = 0;
- io_request->DevHandle = cpu_to_le16(0xFFFF);
+
+ if (fusion->fast_path_io) {
+ local_map_ptr =
+ fusion->ld_drv_map[(instance->map_id & 1)];
+ io_request->DevHandle =
+ local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl;
+ } else {
+ io_request->DevHandle = cpu_to_le16(0xFFFF);
+ }
}
cmd->request_desc->SCSIIO.DevHandle = io_request->DevHandle;
- cmd->request_desc->SCSIIO.MSIxIndex =
- instance->reply_map[raw_smp_processor_id()];
+ if ((instance->perf_mode == MR_BALANCED_PERF_MODE) &&
+ atomic_read(&scmd->device->device_busy) > MR_DEVICE_HIGH_IOPS_DEPTH)
+ cmd->request_desc->SCSIIO.MSIxIndex =
+ mega_mod64((atomic64_add_return(1, &instance->high_iops_outstanding) /
+ MR_HIGH_IOPS_BATCH_COUNT), instance->low_latency_index_start);
+ else if (instance->msix_load_balance)
+ cmd->request_desc->SCSIIO.MSIxIndex =
+ (mega_mod64(atomic64_add_return(1, &instance->total_io_count),
+ instance->msix_vectors));
+ else
+ cmd->request_desc->SCSIIO.MSIxIndex =
+ instance->reply_map[raw_smp_processor_id()];
if (!fp_possible) {
/* system pd firmware path */
@@ -3193,9 +3351,9 @@ void megasas_prepare_secondRaid1_IO(struct megasas_instance *instance,
r1_cmd->request_desc->SCSIIO.DevHandle = cmd->r1_alt_dev_handle;
r1_cmd->io_request->DevHandle = cmd->r1_alt_dev_handle;
r1_cmd->r1_alt_dev_handle = cmd->io_request->DevHandle;
- cmd->io_request->RaidContext.raid_context_g35.smid.peer_smid =
+ cmd->io_request->RaidContext.raid_context_g35.flow_specific.peer_smid =
cpu_to_le16(r1_cmd->index);
- r1_cmd->io_request->RaidContext.raid_context_g35.smid.peer_smid =
+ r1_cmd->io_request->RaidContext.raid_context_g35.flow_specific.peer_smid =
cpu_to_le16(cmd->index);
/*MSIxIndex of both commands request descriptors should be same*/
r1_cmd->request_desc->SCSIIO.MSIxIndex =
@@ -3313,7 +3471,7 @@ megasas_complete_r1_command(struct megasas_instance *instance,
rctx_g35 = &cmd->io_request->RaidContext.raid_context_g35;
fusion = instance->ctrl_context;
- peer_smid = le16_to_cpu(rctx_g35->smid.peer_smid);
+ peer_smid = le16_to_cpu(rctx_g35->flow_specific.peer_smid);
r1_cmd = fusion->cmd_list[peer_smid - 1];
scmd_local = cmd->scmd;
@@ -3353,7 +3511,8 @@ megasas_complete_r1_command(struct megasas_instance *instance,
* Completes all commands that is in reply descriptor queue
*/
int
-complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
+complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex,
+ struct megasas_irq_context *irq_context)
{
union MPI2_REPLY_DESCRIPTORS_UNION *desc;
struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *reply_desc;
@@ -3486,7 +3645,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
* number of reply counts and still there are more replies in reply queue
* pending to be completed
*/
- if (threshold_reply_count >= THRESHOLD_REPLY_COUNT) {
+ if (threshold_reply_count >= instance->threshold_reply_count) {
if (instance->msix_combined)
writel(((MSIxIndex & 0x7) << 24) |
fusion->last_reply_idx[MSIxIndex],
@@ -3496,23 +3655,46 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
fusion->last_reply_idx[MSIxIndex],
instance->reply_post_host_index_addr[0]);
threshold_reply_count = 0;
+ if (irq_context) {
+ if (!irq_context->irq_poll_scheduled) {
+ irq_context->irq_poll_scheduled = true;
+ irq_context->irq_line_enable = true;
+ irq_poll_sched(&irq_context->irqpoll);
+ }
+ return num_completed;
+ }
}
}
- if (!num_completed)
- return IRQ_NONE;
+ if (num_completed) {
+ wmb();
+ if (instance->msix_combined)
+ writel(((MSIxIndex & 0x7) << 24) |
+ fusion->last_reply_idx[MSIxIndex],
+ instance->reply_post_host_index_addr[MSIxIndex/8]);
+ else
+ writel((MSIxIndex << 24) |
+ fusion->last_reply_idx[MSIxIndex],
+ instance->reply_post_host_index_addr[0]);
+ megasas_check_and_restore_queue_depth(instance);
+ }
+ return num_completed;
+}
- wmb();
- if (instance->msix_combined)
- writel(((MSIxIndex & 0x7) << 24) |
- fusion->last_reply_idx[MSIxIndex],
- instance->reply_post_host_index_addr[MSIxIndex/8]);
- else
- writel((MSIxIndex << 24) |
- fusion->last_reply_idx[MSIxIndex],
- instance->reply_post_host_index_addr[0]);
- megasas_check_and_restore_queue_depth(instance);
- return IRQ_HANDLED;
+/**
+ * megasas_enable_irq_poll() - enable irqpoll
+ */
+static void megasas_enable_irq_poll(struct megasas_instance *instance)
+{
+ u32 count, i;
+ struct megasas_irq_context *irq_ctx;
+
+ count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
+
+ for (i = 0; i < count; i++) {
+ irq_ctx = &instance->irq_context[i];
+ irq_poll_enable(&irq_ctx->irqpoll);
+ }
}
/**
@@ -3524,11 +3706,51 @@ void megasas_sync_irqs(unsigned long instance_addr)
u32 count, i;
struct megasas_instance *instance =
(struct megasas_instance *)instance_addr;
+ struct megasas_irq_context *irq_ctx;
count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
- for (i = 0; i < count; i++)
+ for (i = 0; i < count; i++) {
synchronize_irq(pci_irq_vector(instance->pdev, i));
+ irq_ctx = &instance->irq_context[i];
+ irq_poll_disable(&irq_ctx->irqpoll);
+ if (irq_ctx->irq_poll_scheduled) {
+ irq_ctx->irq_poll_scheduled = false;
+ enable_irq(irq_ctx->os_irq);
+ }
+ }
+}
+
+/**
+ * megasas_irqpoll() - process a queue for completed reply descriptors
+ * @irqpoll: IRQ poll structure associated with queue to poll.
+ * @budget: Threshold of reply descriptors to process per poll.
+ *
+ * Return: The number of entries processed.
+ */
+
+int megasas_irqpoll(struct irq_poll *irqpoll, int budget)
+{
+ struct megasas_irq_context *irq_ctx;
+ struct megasas_instance *instance;
+ int num_entries;
+
+ irq_ctx = container_of(irqpoll, struct megasas_irq_context, irqpoll);
+ instance = irq_ctx->instance;
+
+ if (irq_ctx->irq_line_enable) {
+ disable_irq(irq_ctx->os_irq);
+ irq_ctx->irq_line_enable = false;
+ }
+
+ num_entries = complete_cmd_fusion(instance, irq_ctx->MSIxIndex, irq_ctx);
+ if (num_entries < budget) {
+ irq_poll_complete(irqpoll);
+ irq_ctx->irq_poll_scheduled = false;
+ enable_irq(irq_ctx->os_irq);
+ }
+
+ return num_entries;
}
/**
@@ -3551,7 +3773,7 @@ megasas_complete_cmd_dpc_fusion(unsigned long instance_addr)
return;
for (MSIxIndex = 0 ; MSIxIndex < count; MSIxIndex++)
- complete_cmd_fusion(instance, MSIxIndex);
+ complete_cmd_fusion(instance, MSIxIndex, NULL);
}
/**
@@ -3566,6 +3788,11 @@ irqreturn_t megasas_isr_fusion(int irq, void *devp)
if (instance->mask_interrupts)
return IRQ_NONE;
+#if defined(ENABLE_IRQ_POLL)
+ if (irq_context->irq_poll_scheduled)
+ return IRQ_HANDLED;
+#endif
+
if (!instance->msix_vectors) {
mfiStatus = instance->instancet->clear_intr(instance);
if (!mfiStatus)
@@ -3578,7 +3805,8 @@ irqreturn_t megasas_isr_fusion(int irq, void *devp)
return IRQ_HANDLED;
}
- return complete_cmd_fusion(instance, irq_context->MSIxIndex);
+ return complete_cmd_fusion(instance, irq_context->MSIxIndex, irq_context)
+ ? IRQ_HANDLED : IRQ_NONE;
}
/**
@@ -3843,7 +4071,7 @@ megasas_check_reset_fusion(struct megasas_instance *instance,
static inline void megasas_trigger_snap_dump(struct megasas_instance *instance)
{
int j;
- u32 fw_state;
+ u32 fw_state, abs_state;
if (!instance->disableOnlineCtrlReset) {
dev_info(&instance->pdev->dev, "Trigger snap dump\n");
@@ -3853,11 +4081,13 @@ static inline void megasas_trigger_snap_dump(struct megasas_instance *instance)
}
for (j = 0; j < instance->snapdump_wait_time; j++) {
- fw_state = instance->instancet->read_fw_status_reg(instance) &
- MFI_STATE_MASK;
+ abs_state = instance->instancet->read_fw_status_reg(instance);
+ fw_state = abs_state & MFI_STATE_MASK;
if (fw_state == MFI_STATE_FAULT) {
- dev_err(&instance->pdev->dev,
- "Found FW in FAULT state, after snap dump trigger\n");
+ dev_printk(KERN_ERR, &instance->pdev->dev,
+ "FW in FAULT state Fault code:0x%x subcode:0x%x func:%s\n",
+ abs_state & MFI_STATE_FAULT_CODE,
+ abs_state & MFI_STATE_FAULT_SUBCODE, __func__);
return;
}
msleep(1000);
@@ -3869,7 +4099,7 @@ int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance,
int reason, int *convert)
{
int i, outstanding, retval = 0, hb_seconds_missed = 0;
- u32 fw_state;
+ u32 fw_state, abs_state;
u32 waittime_for_io_completion;
waittime_for_io_completion =
@@ -3888,12 +4118,13 @@ int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance,
for (i = 0; i < waittime_for_io_completion; i++) {
/* Check if firmware is in fault state */
- fw_state = instance->instancet->read_fw_status_reg(instance) &
- MFI_STATE_MASK;
+ abs_state = instance->instancet->read_fw_status_reg(instance);
+ fw_state = abs_state & MFI_STATE_MASK;
if (fw_state == MFI_STATE_FAULT) {
- dev_warn(&instance->pdev->dev, "Found FW in FAULT state,"
- " will reset adapter scsi%d.\n",
- instance->host->host_no);
+ dev_printk(KERN_ERR, &instance->pdev->dev,
+ "FW in FAULT state Fault code:0x%x subcode:0x%x func:%s\n",
+ abs_state & MFI_STATE_FAULT_CODE,
+ abs_state & MFI_STATE_FAULT_SUBCODE, __func__);
megasas_complete_cmd_dpc_fusion((unsigned long)instance);
if (instance->requestorId && reason) {
dev_warn(&instance->pdev->dev, "SR-IOV Found FW in FAULT"
@@ -4042,6 +4273,13 @@ void megasas_refire_mgmt_cmd(struct megasas_instance *instance)
}
break;
+ case MFI_CMD_TOOLBOX:
+ if (!instance->support_pci_lane_margining) {
+ cmd_mfi->frame->hdr.cmd_status = MFI_STAT_INVALID_CMD;
+ result = COMPLETE_CMD;
+ }
+
+ break;
default:
break;
}
@@ -4265,6 +4503,7 @@ megasas_issue_tm(struct megasas_instance *instance, u16 device_handle,
instance->instancet->disable_intr(instance);
megasas_sync_irqs((unsigned long)instance);
instance->instancet->enable_intr(instance);
+ megasas_enable_irq_poll(instance);
if (scsi_lookup->scmd == NULL)
break;
}
@@ -4278,6 +4517,7 @@ megasas_issue_tm(struct megasas_instance *instance, u16 device_handle,
megasas_sync_irqs((unsigned long)instance);
rc = megasas_track_scsiio(instance, id, channel);
instance->instancet->enable_intr(instance);
+ megasas_enable_irq_poll(instance);
break;
case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET:
@@ -4376,9 +4616,6 @@ int megasas_task_abort_fusion(struct scsi_cmnd *scmd)
instance = (struct megasas_instance *)scmd->device->host->hostdata;
- scmd_printk(KERN_INFO, scmd, "task abort called for scmd(%p)\n", scmd);
- scsi_print_command(scmd);
-
if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL,"
"SCSI host:%d\n", instance->host->host_no);
@@ -4421,7 +4658,7 @@ int megasas_task_abort_fusion(struct scsi_cmnd *scmd)
goto out;
}
sdev_printk(KERN_INFO, scmd->device,
- "attempting task abort! scmd(%p) tm_dev_handle 0x%x\n",
+ "attempting task abort! scmd(0x%p) tm_dev_handle 0x%x\n",
scmd, devhandle);
mr_device_priv_data->tm_busy = 1;
@@ -4432,9 +4669,12 @@ int megasas_task_abort_fusion(struct scsi_cmnd *scmd)
mr_device_priv_data->tm_busy = 0;
mutex_unlock(&instance->reset_mutex);
-out:
- sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n",
+ scmd_printk(KERN_INFO, scmd, "task abort %s!! scmd(0x%p)\n",
((ret == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
+out:
+ scsi_print_command(scmd);
+ if (megasas_dbg_lvl & TM_DEBUG)
+ megasas_dump_fusion_io(scmd);
return ret;
}
@@ -4457,9 +4697,6 @@ int megasas_reset_target_fusion(struct scsi_cmnd *scmd)
instance = (struct megasas_instance *)scmd->device->host->hostdata;
- sdev_printk(KERN_INFO, scmd->device,
- "target reset called for scmd(%p)\n", scmd);
-
if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL,"
"SCSI host:%d\n", instance->host->host_no);
@@ -4468,8 +4705,8 @@ int megasas_reset_target_fusion(struct scsi_cmnd *scmd)
}
if (!mr_device_priv_data) {
- sdev_printk(KERN_INFO, scmd->device, "device been deleted! "
- "scmd(%p)\n", scmd);
+ sdev_printk(KERN_INFO, scmd->device,
+ "device been deleted! scmd: (0x%p)\n", scmd);
scmd->result = DID_NO_CONNECT << 16;
ret = SUCCESS;
goto out;
@@ -4492,7 +4729,7 @@ int megasas_reset_target_fusion(struct scsi_cmnd *scmd)
}
sdev_printk(KERN_INFO, scmd->device,
- "attempting target reset! scmd(%p) tm_dev_handle 0x%x\n",
+ "attempting target reset! scmd(0x%p) tm_dev_handle: 0x%x\n",
scmd, devhandle);
mr_device_priv_data->tm_busy = 1;
ret = megasas_issue_tm(instance, devhandle,
@@ -4501,10 +4738,10 @@ int megasas_reset_target_fusion(struct scsi_cmnd *scmd)
mr_device_priv_data);
mr_device_priv_data->tm_busy = 0;
mutex_unlock(&instance->reset_mutex);
-out:
- scmd_printk(KERN_NOTICE, scmd, "megasas: target reset %s!!\n",
+ scmd_printk(KERN_NOTICE, scmd, "target reset %s!!\n",
(ret == SUCCESS) ? "SUCCESS" : "FAILED");
+out:
return ret;
}
@@ -4549,12 +4786,14 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
struct megasas_instance *instance;
struct megasas_cmd_fusion *cmd_fusion, *r1_cmd;
struct fusion_context *fusion;
- u32 abs_state, status_reg, reset_adapter;
+ u32 abs_state, status_reg, reset_adapter, fpio_count = 0;
u32 io_timeout_in_crash_mode = 0;
struct scsi_cmnd *scmd_local = NULL;
struct scsi_device *sdev;
int ret_target_prop = DCMD_FAILED;
bool is_target_prop = false;
+ bool do_adp_reset = true;
+ int max_reset_tries = MEGASAS_FUSION_MAX_RESET_TRIES;
instance = (struct megasas_instance *)shost->hostdata;
fusion = instance->ctrl_context;
@@ -4621,7 +4860,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
if (convert)
reason = 0;
- if (megasas_dbg_lvl & OCR_LOGS)
+ if (megasas_dbg_lvl & OCR_DEBUG)
dev_info(&instance->pdev->dev, "\nPending SCSI commands:\n");
/* Now return commands back to the OS */
@@ -4634,13 +4873,17 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
}
scmd_local = cmd_fusion->scmd;
if (cmd_fusion->scmd) {
- if (megasas_dbg_lvl & OCR_LOGS) {
+ if (megasas_dbg_lvl & OCR_DEBUG) {
sdev_printk(KERN_INFO,
cmd_fusion->scmd->device, "SMID: 0x%x\n",
cmd_fusion->index);
- scsi_print_command(cmd_fusion->scmd);
+ megasas_dump_fusion_io(cmd_fusion->scmd);
}
+ if (cmd_fusion->io_request->Function ==
+ MPI2_FUNCTION_SCSI_IO_REQUEST)
+ fpio_count++;
+
scmd_local->result =
megasas_check_mpio_paths(instance,
scmd_local);
@@ -4653,6 +4896,9 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
}
}
+ dev_info(&instance->pdev->dev, "Outstanding fastpath IOs: %d\n",
+ fpio_count);
+
atomic_set(&instance->fw_outstanding, 0);
status_reg = instance->instancet->read_fw_status_reg(instance);
@@ -4664,52 +4910,45 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
dev_warn(&instance->pdev->dev, "Reset not supported"
", killing adapter scsi%d.\n",
instance->host->host_no);
- megaraid_sas_kill_hba(instance);
- instance->skip_heartbeat_timer_del = 1;
- retval = FAILED;
- goto out;
+ goto kill_hba;
}
/* Let SR-IOV VF & PF sync up if there was a HB failure */
if (instance->requestorId && !reason) {
msleep(MEGASAS_OCR_SETTLE_TIME_VF);
- goto transition_to_ready;
+ do_adp_reset = false;
+ max_reset_tries = MEGASAS_SRIOV_MAX_RESET_TRIES_VF;
}
/* Now try to reset the chip */
- for (i = 0; i < MEGASAS_FUSION_MAX_RESET_TRIES; i++) {
-
- if (instance->instancet->adp_reset
- (instance, instance->reg_set))
+ for (i = 0; i < max_reset_tries; i++) {
+ /*
+ * Do adp reset and wait for
+ * controller to transition to ready
+ */
+ if (megasas_adp_reset_wait_for_ready(instance,
+ do_adp_reset, 1) == FAILED)
continue;
-transition_to_ready:
+
/* Wait for FW to become ready */
if (megasas_transition_to_ready(instance, 1)) {
dev_warn(&instance->pdev->dev,
"Failed to transition controller to ready for "
"scsi%d.\n", instance->host->host_no);
- if (instance->requestorId && !reason)
- goto fail_kill_adapter;
- else
- continue;
+ continue;
}
megasas_reset_reply_desc(instance);
megasas_fusion_update_can_queue(instance, OCR_CONTEXT);
if (megasas_ioc_init_fusion(instance)) {
- if (instance->requestorId && !reason)
- goto fail_kill_adapter;
- else
- continue;
+ continue;
}
if (megasas_get_ctrl_info(instance)) {
dev_info(&instance->pdev->dev,
"Failed from %s %d\n",
__func__, __LINE__);
- megaraid_sas_kill_hba(instance);
- retval = FAILED;
- goto out;
+ goto kill_hba;
}
megasas_refire_mgmt_cmd(instance);
@@ -4738,7 +4977,7 @@ transition_to_ready:
clear_bit(MEGASAS_FUSION_IN_RESET,
&instance->reset_flags);
instance->instancet->enable_intr(instance);
-
+ megasas_enable_irq_poll(instance);
shost_for_each_device(sdev, shost) {
if ((instance->tgt_prop) &&
(instance->nvme_page_size))
@@ -4750,9 +4989,9 @@ transition_to_ready:
atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
- dev_info(&instance->pdev->dev, "Interrupts are enabled and"
- " controller is OPERATIONAL for scsi:%d\n",
- instance->host->host_no);
+ dev_info(&instance->pdev->dev,
+ "Adapter is OPERATIONAL for scsi:%d\n",
+ instance->host->host_no);
/* Restart SR-IOV heartbeat */
if (instance->requestorId) {
@@ -4786,13 +5025,10 @@ transition_to_ready:
goto out;
}
-fail_kill_adapter:
/* Reset failed, kill the adapter */
dev_warn(&instance->pdev->dev, "Reset failed, killing "
"adapter scsi%d.\n", instance->host->host_no);
- megaraid_sas_kill_hba(instance);
- instance->skip_heartbeat_timer_del = 1;
- retval = FAILED;
+ goto kill_hba;
} else {
/* For VF: Restart HB timer if we didn't OCR */
if (instance->requestorId) {
@@ -4800,8 +5036,15 @@ fail_kill_adapter:
}
clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
instance->instancet->enable_intr(instance);
+ megasas_enable_irq_poll(instance);
atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
+ goto out;
}
+kill_hba:
+ megaraid_sas_kill_hba(instance);
+ megasas_enable_irq_poll(instance);
+ instance->skip_heartbeat_timer_del = 1;
+ retval = FAILED;
out:
clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
mutex_unlock(&instance->reset_mutex);
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h
index 7fa73eaca1a8..c013c80fe4e6 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.h
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h
@@ -75,7 +75,8 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE {
MR_RAID_FLAGS_IO_SUB_TYPE_RMW_P = 3,
MR_RAID_FLAGS_IO_SUB_TYPE_RMW_Q = 4,
MR_RAID_FLAGS_IO_SUB_TYPE_CACHE_BYPASS = 6,
- MR_RAID_FLAGS_IO_SUB_TYPE_LDIO_BW_LIMIT = 7
+ MR_RAID_FLAGS_IO_SUB_TYPE_LDIO_BW_LIMIT = 7,
+ MR_RAID_FLAGS_IO_SUB_TYPE_R56_DIV_OFFLOAD = 8
};
/*
@@ -88,7 +89,6 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE {
#define MEGASAS_FP_CMD_LEN 16
#define MEGASAS_FUSION_IN_RESET 0
-#define THRESHOLD_REPLY_COUNT 50
#define RAID_1_PEER_CMDS 2
#define JBOD_MAPS_COUNT 2
#define MEGASAS_REDUCE_QD_COUNT 64
@@ -140,12 +140,15 @@ struct RAID_CONTEXT_G35 {
u16 timeout_value; /* 0x02 -0x03 */
u16 routing_flags; // 0x04 -0x05 routing flags
u16 virtual_disk_tgt_id; /* 0x06 -0x07 */
- u64 reg_lock_row_lba; /* 0x08 - 0x0F */
+ __le64 reg_lock_row_lba; /* 0x08 - 0x0F */
u32 reg_lock_length; /* 0x10 - 0x13 */
- union {
- u16 next_lmid; /* 0x14 - 0x15 */
- u16 peer_smid; /* used for the raid 1/10 fp writes */
- } smid;
+ union { // flow specific
+ u16 rmw_op_index; /* 0x14 - 0x15, R5/6 RMW: rmw operation index*/
+ u16 peer_smid; /* 0x14 - 0x15, R1 Write: peer smid*/
+ u16 r56_arm_map; /* 0x14 - 0x15, Unused [15], LogArm[14:10], P-Arm[9:5], Q-Arm[4:0] */
+
+ } flow_specific;
+
u8 ex_status; /* 0x16 : OUT */
u8 status; /* 0x17 status */
u8 raid_flags; /* 0x18 resvd[7:6], ioSubType[5:4],
@@ -236,6 +239,13 @@ union RAID_CONTEXT_UNION {
#define RAID_CTX_SPANARM_SPAN_SHIFT (5)
#define RAID_CTX_SPANARM_SPAN_MASK (0xE0)
+/* LogArm[14:10], P-Arm[9:5], Q-Arm[4:0] */
+#define RAID_CTX_R56_Q_ARM_MASK (0x1F)
+#define RAID_CTX_R56_P_ARM_SHIFT (5)
+#define RAID_CTX_R56_P_ARM_MASK (0x3E0)
+#define RAID_CTX_R56_LOG_ARM_SHIFT (10)
+#define RAID_CTX_R56_LOG_ARM_MASK (0x7C00)
+
/* number of bits per index in U32 TrackStream */
#define BITS_PER_INDEX_STREAM 4
#define INVALID_STREAM_NUM 16
@@ -940,6 +950,7 @@ struct IO_REQUEST_INFO {
u8 pd_after_lb;
u16 r1_alt_dev_handle; /* raid 1/10 only */
bool ra_capable;
+ u8 data_arms;
};
struct MR_LD_TARGET_SYNC {
@@ -1324,7 +1335,8 @@ struct fusion_context {
dma_addr_t ioc_init_request_phys;
struct MPI2_IOC_INIT_REQUEST *ioc_init_request;
struct megasas_cmd *ioc_init_cmd;
-
+ bool pcie_bw_limitation;
+ bool r56_div_offload;
};
union desc_value {
@@ -1349,6 +1361,11 @@ struct MR_SNAPDUMP_PROPERTIES {
u8 reserved[12];
};
+struct megasas_debugfs_buffer {
+ void *buf;
+ u32 len;
+};
+
void megasas_free_cmds_fusion(struct megasas_instance *instance);
int megasas_ioc_init_fusion(struct megasas_instance *instance);
u8 megasas_get_map_info(struct megasas_instance *instance);
diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h
index a2f4a55c51be..167d79d145ca 100644
--- a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h
+++ b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h
@@ -1398,7 +1398,7 @@ typedef struct _MPI2_CONFIG_PAGE_IOC_1 {
U8 PCIBusNum; /*0x0E */
U8 PCIDomainSegment; /*0x0F */
U32 Reserved1; /*0x10 */
- U32 Reserved2; /*0x14 */
+ U32 ProductSpecific; /* 0x14 */
} MPI2_CONFIG_PAGE_IOC_1,
*PTR_MPI2_CONFIG_PAGE_IOC_1,
Mpi2IOCPage1_t, *pMpi2IOCPage1_t;
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c
index 8aacbd1e7db2..684662888792 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -74,28 +74,28 @@ static MPT_CALLBACK mpt_callbacks[MPT_MAX_CALLBACKS];
#define MAX_HBA_QUEUE_DEPTH 30000
#define MAX_CHAIN_DEPTH 100000
static int max_queue_depth = -1;
-module_param(max_queue_depth, int, 0);
+module_param(max_queue_depth, int, 0444);
MODULE_PARM_DESC(max_queue_depth, " max controller queue depth ");
static int max_sgl_entries = -1;
-module_param(max_sgl_entries, int, 0);
+module_param(max_sgl_entries, int, 0444);
MODULE_PARM_DESC(max_sgl_entries, " max sg entries ");
static int msix_disable = -1;
-module_param(msix_disable, int, 0);
+module_param(msix_disable, int, 0444);
MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)");
static int smp_affinity_enable = 1;
-module_param(smp_affinity_enable, int, S_IRUGO);
+module_param(smp_affinity_enable, int, 0444);
MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disable Default: enable(1)");
static int max_msix_vectors = -1;
-module_param(max_msix_vectors, int, 0);
+module_param(max_msix_vectors, int, 0444);
MODULE_PARM_DESC(max_msix_vectors,
" max msix vectors");
static int irqpoll_weight = -1;
-module_param(irqpoll_weight, int, 0);
+module_param(irqpoll_weight, int, 0444);
MODULE_PARM_DESC(irqpoll_weight,
"irq poll weight (default= one fourth of HBA queue depth)");
@@ -103,6 +103,26 @@ static int mpt3sas_fwfault_debug;
MODULE_PARM_DESC(mpt3sas_fwfault_debug,
" enable detection of firmware fault and halt firmware - (default=0)");
+static int perf_mode = -1;
+module_param(perf_mode, int, 0444);
+MODULE_PARM_DESC(perf_mode,
+ "Performance mode (only for Aero/Sea Generation), options:\n\t\t"
+ "0 - balanced: high iops mode is enabled &\n\t\t"
+ "interrupt coalescing is enabled only on high iops queues,\n\t\t"
+ "1 - iops: high iops mode is disabled &\n\t\t"
+ "interrupt coalescing is enabled on all queues,\n\t\t"
+ "2 - latency: high iops mode is disabled &\n\t\t"
+ "interrupt coalescing is enabled on all queues with timeout value 0xA,\n"
+ "\t\tdefault - default perf_mode is 'balanced'"
+ );
+
+enum mpt3sas_perf_mode {
+ MPT_PERF_MODE_DEFAULT = -1,
+ MPT_PERF_MODE_BALANCED = 0,
+ MPT_PERF_MODE_IOPS = 1,
+ MPT_PERF_MODE_LATENCY = 2,
+};
+
static int
_base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc);
@@ -1282,7 +1302,7 @@ _base_async_event(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, u32 reply)
ack_request->EventContext = mpi_reply->EventContext;
ack_request->VF_ID = 0; /* TODO */
ack_request->VP_ID = 0;
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
out:
@@ -2793,6 +2813,9 @@ _base_free_irq(struct MPT3SAS_ADAPTER *ioc)
list_for_each_entry_safe(reply_q, next, &ioc->reply_queue_list, list) {
list_del(&reply_q->list);
+ if (ioc->smp_affinity_enable)
+ irq_set_affinity_hint(pci_irq_vector(ioc->pdev,
+ reply_q->msix_index), NULL);
free_irq(pci_irq_vector(ioc->pdev, reply_q->msix_index),
reply_q);
kfree(reply_q);
@@ -2857,14 +2880,13 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc)
{
unsigned int cpu, nr_cpus, nr_msix, index = 0;
struct adapter_reply_queue *reply_q;
+ int local_numa_node;
if (!_base_is_controller_msix_enabled(ioc))
return;
- ioc->msix_load_balance = false;
- if (ioc->reply_queue_count < num_online_cpus()) {
- ioc->msix_load_balance = true;
+
+ if (ioc->msix_load_balance)
return;
- }
memset(ioc->cpu_msix_table, 0, ioc->cpu_msix_table_sz);
@@ -2874,14 +2896,33 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc)
if (!nr_msix)
return;
- if (smp_affinity_enable) {
+ if (ioc->smp_affinity_enable) {
+
+ /*
+ * set irq affinity to local numa node for those irqs
+ * corresponding to high iops queues.
+ */
+ if (ioc->high_iops_queues) {
+ local_numa_node = dev_to_node(&ioc->pdev->dev);
+ for (index = 0; index < ioc->high_iops_queues;
+ index++) {
+ irq_set_affinity_hint(pci_irq_vector(ioc->pdev,
+ index), cpumask_of_node(local_numa_node));
+ }
+ }
+
list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
- const cpumask_t *mask = pci_irq_get_affinity(ioc->pdev,
- reply_q->msix_index);
+ const cpumask_t *mask;
+
+ if (reply_q->msix_index < ioc->high_iops_queues)
+ continue;
+
+ mask = pci_irq_get_affinity(ioc->pdev,
+ reply_q->msix_index);
if (!mask) {
ioc_warn(ioc, "no affinity for msi %x\n",
reply_q->msix_index);
- continue;
+ goto fall_back;
}
for_each_cpu_and(cpu, mask, cpu_online_mask) {
@@ -2892,12 +2933,18 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc)
}
return;
}
+
+fall_back:
cpu = cpumask_first(cpu_online_mask);
+ nr_msix -= ioc->high_iops_queues;
+ index = 0;
list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
-
unsigned int i, group = nr_cpus / nr_msix;
+ if (reply_q->msix_index < ioc->high_iops_queues)
+ continue;
+
if (cpu >= nr_cpus)
break;
@@ -2913,6 +2960,52 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc)
}
/**
+ * _base_check_and_enable_high_iops_queues - enable high iops mode
+ * @ ioc - per adapter object
+ * @ hba_msix_vector_count - msix vectors supported by HBA
+ *
+ * Enable high iops queues only if
+ * - HBA is a SEA/AERO controller and
+ * - MSI-Xs vector supported by the HBA is 128 and
+ * - total CPU count in the system >=16 and
+ * - loaded driver with default max_msix_vectors module parameter and
+ * - system booted in non kdump mode
+ *
+ * returns nothing.
+ */
+static void
+_base_check_and_enable_high_iops_queues(struct MPT3SAS_ADAPTER *ioc,
+ int hba_msix_vector_count)
+{
+ u16 lnksta, speed;
+
+ if (perf_mode == MPT_PERF_MODE_IOPS ||
+ perf_mode == MPT_PERF_MODE_LATENCY) {
+ ioc->high_iops_queues = 0;
+ return;
+ }
+
+ if (perf_mode == MPT_PERF_MODE_DEFAULT) {
+
+ pcie_capability_read_word(ioc->pdev, PCI_EXP_LNKSTA, &lnksta);
+ speed = lnksta & PCI_EXP_LNKSTA_CLS;
+
+ if (speed < 0x4) {
+ ioc->high_iops_queues = 0;
+ return;
+ }
+ }
+
+ if (!reset_devices && ioc->is_aero_ioc &&
+ hba_msix_vector_count == MPT3SAS_GEN35_MAX_MSIX_QUEUES &&
+ num_online_cpus() >= MPT3SAS_HIGH_IOPS_REPLY_QUEUES &&
+ max_msix_vectors == -1)
+ ioc->high_iops_queues = MPT3SAS_HIGH_IOPS_REPLY_QUEUES;
+ else
+ ioc->high_iops_queues = 0;
+}
+
+/**
* _base_disable_msix - disables msix
* @ioc: per adapter object
*
@@ -2922,11 +3015,38 @@ _base_disable_msix(struct MPT3SAS_ADAPTER *ioc)
{
if (!ioc->msix_enable)
return;
- pci_disable_msix(ioc->pdev);
+ pci_free_irq_vectors(ioc->pdev);
ioc->msix_enable = 0;
}
/**
+ * _base_alloc_irq_vectors - allocate msix vectors
+ * @ioc: per adapter object
+ *
+ */
+static int
+_base_alloc_irq_vectors(struct MPT3SAS_ADAPTER *ioc)
+{
+ int i, irq_flags = PCI_IRQ_MSIX;
+ struct irq_affinity desc = { .pre_vectors = ioc->high_iops_queues };
+ struct irq_affinity *descp = &desc;
+
+ if (ioc->smp_affinity_enable)
+ irq_flags |= PCI_IRQ_AFFINITY;
+ else
+ descp = NULL;
+
+ ioc_info(ioc, " %d %d\n", ioc->high_iops_queues,
+ ioc->msix_vector_count);
+
+ i = pci_alloc_irq_vectors_affinity(ioc->pdev,
+ ioc->high_iops_queues,
+ ioc->msix_vector_count, irq_flags, descp);
+
+ return i;
+}
+
+/**
* _base_enable_msix - enables msix, failback to io_apic
* @ioc: per adapter object
*
@@ -2937,7 +3057,8 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
int r;
int i, local_max_msix_vectors;
u8 try_msix = 0;
- unsigned int irq_flags = PCI_IRQ_MSIX;
+
+ ioc->msix_load_balance = false;
if (msix_disable == -1 || msix_disable == 0)
try_msix = 1;
@@ -2948,12 +3069,16 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
if (_base_check_enable_msix(ioc) != 0)
goto try_ioapic;
- ioc->reply_queue_count = min_t(int, ioc->cpu_count,
+ ioc_info(ioc, "MSI-X vectors supported: %d\n", ioc->msix_vector_count);
+ pr_info("\t no of cores: %d, max_msix_vectors: %d\n",
+ ioc->cpu_count, max_msix_vectors);
+ if (ioc->is_aero_ioc)
+ _base_check_and_enable_high_iops_queues(ioc,
+ ioc->msix_vector_count);
+ ioc->reply_queue_count =
+ min_t(int, ioc->cpu_count + ioc->high_iops_queues,
ioc->msix_vector_count);
- ioc_info(ioc, "MSI-X vectors supported: %d, no of cores: %d, max_msix_vectors: %d\n",
- ioc->msix_vector_count, ioc->cpu_count, max_msix_vectors);
-
if (!ioc->rdpq_array_enable && max_msix_vectors == -1)
local_max_msix_vectors = (reset_devices) ? 1 : 8;
else
@@ -2965,14 +3090,23 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
else if (local_max_msix_vectors == 0)
goto try_ioapic;
- if (ioc->msix_vector_count < ioc->cpu_count)
- smp_affinity_enable = 0;
+ /*
+ * Enable msix_load_balance only if combined reply queue mode is
+ * disabled on SAS3 & above generation HBA devices.
+ */
+ if (!ioc->combined_reply_queue &&
+ ioc->hba_mpi_version_belonged != MPI2_VERSION) {
+ ioc->msix_load_balance = true;
+ }
- if (smp_affinity_enable)
- irq_flags |= PCI_IRQ_AFFINITY;
+ /*
+ * smp affinity setting is not need when msix load balance
+ * is enabled.
+ */
+ if (ioc->msix_load_balance)
+ ioc->smp_affinity_enable = 0;
- r = pci_alloc_irq_vectors(ioc->pdev, 1, ioc->reply_queue_count,
- irq_flags);
+ r = _base_alloc_irq_vectors(ioc);
if (r < 0) {
dfailprintk(ioc,
ioc_info(ioc, "pci_alloc_irq_vectors failed (r=%d) !!!\n",
@@ -2991,11 +3125,15 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
}
}
+ ioc_info(ioc, "High IOPs queues : %s\n",
+ ioc->high_iops_queues ? "enabled" : "disabled");
+
return 0;
/* failback to io_apic interrupt routing */
try_ioapic:
-
+ ioc->high_iops_queues = 0;
+ ioc_info(ioc, "High IOPs queues : disabled\n");
ioc->reply_queue_count = 1;
r = pci_alloc_irq_vectors(ioc->pdev, 1, 1, PCI_IRQ_LEGACY);
if (r < 0) {
@@ -3265,8 +3403,18 @@ mpt3sas_base_get_reply_virt_addr(struct MPT3SAS_ADAPTER *ioc, u32 phys_addr)
return ioc->reply + (phys_addr - (u32)ioc->reply_dma);
}
+/**
+ * _base_get_msix_index - get the msix index
+ * @ioc: per adapter object
+ * @scmd: scsi_cmnd object
+ *
+ * returns msix index of general reply queues,
+ * i.e. reply queue on which IO request's reply
+ * should be posted by the HBA firmware.
+ */
static inline u8
-_base_get_msix_index(struct MPT3SAS_ADAPTER *ioc)
+_base_get_msix_index(struct MPT3SAS_ADAPTER *ioc,
+ struct scsi_cmnd *scmd)
{
/* Enables reply_queue load balancing */
if (ioc->msix_load_balance)
@@ -3278,6 +3426,35 @@ _base_get_msix_index(struct MPT3SAS_ADAPTER *ioc)
}
/**
+ * _base_get_high_iops_msix_index - get the msix index of
+ * high iops queues
+ * @ioc: per adapter object
+ * @scmd: scsi_cmnd object
+ *
+ * Returns: msix index of high iops reply queues.
+ * i.e. high iops reply queue on which IO request's
+ * reply should be posted by the HBA firmware.
+ */
+static inline u8
+_base_get_high_iops_msix_index(struct MPT3SAS_ADAPTER *ioc,
+ struct scsi_cmnd *scmd)
+{
+ /**
+ * Round robin the IO interrupts among the high iops
+ * reply queues in terms of batch count 16 when outstanding
+ * IOs on the target device is >=8.
+ */
+ if (atomic_read(&scmd->device->device_busy) >
+ MPT3SAS_DEVICE_HIGH_IOPS_DEPTH)
+ return base_mod64((
+ atomic64_add_return(1, &ioc->high_iops_outstanding) /
+ MPT3SAS_HIGH_IOPS_BATCH_COUNT),
+ MPT3SAS_HIGH_IOPS_REPLY_QUEUES);
+
+ return _base_get_msix_index(ioc, scmd);
+}
+
+/**
* mpt3sas_base_get_smid - obtain a free smid from internal queue
* @ioc: per adapter object
* @cb_idx: callback index
@@ -3325,8 +3502,8 @@ mpt3sas_base_get_smid_scsiio(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx,
smid = tag + 1;
request->cb_idx = cb_idx;
- request->msix_io = _base_get_msix_index(ioc);
request->smid = smid;
+ request->scmd = scmd;
INIT_LIST_HEAD(&request->chain_list);
return smid;
}
@@ -3380,6 +3557,7 @@ void mpt3sas_base_clear_st(struct MPT3SAS_ADAPTER *ioc,
return;
st->cb_idx = 0xFF;
st->direct_io = 0;
+ st->scmd = NULL;
atomic_set(&ioc->chain_lookup[st->smid - 1].chain_offset, 0);
st->smid = 0;
}
@@ -3479,13 +3657,37 @@ _base_writeq(__u64 b, volatile void __iomem *addr, spinlock_t *writeq_lock)
#endif
/**
+ * _base_set_and_get_msix_index - get the msix index and assign to msix_io
+ * variable of scsi tracker
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * returns msix index.
+ */
+static u8
+_base_set_and_get_msix_index(struct MPT3SAS_ADAPTER *ioc, u16 smid)
+{
+ struct scsiio_tracker *st = NULL;
+
+ if (smid < ioc->hi_priority_smid)
+ st = _get_st_from_smid(ioc, smid);
+
+ if (st == NULL)
+ return _base_get_msix_index(ioc, NULL);
+
+ st->msix_io = ioc->get_msix_index_for_smlio(ioc, st->scmd);
+ return st->msix_io;
+}
+
+/**
* _base_put_smid_mpi_ep_scsi_io - send SCSI_IO request to firmware
* @ioc: per adapter object
* @smid: system request message index
* @handle: device handle
*/
static void
-_base_put_smid_mpi_ep_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle)
+_base_put_smid_mpi_ep_scsi_io(struct MPT3SAS_ADAPTER *ioc,
+ u16 smid, u16 handle)
{
Mpi2RequestDescriptorUnion_t descriptor;
u64 *request = (u64 *)&descriptor;
@@ -3498,7 +3700,7 @@ _base_put_smid_mpi_ep_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle)
_base_clone_mpi_to_sys_mem(mpi_req_iomem, (void *)mfp,
ioc->request_sz);
descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
- descriptor.SCSIIO.MSIxIndex = _base_get_msix_index(ioc);
+ descriptor.SCSIIO.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
descriptor.SCSIIO.SMID = cpu_to_le16(smid);
descriptor.SCSIIO.DevHandle = cpu_to_le16(handle);
descriptor.SCSIIO.LMID = 0;
@@ -3520,7 +3722,7 @@ _base_put_smid_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle)
descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
- descriptor.SCSIIO.MSIxIndex = _base_get_msix_index(ioc);
+ descriptor.SCSIIO.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
descriptor.SCSIIO.SMID = cpu_to_le16(smid);
descriptor.SCSIIO.DevHandle = cpu_to_le16(handle);
descriptor.SCSIIO.LMID = 0;
@@ -3529,13 +3731,13 @@ _base_put_smid_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle)
}
/**
- * mpt3sas_base_put_smid_fast_path - send fast path request to firmware
+ * _base_put_smid_fast_path - send fast path request to firmware
* @ioc: per adapter object
* @smid: system request message index
* @handle: device handle
*/
-void
-mpt3sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid,
+static void
+_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid,
u16 handle)
{
Mpi2RequestDescriptorUnion_t descriptor;
@@ -3543,7 +3745,7 @@ mpt3sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid,
descriptor.SCSIIO.RequestFlags =
MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO;
- descriptor.SCSIIO.MSIxIndex = _base_get_msix_index(ioc);
+ descriptor.SCSIIO.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
descriptor.SCSIIO.SMID = cpu_to_le16(smid);
descriptor.SCSIIO.DevHandle = cpu_to_le16(handle);
descriptor.SCSIIO.LMID = 0;
@@ -3552,13 +3754,13 @@ mpt3sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid,
}
/**
- * mpt3sas_base_put_smid_hi_priority - send Task Management request to firmware
+ * _base_put_smid_hi_priority - send Task Management request to firmware
* @ioc: per adapter object
* @smid: system request message index
* @msix_task: msix_task will be same as msix of IO incase of task abort else 0.
*/
-void
-mpt3sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid,
+static void
+_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid,
u16 msix_task)
{
Mpi2RequestDescriptorUnion_t descriptor;
@@ -3607,7 +3809,7 @@ mpt3sas_base_put_smid_nvme_encap(struct MPT3SAS_ADAPTER *ioc, u16 smid)
descriptor.Default.RequestFlags =
MPI26_REQ_DESCRIPT_FLAGS_PCIE_ENCAPSULATED;
- descriptor.Default.MSIxIndex = _base_get_msix_index(ioc);
+ descriptor.Default.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
descriptor.Default.SMID = cpu_to_le16(smid);
descriptor.Default.LMID = 0;
descriptor.Default.DescriptorTypeDependent = 0;
@@ -3616,12 +3818,12 @@ mpt3sas_base_put_smid_nvme_encap(struct MPT3SAS_ADAPTER *ioc, u16 smid)
}
/**
- * mpt3sas_base_put_smid_default - Default, primarily used for config pages
+ * _base_put_smid_default - Default, primarily used for config pages
* @ioc: per adapter object
* @smid: system request message index
*/
-void
-mpt3sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid)
+static void
+_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid)
{
Mpi2RequestDescriptorUnion_t descriptor;
void *mpi_req_iomem;
@@ -3639,7 +3841,7 @@ mpt3sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid)
}
request = (u64 *)&descriptor;
descriptor.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
- descriptor.Default.MSIxIndex = _base_get_msix_index(ioc);
+ descriptor.Default.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
descriptor.Default.SMID = cpu_to_le16(smid);
descriptor.Default.LMID = 0;
descriptor.Default.DescriptorTypeDependent = 0;
@@ -3653,6 +3855,95 @@ mpt3sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid)
}
/**
+ * _base_put_smid_scsi_io_atomic - send SCSI_IO request to firmware using
+ * Atomic Request Descriptor
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @handle: device handle, unused in this function, for function type match
+ *
+ * Return nothing.
+ */
+static void
+_base_put_smid_scsi_io_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid,
+ u16 handle)
+{
+ Mpi26AtomicRequestDescriptor_t descriptor;
+ u32 *request = (u32 *)&descriptor;
+
+ descriptor.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
+ descriptor.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
+ descriptor.SMID = cpu_to_le16(smid);
+
+ writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost);
+}
+
+/**
+ * _base_put_smid_fast_path_atomic - send fast path request to firmware
+ * using Atomic Request Descriptor
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @handle: device handle, unused in this function, for function type match
+ * Return nothing
+ */
+static void
+_base_put_smid_fast_path_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid,
+ u16 handle)
+{
+ Mpi26AtomicRequestDescriptor_t descriptor;
+ u32 *request = (u32 *)&descriptor;
+
+ descriptor.RequestFlags = MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO;
+ descriptor.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
+ descriptor.SMID = cpu_to_le16(smid);
+
+ writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost);
+}
+
+/**
+ * _base_put_smid_hi_priority_atomic - send Task Management request to
+ * firmware using Atomic Request Descriptor
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @msix_task: msix_task will be same as msix of IO incase of task abort else 0
+ *
+ * Return nothing.
+ */
+static void
+_base_put_smid_hi_priority_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid,
+ u16 msix_task)
+{
+ Mpi26AtomicRequestDescriptor_t descriptor;
+ u32 *request = (u32 *)&descriptor;
+
+ descriptor.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
+ descriptor.MSIxIndex = msix_task;
+ descriptor.SMID = cpu_to_le16(smid);
+
+ writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost);
+}
+
+/**
+ * _base_put_smid_default - Default, primarily used for config pages
+ * use Atomic Request Descriptor
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * Return nothing.
+ */
+static void
+_base_put_smid_default_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid)
+{
+ Mpi26AtomicRequestDescriptor_t descriptor;
+ u32 *request = (u32 *)&descriptor;
+
+ descriptor.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ descriptor.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
+ descriptor.SMID = cpu_to_le16(smid);
+
+ writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost);
+}
+
+/**
* _base_display_OEMs_branding - Display branding string
* @ioc: per adapter object
*/
@@ -3952,7 +4243,7 @@ _base_display_fwpkg_version(struct MPT3SAS_ADAPTER *ioc)
ioc->build_sg(ioc, &mpi_request->SGL, 0, 0, fwpkg_data_dma,
data_length);
init_completion(&ioc->base_cmds.done);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
/* Wait for 15 seconds */
wait_for_completion_timeout(&ioc->base_cmds.done,
FW_IMG_HDR_READ_TIMEOUT*HZ);
@@ -4192,6 +4483,71 @@ out:
}
/**
+ * _base_update_ioc_page1_inlinewith_perf_mode - Update IOC Page1 fields
+ * according to performance mode.
+ * @ioc : per adapter object
+ *
+ * Return nothing.
+ */
+static void
+_base_update_ioc_page1_inlinewith_perf_mode(struct MPT3SAS_ADAPTER *ioc)
+{
+ Mpi2IOCPage1_t ioc_pg1;
+ Mpi2ConfigReply_t mpi_reply;
+
+ mpt3sas_config_get_ioc_pg1(ioc, &mpi_reply, &ioc->ioc_pg1_copy);
+ memcpy(&ioc_pg1, &ioc->ioc_pg1_copy, sizeof(Mpi2IOCPage1_t));
+
+ switch (perf_mode) {
+ case MPT_PERF_MODE_DEFAULT:
+ case MPT_PERF_MODE_BALANCED:
+ if (ioc->high_iops_queues) {
+ ioc_info(ioc,
+ "Enable interrupt coalescing only for first\t"
+ "%d reply queues\n",
+ MPT3SAS_HIGH_IOPS_REPLY_QUEUES);
+ /*
+ * If 31st bit is zero then interrupt coalescing is
+ * enabled for all reply descriptor post queues.
+ * If 31st bit is set to one then user can
+ * enable/disable interrupt coalescing on per reply
+ * descriptor post queue group(8) basis. So to enable
+ * interrupt coalescing only on first reply descriptor
+ * post queue group 31st bit and zero th bit is enabled.
+ */
+ ioc_pg1.ProductSpecific = cpu_to_le32(0x80000000 |
+ ((1 << MPT3SAS_HIGH_IOPS_REPLY_QUEUES/8) - 1));
+ mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply, &ioc_pg1);
+ ioc_info(ioc, "performance mode: balanced\n");
+ return;
+ }
+ /* Fall through */
+ case MPT_PERF_MODE_LATENCY:
+ /*
+ * Enable interrupt coalescing on all reply queues
+ * with timeout value 0xA
+ */
+ ioc_pg1.CoalescingTimeout = cpu_to_le32(0xa);
+ ioc_pg1.Flags |= cpu_to_le32(MPI2_IOCPAGE1_REPLY_COALESCING);
+ ioc_pg1.ProductSpecific = 0;
+ mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply, &ioc_pg1);
+ ioc_info(ioc, "performance mode: latency\n");
+ break;
+ case MPT_PERF_MODE_IOPS:
+ /*
+ * Enable interrupt coalescing on all reply queues.
+ */
+ ioc_info(ioc,
+ "performance mode: iops with coalescing timeout: 0x%x\n",
+ le32_to_cpu(ioc_pg1.CoalescingTimeout));
+ ioc_pg1.Flags |= cpu_to_le32(MPI2_IOCPAGE1_REPLY_COALESCING);
+ ioc_pg1.ProductSpecific = 0;
+ mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply, &ioc_pg1);
+ break;
+ }
+}
+
+/**
* _base_static_config_pages - static start of day config pages
* @ioc: per adapter object
*/
@@ -4258,6 +4614,8 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc)
if (ioc->iounit_pg8.NumSensors)
ioc->temp_sensors_count = ioc->iounit_pg8.NumSensors;
+ if (ioc->is_aero_ioc)
+ _base_update_ioc_page1_inlinewith_perf_mode(ioc);
}
/**
@@ -5431,7 +5789,7 @@ mpt3sas_base_sas_iounit_control(struct MPT3SAS_ADAPTER *ioc,
mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET)
ioc->ioc_link_reset_in_progress = 1;
init_completion(&ioc->base_cmds.done);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->base_cmds.done,
msecs_to_jiffies(10000));
if ((mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET ||
@@ -5510,7 +5868,7 @@ mpt3sas_base_scsi_enclosure_processor(struct MPT3SAS_ADAPTER *ioc,
ioc->base_cmds.smid = smid;
memcpy(request, mpi_request, sizeof(Mpi2SepReply_t));
init_completion(&ioc->base_cmds.done);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->base_cmds.done,
msecs_to_jiffies(10000));
if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) {
@@ -5693,6 +6051,9 @@ _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc)
if ((facts->IOCCapabilities &
MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE) && (!reset_devices))
ioc->rdpq_array_capable = 1;
+ if ((facts->IOCCapabilities & MPI26_IOCFACTS_CAPABILITY_ATOMIC_REQ)
+ && ioc->is_aero_ioc)
+ ioc->atomic_desc_capable = 1;
facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word);
facts->IOCRequestFrameSize =
le16_to_cpu(mpi_reply.IOCRequestFrameSize);
@@ -5914,7 +6275,7 @@ _base_send_port_enable(struct MPT3SAS_ADAPTER *ioc)
mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE;
init_completion(&ioc->port_enable_cmds.done);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->port_enable_cmds.done, 300*HZ);
if (!(ioc->port_enable_cmds.status & MPT3_CMD_COMPLETE)) {
ioc_err(ioc, "%s: timeout\n", __func__);
@@ -5973,7 +6334,7 @@ mpt3sas_port_enable(struct MPT3SAS_ADAPTER *ioc)
memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t));
mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE;
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
return 0;
}
@@ -6089,7 +6450,7 @@ _base_event_notification(struct MPT3SAS_ADAPTER *ioc)
mpi_request->EventMasks[i] =
cpu_to_le32(ioc->event_masks[i]);
init_completion(&ioc->base_cmds.done);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ);
if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) {
ioc_err(ioc, "%s: timeout\n", __func__);
@@ -6549,6 +6910,8 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
}
}
+ ioc->smp_affinity_enable = smp_affinity_enable;
+
ioc->rdpq_array_enable_assigned = 0;
ioc->dma_mask = 0;
if (ioc->is_aero_ioc)
@@ -6569,6 +6932,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
ioc->build_sg_scmd = &_base_build_sg_scmd;
ioc->build_sg = &_base_build_sg;
ioc->build_zero_len_sge = &_base_build_zero_len_sge;
+ ioc->get_msix_index_for_smlio = &_base_get_msix_index;
break;
case MPI25_VERSION:
case MPI26_VERSION:
@@ -6583,15 +6947,30 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
ioc->build_nvme_prp = &_base_build_nvme_prp;
ioc->build_zero_len_sge = &_base_build_zero_len_sge_ieee;
ioc->sge_size_ieee = sizeof(Mpi2IeeeSgeSimple64_t);
-
+ if (ioc->high_iops_queues)
+ ioc->get_msix_index_for_smlio =
+ &_base_get_high_iops_msix_index;
+ else
+ ioc->get_msix_index_for_smlio = &_base_get_msix_index;
break;
}
-
- if (ioc->is_mcpu_endpoint)
- ioc->put_smid_scsi_io = &_base_put_smid_mpi_ep_scsi_io;
- else
- ioc->put_smid_scsi_io = &_base_put_smid_scsi_io;
-
+ if (ioc->atomic_desc_capable) {
+ ioc->put_smid_default = &_base_put_smid_default_atomic;
+ ioc->put_smid_scsi_io = &_base_put_smid_scsi_io_atomic;
+ ioc->put_smid_fast_path =
+ &_base_put_smid_fast_path_atomic;
+ ioc->put_smid_hi_priority =
+ &_base_put_smid_hi_priority_atomic;
+ } else {
+ ioc->put_smid_default = &_base_put_smid_default;
+ ioc->put_smid_fast_path = &_base_put_smid_fast_path;
+ ioc->put_smid_hi_priority = &_base_put_smid_hi_priority;
+ if (ioc->is_mcpu_endpoint)
+ ioc->put_smid_scsi_io =
+ &_base_put_smid_mpi_ep_scsi_io;
+ else
+ ioc->put_smid_scsi_io = &_base_put_smid_scsi_io;
+ }
/*
* These function pointers for other requests that don't
* the require IEEE scatter gather elements.
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h
index 480219f0efc5..6afbdb044310 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.h
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.h
@@ -76,8 +76,8 @@
#define MPT3SAS_DRIVER_NAME "mpt3sas"
#define MPT3SAS_AUTHOR "Avago Technologies <MPT-FusionLinux.pdl@avagotech.com>"
#define MPT3SAS_DESCRIPTION "LSI MPT Fusion SAS 3.0 Device Driver"
-#define MPT3SAS_DRIVER_VERSION "28.100.00.00"
-#define MPT3SAS_MAJOR_VERSION 28
+#define MPT3SAS_DRIVER_VERSION "29.100.00.00"
+#define MPT3SAS_MAJOR_VERSION 29
#define MPT3SAS_MINOR_VERSION 100
#define MPT3SAS_BUILD_VERSION 0
#define MPT3SAS_RELEASE_VERSION 00
@@ -355,6 +355,12 @@ struct mpt3sas_nvme_cmd {
#define VIRTUAL_IO_FAILED_RETRY (0x32010081)
+/* High IOPs definitions */
+#define MPT3SAS_DEVICE_HIGH_IOPS_DEPTH 8
+#define MPT3SAS_HIGH_IOPS_REPLY_QUEUES 8
+#define MPT3SAS_HIGH_IOPS_BATCH_COUNT 16
+#define MPT3SAS_GEN35_MAX_MSIX_QUEUES 128
+
/* OEM Specific Flags will come from OEM specific header files */
struct Mpi2ManufacturingPage10_t {
MPI2_CONFIG_PAGE_HEADER Header; /* 00h */
@@ -824,6 +830,7 @@ struct chain_lookup {
*/
struct scsiio_tracker {
u16 smid;
+ struct scsi_cmnd *scmd;
u8 cb_idx;
u8 direct_io;
struct pcie_sg_list pcie_sg_list;
@@ -924,6 +931,12 @@ typedef void (*PUT_SMID_IO_FP_HIP) (struct MPT3SAS_ADAPTER *ioc, u16 smid,
u16 funcdep);
typedef void (*PUT_SMID_DEFAULT) (struct MPT3SAS_ADAPTER *ioc, u16 smid);
typedef u32 (*BASE_READ_REG) (const volatile void __iomem *addr);
+/*
+ * To get high iops reply queue's msix index when high iops mode is enabled
+ * else get the msix index of general reply queues.
+ */
+typedef u8 (*GET_MSIX_INDEX) (struct MPT3SAS_ADAPTER *ioc,
+ struct scsi_cmnd *scmd);
/* IOC Facts and Port Facts converted from little endian to cpu */
union mpi3_version_union {
@@ -1025,6 +1038,8 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc);
* @cpu_msix_table: table for mapping cpus to msix index
* @cpu_msix_table_sz: table size
* @total_io_cnt: Gives total IO count, used to load balance the interrupts
+ * @high_iops_outstanding: used to load balance the interrupts
+ * within high iops reply queues
* @msix_load_balance: Enables load balancing of interrupts across
* the multiple MSIXs
* @schedule_dead_ioc_flush_running_cmds: callback to flush pending commands
@@ -1147,6 +1162,8 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc);
* path functions resulting in Null pointer reference followed by kernel
* crash. To avoid the above race condition we use mutex syncrhonization
* which ensures the syncrhonization between cli/sysfs_show path.
+ * @atomic_desc_capable: Atomic Request Descriptor support.
+ * @GET_MSIX_INDEX: Get the msix index of high iops queues.
*/
struct MPT3SAS_ADAPTER {
struct list_head list;
@@ -1206,8 +1223,10 @@ struct MPT3SAS_ADAPTER {
MPT3SAS_FLUSH_RUNNING_CMDS schedule_dead_ioc_flush_running_cmds;
u32 non_operational_loop;
atomic64_t total_io_cnt;
+ atomic64_t high_iops_outstanding;
bool msix_load_balance;
u16 thresh_hold;
+ u8 high_iops_queues;
/* internal commands, callback index */
u8 scsi_io_cb_idx;
@@ -1267,6 +1286,7 @@ struct MPT3SAS_ADAPTER {
Mpi2IOUnitPage0_t iounit_pg0;
Mpi2IOUnitPage1_t iounit_pg1;
Mpi2IOUnitPage8_t iounit_pg8;
+ Mpi2IOCPage1_t ioc_pg1_copy;
struct _boot_device req_boot_device;
struct _boot_device req_alt_boot_device;
@@ -1385,6 +1405,7 @@ struct MPT3SAS_ADAPTER {
u8 combined_reply_queue;
u8 combined_reply_index_count;
+ u8 smp_affinity_enable;
/* reply post register index */
resource_size_t **replyPostRegisterIndex;
@@ -1412,6 +1433,7 @@ struct MPT3SAS_ADAPTER {
u8 hide_drives;
spinlock_t diag_trigger_lock;
u8 diag_trigger_active;
+ u8 atomic_desc_capable;
BASE_READ_REG base_readl;
struct SL_WH_MASTER_TRIGGER_T diag_trigger_master;
struct SL_WH_EVENT_TRIGGERS_T diag_trigger_event;
@@ -1422,7 +1444,10 @@ struct MPT3SAS_ADAPTER {
u8 is_gen35_ioc;
u8 is_aero_ioc;
PUT_SMID_IO_FP_HIP put_smid_scsi_io;
-
+ PUT_SMID_IO_FP_HIP put_smid_fast_path;
+ PUT_SMID_IO_FP_HIP put_smid_hi_priority;
+ PUT_SMID_DEFAULT put_smid_default;
+ GET_MSIX_INDEX get_msix_index_for_smlio;
};
typedef u8 (*MPT_CALLBACK)(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
@@ -1611,6 +1636,10 @@ int mpt3sas_config_get_sas_iounit_pg1(struct MPT3SAS_ADAPTER *ioc,
int mpt3sas_config_set_sas_iounit_pg1(struct MPT3SAS_ADAPTER *ioc,
Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage1_t *config_page,
u16 sz);
+int mpt3sas_config_get_ioc_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+ *mpi_reply, Mpi2IOCPage1_t *config_page);
+int mpt3sas_config_set_ioc_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+ *mpi_reply, Mpi2IOCPage1_t *config_page);
int mpt3sas_config_get_ioc_pg8(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2IOCPage8_t *config_page);
int mpt3sas_config_get_expander_pg0(struct MPT3SAS_ADAPTER *ioc,
diff --git a/drivers/scsi/mpt3sas/mpt3sas_config.c b/drivers/scsi/mpt3sas/mpt3sas_config.c
index fb0a17252f86..14a1a2793dd5 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_config.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_config.c
@@ -380,7 +380,7 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
memcpy(config_request, mpi_request, sizeof(Mpi2ConfigRequest_t));
_config_display_some_debug(ioc, smid, "config_request", NULL);
init_completion(&ioc->config_cmds.done);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->config_cmds.done, timeout*HZ);
if (!(ioc->config_cmds.status & MPT3_CMD_COMPLETE)) {
mpt3sas_base_check_cmd_timeout(ioc,
@@ -949,6 +949,77 @@ mpt3sas_config_get_ioc_pg8(struct MPT3SAS_ADAPTER *ioc,
out:
return r;
}
+/**
+ * mpt3sas_config_get_ioc_pg1 - obtain ioc page 1
+ * @ioc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * Context: sleep.
+ *
+ * Return: 0 for success, non-zero for failure.
+ */
+int
+mpt3sas_config_get_ioc_pg1(struct MPT3SAS_ADAPTER *ioc,
+ Mpi2ConfigReply_t *mpi_reply, Mpi2IOCPage1_t *config_page)
+{
+ Mpi2ConfigRequest_t mpi_request;
+ int r;
+
+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+ mpi_request.Function = MPI2_FUNCTION_CONFIG;
+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IOC;
+ mpi_request.Header.PageNumber = 1;
+ mpi_request.Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION;
+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
+ r = _config_request(ioc, &mpi_request, mpi_reply,
+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
+ if (r)
+ goto out;
+
+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+ r = _config_request(ioc, &mpi_request, mpi_reply,
+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
+ sizeof(*config_page));
+ out:
+ return r;
+}
+
+/**
+ * mpt3sas_config_set_ioc_pg1 - modify ioc page 1
+ * @ioc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * Context: sleep.
+ *
+ * Return: 0 for success, non-zero for failure.
+ */
+int
+mpt3sas_config_set_ioc_pg1(struct MPT3SAS_ADAPTER *ioc,
+ Mpi2ConfigReply_t *mpi_reply, Mpi2IOCPage1_t *config_page)
+{
+ Mpi2ConfigRequest_t mpi_request;
+ int r;
+
+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+ mpi_request.Function = MPI2_FUNCTION_CONFIG;
+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IOC;
+ mpi_request.Header.PageNumber = 1;
+ mpi_request.Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION;
+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
+ r = _config_request(ioc, &mpi_request, mpi_reply,
+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
+ if (r)
+ goto out;
+
+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+ r = _config_request(ioc, &mpi_request, mpi_reply,
+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
+ sizeof(*config_page));
+ out:
+ return r;
+}
/**
* mpt3sas_config_get_sas_device_pg0 - obtain sas device page 0
diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
index b2bb47c14d35..d4ecfbbe738c 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
@@ -822,7 +822,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)
ioc->put_smid_scsi_io(ioc, smid, device_handle);
else
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
break;
}
case MPI2_FUNCTION_SCSI_TASK_MGMT:
@@ -859,7 +859,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
tm_request->DevHandle));
ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz,
data_in_dma, data_in_sz);
- mpt3sas_base_put_smid_hi_priority(ioc, smid, 0);
+ ioc->put_smid_hi_priority(ioc, smid, 0);
break;
}
case MPI2_FUNCTION_SMP_PASSTHROUGH:
@@ -890,7 +890,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
}
ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma,
data_in_sz);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
break;
}
case MPI2_FUNCTION_SATA_PASSTHROUGH:
@@ -905,7 +905,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
}
ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma,
data_in_sz);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
break;
}
case MPI2_FUNCTION_FW_DOWNLOAD:
@@ -913,7 +913,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
{
ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma,
data_in_sz);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
break;
}
case MPI2_FUNCTION_TOOLBOX:
@@ -928,7 +928,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz,
data_in_dma, data_in_sz);
}
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
break;
}
case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL:
@@ -948,7 +948,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
default:
ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz,
data_in_dma, data_in_sz);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
break;
}
@@ -1576,7 +1576,7 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc,
cpu_to_le32(ioc->product_specific[buffer_type][i]);
init_completion(&ioc->ctl_cmds.done);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->ctl_cmds.done,
MPT3_IOCTL_DEFAULT_TIMEOUT*HZ);
@@ -1903,7 +1903,7 @@ mpt3sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type,
mpi_request->VP_ID = 0;
init_completion(&ioc->ctl_cmds.done);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->ctl_cmds.done,
MPT3_IOCTL_DEFAULT_TIMEOUT*HZ);
@@ -2151,7 +2151,7 @@ _ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
mpi_request->VP_ID = 0;
init_completion(&ioc->ctl_cmds.done);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->ctl_cmds.done,
MPT3_IOCTL_DEFAULT_TIMEOUT*HZ);
@@ -2319,6 +2319,10 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg,
break;
}
+ if (karg.hdr.ioc_number != ioctl_header.ioc_number) {
+ ret = -EINVAL;
+ break;
+ }
if (_IOC_SIZE(cmd) == sizeof(struct mpt3_ioctl_command)) {
uarg = arg;
ret = _ctl_do_mpt_command(ioc, karg, &uarg->mf);
@@ -2453,7 +2457,7 @@ _ctl_mpt2_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg)
/* scsi host attributes */
/**
- * _ctl_version_fw_show - firmware version
+ * version_fw_show - firmware version
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2461,7 +2465,7 @@ _ctl_mpt2_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg)
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_version_fw_show(struct device *cdev, struct device_attribute *attr,
+version_fw_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2473,10 +2477,10 @@ _ctl_version_fw_show(struct device *cdev, struct device_attribute *attr,
(ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
ioc->facts.FWVersion.Word & 0x000000FF);
}
-static DEVICE_ATTR(version_fw, S_IRUGO, _ctl_version_fw_show, NULL);
+static DEVICE_ATTR_RO(version_fw);
/**
- * _ctl_version_bios_show - bios version
+ * version_bios_show - bios version
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2484,7 +2488,7 @@ static DEVICE_ATTR(version_fw, S_IRUGO, _ctl_version_fw_show, NULL);
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_version_bios_show(struct device *cdev, struct device_attribute *attr,
+version_bios_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2498,10 +2502,10 @@ _ctl_version_bios_show(struct device *cdev, struct device_attribute *attr,
(version & 0x0000FF00) >> 8,
version & 0x000000FF);
}
-static DEVICE_ATTR(version_bios, S_IRUGO, _ctl_version_bios_show, NULL);
+static DEVICE_ATTR_RO(version_bios);
/**
- * _ctl_version_mpi_show - MPI (message passing interface) version
+ * version_mpi_show - MPI (message passing interface) version
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2509,7 +2513,7 @@ static DEVICE_ATTR(version_bios, S_IRUGO, _ctl_version_bios_show, NULL);
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_version_mpi_show(struct device *cdev, struct device_attribute *attr,
+version_mpi_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2518,10 +2522,10 @@ _ctl_version_mpi_show(struct device *cdev, struct device_attribute *attr,
return snprintf(buf, PAGE_SIZE, "%03x.%02x\n",
ioc->facts.MsgVersion, ioc->facts.HeaderVersion >> 8);
}
-static DEVICE_ATTR(version_mpi, S_IRUGO, _ctl_version_mpi_show, NULL);
+static DEVICE_ATTR_RO(version_mpi);
/**
- * _ctl_version_product_show - product name
+ * version_product_show - product name
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2529,7 +2533,7 @@ static DEVICE_ATTR(version_mpi, S_IRUGO, _ctl_version_mpi_show, NULL);
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_version_product_show(struct device *cdev, struct device_attribute *attr,
+version_product_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2537,10 +2541,10 @@ _ctl_version_product_show(struct device *cdev, struct device_attribute *attr,
return snprintf(buf, 16, "%s\n", ioc->manu_pg0.ChipName);
}
-static DEVICE_ATTR(version_product, S_IRUGO, _ctl_version_product_show, NULL);
+static DEVICE_ATTR_RO(version_product);
/**
- * _ctl_version_nvdata_persistent_show - ndvata persistent version
+ * version_nvdata_persistent_show - ndvata persistent version
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2548,7 +2552,7 @@ static DEVICE_ATTR(version_product, S_IRUGO, _ctl_version_product_show, NULL);
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_version_nvdata_persistent_show(struct device *cdev,
+version_nvdata_persistent_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2557,11 +2561,10 @@ _ctl_version_nvdata_persistent_show(struct device *cdev,
return snprintf(buf, PAGE_SIZE, "%08xh\n",
le32_to_cpu(ioc->iounit_pg0.NvdataVersionPersistent.Word));
}
-static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
- _ctl_version_nvdata_persistent_show, NULL);
+static DEVICE_ATTR_RO(version_nvdata_persistent);
/**
- * _ctl_version_nvdata_default_show - nvdata default version
+ * version_nvdata_default_show - nvdata default version
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2569,7 +2572,7 @@ static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_version_nvdata_default_show(struct device *cdev, struct device_attribute
+version_nvdata_default_show(struct device *cdev, struct device_attribute
*attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2578,11 +2581,10 @@ _ctl_version_nvdata_default_show(struct device *cdev, struct device_attribute
return snprintf(buf, PAGE_SIZE, "%08xh\n",
le32_to_cpu(ioc->iounit_pg0.NvdataVersionDefault.Word));
}
-static DEVICE_ATTR(version_nvdata_default, S_IRUGO,
- _ctl_version_nvdata_default_show, NULL);
+static DEVICE_ATTR_RO(version_nvdata_default);
/**
- * _ctl_board_name_show - board name
+ * board_name_show - board name
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2590,7 +2592,7 @@ static DEVICE_ATTR(version_nvdata_default, S_IRUGO,
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_board_name_show(struct device *cdev, struct device_attribute *attr,
+board_name_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2598,10 +2600,10 @@ _ctl_board_name_show(struct device *cdev, struct device_attribute *attr,
return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardName);
}
-static DEVICE_ATTR(board_name, S_IRUGO, _ctl_board_name_show, NULL);
+static DEVICE_ATTR_RO(board_name);
/**
- * _ctl_board_assembly_show - board assembly name
+ * board_assembly_show - board assembly name
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2609,7 +2611,7 @@ static DEVICE_ATTR(board_name, S_IRUGO, _ctl_board_name_show, NULL);
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_board_assembly_show(struct device *cdev, struct device_attribute *attr,
+board_assembly_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2617,10 +2619,10 @@ _ctl_board_assembly_show(struct device *cdev, struct device_attribute *attr,
return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardAssembly);
}
-static DEVICE_ATTR(board_assembly, S_IRUGO, _ctl_board_assembly_show, NULL);
+static DEVICE_ATTR_RO(board_assembly);
/**
- * _ctl_board_tracer_show - board tracer number
+ * board_tracer_show - board tracer number
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2628,7 +2630,7 @@ static DEVICE_ATTR(board_assembly, S_IRUGO, _ctl_board_assembly_show, NULL);
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_board_tracer_show(struct device *cdev, struct device_attribute *attr,
+board_tracer_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2636,10 +2638,10 @@ _ctl_board_tracer_show(struct device *cdev, struct device_attribute *attr,
return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardTracerNumber);
}
-static DEVICE_ATTR(board_tracer, S_IRUGO, _ctl_board_tracer_show, NULL);
+static DEVICE_ATTR_RO(board_tracer);
/**
- * _ctl_io_delay_show - io missing delay
+ * io_delay_show - io missing delay
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2650,7 +2652,7 @@ static DEVICE_ATTR(board_tracer, S_IRUGO, _ctl_board_tracer_show, NULL);
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_io_delay_show(struct device *cdev, struct device_attribute *attr,
+io_delay_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2658,10 +2660,10 @@ _ctl_io_delay_show(struct device *cdev, struct device_attribute *attr,
return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
}
-static DEVICE_ATTR(io_delay, S_IRUGO, _ctl_io_delay_show, NULL);
+static DEVICE_ATTR_RO(io_delay);
/**
- * _ctl_device_delay_show - device missing delay
+ * device_delay_show - device missing delay
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2672,7 +2674,7 @@ static DEVICE_ATTR(io_delay, S_IRUGO, _ctl_io_delay_show, NULL);
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_device_delay_show(struct device *cdev, struct device_attribute *attr,
+device_delay_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2680,10 +2682,10 @@ _ctl_device_delay_show(struct device *cdev, struct device_attribute *attr,
return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
}
-static DEVICE_ATTR(device_delay, S_IRUGO, _ctl_device_delay_show, NULL);
+static DEVICE_ATTR_RO(device_delay);
/**
- * _ctl_fw_queue_depth_show - global credits
+ * fw_queue_depth_show - global credits
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2693,7 +2695,7 @@ static DEVICE_ATTR(device_delay, S_IRUGO, _ctl_device_delay_show, NULL);
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_fw_queue_depth_show(struct device *cdev, struct device_attribute *attr,
+fw_queue_depth_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2701,10 +2703,10 @@ _ctl_fw_queue_depth_show(struct device *cdev, struct device_attribute *attr,
return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->facts.RequestCredit);
}
-static DEVICE_ATTR(fw_queue_depth, S_IRUGO, _ctl_fw_queue_depth_show, NULL);
+static DEVICE_ATTR_RO(fw_queue_depth);
/**
- * _ctl_sas_address_show - sas address
+ * sas_address_show - sas address
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2714,7 +2716,7 @@ static DEVICE_ATTR(fw_queue_depth, S_IRUGO, _ctl_fw_queue_depth_show, NULL);
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_host_sas_address_show(struct device *cdev, struct device_attribute *attr,
+host_sas_address_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
@@ -2724,11 +2726,10 @@ _ctl_host_sas_address_show(struct device *cdev, struct device_attribute *attr,
return snprintf(buf, PAGE_SIZE, "0x%016llx\n",
(unsigned long long)ioc->sas_hba.sas_address);
}
-static DEVICE_ATTR(host_sas_address, S_IRUGO,
- _ctl_host_sas_address_show, NULL);
+static DEVICE_ATTR_RO(host_sas_address);
/**
- * _ctl_logging_level_show - logging level
+ * logging_level_show - logging level
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2736,7 +2737,7 @@ static DEVICE_ATTR(host_sas_address, S_IRUGO,
* A sysfs 'read/write' shost attribute.
*/
static ssize_t
-_ctl_logging_level_show(struct device *cdev, struct device_attribute *attr,
+logging_level_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2745,7 +2746,7 @@ _ctl_logging_level_show(struct device *cdev, struct device_attribute *attr,
return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->logging_level);
}
static ssize_t
-_ctl_logging_level_store(struct device *cdev, struct device_attribute *attr,
+logging_level_store(struct device *cdev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2760,11 +2761,10 @@ _ctl_logging_level_store(struct device *cdev, struct device_attribute *attr,
ioc->logging_level);
return strlen(buf);
}
-static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR, _ctl_logging_level_show,
- _ctl_logging_level_store);
+static DEVICE_ATTR_RW(logging_level);
/**
- * _ctl_fwfault_debug_show - show/store fwfault_debug
+ * fwfault_debug_show - show/store fwfault_debug
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2773,7 +2773,7 @@ static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR, _ctl_logging_level_show,
* A sysfs 'read/write' shost attribute.
*/
static ssize_t
-_ctl_fwfault_debug_show(struct device *cdev, struct device_attribute *attr,
+fwfault_debug_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2782,7 +2782,7 @@ _ctl_fwfault_debug_show(struct device *cdev, struct device_attribute *attr,
return snprintf(buf, PAGE_SIZE, "%d\n", ioc->fwfault_debug);
}
static ssize_t
-_ctl_fwfault_debug_store(struct device *cdev, struct device_attribute *attr,
+fwfault_debug_store(struct device *cdev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2797,11 +2797,10 @@ _ctl_fwfault_debug_store(struct device *cdev, struct device_attribute *attr,
ioc->fwfault_debug);
return strlen(buf);
}
-static DEVICE_ATTR(fwfault_debug, S_IRUGO | S_IWUSR,
- _ctl_fwfault_debug_show, _ctl_fwfault_debug_store);
+static DEVICE_ATTR_RW(fwfault_debug);
/**
- * _ctl_ioc_reset_count_show - ioc reset count
+ * ioc_reset_count_show - ioc reset count
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2811,7 +2810,7 @@ static DEVICE_ATTR(fwfault_debug, S_IRUGO | S_IWUSR,
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_ioc_reset_count_show(struct device *cdev, struct device_attribute *attr,
+ioc_reset_count_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2819,10 +2818,10 @@ _ctl_ioc_reset_count_show(struct device *cdev, struct device_attribute *attr,
return snprintf(buf, PAGE_SIZE, "%d\n", ioc->ioc_reset_count);
}
-static DEVICE_ATTR(ioc_reset_count, S_IRUGO, _ctl_ioc_reset_count_show, NULL);
+static DEVICE_ATTR_RO(ioc_reset_count);
/**
- * _ctl_ioc_reply_queue_count_show - number of reply queues
+ * reply_queue_count_show - number of reply queues
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2832,7 +2831,7 @@ static DEVICE_ATTR(ioc_reset_count, S_IRUGO, _ctl_ioc_reset_count_show, NULL);
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_ioc_reply_queue_count_show(struct device *cdev,
+reply_queue_count_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
u8 reply_queue_count;
@@ -2847,11 +2846,10 @@ _ctl_ioc_reply_queue_count_show(struct device *cdev,
return snprintf(buf, PAGE_SIZE, "%d\n", reply_queue_count);
}
-static DEVICE_ATTR(reply_queue_count, S_IRUGO, _ctl_ioc_reply_queue_count_show,
- NULL);
+static DEVICE_ATTR_RO(reply_queue_count);
/**
- * _ctl_BRM_status_show - Backup Rail Monitor Status
+ * BRM_status_show - Backup Rail Monitor Status
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2861,7 +2859,7 @@ static DEVICE_ATTR(reply_queue_count, S_IRUGO, _ctl_ioc_reply_queue_count_show,
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_BRM_status_show(struct device *cdev, struct device_attribute *attr,
+BRM_status_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2923,7 +2921,7 @@ _ctl_BRM_status_show(struct device *cdev, struct device_attribute *attr,
mutex_unlock(&ioc->pci_access_mutex);
return rc;
}
-static DEVICE_ATTR(BRM_status, S_IRUGO, _ctl_BRM_status_show, NULL);
+static DEVICE_ATTR_RO(BRM_status);
struct DIAG_BUFFER_START {
__le32 Size;
@@ -2936,7 +2934,7 @@ struct DIAG_BUFFER_START {
};
/**
- * _ctl_host_trace_buffer_size_show - host buffer size (trace only)
+ * host_trace_buffer_size_show - host buffer size (trace only)
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2944,7 +2942,7 @@ struct DIAG_BUFFER_START {
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_host_trace_buffer_size_show(struct device *cdev,
+host_trace_buffer_size_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2976,11 +2974,10 @@ _ctl_host_trace_buffer_size_show(struct device *cdev,
ioc->ring_buffer_sz = size;
return snprintf(buf, PAGE_SIZE, "%d\n", size);
}
-static DEVICE_ATTR(host_trace_buffer_size, S_IRUGO,
- _ctl_host_trace_buffer_size_show, NULL);
+static DEVICE_ATTR_RO(host_trace_buffer_size);
/**
- * _ctl_host_trace_buffer_show - firmware ring buffer (trace only)
+ * host_trace_buffer_show - firmware ring buffer (trace only)
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2992,7 +2989,7 @@ static DEVICE_ATTR(host_trace_buffer_size, S_IRUGO,
* offset to the same attribute, it will move the pointer.
*/
static ssize_t
-_ctl_host_trace_buffer_show(struct device *cdev, struct device_attribute *attr,
+host_trace_buffer_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3024,7 +3021,7 @@ _ctl_host_trace_buffer_show(struct device *cdev, struct device_attribute *attr,
}
static ssize_t
-_ctl_host_trace_buffer_store(struct device *cdev, struct device_attribute *attr,
+host_trace_buffer_store(struct device *cdev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3037,14 +3034,13 @@ _ctl_host_trace_buffer_store(struct device *cdev, struct device_attribute *attr,
ioc->ring_buffer_offset = val;
return strlen(buf);
}
-static DEVICE_ATTR(host_trace_buffer, S_IRUGO | S_IWUSR,
- _ctl_host_trace_buffer_show, _ctl_host_trace_buffer_store);
+static DEVICE_ATTR_RW(host_trace_buffer);
/*****************************************/
/**
- * _ctl_host_trace_buffer_enable_show - firmware ring buffer (trace only)
+ * host_trace_buffer_enable_show - firmware ring buffer (trace only)
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -3054,7 +3050,7 @@ static DEVICE_ATTR(host_trace_buffer, S_IRUGO | S_IWUSR,
* This is a mechnism to post/release host_trace_buffers
*/
static ssize_t
-_ctl_host_trace_buffer_enable_show(struct device *cdev,
+host_trace_buffer_enable_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3072,7 +3068,7 @@ _ctl_host_trace_buffer_enable_show(struct device *cdev,
}
static ssize_t
-_ctl_host_trace_buffer_enable_store(struct device *cdev,
+host_trace_buffer_enable_store(struct device *cdev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3122,14 +3118,12 @@ _ctl_host_trace_buffer_enable_store(struct device *cdev,
out:
return strlen(buf);
}
-static DEVICE_ATTR(host_trace_buffer_enable, S_IRUGO | S_IWUSR,
- _ctl_host_trace_buffer_enable_show,
- _ctl_host_trace_buffer_enable_store);
+static DEVICE_ATTR_RW(host_trace_buffer_enable);
/*********** diagnostic trigger suppport *********************************/
/**
- * _ctl_diag_trigger_master_show - show the diag_trigger_master attribute
+ * diag_trigger_master_show - show the diag_trigger_master attribute
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -3137,7 +3131,7 @@ static DEVICE_ATTR(host_trace_buffer_enable, S_IRUGO | S_IWUSR,
* A sysfs 'read/write' shost attribute.
*/
static ssize_t
-_ctl_diag_trigger_master_show(struct device *cdev,
+diag_trigger_master_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
@@ -3154,7 +3148,7 @@ _ctl_diag_trigger_master_show(struct device *cdev,
}
/**
- * _ctl_diag_trigger_master_store - store the diag_trigger_master attribute
+ * diag_trigger_master_store - store the diag_trigger_master attribute
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -3163,7 +3157,7 @@ _ctl_diag_trigger_master_show(struct device *cdev,
* A sysfs 'read/write' shost attribute.
*/
static ssize_t
-_ctl_diag_trigger_master_store(struct device *cdev,
+diag_trigger_master_store(struct device *cdev,
struct device_attribute *attr, const char *buf, size_t count)
{
@@ -3182,12 +3176,11 @@ _ctl_diag_trigger_master_store(struct device *cdev,
spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
return rc;
}
-static DEVICE_ATTR(diag_trigger_master, S_IRUGO | S_IWUSR,
- _ctl_diag_trigger_master_show, _ctl_diag_trigger_master_store);
+static DEVICE_ATTR_RW(diag_trigger_master);
/**
- * _ctl_diag_trigger_event_show - show the diag_trigger_event attribute
+ * diag_trigger_event_show - show the diag_trigger_event attribute
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -3195,7 +3188,7 @@ static DEVICE_ATTR(diag_trigger_master, S_IRUGO | S_IWUSR,
* A sysfs 'read/write' shost attribute.
*/
static ssize_t
-_ctl_diag_trigger_event_show(struct device *cdev,
+diag_trigger_event_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3211,7 +3204,7 @@ _ctl_diag_trigger_event_show(struct device *cdev,
}
/**
- * _ctl_diag_trigger_event_store - store the diag_trigger_event attribute
+ * diag_trigger_event_store - store the diag_trigger_event attribute
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -3220,7 +3213,7 @@ _ctl_diag_trigger_event_show(struct device *cdev,
* A sysfs 'read/write' shost attribute.
*/
static ssize_t
-_ctl_diag_trigger_event_store(struct device *cdev,
+diag_trigger_event_store(struct device *cdev,
struct device_attribute *attr, const char *buf, size_t count)
{
@@ -3239,12 +3232,11 @@ _ctl_diag_trigger_event_store(struct device *cdev,
spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
return sz;
}
-static DEVICE_ATTR(diag_trigger_event, S_IRUGO | S_IWUSR,
- _ctl_diag_trigger_event_show, _ctl_diag_trigger_event_store);
+static DEVICE_ATTR_RW(diag_trigger_event);
/**
- * _ctl_diag_trigger_scsi_show - show the diag_trigger_scsi attribute
+ * diag_trigger_scsi_show - show the diag_trigger_scsi attribute
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -3252,7 +3244,7 @@ static DEVICE_ATTR(diag_trigger_event, S_IRUGO | S_IWUSR,
* A sysfs 'read/write' shost attribute.
*/
static ssize_t
-_ctl_diag_trigger_scsi_show(struct device *cdev,
+diag_trigger_scsi_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3268,7 +3260,7 @@ _ctl_diag_trigger_scsi_show(struct device *cdev,
}
/**
- * _ctl_diag_trigger_scsi_store - store the diag_trigger_scsi attribute
+ * diag_trigger_scsi_store - store the diag_trigger_scsi attribute
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -3277,7 +3269,7 @@ _ctl_diag_trigger_scsi_show(struct device *cdev,
* A sysfs 'read/write' shost attribute.
*/
static ssize_t
-_ctl_diag_trigger_scsi_store(struct device *cdev,
+diag_trigger_scsi_store(struct device *cdev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3295,12 +3287,11 @@ _ctl_diag_trigger_scsi_store(struct device *cdev,
spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
return sz;
}
-static DEVICE_ATTR(diag_trigger_scsi, S_IRUGO | S_IWUSR,
- _ctl_diag_trigger_scsi_show, _ctl_diag_trigger_scsi_store);
+static DEVICE_ATTR_RW(diag_trigger_scsi);
/**
- * _ctl_diag_trigger_scsi_show - show the diag_trigger_mpi attribute
+ * diag_trigger_scsi_show - show the diag_trigger_mpi attribute
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -3308,7 +3299,7 @@ static DEVICE_ATTR(diag_trigger_scsi, S_IRUGO | S_IWUSR,
* A sysfs 'read/write' shost attribute.
*/
static ssize_t
-_ctl_diag_trigger_mpi_show(struct device *cdev,
+diag_trigger_mpi_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3324,7 +3315,7 @@ _ctl_diag_trigger_mpi_show(struct device *cdev,
}
/**
- * _ctl_diag_trigger_mpi_store - store the diag_trigger_mpi attribute
+ * diag_trigger_mpi_store - store the diag_trigger_mpi attribute
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -3333,7 +3324,7 @@ _ctl_diag_trigger_mpi_show(struct device *cdev,
* A sysfs 'read/write' shost attribute.
*/
static ssize_t
-_ctl_diag_trigger_mpi_store(struct device *cdev,
+diag_trigger_mpi_store(struct device *cdev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3352,8 +3343,7 @@ _ctl_diag_trigger_mpi_store(struct device *cdev,
return sz;
}
-static DEVICE_ATTR(diag_trigger_mpi, S_IRUGO | S_IWUSR,
- _ctl_diag_trigger_mpi_show, _ctl_diag_trigger_mpi_store);
+static DEVICE_ATTR_RW(diag_trigger_mpi);
/*********** diagnostic trigger suppport *** END ****************************/
@@ -3391,7 +3381,7 @@ struct device_attribute *mpt3sas_host_attrs[] = {
/* device attributes */
/**
- * _ctl_device_sas_address_show - sas address
+ * sas_address_show - sas address
* @dev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -3401,7 +3391,7 @@ struct device_attribute *mpt3sas_host_attrs[] = {
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_device_sas_address_show(struct device *dev, struct device_attribute *attr,
+sas_address_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct scsi_device *sdev = to_scsi_device(dev);
@@ -3410,10 +3400,10 @@ _ctl_device_sas_address_show(struct device *dev, struct device_attribute *attr,
return snprintf(buf, PAGE_SIZE, "0x%016llx\n",
(unsigned long long)sas_device_priv_data->sas_target->sas_address);
}
-static DEVICE_ATTR(sas_address, S_IRUGO, _ctl_device_sas_address_show, NULL);
+static DEVICE_ATTR_RO(sas_address);
/**
- * _ctl_device_handle_show - device handle
+ * sas_device_handle_show - device handle
* @dev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -3423,7 +3413,7 @@ static DEVICE_ATTR(sas_address, S_IRUGO, _ctl_device_sas_address_show, NULL);
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_device_handle_show(struct device *dev, struct device_attribute *attr,
+sas_device_handle_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct scsi_device *sdev = to_scsi_device(dev);
@@ -3432,10 +3422,10 @@ _ctl_device_handle_show(struct device *dev, struct device_attribute *attr,
return snprintf(buf, PAGE_SIZE, "0x%04x\n",
sas_device_priv_data->sas_target->handle);
}
-static DEVICE_ATTR(sas_device_handle, S_IRUGO, _ctl_device_handle_show, NULL);
+static DEVICE_ATTR_RO(sas_device_handle);
/**
- * _ctl_device_ncq_io_prio_show - send prioritized io commands to device
+ * sas_ncq_io_prio_show - send prioritized io commands to device
* @dev: pointer to embedded device
* @attr: ?
* @buf: the buffer returned
@@ -3443,7 +3433,7 @@ static DEVICE_ATTR(sas_device_handle, S_IRUGO, _ctl_device_handle_show, NULL);
* A sysfs 'read/write' sdev attribute, only works with SATA
*/
static ssize_t
-_ctl_device_ncq_prio_enable_show(struct device *dev,
+sas_ncq_prio_enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct scsi_device *sdev = to_scsi_device(dev);
@@ -3454,7 +3444,7 @@ _ctl_device_ncq_prio_enable_show(struct device *dev,
}
static ssize_t
-_ctl_device_ncq_prio_enable_store(struct device *dev,
+sas_ncq_prio_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -3471,9 +3461,7 @@ _ctl_device_ncq_prio_enable_store(struct device *dev,
sas_device_priv_data->ncq_prio_enable = ncq_prio_enable;
return strlen(buf);
}
-static DEVICE_ATTR(sas_ncq_prio_enable, S_IRUGO | S_IWUSR,
- _ctl_device_ncq_prio_enable_show,
- _ctl_device_ncq_prio_enable_store);
+static DEVICE_ATTR_RW(sas_ncq_prio_enable);
struct device_attribute *mpt3sas_dev_attrs[] = {
&dev_attr_sas_address,
diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
index 1ccfbc7eebe0..27c731a3fb49 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
@@ -113,22 +113,22 @@ MODULE_PARM_DESC(logging_level,
static ushort max_sectors = 0xFFFF;
-module_param(max_sectors, ushort, 0);
+module_param(max_sectors, ushort, 0444);
MODULE_PARM_DESC(max_sectors, "max sectors, range 64 to 32767 default=32767");
static int missing_delay[2] = {-1, -1};
-module_param_array(missing_delay, int, NULL, 0);
+module_param_array(missing_delay, int, NULL, 0444);
MODULE_PARM_DESC(missing_delay, " device missing delay , io missing delay");
/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
#define MPT3SAS_MAX_LUN (16895)
static u64 max_lun = MPT3SAS_MAX_LUN;
-module_param(max_lun, ullong, 0);
+module_param(max_lun, ullong, 0444);
MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
static ushort hbas_to_enumerate;
-module_param(hbas_to_enumerate, ushort, 0);
+module_param(hbas_to_enumerate, ushort, 0444);
MODULE_PARM_DESC(hbas_to_enumerate,
" 0 - enumerates both SAS 2.0 & SAS 3.0 generation HBAs\n \
1 - enumerates only SAS 2.0 generation HBAs\n \
@@ -142,17 +142,17 @@ MODULE_PARM_DESC(hbas_to_enumerate,
* Either bit can be set, or both
*/
static int diag_buffer_enable = -1;
-module_param(diag_buffer_enable, int, 0);
+module_param(diag_buffer_enable, int, 0444);
MODULE_PARM_DESC(diag_buffer_enable,
" post diag buffers (TRACE=1/SNAPSHOT=2/EXTENDED=4/default=0)");
static int disable_discovery = -1;
-module_param(disable_discovery, int, 0);
+module_param(disable_discovery, int, 0444);
MODULE_PARM_DESC(disable_discovery, " disable discovery ");
/* permit overriding the host protection capabilities mask (EEDP/T10 PI) */
static int prot_mask = -1;
-module_param(prot_mask, int, 0);
+module_param(prot_mask, int, 0444);
MODULE_PARM_DESC(prot_mask, " host protection capabilities mask, def=7 ");
@@ -2685,7 +2685,7 @@ mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, u64 lun,
int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN);
mpt3sas_scsih_set_tm_flag(ioc, handle);
init_completion(&ioc->tm_cmds.done);
- mpt3sas_base_put_smid_hi_priority(ioc, smid, msix_task);
+ ioc->put_smid_hi_priority(ioc, smid, msix_task);
wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
if (!(ioc->tm_cmds.status & MPT3_CMD_COMPLETE)) {
if (mpt3sas_base_check_cmd_timeout(ioc,
@@ -3659,7 +3659,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
mpi_request->MsgFlags = tr_method;
set_bit(handle, ioc->device_remove_in_progress);
- mpt3sas_base_put_smid_hi_priority(ioc, smid, 0);
+ ioc->put_smid_hi_priority(ioc, smid, 0);
mpt3sas_trigger_master(ioc, MASTER_TRIGGER_DEVICE_REMOVAL);
out:
@@ -3755,7 +3755,7 @@ _scsih_tm_tr_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
mpi_request->DevHandle = mpi_request_tm->DevHandle;
- mpt3sas_base_put_smid_default(ioc, smid_sas_ctrl);
+ ioc->put_smid_default(ioc, smid_sas_ctrl);
return _scsih_check_for_pending_tm(ioc, smid);
}
@@ -3881,7 +3881,7 @@ _scsih_tm_tr_volume_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
mpi_request->DevHandle = cpu_to_le16(handle);
mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
- mpt3sas_base_put_smid_hi_priority(ioc, smid, 0);
+ ioc->put_smid_hi_priority(ioc, smid, 0);
}
/**
@@ -3970,7 +3970,7 @@ _scsih_issue_delayed_event_ack(struct MPT3SAS_ADAPTER *ioc, u16 smid, U16 event,
ack_request->EventContext = event_context;
ack_request->VF_ID = 0; /* TODO */
ack_request->VP_ID = 0;
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
}
/**
@@ -4026,7 +4026,7 @@ _scsih_issue_delayed_sas_io_unit_ctrl(struct MPT3SAS_ADAPTER *ioc,
mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
mpi_request->DevHandle = cpu_to_le16(handle);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
}
/**
@@ -4734,12 +4734,12 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
if (sas_target_priv_data->flags & MPT_TARGET_FASTPATH_IO) {
mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len |
MPI25_SCSIIO_IOFLAGS_FAST_PATH);
- mpt3sas_base_put_smid_fast_path(ioc, smid, handle);
+ ioc->put_smid_fast_path(ioc, smid, handle);
} else
ioc->put_smid_scsi_io(ioc, smid,
le16_to_cpu(mpi_request->DevHandle));
} else
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
return 0;
out:
@@ -5210,6 +5210,7 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
((ioc_status & MPI2_IOCSTATUS_MASK)
!= MPI2_IOCSTATUS_SCSI_TASK_TERMINATED)) {
st->direct_io = 0;
+ st->scmd = scmd;
memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
mpi_request->DevHandle =
cpu_to_le16(sas_device_priv_data->sas_target->handle);
@@ -7601,7 +7602,7 @@ _scsih_ir_fastpath(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phys_disk_num)
handle, phys_disk_num));
init_completion(&ioc->scsih_cmds.done);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ);
if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) {
@@ -9633,7 +9634,7 @@ _scsih_ir_shutdown(struct MPT3SAS_ADAPTER *ioc)
if (!ioc->hide_ir_msg)
ioc_info(ioc, "IR shutdown (sending)\n");
init_completion(&ioc->scsih_cmds.done);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ);
if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) {
@@ -9670,6 +9671,7 @@ static void scsih_remove(struct pci_dev *pdev)
struct _pcie_device *pcie_device, *pcienext;
struct workqueue_struct *wq;
unsigned long flags;
+ Mpi2ConfigReply_t mpi_reply;
ioc->remove_host = 1;
@@ -9684,7 +9686,13 @@ static void scsih_remove(struct pci_dev *pdev)
spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
if (wq)
destroy_workqueue(wq);
-
+ /*
+ * Copy back the unmodified ioc page1. so that on next driver load,
+ * current modified changes on ioc page1 won't take effect.
+ */
+ if (ioc->is_aero_ioc)
+ mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply,
+ &ioc->ioc_pg1_copy);
/* release all the volumes */
_scsih_ir_shutdown(ioc);
sas_remove_host(shost);
@@ -9747,6 +9755,7 @@ scsih_shutdown(struct pci_dev *pdev)
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
struct workqueue_struct *wq;
unsigned long flags;
+ Mpi2ConfigReply_t mpi_reply;
ioc->remove_host = 1;
@@ -9761,6 +9770,13 @@ scsih_shutdown(struct pci_dev *pdev)
spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
if (wq)
destroy_workqueue(wq);
+ /*
+ * Copy back the unmodified ioc page1 so that on next driver load,
+ * current modified changes on ioc page1 won't take effect.
+ */
+ if (ioc->is_aero_ioc)
+ mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply,
+ &ioc->ioc_pg1_copy);
_scsih_ir_shutdown(ioc);
mpt3sas_base_detach(ioc);
diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c
index 60ae2d0feb2b..5324662751bf 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_transport.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c
@@ -367,7 +367,7 @@ _transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc,
ioc_info(ioc, "report_manufacture - send to sas_addr(0x%016llx)\n",
(u64)sas_address));
init_completion(&ioc->transport_cmds.done);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);
if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {
@@ -1139,7 +1139,7 @@ _transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc,
(u64)phy->identify.sas_address,
phy->number));
init_completion(&ioc->transport_cmds.done);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);
if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {
@@ -1434,7 +1434,7 @@ _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc,
(u64)phy->identify.sas_address,
phy->number, phy_operation));
init_completion(&ioc->transport_cmds.done);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);
if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {
@@ -1911,7 +1911,7 @@ _transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
ioc_info(ioc, "%s: sending smp request\n", __func__));
init_completion(&ioc->transport_cmds.done);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);
if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {
diff --git a/drivers/scsi/mvsas/Kconfig b/drivers/scsi/mvsas/Kconfig
index 78f7e20a0c1c..79812b80743b 100644
--- a/drivers/scsi/mvsas/Kconfig
+++ b/drivers/scsi/mvsas/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# Kernel configuration file for 88SE64XX/88SE94XX SAS/SATA driver.
#
@@ -5,25 +6,6 @@
# Copyright 2008 Marvell. <kewei@marvell.com>
# Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
#
-# This file is licensed under GPLv2.
-#
-# This file is part of the 88SE64XX/88SE94XX driver.
-#
-# The 88SE64XX/88SE94XX driver is free software; you can redistribute
-# it and/or modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; version 2 of the
-# License.
-#
-# The 88SE64XX/88SE94XX driver is distributed in the hope that it will be
-# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with 88SE64XX/88SE94XX Driver; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-#
-#
config SCSI_MVSAS
tristate "Marvell 88SE64XX/88SE94XX SAS/SATA support"
diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c
index 6dcae0e50018..3e0b8ebe257f 100644
--- a/drivers/scsi/mvsas/mv_sas.c
+++ b/drivers/scsi/mvsas/mv_sas.c
@@ -1193,7 +1193,7 @@ static int mvs_dev_found_notify(struct domain_device *dev, int lock)
mvi_device->dev_type = dev->dev_type;
mvi_device->mvi_info = mvi;
mvi_device->sas_device = dev;
- if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) {
+ if (parent_dev && dev_is_expander(parent_dev->dev_type)) {
int phy_id;
u8 phy_num = parent_dev->ex_dev.num_phys;
struct ex_phy *phy;
diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h
index b7d7ec435487..519edc796691 100644
--- a/drivers/scsi/mvsas/mv_sas.h
+++ b/drivers/scsi/mvsas/mv_sas.h
@@ -50,9 +50,6 @@ extern struct mvs_info *tgt_mvi;
extern const struct mvs_dispatch mvs_64xx_dispatch;
extern const struct mvs_dispatch mvs_94xx_dispatch;
-#define DEV_IS_EXPANDER(type) \
- ((type == SAS_EDGE_EXPANDER_DEVICE) || (type == SAS_FANOUT_EXPANDER_DEVICE))
-
#define bit(n) ((u64)1 << n)
#define for_each_phy(__lseq_mask, __mc, __lseq) \
diff --git a/drivers/scsi/mvumi.c b/drivers/scsi/mvumi.c
index 1fb6f6ca627e..8906aceda4c4 100644
--- a/drivers/scsi/mvumi.c
+++ b/drivers/scsi/mvumi.c
@@ -195,23 +195,22 @@ static int mvumi_make_sgl(struct mvumi_hba *mhba, struct scsi_cmnd *scmd,
unsigned int sgnum = scsi_sg_count(scmd);
dma_addr_t busaddr;
- sg = scsi_sglist(scmd);
- *sg_count = dma_map_sg(&mhba->pdev->dev, sg, sgnum,
+ *sg_count = dma_map_sg(&mhba->pdev->dev, scsi_sglist(scmd), sgnum,
scmd->sc_data_direction);
if (*sg_count > mhba->max_sge) {
dev_err(&mhba->pdev->dev,
"sg count[0x%x] is bigger than max sg[0x%x].\n",
*sg_count, mhba->max_sge);
- dma_unmap_sg(&mhba->pdev->dev, sg, sgnum,
+ dma_unmap_sg(&mhba->pdev->dev, scsi_sglist(scmd), sgnum,
scmd->sc_data_direction);
return -1;
}
- for (i = 0; i < *sg_count; i++) {
- busaddr = sg_dma_address(&sg[i]);
+ scsi_for_each_sg(scmd, sg, *sg_count, i) {
+ busaddr = sg_dma_address(sg);
m_sg->baseaddr_l = cpu_to_le32(lower_32_bits(busaddr));
m_sg->baseaddr_h = cpu_to_le32(upper_32_bits(busaddr));
m_sg->flags = 0;
- sgd_setsz(mhba, m_sg, cpu_to_le32(sg_dma_len(&sg[i])));
+ sgd_setsz(mhba, m_sg, cpu_to_le32(sg_dma_len(sg)));
if ((i + 1) == *sg_count)
m_sg->flags |= 1U << mhba->eot_flag;
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c
deleted file mode 100644
index 815bb4097c1b..000000000000
--- a/drivers/scsi/osst.c
+++ /dev/null
@@ -1,6108 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- SCSI Tape Driver for Linux version 1.1 and newer. See the accompanying
- file Documentation/scsi/st.txt for more information.
-
- History:
-
- OnStream SCSI Tape support (osst) cloned from st.c by
- Willem Riede (osst@riede.org) Feb 2000
- Fixes ... Kurt Garloff <garloff@suse.de> Mar 2000
-
- Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara.
- Contribution and ideas from several people including (in alphabetical
- order) Klaus Ehrenfried, Wolfgang Denk, Steve Hirsch, Andreas Koppenh"ofer,
- Michael Leodolter, Eyal Lebedinsky, J"org Weule, and Eric Youngdale.
-
- Copyright 1992 - 2002 Kai Makisara / 2000 - 2006 Willem Riede
- email osst@riede.org
-
- $Header: /cvsroot/osst/Driver/osst.c,v 1.73 2005/01/01 21:13:34 wriede Exp $
-
- Microscopic alterations - Rik Ling, 2000/12/21
- Last st.c sync: Tue Oct 15 22:01:04 2002 by makisara
- Some small formal changes - aeb, 950809
-*/
-
-static const char * cvsid = "$Id: osst.c,v 1.73 2005/01/01 21:13:34 wriede Exp $";
-static const char * osst_version = "0.99.4";
-
-/* The "failure to reconnect" firmware bug */
-#define OSST_FW_NEED_POLL_MIN 10601 /*(107A)*/
-#define OSST_FW_NEED_POLL_MAX 10704 /*(108D)*/
-#define OSST_FW_NEED_POLL(x,d) ((x) >= OSST_FW_NEED_POLL_MIN && (x) <= OSST_FW_NEED_POLL_MAX && d->host->this_id != 7)
-
-#include <linux/module.h>
-
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/sched/signal.h>
-#include <linux/proc_fs.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/mtio.h>
-#include <linux/ioctl.h>
-#include <linux/fcntl.h>
-#include <linux/spinlock.h>
-#include <linux/vmalloc.h>
-#include <linux/blkdev.h>
-#include <linux/moduleparam.h>
-#include <linux/delay.h>
-#include <linux/jiffies.h>
-#include <linux/mutex.h>
-#include <linux/uaccess.h>
-#include <asm/dma.h>
-
-/* The driver prints some debugging information on the console if DEBUG
- is defined and non-zero. */
-#define DEBUG 0
-
-/* The message level for the debug messages is currently set to KERN_NOTICE
- so that people can easily see the messages. Later when the debugging messages
- in the drivers are more widely classified, this may be changed to KERN_DEBUG. */
-#define OSST_DEB_MSG KERN_NOTICE
-
-#include <scsi/scsi.h>
-#include <scsi/scsi_dbg.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_driver.h>
-#include <scsi/scsi_eh.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_ioctl.h>
-
-#define ST_KILOBYTE 1024
-
-#include "st.h"
-#include "osst.h"
-#include "osst_options.h"
-#include "osst_detect.h"
-
-static DEFINE_MUTEX(osst_int_mutex);
-static int max_dev = 0;
-static int write_threshold_kbs = 0;
-static int max_sg_segs = 0;
-
-#ifdef MODULE
-MODULE_AUTHOR("Willem Riede");
-MODULE_DESCRIPTION("OnStream {DI-|FW-|SC-|USB}{30|50} Tape Driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_CHARDEV_MAJOR(OSST_MAJOR);
-MODULE_ALIAS_SCSI_DEVICE(TYPE_TAPE);
-
-module_param(max_dev, int, 0444);
-MODULE_PARM_DESC(max_dev, "Maximum number of OnStream Tape Drives to attach (4)");
-
-module_param(write_threshold_kbs, int, 0644);
-MODULE_PARM_DESC(write_threshold_kbs, "Asynchronous write threshold (KB; 32)");
-
-module_param(max_sg_segs, int, 0644);
-MODULE_PARM_DESC(max_sg_segs, "Maximum number of scatter/gather segments to use (9)");
-#else
-static struct osst_dev_parm {
- char *name;
- int *val;
-} parms[] __initdata = {
- { "max_dev", &max_dev },
- { "write_threshold_kbs", &write_threshold_kbs },
- { "max_sg_segs", &max_sg_segs }
-};
-#endif
-
-/* Some default definitions have been moved to osst_options.h */
-#define OSST_BUFFER_SIZE (OSST_BUFFER_BLOCKS * ST_KILOBYTE)
-#define OSST_WRITE_THRESHOLD (OSST_WRITE_THRESHOLD_BLOCKS * ST_KILOBYTE)
-
-/* The buffer size should fit into the 24 bits for length in the
- 6-byte SCSI read and write commands. */
-#if OSST_BUFFER_SIZE >= (2 << 24 - 1)
-#error "Buffer size should not exceed (2 << 24 - 1) bytes!"
-#endif
-
-#if DEBUG
-static int debugging = 1;
-/* uncomment define below to test error recovery */
-// #define OSST_INJECT_ERRORS 1
-#endif
-
-/* Do not retry! The drive firmware already retries when appropriate,
- and when it tries to tell us something, we had better listen... */
-#define MAX_RETRIES 0
-
-#define NO_TAPE NOT_READY
-
-#define OSST_WAIT_POSITION_COMPLETE (HZ > 200 ? HZ / 200 : 1)
-#define OSST_WAIT_WRITE_COMPLETE (HZ / 12)
-#define OSST_WAIT_LONG_WRITE_COMPLETE (HZ / 2)
-
-#define OSST_TIMEOUT (200 * HZ)
-#define OSST_LONG_TIMEOUT (1800 * HZ)
-
-#define TAPE_NR(x) (iminor(x) & ((1 << ST_MODE_SHIFT)-1))
-#define TAPE_MODE(x) ((iminor(x) & ST_MODE_MASK) >> ST_MODE_SHIFT)
-#define TAPE_REWIND(x) ((iminor(x) & 0x80) == 0)
-#define TAPE_IS_RAW(x) (TAPE_MODE(x) & (ST_NBR_MODES >> 1))
-
-/* Internal ioctl to set both density (uppermost 8 bits) and blocksize (lower
- 24 bits) */
-#define SET_DENS_AND_BLK 0x10001
-
-static int osst_buffer_size = OSST_BUFFER_SIZE;
-static int osst_write_threshold = OSST_WRITE_THRESHOLD;
-static int osst_max_sg_segs = OSST_MAX_SG;
-static int osst_max_dev = OSST_MAX_TAPES;
-static int osst_nr_dev;
-
-static struct osst_tape **os_scsi_tapes = NULL;
-static DEFINE_RWLOCK(os_scsi_tapes_lock);
-
-static int modes_defined = 0;
-
-static struct osst_buffer *new_tape_buffer(int, int, int);
-static int enlarge_buffer(struct osst_buffer *, int);
-static void normalize_buffer(struct osst_buffer *);
-static int append_to_buffer(const char __user *, struct osst_buffer *, int);
-static int from_buffer(struct osst_buffer *, char __user *, int);
-static int osst_zero_buffer_tail(struct osst_buffer *);
-static int osst_copy_to_buffer(struct osst_buffer *, unsigned char *);
-static int osst_copy_from_buffer(struct osst_buffer *, unsigned char *);
-
-static int osst_probe(struct device *);
-static int osst_remove(struct device *);
-
-static struct scsi_driver osst_template = {
- .gendrv = {
- .name = "osst",
- .owner = THIS_MODULE,
- .probe = osst_probe,
- .remove = osst_remove,
- }
-};
-
-static int osst_int_ioctl(struct osst_tape *STp, struct osst_request ** aSRpnt,
- unsigned int cmd_in, unsigned long arg);
-
-static int osst_set_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt, int frame, int skip);
-
-static int osst_get_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt);
-
-static int osst_flush_write_buffer(struct osst_tape *STp, struct osst_request ** aSRpnt);
-
-static int osst_write_error_recovery(struct osst_tape * STp, struct osst_request ** aSRpnt, int pending);
-
-static inline char *tape_name(struct osst_tape *tape)
-{
- return tape->drive->disk_name;
-}
-
-/* Routines that handle the interaction with mid-layer SCSI routines */
-
-
-/* Normalize Sense */
-static void osst_analyze_sense(struct osst_request *SRpnt, struct st_cmdstatus *s)
-{
- const u8 *ucp;
- const u8 *sense = SRpnt->sense;
-
- s->have_sense = scsi_normalize_sense(SRpnt->sense,
- SCSI_SENSE_BUFFERSIZE, &s->sense_hdr);
- s->flags = 0;
-
- if (s->have_sense) {
- s->deferred = 0;
- s->remainder_valid =
- scsi_get_sense_info_fld(sense, SCSI_SENSE_BUFFERSIZE, &s->uremainder64);
- switch (sense[0] & 0x7f) {
- case 0x71:
- s->deferred = 1;
- /* fall through */
- case 0x70:
- s->fixed_format = 1;
- s->flags = sense[2] & 0xe0;
- break;
- case 0x73:
- s->deferred = 1;
- /* fall through */
- case 0x72:
- s->fixed_format = 0;
- ucp = scsi_sense_desc_find(sense, SCSI_SENSE_BUFFERSIZE, 4);
- s->flags = ucp ? (ucp[3] & 0xe0) : 0;
- break;
- }
- }
-}
-
-/* Convert the result to success code */
-static int osst_chk_result(struct osst_tape * STp, struct osst_request * SRpnt)
-{
- char *name = tape_name(STp);
- int result = SRpnt->result;
- u8 * sense = SRpnt->sense, scode;
-#if DEBUG
- const char *stp;
-#endif
- struct st_cmdstatus *cmdstatp;
-
- if (!result)
- return 0;
-
- cmdstatp = &STp->buffer->cmdstat;
- osst_analyze_sense(SRpnt, cmdstatp);
-
- if (cmdstatp->have_sense)
- scode = STp->buffer->cmdstat.sense_hdr.sense_key;
- else
- scode = 0;
-#if DEBUG
- if (debugging) {
- printk(OSST_DEB_MSG "%s:D: Error: %x, cmd: %x %x %x %x %x %x\n",
- name, result,
- SRpnt->cmd[0], SRpnt->cmd[1], SRpnt->cmd[2],
- SRpnt->cmd[3], SRpnt->cmd[4], SRpnt->cmd[5]);
- if (scode) printk(OSST_DEB_MSG "%s:D: Sense: %02x, ASC: %02x, ASCQ: %02x\n",
- name, scode, sense[12], sense[13]);
- if (cmdstatp->have_sense)
- __scsi_print_sense(STp->device, name,
- SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
- }
- else
-#endif
- if (cmdstatp->have_sense && (
- scode != NO_SENSE &&
- scode != RECOVERED_ERROR &&
-/* scode != UNIT_ATTENTION && */
- scode != BLANK_CHECK &&
- scode != VOLUME_OVERFLOW &&
- SRpnt->cmd[0] != MODE_SENSE &&
- SRpnt->cmd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */
- if (cmdstatp->have_sense) {
- printk(KERN_WARNING "%s:W: Command with sense data:\n", name);
- __scsi_print_sense(STp->device, name,
- SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
- }
- else {
- static int notyetprinted = 1;
-
- printk(KERN_WARNING
- "%s:W: Warning %x (driver bt 0x%x, host bt 0x%x).\n",
- name, result, driver_byte(result),
- host_byte(result));
- if (notyetprinted) {
- notyetprinted = 0;
- printk(KERN_INFO
- "%s:I: This warning may be caused by your scsi controller,\n", name);
- printk(KERN_INFO
- "%s:I: it has been reported with some Buslogic cards.\n", name);
- }
- }
- }
- STp->pos_unknown |= STp->device->was_reset;
-
- if (cmdstatp->have_sense && scode == RECOVERED_ERROR) {
- STp->recover_count++;
- STp->recover_erreg++;
-#if DEBUG
- if (debugging) {
- if (SRpnt->cmd[0] == READ_6)
- stp = "read";
- else if (SRpnt->cmd[0] == WRITE_6)
- stp = "write";
- else
- stp = "ioctl";
- printk(OSST_DEB_MSG "%s:D: Recovered %s error (%d).\n", name, stp,
- STp->recover_count);
- }
-#endif
- if ((sense[2] & 0xe0) == 0)
- return 0;
- }
- return (-EIO);
-}
-
-
-/* Wakeup from interrupt */
-static void osst_end_async(struct request *req, blk_status_t status)
-{
- struct scsi_request *rq = scsi_req(req);
- struct osst_request *SRpnt = req->end_io_data;
- struct osst_tape *STp = SRpnt->stp;
- struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data;
-
- STp->buffer->cmdstat.midlevel_result = SRpnt->result = rq->result;
-#if DEBUG
- STp->write_pending = 0;
-#endif
- if (rq->sense_len)
- memcpy(SRpnt->sense, rq->sense, SCSI_SENSE_BUFFERSIZE);
- if (SRpnt->waiting)
- complete(SRpnt->waiting);
-
- if (SRpnt->bio) {
- kfree(mdata->pages);
- blk_rq_unmap_user(SRpnt->bio);
- }
-
- blk_put_request(req);
-}
-
-/* osst_request memory management */
-static struct osst_request *osst_allocate_request(void)
-{
- return kzalloc(sizeof(struct osst_request), GFP_KERNEL);
-}
-
-static void osst_release_request(struct osst_request *streq)
-{
- kfree(streq);
-}
-
-static int osst_execute(struct osst_request *SRpnt, const unsigned char *cmd,
- int cmd_len, int data_direction, void *buffer, unsigned bufflen,
- int use_sg, int timeout, int retries)
-{
- struct request *req;
- struct scsi_request *rq;
- struct page **pages = NULL;
- struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data;
-
- int err = 0;
- int write = (data_direction == DMA_TO_DEVICE);
-
- req = blk_get_request(SRpnt->stp->device->request_queue,
- write ? REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, 0);
- if (IS_ERR(req))
- return DRIVER_ERROR << 24;
-
- rq = scsi_req(req);
- req->rq_flags |= RQF_QUIET;
-
- SRpnt->bio = NULL;
-
- if (use_sg) {
- struct scatterlist *sg, *sgl = (struct scatterlist *)buffer;
- int i;
-
- pages = kcalloc(use_sg, sizeof(struct page *), GFP_KERNEL);
- if (!pages)
- goto free_req;
-
- for_each_sg(sgl, sg, use_sg, i)
- pages[i] = sg_page(sg);
-
- mdata->null_mapped = 1;
-
- mdata->page_order = get_order(sgl[0].length);
- mdata->nr_entries =
- DIV_ROUND_UP(bufflen, PAGE_SIZE << mdata->page_order);
- mdata->offset = 0;
-
- err = blk_rq_map_user(req->q, req, mdata, NULL, bufflen, GFP_KERNEL);
- if (err) {
- kfree(pages);
- goto free_req;
- }
- SRpnt->bio = req->bio;
- mdata->pages = pages;
-
- } else if (bufflen) {
- err = blk_rq_map_kern(req->q, req, buffer, bufflen, GFP_KERNEL);
- if (err)
- goto free_req;
- }
-
- rq->cmd_len = cmd_len;
- memset(rq->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */
- memcpy(rq->cmd, cmd, rq->cmd_len);
- req->timeout = timeout;
- rq->retries = retries;
- req->end_io_data = SRpnt;
-
- blk_execute_rq_nowait(req->q, NULL, req, 1, osst_end_async);
- return 0;
-free_req:
- blk_put_request(req);
- return DRIVER_ERROR << 24;
-}
-
-/* Do the scsi command. Waits until command performed if do_wait is true.
- Otherwise osst_write_behind_check() is used to check that the command
- has finished. */
-static struct osst_request * osst_do_scsi(struct osst_request *SRpnt, struct osst_tape *STp,
- unsigned char *cmd, int bytes, int direction, int timeout, int retries, int do_wait)
-{
- unsigned char *bp;
- unsigned short use_sg;
-#ifdef OSST_INJECT_ERRORS
- static int inject = 0;
- static int repeat = 0;
-#endif
- struct completion *waiting;
-
- /* if async, make sure there's no command outstanding */
- if (!do_wait && ((STp->buffer)->last_SRpnt)) {
- printk(KERN_ERR "%s: Async command already active.\n",
- tape_name(STp));
- if (signal_pending(current))
- (STp->buffer)->syscall_result = (-EINTR);
- else
- (STp->buffer)->syscall_result = (-EBUSY);
- return NULL;
- }
-
- if (SRpnt == NULL) {
- SRpnt = osst_allocate_request();
- if (SRpnt == NULL) {
- printk(KERN_ERR "%s: Can't allocate SCSI request.\n",
- tape_name(STp));
- if (signal_pending(current))
- (STp->buffer)->syscall_result = (-EINTR);
- else
- (STp->buffer)->syscall_result = (-EBUSY);
- return NULL;
- }
- SRpnt->stp = STp;
- }
-
- /* If async IO, set last_SRpnt. This ptr tells write_behind_check
- which IO is outstanding. It's nulled out when the IO completes. */
- if (!do_wait)
- (STp->buffer)->last_SRpnt = SRpnt;
-
- waiting = &STp->wait;
- init_completion(waiting);
- SRpnt->waiting = waiting;
-
- use_sg = (bytes > STp->buffer->sg[0].length) ? STp->buffer->use_sg : 0;
- if (use_sg) {
- bp = (char *)&(STp->buffer->sg[0]);
- if (STp->buffer->sg_segs < use_sg)
- use_sg = STp->buffer->sg_segs;
- }
- else
- bp = (STp->buffer)->b_data;
-
- memcpy(SRpnt->cmd, cmd, sizeof(SRpnt->cmd));
- STp->buffer->cmdstat.have_sense = 0;
- STp->buffer->syscall_result = 0;
-
- if (osst_execute(SRpnt, cmd, COMMAND_SIZE(cmd[0]), direction, bp, bytes,
- use_sg, timeout, retries))
- /* could not allocate the buffer or request was too large */
- (STp->buffer)->syscall_result = (-EBUSY);
- else if (do_wait) {
- wait_for_completion(waiting);
- SRpnt->waiting = NULL;
- STp->buffer->syscall_result = osst_chk_result(STp, SRpnt);
-#ifdef OSST_INJECT_ERRORS
- if (STp->buffer->syscall_result == 0 &&
- cmd[0] == READ_6 &&
- cmd[4] &&
- ( (++ inject % 83) == 29 ||
- (STp->first_frame_position == 240
- /* or STp->read_error_frame to fail again on the block calculated above */ &&
- ++repeat < 3))) {
- printk(OSST_DEB_MSG "%s:D: Injecting read error\n", tape_name(STp));
- STp->buffer->last_result_fatal = 1;
- }
-#endif
- }
- return SRpnt;
-}
-
-
-/* Handle the write-behind checking (downs the semaphore) */
-static void osst_write_behind_check(struct osst_tape *STp)
-{
- struct osst_buffer * STbuffer;
-
- STbuffer = STp->buffer;
-
-#if DEBUG
- if (STp->write_pending)
- STp->nbr_waits++;
- else
- STp->nbr_finished++;
-#endif
- wait_for_completion(&(STp->wait));
- STp->buffer->last_SRpnt->waiting = NULL;
-
- STp->buffer->syscall_result = osst_chk_result(STp, STp->buffer->last_SRpnt);
-
- if (STp->buffer->syscall_result)
- STp->buffer->syscall_result =
- osst_write_error_recovery(STp, &(STp->buffer->last_SRpnt), 1);
- else
- STp->first_frame_position++;
-
- osst_release_request(STp->buffer->last_SRpnt);
-
- if (STbuffer->writing < STbuffer->buffer_bytes)
- printk(KERN_WARNING "osst :A: write_behind_check: something left in buffer!\n");
-
- STbuffer->last_SRpnt = NULL;
- STbuffer->buffer_bytes -= STbuffer->writing;
- STbuffer->writing = 0;
-
- return;
-}
-
-
-
-/* Onstream specific Routines */
-/*
- * Initialize the OnStream AUX
- */
-static void osst_init_aux(struct osst_tape * STp, int frame_type, int frame_seq_number,
- int logical_blk_num, int blk_sz, int blk_cnt)
-{
- os_aux_t *aux = STp->buffer->aux;
- os_partition_t *par = &aux->partition;
- os_dat_t *dat = &aux->dat;
-
- if (STp->raw) return;
-
- memset(aux, 0, sizeof(*aux));
- aux->format_id = htonl(0);
- memcpy(aux->application_sig, "LIN4", 4);
- aux->hdwr = htonl(0);
- aux->frame_type = frame_type;
-
- switch (frame_type) {
- case OS_FRAME_TYPE_HEADER:
- aux->update_frame_cntr = htonl(STp->update_frame_cntr);
- par->partition_num = OS_CONFIG_PARTITION;
- par->par_desc_ver = OS_PARTITION_VERSION;
- par->wrt_pass_cntr = htons(0xffff);
- /* 0-4 = reserved, 5-9 = header, 2990-2994 = header, 2995-2999 = reserved */
- par->first_frame_ppos = htonl(0);
- par->last_frame_ppos = htonl(0xbb7);
- aux->frame_seq_num = htonl(0);
- aux->logical_blk_num_high = htonl(0);
- aux->logical_blk_num = htonl(0);
- aux->next_mark_ppos = htonl(STp->first_mark_ppos);
- break;
- case OS_FRAME_TYPE_DATA:
- case OS_FRAME_TYPE_MARKER:
- dat->dat_sz = 8;
- dat->reserved1 = 0;
- dat->entry_cnt = 1;
- dat->reserved3 = 0;
- dat->dat_list[0].blk_sz = htonl(blk_sz);
- dat->dat_list[0].blk_cnt = htons(blk_cnt);
- dat->dat_list[0].flags = frame_type==OS_FRAME_TYPE_MARKER?
- OS_DAT_FLAGS_MARK:OS_DAT_FLAGS_DATA;
- dat->dat_list[0].reserved = 0;
- /* fall through */
- case OS_FRAME_TYPE_EOD:
- aux->update_frame_cntr = htonl(0);
- par->partition_num = OS_DATA_PARTITION;
- par->par_desc_ver = OS_PARTITION_VERSION;
- par->wrt_pass_cntr = htons(STp->wrt_pass_cntr);
- par->first_frame_ppos = htonl(STp->first_data_ppos);
- par->last_frame_ppos = htonl(STp->capacity);
- aux->frame_seq_num = htonl(frame_seq_number);
- aux->logical_blk_num_high = htonl(0);
- aux->logical_blk_num = htonl(logical_blk_num);
- break;
- default: ; /* probably FILL */
- }
- aux->filemark_cnt = htonl(STp->filemark_cnt);
- aux->phys_fm = htonl(0xffffffff);
- aux->last_mark_ppos = htonl(STp->last_mark_ppos);
- aux->last_mark_lbn = htonl(STp->last_mark_lbn);
-}
-
-/*
- * Verify that we have the correct tape frame
- */
-static int osst_verify_frame(struct osst_tape * STp, int frame_seq_number, int quiet)
-{
- char * name = tape_name(STp);
- os_aux_t * aux = STp->buffer->aux;
- os_partition_t * par = &(aux->partition);
- struct st_partstat * STps = &(STp->ps[STp->partition]);
- unsigned int blk_cnt, blk_sz, i;
-
- if (STp->raw) {
- if (STp->buffer->syscall_result) {
- for (i=0; i < STp->buffer->sg_segs; i++)
- memset(page_address(sg_page(&STp->buffer->sg[i])),
- 0, STp->buffer->sg[i].length);
- strcpy(STp->buffer->b_data, "READ ERROR ON FRAME");
- } else
- STp->buffer->buffer_bytes = OS_FRAME_SIZE;
- return 1;
- }
- if (STp->buffer->syscall_result) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Skipping frame, read error\n", name);
-#endif
- return 0;
- }
- if (ntohl(aux->format_id) != 0) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Skipping frame, format_id %u\n", name, ntohl(aux->format_id));
-#endif
- goto err_out;
- }
- if (memcmp(aux->application_sig, STp->application_sig, 4) != 0 &&
- (memcmp(aux->application_sig, "LIN3", 4) != 0 || STp->linux_media_version != 4)) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Skipping frame, incorrect application signature\n", name);
-#endif
- goto err_out;
- }
- if (par->partition_num != OS_DATA_PARTITION) {
- if (!STp->linux_media || STp->linux_media_version != 2) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Skipping frame, partition num %d\n",
- name, par->partition_num);
-#endif
- goto err_out;
- }
- }
- if (par->par_desc_ver != OS_PARTITION_VERSION) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Skipping frame, partition version %d\n", name, par->par_desc_ver);
-#endif
- goto err_out;
- }
- if (ntohs(par->wrt_pass_cntr) != STp->wrt_pass_cntr) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Skipping frame, wrt_pass_cntr %d (expected %d)\n",
- name, ntohs(par->wrt_pass_cntr), STp->wrt_pass_cntr);
-#endif
- goto err_out;
- }
- if (aux->frame_type != OS_FRAME_TYPE_DATA &&
- aux->frame_type != OS_FRAME_TYPE_EOD &&
- aux->frame_type != OS_FRAME_TYPE_MARKER) {
- if (!quiet) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Skipping frame, frame type %x\n", name, aux->frame_type);
-#endif
- }
- goto err_out;
- }
- if (aux->frame_type == OS_FRAME_TYPE_EOD &&
- STp->first_frame_position < STp->eod_frame_ppos) {
- printk(KERN_INFO "%s:I: Skipping premature EOD frame %d\n", name,
- STp->first_frame_position);
- goto err_out;
- }
- if (frame_seq_number != -1 && ntohl(aux->frame_seq_num) != frame_seq_number) {
- if (!quiet) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Skipping frame, sequence number %u (expected %d)\n",
- name, ntohl(aux->frame_seq_num), frame_seq_number);
-#endif
- }
- goto err_out;
- }
- if (aux->frame_type == OS_FRAME_TYPE_MARKER) {
- STps->eof = ST_FM_HIT;
-
- i = ntohl(aux->filemark_cnt);
- if (STp->header_cache != NULL && i < OS_FM_TAB_MAX && (i > STp->filemark_cnt ||
- STp->first_frame_position - 1 != ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i]))) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: %s filemark %d at frame pos %d\n", name,
- STp->header_cache->dat_fm_tab.fm_tab_ent[i] == 0?"Learned":"Corrected",
- i, STp->first_frame_position - 1);
-#endif
- STp->header_cache->dat_fm_tab.fm_tab_ent[i] = htonl(STp->first_frame_position - 1);
- if (i >= STp->filemark_cnt)
- STp->filemark_cnt = i+1;
- }
- }
- if (aux->frame_type == OS_FRAME_TYPE_EOD) {
- STps->eof = ST_EOD_1;
- STp->frame_in_buffer = 1;
- }
- if (aux->frame_type == OS_FRAME_TYPE_DATA) {
- blk_cnt = ntohs(aux->dat.dat_list[0].blk_cnt);
- blk_sz = ntohl(aux->dat.dat_list[0].blk_sz);
- STp->buffer->buffer_bytes = blk_cnt * blk_sz;
- STp->buffer->read_pointer = 0;
- STp->frame_in_buffer = 1;
-
- /* See what block size was used to write file */
- if (STp->block_size != blk_sz && blk_sz > 0) {
- printk(KERN_INFO
- "%s:I: File was written with block size %d%c, currently %d%c, adjusted to match.\n",
- name, blk_sz<1024?blk_sz:blk_sz/1024,blk_sz<1024?'b':'k',
- STp->block_size<1024?STp->block_size:STp->block_size/1024,
- STp->block_size<1024?'b':'k');
- STp->block_size = blk_sz;
- STp->buffer->buffer_blocks = OS_DATA_SIZE / blk_sz;
- }
- STps->eof = ST_NOEOF;
- }
- STp->frame_seq_number = ntohl(aux->frame_seq_num);
- STp->logical_blk_num = ntohl(aux->logical_blk_num);
- return 1;
-
-err_out:
- if (STp->read_error_frame == 0)
- STp->read_error_frame = STp->first_frame_position - 1;
- return 0;
-}
-
-/*
- * Wait for the unit to become Ready
- */
-static int osst_wait_ready(struct osst_tape * STp, struct osst_request ** aSRpnt,
- unsigned timeout, int initial_delay)
-{
- unsigned char cmd[MAX_COMMAND_SIZE];
- struct osst_request * SRpnt;
- unsigned long startwait = jiffies;
-#if DEBUG
- int dbg = debugging;
- char * name = tape_name(STp);
-
- printk(OSST_DEB_MSG "%s:D: Reached onstream wait ready\n", name);
-#endif
-
- if (initial_delay > 0)
- msleep(jiffies_to_msecs(initial_delay));
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = TEST_UNIT_READY;
-
- SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
- *aSRpnt = SRpnt;
- if (!SRpnt) return (-EBUSY);
-
- while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) &&
- (( SRpnt->sense[2] == 2 && SRpnt->sense[12] == 4 &&
- (SRpnt->sense[13] == 1 || SRpnt->sense[13] == 8) ) ||
- ( SRpnt->sense[2] == 6 && SRpnt->sense[12] == 0x28 &&
- SRpnt->sense[13] == 0 ) )) {
-#if DEBUG
- if (debugging) {
- printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait ready\n", name);
- printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
- debugging = 0;
- }
-#endif
- msleep(100);
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = TEST_UNIT_READY;
-
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
- }
- *aSRpnt = SRpnt;
-#if DEBUG
- debugging = dbg;
-#endif
- if ( STp->buffer->syscall_result &&
- osst_write_error_recovery(STp, aSRpnt, 0) ) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait ready\n", name);
- printk(OSST_DEB_MSG "%s:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", name,
- STp->buffer->syscall_result, SRpnt->sense[0], SRpnt->sense[2],
- SRpnt->sense[12], SRpnt->sense[13]);
-#endif
- return (-EIO);
- }
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait ready\n", name);
-#endif
- return 0;
-}
-
-/*
- * Wait for a tape to be inserted in the unit
- */
-static int osst_wait_for_medium(struct osst_tape * STp, struct osst_request ** aSRpnt, unsigned timeout)
-{
- unsigned char cmd[MAX_COMMAND_SIZE];
- struct osst_request * SRpnt;
- unsigned long startwait = jiffies;
-#if DEBUG
- int dbg = debugging;
- char * name = tape_name(STp);
-
- printk(OSST_DEB_MSG "%s:D: Reached onstream wait for medium\n", name);
-#endif
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = TEST_UNIT_READY;
-
- SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
- *aSRpnt = SRpnt;
- if (!SRpnt) return (-EBUSY);
-
- while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) &&
- SRpnt->sense[2] == 2 && SRpnt->sense[12] == 0x3a && SRpnt->sense[13] == 0 ) {
-#if DEBUG
- if (debugging) {
- printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait medium\n", name);
- printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
- debugging = 0;
- }
-#endif
- msleep(100);
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = TEST_UNIT_READY;
-
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
- }
- *aSRpnt = SRpnt;
-#if DEBUG
- debugging = dbg;
-#endif
- if ( STp->buffer->syscall_result && SRpnt->sense[2] != 2 &&
- SRpnt->sense[12] != 4 && SRpnt->sense[13] == 1) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait medium\n", name);
- printk(OSST_DEB_MSG "%s:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", name,
- STp->buffer->syscall_result, SRpnt->sense[0], SRpnt->sense[2],
- SRpnt->sense[12], SRpnt->sense[13]);
-#endif
- return 0;
- }
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait medium\n", name);
-#endif
- return 1;
-}
-
-static int osst_position_tape_and_confirm(struct osst_tape * STp, struct osst_request ** aSRpnt, int frame)
-{
- int retval;
-
- osst_wait_ready(STp, aSRpnt, 15 * 60, 0); /* TODO - can this catch a write error? */
- retval = osst_set_frame_position(STp, aSRpnt, frame, 0);
- if (retval) return (retval);
- osst_wait_ready(STp, aSRpnt, 15 * 60, OSST_WAIT_POSITION_COMPLETE);
- return (osst_get_frame_position(STp, aSRpnt));
-}
-
-/*
- * Wait for write(s) to complete
- */
-static int osst_flush_drive_buffer(struct osst_tape * STp, struct osst_request ** aSRpnt)
-{
- unsigned char cmd[MAX_COMMAND_SIZE];
- struct osst_request * SRpnt;
- int result = 0;
- int delay = OSST_WAIT_WRITE_COMPLETE;
-#if DEBUG
- char * name = tape_name(STp);
-
- printk(OSST_DEB_MSG "%s:D: Reached onstream flush drive buffer (write filemark)\n", name);
-#endif
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = WRITE_FILEMARKS;
- cmd[1] = 1;
-
- SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
- *aSRpnt = SRpnt;
- if (!SRpnt) return (-EBUSY);
- if (STp->buffer->syscall_result) {
- if ((SRpnt->sense[2] & 0x0f) == 2 && SRpnt->sense[12] == 4) {
- if (SRpnt->sense[13] == 8) {
- delay = OSST_WAIT_LONG_WRITE_COMPLETE;
- }
- } else
- result = osst_write_error_recovery(STp, aSRpnt, 0);
- }
- result |= osst_wait_ready(STp, aSRpnt, 5 * 60, delay);
- STp->ps[STp->partition].rw = OS_WRITING_COMPLETE;
-
- return (result);
-}
-
-#define OSST_POLL_PER_SEC 10
-static int osst_wait_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int curr, int minlast, int to)
-{
- unsigned long startwait = jiffies;
- char * name = tape_name(STp);
-#if DEBUG
- char notyetprinted = 1;
-#endif
- if (minlast >= 0 && STp->ps[STp->partition].rw != ST_READING)
- printk(KERN_ERR "%s:A: Waiting for frame without having initialized read!\n", name);
-
- while (time_before (jiffies, startwait + to*HZ))
- {
- int result;
- result = osst_get_frame_position(STp, aSRpnt);
- if (result == -EIO)
- if ((result = osst_write_error_recovery(STp, aSRpnt, 0)) == 0)
- return 0; /* successful recovery leaves drive ready for frame */
- if (result < 0) break;
- if (STp->first_frame_position == curr &&
- ((minlast < 0 &&
- (signed)STp->last_frame_position > (signed)curr + minlast) ||
- (minlast >= 0 && STp->cur_frames > minlast)
- ) && result >= 0)
- {
-#if DEBUG
- if (debugging || time_after_eq(jiffies, startwait + 2*HZ/OSST_POLL_PER_SEC))
- printk (OSST_DEB_MSG
- "%s:D: Succ wait f fr %i (>%i): %i-%i %i (%i): %3li.%li s\n",
- name, curr, curr+minlast, STp->first_frame_position,
- STp->last_frame_position, STp->cur_frames,
- result, (jiffies-startwait)/HZ,
- (((jiffies-startwait)%HZ)*10)/HZ);
-#endif
- return 0;
- }
-#if DEBUG
- if (time_after_eq(jiffies, startwait + 2*HZ/OSST_POLL_PER_SEC) && notyetprinted)
- {
- printk (OSST_DEB_MSG "%s:D: Wait for frame %i (>%i): %i-%i %i (%i)\n",
- name, curr, curr+minlast, STp->first_frame_position,
- STp->last_frame_position, STp->cur_frames, result);
- notyetprinted--;
- }
-#endif
- msleep(1000 / OSST_POLL_PER_SEC);
- }
-#if DEBUG
- printk (OSST_DEB_MSG "%s:D: Fail wait f fr %i (>%i): %i-%i %i: %3li.%li s\n",
- name, curr, curr+minlast, STp->first_frame_position,
- STp->last_frame_position, STp->cur_frames,
- (jiffies-startwait)/HZ, (((jiffies-startwait)%HZ)*10)/HZ);
-#endif
- return -EBUSY;
-}
-
-static int osst_recover_wait_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int writing)
-{
- struct osst_request * SRpnt;
- unsigned char cmd[MAX_COMMAND_SIZE];
- unsigned long startwait = jiffies;
- int retval = 1;
- char * name = tape_name(STp);
-
- if (writing) {
- char mybuf[24];
- char * olddata = STp->buffer->b_data;
- int oldsize = STp->buffer->buffer_size;
-
- /* write zero fm then read pos - if shows write error, try to recover - if no progress, wait */
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = WRITE_FILEMARKS;
- cmd[1] = 1;
- SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout,
- MAX_RETRIES, 1);
-
- while (retval && time_before (jiffies, startwait + 5*60*HZ)) {
-
- if (STp->buffer->syscall_result && (SRpnt->sense[2] & 0x0f) != 2) {
-
- /* some failure - not just not-ready */
- retval = osst_write_error_recovery(STp, aSRpnt, 0);
- break;
- }
- schedule_timeout_interruptible(HZ / OSST_POLL_PER_SEC);
-
- STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = READ_POSITION;
-
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, 20, DMA_FROM_DEVICE, STp->timeout,
- MAX_RETRIES, 1);
-
- retval = ( STp->buffer->syscall_result || (STp->buffer)->b_data[15] > 25 );
- STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
- }
- if (retval)
- printk(KERN_ERR "%s:E: Device did not succeed to write buffered data\n", name);
- } else
- /* TODO - figure out which error conditions can be handled */
- if (STp->buffer->syscall_result)
- printk(KERN_WARNING
- "%s:W: Recover_wait_frame(read) cannot handle %02x:%02x:%02x\n", name,
- (*aSRpnt)->sense[ 2] & 0x0f,
- (*aSRpnt)->sense[12],
- (*aSRpnt)->sense[13]);
-
- return retval;
-}
-
-/*
- * Read the next OnStream tape frame at the current location
- */
-static int osst_read_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int timeout)
-{
- unsigned char cmd[MAX_COMMAND_SIZE];
- struct osst_request * SRpnt;
- int retval = 0;
-#if DEBUG
- os_aux_t * aux = STp->buffer->aux;
- char * name = tape_name(STp);
-#endif
-
- if (STp->poll)
- if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, 0, timeout))
- retval = osst_recover_wait_frame(STp, aSRpnt, 0);
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = READ_6;
- cmd[1] = 1;
- cmd[4] = 1;
-
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Reading frame from OnStream tape\n", name);
-#endif
- SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_FROM_DEVICE,
- STp->timeout, MAX_RETRIES, 1);
- *aSRpnt = SRpnt;
- if (!SRpnt)
- return (-EBUSY);
-
- if ((STp->buffer)->syscall_result) {
- retval = 1;
- if (STp->read_error_frame == 0) {
- STp->read_error_frame = STp->first_frame_position;
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Recording read error at %d\n", name, STp->read_error_frame);
-#endif
- }
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
- name,
- SRpnt->sense[0], SRpnt->sense[1],
- SRpnt->sense[2], SRpnt->sense[3],
- SRpnt->sense[4], SRpnt->sense[5],
- SRpnt->sense[6], SRpnt->sense[7]);
-#endif
- }
- else
- STp->first_frame_position++;
-#if DEBUG
- if (debugging) {
- char sig[8]; int i;
- for (i=0;i<4;i++)
- sig[i] = aux->application_sig[i]<32?'^':aux->application_sig[i];
- sig[4] = '\0';
- printk(OSST_DEB_MSG
- "%s:D: AUX: %s UpdFrCt#%d Wpass#%d %s FrSeq#%d LogBlk#%d Qty=%d Sz=%d\n", name, sig,
- ntohl(aux->update_frame_cntr), ntohs(aux->partition.wrt_pass_cntr),
- aux->frame_type==1?"EOD":aux->frame_type==2?"MARK":
- aux->frame_type==8?"HEADR":aux->frame_type==0x80?"DATA":"FILL",
- ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num),
- ntohs(aux->dat.dat_list[0].blk_cnt), ntohl(aux->dat.dat_list[0].blk_sz) );
- if (aux->frame_type==2)
- printk(OSST_DEB_MSG "%s:D: mark_cnt=%d, last_mark_ppos=%d, last_mark_lbn=%d\n", name,
- ntohl(aux->filemark_cnt), ntohl(aux->last_mark_ppos), ntohl(aux->last_mark_lbn));
- printk(OSST_DEB_MSG "%s:D: Exit read frame from OnStream tape with code %d\n", name, retval);
- }
-#endif
- return (retval);
-}
-
-static int osst_initiate_read(struct osst_tape * STp, struct osst_request ** aSRpnt)
-{
- struct st_partstat * STps = &(STp->ps[STp->partition]);
- struct osst_request * SRpnt ;
- unsigned char cmd[MAX_COMMAND_SIZE];
- int retval = 0;
- char * name = tape_name(STp);
-
- if (STps->rw != ST_READING) { /* Initialize read operation */
- if (STps->rw == ST_WRITING || STp->dirty) {
- STp->write_type = OS_WRITE_DATA;
- osst_flush_write_buffer(STp, aSRpnt);
- osst_flush_drive_buffer(STp, aSRpnt);
- }
- STps->rw = ST_READING;
- STp->frame_in_buffer = 0;
-
- /*
- * Issue a read 0 command to get the OnStream drive
- * read frames into its buffer.
- */
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = READ_6;
- cmd[1] = 1;
-
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Start Read Ahead on OnStream tape\n", name);
-#endif
- SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
- *aSRpnt = SRpnt;
- if ((retval = STp->buffer->syscall_result))
- printk(KERN_WARNING "%s:W: Error starting read ahead\n", name);
- }
-
- return retval;
-}
-
-static int osst_get_logical_frame(struct osst_tape * STp, struct osst_request ** aSRpnt,
- int frame_seq_number, int quiet)
-{
- struct st_partstat * STps = &(STp->ps[STp->partition]);
- char * name = tape_name(STp);
- int cnt = 0,
- bad = 0,
- past = 0,
- x,
- position;
-
- /*
- * If we want just any frame (-1) and there is a frame in the buffer, return it
- */
- if (frame_seq_number == -1 && STp->frame_in_buffer) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Frame %d still in buffer\n", name, STp->frame_seq_number);
-#endif
- return (STps->eof);
- }
- /*
- * Search and wait for the next logical tape frame
- */
- while (1) {
- if (cnt++ > 400) {
- printk(KERN_ERR "%s:E: Couldn't find logical frame %d, aborting\n",
- name, frame_seq_number);
- if (STp->read_error_frame) {
- osst_set_frame_position(STp, aSRpnt, STp->read_error_frame, 0);
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Repositioning tape to bad frame %d\n",
- name, STp->read_error_frame);
-#endif
- STp->read_error_frame = 0;
- STp->abort_count++;
- }
- return (-EIO);
- }
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Looking for frame %d, attempt %d\n",
- name, frame_seq_number, cnt);
-#endif
- if ( osst_initiate_read(STp, aSRpnt)
- || ( (!STp->frame_in_buffer) && osst_read_frame(STp, aSRpnt, 30) ) ) {
- if (STp->raw)
- return (-EIO);
- position = osst_get_frame_position(STp, aSRpnt);
- if (position >= 0xbae && position < 0xbb8)
- position = 0xbb8;
- else if (position > STp->eod_frame_ppos || ++bad == 10) {
- position = STp->read_error_frame - 1;
- bad = 0;
- }
- else {
- position += 29;
- cnt += 19;
- }
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Bad frame detected, positioning tape to block %d\n",
- name, position);
-#endif
- osst_set_frame_position(STp, aSRpnt, position, 0);
- continue;
- }
- if (osst_verify_frame(STp, frame_seq_number, quiet))
- break;
- if (osst_verify_frame(STp, -1, quiet)) {
- x = ntohl(STp->buffer->aux->frame_seq_num);
- if (STp->fast_open) {
- printk(KERN_WARNING
- "%s:W: Found logical frame %d instead of %d after fast open\n",
- name, x, frame_seq_number);
- STp->header_ok = 0;
- STp->read_error_frame = 0;
- return (-EIO);
- }
- if (x > frame_seq_number) {
- if (++past > 3) {
- /* positioning backwards did not bring us to the desired frame */
- position = STp->read_error_frame - 1;
- }
- else {
- position = osst_get_frame_position(STp, aSRpnt)
- + frame_seq_number - x - 1;
-
- if (STp->first_frame_position >= 3000 && position < 3000)
- position -= 10;
- }
-#if DEBUG
- printk(OSST_DEB_MSG
- "%s:D: Found logical frame %d while looking for %d: back up %d\n",
- name, x, frame_seq_number,
- STp->first_frame_position - position);
-#endif
- osst_set_frame_position(STp, aSRpnt, position, 0);
- cnt += 10;
- }
- else
- past = 0;
- }
- if (osst_get_frame_position(STp, aSRpnt) == 0xbaf) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Skipping config partition\n", name);
-#endif
- osst_set_frame_position(STp, aSRpnt, 0xbb8, 0);
- cnt--;
- }
- STp->frame_in_buffer = 0;
- }
- if (cnt > 1) {
- STp->recover_count++;
- STp->recover_erreg++;
- printk(KERN_WARNING "%s:I: Don't worry, Read error at position %d recovered\n",
- name, STp->read_error_frame);
- }
- STp->read_count++;
-
-#if DEBUG
- if (debugging || STps->eof)
- printk(OSST_DEB_MSG
- "%s:D: Exit get logical frame (%d=>%d) from OnStream tape with code %d\n",
- name, frame_seq_number, STp->frame_seq_number, STps->eof);
-#endif
- STp->fast_open = 0;
- STp->read_error_frame = 0;
- return (STps->eof);
-}
-
-static int osst_seek_logical_blk(struct osst_tape * STp, struct osst_request ** aSRpnt, int logical_blk_num)
-{
- struct st_partstat * STps = &(STp->ps[STp->partition]);
- char * name = tape_name(STp);
- int retries = 0;
- int frame_seq_estimate, ppos_estimate, move;
-
- if (logical_blk_num < 0) logical_blk_num = 0;
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Seeking logical block %d (now at %d, size %d%c)\n",
- name, logical_blk_num, STp->logical_blk_num,
- STp->block_size<1024?STp->block_size:STp->block_size/1024,
- STp->block_size<1024?'b':'k');
-#endif
- /* Do we know where we are? */
- if (STps->drv_block >= 0) {
- move = logical_blk_num - STp->logical_blk_num;
- if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1;
- move /= (OS_DATA_SIZE / STp->block_size);
- frame_seq_estimate = STp->frame_seq_number + move;
- } else
- frame_seq_estimate = logical_blk_num * STp->block_size / OS_DATA_SIZE;
-
- if (frame_seq_estimate < 2980) ppos_estimate = frame_seq_estimate + 10;
- else ppos_estimate = frame_seq_estimate + 20;
- while (++retries < 10) {
- if (ppos_estimate > STp->eod_frame_ppos-2) {
- frame_seq_estimate += STp->eod_frame_ppos - 2 - ppos_estimate;
- ppos_estimate = STp->eod_frame_ppos - 2;
- }
- if (frame_seq_estimate < 0) {
- frame_seq_estimate = 0;
- ppos_estimate = 10;
- }
- osst_set_frame_position(STp, aSRpnt, ppos_estimate, 0);
- if (osst_get_logical_frame(STp, aSRpnt, frame_seq_estimate, 1) >= 0) {
- /* we've located the estimated frame, now does it have our block? */
- if (logical_blk_num < STp->logical_blk_num ||
- logical_blk_num >= STp->logical_blk_num + ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt)) {
- if (STps->eof == ST_FM_HIT)
- move = logical_blk_num < STp->logical_blk_num? -2 : 1;
- else {
- move = logical_blk_num - STp->logical_blk_num;
- if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1;
- move /= (OS_DATA_SIZE / STp->block_size);
- }
- if (!move) move = logical_blk_num > STp->logical_blk_num ? 1 : -1;
-#if DEBUG
- printk(OSST_DEB_MSG
- "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d) move %d\n",
- name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate,
- STp->logical_blk_num, logical_blk_num, move);
-#endif
- frame_seq_estimate += move;
- ppos_estimate += move;
- continue;
- } else {
- STp->buffer->read_pointer = (logical_blk_num - STp->logical_blk_num) * STp->block_size;
- STp->buffer->buffer_bytes -= STp->buffer->read_pointer;
- STp->logical_blk_num = logical_blk_num;
-#if DEBUG
- printk(OSST_DEB_MSG
- "%s:D: Seek success at ppos %d fsq %d in_buf %d, bytes %d, ptr %d*%d\n",
- name, ppos_estimate, STp->frame_seq_number, STp->frame_in_buffer,
- STp->buffer->buffer_bytes, STp->buffer->read_pointer / STp->block_size,
- STp->block_size);
-#endif
- STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt);
- if (STps->eof == ST_FM_HIT) {
- STps->drv_file++;
- STps->drv_block = 0;
- } else {
- STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)?
- STp->logical_blk_num -
- (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0):
- -1;
- }
- STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF;
- return 0;
- }
- }
- if (osst_get_logical_frame(STp, aSRpnt, -1, 1) < 0)
- goto error;
- /* we are not yet at the estimated frame, adjust our estimate of its physical position */
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d)\n",
- name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate,
- STp->logical_blk_num, logical_blk_num);
-#endif
- if (frame_seq_estimate != STp->frame_seq_number)
- ppos_estimate += frame_seq_estimate - STp->frame_seq_number;
- else
- break;
- }
-error:
- printk(KERN_ERR "%s:E: Couldn't seek to logical block %d (at %d), %d retries\n",
- name, logical_blk_num, STp->logical_blk_num, retries);
- return (-EIO);
-}
-
-/* The values below are based on the OnStream frame payload size of 32K == 2**15,
- * that is, OSST_FRAME_SHIFT + OSST_SECTOR_SHIFT must be 15. With a minimum block
- * size of 512 bytes, we need to be able to resolve 32K/512 == 64 == 2**6 positions
- * inside each frame. Finally, OSST_SECTOR_MASK == 2**OSST_FRAME_SHIFT - 1.
- */
-#define OSST_FRAME_SHIFT 6
-#define OSST_SECTOR_SHIFT 9
-#define OSST_SECTOR_MASK 0x03F
-
-static int osst_get_sector(struct osst_tape * STp, struct osst_request ** aSRpnt)
-{
- int sector;
-#if DEBUG
- char * name = tape_name(STp);
-
- printk(OSST_DEB_MSG
- "%s:D: Positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, %cptr %d, eof %d\n",
- name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num,
- STp->ps[STp->partition].drv_file, STp->ps[STp->partition].drv_block,
- STp->ps[STp->partition].rw == ST_WRITING?'w':'r',
- STp->ps[STp->partition].rw == ST_WRITING?STp->buffer->buffer_bytes:
- STp->buffer->read_pointer, STp->ps[STp->partition].eof);
-#endif
- /* do we know where we are inside a file? */
- if (STp->ps[STp->partition].drv_block >= 0) {
- sector = (STp->frame_in_buffer ? STp->first_frame_position-1 :
- STp->first_frame_position) << OSST_FRAME_SHIFT;
- if (STp->ps[STp->partition].rw == ST_WRITING)
- sector |= (STp->buffer->buffer_bytes >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK;
- else
- sector |= (STp->buffer->read_pointer >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK;
- } else {
- sector = osst_get_frame_position(STp, aSRpnt);
- if (sector > 0)
- sector <<= OSST_FRAME_SHIFT;
- }
- return sector;
-}
-
-static int osst_seek_sector(struct osst_tape * STp, struct osst_request ** aSRpnt, int sector)
-{
- struct st_partstat * STps = &(STp->ps[STp->partition]);
- int frame = sector >> OSST_FRAME_SHIFT,
- offset = (sector & OSST_SECTOR_MASK) << OSST_SECTOR_SHIFT,
- r;
-#if DEBUG
- char * name = tape_name(STp);
-
- printk(OSST_DEB_MSG "%s:D: Seeking sector %d in frame %d at offset %d\n",
- name, sector, frame, offset);
-#endif
- if (frame < 0 || frame >= STp->capacity) return (-ENXIO);
-
- if (frame <= STp->first_data_ppos) {
- STp->frame_seq_number = STp->logical_blk_num = STps->drv_file = STps->drv_block = 0;
- return (osst_set_frame_position(STp, aSRpnt, frame, 0));
- }
- r = osst_set_frame_position(STp, aSRpnt, offset?frame:frame-1, 0);
- if (r < 0) return r;
-
- r = osst_get_logical_frame(STp, aSRpnt, -1, 1);
- if (r < 0) return r;
-
- if (osst_get_frame_position(STp, aSRpnt) != (offset?frame+1:frame)) return (-EIO);
-
- if (offset) {
- STp->logical_blk_num += offset / STp->block_size;
- STp->buffer->read_pointer = offset;
- STp->buffer->buffer_bytes -= offset;
- } else {
- STp->frame_seq_number++;
- STp->frame_in_buffer = 0;
- STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
- STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0;
- }
- STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt);
- if (STps->eof == ST_FM_HIT) {
- STps->drv_file++;
- STps->drv_block = 0;
- } else {
- STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)?
- STp->logical_blk_num -
- (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0):
- -1;
- }
- STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF;
-#if DEBUG
- printk(OSST_DEB_MSG
- "%s:D: Now positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, rptr %d, eof %d\n",
- name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num,
- STps->drv_file, STps->drv_block, STp->buffer->read_pointer, STps->eof);
-#endif
- return 0;
-}
-
-/*
- * Read back the drive's internal buffer contents, as a part
- * of the write error recovery mechanism for old OnStream
- * firmware revisions.
- * Precondition for this function to work: all frames in the
- * drive's buffer must be of one type (DATA, MARK or EOD)!
- */
-static int osst_read_back_buffer_and_rewrite(struct osst_tape * STp, struct osst_request ** aSRpnt,
- unsigned int frame, unsigned int skip, int pending)
-{
- struct osst_request * SRpnt = * aSRpnt;
- unsigned char * buffer, * p;
- unsigned char cmd[MAX_COMMAND_SIZE];
- int flag, new_frame, i;
- int nframes = STp->cur_frames;
- int blks_per_frame = ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
- int frame_seq_number = ntohl(STp->buffer->aux->frame_seq_num)
- - (nframes + pending - 1);
- int logical_blk_num = ntohl(STp->buffer->aux->logical_blk_num)
- - (nframes + pending - 1) * blks_per_frame;
- char * name = tape_name(STp);
- unsigned long startwait = jiffies;
-#if DEBUG
- int dbg = debugging;
-#endif
-
- if ((buffer = vmalloc(array_size((nframes + 1), OS_DATA_SIZE))) == NULL)
- return (-EIO);
-
- printk(KERN_INFO "%s:I: Reading back %d frames from drive buffer%s\n",
- name, nframes, pending?" and one that was pending":"");
-
- osst_copy_from_buffer(STp->buffer, (p = &buffer[nframes * OS_DATA_SIZE]));
-#if DEBUG
- if (pending && debugging)
- printk(OSST_DEB_MSG "%s:D: Pending frame %d (lblk %d), data %02x %02x %02x %02x\n",
- name, frame_seq_number + nframes,
- logical_blk_num + nframes * blks_per_frame,
- p[0], p[1], p[2], p[3]);
-#endif
- for (i = 0, p = buffer; i < nframes; i++, p += OS_DATA_SIZE) {
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = 0x3C; /* Buffer Read */
- cmd[1] = 6; /* Retrieve Faulty Block */
- cmd[7] = 32768 >> 8;
- cmd[8] = 32768 & 0xff;
-
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, DMA_FROM_DEVICE,
- STp->timeout, MAX_RETRIES, 1);
-
- if ((STp->buffer)->syscall_result || !SRpnt) {
- printk(KERN_ERR "%s:E: Failed to read frame back from OnStream buffer\n", name);
- vfree(buffer);
- *aSRpnt = SRpnt;
- return (-EIO);
- }
- osst_copy_from_buffer(STp->buffer, p);
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Read back logical frame %d, data %02x %02x %02x %02x\n",
- name, frame_seq_number + i, p[0], p[1], p[2], p[3]);
-#endif
- }
- *aSRpnt = SRpnt;
- osst_get_frame_position(STp, aSRpnt);
-
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Frames left in buffer: %d\n", name, STp->cur_frames);
-#endif
- /* Write synchronously so we can be sure we're OK again and don't have to recover recursively */
- /* In the header we don't actually re-write the frames that fail, just the ones after them */
-
- for (flag=1, new_frame=frame, p=buffer, i=0; i < nframes + pending; ) {
-
- if (flag) {
- if (STp->write_type == OS_WRITE_HEADER) {
- i += skip;
- p += skip * OS_DATA_SIZE;
- }
- else if (new_frame < 2990 && new_frame+skip+nframes+pending >= 2990)
- new_frame = 3000-i;
- else
- new_frame += skip;
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Position to frame %d, write fseq %d\n",
- name, new_frame+i, frame_seq_number+i);
-#endif
- osst_set_frame_position(STp, aSRpnt, new_frame + i, 0);
- osst_wait_ready(STp, aSRpnt, 60, OSST_WAIT_POSITION_COMPLETE);
- osst_get_frame_position(STp, aSRpnt);
- SRpnt = * aSRpnt;
-
- if (new_frame > frame + 1000) {
- printk(KERN_ERR "%s:E: Failed to find writable tape media\n", name);
- vfree(buffer);
- return (-EIO);
- }
- if ( i >= nframes + pending ) break;
- flag = 0;
- }
- osst_copy_to_buffer(STp->buffer, p);
- /*
- * IMPORTANT: for error recovery to work, _never_ queue frames with mixed frame type!
- */
- osst_init_aux(STp, STp->buffer->aux->frame_type, frame_seq_number+i,
- logical_blk_num + i*blks_per_frame,
- ntohl(STp->buffer->aux->dat.dat_list[0].blk_sz), blks_per_frame);
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = WRITE_6;
- cmd[1] = 1;
- cmd[4] = 1;
-
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG
- "%s:D: About to write frame %d, seq %d, lbn %d, data %02x %02x %02x %02x\n",
- name, new_frame+i, frame_seq_number+i, logical_blk_num + i*blks_per_frame,
- p[0], p[1], p[2], p[3]);
-#endif
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE,
- STp->timeout, MAX_RETRIES, 1);
-
- if (STp->buffer->syscall_result)
- flag = 1;
- else {
- p += OS_DATA_SIZE; i++;
-
- /* if we just sent the last frame, wait till all successfully written */
- if ( i == nframes + pending ) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Check re-write successful\n", name);
-#endif
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = WRITE_FILEMARKS;
- cmd[1] = 1;
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
- STp->timeout, MAX_RETRIES, 1);
-#if DEBUG
- if (debugging) {
- printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name);
- printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
- debugging = 0;
- }
-#endif
- flag = STp->buffer->syscall_result;
- while ( !flag && time_before(jiffies, startwait + 60*HZ) ) {
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = TEST_UNIT_READY;
-
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout,
- MAX_RETRIES, 1);
-
- if (SRpnt->sense[2] == 2 && SRpnt->sense[12] == 4 &&
- (SRpnt->sense[13] == 1 || SRpnt->sense[13] == 8)) {
- /* in the process of becoming ready */
- msleep(100);
- continue;
- }
- if (STp->buffer->syscall_result)
- flag = 1;
- break;
- }
-#if DEBUG
- debugging = dbg;
- printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name);
-#endif
- }
- }
- *aSRpnt = SRpnt;
- if (flag) {
- if ((SRpnt->sense[ 2] & 0x0f) == 13 &&
- SRpnt->sense[12] == 0 &&
- SRpnt->sense[13] == 2) {
- printk(KERN_ERR "%s:E: Volume overflow in write error recovery\n", name);
- vfree(buffer);
- return (-EIO); /* hit end of tape = fail */
- }
- i = ((SRpnt->sense[3] << 24) |
- (SRpnt->sense[4] << 16) |
- (SRpnt->sense[5] << 8) |
- SRpnt->sense[6] ) - new_frame;
- p = &buffer[i * OS_DATA_SIZE];
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Additional write error at %d\n", name, new_frame+i);
-#endif
- osst_get_frame_position(STp, aSRpnt);
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d, buffer = %d\n",
- name, STp->first_frame_position, STp->last_frame_position, STp->cur_frames);
-#endif
- }
- }
- if (flag) {
- /* error recovery did not successfully complete */
- printk(KERN_ERR "%s:D: Write error recovery failed in %s\n", name,
- STp->write_type == OS_WRITE_HEADER?"header":"body");
- }
- if (!pending)
- osst_copy_to_buffer(STp->buffer, p); /* so buffer content == at entry in all cases */
- vfree(buffer);
- return 0;
-}
-
-static int osst_reposition_and_retry(struct osst_tape * STp, struct osst_request ** aSRpnt,
- unsigned int frame, unsigned int skip, int pending)
-{
- unsigned char cmd[MAX_COMMAND_SIZE];
- struct osst_request * SRpnt;
- char * name = tape_name(STp);
- int expected = 0;
- int attempts = 1000 / skip;
- int flag = 1;
- unsigned long startwait = jiffies;
-#if DEBUG
- int dbg = debugging;
-#endif
-
- while (attempts && time_before(jiffies, startwait + 60*HZ)) {
- if (flag) {
-#if DEBUG
- debugging = dbg;
-#endif
- if (frame < 2990 && frame+skip+STp->cur_frames+pending >= 2990)
- frame = 3000-skip;
- expected = frame+skip+STp->cur_frames+pending;
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Position to fppos %d, re-write from fseq %d\n",
- name, frame+skip, STp->frame_seq_number-STp->cur_frames-pending);
-#endif
- osst_set_frame_position(STp, aSRpnt, frame + skip, 1);
- flag = 0;
- attempts--;
- schedule_timeout_interruptible(msecs_to_jiffies(100));
- }
- if (osst_get_frame_position(STp, aSRpnt) < 0) { /* additional write error */
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Addl error, host %d, tape %d, buffer %d\n",
- name, STp->first_frame_position,
- STp->last_frame_position, STp->cur_frames);
-#endif
- frame = STp->last_frame_position;
- flag = 1;
- continue;
- }
- if (pending && STp->cur_frames < 50) {
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = WRITE_6;
- cmd[1] = 1;
- cmd[4] = 1;
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: About to write pending fseq %d at fppos %d\n",
- name, STp->frame_seq_number-1, STp->first_frame_position);
-#endif
- SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE,
- STp->timeout, MAX_RETRIES, 1);
- *aSRpnt = SRpnt;
-
- if (STp->buffer->syscall_result) { /* additional write error */
- if ((SRpnt->sense[ 2] & 0x0f) == 13 &&
- SRpnt->sense[12] == 0 &&
- SRpnt->sense[13] == 2) {
- printk(KERN_ERR
- "%s:E: Volume overflow in write error recovery\n",
- name);
- break; /* hit end of tape = fail */
- }
- flag = 1;
- }
- else
- pending = 0;
-
- continue;
- }
- if (STp->cur_frames == 0) {
-#if DEBUG
- debugging = dbg;
- printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name);
-#endif
- if (STp->first_frame_position != expected) {
- printk(KERN_ERR "%s:A: Actual position %d - expected %d\n",
- name, STp->first_frame_position, expected);
- return (-EIO);
- }
- return 0;
- }
-#if DEBUG
- if (debugging) {
- printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name);
- printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
- debugging = 0;
- }
-#endif
- schedule_timeout_interruptible(msecs_to_jiffies(100));
- }
- printk(KERN_ERR "%s:E: Failed to find valid tape media\n", name);
-#if DEBUG
- debugging = dbg;
-#endif
- return (-EIO);
-}
-
-/*
- * Error recovery algorithm for the OnStream tape.
- */
-
-static int osst_write_error_recovery(struct osst_tape * STp, struct osst_request ** aSRpnt, int pending)
-{
- struct osst_request * SRpnt = * aSRpnt;
- struct st_partstat * STps = & STp->ps[STp->partition];
- char * name = tape_name(STp);
- int retval = 0;
- int rw_state;
- unsigned int frame, skip;
-
- rw_state = STps->rw;
-
- if ((SRpnt->sense[ 2] & 0x0f) != 3
- || SRpnt->sense[12] != 12
- || SRpnt->sense[13] != 0) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Write error recovery cannot handle %02x:%02x:%02x\n", name,
- SRpnt->sense[2], SRpnt->sense[12], SRpnt->sense[13]);
-#endif
- return (-EIO);
- }
- frame = (SRpnt->sense[3] << 24) |
- (SRpnt->sense[4] << 16) |
- (SRpnt->sense[5] << 8) |
- SRpnt->sense[6];
- skip = SRpnt->sense[9];
-
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Detected physical bad frame at %u, advised to skip %d\n", name, frame, skip);
-#endif
- osst_get_frame_position(STp, aSRpnt);
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d\n",
- name, STp->first_frame_position, STp->last_frame_position);
-#endif
- switch (STp->write_type) {
- case OS_WRITE_DATA:
- case OS_WRITE_EOD:
- case OS_WRITE_NEW_MARK:
- printk(KERN_WARNING
- "%s:I: Relocating %d buffered logical frames from position %u to %u\n",
- name, STp->cur_frames, frame, (frame + skip > 3000 && frame < 3000)?3000:frame + skip);
- if (STp->os_fw_rev >= 10600)
- retval = osst_reposition_and_retry(STp, aSRpnt, frame, skip, pending);
- else
- retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, skip, pending);
- printk(KERN_WARNING "%s:%s: %sWrite error%srecovered\n", name,
- retval?"E" :"I",
- retval?"" :"Don't worry, ",
- retval?" not ":" ");
- break;
- case OS_WRITE_LAST_MARK:
- printk(KERN_ERR "%s:E: Bad frame in update last marker, fatal\n", name);
- osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0);
- retval = -EIO;
- break;
- case OS_WRITE_HEADER:
- printk(KERN_WARNING "%s:I: Bad frame in header partition, skipped\n", name);
- retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, 1, pending);
- break;
- default:
- printk(KERN_INFO "%s:I: Bad frame in filler, ignored\n", name);
- osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0);
- }
- osst_get_frame_position(STp, aSRpnt);
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Positioning complete, cur_frames %d, pos %d, tape pos %d\n",
- name, STp->cur_frames, STp->first_frame_position, STp->last_frame_position);
- printk(OSST_DEB_MSG "%s:D: next logical frame to write: %d\n", name, STp->logical_blk_num);
-#endif
- if (retval == 0) {
- STp->recover_count++;
- STp->recover_erreg++;
- } else
- STp->abort_count++;
-
- STps->rw = rw_state;
- return retval;
-}
-
-static int osst_space_over_filemarks_backward(struct osst_tape * STp, struct osst_request ** aSRpnt,
- int mt_op, int mt_count)
-{
- char * name = tape_name(STp);
- int cnt;
- int last_mark_ppos = -1;
-
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_backwards %d %d\n", name, mt_op, mt_count);
-#endif
- if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_bwd\n", name);
-#endif
- return -EIO;
- }
- if (STp->linux_media_version >= 4) {
- /*
- * direct lookup in header filemark list
- */
- cnt = ntohl(STp->buffer->aux->filemark_cnt);
- if (STp->header_ok &&
- STp->header_cache != NULL &&
- (cnt - mt_count) >= 0 &&
- (cnt - mt_count) < OS_FM_TAB_MAX &&
- (cnt - mt_count) < STp->filemark_cnt &&
- STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] == STp->buffer->aux->last_mark_ppos)
-
- last_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt - mt_count]);
-#if DEBUG
- if (STp->header_cache == NULL || (cnt - mt_count) < 0 || (cnt - mt_count) >= OS_FM_TAB_MAX)
- printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name,
- STp->header_cache == NULL?"lack of header cache":"count out of range");
- else
- printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n",
- name, cnt,
- ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
- (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] ==
- STp->buffer->aux->last_mark_ppos))?"match":"error",
- mt_count, last_mark_ppos);
-#endif
- if (last_mark_ppos > 10 && last_mark_ppos < STp->eod_frame_ppos) {
- osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos);
- if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
-#if DEBUG
- printk(OSST_DEB_MSG
- "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
-#endif
- return (-EIO);
- }
- if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
- printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
- name, last_mark_ppos);
- return (-EIO);
- }
- goto found;
- }
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Reverting to scan filemark backwards\n", name);
-#endif
- }
- cnt = 0;
- while (cnt != mt_count) {
- last_mark_ppos = ntohl(STp->buffer->aux->last_mark_ppos);
- if (last_mark_ppos == -1)
- return (-EIO);
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Positioning to last mark at %d\n", name, last_mark_ppos);
-#endif
- osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos);
- cnt++;
- if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
-#endif
- return (-EIO);
- }
- if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
- printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
- name, last_mark_ppos);
- return (-EIO);
- }
- }
-found:
- if (mt_op == MTBSFM) {
- STp->frame_seq_number++;
- STp->frame_in_buffer = 0;
- STp->buffer->buffer_bytes = 0;
- STp->buffer->read_pointer = 0;
- STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
- }
- return 0;
-}
-
-/*
- * ADRL 1.1 compatible "slow" space filemarks fwd version
- *
- * Just scans for the filemark sequentially.
- */
-static int osst_space_over_filemarks_forward_slow(struct osst_tape * STp, struct osst_request ** aSRpnt,
- int mt_op, int mt_count)
-{
- int cnt = 0;
-#if DEBUG
- char * name = tape_name(STp);
-
- printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_slow %d %d\n", name, mt_op, mt_count);
-#endif
- if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name);
-#endif
- return (-EIO);
- }
- while (1) {
- if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
-#endif
- return (-EIO);
- }
- if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER)
- cnt++;
- if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name);
-#endif
- if (STp->first_frame_position > STp->eod_frame_ppos+1) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: EOD position corrected (%d=>%d)\n",
- name, STp->eod_frame_ppos, STp->first_frame_position-1);
-#endif
- STp->eod_frame_ppos = STp->first_frame_position-1;
- }
- return (-EIO);
- }
- if (cnt == mt_count)
- break;
- STp->frame_in_buffer = 0;
- }
- if (mt_op == MTFSF) {
- STp->frame_seq_number++;
- STp->frame_in_buffer = 0;
- STp->buffer->buffer_bytes = 0;
- STp->buffer->read_pointer = 0;
- STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
- }
- return 0;
-}
-
-/*
- * Fast linux specific version of OnStream FSF
- */
-static int osst_space_over_filemarks_forward_fast(struct osst_tape * STp, struct osst_request ** aSRpnt,
- int mt_op, int mt_count)
-{
- char * name = tape_name(STp);
- int cnt = 0,
- next_mark_ppos = -1;
-
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_fast %d %d\n", name, mt_op, mt_count);
-#endif
- if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name);
-#endif
- return (-EIO);
- }
-
- if (STp->linux_media_version >= 4) {
- /*
- * direct lookup in header filemark list
- */
- cnt = ntohl(STp->buffer->aux->filemark_cnt) - 1;
- if (STp->header_ok &&
- STp->header_cache != NULL &&
- (cnt + mt_count) < OS_FM_TAB_MAX &&
- (cnt + mt_count) < STp->filemark_cnt &&
- ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
- (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] == STp->buffer->aux->last_mark_ppos)))
-
- next_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt + mt_count]);
-#if DEBUG
- if (STp->header_cache == NULL || (cnt + mt_count) >= OS_FM_TAB_MAX)
- printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name,
- STp->header_cache == NULL?"lack of header cache":"count out of range");
- else
- printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n",
- name, cnt,
- ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
- (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] ==
- STp->buffer->aux->last_mark_ppos))?"match":"error",
- mt_count, next_mark_ppos);
-#endif
- if (next_mark_ppos <= 10 || next_mark_ppos > STp->eod_frame_ppos) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
-#endif
- return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
- } else {
- osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos);
- if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n",
- name);
-#endif
- return (-EIO);
- }
- if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
- printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
- name, next_mark_ppos);
- return (-EIO);
- }
- if (ntohl(STp->buffer->aux->filemark_cnt) != cnt + mt_count) {
- printk(KERN_WARNING "%s:W: Expected to find marker %d at ppos %d, not %d\n",
- name, cnt+mt_count, next_mark_ppos,
- ntohl(STp->buffer->aux->filemark_cnt));
- return (-EIO);
- }
- }
- } else {
- /*
- * Find nearest (usually previous) marker, then jump from marker to marker
- */
- while (1) {
- if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER)
- break;
- if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name);
-#endif
- return (-EIO);
- }
- if (ntohl(STp->buffer->aux->filemark_cnt) == 0) {
- if (STp->first_mark_ppos == -1) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
-#endif
- return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
- }
- osst_position_tape_and_confirm(STp, aSRpnt, STp->first_mark_ppos);
- if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
-#if DEBUG
- printk(OSST_DEB_MSG
- "%s:D: Couldn't get logical blk num in space_filemarks_fwd_fast\n",
- name);
-#endif
- return (-EIO);
- }
- if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
- printk(KERN_WARNING "%s:W: Expected to find filemark at %d\n",
- name, STp->first_mark_ppos);
- return (-EIO);
- }
- } else {
- if (osst_space_over_filemarks_backward(STp, aSRpnt, MTBSF, 1) < 0)
- return (-EIO);
- mt_count++;
- }
- }
- cnt++;
- while (cnt != mt_count) {
- next_mark_ppos = ntohl(STp->buffer->aux->next_mark_ppos);
- if (!next_mark_ppos || next_mark_ppos > STp->eod_frame_ppos) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
-#endif
- return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count - cnt);
- }
-#if DEBUG
- else printk(OSST_DEB_MSG "%s:D: Positioning to next mark at %d\n", name, next_mark_ppos);
-#endif
- osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos);
- cnt++;
- if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n",
- name);
-#endif
- return (-EIO);
- }
- if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
- printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
- name, next_mark_ppos);
- return (-EIO);
- }
- }
- }
- if (mt_op == MTFSF) {
- STp->frame_seq_number++;
- STp->frame_in_buffer = 0;
- STp->buffer->buffer_bytes = 0;
- STp->buffer->read_pointer = 0;
- STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
- }
- return 0;
-}
-
-/*
- * In debug mode, we want to see as many errors as possible
- * to test the error recovery mechanism.
- */
-#if DEBUG
-static void osst_set_retries(struct osst_tape * STp, struct osst_request ** aSRpnt, int retries)
-{
- unsigned char cmd[MAX_COMMAND_SIZE];
- struct osst_request * SRpnt = * aSRpnt;
- char * name = tape_name(STp);
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = MODE_SELECT;
- cmd[1] = 0x10;
- cmd[4] = NUMBER_RETRIES_PAGE_LENGTH + MODE_HEADER_LENGTH;
-
- (STp->buffer)->b_data[0] = cmd[4] - 1;
- (STp->buffer)->b_data[1] = 0; /* Medium Type - ignoring */
- (STp->buffer)->b_data[2] = 0; /* Reserved */
- (STp->buffer)->b_data[3] = 0; /* Block Descriptor Length */
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = NUMBER_RETRIES_PAGE | (1 << 7);
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 2;
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 4;
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = retries;
-
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Setting number of retries on OnStream tape to %d\n", name, retries);
-
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
- *aSRpnt = SRpnt;
-
- if ((STp->buffer)->syscall_result)
- printk (KERN_ERR "%s:D: Couldn't set retries to %d\n", name, retries);
-}
-#endif
-
-
-static int osst_write_filemark(struct osst_tape * STp, struct osst_request ** aSRpnt)
-{
- int result;
- int this_mark_ppos = STp->first_frame_position;
- int this_mark_lbn = STp->logical_blk_num;
-#if DEBUG
- char * name = tape_name(STp);
-#endif
-
- if (STp->raw) return 0;
-
- STp->write_type = OS_WRITE_NEW_MARK;
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Writing Filemark %i at fppos %d (fseq %d, lblk %d)\n",
- name, STp->filemark_cnt, this_mark_ppos, STp->frame_seq_number, this_mark_lbn);
-#endif
- STp->dirty = 1;
- result = osst_flush_write_buffer(STp, aSRpnt);
- result |= osst_flush_drive_buffer(STp, aSRpnt);
- STp->last_mark_ppos = this_mark_ppos;
- STp->last_mark_lbn = this_mark_lbn;
- if (STp->header_cache != NULL && STp->filemark_cnt < OS_FM_TAB_MAX)
- STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt] = htonl(this_mark_ppos);
- if (STp->filemark_cnt++ == 0)
- STp->first_mark_ppos = this_mark_ppos;
- return result;
-}
-
-static int osst_write_eod(struct osst_tape * STp, struct osst_request ** aSRpnt)
-{
- int result;
-#if DEBUG
- char * name = tape_name(STp);
-#endif
-
- if (STp->raw) return 0;
-
- STp->write_type = OS_WRITE_EOD;
- STp->eod_frame_ppos = STp->first_frame_position;
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Writing EOD at fppos %d (fseq %d, lblk %d)\n", name,
- STp->eod_frame_ppos, STp->frame_seq_number, STp->logical_blk_num);
-#endif
- STp->dirty = 1;
-
- result = osst_flush_write_buffer(STp, aSRpnt);
- result |= osst_flush_drive_buffer(STp, aSRpnt);
- STp->eod_frame_lfa = --(STp->frame_seq_number);
- return result;
-}
-
-static int osst_write_filler(struct osst_tape * STp, struct osst_request ** aSRpnt, int where, int count)
-{
- char * name = tape_name(STp);
-
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Reached onstream write filler group %d\n", name, where);
-#endif
- osst_wait_ready(STp, aSRpnt, 60 * 5, 0);
- osst_set_frame_position(STp, aSRpnt, where, 0);
- STp->write_type = OS_WRITE_FILLER;
- while (count--) {
- memcpy(STp->buffer->b_data, "Filler", 6);
- STp->buffer->buffer_bytes = 6;
- STp->dirty = 1;
- if (osst_flush_write_buffer(STp, aSRpnt)) {
- printk(KERN_INFO "%s:I: Couldn't write filler frame\n", name);
- return (-EIO);
- }
- }
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Exiting onstream write filler group\n", name);
-#endif
- return osst_flush_drive_buffer(STp, aSRpnt);
-}
-
-static int __osst_write_header(struct osst_tape * STp, struct osst_request ** aSRpnt, int where, int count)
-{
- char * name = tape_name(STp);
- int result;
-
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Reached onstream write header group %d\n", name, where);
-#endif
- osst_wait_ready(STp, aSRpnt, 60 * 5, 0);
- osst_set_frame_position(STp, aSRpnt, where, 0);
- STp->write_type = OS_WRITE_HEADER;
- while (count--) {
- osst_copy_to_buffer(STp->buffer, (unsigned char *)STp->header_cache);
- STp->buffer->buffer_bytes = sizeof(os_header_t);
- STp->dirty = 1;
- if (osst_flush_write_buffer(STp, aSRpnt)) {
- printk(KERN_INFO "%s:I: Couldn't write header frame\n", name);
- return (-EIO);
- }
- }
- result = osst_flush_drive_buffer(STp, aSRpnt);
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Write onstream header group %s\n", name, result?"failed":"done");
-#endif
- return result;
-}
-
-static int osst_write_header(struct osst_tape * STp, struct osst_request ** aSRpnt, int locate_eod)
-{
- os_header_t * header;
- int result;
- char * name = tape_name(STp);
-
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Writing tape header\n", name);
-#endif
- if (STp->raw) return 0;
-
- if (STp->header_cache == NULL) {
- if ((STp->header_cache = vmalloc(sizeof(os_header_t))) == NULL) {
- printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name);
- return (-ENOMEM);
- }
- memset(STp->header_cache, 0, sizeof(os_header_t));
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Allocated and cleared memory for header cache\n", name);
-#endif
- }
- if (STp->header_ok) STp->update_frame_cntr++;
- else STp->update_frame_cntr = 0;
-
- header = STp->header_cache;
- strcpy(header->ident_str, "ADR_SEQ");
- header->major_rev = 1;
- header->minor_rev = 4;
- header->ext_trk_tb_off = htons(17192);
- header->pt_par_num = 1;
- header->partition[0].partition_num = OS_DATA_PARTITION;
- header->partition[0].par_desc_ver = OS_PARTITION_VERSION;
- header->partition[0].wrt_pass_cntr = htons(STp->wrt_pass_cntr);
- header->partition[0].first_frame_ppos = htonl(STp->first_data_ppos);
- header->partition[0].last_frame_ppos = htonl(STp->capacity);
- header->partition[0].eod_frame_ppos = htonl(STp->eod_frame_ppos);
- header->cfg_col_width = htonl(20);
- header->dat_col_width = htonl(1500);
- header->qfa_col_width = htonl(0);
- header->ext_track_tb.nr_stream_part = 1;
- header->ext_track_tb.et_ent_sz = 32;
- header->ext_track_tb.dat_ext_trk_ey.et_part_num = 0;
- header->ext_track_tb.dat_ext_trk_ey.fmt = 1;
- header->ext_track_tb.dat_ext_trk_ey.fm_tab_off = htons(17736);
- header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi = 0;
- header->ext_track_tb.dat_ext_trk_ey.last_hlb = htonl(STp->eod_frame_lfa);
- header->ext_track_tb.dat_ext_trk_ey.last_pp = htonl(STp->eod_frame_ppos);
- header->dat_fm_tab.fm_part_num = 0;
- header->dat_fm_tab.fm_tab_ent_sz = 4;
- header->dat_fm_tab.fm_tab_ent_cnt = htons(STp->filemark_cnt<OS_FM_TAB_MAX?
- STp->filemark_cnt:OS_FM_TAB_MAX);
-
- result = __osst_write_header(STp, aSRpnt, 0xbae, 5);
- if (STp->update_frame_cntr == 0)
- osst_write_filler(STp, aSRpnt, 0xbb3, 5);
- result &= __osst_write_header(STp, aSRpnt, 5, 5);
-
- if (locate_eod) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Locating back to eod frame addr %d\n", name, STp->eod_frame_ppos);
-#endif
- osst_set_frame_position(STp, aSRpnt, STp->eod_frame_ppos, 0);
- }
- if (result)
- printk(KERN_ERR "%s:E: Write header failed\n", name);
- else {
- memcpy(STp->application_sig, "LIN4", 4);
- STp->linux_media = 1;
- STp->linux_media_version = 4;
- STp->header_ok = 1;
- }
- return result;
-}
-
-static int osst_reset_header(struct osst_tape * STp, struct osst_request ** aSRpnt)
-{
- if (STp->header_cache != NULL)
- memset(STp->header_cache, 0, sizeof(os_header_t));
-
- STp->logical_blk_num = STp->frame_seq_number = 0;
- STp->frame_in_buffer = 0;
- STp->eod_frame_ppos = STp->first_data_ppos = 0x0000000A;
- STp->filemark_cnt = 0;
- STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1;
- return osst_write_header(STp, aSRpnt, 1);
-}
-
-static int __osst_analyze_headers(struct osst_tape * STp, struct osst_request ** aSRpnt, int ppos)
-{
- char * name = tape_name(STp);
- os_header_t * header;
- os_aux_t * aux;
- char id_string[8];
- int linux_media_version,
- update_frame_cntr;
-
- if (STp->raw)
- return 1;
-
- if (ppos == 5 || ppos == 0xbae || STp->buffer->syscall_result) {
- if (osst_set_frame_position(STp, aSRpnt, ppos, 0))
- printk(KERN_WARNING "%s:W: Couldn't position tape\n", name);
- osst_wait_ready(STp, aSRpnt, 60 * 15, 0);
- if (osst_initiate_read (STp, aSRpnt)) {
- printk(KERN_WARNING "%s:W: Couldn't initiate read\n", name);
- return 0;
- }
- }
- if (osst_read_frame(STp, aSRpnt, 180)) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Couldn't read header frame\n", name);
-#endif
- return 0;
- }
- header = (os_header_t *) STp->buffer->b_data; /* warning: only first segment addressable */
- aux = STp->buffer->aux;
- if (aux->frame_type != OS_FRAME_TYPE_HEADER) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Skipping non-header frame (%d)\n", name, ppos);
-#endif
- return 0;
- }
- if (ntohl(aux->frame_seq_num) != 0 ||
- ntohl(aux->logical_blk_num) != 0 ||
- aux->partition.partition_num != OS_CONFIG_PARTITION ||
- ntohl(aux->partition.first_frame_ppos) != 0 ||
- ntohl(aux->partition.last_frame_ppos) != 0xbb7 ) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Invalid header frame (%d,%d,%d,%d,%d)\n", name,
- ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num),
- aux->partition.partition_num, ntohl(aux->partition.first_frame_ppos),
- ntohl(aux->partition.last_frame_ppos));
-#endif
- return 0;
- }
- if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0 &&
- strncmp(header->ident_str, "ADR-SEQ", 7) != 0) {
- strlcpy(id_string, header->ident_str, 8);
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Invalid header identification string %s\n", name, id_string);
-#endif
- return 0;
- }
- update_frame_cntr = ntohl(aux->update_frame_cntr);
- if (update_frame_cntr < STp->update_frame_cntr) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Skipping frame %d with update_frame_counter %d<%d\n",
- name, ppos, update_frame_cntr, STp->update_frame_cntr);
-#endif
- return 0;
- }
- if (header->major_rev != 1 || header->minor_rev != 4 ) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: %s revision %d.%d detected (1.4 supported)\n",
- name, (header->major_rev != 1 || header->minor_rev < 2 ||
- header->minor_rev > 4 )? "Invalid" : "Warning:",
- header->major_rev, header->minor_rev);
-#endif
- if (header->major_rev != 1 || header->minor_rev < 2 || header->minor_rev > 4)
- return 0;
- }
-#if DEBUG
- if (header->pt_par_num != 1)
- printk(KERN_INFO "%s:W: %d partitions defined, only one supported\n",
- name, header->pt_par_num);
-#endif
- memcpy(id_string, aux->application_sig, 4);
- id_string[4] = 0;
- if (memcmp(id_string, "LIN", 3) == 0) {
- STp->linux_media = 1;
- linux_media_version = id_string[3] - '0';
- if (linux_media_version != 4)
- printk(KERN_INFO "%s:I: Linux media version %d detected (current 4)\n",
- name, linux_media_version);
- } else {
- printk(KERN_WARNING "%s:W: Non Linux media detected (%s)\n", name, id_string);
- return 0;
- }
- if (linux_media_version < STp->linux_media_version) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Skipping frame %d with linux_media_version %d\n",
- name, ppos, linux_media_version);
-#endif
- return 0;
- }
- if (linux_media_version > STp->linux_media_version) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Frame %d sets linux_media_version to %d\n",
- name, ppos, linux_media_version);
-#endif
- memcpy(STp->application_sig, id_string, 5);
- STp->linux_media_version = linux_media_version;
- STp->update_frame_cntr = -1;
- }
- if (update_frame_cntr > STp->update_frame_cntr) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Frame %d sets update_frame_counter to %d\n",
- name, ppos, update_frame_cntr);
-#endif
- if (STp->header_cache == NULL) {
- if ((STp->header_cache = vmalloc(sizeof(os_header_t))) == NULL) {
- printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name);
- return 0;
- }
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Allocated memory for header cache\n", name);
-#endif
- }
- osst_copy_from_buffer(STp->buffer, (unsigned char *)STp->header_cache);
- header = STp->header_cache; /* further accesses from cached (full) copy */
-
- STp->wrt_pass_cntr = ntohs(header->partition[0].wrt_pass_cntr);
- STp->first_data_ppos = ntohl(header->partition[0].first_frame_ppos);
- STp->eod_frame_ppos = ntohl(header->partition[0].eod_frame_ppos);
- STp->eod_frame_lfa = ntohl(header->ext_track_tb.dat_ext_trk_ey.last_hlb);
- STp->filemark_cnt = ntohl(aux->filemark_cnt);
- STp->first_mark_ppos = ntohl(aux->next_mark_ppos);
- STp->last_mark_ppos = ntohl(aux->last_mark_ppos);
- STp->last_mark_lbn = ntohl(aux->last_mark_lbn);
- STp->update_frame_cntr = update_frame_cntr;
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Detected write pass %d, update frame counter %d, filemark counter %d\n",
- name, STp->wrt_pass_cntr, STp->update_frame_cntr, STp->filemark_cnt);
- printk(OSST_DEB_MSG "%s:D: first data frame on tape = %d, last = %d, eod frame = %d\n", name,
- STp->first_data_ppos,
- ntohl(header->partition[0].last_frame_ppos),
- ntohl(header->partition[0].eod_frame_ppos));
- printk(OSST_DEB_MSG "%s:D: first mark on tape = %d, last = %d, eod frame = %d\n",
- name, STp->first_mark_ppos, STp->last_mark_ppos, STp->eod_frame_ppos);
-#endif
- if (header->minor_rev < 4 && STp->linux_media_version == 4) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Moving filemark list to ADR 1.4 location\n", name);
-#endif
- memcpy((void *)header->dat_fm_tab.fm_tab_ent,
- (void *)header->old_filemark_list, sizeof(header->dat_fm_tab.fm_tab_ent));
- memset((void *)header->old_filemark_list, 0, sizeof(header->old_filemark_list));
- }
- if (header->minor_rev == 4 &&
- (header->ext_trk_tb_off != htons(17192) ||
- header->partition[0].partition_num != OS_DATA_PARTITION ||
- header->partition[0].par_desc_ver != OS_PARTITION_VERSION ||
- header->partition[0].last_frame_ppos != htonl(STp->capacity) ||
- header->cfg_col_width != htonl(20) ||
- header->dat_col_width != htonl(1500) ||
- header->qfa_col_width != htonl(0) ||
- header->ext_track_tb.nr_stream_part != 1 ||
- header->ext_track_tb.et_ent_sz != 32 ||
- header->ext_track_tb.dat_ext_trk_ey.et_part_num != OS_DATA_PARTITION ||
- header->ext_track_tb.dat_ext_trk_ey.fmt != 1 ||
- header->ext_track_tb.dat_ext_trk_ey.fm_tab_off != htons(17736) ||
- header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi != 0 ||
- header->ext_track_tb.dat_ext_trk_ey.last_pp != htonl(STp->eod_frame_ppos) ||
- header->dat_fm_tab.fm_part_num != OS_DATA_PARTITION ||
- header->dat_fm_tab.fm_tab_ent_sz != 4 ||
- header->dat_fm_tab.fm_tab_ent_cnt !=
- htons(STp->filemark_cnt<OS_FM_TAB_MAX?STp->filemark_cnt:OS_FM_TAB_MAX)))
- printk(KERN_WARNING "%s:W: Failed consistency check ADR 1.4 format\n", name);
-
- }
-
- return 1;
-}
-
-static int osst_analyze_headers(struct osst_tape * STp, struct osst_request ** aSRpnt)
-{
- int position, ppos;
- int first, last;
- int valid = 0;
- char * name = tape_name(STp);
-
- position = osst_get_frame_position(STp, aSRpnt);
-
- if (STp->raw) {
- STp->header_ok = STp->linux_media = 1;
- STp->linux_media_version = 0;
- return 1;
- }
- STp->header_ok = STp->linux_media = STp->linux_media_version = 0;
- STp->wrt_pass_cntr = STp->update_frame_cntr = -1;
- STp->eod_frame_ppos = STp->first_data_ppos = -1;
- STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1;
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Reading header\n", name);
-#endif
-
- /* optimization for speed - if we are positioned at ppos 10, read second group first */
- /* TODO try the ADR 1.1 locations for the second group if we have no valid one yet... */
-
- first = position==10?0xbae: 5;
- last = position==10?0xbb3:10;
-
- for (ppos = first; ppos < last; ppos++)
- if (__osst_analyze_headers(STp, aSRpnt, ppos))
- valid = 1;
-
- first = position==10? 5:0xbae;
- last = position==10?10:0xbb3;
-
- for (ppos = first; ppos < last; ppos++)
- if (__osst_analyze_headers(STp, aSRpnt, ppos))
- valid = 1;
-
- if (!valid) {
- printk(KERN_ERR "%s:E: Failed to find valid ADRL header, new media?\n", name);
- STp->eod_frame_ppos = STp->first_data_ppos = 0;
- osst_set_frame_position(STp, aSRpnt, 10, 0);
- return 0;
- }
- if (position <= STp->first_data_ppos) {
- position = STp->first_data_ppos;
- STp->ps[0].drv_file = STp->ps[0].drv_block = STp->frame_seq_number = STp->logical_blk_num = 0;
- }
- osst_set_frame_position(STp, aSRpnt, position, 0);
- STp->header_ok = 1;
-
- return 1;
-}
-
-static int osst_verify_position(struct osst_tape * STp, struct osst_request ** aSRpnt)
-{
- int frame_position = STp->first_frame_position;
- int frame_seq_numbr = STp->frame_seq_number;
- int logical_blk_num = STp->logical_blk_num;
- int halfway_frame = STp->frame_in_buffer;
- int read_pointer = STp->buffer->read_pointer;
- int prev_mark_ppos = -1;
- int actual_mark_ppos, i, n;
-#if DEBUG
- char * name = tape_name(STp);
-
- printk(OSST_DEB_MSG "%s:D: Verify that the tape is really the one we think before writing\n", name);
-#endif
- osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0);
- if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in verify_position\n", name);
-#endif
- return (-EIO);
- }
- if (STp->linux_media_version >= 4) {
- for (i=0; i<STp->filemark_cnt; i++)
- if ((n=ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i])) < frame_position)
- prev_mark_ppos = n;
- } else
- prev_mark_ppos = frame_position - 1; /* usually - we don't really know */
- actual_mark_ppos = STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER ?
- frame_position - 1 : ntohl(STp->buffer->aux->last_mark_ppos);
- if (frame_position != STp->first_frame_position ||
- frame_seq_numbr != STp->frame_seq_number + (halfway_frame?0:1) ||
- prev_mark_ppos != actual_mark_ppos ) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Block mismatch: fppos %d-%d, fseq %d-%d, mark %d-%d\n", name,
- STp->first_frame_position, frame_position,
- STp->frame_seq_number + (halfway_frame?0:1),
- frame_seq_numbr, actual_mark_ppos, prev_mark_ppos);
-#endif
- return (-EIO);
- }
- if (halfway_frame) {
- /* prepare buffer for append and rewrite on top of original */
- osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0);
- STp->buffer->buffer_bytes = read_pointer;
- STp->ps[STp->partition].rw = ST_WRITING;
- STp->dirty = 1;
- }
- STp->frame_in_buffer = halfway_frame;
- STp->frame_seq_number = frame_seq_numbr;
- STp->logical_blk_num = logical_blk_num;
- return 0;
-}
-
-/* Acc. to OnStream, the vers. numbering is the following:
- * X.XX for released versions (X=digit),
- * XXXY for unreleased versions (Y=letter)
- * Ordering 1.05 < 106A < 106B < ... < 106a < ... < 1.06
- * This fn makes monoton numbers out of this scheme ...
- */
-static unsigned int osst_parse_firmware_rev (const char * str)
-{
- if (str[1] == '.') {
- return (str[0]-'0')*10000
- +(str[2]-'0')*1000
- +(str[3]-'0')*100;
- } else {
- return (str[0]-'0')*10000
- +(str[1]-'0')*1000
- +(str[2]-'0')*100 - 100
- +(str[3]-'@');
- }
-}
-
-/*
- * Configure the OnStream SCII tape drive for default operation
- */
-static int osst_configure_onstream(struct osst_tape *STp, struct osst_request ** aSRpnt)
-{
- unsigned char cmd[MAX_COMMAND_SIZE];
- char * name = tape_name(STp);
- struct osst_request * SRpnt = * aSRpnt;
- osst_mode_parameter_header_t * header;
- osst_block_size_page_t * bs;
- osst_capabilities_page_t * cp;
- osst_tape_paramtr_page_t * prm;
- int drive_buffer_size;
-
- if (STp->ready != ST_READY) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Not Ready\n", name);
-#endif
- return (-EIO);
- }
-
- if (STp->os_fw_rev < 10600) {
- printk(KERN_INFO "%s:I: Old OnStream firmware revision detected (%s),\n", name, STp->device->rev);
- printk(KERN_INFO "%s:I: an upgrade to version 1.06 or above is recommended\n", name);
- }
-
- /*
- * Configure 32.5KB (data+aux) frame size.
- * Get the current frame size from the block size mode page
- */
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = MODE_SENSE;
- cmd[1] = 8;
- cmd[2] = BLOCK_SIZE_PAGE;
- cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH;
-
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
- if (SRpnt == NULL) {
-#if DEBUG
- printk(OSST_DEB_MSG "osst :D: Busy\n");
-#endif
- return (-EBUSY);
- }
- *aSRpnt = SRpnt;
- if ((STp->buffer)->syscall_result != 0) {
- printk (KERN_ERR "%s:E: Can't get tape block size mode page\n", name);
- return (-EIO);
- }
-
- header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
- bs = (osst_block_size_page_t *) ((STp->buffer)->b_data + sizeof(osst_mode_parameter_header_t) + header->bdl);
-
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: 32KB play back: %s\n", name, bs->play32 ? "Yes" : "No");
- printk(OSST_DEB_MSG "%s:D: 32.5KB play back: %s\n", name, bs->play32_5 ? "Yes" : "No");
- printk(OSST_DEB_MSG "%s:D: 32KB record: %s\n", name, bs->record32 ? "Yes" : "No");
- printk(OSST_DEB_MSG "%s:D: 32.5KB record: %s\n", name, bs->record32_5 ? "Yes" : "No");
-#endif
-
- /*
- * Configure default auto columns mode, 32.5KB transfer mode
- */
- bs->one = 1;
- bs->play32 = 0;
- bs->play32_5 = 1;
- bs->record32 = 0;
- bs->record32_5 = 1;
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = MODE_SELECT;
- cmd[1] = 0x10;
- cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH;
-
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
- *aSRpnt = SRpnt;
- if ((STp->buffer)->syscall_result != 0) {
- printk (KERN_ERR "%s:E: Couldn't set tape block size mode page\n", name);
- return (-EIO);
- }
-
-#if DEBUG
- printk(KERN_INFO "%s:D: Drive Block Size changed to 32.5K\n", name);
- /*
- * In debug mode, we want to see as many errors as possible
- * to test the error recovery mechanism.
- */
- osst_set_retries(STp, aSRpnt, 0);
- SRpnt = * aSRpnt;
-#endif
-
- /*
- * Set vendor name to 'LIN4' for "Linux support version 4".
- */
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = MODE_SELECT;
- cmd[1] = 0x10;
- cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH;
-
- header->mode_data_length = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH - 1;
- header->medium_type = 0; /* Medium Type - ignoring */
- header->dsp = 0; /* Reserved */
- header->bdl = 0; /* Block Descriptor Length */
-
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = VENDOR_IDENT_PAGE | (1 << 7);
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 6;
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 'L';
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 'I';
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 4] = 'N';
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 5] = '4';
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 6] = 0;
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 7] = 0;
-
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
- *aSRpnt = SRpnt;
-
- if ((STp->buffer)->syscall_result != 0) {
- printk (KERN_ERR "%s:E: Couldn't set vendor name to %s\n", name,
- (char *) ((STp->buffer)->b_data + MODE_HEADER_LENGTH + 2));
- return (-EIO);
- }
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = MODE_SENSE;
- cmd[1] = 8;
- cmd[2] = CAPABILITIES_PAGE;
- cmd[4] = CAPABILITIES_PAGE_LENGTH + MODE_HEADER_LENGTH;
-
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
- *aSRpnt = SRpnt;
-
- if ((STp->buffer)->syscall_result != 0) {
- printk (KERN_ERR "%s:E: Can't get capabilities page\n", name);
- return (-EIO);
- }
-
- header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
- cp = (osst_capabilities_page_t *) ((STp->buffer)->b_data +
- sizeof(osst_mode_parameter_header_t) + header->bdl);
-
- drive_buffer_size = ntohs(cp->buffer_size) / 2;
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = MODE_SENSE;
- cmd[1] = 8;
- cmd[2] = TAPE_PARAMTR_PAGE;
- cmd[4] = TAPE_PARAMTR_PAGE_LENGTH + MODE_HEADER_LENGTH;
-
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
- *aSRpnt = SRpnt;
-
- if ((STp->buffer)->syscall_result != 0) {
- printk (KERN_ERR "%s:E: Can't get tape parameter page\n", name);
- return (-EIO);
- }
-
- header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
- prm = (osst_tape_paramtr_page_t *) ((STp->buffer)->b_data +
- sizeof(osst_mode_parameter_header_t) + header->bdl);
-
- STp->density = prm->density;
- STp->capacity = ntohs(prm->segtrk) * ntohs(prm->trks);
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Density %d, tape length: %dMB, drive buffer size: %dKB\n",
- name, STp->density, STp->capacity / 32, drive_buffer_size);
-#endif
-
- return 0;
-
-}
-
-
-/* Step over EOF if it has been inadvertently crossed (ioctl not used because
- it messes up the block number). */
-static int cross_eof(struct osst_tape *STp, struct osst_request ** aSRpnt, int forward)
-{
- int result;
- char * name = tape_name(STp);
-
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Stepping over filemark %s.\n",
- name, forward ? "forward" : "backward");
-#endif
-
- if (forward) {
- /* assumes that the filemark is already read by the drive, so this is low cost */
- result = osst_space_over_filemarks_forward_slow(STp, aSRpnt, MTFSF, 1);
- }
- else
- /* assumes this is only called if we just read the filemark! */
- result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - 1);
-
- if (result < 0)
- printk(KERN_WARNING "%s:W: Stepping over filemark %s failed.\n",
- name, forward ? "forward" : "backward");
-
- return result;
-}
-
-
-/* Get the tape position. */
-
-static int osst_get_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt)
-{
- unsigned char scmd[MAX_COMMAND_SIZE];
- struct osst_request * SRpnt;
- int result = 0;
- char * name = tape_name(STp);
-
- /* KG: We want to be able to use it for checking Write Buffer availability
- * and thus don't want to risk to overwrite anything. Exchange buffers ... */
- char mybuf[24];
- char * olddata = STp->buffer->b_data;
- int oldsize = STp->buffer->buffer_size;
-
- if (STp->ready != ST_READY) return (-EIO);
-
- memset (scmd, 0, MAX_COMMAND_SIZE);
- scmd[0] = READ_POSITION;
-
- STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
- SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 20, DMA_FROM_DEVICE,
- STp->timeout, MAX_RETRIES, 1);
- if (!SRpnt) {
- STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
- return (-EBUSY);
- }
- *aSRpnt = SRpnt;
-
- if (STp->buffer->syscall_result)
- result = ((SRpnt->sense[2] & 0x0f) == 3) ? -EIO : -EINVAL; /* 3: Write Error */
-
- if (result == -EINVAL)
- printk(KERN_ERR "%s:E: Can't read tape position.\n", name);
- else {
- if (result == -EIO) { /* re-read position - this needs to preserve media errors */
- unsigned char mysense[16];
- memcpy (mysense, SRpnt->sense, 16);
- memset (scmd, 0, MAX_COMMAND_SIZE);
- scmd[0] = READ_POSITION;
- STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
- SRpnt = osst_do_scsi(SRpnt, STp, scmd, 20, DMA_FROM_DEVICE,
- STp->timeout, MAX_RETRIES, 1);
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Reread position, reason=[%02x:%02x:%02x], result=[%s%02x:%02x:%02x]\n",
- name, mysense[2], mysense[12], mysense[13], STp->buffer->syscall_result?"":"ok:",
- SRpnt->sense[2],SRpnt->sense[12],SRpnt->sense[13]);
-#endif
- if (!STp->buffer->syscall_result)
- memcpy (SRpnt->sense, mysense, 16);
- else
- printk(KERN_WARNING "%s:W: Double error in get position\n", name);
- }
- STp->first_frame_position = ((STp->buffer)->b_data[4] << 24)
- + ((STp->buffer)->b_data[5] << 16)
- + ((STp->buffer)->b_data[6] << 8)
- + (STp->buffer)->b_data[7];
- STp->last_frame_position = ((STp->buffer)->b_data[ 8] << 24)
- + ((STp->buffer)->b_data[ 9] << 16)
- + ((STp->buffer)->b_data[10] << 8)
- + (STp->buffer)->b_data[11];
- STp->cur_frames = (STp->buffer)->b_data[15];
-#if DEBUG
- if (debugging) {
- printk(OSST_DEB_MSG "%s:D: Drive Positions: host %d, tape %d%s, buffer %d\n", name,
- STp->first_frame_position, STp->last_frame_position,
- ((STp->buffer)->b_data[0]&0x80)?" (BOP)":
- ((STp->buffer)->b_data[0]&0x40)?" (EOP)":"",
- STp->cur_frames);
- }
-#endif
- if (STp->cur_frames == 0 && STp->first_frame_position != STp->last_frame_position) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Correcting read position %d, %d, %d\n", name,
- STp->first_frame_position, STp->last_frame_position, STp->cur_frames);
-#endif
- STp->first_frame_position = STp->last_frame_position;
- }
- }
- STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
-
- return (result == 0 ? STp->first_frame_position : result);
-}
-
-
-/* Set the tape block */
-static int osst_set_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt, int ppos, int skip)
-{
- unsigned char scmd[MAX_COMMAND_SIZE];
- struct osst_request * SRpnt;
- struct st_partstat * STps;
- int result = 0;
- int pp = (ppos == 3000 && !skip)? 0 : ppos;
- char * name = tape_name(STp);
-
- if (STp->ready != ST_READY) return (-EIO);
-
- STps = &(STp->ps[STp->partition]);
-
- if (ppos < 0 || ppos > STp->capacity) {
- printk(KERN_WARNING "%s:W: Reposition request %d out of range\n", name, ppos);
- pp = ppos = ppos < 0 ? 0 : (STp->capacity - 1);
- result = (-EINVAL);
- }
-
- do {
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Setting ppos to %d.\n", name, pp);
-#endif
- memset (scmd, 0, MAX_COMMAND_SIZE);
- scmd[0] = SEEK_10;
- scmd[1] = 1;
- scmd[3] = (pp >> 24);
- scmd[4] = (pp >> 16);
- scmd[5] = (pp >> 8);
- scmd[6] = pp;
- if (skip)
- scmd[9] = 0x80;
-
- SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 0, DMA_NONE, STp->long_timeout,
- MAX_RETRIES, 1);
- if (!SRpnt)
- return (-EBUSY);
- *aSRpnt = SRpnt;
-
- if ((STp->buffer)->syscall_result != 0) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: SEEK command from %d to %d failed.\n",
- name, STp->first_frame_position, pp);
-#endif
- result = (-EIO);
- }
- if (pp != ppos)
- osst_wait_ready(STp, aSRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE);
- } while ((pp != ppos) && (pp = ppos));
- STp->first_frame_position = STp->last_frame_position = ppos;
- STps->eof = ST_NOEOF;
- STps->at_sm = 0;
- STps->rw = ST_IDLE;
- STp->frame_in_buffer = 0;
- return result;
-}
-
-static int osst_write_trailer(struct osst_tape *STp, struct osst_request ** aSRpnt, int leave_at_EOT)
-{
- struct st_partstat * STps = &(STp->ps[STp->partition]);
- int result = 0;
-
- if (STp->write_type != OS_WRITE_NEW_MARK) {
- /* true unless the user wrote the filemark for us */
- result = osst_flush_drive_buffer(STp, aSRpnt);
- if (result < 0) goto out;
- result = osst_write_filemark(STp, aSRpnt);
- if (result < 0) goto out;
-
- if (STps->drv_file >= 0)
- STps->drv_file++ ;
- STps->drv_block = 0;
- }
- result = osst_write_eod(STp, aSRpnt);
- osst_write_header(STp, aSRpnt, leave_at_EOT);
-
- STps->eof = ST_FM;
-out:
- return result;
-}
-
-/* osst versions of st functions - augmented and stripped to suit OnStream only */
-
-/* Flush the write buffer (never need to write if variable blocksize). */
-static int osst_flush_write_buffer(struct osst_tape *STp, struct osst_request ** aSRpnt)
-{
- int offset, transfer, blks = 0;
- int result = 0;
- unsigned char cmd[MAX_COMMAND_SIZE];
- struct osst_request * SRpnt = *aSRpnt;
- struct st_partstat * STps;
- char * name = tape_name(STp);
-
- if ((STp->buffer)->writing) {
- if (SRpnt == (STp->buffer)->last_SRpnt)
-#if DEBUG
- { printk(OSST_DEB_MSG
- "%s:D: aSRpnt points to osst_request that write_behind_check will release -- cleared\n", name);
-#endif
- *aSRpnt = SRpnt = NULL;
-#if DEBUG
- } else if (SRpnt)
- printk(OSST_DEB_MSG
- "%s:D: aSRpnt does not point to osst_request that write_behind_check will release -- strange\n", name);
-#endif
- osst_write_behind_check(STp);
- if ((STp->buffer)->syscall_result) {
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Async write error (flush) %x.\n",
- name, (STp->buffer)->midlevel_result);
-#endif
- if ((STp->buffer)->midlevel_result == INT_MAX)
- return (-ENOSPC);
- return (-EIO);
- }
- }
-
- result = 0;
- if (STp->dirty == 1) {
-
- STp->write_count++;
- STps = &(STp->ps[STp->partition]);
- STps->rw = ST_WRITING;
- offset = STp->buffer->buffer_bytes;
- blks = (offset + STp->block_size - 1) / STp->block_size;
- transfer = OS_FRAME_SIZE;
-
- if (offset < OS_DATA_SIZE)
- osst_zero_buffer_tail(STp->buffer);
-
- if (STp->poll)
- if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -50, 120))
- result = osst_recover_wait_frame(STp, aSRpnt, 1);
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = WRITE_6;
- cmd[1] = 1;
- cmd[4] = 1;
-
- switch (STp->write_type) {
- case OS_WRITE_DATA:
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n",
- name, blks, STp->frame_seq_number,
- STp->logical_blk_num - blks, STp->logical_blk_num - 1);
-#endif
- osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++,
- STp->logical_blk_num - blks, STp->block_size, blks);
- break;
- case OS_WRITE_EOD:
- osst_init_aux(STp, OS_FRAME_TYPE_EOD, STp->frame_seq_number++,
- STp->logical_blk_num, 0, 0);
- break;
- case OS_WRITE_NEW_MARK:
- osst_init_aux(STp, OS_FRAME_TYPE_MARKER, STp->frame_seq_number++,
- STp->logical_blk_num++, 0, blks=1);
- break;
- case OS_WRITE_HEADER:
- osst_init_aux(STp, OS_FRAME_TYPE_HEADER, 0, 0, 0, blks=0);
- break;
- default: /* probably FILLER */
- osst_init_aux(STp, OS_FRAME_TYPE_FILL, 0, 0, 0, 0);
- }
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Flushing %d bytes, Transferring %d bytes in %d lblocks.\n",
- name, offset, transfer, blks);
-#endif
-
- SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, transfer, DMA_TO_DEVICE,
- STp->timeout, MAX_RETRIES, 1);
- *aSRpnt = SRpnt;
- if (!SRpnt)
- return (-EBUSY);
-
- if ((STp->buffer)->syscall_result != 0) {
-#if DEBUG
- printk(OSST_DEB_MSG
- "%s:D: write sense [0]=0x%02x [2]=%02x [12]=%02x [13]=%02x\n",
- name, SRpnt->sense[0], SRpnt->sense[2],
- SRpnt->sense[12], SRpnt->sense[13]);
-#endif
- if ((SRpnt->sense[0] & 0x70) == 0x70 &&
- (SRpnt->sense[2] & 0x40) && /* FIXME - SC-30 drive doesn't assert EOM bit */
- (SRpnt->sense[2] & 0x0f) == NO_SENSE) {
- STp->dirty = 0;
- (STp->buffer)->buffer_bytes = 0;
- result = (-ENOSPC);
- }
- else {
- if (osst_write_error_recovery(STp, aSRpnt, 1)) {
- printk(KERN_ERR "%s:E: Error on flush write.\n", name);
- result = (-EIO);
- }
- }
- STps->drv_block = (-1); /* FIXME - even if write recovery succeeds? */
- }
- else {
- STp->first_frame_position++;
- STp->dirty = 0;
- (STp->buffer)->buffer_bytes = 0;
- }
- }
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Exit flush write buffer with code %d\n", name, result);
-#endif
- return result;
-}
-
-
-/* Flush the tape buffer. The tape will be positioned correctly unless
- seek_next is true. */
-static int osst_flush_buffer(struct osst_tape * STp, struct osst_request ** aSRpnt, int seek_next)
-{
- struct st_partstat * STps;
- int backspace = 0, result = 0;
-#if DEBUG
- char * name = tape_name(STp);
-#endif
-
- /*
- * If there was a bus reset, block further access
- * to this device.
- */
- if( STp->pos_unknown)
- return (-EIO);
-
- if (STp->ready != ST_READY)
- return 0;
-
- STps = &(STp->ps[STp->partition]);
- if (STps->rw == ST_WRITING || STp->dirty) { /* Writing */
- STp->write_type = OS_WRITE_DATA;
- return osst_flush_write_buffer(STp, aSRpnt);
- }
- if (STp->block_size == 0)
- return 0;
-
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Reached flush (read) buffer\n", name);
-#endif
-
- if (!STp->can_bsr) {
- backspace = ((STp->buffer)->buffer_bytes + (STp->buffer)->read_pointer) / STp->block_size -
- ((STp->buffer)->read_pointer + STp->block_size - 1 ) / STp->block_size ;
- (STp->buffer)->buffer_bytes = 0;
- (STp->buffer)->read_pointer = 0;
- STp->frame_in_buffer = 0; /* FIXME is this relevant w. OSST? */
- }
-
- if (!seek_next) {
- if (STps->eof == ST_FM_HIT) {
- result = cross_eof(STp, aSRpnt, 0); /* Back over the EOF hit */
- if (!result)
- STps->eof = ST_NOEOF;
- else {
- if (STps->drv_file >= 0)
- STps->drv_file++;
- STps->drv_block = 0;
- }
- }
- if (!result && backspace > 0) /* TODO -- design and run a test case for this */
- result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - backspace);
- }
- else if (STps->eof == ST_FM_HIT) {
- if (STps->drv_file >= 0)
- STps->drv_file++;
- STps->drv_block = 0;
- STps->eof = ST_NOEOF;
- }
-
- return result;
-}
-
-static int osst_write_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int synchronous)
-{
- unsigned char cmd[MAX_COMMAND_SIZE];
- struct osst_request * SRpnt;
- int blks;
-#if DEBUG
- char * name = tape_name(STp);
-#endif
-
- if ((!STp-> raw) && (STp->first_frame_position == 0xbae)) { /* _must_ preserve buffer! */
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Reaching config partition.\n", name);
-#endif
- if (osst_flush_drive_buffer(STp, aSRpnt) < 0) {
- return (-EIO);
- }
- /* error recovery may have bumped us past the header partition */
- if (osst_get_frame_position(STp, aSRpnt) < 0xbb8) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Skipping over config partition.\n", name);
-#endif
- osst_position_tape_and_confirm(STp, aSRpnt, 0xbb8);
- }
- }
-
- if (STp->poll)
- if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -48, 120))
- if (osst_recover_wait_frame(STp, aSRpnt, 1))
- return (-EIO);
-
-// osst_build_stats(STp, &SRpnt);
-
- STp->ps[STp->partition].rw = ST_WRITING;
- STp->write_type = OS_WRITE_DATA;
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = WRITE_6;
- cmd[1] = 1;
- cmd[4] = 1; /* one frame at a time... */
- blks = STp->buffer->buffer_bytes / STp->block_size;
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n", name, blks,
- STp->frame_seq_number, STp->logical_blk_num - blks, STp->logical_blk_num - 1);
-#endif
- osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++,
- STp->logical_blk_num - blks, STp->block_size, blks);
-
-#if DEBUG
- if (!synchronous)
- STp->write_pending = 1;
-#endif
- SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE, STp->timeout,
- MAX_RETRIES, synchronous);
- if (!SRpnt)
- return (-EBUSY);
- *aSRpnt = SRpnt;
-
- if (synchronous) {
- if (STp->buffer->syscall_result != 0) {
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Error on write:\n", name);
-#endif
- if ((SRpnt->sense[0] & 0x70) == 0x70 &&
- (SRpnt->sense[2] & 0x40)) {
- if ((SRpnt->sense[2] & 0x0f) == VOLUME_OVERFLOW)
- return (-ENOSPC);
- }
- else {
- if (osst_write_error_recovery(STp, aSRpnt, 1))
- return (-EIO);
- }
- }
- else
- STp->first_frame_position++;
- }
-
- STp->write_count++;
-
- return 0;
-}
-
-/* Lock or unlock the drive door. Don't use when struct osst_request allocated. */
-static int do_door_lock(struct osst_tape * STp, int do_lock)
-{
- int retval;
-
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: %socking drive door.\n", tape_name(STp), do_lock ? "L" : "Unl");
-#endif
-
- retval = scsi_set_medium_removal(STp->device,
- do_lock ? SCSI_REMOVAL_PREVENT : SCSI_REMOVAL_ALLOW);
- if (!retval)
- STp->door_locked = do_lock ? ST_LOCKED_EXPLICIT : ST_UNLOCKED;
- else
- STp->door_locked = ST_LOCK_FAILS;
- return retval;
-}
-
-/* Set the internal state after reset */
-static void reset_state(struct osst_tape *STp)
-{
- int i;
- struct st_partstat *STps;
-
- STp->pos_unknown = 0;
- for (i = 0; i < ST_NBR_PARTITIONS; i++) {
- STps = &(STp->ps[i]);
- STps->rw = ST_IDLE;
- STps->eof = ST_NOEOF;
- STps->at_sm = 0;
- STps->last_block_valid = 0;
- STps->drv_block = -1;
- STps->drv_file = -1;
- }
-}
-
-
-/* Entry points to osst */
-
-/* Write command */
-static ssize_t osst_write(struct file * filp, const char __user * buf, size_t count, loff_t *ppos)
-{
- ssize_t total, retval = 0;
- ssize_t i, do_count, blks, transfer;
- int write_threshold;
- int doing_write = 0;
- const char __user * b_point;
- struct osst_request * SRpnt = NULL;
- struct st_modedef * STm;
- struct st_partstat * STps;
- struct osst_tape * STp = filp->private_data;
- char * name = tape_name(STp);
-
-
- if (mutex_lock_interruptible(&STp->lock))
- return (-ERESTARTSYS);
-
- /*
- * If we are in the middle of error recovery, don't let anyone
- * else try and use this device. Also, if error recovery fails, it
- * may try and take the device offline, in which case all further
- * access to the device is prohibited.
- */
- if( !scsi_block_when_processing_errors(STp->device) ) {
- retval = (-ENXIO);
- goto out;
- }
-
- if (STp->ready != ST_READY) {
- if (STp->ready == ST_NO_TAPE)
- retval = (-ENOMEDIUM);
- else
- retval = (-EIO);
- goto out;
- }
- STm = &(STp->modes[STp->current_mode]);
- if (!STm->defined) {
- retval = (-ENXIO);
- goto out;
- }
- if (count == 0)
- goto out;
-
- /*
- * If there was a bus reset, block further access
- * to this device.
- */
- if (STp->pos_unknown) {
- retval = (-EIO);
- goto out;
- }
-
-#if DEBUG
- if (!STp->in_use) {
- printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
- retval = (-EIO);
- goto out;
- }
-#endif
-
- if (STp->write_prot) {
- retval = (-EACCES);
- goto out;
- }
-
- /* Write must be integral number of blocks */
- if (STp->block_size != 0 && (count % STp->block_size) != 0) {
- printk(KERN_ERR "%s:E: Write (%zd bytes) not multiple of tape block size (%d%c).\n",
- name, count, STp->block_size<1024?
- STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k');
- retval = (-EINVAL);
- goto out;
- }
-
- if (STp->first_frame_position >= STp->capacity - OSST_EOM_RESERVE) {
- printk(KERN_ERR "%s:E: Write truncated at EOM early warning (frame %d).\n",
- name, STp->first_frame_position);
- retval = (-ENOSPC);
- goto out;
- }
-
- if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1))
- STp->door_locked = ST_LOCKED_AUTO;
-
- STps = &(STp->ps[STp->partition]);
-
- if (STps->rw == ST_READING) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Switching from read to write at file %d, block %d\n", name,
- STps->drv_file, STps->drv_block);
-#endif
- retval = osst_flush_buffer(STp, &SRpnt, 0);
- if (retval)
- goto out;
- STps->rw = ST_IDLE;
- }
- if (STps->rw != ST_WRITING) {
- /* Are we totally rewriting this tape? */
- if (!STp->header_ok ||
- (STp->first_frame_position == STp->first_data_ppos && STps->drv_block < 0) ||
- (STps->drv_file == 0 && STps->drv_block == 0)) {
- STp->wrt_pass_cntr++;
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Allocating next write pass counter: %d\n",
- name, STp->wrt_pass_cntr);
-#endif
- osst_reset_header(STp, &SRpnt);
- STps->drv_file = STps->drv_block = 0;
- }
- /* Do we know where we'll be writing on the tape? */
- else {
- if ((STp->fast_open && osst_verify_position(STp, &SRpnt)) ||
- STps->drv_file < 0 || STps->drv_block < 0) {
- if (STp->first_frame_position == STp->eod_frame_ppos) { /* at EOD */
- STps->drv_file = STp->filemark_cnt;
- STps->drv_block = 0;
- }
- else {
- /* We have no idea where the tape is positioned - give up */
-#if DEBUG
- printk(OSST_DEB_MSG
- "%s:D: Cannot write at indeterminate position.\n", name);
-#endif
- retval = (-EIO);
- goto out;
- }
- }
- if ((STps->drv_file + STps->drv_block) > 0 && STps->drv_file < STp->filemark_cnt) {
- STp->filemark_cnt = STps->drv_file;
- STp->last_mark_ppos =
- ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt-1]);
- printk(KERN_WARNING
- "%s:W: Overwriting file %d with old write pass counter %d\n",
- name, STps->drv_file, STp->wrt_pass_cntr);
- printk(KERN_WARNING
- "%s:W: may lead to stale data being accepted on reading back!\n",
- name);
-#if DEBUG
- printk(OSST_DEB_MSG
- "%s:D: resetting filemark count to %d and last mark ppos,lbn to %d,%d\n",
- name, STp->filemark_cnt, STp->last_mark_ppos, STp->last_mark_lbn);
-#endif
- }
- }
- STp->fast_open = 0;
- }
- if (!STp->header_ok) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Write cannot proceed without valid headers\n", name);
-#endif
- retval = (-EIO);
- goto out;
- }
-
- if ((STp->buffer)->writing) {
-if (SRpnt) printk(KERN_ERR "%s:A: Not supposed to have SRpnt at line %d\n", name, __LINE__);
- osst_write_behind_check(STp);
- if ((STp->buffer)->syscall_result) {
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Async write error (write) %x.\n", name,
- (STp->buffer)->midlevel_result);
-#endif
- if ((STp->buffer)->midlevel_result == INT_MAX)
- STps->eof = ST_EOM_OK;
- else
- STps->eof = ST_EOM_ERROR;
- }
- }
- if (STps->eof == ST_EOM_OK) {
- retval = (-ENOSPC);
- goto out;
- }
- else if (STps->eof == ST_EOM_ERROR) {
- retval = (-EIO);
- goto out;
- }
-
- /* Check the buffer readability in cases where copy_user might catch
- the problems after some tape movement. */
- if ((copy_from_user(&i, buf, 1) != 0 ||
- copy_from_user(&i, buf + count - 1, 1) != 0)) {
- retval = (-EFAULT);
- goto out;
- }
-
- if (!STm->do_buffer_writes) {
- write_threshold = 1;
- }
- else
- write_threshold = (STp->buffer)->buffer_blocks * STp->block_size;
- if (!STm->do_async_writes)
- write_threshold--;
-
- total = count;
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Writing %d bytes to file %d block %d lblk %d fseq %d fppos %d\n",
- name, (int) count, STps->drv_file, STps->drv_block,
- STp->logical_blk_num, STp->frame_seq_number, STp->first_frame_position);
-#endif
- b_point = buf;
- while ((STp->buffer)->buffer_bytes + count > write_threshold)
- {
- doing_write = 1;
- do_count = (STp->buffer)->buffer_blocks * STp->block_size -
- (STp->buffer)->buffer_bytes;
- if (do_count > count)
- do_count = count;
-
- i = append_to_buffer(b_point, STp->buffer, do_count);
- if (i) {
- retval = i;
- goto out;
- }
-
- blks = do_count / STp->block_size;
- STp->logical_blk_num += blks; /* logical_blk_num is incremented as data is moved from user */
-
- i = osst_write_frame(STp, &SRpnt, 1);
-
- if (i == (-ENOSPC)) {
- transfer = STp->buffer->writing; /* FIXME -- check this logic */
- if (transfer <= do_count) {
- *ppos += do_count - transfer;
- count -= do_count - transfer;
- if (STps->drv_block >= 0) {
- STps->drv_block += (do_count - transfer) / STp->block_size;
- }
- STps->eof = ST_EOM_OK;
- retval = (-ENOSPC); /* EOM within current request */
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: EOM with %d bytes unwritten.\n",
- name, (int) transfer);
-#endif
- }
- else {
- STps->eof = ST_EOM_ERROR;
- STps->drv_block = (-1); /* Too cautious? */
- retval = (-EIO); /* EOM for old data */
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: EOM with lost data.\n", name);
-#endif
- }
- }
- else
- retval = i;
-
- if (retval < 0) {
- if (SRpnt != NULL) {
- osst_release_request(SRpnt);
- SRpnt = NULL;
- }
- STp->buffer->buffer_bytes = 0;
- STp->dirty = 0;
- if (count < total)
- retval = total - count;
- goto out;
- }
-
- *ppos += do_count;
- b_point += do_count;
- count -= do_count;
- if (STps->drv_block >= 0) {
- STps->drv_block += blks;
- }
- STp->buffer->buffer_bytes = 0;
- STp->dirty = 0;
- } /* end while write threshold exceeded */
-
- if (count != 0) {
- STp->dirty = 1;
- i = append_to_buffer(b_point, STp->buffer, count);
- if (i) {
- retval = i;
- goto out;
- }
- blks = count / STp->block_size;
- STp->logical_blk_num += blks;
- if (STps->drv_block >= 0) {
- STps->drv_block += blks;
- }
- *ppos += count;
- count = 0;
- }
-
- if (doing_write && (STp->buffer)->syscall_result != 0) {
- retval = (STp->buffer)->syscall_result;
- goto out;
- }
-
- if (STm->do_async_writes && ((STp->buffer)->buffer_bytes >= STp->write_threshold)) {
- /* Schedule an asynchronous write */
- (STp->buffer)->writing = ((STp->buffer)->buffer_bytes /
- STp->block_size) * STp->block_size;
- STp->dirty = !((STp->buffer)->writing ==
- (STp->buffer)->buffer_bytes);
-
- i = osst_write_frame(STp, &SRpnt, 0);
- if (i < 0) {
- retval = (-EIO);
- goto out;
- }
- SRpnt = NULL; /* Prevent releasing this request! */
- }
- STps->at_sm &= (total == 0);
- if (total > 0)
- STps->eof = ST_NOEOF;
-
- retval = total;
-
-out:
- if (SRpnt != NULL) osst_release_request(SRpnt);
-
- mutex_unlock(&STp->lock);
-
- return retval;
-}
-
-
-/* Read command */
-static ssize_t osst_read(struct file * filp, char __user * buf, size_t count, loff_t *ppos)
-{
- ssize_t total, retval = 0;
- ssize_t i, transfer;
- int special;
- struct st_modedef * STm;
- struct st_partstat * STps;
- struct osst_request * SRpnt = NULL;
- struct osst_tape * STp = filp->private_data;
- char * name = tape_name(STp);
-
-
- if (mutex_lock_interruptible(&STp->lock))
- return (-ERESTARTSYS);
-
- /*
- * If we are in the middle of error recovery, don't let anyone
- * else try and use this device. Also, if error recovery fails, it
- * may try and take the device offline, in which case all further
- * access to the device is prohibited.
- */
- if( !scsi_block_when_processing_errors(STp->device) ) {
- retval = (-ENXIO);
- goto out;
- }
-
- if (STp->ready != ST_READY) {
- if (STp->ready == ST_NO_TAPE)
- retval = (-ENOMEDIUM);
- else
- retval = (-EIO);
- goto out;
- }
- STm = &(STp->modes[STp->current_mode]);
- if (!STm->defined) {
- retval = (-ENXIO);
- goto out;
- }
-#if DEBUG
- if (!STp->in_use) {
- printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
- retval = (-EIO);
- goto out;
- }
-#endif
- /* Must have initialized medium */
- if (!STp->header_ok) {
- retval = (-EIO);
- goto out;
- }
-
- if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1))
- STp->door_locked = ST_LOCKED_AUTO;
-
- STps = &(STp->ps[STp->partition]);
- if (STps->rw == ST_WRITING) {
- retval = osst_flush_buffer(STp, &SRpnt, 0);
- if (retval)
- goto out;
- STps->rw = ST_IDLE;
- /* FIXME -- this may leave the tape without EOD and up2date headers */
- }
-
- if ((count % STp->block_size) != 0) {
- printk(KERN_WARNING
- "%s:W: Read (%zd bytes) not multiple of tape block size (%d%c).\n", name, count,
- STp->block_size<1024?STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k');
- }
-
-#if DEBUG
- if (debugging && STps->eof != ST_NOEOF)
- printk(OSST_DEB_MSG "%s:D: EOF/EOM flag up (%d). Bytes %d\n", name,
- STps->eof, (STp->buffer)->buffer_bytes);
-#endif
- if ((STp->buffer)->buffer_bytes == 0 &&
- STps->eof >= ST_EOD_1) {
- if (STps->eof < ST_EOD) {
- STps->eof += 1;
- retval = 0;
- goto out;
- }
- retval = (-EIO); /* EOM or Blank Check */
- goto out;
- }
-
- /* Check the buffer writability before any tape movement. Don't alter
- buffer data. */
- if (copy_from_user(&i, buf, 1) != 0 ||
- copy_to_user (buf, &i, 1) != 0 ||
- copy_from_user(&i, buf + count - 1, 1) != 0 ||
- copy_to_user (buf + count - 1, &i, 1) != 0) {
- retval = (-EFAULT);
- goto out;
- }
-
- /* Loop until enough data in buffer or a special condition found */
- for (total = 0, special = 0; total < count - STp->block_size + 1 && !special; ) {
-
- /* Get new data if the buffer is empty */
- if ((STp->buffer)->buffer_bytes == 0) {
- if (STps->eof == ST_FM_HIT)
- break;
- special = osst_get_logical_frame(STp, &SRpnt, STp->frame_seq_number, 0);
- if (special < 0) { /* No need to continue read */
- STp->frame_in_buffer = 0;
- retval = special;
- goto out;
- }
- }
-
- /* Move the data from driver buffer to user buffer */
- if ((STp->buffer)->buffer_bytes > 0) {
-#if DEBUG
- if (debugging && STps->eof != ST_NOEOF)
- printk(OSST_DEB_MSG "%s:D: EOF up (%d). Left %d, needed %d.\n", name,
- STps->eof, (STp->buffer)->buffer_bytes, (int) (count - total));
-#endif
- /* force multiple of block size, note block_size may have been adjusted */
- transfer = (((STp->buffer)->buffer_bytes < count - total ?
- (STp->buffer)->buffer_bytes : count - total)/
- STp->block_size) * STp->block_size;
-
- if (transfer == 0) {
- printk(KERN_WARNING
- "%s:W: Nothing can be transferred, requested %zd, tape block size (%d%c).\n",
- name, count, STp->block_size < 1024?
- STp->block_size:STp->block_size/1024,
- STp->block_size<1024?'b':'k');
- break;
- }
- i = from_buffer(STp->buffer, buf, transfer);
- if (i) {
- retval = i;
- goto out;
- }
- STp->logical_blk_num += transfer / STp->block_size;
- STps->drv_block += transfer / STp->block_size;
- *ppos += transfer;
- buf += transfer;
- total += transfer;
- }
-
- if ((STp->buffer)->buffer_bytes == 0) {
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Finished with frame %d\n",
- name, STp->frame_seq_number);
-#endif
- STp->frame_in_buffer = 0;
- STp->frame_seq_number++; /* frame to look for next time */
- }
- } /* for (total = 0, special = 0; total < count && !special; ) */
-
- /* Change the eof state if no data from tape or buffer */
- if (total == 0) {
- if (STps->eof == ST_FM_HIT) {
- STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD_2:ST_FM;
- STps->drv_block = 0;
- if (STps->drv_file >= 0)
- STps->drv_file++;
- }
- else if (STps->eof == ST_EOD_1) {
- STps->eof = ST_EOD_2;
- if (STps->drv_block > 0 && STps->drv_file >= 0)
- STps->drv_file++;
- STps->drv_block = 0;
- }
- else if (STps->eof == ST_EOD_2)
- STps->eof = ST_EOD;
- }
- else if (STps->eof == ST_FM)
- STps->eof = ST_NOEOF;
-
- retval = total;
-
-out:
- if (SRpnt != NULL) osst_release_request(SRpnt);
-
- mutex_unlock(&STp->lock);
-
- return retval;
-}
-
-
-/* Set the driver options */
-static void osst_log_options(struct osst_tape *STp, struct st_modedef *STm, char *name)
-{
- printk(KERN_INFO
-"%s:I: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n",
- name, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes,
- STm->do_read_ahead);
- printk(KERN_INFO
-"%s:I: can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n",
- name, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock);
- printk(KERN_INFO
-"%s:I: defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n",
- name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions,
- STp->scsi2_logical);
- printk(KERN_INFO
-"%s:I: sysv: %d\n", name, STm->sysv);
-#if DEBUG
- printk(KERN_INFO
- "%s:D: debugging: %d\n",
- name, debugging);
-#endif
-}
-
-
-static int osst_set_options(struct osst_tape *STp, long options)
-{
- int value;
- long code;
- struct st_modedef * STm;
- char * name = tape_name(STp);
-
- STm = &(STp->modes[STp->current_mode]);
- if (!STm->defined) {
- memcpy(STm, &(STp->modes[0]), sizeof(*STm));
- modes_defined = 1;
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Initialized mode %d definition from mode 0\n",
- name, STp->current_mode);
-#endif
- }
-
- code = options & MT_ST_OPTIONS;
- if (code == MT_ST_BOOLEANS) {
- STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0;
- STm->do_async_writes = (options & MT_ST_ASYNC_WRITES) != 0;
- STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0;
- STm->do_read_ahead = (options & MT_ST_READ_AHEAD) != 0;
- STp->two_fm = (options & MT_ST_TWO_FM) != 0;
- STp->fast_mteom = (options & MT_ST_FAST_MTEOM) != 0;
- STp->do_auto_lock = (options & MT_ST_AUTO_LOCK) != 0;
- STp->can_bsr = (options & MT_ST_CAN_BSR) != 0;
- STp->omit_blklims = (options & MT_ST_NO_BLKLIMS) != 0;
- if ((STp->device)->scsi_level >= SCSI_2)
- STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0;
- STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0;
- STm->sysv = (options & MT_ST_SYSV) != 0;
-#if DEBUG
- debugging = (options & MT_ST_DEBUGGING) != 0;
-#endif
- osst_log_options(STp, STm, name);
- }
- else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) {
- value = (code == MT_ST_SETBOOLEANS);
- if ((options & MT_ST_BUFFER_WRITES) != 0)
- STm->do_buffer_writes = value;
- if ((options & MT_ST_ASYNC_WRITES) != 0)
- STm->do_async_writes = value;
- if ((options & MT_ST_DEF_WRITES) != 0)
- STm->defaults_for_writes = value;
- if ((options & MT_ST_READ_AHEAD) != 0)
- STm->do_read_ahead = value;
- if ((options & MT_ST_TWO_FM) != 0)
- STp->two_fm = value;
- if ((options & MT_ST_FAST_MTEOM) != 0)
- STp->fast_mteom = value;
- if ((options & MT_ST_AUTO_LOCK) != 0)
- STp->do_auto_lock = value;
- if ((options & MT_ST_CAN_BSR) != 0)
- STp->can_bsr = value;
- if ((options & MT_ST_NO_BLKLIMS) != 0)
- STp->omit_blklims = value;
- if ((STp->device)->scsi_level >= SCSI_2 &&
- (options & MT_ST_CAN_PARTITIONS) != 0)
- STp->can_partitions = value;
- if ((options & MT_ST_SCSI2LOGICAL) != 0)
- STp->scsi2_logical = value;
- if ((options & MT_ST_SYSV) != 0)
- STm->sysv = value;
-#if DEBUG
- if ((options & MT_ST_DEBUGGING) != 0)
- debugging = value;
-#endif
- osst_log_options(STp, STm, name);
- }
- else if (code == MT_ST_WRITE_THRESHOLD) {
- value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE;
- if (value < 1 || value > osst_buffer_size) {
- printk(KERN_WARNING "%s:W: Write threshold %d too small or too large.\n",
- name, value);
- return (-EIO);
- }
- STp->write_threshold = value;
- printk(KERN_INFO "%s:I: Write threshold set to %d bytes.\n",
- name, value);
- }
- else if (code == MT_ST_DEF_BLKSIZE) {
- value = (options & ~MT_ST_OPTIONS);
- if (value == ~MT_ST_OPTIONS) {
- STm->default_blksize = (-1);
- printk(KERN_INFO "%s:I: Default block size disabled.\n", name);
- }
- else {
- if (value < 512 || value > OS_DATA_SIZE || OS_DATA_SIZE % value) {
- printk(KERN_WARNING "%s:W: Default block size cannot be set to %d.\n",
- name, value);
- return (-EINVAL);
- }
- STm->default_blksize = value;
- printk(KERN_INFO "%s:I: Default block size set to %d bytes.\n",
- name, STm->default_blksize);
- }
- }
- else if (code == MT_ST_TIMEOUTS) {
- value = (options & ~MT_ST_OPTIONS);
- if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) {
- STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ;
- printk(KERN_INFO "%s:I: Long timeout set to %d seconds.\n", name,
- (value & ~MT_ST_SET_LONG_TIMEOUT));
- }
- else {
- STp->timeout = value * HZ;
- printk(KERN_INFO "%s:I: Normal timeout set to %d seconds.\n", name, value);
- }
- }
- else if (code == MT_ST_DEF_OPTIONS) {
- code = (options & ~MT_ST_CLEAR_DEFAULT);
- value = (options & MT_ST_CLEAR_DEFAULT);
- if (code == MT_ST_DEF_DENSITY) {
- if (value == MT_ST_CLEAR_DEFAULT) {
- STm->default_density = (-1);
- printk(KERN_INFO "%s:I: Density default disabled.\n", name);
- }
- else {
- STm->default_density = value & 0xff;
- printk(KERN_INFO "%s:I: Density default set to %x\n",
- name, STm->default_density);
- }
- }
- else if (code == MT_ST_DEF_DRVBUFFER) {
- if (value == MT_ST_CLEAR_DEFAULT) {
- STp->default_drvbuffer = 0xff;
- printk(KERN_INFO "%s:I: Drive buffer default disabled.\n", name);
- }
- else {
- STp->default_drvbuffer = value & 7;
- printk(KERN_INFO "%s:I: Drive buffer default set to %x\n",
- name, STp->default_drvbuffer);
- }
- }
- else if (code == MT_ST_DEF_COMPRESSION) {
- if (value == MT_ST_CLEAR_DEFAULT) {
- STm->default_compression = ST_DONT_TOUCH;
- printk(KERN_INFO "%s:I: Compression default disabled.\n", name);
- }
- else {
- STm->default_compression = (value & 1 ? ST_YES : ST_NO);
- printk(KERN_INFO "%s:I: Compression default set to %x\n",
- name, (value & 1));
- }
- }
- }
- else
- return (-EIO);
-
- return 0;
-}
-
-
-/* Internal ioctl function */
-static int osst_int_ioctl(struct osst_tape * STp, struct osst_request ** aSRpnt,
- unsigned int cmd_in, unsigned long arg)
-{
- int timeout;
- long ltmp;
- int i, ioctl_result;
- int chg_eof = 1;
- unsigned char cmd[MAX_COMMAND_SIZE];
- struct osst_request * SRpnt = * aSRpnt;
- struct st_partstat * STps;
- int fileno, blkno, at_sm, frame_seq_numbr, logical_blk_num;
- int datalen = 0, direction = DMA_NONE;
- char * name = tape_name(STp);
-
- if (STp->ready != ST_READY && cmd_in != MTLOAD) {
- if (STp->ready == ST_NO_TAPE)
- return (-ENOMEDIUM);
- else
- return (-EIO);
- }
- timeout = STp->long_timeout;
- STps = &(STp->ps[STp->partition]);
- fileno = STps->drv_file;
- blkno = STps->drv_block;
- at_sm = STps->at_sm;
- frame_seq_numbr = STp->frame_seq_number;
- logical_blk_num = STp->logical_blk_num;
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- switch (cmd_in) {
- case MTFSFM:
- chg_eof = 0; /* Changed from the FSF after this */
- /* fall through */
- case MTFSF:
- if (STp->raw)
- return (-EIO);
- if (STp->linux_media)
- ioctl_result = osst_space_over_filemarks_forward_fast(STp, &SRpnt, cmd_in, arg);
- else
- ioctl_result = osst_space_over_filemarks_forward_slow(STp, &SRpnt, cmd_in, arg);
- if (fileno >= 0)
- fileno += arg;
- blkno = 0;
- at_sm &= (arg == 0);
- goto os_bypass;
-
- case MTBSF:
- chg_eof = 0; /* Changed from the FSF after this */
- /* fall through */
- case MTBSFM:
- if (STp->raw)
- return (-EIO);
- ioctl_result = osst_space_over_filemarks_backward(STp, &SRpnt, cmd_in, arg);
- if (fileno >= 0)
- fileno -= arg;
- blkno = (-1); /* We can't know the block number */
- at_sm &= (arg == 0);
- goto os_bypass;
-
- case MTFSR:
- case MTBSR:
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Skipping %lu blocks %s from logical block %d\n",
- name, arg, cmd_in==MTFSR?"forward":"backward", logical_blk_num);
-#endif
- if (cmd_in == MTFSR) {
- logical_blk_num += arg;
- if (blkno >= 0) blkno += arg;
- }
- else {
- logical_blk_num -= arg;
- if (blkno >= 0) blkno -= arg;
- }
- ioctl_result = osst_seek_logical_blk(STp, &SRpnt, logical_blk_num);
- fileno = STps->drv_file;
- blkno = STps->drv_block;
- at_sm &= (arg == 0);
- goto os_bypass;
-
- case MTFSS:
- cmd[0] = SPACE;
- cmd[1] = 0x04; /* Space Setmarks */ /* FIXME -- OS can't do this? */
- cmd[2] = (arg >> 16);
- cmd[3] = (arg >> 8);
- cmd[4] = arg;
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Spacing tape forward %d setmarks.\n", name,
- cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
-#endif
- if (arg != 0) {
- blkno = fileno = (-1);
- at_sm = 1;
- }
- break;
- case MTBSS:
- cmd[0] = SPACE;
- cmd[1] = 0x04; /* Space Setmarks */ /* FIXME -- OS can't do this? */
- ltmp = (-arg);
- cmd[2] = (ltmp >> 16);
- cmd[3] = (ltmp >> 8);
- cmd[4] = ltmp;
-#if DEBUG
- if (debugging) {
- if (cmd[2] & 0x80)
- ltmp = 0xff000000;
- ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
- printk(OSST_DEB_MSG "%s:D: Spacing tape backward %ld setmarks.\n",
- name, (-ltmp));
- }
-#endif
- if (arg != 0) {
- blkno = fileno = (-1);
- at_sm = 1;
- }
- break;
- case MTWEOF:
- if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) {
- STp->write_type = OS_WRITE_DATA;
- ioctl_result = osst_flush_write_buffer(STp, &SRpnt);
- } else
- ioctl_result = 0;
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Writing %ld filemark(s).\n", name, arg);
-#endif
- for (i=0; i<arg; i++)
- ioctl_result |= osst_write_filemark(STp, &SRpnt);
- if (fileno >= 0) fileno += arg;
- if (blkno >= 0) blkno = 0;
- goto os_bypass;
-
- case MTWSM:
- if (STp->write_prot)
- return (-EACCES);
- if (!STp->raw)
- return 0;
- cmd[0] = WRITE_FILEMARKS; /* FIXME -- need OS version */
- if (cmd_in == MTWSM)
- cmd[1] = 2;
- cmd[2] = (arg >> 16);
- cmd[3] = (arg >> 8);
- cmd[4] = arg;
- timeout = STp->timeout;
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Writing %d setmark(s).\n", name,
- cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
-#endif
- if (fileno >= 0)
- fileno += arg;
- blkno = 0;
- at_sm = (cmd_in == MTWSM);
- break;
- case MTOFFL:
- case MTLOAD:
- case MTUNLOAD:
- case MTRETEN:
- cmd[0] = START_STOP;
- cmd[1] = 1; /* Don't wait for completion */
- if (cmd_in == MTLOAD) {
- if (STp->ready == ST_NO_TAPE)
- cmd[4] = 4; /* open tray */
- else
- cmd[4] = 1; /* load */
- }
- if (cmd_in == MTRETEN)
- cmd[4] = 3; /* retension then mount */
- if (cmd_in == MTOFFL)
- cmd[4] = 4; /* rewind then eject */
- timeout = STp->timeout;
-#if DEBUG
- if (debugging) {
- switch (cmd_in) {
- case MTUNLOAD:
- printk(OSST_DEB_MSG "%s:D: Unloading tape.\n", name);
- break;
- case MTLOAD:
- printk(OSST_DEB_MSG "%s:D: Loading tape.\n", name);
- break;
- case MTRETEN:
- printk(OSST_DEB_MSG "%s:D: Retensioning tape.\n", name);
- break;
- case MTOFFL:
- printk(OSST_DEB_MSG "%s:D: Ejecting tape.\n", name);
- break;
- }
- }
-#endif
- fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
- break;
- case MTNOP:
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: No-op on tape.\n", name);
-#endif
- return 0; /* Should do something ? */
- break;
- case MTEOM:
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Spacing to end of recorded medium.\n", name);
-#endif
- if ((osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0) ||
- (osst_get_logical_frame(STp, &SRpnt, -1, 0) < 0)) {
- ioctl_result = -EIO;
- goto os_bypass;
- }
- if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_EOD) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: No EOD frame found where expected.\n", name);
-#endif
- ioctl_result = -EIO;
- goto os_bypass;
- }
- ioctl_result = osst_set_frame_position(STp, &SRpnt, STp->eod_frame_ppos, 0);
- fileno = STp->filemark_cnt;
- blkno = at_sm = 0;
- goto os_bypass;
-
- case MTERASE:
- if (STp->write_prot)
- return (-EACCES);
- ioctl_result = osst_reset_header(STp, &SRpnt);
- i = osst_write_eod(STp, &SRpnt);
- if (i < ioctl_result) ioctl_result = i;
- i = osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos);
- if (i < ioctl_result) ioctl_result = i;
- fileno = blkno = at_sm = 0 ;
- goto os_bypass;
-
- case MTREW:
- cmd[0] = REZERO_UNIT; /* rewind */
- cmd[1] = 1;
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Rewinding tape, Immed=%d.\n", name, cmd[1]);
-#endif
- fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
- break;
-
- case MTSETBLK: /* Set block length */
- if ((STps->drv_block == 0 ) &&
- !STp->dirty &&
- ((STp->buffer)->buffer_bytes == 0) &&
- ((arg & MT_ST_BLKSIZE_MASK) >= 512 ) &&
- ((arg & MT_ST_BLKSIZE_MASK) <= OS_DATA_SIZE) &&
- !(OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK)) ) {
- /*
- * Only allowed to change the block size if you opened the
- * device at the beginning of a file before writing anything.
- * Note, that when reading, changing block_size is futile,
- * as the size used when writing overrides it.
- */
- STp->block_size = (arg & MT_ST_BLKSIZE_MASK);
- printk(KERN_INFO "%s:I: Block size set to %d bytes.\n",
- name, STp->block_size);
- return 0;
- }
- /* fall through */
- case MTSETDENSITY: /* Set tape density */
- case MTSETDRVBUFFER: /* Set drive buffering */
- case SET_DENS_AND_BLK: /* Set density and block size */
- chg_eof = 0;
- if (STp->dirty || (STp->buffer)->buffer_bytes != 0)
- return (-EIO); /* Not allowed if data in buffer */
- if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) &&
- (arg & MT_ST_BLKSIZE_MASK) != 0 &&
- (arg & MT_ST_BLKSIZE_MASK) != STp->block_size ) {
- printk(KERN_WARNING "%s:W: Illegal to set block size to %d%s.\n",
- name, (int)(arg & MT_ST_BLKSIZE_MASK),
- (OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK))?"":" now");
- return (-EINVAL);
- }
- return 0; /* FIXME silently ignore if block size didn't change */
-
- default:
- return (-ENOSYS);
- }
-
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, datalen, direction, timeout, MAX_RETRIES, 1);
-
- ioctl_result = (STp->buffer)->syscall_result;
-
- if (!SRpnt) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Couldn't exec scsi cmd for IOCTL\n", name);
-#endif
- return ioctl_result;
- }
-
- if (!ioctl_result) { /* SCSI command successful */
- STp->frame_seq_number = frame_seq_numbr;
- STp->logical_blk_num = logical_blk_num;
- }
-
-os_bypass:
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: IOCTL (%d) Result=%d\n", name, cmd_in, ioctl_result);
-#endif
-
- if (!ioctl_result) { /* success */
-
- if (cmd_in == MTFSFM) {
- fileno--;
- blkno--;
- }
- if (cmd_in == MTBSFM) {
- fileno++;
- blkno++;
- }
- STps->drv_block = blkno;
- STps->drv_file = fileno;
- STps->at_sm = at_sm;
-
- if (cmd_in == MTEOM)
- STps->eof = ST_EOD;
- else if ((cmd_in == MTFSFM || cmd_in == MTBSF) && STps->eof == ST_FM_HIT) {
- ioctl_result = osst_seek_logical_blk(STp, &SRpnt, STp->logical_blk_num-1);
- STps->drv_block++;
- STp->logical_blk_num++;
- STp->frame_seq_number++;
- STp->frame_in_buffer = 0;
- STp->buffer->read_pointer = 0;
- }
- else if (cmd_in == MTFSF)
- STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_FM;
- else if (chg_eof)
- STps->eof = ST_NOEOF;
-
- if (cmd_in == MTOFFL || cmd_in == MTUNLOAD)
- STp->rew_at_close = 0;
- else if (cmd_in == MTLOAD) {
- for (i=0; i < ST_NBR_PARTITIONS; i++) {
- STp->ps[i].rw = ST_IDLE;
- STp->ps[i].last_block_valid = 0;/* FIXME - where else is this field maintained? */
- }
- STp->partition = 0;
- }
-
- if (cmd_in == MTREW) {
- ioctl_result = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos);
- if (ioctl_result > 0)
- ioctl_result = 0;
- }
-
- } else if (cmd_in == MTBSF || cmd_in == MTBSFM ) {
- if (osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos) < 0)
- STps->drv_file = STps->drv_block = -1;
- else
- STps->drv_file = STps->drv_block = 0;
- STps->eof = ST_NOEOF;
- } else if (cmd_in == MTFSF || cmd_in == MTFSFM) {
- if (osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0)
- STps->drv_file = STps->drv_block = -1;
- else {
- STps->drv_file = STp->filemark_cnt;
- STps->drv_block = 0;
- }
- STps->eof = ST_EOD;
- } else if (cmd_in == MTBSR || cmd_in == MTFSR || cmd_in == MTWEOF || cmd_in == MTEOM) {
- STps->drv_file = STps->drv_block = (-1);
- STps->eof = ST_NOEOF;
- STp->header_ok = 0;
- } else if (cmd_in == MTERASE) {
- STp->header_ok = 0;
- } else if (SRpnt) { /* SCSI command was not completely successful. */
- if (SRpnt->sense[2] & 0x40) {
- STps->eof = ST_EOM_OK;
- STps->drv_block = 0;
- }
- if (chg_eof)
- STps->eof = ST_NOEOF;
-
- if ((SRpnt->sense[2] & 0x0f) == BLANK_CHECK)
- STps->eof = ST_EOD;
-
- if (cmd_in == MTLOAD && osst_wait_for_medium(STp, &SRpnt, 60))
- ioctl_result = osst_wait_ready(STp, &SRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE);
- }
- *aSRpnt = SRpnt;
-
- return ioctl_result;
-}
-
-
-/* Open the device */
-static int __os_scsi_tape_open(struct inode * inode, struct file * filp)
-{
- unsigned short flags;
- int i, b_size, new_session = 0, retval = 0;
- unsigned char cmd[MAX_COMMAND_SIZE];
- struct osst_request * SRpnt = NULL;
- struct osst_tape * STp;
- struct st_modedef * STm;
- struct st_partstat * STps;
- char * name;
- int dev = TAPE_NR(inode);
- int mode = TAPE_MODE(inode);
-
- /*
- * We really want to do nonseekable_open(inode, filp); here, but some
- * versions of tar incorrectly call lseek on tapes and bail out if that
- * fails. So we disallow pread() and pwrite(), but permit lseeks.
- */
- filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
-
- write_lock(&os_scsi_tapes_lock);
- if (dev >= osst_max_dev || os_scsi_tapes == NULL ||
- (STp = os_scsi_tapes[dev]) == NULL || !STp->device) {
- write_unlock(&os_scsi_tapes_lock);
- return (-ENXIO);
- }
-
- name = tape_name(STp);
-
- if (STp->in_use) {
- write_unlock(&os_scsi_tapes_lock);
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Device already in use.\n", name);
-#endif
- return (-EBUSY);
- }
- if (scsi_device_get(STp->device)) {
- write_unlock(&os_scsi_tapes_lock);
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Failed scsi_device_get.\n", name);
-#endif
- return (-ENXIO);
- }
- filp->private_data = STp;
- STp->in_use = 1;
- write_unlock(&os_scsi_tapes_lock);
- STp->rew_at_close = TAPE_REWIND(inode);
-
- if( !scsi_block_when_processing_errors(STp->device) ) {
- return -ENXIO;
- }
-
- if (mode != STp->current_mode) {
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Mode change from %d to %d.\n",
- name, STp->current_mode, mode);
-#endif
- new_session = 1;
- STp->current_mode = mode;
- }
- STm = &(STp->modes[STp->current_mode]);
-
- flags = filp->f_flags;
- STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY);
-
- STp->raw = TAPE_IS_RAW(inode);
- if (STp->raw)
- STp->header_ok = 0;
-
- /* Allocate data segments for this device's tape buffer */
- if (!enlarge_buffer(STp->buffer, STp->restr_dma)) {
- printk(KERN_ERR "%s:E: Unable to allocate memory segments for tape buffer.\n", name);
- retval = (-EOVERFLOW);
- goto err_out;
- }
- if (STp->buffer->buffer_size >= OS_FRAME_SIZE) {
- for (i = 0, b_size = 0;
- (i < STp->buffer->sg_segs) && ((b_size + STp->buffer->sg[i].length) <= OS_DATA_SIZE);
- b_size += STp->buffer->sg[i++].length);
- STp->buffer->aux = (os_aux_t *) (page_address(sg_page(&STp->buffer->sg[i])) + OS_DATA_SIZE - b_size);
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: b_data points to %p in segment 0 at %p\n", name,
- STp->buffer->b_data, page_address(STp->buffer->sg[0].page));
- printk(OSST_DEB_MSG "%s:D: AUX points to %p in segment %d at %p\n", name,
- STp->buffer->aux, i, page_address(STp->buffer->sg[i].page));
-#endif
- } else {
- STp->buffer->aux = NULL; /* this had better never happen! */
- printk(KERN_NOTICE "%s:A: Framesize %d too large for buffer.\n", name, OS_FRAME_SIZE);
- retval = (-EIO);
- goto err_out;
- }
- STp->buffer->writing = 0;
- STp->buffer->syscall_result = 0;
- STp->dirty = 0;
- for (i=0; i < ST_NBR_PARTITIONS; i++) {
- STps = &(STp->ps[i]);
- STps->rw = ST_IDLE;
- }
- STp->ready = ST_READY;
-#if DEBUG
- STp->nbr_waits = STp->nbr_finished = 0;
-#endif
-
- memset (cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = TEST_UNIT_READY;
-
- SRpnt = osst_do_scsi(NULL, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
- if (!SRpnt) {
- retval = (STp->buffer)->syscall_result; /* FIXME - valid? */
- goto err_out;
- }
- if ((SRpnt->sense[0] & 0x70) == 0x70 &&
- (SRpnt->sense[2] & 0x0f) == NOT_READY &&
- SRpnt->sense[12] == 4 ) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Unit not ready, cause %x\n", name, SRpnt->sense[13]);
-#endif
- if (filp->f_flags & O_NONBLOCK) {
- retval = -EAGAIN;
- goto err_out;
- }
- if (SRpnt->sense[13] == 2) { /* initialize command required (LOAD) */
- memset (cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = START_STOP;
- cmd[1] = 1;
- cmd[4] = 1;
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
- STp->timeout, MAX_RETRIES, 1);
- }
- osst_wait_ready(STp, &SRpnt, (SRpnt->sense[13]==1?15:3) * 60, 0);
- }
- if ((SRpnt->sense[0] & 0x70) == 0x70 &&
- (SRpnt->sense[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Unit wants attention\n", name);
-#endif
- STp->header_ok = 0;
-
- for (i=0; i < 10; i++) {
-
- memset (cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = TEST_UNIT_READY;
-
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
- STp->timeout, MAX_RETRIES, 1);
- if ((SRpnt->sense[0] & 0x70) != 0x70 ||
- (SRpnt->sense[2] & 0x0f) != UNIT_ATTENTION)
- break;
- }
-
- STp->pos_unknown = 0;
- STp->partition = STp->new_partition = 0;
- if (STp->can_partitions)
- STp->nbr_partitions = 1; /* This guess will be updated later if necessary */
- for (i=0; i < ST_NBR_PARTITIONS; i++) {
- STps = &(STp->ps[i]);
- STps->rw = ST_IDLE; /* FIXME - seems to be redundant... */
- STps->eof = ST_NOEOF;
- STps->at_sm = 0;
- STps->last_block_valid = 0;
- STps->drv_block = 0;
- STps->drv_file = 0 ;
- }
- new_session = 1;
- STp->recover_count = 0;
- STp->abort_count = 0;
- }
- /*
- * if we have valid headers from before, and the drive/tape seem untouched,
- * open without reconfiguring and re-reading the headers
- */
- if (!STp->buffer->syscall_result && STp->header_ok &&
- !SRpnt->result && SRpnt->sense[0] == 0) {
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = MODE_SENSE;
- cmd[1] = 8;
- cmd[2] = VENDOR_IDENT_PAGE;
- cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH;
-
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
-
- if (STp->buffer->syscall_result ||
- STp->buffer->b_data[MODE_HEADER_LENGTH + 2] != 'L' ||
- STp->buffer->b_data[MODE_HEADER_LENGTH + 3] != 'I' ||
- STp->buffer->b_data[MODE_HEADER_LENGTH + 4] != 'N' ||
- STp->buffer->b_data[MODE_HEADER_LENGTH + 5] != '4' ) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Signature was changed to %c%c%c%c\n", name,
- STp->buffer->b_data[MODE_HEADER_LENGTH + 2],
- STp->buffer->b_data[MODE_HEADER_LENGTH + 3],
- STp->buffer->b_data[MODE_HEADER_LENGTH + 4],
- STp->buffer->b_data[MODE_HEADER_LENGTH + 5]);
-#endif
- STp->header_ok = 0;
- }
- i = STp->first_frame_position;
- if (STp->header_ok && i == osst_get_frame_position(STp, &SRpnt)) {
- if (STp->door_locked == ST_UNLOCKED) {
- if (do_door_lock(STp, 1))
- printk(KERN_INFO "%s:I: Can't lock drive door\n", name);
- else
- STp->door_locked = ST_LOCKED_AUTO;
- }
- if (!STp->frame_in_buffer) {
- STp->block_size = (STm->default_blksize > 0) ?
- STm->default_blksize : OS_DATA_SIZE;
- STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0;
- }
- STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size;
- STp->fast_open = 1;
- osst_release_request(SRpnt);
- return 0;
- }
-#if DEBUG
- if (i != STp->first_frame_position)
- printk(OSST_DEB_MSG "%s:D: Tape position changed from %d to %d\n",
- name, i, STp->first_frame_position);
-#endif
- STp->header_ok = 0;
- }
- STp->fast_open = 0;
-
- if ((STp->buffer)->syscall_result != 0 && /* in all error conditions except no medium */
- (SRpnt->sense[2] != 2 || SRpnt->sense[12] != 0x3A) ) {
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = MODE_SELECT;
- cmd[1] = 0x10;
- cmd[4] = 4 + MODE_HEADER_LENGTH;
-
- (STp->buffer)->b_data[0] = cmd[4] - 1;
- (STp->buffer)->b_data[1] = 0; /* Medium Type - ignoring */
- (STp->buffer)->b_data[2] = 0; /* Reserved */
- (STp->buffer)->b_data[3] = 0; /* Block Descriptor Length */
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = 0x3f;
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 1;
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 2;
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 3;
-
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Applying soft reset\n", name);
-#endif
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
-
- STp->header_ok = 0;
-
- for (i=0; i < 10; i++) {
-
- memset (cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = TEST_UNIT_READY;
-
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
- STp->timeout, MAX_RETRIES, 1);
- if ((SRpnt->sense[0] & 0x70) != 0x70 ||
- (SRpnt->sense[2] & 0x0f) == NOT_READY)
- break;
-
- if ((SRpnt->sense[2] & 0x0f) == UNIT_ATTENTION) {
- int j;
-
- STp->pos_unknown = 0;
- STp->partition = STp->new_partition = 0;
- if (STp->can_partitions)
- STp->nbr_partitions = 1; /* This guess will be updated later if necessary */
- for (j = 0; j < ST_NBR_PARTITIONS; j++) {
- STps = &(STp->ps[j]);
- STps->rw = ST_IDLE;
- STps->eof = ST_NOEOF;
- STps->at_sm = 0;
- STps->last_block_valid = 0;
- STps->drv_block = 0;
- STps->drv_file = 0 ;
- }
- new_session = 1;
- }
- }
- }
-
- if (osst_wait_ready(STp, &SRpnt, 15 * 60, 0)) /* FIXME - not allowed with NOBLOCK */
- printk(KERN_INFO "%s:I: Device did not become Ready in open\n", name);
-
- if ((STp->buffer)->syscall_result != 0) {
- if ((STp->device)->scsi_level >= SCSI_2 &&
- (SRpnt->sense[0] & 0x70) == 0x70 &&
- (SRpnt->sense[2] & 0x0f) == NOT_READY &&
- SRpnt->sense[12] == 0x3a) { /* Check ASC */
- STp->ready = ST_NO_TAPE;
- } else
- STp->ready = ST_NOT_READY;
- osst_release_request(SRpnt);
- SRpnt = NULL;
- STp->density = 0; /* Clear the erroneous "residue" */
- STp->write_prot = 0;
- STp->block_size = 0;
- STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
- STp->partition = STp->new_partition = 0;
- STp->door_locked = ST_UNLOCKED;
- return 0;
- }
-
- osst_configure_onstream(STp, &SRpnt);
-
- STp->block_size = STp->raw ? OS_FRAME_SIZE : (
- (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE);
- STp->buffer->buffer_blocks = STp->raw ? 1 : OS_DATA_SIZE / STp->block_size;
- STp->buffer->buffer_bytes =
- STp->buffer->read_pointer =
- STp->frame_in_buffer = 0;
-
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Block size: %d, frame size: %d, buffer size: %d (%d blocks).\n",
- name, STp->block_size, OS_FRAME_SIZE, (STp->buffer)->buffer_size,
- (STp->buffer)->buffer_blocks);
-#endif
-
- if (STp->drv_write_prot) {
- STp->write_prot = 1;
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Write protected\n", name);
-#endif
- if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) {
- retval = (-EROFS);
- goto err_out;
- }
- }
-
- if (new_session) { /* Change the drive parameters for the new mode */
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: New Session\n", name);
-#endif
- STp->density_changed = STp->blksize_changed = 0;
- STp->compression_changed = 0;
- }
-
- /*
- * properly position the tape and check the ADR headers
- */
- if (STp->door_locked == ST_UNLOCKED) {
- if (do_door_lock(STp, 1))
- printk(KERN_INFO "%s:I: Can't lock drive door\n", name);
- else
- STp->door_locked = ST_LOCKED_AUTO;
- }
-
- osst_analyze_headers(STp, &SRpnt);
-
- osst_release_request(SRpnt);
- SRpnt = NULL;
-
- return 0;
-
-err_out:
- if (SRpnt != NULL)
- osst_release_request(SRpnt);
- normalize_buffer(STp->buffer);
- STp->header_ok = 0;
- STp->in_use = 0;
- scsi_device_put(STp->device);
-
- return retval;
-}
-
-/* BKL pushdown: spaghetti avoidance wrapper */
-static int os_scsi_tape_open(struct inode * inode, struct file * filp)
-{
- int ret;
-
- mutex_lock(&osst_int_mutex);
- ret = __os_scsi_tape_open(inode, filp);
- mutex_unlock(&osst_int_mutex);
- return ret;
-}
-
-
-
-/* Flush the tape buffer before close */
-static int os_scsi_tape_flush(struct file * filp, fl_owner_t id)
-{
- int result = 0, result2;
- struct osst_tape * STp = filp->private_data;
- struct st_modedef * STm = &(STp->modes[STp->current_mode]);
- struct st_partstat * STps = &(STp->ps[STp->partition]);
- struct osst_request * SRpnt = NULL;
- char * name = tape_name(STp);
-
- if (file_count(filp) > 1)
- return 0;
-
- if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) {
- STp->write_type = OS_WRITE_DATA;
- result = osst_flush_write_buffer(STp, &SRpnt);
- if (result != 0 && result != (-ENOSPC))
- goto out;
- }
- if ( STps->rw >= ST_WRITING && !STp->pos_unknown) {
-
-#if DEBUG
- if (debugging) {
- printk(OSST_DEB_MSG "%s:D: File length %ld bytes.\n",
- name, (long)(filp->f_pos));
- printk(OSST_DEB_MSG "%s:D: Async write waits %d, finished %d.\n",
- name, STp->nbr_waits, STp->nbr_finished);
- }
-#endif
- result = osst_write_trailer(STp, &SRpnt, !(STp->rew_at_close));
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Buffer flushed, %d EOF(s) written\n",
- name, 1+STp->two_fm);
-#endif
- }
- else if (!STp->rew_at_close) {
- STps = &(STp->ps[STp->partition]);
- if (!STm->sysv || STps->rw != ST_READING) {
- if (STp->can_bsr)
- result = osst_flush_buffer(STp, &SRpnt, 0); /* this is the default path */
- else if (STps->eof == ST_FM_HIT) {
- result = cross_eof(STp, &SRpnt, 0);
- if (result) {
- if (STps->drv_file >= 0)
- STps->drv_file++;
- STps->drv_block = 0;
- STps->eof = ST_FM;
- }
- else
- STps->eof = ST_NOEOF;
- }
- }
- else if ((STps->eof == ST_NOEOF &&
- !(result = cross_eof(STp, &SRpnt, 1))) ||
- STps->eof == ST_FM_HIT) {
- if (STps->drv_file >= 0)
- STps->drv_file++;
- STps->drv_block = 0;
- STps->eof = ST_FM;
- }
- }
-
-out:
- if (STp->rew_at_close) {
- result2 = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos);
- STps->drv_file = STps->drv_block = STp->frame_seq_number = STp->logical_blk_num = 0;
- if (result == 0 && result2 < 0)
- result = result2;
- }
- if (SRpnt) osst_release_request(SRpnt);
-
- if (STp->abort_count || STp->recover_count) {
- printk(KERN_INFO "%s:I:", name);
- if (STp->abort_count)
- printk(" %d unrecovered errors", STp->abort_count);
- if (STp->recover_count)
- printk(" %d recovered errors", STp->recover_count);
- if (STp->write_count)
- printk(" in %d frames written", STp->write_count);
- if (STp->read_count)
- printk(" in %d frames read", STp->read_count);
- printk("\n");
- STp->recover_count = 0;
- STp->abort_count = 0;
- }
- STp->write_count = 0;
- STp->read_count = 0;
-
- return result;
-}
-
-
-/* Close the device and release it */
-static int os_scsi_tape_close(struct inode * inode, struct file * filp)
-{
- int result = 0;
- struct osst_tape * STp = filp->private_data;
-
- if (STp->door_locked == ST_LOCKED_AUTO)
- do_door_lock(STp, 0);
-
- if (STp->raw)
- STp->header_ok = 0;
-
- normalize_buffer(STp->buffer);
- write_lock(&os_scsi_tapes_lock);
- STp->in_use = 0;
- write_unlock(&os_scsi_tapes_lock);
-
- scsi_device_put(STp->device);
-
- return result;
-}
-
-
-/* The ioctl command */
-static long osst_ioctl(struct file * file,
- unsigned int cmd_in, unsigned long arg)
-{
- int i, cmd_nr, cmd_type, blk, retval = 0;
- struct st_modedef * STm;
- struct st_partstat * STps;
- struct osst_request * SRpnt = NULL;
- struct osst_tape * STp = file->private_data;
- char * name = tape_name(STp);
- void __user * p = (void __user *)arg;
-
- mutex_lock(&osst_int_mutex);
- if (mutex_lock_interruptible(&STp->lock)) {
- mutex_unlock(&osst_int_mutex);
- return -ERESTARTSYS;
- }
-
-#if DEBUG
- if (debugging && !STp->in_use) {
- printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
- retval = (-EIO);
- goto out;
- }
-#endif
- STm = &(STp->modes[STp->current_mode]);
- STps = &(STp->ps[STp->partition]);
-
- /*
- * If we are in the middle of error recovery, don't let anyone
- * else try and use this device. Also, if error recovery fails, it
- * may try and take the device offline, in which case all further
- * access to the device is prohibited.
- */
- retval = scsi_ioctl_block_when_processing_errors(STp->device, cmd_in,
- file->f_flags & O_NDELAY);
- if (retval)
- goto out;
-
- cmd_type = _IOC_TYPE(cmd_in);
- cmd_nr = _IOC_NR(cmd_in);
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Ioctl %d,%d in %s mode\n", name,
- cmd_type, cmd_nr, STp->raw?"raw":"normal");
-#endif
- if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {
- struct mtop mtc;
- int auto_weof = 0;
-
- if (_IOC_SIZE(cmd_in) != sizeof(mtc)) {
- retval = (-EINVAL);
- goto out;
- }
-
- i = copy_from_user((char *) &mtc, p, sizeof(struct mtop));
- if (i) {
- retval = (-EFAULT);
- goto out;
- }
-
- if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) {
- printk(KERN_WARNING "%s:W: MTSETDRVBUFFER only allowed for root.\n", name);
- retval = (-EPERM);
- goto out;
- }
-
- if (!STm->defined && (mtc.mt_op != MTSETDRVBUFFER && (mtc.mt_count & MT_ST_OPTIONS) == 0)) {
- retval = (-ENXIO);
- goto out;
- }
-
- if (!STp->pos_unknown) {
-
- if (STps->eof == ST_FM_HIT) {
- if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM|| mtc.mt_op == MTEOM) {
- mtc.mt_count -= 1;
- if (STps->drv_file >= 0)
- STps->drv_file += 1;
- }
- else if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) {
- mtc.mt_count += 1;
- if (STps->drv_file >= 0)
- STps->drv_file += 1;
- }
- }
-
- if (mtc.mt_op == MTSEEK) {
- /* Old position must be restored if partition will be changed */
- i = !STp->can_partitions || (STp->new_partition != STp->partition);
- }
- else {
- i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
- mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM ||
- mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD ||
- mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM ||
- mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM ||
- mtc.mt_op == MTCOMPRESSION;
- }
- i = osst_flush_buffer(STp, &SRpnt, i);
- if (i < 0) {
- retval = i;
- goto out;
- }
- }
- else {
- /*
- * If there was a bus reset, block further access
- * to this device. If the user wants to rewind the tape,
- * then reset the flag and allow access again.
- */
- if(mtc.mt_op != MTREW &&
- mtc.mt_op != MTOFFL &&
- mtc.mt_op != MTRETEN &&
- mtc.mt_op != MTERASE &&
- mtc.mt_op != MTSEEK &&
- mtc.mt_op != MTEOM) {
- retval = (-EIO);
- goto out;
- }
- reset_state(STp);
- /* remove this when the midlevel properly clears was_reset */
- STp->device->was_reset = 0;
- }
-
- if (mtc.mt_op != MTCOMPRESSION && mtc.mt_op != MTLOCK &&
- mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK &&
- mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTSETDRVBUFFER &&
- mtc.mt_op != MTMKPART && mtc.mt_op != MTSETPART &&
- mtc.mt_op != MTWEOF && mtc.mt_op != MTWSM ) {
-
- /*
- * The user tells us to move to another position on the tape.
- * If we were appending to the tape content, that would leave
- * the tape without proper end, in that case write EOD and
- * update the header to reflect its position.
- */
-#if DEBUG
- printk(KERN_WARNING "%s:D: auto_weod %s at ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n", name,
- STps->rw >= ST_WRITING ? "write" : STps->rw == ST_READING ? "read" : "idle",
- STp->first_frame_position, STp->eod_frame_ppos, STp->frame_seq_number,
- STp->logical_blk_num, STps->drv_file, STps->drv_block );
-#endif
- if (STps->rw >= ST_WRITING && STp->first_frame_position >= STp->eod_frame_ppos) {
- auto_weof = ((STp->write_type != OS_WRITE_NEW_MARK) &&
- !(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL));
- i = osst_write_trailer(STp, &SRpnt,
- !(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL));
-#if DEBUG
- printk(KERN_WARNING "%s:D: post trailer xeof=%d,ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n",
- name, auto_weof, STp->first_frame_position, STp->eod_frame_ppos,
- STp->frame_seq_number, STp->logical_blk_num, STps->drv_file, STps->drv_block );
-#endif
- if (i < 0) {
- retval = i;
- goto out;
- }
- }
- STps->rw = ST_IDLE;
- }
-
- if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED)
- do_door_lock(STp, 0); /* Ignore result! */
-
- if (mtc.mt_op == MTSETDRVBUFFER &&
- (mtc.mt_count & MT_ST_OPTIONS) != 0) {
- retval = osst_set_options(STp, mtc.mt_count);
- goto out;
- }
-
- if (mtc.mt_op == MTSETPART) {
- if (mtc.mt_count >= STp->nbr_partitions)
- retval = -EINVAL;
- else {
- STp->new_partition = mtc.mt_count;
- retval = 0;
- }
- goto out;
- }
-
- if (mtc.mt_op == MTMKPART) {
- if (!STp->can_partitions) {
- retval = (-EINVAL);
- goto out;
- }
- if ((i = osst_int_ioctl(STp, &SRpnt, MTREW, 0)) < 0 /*||
- (i = partition_tape(inode, mtc.mt_count)) < 0*/) {
- retval = i;
- goto out;
- }
- for (i=0; i < ST_NBR_PARTITIONS; i++) {
- STp->ps[i].rw = ST_IDLE;
- STp->ps[i].at_sm = 0;
- STp->ps[i].last_block_valid = 0;
- }
- STp->partition = STp->new_partition = 0;
- STp->nbr_partitions = 1; /* Bad guess ?-) */
- STps->drv_block = STps->drv_file = 0;
- retval = 0;
- goto out;
- }
-
- if (mtc.mt_op == MTSEEK) {
- if (STp->raw)
- i = osst_set_frame_position(STp, &SRpnt, mtc.mt_count, 0);
- else
- i = osst_seek_sector(STp, &SRpnt, mtc.mt_count);
- if (!STp->can_partitions)
- STp->ps[0].rw = ST_IDLE;
- retval = i;
- goto out;
- }
-
- if (mtc.mt_op == MTLOCK || mtc.mt_op == MTUNLOCK) {
- retval = do_door_lock(STp, (mtc.mt_op == MTLOCK));
- goto out;
- }
-
- if (auto_weof)
- cross_eof(STp, &SRpnt, 0);
-
- if (mtc.mt_op == MTCOMPRESSION)
- retval = -EINVAL; /* OnStream drives don't have compression hardware */
- else
- /* MTBSF MTBSFM MTBSR MTBSS MTEOM MTERASE MTFSF MTFSFB MTFSR MTFSS
- * MTLOAD MTOFFL MTRESET MTRETEN MTREW MTUNLOAD MTWEOF MTWSM */
- retval = osst_int_ioctl(STp, &SRpnt, mtc.mt_op, mtc.mt_count);
- goto out;
- }
-
- if (!STm->defined) {
- retval = (-ENXIO);
- goto out;
- }
-
- if ((i = osst_flush_buffer(STp, &SRpnt, 0)) < 0) {
- retval = i;
- goto out;
- }
-
- if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) {
- struct mtget mt_status;
-
- if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) {
- retval = (-EINVAL);
- goto out;
- }
-
- mt_status.mt_type = MT_ISONSTREAM_SC;
- mt_status.mt_erreg = STp->recover_erreg << MT_ST_SOFTERR_SHIFT;
- mt_status.mt_dsreg =
- ((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) |
- ((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK);
- mt_status.mt_blkno = STps->drv_block;
- mt_status.mt_fileno = STps->drv_file;
- if (STp->block_size != 0) {
- if (STps->rw == ST_WRITING)
- mt_status.mt_blkno += (STp->buffer)->buffer_bytes / STp->block_size;
- else if (STps->rw == ST_READING)
- mt_status.mt_blkno -= ((STp->buffer)->buffer_bytes +
- STp->block_size - 1) / STp->block_size;
- }
-
- mt_status.mt_gstat = 0;
- if (STp->drv_write_prot)
- mt_status.mt_gstat |= GMT_WR_PROT(0xffffffff);
- if (mt_status.mt_blkno == 0) {
- if (mt_status.mt_fileno == 0)
- mt_status.mt_gstat |= GMT_BOT(0xffffffff);
- else
- mt_status.mt_gstat |= GMT_EOF(0xffffffff);
- }
- mt_status.mt_resid = STp->partition;
- if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR)
- mt_status.mt_gstat |= GMT_EOT(0xffffffff);
- else if (STps->eof >= ST_EOM_OK)
- mt_status.mt_gstat |= GMT_EOD(0xffffffff);
- if (STp->density == 1)
- mt_status.mt_gstat |= GMT_D_800(0xffffffff);
- else if (STp->density == 2)
- mt_status.mt_gstat |= GMT_D_1600(0xffffffff);
- else if (STp->density == 3)
- mt_status.mt_gstat |= GMT_D_6250(0xffffffff);
- if (STp->ready == ST_READY)
- mt_status.mt_gstat |= GMT_ONLINE(0xffffffff);
- if (STp->ready == ST_NO_TAPE)
- mt_status.mt_gstat |= GMT_DR_OPEN(0xffffffff);
- if (STps->at_sm)
- mt_status.mt_gstat |= GMT_SM(0xffffffff);
- if (STm->do_async_writes || (STm->do_buffer_writes && STp->block_size != 0) ||
- STp->drv_buffer != 0)
- mt_status.mt_gstat |= GMT_IM_REP_EN(0xffffffff);
-
- i = copy_to_user(p, &mt_status, sizeof(struct mtget));
- if (i) {
- retval = (-EFAULT);
- goto out;
- }
-
- STp->recover_erreg = 0; /* Clear after read */
- retval = 0;
- goto out;
- } /* End of MTIOCGET */
-
- if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) {
- struct mtpos mt_pos;
-
- if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos)) {
- retval = (-EINVAL);
- goto out;
- }
- if (STp->raw)
- blk = osst_get_frame_position(STp, &SRpnt);
- else
- blk = osst_get_sector(STp, &SRpnt);
- if (blk < 0) {
- retval = blk;
- goto out;
- }
- mt_pos.mt_blkno = blk;
- i = copy_to_user(p, &mt_pos, sizeof(struct mtpos));
- if (i)
- retval = -EFAULT;
- goto out;
- }
- if (SRpnt) osst_release_request(SRpnt);
-
- mutex_unlock(&STp->lock);
-
- retval = scsi_ioctl(STp->device, cmd_in, p);
- mutex_unlock(&osst_int_mutex);
- return retval;
-
-out:
- if (SRpnt) osst_release_request(SRpnt);
-
- mutex_unlock(&STp->lock);
- mutex_unlock(&osst_int_mutex);
-
- return retval;
-}
-
-#ifdef CONFIG_COMPAT
-static long osst_compat_ioctl(struct file * file, unsigned int cmd_in, unsigned long arg)
-{
- struct osst_tape *STp = file->private_data;
- struct scsi_device *sdev = STp->device;
- int ret = -ENOIOCTLCMD;
- if (sdev->host->hostt->compat_ioctl) {
-
- ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg);
-
- }
- return ret;
-}
-#endif
-
-
-
-/* Memory handling routines */
-
-/* Try to allocate a new tape buffer skeleton. Caller must not hold os_scsi_tapes_lock */
-static struct osst_buffer * new_tape_buffer( int from_initialization, int need_dma, int max_sg )
-{
- int i;
- gfp_t priority;
- struct osst_buffer *tb;
-
- if (from_initialization)
- priority = GFP_ATOMIC;
- else
- priority = GFP_KERNEL;
-
- i = sizeof(struct osst_buffer) + (osst_max_sg_segs - 1) * sizeof(struct scatterlist);
- tb = kzalloc(i, priority);
- if (!tb) {
- printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer.\n");
- return NULL;
- }
-
- tb->sg_segs = tb->orig_sg_segs = 0;
- tb->use_sg = max_sg;
- tb->in_use = 1;
- tb->dma = need_dma;
- tb->buffer_size = 0;
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG
- "osst :D: Allocated tape buffer skeleton (%d bytes, %d segments, dma: %d).\n",
- i, max_sg, need_dma);
-#endif
- return tb;
-}
-
-/* Try to allocate a temporary (while a user has the device open) enlarged tape buffer */
-static int enlarge_buffer(struct osst_buffer *STbuffer, int need_dma)
-{
- int segs, nbr, max_segs, b_size, order, got;
- gfp_t priority;
-
- if (STbuffer->buffer_size >= OS_FRAME_SIZE)
- return 1;
-
- if (STbuffer->sg_segs) {
- printk(KERN_WARNING "osst :A: Buffer not previously normalized.\n");
- normalize_buffer(STbuffer);
- }
- /* See how many segments we can use -- need at least two */
- nbr = max_segs = STbuffer->use_sg;
- if (nbr <= 2)
- return 0;
-
- priority = GFP_KERNEL /* | __GFP_NOWARN */;
- if (need_dma)
- priority |= GFP_DMA;
-
- /* Try to allocate the first segment up to OS_DATA_SIZE and the others
- big enough to reach the goal (code assumes no segments in place) */
- for (b_size = OS_DATA_SIZE, order = OSST_FIRST_ORDER; b_size >= PAGE_SIZE; order--, b_size /= 2) {
- struct page *page = alloc_pages(priority, order);
-
- STbuffer->sg[0].offset = 0;
- if (page != NULL) {
- sg_set_page(&STbuffer->sg[0], page, b_size, 0);
- STbuffer->b_data = page_address(page);
- break;
- }
- }
- if (sg_page(&STbuffer->sg[0]) == NULL) {
- printk(KERN_NOTICE "osst :I: Can't allocate tape buffer main segment.\n");
- return 0;
- }
- /* Got initial segment of 'bsize,order', continue with same size if possible, except for AUX */
- for (segs=STbuffer->sg_segs=1, got=b_size;
- segs < max_segs && got < OS_FRAME_SIZE; ) {
- struct page *page = alloc_pages(priority, (OS_FRAME_SIZE - got <= PAGE_SIZE) ? 0 : order);
- STbuffer->sg[segs].offset = 0;
- if (page == NULL) {
- printk(KERN_WARNING "osst :W: Failed to enlarge buffer to %d bytes.\n",
- OS_FRAME_SIZE);
-#if DEBUG
- STbuffer->buffer_size = got;
-#endif
- normalize_buffer(STbuffer);
- return 0;
- }
- sg_set_page(&STbuffer->sg[segs], page, (OS_FRAME_SIZE - got <= PAGE_SIZE / 2) ? (OS_FRAME_SIZE - got) : b_size, 0);
- got += STbuffer->sg[segs].length;
- STbuffer->buffer_size = got;
- STbuffer->sg_segs = ++segs;
- }
-#if DEBUG
- if (debugging) {
- printk(OSST_DEB_MSG
- "osst :D: Expanded tape buffer (%d bytes, %d->%d segments, dma: %d, at: %p).\n",
- got, STbuffer->orig_sg_segs, STbuffer->sg_segs, need_dma, STbuffer->b_data);
- printk(OSST_DEB_MSG
- "osst :D: segment sizes: first %d at %p, last %d bytes at %p.\n",
- STbuffer->sg[0].length, page_address(STbuffer->sg[0].page),
- STbuffer->sg[segs-1].length, page_address(STbuffer->sg[segs-1].page));
- }
-#endif
-
- return 1;
-}
-
-
-/* Release the segments */
-static void normalize_buffer(struct osst_buffer *STbuffer)
-{
- int i, order, b_size;
-
- for (i=0; i < STbuffer->sg_segs; i++) {
-
- for (b_size = PAGE_SIZE, order = 0;
- b_size < STbuffer->sg[i].length;
- b_size *= 2, order++);
-
- __free_pages(sg_page(&STbuffer->sg[i]), order);
- STbuffer->buffer_size -= STbuffer->sg[i].length;
- }
-#if DEBUG
- if (debugging && STbuffer->orig_sg_segs < STbuffer->sg_segs)
- printk(OSST_DEB_MSG "osst :D: Buffer at %p normalized to %d bytes (segs %d).\n",
- STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs);
-#endif
- STbuffer->sg_segs = STbuffer->orig_sg_segs = 0;
-}
-
-
-/* Move data from the user buffer to the tape buffer. Returns zero (success) or
- negative error code. */
-static int append_to_buffer(const char __user *ubp, struct osst_buffer *st_bp, int do_count)
-{
- int i, cnt, res, offset;
-
- for (i=0, offset=st_bp->buffer_bytes;
- i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
- offset -= st_bp->sg[i].length;
- if (i == st_bp->sg_segs) { /* Should never happen */
- printk(KERN_WARNING "osst :A: Append_to_buffer offset overflow.\n");
- return (-EIO);
- }
- for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
- cnt = st_bp->sg[i].length - offset < do_count ?
- st_bp->sg[i].length - offset : do_count;
- res = copy_from_user(page_address(sg_page(&st_bp->sg[i])) + offset, ubp, cnt);
- if (res)
- return (-EFAULT);
- do_count -= cnt;
- st_bp->buffer_bytes += cnt;
- ubp += cnt;
- offset = 0;
- }
- if (do_count) { /* Should never happen */
- printk(KERN_WARNING "osst :A: Append_to_buffer overflow (left %d).\n",
- do_count);
- return (-EIO);
- }
- return 0;
-}
-
-
-/* Move data from the tape buffer to the user buffer. Returns zero (success) or
- negative error code. */
-static int from_buffer(struct osst_buffer *st_bp, char __user *ubp, int do_count)
-{
- int i, cnt, res, offset;
-
- for (i=0, offset=st_bp->read_pointer;
- i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
- offset -= st_bp->sg[i].length;
- if (i == st_bp->sg_segs) { /* Should never happen */
- printk(KERN_WARNING "osst :A: From_buffer offset overflow.\n");
- return (-EIO);
- }
- for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
- cnt = st_bp->sg[i].length - offset < do_count ?
- st_bp->sg[i].length - offset : do_count;
- res = copy_to_user(ubp, page_address(sg_page(&st_bp->sg[i])) + offset, cnt);
- if (res)
- return (-EFAULT);
- do_count -= cnt;
- st_bp->buffer_bytes -= cnt;
- st_bp->read_pointer += cnt;
- ubp += cnt;
- offset = 0;
- }
- if (do_count) { /* Should never happen */
- printk(KERN_WARNING "osst :A: From_buffer overflow (left %d).\n", do_count);
- return (-EIO);
- }
- return 0;
-}
-
-/* Sets the tail of the buffer after fill point to zero.
- Returns zero (success) or negative error code. */
-static int osst_zero_buffer_tail(struct osst_buffer *st_bp)
-{
- int i, offset, do_count, cnt;
-
- for (i = 0, offset = st_bp->buffer_bytes;
- i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
- offset -= st_bp->sg[i].length;
- if (i == st_bp->sg_segs) { /* Should never happen */
- printk(KERN_WARNING "osst :A: Zero_buffer offset overflow.\n");
- return (-EIO);
- }
- for (do_count = OS_DATA_SIZE - st_bp->buffer_bytes;
- i < st_bp->sg_segs && do_count > 0; i++) {
- cnt = st_bp->sg[i].length - offset < do_count ?
- st_bp->sg[i].length - offset : do_count ;
- memset(page_address(sg_page(&st_bp->sg[i])) + offset, 0, cnt);
- do_count -= cnt;
- offset = 0;
- }
- if (do_count) { /* Should never happen */
- printk(KERN_WARNING "osst :A: Zero_buffer overflow (left %d).\n", do_count);
- return (-EIO);
- }
- return 0;
-}
-
-/* Copy a osst 32K chunk of memory into the buffer.
- Returns zero (success) or negative error code. */
-static int osst_copy_to_buffer(struct osst_buffer *st_bp, unsigned char *ptr)
-{
- int i, cnt, do_count = OS_DATA_SIZE;
-
- for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
- cnt = st_bp->sg[i].length < do_count ?
- st_bp->sg[i].length : do_count ;
- memcpy(page_address(sg_page(&st_bp->sg[i])), ptr, cnt);
- do_count -= cnt;
- ptr += cnt;
- }
- if (do_count || i != st_bp->sg_segs-1) { /* Should never happen */
- printk(KERN_WARNING "osst :A: Copy_to_buffer overflow (left %d at sg %d).\n",
- do_count, i);
- return (-EIO);
- }
- return 0;
-}
-
-/* Copy a osst 32K chunk of memory from the buffer.
- Returns zero (success) or negative error code. */
-static int osst_copy_from_buffer(struct osst_buffer *st_bp, unsigned char *ptr)
-{
- int i, cnt, do_count = OS_DATA_SIZE;
-
- for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
- cnt = st_bp->sg[i].length < do_count ?
- st_bp->sg[i].length : do_count ;
- memcpy(ptr, page_address(sg_page(&st_bp->sg[i])), cnt);
- do_count -= cnt;
- ptr += cnt;
- }
- if (do_count || i != st_bp->sg_segs-1) { /* Should never happen */
- printk(KERN_WARNING "osst :A: Copy_from_buffer overflow (left %d at sg %d).\n",
- do_count, i);
- return (-EIO);
- }
- return 0;
-}
-
-
-/* Module housekeeping */
-
-static void validate_options (void)
-{
- if (max_dev > 0)
- osst_max_dev = max_dev;
- if (write_threshold_kbs > 0)
- osst_write_threshold = write_threshold_kbs * ST_KILOBYTE;
- if (osst_write_threshold > osst_buffer_size)
- osst_write_threshold = osst_buffer_size;
- if (max_sg_segs >= OSST_FIRST_SG)
- osst_max_sg_segs = max_sg_segs;
-#if DEBUG
- printk(OSST_DEB_MSG "osst :D: max tapes %d, write threshold %d, max s/g segs %d.\n",
- osst_max_dev, osst_write_threshold, osst_max_sg_segs);
-#endif
-}
-
-#ifndef MODULE
-/* Set the boot options. Syntax: osst=xxx,yyy,...
- where xxx is write threshold in 1024 byte blocks,
- and yyy is number of s/g segments to use. */
-static int __init osst_setup (char *str)
-{
- int i, ints[5];
- char *stp;
-
- stp = get_options(str, ARRAY_SIZE(ints), ints);
-
- if (ints[0] > 0) {
- for (i = 0; i < ints[0] && i < ARRAY_SIZE(parms); i++)
- *parms[i].val = ints[i + 1];
- } else {
- while (stp != NULL) {
- for (i = 0; i < ARRAY_SIZE(parms); i++) {
- int len = strlen(parms[i].name);
- if (!strncmp(stp, parms[i].name, len) &&
- (*(stp + len) == ':' || *(stp + len) == '=')) {
- *parms[i].val =
- simple_strtoul(stp + len + 1, NULL, 0);
- break;
- }
- }
- if (i >= ARRAY_SIZE(parms))
- printk(KERN_INFO "osst :I: Illegal parameter in '%s'\n",
- stp);
- stp = strchr(stp, ',');
- if (stp)
- stp++;
- }
- }
-
- return 1;
-}
-
-__setup("osst=", osst_setup);
-
-#endif
-
-static const struct file_operations osst_fops = {
- .owner = THIS_MODULE,
- .read = osst_read,
- .write = osst_write,
- .unlocked_ioctl = osst_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = osst_compat_ioctl,
-#endif
- .open = os_scsi_tape_open,
- .flush = os_scsi_tape_flush,
- .release = os_scsi_tape_close,
- .llseek = noop_llseek,
-};
-
-static int osst_supports(struct scsi_device * SDp)
-{
- struct osst_support_data {
- char *vendor;
- char *model;
- char *rev;
- char *driver_hint; /* Name of the correct driver, NULL if unknown */
- };
-
-static struct osst_support_data support_list[] = {
- /* {"XXX", "Yy-", "", NULL}, example */
- SIGS_FROM_OSST,
- {NULL, }};
-
- struct osst_support_data *rp;
-
- /* We are willing to drive OnStream SC-x0 as well as the
- * * IDE, ParPort, FireWire, USB variants, if accessible by
- * * emulation layer (ide-scsi, usb-storage, ...) */
-
- for (rp=&(support_list[0]); rp->vendor != NULL; rp++)
- if (!strncmp(rp->vendor, SDp->vendor, strlen(rp->vendor)) &&
- !strncmp(rp->model, SDp->model, strlen(rp->model)) &&
- !strncmp(rp->rev, SDp->rev, strlen(rp->rev)))
- return 1;
- return 0;
-}
-
-/*
- * sysfs support for osst driver parameter information
- */
-
-static ssize_t version_show(struct device_driver *ddd, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%s\n", osst_version);
-}
-
-static DRIVER_ATTR_RO(version);
-
-static int osst_create_sysfs_files(struct device_driver *sysfs)
-{
- return driver_create_file(sysfs, &driver_attr_version);
-}
-
-static void osst_remove_sysfs_files(struct device_driver *sysfs)
-{
- driver_remove_file(sysfs, &driver_attr_version);
-}
-
-/*
- * sysfs support for accessing ADR header information
- */
-
-static ssize_t osst_adr_rev_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
- ssize_t l = 0;
-
- if (STp && STp->header_ok && STp->linux_media)
- l = snprintf(buf, PAGE_SIZE, "%d.%d\n", STp->header_cache->major_rev, STp->header_cache->minor_rev);
- return l;
-}
-
-DEVICE_ATTR(ADR_rev, S_IRUGO, osst_adr_rev_show, NULL);
-
-static ssize_t osst_linux_media_version_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
- ssize_t l = 0;
-
- if (STp && STp->header_ok && STp->linux_media)
- l = snprintf(buf, PAGE_SIZE, "LIN%d\n", STp->linux_media_version);
- return l;
-}
-
-DEVICE_ATTR(media_version, S_IRUGO, osst_linux_media_version_show, NULL);
-
-static ssize_t osst_capacity_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
- ssize_t l = 0;
-
- if (STp && STp->header_ok && STp->linux_media)
- l = snprintf(buf, PAGE_SIZE, "%d\n", STp->capacity);
- return l;
-}
-
-DEVICE_ATTR(capacity, S_IRUGO, osst_capacity_show, NULL);
-
-static ssize_t osst_first_data_ppos_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
- ssize_t l = 0;
-
- if (STp && STp->header_ok && STp->linux_media)
- l = snprintf(buf, PAGE_SIZE, "%d\n", STp->first_data_ppos);
- return l;
-}
-
-DEVICE_ATTR(BOT_frame, S_IRUGO, osst_first_data_ppos_show, NULL);
-
-static ssize_t osst_eod_frame_ppos_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
- ssize_t l = 0;
-
- if (STp && STp->header_ok && STp->linux_media)
- l = snprintf(buf, PAGE_SIZE, "%d\n", STp->eod_frame_ppos);
- return l;
-}
-
-DEVICE_ATTR(EOD_frame, S_IRUGO, osst_eod_frame_ppos_show, NULL);
-
-static ssize_t osst_filemark_cnt_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
- ssize_t l = 0;
-
- if (STp && STp->header_ok && STp->linux_media)
- l = snprintf(buf, PAGE_SIZE, "%d\n", STp->filemark_cnt);
- return l;
-}
-
-DEVICE_ATTR(file_count, S_IRUGO, osst_filemark_cnt_show, NULL);
-
-static struct class *osst_sysfs_class;
-
-static int osst_sysfs_init(void)
-{
- osst_sysfs_class = class_create(THIS_MODULE, "onstream_tape");
- if (IS_ERR(osst_sysfs_class)) {
- printk(KERN_ERR "osst :W: Unable to register sysfs class\n");
- return PTR_ERR(osst_sysfs_class);
- }
-
- return 0;
-}
-
-static void osst_sysfs_destroy(dev_t dev)
-{
- device_destroy(osst_sysfs_class, dev);
-}
-
-static int osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * STp, char * name)
-{
- struct device *osst_member;
- int err;
-
- osst_member = device_create(osst_sysfs_class, device, dev, STp,
- "%s", name);
- if (IS_ERR(osst_member)) {
- printk(KERN_WARNING "osst :W: Unable to add sysfs class member %s\n", name);
- return PTR_ERR(osst_member);
- }
-
- err = device_create_file(osst_member, &dev_attr_ADR_rev);
- if (err)
- goto err_out;
- err = device_create_file(osst_member, &dev_attr_media_version);
- if (err)
- goto err_out;
- err = device_create_file(osst_member, &dev_attr_capacity);
- if (err)
- goto err_out;
- err = device_create_file(osst_member, &dev_attr_BOT_frame);
- if (err)
- goto err_out;
- err = device_create_file(osst_member, &dev_attr_EOD_frame);
- if (err)
- goto err_out;
- err = device_create_file(osst_member, &dev_attr_file_count);
- if (err)
- goto err_out;
-
- return 0;
-
-err_out:
- osst_sysfs_destroy(dev);
- return err;
-}
-
-static void osst_sysfs_cleanup(void)
-{
- class_destroy(osst_sysfs_class);
-}
-
-/*
- * osst startup / cleanup code
- */
-
-static int osst_probe(struct device *dev)
-{
- struct scsi_device * SDp = to_scsi_device(dev);
- struct osst_tape * tpnt;
- struct st_modedef * STm;
- struct st_partstat * STps;
- struct osst_buffer * buffer;
- struct gendisk * drive;
- int i, dev_num, err = -ENODEV;
-
- if (SDp->type != TYPE_TAPE || !osst_supports(SDp))
- return -ENODEV;
-
- drive = alloc_disk(1);
- if (!drive) {
- printk(KERN_ERR "osst :E: Out of memory. Device not attached.\n");
- return -ENODEV;
- }
-
- /* if this is the first attach, build the infrastructure */
- write_lock(&os_scsi_tapes_lock);
- if (os_scsi_tapes == NULL) {
- os_scsi_tapes = kmalloc_array(osst_max_dev,
- sizeof(struct osst_tape *),
- GFP_ATOMIC);
- if (os_scsi_tapes == NULL) {
- write_unlock(&os_scsi_tapes_lock);
- printk(KERN_ERR "osst :E: Unable to allocate array for OnStream SCSI tapes.\n");
- goto out_put_disk;
- }
- for (i=0; i < osst_max_dev; ++i) os_scsi_tapes[i] = NULL;
- }
-
- if (osst_nr_dev >= osst_max_dev) {
- write_unlock(&os_scsi_tapes_lock);
- printk(KERN_ERR "osst :E: Too many tape devices (max. %d).\n", osst_max_dev);
- goto out_put_disk;
- }
-
- /* find a free minor number */
- for (i = 0; i < osst_max_dev && os_scsi_tapes[i]; i++)
- ;
- if(i >= osst_max_dev) panic ("Scsi_devices corrupt (osst)");
- dev_num = i;
-
- /* allocate a struct osst_tape for this device */
- tpnt = kzalloc(sizeof(struct osst_tape), GFP_ATOMIC);
- if (!tpnt) {
- write_unlock(&os_scsi_tapes_lock);
- printk(KERN_ERR "osst :E: Can't allocate device descriptor, device not attached.\n");
- goto out_put_disk;
- }
-
- /* allocate a buffer for this device */
- i = SDp->host->sg_tablesize;
- if (osst_max_sg_segs < i)
- i = osst_max_sg_segs;
- buffer = new_tape_buffer(1, SDp->host->unchecked_isa_dma, i);
- if (buffer == NULL) {
- write_unlock(&os_scsi_tapes_lock);
- printk(KERN_ERR "osst :E: Unable to allocate a tape buffer, device not attached.\n");
- kfree(tpnt);
- goto out_put_disk;
- }
- os_scsi_tapes[dev_num] = tpnt;
- tpnt->buffer = buffer;
- tpnt->device = SDp;
- drive->private_data = &tpnt->driver;
- sprintf(drive->disk_name, "osst%d", dev_num);
- tpnt->driver = &osst_template;
- tpnt->drive = drive;
- tpnt->in_use = 0;
- tpnt->capacity = 0xfffff;
- tpnt->dirty = 0;
- tpnt->drv_buffer = 1; /* Try buffering if no mode sense */
- tpnt->restr_dma = (SDp->host)->unchecked_isa_dma;
- tpnt->density = 0;
- tpnt->do_auto_lock = OSST_AUTO_LOCK;
- tpnt->can_bsr = OSST_IN_FILE_POS;
- tpnt->can_partitions = 0;
- tpnt->two_fm = OSST_TWO_FM;
- tpnt->fast_mteom = OSST_FAST_MTEOM;
- tpnt->scsi2_logical = OSST_SCSI2LOGICAL; /* FIXME */
- tpnt->write_threshold = osst_write_threshold;
- tpnt->default_drvbuffer = 0xff; /* No forced buffering */
- tpnt->partition = 0;
- tpnt->new_partition = 0;
- tpnt->nbr_partitions = 0;
- tpnt->min_block = 512;
- tpnt->max_block = OS_DATA_SIZE;
- tpnt->timeout = OSST_TIMEOUT;
- tpnt->long_timeout = OSST_LONG_TIMEOUT;
-
- /* Recognize OnStream tapes */
- /* We don't need to test for OnStream, as this has been done in detect () */
- tpnt->os_fw_rev = osst_parse_firmware_rev (SDp->rev);
- tpnt->omit_blklims = 1;
-
- tpnt->poll = (strncmp(SDp->model, "DI-", 3) == 0) ||
- (strncmp(SDp->model, "FW-", 3) == 0) || OSST_FW_NEED_POLL(tpnt->os_fw_rev,SDp);
- tpnt->frame_in_buffer = 0;
- tpnt->header_ok = 0;
- tpnt->linux_media = 0;
- tpnt->header_cache = NULL;
-
- for (i=0; i < ST_NBR_MODES; i++) {
- STm = &(tpnt->modes[i]);
- STm->defined = 0;
- STm->sysv = OSST_SYSV;
- STm->defaults_for_writes = 0;
- STm->do_async_writes = OSST_ASYNC_WRITES;
- STm->do_buffer_writes = OSST_BUFFER_WRITES;
- STm->do_read_ahead = OSST_READ_AHEAD;
- STm->default_compression = ST_DONT_TOUCH;
- STm->default_blksize = 512;
- STm->default_density = (-1); /* No forced density */
- }
-
- for (i=0; i < ST_NBR_PARTITIONS; i++) {
- STps = &(tpnt->ps[i]);
- STps->rw = ST_IDLE;
- STps->eof = ST_NOEOF;
- STps->at_sm = 0;
- STps->last_block_valid = 0;
- STps->drv_block = (-1);
- STps->drv_file = (-1);
- }
-
- tpnt->current_mode = 0;
- tpnt->modes[0].defined = 1;
- tpnt->modes[2].defined = 1;
- tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = 0;
-
- mutex_init(&tpnt->lock);
- osst_nr_dev++;
- write_unlock(&os_scsi_tapes_lock);
-
- {
- char name[8];
-
- /* Rewind entry */
- err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num), dev, tpnt, tape_name(tpnt));
- if (err)
- goto out_free_buffer;
-
- /* No-rewind entry */
- snprintf(name, 8, "%s%s", "n", tape_name(tpnt));
- err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num + 128), dev, tpnt, name);
- if (err)
- goto out_free_sysfs1;
- }
-
- sdev_printk(KERN_INFO, SDp,
- "osst :I: Attached OnStream %.5s tape as %s\n",
- SDp->model, tape_name(tpnt));
-
- return 0;
-
-out_free_sysfs1:
- osst_sysfs_destroy(MKDEV(OSST_MAJOR, dev_num));
-out_free_buffer:
- kfree(buffer);
-out_put_disk:
- put_disk(drive);
- return err;
-};
-
-static int osst_remove(struct device *dev)
-{
- struct scsi_device * SDp = to_scsi_device(dev);
- struct osst_tape * tpnt;
- int i;
-
- if ((SDp->type != TYPE_TAPE) || (osst_nr_dev <= 0))
- return 0;
-
- write_lock(&os_scsi_tapes_lock);
- for(i=0; i < osst_max_dev; i++) {
- if((tpnt = os_scsi_tapes[i]) && (tpnt->device == SDp)) {
- osst_sysfs_destroy(MKDEV(OSST_MAJOR, i));
- osst_sysfs_destroy(MKDEV(OSST_MAJOR, i+128));
- tpnt->device = NULL;
- put_disk(tpnt->drive);
- os_scsi_tapes[i] = NULL;
- osst_nr_dev--;
- write_unlock(&os_scsi_tapes_lock);
- vfree(tpnt->header_cache);
- if (tpnt->buffer) {
- normalize_buffer(tpnt->buffer);
- kfree(tpnt->buffer);
- }
- kfree(tpnt);
- return 0;
- }
- }
- write_unlock(&os_scsi_tapes_lock);
- return 0;
-}
-
-static int __init init_osst(void)
-{
- int err;
-
- printk(KERN_INFO "osst :I: Tape driver with OnStream support version %s\nosst :I: %s\n", osst_version, cvsid);
-
- validate_options();
-
- err = osst_sysfs_init();
- if (err)
- return err;
-
- err = register_chrdev(OSST_MAJOR, "osst", &osst_fops);
- if (err < 0) {
- printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n", OSST_MAJOR);
- goto err_out;
- }
-
- err = scsi_register_driver(&osst_template.gendrv);
- if (err)
- goto err_out_chrdev;
-
- err = osst_create_sysfs_files(&osst_template.gendrv);
- if (err)
- goto err_out_scsidrv;
-
- return 0;
-
-err_out_scsidrv:
- scsi_unregister_driver(&osst_template.gendrv);
-err_out_chrdev:
- unregister_chrdev(OSST_MAJOR, "osst");
-err_out:
- osst_sysfs_cleanup();
- return err;
-}
-
-static void __exit exit_osst (void)
-{
- int i;
- struct osst_tape * STp;
-
- osst_remove_sysfs_files(&osst_template.gendrv);
- scsi_unregister_driver(&osst_template.gendrv);
- unregister_chrdev(OSST_MAJOR, "osst");
- osst_sysfs_cleanup();
-
- if (os_scsi_tapes) {
- for (i=0; i < osst_max_dev; ++i) {
- if (!(STp = os_scsi_tapes[i])) continue;
- /* This is defensive, supposed to happen during detach */
- vfree(STp->header_cache);
- if (STp->buffer) {
- normalize_buffer(STp->buffer);
- kfree(STp->buffer);
- }
- put_disk(STp->drive);
- kfree(STp);
- }
- kfree(os_scsi_tapes);
- }
- printk(KERN_INFO "osst :I: Unloaded.\n");
-}
-
-module_init(init_osst);
-module_exit(exit_osst);
diff --git a/drivers/scsi/osst.h b/drivers/scsi/osst.h
deleted file mode 100644
index b90ae280853d..000000000000
--- a/drivers/scsi/osst.h
+++ /dev/null
@@ -1,651 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * $Header: /cvsroot/osst/Driver/osst.h,v 1.16 2005/01/01 21:13:35 wriede Exp $
- */
-
-#include <asm/byteorder.h>
-#include <linux/completion.h>
-#include <linux/mutex.h>
-
-/* FIXME - rename and use the following two types or delete them!
- * and the types really should go to st.h anyway...
- * INQUIRY packet command - Data Format (From Table 6-8 of QIC-157C)
- */
-typedef struct {
- unsigned device_type :5; /* Peripheral Device Type */
- unsigned reserved0_765 :3; /* Peripheral Qualifier - Reserved */
- unsigned reserved1_6t0 :7; /* Reserved */
- unsigned rmb :1; /* Removable Medium Bit */
- unsigned ansi_version :3; /* ANSI Version */
- unsigned ecma_version :3; /* ECMA Version */
- unsigned iso_version :2; /* ISO Version */
- unsigned response_format :4; /* Response Data Format */
- unsigned reserved3_45 :2; /* Reserved */
- unsigned reserved3_6 :1; /* TrmIOP - Reserved */
- unsigned reserved3_7 :1; /* AENC - Reserved */
- u8 additional_length; /* Additional Length (total_length-4) */
- u8 rsv5, rsv6, rsv7; /* Reserved */
- u8 vendor_id[8]; /* Vendor Identification */
- u8 product_id[16]; /* Product Identification */
- u8 revision_level[4]; /* Revision Level */
- u8 vendor_specific[20]; /* Vendor Specific - Optional */
- u8 reserved56t95[40]; /* Reserved - Optional */
- /* Additional information may be returned */
-} idetape_inquiry_result_t;
-
-/*
- * READ POSITION packet command - Data Format (From Table 6-57)
- */
-typedef struct {
- unsigned reserved0_10 :2; /* Reserved */
- unsigned bpu :1; /* Block Position Unknown */
- unsigned reserved0_543 :3; /* Reserved */
- unsigned eop :1; /* End Of Partition */
- unsigned bop :1; /* Beginning Of Partition */
- u8 partition; /* Partition Number */
- u8 reserved2, reserved3; /* Reserved */
- u32 first_block; /* First Block Location */
- u32 last_block; /* Last Block Location (Optional) */
- u8 reserved12; /* Reserved */
- u8 blocks_in_buffer[3]; /* Blocks In Buffer - (Optional) */
- u32 bytes_in_buffer; /* Bytes In Buffer (Optional) */
-} idetape_read_position_result_t;
-
-/*
- * Follows structures which are related to the SELECT SENSE / MODE SENSE
- * packet commands.
- */
-#define COMPRESSION_PAGE 0x0f
-#define COMPRESSION_PAGE_LENGTH 16
-
-#define CAPABILITIES_PAGE 0x2a
-#define CAPABILITIES_PAGE_LENGTH 20
-
-#define TAPE_PARAMTR_PAGE 0x2b
-#define TAPE_PARAMTR_PAGE_LENGTH 16
-
-#define NUMBER_RETRIES_PAGE 0x2f
-#define NUMBER_RETRIES_PAGE_LENGTH 4
-
-#define BLOCK_SIZE_PAGE 0x30
-#define BLOCK_SIZE_PAGE_LENGTH 4
-
-#define BUFFER_FILLING_PAGE 0x33
-#define BUFFER_FILLING_PAGE_LENGTH 4
-
-#define VENDOR_IDENT_PAGE 0x36
-#define VENDOR_IDENT_PAGE_LENGTH 8
-
-#define LOCATE_STATUS_PAGE 0x37
-#define LOCATE_STATUS_PAGE_LENGTH 0
-
-#define MODE_HEADER_LENGTH 4
-
-
-/*
- * REQUEST SENSE packet command result - Data Format.
- */
-typedef struct {
- unsigned error_code :7; /* Current of deferred errors */
- unsigned valid :1; /* The information field conforms to QIC-157C */
- u8 reserved1 :8; /* Segment Number - Reserved */
- unsigned sense_key :4; /* Sense Key */
- unsigned reserved2_4 :1; /* Reserved */
- unsigned ili :1; /* Incorrect Length Indicator */
- unsigned eom :1; /* End Of Medium */
- unsigned filemark :1; /* Filemark */
- u32 information __attribute__ ((packed));
- u8 asl; /* Additional sense length (n-7) */
- u32 command_specific; /* Additional command specific information */
- u8 asc; /* Additional Sense Code */
- u8 ascq; /* Additional Sense Code Qualifier */
- u8 replaceable_unit_code; /* Field Replaceable Unit Code */
- unsigned sk_specific1 :7; /* Sense Key Specific */
- unsigned sksv :1; /* Sense Key Specific information is valid */
- u8 sk_specific2; /* Sense Key Specific */
- u8 sk_specific3; /* Sense Key Specific */
- u8 pad[2]; /* Padding to 20 bytes */
-} idetape_request_sense_result_t;
-
-/*
- * Mode Parameter Header for the MODE SENSE packet command
- */
-typedef struct {
- u8 mode_data_length; /* Length of the following data transfer */
- u8 medium_type; /* Medium Type */
- u8 dsp; /* Device Specific Parameter */
- u8 bdl; /* Block Descriptor Length */
-} osst_mode_parameter_header_t;
-
-/*
- * Mode Parameter Block Descriptor the MODE SENSE packet command
- *
- * Support for block descriptors is optional.
- */
-typedef struct {
- u8 density_code; /* Medium density code */
- u8 blocks[3]; /* Number of blocks */
- u8 reserved4; /* Reserved */
- u8 length[3]; /* Block Length */
-} osst_parameter_block_descriptor_t;
-
-/*
- * The Data Compression Page, as returned by the MODE SENSE packet command.
- */
-typedef struct {
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned ps :1;
- unsigned reserved0 :1; /* Reserved */
- unsigned page_code :6; /* Page Code - Should be 0xf */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned page_code :6; /* Page Code - Should be 0xf */
- unsigned reserved0 :1; /* Reserved */
- unsigned ps :1;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
- u8 page_length; /* Page Length - Should be 14 */
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned dce :1; /* Data Compression Enable */
- unsigned dcc :1; /* Data Compression Capable */
- unsigned reserved2 :6; /* Reserved */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned reserved2 :6; /* Reserved */
- unsigned dcc :1; /* Data Compression Capable */
- unsigned dce :1; /* Data Compression Enable */
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned dde :1; /* Data Decompression Enable */
- unsigned red :2; /* Report Exception on Decompression */
- unsigned reserved3 :5; /* Reserved */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned reserved3 :5; /* Reserved */
- unsigned red :2; /* Report Exception on Decompression */
- unsigned dde :1; /* Data Decompression Enable */
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
- u32 ca; /* Compression Algorithm */
- u32 da; /* Decompression Algorithm */
- u8 reserved[4]; /* Reserved */
-} osst_data_compression_page_t;
-
-/*
- * The Medium Partition Page, as returned by the MODE SENSE packet command.
- */
-typedef struct {
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned ps :1;
- unsigned reserved1_6 :1; /* Reserved */
- unsigned page_code :6; /* Page Code - Should be 0x11 */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned page_code :6; /* Page Code - Should be 0x11 */
- unsigned reserved1_6 :1; /* Reserved */
- unsigned ps :1;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
- u8 page_length; /* Page Length - Should be 6 */
- u8 map; /* Maximum Additional Partitions - Should be 0 */
- u8 apd; /* Additional Partitions Defined - Should be 0 */
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned fdp :1; /* Fixed Data Partitions */
- unsigned sdp :1; /* Should be 0 */
- unsigned idp :1; /* Should be 0 */
- unsigned psum :2; /* Should be 0 */
- unsigned reserved4_012 :3; /* Reserved */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned reserved4_012 :3; /* Reserved */
- unsigned psum :2; /* Should be 0 */
- unsigned idp :1; /* Should be 0 */
- unsigned sdp :1; /* Should be 0 */
- unsigned fdp :1; /* Fixed Data Partitions */
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
- u8 mfr; /* Medium Format Recognition */
- u8 reserved[2]; /* Reserved */
-} osst_medium_partition_page_t;
-
-/*
- * Capabilities and Mechanical Status Page
- */
-typedef struct {
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned reserved1_67 :2;
- unsigned page_code :6; /* Page code - Should be 0x2a */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned page_code :6; /* Page code - Should be 0x2a */
- unsigned reserved1_67 :2;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
- u8 page_length; /* Page Length - Should be 0x12 */
- u8 reserved2, reserved3;
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned reserved4_67 :2;
- unsigned sprev :1; /* Supports SPACE in the reverse direction */
- unsigned reserved4_1234 :4;
- unsigned ro :1; /* Read Only Mode */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned ro :1; /* Read Only Mode */
- unsigned reserved4_1234 :4;
- unsigned sprev :1; /* Supports SPACE in the reverse direction */
- unsigned reserved4_67 :2;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned reserved5_67 :2;
- unsigned qfa :1; /* Supports the QFA two partition formats */
- unsigned reserved5_4 :1;
- unsigned efmt :1; /* Supports ERASE command initiated formatting */
- unsigned reserved5_012 :3;
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned reserved5_012 :3;
- unsigned efmt :1; /* Supports ERASE command initiated formatting */
- unsigned reserved5_4 :1;
- unsigned qfa :1; /* Supports the QFA two partition formats */
- unsigned reserved5_67 :2;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned cmprs :1; /* Supports data compression */
- unsigned ecc :1; /* Supports error correction */
- unsigned reserved6_45 :2; /* Reserved */
- unsigned eject :1; /* The device can eject the volume */
- unsigned prevent :1; /* The device defaults in the prevent state after power up */
- unsigned locked :1; /* The volume is locked */
- unsigned lock :1; /* Supports locking the volume */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned lock :1; /* Supports locking the volume */
- unsigned locked :1; /* The volume is locked */
- unsigned prevent :1; /* The device defaults in the prevent state after power up */
- unsigned eject :1; /* The device can eject the volume */
- unsigned reserved6_45 :2; /* Reserved */
- unsigned ecc :1; /* Supports error correction */
- unsigned cmprs :1; /* Supports data compression */
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned blk32768 :1; /* slowb - the device restricts the byte count for PIO */
- /* transfers for slow buffer memory ??? */
- /* Also 32768 block size in some cases */
- unsigned reserved7_3_6 :4;
- unsigned blk1024 :1; /* Supports 1024 bytes block size */
- unsigned blk512 :1; /* Supports 512 bytes block size */
- unsigned reserved7_0 :1;
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned reserved7_0 :1;
- unsigned blk512 :1; /* Supports 512 bytes block size */
- unsigned blk1024 :1; /* Supports 1024 bytes block size */
- unsigned reserved7_3_6 :4;
- unsigned blk32768 :1; /* slowb - the device restricts the byte count for PIO */
- /* transfers for slow buffer memory ??? */
- /* Also 32768 block size in some cases */
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
- __be16 max_speed; /* Maximum speed supported in KBps */
- u8 reserved10, reserved11;
- __be16 ctl; /* Continuous Transfer Limit in blocks */
- __be16 speed; /* Current Speed, in KBps */
- __be16 buffer_size; /* Buffer Size, in 512 bytes */
- u8 reserved18, reserved19;
-} osst_capabilities_page_t;
-
-/*
- * Block Size Page
- */
-typedef struct {
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned ps :1;
- unsigned reserved1_6 :1;
- unsigned page_code :6; /* Page code - Should be 0x30 */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned page_code :6; /* Page code - Should be 0x30 */
- unsigned reserved1_6 :1;
- unsigned ps :1;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
- u8 page_length; /* Page Length - Should be 2 */
- u8 reserved2;
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned one :1;
- unsigned reserved2_6 :1;
- unsigned record32_5 :1;
- unsigned record32 :1;
- unsigned reserved2_23 :2;
- unsigned play32_5 :1;
- unsigned play32 :1;
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned play32 :1;
- unsigned play32_5 :1;
- unsigned reserved2_23 :2;
- unsigned record32 :1;
- unsigned record32_5 :1;
- unsigned reserved2_6 :1;
- unsigned one :1;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-} osst_block_size_page_t;
-
-/*
- * Tape Parameters Page
- */
-typedef struct {
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned ps :1;
- unsigned reserved1_6 :1;
- unsigned page_code :6; /* Page code - Should be 0x2b */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned page_code :6; /* Page code - Should be 0x2b */
- unsigned reserved1_6 :1;
- unsigned ps :1;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
- u8 reserved2;
- u8 density;
- u8 reserved3,reserved4;
- __be16 segtrk;
- __be16 trks;
- u8 reserved5,reserved6,reserved7,reserved8,reserved9,reserved10;
-} osst_tape_paramtr_page_t;
-
-/* OnStream definitions */
-
-#define OS_CONFIG_PARTITION (0xff)
-#define OS_DATA_PARTITION (0)
-#define OS_PARTITION_VERSION (1)
-
-/*
- * partition
- */
-typedef struct os_partition_s {
- __u8 partition_num;
- __u8 par_desc_ver;
- __be16 wrt_pass_cntr;
- __be32 first_frame_ppos;
- __be32 last_frame_ppos;
- __be32 eod_frame_ppos;
-} os_partition_t;
-
-/*
- * DAT entry
- */
-typedef struct os_dat_entry_s {
- __be32 blk_sz;
- __be16 blk_cnt;
- __u8 flags;
- __u8 reserved;
-} os_dat_entry_t;
-
-/*
- * DAT
- */
-#define OS_DAT_FLAGS_DATA (0xc)
-#define OS_DAT_FLAGS_MARK (0x1)
-
-typedef struct os_dat_s {
- __u8 dat_sz;
- __u8 reserved1;
- __u8 entry_cnt;
- __u8 reserved3;
- os_dat_entry_t dat_list[16];
-} os_dat_t;
-
-/*
- * Frame types
- */
-#define OS_FRAME_TYPE_FILL (0)
-#define OS_FRAME_TYPE_EOD (1 << 0)
-#define OS_FRAME_TYPE_MARKER (1 << 1)
-#define OS_FRAME_TYPE_HEADER (1 << 3)
-#define OS_FRAME_TYPE_DATA (1 << 7)
-
-/*
- * AUX
- */
-typedef struct os_aux_s {
- __be32 format_id; /* hardware compatibility AUX is based on */
- char application_sig[4]; /* driver used to write this media */
- __be32 hdwr; /* reserved */
- __be32 update_frame_cntr; /* for configuration frame */
- __u8 frame_type;
- __u8 frame_type_reserved;
- __u8 reserved_18_19[2];
- os_partition_t partition;
- __u8 reserved_36_43[8];
- __be32 frame_seq_num;
- __be32 logical_blk_num_high;
- __be32 logical_blk_num;
- os_dat_t dat;
- __u8 reserved188_191[4];
- __be32 filemark_cnt;
- __be32 phys_fm;
- __be32 last_mark_ppos;
- __u8 reserved204_223[20];
-
- /*
- * __u8 app_specific[32];
- *
- * Linux specific fields:
- */
- __be32 next_mark_ppos; /* when known, points to next marker */
- __be32 last_mark_lbn; /* storing log_blk_num of last mark is extends ADR spec */
- __u8 linux_specific[24];
-
- __u8 reserved_256_511[256];
-} os_aux_t;
-
-#define OS_FM_TAB_MAX 1024
-
-typedef struct os_fm_tab_s {
- __u8 fm_part_num;
- __u8 reserved_1;
- __u8 fm_tab_ent_sz;
- __u8 reserved_3;
- __be16 fm_tab_ent_cnt;
- __u8 reserved6_15[10];
- __be32 fm_tab_ent[OS_FM_TAB_MAX];
-} os_fm_tab_t;
-
-typedef struct os_ext_trk_ey_s {
- __u8 et_part_num;
- __u8 fmt;
- __be16 fm_tab_off;
- __u8 reserved4_7[4];
- __be32 last_hlb_hi;
- __be32 last_hlb;
- __be32 last_pp;
- __u8 reserved20_31[12];
-} os_ext_trk_ey_t;
-
-typedef struct os_ext_trk_tb_s {
- __u8 nr_stream_part;
- __u8 reserved_1;
- __u8 et_ent_sz;
- __u8 reserved3_15[13];
- os_ext_trk_ey_t dat_ext_trk_ey;
- os_ext_trk_ey_t qfa_ext_trk_ey;
-} os_ext_trk_tb_t;
-
-typedef struct os_header_s {
- char ident_str[8];
- __u8 major_rev;
- __u8 minor_rev;
- __be16 ext_trk_tb_off;
- __u8 reserved12_15[4];
- __u8 pt_par_num;
- __u8 pt_reserved1_3[3];
- os_partition_t partition[16];
- __be32 cfg_col_width;
- __be32 dat_col_width;
- __be32 qfa_col_width;
- __u8 cartridge[16];
- __u8 reserved304_511[208];
- __be32 old_filemark_list[16680/4]; /* in ADR 1.4 __u8 track_table[16680] */
- os_ext_trk_tb_t ext_track_tb;
- __u8 reserved17272_17735[464];
- os_fm_tab_t dat_fm_tab;
- os_fm_tab_t qfa_fm_tab;
- __u8 reserved25960_32767[6808];
-} os_header_t;
-
-
-/*
- * OnStream ADRL frame
- */
-#define OS_FRAME_SIZE (32 * 1024 + 512)
-#define OS_DATA_SIZE (32 * 1024)
-#define OS_AUX_SIZE (512)
-//#define OSST_MAX_SG 2
-
-/* The OnStream tape buffer descriptor. */
-struct osst_buffer {
- unsigned char in_use;
- unsigned char dma; /* DMA-able buffer */
- int buffer_size;
- int buffer_blocks;
- int buffer_bytes;
- int read_pointer;
- int writing;
- int midlevel_result;
- int syscall_result;
- struct osst_request *last_SRpnt;
- struct st_cmdstatus cmdstat;
- struct rq_map_data map_data;
- unsigned char *b_data;
- os_aux_t *aux; /* onstream AUX structure at end of each block */
- unsigned short use_sg; /* zero or number of s/g segments for this adapter */
- unsigned short sg_segs; /* number of segments in s/g list */
- unsigned short orig_sg_segs; /* number of segments allocated at first try */
- struct scatterlist sg[1]; /* MUST BE last item */
-} ;
-
-/* The OnStream tape drive descriptor */
-struct osst_tape {
- struct scsi_driver *driver;
- unsigned capacity;
- struct scsi_device *device;
- struct mutex lock; /* for serialization */
- struct completion wait; /* for SCSI commands */
- struct osst_buffer * buffer;
-
- /* Drive characteristics */
- unsigned char omit_blklims;
- unsigned char do_auto_lock;
- unsigned char can_bsr;
- unsigned char can_partitions;
- unsigned char two_fm;
- unsigned char fast_mteom;
- unsigned char restr_dma;
- unsigned char scsi2_logical;
- unsigned char default_drvbuffer; /* 0xff = don't touch, value 3 bits */
- unsigned char pos_unknown; /* after reset position unknown */
- int write_threshold;
- int timeout; /* timeout for normal commands */
- int long_timeout; /* timeout for commands known to take long time*/
-
- /* Mode characteristics */
- struct st_modedef modes[ST_NBR_MODES];
- int current_mode;
-
- /* Status variables */
- int partition;
- int new_partition;
- int nbr_partitions; /* zero until partition support enabled */
- struct st_partstat ps[ST_NBR_PARTITIONS];
- unsigned char dirty;
- unsigned char ready;
- unsigned char write_prot;
- unsigned char drv_write_prot;
- unsigned char in_use;
- unsigned char blksize_changed;
- unsigned char density_changed;
- unsigned char compression_changed;
- unsigned char drv_buffer;
- unsigned char density;
- unsigned char door_locked;
- unsigned char rew_at_close;
- unsigned char inited;
- int block_size;
- int min_block;
- int max_block;
- int recover_count; /* from tape opening */
- int abort_count;
- int write_count;
- int read_count;
- int recover_erreg; /* from last status call */
- /*
- * OnStream specific data
- */
- int os_fw_rev; /* the firmware revision * 10000 */
- unsigned char raw; /* flag OnStream raw access (32.5KB block size) */
- unsigned char poll; /* flag that this drive needs polling (IDE|firmware) */
- unsigned char frame_in_buffer; /* flag that the frame as per frame_seq_number
- * has been read into STp->buffer and is valid */
- int frame_seq_number; /* logical frame number */
- int logical_blk_num; /* logical block number */
- unsigned first_frame_position; /* physical frame to be transferred to/from host */
- unsigned last_frame_position; /* physical frame to be transferd to/from tape */
- int cur_frames; /* current number of frames in internal buffer */
- int max_frames; /* max number of frames in internal buffer */
- char application_sig[5]; /* application signature */
- unsigned char fast_open; /* flag that reminds us we didn't check headers at open */
- unsigned short wrt_pass_cntr; /* write pass counter */
- int update_frame_cntr; /* update frame counter */
- int onstream_write_error; /* write error recovery active */
- int header_ok; /* header frame verified ok */
- int linux_media; /* reading linux-specifc media */
- int linux_media_version;
- os_header_t * header_cache; /* cache is kept for filemark positions */
- int filemark_cnt;
- int first_mark_ppos;
- int last_mark_ppos;
- int last_mark_lbn; /* storing log_blk_num of last mark is extends ADR spec */
- int first_data_ppos;
- int eod_frame_ppos;
- int eod_frame_lfa;
- int write_type; /* used in write error recovery */
- int read_error_frame; /* used in read error recovery */
- unsigned long cmd_start_time;
- unsigned long max_cmd_time;
-
-#if DEBUG
- unsigned char write_pending;
- int nbr_finished;
- int nbr_waits;
- unsigned char last_cmnd[6];
- unsigned char last_sense[16];
-#endif
- struct gendisk *drive;
-} ;
-
-/* scsi tape command */
-struct osst_request {
- unsigned char cmd[MAX_COMMAND_SIZE];
- unsigned char sense[SCSI_SENSE_BUFFERSIZE];
- int result;
- struct osst_tape *stp;
- struct completion *waiting;
- struct bio *bio;
-};
-
-/* Values of write_type */
-#define OS_WRITE_DATA 0
-#define OS_WRITE_EOD 1
-#define OS_WRITE_NEW_MARK 2
-#define OS_WRITE_LAST_MARK 3
-#define OS_WRITE_HEADER 4
-#define OS_WRITE_FILLER 5
-
-/* Additional rw state */
-#define OS_WRITING_COMPLETE 3
diff --git a/drivers/scsi/osst_detect.h b/drivers/scsi/osst_detect.h
deleted file mode 100644
index 83c1d4fb11db..000000000000
--- a/drivers/scsi/osst_detect.h
+++ /dev/null
@@ -1,7 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#define SIGS_FROM_OSST \
- {"OnStream", "SC-", "", "osst"}, \
- {"OnStream", "DI-", "", "osst"}, \
- {"OnStream", "DP-", "", "osst"}, \
- {"OnStream", "FW-", "", "osst"}, \
- {"OnStream", "USB", "", "osst"}
diff --git a/drivers/scsi/osst_options.h b/drivers/scsi/osst_options.h
deleted file mode 100644
index a6a389b88876..000000000000
--- a/drivers/scsi/osst_options.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- The compile-time configurable defaults for the Linux SCSI tape driver.
-
- Copyright 1995 Kai Makisara.
-
- Last modified: Wed Sep 2 21:24:07 1998 by root@home
-
- Changed (and renamed) for OnStream SCSI drives garloff@suse.de
- 2000-06-21
-
- $Header: /cvsroot/osst/Driver/osst_options.h,v 1.6 2003/12/23 14:22:12 wriede Exp $
-*/
-
-#ifndef _OSST_OPTIONS_H
-#define _OSST_OPTIONS_H
-
-/* The minimum limit for the number of SCSI tape devices is determined by
- OSST_MAX_TAPES. If the number of tape devices and the "slack" defined by
- OSST_EXTRA_DEVS exceeds OSST_MAX_TAPES, the large number is used. */
-#define OSST_MAX_TAPES 4
-
-/* If OSST_IN_FILE_POS is nonzero, the driver positions the tape after the
- record been read by the user program even if the tape has moved further
- because of buffered reads. Should be set to zero to support also drives
- that can't space backwards over records. NOTE: The tape will be
- spaced backwards over an "accidentally" crossed filemark in any case. */
-#define OSST_IN_FILE_POS 1
-
-/* The tape driver buffer size in kilobytes. */
-/* Don't change, as this is the HW blocksize */
-#define OSST_BUFFER_BLOCKS 32
-
-/* The number of kilobytes of data in the buffer that triggers an
- asynchronous write in fixed block mode. See also OSST_ASYNC_WRITES
- below. */
-#define OSST_WRITE_THRESHOLD_BLOCKS 32
-
-/* OSST_EOM_RESERVE defines the number of frames are kept in reserve for
- * * write error recovery when writing near end of medium. ENOSPC is returned
- * * when write() is called and the tape write position is within this number
- * * of blocks from the tape capacity. */
-#define OSST_EOM_RESERVE 300
-
-/* The maximum number of tape buffers the driver allocates. The number
- is also constrained by the number of drives detected. Determines the
- maximum number of concurrently active tape drives. */
-#define OSST_MAX_BUFFERS OSST_MAX_TAPES
-
-/* Maximum number of scatter/gather segments */
-/* Fit one buffer in pages and add one for the AUX header */
-#define OSST_MAX_SG (((OSST_BUFFER_BLOCKS*1024) / PAGE_SIZE) + 1)
-
-/* The number of scatter/gather segments to allocate at first try (must be
- smaller or equal to the maximum). */
-#define OSST_FIRST_SG ((OSST_BUFFER_BLOCKS*1024) / PAGE_SIZE)
-
-/* The size of the first scatter/gather segments (determines the maximum block
- size for SCSI adapters not supporting scatter/gather). The default is set
- to try to allocate the buffer as one chunk. */
-#define OSST_FIRST_ORDER (15-PAGE_SHIFT)
-
-
-/* The following lines define defaults for properties that can be set
- separately for each drive using the MTSTOPTIONS ioctl. */
-
-/* If OSST_TWO_FM is non-zero, the driver writes two filemarks after a
- file being written. Some drives can't handle two filemarks at the
- end of data. */
-#define OSST_TWO_FM 0
-
-/* If OSST_BUFFER_WRITES is non-zero, writes in fixed block mode are
- buffered until the driver buffer is full or asynchronous write is
- triggered. */
-#define OSST_BUFFER_WRITES 1
-
-/* If OSST_ASYNC_WRITES is non-zero, the SCSI write command may be started
- without waiting for it to finish. May cause problems in multiple
- tape backups. */
-#define OSST_ASYNC_WRITES 1
-
-/* If OSST_READ_AHEAD is non-zero, blocks are read ahead in fixed block
- mode. */
-#define OSST_READ_AHEAD 1
-
-/* If OSST_AUTO_LOCK is non-zero, the drive door is locked at the first
- read or write command after the device is opened. The door is opened
- when the device is closed. */
-#define OSST_AUTO_LOCK 0
-
-/* If OSST_FAST_MTEOM is non-zero, the MTEOM ioctl is done using the
- direct SCSI command. The file number status is lost but this method
- is fast with some drives. Otherwise MTEOM is done by spacing over
- files and the file number status is retained. */
-#define OSST_FAST_MTEOM 0
-
-/* If OSST_SCSI2LOGICAL is nonzero, the logical block addresses are used for
- MTIOCPOS and MTSEEK by default. Vendor addresses are used if OSST_SCSI2LOGICAL
- is zero. */
-#define OSST_SCSI2LOGICAL 0
-
-/* If OSST_SYSV is non-zero, the tape behaves according to the SYS V semantics.
- The default is BSD semantics. */
-#define OSST_SYSV 0
-
-
-#endif
diff --git a/drivers/scsi/pcmcia/Kconfig b/drivers/scsi/pcmcia/Kconfig
index c544f48a1d18..2368f34efba3 100644
--- a/drivers/scsi/pcmcia/Kconfig
+++ b/drivers/scsi/pcmcia/Kconfig
@@ -20,6 +20,16 @@ config PCMCIA_AHA152X
To compile this driver as a module, choose M here: the
module will be called aha152x_cs.
+config PCMCIA_FDOMAIN
+ tristate "Future Domain PCMCIA support"
+ select SCSI_FDOMAIN
+ help
+ Say Y here if you intend to attach this type of PCMCIA SCSI host
+ adapter to your computer.
+
+ To compile this driver as a module, choose M here: the
+ module will be called fdomain_cs.
+
config PCMCIA_NINJA_SCSI
tristate "NinjaSCSI-3 / NinjaSCSI-32Bi (16bit) PCMCIA support"
depends on !64BIT
diff --git a/drivers/scsi/pcmcia/Makefile b/drivers/scsi/pcmcia/Makefile
index a5a24dd44e7e..02f5b44a2685 100644
--- a/drivers/scsi/pcmcia/Makefile
+++ b/drivers/scsi/pcmcia/Makefile
@@ -4,6 +4,7 @@ ccflags-y := -I $(srctree)/drivers/scsi
# 16-bit client drivers
obj-$(CONFIG_PCMCIA_QLOGIC) += qlogic_cs.o
+obj-$(CONFIG_PCMCIA_FDOMAIN) += fdomain_cs.o
obj-$(CONFIG_PCMCIA_AHA152X) += aha152x_cs.o
obj-$(CONFIG_PCMCIA_NINJA_SCSI) += nsp_cs.o
obj-$(CONFIG_PCMCIA_SYM53C500) += sym53c500_cs.o
diff --git a/drivers/scsi/pcmcia/fdomain_cs.c b/drivers/scsi/pcmcia/fdomain_cs.c
new file mode 100644
index 000000000000..e42acf314d06
--- /dev/null
+++ b/drivers/scsi/pcmcia/fdomain_cs.c
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1)
+/*
+ * Driver for Future Domain-compatible PCMCIA SCSI cards
+ * Copyright 2019 Ondrej Zary
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <scsi/scsi_host.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+#include "fdomain.h"
+
+MODULE_AUTHOR("Ondrej Zary, David Hinds");
+MODULE_DESCRIPTION("Future Domain PCMCIA SCSI driver");
+MODULE_LICENSE("Dual MPL/GPL");
+
+static int fdomain_config_check(struct pcmcia_device *p_dev, void *priv_data)
+{
+ p_dev->io_lines = 10;
+ p_dev->resource[0]->end = FDOMAIN_REGION_SIZE;
+ p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+ p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
+ return pcmcia_request_io(p_dev);
+}
+
+static int fdomain_probe(struct pcmcia_device *link)
+{
+ int ret;
+ struct Scsi_Host *sh;
+
+ link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
+ link->config_regs = PRESENT_OPTION;
+
+ ret = pcmcia_loop_config(link, fdomain_config_check, NULL);
+ if (ret)
+ return ret;
+
+ ret = pcmcia_enable_device(link);
+ if (ret)
+ goto fail_disable;
+
+ if (!request_region(link->resource[0]->start, FDOMAIN_REGION_SIZE,
+ "fdomain_cs"))
+ goto fail_disable;
+
+ sh = fdomain_create(link->resource[0]->start, link->irq, 7, &link->dev);
+ if (!sh) {
+ dev_err(&link->dev, "Controller initialization failed");
+ ret = -ENODEV;
+ goto fail_release;
+ }
+
+ link->priv = sh;
+
+ return 0;
+
+fail_release:
+ release_region(link->resource[0]->start, FDOMAIN_REGION_SIZE);
+fail_disable:
+ pcmcia_disable_device(link);
+ return ret;
+}
+
+static void fdomain_remove(struct pcmcia_device *link)
+{
+ fdomain_destroy(link->priv);
+ release_region(link->resource[0]->start, FDOMAIN_REGION_SIZE);
+ pcmcia_disable_device(link);
+}
+
+static const struct pcmcia_device_id fdomain_ids[] = {
+ PCMCIA_DEVICE_PROD_ID12("IBM Corp.", "SCSI PCMCIA Card", 0xe3736c88,
+ 0x859cad20),
+ PCMCIA_DEVICE_PROD_ID1("SCSI PCMCIA Adapter Card", 0x8dacb57e),
+ PCMCIA_DEVICE_PROD_ID12(" SIMPLE TECHNOLOGY Corporation",
+ "SCSI PCMCIA Credit Card Controller",
+ 0x182bdafe, 0xc80d106f),
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, fdomain_ids);
+
+static struct pcmcia_driver fdomain_cs_driver = {
+ .owner = THIS_MODULE,
+ .name = "fdomain_cs",
+ .probe = fdomain_probe,
+ .remove = fdomain_remove,
+ .id_table = fdomain_ids,
+};
+
+module_pcmcia_driver(fdomain_cs_driver);
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
index a81748e6e8fb..97416e1dcc5b 100644
--- a/drivers/scsi/pcmcia/nsp_cs.c
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -789,7 +789,7 @@ static void nsp_pio_read(struct scsi_cmnd *SCpnt)
SCpnt->SCp.buffers_residual != 0 ) {
//nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next timeout=%d", time_out);
SCpnt->SCp.buffers_residual--;
- SCpnt->SCp.buffer++;
+ SCpnt->SCp.buffer = sg_next(SCpnt->SCp.buffer);
SCpnt->SCp.ptr = BUFFER_ADDR;
SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
time_out = 1000;
@@ -887,7 +887,7 @@ static void nsp_pio_write(struct scsi_cmnd *SCpnt)
SCpnt->SCp.buffers_residual != 0 ) {
//nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next");
SCpnt->SCp.buffers_residual--;
- SCpnt->SCp.buffer++;
+ SCpnt->SCp.buffer = sg_next(SCpnt->SCp.buffer);
SCpnt->SCp.ptr = BUFFER_ADDR;
SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
time_out = 1000;
diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c
index d193961ea82f..6b85016b4db3 100644
--- a/drivers/scsi/pm8001/pm8001_ctl.c
+++ b/drivers/scsi/pm8001/pm8001_ctl.c
@@ -462,6 +462,24 @@ static ssize_t pm8001_ctl_bios_version_show(struct device *cdev,
}
static DEVICE_ATTR(bios_version, S_IRUGO, pm8001_ctl_bios_version_show, NULL);
/**
+ * event_log_size_show - event log size
+ * @cdev: pointer to embedded class device
+ * @buf: the buffer returned
+ *
+ * A sysfs read shost attribute.
+ */
+static ssize_t event_log_size_show(struct device *cdev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+ struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_size);
+}
+static DEVICE_ATTR_RO(event_log_size);
+/**
* pm8001_ctl_aap_log_show - IOP event log
* @cdev: pointer to embedded class device
* @buf: the buffer returned
@@ -474,25 +492,26 @@ static ssize_t pm8001_ctl_iop_log_show(struct device *cdev,
struct Scsi_Host *shost = class_to_shost(cdev);
struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
-#define IOP_MEMMAP(r, c) \
- (*(u32 *)((u8*)pm8001_ha->memoryMap.region[IOP].virt_ptr + (r) * 32 \
- + (c)))
- int i;
char *str = buf;
- int max = 2;
- for (i = 0; i < max; i++) {
- str += sprintf(str, "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x"
- "0x%08x 0x%08x\n",
- IOP_MEMMAP(i, 0),
- IOP_MEMMAP(i, 4),
- IOP_MEMMAP(i, 8),
- IOP_MEMMAP(i, 12),
- IOP_MEMMAP(i, 16),
- IOP_MEMMAP(i, 20),
- IOP_MEMMAP(i, 24),
- IOP_MEMMAP(i, 28));
+ u32 read_size =
+ pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_size / 1024;
+ static u32 start, end, count;
+ u32 max_read_times = 32;
+ u32 max_count = (read_size * 1024) / (max_read_times * 4);
+ u32 *temp = (u32 *)pm8001_ha->memoryMap.region[IOP].virt_ptr;
+
+ if ((count % max_count) == 0) {
+ start = 0;
+ end = max_read_times;
+ count = 0;
+ } else {
+ start = end;
+ end = end + max_read_times;
}
+ for (; start < end; start++)
+ str += sprintf(str, "%08x ", *(temp+start));
+ count++;
return str - buf;
}
static DEVICE_ATTR(iop_log, S_IRUGO, pm8001_ctl_iop_log_show, NULL);
@@ -796,6 +815,7 @@ struct device_attribute *pm8001_host_attrs[] = {
&dev_attr_max_sg_list,
&dev_attr_sas_spec_support,
&dev_attr_logging_level,
+ &dev_attr_event_log_size,
&dev_attr_host_sas_address,
&dev_attr_bios_version,
&dev_attr_ib_log,
diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
index 109effd3557d..68a8217032d0 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.c
+++ b/drivers/scsi/pm8001/pm8001_hwi.c
@@ -2356,7 +2356,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) &&
(status != IO_UNDERFLOW)) {
if (!((t->dev->parent) &&
- (DEV_IS_EXPANDER(t->dev->parent->dev_type)))) {
+ (dev_is_expander(t->dev->parent->dev_type)))) {
for (i = 0 , j = 4; j <= 7 && i <= 3; i++ , j++)
sata_addr_low[i] = pm8001_ha->sas_addr[j];
for (i = 0 , j = 0; j <= 3 && i <= 3; i++ , j++)
@@ -4560,7 +4560,7 @@ static int pm8001_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha,
pm8001_dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE)
stp_sspsmp_sata = 0x01; /*ssp or smp*/
}
- if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
+ if (parent_dev && dev_is_expander(parent_dev->dev_type))
phy_id = parent_dev->ex_dev.ex_phy->phy_id;
else
phy_id = pm8001_dev->attached_phy;
diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c
index 88eef3b18e41..dd38c356a1a4 100644
--- a/drivers/scsi/pm8001/pm8001_sas.c
+++ b/drivers/scsi/pm8001/pm8001_sas.c
@@ -634,7 +634,7 @@ static int pm8001_dev_found_notify(struct domain_device *dev)
dev->lldd_dev = pm8001_device;
pm8001_device->dev_type = dev->dev_type;
pm8001_device->dcompletion = &completion;
- if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) {
+ if (parent_dev && dev_is_expander(parent_dev->dev_type)) {
int phy_id;
struct ex_phy *phy;
for (phy_id = 0; phy_id < parent_dev->ex_dev.num_phys;
@@ -1181,7 +1181,7 @@ int pm8001_query_task(struct sas_task *task)
return rc;
}
-/* mandatory SAM-3, still need free task/ccb info, abord the specified task */
+/* mandatory SAM-3, still need free task/ccb info, abort the specified task */
int pm8001_abort_task(struct sas_task *task)
{
unsigned long flags;
diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h
index ac6d8e3f22de..ff17c6aff63d 100644
--- a/drivers/scsi/pm8001/pm8001_sas.h
+++ b/drivers/scsi/pm8001/pm8001_sas.h
@@ -103,7 +103,6 @@ do { \
#define PM8001_READ_VPD
-#define DEV_IS_EXPANDER(type) ((type == SAS_EDGE_EXPANDER_DEVICE) || (type == SAS_FANOUT_EXPANDER_DEVICE))
#define IS_SPCV_12G(dev) ((dev->device == 0X8074) \
|| (dev->device == 0X8076) \
|| (dev->device == 0X8077) \
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
index 301de40eb708..1128d86d241a 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.c
+++ b/drivers/scsi/pm8001/pm80xx_hwi.c
@@ -2066,7 +2066,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) &&
(status != IO_UNDERFLOW)) {
if (!((t->dev->parent) &&
- (DEV_IS_EXPANDER(t->dev->parent->dev_type)))) {
+ (dev_is_expander(t->dev->parent->dev_type)))) {
for (i = 0 , j = 4; i <= 3 && j <= 7; i++ , j++)
sata_addr_low[i] = pm8001_ha->sas_addr[j];
for (i = 0 , j = 0; i <= 3 && j <= 3; i++ , j++)
@@ -4561,7 +4561,7 @@ static int pm80xx_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha,
pm8001_dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE)
stp_sspsmp_sata = 0x01; /*ssp or smp*/
}
- if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
+ if (parent_dev && dev_is_expander(parent_dev->dev_type))
phy_id = parent_dev->ex_dev.ex_phy->phy_id;
else
phy_id = pm8001_dev->attached_phy;
diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c
index ca22526aff7f..71ff3936da4f 100644
--- a/drivers/scsi/pmcraid.c
+++ b/drivers/scsi/pmcraid.c
@@ -3255,7 +3255,7 @@ static int pmcraid_copy_sglist(
int direction
)
{
- struct scatterlist *scatterlist;
+ struct scatterlist *sg;
void *kaddr;
int bsize_elem;
int i;
@@ -3264,10 +3264,10 @@ static int pmcraid_copy_sglist(
/* Determine the actual number of bytes per element */
bsize_elem = PAGE_SIZE * (1 << sglist->order);
- scatterlist = sglist->scatterlist;
+ sg = sglist->scatterlist;
- for (i = 0; i < (len / bsize_elem); i++, buffer += bsize_elem) {
- struct page *page = sg_page(&scatterlist[i]);
+ for (i = 0; i < (len / bsize_elem); i++, sg = sg_next(sg), buffer += bsize_elem) {
+ struct page *page = sg_page(sg);
kaddr = kmap(page);
if (direction == DMA_TO_DEVICE)
@@ -3282,11 +3282,11 @@ static int pmcraid_copy_sglist(
return -EFAULT;
}
- scatterlist[i].length = bsize_elem;
+ sg->length = bsize_elem;
}
if (len % bsize_elem) {
- struct page *page = sg_page(&scatterlist[i]);
+ struct page *page = sg_page(sg);
kaddr = kmap(page);
@@ -3297,7 +3297,7 @@ static int pmcraid_copy_sglist(
kunmap(page);
- scatterlist[i].length = len % bsize_elem;
+ sg->length = len % bsize_elem;
}
if (rc) {
diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
index 35213082e933..a406cc825426 100644
--- a/drivers/scsi/ppa.c
+++ b/drivers/scsi/ppa.c
@@ -590,7 +590,7 @@ static int ppa_completion(struct scsi_cmnd *cmd)
if (cmd->SCp.buffer && !cmd->SCp.this_residual) {
/* if scatter/gather, advance to the next segment */
if (cmd->SCp.buffers_residual--) {
- cmd->SCp.buffer++;
+ cmd->SCp.buffer = sg_next(cmd->SCp.buffer);
cmd->SCp.this_residual =
cmd->SCp.buffer->length;
cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c
index 6ef0f741bf89..a42babde036d 100644
--- a/drivers/scsi/qedf/qedf_main.c
+++ b/drivers/scsi/qedf/qedf_main.c
@@ -2215,16 +2215,21 @@ static void qedf_simd_int_handler(void *cookie)
static void qedf_sync_free_irqs(struct qedf_ctx *qedf)
{
int i;
+ u16 vector_idx = 0;
+ u32 vector;
if (qedf->int_info.msix_cnt) {
for (i = 0; i < qedf->int_info.used_cnt; i++) {
- synchronize_irq(qedf->int_info.msix[i].vector);
- irq_set_affinity_hint(qedf->int_info.msix[i].vector,
- NULL);
- irq_set_affinity_notifier(qedf->int_info.msix[i].vector,
- NULL);
- free_irq(qedf->int_info.msix[i].vector,
- &qedf->fp_array[i]);
+ vector_idx = i * qedf->dev_info.common.num_hwfns +
+ qed_ops->common->get_affin_hwfn_idx(qedf->cdev);
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
+ "Freeing IRQ #%d vector_idx=%d.\n",
+ i, vector_idx);
+ vector = qedf->int_info.msix[vector_idx].vector;
+ synchronize_irq(vector);
+ irq_set_affinity_hint(vector, NULL);
+ irq_set_affinity_notifier(vector, NULL);
+ free_irq(vector, &qedf->fp_array[i]);
}
} else
qed_ops->common->simd_handler_clean(qedf->cdev,
@@ -2237,11 +2242,19 @@ static void qedf_sync_free_irqs(struct qedf_ctx *qedf)
static int qedf_request_msix_irq(struct qedf_ctx *qedf)
{
int i, rc, cpu;
+ u16 vector_idx = 0;
+ u32 vector;
cpu = cpumask_first(cpu_online_mask);
for (i = 0; i < qedf->num_queues; i++) {
- rc = request_irq(qedf->int_info.msix[i].vector,
- qedf_msix_handler, 0, "qedf", &qedf->fp_array[i]);
+ vector_idx = i * qedf->dev_info.common.num_hwfns +
+ qed_ops->common->get_affin_hwfn_idx(qedf->cdev);
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
+ "Requesting IRQ #%d vector_idx=%d.\n",
+ i, vector_idx);
+ vector = qedf->int_info.msix[vector_idx].vector;
+ rc = request_irq(vector, qedf_msix_handler, 0, "qedf",
+ &qedf->fp_array[i]);
if (rc) {
QEDF_WARN(&(qedf->dbg_ctx), "request_irq failed.\n");
@@ -2250,8 +2263,7 @@ static int qedf_request_msix_irq(struct qedf_ctx *qedf)
}
qedf->int_info.used_cnt++;
- rc = irq_set_affinity_hint(qedf->int_info.msix[i].vector,
- get_cpu_mask(cpu));
+ rc = irq_set_affinity_hint(vector, get_cpu_mask(cpu));
cpu = cpumask_next(cpu, cpu_online_mask);
}
@@ -3208,6 +3220,11 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
goto err1;
}
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
+ "dev_info: num_hwfns=%d affin_hwfn_idx=%d.\n",
+ qedf->dev_info.common.num_hwfns,
+ qed_ops->common->get_affin_hwfn_idx(qedf->cdev));
+
/* queue allocation code should come here
* order should be
* slowpath_start
diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c
index 8814bfcb6449..acb930b8c6a6 100644
--- a/drivers/scsi/qedi/qedi_main.c
+++ b/drivers/scsi/qedi/qedi_main.c
@@ -987,6 +987,9 @@ static int qedi_find_boot_info(struct qedi_ctx *qedi,
if (!iscsi_is_session_online(cls_sess))
continue;
+ if (!sess->targetname)
+ continue;
+
if (pri_ctrl_flags) {
if (!strcmp(pri_tgt->iscsi_name, sess->targetname) &&
!strcmp(pri_tgt->ip_addr, ep_ip_addr)) {
@@ -1310,13 +1313,20 @@ static void qedi_simd_int_handler(void *cookie)
static void qedi_sync_free_irqs(struct qedi_ctx *qedi)
{
int i;
+ u16 idx;
if (qedi->int_info.msix_cnt) {
for (i = 0; i < qedi->int_info.used_cnt; i++) {
- synchronize_irq(qedi->int_info.msix[i].vector);
- irq_set_affinity_hint(qedi->int_info.msix[i].vector,
+ idx = i * qedi->dev_info.common.num_hwfns +
+ qedi_ops->common->get_affin_hwfn_idx(qedi->cdev);
+
+ QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
+ "Freeing IRQ #%d vector_idx=%d.\n", i, idx);
+
+ synchronize_irq(qedi->int_info.msix[idx].vector);
+ irq_set_affinity_hint(qedi->int_info.msix[idx].vector,
NULL);
- free_irq(qedi->int_info.msix[i].vector,
+ free_irq(qedi->int_info.msix[idx].vector,
&qedi->fp_array[i]);
}
} else {
@@ -1331,20 +1341,28 @@ static void qedi_sync_free_irqs(struct qedi_ctx *qedi)
static int qedi_request_msix_irq(struct qedi_ctx *qedi)
{
int i, rc, cpu;
+ u16 idx;
cpu = cpumask_first(cpu_online_mask);
- for (i = 0; i < qedi->int_info.msix_cnt; i++) {
- rc = request_irq(qedi->int_info.msix[i].vector,
+ for (i = 0; i < MIN_NUM_CPUS_MSIX(qedi); i++) {
+ idx = i * qedi->dev_info.common.num_hwfns +
+ qedi_ops->common->get_affin_hwfn_idx(qedi->cdev);
+
+ QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
+ "dev_info: num_hwfns=%d affin_hwfn_idx=%d.\n",
+ qedi->dev_info.common.num_hwfns,
+ qedi_ops->common->get_affin_hwfn_idx(qedi->cdev));
+
+ rc = request_irq(qedi->int_info.msix[idx].vector,
qedi_msix_handler, 0, "qedi",
&qedi->fp_array[i]);
-
if (rc) {
QEDI_WARN(&qedi->dbg_ctx, "request_irq failed.\n");
qedi_sync_free_irqs(qedi);
return rc;
}
qedi->int_info.used_cnt++;
- rc = irq_set_affinity_hint(qedi->int_info.msix[i].vector,
+ rc = irq_set_affinity_hint(qedi->int_info.msix[idx].vector,
get_cpu_mask(cpu));
cpu = cpumask_next(cpu, cpu_online_mask);
}
@@ -2412,6 +2430,11 @@ static int __qedi_probe(struct pci_dev *pdev, int mode)
if (rc)
goto free_host;
+ QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
+ "dev_info: num_hwfns=%d affin_hwfn_idx=%d.\n",
+ qedi->dev_info.common.num_hwfns,
+ qedi_ops->common->get_affin_hwfn_idx(qedi->cdev));
+
if (mode != QEDI_MODE_RECOVERY) {
rc = qedi_set_iscsi_pf_param(qedi);
if (rc) {
diff --git a/drivers/scsi/qedi/qedi_version.h b/drivers/scsi/qedi/qedi_version.h
index f56f0ba0c4a8..0ac1055bd420 100644
--- a/drivers/scsi/qedi/qedi_version.h
+++ b/drivers/scsi/qedi/qedi_version.h
@@ -4,8 +4,8 @@
* Copyright (c) 2016 Cavium Inc.
*/
-#define QEDI_MODULE_VERSION "8.33.0.21"
+#define QEDI_MODULE_VERSION "8.37.0.20"
#define QEDI_DRIVER_MAJOR_VER 8
-#define QEDI_DRIVER_MINOR_VER 33
+#define QEDI_DRIVER_MINOR_VER 37
#define QEDI_DRIVER_REV_VER 0
-#define QEDI_DRIVER_ENG_VER 21
+#define QEDI_DRIVER_ENG_VER 20
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 1a4095c56eee..bad2b12604f1 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -532,6 +532,8 @@ typedef struct srb {
uint8_t cmd_type;
uint8_t pad[3];
atomic_t ref_count;
+ struct kref cmd_kref; /* need to migrate ref_count over to this */
+ void *priv;
wait_queue_head_t nvme_ls_waitq;
struct fc_port *fcport;
struct scsi_qla_host *vha;
@@ -554,6 +556,7 @@ typedef struct srb {
} u;
void (*done)(void *, int);
void (*free)(void *);
+ void (*put_fn)(struct kref *kref);
} srb_t;
#define GET_CMD_SP(sp) (sp->u.scmd.cmd)
@@ -2336,7 +2339,6 @@ typedef struct fc_port {
unsigned int id_changed:1;
unsigned int scan_needed:1;
- struct work_struct nvme_del_work;
struct completion nvme_del_done;
uint32_t nvme_prli_service_param;
#define NVME_PRLI_SP_CONF BIT_7
@@ -4376,7 +4378,6 @@ typedef struct scsi_qla_host {
struct nvme_fc_local_port *nvme_local_port;
struct completion nvme_del_done;
- struct list_head nvme_rport_list;
uint16_t fcoe_vlan_id;
uint16_t fcoe_fcf_idx;
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index bbe69ab5cf3f..f9669fdf7798 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -908,4 +908,6 @@ void qlt_clr_qp_table(struct scsi_qla_host *vha);
void qlt_set_mode(struct scsi_qla_host *);
int qla2x00_set_data_rate(scsi_qla_host_t *vha, uint16_t mode);
+/* nvme.c */
+void qla_nvme_unregister_remote_port(struct fc_port *fcport);
#endif /* _QLA_GBL_H */
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 54772d4c377f..4059655639d9 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -5403,7 +5403,6 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT);
fcport->deleted = 0;
fcport->logout_on_delete = 1;
- fcport->login_retry = vha->hw->login_retry_count;
fcport->n2n_chip_reset = fcport->n2n_link_reset_cnt = 0;
switch (vha->hw->current_topology) {
diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c
index 22e3fba28e51..963094b3c300 100644
--- a/drivers/scsi/qla2xxx/qla_nvme.c
+++ b/drivers/scsi/qla2xxx/qla_nvme.c
@@ -12,8 +12,6 @@
static struct nvme_fc_port_template qla_nvme_fc_transport;
-static void qla_nvme_unregister_remote_port(struct work_struct *);
-
int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport)
{
struct qla_nvme_rport *rport;
@@ -38,7 +36,6 @@ int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport)
(fcport->nvme_flag & NVME_FLAG_REGISTERED))
return 0;
- INIT_WORK(&fcport->nvme_del_work, qla_nvme_unregister_remote_port);
fcport->nvme_flag &= ~NVME_FLAG_RESETTING;
memset(&req, 0, sizeof(struct nvme_fc_port_info));
@@ -74,7 +71,6 @@ int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport)
rport = fcport->nvme_remote_port->private;
rport->fcport = fcport;
- list_add_tail(&rport->list, &vha->nvme_rport_list);
fcport->nvme_flag |= NVME_FLAG_REGISTERED;
return 0;
@@ -124,53 +120,91 @@ static int qla_nvme_alloc_queue(struct nvme_fc_local_port *lport,
return 0;
}
+static void qla_nvme_release_fcp_cmd_kref(struct kref *kref)
+{
+ struct srb *sp = container_of(kref, struct srb, cmd_kref);
+ struct nvme_private *priv = (struct nvme_private *)sp->priv;
+ struct nvmefc_fcp_req *fd;
+ struct srb_iocb *nvme;
+ unsigned long flags;
+
+ if (!priv)
+ goto out;
+
+ nvme = &sp->u.iocb_cmd;
+ fd = nvme->u.nvme.desc;
+
+ spin_lock_irqsave(&priv->cmd_lock, flags);
+ priv->sp = NULL;
+ sp->priv = NULL;
+ if (priv->comp_status == QLA_SUCCESS) {
+ fd->rcv_rsplen = nvme->u.nvme.rsp_pyld_len;
+ } else {
+ fd->rcv_rsplen = 0;
+ fd->transferred_length = 0;
+ }
+ fd->status = 0;
+ spin_unlock_irqrestore(&priv->cmd_lock, flags);
+
+ fd->done(fd);
+out:
+ qla2xxx_rel_qpair_sp(sp->qpair, sp);
+}
+
+static void qla_nvme_release_ls_cmd_kref(struct kref *kref)
+{
+ struct srb *sp = container_of(kref, struct srb, cmd_kref);
+ struct nvme_private *priv = (struct nvme_private *)sp->priv;
+ struct nvmefc_ls_req *fd;
+ unsigned long flags;
+
+ if (!priv)
+ goto out;
+
+ spin_lock_irqsave(&priv->cmd_lock, flags);
+ priv->sp = NULL;
+ sp->priv = NULL;
+ spin_unlock_irqrestore(&priv->cmd_lock, flags);
+
+ fd = priv->fd;
+ fd->done(fd, priv->comp_status);
+out:
+ qla2x00_rel_sp(sp);
+}
+
+static void qla_nvme_ls_complete(struct work_struct *work)
+{
+ struct nvme_private *priv =
+ container_of(work, struct nvme_private, ls_work);
+
+ kref_put(&priv->sp->cmd_kref, qla_nvme_release_ls_cmd_kref);
+}
+
static void qla_nvme_sp_ls_done(void *ptr, int res)
{
srb_t *sp = ptr;
- struct srb_iocb *nvme;
- struct nvmefc_ls_req *fd;
struct nvme_private *priv;
- if (WARN_ON_ONCE(atomic_read(&sp->ref_count) == 0))
+ if (WARN_ON_ONCE(kref_read(&sp->cmd_kref) == 0))
return;
- atomic_dec(&sp->ref_count);
-
if (res)
res = -EINVAL;
- nvme = &sp->u.iocb_cmd;
- fd = nvme->u.nvme.desc;
- priv = fd->private;
+ priv = (struct nvme_private *)sp->priv;
priv->comp_status = res;
+ INIT_WORK(&priv->ls_work, qla_nvme_ls_complete);
schedule_work(&priv->ls_work);
- /* work schedule doesn't need the sp */
- qla2x00_rel_sp(sp);
}
+/* it assumed that QPair lock is held. */
static void qla_nvme_sp_done(void *ptr, int res)
{
srb_t *sp = ptr;
- struct srb_iocb *nvme;
- struct nvmefc_fcp_req *fd;
-
- nvme = &sp->u.iocb_cmd;
- fd = nvme->u.nvme.desc;
-
- if (WARN_ON_ONCE(atomic_read(&sp->ref_count) == 0))
- return;
+ struct nvme_private *priv = (struct nvme_private *)sp->priv;
- atomic_dec(&sp->ref_count);
-
- if (res == QLA_SUCCESS) {
- fd->rcv_rsplen = nvme->u.nvme.rsp_pyld_len;
- } else {
- fd->rcv_rsplen = 0;
- fd->transferred_length = 0;
- }
- fd->status = 0;
- fd->done(fd);
- qla2xxx_rel_qpair_sp(sp->qpair, sp);
+ priv->comp_status = res;
+ kref_put(&sp->cmd_kref, qla_nvme_release_fcp_cmd_kref);
return;
}
@@ -189,44 +223,50 @@ static void qla_nvme_abort_work(struct work_struct *work)
__func__, sp, sp->handle, fcport, fcport->deleted);
if (!ha->flags.fw_started && (fcport && fcport->deleted))
- return;
+ goto out;
if (ha->flags.host_shutting_down) {
ql_log(ql_log_info, sp->fcport->vha, 0xffff,
"%s Calling done on sp: %p, type: 0x%x, sp->ref_count: 0x%x\n",
__func__, sp, sp->type, atomic_read(&sp->ref_count));
sp->done(sp, 0);
- return;
+ goto out;
}
- if (WARN_ON_ONCE(atomic_read(&sp->ref_count) == 0))
- return;
-
rval = ha->isp_ops->abort_command(sp);
ql_dbg(ql_dbg_io, fcport->vha, 0x212b,
"%s: %s command for sp=%p, handle=%x on fcport=%p rval=%x\n",
__func__, (rval != QLA_SUCCESS) ? "Failed to abort" : "Aborted",
sp, sp->handle, fcport, rval);
+
+out:
+ /* kref_get was done before work was schedule. */
+ kref_put(&sp->cmd_kref, sp->put_fn);
}
static void qla_nvme_ls_abort(struct nvme_fc_local_port *lport,
struct nvme_fc_remote_port *rport, struct nvmefc_ls_req *fd)
{
struct nvme_private *priv = fd->private;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->cmd_lock, flags);
+ if (!priv->sp) {
+ spin_unlock_irqrestore(&priv->cmd_lock, flags);
+ return;
+ }
+
+ if (!kref_get_unless_zero(&priv->sp->cmd_kref)) {
+ spin_unlock_irqrestore(&priv->cmd_lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&priv->cmd_lock, flags);
INIT_WORK(&priv->abort_work, qla_nvme_abort_work);
schedule_work(&priv->abort_work);
}
-static void qla_nvme_ls_complete(struct work_struct *work)
-{
- struct nvme_private *priv =
- container_of(work, struct nvme_private, ls_work);
- struct nvmefc_ls_req *fd = priv->fd;
-
- fd->done(fd, priv->comp_status);
-}
static int qla_nvme_ls_req(struct nvme_fc_local_port *lport,
struct nvme_fc_remote_port *rport, struct nvmefc_ls_req *fd)
@@ -240,8 +280,16 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport,
struct qla_hw_data *ha;
srb_t *sp;
+
+ if (!fcport || (fcport && fcport->deleted))
+ return rval;
+
vha = fcport->vha;
ha = vha->hw;
+
+ if (!ha->flags.fw_started)
+ return rval;
+
/* Alloc SRB structure */
sp = qla2x00_get_sp(vha, fcport, GFP_ATOMIC);
if (!sp)
@@ -250,11 +298,13 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport,
sp->type = SRB_NVME_LS;
sp->name = "nvme_ls";
sp->done = qla_nvme_sp_ls_done;
- atomic_set(&sp->ref_count, 1);
- nvme = &sp->u.iocb_cmd;
+ sp->put_fn = qla_nvme_release_ls_cmd_kref;
+ sp->priv = (void *)priv;
priv->sp = sp;
+ kref_init(&sp->cmd_kref);
+ spin_lock_init(&priv->cmd_lock);
+ nvme = &sp->u.iocb_cmd;
priv->fd = fd;
- INIT_WORK(&priv->ls_work, qla_nvme_ls_complete);
nvme->u.nvme.desc = fd;
nvme->u.nvme.dir = 0;
nvme->u.nvme.dl = 0;
@@ -271,8 +321,10 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport,
if (rval != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x700e,
"qla2x00_start_sp failed = %d\n", rval);
- atomic_dec(&sp->ref_count);
wake_up(&sp->nvme_ls_waitq);
+ sp->priv = NULL;
+ priv->sp = NULL;
+ qla2x00_rel_sp(sp);
return rval;
}
@@ -284,6 +336,18 @@ static void qla_nvme_fcp_abort(struct nvme_fc_local_port *lport,
struct nvmefc_fcp_req *fd)
{
struct nvme_private *priv = fd->private;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->cmd_lock, flags);
+ if (!priv->sp) {
+ spin_unlock_irqrestore(&priv->cmd_lock, flags);
+ return;
+ }
+ if (!kref_get_unless_zero(&priv->sp->cmd_kref)) {
+ spin_unlock_irqrestore(&priv->cmd_lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&priv->cmd_lock, flags);
INIT_WORK(&priv->abort_work, qla_nvme_abort_work);
schedule_work(&priv->abort_work);
@@ -487,11 +551,11 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport,
fcport = qla_rport->fcport;
- vha = fcport->vha;
-
- if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags))
+ if (!qpair || !fcport || (qpair && !qpair->fw_started) ||
+ (fcport && fcport->deleted))
return rval;
+ vha = fcport->vha;
/*
* If we know the dev is going away while the transport is still sending
* IO's return busy back to stall the IO Q. This happens when the
@@ -507,12 +571,15 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport,
if (!sp)
return -EBUSY;
- atomic_set(&sp->ref_count, 1);
init_waitqueue_head(&sp->nvme_ls_waitq);
+ kref_init(&sp->cmd_kref);
+ spin_lock_init(&priv->cmd_lock);
+ sp->priv = (void *)priv;
priv->sp = sp;
sp->type = SRB_NVME_CMD;
sp->name = "nvme_cmd";
sp->done = qla_nvme_sp_done;
+ sp->put_fn = qla_nvme_release_fcp_cmd_kref;
sp->qpair = qpair;
sp->vha = vha;
nvme = &sp->u.iocb_cmd;
@@ -522,8 +589,10 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport,
if (rval != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x212d,
"qla2x00_start_nvme_mq failed = %d\n", rval);
- atomic_dec(&sp->ref_count);
wake_up(&sp->nvme_ls_waitq);
+ sp->priv = NULL;
+ priv->sp = NULL;
+ qla2xxx_rel_qpair_sp(sp->qpair, sp);
}
return rval;
@@ -542,29 +611,16 @@ static void qla_nvme_localport_delete(struct nvme_fc_local_port *lport)
static void qla_nvme_remoteport_delete(struct nvme_fc_remote_port *rport)
{
fc_port_t *fcport;
- struct qla_nvme_rport *qla_rport = rport->private, *trport;
+ struct qla_nvme_rport *qla_rport = rport->private;
fcport = qla_rport->fcport;
fcport->nvme_remote_port = NULL;
fcport->nvme_flag &= ~NVME_FLAG_REGISTERED;
-
- list_for_each_entry_safe(qla_rport, trport,
- &fcport->vha->nvme_rport_list, list) {
- if (qla_rport->fcport == fcport) {
- list_del(&qla_rport->list);
- break;
- }
- }
- complete(&fcport->nvme_del_done);
-
- if (!test_bit(UNLOADING, &fcport->vha->dpc_flags)) {
- INIT_WORK(&fcport->free_work, qlt_free_session_done);
- schedule_work(&fcport->free_work);
- }
-
fcport->nvme_flag &= ~NVME_FLAG_DELETING;
ql_log(ql_log_info, fcport->vha, 0x2110,
- "remoteport_delete of %p completed.\n", fcport);
+ "remoteport_delete of %p %8phN completed.\n",
+ fcport, fcport->port_name);
+ complete(&fcport->nvme_del_done);
}
static struct nvme_fc_port_template qla_nvme_fc_transport = {
@@ -586,35 +642,25 @@ static struct nvme_fc_port_template qla_nvme_fc_transport = {
.fcprqst_priv_sz = sizeof(struct nvme_private),
};
-static void qla_nvme_unregister_remote_port(struct work_struct *work)
+void qla_nvme_unregister_remote_port(struct fc_port *fcport)
{
- struct fc_port *fcport = container_of(work, struct fc_port,
- nvme_del_work);
- struct qla_nvme_rport *qla_rport, *trport;
+ int ret;
if (!IS_ENABLED(CONFIG_NVME_FC))
return;
ql_log(ql_log_warn, NULL, 0x2112,
- "%s: unregister remoteport on %p\n",__func__, fcport);
-
- list_for_each_entry_safe(qla_rport, trport,
- &fcport->vha->nvme_rport_list, list) {
- if (qla_rport->fcport == fcport) {
- ql_log(ql_log_info, fcport->vha, 0x2113,
- "%s: fcport=%p\n", __func__, fcport);
- nvme_fc_set_remoteport_devloss
- (fcport->nvme_remote_port, 0);
- init_completion(&fcport->nvme_del_done);
- if (nvme_fc_unregister_remoteport
- (fcport->nvme_remote_port))
- ql_log(ql_log_info, fcport->vha, 0x2114,
- "%s: Failed to unregister nvme_remote_port\n",
- __func__);
- wait_for_completion(&fcport->nvme_del_done);
- break;
- }
- }
+ "%s: unregister remoteport on %p %8phN\n",
+ __func__, fcport, fcport->port_name);
+
+ nvme_fc_set_remoteport_devloss(fcport->nvme_remote_port, 0);
+ init_completion(&fcport->nvme_del_done);
+ ret = nvme_fc_unregister_remoteport(fcport->nvme_remote_port);
+ if (ret)
+ ql_log(ql_log_info, fcport->vha, 0x2114,
+ "%s: Failed to unregister nvme_remote_port (%d)\n",
+ __func__, ret);
+ wait_for_completion(&fcport->nvme_del_done);
}
void qla_nvme_delete(struct scsi_qla_host *vha)
diff --git a/drivers/scsi/qla2xxx/qla_nvme.h b/drivers/scsi/qla2xxx/qla_nvme.h
index d3b8a6440113..67bb4a2a3742 100644
--- a/drivers/scsi/qla2xxx/qla_nvme.h
+++ b/drivers/scsi/qla2xxx/qla_nvme.h
@@ -34,10 +34,10 @@ struct nvme_private {
struct work_struct ls_work;
struct work_struct abort_work;
int comp_status;
+ spinlock_t cmd_lock;
};
struct qla_nvme_rport {
- struct list_head list;
struct fc_port *fcport;
};
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 172ef21827dd..2e58cff9d200 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -1731,8 +1731,8 @@ static void qla2x00_abort_srb(struct qla_qpair *qp, srb_t *sp, const int res,
!test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) &&
!qla2x00_isp_reg_stat(ha))) {
sp->comp = &comp;
- rval = ha->isp_ops->abort_command(sp);
spin_unlock_irqrestore(qp->qp_lock_ptr, *flags);
+ rval = ha->isp_ops->abort_command(sp);
switch (rval) {
case QLA_SUCCESS:
@@ -4789,7 +4789,6 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
INIT_LIST_HEAD(&vha->plogi_ack_list);
INIT_LIST_HEAD(&vha->qp_list);
INIT_LIST_HEAD(&vha->gnl.fcports);
- INIT_LIST_HEAD(&vha->nvme_rport_list);
INIT_LIST_HEAD(&vha->gpnid_list);
INIT_WORK(&vha->iocb_work, qla2x00_iocb_work_fn);
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 2fd5c09b42d4..1c1f63be6eed 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -1004,6 +1004,12 @@ void qlt_free_session_done(struct work_struct *work)
else
logout_started = true;
}
+ } /* if sess->logout_on_delete */
+
+ if (sess->nvme_flag & NVME_FLAG_REGISTERED &&
+ !(sess->nvme_flag & NVME_FLAG_DELETING)) {
+ sess->nvme_flag |= NVME_FLAG_DELETING;
+ qla_nvme_unregister_remote_port(sess);
}
}
@@ -1155,14 +1161,8 @@ void qlt_unreg_sess(struct fc_port *sess)
sess->last_rscn_gen = sess->rscn_gen;
sess->last_login_gen = sess->login_gen;
- if (sess->nvme_flag & NVME_FLAG_REGISTERED &&
- !(sess->nvme_flag & NVME_FLAG_DELETING)) {
- sess->nvme_flag |= NVME_FLAG_DELETING;
- schedule_work(&sess->nvme_del_work);
- } else {
- INIT_WORK(&sess->free_work, qlt_free_session_done);
- schedule_work(&sess->free_work);
- }
+ INIT_WORK(&sess->free_work, qlt_free_session_done);
+ schedule_work(&sess->free_work);
}
EXPORT_SYMBOL(qlt_unreg_sess);
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 653d5ea6c5d9..1f5b5c8a7f72 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -86,15 +86,10 @@ unsigned int scsi_logging_level;
EXPORT_SYMBOL(scsi_logging_level);
#endif
-/* sd, scsi core and power management need to coordinate flushing async actions */
-ASYNC_DOMAIN(scsi_sd_probe_domain);
-EXPORT_SYMBOL(scsi_sd_probe_domain);
-
/*
- * Separate domain (from scsi_sd_probe_domain) to maximize the benefit of
- * asynchronous system resume operations. It is marked 'exclusive' to avoid
- * being included in the async_synchronize_full() that is invoked by
- * dpm_resume()
+ * Domain for asynchronous system resume operations. It is marked 'exclusive'
+ * to avoid being included in the async_synchronize_full() that is invoked by
+ * dpm_resume().
*/
ASYNC_DOMAIN_EXCLUSIVE(scsi_sd_pm_domain);
EXPORT_SYMBOL(scsi_sd_pm_domain);
@@ -821,7 +816,6 @@ static void __exit exit_scsi(void)
scsi_exit_devinfo();
scsi_exit_procfs();
scsi_exit_queue();
- async_unregister_domain(&scsi_sd_probe_domain);
}
subsys_initcall(init_scsi);
diff --git a/drivers/scsi/scsi_debugfs.h b/drivers/scsi/scsi_debugfs.h
index 951b043e82d0..d125d1bd4184 100644
--- a/drivers/scsi/scsi_debugfs.h
+++ b/drivers/scsi/scsi_debugfs.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
struct request;
struct seq_file;
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index bfa569facd5b..1c470e31ae81 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -1055,7 +1055,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
struct scsi_device *sdev = scmd->device;
struct Scsi_Host *shost = sdev->host;
DECLARE_COMPLETION_ONSTACK(done);
- unsigned long timeleft = timeout;
+ unsigned long timeleft = timeout, delay;
struct scsi_eh_save ses;
const unsigned long stall_for = msecs_to_jiffies(100);
int rtn;
@@ -1066,7 +1066,29 @@ retry:
scsi_log_send(scmd);
scmd->scsi_done = scsi_eh_done;
- rtn = shost->hostt->queuecommand(shost, scmd);
+
+ /*
+ * Lock sdev->state_mutex to avoid that scsi_device_quiesce() can
+ * change the SCSI device state after we have examined it and before
+ * .queuecommand() is called.
+ */
+ mutex_lock(&sdev->state_mutex);
+ while (sdev->sdev_state == SDEV_BLOCK && timeleft > 0) {
+ mutex_unlock(&sdev->state_mutex);
+ SCSI_LOG_ERROR_RECOVERY(5, sdev_printk(KERN_DEBUG, sdev,
+ "%s: state %d <> %d\n", __func__, sdev->sdev_state,
+ SDEV_BLOCK));
+ delay = min(timeleft, stall_for);
+ timeleft -= delay;
+ msleep(jiffies_to_msecs(delay));
+ mutex_lock(&sdev->state_mutex);
+ }
+ if (sdev->sdev_state != SDEV_BLOCK)
+ rtn = shost->hostt->queuecommand(shost, scmd);
+ else
+ rtn = SCSI_MLQUEUE_DEVICE_BUSY;
+ mutex_unlock(&sdev->state_mutex);
+
if (rtn) {
if (timeleft > stall_for) {
scsi_eh_restore_cmnd(scmd, &ses);
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 65d0a10c76ad..e1da8c70a266 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -40,6 +40,18 @@
#include "scsi_priv.h"
#include "scsi_logging.h"
+/*
+ * Size of integrity metadata is usually small, 1 inline sg should
+ * cover normal cases.
+ */
+#ifdef CONFIG_ARCH_NO_SG_CHAIN
+#define SCSI_INLINE_PROT_SG_CNT 0
+#define SCSI_INLINE_SG_CNT 0
+#else
+#define SCSI_INLINE_PROT_SG_CNT 1
+#define SCSI_INLINE_SG_CNT 2
+#endif
+
static struct kmem_cache *scsi_sdb_cache;
static struct kmem_cache *scsi_sense_cache;
static struct kmem_cache *scsi_sense_isadma_cache;
@@ -542,9 +554,11 @@ static void scsi_uninit_cmd(struct scsi_cmnd *cmd)
static void scsi_mq_free_sgtables(struct scsi_cmnd *cmd)
{
if (cmd->sdb.table.nents)
- sg_free_table_chained(&cmd->sdb.table, true);
+ sg_free_table_chained(&cmd->sdb.table,
+ SCSI_INLINE_SG_CNT);
if (scsi_prot_sg_count(cmd))
- sg_free_table_chained(&cmd->prot_sdb->table, true);
+ sg_free_table_chained(&cmd->prot_sdb->table,
+ SCSI_INLINE_PROT_SG_CNT);
}
static void scsi_mq_uninit_cmd(struct scsi_cmnd *cmd)
@@ -977,7 +991,8 @@ static blk_status_t scsi_init_sgtable(struct request *req,
* If sg table allocation fails, requeue request later.
*/
if (unlikely(sg_alloc_table_chained(&sdb->table,
- blk_rq_nr_phys_segments(req), sdb->table.sgl)))
+ blk_rq_nr_phys_segments(req), sdb->table.sgl,
+ SCSI_INLINE_SG_CNT)))
return BLK_STS_RESOURCE;
/*
@@ -1031,7 +1046,8 @@ blk_status_t scsi_init_io(struct scsi_cmnd *cmd)
ivecs = blk_rq_count_integrity_sg(rq->q, rq->bio);
if (sg_alloc_table_chained(&prot_sdb->table, ivecs,
- prot_sdb->table.sgl)) {
+ prot_sdb->table.sgl,
+ SCSI_INLINE_PROT_SG_CNT)) {
ret = BLK_STS_RESOURCE;
goto out_free_sgtables;
}
@@ -1542,9 +1558,9 @@ static int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
}
/* Size in bytes of the sg-list stored in the scsi-mq command-private data. */
-static unsigned int scsi_mq_sgl_size(struct Scsi_Host *shost)
+static unsigned int scsi_mq_inline_sgl_size(struct Scsi_Host *shost)
{
- return min_t(unsigned int, shost->sg_tablesize, SG_CHUNK_SIZE) *
+ return min_t(unsigned int, shost->sg_tablesize, SCSI_INLINE_SG_CNT) *
sizeof(struct scatterlist);
}
@@ -1726,7 +1742,7 @@ static int scsi_mq_init_request(struct blk_mq_tag_set *set, struct request *rq,
if (scsi_host_get_prot(shost)) {
sg = (void *)cmd + sizeof(struct scsi_cmnd) +
shost->hostt->cmd_size;
- cmd->prot_sdb = (void *)sg + scsi_mq_sgl_size(shost);
+ cmd->prot_sdb = (void *)sg + scsi_mq_inline_sgl_size(shost);
}
return 0;
@@ -1820,10 +1836,11 @@ int scsi_mq_setup_tags(struct Scsi_Host *shost)
{
unsigned int cmd_size, sgl_size;
- sgl_size = scsi_mq_sgl_size(shost);
+ sgl_size = scsi_mq_inline_sgl_size(shost);
cmd_size = sizeof(struct scsi_cmnd) + shost->hostt->cmd_size + sgl_size;
if (scsi_host_get_prot(shost))
- cmd_size += sizeof(struct scsi_data_buffer) + sgl_size;
+ cmd_size += sizeof(struct scsi_data_buffer) +
+ sizeof(struct scatterlist) * SCSI_INLINE_PROT_SG_CNT;
memset(&shost->tag_set, 0, sizeof(shost->tag_set));
shost->tag_set.ops = &scsi_mq_ops;
@@ -2616,10 +2633,6 @@ EXPORT_SYMBOL_GPL(scsi_internal_device_block_nowait);
* a legal transition). When the device is in this state, command processing
* is paused until the device leaves the SDEV_BLOCK state. See also
* scsi_internal_device_unblock().
- *
- * To do: avoid that scsi_send_eh_cmnd() calls queuecommand() after
- * scsi_internal_device_block() has blocked a SCSI device and also
- * remove the rport mutex lock and unlock calls from srp_queuecommand().
*/
static int scsi_internal_device_block(struct scsi_device *sdev)
{
diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c
index 48ee68059fe6..74ded5f3c236 100644
--- a/drivers/scsi/scsi_pm.c
+++ b/drivers/scsi/scsi_pm.c
@@ -176,11 +176,7 @@ static int scsi_bus_resume_common(struct device *dev,
static int scsi_bus_prepare(struct device *dev)
{
- if (scsi_is_sdev_device(dev)) {
- /* sd probing uses async_schedule. Wait until it finishes. */
- async_synchronize_full_domain(&scsi_sd_probe_domain);
-
- } else if (scsi_is_host_device(dev)) {
+ if (scsi_is_host_device(dev)) {
/* Wait until async scanning is finished */
scsi_complete_async_scans();
}
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index 5f21547b2ad2..cc2859d76d81 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -175,7 +175,6 @@ static inline void scsi_autopm_put_host(struct Scsi_Host *h) {}
#endif /* CONFIG_PM */
extern struct async_domain scsi_sd_pm_domain;
-extern struct async_domain scsi_sd_probe_domain;
/* scsi_dh.c */
#ifdef CONFIG_SCSI_DH
diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c
index 7f0ceb65c3f3..c074631086a4 100644
--- a/drivers/scsi/scsi_proc.c
+++ b/drivers/scsi/scsi_proc.c
@@ -372,7 +372,7 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf,
return err;
}
-static int always_match(struct device *dev, void *data)
+static int always_match(struct device *dev, const void *data)
{
return 1;
}
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index dbb206c90ecf..64c96c7828ee 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -767,8 +767,13 @@ store_state_field(struct device *dev, struct device_attribute *attr,
break;
}
}
- if (!state)
+ switch (state) {
+ case SDEV_RUNNING:
+ case SDEV_OFFLINE:
+ break;
+ default:
return -EINVAL;
+ }
mutex_lock(&sdev->state_mutex);
ret = scsi_device_set_state(sdev, state);
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 118a687709ed..2732fa65119c 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -3,9 +3,6 @@
* FiberChannel transport specific attributes exported to sysfs.
*
* Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved.
- *
- * ========
- *
* Copyright (C) 2004-2007 James Smart, Emulex Corporation
* Rewrite for host, target, device, and remote port attributes,
* statistics, and service functions...
diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c
index 4e46fdb2d7c9..d4d1104fac99 100644
--- a/drivers/scsi/scsi_transport_srp.c
+++ b/drivers/scsi/scsi_transport_srp.c
@@ -1,22 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* SCSI RDMA (SRP) transport class
*
* Copyright (C) 2007 FUJITA Tomonori <tomof@acm.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, version 2 of the
- * License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
*/
#include <linux/init.h>
#include <linux/module.h>
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index a3406bd62391..149d406aacc9 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -568,6 +568,7 @@ static struct scsi_driver sd_template = {
.name = "sd",
.owner = THIS_MODULE,
.probe = sd_probe,
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
.remove = sd_remove,
.shutdown = sd_shutdown,
.pm = &sd_pm_ops,
@@ -3252,69 +3253,6 @@ static int sd_format_disk_name(char *prefix, int index, char *buf, int buflen)
return 0;
}
-/*
- * The asynchronous part of sd_probe
- */
-static void sd_probe_async(void *data, async_cookie_t cookie)
-{
- struct scsi_disk *sdkp = data;
- struct scsi_device *sdp;
- struct gendisk *gd;
- u32 index;
- struct device *dev;
-
- sdp = sdkp->device;
- gd = sdkp->disk;
- index = sdkp->index;
- dev = &sdp->sdev_gendev;
-
- gd->major = sd_major((index & 0xf0) >> 4);
- gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00);
-
- gd->fops = &sd_fops;
- gd->private_data = &sdkp->driver;
- gd->queue = sdkp->device->request_queue;
-
- /* defaults, until the device tells us otherwise */
- sdp->sector_size = 512;
- sdkp->capacity = 0;
- sdkp->media_present = 1;
- sdkp->write_prot = 0;
- sdkp->cache_override = 0;
- sdkp->WCE = 0;
- sdkp->RCD = 0;
- sdkp->ATO = 0;
- sdkp->first_scan = 1;
- sdkp->max_medium_access_timeouts = SD_MAX_MEDIUM_TIMEOUTS;
-
- sd_revalidate_disk(gd);
-
- gd->flags = GENHD_FL_EXT_DEVT;
- if (sdp->removable) {
- gd->flags |= GENHD_FL_REMOVABLE;
- gd->events |= DISK_EVENT_MEDIA_CHANGE;
- gd->event_flags = DISK_EVENT_FLAG_POLL | DISK_EVENT_FLAG_UEVENT;
- }
-
- blk_pm_runtime_init(sdp->request_queue, dev);
- device_add_disk(dev, gd, NULL);
- if (sdkp->capacity)
- sd_dif_config_host(sdkp);
-
- sd_revalidate_disk(gd);
-
- if (sdkp->security) {
- sdkp->opal_dev = init_opal_dev(sdp, &sd_sec_submit);
- if (sdkp->opal_dev)
- sd_printk(KERN_NOTICE, sdkp, "supports TCG Opal\n");
- }
-
- sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
- sdp->removable ? "removable " : "");
- scsi_autopm_put_device(sdp);
- put_device(&sdkp->dev);
-}
-
/**
* sd_probe - called during driver initialization and whenever a
* new scsi device is attached to the system. It is called once
@@ -3404,8 +3342,50 @@ static int sd_probe(struct device *dev)
get_device(dev);
dev_set_drvdata(dev, sdkp);
- get_device(&sdkp->dev); /* prevent release before async_schedule */
- async_schedule_domain(sd_probe_async, sdkp, &scsi_sd_probe_domain);
+ gd->major = sd_major((index & 0xf0) >> 4);
+ gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00);
+
+ gd->fops = &sd_fops;
+ gd->private_data = &sdkp->driver;
+ gd->queue = sdkp->device->request_queue;
+
+ /* defaults, until the device tells us otherwise */
+ sdp->sector_size = 512;
+ sdkp->capacity = 0;
+ sdkp->media_present = 1;
+ sdkp->write_prot = 0;
+ sdkp->cache_override = 0;
+ sdkp->WCE = 0;
+ sdkp->RCD = 0;
+ sdkp->ATO = 0;
+ sdkp->first_scan = 1;
+ sdkp->max_medium_access_timeouts = SD_MAX_MEDIUM_TIMEOUTS;
+
+ sd_revalidate_disk(gd);
+
+ gd->flags = GENHD_FL_EXT_DEVT;
+ if (sdp->removable) {
+ gd->flags |= GENHD_FL_REMOVABLE;
+ gd->events |= DISK_EVENT_MEDIA_CHANGE;
+ gd->event_flags = DISK_EVENT_FLAG_POLL | DISK_EVENT_FLAG_UEVENT;
+ }
+
+ blk_pm_runtime_init(sdp->request_queue, dev);
+ device_add_disk(dev, gd, NULL);
+ if (sdkp->capacity)
+ sd_dif_config_host(sdkp);
+
+ sd_revalidate_disk(gd);
+
+ if (sdkp->security) {
+ sdkp->opal_dev = init_opal_dev(sdp, &sd_sec_submit);
+ if (sdkp->opal_dev)
+ sd_printk(KERN_NOTICE, sdkp, "supports TCG Opal\n");
+ }
+
+ sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
+ sdp->removable ? "removable " : "");
+ scsi_autopm_put_device(sdp);
return 0;
@@ -3441,7 +3421,6 @@ static int sd_remove(struct device *dev)
scsi_autopm_get_device(sdkp->device);
async_synchronize_full_domain(&scsi_sd_pm_domain);
- async_synchronize_full_domain(&scsi_sd_probe_domain);
device_del(&sdkp->dev);
del_gendisk(sdkp->disk);
sd_shutdown(dev);
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h
index 5796ace76225..38c50946fc42 100644
--- a/drivers/scsi/sd.h
+++ b/drivers/scsi/sd.h
@@ -213,8 +213,7 @@ extern blk_status_t sd_zbc_setup_reset_cmnd(struct scsi_cmnd *cmd);
extern void sd_zbc_complete(struct scsi_cmnd *cmd, unsigned int good_bytes,
struct scsi_sense_hdr *sshdr);
extern int sd_zbc_report_zones(struct gendisk *disk, sector_t sector,
- struct blk_zone *zones, unsigned int *nr_zones,
- gfp_t gfp_mask);
+ struct blk_zone *zones, unsigned int *nr_zones);
#else /* CONFIG_BLK_DEV_ZONED */
diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c
index 7334024b64f1..db16c19e05c4 100644
--- a/drivers/scsi/sd_zbc.c
+++ b/drivers/scsi/sd_zbc.c
@@ -9,6 +9,8 @@
*/
#include <linux/blkdev.h>
+#include <linux/vmalloc.h>
+#include <linux/sched/mm.h>
#include <asm/unaligned.h>
@@ -50,7 +52,7 @@ static void sd_zbc_parse_report(struct scsi_disk *sdkp, u8 *buf,
/**
* sd_zbc_do_report_zones - Issue a REPORT ZONES scsi command.
* @sdkp: The target disk
- * @buf: Buffer to use for the reply
+ * @buf: vmalloc-ed buffer to use for the reply
* @buflen: the buffer size
* @lba: Start LBA of the report
* @partial: Do partial report
@@ -79,7 +81,6 @@ static int sd_zbc_do_report_zones(struct scsi_disk *sdkp, unsigned char *buf,
put_unaligned_be32(buflen, &cmd[10]);
if (partial)
cmd[14] = ZBC_REPORT_ZONE_PARTIAL;
- memset(buf, 0, buflen);
result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE,
buf, buflen, &sshdr,
@@ -103,45 +104,83 @@ static int sd_zbc_do_report_zones(struct scsi_disk *sdkp, unsigned char *buf,
return 0;
}
+/*
+ * Maximum number of zones to get with one report zones command.
+ */
+#define SD_ZBC_REPORT_MAX_ZONES 8192U
+
+/**
+ * Allocate a buffer for report zones reply.
+ * @sdkp: The target disk
+ * @nr_zones: Maximum number of zones to report
+ * @buflen: Size of the buffer allocated
+ *
+ * Try to allocate a reply buffer for the number of requested zones.
+ * The size of the buffer allocated may be smaller than requested to
+ * satify the device constraint (max_hw_sectors, max_segments, etc).
+ *
+ * Return the address of the allocated buffer and update @buflen with
+ * the size of the allocated buffer.
+ */
+static void *sd_zbc_alloc_report_buffer(struct scsi_disk *sdkp,
+ unsigned int nr_zones, size_t *buflen)
+{
+ struct request_queue *q = sdkp->disk->queue;
+ size_t bufsize;
+ void *buf;
+
+ /*
+ * Report zone buffer size should be at most 64B times the number of
+ * zones requested plus the 64B reply header, but should be at least
+ * SECTOR_SIZE for ATA devices.
+ * Make sure that this size does not exceed the hardware capabilities.
+ * Furthermore, since the report zone command cannot be split, make
+ * sure that the allocated buffer can always be mapped by limiting the
+ * number of pages allocated to the HBA max segments limit.
+ */
+ nr_zones = min(nr_zones, SD_ZBC_REPORT_MAX_ZONES);
+ bufsize = roundup((nr_zones + 1) * 64, 512);
+ bufsize = min_t(size_t, bufsize,
+ queue_max_hw_sectors(q) << SECTOR_SHIFT);
+ bufsize = min_t(size_t, bufsize, queue_max_segments(q) << PAGE_SHIFT);
+
+ buf = vzalloc(bufsize);
+ if (buf)
+ *buflen = bufsize;
+
+ return buf;
+}
+
/**
* sd_zbc_report_zones - Disk report zones operation.
* @disk: The target disk
* @sector: Start 512B sector of the report
* @zones: Array of zone descriptors
* @nr_zones: Number of descriptors in the array
- * @gfp_mask: Memory allocation mask
*
* Execute a report zones command on the target disk.
*/
int sd_zbc_report_zones(struct gendisk *disk, sector_t sector,
- struct blk_zone *zones, unsigned int *nr_zones,
- gfp_t gfp_mask)
+ struct blk_zone *zones, unsigned int *nr_zones)
{
struct scsi_disk *sdkp = scsi_disk(disk);
- unsigned int i, buflen, nrz = *nr_zones;
+ unsigned int i, nrz = *nr_zones;
unsigned char *buf;
- size_t offset = 0;
+ size_t buflen = 0, offset = 0;
int ret = 0;
if (!sd_is_zoned(sdkp))
/* Not a zoned device */
return -EOPNOTSUPP;
- /*
- * Get a reply buffer for the number of requested zones plus a header,
- * without exceeding the device maximum command size. For ATA disks,
- * buffers must be aligned to 512B.
- */
- buflen = min(queue_max_hw_sectors(disk->queue) << 9,
- roundup((nrz + 1) * 64, 512));
- buf = kmalloc(buflen, gfp_mask);
+ buf = sd_zbc_alloc_report_buffer(sdkp, nrz, &buflen);
if (!buf)
return -ENOMEM;
ret = sd_zbc_do_report_zones(sdkp, buf, buflen,
sectors_to_logical(sdkp->device, sector), true);
if (ret)
- goto out_free_buf;
+ goto out;
nrz = min(nrz, get_unaligned_be32(&buf[0]) / 64);
for (i = 0; i < nrz; i++) {
@@ -152,8 +191,8 @@ int sd_zbc_report_zones(struct gendisk *disk, sector_t sector,
*nr_zones = nrz;
-out_free_buf:
- kfree(buf);
+out:
+ kvfree(buf);
return ret;
}
@@ -287,8 +326,6 @@ static int sd_zbc_check_zoned_characteristics(struct scsi_disk *sdkp,
return 0;
}
-#define SD_ZBC_BUF_SIZE 131072U
-
/**
* sd_zbc_check_zones - Check the device capacity and zone sizes
* @sdkp: Target disk
@@ -304,22 +341,28 @@ static int sd_zbc_check_zoned_characteristics(struct scsi_disk *sdkp,
*/
static int sd_zbc_check_zones(struct scsi_disk *sdkp, u32 *zblocks)
{
+ size_t bufsize, buflen;
+ unsigned int noio_flag;
u64 zone_blocks = 0;
sector_t max_lba, block = 0;
unsigned char *buf;
unsigned char *rec;
- unsigned int buf_len;
- unsigned int list_length;
int ret;
u8 same;
+ /* Do all memory allocations as if GFP_NOIO was specified */
+ noio_flag = memalloc_noio_save();
+
/* Get a buffer */
- buf = kmalloc(SD_ZBC_BUF_SIZE, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
+ buf = sd_zbc_alloc_report_buffer(sdkp, SD_ZBC_REPORT_MAX_ZONES,
+ &bufsize);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto out;
+ }
/* Do a report zone to get max_lba and the same field */
- ret = sd_zbc_do_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, 0, false);
+ ret = sd_zbc_do_report_zones(sdkp, buf, bufsize, 0, false);
if (ret)
goto out_free;
@@ -355,12 +398,12 @@ static int sd_zbc_check_zones(struct scsi_disk *sdkp, u32 *zblocks)
do {
/* Parse REPORT ZONES header */
- list_length = get_unaligned_be32(&buf[0]) + 64;
+ buflen = min_t(size_t, get_unaligned_be32(&buf[0]) + 64,
+ bufsize);
rec = buf + 64;
- buf_len = min(list_length, SD_ZBC_BUF_SIZE);
/* Parse zone descriptors */
- while (rec < buf + buf_len) {
+ while (rec < buf + buflen) {
u64 this_zone_blocks = get_unaligned_be64(&rec[8]);
if (zone_blocks == 0) {
@@ -376,8 +419,8 @@ static int sd_zbc_check_zones(struct scsi_disk *sdkp, u32 *zblocks)
}
if (block < sdkp->capacity) {
- ret = sd_zbc_do_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE,
- block, true);
+ ret = sd_zbc_do_report_zones(sdkp, buf, bufsize, block,
+ true);
if (ret)
goto out_free;
}
@@ -408,7 +451,8 @@ out:
}
out_free:
- kfree(buf);
+ memalloc_noio_restore(noio_flag);
+ kvfree(buf);
return ret;
}
diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c
index 60f01a7b728c..c2afba2a5414 100644
--- a/drivers/scsi/ses.c
+++ b/drivers/scsi/ses.c
@@ -3,12 +3,7 @@
* SCSI Enclosure Services
*
* Copyright (C) 2008 James Bottomley <James.Bottomley@HansenPartnership.com>
- *
-**-----------------------------------------------------------------------------
-**
-**
-**-----------------------------------------------------------------------------
-*/
+ */
#include <linux/slab.h>
#include <linux/module.h>
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index baada5b50bb1..e3266a64a477 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -228,7 +228,6 @@ static DEFINE_IDR(st_index_idr);
-#include "osst_detect.h"
#ifndef SIGS_FROM_OSST
#define SIGS_FROM_OSST \
{"OnStream", "SC-", "", "osst"}, \
@@ -4267,9 +4266,10 @@ static int st_probe(struct device *dev)
if (SDp->type != TYPE_TAPE)
return -ENODEV;
if ((stp = st_incompatible(SDp))) {
- sdev_printk(KERN_INFO, SDp, "Found incompatible tape\n");
sdev_printk(KERN_INFO, SDp,
- "st: The suggested driver is %s.\n", stp);
+ "OnStream tapes are no longer supported;\n");
+ sdev_printk(KERN_INFO, SDp,
+ "please mail to linux-scsi@vger.kernel.org.\n");
return -ENODEV;
}
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index b89269120a2d..c2b6a0ca6933 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -375,6 +375,7 @@ enum storvsc_request_type {
static int storvsc_ringbuffer_size = (128 * 1024);
static u32 max_outstanding_req_per_channel;
+static int storvsc_change_queue_depth(struct scsi_device *sdev, int queue_depth);
static int storvsc_vcpus_per_sub_channel = 4;
@@ -1699,6 +1700,7 @@ static struct scsi_host_template scsi_driver = {
.dma_boundary = PAGE_SIZE-1,
.no_write_same = 1,
.track_queue_depth = 1,
+ .change_queue_depth = storvsc_change_queue_depth,
};
enum {
@@ -1905,6 +1907,15 @@ err_out0:
return ret;
}
+/* Change a scsi target's queue depth */
+static int storvsc_change_queue_depth(struct scsi_device *sdev, int queue_depth)
+{
+ if (queue_depth > scsi_driver.can_queue)
+ queue_depth = scsi_driver.can_queue;
+
+ return scsi_change_queue_depth(sdev, queue_depth);
+}
+
static int storvsc_remove(struct hv_device *dev)
{
struct storvsc_device *stor_device = hv_get_drvdata(dev);
diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c b/drivers/scsi/ufs/tc-dwc-g210-pci.c
index 2f41722a8c28..67a6a61154b7 100644
--- a/drivers/scsi/ufs/tc-dwc-g210-pci.c
+++ b/drivers/scsi/ufs/tc-dwc-g210-pci.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Synopsys G210 Test Chip driver
*
* Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
*
* Authors: Joao Pinto <jpinto@synopsys.com>
- *
- * 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.
*/
#include "ufshcd.h"
diff --git a/drivers/scsi/ufs/tc-dwc-g210-pltfrm.c b/drivers/scsi/ufs/tc-dwc-g210-pltfrm.c
index 6dfe5a9206e9..a1268e4f44d6 100644
--- a/drivers/scsi/ufs/tc-dwc-g210-pltfrm.c
+++ b/drivers/scsi/ufs/tc-dwc-g210-pltfrm.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Synopsys G210 Test Chip driver
*
* Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
*
* Authors: Joao Pinto <jpinto@synopsys.com>
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/scsi/ufs/tc-dwc-g210.c b/drivers/scsi/ufs/tc-dwc-g210.c
index 3a8bc6d9cb5b..f954a68f6b4c 100644
--- a/drivers/scsi/ufs/tc-dwc-g210.c
+++ b/drivers/scsi/ufs/tc-dwc-g210.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Synopsys G210 Test Chip driver
*
* Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
*
* Authors: Joao Pinto <jpinto@synopsys.com>
- *
- * 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.
*/
#include "ufshcd.h"
diff --git a/drivers/scsi/ufs/tc-dwc-g210.h b/drivers/scsi/ufs/tc-dwc-g210.h
index fb177db1227d..5a506da03f4a 100644
--- a/drivers/scsi/ufs/tc-dwc-g210.h
+++ b/drivers/scsi/ufs/tc-dwc-g210.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Synopsys G210 Test Chip driver
*
* Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
*
* Authors: Joao Pinto <jpinto@synopsys.com>
- *
- * 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.
*/
#ifndef _TC_DWC_G210_H
diff --git a/drivers/scsi/ufs/ufs-hisi.c b/drivers/scsi/ufs/ufs-hisi.c
index 7aed0a1a794e..f4d1dca962c4 100644
--- a/drivers/scsi/ufs/ufs-hisi.c
+++ b/drivers/scsi/ufs/ufs-hisi.c
@@ -1,11 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* HiSilicon Hixxxx UFS Driver
*
* Copyright (c) 2016-2017 Linaro Ltd.
* Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
- *
- * Released under the GPLv2 only.
- * SPDX-License-Identifier: GPL-2.0
*/
#include <linux/time.h>
diff --git a/drivers/scsi/ufs/ufs-hisi.h b/drivers/scsi/ufs/ufs-hisi.h
index 667dfe39b57e..3231d3d81c98 100644
--- a/drivers/scsi/ufs/ufs-hisi.h
+++ b/drivers/scsi/ufs/ufs-hisi.h
@@ -1,8 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2017, HiSilicon. All rights reserved.
- *
- * Released under the GPLv2 only.
- * SPDX-License-Identifier: GPL-2.0
*/
#ifndef UFS_HISI_H_
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index b4d1b5c22987..ee4b1da1e223 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -3,6 +3,7 @@
* Copyright (c) 2013-2016, Linux Foundation. All rights reserved.
*/
+#include <linux/acpi.h>
#include <linux/time.h>
#include <linux/of.h>
#include <linux/platform_device.h>
@@ -161,6 +162,9 @@ static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host)
int err = 0;
struct device *dev = host->hba->dev;
+ if (has_acpi_companion(dev))
+ return 0;
+
err = ufs_qcom_host_clk_get(dev, "rx_lane0_sync_clk",
&host->rx_l0_sync_clk, false);
if (err)
@@ -1127,9 +1131,13 @@ static int ufs_qcom_init(struct ufs_hba *hba)
__func__, err);
goto out_variant_clear;
} else if (IS_ERR(host->generic_phy)) {
- err = PTR_ERR(host->generic_phy);
- dev_err(dev, "%s: PHY get failed %d\n", __func__, err);
- goto out_variant_clear;
+ if (has_acpi_companion(dev)) {
+ host->generic_phy = NULL;
+ } else {
+ err = PTR_ERR(host->generic_phy);
+ dev_err(dev, "%s: PHY get failed %d\n", __func__, err);
+ goto out_variant_clear;
+ }
}
err = ufs_qcom_bus_register(host);
@@ -1599,6 +1607,14 @@ static const struct of_device_id ufs_qcom_of_match[] = {
};
MODULE_DEVICE_TABLE(of, ufs_qcom_of_match);
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id ufs_qcom_acpi_match[] = {
+ { "QCOM24A5" },
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, ufs_qcom_acpi_match);
+#endif
+
static const struct dev_pm_ops ufs_qcom_pm_ops = {
.suspend = ufshcd_pltfrm_suspend,
.resume = ufshcd_pltfrm_resume,
@@ -1615,6 +1631,7 @@ static struct platform_driver ufs_qcom_pltform = {
.name = "ufshcd-qcom",
.pm = &ufs_qcom_pm_ops,
.of_match_table = of_match_ptr(ufs_qcom_of_match),
+ .acpi_match_table = ACPI_PTR(ufs_qcom_acpi_match),
},
};
module_platform_driver(ufs_qcom_pltform);
diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c
index 8d9332bb7d0c..f478685122ff 100644
--- a/drivers/scsi/ufs/ufs-sysfs.c
+++ b/drivers/scsi/ufs/ufs-sysfs.c
@@ -122,7 +122,7 @@ static void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit)
{
unsigned long flags;
- if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT))
+ if (!ufshcd_is_auto_hibern8_supported(hba))
return;
spin_lock_irqsave(hba->host->host_lock, flags);
@@ -164,7 +164,7 @@ static ssize_t auto_hibern8_show(struct device *dev,
{
struct ufs_hba *hba = dev_get_drvdata(dev);
- if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT))
+ if (!ufshcd_is_auto_hibern8_supported(hba))
return -EOPNOTSUPP;
return snprintf(buf, PAGE_SIZE, "%d\n", ufshcd_ahit_to_us(hba->ahit));
@@ -177,7 +177,7 @@ static ssize_t auto_hibern8_store(struct device *dev,
struct ufs_hba *hba = dev_get_drvdata(dev);
unsigned int timer;
- if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT))
+ if (!ufshcd_is_auto_hibern8_supported(hba))
return -EOPNOTSUPP;
if (kstrtouint(buf, 0, &timer))
diff --git a/drivers/scsi/ufs/ufs_bsg.c b/drivers/scsi/ufs/ufs_bsg.c
index 869e71f861d6..a9344eb4e047 100644
--- a/drivers/scsi/ufs/ufs_bsg.c
+++ b/drivers/scsi/ufs/ufs_bsg.c
@@ -122,7 +122,7 @@ static int ufs_bsg_request(struct bsg_job *job)
memcpy(&uc, &bsg_request->upiu_req.uc, UIC_CMD_SIZE);
ret = ufshcd_send_uic_cmd(hba, &uc);
if (ret)
- dev_dbg(hba->dev,
+ dev_err(hba->dev,
"send uic cmd: error code %d\n", ret);
memcpy(&bsg_reply->upiu_rsp.uc, &uc, UIC_CMD_SIZE);
@@ -149,7 +149,9 @@ static int ufs_bsg_request(struct bsg_job *job)
out:
bsg_reply->result = ret;
job->reply_len = sizeof(struct ufs_bsg_reply);
- bsg_job_done(job, ret, bsg_reply->reply_payload_rcv_len);
+ /* complete the job here only if no error */
+ if (ret == 0)
+ bsg_job_done(job, ret, bsg_reply->reply_payload_rcv_len);
return ret;
}
diff --git a/drivers/scsi/ufs/ufshcd-dwc.c b/drivers/scsi/ufs/ufshcd-dwc.c
index 977b21871a5d..fb9e2ff4f8d2 100644
--- a/drivers/scsi/ufs/ufshcd-dwc.c
+++ b/drivers/scsi/ufs/ufshcd-dwc.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* UFS Host driver for Synopsys Designware Core
*
* Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
*
* Authors: Joao Pinto <jpinto@synopsys.com>
- *
- * 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.
*/
#include "ufshcd.h"
diff --git a/drivers/scsi/ufs/ufshcd-dwc.h b/drivers/scsi/ufs/ufshcd-dwc.h
index c8be295e0ebe..4268ca2eb64c 100644
--- a/drivers/scsi/ufs/ufshcd-dwc.h
+++ b/drivers/scsi/ufs/ufshcd-dwc.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* UFS Host driver for Synopsys Designware Core
*
* Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
*
* Authors: Joao Pinto <jpinto@synopsys.com>
- *
- * 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.
*/
#ifndef _UFSHCD_DWC_H
diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
index ffe6f82182ba..3b19de3ae9a3 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -200,6 +200,8 @@ static const struct dev_pm_ops ufshcd_pci_pm_ops = {
static const struct pci_device_id ufshcd_pci_tbl[] = {
{ PCI_VENDOR_ID_SAMSUNG, 0xC00C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ PCI_VDEVICE(INTEL, 0x9DFA), (kernel_ulong_t)&ufs_intel_cnl_hba_vops },
+ { PCI_VDEVICE(INTEL, 0x4B41), (kernel_ulong_t)&ufs_intel_cnl_hba_vops },
+ { PCI_VDEVICE(INTEL, 0x4B43), (kernel_ulong_t)&ufs_intel_cnl_hba_vops },
{ } /* terminate list */
};
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 8a74ec30c3d2..d7d521b394c3 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -430,24 +430,21 @@ int ufshcd_pltfrm_init(struct platform_device *pdev,
goto dealloc_host;
}
- pm_runtime_set_active(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
-
ufshcd_init_lanes_per_dir(hba);
err = ufshcd_init(hba, mmio_base, irq);
if (err) {
dev_err(dev, "Initialization failed\n");
- goto out_disable_rpm;
+ goto dealloc_host;
}
platform_set_drvdata(pdev, hba);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
return 0;
-out_disable_rpm:
- pm_runtime_disable(&pdev->dev);
- pm_runtime_set_suspended(&pdev->dev);
dealloc_host:
ufshcd_dealloc_host(hba);
out:
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 3fe3029617a8..04d3686511c8 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3908,7 +3908,7 @@ static void ufshcd_auto_hibern8_enable(struct ufs_hba *hba)
{
unsigned long flags;
- if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT) || !hba->ahit)
+ if (!ufshcd_is_auto_hibern8_supported(hba) || !hba->ahit)
return;
spin_lock_irqsave(hba->host->host_lock, flags);
@@ -5255,6 +5255,7 @@ static void ufshcd_err_handler(struct work_struct *work)
goto skip_err_handling;
}
if ((hba->saved_err & INT_FATAL_ERRORS) ||
+ (hba->saved_err & UFSHCD_UIC_HIBERN8_MASK) ||
((hba->saved_err & UIC_ERROR) &&
(hba->saved_uic_err & (UFSHCD_UIC_DL_PA_INIT_ERROR |
UFSHCD_UIC_DL_NAC_RECEIVED_ERROR |
@@ -5414,6 +5415,23 @@ static void ufshcd_update_uic_error(struct ufs_hba *hba)
__func__, hba->uic_error);
}
+static bool ufshcd_is_auto_hibern8_error(struct ufs_hba *hba,
+ u32 intr_mask)
+{
+ if (!ufshcd_is_auto_hibern8_supported(hba))
+ return false;
+
+ if (!(intr_mask & UFSHCD_UIC_HIBERN8_MASK))
+ return false;
+
+ if (hba->active_uic_cmd &&
+ (hba->active_uic_cmd->command == UIC_CMD_DME_HIBER_ENTER ||
+ hba->active_uic_cmd->command == UIC_CMD_DME_HIBER_EXIT))
+ return false;
+
+ return true;
+}
+
/**
* ufshcd_check_errors - Check for errors that need s/w attention
* @hba: per-adapter instance
@@ -5432,6 +5450,15 @@ static void ufshcd_check_errors(struct ufs_hba *hba)
queue_eh_work = true;
}
+ if (hba->errors & UFSHCD_UIC_HIBERN8_MASK) {
+ dev_err(hba->dev,
+ "%s: Auto Hibern8 %s failed - status: 0x%08x, upmcrs: 0x%08x\n",
+ __func__, (hba->errors & UIC_HIBERNATE_ENTER) ?
+ "Enter" : "Exit",
+ hba->errors, ufshcd_get_upmcrs(hba));
+ queue_eh_work = true;
+ }
+
if (queue_eh_work) {
/*
* update the transfer error masks to sticky bits, let's do this
@@ -5494,6 +5521,10 @@ static void ufshcd_tmc_handler(struct ufs_hba *hba)
static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
{
hba->errors = UFSHCD_ERROR_MASK & intr_status;
+
+ if (ufshcd_is_auto_hibern8_error(hba, intr_status))
+ hba->errors |= (UFSHCD_UIC_HIBERN8_MASK & intr_status);
+
if (hba->errors)
ufshcd_check_errors(hba);
@@ -8313,7 +8344,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
UIC_LINK_HIBERN8_STATE);
/* Set the default auto-hiberate idle timer value to 150 ms */
- if (hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT) {
+ if (ufshcd_is_auto_hibern8_supported(hba) && !hba->ahit) {
hba->ahit = FIELD_PREP(UFSHCI_AHIBERN8_TIMER_MASK, 150) |
FIELD_PREP(UFSHCI_AHIBERN8_SCALE_MASK, 3);
}
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index ecfa898b9ccc..994d73d03207 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -740,6 +740,11 @@ return true;
#endif
}
+static inline bool ufshcd_is_auto_hibern8_supported(struct ufs_hba *hba)
+{
+ return (hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT);
+}
+
#define ufshcd_writel(hba, val, reg) \
writel((val), (hba)->mmio_base + (reg))
#define ufshcd_readl(hba, reg) \
diff --git a/drivers/scsi/ufs/ufshci-dwc.h b/drivers/scsi/ufs/ufshci-dwc.h
index ca341fece310..6c290e272106 100644
--- a/drivers/scsi/ufs/ufshci-dwc.h
+++ b/drivers/scsi/ufs/ufshci-dwc.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* UFS Host driver for Synopsys Designware Core
*
* Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
*
* Authors: Joao Pinto <jpinto@synopsys.com>
- *
- * 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.
*/
#ifndef _UFSHCI_DWC_H
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index 6fa889de5ee5..dbb75cd28dc8 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -144,8 +144,10 @@ enum {
#define CONTROLLER_FATAL_ERROR 0x10000
#define SYSTEM_BUS_FATAL_ERROR 0x20000
-#define UFSHCD_UIC_PWR_MASK (UIC_HIBERNATE_ENTER |\
- UIC_HIBERNATE_EXIT |\
+#define UFSHCD_UIC_HIBERN8_MASK (UIC_HIBERNATE_ENTER |\
+ UIC_HIBERNATE_EXIT)
+
+#define UFSHCD_UIC_PWR_MASK (UFSHCD_UIC_HIBERN8_MASK |\
UIC_POWER_MODE)
#define UFSHCD_UIC_MASK (UIC_COMMAND_COMPL | UFSHCD_UIC_PWR_MASK)
diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
index 13f1b3b9923a..297e1076e571 100644
--- a/drivers/scsi/virtio_scsi.c
+++ b/drivers/scsi/virtio_scsi.c
@@ -74,9 +74,6 @@ struct virtio_scsi {
u32 num_queues;
- /* If the affinity hint is set for virtqueues */
- bool affinity_hint_set;
-
struct hlist_node node;
/* Protected by event_vq lock */
@@ -795,7 +792,7 @@ static int virtscsi_probe(struct virtio_device *vdev)
num_targets = virtscsi_config_get(vdev, max_target) + 1;
shost = scsi_host_alloc(&virtscsi_host_template,
- sizeof(*vscsi) + sizeof(vscsi->req_vqs[0]) * num_queues);
+ struct_size(vscsi, req_vqs, num_queues));
if (!shost)
return -ENOMEM;
diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c
index ecee4b3ff073..70008816c91f 100644
--- a/drivers/scsi/vmw_pvscsi.c
+++ b/drivers/scsi/vmw_pvscsi.c
@@ -335,7 +335,7 @@ static void pvscsi_create_sg(struct pvscsi_ctx *ctx,
BUG_ON(count > PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT);
sge = &ctx->sgl->sge[0];
- for (i = 0; i < count; i++, sg++) {
+ for (i = 0; i < count; i++, sg = sg_next(sg)) {
sge[i].addr = sg_dma_address(sg);
sge[i].length = sg_dma_len(sg);
sge[i].flags = 0;
@@ -763,6 +763,7 @@ static int pvscsi_queue_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd
struct pvscsi_adapter *adapter = shost_priv(host);
struct pvscsi_ctx *ctx;
unsigned long flags;
+ unsigned char op;
spin_lock_irqsave(&adapter->hw_lock, flags);
@@ -775,13 +776,14 @@ static int pvscsi_queue_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd
}
cmd->scsi_done = done;
+ op = cmd->cmnd[0];
dev_dbg(&cmd->device->sdev_gendev,
- "queued cmd %p, ctx %p, op=%x\n", cmd, ctx, cmd->cmnd[0]);
+ "queued cmd %p, ctx %p, op=%x\n", cmd, ctx, op);
spin_unlock_irqrestore(&adapter->hw_lock, flags);
- pvscsi_kick_io(adapter, cmd->cmnd[0]);
+ pvscsi_kick_io(adapter, op);
return 0;
}
diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
index f965a3ee9ce5..fb7b289fa09f 100644
--- a/drivers/scsi/wd33c93.c
+++ b/drivers/scsi/wd33c93.c
@@ -735,7 +735,7 @@ transfer_bytes(const wd33c93_regs regs, struct scsi_cmnd *cmd,
* source or destination for THIS transfer.
*/
if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
- ++cmd->SCp.buffer;
+ cmd->SCp.buffer = sg_next(cmd->SCp.buffer);
--cmd->SCp.buffers_residual;
cmd->SCp.this_residual = cmd->SCp.buffer->length;
cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
diff --git a/drivers/scsi/wd719x.c b/drivers/scsi/wd719x.c
index c2f40068f235..edc8a139a60d 100644
--- a/drivers/scsi/wd719x.c
+++ b/drivers/scsi/wd719x.c
@@ -108,8 +108,15 @@ static inline int wd719x_wait_done(struct wd719x *wd, int timeout)
}
if (status != WD719X_INT_NOERRORS) {
+ u8 sue = wd719x_readb(wd, WD719X_AMR_SCB_ERROR);
+ /* we get this after wd719x_dev_reset, it's not an error */
+ if (sue == WD719X_SUE_TERM)
+ return 0;
+ /* we get this after wd719x_bus_reset, it's not an error */
+ if (sue == WD719X_SUE_RESET)
+ return 0;
dev_err(&wd->pdev->dev, "direct command failed, status 0x%02x, SUE 0x%02x\n",
- status, wd719x_readb(wd, WD719X_AMR_SCB_ERROR));
+ status, sue);
return -EIO;
}
@@ -128,8 +135,10 @@ static int wd719x_direct_cmd(struct wd719x *wd, u8 opcode, u8 dev, u8 lun,
if (wd719x_wait_ready(wd))
return -ETIMEDOUT;
- /* make sure we get NO interrupts */
- dev |= WD719X_DISABLE_INT;
+ /* disable interrupts except for RESET/ABORT (it breaks them) */
+ if (opcode != WD719X_CMD_BUSRESET && opcode != WD719X_CMD_ABORT &&
+ opcode != WD719X_CMD_ABORT_TAG && opcode != WD719X_CMD_RESET)
+ dev |= WD719X_DISABLE_INT;
wd719x_writeb(wd, WD719X_AMR_CMD_PARAM, dev);
wd719x_writeb(wd, WD719X_AMR_CMD_PARAM_2, lun);
wd719x_writeb(wd, WD719X_AMR_CMD_PARAM_3, tag);
@@ -465,6 +474,7 @@ static int wd719x_abort(struct scsi_cmnd *cmd)
spin_lock_irqsave(wd->sh->host_lock, flags);
result = wd719x_direct_cmd(wd, action, cmd->device->id,
cmd->device->lun, cmd->tag, scb->phys, 0);
+ wd719x_finish_cmd(scb, DID_ABORT);
spin_unlock_irqrestore(wd->sh->host_lock, flags);
if (result)
return FAILED;
@@ -477,6 +487,7 @@ static int wd719x_reset(struct scsi_cmnd *cmd, u8 opcode, u8 device)
int result;
unsigned long flags;
struct wd719x *wd = shost_priv(cmd->device->host);
+ struct wd719x_scb *scb, *tmp;
dev_info(&wd->pdev->dev, "%s reset requested\n",
(opcode == WD719X_CMD_BUSRESET) ? "bus" : "device");
@@ -484,6 +495,12 @@ static int wd719x_reset(struct scsi_cmnd *cmd, u8 opcode, u8 device)
spin_lock_irqsave(wd->sh->host_lock, flags);
result = wd719x_direct_cmd(wd, opcode, device, 0, 0, 0,
WD719X_WAIT_FOR_SCSI_RESET);
+ /* flush all SCBs (or all for a device if dev_reset) */
+ list_for_each_entry_safe(scb, tmp, &wd->active_scbs, list) {
+ if (opcode == WD719X_CMD_BUSRESET ||
+ scb->cmd->device->id == device)
+ wd719x_finish_cmd(scb, DID_RESET);
+ }
spin_unlock_irqrestore(wd->sh->host_lock, flags);
if (result)
return FAILED;
@@ -506,22 +523,23 @@ static int wd719x_host_reset(struct scsi_cmnd *cmd)
struct wd719x *wd = shost_priv(cmd->device->host);
struct wd719x_scb *scb, *tmp;
unsigned long flags;
- int result;
dev_info(&wd->pdev->dev, "host reset requested\n");
spin_lock_irqsave(wd->sh->host_lock, flags);
- /* Try to reinit the RISC */
- if (wd719x_chip_init(wd) == 0)
- result = SUCCESS;
- else
- result = FAILED;
+ /* stop the RISC */
+ if (wd719x_direct_cmd(wd, WD719X_CMD_SLEEP, 0, 0, 0, 0,
+ WD719X_WAIT_FOR_RISC))
+ dev_warn(&wd->pdev->dev, "RISC sleep command failed\n");
+ /* disable RISC */
+ wd719x_writeb(wd, WD719X_PCI_MODE_SELECT, 0);
/* flush all SCBs */
list_for_each_entry_safe(scb, tmp, &wd->active_scbs, list)
- wd719x_finish_cmd(scb, result);
+ wd719x_finish_cmd(scb, DID_RESET);
spin_unlock_irqrestore(wd->sh->host_lock, flags);
- return result;
+ /* Try to reinit the RISC */
+ return wd719x_chip_init(wd) == 0 ? SUCCESS : FAILED;
}
static int wd719x_biosparam(struct scsi_device *sdev, struct block_device *bdev,
@@ -673,7 +691,7 @@ static irqreturn_t wd719x_interrupt(int irq, void *dev_id)
else
dev_err(&wd->pdev->dev, "card returned invalid SCB pointer\n");
} else
- dev_warn(&wd->pdev->dev, "direct command 0x%x completed\n",
+ dev_dbg(&wd->pdev->dev, "direct command 0x%x completed\n",
regs.bytes.OPC);
break;
case WD719X_INT_PIOREADY:
diff --git a/drivers/slimbus/core.c b/drivers/slimbus/core.c
index b2f07d2043eb..526e3215d8fe 100644
--- a/drivers/slimbus/core.c
+++ b/drivers/slimbus/core.c
@@ -98,11 +98,6 @@ static int slim_device_remove(struct device *dev)
static int slim_device_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct slim_device *sbdev = to_slim_device(dev);
- int ret;
-
- ret = of_device_uevent_modalias(dev, env);
- if (ret != -ENODEV)
- return ret;
return add_uevent_var(env, "MODALIAS=slim:%s", dev_name(&sbdev->dev));
}
diff --git a/drivers/slimbus/qcom-ctrl.c b/drivers/slimbus/qcom-ctrl.c
index ad3e2e23f56e..a444badd8df5 100644
--- a/drivers/slimbus/qcom-ctrl.c
+++ b/drivers/slimbus/qcom-ctrl.c
@@ -528,10 +528,8 @@ static int qcom_slim_probe(struct platform_device *pdev)
slim_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ctrl");
ctrl->base = devm_ioremap_resource(ctrl->dev, slim_mem);
- if (IS_ERR(ctrl->base)) {
- dev_err(&pdev->dev, "IOremap failed\n");
+ if (IS_ERR(ctrl->base))
return PTR_ERR(ctrl->base);
- }
sctrl->set_laddr = qcom_set_laddr;
sctrl->xfer_msg = qcom_xfer_msg;
diff --git a/drivers/slimbus/stream.c b/drivers/slimbus/stream.c
index 2fa05324ed07..75f87b3d8b95 100644
--- a/drivers/slimbus/stream.c
+++ b/drivers/slimbus/stream.c
@@ -84,7 +84,7 @@ static const int slim_presence_rate_table[] = {
512000,
};
-/*
+/**
* slim_stream_allocate() - Allocate a new SLIMbus Stream
* @dev:Slim device to be associated with
* @name: name of the stream
@@ -189,7 +189,7 @@ static int slim_get_prate_code(int rate)
return -EINVAL;
}
-/*
+/**
* slim_stream_prepare() - Prepare a SLIMbus Stream
*
* @rt: instance of slim stream runtime to configure
@@ -336,7 +336,7 @@ static int slim_activate_channel(struct slim_stream_runtime *stream,
return slim_do_transfer(sdev->ctrl, &txn);
}
-/*
+/**
* slim_stream_enable() - Enable a prepared SLIMbus Stream
*
* @stream: instance of slim stream runtime to enable
@@ -389,7 +389,7 @@ int slim_stream_enable(struct slim_stream_runtime *stream)
}
EXPORT_SYMBOL_GPL(slim_stream_enable);
-/*
+/**
* slim_stream_disable() - Disable a SLIMbus Stream
*
* @stream: instance of slim stream runtime to disable
@@ -423,7 +423,7 @@ int slim_stream_disable(struct slim_stream_runtime *stream)
}
EXPORT_SYMBOL_GPL(slim_stream_disable);
-/*
+/**
* slim_stream_unprepare() - Un-prepare a SLIMbus Stream
*
* @stream: instance of slim stream runtime to unprepare
@@ -449,7 +449,7 @@ int slim_stream_unprepare(struct slim_stream_runtime *stream)
}
EXPORT_SYMBOL_GPL(slim_stream_unprepare);
-/*
+/**
* slim_stream_free() - Free a SLIMbus Stream
*
* @stream: instance of slim stream runtime to free
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index 524ecdc2a9bb..2ec355003524 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -22,7 +22,7 @@ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
obj-$(CONFIG_SOC_SAMSUNG) += samsung/
obj-y += sunxi/
obj-$(CONFIG_ARCH_TEGRA) += tegra/
-obj-$(CONFIG_SOC_TI) += ti/
+obj-y += ti/
obj-$(CONFIG_ARCH_U8500) += ux500/
obj-$(CONFIG_PLAT_VERSATILE) += versatile/
obj-y += xilinx/
diff --git a/drivers/soc/bcm/brcmstb/biuctrl.c b/drivers/soc/bcm/brcmstb/biuctrl.c
index b3dbdb365749..d326915e0f40 100644
--- a/drivers/soc/bcm/brcmstb/biuctrl.c
+++ b/drivers/soc/bcm/brcmstb/biuctrl.c
@@ -48,7 +48,7 @@ static inline void cbc_writel(u32 val, int reg)
if (offset == -1)
return;
- writel_relaxed(val, cpubiuctrl_base + offset);
+ writel(val, cpubiuctrl_base + offset);
}
enum cpubiuctrl_regs {
@@ -238,7 +238,9 @@ static int __init brcmstb_biuctrl_init(void)
if (!np)
return 0;
- setup_hifcpubiuctrl_regs(np);
+ ret = setup_hifcpubiuctrl_regs(np);
+ if (ret)
+ return ret;
ret = mcp_write_pairing_set();
if (ret) {
diff --git a/drivers/soc/imx/soc-imx8.c b/drivers/soc/imx/soc-imx8.c
index fc6429f9170a..b1bd8e2543ac 100644
--- a/drivers/soc/imx/soc-imx8.c
+++ b/drivers/soc/imx/soc-imx8.c
@@ -103,6 +103,9 @@ static int __init imx8_soc_init(void)
if (IS_ERR(soc_dev))
goto free_rev;
+ if (IS_ENABLED(CONFIG_ARM_IMX_CPUFREQ_DT))
+ platform_device_register_simple("imx-cpufreq-dt", -1, NULL, 0);
+
return 0;
free_rev:
diff --git a/drivers/soc/ixp4xx/ixp4xx-npe.c b/drivers/soc/ixp4xx/ixp4xx-npe.c
index bc10e3194809..ec90b44fa0cd 100644
--- a/drivers/soc/ixp4xx/ixp4xx-npe.c
+++ b/drivers/soc/ixp4xx/ixp4xx-npe.c
@@ -695,8 +695,8 @@ static int ixp4xx_npe_probe(struct platform_device *pdev)
continue; /* NPE already disabled or not present */
}
npe->regs = devm_ioremap_resource(dev, res);
- if (!npe->regs)
- return -ENOMEM;
+ if (IS_ERR(npe->regs))
+ return PTR_ERR(npe->regs);
if (npe_reset(npe)) {
dev_info(dev, "NPE%d at 0x%08x-0x%08x does not reset\n",
diff --git a/drivers/soc/lantiq/fpi-bus.c b/drivers/soc/lantiq/fpi-bus.c
index a671c9984c4c..cb0303a0fe60 100644
--- a/drivers/soc/lantiq/fpi-bus.c
+++ b/drivers/soc/lantiq/fpi-bus.c
@@ -1,7 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
- * 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.
*
* Copyright (C) 2011-2015 John Crispin <blogic@phrozen.org>
* Copyright (C) 2015 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c
index 9ca7d9484de0..24cd193dec55 100644
--- a/drivers/soc/qcom/mdt_loader.c
+++ b/drivers/soc/qcom/mdt_loader.c
@@ -66,6 +66,66 @@ ssize_t qcom_mdt_get_size(const struct firmware *fw)
}
EXPORT_SYMBOL_GPL(qcom_mdt_get_size);
+/**
+ * qcom_mdt_read_metadata() - read header and metadata from mdt or mbn
+ * @fw: firmware of mdt header or mbn
+ * @data_len: length of the read metadata blob
+ *
+ * The mechanism that performs the authentication of the loading firmware
+ * expects an ELF header directly followed by the segment of hashes, with no
+ * padding inbetween. This function allocates a chunk of memory for this pair
+ * and copy the two pieces into the buffer.
+ *
+ * In the case of split firmware the hash is found directly following the ELF
+ * header, rather than at p_offset described by the second program header.
+ *
+ * The caller is responsible to free (kfree()) the returned pointer.
+ *
+ * Return: pointer to data, or ERR_PTR()
+ */
+void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len)
+{
+ const struct elf32_phdr *phdrs;
+ const struct elf32_hdr *ehdr;
+ size_t hash_offset;
+ size_t hash_size;
+ size_t ehdr_size;
+ void *data;
+
+ ehdr = (struct elf32_hdr *)fw->data;
+ phdrs = (struct elf32_phdr *)(ehdr + 1);
+
+ if (ehdr->e_phnum < 2)
+ return ERR_PTR(-EINVAL);
+
+ if (phdrs[0].p_type == PT_LOAD || phdrs[1].p_type == PT_LOAD)
+ return ERR_PTR(-EINVAL);
+
+ if ((phdrs[1].p_flags & QCOM_MDT_TYPE_MASK) != QCOM_MDT_TYPE_HASH)
+ return ERR_PTR(-EINVAL);
+
+ ehdr_size = phdrs[0].p_filesz;
+ hash_size = phdrs[1].p_filesz;
+
+ data = kmalloc(ehdr_size + hash_size, GFP_KERNEL);
+ if (!data)
+ return ERR_PTR(-ENOMEM);
+
+ /* Is the header and hash already packed */
+ if (ehdr_size + hash_size == fw->size)
+ hash_offset = phdrs[0].p_filesz;
+ else
+ hash_offset = phdrs[1].p_offset;
+
+ memcpy(data, fw->data, ehdr_size);
+ memcpy(data + ehdr_size, fw->data + hash_offset, hash_size);
+
+ *data_len = ehdr_size + hash_size;
+
+ return data;
+}
+EXPORT_SYMBOL_GPL(qcom_mdt_read_metadata);
+
static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
const char *firmware, int pas_id, void *mem_region,
phys_addr_t mem_phys, size_t mem_size,
@@ -78,12 +138,14 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
phys_addr_t mem_reloc;
phys_addr_t min_addr = PHYS_ADDR_MAX;
phys_addr_t max_addr = 0;
+ size_t metadata_len;
size_t fw_name_len;
ssize_t offset;
+ void *metadata;
char *fw_name;
bool relocate = false;
void *ptr;
- int ret;
+ int ret = 0;
int i;
if (!fw || !mem_region || !mem_phys || !mem_size)
@@ -101,7 +163,15 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
return -ENOMEM;
if (pas_init) {
- ret = qcom_scm_pas_init_image(pas_id, fw->data, fw->size);
+ metadata = qcom_mdt_read_metadata(fw, &metadata_len);
+ if (IS_ERR(metadata)) {
+ ret = PTR_ERR(metadata);
+ goto out;
+ }
+
+ ret = qcom_scm_pas_init_image(pas_id, metadata, metadata_len);
+
+ kfree(metadata);
if (ret) {
dev_err(dev, "invalid firmware metadata\n");
goto out;
@@ -162,7 +232,19 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
ptr = mem_region + offset;
- if (phdr->p_filesz) {
+ if (phdr->p_filesz && phdr->p_offset < fw->size) {
+ /* Firmware is large enough to be non-split */
+ if (phdr->p_offset + phdr->p_filesz > fw->size) {
+ dev_err(dev,
+ "failed to load segment %d from truncated file %s\n",
+ i, firmware);
+ ret = -EINVAL;
+ break;
+ }
+
+ memcpy(ptr, fw->data + phdr->p_offset, phdr->p_filesz);
+ } else if (phdr->p_filesz) {
+ /* Firmware not large enough, load split-out segments */
sprintf(fw_name + fw_name_len - 3, "b%02d", i);
ret = request_firmware_into_buf(&seg_fw, fw_name, dev,
ptr, phdr->p_filesz);
diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c
index 6b8ef01472e9..d5cf953b4337 100644
--- a/drivers/soc/qcom/qcom-geni-se.c
+++ b/drivers/soc/qcom/qcom-geni-se.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+#include <linux/acpi.h>
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
@@ -450,6 +451,9 @@ int geni_se_resources_off(struct geni_se *se)
{
int ret;
+ if (has_acpi_companion(se->dev))
+ return 0;
+
ret = pinctrl_pm_select_sleep_state(se->dev);
if (ret)
return ret;
@@ -487,6 +491,9 @@ int geni_se_resources_on(struct geni_se *se)
{
int ret;
+ if (has_acpi_companion(se->dev))
+ return 0;
+
ret = geni_se_clks_on(se);
if (ret)
return ret;
@@ -724,12 +731,14 @@ static int geni_se_probe(struct platform_device *pdev)
if (IS_ERR(wrapper->base))
return PTR_ERR(wrapper->base);
- wrapper->ahb_clks[0].id = "m-ahb";
- wrapper->ahb_clks[1].id = "s-ahb";
- ret = devm_clk_bulk_get(dev, NUM_AHB_CLKS, wrapper->ahb_clks);
- if (ret) {
- dev_err(dev, "Err getting AHB clks %d\n", ret);
- return ret;
+ if (!has_acpi_companion(&pdev->dev)) {
+ wrapper->ahb_clks[0].id = "m-ahb";
+ wrapper->ahb_clks[1].id = "s-ahb";
+ ret = devm_clk_bulk_get(dev, NUM_AHB_CLKS, wrapper->ahb_clks);
+ if (ret) {
+ dev_err(dev, "Err getting AHB clks %d\n", ret);
+ return ret;
+ }
}
dev_set_drvdata(dev, wrapper);
diff --git a/drivers/soc/rockchip/grf.c b/drivers/soc/rockchip/grf.c
index 3b81e1d75a97..494cf2b5bf7b 100644
--- a/drivers/soc/rockchip/grf.c
+++ b/drivers/soc/rockchip/grf.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Rockchip Generic Register Files setup
*
* Copyright (c) 2016 Heiko Stuebner <heiko@sntech.de>
- *
- * 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.
*/
#include <linux/err.h>
diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c
index 847c7c482b26..3342332cc007 100644
--- a/drivers/soc/rockchip/pm_domains.c
+++ b/drivers/soc/rockchip/pm_domains.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Rockchip Generic power domain support.
*
* Copyright (c) 2015 ROCKCHIP, Co. Ltd.
- *
- * 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.
*/
#include <linux/io.h>
diff --git a/drivers/soc/tegra/common.c b/drivers/soc/tegra/common.c
index 7bfb154d6fa5..3dc54f59cafe 100644
--- a/drivers/soc/tegra/common.c
+++ b/drivers/soc/tegra/common.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/of.h>
diff --git a/drivers/soc/tegra/fuse/fuse-tegra20.c b/drivers/soc/tegra/fuse/fuse-tegra20.c
index 4bb16e9bc297..d4aef9c4a94c 100644
--- a/drivers/soc/tegra/fuse/fuse-tegra20.c
+++ b/drivers/soc/tegra/fuse/fuse-tegra20.c
@@ -99,7 +99,7 @@ static int tegra20_fuse_probe(struct tegra_fuse *fuse)
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
- fuse->apbdma.chan = __dma_request_channel(&mask, dma_filter, NULL);
+ fuse->apbdma.chan = dma_request_channel(mask, dma_filter, NULL);
if (!fuse->apbdma.chan)
return -EPROBE_DEFER;
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 8878720dd779..17e7796a832b 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -700,6 +700,7 @@ int tegra_powergate_power_on(unsigned int id)
return tegra_powergate_set(pmc, id, true);
}
+EXPORT_SYMBOL(tegra_powergate_power_on);
/**
* tegra_powergate_power_off() - power off partition
diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig
index ea0859f7b185..d7d50d48d05d 100644
--- a/drivers/soc/ti/Kconfig
+++ b/drivers/soc/ti/Kconfig
@@ -75,10 +75,10 @@ config TI_SCI_PM_DOMAINS
called ti_sci_pm_domains. Note this is needed early in boot before
rootfs may be available.
+endif # SOC_TI
+
config TI_SCI_INTA_MSI_DOMAIN
bool
select GENERIC_MSI_IRQ_DOMAIN
help
Driver to enable Interrupt Aggregator specific MSI Domain.
-
-endif # SOC_TI
diff --git a/drivers/soc/versatile/soc-integrator.c b/drivers/soc/versatile/soc-integrator.c
index a5d7d39ae0ad..ae13fa2aa582 100644
--- a/drivers/soc/versatile/soc-integrator.c
+++ b/drivers/soc/versatile/soc-integrator.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 Linaro Ltd.
*
* Author: Linus Walleij <linus.walleij@linaro.org>
- *
- * 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.
- *
*/
#include <linux/init.h>
#include <linux/io.h>
diff --git a/drivers/soc/versatile/soc-realview.c b/drivers/soc/versatile/soc-realview.c
index caf698e5f0b0..9471353dd8c3 100644
--- a/drivers/soc/versatile/soc-realview.c
+++ b/drivers/soc/versatile/soc-realview.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 Linaro Ltd.
*
* Author: Linus Walleij <linus.walleij@linaro.org>
- *
- * 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.
- *
*/
#include <linux/init.h>
#include <linux/io.h>
diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
index aac35fc3cf22..fe745830a261 100644
--- a/drivers/soundwire/bus.c
+++ b/drivers/soundwire/bus.c
@@ -87,7 +87,7 @@ int sdw_add_bus_master(struct sdw_bus *bus)
/*
* Initialize clock values based on Master properties. The max
- * frequency is read from max_freq property. Current assumption
+ * frequency is read from max_clk_freq property. Current assumption
* is that the bus will start at highest clock frequency when
* powered on.
*
@@ -95,7 +95,7 @@ int sdw_add_bus_master(struct sdw_bus *bus)
* to start with bank 0 (Table 40 of Spec)
*/
prop = &bus->prop;
- bus->params.max_dr_freq = prop->max_freq * SDW_DOUBLE_RATE_FACTOR;
+ bus->params.max_dr_freq = prop->max_clk_freq * SDW_DOUBLE_RATE_FACTOR;
bus->params.curr_dr_freq = bus->params.max_dr_freq;
bus->params.curr_bank = SDW_BANK0;
bus->params.next_bank = SDW_BANK1;
@@ -648,7 +648,7 @@ static int sdw_initialize_slave(struct sdw_slave *slave)
return 0;
/* Enable DP0 interrupts */
- val = prop->dp0_prop->device_interrupts;
+ val = prop->dp0_prop->imp_def_interrupts;
val |= SDW_DP0_INT_PORT_READY | SDW_DP0_INT_BRA_FAILURE;
ret = sdw_update(slave, SDW_DP0_INTMASK, val, val);
diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
index 682789bb8ab3..ff4badc9b3de 100644
--- a/drivers/soundwire/cadence_master.c
+++ b/drivers/soundwire/cadence_master.c
@@ -9,6 +9,7 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/interrupt.h>
+#include <linux/io.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/soundwire/sdw_registers.h>
@@ -236,19 +237,19 @@ cdns_fill_msg_resp(struct sdw_cdns *cdns,
for (i = 0; i < count; i++) {
if (!(cdns->response_buf[i] & CDNS_MCP_RESP_ACK)) {
no_ack = 1;
- dev_dbg(cdns->dev, "Msg Ack not received\n");
+ dev_dbg_ratelimited(cdns->dev, "Msg Ack not received\n");
if (cdns->response_buf[i] & CDNS_MCP_RESP_NACK) {
nack = 1;
- dev_err(cdns->dev, "Msg NACK received\n");
+ dev_err_ratelimited(cdns->dev, "Msg NACK received\n");
}
}
}
if (nack) {
- dev_err(cdns->dev, "Msg NACKed for Slave %d\n", msg->dev_num);
+ dev_err_ratelimited(cdns->dev, "Msg NACKed for Slave %d\n", msg->dev_num);
return SDW_CMD_FAIL;
} else if (no_ack) {
- dev_dbg(cdns->dev, "Msg ignored for Slave %d\n", msg->dev_num);
+ dev_dbg_ratelimited(cdns->dev, "Msg ignored for Slave %d\n", msg->dev_num);
return SDW_CMD_IGNORED;
}
@@ -356,12 +357,12 @@ cdns_program_scp_addr(struct sdw_cdns *cdns, struct sdw_msg *msg)
/* For NACK, NO ack, don't return err if we are in Broadcast mode */
if (nack) {
- dev_err(cdns->dev,
- "SCP_addrpage NACKed for Slave %d\n", msg->dev_num);
+ dev_err_ratelimited(cdns->dev,
+ "SCP_addrpage NACKed for Slave %d\n", msg->dev_num);
return SDW_CMD_FAIL;
} else if (no_ack) {
- dev_dbg(cdns->dev,
- "SCP_addrpage ignored for Slave %d\n", msg->dev_num);
+ dev_dbg_ratelimited(cdns->dev,
+ "SCP_addrpage ignored for Slave %d\n", msg->dev_num);
return SDW_CMD_IGNORED;
}
@@ -486,7 +487,8 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns,
{
enum sdw_slave_status status[SDW_MAX_DEVICES + 1];
bool is_slave = false;
- u64 slave, mask;
+ u64 slave;
+ u32 mask;
int i, set_status;
/* combine the two status */
@@ -524,9 +526,9 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns,
/* first check if Slave reported multiple status */
if (set_status > 1) {
- dev_warn(cdns->dev,
- "Slave reported multiple Status: %d\n",
- status[i]);
+ dev_warn_ratelimited(cdns->dev,
+ "Slave reported multiple Status: %d\n",
+ mask);
/*
* TODO: we need to reread the status here by
* issuing a PING cmd
@@ -612,7 +614,7 @@ irqreturn_t sdw_cdns_thread(int irq, void *dev_id)
struct sdw_cdns *cdns = dev_id;
u32 slave0, slave1;
- dev_dbg(cdns->dev, "Slave status change\n");
+ dev_dbg_ratelimited(cdns->dev, "Slave status change\n");
slave0 = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT0);
slave1 = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT1);
@@ -716,6 +718,8 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
stream = &cdns->pcm;
/* First two PDIs are reserved for bulk transfers */
+ if (stream->num_bd < CDNS_PCM_PDI_OFFSET)
+ return -EINVAL;
stream->num_bd -= CDNS_PCM_PDI_OFFSET;
offset = CDNS_PCM_PDI_OFFSET;
diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index 31336b0271b0..317873bc0555 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -263,6 +263,9 @@ static void intel_pdi_init(struct sdw_intel *sdw,
config->pcm_out = (pcm_cap & SDW_SHIM_PCMSCAP_OSS) >>
SDW_REG_SHIFT(SDW_SHIM_PCMSCAP_OSS);
+ dev_dbg(sdw->cdns.dev, "PCM cap bd:%d in:%d out:%d\n",
+ config->pcm_bd, config->pcm_in, config->pcm_out);
+
/* PDM Stream Capability */
pdm_cap = intel_readw(shim, SDW_SHIM_PDMSCAP(link_id));
@@ -272,6 +275,9 @@ static void intel_pdi_init(struct sdw_intel *sdw,
SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_ISS);
config->pdm_out = (pdm_cap & SDW_SHIM_PDMSCAP_OSS) >>
SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_OSS);
+
+ dev_dbg(sdw->cdns.dev, "PDM cap bd:%d in:%d out:%d\n",
+ config->pdm_bd, config->pdm_in, config->pdm_out);
}
static int
@@ -715,8 +721,8 @@ static int intel_create_dai(struct sdw_cdns *cdns,
return -ENOMEM;
}
- dais[i].playback.channels_min = 1;
- dais[i].playback.channels_max = max_ch;
+ dais[i].capture.channels_min = 1;
+ dais[i].capture.channels_max = max_ch;
dais[i].capture.rates = SNDRV_PCM_RATE_48000;
dais[i].capture.formats = SNDRV_PCM_FMTBIT_S16_LE;
}
@@ -796,13 +802,14 @@ static int intel_prop_read(struct sdw_bus *bus)
sdw_master_read_prop(bus);
/* BIOS is not giving some values correctly. So, lets override them */
- bus->prop.num_freq = 1;
- bus->prop.freq = devm_kcalloc(bus->dev, bus->prop.num_freq,
- sizeof(*bus->prop.freq), GFP_KERNEL);
- if (!bus->prop.freq)
+ bus->prop.num_clk_freq = 1;
+ bus->prop.clk_freq = devm_kcalloc(bus->dev, bus->prop.num_clk_freq,
+ sizeof(*bus->prop.clk_freq),
+ GFP_KERNEL);
+ if (!bus->prop.clk_freq)
return -ENOMEM;
- bus->prop.freq[0] = bus->prop.max_freq;
+ bus->prop.clk_freq[0] = bus->prop.max_clk_freq;
bus->prop.err_threshold = 5;
return 0;
diff --git a/drivers/soundwire/intel.h b/drivers/soundwire/intel.h
index 71050e5f643d..d923b6262330 100644
--- a/drivers/soundwire/intel.h
+++ b/drivers/soundwire/intel.h
@@ -5,7 +5,7 @@
#define __SDW_INTEL_LOCAL_H
/**
- * struct sdw_intel_res - Soundwire link resources
+ * struct sdw_intel_link_res - Soundwire link resources
* @registers: Link IO registers base
* @shim: Audio shim pointer
* @alh: ALH (Audio Link Hub) pointer
diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c
index d3d6b54c5791..70637a0383d2 100644
--- a/drivers/soundwire/intel_init.c
+++ b/drivers/soundwire/intel_init.c
@@ -14,6 +14,7 @@
#include <linux/soundwire/sdw_intel.h>
#include "intel.h"
+#define SDW_LINK_TYPE 4 /* from Intel ACPI documentation */
#define SDW_MAX_LINKS 4
#define SDW_SHIM_LCAP 0x0
#define SDW_SHIM_BASE 0x2C000
@@ -80,6 +81,7 @@ static struct sdw_intel_ctx
/* Check SNDWLCAP.LCOUNT */
caps = ioread32(res->mmio_base + SDW_SHIM_BASE + SDW_SHIM_LCAP);
+ caps &= GENMASK(2, 0);
/* Check HW supported vs property value and use min of two */
count = min_t(u8, caps, count);
@@ -89,6 +91,9 @@ static struct sdw_intel_ctx
dev_err(&adev->dev, "Link count %d exceeds max %d\n",
count, SDW_MAX_LINKS);
return NULL;
+ } else if (!count) {
+ dev_warn(&adev->dev, "No SoundWire links detected\n");
+ return NULL;
}
dev_dbg(&adev->dev, "Creating %d SDW Link devices\n", count);
@@ -150,6 +155,12 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
{
struct sdw_intel_res *res = cdata;
struct acpi_device *adev;
+ acpi_status status;
+ u64 adr;
+
+ status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
+ if (ACPI_FAILURE(status))
+ return AE_OK; /* keep going */
if (acpi_bus_get_device(handle, &adev)) {
pr_err("%s: Couldn't find ACPI handle\n", __func__);
@@ -157,7 +168,19 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
}
res->handle = handle;
- return AE_OK;
+
+ /*
+ * On some Intel platforms, multiple children of the HDAS
+ * device can be found, but only one of them is the SoundWire
+ * controller. The SNDW device is always exposed with
+ * Name(_ADR, 0x40000000), with bits 31..28 representing the
+ * SoundWire link so filter accordingly
+ */
+ if ((adr & GENMASK(31, 28)) >> 28 != SDW_LINK_TYPE)
+ return AE_OK; /* keep going */
+
+ /* device found, stop namespace walk */
+ return AE_CTRL_TERMINATE;
}
/**
diff --git a/drivers/soundwire/mipi_disco.c b/drivers/soundwire/mipi_disco.c
index c1f51d6a23d2..79fee1b21ab6 100644
--- a/drivers/soundwire/mipi_disco.c
+++ b/drivers/soundwire/mipi_disco.c
@@ -40,7 +40,7 @@ int sdw_master_read_prop(struct sdw_bus *bus)
/* Find master handle */
snprintf(name, sizeof(name),
- "mipi-sdw-master-%d-subproperties", bus->link_id);
+ "mipi-sdw-link-%d-subproperties", bus->link_id);
link = device_get_named_child_node(bus->dev, name);
if (!link) {
@@ -50,39 +50,40 @@ int sdw_master_read_prop(struct sdw_bus *bus)
if (fwnode_property_read_bool(link,
"mipi-sdw-clock-stop-mode0-supported"))
- prop->clk_stop_mode = SDW_CLK_STOP_MODE0;
+ prop->clk_stop_modes |= BIT(SDW_CLK_STOP_MODE0);
if (fwnode_property_read_bool(link,
"mipi-sdw-clock-stop-mode1-supported"))
- prop->clk_stop_mode |= SDW_CLK_STOP_MODE1;
+ prop->clk_stop_modes |= BIT(SDW_CLK_STOP_MODE1);
fwnode_property_read_u32(link,
"mipi-sdw-max-clock-frequency",
- &prop->max_freq);
+ &prop->max_clk_freq);
nval = fwnode_property_read_u32_array(link,
"mipi-sdw-clock-frequencies-supported", NULL, 0);
if (nval > 0) {
- prop->num_freq = nval;
- prop->freq = devm_kcalloc(bus->dev, prop->num_freq,
- sizeof(*prop->freq), GFP_KERNEL);
- if (!prop->freq)
+ prop->num_clk_freq = nval;
+ prop->clk_freq = devm_kcalloc(bus->dev, prop->num_clk_freq,
+ sizeof(*prop->clk_freq),
+ GFP_KERNEL);
+ if (!prop->clk_freq)
return -ENOMEM;
fwnode_property_read_u32_array(link,
"mipi-sdw-clock-frequencies-supported",
- prop->freq, prop->num_freq);
+ prop->clk_freq, prop->num_clk_freq);
}
/*
* Check the frequencies supported. If FW doesn't provide max
* freq, then populate here by checking values.
*/
- if (!prop->max_freq && prop->freq) {
- prop->max_freq = prop->freq[0];
- for (i = 1; i < prop->num_freq; i++) {
- if (prop->freq[i] > prop->max_freq)
- prop->max_freq = prop->freq[i];
+ if (!prop->max_clk_freq && prop->clk_freq) {
+ prop->max_clk_freq = prop->clk_freq[0];
+ for (i = 1; i < prop->num_clk_freq; i++) {
+ if (prop->clk_freq[i] > prop->max_clk_freq)
+ prop->max_clk_freq = prop->clk_freq[i];
}
}
@@ -149,13 +150,13 @@ static int sdw_slave_read_dp0(struct sdw_slave *slave,
dp0->words, dp0->num_words);
}
- dp0->flow_controlled = fwnode_property_read_bool(port,
+ dp0->BRA_flow_controlled = fwnode_property_read_bool(port,
"mipi-sdw-bra-flow-controlled");
dp0->simple_ch_prep_sm = fwnode_property_read_bool(port,
"mipi-sdw-simplified-channel-prepare-sm");
- dp0->device_interrupts = fwnode_property_read_bool(port,
+ dp0->imp_def_interrupts = fwnode_property_read_bool(port,
"mipi-sdw-imp-def-dp0-interrupts-supported");
return 0;
@@ -224,7 +225,7 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave,
fwnode_property_read_u32(node,
"mipi-sdw-imp-def-dpn-interrupts-supported",
- &dpn[i].device_interrupts);
+ &dpn[i].imp_def_interrupts);
fwnode_property_read_u32(node, "mipi-sdw-min-channel-number",
&dpn[i].min_ch);
diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c
index d01060dbee96..a0476755a459 100644
--- a/drivers/soundwire/stream.c
+++ b/drivers/soundwire/stream.c
@@ -439,7 +439,7 @@ static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus,
prep_ch.bank = bus->params.next_bank;
- if (dpn_prop->device_interrupts || !dpn_prop->simple_ch_prep_sm)
+ if (dpn_prop->imp_def_interrupts || !dpn_prop->simple_ch_prep_sm)
intr = true;
/*
@@ -449,7 +449,7 @@ static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus,
*/
if (prep && intr) {
ret = sdw_configure_dpn_intr(s_rt->slave, p_rt->num, prep,
- dpn_prop->device_interrupts);
+ dpn_prop->imp_def_interrupts);
if (ret < 0)
return ret;
}
@@ -493,7 +493,7 @@ static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus,
/* Disable interrupt after Port de-prepare */
if (!prep && intr)
ret = sdw_configure_dpn_intr(s_rt->slave, p_rt->num, prep,
- dpn_prop->device_interrupts);
+ dpn_prop->imp_def_interrupts);
return ret;
}
@@ -814,7 +814,8 @@ static int do_bank_switch(struct sdw_stream_runtime *stream)
goto error;
}
- mutex_unlock(&bus->msg_lock);
+ if (bus->multi_link)
+ mutex_unlock(&bus->msg_lock);
}
return ret;
@@ -1406,9 +1407,7 @@ struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave,
}
for (i = 0; i < num_ports; i++) {
- dpn_prop = &dpn_prop[i];
-
- if (dpn_prop->num == port_num)
+ if (dpn_prop[i].num == port_num)
return &dpn_prop[i];
}
@@ -1474,7 +1473,7 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream)
memcpy(&params, &bus->params, sizeof(params));
/* TODO: Support Asynchronous mode */
- if ((prop->max_freq % stream->params.rate) != 0) {
+ if ((prop->max_clk_freq % stream->params.rate) != 0) {
dev_err(bus->dev, "Async mode not supported\n");
return -EINVAL;
}
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 30a40280c157..3a1d8f1170de 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -120,7 +120,7 @@ config SPI_AXI_SPI_ENGINE
config SPI_BCM2835
tristate "BCM2835 SPI controller"
depends on GPIOLIB
- depends on ARCH_BCM2835 || COMPILE_TEST
+ depends on ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST
help
This selects a driver for the Broadcom BCM2835 SPI master.
@@ -131,7 +131,7 @@ config SPI_BCM2835
config SPI_BCM2835AUX
tristate "BCM2835 SPI auxiliary controller"
- depends on (ARCH_BCM2835 && GPIOLIB) || COMPILE_TEST
+ depends on ((ARCH_BCM2835 || ARCH_BRCMSTB) && GPIOLIB) || COMPILE_TEST
help
This selects a driver for the Broadcom BCM2835 SPI aux master.
@@ -733,6 +733,16 @@ config SPI_SUN6I
help
This enables using the SPI controller on the Allwinner A31 SoCs.
+config SPI_SYNQUACER
+ tristate "Socionext's SynQuacer HighSpeed SPI controller"
+ depends on ARCH_SYNQUACER || COMPILE_TEST
+ help
+ SPI driver for Socionext's High speed SPI controller which provides
+ various operating modes for interfacing to serial peripheral devices
+ that use the de-facto standard SPI protocol.
+
+ It also supports the new dual-bit and quad-bit SPI protocol.
+
config SPI_MXIC
tristate "Macronix MX25F0A SPI controller"
depends on SPI_MASTER
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index f2f78d03dc28..63dcab552bcb 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -106,6 +106,7 @@ obj-$(CONFIG_SPI_STM32_QSPI) += spi-stm32-qspi.o
obj-$(CONFIG_SPI_ST_SSC4) += spi-st-ssc4.o
obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o
obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o
+obj-$(CONFIG_SPI_SYNQUACER) += spi-synquacer.o
obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.o
obj-$(CONFIG_SPI_TEGRA20_SFLASH) += spi-tegra20-sflash.o
obj-$(CONFIG_SPI_TEGRA20_SLINK) += spi-tegra20-slink.o
diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c
index 9f24d5f0b431..6a7d7b553d95 100644
--- a/drivers/spi/atmel-quadspi.c
+++ b/drivers/spi/atmel-quadspi.c
@@ -151,6 +151,7 @@ struct atmel_qspi {
const struct atmel_qspi_caps *caps;
u32 pending;
u32 mr;
+ u32 scr;
struct completion cmd_completion;
};
@@ -382,7 +383,7 @@ static int atmel_qspi_setup(struct spi_device *spi)
struct spi_controller *ctrl = spi->master;
struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
unsigned long src_rate;
- u32 scr, scbr;
+ u32 scbr;
if (ctrl->busy)
return -EBUSY;
@@ -399,13 +400,13 @@ static int atmel_qspi_setup(struct spi_device *spi)
if (scbr > 0)
scbr--;
- scr = QSPI_SCR_SCBR(scbr);
- writel_relaxed(scr, aq->regs + QSPI_SCR);
+ aq->scr = QSPI_SCR_SCBR(scbr);
+ writel_relaxed(aq->scr, aq->regs + QSPI_SCR);
return 0;
}
-static int atmel_qspi_init(struct atmel_qspi *aq)
+static void atmel_qspi_init(struct atmel_qspi *aq)
{
/* Reset the QSPI controller */
writel_relaxed(QSPI_CR_SWRST, aq->regs + QSPI_CR);
@@ -416,8 +417,6 @@ static int atmel_qspi_init(struct atmel_qspi *aq)
/* Enable the QSPI controller */
writel_relaxed(QSPI_CR_QSPIEN, aq->regs + QSPI_CR);
-
- return 0;
}
static irqreturn_t atmel_qspi_interrupt(int irq, void *dev_id)
@@ -536,9 +535,7 @@ static int atmel_qspi_probe(struct platform_device *pdev)
if (err)
goto disable_qspick;
- err = atmel_qspi_init(aq);
- if (err)
- goto disable_qspick;
+ atmel_qspi_init(aq);
err = spi_register_controller(ctrl);
if (err)
@@ -587,7 +584,11 @@ static int __maybe_unused atmel_qspi_resume(struct device *dev)
clk_prepare_enable(aq->pclk);
clk_prepare_enable(aq->qspick);
- return atmel_qspi_init(aq);
+ atmel_qspi_init(aq);
+
+ writel_relaxed(aq->scr, aq->regs + QSPI_SCR);
+
+ return 0;
}
static SIMPLE_DEV_PM_OPS(atmel_qspi_pm_ops, atmel_qspi_suspend,
diff --git a/drivers/spi/spi-altera.c b/drivers/spi/spi-altera.c
index a5adf0d868fc..ea160f117f88 100644
--- a/drivers/spi/spi-altera.c
+++ b/drivers/spi/spi-altera.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Altera SPI driver
*
@@ -7,10 +8,6 @@
* Copyright (c) 2006 Ben Dooks
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
- *
- * 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.
*/
#include <linux/interrupt.h>
diff --git a/drivers/spi/spi-armada-3700.c b/drivers/spi/spi-armada-3700.c
index 7dcb14d303eb..032888344822 100644
--- a/drivers/spi/spi-armada-3700.c
+++ b/drivers/spi/spi-armada-3700.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Marvell Armada-3700 SPI controller driver
*
@@ -5,10 +6,6 @@
*
* Author: Wilson Ding <dingwei@marvell.com>
* Author: Romain Perier <romain.perier@free-electrons.com>
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/spi/spi-at91-usart.c b/drivers/spi/spi-at91-usart.c
index f763e14bdf12..a40bb2ef89dc 100644
--- a/drivers/spi/spi-at91-usart.c
+++ b/drivers/spi/spi-at91-usart.c
@@ -8,9 +8,12 @@
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-direction.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
@@ -59,6 +62,8 @@
#define US_INIT \
(US_MR_SPI_MASTER | US_MR_CHRL | US_MR_CLKO | US_MR_WRDBT)
+#define US_DMA_MIN_BYTES 16
+#define US_DMA_TIMEOUT (msecs_to_jiffies(1000))
/* Register access macros */
#define at91_usart_spi_readl(port, reg) \
@@ -72,14 +77,19 @@
writeb_relaxed((value), (port)->regs + US_##reg)
struct at91_usart_spi {
+ struct platform_device *mpdev;
struct spi_transfer *current_transfer;
void __iomem *regs;
struct device *dev;
struct clk *clk;
+ struct completion xfer_completion;
+
/*used in interrupt to protect data reading*/
spinlock_t lock;
+ phys_addr_t phybase;
+
int irq;
unsigned int current_tx_remaining_bytes;
unsigned int current_rx_remaining_bytes;
@@ -88,8 +98,182 @@ struct at91_usart_spi {
u32 status;
bool xfer_failed;
+ bool use_dma;
};
+static void dma_callback(void *data)
+{
+ struct spi_controller *ctlr = data;
+ struct at91_usart_spi *aus = spi_master_get_devdata(ctlr);
+
+ at91_usart_spi_writel(aus, IER, US_IR_RXRDY);
+ aus->current_rx_remaining_bytes = 0;
+ complete(&aus->xfer_completion);
+}
+
+static bool at91_usart_spi_can_dma(struct spi_controller *ctrl,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct at91_usart_spi *aus = spi_master_get_devdata(ctrl);
+
+ return aus->use_dma && xfer->len >= US_DMA_MIN_BYTES;
+}
+
+static int at91_usart_spi_configure_dma(struct spi_controller *ctlr,
+ struct at91_usart_spi *aus)
+{
+ struct dma_slave_config slave_config;
+ struct device *dev = &aus->mpdev->dev;
+ phys_addr_t phybase = aus->phybase;
+ dma_cap_mask_t mask;
+ int err = 0;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ ctlr->dma_tx = dma_request_slave_channel_reason(dev, "tx");
+ if (IS_ERR_OR_NULL(ctlr->dma_tx)) {
+ if (IS_ERR(ctlr->dma_tx)) {
+ err = PTR_ERR(ctlr->dma_tx);
+ goto at91_usart_spi_error_clear;
+ }
+
+ dev_dbg(dev,
+ "DMA TX channel not available, SPI unable to use DMA\n");
+ err = -EBUSY;
+ goto at91_usart_spi_error_clear;
+ }
+
+ ctlr->dma_rx = dma_request_slave_channel_reason(dev, "rx");
+ if (IS_ERR_OR_NULL(ctlr->dma_rx)) {
+ if (IS_ERR(ctlr->dma_rx)) {
+ err = PTR_ERR(ctlr->dma_rx);
+ goto at91_usart_spi_error;
+ }
+
+ dev_dbg(dev,
+ "DMA RX channel not available, SPI unable to use DMA\n");
+ err = -EBUSY;
+ goto at91_usart_spi_error;
+ }
+
+ slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ slave_config.dst_addr = (dma_addr_t)phybase + US_THR;
+ slave_config.src_addr = (dma_addr_t)phybase + US_RHR;
+ slave_config.src_maxburst = 1;
+ slave_config.dst_maxburst = 1;
+ slave_config.device_fc = false;
+
+ slave_config.direction = DMA_DEV_TO_MEM;
+ if (dmaengine_slave_config(ctlr->dma_rx, &slave_config)) {
+ dev_err(&ctlr->dev,
+ "failed to configure rx dma channel\n");
+ err = -EINVAL;
+ goto at91_usart_spi_error;
+ }
+
+ slave_config.direction = DMA_MEM_TO_DEV;
+ if (dmaengine_slave_config(ctlr->dma_tx, &slave_config)) {
+ dev_err(&ctlr->dev,
+ "failed to configure tx dma channel\n");
+ err = -EINVAL;
+ goto at91_usart_spi_error;
+ }
+
+ aus->use_dma = true;
+ return 0;
+
+at91_usart_spi_error:
+ if (!IS_ERR_OR_NULL(ctlr->dma_tx))
+ dma_release_channel(ctlr->dma_tx);
+ if (!IS_ERR_OR_NULL(ctlr->dma_rx))
+ dma_release_channel(ctlr->dma_rx);
+ ctlr->dma_tx = NULL;
+ ctlr->dma_rx = NULL;
+
+at91_usart_spi_error_clear:
+ return err;
+}
+
+static void at91_usart_spi_release_dma(struct spi_controller *ctlr)
+{
+ if (ctlr->dma_rx)
+ dma_release_channel(ctlr->dma_rx);
+ if (ctlr->dma_tx)
+ dma_release_channel(ctlr->dma_tx);
+}
+
+static void at91_usart_spi_stop_dma(struct spi_controller *ctlr)
+{
+ if (ctlr->dma_rx)
+ dmaengine_terminate_all(ctlr->dma_rx);
+ if (ctlr->dma_tx)
+ dmaengine_terminate_all(ctlr->dma_tx);
+}
+
+static int at91_usart_spi_dma_transfer(struct spi_controller *ctlr,
+ struct spi_transfer *xfer)
+{
+ struct at91_usart_spi *aus = spi_master_get_devdata(ctlr);
+ struct dma_chan *rxchan = ctlr->dma_rx;
+ struct dma_chan *txchan = ctlr->dma_tx;
+ struct dma_async_tx_descriptor *rxdesc;
+ struct dma_async_tx_descriptor *txdesc;
+ dma_cookie_t cookie;
+
+ /* Disable RX interrupt */
+ at91_usart_spi_writel(aus, IDR, US_IR_RXRDY);
+
+ rxdesc = dmaengine_prep_slave_sg(rxchan,
+ xfer->rx_sg.sgl,
+ xfer->rx_sg.nents,
+ DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT |
+ DMA_CTRL_ACK);
+ if (!rxdesc)
+ goto at91_usart_spi_err_dma;
+
+ txdesc = dmaengine_prep_slave_sg(txchan,
+ xfer->tx_sg.sgl,
+ xfer->tx_sg.nents,
+ DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT |
+ DMA_CTRL_ACK);
+ if (!txdesc)
+ goto at91_usart_spi_err_dma;
+
+ rxdesc->callback = dma_callback;
+ rxdesc->callback_param = ctlr;
+
+ cookie = rxdesc->tx_submit(rxdesc);
+ if (dma_submit_error(cookie))
+ goto at91_usart_spi_err_dma;
+
+ cookie = txdesc->tx_submit(txdesc);
+ if (dma_submit_error(cookie))
+ goto at91_usart_spi_err_dma;
+
+ rxchan->device->device_issue_pending(rxchan);
+ txchan->device->device_issue_pending(txchan);
+
+ return 0;
+
+at91_usart_spi_err_dma:
+ /* Enable RX interrupt if something fails and fallback to PIO */
+ at91_usart_spi_writel(aus, IER, US_IR_RXRDY);
+ at91_usart_spi_stop_dma(ctlr);
+
+ return -ENOMEM;
+}
+
+static unsigned long at91_usart_spi_dma_timeout(struct at91_usart_spi *aus)
+{
+ return wait_for_completion_timeout(&aus->xfer_completion,
+ US_DMA_TIMEOUT);
+}
+
static inline u32 at91_usart_spi_tx_ready(struct at91_usart_spi *aus)
{
return aus->status & US_IR_TXRDY;
@@ -216,6 +400,8 @@ static int at91_usart_spi_transfer_one(struct spi_controller *ctlr,
struct spi_transfer *xfer)
{
struct at91_usart_spi *aus = spi_master_get_devdata(ctlr);
+ unsigned long dma_timeout = 0;
+ int ret = 0;
at91_usart_spi_set_xfer_speed(aus, xfer);
aus->xfer_failed = false;
@@ -225,8 +411,25 @@ static int at91_usart_spi_transfer_one(struct spi_controller *ctlr,
while ((aus->current_tx_remaining_bytes ||
aus->current_rx_remaining_bytes) && !aus->xfer_failed) {
- at91_usart_spi_read_status(aus);
- at91_usart_spi_tx(aus);
+ reinit_completion(&aus->xfer_completion);
+ if (at91_usart_spi_can_dma(ctlr, spi, xfer) &&
+ !ret) {
+ ret = at91_usart_spi_dma_transfer(ctlr, xfer);
+ if (ret)
+ continue;
+
+ dma_timeout = at91_usart_spi_dma_timeout(aus);
+
+ if (WARN_ON(dma_timeout == 0)) {
+ dev_err(&spi->dev, "DMA transfer timeout\n");
+ return -EIO;
+ }
+ aus->current_tx_remaining_bytes = 0;
+ } else {
+ at91_usart_spi_read_status(aus);
+ at91_usart_spi_tx(aus);
+ }
+
cpu_relax();
}
@@ -345,6 +548,7 @@ static int at91_usart_spi_probe(struct platform_device *pdev)
controller->transfer_one = at91_usart_spi_transfer_one;
controller->prepare_message = at91_usart_spi_prepare_message;
controller->unprepare_message = at91_usart_spi_unprepare_message;
+ controller->can_dma = at91_usart_spi_can_dma;
controller->cleanup = at91_usart_spi_cleanup;
controller->max_speed_hz = DIV_ROUND_UP(clk_get_rate(clk),
US_MIN_CLK_DIV);
@@ -376,7 +580,17 @@ static int at91_usart_spi_probe(struct platform_device *pdev)
aus->spi_clk = clk_get_rate(clk);
at91_usart_spi_init(aus);
+ aus->phybase = regs->start;
+
+ aus->mpdev = to_platform_device(pdev->dev.parent);
+
+ ret = at91_usart_spi_configure_dma(controller, aus);
+ if (ret)
+ goto at91_usart_fail_dma;
+
spin_lock_init(&aus->lock);
+ init_completion(&aus->xfer_completion);
+
ret = devm_spi_register_master(&pdev->dev, controller);
if (ret)
goto at91_usart_fail_register_master;
@@ -389,6 +603,8 @@ static int at91_usart_spi_probe(struct platform_device *pdev)
return 0;
at91_usart_fail_register_master:
+ at91_usart_spi_release_dma(controller);
+at91_usart_fail_dma:
clk_disable_unprepare(clk);
at91_usart_spi_probe_fail:
spi_master_put(controller);
@@ -453,6 +669,7 @@ static int at91_usart_spi_remove(struct platform_device *pdev)
struct spi_controller *ctlr = platform_get_drvdata(pdev);
struct at91_usart_spi *aus = spi_master_get_devdata(ctlr);
+ at91_usart_spi_release_dma(ctlr);
clk_disable_unprepare(aus->clk);
return 0;
diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c
index 847f354ebef1..032a615e4ccd 100644
--- a/drivers/spi/spi-ath79.c
+++ b/drivers/spi/spi-ath79.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* SPI controller driver for the Atheros AR71XX/AR724X/AR913X SoCs
*
@@ -5,11 +6,6 @@
*
* This driver has been based on the spi-gpio.c:
* Copyright (C) 2006,2008 David Brownell
- *
- * 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.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index 4954f0ab1606..f00b367523cd 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for Atmel AT32 and AT91 SPI Controllers
*
* Copyright (C) 2006 Atmel Corporation
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c
index 584bcb018a62..902bdbfedea8 100644
--- a/drivers/spi/spi-bcm-qspi.c
+++ b/drivers/spi/spi-bcm-qspi.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for Broadcom BRCMSTB, NSP, NS2, Cygnus SPI Controllers
*
* Copyright 2016 Broadcom
- *
- * 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 (the "GPL").
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License version 2 (GPLv2) for more details.
- *
- * You should have received a copy of the GNU General Public License
- * version 2 (GPLv2) along with this source code.
*/
#include <linux/clk.h>
diff --git a/drivers/spi/spi-bcm-qspi.h b/drivers/spi/spi-bcm-qspi.h
index 7abfc75a3860..01aec6460108 100644
--- a/drivers/spi/spi-bcm-qspi.h
+++ b/drivers/spi/spi-bcm-qspi.h
@@ -1,17 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2016 Broadcom
- *
- * 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 (the "GPL").
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License version 2 (GPLv2) for more details.
- *
- * You should have received a copy of the GNU General Public License
- * version 2 (GPLv2) along with this source code.
*/
#ifndef __SPI_BCM_QSPI_H__
diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c
index 402c1efcd762..6f243a90c844 100644
--- a/drivers/spi/spi-bcm2835.c
+++ b/drivers/spi/spi-bcm2835.c
@@ -13,6 +13,7 @@
#include <linux/clk.h>
#include <linux/completion.h>
+#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
@@ -64,14 +65,18 @@
#define BCM2835_SPI_FIFO_SIZE 64
#define BCM2835_SPI_FIFO_SIZE_3_4 48
-#define BCM2835_SPI_POLLING_LIMIT_US 30
-#define BCM2835_SPI_POLLING_JIFFIES 2
#define BCM2835_SPI_DMA_MIN_LENGTH 96
#define BCM2835_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
| SPI_NO_CS | SPI_3WIRE)
#define DRV_NAME "spi-bcm2835"
+/* define polling limits */
+unsigned int polling_limit_us = 30;
+module_param(polling_limit_us, uint, 0664);
+MODULE_PARM_DESC(polling_limit_us,
+ "time in us to run a transfer in polling mode\n");
+
/**
* struct bcm2835_spi - BCM2835 SPI controller
* @regs: base address of register map
@@ -88,6 +93,15 @@
* length is not a multiple of 4 (to overcome hardware limitation)
* @tx_spillover: whether @tx_prologue spills over to second TX sglist entry
* @dma_pending: whether a DMA transfer is in progress
+ * @debugfs_dir: the debugfs directory - neede to remove debugfs when
+ * unloading the module
+ * @count_transfer_polling: count of how often polling mode is used
+ * @count_transfer_irq: count of how often interrupt mode is used
+ * @count_transfer_irq_after_polling: count of how often we fall back to
+ * interrupt mode after starting in polling mode.
+ * These are counted as well in @count_transfer_polling and
+ * @count_transfer_irq
+ * @count_transfer_dma: count how often dma mode is used
*/
struct bcm2835_spi {
void __iomem *regs;
@@ -102,8 +116,55 @@ struct bcm2835_spi {
int rx_prologue;
unsigned int tx_spillover;
unsigned int dma_pending;
+
+ struct dentry *debugfs_dir;
+ u64 count_transfer_polling;
+ u64 count_transfer_irq;
+ u64 count_transfer_irq_after_polling;
+ u64 count_transfer_dma;
};
+#if defined(CONFIG_DEBUG_FS)
+static void bcm2835_debugfs_create(struct bcm2835_spi *bs,
+ const char *dname)
+{
+ char name[64];
+ struct dentry *dir;
+
+ /* get full name */
+ snprintf(name, sizeof(name), "spi-bcm2835-%s", dname);
+
+ /* the base directory */
+ dir = debugfs_create_dir(name, NULL);
+ bs->debugfs_dir = dir;
+
+ /* the counters */
+ debugfs_create_u64("count_transfer_polling", 0444, dir,
+ &bs->count_transfer_polling);
+ debugfs_create_u64("count_transfer_irq", 0444, dir,
+ &bs->count_transfer_irq);
+ debugfs_create_u64("count_transfer_irq_after_polling", 0444, dir,
+ &bs->count_transfer_irq_after_polling);
+ debugfs_create_u64("count_transfer_dma", 0444, dir,
+ &bs->count_transfer_dma);
+}
+
+static void bcm2835_debugfs_remove(struct bcm2835_spi *bs)
+{
+ debugfs_remove_recursive(bs->debugfs_dir);
+ bs->debugfs_dir = NULL;
+}
+#else
+static void bcm2835_debugfs_create(struct bcm2835_spi *bs,
+ const char *dname)
+{
+}
+
+static void bcm2835_debugfs_remove(struct bcm2835_spi *bs)
+{
+}
+#endif /* CONFIG_DEBUG_FS */
+
static inline u32 bcm2835_rd(struct bcm2835_spi *bs, unsigned reg)
{
return readl(bs->regs + reg);
@@ -248,9 +309,9 @@ static inline void bcm2835_wr_fifo_blind(struct bcm2835_spi *bs, int count)
}
}
-static void bcm2835_spi_reset_hw(struct spi_master *master)
+static void bcm2835_spi_reset_hw(struct spi_controller *ctlr)
{
- struct bcm2835_spi *bs = spi_master_get_devdata(master);
+ struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
/* Disable SPI interrupts and transfer */
@@ -269,8 +330,8 @@ static void bcm2835_spi_reset_hw(struct spi_master *master)
static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id)
{
- struct spi_master *master = dev_id;
- struct bcm2835_spi *bs = spi_master_get_devdata(master);
+ struct spi_controller *ctlr = dev_id;
+ struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
/*
@@ -292,20 +353,23 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id)
if (!bs->rx_len) {
/* Transfer complete - reset SPI HW */
- bcm2835_spi_reset_hw(master);
+ bcm2835_spi_reset_hw(ctlr);
/* wake up the framework */
- complete(&master->xfer_completion);
+ complete(&ctlr->xfer_completion);
}
return IRQ_HANDLED;
}
-static int bcm2835_spi_transfer_one_irq(struct spi_master *master,
+static int bcm2835_spi_transfer_one_irq(struct spi_controller *ctlr,
struct spi_device *spi,
struct spi_transfer *tfr,
u32 cs, bool fifo_empty)
{
- struct bcm2835_spi *bs = spi_master_get_devdata(master);
+ struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
+
+ /* update usage statistics */
+ bs->count_transfer_irq++;
/*
* Enable HW block, but with interrupts still disabled.
@@ -328,7 +392,7 @@ static int bcm2835_spi_transfer_one_irq(struct spi_master *master,
/**
* bcm2835_spi_transfer_prologue() - transfer first few bytes without DMA
- * @master: SPI master
+ * @ctlr: SPI master controller
* @tfr: SPI transfer
* @bs: BCM2835 SPI controller
* @cs: CS register
@@ -372,7 +436,7 @@ static int bcm2835_spi_transfer_one_irq(struct spi_master *master,
* be transmitted in 32-bit width to ensure that the following DMA transfer can
* pick up the residue in the RX FIFO in ungarbled form.
*/
-static void bcm2835_spi_transfer_prologue(struct spi_master *master,
+static void bcm2835_spi_transfer_prologue(struct spi_controller *ctlr,
struct spi_transfer *tfr,
struct bcm2835_spi *bs,
u32 cs)
@@ -413,9 +477,9 @@ static void bcm2835_spi_transfer_prologue(struct spi_master *master,
bcm2835_wr_fifo_count(bs, bs->rx_prologue);
bcm2835_wait_tx_fifo_empty(bs);
bcm2835_rd_fifo_count(bs, bs->rx_prologue);
- bcm2835_spi_reset_hw(master);
+ bcm2835_spi_reset_hw(ctlr);
- dma_sync_single_for_device(master->dma_rx->device->dev,
+ dma_sync_single_for_device(ctlr->dma_rx->device->dev,
sg_dma_address(&tfr->rx_sg.sgl[0]),
bs->rx_prologue, DMA_FROM_DEVICE);
@@ -479,11 +543,11 @@ static void bcm2835_spi_undo_prologue(struct bcm2835_spi *bs)
static void bcm2835_spi_dma_done(void *data)
{
- struct spi_master *master = data;
- struct bcm2835_spi *bs = spi_master_get_devdata(master);
+ struct spi_controller *ctlr = data;
+ struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
/* reset fifo and HW */
- bcm2835_spi_reset_hw(master);
+ bcm2835_spi_reset_hw(ctlr);
/* and terminate tx-dma as we do not have an irq for it
* because when the rx dma will terminate and this callback
@@ -491,15 +555,15 @@ static void bcm2835_spi_dma_done(void *data)
* situation otherwise...
*/
if (cmpxchg(&bs->dma_pending, true, false)) {
- dmaengine_terminate_async(master->dma_tx);
+ dmaengine_terminate_async(ctlr->dma_tx);
bcm2835_spi_undo_prologue(bs);
}
/* and mark as completed */;
- complete(&master->xfer_completion);
+ complete(&ctlr->xfer_completion);
}
-static int bcm2835_spi_prepare_sg(struct spi_master *master,
+static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr,
struct spi_transfer *tfr,
bool is_tx)
{
@@ -514,14 +578,14 @@ static int bcm2835_spi_prepare_sg(struct spi_master *master,
if (is_tx) {
dir = DMA_MEM_TO_DEV;
- chan = master->dma_tx;
+ chan = ctlr->dma_tx;
nents = tfr->tx_sg.nents;
sgl = tfr->tx_sg.sgl;
flags = 0 /* no tx interrupt */;
} else {
dir = DMA_DEV_TO_MEM;
- chan = master->dma_rx;
+ chan = ctlr->dma_rx;
nents = tfr->rx_sg.nents;
sgl = tfr->rx_sg.sgl;
flags = DMA_PREP_INTERRUPT;
@@ -534,7 +598,7 @@ static int bcm2835_spi_prepare_sg(struct spi_master *master,
/* set callback for rx */
if (!is_tx) {
desc->callback = bcm2835_spi_dma_done;
- desc->callback_param = master;
+ desc->callback_param = ctlr;
}
/* submit it to DMA-engine */
@@ -543,27 +607,30 @@ static int bcm2835_spi_prepare_sg(struct spi_master *master,
return dma_submit_error(cookie);
}
-static int bcm2835_spi_transfer_one_dma(struct spi_master *master,
+static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr,
struct spi_device *spi,
struct spi_transfer *tfr,
u32 cs)
{
- struct bcm2835_spi *bs = spi_master_get_devdata(master);
+ struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
int ret;
+ /* update usage statistics */
+ bs->count_transfer_dma++;
+
/*
* Transfer first few bytes without DMA if length of first TX or RX
* sglist entry is not a multiple of 4 bytes (hardware limitation).
*/
- bcm2835_spi_transfer_prologue(master, tfr, bs, cs);
+ bcm2835_spi_transfer_prologue(ctlr, tfr, bs, cs);
/* setup tx-DMA */
- ret = bcm2835_spi_prepare_sg(master, tfr, true);
+ ret = bcm2835_spi_prepare_sg(ctlr, tfr, true);
if (ret)
goto err_reset_hw;
/* start TX early */
- dma_async_issue_pending(master->dma_tx);
+ dma_async_issue_pending(ctlr->dma_tx);
/* mark as dma pending */
bs->dma_pending = 1;
@@ -579,27 +646,27 @@ static int bcm2835_spi_transfer_one_dma(struct spi_master *master,
* mapping of the rx buffers still takes place
* this saves 10us or more.
*/
- ret = bcm2835_spi_prepare_sg(master, tfr, false);
+ ret = bcm2835_spi_prepare_sg(ctlr, tfr, false);
if (ret) {
/* need to reset on errors */
- dmaengine_terminate_sync(master->dma_tx);
+ dmaengine_terminate_sync(ctlr->dma_tx);
bs->dma_pending = false;
goto err_reset_hw;
}
/* start rx dma late */
- dma_async_issue_pending(master->dma_rx);
+ dma_async_issue_pending(ctlr->dma_rx);
/* wait for wakeup in framework */
return 1;
err_reset_hw:
- bcm2835_spi_reset_hw(master);
+ bcm2835_spi_reset_hw(ctlr);
bcm2835_spi_undo_prologue(bs);
return ret;
}
-static bool bcm2835_spi_can_dma(struct spi_master *master,
+static bool bcm2835_spi_can_dma(struct spi_controller *ctlr,
struct spi_device *spi,
struct spi_transfer *tfr)
{
@@ -611,21 +678,21 @@ static bool bcm2835_spi_can_dma(struct spi_master *master,
return true;
}
-static void bcm2835_dma_release(struct spi_master *master)
+static void bcm2835_dma_release(struct spi_controller *ctlr)
{
- if (master->dma_tx) {
- dmaengine_terminate_sync(master->dma_tx);
- dma_release_channel(master->dma_tx);
- master->dma_tx = NULL;
+ if (ctlr->dma_tx) {
+ dmaengine_terminate_sync(ctlr->dma_tx);
+ dma_release_channel(ctlr->dma_tx);
+ ctlr->dma_tx = NULL;
}
- if (master->dma_rx) {
- dmaengine_terminate_sync(master->dma_rx);
- dma_release_channel(master->dma_rx);
- master->dma_rx = NULL;
+ if (ctlr->dma_rx) {
+ dmaengine_terminate_sync(ctlr->dma_rx);
+ dma_release_channel(ctlr->dma_rx);
+ ctlr->dma_rx = NULL;
}
}
-static void bcm2835_dma_init(struct spi_master *master, struct device *dev)
+static void bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev)
{
struct dma_slave_config slave_config;
const __be32 *addr;
@@ -633,7 +700,7 @@ static void bcm2835_dma_init(struct spi_master *master, struct device *dev)
int ret;
/* base address in dma-space */
- addr = of_get_address(master->dev.of_node, 0, NULL, NULL);
+ addr = of_get_address(ctlr->dev.of_node, 0, NULL, NULL);
if (!addr) {
dev_err(dev, "could not get DMA-register address - not using dma mode\n");
goto err;
@@ -641,38 +708,36 @@ static void bcm2835_dma_init(struct spi_master *master, struct device *dev)
dma_reg_base = be32_to_cpup(addr);
/* get tx/rx dma */
- master->dma_tx = dma_request_slave_channel(dev, "tx");
- if (!master->dma_tx) {
+ ctlr->dma_tx = dma_request_slave_channel(dev, "tx");
+ if (!ctlr->dma_tx) {
dev_err(dev, "no tx-dma configuration found - not using dma mode\n");
goto err;
}
- master->dma_rx = dma_request_slave_channel(dev, "rx");
- if (!master->dma_rx) {
+ ctlr->dma_rx = dma_request_slave_channel(dev, "rx");
+ if (!ctlr->dma_rx) {
dev_err(dev, "no rx-dma configuration found - not using dma mode\n");
goto err_release;
}
/* configure DMAs */
- slave_config.direction = DMA_MEM_TO_DEV;
slave_config.dst_addr = (u32)(dma_reg_base + BCM2835_SPI_FIFO);
slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- ret = dmaengine_slave_config(master->dma_tx, &slave_config);
+ ret = dmaengine_slave_config(ctlr->dma_tx, &slave_config);
if (ret)
goto err_config;
- slave_config.direction = DMA_DEV_TO_MEM;
slave_config.src_addr = (u32)(dma_reg_base + BCM2835_SPI_FIFO);
slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- ret = dmaengine_slave_config(master->dma_rx, &slave_config);
+ ret = dmaengine_slave_config(ctlr->dma_rx, &slave_config);
if (ret)
goto err_config;
/* all went well, so set can_dma */
- master->can_dma = bcm2835_spi_can_dma;
+ ctlr->can_dma = bcm2835_spi_can_dma;
/* need to do TX AND RX DMA, so we need dummy buffers */
- master->flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX;
+ ctlr->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX;
return;
@@ -680,20 +745,22 @@ err_config:
dev_err(dev, "issue configuring dma: %d - not using DMA mode\n",
ret);
err_release:
- bcm2835_dma_release(master);
+ bcm2835_dma_release(ctlr);
err:
return;
}
-static int bcm2835_spi_transfer_one_poll(struct spi_master *master,
+static int bcm2835_spi_transfer_one_poll(struct spi_controller *ctlr,
struct spi_device *spi,
struct spi_transfer *tfr,
- u32 cs,
- unsigned long long xfer_time_us)
+ u32 cs)
{
- struct bcm2835_spi *bs = spi_master_get_devdata(master);
+ struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
unsigned long timeout;
+ /* update usage statistics */
+ bs->count_transfer_polling++;
+
/* enable HW block without interrupts */
bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA);
@@ -703,8 +770,8 @@ static int bcm2835_spi_transfer_one_poll(struct spi_master *master,
*/
bcm2835_wr_fifo_blind(bs, BCM2835_SPI_FIFO_SIZE);
- /* set the timeout */
- timeout = jiffies + BCM2835_SPI_POLLING_JIFFIES;
+ /* set the timeout to at least 2 jiffies */
+ timeout = jiffies + 2 + HZ * polling_limit_us / 1000000;
/* loop until finished the transfer */
while (bs->rx_len) {
@@ -723,25 +790,28 @@ static int bcm2835_spi_transfer_one_poll(struct spi_master *master,
jiffies - timeout,
bs->tx_len, bs->rx_len);
/* fall back to interrupt mode */
- return bcm2835_spi_transfer_one_irq(master, spi,
+
+ /* update usage statistics */
+ bs->count_transfer_irq_after_polling++;
+
+ return bcm2835_spi_transfer_one_irq(ctlr, spi,
tfr, cs, false);
}
}
/* Transfer complete - reset SPI HW */
- bcm2835_spi_reset_hw(master);
+ bcm2835_spi_reset_hw(ctlr);
/* and return without waiting for completion */
return 0;
}
-static int bcm2835_spi_transfer_one(struct spi_master *master,
+static int bcm2835_spi_transfer_one(struct spi_controller *ctlr,
struct spi_device *spi,
struct spi_transfer *tfr)
{
- struct bcm2835_spi *bs = spi_master_get_devdata(master);
- unsigned long spi_hz, clk_hz, cdiv;
- unsigned long spi_used_hz;
- unsigned long long xfer_time_us;
+ struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
+ unsigned long spi_hz, clk_hz, cdiv, spi_used_hz;
+ unsigned long hz_per_byte, byte_limit;
u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
/* set clock */
@@ -782,42 +852,49 @@ static int bcm2835_spi_transfer_one(struct spi_master *master,
bs->tx_len = tfr->len;
bs->rx_len = tfr->len;
- /* calculate the estimated time in us the transfer runs */
- xfer_time_us = (unsigned long long)tfr->len
- * 9 /* clocks/byte - SPI-HW waits 1 clock after each byte */
- * 1000000;
- do_div(xfer_time_us, spi_used_hz);
+ /* Calculate the estimated time in us the transfer runs. Note that
+ * there is 1 idle clocks cycles after each byte getting transferred
+ * so we have 9 cycles/byte. This is used to find the number of Hz
+ * per byte per polling limit. E.g., we can transfer 1 byte in 30 us
+ * per 300,000 Hz of bus clock.
+ */
+ hz_per_byte = polling_limit_us ? (9 * 1000000) / polling_limit_us : 0;
+ byte_limit = hz_per_byte ? spi_used_hz / hz_per_byte : 1;
- /* for short requests run polling*/
- if (xfer_time_us <= BCM2835_SPI_POLLING_LIMIT_US)
- return bcm2835_spi_transfer_one_poll(master, spi, tfr,
- cs, xfer_time_us);
+ /* run in polling mode for short transfers */
+ if (tfr->len < byte_limit)
+ return bcm2835_spi_transfer_one_poll(ctlr, spi, tfr, cs);
- /* run in dma mode if conditions are right */
- if (master->can_dma && bcm2835_spi_can_dma(master, spi, tfr))
- return bcm2835_spi_transfer_one_dma(master, spi, tfr, cs);
+ /* run in dma mode if conditions are right
+ * Note that unlike poll or interrupt mode DMA mode does not have
+ * 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, spi, tfr, cs);
/* run in interrupt-mode */
- return bcm2835_spi_transfer_one_irq(master, spi, tfr, cs, true);
+ return bcm2835_spi_transfer_one_irq(ctlr, spi, tfr, cs, true);
}
-static int bcm2835_spi_prepare_message(struct spi_master *master,
+static int bcm2835_spi_prepare_message(struct spi_controller *ctlr,
struct spi_message *msg)
{
struct spi_device *spi = msg->spi;
- struct bcm2835_spi *bs = spi_master_get_devdata(master);
+ struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
int ret;
- /*
- * DMA transfers are limited to 16 bit (0 to 65535 bytes) by the SPI HW
- * due to DLEN. Split up transfers (32-bit FIFO aligned) if the limit is
- * exceeded.
- */
- ret = spi_split_transfers_maxsize(master, msg, 65532,
- GFP_KERNEL | GFP_DMA);
- if (ret)
- return ret;
+ if (ctlr->can_dma) {
+ /*
+ * DMA transfers are limited to 16 bit (0 to 65535 bytes) by
+ * the SPI HW due to DLEN. Split up transfers (32-bit FIFO
+ * aligned) if the limit is exceeded.
+ */
+ ret = spi_split_transfers_maxsize(ctlr, msg, 65532,
+ GFP_KERNEL | GFP_DMA);
+ if (ret)
+ return ret;
+ }
cs &= ~(BCM2835_SPI_CS_CPOL | BCM2835_SPI_CS_CPHA);
@@ -831,19 +908,19 @@ static int bcm2835_spi_prepare_message(struct spi_master *master,
return 0;
}
-static void bcm2835_spi_handle_err(struct spi_master *master,
+static void bcm2835_spi_handle_err(struct spi_controller *ctlr,
struct spi_message *msg)
{
- struct bcm2835_spi *bs = spi_master_get_devdata(master);
+ struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
/* if an error occurred and we have an active dma, then terminate */
if (cmpxchg(&bs->dma_pending, true, false)) {
- dmaengine_terminate_sync(master->dma_tx);
- dmaengine_terminate_sync(master->dma_rx);
+ dmaengine_terminate_sync(ctlr->dma_tx);
+ dmaengine_terminate_sync(ctlr->dma_rx);
bcm2835_spi_undo_prologue(bs);
}
/* and reset */
- bcm2835_spi_reset_hw(master);
+ bcm2835_spi_reset_hw(ctlr);
}
static int chip_match_name(struct gpio_chip *chip, void *data)
@@ -900,85 +977,88 @@ static int bcm2835_spi_setup(struct spi_device *spi)
static int bcm2835_spi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *ctlr;
struct bcm2835_spi *bs;
struct resource *res;
int err;
- master = spi_alloc_master(&pdev->dev, sizeof(*bs));
- if (!master) {
- dev_err(&pdev->dev, "spi_alloc_master() failed\n");
+ ctlr = spi_alloc_master(&pdev->dev, sizeof(*bs));
+ if (!ctlr)
return -ENOMEM;
- }
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, ctlr);
- master->mode_bits = BCM2835_SPI_MODE_BITS;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->num_chipselect = 3;
- master->setup = bcm2835_spi_setup;
- master->transfer_one = bcm2835_spi_transfer_one;
- master->handle_err = bcm2835_spi_handle_err;
- master->prepare_message = bcm2835_spi_prepare_message;
- master->dev.of_node = pdev->dev.of_node;
+ ctlr->mode_bits = BCM2835_SPI_MODE_BITS;
+ ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
+ ctlr->num_chipselect = 3;
+ ctlr->setup = bcm2835_spi_setup;
+ ctlr->transfer_one = bcm2835_spi_transfer_one;
+ ctlr->handle_err = bcm2835_spi_handle_err;
+ ctlr->prepare_message = bcm2835_spi_prepare_message;
+ ctlr->dev.of_node = pdev->dev.of_node;
- bs = spi_master_get_devdata(master);
+ bs = spi_controller_get_devdata(ctlr);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
bs->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(bs->regs)) {
err = PTR_ERR(bs->regs);
- goto out_master_put;
+ goto out_controller_put;
}
bs->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(bs->clk)) {
err = PTR_ERR(bs->clk);
dev_err(&pdev->dev, "could not get clk: %d\n", err);
- goto out_master_put;
+ goto out_controller_put;
}
bs->irq = platform_get_irq(pdev, 0);
if (bs->irq <= 0) {
dev_err(&pdev->dev, "could not get IRQ: %d\n", bs->irq);
err = bs->irq ? bs->irq : -ENODEV;
- goto out_master_put;
+ goto out_controller_put;
}
clk_prepare_enable(bs->clk);
- bcm2835_dma_init(master, &pdev->dev);
+ bcm2835_dma_init(ctlr, &pdev->dev);
/* initialise the hardware with the default polarities */
bcm2835_wr(bs, BCM2835_SPI_CS,
BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX);
err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt, 0,
- dev_name(&pdev->dev), master);
+ dev_name(&pdev->dev), ctlr);
if (err) {
dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
goto out_clk_disable;
}
- err = devm_spi_register_master(&pdev->dev, master);
+ err = devm_spi_register_controller(&pdev->dev, ctlr);
if (err) {
- dev_err(&pdev->dev, "could not register SPI master: %d\n", err);
+ dev_err(&pdev->dev, "could not register SPI controller: %d\n",
+ err);
goto out_clk_disable;
}
+ bcm2835_debugfs_create(bs, dev_name(&pdev->dev));
+
return 0;
out_clk_disable:
clk_disable_unprepare(bs->clk);
-out_master_put:
- spi_master_put(master);
+out_controller_put:
+ spi_controller_put(ctlr);
return err;
}
static int bcm2835_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct bcm2835_spi *bs = spi_master_get_devdata(master);
+ struct spi_controller *ctlr = platform_get_drvdata(pdev);
+ struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
+
+ bcm2835_debugfs_remove(bs);
/* Clear FIFOs, and disable the HW block */
bcm2835_wr(bs, BCM2835_SPI_CS,
@@ -986,7 +1066,7 @@ static int bcm2835_spi_remove(struct platform_device *pdev)
clk_disable_unprepare(bs->clk);
- bcm2835_dma_release(master);
+ bcm2835_dma_release(ctlr);
return 0;
}
diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c
index 40dfb7f58efe..bb57035c5770 100644
--- a/drivers/spi/spi-bcm2835aux.c
+++ b/drivers/spi/spi-bcm2835aux.c
@@ -496,10 +496,8 @@ static int bcm2835aux_spi_probe(struct platform_device *pdev)
int err;
master = spi_alloc_master(&pdev->dev, sizeof(*bs));
- if (!master) {
- dev_err(&pdev->dev, "spi_alloc_master() failed\n");
+ if (!master)
return -ENOMEM;
- }
platform_set_drvdata(pdev, master);
master->mode_bits = (SPI_CPOL | SPI_CS_HIGH | SPI_NO_CS);
diff --git a/drivers/spi/spi-brcmstb-qspi.c b/drivers/spi/spi-brcmstb-qspi.c
index c7df92e7cf6f..75e9b76dab1e 100644
--- a/drivers/spi/spi-brcmstb-qspi.c
+++ b/drivers/spi/spi-brcmstb-qspi.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2016 Broadcom
- *
- * 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 (the "GPL").
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License version 2 (GPLv2) for more details.
- *
- * You should have received a copy of the GNU General Public License
- * version 2 (GPLv2) along with this source code.
*/
#include <linux/device.h>
diff --git a/drivers/spi/spi-efm32.c b/drivers/spi/spi-efm32.c
index 065fe8744989..eb1f2142a335 100644
--- a/drivers/spi/spi-efm32.c
+++ b/drivers/spi/spi-efm32.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012-2013 Uwe Kleine-Koenig for Pengutronix
- *
- * 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.
*/
#include <linux/kernel.h>
#include <linux/io.h>
diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c
index 81889389280b..4034e3ec0ba2 100644
--- a/drivers/spi/spi-ep93xx.c
+++ b/drivers/spi/spi-ep93xx.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for Cirrus Logic EP93xx SPI controller.
*
@@ -10,10 +11,6 @@
* For more information about the SPI controller see documentation on Cirrus
* Logic web site:
* http://www.cirrus.com/en/pubs/manual/EP93xx_Users_Guide_UM1.pdf
- *
- * 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.
*/
#include <linux/io.h>
diff --git a/drivers/spi/spi-falcon.c b/drivers/spi/spi-falcon.c
index f8638e82e5db..00f46c816a56 100644
--- a/drivers/spi/spi-falcon.c
+++ b/drivers/spi/spi-falcon.c
@@ -1,7 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
- * 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.
*
* Copyright (C) 2012 Thomas Langer <thomas.langer@lantiq.com>
*/
diff --git a/drivers/spi/spi-meson-spifc.c b/drivers/spi/spi-meson-spifc.c
index ea4b1bf0fa16..f7fe9b13d122 100644
--- a/drivers/spi/spi-meson-spifc.c
+++ b/drivers/spi/spi-meson-spifc.c
@@ -1,9 +1,9 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Driver for Amlogic Meson SPI flash controller (SPIFC)
- *
- * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Driver for Amlogic Meson SPI flash controller (SPIFC)
+//
+// Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
+//
#include <linux/clk.h>
#include <linux/delay.h>
diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c
index 10041eab36a2..45d8a7048b6c 100644
--- a/drivers/spi/spi-mt65xx.c
+++ b/drivers/spi/spi-mt65xx.c
@@ -123,8 +123,6 @@ static const struct mtk_spi_compatible mt8183_compat = {
* supplies it.
*/
static const struct mtk_chip_config mtk_default_chip_info = {
- .rx_mlsb = 1,
- .tx_mlsb = 1,
.cs_pol = 0,
.sample_sel = 0,
};
@@ -195,14 +193,13 @@ static int mtk_spi_prepare_message(struct spi_master *master,
reg_val &= ~SPI_CMD_CPOL;
/* set the mlsbx and mlsbtx */
- if (chip_config->tx_mlsb)
- reg_val |= SPI_CMD_TXMSBF;
- else
+ if (spi->mode & SPI_LSB_FIRST) {
reg_val &= ~SPI_CMD_TXMSBF;
- if (chip_config->rx_mlsb)
- reg_val |= SPI_CMD_RXMSBF;
- else
reg_val &= ~SPI_CMD_RXMSBF;
+ } else {
+ reg_val |= SPI_CMD_TXMSBF;
+ reg_val |= SPI_CMD_RXMSBF;
+ }
/* set the tx/rx endian */
#ifdef __LITTLE_ENDIAN
@@ -599,7 +596,7 @@ static int mtk_spi_probe(struct platform_device *pdev)
master->auto_runtime_pm = true;
master->dev.of_node = pdev->dev.of_node;
- master->mode_bits = SPI_CPOL | SPI_CPHA;
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
master->set_cs = mtk_spi_set_cs;
master->prepare_message = mtk_spi_prepare_message;
diff --git a/drivers/spi/spi-nuc900.c b/drivers/spi/spi-nuc900.c
index f51a058e7678..37e2034ad4d5 100644
--- a/drivers/spi/spi-nuc900.c
+++ b/drivers/spi/spi-nuc900.c
@@ -1,11 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2009 Nuvoton technology.
* Wan ZongShun <mcuos.com@gmail.com>
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c
index 085f580be7ec..bbc4ba66571f 100644
--- a/drivers/spi/spi-oc-tiny.c
+++ b/drivers/spi/spi-oc-tiny.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* OpenCores tiny SPI master driver
*
@@ -9,10 +10,6 @@
* Copyright (c) 2006 Ben Dooks
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
- *
- * 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.
*/
#include <linux/interrupt.h>
diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c
index 25ea4a9e0dbc..6643ccdc2508 100644
--- a/drivers/spi/spi-orion.c
+++ b/drivers/spi/spi-orion.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Marvell Orion SPI controller driver
*
* Author: Shadi Ammouri <shadi@marvell.com>
* Copyright (C) 2007-2008 Marvell Ltd.
- *
- * 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.
*/
#include <linux/interrupt.h>
diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c
index 967d94844b30..0ea2d9a369d9 100644
--- a/drivers/spi/spi-ppc4xx.c
+++ b/drivers/spi/spi-ppc4xx.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* SPI_PPC4XX SPI controller driver.
*
@@ -10,10 +11,6 @@
* Copyright (c) 2006 Ben Dooks
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
- *
- * 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.
*/
/*
diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c
index e5c26c1779ab..37567bc7a523 100644
--- a/drivers/spi/spi-pxa2xx-dma.c
+++ b/drivers/spi/spi-pxa2xx-dma.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* PXA2xx SPI DMA engine support.
*
* Copyright (C) 2013, Intel Corporation
* Author: Mika Westerberg <mika.westerberg@linux.intel.com>
- *
- * 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.
*/
#include <linux/device.h>
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index af3f37ba82c8..fc7ab4b26880 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -1437,6 +1437,10 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = {
{ PCI_VDEVICE(INTEL, 0x34aa), LPSS_CNL_SSP },
{ PCI_VDEVICE(INTEL, 0x34ab), LPSS_CNL_SSP },
{ PCI_VDEVICE(INTEL, 0x34fb), LPSS_CNL_SSP },
+ /* EHL */
+ { PCI_VDEVICE(INTEL, 0x4b2a), LPSS_BXT_SSP },
+ { PCI_VDEVICE(INTEL, 0x4b2b), LPSS_BXT_SSP },
+ { PCI_VDEVICE(INTEL, 0x4b37), LPSS_BXT_SSP },
/* APL */
{ PCI_VDEVICE(INTEL, 0x5ac2), LPSS_BXT_SSP },
{ PCI_VDEVICE(INTEL, 0x5ac4), LPSS_BXT_SSP },
@@ -1704,6 +1708,16 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
goto out_error_dma_irq_alloc;
controller->max_speed_hz = clk_get_rate(ssp->clk);
+ /*
+ * Set minimum speed for all other platforms than Intel Quark which is
+ * able do under 1 Hz transfers.
+ */
+ if (!pxa25x_ssp_comp(drv_data))
+ controller->min_speed_hz =
+ DIV_ROUND_UP(controller->max_speed_hz, 4096);
+ else if (!is_quark_x1000_ssp(drv_data))
+ controller->min_speed_hz =
+ DIV_ROUND_UP(controller->max_speed_hz, 512);
/* Load default SSP configuration */
pxa2xx_spi_write(drv_data, SSCR0, 0);
diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h
index aba777b4502d..1400472bc986 100644
--- a/drivers/spi/spi-pxa2xx.h
+++ b/drivers/spi/spi-pxa2xx.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2005 Stephen Street / StreetFire Sound Labs
* Copyright (C) 2013, Intel Corporation
- *
- * 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.
*/
#ifndef SPI_PXA2XX_H
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index f22dbb4b87a5..2f559e531100 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -273,6 +273,9 @@ static void spi_qup_read(struct spi_qup *controller, u32 *opflags)
writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
controller->base + QUP_OPERATIONAL);
+ if (!remainder)
+ goto exit;
+
if (is_block_mode) {
num_words = (remainder > words_per_block) ?
words_per_block : remainder;
@@ -302,11 +305,13 @@ static void spi_qup_read(struct spi_qup *controller, u32 *opflags)
* to refresh opflags value because MAX_INPUT_DONE_FLAG may now be
* present and this is used to determine if transaction is complete
*/
- *opflags = readl_relaxed(controller->base + QUP_OPERATIONAL);
- if (is_block_mode && *opflags & QUP_OP_MAX_INPUT_DONE_FLAG)
- writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
- controller->base + QUP_OPERATIONAL);
-
+exit:
+ if (!remainder) {
+ *opflags = readl_relaxed(controller->base + QUP_OPERATIONAL);
+ if (is_block_mode && *opflags & QUP_OP_MAX_INPUT_DONE_FLAG)
+ writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
+ controller->base + QUP_OPERATIONAL);
+ }
}
static void spi_qup_write_to_fifo(struct spi_qup *controller, u32 num_words)
@@ -354,6 +359,10 @@ static void spi_qup_write(struct spi_qup *controller)
writel_relaxed(QUP_OP_OUT_SERVICE_FLAG,
controller->base + QUP_OPERATIONAL);
+ /* make sure the interrupt is valid */
+ if (!remainder)
+ return;
+
if (is_block_mode) {
num_words = (remainder > words_per_block) ?
words_per_block : remainder;
@@ -567,10 +576,24 @@ static int spi_qup_do_pio(struct spi_device *spi, struct spi_transfer *xfer,
return 0;
}
+static bool spi_qup_data_pending(struct spi_qup *controller)
+{
+ unsigned int remainder_tx, remainder_rx;
+
+ remainder_tx = DIV_ROUND_UP(spi_qup_len(controller) -
+ controller->tx_bytes, controller->w_size);
+
+ remainder_rx = DIV_ROUND_UP(spi_qup_len(controller) -
+ controller->rx_bytes, controller->w_size);
+
+ return remainder_tx || remainder_rx;
+}
+
static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
{
struct spi_qup *controller = dev_id;
u32 opflags, qup_err, spi_err;
+ unsigned long flags;
int error = 0;
qup_err = readl_relaxed(controller->base + QUP_ERROR_FLAGS);
@@ -602,6 +625,11 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
error = -EIO;
}
+ spin_lock_irqsave(&controller->lock, flags);
+ if (!controller->error)
+ controller->error = error;
+ spin_unlock_irqrestore(&controller->lock, flags);
+
if (spi_qup_is_dma_xfer(controller->mode)) {
writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
} else {
@@ -610,10 +638,21 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
if (opflags & QUP_OP_OUT_SERVICE_FLAG)
spi_qup_write(controller);
+
+ if (!spi_qup_data_pending(controller))
+ complete(&controller->done);
}
- if ((opflags & QUP_OP_MAX_INPUT_DONE_FLAG) || error)
+ if (error)
+ complete(&controller->done);
+
+ if (opflags & QUP_OP_MAX_INPUT_DONE_FLAG) {
+ if (!spi_qup_is_dma_xfer(controller->mode)) {
+ if (spi_qup_data_pending(controller))
+ return IRQ_HANDLED;
+ }
complete(&controller->done);
+ }
return IRQ_HANDLED;
}
@@ -834,10 +873,6 @@ static int spi_qup_transfer_one(struct spi_master *master,
else
ret = spi_qup_do_pio(spi, xfer, timeout);
- if (ret)
- goto exit;
-
-exit:
spi_qup_set_state(controller, QUP_STATE_RESET);
spin_lock_irqsave(&controller->lock, flags);
if (!ret)
diff --git a/drivers/spi/spi-rb4xx.c b/drivers/spi/spi-rb4xx.c
index fbbf9a188247..51f03d977ad6 100644
--- a/drivers/spi/spi-rb4xx.c
+++ b/drivers/spi/spi-rb4xx.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* SPI controller driver for the Mikrotik RB4xx boards
*
@@ -6,11 +7,6 @@
*
* This file was based on the patches for Linux 2.6.27.39 published by
* MikroTik for their RouterBoard 4xx series devices.
- *
- * 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.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 9b91188a85f9..2cc6d9951b52 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -417,7 +417,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
.direction = DMA_MEM_TO_DEV,
.dst_addr = rs->dma_addr_tx,
.dst_addr_width = rs->n_bytes,
- .dst_maxburst = rs->fifo_len / 2,
+ .dst_maxburst = rs->fifo_len / 4,
};
dmaengine_slave_config(master->dma_tx, &txconf);
@@ -518,7 +518,7 @@ static void rockchip_spi_config(struct rockchip_spi *rs,
else
writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR);
- writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_DMATDLR);
+ writel_relaxed(rs->fifo_len / 2, rs->regs + ROCKCHIP_SPI_DMATDLR);
writel_relaxed(0, rs->regs + ROCKCHIP_SPI_DMARDLR);
writel_relaxed(dmacr, rs->regs + ROCKCHIP_SPI_DMACR);
diff --git a/drivers/spi/spi-s3c24xx-fiq.S b/drivers/spi/spi-s3c24xx-fiq.S
index 059f2dc1fda2..e95d6282109e 100644
--- a/drivers/spi/spi-s3c24xx-fiq.S
+++ b/drivers/spi/spi-s3c24xx-fiq.S
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/* linux/drivers/spi/spi_s3c24xx_fiq.S
*
* Copyright 2009 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* S3C24XX SPI - FIQ pseudo-DMA transfer code
- *
- * 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.
*/
#include <linux/linkage.h>
diff --git a/drivers/spi/spi-s3c24xx-fiq.h b/drivers/spi/spi-s3c24xx-fiq.h
index a5950bb25b51..7786b0ea56ec 100644
--- a/drivers/spi/spi-s3c24xx-fiq.h
+++ b/drivers/spi/spi-s3c24xx-fiq.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/* linux/drivers/spi/spi_s3c24xx_fiq.h
*
* Copyright 2009 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* S3C24XX SPI - FIQ pseudo-DMA transfer support
- *
- * 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.
*/
/* We have R8 through R13 to play with */
diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c
index 4e7d1bfed7e6..48d8dff05a3a 100644
--- a/drivers/spi/spi-s3c24xx.c
+++ b/drivers/spi/spi-s3c24xx.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2006 Ben Dooks
* Copyright 2006-2009 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
- *
- * 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.
- *
*/
#include <linux/spinlock.h>
diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c
index 6aab7b2136db..b50bdbc27e58 100644
--- a/drivers/spi/spi-sh-msiof.c
+++ b/drivers/spi/spi-sh-msiof.c
@@ -229,7 +229,7 @@ static int sh_msiof_modify_ctr_wait(struct sh_msiof_spi_priv *p,
sh_msiof_write(p, CTR, data);
return readl_poll_timeout_atomic(p->mapbase + CTR, data,
- (data & mask) == set, 10, 1000);
+ (data & mask) == set, 1, 100);
}
static irqreturn_t sh_msiof_spi_irq(int irq, void *data)
diff --git a/drivers/spi/spi-sh-sci.c b/drivers/spi/spi-sh-sci.c
index 393701cfca3c..8f30531e1418 100644
--- a/drivers/spi/spi-sh-sci.c
+++ b/drivers/spi/spi-sh-sci.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* SH SCI SPI interface
*
@@ -6,11 +7,6 @@
* Based on S3C24XX GPIO based SPI driver, which is:
* Copyright (c) 2006 Ben Dooks
* Copyright (c) 2006 Simtec Electronics
- *
- * 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.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c
index 42f8e3c6aa1f..655e4afbfb2a 100644
--- a/drivers/spi/spi-stm32-qspi.c
+++ b/drivers/spi/spi-stm32-qspi.c
@@ -29,7 +29,7 @@
#define CR_SSHIFT BIT(4)
#define CR_DFM BIT(6)
#define CR_FSEL BIT(7)
-#define CR_FTHRES_MASK GENMASK(12, 8)
+#define CR_FTHRES_SHIFT 8
#define CR_TEIE BIT(16)
#define CR_TCIE BIT(17)
#define CR_FTIE BIT(18)
@@ -245,12 +245,8 @@ static int stm32_qspi_tx_dma(struct stm32_qspi *qspi,
writel_relaxed(cr | CR_DMAEN, qspi->io_base + QSPI_CR);
t_out = sgt.nents * STM32_COMP_TIMEOUT_MS;
- if (!wait_for_completion_interruptible_timeout(&qspi->dma_completion,
- msecs_to_jiffies(t_out)))
- err = -ETIMEDOUT;
-
- if (dma_async_is_tx_complete(dma_ch, cookie,
- NULL, NULL) != DMA_COMPLETE)
+ if (!wait_for_completion_timeout(&qspi->dma_completion,
+ msecs_to_jiffies(t_out)))
err = -ETIMEDOUT;
if (err)
@@ -304,7 +300,7 @@ static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi,
cr = readl_relaxed(qspi->io_base + QSPI_CR);
writel_relaxed(cr | CR_TCIE | CR_TEIE, qspi->io_base + QSPI_CR);
- if (!wait_for_completion_interruptible_timeout(&qspi->data_completion,
+ if (!wait_for_completion_timeout(&qspi->data_completion,
msecs_to_jiffies(STM32_COMP_TIMEOUT_MS))) {
err = -ETIMEDOUT;
} else {
@@ -463,7 +459,7 @@ static int stm32_qspi_setup(struct spi_device *spi)
flash->presc = presc;
mutex_lock(&qspi->lock);
- qspi->cr_reg = FIELD_PREP(CR_FTHRES_MASK, 3) | CR_SSHIFT | CR_EN;
+ qspi->cr_reg = 3 << CR_FTHRES_SHIFT | CR_SSHIFT | CR_EN;
writel_relaxed(qspi->cr_reg, qspi->io_base + QSPI_CR);
/* set dcr fsize to max address */
diff --git a/drivers/spi/spi-synquacer.c b/drivers/spi/spi-synquacer.c
new file mode 100644
index 000000000000..f99abd85c50a
--- /dev/null
+++ b/drivers/spi/spi-synquacer.c
@@ -0,0 +1,828 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Synquacer HSSPI controller driver
+//
+// Copyright (c) 2015-2018 Socionext Inc.
+// Copyright (c) 2018-2019 Linaro Ltd.
+//
+
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+
+/* HSSPI register address definitions */
+#define SYNQUACER_HSSPI_REG_MCTRL 0x00
+#define SYNQUACER_HSSPI_REG_PCC0 0x04
+#define SYNQUACER_HSSPI_REG_PCC(n) (SYNQUACER_HSSPI_REG_PCC0 + (n) * 4)
+#define SYNQUACER_HSSPI_REG_TXF 0x14
+#define SYNQUACER_HSSPI_REG_TXE 0x18
+#define SYNQUACER_HSSPI_REG_TXC 0x1C
+#define SYNQUACER_HSSPI_REG_RXF 0x20
+#define SYNQUACER_HSSPI_REG_RXE 0x24
+#define SYNQUACER_HSSPI_REG_RXC 0x28
+#define SYNQUACER_HSSPI_REG_FAULTF 0x2C
+#define SYNQUACER_HSSPI_REG_FAULTC 0x30
+#define SYNQUACER_HSSPI_REG_DMCFG 0x34
+#define SYNQUACER_HSSPI_REG_DMSTART 0x38
+#define SYNQUACER_HSSPI_REG_DMBCC 0x3C
+#define SYNQUACER_HSSPI_REG_DMSTATUS 0x40
+#define SYNQUACER_HSSPI_REG_FIFOCFG 0x4C
+#define SYNQUACER_HSSPI_REG_TX_FIFO 0x50
+#define SYNQUACER_HSSPI_REG_RX_FIFO 0x90
+#define SYNQUACER_HSSPI_REG_MID 0xFC
+
+/* HSSPI register bit definitions */
+#define SYNQUACER_HSSPI_MCTRL_MEN BIT(0)
+#define SYNQUACER_HSSPI_MCTRL_COMMAND_SEQUENCE_EN BIT(1)
+#define SYNQUACER_HSSPI_MCTRL_CDSS BIT(3)
+#define SYNQUACER_HSSPI_MCTRL_MES BIT(4)
+#define SYNQUACER_HSSPI_MCTRL_SYNCON BIT(5)
+
+#define SYNQUACER_HSSPI_PCC_CPHA BIT(0)
+#define SYNQUACER_HSSPI_PCC_CPOL BIT(1)
+#define SYNQUACER_HSSPI_PCC_ACES BIT(2)
+#define SYNQUACER_HSSPI_PCC_RTM BIT(3)
+#define SYNQUACER_HSSPI_PCC_SSPOL BIT(4)
+#define SYNQUACER_HSSPI_PCC_SDIR BIT(7)
+#define SYNQUACER_HSSPI_PCC_SENDIAN BIT(8)
+#define SYNQUACER_HSSPI_PCC_SAFESYNC BIT(16)
+#define SYNQUACER_HSSPI_PCC_SS2CD_SHIFT 5U
+#define SYNQUACER_HSSPI_PCC_CDRS_MASK 0x7f
+#define SYNQUACER_HSSPI_PCC_CDRS_SHIFT 9U
+
+#define SYNQUACER_HSSPI_TXF_FIFO_FULL BIT(0)
+#define SYNQUACER_HSSPI_TXF_FIFO_EMPTY BIT(1)
+#define SYNQUACER_HSSPI_TXF_SLAVE_RELEASED BIT(6)
+
+#define SYNQUACER_HSSPI_TXE_FIFO_FULL BIT(0)
+#define SYNQUACER_HSSPI_TXE_FIFO_EMPTY BIT(1)
+#define SYNQUACER_HSSPI_TXE_SLAVE_RELEASED BIT(6)
+
+#define SYNQUACER_HSSPI_RXF_FIFO_MORE_THAN_THRESHOLD BIT(5)
+#define SYNQUACER_HSSPI_RXF_SLAVE_RELEASED BIT(6)
+
+#define SYNQUACER_HSSPI_RXE_FIFO_MORE_THAN_THRESHOLD BIT(5)
+#define SYNQUACER_HSSPI_RXE_SLAVE_RELEASED BIT(6)
+
+#define SYNQUACER_HSSPI_DMCFG_SSDC BIT(1)
+#define SYNQUACER_HSSPI_DMCFG_MSTARTEN BIT(2)
+
+#define SYNQUACER_HSSPI_DMSTART_START BIT(0)
+#define SYNQUACER_HSSPI_DMSTOP_STOP BIT(8)
+#define SYNQUACER_HSSPI_DMPSEL_CS_MASK 0x3
+#define SYNQUACER_HSSPI_DMPSEL_CS_SHIFT 16U
+#define SYNQUACER_HSSPI_DMTRP_BUS_WIDTH_SHIFT 24U
+#define SYNQUACER_HSSPI_DMTRP_DATA_MASK 0x3
+#define SYNQUACER_HSSPI_DMTRP_DATA_SHIFT 26U
+#define SYNQUACER_HSSPI_DMTRP_DATA_TXRX 0
+#define SYNQUACER_HSSPI_DMTRP_DATA_RX 1
+#define SYNQUACER_HSSPI_DMTRP_DATA_TX 2
+
+#define SYNQUACER_HSSPI_DMSTATUS_RX_DATA_MASK 0x1f
+#define SYNQUACER_HSSPI_DMSTATUS_RX_DATA_SHIFT 8U
+#define SYNQUACER_HSSPI_DMSTATUS_TX_DATA_MASK 0x1f
+#define SYNQUACER_HSSPI_DMSTATUS_TX_DATA_SHIFT 16U
+
+#define SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_MASK 0xf
+#define SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_SHIFT 0U
+#define SYNQUACER_HSSPI_FIFOCFG_TX_THRESHOLD_MASK 0xf
+#define SYNQUACER_HSSPI_FIFOCFG_TX_THRESHOLD_SHIFT 4U
+#define SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_MASK 0x3
+#define SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_SHIFT 8U
+#define SYNQUACER_HSSPI_FIFOCFG_RX_FLUSH BIT(11)
+#define SYNQUACER_HSSPI_FIFOCFG_TX_FLUSH BIT(12)
+
+#define SYNQUACER_HSSPI_FIFO_DEPTH 16U
+#define SYNQUACER_HSSPI_FIFO_TX_THRESHOLD 4U
+#define SYNQUACER_HSSPI_FIFO_RX_THRESHOLD \
+ (SYNQUACER_HSSPI_FIFO_DEPTH - SYNQUACER_HSSPI_FIFO_TX_THRESHOLD)
+
+#define SYNQUACER_HSSPI_TRANSFER_MODE_TX BIT(1)
+#define SYNQUACER_HSSPI_TRANSFER_MODE_RX BIT(2)
+#define SYNQUACER_HSSPI_TRANSFER_TMOUT_MSEC 2000U
+#define SYNQUACER_HSSPI_ENABLE_TMOUT_MSEC 1000U
+
+#define SYNQUACER_HSSPI_CLOCK_SRC_IHCLK 0
+#define SYNQUACER_HSSPI_CLOCK_SRC_IPCLK 1
+
+#define SYNQUACER_HSSPI_NUM_CHIP_SELECT 4U
+#define SYNQUACER_HSSPI_IRQ_NAME_MAX 32U
+
+struct synquacer_spi {
+ struct device *dev;
+ struct completion transfer_done;
+ unsigned int cs;
+ unsigned int bpw;
+ unsigned int mode;
+ unsigned int speed;
+ bool aces, rtm;
+ void *rx_buf;
+ const void *tx_buf;
+ struct clk *clk;
+ int clk_src_type;
+ void __iomem *regs;
+ u32 tx_words, rx_words;
+ unsigned int bus_width;
+ unsigned int transfer_mode;
+ char rx_irq_name[SYNQUACER_HSSPI_IRQ_NAME_MAX];
+ char tx_irq_name[SYNQUACER_HSSPI_IRQ_NAME_MAX];
+};
+
+static int read_fifo(struct synquacer_spi *sspi)
+{
+ u32 len = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTATUS);
+
+ len = (len >> SYNQUACER_HSSPI_DMSTATUS_RX_DATA_SHIFT) &
+ SYNQUACER_HSSPI_DMSTATUS_RX_DATA_MASK;
+ len = min(len, sspi->rx_words);
+
+ switch (sspi->bpw) {
+ case 8: {
+ u8 *buf = sspi->rx_buf;
+
+ ioread8_rep(sspi->regs + SYNQUACER_HSSPI_REG_RX_FIFO,
+ buf, len);
+ sspi->rx_buf = buf + len;
+ break;
+ }
+ case 16: {
+ u16 *buf = sspi->rx_buf;
+
+ ioread16_rep(sspi->regs + SYNQUACER_HSSPI_REG_RX_FIFO,
+ buf, len);
+ sspi->rx_buf = buf + len;
+ break;
+ }
+ case 24:
+ /* fallthrough, should use 32-bits access */
+ case 32: {
+ u32 *buf = sspi->rx_buf;
+
+ ioread32_rep(sspi->regs + SYNQUACER_HSSPI_REG_RX_FIFO,
+ buf, len);
+ sspi->rx_buf = buf + len;
+ break;
+ }
+ default:
+ return -EINVAL;
+ }
+
+ sspi->rx_words -= len;
+ return 0;
+}
+
+static int write_fifo(struct synquacer_spi *sspi)
+{
+ u32 len = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTATUS);
+
+ len = (len >> SYNQUACER_HSSPI_DMSTATUS_TX_DATA_SHIFT) &
+ SYNQUACER_HSSPI_DMSTATUS_TX_DATA_MASK;
+ len = min(SYNQUACER_HSSPI_FIFO_DEPTH - len,
+ sspi->tx_words);
+
+ switch (sspi->bpw) {
+ case 8: {
+ const u8 *buf = sspi->tx_buf;
+
+ iowrite8_rep(sspi->regs + SYNQUACER_HSSPI_REG_TX_FIFO,
+ buf, len);
+ sspi->tx_buf = buf + len;
+ break;
+ }
+ case 16: {
+ const u16 *buf = sspi->tx_buf;
+
+ iowrite16_rep(sspi->regs + SYNQUACER_HSSPI_REG_TX_FIFO,
+ buf, len);
+ sspi->tx_buf = buf + len;
+ break;
+ }
+ case 24:
+ /* fallthrough, should use 32-bits access */
+ case 32: {
+ const u32 *buf = sspi->tx_buf;
+
+ iowrite32_rep(sspi->regs + SYNQUACER_HSSPI_REG_TX_FIFO,
+ buf, len);
+ sspi->tx_buf = buf + len;
+ break;
+ }
+ default:
+ return -EINVAL;
+ }
+
+ sspi->tx_words -= len;
+ return 0;
+}
+
+static int synquacer_spi_config(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct synquacer_spi *sspi = spi_master_get_devdata(master);
+ unsigned int speed, mode, bpw, cs, bus_width, transfer_mode;
+ u32 rate, val, div;
+
+ /* Full Duplex only on 1-bit wide bus */
+ if (xfer->rx_buf && xfer->tx_buf &&
+ (xfer->rx_nbits != 1 || xfer->tx_nbits != 1)) {
+ dev_err(sspi->dev,
+ "RX and TX bus widths must be 1-bit for Full-Duplex!\n");
+ return -EINVAL;
+ }
+
+ if (xfer->tx_buf) {
+ bus_width = xfer->tx_nbits;
+ transfer_mode = SYNQUACER_HSSPI_TRANSFER_MODE_TX;
+ } else {
+ bus_width = xfer->rx_nbits;
+ transfer_mode = SYNQUACER_HSSPI_TRANSFER_MODE_RX;
+ }
+
+ mode = spi->mode;
+ cs = spi->chip_select;
+ speed = xfer->speed_hz;
+ bpw = xfer->bits_per_word;
+
+ /* return if nothing to change */
+ if (speed == sspi->speed &&
+ bus_width == sspi->bus_width && bpw == sspi->bpw &&
+ mode == sspi->mode && cs == sspi->cs &&
+ transfer_mode == sspi->transfer_mode) {
+ return 0;
+ }
+
+ sspi->transfer_mode = transfer_mode;
+ rate = master->max_speed_hz;
+
+ div = DIV_ROUND_UP(rate, speed);
+ if (div > 254) {
+ dev_err(sspi->dev, "Requested rate too low (%u)\n",
+ sspi->speed);
+ return -EINVAL;
+ }
+
+ val = readl(sspi->regs + SYNQUACER_HSSPI_REG_PCC(cs));
+ val &= ~SYNQUACER_HSSPI_PCC_SAFESYNC;
+ if (bpw == 8 && (mode & (SPI_TX_DUAL | SPI_RX_DUAL)) && div < 3)
+ val |= SYNQUACER_HSSPI_PCC_SAFESYNC;
+ if (bpw == 8 && (mode & (SPI_TX_QUAD | SPI_RX_QUAD)) && div < 6)
+ val |= SYNQUACER_HSSPI_PCC_SAFESYNC;
+ if (bpw == 16 && (mode & (SPI_TX_QUAD | SPI_RX_QUAD)) && div < 3)
+ val |= SYNQUACER_HSSPI_PCC_SAFESYNC;
+
+ if (mode & SPI_CPHA)
+ val |= SYNQUACER_HSSPI_PCC_CPHA;
+ else
+ val &= ~SYNQUACER_HSSPI_PCC_CPHA;
+
+ if (mode & SPI_CPOL)
+ val |= SYNQUACER_HSSPI_PCC_CPOL;
+ else
+ val &= ~SYNQUACER_HSSPI_PCC_CPOL;
+
+ if (mode & SPI_CS_HIGH)
+ val |= SYNQUACER_HSSPI_PCC_SSPOL;
+ else
+ val &= ~SYNQUACER_HSSPI_PCC_SSPOL;
+
+ if (mode & SPI_LSB_FIRST)
+ val |= SYNQUACER_HSSPI_PCC_SDIR;
+ else
+ val &= ~SYNQUACER_HSSPI_PCC_SDIR;
+
+ if (sspi->aces)
+ val |= SYNQUACER_HSSPI_PCC_ACES;
+ else
+ val &= ~SYNQUACER_HSSPI_PCC_ACES;
+
+ if (sspi->rtm)
+ val |= SYNQUACER_HSSPI_PCC_RTM;
+ else
+ val &= ~SYNQUACER_HSSPI_PCC_RTM;
+
+ val |= (3 << SYNQUACER_HSSPI_PCC_SS2CD_SHIFT);
+ val |= SYNQUACER_HSSPI_PCC_SENDIAN;
+
+ val &= ~(SYNQUACER_HSSPI_PCC_CDRS_MASK <<
+ SYNQUACER_HSSPI_PCC_CDRS_SHIFT);
+ val |= ((div >> 1) << SYNQUACER_HSSPI_PCC_CDRS_SHIFT);
+
+ writel(val, sspi->regs + SYNQUACER_HSSPI_REG_PCC(cs));
+
+ val = readl(sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG);
+ val &= ~(SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_MASK <<
+ SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_SHIFT);
+ val |= ((bpw / 8 - 1) << SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_SHIFT);
+ writel(val, sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG);
+
+ val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
+ val &= ~(SYNQUACER_HSSPI_DMTRP_DATA_MASK <<
+ SYNQUACER_HSSPI_DMTRP_DATA_SHIFT);
+
+ if (xfer->rx_buf)
+ val |= (SYNQUACER_HSSPI_DMTRP_DATA_RX <<
+ SYNQUACER_HSSPI_DMTRP_DATA_SHIFT);
+ else
+ val |= (SYNQUACER_HSSPI_DMTRP_DATA_TX <<
+ SYNQUACER_HSSPI_DMTRP_DATA_SHIFT);
+
+ val &= ~(3 << SYNQUACER_HSSPI_DMTRP_BUS_WIDTH_SHIFT);
+ val |= ((bus_width >> 1) << SYNQUACER_HSSPI_DMTRP_BUS_WIDTH_SHIFT);
+ writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
+
+ sspi->bpw = bpw;
+ sspi->mode = mode;
+ sspi->speed = speed;
+ sspi->cs = spi->chip_select;
+ sspi->bus_width = bus_width;
+
+ return 0;
+}
+
+static int synquacer_spi_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct synquacer_spi *sspi = spi_master_get_devdata(master);
+ int ret;
+ int status = 0;
+ u32 words;
+ u8 bpw;
+ u32 val;
+
+ val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
+ val &= ~SYNQUACER_HSSPI_DMSTOP_STOP;
+ writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
+
+ val = readl(sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG);
+ val |= SYNQUACER_HSSPI_FIFOCFG_RX_FLUSH;
+ val |= SYNQUACER_HSSPI_FIFOCFG_TX_FLUSH;
+ writel(val, sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG);
+
+ /*
+ * See if we can transfer 4-bytes as 1 word
+ * to maximize the FIFO buffer efficiency.
+ */
+ bpw = xfer->bits_per_word;
+ if (bpw == 8 && !(xfer->len % 4) && !(spi->mode & SPI_LSB_FIRST))
+ xfer->bits_per_word = 32;
+
+ ret = synquacer_spi_config(master, spi, xfer);
+
+ /* restore */
+ xfer->bits_per_word = bpw;
+
+ if (ret)
+ return ret;
+
+ reinit_completion(&sspi->transfer_done);
+
+ sspi->tx_buf = xfer->tx_buf;
+ sspi->rx_buf = xfer->rx_buf;
+
+ switch (sspi->bpw) {
+ case 8:
+ words = xfer->len;
+ break;
+ case 16:
+ words = xfer->len / 2;
+ break;
+ case 24:
+ /* fallthrough, should use 32-bits access */
+ case 32:
+ words = xfer->len / 4;
+ break;
+ default:
+ dev_err(sspi->dev, "unsupported bpw: %d\n", sspi->bpw);
+ return -EINVAL;
+ }
+
+ if (xfer->tx_buf)
+ sspi->tx_words = words;
+ else
+ sspi->tx_words = 0;
+
+ if (xfer->rx_buf)
+ sspi->rx_words = words;
+ else
+ sspi->rx_words = 0;
+
+ if (xfer->tx_buf) {
+ status = write_fifo(sspi);
+ if (status < 0) {
+ dev_err(sspi->dev, "failed write_fifo. status: 0x%x\n",
+ status);
+ return status;
+ }
+ }
+
+ if (xfer->rx_buf) {
+ val = readl(sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG);
+ val &= ~(SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_MASK <<
+ SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_SHIFT);
+ val |= ((sspi->rx_words > SYNQUACER_HSSPI_FIFO_DEPTH ?
+ SYNQUACER_HSSPI_FIFO_RX_THRESHOLD : sspi->rx_words) <<
+ SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_SHIFT);
+ writel(val, sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG);
+ }
+
+ writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_TXC);
+ writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_RXC);
+
+ /* Trigger */
+ val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
+ val |= SYNQUACER_HSSPI_DMSTART_START;
+ writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
+
+ if (xfer->tx_buf) {
+ val = SYNQUACER_HSSPI_TXE_FIFO_EMPTY;
+ writel(val, sspi->regs + SYNQUACER_HSSPI_REG_TXE);
+ status = wait_for_completion_timeout(&sspi->transfer_done,
+ msecs_to_jiffies(SYNQUACER_HSSPI_TRANSFER_TMOUT_MSEC));
+ writel(0, sspi->regs + SYNQUACER_HSSPI_REG_TXE);
+ }
+
+ if (xfer->rx_buf) {
+ u32 buf[SYNQUACER_HSSPI_FIFO_DEPTH];
+
+ val = SYNQUACER_HSSPI_RXE_FIFO_MORE_THAN_THRESHOLD |
+ SYNQUACER_HSSPI_RXE_SLAVE_RELEASED;
+ writel(val, sspi->regs + SYNQUACER_HSSPI_REG_RXE);
+ status = wait_for_completion_timeout(&sspi->transfer_done,
+ msecs_to_jiffies(SYNQUACER_HSSPI_TRANSFER_TMOUT_MSEC));
+ writel(0, sspi->regs + SYNQUACER_HSSPI_REG_RXE);
+
+ /* stop RX and clean RXFIFO */
+ val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
+ val |= SYNQUACER_HSSPI_DMSTOP_STOP;
+ writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
+ sspi->rx_buf = buf;
+ sspi->rx_words = SYNQUACER_HSSPI_FIFO_DEPTH;
+ read_fifo(sspi);
+ }
+
+ if (status < 0) {
+ dev_err(sspi->dev, "failed to transfer. status: 0x%x\n",
+ status);
+ return status;
+ }
+
+ return 0;
+}
+
+static void synquacer_spi_set_cs(struct spi_device *spi, bool enable)
+{
+ struct synquacer_spi *sspi = spi_master_get_devdata(spi->master);
+ u32 val;
+
+ val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
+ val &= ~(SYNQUACER_HSSPI_DMPSEL_CS_MASK <<
+ SYNQUACER_HSSPI_DMPSEL_CS_SHIFT);
+ val |= spi->chip_select << SYNQUACER_HSSPI_DMPSEL_CS_SHIFT;
+ writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
+}
+
+static int synquacer_spi_wait_status_update(struct synquacer_spi *sspi,
+ bool enable)
+{
+ u32 val;
+ unsigned long timeout = jiffies +
+ msecs_to_jiffies(SYNQUACER_HSSPI_ENABLE_TMOUT_MSEC);
+
+ /* wait MES(Module Enable Status) is updated */
+ do {
+ val = readl(sspi->regs + SYNQUACER_HSSPI_REG_MCTRL) &
+ SYNQUACER_HSSPI_MCTRL_MES;
+ if (enable && val)
+ return 0;
+ if (!enable && !val)
+ return 0;
+ } while (time_before(jiffies, timeout));
+
+ dev_err(sspi->dev, "timeout occurs in updating Module Enable Status\n");
+ return -EBUSY;
+}
+
+static int synquacer_spi_enable(struct spi_master *master)
+{
+ u32 val;
+ int status;
+ struct synquacer_spi *sspi = spi_master_get_devdata(master);
+
+ /* Disable module */
+ writel(0, sspi->regs + SYNQUACER_HSSPI_REG_MCTRL);
+ status = synquacer_spi_wait_status_update(sspi, false);
+ if (status < 0)
+ return status;
+
+ writel(0, sspi->regs + SYNQUACER_HSSPI_REG_TXE);
+ writel(0, sspi->regs + SYNQUACER_HSSPI_REG_RXE);
+ writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_TXC);
+ writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_RXC);
+ writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_FAULTC);
+
+ val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMCFG);
+ val &= ~SYNQUACER_HSSPI_DMCFG_SSDC;
+ val &= ~SYNQUACER_HSSPI_DMCFG_MSTARTEN;
+ writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMCFG);
+
+ val = readl(sspi->regs + SYNQUACER_HSSPI_REG_MCTRL);
+ if (sspi->clk_src_type == SYNQUACER_HSSPI_CLOCK_SRC_IPCLK)
+ val |= SYNQUACER_HSSPI_MCTRL_CDSS;
+ else
+ val &= ~SYNQUACER_HSSPI_MCTRL_CDSS;
+
+ val &= ~SYNQUACER_HSSPI_MCTRL_COMMAND_SEQUENCE_EN;
+ val |= SYNQUACER_HSSPI_MCTRL_MEN;
+ val |= SYNQUACER_HSSPI_MCTRL_SYNCON;
+
+ /* Enable module */
+ writel(val, sspi->regs + SYNQUACER_HSSPI_REG_MCTRL);
+ status = synquacer_spi_wait_status_update(sspi, true);
+ if (status < 0)
+ return status;
+
+ return 0;
+}
+
+static irqreturn_t sq_spi_rx_handler(int irq, void *priv)
+{
+ uint32_t val;
+ struct synquacer_spi *sspi = priv;
+
+ val = readl(sspi->regs + SYNQUACER_HSSPI_REG_RXF);
+ if ((val & SYNQUACER_HSSPI_RXF_SLAVE_RELEASED) ||
+ (val & SYNQUACER_HSSPI_RXF_FIFO_MORE_THAN_THRESHOLD)) {
+ read_fifo(sspi);
+
+ if (sspi->rx_words == 0) {
+ writel(0, sspi->regs + SYNQUACER_HSSPI_REG_RXE);
+ complete(&sspi->transfer_done);
+ }
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static irqreturn_t sq_spi_tx_handler(int irq, void *priv)
+{
+ uint32_t val;
+ struct synquacer_spi *sspi = priv;
+
+ val = readl(sspi->regs + SYNQUACER_HSSPI_REG_TXF);
+ if (val & SYNQUACER_HSSPI_TXF_FIFO_EMPTY) {
+ if (sspi->tx_words == 0) {
+ writel(0, sspi->regs + SYNQUACER_HSSPI_REG_TXE);
+ complete(&sspi->transfer_done);
+ } else {
+ write_fifo(sspi);
+ }
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static int synquacer_spi_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct spi_master *master;
+ struct synquacer_spi *sspi;
+ int ret;
+ int rx_irq, tx_irq;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(*sspi));
+ if (!master)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, master);
+
+ sspi = spi_master_get_devdata(master);
+ sspi->dev = &pdev->dev;
+
+ init_completion(&sspi->transfer_done);
+
+ sspi->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(sspi->regs)) {
+ ret = PTR_ERR(sspi->regs);
+ goto put_spi;
+ }
+
+ sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IHCLK; /* Default */
+ device_property_read_u32(&pdev->dev, "socionext,ihclk-rate",
+ &master->max_speed_hz); /* for ACPI */
+
+ if (dev_of_node(&pdev->dev)) {
+ if (device_property_match_string(&pdev->dev,
+ "clock-names", "iHCLK") >= 0) {
+ sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IHCLK;
+ sspi->clk = devm_clk_get(sspi->dev, "iHCLK");
+ } else if (device_property_match_string(&pdev->dev,
+ "clock-names", "iPCLK") >= 0) {
+ sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IPCLK;
+ sspi->clk = devm_clk_get(sspi->dev, "iPCLK");
+ } else {
+ dev_err(&pdev->dev, "specified wrong clock source\n");
+ ret = -EINVAL;
+ goto put_spi;
+ }
+
+ if (IS_ERR(sspi->clk)) {
+ if (!(PTR_ERR(sspi->clk) == -EPROBE_DEFER))
+ dev_err(&pdev->dev, "clock not found\n");
+ ret = PTR_ERR(sspi->clk);
+ goto put_spi;
+ }
+
+ ret = clk_prepare_enable(sspi->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable clock (%d)\n",
+ ret);
+ goto put_spi;
+ }
+
+ master->max_speed_hz = clk_get_rate(sspi->clk);
+ }
+
+ if (!master->max_speed_hz) {
+ dev_err(&pdev->dev, "missing clock source\n");
+ return -EINVAL;
+ }
+ master->min_speed_hz = master->max_speed_hz / 254;
+
+ sspi->aces = device_property_read_bool(&pdev->dev,
+ "socionext,set-aces");
+ sspi->rtm = device_property_read_bool(&pdev->dev, "socionext,use-rtm");
+
+ master->num_chipselect = SYNQUACER_HSSPI_NUM_CHIP_SELECT;
+
+ rx_irq = platform_get_irq(pdev, 0);
+ if (rx_irq <= 0) {
+ dev_err(&pdev->dev, "get rx_irq failed (%d)\n", rx_irq);
+ ret = rx_irq;
+ goto put_spi;
+ }
+ snprintf(sspi->rx_irq_name, SYNQUACER_HSSPI_IRQ_NAME_MAX, "%s-rx",
+ dev_name(&pdev->dev));
+ ret = devm_request_irq(&pdev->dev, rx_irq, sq_spi_rx_handler,
+ 0, sspi->rx_irq_name, sspi);
+ if (ret) {
+ dev_err(&pdev->dev, "request rx_irq failed (%d)\n", ret);
+ goto put_spi;
+ }
+
+ tx_irq = platform_get_irq(pdev, 1);
+ if (tx_irq <= 0) {
+ dev_err(&pdev->dev, "get tx_irq failed (%d)\n", tx_irq);
+ ret = tx_irq;
+ goto put_spi;
+ }
+ snprintf(sspi->tx_irq_name, SYNQUACER_HSSPI_IRQ_NAME_MAX, "%s-tx",
+ dev_name(&pdev->dev));
+ ret = devm_request_irq(&pdev->dev, tx_irq, sq_spi_tx_handler,
+ 0, sspi->tx_irq_name, sspi);
+ if (ret) {
+ dev_err(&pdev->dev, "request tx_irq failed (%d)\n", ret);
+ goto put_spi;
+ }
+
+ master->dev.of_node = np;
+ master->dev.fwnode = pdev->dev.fwnode;
+ master->auto_runtime_pm = true;
+ master->bus_num = pdev->id;
+
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL |
+ SPI_TX_QUAD | SPI_RX_QUAD;
+ master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(24) |
+ SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
+
+ master->set_cs = synquacer_spi_set_cs;
+ master->transfer_one = synquacer_spi_transfer_one;
+
+ ret = synquacer_spi_enable(master);
+ if (ret)
+ goto fail_enable;
+
+ pm_runtime_set_active(sspi->dev);
+ pm_runtime_enable(sspi->dev);
+
+ ret = devm_spi_register_master(sspi->dev, master);
+ if (ret)
+ goto disable_pm;
+
+ return 0;
+
+disable_pm:
+ pm_runtime_disable(sspi->dev);
+fail_enable:
+ clk_disable_unprepare(sspi->clk);
+put_spi:
+ spi_master_put(master);
+
+ return ret;
+}
+
+static int synquacer_spi_remove(struct platform_device *pdev)
+{
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct synquacer_spi *sspi = spi_master_get_devdata(master);
+
+ pm_runtime_disable(sspi->dev);
+
+ clk_disable_unprepare(sspi->clk);
+
+ return 0;
+}
+
+static int __maybe_unused synquacer_spi_suspend(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct synquacer_spi *sspi = spi_master_get_devdata(master);
+ int ret;
+
+ ret = spi_master_suspend(master);
+ if (ret)
+ return ret;
+
+ if (!pm_runtime_suspended(dev))
+ clk_disable_unprepare(sspi->clk);
+
+ return ret;
+}
+
+static int __maybe_unused synquacer_spi_resume(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct synquacer_spi *sspi = spi_master_get_devdata(master);
+ int ret;
+
+ if (!pm_runtime_suspended(dev)) {
+ /* Ensure reconfigure during next xfer */
+ sspi->speed = 0;
+
+ ret = clk_prepare_enable(sspi->clk);
+ if (ret < 0) {
+ dev_err(dev, "failed to enable clk (%d)\n",
+ ret);
+ return ret;
+ }
+
+ ret = synquacer_spi_enable(master);
+ if (ret) {
+ dev_err(dev, "failed to enable spi (%d)\n", ret);
+ return ret;
+ }
+ }
+
+ ret = spi_master_resume(master);
+ if (ret < 0)
+ clk_disable_unprepare(sspi->clk);
+
+ return ret;
+}
+
+static SIMPLE_DEV_PM_OPS(synquacer_spi_pm_ops, synquacer_spi_suspend,
+ synquacer_spi_resume);
+
+static const struct of_device_id synquacer_spi_of_match[] = {
+ {.compatible = "socionext,synquacer-spi"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, synquacer_spi_of_match);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id synquacer_hsspi_acpi_ids[] = {
+ { "SCX0004" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(acpi, synquacer_hsspi_acpi_ids);
+#endif
+
+static struct platform_driver synquacer_spi_driver = {
+ .driver = {
+ .name = "synquacer-spi",
+ .pm = &synquacer_spi_pm_ops,
+ .of_match_table = synquacer_spi_of_match,
+ .acpi_match_table = ACPI_PTR(synquacer_hsspi_acpi_ids),
+ },
+ .probe = synquacer_spi_probe,
+ .remove = synquacer_spi_remove,
+};
+module_platform_driver(synquacer_spi_driver);
+
+MODULE_DESCRIPTION("Socionext Synquacer HS-SPI controller driver");
+MODULE_AUTHOR("Masahisa Kojima <masahisa.kojima@linaro.org>");
+MODULE_AUTHOR("Jassi Brar <jaswinder.singh@linaro.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index d22f4d10413f..39374c2edcf3 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -84,8 +84,10 @@
(reg = (((val) & 0x1) << ((cs) * 8 + 5)) | \
((reg) & ~(1 << ((cs) * 8 + 5))))
#define SPI_SET_CYCLES_BETWEEN_PACKETS(reg, cs, val) \
- (reg = (((val) & 0xF) << ((cs) * 8)) | \
- ((reg) & ~(0xF << ((cs) * 8))))
+ (reg = (((val) & 0x1F) << ((cs) * 8)) | \
+ ((reg) & ~(0x1F << ((cs) * 8))))
+#define MAX_SETUP_HOLD_CYCLES 16
+#define MAX_INACTIVE_CYCLES 32
#define SPI_TRANS_STATUS 0x010
#define SPI_BLK_CNT(val) (((val) >> 0) & 0xFFFF)
@@ -156,6 +158,11 @@ struct tegra_spi_soc_data {
bool has_intr_mask_reg;
};
+struct tegra_spi_client_data {
+ int tx_clk_tap_delay;
+ int rx_clk_tap_delay;
+};
+
struct tegra_spi_data {
struct device *dev;
struct spi_master *master;
@@ -182,6 +189,7 @@ struct tegra_spi_data {
unsigned dma_buf_size;
unsigned max_buf_size;
bool is_curr_dma_xfer;
+ bool use_hw_based_cs;
struct completion rx_dma_complete;
struct completion tx_dma_complete;
@@ -194,6 +202,10 @@ struct tegra_spi_data {
u32 command1_reg;
u32 dma_control_reg;
u32 def_command1_reg;
+ u32 def_command2_reg;
+ u32 spi_cs_timing1;
+ u32 spi_cs_timing2;
+ u8 last_used_cs;
struct completion xfer_completion;
struct spi_transfer *curr_xfer;
@@ -711,14 +723,55 @@ static void tegra_spi_deinit_dma_param(struct tegra_spi_data *tspi,
dma_release_channel(dma_chan);
}
+static void tegra_spi_set_hw_cs_timing(struct spi_device *spi, u8 setup_dly,
+ u8 hold_dly, u8 inactive_dly)
+{
+ struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
+ u32 setup_hold;
+ u32 spi_cs_timing;
+ u32 inactive_cycles;
+ u8 cs_state;
+
+ setup_dly = min_t(u8, setup_dly, MAX_SETUP_HOLD_CYCLES);
+ hold_dly = min_t(u8, hold_dly, 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,
+ spi->chip_select,
+ setup_hold);
+ if (tspi->spi_cs_timing1 != spi_cs_timing) {
+ tspi->spi_cs_timing1 = spi_cs_timing;
+ tegra_spi_writel(tspi, spi_cs_timing, SPI_CS_TIMING1);
+ }
+ }
+
+ inactive_cycles = min_t(u8, inactive_dly, MAX_INACTIVE_CYCLES);
+ if (inactive_cycles)
+ inactive_cycles--;
+ cs_state = inactive_cycles ? 0 : 1;
+ spi_cs_timing = tspi->spi_cs_timing2;
+ SPI_SET_CS_ACTIVE_BETWEEN_PACKETS(spi_cs_timing, spi->chip_select,
+ cs_state);
+ SPI_SET_CYCLES_BETWEEN_PACKETS(spi_cs_timing, spi->chip_select,
+ inactive_cycles);
+ if (tspi->spi_cs_timing2 != spi_cs_timing) {
+ tspi->spi_cs_timing2 = spi_cs_timing;
+ tegra_spi_writel(tspi, spi_cs_timing, SPI_CS_TIMING2);
+ }
+}
+
static u32 tegra_spi_setup_transfer_one(struct spi_device *spi,
- struct spi_transfer *t, bool is_first_of_msg)
+ struct spi_transfer *t,
+ bool is_first_of_msg,
+ bool is_single_xfer)
{
struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
+ struct tegra_spi_client_data *cdata = spi->controller_data;
u32 speed = t->speed_hz;
u8 bits_per_word = t->bits_per_word;
- u32 command1;
+ u32 command1, command2;
int req_mode;
+ u32 tx_tap = 0, rx_tap = 0;
if (speed != tspi->cur_speed) {
clk_set_rate(tspi->clk, speed);
@@ -765,13 +818,34 @@ static u32 tegra_spi_setup_transfer_one(struct spi_device *spi,
} else
tegra_spi_writel(tspi, command1, SPI_COMMAND1);
- command1 |= SPI_CS_SW_HW;
- if (spi->mode & SPI_CS_HIGH)
- command1 |= SPI_CS_SW_VAL;
- else
- command1 &= ~SPI_CS_SW_VAL;
+ /* GPIO based chip select control */
+ if (spi->cs_gpiod)
+ gpiod_set_value(spi->cs_gpiod, 1);
+
+ if (is_single_xfer && !(t->cs_change)) {
+ tspi->use_hw_based_cs = true;
+ command1 &= ~(SPI_CS_SW_HW | SPI_CS_SW_VAL);
+ } else {
+ tspi->use_hw_based_cs = false;
+ command1 |= SPI_CS_SW_HW;
+ if (spi->mode & SPI_CS_HIGH)
+ command1 |= SPI_CS_SW_VAL;
+ else
+ command1 &= ~SPI_CS_SW_VAL;
+ }
+
+ if (tspi->last_used_cs != spi->chip_select) {
+ if (cdata && cdata->tx_clk_tap_delay)
+ tx_tap = cdata->tx_clk_tap_delay;
+ if (cdata && cdata->rx_clk_tap_delay)
+ rx_tap = cdata->rx_clk_tap_delay;
+ command2 = SPI_TX_TAP_DELAY(tx_tap) |
+ SPI_RX_TAP_DELAY(rx_tap);
+ if (command2 != tspi->def_command2_reg)
+ tegra_spi_writel(tspi, command2, SPI_COMMAND2);
+ tspi->last_used_cs = spi->chip_select;
+ }
- tegra_spi_writel(tspi, 0, SPI_COMMAND2);
} else {
command1 = tspi->command1_reg;
command1 &= ~SPI_BIT_LENGTH(~0);
@@ -827,9 +901,42 @@ static int tegra_spi_start_transfer_one(struct spi_device *spi,
return ret;
}
+static struct tegra_spi_client_data
+ *tegra_spi_parse_cdata_dt(struct spi_device *spi)
+{
+ struct tegra_spi_client_data *cdata;
+ struct device_node *slave_np;
+
+ slave_np = spi->dev.of_node;
+ if (!slave_np) {
+ dev_dbg(&spi->dev, "device node not found\n");
+ return NULL;
+ }
+
+ cdata = kzalloc(sizeof(*cdata), GFP_KERNEL);
+ if (!cdata)
+ return NULL;
+
+ of_property_read_u32(slave_np, "nvidia,tx-clk-tap-delay",
+ &cdata->tx_clk_tap_delay);
+ of_property_read_u32(slave_np, "nvidia,rx-clk-tap-delay",
+ &cdata->rx_clk_tap_delay);
+ return cdata;
+}
+
+static void tegra_spi_cleanup(struct spi_device *spi)
+{
+ struct tegra_spi_client_data *cdata = spi->controller_data;
+
+ spi->controller_data = NULL;
+ if (spi->dev.of_node)
+ kfree(cdata);
+}
+
static int tegra_spi_setup(struct spi_device *spi)
{
struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
+ struct tegra_spi_client_data *cdata = spi->controller_data;
u32 val;
unsigned long flags;
int ret;
@@ -840,9 +947,16 @@ static int tegra_spi_setup(struct spi_device *spi)
spi->mode & SPI_CPHA ? "" : "~",
spi->max_speed_hz);
+ if (!cdata) {
+ cdata = tegra_spi_parse_cdata_dt(spi);
+ spi->controller_data = cdata;
+ }
+
ret = pm_runtime_get_sync(tspi->dev);
if (ret < 0) {
dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret);
+ if (cdata)
+ tegra_spi_cleanup(spi);
return ret;
}
@@ -853,6 +967,10 @@ static int tegra_spi_setup(struct spi_device *spi)
}
spin_lock_irqsave(&tspi->lock, flags);
+ /* GPIO based chip select control */
+ if (spi->cs_gpiod)
+ gpiod_set_value(spi->cs_gpiod, 0);
+
val = tspi->def_command1_reg;
if (spi->mode & SPI_CS_HIGH)
val &= ~SPI_CS_POL_INACTIVE(spi->chip_select);
@@ -882,11 +1000,18 @@ static void tegra_spi_transfer_end(struct spi_device *spi)
struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
int cs_val = (spi->mode & SPI_CS_HIGH) ? 0 : 1;
- if (cs_val)
- tspi->command1_reg |= SPI_CS_SW_VAL;
- else
- tspi->command1_reg &= ~SPI_CS_SW_VAL;
- tegra_spi_writel(tspi, tspi->command1_reg, SPI_COMMAND1);
+ /* GPIO based chip select control */
+ if (spi->cs_gpiod)
+ gpiod_set_value(spi->cs_gpiod, 0);
+
+ if (!tspi->use_hw_based_cs) {
+ if (cs_val)
+ tspi->command1_reg |= SPI_CS_SW_VAL;
+ else
+ tspi->command1_reg &= ~SPI_CS_SW_VAL;
+ tegra_spi_writel(tspi, tspi->command1_reg, SPI_COMMAND1);
+ }
+
tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1);
}
@@ -913,16 +1038,19 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
struct spi_device *spi = msg->spi;
int ret;
bool skip = false;
+ int single_xfer;
msg->status = 0;
msg->actual_length = 0;
+ single_xfer = list_is_singular(&msg->transfers);
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
u32 cmd1;
reinit_completion(&tspi->xfer_completion);
- cmd1 = tegra_spi_setup_transfer_one(spi, xfer, is_first_msg);
+ cmd1 = tegra_spi_setup_transfer_one(spi, xfer, is_first_msg,
+ single_xfer);
if (!xfer->len) {
ret = 0;
@@ -955,6 +1083,7 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
reset_control_assert(tspi->rst);
udelay(2);
reset_control_deassert(tspi->rst);
+ tspi->last_used_cs = master->num_chipselect + 1;
goto complete_xfer;
}
@@ -1188,11 +1317,14 @@ static int tegra_spi_probe(struct platform_device *pdev)
master->max_speed_hz = 25000000; /* 25MHz */
/* the spi->mode bits understood by this driver: */
+ master->use_gpio_descriptors = true;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST |
SPI_TX_DUAL | SPI_RX_DUAL | SPI_3WIRE;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
master->setup = tegra_spi_setup;
+ master->cleanup = tegra_spi_cleanup;
master->transfer_one_message = tegra_spi_transfer_one_message;
+ master->set_cs_timing = tegra_spi_set_hw_cs_timing;
master->num_chipselect = MAX_CHIP_SELECT;
master->auto_runtime_pm = true;
bus_num = of_alias_get_id(pdev->dev.of_node, "spi");
@@ -1268,6 +1400,10 @@ static int tegra_spi_probe(struct platform_device *pdev)
reset_control_deassert(tspi->rst);
tspi->def_command1_reg = SPI_M_S;
tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1);
+ tspi->spi_cs_timing1 = tegra_spi_readl(tspi, SPI_CS_TIMING1);
+ tspi->spi_cs_timing2 = tegra_spi_readl(tspi, SPI_CS_TIMING2);
+ tspi->def_command2_reg = tegra_spi_readl(tspi, SPI_COMMAND2);
+ tspi->last_used_cs = master->num_chipselect + 1;
pm_runtime_put(&pdev->dev);
ret = request_threaded_irq(tspi->irq, tegra_spi_isr,
tegra_spi_isr_thread, IRQF_ONESHOT,
@@ -1340,6 +1476,8 @@ static int tegra_spi_resume(struct device *dev)
return ret;
}
tegra_spi_writel(tspi, tspi->command1_reg, SPI_COMMAND1);
+ tegra_spi_writel(tspi, tspi->def_command2_reg, SPI_COMMAND2);
+ tspi->last_used_cs = master->num_chipselect + 1;
pm_runtime_put(dev);
return spi_master_resume(master);
diff --git a/drivers/spi/spi-tle62x0.c b/drivers/spi/spi-tle62x0.c
index c6ae775289e5..60dc69a39ace 100644
--- a/drivers/spi/spi-tle62x0.c
+++ b/drivers/spi/spi-tle62x0.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Support Infineon TLE62x0 driver chips
*
* Copyright (c) 2007 Simtec Electronics
* Ben Dooks, <ben@simtec.co.uk>
- *
- * 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.
*/
#include <linux/device.h>
diff --git a/drivers/spi/spi-uniphier.c b/drivers/spi/spi-uniphier.c
index 5a6137fe172d..b32c77df5d49 100644
--- a/drivers/spi/spi-uniphier.c
+++ b/drivers/spi/spi-uniphier.c
@@ -328,7 +328,12 @@ static int uniphier_spi_transfer_one(struct spi_master *master,
struct spi_transfer *t)
{
struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
- int status;
+ struct device *dev = master->dev.parent;
+ unsigned long time_left;
+
+ /* Terminate and return success for 0 byte length transfer */
+ if (!t->len)
+ return 0;
uniphier_spi_setup_transfer(spi, t);
@@ -338,13 +343,15 @@ static int uniphier_spi_transfer_one(struct spi_master *master,
uniphier_spi_irq_enable(spi, SSI_IE_RCIE | SSI_IE_RORIE);
- status = wait_for_completion_timeout(&priv->xfer_done,
- msecs_to_jiffies(SSI_TIMEOUT_MS));
+ time_left = wait_for_completion_timeout(&priv->xfer_done,
+ msecs_to_jiffies(SSI_TIMEOUT_MS));
uniphier_spi_irq_disable(spi, SSI_IE_RCIE | SSI_IE_RORIE);
- if (status < 0)
- return status;
+ if (!time_left) {
+ dev_err(dev, "transfer timeout.\n");
+ return -ETIMEDOUT;
+ }
return priv->error;
}
diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c
index 63fedc49ae9c..d5f9d5fbb3e8 100644
--- a/drivers/spi/spi-xilinx.c
+++ b/drivers/spi/spi-xilinx.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Xilinx SPI controller driver (master mode only)
*
@@ -8,9 +9,6 @@
* Copyright (c) 2009 Intel Corporation
* 2002-2007 (c) MontaVista Software, 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.
*/
#include <linux/module.h>
diff --git a/drivers/spi/spi-xlp.c b/drivers/spi/spi-xlp.c
index 74a01b09a8a5..1dc479fab98c 100644
--- a/drivers/spi/spi-xlp.c
+++ b/drivers/spi/spi-xlp.c
@@ -1,15 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2003-2015 Broadcom Corporation
* All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 (GPL v2)
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/acpi.h>
#include <linux/clk.h>
diff --git a/drivers/spi/spi-xtensa-xtfpga.c b/drivers/spi/spi-xtensa-xtfpga.c
index 8ce04f829a80..86516eb1e143 100644
--- a/drivers/spi/spi-xtensa-xtfpga.c
+++ b/drivers/spi/spi-xtensa-xtfpga.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Xtensa xtfpga SPI controller driver
*
* Copyright (c) 2014 Cadence Design Systems 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.
*/
#include <linux/delay.h>
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 5e4654032bfa..75ac046cae52 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -1090,6 +1090,60 @@ static int spi_transfer_wait(struct spi_controller *ctlr,
return 0;
}
+static void _spi_transfer_delay_ns(u32 ns)
+{
+ if (!ns)
+ return;
+ if (ns <= 1000) {
+ ndelay(ns);
+ } else {
+ u32 us = DIV_ROUND_UP(ns, 1000);
+
+ if (us <= 10)
+ udelay(us);
+ else
+ usleep_range(us, us + DIV_ROUND_UP(us, 10));
+ }
+}
+
+static void _spi_transfer_cs_change_delay(struct spi_message *msg,
+ struct spi_transfer *xfer)
+{
+ u32 delay = xfer->cs_change_delay;
+ u32 unit = xfer->cs_change_delay_unit;
+ u32 hz;
+
+ /* return early on "fast" mode - for everything but USECS */
+ if (!delay && unit != SPI_DELAY_UNIT_USECS)
+ return;
+
+ switch (unit) {
+ case SPI_DELAY_UNIT_USECS:
+ /* for compatibility use default of 10us */
+ if (!delay)
+ delay = 10000;
+ else
+ delay *= 1000;
+ break;
+ case SPI_DELAY_UNIT_NSECS: /* nothing to do here */
+ break;
+ case SPI_DELAY_UNIT_SCK:
+ /* if there is no effective speed know, then approximate
+ * by underestimating with half the requested hz
+ */
+ hz = xfer->effective_speed_hz ?: xfer->speed_hz / 2;
+ delay *= DIV_ROUND_UP(1000000000, hz);
+ break;
+ default:
+ dev_err_once(&msg->spi->dev,
+ "Use of unsupported delay unit %i, using default of 10us\n",
+ xfer->cs_change_delay_unit);
+ delay = 10000;
+ }
+ /* now sleep for the requested amount of time */
+ _spi_transfer_delay_ns(delay);
+}
+
/*
* spi_transfer_one_message - Default implementation of transfer_one_message()
*
@@ -1148,14 +1202,8 @@ static int spi_transfer_one_message(struct spi_controller *ctlr,
if (msg->status != -EINPROGRESS)
goto out;
- if (xfer->delay_usecs) {
- u16 us = xfer->delay_usecs;
-
- if (us <= 10)
- udelay(us);
- else
- usleep_range(us, us + DIV_ROUND_UP(us, 10));
- }
+ if (xfer->delay_usecs)
+ _spi_transfer_delay_ns(xfer->delay_usecs * 1000);
if (xfer->cs_change) {
if (list_is_last(&xfer->transfer_list,
@@ -1163,7 +1211,7 @@ static int spi_transfer_one_message(struct spi_controller *ctlr,
keep_cs = true;
} else {
spi_set_cs(msg->spi, false);
- udelay(10);
+ _spi_transfer_cs_change_delay(msg, xfer);
spi_set_cs(msg->spi, true);
}
}
@@ -1369,10 +1417,32 @@ static void spi_pump_messages(struct kthread_work *work)
__spi_pump_messages(ctlr, true);
}
-static int spi_init_queue(struct spi_controller *ctlr)
+/**
+ * spi_set_thread_rt - set the controller to pump at realtime priority
+ * @ctlr: controller to boost priority of
+ *
+ * This can be called because the controller requested realtime priority
+ * (by setting the ->rt value before calling spi_register_controller()) or
+ * because a device on the bus said that its transfers needed realtime
+ * priority.
+ *
+ * NOTE: at the moment if any device on a bus says it needs realtime then
+ * the thread will be at realtime priority for all transfers on that
+ * controller. If this eventually becomes a problem we may see if we can
+ * find a way to boost the priority only temporarily during relevant
+ * transfers.
+ */
+static void spi_set_thread_rt(struct spi_controller *ctlr)
{
struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
+ dev_info(&ctlr->dev,
+ "will run message pump with realtime priority\n");
+ sched_setscheduler(ctlr->kworker_task, SCHED_FIFO, &param);
+}
+
+static int spi_init_queue(struct spi_controller *ctlr)
+{
ctlr->running = false;
ctlr->busy = false;
@@ -1392,11 +1462,8 @@ static int spi_init_queue(struct spi_controller *ctlr)
* request and the scheduling of the message pump thread. Without this
* setting the message pump thread will remain at default priority.
*/
- if (ctlr->rt) {
- dev_info(&ctlr->dev,
- "will run message pump with realtime priority\n");
- sched_setscheduler(ctlr->kworker_task, SCHED_FIFO, &param);
- }
+ if (ctlr->rt)
+ spi_set_thread_rt(ctlr);
return 0;
}
@@ -1804,9 +1871,18 @@ static void of_register_spi_devices(struct spi_controller *ctlr) { }
#endif
#ifdef CONFIG_ACPI
-static void acpi_spi_parse_apple_properties(struct spi_device *spi)
+struct acpi_spi_lookup {
+ struct spi_controller *ctlr;
+ u32 max_speed_hz;
+ u32 mode;
+ int irq;
+ u8 bits_per_word;
+ u8 chip_select;
+};
+
+static void acpi_spi_parse_apple_properties(struct acpi_device *dev,
+ struct acpi_spi_lookup *lookup)
{
- struct acpi_device *dev = ACPI_COMPANION(&spi->dev);
const union acpi_object *obj;
if (!x86_apple_machine)
@@ -1814,35 +1890,46 @@ static void acpi_spi_parse_apple_properties(struct spi_device *spi)
if (!acpi_dev_get_property(dev, "spiSclkPeriod", ACPI_TYPE_BUFFER, &obj)
&& obj->buffer.length >= 4)
- spi->max_speed_hz = NSEC_PER_SEC / *(u32 *)obj->buffer.pointer;
+ lookup->max_speed_hz = NSEC_PER_SEC / *(u32 *)obj->buffer.pointer;
if (!acpi_dev_get_property(dev, "spiWordSize", ACPI_TYPE_BUFFER, &obj)
&& obj->buffer.length == 8)
- spi->bits_per_word = *(u64 *)obj->buffer.pointer;
+ lookup->bits_per_word = *(u64 *)obj->buffer.pointer;
if (!acpi_dev_get_property(dev, "spiBitOrder", ACPI_TYPE_BUFFER, &obj)
&& obj->buffer.length == 8 && !*(u64 *)obj->buffer.pointer)
- spi->mode |= SPI_LSB_FIRST;
+ lookup->mode |= SPI_LSB_FIRST;
if (!acpi_dev_get_property(dev, "spiSPO", ACPI_TYPE_BUFFER, &obj)
&& obj->buffer.length == 8 && *(u64 *)obj->buffer.pointer)
- spi->mode |= SPI_CPOL;
+ lookup->mode |= SPI_CPOL;
if (!acpi_dev_get_property(dev, "spiSPH", ACPI_TYPE_BUFFER, &obj)
&& obj->buffer.length == 8 && *(u64 *)obj->buffer.pointer)
- spi->mode |= SPI_CPHA;
+ lookup->mode |= SPI_CPHA;
}
static int acpi_spi_add_resource(struct acpi_resource *ares, void *data)
{
- struct spi_device *spi = data;
- struct spi_controller *ctlr = spi->controller;
+ struct acpi_spi_lookup *lookup = data;
+ struct spi_controller *ctlr = lookup->ctlr;
if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {
struct acpi_resource_spi_serialbus *sb;
+ acpi_handle parent_handle;
+ acpi_status status;
sb = &ares->data.spi_serial_bus;
if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_SPI) {
+
+ status = acpi_get_handle(NULL,
+ sb->resource_source.string_ptr,
+ &parent_handle);
+
+ if (ACPI_FAILURE(status) ||
+ ACPI_HANDLE(ctlr->dev.parent) != parent_handle)
+ return -ENODEV;
+
/*
* ACPI DeviceSelection numbering is handled by the
* host controller driver in Windows and can vary
@@ -1855,25 +1942,25 @@ static int acpi_spi_add_resource(struct acpi_resource *ares, void *data)
sb->device_selection);
if (cs < 0)
return cs;
- spi->chip_select = cs;
+ lookup->chip_select = cs;
} else {
- spi->chip_select = sb->device_selection;
+ lookup->chip_select = sb->device_selection;
}
- spi->max_speed_hz = sb->connection_speed;
+ lookup->max_speed_hz = sb->connection_speed;
if (sb->clock_phase == ACPI_SPI_SECOND_PHASE)
- spi->mode |= SPI_CPHA;
+ lookup->mode |= SPI_CPHA;
if (sb->clock_polarity == ACPI_SPI_START_HIGH)
- spi->mode |= SPI_CPOL;
+ lookup->mode |= SPI_CPOL;
if (sb->device_polarity == ACPI_SPI_ACTIVE_HIGH)
- spi->mode |= SPI_CS_HIGH;
+ lookup->mode |= SPI_CS_HIGH;
}
- } else if (spi->irq < 0) {
+ } else if (lookup->irq < 0) {
struct resource r;
if (acpi_dev_resource_interrupt(ares, 0, &r))
- spi->irq = r.start;
+ lookup->irq = r.start;
}
/* Always tell the ACPI core to skip this resource */
@@ -1883,7 +1970,9 @@ static int acpi_spi_add_resource(struct acpi_resource *ares, void *data)
static acpi_status acpi_register_spi_device(struct spi_controller *ctlr,
struct acpi_device *adev)
{
+ acpi_handle parent_handle = NULL;
struct list_head resource_list;
+ struct acpi_spi_lookup lookup = {};
struct spi_device *spi;
int ret;
@@ -1891,28 +1980,42 @@ static acpi_status acpi_register_spi_device(struct spi_controller *ctlr,
acpi_device_enumerated(adev))
return AE_OK;
- spi = spi_alloc_device(ctlr);
- if (!spi) {
- dev_err(&ctlr->dev, "failed to allocate SPI device for %s\n",
- dev_name(&adev->dev));
- return AE_NO_MEMORY;
- }
-
- ACPI_COMPANION_SET(&spi->dev, adev);
- spi->irq = -1;
+ lookup.ctlr = ctlr;
+ lookup.irq = -1;
INIT_LIST_HEAD(&resource_list);
ret = acpi_dev_get_resources(adev, &resource_list,
- acpi_spi_add_resource, spi);
+ acpi_spi_add_resource, &lookup);
acpi_dev_free_resource_list(&resource_list);
- acpi_spi_parse_apple_properties(spi);
+ if (ret < 0)
+ /* found SPI in _CRS but it points to another controller */
+ return AE_OK;
- if (ret < 0 || !spi->max_speed_hz) {
- spi_dev_put(spi);
+ if (!lookup.max_speed_hz &&
+ !ACPI_FAILURE(acpi_get_parent(adev->handle, &parent_handle)) &&
+ ACPI_HANDLE(ctlr->dev.parent) == parent_handle) {
+ /* Apple does not use _CRS but nested devices for SPI slaves */
+ acpi_spi_parse_apple_properties(adev, &lookup);
+ }
+
+ if (!lookup.max_speed_hz)
return AE_OK;
+
+ spi = spi_alloc_device(ctlr);
+ if (!spi) {
+ dev_err(&ctlr->dev, "failed to allocate SPI device for %s\n",
+ dev_name(&adev->dev));
+ return AE_NO_MEMORY;
}
+ ACPI_COMPANION_SET(&spi->dev, adev);
+ spi->max_speed_hz = lookup.max_speed_hz;
+ spi->mode = lookup.mode;
+ spi->irq = lookup.irq;
+ spi->bits_per_word = lookup.bits_per_word;
+ spi->chip_select = lookup.chip_select;
+
acpi_set_modalias(adev, acpi_device_hid(adev), spi->modalias,
sizeof(spi->modalias));
@@ -1944,6 +2047,8 @@ static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level,
return acpi_register_spi_device(ctlr, adev);
}
+#define SPI_ACPI_ENUMERATE_MAX_DEPTH 32
+
static void acpi_register_spi_devices(struct spi_controller *ctlr)
{
acpi_status status;
@@ -1953,7 +2058,8 @@ static void acpi_register_spi_devices(struct spi_controller *ctlr)
if (!handle)
return;
- status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+ SPI_ACPI_ENUMERATE_MAX_DEPTH,
acpi_spi_add_device, NULL, ctlr, NULL);
if (ACPI_FAILURE(status))
dev_warn(&ctlr->dev, "failed to enumerate SPI slaves\n");
@@ -2286,11 +2392,6 @@ int spi_register_controller(struct spi_controller *ctlr)
if (status)
return status;
- /* even if it's just one always-selected device, there must
- * be at least one chipselect
- */
- if (ctlr->num_chipselect == 0)
- return -EINVAL;
if (ctlr->bus_num >= 0) {
/* devices with a fixed bus num must check-in with the num */
mutex_lock(&board_lock);
@@ -2361,6 +2462,13 @@ int spi_register_controller(struct spi_controller *ctlr)
}
}
+ /*
+ * Even if it's just one always-selected device, there must
+ * be at least one chipselect.
+ */
+ if (!ctlr->num_chipselect)
+ return -EINVAL;
+
status = device_add(&ctlr->dev);
if (status < 0) {
/* free bus id */
@@ -2470,7 +2578,6 @@ void spi_unregister_controller(struct spi_controller *ctlr)
{
struct spi_controller *found;
int id = ctlr->bus_num;
- int dummy;
/* First make sure that this controller was ever added */
mutex_lock(&board_lock);
@@ -2484,7 +2591,7 @@ void spi_unregister_controller(struct spi_controller *ctlr)
list_del(&ctlr->list);
mutex_unlock(&board_lock);
- dummy = device_for_each_child(&ctlr->dev, NULL, __unregister);
+ device_for_each_child(&ctlr->dev, NULL, __unregister);
device_unregister(&ctlr->dev);
/* free bus id */
mutex_lock(&board_lock);
@@ -2633,12 +2740,9 @@ EXPORT_SYMBOL_GPL(spi_res_add);
*/
void spi_res_release(struct spi_controller *ctlr, struct spi_message *message)
{
- struct spi_res *res;
-
- while (!list_empty(&message->resources)) {
- res = list_last_entry(&message->resources,
- struct spi_res, entry);
+ struct spi_res *res, *tmp;
+ list_for_each_entry_safe_reverse(res, tmp, &message->resources, entry) {
if (res->release)
res->release(ctlr, message, res->data);
@@ -2702,8 +2806,7 @@ struct spi_replaced_transfers *spi_replace_transfers(
/* allocate the structure using spi_res */
rxfer = spi_res_alloc(msg->spi, __spi_replace_transfers_release,
- insert * sizeof(struct spi_transfer)
- + sizeof(struct spi_replaced_transfers)
+ struct_size(rxfer, inserted_transfers, insert)
+ extradatasize,
gfp);
if (!rxfer)
@@ -2987,6 +3090,11 @@ int spi_setup(struct spi_device *spi)
spi_set_cs(spi, false);
+ if (spi->rt && !spi->controller->rt) {
+ spi->controller->rt = true;
+ spi_set_thread_rt(spi->controller);
+ }
+
dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s%u bits/w, %u Hz max --> %d\n",
(int) (spi->mode & (SPI_CPOL | SPI_CPHA)),
(spi->mode & SPI_CS_HIGH) ? "cs_high, " : "",
@@ -3083,6 +3191,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
*/
message->frame_length = 0;
list_for_each_entry(xfer, &message->transfers, transfer_list) {
+ xfer->effective_speed_hz = 0;
message->frame_length += xfer->len;
if (!xfer->bits_per_word)
xfer->bits_per_word = spi->bits_per_word;
@@ -3543,7 +3652,7 @@ EXPORT_SYMBOL_GPL(spi_write_then_read);
/*-------------------------------------------------------------------------*/
#if IS_ENABLED(CONFIG_OF)
-static int __spi_of_device_match(struct device *dev, void *data)
+static int __spi_of_device_match(struct device *dev, const void *data)
{
return dev->of_node == data;
}
@@ -3644,7 +3753,7 @@ static int spi_acpi_controller_match(struct device *dev, const void *data)
return ACPI_COMPANION(dev->parent) == data;
}
-static int spi_acpi_device_match(struct device *dev, void *data)
+static int spi_acpi_device_match(struct device *dev, const void *data)
{
return ACPI_COMPANION(dev) == data;
}
@@ -3762,4 +3871,3 @@ err0:
* include needing to have boardinfo data structures be much more public.
*/
postcore_initcall(spi_init);
-
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index 422bac8cc3e0..255786f2e844 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -663,6 +663,8 @@ static const struct of_device_id spidev_dt_ids[] = {
{ .compatible = "ge,achc" },
{ .compatible = "semtech,sx1301" },
{ .compatible = "lwn,bk4" },
+ { .compatible = "dh,dhcom-board" },
+ { .compatible = "menlo,m53cpld" },
{},
};
MODULE_DEVICE_TABLE(of, spidev_dt_ids);
diff --git a/drivers/ssb/driver_gpio.c b/drivers/ssb/driver_gpio.c
index e809dae4c470..66a76fd83248 100644
--- a/drivers/ssb/driver_gpio.c
+++ b/drivers/ssb/driver_gpio.c
@@ -460,9 +460,6 @@ int ssb_gpio_init(struct ssb_bus *bus)
return ssb_gpio_chipco_init(bus);
else if (ssb_extif_available(&bus->extif))
return ssb_gpio_extif_init(bus);
- else
- WARN_ON(1);
-
return -1;
}
@@ -472,9 +469,6 @@ int ssb_gpio_unregister(struct ssb_bus *bus)
ssb_extif_available(&bus->extif)) {
gpiochip_remove(&bus->gpio);
return 0;
- } else {
- WARN_ON(1);
}
-
return -1;
}
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index d5f771fafc21..7c96a01eef6c 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -118,4 +118,6 @@ source "drivers/staging/fieldbus/Kconfig"
source "drivers/staging/kpc2000/Kconfig"
+source "drivers/staging/isdn/Kconfig"
+
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 0da0d3f0b5e4..fcaac9693b83 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -49,3 +49,4 @@ obj-$(CONFIG_XIL_AXIS_FIFO) += axis-fifo/
obj-$(CONFIG_EROFS_FS) += erofs/
obj-$(CONFIG_FIELDBUS_DEV) += fieldbus/
obj-$(CONFIG_KPC2000) += kpc2000/
+obj-$(CONFIG_ISDN_CAPI) += isdn/
diff --git a/drivers/staging/android/ion/Kconfig b/drivers/staging/android/ion/Kconfig
index 178df581a8fc..989fe84a9f9d 100644
--- a/drivers/staging/android/ion/Kconfig
+++ b/drivers/staging/android/ion/Kconfig
@@ -18,24 +18,6 @@ config ION_SYSTEM_HEAP
Choose this option to enable the Ion system heap. The system heap
is backed by pages from the buddy allocator. If in doubt, say Y.
-config ION_CARVEOUT_HEAP
- bool "Ion carveout heap support"
- depends on ION
- help
- Choose this option to enable carveout heaps with Ion. Carveout heaps
- are backed by memory reserved from the system. Allocation times are
- typically faster at the cost of memory not being used. Unless you
- know your system has these regions, you should say N here.
-
-config ION_CHUNK_HEAP
- bool "Ion chunk heap support"
- depends on ION
- help
- Choose this option to enable chunk heaps with Ion. This heap is
- similar in function the carveout heap but memory is broken down
- into smaller chunk sizes, typically corresponding to a TLB size.
- Unless you know your system has these regions, you should say N here.
-
config ION_CMA_HEAP
bool "Ion CMA heap support"
depends on ION && DMA_CMA
diff --git a/drivers/staging/android/ion/Makefile b/drivers/staging/android/ion/Makefile
index 17f3a7569e3d..5f4487b1a224 100644
--- a/drivers/staging/android/ion/Makefile
+++ b/drivers/staging/android/ion/Makefile
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_ION) += ion.o ion_heap.o
obj-$(CONFIG_ION_SYSTEM_HEAP) += ion_system_heap.o ion_page_pool.o
-obj-$(CONFIG_ION_CARVEOUT_HEAP) += ion_carveout_heap.o
-obj-$(CONFIG_ION_CHUNK_HEAP) += ion_chunk_heap.o
obj-$(CONFIG_ION_CMA_HEAP) += ion_cma_heap.o
diff --git a/drivers/staging/android/ion/ion_carveout_heap.c b/drivers/staging/android/ion/ion_carveout_heap.c
deleted file mode 100644
index bb9d614767a2..000000000000
--- a/drivers/staging/android/ion/ion_carveout_heap.c
+++ /dev/null
@@ -1,133 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * ION Memory Allocator carveout heap helper
- *
- * Copyright (C) 2011 Google, Inc.
- */
-
-#include <linux/dma-mapping.h>
-#include <linux/err.h>
-#include <linux/genalloc.h>
-#include <linux/io.h>
-#include <linux/mm.h>
-#include <linux/scatterlist.h>
-#include <linux/slab.h>
-
-#include "ion.h"
-
-#define ION_CARVEOUT_ALLOCATE_FAIL -1
-
-struct ion_carveout_heap {
- struct ion_heap heap;
- struct gen_pool *pool;
-};
-
-static phys_addr_t ion_carveout_allocate(struct ion_heap *heap,
- unsigned long size)
-{
- struct ion_carveout_heap *carveout_heap =
- container_of(heap, struct ion_carveout_heap, heap);
- unsigned long offset = gen_pool_alloc(carveout_heap->pool, size);
-
- if (!offset)
- return ION_CARVEOUT_ALLOCATE_FAIL;
-
- return offset;
-}
-
-static void ion_carveout_free(struct ion_heap *heap, phys_addr_t addr,
- unsigned long size)
-{
- struct ion_carveout_heap *carveout_heap =
- container_of(heap, struct ion_carveout_heap, heap);
-
- if (addr == ION_CARVEOUT_ALLOCATE_FAIL)
- return;
-
- gen_pool_free(carveout_heap->pool, addr, size);
-}
-
-static int ion_carveout_heap_allocate(struct ion_heap *heap,
- struct ion_buffer *buffer,
- unsigned long size,
- unsigned long flags)
-{
- struct sg_table *table;
- phys_addr_t paddr;
- int ret;
-
- table = kmalloc(sizeof(*table), GFP_KERNEL);
- if (!table)
- return -ENOMEM;
- ret = sg_alloc_table(table, 1, GFP_KERNEL);
- if (ret)
- goto err_free;
-
- paddr = ion_carveout_allocate(heap, size);
- if (paddr == ION_CARVEOUT_ALLOCATE_FAIL) {
- ret = -ENOMEM;
- goto err_free_table;
- }
-
- sg_set_page(table->sgl, pfn_to_page(PFN_DOWN(paddr)), size, 0);
- buffer->sg_table = table;
-
- return 0;
-
-err_free_table:
- sg_free_table(table);
-err_free:
- kfree(table);
- return ret;
-}
-
-static void ion_carveout_heap_free(struct ion_buffer *buffer)
-{
- struct ion_heap *heap = buffer->heap;
- struct sg_table *table = buffer->sg_table;
- struct page *page = sg_page(table->sgl);
- phys_addr_t paddr = PFN_PHYS(page_to_pfn(page));
-
- ion_heap_buffer_zero(buffer);
-
- ion_carveout_free(heap, paddr, buffer->size);
- sg_free_table(table);
- kfree(table);
-}
-
-static struct ion_heap_ops carveout_heap_ops = {
- .allocate = ion_carveout_heap_allocate,
- .free = ion_carveout_heap_free,
- .map_user = ion_heap_map_user,
- .map_kernel = ion_heap_map_kernel,
- .unmap_kernel = ion_heap_unmap_kernel,
-};
-
-struct ion_heap *ion_carveout_heap_create(phys_addr_t base, size_t size)
-{
- struct ion_carveout_heap *carveout_heap;
- int ret;
-
- struct page *page;
-
- page = pfn_to_page(PFN_DOWN(base));
- ret = ion_heap_pages_zero(page, size, pgprot_writecombine(PAGE_KERNEL));
- if (ret)
- return ERR_PTR(ret);
-
- carveout_heap = kzalloc(sizeof(*carveout_heap), GFP_KERNEL);
- if (!carveout_heap)
- return ERR_PTR(-ENOMEM);
-
- carveout_heap->pool = gen_pool_create(PAGE_SHIFT, -1);
- if (!carveout_heap->pool) {
- kfree(carveout_heap);
- return ERR_PTR(-ENOMEM);
- }
- gen_pool_add(carveout_heap->pool, base, size, -1);
- carveout_heap->heap.ops = &carveout_heap_ops;
- carveout_heap->heap.type = ION_HEAP_TYPE_CARVEOUT;
- carveout_heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE;
-
- return &carveout_heap->heap;
-}
diff --git a/drivers/staging/android/ion/ion_chunk_heap.c b/drivers/staging/android/ion/ion_chunk_heap.c
deleted file mode 100644
index 3cdde9c1a717..000000000000
--- a/drivers/staging/android/ion/ion_chunk_heap.c
+++ /dev/null
@@ -1,146 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * ION memory allocator chunk heap helper
- *
- * Copyright (C) 2012 Google, Inc.
- */
-
-#include <linux/dma-mapping.h>
-#include <linux/err.h>
-#include <linux/genalloc.h>
-#include <linux/mm.h>
-#include <linux/scatterlist.h>
-#include <linux/slab.h>
-
-#include "ion.h"
-
-struct ion_chunk_heap {
- struct ion_heap heap;
- struct gen_pool *pool;
- unsigned long chunk_size;
- unsigned long size;
- unsigned long allocated;
-};
-
-static int ion_chunk_heap_allocate(struct ion_heap *heap,
- struct ion_buffer *buffer,
- unsigned long size,
- unsigned long flags)
-{
- struct ion_chunk_heap *chunk_heap =
- container_of(heap, struct ion_chunk_heap, heap);
- struct sg_table *table;
- struct scatterlist *sg;
- int ret, i;
- unsigned long num_chunks;
- unsigned long allocated_size;
-
- allocated_size = ALIGN(size, chunk_heap->chunk_size);
- num_chunks = allocated_size / chunk_heap->chunk_size;
-
- if (allocated_size > chunk_heap->size - chunk_heap->allocated)
- return -ENOMEM;
-
- table = kmalloc(sizeof(*table), GFP_KERNEL);
- if (!table)
- return -ENOMEM;
- ret = sg_alloc_table(table, num_chunks, GFP_KERNEL);
- if (ret) {
- kfree(table);
- return ret;
- }
-
- sg = table->sgl;
- for (i = 0; i < num_chunks; i++) {
- unsigned long paddr = gen_pool_alloc(chunk_heap->pool,
- chunk_heap->chunk_size);
- if (!paddr)
- goto err;
- sg_set_page(sg, pfn_to_page(PFN_DOWN(paddr)),
- chunk_heap->chunk_size, 0);
- sg = sg_next(sg);
- }
-
- buffer->sg_table = table;
- chunk_heap->allocated += allocated_size;
- return 0;
-err:
- sg = table->sgl;
- for (i -= 1; i >= 0; i--) {
- gen_pool_free(chunk_heap->pool, page_to_phys(sg_page(sg)),
- sg->length);
- sg = sg_next(sg);
- }
- sg_free_table(table);
- kfree(table);
- return -ENOMEM;
-}
-
-static void ion_chunk_heap_free(struct ion_buffer *buffer)
-{
- struct ion_heap *heap = buffer->heap;
- struct ion_chunk_heap *chunk_heap =
- container_of(heap, struct ion_chunk_heap, heap);
- struct sg_table *table = buffer->sg_table;
- struct scatterlist *sg;
- int i;
- unsigned long allocated_size;
-
- allocated_size = ALIGN(buffer->size, chunk_heap->chunk_size);
-
- ion_heap_buffer_zero(buffer);
-
- for_each_sg(table->sgl, sg, table->nents, i) {
- gen_pool_free(chunk_heap->pool, page_to_phys(sg_page(sg)),
- sg->length);
- }
- chunk_heap->allocated -= allocated_size;
- sg_free_table(table);
- kfree(table);
-}
-
-static struct ion_heap_ops chunk_heap_ops = {
- .allocate = ion_chunk_heap_allocate,
- .free = ion_chunk_heap_free,
- .map_user = ion_heap_map_user,
- .map_kernel = ion_heap_map_kernel,
- .unmap_kernel = ion_heap_unmap_kernel,
-};
-
-struct ion_heap *ion_chunk_heap_create(phys_addr_t base, size_t size, size_t chunk_size)
-{
- struct ion_chunk_heap *chunk_heap;
- int ret;
- struct page *page;
-
- page = pfn_to_page(PFN_DOWN(base));
- ret = ion_heap_pages_zero(page, size, pgprot_writecombine(PAGE_KERNEL));
- if (ret)
- return ERR_PTR(ret);
-
- chunk_heap = kzalloc(sizeof(*chunk_heap), GFP_KERNEL);
- if (!chunk_heap)
- return ERR_PTR(-ENOMEM);
-
- chunk_heap->chunk_size = chunk_size;
- chunk_heap->pool = gen_pool_create(get_order(chunk_heap->chunk_size) +
- PAGE_SHIFT, -1);
- if (!chunk_heap->pool) {
- ret = -ENOMEM;
- goto error_gen_pool_create;
- }
- chunk_heap->size = size;
- chunk_heap->allocated = 0;
-
- gen_pool_add(chunk_heap->pool, base, size, -1);
- chunk_heap->heap.ops = &chunk_heap_ops;
- chunk_heap->heap.type = ION_HEAP_TYPE_CHUNK;
- chunk_heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE;
- pr_debug("%s: base %pa size %zu\n", __func__, &base, size);
-
- return &chunk_heap->heap;
-
-error_gen_pool_create:
- kfree(chunk_heap);
- return ERR_PTR(ret);
-}
diff --git a/drivers/staging/comedi/comedi_buf.c b/drivers/staging/comedi/comedi_buf.c
index d2c8cc72a99d..3ef3ddabf139 100644
--- a/drivers/staging/comedi/comedi_buf.c
+++ b/drivers/staging/comedi/comedi_buf.c
@@ -27,18 +27,19 @@ static void comedi_buf_map_kref_release(struct kref *kref)
unsigned int i;
if (bm->page_list) {
- for (i = 0; i < bm->n_pages; i++) {
- buf = &bm->page_list[i];
- clear_bit(PG_reserved,
- &(virt_to_page(buf->virt_addr)->flags));
- if (bm->dma_dir != DMA_NONE) {
-#ifdef CONFIG_HAS_DMA
- dma_free_coherent(bm->dma_hw_dev,
- PAGE_SIZE,
- buf->virt_addr,
- buf->dma_addr);
-#endif
- } else {
+ if (bm->dma_dir != DMA_NONE) {
+ /*
+ * DMA buffer was allocated as a single block.
+ * Address is in page_list[0].
+ */
+ buf = &bm->page_list[0];
+ dma_free_coherent(bm->dma_hw_dev,
+ PAGE_SIZE * bm->n_pages,
+ buf->virt_addr, buf->dma_addr);
+ } else {
+ for (i = 0; i < bm->n_pages; i++) {
+ buf = &bm->page_list[i];
+ ClearPageReserved(virt_to_page(buf->virt_addr));
free_page((unsigned long)buf->virt_addr);
}
}
@@ -57,7 +58,8 @@ static void __comedi_buf_free(struct comedi_device *dev,
unsigned long flags;
if (async->prealloc_buf) {
- vunmap(async->prealloc_buf);
+ if (s->async_dma_dir == DMA_NONE)
+ vunmap(async->prealloc_buf);
async->prealloc_buf = NULL;
async->prealloc_bufsz = 0;
}
@@ -69,6 +71,72 @@ static void __comedi_buf_free(struct comedi_device *dev,
comedi_buf_map_put(bm);
}
+static struct comedi_buf_map *
+comedi_buf_map_alloc(struct comedi_device *dev, enum dma_data_direction dma_dir,
+ unsigned int n_pages)
+{
+ struct comedi_buf_map *bm;
+ struct comedi_buf_page *buf;
+ unsigned int i;
+
+ bm = kzalloc(sizeof(*bm), GFP_KERNEL);
+ if (!bm)
+ return NULL;
+
+ kref_init(&bm->refcount);
+ bm->dma_dir = dma_dir;
+ if (bm->dma_dir != DMA_NONE) {
+ /* Need ref to hardware device to free buffer later. */
+ bm->dma_hw_dev = get_device(dev->hw_dev);
+ }
+
+ bm->page_list = vzalloc(sizeof(*buf) * n_pages);
+ if (!bm->page_list)
+ goto err;
+
+ if (bm->dma_dir != DMA_NONE) {
+ void *virt_addr;
+ dma_addr_t dma_addr;
+
+ /*
+ * Currently, the DMA buffer needs to be allocated as a
+ * single block so that it can be mmap()'ed.
+ */
+ virt_addr = dma_alloc_coherent(bm->dma_hw_dev,
+ PAGE_SIZE * n_pages, &dma_addr,
+ GFP_KERNEL);
+ if (!virt_addr)
+ goto err;
+
+ for (i = 0; i < n_pages; i++) {
+ buf = &bm->page_list[i];
+ buf->virt_addr = virt_addr + (i << PAGE_SHIFT);
+ buf->dma_addr = dma_addr + (i << PAGE_SHIFT);
+ }
+
+ bm->n_pages = i;
+ } else {
+ for (i = 0; i < n_pages; i++) {
+ buf = &bm->page_list[i];
+ buf->virt_addr = (void *)get_zeroed_page(GFP_KERNEL);
+ if (!buf->virt_addr)
+ break;
+
+ SetPageReserved(virt_to_page(buf->virt_addr));
+ }
+
+ bm->n_pages = i;
+ if (i < n_pages)
+ goto err;
+ }
+
+ return bm;
+
+err:
+ comedi_buf_map_put(bm);
+ return NULL;
+}
+
static void __comedi_buf_alloc(struct comedi_device *dev,
struct comedi_subdevice *s,
unsigned int n_pages)
@@ -86,57 +154,37 @@ static void __comedi_buf_alloc(struct comedi_device *dev,
return;
}
- bm = kzalloc(sizeof(*async->buf_map), GFP_KERNEL);
+ bm = comedi_buf_map_alloc(dev, s->async_dma_dir, n_pages);
if (!bm)
return;
- kref_init(&bm->refcount);
spin_lock_irqsave(&s->spin_lock, flags);
async->buf_map = bm;
spin_unlock_irqrestore(&s->spin_lock, flags);
- bm->dma_dir = s->async_dma_dir;
- if (bm->dma_dir != DMA_NONE)
- /* Need ref to hardware device to free buffer later. */
- bm->dma_hw_dev = get_device(dev->hw_dev);
- bm->page_list = vzalloc(sizeof(*buf) * n_pages);
- if (bm->page_list)
+ if (bm->dma_dir != DMA_NONE) {
+ /*
+ * DMA buffer was allocated as a single block.
+ * Address is in page_list[0].
+ */
+ buf = &bm->page_list[0];
+ async->prealloc_buf = buf->virt_addr;
+ } else {
pages = vmalloc(sizeof(struct page *) * n_pages);
+ if (!pages)
+ return;
- if (!pages)
- return;
-
- for (i = 0; i < n_pages; i++) {
- buf = &bm->page_list[i];
- if (bm->dma_dir != DMA_NONE)
-#ifdef CONFIG_HAS_DMA
- buf->virt_addr = dma_alloc_coherent(bm->dma_hw_dev,
- PAGE_SIZE,
- &buf->dma_addr,
- GFP_KERNEL |
- __GFP_COMP);
-#else
- break;
-#endif
- else
- buf->virt_addr = (void *)get_zeroed_page(GFP_KERNEL);
- if (!buf->virt_addr)
- break;
-
- set_bit(PG_reserved, &(virt_to_page(buf->virt_addr)->flags));
-
- pages[i] = virt_to_page(buf->virt_addr);
- }
- spin_lock_irqsave(&s->spin_lock, flags);
- bm->n_pages = i;
- spin_unlock_irqrestore(&s->spin_lock, flags);
+ for (i = 0; i < n_pages; i++) {
+ buf = &bm->page_list[i];
+ pages[i] = virt_to_page(buf->virt_addr);
+ }
- /* vmap the prealloc_buf if all the pages were allocated */
- if (i == n_pages)
+ /* vmap the pages to prealloc_buf */
async->prealloc_buf = vmap(pages, n_pages, VM_MAP,
COMEDI_PAGE_PROTECTION);
- vfree(pages);
+ vfree(pages);
+ }
}
void comedi_buf_map_get(struct comedi_buf_map *bm)
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index f6d1287c7b83..08d1bbbebf2d 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -2301,11 +2301,12 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
struct comedi_subdevice *s;
struct comedi_async *async;
struct comedi_buf_map *bm = NULL;
+ struct comedi_buf_page *buf;
unsigned long start = vma->vm_start;
unsigned long size;
int n_pages;
int i;
- int retval;
+ int retval = 0;
/*
* 'trylock' avoids circular dependency with current->mm->mmap_sem
@@ -2361,24 +2362,36 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
retval = -EINVAL;
goto done;
}
- for (i = 0; i < n_pages; ++i) {
- struct comedi_buf_page *buf = &bm->page_list[i];
+ if (bm->dma_dir != DMA_NONE) {
+ /*
+ * DMA buffer was allocated as a single block.
+ * Address is in page_list[0].
+ */
+ buf = &bm->page_list[0];
+ retval = dma_mmap_coherent(bm->dma_hw_dev, vma, buf->virt_addr,
+ buf->dma_addr, n_pages * PAGE_SIZE);
+ } else {
+ for (i = 0; i < n_pages; ++i) {
+ unsigned long pfn;
+
+ buf = &bm->page_list[i];
+ pfn = page_to_pfn(virt_to_page(buf->virt_addr));
+ retval = remap_pfn_range(vma, start, pfn, PAGE_SIZE,
+ PAGE_SHARED);
+ if (retval)
+ break;
- if (remap_pfn_range(vma, start,
- page_to_pfn(virt_to_page(buf->virt_addr)),
- PAGE_SIZE, PAGE_SHARED)) {
- retval = -EAGAIN;
- goto done;
+ start += PAGE_SIZE;
}
- start += PAGE_SIZE;
}
- vma->vm_ops = &comedi_vm_ops;
- vma->vm_private_data = bm;
+ if (retval == 0) {
+ vma->vm_ops = &comedi_vm_ops;
+ vma->vm_private_data = bm;
- vma->vm_ops->open(vma);
+ vma->vm_ops->open(vma);
+ }
- retval = 0;
done:
up_read(&dev->attach_lock);
comedi_buf_map_put(bm); /* put reference to buf map - okay if NULL */
diff --git a/drivers/staging/comedi/drivers/amplc_dio200_common.c b/drivers/staging/comedi/drivers/amplc_dio200_common.c
index 8697dc02ffb4..0b2f04b02ebc 100644
--- a/drivers/staging/comedi/drivers/amplc_dio200_common.c
+++ b/drivers/staging/comedi/drivers/amplc_dio200_common.c
@@ -46,18 +46,6 @@ static unsigned char clk_gat_sce(unsigned int which, unsigned int chan,
((source & 030) << 3) | (source & 007);
}
-static unsigned char clk_sce(unsigned int which, unsigned int chan,
- unsigned int source)
-{
- return clk_gat_sce(which, chan, source);
-}
-
-static unsigned char gat_sce(unsigned int which, unsigned int chan,
- unsigned int source)
-{
- return clk_gat_sce(which, chan, source);
-}
-
/*
* Periods of the internal clock sources in nanoseconds.
*/
@@ -489,7 +477,7 @@ static void dio200_subdev_8254_set_gate_src(struct comedi_device *dev,
unsigned int offset = dio200_subdev_8254_offset(dev, s);
dio200_write8(dev, DIO200_GAT_SCE(offset >> 3),
- gat_sce((offset >> 2) & 1, chan, src));
+ clk_gat_sce((offset >> 2) & 1, chan, src));
}
static void dio200_subdev_8254_set_clock_src(struct comedi_device *dev,
@@ -500,7 +488,7 @@ static void dio200_subdev_8254_set_clock_src(struct comedi_device *dev,
unsigned int offset = dio200_subdev_8254_offset(dev, s);
dio200_write8(dev, DIO200_CLK_SCE(offset >> 3),
- clk_sce((offset >> 2) & 1, chan, src));
+ clk_gat_sce((offset >> 2) & 1, chan, src));
}
static int dio200_subdev_8254_config(struct comedi_device *dev,
diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c
index 65f60c2b702a..f7e673121864 100644
--- a/drivers/staging/comedi/drivers/amplc_pci230.c
+++ b/drivers/staging/comedi/drivers/amplc_pci230.c
@@ -2330,7 +2330,8 @@ static irqreturn_t pci230_interrupt(int irq, void *d)
devpriv->intr_running = false;
spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
- comedi_handle_events(dev, s_ao);
+ if (s_ao)
+ comedi_handle_events(dev, s_ao);
comedi_handle_events(dev, s_ai);
return IRQ_HANDLED;
diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c
index 3be927f1d3a9..e15e33ed94ae 100644
--- a/drivers/staging/comedi/drivers/dt282x.c
+++ b/drivers/staging/comedi/drivers/dt282x.c
@@ -557,7 +557,8 @@ static irqreturn_t dt282x_interrupt(int irq, void *d)
}
#endif
comedi_handle_events(dev, s);
- comedi_handle_events(dev, s_ao);
+ if (s_ao)
+ comedi_handle_events(dev, s_ao);
return IRQ_RETVAL(handled);
}
diff --git a/drivers/staging/comedi/drivers/mite.c b/drivers/staging/comedi/drivers/mite.c
index 639ec1586976..cc9fc263573e 100644
--- a/drivers/staging/comedi/drivers/mite.c
+++ b/drivers/staging/comedi/drivers/mite.c
@@ -558,7 +558,14 @@ void mite_prep_dma(struct mite_channel *mite_chan,
}
EXPORT_SYMBOL_GPL(mite_prep_dma);
-static struct mite_channel *__mite_request_channel(struct mite *mite,
+/**
+ * mite_request_channel_in_range() - Request a MITE dma channel.
+ * @mite: MITE device.
+ * @ring: MITE dma ring.
+ * @min_channel: minimum channel index to use.
+ * @max_channel: maximum channel index to use.
+ */
+struct mite_channel *mite_request_channel_in_range(struct mite *mite,
struct mite_ring *ring,
unsigned int min_channel,
unsigned int max_channel)
@@ -583,21 +590,6 @@ static struct mite_channel *__mite_request_channel(struct mite *mite,
spin_unlock_irqrestore(&mite->lock, flags);
return mite_chan;
}
-
-/**
- * mite_request_channel_in_range() - Request a MITE dma channel.
- * @mite: MITE device.
- * @ring: MITE dma ring.
- * @min_channel: minimum channel index to use.
- * @max_channel: maximum channel index to use.
- */
-struct mite_channel *mite_request_channel_in_range(struct mite *mite,
- struct mite_ring *ring,
- unsigned int min_channel,
- unsigned int max_channel)
-{
- return __mite_request_channel(mite, ring, min_channel, max_channel);
-}
EXPORT_SYMBOL_GPL(mite_request_channel_in_range);
/**
@@ -608,7 +600,8 @@ EXPORT_SYMBOL_GPL(mite_request_channel_in_range);
struct mite_channel *mite_request_channel(struct mite *mite,
struct mite_ring *ring)
{
- return __mite_request_channel(mite, ring, 0, mite->num_channels - 1);
+ return mite_request_channel_in_range(mite, ring, 0,
+ mite->num_channels - 1);
}
EXPORT_SYMBOL_GPL(mite_request_channel);
diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c
index b8f54b7fb34a..0350f303d557 100644
--- a/drivers/staging/comedi/drivers/usbdux.c
+++ b/drivers/staging/comedi/drivers/usbdux.c
@@ -1226,7 +1226,7 @@ static int usbdux_pwm_period(struct comedi_device *dev,
unsigned int period)
{
struct usbdux_private *devpriv = dev->private;
- int fx2delay = 255;
+ int fx2delay;
if (period < MIN_PWM_PERIOD)
return -EAGAIN;
diff --git a/drivers/staging/erofs/Makefile b/drivers/staging/erofs/Makefile
index 38ab344a285e..e704d9e51514 100644
--- a/drivers/staging/erofs/Makefile
+++ b/drivers/staging/erofs/Makefile
@@ -2,12 +2,12 @@
EROFS_VERSION = "1.0pre1"
-ccflags-y += -Wall -DEROFS_VERSION=\"$(EROFS_VERSION)\"
+ccflags-y += -DEROFS_VERSION=\"$(EROFS_VERSION)\"
obj-$(CONFIG_EROFS_FS) += erofs.o
# staging requirement: to be self-contained in its own directory
ccflags-y += -I $(srctree)/$(src)/include
erofs-objs := super.o inode.o data.o namei.o dir.o utils.o
erofs-$(CONFIG_EROFS_FS_XATTR) += xattr.o
-erofs-$(CONFIG_EROFS_FS_ZIP) += unzip_vle.o unzip_vle_lz4.o
+erofs-$(CONFIG_EROFS_FS_ZIP) += unzip_vle.o zmap.o decompressor.o
diff --git a/drivers/staging/erofs/compress.h b/drivers/staging/erofs/compress.h
new file mode 100644
index 000000000000..c43aa3374d28
--- /dev/null
+++ b/drivers/staging/erofs/compress.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * linux/drivers/staging/erofs/compress.h
+ *
+ * Copyright (C) 2019 HUAWEI, Inc.
+ * http://www.huawei.com/
+ * Created by Gao Xiang <gaoxiang25@huawei.com>
+ */
+#ifndef __EROFS_FS_COMPRESS_H
+#define __EROFS_FS_COMPRESS_H
+
+#include "internal.h"
+
+enum {
+ Z_EROFS_COMPRESSION_SHIFTED = Z_EROFS_COMPRESSION_MAX,
+ Z_EROFS_COMPRESSION_RUNTIME_MAX
+};
+
+struct z_erofs_decompress_req {
+ struct super_block *sb;
+ struct page **in, **out;
+
+ unsigned short pageofs_out;
+ unsigned int inputsize, outputsize;
+
+ /* indicate the algorithm will be used for decompression */
+ unsigned int alg;
+ bool inplace_io, partial_decoding;
+};
+
+/*
+ * - 0x5A110C8D ('sallocated', Z_EROFS_MAPPING_STAGING) -
+ * used to mark temporary allocated pages from other
+ * file/cached pages and NULL mapping pages.
+ */
+#define Z_EROFS_MAPPING_STAGING ((void *)0x5A110C8D)
+
+/* check if a page is marked as staging */
+static inline bool z_erofs_page_is_staging(struct page *page)
+{
+ return page->mapping == Z_EROFS_MAPPING_STAGING;
+}
+
+static inline bool z_erofs_put_stagingpage(struct list_head *pagepool,
+ struct page *page)
+{
+ if (!z_erofs_page_is_staging(page))
+ return false;
+
+ /* staging pages should not be used by others at the same time */
+ if (page_ref_count(page) > 1)
+ put_page(page);
+ else
+ list_add(&page->lru, pagepool);
+ return true;
+}
+
+int z_erofs_decompress(struct z_erofs_decompress_req *rq,
+ struct list_head *pagepool);
+
+#endif
+
diff --git a/drivers/staging/erofs/data.c b/drivers/staging/erofs/data.c
index 746685f90564..cc31c3e5984c 100644
--- a/drivers/staging/erofs/data.c
+++ b/drivers/staging/erofs/data.c
@@ -124,7 +124,7 @@ static int erofs_map_blocks_flatmode(struct inode *inode,
trace_erofs_map_blocks_flatmode_enter(inode, map, flags);
nblocks = DIV_ROUND_UP(inode->i_size, PAGE_SIZE);
- lastblk = nblocks - is_inode_layout_inline(inode);
+ lastblk = nblocks - is_inode_flat_inline(inode);
if (unlikely(offset >= inode->i_size)) {
/* leave out-of-bound access unmapped */
@@ -139,7 +139,7 @@ static int erofs_map_blocks_flatmode(struct inode *inode,
if (offset < blknr_to_addr(lastblk)) {
map->m_pa = blknr_to_addr(vi->raw_blkaddr) + map->m_la;
map->m_plen = blknr_to_addr(lastblk) - offset;
- } else if (is_inode_layout_inline(inode)) {
+ } else if (is_inode_flat_inline(inode)) {
/* 2 - inode inline B: inode, [xattrs], inline last blk... */
struct erofs_sb_info *sbi = EROFS_SB(inode->i_sb);
diff --git a/drivers/staging/erofs/decompressor.c b/drivers/staging/erofs/decompressor.c
new file mode 100644
index 000000000000..1fb0abb98dff
--- /dev/null
+++ b/drivers/staging/erofs/decompressor.c
@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * linux/drivers/staging/erofs/decompressor.c
+ *
+ * Copyright (C) 2019 HUAWEI, Inc.
+ * http://www.huawei.com/
+ * Created by Gao Xiang <gaoxiang25@huawei.com>
+ */
+#include "compress.h"
+#include <linux/lz4.h>
+
+#ifndef LZ4_DISTANCE_MAX /* history window size */
+#define LZ4_DISTANCE_MAX 65535 /* set to maximum value by default */
+#endif
+
+#define LZ4_MAX_DISTANCE_PAGES (DIV_ROUND_UP(LZ4_DISTANCE_MAX, PAGE_SIZE) + 1)
+#ifndef LZ4_DECOMPRESS_INPLACE_MARGIN
+#define LZ4_DECOMPRESS_INPLACE_MARGIN(srcsize) (((srcsize) >> 8) + 32)
+#endif
+
+struct z_erofs_decompressor {
+ /*
+ * if destpages have sparsed pages, fill them with bounce pages.
+ * it also check whether destpages indicate continuous physical memory.
+ */
+ int (*prepare_destpages)(struct z_erofs_decompress_req *rq,
+ struct list_head *pagepool);
+ int (*decompress)(struct z_erofs_decompress_req *rq, u8 *out);
+ char *name;
+};
+
+static int lz4_prepare_destpages(struct z_erofs_decompress_req *rq,
+ struct list_head *pagepool)
+{
+ const unsigned int nr =
+ PAGE_ALIGN(rq->pageofs_out + rq->outputsize) >> PAGE_SHIFT;
+ struct page *availables[LZ4_MAX_DISTANCE_PAGES] = { NULL };
+ unsigned long bounced[DIV_ROUND_UP(LZ4_MAX_DISTANCE_PAGES,
+ BITS_PER_LONG)] = { 0 };
+ void *kaddr = NULL;
+ unsigned int i, j, top;
+
+ top = 0;
+ for (i = j = 0; i < nr; ++i, ++j) {
+ struct page *const page = rq->out[i];
+ struct page *victim;
+
+ if (j >= LZ4_MAX_DISTANCE_PAGES)
+ j = 0;
+
+ /* 'valid' bounced can only be tested after a complete round */
+ if (test_bit(j, bounced)) {
+ DBG_BUGON(i < LZ4_MAX_DISTANCE_PAGES);
+ DBG_BUGON(top >= LZ4_MAX_DISTANCE_PAGES);
+ availables[top++] = rq->out[i - LZ4_MAX_DISTANCE_PAGES];
+ }
+
+ if (page) {
+ __clear_bit(j, bounced);
+ if (kaddr) {
+ if (kaddr + PAGE_SIZE == page_address(page))
+ kaddr += PAGE_SIZE;
+ else
+ kaddr = NULL;
+ } else if (!i) {
+ kaddr = page_address(page);
+ }
+ continue;
+ }
+ kaddr = NULL;
+ __set_bit(j, bounced);
+
+ if (top) {
+ victim = availables[--top];
+ get_page(victim);
+ } else {
+ if (!list_empty(pagepool)) {
+ victim = lru_to_page(pagepool);
+ list_del(&victim->lru);
+ DBG_BUGON(page_ref_count(victim) != 1);
+ } else {
+ victim = alloc_pages(GFP_KERNEL, 0);
+ if (!victim)
+ return -ENOMEM;
+ }
+ victim->mapping = Z_EROFS_MAPPING_STAGING;
+ }
+ rq->out[i] = victim;
+ }
+ return kaddr ? 1 : 0;
+}
+
+static void *generic_copy_inplace_data(struct z_erofs_decompress_req *rq,
+ u8 *src, unsigned int pageofs_in)
+{
+ /*
+ * if in-place decompression is ongoing, those decompressed
+ * pages should be copied in order to avoid being overlapped.
+ */
+ struct page **in = rq->in;
+ u8 *const tmp = erofs_get_pcpubuf(0);
+ u8 *tmpp = tmp;
+ unsigned int inlen = rq->inputsize - pageofs_in;
+ unsigned int count = min_t(uint, inlen, PAGE_SIZE - pageofs_in);
+
+ while (tmpp < tmp + inlen) {
+ if (!src)
+ src = kmap_atomic(*in);
+ memcpy(tmpp, src + pageofs_in, count);
+ kunmap_atomic(src);
+ src = NULL;
+ tmpp += count;
+ pageofs_in = 0;
+ count = PAGE_SIZE;
+ ++in;
+ }
+ return tmp;
+}
+
+static int lz4_decompress(struct z_erofs_decompress_req *rq, u8 *out)
+{
+ unsigned int inputmargin, inlen;
+ u8 *src;
+ bool copied, support_0padding;
+ int ret;
+
+ if (rq->inputsize > PAGE_SIZE)
+ return -ENOTSUPP;
+
+ src = kmap_atomic(*rq->in);
+ inputmargin = 0;
+ support_0padding = false;
+
+ /* decompression inplace is only safe when 0padding is enabled */
+ if (EROFS_SB(rq->sb)->requirements & EROFS_REQUIREMENT_LZ4_0PADDING) {
+ support_0padding = true;
+
+ while (!src[inputmargin & ~PAGE_MASK])
+ if (!(++inputmargin & ~PAGE_MASK))
+ break;
+
+ if (inputmargin >= rq->inputsize) {
+ kunmap_atomic(src);
+ return -EIO;
+ }
+ }
+
+ copied = false;
+ inlen = rq->inputsize - inputmargin;
+ if (rq->inplace_io) {
+ const uint oend = (rq->pageofs_out +
+ rq->outputsize) & ~PAGE_MASK;
+ const uint nr = PAGE_ALIGN(rq->pageofs_out +
+ rq->outputsize) >> PAGE_SHIFT;
+
+ if (rq->partial_decoding || !support_0padding ||
+ rq->out[nr - 1] != rq->in[0] ||
+ rq->inputsize - oend <
+ LZ4_DECOMPRESS_INPLACE_MARGIN(inlen)) {
+ src = generic_copy_inplace_data(rq, src, inputmargin);
+ inputmargin = 0;
+ copied = true;
+ }
+ }
+
+ ret = LZ4_decompress_safe_partial(src + inputmargin, out,
+ inlen, rq->outputsize,
+ rq->outputsize);
+ if (ret < 0) {
+ errln("%s, failed to decompress, in[%p, %u, %u] out[%p, %u]",
+ __func__, src + inputmargin, inlen, inputmargin,
+ out, rq->outputsize);
+ WARN_ON(1);
+ print_hex_dump(KERN_DEBUG, "[ in]: ", DUMP_PREFIX_OFFSET,
+ 16, 1, src + inputmargin, inlen, true);
+ print_hex_dump(KERN_DEBUG, "[out]: ", DUMP_PREFIX_OFFSET,
+ 16, 1, out, rq->outputsize, true);
+ ret = -EIO;
+ }
+
+ if (copied)
+ erofs_put_pcpubuf(src);
+ else
+ kunmap_atomic(src);
+ return ret;
+}
+
+static struct z_erofs_decompressor decompressors[] = {
+ [Z_EROFS_COMPRESSION_SHIFTED] = {
+ .name = "shifted"
+ },
+ [Z_EROFS_COMPRESSION_LZ4] = {
+ .prepare_destpages = lz4_prepare_destpages,
+ .decompress = lz4_decompress,
+ .name = "lz4"
+ },
+};
+
+static void copy_from_pcpubuf(struct page **out, const char *dst,
+ unsigned short pageofs_out,
+ unsigned int outputsize)
+{
+ const char *end = dst + outputsize;
+ const unsigned int righthalf = PAGE_SIZE - pageofs_out;
+ const char *cur = dst - pageofs_out;
+
+ while (cur < end) {
+ struct page *const page = *out++;
+
+ if (page) {
+ char *buf = kmap_atomic(page);
+
+ if (cur >= dst) {
+ memcpy(buf, cur, min_t(uint, PAGE_SIZE,
+ end - cur));
+ } else {
+ memcpy(buf + pageofs_out, cur + pageofs_out,
+ min_t(uint, righthalf, end - cur));
+ }
+ kunmap_atomic(buf);
+ }
+ cur += PAGE_SIZE;
+ }
+}
+
+static int decompress_generic(struct z_erofs_decompress_req *rq,
+ struct list_head *pagepool)
+{
+ const unsigned int nrpages_out =
+ PAGE_ALIGN(rq->pageofs_out + rq->outputsize) >> PAGE_SHIFT;
+ const struct z_erofs_decompressor *alg = decompressors + rq->alg;
+ unsigned int dst_maptype;
+ void *dst;
+ int ret;
+
+ if (nrpages_out == 1 && !rq->inplace_io) {
+ DBG_BUGON(!*rq->out);
+ dst = kmap_atomic(*rq->out);
+ dst_maptype = 0;
+ goto dstmap_out;
+ }
+
+ /*
+ * For the case of small output size (especially much less
+ * than PAGE_SIZE), memcpy the decompressed data rather than
+ * compressed data is preferred.
+ */
+ if (rq->outputsize <= PAGE_SIZE * 7 / 8) {
+ dst = erofs_get_pcpubuf(0);
+ if (IS_ERR(dst))
+ return PTR_ERR(dst);
+
+ rq->inplace_io = false;
+ ret = alg->decompress(rq, dst);
+ if (!ret)
+ copy_from_pcpubuf(rq->out, dst, rq->pageofs_out,
+ rq->outputsize);
+
+ erofs_put_pcpubuf(dst);
+ return ret;
+ }
+
+ ret = alg->prepare_destpages(rq, pagepool);
+ if (ret < 0) {
+ return ret;
+ } else if (ret) {
+ dst = page_address(*rq->out);
+ dst_maptype = 1;
+ goto dstmap_out;
+ }
+
+ dst = erofs_vmap(rq->out, nrpages_out);
+ if (!dst)
+ return -ENOMEM;
+ dst_maptype = 2;
+
+dstmap_out:
+ ret = alg->decompress(rq, dst + rq->pageofs_out);
+
+ if (!dst_maptype)
+ kunmap_atomic(dst);
+ else if (dst_maptype == 2)
+ erofs_vunmap(dst, nrpages_out);
+ return ret;
+}
+
+static int shifted_decompress(const struct z_erofs_decompress_req *rq,
+ struct list_head *pagepool)
+{
+ const unsigned int nrpages_out =
+ PAGE_ALIGN(rq->pageofs_out + rq->outputsize) >> PAGE_SHIFT;
+ const unsigned int righthalf = PAGE_SIZE - rq->pageofs_out;
+ unsigned char *src, *dst;
+
+ if (nrpages_out > 2) {
+ DBG_BUGON(1);
+ return -EIO;
+ }
+
+ if (rq->out[0] == *rq->in) {
+ DBG_BUGON(nrpages_out != 1);
+ return 0;
+ }
+
+ src = kmap_atomic(*rq->in);
+ if (!rq->out[0]) {
+ dst = NULL;
+ } else {
+ dst = kmap_atomic(rq->out[0]);
+ memcpy(dst + rq->pageofs_out, src, righthalf);
+ }
+
+ if (rq->out[1] == *rq->in) {
+ memmove(src, src + righthalf, rq->pageofs_out);
+ } else if (nrpages_out == 2) {
+ if (dst)
+ kunmap_atomic(dst);
+ DBG_BUGON(!rq->out[1]);
+ dst = kmap_atomic(rq->out[1]);
+ memcpy(dst, src + righthalf, rq->pageofs_out);
+ }
+ if (dst)
+ kunmap_atomic(dst);
+ kunmap_atomic(src);
+ return 0;
+}
+
+int z_erofs_decompress(struct z_erofs_decompress_req *rq,
+ struct list_head *pagepool)
+{
+ if (rq->alg == Z_EROFS_COMPRESSION_SHIFTED)
+ return shifted_decompress(rq, pagepool);
+ return decompress_generic(rq, pagepool);
+}
+
diff --git a/drivers/staging/erofs/dir.c b/drivers/staging/erofs/dir.c
index 9bbc68729c11..dbf6a151886c 100644
--- a/drivers/staging/erofs/dir.c
+++ b/drivers/staging/erofs/dir.c
@@ -42,10 +42,9 @@ static int erofs_fill_dentries(struct dir_context *ctx,
void *dentry_blk, unsigned int *ofs,
unsigned int nameoff, unsigned int maxsize)
{
- struct erofs_dirent *de = dentry_blk;
+ struct erofs_dirent *de = dentry_blk + *ofs;
const struct erofs_dirent *end = dentry_blk + nameoff;
- de = dentry_blk + *ofs;
while (de < end) {
const char *de_name;
unsigned int de_namelen;
diff --git a/drivers/staging/erofs/erofs_fs.h b/drivers/staging/erofs/erofs_fs.h
index fa52898df006..9f61abb7c1ca 100644
--- a/drivers/staging/erofs/erofs_fs.h
+++ b/drivers/staging/erofs/erofs_fs.h
@@ -17,10 +17,17 @@
#define EROFS_SUPER_MAGIC_V1 0xE0F5E1E2
#define EROFS_SUPER_OFFSET 1024
+/*
+ * Any bits that aren't in EROFS_ALL_REQUIREMENTS should be
+ * incompatible with this kernel version.
+ */
+#define EROFS_REQUIREMENT_LZ4_0PADDING 0x00000001
+#define EROFS_ALL_REQUIREMENTS EROFS_REQUIREMENT_LZ4_0PADDING
+
struct erofs_super_block {
/* 0 */__le32 magic; /* in the little endian */
/* 4 */__le32 checksum; /* crc32c(super_block) */
-/* 8 */__le32 features;
+/* 8 */__le32 features; /* (aka. feature_compat) */
/* 12 */__u8 blkszbits; /* support block_size == PAGE_SIZE only */
/* 13 */__u8 reserved;
@@ -34,27 +41,38 @@ struct erofs_super_block {
/* 44 */__le32 xattr_blkaddr;
/* 48 */__u8 uuid[16]; /* 128-bit uuid for volume */
/* 64 */__u8 volume_name[16]; /* volume name */
+/* 80 */__le32 requirements; /* (aka. feature_incompat) */
-/* 80 */__u8 reserved2[48]; /* 128 bytes */
-} __packed;
+/* 84 */__u8 reserved2[44];
+} __packed; /* 128 bytes */
/*
* erofs inode data mapping:
* 0 - inode plain without inline data A:
* inode, [xattrs], ... | ... | no-holed data
- * 1 - inode VLE compression B:
+ * 1 - inode VLE compression B (legacy):
* inode, [xattrs], extents ... | ...
* 2 - inode plain with inline data C:
* inode, [xattrs], last_inline_data, ... | ... | no-holed data
- * 3~7 - reserved
+ * 3 - inode compression D:
+ * inode, [xattrs], map_header, extents ... | ...
+ * 4~7 - reserved
*/
enum {
- EROFS_INODE_LAYOUT_PLAIN,
- EROFS_INODE_LAYOUT_COMPRESSION,
- EROFS_INODE_LAYOUT_INLINE,
+ EROFS_INODE_FLAT_PLAIN,
+ EROFS_INODE_FLAT_COMPRESSION_LEGACY,
+ EROFS_INODE_FLAT_INLINE,
+ EROFS_INODE_FLAT_COMPRESSION,
EROFS_INODE_LAYOUT_MAX
};
+static bool erofs_inode_is_data_compressed(unsigned int datamode)
+{
+ if (datamode == EROFS_INODE_FLAT_COMPRESSION)
+ return true;
+ return datamode == EROFS_INODE_FLAT_COMPRESSION_LEGACY;
+}
+
/* bit definitions of inode i_advise */
#define EROFS_I_VERSION_BITS 1
#define EROFS_I_DATA_MAPPING_BITS 3
@@ -169,11 +187,39 @@ struct erofs_xattr_entry {
sizeof(struct erofs_xattr_entry) + \
(entry)->e_name_len + le16_to_cpu((entry)->e_value_size))
-/* have to be aligned with 8 bytes on disk */
-struct erofs_extent_header {
- __le32 eh_checksum;
- __le32 eh_reserved[3];
-} __packed;
+/* available compression algorithm types */
+enum {
+ Z_EROFS_COMPRESSION_LZ4,
+ Z_EROFS_COMPRESSION_MAX
+};
+
+/*
+ * bit 0 : COMPACTED_2B indexes (0 - off; 1 - on)
+ * e.g. for 4k logical cluster size, 4B if compacted 2B is off;
+ * (4B) + 2B + (4B) if compacted 2B is on.
+ */
+#define Z_EROFS_ADVISE_COMPACTED_2B_BIT 0
+
+#define Z_EROFS_ADVISE_COMPACTED_2B (1 << Z_EROFS_ADVISE_COMPACTED_2B_BIT)
+
+struct z_erofs_map_header {
+ __le32 h_reserved1;
+ __le16 h_advise;
+ /*
+ * bit 0-3 : algorithm type of head 1 (logical cluster type 01);
+ * bit 4-7 : algorithm type of head 2 (logical cluster type 11).
+ */
+ __u8 h_algorithmtype;
+ /*
+ * bit 0-2 : logical cluster bits - 12, e.g. 0 for 4096;
+ * bit 3-4 : (physical - logical) cluster bits of head 1:
+ * For example, if logical clustersize = 4096, 1 for 8192.
+ * bit 5-7 : (physical - logical) cluster bits of head 2.
+ */
+ __u8 h_clusterbits;
+};
+
+#define Z_EROFS_VLE_LEGACY_HEADER_PADDING 8
/*
* Z_EROFS Variable-sized Logical Extent cluster type:
@@ -229,8 +275,9 @@ struct z_erofs_vle_decompressed_index {
} di_u __packed; /* 8 bytes */
} __packed;
-#define Z_EROFS_VLE_EXTENT_ALIGN(size) round_up(size, \
- sizeof(struct z_erofs_vle_decompressed_index))
+#define Z_EROFS_VLE_LEGACY_INDEX_ALIGN(size) \
+ (round_up(size, sizeof(struct z_erofs_vle_decompressed_index)) + \
+ sizeof(struct z_erofs_map_header) + Z_EROFS_VLE_LEGACY_HEADER_PADDING)
/* dirent sorts in alphabet order, thus we can do binary search */
struct erofs_dirent {
@@ -263,7 +310,7 @@ static inline void erofs_check_ondisk_layout_definitions(void)
BUILD_BUG_ON(sizeof(struct erofs_inode_v2) != 64);
BUILD_BUG_ON(sizeof(struct erofs_xattr_ibody_header) != 12);
BUILD_BUG_ON(sizeof(struct erofs_xattr_entry) != 4);
- BUILD_BUG_ON(sizeof(struct erofs_extent_header) != 16);
+ BUILD_BUG_ON(sizeof(struct z_erofs_map_header) != 8);
BUILD_BUG_ON(sizeof(struct z_erofs_vle_decompressed_index) != 8);
BUILD_BUG_ON(sizeof(struct erofs_dirent) != 12);
diff --git a/drivers/staging/erofs/inode.c b/drivers/staging/erofs/inode.c
index c7d3b815a798..4c3d8bf8d249 100644
--- a/drivers/staging/erofs/inode.c
+++ b/drivers/staging/erofs/inode.c
@@ -20,12 +20,13 @@ static int read_inode(struct inode *inode, void *data)
struct erofs_vnode *vi = EROFS_V(inode);
struct erofs_inode_v1 *v1 = data;
const unsigned int advise = le16_to_cpu(v1->i_advise);
+ erofs_blk_t nblks = 0;
- vi->data_mapping_mode = __inode_data_mapping(advise);
+ vi->datamode = __inode_data_mapping(advise);
- if (unlikely(vi->data_mapping_mode >= EROFS_INODE_LAYOUT_MAX)) {
- errln("unknown data mapping mode %u of nid %llu",
- vi->data_mapping_mode, vi->nid);
+ if (unlikely(vi->datamode >= EROFS_INODE_LAYOUT_MAX)) {
+ errln("unsupported data mapping %u of nid %llu",
+ vi->datamode, vi->nid);
DBG_BUGON(1);
return -EIO;
}
@@ -60,6 +61,10 @@ static int read_inode(struct inode *inode, void *data)
le32_to_cpu(v2->i_ctime_nsec);
inode->i_size = le64_to_cpu(v2->i_size);
+
+ /* total blocks for compressed files */
+ if (is_inode_layout_compression(inode))
+ nblks = le32_to_cpu(v2->i_u.compressed_blocks);
} else if (__inode_version(advise) == EROFS_INODE_LAYOUT_V1) {
struct erofs_sb_info *sbi = EROFS_SB(inode->i_sb);
@@ -90,6 +95,8 @@ static int read_inode(struct inode *inode, void *data)
sbi->build_time_nsec;
inode->i_size = le32_to_cpu(v1->i_size);
+ if (is_inode_layout_compression(inode))
+ nblks = le32_to_cpu(v1->i_u.compressed_blocks);
} else {
errln("unsupported on-disk inode version %u of nid %llu",
__inode_version(advise), vi->nid);
@@ -97,8 +104,11 @@ static int read_inode(struct inode *inode, void *data)
return -EIO;
}
- /* measure inode.i_blocks as the generic filesystem */
- inode->i_blocks = ((inode->i_size - 1) >> 9) + 1;
+ if (!nblks)
+ /* measure inode.i_blocks as generic filesystems */
+ inode->i_blocks = roundup(inode->i_size, EROFS_BLKSIZ) >> 9;
+ else
+ inode->i_blocks = nblks << LOG_SECTORS_PER_BLOCK;
return 0;
}
@@ -117,12 +127,9 @@ static int fill_inline_data(struct inode *inode, void *data,
{
struct erofs_vnode *vi = EROFS_V(inode);
struct erofs_sb_info *sbi = EROFS_I_SB(inode);
- int mode = vi->data_mapping_mode;
-
- DBG_BUGON(mode >= EROFS_INODE_LAYOUT_MAX);
/* should be inode inline C */
- if (mode != EROFS_INODE_LAYOUT_INLINE)
+ if (!is_inode_flat_inline(inode))
return 0;
/* fast symlink (following ext4) */
@@ -148,7 +155,7 @@ static int fill_inline_data(struct inode *inode, void *data,
inode->i_link = lnk;
set_inode_fast_symlink(inode);
}
- return -EAGAIN;
+ return 0;
}
static int fill_inode(struct inode *inode, int isdir)
@@ -197,25 +204,21 @@ static int fill_inode(struct inode *inode, int isdir)
S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
inode->i_op = &erofs_generic_iops;
init_special_inode(inode, inode->i_mode, inode->i_rdev);
+ goto out_unlock;
} else {
err = -EIO;
goto out_unlock;
}
if (is_inode_layout_compression(inode)) {
-#ifdef CONFIG_EROFS_FS_ZIP
- inode->i_mapping->a_ops =
- &z_erofs_vle_normalaccess_aops;
-#else
- err = -ENOTSUPP;
-#endif
+ err = z_erofs_fill_inode(inode);
goto out_unlock;
}
inode->i_mapping->a_ops = &erofs_raw_access_aops;
/* fill last page if inline data is available */
- fill_inline_data(inode, data, ofs);
+ err = fill_inline_data(inode, data, ofs);
}
out_unlock:
@@ -285,7 +288,24 @@ struct inode *erofs_iget(struct super_block *sb,
return inode;
}
+int erofs_getattr(const struct path *path, struct kstat *stat,
+ u32 request_mask, unsigned int query_flags)
+{
+ struct inode *const inode = d_inode(path->dentry);
+
+ if (is_inode_layout_compression(inode))
+ stat->attributes |= STATX_ATTR_COMPRESSED;
+
+ stat->attributes |= STATX_ATTR_IMMUTABLE;
+ stat->attributes_mask |= (STATX_ATTR_COMPRESSED |
+ STATX_ATTR_IMMUTABLE);
+
+ generic_fillattr(inode, stat);
+ return 0;
+}
+
const struct inode_operations erofs_generic_iops = {
+ .getattr = erofs_getattr,
#ifdef CONFIG_EROFS_FS_XATTR
.listxattr = erofs_listxattr,
#endif
@@ -294,6 +314,7 @@ const struct inode_operations erofs_generic_iops = {
const struct inode_operations erofs_symlink_iops = {
.get_link = page_get_link,
+ .getattr = erofs_getattr,
#ifdef CONFIG_EROFS_FS_XATTR
.listxattr = erofs_listxattr,
#endif
@@ -302,6 +323,7 @@ const struct inode_operations erofs_symlink_iops = {
const struct inode_operations erofs_fast_symlink_iops = {
.get_link = simple_get_link,
+ .getattr = erofs_getattr,
#ifdef CONFIG_EROFS_FS_XATTR
.listxattr = erofs_listxattr,
#endif
diff --git a/drivers/staging/erofs/internal.h b/drivers/staging/erofs/internal.h
index c47778b3fabd..963cc1b8b896 100644
--- a/drivers/staging/erofs/internal.h
+++ b/drivers/staging/erofs/internal.h
@@ -115,6 +115,8 @@ struct erofs_sb_info {
u8 uuid[16]; /* 128-bit uuid for volume */
u8 volume_name[16]; /* volume name */
+ u32 requirements;
+
char *dev_name;
unsigned int mount_opt;
@@ -319,6 +321,10 @@ static inline void z_erofs_exit_zip_subsystem(void) {}
/* page count of a compressed cluster */
#define erofs_clusterpages(sbi) ((1 << (sbi)->clusterbits) / PAGE_SIZE)
+
+#define EROFS_PCPUBUF_NR_PAGES Z_EROFS_CLUSTER_MAX_PAGES
+#else
+#define EROFS_PCPUBUF_NR_PAGES 0
#endif
typedef u64 erofs_off_t;
@@ -337,9 +343,11 @@ static inline erofs_off_t iloc(struct erofs_sb_info *sbi, erofs_nid_t nid)
/* atomic flag definitions */
#define EROFS_V_EA_INITED_BIT 0
+#define EROFS_V_Z_INITED_BIT 1
/* bitlock definitions (arranged in reverse order) */
#define EROFS_V_BL_XATTR_BIT (BITS_PER_LONG - 1)
+#define EROFS_V_BL_Z_BIT (BITS_PER_LONG - 2)
struct erofs_vnode {
erofs_nid_t nid;
@@ -347,16 +355,24 @@ struct erofs_vnode {
/* atomic flags (including bitlocks) */
unsigned long flags;
- unsigned char data_mapping_mode;
- /* inline size in bytes */
+ unsigned char datamode;
unsigned char inode_isize;
unsigned short xattr_isize;
unsigned xattr_shared_count;
unsigned *xattr_shared_xattrs;
- erofs_blk_t raw_blkaddr;
-
+ union {
+ erofs_blk_t raw_blkaddr;
+#ifdef CONFIG_EROFS_FS_ZIP
+ struct {
+ unsigned short z_advise;
+ unsigned char z_algorithmtype[2];
+ unsigned char z_logical_clusterbits;
+ unsigned char z_physical_clusterbits[2];
+ };
+#endif
+ };
/* the corresponding vfs inode */
struct inode vfs_inode;
};
@@ -381,20 +397,14 @@ static inline unsigned long inode_datablocks(struct inode *inode)
return DIV_ROUND_UP(inode->i_size, EROFS_BLKSIZ);
}
-static inline bool is_inode_layout_plain(struct inode *inode)
-{
- return EROFS_V(inode)->data_mapping_mode == EROFS_INODE_LAYOUT_PLAIN;
-}
-
static inline bool is_inode_layout_compression(struct inode *inode)
{
- return EROFS_V(inode)->data_mapping_mode ==
- EROFS_INODE_LAYOUT_COMPRESSION;
+ return erofs_inode_is_data_compressed(EROFS_V(inode)->datamode);
}
-static inline bool is_inode_layout_inline(struct inode *inode)
+static inline bool is_inode_flat_inline(struct inode *inode)
{
- return EROFS_V(inode)->data_mapping_mode == EROFS_INODE_LAYOUT_INLINE;
+ return EROFS_V(inode)->datamode == EROFS_INODE_FLAT_INLINE;
}
extern const struct super_operations erofs_sops;
@@ -431,6 +441,7 @@ extern const struct address_space_operations z_erofs_vle_normalaccess_aops;
*/
enum {
BH_Zipped = BH_PrivateStart,
+ BH_FullMapped,
};
/* Has a disk mapping */
@@ -439,6 +450,8 @@ enum {
#define EROFS_MAP_META (1 << BH_Meta)
/* The extent has been compressed */
#define EROFS_MAP_ZIPPED (1 << BH_Zipped)
+/* The length of extent is full */
+#define EROFS_MAP_FULL_MAPPED (1 << BH_FullMapped)
struct erofs_map_blocks {
erofs_off_t m_pa, m_la;
@@ -452,11 +465,14 @@ struct erofs_map_blocks {
/* Flags used by erofs_map_blocks() */
#define EROFS_GET_BLOCKS_RAW 0x0001
+/* zmap.c */
#ifdef CONFIG_EROFS_FS_ZIP
+int z_erofs_fill_inode(struct inode *inode);
int z_erofs_map_blocks_iter(struct inode *inode,
struct erofs_map_blocks *map,
int flags);
#else
+static inline int z_erofs_fill_inode(struct inode *inode) { return -ENOTSUPP; }
static inline int z_erofs_map_blocks_iter(struct inode *inode,
struct erofs_map_blocks *map,
int flags)
@@ -556,6 +572,8 @@ static inline bool is_inode_fast_symlink(struct inode *inode)
}
struct inode *erofs_iget(struct super_block *sb, erofs_nid_t nid, bool dir);
+int erofs_getattr(const struct path *path, struct kstat *stat,
+ u32 request_mask, unsigned int query_flags);
/* namei.c */
extern const struct inode_operations erofs_dir_iops;
@@ -597,6 +615,22 @@ static inline void erofs_vunmap(const void *mem, unsigned int count)
extern struct shrinker erofs_shrinker_info;
struct page *erofs_allocpage(struct list_head *pool, gfp_t gfp);
+
+#if (EROFS_PCPUBUF_NR_PAGES > 0)
+void *erofs_get_pcpubuf(unsigned int pagenr);
+#define erofs_put_pcpubuf(buf) do { \
+ (void)&(buf); \
+ preempt_enable(); \
+} while (0)
+#else
+static inline void *erofs_get_pcpubuf(unsigned int pagenr)
+{
+ return ERR_PTR(-ENOTSUPP);
+}
+
+#define erofs_put_pcpubuf(buf) do {} while (0)
+#endif
+
void erofs_register_super(struct super_block *sb);
void erofs_unregister_super(struct super_block *sb);
diff --git a/drivers/staging/erofs/namei.c b/drivers/staging/erofs/namei.c
index d8d9dc9dab43..fd3ae78d0ba5 100644
--- a/drivers/staging/erofs/namei.c
+++ b/drivers/staging/erofs/namei.c
@@ -247,6 +247,7 @@ static struct dentry *erofs_lookup(struct inode *dir,
const struct inode_operations erofs_dir_iops = {
.lookup = erofs_lookup,
+ .getattr = erofs_getattr,
#ifdef CONFIG_EROFS_FS_XATTR
.listxattr = erofs_listxattr,
#endif
diff --git a/drivers/staging/erofs/super.c b/drivers/staging/erofs/super.c
index f580d4ef77a1..54494412eba4 100644
--- a/drivers/staging/erofs/super.c
+++ b/drivers/staging/erofs/super.c
@@ -71,6 +71,22 @@ static void free_inode(struct inode *inode)
kmem_cache_free(erofs_inode_cachep, vi);
}
+static bool check_layout_compatibility(struct super_block *sb,
+ struct erofs_super_block *layout)
+{
+ const unsigned int requirements = le32_to_cpu(layout->requirements);
+
+ EROFS_SB(sb)->requirements = requirements;
+
+ /* check if current kernel meets all mandatory requirements */
+ if (requirements & (~EROFS_ALL_REQUIREMENTS)) {
+ errln("unidentified requirements %x, please upgrade kernel version",
+ requirements & ~EROFS_ALL_REQUIREMENTS);
+ return false;
+ }
+ return true;
+}
+
static int superblock_read(struct super_block *sb)
{
struct erofs_sb_info *sbi;
@@ -104,6 +120,9 @@ static int superblock_read(struct super_block *sb)
goto out;
}
+ if (!check_layout_compatibility(sb, layout))
+ goto out;
+
sbi->blocks = le32_to_cpu(layout->blocks);
sbi->meta_blkaddr = le32_to_cpu(layout->meta_blkaddr);
#ifdef CONFIG_EROFS_FS_XATTR
@@ -364,7 +383,7 @@ static int erofs_read_super(struct super_block *sb,
goto err;
}
- sbi = kzalloc(sizeof(struct erofs_sb_info), GFP_KERNEL);
+ sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
if (unlikely(!sbi)) {
err = -ENOMEM;
goto err;
diff --git a/drivers/staging/erofs/unzip_pagevec.h b/drivers/staging/erofs/unzip_pagevec.h
index f37d8fd14771..7af0ba8d8495 100644
--- a/drivers/staging/erofs/unzip_pagevec.h
+++ b/drivers/staging/erofs/unzip_pagevec.h
@@ -69,10 +69,7 @@ z_erofs_pagevec_ctor_next_page(struct z_erofs_pagevec_ctor *ctor,
if (tags == Z_EROFS_PAGE_TYPE_EXCLUSIVE)
return tagptr_unfold_ptr(t);
}
-
- if (unlikely(nr >= ctor->nr))
- BUG();
-
+ DBG_BUGON(nr >= ctor->nr);
return NULL;
}
diff --git a/drivers/staging/erofs/unzip_vle.c b/drivers/staging/erofs/unzip_vle.c
index 9ecaa872bae8..f0dab81ff816 100644
--- a/drivers/staging/erofs/unzip_vle.c
+++ b/drivers/staging/erofs/unzip_vle.c
@@ -11,6 +11,7 @@
* distribution for more details.
*/
#include "unzip_vle.h"
+#include "compress.h"
#include <linux/prefetch.h>
#include <trace/events/erofs.h>
@@ -329,7 +330,7 @@ try_to_claim_workgroup(struct z_erofs_vle_workgroup *grp,
z_erofs_vle_owned_workgrp_t *owned_head,
bool *hosted)
{
- DBG_BUGON(*hosted == true);
+ DBG_BUGON(*hosted);
/* let's claim these following types of workgroup */
retry:
@@ -468,6 +469,9 @@ z_erofs_vle_work_register(const struct z_erofs_vle_work_finder *f,
Z_EROFS_VLE_WORKGRP_FMT_LZ4 :
Z_EROFS_VLE_WORKGRP_FMT_PLAIN);
+ if (map->m_flags & EROFS_MAP_FULL_MAPPED)
+ grp->flags |= Z_EROFS_VLE_WORKGRP_FULL_LENGTH;
+
/* new workgrps have been claimed as type 1 */
WRITE_ONCE(grp->next, *f->owned_head);
/* primary and followed work for all new workgrps */
@@ -552,8 +556,7 @@ repeat:
if (IS_ERR(work))
return PTR_ERR(work);
got_it:
- z_erofs_pagevec_ctor_init(&builder->vector,
- Z_EROFS_VLE_INLINE_PAGEVECS,
+ z_erofs_pagevec_ctor_init(&builder->vector, Z_EROFS_NR_INLINE_PAGEVECS,
work->pagevec, work->vcnt);
if (builder->role >= Z_EROFS_VLE_WORK_PRIMARY) {
@@ -856,7 +859,7 @@ static inline void z_erofs_vle_read_endio(struct bio *bio)
DBG_BUGON(PageUptodate(page));
DBG_BUGON(!page->mapping);
- if (unlikely(!sbi && !z_erofs_is_stagingpage(page))) {
+ if (unlikely(!sbi && !z_erofs_page_is_staging(page))) {
sbi = EROFS_SB(page->mapping->host->i_sb);
if (time_to_inject(sbi, FAULT_READ_IO)) {
@@ -897,12 +900,12 @@ static int z_erofs_vle_unzip(struct super_block *sb,
unsigned int sparsemem_pages = 0;
struct page *pages_onstack[Z_EROFS_VLE_VMAP_ONSTACK_PAGES];
struct page **pages, **compressed_pages, *page;
- unsigned int i, llen;
+ unsigned int algorithm;
+ unsigned int i, outputsize;
enum z_erofs_page_type page_type;
- bool overlapped;
+ bool overlapped, partial;
struct z_erofs_vle_work *work;
- void *vout;
int err;
might_sleep();
@@ -936,7 +939,7 @@ repeat:
for (i = 0; i < nr_pages; ++i)
pages[i] = NULL;
- z_erofs_pagevec_ctor_init(&ctor, Z_EROFS_VLE_INLINE_PAGEVECS,
+ z_erofs_pagevec_ctor_init(&ctor, Z_EROFS_NR_INLINE_PAGEVECS,
work->pagevec, 0);
for (i = 0; i < work->vcnt; ++i) {
@@ -948,7 +951,7 @@ repeat:
DBG_BUGON(!page);
DBG_BUGON(!page->mapping);
- if (z_erofs_gather_if_stagingpage(page_pool, page))
+ if (z_erofs_put_stagingpage(page_pool, page))
continue;
if (page_type == Z_EROFS_VLE_PAGE_TYPE_HEAD)
@@ -978,7 +981,7 @@ repeat:
DBG_BUGON(!page);
DBG_BUGON(!page->mapping);
- if (!z_erofs_is_stagingpage(page)) {
+ if (!z_erofs_page_is_staging(page)) {
if (erofs_page_is_managed(sbi, page)) {
if (unlikely(!PageUptodate(page)))
err = -EIO;
@@ -1009,43 +1012,30 @@ repeat:
if (unlikely(err))
goto out;
- llen = (nr_pages << PAGE_SHIFT) - work->pageofs;
-
- if (z_erofs_vle_workgrp_fmt(grp) == Z_EROFS_VLE_WORKGRP_FMT_PLAIN) {
- err = z_erofs_vle_plain_copy(compressed_pages, clusterpages,
- pages, nr_pages, work->pageofs);
- goto out;
- }
-
- if (llen > grp->llen)
- llen = grp->llen;
-
- err = z_erofs_vle_unzip_fast_percpu(compressed_pages, clusterpages,
- pages, llen, work->pageofs);
- if (err != -ENOTSUPP)
- goto out;
-
- if (sparsemem_pages >= nr_pages)
- goto skip_allocpage;
-
- for (i = 0; i < nr_pages; ++i) {
- if (pages[i])
- continue;
-
- pages[i] = __stagingpage_alloc(page_pool, GFP_NOFS);
- }
-
-skip_allocpage:
- vout = erofs_vmap(pages, nr_pages);
- if (!vout) {
- err = -ENOMEM;
- goto out;
+ if (nr_pages << PAGE_SHIFT >= work->pageofs + grp->llen) {
+ outputsize = grp->llen;
+ partial = !(grp->flags & Z_EROFS_VLE_WORKGRP_FULL_LENGTH);
+ } else {
+ outputsize = (nr_pages << PAGE_SHIFT) - work->pageofs;
+ partial = true;
}
- err = z_erofs_vle_unzip_vmap(compressed_pages, clusterpages, vout,
- llen, work->pageofs, overlapped);
-
- erofs_vunmap(vout, nr_pages);
+ if (z_erofs_vle_workgrp_fmt(grp) == Z_EROFS_VLE_WORKGRP_FMT_PLAIN)
+ algorithm = Z_EROFS_COMPRESSION_SHIFTED;
+ else
+ algorithm = Z_EROFS_COMPRESSION_LZ4;
+
+ err = z_erofs_decompress(&(struct z_erofs_decompress_req) {
+ .sb = sb,
+ .in = compressed_pages,
+ .out = pages,
+ .pageofs_out = work->pageofs,
+ .inputsize = PAGE_SIZE,
+ .outputsize = outputsize,
+ .alg = algorithm,
+ .inplace_io = overlapped,
+ .partial_decoding = partial
+ }, page_pool);
out:
/* must handle all compressed pages before endding pages */
@@ -1056,7 +1046,7 @@ out:
continue;
/* recycle all individual staging pages */
- (void)z_erofs_gather_if_stagingpage(page_pool, page);
+ (void)z_erofs_put_stagingpage(page_pool, page);
WRITE_ONCE(compressed_pages[i], NULL);
}
@@ -1069,7 +1059,7 @@ out:
DBG_BUGON(!page->mapping);
/* recycle all individual staging pages */
- if (z_erofs_gather_if_stagingpage(page_pool, page))
+ if (z_erofs_put_stagingpage(page_pool, page))
continue;
if (unlikely(err < 0))
@@ -1273,8 +1263,7 @@ jobqueue_init(struct super_block *sb,
goto out;
}
- iosb = kvzalloc(sizeof(struct z_erofs_vle_unzip_io_sb),
- GFP_KERNEL | __GFP_NOFAIL);
+ iosb = kvzalloc(sizeof(*iosb), GFP_KERNEL | __GFP_NOFAIL);
DBG_BUGON(!iosb);
/* initialize fields in the allocated descriptor */
@@ -1600,289 +1589,3 @@ const struct address_space_operations z_erofs_vle_normalaccess_aops = {
.readpages = z_erofs_vle_normalaccess_readpages,
};
-/*
- * Variable-sized Logical Extent (Fixed Physical Cluster) Compression Mode
- * ---
- * VLE compression mode attempts to compress a number of logical data into
- * a physical cluster with a fixed size.
- * VLE compression mode uses "struct z_erofs_vle_decompressed_index".
- */
-#define __vle_cluster_advise(x, bit, bits) \
- ((le16_to_cpu(x) >> (bit)) & ((1 << (bits)) - 1))
-
-#define __vle_cluster_type(advise) __vle_cluster_advise(advise, \
- Z_EROFS_VLE_DI_CLUSTER_TYPE_BIT, Z_EROFS_VLE_DI_CLUSTER_TYPE_BITS)
-
-#define vle_cluster_type(di) \
- __vle_cluster_type((di)->di_advise)
-
-static int
-vle_decompressed_index_clusterofs(unsigned int *clusterofs,
- unsigned int clustersize,
- struct z_erofs_vle_decompressed_index *di)
-{
- switch (vle_cluster_type(di)) {
- case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
- *clusterofs = clustersize;
- break;
- case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
- case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
- *clusterofs = le16_to_cpu(di->di_clusterofs);
- break;
- default:
- DBG_BUGON(1);
- return -EIO;
- }
- return 0;
-}
-
-static inline erofs_blk_t
-vle_extent_blkaddr(struct inode *inode, pgoff_t index)
-{
- struct erofs_sb_info *sbi = EROFS_I_SB(inode);
- struct erofs_vnode *vi = EROFS_V(inode);
-
- unsigned int ofs = Z_EROFS_VLE_EXTENT_ALIGN(vi->inode_isize +
- vi->xattr_isize) + sizeof(struct erofs_extent_header) +
- index * sizeof(struct z_erofs_vle_decompressed_index);
-
- return erofs_blknr(iloc(sbi, vi->nid) + ofs);
-}
-
-static inline unsigned int
-vle_extent_blkoff(struct inode *inode, pgoff_t index)
-{
- struct erofs_sb_info *sbi = EROFS_I_SB(inode);
- struct erofs_vnode *vi = EROFS_V(inode);
-
- unsigned int ofs = Z_EROFS_VLE_EXTENT_ALIGN(vi->inode_isize +
- vi->xattr_isize) + sizeof(struct erofs_extent_header) +
- index * sizeof(struct z_erofs_vle_decompressed_index);
-
- return erofs_blkoff(iloc(sbi, vi->nid) + ofs);
-}
-
-struct vle_map_blocks_iter_ctx {
- struct inode *inode;
- struct super_block *sb;
- unsigned int clusterbits;
-
- struct page **mpage_ret;
- void **kaddr_ret;
-};
-
-static int
-vle_get_logical_extent_head(const struct vle_map_blocks_iter_ctx *ctx,
- unsigned int lcn, /* logical cluster number */
- unsigned long long *ofs,
- erofs_blk_t *pblk,
- unsigned int *flags)
-{
- const unsigned int clustersize = 1 << ctx->clusterbits;
- const erofs_blk_t mblk = vle_extent_blkaddr(ctx->inode, lcn);
- struct page *mpage = *ctx->mpage_ret; /* extent metapage */
-
- struct z_erofs_vle_decompressed_index *di;
- unsigned int cluster_type, delta0;
-
- if (mpage->index != mblk) {
- kunmap_atomic(*ctx->kaddr_ret);
- unlock_page(mpage);
- put_page(mpage);
-
- mpage = erofs_get_meta_page(ctx->sb, mblk, false);
- if (IS_ERR(mpage)) {
- *ctx->mpage_ret = NULL;
- return PTR_ERR(mpage);
- }
- *ctx->mpage_ret = mpage;
- *ctx->kaddr_ret = kmap_atomic(mpage);
- }
-
- di = *ctx->kaddr_ret + vle_extent_blkoff(ctx->inode, lcn);
-
- cluster_type = vle_cluster_type(di);
- switch (cluster_type) {
- case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
- delta0 = le16_to_cpu(di->di_u.delta[0]);
- if (unlikely(!delta0 || delta0 > lcn)) {
- errln("invalid NONHEAD dl0 %u at lcn %u of nid %llu",
- delta0, lcn, EROFS_V(ctx->inode)->nid);
- DBG_BUGON(1);
- return -EIO;
- }
- return vle_get_logical_extent_head(ctx,
- lcn - delta0, ofs, pblk, flags);
- case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
- *flags ^= EROFS_MAP_ZIPPED;
- /* fallthrough */
- case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
- /* clustersize should be a power of two */
- *ofs = ((u64)lcn << ctx->clusterbits) +
- (le16_to_cpu(di->di_clusterofs) & (clustersize - 1));
- *pblk = le32_to_cpu(di->di_u.blkaddr);
- break;
- default:
- errln("unknown cluster type %u at lcn %u of nid %llu",
- cluster_type, lcn, EROFS_V(ctx->inode)->nid);
- DBG_BUGON(1);
- return -EIO;
- }
- return 0;
-}
-
-int z_erofs_map_blocks_iter(struct inode *inode,
- struct erofs_map_blocks *map,
- int flags)
-{
- void *kaddr;
- const struct vle_map_blocks_iter_ctx ctx = {
- .inode = inode,
- .sb = inode->i_sb,
- .clusterbits = EROFS_I_SB(inode)->clusterbits,
- .mpage_ret = &map->mpage,
- .kaddr_ret = &kaddr
- };
- const unsigned int clustersize = 1 << ctx.clusterbits;
- /* if both m_(l,p)len are 0, regularize l_lblk, l_lofs, etc... */
- const bool initial = !map->m_llen;
-
- /* logicial extent (start, end) offset */
- unsigned long long ofs, end;
- unsigned int lcn;
- u32 ofs_rem;
-
- /* initialize `pblk' to keep gcc from printing foolish warnings */
- erofs_blk_t mblk, pblk = 0;
- struct page *mpage = map->mpage;
- struct z_erofs_vle_decompressed_index *di;
- unsigned int cluster_type, logical_cluster_ofs;
- int err = 0;
-
- trace_z_erofs_map_blocks_iter_enter(inode, map, flags);
-
- /* when trying to read beyond EOF, leave it unmapped */
- if (unlikely(map->m_la >= inode->i_size)) {
- DBG_BUGON(!initial);
- map->m_llen = map->m_la + 1 - inode->i_size;
- map->m_la = inode->i_size;
- map->m_flags = 0;
- goto out;
- }
-
- debugln("%s, m_la %llu m_llen %llu --- start", __func__,
- map->m_la, map->m_llen);
-
- ofs = map->m_la + map->m_llen;
-
- /* clustersize should be power of two */
- lcn = ofs >> ctx.clusterbits;
- ofs_rem = ofs & (clustersize - 1);
-
- mblk = vle_extent_blkaddr(inode, lcn);
-
- if (!mpage || mpage->index != mblk) {
- if (mpage)
- put_page(mpage);
-
- mpage = erofs_get_meta_page(ctx.sb, mblk, false);
- if (IS_ERR(mpage)) {
- err = PTR_ERR(mpage);
- goto out;
- }
- map->mpage = mpage;
- } else {
- lock_page(mpage);
- DBG_BUGON(!PageUptodate(mpage));
- }
-
- kaddr = kmap_atomic(mpage);
- di = kaddr + vle_extent_blkoff(inode, lcn);
-
- debugln("%s, lcn %u mblk %u e_blkoff %u", __func__, lcn,
- mblk, vle_extent_blkoff(inode, lcn));
-
- err = vle_decompressed_index_clusterofs(&logical_cluster_ofs,
- clustersize, di);
- if (unlikely(err))
- goto unmap_out;
-
- if (!initial) {
- /* [walking mode] 'map' has been already initialized */
- map->m_llen += logical_cluster_ofs;
- goto unmap_out;
- }
-
- /* by default, compressed */
- map->m_flags |= EROFS_MAP_ZIPPED;
-
- end = ((u64)lcn + 1) * clustersize;
-
- cluster_type = vle_cluster_type(di);
-
- switch (cluster_type) {
- case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
- if (ofs_rem >= logical_cluster_ofs)
- map->m_flags ^= EROFS_MAP_ZIPPED;
- /* fallthrough */
- case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
- if (ofs_rem == logical_cluster_ofs) {
- pblk = le32_to_cpu(di->di_u.blkaddr);
- goto exact_hitted;
- }
-
- if (ofs_rem > logical_cluster_ofs) {
- ofs = (u64)lcn * clustersize | logical_cluster_ofs;
- pblk = le32_to_cpu(di->di_u.blkaddr);
- break;
- }
-
- /* logical cluster number should be >= 1 */
- if (unlikely(!lcn)) {
- errln("invalid logical cluster 0 at nid %llu",
- EROFS_V(inode)->nid);
- err = -EIO;
- goto unmap_out;
- }
- end = ((u64)lcn-- * clustersize) | logical_cluster_ofs;
- /* fallthrough */
- case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
- /* get the correspoinding first chunk */
- err = vle_get_logical_extent_head(&ctx, lcn, &ofs,
- &pblk, &map->m_flags);
- mpage = map->mpage;
-
- if (unlikely(err)) {
- if (mpage)
- goto unmap_out;
- goto out;
- }
- break;
- default:
- errln("unknown cluster type %u at offset %llu of nid %llu",
- cluster_type, ofs, EROFS_V(inode)->nid);
- err = -EIO;
- goto unmap_out;
- }
-
- map->m_la = ofs;
-exact_hitted:
- map->m_llen = end - ofs;
- map->m_plen = clustersize;
- map->m_pa = blknr_to_addr(pblk);
- map->m_flags |= EROFS_MAP_MAPPED;
-unmap_out:
- kunmap_atomic(kaddr);
- unlock_page(mpage);
-out:
- debugln("%s, m_la %llu m_pa %llu m_llen %llu m_plen %llu m_flags 0%o",
- __func__, map->m_la, map->m_pa,
- map->m_llen, map->m_plen, map->m_flags);
-
- trace_z_erofs_map_blocks_iter_exit(inode, map, flags, err);
-
- /* aggressively BUG_ON iff CONFIG_EROFS_FS_DEBUG is on */
- DBG_BUGON(err < 0 && err != -ENOMEM);
- return err;
-}
-
diff --git a/drivers/staging/erofs/unzip_vle.h b/drivers/staging/erofs/unzip_vle.h
index 517e5ce8c5e9..ab509d75aefd 100644
--- a/drivers/staging/erofs/unzip_vle.h
+++ b/drivers/staging/erofs/unzip_vle.h
@@ -16,25 +16,7 @@
#include "internal.h"
#include "unzip_pagevec.h"
-/*
- * - 0x5A110C8D ('sallocated', Z_EROFS_MAPPING_STAGING) -
- * used for temporary allocated pages (via erofs_allocpage),
- * in order to seperate those from NULL mapping (eg. truncated pages)
- */
-#define Z_EROFS_MAPPING_STAGING ((void *)0x5A110C8D)
-
-#define z_erofs_is_stagingpage(page) \
- ((page)->mapping == Z_EROFS_MAPPING_STAGING)
-
-static inline bool z_erofs_gather_if_stagingpage(struct list_head *page_pool,
- struct page *page)
-{
- if (z_erofs_is_stagingpage(page)) {
- list_add(&page->lru, page_pool);
- return true;
- }
- return false;
-}
+#define Z_EROFS_NR_INLINE_PAGEVECS 3
/*
* Structure fields follow one of the following exclusion rules.
@@ -44,8 +26,6 @@ static inline bool z_erofs_gather_if_stagingpage(struct list_head *page_pool,
*
*/
-#define Z_EROFS_VLE_INLINE_PAGEVECS 3
-
struct z_erofs_vle_work {
struct mutex lock;
@@ -58,7 +38,7 @@ struct z_erofs_vle_work {
union {
/* L: pagevec */
- erofs_vtptr_t pagevec[Z_EROFS_VLE_INLINE_PAGEVECS];
+ erofs_vtptr_t pagevec[Z_EROFS_NR_INLINE_PAGEVECS];
struct rcu_head rcu;
};
};
@@ -66,6 +46,7 @@ struct z_erofs_vle_work {
#define Z_EROFS_VLE_WORKGRP_FMT_PLAIN 0
#define Z_EROFS_VLE_WORKGRP_FMT_LZ4 1
#define Z_EROFS_VLE_WORKGRP_FMT_MASK 1
+#define Z_EROFS_VLE_WORKGRP_FULL_LENGTH 2
typedef void *z_erofs_vle_owned_workgrp_t;
@@ -147,7 +128,7 @@ static inline unsigned z_erofs_onlinepage_index(struct page *page)
{
union z_erofs_onlinepage_converter u;
- BUG_ON(!PagePrivate(page));
+ DBG_BUGON(!PagePrivate(page));
u.v = &page_private(page);
return atomic_read(u.o) >> Z_EROFS_ONLINEPAGE_INDEX_SHIFT;
@@ -179,7 +160,7 @@ repeat:
if (!index)
return;
- BUG_ON(id != index);
+ DBG_BUGON(id != index);
}
v = (index << Z_EROFS_ONLINEPAGE_INDEX_SHIFT) |
@@ -193,7 +174,7 @@ static inline void z_erofs_onlinepage_endio(struct page *page)
union z_erofs_onlinepage_converter u;
unsigned v;
- BUG_ON(!PagePrivate(page));
+ DBG_BUGON(!PagePrivate(page));
u.v = &page_private(page);
v = atomic_dec_return(u.o);
@@ -211,18 +192,5 @@ static inline void z_erofs_onlinepage_endio(struct page *page)
min_t(unsigned int, THREAD_SIZE / 8 / sizeof(struct page *), 96U)
#define Z_EROFS_VLE_VMAP_GLOBAL_PAGES 2048
-/* unzip_vle_lz4.c */
-int z_erofs_vle_plain_copy(struct page **compressed_pages,
- unsigned int clusterpages, struct page **pages,
- unsigned int nr_pages, unsigned short pageofs);
-int z_erofs_vle_unzip_fast_percpu(struct page **compressed_pages,
- unsigned int clusterpages,
- struct page **pages, unsigned int outlen,
- unsigned short pageofs);
-int z_erofs_vle_unzip_vmap(struct page **compressed_pages,
- unsigned int clusterpages,
- void *vaddr, unsigned int llen,
- unsigned short pageofs, bool overlapped);
-
#endif
diff --git a/drivers/staging/erofs/unzip_vle_lz4.c b/drivers/staging/erofs/unzip_vle_lz4.c
deleted file mode 100644
index 0daac9b984a8..000000000000
--- a/drivers/staging/erofs/unzip_vle_lz4.c
+++ /dev/null
@@ -1,229 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * linux/drivers/staging/erofs/unzip_vle_lz4.c
- *
- * Copyright (C) 2018 HUAWEI, Inc.
- * http://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of the Linux
- * distribution for more details.
- */
-#include "unzip_vle.h"
-#include <linux/lz4.h>
-
-static int z_erofs_unzip_lz4(void *in, void *out, size_t inlen, size_t outlen)
-{
- int ret = LZ4_decompress_safe_partial(in, out, inlen, outlen, outlen);
-
- if (ret >= 0)
- return ret;
-
- /*
- * LZ4_decompress_safe_partial will return an error code
- * (< 0) if decompression failed
- */
- errln("%s, failed to decompress, in[%p, %zu] outlen[%p, %zu]",
- __func__, in, inlen, out, outlen);
- WARN_ON(1);
- print_hex_dump(KERN_DEBUG, "raw data [in]: ", DUMP_PREFIX_OFFSET,
- 16, 1, in, inlen, true);
- print_hex_dump(KERN_DEBUG, "raw data [out]: ", DUMP_PREFIX_OFFSET,
- 16, 1, out, outlen, true);
- return -EIO;
-}
-
-#if Z_EROFS_CLUSTER_MAX_PAGES > Z_EROFS_VLE_INLINE_PAGEVECS
-#define EROFS_PERCPU_NR_PAGES Z_EROFS_CLUSTER_MAX_PAGES
-#else
-#define EROFS_PERCPU_NR_PAGES Z_EROFS_VLE_INLINE_PAGEVECS
-#endif
-
-static struct {
- char data[PAGE_SIZE * EROFS_PERCPU_NR_PAGES];
-} erofs_pcpubuf[NR_CPUS];
-
-int z_erofs_vle_plain_copy(struct page **compressed_pages,
- unsigned int clusterpages,
- struct page **pages,
- unsigned int nr_pages,
- unsigned short pageofs)
-{
- unsigned int i, j;
- void *src = NULL;
- const unsigned int righthalf = PAGE_SIZE - pageofs;
- char *percpu_data;
- bool mirrored[Z_EROFS_CLUSTER_MAX_PAGES] = { 0 };
-
- preempt_disable();
- percpu_data = erofs_pcpubuf[smp_processor_id()].data;
-
- j = 0;
- for (i = 0; i < nr_pages; j = i++) {
- struct page *page = pages[i];
- void *dst;
-
- if (!page) {
- if (src) {
- if (!mirrored[j])
- kunmap_atomic(src);
- src = NULL;
- }
- continue;
- }
-
- dst = kmap_atomic(page);
-
- for (; j < clusterpages; ++j) {
- if (compressed_pages[j] != page)
- continue;
-
- DBG_BUGON(mirrored[j]);
- memcpy(percpu_data + j * PAGE_SIZE, dst, PAGE_SIZE);
- mirrored[j] = true;
- break;
- }
-
- if (i) {
- if (!src)
- src = mirrored[i - 1] ?
- percpu_data + (i - 1) * PAGE_SIZE :
- kmap_atomic(compressed_pages[i - 1]);
-
- memcpy(dst, src + righthalf, pageofs);
-
- if (!mirrored[i - 1])
- kunmap_atomic(src);
-
- if (unlikely(i >= clusterpages)) {
- kunmap_atomic(dst);
- break;
- }
- }
-
- if (!righthalf) {
- src = NULL;
- } else {
- src = mirrored[i] ? percpu_data + i * PAGE_SIZE :
- kmap_atomic(compressed_pages[i]);
-
- memcpy(dst + pageofs, src, righthalf);
- }
-
- kunmap_atomic(dst);
- }
-
- if (src && !mirrored[j])
- kunmap_atomic(src);
-
- preempt_enable();
- return 0;
-}
-
-int z_erofs_vle_unzip_fast_percpu(struct page **compressed_pages,
- unsigned int clusterpages,
- struct page **pages,
- unsigned int outlen,
- unsigned short pageofs)
-{
- void *vin, *vout;
- unsigned int nr_pages, i, j;
- int ret;
-
- if (outlen + pageofs > EROFS_PERCPU_NR_PAGES * PAGE_SIZE)
- return -ENOTSUPP;
-
- nr_pages = DIV_ROUND_UP(outlen + pageofs, PAGE_SIZE);
-
- if (clusterpages == 1) {
- vin = kmap_atomic(compressed_pages[0]);
- } else {
- vin = erofs_vmap(compressed_pages, clusterpages);
- if (!vin)
- return -ENOMEM;
- }
-
- preempt_disable();
- vout = erofs_pcpubuf[smp_processor_id()].data;
-
- ret = z_erofs_unzip_lz4(vin, vout + pageofs,
- clusterpages * PAGE_SIZE, outlen);
-
- if (ret < 0)
- goto out;
- ret = 0;
-
- for (i = 0; i < nr_pages; ++i) {
- j = min((unsigned int)PAGE_SIZE - pageofs, outlen);
-
- if (pages[i]) {
- if (clusterpages == 1 &&
- pages[i] == compressed_pages[0]) {
- memcpy(vin + pageofs, vout + pageofs, j);
- } else {
- void *dst = kmap_atomic(pages[i]);
-
- memcpy(dst + pageofs, vout + pageofs, j);
- kunmap_atomic(dst);
- }
- }
- vout += PAGE_SIZE;
- outlen -= j;
- pageofs = 0;
- }
-
-out:
- preempt_enable();
-
- if (clusterpages == 1)
- kunmap_atomic(vin);
- else
- erofs_vunmap(vin, clusterpages);
-
- return ret;
-}
-
-int z_erofs_vle_unzip_vmap(struct page **compressed_pages,
- unsigned int clusterpages,
- void *vout,
- unsigned int llen,
- unsigned short pageofs,
- bool overlapped)
-{
- void *vin;
- unsigned int i;
- int ret;
-
- if (overlapped) {
- preempt_disable();
- vin = erofs_pcpubuf[smp_processor_id()].data;
-
- for (i = 0; i < clusterpages; ++i) {
- void *t = kmap_atomic(compressed_pages[i]);
-
- memcpy(vin + PAGE_SIZE * i, t, PAGE_SIZE);
- kunmap_atomic(t);
- }
- } else if (clusterpages == 1) {
- vin = kmap_atomic(compressed_pages[0]);
- } else {
- vin = erofs_vmap(compressed_pages, clusterpages);
- }
-
- ret = z_erofs_unzip_lz4(vin, vout + pageofs,
- clusterpages * PAGE_SIZE, llen);
- if (ret > 0)
- ret = 0;
-
- if (!overlapped) {
- if (clusterpages == 1)
- kunmap_atomic(vin);
- else
- erofs_vunmap(vin, clusterpages);
- } else {
- preempt_enable();
- }
- return ret;
-}
-
diff --git a/drivers/staging/erofs/utils.c b/drivers/staging/erofs/utils.c
index 3e7d30b6de1d..4bbd3bf34acd 100644
--- a/drivers/staging/erofs/utils.c
+++ b/drivers/staging/erofs/utils.c
@@ -27,6 +27,18 @@ struct page *erofs_allocpage(struct list_head *pool, gfp_t gfp)
return page;
}
+#if (EROFS_PCPUBUF_NR_PAGES > 0)
+static struct {
+ u8 data[PAGE_SIZE * EROFS_PCPUBUF_NR_PAGES];
+} ____cacheline_aligned_in_smp erofs_pcpubuf[NR_CPUS];
+
+void *erofs_get_pcpubuf(unsigned int pagenr)
+{
+ preempt_disable();
+ return &erofs_pcpubuf[smp_processor_id()].data[pagenr * PAGE_SIZE];
+}
+#endif
+
/* global shrink count (for all mounted EROFS instances) */
static atomic_long_t erofs_global_shrink_cnt;
diff --git a/drivers/staging/erofs/zmap.c b/drivers/staging/erofs/zmap.c
new file mode 100644
index 000000000000..9c0bd65c46bf
--- /dev/null
+++ b/drivers/staging/erofs/zmap.c
@@ -0,0 +1,463 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * linux/drivers/staging/erofs/zmap.c
+ *
+ * Copyright (C) 2018-2019 HUAWEI, Inc.
+ * http://www.huawei.com/
+ * Created by Gao Xiang <gaoxiang25@huawei.com>
+ */
+#include "internal.h"
+#include <asm/unaligned.h>
+#include <trace/events/erofs.h>
+
+int z_erofs_fill_inode(struct inode *inode)
+{
+ struct erofs_vnode *const vi = EROFS_V(inode);
+ struct super_block *const sb = inode->i_sb;
+
+ if (vi->datamode == EROFS_INODE_FLAT_COMPRESSION_LEGACY) {
+ vi->z_advise = 0;
+ vi->z_algorithmtype[0] = 0;
+ vi->z_algorithmtype[1] = 0;
+ vi->z_logical_clusterbits = EROFS_SB(sb)->clusterbits;
+ vi->z_physical_clusterbits[0] = vi->z_logical_clusterbits;
+ vi->z_physical_clusterbits[1] = vi->z_logical_clusterbits;
+ set_bit(EROFS_V_Z_INITED_BIT, &vi->flags);
+ }
+
+ inode->i_mapping->a_ops = &z_erofs_vle_normalaccess_aops;
+ return 0;
+}
+
+static int fill_inode_lazy(struct inode *inode)
+{
+ struct erofs_vnode *const vi = EROFS_V(inode);
+ struct super_block *const sb = inode->i_sb;
+ int err;
+ erofs_off_t pos;
+ struct page *page;
+ void *kaddr;
+ struct z_erofs_map_header *h;
+
+ if (test_bit(EROFS_V_Z_INITED_BIT, &vi->flags))
+ return 0;
+
+ if (wait_on_bit_lock(&vi->flags, EROFS_V_BL_Z_BIT, TASK_KILLABLE))
+ return -ERESTARTSYS;
+
+ err = 0;
+ if (test_bit(EROFS_V_Z_INITED_BIT, &vi->flags))
+ goto out_unlock;
+
+ DBG_BUGON(vi->datamode == EROFS_INODE_FLAT_COMPRESSION_LEGACY);
+
+ pos = ALIGN(iloc(EROFS_SB(sb), vi->nid) + vi->inode_isize +
+ vi->xattr_isize, 8);
+ page = erofs_get_meta_page(sb, erofs_blknr(pos), false);
+ if (IS_ERR(page)) {
+ err = PTR_ERR(page);
+ goto out_unlock;
+ }
+
+ kaddr = kmap_atomic(page);
+
+ h = kaddr + erofs_blkoff(pos);
+ vi->z_advise = le16_to_cpu(h->h_advise);
+ vi->z_algorithmtype[0] = h->h_algorithmtype & 15;
+ vi->z_algorithmtype[1] = h->h_algorithmtype >> 4;
+
+ if (vi->z_algorithmtype[0] >= Z_EROFS_COMPRESSION_MAX) {
+ errln("unknown compression format %u for nid %llu, please upgrade kernel",
+ vi->z_algorithmtype[0], vi->nid);
+ err = -ENOTSUPP;
+ goto unmap_done;
+ }
+
+ vi->z_logical_clusterbits = LOG_BLOCK_SIZE + (h->h_clusterbits & 7);
+ vi->z_physical_clusterbits[0] = vi->z_logical_clusterbits +
+ ((h->h_clusterbits >> 3) & 3);
+
+ if (vi->z_physical_clusterbits[0] != LOG_BLOCK_SIZE) {
+ errln("unsupported physical clusterbits %u for nid %llu, please upgrade kernel",
+ vi->z_physical_clusterbits[0], vi->nid);
+ err = -ENOTSUPP;
+ goto unmap_done;
+ }
+
+ vi->z_physical_clusterbits[1] = vi->z_logical_clusterbits +
+ ((h->h_clusterbits >> 5) & 7);
+unmap_done:
+ kunmap_atomic(kaddr);
+ unlock_page(page);
+ put_page(page);
+
+ set_bit(EROFS_V_Z_INITED_BIT, &vi->flags);
+out_unlock:
+ clear_and_wake_up_bit(EROFS_V_BL_Z_BIT, &vi->flags);
+ return err;
+}
+
+struct z_erofs_maprecorder {
+ struct inode *inode;
+ struct erofs_map_blocks *map;
+ void *kaddr;
+
+ unsigned long lcn;
+ /* compression extent information gathered */
+ u8 type;
+ u16 clusterofs;
+ u16 delta[2];
+ erofs_blk_t pblk;
+};
+
+static int z_erofs_reload_indexes(struct z_erofs_maprecorder *m,
+ erofs_blk_t eblk)
+{
+ struct super_block *const sb = m->inode->i_sb;
+ struct erofs_map_blocks *const map = m->map;
+ struct page *mpage = map->mpage;
+
+ if (mpage) {
+ if (mpage->index == eblk) {
+ if (!m->kaddr)
+ m->kaddr = kmap_atomic(mpage);
+ return 0;
+ }
+
+ if (m->kaddr) {
+ kunmap_atomic(m->kaddr);
+ m->kaddr = NULL;
+ }
+ put_page(mpage);
+ }
+
+ mpage = erofs_get_meta_page(sb, eblk, false);
+ if (IS_ERR(mpage)) {
+ map->mpage = NULL;
+ return PTR_ERR(mpage);
+ }
+ m->kaddr = kmap_atomic(mpage);
+ unlock_page(mpage);
+ map->mpage = mpage;
+ return 0;
+}
+
+static int vle_legacy_load_cluster_from_disk(struct z_erofs_maprecorder *m,
+ unsigned long lcn)
+{
+ struct inode *const inode = m->inode;
+ struct erofs_vnode *const vi = EROFS_V(inode);
+ const erofs_off_t ibase = iloc(EROFS_I_SB(inode), vi->nid);
+ const erofs_off_t pos =
+ Z_EROFS_VLE_LEGACY_INDEX_ALIGN(ibase + vi->inode_isize +
+ vi->xattr_isize) +
+ lcn * sizeof(struct z_erofs_vle_decompressed_index);
+ struct z_erofs_vle_decompressed_index *di;
+ unsigned int advise, type;
+ int err;
+
+ err = z_erofs_reload_indexes(m, erofs_blknr(pos));
+ if (err)
+ return err;
+
+ m->lcn = lcn;
+ di = m->kaddr + erofs_blkoff(pos);
+
+ advise = le16_to_cpu(di->di_advise);
+ type = (advise >> Z_EROFS_VLE_DI_CLUSTER_TYPE_BIT) &
+ ((1 << Z_EROFS_VLE_DI_CLUSTER_TYPE_BITS) - 1);
+ switch (type) {
+ case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
+ m->clusterofs = 1 << vi->z_logical_clusterbits;
+ m->delta[0] = le16_to_cpu(di->di_u.delta[0]);
+ m->delta[1] = le16_to_cpu(di->di_u.delta[1]);
+ break;
+ case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
+ case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
+ m->clusterofs = le16_to_cpu(di->di_clusterofs);
+ m->pblk = le32_to_cpu(di->di_u.blkaddr);
+ break;
+ default:
+ DBG_BUGON(1);
+ return -EIO;
+ }
+ m->type = type;
+ return 0;
+}
+
+static unsigned int decode_compactedbits(unsigned int lobits,
+ unsigned int lomask,
+ u8 *in, unsigned int pos, u8 *type)
+{
+ const unsigned int v = get_unaligned_le32(in + pos / 8) >> (pos & 7);
+ const unsigned int lo = v & lomask;
+
+ *type = (v >> lobits) & 3;
+ return lo;
+}
+
+static int unpack_compacted_index(struct z_erofs_maprecorder *m,
+ unsigned int amortizedshift,
+ unsigned int eofs)
+{
+ struct erofs_vnode *const vi = EROFS_V(m->inode);
+ const unsigned int lclusterbits = vi->z_logical_clusterbits;
+ const unsigned int lomask = (1 << lclusterbits) - 1;
+ unsigned int vcnt, base, lo, encodebits, nblk;
+ int i;
+ u8 *in, type;
+
+ if (1 << amortizedshift == 4)
+ vcnt = 2;
+ else if (1 << amortizedshift == 2 && lclusterbits == 12)
+ vcnt = 16;
+ else
+ return -ENOTSUPP;
+
+ encodebits = ((vcnt << amortizedshift) - sizeof(__le32)) * 8 / vcnt;
+ base = round_down(eofs, vcnt << amortizedshift);
+ in = m->kaddr + base;
+
+ i = (eofs - base) >> amortizedshift;
+
+ lo = decode_compactedbits(lclusterbits, lomask,
+ in, encodebits * i, &type);
+ m->type = type;
+ if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) {
+ m->clusterofs = 1 << lclusterbits;
+ if (i + 1 != vcnt) {
+ m->delta[0] = lo;
+ return 0;
+ }
+ /*
+ * since the last lcluster in the pack is special,
+ * of which lo saves delta[1] rather than delta[0].
+ * Hence, get delta[0] by the previous lcluster indirectly.
+ */
+ lo = decode_compactedbits(lclusterbits, lomask,
+ in, encodebits * (i - 1), &type);
+ if (type != Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD)
+ lo = 0;
+ m->delta[0] = lo + 1;
+ return 0;
+ }
+ m->clusterofs = lo;
+ m->delta[0] = 0;
+ /* figout out blkaddr (pblk) for HEAD lclusters */
+ nblk = 1;
+ while (i > 0) {
+ --i;
+ lo = decode_compactedbits(lclusterbits, lomask,
+ in, encodebits * i, &type);
+ if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD)
+ i -= lo;
+
+ if (i >= 0)
+ ++nblk;
+ }
+ in += (vcnt << amortizedshift) - sizeof(__le32);
+ m->pblk = le32_to_cpu(*(__le32 *)in) + nblk;
+ return 0;
+}
+
+static int compacted_load_cluster_from_disk(struct z_erofs_maprecorder *m,
+ unsigned long lcn)
+{
+ struct inode *const inode = m->inode;
+ struct erofs_vnode *const vi = EROFS_V(inode);
+ const unsigned int lclusterbits = vi->z_logical_clusterbits;
+ const erofs_off_t ebase = ALIGN(iloc(EROFS_I_SB(inode), vi->nid) +
+ vi->inode_isize + vi->xattr_isize, 8) +
+ sizeof(struct z_erofs_map_header);
+ const unsigned int totalidx = DIV_ROUND_UP(inode->i_size, EROFS_BLKSIZ);
+ unsigned int compacted_4b_initial, compacted_2b;
+ unsigned int amortizedshift;
+ erofs_off_t pos;
+ int err;
+
+ if (lclusterbits != 12)
+ return -ENOTSUPP;
+
+ if (lcn >= totalidx)
+ return -EINVAL;
+
+ m->lcn = lcn;
+ /* used to align to 32-byte (compacted_2b) alignment */
+ compacted_4b_initial = (32 - ebase % 32) / 4;
+ if (compacted_4b_initial == 32 / 4)
+ compacted_4b_initial = 0;
+
+ if (vi->z_advise & Z_EROFS_ADVISE_COMPACTED_2B)
+ compacted_2b = rounddown(totalidx - compacted_4b_initial, 16);
+ else
+ compacted_2b = 0;
+
+ pos = ebase;
+ if (lcn < compacted_4b_initial) {
+ amortizedshift = 2;
+ goto out;
+ }
+ pos += compacted_4b_initial * 4;
+ lcn -= compacted_4b_initial;
+
+ if (lcn < compacted_2b) {
+ amortizedshift = 1;
+ goto out;
+ }
+ pos += compacted_2b * 2;
+ lcn -= compacted_2b;
+ amortizedshift = 2;
+out:
+ pos += lcn * (1 << amortizedshift);
+ err = z_erofs_reload_indexes(m, erofs_blknr(pos));
+ if (err)
+ return err;
+ return unpack_compacted_index(m, amortizedshift, erofs_blkoff(pos));
+}
+
+static int vle_load_cluster_from_disk(struct z_erofs_maprecorder *m,
+ unsigned int lcn)
+{
+ const unsigned int datamode = EROFS_V(m->inode)->datamode;
+
+ if (datamode == EROFS_INODE_FLAT_COMPRESSION_LEGACY)
+ return vle_legacy_load_cluster_from_disk(m, lcn);
+
+ if (datamode == EROFS_INODE_FLAT_COMPRESSION)
+ return compacted_load_cluster_from_disk(m, lcn);
+
+ return -EINVAL;
+}
+
+static int vle_extent_lookback(struct z_erofs_maprecorder *m,
+ unsigned int lookback_distance)
+{
+ struct erofs_vnode *const vi = EROFS_V(m->inode);
+ struct erofs_map_blocks *const map = m->map;
+ const unsigned int lclusterbits = vi->z_logical_clusterbits;
+ unsigned long lcn = m->lcn;
+ int err;
+
+ if (lcn < lookback_distance) {
+ DBG_BUGON(1);
+ return -EIO;
+ }
+
+ /* load extent head logical cluster if needed */
+ lcn -= lookback_distance;
+ err = vle_load_cluster_from_disk(m, lcn);
+ if (err)
+ return err;
+
+ switch (m->type) {
+ case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
+ return vle_extent_lookback(m, m->delta[0]);
+ case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
+ map->m_flags &= ~EROFS_MAP_ZIPPED;
+ /* fallthrough */
+ case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
+ map->m_la = (lcn << lclusterbits) | m->clusterofs;
+ break;
+ default:
+ errln("unknown type %u at lcn %lu of nid %llu",
+ m->type, lcn, vi->nid);
+ DBG_BUGON(1);
+ return -EIO;
+ }
+ return 0;
+}
+
+int z_erofs_map_blocks_iter(struct inode *inode,
+ struct erofs_map_blocks *map,
+ int flags)
+{
+ struct erofs_vnode *const vi = EROFS_V(inode);
+ struct z_erofs_maprecorder m = {
+ .inode = inode,
+ .map = map,
+ };
+ int err = 0;
+ unsigned int lclusterbits, endoff;
+ unsigned long long ofs, end;
+
+ trace_z_erofs_map_blocks_iter_enter(inode, map, flags);
+
+ /* when trying to read beyond EOF, leave it unmapped */
+ if (unlikely(map->m_la >= inode->i_size)) {
+ map->m_llen = map->m_la + 1 - inode->i_size;
+ map->m_la = inode->i_size;
+ map->m_flags = 0;
+ goto out;
+ }
+
+ err = fill_inode_lazy(inode);
+ if (err)
+ goto out;
+
+ lclusterbits = vi->z_logical_clusterbits;
+ ofs = map->m_la;
+ m.lcn = ofs >> lclusterbits;
+ endoff = ofs & ((1 << lclusterbits) - 1);
+
+ err = vle_load_cluster_from_disk(&m, m.lcn);
+ if (err)
+ goto unmap_out;
+
+ map->m_flags = EROFS_MAP_ZIPPED; /* by default, compressed */
+ end = (m.lcn + 1ULL) << lclusterbits;
+
+ switch (m.type) {
+ case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
+ if (endoff >= m.clusterofs)
+ map->m_flags &= ~EROFS_MAP_ZIPPED;
+ /* fallthrough */
+ case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
+ if (endoff >= m.clusterofs) {
+ map->m_la = (m.lcn << lclusterbits) | m.clusterofs;
+ break;
+ }
+ /* m.lcn should be >= 1 if endoff < m.clusterofs */
+ if (unlikely(!m.lcn)) {
+ errln("invalid logical cluster 0 at nid %llu",
+ vi->nid);
+ err = -EIO;
+ goto unmap_out;
+ }
+ end = (m.lcn << lclusterbits) | m.clusterofs;
+ map->m_flags |= EROFS_MAP_FULL_MAPPED;
+ m.delta[0] = 1;
+ /* fallthrough */
+ case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
+ /* get the correspoinding first chunk */
+ err = vle_extent_lookback(&m, m.delta[0]);
+ if (unlikely(err))
+ goto unmap_out;
+ break;
+ default:
+ errln("unknown type %u at offset %llu of nid %llu",
+ m.type, ofs, vi->nid);
+ err = -EIO;
+ goto unmap_out;
+ }
+
+ map->m_llen = end - map->m_la;
+ map->m_plen = 1 << lclusterbits;
+ map->m_pa = blknr_to_addr(m.pblk);
+ map->m_flags |= EROFS_MAP_MAPPED;
+
+unmap_out:
+ if (m.kaddr)
+ kunmap_atomic(m.kaddr);
+
+out:
+ debugln("%s, m_la %llu m_pa %llu m_llen %llu m_plen %llu m_flags 0%o",
+ __func__, map->m_la, map->m_pa,
+ map->m_llen, map->m_plen, map->m_flags);
+
+ trace_z_erofs_map_blocks_iter_exit(inode, map, flags, err);
+
+ /* aggressively BUG_ON iff CONFIG_EROFS_FS_DEBUG is on */
+ DBG_BUGON(err < 0 && err != -ENOMEM);
+ return err;
+}
+
diff --git a/drivers/staging/fieldbus/Documentation/fieldbus_dev.txt b/drivers/staging/fieldbus/Documentation/fieldbus_dev.txt
index 56af3f650fa3..89fb8e14676f 100644
--- a/drivers/staging/fieldbus/Documentation/fieldbus_dev.txt
+++ b/drivers/staging/fieldbus/Documentation/fieldbus_dev.txt
@@ -54,8 +54,8 @@ a limited few common behaviours and properties. This allows us to define
a simple interface consisting of a character device and a set of sysfs files:
See:
-Documentation/ABI/testing/sysfs-class-fieldbus-dev
-Documentation/ABI/testing/fieldbus-dev-cdev
+drivers/staging/fieldbus/Documentation/ABI/sysfs-class-fieldbus-dev
+drivers/staging/fieldbus/Documentation/ABI/fieldbus-dev-cdev
Note that this simple interface does not provide a way to modify adapter
configuration settings. It is therefore useful only for adapters that get their
diff --git a/drivers/staging/fieldbus/anybuss/Kconfig b/drivers/staging/fieldbus/anybuss/Kconfig
index 8bc3d9a87743..635a0a7b7dd2 100644
--- a/drivers/staging/fieldbus/anybuss/Kconfig
+++ b/drivers/staging/fieldbus/anybuss/Kconfig
@@ -14,6 +14,7 @@ if HMS_ANYBUSS_BUS
config ARCX_ANYBUS_CONTROLLER
tristate "Arcx Anybus-S Controller"
depends on OF && GPIOLIB && HAS_IOMEM && REGULATOR
+ select REGMAP_MMIO
help
Select this to get support for the Arcx Anybus controller.
It connects to the SoC via a parallel memory bus, and
diff --git a/drivers/staging/fieldbus/anybuss/arcx-anybus.c b/drivers/staging/fieldbus/anybuss/arcx-anybus.c
index a167fb68e355..2ecffa42e561 100644
--- a/drivers/staging/fieldbus/anybuss/arcx-anybus.c
+++ b/drivers/staging/fieldbus/anybuss/arcx-anybus.c
@@ -111,49 +111,31 @@ static void export_reset_1(struct device *dev, bool assert)
* at a time for now.
*/
-static int read_reg_bus(void *context, unsigned int reg,
- unsigned int *val)
-{
- void __iomem *base = context;
-
- *val = readb(base + reg);
- return 0;
-}
-
-static int write_reg_bus(void *context, unsigned int reg,
- unsigned int val)
-{
- void __iomem *base = context;
-
- writeb(val, base + reg);
- return 0;
-}
+static const struct regmap_config arcx_regmap_cfg = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = 0x7ff,
+ .use_single_read = true,
+ .use_single_write = true,
+ /*
+ * single-byte parallel bus accesses are atomic, so don't
+ * require any synchronization.
+ */
+ .disable_locking = true,
+};
static struct regmap *create_parallel_regmap(struct platform_device *pdev,
int idx)
{
- struct regmap_config regmap_cfg = {
- .reg_bits = 11,
- .val_bits = 8,
- /*
- * single-byte parallel bus accesses are atomic, so don't
- * require any synchronization.
- */
- .disable_locking = true,
- .reg_read = read_reg_bus,
- .reg_write = write_reg_bus,
- };
struct resource *res;
void __iomem *base;
struct device *dev = &pdev->dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, idx + 1);
- if (resource_size(res) < (1 << regmap_cfg.reg_bits))
- return ERR_PTR(-EINVAL);
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
return ERR_CAST(base);
- return devm_regmap_init(dev, NULL, base, &regmap_cfg);
+ return devm_regmap_init_mmio(dev, base, &arcx_regmap_cfg);
}
static struct anybuss_host *
diff --git a/drivers/staging/fieldbus/dev_core.c b/drivers/staging/fieldbus/dev_core.c
index 60b85140675a..f6f5b92ba914 100644
--- a/drivers/staging/fieldbus/dev_core.c
+++ b/drivers/staging/fieldbus/dev_core.c
@@ -211,16 +211,16 @@ static ssize_t fieldbus_write(struct file *filp, const char __user *buf,
return fbdev->write_area(fbdev, buf, size, offset);
}
-static unsigned int fieldbus_poll(struct file *filp, poll_table *wait)
+static __poll_t fieldbus_poll(struct file *filp, poll_table *wait)
{
struct fb_open_file *of = filp->private_data;
struct fieldbus_dev *fbdev = of->fbdev;
- unsigned int mask = POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM;
+ __poll_t mask = EPOLLIN | EPOLLRDNORM | EPOLLOUT | EPOLLWRNORM;
poll_wait(filp, &fbdev->dc_wq, wait);
/* data changed ? */
if (fbdev->dc_event != of->dc_event)
- mask |= POLLPRI | POLLERR;
+ mask |= EPOLLPRI | EPOLLERR;
return mask;
}
diff --git a/drivers/staging/fsl-dpaa2/Kconfig b/drivers/staging/fsl-dpaa2/Kconfig
index 368837cdf281..244237bb068a 100644
--- a/drivers/staging/fsl-dpaa2/Kconfig
+++ b/drivers/staging/fsl-dpaa2/Kconfig
@@ -6,7 +6,7 @@
config FSL_DPAA2
bool "Freescale DPAA2 devices"
depends on FSL_MC_BUS
- ---help---
+ help
Build drivers for Freescale DataPath Acceleration
Architecture (DPAA2) family of SoCs.
@@ -14,6 +14,6 @@ config FSL_DPAA2_ETHSW
tristate "Freescale DPAA2 Ethernet Switch"
depends on FSL_DPAA2
depends on NET_SWITCHDEV
- ---help---
- Driver for Freescale DPAA2 Ethernet Switch. Select
- BRIDGE to have support for bridge tools.
+ help
+ Driver for Freescale DPAA2 Ethernet Switch. Select
+ BRIDGE to have support for bridge tools.
diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
index e3c3e427309a..f73edaf6ce87 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
@@ -1086,6 +1086,7 @@ static int port_switchdev_event(struct notifier_block *unused,
dev_hold(dev);
break;
default:
+ kfree(switchdev_work);
return NOTIFY_DONE;
}
diff --git a/drivers/staging/gasket/gasket_core.c b/drivers/staging/gasket/gasket_core.c
index a445d58fb399..13179f063a61 100644
--- a/drivers/staging/gasket/gasket_core.c
+++ b/drivers/staging/gasket/gasket_core.c
@@ -702,8 +702,7 @@ static bool gasket_mmap_has_permissions(struct gasket_dev *gasket_dev,
if ((vma->vm_flags & VM_WRITE) &&
!gasket_owned_by_current_tgid(&gasket_dev->dev_info)) {
dev_dbg(gasket_dev->dev,
- "Attempting to mmap a region for write without owning "
- "device.\n");
+ "Attempting to mmap a region for write without owning device.\n");
return false;
}
@@ -1054,8 +1053,7 @@ static int gasket_mmap(struct file *filp, struct vm_area_struct *vma)
}
if (bar_index > 0 && is_coherent_region) {
dev_err(gasket_dev->dev,
- "double matching bar and coherent buffers for address "
- "0x%lx\n",
+ "double matching bar and coherent buffers for address 0x%lx\n",
raw_offset);
trace_gasket_mmap_exit(bar_index);
return -EINVAL;
diff --git a/drivers/staging/gasket/gasket_ioctl.c b/drivers/staging/gasket/gasket_ioctl.c
index 0ca48e688818..7ecfba4f2b06 100644
--- a/drivers/staging/gasket/gasket_ioctl.c
+++ b/drivers/staging/gasket/gasket_ioctl.c
@@ -353,8 +353,7 @@ long gasket_handle_ioctl(struct file *filp, uint cmd, void __user *argp)
*/
trace_gasket_ioctl_integer_data(arg);
dev_dbg(gasket_dev->dev,
- "Unknown ioctl cmd=0x%x not caught by "
- "gasket_is_supported_ioctl\n",
+ "Unknown ioctl cmd=0x%x not caught by gasket_is_supported_ioctl\n",
cmd);
retval = -EINVAL;
break;
diff --git a/drivers/staging/gasket/gasket_page_table.c b/drivers/staging/gasket/gasket_page_table.c
index d35c4fb19e28..f6d715787da8 100644
--- a/drivers/staging/gasket/gasket_page_table.c
+++ b/drivers/staging/gasket/gasket_page_table.c
@@ -237,8 +237,8 @@ int gasket_page_table_init(struct gasket_page_table **ppg_tbl,
* hardware register that contains the page table size.
*/
if (total_entries == ULONG_MAX) {
- dev_dbg(device, "Error reading page table size. "
- "Initializing page table with size 0\n");
+ dev_dbg(device,
+ "Error reading page table size. Initializing page table with size 0\n");
total_entries = 0;
}
@@ -491,8 +491,7 @@ static int gasket_perform_mapping(struct gasket_page_table *pg_tbl,
if (ret <= 0) {
dev_err(pg_tbl->device,
- "get user pages failed for addr=0x%lx, "
- "offset=0x%lx [ret=%d]\n",
+ "get user pages failed for addr=0x%lx, offset=0x%lx [ret=%d]\n",
page_addr, offset, ret);
return ret ? ret : -ENOMEM;
}
@@ -779,8 +778,8 @@ static bool gasket_is_extended_dev_addr_bad(struct gasket_page_table *pg_tbl,
if (page_lvl0_idx >= pg_tbl->num_extended_entries) {
dev_err(pg_tbl->device,
- "starting level 0 slot at %lu is too large, max is < "
- "%u\n", page_lvl0_idx, pg_tbl->num_extended_entries);
+ "starting level 0 slot at %lu is too large, max is < %u\n",
+ page_lvl0_idx, pg_tbl->num_extended_entries);
return true;
}
@@ -965,8 +964,7 @@ static int gasket_map_extended_pages(struct gasket_page_table *pg_tbl,
if (ret) {
dev_addr_end = dev_addr + (num_pages / PAGE_SIZE) - 1;
dev_err(pg_tbl->device,
- "page table slots (%lu,%lu) (@ 0x%lx) to (%lu,%lu) are "
- "not available\n",
+ "page table slots (%lu,%lu) (@ 0x%lx) to (%lu,%lu) are not available\n",
gasket_extended_lvl0_page_idx(pg_tbl, dev_addr),
dev_addr,
gasket_extended_lvl1_page_idx(pg_tbl, dev_addr),
diff --git a/drivers/staging/greybus/tools/loopback_test.c b/drivers/staging/greybus/tools/loopback_test.c
index 2fa88092514d..cebc1d90a180 100644
--- a/drivers/staging/greybus/tools/loopback_test.c
+++ b/drivers/staging/greybus/tools/loopback_test.c
@@ -414,12 +414,6 @@ static int get_results(struct loopback_test *t)
return 0;
}
-void log_csv_error(int len, int err)
-{
- fprintf(stderr, "unable to write %d bytes to csv %s\n", len,
- strerror(err));
-}
-
int format_output(struct loopback_test *t,
struct loopback_results *r,
const char *dev_name,
diff --git a/drivers/staging/iio/accel/adis16203.c b/drivers/staging/iio/accel/adis16203.c
index 70381756a64a..39687139a7d3 100644
--- a/drivers/staging/iio/accel/adis16203.c
+++ b/drivers/staging/iio/accel/adis16203.c
@@ -122,7 +122,7 @@
/* Power supply above 3.625 V */
#define ADIS16203_DIAG_STAT_POWER_HIGH_BIT 1
-/* Power supply below 3.15 V */
+/* Power supply below 2.975 V */
#define ADIS16203_DIAG_STAT_POWER_LOW_BIT 0
/* GLOB_CMD */
@@ -234,7 +234,7 @@ static const char * const adis16203_status_error_msgs[] = {
[ADIS16203_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure",
[ADIS16203_DIAG_STAT_FLASH_UPT_BIT] = "Flash update failed",
[ADIS16203_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V",
- [ADIS16203_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 3.15V",
+ [ADIS16203_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 2.975V",
};
static const struct adis_data adis16203_data = {
@@ -311,9 +311,17 @@ static int adis16203_remove(struct spi_device *spi)
return 0;
}
+static const struct of_device_id adis16203_of_match[] = {
+ { .compatible = "adi,adis16203" },
+ { },
+};
+
+MODULE_DEVICE_TABLE(of, adis16203_of_match);
+
static struct spi_driver adis16203_driver = {
.driver = {
.name = "adis16203",
+ .of_match_table = adis16203_of_match,
},
.probe = adis16203_probe,
.remove = adis16203_remove,
diff --git a/drivers/staging/iio/accel/adis16240.c b/drivers/staging/iio/accel/adis16240.c
index b80e0d248b0f..62f4b3b1b457 100644
--- a/drivers/staging/iio/accel/adis16240.c
+++ b/drivers/staging/iio/accel/adis16240.c
@@ -175,7 +175,7 @@
/* Power supply above 3.625 V */
#define ADIS16240_DIAG_STAT_POWER_HIGH_BIT 1
- /* Power supply below 3.15 V */
+ /* Power supply below 2.225 V */
#define ADIS16240_DIAG_STAT_POWER_LOW_BIT 0
/* GLOB_CMD */
@@ -435,9 +435,16 @@ static int adis16240_remove(struct spi_device *spi)
return 0;
}
+static const struct of_device_id adis16240_of_match[] = {
+ { .compatible = "adi,adis16240" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, adis16240_of_match);
+
static struct spi_driver adis16240_driver = {
.driver = {
.name = "adis16240",
+ .of_match_table = adis16240_of_match,
},
.probe = adis16240_probe,
.remove = adis16240_remove,
diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig
index 23d9a655a520..31cd9a12f40f 100644
--- a/drivers/staging/iio/adc/Kconfig
+++ b/drivers/staging/iio/adc/Kconfig
@@ -12,6 +12,9 @@ config AD7816
Say yes here to build support for Analog Devices AD7816/7/8
temperature sensors and ADC.
+ To compile this driver as a module, choose M here: the
+ module will be called ad7816.
+
config AD7192
tristate "Analog Devices AD7190 AD7192 AD7193 AD7195 ADC driver"
depends on SPI
diff --git a/drivers/staging/iio/addac/adt7316-spi.c b/drivers/staging/iio/addac/adt7316-spi.c
index 2066241b15b1..af513e003da7 100644
--- a/drivers/staging/iio/addac/adt7316-spi.c
+++ b/drivers/staging/iio/addac/adt7316-spi.c
@@ -126,9 +126,22 @@ static const struct spi_device_id adt7316_spi_id[] = {
MODULE_DEVICE_TABLE(spi, adt7316_spi_id);
+static const struct of_device_id adt7316_of_spi_match[] = {
+ { .compatible = "adi,adt7316" },
+ { .compatible = "adi,adt7317" },
+ { .compatible = "adi,adt7318" },
+ { .compatible = "adi,adt7516" },
+ { .compatible = "adi,adt7517" },
+ { .compatible = "adi,adt7519" },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, adt7316_of_spi_match);
+
static struct spi_driver adt7316_driver = {
.driver = {
.name = "adt7316",
+ .of_match_table = adt7316_of_spi_match,
.pm = ADT7316_PM_OPS,
},
.probe = adt7316_spi_probe,
diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c
index b6a65ee8d558..9cb3d0e42c38 100644
--- a/drivers/staging/iio/addac/adt7316.c
+++ b/drivers/staging/iio/addac/adt7316.c
@@ -6,7 +6,8 @@
*/
#include <linux/interrupt.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/irq.h>
#include <linux/workqueue.h>
#include <linux/device.h>
#include <linux/kernel.h>
@@ -2154,7 +2155,7 @@ int adt7316_probe(struct device *dev, struct adt7316_bus *bus,
chip->dac_bits = 8;
chip->ldac_pin = devm_gpiod_get_optional(dev, "adi,ldac",
- GPIOD_OUT_LOW);
+ GPIOD_OUT_LOW);
if (IS_ERR(chip->ldac_pin)) {
ret = PTR_ERR(chip->ldac_pin);
dev_err(dev, "Failed to request ldac GPIO: %d\n", ret);
diff --git a/drivers/staging/iio/cdc/ad7150.c b/drivers/staging/iio/cdc/ad7150.c
index dd7fcab8e19e..f4954d85553e 100644
--- a/drivers/staging/iio/cdc/ad7150.c
+++ b/drivers/staging/iio/cdc/ad7150.c
@@ -5,6 +5,7 @@
* Copyright 2010-2011 Analog Devices Inc.
*/
+#include <linux/bitfield.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/kernel.h>
@@ -45,6 +46,9 @@
#define AD7150_SN0 22
#define AD7150_ID 23
+/* AD7150 masks */
+#define AD7150_THRESHTYPE_MSK GENMASK(6, 5)
+
/**
* struct ad7150_chip_info - instance specific chip data
* @client: i2c client for this device
@@ -130,36 +134,39 @@ static int ad7150_read_event_config(struct iio_dev *indio_dev,
{
int ret;
u8 threshtype;
- bool adaptive;
+ bool thrfixed;
struct ad7150_chip_info *chip = iio_priv(indio_dev);
ret = i2c_smbus_read_byte_data(chip->client, AD7150_CFG);
if (ret < 0)
return ret;
- threshtype = (ret >> 5) & 0x03;
- adaptive = !!(ret & 0x80);
+ threshtype = FIELD_GET(AD7150_THRESHTYPE_MSK, ret);
+
+ /*check if threshold mode is fixed or adaptive*/
+ thrfixed = FIELD_GET(AD7150_CFG_FIX, ret);
switch (type) {
case IIO_EV_TYPE_MAG_ADAPTIVE:
if (dir == IIO_EV_DIR_RISING)
- return adaptive && (threshtype == 0x1);
- return adaptive && (threshtype == 0x0);
+ return !thrfixed && (threshtype == 0x1);
+ return !thrfixed && (threshtype == 0x0);
case IIO_EV_TYPE_THRESH_ADAPTIVE:
if (dir == IIO_EV_DIR_RISING)
- return adaptive && (threshtype == 0x3);
- return adaptive && (threshtype == 0x2);
+ return !thrfixed && (threshtype == 0x3);
+ return !thrfixed && (threshtype == 0x2);
case IIO_EV_TYPE_THRESH:
if (dir == IIO_EV_DIR_RISING)
- return !adaptive && (threshtype == 0x1);
- return !adaptive && (threshtype == 0x0);
+ return thrfixed && (threshtype == 0x1);
+ return thrfixed && (threshtype == 0x0);
default:
break;
}
return -EINVAL;
}
-/* lock should be held */
+/* state_lock should be held to ensure consistent state*/
+
static int ad7150_write_event_params(struct iio_dev *indio_dev,
unsigned int chan,
enum iio_event_type type,
@@ -198,16 +205,11 @@ static int ad7150_write_event_params(struct iio_dev *indio_dev,
ret = i2c_smbus_write_byte_data(chip->client,
ad7150_addresses[chan][4],
sens);
- if (ret < 0)
+ if (ret)
return ret;
-
- ret = i2c_smbus_write_byte_data(chip->client,
+ return i2c_smbus_write_byte_data(chip->client,
ad7150_addresses[chan][5],
timeout);
- if (ret < 0)
- return ret;
-
- return 0;
}
static int ad7150_write_event_config(struct iio_dev *indio_dev,
@@ -350,8 +352,8 @@ static ssize_t ad7150_show_timeout(struct device *dev,
/* use the event code for consistency reasons */
int chan = IIO_EVENT_CODE_EXTRACT_CHAN(this_attr->address);
- int rising = !!(IIO_EVENT_CODE_EXTRACT_DIR(this_attr->address)
- == IIO_EV_DIR_RISING);
+ int rising = (IIO_EVENT_CODE_EXTRACT_DIR(this_attr->address)
+ == IIO_EV_DIR_RISING) ? 1 : 0;
switch (IIO_EVENT_CODE_EXTRACT_TYPE(this_attr->address)) {
case IIO_EV_TYPE_MAG_ADAPTIVE:
@@ -465,30 +467,21 @@ static const struct iio_event_spec ad7150_events[] = {
},
};
+#define AD7150_CAPACITANCE_CHAN(_chan) { \
+ .type = IIO_CAPACITANCE, \
+ .indexed = 1, \
+ .channel = _chan, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_AVERAGE_RAW), \
+ .event_spec = ad7150_events, \
+ .num_event_specs = ARRAY_SIZE(ad7150_events), \
+ }
+
static const struct iio_chan_spec ad7150_channels[] = {
- {
- .type = IIO_CAPACITANCE,
- .indexed = 1,
- .channel = 0,
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
- BIT(IIO_CHAN_INFO_AVERAGE_RAW),
- .event_spec = ad7150_events,
- .num_event_specs = ARRAY_SIZE(ad7150_events),
- }, {
- .type = IIO_CAPACITANCE,
- .indexed = 1,
- .channel = 1,
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
- BIT(IIO_CHAN_INFO_AVERAGE_RAW),
- .event_spec = ad7150_events,
- .num_event_specs = ARRAY_SIZE(ad7150_events),
- },
+ AD7150_CAPACITANCE_CHAN(0),
+ AD7150_CAPACITANCE_CHAN(1)
};
-/*
- * threshold events
- */
-
static irqreturn_t ad7150_event_handler(int irq, void *private)
{
struct iio_dev *indio_dev = private;
@@ -577,10 +570,6 @@ static const struct iio_info ad7150_info = {
.write_event_value = &ad7150_write_event_value,
};
-/*
- * device probe and remove
- */
-
static int ad7150_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
diff --git a/drivers/staging/iio/cdc/ad7746.c b/drivers/staging/iio/cdc/ad7746.c
index 47610d863908..21527d84f940 100644
--- a/drivers/staging/iio/cdc/ad7746.c
+++ b/drivers/staging/iio/cdc/ad7746.c
@@ -748,9 +748,19 @@ static const struct i2c_device_id ad7746_id[] = {
MODULE_DEVICE_TABLE(i2c, ad7746_id);
+static const struct of_device_id ad7746_of_match[] = {
+ { .compatible = "adi,ad7745" },
+ { .compatible = "adi,ad7746" },
+ { .compatible = "adi,ad7747" },
+ { },
+};
+
+MODULE_DEVICE_TABLE(of, ad7746_of_match);
+
static struct i2c_driver ad7746_driver = {
.driver = {
.name = KBUILD_MODNAME,
+ .of_match_table = ad7746_of_match,
},
.probe = ad7746_probe,
.id_table = ad7746_id,
diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c
index 6de3cd7363d7..038d6732c3fd 100644
--- a/drivers/staging/iio/frequency/ad9834.c
+++ b/drivers/staging/iio/frequency/ad9834.c
@@ -521,9 +521,20 @@ static const struct spi_device_id ad9834_id[] = {
};
MODULE_DEVICE_TABLE(spi, ad9834_id);
+static const struct of_device_id ad9834_of_match[] = {
+ {.compatible = "adi,ad9833"},
+ {.compatible = "adi,ad9834"},
+ {.compatible = "adi,ad9837"},
+ {.compatible = "adi,ad9838"},
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, ad9834_of_match);
+
static struct spi_driver ad9834_driver = {
.driver = {
.name = "ad9834",
+ .of_match_table = ad9834_of_match
},
.probe = ad9834_probe,
.remove = ad9834_remove,
diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c
index b6be0bc202f5..0c1bd108c386 100644
--- a/drivers/staging/iio/resolver/ad2s1210.c
+++ b/drivers/staging/iio/resolver/ad2s1210.c
@@ -647,9 +647,6 @@ static int ad2s1210_probe(struct spi_device *spi)
struct ad2s1210_state *st;
int ret;
- if (!spi->dev.platform_data)
- return -EINVAL;
-
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
diff --git a/drivers/staging/isdn/Kconfig b/drivers/staging/isdn/Kconfig
new file mode 100644
index 000000000000..faaf63887094
--- /dev/null
+++ b/drivers/staging/isdn/Kconfig
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0-only
+menu "ISDN CAPI drivers"
+ depends on ISDN_CAPI
+
+source "drivers/staging/isdn/avm/Kconfig"
+
+source "drivers/staging/isdn/gigaset/Kconfig"
+
+source "drivers/staging/isdn/hysdn/Kconfig"
+
+endmenu
+
diff --git a/drivers/staging/isdn/Makefile b/drivers/staging/isdn/Makefile
new file mode 100644
index 000000000000..025504bae5df
--- /dev/null
+++ b/drivers/staging/isdn/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0
+# Makefile for the kernel ISDN subsystem and device drivers.
+
+# Object files in subdirectories
+
+obj-$(CONFIG_CAPI_AVM) += avm/
+obj-$(CONFIG_HYSDN) += hysdn/
+obj-$(CONFIG_ISDN_DRV_GIGASET) += gigaset/
diff --git a/drivers/staging/isdn/TODO b/drivers/staging/isdn/TODO
new file mode 100644
index 000000000000..9210d11eb68b
--- /dev/null
+++ b/drivers/staging/isdn/TODO
@@ -0,0 +1,22 @@
+TODO: Remove in late 2019 unless there are users
+
+
+I tried to find any indication of whether the capi drivers are
+still in use, and have not found anything from a long time ago.
+
+With public ISDN networks almost completely shut down over the past 12
+months, there is very little you can actually do with this hardware. The
+main remaining use case would be to connect ISDN voice phones to an
+in-house installation with Asterisk or LCR, but anyone trying this in
+turn seems to be using either the mISDN driver stack, or out-of-tree
+drivers from the hardware vendors.
+
+I may of course have missed something, so I would suggest moving
+these into drivers/staging/ just in case someone still uses one
+of the three remaining in-kernel drivers (avm, hysdn, gigaset).
+
+If nobody complains, we can remove them entirely in six months,
+or otherwise move the core code and any drivers that are still
+needed back into drivers/isdn.
+
+ Arnd Bergmann <arnd@arndb.de>
diff --git a/drivers/isdn/hardware/avm/Kconfig b/drivers/staging/isdn/avm/Kconfig
index 81483db067bb..81483db067bb 100644
--- a/drivers/isdn/hardware/avm/Kconfig
+++ b/drivers/staging/isdn/avm/Kconfig
diff --git a/drivers/isdn/hardware/avm/Makefile b/drivers/staging/isdn/avm/Makefile
index 3830a0573fcc..3830a0573fcc 100644
--- a/drivers/isdn/hardware/avm/Makefile
+++ b/drivers/staging/isdn/avm/Makefile
diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/staging/isdn/avm/avm_cs.c
index 62b8030ee331..62b8030ee331 100644
--- a/drivers/isdn/hardware/avm/avm_cs.c
+++ b/drivers/staging/isdn/avm/avm_cs.c
diff --git a/drivers/isdn/hardware/avm/avmcard.h b/drivers/staging/isdn/avm/avmcard.h
index cdfa89c71997..cdfa89c71997 100644
--- a/drivers/isdn/hardware/avm/avmcard.h
+++ b/drivers/staging/isdn/avm/avmcard.h
diff --git a/drivers/isdn/hardware/avm/b1.c b/drivers/staging/isdn/avm/b1.c
index 40ca1e8fa09f..40ca1e8fa09f 100644
--- a/drivers/isdn/hardware/avm/b1.c
+++ b/drivers/staging/isdn/avm/b1.c
diff --git a/drivers/isdn/hardware/avm/b1dma.c b/drivers/staging/isdn/avm/b1dma.c
index 6a3dc9937ce5..6a3dc9937ce5 100644
--- a/drivers/isdn/hardware/avm/b1dma.c
+++ b/drivers/staging/isdn/avm/b1dma.c
diff --git a/drivers/isdn/hardware/avm/b1isa.c b/drivers/staging/isdn/avm/b1isa.c
index cdfea72e0ef6..cdfea72e0ef6 100644
--- a/drivers/isdn/hardware/avm/b1isa.c
+++ b/drivers/staging/isdn/avm/b1isa.c
diff --git a/drivers/isdn/hardware/avm/b1pci.c b/drivers/staging/isdn/avm/b1pci.c
index b76b57a82c02..b76b57a82c02 100644
--- a/drivers/isdn/hardware/avm/b1pci.c
+++ b/drivers/staging/isdn/avm/b1pci.c
diff --git a/drivers/isdn/hardware/avm/b1pcmcia.c b/drivers/staging/isdn/avm/b1pcmcia.c
index 3aca16e62902..3aca16e62902 100644
--- a/drivers/isdn/hardware/avm/b1pcmcia.c
+++ b/drivers/staging/isdn/avm/b1pcmcia.c
diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/staging/isdn/avm/c4.c
index ac72cd204c4d..ac72cd204c4d 100644
--- a/drivers/isdn/hardware/avm/c4.c
+++ b/drivers/staging/isdn/avm/c4.c
diff --git a/drivers/isdn/hardware/avm/t1isa.c b/drivers/staging/isdn/avm/t1isa.c
index 2153619c5b31..2153619c5b31 100644
--- a/drivers/isdn/hardware/avm/t1isa.c
+++ b/drivers/staging/isdn/avm/t1isa.c
diff --git a/drivers/isdn/hardware/avm/t1pci.c b/drivers/staging/isdn/avm/t1pci.c
index f5ed1d5004c9..f5ed1d5004c9 100644
--- a/drivers/isdn/hardware/avm/t1pci.c
+++ b/drivers/staging/isdn/avm/t1pci.c
diff --git a/drivers/isdn/gigaset/Kconfig b/drivers/staging/isdn/gigaset/Kconfig
index fe41e9cfb672..c593105b3600 100644
--- a/drivers/isdn/gigaset/Kconfig
+++ b/drivers/staging/isdn/gigaset/Kconfig
@@ -30,15 +30,6 @@ config GIGASET_CAPI
Say N to build the old native ISDN4Linux variant.
If unsure, say Y.
-config GIGASET_I4L
- bool
- depends on ISDN_I4L='y'||(ISDN_I4L='m'&&ISDN_DRV_GIGASET='m')
- default !GIGASET_CAPI
-
-config GIGASET_DUMMYLL
- bool
- default !GIGASET_CAPI&&!GIGASET_I4L
-
config GIGASET_BASE
tristate "Gigaset base station support"
depends on USB
diff --git a/drivers/isdn/gigaset/Makefile b/drivers/staging/isdn/gigaset/Makefile
index ac45a2739f56..9c010891dcd7 100644
--- a/drivers/isdn/gigaset/Makefile
+++ b/drivers/staging/isdn/gigaset/Makefile
@@ -1,8 +1,12 @@
# SPDX-License-Identifier: GPL-2.0
gigaset-y := common.o interface.o proc.o ev-layer.o asyncdata.o
-gigaset-$(CONFIG_GIGASET_CAPI) += capi.o
-gigaset-$(CONFIG_GIGASET_I4L) += i4l.o
-gigaset-$(CONFIG_GIGASET_DUMMYLL) += dummyll.o
+
+ifdef CONFIG_GIGASET_CAPI
+gigaset-y += capi.o
+else
+gigaset-y += dummyll.o
+endif
+
usb_gigaset-y := usb-gigaset.o
ser_gigaset-y := ser-gigaset.o
bas_gigaset-y := bas-gigaset.o isocdata.o
diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/staging/isdn/gigaset/asyncdata.c
index a34b3c9d8a71..a34b3c9d8a71 100644
--- a/drivers/isdn/gigaset/asyncdata.c
+++ b/drivers/staging/isdn/gigaset/asyncdata.c
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/staging/isdn/gigaset/bas-gigaset.c
index c334525a5f63..c334525a5f63 100644
--- a/drivers/isdn/gigaset/bas-gigaset.c
+++ b/drivers/staging/isdn/gigaset/bas-gigaset.c
diff --git a/drivers/isdn/gigaset/capi.c b/drivers/staging/isdn/gigaset/capi.c
index 83d7dd48c61d..83d7dd48c61d 100644
--- a/drivers/isdn/gigaset/capi.c
+++ b/drivers/staging/isdn/gigaset/capi.c
diff --git a/drivers/isdn/gigaset/common.c b/drivers/staging/isdn/gigaset/common.c
index 3bb8092858ab..3bb8092858ab 100644
--- a/drivers/isdn/gigaset/common.c
+++ b/drivers/staging/isdn/gigaset/common.c
diff --git a/drivers/isdn/gigaset/dummyll.c b/drivers/staging/isdn/gigaset/dummyll.c
index 4b9637e5da6e..4b9637e5da6e 100644
--- a/drivers/isdn/gigaset/dummyll.c
+++ b/drivers/staging/isdn/gigaset/dummyll.c
diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/staging/isdn/gigaset/ev-layer.c
index f8bb1869c600..f8bb1869c600 100644
--- a/drivers/isdn/gigaset/ev-layer.c
+++ b/drivers/staging/isdn/gigaset/ev-layer.c
diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/staging/isdn/gigaset/gigaset.h
index 0ecc2b5ea553..0ecc2b5ea553 100644
--- a/drivers/isdn/gigaset/gigaset.h
+++ b/drivers/staging/isdn/gigaset/gigaset.h
diff --git a/drivers/isdn/gigaset/interface.c b/drivers/staging/isdn/gigaset/interface.c
index 17fa615a8c68..17fa615a8c68 100644
--- a/drivers/isdn/gigaset/interface.c
+++ b/drivers/staging/isdn/gigaset/interface.c
diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/staging/isdn/gigaset/isocdata.c
index 3ecf6e33ed15..3ecf6e33ed15 100644
--- a/drivers/isdn/gigaset/isocdata.c
+++ b/drivers/staging/isdn/gigaset/isocdata.c
diff --git a/drivers/isdn/gigaset/proc.c b/drivers/staging/isdn/gigaset/proc.c
index 8914439a4237..8914439a4237 100644
--- a/drivers/isdn/gigaset/proc.c
+++ b/drivers/staging/isdn/gigaset/proc.c
diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/staging/isdn/gigaset/ser-gigaset.c
index 5587e9e7fc73..5587e9e7fc73 100644
--- a/drivers/isdn/gigaset/ser-gigaset.c
+++ b/drivers/staging/isdn/gigaset/ser-gigaset.c
diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/staging/isdn/gigaset/usb-gigaset.c
index 1b9b43659bdf..1b9b43659bdf 100644
--- a/drivers/isdn/gigaset/usb-gigaset.c
+++ b/drivers/staging/isdn/gigaset/usb-gigaset.c
diff --git a/drivers/isdn/hysdn/Kconfig b/drivers/staging/isdn/hysdn/Kconfig
index 1971ef850c9a..1971ef850c9a 100644
--- a/drivers/isdn/hysdn/Kconfig
+++ b/drivers/staging/isdn/hysdn/Kconfig
diff --git a/drivers/isdn/hysdn/Makefile b/drivers/staging/isdn/hysdn/Makefile
index e01f17f22ebb..e01f17f22ebb 100644
--- a/drivers/isdn/hysdn/Makefile
+++ b/drivers/staging/isdn/hysdn/Makefile
diff --git a/drivers/isdn/hysdn/boardergo.c b/drivers/staging/isdn/hysdn/boardergo.c
index 2aa2a0e08247..2aa2a0e08247 100644
--- a/drivers/isdn/hysdn/boardergo.c
+++ b/drivers/staging/isdn/hysdn/boardergo.c
diff --git a/drivers/isdn/hysdn/boardergo.h b/drivers/staging/isdn/hysdn/boardergo.h
index e99bd81c4034..e99bd81c4034 100644
--- a/drivers/isdn/hysdn/boardergo.h
+++ b/drivers/staging/isdn/hysdn/boardergo.h
diff --git a/drivers/isdn/hysdn/hycapi.c b/drivers/staging/isdn/hysdn/hycapi.c
index a2c15cd7bf67..a2c15cd7bf67 100644
--- a/drivers/isdn/hysdn/hycapi.c
+++ b/drivers/staging/isdn/hysdn/hycapi.c
diff --git a/drivers/isdn/hysdn/hysdn_boot.c b/drivers/staging/isdn/hysdn/hysdn_boot.c
index ba177c3a621b..ba177c3a621b 100644
--- a/drivers/isdn/hysdn/hysdn_boot.c
+++ b/drivers/staging/isdn/hysdn/hysdn_boot.c
diff --git a/drivers/isdn/hysdn/hysdn_defs.h b/drivers/staging/isdn/hysdn/hysdn_defs.h
index cdac46a21692..cdac46a21692 100644
--- a/drivers/isdn/hysdn/hysdn_defs.h
+++ b/drivers/staging/isdn/hysdn/hysdn_defs.h
diff --git a/drivers/isdn/hysdn/hysdn_init.c b/drivers/staging/isdn/hysdn/hysdn_init.c
index 0db2f7506250..0db2f7506250 100644
--- a/drivers/isdn/hysdn/hysdn_init.c
+++ b/drivers/staging/isdn/hysdn/hysdn_init.c
diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/staging/isdn/hysdn/hysdn_net.c
index 8e9c34f33d86..bea37ae30ebb 100644
--- a/drivers/isdn/hysdn/hysdn_net.c
+++ b/drivers/staging/isdn/hysdn/hysdn_net.c
@@ -70,9 +70,13 @@ net_open(struct net_device *dev)
for (i = 0; i < ETH_ALEN; i++)
dev->dev_addr[i] = 0xfc;
if ((in_dev = dev->ip_ptr) != NULL) {
- struct in_ifaddr *ifa = in_dev->ifa_list;
+ const struct in_ifaddr *ifa;
+
+ rcu_read_lock();
+ ifa = rcu_dereference(in_dev->ifa_list);
if (ifa != NULL)
memcpy(dev->dev_addr + (ETH_ALEN - sizeof(ifa->ifa_local)), &ifa->ifa_local, sizeof(ifa->ifa_local));
+ rcu_read_unlock();
}
} else
memcpy(dev->dev_addr, card->mac_addr, ETH_ALEN);
diff --git a/drivers/isdn/hysdn/hysdn_pof.h b/drivers/staging/isdn/hysdn/hysdn_pof.h
index f63f5fa59d7e..f63f5fa59d7e 100644
--- a/drivers/isdn/hysdn/hysdn_pof.h
+++ b/drivers/staging/isdn/hysdn/hysdn_pof.h
diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/staging/isdn/hysdn/hysdn_procconf.c
index 73079213ec94..73079213ec94 100644
--- a/drivers/isdn/hysdn/hysdn_procconf.c
+++ b/drivers/staging/isdn/hysdn/hysdn_procconf.c
diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/staging/isdn/hysdn/hysdn_proclog.c
index 6e898b90e86e..6e898b90e86e 100644
--- a/drivers/isdn/hysdn/hysdn_proclog.c
+++ b/drivers/staging/isdn/hysdn/hysdn_proclog.c
diff --git a/drivers/isdn/hysdn/hysdn_sched.c b/drivers/staging/isdn/hysdn/hysdn_sched.c
index 31d7c1415543..31d7c1415543 100644
--- a/drivers/isdn/hysdn/hysdn_sched.c
+++ b/drivers/staging/isdn/hysdn/hysdn_sched.c
diff --git a/drivers/isdn/hysdn/ince1pc.h b/drivers/staging/isdn/hysdn/ince1pc.h
index cab68361de65..cab68361de65 100644
--- a/drivers/isdn/hysdn/ince1pc.h
+++ b/drivers/staging/isdn/hysdn/ince1pc.h
diff --git a/drivers/staging/kpc2000/Kconfig b/drivers/staging/kpc2000/Kconfig
index 3bb2efd511c4..897965359fcb 100644
--- a/drivers/staging/kpc2000/Kconfig
+++ b/drivers/staging/kpc2000/Kconfig
@@ -23,7 +23,7 @@ config KPC2000_CORE
If unsure, say N.
config KPC2000_SPI
- tristate "Kaktronics KPC SPI device"
+ tristate "Daktronics KPC SPI device"
depends on KPC2000 && SPI
help
Say Y here if you wish to support the Daktronics KPC PCI
@@ -35,7 +35,7 @@ config KPC2000_SPI
If unsure, say N.
config KPC2000_I2C
- tristate "Kaktronics KPC I2C device"
+ tristate "Daktronics KPC I2C device"
depends on KPC2000 && I2C
help
Say Y here if you wish to support the Daktronics KPC PCI
diff --git a/drivers/staging/kpc2000/Makefile b/drivers/staging/kpc2000/Makefile
index 1e48e9df1329..d15ed49807d5 100644
--- a/drivers/staging/kpc2000/Makefile
+++ b/drivers/staging/kpc2000/Makefile
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_KPC2000) += kpc2000/
-obj-$(CONFIG_KPC2000_I2C) += kpc_i2c/
-obj-$(CONFIG_KPC2000_SPI) += kpc_spi/
+obj-$(CONFIG_KPC2000_I2C) += kpc2000_i2c.o
+obj-$(CONFIG_KPC2000_SPI) += kpc2000_spi.o
obj-$(CONFIG_KPC2000_DMA) += kpc_dma/
diff --git a/drivers/staging/kpc2000/TODO b/drivers/staging/kpc2000/TODO
index 8c7af29fefae..9b5ab37fb3a0 100644
--- a/drivers/staging/kpc2000/TODO
+++ b/drivers/staging/kpc2000/TODO
@@ -1,8 +1,2 @@
- the kpc_spi driver doesn't seem to let multiple transactions (to different instances of the core) happen in parallel...
- The kpc_i2c driver is a hot mess, it should probably be cleaned up a ton. It functions against current hardware though.
-- pcard->card_num in kp2000_pcie_probe() is a global variable and needs atomic / locking / something better.
-- probe_core_uio() probably needs error handling
-- the loop in kp2000_probe_cores() that uses probe_core_uio() also probably needs error handling
-- would be nice if the AIO fileops in kpc_dma could be made to work
- - probably want to add a CONFIG_ option to control compilation of the AIO functions
-- if the AIO fileops in kpc_dma start working, next would be making iov_count > 1 work too
diff --git a/drivers/staging/kpc2000/kpc2000/Makefile b/drivers/staging/kpc2000/kpc2000/Makefile
index 28ab1e185f9f..c274ad083db6 100644
--- a/drivers/staging/kpc2000/kpc2000/Makefile
+++ b/drivers/staging/kpc2000/kpc2000/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
obj-m := kpc2000.o
-kpc2000-objs += kp2000_module.o core.o cell_probe.o fileops.o
+kpc2000-objs += core.o cell_probe.o
diff --git a/drivers/staging/kpc2000/kpc2000/cell_probe.c b/drivers/staging/kpc2000/kpc2000/cell_probe.c
index e0dba91e7fa8..c124a836db27 100644
--- a/drivers/staging/kpc2000/kpc2000/cell_probe.c
+++ b/drivers/staging/kpc2000/kpc2000/cell_probe.c
@@ -4,7 +4,6 @@
#include <linux/types.h>
#include <linux/export.h>
#include <linux/slab.h>
-#include <asm/io.h>
#include <linux/io.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/mfd/core.h>
@@ -25,7 +24,7 @@
* D C2S DMA Present
* DDD C2S DMA Channel Number [up to 8 channels]
* II IRQ Count [0 to 3 IRQs per core]
- 1111111000
+ * 1111111000
* IIIIIII IRQ Base Number [up to 128 IRQs per card]
* ___ Spare
*
@@ -40,166 +39,192 @@
#define KP_CORE_ID_SPI 5
struct core_table_entry {
- u16 type;
- u32 offset;
- u32 length;
- bool s2c_dma_present;
- u8 s2c_dma_channel_num;
- bool c2s_dma_present;
- u8 c2s_dma_channel_num;
- u8 irq_count;
- u8 irq_base_num;
+ u16 type;
+ u32 offset;
+ u32 length;
+ bool s2c_dma_present;
+ u8 s2c_dma_channel_num;
+ bool c2s_dma_present;
+ u8 c2s_dma_channel_num;
+ u8 irq_count;
+ u8 irq_base_num;
};
static
void parse_core_table_entry_v0(struct core_table_entry *cte, const u64 read_val)
{
- cte->type = ((read_val & 0xFFF0000000000000) >> 52);
- cte->offset = ((read_val & 0x00000000FFFF0000) >> 16) * 4096;
- cte->length = ((read_val & 0x0000FFFF00000000) >> 32) * 8;
- cte->s2c_dma_present = ((read_val & 0x0008000000000000) >> 51);
- cte->s2c_dma_channel_num = ((read_val & 0x0007000000000000) >> 48);
- cte->c2s_dma_present = ((read_val & 0x0000000000008000) >> 15);
- cte->c2s_dma_channel_num = ((read_val & 0x0000000000007000) >> 12);
- cte->irq_count = ((read_val & 0x0000000000000C00) >> 10);
- cte->irq_base_num = ((read_val & 0x00000000000003F8) >> 3);
+ cte->type = ((read_val & 0xFFF0000000000000) >> 52);
+ cte->offset = ((read_val & 0x00000000FFFF0000) >> 16) * 4096;
+ cte->length = ((read_val & 0x0000FFFF00000000) >> 32) * 8;
+ cte->s2c_dma_present = ((read_val & 0x0008000000000000) >> 51);
+ cte->s2c_dma_channel_num = ((read_val & 0x0007000000000000) >> 48);
+ cte->c2s_dma_present = ((read_val & 0x0000000000008000) >> 15);
+ cte->c2s_dma_channel_num = ((read_val & 0x0000000000007000) >> 12);
+ cte->irq_count = ((read_val & 0x0000000000000C00) >> 10);
+ cte->irq_base_num = ((read_val & 0x00000000000003F8) >> 3);
}
static
void dbg_cte(struct kp2000_device *pcard, struct core_table_entry *cte)
{
- dev_dbg(&pcard->pdev->dev, "CTE: type:%3d offset:%3d (%3d) length:%3d (%3d) s2c:%d c2s:%d irq_count:%d base_irq:%d\n",
- cte->type,
- cte->offset,
- cte->offset / 4096,
- cte->length,
- cte->length / 8,
- (cte->s2c_dma_present ? cte->s2c_dma_channel_num : -1),
- (cte->c2s_dma_present ? cte->c2s_dma_channel_num : -1),
- cte->irq_count,
- cte->irq_base_num
- );
+ dev_dbg(&pcard->pdev->dev, "CTE: type:%3d offset:%3d (%3d) length:%3d (%3d) s2c:%d c2s:%d irq_count:%d base_irq:%d\n",
+ cte->type,
+ cte->offset,
+ cte->offset / 4096,
+ cte->length,
+ cte->length / 8,
+ (cte->s2c_dma_present ? cte->s2c_dma_channel_num : -1),
+ (cte->c2s_dma_present ? cte->c2s_dma_channel_num : -1),
+ cte->irq_count,
+ cte->irq_base_num
+ );
}
static
void parse_core_table_entry(struct core_table_entry *cte, const u64 read_val, const u8 entry_rev)
{
switch (entry_rev) {
- case 0: parse_core_table_entry_v0(cte, read_val); break;
- default: cte->type = 0; break;
+ case 0:
+ parse_core_table_entry_v0(cte, read_val);
+ break;
+ default:
+ cte->type = 0;
+ break;
}
}
-
-int probe_core_basic(unsigned int core_num, struct kp2000_device *pcard, char *name, const struct core_table_entry cte)
+static int probe_core_basic(unsigned int core_num, struct kp2000_device *pcard,
+ char *name, const struct core_table_entry cte)
{
- struct mfd_cell cell = {0};
- struct resource resources[2];
-
- struct kpc_core_device_platdata core_pdata = {
- .card_id = pcard->card_id,
- .build_version = pcard->build_version,
- .hardware_revision = pcard->hardware_revision,
- .ssid = pcard->ssid,
- .ddna = pcard->ddna,
- };
-
- dev_dbg(&pcard->pdev->dev, "Found Basic core: type = %02d dma = %02x / %02x offset = 0x%x length = 0x%x (%d regs)\n", cte.type, KPC_OLD_S2C_DMA_CH_NUM(cte), KPC_OLD_C2S_DMA_CH_NUM(cte), cte.offset, cte.length, cte.length / 8);
-
-
- cell.platform_data = &core_pdata;
- cell.pdata_size = sizeof(struct kpc_core_device_platdata);
- cell.name = name;
- cell.id = core_num;
- cell.num_resources = 2;
-
- memset(&resources, 0, sizeof(resources));
-
- resources[0].start = cte.offset;
- resources[0].end = cte.offset + (cte.length - 1);
- resources[0].flags = IORESOURCE_MEM;
-
- resources[1].start = pcard->pdev->irq;
- resources[1].end = pcard->pdev->irq;
- resources[1].flags = IORESOURCE_IRQ;
-
- cell.resources = resources;
-
- return mfd_add_devices(
- PCARD_TO_DEV(pcard), // parent
- pcard->card_num * 100, // id
- &cell, // struct mfd_cell *
- 1, // ndevs
- &pcard->regs_base_resource,
- 0, // irq_base
- NULL // struct irq_domain *
- );
+ struct mfd_cell cell = { .id = core_num, .name = name };
+ struct resource resources[2];
+
+ struct kpc_core_device_platdata core_pdata = {
+ .card_id = pcard->card_id,
+ .build_version = pcard->build_version,
+ .hardware_revision = pcard->hardware_revision,
+ .ssid = pcard->ssid,
+ .ddna = pcard->ddna,
+ };
+
+ dev_dbg(&pcard->pdev->dev, "Found Basic core: type = %02d dma = %02x / %02x offset = 0x%x length = 0x%x (%d regs)\n", cte.type, KPC_OLD_S2C_DMA_CH_NUM(cte), KPC_OLD_C2S_DMA_CH_NUM(cte), cte.offset, cte.length, cte.length / 8);
+
+ cell.platform_data = &core_pdata;
+ cell.pdata_size = sizeof(struct kpc_core_device_platdata);
+ cell.num_resources = 2;
+
+ memset(&resources, 0, sizeof(resources));
+
+ resources[0].start = cte.offset;
+ resources[0].end = cte.offset + (cte.length - 1);
+ resources[0].flags = IORESOURCE_MEM;
+
+ resources[1].start = pcard->pdev->irq;
+ resources[1].end = pcard->pdev->irq;
+ resources[1].flags = IORESOURCE_IRQ;
+
+ cell.resources = resources;
+
+ return mfd_add_devices(PCARD_TO_DEV(pcard), // parent
+ pcard->card_num * 100, // id
+ &cell, // struct mfd_cell *
+ 1, // ndevs
+ &pcard->regs_base_resource,
+ 0, // irq_base
+ NULL); // struct irq_domain *
}
-
struct kpc_uio_device {
- struct list_head list;
- struct kp2000_device *pcard;
- struct device *dev;
- struct uio_info uioinfo;
- struct core_table_entry cte;
- u16 core_num;
+ struct list_head list;
+ struct kp2000_device *pcard;
+ struct device *dev;
+ struct uio_info uioinfo;
+ struct core_table_entry cte;
+ u16 core_num;
};
-static ssize_t show_attr(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t offset_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct kpc_uio_device *kudev = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", kudev->cte.offset);
+}
+static DEVICE_ATTR_RO(offset);
+
+static ssize_t size_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct kpc_uio_device *kudev = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", kudev->cte.length);
+}
+static DEVICE_ATTR_RO(size);
+
+static ssize_t type_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct kpc_uio_device *kudev = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", kudev->cte.type);
+}
+static DEVICE_ATTR_RO(type);
+
+static ssize_t s2c_dma_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct kpc_uio_device *kudev = dev_get_drvdata(dev);
+
+ if (!kudev->cte.s2c_dma_present)
+ return sprintf(buf, "%s", "not present\n");
+
+ return sprintf(buf, "%u\n", kudev->cte.s2c_dma_channel_num);
+}
+static DEVICE_ATTR_RO(s2c_dma);
+
+static ssize_t c2s_dma_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct kpc_uio_device *kudev = dev_get_drvdata(dev);
+
+ if (!kudev->cte.c2s_dma_present)
+ return sprintf(buf, "%s", "not present\n");
+
+ return sprintf(buf, "%u\n", kudev->cte.c2s_dma_channel_num);
+}
+static DEVICE_ATTR_RO(c2s_dma);
+
+static ssize_t irq_count_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
- struct kpc_uio_device *kudev = dev_get_drvdata(dev);
-
- #define ATTR_NAME_CMP(v) (strcmp(v, attr->attr.name) == 0)
- if ATTR_NAME_CMP("offset"){
- return scnprintf(buf, PAGE_SIZE, "%u\n", kudev->cte.offset);
- } else if ATTR_NAME_CMP("size"){
- return scnprintf(buf, PAGE_SIZE, "%u\n", kudev->cte.length);
- } else if ATTR_NAME_CMP("type"){
- return scnprintf(buf, PAGE_SIZE, "%u\n", kudev->cte.type);
- }
- else if ATTR_NAME_CMP("s2c_dma"){
- if (kudev->cte.s2c_dma_present){
- return scnprintf(buf, PAGE_SIZE, "%u\n", kudev->cte.s2c_dma_channel_num);
- } else {
- return scnprintf(buf, PAGE_SIZE, "not present\n");
- }
- } else if ATTR_NAME_CMP("c2s_dma"){
- if (kudev->cte.c2s_dma_present){
- return scnprintf(buf, PAGE_SIZE, "%u\n", kudev->cte.c2s_dma_channel_num);
- } else {
- return scnprintf(buf, PAGE_SIZE, "not present\n");
- }
- }
- else if ATTR_NAME_CMP("irq_count"){
- return scnprintf(buf, PAGE_SIZE, "%u\n", kudev->cte.irq_count);
- } else if ATTR_NAME_CMP("irq_base_num"){
- return scnprintf(buf, PAGE_SIZE, "%u\n", kudev->cte.irq_base_num);
- } else if ATTR_NAME_CMP("core_num"){
- return scnprintf(buf, PAGE_SIZE, "%u\n", kudev->core_num);
- } else {
- return 0;
- }
- #undef ATTR_NAME_CMP
+ struct kpc_uio_device *kudev = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", kudev->cte.irq_count);
+}
+static DEVICE_ATTR_RO(irq_count);
+
+static ssize_t irq_base_num_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct kpc_uio_device *kudev = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", kudev->cte.irq_base_num);
}
+static DEVICE_ATTR_RO(irq_base_num);
+
+static ssize_t core_num_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct kpc_uio_device *kudev = dev_get_drvdata(dev);
+ return sprintf(buf, "%u\n", kudev->core_num);
+}
+static DEVICE_ATTR_RO(core_num);
-DEVICE_ATTR(offset, 0444, show_attr, NULL);
-DEVICE_ATTR(size, 0444, show_attr, NULL);
-DEVICE_ATTR(type, 0444, show_attr, NULL);
-DEVICE_ATTR(s2c_dma_ch, 0444, show_attr, NULL);
-DEVICE_ATTR(c2s_dma_ch, 0444, show_attr, NULL);
-DEVICE_ATTR(s2c_dma, 0444, show_attr, NULL);
-DEVICE_ATTR(c2s_dma, 0444, show_attr, NULL);
-DEVICE_ATTR(irq_count, 0444, show_attr, NULL);
-DEVICE_ATTR(irq_base_num, 0444, show_attr, NULL);
-DEVICE_ATTR(core_num, 0444, show_attr, NULL);
-struct attribute * kpc_uio_class_attrs[] = {
+struct attribute *kpc_uio_class_attrs[] = {
&dev_attr_offset.attr,
&dev_attr_size.attr,
&dev_attr_type.attr,
- &dev_attr_s2c_dma_ch.attr,
- &dev_attr_c2s_dma_ch.attr,
&dev_attr_s2c_dma.attr,
&dev_attr_c2s_dma.attr,
&dev_attr_irq_count.attr,
@@ -208,264 +233,277 @@ struct attribute * kpc_uio_class_attrs[] = {
NULL,
};
-
static
int kp2000_check_uio_irq(struct kp2000_device *pcard, u32 irq_num)
{
- u64 interrupt_active = readq(pcard->sysinfo_regs_base + REG_INTERRUPT_ACTIVE);
- u64 interrupt_mask_inv = ~readq(pcard->sysinfo_regs_base + REG_INTERRUPT_MASK);
- u64 irq_check_mask = (1 << irq_num);
- if (interrupt_active & irq_check_mask){ // if it's active (interrupt pending)
- if (interrupt_mask_inv & irq_check_mask){ // and if it's not masked off
- return 1;
- }
- }
- return 0;
+ u64 interrupt_active = readq(pcard->sysinfo_regs_base + REG_INTERRUPT_ACTIVE);
+ u64 interrupt_mask_inv = ~readq(pcard->sysinfo_regs_base + REG_INTERRUPT_MASK);
+ u64 irq_check_mask = BIT_ULL(irq_num);
+
+ if (interrupt_active & irq_check_mask) { // if it's active (interrupt pending)
+ if (interrupt_mask_inv & irq_check_mask) { // and if it's not masked off
+ return 1;
+ }
+ }
+ return 0;
}
static
irqreturn_t kuio_handler(int irq, struct uio_info *uioinfo)
{
- struct kpc_uio_device *kudev = uioinfo->priv;
- if (irq != kudev->pcard->pdev->irq)
- return IRQ_NONE;
-
- if (kp2000_check_uio_irq(kudev->pcard, kudev->cte.irq_base_num)){
- writeq((1 << kudev->cte.irq_base_num), kudev->pcard->sysinfo_regs_base + REG_INTERRUPT_ACTIVE); // Clear the active flag
- return IRQ_HANDLED;
- }
- return IRQ_NONE;
+ struct kpc_uio_device *kudev = uioinfo->priv;
+
+ if (irq != kudev->pcard->pdev->irq)
+ return IRQ_NONE;
+
+ if (kp2000_check_uio_irq(kudev->pcard, kudev->cte.irq_base_num)) {
+ /* Clear the active flag */
+ writeq(BIT_ULL(kudev->cte.irq_base_num),
+ kudev->pcard->sysinfo_regs_base + REG_INTERRUPT_ACTIVE);
+ return IRQ_HANDLED;
+ }
+ return IRQ_NONE;
}
static
int kuio_irqcontrol(struct uio_info *uioinfo, s32 irq_on)
{
- struct kpc_uio_device *kudev = uioinfo->priv;
- struct kp2000_device *pcard = kudev->pcard;
- u64 mask;
-
- lock_card(pcard);
- mask = readq(pcard->sysinfo_regs_base + REG_INTERRUPT_MASK);
- if (irq_on){
- mask &= ~(1 << (kudev->cte.irq_base_num));
- } else {
- mask |= (1 << (kudev->cte.irq_base_num));
- }
- writeq(mask, pcard->sysinfo_regs_base + REG_INTERRUPT_MASK);
- unlock_card(pcard);
-
- return 0;
+ struct kpc_uio_device *kudev = uioinfo->priv;
+ struct kp2000_device *pcard = kudev->pcard;
+ u64 mask;
+
+ mutex_lock(&pcard->sem);
+ mask = readq(pcard->sysinfo_regs_base + REG_INTERRUPT_MASK);
+ if (irq_on)
+ mask &= ~(BIT_ULL(kudev->cte.irq_base_num));
+ else
+ mask |= BIT_ULL(kudev->cte.irq_base_num);
+ writeq(mask, pcard->sysinfo_regs_base + REG_INTERRUPT_MASK);
+ mutex_unlock(&pcard->sem);
+
+ return 0;
}
-int probe_core_uio(unsigned int core_num, struct kp2000_device *pcard, char *name, const struct core_table_entry cte)
+static int probe_core_uio(unsigned int core_num, struct kp2000_device *pcard,
+ char *name, const struct core_table_entry cte)
{
- struct kpc_uio_device *kudev;
- int rv;
-
- dev_dbg(&pcard->pdev->dev, "Found UIO core: type = %02d dma = %02x / %02x offset = 0x%x length = 0x%x (%d regs)\n", cte.type, KPC_OLD_S2C_DMA_CH_NUM(cte), KPC_OLD_C2S_DMA_CH_NUM(cte), cte.offset, cte.length, cte.length / 8);
-
- kudev = kzalloc(sizeof(struct kpc_uio_device), GFP_KERNEL);
- if (!kudev){
- dev_err(&pcard->pdev->dev, "probe_core_uio: failed to kzalloc kpc_uio_device\n");
- return -ENOMEM;
- }
-
- INIT_LIST_HEAD(&kudev->list);
- kudev->pcard = pcard;
- kudev->cte = cte;
- kudev->core_num = core_num;
-
- kudev->uioinfo.priv = kudev;
- kudev->uioinfo.name = name;
- kudev->uioinfo.version = "0.0";
- if (cte.irq_count > 0){
- kudev->uioinfo.irq_flags = IRQF_SHARED;
- kudev->uioinfo.irq = pcard->pdev->irq;
- kudev->uioinfo.handler = kuio_handler;
- kudev->uioinfo.irqcontrol = kuio_irqcontrol;
- } else {
- kudev->uioinfo.irq = 0;
- }
-
- kudev->uioinfo.mem[0].name = "uiomap";
- kudev->uioinfo.mem[0].addr = pci_resource_start(pcard->pdev, REG_BAR) + cte.offset;
- kudev->uioinfo.mem[0].size = (cte.length + PAGE_SIZE-1) & ~(PAGE_SIZE-1); // Round up to nearest PAGE_SIZE boundary
- kudev->uioinfo.mem[0].memtype = UIO_MEM_PHYS;
-
- kudev->dev = device_create(kpc_uio_class, &pcard->pdev->dev, MKDEV(0,0), kudev, "%s.%d.%d.%d", kudev->uioinfo.name, pcard->card_num, cte.type, kudev->core_num);
- if (IS_ERR(kudev->dev)) {
- dev_err(&pcard->pdev->dev, "probe_core_uio device_create failed!\n");
- return -ENODEV;
- }
- dev_set_drvdata(kudev->dev, kudev);
-
- rv = uio_register_device(kudev->dev, &kudev->uioinfo);
- if (rv){
- dev_err(&pcard->pdev->dev, "probe_core_uio failed uio_register_device: %d\n", rv);
- return rv;
- }
-
- list_add_tail(&kudev->list, &pcard->uio_devices_list);
-
- return 0;
-}
+ struct kpc_uio_device *kudev;
+ int rv;
+
+ dev_dbg(&pcard->pdev->dev, "Found UIO core: type = %02d dma = %02x / %02x offset = 0x%x length = 0x%x (%d regs)\n", cte.type, KPC_OLD_S2C_DMA_CH_NUM(cte), KPC_OLD_C2S_DMA_CH_NUM(cte), cte.offset, cte.length, cte.length / 8);
+
+ kudev = kzalloc(sizeof(*kudev), GFP_KERNEL);
+ if (!kudev)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&kudev->list);
+ kudev->pcard = pcard;
+ kudev->cte = cte;
+ kudev->core_num = core_num;
+
+ kudev->uioinfo.priv = kudev;
+ kudev->uioinfo.name = name;
+ kudev->uioinfo.version = "0.0";
+ if (cte.irq_count > 0) {
+ kudev->uioinfo.irq_flags = IRQF_SHARED;
+ kudev->uioinfo.irq = pcard->pdev->irq;
+ kudev->uioinfo.handler = kuio_handler;
+ kudev->uioinfo.irqcontrol = kuio_irqcontrol;
+ } else {
+ kudev->uioinfo.irq = 0;
+ }
+
+ kudev->uioinfo.mem[0].name = "uiomap";
+ kudev->uioinfo.mem[0].addr = pci_resource_start(pcard->pdev, REG_BAR) + cte.offset;
+ kudev->uioinfo.mem[0].size = (cte.length + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); // Round up to nearest PAGE_SIZE boundary
+ kudev->uioinfo.mem[0].memtype = UIO_MEM_PHYS;
+
+ kudev->dev = device_create(kpc_uio_class, &pcard->pdev->dev, MKDEV(0, 0), kudev, "%s.%d.%d.%d", kudev->uioinfo.name, pcard->card_num, cte.type, kudev->core_num);
+ if (IS_ERR(kudev->dev)) {
+ dev_err(&pcard->pdev->dev, "%s: device_create failed!\n",
+ __func__);
+ kfree(kudev);
+ return -ENODEV;
+ }
+ dev_set_drvdata(kudev->dev, kudev);
+
+ rv = uio_register_device(kudev->dev, &kudev->uioinfo);
+ if (rv) {
+ dev_err(&pcard->pdev->dev, "%s: failed uio_register_device: %d\n",
+ __func__, rv);
+ put_device(kudev->dev);
+ kfree(kudev);
+ return rv;
+ }
+ list_add_tail(&kudev->list, &pcard->uio_devices_list);
+
+ return 0;
+}
static int create_dma_engine_core(struct kp2000_device *pcard, size_t engine_regs_offset, int engine_num, int irq_num)
{
- struct mfd_cell cell = {0};
- struct resource resources[2];
-
- dev_dbg(&pcard->pdev->dev, "create_dma_core(pcard = [%p], engine_regs_offset = %zx, engine_num = %d)\n", pcard, engine_regs_offset, engine_num);
-
- cell.platform_data = NULL;
- cell.pdata_size = 0;
- cell.id = engine_num;
- cell.name = KP_DRIVER_NAME_DMA_CONTROLLER;
- cell.num_resources = 2;
-
- memset(&resources, 0, sizeof(resources));
-
- resources[0].start = engine_regs_offset;
- resources[0].end = engine_regs_offset + (KPC_DMA_ENGINE_SIZE - 1);
- resources[0].flags = IORESOURCE_MEM;
-
- resources[1].start = irq_num;
- resources[1].end = irq_num;
- resources[1].flags = IORESOURCE_IRQ;
-
- cell.resources = resources;
-
- return mfd_add_devices(
- PCARD_TO_DEV(pcard), // parent
- pcard->card_num * 100, // id
- &cell, // struct mfd_cell *
- 1, // ndevs
- &pcard->dma_base_resource,
- 0, // irq_base
- NULL // struct irq_domain *
- );
+ struct mfd_cell cell = { .id = engine_num };
+ struct resource resources[2];
+
+ cell.platform_data = NULL;
+ cell.pdata_size = 0;
+ cell.name = KP_DRIVER_NAME_DMA_CONTROLLER;
+ cell.num_resources = 2;
+
+ memset(&resources, 0, sizeof(resources));
+
+ resources[0].start = engine_regs_offset;
+ resources[0].end = engine_regs_offset + (KPC_DMA_ENGINE_SIZE - 1);
+ resources[0].flags = IORESOURCE_MEM;
+
+ resources[1].start = irq_num;
+ resources[1].end = irq_num;
+ resources[1].flags = IORESOURCE_IRQ;
+
+ cell.resources = resources;
+
+ return mfd_add_devices(PCARD_TO_DEV(pcard), // parent
+ pcard->card_num * 100, // id
+ &cell, // struct mfd_cell *
+ 1, // ndevs
+ &pcard->dma_base_resource,
+ 0, // irq_base
+ NULL); // struct irq_domain *
}
static int kp2000_setup_dma_controller(struct kp2000_device *pcard)
{
- int err;
- unsigned int i;
- u64 capabilities_reg;
-
- // S2C Engines
- for (i = 0 ; i < 32 ; i++){
- capabilities_reg = readq( pcard->dma_bar_base + KPC_DMA_S2C_BASE_OFFSET + (KPC_DMA_ENGINE_SIZE * i) );
- if (capabilities_reg & ENGINE_CAP_PRESENT_MASK){
- err = create_dma_engine_core(pcard, (KPC_DMA_S2C_BASE_OFFSET + (KPC_DMA_ENGINE_SIZE * i)), i, pcard->pdev->irq);
- if (err) goto err_out;
- }
- }
- // C2S Engines
- for (i = 0 ; i < 32 ; i++){
- capabilities_reg = readq( pcard->dma_bar_base + KPC_DMA_C2S_BASE_OFFSET + (KPC_DMA_ENGINE_SIZE * i) );
- if (capabilities_reg & ENGINE_CAP_PRESENT_MASK){
- err = create_dma_engine_core(pcard, (KPC_DMA_C2S_BASE_OFFSET + (KPC_DMA_ENGINE_SIZE * i)), 32+i, pcard->pdev->irq);
- if (err) goto err_out;
- }
- }
-
- return 0;
-
+ int err;
+ unsigned int i;
+ u64 capabilities_reg;
+
+ // S2C Engines
+ for (i = 0 ; i < 32 ; i++) {
+ capabilities_reg = readq(pcard->dma_bar_base + KPC_DMA_S2C_BASE_OFFSET + (KPC_DMA_ENGINE_SIZE * i));
+ if (capabilities_reg & ENGINE_CAP_PRESENT_MASK) {
+ err = create_dma_engine_core(pcard, (KPC_DMA_S2C_BASE_OFFSET + (KPC_DMA_ENGINE_SIZE * i)), i, pcard->pdev->irq);
+ if (err)
+ goto err_out;
+ }
+ }
+ // C2S Engines
+ for (i = 0 ; i < 32 ; i++) {
+ capabilities_reg = readq(pcard->dma_bar_base + KPC_DMA_C2S_BASE_OFFSET + (KPC_DMA_ENGINE_SIZE * i));
+ if (capabilities_reg & ENGINE_CAP_PRESENT_MASK) {
+ err = create_dma_engine_core(pcard, (KPC_DMA_C2S_BASE_OFFSET + (KPC_DMA_ENGINE_SIZE * i)), 32 + i, pcard->pdev->irq);
+ if (err)
+ goto err_out;
+ }
+ }
+
+ return 0;
+
err_out:
- dev_err(&pcard->pdev->dev, "kp2000_setup_dma_controller: failed to add a DMA Engine: %d\n", err);
- return err;
+ dev_err(&pcard->pdev->dev, "%s: failed to add a DMA Engine: %d\n",
+ __func__, err);
+ return err;
}
int kp2000_probe_cores(struct kp2000_device *pcard)
{
- int err = 0;
- int i;
- int current_type_id;
- u64 read_val;
- unsigned int highest_core_id = 0;
- struct core_table_entry cte;
-
- dev_dbg(&pcard->pdev->dev, "kp2000_probe_cores(pcard = %p / %d)\n", pcard, pcard->card_num);
-
- err = kp2000_setup_dma_controller(pcard);
- if (err) return err;
-
- INIT_LIST_HEAD(&pcard->uio_devices_list);
-
- // First, iterate the core table looking for the highest CORE_ID
- for (i = 0 ; i < pcard->core_table_length ; i++){
- read_val = readq(pcard->sysinfo_regs_base + ((pcard->core_table_offset + i) * 8));
- parse_core_table_entry(&cte, read_val, pcard->core_table_rev);
- dbg_cte(pcard, &cte);
- if (cte.type > highest_core_id){
- highest_core_id = cte.type;
- }
- if (cte.type == KP_CORE_ID_INVALID){
- dev_info(&pcard->pdev->dev, "Found Invalid core: %016llx\n", read_val);
- }
- }
- // Then, iterate over the possible core types.
- for (current_type_id = 1 ; current_type_id <= highest_core_id ; current_type_id++){
- unsigned int core_num = 0;
- // Foreach core type, iterate the whole table and instantiate subdevices for each core.
- // Yes, this is O(n*m) but the actual runtime is small enough that it's an acceptable tradeoff.
- for (i = 0 ; i < pcard->core_table_length ; i++){
- read_val = readq(pcard->sysinfo_regs_base + ((pcard->core_table_offset + i) * 8));
- parse_core_table_entry(&cte, read_val, pcard->core_table_rev);
-
- if (cte.type == current_type_id){
- switch (cte.type){
- case KP_CORE_ID_I2C:
- err = probe_core_basic(core_num, pcard, KP_DRIVER_NAME_I2C, cte);
- break;
-
- case KP_CORE_ID_SPI:
- err = probe_core_basic(core_num, pcard, KP_DRIVER_NAME_SPI, cte);
- break;
-
- default:
- err = probe_core_uio(core_num, pcard, "kpc_uio", cte);
- break;
- }
- if (err){
- dev_err(&pcard->pdev->dev, "kp2000_probe_cores: failed to add core %d: %d\n", i, err);
- return err;
- }
- core_num++;
- }
- }
- }
-
- // Finally, instantiate a UIO device for the core_table.
- cte.type = 0; // CORE_ID_BOARD_INFO
- cte.offset = 0; // board info is always at the beginning
- cte.length = 512*8;
- cte.s2c_dma_present = false;
- cte.s2c_dma_channel_num = 0;
- cte.c2s_dma_present = false;
- cte.c2s_dma_channel_num = 0;
- cte.irq_count = 0;
- cte.irq_base_num = 0;
- err = probe_core_uio(0, pcard, "kpc_uio", cte);
- if (err){
- dev_err(&pcard->pdev->dev, "kp2000_probe_cores: failed to add board_info core: %d\n", err);
- return err;
- }
-
- return 0;
+ int err = 0;
+ int i;
+ int current_type_id;
+ u64 read_val;
+ unsigned int highest_core_id = 0;
+ struct core_table_entry cte;
+
+ err = kp2000_setup_dma_controller(pcard);
+ if (err)
+ return err;
+
+ INIT_LIST_HEAD(&pcard->uio_devices_list);
+
+ // First, iterate the core table looking for the highest CORE_ID
+ for (i = 0 ; i < pcard->core_table_length ; i++) {
+ read_val = readq(pcard->sysinfo_regs_base + ((pcard->core_table_offset + i) * 8));
+ parse_core_table_entry(&cte, read_val, pcard->core_table_rev);
+ dbg_cte(pcard, &cte);
+ if (cte.type > highest_core_id)
+ highest_core_id = cte.type;
+ if (cte.type == KP_CORE_ID_INVALID)
+ dev_info(&pcard->pdev->dev, "Found Invalid core: %016llx\n", read_val);
+ }
+ // Then, iterate over the possible core types.
+ for (current_type_id = 1 ; current_type_id <= highest_core_id ; current_type_id++) {
+ unsigned int core_num = 0;
+ // Foreach core type, iterate the whole table and instantiate subdevices for each core.
+ // Yes, this is O(n*m) but the actual runtime is small enough that it's an acceptable tradeoff.
+ for (i = 0 ; i < pcard->core_table_length ; i++) {
+ read_val = readq(pcard->sysinfo_regs_base + ((pcard->core_table_offset + i) * 8));
+ parse_core_table_entry(&cte, read_val, pcard->core_table_rev);
+
+ if (cte.type != current_type_id)
+ continue;
+
+ switch (cte.type) {
+ case KP_CORE_ID_I2C:
+ err = probe_core_basic(core_num, pcard,
+ KP_DRIVER_NAME_I2C, cte);
+ break;
+
+ case KP_CORE_ID_SPI:
+ err = probe_core_basic(core_num, pcard,
+ KP_DRIVER_NAME_SPI, cte);
+ break;
+
+ default:
+ err = probe_core_uio(core_num, pcard, "kpc_uio", cte);
+ break;
+ }
+ if (err) {
+ dev_err(&pcard->pdev->dev,
+ "%s: failed to add core %d: %d\n",
+ __func__, i, err);
+ goto error;
+ }
+ core_num++;
+ }
+ }
+
+ // Finally, instantiate a UIO device for the core_table.
+ cte.type = 0; // CORE_ID_BOARD_INFO
+ cte.offset = 0; // board info is always at the beginning
+ cte.length = 512 * 8;
+ cte.s2c_dma_present = false;
+ cte.s2c_dma_channel_num = 0;
+ cte.c2s_dma_present = false;
+ cte.c2s_dma_channel_num = 0;
+ cte.irq_count = 0;
+ cte.irq_base_num = 0;
+ err = probe_core_uio(0, pcard, "kpc_uio", cte);
+ if (err) {
+ dev_err(&pcard->pdev->dev, "%s: failed to add board_info core: %d\n",
+ __func__, err);
+ goto error;
+ }
+
+ return 0;
+
+error:
+ kp2000_remove_cores(pcard);
+ mfd_remove_devices(PCARD_TO_DEV(pcard));
+ return err;
}
void kp2000_remove_cores(struct kp2000_device *pcard)
{
- struct list_head *ptr;
- struct list_head *next;
- list_for_each_safe(ptr, next, &pcard->uio_devices_list){
- struct kpc_uio_device *kudev = list_entry(ptr, struct kpc_uio_device, list);
- uio_unregister_device(&kudev->uioinfo);
- device_unregister(kudev->dev);
- list_del(&kudev->list);
- kfree(kudev);
- }
+ struct list_head *ptr;
+ struct list_head *next;
+
+ list_for_each_safe(ptr, next, &pcard->uio_devices_list) {
+ struct kpc_uio_device *kudev = list_entry(ptr, struct kpc_uio_device, list);
+
+ uio_unregister_device(&kudev->uioinfo);
+ device_unregister(kudev->dev);
+ list_del(&kudev->list);
+ kfree(kudev);
+ }
}
diff --git a/drivers/staging/kpc2000/kpc2000/core.c b/drivers/staging/kpc2000/kpc2000/core.c
index 40390cdd3c8d..cb05cca687e1 100644
--- a/drivers/staging/kpc2000/kpc2000/core.c
+++ b/drivers/staging/kpc2000/kpc2000/core.c
@@ -1,11 +1,17 @@
// SPDX-License-Identifier: GPL-2.0+
+#include <linux/kernel.h>
+#include <linux/idr.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/types.h>
#include <linux/export.h>
#include <linux/slab.h>
-#include <asm/io.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/cdev.h>
+#include <linux/rwsem.h>
+#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/mfd/core.h>
#include <linux/platform_device.h>
@@ -17,421 +23,543 @@
#include <linux/sched.h>
#include <linux/jiffies.h>
#include "pcie.h"
+#include "uapi.h"
+static DEFINE_IDA(card_num_ida);
/*******************************************************
- * SysFS Attributes
- ******************************************************/
-static ssize_t show_attr(struct device *dev, struct device_attribute *attr, char *buf)
+ * SysFS Attributes
+ ******************************************************/
+
+static ssize_t ssid_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
- struct pci_dev *pdev = to_pci_dev(dev);
- struct kp2000_device *pcard;
-
- if (!pdev) return -ENXIO;
- pcard = pci_get_drvdata(pdev);
- if (!pcard) return -ENXIO;
-
- if (strcmp("ssid", attr->attr.name) == 0){ return scnprintf(buf, PAGE_SIZE, "%016llx\n", pcard->ssid); } else
- if (strcmp("ddna", attr->attr.name) == 0){ return scnprintf(buf, PAGE_SIZE, "%016llx\n", pcard->ddna); } else
- if (strcmp("card_id", attr->attr.name) == 0){ return scnprintf(buf, PAGE_SIZE, "%08x\n", pcard->card_id); } else
- if (strcmp("hw_rev", attr->attr.name) == 0){ return scnprintf(buf, PAGE_SIZE, "%08x\n", pcard->hardware_revision); } else
- if (strcmp("build", attr->attr.name) == 0){ return scnprintf(buf, PAGE_SIZE, "%08x\n", pcard->build_version); } else
- if (strcmp("build_date", attr->attr.name) == 0){ return scnprintf(buf, PAGE_SIZE, "%08x\n", pcard->build_datestamp); } else
- if (strcmp("build_time", attr->attr.name) == 0){ return scnprintf(buf, PAGE_SIZE, "%08x\n", pcard->build_timestamp); } else
- { return -ENXIO; }
+ struct kp2000_device *pcard = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%016llx\n", pcard->ssid);
}
+static DEVICE_ATTR_RO(ssid);
-static ssize_t show_cpld_config_reg(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t ddna_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
- struct pci_dev *pdev = to_pci_dev(dev);
- struct kp2000_device *pcard;
- u64 val;
+ struct kp2000_device *pcard = dev_get_drvdata(dev);
- if (!pdev)
- return -ENXIO;
+ return sprintf(buf, "%016llx\n", pcard->ddna);
+}
+static DEVICE_ATTR_RO(ddna);
- pcard = pci_get_drvdata(pdev);
- if (!pcard)
- return -ENXIO;
+static ssize_t card_id_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct kp2000_device *pcard = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%08x\n", pcard->card_id);
+}
+static DEVICE_ATTR_RO(card_id);
+
+static ssize_t hw_rev_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct kp2000_device *pcard = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%08x\n", pcard->hardware_revision);
+}
+static DEVICE_ATTR_RO(hw_rev);
+
+static ssize_t build_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct kp2000_device *pcard = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%08x\n", pcard->build_version);
+}
+static DEVICE_ATTR_RO(build);
+
+static ssize_t build_date_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct kp2000_device *pcard = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%08x\n", pcard->build_datestamp);
+}
+static DEVICE_ATTR_RO(build_date);
+
+static ssize_t build_time_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct kp2000_device *pcard = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%08x\n", pcard->build_timestamp);
+}
+static DEVICE_ATTR_RO(build_time);
+
+static ssize_t cpld_reg_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct kp2000_device *pcard = dev_get_drvdata(dev);
+ u64 val;
val = readq(pcard->sysinfo_regs_base + REG_CPLD_CONFIG);
- return scnprintf(buf, PAGE_SIZE, "%016llx\n", val);
+ return sprintf(buf, "%016llx\n", val);
+}
+static DEVICE_ATTR_RO(cpld_reg);
+
+static ssize_t cpld_reconfigure(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct kp2000_device *pcard = dev_get_drvdata(dev);
+ long wr_val;
+ int rv;
+
+ rv = kstrtol(buf, 0, &wr_val);
+ if (rv < 0)
+ return rv;
+ if (wr_val > 7)
+ return -EINVAL;
+
+ wr_val = wr_val << 8;
+ wr_val |= 0x1; // Set the "Configure Go" bit
+ writeq(wr_val, pcard->sysinfo_regs_base + REG_CPLD_CONFIG);
+ return count;
}
-static ssize_t cpld_reconfigure(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static DEVICE_ATTR(cpld_reconfigure, 0220, NULL, cpld_reconfigure);
+
+static ssize_t irq_mask_reg_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct pci_dev *pdev = to_pci_dev(dev);
- long wr_val;
- struct kp2000_device *pcard;
- int rv;
-
- if (!pdev) return -ENXIO;
- pcard = pci_get_drvdata(pdev);
- if (!pcard) return -ENXIO;
-
- rv = kstrtol(buf, 0, &wr_val);
- if (rv < 0) return rv;
- if (wr_val > 7) return -EINVAL;
-
- wr_val = wr_val << 8;
- wr_val |= 0x1; // Set the "Configure Go" bit
- writeq(wr_val, pcard->sysinfo_regs_base + REG_CPLD_CONFIG);
- return count;
+ struct kp2000_device *pcard = dev_get_drvdata(dev);
+ u64 val;
+
+ val = readq(pcard->sysinfo_regs_base + REG_INTERRUPT_MASK);
+ return sprintf(buf, "%016llx\n", val);
}
+static DEVICE_ATTR_RO(irq_mask_reg);
+static ssize_t irq_active_reg_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct kp2000_device *pcard = dev_get_drvdata(dev);
+ u64 val;
-DEVICE_ATTR(ssid, 0444, show_attr, NULL);
-DEVICE_ATTR(ddna, 0444, show_attr, NULL);
-DEVICE_ATTR(card_id, 0444, show_attr, NULL);
-DEVICE_ATTR(hw_rev, 0444, show_attr, NULL);
-DEVICE_ATTR(build, 0444, show_attr, NULL);
-DEVICE_ATTR(build_date, 0444, show_attr, NULL);
-DEVICE_ATTR(build_time, 0444, show_attr, NULL);
-DEVICE_ATTR(cpld_reg, 0444, show_cpld_config_reg, NULL);
-DEVICE_ATTR(cpld_reconfigure, 0220, NULL, cpld_reconfigure);
-
-static const struct attribute * kp_attr_list[] = {
- &dev_attr_ssid.attr,
- &dev_attr_ddna.attr,
- &dev_attr_card_id.attr,
- &dev_attr_hw_rev.attr,
- &dev_attr_build.attr,
- &dev_attr_build_date.attr,
- &dev_attr_build_time.attr,
- &dev_attr_cpld_reg.attr,
- &dev_attr_cpld_reconfigure.attr,
- NULL,
-};
+ val = readq(pcard->sysinfo_regs_base + REG_INTERRUPT_ACTIVE);
+ return sprintf(buf, "%016llx\n", val);
+}
+static DEVICE_ATTR_RO(irq_active_reg);
+static ssize_t pcie_error_count_reg_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct kp2000_device *pcard = dev_get_drvdata(dev);
+ u64 val;
+
+ val = readq(pcard->sysinfo_regs_base + REG_PCIE_ERROR_COUNT);
+ return sprintf(buf, "%016llx\n", val);
+}
+static DEVICE_ATTR_RO(pcie_error_count_reg);
+
+static ssize_t core_table_offset_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct kp2000_device *pcard = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%08x\n", pcard->core_table_offset);
+}
+static DEVICE_ATTR_RO(core_table_offset);
+
+static ssize_t core_table_length_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct kp2000_device *pcard = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%08x\n", pcard->core_table_length);
+}
+static DEVICE_ATTR_RO(core_table_length);
+
+static const struct attribute *kp_attr_list[] = {
+ &dev_attr_ssid.attr,
+ &dev_attr_ddna.attr,
+ &dev_attr_card_id.attr,
+ &dev_attr_hw_rev.attr,
+ &dev_attr_build.attr,
+ &dev_attr_build_date.attr,
+ &dev_attr_build_time.attr,
+ &dev_attr_cpld_reg.attr,
+ &dev_attr_cpld_reconfigure.attr,
+ &dev_attr_irq_mask_reg.attr,
+ &dev_attr_irq_active_reg.attr,
+ &dev_attr_pcie_error_count_reg.attr,
+ &dev_attr_core_table_offset.attr,
+ &dev_attr_core_table_length.attr,
+ NULL,
+};
/*******************************************************
- * Functions
- ******************************************************/
+ * Functions
+ ******************************************************/
static void wait_and_read_ssid(struct kp2000_device *pcard)
{
- u64 read_val = readq(pcard->sysinfo_regs_base + REG_FPGA_SSID);
- unsigned long timeout;
-
- if (read_val & 0x8000000000000000){
- pcard->ssid = read_val;
- return;
- }
-
- timeout = jiffies + (HZ * 2);
- do {
- read_val = readq(pcard->sysinfo_regs_base + REG_FPGA_SSID);
- if (read_val & 0x8000000000000000){
- pcard->ssid = read_val;
- return;
- }
- cpu_relax();
- //schedule();
- } while (time_before(jiffies, timeout));
-
- dev_notice(&pcard->pdev->dev, "SSID didn't show up!\n");
-
- #if 0
- // Timed out waiting for the SSID to show up, just use the DDNA instead?
- read_val = readq(pcard->sysinfo_regs_base + REG_FPGA_DDNA);
- pcard->ssid = read_val;
- #else
- // Timed out waiting for the SSID to show up, stick all zeros in the value
- pcard->ssid = 0;
- #endif
+ u64 read_val = readq(pcard->sysinfo_regs_base + REG_FPGA_SSID);
+ unsigned long timeout;
+
+ if (read_val & 0x8000000000000000) {
+ pcard->ssid = read_val;
+ return;
+ }
+
+ timeout = jiffies + (HZ * 2);
+ do {
+ read_val = readq(pcard->sysinfo_regs_base + REG_FPGA_SSID);
+ if (read_val & 0x8000000000000000) {
+ pcard->ssid = read_val;
+ return;
+ }
+ cpu_relax();
+ //schedule();
+ } while (time_before(jiffies, timeout));
+
+ dev_notice(&pcard->pdev->dev, "SSID didn't show up!\n");
+
+ // Timed out waiting for the SSID to show up, stick all zeros in the
+ // value
+ pcard->ssid = 0;
}
static int read_system_regs(struct kp2000_device *pcard)
{
- u64 read_val;
-
- read_val = readq(pcard->sysinfo_regs_base + REG_MAGIC_NUMBER);
- if (read_val != KP2000_MAGIC_VALUE){
- dev_err(&pcard->pdev->dev, "Invalid magic! Got: 0x%016llx Want: 0x%016lx\n", read_val, KP2000_MAGIC_VALUE);
- return -EILSEQ;
- }
-
- read_val = readq(pcard->sysinfo_regs_base + REG_CARD_ID_AND_BUILD);
- pcard->card_id = (read_val & 0xFFFFFFFF00000000) >> 32;
- pcard->build_version = (read_val & 0x00000000FFFFFFFF) >> 0;
-
- read_val = readq(pcard->sysinfo_regs_base + REG_DATE_AND_TIME_STAMPS);
- pcard->build_datestamp = (read_val & 0xFFFFFFFF00000000) >> 32;
- pcard->build_timestamp = (read_val & 0x00000000FFFFFFFF) >> 0;
-
- read_val = readq(pcard->sysinfo_regs_base + REG_CORE_TABLE_OFFSET);
- pcard->core_table_length = (read_val & 0xFFFFFFFF00000000) >> 32;
- pcard->core_table_offset = (read_val & 0x00000000FFFFFFFF) >> 0;
-
- wait_and_read_ssid(pcard);
-
- read_val = readq(pcard->sysinfo_regs_base + REG_FPGA_HW_ID);
- pcard->core_table_rev = (read_val & 0x0000000000000F00) >> 8;
- pcard->hardware_revision = (read_val & 0x000000000000001F);
-
- read_val = readq(pcard->sysinfo_regs_base + REG_FPGA_DDNA);
- pcard->ddna = read_val;
-
- dev_info(&pcard->pdev->dev, "system_regs: %08x %08x %08x %08x %02x %d %d %016llx %016llx\n",
- pcard->card_id,
- pcard->build_version,
- pcard->build_datestamp,
- pcard->build_timestamp,
- pcard->hardware_revision,
- pcard->core_table_rev,
- pcard->core_table_length,
- pcard->ssid,
- pcard->ddna
- );
-
- if (pcard->core_table_rev > 1){
- dev_err(&pcard->pdev->dev, "core table entry revision is higher than we can deal with, cannot continue with this card!\n");
- return 1;
- }
-
- return 0;
+ u64 read_val;
+
+ read_val = readq(pcard->sysinfo_regs_base + REG_MAGIC_NUMBER);
+ if (read_val != KP2000_MAGIC_VALUE) {
+ dev_err(&pcard->pdev->dev,
+ "Invalid magic! Got: 0x%016llx Want: 0x%016llx\n",
+ read_val, KP2000_MAGIC_VALUE);
+ return -EILSEQ;
+ }
+
+ read_val = readq(pcard->sysinfo_regs_base + REG_CARD_ID_AND_BUILD);
+ pcard->card_id = (read_val & 0xFFFFFFFF00000000) >> 32;
+ pcard->build_version = (read_val & 0x00000000FFFFFFFF) >> 0;
+
+ read_val = readq(pcard->sysinfo_regs_base + REG_DATE_AND_TIME_STAMPS);
+ pcard->build_datestamp = (read_val & 0xFFFFFFFF00000000) >> 32;
+ pcard->build_timestamp = (read_val & 0x00000000FFFFFFFF) >> 0;
+
+ read_val = readq(pcard->sysinfo_regs_base + REG_CORE_TABLE_OFFSET);
+ pcard->core_table_length = (read_val & 0xFFFFFFFF00000000) >> 32;
+ pcard->core_table_offset = (read_val & 0x00000000FFFFFFFF) >> 0;
+
+ wait_and_read_ssid(pcard);
+
+ read_val = readq(pcard->sysinfo_regs_base + REG_FPGA_HW_ID);
+ pcard->core_table_rev = (read_val & 0x0000000000000F00) >> 8;
+ pcard->hardware_revision = (read_val & 0x000000000000001F);
+
+ read_val = readq(pcard->sysinfo_regs_base + REG_FPGA_DDNA);
+ pcard->ddna = read_val;
+
+ dev_info(&pcard->pdev->dev,
+ "system_regs: %08x %08x %08x %08x %02x %d %d %016llx %016llx\n",
+ pcard->card_id,
+ pcard->build_version,
+ pcard->build_datestamp,
+ pcard->build_timestamp,
+ pcard->hardware_revision,
+ pcard->core_table_rev,
+ pcard->core_table_length,
+ pcard->ssid,
+ pcard->ddna);
+
+ if (pcard->core_table_rev > 1) {
+ dev_err(&pcard->pdev->dev,
+ "core table entry revision is higher than we can deal with, cannot continue with this card!\n");
+ return 1;
+ }
+
+ return 0;
}
-irqreturn_t kp2000_irq_handler(int irq, void *dev_id)
+static irqreturn_t kp2000_irq_handler(int irq, void *dev_id)
{
- struct kp2000_device *pcard = (struct kp2000_device*)dev_id;
- SetBackEndControl(pcard->dma_common_regs, KPC_DMA_CARD_IRQ_ENABLE | KPC_DMA_CARD_USER_INTERRUPT_MODE | KPC_DMA_CARD_USER_INTERRUPT_ACTIVE);
- return IRQ_HANDLED;
+ struct kp2000_device *pcard = dev_id;
+
+ writel(KPC_DMA_CARD_IRQ_ENABLE |
+ KPC_DMA_CARD_USER_INTERRUPT_MODE |
+ KPC_DMA_CARD_USER_INTERRUPT_ACTIVE,
+ pcard->dma_common_regs);
+ return IRQ_HANDLED;
}
-int kp2000_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+static int kp2000_pcie_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
{
- int err = 0;
- struct kp2000_device *pcard;
- static int card_count = 1;
- int rv;
- unsigned long reg_bar_phys_addr;
- unsigned long reg_bar_phys_len;
- unsigned long dma_bar_phys_addr;
- unsigned long dma_bar_phys_len;
- u16 regval;
-
- dev_dbg(&pdev->dev, "kp2000_pcie_probe(pdev = [%p], id = [%p])\n", pdev, id);
-
- //{ Step 1: Allocate a struct for the pcard
- pcard = kzalloc(sizeof(struct kp2000_device), GFP_KERNEL);
- if (NULL == pcard){
- dev_err(&pdev->dev, "probe: failed to allocate private card data\n");
- return -ENOMEM;
- }
- dev_dbg(&pdev->dev, "probe: allocated struct kp2000_device @ %p\n", pcard);
- //}
-
- //{ Step 2: Initialize trivial pcard elements
- pcard->card_num = card_count;
- card_count++;
- scnprintf(pcard->name, 16, "kpcard%d", pcard->card_num);
-
- mutex_init(&pcard->sem);
- lock_card(pcard);
-
- pcard->pdev = pdev;
- pci_set_drvdata(pdev, pcard);
- //}
-
- //{ Step 3: Enable PCI device
- err = pci_enable_device(pcard->pdev);
- if (err){
- dev_err(&pcard->pdev->dev, "probe: failed to enable PCIE2000 PCIe device (%d)\n", err);
- goto out3;
- }
- //}
-
- //{ Step 4: Setup the Register BAR
- reg_bar_phys_addr = pci_resource_start(pcard->pdev, REG_BAR);
- reg_bar_phys_len = pci_resource_len(pcard->pdev, REG_BAR);
-
- pcard->regs_bar_base = ioremap_nocache(reg_bar_phys_addr, PAGE_SIZE);
- if (NULL == pcard->regs_bar_base){
- dev_err(&pcard->pdev->dev, "probe: REG_BAR could not remap memory to virtual space\n");
- err = -ENODEV;
- goto out4;
- }
- dev_dbg(&pcard->pdev->dev, "probe: REG_BAR virt hardware address start [%p]\n", pcard->regs_bar_base);
-
- err = pci_request_region(pcard->pdev, REG_BAR, KP_DRIVER_NAME_KP2000);
- if (err){
- iounmap(pcard->regs_bar_base);
- dev_err(&pcard->pdev->dev, "probe: failed to acquire PCI region (%d)\n", err);
- err = -ENODEV;
- goto out4;
- }
-
- pcard->regs_base_resource.start = reg_bar_phys_addr;
- pcard->regs_base_resource.end = reg_bar_phys_addr + reg_bar_phys_len - 1;
- pcard->regs_base_resource.flags = IORESOURCE_MEM;
- //}
-
- //{ Step 5: Setup the DMA BAR
- dma_bar_phys_addr = pci_resource_start(pcard->pdev, DMA_BAR);
- dma_bar_phys_len = pci_resource_len(pcard->pdev, DMA_BAR);
-
- pcard->dma_bar_base = ioremap_nocache(dma_bar_phys_addr, dma_bar_phys_len);
- if (NULL == pcard->dma_bar_base){
- dev_err(&pcard->pdev->dev, "probe: DMA_BAR could not remap memory to virtual space\n");
- err = -ENODEV;
- goto out5;
- }
- dev_dbg(&pcard->pdev->dev, "probe: DMA_BAR virt hardware address start [%p]\n", pcard->dma_bar_base);
-
- pcard->dma_common_regs = pcard->dma_bar_base + KPC_DMA_COMMON_OFFSET;
-
- err = pci_request_region(pcard->pdev, DMA_BAR, "kp2000_pcie");
- if (err){
- iounmap(pcard->dma_bar_base);
- dev_err(&pcard->pdev->dev, "probe: failed to acquire PCI region (%d)\n", err);
- err = -ENODEV;
- goto out5;
- }
-
- pcard->dma_base_resource.start = dma_bar_phys_addr;
- pcard->dma_base_resource.end = dma_bar_phys_addr + dma_bar_phys_len - 1;
- pcard->dma_base_resource.flags = IORESOURCE_MEM;
- //}
-
- //{ Step 6: System Regs
- pcard->sysinfo_regs_base = pcard->regs_bar_base;
- err = read_system_regs(pcard);
- if (err)
- goto out6;
-
- // Disable all "user" interrupts because they're not used yet.
- writeq(0xFFFFFFFFFFFFFFFF, pcard->sysinfo_regs_base + REG_INTERRUPT_MASK);
- //}
-
- //{ Step 7: Configure PCI thingies
- // let the card master PCIe
- pci_set_master(pcard->pdev);
- // enable IO and mem if not already done
- pci_read_config_word(pcard->pdev, PCI_COMMAND, &regval);
- regval |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
- pci_write_config_word(pcard->pdev, PCI_COMMAND, regval);
-
- // Clear relaxed ordering bit
- pcie_capability_clear_and_set_word(pcard->pdev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_RELAX_EN, 0);
-
- // Set Max_Payload_Size and Max_Read_Request_Size
- regval = (0x0) << 5; // Max_Payload_Size = 128 B
- pcie_capability_clear_and_set_word(pcard->pdev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_PAYLOAD, regval);
- regval = (0x0) << 12; // Max_Read_Request_Size = 128 B
- pcie_capability_clear_and_set_word(pcard->pdev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_READRQ, regval);
-
- // Enable error reporting for: Correctable Errors, Non-Fatal Errors, Fatal Errors, Unsupported Requests
- pcie_capability_clear_and_set_word(pcard->pdev, PCI_EXP_DEVCTL, 0, PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE);
-
- err = dma_set_mask(PCARD_TO_DEV(pcard), DMA_BIT_MASK(64));
- if (err){
- dev_err(&pcard->pdev->dev, "CANNOT use DMA mask %0llx\n", DMA_BIT_MASK(64));
- goto out7;
- }
- dev_dbg(&pcard->pdev->dev, "Using DMA mask %0llx\n", dma_get_mask(PCARD_TO_DEV(pcard)));
- //}
-
- //{ Step 8: Configure IRQs
- err = pci_enable_msi(pcard->pdev);
- if (err < 0)
- goto out8a;
-
- rv = request_irq(pcard->pdev->irq, kp2000_irq_handler, IRQF_SHARED, pcard->name, pcard);
- if (rv){
- dev_err(&pcard->pdev->dev, "kp2000_pcie_probe: failed to request_irq: %d\n", rv);
- goto out8b;
- }
- //}
-
- //{ Step 9: Setup sysfs attributes
- err = sysfs_create_files(&(pdev->dev.kobj), kp_attr_list);
- if (err){
- dev_err(&pdev->dev, "Failed to add sysfs files: %d\n", err);
- goto out9;
- }
- //}
-
- //{ Step 10: Setup misc device
- pcard->miscdev.minor = MISC_DYNAMIC_MINOR;
- pcard->miscdev.fops = &kp2000_fops;
- pcard->miscdev.parent = &pcard->pdev->dev;
- pcard->miscdev.name = pcard->name;
-
- err = misc_register(&pcard->miscdev);
- if (err){
- dev_err(&pcard->pdev->dev, "kp2000_pcie_probe: misc_register failed: %d\n", err);
- goto out10;
- }
- //}
-
- //{ Step 11: Probe cores
- err = kp2000_probe_cores(pcard);
- if (err)
- goto out11;
- //}
-
- //{ Step 12: Enable IRQs in HW
- SetBackEndControl(pcard->dma_common_regs, KPC_DMA_CARD_IRQ_ENABLE | KPC_DMA_CARD_USER_INTERRUPT_MODE);
- //}
-
- dev_dbg(&pcard->pdev->dev, "kp2000_pcie_probe() complete!\n");
- unlock_card(pcard);
- return 0;
-
- out11:
- misc_deregister(&pcard->miscdev);
- out10:
- sysfs_remove_files(&(pdev->dev.kobj), kp_attr_list);
- out9:
- free_irq(pcard->pdev->irq, pcard);
- out8b:
- pci_disable_msi(pcard->pdev);
- out8a:
- out7:
- out6:
- iounmap(pcard->dma_bar_base);
- pci_release_region(pdev, DMA_BAR);
- pcard->dma_bar_base = NULL;
- out5:
- iounmap(pcard->regs_bar_base);
- pci_release_region(pdev, REG_BAR);
- pcard->regs_bar_base = NULL;
- out4:
- pci_disable_device(pcard->pdev);
- out3:
- unlock_card(pcard);
- kfree(pcard);
- return err;
+ int err = 0;
+ struct kp2000_device *pcard;
+ int rv;
+ unsigned long reg_bar_phys_addr;
+ unsigned long reg_bar_phys_len;
+ unsigned long dma_bar_phys_addr;
+ unsigned long dma_bar_phys_len;
+ u16 regval;
+
+ pcard = kzalloc(sizeof(*pcard), GFP_KERNEL);
+ if (!pcard)
+ return -ENOMEM;
+ dev_dbg(&pdev->dev, "probe: allocated struct kp2000_device @ %p\n",
+ pcard);
+
+ err = ida_simple_get(&card_num_ida, 1, INT_MAX, GFP_KERNEL);
+ if (err < 0) {
+ dev_err(&pdev->dev, "probe: failed to get card number (%d)\n",
+ err);
+ goto err_free_pcard;
+ }
+ pcard->card_num = err;
+ scnprintf(pcard->name, 16, "kpcard%u", pcard->card_num);
+
+ mutex_init(&pcard->sem);
+ mutex_lock(&pcard->sem);
+
+ pcard->pdev = pdev;
+ pci_set_drvdata(pdev, pcard);
+
+ err = pci_enable_device(pcard->pdev);
+ if (err) {
+ dev_err(&pcard->pdev->dev,
+ "probe: failed to enable PCIE2000 PCIe device (%d)\n",
+ err);
+ goto err_remove_ida;
+ }
+
+ /* Setup the Register BAR */
+ reg_bar_phys_addr = pci_resource_start(pcard->pdev, REG_BAR);
+ reg_bar_phys_len = pci_resource_len(pcard->pdev, REG_BAR);
+
+ pcard->regs_bar_base = ioremap_nocache(reg_bar_phys_addr, PAGE_SIZE);
+ if (!pcard->regs_bar_base) {
+ dev_err(&pcard->pdev->dev,
+ "probe: REG_BAR could not remap memory to virtual space\n");
+ err = -ENODEV;
+ goto err_disable_device;
+ }
+ dev_dbg(&pcard->pdev->dev,
+ "probe: REG_BAR virt hardware address start [%p]\n",
+ pcard->regs_bar_base);
+
+ err = pci_request_region(pcard->pdev, REG_BAR, KP_DRIVER_NAME_KP2000);
+ if (err) {
+ dev_err(&pcard->pdev->dev,
+ "probe: failed to acquire PCI region (%d)\n",
+ err);
+ err = -ENODEV;
+ goto err_unmap_regs;
+ }
+
+ pcard->regs_base_resource.start = reg_bar_phys_addr;
+ pcard->regs_base_resource.end = reg_bar_phys_addr +
+ reg_bar_phys_len - 1;
+ pcard->regs_base_resource.flags = IORESOURCE_MEM;
+
+ /* Setup the DMA BAR */
+ dma_bar_phys_addr = pci_resource_start(pcard->pdev, DMA_BAR);
+ dma_bar_phys_len = pci_resource_len(pcard->pdev, DMA_BAR);
+
+ pcard->dma_bar_base = ioremap_nocache(dma_bar_phys_addr,
+ dma_bar_phys_len);
+ if (!pcard->dma_bar_base) {
+ dev_err(&pcard->pdev->dev,
+ "probe: DMA_BAR could not remap memory to virtual space\n");
+ err = -ENODEV;
+ goto err_release_regs;
+ }
+ dev_dbg(&pcard->pdev->dev,
+ "probe: DMA_BAR virt hardware address start [%p]\n",
+ pcard->dma_bar_base);
+
+ pcard->dma_common_regs = pcard->dma_bar_base + KPC_DMA_COMMON_OFFSET;
+
+ err = pci_request_region(pcard->pdev, DMA_BAR, "kp2000_pcie");
+ if (err) {
+ dev_err(&pcard->pdev->dev,
+ "probe: failed to acquire PCI region (%d)\n", err);
+ err = -ENODEV;
+ goto err_unmap_dma;
+ }
+
+ pcard->dma_base_resource.start = dma_bar_phys_addr;
+ pcard->dma_base_resource.end = dma_bar_phys_addr +
+ dma_bar_phys_len - 1;
+ pcard->dma_base_resource.flags = IORESOURCE_MEM;
+
+ /* Read System Regs */
+ pcard->sysinfo_regs_base = pcard->regs_bar_base;
+ err = read_system_regs(pcard);
+ if (err)
+ goto err_release_dma;
+
+ // Disable all "user" interrupts because they're not used yet.
+ writeq(0xFFFFFFFFFFFFFFFF,
+ pcard->sysinfo_regs_base + REG_INTERRUPT_MASK);
+
+ // let the card master PCIe
+ pci_set_master(pcard->pdev);
+
+ // enable IO and mem if not already done
+ pci_read_config_word(pcard->pdev, PCI_COMMAND, &regval);
+ regval |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+ pci_write_config_word(pcard->pdev, PCI_COMMAND, regval);
+
+ // Clear relaxed ordering bit
+ pcie_capability_clear_and_set_word(pcard->pdev, PCI_EXP_DEVCTL,
+ PCI_EXP_DEVCTL_RELAX_EN, 0);
+
+ // Set Max_Payload_Size and Max_Read_Request_Size
+ regval = (0x0) << 5; // Max_Payload_Size = 128 B
+ pcie_capability_clear_and_set_word(pcard->pdev, PCI_EXP_DEVCTL,
+ PCI_EXP_DEVCTL_PAYLOAD, regval);
+ regval = (0x0) << 12; // Max_Read_Request_Size = 128 B
+ pcie_capability_clear_and_set_word(pcard->pdev, PCI_EXP_DEVCTL,
+ PCI_EXP_DEVCTL_READRQ, regval);
+
+ // Enable error reporting for: Correctable Errors, Non-Fatal Errors,
+ // Fatal Errors, Unsupported Requests
+ pcie_capability_clear_and_set_word(pcard->pdev, PCI_EXP_DEVCTL, 0,
+ PCI_EXP_DEVCTL_CERE |
+ PCI_EXP_DEVCTL_NFERE |
+ PCI_EXP_DEVCTL_FERE |
+ PCI_EXP_DEVCTL_URRE);
+
+ err = dma_set_mask(PCARD_TO_DEV(pcard), DMA_BIT_MASK(64));
+ if (err) {
+ dev_err(&pcard->pdev->dev,
+ "CANNOT use DMA mask %0llx\n", DMA_BIT_MASK(64));
+ goto err_release_dma;
+ }
+ dev_dbg(&pcard->pdev->dev,
+ "Using DMA mask %0llx\n", dma_get_mask(PCARD_TO_DEV(pcard)));
+
+ err = pci_enable_msi(pcard->pdev);
+ if (err < 0)
+ goto err_release_dma;
+
+ rv = request_irq(pcard->pdev->irq, kp2000_irq_handler, IRQF_SHARED,
+ pcard->name, pcard);
+ if (rv) {
+ dev_err(&pcard->pdev->dev,
+ "%s: failed to request_irq: %d\n", __func__, rv);
+ goto err_disable_msi;
+ }
+
+ err = sysfs_create_files(&pdev->dev.kobj, kp_attr_list);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to add sysfs files: %d\n", err);
+ goto err_free_irq;
+ }
+
+ err = kp2000_probe_cores(pcard);
+ if (err)
+ goto err_remove_sysfs;
+
+ /* Enable IRQs in HW */
+ writel(KPC_DMA_CARD_IRQ_ENABLE | KPC_DMA_CARD_USER_INTERRUPT_MODE,
+ pcard->dma_common_regs);
+
+ mutex_unlock(&pcard->sem);
+ return 0;
+
+err_remove_sysfs:
+ sysfs_remove_files(&pdev->dev.kobj, kp_attr_list);
+err_free_irq:
+ free_irq(pcard->pdev->irq, pcard);
+err_disable_msi:
+ pci_disable_msi(pcard->pdev);
+err_release_dma:
+ pci_release_region(pdev, DMA_BAR);
+err_unmap_dma:
+ iounmap(pcard->dma_bar_base);
+err_release_regs:
+ pci_release_region(pdev, REG_BAR);
+err_unmap_regs:
+ iounmap(pcard->regs_bar_base);
+err_disable_device:
+ pci_disable_device(pcard->pdev);
+err_remove_ida:
+ mutex_unlock(&pcard->sem);
+ ida_simple_remove(&card_num_ida, pcard->card_num);
+err_free_pcard:
+ kfree(pcard);
+ return err;
+}
+
+static void kp2000_pcie_remove(struct pci_dev *pdev)
+{
+ struct kp2000_device *pcard = pci_get_drvdata(pdev);
+
+ if (!pcard)
+ return;
+
+ mutex_lock(&pcard->sem);
+ kp2000_remove_cores(pcard);
+ mfd_remove_devices(PCARD_TO_DEV(pcard));
+ sysfs_remove_files(&pdev->dev.kobj, kp_attr_list);
+ free_irq(pcard->pdev->irq, pcard);
+ pci_disable_msi(pcard->pdev);
+ if (pcard->dma_bar_base) {
+ iounmap(pcard->dma_bar_base);
+ pci_release_region(pdev, DMA_BAR);
+ pcard->dma_bar_base = NULL;
+ }
+ if (pcard->regs_bar_base) {
+ iounmap(pcard->regs_bar_base);
+ pci_release_region(pdev, REG_BAR);
+ pcard->regs_bar_base = NULL;
+ }
+ pci_disable_device(pcard->pdev);
+ pci_set_drvdata(pdev, NULL);
+ mutex_unlock(&pcard->sem);
+ ida_simple_remove(&card_num_ida, pcard->card_num);
+ kfree(pcard);
}
+struct class *kpc_uio_class;
+ATTRIBUTE_GROUPS(kpc_uio_class);
+
+static const struct pci_device_id kp2000_pci_device_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_DAKTRONICS, PCI_DEVICE_ID_DAKTRONICS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_DAKTRONICS, PCI_DEVICE_ID_DAKTRONICS_KADOKA_P2KR0) },
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, kp2000_pci_device_ids);
+
+static struct pci_driver kp2000_driver_inst = {
+ .name = "kp2000_pcie",
+ .id_table = kp2000_pci_device_ids,
+ .probe = kp2000_pcie_probe,
+ .remove = kp2000_pcie_remove,
+};
-void kp2000_pcie_remove(struct pci_dev *pdev)
+static int __init kp2000_pcie_init(void)
{
- struct kp2000_device *pcard = pci_get_drvdata(pdev);
-
- dev_dbg(&pdev->dev, "kp2000_pcie_remove(pdev=%p)\n", pdev);
-
- if (pcard == NULL) return;
-
- lock_card(pcard);
- kp2000_remove_cores(pcard);
- mfd_remove_devices(PCARD_TO_DEV(pcard));
- misc_deregister(&pcard->miscdev);
- sysfs_remove_files(&(pdev->dev.kobj), kp_attr_list);
- free_irq(pcard->pdev->irq, pcard);
- pci_disable_msi(pcard->pdev);
- if (pcard->dma_bar_base != NULL){
- iounmap(pcard->dma_bar_base);
- pci_release_region(pdev, DMA_BAR);
- pcard->dma_bar_base = NULL;
- }
- if (pcard->regs_bar_base != NULL){
- iounmap(pcard->regs_bar_base);
- pci_release_region(pdev, REG_BAR);
- pcard->regs_bar_base = NULL;
- }
- pci_disable_device(pcard->pdev);
- pci_set_drvdata(pdev, NULL);
- unlock_card(pcard);
- kfree(pcard);
+ kpc_uio_class = class_create(THIS_MODULE, "kpc_uio");
+ if (IS_ERR(kpc_uio_class))
+ return PTR_ERR(kpc_uio_class);
+
+ kpc_uio_class->dev_groups = kpc_uio_class_groups;
+ return pci_register_driver(&kp2000_driver_inst);
}
+module_init(kp2000_pcie_init);
+
+static void __exit kp2000_pcie_exit(void)
+{
+ pci_unregister_driver(&kp2000_driver_inst);
+ class_destroy(kpc_uio_class);
+ ida_destroy(&card_num_ida);
+}
+module_exit(kp2000_pcie_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Lee.Brooke@Daktronics.com, Matt.Sickler@Daktronics.com");
+MODULE_SOFTDEP("pre: uio post: kpc_nwl_dma kpc_i2c kpc_spi");
diff --git a/drivers/staging/kpc2000/kpc2000/dma_common_defs.h b/drivers/staging/kpc2000/kpc2000/dma_common_defs.h
index f35e636b1fb7..21450e3d408f 100644
--- a/drivers/staging/kpc2000/kpc2000/dma_common_defs.h
+++ b/drivers/staging/kpc2000/kpc2000/dma_common_defs.h
@@ -21,23 +21,4 @@
#define KPC_DMA_CARD_S2C_INTERRUPT_STATUS_MASK 0x00FF0000
#define KPC_DMA_CARD_C2S_INTERRUPT_STATUS_MASK 0xFF000000
-static inline void SetBackEndControl(void __iomem *regs, u32 value)
-{
- writel(value, regs + 0);
-}
-static inline u32 GetBackEndStatus(void __iomem *regs)
-{
- return readl(regs + 0);
-}
-
-static inline u32 BackEndControlSetClear(void __iomem *regs, u32 set_bits, u32 clear_bits)
-{
- u32 start_val = GetBackEndStatus(regs);
- u32 new_val = start_val;
- new_val &= ~clear_bits;
- new_val |= set_bits;
- SetBackEndControl(regs, new_val);
- return start_val;
-}
-
#endif /* KPC_DMA_COMMON_DEFS_H_ */
diff --git a/drivers/staging/kpc2000/kpc2000/fileops.c b/drivers/staging/kpc2000/kpc2000/fileops.c
deleted file mode 100644
index b3b0b763fa1e..000000000000
--- a/drivers/staging/kpc2000/kpc2000/fileops.c
+++ /dev/null
@@ -1,131 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h> /* printk() */
-#include <linux/slab.h> /* kmalloc() */
-#include <linux/fs.h> /* everything... */
-#include <linux/errno.h> /* error codes */
-#include <linux/types.h> /* size_t */
-#include <linux/cdev.h>
-#include <linux/uaccess.h> /* copy_*_user */
-#include <linux/rwsem.h>
-#include <linux/idr.h>
-#include <linux/io-64-nonatomic-lo-hi.h>
-#include <linux/device.h>
-#include <linux/sched.h>
-#include "pcie.h"
-#include "uapi.h"
-
-int kp2000_cdev_open(struct inode *inode, struct file *filp)
-{
- struct kp2000_device *pcard = container_of(filp->private_data, struct kp2000_device, miscdev);
-
- dev_dbg(&pcard->pdev->dev, "kp2000_cdev_open(filp = [%p], pcard = [%p])\n", filp, pcard);
-
- filp->private_data = pcard; /* so other methods can access it */
-
- return 0;
-}
-
-int kp2000_cdev_close(struct inode *inode, struct file *filp)
-{
- struct kp2000_device *pcard = filp->private_data;
-
- dev_dbg(&pcard->pdev->dev, "kp2000_cdev_close(filp = [%p], pcard = [%p])\n", filp, pcard);
- return 0;
-}
-
-
-ssize_t kp2000_cdev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
-{
- struct kp2000_device *pcard = filp->private_data;
- int cnt = 0;
- int ret;
-#define BUFF_CNT 1024
- char buff[BUFF_CNT] = {0}; //NOTE: Increase this so it is at least as large as all the scnprintfs. And don't use unbounded strings. "%s"
- //NOTE: also, this is a really shitty way to implement the read() call, but it will work for any size 'count'.
-
- if (WARN(NULL == buf, "kp2000_cdev_read: buf is a NULL pointer!\n"))
- return -EINVAL;
-
- cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "Card ID : 0x%08x\n", pcard->card_id);
- cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "Build Version : 0x%08x\n", pcard->build_version);
- cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "Build Date : 0x%08x\n", pcard->build_datestamp);
- cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "Build Time : 0x%08x\n", pcard->build_timestamp);
- cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "Core Table Offset : 0x%08x\n", pcard->core_table_offset);
- cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "Core Table Length : 0x%08x\n", pcard->core_table_length);
- cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "Hardware Revision : 0x%08x\n", pcard->hardware_revision);
- cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "SSID : 0x%016llx\n", pcard->ssid);
- cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "DDNA : 0x%016llx\n", pcard->ddna);
- cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "IRQ Mask : 0x%016llx\n", readq(pcard->sysinfo_regs_base + REG_INTERRUPT_MASK));
- cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "IRQ Active : 0x%016llx\n", readq(pcard->sysinfo_regs_base + REG_INTERRUPT_ACTIVE));
- cnt += scnprintf(buff+cnt, BUFF_CNT-cnt, "CPLD : 0x%016llx\n", readq(pcard->sysinfo_regs_base + REG_CPLD_CONFIG));
-
- if (*f_pos >= cnt)
- return 0;
-
- if (count > cnt)
- count = cnt;
-
- ret = copy_to_user(buf, buff + *f_pos, count);
- if (ret)
- return -EFAULT;
- *f_pos += count;
- return count;
-}
-
-ssize_t kp2000_cdev_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
-{
- return -EINVAL;
-}
-
-long kp2000_cdev_ioctl(struct file *filp, unsigned int ioctl_num, unsigned long ioctl_param)
-{
- struct kp2000_device *pcard = filp->private_data;
-
- dev_dbg(&pcard->pdev->dev, "kp2000_cdev_ioctl(filp = [%p], ioctl_num = 0x%08x, ioctl_param = 0x%016lx) pcard = [%p]\n", filp, ioctl_num, ioctl_param, pcard);
-
- switch (ioctl_num){
- case KP2000_IOCTL_GET_CPLD_REG: return readq(pcard->sysinfo_regs_base + REG_CPLD_CONFIG);
- case KP2000_IOCTL_GET_PCIE_ERROR_REG: return readq(pcard->sysinfo_regs_base + REG_PCIE_ERROR_COUNT);
-
- case KP2000_IOCTL_GET_EVERYTHING: {
- struct kp2000_regs temp;
- int ret;
-
- memset(&temp, 0, sizeof(temp));
- temp.card_id = pcard->card_id;
- temp.build_version = pcard->build_version;
- temp.build_datestamp = pcard->build_datestamp;
- temp.build_timestamp = pcard->build_timestamp;
- temp.hw_rev = pcard->hardware_revision;
- temp.ssid = pcard->ssid;
- temp.ddna = pcard->ddna;
- temp.cpld_reg = readq(pcard->sysinfo_regs_base + REG_CPLD_CONFIG);
-
- ret = copy_to_user((void*)ioctl_param, (void*)&temp, sizeof(temp));
- if (ret)
- return -EFAULT;
-
- return sizeof(temp);
- }
-
- default:
- return -ENOTTY;
- }
- return -ENOTTY;
-}
-
-
-struct file_operations kp2000_fops = {
- .owner = THIS_MODULE,
- .open = kp2000_cdev_open,
- .release = kp2000_cdev_close,
- .read = kp2000_cdev_read,
- //.write = kp2000_cdev_write,
- //.poll = kp2000_cdev_poll,
- //.fasync = kp2000_cdev_fasync,
- .llseek = noop_llseek,
- .unlocked_ioctl = kp2000_cdev_ioctl,
-};
-
diff --git a/drivers/staging/kpc2000/kpc2000/kp2000_module.c b/drivers/staging/kpc2000/kpc2000/kp2000_module.c
deleted file mode 100644
index fa3bd266ba54..000000000000
--- a/drivers/staging/kpc2000/kpc2000/kp2000_module.c
+++ /dev/null
@@ -1,54 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/types.h>
-#include <linux/export.h>
-#include <linux/slab.h>
-#include <asm/io.h>
-#include <linux/io.h>
-#include <linux/mfd/core.h>
-#include <linux/platform_device.h>
-#include <linux/ioport.h>
-#include "pcie.h"
-
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Lee.Brooke@Daktronics.com, Matt.Sickler@Daktronics.com");
-MODULE_SOFTDEP("pre: uio post: kpc_nwl_dma kpc_i2c kpc_spi");
-
-struct class *kpc_uio_class;
-ATTRIBUTE_GROUPS(kpc_uio_class);
-
-static const struct pci_device_id kp2000_pci_device_ids[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_DAKTRONICS, PCI_DEVICE_ID_DAKTRONICS) },
- { PCI_DEVICE(PCI_VENDOR_ID_DAKTRONICS, PCI_DEVICE_ID_DAKTRONICS_KADOKA_P2KR0) },
- { 0, }
-};
-MODULE_DEVICE_TABLE(pci, kp2000_pci_device_ids);
-
-static struct pci_driver kp2000_driver_inst = {
- .name = "kp2000_pcie",
- .id_table = kp2000_pci_device_ids,
- .probe = kp2000_pcie_probe,
- .remove = kp2000_pcie_remove
-};
-
-
-static int __init kp2000_pcie_init(void)
-{
- kpc_uio_class = class_create(THIS_MODULE, "kpc_uio");
- if (IS_ERR(kpc_uio_class))
- return PTR_ERR(kpc_uio_class);
-
- kpc_uio_class->dev_groups = kpc_uio_class_groups;
- return pci_register_driver(&kp2000_driver_inst);
-}
-module_init(kp2000_pcie_init);
-
-static void __exit kp2000_pcie_exit(void)
-{
- pci_unregister_driver(&kp2000_driver_inst);
- class_destroy(kpc_uio_class);
-}
-module_exit(kp2000_pcie_exit);
diff --git a/drivers/staging/kpc2000/kpc2000/pcie.h b/drivers/staging/kpc2000/kpc2000/pcie.h
index 893aebfd1449..cb815c30faa4 100644
--- a/drivers/staging/kpc2000/kpc2000/pcie.h
+++ b/drivers/staging/kpc2000/kpc2000/pcie.h
@@ -2,7 +2,6 @@
#ifndef KP2000_PCIE_H
#define KP2000_PCIE_H
#include <linux/types.h>
-#include <linux/miscdevice.h>
#include <linux/pci.h>
#include "../kpc.h"
#include "dma_common_defs.h"
@@ -27,86 +26,66 @@
* 9 <---------------------- IRQ Active Flags ---------------------->
*/
-#define REG_WIDTH 8
-#define REG_MAGIC_NUMBER (0 * REG_WIDTH)
-#define REG_CARD_ID_AND_BUILD (1 * REG_WIDTH)
-#define REG_DATE_AND_TIME_STAMPS (2 * REG_WIDTH)
-#define REG_CORE_TABLE_OFFSET (3 * REG_WIDTH)
-#define REG_FPGA_SSID (4 * REG_WIDTH)
-#define REG_FPGA_HW_ID (5 * REG_WIDTH)
-#define REG_FPGA_DDNA (6 * REG_WIDTH)
-#define REG_CPLD_CONFIG (7 * REG_WIDTH)
-#define REG_INTERRUPT_MASK (8 * REG_WIDTH)
-#define REG_INTERRUPT_ACTIVE (9 * REG_WIDTH)
-#define REG_PCIE_ERROR_COUNT (10 * REG_WIDTH)
+#define REG_WIDTH 8
+#define REG_MAGIC_NUMBER (0 * REG_WIDTH)
+#define REG_CARD_ID_AND_BUILD (1 * REG_WIDTH)
+#define REG_DATE_AND_TIME_STAMPS (2 * REG_WIDTH)
+#define REG_CORE_TABLE_OFFSET (3 * REG_WIDTH)
+#define REG_FPGA_SSID (4 * REG_WIDTH)
+#define REG_FPGA_HW_ID (5 * REG_WIDTH)
+#define REG_FPGA_DDNA (6 * REG_WIDTH)
+#define REG_CPLD_CONFIG (7 * REG_WIDTH)
+#define REG_INTERRUPT_MASK (8 * REG_WIDTH)
+#define REG_INTERRUPT_ACTIVE (9 * REG_WIDTH)
+#define REG_PCIE_ERROR_COUNT (10 * REG_WIDTH)
-#define KP2000_MAGIC_VALUE 0x196C61482231894D
+#define KP2000_MAGIC_VALUE 0x196C61482231894DULL
-#define PCI_VENDOR_ID_DAKTRONICS 0x1c33
-#define PCI_DEVICE_ID_DAKTRONICS 0x6021
+#define PCI_VENDOR_ID_DAKTRONICS 0x1c33
+#define PCI_DEVICE_ID_DAKTRONICS 0x6021
-#define DMA_BAR 0
-#define REG_BAR 1
+#define DMA_BAR 0
+#define REG_BAR 1
struct kp2000_device {
- struct pci_dev *pdev;
- struct miscdevice miscdev;
- char name[16];
-
- unsigned int card_num;
- struct mutex sem;
-
- void __iomem *sysinfo_regs_base;
- void __iomem *regs_bar_base;
- struct resource regs_base_resource;
- void __iomem *dma_bar_base;
- void __iomem *dma_common_regs;
- struct resource dma_base_resource;
-
- // "System Registers"
- u32 card_id;
- u32 build_version;
- u32 build_datestamp;
- u32 build_timestamp;
- u32 core_table_offset;
- u32 core_table_length;
- u8 core_table_rev;
- u8 hardware_revision;
- u64 ssid;
- u64 ddna;
-
- // IRQ stuff
- unsigned int irq;
-
- struct list_head uio_devices_list;
+ struct pci_dev *pdev;
+ char name[16];
+
+ unsigned int card_num;
+ struct mutex sem;
+
+ void __iomem *sysinfo_regs_base;
+ void __iomem *regs_bar_base;
+ struct resource regs_base_resource;
+ void __iomem *dma_bar_base;
+ void __iomem *dma_common_regs;
+ struct resource dma_base_resource;
+
+ // "System Registers"
+ u32 card_id;
+ u32 build_version;
+ u32 build_datestamp;
+ u32 build_timestamp;
+ u32 core_table_offset;
+ u32 core_table_length;
+ u8 core_table_rev;
+ u8 hardware_revision;
+ u64 ssid;
+ u64 ddna;
+
+ // IRQ stuff
+ unsigned int irq;
+
+ struct list_head uio_devices_list;
};
extern struct class *kpc_uio_class;
extern struct attribute *kpc_uio_class_attrs[];
-int kp2000_pcie_probe(struct pci_dev *dev, const struct pci_device_id *id);
-void kp2000_pcie_remove(struct pci_dev *pdev);
-int kp2000_probe_cores(struct kp2000_device *pcard);
-void kp2000_remove_cores(struct kp2000_device *pcard);
-
-extern struct file_operations kp2000_fops;
-
+int kp2000_probe_cores(struct kp2000_device *pcard);
+void kp2000_remove_cores(struct kp2000_device *pcard);
// Define this quick little macro because the expression is used frequently
-#define PCARD_TO_DEV(pcard) (&(pcard->pdev->dev))
-
-static inline void
-lock_card(struct kp2000_device *pcard)
-{
- BUG_ON(pcard == NULL);
- mutex_lock(&pcard->sem);
-}
-static inline void
-unlock_card(struct kp2000_device *pcard)
-{
- BUG_ON(pcard == NULL);
- mutex_unlock(&pcard->sem);
-}
-
+#define PCARD_TO_DEV(pcard) (&(pcard->pdev->dev))
#endif /* KP2000_PCIE_H */
diff --git a/drivers/staging/kpc2000/kpc2000/uapi.h b/drivers/staging/kpc2000/kpc2000/uapi.h
index ef8008bcd33d..16f37f002dc6 100644
--- a/drivers/staging/kpc2000/kpc2000/uapi.h
+++ b/drivers/staging/kpc2000/kpc2000/uapi.h
@@ -5,18 +5,18 @@
#include <linux/ioctl.h>
struct kp2000_regs {
- __u32 card_id;
- __u32 build_version;
- __u32 build_datestamp;
- __u32 build_timestamp;
- __u32 hw_rev;
- __u64 ssid;
- __u64 ddna;
- __u64 cpld_reg;
+ __u32 card_id;
+ __u32 build_version;
+ __u32 build_datestamp;
+ __u32 build_timestamp;
+ __u32 hw_rev;
+ __u64 ssid;
+ __u64 ddna;
+ __u64 cpld_reg;
};
-#define KP2000_IOCTL_GET_CPLD_REG _IOR('k', 9, __u32)
-#define KP2000_IOCTL_GET_PCIE_ERROR_REG _IOR('k', 11, __u32)
-#define KP2000_IOCTL_GET_EVERYTHING _IOR('k', 8, struct kp2000_regs*)
+#define KP2000_IOCTL_GET_CPLD_REG _IOR('k', 9, __u32)
+#define KP2000_IOCTL_GET_PCIE_ERROR_REG _IOR('k', 11, __u32)
+#define KP2000_IOCTL_GET_EVERYTHING _IOR('k', 8, struct kp2000_regs*)
#endif /* KP2000_CDEV_UAPI_H_ */
diff --git a/drivers/staging/kpc2000/kpc2000_i2c.c b/drivers/staging/kpc2000/kpc2000_i2c.c
new file mode 100644
index 000000000000..b108da4ac633
--- /dev/null
+++ b/drivers/staging/kpc2000/kpc2000_i2c.c
@@ -0,0 +1,651 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * KPC2000 i2c driver
+ *
+ * Adapted i2c-i801.c for use with Kadoka hardware.
+ *
+ * Copyright (C) 1998 - 2002
+ * Frodo Looijaard <frodol@dds.nl>,
+ * Philip Edelbrock <phil@netroedge.com>,
+ * Mark D. Studebaker <mdsxyz123@yahoo.com>
+ * Copyright (C) 2007 - 2012
+ * Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2010 Intel Corporation
+ * David Woodhouse <dwmw2@infradead.org>
+ * Copyright (C) 2014-2018 Daktronics
+ * Matt Sickler <matt.sickler@daktronics.com>,
+ * Jordon Hofer <jordon.hofer@daktronics.com>
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/io.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include "kpc.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Matt.Sickler@Daktronics.com");
+
+struct i2c_device {
+ unsigned long smba;
+ struct i2c_adapter adapter;
+ unsigned int features;
+};
+
+/*****************************
+ *** Part 1 - i2c Handlers ***
+ *****************************/
+
+#define REG_SIZE 8
+
+/* I801 SMBus address offsets */
+#define SMBHSTSTS(p) ((0 * REG_SIZE) + (p)->smba)
+#define SMBHSTCNT(p) ((2 * REG_SIZE) + (p)->smba)
+#define SMBHSTCMD(p) ((3 * REG_SIZE) + (p)->smba)
+#define SMBHSTADD(p) ((4 * REG_SIZE) + (p)->smba)
+#define SMBHSTDAT0(p) ((5 * REG_SIZE) + (p)->smba)
+#define SMBHSTDAT1(p) ((6 * REG_SIZE) + (p)->smba)
+#define SMBBLKDAT(p) ((7 * REG_SIZE) + (p)->smba)
+#define SMBPEC(p) ((8 * REG_SIZE) + (p)->smba) /* ICH3 and later */
+#define SMBAUXSTS(p) ((12 * REG_SIZE) + (p)->smba) /* ICH4 and later */
+#define SMBAUXCTL(p) ((13 * REG_SIZE) + (p)->smba) /* ICH4 and later */
+
+/* PCI Address Constants */
+#define SMBBAR 4
+#define SMBHSTCFG 0x040
+
+/* Host configuration bits for SMBHSTCFG */
+#define SMBHSTCFG_HST_EN 1
+#define SMBHSTCFG_SMB_SMI_EN 2
+#define SMBHSTCFG_I2C_EN 4
+
+/* Auxiliary control register bits, ICH4+ only */
+#define SMBAUXCTL_CRC 1
+#define SMBAUXCTL_E32B 2
+
+/* kill bit for SMBHSTCNT */
+#define SMBHSTCNT_KILL 2
+
+/* Other settings */
+#define MAX_RETRIES 400
+#define ENABLE_INT9 0 /* set to 0x01 to enable - untested */
+
+/* I801 command constants */
+#define I801_QUICK 0x00
+#define I801_BYTE 0x04
+#define I801_BYTE_DATA 0x08
+#define I801_WORD_DATA 0x0C
+#define I801_PROC_CALL 0x10 /* unimplemented */
+#define I801_BLOCK_DATA 0x14
+#define I801_I2C_BLOCK_DATA 0x18 /* ICH5 and later */
+#define I801_BLOCK_LAST 0x34
+#define I801_I2C_BLOCK_LAST 0x38 /* ICH5 and later */
+#define I801_START 0x40
+#define I801_PEC_EN 0x80 /* ICH3 and later */
+
+/* I801 Hosts Status register bits */
+#define SMBHSTSTS_BYTE_DONE 0x80
+#define SMBHSTSTS_INUSE_STS 0x40
+#define SMBHSTSTS_SMBALERT_STS 0x20
+#define SMBHSTSTS_FAILED 0x10
+#define SMBHSTSTS_BUS_ERR 0x08
+#define SMBHSTSTS_DEV_ERR 0x04
+#define SMBHSTSTS_INTR 0x02
+#define SMBHSTSTS_HOST_BUSY 0x01
+
+#define STATUS_FLAGS (SMBHSTSTS_BYTE_DONE | SMBHSTSTS_FAILED | SMBHSTSTS_BUS_ERR | SMBHSTSTS_DEV_ERR | SMBHSTSTS_INTR)
+
+/* Older devices have their ID defined in <linux/pci_ids.h> */
+#define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS 0x1d22
+/* Patsburg also has three 'Integrated Device Function' SMBus controllers */
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0 0x1d70
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1 0x1d71
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2 0x1d72
+#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS 0x1e22
+#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330
+#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30
+#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22
+#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS 0x9c22
+
+#define FEATURE_SMBUS_PEC BIT(0)
+#define FEATURE_BLOCK_BUFFER BIT(1)
+#define FEATURE_BLOCK_PROC BIT(2)
+#define FEATURE_I2C_BLOCK_READ BIT(3)
+/* Not really a feature, but it's convenient to handle it as such */
+#define FEATURE_IDF BIT(15)
+
+// FIXME!
+#undef inb_p
+#define inb_p(a) readq((void *)a)
+#undef outb_p
+#define outb_p(d, a) writeq(d, (void *)a)
+
+/* Make sure the SMBus host is ready to start transmitting.
+ * Return 0 if it is, -EBUSY if it is not.
+ */
+static int i801_check_pre(struct i2c_device *priv)
+{
+ int status;
+
+ status = inb_p(SMBHSTSTS(priv));
+ if (status & SMBHSTSTS_HOST_BUSY) {
+ dev_err(&priv->adapter.dev, "SMBus is busy, can't use it! (status=%x)\n", status);
+ return -EBUSY;
+ }
+
+ status &= STATUS_FLAGS;
+ if (status) {
+ //dev_dbg(&priv->adapter.dev, "Clearing status flags (%02x)\n", status);
+ outb_p(status, SMBHSTSTS(priv));
+ status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS;
+ if (status) {
+ dev_err(&priv->adapter.dev, "Failed clearing status flags (%02x)\n", status);
+ return -EBUSY;
+ }
+ }
+ return 0;
+}
+
+/* Convert the status register to an error code, and clear it. */
+static int i801_check_post(struct i2c_device *priv, int status, int timeout)
+{
+ int result = 0;
+
+ /* If the SMBus is still busy, we give up */
+ if (timeout) {
+ dev_err(&priv->adapter.dev, "Transaction timeout\n");
+ /* try to stop the current command */
+ dev_dbg(&priv->adapter.dev, "Terminating the current operation\n");
+ outb_p(inb_p(SMBHSTCNT(priv)) | SMBHSTCNT_KILL, SMBHSTCNT(priv));
+ usleep_range(1000, 2000);
+ outb_p(inb_p(SMBHSTCNT(priv)) & (~SMBHSTCNT_KILL), SMBHSTCNT(priv));
+
+ /* Check if it worked */
+ status = inb_p(SMBHSTSTS(priv));
+ if ((status & SMBHSTSTS_HOST_BUSY) || !(status & SMBHSTSTS_FAILED))
+ dev_err(&priv->adapter.dev, "Failed terminating the transaction\n");
+ outb_p(STATUS_FLAGS, SMBHSTSTS(priv));
+ return -ETIMEDOUT;
+ }
+
+ if (status & SMBHSTSTS_FAILED) {
+ result = -EIO;
+ dev_err(&priv->adapter.dev, "Transaction failed\n");
+ }
+ if (status & SMBHSTSTS_DEV_ERR) {
+ result = -ENXIO;
+ dev_dbg(&priv->adapter.dev, "No response\n");
+ }
+ if (status & SMBHSTSTS_BUS_ERR) {
+ result = -EAGAIN;
+ dev_dbg(&priv->adapter.dev, "Lost arbitration\n");
+ }
+
+ if (result) {
+ /* Clear error flags */
+ outb_p(status & STATUS_FLAGS, SMBHSTSTS(priv));
+ status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS;
+ if (status)
+ dev_warn(&priv->adapter.dev, "Failed clearing status flags at end of transaction (%02x)\n", status);
+ }
+
+ return result;
+}
+
+static int i801_transaction(struct i2c_device *priv, int xact)
+{
+ int status;
+ int result;
+ int timeout = 0;
+
+ result = i801_check_pre(priv);
+ if (result < 0)
+ return result;
+ /* the current contents of SMBHSTCNT can be overwritten, since PEC,
+ * INTREN, SMBSCMD are passed in xact
+ */
+ outb_p(xact | I801_START, SMBHSTCNT(priv));
+
+ /* We will always wait for a fraction of a second! */
+ do {
+ usleep_range(250, 500);
+ status = inb_p(SMBHSTSTS(priv));
+ } while ((status & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_RETRIES));
+
+ result = i801_check_post(priv, status, timeout > MAX_RETRIES);
+ if (result < 0)
+ return result;
+
+ outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv));
+ return 0;
+}
+
+/* wait for INTR bit as advised by Intel */
+static void i801_wait_hwpec(struct i2c_device *priv)
+{
+ int timeout = 0;
+ int status;
+
+ do {
+ usleep_range(250, 500);
+ status = inb_p(SMBHSTSTS(priv));
+ } while ((!(status & SMBHSTSTS_INTR)) && (timeout++ < MAX_RETRIES));
+
+ if (timeout > MAX_RETRIES)
+ dev_dbg(&priv->adapter.dev, "PEC Timeout!\n");
+
+ outb_p(status, SMBHSTSTS(priv));
+}
+
+static int i801_block_transaction_by_block(struct i2c_device *priv, union i2c_smbus_data *data, char read_write, int hwpec)
+{
+ int i, len;
+ int status;
+
+ inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */
+
+ /* Use 32-byte buffer to process this transaction */
+ if (read_write == I2C_SMBUS_WRITE) {
+ len = data->block[0];
+ outb_p(len, SMBHSTDAT0(priv));
+ for (i = 0; i < len; i++)
+ outb_p(data->block[i + 1], SMBBLKDAT(priv));
+ }
+
+ status = i801_transaction(priv, I801_BLOCK_DATA | ENABLE_INT9 | I801_PEC_EN * hwpec);
+ if (status)
+ return status;
+
+ if (read_write == I2C_SMBUS_READ) {
+ len = inb_p(SMBHSTDAT0(priv));
+ if (len < 1 || len > I2C_SMBUS_BLOCK_MAX)
+ return -EPROTO;
+
+ data->block[0] = len;
+ for (i = 0; i < len; i++)
+ data->block[i + 1] = inb_p(SMBBLKDAT(priv));
+ }
+ return 0;
+}
+
+static int i801_block_transaction_byte_by_byte(struct i2c_device *priv, union i2c_smbus_data *data, char read_write, int command, int hwpec)
+{
+ int i, len;
+ int smbcmd;
+ int status;
+ int result;
+ int timeout;
+
+ result = i801_check_pre(priv);
+ if (result < 0)
+ return result;
+
+ len = data->block[0];
+
+ if (read_write == I2C_SMBUS_WRITE) {
+ outb_p(len, SMBHSTDAT0(priv));
+ outb_p(data->block[1], SMBBLKDAT(priv));
+ }
+
+ for (i = 1; i <= len; i++) {
+ if (i == len && read_write == I2C_SMBUS_READ) {
+ if (command == I2C_SMBUS_I2C_BLOCK_DATA)
+ smbcmd = I801_I2C_BLOCK_LAST;
+ else
+ smbcmd = I801_BLOCK_LAST;
+ } else {
+ if (command == I2C_SMBUS_I2C_BLOCK_DATA && read_write == I2C_SMBUS_READ)
+ smbcmd = I801_I2C_BLOCK_DATA;
+ else
+ smbcmd = I801_BLOCK_DATA;
+ }
+ outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT(priv));
+
+ if (i == 1)
+ outb_p(inb(SMBHSTCNT(priv)) | I801_START, SMBHSTCNT(priv));
+ /* We will always wait for a fraction of a second! */
+ timeout = 0;
+ do {
+ usleep_range(250, 500);
+ status = inb_p(SMBHSTSTS(priv));
+ } while ((!(status & SMBHSTSTS_BYTE_DONE)) && (timeout++ < MAX_RETRIES));
+
+ result = i801_check_post(priv, status, timeout > MAX_RETRIES);
+ if (result < 0)
+ return result;
+ if (i == 1 && read_write == I2C_SMBUS_READ && command != I2C_SMBUS_I2C_BLOCK_DATA) {
+ len = inb_p(SMBHSTDAT0(priv));
+ if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) {
+ dev_err(&priv->adapter.dev, "Illegal SMBus block read size %d\n", len);
+ /* Recover */
+ while (inb_p(SMBHSTSTS(priv)) & SMBHSTSTS_HOST_BUSY)
+ outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv));
+ outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv));
+ return -EPROTO;
+ }
+ data->block[0] = len;
+ }
+
+ /* Retrieve/store value in SMBBLKDAT */
+ if (read_write == I2C_SMBUS_READ)
+ data->block[i] = inb_p(SMBBLKDAT(priv));
+ if (read_write == I2C_SMBUS_WRITE && i + 1 <= len)
+ outb_p(data->block[i + 1], SMBBLKDAT(priv));
+ /* signals SMBBLKDAT ready */
+ outb_p(SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR, SMBHSTSTS(priv));
+ }
+
+ return 0;
+}
+
+static int i801_set_block_buffer_mode(struct i2c_device *priv)
+{
+ outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv));
+ if ((inb_p(SMBAUXCTL(priv)) & SMBAUXCTL_E32B) == 0)
+ return -EIO;
+ return 0;
+}
+
+/* Block transaction function */
+static int i801_block_transaction(struct i2c_device *priv, union i2c_smbus_data *data, char read_write, int command, int hwpec)
+{
+ int result = 0;
+ //unsigned char hostc;
+
+ if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
+ if (read_write == I2C_SMBUS_WRITE) {
+ /* set I2C_EN bit in configuration register */
+ //TODO: Figure out the right thing to do here...
+ //pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &hostc);
+ //pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc | SMBHSTCFG_I2C_EN);
+ } else if (!(priv->features & FEATURE_I2C_BLOCK_READ)) {
+ dev_err(&priv->adapter.dev, "I2C block read is unsupported!\n");
+ return -EOPNOTSUPP;
+ }
+ }
+
+ if (read_write == I2C_SMBUS_WRITE || command == I2C_SMBUS_I2C_BLOCK_DATA) {
+ if (data->block[0] < 1)
+ data->block[0] = 1;
+ if (data->block[0] > I2C_SMBUS_BLOCK_MAX)
+ data->block[0] = I2C_SMBUS_BLOCK_MAX;
+ } else {
+ data->block[0] = 32; /* max for SMBus block reads */
+ }
+
+ /* Experience has shown that the block buffer can only be used for
+ * SMBus (not I2C) block transactions, even though the datasheet
+ * doesn't mention this limitation.
+ */
+ if ((priv->features & FEATURE_BLOCK_BUFFER) && command != I2C_SMBUS_I2C_BLOCK_DATA && i801_set_block_buffer_mode(priv) == 0)
+ result = i801_block_transaction_by_block(priv, data, read_write, hwpec);
+ else
+ result = i801_block_transaction_byte_by_byte(priv, data, read_write, command, hwpec);
+ if (result == 0 && hwpec)
+ i801_wait_hwpec(priv);
+ if (command == I2C_SMBUS_I2C_BLOCK_DATA && read_write == I2C_SMBUS_WRITE) {
+ /* restore saved configuration register value */
+ //TODO: Figure out the right thing to do here...
+ //pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc);
+ }
+ return result;
+}
+
+/* Return negative errno on error. */
+static s32 i801_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data)
+{
+ int hwpec;
+ int block = 0;
+ int ret, xact = 0;
+ struct i2c_device *priv = i2c_get_adapdata(adap);
+
+ hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ dev_dbg(&priv->adapter.dev, " [acc] SMBUS_QUICK\n");
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD(priv));
+ xact = I801_QUICK;
+ break;
+ case I2C_SMBUS_BYTE:
+ dev_dbg(&priv->adapter.dev, " [acc] SMBUS_BYTE\n");
+
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD(priv));
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(command, SMBHSTCMD(priv));
+ xact = I801_BYTE;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ dev_dbg(&priv->adapter.dev, " [acc] SMBUS_BYTE_DATA\n");
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD(priv));
+ outb_p(command, SMBHSTCMD(priv));
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(data->byte, SMBHSTDAT0(priv));
+ xact = I801_BYTE_DATA;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ dev_dbg(&priv->adapter.dev, " [acc] SMBUS_WORD_DATA\n");
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD(priv));
+ outb_p(command, SMBHSTCMD(priv));
+ if (read_write == I2C_SMBUS_WRITE) {
+ outb_p(data->word & 0xff, SMBHSTDAT0(priv));
+ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv));
+ }
+ xact = I801_WORD_DATA;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ dev_dbg(&priv->adapter.dev, " [acc] SMBUS_BLOCK_DATA\n");
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD(priv));
+ outb_p(command, SMBHSTCMD(priv));
+ block = 1;
+ break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ dev_dbg(&priv->adapter.dev, " [acc] SMBUS_I2C_BLOCK_DATA\n");
+ /* NB: page 240 of ICH5 datasheet shows that the R/#W
+ * bit should be cleared here, even when reading
+ */
+ outb_p((addr & 0x7f) << 1, SMBHSTADD(priv));
+ if (read_write == I2C_SMBUS_READ) {
+ /* NB: page 240 of ICH5 datasheet also shows
+ * that DATA1 is the cmd field when reading
+ */
+ outb_p(command, SMBHSTDAT1(priv));
+ } else {
+ outb_p(command, SMBHSTCMD(priv));
+ }
+ block = 1;
+ break;
+ default:
+ dev_dbg(&priv->adapter.dev, " [acc] Unsupported transaction %d\n", size);
+ return -EOPNOTSUPP;
+ }
+
+ if (hwpec) { /* enable/disable hardware PEC */
+ dev_dbg(&priv->adapter.dev, " [acc] hwpec: yes\n");
+ outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_CRC, SMBAUXCTL(priv));
+ } else {
+ dev_dbg(&priv->adapter.dev, " [acc] hwpec: no\n");
+ outb_p(inb_p(SMBAUXCTL(priv)) & (~SMBAUXCTL_CRC), SMBAUXCTL(priv));
+ }
+
+ if (block) {
+ //ret = 0;
+ dev_dbg(&priv->adapter.dev, " [acc] block: yes\n");
+ ret = i801_block_transaction(priv, data, read_write, size, hwpec);
+ } else {
+ dev_dbg(&priv->adapter.dev, " [acc] block: no\n");
+ ret = i801_transaction(priv, xact | ENABLE_INT9);
+ }
+
+ /* Some BIOSes don't like it when PEC is enabled at reboot or resume
+ * time, so we forcibly disable it after every transaction. Turn off
+ * E32B for the same reason.
+ */
+ if (hwpec || block) {
+ dev_dbg(&priv->adapter.dev, " [acc] hwpec || block\n");
+ outb_p(inb_p(SMBAUXCTL(priv)) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
+ }
+ if (block) {
+ dev_dbg(&priv->adapter.dev, " [acc] block\n");
+ return ret;
+ }
+ if (ret) {
+ dev_dbg(&priv->adapter.dev, " [acc] ret %d\n", ret);
+ return ret;
+ }
+ if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK)) {
+ dev_dbg(&priv->adapter.dev, " [acc] I2C_SMBUS_WRITE || I801_QUICK -> ret 0\n");
+ return 0;
+ }
+
+ switch (xact & 0x7f) {
+ case I801_BYTE: /* Result put in SMBHSTDAT0 */
+ case I801_BYTE_DATA:
+ dev_dbg(&priv->adapter.dev, " [acc] I801_BYTE or I801_BYTE_DATA\n");
+ data->byte = inb_p(SMBHSTDAT0(priv));
+ break;
+ case I801_WORD_DATA:
+ dev_dbg(&priv->adapter.dev, " [acc] I801_WORD_DATA\n");
+ data->word = inb_p(SMBHSTDAT0(priv)) + (inb_p(SMBHSTDAT1(priv)) << 8);
+ break;
+ }
+ return 0;
+}
+
+static u32 i801_func(struct i2c_adapter *adapter)
+{
+ struct i2c_device *priv = i2c_get_adapdata(adapter);
+
+ /* original settings
+ * u32 f = I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ * I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ * I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK |
+ * ((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) |
+ * ((priv->features & FEATURE_I2C_BLOCK_READ) ?
+ * I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0);
+ */
+
+ // http://lxr.free-electrons.com/source/include/uapi/linux/i2c.h#L85
+
+ u32 f =
+ I2C_FUNC_I2C | /* 0x00000001 (I enabled this one) */
+ !I2C_FUNC_10BIT_ADDR | /* 0x00000002 */
+ !I2C_FUNC_PROTOCOL_MANGLING | /* 0x00000004 */
+ ((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) | /* 0x00000008 */
+ !I2C_FUNC_SMBUS_BLOCK_PROC_CALL | /* 0x00008000 */
+ I2C_FUNC_SMBUS_QUICK | /* 0x00010000 */
+ !I2C_FUNC_SMBUS_READ_BYTE | /* 0x00020000 */
+ !I2C_FUNC_SMBUS_WRITE_BYTE | /* 0x00040000 */
+ !I2C_FUNC_SMBUS_READ_BYTE_DATA | /* 0x00080000 */
+ !I2C_FUNC_SMBUS_WRITE_BYTE_DATA | /* 0x00100000 */
+ !I2C_FUNC_SMBUS_READ_WORD_DATA | /* 0x00200000 */
+ !I2C_FUNC_SMBUS_WRITE_WORD_DATA | /* 0x00400000 */
+ !I2C_FUNC_SMBUS_PROC_CALL | /* 0x00800000 */
+ !I2C_FUNC_SMBUS_READ_BLOCK_DATA | /* 0x01000000 */
+ !I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | /* 0x02000000 */
+ ((priv->features & FEATURE_I2C_BLOCK_READ) ? I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0) | /* 0x04000000 */
+ I2C_FUNC_SMBUS_WRITE_I2C_BLOCK | /* 0x08000000 */
+
+ I2C_FUNC_SMBUS_BYTE | /* _READ_BYTE _WRITE_BYTE */
+ I2C_FUNC_SMBUS_BYTE_DATA | /* _READ_BYTE_DATA _WRITE_BYTE_DATA */
+ I2C_FUNC_SMBUS_WORD_DATA | /* _READ_WORD_DATA _WRITE_WORD_DATA */
+ I2C_FUNC_SMBUS_BLOCK_DATA | /* _READ_BLOCK_DATA _WRITE_BLOCK_DATA */
+ !I2C_FUNC_SMBUS_I2C_BLOCK | /* _READ_I2C_BLOCK _WRITE_I2C_BLOCK */
+ !I2C_FUNC_SMBUS_EMUL; /* _QUICK _BYTE _BYTE_DATA _WORD_DATA _PROC_CALL _WRITE_BLOCK_DATA _I2C_BLOCK _PEC */
+ return f;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = i801_access,
+ .functionality = i801_func,
+};
+
+/********************************
+ *** Part 2 - Driver Handlers ***
+ ********************************/
+static int pi2c_probe(struct platform_device *pldev)
+{
+ int err;
+ struct i2c_device *priv;
+ struct resource *res;
+
+ priv = devm_kzalloc(&pldev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ i2c_set_adapdata(&priv->adapter, priv);
+ priv->adapter.owner = THIS_MODULE;
+ priv->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ priv->adapter.algo = &smbus_algorithm;
+
+ res = platform_get_resource(pldev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENXIO;
+
+ priv->smba = (unsigned long)devm_ioremap_nocache(&pldev->dev,
+ res->start,
+ resource_size(res));
+ if (!priv->smba)
+ return -ENOMEM;
+
+ platform_set_drvdata(pldev, priv);
+
+ priv->features |= FEATURE_IDF;
+ priv->features |= FEATURE_I2C_BLOCK_READ;
+ priv->features |= FEATURE_SMBUS_PEC;
+ priv->features |= FEATURE_BLOCK_BUFFER;
+
+ //init_MUTEX(&lddata->sem);
+
+ /* set up the sysfs linkage to our parent device */
+ priv->adapter.dev.parent = &pldev->dev;
+
+ /* Retry up to 3 times on lost arbitration */
+ priv->adapter.retries = 3;
+
+ //snprintf(priv->adapter.name, sizeof(priv->adapter.name), "Fake SMBus I801 adapter at %04lx", priv->smba);
+ snprintf(priv->adapter.name, sizeof(priv->adapter.name), "Fake SMBus I801 adapter");
+
+ err = i2c_add_adapter(&priv->adapter);
+ if (err) {
+ dev_err(&priv->adapter.dev, "Failed to add SMBus adapter\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static int pi2c_remove(struct platform_device *pldev)
+{
+ struct i2c_device *lddev;
+
+ lddev = (struct i2c_device *)platform_get_drvdata(pldev);
+
+ i2c_del_adapter(&lddev->adapter);
+
+ //TODO: Figure out the right thing to do here...
+ //pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
+ //pci_release_region(dev, SMBBAR);
+ //pci_set_drvdata(dev, NULL);
+
+ //cdev_del(&lddev->cdev);
+
+ return 0;
+}
+
+static struct platform_driver i2c_plat_driver_i = {
+ .probe = pi2c_probe,
+ .remove = pi2c_remove,
+ .driver = {
+ .name = KP_DRIVER_NAME_I2C,
+ },
+};
+
+module_platform_driver(i2c_plat_driver_i);
diff --git a/drivers/staging/kpc2000/kpc2000_spi.c b/drivers/staging/kpc2000/kpc2000_spi.c
new file mode 100644
index 000000000000..35ac1d7070b3
--- /dev/null
+++ b/drivers/staging/kpc2000/kpc2000_spi.c
@@ -0,0 +1,520 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * KP2000 SPI controller driver
+ *
+ * Copyright (C) 2014-2018 Daktronics
+ * Author: Matt Sickler <matt.sickler@daktronics.com>
+ * Very loosely based on spi-omap2-mcspi.c
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/gcd.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/mtd/partitions.h>
+
+#include "kpc.h"
+
+static struct mtd_partition p2kr0_spi0_parts[] = {
+ { .name = "SLOT_0", .size = 7798784, .offset = 0, },
+ { .name = "SLOT_1", .size = 7798784, .offset = MTDPART_OFS_NXTBLK},
+ { .name = "SLOT_2", .size = 7798784, .offset = MTDPART_OFS_NXTBLK},
+ { .name = "SLOT_3", .size = 7798784, .offset = MTDPART_OFS_NXTBLK},
+ { .name = "CS0_EXTRA", .size = MTDPART_SIZ_FULL, .offset = MTDPART_OFS_NXTBLK},
+};
+
+static struct mtd_partition p2kr0_spi1_parts[] = {
+ { .name = "SLOT_4", .size = 7798784, .offset = 0, },
+ { .name = "SLOT_5", .size = 7798784, .offset = MTDPART_OFS_NXTBLK},
+ { .name = "SLOT_6", .size = 7798784, .offset = MTDPART_OFS_NXTBLK},
+ { .name = "SLOT_7", .size = 7798784, .offset = MTDPART_OFS_NXTBLK},
+ { .name = "CS1_EXTRA", .size = MTDPART_SIZ_FULL, .offset = MTDPART_OFS_NXTBLK},
+};
+
+static struct flash_platform_data p2kr0_spi0_pdata = {
+ .name = "SPI0",
+ .nr_parts = ARRAY_SIZE(p2kr0_spi0_parts),
+ .parts = p2kr0_spi0_parts,
+};
+static struct flash_platform_data p2kr0_spi1_pdata = {
+ .name = "SPI1",
+ .nr_parts = ARRAY_SIZE(p2kr0_spi1_parts),
+ .parts = p2kr0_spi1_parts,
+};
+
+static struct spi_board_info p2kr0_board_info[] = {
+ {
+ .modalias = "n25q256a11",
+ .bus_num = 1,
+ .chip_select = 0,
+ .mode = SPI_MODE_0,
+ .platform_data = &p2kr0_spi0_pdata
+ },
+ {
+ .modalias = "n25q256a11",
+ .bus_num = 1,
+ .chip_select = 1,
+ .mode = SPI_MODE_0,
+ .platform_data = &p2kr0_spi1_pdata
+ },
+};
+
+/***************
+ * SPI Defines *
+ ***************/
+#define KP_SPI_REG_CONFIG 0x0 /* 0x00 */
+#define KP_SPI_REG_STATUS 0x1 /* 0x08 */
+#define KP_SPI_REG_FFCTRL 0x2 /* 0x10 */
+#define KP_SPI_REG_TXDATA 0x3 /* 0x18 */
+#define KP_SPI_REG_RXDATA 0x4 /* 0x20 */
+
+#define KP_SPI_CLK 48000000
+#define KP_SPI_MAX_FIFODEPTH 64
+#define KP_SPI_MAX_FIFOWCNT 0xFFFF
+
+#define KP_SPI_REG_CONFIG_TRM_TXRX 0
+#define KP_SPI_REG_CONFIG_TRM_RX 1
+#define KP_SPI_REG_CONFIG_TRM_TX 2
+
+#define KP_SPI_REG_STATUS_RXS 0x01
+#define KP_SPI_REG_STATUS_TXS 0x02
+#define KP_SPI_REG_STATUS_EOT 0x04
+#define KP_SPI_REG_STATUS_TXFFE 0x10
+#define KP_SPI_REG_STATUS_TXFFF 0x20
+#define KP_SPI_REG_STATUS_RXFFE 0x40
+#define KP_SPI_REG_STATUS_RXFFF 0x80
+
+/******************
+ * SPI Structures *
+ ******************/
+struct kp_spi {
+ struct spi_master *master;
+ u64 __iomem *base;
+ struct device *dev;
+};
+
+struct kp_spi_controller_state {
+ void __iomem *base;
+ s64 conf_cache;
+};
+
+union kp_spi_config {
+ /* use this to access individual elements */
+ struct __packed spi_config_bitfield {
+ unsigned int pha : 1; /* spim_clk Phase */
+ unsigned int pol : 1; /* spim_clk Polarity */
+ unsigned int epol : 1; /* spim_csx Polarity */
+ unsigned int dpe : 1; /* Transmission Enable */
+ unsigned int wl : 5; /* Word Length */
+ unsigned int : 3;
+ unsigned int trm : 2; /* TxRx Mode */
+ unsigned int cs : 4; /* Chip Select */
+ unsigned int wcnt : 7; /* Word Count */
+ unsigned int ffen : 1; /* FIFO Enable */
+ unsigned int spi_en : 1; /* SPI Enable */
+ unsigned int : 5;
+ } bitfield;
+ /* use this to grab the whole register */
+ u32 reg;
+};
+
+union kp_spi_status {
+ struct __packed spi_status_bitfield {
+ unsigned int rx : 1; /* Rx Status */
+ unsigned int tx : 1; /* Tx Status */
+ unsigned int eo : 1; /* End of Transfer */
+ unsigned int : 1;
+ unsigned int txffe : 1; /* Tx FIFO Empty */
+ unsigned int txfff : 1; /* Tx FIFO Full */
+ unsigned int rxffe : 1; /* Rx FIFO Empty */
+ unsigned int rxfff : 1; /* Rx FIFO Full */
+ unsigned int : 24;
+ } bitfield;
+ u32 reg;
+};
+
+union kp_spi_ffctrl {
+ struct __packed spi_ffctrl_bitfield {
+ unsigned int ffstart : 1; /* FIFO Start */
+ unsigned int : 31;
+ } bitfield;
+ u32 reg;
+};
+
+/***************
+ * SPI Helpers *
+ ***************/
+ static inline u64
+kp_spi_read_reg(struct kp_spi_controller_state *cs, int idx)
+{
+ u64 __iomem *addr = cs->base;
+ u64 val;
+
+ addr += idx;
+ if ((idx == KP_SPI_REG_CONFIG) && (cs->conf_cache >= 0))
+ return cs->conf_cache;
+
+ val = readq(addr);
+ return val;
+}
+
+ static inline void
+kp_spi_write_reg(struct kp_spi_controller_state *cs, int idx, u64 val)
+{
+ u64 __iomem *addr = cs->base;
+
+ addr += idx;
+ writeq(val, addr);
+ if (idx == KP_SPI_REG_CONFIG)
+ cs->conf_cache = val;
+}
+
+ static int
+kp_spi_wait_for_reg_bit(struct kp_spi_controller_state *cs, int idx,
+ unsigned long bit)
+{
+ unsigned long timeout;
+
+ timeout = jiffies + msecs_to_jiffies(1000);
+ while (!(kp_spi_read_reg(cs, idx) & bit)) {
+ if (time_after(jiffies, timeout)) {
+ if (!(kp_spi_read_reg(cs, idx) & bit))
+ return -ETIMEDOUT;
+ else
+ return 0;
+ }
+ cpu_relax();
+ }
+ return 0;
+}
+
+ static unsigned
+kp_spi_txrx_pio(struct spi_device *spidev, struct spi_transfer *transfer)
+{
+ struct kp_spi_controller_state *cs = spidev->controller_state;
+ unsigned int count = transfer->len;
+ unsigned int c = count;
+
+ int i;
+ int res;
+ u8 *rx = transfer->rx_buf;
+ const u8 *tx = transfer->tx_buf;
+ int processed = 0;
+
+ if (tx) {
+ for (i = 0 ; i < c ; i++) {
+ char val = *tx++;
+
+ res = kp_spi_wait_for_reg_bit(cs, KP_SPI_REG_STATUS,
+ KP_SPI_REG_STATUS_TXS);
+ if (res < 0)
+ goto out;
+
+ kp_spi_write_reg(cs, KP_SPI_REG_TXDATA, val);
+ processed++;
+ }
+ }
+ else if (rx) {
+ for (i = 0 ; i < c ; i++) {
+ char test = 0;
+
+ kp_spi_write_reg(cs, KP_SPI_REG_TXDATA, 0x00);
+ res = kp_spi_wait_for_reg_bit(cs, KP_SPI_REG_STATUS,
+ KP_SPI_REG_STATUS_RXS);
+ if (res < 0)
+ goto out;
+
+ test = kp_spi_read_reg(cs, KP_SPI_REG_RXDATA);
+ *rx++ = test;
+ processed++;
+ }
+ }
+
+ if (kp_spi_wait_for_reg_bit(cs, KP_SPI_REG_STATUS,
+ KP_SPI_REG_STATUS_EOT) < 0) {
+ //TODO: Figure out how to abort transaction??
+ //Ths has never happened in practice though...
+ }
+
+out:
+ return processed;
+}
+
+/*****************
+ * SPI Functions *
+ *****************/
+ static int
+kp_spi_setup(struct spi_device *spidev)
+{
+ union kp_spi_config sc;
+ struct kp_spi *kpspi = spi_master_get_devdata(spidev->master);
+ struct kp_spi_controller_state *cs;
+
+ /* setup controller state */
+ cs = spidev->controller_state;
+ if (!cs) {
+ cs = kzalloc(sizeof(*cs), GFP_KERNEL);
+ if (!cs)
+ return -ENOMEM;
+ cs->base = kpspi->base;
+ cs->conf_cache = -1;
+ spidev->controller_state = cs;
+ }
+
+ /* set config register */
+ sc.bitfield.wl = spidev->bits_per_word - 1;
+ sc.bitfield.cs = spidev->chip_select;
+ sc.bitfield.spi_en = 0;
+ sc.bitfield.trm = 0;
+ sc.bitfield.ffen = 0;
+ kp_spi_write_reg(spidev->controller_state, KP_SPI_REG_CONFIG, sc.reg);
+ return 0;
+}
+
+ static int
+kp_spi_transfer_one_message(struct spi_master *master, struct spi_message *m)
+{
+ struct kp_spi_controller_state *cs;
+ struct spi_device *spidev;
+ struct kp_spi *kpspi;
+ struct spi_transfer *transfer;
+ union kp_spi_config sc;
+ int status = 0;
+
+ spidev = m->spi;
+ kpspi = spi_master_get_devdata(master);
+ m->actual_length = 0;
+ m->status = 0;
+
+ cs = spidev->controller_state;
+
+ /* reject invalid messages and transfers */
+ if (list_empty(&m->transfers))
+ return -EINVAL;
+
+ /* validate input */
+ list_for_each_entry(transfer, &m->transfers, transfer_list) {
+ const void *tx_buf = transfer->tx_buf;
+ void *rx_buf = transfer->rx_buf;
+ unsigned int len = transfer->len;
+
+ if (transfer->speed_hz > KP_SPI_CLK ||
+ (len && !(rx_buf || tx_buf))) {
+ dev_dbg(kpspi->dev, " transfer: %d Hz, %d %s%s, %d bpw\n",
+ transfer->speed_hz,
+ len,
+ tx_buf ? "tx" : "",
+ rx_buf ? "rx" : "",
+ transfer->bits_per_word);
+ dev_dbg(kpspi->dev, " transfer -EINVAL\n");
+ return -EINVAL;
+ }
+ if (transfer->speed_hz &&
+ transfer->speed_hz < (KP_SPI_CLK >> 15)) {
+ dev_dbg(kpspi->dev, "speed_hz %d below minimum %d Hz\n",
+ transfer->speed_hz,
+ KP_SPI_CLK >> 15);
+ dev_dbg(kpspi->dev, " speed_hz -EINVAL\n");
+ return -EINVAL;
+ }
+ }
+
+ /* assert chip select to start the sequence*/
+ sc.reg = kp_spi_read_reg(cs, KP_SPI_REG_CONFIG);
+ sc.bitfield.spi_en = 1;
+ kp_spi_write_reg(cs, KP_SPI_REG_CONFIG, sc.reg);
+
+ /* work */
+ if (kp_spi_wait_for_reg_bit(cs, KP_SPI_REG_STATUS,
+ KP_SPI_REG_STATUS_EOT) < 0) {
+ dev_info(kpspi->dev, "EOT timed out\n");
+ goto out;
+ }
+
+ /* do the transfers for this message */
+ list_for_each_entry(transfer, &m->transfers, transfer_list) {
+ if (!transfer->tx_buf && !transfer->rx_buf &&
+ transfer->len) {
+ status = -EINVAL;
+ goto error;
+ }
+
+ /* transfer */
+ if (transfer->len) {
+ unsigned int word_len = spidev->bits_per_word;
+ unsigned int count;
+
+ /* set up the transfer... */
+ sc.reg = kp_spi_read_reg(cs, KP_SPI_REG_CONFIG);
+
+ /* ...direction */
+ if (transfer->tx_buf)
+ sc.bitfield.trm = KP_SPI_REG_CONFIG_TRM_TX;
+ else if (transfer->rx_buf)
+ sc.bitfield.trm = KP_SPI_REG_CONFIG_TRM_RX;
+
+ /* ...word length */
+ if (transfer->bits_per_word)
+ word_len = transfer->bits_per_word;
+ sc.bitfield.wl = word_len - 1;
+
+ /* ...chip select */
+ sc.bitfield.cs = spidev->chip_select;
+
+ /* ...and write the new settings */
+ kp_spi_write_reg(cs, KP_SPI_REG_CONFIG, sc.reg);
+
+ /* do the transfer */
+ count = kp_spi_txrx_pio(spidev, transfer);
+ m->actual_length += count;
+
+ if (count != transfer->len) {
+ status = -EIO;
+ goto error;
+ }
+ }
+
+ if (transfer->delay_usecs)
+ udelay(transfer->delay_usecs);
+ }
+
+ /* de-assert chip select to end the sequence */
+ sc.reg = kp_spi_read_reg(cs, KP_SPI_REG_CONFIG);
+ sc.bitfield.spi_en = 0;
+ kp_spi_write_reg(cs, KP_SPI_REG_CONFIG, sc.reg);
+
+out:
+ /* done work */
+ spi_finalize_current_message(master);
+ return 0;
+
+error:
+ m->status = status;
+ return status;
+}
+
+ static void
+kp_spi_cleanup(struct spi_device *spidev)
+{
+ struct kp_spi_controller_state *cs = spidev->controller_state;
+
+ if (cs)
+ kfree(cs);
+}
+
+/******************
+ * Probe / Remove *
+ ******************/
+ static int
+kp_spi_probe(struct platform_device *pldev)
+{
+ struct kpc_core_device_platdata *drvdata;
+ struct spi_master *master;
+ struct kp_spi *kpspi;
+ struct resource *r;
+ int status = 0;
+ int i;
+
+ drvdata = pldev->dev.platform_data;
+ if (!drvdata) {
+ dev_err(&pldev->dev, "%s: platform_data is NULL\n", __func__);
+ return -ENODEV;
+ }
+
+ master = spi_alloc_master(&pldev->dev, sizeof(struct kp_spi));
+ if (!master) {
+ dev_err(&pldev->dev, "%s: master allocation failed\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ /* set up the spi functions */
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+ master->bits_per_word_mask = (unsigned int)SPI_BPW_RANGE_MASK(4, 32);
+ master->setup = kp_spi_setup;
+ master->transfer_one_message = kp_spi_transfer_one_message;
+ master->cleanup = kp_spi_cleanup;
+
+ platform_set_drvdata(pldev, master);
+
+ kpspi = spi_master_get_devdata(master);
+ kpspi->master = master;
+ kpspi->dev = &pldev->dev;
+
+ master->num_chipselect = 4;
+ if (pldev->id != -1)
+ master->bus_num = pldev->id;
+
+ r = platform_get_resource(pldev, IORESOURCE_MEM, 0);
+ if (!r) {
+ dev_err(&pldev->dev, "%s: Unable to get platform resources\n",
+ __func__);
+ status = -ENODEV;
+ goto free_master;
+ }
+
+ kpspi->base = devm_ioremap_nocache(&pldev->dev, r->start,
+ resource_size(r));
+
+ status = spi_register_master(master);
+ if (status < 0) {
+ dev_err(&pldev->dev, "Unable to register SPI device\n");
+ goto free_master;
+ }
+
+ /* register the slave boards */
+#define NEW_SPI_DEVICE_FROM_BOARD_INFO_TABLE(table) \
+ for (i = 0 ; i < ARRAY_SIZE(table) ; i++) { \
+ spi_new_device(master, &(table[i])); \
+ }
+
+ switch ((drvdata->card_id & 0xFFFF0000) >> 16) {
+ case PCI_DEVICE_ID_DAKTRONICS_KADOKA_P2KR0:
+ NEW_SPI_DEVICE_FROM_BOARD_INFO_TABLE(p2kr0_board_info);
+ break;
+ default:
+ dev_err(&pldev->dev, "Unknown hardware, cant know what partition table to use!\n");
+ goto free_master;
+ }
+
+ return status;
+
+free_master:
+ spi_master_put(master);
+ return status;
+}
+
+ static int
+kp_spi_remove(struct platform_device *pldev)
+{
+ struct spi_master *master = platform_get_drvdata(pldev);
+
+ spi_unregister_master(master);
+ return 0;
+}
+
+static struct platform_driver kp_spi_driver = {
+ .driver = {
+ .name = KP_DRIVER_NAME_SPI,
+ },
+ .probe = kp_spi_probe,
+ .remove = kp_spi_remove,
+};
+
+module_platform_driver(kp_spi_driver);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:kp_spi");
diff --git a/drivers/staging/kpc2000/kpc_dma/dma.c b/drivers/staging/kpc2000/kpc_dma/dma.c
index 6959bac11388..51a4dd534a0d 100644
--- a/drivers/staging/kpc2000/kpc_dma/dma.c
+++ b/drivers/staging/kpc2000/kpc_dma/dma.c
@@ -2,7 +2,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/export.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
@@ -14,11 +14,11 @@
static
irqreturn_t ndd_irq_handler(int irq, void *dev_id)
{
- struct kpc_dma_device *ldev = (struct kpc_dma_device*)dev_id;
-
+ struct kpc_dma_device *ldev = (struct kpc_dma_device *)dev_id;
+
if ((GetEngineControl(ldev) & ENG_CTL_IRQ_ACTIVE) || (ldev->desc_completed->MyDMAAddr != GetEngineCompletePtr(ldev)))
schedule_work(&ldev->irq_work);
-
+
return IRQ_HANDLED;
}
@@ -27,217 +27,215 @@ void ndd_irq_worker(struct work_struct *ws)
{
struct kpc_dma_descriptor *cur;
struct kpc_dma_device *eng = container_of(ws, struct kpc_dma_device, irq_work);
+
lock_engine(eng);
-
+
if (GetEngineCompletePtr(eng) == 0)
goto out;
-
+
if (eng->desc_completed->MyDMAAddr == GetEngineCompletePtr(eng))
goto out;
-
+
cur = eng->desc_completed;
do {
cur = cur->Next;
dev_dbg(&eng->pldev->dev, "Handling completed descriptor %p (acd = %p)\n", cur, cur->acd);
BUG_ON(cur == eng->desc_next); // Ordering failure.
-
- if (cur->DescControlFlags & DMA_DESC_CTL_SOP){
+
+ if (cur->DescControlFlags & DMA_DESC_CTL_SOP) {
eng->accumulated_bytes = 0;
eng->accumulated_flags = 0;
}
-
+
eng->accumulated_bytes += cur->DescByteCount;
if (cur->DescStatusFlags & DMA_DESC_STS_ERROR)
eng->accumulated_flags |= ACD_FLAG_ENG_ACCUM_ERROR;
-
+
if (cur->DescStatusFlags & DMA_DESC_STS_SHORT)
eng->accumulated_flags |= ACD_FLAG_ENG_ACCUM_SHORT;
-
- if (cur->DescControlFlags & DMA_DESC_CTL_EOP){
+
+ if (cur->DescControlFlags & DMA_DESC_CTL_EOP) {
if (cur->acd)
transfer_complete_cb(cur->acd, eng->accumulated_bytes, eng->accumulated_flags | ACD_FLAG_DONE);
}
-
+
eng->desc_completed = cur;
} while (cur->MyDMAAddr != GetEngineCompletePtr(eng));
-
+
out:
SetClearEngineControl(eng, ENG_CTL_IRQ_ACTIVE, 0);
-
+
unlock_engine(eng);
}
-
/********** DMA Engine Init/Teardown **********/
void start_dma_engine(struct kpc_dma_device *eng)
{
eng->desc_next = eng->desc_pool_first;
eng->desc_completed = eng->desc_pool_last;
-
+
// Setup the engine pointer registers
SetEngineNextPtr(eng, eng->desc_pool_first);
SetEngineSWPtr(eng, eng->desc_pool_first);
ClearEngineCompletePtr(eng);
-
+
WriteEngineControl(eng, ENG_CTL_DMA_ENABLE | ENG_CTL_IRQ_ENABLE);
}
int setup_dma_engine(struct kpc_dma_device *eng, u32 desc_cnt)
{
u32 caps;
- struct kpc_dma_descriptor * cur;
- struct kpc_dma_descriptor * next;
+ struct kpc_dma_descriptor *cur;
+ struct kpc_dma_descriptor *next;
dma_addr_t next_handle;
dma_addr_t head_handle;
unsigned int i;
int rv;
- dev_dbg(&eng->pldev->dev, "Setting up DMA engine [%p]\n", eng);
-
+
caps = GetEngineCapabilities(eng);
-
- if (WARN(!(caps & ENG_CAP_PRESENT), "setup_dma_engine() called for DMA Engine at %p which isn't present in hardware!\n", eng))
+
+ if (WARN(!(caps & ENG_CAP_PRESENT), "%s() called for DMA Engine at %p which isn't present in hardware!\n", __func__, eng))
return -ENXIO;
-
- if (caps & ENG_CAP_DIRECTION){
+
+ if (caps & ENG_CAP_DIRECTION) {
eng->dir = DMA_FROM_DEVICE;
} else {
eng->dir = DMA_TO_DEVICE;
}
-
+
eng->desc_pool_cnt = desc_cnt;
eng->desc_pool = dma_pool_create("KPC DMA Descriptors", &eng->pldev->dev, sizeof(struct kpc_dma_descriptor), DMA_DESC_ALIGNMENT, 4096);
-
+
eng->desc_pool_first = dma_pool_alloc(eng->desc_pool, GFP_KERNEL | GFP_DMA, &head_handle);
- if (!eng->desc_pool_first){
- dev_err(&eng->pldev->dev, "setup_dma_engine: couldn't allocate desc_pool_first!\n");
+ if (!eng->desc_pool_first) {
+ dev_err(&eng->pldev->dev, "%s: couldn't allocate desc_pool_first!\n", __func__);
dma_pool_destroy(eng->desc_pool);
return -ENOMEM;
}
-
+
eng->desc_pool_first->MyDMAAddr = head_handle;
clear_desc(eng->desc_pool_first);
-
+
cur = eng->desc_pool_first;
- for (i = 1 ; i < eng->desc_pool_cnt ; i++){
+ for (i = 1 ; i < eng->desc_pool_cnt ; i++) {
next = dma_pool_alloc(eng->desc_pool, GFP_KERNEL | GFP_DMA, &next_handle);
- if (next == NULL)
+ if (!next)
goto done_alloc;
-
+
clear_desc(next);
next->MyDMAAddr = next_handle;
-
+
cur->DescNextDescPtr = next_handle;
cur->Next = next;
cur = next;
}
-
+
done_alloc:
// Link the last descriptor back to the first, so it's a circular linked list
cur->Next = eng->desc_pool_first;
cur->DescNextDescPtr = eng->desc_pool_first->MyDMAAddr;
-
+
eng->desc_pool_last = cur;
eng->desc_completed = eng->desc_pool_last;
-
+
// Setup work queue
INIT_WORK(&eng->irq_work, ndd_irq_worker);
-
+
// Grab IRQ line
rv = request_irq(eng->irq, ndd_irq_handler, IRQF_SHARED, KP_DRIVER_NAME_DMA_CONTROLLER, eng);
- if (rv){
- dev_err(&eng->pldev->dev, "setup_dma_engine: failed to request_irq: %d\n", rv);
+ if (rv) {
+ dev_err(&eng->pldev->dev, "%s: failed to request_irq: %d\n", __func__, rv);
return rv;
}
-
+
// Turn on the engine!
start_dma_engine(eng);
unlock_engine(eng);
-
+
return 0;
}
void stop_dma_engine(struct kpc_dma_device *eng)
{
unsigned long timeout;
- dev_dbg(&eng->pldev->dev, "Destroying DMA engine [%p]\n", eng);
-
+
// Disable the descriptor engine
WriteEngineControl(eng, 0);
-
+
// Wait for descriptor engine to finish current operaion
timeout = jiffies + (HZ / 2);
- while (GetEngineControl(eng) & ENG_CTL_DMA_RUNNING){
- if (time_after(jiffies, timeout)){
+ while (GetEngineControl(eng) & ENG_CTL_DMA_RUNNING) {
+ if (time_after(jiffies, timeout)) {
dev_crit(&eng->pldev->dev, "DMA_RUNNING still asserted!\n");
break;
}
}
-
+
// Request a reset
WriteEngineControl(eng, ENG_CTL_DMA_RESET_REQUEST);
-
+
// Wait for reset request to be processed
timeout = jiffies + (HZ / 2);
- while (GetEngineControl(eng) & (ENG_CTL_DMA_RUNNING | ENG_CTL_DMA_RESET_REQUEST)){
- if (time_after(jiffies, timeout)){
+ while (GetEngineControl(eng) & (ENG_CTL_DMA_RUNNING | ENG_CTL_DMA_RESET_REQUEST)) {
+ if (time_after(jiffies, timeout)) {
dev_crit(&eng->pldev->dev, "ENG_CTL_DMA_RESET_REQUEST still asserted!\n");
break;
}
}
-
+
// Request a reset
WriteEngineControl(eng, ENG_CTL_DMA_RESET);
-
+
// And wait for reset to complete
timeout = jiffies + (HZ / 2);
- while (GetEngineControl(eng) & ENG_CTL_DMA_RESET){
- if (time_after(jiffies, timeout)){
+ while (GetEngineControl(eng) & ENG_CTL_DMA_RESET) {
+ if (time_after(jiffies, timeout)) {
dev_crit(&eng->pldev->dev, "DMA_RESET still asserted!\n");
break;
}
}
-
+
// Clear any persistent bits just to make sure there is no residue from the reset
SetClearEngineControl(eng, (ENG_CTL_IRQ_ACTIVE | ENG_CTL_DESC_COMPLETE | ENG_CTL_DESC_ALIGN_ERR | ENG_CTL_DESC_FETCH_ERR | ENG_CTL_SW_ABORT_ERR | ENG_CTL_DESC_CHAIN_END | ENG_CTL_DMA_WAITING_PERSIST), 0);
-
+
// Reset performance counters
-
+
// Completely disable the engine
WriteEngineControl(eng, 0);
}
void destroy_dma_engine(struct kpc_dma_device *eng)
{
- struct kpc_dma_descriptor * cur;
+ struct kpc_dma_descriptor *cur;
dma_addr_t cur_handle;
unsigned int i;
-
+
stop_dma_engine(eng);
-
+
cur = eng->desc_pool_first;
cur_handle = eng->desc_pool_first->MyDMAAddr;
-
- for (i = 0 ; i < eng->desc_pool_cnt ; i++){
+
+ for (i = 0 ; i < eng->desc_pool_cnt ; i++) {
struct kpc_dma_descriptor *next = cur->Next;
dma_addr_t next_handle = cur->DescNextDescPtr;
+
dma_pool_free(eng->desc_pool, cur, cur_handle);
cur_handle = next_handle;
cur = next;
}
-
+
dma_pool_destroy(eng->desc_pool);
-
+
free_irq(eng->irq, eng);
}
-
-
/********** Helper Functions **********/
int count_descriptors_available(struct kpc_dma_device *eng)
{
u32 count = 0;
struct kpc_dma_descriptor *cur = eng->desc_next;
- while (cur != eng->desc_completed){
+
+ while (cur != eng->desc_completed) {
BUG_ON(cur == NULL);
count++;
cur = cur->Next;
@@ -247,7 +245,7 @@ int count_descriptors_available(struct kpc_dma_device *eng)
void clear_desc(struct kpc_dma_descriptor *desc)
{
- if (desc == NULL)
+ if (!desc)
return;
desc->DescByteCount = 0;
desc->DescStatusErrorFlags = 0;
diff --git a/drivers/staging/kpc2000/kpc_dma/fileops.c b/drivers/staging/kpc2000/kpc_dma/fileops.c
index 616658709bd9..48ca88bc6b0b 100644
--- a/drivers/staging/kpc2000/kpc_dma/fileops.c
+++ b/drivers/staging/kpc2000/kpc_dma/fileops.c
@@ -9,7 +9,6 @@
#include <linux/types.h> /* size_t */
#include <linux/cdev.h>
#include <linux/uaccess.h> /* copy_*_user */
-#include <linux/aio.h> /* aio stuff */
#include <linux/highmem.h>
#include <linux/pagemap.h>
#include "kpc_dma_driver.h"
@@ -21,20 +20,19 @@ unsigned int count_pages(unsigned long iov_base, size_t iov_len)
{
unsigned long first = (iov_base & PAGE_MASK) >> PAGE_SHIFT;
unsigned long last = ((iov_base+iov_len-1) & PAGE_MASK) >> PAGE_SHIFT;
+
return last - first + 1;
}
static inline
unsigned int count_parts_for_sge(struct scatterlist *sg)
{
- unsigned int sg_length = sg_dma_len(sg);
- sg_length += (0x80000-1);
- return (sg_length / 0x80000);
+ return DIV_ROUND_UP(sg_dma_len(sg), 0x80000);
}
/********** Transfer Helpers **********/
-static
-int kpc_dma_transfer(struct dev_private_data *priv, struct kiocb *kcb, unsigned long iov_base, size_t iov_len)
+static int kpc_dma_transfer(struct dev_private_data *priv,
+ unsigned long iov_base, size_t iov_len)
{
unsigned int i = 0;
long rv = 0;
@@ -50,75 +48,72 @@ int kpc_dma_transfer(struct dev_private_data *priv, struct kiocb *kcb, unsigned
u64 card_addr;
u64 dma_addr;
u64 user_ctl;
-
+
BUG_ON(priv == NULL);
ldev = priv->ldev;
BUG_ON(ldev == NULL);
-
- dev_dbg(&priv->ldev->pldev->dev, "kpc_dma_transfer(priv = [%p], kcb = [%p], iov_base = [%p], iov_len = %ld) ldev = [%p]\n", priv, kcb, (void*)iov_base, iov_len, ldev);
-
- acd = (struct aio_cb_data *) kzalloc(sizeof(struct aio_cb_data), GFP_KERNEL);
- if (!acd){
+
+ acd = kzalloc(sizeof(*acd), GFP_KERNEL);
+ if (!acd) {
dev_err(&priv->ldev->pldev->dev, "Couldn't kmalloc space for for the aio data\n");
return -ENOMEM;
}
memset(acd, 0x66, sizeof(struct aio_cb_data));
-
+
acd->priv = priv;
acd->ldev = priv->ldev;
acd->cpl = &done;
acd->flags = 0;
- acd->kcb = kcb;
acd->len = iov_len;
acd->page_count = count_pages(iov_base, iov_len);
-
+
// Allocate an array of page pointers
acd->user_pages = kzalloc(sizeof(struct page *) * acd->page_count, GFP_KERNEL);
- if (!acd->user_pages){
+ if (!acd->user_pages) {
dev_err(&priv->ldev->pldev->dev, "Couldn't kmalloc space for for the page pointers\n");
rv = -ENOMEM;
goto err_alloc_userpages;
}
-
+
// Lock the user buffer pages in memory, and hold on to the page pointers (for the sglist)
down_read(&current->mm->mmap_sem); /* get memory map semaphore */
rv = get_user_pages(iov_base, acd->page_count, FOLL_TOUCH | FOLL_WRITE | FOLL_GET, acd->user_pages, NULL);
up_read(&current->mm->mmap_sem); /* release the semaphore */
- if (rv != acd->page_count){
+ if (rv != acd->page_count) {
dev_err(&priv->ldev->pldev->dev, "Couldn't get_user_pages (%ld)\n", rv);
goto err_get_user_pages;
}
-
+
// Allocate and setup the sg_table (scatterlist entries)
rv = sg_alloc_table_from_pages(&acd->sgt, acd->user_pages, acd->page_count, iov_base & (PAGE_SIZE-1), iov_len, GFP_KERNEL);
- if (rv){
+ if (rv) {
dev_err(&priv->ldev->pldev->dev, "Couldn't alloc sg_table (%ld)\n", rv);
goto err_alloc_sg_table;
}
-
+
// Setup the DMA mapping for all the sg entries
acd->mapped_entry_count = dma_map_sg(&ldev->pldev->dev, acd->sgt.sgl, acd->sgt.nents, ldev->dir);
- if (acd->mapped_entry_count <= 0){
+ if (acd->mapped_entry_count <= 0) {
dev_err(&priv->ldev->pldev->dev, "Couldn't dma_map_sg (%d)\n", acd->mapped_entry_count);
goto err_dma_map_sg;
}
// Calculate how many descriptors are actually needed for this transfer.
- for_each_sg(acd->sgt.sgl, sg, acd->mapped_entry_count, i){
+ for_each_sg(acd->sgt.sgl, sg, acd->mapped_entry_count, i) {
desc_needed += count_parts_for_sge(sg);
}
-
+
lock_engine(ldev);
-
+
// Figoure out how many descriptors are available and return an error if there aren't enough
num_descrs_avail = count_descriptors_available(ldev);
dev_dbg(&priv->ldev->pldev->dev, " mapped_entry_count = %d num_descrs_needed = %d num_descrs_avail = %d\n", acd->mapped_entry_count, desc_needed, num_descrs_avail);
- if (desc_needed >= ldev->desc_pool_cnt){
+ if (desc_needed >= ldev->desc_pool_cnt) {
dev_warn(&priv->ldev->pldev->dev, " mapped_entry_count = %d num_descrs_needed = %d num_descrs_avail = %d TOO MANY to ever complete!\n", acd->mapped_entry_count, desc_needed, num_descrs_avail);
rv = -EAGAIN;
goto err_descr_too_many;
}
- if (desc_needed > num_descrs_avail){
+ if (desc_needed > num_descrs_avail) {
dev_warn(&priv->ldev->pldev->dev, " mapped_entry_count = %d num_descrs_needed = %d num_descrs_avail = %d Too many to complete right now.\n", acd->mapped_entry_count, desc_needed, num_descrs_avail);
rv = -EMSGSIZE;
goto err_descr_too_many;
@@ -127,70 +122,67 @@ int kpc_dma_transfer(struct dev_private_data *priv, struct kiocb *kcb, unsigned
// Loop through all the sg table entries and fill out a descriptor for each one.
desc = ldev->desc_next;
card_addr = acd->priv->card_addr;
- for_each_sg(acd->sgt.sgl, sg, acd->mapped_entry_count, i){
+ for_each_sg(acd->sgt.sgl, sg, acd->mapped_entry_count, i) {
pcnt = count_parts_for_sge(sg);
- for (p = 0 ; p < pcnt ; p++){
+ for (p = 0 ; p < pcnt ; p++) {
// Fill out the descriptor
BUG_ON(desc == NULL);
clear_desc(desc);
- if (p != pcnt-1){
+ if (p != pcnt-1) {
desc->DescByteCount = 0x80000;
} else {
desc->DescByteCount = sg_dma_len(sg) - (p * 0x80000);
}
desc->DescBufferByteCount = desc->DescByteCount;
-
+
desc->DescControlFlags |= DMA_DESC_CTL_IRQONERR;
if (i == 0 && p == 0)
desc->DescControlFlags |= DMA_DESC_CTL_SOP;
if (i == acd->mapped_entry_count-1 && p == pcnt-1)
desc->DescControlFlags |= DMA_DESC_CTL_EOP | DMA_DESC_CTL_IRQONDONE;
-
+
desc->DescCardAddrLS = (card_addr & 0xFFFFFFFF);
desc->DescCardAddrMS = (card_addr >> 32) & 0xF;
card_addr += desc->DescByteCount;
-
+
dma_addr = sg_dma_address(sg) + (p * 0x80000);
desc->DescSystemAddrLS = (dma_addr & 0x00000000FFFFFFFF) >> 0;
desc->DescSystemAddrMS = (dma_addr & 0xFFFFFFFF00000000) >> 32;
-
+
user_ctl = acd->priv->user_ctl;
- if (i == acd->mapped_entry_count-1 && p == pcnt-1){
+ if (i == acd->mapped_entry_count-1 && p == pcnt-1) {
user_ctl = acd->priv->user_ctl_last;
}
desc->DescUserControlLS = (user_ctl & 0x00000000FFFFFFFF) >> 0;
desc->DescUserControlMS = (user_ctl & 0xFFFFFFFF00000000) >> 32;
-
+
if (i == acd->mapped_entry_count-1 && p == pcnt-1)
desc->acd = acd;
-
+
dev_dbg(&priv->ldev->pldev->dev, " Filled descriptor %p (acd = %p)\n", desc, desc->acd);
-
+
ldev->desc_next = desc->Next;
desc = desc->Next;
}
}
-
+
// Send the filled descriptors off to the hardware to process!
SetEngineSWPtr(ldev, ldev->desc_next);
-
+
unlock_engine(ldev);
-
- // If this is a synchronous kiocb, we need to put the calling process to sleep until the transfer is complete
- if (kcb == NULL || is_sync_kiocb(kcb)){
- rv = wait_for_completion_interruptible(&done);
- // If the user aborted (rv == -ERESTARTSYS), we're no longer responsible for cleaning up the acd
- if (rv == -ERESTARTSYS){
- acd->cpl = NULL;
- }
- if (rv == 0){
- rv = acd->len;
- kfree(acd);
- }
- return rv;
+
+ rv = wait_for_completion_interruptible(&done);
+ /*
+ * If the user aborted (rv == -ERESTARTSYS), we're no longer responsible
+ * for cleaning up the acd
+ */
+ if (rv == -ERESTARTSYS)
+ acd->cpl = NULL;
+ if (rv == 0) {
+ rv = acd->len;
+ kfree(acd);
}
-
- return -EIOCBQUEUED;
+ return rv;
err_descr_too_many:
unlock_engine(ldev);
@@ -198,58 +190,52 @@ int kpc_dma_transfer(struct dev_private_data *priv, struct kiocb *kcb, unsigned
sg_free_table(&acd->sgt);
err_dma_map_sg:
err_alloc_sg_table:
- for (i = 0 ; i < acd->page_count ; i++){
+ for (i = 0 ; i < acd->page_count ; i++) {
put_page(acd->user_pages[i]);
}
err_get_user_pages:
kfree(acd->user_pages);
err_alloc_userpages:
kfree(acd);
- dev_dbg(&priv->ldev->pldev->dev, "kpc_dma_transfer returning with error %ld\n", rv);
+ dev_dbg(&priv->ldev->pldev->dev, "%s returning with error %ld\n", __func__, rv);
return rv;
}
void transfer_complete_cb(struct aio_cb_data *acd, size_t xfr_count, u32 flags)
{
unsigned int i;
-
+
BUG_ON(acd == NULL);
BUG_ON(acd->user_pages == NULL);
BUG_ON(acd->sgt.sgl == NULL);
BUG_ON(acd->ldev == NULL);
BUG_ON(acd->ldev->pldev == NULL);
-
- dev_dbg(&acd->ldev->pldev->dev, "transfer_complete_cb(acd = [%p])\n", acd);
-
- for (i = 0 ; i < acd->page_count ; i++){
- if (!PageReserved(acd->user_pages[i])){
+
+ for (i = 0 ; i < acd->page_count ; i++) {
+ if (!PageReserved(acd->user_pages[i])) {
set_page_dirty(acd->user_pages[i]);
}
}
-
+
dma_unmap_sg(&acd->ldev->pldev->dev, acd->sgt.sgl, acd->sgt.nents, acd->ldev->dir);
-
- for (i = 0 ; i < acd->page_count ; i++){
+
+ for (i = 0 ; i < acd->page_count ; i++) {
put_page(acd->user_pages[i]);
}
-
+
sg_free_table(&acd->sgt);
-
+
kfree(acd->user_pages);
-
+
acd->flags = flags;
-
- if (acd->kcb == NULL || is_sync_kiocb(acd->kcb)){
- if (acd->cpl){
- complete(acd->cpl);
- } else {
- // There's no completion, so we're responsible for cleaning up the acd
- kfree(acd);
- }
+
+ if (acd->cpl) {
+ complete(acd->cpl);
} else {
-#ifdef CONFIG_KPC_DMA_AIO
- aio_complete(acd->kcb, acd->len, acd->flags);
-#endif
+ /*
+ * There's no completion, so we're responsible for cleaning up
+ * the acd
+ */
kfree(acd);
}
}
@@ -260,22 +246,22 @@ int kpc_dma_open(struct inode *inode, struct file *filp)
{
struct dev_private_data *priv;
struct kpc_dma_device *ldev = kpc_dma_lookup_device(iminor(inode));
- if (ldev == NULL)
+
+ if (!ldev)
return -ENODEV;
-
- if (! atomic_dec_and_test(&ldev->open_count)){
+
+ if (!atomic_dec_and_test(&ldev->open_count)) {
atomic_inc(&ldev->open_count);
return -EBUSY; /* already open */
}
-
+
priv = kzalloc(sizeof(struct dev_private_data), GFP_KERNEL);
if (!priv)
return -ENOMEM;
-
+
priv->ldev = ldev;
filp->private_data = priv;
-
- dev_dbg(&priv->ldev->pldev->dev, "kpc_dma_open(inode = [%p], filp = [%p]) priv = [%p] ldev = [%p]\n", inode, filp, priv, priv->ldev);
+
return 0;
}
@@ -285,134 +271,81 @@ int kpc_dma_close(struct inode *inode, struct file *filp)
struct kpc_dma_descriptor *cur;
struct dev_private_data *priv = (struct dev_private_data *)filp->private_data;
struct kpc_dma_device *eng = priv->ldev;
- dev_dbg(&priv->ldev->pldev->dev, "kpc_dma_close(inode = [%p], filp = [%p]) priv = [%p], ldev = [%p]\n", inode, filp, priv, priv->ldev);
-
+
lock_engine(eng);
-
+
stop_dma_engine(eng);
-
+
cur = eng->desc_completed->Next;
- while (cur != eng->desc_next){
+ while (cur != eng->desc_next) {
dev_dbg(&eng->pldev->dev, "Aborting descriptor %p (acd = %p)\n", cur, cur->acd);
- if (cur->DescControlFlags & DMA_DESC_CTL_EOP){
+ if (cur->DescControlFlags & DMA_DESC_CTL_EOP) {
if (cur->acd)
transfer_complete_cb(cur->acd, 0, ACD_FLAG_ABORT);
}
-
+
clear_desc(cur);
eng->desc_completed = cur;
-
+
cur = cur->Next;
}
-
+
start_dma_engine(eng);
-
+
unlock_engine(eng);
-
+
atomic_inc(&priv->ldev->open_count); /* release the device */
kfree(priv);
return 0;
}
-#ifdef CONFIG_KPC_DMA_AIO
static
-int kpc_dma_aio_cancel(struct kiocb *kcb)
+ssize_t kpc_dma_read(struct file *filp, char __user *user_buf, size_t count, loff_t *ppos)
{
- struct dev_private_data *priv = (struct dev_private_data *)kcb->ki_filp->private_data;
- dev_dbg(&priv->ldev->pldev->dev, "kpc_dma_aio_cancel(kcb = [%p]) priv = [%p], ldev = [%p]\n", kcb, priv, priv->ldev);
- return 0;
-}
+ struct dev_private_data *priv = (struct dev_private_data *)filp->private_data;
-static
-ssize_t kpc_dma_aio_read(struct kiocb *kcb, const struct iovec *iov, unsigned long iov_count, loff_t pos)
-{
- struct dev_private_data *priv = (struct dev_private_data *)kcb->ki_filp->private_data;
- dev_dbg(&priv->ldev->pldev->dev, "kpc_dma_aio_read(kcb = [%p], iov = [%p], iov_count = %ld, pos = %lld) priv = [%p], ldev = [%p]\n", kcb, iov, iov_count, pos, priv, priv->ldev);
-
if (priv->ldev->dir != DMA_FROM_DEVICE)
return -EMEDIUMTYPE;
-
- if (iov_count != 1){
- dev_err(&priv->ldev->pldev->dev, "kpc_dma_aio_read() called with iov_count > 1!\n");
- return -EFAULT;
- }
-
- if (!is_sync_kiocb(kcb))
- kiocb_set_cancel_fn(kcb, kpc_dma_aio_cancel);
- return kpc_dma_transfer(priv, kcb, (unsigned long)iov->iov_base, iov->iov_len);
-}
-static
-ssize_t kpc_dma_aio_write(struct kiocb *kcb, const struct iovec *iov, unsigned long iov_count, loff_t pos)
-{
- struct dev_private_data *priv = (struct dev_private_data *)kcb->ki_filp->private_data;
- dev_dbg(&priv->ldev->pldev->dev, "kpc_dma_aio_write(kcb = [%p], iov = [%p], iov_count = %ld, pos = %lld) priv = [%p], ldev = [%p]\n", kcb, iov, iov_count, pos, priv, priv->ldev);
-
- if (priv->ldev->dir != DMA_TO_DEVICE)
- return -EMEDIUMTYPE;
-
- if (iov_count != 1){
- dev_err(&priv->ldev->pldev->dev, "kpc_dma_aio_write() called with iov_count > 1!\n");
- return -EFAULT;
- }
-
- if (!is_sync_kiocb(kcb))
- kiocb_set_cancel_fn(kcb, kpc_dma_aio_cancel);
- return kpc_dma_transfer(priv, kcb, (unsigned long)iov->iov_base, iov->iov_len);
-}
-#endif
-
-static
-ssize_t kpc_dma_read( struct file *filp, char __user *user_buf, size_t count, loff_t *ppos)
-{
- struct dev_private_data *priv = (struct dev_private_data *)filp->private_data;
- dev_dbg(&priv->ldev->pldev->dev, "kpc_dma_read(filp = [%p], user_buf = [%p], count = %zu, ppos = [%p]) priv = [%p], ldev = [%p]\n", filp, user_buf, count, ppos, priv, priv->ldev);
-
- if (priv->ldev->dir != DMA_FROM_DEVICE)
- return -EMEDIUMTYPE;
-
- return kpc_dma_transfer(priv, (struct kiocb *)NULL, (unsigned long)user_buf, count);
+ return kpc_dma_transfer(priv, (unsigned long)user_buf, count);
}
static
ssize_t kpc_dma_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *ppos)
{
struct dev_private_data *priv = (struct dev_private_data *)filp->private_data;
- dev_dbg(&priv->ldev->pldev->dev, "kpc_dma_write(filp = [%p], user_buf = [%p], count = %zu, ppos = [%p]) priv = [%p], ldev = [%p]\n", filp, user_buf, count, ppos, priv, priv->ldev);
-
+
if (priv->ldev->dir != DMA_TO_DEVICE)
return -EMEDIUMTYPE;
-
- return kpc_dma_transfer(priv, (struct kiocb *)NULL, (unsigned long)user_buf, count);
+
+ return kpc_dma_transfer(priv, (unsigned long)user_buf, count);
}
static
long kpc_dma_ioctl(struct file *filp, unsigned int ioctl_num, unsigned long ioctl_param)
{
struct dev_private_data *priv = (struct dev_private_data *)filp->private_data;
- dev_dbg(&priv->ldev->pldev->dev, "kpc_dma_ioctl(filp = [%p], ioctl_num = 0x%x, ioctl_param = 0x%lx) priv = [%p], ldev = [%p]\n", filp, ioctl_num, ioctl_param, priv, priv->ldev);
-
- switch (ioctl_num){
- case KND_IOCTL_SET_CARD_ADDR: priv->card_addr = ioctl_param; return priv->card_addr;
- case KND_IOCTL_SET_USER_CTL: priv->user_ctl = ioctl_param; return priv->user_ctl;
- case KND_IOCTL_SET_USER_CTL_LAST: priv->user_ctl_last = ioctl_param; return priv->user_ctl_last;
- case KND_IOCTL_GET_USER_STS: return priv->user_sts;
+
+ switch (ioctl_num) {
+ case KND_IOCTL_SET_CARD_ADDR:
+ priv->card_addr = ioctl_param; return priv->card_addr;
+ case KND_IOCTL_SET_USER_CTL:
+ priv->user_ctl = ioctl_param; return priv->user_ctl;
+ case KND_IOCTL_SET_USER_CTL_LAST:
+ priv->user_ctl_last = ioctl_param; return priv->user_ctl_last;
+ case KND_IOCTL_GET_USER_STS:
+ return priv->user_sts;
}
-
+
return -ENOTTY;
}
-
-struct file_operations kpc_dma_fops = {
+const struct file_operations kpc_dma_fops = {
.owner = THIS_MODULE,
.open = kpc_dma_open,
.release = kpc_dma_close,
.read = kpc_dma_read,
.write = kpc_dma_write,
-#ifdef CONFIG_KPC_DMA_AIO
- .aio_read = kpc_dma_aio_read,
- .aio_write = kpc_dma_aio_write,
-#endif
.unlocked_ioctl = kpc_dma_ioctl,
};
diff --git a/drivers/staging/kpc2000/kpc_dma/kpc_dma_driver.c b/drivers/staging/kpc2000/kpc_dma/kpc_dma_driver.c
index aeae58d9bc18..a05ae6d40db9 100644
--- a/drivers/staging/kpc2000/kpc_dma/kpc_dma_driver.c
+++ b/drivers/staging/kpc2000/kpc_dma/kpc_dma_driver.c
@@ -14,16 +14,16 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Matt.Sickler@daktronics.com");
#define KPC_DMA_CHAR_MAJOR UNNAMED_MAJOR
-#define KPC_DMA_NUM_MINORS 1 << MINORBITS
+#define KPC_DMA_NUM_MINORS BIT(MINORBITS)
static DEFINE_MUTEX(kpc_dma_mtx);
static int assigned_major_num;
static LIST_HEAD(kpc_dma_list);
-
/********** kpc_dma_list list management **********/
-struct kpc_dma_device * kpc_dma_lookup_device(int minor)
+struct kpc_dma_device *kpc_dma_lookup_device(int minor)
{
struct kpc_dma_device *c;
+
mutex_lock(&kpc_dma_mtx);
list_for_each_entry(c, &kpc_dma_list, list) {
if (c->pldev->id == minor) {
@@ -31,19 +31,19 @@ struct kpc_dma_device * kpc_dma_lookup_device(int minor)
}
}
c = NULL; // not-found case
- out:
+out:
mutex_unlock(&kpc_dma_mtx);
return c;
}
-void kpc_dma_add_device(struct kpc_dma_device * ldev)
+static void kpc_dma_add_device(struct kpc_dma_device *ldev)
{
mutex_lock(&kpc_dma_mtx);
list_add(&ldev->list, &kpc_dma_list);
mutex_unlock(&kpc_dma_mtx);
}
-void kpc_dma_del_device(struct kpc_dma_device * ldev)
+static void kpc_dma_del_device(struct kpc_dma_device *ldev)
{
mutex_lock(&kpc_dma_mtx);
list_del(&ldev->list);
@@ -55,11 +55,14 @@ static ssize_t show_engine_regs(struct device *dev, struct device_attribute *at
{
struct kpc_dma_device *ldev;
struct platform_device *pldev = to_platform_device(dev);
- if (!pldev) return 0;
+
+ if (!pldev)
+ return 0;
ldev = platform_get_drvdata(pldev);
- if (!ldev) return 0;
-
- return scnprintf(buf, PAGE_SIZE,
+ if (!ldev)
+ return 0;
+
+ return scnprintf(buf, PAGE_SIZE,
"EngineControlStatus = 0x%08x\n"
"RegNextDescPtr = 0x%08x\n"
"RegSWDescPtr = 0x%08x\n"
@@ -78,15 +81,14 @@ static ssize_t show_engine_regs(struct device *dev, struct device_attribute *at
ldev->desc_completed
);
}
-DEVICE_ATTR(engine_regs, 0444, show_engine_regs, NULL);
+static DEVICE_ATTR(engine_regs, 0444, show_engine_regs, NULL);
-static const struct attribute * ndd_attr_list[] = {
+static const struct attribute *ndd_attr_list[] = {
&dev_attr_engine_regs.attr,
NULL,
};
-struct class *kpc_dma_class;
-
+static struct class *kpc_dma_class;
/********** Platform Driver Functions **********/
static
@@ -95,73 +97,72 @@ int kpc_dma_probe(struct platform_device *pldev)
struct resource *r = NULL;
int rv = 0;
dev_t dev;
-
+
struct kpc_dma_device *ldev = kzalloc(sizeof(struct kpc_dma_device), GFP_KERNEL);
- if (!ldev){
- dev_err(&pldev->dev, "kpc_dma_probe: unable to kzalloc space for kpc_dma_device\n");
+
+ if (!ldev) {
+ dev_err(&pldev->dev, "%s: unable to kzalloc space for kpc_dma_device\n", __func__);
rv = -ENOMEM;
goto err_rv;
}
-
- dev_dbg(&pldev->dev, "kpc_dma_probe(pldev = [%p]) ldev = [%p]\n", pldev, ldev);
-
+
INIT_LIST_HEAD(&ldev->list);
-
+
ldev->pldev = pldev;
platform_set_drvdata(pldev, ldev);
atomic_set(&ldev->open_count, 1);
-
+
mutex_init(&ldev->sem);
lock_engine(ldev);
-
+
// Get Engine regs resource
r = platform_get_resource(pldev, IORESOURCE_MEM, 0);
- if (!r){
- dev_err(&ldev->pldev->dev, "kpc_dma_probe: didn't get the engine regs resource!\n");
+ if (!r) {
+ dev_err(&ldev->pldev->dev, "%s: didn't get the engine regs resource!\n", __func__);
rv = -ENXIO;
goto err_kfree;
}
ldev->eng_regs = ioremap_nocache(r->start, resource_size(r));
- if (!ldev->eng_regs){
- dev_err(&ldev->pldev->dev, "kpc_dma_probe: failed to ioremap engine regs!\n");
+ if (!ldev->eng_regs) {
+ dev_err(&ldev->pldev->dev, "%s: failed to ioremap engine regs!\n", __func__);
rv = -ENXIO;
goto err_kfree;
}
-
+
r = platform_get_resource(pldev, IORESOURCE_IRQ, 0);
- if (!r){
- dev_err(&ldev->pldev->dev, "kpc_dma_probe: didn't get the IRQ resource!\n");
+ if (!r) {
+ dev_err(&ldev->pldev->dev, "%s: didn't get the IRQ resource!\n", __func__);
rv = -ENXIO;
goto err_kfree;
}
ldev->irq = r->start;
-
+
// Setup miscdev struct
dev = MKDEV(assigned_major_num, pldev->id);
ldev->kpc_dma_dev = device_create(kpc_dma_class, &pldev->dev, dev, ldev, "kpc_dma%d", pldev->id);
- if (IS_ERR(ldev->kpc_dma_dev)){
- dev_err(&ldev->pldev->dev, "kpc_dma_probe: device_create failed: %d\n", rv);
+ if (IS_ERR(ldev->kpc_dma_dev)) {
+ dev_err(&ldev->pldev->dev, "%s: device_create failed: %d\n", __func__, rv);
goto err_kfree;
}
-
+
// Setup the DMA engine
rv = setup_dma_engine(ldev, 30);
- if (rv){
- dev_err(&ldev->pldev->dev, "kpc_dma_probe: failed to setup_dma_engine: %d\n", rv);
+ if (rv) {
+ dev_err(&ldev->pldev->dev, "%s: failed to setup_dma_engine: %d\n", __func__, rv);
goto err_misc_dereg;
}
-
+
// Setup the sysfs files
rv = sysfs_create_files(&(ldev->pldev->dev.kobj), ndd_attr_list);
- if (rv){
- dev_err(&ldev->pldev->dev, "kpc_dma_probe: Failed to add sysfs files: %d\n", rv);
+ if (rv) {
+ dev_err(&ldev->pldev->dev, "%s: Failed to add sysfs files: %d\n", __func__, rv);
goto err_destroy_eng;
}
-
+
kpc_dma_add_device(ldev);
-
+
return 0;
-
+
err_destroy_eng:
destroy_dma_engine(ldev);
err_misc_dereg:
@@ -176,70 +177,67 @@ static
int kpc_dma_remove(struct platform_device *pldev)
{
struct kpc_dma_device *ldev = platform_get_drvdata(pldev);
+
if (!ldev)
return -ENXIO;
-
- dev_dbg(&ldev->pldev->dev, "kpc_dma_remove(pldev = [%p]) ldev = [%p]\n", pldev, ldev);
-
+
lock_engine(ldev);
sysfs_remove_files(&(ldev->pldev->dev.kobj), ndd_attr_list);
destroy_dma_engine(ldev);
kpc_dma_del_device(ldev);
device_destroy(kpc_dma_class, MKDEV(assigned_major_num, ldev->pldev->id));
kfree(ldev);
-
+
return 0;
}
-
/********** Driver Functions **********/
-struct platform_driver kpc_dma_plat_driver_i = {
+static struct platform_driver kpc_dma_plat_driver_i = {
.probe = kpc_dma_probe,
.remove = kpc_dma_remove,
.driver = {
.name = KP_DRIVER_NAME_DMA_CONTROLLER,
- .owner = THIS_MODULE,
},
};
static
-int __init kpc_dma_driver_init(void)
+int __init kpc_dma_driver_init(void)
{
int err;
-
+
err = __register_chrdev(KPC_DMA_CHAR_MAJOR, 0, KPC_DMA_NUM_MINORS, "kpc_dma", &kpc_dma_fops);
- if (err < 0){
+ if (err < 0) {
pr_err("Can't allocate a major number (%d) for kpc_dma (err = %d)\n", KPC_DMA_CHAR_MAJOR, err);
goto fail_chrdev_register;
}
assigned_major_num = err;
-
+
kpc_dma_class = class_create(THIS_MODULE, "kpc_dma");
err = PTR_ERR(kpc_dma_class);
- if (IS_ERR(kpc_dma_class)){
+ if (IS_ERR(kpc_dma_class)) {
pr_err("Can't create class kpc_dma (err = %d)\n", err);
goto fail_class_create;
}
-
+
err = platform_driver_register(&kpc_dma_plat_driver_i);
- if (err){
+ if (err) {
pr_err("Can't register platform driver for kpc_dma (err = %d)\n", err);
goto fail_platdriver_register;
}
-
+
return err;
-
- fail_platdriver_register:
+
+fail_platdriver_register:
class_destroy(kpc_dma_class);
- fail_class_create:
+fail_class_create:
__unregister_chrdev(KPC_DMA_CHAR_MAJOR, 0, KPC_DMA_NUM_MINORS, "kpc_dma");
- fail_chrdev_register:
+fail_chrdev_register:
return err;
}
module_init(kpc_dma_driver_init);
static
-void __exit kpc_dma_driver_exit(void)
+void __exit kpc_dma_driver_exit(void)
{
platform_driver_unregister(&kpc_dma_plat_driver_i);
class_destroy(kpc_dma_class);
diff --git a/drivers/staging/kpc2000/kpc_dma/kpc_dma_driver.h b/drivers/staging/kpc2000/kpc_dma/kpc_dma_driver.h
index ef913b7496e6..4c8cc866b826 100644
--- a/drivers/staging/kpc2000/kpc_dma/kpc_dma_driver.h
+++ b/drivers/staging/kpc2000/kpc_dma/kpc_dma_driver.h
@@ -14,11 +14,9 @@
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
-#include <linux/aio.h>
#include <linux/bitops.h>
#include "../kpc.h"
-
struct kp2000_device;
struct kpc_dma_device {
struct list_head list;
@@ -27,23 +25,23 @@ struct kpc_dma_device {
struct device *kpc_dma_dev;
struct kobject kobj;
char name[16];
-
+
int dir; // DMA_FROM_DEVICE || DMA_TO_DEVICE
struct mutex sem;
unsigned int irq;
struct work_struct irq_work;
-
+
atomic_t open_count;
-
+
size_t accumulated_bytes;
u32 accumulated_flags;
-
+
// Descriptor "Pool" housekeeping
u32 desc_pool_cnt;
struct dma_pool *desc_pool;
struct kpc_dma_descriptor *desc_pool_first;
struct kpc_dma_descriptor *desc_pool_last;
-
+
struct kpc_dma_descriptor *desc_next;
struct kpc_dma_descriptor *desc_completed;
};
@@ -56,9 +54,9 @@ struct dev_private_data {
u64 user_sts;
};
-struct kpc_dma_device * kpc_dma_lookup_device(int minor);
+struct kpc_dma_device *kpc_dma_lookup_device(int minor);
-extern struct file_operations kpc_dma_fops;
+extern const struct file_operations kpc_dma_fops;
#define ENG_CAP_PRESENT 0x00000001
#define ENG_CAP_DIRECTION 0x00000002
@@ -88,9 +86,8 @@ struct aio_cb_data {
struct kpc_dma_device *ldev;
struct completion *cpl;
unsigned char flags;
- struct kiocb *kcb;
size_t len;
-
+
unsigned int page_count;
struct page **user_pages;
struct sg_table sgt;
@@ -119,10 +116,10 @@ struct kpc_dma_descriptor {
volatile u32 DescSystemAddrLS;
volatile u32 DescSystemAddrMS;
volatile u32 DescNextDescPtr;
-
+
dma_addr_t MyDMAAddr;
struct kpc_dma_descriptor *Next;
-
+
struct aio_cb_data *acd;
} __attribute__((packed));
// DescControlFlags:
@@ -157,35 +154,41 @@ void WriteEngineControl(struct kpc_dma_device *eng, u32 value)
{
writel(value, eng->eng_regs + 1);
}
+
static inline
u32 GetEngineControl(struct kpc_dma_device *eng)
{
return readl(eng->eng_regs + 1);
}
+
static inline
void SetClearEngineControl(struct kpc_dma_device *eng, u32 set_bits, u32 clear_bits)
{
u32 val = GetEngineControl(eng);
+
val |= set_bits;
val &= ~clear_bits;
WriteEngineControl(eng, val);
}
static inline
-void SetEngineNextPtr(struct kpc_dma_device *eng, struct kpc_dma_descriptor * desc)
+void SetEngineNextPtr(struct kpc_dma_device *eng, struct kpc_dma_descriptor *desc)
{
writel(desc->MyDMAAddr, eng->eng_regs + 2);
}
+
static inline
-void SetEngineSWPtr(struct kpc_dma_device *eng, struct kpc_dma_descriptor * desc)
+void SetEngineSWPtr(struct kpc_dma_device *eng, struct kpc_dma_descriptor *desc)
{
writel(desc->MyDMAAddr, eng->eng_regs + 3);
}
+
static inline
void ClearEngineCompletePtr(struct kpc_dma_device *eng)
{
writel(0, eng->eng_regs + 4);
}
+
static inline
u32 GetEngineCompletePtr(struct kpc_dma_device *eng)
{
@@ -206,7 +209,6 @@ void unlock_engine(struct kpc_dma_device *eng)
mutex_unlock(&eng->sem);
}
-
/// Shared Functions
void start_dma_engine(struct kpc_dma_device *eng);
int setup_dma_engine(struct kpc_dma_device *eng, u32 desc_cnt);
diff --git a/drivers/staging/kpc2000/kpc_i2c/Makefile b/drivers/staging/kpc2000/kpc_i2c/Makefile
deleted file mode 100644
index 73ec07ac7d39..000000000000
--- a/drivers/staging/kpc2000/kpc_i2c/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-obj-m := kpc2000_i2c.o
-kpc2000_i2c-objs := i2c_driver.o fileops.o
diff --git a/drivers/staging/kpc2000/kpc_i2c/fileops.c b/drivers/staging/kpc2000/kpc_i2c/fileops.c
deleted file mode 100644
index e749c0994491..000000000000
--- a/drivers/staging/kpc2000/kpc_i2c/fileops.c
+++ /dev/null
@@ -1,181 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-#if 0
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h> /* printk() */
-#include <linux/slab.h> /* kmalloc() */
-#include <linux/fs.h> /* everything... */
-#include <linux/errno.h> /* error codes */
-#include <linux/types.h> /* size_t */
-#include <linux/cdev.h>
-#include <asm/uaccess.h> /* copy_*_user */
-
-#include "i2c_driver.h"
-
-int i2c_cdev_open(struct inode *inode, struct file *filp)
-{
- struct i2c_device *lddev;
-
- if(NULL == inode) {
- //printk(KERN_WARNING "<pl_i2c> i2c_cdev_open: inode is a NULL pointer\n");
- DBG_PRINT(KERN_WARNING, "i2c_cdev_open: inode is a NULL pointer\n");
- return -EINVAL;
- }
- if(NULL == filp) {
- //printk(KERN_WARNING "<pl_i2c> i2c_cdev_open: filp is a NULL pointer\n");
- DBG_PRINT(KERN_WARNING, "i2c_cdev_open: filp is a NULL pointer\n");
- return -EINVAL;
- }
-
- lddev = container_of(inode->i_cdev, struct i2c_device, cdev);
- //printk(KERN_DEBUG "<pl_i2c> i2c_cdev_open(filp = [%p], lddev = [%p])\n", filp, lddev);
- DBG_PRINT(KERN_DEBUG, "i2c_cdev_open(filp = [%p], lddev = [%p])\n", filp, lddev);
-
- filp->private_data = lddev; /* so other methods can access it */
-
- return 0; /* success */
-}
-
-int i2c_cdev_close(struct inode *inode, struct file *filp)
-{
- struct i2c_device *lddev;
-
- if(NULL == inode) {
- //printk(KERN_WARNING "<pl_i2c> i2c_cdev_close: inode is a NULL pointer\n");
- DBG_PRINT(KERN_WARNING, "i2c_cdev_close: inode is a NULL pointer\n");
- return -EINVAL;
- }
- if(NULL == filp) {
- //printk(KERN_WARNING "<pl_i2c> i2c_cdev_close: filp is a NULL pointer\n");
- DBG_PRINT(KERN_WARNING, "i2c_cdev_close: filp is a NULL pointer\n");
- return -EINVAL;
- }
-
- lddev = filp->private_data;
- //printk(KERN_DEBUG "<pl_i2c> i2c_cdev_close(filp = [%p], lddev = [%p])\n", filp, lddev);
- DBG_PRINT(KERN_DEBUG, "i2c_cdev_close(filp = [%p], lddev = [%p])\n", filp, lddev);
-
- return 0;
-}
-
-ssize_t i2c_cdev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
-{
- size_t copy;
- ssize_t ret = 0;
- int err = 0;
- u64 read_val;
- char tmp_buf[48] = { 0 };
- struct i2c_device *lddev = filp->private_data;
-
- if(NULL == filp) {
- //printk(KERN_WARNING "<pl_i2c> i2c_cdev_read: filp is a NULL pointer\n");
- DBG_PRINT(KERN_WARNING, "i2c_cdev_read: filp is a NULL pointer\n");
- return -EINVAL;
- }
- if(NULL == buf) {
- //printk(KERN_WARNING "<pl_i2c> i2c_cdev_read: buf is a NULL pointer\n");
- DBG_PRINT(KERN_WARNING, "i2c_cdev_read: buf is a NULL pointer\n");
- return -EINVAL;
- }
- if(NULL == f_pos) {
- //printk(KERN_WARNING "<pl_i2c> i2c_cdev_read: f_pos is a NULL pointer\n");
- DBG_PRINT(KERN_WARNING, "i2c_cdev_read: f_pos is a NULL pointer\n");
- return -EINVAL;
- }
-
- if(count < sizeof(tmp_buf)) {
- //printk(KERN_INFO "<pl_i2c> i2c_cdev_read: buffer is too small (count = %d, should be at least %d bytes)\n", (int)count, (int)sizeof(tmp_buf));
- DBG_PRINT(KERN_INFO, "i2c_cdev_read: buffer is too small (count = %d, should be at least %d bytes)\n", (int)count, (int)sizeof(tmp_buf));
- return -EINVAL;
- }
- if(((*f_pos * 8) + lddev->pldev->resource[0].start) > lddev->pldev->resource[0].end) {
- //printk(KERN_INFO "<pl_i2c> i2c_cdev_read: bad read addr %016llx\n", (*f_pos * 8) + lddev->pldev->resource[0].start);
- DBG_PRINT(KERN_INFO, "i2c_cdev_read: bad read addr %016llx\n", (*f_pos * 8) + lddev->pldev->resource[0].start);
- //printk(KERN_INFO "<pl_i2c> i2c_cdev_read: addr end %016llx\n", lddev->pldev->resource[0].end);
- DBG_PRINT(KERN_INFO, "i2c_cdev_read: addr end %016llx\n", lddev->pldev->resource[0].end);
- //printk(KERN_INFO "<pl_i2c> i2c_cdev_read: EOF reached\n");
- DBG_PRINT(KERN_INFO, "i2c_cdev_read: EOF reached\n");
- return 0;
- }
-
- down_read(&lddev->rw_sem);
-
- read_val = *(lddev->regs + *f_pos);
- copy = clamp_t(size_t, count, 1, sizeof(tmp_buf));
- copy = scnprintf(tmp_buf, copy, "reg: 0x%x val: 0x%llx\n", (unsigned int)*f_pos, read_val);
- err = copy_to_user(buf, tmp_buf, copy);
- if(err) {
- //printk(KERN_INFO "<pl_i2c> i2c_cdev_read: could not copy to user (err = %d)\n", err);
- DBG_PRINT(KERN_INFO, "i2c_cdev_read: could not copy to user (err = %d)\n", err);
- return -EINVAL;
- }
-
- ret = (ssize_t)copy;
- (*f_pos)++;
-
- up_read(&lddev->rw_sem);
-
- return ret;
-}
-
-ssize_t i2c_cdev_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
-{
- u8 reg;
- u8 val;
- char tmp[8] = { 0 };
- struct i2c_device *lddev = filp->private_data;
-
- if(NULL == filp) {
- //printk(KERN_WARNING "<pl_i2c> i2c_cdev_write: filp is a NULL pointer\n");
- DBG_PRINT(KERN_WARNING, "i2c_cdev_write: filp is a NULL pointer\n");
- return -EINVAL;
- }
- if(NULL == buf) {
- //printk(KERN_WARNING "<pl_i2c> i2c_cdev_write: buf is a NULL pointer\n");
- DBG_PRINT(KERN_WARNING, "i2c_cdev_write: buf is a NULL pointer\n");
- return -EINVAL;
- }
- if(NULL == f_pos) {
- //printk(KERN_WARNING "<pl_i2c> i2c_cdev_write: f_pos is a NULL pointer\n");
- DBG_PRINT(KERN_WARNING, "i2c_cdev_write: f_pos is a NULL pointer\n");
- return -EINVAL;
- }
-
- //printk(KERN_DEBUG "<pl_i2c> i2c_cdev_write(filp = [%p], lddev = [%p])\n", filp, lddev);
- DBG_PRINT(KERN_DEBUG, "i2c_cdev_write(filp = [%p], lddev = [%p])\n", filp, lddev);
-
- down_write(&lddev->rw_sem);
-
- if(count >= 2) {
- if(copy_from_user(tmp, buf, 2)) {
- return -EFAULT;
- }
-
- reg = tmp[0] - '0';
- val = tmp[1] - '0';
-
- //printk(KERN_DEBUG " reg = %d val = %d\n", reg, val);
- DBG_PRINT(KERN_DEBUG, " reg = %d val = %d\n", reg, val);
-
- if(reg >= 0 && reg < 16) {
- //printk(KERN_DEBUG " Writing 0x%x to %p\n", val, lddev->regs + reg);
- DBG_PRINT(KERN_DEBUG, " Writing 0x%x to %p\n", val, lddev->regs + reg);
- *(lddev->regs + reg) = val;
- }
- }
-
- (*f_pos)++;
-
- up_write(&lddev->rw_sem);
-
- return count;
-}
-
-struct file_operations i2c_fops = {
- .owner = THIS_MODULE,
- .open = i2c_cdev_open,
- .release = i2c_cdev_close,
- .read = i2c_cdev_read,
- .write = i2c_cdev_write,
-};
-#endif
diff --git a/drivers/staging/kpc2000/kpc_i2c/i2c_driver.c b/drivers/staging/kpc2000/kpc_i2c/i2c_driver.c
deleted file mode 100644
index 0fb068b2408d..000000000000
--- a/drivers/staging/kpc2000/kpc_i2c/i2c_driver.c
+++ /dev/null
@@ -1,699 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/* Copyright (c) 2014-2018 Daktronics,
- Matt Sickler <matt.sickler@daktronics.com>,
- Jordon Hofer <jordon.hofer@daktronics.com>
- Adapted i2c-i801.c for use with Kadoka hardware.
- Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>,
- Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker
- <mdsxyz123@yahoo.com>
- Copyright (C) 2007 - 2012 Jean Delvare <khali@linux-fr.org>
- Copyright (C) 2010 Intel Corporation,
- David Woodhouse <dwmw2@infradead.org>
-*/
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <asm/io.h>
-#include <linux/io-64-nonatomic-lo-hi.h>
-#include <linux/export.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <linux/fs.h>
-#include <linux/rwsem.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include "../kpc.h"
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Matt.Sickler@Daktronics.com");
-MODULE_SOFTDEP("pre: i2c-dev");
-
-struct i2c_device {
- unsigned long smba;
- struct i2c_adapter adapter;
- struct platform_device *pldev;
- struct rw_semaphore rw_sem;
- unsigned int features;
-};
-
-/*****************************
- *** Part 1 - i2c Handlers ***
- *****************************/
-
-#define REG_SIZE 8
-
-/* I801 SMBus address offsets */
-#define SMBHSTSTS(p) ((0 * REG_SIZE) + (p)->smba)
-#define SMBHSTCNT(p) ((2 * REG_SIZE) + (p)->smba)
-#define SMBHSTCMD(p) ((3 * REG_SIZE) + (p)->smba)
-#define SMBHSTADD(p) ((4 * REG_SIZE) + (p)->smba)
-#define SMBHSTDAT0(p) ((5 * REG_SIZE) + (p)->smba)
-#define SMBHSTDAT1(p) ((6 * REG_SIZE) + (p)->smba)
-#define SMBBLKDAT(p) ((7 * REG_SIZE) + (p)->smba)
-#define SMBPEC(p) ((8 * REG_SIZE) + (p)->smba) /* ICH3 and later */
-#define SMBAUXSTS(p) ((12 * REG_SIZE) + (p)->smba) /* ICH4 and later */
-#define SMBAUXCTL(p) ((13 * REG_SIZE) + (p)->smba) /* ICH4 and later */
-
-/* PCI Address Constants */
-#define SMBBAR 4
-#define SMBHSTCFG 0x040
-
-/* Host configuration bits for SMBHSTCFG */
-#define SMBHSTCFG_HST_EN 1
-#define SMBHSTCFG_SMB_SMI_EN 2
-#define SMBHSTCFG_I2C_EN 4
-
-/* Auxiliary control register bits, ICH4+ only */
-#define SMBAUXCTL_CRC 1
-#define SMBAUXCTL_E32B 2
-
-/* kill bit for SMBHSTCNT */
-#define SMBHSTCNT_KILL 2
-
-/* Other settings */
-#define MAX_RETRIES 400
-#define ENABLE_INT9 0 /* set to 0x01 to enable - untested */
-
-/* I801 command constants */
-#define I801_QUICK 0x00
-#define I801_BYTE 0x04
-#define I801_BYTE_DATA 0x08
-#define I801_WORD_DATA 0x0C
-#define I801_PROC_CALL 0x10 /* unimplemented */
-#define I801_BLOCK_DATA 0x14
-#define I801_I2C_BLOCK_DATA 0x18 /* ICH5 and later */
-#define I801_BLOCK_LAST 0x34
-#define I801_I2C_BLOCK_LAST 0x38 /* ICH5 and later */
-#define I801_START 0x40
-#define I801_PEC_EN 0x80 /* ICH3 and later */
-
-/* I801 Hosts Status register bits */
-#define SMBHSTSTS_BYTE_DONE 0x80
-#define SMBHSTSTS_INUSE_STS 0x40
-#define SMBHSTSTS_SMBALERT_STS 0x20
-#define SMBHSTSTS_FAILED 0x10
-#define SMBHSTSTS_BUS_ERR 0x08
-#define SMBHSTSTS_DEV_ERR 0x04
-#define SMBHSTSTS_INTR 0x02
-#define SMBHSTSTS_HOST_BUSY 0x01
-
-#define STATUS_FLAGS (SMBHSTSTS_BYTE_DONE | SMBHSTSTS_FAILED | SMBHSTSTS_BUS_ERR | SMBHSTSTS_DEV_ERR | SMBHSTSTS_INTR)
-
-/* Older devices have their ID defined in <linux/pci_ids.h> */
-#define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22
-#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS 0x1d22
-/* Patsburg also has three 'Integrated Device Function' SMBus controllers */
-#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0 0x1d70
-#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1 0x1d71
-#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2 0x1d72
-#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS 0x1e22
-#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330
-#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30
-#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22
-#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS 0x9c22
-
-
-#define FEATURE_SMBUS_PEC (1 << 0)
-#define FEATURE_BLOCK_BUFFER (1 << 1)
-#define FEATURE_BLOCK_PROC (1 << 2)
-#define FEATURE_I2C_BLOCK_READ (1 << 3)
-/* Not really a feature, but it's convenient to handle it as such */
-#define FEATURE_IDF (1 << 15)
-
-static unsigned int disable_features;
-module_param(disable_features, uint, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(disable_features, "Disable selected driver features");
-
-// FIXME!
-#undef inb_p
-#define inb_p(a) readq((void*)a)
-#undef outb_p
-#define outb_p(d,a) writeq(d,(void*)a)
-
-/* Make sure the SMBus host is ready to start transmitting.
- Return 0 if it is, -EBUSY if it is not. */
-static int i801_check_pre(struct i2c_device *priv)
-{
- int status;
-
- dev_dbg(&priv->adapter.dev, "i801_check_pre\n");
-
- status = inb_p(SMBHSTSTS(priv));
- if (status & SMBHSTSTS_HOST_BUSY) {
- dev_err(&priv->adapter.dev, "SMBus is busy, can't use it! (status=%x)\n", status);
- return -EBUSY;
- }
-
- status &= STATUS_FLAGS;
- if (status) {
- //dev_dbg(&priv->adapter.dev, "Clearing status flags (%02x)\n", status);
- outb_p(status, SMBHSTSTS(priv));
- status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS;
- if (status) {
- dev_err(&priv->adapter.dev, "Failed clearing status flags (%02x)\n", status);
- return -EBUSY;
- }
- }
- return 0;
-}
-
-/* Convert the status register to an error code, and clear it. */
-static int i801_check_post(struct i2c_device *priv, int status, int timeout)
-{
- int result = 0;
-
- dev_dbg(&priv->adapter.dev, "i801_check_post\n");
-
- /* If the SMBus is still busy, we give up */
- if (timeout) {
- dev_err(&priv->adapter.dev, "Transaction timeout\n");
- /* try to stop the current command */
- dev_dbg(&priv->adapter.dev, "Terminating the current operation\n");
- outb_p(inb_p(SMBHSTCNT(priv)) | SMBHSTCNT_KILL, SMBHSTCNT(priv));
- usleep_range(1000, 2000);
- outb_p(inb_p(SMBHSTCNT(priv)) & (~SMBHSTCNT_KILL), SMBHSTCNT(priv));
-
- /* Check if it worked */
- status = inb_p(SMBHSTSTS(priv));
- if ((status & SMBHSTSTS_HOST_BUSY) || !(status & SMBHSTSTS_FAILED)) {
- dev_err(&priv->adapter.dev, "Failed terminating the transaction\n");
- }
- outb_p(STATUS_FLAGS, SMBHSTSTS(priv));
- return -ETIMEDOUT;
- }
-
- if (status & SMBHSTSTS_FAILED) {
- result = -EIO;
- dev_err(&priv->adapter.dev, "Transaction failed\n");
- }
- if (status & SMBHSTSTS_DEV_ERR) {
- result = -ENXIO;
- dev_dbg(&priv->adapter.dev, "No response\n");
- }
- if (status & SMBHSTSTS_BUS_ERR) {
- result = -EAGAIN;
- dev_dbg(&priv->adapter.dev, "Lost arbitration\n");
- }
-
- if (result) {
- /* Clear error flags */
- outb_p(status & STATUS_FLAGS, SMBHSTSTS(priv));
- status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS;
- if (status) {
- dev_warn(&priv->adapter.dev, "Failed clearing status flags at end of transaction (%02x)\n", status);
- }
- }
-
- return result;
-}
-
-static int i801_transaction(struct i2c_device *priv, int xact)
-{
- int status;
- int result;
- int timeout = 0;
-
- dev_dbg(&priv->adapter.dev, "i801_transaction\n");
-
- result = i801_check_pre(priv);
- if (result < 0) {
- return result;
- }
- /* the current contents of SMBHSTCNT can be overwritten, since PEC,
- * INTREN, SMBSCMD are passed in xact */
- outb_p(xact | I801_START, SMBHSTCNT(priv));
-
- /* We will always wait for a fraction of a second! */
- do {
- usleep_range(250, 500);
- status = inb_p(SMBHSTSTS(priv));
- } while ((status & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_RETRIES));
-
- result = i801_check_post(priv, status, timeout > MAX_RETRIES);
- if (result < 0) {
- return result;
- }
-
- outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv));
- return 0;
-}
-
-/* wait for INTR bit as advised by Intel */
-static void i801_wait_hwpec(struct i2c_device *priv)
-{
- int timeout = 0;
- int status;
-
- dev_dbg(&priv->adapter.dev, "i801_wait_hwpec\n");
-
- do {
- usleep_range(250, 500);
- status = inb_p(SMBHSTSTS(priv));
- } while ((!(status & SMBHSTSTS_INTR)) && (timeout++ < MAX_RETRIES));
-
- if (timeout > MAX_RETRIES) {
- dev_dbg(&priv->adapter.dev, "PEC Timeout!\n");
- }
-
- outb_p(status, SMBHSTSTS(priv));
-}
-
-static int i801_block_transaction_by_block(struct i2c_device *priv, union i2c_smbus_data *data, char read_write, int hwpec)
-{
- int i, len;
- int status;
-
- dev_dbg(&priv->adapter.dev, "i801_block_transaction_by_block\n");
-
- inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */
-
- /* Use 32-byte buffer to process this transaction */
- if (read_write == I2C_SMBUS_WRITE) {
- len = data->block[0];
- outb_p(len, SMBHSTDAT0(priv));
- for (i = 0; i < len; i++) {
- outb_p(data->block[i+1], SMBBLKDAT(priv));
- }
- }
-
- status = i801_transaction(priv, I801_BLOCK_DATA | ENABLE_INT9 | I801_PEC_EN * hwpec);
- if (status) {
- return status;
- }
-
- if (read_write == I2C_SMBUS_READ) {
- len = inb_p(SMBHSTDAT0(priv));
- if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) {
- return -EPROTO;
- }
-
- data->block[0] = len;
- for (i = 0; i < len; i++) {
- data->block[i + 1] = inb_p(SMBBLKDAT(priv));
- }
- }
- return 0;
-}
-
-static int i801_block_transaction_byte_by_byte(struct i2c_device *priv, union i2c_smbus_data *data, char read_write, int command, int hwpec)
-{
- int i, len;
- int smbcmd;
- int status;
- int result;
- int timeout;
-
- dev_dbg(&priv->adapter.dev, "i801_block_transaction_byte_by_byte\n");
-
- result = i801_check_pre(priv);
- if (result < 0) {
- return result;
- }
-
- len = data->block[0];
-
- if (read_write == I2C_SMBUS_WRITE) {
- outb_p(len, SMBHSTDAT0(priv));
- outb_p(data->block[1], SMBBLKDAT(priv));
- }
-
- for (i = 1; i <= len; i++) {
- if (i == len && read_write == I2C_SMBUS_READ) {
- if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
- smbcmd = I801_I2C_BLOCK_LAST;
- } else {
- smbcmd = I801_BLOCK_LAST;
- }
- } else {
- if (command == I2C_SMBUS_I2C_BLOCK_DATA && read_write == I2C_SMBUS_READ) {
- smbcmd = I801_I2C_BLOCK_DATA;
- } else {
- smbcmd = I801_BLOCK_DATA;
- }
- }
- outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT(priv));
-
- if (i == 1) {
- outb_p(inb(SMBHSTCNT(priv)) | I801_START, SMBHSTCNT(priv));
- }
- /* We will always wait for a fraction of a second! */
- timeout = 0;
- do {
- usleep_range(250, 500);
- status = inb_p(SMBHSTSTS(priv));
- } while ((!(status & SMBHSTSTS_BYTE_DONE)) && (timeout++ < MAX_RETRIES));
-
- result = i801_check_post(priv, status, timeout > MAX_RETRIES);
- if (result < 0) {
- return result;
- }
- if (i == 1 && read_write == I2C_SMBUS_READ && command != I2C_SMBUS_I2C_BLOCK_DATA) {
- len = inb_p(SMBHSTDAT0(priv));
- if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) {
- dev_err(&priv->adapter.dev, "Illegal SMBus block read size %d\n", len);
- /* Recover */
- while (inb_p(SMBHSTSTS(priv)) & SMBHSTSTS_HOST_BUSY) {
- outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv));
- }
- outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv));
- return -EPROTO;
- }
- data->block[0] = len;
- }
-
- /* Retrieve/store value in SMBBLKDAT */
- if (read_write == I2C_SMBUS_READ) {
- data->block[i] = inb_p(SMBBLKDAT(priv));
- }
- if (read_write == I2C_SMBUS_WRITE && i+1 <= len) {
- outb_p(data->block[i+1], SMBBLKDAT(priv));
- }
- /* signals SMBBLKDAT ready */
- outb_p(SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR, SMBHSTSTS(priv));
- }
-
- return 0;
-}
-
-static int i801_set_block_buffer_mode(struct i2c_device *priv)
-{
- dev_dbg(&priv->adapter.dev, "i801_set_block_buffer_mode\n");
-
- outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv));
- if ((inb_p(SMBAUXCTL(priv)) & SMBAUXCTL_E32B) == 0) {
- return -EIO;
- }
- return 0;
-}
-
-/* Block transaction function */
-static int i801_block_transaction(struct i2c_device *priv, union i2c_smbus_data *data, char read_write, int command, int hwpec)
-{
- int result = 0;
- //unsigned char hostc;
-
- dev_dbg(&priv->adapter.dev, "i801_block_transaction\n");
-
- if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
- if (read_write == I2C_SMBUS_WRITE) {
- /* set I2C_EN bit in configuration register */
- //TODO: Figure out the right thing to do here...
- //pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &hostc);
- //pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc | SMBHSTCFG_I2C_EN);
- } else if (!(priv->features & FEATURE_I2C_BLOCK_READ)) {
- dev_err(&priv->adapter.dev, "I2C block read is unsupported!\n");
- return -EOPNOTSUPP;
- }
- }
-
- if (read_write == I2C_SMBUS_WRITE || command == I2C_SMBUS_I2C_BLOCK_DATA) {
- if (data->block[0] < 1) {
- data->block[0] = 1;
- }
- if (data->block[0] > I2C_SMBUS_BLOCK_MAX) {
- data->block[0] = I2C_SMBUS_BLOCK_MAX;
- }
- } else {
- data->block[0] = 32; /* max for SMBus block reads */
- }
-
- /* Experience has shown that the block buffer can only be used for
- SMBus (not I2C) block transactions, even though the datasheet
- doesn't mention this limitation. */
- if ((priv->features & FEATURE_BLOCK_BUFFER) && command != I2C_SMBUS_I2C_BLOCK_DATA && i801_set_block_buffer_mode(priv) == 0) {
- result = i801_block_transaction_by_block(priv, data, read_write, hwpec);
- } else {
- result = i801_block_transaction_byte_by_byte(priv, data, read_write, command, hwpec);
- }
- if (result == 0 && hwpec) {
- i801_wait_hwpec(priv);
- }
- if (command == I2C_SMBUS_I2C_BLOCK_DATA && read_write == I2C_SMBUS_WRITE) {
- /* restore saved configuration register value */
- //TODO: Figure out the right thing to do here...
- //pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc);
- }
- return result;
-}
-
-/* Return negative errno on error. */
-static s32 i801_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data)
-{
- int hwpec;
- int block = 0;
- int ret, xact = 0;
- struct i2c_device *priv = i2c_get_adapdata(adap);
-
- dev_dbg(&priv->adapter.dev, "i801_access (addr=%0d) flags=%x read_write=%x command=%x size=%x",
- addr, flags, read_write, command, size );
-
- hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA;
-
- switch (size) {
- case I2C_SMBUS_QUICK:
- dev_dbg(&priv->adapter.dev, " [acc] SMBUS_QUICK\n");
- outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD(priv));
- xact = I801_QUICK;
- break;
- case I2C_SMBUS_BYTE:
- dev_dbg(&priv->adapter.dev, " [acc] SMBUS_BYTE\n");
-
- outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD(priv));
- if (read_write == I2C_SMBUS_WRITE) {
- outb_p(command, SMBHSTCMD(priv));
- }
- xact = I801_BYTE;
- break;
- case I2C_SMBUS_BYTE_DATA:
- dev_dbg(&priv->adapter.dev, " [acc] SMBUS_BYTE_DATA\n");
- outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD(priv));
- outb_p(command, SMBHSTCMD(priv));
- if (read_write == I2C_SMBUS_WRITE) {
- outb_p(data->byte, SMBHSTDAT0(priv));
- }
- xact = I801_BYTE_DATA;
- break;
- case I2C_SMBUS_WORD_DATA:
- dev_dbg(&priv->adapter.dev, " [acc] SMBUS_WORD_DATA\n");
- outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD(priv));
- outb_p(command, SMBHSTCMD(priv));
- if (read_write == I2C_SMBUS_WRITE) {
- outb_p(data->word & 0xff, SMBHSTDAT0(priv));
- outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv));
- }
- xact = I801_WORD_DATA;
- break;
- case I2C_SMBUS_BLOCK_DATA:
- dev_dbg(&priv->adapter.dev, " [acc] SMBUS_BLOCK_DATA\n");
- outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD(priv));
- outb_p(command, SMBHSTCMD(priv));
- block = 1;
- break;
- case I2C_SMBUS_I2C_BLOCK_DATA:
- dev_dbg(&priv->adapter.dev, " [acc] SMBUS_I2C_BLOCK_DATA\n");
- /* NB: page 240 of ICH5 datasheet shows that the R/#W
- * bit should be cleared here, even when reading */
- outb_p((addr & 0x7f) << 1, SMBHSTADD(priv));
- if (read_write == I2C_SMBUS_READ) {
- /* NB: page 240 of ICH5 datasheet also shows
- * that DATA1 is the cmd field when reading */
- outb_p(command, SMBHSTDAT1(priv));
- } else {
- outb_p(command, SMBHSTCMD(priv));
- }
- block = 1;
- break;
- default:
- dev_dbg(&priv->adapter.dev, " [acc] Unsupported transaction %d\n", size);
- return -EOPNOTSUPP;
- }
-
- if (hwpec) { /* enable/disable hardware PEC */
- dev_dbg(&priv->adapter.dev, " [acc] hwpec: yes\n");
- outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_CRC, SMBAUXCTL(priv));
- } else {
- dev_dbg(&priv->adapter.dev, " [acc] hwpec: no\n");
- outb_p(inb_p(SMBAUXCTL(priv)) & (~SMBAUXCTL_CRC), SMBAUXCTL(priv));
- }
-
- if (block) {
- //ret = 0;
- dev_dbg(&priv->adapter.dev, " [acc] block: yes\n");
- ret = i801_block_transaction(priv, data, read_write, size, hwpec);
- } else {
- dev_dbg(&priv->adapter.dev, " [acc] block: no\n");
- ret = i801_transaction(priv, xact | ENABLE_INT9);
- }
-
- /* Some BIOSes don't like it when PEC is enabled at reboot or resume
- time, so we forcibly disable it after every transaction. Turn off
- E32B for the same reason. */
- if (hwpec || block) {
- dev_dbg(&priv->adapter.dev, " [acc] hwpec || block\n");
- outb_p(inb_p(SMBAUXCTL(priv)) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
- }
- if (block) {
- dev_dbg(&priv->adapter.dev, " [acc] block\n");
- return ret;
- }
- if (ret) {
- dev_dbg(&priv->adapter.dev, " [acc] ret %d\n", ret);
- return ret;
- }
- if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK)) {
- dev_dbg(&priv->adapter.dev, " [acc] I2C_SMBUS_WRITE || I801_QUICK -> ret 0\n");
- return 0;
- }
-
- switch (xact & 0x7f) {
- case I801_BYTE: /* Result put in SMBHSTDAT0 */
- case I801_BYTE_DATA:
- dev_dbg(&priv->adapter.dev, " [acc] I801_BYTE or I801_BYTE_DATA\n");
- data->byte = inb_p(SMBHSTDAT0(priv));
- break;
- case I801_WORD_DATA:
- dev_dbg(&priv->adapter.dev, " [acc] I801_WORD_DATA\n");
- data->word = inb_p(SMBHSTDAT0(priv)) + (inb_p(SMBHSTDAT1(priv)) << 8);
- break;
- }
- return 0;
-}
-
-
-
-static u32 i801_func(struct i2c_adapter *adapter)
-{
- struct i2c_device *priv = i2c_get_adapdata(adapter);
-
- /* original settings
- u32 f = I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
- I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
- I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK |
- ((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) |
- ((priv->features & FEATURE_I2C_BLOCK_READ) ?
- I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0);
- */
-
- // http://lxr.free-electrons.com/source/include/uapi/linux/i2c.h#L85
-
- u32 f =
- I2C_FUNC_I2C | /* 0x00000001 (I enabled this one) */
- !I2C_FUNC_10BIT_ADDR | /* 0x00000002 */
- !I2C_FUNC_PROTOCOL_MANGLING | /* 0x00000004 */
- ((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) | /* 0x00000008 */
- !I2C_FUNC_SMBUS_BLOCK_PROC_CALL | /* 0x00008000 */
- I2C_FUNC_SMBUS_QUICK | /* 0x00010000 */
- !I2C_FUNC_SMBUS_READ_BYTE | /* 0x00020000 */
- !I2C_FUNC_SMBUS_WRITE_BYTE | /* 0x00040000 */
- !I2C_FUNC_SMBUS_READ_BYTE_DATA | /* 0x00080000 */
- !I2C_FUNC_SMBUS_WRITE_BYTE_DATA | /* 0x00100000 */
- !I2C_FUNC_SMBUS_READ_WORD_DATA | /* 0x00200000 */
- !I2C_FUNC_SMBUS_WRITE_WORD_DATA | /* 0x00400000 */
- !I2C_FUNC_SMBUS_PROC_CALL | /* 0x00800000 */
- !I2C_FUNC_SMBUS_READ_BLOCK_DATA | /* 0x01000000 */
- !I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | /* 0x02000000 */
- ((priv->features & FEATURE_I2C_BLOCK_READ) ? I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0) | /* 0x04000000 */
- I2C_FUNC_SMBUS_WRITE_I2C_BLOCK | /* 0x08000000 */
-
- I2C_FUNC_SMBUS_BYTE | /* _READ_BYTE _WRITE_BYTE */
- I2C_FUNC_SMBUS_BYTE_DATA | /* _READ_BYTE_DATA _WRITE_BYTE_DATA */
- I2C_FUNC_SMBUS_WORD_DATA | /* _READ_WORD_DATA _WRITE_WORD_DATA */
- I2C_FUNC_SMBUS_BLOCK_DATA | /* _READ_BLOCK_DATA _WRITE_BLOCK_DATA */
- !I2C_FUNC_SMBUS_I2C_BLOCK | /* _READ_I2C_BLOCK _WRITE_I2C_BLOCK */
- !I2C_FUNC_SMBUS_EMUL; /* _QUICK _BYTE _BYTE_DATA _WORD_DATA _PROC_CALL _WRITE_BLOCK_DATA _I2C_BLOCK _PEC */
- return f;
-}
-
-static const struct i2c_algorithm smbus_algorithm = {
- .smbus_xfer = i801_access,
- .functionality = i801_func,
-};
-
-
-
-/********************************
- *** Part 2 - Driver Handlers ***
- ********************************/
-int pi2c_probe(struct platform_device *pldev)
-{
- int err;
- struct i2c_device *priv;
- struct resource *res;
-
- dev_dbg(&pldev->dev, "pi2c_probe(pldev = %p '%s')\n", pldev, pldev->name);
-
- priv = kzalloc(sizeof(struct i2c_device), GFP_KERNEL);
- if (!priv) {
- return -ENOMEM;
- }
-
- i2c_set_adapdata(&priv->adapter, priv);
- priv->adapter.owner = THIS_MODULE;
- priv->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
- priv->adapter.algo = &smbus_algorithm;
-
- res = platform_get_resource(pldev, IORESOURCE_MEM, 0);
- priv->smba = (unsigned long)ioremap_nocache(res->start, resource_size(res));
-
- priv->pldev = pldev;
- pldev->dev.platform_data = priv;
-
- priv->features |= FEATURE_IDF;
- priv->features |= FEATURE_I2C_BLOCK_READ;
- priv->features |= FEATURE_SMBUS_PEC;
- priv->features |= FEATURE_BLOCK_BUFFER;
-
- //init_MUTEX(&lddata->sem);
- init_rwsem(&priv->rw_sem);
-
- /* set up the sysfs linkage to our parent device */
- priv->adapter.dev.parent = &pldev->dev;
-
- /* Retry up to 3 times on lost arbitration */
- priv->adapter.retries = 3;
-
- //snprintf(priv->adapter.name, sizeof(priv->adapter.name), "Fake SMBus I801 adapter at %04lx", priv->smba);
- snprintf(priv->adapter.name, sizeof(priv->adapter.name), "Fake SMBus I801 adapter");
-
- err = i2c_add_adapter(&priv->adapter);
- if (err) {
- dev_err(&priv->adapter.dev, "Failed to add SMBus adapter\n");
- return err;
- }
-
- return 0;
-}
-
-int pi2c_remove(struct platform_device *pldev)
-{
- struct i2c_device *lddev;
- dev_dbg(&pldev->dev, "pi2c_remove(pldev = %p '%s')\n", pldev, pldev->name);
-
- lddev = (struct i2c_device *)pldev->dev.platform_data;
-
- i2c_del_adapter(&lddev->adapter);
-
- //TODO: Figure out the right thing to do here...
- //pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
- //pci_release_region(dev, SMBBAR);
- //pci_set_drvdata(dev, NULL);
-
- //cdev_del(&lddev->cdev);
- if(lddev != 0) {
- kfree(lddev);
- pldev->dev.platform_data = 0;
- }
-
- return 0;
-}
-
-struct platform_driver i2c_plat_driver_i = {
- .probe = pi2c_probe,
- .remove = pi2c_remove,
- .driver = {
- .name = KP_DRIVER_NAME_I2C,
- .owner = THIS_MODULE,
- },
-};
-
-module_platform_driver(i2c_plat_driver_i);
diff --git a/drivers/staging/kpc2000/kpc_spi/Makefile b/drivers/staging/kpc2000/kpc_spi/Makefile
deleted file mode 100644
index 3018d200484f..000000000000
--- a/drivers/staging/kpc2000/kpc_spi/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-obj-m += kpc2000_spi.o
-kpc2000_spi-objs := spi_driver.o
diff --git a/drivers/staging/kpc2000/kpc_spi/spi_driver.c b/drivers/staging/kpc2000/kpc_spi/spi_driver.c
deleted file mode 100644
index 86df16547a92..000000000000
--- a/drivers/staging/kpc2000/kpc_spi/spi_driver.c
+++ /dev/null
@@ -1,507 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * KP2000 SPI controller driver
- *
- * Copyright (C) 2014-2018 Daktronics
- * Author: Matt Sickler <matt.sickler@daktronics.com>
- * Very loosely based on spi-omap2-mcspi.c
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io-64-nonatomic-lo-hi.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/pm_runtime.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/gcd.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/flash.h>
-#include <linux/mtd/partitions.h>
-
-#include "../kpc.h"
-#include "spi_parts.h"
-
-
-/***************
- * SPI Defines *
- ***************/
-#define KP_SPI_REG_CONFIG 0x0 /* 0x00 */
-#define KP_SPI_REG_STATUS 0x1 /* 0x08 */
-#define KP_SPI_REG_FFCTRL 0x2 /* 0x10 */
-#define KP_SPI_REG_TXDATA 0x3 /* 0x18 */
-#define KP_SPI_REG_RXDATA 0x4 /* 0x20 */
-
-#define KP_SPI_CLK 48000000
-#define KP_SPI_MAX_FIFODEPTH 64
-#define KP_SPI_MAX_FIFOWCNT 0xFFFF
-
-#define KP_SPI_REG_CONFIG_TRM_TXRX 0
-#define KP_SPI_REG_CONFIG_TRM_RX 1
-#define KP_SPI_REG_CONFIG_TRM_TX 2
-
-#define KP_SPI_REG_STATUS_RXS 0x01
-#define KP_SPI_REG_STATUS_TXS 0x02
-#define KP_SPI_REG_STATUS_EOT 0x04
-#define KP_SPI_REG_STATUS_TXFFE 0x10
-#define KP_SPI_REG_STATUS_TXFFF 0x20
-#define KP_SPI_REG_STATUS_RXFFE 0x40
-#define KP_SPI_REG_STATUS_RXFFF 0x80
-
-
-
-/******************
- * SPI Structures *
- ******************/
-struct kp_spi {
- struct spi_master *master;
- u64 __iomem *base;
- unsigned long phys;
- struct device *dev;
- int fifo_depth;
- unsigned int pin_dir:1;
-};
-
-
-struct kp_spi_controller_state {
- void __iomem *base;
- unsigned long phys;
- unsigned char chip_select;
- int word_len;
- s64 conf_cache;
-};
-
-
-union kp_spi_config {
- /* use this to access individual elements */
- struct __attribute__((packed)) spi_config_bitfield {
- unsigned int pha : 1; /* spim_clk Phase */
- unsigned int pol : 1; /* spim_clk Polarity */
- unsigned int epol : 1; /* spim_csx Polarity */
- unsigned int dpe : 1; /* Transmission Enable */
- unsigned int wl : 5; /* Word Length */
- unsigned int : 3;
- unsigned int trm : 2; /* TxRx Mode */
- unsigned int cs : 4; /* Chip Select */
- unsigned int wcnt : 7; /* Word Count */
- unsigned int ffen : 1; /* FIFO Enable */
- unsigned int spi_en : 1; /* SPI Enable */
- unsigned int : 5;
- } bitfield;
- /* use this to grab the whole register */
- u32 reg;
-};
-
-
-
-union kp_spi_status {
- struct __attribute__((packed)) spi_status_bitfield {
- unsigned int rx : 1; /* Rx Status */
- unsigned int tx : 1; /* Tx Status */
- unsigned int eo : 1; /* End of Transfer */
- unsigned int : 1;
- unsigned int txffe : 1; /* Tx FIFO Empty */
- unsigned int txfff : 1; /* Tx FIFO Full */
- unsigned int rxffe : 1; /* Rx FIFO Empty */
- unsigned int rxfff : 1; /* Rx FIFO Full */
- unsigned int : 24;
- } bitfield;
- u32 reg;
-};
-
-
-
-union kp_spi_ffctrl {
- struct __attribute__((packed)) spi_ffctrl_bitfield {
- unsigned int ffstart : 1; /* FIFO Start */
- unsigned int : 31;
- } bitfield;
- u32 reg;
-};
-
-
-
-/***************
- * SPI Helpers *
- ***************/
-static inline int
-kp_spi_bytes_per_word(int word_len)
-{
- if (word_len <= 8){
- return 1;
- }
- else if (word_len <= 16) {
- return 2;
- }
- else { /* word_len <= 32 */
- return 4;
- }
-}
-
-static inline u64
-kp_spi_read_reg(struct kp_spi_controller_state *cs, int idx)
-{
- u64 __iomem *addr = cs->base;
- u64 val;
-
- addr += idx;
- if ((idx == KP_SPI_REG_CONFIG) && (cs->conf_cache >= 0)){
- return cs->conf_cache;
- }
- val = readq((void*)addr);
- return val;
-}
-
-static inline void
-kp_spi_write_reg(struct kp_spi_controller_state *cs, int idx, u64 val)
-{
- u64 __iomem *addr = cs->base;
- addr += idx;
- writeq(val, (void*)addr);
- if (idx == KP_SPI_REG_CONFIG)
- cs->conf_cache = val;
-}
-
-static int
-kp_spi_wait_for_reg_bit(struct kp_spi_controller_state *cs, int idx, unsigned long bit)
-{
- unsigned long timeout;
- timeout = jiffies + msecs_to_jiffies(1000);
- while (!(kp_spi_read_reg(cs, idx) & bit)) {
- if (time_after(jiffies, timeout)) {
- if (!(kp_spi_read_reg(cs, idx) & bit)) {
- return -ETIMEDOUT;
- } else {
- return 0;
- }
- }
- cpu_relax();
- }
- return 0;
-}
-
-static unsigned
-kp_spi_txrx_pio(struct spi_device *spidev, struct spi_transfer *transfer)
-{
- struct kp_spi_controller_state *cs = spidev->controller_state;
- unsigned int count = transfer->len;
- unsigned int c = count;
-
- int i;
- u8 *rx = transfer->rx_buf;
- const u8 *tx = transfer->tx_buf;
- int processed = 0;
-
- if (tx) {
- for (i = 0 ; i < c ; i++) {
- char val = *tx++;
-
- if (kp_spi_wait_for_reg_bit(cs, KP_SPI_REG_STATUS, KP_SPI_REG_STATUS_TXS) < 0) {
- goto out;
- }
-
- kp_spi_write_reg(cs, KP_SPI_REG_TXDATA, val);
- processed++;
- }
- }
- else if(rx) {
- for (i = 0 ; i < c ; i++) {
- char test=0;
-
- kp_spi_write_reg(cs, KP_SPI_REG_TXDATA, 0x00);
-
- if (kp_spi_wait_for_reg_bit(cs, KP_SPI_REG_STATUS, KP_SPI_REG_STATUS_RXS) < 0) {
- goto out;
- }
-
- test = kp_spi_read_reg(cs, KP_SPI_REG_RXDATA);
- *rx++ = test;
- processed++;
- }
- }
-
- if (kp_spi_wait_for_reg_bit(cs, KP_SPI_REG_STATUS, KP_SPI_REG_STATUS_EOT) < 0) {
- //TODO: Figure out how to abort transaction?? This has never happened in practice though...
- }
-
- out:
- return processed;
-}
-
-/*****************
- * SPI Functions *
- *****************/
-static int
-kp_spi_setup(struct spi_device *spidev)
-{
- union kp_spi_config sc;
- struct kp_spi *kpspi = spi_master_get_devdata(spidev->master);
- struct kp_spi_controller_state *cs;
-
- /* setup controller state */
- cs = spidev->controller_state;
- if (!cs) {
- cs = kzalloc(sizeof(*cs), GFP_KERNEL);
- if(!cs) {
- return -ENOMEM;
- }
- cs->base = kpspi->base;
- cs->phys = kpspi->phys;
- cs->chip_select = spidev->chip_select;
- cs->word_len = spidev->bits_per_word;
- cs->conf_cache = -1;
- spidev->controller_state = cs;
- }
-
- /* set config register */
- sc.bitfield.wl = spidev->bits_per_word - 1;
- sc.bitfield.cs = spidev->chip_select;
- sc.bitfield.spi_en = 0;
- sc.bitfield.trm = 0;
- sc.bitfield.ffen = 0;
- kp_spi_write_reg(spidev->controller_state, KP_SPI_REG_CONFIG, sc.reg);
- return 0;
-}
-
-static int
-kp_spi_transfer_one_message(struct spi_master *master, struct spi_message *m)
-{
- struct kp_spi_controller_state *cs;
- struct spi_device *spidev;
- struct kp_spi *kpspi;
- struct spi_transfer *transfer;
- union kp_spi_config sc;
- int status = 0;
-
- spidev = m->spi;
- kpspi = spi_master_get_devdata(master);
- m->actual_length = 0;
- m->status = 0;
-
- cs = spidev->controller_state;
-
- /* reject invalid messages and transfers */
- if (list_empty(&m->transfers)) {
- return -EINVAL;
- }
-
- /* validate input */
- list_for_each_entry(transfer, &m->transfers, transfer_list) {
- const void *tx_buf = transfer->tx_buf;
- void *rx_buf = transfer->rx_buf;
- unsigned len = transfer->len;
-
- if (transfer->speed_hz > KP_SPI_CLK || (len && !(rx_buf || tx_buf))) {
- dev_dbg(kpspi->dev, " transfer: %d Hz, %d %s%s, %d bpw\n",
- transfer->speed_hz,
- len,
- tx_buf ? "tx" : "",
- rx_buf ? "rx" : "",
- transfer->bits_per_word);
- dev_dbg(kpspi->dev, " transfer -EINVAL\n");
- return -EINVAL;
- }
- if (transfer->speed_hz && (transfer->speed_hz < (KP_SPI_CLK >> 15))) {
- dev_dbg(kpspi->dev, "speed_hz %d below minimum %d Hz\n",
- transfer->speed_hz,
- KP_SPI_CLK >> 15);
- dev_dbg(kpspi->dev, " speed_hz -EINVAL\n");
- return -EINVAL;
- }
- }
-
- /* assert chip select to start the sequence*/
- sc.reg = kp_spi_read_reg(cs, KP_SPI_REG_CONFIG);
- sc.bitfield.spi_en = 1;
- kp_spi_write_reg(cs, KP_SPI_REG_CONFIG, sc.reg);
-
- /* work */
- if (kp_spi_wait_for_reg_bit(cs, KP_SPI_REG_STATUS, KP_SPI_REG_STATUS_EOT) < 0) {
- dev_info(kpspi->dev, "EOT timed out\n");
- goto out;
- }
-
- /* do the transfers for this message */
- list_for_each_entry(transfer, &m->transfers, transfer_list) {
- if (transfer->tx_buf == NULL && transfer->rx_buf == NULL && transfer->len) {
- status = -EINVAL;
- break;
- }
-
- /* transfer */
- if (transfer->len) {
- unsigned int word_len = spidev->bits_per_word;
- unsigned count;
-
- /* set up the transfer... */
- sc.reg = kp_spi_read_reg(cs, KP_SPI_REG_CONFIG);
-
- /* ...direction */
- if (transfer->tx_buf) {
- sc.bitfield.trm = KP_SPI_REG_CONFIG_TRM_TX;
- }
- else if (transfer->rx_buf) {
- sc.bitfield.trm = KP_SPI_REG_CONFIG_TRM_RX;
- }
-
- /* ...word length */
- if (transfer->bits_per_word) {
- word_len = transfer->bits_per_word;
- }
- cs->word_len = word_len;
- sc.bitfield.wl = word_len-1;
-
- /* ...chip select */
- sc.bitfield.cs = spidev->chip_select;
-
- /* ...and write the new settings */
- kp_spi_write_reg(cs, KP_SPI_REG_CONFIG, sc.reg);
-
- /* do the transfer */
- count = kp_spi_txrx_pio(spidev, transfer);
- m->actual_length += count;
-
- if (count != transfer->len) {
- status = -EIO;
- break;
- }
- }
-
- if (transfer->delay_usecs) {
- udelay(transfer->delay_usecs);
- }
- }
-
- /* de-assert chip select to end the sequence */
- sc.reg = kp_spi_read_reg(cs, KP_SPI_REG_CONFIG);
- sc.bitfield.spi_en = 0;
- kp_spi_write_reg(cs, KP_SPI_REG_CONFIG, sc.reg);
-
- out:
- /* done work */
- spi_finalize_current_message(master);
- return 0;
-}
-
-static void
-kp_spi_cleanup(struct spi_device *spidev)
-{
- struct kp_spi_controller_state *cs = spidev->controller_state;
- if (cs) {
- kfree(cs);
- }
-}
-
-
-
-/******************
- * Probe / Remove *
- ******************/
-static int
-kp_spi_probe(struct platform_device *pldev)
-{
- struct kpc_core_device_platdata *drvdata;
- struct spi_master *master;
- struct kp_spi *kpspi;
- struct resource *r;
- int status = 0;
- int i;
-
- drvdata = pldev->dev.platform_data;
- if (!drvdata){
- dev_err(&pldev->dev, "kp_spi_probe: platform_data is NULL!\n");
- return -ENODEV;
- }
-
- master = spi_alloc_master(&pldev->dev, sizeof(struct kp_spi));
- if (master == NULL) {
- dev_err(&pldev->dev, "kp_spi_probe: master allocation failed\n");
- return -ENOMEM;
- }
-
- /* set up the spi functions */
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
- master->bits_per_word_mask = (unsigned int)SPI_BPW_RANGE_MASK(4, 32);
- master->setup = kp_spi_setup;
- master->transfer_one_message = kp_spi_transfer_one_message;
- master->cleanup = kp_spi_cleanup;
-
- platform_set_drvdata(pldev, master);
-
- kpspi = spi_master_get_devdata(master);
- kpspi->master = master;
- kpspi->dev = &pldev->dev;
-
- master->num_chipselect = 4;
- if (pldev->id != -1) {
- master->bus_num = pldev->id;
- }
- kpspi->pin_dir = 0;
-
- r = platform_get_resource(pldev, IORESOURCE_MEM, 0);
- if (r == NULL) {
- dev_err(&pldev->dev, "kp_spi_probe: Unable to get platform resources\n");
- status = -ENODEV;
- goto free_master;
- }
-
- kpspi->phys = (unsigned long)ioremap_nocache(r->start, resource_size(r));
- kpspi->base = (u64 __iomem *)kpspi->phys;
-
- status = spi_register_master(master);
- if (status < 0) {
- dev_err(&pldev->dev, "Unable to register SPI device\n");
- goto free_master;
- }
-
- /* register the slave boards */
- #define NEW_SPI_DEVICE_FROM_BOARD_INFO_TABLE(table) \
- for (i = 0 ; i < ARRAY_SIZE(table) ; i++) { \
- spi_new_device(master, &(table[i])); \
- }
-
- switch ((drvdata->card_id & 0xFFFF0000) >> 16){
- case PCI_DEVICE_ID_DAKTRONICS_KADOKA_P2KR0:
- NEW_SPI_DEVICE_FROM_BOARD_INFO_TABLE(p2kr0_board_info);
- break;
- default:
- dev_err(&pldev->dev, "Unknown hardware, cant know what partition table to use!\n");
- goto free_master;
- break;
- }
-
- return status;
-
- free_master:
- spi_master_put(master);
- return status;
-}
-
-static int
-kp_spi_remove(struct platform_device *pldev)
-{
- struct spi_master * master = platform_get_drvdata(pldev);
- spi_unregister_master(master);
- return 0;
-}
-
-
-static struct platform_driver kp_spi_driver = {
- .driver = {
- .name = KP_DRIVER_NAME_SPI,
- },
- .probe = kp_spi_probe,
- .remove = kp_spi_remove,
-};
-
-module_platform_driver(kp_spi_driver);
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:kp_spi");
diff --git a/drivers/staging/kpc2000/kpc_spi/spi_parts.h b/drivers/staging/kpc2000/kpc_spi/spi_parts.h
deleted file mode 100644
index 33e62acc5e08..000000000000
--- a/drivers/staging/kpc2000/kpc_spi/spi_parts.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-#ifndef __KPC_SPI_SPI_PARTS_H__
-#define __KPC_SPI_SPI_PARTS_H__
-
-static struct mtd_partition p2kr0_spi0_parts[] = {
- { .name = "SLOT_0", .size = 7798784, .offset = 0, },
- { .name = "SLOT_1", .size = 7798784, .offset = MTDPART_OFS_NXTBLK },
- { .name = "SLOT_2", .size = 7798784, .offset = MTDPART_OFS_NXTBLK },
- { .name = "SLOT_3", .size = 7798784, .offset = MTDPART_OFS_NXTBLK },
- { .name = "CS0_EXTRA", .size = MTDPART_SIZ_FULL, .offset = MTDPART_OFS_NXTBLK }
-};
-static struct mtd_partition p2kr0_spi1_parts[] = {
- { .name = "SLOT_4", .size = 7798784, .offset = 0, },
- { .name = "SLOT_5", .size = 7798784, .offset = MTDPART_OFS_NXTBLK },
- { .name = "SLOT_6", .size = 7798784, .offset = MTDPART_OFS_NXTBLK },
- { .name = "SLOT_7", .size = 7798784, .offset = MTDPART_OFS_NXTBLK },
- { .name = "CS1_EXTRA", .size = MTDPART_SIZ_FULL, .offset = MTDPART_OFS_NXTBLK }
-};
-
-static struct flash_platform_data p2kr0_spi0_pdata = {
- .name = "SPI0",
- .nr_parts = ARRAY_SIZE(p2kr0_spi0_parts),
- .parts = p2kr0_spi0_parts,
-};
-static struct flash_platform_data p2kr0_spi1_pdata = {
- .name = "SPI1",
- .nr_parts = ARRAY_SIZE(p2kr0_spi1_parts),
- .parts = p2kr0_spi1_parts,
-};
-
-static struct spi_board_info p2kr0_board_info[] = {
- {
- .modalias = "n25q256a11",
- .bus_num = 1,
- .chip_select = 0,
- .mode = SPI_MODE_0,
- .platform_data = &p2kr0_spi0_pdata
- },
- {
- .modalias = "n25q256a11",
- .bus_num = 1,
- .chip_select = 1,
- .mode = SPI_MODE_0,
- .platform_data = &p2kr0_spi1_pdata
- },
-};
-
-#endif
diff --git a/drivers/staging/ks7010/ks7010_sdio.c b/drivers/staging/ks7010/ks7010_sdio.c
index 74551eb717fc..4b379542ecd5 100644
--- a/drivers/staging/ks7010/ks7010_sdio.c
+++ b/drivers/staging/ks7010/ks7010_sdio.c
@@ -380,7 +380,7 @@ int ks_wlan_hw_tx(struct ks_wlan_private *priv, void *p, unsigned long size,
struct sk_buff *skb),
struct sk_buff *skb)
{
- int result = 0;
+ int result;
struct hostif_hdr *hdr;
hdr = (struct hostif_hdr *)p;
diff --git a/drivers/staging/ks7010/ks_hostif.c b/drivers/staging/ks7010/ks_hostif.c
index e089366ed02a..2666f9e30c15 100644
--- a/drivers/staging/ks7010/ks_hostif.c
+++ b/drivers/staging/ks7010/ks_hostif.c
@@ -1067,7 +1067,6 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *skb)
unsigned int length = 0;
struct hostif_data_request *pp;
unsigned char *p;
- int result = 0;
unsigned short eth_proto;
struct ether_hdr *eth_hdr;
unsigned short keyinfo = 0;
@@ -1209,8 +1208,8 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *skb)
pp->header.event = cpu_to_le16(HIF_DATA_REQ);
/* tx request */
- result = ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp) + skb_len),
- send_packet_complete, skb);
+ ret = ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp) + skb_len),
+ send_packet_complete, skb);
/* MIC FAILURE REPORT check */
if (eth_proto == ETH_P_PAE &&
@@ -1225,7 +1224,7 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *skb)
priv->wpa.mic_failure.stop = 1;
}
- return result;
+ return ret;
err_kfree:
kfree(pp);
diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig
index f77f5eee7fc2..534d85d6c5e3 100644
--- a/drivers/staging/media/Kconfig
+++ b/drivers/staging/media/Kconfig
@@ -20,15 +20,19 @@ menuconfig STAGING_MEDIA
if STAGING_MEDIA && MEDIA_SUPPORT
# Please keep them in alphabetic order
+source "drivers/staging/media/allegro-dvt/Kconfig"
+
source "drivers/staging/media/bcm2048/Kconfig"
source "drivers/staging/media/davinci_vpfe/Kconfig"
+source "drivers/staging/media/hantro/Kconfig"
+
source "drivers/staging/media/imx/Kconfig"
-source "drivers/staging/media/omap4iss/Kconfig"
+source "drivers/staging/media/meson/vdec/Kconfig"
-source "drivers/staging/media/rockchip/vpu/Kconfig"
+source "drivers/staging/media/omap4iss/Kconfig"
source "drivers/staging/media/sunxi/Kconfig"
diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile
index 99218bfc997f..c486298194da 100644
--- a/drivers/staging/media/Makefile
+++ b/drivers/staging/media/Makefile
@@ -1,10 +1,12 @@
# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_VIDEO_ALLEGRO_DVT) += allegro-dvt/
obj-$(CONFIG_I2C_BCM2048) += bcm2048/
obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx/
obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci_vpfe/
+obj-$(CONFIG_VIDEO_MESON_VDEC) += meson/vdec/
obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/
obj-$(CONFIG_VIDEO_SUNXI) += sunxi/
obj-$(CONFIG_TEGRA_VDE) += tegra-vde/
-obj-$(CONFIG_VIDEO_ROCKCHIP_VPU) += rockchip/vpu/
+obj-$(CONFIG_VIDEO_HANTRO) += hantro/
obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3/
obj-$(CONFIG_SOC_CAMERA) += soc_camera/
diff --git a/drivers/staging/media/allegro-dvt/Kconfig b/drivers/staging/media/allegro-dvt/Kconfig
new file mode 100644
index 000000000000..6b7107d9995c
--- /dev/null
+++ b/drivers/staging/media/allegro-dvt/Kconfig
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0
+config VIDEO_ALLEGRO_DVT
+ tristate "Allegro DVT Video IP Core"
+ depends on VIDEO_DEV && VIDEO_V4L2
+ depends on ARCH_ZYNQMP || COMPILE_TEST
+ select V4L2_MEM2MEM_DEV
+ select VIDEOBUF2_DMA_CONTIG
+ select REGMAP
+ select REGMAP_MMIO
+ help
+ Support for the encoder video IP core by Allegro DVT. This core is
+ found for example on the Xilinx ZynqMP SoC in the EV family and is
+ called VCU in the reference manual.
+
+ To compile this driver as a module, choose M here: the module
+ will be called allegro.
diff --git a/drivers/staging/media/allegro-dvt/Makefile b/drivers/staging/media/allegro-dvt/Makefile
new file mode 100644
index 000000000000..80817160815c
--- /dev/null
+++ b/drivers/staging/media/allegro-dvt/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
+allegro-objs := allegro-core.o nal-h264.o
+
+obj-$(CONFIG_VIDEO_ALLEGRO_DVT) += allegro.o
diff --git a/drivers/staging/media/allegro-dvt/TODO b/drivers/staging/media/allegro-dvt/TODO
new file mode 100644
index 000000000000..99e19be0e45a
--- /dev/null
+++ b/drivers/staging/media/allegro-dvt/TODO
@@ -0,0 +1,4 @@
+TODO:
+
+- This driver is waiting for the stateful encoder spec and corresponding
+ v4l2-compliance tests to be finalized.
diff --git a/drivers/staging/media/allegro-dvt/allegro-core.c b/drivers/staging/media/allegro-dvt/allegro-core.c
new file mode 100644
index 000000000000..f050c7347fd5
--- /dev/null
+++ b/drivers/staging/media/allegro-dvt/allegro-core.c
@@ -0,0 +1,3014 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Pengutronix, Michael Tretter <kernel@pengutronix.de>
+ *
+ * Allegro DVT video encoder driver
+ */
+
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/log2.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/sizes.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-v4l2.h>
+
+#include "nal-h264.h"
+
+/*
+ * Support up to 4k video streams. The hardware actually supports higher
+ * resolutions, which are specified in PG252 June 6, 2018 (H.264/H.265 Video
+ * Codec Unit v1.1) Chapter 3.
+ */
+#define ALLEGRO_WIDTH_MIN 128
+#define ALLEGRO_WIDTH_DEFAULT 1920
+#define ALLEGRO_WIDTH_MAX 3840
+#define ALLEGRO_HEIGHT_MIN 64
+#define ALLEGRO_HEIGHT_DEFAULT 1080
+#define ALLEGRO_HEIGHT_MAX 2160
+
+#define ALLEGRO_GOP_SIZE_DEFAULT 25
+#define ALLEGRO_GOP_SIZE_MAX 1000
+
+/*
+ * MCU Control Registers
+ *
+ * The Zynq UltraScale+ Devices Register Reference documents the registers
+ * with an offset of 0x9000, which equals the size of the SRAM and one page
+ * gap. The driver handles SRAM and registers separately and, therefore, is
+ * oblivious of the offset.
+ */
+#define AL5_MCU_RESET 0x0000
+#define AL5_MCU_RESET_SOFT BIT(0)
+#define AL5_MCU_RESET_REGS BIT(1)
+#define AL5_MCU_RESET_MODE 0x0004
+#define AL5_MCU_RESET_MODE_SLEEP BIT(0)
+#define AL5_MCU_RESET_MODE_HALT BIT(1)
+#define AL5_MCU_STA 0x0008
+#define AL5_MCU_STA_SLEEP BIT(0)
+#define AL5_MCU_WAKEUP 0x000c
+
+#define AL5_ICACHE_ADDR_OFFSET_MSB 0x0010
+#define AL5_ICACHE_ADDR_OFFSET_LSB 0x0014
+#define AL5_DCACHE_ADDR_OFFSET_MSB 0x0018
+#define AL5_DCACHE_ADDR_OFFSET_LSB 0x001c
+
+#define AL5_MCU_INTERRUPT 0x0100
+#define AL5_ITC_CPU_IRQ_MSK 0x0104
+#define AL5_ITC_CPU_IRQ_CLR 0x0108
+#define AL5_ITC_CPU_IRQ_STA 0x010C
+#define AL5_ITC_CPU_IRQ_STA_TRIGGERED BIT(0)
+
+#define AXI_ADDR_OFFSET_IP 0x0208
+
+/*
+ * The MCU accesses the system memory with a 2G offset compared to CPU
+ * physical addresses.
+ */
+#define MCU_CACHE_OFFSET SZ_2G
+
+/*
+ * The driver needs to reserve some space at the beginning of capture buffers,
+ * because it needs to write SPS/PPS NAL units. The encoder writes the actual
+ * frame data after the offset.
+ */
+#define ENCODER_STREAM_OFFSET SZ_64
+
+#define SIZE_MACROBLOCK 16
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-2)");
+
+struct allegro_buffer {
+ void *vaddr;
+ dma_addr_t paddr;
+ size_t size;
+ struct list_head head;
+};
+
+struct allegro_channel;
+
+struct allegro_mbox {
+ unsigned int head;
+ unsigned int tail;
+ unsigned int data;
+ size_t size;
+ /* protect mailbox from simultaneous accesses */
+ struct mutex lock;
+};
+
+struct allegro_dev {
+ struct v4l2_device v4l2_dev;
+ struct video_device video_dev;
+ struct v4l2_m2m_dev *m2m_dev;
+ struct platform_device *plat_dev;
+
+ /* mutex protecting vb2_queue structure */
+ struct mutex lock;
+
+ struct regmap *regmap;
+ struct regmap *sram;
+
+ struct allegro_buffer firmware;
+ struct allegro_buffer suballocator;
+
+ struct completion init_complete;
+
+ /* The mailbox interface */
+ struct allegro_mbox mbox_command;
+ struct allegro_mbox mbox_status;
+
+ /*
+ * The downstream driver limits the users to 64 users, thus I can use
+ * a bitfield for the user_ids that are in use. See also user_id in
+ * struct allegro_channel.
+ */
+ unsigned long channel_user_ids;
+ struct list_head channels;
+};
+
+static struct regmap_config allegro_regmap_config = {
+ .name = "regmap",
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = 0xfff,
+ .cache_type = REGCACHE_NONE,
+};
+
+static struct regmap_config allegro_sram_config = {
+ .name = "sram",
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = 0x7fff,
+ .cache_type = REGCACHE_NONE,
+};
+
+enum allegro_state {
+ ALLEGRO_STATE_ENCODING,
+ ALLEGRO_STATE_DRAIN,
+ ALLEGRO_STATE_WAIT_FOR_BUFFER,
+ ALLEGRO_STATE_STOPPED,
+};
+
+#define fh_to_channel(__fh) container_of(__fh, struct allegro_channel, fh)
+
+struct allegro_channel {
+ struct allegro_dev *dev;
+ struct v4l2_fh fh;
+ struct v4l2_ctrl_handler ctrl_handler;
+
+ unsigned int width;
+ unsigned int height;
+ unsigned int stride;
+
+ enum v4l2_colorspace colorspace;
+ enum v4l2_ycbcr_encoding ycbcr_enc;
+ enum v4l2_quantization quantization;
+ enum v4l2_xfer_func xfer_func;
+
+ u32 pixelformat;
+ unsigned int sizeimage_raw;
+ unsigned int osequence;
+
+ u32 codec;
+ enum v4l2_mpeg_video_h264_profile profile;
+ enum v4l2_mpeg_video_h264_level level;
+ unsigned int sizeimage_encoded;
+ unsigned int csequence;
+
+ enum v4l2_mpeg_video_bitrate_mode bitrate_mode;
+ unsigned int bitrate;
+ unsigned int bitrate_peak;
+ unsigned int cpb_size;
+ unsigned int gop_size;
+
+ struct v4l2_ctrl *mpeg_video_h264_profile;
+ struct v4l2_ctrl *mpeg_video_h264_level;
+ struct v4l2_ctrl *mpeg_video_bitrate_mode;
+ struct v4l2_ctrl *mpeg_video_bitrate;
+ struct v4l2_ctrl *mpeg_video_bitrate_peak;
+ struct v4l2_ctrl *mpeg_video_cpb_size;
+ struct v4l2_ctrl *mpeg_video_gop_size;
+
+ /* user_id is used to identify the channel during CREATE_CHANNEL */
+ /* not sure, what to set here and if this is actually required */
+ int user_id;
+ /* channel_id is set by the mcu and used by all later commands */
+ int mcu_channel_id;
+
+ struct list_head buffers_reference;
+ struct list_head buffers_intermediate;
+
+ struct list_head list;
+ struct completion completion;
+
+ unsigned int error;
+ enum allegro_state state;
+};
+
+static inline int
+allegro_set_state(struct allegro_channel *channel, enum allegro_state state)
+{
+ channel->state = state;
+
+ return 0;
+}
+
+static inline enum allegro_state
+allegro_get_state(struct allegro_channel *channel)
+{
+ return channel->state;
+}
+
+struct fw_info {
+ unsigned int id;
+ unsigned int id_codec;
+ char *version;
+ unsigned int mailbox_cmd;
+ unsigned int mailbox_status;
+ size_t mailbox_size;
+ size_t suballocator_size;
+};
+
+static const struct fw_info supported_firmware[] = {
+ {
+ .id = 18296,
+ .id_codec = 96272,
+ .version = "v2018.2",
+ .mailbox_cmd = 0x7800,
+ .mailbox_status = 0x7c00,
+ .mailbox_size = 0x400 - 0x8,
+ .suballocator_size = SZ_16M,
+ },
+};
+
+enum mcu_msg_type {
+ MCU_MSG_TYPE_INIT = 0x0000,
+ MCU_MSG_TYPE_CREATE_CHANNEL = 0x0005,
+ MCU_MSG_TYPE_DESTROY_CHANNEL = 0x0006,
+ MCU_MSG_TYPE_ENCODE_FRAME = 0x0007,
+ MCU_MSG_TYPE_PUT_STREAM_BUFFER = 0x0012,
+ MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE = 0x000e,
+ MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE = 0x000f,
+};
+
+static const char *msg_type_name(enum mcu_msg_type type)
+{
+ static char buf[9];
+
+ switch (type) {
+ case MCU_MSG_TYPE_INIT:
+ return "INIT";
+ case MCU_MSG_TYPE_CREATE_CHANNEL:
+ return "CREATE_CHANNEL";
+ case MCU_MSG_TYPE_DESTROY_CHANNEL:
+ return "DESTROY_CHANNEL";
+ case MCU_MSG_TYPE_ENCODE_FRAME:
+ return "ENCODE_FRAME";
+ case MCU_MSG_TYPE_PUT_STREAM_BUFFER:
+ return "PUT_STREAM_BUFFER";
+ case MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE:
+ return "PUSH_BUFFER_INTERMEDIATE";
+ case MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE:
+ return "PUSH_BUFFER_REFERENCE";
+ default:
+ snprintf(buf, sizeof(buf), "(0x%04x)", type);
+ return buf;
+ }
+}
+
+struct mcu_msg_header {
+ u16 length; /* length of the body in bytes */
+ u16 type;
+} __attribute__ ((__packed__));
+
+struct mcu_msg_init_request {
+ struct mcu_msg_header header;
+ u32 reserved0; /* maybe a unused channel id */
+ u32 suballoc_dma;
+ u32 suballoc_size;
+ s32 l2_cache[3];
+} __attribute__ ((__packed__));
+
+struct mcu_msg_init_response {
+ struct mcu_msg_header header;
+ u32 reserved0;
+} __attribute__ ((__packed__));
+
+struct mcu_msg_create_channel {
+ struct mcu_msg_header header;
+ u32 user_id;
+ u16 width;
+ u16 height;
+ u32 format;
+ u32 colorspace;
+ u32 src_mode;
+ u8 profile;
+ u16 constraint_set_flags;
+ s8 codec;
+ u16 level;
+ u16 tier;
+ u32 sps_param;
+ u32 pps_param;
+
+ u32 enc_option;
+#define AL_OPT_WPP BIT(0)
+#define AL_OPT_TILE BIT(1)
+#define AL_OPT_LF BIT(2)
+#define AL_OPT_LF_X_SLICE BIT(3)
+#define AL_OPT_LF_X_TILE BIT(4)
+#define AL_OPT_SCL_LST BIT(5)
+#define AL_OPT_CONST_INTRA_PRED BIT(6)
+#define AL_OPT_QP_TAB_RELATIVE BIT(7)
+#define AL_OPT_FIX_PREDICTOR BIT(8)
+#define AL_OPT_CUSTOM_LDA BIT(9)
+#define AL_OPT_ENABLE_AUTO_QP BIT(10)
+#define AL_OPT_ADAPT_AUTO_QP BIT(11)
+#define AL_OPT_TRANSFO_SKIP BIT(13)
+#define AL_OPT_FORCE_REC BIT(15)
+#define AL_OPT_FORCE_MV_OUT BIT(16)
+#define AL_OPT_FORCE_MV_CLIP BIT(17)
+#define AL_OPT_LOWLAT_SYNC BIT(18)
+#define AL_OPT_LOWLAT_INT BIT(19)
+#define AL_OPT_RDO_COST_MODE BIT(20)
+
+ s8 beta_offset;
+ s8 tc_offset;
+ u16 reserved10;
+ u32 unknown11;
+ u32 unknown12;
+ u16 num_slices;
+ u16 prefetch_auto;
+ u32 prefetch_mem_offset;
+ u32 prefetch_mem_size;
+ u16 clip_hrz_range;
+ u16 clip_vrt_range;
+ u16 me_range[4];
+ u8 max_cu_size;
+ u8 min_cu_size;
+ u8 max_tu_size;
+ u8 min_tu_size;
+ u8 max_transfo_depth_inter;
+ u8 max_transfo_depth_intra;
+ u16 reserved20;
+ u32 entropy_mode;
+ u32 wp_mode;
+
+ /* rate control param */
+ u32 rate_control_mode;
+ u32 initial_rem_delay;
+ u32 cpb_size;
+ u16 framerate;
+ u16 clk_ratio;
+ u32 target_bitrate;
+ u32 max_bitrate;
+ u16 initial_qp;
+ u16 min_qp;
+ u16 max_qp;
+ s16 ip_delta;
+ s16 pb_delta;
+ u16 golden_ref;
+ u16 golden_delta;
+ u16 golden_ref_frequency;
+ u32 rate_control_option;
+
+ /* gop param */
+ u32 gop_ctrl_mode;
+ u32 freq_ird;
+ u32 freq_lt;
+ u32 gdr_mode;
+ u32 gop_length;
+ u32 unknown39;
+
+ u32 subframe_latency;
+ u32 lda_control_mode;
+} __attribute__ ((__packed__));
+
+struct mcu_msg_create_channel_response {
+ struct mcu_msg_header header;
+ u32 channel_id;
+ u32 user_id;
+ u32 options;
+ u32 num_core;
+ u32 pps_param;
+ u32 int_buffers_count;
+ u32 int_buffers_size;
+ u32 rec_buffers_count;
+ u32 rec_buffers_size;
+ u32 reserved;
+ u32 error_code;
+} __attribute__ ((__packed__));
+
+struct mcu_msg_destroy_channel {
+ struct mcu_msg_header header;
+ u32 channel_id;
+} __attribute__ ((__packed__));
+
+struct mcu_msg_destroy_channel_response {
+ struct mcu_msg_header header;
+ u32 channel_id;
+} __attribute__ ((__packed__));
+
+struct mcu_msg_push_buffers_internal_buffer {
+ u32 dma_addr;
+ u32 mcu_addr;
+ u32 size;
+} __attribute__ ((__packed__));
+
+struct mcu_msg_push_buffers_internal {
+ struct mcu_msg_header header;
+ u32 channel_id;
+ struct mcu_msg_push_buffers_internal_buffer buffer[0];
+} __attribute__ ((__packed__));
+
+struct mcu_msg_put_stream_buffer {
+ struct mcu_msg_header header;
+ u32 channel_id;
+ u32 dma_addr;
+ u32 mcu_addr;
+ u32 size;
+ u32 offset;
+ u64 stream_id;
+} __attribute__ ((__packed__));
+
+struct mcu_msg_encode_frame {
+ struct mcu_msg_header header;
+ u32 channel_id;
+ u32 reserved;
+
+ u32 encoding_options;
+#define AL_OPT_USE_QP_TABLE BIT(0)
+#define AL_OPT_FORCE_LOAD BIT(1)
+#define AL_OPT_USE_L2 BIT(2)
+#define AL_OPT_DISABLE_INTRA BIT(3)
+#define AL_OPT_DEPENDENT_SLICES BIT(4)
+
+ s16 pps_qp;
+ u16 padding;
+ u64 user_param;
+ u64 src_handle;
+
+ u32 request_options;
+#define AL_OPT_SCENE_CHANGE BIT(0)
+#define AL_OPT_RESTART_GOP BIT(1)
+#define AL_OPT_USE_LONG_TERM BIT(2)
+#define AL_OPT_UPDATE_PARAMS BIT(3)
+
+ /* u32 scene_change_delay (optional) */
+ /* rate control param (optional) */
+ /* gop param (optional) */
+ u32 src_y;
+ u32 src_uv;
+ u32 stride;
+ u32 ep2;
+ u64 ep2_v;
+} __attribute__ ((__packed__));
+
+struct mcu_msg_encode_frame_response {
+ struct mcu_msg_header header;
+ u32 channel_id;
+ u64 stream_id; /* see mcu_msg_put_stream_buffer */
+ u64 user_param; /* see mcu_msg_encode_frame */
+ u64 src_handle; /* see mcu_msg_encode_frame */
+ u16 skip;
+ u16 is_ref;
+ u32 initial_removal_delay;
+ u32 dpb_output_delay;
+ u32 size;
+ u32 frame_tag_size;
+ s32 stuffing;
+ s32 filler;
+ u16 num_column;
+ u16 num_row;
+ u16 qp;
+ u8 num_ref_idx_l0;
+ u8 num_ref_idx_l1;
+ u32 partition_table_offset;
+ s32 partition_table_size;
+ u32 sum_complex;
+ s32 tile_width[4];
+ s32 tile_height[22];
+ u32 error_code;
+
+ u32 slice_type;
+#define AL_ENC_SLICE_TYPE_B 0
+#define AL_ENC_SLICE_TYPE_P 1
+#define AL_ENC_SLICE_TYPE_I 2
+
+ u32 pic_struct;
+ u8 is_idr;
+ u8 is_first_slice;
+ u8 is_last_slice;
+ u8 reserved;
+ u16 pps_qp;
+ u16 reserved1;
+ u32 reserved2;
+} __attribute__ ((__packed__));
+
+union mcu_msg_response {
+ struct mcu_msg_header header;
+ struct mcu_msg_init_response init;
+ struct mcu_msg_create_channel_response create_channel;
+ struct mcu_msg_destroy_channel_response destroy_channel;
+ struct mcu_msg_encode_frame_response encode_frame;
+};
+
+/* Helper functions for channel and user operations */
+
+static unsigned long allegro_next_user_id(struct allegro_dev *dev)
+{
+ if (dev->channel_user_ids == ~0UL)
+ return -EBUSY;
+
+ return ffz(dev->channel_user_ids);
+}
+
+static struct allegro_channel *
+allegro_find_channel_by_user_id(struct allegro_dev *dev,
+ unsigned int user_id)
+{
+ struct allegro_channel *channel;
+
+ list_for_each_entry(channel, &dev->channels, list) {
+ if (channel->user_id == user_id)
+ return channel;
+ }
+
+ return ERR_PTR(-EINVAL);
+}
+
+static struct allegro_channel *
+allegro_find_channel_by_channel_id(struct allegro_dev *dev,
+ unsigned int channel_id)
+{
+ struct allegro_channel *channel;
+
+ list_for_each_entry(channel, &dev->channels, list) {
+ if (channel->mcu_channel_id == channel_id)
+ return channel;
+ }
+
+ return ERR_PTR(-EINVAL);
+}
+
+static inline bool channel_exists(struct allegro_channel *channel)
+{
+ return channel->mcu_channel_id != -1;
+}
+
+static unsigned int estimate_stream_size(unsigned int width,
+ unsigned int height)
+{
+ unsigned int offset = ENCODER_STREAM_OFFSET;
+ unsigned int num_blocks = DIV_ROUND_UP(width, SIZE_MACROBLOCK) *
+ DIV_ROUND_UP(height, SIZE_MACROBLOCK);
+ unsigned int pcm_size = SZ_256;
+ unsigned int partition_table = SZ_256;
+
+ return round_up(offset + num_blocks * pcm_size + partition_table, 32);
+}
+
+static enum v4l2_mpeg_video_h264_level
+select_minimum_h264_level(unsigned int width, unsigned int height)
+{
+ unsigned int pic_width_in_mb = DIV_ROUND_UP(width, SIZE_MACROBLOCK);
+ unsigned int frame_height_in_mb = DIV_ROUND_UP(height, SIZE_MACROBLOCK);
+ unsigned int frame_size_in_mb = pic_width_in_mb * frame_height_in_mb;
+ enum v4l2_mpeg_video_h264_level level = V4L2_MPEG_VIDEO_H264_LEVEL_4_0;
+
+ /*
+ * The level limits are specified in Rec. ITU-T H.264 Annex A.3.1 and
+ * also specify limits regarding bit rate and CBP size. Only approximate
+ * the levels using the frame size.
+ *
+ * Level 5.1 allows up to 4k video resolution.
+ */
+ if (frame_size_in_mb <= 99)
+ level = V4L2_MPEG_VIDEO_H264_LEVEL_1_0;
+ else if (frame_size_in_mb <= 396)
+ level = V4L2_MPEG_VIDEO_H264_LEVEL_1_1;
+ else if (frame_size_in_mb <= 792)
+ level = V4L2_MPEG_VIDEO_H264_LEVEL_2_1;
+ else if (frame_size_in_mb <= 1620)
+ level = V4L2_MPEG_VIDEO_H264_LEVEL_2_2;
+ else if (frame_size_in_mb <= 3600)
+ level = V4L2_MPEG_VIDEO_H264_LEVEL_3_1;
+ else if (frame_size_in_mb <= 5120)
+ level = V4L2_MPEG_VIDEO_H264_LEVEL_3_2;
+ else if (frame_size_in_mb <= 8192)
+ level = V4L2_MPEG_VIDEO_H264_LEVEL_4_0;
+ else if (frame_size_in_mb <= 8704)
+ level = V4L2_MPEG_VIDEO_H264_LEVEL_4_2;
+ else if (frame_size_in_mb <= 22080)
+ level = V4L2_MPEG_VIDEO_H264_LEVEL_5_0;
+ else
+ level = V4L2_MPEG_VIDEO_H264_LEVEL_5_1;
+
+ return level;
+}
+
+static unsigned int maximum_bitrate(enum v4l2_mpeg_video_h264_level level)
+{
+ switch (level) {
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
+ return 64000;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
+ return 128000;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
+ return 192000;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
+ return 384000;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
+ return 768000;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
+ return 2000000;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
+ return 4000000;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
+ return 4000000;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
+ return 10000000;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
+ return 14000000;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
+ return 20000000;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
+ return 20000000;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
+ return 50000000;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
+ return 50000000;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
+ return 135000000;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
+ default:
+ return 240000000;
+ }
+}
+
+static unsigned int maximum_cpb_size(enum v4l2_mpeg_video_h264_level level)
+{
+ switch (level) {
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
+ return 175;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
+ return 350;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
+ return 500;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
+ return 1000;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
+ return 2000;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
+ return 2000;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
+ return 4000;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
+ return 4000;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
+ return 10000;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
+ return 14000;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
+ return 20000;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
+ return 25000;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
+ return 62500;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
+ return 62500;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
+ return 135000;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
+ default:
+ return 240000;
+ }
+}
+
+static const struct fw_info *
+allegro_get_firmware_info(struct allegro_dev *dev,
+ const struct firmware *fw,
+ const struct firmware *fw_codec)
+{
+ int i;
+ unsigned int id = fw->size;
+ unsigned int id_codec = fw_codec->size;
+
+ for (i = 0; i < ARRAY_SIZE(supported_firmware); i++)
+ if (supported_firmware[i].id == id &&
+ supported_firmware[i].id_codec == id_codec)
+ return &supported_firmware[i];
+
+ return NULL;
+}
+
+/*
+ * Buffers that are used internally by the MCU.
+ */
+
+static int allegro_alloc_buffer(struct allegro_dev *dev,
+ struct allegro_buffer *buffer, size_t size)
+{
+ buffer->vaddr = dma_alloc_coherent(&dev->plat_dev->dev, size,
+ &buffer->paddr, GFP_KERNEL);
+ if (!buffer->vaddr)
+ return -ENOMEM;
+ buffer->size = size;
+
+ return 0;
+}
+
+static void allegro_free_buffer(struct allegro_dev *dev,
+ struct allegro_buffer *buffer)
+{
+ if (buffer->vaddr) {
+ dma_free_coherent(&dev->plat_dev->dev, buffer->size,
+ buffer->vaddr, buffer->paddr);
+ buffer->vaddr = NULL;
+ buffer->size = 0;
+ }
+}
+
+/*
+ * Mailbox interface to send messages to the MCU.
+ */
+
+static int allegro_mbox_init(struct allegro_dev *dev,
+ struct allegro_mbox *mbox,
+ unsigned int base, size_t size)
+{
+ if (!mbox)
+ return -EINVAL;
+
+ mbox->head = base;
+ mbox->tail = base + 0x4;
+ mbox->data = base + 0x8;
+ mbox->size = size;
+ mutex_init(&mbox->lock);
+
+ regmap_write(dev->sram, mbox->head, 0);
+ regmap_write(dev->sram, mbox->tail, 0);
+
+ return 0;
+}
+
+static int allegro_mbox_write(struct allegro_dev *dev,
+ struct allegro_mbox *mbox, void *src, size_t size)
+{
+ struct mcu_msg_header *header = src;
+ unsigned int tail;
+ size_t size_no_wrap;
+ int err = 0;
+
+ if (!src)
+ return -EINVAL;
+
+ if (size > mbox->size) {
+ v4l2_err(&dev->v4l2_dev,
+ "message (%zu bytes) to large for mailbox (%zu bytes)\n",
+ size, mbox->size);
+ return -EINVAL;
+ }
+
+ if (header->length != size - sizeof(*header)) {
+ v4l2_err(&dev->v4l2_dev,
+ "invalid message length: %u bytes (expected %zu bytes)\n",
+ header->length, size - sizeof(*header));
+ return -EINVAL;
+ }
+
+ v4l2_dbg(2, debug, &dev->v4l2_dev,
+ "write command message: type %s, body length %d\n",
+ msg_type_name(header->type), header->length);
+
+ mutex_lock(&mbox->lock);
+ regmap_read(dev->sram, mbox->tail, &tail);
+ if (tail > mbox->size) {
+ v4l2_err(&dev->v4l2_dev,
+ "invalid tail (0x%x): must be smaller than mailbox size (0x%zx)\n",
+ tail, mbox->size);
+ err = -EIO;
+ goto out;
+ }
+ size_no_wrap = min(size, mbox->size - (size_t)tail);
+ regmap_bulk_write(dev->sram, mbox->data + tail, src, size_no_wrap / 4);
+ regmap_bulk_write(dev->sram, mbox->data,
+ src + size_no_wrap, (size - size_no_wrap) / 4);
+ regmap_write(dev->sram, mbox->tail, (tail + size) % mbox->size);
+
+out:
+ mutex_unlock(&mbox->lock);
+
+ return err;
+}
+
+static ssize_t allegro_mbox_read(struct allegro_dev *dev,
+ struct allegro_mbox *mbox,
+ void *dst, size_t nbyte)
+{
+ struct mcu_msg_header *header;
+ unsigned int head;
+ ssize_t size;
+ size_t body_no_wrap;
+
+ regmap_read(dev->sram, mbox->head, &head);
+ if (head > mbox->size) {
+ v4l2_err(&dev->v4l2_dev,
+ "invalid head (0x%x): must be smaller than mailbox size (0x%zx)\n",
+ head, mbox->size);
+ return -EIO;
+ }
+
+ /* Assume that the header does not wrap. */
+ regmap_bulk_read(dev->sram, mbox->data + head,
+ dst, sizeof(*header) / 4);
+ header = dst;
+ size = header->length + sizeof(*header);
+ if (size > mbox->size || size & 0x3) {
+ v4l2_err(&dev->v4l2_dev,
+ "invalid message length: %zu bytes (maximum %zu bytes)\n",
+ header->length + sizeof(*header), mbox->size);
+ return -EIO;
+ }
+ if (size > nbyte) {
+ v4l2_err(&dev->v4l2_dev,
+ "destination buffer too small: %zu bytes (need %zu bytes)\n",
+ nbyte, size);
+ return -EINVAL;
+ }
+
+ /*
+ * The message might wrap within the mailbox. If the message does not
+ * wrap, the first read will read the entire message, otherwise the
+ * first read will read message until the end of the mailbox and the
+ * second read will read the remaining bytes from the beginning of the
+ * mailbox.
+ *
+ * Skip the header, as was already read to get the size of the body.
+ */
+ body_no_wrap = min((size_t)header->length,
+ (size_t)(mbox->size - (head + sizeof(*header))));
+ regmap_bulk_read(dev->sram, mbox->data + head + sizeof(*header),
+ dst + sizeof(*header), body_no_wrap / 4);
+ regmap_bulk_read(dev->sram, mbox->data,
+ dst + sizeof(*header) + body_no_wrap,
+ (header->length - body_no_wrap) / 4);
+
+ regmap_write(dev->sram, mbox->head, (head + size) % mbox->size);
+
+ v4l2_dbg(2, debug, &dev->v4l2_dev,
+ "read status message: type %s, body length %d\n",
+ msg_type_name(header->type), header->length);
+
+ return size;
+}
+
+static void allegro_mcu_interrupt(struct allegro_dev *dev)
+{
+ regmap_write(dev->regmap, AL5_MCU_INTERRUPT, BIT(0));
+}
+
+static void allegro_mcu_send_init(struct allegro_dev *dev,
+ dma_addr_t suballoc_dma, size_t suballoc_size)
+{
+ struct mcu_msg_init_request msg;
+
+ memset(&msg, 0, sizeof(msg));
+
+ msg.header.type = MCU_MSG_TYPE_INIT;
+ msg.header.length = sizeof(msg) - sizeof(msg.header);
+
+ msg.suballoc_dma = lower_32_bits(suballoc_dma) | MCU_CACHE_OFFSET;
+ msg.suballoc_size = suballoc_size;
+
+ /* disable L2 cache */
+ msg.l2_cache[0] = -1;
+ msg.l2_cache[1] = -1;
+ msg.l2_cache[2] = -1;
+
+ allegro_mbox_write(dev, &dev->mbox_command, &msg, sizeof(msg));
+ allegro_mcu_interrupt(dev);
+}
+
+static u32 v4l2_pixelformat_to_mcu_format(u32 pixelformat)
+{
+ switch (pixelformat) {
+ case V4L2_PIX_FMT_NV12:
+ /* AL_420_8BITS: 0x100 -> NV12, 0x88 -> 8 bit */
+ return 0x100 | 0x88;
+ default:
+ return -EINVAL;
+ }
+}
+
+static u32 v4l2_colorspace_to_mcu_colorspace(enum v4l2_colorspace colorspace)
+{
+ switch (colorspace) {
+ case V4L2_COLORSPACE_REC709:
+ return 2;
+ case V4L2_COLORSPACE_SMPTE170M:
+ return 3;
+ case V4L2_COLORSPACE_SMPTE240M:
+ return 4;
+ case V4L2_COLORSPACE_SRGB:
+ return 7;
+ default:
+ /* UNKNOWN */
+ return 0;
+ }
+}
+
+static s8 v4l2_pixelformat_to_mcu_codec(u32 pixelformat)
+{
+ switch (pixelformat) {
+ case V4L2_PIX_FMT_H264:
+ default:
+ return 1;
+ }
+}
+
+static u8 v4l2_profile_to_mcu_profile(enum v4l2_mpeg_video_h264_profile profile)
+{
+ switch (profile) {
+ case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
+ default:
+ return 66;
+ }
+}
+
+static u16 v4l2_level_to_mcu_level(enum v4l2_mpeg_video_h264_level level)
+{
+ switch (level) {
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
+ return 10;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
+ return 11;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
+ return 12;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
+ return 13;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
+ return 20;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
+ return 21;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
+ return 22;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
+ return 30;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
+ return 31;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
+ return 32;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
+ return 40;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
+ return 41;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
+ return 42;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
+ return 50;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
+ default:
+ return 51;
+ }
+}
+
+static u32
+v4l2_bitrate_mode_to_mcu_mode(enum v4l2_mpeg_video_bitrate_mode mode)
+{
+ switch (mode) {
+ case V4L2_MPEG_VIDEO_BITRATE_MODE_VBR:
+ return 2;
+ case V4L2_MPEG_VIDEO_BITRATE_MODE_CBR:
+ default:
+ return 1;
+ }
+}
+
+static int allegro_mcu_send_create_channel(struct allegro_dev *dev,
+ struct allegro_channel *channel)
+{
+ struct mcu_msg_create_channel msg;
+
+ memset(&msg, 0, sizeof(msg));
+
+ msg.header.type = MCU_MSG_TYPE_CREATE_CHANNEL;
+ msg.header.length = sizeof(msg) - sizeof(msg.header);
+
+ msg.user_id = channel->user_id;
+ msg.width = channel->width;
+ msg.height = channel->height;
+ msg.format = v4l2_pixelformat_to_mcu_format(channel->pixelformat);
+ msg.colorspace = v4l2_colorspace_to_mcu_colorspace(channel->colorspace);
+ msg.src_mode = 0x0;
+ msg.profile = v4l2_profile_to_mcu_profile(channel->profile);
+ msg.constraint_set_flags = BIT(1);
+ msg.codec = v4l2_pixelformat_to_mcu_codec(channel->codec);
+ msg.level = v4l2_level_to_mcu_level(channel->level);
+ msg.tier = 0;
+ msg.sps_param = BIT(20) | 0x4a;
+ msg.pps_param = BIT(2);
+ msg.enc_option = AL_OPT_RDO_COST_MODE | AL_OPT_LF_X_TILE |
+ AL_OPT_LF_X_SLICE | AL_OPT_LF;
+ msg.beta_offset = -1;
+ msg.tc_offset = -1;
+ msg.num_slices = 1;
+ msg.me_range[0] = 8;
+ msg.me_range[1] = 8;
+ msg.me_range[2] = 16;
+ msg.me_range[3] = 16;
+ msg.max_cu_size = ilog2(SIZE_MACROBLOCK);
+ msg.min_cu_size = ilog2(8);
+ msg.max_tu_size = 2;
+ msg.min_tu_size = 2;
+ msg.max_transfo_depth_intra = 1;
+ msg.max_transfo_depth_inter = 1;
+
+ msg.rate_control_mode =
+ v4l2_bitrate_mode_to_mcu_mode(channel->bitrate_mode);
+ /* Shall be ]0;cpb_size in 90 kHz units]. Use maximum value. */
+ msg.initial_rem_delay =
+ ((channel->cpb_size * 1000) / channel->bitrate_peak) * 90000;
+ /* Encoder expects cpb_size in units of a 90 kHz clock. */
+ msg.cpb_size =
+ ((channel->cpb_size * 1000) / channel->bitrate_peak) * 90000;
+ msg.framerate = 25;
+ msg.clk_ratio = 1000;
+ msg.target_bitrate = channel->bitrate;
+ msg.max_bitrate = channel->bitrate_peak;
+ msg.initial_qp = 25;
+ msg.min_qp = 10;
+ msg.max_qp = 51;
+ msg.ip_delta = -1;
+ msg.pb_delta = -1;
+ msg.golden_ref = 0;
+ msg.golden_delta = 2;
+ msg.golden_ref_frequency = 10;
+ msg.rate_control_option = 0x00000000;
+
+ msg.gop_ctrl_mode = 0x00000000;
+ msg.freq_ird = 0x7fffffff;
+ msg.freq_lt = 0;
+ msg.gdr_mode = 0x00000000;
+ msg.gop_length = channel->gop_size;
+ msg.subframe_latency = 0x00000000;
+ msg.lda_control_mode = 0x700d0000;
+
+ allegro_mbox_write(dev, &dev->mbox_command, &msg, sizeof(msg));
+ allegro_mcu_interrupt(dev);
+
+ return 0;
+}
+
+static int allegro_mcu_send_destroy_channel(struct allegro_dev *dev,
+ struct allegro_channel *channel)
+{
+ struct mcu_msg_destroy_channel msg;
+
+ memset(&msg, 0, sizeof(msg));
+
+ msg.header.type = MCU_MSG_TYPE_DESTROY_CHANNEL;
+ msg.header.length = sizeof(msg) - sizeof(msg.header);
+
+ msg.channel_id = channel->mcu_channel_id;
+
+ allegro_mbox_write(dev, &dev->mbox_command, &msg, sizeof(msg));
+ allegro_mcu_interrupt(dev);
+
+ return 0;
+}
+
+static int allegro_mcu_send_put_stream_buffer(struct allegro_dev *dev,
+ struct allegro_channel *channel,
+ dma_addr_t paddr,
+ unsigned long size)
+{
+ struct mcu_msg_put_stream_buffer msg;
+
+ memset(&msg, 0, sizeof(msg));
+
+ msg.header.type = MCU_MSG_TYPE_PUT_STREAM_BUFFER;
+ msg.header.length = sizeof(msg) - sizeof(msg.header);
+
+ msg.channel_id = channel->mcu_channel_id;
+ msg.dma_addr = paddr;
+ msg.mcu_addr = paddr | MCU_CACHE_OFFSET;
+ msg.size = size;
+ msg.offset = ENCODER_STREAM_OFFSET;
+ msg.stream_id = 0; /* copied to mcu_msg_encode_frame_response */
+
+ allegro_mbox_write(dev, &dev->mbox_command, &msg, sizeof(msg));
+ allegro_mcu_interrupt(dev);
+
+ return 0;
+}
+
+static int allegro_mcu_send_encode_frame(struct allegro_dev *dev,
+ struct allegro_channel *channel,
+ dma_addr_t src_y, dma_addr_t src_uv)
+{
+ struct mcu_msg_encode_frame msg;
+
+ memset(&msg, 0, sizeof(msg));
+
+ msg.header.type = MCU_MSG_TYPE_ENCODE_FRAME;
+ msg.header.length = sizeof(msg) - sizeof(msg.header);
+
+ msg.channel_id = channel->mcu_channel_id;
+ msg.encoding_options = AL_OPT_FORCE_LOAD;
+ msg.pps_qp = 26; /* qp are relative to 26 */
+ msg.user_param = 0; /* copied to mcu_msg_encode_frame_response */
+ msg.src_handle = 0; /* copied to mcu_msg_encode_frame_response */
+ msg.src_y = src_y;
+ msg.src_uv = src_uv;
+ msg.stride = channel->stride;
+ msg.ep2 = 0x0;
+ msg.ep2_v = msg.ep2 | MCU_CACHE_OFFSET;
+
+ allegro_mbox_write(dev, &dev->mbox_command, &msg, sizeof(msg));
+ allegro_mcu_interrupt(dev);
+
+ return 0;
+}
+
+static int allegro_mcu_wait_for_init_timeout(struct allegro_dev *dev,
+ unsigned long timeout_ms)
+{
+ unsigned long tmo;
+
+ tmo = wait_for_completion_timeout(&dev->init_complete,
+ msecs_to_jiffies(timeout_ms));
+ if (tmo == 0)
+ return -ETIMEDOUT;
+
+ reinit_completion(&dev->init_complete);
+ return 0;
+}
+
+static int allegro_mcu_push_buffer_internal(struct allegro_channel *channel,
+ enum mcu_msg_type type)
+{
+ struct allegro_dev *dev = channel->dev;
+ struct mcu_msg_push_buffers_internal *msg;
+ struct mcu_msg_push_buffers_internal_buffer *buffer;
+ unsigned int num_buffers = 0;
+ size_t size;
+ struct allegro_buffer *al_buffer;
+ struct list_head *list;
+ int err;
+
+ switch (type) {
+ case MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE:
+ list = &channel->buffers_reference;
+ break;
+ case MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE:
+ list = &channel->buffers_intermediate;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ list_for_each_entry(al_buffer, list, head)
+ num_buffers++;
+ size = struct_size(msg, buffer, num_buffers);
+
+ msg = kmalloc(size, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->header.length = size - sizeof(msg->header);
+ msg->header.type = type;
+ msg->channel_id = channel->mcu_channel_id;
+
+ buffer = msg->buffer;
+ list_for_each_entry(al_buffer, list, head) {
+ buffer->dma_addr = lower_32_bits(al_buffer->paddr);
+ buffer->mcu_addr =
+ lower_32_bits(al_buffer->paddr) | MCU_CACHE_OFFSET;
+ buffer->size = al_buffer->size;
+ buffer++;
+ }
+
+ err = allegro_mbox_write(dev, &dev->mbox_command, msg, size);
+ if (err)
+ goto out;
+ allegro_mcu_interrupt(dev);
+
+out:
+ kfree(msg);
+ return err;
+}
+
+static int allegro_mcu_push_buffer_intermediate(struct allegro_channel *channel)
+{
+ enum mcu_msg_type type = MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE;
+
+ return allegro_mcu_push_buffer_internal(channel, type);
+}
+
+static int allegro_mcu_push_buffer_reference(struct allegro_channel *channel)
+{
+ enum mcu_msg_type type = MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE;
+
+ return allegro_mcu_push_buffer_internal(channel, type);
+}
+
+static int allocate_buffers_internal(struct allegro_channel *channel,
+ struct list_head *list,
+ size_t n, size_t size)
+{
+ struct allegro_dev *dev = channel->dev;
+ unsigned int i;
+ int err;
+ struct allegro_buffer *buffer, *tmp;
+
+ for (i = 0; i < n; i++) {
+ buffer = kmalloc(sizeof(*buffer), GFP_KERNEL);
+ if (!buffer) {
+ err = -ENOMEM;
+ goto err;
+ }
+ INIT_LIST_HEAD(&buffer->head);
+
+ err = allegro_alloc_buffer(dev, buffer, size);
+ if (err)
+ goto err;
+ list_add(&buffer->head, list);
+ }
+
+ return 0;
+
+err:
+ list_for_each_entry_safe(buffer, tmp, list, head) {
+ list_del(&buffer->head);
+ allegro_free_buffer(dev, buffer);
+ kfree(buffer);
+ }
+ return err;
+}
+
+static void destroy_buffers_internal(struct allegro_channel *channel,
+ struct list_head *list)
+{
+ struct allegro_dev *dev = channel->dev;
+ struct allegro_buffer *buffer, *tmp;
+
+ list_for_each_entry_safe(buffer, tmp, list, head) {
+ list_del(&buffer->head);
+ allegro_free_buffer(dev, buffer);
+ kfree(buffer);
+ }
+}
+
+static void destroy_reference_buffers(struct allegro_channel *channel)
+{
+ return destroy_buffers_internal(channel, &channel->buffers_reference);
+}
+
+static void destroy_intermediate_buffers(struct allegro_channel *channel)
+{
+ return destroy_buffers_internal(channel,
+ &channel->buffers_intermediate);
+}
+
+static int allocate_intermediate_buffers(struct allegro_channel *channel,
+ size_t n, size_t size)
+{
+ return allocate_buffers_internal(channel,
+ &channel->buffers_intermediate,
+ n, size);
+}
+
+static int allocate_reference_buffers(struct allegro_channel *channel,
+ size_t n, size_t size)
+{
+ return allocate_buffers_internal(channel,
+ &channel->buffers_reference,
+ n, PAGE_ALIGN(size));
+}
+
+static ssize_t allegro_h264_write_sps(struct allegro_channel *channel,
+ void *dest, size_t n)
+{
+ struct allegro_dev *dev = channel->dev;
+ struct nal_h264_sps *sps;
+ ssize_t size;
+ unsigned int size_mb = SIZE_MACROBLOCK;
+ /* Calculation of crop units in Rec. ITU-T H.264 (04/2017) p. 76 */
+ unsigned int crop_unit_x = 2;
+ unsigned int crop_unit_y = 2;
+
+ sps = kzalloc(sizeof(*sps), GFP_KERNEL);
+ if (!sps)
+ return -ENOMEM;
+
+ sps->profile_idc = nal_h264_profile_from_v4l2(channel->profile);
+ sps->constraint_set0_flag = 0;
+ sps->constraint_set1_flag = 1;
+ sps->constraint_set2_flag = 0;
+ sps->constraint_set3_flag = 0;
+ sps->constraint_set4_flag = 0;
+ sps->constraint_set5_flag = 0;
+ sps->level_idc = nal_h264_level_from_v4l2(channel->level);
+ sps->seq_parameter_set_id = 0;
+ sps->log2_max_frame_num_minus4 = 0;
+ sps->pic_order_cnt_type = 0;
+ sps->log2_max_pic_order_cnt_lsb_minus4 = 6;
+ sps->max_num_ref_frames = 3;
+ sps->gaps_in_frame_num_value_allowed_flag = 0;
+ sps->pic_width_in_mbs_minus1 =
+ DIV_ROUND_UP(channel->width, size_mb) - 1;
+ sps->pic_height_in_map_units_minus1 =
+ DIV_ROUND_UP(channel->height, size_mb) - 1;
+ sps->frame_mbs_only_flag = 1;
+ sps->mb_adaptive_frame_field_flag = 0;
+ sps->direct_8x8_inference_flag = 1;
+ sps->frame_cropping_flag =
+ (channel->width % size_mb) || (channel->height % size_mb);
+ if (sps->frame_cropping_flag) {
+ sps->crop_left = 0;
+ sps->crop_right = (round_up(channel->width, size_mb) - channel->width) / crop_unit_x;
+ sps->crop_top = 0;
+ sps->crop_bottom = (round_up(channel->height, size_mb) - channel->height) / crop_unit_y;
+ }
+ sps->vui_parameters_present_flag = 1;
+ sps->vui.aspect_ratio_info_present_flag = 0;
+ sps->vui.overscan_info_present_flag = 0;
+ sps->vui.video_signal_type_present_flag = 1;
+ sps->vui.video_format = 1;
+ sps->vui.video_full_range_flag = 0;
+ sps->vui.colour_description_present_flag = 1;
+ sps->vui.colour_primaries = 5;
+ sps->vui.transfer_characteristics = 5;
+ sps->vui.matrix_coefficients = 5;
+ sps->vui.chroma_loc_info_present_flag = 1;
+ sps->vui.chroma_sample_loc_type_top_field = 0;
+ sps->vui.chroma_sample_loc_type_bottom_field = 0;
+ sps->vui.timing_info_present_flag = 1;
+ sps->vui.num_units_in_tick = 1;
+ sps->vui.time_scale = 50;
+ sps->vui.fixed_frame_rate_flag = 1;
+ sps->vui.nal_hrd_parameters_present_flag = 0;
+ sps->vui.vcl_hrd_parameters_present_flag = 1;
+ sps->vui.vcl_hrd_parameters.cpb_cnt_minus1 = 0;
+ sps->vui.vcl_hrd_parameters.bit_rate_scale = 0;
+ sps->vui.vcl_hrd_parameters.cpb_size_scale = 1;
+ /* See Rec. ITU-T H.264 (04/2017) p. 410 E-53 */
+ sps->vui.vcl_hrd_parameters.bit_rate_value_minus1[0] =
+ channel->bitrate_peak / (1 << (6 + sps->vui.vcl_hrd_parameters.bit_rate_scale)) - 1;
+ /* See Rec. ITU-T H.264 (04/2017) p. 410 E-54 */
+ sps->vui.vcl_hrd_parameters.cpb_size_value_minus1[0] =
+ (channel->cpb_size * 1000) / (1 << (4 + sps->vui.vcl_hrd_parameters.cpb_size_scale)) - 1;
+ sps->vui.vcl_hrd_parameters.cbr_flag[0] = 1;
+ sps->vui.vcl_hrd_parameters.initial_cpb_removal_delay_length_minus1 = 31;
+ sps->vui.vcl_hrd_parameters.cpb_removal_delay_length_minus1 = 31;
+ sps->vui.vcl_hrd_parameters.dpb_output_delay_length_minus1 = 31;
+ sps->vui.vcl_hrd_parameters.time_offset_length = 0;
+ sps->vui.low_delay_hrd_flag = 0;
+ sps->vui.pic_struct_present_flag = 1;
+ sps->vui.bitstream_restriction_flag = 0;
+
+ size = nal_h264_write_sps(&dev->plat_dev->dev, dest, n, sps);
+
+ kfree(sps);
+
+ return size;
+}
+
+static ssize_t allegro_h264_write_pps(struct allegro_channel *channel,
+ void *dest, size_t n)
+{
+ struct allegro_dev *dev = channel->dev;
+ struct nal_h264_pps *pps;
+ ssize_t size;
+
+ pps = kzalloc(sizeof(*pps), GFP_KERNEL);
+ if (!pps)
+ return -ENOMEM;
+
+ pps->pic_parameter_set_id = 0;
+ pps->seq_parameter_set_id = 0;
+ pps->entropy_coding_mode_flag = 0;
+ pps->bottom_field_pic_order_in_frame_present_flag = 0;
+ pps->num_slice_groups_minus1 = 0;
+ pps->num_ref_idx_l0_default_active_minus1 = 2;
+ pps->num_ref_idx_l1_default_active_minus1 = 2;
+ pps->weighted_pred_flag = 0;
+ pps->weighted_bipred_idc = 0;
+ pps->pic_init_qp_minus26 = 0;
+ pps->pic_init_qs_minus26 = 0;
+ pps->chroma_qp_index_offset = 0;
+ pps->deblocking_filter_control_present_flag = 1;
+ pps->constrained_intra_pred_flag = 0;
+ pps->redundant_pic_cnt_present_flag = 0;
+ pps->transform_8x8_mode_flag = 0;
+ pps->pic_scaling_matrix_present_flag = 0;
+ pps->second_chroma_qp_index_offset = 0;
+
+ size = nal_h264_write_pps(&dev->plat_dev->dev, dest, n, pps);
+
+ kfree(pps);
+
+ return size;
+}
+
+static bool allegro_channel_is_at_eos(struct allegro_channel *channel)
+{
+ bool is_at_eos = false;
+
+ switch (allegro_get_state(channel)) {
+ case ALLEGRO_STATE_STOPPED:
+ is_at_eos = true;
+ break;
+ case ALLEGRO_STATE_DRAIN:
+ case ALLEGRO_STATE_WAIT_FOR_BUFFER:
+ if (v4l2_m2m_num_src_bufs_ready(channel->fh.m2m_ctx) == 0)
+ is_at_eos = true;
+ break;
+ default:
+ break;
+ }
+
+ return is_at_eos;
+}
+
+static void allegro_channel_buf_done(struct allegro_channel *channel,
+ struct vb2_v4l2_buffer *buf,
+ enum vb2_buffer_state state)
+{
+ const struct v4l2_event eos_event = {
+ .type = V4L2_EVENT_EOS
+ };
+
+ if (allegro_channel_is_at_eos(channel)) {
+ buf->flags |= V4L2_BUF_FLAG_LAST;
+ v4l2_event_queue_fh(&channel->fh, &eos_event);
+
+ allegro_set_state(channel, ALLEGRO_STATE_STOPPED);
+ }
+
+ v4l2_m2m_buf_done(buf, state);
+}
+
+static void allegro_channel_finish_frame(struct allegro_channel *channel,
+ struct mcu_msg_encode_frame_response *msg)
+{
+ struct allegro_dev *dev = channel->dev;
+ struct vb2_v4l2_buffer *src_buf;
+ struct vb2_v4l2_buffer *dst_buf;
+ struct {
+ u32 offset;
+ u32 size;
+ } *partition;
+ enum vb2_buffer_state state = VB2_BUF_STATE_ERROR;
+ char *curr;
+ ssize_t len;
+ ssize_t free;
+
+ src_buf = v4l2_m2m_src_buf_remove(channel->fh.m2m_ctx);
+
+ dst_buf = v4l2_m2m_dst_buf_remove(channel->fh.m2m_ctx);
+ dst_buf->sequence = channel->csequence++;
+
+ if (msg->error_code) {
+ v4l2_err(&dev->v4l2_dev,
+ "channel %d: error while encoding frame: %x\n",
+ channel->mcu_channel_id, msg->error_code);
+ goto err;
+ }
+
+ if (msg->partition_table_size != 1) {
+ v4l2_warn(&dev->v4l2_dev,
+ "channel %d: only handling first partition table entry (%d entries)\n",
+ channel->mcu_channel_id, msg->partition_table_size);
+ }
+
+ if (msg->partition_table_offset +
+ msg->partition_table_size * sizeof(*partition) >
+ vb2_plane_size(&dst_buf->vb2_buf, 0)) {
+ v4l2_err(&dev->v4l2_dev,
+ "channel %d: partition table outside of dst_buf\n",
+ channel->mcu_channel_id);
+ goto err;
+ }
+
+ partition =
+ vb2_plane_vaddr(&dst_buf->vb2_buf, 0) + msg->partition_table_offset;
+ if (partition->offset + partition->size >
+ vb2_plane_size(&dst_buf->vb2_buf, 0)) {
+ v4l2_err(&dev->v4l2_dev,
+ "channel %d: encoded frame is outside of dst_buf (offset 0x%x, size 0x%x)\n",
+ channel->mcu_channel_id, partition->offset,
+ partition->size);
+ goto err;
+ }
+
+ v4l2_dbg(2, debug, &dev->v4l2_dev,
+ "channel %d: encoded frame of size %d is at offset 0x%x\n",
+ channel->mcu_channel_id, partition->size, partition->offset);
+
+ /*
+ * The payload must include the data before the partition offset,
+ * because we will put the sps and pps data there.
+ */
+ vb2_set_plane_payload(&dst_buf->vb2_buf, 0,
+ partition->offset + partition->size);
+
+ curr = vb2_plane_vaddr(&dst_buf->vb2_buf, 0);
+ free = partition->offset;
+ if (msg->is_idr) {
+ len = allegro_h264_write_sps(channel, curr, free);
+ if (len < 0) {
+ v4l2_err(&dev->v4l2_dev,
+ "not enough space for sequence parameter set: %zd left\n",
+ free);
+ goto err;
+ }
+ curr += len;
+ free -= len;
+ v4l2_dbg(1, debug, &dev->v4l2_dev,
+ "channel %d: wrote %zd byte SPS nal unit\n",
+ channel->mcu_channel_id, len);
+ }
+
+ if (msg->slice_type == AL_ENC_SLICE_TYPE_I) {
+ len = allegro_h264_write_pps(channel, curr, free);
+ if (len < 0) {
+ v4l2_err(&dev->v4l2_dev,
+ "not enough space for picture parameter set: %zd left\n",
+ free);
+ goto err;
+ }
+ curr += len;
+ free -= len;
+ v4l2_dbg(1, debug, &dev->v4l2_dev,
+ "channel %d: wrote %zd byte PPS nal unit\n",
+ channel->mcu_channel_id, len);
+ }
+
+ len = nal_h264_write_filler(&dev->plat_dev->dev, curr, free);
+ if (len < 0) {
+ v4l2_err(&dev->v4l2_dev,
+ "failed to write %zd filler data\n", free);
+ goto err;
+ }
+ curr += len;
+ free -= len;
+ v4l2_dbg(2, debug, &dev->v4l2_dev,
+ "channel %d: wrote %zd bytes filler nal unit\n",
+ channel->mcu_channel_id, len);
+
+ if (free != 0) {
+ v4l2_err(&dev->v4l2_dev,
+ "non-VCL NAL units do not fill space until VCL NAL unit: %zd bytes left\n",
+ free);
+ goto err;
+ }
+
+ state = VB2_BUF_STATE_DONE;
+
+ v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false);
+ if (msg->is_idr)
+ dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME;
+ else
+ dst_buf->flags |= V4L2_BUF_FLAG_PFRAME;
+
+ v4l2_dbg(1, debug, &dev->v4l2_dev,
+ "channel %d: encoded frame #%03d (%s%s, %d bytes)\n",
+ channel->mcu_channel_id,
+ dst_buf->sequence,
+ msg->is_idr ? "IDR, " : "",
+ msg->slice_type == AL_ENC_SLICE_TYPE_I ? "I slice" :
+ msg->slice_type == AL_ENC_SLICE_TYPE_P ? "P slice" : "unknown",
+ partition->size);
+
+err:
+ v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
+
+ allegro_channel_buf_done(channel, dst_buf, state);
+
+ v4l2_m2m_job_finish(dev->m2m_dev, channel->fh.m2m_ctx);
+}
+
+static int allegro_handle_init(struct allegro_dev *dev,
+ struct mcu_msg_init_response *msg)
+{
+ complete(&dev->init_complete);
+
+ return 0;
+}
+
+static int
+allegro_handle_create_channel(struct allegro_dev *dev,
+ struct mcu_msg_create_channel_response *msg)
+{
+ struct allegro_channel *channel;
+ int err = 0;
+
+ channel = allegro_find_channel_by_user_id(dev, msg->user_id);
+ if (IS_ERR(channel)) {
+ v4l2_warn(&dev->v4l2_dev,
+ "received %s for unknown user %d\n",
+ msg_type_name(msg->header.type),
+ msg->user_id);
+ return -EINVAL;
+ }
+
+ if (msg->error_code) {
+ v4l2_err(&dev->v4l2_dev,
+ "user %d: mcu failed to create channel: error %x\n",
+ channel->user_id, msg->error_code);
+ err = -EIO;
+ goto out;
+ }
+
+ channel->mcu_channel_id = msg->channel_id;
+ v4l2_dbg(1, debug, &dev->v4l2_dev,
+ "user %d: channel has channel id %d\n",
+ channel->user_id, channel->mcu_channel_id);
+
+ v4l2_dbg(1, debug, &dev->v4l2_dev,
+ "channel %d: intermediate buffers: %d x %d bytes\n",
+ channel->mcu_channel_id,
+ msg->int_buffers_count, msg->int_buffers_size);
+ err = allocate_intermediate_buffers(channel, msg->int_buffers_count,
+ msg->int_buffers_size);
+ if (err) {
+ v4l2_err(&dev->v4l2_dev,
+ "channel %d: failed to allocate intermediate buffers\n",
+ channel->mcu_channel_id);
+ goto out;
+ }
+ err = allegro_mcu_push_buffer_intermediate(channel);
+ if (err)
+ goto out;
+
+ v4l2_dbg(1, debug, &dev->v4l2_dev,
+ "channel %d: reference buffers: %d x %d bytes\n",
+ channel->mcu_channel_id,
+ msg->rec_buffers_count, msg->rec_buffers_size);
+ err = allocate_reference_buffers(channel, msg->rec_buffers_count,
+ msg->rec_buffers_size);
+ if (err) {
+ v4l2_err(&dev->v4l2_dev,
+ "channel %d: failed to allocate reference buffers\n",
+ channel->mcu_channel_id);
+ goto out;
+ }
+ err = allegro_mcu_push_buffer_reference(channel);
+ if (err)
+ goto out;
+
+out:
+ channel->error = err;
+ complete(&channel->completion);
+
+ /* Handled successfully, error is passed via channel->error */
+ return 0;
+}
+
+static int
+allegro_handle_destroy_channel(struct allegro_dev *dev,
+ struct mcu_msg_destroy_channel_response *msg)
+{
+ struct allegro_channel *channel;
+
+ channel = allegro_find_channel_by_channel_id(dev, msg->channel_id);
+ if (IS_ERR(channel)) {
+ v4l2_err(&dev->v4l2_dev,
+ "received %s for unknown channel %d\n",
+ msg_type_name(msg->header.type),
+ msg->channel_id);
+ return -EINVAL;
+ }
+
+ v4l2_dbg(2, debug, &dev->v4l2_dev,
+ "user %d: vcu destroyed channel %d\n",
+ channel->user_id, channel->mcu_channel_id);
+ complete(&channel->completion);
+
+ return 0;
+}
+
+static int
+allegro_handle_encode_frame(struct allegro_dev *dev,
+ struct mcu_msg_encode_frame_response *msg)
+{
+ struct allegro_channel *channel;
+
+ channel = allegro_find_channel_by_channel_id(dev, msg->channel_id);
+ if (IS_ERR(channel)) {
+ v4l2_err(&dev->v4l2_dev,
+ "received %s for unknown channel %d\n",
+ msg_type_name(msg->header.type),
+ msg->channel_id);
+ return -EINVAL;
+ }
+
+ allegro_channel_finish_frame(channel, msg);
+
+ return 0;
+}
+
+static int allegro_receive_message(struct allegro_dev *dev)
+{
+ union mcu_msg_response *msg;
+ ssize_t size;
+ int err = 0;
+
+ msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ size = allegro_mbox_read(dev, &dev->mbox_status, msg, sizeof(*msg));
+ if (size < sizeof(msg->header)) {
+ v4l2_err(&dev->v4l2_dev,
+ "invalid mbox message (%zd): must be at least %zu\n",
+ size, sizeof(msg->header));
+ err = -EINVAL;
+ goto out;
+ }
+
+ switch (msg->header.type) {
+ case MCU_MSG_TYPE_INIT:
+ err = allegro_handle_init(dev, &msg->init);
+ break;
+ case MCU_MSG_TYPE_CREATE_CHANNEL:
+ err = allegro_handle_create_channel(dev, &msg->create_channel);
+ break;
+ case MCU_MSG_TYPE_DESTROY_CHANNEL:
+ err = allegro_handle_destroy_channel(dev,
+ &msg->destroy_channel);
+ break;
+ case MCU_MSG_TYPE_ENCODE_FRAME:
+ err = allegro_handle_encode_frame(dev, &msg->encode_frame);
+ break;
+ default:
+ v4l2_warn(&dev->v4l2_dev,
+ "%s: unknown message %s\n",
+ __func__, msg_type_name(msg->header.type));
+ err = -EINVAL;
+ break;
+ }
+
+out:
+ kfree(msg);
+
+ return err;
+}
+
+static irqreturn_t allegro_hardirq(int irq, void *data)
+{
+ struct allegro_dev *dev = data;
+ unsigned int status;
+
+ regmap_read(dev->regmap, AL5_ITC_CPU_IRQ_STA, &status);
+ if (!(status & AL5_ITC_CPU_IRQ_STA_TRIGGERED))
+ return IRQ_NONE;
+
+ regmap_write(dev->regmap, AL5_ITC_CPU_IRQ_CLR, status);
+
+ return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t allegro_irq_thread(int irq, void *data)
+{
+ struct allegro_dev *dev = data;
+
+ allegro_receive_message(dev);
+
+ return IRQ_HANDLED;
+}
+
+static void allegro_copy_firmware(struct allegro_dev *dev,
+ const u8 * const buf, size_t size)
+{
+ int err = 0;
+
+ v4l2_dbg(1, debug, &dev->v4l2_dev,
+ "copy mcu firmware (%zu B) to SRAM\n", size);
+ err = regmap_bulk_write(dev->sram, 0x0, buf, size / 4);
+ if (err)
+ v4l2_err(&dev->v4l2_dev,
+ "failed to copy firmware: %d\n", err);
+}
+
+static void allegro_copy_fw_codec(struct allegro_dev *dev,
+ const u8 * const buf, size_t size)
+{
+ int err;
+ dma_addr_t icache_offset, dcache_offset;
+
+ /*
+ * The downstream allocates 600 KB for the codec firmware to have some
+ * extra space for "possible extensions." My tests were fine with
+ * allocating just enough memory for the actual firmware, but I am not
+ * sure that the firmware really does not use the remaining space.
+ */
+ err = allegro_alloc_buffer(dev, &dev->firmware, size);
+ if (err) {
+ v4l2_err(&dev->v4l2_dev,
+ "failed to allocate %zu bytes for firmware\n", size);
+ return;
+ }
+
+ v4l2_dbg(1, debug, &dev->v4l2_dev,
+ "copy codec firmware (%zd B) to phys %pad\n",
+ size, &dev->firmware.paddr);
+ memcpy(dev->firmware.vaddr, buf, size);
+
+ regmap_write(dev->regmap, AXI_ADDR_OFFSET_IP,
+ upper_32_bits(dev->firmware.paddr));
+
+ icache_offset = dev->firmware.paddr - MCU_CACHE_OFFSET;
+ v4l2_dbg(2, debug, &dev->v4l2_dev,
+ "icache_offset: msb = 0x%x, lsb = 0x%x\n",
+ upper_32_bits(icache_offset), lower_32_bits(icache_offset));
+ regmap_write(dev->regmap, AL5_ICACHE_ADDR_OFFSET_MSB,
+ upper_32_bits(icache_offset));
+ regmap_write(dev->regmap, AL5_ICACHE_ADDR_OFFSET_LSB,
+ lower_32_bits(icache_offset));
+
+ dcache_offset =
+ (dev->firmware.paddr & 0xffffffff00000000ULL) - MCU_CACHE_OFFSET;
+ v4l2_dbg(2, debug, &dev->v4l2_dev,
+ "dcache_offset: msb = 0x%x, lsb = 0x%x\n",
+ upper_32_bits(dcache_offset), lower_32_bits(dcache_offset));
+ regmap_write(dev->regmap, AL5_DCACHE_ADDR_OFFSET_MSB,
+ upper_32_bits(dcache_offset));
+ regmap_write(dev->regmap, AL5_DCACHE_ADDR_OFFSET_LSB,
+ lower_32_bits(dcache_offset));
+}
+
+static void allegro_free_fw_codec(struct allegro_dev *dev)
+{
+ allegro_free_buffer(dev, &dev->firmware);
+}
+
+/*
+ * Control functions for the MCU
+ */
+
+static int allegro_mcu_enable_interrupts(struct allegro_dev *dev)
+{
+ return regmap_write(dev->regmap, AL5_ITC_CPU_IRQ_MSK, BIT(0));
+}
+
+static int allegro_mcu_disable_interrupts(struct allegro_dev *dev)
+{
+ return regmap_write(dev->regmap, AL5_ITC_CPU_IRQ_MSK, 0);
+}
+
+static int allegro_mcu_wait_for_sleep(struct allegro_dev *dev)
+{
+ unsigned long timeout;
+ unsigned int status;
+
+ timeout = jiffies + msecs_to_jiffies(100);
+ while (regmap_read(dev->regmap, AL5_MCU_STA, &status) == 0 &&
+ status != AL5_MCU_STA_SLEEP) {
+ if (time_after(jiffies, timeout))
+ return -ETIMEDOUT;
+ cpu_relax();
+ }
+
+ return 0;
+}
+
+static int allegro_mcu_start(struct allegro_dev *dev)
+{
+ unsigned long timeout;
+ unsigned int status;
+ int err;
+
+ err = regmap_write(dev->regmap, AL5_MCU_WAKEUP, BIT(0));
+ if (err)
+ return err;
+
+ timeout = jiffies + msecs_to_jiffies(100);
+ while (regmap_read(dev->regmap, AL5_MCU_STA, &status) == 0 &&
+ status == AL5_MCU_STA_SLEEP) {
+ if (time_after(jiffies, timeout))
+ return -ETIMEDOUT;
+ cpu_relax();
+ }
+
+ err = regmap_write(dev->regmap, AL5_MCU_WAKEUP, 0);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int allegro_mcu_reset(struct allegro_dev *dev)
+{
+ int err;
+
+ err = regmap_write(dev->regmap,
+ AL5_MCU_RESET_MODE, AL5_MCU_RESET_MODE_SLEEP);
+ if (err < 0)
+ return err;
+
+ err = regmap_write(dev->regmap, AL5_MCU_RESET, AL5_MCU_RESET_SOFT);
+ if (err < 0)
+ return err;
+
+ return allegro_mcu_wait_for_sleep(dev);
+}
+
+static void allegro_destroy_channel(struct allegro_channel *channel)
+{
+ struct allegro_dev *dev = channel->dev;
+ unsigned long timeout;
+
+ if (channel_exists(channel)) {
+ reinit_completion(&channel->completion);
+ allegro_mcu_send_destroy_channel(dev, channel);
+ timeout = wait_for_completion_timeout(&channel->completion,
+ msecs_to_jiffies(5000));
+ if (timeout == 0)
+ v4l2_warn(&dev->v4l2_dev,
+ "channel %d: timeout while destroying\n",
+ channel->mcu_channel_id);
+
+ channel->mcu_channel_id = -1;
+ }
+
+ destroy_intermediate_buffers(channel);
+ destroy_reference_buffers(channel);
+
+ v4l2_ctrl_grab(channel->mpeg_video_h264_profile, false);
+ v4l2_ctrl_grab(channel->mpeg_video_h264_level, false);
+ v4l2_ctrl_grab(channel->mpeg_video_bitrate_mode, false);
+ v4l2_ctrl_grab(channel->mpeg_video_bitrate, false);
+ v4l2_ctrl_grab(channel->mpeg_video_bitrate_peak, false);
+ v4l2_ctrl_grab(channel->mpeg_video_cpb_size, false);
+ v4l2_ctrl_grab(channel->mpeg_video_gop_size, false);
+
+ if (channel->user_id != -1) {
+ clear_bit(channel->user_id, &dev->channel_user_ids);
+ channel->user_id = -1;
+ }
+}
+
+/*
+ * Create the MCU channel
+ *
+ * After the channel has been created, the picture size, format, colorspace
+ * and framerate are fixed. Also the codec, profile, bitrate, etc. cannot be
+ * changed anymore.
+ *
+ * The channel can be created only once. The MCU will accept source buffers
+ * and stream buffers only after a channel has been created.
+ */
+static int allegro_create_channel(struct allegro_channel *channel)
+{
+ struct allegro_dev *dev = channel->dev;
+ unsigned long timeout;
+ enum v4l2_mpeg_video_h264_level min_level;
+
+ if (channel_exists(channel)) {
+ v4l2_warn(&dev->v4l2_dev,
+ "channel already exists\n");
+ return 0;
+ }
+
+ channel->user_id = allegro_next_user_id(dev);
+ if (channel->user_id < 0) {
+ v4l2_err(&dev->v4l2_dev,
+ "no free channels available\n");
+ return -EBUSY;
+ }
+ set_bit(channel->user_id, &dev->channel_user_ids);
+
+ v4l2_dbg(1, debug, &dev->v4l2_dev,
+ "user %d: creating channel (%4.4s, %dx%d@%d)\n",
+ channel->user_id,
+ (char *)&channel->codec, channel->width, channel->height, 25);
+
+ min_level = select_minimum_h264_level(channel->width, channel->height);
+ if (channel->level < min_level) {
+ v4l2_warn(&dev->v4l2_dev,
+ "user %d: selected Level %s too low: increasing to Level %s\n",
+ channel->user_id,
+ v4l2_ctrl_get_menu(V4L2_CID_MPEG_VIDEO_H264_LEVEL)[channel->level],
+ v4l2_ctrl_get_menu(V4L2_CID_MPEG_VIDEO_H264_LEVEL)[min_level]);
+ channel->level = min_level;
+ }
+
+ v4l2_ctrl_grab(channel->mpeg_video_h264_profile, true);
+ v4l2_ctrl_grab(channel->mpeg_video_h264_level, true);
+ v4l2_ctrl_grab(channel->mpeg_video_bitrate_mode, true);
+ v4l2_ctrl_grab(channel->mpeg_video_bitrate, true);
+ v4l2_ctrl_grab(channel->mpeg_video_bitrate_peak, true);
+ v4l2_ctrl_grab(channel->mpeg_video_cpb_size, true);
+ v4l2_ctrl_grab(channel->mpeg_video_gop_size, true);
+
+ reinit_completion(&channel->completion);
+ allegro_mcu_send_create_channel(dev, channel);
+ timeout = wait_for_completion_timeout(&channel->completion,
+ msecs_to_jiffies(5000));
+ if (timeout == 0)
+ channel->error = -ETIMEDOUT;
+ if (channel->error)
+ goto err;
+
+ v4l2_dbg(1, debug, &dev->v4l2_dev,
+ "channel %d: accepting buffers\n",
+ channel->mcu_channel_id);
+
+ return 0;
+
+err:
+ allegro_destroy_channel(channel);
+
+ return channel->error;
+}
+
+static void allegro_set_default_params(struct allegro_channel *channel)
+{
+ channel->width = ALLEGRO_WIDTH_DEFAULT;
+ channel->height = ALLEGRO_HEIGHT_DEFAULT;
+ channel->stride = round_up(channel->width, 32);
+
+ channel->colorspace = V4L2_COLORSPACE_REC709;
+ channel->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ channel->quantization = V4L2_QUANTIZATION_DEFAULT;
+ channel->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+
+ channel->pixelformat = V4L2_PIX_FMT_NV12;
+ channel->sizeimage_raw = channel->stride * channel->height * 3 / 2;
+
+ channel->codec = V4L2_PIX_FMT_H264;
+ channel->profile = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE;
+ channel->level =
+ select_minimum_h264_level(channel->width, channel->height);
+ channel->sizeimage_encoded =
+ estimate_stream_size(channel->width, channel->height);
+
+ channel->bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
+ channel->bitrate = maximum_bitrate(channel->level);
+ channel->bitrate_peak = maximum_bitrate(channel->level);
+ channel->cpb_size = maximum_cpb_size(channel->level);
+ channel->gop_size = ALLEGRO_GOP_SIZE_DEFAULT;
+}
+
+static int allegro_queue_setup(struct vb2_queue *vq,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct allegro_channel *channel = vb2_get_drv_priv(vq);
+ struct allegro_dev *dev = channel->dev;
+
+ v4l2_dbg(2, debug, &dev->v4l2_dev,
+ "%s: queue setup[%s]: nplanes = %d\n",
+ V4L2_TYPE_IS_OUTPUT(vq->type) ? "output" : "capture",
+ *nplanes == 0 ? "REQBUFS" : "CREATE_BUFS", *nplanes);
+
+ if (*nplanes != 0) {
+ if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
+ if (sizes[0] < channel->sizeimage_raw)
+ return -EINVAL;
+ } else {
+ if (sizes[0] < channel->sizeimage_encoded)
+ return -EINVAL;
+ }
+ } else {
+ *nplanes = 1;
+ if (V4L2_TYPE_IS_OUTPUT(vq->type))
+ sizes[0] = channel->sizeimage_raw;
+ else
+ sizes[0] = channel->sizeimage_encoded;
+ }
+
+ return 0;
+}
+
+static int allegro_buf_prepare(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct allegro_channel *channel = vb2_get_drv_priv(vb->vb2_queue);
+ struct allegro_dev *dev = channel->dev;
+
+ if (allegro_get_state(channel) == ALLEGRO_STATE_DRAIN &&
+ V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type))
+ return -EBUSY;
+
+ if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
+ if (vbuf->field == V4L2_FIELD_ANY)
+ vbuf->field = V4L2_FIELD_NONE;
+ if (vbuf->field != V4L2_FIELD_NONE) {
+ v4l2_err(&dev->v4l2_dev,
+ "channel %d: unsupported field\n",
+ channel->mcu_channel_id);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static void allegro_buf_queue(struct vb2_buffer *vb)
+{
+ struct allegro_channel *channel = vb2_get_drv_priv(vb->vb2_queue);
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+ if (allegro_get_state(channel) == ALLEGRO_STATE_WAIT_FOR_BUFFER &&
+ vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ allegro_channel_buf_done(channel, vbuf, VB2_BUF_STATE_DONE);
+ return;
+ }
+
+ v4l2_m2m_buf_queue(channel->fh.m2m_ctx, vbuf);
+}
+
+static int allegro_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct allegro_channel *channel = vb2_get_drv_priv(q);
+ struct allegro_dev *dev = channel->dev;
+
+ v4l2_dbg(2, debug, &dev->v4l2_dev,
+ "%s: start streaming\n",
+ V4L2_TYPE_IS_OUTPUT(q->type) ? "output" : "capture");
+
+ if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+ channel->osequence = 0;
+ allegro_set_state(channel, ALLEGRO_STATE_ENCODING);
+ } else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ channel->csequence = 0;
+ }
+
+ return 0;
+}
+
+static void allegro_stop_streaming(struct vb2_queue *q)
+{
+ struct allegro_channel *channel = vb2_get_drv_priv(q);
+ struct allegro_dev *dev = channel->dev;
+ struct vb2_v4l2_buffer *buffer;
+
+ v4l2_dbg(2, debug, &dev->v4l2_dev,
+ "%s: stop streaming\n",
+ V4L2_TYPE_IS_OUTPUT(q->type) ? "output" : "capture");
+
+ if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+ allegro_set_state(channel, ALLEGRO_STATE_STOPPED);
+ while ((buffer = v4l2_m2m_src_buf_remove(channel->fh.m2m_ctx)))
+ v4l2_m2m_buf_done(buffer, VB2_BUF_STATE_ERROR);
+ } else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ allegro_destroy_channel(channel);
+ while ((buffer = v4l2_m2m_dst_buf_remove(channel->fh.m2m_ctx)))
+ v4l2_m2m_buf_done(buffer, VB2_BUF_STATE_ERROR);
+ }
+}
+
+static const struct vb2_ops allegro_queue_ops = {
+ .queue_setup = allegro_queue_setup,
+ .buf_prepare = allegro_buf_prepare,
+ .buf_queue = allegro_buf_queue,
+ .start_streaming = allegro_start_streaming,
+ .stop_streaming = allegro_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+static int allegro_queue_init(void *priv,
+ struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq)
+{
+ int err;
+ struct allegro_channel *channel = priv;
+
+ src_vq->dev = &channel->dev->plat_dev->dev;
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ src_vq->io_modes = VB2_DMABUF | VB2_MMAP;
+ src_vq->mem_ops = &vb2_dma_contig_memops;
+ src_vq->drv_priv = channel;
+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->ops = &allegro_queue_ops;
+ src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ src_vq->lock = &channel->dev->lock;
+ err = vb2_queue_init(src_vq);
+ if (err)
+ return err;
+
+ dst_vq->dev = &channel->dev->plat_dev->dev;
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ dst_vq->io_modes = VB2_DMABUF | VB2_MMAP;
+ dst_vq->mem_ops = &vb2_dma_contig_memops;
+ dst_vq->drv_priv = channel;
+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dst_vq->ops = &allegro_queue_ops;
+ dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ dst_vq->lock = &channel->dev->lock;
+ err = vb2_queue_init(dst_vq);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int allegro_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct allegro_channel *channel = container_of(ctrl->handler,
+ struct allegro_channel,
+ ctrl_handler);
+ struct allegro_dev *dev = channel->dev;
+
+ v4l2_dbg(1, debug, &dev->v4l2_dev,
+ "s_ctrl: %s = %d\n", v4l2_ctrl_get_name(ctrl->id), ctrl->val);
+
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+ channel->level = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ channel->bitrate_mode = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ channel->bitrate = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ channel->bitrate_peak = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE:
+ channel->cpb_size = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ channel->gop_size = ctrl->val;
+ break;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops allegro_ctrl_ops = {
+ .s_ctrl = allegro_s_ctrl,
+};
+
+static int allegro_open(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct allegro_dev *dev = video_get_drvdata(vdev);
+ struct allegro_channel *channel = NULL;
+ struct v4l2_ctrl_handler *handler;
+ u64 mask;
+
+ channel = kzalloc(sizeof(*channel), GFP_KERNEL);
+ if (!channel)
+ return -ENOMEM;
+
+ v4l2_fh_init(&channel->fh, vdev);
+ file->private_data = &channel->fh;
+ v4l2_fh_add(&channel->fh);
+
+ init_completion(&channel->completion);
+
+ channel->dev = dev;
+
+ allegro_set_default_params(channel);
+
+ handler = &channel->ctrl_handler;
+ v4l2_ctrl_handler_init(handler, 0);
+ channel->mpeg_video_h264_profile = v4l2_ctrl_new_std_menu(handler,
+ &allegro_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+ V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, 0x0,
+ V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE);
+ mask = 1 << V4L2_MPEG_VIDEO_H264_LEVEL_1B;
+ channel->mpeg_video_h264_level = v4l2_ctrl_new_std_menu(handler,
+ &allegro_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+ V4L2_MPEG_VIDEO_H264_LEVEL_5_1, mask,
+ V4L2_MPEG_VIDEO_H264_LEVEL_5_1);
+ channel->mpeg_video_bitrate_mode = v4l2_ctrl_new_std_menu(handler,
+ &allegro_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0,
+ channel->bitrate_mode);
+ channel->mpeg_video_bitrate = v4l2_ctrl_new_std(handler,
+ &allegro_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_BITRATE,
+ 0, maximum_bitrate(V4L2_MPEG_VIDEO_H264_LEVEL_5_1),
+ 1, channel->bitrate);
+ channel->mpeg_video_bitrate_peak = v4l2_ctrl_new_std(handler,
+ &allegro_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+ 0, maximum_bitrate(V4L2_MPEG_VIDEO_H264_LEVEL_5_1),
+ 1, channel->bitrate_peak);
+ channel->mpeg_video_cpb_size = v4l2_ctrl_new_std(handler,
+ &allegro_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE,
+ 0, maximum_cpb_size(V4L2_MPEG_VIDEO_H264_LEVEL_5_1),
+ 1, channel->cpb_size);
+ channel->mpeg_video_gop_size = v4l2_ctrl_new_std(handler,
+ &allegro_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+ 0, ALLEGRO_GOP_SIZE_MAX,
+ 1, channel->gop_size);
+ v4l2_ctrl_new_std(handler,
+ &allegro_ctrl_ops,
+ V4L2_CID_MIN_BUFFERS_FOR_OUTPUT,
+ 1, 32,
+ 1, 1);
+ channel->fh.ctrl_handler = handler;
+
+ channel->mcu_channel_id = -1;
+ channel->user_id = -1;
+
+ INIT_LIST_HEAD(&channel->buffers_reference);
+ INIT_LIST_HEAD(&channel->buffers_intermediate);
+
+ list_add(&channel->list, &dev->channels);
+
+ channel->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, channel,
+ allegro_queue_init);
+
+ return 0;
+}
+
+static int allegro_release(struct file *file)
+{
+ struct allegro_channel *channel = fh_to_channel(file->private_data);
+
+ v4l2_m2m_ctx_release(channel->fh.m2m_ctx);
+
+ list_del(&channel->list);
+
+ v4l2_ctrl_handler_free(&channel->ctrl_handler);
+
+ v4l2_fh_del(&channel->fh);
+ v4l2_fh_exit(&channel->fh);
+
+ kfree(channel);
+
+ return 0;
+}
+
+static int allegro_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct allegro_dev *dev = video_get_drvdata(vdev);
+
+ strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
+ strscpy(cap->card, "Allegro DVT Video Encoder", sizeof(cap->card));
+ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+ dev_name(&dev->plat_dev->dev));
+
+ return 0;
+}
+
+static int allegro_enum_fmt_vid(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f)
+{
+ if (f->index)
+ return -EINVAL;
+ switch (f->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ f->pixelformat = V4L2_PIX_FMT_NV12;
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ f->pixelformat = V4L2_PIX_FMT_H264;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int allegro_g_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct allegro_channel *channel = fh_to_channel(fh);
+
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ f->fmt.pix.width = channel->width;
+ f->fmt.pix.height = channel->height;
+
+ f->fmt.pix.colorspace = channel->colorspace;
+ f->fmt.pix.ycbcr_enc = channel->ycbcr_enc;
+ f->fmt.pix.quantization = channel->quantization;
+ f->fmt.pix.xfer_func = channel->xfer_func;
+
+ f->fmt.pix.pixelformat = channel->codec;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage = channel->sizeimage_encoded;
+
+ return 0;
+}
+
+static int allegro_try_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+
+ f->fmt.pix.width = clamp_t(__u32, f->fmt.pix.width,
+ ALLEGRO_WIDTH_MIN, ALLEGRO_WIDTH_MAX);
+ f->fmt.pix.height = clamp_t(__u32, f->fmt.pix.height,
+ ALLEGRO_HEIGHT_MIN, ALLEGRO_HEIGHT_MAX);
+
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_H264;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage =
+ estimate_stream_size(f->fmt.pix.width, f->fmt.pix.height);
+
+ return 0;
+}
+
+static int allegro_g_fmt_vid_out(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct allegro_channel *channel = fh_to_channel(fh);
+
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+
+ f->fmt.pix.width = channel->width;
+ f->fmt.pix.height = channel->height;
+
+ f->fmt.pix.colorspace = channel->colorspace;
+ f->fmt.pix.ycbcr_enc = channel->ycbcr_enc;
+ f->fmt.pix.quantization = channel->quantization;
+ f->fmt.pix.xfer_func = channel->xfer_func;
+
+ f->fmt.pix.pixelformat = channel->pixelformat;
+ f->fmt.pix.bytesperline = channel->stride;
+ f->fmt.pix.sizeimage = channel->sizeimage_raw;
+
+ return 0;
+}
+
+static int allegro_try_fmt_vid_out(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+
+ /*
+ * The firmware of the Allegro codec handles the padding internally
+ * and expects the visual frame size when configuring a channel.
+ * Therefore, unlike other encoder drivers, this driver does not round
+ * up the width and height to macroblock alignment and does not
+ * implement the selection api.
+ */
+ f->fmt.pix.width = clamp_t(__u32, f->fmt.pix.width,
+ ALLEGRO_WIDTH_MIN, ALLEGRO_WIDTH_MAX);
+ f->fmt.pix.height = clamp_t(__u32, f->fmt.pix.height,
+ ALLEGRO_HEIGHT_MIN, ALLEGRO_HEIGHT_MAX);
+
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_NV12;
+ f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 32);
+ f->fmt.pix.sizeimage =
+ f->fmt.pix.bytesperline * f->fmt.pix.height * 3 / 2;
+
+ return 0;
+}
+
+static int allegro_s_fmt_vid_out(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct allegro_channel *channel = fh_to_channel(fh);
+ int err;
+
+ err = allegro_try_fmt_vid_out(file, fh, f);
+ if (err)
+ return err;
+
+ channel->width = f->fmt.pix.width;
+ channel->height = f->fmt.pix.height;
+ channel->stride = f->fmt.pix.bytesperline;
+ channel->sizeimage_raw = f->fmt.pix.sizeimage;
+
+ channel->colorspace = f->fmt.pix.colorspace;
+ channel->ycbcr_enc = f->fmt.pix.ycbcr_enc;
+ channel->quantization = f->fmt.pix.quantization;
+ channel->xfer_func = f->fmt.pix.xfer_func;
+
+ channel->level =
+ select_minimum_h264_level(channel->width, channel->height);
+ channel->sizeimage_encoded =
+ estimate_stream_size(channel->width, channel->height);
+
+ return 0;
+}
+
+static int allegro_channel_cmd_stop(struct allegro_channel *channel)
+{
+ struct allegro_dev *dev = channel->dev;
+ struct vb2_v4l2_buffer *dst_buf;
+
+ switch (allegro_get_state(channel)) {
+ case ALLEGRO_STATE_DRAIN:
+ case ALLEGRO_STATE_WAIT_FOR_BUFFER:
+ return -EBUSY;
+ case ALLEGRO_STATE_ENCODING:
+ allegro_set_state(channel, ALLEGRO_STATE_DRAIN);
+ break;
+ default:
+ return 0;
+ }
+
+ /* If there are output buffers, they must be encoded */
+ if (v4l2_m2m_num_src_bufs_ready(channel->fh.m2m_ctx) != 0) {
+ v4l2_dbg(1, debug, &dev->v4l2_dev,
+ "channel %d: CMD_STOP: continue encoding src buffers\n",
+ channel->mcu_channel_id);
+ return 0;
+ }
+
+ /* If there are capture buffers, use it to signal EOS */
+ dst_buf = v4l2_m2m_dst_buf_remove(channel->fh.m2m_ctx);
+ if (dst_buf) {
+ v4l2_dbg(1, debug, &dev->v4l2_dev,
+ "channel %d: CMD_STOP: signaling EOS\n",
+ channel->mcu_channel_id);
+ allegro_channel_buf_done(channel, dst_buf, VB2_BUF_STATE_DONE);
+ return 0;
+ }
+
+ /*
+ * If there are no capture buffers, we need to wait for the next
+ * buffer to signal EOS.
+ */
+ v4l2_dbg(1, debug, &dev->v4l2_dev,
+ "channel %d: CMD_STOP: wait for CAPTURE buffer to signal EOS\n",
+ channel->mcu_channel_id);
+ allegro_set_state(channel, ALLEGRO_STATE_WAIT_FOR_BUFFER);
+
+ return 0;
+}
+
+static int allegro_channel_cmd_start(struct allegro_channel *channel)
+{
+ switch (allegro_get_state(channel)) {
+ case ALLEGRO_STATE_DRAIN:
+ case ALLEGRO_STATE_WAIT_FOR_BUFFER:
+ return -EBUSY;
+ case ALLEGRO_STATE_STOPPED:
+ allegro_set_state(channel, ALLEGRO_STATE_ENCODING);
+ break;
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int allegro_encoder_cmd(struct file *file, void *fh,
+ struct v4l2_encoder_cmd *cmd)
+{
+ struct allegro_channel *channel = fh_to_channel(fh);
+ int err;
+
+ err = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, cmd);
+ if (err)
+ return err;
+
+ switch (cmd->cmd) {
+ case V4L2_ENC_CMD_STOP:
+ err = allegro_channel_cmd_stop(channel);
+ break;
+ case V4L2_ENC_CMD_START:
+ err = allegro_channel_cmd_start(channel);
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+
+ return err;
+}
+
+static int allegro_enum_framesizes(struct file *file, void *fh,
+ struct v4l2_frmsizeenum *fsize)
+{
+ switch (fsize->pixel_format) {
+ case V4L2_PIX_FMT_H264:
+ case V4L2_PIX_FMT_NV12:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (fsize->index)
+ return -EINVAL;
+
+ fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
+ fsize->stepwise.min_width = ALLEGRO_WIDTH_MIN;
+ fsize->stepwise.max_width = ALLEGRO_WIDTH_MAX;
+ fsize->stepwise.step_width = 1;
+ fsize->stepwise.min_height = ALLEGRO_HEIGHT_MIN;
+ fsize->stepwise.max_height = ALLEGRO_HEIGHT_MAX;
+ fsize->stepwise.step_height = 1;
+
+ return 0;
+}
+
+static int allegro_ioctl_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct v4l2_fh *fh = file->private_data;
+ struct allegro_channel *channel = fh_to_channel(fh);
+ int err;
+
+ if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ err = allegro_create_channel(channel);
+ if (err)
+ return err;
+ }
+
+ return v4l2_m2m_streamon(file, fh->m2m_ctx, type);
+}
+
+static int allegro_subscribe_event(struct v4l2_fh *fh,
+ const struct v4l2_event_subscription *sub)
+{
+ switch (sub->type) {
+ case V4L2_EVENT_EOS:
+ return v4l2_event_subscribe(fh, sub, 0, NULL);
+ default:
+ return v4l2_ctrl_subscribe_event(fh, sub);
+ }
+}
+
+static const struct v4l2_ioctl_ops allegro_ioctl_ops = {
+ .vidioc_querycap = allegro_querycap,
+ .vidioc_enum_fmt_vid_cap = allegro_enum_fmt_vid,
+ .vidioc_enum_fmt_vid_out = allegro_enum_fmt_vid,
+ .vidioc_g_fmt_vid_cap = allegro_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = allegro_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = allegro_try_fmt_vid_cap,
+ .vidioc_g_fmt_vid_out = allegro_g_fmt_vid_out,
+ .vidioc_try_fmt_vid_out = allegro_try_fmt_vid_out,
+ .vidioc_s_fmt_vid_out = allegro_s_fmt_vid_out,
+
+ .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+
+ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
+ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
+
+ .vidioc_streamon = allegro_ioctl_streamon,
+ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
+
+ .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd,
+ .vidioc_encoder_cmd = allegro_encoder_cmd,
+ .vidioc_enum_framesizes = allegro_enum_framesizes,
+
+ .vidioc_subscribe_event = allegro_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static const struct v4l2_file_operations allegro_fops = {
+ .owner = THIS_MODULE,
+ .open = allegro_open,
+ .release = allegro_release,
+ .poll = v4l2_m2m_fop_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = v4l2_m2m_fop_mmap,
+};
+
+static int allegro_register_device(struct allegro_dev *dev)
+{
+ struct video_device *video_dev = &dev->video_dev;
+
+ strscpy(video_dev->name, "allegro", sizeof(video_dev->name));
+ video_dev->fops = &allegro_fops;
+ video_dev->ioctl_ops = &allegro_ioctl_ops;
+ video_dev->release = video_device_release_empty;
+ video_dev->lock = &dev->lock;
+ video_dev->v4l2_dev = &dev->v4l2_dev;
+ video_dev->vfl_dir = VFL_DIR_M2M;
+ video_dev->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
+ video_set_drvdata(video_dev, dev);
+
+ return video_register_device(video_dev, VFL_TYPE_GRABBER, 0);
+}
+
+static void allegro_device_run(void *priv)
+{
+ struct allegro_channel *channel = priv;
+ struct allegro_dev *dev = channel->dev;
+ struct vb2_v4l2_buffer *src_buf;
+ struct vb2_v4l2_buffer *dst_buf;
+ dma_addr_t src_y;
+ dma_addr_t src_uv;
+ dma_addr_t dst_addr;
+ unsigned long dst_size;
+
+ dst_buf = v4l2_m2m_next_dst_buf(channel->fh.m2m_ctx);
+ dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
+ dst_size = vb2_plane_size(&dst_buf->vb2_buf, 0);
+ allegro_mcu_send_put_stream_buffer(dev, channel, dst_addr, dst_size);
+
+ src_buf = v4l2_m2m_next_src_buf(channel->fh.m2m_ctx);
+ src_buf->sequence = channel->osequence++;
+
+ src_y = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
+ src_uv = src_y + (channel->stride * channel->height);
+ allegro_mcu_send_encode_frame(dev, channel, src_y, src_uv);
+}
+
+static const struct v4l2_m2m_ops allegro_m2m_ops = {
+ .device_run = allegro_device_run,
+};
+
+static int allegro_mcu_hw_init(struct allegro_dev *dev,
+ const struct fw_info *info)
+{
+ int err;
+
+ allegro_mbox_init(dev, &dev->mbox_command,
+ info->mailbox_cmd, info->mailbox_size);
+ allegro_mbox_init(dev, &dev->mbox_status,
+ info->mailbox_status, info->mailbox_size);
+
+ allegro_mcu_enable_interrupts(dev);
+
+ /* The mcu sends INIT after reset. */
+ allegro_mcu_start(dev);
+ err = allegro_mcu_wait_for_init_timeout(dev, 5000);
+ if (err < 0) {
+ v4l2_err(&dev->v4l2_dev,
+ "mcu did not send INIT after reset\n");
+ err = -EIO;
+ goto err_disable_interrupts;
+ }
+
+ err = allegro_alloc_buffer(dev, &dev->suballocator,
+ info->suballocator_size);
+ if (err) {
+ v4l2_err(&dev->v4l2_dev,
+ "failed to allocate %zu bytes for suballocator\n",
+ info->suballocator_size);
+ goto err_reset_mcu;
+ }
+
+ allegro_mcu_send_init(dev, dev->suballocator.paddr,
+ dev->suballocator.size);
+ err = allegro_mcu_wait_for_init_timeout(dev, 5000);
+ if (err < 0) {
+ v4l2_err(&dev->v4l2_dev,
+ "mcu failed to configure sub-allocator\n");
+ err = -EIO;
+ goto err_free_suballocator;
+ }
+
+ return 0;
+
+err_free_suballocator:
+ allegro_free_buffer(dev, &dev->suballocator);
+err_reset_mcu:
+ allegro_mcu_reset(dev);
+err_disable_interrupts:
+ allegro_mcu_disable_interrupts(dev);
+
+ return err;
+}
+
+static int allegro_mcu_hw_deinit(struct allegro_dev *dev)
+{
+ int err;
+
+ err = allegro_mcu_reset(dev);
+ if (err)
+ v4l2_warn(&dev->v4l2_dev,
+ "mcu failed to enter sleep state\n");
+
+ err = allegro_mcu_disable_interrupts(dev);
+ if (err)
+ v4l2_warn(&dev->v4l2_dev,
+ "failed to disable interrupts\n");
+
+ allegro_free_buffer(dev, &dev->suballocator);
+
+ return 0;
+}
+
+static void allegro_fw_callback(const struct firmware *fw, void *context)
+{
+ struct allegro_dev *dev = context;
+ const char *fw_codec_name = "al5e.fw";
+ const struct firmware *fw_codec;
+ int err;
+ const struct fw_info *info;
+
+ if (!fw)
+ return;
+
+ v4l2_dbg(1, debug, &dev->v4l2_dev,
+ "requesting codec firmware '%s'\n", fw_codec_name);
+ err = request_firmware(&fw_codec, fw_codec_name, &dev->plat_dev->dev);
+ if (err)
+ goto err_release_firmware;
+
+ info = allegro_get_firmware_info(dev, fw, fw_codec);
+ if (!info) {
+ v4l2_err(&dev->v4l2_dev, "firmware is not supported\n");
+ goto err_release_firmware_codec;
+ }
+
+ v4l2_info(&dev->v4l2_dev,
+ "using mcu firmware version '%s'\n", info->version);
+
+ /* Ensure that the mcu is sleeping at the reset vector */
+ err = allegro_mcu_reset(dev);
+ if (err) {
+ v4l2_err(&dev->v4l2_dev, "failed to reset mcu\n");
+ goto err_release_firmware_codec;
+ }
+
+ allegro_copy_firmware(dev, fw->data, fw->size);
+ allegro_copy_fw_codec(dev, fw_codec->data, fw_codec->size);
+
+ err = allegro_mcu_hw_init(dev, info);
+ if (err) {
+ v4l2_err(&dev->v4l2_dev, "failed to initialize mcu\n");
+ goto err_free_fw_codec;
+ }
+
+ dev->m2m_dev = v4l2_m2m_init(&allegro_m2m_ops);
+ if (IS_ERR(dev->m2m_dev)) {
+ v4l2_err(&dev->v4l2_dev, "failed to init mem2mem device\n");
+ goto err_mcu_hw_deinit;
+ }
+
+ err = allegro_register_device(dev);
+ if (err) {
+ v4l2_err(&dev->v4l2_dev, "failed to register video device\n");
+ goto err_m2m_release;
+ }
+
+ v4l2_dbg(1, debug, &dev->v4l2_dev,
+ "allegro codec registered as /dev/video%d\n",
+ dev->video_dev.num);
+
+ release_firmware(fw_codec);
+ release_firmware(fw);
+
+ return;
+
+err_m2m_release:
+ v4l2_m2m_release(dev->m2m_dev);
+ dev->m2m_dev = NULL;
+err_mcu_hw_deinit:
+ allegro_mcu_hw_deinit(dev);
+err_free_fw_codec:
+ allegro_free_fw_codec(dev);
+err_release_firmware_codec:
+ release_firmware(fw_codec);
+err_release_firmware:
+ release_firmware(fw);
+}
+
+static int allegro_firmware_request_nowait(struct allegro_dev *dev)
+{
+ const char *fw = "al5e_b.fw";
+
+ v4l2_dbg(1, debug, &dev->v4l2_dev,
+ "requesting firmware '%s'\n", fw);
+ return request_firmware_nowait(THIS_MODULE, true, fw,
+ &dev->plat_dev->dev, GFP_KERNEL, dev,
+ allegro_fw_callback);
+}
+
+static int allegro_probe(struct platform_device *pdev)
+{
+ struct allegro_dev *dev;
+ struct resource *res, *sram_res;
+ int ret;
+ int irq;
+ void __iomem *regs, *sram_regs;
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+ dev->plat_dev = pdev;
+ init_completion(&dev->init_complete);
+ INIT_LIST_HEAD(&dev->channels);
+
+ mutex_init(&dev->lock);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
+ if (!res) {
+ dev_err(&pdev->dev,
+ "regs resource missing from device tree\n");
+ return -EINVAL;
+ }
+ regs = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res));
+ if (IS_ERR(regs)) {
+ dev_err(&pdev->dev, "failed to map registers\n");
+ return PTR_ERR(regs);
+ }
+ dev->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+ &allegro_regmap_config);
+ if (IS_ERR(dev->regmap)) {
+ dev_err(&pdev->dev, "failed to init regmap\n");
+ return PTR_ERR(dev->regmap);
+ }
+
+ sram_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram");
+ if (!sram_res) {
+ dev_err(&pdev->dev,
+ "sram resource missing from device tree\n");
+ return -EINVAL;
+ }
+ sram_regs = devm_ioremap_nocache(&pdev->dev,
+ sram_res->start,
+ resource_size(sram_res));
+ if (IS_ERR(sram_regs)) {
+ dev_err(&pdev->dev, "failed to map sram\n");
+ return PTR_ERR(sram_regs);
+ }
+ dev->sram = devm_regmap_init_mmio(&pdev->dev, sram_regs,
+ &allegro_sram_config);
+ if (IS_ERR(dev->sram)) {
+ dev_err(&pdev->dev, "failed to init sram\n");
+ return PTR_ERR(dev->sram);
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "failed to get irq resource\n");
+ return irq;
+ }
+ ret = devm_request_threaded_irq(&pdev->dev, irq,
+ allegro_hardirq,
+ allegro_irq_thread,
+ IRQF_SHARED, dev_name(&pdev->dev), dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to request irq: %d\n", ret);
+ return ret;
+ }
+
+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, dev);
+
+ ret = allegro_firmware_request_nowait(dev);
+ if (ret < 0) {
+ v4l2_err(&dev->v4l2_dev,
+ "failed to request firmware: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int allegro_remove(struct platform_device *pdev)
+{
+ struct allegro_dev *dev = platform_get_drvdata(pdev);
+
+ video_unregister_device(&dev->video_dev);
+ if (dev->m2m_dev)
+ v4l2_m2m_release(dev->m2m_dev);
+ allegro_mcu_hw_deinit(dev);
+ allegro_free_fw_codec(dev);
+
+ v4l2_device_unregister(&dev->v4l2_dev);
+
+ return 0;
+}
+
+static const struct of_device_id allegro_dt_ids[] = {
+ { .compatible = "allegro,al5e-1.1" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, allegro_dt_ids);
+
+static struct platform_driver allegro_driver = {
+ .probe = allegro_probe,
+ .remove = allegro_remove,
+ .driver = {
+ .name = "allegro",
+ .of_match_table = of_match_ptr(allegro_dt_ids),
+ },
+};
+
+module_platform_driver(allegro_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michael Tretter <kernel@pengutronix.de>");
+MODULE_DESCRIPTION("Allegro DVT encoder driver");
diff --git a/drivers/staging/media/allegro-dvt/nal-h264.c b/drivers/staging/media/allegro-dvt/nal-h264.c
new file mode 100644
index 000000000000..4e14b77851e1
--- /dev/null
+++ b/drivers/staging/media/allegro-dvt/nal-h264.c
@@ -0,0 +1,1001 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Pengutronix, Michael Tretter <kernel@pengutronix.de>
+ *
+ * Convert NAL units between raw byte sequence payloads (RBSP) and C structs
+ *
+ * The conversion is defined in "ITU-T Rec. H.264 (04/2017) Advanced video
+ * coding for generic audiovisual services". Decoder drivers may use the
+ * parser to parse RBSP from encoded streams and configure the hardware, if
+ * the hardware is not able to parse RBSP itself. Encoder drivers may use the
+ * generator to generate the RBSP for SPS/PPS nal units and add them to the
+ * encoded stream if the hardware does not generate the units.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/v4l2-controls.h>
+
+#include <linux/device.h>
+#include <linux/export.h>
+#include <linux/log2.h>
+
+#include "nal-h264.h"
+
+/*
+ * See Rec. ITU-T H.264 (04/2017) Table 7-1 – NAL unit type codes, syntax
+ * element categories, and NAL unit type classes
+ */
+enum nal_unit_type {
+ SEQUENCE_PARAMETER_SET = 7,
+ PICTURE_PARAMETER_SET = 8,
+ FILLER_DATA = 12,
+};
+
+struct rbsp;
+
+struct nal_h264_ops {
+ int (*rbsp_bit)(struct rbsp *rbsp, int *val);
+ int (*rbsp_bits)(struct rbsp *rbsp, int n, unsigned int *val);
+ int (*rbsp_uev)(struct rbsp *rbsp, unsigned int *val);
+ int (*rbsp_sev)(struct rbsp *rbsp, int *val);
+};
+
+/**
+ * struct rbsp - State object for handling a raw byte sequence payload
+ * @data: pointer to the data of the rbsp
+ * @size: maximum size of the data of the rbsp
+ * @pos: current bit position inside the rbsp
+ * @num_consecutive_zeros: number of zeros before @pos
+ * @ops: per datatype functions for interacting with the rbsp
+ * @error: an error occurred while handling the rbsp
+ *
+ * This struct is passed around the various parsing functions and tracks the
+ * current position within the raw byte sequence payload.
+ *
+ * The @ops field allows to separate the operation, i.e., reading/writing a
+ * value from/to that rbsp, from the structure of the NAL unit. This allows to
+ * have a single function for iterating the NAL unit, while @ops has function
+ * pointers for handling each type in the rbsp.
+ */
+struct rbsp {
+ u8 *data;
+ size_t size;
+ unsigned int pos;
+ unsigned int num_consecutive_zeros;
+ struct nal_h264_ops *ops;
+ int error;
+};
+
+static void rbsp_init(struct rbsp *rbsp, void *addr, size_t size,
+ struct nal_h264_ops *ops)
+{
+ if (!rbsp)
+ return;
+
+ rbsp->data = addr;
+ rbsp->size = size;
+ rbsp->pos = 0;
+ rbsp->ops = ops;
+ rbsp->error = 0;
+}
+
+/**
+ * nal_h264_profile_from_v4l2() - Get profile_idc for v4l2 h264 profile
+ * @profile: the profile as &enum v4l2_mpeg_video_h264_profile
+ *
+ * Convert the &enum v4l2_mpeg_video_h264_profile to profile_idc as specified
+ * in Rec. ITU-T H.264 (04/2017) A.2.
+ *
+ * Return: the profile_idc for the passed level
+ */
+int nal_h264_profile_from_v4l2(enum v4l2_mpeg_video_h264_profile profile)
+{
+ switch (profile) {
+ case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
+ return 66;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
+ return 77;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED:
+ return 88;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
+ return 100;
+ default:
+ return -EINVAL;
+ }
+}
+
+/**
+ * nal_h264_level_from_v4l2() - Get level_idc for v4l2 h264 level
+ * @level: the level as &enum v4l2_mpeg_video_h264_level
+ *
+ * Convert the &enum v4l2_mpeg_video_h264_level to level_idc as specified in
+ * Rec. ITU-T H.264 (04/2017) A.3.2.
+ *
+ * Return: the level_idc for the passed level
+ */
+int nal_h264_level_from_v4l2(enum v4l2_mpeg_video_h264_level level)
+{
+ switch (level) {
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
+ return 10;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
+ return 9;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
+ return 11;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
+ return 12;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
+ return 13;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
+ return 20;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
+ return 21;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
+ return 22;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
+ return 30;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
+ return 31;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
+ return 32;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
+ return 40;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
+ return 41;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
+ return 42;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
+ return 50;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
+ return 51;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int rbsp_read_bits(struct rbsp *rbsp, int n, unsigned int *value);
+static int rbsp_write_bits(struct rbsp *rbsp, int n, unsigned int value);
+
+/*
+ * When reading or writing, the emulation_prevention_three_byte is detected
+ * only when the 2 one bits need to be inserted. Therefore, we are not
+ * actually adding the 0x3 byte, but the 2 one bits and the six 0 bits of the
+ * next byte.
+ */
+#define EMULATION_PREVENTION_THREE_BYTE (0x3 << 6)
+
+static int add_emulation_prevention_three_byte(struct rbsp *rbsp)
+{
+ rbsp->num_consecutive_zeros = 0;
+ rbsp_write_bits(rbsp, 8, EMULATION_PREVENTION_THREE_BYTE);
+
+ return 0;
+}
+
+static int discard_emulation_prevention_three_byte(struct rbsp *rbsp)
+{
+ unsigned int tmp = 0;
+
+ rbsp->num_consecutive_zeros = 0;
+ rbsp_read_bits(rbsp, 8, &tmp);
+ if (tmp != EMULATION_PREVENTION_THREE_BYTE)
+ return -EINVAL;
+
+ return 0;
+}
+
+static inline int rbsp_read_bit(struct rbsp *rbsp)
+{
+ int shift;
+ int ofs;
+ int bit;
+ int err;
+
+ if (rbsp->num_consecutive_zeros == 22) {
+ err = discard_emulation_prevention_three_byte(rbsp);
+ if (err)
+ return err;
+ }
+
+ shift = 7 - (rbsp->pos % 8);
+ ofs = rbsp->pos / 8;
+ if (ofs >= rbsp->size)
+ return -EINVAL;
+
+ bit = (rbsp->data[ofs] >> shift) & 1;
+
+ rbsp->pos++;
+
+ if (bit == 1 ||
+ (rbsp->num_consecutive_zeros < 7 && (rbsp->pos % 8 == 0)))
+ rbsp->num_consecutive_zeros = 0;
+ else
+ rbsp->num_consecutive_zeros++;
+
+ return bit;
+}
+
+static inline int rbsp_write_bit(struct rbsp *rbsp, bool value)
+{
+ int shift;
+ int ofs;
+
+ if (rbsp->num_consecutive_zeros == 22)
+ add_emulation_prevention_three_byte(rbsp);
+
+ shift = 7 - (rbsp->pos % 8);
+ ofs = rbsp->pos / 8;
+ if (ofs >= rbsp->size)
+ return -EINVAL;
+
+ rbsp->data[ofs] &= ~(1 << shift);
+ rbsp->data[ofs] |= value << shift;
+
+ rbsp->pos++;
+
+ if (value == 1 ||
+ (rbsp->num_consecutive_zeros < 7 && (rbsp->pos % 8 == 0))) {
+ rbsp->num_consecutive_zeros = 0;
+ } else {
+ rbsp->num_consecutive_zeros++;
+ }
+
+ return 0;
+}
+
+static inline int rbsp_read_bits(struct rbsp *rbsp, int n, unsigned int *value)
+{
+ int i;
+ int bit;
+ unsigned int tmp = 0;
+
+ if (n > 8 * sizeof(*value))
+ return -EINVAL;
+
+ for (i = n; i > 0; i--) {
+ bit = rbsp_read_bit(rbsp);
+ if (bit < 0)
+ return bit;
+ tmp |= bit << (i - 1);
+ }
+
+ if (value)
+ *value = tmp;
+
+ return 0;
+}
+
+static int rbsp_write_bits(struct rbsp *rbsp, int n, unsigned int value)
+{
+ int ret;
+
+ if (n > 8 * sizeof(value))
+ return -EINVAL;
+
+ while (n--) {
+ ret = rbsp_write_bit(rbsp, (value >> n) & 1);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rbsp_read_uev(struct rbsp *rbsp, unsigned int *value)
+{
+ int leading_zero_bits = 0;
+ unsigned int tmp = 0;
+ int ret;
+
+ while ((ret = rbsp_read_bit(rbsp)) == 0)
+ leading_zero_bits++;
+ if (ret < 0)
+ return ret;
+
+ if (leading_zero_bits > 0) {
+ ret = rbsp_read_bits(rbsp, leading_zero_bits, &tmp);
+ if (ret)
+ return ret;
+ }
+
+ if (value)
+ *value = (1 << leading_zero_bits) - 1 + tmp;
+
+ return 0;
+}
+
+static int rbsp_write_uev(struct rbsp *rbsp, unsigned int *value)
+{
+ int ret;
+ int leading_zero_bits;
+
+ if (!value)
+ return -EINVAL;
+
+ leading_zero_bits = ilog2(*value + 1);
+
+ ret = rbsp_write_bits(rbsp, leading_zero_bits, 0);
+ if (ret)
+ return ret;
+
+ return rbsp_write_bits(rbsp, leading_zero_bits + 1, *value + 1);
+}
+
+static int rbsp_read_sev(struct rbsp *rbsp, int *value)
+{
+ int ret;
+ unsigned int tmp;
+
+ ret = rbsp_read_uev(rbsp, &tmp);
+ if (ret)
+ return ret;
+
+ if (value) {
+ if (tmp & 1)
+ *value = (tmp + 1) / 2;
+ else
+ *value = -(tmp / 2);
+ }
+
+ return 0;
+}
+
+static int rbsp_write_sev(struct rbsp *rbsp, int *value)
+{
+ unsigned int tmp;
+
+ if (!value)
+ return -EINVAL;
+
+ if (*value > 0)
+ tmp = (2 * (*value)) | 1;
+ else
+ tmp = -2 * (*value);
+
+ return rbsp_write_uev(rbsp, &tmp);
+}
+
+static int __rbsp_write_bit(struct rbsp *rbsp, int *value)
+{
+ return rbsp_write_bit(rbsp, *value);
+}
+
+static int __rbsp_write_bits(struct rbsp *rbsp, int n, unsigned int *value)
+{
+ return rbsp_write_bits(rbsp, n, *value);
+}
+
+static struct nal_h264_ops write = {
+ .rbsp_bit = __rbsp_write_bit,
+ .rbsp_bits = __rbsp_write_bits,
+ .rbsp_uev = rbsp_write_uev,
+ .rbsp_sev = rbsp_write_sev,
+};
+
+static int __rbsp_read_bit(struct rbsp *rbsp, int *value)
+{
+ int tmp = rbsp_read_bit(rbsp);
+
+ if (tmp < 0)
+ return tmp;
+ *value = tmp;
+
+ return 0;
+}
+
+static struct nal_h264_ops read = {
+ .rbsp_bit = __rbsp_read_bit,
+ .rbsp_bits = rbsp_read_bits,
+ .rbsp_uev = rbsp_read_uev,
+ .rbsp_sev = rbsp_read_sev,
+};
+
+static inline void rbsp_bit(struct rbsp *rbsp, int *value)
+{
+ if (rbsp->error)
+ return;
+ rbsp->error = rbsp->ops->rbsp_bit(rbsp, value);
+}
+
+static inline void rbsp_bits(struct rbsp *rbsp, int n, int *value)
+{
+ if (rbsp->error)
+ return;
+ rbsp->error = rbsp->ops->rbsp_bits(rbsp, n, value);
+}
+
+static inline void rbsp_uev(struct rbsp *rbsp, unsigned int *value)
+{
+ if (rbsp->error)
+ return;
+ rbsp->error = rbsp->ops->rbsp_uev(rbsp, value);
+}
+
+static inline void rbsp_sev(struct rbsp *rbsp, int *value)
+{
+ if (rbsp->error)
+ return;
+ rbsp->error = rbsp->ops->rbsp_sev(rbsp, value);
+}
+
+static void nal_h264_rbsp_trailing_bits(struct rbsp *rbsp)
+{
+ unsigned int rbsp_stop_one_bit = 1;
+ unsigned int rbsp_alignment_zero_bit = 0;
+
+ rbsp_bit(rbsp, &rbsp_stop_one_bit);
+ rbsp_bits(rbsp, round_up(rbsp->pos, 8) - rbsp->pos,
+ &rbsp_alignment_zero_bit);
+}
+
+static void nal_h264_write_start_code_prefix(struct rbsp *rbsp)
+{
+ u8 *p = rbsp->data + DIV_ROUND_UP(rbsp->pos, 8);
+ int i = 4;
+
+ if (DIV_ROUND_UP(rbsp->pos, 8) + i > rbsp->size) {
+ rbsp->error = -EINVAL;
+ return;
+ }
+
+ p[0] = 0x00;
+ p[1] = 0x00;
+ p[2] = 0x00;
+ p[3] = 0x01;
+
+ rbsp->pos += i * 8;
+}
+
+static void nal_h264_read_start_code_prefix(struct rbsp *rbsp)
+{
+ u8 *p = rbsp->data + DIV_ROUND_UP(rbsp->pos, 8);
+ int i = 4;
+
+ if (DIV_ROUND_UP(rbsp->pos, 8) + i > rbsp->size) {
+ rbsp->error = -EINVAL;
+ return;
+ }
+
+ if (p[0] != 0x00 || p[1] != 0x00 || p[2] != 0x00 || p[3] != 0x01) {
+ rbsp->error = -EINVAL;
+ return;
+ }
+
+ rbsp->pos += i * 8;
+}
+
+static void nal_h264_write_filler_data(struct rbsp *rbsp)
+{
+ u8 *p = rbsp->data + DIV_ROUND_UP(rbsp->pos, 8);
+ int i;
+
+ /* Keep 1 byte extra for terminating the NAL unit */
+ i = rbsp->size - DIV_ROUND_UP(rbsp->pos, 8) - 1;
+ memset(p, 0xff, i);
+ rbsp->pos += i * 8;
+}
+
+static void nal_h264_read_filler_data(struct rbsp *rbsp)
+{
+ u8 *p = rbsp->data + DIV_ROUND_UP(rbsp->pos, 8);
+
+ while (*p == 0xff) {
+ if (DIV_ROUND_UP(rbsp->pos, 8) > rbsp->size) {
+ rbsp->error = -EINVAL;
+ return;
+ }
+
+ p++;
+ rbsp->pos += 8;
+ }
+}
+
+static void nal_h264_rbsp_hrd_parameters(struct rbsp *rbsp,
+ struct nal_h264_hrd_parameters *hrd)
+{
+ unsigned int i;
+
+ if (!hrd) {
+ rbsp->error = -EINVAL;
+ return;
+ }
+
+ rbsp_uev(rbsp, &hrd->cpb_cnt_minus1);
+ rbsp_bits(rbsp, 4, &hrd->bit_rate_scale);
+ rbsp_bits(rbsp, 4, &hrd->cpb_size_scale);
+
+ for (i = 0; i <= hrd->cpb_cnt_minus1; i++) {
+ rbsp_uev(rbsp, &hrd->bit_rate_value_minus1[i]);
+ rbsp_uev(rbsp, &hrd->cpb_size_value_minus1[i]);
+ rbsp_bit(rbsp, &hrd->cbr_flag[i]);
+ }
+
+ rbsp_bits(rbsp, 5, &hrd->initial_cpb_removal_delay_length_minus1);
+ rbsp_bits(rbsp, 5, &hrd->cpb_removal_delay_length_minus1);
+ rbsp_bits(rbsp, 5, &hrd->dpb_output_delay_length_minus1);
+ rbsp_bits(rbsp, 5, &hrd->time_offset_length);
+}
+
+static void nal_h264_rbsp_vui_parameters(struct rbsp *rbsp,
+ struct nal_h264_vui_parameters *vui)
+{
+ if (!vui) {
+ rbsp->error = -EINVAL;
+ return;
+ }
+
+ rbsp_bit(rbsp, &vui->aspect_ratio_info_present_flag);
+ if (vui->aspect_ratio_info_present_flag) {
+ rbsp_bits(rbsp, 8, &vui->aspect_ratio_idc);
+ if (vui->aspect_ratio_idc == 255) {
+ rbsp_bits(rbsp, 16, &vui->sar_width);
+ rbsp_bits(rbsp, 16, &vui->sar_height);
+ }
+ }
+
+ rbsp_bit(rbsp, &vui->overscan_info_present_flag);
+ if (vui->overscan_info_present_flag)
+ rbsp_bit(rbsp, &vui->overscan_appropriate_flag);
+
+ rbsp_bit(rbsp, &vui->video_signal_type_present_flag);
+ if (vui->video_signal_type_present_flag) {
+ rbsp_bits(rbsp, 3, &vui->video_format);
+ rbsp_bit(rbsp, &vui->video_full_range_flag);
+
+ rbsp_bit(rbsp, &vui->colour_description_present_flag);
+ if (vui->colour_description_present_flag) {
+ rbsp_bits(rbsp, 8, &vui->colour_primaries);
+ rbsp_bits(rbsp, 8, &vui->transfer_characteristics);
+ rbsp_bits(rbsp, 8, &vui->matrix_coefficients);
+ }
+ }
+
+ rbsp_bit(rbsp, &vui->chroma_loc_info_present_flag);
+ if (vui->chroma_loc_info_present_flag) {
+ rbsp_uev(rbsp, &vui->chroma_sample_loc_type_top_field);
+ rbsp_uev(rbsp, &vui->chroma_sample_loc_type_bottom_field);
+ }
+
+ rbsp_bit(rbsp, &vui->timing_info_present_flag);
+ if (vui->timing_info_present_flag) {
+ rbsp_bits(rbsp, 32, &vui->num_units_in_tick);
+ rbsp_bits(rbsp, 32, &vui->time_scale);
+ rbsp_bit(rbsp, &vui->fixed_frame_rate_flag);
+ }
+
+ rbsp_bit(rbsp, &vui->nal_hrd_parameters_present_flag);
+ if (vui->nal_hrd_parameters_present_flag)
+ nal_h264_rbsp_hrd_parameters(rbsp, &vui->nal_hrd_parameters);
+
+ rbsp_bit(rbsp, &vui->vcl_hrd_parameters_present_flag);
+ if (vui->vcl_hrd_parameters_present_flag)
+ nal_h264_rbsp_hrd_parameters(rbsp, &vui->vcl_hrd_parameters);
+
+ if (vui->nal_hrd_parameters_present_flag ||
+ vui->vcl_hrd_parameters_present_flag)
+ rbsp_bit(rbsp, &vui->low_delay_hrd_flag);
+
+ rbsp_bit(rbsp, &vui->pic_struct_present_flag);
+
+ rbsp_bit(rbsp, &vui->bitstream_restriction_flag);
+ if (vui->bitstream_restriction_flag) {
+ rbsp_bit(rbsp, &vui->motion_vectors_over_pic_boundaries_flag);
+ rbsp_uev(rbsp, &vui->max_bytes_per_pic_denom);
+ rbsp_uev(rbsp, &vui->max_bits_per_mb_denom);
+ rbsp_uev(rbsp, &vui->log2_max_mv_length_horizontal);
+ rbsp_uev(rbsp, &vui->log21_max_mv_length_vertical);
+ rbsp_uev(rbsp, &vui->max_num_reorder_frames);
+ rbsp_uev(rbsp, &vui->max_dec_frame_buffering);
+ }
+}
+
+static void nal_h264_rbsp_sps(struct rbsp *rbsp, struct nal_h264_sps *sps)
+{
+ unsigned int i;
+
+ if (!sps) {
+ rbsp->error = -EINVAL;
+ return;
+ }
+
+ rbsp_bits(rbsp, 8, &sps->profile_idc);
+ rbsp_bit(rbsp, &sps->constraint_set0_flag);
+ rbsp_bit(rbsp, &sps->constraint_set1_flag);
+ rbsp_bit(rbsp, &sps->constraint_set2_flag);
+ rbsp_bit(rbsp, &sps->constraint_set3_flag);
+ rbsp_bit(rbsp, &sps->constraint_set4_flag);
+ rbsp_bit(rbsp, &sps->constraint_set5_flag);
+ rbsp_bits(rbsp, 2, &sps->reserved_zero_2bits);
+ rbsp_bits(rbsp, 8, &sps->level_idc);
+
+ rbsp_uev(rbsp, &sps->seq_parameter_set_id);
+
+ if (sps->profile_idc == 100 || sps->profile_idc == 110 ||
+ sps->profile_idc == 122 || sps->profile_idc == 244 ||
+ sps->profile_idc == 44 || sps->profile_idc == 83 ||
+ sps->profile_idc == 86 || sps->profile_idc == 118 ||
+ sps->profile_idc == 128 || sps->profile_idc == 138 ||
+ sps->profile_idc == 139 || sps->profile_idc == 134 ||
+ sps->profile_idc == 135) {
+ rbsp_uev(rbsp, &sps->chroma_format_idc);
+
+ if (sps->chroma_format_idc == 3)
+ rbsp_bit(rbsp, &sps->separate_colour_plane_flag);
+ rbsp_uev(rbsp, &sps->bit_depth_luma_minus8);
+ rbsp_uev(rbsp, &sps->bit_depth_chroma_minus8);
+ rbsp_bit(rbsp, &sps->qpprime_y_zero_transform_bypass_flag);
+ rbsp_bit(rbsp, &sps->seq_scaling_matrix_present_flag);
+ if (sps->seq_scaling_matrix_present_flag)
+ rbsp->error = -EINVAL;
+ }
+
+ rbsp_uev(rbsp, &sps->log2_max_frame_num_minus4);
+
+ rbsp_uev(rbsp, &sps->pic_order_cnt_type);
+ switch (sps->pic_order_cnt_type) {
+ case 0:
+ rbsp_uev(rbsp, &sps->log2_max_pic_order_cnt_lsb_minus4);
+ break;
+ case 1:
+ rbsp_bit(rbsp, &sps->delta_pic_order_always_zero_flag);
+ rbsp_sev(rbsp, &sps->offset_for_non_ref_pic);
+ rbsp_sev(rbsp, &sps->offset_for_top_to_bottom_field);
+
+ rbsp_uev(rbsp, &sps->num_ref_frames_in_pic_order_cnt_cycle);
+ for (i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; i++)
+ rbsp_sev(rbsp, &sps->offset_for_ref_frame[i]);
+ break;
+ default:
+ rbsp->error = -EINVAL;
+ break;
+ }
+
+ rbsp_uev(rbsp, &sps->max_num_ref_frames);
+ rbsp_bit(rbsp, &sps->gaps_in_frame_num_value_allowed_flag);
+ rbsp_uev(rbsp, &sps->pic_width_in_mbs_minus1);
+ rbsp_uev(rbsp, &sps->pic_height_in_map_units_minus1);
+
+ rbsp_bit(rbsp, &sps->frame_mbs_only_flag);
+ if (!sps->frame_mbs_only_flag)
+ rbsp_bit(rbsp, &sps->mb_adaptive_frame_field_flag);
+
+ rbsp_bit(rbsp, &sps->direct_8x8_inference_flag);
+
+ rbsp_bit(rbsp, &sps->frame_cropping_flag);
+ if (sps->frame_cropping_flag) {
+ rbsp_uev(rbsp, &sps->crop_left);
+ rbsp_uev(rbsp, &sps->crop_right);
+ rbsp_uev(rbsp, &sps->crop_top);
+ rbsp_uev(rbsp, &sps->crop_bottom);
+ }
+
+ rbsp_bit(rbsp, &sps->vui_parameters_present_flag);
+ if (sps->vui_parameters_present_flag)
+ nal_h264_rbsp_vui_parameters(rbsp, &sps->vui);
+}
+
+static void nal_h264_rbsp_pps(struct rbsp *rbsp, struct nal_h264_pps *pps)
+{
+ int i;
+
+ rbsp_uev(rbsp, &pps->pic_parameter_set_id);
+ rbsp_uev(rbsp, &pps->seq_parameter_set_id);
+ rbsp_bit(rbsp, &pps->entropy_coding_mode_flag);
+ rbsp_bit(rbsp, &pps->bottom_field_pic_order_in_frame_present_flag);
+ rbsp_uev(rbsp, &pps->num_slice_groups_minus1);
+ if (pps->num_slice_groups_minus1 > 0) {
+ rbsp_uev(rbsp, &pps->slice_group_map_type);
+ switch (pps->slice_group_map_type) {
+ case 0:
+ for (i = 0; i < pps->num_slice_groups_minus1; i++)
+ rbsp_uev(rbsp, &pps->run_length_minus1[i]);
+ break;
+ case 2:
+ for (i = 0; i < pps->num_slice_groups_minus1; i++) {
+ rbsp_uev(rbsp, &pps->top_left[i]);
+ rbsp_uev(rbsp, &pps->bottom_right[i]);
+ }
+ break;
+ case 3: case 4: case 5:
+ rbsp_bit(rbsp, &pps->slice_group_change_direction_flag);
+ rbsp_uev(rbsp, &pps->slice_group_change_rate_minus1);
+ break;
+ case 6:
+ rbsp_uev(rbsp, &pps->pic_size_in_map_units_minus1);
+ for (i = 0; i < pps->pic_size_in_map_units_minus1; i++)
+ rbsp_bits(rbsp,
+ order_base_2(pps->num_slice_groups_minus1 + 1),
+ &pps->slice_group_id[i]);
+ break;
+ default:
+ break;
+ }
+ }
+ rbsp_uev(rbsp, &pps->num_ref_idx_l0_default_active_minus1);
+ rbsp_uev(rbsp, &pps->num_ref_idx_l1_default_active_minus1);
+ rbsp_bit(rbsp, &pps->weighted_pred_flag);
+ rbsp_bits(rbsp, 2, &pps->weighted_bipred_idc);
+ rbsp_sev(rbsp, &pps->pic_init_qp_minus26);
+ rbsp_sev(rbsp, &pps->pic_init_qs_minus26);
+ rbsp_sev(rbsp, &pps->chroma_qp_index_offset);
+ rbsp_bit(rbsp, &pps->deblocking_filter_control_present_flag);
+ rbsp_bit(rbsp, &pps->constrained_intra_pred_flag);
+ rbsp_bit(rbsp, &pps->redundant_pic_cnt_present_flag);
+ if (/* more_rbsp_data() */ false) {
+ rbsp_bit(rbsp, &pps->transform_8x8_mode_flag);
+ rbsp_bit(rbsp, &pps->pic_scaling_matrix_present_flag);
+ if (pps->pic_scaling_matrix_present_flag)
+ rbsp->error = -EINVAL;
+ rbsp_sev(rbsp, &pps->second_chroma_qp_index_offset);
+ }
+}
+
+/**
+ * nal_h264_write_sps() - Write SPS NAL unit into RBSP format
+ * @dev: device pointer
+ * @dest: the buffer that is filled with RBSP data
+ * @n: maximum size of @dest in bytes
+ * @sps: &struct nal_h264_sps to convert to RBSP
+ *
+ * Convert @sps to RBSP data and write it into @dest.
+ *
+ * The size of the SPS NAL unit is not known in advance and this function will
+ * fail, if @dest does not hold sufficient space for the SPS NAL unit.
+ *
+ * Return: number of bytes written to @dest or negative error code
+ */
+ssize_t nal_h264_write_sps(const struct device *dev,
+ void *dest, size_t n, struct nal_h264_sps *sps)
+{
+ struct rbsp rbsp;
+ unsigned int forbidden_zero_bit = 0;
+ unsigned int nal_ref_idc = 0;
+ unsigned int nal_unit_type = SEQUENCE_PARAMETER_SET;
+
+ if (!dest)
+ return -EINVAL;
+
+ rbsp_init(&rbsp, dest, n, &write);
+
+ nal_h264_write_start_code_prefix(&rbsp);
+
+ rbsp_bit(&rbsp, &forbidden_zero_bit);
+ rbsp_bits(&rbsp, 2, &nal_ref_idc);
+ rbsp_bits(&rbsp, 5, &nal_unit_type);
+
+ nal_h264_rbsp_sps(&rbsp, sps);
+
+ nal_h264_rbsp_trailing_bits(&rbsp);
+
+ if (rbsp.error)
+ return rbsp.error;
+
+ return DIV_ROUND_UP(rbsp.pos, 8);
+}
+EXPORT_SYMBOL_GPL(nal_h264_write_sps);
+
+/**
+ * nal_h264_read_sps() - Read SPS NAL unit from RBSP format
+ * @dev: device pointer
+ * @sps: the &struct nal_h264_sps to fill from the RBSP data
+ * @src: the buffer that contains the RBSP data
+ * @n: size of @src in bytes
+ *
+ * Read RBSP data from @src and use it to fill @sps.
+ *
+ * Return: number of bytes read from @src or negative error code
+ */
+ssize_t nal_h264_read_sps(const struct device *dev,
+ struct nal_h264_sps *sps, void *src, size_t n)
+{
+ struct rbsp rbsp;
+ unsigned int forbidden_zero_bit;
+ unsigned int nal_ref_idc;
+ unsigned int nal_unit_type;
+
+ if (!src)
+ return -EINVAL;
+
+ rbsp_init(&rbsp, src, n, &read);
+
+ nal_h264_read_start_code_prefix(&rbsp);
+
+ rbsp_bit(&rbsp, &forbidden_zero_bit);
+ rbsp_bits(&rbsp, 2, &nal_ref_idc);
+ rbsp_bits(&rbsp, 5, &nal_unit_type);
+
+ if (rbsp.error ||
+ forbidden_zero_bit != 0 ||
+ nal_ref_idc != 0 ||
+ nal_unit_type != SEQUENCE_PARAMETER_SET)
+ return -EINVAL;
+
+ nal_h264_rbsp_sps(&rbsp, sps);
+
+ nal_h264_rbsp_trailing_bits(&rbsp);
+
+ if (rbsp.error)
+ return rbsp.error;
+
+ return DIV_ROUND_UP(rbsp.pos, 8);
+}
+EXPORT_SYMBOL_GPL(nal_h264_read_sps);
+
+/**
+ * nal_h264_write_pps() - Write PPS NAL unit into RBSP format
+ * @dev: device pointer
+ * @dest: the buffer that is filled with RBSP data
+ * @n: maximum size of @dest in bytes
+ * @pps: &struct nal_h264_pps to convert to RBSP
+ *
+ * Convert @pps to RBSP data and write it into @dest.
+ *
+ * The size of the PPS NAL unit is not known in advance and this function will
+ * fail, if @dest does not hold sufficient space for the PPS NAL unit.
+ *
+ * Return: number of bytes written to @dest or negative error code
+ */
+ssize_t nal_h264_write_pps(const struct device *dev,
+ void *dest, size_t n, struct nal_h264_pps *pps)
+{
+ struct rbsp rbsp;
+ unsigned int forbidden_zero_bit = 0;
+ unsigned int nal_ref_idc = 0;
+ unsigned int nal_unit_type = PICTURE_PARAMETER_SET;
+
+ if (!dest)
+ return -EINVAL;
+
+ rbsp_init(&rbsp, dest, n, &write);
+
+ nal_h264_write_start_code_prefix(&rbsp);
+
+ /* NAL unit header */
+ rbsp_bit(&rbsp, &forbidden_zero_bit);
+ rbsp_bits(&rbsp, 2, &nal_ref_idc);
+ rbsp_bits(&rbsp, 5, &nal_unit_type);
+
+ nal_h264_rbsp_pps(&rbsp, pps);
+
+ nal_h264_rbsp_trailing_bits(&rbsp);
+
+ if (rbsp.error)
+ return rbsp.error;
+
+ return DIV_ROUND_UP(rbsp.pos, 8);
+}
+EXPORT_SYMBOL_GPL(nal_h264_write_pps);
+
+/**
+ * nal_h264_read_pps() - Read PPS NAL unit from RBSP format
+ * @dev: device pointer
+ * @pps: the &struct nal_h264_pps to fill from the RBSP data
+ * @src: the buffer that contains the RBSP data
+ * @n: size of @src in bytes
+ *
+ * Read RBSP data from @src and use it to fill @pps.
+ *
+ * Return: number of bytes read from @src or negative error code
+ */
+ssize_t nal_h264_read_pps(const struct device *dev,
+ struct nal_h264_pps *pps, void *src, size_t n)
+{
+ struct rbsp rbsp;
+
+ if (!src)
+ return -EINVAL;
+
+ rbsp_init(&rbsp, src, n, &read);
+
+ nal_h264_read_start_code_prefix(&rbsp);
+
+ /* NAL unit header */
+ rbsp.pos += 8;
+
+ nal_h264_rbsp_pps(&rbsp, pps);
+
+ nal_h264_rbsp_trailing_bits(&rbsp);
+
+ if (rbsp.error)
+ return rbsp.error;
+
+ return DIV_ROUND_UP(rbsp.pos, 8);
+}
+EXPORT_SYMBOL_GPL(nal_h264_read_pps);
+
+/**
+ * nal_h264_write_filler() - Write filler data RBSP
+ * @dev: device pointer
+ * @dest: buffer to fill with filler data
+ * @n: size of the buffer to fill with filler data
+ *
+ * Write a filler data RBSP to @dest with a size of @n bytes and return the
+ * number of written filler data bytes.
+ *
+ * Use this function to generate dummy data in an RBSP data stream that can be
+ * safely ignored by h264 decoders.
+ *
+ * The RBSP format of the filler data is specified in Rec. ITU-T H.264
+ * (04/2017) 7.3.2.7 Filler data RBSP syntax.
+ *
+ * Return: number of filler data bytes (including marker) or negative error
+ */
+ssize_t nal_h264_write_filler(const struct device *dev, void *dest, size_t n)
+{
+ struct rbsp rbsp;
+ unsigned int forbidden_zero_bit = 0;
+ unsigned int nal_ref_idc = 0;
+ unsigned int nal_unit_type = FILLER_DATA;
+
+ if (!dest)
+ return -EINVAL;
+
+ rbsp_init(&rbsp, dest, n, &write);
+
+ nal_h264_write_start_code_prefix(&rbsp);
+
+ rbsp_bit(&rbsp, &forbidden_zero_bit);
+ rbsp_bits(&rbsp, 2, &nal_ref_idc);
+ rbsp_bits(&rbsp, 5, &nal_unit_type);
+
+ nal_h264_write_filler_data(&rbsp);
+
+ nal_h264_rbsp_trailing_bits(&rbsp);
+
+ return DIV_ROUND_UP(rbsp.pos, 8);
+}
+EXPORT_SYMBOL_GPL(nal_h264_write_filler);
+
+/**
+ * nal_h264_read_filler() - Read filler data RBSP
+ * @dev: device pointer
+ * @src: buffer with RBSP data that is read
+ * @n: maximum size of src that shall be read
+ *
+ * Read a filler data RBSP from @src up to a maximum size of @n bytes and
+ * return the size of the filler data in bytes including the marker.
+ *
+ * This function is used to parse filler data and skip the respective bytes in
+ * the RBSP data.
+ *
+ * The RBSP format of the filler data is specified in Rec. ITU-T H.264
+ * (04/2017) 7.3.2.7 Filler data RBSP syntax.
+ *
+ * Return: number of filler data bytes (including marker) or negative error
+ */
+ssize_t nal_h264_read_filler(const struct device *dev, void *src, size_t n)
+{
+ struct rbsp rbsp;
+ unsigned int forbidden_zero_bit;
+ unsigned int nal_ref_idc;
+ unsigned int nal_unit_type;
+
+ if (!src)
+ return -EINVAL;
+
+ rbsp_init(&rbsp, src, n, &read);
+
+ nal_h264_read_start_code_prefix(&rbsp);
+
+ rbsp_bit(&rbsp, &forbidden_zero_bit);
+ rbsp_bits(&rbsp, 2, &nal_ref_idc);
+ rbsp_bits(&rbsp, 5, &nal_unit_type);
+
+ if (rbsp.error)
+ return rbsp.error;
+ if (forbidden_zero_bit != 0 ||
+ nal_ref_idc != 0 ||
+ nal_unit_type != FILLER_DATA)
+ return -EINVAL;
+
+ nal_h264_read_filler_data(&rbsp);
+ nal_h264_rbsp_trailing_bits(&rbsp);
+
+ if (rbsp.error)
+ return rbsp.error;
+
+ return DIV_ROUND_UP(rbsp.pos, 8);
+}
+EXPORT_SYMBOL_GPL(nal_h264_read_filler);
diff --git a/drivers/staging/media/allegro-dvt/nal-h264.h b/drivers/staging/media/allegro-dvt/nal-h264.h
new file mode 100644
index 000000000000..2ba7cbced7a5
--- /dev/null
+++ b/drivers/staging/media/allegro-dvt/nal-h264.h
@@ -0,0 +1,208 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2019 Pengutronix, Michael Tretter <kernel@pengutronix.de>
+ *
+ * Convert NAL units between raw byte sequence payloads (RBSP) and C structs.
+ */
+
+#ifndef __NAL_H264_H__
+#define __NAL_H264_H__
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+/**
+ * struct nal_h264_hdr_parameters - HDR parameters
+ *
+ * C struct representation of the sequence parameter set NAL unit as defined by
+ * Rec. ITU-T H.264 (04/2017) E.1.2 HRD parameters syntax.
+ */
+struct nal_h264_hrd_parameters {
+ unsigned int cpb_cnt_minus1;
+ unsigned int bit_rate_scale;
+ unsigned int cpb_size_scale;
+ struct {
+ int bit_rate_value_minus1[16];
+ int cpb_size_value_minus1[16];
+ unsigned int cbr_flag[16];
+ };
+ unsigned int initial_cpb_removal_delay_length_minus1;
+ unsigned int cpb_removal_delay_length_minus1;
+ unsigned int dpb_output_delay_length_minus1;
+ unsigned int time_offset_length;
+};
+
+/**
+ * struct nal_h264_vui_parameters - VUI parameters
+ *
+ * C struct representation of the VUI parameters as defined by Rec. ITU-T
+ * H.264 (04/2017) E.1.1 VUI parameters syntax.
+ */
+struct nal_h264_vui_parameters {
+ unsigned int aspect_ratio_info_present_flag;
+ struct {
+ unsigned int aspect_ratio_idc;
+ unsigned int sar_width;
+ unsigned int sar_height;
+ };
+ unsigned int overscan_info_present_flag;
+ unsigned int overscan_appropriate_flag;
+ unsigned int video_signal_type_present_flag;
+ struct {
+ unsigned int video_format;
+ unsigned int video_full_range_flag;
+ unsigned int colour_description_present_flag;
+ struct {
+ unsigned int colour_primaries;
+ unsigned int transfer_characteristics;
+ unsigned int matrix_coefficients;
+ };
+ };
+ unsigned int chroma_loc_info_present_flag;
+ struct {
+ unsigned int chroma_sample_loc_type_top_field;
+ unsigned int chroma_sample_loc_type_bottom_field;
+ };
+ unsigned int timing_info_present_flag;
+ struct {
+ unsigned int num_units_in_tick;
+ unsigned int time_scale;
+ unsigned int fixed_frame_rate_flag;
+ };
+ unsigned int nal_hrd_parameters_present_flag;
+ struct nal_h264_hrd_parameters nal_hrd_parameters;
+ unsigned int vcl_hrd_parameters_present_flag;
+ struct nal_h264_hrd_parameters vcl_hrd_parameters;
+ unsigned int low_delay_hrd_flag;
+ unsigned int pic_struct_present_flag;
+ unsigned int bitstream_restriction_flag;
+ struct {
+ unsigned int motion_vectors_over_pic_boundaries_flag;
+ unsigned int max_bytes_per_pic_denom;
+ unsigned int max_bits_per_mb_denom;
+ unsigned int log2_max_mv_length_horizontal;
+ unsigned int log21_max_mv_length_vertical;
+ unsigned int max_num_reorder_frames;
+ unsigned int max_dec_frame_buffering;
+ };
+};
+
+/**
+ * struct nal_h264_sps - Sequence parameter set
+ *
+ * C struct representation of the sequence parameter set NAL unit as defined by
+ * Rec. ITU-T H.264 (04/2017) 7.3.2.1.1 Sequence parameter set data syntax.
+ */
+struct nal_h264_sps {
+ unsigned int profile_idc;
+ unsigned int constraint_set0_flag;
+ unsigned int constraint_set1_flag;
+ unsigned int constraint_set2_flag;
+ unsigned int constraint_set3_flag;
+ unsigned int constraint_set4_flag;
+ unsigned int constraint_set5_flag;
+ unsigned int reserved_zero_2bits;
+ unsigned int level_idc;
+ unsigned int seq_parameter_set_id;
+ struct {
+ unsigned int chroma_format_idc;
+ unsigned int separate_colour_plane_flag;
+ unsigned int bit_depth_luma_minus8;
+ unsigned int bit_depth_chroma_minus8;
+ unsigned int qpprime_y_zero_transform_bypass_flag;
+ unsigned int seq_scaling_matrix_present_flag;
+ };
+ unsigned int log2_max_frame_num_minus4;
+ unsigned int pic_order_cnt_type;
+ union {
+ unsigned int log2_max_pic_order_cnt_lsb_minus4;
+ struct {
+ unsigned int delta_pic_order_always_zero_flag;
+ int offset_for_non_ref_pic;
+ int offset_for_top_to_bottom_field;
+ unsigned int num_ref_frames_in_pic_order_cnt_cycle;
+ int offset_for_ref_frame[255];
+ };
+ };
+ unsigned int max_num_ref_frames;
+ unsigned int gaps_in_frame_num_value_allowed_flag;
+ unsigned int pic_width_in_mbs_minus1;
+ unsigned int pic_height_in_map_units_minus1;
+ unsigned int frame_mbs_only_flag;
+ unsigned int mb_adaptive_frame_field_flag;
+ unsigned int direct_8x8_inference_flag;
+ unsigned int frame_cropping_flag;
+ struct {
+ unsigned int crop_left;
+ unsigned int crop_right;
+ unsigned int crop_top;
+ unsigned int crop_bottom;
+ };
+ unsigned int vui_parameters_present_flag;
+ struct nal_h264_vui_parameters vui;
+};
+
+/**
+ * struct nal_h264_pps - Picture parameter set
+ *
+ * C struct representation of the picture parameter set NAL unit as defined by
+ * Rec. ITU-T H.264 (04/2017) 7.3.2.2 Picture parameter set RBSP syntax.
+ */
+struct nal_h264_pps {
+ unsigned int pic_parameter_set_id;
+ unsigned int seq_parameter_set_id;
+ unsigned int entropy_coding_mode_flag;
+ unsigned int bottom_field_pic_order_in_frame_present_flag;
+ unsigned int num_slice_groups_minus1;
+ unsigned int slice_group_map_type;
+ union {
+ unsigned int run_length_minus1[8];
+ struct {
+ unsigned int top_left[8];
+ unsigned int bottom_right[8];
+ };
+ struct {
+ unsigned int slice_group_change_direction_flag;
+ unsigned int slice_group_change_rate_minus1;
+ };
+ struct {
+ unsigned int pic_size_in_map_units_minus1;
+ unsigned int slice_group_id[8];
+ };
+ };
+ unsigned int num_ref_idx_l0_default_active_minus1;
+ unsigned int num_ref_idx_l1_default_active_minus1;
+ unsigned int weighted_pred_flag;
+ unsigned int weighted_bipred_idc;
+ int pic_init_qp_minus26;
+ int pic_init_qs_minus26;
+ int chroma_qp_index_offset;
+ unsigned int deblocking_filter_control_present_flag;
+ unsigned int constrained_intra_pred_flag;
+ unsigned int redundant_pic_cnt_present_flag;
+ struct {
+ unsigned int transform_8x8_mode_flag;
+ unsigned int pic_scaling_matrix_present_flag;
+ int second_chroma_qp_index_offset;
+ };
+};
+
+int nal_h264_profile_from_v4l2(enum v4l2_mpeg_video_h264_profile profile);
+int nal_h264_level_from_v4l2(enum v4l2_mpeg_video_h264_level level);
+
+ssize_t nal_h264_write_sps(const struct device *dev,
+ void *dest, size_t n, struct nal_h264_sps *sps);
+ssize_t nal_h264_read_sps(const struct device *dev,
+ struct nal_h264_sps *sps, void *src, size_t n);
+void nal_h264_print_sps(const struct device *dev, struct nal_h264_sps *sps);
+
+ssize_t nal_h264_write_pps(const struct device *dev,
+ void *dest, size_t n, struct nal_h264_pps *pps);
+ssize_t nal_h264_read_pps(const struct device *dev,
+ struct nal_h264_pps *pps, void *src, size_t n);
+void nal_h264_print_pps(const struct device *dev, struct nal_h264_pps *pps);
+
+ssize_t nal_h264_write_filler(const struct device *dev, void *dest, size_t n);
+ssize_t nal_h264_read_filler(const struct device *dev, void *src, size_t n);
+
+#endif /* __NAL_H264_H__ */
diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.c b/drivers/staging/media/bcm2048/radio-bcm2048.c
index 09903ffb13ba..2c60a1fb6350 100644
--- a/drivers/staging/media/bcm2048/radio-bcm2048.c
+++ b/drivers/staging/media/bcm2048/radio-bcm2048.c
@@ -2310,11 +2310,6 @@ static int bcm2048_vidioc_querycap(struct file *file, void *priv,
strscpy(capability->card, BCM2048_DRIVER_CARD,
sizeof(capability->card));
snprintf(capability->bus_info, 32, "I2C: 0x%X", bdev->client->addr);
- capability->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO |
- V4L2_CAP_HW_FREQ_SEEK;
- capability->capabilities = capability->device_caps |
- V4L2_CAP_DEVICE_CAPS;
-
return 0;
}
@@ -2570,6 +2565,8 @@ static const struct video_device bcm2048_viddev_template = {
.name = BCM2048_DRIVER_NAME,
.release = video_device_release_empty,
.ioctl_ops = &bcm2048_ioctl_ops,
+ .device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO |
+ V4L2_CAP_HW_FREQ_SEEK,
};
/*
diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c
index 30e2edc0cec5..52397ad0e3e2 100644
--- a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c
+++ b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c
@@ -1251,10 +1251,10 @@ static int ipipe_s_config(struct v4l2_subdev *sd, struct vpfe_ipipe_config *cfg)
struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
unsigned int i;
int rval = 0;
+ struct ipipe_module_params *params;
for (i = 0; i < ARRAY_SIZE(ipipe_modules); i++) {
const struct ipipe_module_if *module_if;
- struct ipipe_module_params *params;
void *from, *to;
size_t size;
@@ -1265,25 +1265,30 @@ static int ipipe_s_config(struct v4l2_subdev *sd, struct vpfe_ipipe_config *cfg)
from = *(void **)((void *)cfg + module_if->config_offset);
params = kmalloc(sizeof(*params), GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
to = (void *)params + module_if->param_offset;
size = module_if->param_size;
if (to && from && size) {
if (copy_from_user(to, (void __user *)from, size)) {
rval = -EFAULT;
- break;
+ goto error_free;
}
rval = module_if->set(ipipe, to);
if (rval)
- goto error;
+ goto error_free;
} else if (to && !from && size) {
rval = module_if->set(ipipe, NULL);
if (rval)
- goto error;
+ goto error_free;
}
kfree(params);
}
-error:
+ return rval;
+
+error_free:
+ kfree(params);
return rval;
}
@@ -1772,7 +1777,7 @@ vpfe_ipipe_init(struct vpfe_ipipe_device *ipipe, struct platform_device *pdev)
struct media_pad *pads = &ipipe->pads[0];
struct v4l2_subdev *sd = &ipipe->subdev;
struct media_entity *me = &sd->entity;
- struct resource *res, *memres;
+ struct resource *res, *res2, *memres;
res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
if (!res)
@@ -1786,11 +1791,11 @@ vpfe_ipipe_init(struct vpfe_ipipe_device *ipipe, struct platform_device *pdev)
if (!ipipe->base_addr)
goto error_release;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 6);
- if (!res)
+ res2 = platform_get_resource(pdev, IORESOURCE_MEM, 6);
+ if (!res2)
goto error_unmap;
- ipipe->isp5_base_addr = ioremap_nocache(res->start,
- resource_size(res));
+ ipipe->isp5_base_addr = ioremap_nocache(res2->start,
+ resource_size(res2));
if (!ipipe->isp5_base_addr)
goto error_unmap;
diff --git a/drivers/staging/media/davinci_vpfe/dm365_isif.c b/drivers/staging/media/davinci_vpfe/dm365_isif.c
index 46fd8184fc77..05a997f7aa5d 100644
--- a/drivers/staging/media/davinci_vpfe/dm365_isif.c
+++ b/drivers/staging/media/davinci_vpfe/dm365_isif.c
@@ -816,7 +816,7 @@ isif_config_dfc(struct vpfe_isif_device *isif, struct vpfe_isif_dfc *vdfc)
/* Correct whole line or partial */
if (vdfc->corr_whole_line)
- val |= 1 << ISIF_VDFC_CORR_WHOLE_LN_SHIFT;
+ val |= BIT(ISIF_VDFC_CORR_WHOLE_LN_SHIFT);
/* level shift value */
val |= (vdfc->def_level_shift & ISIF_VDFC_LEVEL_SHFT_MASK) <<
@@ -844,7 +844,7 @@ isif_config_dfc(struct vpfe_isif_device *isif, struct vpfe_isif_dfc *vdfc)
val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL);
/* set DFCMARST and set DFCMWR */
- val |= 1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT;
+ val |= BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT);
val |= 1;
isif_write(isif->isif_cfg.base_addr, val, DFCMEMCTL);
@@ -875,7 +875,7 @@ isif_config_dfc(struct vpfe_isif_device *isif, struct vpfe_isif_dfc *vdfc)
}
val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL);
/* clear DFCMARST and set DFCMWR */
- val &= ~(1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT);
+ val &= ~BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT);
val |= 1;
isif_write(isif->isif_cfg.base_addr, val, DFCMEMCTL);
@@ -1135,7 +1135,7 @@ static int isif_config_raw(struct v4l2_subdev *sd, int mode)
isif_write(isif->isif_cfg.base_addr, val, CGAMMAWD);
/* Configure DPCM compression settings */
if (params->v4l2_pix_fmt == V4L2_PIX_FMT_SGRBG10DPCM8) {
- val = 1 << ISIF_DPCM_EN_SHIFT;
+ val = BIT(ISIF_DPCM_EN_SHIFT);
val |= (params->dpcm_predictor &
ISIF_DPCM_PREDICTOR_MASK) << ISIF_DPCM_PREDICTOR_SHIFT;
}
diff --git a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c
index 57b93605bc58..9dc28ffe38d5 100644
--- a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c
+++ b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c
@@ -158,7 +158,7 @@ static irqreturn_t vpfe_isr(int irq, void *dev_id)
{
struct vpfe_device *vpfe_dev = dev_id;
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_isr\n");
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "%s\n", __func__);
vpfe_isif_buffer_isr(&vpfe_dev->vpfe_isif);
vpfe_resizer_buffer_isr(&vpfe_dev->vpfe_resizer);
return IRQ_HANDLED;
@@ -169,7 +169,7 @@ static irqreturn_t vpfe_vdint1_isr(int irq, void *dev_id)
{
struct vpfe_device *vpfe_dev = dev_id;
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_vdint1_isr\n");
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "%s\n", __func__);
vpfe_isif_vidint1_isr(&vpfe_dev->vpfe_isif);
return IRQ_HANDLED;
}
@@ -179,7 +179,7 @@ static irqreturn_t vpfe_imp_dma_isr(int irq, void *dev_id)
{
struct vpfe_device *vpfe_dev = dev_id;
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_imp_dma_isr\n");
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "%s\n", __func__);
vpfe_ipipeif_ss_buffer_isr(&vpfe_dev->vpfe_ipipeif);
vpfe_resizer_dma_isr(&vpfe_dev->vpfe_resizer);
return IRQ_HANDLED;
@@ -691,7 +691,7 @@ static int vpfe_remove(struct platform_device *pdev)
{
struct vpfe_device *vpfe_dev = platform_get_drvdata(pdev);
- v4l2_info(pdev->dev.driver, "vpfe_remove\n");
+ v4l2_info(pdev->dev.driver, "%s\n", __func__);
kzfree(vpfe_dev->sd);
vpfe_detach_irq(vpfe_dev);
diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.c b/drivers/staging/media/davinci_vpfe/vpfe_video.c
index 510202a3b091..ab6bc452d9f6 100644
--- a/drivers/staging/media/davinci_vpfe/vpfe_video.c
+++ b/drivers/staging/media/davinci_vpfe/vpfe_video.c
@@ -419,6 +419,9 @@ static int vpfe_open(struct file *file)
/* If decoder is not initialized. initialize it */
if (!video->initialized && vpfe_update_pipe_state(video)) {
mutex_unlock(&video->lock);
+ v4l2_fh_del(&handle->vfh);
+ v4l2_fh_exit(&handle->vfh);
+ kfree(handle);
return -ENODEV;
}
/* Increment device users counter */
@@ -609,10 +612,6 @@ static int vpfe_querycap(struct file *file, void *priv,
v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querycap\n");
- if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
- else
- cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS;
strscpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver));
@@ -1625,6 +1624,11 @@ int vpfe_video_register(struct vpfe_video_device *video,
video->video_dev.v4l2_dev = vdev;
+ if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ video->video_dev.device_caps = V4L2_CAP_VIDEO_CAPTURE;
+ else
+ video->video_dev.device_caps = V4L2_CAP_VIDEO_OUTPUT;
+ video->video_dev.device_caps |= V4L2_CAP_STREAMING;
ret = video_register_device(&video->video_dev, VFL_TYPE_GRABBER, -1);
if (ret < 0)
pr_err("%s: could not register video device (%d)\n",
diff --git a/drivers/staging/media/hantro/Kconfig b/drivers/staging/media/hantro/Kconfig
new file mode 100644
index 000000000000..be133bbaa68a
--- /dev/null
+++ b/drivers/staging/media/hantro/Kconfig
@@ -0,0 +1,23 @@
+# SPDX-License-Identifier: GPL-2.0
+config VIDEO_HANTRO
+ tristate "Hantro VPU driver"
+ depends on ARCH_ROCKCHIP || COMPILE_TEST
+ depends on VIDEO_DEV && VIDEO_V4L2 && MEDIA_CONTROLLER
+ depends on MEDIA_CONTROLLER_REQUEST_API
+ select VIDEOBUF2_DMA_CONTIG
+ select VIDEOBUF2_VMALLOC
+ select V4L2_MEM2MEM_DEV
+ help
+ Support for the Hantro IP based Video Processing Unit present on
+ Rockchip SoC, which accelerates video and image encoding and
+ decoding.
+ To compile this driver as a module, choose M here: the module
+ will be called hantro-vpu.
+
+config VIDEO_HANTRO_ROCKCHIP
+ bool "Hantro VPU Rockchip support"
+ depends on VIDEO_HANTRO
+ depends on ARCH_ROCKCHIP || COMPILE_TEST
+ default y
+ help
+ Enable support for RK3288 and RK3399 SoCs.
diff --git a/drivers/staging/media/hantro/Makefile b/drivers/staging/media/hantro/Makefile
new file mode 100644
index 000000000000..1584acdbf4a3
--- /dev/null
+++ b/drivers/staging/media/hantro/Makefile
@@ -0,0 +1,15 @@
+obj-$(CONFIG_VIDEO_HANTRO) += hantro-vpu.o
+
+hantro-vpu-y += \
+ hantro_drv.o \
+ hantro_v4l2.o \
+ hantro_h1_jpeg_enc.o \
+ hantro_g1_mpeg2_dec.o \
+ rk3399_vpu_hw_jpeg_enc.o \
+ rk3399_vpu_hw_mpeg2_dec.o \
+ hantro_jpeg.o \
+ hantro_mpeg2.o
+
+hantro-vpu-$(CONFIG_VIDEO_HANTRO_ROCKCHIP) += \
+ rk3288_vpu_hw.o \
+ rk3399_vpu_hw.o
diff --git a/drivers/staging/media/rockchip/vpu/TODO b/drivers/staging/media/hantro/TODO
index fa0c94057007..fa0c94057007 100644
--- a/drivers/staging/media/rockchip/vpu/TODO
+++ b/drivers/staging/media/hantro/TODO
diff --git a/drivers/staging/media/hantro/hantro.h b/drivers/staging/media/hantro/hantro.h
new file mode 100644
index 000000000000..62dcca9ff19c
--- /dev/null
+++ b/drivers/staging/media/hantro/hantro.h
@@ -0,0 +1,351 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Hantro VPU codec driver
+ *
+ * Copyright 2018 Google LLC.
+ * Tomasz Figa <tfiga@chromium.org>
+ *
+ * Based on s5p-mfc driver by Samsung Electronics Co., Ltd.
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ */
+
+#ifndef HANTRO_H_
+#define HANTRO_H_
+
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+#include <linux/wait.h>
+#include <linux/clk.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "hantro_hw.h"
+
+#define MPEG2_MB_DIM 16
+#define MPEG2_MB_WIDTH(w) DIV_ROUND_UP(w, MPEG2_MB_DIM)
+#define MPEG2_MB_HEIGHT(h) DIV_ROUND_UP(h, MPEG2_MB_DIM)
+
+#define JPEG_MB_DIM 16
+#define JPEG_MB_WIDTH(w) DIV_ROUND_UP(w, JPEG_MB_DIM)
+#define JPEG_MB_HEIGHT(h) DIV_ROUND_UP(h, JPEG_MB_DIM)
+
+struct hantro_ctx;
+struct hantro_codec_ops;
+
+#define HANTRO_JPEG_ENCODER BIT(0)
+#define HANTRO_ENCODERS 0x0000ffff
+
+#define HANTRO_MPEG2_DECODER BIT(16)
+#define HANTRO_DECODERS 0xffff0000
+
+/**
+ * struct hantro_irq - irq handler and name
+ *
+ * @name: irq name for device tree lookup
+ * @handler: interrupt handler
+ */
+struct hantro_irq {
+ const char *name;
+ irqreturn_t (*handler)(int irq, void *priv);
+};
+
+/**
+ * struct hantro_variant - information about VPU hardware variant
+ *
+ * @enc_offset: Offset from VPU base to encoder registers.
+ * @dec_offset: Offset from VPU base to decoder registers.
+ * @enc_fmts: Encoder formats.
+ * @num_enc_fmts: Number of encoder formats.
+ * @dec_fmts: Decoder formats.
+ * @num_dec_fmts: Number of decoder formats.
+ * @codec: Supported codecs
+ * @codec_ops: Codec ops.
+ * @init: Initialize hardware.
+ * @runtime_resume: reenable hardware after power gating
+ * @irqs: array of irq names and interrupt handlers
+ * @num_irqs: number of irqs in the array
+ * @clk_names: array of clock names
+ * @num_clocks: number of clocks in the array
+ * @reg_names: array of register range names
+ * @num_regs: number of register range names in the array
+ */
+struct hantro_variant {
+ unsigned int enc_offset;
+ unsigned int dec_offset;
+ const struct hantro_fmt *enc_fmts;
+ unsigned int num_enc_fmts;
+ const struct hantro_fmt *dec_fmts;
+ unsigned int num_dec_fmts;
+ unsigned int codec;
+ const struct hantro_codec_ops *codec_ops;
+ int (*init)(struct hantro_dev *vpu);
+ int (*runtime_resume)(struct hantro_dev *vpu);
+ const struct hantro_irq *irqs;
+ int num_irqs;
+ const char * const *clk_names;
+ int num_clocks;
+ const char * const *reg_names;
+ int num_regs;
+};
+
+/**
+ * enum hantro_codec_mode - codec operating mode.
+ * @HANTRO_MODE_NONE: No operating mode. Used for RAW video formats.
+ * @HANTRO_MODE_JPEG_ENC: JPEG encoder.
+ * @HANTRO_MODE_MPEG2_DEC: MPEG-2 decoder.
+ */
+enum hantro_codec_mode {
+ HANTRO_MODE_NONE = -1,
+ HANTRO_MODE_JPEG_ENC,
+ HANTRO_MODE_MPEG2_DEC,
+};
+
+/*
+ * struct hantro_ctrl - helper type to declare supported controls
+ * @id: V4L2 control ID (V4L2_CID_xxx)
+ * @codec: codec id this control belong to (HANTRO_JPEG_ENCODER, etc.)
+ * @cfg: control configuration
+ */
+struct hantro_ctrl {
+ unsigned int id;
+ unsigned int codec;
+ struct v4l2_ctrl_config cfg;
+};
+
+/*
+ * struct hantro_func - Hantro VPU functionality
+ *
+ * @id: processing functionality ID (can be
+ * %MEDIA_ENT_F_PROC_VIDEO_ENCODER or
+ * %MEDIA_ENT_F_PROC_VIDEO_DECODER)
+ * @vdev: &struct video_device that exposes the encoder or
+ * decoder functionality
+ * @source_pad: &struct media_pad with the source pad.
+ * @sink: &struct media_entity pointer with the sink entity
+ * @sink_pad: &struct media_pad with the sink pad.
+ * @proc: &struct media_entity pointer with the M2M device itself.
+ * @proc_pads: &struct media_pad with the @proc pads.
+ * @intf_devnode: &struct media_intf devnode pointer with the interface
+ * with controls the M2M device.
+ *
+ * Contains everything needed to attach the video device to the media device.
+ */
+struct hantro_func {
+ unsigned int id;
+ struct video_device vdev;
+ struct media_pad source_pad;
+ struct media_entity sink;
+ struct media_pad sink_pad;
+ struct media_entity proc;
+ struct media_pad proc_pads[2];
+ struct media_intf_devnode *intf_devnode;
+};
+
+static inline struct hantro_func *
+hantro_vdev_to_func(struct video_device *vdev)
+{
+ return container_of(vdev, struct hantro_func, vdev);
+}
+
+/**
+ * struct hantro_dev - driver data
+ * @v4l2_dev: V4L2 device to register video devices for.
+ * @m2m_dev: mem2mem device associated to this device.
+ * @mdev: media device associated to this device.
+ * @encoder: encoder functionality.
+ * @decoder: decoder functionality.
+ * @pdev: Pointer to VPU platform device.
+ * @dev: Pointer to device for convenient logging using
+ * dev_ macros.
+ * @clocks: Array of clock handles.
+ * @reg_bases: Mapped addresses of VPU registers.
+ * @enc_base: Mapped address of VPU encoder register for convenience.
+ * @dec_base: Mapped address of VPU decoder register for convenience.
+ * @ctrl_base: Mapped address of VPU control block.
+ * @vpu_mutex: Mutex to synchronize V4L2 calls.
+ * @irqlock: Spinlock to synchronize access to data structures
+ * shared with interrupt handlers.
+ * @variant: Hardware variant-specific parameters.
+ * @watchdog_work: Delayed work for hardware timeout handling.
+ */
+struct hantro_dev {
+ struct v4l2_device v4l2_dev;
+ struct v4l2_m2m_dev *m2m_dev;
+ struct media_device mdev;
+ struct hantro_func *encoder;
+ struct hantro_func *decoder;
+ struct platform_device *pdev;
+ struct device *dev;
+ struct clk_bulk_data *clocks;
+ void __iomem **reg_bases;
+ void __iomem *enc_base;
+ void __iomem *dec_base;
+ void __iomem *ctrl_base;
+
+ struct mutex vpu_mutex; /* video_device lock */
+ spinlock_t irqlock;
+ const struct hantro_variant *variant;
+ struct delayed_work watchdog_work;
+};
+
+/**
+ * struct hantro_ctx - Context (instance) private data.
+ *
+ * @dev: VPU driver data to which the context belongs.
+ * @fh: V4L2 file handler.
+ *
+ * @sequence_cap: Sequence counter for capture queue
+ * @sequence_out: Sequence counter for output queue
+ *
+ * @vpu_src_fmt: Descriptor of active source format.
+ * @src_fmt: V4L2 pixel format of active source format.
+ * @vpu_dst_fmt: Descriptor of active destination format.
+ * @dst_fmt: V4L2 pixel format of active destination format.
+ *
+ * @ctrl_handler: Control handler used to register controls.
+ * @jpeg_quality: User-specified JPEG compression quality.
+ *
+ * @buf_finish: Buffer finish. This depends on encoder or decoder
+ * context, and it's called right before
+ * calling v4l2_m2m_job_finish.
+ * @codec_ops: Set of operations related to codec mode.
+ * @jpeg_enc: JPEG-encoding context.
+ * @mpeg2_dec: MPEG-2-decoding context.
+ */
+struct hantro_ctx {
+ struct hantro_dev *dev;
+ struct v4l2_fh fh;
+
+ u32 sequence_cap;
+ u32 sequence_out;
+
+ const struct hantro_fmt *vpu_src_fmt;
+ struct v4l2_pix_format_mplane src_fmt;
+ const struct hantro_fmt *vpu_dst_fmt;
+ struct v4l2_pix_format_mplane dst_fmt;
+
+ struct v4l2_ctrl_handler ctrl_handler;
+ int jpeg_quality;
+
+ int (*buf_finish)(struct hantro_ctx *ctx,
+ struct vb2_buffer *buf,
+ unsigned int bytesused);
+
+ const struct hantro_codec_ops *codec_ops;
+
+ /* Specific for particular codec modes. */
+ union {
+ struct hantro_jpeg_enc_hw_ctx jpeg_enc;
+ struct hantro_mpeg2_dec_hw_ctx mpeg2_dec;
+ };
+};
+
+/**
+ * struct hantro_fmt - information about supported video formats.
+ * @name: Human readable name of the format.
+ * @fourcc: FourCC code of the format. See V4L2_PIX_FMT_*.
+ * @codec_mode: Codec mode related to this format. See
+ * enum hantro_codec_mode.
+ * @header_size: Optional header size. Currently used by JPEG encoder.
+ * @max_depth: Maximum depth, for bitstream formats
+ * @enc_fmt: Format identifier for encoder registers.
+ * @frmsize: Supported range of frame sizes (only for bitstream formats).
+ */
+struct hantro_fmt {
+ char *name;
+ u32 fourcc;
+ enum hantro_codec_mode codec_mode;
+ int header_size;
+ int max_depth;
+ enum hantro_enc_fmt enc_fmt;
+ struct v4l2_frmsize_stepwise frmsize;
+};
+
+/* Logging helpers */
+
+/**
+ * debug - Module parameter to control level of debugging messages.
+ *
+ * Level of debugging messages can be controlled by bits of
+ * module parameter called "debug". Meaning of particular
+ * bits is as follows:
+ *
+ * bit 0 - global information: mode, size, init, release
+ * bit 1 - each run start/result information
+ * bit 2 - contents of small controls from userspace
+ * bit 3 - contents of big controls from userspace
+ * bit 4 - detail fmt, ctrl, buffer q/dq information
+ * bit 5 - detail function enter/leave trace information
+ * bit 6 - register write/read information
+ */
+extern int hantro_debug;
+
+#define vpu_debug(level, fmt, args...) \
+ do { \
+ if (hantro_debug & BIT(level)) \
+ pr_info("%s:%d: " fmt, \
+ __func__, __LINE__, ##args); \
+ } while (0)
+
+#define vpu_err(fmt, args...) \
+ pr_err("%s:%d: " fmt, __func__, __LINE__, ##args)
+
+/* Structure access helpers. */
+static inline struct hantro_ctx *fh_to_ctx(struct v4l2_fh *fh)
+{
+ return container_of(fh, struct hantro_ctx, fh);
+}
+
+/* Register accessors. */
+static inline void vepu_write_relaxed(struct hantro_dev *vpu,
+ u32 val, u32 reg)
+{
+ vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val);
+ writel_relaxed(val, vpu->enc_base + reg);
+}
+
+static inline void vepu_write(struct hantro_dev *vpu, u32 val, u32 reg)
+{
+ vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val);
+ writel(val, vpu->enc_base + reg);
+}
+
+static inline u32 vepu_read(struct hantro_dev *vpu, u32 reg)
+{
+ u32 val = readl(vpu->enc_base + reg);
+
+ vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val);
+ return val;
+}
+
+static inline void vdpu_write_relaxed(struct hantro_dev *vpu,
+ u32 val, u32 reg)
+{
+ vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val);
+ writel_relaxed(val, vpu->dec_base + reg);
+}
+
+static inline void vdpu_write(struct hantro_dev *vpu, u32 val, u32 reg)
+{
+ vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val);
+ writel(val, vpu->dec_base + reg);
+}
+
+static inline u32 vdpu_read(struct hantro_dev *vpu, u32 reg)
+{
+ u32 val = readl(vpu->dec_base + reg);
+
+ vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val);
+ return val;
+}
+
+bool hantro_is_encoder_ctx(const struct hantro_ctx *ctx);
+
+void *hantro_get_ctrl(struct hantro_ctx *ctx, u32 id);
+dma_addr_t hantro_get_ref(struct vb2_queue *q, u64 ts);
+
+#endif /* HANTRO_H_ */
diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c
new file mode 100644
index 000000000000..c3665f0e87a2
--- /dev/null
+++ b/drivers/staging/media/hantro/hantro_drv.c
@@ -0,0 +1,876 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Hantro VPU codec driver
+ *
+ * Copyright (C) 2018 Collabora, Ltd.
+ * Copyright 2018 Google LLC.
+ * Tomasz Figa <tfiga@chromium.org>
+ *
+ * Based on s5p-mfc driver by Samsung Electronics Co., Ltd.
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/workqueue.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-vmalloc.h>
+
+#include "hantro_v4l2.h"
+#include "hantro.h"
+#include "hantro_hw.h"
+
+#define DRIVER_NAME "hantro-vpu"
+
+int hantro_debug;
+module_param_named(debug, hantro_debug, int, 0644);
+MODULE_PARM_DESC(debug,
+ "Debug level - higher value produces more verbose messages");
+
+void *hantro_get_ctrl(struct hantro_ctx *ctx, u32 id)
+{
+ struct v4l2_ctrl *ctrl;
+
+ ctrl = v4l2_ctrl_find(&ctx->ctrl_handler, id);
+ return ctrl ? ctrl->p_cur.p : NULL;
+}
+
+dma_addr_t hantro_get_ref(struct vb2_queue *q, u64 ts)
+{
+ struct vb2_buffer *buf;
+ int index;
+
+ index = vb2_find_timestamp(q, ts, 0);
+ if (index < 0)
+ return 0;
+ buf = vb2_get_buffer(q, index);
+ return vb2_dma_contig_plane_dma_addr(buf, 0);
+}
+
+static int
+hantro_enc_buf_finish(struct hantro_ctx *ctx, struct vb2_buffer *buf,
+ unsigned int bytesused)
+{
+ size_t avail_size;
+
+ avail_size = vb2_plane_size(buf, 0) - ctx->vpu_dst_fmt->header_size;
+ if (bytesused > avail_size)
+ return -EINVAL;
+ /*
+ * The bounce buffer is only for the JPEG encoder.
+ * TODO: Rework the JPEG encoder to eliminate the need
+ * for a bounce buffer.
+ */
+ if (ctx->jpeg_enc.bounce_buffer.cpu) {
+ memcpy(vb2_plane_vaddr(buf, 0) +
+ ctx->vpu_dst_fmt->header_size,
+ ctx->jpeg_enc.bounce_buffer.cpu, bytesused);
+ }
+ buf->planes[0].bytesused =
+ ctx->vpu_dst_fmt->header_size + bytesused;
+ return 0;
+}
+
+static int
+hantro_dec_buf_finish(struct hantro_ctx *ctx, struct vb2_buffer *buf,
+ unsigned int bytesused)
+{
+ /* For decoders set bytesused as per the output picture. */
+ buf->planes[0].bytesused = ctx->dst_fmt.plane_fmt[0].sizeimage;
+ return 0;
+}
+
+static void hantro_job_finish(struct hantro_dev *vpu,
+ struct hantro_ctx *ctx,
+ unsigned int bytesused,
+ enum vb2_buffer_state result)
+{
+ struct vb2_v4l2_buffer *src, *dst;
+ int ret;
+
+ pm_runtime_mark_last_busy(vpu->dev);
+ pm_runtime_put_autosuspend(vpu->dev);
+ clk_bulk_disable(vpu->variant->num_clocks, vpu->clocks);
+
+ src = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ dst = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+
+ if (WARN_ON(!src))
+ return;
+ if (WARN_ON(!dst))
+ return;
+
+ src->sequence = ctx->sequence_out++;
+ dst->sequence = ctx->sequence_cap++;
+
+ v4l2_m2m_buf_copy_metadata(src, dst, true);
+
+ ret = ctx->buf_finish(ctx, &dst->vb2_buf, bytesused);
+ if (ret)
+ result = VB2_BUF_STATE_ERROR;
+
+ v4l2_m2m_buf_done(src, result);
+ v4l2_m2m_buf_done(dst, result);
+
+ v4l2_m2m_job_finish(vpu->m2m_dev, ctx->fh.m2m_ctx);
+}
+
+void hantro_irq_done(struct hantro_dev *vpu, unsigned int bytesused,
+ enum vb2_buffer_state result)
+{
+ struct hantro_ctx *ctx =
+ v4l2_m2m_get_curr_priv(vpu->m2m_dev);
+
+ /*
+ * If cancel_delayed_work returns false
+ * the timeout expired. The watchdog is running,
+ * and will take care of finishing the job.
+ */
+ if (cancel_delayed_work(&vpu->watchdog_work))
+ hantro_job_finish(vpu, ctx, bytesused, result);
+}
+
+void hantro_watchdog(struct work_struct *work)
+{
+ struct hantro_dev *vpu;
+ struct hantro_ctx *ctx;
+
+ vpu = container_of(to_delayed_work(work),
+ struct hantro_dev, watchdog_work);
+ ctx = v4l2_m2m_get_curr_priv(vpu->m2m_dev);
+ if (ctx) {
+ vpu_err("frame processing timed out!\n");
+ ctx->codec_ops->reset(ctx);
+ hantro_job_finish(vpu, ctx, 0, VB2_BUF_STATE_ERROR);
+ }
+}
+
+static void device_run(void *priv)
+{
+ struct hantro_ctx *ctx = priv;
+ int ret;
+
+ ret = clk_bulk_enable(ctx->dev->variant->num_clocks, ctx->dev->clocks);
+ if (ret)
+ goto err_cancel_job;
+ ret = pm_runtime_get_sync(ctx->dev->dev);
+ if (ret < 0)
+ goto err_cancel_job;
+
+ ctx->codec_ops->run(ctx);
+ return;
+
+err_cancel_job:
+ hantro_job_finish(ctx->dev, ctx, 0, VB2_BUF_STATE_ERROR);
+}
+
+bool hantro_is_encoder_ctx(const struct hantro_ctx *ctx)
+{
+ return ctx->buf_finish == hantro_enc_buf_finish;
+}
+
+static struct v4l2_m2m_ops vpu_m2m_ops = {
+ .device_run = device_run,
+};
+
+static int
+queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
+{
+ struct hantro_ctx *ctx = priv;
+ int ret;
+
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ src_vq->drv_priv = ctx;
+ src_vq->ops = &hantro_queue_ops;
+ src_vq->mem_ops = &vb2_dma_contig_memops;
+
+ /*
+ * Driver does mostly sequential access, so sacrifice TLB efficiency
+ * for faster allocation. Also, no CPU access on the source queue,
+ * so no kernel mapping needed.
+ */
+ src_vq->dma_attrs = DMA_ATTR_ALLOC_SINGLE_PAGES |
+ DMA_ATTR_NO_KERNEL_MAPPING;
+ src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->lock = &ctx->dev->vpu_mutex;
+ src_vq->dev = ctx->dev->v4l2_dev.dev;
+ src_vq->supports_requests = true;
+
+ ret = vb2_queue_init(src_vq);
+ if (ret)
+ return ret;
+
+ /*
+ * When encoding, the CAPTURE queue doesn't need dma memory,
+ * as the CPU needs to create the JPEG frames, from the
+ * hardware-produced JPEG payload.
+ *
+ * For the DMA destination buffer, we use a bounce buffer.
+ */
+ if (hantro_is_encoder_ctx(ctx)) {
+ dst_vq->mem_ops = &vb2_vmalloc_memops;
+ } else {
+ dst_vq->bidirectional = true;
+ dst_vq->mem_ops = &vb2_dma_contig_memops;
+ dst_vq->dma_attrs = DMA_ATTR_ALLOC_SINGLE_PAGES |
+ DMA_ATTR_NO_KERNEL_MAPPING;
+ }
+
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ dst_vq->drv_priv = ctx;
+ dst_vq->ops = &hantro_queue_ops;
+ dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dst_vq->lock = &ctx->dev->vpu_mutex;
+ dst_vq->dev = ctx->dev->v4l2_dev.dev;
+
+ return vb2_queue_init(dst_vq);
+}
+
+static int hantro_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct hantro_ctx *ctx;
+
+ ctx = container_of(ctrl->handler,
+ struct hantro_ctx, ctrl_handler);
+
+ vpu_debug(1, "s_ctrl: id = %d, val = %d\n", ctrl->id, ctrl->val);
+
+ switch (ctrl->id) {
+ case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+ ctx->jpeg_quality = ctrl->val;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops hantro_ctrl_ops = {
+ .s_ctrl = hantro_s_ctrl,
+};
+
+static struct hantro_ctrl controls[] = {
+ {
+ .id = V4L2_CID_JPEG_COMPRESSION_QUALITY,
+ .codec = HANTRO_JPEG_ENCODER,
+ .cfg = {
+ .min = 5,
+ .max = 100,
+ .step = 1,
+ .def = 50,
+ },
+ }, {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS,
+ .codec = HANTRO_MPEG2_DECODER,
+ .cfg = {
+ .elem_size = sizeof(struct v4l2_ctrl_mpeg2_slice_params),
+ },
+ }, {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION,
+ .codec = HANTRO_MPEG2_DECODER,
+ .cfg = {
+ .elem_size = sizeof(struct v4l2_ctrl_mpeg2_quantization),
+ },
+ },
+};
+
+static int hantro_ctrls_setup(struct hantro_dev *vpu,
+ struct hantro_ctx *ctx,
+ int allowed_codecs)
+{
+ int i, num_ctrls = ARRAY_SIZE(controls);
+
+ v4l2_ctrl_handler_init(&ctx->ctrl_handler, num_ctrls);
+
+ for (i = 0; i < num_ctrls; i++) {
+ if (!(allowed_codecs & controls[i].codec))
+ continue;
+ if (!controls[i].cfg.elem_size) {
+ v4l2_ctrl_new_std(&ctx->ctrl_handler,
+ &hantro_ctrl_ops,
+ controls[i].id, controls[i].cfg.min,
+ controls[i].cfg.max,
+ controls[i].cfg.step,
+ controls[i].cfg.def);
+ } else {
+ controls[i].cfg.id = controls[i].id;
+ v4l2_ctrl_new_custom(&ctx->ctrl_handler,
+ &controls[i].cfg, NULL);
+ }
+
+ if (ctx->ctrl_handler.error) {
+ vpu_err("Adding control (%d) failed %d\n",
+ controls[i].id,
+ ctx->ctrl_handler.error);
+ v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+ return ctx->ctrl_handler.error;
+ }
+ }
+ return v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
+}
+
+/*
+ * V4L2 file operations.
+ */
+
+static int hantro_open(struct file *filp)
+{
+ struct hantro_dev *vpu = video_drvdata(filp);
+ struct video_device *vdev = video_devdata(filp);
+ struct hantro_func *func = hantro_vdev_to_func(vdev);
+ struct hantro_ctx *ctx;
+ int allowed_codecs, ret;
+
+ /*
+ * We do not need any extra locking here, because we operate only
+ * on local data here, except reading few fields from dev, which
+ * do not change through device's lifetime (which is guaranteed by
+ * reference on module from open()) and V4L2 internal objects (such
+ * as vdev and ctx->fh), which have proper locking done in respective
+ * helper functions used here.
+ */
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->dev = vpu;
+ if (func->id == MEDIA_ENT_F_PROC_VIDEO_ENCODER) {
+ allowed_codecs = vpu->variant->codec & HANTRO_ENCODERS;
+ ctx->buf_finish = hantro_enc_buf_finish;
+ ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(vpu->m2m_dev, ctx,
+ queue_init);
+ } else if (func->id == MEDIA_ENT_F_PROC_VIDEO_DECODER) {
+ allowed_codecs = vpu->variant->codec & HANTRO_DECODERS;
+ ctx->buf_finish = hantro_dec_buf_finish;
+ ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(vpu->m2m_dev, ctx,
+ queue_init);
+ } else {
+ ctx->fh.m2m_ctx = ERR_PTR(-ENODEV);
+ }
+ if (IS_ERR(ctx->fh.m2m_ctx)) {
+ ret = PTR_ERR(ctx->fh.m2m_ctx);
+ kfree(ctx);
+ return ret;
+ }
+
+ v4l2_fh_init(&ctx->fh, vdev);
+ filp->private_data = &ctx->fh;
+ v4l2_fh_add(&ctx->fh);
+
+ hantro_reset_fmts(ctx);
+
+ ret = hantro_ctrls_setup(vpu, ctx, allowed_codecs);
+ if (ret) {
+ vpu_err("Failed to set up controls\n");
+ goto err_fh_free;
+ }
+ ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+
+ return 0;
+
+err_fh_free:
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ kfree(ctx);
+ return ret;
+}
+
+static int hantro_release(struct file *filp)
+{
+ struct hantro_ctx *ctx =
+ container_of(filp->private_data, struct hantro_ctx, fh);
+
+ /*
+ * No need for extra locking because this was the last reference
+ * to this file.
+ */
+ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+ kfree(ctx);
+
+ return 0;
+}
+
+static const struct v4l2_file_operations hantro_fops = {
+ .owner = THIS_MODULE,
+ .open = hantro_open,
+ .release = hantro_release,
+ .poll = v4l2_m2m_fop_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = v4l2_m2m_fop_mmap,
+};
+
+static const struct of_device_id of_hantro_match[] = {
+#ifdef CONFIG_VIDEO_HANTRO_ROCKCHIP
+ { .compatible = "rockchip,rk3399-vpu", .data = &rk3399_vpu_variant, },
+ { .compatible = "rockchip,rk3288-vpu", .data = &rk3288_vpu_variant, },
+#endif
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_hantro_match);
+
+static int hantro_register_entity(struct media_device *mdev,
+ struct media_entity *entity,
+ const char *entity_name,
+ struct media_pad *pads, int num_pads,
+ int function, struct video_device *vdev)
+{
+ char *name;
+ int ret;
+
+ entity->obj_type = MEDIA_ENTITY_TYPE_BASE;
+ if (function == MEDIA_ENT_F_IO_V4L) {
+ entity->info.dev.major = VIDEO_MAJOR;
+ entity->info.dev.minor = vdev->minor;
+ }
+
+ name = devm_kasprintf(mdev->dev, GFP_KERNEL, "%s-%s", vdev->name,
+ entity_name);
+ if (!name)
+ return -ENOMEM;
+
+ entity->name = name;
+ entity->function = function;
+
+ ret = media_entity_pads_init(entity, num_pads, pads);
+ if (ret)
+ return ret;
+
+ ret = media_device_register_entity(mdev, entity);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int hantro_attach_func(struct hantro_dev *vpu,
+ struct hantro_func *func)
+{
+ struct media_device *mdev = &vpu->mdev;
+ struct media_link *link;
+ int ret;
+
+ /* Create the three encoder entities with their pads */
+ func->source_pad.flags = MEDIA_PAD_FL_SOURCE;
+ ret = hantro_register_entity(mdev, &func->vdev.entity, "source",
+ &func->source_pad, 1, MEDIA_ENT_F_IO_V4L,
+ &func->vdev);
+ if (ret)
+ return ret;
+
+ func->proc_pads[0].flags = MEDIA_PAD_FL_SINK;
+ func->proc_pads[1].flags = MEDIA_PAD_FL_SOURCE;
+ ret = hantro_register_entity(mdev, &func->proc, "proc",
+ func->proc_pads, 2, func->id,
+ &func->vdev);
+ if (ret)
+ goto err_rel_entity0;
+
+ func->sink_pad.flags = MEDIA_PAD_FL_SINK;
+ ret = hantro_register_entity(mdev, &func->sink, "sink",
+ &func->sink_pad, 1, MEDIA_ENT_F_IO_V4L,
+ &func->vdev);
+ if (ret)
+ goto err_rel_entity1;
+
+ /* Connect the three entities */
+ ret = media_create_pad_link(&func->vdev.entity, 0, &func->proc, 1,
+ MEDIA_LNK_FL_IMMUTABLE |
+ MEDIA_LNK_FL_ENABLED);
+ if (ret)
+ goto err_rel_entity2;
+
+ ret = media_create_pad_link(&func->proc, 0, &func->sink, 0,
+ MEDIA_LNK_FL_IMMUTABLE |
+ MEDIA_LNK_FL_ENABLED);
+ if (ret)
+ goto err_rm_links0;
+
+ /* Create video interface */
+ func->intf_devnode = media_devnode_create(mdev, MEDIA_INTF_T_V4L_VIDEO,
+ 0, VIDEO_MAJOR,
+ func->vdev.minor);
+ if (!func->intf_devnode) {
+ ret = -ENOMEM;
+ goto err_rm_links1;
+ }
+
+ /* Connect the two DMA engines to the interface */
+ link = media_create_intf_link(&func->vdev.entity,
+ &func->intf_devnode->intf,
+ MEDIA_LNK_FL_IMMUTABLE |
+ MEDIA_LNK_FL_ENABLED);
+ if (!link) {
+ ret = -ENOMEM;
+ goto err_rm_devnode;
+ }
+
+ link = media_create_intf_link(&func->sink, &func->intf_devnode->intf,
+ MEDIA_LNK_FL_IMMUTABLE |
+ MEDIA_LNK_FL_ENABLED);
+ if (!link) {
+ ret = -ENOMEM;
+ goto err_rm_devnode;
+ }
+ return 0;
+
+err_rm_devnode:
+ media_devnode_remove(func->intf_devnode);
+
+err_rm_links1:
+ media_entity_remove_links(&func->sink);
+
+err_rm_links0:
+ media_entity_remove_links(&func->proc);
+ media_entity_remove_links(&func->vdev.entity);
+
+err_rel_entity2:
+ media_device_unregister_entity(&func->sink);
+
+err_rel_entity1:
+ media_device_unregister_entity(&func->proc);
+
+err_rel_entity0:
+ media_device_unregister_entity(&func->vdev.entity);
+ return ret;
+}
+
+static void hantro_detach_func(struct hantro_func *func)
+{
+ media_devnode_remove(func->intf_devnode);
+ media_entity_remove_links(&func->sink);
+ media_entity_remove_links(&func->proc);
+ media_entity_remove_links(&func->vdev.entity);
+ media_device_unregister_entity(&func->sink);
+ media_device_unregister_entity(&func->proc);
+ media_device_unregister_entity(&func->vdev.entity);
+}
+
+static int hantro_add_func(struct hantro_dev *vpu, unsigned int funcid)
+{
+ const struct of_device_id *match;
+ struct hantro_func *func;
+ struct video_device *vfd;
+ int ret;
+
+ match = of_match_node(of_hantro_match, vpu->dev->of_node);
+ func = devm_kzalloc(vpu->dev, sizeof(*func), GFP_KERNEL);
+ if (!func) {
+ v4l2_err(&vpu->v4l2_dev, "Failed to allocate video device\n");
+ return -ENOMEM;
+ }
+
+ func->id = funcid;
+
+ vfd = &func->vdev;
+ vfd->fops = &hantro_fops;
+ vfd->release = video_device_release_empty;
+ vfd->lock = &vpu->vpu_mutex;
+ vfd->v4l2_dev = &vpu->v4l2_dev;
+ vfd->vfl_dir = VFL_DIR_M2M;
+ vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
+ vfd->ioctl_ops = &hantro_ioctl_ops;
+ snprintf(vfd->name, sizeof(vfd->name), "%s-%s", match->compatible,
+ funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER ? "enc" : "dec");
+
+ if (funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER)
+ vpu->encoder = func;
+ else
+ vpu->decoder = func;
+
+ video_set_drvdata(vfd, vpu);
+
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
+ if (ret) {
+ v4l2_err(&vpu->v4l2_dev, "Failed to register video device\n");
+ return ret;
+ }
+
+ ret = hantro_attach_func(vpu, func);
+ if (ret) {
+ v4l2_err(&vpu->v4l2_dev,
+ "Failed to attach functionality to the media device\n");
+ goto err_unreg_dev;
+ }
+
+ v4l2_info(&vpu->v4l2_dev, "registered %s as /dev/video%d\n", vfd->name,
+ vfd->num);
+
+ return 0;
+
+err_unreg_dev:
+ video_unregister_device(vfd);
+ return ret;
+}
+
+static int hantro_add_enc_func(struct hantro_dev *vpu)
+{
+ if (!vpu->variant->enc_fmts)
+ return 0;
+
+ return hantro_add_func(vpu, MEDIA_ENT_F_PROC_VIDEO_ENCODER);
+}
+
+static int hantro_add_dec_func(struct hantro_dev *vpu)
+{
+ if (!vpu->variant->dec_fmts)
+ return 0;
+
+ return hantro_add_func(vpu, MEDIA_ENT_F_PROC_VIDEO_DECODER);
+}
+
+static void hantro_remove_func(struct hantro_dev *vpu,
+ unsigned int funcid)
+{
+ struct hantro_func *func;
+
+ if (funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER)
+ func = vpu->encoder;
+ else
+ func = vpu->decoder;
+
+ if (!func)
+ return;
+
+ hantro_detach_func(func);
+ video_unregister_device(&func->vdev);
+}
+
+static void hantro_remove_enc_func(struct hantro_dev *vpu)
+{
+ hantro_remove_func(vpu, MEDIA_ENT_F_PROC_VIDEO_ENCODER);
+}
+
+static void hantro_remove_dec_func(struct hantro_dev *vpu)
+{
+ hantro_remove_func(vpu, MEDIA_ENT_F_PROC_VIDEO_DECODER);
+}
+
+static const struct media_device_ops hantro_m2m_media_ops = {
+ .req_validate = vb2_request_validate,
+ .req_queue = v4l2_m2m_request_queue,
+};
+
+static int hantro_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+ struct hantro_dev *vpu;
+ struct resource *res;
+ int num_bases;
+ int i, ret;
+
+ vpu = devm_kzalloc(&pdev->dev, sizeof(*vpu), GFP_KERNEL);
+ if (!vpu)
+ return -ENOMEM;
+
+ vpu->dev = &pdev->dev;
+ vpu->pdev = pdev;
+ mutex_init(&vpu->vpu_mutex);
+ spin_lock_init(&vpu->irqlock);
+
+ match = of_match_node(of_hantro_match, pdev->dev.of_node);
+ vpu->variant = match->data;
+
+ INIT_DELAYED_WORK(&vpu->watchdog_work, hantro_watchdog);
+
+ vpu->clocks = devm_kcalloc(&pdev->dev, vpu->variant->num_clocks,
+ sizeof(*vpu->clocks), GFP_KERNEL);
+ if (!vpu->clocks)
+ return -ENOMEM;
+
+ for (i = 0; i < vpu->variant->num_clocks; i++)
+ vpu->clocks[i].id = vpu->variant->clk_names[i];
+ ret = devm_clk_bulk_get(&pdev->dev, vpu->variant->num_clocks,
+ vpu->clocks);
+ if (ret)
+ return ret;
+
+ num_bases = vpu->variant->num_regs ?: 1;
+ vpu->reg_bases = devm_kcalloc(&pdev->dev, num_bases,
+ sizeof(*vpu->reg_bases), GFP_KERNEL);
+ if (!vpu->reg_bases)
+ return -ENOMEM;
+
+ for (i = 0; i < num_bases; i++) {
+ res = vpu->variant->reg_names ?
+ platform_get_resource_byname(vpu->pdev, IORESOURCE_MEM,
+ vpu->variant->reg_names[i]) :
+ platform_get_resource(vpu->pdev, IORESOURCE_MEM, 0);
+ vpu->reg_bases[i] = devm_ioremap_resource(vpu->dev, res);
+ if (IS_ERR(vpu->reg_bases[i]))
+ return PTR_ERR(vpu->reg_bases[i]);
+ }
+ vpu->enc_base = vpu->reg_bases[0] + vpu->variant->enc_offset;
+ vpu->dec_base = vpu->reg_bases[0] + vpu->variant->dec_offset;
+
+ ret = dma_set_coherent_mask(vpu->dev, DMA_BIT_MASK(32));
+ if (ret) {
+ dev_err(vpu->dev, "Could not set DMA coherent mask.\n");
+ return ret;
+ }
+
+ for (i = 0; i < vpu->variant->num_irqs; i++) {
+ const char *irq_name = vpu->variant->irqs[i].name;
+ int irq;
+
+ if (!vpu->variant->irqs[i].handler)
+ continue;
+
+ irq = platform_get_irq_byname(vpu->pdev, irq_name);
+ if (irq <= 0) {
+ dev_err(vpu->dev, "Could not get %s IRQ.\n", irq_name);
+ return -ENXIO;
+ }
+
+ ret = devm_request_irq(vpu->dev, irq,
+ vpu->variant->irqs[i].handler, 0,
+ dev_name(vpu->dev), vpu);
+ if (ret) {
+ dev_err(vpu->dev, "Could not request %s IRQ.\n",
+ irq_name);
+ return ret;
+ }
+ }
+
+ ret = vpu->variant->init(vpu);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to init VPU hardware\n");
+ return ret;
+ }
+
+ pm_runtime_set_autosuspend_delay(vpu->dev, 100);
+ pm_runtime_use_autosuspend(vpu->dev);
+ pm_runtime_enable(vpu->dev);
+
+ ret = clk_bulk_prepare(vpu->variant->num_clocks, vpu->clocks);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to prepare clocks\n");
+ return ret;
+ }
+
+ ret = v4l2_device_register(&pdev->dev, &vpu->v4l2_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register v4l2 device\n");
+ goto err_clk_unprepare;
+ }
+ platform_set_drvdata(pdev, vpu);
+
+ vpu->m2m_dev = v4l2_m2m_init(&vpu_m2m_ops);
+ if (IS_ERR(vpu->m2m_dev)) {
+ v4l2_err(&vpu->v4l2_dev, "Failed to init mem2mem device\n");
+ ret = PTR_ERR(vpu->m2m_dev);
+ goto err_v4l2_unreg;
+ }
+
+ vpu->mdev.dev = vpu->dev;
+ strscpy(vpu->mdev.model, DRIVER_NAME, sizeof(vpu->mdev.model));
+ strscpy(vpu->mdev.bus_info, "platform: " DRIVER_NAME,
+ sizeof(vpu->mdev.model));
+ media_device_init(&vpu->mdev);
+ vpu->mdev.ops = &hantro_m2m_media_ops;
+ vpu->v4l2_dev.mdev = &vpu->mdev;
+
+ ret = hantro_add_enc_func(vpu);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register encoder\n");
+ goto err_m2m_rel;
+ }
+
+ ret = hantro_add_dec_func(vpu);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register decoder\n");
+ goto err_rm_enc_func;
+ }
+
+ ret = media_device_register(&vpu->mdev);
+ if (ret) {
+ v4l2_err(&vpu->v4l2_dev, "Failed to register mem2mem media device\n");
+ goto err_rm_dec_func;
+ }
+
+ return 0;
+
+err_rm_dec_func:
+ hantro_remove_dec_func(vpu);
+err_rm_enc_func:
+ hantro_remove_enc_func(vpu);
+err_m2m_rel:
+ media_device_cleanup(&vpu->mdev);
+ v4l2_m2m_release(vpu->m2m_dev);
+err_v4l2_unreg:
+ v4l2_device_unregister(&vpu->v4l2_dev);
+err_clk_unprepare:
+ clk_bulk_unprepare(vpu->variant->num_clocks, vpu->clocks);
+ pm_runtime_dont_use_autosuspend(vpu->dev);
+ pm_runtime_disable(vpu->dev);
+ return ret;
+}
+
+static int hantro_remove(struct platform_device *pdev)
+{
+ struct hantro_dev *vpu = platform_get_drvdata(pdev);
+
+ v4l2_info(&vpu->v4l2_dev, "Removing %s\n", pdev->name);
+
+ media_device_unregister(&vpu->mdev);
+ hantro_remove_dec_func(vpu);
+ hantro_remove_enc_func(vpu);
+ media_device_cleanup(&vpu->mdev);
+ v4l2_m2m_release(vpu->m2m_dev);
+ v4l2_device_unregister(&vpu->v4l2_dev);
+ clk_bulk_unprepare(vpu->variant->num_clocks, vpu->clocks);
+ pm_runtime_dont_use_autosuspend(vpu->dev);
+ pm_runtime_disable(vpu->dev);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int hantro_runtime_resume(struct device *dev)
+{
+ struct hantro_dev *vpu = dev_get_drvdata(dev);
+
+ if (vpu->variant->runtime_resume)
+ return vpu->variant->runtime_resume(vpu);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops hantro_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+ SET_RUNTIME_PM_OPS(NULL, hantro_runtime_resume, NULL)
+};
+
+static struct platform_driver hantro_driver = {
+ .probe = hantro_probe,
+ .remove = hantro_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = of_match_ptr(of_hantro_match),
+ .pm = &hantro_pm_ops,
+ },
+};
+module_platform_driver(hantro_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Alpha Lin <Alpha.Lin@Rock-Chips.com>");
+MODULE_AUTHOR("Tomasz Figa <tfiga@chromium.org>");
+MODULE_AUTHOR("Ezequiel Garcia <ezequiel@collabora.com>");
+MODULE_DESCRIPTION("Hantro VPU codec driver");
diff --git a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c
new file mode 100644
index 000000000000..e592c1b66375
--- /dev/null
+++ b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Hantro VPU codec driver
+ *
+ * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
+ */
+
+#include <asm/unaligned.h>
+#include <linux/bitfield.h>
+#include <media/v4l2-mem2mem.h>
+#include "hantro.h"
+#include "hantro_hw.h"
+
+#define G1_SWREG(nr) ((nr) * 4)
+
+#define G1_REG_RLC_VLC_BASE G1_SWREG(12)
+#define G1_REG_DEC_OUT_BASE G1_SWREG(13)
+#define G1_REG_REFER0_BASE G1_SWREG(14)
+#define G1_REG_REFER1_BASE G1_SWREG(15)
+#define G1_REG_REFER2_BASE G1_SWREG(16)
+#define G1_REG_REFER3_BASE G1_SWREG(17)
+#define G1_REG_QTABLE_BASE G1_SWREG(40)
+#define G1_REG_DEC_E(v) ((v) ? BIT(0) : 0)
+
+#define G1_REG_DEC_AXI_RD_ID(v) (((v) << 24) & GENMASK(31, 24))
+#define G1_REG_DEC_TIMEOUT_E(v) ((v) ? BIT(23) : 0)
+#define G1_REG_DEC_STRSWAP32_E(v) ((v) ? BIT(22) : 0)
+#define G1_REG_DEC_STRENDIAN_E(v) ((v) ? BIT(21) : 0)
+#define G1_REG_DEC_INSWAP32_E(v) ((v) ? BIT(20) : 0)
+#define G1_REG_DEC_OUTSWAP32_E(v) ((v) ? BIT(19) : 0)
+#define G1_REG_DEC_DATA_DISC_E(v) ((v) ? BIT(18) : 0)
+#define G1_REG_DEC_LATENCY(v) (((v) << 11) & GENMASK(16, 11))
+#define G1_REG_DEC_CLK_GATE_E(v) ((v) ? BIT(10) : 0)
+#define G1_REG_DEC_IN_ENDIAN(v) ((v) ? BIT(9) : 0)
+#define G1_REG_DEC_OUT_ENDIAN(v) ((v) ? BIT(8) : 0)
+#define G1_REG_DEC_ADV_PRE_DIS(v) ((v) ? BIT(6) : 0)
+#define G1_REG_DEC_SCMD_DIS(v) ((v) ? BIT(5) : 0)
+#define G1_REG_DEC_MAX_BURST(v) (((v) << 0) & GENMASK(4, 0))
+
+#define G1_REG_DEC_MODE(v) (((v) << 28) & GENMASK(31, 28))
+#define G1_REG_RLC_MODE_E(v) ((v) ? BIT(27) : 0)
+#define G1_REG_PIC_INTERLACE_E(v) ((v) ? BIT(23) : 0)
+#define G1_REG_PIC_FIELDMODE_E(v) ((v) ? BIT(22) : 0)
+#define G1_REG_PIC_B_E(v) ((v) ? BIT(21) : 0)
+#define G1_REG_PIC_INTER_E(v) ((v) ? BIT(20) : 0)
+#define G1_REG_PIC_TOPFIELD_E(v) ((v) ? BIT(19) : 0)
+#define G1_REG_FWD_INTERLACE_E(v) ((v) ? BIT(18) : 0)
+#define G1_REG_FILTERING_DIS(v) ((v) ? BIT(14) : 0)
+#define G1_REG_WRITE_MVS_E(v) ((v) ? BIT(12) : 0)
+#define G1_REG_DEC_AXI_WR_ID(v) (((v) << 0) & GENMASK(7, 0))
+
+#define G1_REG_PIC_MB_WIDTH(v) (((v) << 23) & GENMASK(31, 23))
+#define G1_REG_PIC_MB_HEIGHT_P(v) (((v) << 11) & GENMASK(18, 11))
+#define G1_REG_ALT_SCAN_E(v) ((v) ? BIT(6) : 0)
+#define G1_REG_TOPFIELDFIRST_E(v) ((v) ? BIT(5) : 0)
+
+#define G1_REG_STRM_START_BIT(v) (((v) << 26) & GENMASK(31, 26))
+#define G1_REG_QSCALE_TYPE(v) ((v) ? BIT(24) : 0)
+#define G1_REG_CON_MV_E(v) ((v) ? BIT(4) : 0)
+#define G1_REG_INTRA_DC_PREC(v) (((v) << 2) & GENMASK(3, 2))
+#define G1_REG_INTRA_VLC_TAB(v) ((v) ? BIT(1) : 0)
+#define G1_REG_FRAME_PRED_DCT(v) ((v) ? BIT(0) : 0)
+
+#define G1_REG_INIT_QP(v) (((v) << 25) & GENMASK(30, 25))
+#define G1_REG_STREAM_LEN(v) (((v) << 0) & GENMASK(23, 0))
+
+#define G1_REG_ALT_SCAN_FLAG_E(v) ((v) ? BIT(19) : 0)
+#define G1_REG_FCODE_FWD_HOR(v) (((v) << 15) & GENMASK(18, 15))
+#define G1_REG_FCODE_FWD_VER(v) (((v) << 11) & GENMASK(14, 11))
+#define G1_REG_FCODE_BWD_HOR(v) (((v) << 7) & GENMASK(10, 7))
+#define G1_REG_FCODE_BWD_VER(v) (((v) << 3) & GENMASK(6, 3))
+#define G1_REG_MV_ACCURACY_FWD(v) ((v) ? BIT(2) : 0)
+#define G1_REG_MV_ACCURACY_BWD(v) ((v) ? BIT(1) : 0)
+
+#define G1_REG_STARTMB_X(v) (((v) << 23) & GENMASK(31, 23))
+#define G1_REG_STARTMB_Y(v) (((v) << 15) & GENMASK(22, 15))
+
+#define G1_REG_APF_THRESHOLD(v) (((v) << 0) & GENMASK(13, 0))
+
+#define PICT_TOP_FIELD 1
+#define PICT_BOTTOM_FIELD 2
+#define PICT_FRAME 3
+
+static void
+hantro_g1_mpeg2_dec_set_quantization(struct hantro_dev *vpu,
+ struct hantro_ctx *ctx)
+{
+ struct v4l2_ctrl_mpeg2_quantization *quantization;
+
+ quantization = hantro_get_ctrl(ctx,
+ V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION);
+ hantro_mpeg2_dec_copy_qtable(ctx->mpeg2_dec.qtable.cpu,
+ quantization);
+ vdpu_write_relaxed(vpu, ctx->mpeg2_dec.qtable.dma,
+ G1_REG_QTABLE_BASE);
+}
+
+static void
+hantro_g1_mpeg2_dec_set_buffers(struct hantro_dev *vpu, struct hantro_ctx *ctx,
+ struct vb2_buffer *src_buf,
+ struct vb2_buffer *dst_buf,
+ const struct v4l2_mpeg2_sequence *sequence,
+ const struct v4l2_mpeg2_picture *picture,
+ const struct v4l2_ctrl_mpeg2_slice_params *slice_params)
+{
+ dma_addr_t forward_addr = 0, backward_addr = 0;
+ dma_addr_t current_addr, addr;
+ struct vb2_queue *vq;
+
+ vq = v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx);
+
+ switch (picture->picture_coding_type) {
+ case V4L2_MPEG2_PICTURE_CODING_TYPE_B:
+ backward_addr = hantro_get_ref(vq,
+ slice_params->backward_ref_ts);
+ /* fall-through */
+ case V4L2_MPEG2_PICTURE_CODING_TYPE_P:
+ forward_addr = hantro_get_ref(vq,
+ slice_params->forward_ref_ts);
+ }
+
+ /* Source bitstream buffer */
+ addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+ vdpu_write_relaxed(vpu, addr, G1_REG_RLC_VLC_BASE);
+
+ /* Destination frame buffer */
+ addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+ current_addr = addr;
+
+ if (picture->picture_structure == PICT_BOTTOM_FIELD)
+ addr += ALIGN(ctx->dst_fmt.width, 16);
+ vdpu_write_relaxed(vpu, addr, G1_REG_DEC_OUT_BASE);
+
+ if (!forward_addr)
+ forward_addr = current_addr;
+ if (!backward_addr)
+ backward_addr = current_addr;
+
+ /* Set forward ref frame (top/bottom field) */
+ if (picture->picture_structure == PICT_FRAME ||
+ picture->picture_coding_type == V4L2_MPEG2_PICTURE_CODING_TYPE_B ||
+ (picture->picture_structure == PICT_TOP_FIELD &&
+ picture->top_field_first) ||
+ (picture->picture_structure == PICT_BOTTOM_FIELD &&
+ !picture->top_field_first)) {
+ vdpu_write_relaxed(vpu, forward_addr, G1_REG_REFER0_BASE);
+ vdpu_write_relaxed(vpu, forward_addr, G1_REG_REFER1_BASE);
+ } else if (picture->picture_structure == PICT_TOP_FIELD) {
+ vdpu_write_relaxed(vpu, forward_addr, G1_REG_REFER0_BASE);
+ vdpu_write_relaxed(vpu, current_addr, G1_REG_REFER1_BASE);
+ } else if (picture->picture_structure == PICT_BOTTOM_FIELD) {
+ vdpu_write_relaxed(vpu, current_addr, G1_REG_REFER0_BASE);
+ vdpu_write_relaxed(vpu, forward_addr, G1_REG_REFER1_BASE);
+ }
+
+ /* Set backward ref frame (top/bottom field) */
+ vdpu_write_relaxed(vpu, backward_addr, G1_REG_REFER2_BASE);
+ vdpu_write_relaxed(vpu, backward_addr, G1_REG_REFER3_BASE);
+}
+
+void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx)
+{
+ struct hantro_dev *vpu = ctx->dev;
+ struct vb2_v4l2_buffer *src_buf, *dst_buf;
+ const struct v4l2_ctrl_mpeg2_slice_params *slice_params;
+ const struct v4l2_mpeg2_sequence *sequence;
+ const struct v4l2_mpeg2_picture *picture;
+ u32 reg;
+
+ src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+
+ /* Apply request controls if any */
+ v4l2_ctrl_request_setup(src_buf->vb2_buf.req_obj.req,
+ &ctx->ctrl_handler);
+
+ slice_params = hantro_get_ctrl(ctx,
+ V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS);
+ sequence = &slice_params->sequence;
+ picture = &slice_params->picture;
+
+ reg = G1_REG_DEC_AXI_RD_ID(0) |
+ G1_REG_DEC_TIMEOUT_E(1) |
+ G1_REG_DEC_STRSWAP32_E(1) |
+ G1_REG_DEC_STRENDIAN_E(1) |
+ G1_REG_DEC_INSWAP32_E(1) |
+ G1_REG_DEC_OUTSWAP32_E(1) |
+ G1_REG_DEC_DATA_DISC_E(0) |
+ G1_REG_DEC_LATENCY(0) |
+ G1_REG_DEC_CLK_GATE_E(1) |
+ G1_REG_DEC_IN_ENDIAN(1) |
+ G1_REG_DEC_OUT_ENDIAN(1) |
+ G1_REG_DEC_ADV_PRE_DIS(0) |
+ G1_REG_DEC_SCMD_DIS(0) |
+ G1_REG_DEC_MAX_BURST(16);
+ vdpu_write_relaxed(vpu, reg, G1_SWREG(2));
+
+ reg = G1_REG_DEC_MODE(5) |
+ G1_REG_RLC_MODE_E(0) |
+ G1_REG_PIC_INTERLACE_E(!sequence->progressive_sequence) |
+ G1_REG_PIC_FIELDMODE_E(picture->picture_structure != PICT_FRAME) |
+ G1_REG_PIC_B_E(picture->picture_coding_type == V4L2_MPEG2_PICTURE_CODING_TYPE_B) |
+ G1_REG_PIC_INTER_E(picture->picture_coding_type != V4L2_MPEG2_PICTURE_CODING_TYPE_I) |
+ G1_REG_PIC_TOPFIELD_E(picture->picture_structure == PICT_TOP_FIELD) |
+ G1_REG_FWD_INTERLACE_E(0) |
+ G1_REG_FILTERING_DIS(1) |
+ G1_REG_WRITE_MVS_E(0) |
+ G1_REG_DEC_AXI_WR_ID(0);
+ vdpu_write_relaxed(vpu, reg, G1_SWREG(3));
+
+ reg = G1_REG_PIC_MB_WIDTH(MPEG2_MB_WIDTH(ctx->dst_fmt.width)) |
+ G1_REG_PIC_MB_HEIGHT_P(MPEG2_MB_HEIGHT(ctx->dst_fmt.height)) |
+ G1_REG_ALT_SCAN_E(picture->alternate_scan) |
+ G1_REG_TOPFIELDFIRST_E(picture->top_field_first);
+ vdpu_write_relaxed(vpu, reg, G1_SWREG(4));
+
+ reg = G1_REG_STRM_START_BIT(slice_params->data_bit_offset) |
+ G1_REG_QSCALE_TYPE(picture->q_scale_type) |
+ G1_REG_CON_MV_E(picture->concealment_motion_vectors) |
+ G1_REG_INTRA_DC_PREC(picture->intra_dc_precision) |
+ G1_REG_INTRA_VLC_TAB(picture->intra_vlc_format) |
+ G1_REG_FRAME_PRED_DCT(picture->frame_pred_frame_dct);
+ vdpu_write_relaxed(vpu, reg, G1_SWREG(5));
+
+ reg = G1_REG_INIT_QP(1) |
+ G1_REG_STREAM_LEN(slice_params->bit_size >> 3);
+ vdpu_write_relaxed(vpu, reg, G1_SWREG(6));
+
+ reg = G1_REG_ALT_SCAN_FLAG_E(picture->alternate_scan) |
+ G1_REG_FCODE_FWD_HOR(picture->f_code[0][0]) |
+ G1_REG_FCODE_FWD_VER(picture->f_code[0][1]) |
+ G1_REG_FCODE_BWD_HOR(picture->f_code[1][0]) |
+ G1_REG_FCODE_BWD_VER(picture->f_code[1][1]) |
+ G1_REG_MV_ACCURACY_FWD(1) |
+ G1_REG_MV_ACCURACY_BWD(1);
+ vdpu_write_relaxed(vpu, reg, G1_SWREG(18));
+
+ reg = G1_REG_STARTMB_X(0) |
+ G1_REG_STARTMB_Y(0);
+ vdpu_write_relaxed(vpu, reg, G1_SWREG(48));
+
+ reg = G1_REG_APF_THRESHOLD(8);
+ vdpu_write_relaxed(vpu, reg, G1_SWREG(55));
+
+ hantro_g1_mpeg2_dec_set_quantization(vpu, ctx);
+
+ hantro_g1_mpeg2_dec_set_buffers(vpu, ctx, &src_buf->vb2_buf,
+ &dst_buf->vb2_buf,
+ sequence, picture, slice_params);
+
+ /* Controls no longer in-use, we can complete them */
+ v4l2_ctrl_request_complete(src_buf->vb2_buf.req_obj.req,
+ &ctx->ctrl_handler);
+
+ /* Kick the watchdog and start decoding */
+ schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000));
+
+ reg = G1_REG_DEC_E(1);
+ vdpu_write(vpu, reg, G1_SWREG(1));
+}
diff --git a/drivers/staging/media/hantro/hantro_g1_regs.h b/drivers/staging/media/hantro/hantro_g1_regs.h
new file mode 100644
index 000000000000..5c0ea7994336
--- /dev/null
+++ b/drivers/staging/media/hantro/hantro_g1_regs.h
@@ -0,0 +1,301 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Hantro VPU codec driver
+ *
+ * Copyright 2018 Google LLC.
+ * Tomasz Figa <tfiga@chromium.org>
+ */
+
+#ifndef HANTRO_G1_REGS_H_
+#define HANTRO_G1_REGS_H_
+
+/* Decoder registers. */
+#define G1_REG_INTERRUPT 0x004
+#define G1_REG_INTERRUPT_DEC_PIC_INF BIT(24)
+#define G1_REG_INTERRUPT_DEC_TIMEOUT BIT(18)
+#define G1_REG_INTERRUPT_DEC_SLICE_INT BIT(17)
+#define G1_REG_INTERRUPT_DEC_ERROR_INT BIT(16)
+#define G1_REG_INTERRUPT_DEC_ASO_INT BIT(15)
+#define G1_REG_INTERRUPT_DEC_BUFFER_INT BIT(14)
+#define G1_REG_INTERRUPT_DEC_BUS_INT BIT(13)
+#define G1_REG_INTERRUPT_DEC_RDY_INT BIT(12)
+#define G1_REG_INTERRUPT_DEC_IRQ BIT(8)
+#define G1_REG_INTERRUPT_DEC_IRQ_DIS BIT(4)
+#define G1_REG_INTERRUPT_DEC_E BIT(0)
+#define G1_REG_CONFIG 0x008
+#define G1_REG_CONFIG_DEC_AXI_RD_ID(x) (((x) & 0xff) << 24)
+#define G1_REG_CONFIG_DEC_TIMEOUT_E BIT(23)
+#define G1_REG_CONFIG_DEC_STRSWAP32_E BIT(22)
+#define G1_REG_CONFIG_DEC_STRENDIAN_E BIT(21)
+#define G1_REG_CONFIG_DEC_INSWAP32_E BIT(20)
+#define G1_REG_CONFIG_DEC_OUTSWAP32_E BIT(19)
+#define G1_REG_CONFIG_DEC_DATA_DISC_E BIT(18)
+#define G1_REG_CONFIG_TILED_MODE_MSB BIT(17)
+#define G1_REG_CONFIG_DEC_OUT_TILED_E BIT(17)
+#define G1_REG_CONFIG_DEC_LATENCY(x) (((x) & 0x3f) << 11)
+#define G1_REG_CONFIG_DEC_CLK_GATE_E BIT(10)
+#define G1_REG_CONFIG_DEC_IN_ENDIAN BIT(9)
+#define G1_REG_CONFIG_DEC_OUT_ENDIAN BIT(8)
+#define G1_REG_CONFIG_PRIORITY_MODE(x) (((x) & 0x7) << 5)
+#define G1_REG_CONFIG_TILED_MODE_LSB BIT(7)
+#define G1_REG_CONFIG_DEC_ADV_PRE_DIS BIT(6)
+#define G1_REG_CONFIG_DEC_SCMD_DIS BIT(5)
+#define G1_REG_CONFIG_DEC_MAX_BURST(x) (((x) & 0x1f) << 0)
+#define G1_REG_DEC_CTRL0 0x00c
+#define G1_REG_DEC_CTRL0_DEC_MODE(x) (((x) & 0xf) << 28)
+#define G1_REG_DEC_CTRL0_RLC_MODE_E BIT(27)
+#define G1_REG_DEC_CTRL0_SKIP_MODE BIT(26)
+#define G1_REG_DEC_CTRL0_DIVX3_E BIT(25)
+#define G1_REG_DEC_CTRL0_PJPEG_E BIT(24)
+#define G1_REG_DEC_CTRL0_PIC_INTERLACE_E BIT(23)
+#define G1_REG_DEC_CTRL0_PIC_FIELDMODE_E BIT(22)
+#define G1_REG_DEC_CTRL0_PIC_B_E BIT(21)
+#define G1_REG_DEC_CTRL0_PIC_INTER_E BIT(20)
+#define G1_REG_DEC_CTRL0_PIC_TOPFIELD_E BIT(19)
+#define G1_REG_DEC_CTRL0_FWD_INTERLACE_E BIT(18)
+#define G1_REG_DEC_CTRL0_SORENSON_E BIT(17)
+#define G1_REG_DEC_CTRL0_REF_TOPFIELD_E BIT(16)
+#define G1_REG_DEC_CTRL0_DEC_OUT_DIS BIT(15)
+#define G1_REG_DEC_CTRL0_FILTERING_DIS BIT(14)
+#define G1_REG_DEC_CTRL0_WEBP_E BIT(13)
+#define G1_REG_DEC_CTRL0_MVC_E BIT(13)
+#define G1_REG_DEC_CTRL0_PIC_FIXED_QUANT BIT(13)
+#define G1_REG_DEC_CTRL0_WRITE_MVS_E BIT(12)
+#define G1_REG_DEC_CTRL0_REFTOPFIRST_E BIT(11)
+#define G1_REG_DEC_CTRL0_SEQ_MBAFF_E BIT(10)
+#define G1_REG_DEC_CTRL0_PICORD_COUNT_E BIT(9)
+#define G1_REG_DEC_CTRL0_DEC_AHB_HLOCK_E BIT(8)
+#define G1_REG_DEC_CTRL0_DEC_AXI_WR_ID(x) (((x) & 0xff) << 0)
+#define G1_REG_DEC_CTRL1 0x010
+#define G1_REG_DEC_CTRL1_PIC_MB_WIDTH(x) (((x) & 0x1ff) << 23)
+#define G1_REG_DEC_CTRL1_MB_WIDTH_OFF(x) (((x) & 0xf) << 19)
+#define G1_REG_DEC_CTRL1_PIC_MB_HEIGHT_P(x) (((x) & 0xff) << 11)
+#define G1_REG_DEC_CTRL1_MB_HEIGHT_OFF(x) (((x) & 0xf) << 7)
+#define G1_REG_DEC_CTRL1_ALT_SCAN_E BIT(6)
+#define G1_REG_DEC_CTRL1_TOPFIELDFIRST_E BIT(5)
+#define G1_REG_DEC_CTRL1_REF_FRAMES(x) (((x) & 0x1f) << 0)
+#define G1_REG_DEC_CTRL1_PIC_MB_W_EXT(x) (((x) & 0x7) << 3)
+#define G1_REG_DEC_CTRL1_PIC_MB_H_EXT(x) (((x) & 0x7) << 0)
+#define G1_REG_DEC_CTRL1_PIC_REFER_FLAG BIT(0)
+#define G1_REG_DEC_CTRL2 0x014
+#define G1_REG_DEC_CTRL2_STRM_START_BIT(x) (((x) & 0x3f) << 26)
+#define G1_REG_DEC_CTRL2_SYNC_MARKER_E BIT(25)
+#define G1_REG_DEC_CTRL2_TYPE1_QUANT_E BIT(24)
+#define G1_REG_DEC_CTRL2_CH_QP_OFFSET(x) (((x) & 0x1f) << 19)
+#define G1_REG_DEC_CTRL2_CH_QP_OFFSET2(x) (((x) & 0x1f) << 14)
+#define G1_REG_DEC_CTRL2_FIELDPIC_FLAG_E BIT(0)
+#define G1_REG_DEC_CTRL2_INTRADC_VLC_THR(x) (((x) & 0x7) << 16)
+#define G1_REG_DEC_CTRL2_VOP_TIME_INCR(x) (((x) & 0xffff) << 0)
+#define G1_REG_DEC_CTRL2_DQ_PROFILE BIT(24)
+#define G1_REG_DEC_CTRL2_DQBI_LEVEL BIT(23)
+#define G1_REG_DEC_CTRL2_RANGE_RED_FRM_E BIT(22)
+#define G1_REG_DEC_CTRL2_FAST_UVMC_E BIT(20)
+#define G1_REG_DEC_CTRL2_TRANSDCTAB BIT(17)
+#define G1_REG_DEC_CTRL2_TRANSACFRM(x) (((x) & 0x3) << 15)
+#define G1_REG_DEC_CTRL2_TRANSACFRM2(x) (((x) & 0x3) << 13)
+#define G1_REG_DEC_CTRL2_MB_MODE_TAB(x) (((x) & 0x7) << 10)
+#define G1_REG_DEC_CTRL2_MVTAB(x) (((x) & 0x7) << 7)
+#define G1_REG_DEC_CTRL2_CBPTAB(x) (((x) & 0x7) << 4)
+#define G1_REG_DEC_CTRL2_2MV_BLK_PAT_TAB(x) (((x) & 0x3) << 2)
+#define G1_REG_DEC_CTRL2_4MV_BLK_PAT_TAB(x) (((x) & 0x3) << 0)
+#define G1_REG_DEC_CTRL2_QSCALE_TYPE BIT(24)
+#define G1_REG_DEC_CTRL2_CON_MV_E BIT(4)
+#define G1_REG_DEC_CTRL2_INTRA_DC_PREC(x) (((x) & 0x3) << 2)
+#define G1_REG_DEC_CTRL2_INTRA_VLC_TAB BIT(1)
+#define G1_REG_DEC_CTRL2_FRAME_PRED_DCT BIT(0)
+#define G1_REG_DEC_CTRL2_JPEG_QTABLES(x) (((x) & 0x3) << 11)
+#define G1_REG_DEC_CTRL2_JPEG_MODE(x) (((x) & 0x7) << 8)
+#define G1_REG_DEC_CTRL2_JPEG_FILRIGHT_E BIT(7)
+#define G1_REG_DEC_CTRL2_JPEG_STREAM_ALL BIT(6)
+#define G1_REG_DEC_CTRL2_CR_AC_VLCTABLE BIT(5)
+#define G1_REG_DEC_CTRL2_CB_AC_VLCTABLE BIT(4)
+#define G1_REG_DEC_CTRL2_CR_DC_VLCTABLE BIT(3)
+#define G1_REG_DEC_CTRL2_CB_DC_VLCTABLE BIT(2)
+#define G1_REG_DEC_CTRL2_CR_DC_VLCTABLE3 BIT(1)
+#define G1_REG_DEC_CTRL2_CB_DC_VLCTABLE3 BIT(0)
+#define G1_REG_DEC_CTRL2_STRM1_START_BIT(x) (((x) & 0x3f) << 18)
+#define G1_REG_DEC_CTRL2_HUFFMAN_E BIT(17)
+#define G1_REG_DEC_CTRL2_MULTISTREAM_E BIT(16)
+#define G1_REG_DEC_CTRL2_BOOLEAN_VALUE(x) (((x) & 0xff) << 8)
+#define G1_REG_DEC_CTRL2_BOOLEAN_RANGE(x) (((x) & 0xff) << 0)
+#define G1_REG_DEC_CTRL2_ALPHA_OFFSET(x) (((x) & 0x1f) << 5)
+#define G1_REG_DEC_CTRL2_BETA_OFFSET(x) (((x) & 0x1f) << 0)
+#define G1_REG_DEC_CTRL3 0x018
+#define G1_REG_DEC_CTRL3_START_CODE_E BIT(31)
+#define G1_REG_DEC_CTRL3_INIT_QP(x) (((x) & 0x3f) << 25)
+#define G1_REG_DEC_CTRL3_CH_8PIX_ILEAV_E BIT(24)
+#define G1_REG_DEC_CTRL3_STREAM_LEN_EXT(x) (((x) & 0xff) << 24)
+#define G1_REG_DEC_CTRL3_STREAM_LEN(x) (((x) & 0xffffff) << 0)
+#define G1_REG_DEC_CTRL4 0x01c
+#define G1_REG_DEC_CTRL4_CABAC_E BIT(31)
+#define G1_REG_DEC_CTRL4_BLACKWHITE_E BIT(30)
+#define G1_REG_DEC_CTRL4_DIR_8X8_INFER_E BIT(29)
+#define G1_REG_DEC_CTRL4_WEIGHT_PRED_E BIT(28)
+#define G1_REG_DEC_CTRL4_WEIGHT_BIPR_IDC(x) (((x) & 0x3) << 26)
+#define G1_REG_DEC_CTRL4_AVS_H264_H_EXT BIT(25)
+#define G1_REG_DEC_CTRL4_FRAMENUM_LEN(x) (((x) & 0x1f) << 16)
+#define G1_REG_DEC_CTRL4_FRAMENUM(x) (((x) & 0xffff) << 0)
+#define G1_REG_DEC_CTRL4_BITPLANE0_E BIT(31)
+#define G1_REG_DEC_CTRL4_BITPLANE1_E BIT(30)
+#define G1_REG_DEC_CTRL4_BITPLANE2_E BIT(29)
+#define G1_REG_DEC_CTRL4_ALT_PQUANT(x) (((x) & 0x1f) << 24)
+#define G1_REG_DEC_CTRL4_DQ_EDGES(x) (((x) & 0xf) << 20)
+#define G1_REG_DEC_CTRL4_TTMBF BIT(19)
+#define G1_REG_DEC_CTRL4_PQINDEX(x) (((x) & 0x1f) << 14)
+#define G1_REG_DEC_CTRL4_VC1_HEIGHT_EXT BIT(13)
+#define G1_REG_DEC_CTRL4_BILIN_MC_E BIT(12)
+#define G1_REG_DEC_CTRL4_UNIQP_E BIT(11)
+#define G1_REG_DEC_CTRL4_HALFQP_E BIT(10)
+#define G1_REG_DEC_CTRL4_TTFRM(x) (((x) & 0x3) << 8)
+#define G1_REG_DEC_CTRL4_2ND_BYTE_EMUL_E BIT(7)
+#define G1_REG_DEC_CTRL4_DQUANT_E BIT(6)
+#define G1_REG_DEC_CTRL4_VC1_ADV_E BIT(5)
+#define G1_REG_DEC_CTRL4_PJPEG_FILDOWN_E BIT(26)
+#define G1_REG_DEC_CTRL4_PJPEG_WDIV8 BIT(25)
+#define G1_REG_DEC_CTRL4_PJPEG_HDIV8 BIT(24)
+#define G1_REG_DEC_CTRL4_PJPEG_AH(x) (((x) & 0xf) << 20)
+#define G1_REG_DEC_CTRL4_PJPEG_AL(x) (((x) & 0xf) << 16)
+#define G1_REG_DEC_CTRL4_PJPEG_SS(x) (((x) & 0xff) << 8)
+#define G1_REG_DEC_CTRL4_PJPEG_SE(x) (((x) & 0xff) << 0)
+#define G1_REG_DEC_CTRL4_DCT1_START_BIT(x) (((x) & 0x3f) << 26)
+#define G1_REG_DEC_CTRL4_DCT2_START_BIT(x) (((x) & 0x3f) << 20)
+#define G1_REG_DEC_CTRL4_CH_MV_RES BIT(13)
+#define G1_REG_DEC_CTRL4_INIT_DC_MATCH0(x) (((x) & 0x7) << 9)
+#define G1_REG_DEC_CTRL4_INIT_DC_MATCH1(x) (((x) & 0x7) << 6)
+#define G1_REG_DEC_CTRL4_VP7_VERSION BIT(5)
+#define G1_REG_DEC_CTRL5 0x020
+#define G1_REG_DEC_CTRL5_CONST_INTRA_E BIT(31)
+#define G1_REG_DEC_CTRL5_FILT_CTRL_PRES BIT(30)
+#define G1_REG_DEC_CTRL5_RDPIC_CNT_PRES BIT(29)
+#define G1_REG_DEC_CTRL5_8X8TRANS_FLAG_E BIT(28)
+#define G1_REG_DEC_CTRL5_REFPIC_MK_LEN(x) (((x) & 0x7ff) << 17)
+#define G1_REG_DEC_CTRL5_IDR_PIC_E BIT(16)
+#define G1_REG_DEC_CTRL5_IDR_PIC_ID(x) (((x) & 0xffff) << 0)
+#define G1_REG_DEC_CTRL5_MV_SCALEFACTOR(x) (((x) & 0xff) << 24)
+#define G1_REG_DEC_CTRL5_REF_DIST_FWD(x) (((x) & 0x1f) << 19)
+#define G1_REG_DEC_CTRL5_REF_DIST_BWD(x) (((x) & 0x1f) << 14)
+#define G1_REG_DEC_CTRL5_LOOP_FILT_LIMIT(x) (((x) & 0xf) << 14)
+#define G1_REG_DEC_CTRL5_VARIANCE_TEST_E BIT(13)
+#define G1_REG_DEC_CTRL5_MV_THRESHOLD(x) (((x) & 0x7) << 10)
+#define G1_REG_DEC_CTRL5_VAR_THRESHOLD(x) (((x) & 0x3ff) << 0)
+#define G1_REG_DEC_CTRL5_DIVX_IDCT_E BIT(8)
+#define G1_REG_DEC_CTRL5_DIVX3_SLICE_SIZE(x) (((x) & 0xff) << 0)
+#define G1_REG_DEC_CTRL5_PJPEG_REST_FREQ(x) (((x) & 0xffff) << 0)
+#define G1_REG_DEC_CTRL5_RV_PROFILE(x) (((x) & 0x3) << 30)
+#define G1_REG_DEC_CTRL5_RV_OSV_QUANT(x) (((x) & 0x3) << 28)
+#define G1_REG_DEC_CTRL5_RV_FWD_SCALE(x) (((x) & 0x3fff) << 14)
+#define G1_REG_DEC_CTRL5_RV_BWD_SCALE(x) (((x) & 0x3fff) << 0)
+#define G1_REG_DEC_CTRL5_INIT_DC_COMP0(x) (((x) & 0xffff) << 16)
+#define G1_REG_DEC_CTRL5_INIT_DC_COMP1(x) (((x) & 0xffff) << 0)
+#define G1_REG_DEC_CTRL6 0x024
+#define G1_REG_DEC_CTRL6_PPS_ID(x) (((x) & 0xff) << 24)
+#define G1_REG_DEC_CTRL6_REFIDX1_ACTIVE(x) (((x) & 0x1f) << 19)
+#define G1_REG_DEC_CTRL6_REFIDX0_ACTIVE(x) (((x) & 0x1f) << 14)
+#define G1_REG_DEC_CTRL6_POC_LENGTH(x) (((x) & 0xff) << 0)
+#define G1_REG_DEC_CTRL6_ICOMP0_E BIT(24)
+#define G1_REG_DEC_CTRL6_ISCALE0(x) (((x) & 0xff) << 16)
+#define G1_REG_DEC_CTRL6_ISHIFT0(x) (((x) & 0xffff) << 0)
+#define G1_REG_DEC_CTRL6_STREAM1_LEN(x) (((x) & 0xffffff) << 0)
+#define G1_REG_DEC_CTRL6_PIC_SLICE_AM(x) (((x) & 0x1fff) << 0)
+#define G1_REG_DEC_CTRL6_COEFFS_PART_AM(x) (((x) & 0xf) << 24)
+#define G1_REG_FWD_PIC(i) (0x028 + ((i) * 0x4))
+#define G1_REG_FWD_PIC_PINIT_RLIST_F5(x) (((x) & 0x1f) << 25)
+#define G1_REG_FWD_PIC_PINIT_RLIST_F4(x) (((x) & 0x1f) << 20)
+#define G1_REG_FWD_PIC_PINIT_RLIST_F3(x) (((x) & 0x1f) << 15)
+#define G1_REG_FWD_PIC_PINIT_RLIST_F2(x) (((x) & 0x1f) << 10)
+#define G1_REG_FWD_PIC_PINIT_RLIST_F1(x) (((x) & 0x1f) << 5)
+#define G1_REG_FWD_PIC_PINIT_RLIST_F0(x) (((x) & 0x1f) << 0)
+#define G1_REG_FWD_PIC1_ICOMP1_E BIT(24)
+#define G1_REG_FWD_PIC1_ISCALE1(x) (((x) & 0xff) << 16)
+#define G1_REG_FWD_PIC1_ISHIFT1(x) (((x) & 0xffff) << 0)
+#define G1_REG_FWD_PIC1_SEGMENT_BASE(x) ((x) << 0)
+#define G1_REG_FWD_PIC1_SEGMENT_UPD_E BIT(1)
+#define G1_REG_FWD_PIC1_SEGMENT_E BIT(0)
+#define G1_REG_DEC_CTRL7 0x02c
+#define G1_REG_DEC_CTRL7_PINIT_RLIST_F15(x) (((x) & 0x1f) << 25)
+#define G1_REG_DEC_CTRL7_PINIT_RLIST_F14(x) (((x) & 0x1f) << 20)
+#define G1_REG_DEC_CTRL7_PINIT_RLIST_F13(x) (((x) & 0x1f) << 15)
+#define G1_REG_DEC_CTRL7_PINIT_RLIST_F12(x) (((x) & 0x1f) << 10)
+#define G1_REG_DEC_CTRL7_PINIT_RLIST_F11(x) (((x) & 0x1f) << 5)
+#define G1_REG_DEC_CTRL7_PINIT_RLIST_F10(x) (((x) & 0x1f) << 0)
+#define G1_REG_DEC_CTRL7_ICOMP2_E BIT(24)
+#define G1_REG_DEC_CTRL7_ISCALE2(x) (((x) & 0xff) << 16)
+#define G1_REG_DEC_CTRL7_ISHIFT2(x) (((x) & 0xffff) << 0)
+#define G1_REG_DEC_CTRL7_DCT3_START_BIT(x) (((x) & 0x3f) << 24)
+#define G1_REG_DEC_CTRL7_DCT4_START_BIT(x) (((x) & 0x3f) << 18)
+#define G1_REG_DEC_CTRL7_DCT5_START_BIT(x) (((x) & 0x3f) << 12)
+#define G1_REG_DEC_CTRL7_DCT6_START_BIT(x) (((x) & 0x3f) << 6)
+#define G1_REG_DEC_CTRL7_DCT7_START_BIT(x) (((x) & 0x3f) << 0)
+#define G1_REG_ADDR_STR 0x030
+#define G1_REG_ADDR_DST 0x034
+#define G1_REG_ADDR_REF(i) (0x038 + ((i) * 0x4))
+#define G1_REG_ADDR_REF_FIELD_E BIT(1)
+#define G1_REG_ADDR_REF_TOPC_E BIT(0)
+#define G1_REG_REF_PIC(i) (0x078 + ((i) * 0x4))
+#define G1_REG_REF_PIC_FILT_TYPE_E BIT(31)
+#define G1_REG_REF_PIC_FILT_SHARPNESS(x) (((x) & 0x7) << 28)
+#define G1_REG_REF_PIC_MB_ADJ_0(x) (((x) & 0x7f) << 21)
+#define G1_REG_REF_PIC_MB_ADJ_1(x) (((x) & 0x7f) << 14)
+#define G1_REG_REF_PIC_MB_ADJ_2(x) (((x) & 0x7f) << 7)
+#define G1_REG_REF_PIC_MB_ADJ_3(x) (((x) & 0x7f) << 0)
+#define G1_REG_REF_PIC_REFER1_NBR(x) (((x) & 0xffff) << 16)
+#define G1_REG_REF_PIC_REFER0_NBR(x) (((x) & 0xffff) << 0)
+#define G1_REG_REF_PIC_LF_LEVEL_0(x) (((x) & 0x3f) << 18)
+#define G1_REG_REF_PIC_LF_LEVEL_1(x) (((x) & 0x3f) << 12)
+#define G1_REG_REF_PIC_LF_LEVEL_2(x) (((x) & 0x3f) << 6)
+#define G1_REG_REF_PIC_LF_LEVEL_3(x) (((x) & 0x3f) << 0)
+#define G1_REG_REF_PIC_QUANT_DELTA_0(x) (((x) & 0x1f) << 27)
+#define G1_REG_REF_PIC_QUANT_DELTA_1(x) (((x) & 0x1f) << 22)
+#define G1_REG_REF_PIC_QUANT_0(x) (((x) & 0x7ff) << 11)
+#define G1_REG_REF_PIC_QUANT_1(x) (((x) & 0x7ff) << 0)
+#define G1_REG_LT_REF 0x098
+#define G1_REG_VALID_REF 0x09c
+#define G1_REG_ADDR_QTABLE 0x0a0
+#define G1_REG_ADDR_DIR_MV 0x0a4
+#define G1_REG_BD_REF_PIC(i) (0x0a8 + ((i) * 0x4))
+#define G1_REG_BD_REF_PIC_BINIT_RLIST_B2(x) (((x) & 0x1f) << 25)
+#define G1_REG_BD_REF_PIC_BINIT_RLIST_F2(x) (((x) & 0x1f) << 20)
+#define G1_REG_BD_REF_PIC_BINIT_RLIST_B1(x) (((x) & 0x1f) << 15)
+#define G1_REG_BD_REF_PIC_BINIT_RLIST_F1(x) (((x) & 0x1f) << 10)
+#define G1_REG_BD_REF_PIC_BINIT_RLIST_B0(x) (((x) & 0x1f) << 5)
+#define G1_REG_BD_REF_PIC_BINIT_RLIST_F0(x) (((x) & 0x1f) << 0)
+#define G1_REG_BD_REF_PIC_PRED_TAP_2_M1(x) (((x) & 0x3) << 10)
+#define G1_REG_BD_REF_PIC_PRED_TAP_2_4(x) (((x) & 0x3) << 8)
+#define G1_REG_BD_REF_PIC_PRED_TAP_4_M1(x) (((x) & 0x3) << 6)
+#define G1_REG_BD_REF_PIC_PRED_TAP_4_4(x) (((x) & 0x3) << 4)
+#define G1_REG_BD_REF_PIC_PRED_TAP_6_M1(x) (((x) & 0x3) << 2)
+#define G1_REG_BD_REF_PIC_PRED_TAP_6_4(x) (((x) & 0x3) << 0)
+#define G1_REG_BD_REF_PIC_QUANT_DELTA_2(x) (((x) & 0x1f) << 27)
+#define G1_REG_BD_REF_PIC_QUANT_DELTA_3(x) (((x) & 0x1f) << 22)
+#define G1_REG_BD_REF_PIC_QUANT_2(x) (((x) & 0x7ff) << 11)
+#define G1_REG_BD_REF_PIC_QUANT_3(x) (((x) & 0x7ff) << 0)
+#define G1_REG_BD_P_REF_PIC 0x0bc
+#define G1_REG_BD_P_REF_PIC_QUANT_DELTA_4(x) (((x) & 0x1f) << 27)
+#define G1_REG_BD_P_REF_PIC_PINIT_RLIST_F3(x) (((x) & 0x1f) << 25)
+#define G1_REG_BD_P_REF_PIC_PINIT_RLIST_F2(x) (((x) & 0x1f) << 20)
+#define G1_REG_BD_P_REF_PIC_PINIT_RLIST_F1(x) (((x) & 0x1f) << 15)
+#define G1_REG_BD_P_REF_PIC_PINIT_RLIST_F0(x) (((x) & 0x1f) << 10)
+#define G1_REG_BD_P_REF_PIC_BINIT_RLIST_B15(x) (((x) & 0x1f) << 5)
+#define G1_REG_BD_P_REF_PIC_BINIT_RLIST_F15(x) (((x) & 0x1f) << 0)
+#define G1_REG_ERR_CONC 0x0c0
+#define G1_REG_ERR_CONC_STARTMB_X(x) (((x) & 0x1ff) << 23)
+#define G1_REG_ERR_CONC_STARTMB_Y(x) (((x) & 0xff) << 15)
+#define G1_REG_PRED_FLT 0x0c4
+#define G1_REG_PRED_FLT_PRED_BC_TAP_0_0(x) (((x) & 0x3ff) << 22)
+#define G1_REG_PRED_FLT_PRED_BC_TAP_0_1(x) (((x) & 0x3ff) << 12)
+#define G1_REG_PRED_FLT_PRED_BC_TAP_0_2(x) (((x) & 0x3ff) << 2)
+#define G1_REG_REF_BUF_CTRL 0x0cc
+#define G1_REG_REF_BUF_CTRL_REFBU_E BIT(31)
+#define G1_REG_REF_BUF_CTRL_REFBU_THR(x) (((x) & 0xfff) << 19)
+#define G1_REG_REF_BUF_CTRL_REFBU_PICID(x) (((x) & 0x1f) << 14)
+#define G1_REG_REF_BUF_CTRL_REFBU_EVAL_E BIT(13)
+#define G1_REG_REF_BUF_CTRL_REFBU_FPARMOD_E BIT(12)
+#define G1_REG_REF_BUF_CTRL_REFBU_Y_OFFSET(x) (((x) & 0x1ff) << 0)
+#define G1_REG_REF_BUF_CTRL2 0x0dc
+#define G1_REG_REF_BUF_CTRL2_REFBU2_BUF_E BIT(31)
+#define G1_REG_REF_BUF_CTRL2_REFBU2_THR(x) (((x) & 0xfff) << 19)
+#define G1_REG_REF_BUF_CTRL2_REFBU2_PICID(x) (((x) & 0x1f) << 14)
+#define G1_REG_REF_BUF_CTRL2_APF_THRESHOLD(x) (((x) & 0x3fff) << 0)
+#define G1_REG_SOFT_RESET 0x194
+
+#endif /* HANTRO_G1_REGS_H_ */
diff --git a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c
new file mode 100644
index 000000000000..0c1e3043dc7e
--- /dev/null
+++ b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Hantro VPU codec driver
+ *
+ * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
+ */
+
+#include <asm/unaligned.h>
+#include <media/v4l2-mem2mem.h>
+#include "hantro_jpeg.h"
+#include "hantro.h"
+#include "hantro_v4l2.h"
+#include "hantro_hw.h"
+#include "hantro_h1_regs.h"
+
+#define H1_JPEG_QUANT_TABLE_COUNT 16
+
+static void hantro_h1_set_src_img_ctrl(struct hantro_dev *vpu,
+ struct hantro_ctx *ctx)
+{
+ struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt;
+ u32 reg;
+
+ reg = H1_REG_IN_IMG_CTRL_ROW_LEN(pix_fmt->width)
+ | H1_REG_IN_IMG_CTRL_OVRFLR_D4(0)
+ | H1_REG_IN_IMG_CTRL_OVRFLB_D4(0)
+ | H1_REG_IN_IMG_CTRL_FMT(ctx->vpu_src_fmt->enc_fmt);
+ vepu_write_relaxed(vpu, reg, H1_REG_IN_IMG_CTRL);
+}
+
+static void hantro_h1_jpeg_enc_set_buffers(struct hantro_dev *vpu,
+ struct hantro_ctx *ctx,
+ struct vb2_buffer *src_buf)
+{
+ struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt;
+ dma_addr_t src[3];
+
+ WARN_ON(pix_fmt->num_planes > 3);
+
+ vepu_write_relaxed(vpu, ctx->jpeg_enc.bounce_buffer.dma,
+ H1_REG_ADDR_OUTPUT_STREAM);
+ vepu_write_relaxed(vpu, ctx->jpeg_enc.bounce_buffer.size,
+ H1_REG_STR_BUF_LIMIT);
+
+ if (pix_fmt->num_planes == 1) {
+ src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+ /* single plane formats we supported are all interlaced */
+ vepu_write_relaxed(vpu, src[0], H1_REG_ADDR_IN_PLANE_0);
+ } else if (pix_fmt->num_planes == 2) {
+ src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+ src[1] = vb2_dma_contig_plane_dma_addr(src_buf, 1);
+ vepu_write_relaxed(vpu, src[0], H1_REG_ADDR_IN_PLANE_0);
+ vepu_write_relaxed(vpu, src[1], H1_REG_ADDR_IN_PLANE_1);
+ } else {
+ src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+ src[1] = vb2_dma_contig_plane_dma_addr(src_buf, 1);
+ src[2] = vb2_dma_contig_plane_dma_addr(src_buf, 2);
+ vepu_write_relaxed(vpu, src[0], H1_REG_ADDR_IN_PLANE_0);
+ vepu_write_relaxed(vpu, src[1], H1_REG_ADDR_IN_PLANE_1);
+ vepu_write_relaxed(vpu, src[2], H1_REG_ADDR_IN_PLANE_2);
+ }
+}
+
+static void
+hantro_h1_jpeg_enc_set_qtable(struct hantro_dev *vpu,
+ unsigned char *luma_qtable,
+ unsigned char *chroma_qtable)
+{
+ u32 reg, i;
+
+ for (i = 0; i < H1_JPEG_QUANT_TABLE_COUNT; i++) {
+ reg = get_unaligned_be32(&luma_qtable[i]);
+ vepu_write_relaxed(vpu, reg, H1_REG_JPEG_LUMA_QUAT(i));
+
+ reg = get_unaligned_be32(&chroma_qtable[i]);
+ vepu_write_relaxed(vpu, reg, H1_REG_JPEG_CHROMA_QUAT(i));
+ }
+}
+
+void hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx)
+{
+ struct hantro_dev *vpu = ctx->dev;
+ struct vb2_v4l2_buffer *src_buf, *dst_buf;
+ struct hantro_jpeg_ctx jpeg_ctx;
+ u32 reg;
+
+ src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+
+ memset(&jpeg_ctx, 0, sizeof(jpeg_ctx));
+ jpeg_ctx.buffer = vb2_plane_vaddr(&dst_buf->vb2_buf, 0);
+ jpeg_ctx.width = ctx->dst_fmt.width;
+ jpeg_ctx.height = ctx->dst_fmt.height;
+ jpeg_ctx.quality = ctx->jpeg_quality;
+ hantro_jpeg_header_assemble(&jpeg_ctx);
+
+ /* Switch to JPEG encoder mode before writing registers */
+ vepu_write_relaxed(vpu, H1_REG_ENC_CTRL_ENC_MODE_JPEG,
+ H1_REG_ENC_CTRL);
+
+ hantro_h1_set_src_img_ctrl(vpu, ctx);
+ hantro_h1_jpeg_enc_set_buffers(vpu, ctx, &src_buf->vb2_buf);
+ hantro_h1_jpeg_enc_set_qtable(vpu,
+ hantro_jpeg_get_qtable(&jpeg_ctx, 0),
+ hantro_jpeg_get_qtable(&jpeg_ctx, 1));
+
+ reg = H1_REG_AXI_CTRL_OUTPUT_SWAP16
+ | H1_REG_AXI_CTRL_INPUT_SWAP16
+ | H1_REG_AXI_CTRL_BURST_LEN(16)
+ | H1_REG_AXI_CTRL_OUTPUT_SWAP32
+ | H1_REG_AXI_CTRL_INPUT_SWAP32
+ | H1_REG_AXI_CTRL_OUTPUT_SWAP8
+ | H1_REG_AXI_CTRL_INPUT_SWAP8;
+ /* Make sure that all registers are written at this point. */
+ vepu_write(vpu, reg, H1_REG_AXI_CTRL);
+
+ reg = H1_REG_ENC_CTRL_WIDTH(JPEG_MB_WIDTH(ctx->src_fmt.width))
+ | H1_REG_ENC_CTRL_HEIGHT(JPEG_MB_HEIGHT(ctx->src_fmt.height))
+ | H1_REG_ENC_CTRL_ENC_MODE_JPEG
+ | H1_REG_ENC_PIC_INTRA
+ | H1_REG_ENC_CTRL_EN_BIT;
+ /* Kick the watchdog and start encoding */
+ schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000));
+ vepu_write(vpu, reg, H1_REG_ENC_CTRL);
+}
diff --git a/drivers/staging/media/hantro/hantro_h1_regs.h b/drivers/staging/media/hantro/hantro_h1_regs.h
new file mode 100644
index 000000000000..d6e9825bb5c7
--- /dev/null
+++ b/drivers/staging/media/hantro/hantro_h1_regs.h
@@ -0,0 +1,154 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Hantro VPU codec driver
+ *
+ * Copyright 2018 Google LLC.
+ * Tomasz Figa <tfiga@chromium.org>
+ */
+
+#ifndef HANTRO_H1_REGS_H_
+#define HANTRO_H1_REGS_H_
+
+/* Encoder registers. */
+#define H1_REG_INTERRUPT 0x004
+#define H1_REG_INTERRUPT_FRAME_RDY BIT(2)
+#define H1_REG_INTERRUPT_DIS_BIT BIT(1)
+#define H1_REG_INTERRUPT_BIT BIT(0)
+#define H1_REG_AXI_CTRL 0x008
+#define H1_REG_AXI_CTRL_OUTPUT_SWAP16 BIT(15)
+#define H1_REG_AXI_CTRL_INPUT_SWAP16 BIT(14)
+#define H1_REG_AXI_CTRL_BURST_LEN(x) ((x) << 8)
+#define H1_REG_AXI_CTRL_GATE_BIT BIT(4)
+#define H1_REG_AXI_CTRL_OUTPUT_SWAP32 BIT(3)
+#define H1_REG_AXI_CTRL_INPUT_SWAP32 BIT(2)
+#define H1_REG_AXI_CTRL_OUTPUT_SWAP8 BIT(1)
+#define H1_REG_AXI_CTRL_INPUT_SWAP8 BIT(0)
+#define H1_REG_ADDR_OUTPUT_STREAM 0x014
+#define H1_REG_ADDR_OUTPUT_CTRL 0x018
+#define H1_REG_ADDR_REF_LUMA 0x01c
+#define H1_REG_ADDR_REF_CHROMA 0x020
+#define H1_REG_ADDR_REC_LUMA 0x024
+#define H1_REG_ADDR_REC_CHROMA 0x028
+#define H1_REG_ADDR_IN_PLANE_0 0x02c
+#define H1_REG_ADDR_IN_PLANE_1 0x030
+#define H1_REG_ADDR_IN_PLANE_2 0x034
+#define H1_REG_ENC_CTRL 0x038
+#define H1_REG_ENC_CTRL_TIMEOUT_EN BIT(31)
+#define H1_REG_ENC_CTRL_NAL_MODE_BIT BIT(29)
+#define H1_REG_ENC_CTRL_WIDTH(w) ((w) << 19)
+#define H1_REG_ENC_CTRL_HEIGHT(h) ((h) << 10)
+#define H1_REG_ENC_PIC_INTER (0x0 << 3)
+#define H1_REG_ENC_PIC_INTRA (0x1 << 3)
+#define H1_REG_ENC_PIC_MVCINTER (0x2 << 3)
+#define H1_REG_ENC_CTRL_ENC_MODE_H264 (0x3 << 1)
+#define H1_REG_ENC_CTRL_ENC_MODE_JPEG (0x2 << 1)
+#define H1_REG_ENC_CTRL_ENC_MODE_VP8 (0x1 << 1)
+#define H1_REG_ENC_CTRL_EN_BIT BIT(0)
+#define H1_REG_IN_IMG_CTRL 0x03c
+#define H1_REG_IN_IMG_CTRL_ROW_LEN(x) ((x) << 12)
+#define H1_REG_IN_IMG_CTRL_OVRFLR_D4(x) ((x) << 10)
+#define H1_REG_IN_IMG_CTRL_OVRFLB_D4(x) ((x) << 6)
+#define H1_REG_IN_IMG_CTRL_FMT(x) ((x) << 2)
+#define H1_REG_ENC_CTRL0 0x040
+#define H1_REG_ENC_CTRL0_INIT_QP(x) ((x) << 26)
+#define H1_REG_ENC_CTRL0_SLICE_ALPHA(x) ((x) << 22)
+#define H1_REG_ENC_CTRL0_SLICE_BETA(x) ((x) << 18)
+#define H1_REG_ENC_CTRL0_CHROMA_QP_OFFSET(x) ((x) << 13)
+#define H1_REG_ENC_CTRL0_FILTER_DIS(x) ((x) << 5)
+#define H1_REG_ENC_CTRL0_IDR_PICID(x) ((x) << 1)
+#define H1_REG_ENC_CTRL0_CONSTR_INTRA_PRED BIT(0)
+#define H1_REG_ENC_CTRL1 0x044
+#define H1_REG_ENC_CTRL1_PPS_ID(x) ((x) << 24)
+#define H1_REG_ENC_CTRL1_INTRA_PRED_MODE(x) ((x) << 16)
+#define H1_REG_ENC_CTRL1_FRAME_NUM(x) ((x))
+#define H1_REG_ENC_CTRL2 0x048
+#define H1_REG_ENC_CTRL2_DEBLOCKING_FILETER_MODE(x) ((x) << 30)
+#define H1_REG_ENC_CTRL2_H264_SLICE_SIZE(x) ((x) << 23)
+#define H1_REG_ENC_CTRL2_DISABLE_QUARTER_PIXMV BIT(22)
+#define H1_REG_ENC_CTRL2_TRANS8X8_MODE_EN BIT(21)
+#define H1_REG_ENC_CTRL2_CABAC_INIT_IDC(x) ((x) << 19)
+#define H1_REG_ENC_CTRL2_ENTROPY_CODING_MODE BIT(18)
+#define H1_REG_ENC_CTRL2_H264_INTER4X4_MODE BIT(17)
+#define H1_REG_ENC_CTRL2_H264_STREAM_MODE BIT(16)
+#define H1_REG_ENC_CTRL2_INTRA16X16_MODE(x) ((x))
+#define H1_REG_ENC_CTRL3 0x04c
+#define H1_REG_ENC_CTRL3_MUTIMV_EN BIT(30)
+#define H1_REG_ENC_CTRL3_MV_PENALTY_1_4P(x) ((x) << 20)
+#define H1_REG_ENC_CTRL3_MV_PENALTY_4P(x) ((x) << 10)
+#define H1_REG_ENC_CTRL3_MV_PENALTY_1P(x) ((x))
+#define H1_REG_ENC_CTRL4 0x050
+#define H1_REG_ENC_CTRL4_MV_PENALTY_16X8_8X16(x) ((x) << 20)
+#define H1_REG_ENC_CTRL4_MV_PENALTY_8X8(x) ((x) << 10)
+#define H1_REG_ENC_CTRL4_8X4_4X8(x) ((x))
+#define H1_REG_ENC_CTRL5 0x054
+#define H1_REG_ENC_CTRL5_MACROBLOCK_PENALTY(x) ((x) << 24)
+#define H1_REG_ENC_CTRL5_COMPLETE_SLICES(x) ((x) << 16)
+#define H1_REG_ENC_CTRL5_INTER_MODE(x) ((x))
+#define H1_REG_STR_HDR_REM_MSB 0x058
+#define H1_REG_STR_HDR_REM_LSB 0x05c
+#define H1_REG_STR_BUF_LIMIT 0x060
+#define H1_REG_MAD_CTRL 0x064
+#define H1_REG_MAD_CTRL_QP_ADJUST(x) ((x) << 28)
+#define H1_REG_MAD_CTRL_MAD_THREDHOLD(x) ((x) << 22)
+#define H1_REG_MAD_CTRL_QP_SUM_DIV2(x) ((x))
+#define H1_REG_ADDR_VP8_PROB_CNT 0x068
+#define H1_REG_QP_VAL 0x06c
+#define H1_REG_QP_VAL_LUM(x) ((x) << 26)
+#define H1_REG_QP_VAL_MAX(x) ((x) << 20)
+#define H1_REG_QP_VAL_MIN(x) ((x) << 14)
+#define H1_REG_QP_VAL_CHECKPOINT_DISTAN(x) ((x))
+#define H1_REG_VP8_QP_VAL(i) (0x06c + ((i) * 0x4))
+#define H1_REG_CHECKPOINT(i) (0x070 + ((i) * 0x4))
+#define H1_REG_CHECKPOINT_CHECK0(x) (((x) & 0xffff))
+#define H1_REG_CHECKPOINT_CHECK1(x) (((x) & 0xffff) << 16)
+#define H1_REG_CHECKPOINT_RESULT(x) ((((x) >> (16 - 16 \
+ * (i & 1))) & 0xffff) \
+ * 32)
+#define H1_REG_CHKPT_WORD_ERR(i) (0x084 + ((i) * 0x4))
+#define H1_REG_CHKPT_WORD_ERR_CHK0(x) (((x) & 0xffff))
+#define H1_REG_CHKPT_WORD_ERR_CHK1(x) (((x) & 0xffff) << 16)
+#define H1_REG_VP8_BOOL_ENC 0x08c
+#define H1_REG_CHKPT_DELTA_QP 0x090
+#define H1_REG_CHKPT_DELTA_QP_CHK0(x) (((x) & 0x0f) << 0)
+#define H1_REG_CHKPT_DELTA_QP_CHK1(x) (((x) & 0x0f) << 4)
+#define H1_REG_CHKPT_DELTA_QP_CHK2(x) (((x) & 0x0f) << 8)
+#define H1_REG_CHKPT_DELTA_QP_CHK3(x) (((x) & 0x0f) << 12)
+#define H1_REG_CHKPT_DELTA_QP_CHK4(x) (((x) & 0x0f) << 16)
+#define H1_REG_CHKPT_DELTA_QP_CHK5(x) (((x) & 0x0f) << 20)
+#define H1_REG_CHKPT_DELTA_QP_CHK6(x) (((x) & 0x0f) << 24)
+#define H1_REG_VP8_CTRL0 0x090
+#define H1_REG_RLC_CTRL 0x094
+#define H1_REG_RLC_CTRL_STR_OFFS_SHIFT 23
+#define H1_REG_RLC_CTRL_STR_OFFS_MASK (0x3f << 23)
+#define H1_REG_RLC_CTRL_RLC_SUM(x) ((x))
+#define H1_REG_MB_CTRL 0x098
+#define H1_REG_MB_CNT_OUT(x) (((x) & 0xffff))
+#define H1_REG_MB_CNT_SET(x) (((x) & 0xffff) << 16)
+#define H1_REG_ADDR_NEXT_PIC 0x09c
+#define H1_REG_JPEG_LUMA_QUAT(i) (0x100 + ((i) * 0x4))
+#define H1_REG_JPEG_CHROMA_QUAT(i) (0x140 + ((i) * 0x4))
+#define H1_REG_STABILIZATION_OUTPUT 0x0A0
+#define H1_REG_ADDR_CABAC_TBL 0x0cc
+#define H1_REG_ADDR_MV_OUT 0x0d0
+#define H1_REG_RGB_YUV_COEFF(i) (0x0d4 + ((i) * 0x4))
+#define H1_REG_RGB_MASK_MSB 0x0dc
+#define H1_REG_INTRA_AREA_CTRL 0x0e0
+#define H1_REG_CIR_INTRA_CTRL 0x0e4
+#define H1_REG_INTRA_SLICE_BITMAP(i) (0x0e8 + ((i) * 0x4))
+#define H1_REG_ADDR_VP8_DCT_PART(i) (0x0e8 + ((i) * 0x4))
+#define H1_REG_FIRST_ROI_AREA 0x0f0
+#define H1_REG_SECOND_ROI_AREA 0x0f4
+#define H1_REG_MVC_CTRL 0x0f8
+#define H1_REG_MVC_CTRL_MV16X16_FAVOR(x) ((x) << 28)
+#define H1_REG_VP8_INTRA_PENALTY(i) (0x100 + ((i) * 0x4))
+#define H1_REG_ADDR_VP8_SEG_MAP 0x11c
+#define H1_REG_VP8_SEG_QP(i) (0x120 + ((i) * 0x4))
+#define H1_REG_DMV_4P_1P_PENALTY(i) (0x180 + ((i) * 0x4))
+#define H1_REG_DMV_4P_1P_PENALTY_BIT(x, i) ((x) << (i) * 8)
+#define H1_REG_DMV_QPEL_PENALTY(i) (0x200 + ((i) * 0x4))
+#define H1_REG_DMV_QPEL_PENALTY_BIT(x, i) ((x) << (i) * 8)
+#define H1_REG_VP8_CTRL1 0x280
+#define H1_REG_VP8_BIT_COST_GOLDEN 0x284
+#define H1_REG_VP8_LOOP_FLT_DELTA(i) (0x288 + ((i) * 0x4))
+
+#endif /* HANTRO_H1_REGS_H_ */
diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h
new file mode 100644
index 000000000000..3c361c2e9b88
--- /dev/null
+++ b/drivers/staging/media/hantro/hantro_hw.h
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Hantro VPU codec driver
+ *
+ * Copyright 2018 Google LLC.
+ * Tomasz Figa <tfiga@chromium.org>
+ */
+
+#ifndef HANTRO_HW_H_
+#define HANTRO_HW_H_
+
+#include <linux/interrupt.h>
+#include <linux/v4l2-controls.h>
+#include <media/mpeg2-ctrls.h>
+#include <media/videobuf2-core.h>
+
+struct hantro_dev;
+struct hantro_ctx;
+struct hantro_buf;
+struct hantro_variant;
+
+/**
+ * struct hantro_aux_buf - auxiliary DMA buffer for hardware data
+ * @cpu: CPU pointer to the buffer.
+ * @dma: DMA address of the buffer.
+ * @size: Size of the buffer.
+ */
+struct hantro_aux_buf {
+ void *cpu;
+ dma_addr_t dma;
+ size_t size;
+};
+
+/**
+ * struct hantro_jpeg_enc_hw_ctx
+ * @bounce_buffer: Bounce buffer
+ */
+struct hantro_jpeg_enc_hw_ctx {
+ struct hantro_aux_buf bounce_buffer;
+};
+
+/**
+ * struct hantro_mpeg2_dec_hw_ctx
+ * @qtable: Quantization table
+ */
+struct hantro_mpeg2_dec_hw_ctx {
+ struct hantro_aux_buf qtable;
+};
+
+/**
+ * struct hantro_codec_ops - codec mode specific operations
+ *
+ * @init: If needed, can be used for initialization.
+ * Optional and called from process context.
+ * @exit: If needed, can be used to undo the .init phase.
+ * Optional and called from process context.
+ * @run: Start single {en,de)coding job. Called from atomic context
+ * to indicate that a pair of buffers is ready and the hardware
+ * should be programmed and started.
+ * @done: Read back processing results and additional data from hardware.
+ * @reset: Reset the hardware in case of a timeout.
+ */
+struct hantro_codec_ops {
+ int (*init)(struct hantro_ctx *ctx);
+ void (*exit)(struct hantro_ctx *ctx);
+ void (*run)(struct hantro_ctx *ctx);
+ void (*done)(struct hantro_ctx *ctx, enum vb2_buffer_state);
+ void (*reset)(struct hantro_ctx *ctx);
+};
+
+/**
+ * enum hantro_enc_fmt - source format ID for hardware registers.
+ */
+enum hantro_enc_fmt {
+ RK3288_VPU_ENC_FMT_YUV420P = 0,
+ RK3288_VPU_ENC_FMT_YUV420SP = 1,
+ RK3288_VPU_ENC_FMT_YUYV422 = 2,
+ RK3288_VPU_ENC_FMT_UYVY422 = 3,
+};
+
+extern const struct hantro_variant rk3399_vpu_variant;
+extern const struct hantro_variant rk3328_vpu_variant;
+extern const struct hantro_variant rk3288_vpu_variant;
+
+void hantro_watchdog(struct work_struct *work);
+void hantro_run(struct hantro_ctx *ctx);
+void hantro_irq_done(struct hantro_dev *vpu, unsigned int bytesused,
+ enum vb2_buffer_state result);
+
+void hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx);
+void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx);
+int hantro_jpeg_enc_init(struct hantro_ctx *ctx);
+void hantro_jpeg_enc_exit(struct hantro_ctx *ctx);
+
+void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx);
+void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx);
+void hantro_mpeg2_dec_copy_qtable(u8 *qtable,
+ const struct v4l2_ctrl_mpeg2_quantization *ctrl);
+int hantro_mpeg2_dec_init(struct hantro_ctx *ctx);
+void hantro_mpeg2_dec_exit(struct hantro_ctx *ctx);
+
+#endif /* HANTRO_HW_H_ */
diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu_jpeg.c b/drivers/staging/media/hantro/hantro_jpeg.c
index 0ff0badc1f7a..125eb41f2ede 100644
--- a/drivers/staging/media/rockchip/vpu/rockchip_vpu_jpeg.c
+++ b/drivers/staging/media/hantro/hantro_jpeg.c
@@ -6,9 +6,11 @@
* Copyright (C) Jean-Francois Moine (http://moinejf.free.fr)
* Copyright (C) 2014 Philipp Zabel, Pengutronix
*/
+#include <linux/dma-mapping.h>
#include <linux/kernel.h>
#include <linux/string.h>
-#include "rockchip_vpu_jpeg.h"
+#include "hantro_jpeg.h"
+#include "hantro.h"
#define LUMA_QUANT_OFF 7
#define CHROMA_QUANT_OFF 72
@@ -116,7 +118,7 @@ static const unsigned char chroma_ac_table[] = {
* and we'll use fixed offsets to change the width, height
* quantization tables, etc.
*/
-static const unsigned char rockchip_vpu_jpeg_header[JPEG_HEADER_SIZE] = {
+static const unsigned char hantro_jpeg_header[JPEG_HEADER_SIZE] = {
/* SOI */
0xff, 0xd8,
@@ -260,19 +262,19 @@ static void jpeg_set_quality(unsigned char *buffer, int quality)
}
unsigned char *
-rockchip_vpu_jpeg_get_qtable(struct rockchip_vpu_jpeg_ctx *ctx, int index)
+hantro_jpeg_get_qtable(struct hantro_jpeg_ctx *ctx, int index)
{
if (index == 0)
return ctx->buffer + LUMA_QUANT_OFF;
return ctx->buffer + CHROMA_QUANT_OFF;
}
-void rockchip_vpu_jpeg_header_assemble(struct rockchip_vpu_jpeg_ctx *ctx)
+void hantro_jpeg_header_assemble(struct hantro_jpeg_ctx *ctx)
{
char *buf = ctx->buffer;
- memcpy(buf, rockchip_vpu_jpeg_header,
- sizeof(rockchip_vpu_jpeg_header));
+ memcpy(buf, hantro_jpeg_header,
+ sizeof(hantro_jpeg_header));
buf[HEIGHT_OFF + 0] = ctx->height >> 8;
buf[HEIGHT_OFF + 1] = ctx->height;
@@ -288,3 +290,30 @@ void rockchip_vpu_jpeg_header_assemble(struct rockchip_vpu_jpeg_ctx *ctx)
jpeg_set_quality(buf, ctx->quality);
}
+
+int hantro_jpeg_enc_init(struct hantro_ctx *ctx)
+{
+ ctx->jpeg_enc.bounce_buffer.size =
+ ctx->dst_fmt.plane_fmt[0].sizeimage -
+ ctx->vpu_dst_fmt->header_size;
+
+ ctx->jpeg_enc.bounce_buffer.cpu =
+ dma_alloc_attrs(ctx->dev->dev,
+ ctx->jpeg_enc.bounce_buffer.size,
+ &ctx->jpeg_enc.bounce_buffer.dma,
+ GFP_KERNEL,
+ DMA_ATTR_ALLOC_SINGLE_PAGES);
+ if (!ctx->jpeg_enc.bounce_buffer.cpu)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void hantro_jpeg_enc_exit(struct hantro_ctx *ctx)
+{
+ dma_free_attrs(ctx->dev->dev,
+ ctx->jpeg_enc.bounce_buffer.size,
+ ctx->jpeg_enc.bounce_buffer.cpu,
+ ctx->jpeg_enc.bounce_buffer.dma,
+ DMA_ATTR_ALLOC_SINGLE_PAGES);
+}
diff --git a/drivers/staging/media/hantro/hantro_jpeg.h b/drivers/staging/media/hantro/hantro_jpeg.h
new file mode 100644
index 000000000000..9e8397c71388
--- /dev/null
+++ b/drivers/staging/media/hantro/hantro_jpeg.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#define JPEG_HEADER_SIZE 601
+
+struct hantro_jpeg_ctx {
+ int width;
+ int height;
+ int quality;
+ unsigned char *buffer;
+};
+
+unsigned char *hantro_jpeg_get_qtable(struct hantro_jpeg_ctx *ctx, int index);
+void hantro_jpeg_header_assemble(struct hantro_jpeg_ctx *ctx);
diff --git a/drivers/staging/media/hantro/hantro_mpeg2.c b/drivers/staging/media/hantro/hantro_mpeg2.c
new file mode 100644
index 000000000000..1d334e6fcd06
--- /dev/null
+++ b/drivers/staging/media/hantro/hantro_mpeg2.c
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Hantro VPU codec driver
+ *
+ * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
+ */
+
+#include "hantro.h"
+
+static const u8 zigzag[64] = {
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 32, 25, 18, 11, 4, 5,
+ 12, 19, 26, 33, 40, 48, 41, 34,
+ 27, 20, 13, 6, 7, 14, 21, 28,
+ 35, 42, 49, 56, 57, 50, 43, 36,
+ 29, 22, 15, 23, 30, 37, 44, 51,
+ 58, 59, 52, 45, 38, 31, 39, 46,
+ 53, 60, 61, 54, 47, 55, 62, 63
+};
+
+void hantro_mpeg2_dec_copy_qtable(u8 *qtable,
+ const struct v4l2_ctrl_mpeg2_quantization *ctrl)
+{
+ int i, n;
+
+ if (!qtable || !ctrl)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(zigzag); i++) {
+ n = zigzag[i];
+ qtable[n + 0] = ctrl->intra_quantiser_matrix[i];
+ qtable[n + 64] = ctrl->non_intra_quantiser_matrix[i];
+ qtable[n + 128] = ctrl->chroma_intra_quantiser_matrix[i];
+ qtable[n + 192] = ctrl->chroma_non_intra_quantiser_matrix[i];
+ }
+}
+
+int hantro_mpeg2_dec_init(struct hantro_ctx *ctx)
+{
+ struct hantro_dev *vpu = ctx->dev;
+
+ ctx->mpeg2_dec.qtable.size = ARRAY_SIZE(zigzag) * 4;
+ ctx->mpeg2_dec.qtable.cpu =
+ dma_alloc_coherent(vpu->dev,
+ ctx->mpeg2_dec.qtable.size,
+ &ctx->mpeg2_dec.qtable.dma,
+ GFP_KERNEL);
+ if (!ctx->mpeg2_dec.qtable.cpu)
+ return -ENOMEM;
+ return 0;
+}
+
+void hantro_mpeg2_dec_exit(struct hantro_ctx *ctx)
+{
+ struct hantro_dev *vpu = ctx->dev;
+
+ dma_free_coherent(vpu->dev,
+ ctx->mpeg2_dec.qtable.size,
+ ctx->mpeg2_dec.qtable.cpu,
+ ctx->mpeg2_dec.qtable.dma);
+}
diff --git a/drivers/staging/media/hantro/hantro_v4l2.c b/drivers/staging/media/hantro/hantro_v4l2.c
new file mode 100644
index 000000000000..68f45ee66821
--- /dev/null
+++ b/drivers/staging/media/hantro/hantro_v4l2.c
@@ -0,0 +1,686 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Hantro VPU codec driver
+ *
+ * Copyright (C) 2018 Collabora, Ltd.
+ * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
+ * Alpha Lin <Alpha.Lin@rock-chips.com>
+ * Jeffy Chen <jeffy.chen@rock-chips.com>
+ *
+ * Copyright 2018 Google LLC.
+ * Tomasz Figa <tfiga@chromium.org>
+ *
+ * Based on s5p-mfc driver by Samsung Electronics Co., Ltd.
+ * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/videodev2.h>
+#include <linux/workqueue.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-sg.h>
+
+#include "hantro.h"
+#include "hantro_hw.h"
+#include "hantro_v4l2.h"
+
+static const struct hantro_fmt *
+hantro_get_formats(const struct hantro_ctx *ctx, unsigned int *num_fmts)
+{
+ const struct hantro_fmt *formats;
+
+ if (hantro_is_encoder_ctx(ctx)) {
+ formats = ctx->dev->variant->enc_fmts;
+ *num_fmts = ctx->dev->variant->num_enc_fmts;
+ } else {
+ formats = ctx->dev->variant->dec_fmts;
+ *num_fmts = ctx->dev->variant->num_dec_fmts;
+ }
+
+ return formats;
+}
+
+static const struct hantro_fmt *
+hantro_find_format(const struct hantro_fmt *formats, unsigned int num_fmts,
+ u32 fourcc)
+{
+ unsigned int i;
+
+ for (i = 0; i < num_fmts; i++)
+ if (formats[i].fourcc == fourcc)
+ return &formats[i];
+ return NULL;
+}
+
+static const struct hantro_fmt *
+hantro_get_default_fmt(const struct hantro_fmt *formats, unsigned int num_fmts,
+ bool bitstream)
+{
+ unsigned int i;
+
+ for (i = 0; i < num_fmts; i++) {
+ if (bitstream == (formats[i].codec_mode !=
+ HANTRO_MODE_NONE))
+ return &formats[i];
+ }
+ return NULL;
+}
+
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct hantro_dev *vpu = video_drvdata(file);
+ struct video_device *vdev = video_devdata(file);
+
+ strscpy(cap->driver, vpu->dev->driver->name, sizeof(cap->driver));
+ strscpy(cap->card, vdev->name, sizeof(cap->card));
+ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform: %s",
+ vpu->dev->driver->name);
+ return 0;
+}
+
+static int vidioc_enum_framesizes(struct file *file, void *priv,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct hantro_ctx *ctx = fh_to_ctx(priv);
+ const struct hantro_fmt *formats, *fmt;
+ unsigned int num_fmts;
+
+ if (fsize->index != 0) {
+ vpu_debug(0, "invalid frame size index (expected 0, got %d)\n",
+ fsize->index);
+ return -EINVAL;
+ }
+
+ formats = hantro_get_formats(ctx, &num_fmts);
+ fmt = hantro_find_format(formats, num_fmts, fsize->pixel_format);
+ if (!fmt) {
+ vpu_debug(0, "unsupported bitstream format (%08x)\n",
+ fsize->pixel_format);
+ return -EINVAL;
+ }
+
+ /* This only makes sense for coded formats */
+ if (fmt->codec_mode == HANTRO_MODE_NONE)
+ return -EINVAL;
+
+ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+ fsize->stepwise = fmt->frmsize;
+
+ return 0;
+}
+
+static int vidioc_enum_fmt(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f, bool capture)
+
+{
+ struct hantro_ctx *ctx = fh_to_ctx(priv);
+ const struct hantro_fmt *fmt, *formats;
+ unsigned int num_fmts, i, j = 0;
+ bool skip_mode_none;
+
+ /*
+ * When dealing with an encoder:
+ * - on the capture side we want to filter out all MODE_NONE formats.
+ * - on the output side we want to filter out all formats that are
+ * not MODE_NONE.
+ * When dealing with a decoder:
+ * - on the capture side we want to filter out all formats that are
+ * not MODE_NONE.
+ * - on the output side we want to filter out all MODE_NONE formats.
+ */
+ skip_mode_none = capture == hantro_is_encoder_ctx(ctx);
+
+ formats = hantro_get_formats(ctx, &num_fmts);
+ for (i = 0; i < num_fmts; i++) {
+ bool mode_none = formats[i].codec_mode == HANTRO_MODE_NONE;
+
+ if (skip_mode_none == mode_none)
+ continue;
+ if (j == f->index) {
+ fmt = &formats[i];
+ f->pixelformat = fmt->fourcc;
+ return 0;
+ }
+ ++j;
+ }
+ return -EINVAL;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ return vidioc_enum_fmt(file, priv, f, true);
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ return vidioc_enum_fmt(file, priv, f, false);
+}
+
+static int vidioc_g_fmt_out_mplane(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ struct hantro_ctx *ctx = fh_to_ctx(priv);
+
+ vpu_debug(4, "f->type = %d\n", f->type);
+
+ *pix_mp = ctx->src_fmt;
+
+ return 0;
+}
+
+static int vidioc_g_fmt_cap_mplane(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ struct hantro_ctx *ctx = fh_to_ctx(priv);
+
+ vpu_debug(4, "f->type = %d\n", f->type);
+
+ *pix_mp = ctx->dst_fmt;
+
+ return 0;
+}
+
+static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f,
+ bool capture)
+{
+ struct hantro_ctx *ctx = fh_to_ctx(priv);
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ const struct hantro_fmt *formats, *fmt, *vpu_fmt;
+ unsigned int num_fmts;
+ bool coded;
+
+ coded = capture == hantro_is_encoder_ctx(ctx);
+
+ vpu_debug(4, "trying format %c%c%c%c\n",
+ (pix_mp->pixelformat & 0x7f),
+ (pix_mp->pixelformat >> 8) & 0x7f,
+ (pix_mp->pixelformat >> 16) & 0x7f,
+ (pix_mp->pixelformat >> 24) & 0x7f);
+
+ formats = hantro_get_formats(ctx, &num_fmts);
+ fmt = hantro_find_format(formats, num_fmts, pix_mp->pixelformat);
+ if (!fmt) {
+ fmt = hantro_get_default_fmt(formats, num_fmts, coded);
+ f->fmt.pix_mp.pixelformat = fmt->fourcc;
+ }
+
+ if (coded) {
+ pix_mp->num_planes = 1;
+ vpu_fmt = fmt;
+ } else if (hantro_is_encoder_ctx(ctx)) {
+ vpu_fmt = ctx->vpu_dst_fmt;
+ } else {
+ vpu_fmt = ctx->vpu_src_fmt;
+ /*
+ * Width/height on the CAPTURE end of a decoder are ignored and
+ * replaced by the OUTPUT ones.
+ */
+ pix_mp->width = ctx->src_fmt.width;
+ pix_mp->height = ctx->src_fmt.height;
+ }
+
+ pix_mp->field = V4L2_FIELD_NONE;
+
+ v4l2_apply_frmsize_constraints(&pix_mp->width, &pix_mp->height,
+ &vpu_fmt->frmsize);
+
+ if (!coded) {
+ /* Fill remaining fields */
+ v4l2_fill_pixfmt_mp(pix_mp, fmt->fourcc, pix_mp->width,
+ pix_mp->height);
+ } else if (!pix_mp->plane_fmt[0].sizeimage) {
+ /*
+ * For coded formats the application can specify
+ * sizeimage. If the application passes a zero sizeimage,
+ * let's default to the maximum frame size.
+ */
+ pix_mp->plane_fmt[0].sizeimage = fmt->header_size +
+ pix_mp->width * pix_mp->height * fmt->max_depth;
+ }
+
+ return 0;
+}
+
+static int vidioc_try_fmt_cap_mplane(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ return vidioc_try_fmt(file, priv, f, true);
+}
+
+static int vidioc_try_fmt_out_mplane(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ return vidioc_try_fmt(file, priv, f, false);
+}
+
+static void
+hantro_reset_fmt(struct v4l2_pix_format_mplane *fmt,
+ const struct hantro_fmt *vpu_fmt)
+{
+ memset(fmt, 0, sizeof(*fmt));
+
+ fmt->pixelformat = vpu_fmt->fourcc;
+ fmt->field = V4L2_FIELD_NONE;
+ fmt->colorspace = V4L2_COLORSPACE_JPEG,
+ fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ fmt->quantization = V4L2_QUANTIZATION_DEFAULT;
+ fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+}
+
+static void
+hantro_reset_encoded_fmt(struct hantro_ctx *ctx)
+{
+ const struct hantro_fmt *vpu_fmt, *formats;
+ struct v4l2_pix_format_mplane *fmt;
+ unsigned int num_fmts;
+
+ formats = hantro_get_formats(ctx, &num_fmts);
+ vpu_fmt = hantro_get_default_fmt(formats, num_fmts, true);
+
+ if (hantro_is_encoder_ctx(ctx)) {
+ ctx->vpu_dst_fmt = vpu_fmt;
+ fmt = &ctx->dst_fmt;
+ } else {
+ ctx->vpu_src_fmt = vpu_fmt;
+ fmt = &ctx->src_fmt;
+ }
+
+ hantro_reset_fmt(fmt, vpu_fmt);
+ fmt->num_planes = 1;
+ fmt->width = vpu_fmt->frmsize.min_width;
+ fmt->height = vpu_fmt->frmsize.min_height;
+ fmt->plane_fmt[0].sizeimage = vpu_fmt->header_size +
+ fmt->width * fmt->height * vpu_fmt->max_depth;
+}
+
+static void
+hantro_reset_raw_fmt(struct hantro_ctx *ctx)
+{
+ const struct hantro_fmt *raw_vpu_fmt, *formats;
+ struct v4l2_pix_format_mplane *raw_fmt, *encoded_fmt;
+ unsigned int num_fmts;
+
+ formats = hantro_get_formats(ctx, &num_fmts);
+ raw_vpu_fmt = hantro_get_default_fmt(formats, num_fmts, false);
+
+ if (hantro_is_encoder_ctx(ctx)) {
+ ctx->vpu_src_fmt = raw_vpu_fmt;
+ raw_fmt = &ctx->src_fmt;
+ encoded_fmt = &ctx->dst_fmt;
+ } else {
+ ctx->vpu_dst_fmt = raw_vpu_fmt;
+ raw_fmt = &ctx->dst_fmt;
+ encoded_fmt = &ctx->src_fmt;
+ }
+
+ hantro_reset_fmt(raw_fmt, raw_vpu_fmt);
+ v4l2_fill_pixfmt_mp(raw_fmt, raw_vpu_fmt->fourcc,
+ encoded_fmt->width,
+ encoded_fmt->height);
+}
+
+void hantro_reset_fmts(struct hantro_ctx *ctx)
+{
+ hantro_reset_encoded_fmt(ctx);
+ hantro_reset_raw_fmt(ctx);
+}
+
+static void
+hantro_update_requires_request(struct hantro_ctx *ctx, u32 fourcc)
+{
+ switch (fourcc) {
+ case V4L2_PIX_FMT_JPEG:
+ ctx->fh.m2m_ctx->out_q_ctx.q.requires_requests = false;
+ break;
+ case V4L2_PIX_FMT_MPEG2_SLICE:
+ ctx->fh.m2m_ctx->out_q_ctx.q.requires_requests = true;
+ break;
+ default:
+ break;
+ }
+}
+
+static int
+vidioc_s_fmt_out_mplane(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ struct hantro_ctx *ctx = fh_to_ctx(priv);
+ const struct hantro_fmt *formats;
+ unsigned int num_fmts;
+ struct vb2_queue *vq;
+ int ret;
+
+ /* Change not allowed if queue is busy. */
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+ if (vb2_is_busy(vq))
+ return -EBUSY;
+
+ if (!hantro_is_encoder_ctx(ctx)) {
+ struct vb2_queue *peer_vq;
+
+ /*
+ * Since format change on the OUTPUT queue will reset
+ * the CAPTURE queue, we can't allow doing so
+ * when the CAPTURE queue has buffers allocated.
+ */
+ peer_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+ if (vb2_is_busy(peer_vq))
+ return -EBUSY;
+ }
+
+ ret = vidioc_try_fmt_out_mplane(file, priv, f);
+ if (ret)
+ return ret;
+
+ formats = hantro_get_formats(ctx, &num_fmts);
+ ctx->vpu_src_fmt = hantro_find_format(formats, num_fmts,
+ pix_mp->pixelformat);
+ ctx->src_fmt = *pix_mp;
+
+ /*
+ * Current raw format might have become invalid with newly
+ * selected codec, so reset it to default just to be safe and
+ * keep internal driver state sane. User is mandated to set
+ * the raw format again after we return, so we don't need
+ * anything smarter.
+ * Note that hantro_reset_raw_fmt() also propagates size
+ * changes to the raw format.
+ */
+ if (!hantro_is_encoder_ctx(ctx))
+ hantro_reset_raw_fmt(ctx);
+
+ /* Colorimetry information are always propagated. */
+ ctx->dst_fmt.colorspace = pix_mp->colorspace;
+ ctx->dst_fmt.ycbcr_enc = pix_mp->ycbcr_enc;
+ ctx->dst_fmt.xfer_func = pix_mp->xfer_func;
+ ctx->dst_fmt.quantization = pix_mp->quantization;
+
+ hantro_update_requires_request(ctx, pix_mp->pixelformat);
+
+ vpu_debug(0, "OUTPUT codec mode: %d\n", ctx->vpu_src_fmt->codec_mode);
+ vpu_debug(0, "fmt - w: %d, h: %d\n",
+ pix_mp->width, pix_mp->height);
+ return 0;
+}
+
+static int vidioc_s_fmt_cap_mplane(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ struct hantro_ctx *ctx = fh_to_ctx(priv);
+ const struct hantro_fmt *formats;
+ struct vb2_queue *vq;
+ unsigned int num_fmts;
+ int ret;
+
+ /* Change not allowed if queue is busy. */
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+ if (vb2_is_busy(vq))
+ return -EBUSY;
+
+ if (hantro_is_encoder_ctx(ctx)) {
+ struct vb2_queue *peer_vq;
+
+ /*
+ * Since format change on the CAPTURE queue will reset
+ * the OUTPUT queue, we can't allow doing so
+ * when the OUTPUT queue has buffers allocated.
+ */
+ peer_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
+ V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+ if (vb2_is_busy(peer_vq) &&
+ (pix_mp->pixelformat != ctx->dst_fmt.pixelformat ||
+ pix_mp->height != ctx->dst_fmt.height ||
+ pix_mp->width != ctx->dst_fmt.width))
+ return -EBUSY;
+ }
+
+ ret = vidioc_try_fmt_cap_mplane(file, priv, f);
+ if (ret)
+ return ret;
+
+ formats = hantro_get_formats(ctx, &num_fmts);
+ ctx->vpu_dst_fmt = hantro_find_format(formats, num_fmts,
+ pix_mp->pixelformat);
+ ctx->dst_fmt = *pix_mp;
+
+ /*
+ * Current raw format might have become invalid with newly
+ * selected codec, so reset it to default just to be safe and
+ * keep internal driver state sane. User is mandated to set
+ * the raw format again after we return, so we don't need
+ * anything smarter.
+ * Note that hantro_reset_raw_fmt() also propagates size
+ * changes to the raw format.
+ */
+ if (hantro_is_encoder_ctx(ctx))
+ hantro_reset_raw_fmt(ctx);
+
+ /* Colorimetry information are always propagated. */
+ ctx->src_fmt.colorspace = pix_mp->colorspace;
+ ctx->src_fmt.ycbcr_enc = pix_mp->ycbcr_enc;
+ ctx->src_fmt.xfer_func = pix_mp->xfer_func;
+ ctx->src_fmt.quantization = pix_mp->quantization;
+
+ vpu_debug(0, "CAPTURE codec mode: %d\n", ctx->vpu_dst_fmt->codec_mode);
+ vpu_debug(0, "fmt - w: %d, h: %d\n",
+ pix_mp->width, pix_mp->height);
+
+ hantro_update_requires_request(ctx, pix_mp->pixelformat);
+
+ return 0;
+}
+
+const struct v4l2_ioctl_ops hantro_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_framesizes = vidioc_enum_framesizes,
+
+ .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_cap_mplane,
+ .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_out_mplane,
+ .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_out_mplane,
+ .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_cap_mplane,
+ .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_out_mplane,
+ .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_cap_mplane,
+ .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+
+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
+ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
+ .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
+ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
+
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+
+ .vidioc_streamon = v4l2_m2m_ioctl_streamon,
+ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
+};
+
+static int
+hantro_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct hantro_ctx *ctx = vb2_get_drv_priv(vq);
+ struct v4l2_pix_format_mplane *pixfmt;
+ int i;
+
+ switch (vq->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ pixfmt = &ctx->dst_fmt;
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ pixfmt = &ctx->src_fmt;
+ break;
+ default:
+ vpu_err("invalid queue type: %d\n", vq->type);
+ return -EINVAL;
+ }
+
+ if (*num_planes) {
+ if (*num_planes != pixfmt->num_planes)
+ return -EINVAL;
+ for (i = 0; i < pixfmt->num_planes; ++i)
+ if (sizes[i] < pixfmt->plane_fmt[i].sizeimage)
+ return -EINVAL;
+ return 0;
+ }
+
+ *num_planes = pixfmt->num_planes;
+ for (i = 0; i < pixfmt->num_planes; ++i)
+ sizes[i] = pixfmt->plane_fmt[i].sizeimage;
+ return 0;
+}
+
+static int
+hantro_buf_plane_check(struct vb2_buffer *vb, const struct hantro_fmt *vpu_fmt,
+ struct v4l2_pix_format_mplane *pixfmt)
+{
+ unsigned int sz;
+ int i;
+
+ for (i = 0; i < pixfmt->num_planes; ++i) {
+ sz = pixfmt->plane_fmt[i].sizeimage;
+ vpu_debug(4, "plane %d size: %ld, sizeimage: %u\n",
+ i, vb2_plane_size(vb, i), sz);
+ if (vb2_plane_size(vb, i) < sz) {
+ vpu_err("plane %d is too small for output\n", i);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static int hantro_buf_prepare(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct hantro_ctx *ctx = vb2_get_drv_priv(vq);
+
+ if (V4L2_TYPE_IS_OUTPUT(vq->type))
+ return hantro_buf_plane_check(vb, ctx->vpu_src_fmt,
+ &ctx->src_fmt);
+
+ return hantro_buf_plane_check(vb, ctx->vpu_dst_fmt, &ctx->dst_fmt);
+}
+
+static void hantro_buf_queue(struct vb2_buffer *vb)
+{
+ struct hantro_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+ v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
+}
+
+static bool hantro_vq_is_coded(struct vb2_queue *q)
+{
+ struct hantro_ctx *ctx = vb2_get_drv_priv(q);
+
+ return hantro_is_encoder_ctx(ctx) != V4L2_TYPE_IS_OUTPUT(q->type);
+}
+
+static int hantro_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct hantro_ctx *ctx = vb2_get_drv_priv(q);
+ int ret = 0;
+
+ if (V4L2_TYPE_IS_OUTPUT(q->type))
+ ctx->sequence_out = 0;
+ else
+ ctx->sequence_cap = 0;
+
+ if (hantro_vq_is_coded(q)) {
+ enum hantro_codec_mode codec_mode;
+
+ if (V4L2_TYPE_IS_OUTPUT(q->type))
+ codec_mode = ctx->vpu_src_fmt->codec_mode;
+ else
+ codec_mode = ctx->vpu_dst_fmt->codec_mode;
+
+ vpu_debug(4, "Codec mode = %d\n", codec_mode);
+ ctx->codec_ops = &ctx->dev->variant->codec_ops[codec_mode];
+ if (ctx->codec_ops->init)
+ ret = ctx->codec_ops->init(ctx);
+ }
+
+ return ret;
+}
+
+static void
+hantro_return_bufs(struct vb2_queue *q,
+ struct vb2_v4l2_buffer *(*buf_remove)(struct v4l2_m2m_ctx *))
+{
+ struct hantro_ctx *ctx = vb2_get_drv_priv(q);
+
+ for (;;) {
+ struct vb2_v4l2_buffer *vbuf;
+
+ vbuf = buf_remove(ctx->fh.m2m_ctx);
+ if (!vbuf)
+ break;
+ v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req,
+ &ctx->ctrl_handler);
+ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
+ }
+}
+
+static void hantro_stop_streaming(struct vb2_queue *q)
+{
+ struct hantro_ctx *ctx = vb2_get_drv_priv(q);
+
+ if (hantro_vq_is_coded(q)) {
+ if (ctx->codec_ops && ctx->codec_ops->exit)
+ ctx->codec_ops->exit(ctx);
+ }
+
+ /*
+ * The mem2mem framework calls v4l2_m2m_cancel_job before
+ * .stop_streaming, so there isn't any job running and
+ * it is safe to return all the buffers.
+ */
+ if (V4L2_TYPE_IS_OUTPUT(q->type))
+ hantro_return_bufs(q, v4l2_m2m_src_buf_remove);
+ else
+ hantro_return_bufs(q, v4l2_m2m_dst_buf_remove);
+}
+
+static void hantro_buf_request_complete(struct vb2_buffer *vb)
+{
+ struct hantro_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+ v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->ctrl_handler);
+}
+
+static int hantro_buf_out_validate(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+ vbuf->field = V4L2_FIELD_NONE;
+ return 0;
+}
+
+const struct vb2_ops hantro_queue_ops = {
+ .queue_setup = hantro_queue_setup,
+ .buf_prepare = hantro_buf_prepare,
+ .buf_queue = hantro_buf_queue,
+ .buf_out_validate = hantro_buf_out_validate,
+ .buf_request_complete = hantro_buf_request_complete,
+ .start_streaming = hantro_start_streaming,
+ .stop_streaming = hantro_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
diff --git a/drivers/staging/media/hantro/hantro_v4l2.h b/drivers/staging/media/hantro/hantro_v4l2.h
new file mode 100644
index 000000000000..18bc682c8556
--- /dev/null
+++ b/drivers/staging/media/hantro/hantro_v4l2.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Hantro VPU codec driver
+ *
+ * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
+ * Alpha Lin <Alpha.Lin@rock-chips.com>
+ * Jeffy Chen <jeffy.chen@rock-chips.com>
+ *
+ * Copyright 2018 Google LLC.
+ * Tomasz Figa <tfiga@chromium.org>
+ *
+ * Based on s5p-mfc driver by Samsung Electronics Co., Ltd.
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ */
+
+#ifndef HANTRO_V4L2_H_
+#define HANTRO_V4L2_H_
+
+#include "hantro.h"
+
+extern const struct v4l2_ioctl_ops hantro_ioctl_ops;
+extern const struct vb2_ops hantro_queue_ops;
+
+void hantro_reset_fmts(struct hantro_ctx *ctx);
+
+#endif /* HANTRO_V4L2_H_ */
diff --git a/drivers/staging/media/hantro/rk3288_vpu_hw.c b/drivers/staging/media/hantro/rk3288_vpu_hw.c
new file mode 100644
index 000000000000..bcacc4f51093
--- /dev/null
+++ b/drivers/staging/media/hantro/rk3288_vpu_hw.c
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Hantro VPU codec driver
+ *
+ * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
+ * Jeffy Chen <jeffy.chen@rock-chips.com>
+ */
+
+#include <linux/clk.h>
+
+#include "hantro.h"
+#include "hantro_jpeg.h"
+#include "hantro_g1_regs.h"
+#include "hantro_h1_regs.h"
+
+#define RK3288_ACLK_MAX_FREQ (400 * 1000 * 1000)
+
+/*
+ * Supported formats.
+ */
+
+static const struct hantro_fmt rk3288_vpu_enc_fmts[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_YUV420M,
+ .codec_mode = HANTRO_MODE_NONE,
+ .enc_fmt = RK3288_VPU_ENC_FMT_YUV420P,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV12M,
+ .codec_mode = HANTRO_MODE_NONE,
+ .enc_fmt = RK3288_VPU_ENC_FMT_YUV420SP,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .codec_mode = HANTRO_MODE_NONE,
+ .enc_fmt = RK3288_VPU_ENC_FMT_YUYV422,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .codec_mode = HANTRO_MODE_NONE,
+ .enc_fmt = RK3288_VPU_ENC_FMT_UYVY422,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_JPEG,
+ .codec_mode = HANTRO_MODE_JPEG_ENC,
+ .max_depth = 2,
+ .header_size = JPEG_HEADER_SIZE,
+ .frmsize = {
+ .min_width = 96,
+ .max_width = 8192,
+ .step_width = JPEG_MB_DIM,
+ .min_height = 32,
+ .max_height = 8192,
+ .step_height = JPEG_MB_DIM,
+ },
+ },
+};
+
+static const struct hantro_fmt rk3288_vpu_dec_fmts[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .codec_mode = HANTRO_MODE_NONE,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_MPEG2_SLICE,
+ .codec_mode = HANTRO_MODE_MPEG2_DEC,
+ .max_depth = 2,
+ .frmsize = {
+ .min_width = 48,
+ .max_width = 1920,
+ .step_width = MPEG2_MB_DIM,
+ .min_height = 48,
+ .max_height = 1088,
+ .step_height = MPEG2_MB_DIM,
+ },
+ },
+};
+
+static irqreturn_t rk3288_vepu_irq(int irq, void *dev_id)
+{
+ struct hantro_dev *vpu = dev_id;
+ enum vb2_buffer_state state;
+ u32 status, bytesused;
+
+ status = vepu_read(vpu, H1_REG_INTERRUPT);
+ bytesused = vepu_read(vpu, H1_REG_STR_BUF_LIMIT) / 8;
+ state = (status & H1_REG_INTERRUPT_FRAME_RDY) ?
+ VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR;
+
+ vepu_write(vpu, 0, H1_REG_INTERRUPT);
+ vepu_write(vpu, 0, H1_REG_AXI_CTRL);
+
+ hantro_irq_done(vpu, bytesused, state);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t rk3288_vdpu_irq(int irq, void *dev_id)
+{
+ struct hantro_dev *vpu = dev_id;
+ enum vb2_buffer_state state;
+ u32 status;
+
+ status = vdpu_read(vpu, G1_REG_INTERRUPT);
+ state = (status & G1_REG_INTERRUPT_DEC_RDY_INT) ?
+ VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR;
+
+ vdpu_write(vpu, 0, G1_REG_INTERRUPT);
+ vdpu_write(vpu, G1_REG_CONFIG_DEC_CLK_GATE_E, G1_REG_CONFIG);
+
+ hantro_irq_done(vpu, 0, state);
+
+ return IRQ_HANDLED;
+}
+
+static int rk3288_vpu_hw_init(struct hantro_dev *vpu)
+{
+ /* Bump ACLK to max. possible freq. to improve performance. */
+ clk_set_rate(vpu->clocks[0].clk, RK3288_ACLK_MAX_FREQ);
+ return 0;
+}
+
+static void rk3288_vpu_enc_reset(struct hantro_ctx *ctx)
+{
+ struct hantro_dev *vpu = ctx->dev;
+
+ vepu_write(vpu, H1_REG_INTERRUPT_DIS_BIT, H1_REG_INTERRUPT);
+ vepu_write(vpu, 0, H1_REG_ENC_CTRL);
+ vepu_write(vpu, 0, H1_REG_AXI_CTRL);
+}
+
+static void rk3288_vpu_dec_reset(struct hantro_ctx *ctx)
+{
+ struct hantro_dev *vpu = ctx->dev;
+
+ vdpu_write(vpu, G1_REG_INTERRUPT_DEC_IRQ_DIS, G1_REG_INTERRUPT);
+ vdpu_write(vpu, G1_REG_CONFIG_DEC_CLK_GATE_E, G1_REG_CONFIG);
+ vdpu_write(vpu, 1, G1_REG_SOFT_RESET);
+}
+
+/*
+ * Supported codec ops.
+ */
+
+static const struct hantro_codec_ops rk3288_vpu_codec_ops[] = {
+ [HANTRO_MODE_JPEG_ENC] = {
+ .run = hantro_h1_jpeg_enc_run,
+ .reset = rk3288_vpu_enc_reset,
+ .init = hantro_jpeg_enc_init,
+ .exit = hantro_jpeg_enc_exit,
+ },
+ [HANTRO_MODE_MPEG2_DEC] = {
+ .run = hantro_g1_mpeg2_dec_run,
+ .reset = rk3288_vpu_dec_reset,
+ .init = hantro_mpeg2_dec_init,
+ .exit = hantro_mpeg2_dec_exit,
+ },
+};
+
+/*
+ * VPU variant.
+ */
+
+static const struct hantro_irq rk3288_irqs[] = {
+ { "vepu", rk3288_vepu_irq },
+ { "vdpu", rk3288_vdpu_irq },
+};
+
+static const char * const rk3288_clk_names[] = {
+ "aclk", "hclk"
+};
+
+const struct hantro_variant rk3288_vpu_variant = {
+ .enc_offset = 0x0,
+ .enc_fmts = rk3288_vpu_enc_fmts,
+ .num_enc_fmts = ARRAY_SIZE(rk3288_vpu_enc_fmts),
+ .dec_offset = 0x400,
+ .dec_fmts = rk3288_vpu_dec_fmts,
+ .num_dec_fmts = ARRAY_SIZE(rk3288_vpu_dec_fmts),
+ .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER,
+ .codec_ops = rk3288_vpu_codec_ops,
+ .irqs = rk3288_irqs,
+ .num_irqs = ARRAY_SIZE(rk3288_irqs),
+ .init = rk3288_vpu_hw_init,
+ .clk_names = rk3288_clk_names,
+ .num_clocks = ARRAY_SIZE(rk3288_clk_names)
+};
diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw.c b/drivers/staging/media/hantro/rk3399_vpu_hw.c
new file mode 100644
index 000000000000..5718f8063542
--- /dev/null
+++ b/drivers/staging/media/hantro/rk3399_vpu_hw.c
@@ -0,0 +1,186 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Hantro VPU codec driver
+ *
+ * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
+ * Jeffy Chen <jeffy.chen@rock-chips.com>
+ */
+
+#include <linux/clk.h>
+
+#include "hantro.h"
+#include "hantro_jpeg.h"
+#include "rk3399_vpu_regs.h"
+
+#define RK3399_ACLK_MAX_FREQ (400 * 1000 * 1000)
+
+/*
+ * Supported formats.
+ */
+
+static const struct hantro_fmt rk3399_vpu_enc_fmts[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_YUV420M,
+ .codec_mode = HANTRO_MODE_NONE,
+ .enc_fmt = RK3288_VPU_ENC_FMT_YUV420P,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV12M,
+ .codec_mode = HANTRO_MODE_NONE,
+ .enc_fmt = RK3288_VPU_ENC_FMT_YUV420SP,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .codec_mode = HANTRO_MODE_NONE,
+ .enc_fmt = RK3288_VPU_ENC_FMT_YUYV422,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .codec_mode = HANTRO_MODE_NONE,
+ .enc_fmt = RK3288_VPU_ENC_FMT_UYVY422,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_JPEG,
+ .codec_mode = HANTRO_MODE_JPEG_ENC,
+ .max_depth = 2,
+ .header_size = JPEG_HEADER_SIZE,
+ .frmsize = {
+ .min_width = 96,
+ .max_width = 8192,
+ .step_width = JPEG_MB_DIM,
+ .min_height = 32,
+ .max_height = 8192,
+ .step_height = JPEG_MB_DIM,
+ },
+ },
+};
+
+static const struct hantro_fmt rk3399_vpu_dec_fmts[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .codec_mode = HANTRO_MODE_NONE,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_MPEG2_SLICE,
+ .codec_mode = HANTRO_MODE_MPEG2_DEC,
+ .max_depth = 2,
+ .frmsize = {
+ .min_width = 48,
+ .max_width = 1920,
+ .step_width = MPEG2_MB_DIM,
+ .min_height = 48,
+ .max_height = 1088,
+ .step_height = MPEG2_MB_DIM,
+ },
+ },
+};
+
+static irqreturn_t rk3399_vepu_irq(int irq, void *dev_id)
+{
+ struct hantro_dev *vpu = dev_id;
+ enum vb2_buffer_state state;
+ u32 status, bytesused;
+
+ status = vepu_read(vpu, VEPU_REG_INTERRUPT);
+ bytesused = vepu_read(vpu, VEPU_REG_STR_BUF_LIMIT) / 8;
+ state = (status & VEPU_REG_INTERRUPT_FRAME_READY) ?
+ VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR;
+
+ vepu_write(vpu, 0, VEPU_REG_INTERRUPT);
+ vepu_write(vpu, 0, VEPU_REG_AXI_CTRL);
+
+ hantro_irq_done(vpu, bytesused, state);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t rk3399_vdpu_irq(int irq, void *dev_id)
+{
+ struct hantro_dev *vpu = dev_id;
+ enum vb2_buffer_state state;
+ u32 status;
+
+ status = vdpu_read(vpu, VDPU_REG_INTERRUPT);
+ state = (status & VDPU_REG_INTERRUPT_DEC_IRQ) ?
+ VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR;
+
+ vdpu_write(vpu, 0, VDPU_REG_INTERRUPT);
+ vdpu_write(vpu, 0, VDPU_REG_AXI_CTRL);
+
+ hantro_irq_done(vpu, 0, state);
+
+ return IRQ_HANDLED;
+}
+
+static int rk3399_vpu_hw_init(struct hantro_dev *vpu)
+{
+ /* Bump ACLK to max. possible freq. to improve performance. */
+ clk_set_rate(vpu->clocks[0].clk, RK3399_ACLK_MAX_FREQ);
+ return 0;
+}
+
+static void rk3399_vpu_enc_reset(struct hantro_ctx *ctx)
+{
+ struct hantro_dev *vpu = ctx->dev;
+
+ vepu_write(vpu, VEPU_REG_INTERRUPT_DIS_BIT, VEPU_REG_INTERRUPT);
+ vepu_write(vpu, 0, VEPU_REG_ENCODE_START);
+ vepu_write(vpu, 0, VEPU_REG_AXI_CTRL);
+}
+
+static void rk3399_vpu_dec_reset(struct hantro_ctx *ctx)
+{
+ struct hantro_dev *vpu = ctx->dev;
+
+ vdpu_write(vpu, VDPU_REG_INTERRUPT_DEC_IRQ_DIS, VDPU_REG_INTERRUPT);
+ vdpu_write(vpu, 0, VDPU_REG_EN_FLAGS);
+ vdpu_write(vpu, 1, VDPU_REG_SOFT_RESET);
+}
+
+/*
+ * Supported codec ops.
+ */
+
+static const struct hantro_codec_ops rk3399_vpu_codec_ops[] = {
+ [HANTRO_MODE_JPEG_ENC] = {
+ .run = rk3399_vpu_jpeg_enc_run,
+ .reset = rk3399_vpu_enc_reset,
+ .init = hantro_jpeg_enc_init,
+ .exit = hantro_jpeg_enc_exit,
+ },
+ [HANTRO_MODE_MPEG2_DEC] = {
+ .run = rk3399_vpu_mpeg2_dec_run,
+ .reset = rk3399_vpu_dec_reset,
+ .init = hantro_mpeg2_dec_init,
+ .exit = hantro_mpeg2_dec_exit,
+ },
+};
+
+/*
+ * VPU variant.
+ */
+
+static const struct hantro_irq rk3399_irqs[] = {
+ { "vepu", rk3399_vepu_irq },
+ { "vdpu", rk3399_vdpu_irq },
+};
+
+static const char * const rk3399_clk_names[] = {
+ "aclk", "hclk"
+};
+
+const struct hantro_variant rk3399_vpu_variant = {
+ .enc_offset = 0x0,
+ .enc_fmts = rk3399_vpu_enc_fmts,
+ .num_enc_fmts = ARRAY_SIZE(rk3399_vpu_enc_fmts),
+ .dec_offset = 0x400,
+ .dec_fmts = rk3399_vpu_dec_fmts,
+ .num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts),
+ .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER,
+ .codec_ops = rk3399_vpu_codec_ops,
+ .irqs = rk3399_irqs,
+ .num_irqs = ARRAY_SIZE(rk3399_irqs),
+ .init = rk3399_vpu_hw_init,
+ .clk_names = rk3399_clk_names,
+ .num_clocks = ARRAY_SIZE(rk3399_clk_names)
+};
diff --git a/drivers/staging/media/rockchip/vpu/rk3399_vpu_hw_jpeg_enc.c b/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c
index 3d438797692e..ae66354d2d93 100644
--- a/drivers/staging/media/rockchip/vpu/rk3399_vpu_hw_jpeg_enc.c
+++ b/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Rockchip VPU codec driver
+ * Hantro VPU codec driver
*
* Copyright (C) 2018 Rockchip Electronics Co., Ltd.
*
@@ -25,16 +25,16 @@
#include <asm/unaligned.h>
#include <media/v4l2-mem2mem.h>
-#include "rockchip_vpu_jpeg.h"
-#include "rockchip_vpu.h"
-#include "rockchip_vpu_common.h"
-#include "rockchip_vpu_hw.h"
+#include "hantro_jpeg.h"
+#include "hantro.h"
+#include "hantro_v4l2.h"
+#include "hantro_hw.h"
#include "rk3399_vpu_regs.h"
#define VEPU_JPEG_QUANT_TABLE_COUNT 16
-static void rk3399_vpu_set_src_img_ctrl(struct rockchip_vpu_dev *vpu,
- struct rockchip_vpu_ctx *ctx)
+static void rk3399_vpu_set_src_img_ctrl(struct hantro_dev *vpu,
+ struct hantro_ctx *ctx)
{
struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt;
u32 reg;
@@ -60,8 +60,8 @@ static void rk3399_vpu_set_src_img_ctrl(struct rockchip_vpu_dev *vpu,
vepu_write_relaxed(vpu, reg, VEPU_REG_ENC_CTRL1);
}
-static void rk3399_vpu_jpeg_enc_set_buffers(struct rockchip_vpu_dev *vpu,
- struct rockchip_vpu_ctx *ctx,
+static void rk3399_vpu_jpeg_enc_set_buffers(struct hantro_dev *vpu,
+ struct hantro_ctx *ctx,
struct vb2_buffer *src_buf)
{
struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt;
@@ -69,9 +69,9 @@ static void rk3399_vpu_jpeg_enc_set_buffers(struct rockchip_vpu_dev *vpu,
WARN_ON(pix_fmt->num_planes > 3);
- vepu_write_relaxed(vpu, ctx->bounce_dma_addr,
+ vepu_write_relaxed(vpu, ctx->jpeg_enc.bounce_buffer.dma,
VEPU_REG_ADDR_OUTPUT_STREAM);
- vepu_write_relaxed(vpu, ctx->bounce_size,
+ vepu_write_relaxed(vpu, ctx->jpeg_enc.bounce_buffer.size,
VEPU_REG_STR_BUF_LIMIT);
if (pix_fmt->num_planes == 1) {
@@ -93,7 +93,7 @@ static void rk3399_vpu_jpeg_enc_set_buffers(struct rockchip_vpu_dev *vpu,
}
static void
-rk3399_vpu_jpeg_enc_set_qtable(struct rockchip_vpu_dev *vpu,
+rk3399_vpu_jpeg_enc_set_qtable(struct hantro_dev *vpu,
unsigned char *luma_qtable,
unsigned char *chroma_qtable)
{
@@ -108,22 +108,26 @@ rk3399_vpu_jpeg_enc_set_qtable(struct rockchip_vpu_dev *vpu,
}
}
-void rk3399_vpu_jpeg_enc_run(struct rockchip_vpu_ctx *ctx)
+void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx)
{
- struct rockchip_vpu_dev *vpu = ctx->dev;
+ struct hantro_dev *vpu = ctx->dev;
struct vb2_v4l2_buffer *src_buf, *dst_buf;
- struct rockchip_vpu_jpeg_ctx jpeg_ctx;
+ struct hantro_jpeg_ctx jpeg_ctx;
+ struct media_request *src_req;
u32 reg;
src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+ src_req = src_buf->vb2_buf.req_obj.req;
+ v4l2_ctrl_request_setup(src_req, &ctx->ctrl_handler);
+
memset(&jpeg_ctx, 0, sizeof(jpeg_ctx));
jpeg_ctx.buffer = vb2_plane_vaddr(&dst_buf->vb2_buf, 0);
jpeg_ctx.width = ctx->dst_fmt.width;
jpeg_ctx.height = ctx->dst_fmt.height;
jpeg_ctx.quality = ctx->jpeg_quality;
- rockchip_vpu_jpeg_header_assemble(&jpeg_ctx);
+ hantro_jpeg_header_assemble(&jpeg_ctx);
/* Switch to JPEG encoder mode before writing registers */
vepu_write_relaxed(vpu, VEPU_REG_ENCODE_FORMAT_JPEG,
@@ -132,8 +136,8 @@ void rk3399_vpu_jpeg_enc_run(struct rockchip_vpu_ctx *ctx)
rk3399_vpu_set_src_img_ctrl(vpu, ctx);
rk3399_vpu_jpeg_enc_set_buffers(vpu, ctx, &src_buf->vb2_buf);
rk3399_vpu_jpeg_enc_set_qtable(vpu,
- rockchip_vpu_jpeg_get_qtable(&jpeg_ctx, 0),
- rockchip_vpu_jpeg_get_qtable(&jpeg_ctx, 1));
+ hantro_jpeg_get_qtable(&jpeg_ctx, 0),
+ hantro_jpeg_get_qtable(&jpeg_ctx, 1));
reg = VEPU_REG_OUTPUT_SWAP32
| VEPU_REG_OUTPUT_SWAP16
@@ -153,6 +157,8 @@ void rk3399_vpu_jpeg_enc_run(struct rockchip_vpu_ctx *ctx)
| VEPU_REG_ENCODE_FORMAT_JPEG
| VEPU_REG_ENCODE_ENABLE;
+ v4l2_ctrl_request_complete(src_req, &ctx->ctrl_handler);
+
/* Kick the watchdog and start encoding */
schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000));
vepu_write(vpu, reg, VEPU_REG_ENCODE_START);
diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c b/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c
new file mode 100644
index 000000000000..8685bddfbcab
--- /dev/null
+++ b/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c
@@ -0,0 +1,266 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Hantro VPU codec driver
+ *
+ * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
+ */
+
+#include <asm/unaligned.h>
+#include <linux/bitfield.h>
+#include <media/v4l2-mem2mem.h>
+#include "hantro.h"
+#include "hantro_hw.h"
+
+#define VDPU_SWREG(nr) ((nr) * 4)
+
+#define VDPU_REG_DEC_OUT_BASE VDPU_SWREG(63)
+#define VDPU_REG_RLC_VLC_BASE VDPU_SWREG(64)
+#define VDPU_REG_QTABLE_BASE VDPU_SWREG(61)
+#define VDPU_REG_REFER0_BASE VDPU_SWREG(131)
+#define VDPU_REG_REFER2_BASE VDPU_SWREG(134)
+#define VDPU_REG_REFER3_BASE VDPU_SWREG(135)
+#define VDPU_REG_REFER1_BASE VDPU_SWREG(148)
+#define VDPU_REG_DEC_E(v) ((v) ? BIT(0) : 0)
+
+#define VDPU_REG_DEC_ADV_PRE_DIS(v) ((v) ? BIT(11) : 0)
+#define VDPU_REG_DEC_SCMD_DIS(v) ((v) ? BIT(10) : 0)
+#define VDPU_REG_FILTERING_DIS(v) ((v) ? BIT(8) : 0)
+#define VDPU_REG_DEC_LATENCY(v) (((v) << 1) & GENMASK(6, 1))
+
+#define VDPU_REG_INIT_QP(v) (((v) << 25) & GENMASK(30, 25))
+#define VDPU_REG_STREAM_LEN(v) (((v) << 0) & GENMASK(23, 0))
+
+#define VDPU_REG_APF_THRESHOLD(v) (((v) << 17) & GENMASK(30, 17))
+#define VDPU_REG_STARTMB_X(v) (((v) << 8) & GENMASK(16, 8))
+#define VDPU_REG_STARTMB_Y(v) (((v) << 0) & GENMASK(7, 0))
+
+#define VDPU_REG_DEC_MODE(v) (((v) << 0) & GENMASK(3, 0))
+
+#define VDPU_REG_DEC_STRENDIAN_E(v) ((v) ? BIT(5) : 0)
+#define VDPU_REG_DEC_STRSWAP32_E(v) ((v) ? BIT(4) : 0)
+#define VDPU_REG_DEC_OUTSWAP32_E(v) ((v) ? BIT(3) : 0)
+#define VDPU_REG_DEC_INSWAP32_E(v) ((v) ? BIT(2) : 0)
+#define VDPU_REG_DEC_OUT_ENDIAN(v) ((v) ? BIT(1) : 0)
+#define VDPU_REG_DEC_IN_ENDIAN(v) ((v) ? BIT(0) : 0)
+
+#define VDPU_REG_DEC_DATA_DISC_E(v) ((v) ? BIT(22) : 0)
+#define VDPU_REG_DEC_MAX_BURST(v) (((v) << 16) & GENMASK(20, 16))
+#define VDPU_REG_DEC_AXI_WR_ID(v) (((v) << 8) & GENMASK(15, 8))
+#define VDPU_REG_DEC_AXI_RD_ID(v) (((v) << 0) & GENMASK(7, 0))
+
+#define VDPU_REG_RLC_MODE_E(v) ((v) ? BIT(20) : 0)
+#define VDPU_REG_PIC_INTERLACE_E(v) ((v) ? BIT(17) : 0)
+#define VDPU_REG_PIC_FIELDMODE_E(v) ((v) ? BIT(16) : 0)
+#define VDPU_REG_PIC_B_E(v) ((v) ? BIT(15) : 0)
+#define VDPU_REG_PIC_INTER_E(v) ((v) ? BIT(14) : 0)
+#define VDPU_REG_PIC_TOPFIELD_E(v) ((v) ? BIT(13) : 0)
+#define VDPU_REG_FWD_INTERLACE_E(v) ((v) ? BIT(12) : 0)
+#define VDPU_REG_WRITE_MVS_E(v) ((v) ? BIT(10) : 0)
+#define VDPU_REG_DEC_TIMEOUT_E(v) ((v) ? BIT(5) : 0)
+#define VDPU_REG_DEC_CLK_GATE_E(v) ((v) ? BIT(4) : 0)
+
+#define VDPU_REG_PIC_MB_WIDTH(v) (((v) << 23) & GENMASK(31, 23))
+#define VDPU_REG_PIC_MB_HEIGHT_P(v) (((v) << 11) & GENMASK(18, 11))
+#define VDPU_REG_ALT_SCAN_E(v) ((v) ? BIT(6) : 0)
+#define VDPU_REG_TOPFIELDFIRST_E(v) ((v) ? BIT(5) : 0)
+
+#define VDPU_REG_STRM_START_BIT(v) (((v) << 26) & GENMASK(31, 26))
+#define VDPU_REG_QSCALE_TYPE(v) ((v) ? BIT(24) : 0)
+#define VDPU_REG_CON_MV_E(v) ((v) ? BIT(4) : 0)
+#define VDPU_REG_INTRA_DC_PREC(v) (((v) << 2) & GENMASK(3, 2))
+#define VDPU_REG_INTRA_VLC_TAB(v) ((v) ? BIT(1) : 0)
+#define VDPU_REG_FRAME_PRED_DCT(v) ((v) ? BIT(0) : 0)
+
+#define VDPU_REG_ALT_SCAN_FLAG_E(v) ((v) ? BIT(19) : 0)
+#define VDPU_REG_FCODE_FWD_HOR(v) (((v) << 15) & GENMASK(18, 15))
+#define VDPU_REG_FCODE_FWD_VER(v) (((v) << 11) & GENMASK(14, 11))
+#define VDPU_REG_FCODE_BWD_HOR(v) (((v) << 7) & GENMASK(10, 7))
+#define VDPU_REG_FCODE_BWD_VER(v) (((v) << 3) & GENMASK(6, 3))
+#define VDPU_REG_MV_ACCURACY_FWD(v) ((v) ? BIT(2) : 0)
+#define VDPU_REG_MV_ACCURACY_BWD(v) ((v) ? BIT(1) : 0)
+
+#define PICT_TOP_FIELD 1
+#define PICT_BOTTOM_FIELD 2
+#define PICT_FRAME 3
+
+static void
+rk3399_vpu_mpeg2_dec_set_quantization(struct hantro_dev *vpu,
+ struct hantro_ctx *ctx)
+{
+ struct v4l2_ctrl_mpeg2_quantization *quantization;
+
+ quantization = hantro_get_ctrl(ctx,
+ V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION);
+ hantro_mpeg2_dec_copy_qtable(ctx->mpeg2_dec.qtable.cpu, quantization);
+ vdpu_write_relaxed(vpu, ctx->mpeg2_dec.qtable.dma,
+ VDPU_REG_QTABLE_BASE);
+}
+
+static void
+rk3399_vpu_mpeg2_dec_set_buffers(struct hantro_dev *vpu,
+ struct hantro_ctx *ctx,
+ struct vb2_buffer *src_buf,
+ struct vb2_buffer *dst_buf,
+ const struct v4l2_mpeg2_sequence *sequence,
+ const struct v4l2_mpeg2_picture *picture,
+ const struct v4l2_ctrl_mpeg2_slice_params *slice_params)
+{
+ dma_addr_t forward_addr = 0, backward_addr = 0;
+ dma_addr_t current_addr, addr;
+ struct vb2_queue *vq;
+
+ vq = v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx);
+
+ switch (picture->picture_coding_type) {
+ case V4L2_MPEG2_PICTURE_CODING_TYPE_B:
+ backward_addr = hantro_get_ref(vq,
+ slice_params->backward_ref_ts);
+ /* fall-through */
+ case V4L2_MPEG2_PICTURE_CODING_TYPE_P:
+ forward_addr = hantro_get_ref(vq,
+ slice_params->forward_ref_ts);
+ }
+
+ /* Source bitstream buffer */
+ addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+ vdpu_write_relaxed(vpu, addr, VDPU_REG_RLC_VLC_BASE);
+
+ /* Destination frame buffer */
+ addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+ current_addr = addr;
+
+ if (picture->picture_structure == PICT_BOTTOM_FIELD)
+ addr += ALIGN(ctx->dst_fmt.width, 16);
+ vdpu_write_relaxed(vpu, addr, VDPU_REG_DEC_OUT_BASE);
+
+ if (!forward_addr)
+ forward_addr = current_addr;
+ if (!backward_addr)
+ backward_addr = current_addr;
+
+ /* Set forward ref frame (top/bottom field) */
+ if (picture->picture_structure == PICT_FRAME ||
+ picture->picture_coding_type == V4L2_MPEG2_PICTURE_CODING_TYPE_B ||
+ (picture->picture_structure == PICT_TOP_FIELD &&
+ picture->top_field_first) ||
+ (picture->picture_structure == PICT_BOTTOM_FIELD &&
+ !picture->top_field_first)) {
+ vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER0_BASE);
+ vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER1_BASE);
+ } else if (picture->picture_structure == PICT_TOP_FIELD) {
+ vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER0_BASE);
+ vdpu_write_relaxed(vpu, current_addr, VDPU_REG_REFER1_BASE);
+ } else if (picture->picture_structure == PICT_BOTTOM_FIELD) {
+ vdpu_write_relaxed(vpu, current_addr, VDPU_REG_REFER0_BASE);
+ vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER1_BASE);
+ }
+
+ /* Set backward ref frame (top/bottom field) */
+ vdpu_write_relaxed(vpu, backward_addr, VDPU_REG_REFER2_BASE);
+ vdpu_write_relaxed(vpu, backward_addr, VDPU_REG_REFER3_BASE);
+}
+
+void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx)
+{
+ struct hantro_dev *vpu = ctx->dev;
+ struct vb2_v4l2_buffer *src_buf, *dst_buf;
+ const struct v4l2_ctrl_mpeg2_slice_params *slice_params;
+ const struct v4l2_mpeg2_sequence *sequence;
+ const struct v4l2_mpeg2_picture *picture;
+ u32 reg;
+
+ src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+
+ /* Apply request controls if any */
+ v4l2_ctrl_request_setup(src_buf->vb2_buf.req_obj.req,
+ &ctx->ctrl_handler);
+
+ slice_params = hantro_get_ctrl(ctx,
+ V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS);
+ sequence = &slice_params->sequence;
+ picture = &slice_params->picture;
+
+ reg = VDPU_REG_DEC_ADV_PRE_DIS(0) |
+ VDPU_REG_DEC_SCMD_DIS(0) |
+ VDPU_REG_FILTERING_DIS(1) |
+ VDPU_REG_DEC_LATENCY(0);
+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(50));
+
+ reg = VDPU_REG_INIT_QP(1) |
+ VDPU_REG_STREAM_LEN(slice_params->bit_size >> 3);
+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(51));
+
+ reg = VDPU_REG_APF_THRESHOLD(8) |
+ VDPU_REG_STARTMB_X(0) |
+ VDPU_REG_STARTMB_Y(0);
+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(52));
+
+ reg = VDPU_REG_DEC_MODE(5);
+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(53));
+
+ reg = VDPU_REG_DEC_STRENDIAN_E(1) |
+ VDPU_REG_DEC_STRSWAP32_E(1) |
+ VDPU_REG_DEC_OUTSWAP32_E(1) |
+ VDPU_REG_DEC_INSWAP32_E(1) |
+ VDPU_REG_DEC_OUT_ENDIAN(1) |
+ VDPU_REG_DEC_IN_ENDIAN(1);
+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(54));
+
+ reg = VDPU_REG_DEC_DATA_DISC_E(0) |
+ VDPU_REG_DEC_MAX_BURST(16) |
+ VDPU_REG_DEC_AXI_WR_ID(0) |
+ VDPU_REG_DEC_AXI_RD_ID(0);
+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(56));
+
+ reg = VDPU_REG_RLC_MODE_E(0) |
+ VDPU_REG_PIC_INTERLACE_E(!sequence->progressive_sequence) |
+ VDPU_REG_PIC_FIELDMODE_E(picture->picture_structure != PICT_FRAME) |
+ VDPU_REG_PIC_B_E(picture->picture_coding_type == V4L2_MPEG2_PICTURE_CODING_TYPE_B) |
+ VDPU_REG_PIC_INTER_E(picture->picture_coding_type != V4L2_MPEG2_PICTURE_CODING_TYPE_I) |
+ VDPU_REG_PIC_TOPFIELD_E(picture->picture_structure == PICT_TOP_FIELD) |
+ VDPU_REG_FWD_INTERLACE_E(0) |
+ VDPU_REG_WRITE_MVS_E(0) |
+ VDPU_REG_DEC_TIMEOUT_E(1) |
+ VDPU_REG_DEC_CLK_GATE_E(1);
+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(57));
+
+ reg = VDPU_REG_PIC_MB_WIDTH(MPEG2_MB_WIDTH(ctx->dst_fmt.width)) |
+ VDPU_REG_PIC_MB_HEIGHT_P(MPEG2_MB_HEIGHT(ctx->dst_fmt.height)) |
+ VDPU_REG_ALT_SCAN_E(picture->alternate_scan) |
+ VDPU_REG_TOPFIELDFIRST_E(picture->top_field_first);
+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(120));
+
+ reg = VDPU_REG_STRM_START_BIT(slice_params->data_bit_offset) |
+ VDPU_REG_QSCALE_TYPE(picture->q_scale_type) |
+ VDPU_REG_CON_MV_E(picture->concealment_motion_vectors) |
+ VDPU_REG_INTRA_DC_PREC(picture->intra_dc_precision) |
+ VDPU_REG_INTRA_VLC_TAB(picture->intra_vlc_format) |
+ VDPU_REG_FRAME_PRED_DCT(picture->frame_pred_frame_dct);
+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(122));
+
+ reg = VDPU_REG_ALT_SCAN_FLAG_E(picture->alternate_scan) |
+ VDPU_REG_FCODE_FWD_HOR(picture->f_code[0][0]) |
+ VDPU_REG_FCODE_FWD_VER(picture->f_code[0][1]) |
+ VDPU_REG_FCODE_BWD_HOR(picture->f_code[1][0]) |
+ VDPU_REG_FCODE_BWD_VER(picture->f_code[1][1]) |
+ VDPU_REG_MV_ACCURACY_FWD(1) |
+ VDPU_REG_MV_ACCURACY_BWD(1);
+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(136));
+
+ rk3399_vpu_mpeg2_dec_set_quantization(vpu, ctx);
+
+ rk3399_vpu_mpeg2_dec_set_buffers(vpu, ctx, &src_buf->vb2_buf,
+ &dst_buf->vb2_buf,
+ sequence, picture, slice_params);
+
+ /* Controls no longer in-use, we can complete them */
+ v4l2_ctrl_request_complete(src_buf->vb2_buf.req_obj.req,
+ &ctx->ctrl_handler);
+
+ /* Kick the watchdog and start decoding */
+ schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000));
+
+ reg = vdpu_read(vpu, VDPU_SWREG(57)) | VDPU_REG_DEC_E(1);
+ vdpu_write(vpu, reg, VDPU_SWREG(57));
+}
diff --git a/drivers/staging/media/rockchip/vpu/rk3399_vpu_regs.h b/drivers/staging/media/hantro/rk3399_vpu_regs.h
index fbe294177ec9..88d096920f30 100644
--- a/drivers/staging/media/rockchip/vpu/rk3399_vpu_regs.h
+++ b/drivers/staging/media/hantro/rk3399_vpu_regs.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
- * Rockchip VPU codec driver
+ * Hantro VPU codec driver
*
* Copyright (C) 2018 Rockchip Electronics Co., Ltd.
* Alpha Lin <alpha.lin@rock-chips.com>
diff --git a/drivers/staging/media/imx/Makefile b/drivers/staging/media/imx/Makefile
index d2d909a36239..aa6c4b4ad37e 100644
--- a/drivers/staging/media/imx/Makefile
+++ b/drivers/staging/media/imx/Makefile
@@ -1,16 +1,16 @@
# SPDX-License-Identifier: GPL-2.0
-imx-media-objs := imx-media-dev.o imx-media-internal-sd.o imx-media-of.o
-imx-media-objs += imx-media-dev-common.o
-imx-media-common-objs := imx-media-utils.o imx-media-fim.o
-imx-media-ic-objs := imx-ic-common.o imx-ic-prp.o imx-ic-prpencvf.o
+imx6-media-objs := imx-media-dev.o imx-media-internal-sd.o \
+ imx-ic-common.o imx-ic-prp.o imx-ic-prpencvf.o imx-media-vdic.o
-obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx-media.o
+imx-media-common-objs := imx-media-capture.o imx-media-dev-common.o \
+ imx-media-of.o imx-media-utils.o
+
+imx6-media-csi-objs := imx-media-csi.o imx-media-fim.o
+
+obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx6-media.o
obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx-media-common.o
-obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx-media-capture.o
-obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx-media-vdic.o
-obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx-media-ic.o
-obj-$(CONFIG_VIDEO_IMX_CSI) += imx-media-csi.o
+obj-$(CONFIG_VIDEO_IMX_CSI) += imx6-media-csi.o
obj-$(CONFIG_VIDEO_IMX_CSI) += imx6-mipi-csi2.o
obj-$(CONFIG_VIDEO_IMX7_CSI) += imx7-media-csi.o
diff --git a/drivers/staging/media/imx/imx-ic-common.c b/drivers/staging/media/imx/imx-ic-common.c
index 18cd4cb92431..6df1ffb53895 100644
--- a/drivers/staging/media/imx/imx-ic-common.c
+++ b/drivers/staging/media/imx/imx-ic-common.c
@@ -4,8 +4,6 @@
*
* Copyright (c) 2014-2016 Mentor Graphics Inc.
*/
-#include <linux/module.h>
-#include <linux/platform_device.h>
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
#include "imx-media.h"
@@ -20,23 +18,23 @@ static struct imx_ic_ops *ic_ops[IC_NUM_OPS] = {
[IC_TASK_VIEWFINDER] = &imx_ic_prpencvf_ops,
};
-static int imx_ic_probe(struct platform_device *pdev)
+struct v4l2_subdev *imx_media_ic_register(struct v4l2_device *v4l2_dev,
+ struct device *ipu_dev,
+ struct ipu_soc *ipu,
+ u32 grp_id)
{
- struct imx_media_ipu_internal_sd_pdata *pdata;
struct imx_ic_priv *priv;
int ret;
- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ priv = devm_kzalloc(ipu_dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
- platform_set_drvdata(pdev, &priv->sd);
- priv->dev = &pdev->dev;
+ priv->ipu_dev = ipu_dev;
+ priv->ipu = ipu;
- /* get our ipu_id, grp_id and IC task id */
- pdata = priv->dev->platform_data;
- priv->ipu_id = pdata->ipu_id;
- switch (pdata->grp_id) {
+ /* get our IC task id */
+ switch (grp_id) {
case IMX_MEDIA_GRP_ID_IPU_IC_PRP:
priv->task_id = IC_TASK_PRP;
break;
@@ -47,7 +45,7 @@ static int imx_ic_probe(struct platform_device *pdev)
priv->task_id = IC_TASK_VIEWFINDER;
break;
default:
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
}
v4l2_subdev_init(&priv->sd, ic_ops[priv->task_id]->subdev_ops);
@@ -55,55 +53,35 @@ static int imx_ic_probe(struct platform_device *pdev)
priv->sd.internal_ops = ic_ops[priv->task_id]->internal_ops;
priv->sd.entity.ops = ic_ops[priv->task_id]->entity_ops;
priv->sd.entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER;
- priv->sd.dev = &pdev->dev;
- priv->sd.owner = THIS_MODULE;
+ priv->sd.owner = ipu_dev->driver->owner;
priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
- priv->sd.grp_id = pdata->grp_id;
- strscpy(priv->sd.name, pdata->sd_name, sizeof(priv->sd.name));
+ priv->sd.grp_id = grp_id;
+ imx_media_grp_id_to_sd_name(priv->sd.name, sizeof(priv->sd.name),
+ priv->sd.grp_id, ipu_get_num(ipu));
ret = ic_ops[priv->task_id]->init(priv);
if (ret)
- return ret;
+ return ERR_PTR(ret);
- ret = v4l2_async_register_subdev(&priv->sd);
- if (ret)
+ ret = v4l2_device_register_subdev(v4l2_dev, &priv->sd);
+ if (ret) {
ic_ops[priv->task_id]->remove(priv);
+ return ERR_PTR(ret);
+ }
- return ret;
+ return &priv->sd;
}
-static int imx_ic_remove(struct platform_device *pdev)
+int imx_media_ic_unregister(struct v4l2_subdev *sd)
{
- struct v4l2_subdev *sd = platform_get_drvdata(pdev);
struct imx_ic_priv *priv = container_of(sd, struct imx_ic_priv, sd);
v4l2_info(sd, "Removing\n");
ic_ops[priv->task_id]->remove(priv);
- v4l2_async_unregister_subdev(sd);
+ v4l2_device_unregister_subdev(sd);
media_entity_cleanup(&sd->entity);
return 0;
}
-
-static const struct platform_device_id imx_ic_ids[] = {
- { .name = "imx-ipuv3-ic" },
- { },
-};
-MODULE_DEVICE_TABLE(platform, imx_ic_ids);
-
-static struct platform_driver imx_ic_driver = {
- .probe = imx_ic_probe,
- .remove = imx_ic_remove,
- .id_table = imx_ic_ids,
- .driver = {
- .name = "imx-ipuv3-ic",
- },
-};
-module_platform_driver(imx_ic_driver);
-
-MODULE_DESCRIPTION("i.MX IC subdev driver");
-MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx-ipuv3-ic");
diff --git a/drivers/staging/media/imx/imx-ic-prp.c b/drivers/staging/media/imx/imx-ic-prp.c
index f87fe0203720..35e60a120dc1 100644
--- a/drivers/staging/media/imx/imx-ic-prp.c
+++ b/drivers/staging/media/imx/imx-ic-prp.c
@@ -35,16 +35,12 @@
#define S_ALIGN 1 /* multiple of 2 */
struct prp_priv {
- struct imx_media_dev *md;
struct imx_ic_priv *ic_priv;
struct media_pad pad[PRP_NUM_PADS];
/* lock to protect all members below */
struct mutex lock;
- /* IPU units we require */
- struct ipu_soc *ipu;
-
struct v4l2_subdev *src_sd;
struct v4l2_subdev *sink_sd_prpenc;
struct v4l2_subdev *sink_sd_prpvf;
@@ -62,7 +58,7 @@ static inline struct prp_priv *sd_to_priv(struct v4l2_subdev *sd)
{
struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
- return ic_priv->prp_priv;
+ return ic_priv->task_priv;
}
static int prp_start(struct prp_priv *priv)
@@ -70,12 +66,10 @@ static int prp_start(struct prp_priv *priv)
struct imx_ic_priv *ic_priv = priv->ic_priv;
bool src_is_vdic;
- priv->ipu = priv->md->ipu[ic_priv->ipu_id];
-
/* set IC to receive from CSI or VDI depending on source */
src_is_vdic = !!(priv->src_sd->grp_id & IMX_MEDIA_GRP_ID_IPU_VDIC);
- ipu_set_ic_src_mux(priv->ipu, priv->csi_id, src_is_vdic);
+ ipu_set_ic_src_mux(ic_priv->ipu, priv->csi_id, src_is_vdic);
return 0;
}
@@ -218,12 +212,12 @@ static int prp_link_setup(struct media_entity *entity,
{
struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
- struct prp_priv *priv = ic_priv->prp_priv;
+ struct prp_priv *priv = ic_priv->task_priv;
struct v4l2_subdev *remote_sd;
int ret = 0;
- dev_dbg(ic_priv->dev, "link setup %s -> %s", remote->entity->name,
- local->entity->name);
+ dev_dbg(ic_priv->ipu_dev, "%s: link setup %s -> %s",
+ ic_priv->sd.name, remote->entity->name, local->entity->name);
remote_sd = media_entity_to_v4l2_subdev(remote->entity);
@@ -297,7 +291,7 @@ static int prp_link_validate(struct v4l2_subdev *sd,
struct v4l2_subdev_format *sink_fmt)
{
struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
- struct prp_priv *priv = ic_priv->prp_priv;
+ struct prp_priv *priv = ic_priv->task_priv;
struct v4l2_subdev *csi;
int ret;
@@ -306,8 +300,8 @@ static int prp_link_validate(struct v4l2_subdev *sd,
if (ret)
return ret;
- csi = imx_media_find_upstream_subdev(priv->md, &ic_priv->sd.entity,
- IMX_MEDIA_GRP_ID_IPU_CSI);
+ csi = imx_media_pipeline_subdev(&ic_priv->sd.entity,
+ IMX_MEDIA_GRP_ID_IPU_CSI, true);
if (IS_ERR(csi))
csi = NULL;
@@ -353,7 +347,7 @@ out:
static int prp_s_stream(struct v4l2_subdev *sd, int enable)
{
struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
- struct prp_priv *priv = ic_priv->prp_priv;
+ struct prp_priv *priv = ic_priv->task_priv;
int ret = 0;
mutex_lock(&priv->lock);
@@ -370,7 +364,8 @@ static int prp_s_stream(struct v4l2_subdev *sd, int enable)
if (priv->stream_count != !enable)
goto update_count;
- dev_dbg(ic_priv->dev, "stream %s\n", enable ? "ON" : "OFF");
+ dev_dbg(ic_priv->ipu_dev, "%s: stream %s\n", sd->name,
+ enable ? "ON" : "OFF");
if (enable)
ret = prp_start(priv);
@@ -442,9 +437,6 @@ static int prp_registered(struct v4l2_subdev *sd)
int i, ret;
u32 code;
- /* get media device */
- priv->md = dev_get_drvdata(sd->v4l2_dev->dev);
-
for (i = 0; i < PRP_NUM_PADS; i++) {
priv->pad[i].flags = (i == PRP_SINK_PAD) ?
MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
@@ -496,12 +488,12 @@ static int prp_init(struct imx_ic_priv *ic_priv)
{
struct prp_priv *priv;
- priv = devm_kzalloc(ic_priv->dev, sizeof(*priv), GFP_KERNEL);
+ priv = devm_kzalloc(ic_priv->ipu_dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
mutex_init(&priv->lock);
- ic_priv->prp_priv = priv;
+ ic_priv->task_priv = priv;
priv->ic_priv = ic_priv;
return 0;
@@ -509,7 +501,7 @@ static int prp_init(struct imx_ic_priv *ic_priv)
static void prp_remove(struct imx_ic_priv *ic_priv)
{
- struct prp_priv *priv = ic_priv->prp_priv;
+ struct prp_priv *priv = ic_priv->task_priv;
mutex_destroy(&priv->lock);
}
diff --git a/drivers/staging/media/imx/imx-ic-prpencvf.c b/drivers/staging/media/imx/imx-ic-prpencvf.c
index f2fe3c11c70e..67ffa46a8e96 100644
--- a/drivers/staging/media/imx/imx-ic-prpencvf.c
+++ b/drivers/staging/media/imx/imx-ic-prpencvf.c
@@ -50,7 +50,6 @@
#define S_ALIGN 1 /* multiple of 2 */
struct prp_priv {
- struct imx_media_dev *md;
struct imx_ic_priv *ic_priv;
struct media_pad pad[PRPENCVF_NUM_PADS];
/* the video device at output pad */
@@ -60,7 +59,6 @@ struct prp_priv {
struct mutex lock;
/* IPU units we require */
- struct ipu_soc *ipu;
struct ipu_ic *ic;
struct ipuv3_channel *out_ch;
struct ipuv3_channel *rot_in_ch;
@@ -156,9 +154,7 @@ static int prp_get_ipu_resources(struct prp_priv *priv)
struct ipuv3_channel *out_ch, *rot_in_ch, *rot_out_ch;
int ret, task = ic_priv->task_id;
- priv->ipu = priv->md->ipu[ic_priv->ipu_id];
-
- ic = ipu_ic_get(priv->ipu, task);
+ ic = ipu_ic_get(ic_priv->ipu, task);
if (IS_ERR(ic)) {
v4l2_err(&ic_priv->sd, "failed to get IC\n");
ret = PTR_ERR(ic);
@@ -166,7 +162,7 @@ static int prp_get_ipu_resources(struct prp_priv *priv)
}
priv->ic = ic;
- out_ch = ipu_idmac_get(priv->ipu, prp_channel[task].out_ch);
+ out_ch = ipu_idmac_get(ic_priv->ipu, prp_channel[task].out_ch);
if (IS_ERR(out_ch)) {
v4l2_err(&ic_priv->sd, "could not get IDMAC channel %u\n",
prp_channel[task].out_ch);
@@ -175,7 +171,7 @@ static int prp_get_ipu_resources(struct prp_priv *priv)
}
priv->out_ch = out_ch;
- rot_in_ch = ipu_idmac_get(priv->ipu, prp_channel[task].rot_in_ch);
+ rot_in_ch = ipu_idmac_get(ic_priv->ipu, prp_channel[task].rot_in_ch);
if (IS_ERR(rot_in_ch)) {
v4l2_err(&ic_priv->sd, "could not get IDMAC channel %u\n",
prp_channel[task].rot_in_ch);
@@ -184,7 +180,7 @@ static int prp_get_ipu_resources(struct prp_priv *priv)
}
priv->rot_in_ch = rot_in_ch;
- rot_out_ch = ipu_idmac_get(priv->ipu, prp_channel[task].rot_out_ch);
+ rot_out_ch = ipu_idmac_get(ic_priv->ipu, prp_channel[task].rot_out_ch);
if (IS_ERR(rot_out_ch)) {
v4l2_err(&ic_priv->sd, "could not get IDMAC channel %u\n",
prp_channel[task].rot_out_ch);
@@ -476,13 +472,13 @@ static int prp_setup_rotation(struct prp_priv *priv)
return ret;
}
- ret = imx_media_alloc_dma_buf(priv->md, &priv->rot_buf[0],
+ ret = imx_media_alloc_dma_buf(ic_priv->ipu_dev, &priv->rot_buf[0],
outfmt->sizeimage);
if (ret) {
v4l2_err(&ic_priv->sd, "failed to alloc rot_buf[0], %d\n", ret);
return ret;
}
- ret = imx_media_alloc_dma_buf(priv->md, &priv->rot_buf[1],
+ ret = imx_media_alloc_dma_buf(ic_priv->ipu_dev, &priv->rot_buf[1],
outfmt->sizeimage);
if (ret) {
v4l2_err(&ic_priv->sd, "failed to alloc rot_buf[1], %d\n", ret);
@@ -554,14 +550,16 @@ static int prp_setup_rotation(struct prp_priv *priv)
unsetup_vb2:
prp_unsetup_vb2_buf(priv, VB2_BUF_STATE_QUEUED);
free_rot1:
- imx_media_free_dma_buf(priv->md, &priv->rot_buf[1]);
+ imx_media_free_dma_buf(ic_priv->ipu_dev, &priv->rot_buf[1]);
free_rot0:
- imx_media_free_dma_buf(priv->md, &priv->rot_buf[0]);
+ imx_media_free_dma_buf(ic_priv->ipu_dev, &priv->rot_buf[0]);
return ret;
}
static void prp_unsetup_rotation(struct prp_priv *priv)
{
+ struct imx_ic_priv *ic_priv = priv->ic_priv;
+
ipu_ic_task_disable(priv->ic);
ipu_idmac_disable_channel(priv->out_ch);
@@ -572,8 +570,8 @@ static void prp_unsetup_rotation(struct prp_priv *priv)
ipu_ic_disable(priv->ic);
- imx_media_free_dma_buf(priv->md, &priv->rot_buf[0]);
- imx_media_free_dma_buf(priv->md, &priv->rot_buf[1]);
+ imx_media_free_dma_buf(ic_priv->ipu_dev, &priv->rot_buf[0]);
+ imx_media_free_dma_buf(ic_priv->ipu_dev, &priv->rot_buf[1]);
}
static int prp_setup_norotation(struct prp_priv *priv)
@@ -624,7 +622,7 @@ static int prp_setup_norotation(struct prp_priv *priv)
ipu_cpmem_dump(priv->out_ch);
ipu_ic_dump(priv->ic);
- ipu_dump(priv->ipu);
+ ipu_dump(ic_priv->ipu);
ipu_ic_enable(priv->ic);
@@ -676,7 +674,7 @@ static int prp_start(struct prp_priv *priv)
outfmt = &vdev->fmt.fmt.pix;
- ret = imx_media_alloc_dma_buf(priv->md, &priv->underrun_buf,
+ ret = imx_media_alloc_dma_buf(ic_priv->ipu_dev, &priv->underrun_buf,
outfmt->sizeimage);
if (ret)
goto out_put_ipu;
@@ -696,10 +694,10 @@ static int prp_start(struct prp_priv *priv)
if (ret)
goto out_free_underrun;
- priv->nfb4eof_irq = ipu_idmac_channel_irq(priv->ipu,
+ priv->nfb4eof_irq = ipu_idmac_channel_irq(ic_priv->ipu,
priv->out_ch,
IPU_IRQ_NFB4EOF);
- ret = devm_request_irq(ic_priv->dev, priv->nfb4eof_irq,
+ ret = devm_request_irq(ic_priv->ipu_dev, priv->nfb4eof_irq,
prp_nfb4eof_interrupt, 0,
"imx-ic-prp-nfb4eof", priv);
if (ret) {
@@ -710,12 +708,12 @@ static int prp_start(struct prp_priv *priv)
if (ipu_rot_mode_is_irt(priv->rot_mode))
priv->eof_irq = ipu_idmac_channel_irq(
- priv->ipu, priv->rot_out_ch, IPU_IRQ_EOF);
+ ic_priv->ipu, priv->rot_out_ch, IPU_IRQ_EOF);
else
priv->eof_irq = ipu_idmac_channel_irq(
- priv->ipu, priv->out_ch, IPU_IRQ_EOF);
+ ic_priv->ipu, priv->out_ch, IPU_IRQ_EOF);
- ret = devm_request_irq(ic_priv->dev, priv->eof_irq,
+ ret = devm_request_irq(ic_priv->ipu_dev, priv->eof_irq,
prp_eof_interrupt, 0,
"imx-ic-prp-eof", priv);
if (ret) {
@@ -740,13 +738,13 @@ static int prp_start(struct prp_priv *priv)
return 0;
out_free_eof_irq:
- devm_free_irq(ic_priv->dev, priv->eof_irq, priv);
+ devm_free_irq(ic_priv->ipu_dev, priv->eof_irq, priv);
out_free_nfb4eof_irq:
- devm_free_irq(ic_priv->dev, priv->nfb4eof_irq, priv);
+ devm_free_irq(ic_priv->ipu_dev, priv->nfb4eof_irq, priv);
out_unsetup:
prp_unsetup(priv, VB2_BUF_STATE_QUEUED);
out_free_underrun:
- imx_media_free_dma_buf(priv->md, &priv->underrun_buf);
+ imx_media_free_dma_buf(ic_priv->ipu_dev, &priv->underrun_buf);
out_put_ipu:
prp_put_ipu_resources(priv);
return ret;
@@ -778,12 +776,12 @@ static void prp_stop(struct prp_priv *priv)
v4l2_warn(&ic_priv->sd,
"upstream stream off failed: %d\n", ret);
- devm_free_irq(ic_priv->dev, priv->eof_irq, priv);
- devm_free_irq(ic_priv->dev, priv->nfb4eof_irq, priv);
+ devm_free_irq(ic_priv->ipu_dev, priv->eof_irq, priv);
+ devm_free_irq(ic_priv->ipu_dev, priv->nfb4eof_irq, priv);
prp_unsetup(priv, VB2_BUF_STATE_ERROR);
- imx_media_free_dma_buf(priv->md, &priv->underrun_buf);
+ imx_media_free_dma_buf(ic_priv->ipu_dev, &priv->underrun_buf);
/* cancel the EOF timeout timer */
del_timer_sync(&priv->eof_timeout_timer);
@@ -926,11 +924,8 @@ static int prp_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_format *sdformat)
{
struct prp_priv *priv = sd_to_priv(sd);
- struct imx_media_video_dev *vdev = priv->vdev;
const struct imx_media_pixfmt *cc;
- struct v4l2_pix_format vdev_fmt;
struct v4l2_mbus_framefmt *fmt;
- struct v4l2_rect vdev_compose;
int ret = 0;
if (sdformat->pad >= PRPENCVF_NUM_PADS)
@@ -966,19 +961,9 @@ static int prp_set_fmt(struct v4l2_subdev *sd,
priv->cc[PRPENCVF_SRC_PAD] = outcc;
}
- if (sdformat->which == V4L2_SUBDEV_FORMAT_TRY)
- goto out;
-
- priv->cc[sdformat->pad] = cc;
+ if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ priv->cc[sdformat->pad] = cc;
- /* propagate output pad format to capture device */
- imx_media_mbus_fmt_to_pix_fmt(&vdev_fmt, &vdev_compose,
- &priv->format_mbus[PRPENCVF_SRC_PAD],
- priv->cc[PRPENCVF_SRC_PAD]);
- mutex_unlock(&priv->lock);
- imx_media_capture_device_set_format(vdev, &vdev_fmt, &vdev_compose);
-
- return 0;
out:
mutex_unlock(&priv->lock);
return ret;
@@ -1033,8 +1018,8 @@ static int prp_link_setup(struct media_entity *entity,
struct v4l2_subdev *remote_sd;
int ret = 0;
- dev_dbg(ic_priv->dev, "link setup %s -> %s", remote->entity->name,
- local->entity->name);
+ dev_dbg(ic_priv->ipu_dev, "%s: link setup %s -> %s",
+ ic_priv->sd.name, remote->entity->name, local->entity->name);
mutex_lock(&priv->lock);
@@ -1200,7 +1185,8 @@ static int prp_s_stream(struct v4l2_subdev *sd, int enable)
if (priv->stream_count != !enable)
goto update_count;
- dev_dbg(ic_priv->dev, "stream %s\n", enable ? "ON" : "OFF");
+ dev_dbg(ic_priv->ipu_dev, "%s: stream %s\n", sd->name,
+ enable ? "ON" : "OFF");
if (enable)
ret = prp_start(priv);
@@ -1263,9 +1249,6 @@ static int prp_registered(struct v4l2_subdev *sd)
int i, ret;
u32 code;
- /* get media device */
- priv->md = dev_get_drvdata(sd->v4l2_dev->dev);
-
for (i = 0; i < PRPENCVF_NUM_PADS; i++) {
priv->pad[i].flags = (i == PRPENCVF_SINK_PAD) ?
MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
@@ -1288,14 +1271,10 @@ static int prp_registered(struct v4l2_subdev *sd)
if (ret)
return ret;
- ret = imx_media_capture_device_register(priv->md, priv->vdev);
+ ret = imx_media_capture_device_register(priv->vdev);
if (ret)
return ret;
- ret = imx_media_add_video_device(priv->md, priv->vdev);
- if (ret)
- goto unreg;
-
ret = prp_init_controls(priv);
if (ret)
goto unreg;
@@ -1347,7 +1326,7 @@ static int prp_init(struct imx_ic_priv *ic_priv)
{
struct prp_priv *priv;
- priv = devm_kzalloc(ic_priv->dev, sizeof(*priv), GFP_KERNEL);
+ priv = devm_kzalloc(ic_priv->ipu_dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -1357,7 +1336,8 @@ static int prp_init(struct imx_ic_priv *ic_priv)
spin_lock_init(&priv->irqlock);
timer_setup(&priv->eof_timeout_timer, prp_eof_timeout, 0);
- priv->vdev = imx_media_capture_device_init(&ic_priv->sd,
+ priv->vdev = imx_media_capture_device_init(ic_priv->ipu_dev,
+ &ic_priv->sd,
PRPENCVF_SRC_PAD);
if (IS_ERR(priv->vdev))
return PTR_ERR(priv->vdev);
diff --git a/drivers/staging/media/imx/imx-ic.h b/drivers/staging/media/imx/imx-ic.h
index 0dbcf2a7ab5f..587c191c3eab 100644
--- a/drivers/staging/media/imx/imx-ic.h
+++ b/drivers/staging/media/imx/imx-ic.h
@@ -10,11 +10,10 @@
#include <media/v4l2-subdev.h>
struct imx_ic_priv {
- struct device *dev;
+ struct device *ipu_dev;
+ struct ipu_soc *ipu;
struct v4l2_subdev sd;
- int ipu_id;
int task_id;
- void *prp_priv;
void *task_priv;
};
@@ -29,6 +28,5 @@ struct imx_ic_ops {
extern struct imx_ic_ops imx_ic_prp_ops;
extern struct imx_ic_ops imx_ic_prpencvf_ops;
-extern struct imx_ic_ops imx_ic_pp_ops;
#endif
diff --git a/drivers/staging/media/imx/imx-media-capture.c b/drivers/staging/media/imx/imx-media-capture.c
index 9430c835c434..b33a07bc9105 100644
--- a/drivers/staging/media/imx/imx-media-capture.c
+++ b/drivers/staging/media/imx/imx-media-capture.c
@@ -202,6 +202,7 @@ static int capture_g_fmt_vid_cap(struct file *file, void *fh,
static int __capture_try_fmt_vid_cap(struct capture_priv *priv,
struct v4l2_subdev_format *fmt_src,
struct v4l2_format *f,
+ const struct imx_media_pixfmt **retcc,
struct v4l2_rect *compose)
{
const struct imx_media_pixfmt *cc, *cc_src;
@@ -242,8 +243,17 @@ static int __capture_try_fmt_vid_cap(struct capture_priv *priv,
}
}
- imx_media_mbus_fmt_to_pix_fmt(&f->fmt.pix, compose,
- &fmt_src->format, cc);
+ imx_media_mbus_fmt_to_pix_fmt(&f->fmt.pix, &fmt_src->format, cc);
+
+ if (retcc)
+ *retcc = cc;
+
+ if (compose) {
+ compose->left = 0;
+ compose->top = 0;
+ compose->width = fmt_src->format.width;
+ compose->height = fmt_src->format.height;
+ }
return 0;
}
@@ -261,7 +271,7 @@ static int capture_try_fmt_vid_cap(struct file *file, void *fh,
if (ret)
return ret;
- return __capture_try_fmt_vid_cap(priv, &fmt_src, f, NULL);
+ return __capture_try_fmt_vid_cap(priv, &fmt_src, f, NULL, NULL);
}
static int capture_s_fmt_vid_cap(struct file *file, void *fh,
@@ -269,7 +279,6 @@ static int capture_s_fmt_vid_cap(struct file *file, void *fh,
{
struct capture_priv *priv = video_drvdata(file);
struct v4l2_subdev_format fmt_src;
- struct v4l2_rect compose;
int ret;
if (vb2_is_busy(&priv->q)) {
@@ -283,14 +292,12 @@ static int capture_s_fmt_vid_cap(struct file *file, void *fh,
if (ret)
return ret;
- ret = __capture_try_fmt_vid_cap(priv, &fmt_src, f, &compose);
+ ret = __capture_try_fmt_vid_cap(priv, &fmt_src, f, &priv->vdev.cc,
+ &priv->vdev.compose);
if (ret)
return ret;
priv->vdev.fmt.fmt.pix = f->fmt.pix;
- priv->vdev.cc = imx_media_find_format(f->fmt.pix.pixelformat,
- CS_SEL_ANY, true);
- priv->vdev.compose = compose;
return 0;
}
@@ -520,6 +527,33 @@ static void capture_buf_queue(struct vb2_buffer *vb)
spin_unlock_irqrestore(&priv->q_lock, flags);
}
+static int capture_validate_fmt(struct capture_priv *priv)
+{
+ struct v4l2_subdev_format fmt_src;
+ const struct imx_media_pixfmt *cc;
+ struct v4l2_rect compose;
+ struct v4l2_format f;
+ int ret;
+
+ fmt_src.pad = priv->src_sd_pad;
+ fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ ret = v4l2_subdev_call(priv->src_sd, pad, get_fmt, NULL, &fmt_src);
+ if (ret)
+ return ret;
+
+ v4l2_fill_pix_format(&f.fmt.pix, &fmt_src.format);
+
+ ret = __capture_try_fmt_vid_cap(priv, &fmt_src, &f, &cc, &compose);
+ if (ret)
+ return ret;
+
+ return (priv->vdev.fmt.fmt.pix.width != f.fmt.pix.width ||
+ priv->vdev.fmt.fmt.pix.height != f.fmt.pix.height ||
+ priv->vdev.cc->cs != cc->cs ||
+ priv->vdev.compose.width != compose.width ||
+ priv->vdev.compose.height != compose.height) ? -EINVAL : 0;
+}
+
static int capture_start_streaming(struct vb2_queue *vq, unsigned int count)
{
struct capture_priv *priv = vb2_get_drv_priv(vq);
@@ -527,6 +561,12 @@ static int capture_start_streaming(struct vb2_queue *vq, unsigned int count)
unsigned long flags;
int ret;
+ ret = capture_validate_fmt(priv);
+ if (ret) {
+ v4l2_err(priv->src_sd, "capture format not valid\n");
+ goto return_bufs;
+ }
+
ret = imx_media_pipeline_set_stream(priv->md, &priv->src_sd->entity,
true);
if (ret) {
@@ -614,7 +654,6 @@ static int capture_release(struct file *file)
struct capture_priv *priv = video_drvdata(file);
struct video_device *vfd = priv->vdev.vfd;
struct vb2_queue *vq = &priv->q;
- int ret = 0;
mutex_lock(&priv->mutex);
@@ -627,7 +666,7 @@ static int capture_release(struct file *file)
v4l2_fh_release(file);
mutex_unlock(&priv->mutex);
- return ret;
+ return 0;
}
static const struct v4l2_file_operations capture_fops = {
@@ -649,21 +688,6 @@ static struct video_device capture_videodev = {
.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING,
};
-void imx_media_capture_device_set_format(struct imx_media_video_dev *vdev,
- const struct v4l2_pix_format *pix,
- const struct v4l2_rect *compose)
-{
- struct capture_priv *priv = to_capture_priv(vdev);
-
- mutex_lock(&priv->mutex);
- priv->vdev.fmt.fmt.pix = *pix;
- priv->vdev.cc = imx_media_find_format(pix->pixelformat, CS_SEL_ANY,
- true);
- priv->vdev.compose = *compose;
- mutex_unlock(&priv->mutex);
-}
-EXPORT_SYMBOL_GPL(imx_media_capture_device_set_format);
-
struct imx_media_buffer *
imx_media_capture_device_next_buf(struct imx_media_video_dev *vdev)
{
@@ -701,19 +725,20 @@ void imx_media_capture_device_error(struct imx_media_video_dev *vdev)
}
EXPORT_SYMBOL_GPL(imx_media_capture_device_error);
-int imx_media_capture_device_register(struct imx_media_dev *md,
- struct imx_media_video_dev *vdev)
+int imx_media_capture_device_register(struct imx_media_video_dev *vdev)
{
struct capture_priv *priv = to_capture_priv(vdev);
struct v4l2_subdev *sd = priv->src_sd;
+ struct v4l2_device *v4l2_dev = sd->v4l2_dev;
struct video_device *vfd = vdev->vfd;
struct vb2_queue *vq = &priv->q;
struct v4l2_subdev_format fmt_src;
int ret;
- priv->md = md;
+ /* get media device */
+ priv->md = container_of(v4l2_dev->mdev, struct imx_media_dev, md);
- vfd->v4l2_dev = sd->v4l2_dev;
+ vfd->v4l2_dev = v4l2_dev;
ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
if (ret) {
@@ -765,8 +790,10 @@ int imx_media_capture_device_register(struct imx_media_dev *md,
}
vdev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- imx_media_mbus_fmt_to_pix_fmt(&vdev->fmt.fmt.pix, &vdev->compose,
+ imx_media_mbus_fmt_to_pix_fmt(&vdev->fmt.fmt.pix,
&fmt_src.format, NULL);
+ vdev->compose.width = fmt_src.format.width;
+ vdev->compose.height = fmt_src.format.height;
vdev->cc = imx_media_find_format(vdev->fmt.fmt.pix.pixelformat,
CS_SEL_ANY, false);
@@ -775,6 +802,9 @@ int imx_media_capture_device_register(struct imx_media_dev *md,
vfd->ctrl_handler = &priv->ctrl_hdlr;
+ /* add vdev to the video device list */
+ imx_media_add_video_device(priv->md, vdev);
+
return 0;
unreg:
video_unregister_device(vfd);
@@ -799,18 +829,19 @@ void imx_media_capture_device_unregister(struct imx_media_video_dev *vdev)
EXPORT_SYMBOL_GPL(imx_media_capture_device_unregister);
struct imx_media_video_dev *
-imx_media_capture_device_init(struct v4l2_subdev *src_sd, int pad)
+imx_media_capture_device_init(struct device *dev, struct v4l2_subdev *src_sd,
+ int pad)
{
struct capture_priv *priv;
struct video_device *vfd;
- priv = devm_kzalloc(src_sd->dev, sizeof(*priv), GFP_KERNEL);
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return ERR_PTR(-ENOMEM);
priv->src_sd = src_sd;
priv->src_sd_pad = pad;
- priv->dev = src_sd->dev;
+ priv->dev = dev;
mutex_init(&priv->mutex);
spin_lock_init(&priv->q_lock);
diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c
index dce4addadff4..367e39f5b382 100644
--- a/drivers/staging/media/imx/imx-media-csi.c
+++ b/drivers/staging/media/imx/imx-media-csi.c
@@ -56,7 +56,6 @@ struct csi_skip_desc {
struct csi_priv {
struct device *dev;
struct ipu_soc *ipu;
- struct imx_media_dev *md;
struct v4l2_subdev sd;
struct media_pad pad[CSI_NUM_PADS];
/* the video device at IDMAC output pad */
@@ -178,8 +177,8 @@ static int csi_get_upstream_endpoint(struct csi_priv *priv,
* CSI-2 receiver if it is in the path, otherwise stay
* with video mux.
*/
- sd = imx_media_find_upstream_subdev(priv->md, src,
- IMX_MEDIA_GRP_ID_CSI2);
+ sd = imx_media_pipeline_subdev(src, IMX_MEDIA_GRP_ID_CSI2,
+ true);
if (!IS_ERR(sd))
src = &sd->entity;
}
@@ -193,9 +192,9 @@ static int csi_get_upstream_endpoint(struct csi_priv *priv,
src = &priv->sd.entity;
/* get source pad of entity directly upstream from src */
- pad = imx_media_find_upstream_pad(priv->md, src, 0);
- if (IS_ERR(pad))
- return PTR_ERR(pad);
+ pad = imx_media_pipeline_pad(src, 0, 0, true);
+ if (!pad)
+ return -ENODEV;
sd = media_entity_to_v4l2_subdev(pad->entity);
@@ -608,7 +607,7 @@ static int csi_idmac_start(struct csi_priv *priv)
outfmt = &vdev->fmt.fmt.pix;
- ret = imx_media_alloc_dma_buf(priv->md, &priv->underrun_buf,
+ ret = imx_media_alloc_dma_buf(priv->dev, &priv->underrun_buf,
outfmt->sizeimage);
if (ret)
goto out_put_ipu;
@@ -662,7 +661,7 @@ out_free_nfb4eof_irq:
out_unsetup:
csi_idmac_unsetup(priv, VB2_BUF_STATE_QUEUED);
out_free_dma_buf:
- imx_media_free_dma_buf(priv->md, &priv->underrun_buf);
+ imx_media_free_dma_buf(priv->dev, &priv->underrun_buf);
out_put_ipu:
csi_idmac_put_ipu_resources(priv);
return ret;
@@ -694,7 +693,7 @@ static void csi_idmac_stop(struct csi_priv *priv)
csi_idmac_unsetup(priv, VB2_BUF_STATE_ERROR);
- imx_media_free_dma_buf(priv->md, &priv->underrun_buf);
+ imx_media_free_dma_buf(priv->dev, &priv->underrun_buf);
/* cancel the EOF timeout timer */
del_timer_sync(&priv->eof_timeout_timer);
@@ -1134,8 +1133,7 @@ static int csi_link_validate(struct v4l2_subdev *sd,
*/
#if 0
mutex_unlock(&priv->lock);
- vc_num = imx_media_find_mipi_csi2_channel(priv->md,
- &priv->sd.entity);
+ vc_num = imx_media_find_mipi_csi2_channel(&priv->sd.entity);
if (vc_num < 0)
return vc_num;
mutex_lock(&priv->lock);
@@ -1505,13 +1503,10 @@ static int csi_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_format *sdformat)
{
struct csi_priv *priv = v4l2_get_subdevdata(sd);
- struct imx_media_video_dev *vdev = priv->vdev;
struct v4l2_fwnode_endpoint upstream_ep = { .bus_type = 0 };
const struct imx_media_pixfmt *cc;
- struct v4l2_pix_format vdev_fmt;
struct v4l2_mbus_framefmt *fmt;
struct v4l2_rect *crop, *compose;
- struct v4l2_rect vdev_compose;
int ret;
if (sdformat->pad >= CSI_NUM_PADS)
@@ -1561,19 +1556,9 @@ static int csi_set_fmt(struct v4l2_subdev *sd,
}
}
- if (sdformat->which == V4L2_SUBDEV_FORMAT_TRY)
- goto out;
-
- priv->cc[sdformat->pad] = cc;
-
- /* propagate IDMAC output pad format to capture device */
- imx_media_mbus_fmt_to_pix_fmt(&vdev_fmt, &vdev_compose,
- &priv->format_mbus[CSI_SRC_PAD_IDMAC],
- priv->cc[CSI_SRC_PAD_IDMAC]);
- mutex_unlock(&priv->lock);
- imx_media_capture_device_set_format(vdev, &vdev_fmt, &vdev_compose);
+ if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ priv->cc[sdformat->pad] = cc;
- return 0;
out:
mutex_unlock(&priv->lock);
return ret;
@@ -1765,9 +1750,6 @@ static int csi_registered(struct v4l2_subdev *sd)
int i, ret;
u32 code;
- /* get media device */
- priv->md = dev_get_drvdata(sd->v4l2_dev->dev);
-
/* get handle to IPU CSI */
csi = ipu_csi_get(priv->ipu, priv->csi_id);
if (IS_ERR(csi)) {
@@ -1815,17 +1797,12 @@ static int csi_registered(struct v4l2_subdev *sd)
if (ret)
goto free_fim;
- ret = imx_media_capture_device_register(priv->md, priv->vdev);
+ ret = imx_media_capture_device_register(priv->vdev);
if (ret)
goto free_fim;
- ret = imx_media_add_video_device(priv->md, priv->vdev);
- if (ret)
- goto unreg;
-
return 0;
-unreg:
- imx_media_capture_device_unregister(priv->vdev);
+
free_fim:
if (priv->fim)
imx_media_fim_free(priv->fim);
@@ -1986,7 +1963,7 @@ static int imx_csi_probe(struct platform_device *pdev)
imx_media_grp_id_to_sd_name(priv->sd.name, sizeof(priv->sd.name),
priv->sd.grp_id, ipu_get_num(priv->ipu));
- priv->vdev = imx_media_capture_device_init(&priv->sd,
+ priv->vdev = imx_media_capture_device_init(priv->sd.dev, &priv->sd,
CSI_SRC_PAD_IDMAC);
if (IS_ERR(priv->vdev))
return PTR_ERR(priv->vdev);
diff --git a/drivers/staging/media/imx/imx-media-dev-common.c b/drivers/staging/media/imx/imx-media-dev-common.c
index 6cd93419b81d..66b505f7e8df 100644
--- a/drivers/staging/media/imx/imx-media-dev-common.c
+++ b/drivers/staging/media/imx/imx-media-dev-common.c
@@ -8,9 +8,341 @@
#include <linux/of_graph.h>
#include <linux/of_platform.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mc.h>
#include "imx-media.h"
-static const struct v4l2_async_notifier_operations imx_media_subdev_ops = {
+static inline struct imx_media_dev *notifier2dev(struct v4l2_async_notifier *n)
+{
+ return container_of(n, struct imx_media_dev, notifier);
+}
+
+/* async subdev bound notifier */
+static int imx_media_subdev_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *sd,
+ struct v4l2_async_subdev *asd)
+{
+ v4l2_info(sd->v4l2_dev, "subdev %s bound\n", sd->name);
+
+ return 0;
+}
+
+/*
+ * Create the media links for all subdevs that registered.
+ * Called after all async subdevs have bound.
+ */
+static int imx_media_create_links(struct v4l2_async_notifier *notifier)
+{
+ struct imx_media_dev *imxmd = notifier2dev(notifier);
+ struct v4l2_subdev *sd;
+
+ list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
+ switch (sd->grp_id) {
+ case IMX_MEDIA_GRP_ID_IPU_VDIC:
+ case IMX_MEDIA_GRP_ID_IPU_IC_PRP:
+ case IMX_MEDIA_GRP_ID_IPU_IC_PRPENC:
+ case IMX_MEDIA_GRP_ID_IPU_IC_PRPVF:
+ /*
+ * links have already been created for the
+ * sync-registered subdevs.
+ */
+ break;
+ case IMX_MEDIA_GRP_ID_IPU_CSI0:
+ case IMX_MEDIA_GRP_ID_IPU_CSI1:
+ case IMX_MEDIA_GRP_ID_CSI:
+ imx_media_create_csi_of_links(imxmd, sd);
+ break;
+ default:
+ /*
+ * if this subdev has fwnode links, create media
+ * links for them.
+ */
+ imx_media_create_of_links(imxmd, sd);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * adds given video device to given imx-media source pad vdev list.
+ * Continues upstream from the pad entity's sink pads.
+ */
+static int imx_media_add_vdev_to_pad(struct imx_media_dev *imxmd,
+ struct imx_media_video_dev *vdev,
+ struct media_pad *srcpad)
+{
+ struct media_entity *entity = srcpad->entity;
+ struct imx_media_pad_vdev *pad_vdev;
+ struct list_head *pad_vdev_list;
+ struct media_link *link;
+ struct v4l2_subdev *sd;
+ int i, ret;
+
+ /* skip this entity if not a v4l2_subdev */
+ if (!is_media_entity_v4l2_subdev(entity))
+ return 0;
+
+ sd = media_entity_to_v4l2_subdev(entity);
+
+ pad_vdev_list = to_pad_vdev_list(sd, srcpad->index);
+ if (!pad_vdev_list) {
+ v4l2_warn(&imxmd->v4l2_dev, "%s:%u has no vdev list!\n",
+ entity->name, srcpad->index);
+ /*
+ * shouldn't happen, but no reason to fail driver load,
+ * just skip this entity.
+ */
+ return 0;
+ }
+
+ /* just return if we've been here before */
+ list_for_each_entry(pad_vdev, pad_vdev_list, list) {
+ if (pad_vdev->vdev == vdev)
+ return 0;
+ }
+
+ dev_dbg(imxmd->md.dev, "adding %s to pad %s:%u\n",
+ vdev->vfd->entity.name, entity->name, srcpad->index);
+
+ pad_vdev = devm_kzalloc(imxmd->md.dev, sizeof(*pad_vdev), GFP_KERNEL);
+ if (!pad_vdev)
+ return -ENOMEM;
+
+ /* attach this vdev to this pad */
+ pad_vdev->vdev = vdev;
+ list_add_tail(&pad_vdev->list, pad_vdev_list);
+
+ /* move upstream from this entity's sink pads */
+ for (i = 0; i < entity->num_pads; i++) {
+ struct media_pad *pad = &entity->pads[i];
+
+ if (!(pad->flags & MEDIA_PAD_FL_SINK))
+ continue;
+
+ list_for_each_entry(link, &entity->links, list) {
+ if (link->sink != pad)
+ continue;
+ ret = imx_media_add_vdev_to_pad(imxmd, vdev,
+ link->source);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * For every subdevice, allocate an array of list_head's, one list_head
+ * for each pad, to hold the list of video devices reachable from that
+ * pad.
+ */
+static int imx_media_alloc_pad_vdev_lists(struct imx_media_dev *imxmd)
+{
+ struct list_head *vdev_lists;
+ struct media_entity *entity;
+ struct v4l2_subdev *sd;
+ int i;
+
+ list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
+ entity = &sd->entity;
+ vdev_lists = devm_kcalloc(imxmd->md.dev,
+ entity->num_pads, sizeof(*vdev_lists),
+ GFP_KERNEL);
+ if (!vdev_lists)
+ return -ENOMEM;
+
+ /* attach to the subdev's host private pointer */
+ sd->host_priv = vdev_lists;
+
+ for (i = 0; i < entity->num_pads; i++)
+ INIT_LIST_HEAD(to_pad_vdev_list(sd, i));
+ }
+
+ return 0;
+}
+
+/* form the vdev lists in all imx-media source pads */
+static int imx_media_create_pad_vdev_lists(struct imx_media_dev *imxmd)
+{
+ struct imx_media_video_dev *vdev;
+ struct media_link *link;
+ int ret;
+
+ ret = imx_media_alloc_pad_vdev_lists(imxmd);
+ if (ret)
+ return ret;
+
+ list_for_each_entry(vdev, &imxmd->vdev_list, list) {
+ link = list_first_entry(&vdev->vfd->entity.links,
+ struct media_link, list);
+ ret = imx_media_add_vdev_to_pad(imxmd, vdev, link->source);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/* async subdev complete notifier */
+int imx_media_probe_complete(struct v4l2_async_notifier *notifier)
+{
+ struct imx_media_dev *imxmd = notifier2dev(notifier);
+ int ret;
+
+ mutex_lock(&imxmd->mutex);
+
+ ret = imx_media_create_links(notifier);
+ if (ret)
+ goto unlock;
+
+ ret = imx_media_create_pad_vdev_lists(imxmd);
+ if (ret)
+ goto unlock;
+
+ ret = v4l2_device_register_subdev_nodes(&imxmd->v4l2_dev);
+unlock:
+ mutex_unlock(&imxmd->mutex);
+ if (ret)
+ return ret;
+
+ return media_device_register(&imxmd->md);
+}
+EXPORT_SYMBOL_GPL(imx_media_probe_complete);
+
+/*
+ * adds controls to a video device from an entity subdevice.
+ * Continues upstream from the entity's sink pads.
+ */
+static int imx_media_inherit_controls(struct imx_media_dev *imxmd,
+ struct video_device *vfd,
+ struct media_entity *entity)
+{
+ int i, ret = 0;
+
+ if (is_media_entity_v4l2_subdev(entity)) {
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+
+ dev_dbg(imxmd->md.dev,
+ "adding controls to %s from %s\n",
+ vfd->entity.name, sd->entity.name);
+
+ ret = v4l2_ctrl_add_handler(vfd->ctrl_handler,
+ sd->ctrl_handler,
+ NULL, true);
+ if (ret)
+ return ret;
+ }
+
+ /* move upstream */
+ for (i = 0; i < entity->num_pads; i++) {
+ struct media_pad *pad, *spad = &entity->pads[i];
+
+ if (!(spad->flags & MEDIA_PAD_FL_SINK))
+ continue;
+
+ pad = media_entity_remote_pad(spad);
+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
+ continue;
+
+ ret = imx_media_inherit_controls(imxmd, vfd, pad->entity);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+static int imx_media_link_notify(struct media_link *link, u32 flags,
+ unsigned int notification)
+{
+ struct imx_media_dev *imxmd = container_of(link->graph_obj.mdev,
+ struct imx_media_dev, md);
+ struct media_entity *source = link->source->entity;
+ struct imx_media_pad_vdev *pad_vdev;
+ struct list_head *pad_vdev_list;
+ struct video_device *vfd;
+ struct v4l2_subdev *sd;
+ int pad_idx, ret;
+
+ ret = v4l2_pipeline_link_notify(link, flags, notification);
+ if (ret)
+ return ret;
+
+ /* don't bother if source is not a subdev */
+ if (!is_media_entity_v4l2_subdev(source))
+ return 0;
+
+ sd = media_entity_to_v4l2_subdev(source);
+ pad_idx = link->source->index;
+
+ pad_vdev_list = to_pad_vdev_list(sd, pad_idx);
+ if (!pad_vdev_list) {
+ /* nothing to do if source sd has no pad vdev list */
+ return 0;
+ }
+
+ /*
+ * Before disabling a link, reset controls for all video
+ * devices reachable from this link.
+ *
+ * After enabling a link, refresh controls for all video
+ * devices reachable from this link.
+ */
+ if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH &&
+ !(flags & MEDIA_LNK_FL_ENABLED)) {
+ list_for_each_entry(pad_vdev, pad_vdev_list, list) {
+ vfd = pad_vdev->vdev->vfd;
+ dev_dbg(imxmd->md.dev,
+ "reset controls for %s\n",
+ vfd->entity.name);
+ v4l2_ctrl_handler_free(vfd->ctrl_handler);
+ v4l2_ctrl_handler_init(vfd->ctrl_handler, 0);
+ }
+ } else if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
+ (link->flags & MEDIA_LNK_FL_ENABLED)) {
+ list_for_each_entry(pad_vdev, pad_vdev_list, list) {
+ vfd = pad_vdev->vdev->vfd;
+ dev_dbg(imxmd->md.dev,
+ "refresh controls for %s\n",
+ vfd->entity.name);
+ ret = imx_media_inherit_controls(imxmd, vfd,
+ &vfd->entity);
+ if (ret)
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static void imx_media_notify(struct v4l2_subdev *sd, unsigned int notification,
+ void *arg)
+{
+ struct media_entity *entity = &sd->entity;
+ int i;
+
+ if (notification != V4L2_DEVICE_NOTIFY_EVENT)
+ return;
+
+ for (i = 0; i < entity->num_pads; i++) {
+ struct media_pad *pad = &entity->pads[i];
+ struct imx_media_pad_vdev *pad_vdev;
+ struct list_head *pad_vdev_list;
+
+ pad_vdev_list = to_pad_vdev_list(sd, pad->index);
+ if (!pad_vdev_list)
+ continue;
+ list_for_each_entry(pad_vdev, pad_vdev_list, list)
+ v4l2_event_queue(pad_vdev->vdev->vfd, arg);
+ }
+}
+
+static const struct v4l2_async_notifier_operations imx_media_notifier_ops = {
.bound = imx_media_subdev_bound,
.complete = imx_media_probe_complete,
};
@@ -19,7 +351,8 @@ static const struct media_device_ops imx_media_md_ops = {
.link_notify = imx_media_link_notify,
};
-struct imx_media_dev *imx_media_dev_init(struct device *dev)
+struct imx_media_dev *imx_media_dev_init(struct device *dev,
+ const struct media_device_ops *ops)
{
struct imx_media_dev *imxmd;
int ret;
@@ -31,7 +364,7 @@ struct imx_media_dev *imx_media_dev_init(struct device *dev)
dev_set_drvdata(dev, imxmd);
strscpy(imxmd->md.model, "imx-media", sizeof(imxmd->md.model));
- imxmd->md.ops = &imx_media_md_ops;
+ imxmd->md.ops = ops ? ops : &imx_media_md_ops;
imxmd->md.dev = dev;
mutex_init(&imxmd->mutex);
@@ -50,8 +383,6 @@ struct imx_media_dev *imx_media_dev_init(struct device *dev)
goto cleanup;
}
- dev_set_drvdata(imxmd->v4l2_dev.dev, imxmd);
-
INIT_LIST_HEAD(&imxmd->vdev_list);
v4l2_async_notifier_init(&imxmd->notifier);
@@ -65,7 +396,8 @@ cleanup:
}
EXPORT_SYMBOL_GPL(imx_media_dev_init);
-int imx_media_dev_notifier_register(struct imx_media_dev *imxmd)
+int imx_media_dev_notifier_register(struct imx_media_dev *imxmd,
+ const struct v4l2_async_notifier_operations *ops)
{
int ret;
@@ -76,7 +408,7 @@ int imx_media_dev_notifier_register(struct imx_media_dev *imxmd)
}
/* prepare the async subdev notifier and register it */
- imxmd->notifier.ops = &imx_media_subdev_ops;
+ imxmd->notifier.ops = ops ? ops : &imx_media_notifier_ops;
ret = v4l2_async_notifier_register(&imxmd->v4l2_dev,
&imxmd->notifier);
if (ret) {
diff --git a/drivers/staging/media/imx/imx-media-dev.c b/drivers/staging/media/imx/imx-media-dev.c
index 6be95584006d..6ac371f6e971 100644
--- a/drivers/staging/media/imx/imx-media-dev.c
+++ b/drivers/staging/media/imx/imx-media-dev.c
@@ -2,24 +2,13 @@
/*
* V4L2 Media Controller Driver for Freescale i.MX5/6 SOC
*
- * Copyright (c) 2016 Mentor Graphics Inc.
+ * Copyright (c) 2016-2019 Mentor Graphics Inc.
*/
-#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/module.h>
-#include <linux/of_graph.h>
-#include <linux/of_platform.h>
-#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/timer.h>
-#include <media/v4l2-ctrls.h>
+#include <media/v4l2-async.h>
#include <media/v4l2-event.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-mc.h>
-#include <video/imx-ipu-v3.h>
#include <media/imx.h>
#include "imx-media.h"
@@ -28,433 +17,31 @@ static inline struct imx_media_dev *notifier2dev(struct v4l2_async_notifier *n)
return container_of(n, struct imx_media_dev, notifier);
}
-/*
- * Adds a subdev to the root notifier's async subdev list. If fwnode is
- * non-NULL, adds the async as a V4L2_ASYNC_MATCH_FWNODE match type,
- * otherwise as a V4L2_ASYNC_MATCH_DEVNAME match type using the dev_name
- * of the given platform_device. This is called during driver load when
- * forming the async subdev list.
- */
-int imx_media_add_async_subdev(struct imx_media_dev *imxmd,
- struct fwnode_handle *fwnode,
- struct platform_device *pdev)
-{
- struct device_node *np = to_of_node(fwnode);
- struct imx_media_async_subdev *imxasd;
- struct v4l2_async_subdev *asd;
- const char *devname = NULL;
- int ret;
-
- if (fwnode) {
- asd = v4l2_async_notifier_add_fwnode_subdev(&imxmd->notifier,
- fwnode,
- sizeof(*imxasd));
- } else {
- devname = dev_name(&pdev->dev);
- asd = v4l2_async_notifier_add_devname_subdev(&imxmd->notifier,
- devname,
- sizeof(*imxasd));
- }
-
- if (IS_ERR(asd)) {
- ret = PTR_ERR(asd);
- if (ret == -EEXIST) {
- if (np)
- dev_dbg(imxmd->md.dev, "%s: already added %pOFn\n",
- __func__, np);
- else
- dev_dbg(imxmd->md.dev, "%s: already added %s\n",
- __func__, devname);
- }
- return ret;
- }
-
- imxasd = to_imx_media_asd(asd);
-
- if (devname)
- imxasd->pdev = pdev;
-
- if (np)
- dev_dbg(imxmd->md.dev, "%s: added %pOFn, match type FWNODE\n",
- __func__, np);
- else
- dev_dbg(imxmd->md.dev, "%s: added %s, match type DEVNAME\n",
- __func__, devname);
-
- return 0;
-}
-
-/*
- * get IPU from this CSI and add it to the list of IPUs
- * the media driver will control.
- */
-static int imx_media_get_ipu(struct imx_media_dev *imxmd,
- struct v4l2_subdev *csi_sd)
-{
- struct ipu_soc *ipu;
- int ipu_id;
-
- ipu = dev_get_drvdata(csi_sd->dev->parent);
- if (!ipu) {
- v4l2_err(&imxmd->v4l2_dev,
- "CSI %s has no parent IPU!\n", csi_sd->name);
- return -ENODEV;
- }
-
- ipu_id = ipu_get_num(ipu);
- if (ipu_id > 1) {
- v4l2_err(&imxmd->v4l2_dev, "invalid IPU id %d!\n", ipu_id);
- return -ENODEV;
- }
-
- if (!imxmd->ipu[ipu_id])
- imxmd->ipu[ipu_id] = ipu;
-
- return 0;
-}
-
/* async subdev bound notifier */
-int imx_media_subdev_bound(struct v4l2_async_notifier *notifier,
- struct v4l2_subdev *sd,
- struct v4l2_async_subdev *asd)
+static int imx_media_subdev_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *sd,
+ struct v4l2_async_subdev *asd)
{
struct imx_media_dev *imxmd = notifier2dev(notifier);
- int ret = 0;
-
- mutex_lock(&imxmd->mutex);
+ int ret;
if (sd->grp_id & IMX_MEDIA_GRP_ID_IPU_CSI) {
- ret = imx_media_get_ipu(imxmd, sd);
+ /* register the IPU internal subdevs */
+ ret = imx_media_register_ipu_internal_subdevs(imxmd, sd);
if (ret)
- goto out;
+ return ret;
}
v4l2_info(&imxmd->v4l2_dev, "subdev %s bound\n", sd->name);
-out:
- mutex_unlock(&imxmd->mutex);
- return ret;
-}
-
-/*
- * Create the media links for all subdevs that registered.
- * Called after all async subdevs have bound.
- */
-static int imx_media_create_links(struct v4l2_async_notifier *notifier)
-{
- struct imx_media_dev *imxmd = notifier2dev(notifier);
- struct v4l2_subdev *sd;
- int ret;
-
- list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
- switch (sd->grp_id) {
- case IMX_MEDIA_GRP_ID_IPU_VDIC:
- case IMX_MEDIA_GRP_ID_IPU_IC_PRP:
- case IMX_MEDIA_GRP_ID_IPU_IC_PRPENC:
- case IMX_MEDIA_GRP_ID_IPU_IC_PRPVF:
- case IMX_MEDIA_GRP_ID_IPU_CSI0:
- case IMX_MEDIA_GRP_ID_IPU_CSI1:
- ret = imx_media_create_ipu_internal_links(imxmd, sd);
- if (ret)
- return ret;
- /*
- * the CSIs straddle between the external and the IPU
- * internal entities, so create the external links
- * to the CSI sink pads.
- */
- if (sd->grp_id & IMX_MEDIA_GRP_ID_IPU_CSI)
- imx_media_create_csi_of_links(imxmd, sd);
- break;
- case IMX_MEDIA_GRP_ID_CSI:
- imx_media_create_csi_of_links(imxmd, sd);
-
- break;
- default:
- /*
- * if this subdev has fwnode links, create media
- * links for them.
- */
- imx_media_create_of_links(imxmd, sd);
- break;
- }
- }
-
- return 0;
-}
-
-/*
- * adds given video device to given imx-media source pad vdev list.
- * Continues upstream from the pad entity's sink pads.
- */
-static int imx_media_add_vdev_to_pad(struct imx_media_dev *imxmd,
- struct imx_media_video_dev *vdev,
- struct media_pad *srcpad)
-{
- struct media_entity *entity = srcpad->entity;
- struct imx_media_pad_vdev *pad_vdev;
- struct list_head *pad_vdev_list;
- struct media_link *link;
- struct v4l2_subdev *sd;
- int i, ret;
-
- /* skip this entity if not a v4l2_subdev */
- if (!is_media_entity_v4l2_subdev(entity))
- return 0;
-
- sd = media_entity_to_v4l2_subdev(entity);
-
- pad_vdev_list = to_pad_vdev_list(sd, srcpad->index);
- if (!pad_vdev_list) {
- v4l2_warn(&imxmd->v4l2_dev, "%s:%u has no vdev list!\n",
- entity->name, srcpad->index);
- /*
- * shouldn't happen, but no reason to fail driver load,
- * just skip this entity.
- */
- return 0;
- }
-
- /* just return if we've been here before */
- list_for_each_entry(pad_vdev, pad_vdev_list, list) {
- if (pad_vdev->vdev == vdev)
- return 0;
- }
-
- dev_dbg(imxmd->md.dev, "adding %s to pad %s:%u\n",
- vdev->vfd->entity.name, entity->name, srcpad->index);
-
- pad_vdev = devm_kzalloc(imxmd->md.dev, sizeof(*pad_vdev), GFP_KERNEL);
- if (!pad_vdev)
- return -ENOMEM;
-
- /* attach this vdev to this pad */
- pad_vdev->vdev = vdev;
- list_add_tail(&pad_vdev->list, pad_vdev_list);
-
- /* move upstream from this entity's sink pads */
- for (i = 0; i < entity->num_pads; i++) {
- struct media_pad *pad = &entity->pads[i];
-
- if (!(pad->flags & MEDIA_PAD_FL_SINK))
- continue;
-
- list_for_each_entry(link, &entity->links, list) {
- if (link->sink != pad)
- continue;
- ret = imx_media_add_vdev_to_pad(imxmd, vdev,
- link->source);
- if (ret)
- return ret;
- }
- }
-
- return 0;
-}
-
-/*
- * For every subdevice, allocate an array of list_head's, one list_head
- * for each pad, to hold the list of video devices reachable from that
- * pad.
- */
-static int imx_media_alloc_pad_vdev_lists(struct imx_media_dev *imxmd)
-{
- struct list_head *vdev_lists;
- struct media_entity *entity;
- struct v4l2_subdev *sd;
- int i;
-
- list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
- entity = &sd->entity;
- vdev_lists = devm_kcalloc(imxmd->md.dev,
- entity->num_pads, sizeof(*vdev_lists),
- GFP_KERNEL);
- if (!vdev_lists)
- return -ENOMEM;
-
- /* attach to the subdev's host private pointer */
- sd->host_priv = vdev_lists;
-
- for (i = 0; i < entity->num_pads; i++)
- INIT_LIST_HEAD(to_pad_vdev_list(sd, i));
- }
-
- return 0;
-}
-
-/* form the vdev lists in all imx-media source pads */
-static int imx_media_create_pad_vdev_lists(struct imx_media_dev *imxmd)
-{
- struct imx_media_video_dev *vdev;
- struct media_link *link;
- int ret;
-
- ret = imx_media_alloc_pad_vdev_lists(imxmd);
- if (ret)
- return ret;
-
- list_for_each_entry(vdev, &imxmd->vdev_list, list) {
- link = list_first_entry(&vdev->vfd->entity.links,
- struct media_link, list);
- ret = imx_media_add_vdev_to_pad(imxmd, vdev, link->source);
- if (ret)
- return ret;
- }
return 0;
}
/* async subdev complete notifier */
-int imx_media_probe_complete(struct v4l2_async_notifier *notifier)
-{
- struct imx_media_dev *imxmd = notifier2dev(notifier);
- int ret;
-
- mutex_lock(&imxmd->mutex);
-
- ret = imx_media_create_links(notifier);
- if (ret)
- goto unlock;
-
- ret = imx_media_create_pad_vdev_lists(imxmd);
- if (ret)
- goto unlock;
-
- ret = v4l2_device_register_subdev_nodes(&imxmd->v4l2_dev);
-unlock:
- mutex_unlock(&imxmd->mutex);
- if (ret)
- return ret;
-
- return media_device_register(&imxmd->md);
-}
-
-/*
- * adds controls to a video device from an entity subdevice.
- * Continues upstream from the entity's sink pads.
- */
-static int imx_media_inherit_controls(struct imx_media_dev *imxmd,
- struct video_device *vfd,
- struct media_entity *entity)
-{
- int i, ret = 0;
-
- if (is_media_entity_v4l2_subdev(entity)) {
- struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
-
- dev_dbg(imxmd->md.dev,
- "adding controls to %s from %s\n",
- vfd->entity.name, sd->entity.name);
-
- ret = v4l2_ctrl_add_handler(vfd->ctrl_handler,
- sd->ctrl_handler,
- NULL, true);
- if (ret)
- return ret;
- }
-
- /* move upstream */
- for (i = 0; i < entity->num_pads; i++) {
- struct media_pad *pad, *spad = &entity->pads[i];
-
- if (!(spad->flags & MEDIA_PAD_FL_SINK))
- continue;
-
- pad = media_entity_remote_pad(spad);
- if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
- continue;
-
- ret = imx_media_inherit_controls(imxmd, vfd, pad->entity);
- if (ret)
- break;
- }
-
- return ret;
-}
-
-int imx_media_link_notify(struct media_link *link, u32 flags,
- unsigned int notification)
-{
- struct media_entity *source = link->source->entity;
- struct imx_media_pad_vdev *pad_vdev;
- struct list_head *pad_vdev_list;
- struct imx_media_dev *imxmd;
- struct video_device *vfd;
- struct v4l2_subdev *sd;
- int pad_idx, ret;
-
- ret = v4l2_pipeline_link_notify(link, flags, notification);
- if (ret)
- return ret;
-
- /* don't bother if source is not a subdev */
- if (!is_media_entity_v4l2_subdev(source))
- return 0;
-
- sd = media_entity_to_v4l2_subdev(source);
- pad_idx = link->source->index;
-
- imxmd = dev_get_drvdata(sd->v4l2_dev->dev);
-
- pad_vdev_list = to_pad_vdev_list(sd, pad_idx);
- if (!pad_vdev_list) {
- /* shouldn't happen, but no reason to fail link setup */
- return 0;
- }
-
- /*
- * Before disabling a link, reset controls for all video
- * devices reachable from this link.
- *
- * After enabling a link, refresh controls for all video
- * devices reachable from this link.
- */
- if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH &&
- !(flags & MEDIA_LNK_FL_ENABLED)) {
- list_for_each_entry(pad_vdev, pad_vdev_list, list) {
- vfd = pad_vdev->vdev->vfd;
- dev_dbg(imxmd->md.dev,
- "reset controls for %s\n",
- vfd->entity.name);
- v4l2_ctrl_handler_free(vfd->ctrl_handler);
- v4l2_ctrl_handler_init(vfd->ctrl_handler, 0);
- }
- } else if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
- (link->flags & MEDIA_LNK_FL_ENABLED)) {
- list_for_each_entry(pad_vdev, pad_vdev_list, list) {
- vfd = pad_vdev->vdev->vfd;
- dev_dbg(imxmd->md.dev,
- "refresh controls for %s\n",
- vfd->entity.name);
- ret = imx_media_inherit_controls(imxmd, vfd,
- &vfd->entity);
- if (ret)
- break;
- }
- }
-
- return ret;
-}
-
-void imx_media_notify(struct v4l2_subdev *sd, unsigned int notification,
- void *arg)
-{
- struct media_entity *entity = &sd->entity;
- int i;
-
- if (notification != V4L2_DEVICE_NOTIFY_EVENT)
- return;
-
- for (i = 0; i < entity->num_pads; i++) {
- struct media_pad *pad = &entity->pads[i];
- struct imx_media_pad_vdev *pad_vdev;
- struct list_head *pad_vdev_list;
-
- pad_vdev_list = to_pad_vdev_list(sd, pad->index);
- if (!pad_vdev_list)
- continue;
- list_for_each_entry(pad_vdev, pad_vdev_list, list)
- v4l2_event_queue(pad_vdev->vdev->vfd, arg);
- }
-}
+static const struct v4l2_async_notifier_operations imx_media_notifier_ops = {
+ .bound = imx_media_subdev_bound,
+ .complete = imx_media_probe_complete,
+};
static int imx_media_probe(struct platform_device *pdev)
{
@@ -463,7 +50,7 @@ static int imx_media_probe(struct platform_device *pdev)
struct imx_media_dev *imxmd;
int ret;
- imxmd = imx_media_dev_init(dev);
+ imxmd = imx_media_dev_init(dev, NULL);
if (IS_ERR(imxmd))
return PTR_ERR(imxmd);
@@ -474,14 +61,12 @@ static int imx_media_probe(struct platform_device *pdev)
goto cleanup;
}
- ret = imx_media_dev_notifier_register(imxmd);
+ ret = imx_media_dev_notifier_register(imxmd, &imx_media_notifier_ops);
if (ret)
- goto del_int;
+ goto cleanup;
return 0;
-del_int:
- imx_media_remove_ipu_internal_subdevs(imxmd);
cleanup:
v4l2_async_notifier_cleanup(&imxmd->notifier);
v4l2_device_unregister(&imxmd->v4l2_dev);
@@ -498,7 +83,7 @@ static int imx_media_remove(struct platform_device *pdev)
v4l2_info(&imxmd->v4l2_dev, "Removing imx-media\n");
v4l2_async_notifier_unregister(&imxmd->notifier);
- imx_media_remove_ipu_internal_subdevs(imxmd);
+ imx_media_unregister_ipu_internal_subdevs(imxmd);
v4l2_async_notifier_cleanup(&imxmd->notifier);
media_device_unregister(&imxmd->md);
v4l2_device_unregister(&imxmd->v4l2_dev);
diff --git a/drivers/staging/media/imx/imx-media-fim.c b/drivers/staging/media/imx/imx-media-fim.c
index 2ab64bc30f5c..3a9182933508 100644
--- a/drivers/staging/media/imx/imx-media-fim.c
+++ b/drivers/staging/media/imx/imx-media-fim.c
@@ -37,8 +37,6 @@ enum {
#define FIM_CL_TOLERANCE_MAX_DEF 0 /* no max tolerance (unbounded) */
struct imx_media_fim {
- struct imx_media_dev *md;
-
/* the owning subdev of this fim instance */
struct v4l2_subdev *sd;
@@ -416,7 +414,6 @@ void imx_media_fim_eof_monitor(struct imx_media_fim *fim, ktime_t timestamp)
spin_unlock_irqrestore(&fim->lock, flags);
}
-EXPORT_SYMBOL_GPL(imx_media_fim_eof_monitor);
/* Called by the subdev in its s_stream callback */
int imx_media_fim_set_stream(struct imx_media_fim *fim,
@@ -453,7 +450,6 @@ out:
v4l2_ctrl_unlock(fim->ctrl[FIM_CL_ENABLE]);
return ret;
}
-EXPORT_SYMBOL_GPL(imx_media_fim_set_stream);
int imx_media_fim_add_controls(struct imx_media_fim *fim)
{
@@ -461,7 +457,6 @@ int imx_media_fim_add_controls(struct imx_media_fim *fim)
return v4l2_ctrl_add_handler(fim->sd->ctrl_handler,
&fim->ctrl_handler, NULL, false);
}
-EXPORT_SYMBOL_GPL(imx_media_fim_add_controls);
/* Called by the subdev in its subdev registered callback */
struct imx_media_fim *imx_media_fim_init(struct v4l2_subdev *sd)
@@ -473,8 +468,6 @@ struct imx_media_fim *imx_media_fim_init(struct v4l2_subdev *sd)
if (!fim)
return ERR_PTR(-ENOMEM);
- /* get media device */
- fim->md = dev_get_drvdata(sd->v4l2_dev->dev);
fim->sd = sd;
spin_lock_init(&fim->lock);
@@ -485,10 +478,8 @@ struct imx_media_fim *imx_media_fim_init(struct v4l2_subdev *sd)
return fim;
}
-EXPORT_SYMBOL_GPL(imx_media_fim_init);
void imx_media_fim_free(struct imx_media_fim *fim)
{
v4l2_ctrl_handler_free(&fim->ctrl_handler);
}
-EXPORT_SYMBOL_GPL(imx_media_fim_free);
diff --git a/drivers/staging/media/imx/imx-media-internal-sd.c b/drivers/staging/media/imx/imx-media-internal-sd.c
index df49ebfbe98a..cb1e4cdd5079 100644
--- a/drivers/staging/media/imx/imx-media-internal-sd.c
+++ b/drivers/staging/media/imx/imx-media-internal-sd.c
@@ -9,208 +9,138 @@
#include <linux/platform_device.h>
#include "imx-media.h"
-enum isd_enum {
- isd_csi0 = 0,
- isd_csi1,
- isd_vdic,
- isd_ic_prp,
- isd_ic_prpenc,
- isd_ic_prpvf,
- num_isd,
-};
-
-static const struct internal_subdev_id {
- enum isd_enum index;
- const char *name;
- u32 grp_id;
-} isd_id[num_isd] = {
- [isd_csi0] = {
- .index = isd_csi0,
- .grp_id = IMX_MEDIA_GRP_ID_IPU_CSI0,
- .name = "imx-ipuv3-csi",
- },
- [isd_csi1] = {
- .index = isd_csi1,
- .grp_id = IMX_MEDIA_GRP_ID_IPU_CSI1,
- .name = "imx-ipuv3-csi",
- },
- [isd_vdic] = {
- .index = isd_vdic,
- .grp_id = IMX_MEDIA_GRP_ID_IPU_VDIC,
- .name = "imx-ipuv3-vdic",
- },
- [isd_ic_prp] = {
- .index = isd_ic_prp,
- .grp_id = IMX_MEDIA_GRP_ID_IPU_IC_PRP,
- .name = "imx-ipuv3-ic",
- },
- [isd_ic_prpenc] = {
- .index = isd_ic_prpenc,
- .grp_id = IMX_MEDIA_GRP_ID_IPU_IC_PRPENC,
- .name = "imx-ipuv3-ic",
- },
- [isd_ic_prpvf] = {
- .index = isd_ic_prpvf,
- .grp_id = IMX_MEDIA_GRP_ID_IPU_IC_PRPVF,
- .name = "imx-ipuv3-ic",
- },
-};
+/* max pads per internal-sd */
+#define MAX_INTERNAL_PADS 8
+/* max links per internal-sd pad */
+#define MAX_INTERNAL_LINKS 8
struct internal_subdev;
struct internal_link {
- const struct internal_subdev *remote;
+ int remote;
int local_pad;
int remote_pad;
};
-/* max pads per internal-sd */
-#define MAX_INTERNAL_PADS 8
-/* max links per internal-sd pad */
-#define MAX_INTERNAL_LINKS 8
-
struct internal_pad {
+ int num_links;
struct internal_link link[MAX_INTERNAL_LINKS];
};
-static const struct internal_subdev {
- const struct internal_subdev_id *id;
+struct internal_subdev {
+ u32 grp_id;
struct internal_pad pad[MAX_INTERNAL_PADS];
-} int_subdev[num_isd] = {
- [isd_csi0] = {
- .id = &isd_id[isd_csi0],
+
+ struct v4l2_subdev * (*sync_register)(struct v4l2_device *v4l2_dev,
+ struct device *ipu_dev,
+ struct ipu_soc *ipu,
+ u32 grp_id);
+ int (*sync_unregister)(struct v4l2_subdev *sd);
+};
+
+static const struct internal_subdev int_subdev[NUM_IPU_SUBDEVS] = {
+ [IPU_CSI0] = {
+ .grp_id = IMX_MEDIA_GRP_ID_IPU_CSI0,
.pad[CSI_SRC_PAD_DIRECT] = {
+ .num_links = 2,
.link = {
{
.local_pad = CSI_SRC_PAD_DIRECT,
- .remote = &int_subdev[isd_ic_prp],
+ .remote = IPU_IC_PRP,
.remote_pad = PRP_SINK_PAD,
}, {
.local_pad = CSI_SRC_PAD_DIRECT,
- .remote = &int_subdev[isd_vdic],
+ .remote = IPU_VDIC,
.remote_pad = VDIC_SINK_PAD_DIRECT,
},
},
},
},
- [isd_csi1] = {
- .id = &isd_id[isd_csi1],
+ [IPU_CSI1] = {
+ .grp_id = IMX_MEDIA_GRP_ID_IPU_CSI1,
.pad[CSI_SRC_PAD_DIRECT] = {
+ .num_links = 2,
.link = {
{
.local_pad = CSI_SRC_PAD_DIRECT,
- .remote = &int_subdev[isd_ic_prp],
+ .remote = IPU_IC_PRP,
.remote_pad = PRP_SINK_PAD,
}, {
.local_pad = CSI_SRC_PAD_DIRECT,
- .remote = &int_subdev[isd_vdic],
+ .remote = IPU_VDIC,
.remote_pad = VDIC_SINK_PAD_DIRECT,
},
},
},
},
- [isd_vdic] = {
- .id = &isd_id[isd_vdic],
+ [IPU_VDIC] = {
+ .grp_id = IMX_MEDIA_GRP_ID_IPU_VDIC,
+ .sync_register = imx_media_vdic_register,
+ .sync_unregister = imx_media_vdic_unregister,
.pad[VDIC_SRC_PAD_DIRECT] = {
+ .num_links = 1,
.link = {
{
.local_pad = VDIC_SRC_PAD_DIRECT,
- .remote = &int_subdev[isd_ic_prp],
+ .remote = IPU_IC_PRP,
.remote_pad = PRP_SINK_PAD,
},
},
},
},
- [isd_ic_prp] = {
- .id = &isd_id[isd_ic_prp],
+ [IPU_IC_PRP] = {
+ .grp_id = IMX_MEDIA_GRP_ID_IPU_IC_PRP,
+ .sync_register = imx_media_ic_register,
+ .sync_unregister = imx_media_ic_unregister,
.pad[PRP_SRC_PAD_PRPENC] = {
+ .num_links = 1,
.link = {
{
.local_pad = PRP_SRC_PAD_PRPENC,
- .remote = &int_subdev[isd_ic_prpenc],
- .remote_pad = 0,
+ .remote = IPU_IC_PRPENC,
+ .remote_pad = PRPENCVF_SINK_PAD,
},
},
},
.pad[PRP_SRC_PAD_PRPVF] = {
+ .num_links = 1,
.link = {
{
.local_pad = PRP_SRC_PAD_PRPVF,
- .remote = &int_subdev[isd_ic_prpvf],
- .remote_pad = 0,
+ .remote = IPU_IC_PRPVF,
+ .remote_pad = PRPENCVF_SINK_PAD,
},
},
},
},
- [isd_ic_prpenc] = {
- .id = &isd_id[isd_ic_prpenc],
+ [IPU_IC_PRPENC] = {
+ .grp_id = IMX_MEDIA_GRP_ID_IPU_IC_PRPENC,
+ .sync_register = imx_media_ic_register,
+ .sync_unregister = imx_media_ic_unregister,
},
- [isd_ic_prpvf] = {
- .id = &isd_id[isd_ic_prpvf],
+ [IPU_IC_PRPVF] = {
+ .grp_id = IMX_MEDIA_GRP_ID_IPU_IC_PRPVF,
+ .sync_register = imx_media_ic_register,
+ .sync_unregister = imx_media_ic_unregister,
},
};
-/* form a device name given an internal subdev and ipu id */
-static inline void isd_to_devname(char *devname, int sz,
- const struct internal_subdev *isd,
- int ipu_id)
-{
- int pdev_id = ipu_id * num_isd + isd->id->index;
-
- snprintf(devname, sz, "%s.%d", isd->id->name, pdev_id);
-}
-
-static const struct internal_subdev *find_intsd_by_grp_id(u32 grp_id)
-{
- enum isd_enum i;
-
- for (i = 0; i < num_isd; i++) {
- const struct internal_subdev *isd = &int_subdev[i];
-
- if (isd->id->grp_id == grp_id)
- return isd;
- }
-
- return NULL;
-}
-
-static struct v4l2_subdev *find_sink(struct imx_media_dev *imxmd,
- struct v4l2_subdev *src,
- const struct internal_link *link)
-{
- char sink_devname[32];
- int ipu_id;
-
- /*
- * retrieve IPU id from subdev name, note: can't get this from
- * struct imx_media_ipu_internal_sd_pdata because if src is
- * a CSI, it has different struct ipu_client_platformdata which
- * does not contain IPU id.
- */
- if (sscanf(src->name, "ipu%d", &ipu_id) != 1)
- return NULL;
-
- isd_to_devname(sink_devname, sizeof(sink_devname),
- link->remote, ipu_id - 1);
-
- return imx_media_find_subdev_by_devname(imxmd, sink_devname);
-}
-
-static int create_ipu_internal_link(struct imx_media_dev *imxmd,
- struct v4l2_subdev *src,
- const struct internal_link *link)
+static int create_internal_link(struct imx_media_dev *imxmd,
+ struct v4l2_subdev *src,
+ struct v4l2_subdev *sink,
+ const struct internal_link *link)
{
- struct v4l2_subdev *sink;
int ret;
- sink = find_sink(imxmd, src, link);
- if (!sink)
- return -ENODEV;
+ /* skip if this link already created */
+ if (media_entity_find_link(&src->entity.pads[link->local_pad],
+ &sink->entity.pads[link->remote_pad]))
+ return 0;
v4l2_info(&imxmd->v4l2_dev, "%s:%d -> %s:%d\n",
src->name, link->local_pad,
@@ -219,25 +149,21 @@ static int create_ipu_internal_link(struct imx_media_dev *imxmd,
ret = media_create_pad_link(&src->entity, link->local_pad,
&sink->entity, link->remote_pad, 0);
if (ret)
- v4l2_err(&imxmd->v4l2_dev,
- "create_pad_link failed: %d\n", ret);
+ v4l2_err(&imxmd->v4l2_dev, "%s failed: %d\n", __func__, ret);
return ret;
}
-int imx_media_create_ipu_internal_links(struct imx_media_dev *imxmd,
- struct v4l2_subdev *sd)
+static int create_ipu_internal_links(struct imx_media_dev *imxmd,
+ const struct internal_subdev *intsd,
+ struct v4l2_subdev *sd,
+ int ipu_id)
{
- const struct internal_subdev *intsd;
const struct internal_pad *intpad;
const struct internal_link *link;
struct media_pad *pad;
int i, j, ret;
- intsd = find_intsd_by_grp_id(sd->grp_id);
- if (!intsd)
- return -ENODEV;
-
/* create the source->sink links */
for (i = 0; i < sd->entity.num_pads; i++) {
intpad = &intsd->pad[i];
@@ -246,13 +172,13 @@ int imx_media_create_ipu_internal_links(struct imx_media_dev *imxmd,
if (!(pad->flags & MEDIA_PAD_FL_SOURCE))
continue;
- for (j = 0; ; j++) {
- link = &intpad->link[j];
+ for (j = 0; j < intpad->num_links; j++) {
+ struct v4l2_subdev *sink;
- if (!link->remote)
- break;
+ link = &intpad->link[j];
+ sink = imxmd->sync_sd[ipu_id][link->remote];
- ret = create_ipu_internal_link(imxmd, sd, link);
+ ret = create_internal_link(imxmd, sd, sink, link);
if (ret)
return ret;
}
@@ -261,85 +187,116 @@ int imx_media_create_ipu_internal_links(struct imx_media_dev *imxmd,
return 0;
}
-/* register an internal subdev as a platform device */
-static int add_internal_subdev(struct imx_media_dev *imxmd,
- const struct internal_subdev *isd,
- int ipu_id)
+int imx_media_register_ipu_internal_subdevs(struct imx_media_dev *imxmd,
+ struct v4l2_subdev *csi)
{
- struct imx_media_ipu_internal_sd_pdata pdata;
- struct platform_device_info pdevinfo = {};
- struct platform_device *pdev;
+ struct device *ipu_dev = csi->dev->parent;
+ const struct internal_subdev *intsd;
+ struct v4l2_subdev *sd;
+ struct ipu_soc *ipu;
+ int i, ipu_id, ret;
- pdata.grp_id = isd->id->grp_id;
+ ipu = dev_get_drvdata(ipu_dev);
+ if (!ipu) {
+ v4l2_err(&imxmd->v4l2_dev, "invalid IPU device!\n");
+ return -ENODEV;
+ }
- /* the id of IPU this subdev will control */
- pdata.ipu_id = ipu_id;
+ ipu_id = ipu_get_num(ipu);
+ if (ipu_id > 1) {
+ v4l2_err(&imxmd->v4l2_dev, "invalid IPU id %d!\n", ipu_id);
+ return -ENODEV;
+ }
- /* create subdev name */
- imx_media_grp_id_to_sd_name(pdata.sd_name, sizeof(pdata.sd_name),
- pdata.grp_id, ipu_id);
+ mutex_lock(&imxmd->mutex);
- pdevinfo.name = isd->id->name;
- pdevinfo.id = ipu_id * num_isd + isd->id->index;
- pdevinfo.parent = imxmd->md.dev;
- pdevinfo.data = &pdata;
- pdevinfo.size_data = sizeof(pdata);
- pdevinfo.dma_mask = DMA_BIT_MASK(32);
+ /* register the synchronous subdevs */
+ for (i = 0; i < NUM_IPU_SUBDEVS; i++) {
+ intsd = &int_subdev[i];
- pdev = platform_device_register_full(&pdevinfo);
- if (IS_ERR(pdev))
- return PTR_ERR(pdev);
+ sd = imxmd->sync_sd[ipu_id][i];
- return imx_media_add_async_subdev(imxmd, NULL, pdev);
-}
+ /*
+ * skip if this sync subdev already registered or its
+ * not a sync subdev (one of the CSIs)
+ */
+ if (sd || !intsd->sync_register)
+ continue;
-/* adds the internal subdevs in one ipu */
-int imx_media_add_ipu_internal_subdevs(struct imx_media_dev *imxmd,
- int ipu_id)
-{
- enum isd_enum i;
- int ret;
+ mutex_unlock(&imxmd->mutex);
+ sd = intsd->sync_register(&imxmd->v4l2_dev, ipu_dev, ipu,
+ intsd->grp_id);
+ mutex_lock(&imxmd->mutex);
+ if (IS_ERR(sd)) {
+ ret = PTR_ERR(sd);
+ goto err_unwind;
+ }
- for (i = 0; i < num_isd; i++) {
- const struct internal_subdev *isd = &int_subdev[i];
+ imxmd->sync_sd[ipu_id][i] = sd;
+ }
- /*
- * the CSIs are represented in the device-tree, so those
- * devices are already added to the async subdev list by
- * of_parse_subdev().
- */
- switch (isd->id->grp_id) {
- case IMX_MEDIA_GRP_ID_IPU_CSI0:
- case IMX_MEDIA_GRP_ID_IPU_CSI1:
- ret = 0;
- break;
- default:
- ret = add_internal_subdev(imxmd, isd, ipu_id);
- break;
+ /*
+ * all the sync subdevs are registered, create the media links
+ * between them.
+ */
+ for (i = 0; i < NUM_IPU_SUBDEVS; i++) {
+ intsd = &int_subdev[i];
+
+ if (intsd->grp_id == csi->grp_id) {
+ sd = csi;
+ } else {
+ sd = imxmd->sync_sd[ipu_id][i];
+ if (!sd)
+ continue;
}
- if (ret)
- goto remove;
+ ret = create_ipu_internal_links(imxmd, intsd, sd, ipu_id);
+ if (ret) {
+ mutex_unlock(&imxmd->mutex);
+ imx_media_unregister_ipu_internal_subdevs(imxmd);
+ return ret;
+ }
}
+ mutex_unlock(&imxmd->mutex);
return 0;
-remove:
- imx_media_remove_ipu_internal_subdevs(imxmd);
+err_unwind:
+ while (--i >= 0) {
+ intsd = &int_subdev[i];
+ sd = imxmd->sync_sd[ipu_id][i];
+ if (!sd || !intsd->sync_unregister)
+ continue;
+ mutex_unlock(&imxmd->mutex);
+ intsd->sync_unregister(sd);
+ mutex_lock(&imxmd->mutex);
+ }
+
+ mutex_unlock(&imxmd->mutex);
return ret;
}
-void imx_media_remove_ipu_internal_subdevs(struct imx_media_dev *imxmd)
+void imx_media_unregister_ipu_internal_subdevs(struct imx_media_dev *imxmd)
{
- struct imx_media_async_subdev *imxasd;
- struct v4l2_async_subdev *asd;
+ const struct internal_subdev *intsd;
+ struct v4l2_subdev *sd;
+ int i, j;
- list_for_each_entry(asd, &imxmd->notifier.asd_list, asd_list) {
- imxasd = to_imx_media_asd(asd);
+ mutex_lock(&imxmd->mutex);
- if (!imxasd->pdev)
- continue;
+ for (i = 0; i < 2; i++) {
+ for (j = 0; j < NUM_IPU_SUBDEVS; j++) {
+ intsd = &int_subdev[j];
+ sd = imxmd->sync_sd[i][j];
+
+ if (!sd || !intsd->sync_unregister)
+ continue;
- platform_device_unregister(imxasd->pdev);
+ mutex_unlock(&imxmd->mutex);
+ intsd->sync_unregister(sd);
+ mutex_lock(&imxmd->mutex);
+ }
}
+
+ mutex_unlock(&imxmd->mutex);
}
diff --git a/drivers/staging/media/imx/imx-media-of.c b/drivers/staging/media/imx/imx-media-of.c
index 990e82aa8e42..2d3efd2a6dde 100644
--- a/drivers/staging/media/imx/imx-media-of.c
+++ b/drivers/staging/media/imx/imx-media-of.c
@@ -19,6 +19,9 @@
int imx_media_of_add_csi(struct imx_media_dev *imxmd,
struct device_node *csi_np)
{
+ struct v4l2_async_subdev *asd;
+ int ret = 0;
+
if (!of_device_is_available(csi_np)) {
dev_dbg(imxmd->md.dev, "%s: %pOFn not enabled\n", __func__,
csi_np);
@@ -26,18 +29,25 @@ int imx_media_of_add_csi(struct imx_media_dev *imxmd,
}
/* add CSI fwnode to async notifier */
- return imx_media_add_async_subdev(imxmd, of_fwnode_handle(csi_np),
- NULL);
+ asd = v4l2_async_notifier_add_fwnode_subdev(&imxmd->notifier,
+ of_fwnode_handle(csi_np),
+ sizeof(*asd));
+ if (IS_ERR(asd)) {
+ ret = PTR_ERR(asd);
+ if (ret == -EEXIST)
+ dev_dbg(imxmd->md.dev, "%s: already added %pOFn\n",
+ __func__, csi_np);
+ }
+
+ return ret;
}
EXPORT_SYMBOL_GPL(imx_media_of_add_csi);
int imx_media_add_of_subdevs(struct imx_media_dev *imxmd,
struct device_node *np)
{
- bool ipu_found[2] = {false, false};
struct device_node *csi_np;
int i, ret;
- u32 ipu_id;
for (i = 0; ; i++) {
csi_np = of_parse_phandle(np, "ports", i);
@@ -55,34 +65,15 @@ int imx_media_add_of_subdevs(struct imx_media_dev *imxmd,
/* other error, can't continue */
goto err_out;
}
-
- ret = of_alias_get_id(csi_np->parent, "ipu");
- if (ret < 0)
- goto err_out;
- if (ret > 1) {
- ret = -EINVAL;
- goto err_out;
- }
-
- ipu_id = ret;
-
- if (!ipu_found[ipu_id]) {
- ret = imx_media_add_ipu_internal_subdevs(imxmd,
- ipu_id);
- if (ret)
- goto err_out;
- }
-
- ipu_found[ipu_id] = true;
}
return 0;
err_out:
- imx_media_remove_ipu_internal_subdevs(imxmd);
of_node_put(csi_np);
return ret;
}
+EXPORT_SYMBOL_GPL(imx_media_add_of_subdevs);
/*
* Create a single media link to/from sd using a fwnode link.
@@ -152,6 +143,7 @@ int imx_media_create_of_links(struct imx_media_dev *imxmd,
return 0;
}
+EXPORT_SYMBOL_GPL(imx_media_create_of_links);
/*
* Create media links to the given CSI subdevice's sink pads,
@@ -195,3 +187,4 @@ int imx_media_create_csi_of_links(struct imx_media_dev *imxmd,
return 0;
}
+EXPORT_SYMBOL_GPL(imx_media_create_csi_of_links);
diff --git a/drivers/staging/media/imx/imx-media-utils.c b/drivers/staging/media/imx/imx-media-utils.c
index 05b63395084e..9088c4b720a3 100644
--- a/drivers/staging/media/imx/imx-media-utils.c
+++ b/drivers/staging/media/imx/imx-media-utils.c
@@ -572,8 +572,7 @@ void imx_media_try_colorimetry(struct v4l2_mbus_framefmt *tryfmt,
EXPORT_SYMBOL_GPL(imx_media_try_colorimetry);
int imx_media_mbus_fmt_to_pix_fmt(struct v4l2_pix_format *pix,
- struct v4l2_rect *compose,
- const struct v4l2_mbus_framefmt *mbus,
+ struct v4l2_mbus_framefmt *mbus,
const struct imx_media_pixfmt *cc)
{
u32 width;
@@ -620,17 +619,6 @@ int imx_media_mbus_fmt_to_pix_fmt(struct v4l2_pix_format *pix,
pix->sizeimage = cc->planar ? ((stride * pix->height * cc->bpp) >> 3) :
stride * pix->height;
- /*
- * set capture compose rectangle, which is fixed to the
- * source subdevice mbus format.
- */
- if (compose) {
- compose->left = 0;
- compose->top = 0;
- compose->width = mbus->width;
- compose->height = mbus->height;
- }
-
return 0;
}
EXPORT_SYMBOL_GPL(imx_media_mbus_fmt_to_pix_fmt);
@@ -642,11 +630,13 @@ int imx_media_mbus_fmt_to_ipu_image(struct ipu_image *image,
memset(image, 0, sizeof(*image));
- ret = imx_media_mbus_fmt_to_pix_fmt(&image->pix, &image->rect,
- mbus, NULL);
+ ret = imx_media_mbus_fmt_to_pix_fmt(&image->pix, mbus, NULL);
if (ret)
return ret;
+ image->rect.width = mbus->width;
+ image->rect.height = mbus->height;
+
return 0;
}
EXPORT_SYMBOL_GPL(imx_media_mbus_fmt_to_ipu_image);
@@ -674,29 +664,28 @@ int imx_media_ipu_image_to_mbus_fmt(struct v4l2_mbus_framefmt *mbus,
}
EXPORT_SYMBOL_GPL(imx_media_ipu_image_to_mbus_fmt);
-void imx_media_free_dma_buf(struct imx_media_dev *imxmd,
+void imx_media_free_dma_buf(struct device *dev,
struct imx_media_dma_buf *buf)
{
if (buf->virt)
- dma_free_coherent(imxmd->md.dev, buf->len,
- buf->virt, buf->phys);
+ dma_free_coherent(dev, buf->len, buf->virt, buf->phys);
buf->virt = NULL;
buf->phys = 0;
}
EXPORT_SYMBOL_GPL(imx_media_free_dma_buf);
-int imx_media_alloc_dma_buf(struct imx_media_dev *imxmd,
+int imx_media_alloc_dma_buf(struct device *dev,
struct imx_media_dma_buf *buf,
int size)
{
- imx_media_free_dma_buf(imxmd, buf);
+ imx_media_free_dma_buf(dev, buf);
buf->len = PAGE_ALIGN(size);
- buf->virt = dma_alloc_coherent(imxmd->md.dev, buf->len, &buf->phys,
+ buf->virt = dma_alloc_coherent(dev, buf->len, &buf->phys,
GFP_DMA | GFP_KERNEL);
if (!buf->virt) {
- dev_err(imxmd->md.dev, "failed to alloc dma buffer\n");
+ dev_err(dev, "%s: failed\n", __func__);
return -ENOMEM;
}
@@ -763,35 +752,37 @@ imx_media_find_subdev_by_devname(struct imx_media_dev *imxmd,
EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_devname);
/*
- * Adds a video device to the master video device list. This is called by
- * an async subdev that owns a video device when it is registered.
+ * Adds a video device to the master video device list. This is called
+ * when a video device is registered.
*/
-int imx_media_add_video_device(struct imx_media_dev *imxmd,
- struct imx_media_video_dev *vdev)
+void imx_media_add_video_device(struct imx_media_dev *imxmd,
+ struct imx_media_video_dev *vdev)
{
mutex_lock(&imxmd->mutex);
list_add_tail(&vdev->list, &imxmd->vdev_list);
mutex_unlock(&imxmd->mutex);
- return 0;
}
EXPORT_SYMBOL_GPL(imx_media_add_video_device);
/*
- * Search upstream/downstream for a subdevice in the current pipeline
- * with given grp_id, starting from start_entity. Returns the subdev's
- * source/sink pad that it was reached from. If grp_id is zero, just
- * returns the nearest source/sink pad to start_entity. Must be called
- * with mdev->graph_mutex held.
+ * Search upstream/downstream for a subdevice or video device pad in the
+ * current pipeline, starting from start_entity. Returns the device's
+ * source/sink pad that it was reached from. Must be called with
+ * mdev->graph_mutex held.
+ *
+ * If grp_id != 0, finds a subdevice's pad of given grp_id.
+ * Else If buftype != 0, finds a video device's pad of given buffer type.
+ * Else, returns the nearest source/sink pad to start_entity.
*/
-static struct media_pad *
-find_pipeline_pad(struct imx_media_dev *imxmd,
- struct media_entity *start_entity,
- u32 grp_id, bool upstream)
+struct media_pad *
+imx_media_pipeline_pad(struct media_entity *start_entity, u32 grp_id,
+ enum v4l2_buf_type buftype, bool upstream)
{
struct media_entity *me = start_entity;
struct media_pad *pad = NULL;
+ struct video_device *vfd;
struct v4l2_subdev *sd;
int i;
@@ -803,16 +794,27 @@ find_pipeline_pad(struct imx_media_dev *imxmd,
continue;
pad = media_entity_remote_pad(spad);
- if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
+ if (!pad)
continue;
- if (grp_id != 0) {
- sd = media_entity_to_v4l2_subdev(pad->entity);
- if (sd->grp_id & grp_id)
- return pad;
+ if (grp_id) {
+ if (is_media_entity_v4l2_subdev(pad->entity)) {
+ sd = media_entity_to_v4l2_subdev(pad->entity);
+ if (sd->grp_id & grp_id)
+ return pad;
+ }
+
+ return imx_media_pipeline_pad(pad->entity, grp_id,
+ buftype, upstream);
+ } else if (buftype) {
+ if (is_media_entity_v4l2_video_device(pad->entity)) {
+ vfd = media_entity_to_video_device(pad->entity);
+ if (buftype == vfd->queue->type)
+ return pad;
+ }
- return find_pipeline_pad(imxmd, pad->entity,
- grp_id, upstream);
+ return imx_media_pipeline_pad(pad->entity, grp_id,
+ buftype, upstream);
} else {
return pad;
}
@@ -820,28 +822,33 @@ find_pipeline_pad(struct imx_media_dev *imxmd,
return NULL;
}
+EXPORT_SYMBOL_GPL(imx_media_pipeline_pad);
/*
- * Search upstream for a subdev in the current pipeline with
- * given grp_id. Must be called with mdev->graph_mutex held.
+ * Search upstream/downstream for a subdev or video device in the current
+ * pipeline. Must be called with mdev->graph_mutex held.
*/
-static struct v4l2_subdev *
-find_upstream_subdev(struct imx_media_dev *imxmd,
- struct media_entity *start_entity,
- u32 grp_id)
+static struct media_entity *
+find_pipeline_entity(struct media_entity *start, u32 grp_id,
+ enum v4l2_buf_type buftype, bool upstream)
{
+ struct media_pad *pad = NULL;
+ struct video_device *vfd;
struct v4l2_subdev *sd;
- struct media_pad *pad;
- if (is_media_entity_v4l2_subdev(start_entity)) {
- sd = media_entity_to_v4l2_subdev(start_entity);
+ if (grp_id && is_media_entity_v4l2_subdev(start)) {
+ sd = media_entity_to_v4l2_subdev(start);
if (sd->grp_id & grp_id)
- return sd;
+ return &sd->entity;
+ } else if (buftype && is_media_entity_v4l2_video_device(start)) {
+ vfd = media_entity_to_video_device(pad->entity);
+ if (buftype == vfd->queue->type)
+ return &vfd->entity;
}
- pad = find_pipeline_pad(imxmd, start_entity, grp_id, true);
+ pad = imx_media_pipeline_pad(start, grp_id, buftype, upstream);
- return pad ? media_entity_to_v4l2_subdev(pad->entity) : NULL;
+ return pad ? pad->entity : NULL;
}
/*
@@ -849,62 +856,57 @@ find_upstream_subdev(struct imx_media_dev *imxmd,
* start entity in the current pipeline.
* Must be called with mdev->graph_mutex held.
*/
-int imx_media_find_mipi_csi2_channel(struct imx_media_dev *imxmd,
- struct media_entity *start_entity)
+int imx_media_pipeline_csi2_channel(struct media_entity *start_entity)
{
struct media_pad *pad;
int ret = -EPIPE;
- pad = find_pipeline_pad(imxmd, start_entity, IMX_MEDIA_GRP_ID_CSI2,
- true);
- if (pad) {
+ pad = imx_media_pipeline_pad(start_entity, IMX_MEDIA_GRP_ID_CSI2,
+ 0, true);
+ if (pad)
ret = pad->index - 1;
- dev_dbg(imxmd->md.dev, "found vc%d from %s\n",
- ret, start_entity->name);
- }
return ret;
}
-EXPORT_SYMBOL_GPL(imx_media_find_mipi_csi2_channel);
+EXPORT_SYMBOL_GPL(imx_media_pipeline_csi2_channel);
/*
- * Find a source pad reached upstream from the given start entity in
- * the current pipeline. Must be called with mdev->graph_mutex held.
+ * Find a subdev reached upstream from the given start entity in
+ * the current pipeline.
+ * Must be called with mdev->graph_mutex held.
*/
-struct media_pad *
-imx_media_find_upstream_pad(struct imx_media_dev *imxmd,
- struct media_entity *start_entity,
- u32 grp_id)
+struct v4l2_subdev *
+imx_media_pipeline_subdev(struct media_entity *start_entity, u32 grp_id,
+ bool upstream)
{
- struct media_pad *pad;
+ struct media_entity *me;
- pad = find_pipeline_pad(imxmd, start_entity, grp_id, true);
- if (!pad)
+ me = find_pipeline_entity(start_entity, grp_id, 0, upstream);
+ if (!me)
return ERR_PTR(-ENODEV);
- return pad;
+ return media_entity_to_v4l2_subdev(me);
}
-EXPORT_SYMBOL_GPL(imx_media_find_upstream_pad);
+EXPORT_SYMBOL_GPL(imx_media_pipeline_subdev);
/*
* Find a subdev reached upstream from the given start entity in
* the current pipeline.
* Must be called with mdev->graph_mutex held.
*/
-struct v4l2_subdev *
-imx_media_find_upstream_subdev(struct imx_media_dev *imxmd,
- struct media_entity *start_entity,
- u32 grp_id)
+struct video_device *
+imx_media_pipeline_video_device(struct media_entity *start_entity,
+ enum v4l2_buf_type buftype, bool upstream)
{
- struct v4l2_subdev *sd;
+ struct media_entity *me;
- sd = find_upstream_subdev(imxmd, start_entity, grp_id);
- if (!sd)
+ me = find_pipeline_entity(start_entity, 0, buftype, upstream);
+ if (!me)
return ERR_PTR(-ENODEV);
- return sd;
+ return media_entity_to_video_device(me);
}
-EXPORT_SYMBOL_GPL(imx_media_find_upstream_subdev);
+EXPORT_SYMBOL_GPL(imx_media_pipeline_video_device);
/*
* Turn current pipeline streaming on/off starting from entity.
diff --git a/drivers/staging/media/imx/imx-media-vdic.c b/drivers/staging/media/imx/imx-media-vdic.c
index fbafd7fb7aeb..cfad65a16917 100644
--- a/drivers/staging/media/imx/imx-media-vdic.c
+++ b/drivers/staging/media/imx/imx-media-vdic.c
@@ -4,13 +4,6 @@
*
* Copyright (c) 2017 Mentor Graphics Inc.
*/
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/timer.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
@@ -65,12 +58,11 @@ struct vdic_pipeline_ops {
#define S_ALIGN 1 /* multiple of 2 */
struct vdic_priv {
- struct device *dev;
- struct ipu_soc *ipu;
- struct imx_media_dev *md;
+ struct device *ipu_dev;
+ struct ipu_soc *ipu;
+
struct v4l2_subdev sd;
struct media_pad pad[VDIC_NUM_PADS];
- int ipu_id;
/* lock to protect all members below */
struct mutex lock;
@@ -145,8 +137,6 @@ static int vdic_get_ipu_resources(struct vdic_priv *priv)
struct ipuv3_channel *ch;
struct ipu_vdi *vdi;
- priv->ipu = priv->md->ipu[priv->ipu_id];
-
vdi = ipu_vdi_get(priv->ipu);
if (IS_ERR(vdi)) {
v4l2_err(&priv->sd, "failed to get VDIC\n");
@@ -511,7 +501,8 @@ static int vdic_s_stream(struct v4l2_subdev *sd, int enable)
if (priv->stream_count != !enable)
goto update_count;
- dev_dbg(priv->dev, "stream %s\n", enable ? "ON" : "OFF");
+ dev_dbg(priv->ipu_dev, "%s: stream %s\n", sd->name,
+ enable ? "ON" : "OFF");
if (enable)
ret = vdic_start(priv);
@@ -685,8 +676,8 @@ static int vdic_link_setup(struct media_entity *entity,
struct v4l2_subdev *remote_sd;
int ret = 0;
- dev_dbg(priv->dev, "link setup %s -> %s", remote->entity->name,
- local->entity->name);
+ dev_dbg(priv->ipu_dev, "%s: link setup %s -> %s",
+ sd->name, remote->entity->name, local->entity->name);
mutex_lock(&priv->lock);
@@ -859,9 +850,6 @@ static int vdic_registered(struct v4l2_subdev *sd)
int i, ret;
u32 code;
- /* get media device */
- priv->md = dev_get_drvdata(sd->v4l2_dev->dev);
-
for (i = 0; i < VDIC_NUM_PADS; i++) {
priv->pad[i].flags = (i == VDIC_SRC_PAD_DIRECT) ?
MEDIA_PAD_FL_SOURCE : MEDIA_PAD_FL_SINK;
@@ -933,77 +921,53 @@ static const struct v4l2_subdev_internal_ops vdic_internal_ops = {
.unregistered = vdic_unregistered,
};
-static int imx_vdic_probe(struct platform_device *pdev)
+struct v4l2_subdev *imx_media_vdic_register(struct v4l2_device *v4l2_dev,
+ struct device *ipu_dev,
+ struct ipu_soc *ipu,
+ u32 grp_id)
{
- struct imx_media_ipu_internal_sd_pdata *pdata;
struct vdic_priv *priv;
int ret;
- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ priv = devm_kzalloc(ipu_dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
- platform_set_drvdata(pdev, &priv->sd);
- priv->dev = &pdev->dev;
-
- pdata = priv->dev->platform_data;
- priv->ipu_id = pdata->ipu_id;
+ priv->ipu_dev = ipu_dev;
+ priv->ipu = ipu;
v4l2_subdev_init(&priv->sd, &vdic_subdev_ops);
v4l2_set_subdevdata(&priv->sd, priv);
priv->sd.internal_ops = &vdic_internal_ops;
priv->sd.entity.ops = &vdic_entity_ops;
priv->sd.entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
- priv->sd.dev = &pdev->dev;
- priv->sd.owner = THIS_MODULE;
+ priv->sd.owner = ipu_dev->driver->owner;
priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
- /* get our group id */
- priv->sd.grp_id = pdata->grp_id;
- strscpy(priv->sd.name, pdata->sd_name, sizeof(priv->sd.name));
+ priv->sd.grp_id = grp_id;
+ imx_media_grp_id_to_sd_name(priv->sd.name, sizeof(priv->sd.name),
+ priv->sd.grp_id, ipu_get_num(ipu));
mutex_init(&priv->lock);
- ret = v4l2_async_register_subdev(&priv->sd);
+ ret = v4l2_device_register_subdev(v4l2_dev, &priv->sd);
if (ret)
goto free;
- return 0;
+ return &priv->sd;
free:
mutex_destroy(&priv->lock);
- return ret;
+ return ERR_PTR(ret);
}
-static int imx_vdic_remove(struct platform_device *pdev)
+int imx_media_vdic_unregister(struct v4l2_subdev *sd)
{
- struct v4l2_subdev *sd = platform_get_drvdata(pdev);
struct vdic_priv *priv = v4l2_get_subdevdata(sd);
v4l2_info(sd, "Removing\n");
- v4l2_async_unregister_subdev(sd);
+ v4l2_device_unregister_subdev(sd);
mutex_destroy(&priv->lock);
media_entity_cleanup(&sd->entity);
return 0;
}
-
-static const struct platform_device_id imx_vdic_ids[] = {
- { .name = "imx-ipuv3-vdic" },
- { },
-};
-MODULE_DEVICE_TABLE(platform, imx_vdic_ids);
-
-static struct platform_driver imx_vdic_driver = {
- .probe = imx_vdic_probe,
- .remove = imx_vdic_remove,
- .id_table = imx_vdic_ids,
- .driver = {
- .name = "imx-ipuv3-vdic",
- },
-};
-module_platform_driver(imx_vdic_driver);
-
-MODULE_DESCRIPTION("i.MX VDIC subdev driver");
-MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx-ipuv3-vdic");
diff --git a/drivers/staging/media/imx/imx-media.h b/drivers/staging/media/imx/imx-media.h
index 23024c9bc887..4d124a86b358 100644
--- a/drivers/staging/media/imx/imx-media.h
+++ b/drivers/staging/media/imx/imx-media.h
@@ -16,6 +16,19 @@
#include <video/imx-ipu-v3.h>
/*
+ * Enumeration of the IPU internal sub-devices
+ */
+enum {
+ IPU_CSI0 = 0,
+ IPU_CSI1,
+ IPU_VDIC,
+ IPU_IC_PRP,
+ IPU_IC_PRPENC,
+ IPU_IC_PRPVF,
+ NUM_IPU_SUBDEVS,
+};
+
+/*
* Pad definitions for the subdevs with multiple source or
* sink pads
*/
@@ -111,25 +124,6 @@ struct imx_media_pad_vdev {
struct list_head list;
};
-struct imx_media_ipu_internal_sd_pdata {
- char sd_name[V4L2_SUBDEV_NAME_SIZE];
- u32 grp_id;
- int ipu_id;
-};
-
-struct imx_media_async_subdev {
- /* the base asd - must be first in this struct */
- struct v4l2_async_subdev asd;
- /* the platform device of IPU-internal subdevs */
- struct platform_device *pdev;
-};
-
-static inline struct imx_media_async_subdev *
-to_imx_media_asd(struct v4l2_async_subdev *asd)
-{
- return container_of(asd, struct imx_media_async_subdev, asd);
-}
-
struct imx_media_dev {
struct media_device md;
struct v4l2_device v4l2_dev;
@@ -142,11 +136,11 @@ struct imx_media_dev {
/* master video device list */
struct list_head vdev_list;
- /* IPUs this media driver control, valid after subdevs bound */
- struct ipu_soc *ipu[2];
-
/* for async subdev registration */
struct v4l2_async_notifier notifier;
+
+ /* the IPU internal subdev's registered synchronously */
+ struct v4l2_subdev *sync_sd[2][NUM_IPU_SUBDEVS];
};
enum codespace_sel {
@@ -175,8 +169,7 @@ int imx_media_init_cfg(struct v4l2_subdev *sd,
void imx_media_try_colorimetry(struct v4l2_mbus_framefmt *tryfmt,
bool ic_route);
int imx_media_mbus_fmt_to_pix_fmt(struct v4l2_pix_format *pix,
- struct v4l2_rect *compose,
- const struct v4l2_mbus_framefmt *mbus,
+ struct v4l2_mbus_framefmt *mbus,
const struct imx_media_pixfmt *cc);
int imx_media_mbus_fmt_to_ipu_image(struct ipu_image *image,
struct v4l2_mbus_framefmt *mbus);
@@ -190,18 +183,18 @@ imx_media_find_subdev_by_fwnode(struct imx_media_dev *imxmd,
struct v4l2_subdev *
imx_media_find_subdev_by_devname(struct imx_media_dev *imxmd,
const char *devname);
-int imx_media_add_video_device(struct imx_media_dev *imxmd,
- struct imx_media_video_dev *vdev);
-int imx_media_find_mipi_csi2_channel(struct imx_media_dev *imxmd,
- struct media_entity *start_entity);
+void imx_media_add_video_device(struct imx_media_dev *imxmd,
+ struct imx_media_video_dev *vdev);
+int imx_media_pipeline_csi2_channel(struct media_entity *start_entity);
struct media_pad *
-imx_media_find_upstream_pad(struct imx_media_dev *imxmd,
- struct media_entity *start_entity,
- u32 grp_id);
+imx_media_pipeline_pad(struct media_entity *start_entity, u32 grp_id,
+ enum v4l2_buf_type buftype, bool upstream);
struct v4l2_subdev *
-imx_media_find_upstream_subdev(struct imx_media_dev *imxmd,
- struct media_entity *start_entity,
- u32 grp_id);
+imx_media_pipeline_subdev(struct media_entity *start_entity, u32 grp_id,
+ bool upstream);
+struct video_device *
+imx_media_pipeline_video_device(struct media_entity *start_entity,
+ enum v4l2_buf_type buftype, bool upstream);
struct imx_media_dma_buf {
void *virt;
@@ -209,9 +202,9 @@ struct imx_media_dma_buf {
unsigned long len;
};
-void imx_media_free_dma_buf(struct imx_media_dev *imxmd,
+void imx_media_free_dma_buf(struct device *dev,
struct imx_media_dma_buf *buf);
-int imx_media_alloc_dma_buf(struct imx_media_dev *imxmd,
+int imx_media_alloc_dma_buf(struct device *dev,
struct imx_media_dma_buf *buf,
int size);
@@ -219,22 +212,12 @@ int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd,
struct media_entity *entity,
bool on);
-/* imx-media-dev.c */
-int imx_media_add_async_subdev(struct imx_media_dev *imxmd,
- struct fwnode_handle *fwnode,
- struct platform_device *pdev);
-
-int imx_media_subdev_bound(struct v4l2_async_notifier *notifier,
- struct v4l2_subdev *sd,
- struct v4l2_async_subdev *asd);
-int imx_media_link_notify(struct media_link *link, u32 flags,
- unsigned int notification);
-void imx_media_notify(struct v4l2_subdev *sd, unsigned int notification,
- void *arg);
+/* imx-media-dev-common.c */
int imx_media_probe_complete(struct v4l2_async_notifier *notifier);
-
-struct imx_media_dev *imx_media_dev_init(struct device *dev);
-int imx_media_dev_notifier_register(struct imx_media_dev *imxmd);
+struct imx_media_dev *imx_media_dev_init(struct device *dev,
+ const struct media_device_ops *ops);
+int imx_media_dev_notifier_register(struct imx_media_dev *imxmd,
+ const struct v4l2_async_notifier_operations *ops);
/* imx-media-fim.c */
struct imx_media_fim;
@@ -247,11 +230,9 @@ struct imx_media_fim *imx_media_fim_init(struct v4l2_subdev *sd);
void imx_media_fim_free(struct imx_media_fim *fim);
/* imx-media-internal-sd.c */
-int imx_media_add_ipu_internal_subdevs(struct imx_media_dev *imxmd,
- int ipu_id);
-int imx_media_create_ipu_internal_links(struct imx_media_dev *imxmd,
- struct v4l2_subdev *sd);
-void imx_media_remove_ipu_internal_subdevs(struct imx_media_dev *imxmd);
+int imx_media_register_ipu_internal_subdevs(struct imx_media_dev *imxmd,
+ struct v4l2_subdev *csi);
+void imx_media_unregister_ipu_internal_subdevs(struct imx_media_dev *imxmd);
/* imx-media-of.c */
int imx_media_add_of_subdevs(struct imx_media_dev *dev,
@@ -263,18 +244,29 @@ int imx_media_create_csi_of_links(struct imx_media_dev *imxmd,
int imx_media_of_add_csi(struct imx_media_dev *imxmd,
struct device_node *csi_np);
+/* imx-media-vdic.c */
+struct v4l2_subdev *imx_media_vdic_register(struct v4l2_device *v4l2_dev,
+ struct device *ipu_dev,
+ struct ipu_soc *ipu,
+ u32 grp_id);
+int imx_media_vdic_unregister(struct v4l2_subdev *sd);
+
+/* imx-ic-common.c */
+struct v4l2_subdev *imx_media_ic_register(struct v4l2_device *v4l2_dev,
+ struct device *ipu_dev,
+ struct ipu_soc *ipu,
+ u32 grp_id);
+int imx_media_ic_unregister(struct v4l2_subdev *sd);
+
/* imx-media-capture.c */
struct imx_media_video_dev *
-imx_media_capture_device_init(struct v4l2_subdev *src_sd, int pad);
+imx_media_capture_device_init(struct device *dev, struct v4l2_subdev *src_sd,
+ int pad);
void imx_media_capture_device_remove(struct imx_media_video_dev *vdev);
-int imx_media_capture_device_register(struct imx_media_dev *md,
- struct imx_media_video_dev *vdev);
+int imx_media_capture_device_register(struct imx_media_video_dev *vdev);
void imx_media_capture_device_unregister(struct imx_media_video_dev *vdev);
struct imx_media_buffer *
imx_media_capture_device_next_buf(struct imx_media_video_dev *vdev);
-void imx_media_capture_device_set_format(struct imx_media_video_dev *vdev,
- const struct v4l2_pix_format *pix,
- const struct v4l2_rect *compose);
void imx_media_capture_device_error(struct imx_media_video_dev *vdev);
/* subdev group ids */
diff --git a/drivers/staging/media/imx/imx7-media-csi.c b/drivers/staging/media/imx/imx7-media-csi.c
index 6e2f4c3eb24f..500b4c08d967 100644
--- a/drivers/staging/media/imx/imx7-media-csi.c
+++ b/drivers/staging/media/imx/imx7-media-csi.c
@@ -152,8 +152,6 @@
#define CSI_CSICR18 0x48
#define CSI_CSICR19 0x4c
-static const char * const imx7_csi_clk_id[] = {"axi", "dcic", "mclk"};
-
struct imx7_csi {
struct device *dev;
struct v4l2_subdev sd;
@@ -180,9 +178,7 @@ struct imx7_csi {
void __iomem *regbase;
int irq;
-
- int num_clks;
- struct clk_bulk_data *clks;
+ struct clk *mclk;
/* active vb2 buffers to send to video dev sink */
struct imx_media_buffer *active_vb2_buf[2];
@@ -199,23 +195,15 @@ struct imx7_csi {
struct completion last_eof_completion;
};
-#define imx7_csi_reg_read(_csi, _offset) \
- __raw_readl((_csi)->regbase + (_offset))
-#define imx7_csi_reg_write(_csi, _val, _offset) \
- __raw_writel(_val, (_csi)->regbase + (_offset))
-
-static void imx7_csi_clk_enable(struct imx7_csi *csi)
+static u32 imx7_csi_reg_read(struct imx7_csi *csi, unsigned int offset)
{
- int ret;
-
- ret = clk_bulk_prepare_enable(csi->num_clks, csi->clks);
- if (ret < 0)
- dev_err(csi->dev, "failed to enable clocks\n");
+ return readl(csi->regbase + offset);
}
-static void imx7_csi_clk_disable(struct imx7_csi *csi)
+static void imx7_csi_reg_write(struct imx7_csi *csi, unsigned int value,
+ unsigned int offset)
{
- clk_bulk_disable_unprepare(csi->num_clks, csi->clks);
+ writel(value, csi->regbase + offset);
}
static void imx7_csi_hw_reset(struct imx7_csi *csi)
@@ -229,9 +217,9 @@ static void imx7_csi_hw_reset(struct imx7_csi *csi)
imx7_csi_reg_write(csi, CSICR3_RESET_VAL, CSI_CSICR3);
}
-static unsigned long imx7_csi_irq_clear(struct imx7_csi *csi)
+static u32 imx7_csi_irq_clear(struct imx7_csi *csi)
{
- unsigned long isr;
+ u32 isr;
isr = imx7_csi_reg_read(csi, CSI_CSISR);
imx7_csi_reg_write(csi, isr, CSI_CSISR);
@@ -257,7 +245,7 @@ static void imx7_csi_init_interface(struct imx7_csi *csi)
static void imx7_csi_hw_enable_irq(struct imx7_csi *csi)
{
- unsigned long cr1 = imx7_csi_reg_read(csi, CSI_CSICR1);
+ u32 cr1 = imx7_csi_reg_read(csi, CSI_CSICR1);
cr1 |= BIT_SOF_INTEN;
cr1 |= BIT_RFF_OR_INT;
@@ -273,7 +261,7 @@ static void imx7_csi_hw_enable_irq(struct imx7_csi *csi)
static void imx7_csi_hw_disable_irq(struct imx7_csi *csi)
{
- unsigned long cr1 = imx7_csi_reg_read(csi, CSI_CSICR1);
+ u32 cr1 = imx7_csi_reg_read(csi, CSI_CSICR1);
cr1 &= ~BIT_SOF_INTEN;
cr1 &= ~BIT_RFF_OR_INT;
@@ -286,7 +274,7 @@ static void imx7_csi_hw_disable_irq(struct imx7_csi *csi)
static void imx7_csi_hw_enable(struct imx7_csi *csi)
{
- unsigned long cr = imx7_csi_reg_read(csi, CSI_CSICR18);
+ u32 cr = imx7_csi_reg_read(csi, CSI_CSICR18);
cr |= BIT_CSI_HW_ENABLE;
@@ -295,7 +283,7 @@ static void imx7_csi_hw_enable(struct imx7_csi *csi)
static void imx7_csi_hw_disable(struct imx7_csi *csi)
{
- unsigned long cr = imx7_csi_reg_read(csi, CSI_CSICR18);
+ u32 cr = imx7_csi_reg_read(csi, CSI_CSICR18);
cr &= ~BIT_CSI_HW_ENABLE;
@@ -304,7 +292,7 @@ static void imx7_csi_hw_disable(struct imx7_csi *csi)
static void imx7_csi_dma_reflash(struct imx7_csi *csi)
{
- unsigned long cr3 = imx7_csi_reg_read(csi, CSI_CSICR18);
+ u32 cr3 = imx7_csi_reg_read(csi, CSI_CSICR18);
cr3 = imx7_csi_reg_read(csi, CSI_CSICR3);
cr3 |= BIT_DMA_REFLASH_RFF;
@@ -313,7 +301,7 @@ static void imx7_csi_dma_reflash(struct imx7_csi *csi)
static void imx7_csi_rx_fifo_clear(struct imx7_csi *csi)
{
- unsigned long cr1;
+ u32 cr1;
cr1 = imx7_csi_reg_read(csi, CSI_CSICR1);
imx7_csi_reg_write(csi, cr1 & ~BIT_FCC, CSI_CSICR1);
@@ -331,7 +319,7 @@ static void imx7_csi_buf_stride_set(struct imx7_csi *csi, u32 stride)
static void imx7_csi_deinterlace_enable(struct imx7_csi *csi, bool enable)
{
- unsigned long cr18 = imx7_csi_reg_read(csi, CSI_CSICR18);
+ u32 cr18 = imx7_csi_reg_read(csi, CSI_CSICR18);
if (enable)
cr18 |= BIT_DEINTERLACE_EN;
@@ -343,8 +331,8 @@ static void imx7_csi_deinterlace_enable(struct imx7_csi *csi, bool enable)
static void imx7_csi_dmareq_rff_enable(struct imx7_csi *csi)
{
- unsigned long cr3 = imx7_csi_reg_read(csi, CSI_CSICR3);
- unsigned long cr2 = imx7_csi_reg_read(csi, CSI_CSICR2);
+ u32 cr3 = imx7_csi_reg_read(csi, CSI_CSICR3);
+ u32 cr2 = imx7_csi_reg_read(csi, CSI_CSICR2);
/* Burst Type of DMA Transfer from RxFIFO. INCR16 */
cr2 |= 0xC0000000;
@@ -360,7 +348,7 @@ static void imx7_csi_dmareq_rff_enable(struct imx7_csi *csi)
static void imx7_csi_dmareq_rff_disable(struct imx7_csi *csi)
{
- unsigned long cr3 = imx7_csi_reg_read(csi, CSI_CSICR3);
+ u32 cr3 = imx7_csi_reg_read(csi, CSI_CSICR3);
cr3 &= ~BIT_DMA_REQ_EN_RFF;
cr3 &= ~BIT_HRESP_ERR_EN;
@@ -408,17 +396,23 @@ static void imx7_csi_error_recovery(struct imx7_csi *csi)
imx7_csi_hw_enable(csi);
}
-static void imx7_csi_init(struct imx7_csi *csi)
+static int imx7_csi_init(struct imx7_csi *csi)
{
+ int ret;
+
if (csi->is_init)
- return;
+ return 0;
- imx7_csi_clk_enable(csi);
+ ret = clk_prepare_enable(csi->mclk);
+ if (ret < 0)
+ return ret;
imx7_csi_hw_reset(csi);
imx7_csi_init_interface(csi);
imx7_csi_dmareq_rff_enable(csi);
csi->is_init = true;
+
+ return 0;
}
static void imx7_csi_deinit(struct imx7_csi *csi)
@@ -429,7 +423,7 @@ static void imx7_csi_deinit(struct imx7_csi *csi)
imx7_csi_hw_reset(csi);
imx7_csi_init_interface(csi);
imx7_csi_dmareq_rff_disable(csi);
- imx7_csi_clk_disable(csi);
+ clk_disable_unprepare(csi->mclk);
csi->is_init = false;
}
@@ -448,11 +442,19 @@ static int imx7_csi_get_upstream_endpoint(struct imx7_csi *csi,
src = &csi->src_sd->entity;
+ /*
+ * if the source is neither a mux or csi2 get the one directly upstream
+ * from this csi
+ */
+ if (src->function != MEDIA_ENT_F_VID_IF_BRIDGE &&
+ src->function != MEDIA_ENT_F_VID_MUX)
+ src = &csi->sd.entity;
+
skip_video_mux:
/* get source pad of entity directly upstream from src */
- pad = imx_media_find_upstream_pad(csi->imxmd, src, 0);
- if (IS_ERR(pad))
- return PTR_ERR(pad);
+ pad = imx_media_pipeline_pad(src, 0, 0, true);
+ if (!pad)
+ return -ENODEV;
sd = media_entity_to_v4l2_subdev(pad->entity);
@@ -531,7 +533,7 @@ static int imx7_csi_link_setup(struct media_entity *entity,
init:
if (csi->sink || csi->src_sd)
- imx7_csi_init(csi);
+ ret = imx7_csi_init(csi);
else
imx7_csi_deinit(csi);
@@ -653,7 +655,7 @@ static void imx7_csi_vb2_buf_done(struct imx7_csi *csi)
static irqreturn_t imx7_csi_irq_handler(int irq, void *data)
{
struct imx7_csi *csi = data;
- unsigned long status;
+ u32 status;
spin_lock(&csi->irqlock);
@@ -714,7 +716,7 @@ static int imx7_csi_dma_start(struct imx7_csi *csi)
struct v4l2_pix_format *out_pix = &vdev->fmt.fmt.pix;
int ret;
- ret = imx_media_alloc_dma_buf(csi->imxmd, &csi->underrun_buf,
+ ret = imx_media_alloc_dma_buf(csi->dev, &csi->underrun_buf,
out_pix->sizeimage);
if (ret < 0) {
v4l2_warn(&csi->sd, "consider increasing the CMA area\n");
@@ -754,7 +756,7 @@ static void imx7_csi_dma_stop(struct imx7_csi *csi)
imx7_csi_dma_unsetup_vb2_buf(csi, VB2_BUF_STATE_ERROR);
- imx_media_free_dma_buf(csi->imxmd, &csi->underrun_buf);
+ imx_media_free_dma_buf(csi->dev, &csi->underrun_buf);
}
static int imx7_csi_configure(struct imx7_csi *csi)
@@ -811,7 +813,7 @@ static int imx7_csi_configure(struct imx7_csi *csi)
return 0;
}
-static int imx7_csi_enable(struct imx7_csi *csi)
+static void imx7_csi_enable(struct imx7_csi *csi)
{
imx7_csi_sw_reset(csi);
@@ -819,10 +821,7 @@ static int imx7_csi_enable(struct imx7_csi *csi)
imx7_csi_dmareq_rff_enable(csi);
imx7_csi_hw_enable_irq(csi);
imx7_csi_hw_enable(csi);
- return 0;
}
-
- return 0;
}
static void imx7_csi_disable(struct imx7_csi *csi)
@@ -1016,7 +1015,6 @@ static int imx7_csi_try_fmt(struct imx7_csi *csi,
break;
default:
return -EINVAL;
- break;
}
imx_media_try_colorimetry(&sdformat->format, false);
@@ -1029,11 +1027,8 @@ static int imx7_csi_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_format *sdformat)
{
struct imx7_csi *csi = v4l2_get_subdevdata(sd);
- struct imx_media_video_dev *vdev = csi->vdev;
const struct imx_media_pixfmt *outcc;
struct v4l2_mbus_framefmt *outfmt;
- struct v4l2_pix_format vdev_fmt;
- struct v4l2_rect vdev_compose;
const struct imx_media_pixfmt *cc;
struct v4l2_mbus_framefmt *fmt;
struct v4l2_subdev_format format;
@@ -1078,19 +1073,8 @@ static int imx7_csi_set_fmt(struct v4l2_subdev *sd,
csi->cc[IMX7_CSI_PAD_SRC] = outcc;
}
- if (sdformat->which == V4L2_SUBDEV_FORMAT_TRY)
- goto out_unlock;
-
- csi->cc[sdformat->pad] = cc;
-
- /* propagate output pad format to capture device */
- imx_media_mbus_fmt_to_pix_fmt(&vdev_fmt, &vdev_compose,
- &csi->format_mbus[IMX7_CSI_PAD_SRC],
- csi->cc[IMX7_CSI_PAD_SRC]);
- mutex_unlock(&csi->lock);
- imx_media_capture_device_set_format(vdev, &vdev_fmt, &vdev_compose);
-
- return 0;
+ if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ csi->cc[sdformat->pad] = cc;
out_unlock:
mutex_unlock(&csi->lock);
@@ -1124,17 +1108,7 @@ static int imx7_csi_registered(struct v4l2_subdev *sd)
if (ret < 0)
return ret;
- ret = imx_media_capture_device_register(csi->imxmd, csi->vdev);
- if (ret < 0)
- return ret;
-
- ret = imx_media_add_video_device(csi->imxmd, csi->vdev);
- if (ret < 0) {
- imx_media_capture_device_unregister(csi->vdev);
- return ret;
- }
-
- return 0;
+ return imx_media_capture_device_register(csi->vdev);
}
static void imx7_csi_unregistered(struct v4l2_subdev *sd)
@@ -1198,31 +1172,12 @@ static int imx7_csi_parse_endpoint(struct device *dev,
return fwnode_device_is_available(asd->match.fwnode) ? 0 : -EINVAL;
}
-static int imx7_csi_clocks_get(struct imx7_csi *csi)
-{
- struct device *dev = csi->dev;
- int i;
-
- csi->num_clks = ARRAY_SIZE(imx7_csi_clk_id);
- csi->clks = devm_kcalloc(dev, csi->num_clks, sizeof(*csi->clks),
- GFP_KERNEL);
-
- if (!csi->clks)
- return -ENOMEM;
-
- for (i = 0; i < csi->num_clks; i++)
- csi->clks[i].id = imx7_csi_clk_id[i];
-
- return devm_clk_bulk_get(dev, csi->num_clks, csi->clks);
-}
-
static int imx7_csi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
struct imx_media_dev *imxmd;
struct imx7_csi *csi;
- struct resource *res;
int ret;
csi = devm_kzalloc(&pdev->dev, sizeof(*csi), GFP_KERNEL);
@@ -1231,24 +1186,22 @@ static int imx7_csi_probe(struct platform_device *pdev)
csi->dev = dev;
- ret = imx7_csi_clocks_get(csi);
- if (ret < 0) {
- dev_err(dev, "Failed to get clocks");
- return -ENODEV;
+ csi->mclk = devm_clk_get(&pdev->dev, "mclk");
+ if (IS_ERR(csi->mclk)) {
+ ret = PTR_ERR(csi->mclk);
+ dev_err(dev, "Failed to get mclk: %d", ret);
+ return ret;
}
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
csi->irq = platform_get_irq(pdev, 0);
- if (!res || csi->irq < 0) {
+ if (csi->irq < 0) {
dev_err(dev, "Missing platform resources data\n");
- return -ENODEV;
+ return csi->irq;
}
- csi->regbase = devm_ioremap_resource(dev, res);
- if (IS_ERR(csi->regbase)) {
- dev_err(dev, "Failed platform resources map\n");
- return -ENODEV;
- }
+ csi->regbase = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(csi->regbase))
+ return PTR_ERR(csi->regbase);
spin_lock_init(&csi->irqlock);
mutex_init(&csi->lock);
@@ -1258,12 +1211,11 @@ static int imx7_csi_probe(struct platform_device *pdev)
(void *)csi);
if (ret < 0) {
dev_err(dev, "Request CSI IRQ failed.\n");
- ret = -ENODEV;
goto destroy_mutex;
}
/* add media device */
- imxmd = imx_media_dev_init(dev);
+ imxmd = imx_media_dev_init(dev, NULL);
if (IS_ERR(imxmd)) {
ret = PTR_ERR(imxmd);
goto destroy_mutex;
@@ -1274,7 +1226,7 @@ static int imx7_csi_probe(struct platform_device *pdev)
if (ret < 0 && ret != -ENODEV && ret != -EEXIST)
goto cleanup;
- ret = imx_media_dev_notifier_register(imxmd);
+ ret = imx_media_dev_notifier_register(imxmd, NULL);
if (ret < 0)
goto cleanup;
@@ -1290,7 +1242,8 @@ static int imx7_csi_probe(struct platform_device *pdev)
csi->sd.grp_id = IMX_MEDIA_GRP_ID_CSI;
snprintf(csi->sd.name, sizeof(csi->sd.name), "csi");
- csi->vdev = imx_media_capture_device_init(&csi->sd, IMX7_CSI_PAD_SRC);
+ csi->vdev = imx_media_capture_device_init(csi->sd.dev, &csi->sd,
+ IMX7_CSI_PAD_SRC);
if (IS_ERR(csi->vdev))
return PTR_ERR(csi->vdev);
diff --git a/drivers/staging/media/imx/imx7-mipi-csis.c b/drivers/staging/media/imx/imx7-mipi-csis.c
index 19455f425416..d1cdf011c8f1 100644
--- a/drivers/staging/media/imx/imx7-mipi-csis.c
+++ b/drivers/staging/media/imx/imx7-mipi-csis.c
@@ -456,13 +456,9 @@ static void mipi_csis_set_params(struct csi_state *state)
MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW_CTRL);
}
-static void mipi_csis_clk_enable(struct csi_state *state)
+static int mipi_csis_clk_enable(struct csi_state *state)
{
- int ret;
-
- ret = clk_bulk_prepare_enable(state->num_clks, state->clks);
- if (ret < 0)
- dev_err(state->dev, "failed to enable clocks\n");
+ return clk_bulk_prepare_enable(state->num_clks, state->clks);
}
static void mipi_csis_clk_disable(struct csi_state *state)
@@ -784,6 +780,17 @@ static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static int mipi_csis_registered(struct v4l2_subdev *mipi_sd)
+{
+ struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
+
+ state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+ return media_entity_pads_init(&state->mipi_sd.entity, CSIS_PADS_NUM,
+ state->pads);
+}
+
static const struct v4l2_subdev_core_ops mipi_csis_core_ops = {
.log_status = mipi_csis_log_status,
};
@@ -809,6 +816,10 @@ static const struct v4l2_subdev_ops mipi_csis_subdev_ops = {
.pad = &mipi_csis_pad_ops,
};
+static const struct v4l2_subdev_internal_ops mipi_csis_internal_ops = {
+ .registered = mipi_csis_registered,
+};
+
static int mipi_csis_parse_dt(struct platform_device *pdev,
struct csi_state *state)
{
@@ -869,6 +880,7 @@ static int mipi_csis_subdev_init(struct v4l2_subdev *mipi_sd,
mipi_sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
mipi_sd->entity.ops = &mipi_csis_entity_ops;
+ mipi_sd->internal_ops = &mipi_csis_internal_ops;
mipi_sd->dev = &pdev->dev;
@@ -890,7 +902,6 @@ static int mipi_csis_subdev_init(struct v4l2_subdev *mipi_sd,
return ret;
}
-
static int mipi_csis_dump_regs_show(struct seq_file *m, void *private)
{
struct csi_state *state = m->private;
@@ -938,7 +949,7 @@ static int mipi_csis_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct resource *mem_res;
struct csi_state *state;
- int ret = -ENOMEM;
+ int ret;
state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
if (!state)
@@ -973,7 +984,11 @@ static int mipi_csis_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
- mipi_csis_clk_enable(state);
+ ret = mipi_csis_clk_enable(state);
+ if (ret < 0) {
+ dev_err(state->dev, "failed to enable clocks: %d\n", ret);
+ return ret;
+ }
ret = devm_request_irq(dev, state->irq, mipi_csis_irq_handler,
0, dev_name(dev), state);
@@ -990,13 +1005,6 @@ static int mipi_csis_probe(struct platform_device *pdev)
if (ret < 0)
goto disable_clock;
- state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
- state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
- ret = media_entity_pads_init(&state->mipi_sd.entity, CSIS_PADS_NUM,
- state->pads);
- if (ret < 0)
- goto unregister_subdev;
-
memcpy(state->events, mipi_csis_events, sizeof(state->events));
mipi_csis_debugfs_init(state);
@@ -1016,7 +1024,6 @@ static int mipi_csis_probe(struct platform_device *pdev)
unregister_all:
mipi_csis_debugfs_exit(state);
media_entity_cleanup(&state->mipi_sd.entity);
-unregister_subdev:
v4l2_async_unregister_subdev(&state->mipi_sd);
disable_clock:
mipi_csis_clk_disable(state);
diff --git a/drivers/staging/media/ipu3/include/intel-ipu3.h b/drivers/staging/media/ipu3/include/intel-ipu3.h
index 1e7184e4311d..c7cd27efac8a 100644
--- a/drivers/staging/media/ipu3/include/intel-ipu3.h
+++ b/drivers/staging/media/ipu3/include/intel-ipu3.h
@@ -2472,7 +2472,7 @@ struct ipu3_uapi_acc_param {
struct ipu3_uapi_yuvp1_yds_config yds2 __attribute__((aligned(32)));
struct ipu3_uapi_yuvp2_tcc_static_config tcc __attribute__((aligned(32)));
struct ipu3_uapi_anr_config anr;
- struct ipu3_uapi_awb_fr_config_s awb_fr;
+ struct ipu3_uapi_awb_fr_config_s awb_fr __attribute__((aligned(32)));
struct ipu3_uapi_ae_config ae;
struct ipu3_uapi_af_config_s af;
struct ipu3_uapi_awb_config awb;
diff --git a/drivers/staging/media/ipu3/ipu3-css-fw.c b/drivers/staging/media/ipu3/ipu3-css-fw.c
index 4122d4e42db6..45aff76198e2 100644
--- a/drivers/staging/media/ipu3/ipu3-css-fw.c
+++ b/drivers/staging/media/ipu3/ipu3-css-fw.c
@@ -200,13 +200,11 @@ int imgu_css_fw_init(struct imgu_css *css)
goto bad_fw;
for (j = 0; j < bi->info.isp.num_output_formats; j++)
- if (bi->info.isp.output_formats[j] < 0 ||
- bi->info.isp.output_formats[j] >=
+ if (bi->info.isp.output_formats[j] >=
IMGU_ABI_FRAME_FORMAT_NUM)
goto bad_fw;
for (j = 0; j < bi->info.isp.num_vf_formats; j++)
- if (bi->info.isp.vf_formats[j] < 0 ||
- bi->info.isp.vf_formats[j] >=
+ if (bi->info.isp.vf_formats[j] >=
IMGU_ABI_FRAME_FORMAT_NUM)
goto bad_fw;
diff --git a/drivers/staging/media/ipu3/ipu3-css.c b/drivers/staging/media/ipu3/ipu3-css.c
index 23cf5b2cfe8b..fd1ed84c400c 100644
--- a/drivers/staging/media/ipu3/ipu3-css.c
+++ b/drivers/staging/media/ipu3/ipu3-css.c
@@ -24,9 +24,8 @@
#define IPU3_CSS_MAX_H 3136
#define IPU3_CSS_MAX_W 4224
-/* filter size from graph settings is fixed as 4 */
-#define FILTER_SIZE 4
-#define MIN_ENVELOPE 8
+/* minimal envelope size(GDC in - out) should be 4 */
+#define MIN_ENVELOPE 4
/*
* pre-allocated buffer size for CSS ABI, auxiliary frames
@@ -1827,9 +1826,9 @@ int imgu_css_fmt_try(struct imgu_css *css,
vf->width = imgu_css_adjust(vf->width, VF_ALIGN_W);
vf->height = imgu_css_adjust(vf->height, 1);
- s = (bds->width - gdc->width) / 2 - FILTER_SIZE;
+ s = (bds->width - gdc->width) / 2;
env->width = s < MIN_ENVELOPE ? MIN_ENVELOPE : s;
- s = (bds->height - gdc->height) / 2 - FILTER_SIZE;
+ s = (bds->height - gdc->height) / 2;
env->height = s < MIN_ENVELOPE ? MIN_ENVELOPE : s;
ret = imgu_css_find_binary(css, pipe, q, r);
@@ -2251,9 +2250,8 @@ int imgu_css_set_parameters(struct imgu_css *css, unsigned int pipe,
css_pipe->aux_frames[a].height,
css_pipe->rect[g].width,
css_pipe->rect[g].height,
- css_pipe->rect[e].width + FILTER_SIZE,
- css_pipe->rect[e].height +
- FILTER_SIZE);
+ css_pipe->rect[e].width,
+ css_pipe->rect[e].height);
}
}
diff --git a/drivers/staging/media/ipu3/ipu3-dmamap.c b/drivers/staging/media/ipu3/ipu3-dmamap.c
index d978a00e1e0b..7431322379f6 100644
--- a/drivers/staging/media/ipu3/ipu3-dmamap.c
+++ b/drivers/staging/media/ipu3/ipu3-dmamap.c
@@ -31,12 +31,11 @@ static void imgu_dmamap_free_buffer(struct page **pages,
* Based on the implementation of __iommu_dma_alloc_pages()
* defined in drivers/iommu/dma-iommu.c
*/
-static struct page **imgu_dmamap_alloc_buffer(size_t size,
- unsigned long order_mask,
- gfp_t gfp)
+static struct page **imgu_dmamap_alloc_buffer(size_t size, gfp_t gfp)
{
struct page **pages;
unsigned int i = 0, count = size >> PAGE_SHIFT;
+ unsigned int order_mask = 1;
const gfp_t high_order_gfp = __GFP_NOWARN | __GFP_NORETRY;
/* Allocate mem for array of page ptrs */
@@ -45,10 +44,6 @@ static struct page **imgu_dmamap_alloc_buffer(size_t size,
if (!pages)
return NULL;
- order_mask &= (2U << MAX_ORDER) - 1;
- if (!order_mask)
- return NULL;
-
gfp |= __GFP_HIGHMEM | __GFP_ZERO;
while (count) {
@@ -99,7 +94,6 @@ void *imgu_dmamap_alloc(struct imgu_device *imgu, struct imgu_css_map *map,
size_t len)
{
unsigned long shift = iova_shift(&imgu->iova_domain);
- unsigned int alloc_sizes = imgu->mmu->pgsize_bitmap;
struct device *dev = &imgu->pci_dev->dev;
size_t size = PAGE_ALIGN(len);
struct page **pages;
@@ -114,8 +108,7 @@ void *imgu_dmamap_alloc(struct imgu_device *imgu, struct imgu_css_map *map,
if (!iova)
return NULL;
- pages = imgu_dmamap_alloc_buffer(size, alloc_sizes >> PAGE_SHIFT,
- GFP_KERNEL);
+ pages = imgu_dmamap_alloc_buffer(size, GFP_KERNEL);
if (!pages)
goto out_free_iova;
@@ -257,7 +250,7 @@ int imgu_dmamap_init(struct imgu_device *imgu)
if (ret)
return ret;
- order = __ffs(imgu->mmu->pgsize_bitmap);
+ order = __ffs(IPU3_PAGE_SIZE);
base_pfn = max_t(unsigned long, 1, imgu->mmu->aperture_start >> order);
init_iova_domain(&imgu->iova_domain, 1UL << order, base_pfn);
diff --git a/drivers/staging/media/ipu3/ipu3-mmu.c b/drivers/staging/media/ipu3/ipu3-mmu.c
index cfc2bdfb14b3..3d969b0522ab 100644
--- a/drivers/staging/media/ipu3/ipu3-mmu.c
+++ b/drivers/staging/media/ipu3/ipu3-mmu.c
@@ -20,9 +20,6 @@
#include "ipu3-mmu.h"
-#define IPU3_PAGE_SHIFT 12
-#define IPU3_PAGE_SIZE (1UL << IPU3_PAGE_SHIFT)
-
#define IPU3_PT_BITS 10
#define IPU3_PT_PTES (1UL << IPU3_PT_BITS)
#define IPU3_PT_SIZE (IPU3_PT_PTES << 2)
@@ -238,62 +235,31 @@ static int __imgu_mmu_map(struct imgu_mmu *mmu, unsigned long iova,
return 0;
}
-/*
- * The following four functions are implemented based on iommu.c
- * drivers/iommu/iommu.c/iommu_pgsize().
+/**
+ * imgu_mmu_map - map a buffer to a physical address
+ *
+ * @info: MMU mappable range
+ * @iova: the virtual address
+ * @paddr: the physical address
+ * @size: length of the mappable area
+ *
+ * The function has been adapted from iommu_map() in
+ * drivers/iommu/iommu.c .
*/
-static size_t imgu_mmu_pgsize(unsigned long pgsize_bitmap,
- unsigned long addr_merge, size_t size)
-{
- unsigned int pgsize_idx;
- size_t pgsize;
-
- /* Max page size that still fits into 'size' */
- pgsize_idx = __fls(size);
-
- /* need to consider alignment requirements ? */
- if (likely(addr_merge)) {
- /* Max page size allowed by address */
- unsigned int align_pgsize_idx = __ffs(addr_merge);
-
- pgsize_idx = min(pgsize_idx, align_pgsize_idx);
- }
-
- /* build a mask of acceptable page sizes */
- pgsize = (1UL << (pgsize_idx + 1)) - 1;
-
- /* throw away page sizes not supported by the hardware */
- pgsize &= pgsize_bitmap;
-
- /* make sure we're still sane */
- WARN_ON(!pgsize);
-
- /* pick the biggest page */
- pgsize_idx = __fls(pgsize);
- pgsize = 1UL << pgsize_idx;
-
- return pgsize;
-}
-
-/* drivers/iommu/iommu.c/iommu_map() */
int imgu_mmu_map(struct imgu_mmu_info *info, unsigned long iova,
phys_addr_t paddr, size_t size)
{
struct imgu_mmu *mmu = to_imgu_mmu(info);
- unsigned int min_pagesz;
int ret = 0;
- /* find out the minimum page size supported */
- min_pagesz = 1 << __ffs(mmu->geometry.pgsize_bitmap);
-
/*
* both the virtual address and the physical one, as well as
* the size of the mapping, must be aligned (at least) to the
* size of the smallest page supported by the hardware
*/
- if (!IS_ALIGNED(iova | paddr | size, min_pagesz)) {
- dev_err(mmu->dev, "unaligned: iova 0x%lx pa %pa size 0x%zx min_pagesz 0x%x\n",
- iova, &paddr, size, min_pagesz);
+ if (!IS_ALIGNED(iova | paddr | size, IPU3_PAGE_SIZE)) {
+ dev_err(mmu->dev, "unaligned: iova 0x%lx pa %pa size 0x%zx\n",
+ iova, &paddr, size);
return -EINVAL;
}
@@ -301,19 +267,15 @@ int imgu_mmu_map(struct imgu_mmu_info *info, unsigned long iova,
iova, &paddr, size);
while (size) {
- size_t pgsize = imgu_mmu_pgsize(mmu->geometry.pgsize_bitmap,
- iova | paddr, size);
-
- dev_dbg(mmu->dev, "mapping: iova 0x%lx pa %pa pgsize 0x%zx\n",
- iova, &paddr, pgsize);
+ dev_dbg(mmu->dev, "mapping: iova 0x%lx pa %pa\n", iova, &paddr);
ret = __imgu_mmu_map(mmu, iova, paddr);
if (ret)
break;
- iova += pgsize;
- paddr += pgsize;
- size -= pgsize;
+ iova += IPU3_PAGE_SIZE;
+ paddr += IPU3_PAGE_SIZE;
+ size -= IPU3_PAGE_SIZE;
}
call_if_imgu_is_powered(mmu, imgu_mmu_tlb_invalidate);
@@ -321,28 +283,36 @@ int imgu_mmu_map(struct imgu_mmu_info *info, unsigned long iova,
return ret;
}
-/* drivers/iommu/iommu.c/default_iommu_map_sg() */
+/**
+ * imgu_mmu_map_sg - Map a scatterlist
+ *
+ * @info: MMU mappable range
+ * @iova: the virtual address
+ * @sg: the scatterlist to map
+ * @nents: number of entries in the scatterlist
+ *
+ * The function has been adapted from default_iommu_map_sg() in
+ * drivers/iommu/iommu.c .
+ */
size_t imgu_mmu_map_sg(struct imgu_mmu_info *info, unsigned long iova,
struct scatterlist *sg, unsigned int nents)
{
struct imgu_mmu *mmu = to_imgu_mmu(info);
struct scatterlist *s;
size_t s_length, mapped = 0;
- unsigned int i, min_pagesz;
+ unsigned int i;
int ret;
- min_pagesz = 1 << __ffs(mmu->geometry.pgsize_bitmap);
-
for_each_sg(sg, s, nents, i) {
phys_addr_t phys = page_to_phys(sg_page(s)) + s->offset;
s_length = s->length;
- if (!IS_ALIGNED(s->offset, min_pagesz))
+ if (!IS_ALIGNED(s->offset, IPU3_PAGE_SIZE))
goto out_err;
- /* must be min_pagesz aligned to be mapped singlely */
- if (i == nents - 1 && !IS_ALIGNED(s->length, min_pagesz))
+ /* must be IPU3_PAGE_SIZE aligned to be mapped singlely */
+ if (i == nents - 1 && !IS_ALIGNED(s->length, IPU3_PAGE_SIZE))
s_length = PAGE_ALIGN(s->length);
ret = imgu_mmu_map(info, iova + mapped, phys, s_length);
@@ -394,25 +364,30 @@ static size_t __imgu_mmu_unmap(struct imgu_mmu *mmu,
return unmap;
}
-/* drivers/iommu/iommu.c/iommu_unmap() */
+/**
+ * imgu_mmu_unmap - Unmap a buffer
+ *
+ * @info: MMU mappable range
+ * @iova: the virtual address
+ * @size: the length of the buffer
+ *
+ * The function has been adapted from iommu_unmap() in
+ * drivers/iommu/iommu.c .
+ */
size_t imgu_mmu_unmap(struct imgu_mmu_info *info, unsigned long iova,
size_t size)
{
struct imgu_mmu *mmu = to_imgu_mmu(info);
size_t unmapped_page, unmapped = 0;
- unsigned int min_pagesz;
-
- /* find out the minimum page size supported */
- min_pagesz = 1 << __ffs(mmu->geometry.pgsize_bitmap);
/*
* The virtual address, as well as the size of the mapping, must be
* aligned (at least) to the size of the smallest page supported
* by the hardware
*/
- if (!IS_ALIGNED(iova | size, min_pagesz)) {
- dev_err(mmu->dev, "unaligned: iova 0x%lx size 0x%zx min_pagesz 0x%x\n",
- iova, size, min_pagesz);
+ if (!IS_ALIGNED(iova | size, IPU3_PAGE_SIZE)) {
+ dev_err(mmu->dev, "unaligned: iova 0x%lx size 0x%zx\n",
+ iova, size);
return -EINVAL;
}
@@ -423,10 +398,7 @@ size_t imgu_mmu_unmap(struct imgu_mmu_info *info, unsigned long iova,
* or we hit an area that isn't mapped.
*/
while (unmapped < size) {
- size_t pgsize = imgu_mmu_pgsize(mmu->geometry.pgsize_bitmap,
- iova, size - unmapped);
-
- unmapped_page = __imgu_mmu_unmap(mmu, iova, pgsize);
+ unmapped_page = __imgu_mmu_unmap(mmu, iova, IPU3_PAGE_SIZE);
if (!unmapped_page)
break;
@@ -444,6 +416,7 @@ size_t imgu_mmu_unmap(struct imgu_mmu_info *info, unsigned long iova,
/**
* imgu_mmu_init() - initialize IPU3 MMU block
+ *
* @parent: struct device parent
* @base: IOMEM base of hardware registers.
*
@@ -505,7 +478,6 @@ struct imgu_mmu_info *imgu_mmu_init(struct device *parent, void __iomem *base)
mmu->geometry.aperture_start = 0;
mmu->geometry.aperture_end = DMA_BIT_MASK(IPU3_MMU_ADDRESS_BITS);
- mmu->geometry.pgsize_bitmap = IPU3_PAGE_SIZE;
return &mmu->geometry;
@@ -523,7 +495,8 @@ fail_group:
/**
* imgu_mmu_exit() - clean up IPU3 MMU block
- * @info: IPU3 MMU private data
+ *
+ * @info: MMU mappable range
*/
void imgu_mmu_exit(struct imgu_mmu_info *info)
{
diff --git a/drivers/staging/media/ipu3/ipu3-mmu.h b/drivers/staging/media/ipu3/ipu3-mmu.h
index fa58827eb19c..a5f0bca7e7e0 100644
--- a/drivers/staging/media/ipu3/ipu3-mmu.h
+++ b/drivers/staging/media/ipu3/ipu3-mmu.h
@@ -5,17 +5,18 @@
#ifndef __IPU3_MMU_H
#define __IPU3_MMU_H
+#define IPU3_PAGE_SHIFT 12
+#define IPU3_PAGE_SIZE (1UL << IPU3_PAGE_SHIFT)
+
/**
* struct imgu_mmu_info - Describes mmu geometry
*
* @aperture_start: First address that can be mapped
* @aperture_end: Last address that can be mapped
- * @pgsize_bitmap: Bitmap of page sizes in use
*/
struct imgu_mmu_info {
dma_addr_t aperture_start;
dma_addr_t aperture_end;
- unsigned long pgsize_bitmap;
};
struct device;
diff --git a/drivers/staging/media/ipu3/ipu3-v4l2.c b/drivers/staging/media/ipu3/ipu3-v4l2.c
index a7bc22040ed8..3c7ad1eed434 100644
--- a/drivers/staging/media/ipu3/ipu3-v4l2.c
+++ b/drivers/staging/media/ipu3/ipu3-v4l2.c
@@ -955,12 +955,12 @@ static const struct v4l2_file_operations imgu_v4l2_fops = {
static const struct v4l2_ioctl_ops imgu_v4l2_ioctl_ops = {
.vidioc_querycap = imgu_vidioc_querycap,
- .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
.vidioc_g_fmt_vid_cap_mplane = imgu_vidioc_g_fmt,
.vidioc_s_fmt_vid_cap_mplane = imgu_vidioc_s_fmt,
.vidioc_try_fmt_vid_cap_mplane = imgu_vidioc_try_fmt,
- .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out,
+ .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
.vidioc_g_fmt_vid_out_mplane = imgu_vidioc_g_fmt,
.vidioc_s_fmt_vid_out_mplane = imgu_vidioc_s_fmt,
.vidioc_try_fmt_vid_out_mplane = imgu_vidioc_try_fmt,
diff --git a/drivers/staging/media/meson/vdec/Kconfig b/drivers/staging/media/meson/vdec/Kconfig
new file mode 100644
index 000000000000..9e1450193392
--- /dev/null
+++ b/drivers/staging/media/meson/vdec/Kconfig
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config VIDEO_MESON_VDEC
+ tristate "Amlogic video decoder driver"
+ depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA
+ depends on ARCH_MESON || COMPILE_TEST
+ select VIDEOBUF2_DMA_CONTIG
+ select V4L2_MEM2MEM_DEV
+ select MESON_CANVAS
+ help
+ Support for the video decoder found in gxbb/gxl/gxm chips.
diff --git a/drivers/staging/media/meson/vdec/Makefile b/drivers/staging/media/meson/vdec/Makefile
new file mode 100644
index 000000000000..6bea129084b7
--- /dev/null
+++ b/drivers/staging/media/meson/vdec/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0
+# Makefile for Amlogic meson video decoder driver
+
+meson-vdec-objs = esparser.o vdec.o vdec_helpers.o vdec_platform.o
+meson-vdec-objs += vdec_1.o
+meson-vdec-objs += codec_mpeg12.o
+
+obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o
diff --git a/drivers/staging/media/meson/vdec/TODO b/drivers/staging/media/meson/vdec/TODO
new file mode 100644
index 000000000000..70ae990cf13b
--- /dev/null
+++ b/drivers/staging/media/meson/vdec/TODO
@@ -0,0 +1,8 @@
+This driver is in staging until the V4L2 documentation about stateful video
+decoders is finalized, as well as the corresponding compliance tests.
+
+It is at the moment not guaranteed to work properly with a userspace
+stack that follows the latest version of the specification, especially
+with compression standards like MPEG1/2 where the driver does not support
+dynamic resolution switching, including the first one used to determine coded
+resolution.
diff --git a/drivers/staging/media/meson/vdec/codec_mpeg12.c b/drivers/staging/media/meson/vdec/codec_mpeg12.c
new file mode 100644
index 000000000000..48869cc3d973
--- /dev/null
+++ b/drivers/staging/media/meson/vdec/codec_mpeg12.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 BayLibre, SAS
+ * Author: Maxime Jourdan <mjourdan@baylibre.com>
+ */
+
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "codec_mpeg12.h"
+#include "dos_regs.h"
+#include "vdec_helpers.h"
+
+#define SIZE_WORKSPACE SZ_128K
+/* Offset substracted by the firmware from the workspace paddr */
+#define WORKSPACE_OFFSET (5 * SZ_1K)
+
+/* map firmware registers to known MPEG1/2 functions */
+#define MREG_SEQ_INFO AV_SCRATCH_4
+ #define MPEG2_SEQ_DAR_MASK GENMASK(3, 0)
+ #define MPEG2_DAR_4_3 2
+ #define MPEG2_DAR_16_9 3
+ #define MPEG2_DAR_221_100 4
+#define MREG_PIC_INFO AV_SCRATCH_5
+#define MREG_PIC_WIDTH AV_SCRATCH_6
+#define MREG_PIC_HEIGHT AV_SCRATCH_7
+#define MREG_BUFFERIN AV_SCRATCH_8
+#define MREG_BUFFEROUT AV_SCRATCH_9
+#define MREG_CMD AV_SCRATCH_A
+#define MREG_CO_MV_START AV_SCRATCH_B
+#define MREG_ERROR_COUNT AV_SCRATCH_C
+#define MREG_FRAME_OFFSET AV_SCRATCH_D
+#define MREG_WAIT_BUFFER AV_SCRATCH_E
+#define MREG_FATAL_ERROR AV_SCRATCH_F
+
+#define PICINFO_PROG 0x00008000
+#define PICINFO_TOP_FIRST 0x00002000
+
+struct codec_mpeg12 {
+ /* Buffer for the MPEG1/2 Workspace */
+ void *workspace_vaddr;
+ dma_addr_t workspace_paddr;
+};
+
+static const u8 eos_sequence[SZ_1K] = { 0x00, 0x00, 0x01, 0xB7 };
+
+static const u8 *codec_mpeg12_eos_sequence(u32 *len)
+{
+ *len = ARRAY_SIZE(eos_sequence);
+ return eos_sequence;
+}
+
+static int codec_mpeg12_can_recycle(struct amvdec_core *core)
+{
+ return !amvdec_read_dos(core, MREG_BUFFERIN);
+}
+
+static void codec_mpeg12_recycle(struct amvdec_core *core, u32 buf_idx)
+{
+ amvdec_write_dos(core, MREG_BUFFERIN, buf_idx + 1);
+}
+
+static int codec_mpeg12_start(struct amvdec_session *sess)
+{
+ struct amvdec_core *core = sess->core;
+ struct codec_mpeg12 *mpeg12;
+ int ret;
+
+ mpeg12 = kzalloc(sizeof(*mpeg12), GFP_KERNEL);
+ if (!mpeg12)
+ return -ENOMEM;
+
+ /* Allocate some memory for the MPEG1/2 decoder's state */
+ mpeg12->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE,
+ &mpeg12->workspace_paddr,
+ GFP_KERNEL);
+ if (!mpeg12->workspace_vaddr) {
+ dev_err(core->dev, "Failed to request MPEG 1/2 Workspace\n");
+ ret = -ENOMEM;
+ goto free_mpeg12;
+ }
+
+ ret = amvdec_set_canvases(sess, (u32[]){ AV_SCRATCH_0, 0 },
+ (u32[]){ 8, 0 });
+ if (ret)
+ goto free_workspace;
+
+ amvdec_write_dos(core, POWER_CTL_VLD, BIT(4));
+ amvdec_write_dos(core, MREG_CO_MV_START,
+ mpeg12->workspace_paddr + WORKSPACE_OFFSET);
+
+ amvdec_write_dos(core, MPEG1_2_REG, 0);
+ amvdec_write_dos(core, PSCALE_CTRL, 0);
+ amvdec_write_dos(core, PIC_HEAD_INFO, 0x380);
+ amvdec_write_dos(core, M4_CONTROL_REG, 0);
+ amvdec_write_dos(core, MREG_BUFFERIN, 0);
+ amvdec_write_dos(core, MREG_BUFFEROUT, 0);
+ amvdec_write_dos(core, MREG_CMD, (sess->width << 16) | sess->height);
+ amvdec_write_dos(core, MREG_ERROR_COUNT, 0);
+ amvdec_write_dos(core, MREG_FATAL_ERROR, 0);
+ amvdec_write_dos(core, MREG_WAIT_BUFFER, 0);
+
+ sess->keyframe_found = 1;
+ sess->priv = mpeg12;
+
+ return 0;
+
+free_workspace:
+ dma_free_coherent(core->dev, SIZE_WORKSPACE, mpeg12->workspace_vaddr,
+ mpeg12->workspace_paddr);
+free_mpeg12:
+ kfree(mpeg12);
+
+ return ret;
+}
+
+static int codec_mpeg12_stop(struct amvdec_session *sess)
+{
+ struct codec_mpeg12 *mpeg12 = sess->priv;
+ struct amvdec_core *core = sess->core;
+
+ if (mpeg12->workspace_vaddr)
+ dma_free_coherent(core->dev, SIZE_WORKSPACE,
+ mpeg12->workspace_vaddr,
+ mpeg12->workspace_paddr);
+
+ return 0;
+}
+
+static void codec_mpeg12_update_dar(struct amvdec_session *sess)
+{
+ struct amvdec_core *core = sess->core;
+ u32 seq = amvdec_read_dos(core, MREG_SEQ_INFO);
+ u32 ar = seq & MPEG2_SEQ_DAR_MASK;
+
+ switch (ar) {
+ case MPEG2_DAR_4_3:
+ amvdec_set_par_from_dar(sess, 4, 3);
+ break;
+ case MPEG2_DAR_16_9:
+ amvdec_set_par_from_dar(sess, 16, 9);
+ break;
+ case MPEG2_DAR_221_100:
+ amvdec_set_par_from_dar(sess, 221, 100);
+ break;
+ default:
+ sess->pixelaspect.numerator = 1;
+ sess->pixelaspect.denominator = 1;
+ break;
+ }
+}
+
+static irqreturn_t codec_mpeg12_threaded_isr(struct amvdec_session *sess)
+{
+ struct amvdec_core *core = sess->core;
+ u32 reg;
+ u32 pic_info;
+ u32 is_progressive;
+ u32 buffer_index;
+ u32 field = V4L2_FIELD_NONE;
+ u32 offset;
+
+ amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1);
+ reg = amvdec_read_dos(core, MREG_FATAL_ERROR);
+ if (reg == 1) {
+ dev_err(core->dev, "MPEG1/2 fatal error\n");
+ amvdec_abort(sess);
+ return IRQ_HANDLED;
+ }
+
+ reg = amvdec_read_dos(core, MREG_BUFFEROUT);
+ if (!reg)
+ return IRQ_HANDLED;
+
+ /* Unclear what this means */
+ if ((reg & GENMASK(23, 17)) == GENMASK(23, 17))
+ goto end;
+
+ pic_info = amvdec_read_dos(core, MREG_PIC_INFO);
+ is_progressive = pic_info & PICINFO_PROG;
+
+ if (!is_progressive)
+ field = (pic_info & PICINFO_TOP_FIRST) ?
+ V4L2_FIELD_INTERLACED_TB :
+ V4L2_FIELD_INTERLACED_BT;
+
+ codec_mpeg12_update_dar(sess);
+ buffer_index = ((reg & 0xf) - 1) & 7;
+ offset = amvdec_read_dos(core, MREG_FRAME_OFFSET);
+ amvdec_dst_buf_done_idx(sess, buffer_index, offset, field);
+
+end:
+ amvdec_write_dos(core, MREG_BUFFEROUT, 0);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t codec_mpeg12_isr(struct amvdec_session *sess)
+{
+ return IRQ_WAKE_THREAD;
+}
+
+struct amvdec_codec_ops codec_mpeg12_ops = {
+ .start = codec_mpeg12_start,
+ .stop = codec_mpeg12_stop,
+ .isr = codec_mpeg12_isr,
+ .threaded_isr = codec_mpeg12_threaded_isr,
+ .can_recycle = codec_mpeg12_can_recycle,
+ .recycle = codec_mpeg12_recycle,
+ .eos_sequence = codec_mpeg12_eos_sequence,
+};
diff --git a/drivers/staging/media/meson/vdec/codec_mpeg12.h b/drivers/staging/media/meson/vdec/codec_mpeg12.h
new file mode 100644
index 000000000000..43cab5f39ca0
--- /dev/null
+++ b/drivers/staging/media/meson/vdec/codec_mpeg12.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2018 BayLibre, SAS
+ * Author: Maxime Jourdan <mjourdan@baylibre.com>
+ */
+
+#ifndef __MESON_VDEC_CODEC_MPEG12_H_
+#define __MESON_VDEC_CODEC_MPEG12_H_
+
+#include "vdec.h"
+
+extern struct amvdec_codec_ops codec_mpeg12_ops;
+
+#endif
diff --git a/drivers/staging/media/meson/vdec/dos_regs.h b/drivers/staging/media/meson/vdec/dos_regs.h
new file mode 100644
index 000000000000..abd810542dbb
--- /dev/null
+++ b/drivers/staging/media/meson/vdec/dos_regs.h
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2018 BayLibre, SAS
+ * Author: Maxime Jourdan <mjourdan@baylibre.com>
+ */
+
+#ifndef __MESON_VDEC_DOS_REGS_H_
+#define __MESON_VDEC_DOS_REGS_H_
+
+/* DOS registers */
+#define VDEC_ASSIST_AMR1_INT8 0x00b4
+
+#define ASSIST_MBOX1_CLR_REG 0x01d4
+#define ASSIST_MBOX1_MASK 0x01d8
+
+#define MPSR 0x0c04
+#define MCPU_INTR_MSK 0x0c10
+#define CPSR 0x0c84
+
+#define IMEM_DMA_CTRL 0x0d00
+#define IMEM_DMA_ADR 0x0d04
+#define IMEM_DMA_COUNT 0x0d08
+#define LMEM_DMA_CTRL 0x0d40
+
+#define MC_STATUS0 0x2424
+#define MC_CTRL1 0x242c
+
+#define PSCALE_RST 0x2440
+#define PSCALE_CTRL 0x2444
+#define PSCALE_BMEM_ADDR 0x247c
+#define PSCALE_BMEM_DAT 0x2480
+
+#define DBLK_CTRL 0x2544
+#define DBLK_STATUS 0x254c
+
+#define GCLK_EN 0x260c
+#define MDEC_PIC_DC_CTRL 0x2638
+#define MDEC_PIC_DC_STATUS 0x263c
+#define ANC0_CANVAS_ADDR 0x2640
+#define MDEC_PIC_DC_THRESH 0x26e0
+
+/* Firmware interface registers */
+#define AV_SCRATCH_0 0x2700
+#define AV_SCRATCH_1 0x2704
+#define AV_SCRATCH_2 0x2708
+#define AV_SCRATCH_3 0x270c
+#define AV_SCRATCH_4 0x2710
+#define AV_SCRATCH_5 0x2714
+#define AV_SCRATCH_6 0x2718
+#define AV_SCRATCH_7 0x271c
+#define AV_SCRATCH_8 0x2720
+#define AV_SCRATCH_9 0x2724
+#define AV_SCRATCH_A 0x2728
+#define AV_SCRATCH_B 0x272c
+#define AV_SCRATCH_C 0x2730
+#define AV_SCRATCH_D 0x2734
+#define AV_SCRATCH_E 0x2738
+#define AV_SCRATCH_F 0x273c
+#define AV_SCRATCH_G 0x2740
+#define AV_SCRATCH_H 0x2744
+#define AV_SCRATCH_I 0x2748
+#define AV_SCRATCH_J 0x274c
+#define AV_SCRATCH_K 0x2750
+#define AV_SCRATCH_L 0x2754
+
+#define MPEG1_2_REG 0x3004
+#define PIC_HEAD_INFO 0x300c
+#define POWER_CTL_VLD 0x3020
+#define M4_CONTROL_REG 0x30a4
+
+/* Stream Buffer (stbuf) regs */
+#define VLD_MEM_VIFIFO_START_PTR 0x3100
+#define VLD_MEM_VIFIFO_CURR_PTR 0x3104
+#define VLD_MEM_VIFIFO_END_PTR 0x3108
+#define VLD_MEM_VIFIFO_CONTROL 0x3110
+ #define MEM_FIFO_CNT_BIT 16
+ #define MEM_FILL_ON_LEVEL BIT(10)
+ #define MEM_CTRL_EMPTY_EN BIT(2)
+ #define MEM_CTRL_FILL_EN BIT(1)
+#define VLD_MEM_VIFIFO_WP 0x3114
+#define VLD_MEM_VIFIFO_RP 0x3118
+#define VLD_MEM_VIFIFO_LEVEL 0x311c
+#define VLD_MEM_VIFIFO_BUF_CNTL 0x3120
+ #define MEM_BUFCTRL_MANUAL BIT(1)
+#define VLD_MEM_VIFIFO_WRAP_COUNT 0x3144
+
+#define DCAC_DMA_CTRL 0x3848
+
+#define DOS_SW_RESET0 0xfc00
+#define DOS_GCLK_EN0 0xfc04
+#define DOS_GEN_CTRL0 0xfc08
+#define DOS_MEM_PD_VDEC 0xfcc0
+#define DOS_MEM_PD_HEVC 0xfccc
+#define DOS_SW_RESET3 0xfcd0
+#define DOS_GCLK_EN3 0xfcd4
+#define DOS_VDEC_MCRCC_STALL_CTRL 0xfd00
+
+#endif
diff --git a/drivers/staging/media/meson/vdec/esparser.c b/drivers/staging/media/meson/vdec/esparser.c
new file mode 100644
index 000000000000..3a21a8cec799
--- /dev/null
+++ b/drivers/staging/media/meson/vdec/esparser.c
@@ -0,0 +1,324 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 BayLibre, SAS
+ * Author: Maxime Jourdan <mjourdan@baylibre.com>
+ *
+ * The Elementary Stream Parser is a HW bitstream parser.
+ * It reads bitstream buffers and feeds them to the VIFIFO
+ */
+
+#include <linux/init.h>
+#include <linux/ioctl.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/reset.h>
+#include <linux/interrupt.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "dos_regs.h"
+#include "esparser.h"
+#include "vdec_helpers.h"
+
+/* PARSER REGS (CBUS) */
+#define PARSER_CONTROL 0x00
+ #define ES_PACK_SIZE_BIT 8
+ #define ES_WRITE BIT(5)
+ #define ES_SEARCH BIT(1)
+ #define ES_PARSER_START BIT(0)
+#define PARSER_FETCH_ADDR 0x4
+#define PARSER_FETCH_CMD 0x8
+#define PARSER_CONFIG 0x14
+ #define PS_CFG_MAX_FETCH_CYCLE_BIT 0
+ #define PS_CFG_STARTCODE_WID_24_BIT 10
+ #define PS_CFG_MAX_ES_WR_CYCLE_BIT 12
+ #define PS_CFG_PFIFO_EMPTY_CNT_BIT 16
+#define PFIFO_WR_PTR 0x18
+#define PFIFO_RD_PTR 0x1c
+#define PARSER_SEARCH_PATTERN 0x24
+ #define ES_START_CODE_PATTERN 0x00000100
+#define PARSER_SEARCH_MASK 0x28
+ #define ES_START_CODE_MASK 0xffffff00
+ #define FETCH_ENDIAN_BIT 27
+#define PARSER_INT_ENABLE 0x2c
+ #define PARSER_INT_HOST_EN_BIT 8
+#define PARSER_INT_STATUS 0x30
+ #define PARSER_INTSTAT_SC_FOUND 1
+#define PARSER_ES_CONTROL 0x5c
+#define PARSER_VIDEO_START_PTR 0x80
+#define PARSER_VIDEO_END_PTR 0x84
+#define PARSER_VIDEO_WP 0x88
+#define PARSER_VIDEO_HOLE 0x90
+
+#define SEARCH_PATTERN_LEN 512
+
+static DECLARE_WAIT_QUEUE_HEAD(wq);
+static int search_done;
+
+static irqreturn_t esparser_isr(int irq, void *dev)
+{
+ int int_status;
+ struct amvdec_core *core = dev;
+
+ int_status = amvdec_read_parser(core, PARSER_INT_STATUS);
+ amvdec_write_parser(core, PARSER_INT_STATUS, int_status);
+
+ if (int_status & PARSER_INTSTAT_SC_FOUND) {
+ amvdec_write_parser(core, PFIFO_RD_PTR, 0);
+ amvdec_write_parser(core, PFIFO_WR_PTR, 0);
+ search_done = 1;
+ wake_up_interruptible(&wq);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/* Pad the packet to at least 4KiB bytes otherwise the VDEC unit won't trigger
+ * ISRs.
+ * Also append a start code 000001ff at the end to trigger
+ * the ESPARSER interrupt.
+ */
+static u32 esparser_pad_start_code(struct vb2_buffer *vb)
+{
+ u32 payload_size = vb2_get_plane_payload(vb, 0);
+ u32 pad_size = 0;
+ u8 *vaddr = vb2_plane_vaddr(vb, 0) + payload_size;
+
+ if (payload_size < ESPARSER_MIN_PACKET_SIZE) {
+ pad_size = ESPARSER_MIN_PACKET_SIZE - payload_size;
+ memset(vaddr, 0, pad_size);
+ }
+
+ memset(vaddr + pad_size, 0, SEARCH_PATTERN_LEN);
+ vaddr[pad_size] = 0x00;
+ vaddr[pad_size + 1] = 0x00;
+ vaddr[pad_size + 2] = 0x01;
+ vaddr[pad_size + 3] = 0xff;
+
+ return pad_size;
+}
+
+static int
+esparser_write_data(struct amvdec_core *core, dma_addr_t addr, u32 size)
+{
+ amvdec_write_parser(core, PFIFO_RD_PTR, 0);
+ amvdec_write_parser(core, PFIFO_WR_PTR, 0);
+ amvdec_write_parser(core, PARSER_CONTROL,
+ ES_WRITE |
+ ES_PARSER_START |
+ ES_SEARCH |
+ (size << ES_PACK_SIZE_BIT));
+
+ amvdec_write_parser(core, PARSER_FETCH_ADDR, addr);
+ amvdec_write_parser(core, PARSER_FETCH_CMD,
+ (7 << FETCH_ENDIAN_BIT) |
+ (size + SEARCH_PATTERN_LEN));
+
+ search_done = 0;
+ return wait_event_interruptible_timeout(wq, search_done, (HZ / 5));
+}
+
+static u32 esparser_vififo_get_free_space(struct amvdec_session *sess)
+{
+ u32 vififo_usage;
+ struct amvdec_ops *vdec_ops = sess->fmt_out->vdec_ops;
+ struct amvdec_core *core = sess->core;
+
+ vififo_usage = vdec_ops->vififo_level(sess);
+ vififo_usage += amvdec_read_parser(core, PARSER_VIDEO_HOLE);
+ vififo_usage += (6 * SZ_1K); // 6 KiB internal fifo
+
+ if (vififo_usage > sess->vififo_size) {
+ dev_warn(sess->core->dev,
+ "VIFIFO usage (%u) > VIFIFO size (%u)\n",
+ vififo_usage, sess->vififo_size);
+ return 0;
+ }
+
+ return sess->vififo_size - vififo_usage;
+}
+
+int esparser_queue_eos(struct amvdec_core *core, const u8 *data, u32 len)
+{
+ struct device *dev = core->dev;
+ void *eos_vaddr;
+ dma_addr_t eos_paddr;
+ int ret;
+
+ eos_vaddr = dma_alloc_coherent(dev, len + SEARCH_PATTERN_LEN,
+ &eos_paddr, GFP_KERNEL);
+ if (!eos_vaddr)
+ return -ENOMEM;
+
+ memcpy(eos_vaddr, data, len);
+ ret = esparser_write_data(core, eos_paddr, len);
+ dma_free_coherent(dev, len + SEARCH_PATTERN_LEN,
+ eos_vaddr, eos_paddr);
+
+ return ret;
+}
+
+static u32 esparser_get_offset(struct amvdec_session *sess)
+{
+ struct amvdec_core *core = sess->core;
+ u32 offset = amvdec_read_parser(core, PARSER_VIDEO_WP) -
+ sess->vififo_paddr;
+
+ if (offset < sess->last_offset)
+ sess->wrap_count++;
+
+ sess->last_offset = offset;
+ offset += (sess->wrap_count * sess->vififo_size);
+
+ return offset;
+}
+
+static int
+esparser_queue(struct amvdec_session *sess, struct vb2_v4l2_buffer *vbuf)
+{
+ int ret;
+ struct vb2_buffer *vb = &vbuf->vb2_buf;
+ struct amvdec_core *core = sess->core;
+ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
+ u32 num_dst_bufs = 0;
+ u32 payload_size = vb2_get_plane_payload(vb, 0);
+ dma_addr_t phy = vb2_dma_contig_plane_dma_addr(vb, 0);
+ u32 offset;
+ u32 pad_size;
+
+ if (codec_ops->num_pending_bufs)
+ num_dst_bufs = codec_ops->num_pending_bufs(sess);
+
+ num_dst_bufs += v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx);
+
+ if (esparser_vififo_get_free_space(sess) < payload_size ||
+ atomic_read(&sess->esparser_queued_bufs) >= num_dst_bufs)
+ return -EAGAIN;
+
+ v4l2_m2m_src_buf_remove_by_buf(sess->m2m_ctx, vbuf);
+
+ offset = esparser_get_offset(sess);
+
+ amvdec_add_ts_reorder(sess, vb->timestamp, offset);
+ dev_dbg(core->dev, "esparser: ts = %llu pld_size = %u offset = %08X\n",
+ vb->timestamp, payload_size, offset);
+
+ pad_size = esparser_pad_start_code(vb);
+ ret = esparser_write_data(core, phy, payload_size + pad_size);
+
+ if (ret <= 0) {
+ dev_warn(core->dev, "esparser: input parsing error\n");
+ amvdec_remove_ts(sess, vb->timestamp);
+ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
+ amvdec_write_parser(core, PARSER_FETCH_CMD, 0);
+
+ return 0;
+ }
+
+ /* We need to wait until we parse the first keyframe.
+ * All buffers prior to the first keyframe must be dropped.
+ */
+ if (!sess->keyframe_found)
+ usleep_range(1000, 2000);
+
+ if (sess->keyframe_found)
+ atomic_inc(&sess->esparser_queued_bufs);
+ else
+ amvdec_remove_ts(sess, vb->timestamp);
+
+ vbuf->flags = 0;
+ vbuf->field = V4L2_FIELD_NONE;
+ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
+
+ return 0;
+}
+
+void esparser_queue_all_src(struct work_struct *work)
+{
+ struct v4l2_m2m_buffer *buf, *n;
+ struct amvdec_session *sess =
+ container_of(work, struct amvdec_session, esparser_queue_work);
+
+ mutex_lock(&sess->lock);
+ v4l2_m2m_for_each_src_buf_safe(sess->m2m_ctx, buf, n) {
+ if (sess->should_stop)
+ break;
+
+ if (esparser_queue(sess, &buf->vb) < 0)
+ break;
+ }
+ mutex_unlock(&sess->lock);
+}
+
+int esparser_power_up(struct amvdec_session *sess)
+{
+ struct amvdec_core *core = sess->core;
+ struct amvdec_ops *vdec_ops = sess->fmt_out->vdec_ops;
+
+ reset_control_reset(core->esparser_reset);
+ amvdec_write_parser(core, PARSER_CONFIG,
+ (10 << PS_CFG_PFIFO_EMPTY_CNT_BIT) |
+ (1 << PS_CFG_MAX_ES_WR_CYCLE_BIT) |
+ (16 << PS_CFG_MAX_FETCH_CYCLE_BIT));
+
+ amvdec_write_parser(core, PFIFO_RD_PTR, 0);
+ amvdec_write_parser(core, PFIFO_WR_PTR, 0);
+
+ amvdec_write_parser(core, PARSER_SEARCH_PATTERN,
+ ES_START_CODE_PATTERN);
+ amvdec_write_parser(core, PARSER_SEARCH_MASK, ES_START_CODE_MASK);
+
+ amvdec_write_parser(core, PARSER_CONFIG,
+ (10 << PS_CFG_PFIFO_EMPTY_CNT_BIT) |
+ (1 << PS_CFG_MAX_ES_WR_CYCLE_BIT) |
+ (16 << PS_CFG_MAX_FETCH_CYCLE_BIT) |
+ (2 << PS_CFG_STARTCODE_WID_24_BIT));
+
+ amvdec_write_parser(core, PARSER_CONTROL,
+ (ES_SEARCH | ES_PARSER_START));
+
+ amvdec_write_parser(core, PARSER_VIDEO_START_PTR, sess->vififo_paddr);
+ amvdec_write_parser(core, PARSER_VIDEO_END_PTR,
+ sess->vififo_paddr + sess->vififo_size - 8);
+ amvdec_write_parser(core, PARSER_ES_CONTROL,
+ amvdec_read_parser(core, PARSER_ES_CONTROL) & ~1);
+
+ if (vdec_ops->conf_esparser)
+ vdec_ops->conf_esparser(sess);
+
+ amvdec_write_parser(core, PARSER_INT_STATUS, 0xffff);
+ amvdec_write_parser(core, PARSER_INT_ENABLE,
+ BIT(PARSER_INT_HOST_EN_BIT));
+
+ return 0;
+}
+
+int esparser_init(struct platform_device *pdev, struct amvdec_core *core)
+{
+ struct device *dev = &pdev->dev;
+ int ret;
+ int irq;
+
+ irq = platform_get_irq_byname(pdev, "esparser");
+ if (irq < 0) {
+ dev_err(dev, "Failed getting ESPARSER IRQ from dtb\n");
+ return irq;
+ }
+
+ ret = devm_request_irq(dev, irq, esparser_isr, IRQF_SHARED,
+ "esparserirq", core);
+ if (ret) {
+ dev_err(dev, "Failed requesting ESPARSER IRQ\n");
+ return ret;
+ }
+
+ core->esparser_reset =
+ devm_reset_control_get_exclusive(dev, "esparser");
+ if (IS_ERR(core->esparser_reset)) {
+ dev_err(dev, "Failed to get esparser_reset\n");
+ return PTR_ERR(core->esparser_reset);
+ }
+
+ return 0;
+}
diff --git a/drivers/staging/media/meson/vdec/esparser.h b/drivers/staging/media/meson/vdec/esparser.h
new file mode 100644
index 000000000000..ff51fe7fda66
--- /dev/null
+++ b/drivers/staging/media/meson/vdec/esparser.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2018 BayLibre, SAS
+ * Author: Maxime Jourdan <mjourdan@baylibre.com>
+ */
+
+#ifndef __MESON_VDEC_ESPARSER_H_
+#define __MESON_VDEC_ESPARSER_H_
+
+#include <linux/platform_device.h>
+
+#include "vdec.h"
+
+int esparser_init(struct platform_device *pdev, struct amvdec_core *core);
+int esparser_power_up(struct amvdec_session *sess);
+
+/**
+ * esparser_queue_eos() - write End Of Stream sequence to the ESPARSER
+ *
+ * @core vdec core struct
+ */
+int esparser_queue_eos(struct amvdec_core *core, const u8 *data, u32 len);
+
+/**
+ * esparser_queue_all_src() - work handler that writes as many src buffers
+ * as possible to the ESPARSER
+ */
+void esparser_queue_all_src(struct work_struct *work);
+
+#define ESPARSER_MIN_PACKET_SIZE SZ_4K
+
+#endif
diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c
new file mode 100644
index 000000000000..0a1a04fd5d13
--- /dev/null
+++ b/drivers/staging/media/meson/vdec/vdec.c
@@ -0,0 +1,1099 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 BayLibre, SAS
+ * Author: Maxime Jourdan <mjourdan@baylibre.com>
+ */
+
+#include <linux/of_device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/syscon.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-dev.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "vdec.h"
+#include "esparser.h"
+#include "vdec_helpers.h"
+
+struct dummy_buf {
+ struct vb2_v4l2_buffer vb;
+ struct list_head list;
+};
+
+/* 16 MiB for parsed bitstream swap exchange */
+#define SIZE_VIFIFO SZ_16M
+
+static u32 get_output_size(u32 width, u32 height)
+{
+ return ALIGN(width * height, SZ_64K);
+}
+
+u32 amvdec_get_output_size(struct amvdec_session *sess)
+{
+ return get_output_size(sess->width, sess->height);
+}
+EXPORT_SYMBOL_GPL(amvdec_get_output_size);
+
+static int vdec_codec_needs_recycle(struct amvdec_session *sess)
+{
+ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
+
+ return codec_ops->can_recycle && codec_ops->recycle;
+}
+
+static int vdec_recycle_thread(void *data)
+{
+ struct amvdec_session *sess = data;
+ struct amvdec_core *core = sess->core;
+ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
+ struct amvdec_buffer *tmp, *n;
+
+ while (!kthread_should_stop()) {
+ mutex_lock(&sess->bufs_recycle_lock);
+ list_for_each_entry_safe(tmp, n, &sess->bufs_recycle, list) {
+ if (!codec_ops->can_recycle(core))
+ break;
+
+ codec_ops->recycle(core, tmp->vb->index);
+ list_del(&tmp->list);
+ kfree(tmp);
+ }
+ mutex_unlock(&sess->bufs_recycle_lock);
+
+ usleep_range(5000, 10000);
+ }
+
+ return 0;
+}
+
+static int vdec_poweron(struct amvdec_session *sess)
+{
+ int ret;
+ struct amvdec_ops *vdec_ops = sess->fmt_out->vdec_ops;
+
+ ret = clk_prepare_enable(sess->core->dos_parser_clk);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(sess->core->dos_clk);
+ if (ret)
+ goto disable_dos_parser;
+
+ ret = vdec_ops->start(sess);
+ if (ret)
+ goto disable_dos;
+
+ esparser_power_up(sess);
+
+ return 0;
+
+disable_dos:
+ clk_disable_unprepare(sess->core->dos_clk);
+disable_dos_parser:
+ clk_disable_unprepare(sess->core->dos_parser_clk);
+
+ return ret;
+}
+
+static void vdec_wait_inactive(struct amvdec_session *sess)
+{
+ /* We consider 50ms with no IRQ to be inactive. */
+ while (time_is_after_jiffies64(sess->last_irq_jiffies +
+ msecs_to_jiffies(50)))
+ msleep(25);
+}
+
+static void vdec_poweroff(struct amvdec_session *sess)
+{
+ struct amvdec_ops *vdec_ops = sess->fmt_out->vdec_ops;
+ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
+
+ sess->should_stop = 1;
+ vdec_wait_inactive(sess);
+ if (codec_ops->drain)
+ codec_ops->drain(sess);
+
+ vdec_ops->stop(sess);
+ clk_disable_unprepare(sess->core->dos_clk);
+ clk_disable_unprepare(sess->core->dos_parser_clk);
+}
+
+static void
+vdec_queue_recycle(struct amvdec_session *sess, struct vb2_buffer *vb)
+{
+ struct amvdec_buffer *new_buf;
+
+ new_buf = kmalloc(sizeof(*new_buf), GFP_KERNEL);
+ new_buf->vb = vb;
+
+ mutex_lock(&sess->bufs_recycle_lock);
+ list_add_tail(&new_buf->list, &sess->bufs_recycle);
+ mutex_unlock(&sess->bufs_recycle_lock);
+}
+
+static void vdec_m2m_device_run(void *priv)
+{
+ struct amvdec_session *sess = priv;
+
+ schedule_work(&sess->esparser_queue_work);
+}
+
+static void vdec_m2m_job_abort(void *priv)
+{
+ struct amvdec_session *sess = priv;
+
+ v4l2_m2m_job_finish(sess->m2m_dev, sess->m2m_ctx);
+}
+
+static const struct v4l2_m2m_ops vdec_m2m_ops = {
+ .device_run = vdec_m2m_device_run,
+ .job_abort = vdec_m2m_job_abort,
+};
+
+static void process_num_buffers(struct vb2_queue *q,
+ struct amvdec_session *sess,
+ unsigned int *num_buffers,
+ bool is_reqbufs)
+{
+ const struct amvdec_format *fmt_out = sess->fmt_out;
+ unsigned int buffers_total = q->num_buffers + *num_buffers;
+
+ if (is_reqbufs && buffers_total < fmt_out->min_buffers)
+ *num_buffers = fmt_out->min_buffers - q->num_buffers;
+ if (buffers_total > fmt_out->max_buffers)
+ *num_buffers = fmt_out->max_buffers - q->num_buffers;
+
+ /* We need to program the complete CAPTURE buffer list
+ * in registers during start_streaming, and the firmwares
+ * are free to choose any of them to write frames to. As such,
+ * we need all of them to be queued into the driver
+ */
+ sess->num_dst_bufs = q->num_buffers + *num_buffers;
+ q->min_buffers_needed = max(fmt_out->min_buffers, sess->num_dst_bufs);
+}
+
+static int vdec_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct amvdec_session *sess = vb2_get_drv_priv(q);
+ u32 output_size = amvdec_get_output_size(sess);
+
+ if (*num_planes) {
+ switch (q->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ if (*num_planes != 1 || sizes[0] < output_size)
+ return -EINVAL;
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ switch (sess->pixfmt_cap) {
+ case V4L2_PIX_FMT_NV12M:
+ if (*num_planes != 2 ||
+ sizes[0] < output_size ||
+ sizes[1] < output_size / 2)
+ return -EINVAL;
+ break;
+ case V4L2_PIX_FMT_YUV420M:
+ if (*num_planes != 3 ||
+ sizes[0] < output_size ||
+ sizes[1] < output_size / 4 ||
+ sizes[2] < output_size / 4)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ process_num_buffers(q, sess, num_buffers, false);
+ break;
+ }
+
+ return 0;
+ }
+
+ switch (q->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ sizes[0] = amvdec_get_output_size(sess);
+ *num_planes = 1;
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ switch (sess->pixfmt_cap) {
+ case V4L2_PIX_FMT_NV12M:
+ sizes[0] = output_size;
+ sizes[1] = output_size / 2;
+ *num_planes = 2;
+ break;
+ case V4L2_PIX_FMT_YUV420M:
+ sizes[0] = output_size;
+ sizes[1] = output_size / 4;
+ sizes[2] = output_size / 4;
+ *num_planes = 3;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ process_num_buffers(q, sess, num_buffers, true);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void vdec_vb2_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct amvdec_session *sess = vb2_get_drv_priv(vb->vb2_queue);
+ struct v4l2_m2m_ctx *m2m_ctx = sess->m2m_ctx;
+
+ v4l2_m2m_buf_queue(m2m_ctx, vbuf);
+
+ if (!sess->streamon_out || !sess->streamon_cap)
+ return;
+
+ if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+ vdec_codec_needs_recycle(sess))
+ vdec_queue_recycle(sess, vb);
+
+ schedule_work(&sess->esparser_queue_work);
+}
+
+static int vdec_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct amvdec_session *sess = vb2_get_drv_priv(q);
+ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
+ struct amvdec_core *core = sess->core;
+ struct vb2_v4l2_buffer *buf;
+ int ret;
+
+ if (core->cur_sess && core->cur_sess != sess) {
+ ret = -EBUSY;
+ goto bufs_done;
+ }
+
+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ sess->streamon_out = 1;
+ else
+ sess->streamon_cap = 1;
+
+ if (!sess->streamon_out || !sess->streamon_cap)
+ return 0;
+
+ if (sess->status == STATUS_NEEDS_RESUME &&
+ q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ codec_ops->resume(sess);
+ sess->status = STATUS_RUNNING;
+ return 0;
+ }
+
+ sess->vififo_size = SIZE_VIFIFO;
+ sess->vififo_vaddr =
+ dma_alloc_coherent(sess->core->dev, sess->vififo_size,
+ &sess->vififo_paddr, GFP_KERNEL);
+ if (!sess->vififo_vaddr) {
+ dev_err(sess->core->dev, "Failed to request VIFIFO buffer\n");
+ ret = -ENOMEM;
+ goto bufs_done;
+ }
+
+ sess->should_stop = 0;
+ sess->keyframe_found = 0;
+ sess->last_offset = 0;
+ sess->wrap_count = 0;
+ sess->pixelaspect.numerator = 1;
+ sess->pixelaspect.denominator = 1;
+ atomic_set(&sess->esparser_queued_bufs, 0);
+ v4l2_ctrl_s_ctrl(sess->ctrl_min_buf_capture, 1);
+
+ ret = vdec_poweron(sess);
+ if (ret)
+ goto vififo_free;
+
+ sess->sequence_cap = 0;
+ if (vdec_codec_needs_recycle(sess))
+ sess->recycle_thread = kthread_run(vdec_recycle_thread, sess,
+ "vdec_recycle");
+
+ sess->status = STATUS_RUNNING;
+ core->cur_sess = sess;
+
+ return 0;
+
+vififo_free:
+ dma_free_coherent(sess->core->dev, sess->vififo_size,
+ sess->vififo_vaddr, sess->vififo_paddr);
+bufs_done:
+ while ((buf = v4l2_m2m_src_buf_remove(sess->m2m_ctx)))
+ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED);
+ while ((buf = v4l2_m2m_dst_buf_remove(sess->m2m_ctx)))
+ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED);
+
+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ sess->streamon_out = 0;
+ else
+ sess->streamon_cap = 0;
+
+ return ret;
+}
+
+static void vdec_free_canvas(struct amvdec_session *sess)
+{
+ int i;
+
+ for (i = 0; i < sess->canvas_num; ++i)
+ meson_canvas_free(sess->core->canvas, sess->canvas_alloc[i]);
+
+ sess->canvas_num = 0;
+}
+
+static void vdec_reset_timestamps(struct amvdec_session *sess)
+{
+ struct amvdec_timestamp *tmp, *n;
+
+ list_for_each_entry_safe(tmp, n, &sess->timestamps, list) {
+ list_del(&tmp->list);
+ kfree(tmp);
+ }
+}
+
+static void vdec_reset_bufs_recycle(struct amvdec_session *sess)
+{
+ struct amvdec_buffer *tmp, *n;
+
+ list_for_each_entry_safe(tmp, n, &sess->bufs_recycle, list) {
+ list_del(&tmp->list);
+ kfree(tmp);
+ }
+}
+
+static void vdec_stop_streaming(struct vb2_queue *q)
+{
+ struct amvdec_session *sess = vb2_get_drv_priv(q);
+ struct amvdec_core *core = sess->core;
+ struct vb2_v4l2_buffer *buf;
+
+ if (sess->status == STATUS_RUNNING ||
+ (sess->status == STATUS_NEEDS_RESUME &&
+ (!sess->streamon_out || !sess->streamon_cap))) {
+ if (vdec_codec_needs_recycle(sess))
+ kthread_stop(sess->recycle_thread);
+
+ vdec_poweroff(sess);
+ vdec_free_canvas(sess);
+ dma_free_coherent(sess->core->dev, sess->vififo_size,
+ sess->vififo_vaddr, sess->vififo_paddr);
+ vdec_reset_timestamps(sess);
+ vdec_reset_bufs_recycle(sess);
+ kfree(sess->priv);
+ sess->priv = NULL;
+ core->cur_sess = NULL;
+ sess->status = STATUS_STOPPED;
+ }
+
+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ while ((buf = v4l2_m2m_src_buf_remove(sess->m2m_ctx)))
+ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR);
+
+ sess->streamon_out = 0;
+ } else {
+ while ((buf = v4l2_m2m_dst_buf_remove(sess->m2m_ctx)))
+ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR);
+
+ sess->streamon_cap = 0;
+ }
+}
+
+static int vdec_vb2_buf_prepare(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+ vbuf->field = V4L2_FIELD_NONE;
+ return 0;
+}
+
+static const struct vb2_ops vdec_vb2_ops = {
+ .queue_setup = vdec_queue_setup,
+ .start_streaming = vdec_start_streaming,
+ .stop_streaming = vdec_stop_streaming,
+ .buf_queue = vdec_vb2_buf_queue,
+ .buf_prepare = vdec_vb2_buf_prepare,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+static int
+vdec_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
+{
+ strscpy(cap->driver, "meson-vdec", sizeof(cap->driver));
+ strscpy(cap->card, "Amlogic Video Decoder", sizeof(cap->card));
+ strscpy(cap->bus_info, "platform:meson-vdec", sizeof(cap->bus_info));
+
+ return 0;
+}
+
+static const struct amvdec_format *
+find_format(const struct amvdec_format *fmts, u32 size, u32 pixfmt)
+{
+ unsigned int i;
+
+ for (i = 0; i < size; i++) {
+ if (fmts[i].pixfmt == pixfmt)
+ return &fmts[i];
+ }
+
+ return NULL;
+}
+
+static unsigned int
+vdec_supports_pixfmt_cap(const struct amvdec_format *fmt_out, u32 pixfmt_cap)
+{
+ int i;
+
+ for (i = 0; fmt_out->pixfmts_cap[i]; i++)
+ if (fmt_out->pixfmts_cap[i] == pixfmt_cap)
+ return 1;
+
+ return 0;
+}
+
+static const struct amvdec_format *
+vdec_try_fmt_common(struct amvdec_session *sess, u32 size,
+ struct v4l2_format *f)
+{
+ struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
+ struct v4l2_plane_pix_format *pfmt = pixmp->plane_fmt;
+ const struct amvdec_format *fmts = sess->core->platform->formats;
+ const struct amvdec_format *fmt_out;
+
+ memset(pfmt[0].reserved, 0, sizeof(pfmt[0].reserved));
+ memset(pixmp->reserved, 0, sizeof(pixmp->reserved));
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ fmt_out = find_format(fmts, size, pixmp->pixelformat);
+ if (!fmt_out) {
+ pixmp->pixelformat = V4L2_PIX_FMT_MPEG2;
+ fmt_out = find_format(fmts, size, pixmp->pixelformat);
+ }
+
+ pfmt[0].sizeimage =
+ get_output_size(pixmp->width, pixmp->height);
+ pfmt[0].bytesperline = 0;
+ pixmp->num_planes = 1;
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ fmt_out = sess->fmt_out;
+ if (!vdec_supports_pixfmt_cap(fmt_out, pixmp->pixelformat))
+ pixmp->pixelformat = fmt_out->pixfmts_cap[0];
+
+ memset(pfmt[1].reserved, 0, sizeof(pfmt[1].reserved));
+ if (pixmp->pixelformat == V4L2_PIX_FMT_NV12M) {
+ pfmt[0].sizeimage =
+ get_output_size(pixmp->width, pixmp->height);
+ pfmt[0].bytesperline = ALIGN(pixmp->width, 64);
+
+ pfmt[1].sizeimage =
+ get_output_size(pixmp->width, pixmp->height) / 2;
+ pfmt[1].bytesperline = ALIGN(pixmp->width, 64);
+ pixmp->num_planes = 2;
+ } else if (pixmp->pixelformat == V4L2_PIX_FMT_YUV420M) {
+ pfmt[0].sizeimage =
+ get_output_size(pixmp->width, pixmp->height);
+ pfmt[0].bytesperline = ALIGN(pixmp->width, 64);
+
+ pfmt[1].sizeimage =
+ get_output_size(pixmp->width, pixmp->height) / 4;
+ pfmt[1].bytesperline = ALIGN(pixmp->width, 64) / 2;
+
+ pfmt[2].sizeimage =
+ get_output_size(pixmp->width, pixmp->height) / 4;
+ pfmt[2].bytesperline = ALIGN(pixmp->width, 64) / 2;
+ pixmp->num_planes = 3;
+ }
+ } else {
+ return NULL;
+ }
+
+ pixmp->width = clamp(pixmp->width, (u32)256, fmt_out->max_width);
+ pixmp->height = clamp(pixmp->height, (u32)144, fmt_out->max_height);
+
+ if (pixmp->field == V4L2_FIELD_ANY)
+ pixmp->field = V4L2_FIELD_NONE;
+
+ return fmt_out;
+}
+
+static int vdec_try_fmt(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct amvdec_session *sess =
+ container_of(file->private_data, struct amvdec_session, fh);
+
+ vdec_try_fmt_common(sess, sess->core->platform->num_formats, f);
+
+ return 0;
+}
+
+static int vdec_g_fmt(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct amvdec_session *sess =
+ container_of(file->private_data, struct amvdec_session, fh);
+ struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ pixmp->pixelformat = sess->pixfmt_cap;
+ else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ pixmp->pixelformat = sess->fmt_out->pixfmt;
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ pixmp->width = sess->width;
+ pixmp->height = sess->height;
+ pixmp->colorspace = sess->colorspace;
+ pixmp->ycbcr_enc = sess->ycbcr_enc;
+ pixmp->quantization = sess->quantization;
+ pixmp->xfer_func = sess->xfer_func;
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ pixmp->width = sess->width;
+ pixmp->height = sess->height;
+ }
+
+ vdec_try_fmt_common(sess, sess->core->platform->num_formats, f);
+
+ return 0;
+}
+
+static int vdec_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct amvdec_session *sess =
+ container_of(file->private_data, struct amvdec_session, fh);
+ struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
+ u32 num_formats = sess->core->platform->num_formats;
+ const struct amvdec_format *fmt_out;
+ struct v4l2_pix_format_mplane orig_pixmp;
+ struct v4l2_format format;
+ u32 pixfmt_out = 0, pixfmt_cap = 0;
+
+ orig_pixmp = *pixmp;
+
+ fmt_out = vdec_try_fmt_common(sess, num_formats, f);
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ pixfmt_out = pixmp->pixelformat;
+ pixfmt_cap = sess->pixfmt_cap;
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ pixfmt_cap = pixmp->pixelformat;
+ pixfmt_out = sess->fmt_out->pixfmt;
+ }
+
+ memset(&format, 0, sizeof(format));
+
+ format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ format.fmt.pix_mp.pixelformat = pixfmt_out;
+ format.fmt.pix_mp.width = orig_pixmp.width;
+ format.fmt.pix_mp.height = orig_pixmp.height;
+ vdec_try_fmt_common(sess, num_formats, &format);
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ sess->width = format.fmt.pix_mp.width;
+ sess->height = format.fmt.pix_mp.height;
+ sess->colorspace = pixmp->colorspace;
+ sess->ycbcr_enc = pixmp->ycbcr_enc;
+ sess->quantization = pixmp->quantization;
+ sess->xfer_func = pixmp->xfer_func;
+ }
+
+ memset(&format, 0, sizeof(format));
+
+ format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ format.fmt.pix_mp.pixelformat = pixfmt_cap;
+ format.fmt.pix_mp.width = orig_pixmp.width;
+ format.fmt.pix_mp.height = orig_pixmp.height;
+ vdec_try_fmt_common(sess, num_formats, &format);
+
+ sess->width = format.fmt.pix_mp.width;
+ sess->height = format.fmt.pix_mp.height;
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ sess->fmt_out = fmt_out;
+ else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ sess->pixfmt_cap = format.fmt.pix_mp.pixelformat;
+
+ return 0;
+}
+
+static int vdec_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+{
+ struct amvdec_session *sess =
+ container_of(file->private_data, struct amvdec_session, fh);
+ const struct vdec_platform *platform = sess->core->platform;
+ const struct amvdec_format *fmt_out;
+
+ memset(f->reserved, 0, sizeof(f->reserved));
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ if (f->index >= platform->num_formats)
+ return -EINVAL;
+
+ fmt_out = &platform->formats[f->index];
+ f->pixelformat = fmt_out->pixfmt;
+ f->flags = fmt_out->flags;
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ fmt_out = sess->fmt_out;
+ if (f->index >= 4 || !fmt_out->pixfmts_cap[f->index])
+ return -EINVAL;
+
+ f->pixelformat = fmt_out->pixfmts_cap[f->index];
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vdec_enum_framesizes(struct file *file, void *fh,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct amvdec_session *sess =
+ container_of(file->private_data, struct amvdec_session, fh);
+ const struct amvdec_format *formats = sess->core->platform->formats;
+ const struct amvdec_format *fmt;
+ u32 num_formats = sess->core->platform->num_formats;
+
+ fmt = find_format(formats, num_formats, fsize->pixel_format);
+ if (!fmt || fsize->index)
+ return -EINVAL;
+
+ fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
+
+ fsize->stepwise.min_width = 256;
+ fsize->stepwise.max_width = fmt->max_width;
+ fsize->stepwise.step_width = 1;
+ fsize->stepwise.min_height = 144;
+ fsize->stepwise.max_height = fmt->max_height;
+ fsize->stepwise.step_height = 1;
+
+ return 0;
+}
+
+static int
+vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd)
+{
+ struct amvdec_session *sess =
+ container_of(file->private_data, struct amvdec_session, fh);
+ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
+ struct device *dev = sess->core->dev;
+ int ret;
+
+ ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, cmd);
+ if (ret)
+ return ret;
+
+ if (!(sess->streamon_out & sess->streamon_cap))
+ return 0;
+
+ /* Currently not handled since we do not support dynamic resolution
+ * for MPEG2. We consider both queues streaming to mean that the
+ * decoding session is started
+ */
+ if (cmd->cmd == V4L2_DEC_CMD_START)
+ return 0;
+
+ /* Should not happen */
+ if (cmd->cmd != V4L2_DEC_CMD_STOP)
+ return -EINVAL;
+
+ dev_dbg(dev, "Received V4L2_DEC_CMD_STOP\n");
+ sess->should_stop = 1;
+
+ vdec_wait_inactive(sess);
+
+ if (codec_ops->drain) {
+ codec_ops->drain(sess);
+ } else if (codec_ops->eos_sequence) {
+ u32 len;
+ const u8 *data = codec_ops->eos_sequence(&len);
+
+ esparser_queue_eos(sess->core, data, len);
+ }
+
+ return ret;
+}
+
+static int vdec_subscribe_event(struct v4l2_fh *fh,
+ const struct v4l2_event_subscription *sub)
+{
+ switch (sub->type) {
+ case V4L2_EVENT_EOS:
+ case V4L2_EVENT_SOURCE_CHANGE:
+ return v4l2_event_subscribe(fh, sub, 0, NULL);
+ case V4L2_EVENT_CTRL:
+ return v4l2_ctrl_subscribe_event(fh, sub);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int vdec_g_pixelaspect(struct file *file, void *fh, int type,
+ struct v4l2_fract *f)
+{
+ struct amvdec_session *sess =
+ container_of(file->private_data, struct amvdec_session, fh);
+
+ if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return -EINVAL;
+
+ *f = sess->pixelaspect;
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops vdec_ioctl_ops = {
+ .vidioc_querycap = vdec_querycap,
+ .vidioc_enum_fmt_vid_cap = vdec_enum_fmt,
+ .vidioc_enum_fmt_vid_out = vdec_enum_fmt,
+ .vidioc_s_fmt_vid_cap_mplane = vdec_s_fmt,
+ .vidioc_s_fmt_vid_out_mplane = vdec_s_fmt,
+ .vidioc_g_fmt_vid_cap_mplane = vdec_g_fmt,
+ .vidioc_g_fmt_vid_out_mplane = vdec_g_fmt,
+ .vidioc_try_fmt_vid_cap_mplane = vdec_try_fmt,
+ .vidioc_try_fmt_vid_out_mplane = vdec_try_fmt,
+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
+ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
+ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
+ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+ .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
+ .vidioc_streamon = v4l2_m2m_ioctl_streamon,
+ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
+ .vidioc_enum_framesizes = vdec_enum_framesizes,
+ .vidioc_subscribe_event = vdec_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+ .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd,
+ .vidioc_decoder_cmd = vdec_decoder_cmd,
+ .vidioc_g_pixelaspect = vdec_g_pixelaspect,
+};
+
+static int m2m_queue_init(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq)
+{
+ struct amvdec_session *sess = priv;
+ int ret;
+
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->ops = &vdec_vb2_ops;
+ src_vq->mem_ops = &vb2_dma_contig_memops;
+ src_vq->drv_priv = sess;
+ src_vq->buf_struct_size = sizeof(struct dummy_buf);
+ src_vq->min_buffers_needed = 1;
+ src_vq->dev = sess->core->dev;
+ src_vq->lock = &sess->lock;
+ ret = vb2_queue_init(src_vq);
+ if (ret)
+ return ret;
+
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dst_vq->ops = &vdec_vb2_ops;
+ dst_vq->mem_ops = &vb2_dma_contig_memops;
+ dst_vq->drv_priv = sess;
+ dst_vq->buf_struct_size = sizeof(struct dummy_buf);
+ dst_vq->min_buffers_needed = 1;
+ dst_vq->dev = sess->core->dev;
+ dst_vq->lock = &sess->lock;
+ ret = vb2_queue_init(dst_vq);
+ if (ret) {
+ vb2_queue_release(src_vq);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int vdec_init_ctrls(struct amvdec_session *sess)
+{
+ struct v4l2_ctrl_handler *ctrl_handler = &sess->ctrl_handler;
+ int ret;
+
+ ret = v4l2_ctrl_handler_init(ctrl_handler, 1);
+ if (ret)
+ return ret;
+
+ sess->ctrl_min_buf_capture =
+ v4l2_ctrl_new_std(ctrl_handler, NULL,
+ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1,
+ 1);
+
+ ret = ctrl_handler->error;
+ if (ret) {
+ v4l2_ctrl_handler_free(ctrl_handler);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int vdec_open(struct file *file)
+{
+ struct amvdec_core *core = video_drvdata(file);
+ struct device *dev = core->dev;
+ const struct amvdec_format *formats = core->platform->formats;
+ struct amvdec_session *sess;
+ int ret;
+
+ sess = kzalloc(sizeof(*sess), GFP_KERNEL);
+ if (!sess)
+ return -ENOMEM;
+
+ sess->core = core;
+
+ sess->m2m_dev = v4l2_m2m_init(&vdec_m2m_ops);
+ if (IS_ERR(sess->m2m_dev)) {
+ dev_err(dev, "Fail to v4l2_m2m_init\n");
+ ret = PTR_ERR(sess->m2m_dev);
+ goto err_free_sess;
+ }
+
+ sess->m2m_ctx = v4l2_m2m_ctx_init(sess->m2m_dev, sess, m2m_queue_init);
+ if (IS_ERR(sess->m2m_ctx)) {
+ dev_err(dev, "Fail to v4l2_m2m_ctx_init\n");
+ ret = PTR_ERR(sess->m2m_ctx);
+ goto err_m2m_release;
+ }
+
+ ret = vdec_init_ctrls(sess);
+ if (ret)
+ goto err_m2m_release;
+
+ sess->pixfmt_cap = formats[0].pixfmts_cap[0];
+ sess->fmt_out = &formats[0];
+ sess->width = 1280;
+ sess->height = 720;
+ sess->pixelaspect.numerator = 1;
+ sess->pixelaspect.denominator = 1;
+
+ INIT_LIST_HEAD(&sess->timestamps);
+ INIT_LIST_HEAD(&sess->bufs_recycle);
+ INIT_WORK(&sess->esparser_queue_work, esparser_queue_all_src);
+ mutex_init(&sess->lock);
+ mutex_init(&sess->bufs_recycle_lock);
+ spin_lock_init(&sess->ts_spinlock);
+
+ v4l2_fh_init(&sess->fh, core->vdev_dec);
+ sess->fh.ctrl_handler = &sess->ctrl_handler;
+ v4l2_fh_add(&sess->fh);
+ sess->fh.m2m_ctx = sess->m2m_ctx;
+ file->private_data = &sess->fh;
+
+ return 0;
+
+err_m2m_release:
+ v4l2_m2m_release(sess->m2m_dev);
+err_free_sess:
+ kfree(sess);
+ return ret;
+}
+
+static int vdec_close(struct file *file)
+{
+ struct amvdec_session *sess =
+ container_of(file->private_data, struct amvdec_session, fh);
+
+ v4l2_m2m_ctx_release(sess->m2m_ctx);
+ v4l2_m2m_release(sess->m2m_dev);
+ v4l2_fh_del(&sess->fh);
+ v4l2_fh_exit(&sess->fh);
+
+ mutex_destroy(&sess->lock);
+ mutex_destroy(&sess->bufs_recycle_lock);
+
+ kfree(sess);
+
+ return 0;
+}
+
+static const struct v4l2_file_operations vdec_fops = {
+ .owner = THIS_MODULE,
+ .open = vdec_open,
+ .release = vdec_close,
+ .unlocked_ioctl = video_ioctl2,
+ .poll = v4l2_m2m_fop_poll,
+ .mmap = v4l2_m2m_fop_mmap,
+};
+
+static irqreturn_t vdec_isr(int irq, void *data)
+{
+ struct amvdec_core *core = data;
+ struct amvdec_session *sess = core->cur_sess;
+
+ sess->last_irq_jiffies = get_jiffies_64();
+
+ return sess->fmt_out->codec_ops->isr(sess);
+}
+
+static irqreturn_t vdec_threaded_isr(int irq, void *data)
+{
+ struct amvdec_core *core = data;
+ struct amvdec_session *sess = core->cur_sess;
+
+ return sess->fmt_out->codec_ops->threaded_isr(sess);
+}
+
+static const struct of_device_id vdec_dt_match[] = {
+ { .compatible = "amlogic,gxbb-vdec",
+ .data = &vdec_platform_gxbb },
+ { .compatible = "amlogic,gxm-vdec",
+ .data = &vdec_platform_gxm },
+ { .compatible = "amlogic,gxl-vdec",
+ .data = &vdec_platform_gxl },
+ {}
+};
+MODULE_DEVICE_TABLE(of, vdec_dt_match);
+
+static int vdec_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct video_device *vdev;
+ struct amvdec_core *core;
+ struct resource *r;
+ const struct of_device_id *of_id;
+ int irq;
+ int ret;
+
+ core = devm_kzalloc(dev, sizeof(*core), GFP_KERNEL);
+ if (!core)
+ return -ENOMEM;
+
+ core->dev = dev;
+ platform_set_drvdata(pdev, core);
+
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dos");
+ core->dos_base = devm_ioremap_resource(dev, r);
+ if (IS_ERR(core->dos_base)) {
+ dev_err(dev, "Couldn't remap DOS memory\n");
+ return PTR_ERR(core->dos_base);
+ }
+
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "esparser");
+ core->esparser_base = devm_ioremap_resource(dev, r);
+ if (IS_ERR(core->esparser_base)) {
+ dev_err(dev, "Couldn't remap ESPARSER memory\n");
+ return PTR_ERR(core->esparser_base);
+ }
+
+ core->regmap_ao =
+ syscon_regmap_lookup_by_phandle(dev->of_node,
+ "amlogic,ao-sysctrl");
+ if (IS_ERR(core->regmap_ao)) {
+ dev_err(dev, "Couldn't regmap AO sysctrl\n");
+ return PTR_ERR(core->regmap_ao);
+ }
+
+ core->canvas = meson_canvas_get(dev);
+ if (IS_ERR(core->canvas))
+ return PTR_ERR(core->canvas);
+
+ core->dos_parser_clk = devm_clk_get(dev, "dos_parser");
+ if (IS_ERR(core->dos_parser_clk))
+ return -EPROBE_DEFER;
+
+ core->dos_clk = devm_clk_get(dev, "dos");
+ if (IS_ERR(core->dos_clk))
+ return -EPROBE_DEFER;
+
+ core->vdec_1_clk = devm_clk_get(dev, "vdec_1");
+ if (IS_ERR(core->vdec_1_clk))
+ return -EPROBE_DEFER;
+
+ core->vdec_hevc_clk = devm_clk_get(dev, "vdec_hevc");
+ if (IS_ERR(core->vdec_hevc_clk))
+ return -EPROBE_DEFER;
+
+ irq = platform_get_irq_byname(pdev, "vdec");
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_threaded_irq(core->dev, irq, vdec_isr,
+ vdec_threaded_isr, IRQF_ONESHOT,
+ "vdec", core);
+ if (ret)
+ return ret;
+
+ ret = esparser_init(pdev, core);
+ if (ret)
+ return ret;
+
+ ret = v4l2_device_register(dev, &core->v4l2_dev);
+ if (ret) {
+ dev_err(dev, "Couldn't register v4l2 device\n");
+ return -ENOMEM;
+ }
+
+ vdev = video_device_alloc();
+ if (!vdev) {
+ ret = -ENOMEM;
+ goto err_vdev_release;
+ }
+
+ of_id = of_match_node(vdec_dt_match, dev->of_node);
+ core->platform = of_id->data;
+ core->vdev_dec = vdev;
+ core->dev_dec = dev;
+ mutex_init(&core->lock);
+
+ strscpy(vdev->name, "meson-video-decoder", sizeof(vdev->name));
+ vdev->release = video_device_release;
+ vdev->fops = &vdec_fops;
+ vdev->ioctl_ops = &vdec_ioctl_ops;
+ vdev->vfl_dir = VFL_DIR_M2M;
+ vdev->v4l2_dev = &core->v4l2_dev;
+ vdev->lock = &core->lock;
+ vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
+
+ video_set_drvdata(vdev, core);
+
+ ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+ if (ret) {
+ dev_err(dev, "Failed registering video device\n");
+ goto err_vdev_release;
+ }
+
+ return 0;
+
+err_vdev_release:
+ video_device_release(vdev);
+ return ret;
+}
+
+static int vdec_remove(struct platform_device *pdev)
+{
+ struct amvdec_core *core = platform_get_drvdata(pdev);
+
+ video_unregister_device(core->vdev_dec);
+
+ return 0;
+}
+
+static struct platform_driver meson_vdec_driver = {
+ .probe = vdec_probe,
+ .remove = vdec_remove,
+ .driver = {
+ .name = "meson-vdec",
+ .of_match_table = vdec_dt_match,
+ },
+};
+module_platform_driver(meson_vdec_driver);
+
+MODULE_DESCRIPTION("Meson video decoder driver for GXBB/GXL/GXM");
+MODULE_AUTHOR("Maxime Jourdan <mjourdan@baylibre.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/media/meson/vdec/vdec.h b/drivers/staging/media/meson/vdec/vdec.h
new file mode 100644
index 000000000000..d811e7976519
--- /dev/null
+++ b/drivers/staging/media/meson/vdec/vdec.h
@@ -0,0 +1,267 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2018 BayLibre, SAS
+ * Author: Maxime Jourdan <mjourdan@baylibre.com>
+ */
+
+#ifndef __MESON_VDEC_CORE_H_
+#define __MESON_VDEC_CORE_H_
+
+#include <linux/irqreturn.h>
+#include <linux/regmap.h>
+#include <linux/list.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <linux/soc/amlogic/meson-canvas.h>
+
+#include "vdec_platform.h"
+
+/* 32 buffers in 3-plane YUV420 */
+#define MAX_CANVAS (32 * 3)
+
+struct amvdec_buffer {
+ struct list_head list;
+ struct vb2_buffer *vb;
+};
+
+/**
+ * struct amvdec_timestamp - stores a src timestamp along with a VIFIFO offset
+ *
+ * @list: used to make lists out of this struct
+ * @ts: timestamp
+ * @offset: offset in the VIFIFO where the associated packet was written
+ */
+struct amvdec_timestamp {
+ struct list_head list;
+ u64 ts;
+ u32 offset;
+};
+
+struct amvdec_session;
+
+/**
+ * struct amvdec_core - device parameters, singleton
+ *
+ * @dos_base: DOS memory base address
+ * @esparser_base: PARSER memory base address
+ * @regmap_ao: regmap for the AO bus
+ * @dev: core device
+ * @dev_dec: decoder device
+ * @platform: platform-specific data
+ * @canvas: canvas provider reference
+ * @dos_parser_clk: DOS_PARSER clock
+ * @dos_clk: DOS clock
+ * @vdec_1_clk: VDEC_1 clock
+ * @vdec_hevc_clk: VDEC_HEVC clock
+ * @esparser_reset: RESET for the PARSER
+ * @vdec_dec: video device for the decoder
+ * @v4l2_dev: v4l2 device
+ * @cur_sess: current decoding session
+ */
+struct amvdec_core {
+ void __iomem *dos_base;
+ void __iomem *esparser_base;
+ struct regmap *regmap_ao;
+
+ struct device *dev;
+ struct device *dev_dec;
+ const struct vdec_platform *platform;
+
+ struct meson_canvas *canvas;
+
+ struct clk *dos_parser_clk;
+ struct clk *dos_clk;
+ struct clk *vdec_1_clk;
+ struct clk *vdec_hevc_clk;
+
+ struct reset_control *esparser_reset;
+
+ struct video_device *vdev_dec;
+ struct v4l2_device v4l2_dev;
+
+ struct amvdec_session *cur_sess;
+ struct mutex lock; /* video device lock */
+};
+
+/**
+ * struct amvdec_ops - vdec operations
+ *
+ * @start: mandatory call when the vdec needs to initialize
+ * @stop: mandatory call when the vdec needs to stop
+ * @conf_esparser: mandatory call to let the vdec configure the ESPARSER
+ * @vififo_level: mandatory call to get the current amount of data
+ * in the VIFIFO
+ * @use_offsets: mandatory call. Returns 1 if the VDEC supports vififo offsets
+ */
+struct amvdec_ops {
+ int (*start)(struct amvdec_session *sess);
+ int (*stop)(struct amvdec_session *sess);
+ void (*conf_esparser)(struct amvdec_session *sess);
+ u32 (*vififo_level)(struct amvdec_session *sess);
+};
+
+/**
+ * struct amvdec_codec_ops - codec operations
+ *
+ * @start: mandatory call when the codec needs to initialize
+ * @stop: mandatory call when the codec needs to stop
+ * @load_extended_firmware: optional call to load additional firmware bits
+ * @num_pending_bufs: optional call to get the number of dst buffers on hold
+ * @can_recycle: optional call to know if the codec is ready to recycle
+ * a dst buffer
+ * @recycle: optional call to tell the codec to recycle a dst buffer. Must go
+ * in pair with @can_recycle
+ * @drain: optional call if the codec has a custom way of draining
+ * @eos_sequence: optional call to get an end sequence to send to esparser
+ * for flush. Mutually exclusive with @drain.
+ * @isr: mandatory call when the ISR triggers
+ * @threaded_isr: mandatory call for the threaded ISR
+ */
+struct amvdec_codec_ops {
+ int (*start)(struct amvdec_session *sess);
+ int (*stop)(struct amvdec_session *sess);
+ int (*load_extended_firmware)(struct amvdec_session *sess,
+ const u8 *data, u32 len);
+ u32 (*num_pending_bufs)(struct amvdec_session *sess);
+ int (*can_recycle)(struct amvdec_core *core);
+ void (*recycle)(struct amvdec_core *core, u32 buf_idx);
+ void (*drain)(struct amvdec_session *sess);
+ void (*resume)(struct amvdec_session *sess);
+ const u8 * (*eos_sequence)(u32 *len);
+ irqreturn_t (*isr)(struct amvdec_session *sess);
+ irqreturn_t (*threaded_isr)(struct amvdec_session *sess);
+};
+
+/**
+ * struct amvdec_format - describes one of the OUTPUT (src) format supported
+ *
+ * @pixfmt: V4L2 pixel format
+ * @min_buffers: minimum amount of CAPTURE (dst) buffers
+ * @max_buffers: maximum amount of CAPTURE (dst) buffers
+ * @max_width: maximum picture width supported
+ * @max_height: maximum picture height supported
+ * @flags: enum flags associated with this pixfmt
+ * @vdec_ops: the VDEC operations that support this format
+ * @codec_ops: the codec operations that support this format
+ * @firmware_path: Path to the firmware that supports this format
+ * @pixfmts_cap: list of CAPTURE pixel formats available with pixfmt
+ */
+struct amvdec_format {
+ u32 pixfmt;
+ u32 min_buffers;
+ u32 max_buffers;
+ u32 max_width;
+ u32 max_height;
+ u32 flags;
+
+ struct amvdec_ops *vdec_ops;
+ struct amvdec_codec_ops *codec_ops;
+
+ char *firmware_path;
+ u32 pixfmts_cap[4];
+};
+
+enum amvdec_status {
+ STATUS_STOPPED,
+ STATUS_RUNNING,
+ STATUS_NEEDS_RESUME,
+};
+
+/**
+ * struct amvdec_session - decoding session parameters
+ *
+ * @core: reference to the vdec core struct
+ * @fh: v4l2 file handle
+ * @m2m_dev: v4l2 m2m device
+ * @m2m_ctx: v4l2 m2m context
+ * @ctrl_handler: V4L2 control handler
+ * @ctrl_min_buf_capture: V4L2 control V4L2_CID_MIN_BUFFERS_FOR_CAPTURE
+ * @fmt_out: vdec pixel format for the OUTPUT queue
+ * @pixfmt_cap: V4L2 pixel format for the CAPTURE queue
+ * @width: current picture width
+ * @height: current picture height
+ * @colorspace: current colorspace
+ * @ycbcr_enc: current ycbcr_enc
+ * @quantization: current quantization
+ * @xfer_func: current transfer function
+ * @pixelaspect: Pixel Aspect Ratio reported by the decoder
+ * @esparser_queued_bufs: number of buffers currently queued into ESPARSER
+ * @esparser_queue_work: work struct for the ESPARSER to process src buffers
+ * @streamon_cap: stream on flag for capture queue
+ * @streamon_out: stream on flag for output queue
+ * @sequence_cap: capture sequence counter
+ * @should_stop: flag set if userspace signaled EOS via command
+ * or empty buffer
+ * @keyframe_found: flag set once a keyframe has been parsed
+ * @canvas_alloc: array of all the canvas IDs allocated
+ * @canvas_num: number of canvas IDs allocated
+ * @vififo_vaddr: virtual address for the VIFIFO
+ * @vififo_paddr: physical address for the VIFIFO
+ * @vififo_size: size of the VIFIFO dma alloc
+ * @bufs_recycle: list of buffers that need to be recycled
+ * @bufs_recycle_lock: lock for the bufs_recycle list
+ * @recycle_thread: task struct for the recycling thread
+ * @timestamps: chronological list of src timestamps
+ * @ts_spinlock: spinlock for the timestamps list
+ * @last_irq_jiffies: tracks last time the vdec triggered an IRQ
+ * @status: current decoding status
+ * @priv: codec private data
+ */
+struct amvdec_session {
+ struct amvdec_core *core;
+
+ struct v4l2_fh fh;
+ struct v4l2_m2m_dev *m2m_dev;
+ struct v4l2_m2m_ctx *m2m_ctx;
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_ctrl *ctrl_min_buf_capture;
+ struct mutex lock; /* cap & out queues lock */
+
+ const struct amvdec_format *fmt_out;
+ u32 pixfmt_cap;
+
+ u32 width;
+ u32 height;
+ u32 colorspace;
+ u8 ycbcr_enc;
+ u8 quantization;
+ u8 xfer_func;
+
+ struct v4l2_fract pixelaspect;
+
+ atomic_t esparser_queued_bufs;
+ struct work_struct esparser_queue_work;
+
+ unsigned int streamon_cap, streamon_out;
+ unsigned int sequence_cap;
+ unsigned int should_stop;
+ unsigned int keyframe_found;
+ unsigned int num_dst_bufs;
+
+ u8 canvas_alloc[MAX_CANVAS];
+ u32 canvas_num;
+
+ void *vififo_vaddr;
+ dma_addr_t vififo_paddr;
+ u32 vififo_size;
+
+ struct list_head bufs_recycle;
+ struct mutex bufs_recycle_lock; /* bufs_recycle list lock */
+ struct task_struct *recycle_thread;
+
+ struct list_head timestamps;
+ spinlock_t ts_spinlock; /* timestamp list lock */
+
+ u64 last_irq_jiffies;
+ u32 last_offset;
+ u32 wrap_count;
+ u32 fw_idx_to_vb2_idx[32];
+
+ enum amvdec_status status;
+ void *priv;
+};
+
+u32 amvdec_get_output_size(struct amvdec_session *sess);
+
+#endif
diff --git a/drivers/staging/media/meson/vdec/vdec_1.c b/drivers/staging/media/meson/vdec/vdec_1.c
new file mode 100644
index 000000000000..3a15c6fc0567
--- /dev/null
+++ b/drivers/staging/media/meson/vdec/vdec_1.c
@@ -0,0 +1,230 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 BayLibre, SAS
+ * Author: Maxime Jourdan <mjourdan@baylibre.com>
+ *
+ * VDEC_1 is a video decoding block that allows decoding of
+ * MPEG 1/2/4, H.263, H.264, MJPEG, VC1
+ */
+
+#include <linux/firmware.h>
+#include <linux/clk.h>
+
+#include "vdec_1.h"
+#include "vdec_helpers.h"
+#include "dos_regs.h"
+
+/* AO Registers */
+#define AO_RTI_GEN_PWR_SLEEP0 0xe8
+#define AO_RTI_GEN_PWR_ISO0 0xec
+ #define GEN_PWR_VDEC_1 (BIT(3) | BIT(2))
+
+#define MC_SIZE (4096 * 4)
+
+static int
+vdec_1_load_firmware(struct amvdec_session *sess, const char *fwname)
+{
+ const struct firmware *fw;
+ struct amvdec_core *core = sess->core;
+ struct device *dev = core->dev_dec;
+ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
+ static void *mc_addr;
+ static dma_addr_t mc_addr_map;
+ int ret;
+ u32 i = 1000;
+
+ ret = request_firmware(&fw, fwname, dev);
+ if (ret < 0)
+ return -EINVAL;
+
+ if (fw->size < MC_SIZE) {
+ dev_err(dev, "Firmware size %zu is too small. Expected %u.\n",
+ fw->size, MC_SIZE);
+ ret = -EINVAL;
+ goto release_firmware;
+ }
+
+ mc_addr = dma_alloc_coherent(core->dev, MC_SIZE,
+ &mc_addr_map, GFP_KERNEL);
+ if (!mc_addr) {
+ ret = -ENOMEM;
+ goto release_firmware;
+ }
+
+ memcpy(mc_addr, fw->data, MC_SIZE);
+
+ amvdec_write_dos(core, MPSR, 0);
+ amvdec_write_dos(core, CPSR, 0);
+
+ amvdec_clear_dos_bits(core, MDEC_PIC_DC_CTRL, BIT(31));
+
+ amvdec_write_dos(core, IMEM_DMA_ADR, mc_addr_map);
+ amvdec_write_dos(core, IMEM_DMA_COUNT, MC_SIZE / 4);
+ amvdec_write_dos(core, IMEM_DMA_CTRL, (0x8000 | (7 << 16)));
+
+ while (--i && amvdec_read_dos(core, IMEM_DMA_CTRL) & 0x8000);
+
+ if (i == 0) {
+ dev_err(dev, "Firmware load fail (DMA hang?)\n");
+ ret = -EINVAL;
+ goto free_mc;
+ }
+
+ if (codec_ops->load_extended_firmware)
+ ret = codec_ops->load_extended_firmware(sess,
+ fw->data + MC_SIZE,
+ fw->size - MC_SIZE);
+
+free_mc:
+ dma_free_coherent(core->dev, MC_SIZE, mc_addr, mc_addr_map);
+release_firmware:
+ release_firmware(fw);
+ return ret;
+}
+
+static int vdec_1_stbuf_power_up(struct amvdec_session *sess)
+{
+ struct amvdec_core *core = sess->core;
+
+ amvdec_write_dos(core, VLD_MEM_VIFIFO_CONTROL, 0);
+ amvdec_write_dos(core, VLD_MEM_VIFIFO_WRAP_COUNT, 0);
+ amvdec_write_dos(core, POWER_CTL_VLD, BIT(4));
+
+ amvdec_write_dos(core, VLD_MEM_VIFIFO_START_PTR, sess->vififo_paddr);
+ amvdec_write_dos(core, VLD_MEM_VIFIFO_CURR_PTR, sess->vififo_paddr);
+ amvdec_write_dos(core, VLD_MEM_VIFIFO_END_PTR,
+ sess->vififo_paddr + sess->vififo_size - 8);
+
+ amvdec_write_dos_bits(core, VLD_MEM_VIFIFO_CONTROL, 1);
+ amvdec_clear_dos_bits(core, VLD_MEM_VIFIFO_CONTROL, 1);
+
+ amvdec_write_dos(core, VLD_MEM_VIFIFO_BUF_CNTL, MEM_BUFCTRL_MANUAL);
+ amvdec_write_dos(core, VLD_MEM_VIFIFO_WP, sess->vififo_paddr);
+
+ amvdec_write_dos_bits(core, VLD_MEM_VIFIFO_BUF_CNTL, 1);
+ amvdec_clear_dos_bits(core, VLD_MEM_VIFIFO_BUF_CNTL, 1);
+
+ amvdec_write_dos_bits(core, VLD_MEM_VIFIFO_CONTROL,
+ (0x11 << MEM_FIFO_CNT_BIT) | MEM_FILL_ON_LEVEL |
+ MEM_CTRL_FILL_EN | MEM_CTRL_EMPTY_EN);
+
+ return 0;
+}
+
+static void vdec_1_conf_esparser(struct amvdec_session *sess)
+{
+ struct amvdec_core *core = sess->core;
+
+ /* VDEC_1 specific ESPARSER stuff */
+ amvdec_write_dos(core, DOS_GEN_CTRL0, 0);
+ amvdec_write_dos(core, VLD_MEM_VIFIFO_BUF_CNTL, 1);
+ amvdec_clear_dos_bits(core, VLD_MEM_VIFIFO_BUF_CNTL, 1);
+}
+
+static u32 vdec_1_vififo_level(struct amvdec_session *sess)
+{
+ struct amvdec_core *core = sess->core;
+
+ return amvdec_read_dos(core, VLD_MEM_VIFIFO_LEVEL);
+}
+
+static int vdec_1_stop(struct amvdec_session *sess)
+{
+ struct amvdec_core *core = sess->core;
+ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
+
+ amvdec_write_dos(core, MPSR, 0);
+ amvdec_write_dos(core, CPSR, 0);
+ amvdec_write_dos(core, ASSIST_MBOX1_MASK, 0);
+
+ amvdec_write_dos(core, DOS_SW_RESET0, BIT(12) | BIT(11));
+ amvdec_write_dos(core, DOS_SW_RESET0, 0);
+ amvdec_read_dos(core, DOS_SW_RESET0);
+
+ /* enable vdec1 isolation */
+ regmap_write(core->regmap_ao, AO_RTI_GEN_PWR_ISO0, 0xc0);
+ /* power off vdec1 memories */
+ amvdec_write_dos(core, DOS_MEM_PD_VDEC, 0xffffffff);
+ /* power off vdec1 */
+ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
+ GEN_PWR_VDEC_1, GEN_PWR_VDEC_1);
+
+ clk_disable_unprepare(core->vdec_1_clk);
+
+ if (sess->priv)
+ codec_ops->stop(sess);
+
+ return 0;
+}
+
+static int vdec_1_start(struct amvdec_session *sess)
+{
+ int ret;
+ struct amvdec_core *core = sess->core;
+ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
+
+ /* Configure the vdec clk to the maximum available */
+ clk_set_rate(core->vdec_1_clk, 666666666);
+ ret = clk_prepare_enable(core->vdec_1_clk);
+ if (ret)
+ return ret;
+
+ /* Enable power for VDEC_1 */
+ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
+ GEN_PWR_VDEC_1, 0);
+ usleep_range(10, 20);
+
+ /* Reset VDEC1 */
+ amvdec_write_dos(core, DOS_SW_RESET0, 0xfffffffc);
+ amvdec_write_dos(core, DOS_SW_RESET0, 0x00000000);
+
+ amvdec_write_dos(core, DOS_GCLK_EN0, 0x3ff);
+
+ /* enable VDEC Memories */
+ amvdec_write_dos(core, DOS_MEM_PD_VDEC, 0);
+ /* Remove VDEC1 Isolation */
+ regmap_write(core->regmap_ao, AO_RTI_GEN_PWR_ISO0, 0);
+ /* Reset DOS top registers */
+ amvdec_write_dos(core, DOS_VDEC_MCRCC_STALL_CTRL, 0);
+
+ amvdec_write_dos(core, GCLK_EN, 0x3ff);
+ amvdec_clear_dos_bits(core, MDEC_PIC_DC_CTRL, BIT(31));
+
+ vdec_1_stbuf_power_up(sess);
+
+ ret = vdec_1_load_firmware(sess, sess->fmt_out->firmware_path);
+ if (ret)
+ goto stop;
+
+ ret = codec_ops->start(sess);
+ if (ret)
+ goto stop;
+
+ /* Enable IRQ */
+ amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1);
+ amvdec_write_dos(core, ASSIST_MBOX1_MASK, 1);
+
+ /* Enable 2-plane output */
+ if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M)
+ amvdec_write_dos_bits(core, MDEC_PIC_DC_CTRL, BIT(17));
+ else
+ amvdec_clear_dos_bits(core, MDEC_PIC_DC_CTRL, BIT(17));
+
+ /* Enable firmware processor */
+ amvdec_write_dos(core, MPSR, 1);
+ /* Let the firmware settle */
+ usleep_range(10, 20);
+
+ return 0;
+
+stop:
+ vdec_1_stop(sess);
+ return ret;
+}
+
+struct amvdec_ops vdec_1_ops = {
+ .start = vdec_1_start,
+ .stop = vdec_1_stop,
+ .conf_esparser = vdec_1_conf_esparser,
+ .vififo_level = vdec_1_vififo_level,
+};
diff --git a/drivers/staging/media/meson/vdec/vdec_1.h b/drivers/staging/media/meson/vdec/vdec_1.h
new file mode 100644
index 000000000000..042d930c40d7
--- /dev/null
+++ b/drivers/staging/media/meson/vdec/vdec_1.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2018 BayLibre, SAS
+ * Author: Maxime Jourdan <mjourdan@baylibre.com>
+ */
+
+#ifndef __MESON_VDEC_VDEC_1_H_
+#define __MESON_VDEC_VDEC_1_H_
+
+#include "vdec.h"
+
+extern struct amvdec_ops vdec_1_ops;
+
+#endif
diff --git a/drivers/staging/media/meson/vdec/vdec_helpers.c b/drivers/staging/media/meson/vdec/vdec_helpers.c
new file mode 100644
index 000000000000..f16948bdbf2f
--- /dev/null
+++ b/drivers/staging/media/meson/vdec/vdec_helpers.c
@@ -0,0 +1,449 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 BayLibre, SAS
+ * Author: Maxime Jourdan <mjourdan@baylibre.com>
+ */
+
+#include <linux/gcd.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "vdec_helpers.h"
+
+#define NUM_CANVAS_NV12 2
+#define NUM_CANVAS_YUV420 3
+
+u32 amvdec_read_dos(struct amvdec_core *core, u32 reg)
+{
+ return readl_relaxed(core->dos_base + reg);
+}
+EXPORT_SYMBOL_GPL(amvdec_read_dos);
+
+void amvdec_write_dos(struct amvdec_core *core, u32 reg, u32 val)
+{
+ writel_relaxed(val, core->dos_base + reg);
+}
+EXPORT_SYMBOL_GPL(amvdec_write_dos);
+
+void amvdec_write_dos_bits(struct amvdec_core *core, u32 reg, u32 val)
+{
+ amvdec_write_dos(core, reg, amvdec_read_dos(core, reg) | val);
+}
+EXPORT_SYMBOL_GPL(amvdec_write_dos_bits);
+
+void amvdec_clear_dos_bits(struct amvdec_core *core, u32 reg, u32 val)
+{
+ amvdec_write_dos(core, reg, amvdec_read_dos(core, reg) & ~val);
+}
+EXPORT_SYMBOL_GPL(amvdec_clear_dos_bits);
+
+u32 amvdec_read_parser(struct amvdec_core *core, u32 reg)
+{
+ return readl_relaxed(core->esparser_base + reg);
+}
+EXPORT_SYMBOL_GPL(amvdec_read_parser);
+
+void amvdec_write_parser(struct amvdec_core *core, u32 reg, u32 val)
+{
+ writel_relaxed(val, core->esparser_base + reg);
+}
+EXPORT_SYMBOL_GPL(amvdec_write_parser);
+
+static int canvas_alloc(struct amvdec_session *sess, u8 *canvas_id)
+{
+ int ret;
+
+ if (sess->canvas_num >= MAX_CANVAS) {
+ dev_err(sess->core->dev, "Reached max number of canvas\n");
+ return -ENOMEM;
+ }
+
+ ret = meson_canvas_alloc(sess->core->canvas, canvas_id);
+ if (ret)
+ return ret;
+
+ sess->canvas_alloc[sess->canvas_num++] = *canvas_id;
+ return 0;
+}
+
+static int set_canvas_yuv420m(struct amvdec_session *sess,
+ struct vb2_buffer *vb, u32 width,
+ u32 height, u32 reg)
+{
+ struct amvdec_core *core = sess->core;
+ u8 canvas_id[NUM_CANVAS_YUV420]; /* Y U V */
+ dma_addr_t buf_paddr[NUM_CANVAS_YUV420]; /* Y U V */
+ int ret, i;
+
+ for (i = 0; i < NUM_CANVAS_YUV420; ++i) {
+ ret = canvas_alloc(sess, &canvas_id[i]);
+ if (ret)
+ return ret;
+
+ buf_paddr[i] =
+ vb2_dma_contig_plane_dma_addr(vb, i);
+ }
+
+ /* Y plane */
+ meson_canvas_config(core->canvas, canvas_id[0], buf_paddr[0],
+ width, height, MESON_CANVAS_WRAP_NONE,
+ MESON_CANVAS_BLKMODE_LINEAR,
+ MESON_CANVAS_ENDIAN_SWAP64);
+
+ /* U plane */
+ meson_canvas_config(core->canvas, canvas_id[1], buf_paddr[1],
+ width / 2, height / 2, MESON_CANVAS_WRAP_NONE,
+ MESON_CANVAS_BLKMODE_LINEAR,
+ MESON_CANVAS_ENDIAN_SWAP64);
+
+ /* V plane */
+ meson_canvas_config(core->canvas, canvas_id[2], buf_paddr[2],
+ width / 2, height / 2, MESON_CANVAS_WRAP_NONE,
+ MESON_CANVAS_BLKMODE_LINEAR,
+ MESON_CANVAS_ENDIAN_SWAP64);
+
+ amvdec_write_dos(core, reg,
+ ((canvas_id[2]) << 16) |
+ ((canvas_id[1]) << 8) |
+ (canvas_id[0]));
+
+ return 0;
+}
+
+static int set_canvas_nv12m(struct amvdec_session *sess,
+ struct vb2_buffer *vb, u32 width,
+ u32 height, u32 reg)
+{
+ struct amvdec_core *core = sess->core;
+ u8 canvas_id[NUM_CANVAS_NV12]; /* Y U/V */
+ dma_addr_t buf_paddr[NUM_CANVAS_NV12]; /* Y U/V */
+ int ret, i;
+
+ for (i = 0; i < NUM_CANVAS_NV12; ++i) {
+ ret = canvas_alloc(sess, &canvas_id[i]);
+ if (ret)
+ return ret;
+
+ buf_paddr[i] =
+ vb2_dma_contig_plane_dma_addr(vb, i);
+ }
+
+ /* Y plane */
+ meson_canvas_config(core->canvas, canvas_id[0], buf_paddr[0],
+ width, height, MESON_CANVAS_WRAP_NONE,
+ MESON_CANVAS_BLKMODE_LINEAR,
+ MESON_CANVAS_ENDIAN_SWAP64);
+
+ /* U/V plane */
+ meson_canvas_config(core->canvas, canvas_id[1], buf_paddr[1],
+ width, height / 2, MESON_CANVAS_WRAP_NONE,
+ MESON_CANVAS_BLKMODE_LINEAR,
+ MESON_CANVAS_ENDIAN_SWAP64);
+
+ amvdec_write_dos(core, reg,
+ ((canvas_id[1]) << 16) |
+ ((canvas_id[1]) << 8) |
+ (canvas_id[0]));
+
+ return 0;
+}
+
+int amvdec_set_canvases(struct amvdec_session *sess,
+ u32 reg_base[], u32 reg_num[])
+{
+ struct v4l2_m2m_buffer *buf;
+ u32 pixfmt = sess->pixfmt_cap;
+ u32 width = ALIGN(sess->width, 64);
+ u32 height = ALIGN(sess->height, 64);
+ u32 reg_cur = reg_base[0];
+ u32 reg_num_cur = 0;
+ u32 reg_base_cur = 0;
+ int i = 0;
+ int ret;
+
+ v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) {
+ if (!reg_base[reg_base_cur])
+ return -EINVAL;
+
+ reg_cur = reg_base[reg_base_cur] + reg_num_cur * 4;
+
+ switch (pixfmt) {
+ case V4L2_PIX_FMT_NV12M:
+ ret = set_canvas_nv12m(sess, &buf->vb.vb2_buf, width,
+ height, reg_cur);
+ if (ret)
+ return ret;
+ break;
+ case V4L2_PIX_FMT_YUV420M:
+ ret = set_canvas_yuv420m(sess, &buf->vb.vb2_buf, width,
+ height, reg_cur);
+ if (ret)
+ return ret;
+ break;
+ default:
+ dev_err(sess->core->dev, "Unsupported pixfmt %08X\n",
+ pixfmt);
+ return -EINVAL;
+ }
+
+ reg_num_cur++;
+ if (reg_num_cur >= reg_num[reg_base_cur]) {
+ reg_base_cur++;
+ reg_num_cur = 0;
+ }
+
+ sess->fw_idx_to_vb2_idx[i++] = buf->vb.vb2_buf.index;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(amvdec_set_canvases);
+
+void amvdec_add_ts_reorder(struct amvdec_session *sess, u64 ts, u32 offset)
+{
+ struct amvdec_timestamp *new_ts, *tmp;
+ unsigned long flags;
+
+ new_ts = kmalloc(sizeof(*new_ts), GFP_KERNEL);
+ new_ts->ts = ts;
+ new_ts->offset = offset;
+
+ spin_lock_irqsave(&sess->ts_spinlock, flags);
+
+ if (list_empty(&sess->timestamps))
+ goto add_tail;
+
+ list_for_each_entry(tmp, &sess->timestamps, list) {
+ if (ts <= tmp->ts) {
+ list_add_tail(&new_ts->list, &tmp->list);
+ goto unlock;
+ }
+ }
+
+add_tail:
+ list_add_tail(&new_ts->list, &sess->timestamps);
+unlock:
+ spin_unlock_irqrestore(&sess->ts_spinlock, flags);
+}
+EXPORT_SYMBOL_GPL(amvdec_add_ts_reorder);
+
+void amvdec_remove_ts(struct amvdec_session *sess, u64 ts)
+{
+ struct amvdec_timestamp *tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sess->ts_spinlock, flags);
+ list_for_each_entry(tmp, &sess->timestamps, list) {
+ if (tmp->ts == ts) {
+ list_del(&tmp->list);
+ kfree(tmp);
+ goto unlock;
+ }
+ }
+ dev_warn(sess->core->dev_dec,
+ "Couldn't remove buffer with timestamp %llu from list\n", ts);
+
+unlock:
+ spin_unlock_irqrestore(&sess->ts_spinlock, flags);
+}
+EXPORT_SYMBOL_GPL(amvdec_remove_ts);
+
+static void dst_buf_done(struct amvdec_session *sess,
+ struct vb2_v4l2_buffer *vbuf,
+ u32 field,
+ u64 timestamp)
+{
+ struct device *dev = sess->core->dev_dec;
+ u32 output_size = amvdec_get_output_size(sess);
+
+ switch (sess->pixfmt_cap) {
+ case V4L2_PIX_FMT_NV12M:
+ vbuf->vb2_buf.planes[0].bytesused = output_size;
+ vbuf->vb2_buf.planes[1].bytesused = output_size / 2;
+ break;
+ case V4L2_PIX_FMT_YUV420M:
+ vbuf->vb2_buf.planes[0].bytesused = output_size;
+ vbuf->vb2_buf.planes[1].bytesused = output_size / 4;
+ vbuf->vb2_buf.planes[2].bytesused = output_size / 4;
+ break;
+ }
+
+ vbuf->vb2_buf.timestamp = timestamp;
+ vbuf->sequence = sess->sequence_cap++;
+
+ if (sess->should_stop &&
+ atomic_read(&sess->esparser_queued_bufs) <= 2) {
+ const struct v4l2_event ev = { .type = V4L2_EVENT_EOS };
+
+ dev_dbg(dev, "Signaling EOS\n");
+ v4l2_event_queue_fh(&sess->fh, &ev);
+ vbuf->flags |= V4L2_BUF_FLAG_LAST;
+ } else if (sess->should_stop)
+ dev_dbg(dev, "should_stop, %u bufs remain\n",
+ atomic_read(&sess->esparser_queued_bufs));
+
+ dev_dbg(dev, "Buffer %u done\n", vbuf->vb2_buf.index);
+ vbuf->field = field;
+ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
+
+ /* Buffer done probably means the vififo got freed */
+ schedule_work(&sess->esparser_queue_work);
+}
+
+void amvdec_dst_buf_done(struct amvdec_session *sess,
+ struct vb2_v4l2_buffer *vbuf, u32 field)
+{
+ struct device *dev = sess->core->dev_dec;
+ struct amvdec_timestamp *tmp;
+ struct list_head *timestamps = &sess->timestamps;
+ u64 timestamp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sess->ts_spinlock, flags);
+ if (list_empty(timestamps)) {
+ dev_err(dev, "Buffer %u done but list is empty\n",
+ vbuf->vb2_buf.index);
+
+ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
+ spin_unlock_irqrestore(&sess->ts_spinlock, flags);
+ return;
+ }
+
+ tmp = list_first_entry(timestamps, struct amvdec_timestamp, list);
+ timestamp = tmp->ts;
+ list_del(&tmp->list);
+ kfree(tmp);
+ spin_unlock_irqrestore(&sess->ts_spinlock, flags);
+
+ dst_buf_done(sess, vbuf, field, timestamp);
+ atomic_dec(&sess->esparser_queued_bufs);
+}
+EXPORT_SYMBOL_GPL(amvdec_dst_buf_done);
+
+void amvdec_dst_buf_done_offset(struct amvdec_session *sess,
+ struct vb2_v4l2_buffer *vbuf,
+ u32 offset, u32 field, bool allow_drop)
+{
+ struct device *dev = sess->core->dev_dec;
+ struct amvdec_timestamp *match = NULL;
+ struct amvdec_timestamp *tmp, *n;
+ u64 timestamp = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sess->ts_spinlock, flags);
+
+ /* Look for our vififo offset to get the corresponding timestamp. */
+ list_for_each_entry_safe(tmp, n, &sess->timestamps, list) {
+ s64 delta = (s64)offset - tmp->offset;
+
+ /* Offsets reported by codecs usually differ slightly,
+ * so we need some wiggle room.
+ * 4KiB being the minimum packet size, there is no risk here.
+ */
+ if (delta > (-1 * (s32)SZ_4K) && delta < SZ_4K) {
+ match = tmp;
+ break;
+ }
+
+ if (!allow_drop)
+ continue;
+
+ /* Delete any timestamp entry that appears before our target
+ * (not all src packets/timestamps lead to a frame)
+ */
+ if (delta > 0 || delta < -1 * (s32)sess->vififo_size) {
+ atomic_dec(&sess->esparser_queued_bufs);
+ list_del(&tmp->list);
+ kfree(tmp);
+ }
+ }
+
+ if (!match) {
+ dev_dbg(dev, "Buffer %u done but can't match offset (%08X)\n",
+ vbuf->vb2_buf.index, offset);
+ } else {
+ timestamp = match->ts;
+ list_del(&match->list);
+ kfree(match);
+ }
+ spin_unlock_irqrestore(&sess->ts_spinlock, flags);
+
+ dst_buf_done(sess, vbuf, field, timestamp);
+ if (match)
+ atomic_dec(&sess->esparser_queued_bufs);
+}
+EXPORT_SYMBOL_GPL(amvdec_dst_buf_done_offset);
+
+void amvdec_dst_buf_done_idx(struct amvdec_session *sess,
+ u32 buf_idx, u32 offset, u32 field)
+{
+ struct vb2_v4l2_buffer *vbuf;
+ struct device *dev = sess->core->dev_dec;
+
+ vbuf = v4l2_m2m_dst_buf_remove_by_idx(sess->m2m_ctx,
+ sess->fw_idx_to_vb2_idx[buf_idx]);
+
+ if (!vbuf) {
+ dev_err(dev,
+ "Buffer %u done but it doesn't exist in m2m_ctx\n",
+ buf_idx);
+ return;
+ }
+
+ if (offset != -1)
+ amvdec_dst_buf_done_offset(sess, vbuf, offset, field, true);
+ else
+ amvdec_dst_buf_done(sess, vbuf, field);
+}
+EXPORT_SYMBOL_GPL(amvdec_dst_buf_done_idx);
+
+void amvdec_set_par_from_dar(struct amvdec_session *sess,
+ u32 dar_num, u32 dar_den)
+{
+ u32 div;
+
+ sess->pixelaspect.numerator = sess->height * dar_num;
+ sess->pixelaspect.denominator = sess->width * dar_den;
+ div = gcd(sess->pixelaspect.numerator, sess->pixelaspect.denominator);
+ sess->pixelaspect.numerator /= div;
+ sess->pixelaspect.denominator /= div;
+}
+EXPORT_SYMBOL_GPL(amvdec_set_par_from_dar);
+
+void amvdec_src_change(struct amvdec_session *sess, u32 width,
+ u32 height, u32 dpb_size)
+{
+ static const struct v4l2_event ev = {
+ .type = V4L2_EVENT_SOURCE_CHANGE,
+ .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION };
+
+ v4l2_ctrl_s_ctrl(sess->ctrl_min_buf_capture, dpb_size);
+
+ /* Check if the capture queue is already configured well for our
+ * usecase. If so, keep decoding with it and do not send the event
+ */
+ if (sess->width == width &&
+ sess->height == height &&
+ dpb_size <= sess->num_dst_bufs) {
+ sess->fmt_out->codec_ops->resume(sess);
+ return;
+ }
+
+ sess->width = width;
+ sess->height = height;
+ sess->status = STATUS_NEEDS_RESUME;
+
+ dev_dbg(sess->core->dev, "Res. changed (%ux%u), DPB size %u\n",
+ width, height, dpb_size);
+ v4l2_event_queue_fh(&sess->fh, &ev);
+}
+EXPORT_SYMBOL_GPL(amvdec_src_change);
+
+void amvdec_abort(struct amvdec_session *sess)
+{
+ dev_info(sess->core->dev, "Aborting decoding session!\n");
+ vb2_queue_error(&sess->m2m_ctx->cap_q_ctx.q);
+ vb2_queue_error(&sess->m2m_ctx->out_q_ctx.q);
+}
+EXPORT_SYMBOL_GPL(amvdec_abort);
diff --git a/drivers/staging/media/meson/vdec/vdec_helpers.h b/drivers/staging/media/meson/vdec/vdec_helpers.h
new file mode 100644
index 000000000000..a455a9ee1cc2
--- /dev/null
+++ b/drivers/staging/media/meson/vdec/vdec_helpers.h
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2018 BayLibre, SAS
+ * Author: Maxime Jourdan <mjourdan@baylibre.com>
+ */
+
+#ifndef __MESON_VDEC_HELPERS_H_
+#define __MESON_VDEC_HELPERS_H_
+
+#include "vdec.h"
+
+/**
+ * amvdec_set_canvases() - Map VB2 buffers to canvases
+ *
+ * @sess: current session
+ * @reg_base: Registry bases of where to write the canvas indexes
+ * @reg_num: number of contiguous registers after each reg_base (including it)
+ */
+int amvdec_set_canvases(struct amvdec_session *sess,
+ u32 reg_base[], u32 reg_num[]);
+
+/* Helpers to read/write to the various IPs (DOS, PARSER) */
+u32 amvdec_read_dos(struct amvdec_core *core, u32 reg);
+void amvdec_write_dos(struct amvdec_core *core, u32 reg, u32 val);
+void amvdec_write_dos_bits(struct amvdec_core *core, u32 reg, u32 val);
+void amvdec_clear_dos_bits(struct amvdec_core *core, u32 reg, u32 val);
+u32 amvdec_read_parser(struct amvdec_core *core, u32 reg);
+void amvdec_write_parser(struct amvdec_core *core, u32 reg, u32 val);
+
+/**
+ * amvdec_dst_buf_done_idx() - Signal that a buffer is done decoding
+ *
+ * @sess: current session
+ * @buf_idx: hardware buffer index
+ * @offset: VIFIFO bitstream offset corresponding to the buffer
+ * @field: V4L2 interlaced field
+ */
+void amvdec_dst_buf_done_idx(struct amvdec_session *sess, u32 buf_idx,
+ u32 offset, u32 field);
+void amvdec_dst_buf_done(struct amvdec_session *sess,
+ struct vb2_v4l2_buffer *vbuf, u32 field);
+void amvdec_dst_buf_done_offset(struct amvdec_session *sess,
+ struct vb2_v4l2_buffer *vbuf,
+ u32 offset, u32 field, bool allow_drop);
+
+/**
+ * amvdec_add_ts_reorder() - Add a timestamp to the list in chronological order
+ *
+ * @sess: current session
+ * @ts: timestamp to add
+ * @offset: offset in the VIFIFO where the associated packet was written
+ */
+void amvdec_add_ts_reorder(struct amvdec_session *sess, u64 ts, u32 offset);
+void amvdec_remove_ts(struct amvdec_session *sess, u64 ts);
+
+/**
+ * amvdec_set_par_from_dar() - Set Pixel Aspect Ratio from Display Aspect Ratio
+ *
+ * @sess: current session
+ * @dar_num: numerator of the DAR
+ * @dar_den: denominator of the DAR
+ */
+void amvdec_set_par_from_dar(struct amvdec_session *sess,
+ u32 dar_num, u32 dar_den);
+
+/**
+ * amvdec_src_change() - Notify new resolution/DPB size to the core
+ *
+ * @sess: current session
+ * @width: picture width detected by the hardware
+ * @height: picture height detected by the hardware
+ * @dpb_size: Decoded Picture Buffer size (= amount of buffers for decoding)
+ */
+void amvdec_src_change(struct amvdec_session *sess, u32 width,
+ u32 height, u32 dpb_size);
+
+/**
+ * amvdec_abort() - Abort the current decoding session
+ *
+ * @sess: current session
+ */
+void amvdec_abort(struct amvdec_session *sess);
+#endif
diff --git a/drivers/staging/media/meson/vdec/vdec_platform.c b/drivers/staging/media/meson/vdec/vdec_platform.c
new file mode 100644
index 000000000000..824dbc7f46f5
--- /dev/null
+++ b/drivers/staging/media/meson/vdec/vdec_platform.c
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 BayLibre, SAS
+ * Author: Maxime Jourdan <mjourdan@baylibre.com>
+ */
+
+#include "vdec_platform.h"
+#include "vdec.h"
+
+#include "vdec_1.h"
+#include "codec_mpeg12.h"
+
+static const struct amvdec_format vdec_formats_gxbb[] = {
+ {
+ .pixfmt = V4L2_PIX_FMT_MPEG1,
+ .min_buffers = 8,
+ .max_buffers = 8,
+ .max_width = 1920,
+ .max_height = 1080,
+ .vdec_ops = &vdec_1_ops,
+ .codec_ops = &codec_mpeg12_ops,
+ .firmware_path = "meson/vdec/gxl_mpeg12.bin",
+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
+ }, {
+ .pixfmt = V4L2_PIX_FMT_MPEG2,
+ .min_buffers = 8,
+ .max_buffers = 8,
+ .max_width = 1920,
+ .max_height = 1080,
+ .vdec_ops = &vdec_1_ops,
+ .codec_ops = &codec_mpeg12_ops,
+ .firmware_path = "meson/vdec/gxl_mpeg12.bin",
+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
+ },
+};
+
+static const struct amvdec_format vdec_formats_gxl[] = {
+ {
+ .pixfmt = V4L2_PIX_FMT_MPEG1,
+ .min_buffers = 8,
+ .max_buffers = 8,
+ .max_width = 1920,
+ .max_height = 1080,
+ .vdec_ops = &vdec_1_ops,
+ .codec_ops = &codec_mpeg12_ops,
+ .firmware_path = "meson/vdec/gxl_mpeg12.bin",
+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
+ }, {
+ .pixfmt = V4L2_PIX_FMT_MPEG2,
+ .min_buffers = 8,
+ .max_buffers = 8,
+ .max_width = 1920,
+ .max_height = 1080,
+ .vdec_ops = &vdec_1_ops,
+ .codec_ops = &codec_mpeg12_ops,
+ .firmware_path = "meson/vdec/gxl_mpeg12.bin",
+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
+ },
+};
+
+static const struct amvdec_format vdec_formats_gxm[] = {
+ {
+ .pixfmt = V4L2_PIX_FMT_MPEG1,
+ .min_buffers = 8,
+ .max_buffers = 8,
+ .max_width = 1920,
+ .max_height = 1080,
+ .vdec_ops = &vdec_1_ops,
+ .codec_ops = &codec_mpeg12_ops,
+ .firmware_path = "meson/vdec/gxl_mpeg12.bin",
+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
+ }, {
+ .pixfmt = V4L2_PIX_FMT_MPEG2,
+ .min_buffers = 8,
+ .max_buffers = 8,
+ .max_width = 1920,
+ .max_height = 1080,
+ .vdec_ops = &vdec_1_ops,
+ .codec_ops = &codec_mpeg12_ops,
+ .firmware_path = "meson/vdec/gxl_mpeg12.bin",
+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
+ },
+};
+
+const struct vdec_platform vdec_platform_gxbb = {
+ .formats = vdec_formats_gxbb,
+ .num_formats = ARRAY_SIZE(vdec_formats_gxbb),
+ .revision = VDEC_REVISION_GXBB,
+};
+
+const struct vdec_platform vdec_platform_gxl = {
+ .formats = vdec_formats_gxl,
+ .num_formats = ARRAY_SIZE(vdec_formats_gxl),
+ .revision = VDEC_REVISION_GXL,
+};
+
+const struct vdec_platform vdec_platform_gxm = {
+ .formats = vdec_formats_gxm,
+ .num_formats = ARRAY_SIZE(vdec_formats_gxm),
+ .revision = VDEC_REVISION_GXM,
+};
diff --git a/drivers/staging/media/meson/vdec/vdec_platform.h b/drivers/staging/media/meson/vdec/vdec_platform.h
new file mode 100644
index 000000000000..f6025326db1d
--- /dev/null
+++ b/drivers/staging/media/meson/vdec/vdec_platform.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2018 BayLibre, SAS
+ * Author: Maxime Jourdan <mjourdan@baylibre.com>
+ */
+
+#ifndef __MESON_VDEC_PLATFORM_H_
+#define __MESON_VDEC_PLATFORM_H_
+
+#include "vdec.h"
+
+struct amvdec_format;
+
+enum vdec_revision {
+ VDEC_REVISION_GXBB,
+ VDEC_REVISION_GXL,
+ VDEC_REVISION_GXM,
+};
+
+struct vdec_platform {
+ const struct amvdec_format *formats;
+ const u32 num_formats;
+ enum vdec_revision revision;
+};
+
+extern const struct vdec_platform vdec_platform_gxbb;
+extern const struct vdec_platform vdec_platform_gxm;
+extern const struct vdec_platform vdec_platform_gxl;
+
+#endif
diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c
index c2c5a9cd8642..c307707480f7 100644
--- a/drivers/staging/media/omap4iss/iss_video.c
+++ b/drivers/staging/media/omap4iss/iss_video.c
@@ -533,12 +533,6 @@ iss_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
strscpy(cap->driver, ISS_VIDEO_DRIVER_NAME, sizeof(cap->driver));
strscpy(cap->card, video->video.name, sizeof(cap->card));
strscpy(cap->bus_info, "media", sizeof(cap->bus_info));
-
- if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
- else
- cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
-
cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING
| V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT;
@@ -1272,6 +1266,11 @@ int omap4iss_video_register(struct iss_video *video, struct v4l2_device *vdev)
int ret;
video->video.v4l2_dev = vdev;
+ if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ video->video.device_caps = V4L2_CAP_VIDEO_CAPTURE;
+ else
+ video->video.device_caps = V4L2_CAP_VIDEO_OUTPUT;
+ video->video.device_caps |= V4L2_CAP_STREAMING;
ret = video_register_device(&video->video, VFL_TYPE_GRABBER, -1);
if (ret < 0)
diff --git a/drivers/staging/media/rockchip/vpu/Kconfig b/drivers/staging/media/rockchip/vpu/Kconfig
deleted file mode 100644
index fc54bbf6753d..000000000000
--- a/drivers/staging/media/rockchip/vpu/Kconfig
+++ /dev/null
@@ -1,13 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-config VIDEO_ROCKCHIP_VPU
- tristate "Rockchip VPU driver"
- depends on ARCH_ROCKCHIP || COMPILE_TEST
- depends on VIDEO_DEV && VIDEO_V4L2 && MEDIA_CONTROLLER
- select VIDEOBUF2_DMA_CONTIG
- select VIDEOBUF2_VMALLOC
- select V4L2_MEM2MEM_DEV
- help
- Support for the Video Processing Unit present on Rockchip SoC,
- which accelerates video and image encoding and decoding.
- To compile this driver as a module, choose M here: the module
- will be called rockchip-vpu.
diff --git a/drivers/staging/media/rockchip/vpu/Makefile b/drivers/staging/media/rockchip/vpu/Makefile
deleted file mode 100644
index ae5d143a0bfa..000000000000
--- a/drivers/staging/media/rockchip/vpu/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_VIDEO_ROCKCHIP_VPU) += rockchip-vpu.o
-
-rockchip-vpu-y += \
- rockchip_vpu_drv.o \
- rockchip_vpu_enc.o \
- rk3288_vpu_hw.o \
- rk3288_vpu_hw_jpeg_enc.o \
- rk3399_vpu_hw.o \
- rk3399_vpu_hw_jpeg_enc.o \
- rockchip_vpu_jpeg.o
diff --git a/drivers/staging/media/rockchip/vpu/rk3288_vpu_hw.c b/drivers/staging/media/rockchip/vpu/rk3288_vpu_hw.c
deleted file mode 100644
index a5e9d183fffd..000000000000
--- a/drivers/staging/media/rockchip/vpu/rk3288_vpu_hw.c
+++ /dev/null
@@ -1,118 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Rockchip VPU codec driver
- *
- * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
- * Jeffy Chen <jeffy.chen@rock-chips.com>
- */
-
-#include <linux/clk.h>
-
-#include "rockchip_vpu.h"
-#include "rockchip_vpu_jpeg.h"
-#include "rk3288_vpu_regs.h"
-
-#define RK3288_ACLK_MAX_FREQ (400 * 1000 * 1000)
-
-/*
- * Supported formats.
- */
-
-static const struct rockchip_vpu_fmt rk3288_vpu_enc_fmts[] = {
- {
- .fourcc = V4L2_PIX_FMT_YUV420M,
- .codec_mode = RK_VPU_MODE_NONE,
- .enc_fmt = RK3288_VPU_ENC_FMT_YUV420P,
- },
- {
- .fourcc = V4L2_PIX_FMT_NV12M,
- .codec_mode = RK_VPU_MODE_NONE,
- .enc_fmt = RK3288_VPU_ENC_FMT_YUV420SP,
- },
- {
- .fourcc = V4L2_PIX_FMT_YUYV,
- .codec_mode = RK_VPU_MODE_NONE,
- .enc_fmt = RK3288_VPU_ENC_FMT_YUYV422,
- },
- {
- .fourcc = V4L2_PIX_FMT_UYVY,
- .codec_mode = RK_VPU_MODE_NONE,
- .enc_fmt = RK3288_VPU_ENC_FMT_UYVY422,
- },
- {
- .fourcc = V4L2_PIX_FMT_JPEG,
- .codec_mode = RK_VPU_MODE_JPEG_ENC,
- .max_depth = 2,
- .header_size = JPEG_HEADER_SIZE,
- .frmsize = {
- .min_width = 96,
- .max_width = 8192,
- .step_width = JPEG_MB_DIM,
- .min_height = 32,
- .max_height = 8192,
- .step_height = JPEG_MB_DIM,
- },
- },
-};
-
-static irqreturn_t rk3288_vepu_irq(int irq, void *dev_id)
-{
- struct rockchip_vpu_dev *vpu = dev_id;
- enum vb2_buffer_state state;
- u32 status, bytesused;
-
- status = vepu_read(vpu, VEPU_REG_INTERRUPT);
- bytesused = vepu_read(vpu, VEPU_REG_STR_BUF_LIMIT) / 8;
- state = (status & VEPU_REG_INTERRUPT_FRAME_RDY) ?
- VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR;
-
- vepu_write(vpu, 0, VEPU_REG_INTERRUPT);
- vepu_write(vpu, 0, VEPU_REG_AXI_CTRL);
-
- rockchip_vpu_irq_done(vpu, bytesused, state);
-
- return IRQ_HANDLED;
-}
-
-static int rk3288_vpu_hw_init(struct rockchip_vpu_dev *vpu)
-{
- /* Bump ACLK to max. possible freq. to improve performance. */
- clk_set_rate(vpu->clocks[0].clk, RK3288_ACLK_MAX_FREQ);
- return 0;
-}
-
-static void rk3288_vpu_enc_reset(struct rockchip_vpu_ctx *ctx)
-{
- struct rockchip_vpu_dev *vpu = ctx->dev;
-
- vepu_write(vpu, VEPU_REG_INTERRUPT_DIS_BIT, VEPU_REG_INTERRUPT);
- vepu_write(vpu, 0, VEPU_REG_ENC_CTRL);
- vepu_write(vpu, 0, VEPU_REG_AXI_CTRL);
-}
-
-/*
- * Supported codec ops.
- */
-
-static const struct rockchip_vpu_codec_ops rk3288_vpu_codec_ops[] = {
- [RK_VPU_MODE_JPEG_ENC] = {
- .run = rk3288_vpu_jpeg_enc_run,
- .reset = rk3288_vpu_enc_reset,
- },
-};
-
-/*
- * VPU variant.
- */
-
-const struct rockchip_vpu_variant rk3288_vpu_variant = {
- .enc_offset = 0x0,
- .enc_fmts = rk3288_vpu_enc_fmts,
- .num_enc_fmts = ARRAY_SIZE(rk3288_vpu_enc_fmts),
- .codec_ops = rk3288_vpu_codec_ops,
- .codec = RK_VPU_CODEC_JPEG,
- .vepu_irq = rk3288_vepu_irq,
- .init = rk3288_vpu_hw_init,
- .clk_names = {"aclk", "hclk"},
- .num_clocks = 2
-};
diff --git a/drivers/staging/media/rockchip/vpu/rk3288_vpu_hw_jpeg_enc.c b/drivers/staging/media/rockchip/vpu/rk3288_vpu_hw_jpeg_enc.c
deleted file mode 100644
index 06daea66fb49..000000000000
--- a/drivers/staging/media/rockchip/vpu/rk3288_vpu_hw_jpeg_enc.c
+++ /dev/null
@@ -1,125 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Rockchip VPU codec driver
- *
- * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
- */
-
-#include <asm/unaligned.h>
-#include <media/v4l2-mem2mem.h>
-#include "rockchip_vpu_jpeg.h"
-#include "rockchip_vpu.h"
-#include "rockchip_vpu_common.h"
-#include "rockchip_vpu_hw.h"
-#include "rk3288_vpu_regs.h"
-
-#define VEPU_JPEG_QUANT_TABLE_COUNT 16
-
-static void rk3288_vpu_set_src_img_ctrl(struct rockchip_vpu_dev *vpu,
- struct rockchip_vpu_ctx *ctx)
-{
- struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt;
- u32 reg;
-
- reg = VEPU_REG_IN_IMG_CTRL_ROW_LEN(pix_fmt->width)
- | VEPU_REG_IN_IMG_CTRL_OVRFLR_D4(0)
- | VEPU_REG_IN_IMG_CTRL_OVRFLB_D4(0)
- | VEPU_REG_IN_IMG_CTRL_FMT(ctx->vpu_src_fmt->enc_fmt);
- vepu_write_relaxed(vpu, reg, VEPU_REG_IN_IMG_CTRL);
-}
-
-static void rk3288_vpu_jpeg_enc_set_buffers(struct rockchip_vpu_dev *vpu,
- struct rockchip_vpu_ctx *ctx,
- struct vb2_buffer *src_buf)
-{
- struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt;
- dma_addr_t src[3];
-
- WARN_ON(pix_fmt->num_planes > 3);
-
- vepu_write_relaxed(vpu, ctx->bounce_dma_addr,
- VEPU_REG_ADDR_OUTPUT_STREAM);
- vepu_write_relaxed(vpu, ctx->bounce_size,
- VEPU_REG_STR_BUF_LIMIT);
-
- if (pix_fmt->num_planes == 1) {
- src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0);
- /* single plane formats we supported are all interlaced */
- vepu_write_relaxed(vpu, src[0], VEPU_REG_ADDR_IN_PLANE_0);
- } else if (pix_fmt->num_planes == 2) {
- src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0);
- src[1] = vb2_dma_contig_plane_dma_addr(src_buf, 1);
- vepu_write_relaxed(vpu, src[0], VEPU_REG_ADDR_IN_PLANE_0);
- vepu_write_relaxed(vpu, src[1], VEPU_REG_ADDR_IN_PLANE_1);
- } else {
- src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0);
- src[1] = vb2_dma_contig_plane_dma_addr(src_buf, 1);
- src[2] = vb2_dma_contig_plane_dma_addr(src_buf, 2);
- vepu_write_relaxed(vpu, src[0], VEPU_REG_ADDR_IN_PLANE_0);
- vepu_write_relaxed(vpu, src[1], VEPU_REG_ADDR_IN_PLANE_1);
- vepu_write_relaxed(vpu, src[2], VEPU_REG_ADDR_IN_PLANE_2);
- }
-}
-
-static void
-rk3288_vpu_jpeg_enc_set_qtable(struct rockchip_vpu_dev *vpu,
- unsigned char *luma_qtable,
- unsigned char *chroma_qtable)
-{
- u32 reg, i;
-
- for (i = 0; i < VEPU_JPEG_QUANT_TABLE_COUNT; i++) {
- reg = get_unaligned_be32(&luma_qtable[i]);
- vepu_write_relaxed(vpu, reg, VEPU_REG_JPEG_LUMA_QUAT(i));
-
- reg = get_unaligned_be32(&chroma_qtable[i]);
- vepu_write_relaxed(vpu, reg, VEPU_REG_JPEG_CHROMA_QUAT(i));
- }
-}
-
-void rk3288_vpu_jpeg_enc_run(struct rockchip_vpu_ctx *ctx)
-{
- struct rockchip_vpu_dev *vpu = ctx->dev;
- struct vb2_v4l2_buffer *src_buf, *dst_buf;
- struct rockchip_vpu_jpeg_ctx jpeg_ctx;
- u32 reg;
-
- src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
- dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
-
- memset(&jpeg_ctx, 0, sizeof(jpeg_ctx));
- jpeg_ctx.buffer = vb2_plane_vaddr(&dst_buf->vb2_buf, 0);
- jpeg_ctx.width = ctx->dst_fmt.width;
- jpeg_ctx.height = ctx->dst_fmt.height;
- jpeg_ctx.quality = ctx->jpeg_quality;
- rockchip_vpu_jpeg_header_assemble(&jpeg_ctx);
-
- /* Switch to JPEG encoder mode before writing registers */
- vepu_write_relaxed(vpu, VEPU_REG_ENC_CTRL_ENC_MODE_JPEG,
- VEPU_REG_ENC_CTRL);
-
- rk3288_vpu_set_src_img_ctrl(vpu, ctx);
- rk3288_vpu_jpeg_enc_set_buffers(vpu, ctx, &src_buf->vb2_buf);
- rk3288_vpu_jpeg_enc_set_qtable(vpu,
- rockchip_vpu_jpeg_get_qtable(&jpeg_ctx, 0),
- rockchip_vpu_jpeg_get_qtable(&jpeg_ctx, 1));
-
- reg = VEPU_REG_AXI_CTRL_OUTPUT_SWAP16
- | VEPU_REG_AXI_CTRL_INPUT_SWAP16
- | VEPU_REG_AXI_CTRL_BURST_LEN(16)
- | VEPU_REG_AXI_CTRL_OUTPUT_SWAP32
- | VEPU_REG_AXI_CTRL_INPUT_SWAP32
- | VEPU_REG_AXI_CTRL_OUTPUT_SWAP8
- | VEPU_REG_AXI_CTRL_INPUT_SWAP8;
- /* Make sure that all registers are written at this point. */
- vepu_write(vpu, reg, VEPU_REG_AXI_CTRL);
-
- reg = VEPU_REG_ENC_CTRL_WIDTH(JPEG_MB_WIDTH(ctx->src_fmt.width))
- | VEPU_REG_ENC_CTRL_HEIGHT(JPEG_MB_HEIGHT(ctx->src_fmt.height))
- | VEPU_REG_ENC_CTRL_ENC_MODE_JPEG
- | VEPU_REG_ENC_PIC_INTRA
- | VEPU_REG_ENC_CTRL_EN_BIT;
- /* Kick the watchdog and start encoding */
- schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000));
- vepu_write(vpu, reg, VEPU_REG_ENC_CTRL);
-}
diff --git a/drivers/staging/media/rockchip/vpu/rk3288_vpu_regs.h b/drivers/staging/media/rockchip/vpu/rk3288_vpu_regs.h
deleted file mode 100644
index 9d0b9bdf3297..000000000000
--- a/drivers/staging/media/rockchip/vpu/rk3288_vpu_regs.h
+++ /dev/null
@@ -1,442 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Rockchip VPU codec driver
- *
- * Copyright 2018 Google LLC.
- * Tomasz Figa <tfiga@chromium.org>
- */
-
-#ifndef RK3288_VPU_REGS_H_
-#define RK3288_VPU_REGS_H_
-
-/* Encoder registers. */
-#define VEPU_REG_INTERRUPT 0x004
-#define VEPU_REG_INTERRUPT_FRAME_RDY BIT(2)
-#define VEPU_REG_INTERRUPT_DIS_BIT BIT(1)
-#define VEPU_REG_INTERRUPT_BIT BIT(0)
-#define VEPU_REG_AXI_CTRL 0x008
-#define VEPU_REG_AXI_CTRL_OUTPUT_SWAP16 BIT(15)
-#define VEPU_REG_AXI_CTRL_INPUT_SWAP16 BIT(14)
-#define VEPU_REG_AXI_CTRL_BURST_LEN(x) ((x) << 8)
-#define VEPU_REG_AXI_CTRL_GATE_BIT BIT(4)
-#define VEPU_REG_AXI_CTRL_OUTPUT_SWAP32 BIT(3)
-#define VEPU_REG_AXI_CTRL_INPUT_SWAP32 BIT(2)
-#define VEPU_REG_AXI_CTRL_OUTPUT_SWAP8 BIT(1)
-#define VEPU_REG_AXI_CTRL_INPUT_SWAP8 BIT(0)
-#define VEPU_REG_ADDR_OUTPUT_STREAM 0x014
-#define VEPU_REG_ADDR_OUTPUT_CTRL 0x018
-#define VEPU_REG_ADDR_REF_LUMA 0x01c
-#define VEPU_REG_ADDR_REF_CHROMA 0x020
-#define VEPU_REG_ADDR_REC_LUMA 0x024
-#define VEPU_REG_ADDR_REC_CHROMA 0x028
-#define VEPU_REG_ADDR_IN_PLANE_0 0x02c
-#define VEPU_REG_ADDR_IN_PLANE_1 0x030
-#define VEPU_REG_ADDR_IN_PLANE_2 0x034
-#define VEPU_REG_ENC_CTRL 0x038
-#define VEPU_REG_ENC_CTRL_TIMEOUT_EN BIT(31)
-#define VEPU_REG_ENC_CTRL_NAL_MODE_BIT BIT(29)
-#define VEPU_REG_ENC_CTRL_WIDTH(w) ((w) << 19)
-#define VEPU_REG_ENC_CTRL_HEIGHT(h) ((h) << 10)
-#define VEPU_REG_ENC_PIC_INTER (0x0 << 3)
-#define VEPU_REG_ENC_PIC_INTRA (0x1 << 3)
-#define VEPU_REG_ENC_PIC_MVCINTER (0x2 << 3)
-#define VEPU_REG_ENC_CTRL_ENC_MODE_H264 (0x3 << 1)
-#define VEPU_REG_ENC_CTRL_ENC_MODE_JPEG (0x2 << 1)
-#define VEPU_REG_ENC_CTRL_ENC_MODE_VP8 (0x1 << 1)
-#define VEPU_REG_ENC_CTRL_EN_BIT BIT(0)
-#define VEPU_REG_IN_IMG_CTRL 0x03c
-#define VEPU_REG_IN_IMG_CTRL_ROW_LEN(x) ((x) << 12)
-#define VEPU_REG_IN_IMG_CTRL_OVRFLR_D4(x) ((x) << 10)
-#define VEPU_REG_IN_IMG_CTRL_OVRFLB_D4(x) ((x) << 6)
-#define VEPU_REG_IN_IMG_CTRL_FMT(x) ((x) << 2)
-#define VEPU_REG_ENC_CTRL0 0x040
-#define VEPU_REG_ENC_CTRL0_INIT_QP(x) ((x) << 26)
-#define VEPU_REG_ENC_CTRL0_SLICE_ALPHA(x) ((x) << 22)
-#define VEPU_REG_ENC_CTRL0_SLICE_BETA(x) ((x) << 18)
-#define VEPU_REG_ENC_CTRL0_CHROMA_QP_OFFSET(x) ((x) << 13)
-#define VEPU_REG_ENC_CTRL0_FILTER_DIS(x) ((x) << 5)
-#define VEPU_REG_ENC_CTRL0_IDR_PICID(x) ((x) << 1)
-#define VEPU_REG_ENC_CTRL0_CONSTR_INTRA_PRED BIT(0)
-#define VEPU_REG_ENC_CTRL1 0x044
-#define VEPU_REG_ENC_CTRL1_PPS_ID(x) ((x) << 24)
-#define VEPU_REG_ENC_CTRL1_INTRA_PRED_MODE(x) ((x) << 16)
-#define VEPU_REG_ENC_CTRL1_FRAME_NUM(x) ((x))
-#define VEPU_REG_ENC_CTRL2 0x048
-#define VEPU_REG_ENC_CTRL2_DEBLOCKING_FILETER_MODE(x) ((x) << 30)
-#define VEPU_REG_ENC_CTRL2_H264_SLICE_SIZE(x) ((x) << 23)
-#define VEPU_REG_ENC_CTRL2_DISABLE_QUARTER_PIXMV BIT(22)
-#define VEPU_REG_ENC_CTRL2_TRANS8X8_MODE_EN BIT(21)
-#define VEPU_REG_ENC_CTRL2_CABAC_INIT_IDC(x) ((x) << 19)
-#define VEPU_REG_ENC_CTRL2_ENTROPY_CODING_MODE BIT(18)
-#define VEPU_REG_ENC_CTRL2_H264_INTER4X4_MODE BIT(17)
-#define VEPU_REG_ENC_CTRL2_H264_STREAM_MODE BIT(16)
-#define VEPU_REG_ENC_CTRL2_INTRA16X16_MODE(x) ((x))
-#define VEPU_REG_ENC_CTRL3 0x04c
-#define VEPU_REG_ENC_CTRL3_MUTIMV_EN BIT(30)
-#define VEPU_REG_ENC_CTRL3_MV_PENALTY_1_4P(x) ((x) << 20)
-#define VEPU_REG_ENC_CTRL3_MV_PENALTY_4P(x) ((x) << 10)
-#define VEPU_REG_ENC_CTRL3_MV_PENALTY_1P(x) ((x))
-#define VEPU_REG_ENC_CTRL4 0x050
-#define VEPU_REG_ENC_CTRL4_MV_PENALTY_16X8_8X16(x) ((x) << 20)
-#define VEPU_REG_ENC_CTRL4_MV_PENALTY_8X8(x) ((x) << 10)
-#define VEPU_REG_ENC_CTRL4_8X4_4X8(x) ((x))
-#define VEPU_REG_ENC_CTRL5 0x054
-#define VEPU_REG_ENC_CTRL5_MACROBLOCK_PENALTY(x) ((x) << 24)
-#define VEPU_REG_ENC_CTRL5_COMPLETE_SLICES(x) ((x) << 16)
-#define VEPU_REG_ENC_CTRL5_INTER_MODE(x) ((x))
-#define VEPU_REG_STR_HDR_REM_MSB 0x058
-#define VEPU_REG_STR_HDR_REM_LSB 0x05c
-#define VEPU_REG_STR_BUF_LIMIT 0x060
-#define VEPU_REG_MAD_CTRL 0x064
-#define VEPU_REG_MAD_CTRL_QP_ADJUST(x) ((x) << 28)
-#define VEPU_REG_MAD_CTRL_MAD_THREDHOLD(x) ((x) << 22)
-#define VEPU_REG_MAD_CTRL_QP_SUM_DIV2(x) ((x))
-#define VEPU_REG_ADDR_VP8_PROB_CNT 0x068
-#define VEPU_REG_QP_VAL 0x06c
-#define VEPU_REG_QP_VAL_LUM(x) ((x) << 26)
-#define VEPU_REG_QP_VAL_MAX(x) ((x) << 20)
-#define VEPU_REG_QP_VAL_MIN(x) ((x) << 14)
-#define VEPU_REG_QP_VAL_CHECKPOINT_DISTAN(x) ((x))
-#define VEPU_REG_VP8_QP_VAL(i) (0x06c + ((i) * 0x4))
-#define VEPU_REG_CHECKPOINT(i) (0x070 + ((i) * 0x4))
-#define VEPU_REG_CHECKPOINT_CHECK0(x) (((x) & 0xffff))
-#define VEPU_REG_CHECKPOINT_CHECK1(x) (((x) & 0xffff) << 16)
-#define VEPU_REG_CHECKPOINT_RESULT(x) ((((x) >> (16 - 16 \
- * (i & 1))) & 0xffff) \
- * 32)
-#define VEPU_REG_CHKPT_WORD_ERR(i) (0x084 + ((i) * 0x4))
-#define VEPU_REG_CHKPT_WORD_ERR_CHK0(x) (((x) & 0xffff))
-#define VEPU_REG_CHKPT_WORD_ERR_CHK1(x) (((x) & 0xffff) << 16)
-#define VEPU_REG_VP8_BOOL_ENC 0x08c
-#define VEPU_REG_CHKPT_DELTA_QP 0x090
-#define VEPU_REG_CHKPT_DELTA_QP_CHK0(x) (((x) & 0x0f) << 0)
-#define VEPU_REG_CHKPT_DELTA_QP_CHK1(x) (((x) & 0x0f) << 4)
-#define VEPU_REG_CHKPT_DELTA_QP_CHK2(x) (((x) & 0x0f) << 8)
-#define VEPU_REG_CHKPT_DELTA_QP_CHK3(x) (((x) & 0x0f) << 12)
-#define VEPU_REG_CHKPT_DELTA_QP_CHK4(x) (((x) & 0x0f) << 16)
-#define VEPU_REG_CHKPT_DELTA_QP_CHK5(x) (((x) & 0x0f) << 20)
-#define VEPU_REG_CHKPT_DELTA_QP_CHK6(x) (((x) & 0x0f) << 24)
-#define VEPU_REG_VP8_CTRL0 0x090
-#define VEPU_REG_RLC_CTRL 0x094
-#define VEPU_REG_RLC_CTRL_STR_OFFS_SHIFT 23
-#define VEPU_REG_RLC_CTRL_STR_OFFS_MASK (0x3f << 23)
-#define VEPU_REG_RLC_CTRL_RLC_SUM(x) ((x))
-#define VEPU_REG_MB_CTRL 0x098
-#define VEPU_REG_MB_CNT_OUT(x) (((x) & 0xffff))
-#define VEPU_REG_MB_CNT_SET(x) (((x) & 0xffff) << 16)
-#define VEPU_REG_ADDR_NEXT_PIC 0x09c
-#define VEPU_REG_JPEG_LUMA_QUAT(i) (0x100 + ((i) * 0x4))
-#define VEPU_REG_JPEG_CHROMA_QUAT(i) (0x140 + ((i) * 0x4))
-#define VEPU_REG_STABILIZATION_OUTPUT 0x0A0
-#define VEPU_REG_ADDR_CABAC_TBL 0x0cc
-#define VEPU_REG_ADDR_MV_OUT 0x0d0
-#define VEPU_REG_RGB_YUV_COEFF(i) (0x0d4 + ((i) * 0x4))
-#define VEPU_REG_RGB_MASK_MSB 0x0dc
-#define VEPU_REG_INTRA_AREA_CTRL 0x0e0
-#define VEPU_REG_CIR_INTRA_CTRL 0x0e4
-#define VEPU_REG_INTRA_SLICE_BITMAP(i) (0x0e8 + ((i) * 0x4))
-#define VEPU_REG_ADDR_VP8_DCT_PART(i) (0x0e8 + ((i) * 0x4))
-#define VEPU_REG_FIRST_ROI_AREA 0x0f0
-#define VEPU_REG_SECOND_ROI_AREA 0x0f4
-#define VEPU_REG_MVC_CTRL 0x0f8
-#define VEPU_REG_MVC_CTRL_MV16X16_FAVOR(x) ((x) << 28)
-#define VEPU_REG_VP8_INTRA_PENALTY(i) (0x100 + ((i) * 0x4))
-#define VEPU_REG_ADDR_VP8_SEG_MAP 0x11c
-#define VEPU_REG_VP8_SEG_QP(i) (0x120 + ((i) * 0x4))
-#define VEPU_REG_DMV_4P_1P_PENALTY(i) (0x180 + ((i) * 0x4))
-#define VEPU_REG_DMV_4P_1P_PENALTY_BIT(x, i) ((x) << (i) * 8)
-#define VEPU_REG_DMV_QPEL_PENALTY(i) (0x200 + ((i) * 0x4))
-#define VEPU_REG_DMV_QPEL_PENALTY_BIT(x, i) ((x) << (i) * 8)
-#define VEPU_REG_VP8_CTRL1 0x280
-#define VEPU_REG_VP8_BIT_COST_GOLDEN 0x284
-#define VEPU_REG_VP8_LOOP_FLT_DELTA(i) (0x288 + ((i) * 0x4))
-
-/* Decoder registers. */
-#define VDPU_REG_INTERRUPT 0x004
-#define VDPU_REG_INTERRUPT_DEC_PIC_INF BIT(24)
-#define VDPU_REG_INTERRUPT_DEC_TIMEOUT BIT(18)
-#define VDPU_REG_INTERRUPT_DEC_SLICE_INT BIT(17)
-#define VDPU_REG_INTERRUPT_DEC_ERROR_INT BIT(16)
-#define VDPU_REG_INTERRUPT_DEC_ASO_INT BIT(15)
-#define VDPU_REG_INTERRUPT_DEC_BUFFER_INT BIT(14)
-#define VDPU_REG_INTERRUPT_DEC_BUS_INT BIT(13)
-#define VDPU_REG_INTERRUPT_DEC_RDY_INT BIT(12)
-#define VDPU_REG_INTERRUPT_DEC_IRQ BIT(8)
-#define VDPU_REG_INTERRUPT_DEC_IRQ_DIS BIT(4)
-#define VDPU_REG_INTERRUPT_DEC_E BIT(0)
-#define VDPU_REG_CONFIG 0x008
-#define VDPU_REG_CONFIG_DEC_AXI_RD_ID(x) (((x) & 0xff) << 24)
-#define VDPU_REG_CONFIG_DEC_TIMEOUT_E BIT(23)
-#define VDPU_REG_CONFIG_DEC_STRSWAP32_E BIT(22)
-#define VDPU_REG_CONFIG_DEC_STRENDIAN_E BIT(21)
-#define VDPU_REG_CONFIG_DEC_INSWAP32_E BIT(20)
-#define VDPU_REG_CONFIG_DEC_OUTSWAP32_E BIT(19)
-#define VDPU_REG_CONFIG_DEC_DATA_DISC_E BIT(18)
-#define VDPU_REG_CONFIG_TILED_MODE_MSB BIT(17)
-#define VDPU_REG_CONFIG_DEC_OUT_TILED_E BIT(17)
-#define VDPU_REG_CONFIG_DEC_LATENCY(x) (((x) & 0x3f) << 11)
-#define VDPU_REG_CONFIG_DEC_CLK_GATE_E BIT(10)
-#define VDPU_REG_CONFIG_DEC_IN_ENDIAN BIT(9)
-#define VDPU_REG_CONFIG_DEC_OUT_ENDIAN BIT(8)
-#define VDPU_REG_CONFIG_PRIORITY_MODE(x) (((x) & 0x7) << 5)
-#define VDPU_REG_CONFIG_TILED_MODE_LSB BIT(7)
-#define VDPU_REG_CONFIG_DEC_ADV_PRE_DIS BIT(6)
-#define VDPU_REG_CONFIG_DEC_SCMD_DIS BIT(5)
-#define VDPU_REG_CONFIG_DEC_MAX_BURST(x) (((x) & 0x1f) << 0)
-#define VDPU_REG_DEC_CTRL0 0x00c
-#define VDPU_REG_DEC_CTRL0_DEC_MODE(x) (((x) & 0xf) << 28)
-#define VDPU_REG_DEC_CTRL0_RLC_MODE_E BIT(27)
-#define VDPU_REG_DEC_CTRL0_SKIP_MODE BIT(26)
-#define VDPU_REG_DEC_CTRL0_DIVX3_E BIT(25)
-#define VDPU_REG_DEC_CTRL0_PJPEG_E BIT(24)
-#define VDPU_REG_DEC_CTRL0_PIC_INTERLACE_E BIT(23)
-#define VDPU_REG_DEC_CTRL0_PIC_FIELDMODE_E BIT(22)
-#define VDPU_REG_DEC_CTRL0_PIC_B_E BIT(21)
-#define VDPU_REG_DEC_CTRL0_PIC_INTER_E BIT(20)
-#define VDPU_REG_DEC_CTRL0_PIC_TOPFIELD_E BIT(19)
-#define VDPU_REG_DEC_CTRL0_FWD_INTERLACE_E BIT(18)
-#define VDPU_REG_DEC_CTRL0_SORENSON_E BIT(17)
-#define VDPU_REG_DEC_CTRL0_REF_TOPFIELD_E BIT(16)
-#define VDPU_REG_DEC_CTRL0_DEC_OUT_DIS BIT(15)
-#define VDPU_REG_DEC_CTRL0_FILTERING_DIS BIT(14)
-#define VDPU_REG_DEC_CTRL0_WEBP_E BIT(13)
-#define VDPU_REG_DEC_CTRL0_MVC_E BIT(13)
-#define VDPU_REG_DEC_CTRL0_PIC_FIXED_QUANT BIT(13)
-#define VDPU_REG_DEC_CTRL0_WRITE_MVS_E BIT(12)
-#define VDPU_REG_DEC_CTRL0_REFTOPFIRST_E BIT(11)
-#define VDPU_REG_DEC_CTRL0_SEQ_MBAFF_E BIT(10)
-#define VDPU_REG_DEC_CTRL0_PICORD_COUNT_E BIT(9)
-#define VDPU_REG_DEC_CTRL0_DEC_AHB_HLOCK_E BIT(8)
-#define VDPU_REG_DEC_CTRL0_DEC_AXI_WR_ID(x) (((x) & 0xff) << 0)
-#define VDPU_REG_DEC_CTRL1 0x010
-#define VDPU_REG_DEC_CTRL1_PIC_MB_WIDTH(x) (((x) & 0x1ff) << 23)
-#define VDPU_REG_DEC_CTRL1_MB_WIDTH_OFF(x) (((x) & 0xf) << 19)
-#define VDPU_REG_DEC_CTRL1_PIC_MB_HEIGHT_P(x) (((x) & 0xff) << 11)
-#define VDPU_REG_DEC_CTRL1_MB_HEIGHT_OFF(x) (((x) & 0xf) << 7)
-#define VDPU_REG_DEC_CTRL1_ALT_SCAN_E BIT(6)
-#define VDPU_REG_DEC_CTRL1_TOPFIELDFIRST_E BIT(5)
-#define VDPU_REG_DEC_CTRL1_REF_FRAMES(x) (((x) & 0x1f) << 0)
-#define VDPU_REG_DEC_CTRL1_PIC_MB_W_EXT(x) (((x) & 0x7) << 3)
-#define VDPU_REG_DEC_CTRL1_PIC_MB_H_EXT(x) (((x) & 0x7) << 0)
-#define VDPU_REG_DEC_CTRL1_PIC_REFER_FLAG BIT(0)
-#define VDPU_REG_DEC_CTRL2 0x014
-#define VDPU_REG_DEC_CTRL2_STRM_START_BIT(x) (((x) & 0x3f) << 26)
-#define VDPU_REG_DEC_CTRL2_SYNC_MARKER_E BIT(25)
-#define VDPU_REG_DEC_CTRL2_TYPE1_QUANT_E BIT(24)
-#define VDPU_REG_DEC_CTRL2_CH_QP_OFFSET(x) (((x) & 0x1f) << 19)
-#define VDPU_REG_DEC_CTRL2_CH_QP_OFFSET2(x) (((x) & 0x1f) << 14)
-#define VDPU_REG_DEC_CTRL2_FIELDPIC_FLAG_E BIT(0)
-#define VDPU_REG_DEC_CTRL2_INTRADC_VLC_THR(x) (((x) & 0x7) << 16)
-#define VDPU_REG_DEC_CTRL2_VOP_TIME_INCR(x) (((x) & 0xffff) << 0)
-#define VDPU_REG_DEC_CTRL2_DQ_PROFILE BIT(24)
-#define VDPU_REG_DEC_CTRL2_DQBI_LEVEL BIT(23)
-#define VDPU_REG_DEC_CTRL2_RANGE_RED_FRM_E BIT(22)
-#define VDPU_REG_DEC_CTRL2_FAST_UVMC_E BIT(20)
-#define VDPU_REG_DEC_CTRL2_TRANSDCTAB BIT(17)
-#define VDPU_REG_DEC_CTRL2_TRANSACFRM(x) (((x) & 0x3) << 15)
-#define VDPU_REG_DEC_CTRL2_TRANSACFRM2(x) (((x) & 0x3) << 13)
-#define VDPU_REG_DEC_CTRL2_MB_MODE_TAB(x) (((x) & 0x7) << 10)
-#define VDPU_REG_DEC_CTRL2_MVTAB(x) (((x) & 0x7) << 7)
-#define VDPU_REG_DEC_CTRL2_CBPTAB(x) (((x) & 0x7) << 4)
-#define VDPU_REG_DEC_CTRL2_2MV_BLK_PAT_TAB(x) (((x) & 0x3) << 2)
-#define VDPU_REG_DEC_CTRL2_4MV_BLK_PAT_TAB(x) (((x) & 0x3) << 0)
-#define VDPU_REG_DEC_CTRL2_QSCALE_TYPE BIT(24)
-#define VDPU_REG_DEC_CTRL2_CON_MV_E BIT(4)
-#define VDPU_REG_DEC_CTRL2_INTRA_DC_PREC(x) (((x) & 0x3) << 2)
-#define VDPU_REG_DEC_CTRL2_INTRA_VLC_TAB BIT(1)
-#define VDPU_REG_DEC_CTRL2_FRAME_PRED_DCT BIT(0)
-#define VDPU_REG_DEC_CTRL2_JPEG_QTABLES(x) (((x) & 0x3) << 11)
-#define VDPU_REG_DEC_CTRL2_JPEG_MODE(x) (((x) & 0x7) << 8)
-#define VDPU_REG_DEC_CTRL2_JPEG_FILRIGHT_E BIT(7)
-#define VDPU_REG_DEC_CTRL2_JPEG_STREAM_ALL BIT(6)
-#define VDPU_REG_DEC_CTRL2_CR_AC_VLCTABLE BIT(5)
-#define VDPU_REG_DEC_CTRL2_CB_AC_VLCTABLE BIT(4)
-#define VDPU_REG_DEC_CTRL2_CR_DC_VLCTABLE BIT(3)
-#define VDPU_REG_DEC_CTRL2_CB_DC_VLCTABLE BIT(2)
-#define VDPU_REG_DEC_CTRL2_CR_DC_VLCTABLE3 BIT(1)
-#define VDPU_REG_DEC_CTRL2_CB_DC_VLCTABLE3 BIT(0)
-#define VDPU_REG_DEC_CTRL2_STRM1_START_BIT(x) (((x) & 0x3f) << 18)
-#define VDPU_REG_DEC_CTRL2_HUFFMAN_E BIT(17)
-#define VDPU_REG_DEC_CTRL2_MULTISTREAM_E BIT(16)
-#define VDPU_REG_DEC_CTRL2_BOOLEAN_VALUE(x) (((x) & 0xff) << 8)
-#define VDPU_REG_DEC_CTRL2_BOOLEAN_RANGE(x) (((x) & 0xff) << 0)
-#define VDPU_REG_DEC_CTRL2_ALPHA_OFFSET(x) (((x) & 0x1f) << 5)
-#define VDPU_REG_DEC_CTRL2_BETA_OFFSET(x) (((x) & 0x1f) << 0)
-#define VDPU_REG_DEC_CTRL3 0x018
-#define VDPU_REG_DEC_CTRL3_START_CODE_E BIT(31)
-#define VDPU_REG_DEC_CTRL3_INIT_QP(x) (((x) & 0x3f) << 25)
-#define VDPU_REG_DEC_CTRL3_CH_8PIX_ILEAV_E BIT(24)
-#define VDPU_REG_DEC_CTRL3_STREAM_LEN_EXT(x) (((x) & 0xff) << 24)
-#define VDPU_REG_DEC_CTRL3_STREAM_LEN(x) (((x) & 0xffffff) << 0)
-#define VDPU_REG_DEC_CTRL4 0x01c
-#define VDPU_REG_DEC_CTRL4_CABAC_E BIT(31)
-#define VDPU_REG_DEC_CTRL4_BLACKWHITE_E BIT(30)
-#define VDPU_REG_DEC_CTRL4_DIR_8X8_INFER_E BIT(29)
-#define VDPU_REG_DEC_CTRL4_WEIGHT_PRED_E BIT(28)
-#define VDPU_REG_DEC_CTRL4_WEIGHT_BIPR_IDC(x) (((x) & 0x3) << 26)
-#define VDPU_REG_DEC_CTRL4_AVS_H264_H_EXT BIT(25)
-#define VDPU_REG_DEC_CTRL4_FRAMENUM_LEN(x) (((x) & 0x1f) << 16)
-#define VDPU_REG_DEC_CTRL4_FRAMENUM(x) (((x) & 0xffff) << 0)
-#define VDPU_REG_DEC_CTRL4_BITPLANE0_E BIT(31)
-#define VDPU_REG_DEC_CTRL4_BITPLANE1_E BIT(30)
-#define VDPU_REG_DEC_CTRL4_BITPLANE2_E BIT(29)
-#define VDPU_REG_DEC_CTRL4_ALT_PQUANT(x) (((x) & 0x1f) << 24)
-#define VDPU_REG_DEC_CTRL4_DQ_EDGES(x) (((x) & 0xf) << 20)
-#define VDPU_REG_DEC_CTRL4_TTMBF BIT(19)
-#define VDPU_REG_DEC_CTRL4_PQINDEX(x) (((x) & 0x1f) << 14)
-#define VDPU_REG_DEC_CTRL4_VC1_HEIGHT_EXT BIT(13)
-#define VDPU_REG_DEC_CTRL4_BILIN_MC_E BIT(12)
-#define VDPU_REG_DEC_CTRL4_UNIQP_E BIT(11)
-#define VDPU_REG_DEC_CTRL4_HALFQP_E BIT(10)
-#define VDPU_REG_DEC_CTRL4_TTFRM(x) (((x) & 0x3) << 8)
-#define VDPU_REG_DEC_CTRL4_2ND_BYTE_EMUL_E BIT(7)
-#define VDPU_REG_DEC_CTRL4_DQUANT_E BIT(6)
-#define VDPU_REG_DEC_CTRL4_VC1_ADV_E BIT(5)
-#define VDPU_REG_DEC_CTRL4_PJPEG_FILDOWN_E BIT(26)
-#define VDPU_REG_DEC_CTRL4_PJPEG_WDIV8 BIT(25)
-#define VDPU_REG_DEC_CTRL4_PJPEG_HDIV8 BIT(24)
-#define VDPU_REG_DEC_CTRL4_PJPEG_AH(x) (((x) & 0xf) << 20)
-#define VDPU_REG_DEC_CTRL4_PJPEG_AL(x) (((x) & 0xf) << 16)
-#define VDPU_REG_DEC_CTRL4_PJPEG_SS(x) (((x) & 0xff) << 8)
-#define VDPU_REG_DEC_CTRL4_PJPEG_SE(x) (((x) & 0xff) << 0)
-#define VDPU_REG_DEC_CTRL4_DCT1_START_BIT(x) (((x) & 0x3f) << 26)
-#define VDPU_REG_DEC_CTRL4_DCT2_START_BIT(x) (((x) & 0x3f) << 20)
-#define VDPU_REG_DEC_CTRL4_CH_MV_RES BIT(13)
-#define VDPU_REG_DEC_CTRL4_INIT_DC_MATCH0(x) (((x) & 0x7) << 9)
-#define VDPU_REG_DEC_CTRL4_INIT_DC_MATCH1(x) (((x) & 0x7) << 6)
-#define VDPU_REG_DEC_CTRL4_VP7_VERSION BIT(5)
-#define VDPU_REG_DEC_CTRL5 0x020
-#define VDPU_REG_DEC_CTRL5_CONST_INTRA_E BIT(31)
-#define VDPU_REG_DEC_CTRL5_FILT_CTRL_PRES BIT(30)
-#define VDPU_REG_DEC_CTRL5_RDPIC_CNT_PRES BIT(29)
-#define VDPU_REG_DEC_CTRL5_8X8TRANS_FLAG_E BIT(28)
-#define VDPU_REG_DEC_CTRL5_REFPIC_MK_LEN(x) (((x) & 0x7ff) << 17)
-#define VDPU_REG_DEC_CTRL5_IDR_PIC_E BIT(16)
-#define VDPU_REG_DEC_CTRL5_IDR_PIC_ID(x) (((x) & 0xffff) << 0)
-#define VDPU_REG_DEC_CTRL5_MV_SCALEFACTOR(x) (((x) & 0xff) << 24)
-#define VDPU_REG_DEC_CTRL5_REF_DIST_FWD(x) (((x) & 0x1f) << 19)
-#define VDPU_REG_DEC_CTRL5_REF_DIST_BWD(x) (((x) & 0x1f) << 14)
-#define VDPU_REG_DEC_CTRL5_LOOP_FILT_LIMIT(x) (((x) & 0xf) << 14)
-#define VDPU_REG_DEC_CTRL5_VARIANCE_TEST_E BIT(13)
-#define VDPU_REG_DEC_CTRL5_MV_THRESHOLD(x) (((x) & 0x7) << 10)
-#define VDPU_REG_DEC_CTRL5_VAR_THRESHOLD(x) (((x) & 0x3ff) << 0)
-#define VDPU_REG_DEC_CTRL5_DIVX_IDCT_E BIT(8)
-#define VDPU_REG_DEC_CTRL5_DIVX3_SLICE_SIZE(x) (((x) & 0xff) << 0)
-#define VDPU_REG_DEC_CTRL5_PJPEG_REST_FREQ(x) (((x) & 0xffff) << 0)
-#define VDPU_REG_DEC_CTRL5_RV_PROFILE(x) (((x) & 0x3) << 30)
-#define VDPU_REG_DEC_CTRL5_RV_OSV_QUANT(x) (((x) & 0x3) << 28)
-#define VDPU_REG_DEC_CTRL5_RV_FWD_SCALE(x) (((x) & 0x3fff) << 14)
-#define VDPU_REG_DEC_CTRL5_RV_BWD_SCALE(x) (((x) & 0x3fff) << 0)
-#define VDPU_REG_DEC_CTRL5_INIT_DC_COMP0(x) (((x) & 0xffff) << 16)
-#define VDPU_REG_DEC_CTRL5_INIT_DC_COMP1(x) (((x) & 0xffff) << 0)
-#define VDPU_REG_DEC_CTRL6 0x024
-#define VDPU_REG_DEC_CTRL6_PPS_ID(x) (((x) & 0xff) << 24)
-#define VDPU_REG_DEC_CTRL6_REFIDX1_ACTIVE(x) (((x) & 0x1f) << 19)
-#define VDPU_REG_DEC_CTRL6_REFIDX0_ACTIVE(x) (((x) & 0x1f) << 14)
-#define VDPU_REG_DEC_CTRL6_POC_LENGTH(x) (((x) & 0xff) << 0)
-#define VDPU_REG_DEC_CTRL6_ICOMP0_E BIT(24)
-#define VDPU_REG_DEC_CTRL6_ISCALE0(x) (((x) & 0xff) << 16)
-#define VDPU_REG_DEC_CTRL6_ISHIFT0(x) (((x) & 0xffff) << 0)
-#define VDPU_REG_DEC_CTRL6_STREAM1_LEN(x) (((x) & 0xffffff) << 0)
-#define VDPU_REG_DEC_CTRL6_PIC_SLICE_AM(x) (((x) & 0x1fff) << 0)
-#define VDPU_REG_DEC_CTRL6_COEFFS_PART_AM(x) (((x) & 0xf) << 24)
-#define VDPU_REG_FWD_PIC(i) (0x028 + ((i) * 0x4))
-#define VDPU_REG_FWD_PIC_PINIT_RLIST_F5(x) (((x) & 0x1f) << 25)
-#define VDPU_REG_FWD_PIC_PINIT_RLIST_F4(x) (((x) & 0x1f) << 20)
-#define VDPU_REG_FWD_PIC_PINIT_RLIST_F3(x) (((x) & 0x1f) << 15)
-#define VDPU_REG_FWD_PIC_PINIT_RLIST_F2(x) (((x) & 0x1f) << 10)
-#define VDPU_REG_FWD_PIC_PINIT_RLIST_F1(x) (((x) & 0x1f) << 5)
-#define VDPU_REG_FWD_PIC_PINIT_RLIST_F0(x) (((x) & 0x1f) << 0)
-#define VDPU_REG_FWD_PIC1_ICOMP1_E BIT(24)
-#define VDPU_REG_FWD_PIC1_ISCALE1(x) (((x) & 0xff) << 16)
-#define VDPU_REG_FWD_PIC1_ISHIFT1(x) (((x) & 0xffff) << 0)
-#define VDPU_REG_FWD_PIC1_SEGMENT_BASE(x) ((x) << 0)
-#define VDPU_REG_FWD_PIC1_SEGMENT_UPD_E BIT(1)
-#define VDPU_REG_FWD_PIC1_SEGMENT_E BIT(0)
-#define VDPU_REG_DEC_CTRL7 0x02c
-#define VDPU_REG_DEC_CTRL7_PINIT_RLIST_F15(x) (((x) & 0x1f) << 25)
-#define VDPU_REG_DEC_CTRL7_PINIT_RLIST_F14(x) (((x) & 0x1f) << 20)
-#define VDPU_REG_DEC_CTRL7_PINIT_RLIST_F13(x) (((x) & 0x1f) << 15)
-#define VDPU_REG_DEC_CTRL7_PINIT_RLIST_F12(x) (((x) & 0x1f) << 10)
-#define VDPU_REG_DEC_CTRL7_PINIT_RLIST_F11(x) (((x) & 0x1f) << 5)
-#define VDPU_REG_DEC_CTRL7_PINIT_RLIST_F10(x) (((x) & 0x1f) << 0)
-#define VDPU_REG_DEC_CTRL7_ICOMP2_E BIT(24)
-#define VDPU_REG_DEC_CTRL7_ISCALE2(x) (((x) & 0xff) << 16)
-#define VDPU_REG_DEC_CTRL7_ISHIFT2(x) (((x) & 0xffff) << 0)
-#define VDPU_REG_DEC_CTRL7_DCT3_START_BIT(x) (((x) & 0x3f) << 24)
-#define VDPU_REG_DEC_CTRL7_DCT4_START_BIT(x) (((x) & 0x3f) << 18)
-#define VDPU_REG_DEC_CTRL7_DCT5_START_BIT(x) (((x) & 0x3f) << 12)
-#define VDPU_REG_DEC_CTRL7_DCT6_START_BIT(x) (((x) & 0x3f) << 6)
-#define VDPU_REG_DEC_CTRL7_DCT7_START_BIT(x) (((x) & 0x3f) << 0)
-#define VDPU_REG_ADDR_STR 0x030
-#define VDPU_REG_ADDR_DST 0x034
-#define VDPU_REG_ADDR_REF(i) (0x038 + ((i) * 0x4))
-#define VDPU_REG_ADDR_REF_FIELD_E BIT(1)
-#define VDPU_REG_ADDR_REF_TOPC_E BIT(0)
-#define VDPU_REG_REF_PIC(i) (0x078 + ((i) * 0x4))
-#define VDPU_REG_REF_PIC_FILT_TYPE_E BIT(31)
-#define VDPU_REG_REF_PIC_FILT_SHARPNESS(x) (((x) & 0x7) << 28)
-#define VDPU_REG_REF_PIC_MB_ADJ_0(x) (((x) & 0x7f) << 21)
-#define VDPU_REG_REF_PIC_MB_ADJ_1(x) (((x) & 0x7f) << 14)
-#define VDPU_REG_REF_PIC_MB_ADJ_2(x) (((x) & 0x7f) << 7)
-#define VDPU_REG_REF_PIC_MB_ADJ_3(x) (((x) & 0x7f) << 0)
-#define VDPU_REG_REF_PIC_REFER1_NBR(x) (((x) & 0xffff) << 16)
-#define VDPU_REG_REF_PIC_REFER0_NBR(x) (((x) & 0xffff) << 0)
-#define VDPU_REG_REF_PIC_LF_LEVEL_0(x) (((x) & 0x3f) << 18)
-#define VDPU_REG_REF_PIC_LF_LEVEL_1(x) (((x) & 0x3f) << 12)
-#define VDPU_REG_REF_PIC_LF_LEVEL_2(x) (((x) & 0x3f) << 6)
-#define VDPU_REG_REF_PIC_LF_LEVEL_3(x) (((x) & 0x3f) << 0)
-#define VDPU_REG_REF_PIC_QUANT_DELTA_0(x) (((x) & 0x1f) << 27)
-#define VDPU_REG_REF_PIC_QUANT_DELTA_1(x) (((x) & 0x1f) << 22)
-#define VDPU_REG_REF_PIC_QUANT_0(x) (((x) & 0x7ff) << 11)
-#define VDPU_REG_REF_PIC_QUANT_1(x) (((x) & 0x7ff) << 0)
-#define VDPU_REG_LT_REF 0x098
-#define VDPU_REG_VALID_REF 0x09c
-#define VDPU_REG_ADDR_QTABLE 0x0a0
-#define VDPU_REG_ADDR_DIR_MV 0x0a4
-#define VDPU_REG_BD_REF_PIC(i) (0x0a8 + ((i) * 0x4))
-#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B2(x) (((x) & 0x1f) << 25)
-#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F2(x) (((x) & 0x1f) << 20)
-#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B1(x) (((x) & 0x1f) << 15)
-#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F1(x) (((x) & 0x1f) << 10)
-#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B0(x) (((x) & 0x1f) << 5)
-#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F0(x) (((x) & 0x1f) << 0)
-#define VDPU_REG_BD_REF_PIC_PRED_TAP_2_M1(x) (((x) & 0x3) << 10)
-#define VDPU_REG_BD_REF_PIC_PRED_TAP_2_4(x) (((x) & 0x3) << 8)
-#define VDPU_REG_BD_REF_PIC_PRED_TAP_4_M1(x) (((x) & 0x3) << 6)
-#define VDPU_REG_BD_REF_PIC_PRED_TAP_4_4(x) (((x) & 0x3) << 4)
-#define VDPU_REG_BD_REF_PIC_PRED_TAP_6_M1(x) (((x) & 0x3) << 2)
-#define VDPU_REG_BD_REF_PIC_PRED_TAP_6_4(x) (((x) & 0x3) << 0)
-#define VDPU_REG_BD_REF_PIC_QUANT_DELTA_2(x) (((x) & 0x1f) << 27)
-#define VDPU_REG_BD_REF_PIC_QUANT_DELTA_3(x) (((x) & 0x1f) << 22)
-#define VDPU_REG_BD_REF_PIC_QUANT_2(x) (((x) & 0x7ff) << 11)
-#define VDPU_REG_BD_REF_PIC_QUANT_3(x) (((x) & 0x7ff) << 0)
-#define VDPU_REG_BD_P_REF_PIC 0x0bc
-#define VDPU_REG_BD_P_REF_PIC_QUANT_DELTA_4(x) (((x) & 0x1f) << 27)
-#define VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F3(x) (((x) & 0x1f) << 25)
-#define VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F2(x) (((x) & 0x1f) << 20)
-#define VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F1(x) (((x) & 0x1f) << 15)
-#define VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F0(x) (((x) & 0x1f) << 10)
-#define VDPU_REG_BD_P_REF_PIC_BINIT_RLIST_B15(x) (((x) & 0x1f) << 5)
-#define VDPU_REG_BD_P_REF_PIC_BINIT_RLIST_F15(x) (((x) & 0x1f) << 0)
-#define VDPU_REG_ERR_CONC 0x0c0
-#define VDPU_REG_ERR_CONC_STARTMB_X(x) (((x) & 0x1ff) << 23)
-#define VDPU_REG_ERR_CONC_STARTMB_Y(x) (((x) & 0xff) << 15)
-#define VDPU_REG_PRED_FLT 0x0c4
-#define VDPU_REG_PRED_FLT_PRED_BC_TAP_0_0(x) (((x) & 0x3ff) << 22)
-#define VDPU_REG_PRED_FLT_PRED_BC_TAP_0_1(x) (((x) & 0x3ff) << 12)
-#define VDPU_REG_PRED_FLT_PRED_BC_TAP_0_2(x) (((x) & 0x3ff) << 2)
-#define VDPU_REG_REF_BUF_CTRL 0x0cc
-#define VDPU_REG_REF_BUF_CTRL_REFBU_E BIT(31)
-#define VDPU_REG_REF_BUF_CTRL_REFBU_THR(x) (((x) & 0xfff) << 19)
-#define VDPU_REG_REF_BUF_CTRL_REFBU_PICID(x) (((x) & 0x1f) << 14)
-#define VDPU_REG_REF_BUF_CTRL_REFBU_EVAL_E BIT(13)
-#define VDPU_REG_REF_BUF_CTRL_REFBU_FPARMOD_E BIT(12)
-#define VDPU_REG_REF_BUF_CTRL_REFBU_Y_OFFSET(x) (((x) & 0x1ff) << 0)
-#define VDPU_REG_REF_BUF_CTRL2 0x0dc
-#define VDPU_REG_REF_BUF_CTRL2_REFBU2_BUF_E BIT(31)
-#define VDPU_REG_REF_BUF_CTRL2_REFBU2_THR(x) (((x) & 0xfff) << 19)
-#define VDPU_REG_REF_BUF_CTRL2_REFBU2_PICID(x) (((x) & 0x1f) << 14)
-#define VDPU_REG_REF_BUF_CTRL2_APF_THRESHOLD(x) (((x) & 0x3fff) << 0)
-
-#endif /* RK3288_VPU_REGS_H_ */
diff --git a/drivers/staging/media/rockchip/vpu/rk3399_vpu_hw.c b/drivers/staging/media/rockchip/vpu/rk3399_vpu_hw.c
deleted file mode 100644
index 6fdef61e2127..000000000000
--- a/drivers/staging/media/rockchip/vpu/rk3399_vpu_hw.c
+++ /dev/null
@@ -1,118 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Rockchip VPU codec driver
- *
- * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
- * Jeffy Chen <jeffy.chen@rock-chips.com>
- */
-
-#include <linux/clk.h>
-
-#include "rockchip_vpu.h"
-#include "rockchip_vpu_jpeg.h"
-#include "rk3399_vpu_regs.h"
-
-#define RK3399_ACLK_MAX_FREQ (400 * 1000 * 1000)
-
-/*
- * Supported formats.
- */
-
-static const struct rockchip_vpu_fmt rk3399_vpu_enc_fmts[] = {
- {
- .fourcc = V4L2_PIX_FMT_YUV420M,
- .codec_mode = RK_VPU_MODE_NONE,
- .enc_fmt = RK3288_VPU_ENC_FMT_YUV420P,
- },
- {
- .fourcc = V4L2_PIX_FMT_NV12M,
- .codec_mode = RK_VPU_MODE_NONE,
- .enc_fmt = RK3288_VPU_ENC_FMT_YUV420SP,
- },
- {
- .fourcc = V4L2_PIX_FMT_YUYV,
- .codec_mode = RK_VPU_MODE_NONE,
- .enc_fmt = RK3288_VPU_ENC_FMT_YUYV422,
- },
- {
- .fourcc = V4L2_PIX_FMT_UYVY,
- .codec_mode = RK_VPU_MODE_NONE,
- .enc_fmt = RK3288_VPU_ENC_FMT_UYVY422,
- },
- {
- .fourcc = V4L2_PIX_FMT_JPEG,
- .codec_mode = RK_VPU_MODE_JPEG_ENC,
- .max_depth = 2,
- .header_size = JPEG_HEADER_SIZE,
- .frmsize = {
- .min_width = 96,
- .max_width = 8192,
- .step_width = JPEG_MB_DIM,
- .min_height = 32,
- .max_height = 8192,
- .step_height = JPEG_MB_DIM,
- },
- },
-};
-
-static irqreturn_t rk3399_vepu_irq(int irq, void *dev_id)
-{
- struct rockchip_vpu_dev *vpu = dev_id;
- enum vb2_buffer_state state;
- u32 status, bytesused;
-
- status = vepu_read(vpu, VEPU_REG_INTERRUPT);
- bytesused = vepu_read(vpu, VEPU_REG_STR_BUF_LIMIT) / 8;
- state = (status & VEPU_REG_INTERRUPT_FRAME_READY) ?
- VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR;
-
- vepu_write(vpu, 0, VEPU_REG_INTERRUPT);
- vepu_write(vpu, 0, VEPU_REG_AXI_CTRL);
-
- rockchip_vpu_irq_done(vpu, bytesused, state);
-
- return IRQ_HANDLED;
-}
-
-static int rk3399_vpu_hw_init(struct rockchip_vpu_dev *vpu)
-{
- /* Bump ACLK to max. possible freq. to improve performance. */
- clk_set_rate(vpu->clocks[0].clk, RK3399_ACLK_MAX_FREQ);
- return 0;
-}
-
-static void rk3399_vpu_enc_reset(struct rockchip_vpu_ctx *ctx)
-{
- struct rockchip_vpu_dev *vpu = ctx->dev;
-
- vepu_write(vpu, VEPU_REG_INTERRUPT_DIS_BIT, VEPU_REG_INTERRUPT);
- vepu_write(vpu, 0, VEPU_REG_ENCODE_START);
- vepu_write(vpu, 0, VEPU_REG_AXI_CTRL);
-}
-
-/*
- * Supported codec ops.
- */
-
-static const struct rockchip_vpu_codec_ops rk3399_vpu_codec_ops[] = {
- [RK_VPU_MODE_JPEG_ENC] = {
- .run = rk3399_vpu_jpeg_enc_run,
- .reset = rk3399_vpu_enc_reset,
- },
-};
-
-/*
- * VPU variant.
- */
-
-const struct rockchip_vpu_variant rk3399_vpu_variant = {
- .enc_offset = 0x0,
- .enc_fmts = rk3399_vpu_enc_fmts,
- .num_enc_fmts = ARRAY_SIZE(rk3399_vpu_enc_fmts),
- .codec = RK_VPU_CODEC_JPEG,
- .codec_ops = rk3399_vpu_codec_ops,
- .vepu_irq = rk3399_vepu_irq,
- .init = rk3399_vpu_hw_init,
- .clk_names = {"aclk", "hclk"},
- .num_clocks = 2
-};
diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu.h b/drivers/staging/media/rockchip/vpu/rockchip_vpu.h
deleted file mode 100644
index 1ec2be483e27..000000000000
--- a/drivers/staging/media/rockchip/vpu/rockchip_vpu.h
+++ /dev/null
@@ -1,232 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Rockchip VPU codec driver
- *
- * Copyright 2018 Google LLC.
- * Tomasz Figa <tfiga@chromium.org>
- *
- * Based on s5p-mfc driver by Samsung Electronics Co., Ltd.
- * Copyright (C) 2011 Samsung Electronics Co., Ltd.
- */
-
-#ifndef ROCKCHIP_VPU_H_
-#define ROCKCHIP_VPU_H_
-
-#include <linux/platform_device.h>
-#include <linux/videodev2.h>
-#include <linux/wait.h>
-#include <linux/clk.h>
-
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ioctl.h>
-#include <media/videobuf2-core.h>
-#include <media/videobuf2-dma-contig.h>
-
-#include "rockchip_vpu_hw.h"
-
-#define ROCKCHIP_VPU_MAX_CLOCKS 4
-
-#define JPEG_MB_DIM 16
-#define JPEG_MB_WIDTH(w) DIV_ROUND_UP(w, JPEG_MB_DIM)
-#define JPEG_MB_HEIGHT(h) DIV_ROUND_UP(h, JPEG_MB_DIM)
-
-struct rockchip_vpu_ctx;
-struct rockchip_vpu_codec_ops;
-
-#define RK_VPU_CODEC_JPEG BIT(0)
-
-/**
- * struct rockchip_vpu_variant - information about VPU hardware variant
- *
- * @enc_offset: Offset from VPU base to encoder registers.
- * @enc_fmts: Encoder formats.
- * @num_enc_fmts: Number of encoder formats.
- * @codec: Supported codecs
- * @codec_ops: Codec ops.
- * @init: Initialize hardware.
- * @vepu_irq: encoder interrupt handler
- * @clk_names: array of clock names
- * @num_clocks: number of clocks in the array
- */
-struct rockchip_vpu_variant {
- unsigned int enc_offset;
- const struct rockchip_vpu_fmt *enc_fmts;
- unsigned int num_enc_fmts;
- unsigned int codec;
- const struct rockchip_vpu_codec_ops *codec_ops;
- int (*init)(struct rockchip_vpu_dev *vpu);
- irqreturn_t (*vepu_irq)(int irq, void *priv);
- const char *clk_names[ROCKCHIP_VPU_MAX_CLOCKS];
- int num_clocks;
-};
-
-/**
- * enum rockchip_vpu_codec_mode - codec operating mode.
- * @RK_VPU_MODE_NONE: No operating mode. Used for RAW video formats.
- * @RK_VPU_MODE_JPEG_ENC: JPEG encoder.
- */
-enum rockchip_vpu_codec_mode {
- RK_VPU_MODE_NONE = -1,
- RK_VPU_MODE_JPEG_ENC,
-};
-
-/**
- * struct rockchip_vpu_dev - driver data
- * @v4l2_dev: V4L2 device to register video devices for.
- * @m2m_dev: mem2mem device associated to this device.
- * @mdev: media device associated to this device.
- * @vfd_enc: Video device for encoder.
- * @pdev: Pointer to VPU platform device.
- * @dev: Pointer to device for convenient logging using
- * dev_ macros.
- * @clocks: Array of clock handles.
- * @base: Mapped address of VPU registers.
- * @enc_base: Mapped address of VPU encoder register for convenience.
- * @vpu_mutex: Mutex to synchronize V4L2 calls.
- * @irqlock: Spinlock to synchronize access to data structures
- * shared with interrupt handlers.
- * @variant: Hardware variant-specific parameters.
- * @watchdog_work: Delayed work for hardware timeout handling.
- */
-struct rockchip_vpu_dev {
- struct v4l2_device v4l2_dev;
- struct v4l2_m2m_dev *m2m_dev;
- struct media_device mdev;
- struct video_device *vfd_enc;
- struct platform_device *pdev;
- struct device *dev;
- struct clk_bulk_data clocks[ROCKCHIP_VPU_MAX_CLOCKS];
- void __iomem *base;
- void __iomem *enc_base;
-
- struct mutex vpu_mutex; /* video_device lock */
- spinlock_t irqlock;
- const struct rockchip_vpu_variant *variant;
- struct delayed_work watchdog_work;
-};
-
-/**
- * struct rockchip_vpu_ctx - Context (instance) private data.
- *
- * @dev: VPU driver data to which the context belongs.
- * @fh: V4L2 file handler.
- *
- * @sequence_cap: Sequence counter for capture queue
- * @sequence_out: Sequence counter for output queue
- *
- * @vpu_src_fmt: Descriptor of active source format.
- * @src_fmt: V4L2 pixel format of active source format.
- * @vpu_dst_fmt: Descriptor of active destination format.
- * @dst_fmt: V4L2 pixel format of active destination format.
- *
- * @ctrl_handler: Control handler used to register controls.
- * @jpeg_quality: User-specified JPEG compression quality.
- *
- * @codec_ops: Set of operations related to codec mode.
- *
- * @bounce_dma_addr: Bounce buffer bus address.
- * @bounce_buf: Bounce buffer pointer.
- * @bounce_size: Bounce buffer size.
- */
-struct rockchip_vpu_ctx {
- struct rockchip_vpu_dev *dev;
- struct v4l2_fh fh;
-
- u32 sequence_cap;
- u32 sequence_out;
-
- const struct rockchip_vpu_fmt *vpu_src_fmt;
- struct v4l2_pix_format_mplane src_fmt;
- const struct rockchip_vpu_fmt *vpu_dst_fmt;
- struct v4l2_pix_format_mplane dst_fmt;
-
- struct v4l2_ctrl_handler ctrl_handler;
- int jpeg_quality;
-
- const struct rockchip_vpu_codec_ops *codec_ops;
-
- dma_addr_t bounce_dma_addr;
- void *bounce_buf;
- size_t bounce_size;
-};
-
-/**
- * struct rockchip_vpu_fmt - information about supported video formats.
- * @name: Human readable name of the format.
- * @fourcc: FourCC code of the format. See V4L2_PIX_FMT_*.
- * @codec_mode: Codec mode related to this format. See
- * enum rockchip_vpu_codec_mode.
- * @header_size: Optional header size. Currently used by JPEG encoder.
- * @max_depth: Maximum depth, for bitstream formats
- * @enc_fmt: Format identifier for encoder registers.
- * @frmsize: Supported range of frame sizes (only for bitstream formats).
- */
-struct rockchip_vpu_fmt {
- char *name;
- u32 fourcc;
- enum rockchip_vpu_codec_mode codec_mode;
- int header_size;
- int max_depth;
- enum rockchip_vpu_enc_fmt enc_fmt;
- struct v4l2_frmsize_stepwise frmsize;
-};
-
-/* Logging helpers */
-
-/**
- * debug - Module parameter to control level of debugging messages.
- *
- * Level of debugging messages can be controlled by bits of
- * module parameter called "debug". Meaning of particular
- * bits is as follows:
- *
- * bit 0 - global information: mode, size, init, release
- * bit 1 - each run start/result information
- * bit 2 - contents of small controls from userspace
- * bit 3 - contents of big controls from userspace
- * bit 4 - detail fmt, ctrl, buffer q/dq information
- * bit 5 - detail function enter/leave trace information
- * bit 6 - register write/read information
- */
-extern int rockchip_vpu_debug;
-
-#define vpu_debug(level, fmt, args...) \
- do { \
- if (rockchip_vpu_debug & BIT(level)) \
- pr_info("%s:%d: " fmt, \
- __func__, __LINE__, ##args); \
- } while (0)
-
-#define vpu_err(fmt, args...) \
- pr_err("%s:%d: " fmt, __func__, __LINE__, ##args)
-
-/* Structure access helpers. */
-static inline struct rockchip_vpu_ctx *fh_to_ctx(struct v4l2_fh *fh)
-{
- return container_of(fh, struct rockchip_vpu_ctx, fh);
-}
-
-/* Register accessors. */
-static inline void vepu_write_relaxed(struct rockchip_vpu_dev *vpu,
- u32 val, u32 reg)
-{
- vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val);
- writel_relaxed(val, vpu->enc_base + reg);
-}
-
-static inline void vepu_write(struct rockchip_vpu_dev *vpu, u32 val, u32 reg)
-{
- vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val);
- writel(val, vpu->enc_base + reg);
-}
-
-static inline u32 vepu_read(struct rockchip_vpu_dev *vpu, u32 reg)
-{
- u32 val = readl(vpu->enc_base + reg);
-
- vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val);
- return val;
-}
-
-#endif /* ROCKCHIP_VPU_H_ */
diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu_common.h b/drivers/staging/media/rockchip/vpu/rockchip_vpu_common.h
deleted file mode 100644
index ca77668d9579..000000000000
--- a/drivers/staging/media/rockchip/vpu/rockchip_vpu_common.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Rockchip VPU codec driver
- *
- * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
- * Alpha Lin <Alpha.Lin@rock-chips.com>
- * Jeffy Chen <jeffy.chen@rock-chips.com>
- *
- * Copyright 2018 Google LLC.
- * Tomasz Figa <tfiga@chromium.org>
- *
- * Based on s5p-mfc driver by Samsung Electronics Co., Ltd.
- * Copyright (C) 2011 Samsung Electronics Co., Ltd.
- */
-
-#ifndef ROCKCHIP_VPU_COMMON_H_
-#define ROCKCHIP_VPU_COMMON_H_
-
-#include "rockchip_vpu.h"
-
-extern const struct v4l2_ioctl_ops rockchip_vpu_enc_ioctl_ops;
-extern const struct vb2_ops rockchip_vpu_enc_queue_ops;
-
-void rockchip_vpu_enc_reset_src_fmt(struct rockchip_vpu_dev *vpu,
- struct rockchip_vpu_ctx *ctx);
-void rockchip_vpu_enc_reset_dst_fmt(struct rockchip_vpu_dev *vpu,
- struct rockchip_vpu_ctx *ctx);
-
-#endif /* ROCKCHIP_VPU_COMMON_H_ */
diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu_drv.c b/drivers/staging/media/rockchip/vpu/rockchip_vpu_drv.c
deleted file mode 100644
index 8bbc905b26c8..000000000000
--- a/drivers/staging/media/rockchip/vpu/rockchip_vpu_drv.c
+++ /dev/null
@@ -1,542 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Rockchip VPU codec driver
- *
- * Copyright (C) 2018 Collabora, Ltd.
- * Copyright 2018 Google LLC.
- * Tomasz Figa <tfiga@chromium.org>
- *
- * Based on s5p-mfc driver by Samsung Electronics Co., Ltd.
- * Copyright (C) 2011 Samsung Electronics Co., Ltd.
- */
-
-#include <linux/clk.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/pm.h>
-#include <linux/pm_runtime.h>
-#include <linux/slab.h>
-#include <linux/videodev2.h>
-#include <linux/workqueue.h>
-#include <media/v4l2-event.h>
-#include <media/v4l2-mem2mem.h>
-#include <media/videobuf2-core.h>
-#include <media/videobuf2-vmalloc.h>
-
-#include "rockchip_vpu_common.h"
-#include "rockchip_vpu.h"
-#include "rockchip_vpu_hw.h"
-
-#define DRIVER_NAME "rockchip-vpu"
-
-int rockchip_vpu_debug;
-module_param_named(debug, rockchip_vpu_debug, int, 0644);
-MODULE_PARM_DESC(debug,
- "Debug level - higher value produces more verbose messages");
-
-static void rockchip_vpu_job_finish(struct rockchip_vpu_dev *vpu,
- struct rockchip_vpu_ctx *ctx,
- unsigned int bytesused,
- enum vb2_buffer_state result)
-{
- struct vb2_v4l2_buffer *src, *dst;
- size_t avail_size;
-
- pm_runtime_mark_last_busy(vpu->dev);
- pm_runtime_put_autosuspend(vpu->dev);
- clk_bulk_disable(vpu->variant->num_clocks, vpu->clocks);
-
- src = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
- dst = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
-
- if (WARN_ON(!src))
- return;
- if (WARN_ON(!dst))
- return;
-
- src->sequence = ctx->sequence_out++;
- dst->sequence = ctx->sequence_cap++;
-
- dst->field = src->field;
- if (src->flags & V4L2_BUF_FLAG_TIMECODE)
- dst->timecode = src->timecode;
- dst->vb2_buf.timestamp = src->vb2_buf.timestamp;
- dst->flags &= ~(V4L2_BUF_FLAG_TSTAMP_SRC_MASK |
- V4L2_BUF_FLAG_TIMECODE);
- dst->flags |= src->flags & (V4L2_BUF_FLAG_TSTAMP_SRC_MASK |
- V4L2_BUF_FLAG_TIMECODE);
-
- avail_size = vb2_plane_size(&dst->vb2_buf, 0) -
- ctx->vpu_dst_fmt->header_size;
- if (bytesused <= avail_size) {
- if (ctx->bounce_buf) {
- memcpy(vb2_plane_vaddr(&dst->vb2_buf, 0) +
- ctx->vpu_dst_fmt->header_size,
- ctx->bounce_buf, bytesused);
- }
- dst->vb2_buf.planes[0].bytesused =
- ctx->vpu_dst_fmt->header_size + bytesused;
- } else {
- result = VB2_BUF_STATE_ERROR;
- }
-
- v4l2_m2m_buf_done(src, result);
- v4l2_m2m_buf_done(dst, result);
-
- v4l2_m2m_job_finish(vpu->m2m_dev, ctx->fh.m2m_ctx);
-}
-
-void rockchip_vpu_irq_done(struct rockchip_vpu_dev *vpu,
- unsigned int bytesused,
- enum vb2_buffer_state result)
-{
- struct rockchip_vpu_ctx *ctx =
- v4l2_m2m_get_curr_priv(vpu->m2m_dev);
-
- /*
- * If cancel_delayed_work returns false
- * the timeout expired. The watchdog is running,
- * and will take care of finishing the job.
- */
- if (cancel_delayed_work(&vpu->watchdog_work))
- rockchip_vpu_job_finish(vpu, ctx, bytesused, result);
-}
-
-void rockchip_vpu_watchdog(struct work_struct *work)
-{
- struct rockchip_vpu_dev *vpu;
- struct rockchip_vpu_ctx *ctx;
-
- vpu = container_of(to_delayed_work(work),
- struct rockchip_vpu_dev, watchdog_work);
- ctx = v4l2_m2m_get_curr_priv(vpu->m2m_dev);
- if (ctx) {
- vpu_err("frame processing timed out!\n");
- ctx->codec_ops->reset(ctx);
- rockchip_vpu_job_finish(vpu, ctx, 0, VB2_BUF_STATE_ERROR);
- }
-}
-
-static void device_run(void *priv)
-{
- struct rockchip_vpu_ctx *ctx = priv;
- int ret;
-
- ret = clk_bulk_enable(ctx->dev->variant->num_clocks, ctx->dev->clocks);
- if (ret)
- goto err_cancel_job;
- ret = pm_runtime_get_sync(ctx->dev->dev);
- if (ret < 0)
- goto err_cancel_job;
-
- ctx->codec_ops->run(ctx);
- return;
-
-err_cancel_job:
- rockchip_vpu_job_finish(ctx->dev, ctx, 0, VB2_BUF_STATE_ERROR);
-}
-
-static struct v4l2_m2m_ops vpu_m2m_ops = {
- .device_run = device_run,
-};
-
-static int
-enc_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
-{
- struct rockchip_vpu_ctx *ctx = priv;
- int ret;
-
- src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
- src_vq->drv_priv = ctx;
- src_vq->ops = &rockchip_vpu_enc_queue_ops;
- src_vq->mem_ops = &vb2_dma_contig_memops;
-
- /*
- * Driver does mostly sequential access, so sacrifice TLB efficiency
- * for faster allocation. Also, no CPU access on the source queue,
- * so no kernel mapping needed.
- */
- src_vq->dma_attrs = DMA_ATTR_ALLOC_SINGLE_PAGES |
- DMA_ATTR_NO_KERNEL_MAPPING;
- src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
- src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
- src_vq->lock = &ctx->dev->vpu_mutex;
- src_vq->dev = ctx->dev->v4l2_dev.dev;
-
- ret = vb2_queue_init(src_vq);
- if (ret)
- return ret;
-
- /*
- * The CAPTURE queue doesn't need dma memory,
- * as the CPU needs to create the JPEG frames,
- * from the hardware-produced JPEG payload.
- *
- * For the DMA destination buffer, we use
- * a bounce buffer.
- */
- dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
- dst_vq->drv_priv = ctx;
- dst_vq->ops = &rockchip_vpu_enc_queue_ops;
- dst_vq->mem_ops = &vb2_vmalloc_memops;
- dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
- dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
- dst_vq->lock = &ctx->dev->vpu_mutex;
- dst_vq->dev = ctx->dev->v4l2_dev.dev;
-
- return vb2_queue_init(dst_vq);
-}
-
-static int rockchip_vpu_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct rockchip_vpu_ctx *ctx;
-
- ctx = container_of(ctrl->handler,
- struct rockchip_vpu_ctx, ctrl_handler);
-
- vpu_debug(1, "s_ctrl: id = %d, val = %d\n", ctrl->id, ctrl->val);
-
- switch (ctrl->id) {
- case V4L2_CID_JPEG_COMPRESSION_QUALITY:
- ctx->jpeg_quality = ctrl->val;
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static const struct v4l2_ctrl_ops rockchip_vpu_ctrl_ops = {
- .s_ctrl = rockchip_vpu_s_ctrl,
-};
-
-static int rockchip_vpu_ctrls_setup(struct rockchip_vpu_dev *vpu,
- struct rockchip_vpu_ctx *ctx)
-{
- v4l2_ctrl_handler_init(&ctx->ctrl_handler, 1);
- if (vpu->variant->codec & RK_VPU_CODEC_JPEG) {
- v4l2_ctrl_new_std(&ctx->ctrl_handler, &rockchip_vpu_ctrl_ops,
- V4L2_CID_JPEG_COMPRESSION_QUALITY,
- 5, 100, 1, 50);
- if (ctx->ctrl_handler.error) {
- vpu_err("Adding JPEG control failed %d\n",
- ctx->ctrl_handler.error);
- v4l2_ctrl_handler_free(&ctx->ctrl_handler);
- return ctx->ctrl_handler.error;
- }
- }
-
- return v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
-}
-
-/*
- * V4L2 file operations.
- */
-
-static int rockchip_vpu_open(struct file *filp)
-{
- struct rockchip_vpu_dev *vpu = video_drvdata(filp);
- struct video_device *vdev = video_devdata(filp);
- struct rockchip_vpu_ctx *ctx;
- int ret;
-
- /*
- * We do not need any extra locking here, because we operate only
- * on local data here, except reading few fields from dev, which
- * do not change through device's lifetime (which is guaranteed by
- * reference on module from open()) and V4L2 internal objects (such
- * as vdev and ctx->fh), which have proper locking done in respective
- * helper functions used here.
- */
-
- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
-
- ctx->dev = vpu;
- if (vdev == vpu->vfd_enc)
- ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(vpu->m2m_dev, ctx,
- &enc_queue_init);
- else
- ctx->fh.m2m_ctx = ERR_PTR(-ENODEV);
- if (IS_ERR(ctx->fh.m2m_ctx)) {
- ret = PTR_ERR(ctx->fh.m2m_ctx);
- kfree(ctx);
- return ret;
- }
-
- v4l2_fh_init(&ctx->fh, vdev);
- filp->private_data = &ctx->fh;
- v4l2_fh_add(&ctx->fh);
-
- if (vdev == vpu->vfd_enc) {
- rockchip_vpu_enc_reset_dst_fmt(vpu, ctx);
- rockchip_vpu_enc_reset_src_fmt(vpu, ctx);
- }
-
- ret = rockchip_vpu_ctrls_setup(vpu, ctx);
- if (ret) {
- vpu_err("Failed to set up controls\n");
- goto err_fh_free;
- }
- ctx->fh.ctrl_handler = &ctx->ctrl_handler;
-
- return 0;
-
-err_fh_free:
- v4l2_fh_del(&ctx->fh);
- v4l2_fh_exit(&ctx->fh);
- kfree(ctx);
- return ret;
-}
-
-static int rockchip_vpu_release(struct file *filp)
-{
- struct rockchip_vpu_ctx *ctx =
- container_of(filp->private_data, struct rockchip_vpu_ctx, fh);
-
- /*
- * No need for extra locking because this was the last reference
- * to this file.
- */
- v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
- v4l2_fh_del(&ctx->fh);
- v4l2_fh_exit(&ctx->fh);
- v4l2_ctrl_handler_free(&ctx->ctrl_handler);
- kfree(ctx);
-
- return 0;
-}
-
-static const struct v4l2_file_operations rockchip_vpu_fops = {
- .owner = THIS_MODULE,
- .open = rockchip_vpu_open,
- .release = rockchip_vpu_release,
- .poll = v4l2_m2m_fop_poll,
- .unlocked_ioctl = video_ioctl2,
- .mmap = v4l2_m2m_fop_mmap,
-};
-
-static const struct of_device_id of_rockchip_vpu_match[] = {
- { .compatible = "rockchip,rk3399-vpu", .data = &rk3399_vpu_variant, },
- { .compatible = "rockchip,rk3288-vpu", .data = &rk3288_vpu_variant, },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, of_rockchip_vpu_match);
-
-static int rockchip_vpu_video_device_register(struct rockchip_vpu_dev *vpu)
-{
- const struct of_device_id *match;
- struct video_device *vfd;
- int function, ret;
-
- match = of_match_node(of_rockchip_vpu_match, vpu->dev->of_node);
- vfd = video_device_alloc();
- if (!vfd) {
- v4l2_err(&vpu->v4l2_dev, "Failed to allocate video device\n");
- return -ENOMEM;
- }
-
- vfd->fops = &rockchip_vpu_fops;
- vfd->release = video_device_release;
- vfd->lock = &vpu->vpu_mutex;
- vfd->v4l2_dev = &vpu->v4l2_dev;
- vfd->vfl_dir = VFL_DIR_M2M;
- vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
- vfd->ioctl_ops = &rockchip_vpu_enc_ioctl_ops;
- snprintf(vfd->name, sizeof(vfd->name), "%s-enc", match->compatible);
- vpu->vfd_enc = vfd;
- video_set_drvdata(vfd, vpu);
-
- ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
- if (ret) {
- v4l2_err(&vpu->v4l2_dev, "Failed to register video device\n");
- goto err_free_dev;
- }
- v4l2_info(&vpu->v4l2_dev, "registered as /dev/video%d\n", vfd->num);
-
- function = MEDIA_ENT_F_PROC_VIDEO_ENCODER;
- ret = v4l2_m2m_register_media_controller(vpu->m2m_dev, vfd, function);
- if (ret) {
- v4l2_err(&vpu->v4l2_dev, "Failed to init mem2mem media controller\n");
- goto err_unreg_video;
- }
- return 0;
-
-err_unreg_video:
- video_unregister_device(vfd);
-err_free_dev:
- video_device_release(vfd);
- return ret;
-}
-
-static int rockchip_vpu_probe(struct platform_device *pdev)
-{
- const struct of_device_id *match;
- struct rockchip_vpu_dev *vpu;
- struct resource *res;
- int i, ret;
-
- vpu = devm_kzalloc(&pdev->dev, sizeof(*vpu), GFP_KERNEL);
- if (!vpu)
- return -ENOMEM;
-
- vpu->dev = &pdev->dev;
- vpu->pdev = pdev;
- mutex_init(&vpu->vpu_mutex);
- spin_lock_init(&vpu->irqlock);
-
- match = of_match_node(of_rockchip_vpu_match, pdev->dev.of_node);
- vpu->variant = match->data;
-
- INIT_DELAYED_WORK(&vpu->watchdog_work, rockchip_vpu_watchdog);
-
- for (i = 0; i < vpu->variant->num_clocks; i++)
- vpu->clocks[i].id = vpu->variant->clk_names[i];
- ret = devm_clk_bulk_get(&pdev->dev, vpu->variant->num_clocks,
- vpu->clocks);
- if (ret)
- return ret;
-
- res = platform_get_resource(vpu->pdev, IORESOURCE_MEM, 0);
- vpu->base = devm_ioremap_resource(vpu->dev, res);
- if (IS_ERR(vpu->base))
- return PTR_ERR(vpu->base);
- vpu->enc_base = vpu->base + vpu->variant->enc_offset;
-
- ret = dma_set_coherent_mask(vpu->dev, DMA_BIT_MASK(32));
- if (ret) {
- dev_err(vpu->dev, "Could not set DMA coherent mask.\n");
- return ret;
- }
-
- if (vpu->variant->vepu_irq) {
- int irq;
-
- irq = platform_get_irq_byname(vpu->pdev, "vepu");
- if (irq <= 0) {
- dev_err(vpu->dev, "Could not get vepu IRQ.\n");
- return -ENXIO;
- }
-
- ret = devm_request_irq(vpu->dev, irq, vpu->variant->vepu_irq,
- 0, dev_name(vpu->dev), vpu);
- if (ret) {
- dev_err(vpu->dev, "Could not request vepu IRQ.\n");
- return ret;
- }
- }
-
- ret = vpu->variant->init(vpu);
- if (ret) {
- dev_err(&pdev->dev, "Failed to init VPU hardware\n");
- return ret;
- }
-
- pm_runtime_set_autosuspend_delay(vpu->dev, 100);
- pm_runtime_use_autosuspend(vpu->dev);
- pm_runtime_enable(vpu->dev);
-
- ret = clk_bulk_prepare(vpu->variant->num_clocks, vpu->clocks);
- if (ret) {
- dev_err(&pdev->dev, "Failed to prepare clocks\n");
- return ret;
- }
-
- ret = v4l2_device_register(&pdev->dev, &vpu->v4l2_dev);
- if (ret) {
- dev_err(&pdev->dev, "Failed to register v4l2 device\n");
- goto err_clk_unprepare;
- }
- platform_set_drvdata(pdev, vpu);
-
- vpu->m2m_dev = v4l2_m2m_init(&vpu_m2m_ops);
- if (IS_ERR(vpu->m2m_dev)) {
- v4l2_err(&vpu->v4l2_dev, "Failed to init mem2mem device\n");
- ret = PTR_ERR(vpu->m2m_dev);
- goto err_v4l2_unreg;
- }
-
- vpu->mdev.dev = vpu->dev;
- strscpy(vpu->mdev.model, DRIVER_NAME, sizeof(vpu->mdev.model));
- strscpy(vpu->mdev.bus_info, "platform: " DRIVER_NAME,
- sizeof(vpu->mdev.model));
- media_device_init(&vpu->mdev);
- vpu->v4l2_dev.mdev = &vpu->mdev;
-
- ret = rockchip_vpu_video_device_register(vpu);
- if (ret) {
- dev_err(&pdev->dev, "Failed to register encoder\n");
- goto err_m2m_rel;
- }
-
- ret = media_device_register(&vpu->mdev);
- if (ret) {
- v4l2_err(&vpu->v4l2_dev, "Failed to register mem2mem media device\n");
- goto err_video_dev_unreg;
- }
- return 0;
-err_video_dev_unreg:
- if (vpu->vfd_enc) {
- v4l2_m2m_unregister_media_controller(vpu->m2m_dev);
- video_unregister_device(vpu->vfd_enc);
- video_device_release(vpu->vfd_enc);
- }
-err_m2m_rel:
- media_device_cleanup(&vpu->mdev);
- v4l2_m2m_release(vpu->m2m_dev);
-err_v4l2_unreg:
- v4l2_device_unregister(&vpu->v4l2_dev);
-err_clk_unprepare:
- clk_bulk_unprepare(vpu->variant->num_clocks, vpu->clocks);
- pm_runtime_dont_use_autosuspend(vpu->dev);
- pm_runtime_disable(vpu->dev);
- return ret;
-}
-
-static int rockchip_vpu_remove(struct platform_device *pdev)
-{
- struct rockchip_vpu_dev *vpu = platform_get_drvdata(pdev);
-
- v4l2_info(&vpu->v4l2_dev, "Removing %s\n", pdev->name);
-
- media_device_unregister(&vpu->mdev);
- if (vpu->vfd_enc) {
- v4l2_m2m_unregister_media_controller(vpu->m2m_dev);
- video_unregister_device(vpu->vfd_enc);
- video_device_release(vpu->vfd_enc);
- }
- media_device_cleanup(&vpu->mdev);
- v4l2_m2m_release(vpu->m2m_dev);
- v4l2_device_unregister(&vpu->v4l2_dev);
- clk_bulk_unprepare(vpu->variant->num_clocks, vpu->clocks);
- pm_runtime_dont_use_autosuspend(vpu->dev);
- pm_runtime_disable(vpu->dev);
- return 0;
-}
-
-static const struct dev_pm_ops rockchip_vpu_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
-};
-
-static struct platform_driver rockchip_vpu_driver = {
- .probe = rockchip_vpu_probe,
- .remove = rockchip_vpu_remove,
- .driver = {
- .name = DRIVER_NAME,
- .of_match_table = of_match_ptr(of_rockchip_vpu_match),
- .pm = &rockchip_vpu_pm_ops,
- },
-};
-module_platform_driver(rockchip_vpu_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Alpha Lin <Alpha.Lin@Rock-Chips.com>");
-MODULE_AUTHOR("Tomasz Figa <tfiga@chromium.org>");
-MODULE_AUTHOR("Ezequiel Garcia <ezequiel@collabora.com>");
-MODULE_DESCRIPTION("Rockchip VPU codec driver");
diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu_enc.c b/drivers/staging/media/rockchip/vpu/rockchip_vpu_enc.c
deleted file mode 100644
index dcbfc3cbc9f3..000000000000
--- a/drivers/staging/media/rockchip/vpu/rockchip_vpu_enc.c
+++ /dev/null
@@ -1,671 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Rockchip VPU codec driver
- *
- * Copyright (C) 2018 Collabora, Ltd.
- * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
- * Alpha Lin <Alpha.Lin@rock-chips.com>
- * Jeffy Chen <jeffy.chen@rock-chips.com>
- *
- * Copyright 2018 Google LLC.
- * Tomasz Figa <tfiga@chromium.org>
- *
- * Based on s5p-mfc driver by Samsung Electronics Co., Ltd.
- * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd.
- */
-
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/pm_runtime.h>
-#include <linux/videodev2.h>
-#include <linux/workqueue.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-event.h>
-#include <media/v4l2-mem2mem.h>
-#include <media/videobuf2-core.h>
-#include <media/videobuf2-dma-sg.h>
-
-#include "rockchip_vpu.h"
-#include "rockchip_vpu_hw.h"
-#include "rockchip_vpu_common.h"
-
-/**
- * struct v4l2_format_info - information about a V4L2 format
- * @format: 4CC format identifier (V4L2_PIX_FMT_*)
- * @header_size: Size of header, optional and used by compressed formats
- * @num_planes: Number of planes (1 to 3)
- * @cpp: Number of bytes per pixel (per plane)
- * @hsub: Horizontal chroma subsampling factor
- * @vsub: Vertical chroma subsampling factor
- * @is_compressed: Is it a compressed format?
- * @multiplanar: Is it a multiplanar variant format? (e.g. NV12M)
- */
-struct rockchip_vpu_v4l2_format_info {
- u32 format;
- u32 header_size;
- u8 num_planes;
- u8 cpp[3];
- u8 hsub;
- u8 vsub;
- u8 is_compressed;
- u8 multiplanar;
-};
-
-static const struct rockchip_vpu_v4l2_format_info *
-rockchip_vpu_v4l2_format_info(u32 format)
-{
- static const struct rockchip_vpu_v4l2_format_info formats[] = {
- { .format = V4L2_PIX_FMT_YUV420M, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 2, .multiplanar = 1 },
- { .format = V4L2_PIX_FMT_NV12M, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 2, .multiplanar = 1 },
- { .format = V4L2_PIX_FMT_YUYV, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 },
- { .format = V4L2_PIX_FMT_UYVY, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 },
- };
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(formats); ++i) {
- if (formats[i].format == format)
- return &formats[i];
- }
-
- vpu_err("Unsupported V4L 4CC format (%08x)\n", format);
- return NULL;
-}
-
-static void
-fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt,
- int pixelformat, int width, int height)
-{
- const struct rockchip_vpu_v4l2_format_info *info;
- struct v4l2_plane_pix_format *plane;
- int i;
-
- info = rockchip_vpu_v4l2_format_info(pixelformat);
- if (!info)
- return;
-
- pixfmt->width = width;
- pixfmt->height = height;
- pixfmt->pixelformat = pixelformat;
-
- if (!info->multiplanar) {
- pixfmt->num_planes = 1;
- plane = &pixfmt->plane_fmt[0];
- plane->bytesperline = info->is_compressed ?
- 0 : width * info->cpp[0];
- plane->sizeimage = info->header_size;
- for (i = 0; i < info->num_planes; i++) {
- unsigned int hsub = (i == 0) ? 1 : info->hsub;
- unsigned int vsub = (i == 0) ? 1 : info->vsub;
-
- plane->sizeimage += info->cpp[i] *
- DIV_ROUND_UP(width, hsub) *
- DIV_ROUND_UP(height, vsub);
- }
- } else {
- pixfmt->num_planes = info->num_planes;
- for (i = 0; i < info->num_planes; i++) {
- unsigned int hsub = (i == 0) ? 1 : info->hsub;
- unsigned int vsub = (i == 0) ? 1 : info->vsub;
-
- plane = &pixfmt->plane_fmt[i];
- plane->bytesperline =
- info->cpp[i] * DIV_ROUND_UP(width, hsub);
- plane->sizeimage =
- plane->bytesperline * DIV_ROUND_UP(height, vsub);
- }
- }
-}
-
-static const struct rockchip_vpu_fmt *
-rockchip_vpu_find_format(struct rockchip_vpu_ctx *ctx, u32 fourcc)
-{
- struct rockchip_vpu_dev *dev = ctx->dev;
- const struct rockchip_vpu_fmt *formats;
- unsigned int num_fmts, i;
-
- formats = dev->variant->enc_fmts;
- num_fmts = dev->variant->num_enc_fmts;
- for (i = 0; i < num_fmts; i++)
- if (formats[i].fourcc == fourcc)
- return &formats[i];
- return NULL;
-}
-
-static const struct rockchip_vpu_fmt *
-rockchip_vpu_get_default_fmt(struct rockchip_vpu_ctx *ctx, bool bitstream)
-{
- struct rockchip_vpu_dev *dev = ctx->dev;
- const struct rockchip_vpu_fmt *formats;
- unsigned int num_fmts, i;
-
- formats = dev->variant->enc_fmts;
- num_fmts = dev->variant->num_enc_fmts;
- for (i = 0; i < num_fmts; i++) {
- if (bitstream == (formats[i].codec_mode != RK_VPU_MODE_NONE))
- return &formats[i];
- }
- return NULL;
-}
-
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct rockchip_vpu_dev *vpu = video_drvdata(file);
- struct video_device *vdev = video_devdata(file);
-
- strscpy(cap->driver, vpu->dev->driver->name, sizeof(cap->driver));
- strscpy(cap->card, vdev->name, sizeof(cap->card));
- snprintf(cap->bus_info, sizeof(cap->bus_info), "platform: %s",
- vpu->dev->driver->name);
- return 0;
-}
-
-static int vidioc_enum_framesizes(struct file *file, void *priv,
- struct v4l2_frmsizeenum *fsize)
-{
- struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv);
- const struct rockchip_vpu_fmt *fmt;
-
- if (fsize->index != 0) {
- vpu_debug(0, "invalid frame size index (expected 0, got %d)\n",
- fsize->index);
- return -EINVAL;
- }
-
- fmt = rockchip_vpu_find_format(ctx, fsize->pixel_format);
- if (!fmt) {
- vpu_debug(0, "unsupported bitstream format (%08x)\n",
- fsize->pixel_format);
- return -EINVAL;
- }
-
- /* This only makes sense for coded formats */
- if (fmt->codec_mode == RK_VPU_MODE_NONE)
- return -EINVAL;
-
- fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
- fsize->stepwise = fmt->frmsize;
-
- return 0;
-}
-
-static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
-{
- struct rockchip_vpu_dev *dev = video_drvdata(file);
- const struct rockchip_vpu_fmt *fmt;
- const struct rockchip_vpu_fmt *formats;
- int num_fmts, i, j = 0;
-
- formats = dev->variant->enc_fmts;
- num_fmts = dev->variant->num_enc_fmts;
- for (i = 0; i < num_fmts; i++) {
- /* Skip uncompressed formats */
- if (formats[i].codec_mode == RK_VPU_MODE_NONE)
- continue;
- if (j == f->index) {
- fmt = &formats[i];
- f->pixelformat = fmt->fourcc;
- return 0;
- }
- ++j;
- }
- return -EINVAL;
-}
-
-static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
-{
- struct rockchip_vpu_dev *dev = video_drvdata(file);
- const struct rockchip_vpu_fmt *formats;
- const struct rockchip_vpu_fmt *fmt;
- int num_fmts, i, j = 0;
-
- formats = dev->variant->enc_fmts;
- num_fmts = dev->variant->num_enc_fmts;
- for (i = 0; i < num_fmts; i++) {
- if (formats[i].codec_mode != RK_VPU_MODE_NONE)
- continue;
- if (j == f->index) {
- fmt = &formats[i];
- f->pixelformat = fmt->fourcc;
- return 0;
- }
- ++j;
- }
- return -EINVAL;
-}
-
-static int vidioc_g_fmt_out_mplane(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
- struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv);
-
- vpu_debug(4, "f->type = %d\n", f->type);
-
- *pix_mp = ctx->src_fmt;
-
- return 0;
-}
-
-static int vidioc_g_fmt_cap_mplane(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
- struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv);
-
- vpu_debug(4, "f->type = %d\n", f->type);
-
- *pix_mp = ctx->dst_fmt;
-
- return 0;
-}
-
-static int
-vidioc_try_fmt_cap_mplane(struct file *file, void *priv, struct v4l2_format *f)
-{
- struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv);
- struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
- const struct rockchip_vpu_fmt *fmt;
-
- vpu_debug(4, "%c%c%c%c\n",
- (pix_mp->pixelformat & 0x7f),
- (pix_mp->pixelformat >> 8) & 0x7f,
- (pix_mp->pixelformat >> 16) & 0x7f,
- (pix_mp->pixelformat >> 24) & 0x7f);
-
- fmt = rockchip_vpu_find_format(ctx, pix_mp->pixelformat);
- if (!fmt) {
- fmt = rockchip_vpu_get_default_fmt(ctx, true);
- f->fmt.pix.pixelformat = fmt->fourcc;
- }
-
- pix_mp->num_planes = 1;
- pix_mp->field = V4L2_FIELD_NONE;
- pix_mp->width = clamp(pix_mp->width,
- fmt->frmsize.min_width,
- fmt->frmsize.max_width);
- pix_mp->height = clamp(pix_mp->height,
- fmt->frmsize.min_height,
- fmt->frmsize.max_height);
- /* Round up to macroblocks. */
- pix_mp->width = round_up(pix_mp->width, JPEG_MB_DIM);
- pix_mp->height = round_up(pix_mp->height, JPEG_MB_DIM);
-
- /*
- * For compressed formats the application can specify
- * sizeimage. If the application passes a zero sizeimage,
- * let's default to the maximum frame size.
- */
- if (!pix_mp->plane_fmt[0].sizeimage)
- pix_mp->plane_fmt[0].sizeimage = fmt->header_size +
- pix_mp->width * pix_mp->height * fmt->max_depth;
- memset(pix_mp->plane_fmt[0].reserved, 0,
- sizeof(pix_mp->plane_fmt[0].reserved));
- return 0;
-}
-
-static int
-vidioc_try_fmt_out_mplane(struct file *file, void *priv, struct v4l2_format *f)
-{
- struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv);
- struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
- const struct rockchip_vpu_fmt *fmt;
- unsigned int width, height;
- int i;
-
- vpu_debug(4, "%c%c%c%c\n",
- (pix_mp->pixelformat & 0x7f),
- (pix_mp->pixelformat >> 8) & 0x7f,
- (pix_mp->pixelformat >> 16) & 0x7f,
- (pix_mp->pixelformat >> 24) & 0x7f);
-
- fmt = rockchip_vpu_find_format(ctx, pix_mp->pixelformat);
- if (!fmt) {
- fmt = rockchip_vpu_get_default_fmt(ctx, false);
- f->fmt.pix.pixelformat = fmt->fourcc;
- }
-
- pix_mp->field = V4L2_FIELD_NONE;
- width = clamp(pix_mp->width,
- ctx->vpu_dst_fmt->frmsize.min_width,
- ctx->vpu_dst_fmt->frmsize.max_width);
- height = clamp(pix_mp->height,
- ctx->vpu_dst_fmt->frmsize.min_height,
- ctx->vpu_dst_fmt->frmsize.max_height);
- /* Round up to macroblocks. */
- width = round_up(width, JPEG_MB_DIM);
- height = round_up(height, JPEG_MB_DIM);
-
- /* Fill remaining fields */
- fill_pixfmt_mp(pix_mp, fmt->fourcc, width, height);
-
- for (i = 0; i < pix_mp->num_planes; i++) {
- memset(pix_mp->plane_fmt[i].reserved, 0,
- sizeof(pix_mp->plane_fmt[i].reserved));
- }
- return 0;
-}
-
-void rockchip_vpu_enc_reset_dst_fmt(struct rockchip_vpu_dev *vpu,
- struct rockchip_vpu_ctx *ctx)
-{
- struct v4l2_pix_format_mplane *fmt = &ctx->dst_fmt;
-
- ctx->vpu_dst_fmt = rockchip_vpu_get_default_fmt(ctx, true);
-
- memset(fmt, 0, sizeof(*fmt));
-
- fmt->num_planes = 1;
- fmt->width = clamp(fmt->width, ctx->vpu_dst_fmt->frmsize.min_width,
- ctx->vpu_dst_fmt->frmsize.max_width);
- fmt->height = clamp(fmt->height, ctx->vpu_dst_fmt->frmsize.min_height,
- ctx->vpu_dst_fmt->frmsize.max_height);
- fmt->pixelformat = ctx->vpu_dst_fmt->fourcc;
- fmt->field = V4L2_FIELD_NONE;
- fmt->colorspace = V4L2_COLORSPACE_JPEG,
- fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
- fmt->quantization = V4L2_QUANTIZATION_DEFAULT;
- fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT;
-
- fmt->plane_fmt[0].sizeimage = ctx->vpu_dst_fmt->header_size +
- fmt->width * fmt->height * ctx->vpu_dst_fmt->max_depth;
-}
-
-void rockchip_vpu_enc_reset_src_fmt(struct rockchip_vpu_dev *vpu,
- struct rockchip_vpu_ctx *ctx)
-{
- struct v4l2_pix_format_mplane *fmt = &ctx->src_fmt;
- unsigned int width, height;
-
- ctx->vpu_src_fmt = rockchip_vpu_get_default_fmt(ctx, false);
-
- memset(fmt, 0, sizeof(*fmt));
-
- width = clamp(fmt->width, ctx->vpu_dst_fmt->frmsize.min_width,
- ctx->vpu_dst_fmt->frmsize.max_width);
- height = clamp(fmt->height, ctx->vpu_dst_fmt->frmsize.min_height,
- ctx->vpu_dst_fmt->frmsize.max_height);
- fmt->field = V4L2_FIELD_NONE;
- fmt->colorspace = V4L2_COLORSPACE_JPEG,
- fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
- fmt->quantization = V4L2_QUANTIZATION_DEFAULT;
- fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT;
-
- fill_pixfmt_mp(fmt, ctx->vpu_src_fmt->fourcc, width, height);
-}
-
-static int
-vidioc_s_fmt_out_mplane(struct file *file, void *priv, struct v4l2_format *f)
-{
- struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
- struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv);
- struct vb2_queue *vq;
- int ret;
-
- /* Change not allowed if queue is streaming. */
- vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
- if (vb2_is_streaming(vq))
- return -EBUSY;
-
- ret = vidioc_try_fmt_out_mplane(file, priv, f);
- if (ret)
- return ret;
-
- ctx->vpu_src_fmt = rockchip_vpu_find_format(ctx, pix_mp->pixelformat);
- ctx->src_fmt = *pix_mp;
-
- /* Propagate to the CAPTURE format */
- ctx->dst_fmt.colorspace = pix_mp->colorspace;
- ctx->dst_fmt.ycbcr_enc = pix_mp->ycbcr_enc;
- ctx->dst_fmt.xfer_func = pix_mp->xfer_func;
- ctx->dst_fmt.quantization = pix_mp->quantization;
- ctx->dst_fmt.width = pix_mp->width;
- ctx->dst_fmt.height = pix_mp->height;
-
- vpu_debug(0, "OUTPUT codec mode: %d\n", ctx->vpu_src_fmt->codec_mode);
- vpu_debug(0, "fmt - w: %d, h: %d, mb - w: %d, h: %d\n",
- pix_mp->width, pix_mp->height,
- JPEG_MB_WIDTH(pix_mp->width),
- JPEG_MB_HEIGHT(pix_mp->height));
- return 0;
-}
-
-static int
-vidioc_s_fmt_cap_mplane(struct file *file, void *priv, struct v4l2_format *f)
-{
- struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
- struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv);
- struct rockchip_vpu_dev *vpu = ctx->dev;
- struct vb2_queue *vq, *peer_vq;
- int ret;
-
- /* Change not allowed if queue is streaming. */
- vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
- if (vb2_is_streaming(vq))
- return -EBUSY;
-
- /*
- * Since format change on the CAPTURE queue will reset
- * the OUTPUT queue, we can't allow doing so
- * when the OUTPUT queue has buffers allocated.
- */
- peer_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
- V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
- if (vb2_is_busy(peer_vq) &&
- (pix_mp->pixelformat != ctx->dst_fmt.pixelformat ||
- pix_mp->height != ctx->dst_fmt.height ||
- pix_mp->width != ctx->dst_fmt.width))
- return -EBUSY;
-
- ret = vidioc_try_fmt_cap_mplane(file, priv, f);
- if (ret)
- return ret;
-
- ctx->vpu_dst_fmt = rockchip_vpu_find_format(ctx, pix_mp->pixelformat);
- ctx->dst_fmt = *pix_mp;
-
- vpu_debug(0, "CAPTURE codec mode: %d\n", ctx->vpu_dst_fmt->codec_mode);
- vpu_debug(0, "fmt - w: %d, h: %d, mb - w: %d, h: %d\n",
- pix_mp->width, pix_mp->height,
- JPEG_MB_WIDTH(pix_mp->width),
- JPEG_MB_HEIGHT(pix_mp->height));
-
- /*
- * Current raw format might have become invalid with newly
- * selected codec, so reset it to default just to be safe and
- * keep internal driver state sane. User is mandated to set
- * the raw format again after we return, so we don't need
- * anything smarter.
- */
- rockchip_vpu_enc_reset_src_fmt(vpu, ctx);
- return 0;
-}
-
-const struct v4l2_ioctl_ops rockchip_vpu_enc_ioctl_ops = {
- .vidioc_querycap = vidioc_querycap,
- .vidioc_enum_framesizes = vidioc_enum_framesizes,
-
- .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_cap_mplane,
- .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_out_mplane,
- .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_out_mplane,
- .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_cap_mplane,
- .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_out_mplane,
- .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_cap_mplane,
- .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane,
- .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane,
-
- .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
- .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
- .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
- .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
- .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
- .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
- .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
-
- .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
- .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-
- .vidioc_streamon = v4l2_m2m_ioctl_streamon,
- .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
-};
-
-static int
-rockchip_vpu_queue_setup(struct vb2_queue *vq,
- unsigned int *num_buffers,
- unsigned int *num_planes,
- unsigned int sizes[],
- struct device *alloc_devs[])
-{
- struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(vq);
- struct v4l2_pix_format_mplane *pixfmt;
- int i;
-
- switch (vq->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- pixfmt = &ctx->dst_fmt;
- break;
- case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
- pixfmt = &ctx->src_fmt;
- break;
- default:
- vpu_err("invalid queue type: %d\n", vq->type);
- return -EINVAL;
- }
-
- if (*num_planes) {
- if (*num_planes != pixfmt->num_planes)
- return -EINVAL;
- for (i = 0; i < pixfmt->num_planes; ++i)
- if (sizes[i] < pixfmt->plane_fmt[i].sizeimage)
- return -EINVAL;
- return 0;
- }
-
- *num_planes = pixfmt->num_planes;
- for (i = 0; i < pixfmt->num_planes; ++i)
- sizes[i] = pixfmt->plane_fmt[i].sizeimage;
- return 0;
-}
-
-static int rockchip_vpu_buf_prepare(struct vb2_buffer *vb)
-{
- struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
- struct vb2_queue *vq = vb->vb2_queue;
- struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(vq);
- struct v4l2_pix_format_mplane *pixfmt;
- unsigned int sz;
- int ret = 0;
- int i;
-
- switch (vq->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- pixfmt = &ctx->dst_fmt;
- break;
- case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
- pixfmt = &ctx->src_fmt;
-
- if (vbuf->field == V4L2_FIELD_ANY)
- vbuf->field = V4L2_FIELD_NONE;
- if (vbuf->field != V4L2_FIELD_NONE) {
- vpu_debug(4, "field %d not supported\n",
- vbuf->field);
- return -EINVAL;
- }
- break;
- default:
- vpu_err("invalid queue type: %d\n", vq->type);
- return -EINVAL;
- }
-
- for (i = 0; i < pixfmt->num_planes; ++i) {
- sz = pixfmt->plane_fmt[i].sizeimage;
- vpu_debug(4, "plane %d size: %ld, sizeimage: %u\n",
- i, vb2_plane_size(vb, i), sz);
- if (vb2_plane_size(vb, i) < sz) {
- vpu_err("plane %d is too small\n", i);
- ret = -EINVAL;
- break;
- }
- }
-
- return ret;
-}
-
-static void rockchip_vpu_buf_queue(struct vb2_buffer *vb)
-{
- struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
- struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
-
- v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
-}
-
-static int rockchip_vpu_start_streaming(struct vb2_queue *q, unsigned int count)
-{
- struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(q);
- enum rockchip_vpu_codec_mode codec_mode;
-
- if (V4L2_TYPE_IS_OUTPUT(q->type))
- ctx->sequence_out = 0;
- else
- ctx->sequence_cap = 0;
-
- /* Set codec_ops for the chosen destination format */
- codec_mode = ctx->vpu_dst_fmt->codec_mode;
-
- vpu_debug(4, "Codec mode = %d\n", codec_mode);
- ctx->codec_ops = &ctx->dev->variant->codec_ops[codec_mode];
-
- /* A bounce buffer is needed for the JPEG payload */
- if (!V4L2_TYPE_IS_OUTPUT(q->type)) {
- ctx->bounce_size = ctx->dst_fmt.plane_fmt[0].sizeimage -
- ctx->vpu_dst_fmt->header_size;
- ctx->bounce_buf = dma_alloc_attrs(ctx->dev->dev,
- ctx->bounce_size,
- &ctx->bounce_dma_addr,
- GFP_KERNEL,
- DMA_ATTR_ALLOC_SINGLE_PAGES);
- }
- return 0;
-}
-
-static void rockchip_vpu_stop_streaming(struct vb2_queue *q)
-{
- struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(q);
-
- if (!V4L2_TYPE_IS_OUTPUT(q->type))
- dma_free_attrs(ctx->dev->dev,
- ctx->bounce_size,
- ctx->bounce_buf,
- ctx->bounce_dma_addr,
- DMA_ATTR_ALLOC_SINGLE_PAGES);
-
- /*
- * The mem2mem framework calls v4l2_m2m_cancel_job before
- * .stop_streaming, so there isn't any job running and
- * it is safe to return all the buffers.
- */
- for (;;) {
- struct vb2_v4l2_buffer *vbuf;
-
- if (V4L2_TYPE_IS_OUTPUT(q->type))
- vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
- else
- vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
- if (!vbuf)
- break;
- v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
- }
-}
-
-const struct vb2_ops rockchip_vpu_enc_queue_ops = {
- .queue_setup = rockchip_vpu_queue_setup,
- .buf_prepare = rockchip_vpu_buf_prepare,
- .buf_queue = rockchip_vpu_buf_queue,
- .start_streaming = rockchip_vpu_start_streaming,
- .stop_streaming = rockchip_vpu_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
-};
diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu_hw.h b/drivers/staging/media/rockchip/vpu/rockchip_vpu_hw.h
deleted file mode 100644
index 2b955da1be1a..000000000000
--- a/drivers/staging/media/rockchip/vpu/rockchip_vpu_hw.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Rockchip VPU codec driver
- *
- * Copyright 2018 Google LLC.
- * Tomasz Figa <tfiga@chromium.org>
- */
-
-#ifndef ROCKCHIP_VPU_HW_H_
-#define ROCKCHIP_VPU_HW_H_
-
-#include <linux/interrupt.h>
-#include <linux/v4l2-controls.h>
-#include <media/videobuf2-core.h>
-
-struct rockchip_vpu_dev;
-struct rockchip_vpu_ctx;
-struct rockchip_vpu_buf;
-struct rockchip_vpu_variant;
-
-/**
- * struct rockchip_vpu_codec_ops - codec mode specific operations
- *
- * @run: Start single {en,de)coding job. Called from atomic context
- * to indicate that a pair of buffers is ready and the hardware
- * should be programmed and started.
- * @done: Read back processing results and additional data from hardware.
- * @reset: Reset the hardware in case of a timeout.
- */
-struct rockchip_vpu_codec_ops {
- void (*run)(struct rockchip_vpu_ctx *ctx);
- void (*done)(struct rockchip_vpu_ctx *ctx, enum vb2_buffer_state);
- void (*reset)(struct rockchip_vpu_ctx *ctx);
-};
-
-/**
- * enum rockchip_vpu_enc_fmt - source format ID for hardware registers.
- */
-enum rockchip_vpu_enc_fmt {
- RK3288_VPU_ENC_FMT_YUV420P = 0,
- RK3288_VPU_ENC_FMT_YUV420SP = 1,
- RK3288_VPU_ENC_FMT_YUYV422 = 2,
- RK3288_VPU_ENC_FMT_UYVY422 = 3,
-};
-
-extern const struct rockchip_vpu_variant rk3399_vpu_variant;
-extern const struct rockchip_vpu_variant rk3288_vpu_variant;
-
-void rockchip_vpu_watchdog(struct work_struct *work);
-void rockchip_vpu_run(struct rockchip_vpu_ctx *ctx);
-void rockchip_vpu_irq_done(struct rockchip_vpu_dev *vpu,
- unsigned int bytesused,
- enum vb2_buffer_state result);
-
-void rk3288_vpu_jpeg_enc_run(struct rockchip_vpu_ctx *ctx);
-void rk3399_vpu_jpeg_enc_run(struct rockchip_vpu_ctx *ctx);
-
-#endif /* ROCKCHIP_VPU_HW_H_ */
diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu_jpeg.h b/drivers/staging/media/rockchip/vpu/rockchip_vpu_jpeg.h
deleted file mode 100644
index 72645d8e2ade..000000000000
--- a/drivers/staging/media/rockchip/vpu/rockchip_vpu_jpeg.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-
-#define JPEG_HEADER_SIZE 601
-
-struct rockchip_vpu_jpeg_ctx {
- int width;
- int height;
- int quality;
- unsigned char *buffer;
-};
-
-unsigned char *
-rockchip_vpu_jpeg_get_qtable(struct rockchip_vpu_jpeg_ctx *ctx, int index);
-void rockchip_vpu_jpeg_header_assemble(struct rockchip_vpu_jpeg_ctx *ctx);
diff --git a/drivers/staging/media/soc_camera/imx074.c b/drivers/staging/media/soc_camera/imx074.c
index d907aa62f898..14240b74cdd0 100644
--- a/drivers/staging/media/soc_camera/imx074.c
+++ b/drivers/staging/media/soc_camera/imx074.c
@@ -409,7 +409,7 @@ static int imx074_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct imx074 *priv;
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adapter = client->adapter;
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
int ret;
diff --git a/drivers/staging/media/soc_camera/mt9t031.c b/drivers/staging/media/soc_camera/mt9t031.c
index 615ae9df2c57..c14f23221544 100644
--- a/drivers/staging/media/soc_camera/mt9t031.c
+++ b/drivers/staging/media/soc_camera/mt9t031.c
@@ -751,7 +751,7 @@ static int mt9t031_probe(struct i2c_client *client,
{
struct mt9t031 *mt9t031;
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adapter = client->adapter;
int ret;
if (!ssdd) {
diff --git a/drivers/staging/media/soc_camera/soc_mt9v022.c b/drivers/staging/media/soc_camera/soc_mt9v022.c
index e7e0d3d29499..1739a618846d 100644
--- a/drivers/staging/media/soc_camera/soc_mt9v022.c
+++ b/drivers/staging/media/soc_camera/soc_mt9v022.c
@@ -883,7 +883,7 @@ static int mt9v022_probe(struct i2c_client *client,
{
struct mt9v022 *mt9v022;
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adapter = client->adapter;
struct mt9v022_platform_data *pdata;
int ret;
diff --git a/drivers/staging/media/soc_camera/soc_ov5642.c b/drivers/staging/media/soc_camera/soc_ov5642.c
index 94696d7baf83..39ae24dca65f 100644
--- a/drivers/staging/media/soc_camera/soc_ov5642.c
+++ b/drivers/staging/media/soc_camera/soc_ov5642.c
@@ -687,7 +687,8 @@ static int reg_write16(struct i2c_client *client, u16 reg, u16 val16)
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int ov5642_get_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+static int ov5642_get_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;
@@ -705,7 +706,8 @@ static int ov5642_get_register(struct v4l2_subdev *sd, struct v4l2_dbg_register
return ret;
}
-static int ov5642_set_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
+static int ov5642_set_register(struct v4l2_subdev *sd,
+ const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/staging/media/sunxi/cedrus/Makefile b/drivers/staging/media/sunxi/cedrus/Makefile
index 808842f0119e..c85ac6db0302 100644
--- a/drivers/staging/media/sunxi/cedrus/Makefile
+++ b/drivers/staging/media/sunxi/cedrus/Makefile
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_VIDEO_SUNXI_CEDRUS) += sunxi-cedrus.o
-sunxi-cedrus-y = cedrus.o cedrus_video.o cedrus_hw.o cedrus_dec.o cedrus_mpeg2.o
+sunxi-cedrus-y = cedrus.o cedrus_video.o cedrus_hw.o cedrus_dec.o \
+ cedrus_mpeg2.o cedrus_h264.o
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c
index d0429c0e6b6b..370937edfc14 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.c
@@ -40,6 +40,36 @@ static const struct cedrus_control cedrus_controls[] = {
.codec = CEDRUS_CODEC_MPEG2,
.required = false,
},
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS,
+ .elem_size = sizeof(struct v4l2_ctrl_h264_decode_params),
+ .codec = CEDRUS_CODEC_H264,
+ .required = true,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS,
+ .elem_size = sizeof(struct v4l2_ctrl_h264_slice_params),
+ .codec = CEDRUS_CODEC_H264,
+ .required = true,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_SPS,
+ .elem_size = sizeof(struct v4l2_ctrl_h264_sps),
+ .codec = CEDRUS_CODEC_H264,
+ .required = true,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_PPS,
+ .elem_size = sizeof(struct v4l2_ctrl_h264_pps),
+ .codec = CEDRUS_CODEC_H264,
+ .required = true,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX,
+ .elem_size = sizeof(struct v4l2_ctrl_h264_scaling_matrix),
+ .codec = CEDRUS_CODEC_H264,
+ .required = true,
+ },
};
#define CEDRUS_CONTROLS_COUNT ARRAY_SIZE(cedrus_controls)
@@ -278,6 +308,7 @@ static int cedrus_probe(struct platform_device *pdev)
}
dev->dec_ops[CEDRUS_CODEC_MPEG2] = &cedrus_dec_ops_mpeg2;
+ dev->dec_ops[CEDRUS_CODEC_H264] = &cedrus_dec_ops_h264;
mutex_init(&dev->dev_mutex);
@@ -369,36 +400,41 @@ static int cedrus_remove(struct platform_device *pdev)
}
static const struct cedrus_variant sun4i_a10_cedrus_variant = {
- /* No particular capability. */
+ .mod_rate = 320000000,
};
static const struct cedrus_variant sun5i_a13_cedrus_variant = {
- /* No particular capability. */
+ .mod_rate = 320000000,
};
static const struct cedrus_variant sun7i_a20_cedrus_variant = {
- /* No particular capability. */
+ .mod_rate = 320000000,
};
static const struct cedrus_variant sun8i_a33_cedrus_variant = {
.capabilities = CEDRUS_CAPABILITY_UNTILED,
+ .mod_rate = 320000000,
};
static const struct cedrus_variant sun8i_h3_cedrus_variant = {
.capabilities = CEDRUS_CAPABILITY_UNTILED,
+ .mod_rate = 402000000,
};
static const struct cedrus_variant sun50i_a64_cedrus_variant = {
.capabilities = CEDRUS_CAPABILITY_UNTILED,
+ .mod_rate = 402000000,
};
static const struct cedrus_variant sun50i_h5_cedrus_variant = {
.capabilities = CEDRUS_CAPABILITY_UNTILED,
+ .mod_rate = 402000000,
};
static const struct cedrus_variant sun50i_h6_cedrus_variant = {
.capabilities = CEDRUS_CAPABILITY_UNTILED,
.quirks = CEDRUS_QUIRK_NO_DMA_OFFSET,
+ .mod_rate = 600000000,
};
static const struct of_device_id cedrus_dt_match[] = {
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h
index c57c04b41d2e..3f476d0fd981 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.h
@@ -32,7 +32,7 @@
enum cedrus_codec {
CEDRUS_CODEC_MPEG2,
-
+ CEDRUS_CODEC_H264,
CEDRUS_CODEC_LAST,
};
@@ -42,6 +42,12 @@ enum cedrus_irq_status {
CEDRUS_IRQ_OK,
};
+enum cedrus_h264_pic_type {
+ CEDRUS_H264_PIC_TYPE_FRAME = 0,
+ CEDRUS_H264_PIC_TYPE_FIELD,
+ CEDRUS_H264_PIC_TYPE_MBAFF,
+};
+
struct cedrus_control {
u32 id;
u32 elem_size;
@@ -49,6 +55,14 @@ struct cedrus_control {
unsigned char required:1;
};
+struct cedrus_h264_run {
+ const struct v4l2_ctrl_h264_decode_params *decode_params;
+ const struct v4l2_ctrl_h264_pps *pps;
+ const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix;
+ const struct v4l2_ctrl_h264_slice_params *slice_params;
+ const struct v4l2_ctrl_h264_sps *sps;
+};
+
struct cedrus_mpeg2_run {
const struct v4l2_ctrl_mpeg2_slice_params *slice_params;
const struct v4l2_ctrl_mpeg2_quantization *quantization;
@@ -59,12 +73,20 @@ struct cedrus_run {
struct vb2_v4l2_buffer *dst;
union {
+ struct cedrus_h264_run h264;
struct cedrus_mpeg2_run mpeg2;
};
};
struct cedrus_buffer {
struct v4l2_m2m_buffer m2m_buf;
+
+ union {
+ struct {
+ unsigned int position;
+ enum cedrus_h264_pic_type pic_type;
+ } h264;
+ } codec;
};
struct cedrus_ctx {
@@ -79,6 +101,19 @@ struct cedrus_ctx {
struct v4l2_ctrl **ctrls;
struct vb2_buffer *dst_bufs[VIDEO_MAX_FRAME];
+
+ union {
+ struct {
+ void *mv_col_buf;
+ dma_addr_t mv_col_buf_dma;
+ ssize_t mv_col_buf_field_size;
+ ssize_t mv_col_buf_size;
+ void *pic_info_buf;
+ dma_addr_t pic_info_buf_dma;
+ void *neighbor_info_buf;
+ dma_addr_t neighbor_info_buf_dma;
+ } h264;
+ } codec;
};
struct cedrus_dec_ops {
@@ -94,6 +129,7 @@ struct cedrus_dec_ops {
struct cedrus_variant {
unsigned int capabilities;
unsigned int quirks;
+ unsigned int mod_rate;
};
struct cedrus_dev {
@@ -121,6 +157,7 @@ struct cedrus_dev {
};
extern struct cedrus_dec_ops cedrus_dec_ops_mpeg2;
+extern struct cedrus_dec_ops cedrus_dec_ops_h264;
static inline void cedrus_write(struct cedrus_dev *dev, u32 reg, u32 val)
{
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
index 4d6d602cdde6..bdad87eb9d79 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
@@ -46,6 +46,19 @@ void cedrus_device_run(void *priv)
V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION);
break;
+ case V4L2_PIX_FMT_H264_SLICE_RAW:
+ run.h264.decode_params = cedrus_find_control_data(ctx,
+ V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS);
+ run.h264.pps = cedrus_find_control_data(ctx,
+ V4L2_CID_MPEG_VIDEO_H264_PPS);
+ run.h264.scaling_matrix = cedrus_find_control_data(ctx,
+ V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX);
+ run.h264.slice_params = cedrus_find_control_data(ctx,
+ V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS);
+ run.h264.sps = cedrus_find_control_data(ctx,
+ V4L2_CID_MPEG_VIDEO_H264_SPS);
+ break;
+
default:
break;
}
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
new file mode 100644
index 000000000000..a30bb283f69f
--- /dev/null
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
@@ -0,0 +1,576 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Cedrus VPU driver
+ *
+ * Copyright (c) 2013 Jens Kuske <jenskuske@gmail.com>
+ * Copyright (c) 2018 Bootlin
+ */
+
+#include <linux/types.h>
+
+#include <media/videobuf2-dma-contig.h>
+
+#include "cedrus.h"
+#include "cedrus_hw.h"
+#include "cedrus_regs.h"
+
+enum cedrus_h264_sram_off {
+ CEDRUS_SRAM_H264_PRED_WEIGHT_TABLE = 0x000,
+ CEDRUS_SRAM_H264_FRAMEBUFFER_LIST = 0x100,
+ CEDRUS_SRAM_H264_REF_LIST_0 = 0x190,
+ CEDRUS_SRAM_H264_REF_LIST_1 = 0x199,
+ CEDRUS_SRAM_H264_SCALING_LIST_8x8_0 = 0x200,
+ CEDRUS_SRAM_H264_SCALING_LIST_8x8_1 = 0x210,
+ CEDRUS_SRAM_H264_SCALING_LIST_4x4 = 0x220,
+};
+
+struct cedrus_h264_sram_ref_pic {
+ __le32 top_field_order_cnt;
+ __le32 bottom_field_order_cnt;
+ __le32 frame_info;
+ __le32 luma_ptr;
+ __le32 chroma_ptr;
+ __le32 mv_col_top_ptr;
+ __le32 mv_col_bot_ptr;
+ __le32 reserved;
+} __packed;
+
+#define CEDRUS_H264_FRAME_NUM 18
+
+#define CEDRUS_NEIGHBOR_INFO_BUF_SIZE (16 * SZ_1K)
+#define CEDRUS_PIC_INFO_BUF_SIZE (128 * SZ_1K)
+
+static void cedrus_h264_write_sram(struct cedrus_dev *dev,
+ enum cedrus_h264_sram_off off,
+ const void *data, size_t len)
+{
+ const u32 *buffer = data;
+ size_t count = DIV_ROUND_UP(len, 4);
+
+ cedrus_write(dev, VE_AVC_SRAM_PORT_OFFSET, off << 2);
+
+ while (count--)
+ cedrus_write(dev, VE_AVC_SRAM_PORT_DATA, *buffer++);
+}
+
+static dma_addr_t cedrus_h264_mv_col_buf_addr(struct cedrus_ctx *ctx,
+ unsigned int position,
+ unsigned int field)
+{
+ dma_addr_t addr = ctx->codec.h264.mv_col_buf_dma;
+
+ /* Adjust for the position */
+ addr += position * ctx->codec.h264.mv_col_buf_field_size * 2;
+
+ /* Adjust for the field */
+ addr += field * ctx->codec.h264.mv_col_buf_field_size;
+
+ return addr;
+}
+
+static void cedrus_fill_ref_pic(struct cedrus_ctx *ctx,
+ struct cedrus_buffer *buf,
+ unsigned int top_field_order_cnt,
+ unsigned int bottom_field_order_cnt,
+ struct cedrus_h264_sram_ref_pic *pic)
+{
+ struct vb2_buffer *vbuf = &buf->m2m_buf.vb.vb2_buf;
+ unsigned int position = buf->codec.h264.position;
+
+ pic->top_field_order_cnt = cpu_to_le32(top_field_order_cnt);
+ pic->bottom_field_order_cnt = cpu_to_le32(bottom_field_order_cnt);
+ pic->frame_info = cpu_to_le32(buf->codec.h264.pic_type << 8);
+
+ pic->luma_ptr = cpu_to_le32(cedrus_buf_addr(vbuf, &ctx->dst_fmt, 0));
+ pic->chroma_ptr = cpu_to_le32(cedrus_buf_addr(vbuf, &ctx->dst_fmt, 1));
+ pic->mv_col_top_ptr =
+ cpu_to_le32(cedrus_h264_mv_col_buf_addr(ctx, position, 0));
+ pic->mv_col_bot_ptr =
+ cpu_to_le32(cedrus_h264_mv_col_buf_addr(ctx, position, 1));
+}
+
+static void cedrus_write_frame_list(struct cedrus_ctx *ctx,
+ struct cedrus_run *run)
+{
+ struct cedrus_h264_sram_ref_pic pic_list[CEDRUS_H264_FRAME_NUM];
+ const struct v4l2_ctrl_h264_decode_params *decode = run->h264.decode_params;
+ const struct v4l2_ctrl_h264_slice_params *slice = run->h264.slice_params;
+ const struct v4l2_ctrl_h264_sps *sps = run->h264.sps;
+ struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q;
+ struct cedrus_buffer *output_buf;
+ struct cedrus_dev *dev = ctx->dev;
+ unsigned long used_dpbs = 0;
+ unsigned int position;
+ unsigned int output = 0;
+ unsigned int i;
+
+ memset(pic_list, 0, sizeof(pic_list));
+
+ for (i = 0; i < ARRAY_SIZE(decode->dpb); i++) {
+ const struct v4l2_h264_dpb_entry *dpb = &decode->dpb[i];
+ struct cedrus_buffer *cedrus_buf;
+ int buf_idx;
+
+ if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_VALID))
+ continue;
+
+ buf_idx = vb2_find_timestamp(cap_q, dpb->reference_ts, 0);
+ if (buf_idx < 0)
+ continue;
+
+ cedrus_buf = vb2_to_cedrus_buffer(ctx->dst_bufs[buf_idx]);
+ position = cedrus_buf->codec.h264.position;
+ used_dpbs |= BIT(position);
+
+ if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
+ continue;
+
+ cedrus_fill_ref_pic(ctx, cedrus_buf,
+ dpb->top_field_order_cnt,
+ dpb->bottom_field_order_cnt,
+ &pic_list[position]);
+
+ output = max(position, output);
+ }
+
+ position = find_next_zero_bit(&used_dpbs, CEDRUS_H264_FRAME_NUM,
+ output);
+ if (position >= CEDRUS_H264_FRAME_NUM)
+ position = find_first_zero_bit(&used_dpbs, CEDRUS_H264_FRAME_NUM);
+
+ output_buf = vb2_to_cedrus_buffer(&run->dst->vb2_buf);
+ output_buf->codec.h264.position = position;
+
+ if (slice->flags & V4L2_H264_SLICE_FLAG_FIELD_PIC)
+ output_buf->codec.h264.pic_type = CEDRUS_H264_PIC_TYPE_FIELD;
+ else if (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD)
+ output_buf->codec.h264.pic_type = CEDRUS_H264_PIC_TYPE_MBAFF;
+ else
+ output_buf->codec.h264.pic_type = CEDRUS_H264_PIC_TYPE_FRAME;
+
+ cedrus_fill_ref_pic(ctx, output_buf,
+ decode->top_field_order_cnt,
+ decode->bottom_field_order_cnt,
+ &pic_list[position]);
+
+ cedrus_h264_write_sram(dev, CEDRUS_SRAM_H264_FRAMEBUFFER_LIST,
+ pic_list, sizeof(pic_list));
+
+ cedrus_write(dev, VE_H264_OUTPUT_FRAME_IDX, position);
+}
+
+#define CEDRUS_MAX_REF_IDX 32
+
+static void _cedrus_write_ref_list(struct cedrus_ctx *ctx,
+ struct cedrus_run *run,
+ const u8 *ref_list, u8 num_ref,
+ enum cedrus_h264_sram_off sram)
+{
+ const struct v4l2_ctrl_h264_decode_params *decode = run->h264.decode_params;
+ struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q;
+ struct cedrus_dev *dev = ctx->dev;
+ u8 sram_array[CEDRUS_MAX_REF_IDX];
+ unsigned int i;
+ size_t size;
+
+ memset(sram_array, 0, sizeof(sram_array));
+
+ for (i = 0; i < num_ref; i++) {
+ const struct v4l2_h264_dpb_entry *dpb;
+ const struct cedrus_buffer *cedrus_buf;
+ const struct vb2_v4l2_buffer *ref_buf;
+ unsigned int position;
+ int buf_idx;
+ u8 dpb_idx;
+
+ dpb_idx = ref_list[i];
+ dpb = &decode->dpb[dpb_idx];
+
+ if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
+ continue;
+
+ buf_idx = vb2_find_timestamp(cap_q, dpb->reference_ts, 0);
+ if (buf_idx < 0)
+ continue;
+
+ ref_buf = to_vb2_v4l2_buffer(ctx->dst_bufs[buf_idx]);
+ cedrus_buf = vb2_v4l2_to_cedrus_buffer(ref_buf);
+ position = cedrus_buf->codec.h264.position;
+
+ sram_array[i] |= position << 1;
+ if (ref_buf->field == V4L2_FIELD_BOTTOM)
+ sram_array[i] |= BIT(0);
+ }
+
+ size = min_t(size_t, ALIGN(num_ref, 4), sizeof(sram_array));
+ cedrus_h264_write_sram(dev, sram, &sram_array, size);
+}
+
+static void cedrus_write_ref_list0(struct cedrus_ctx *ctx,
+ struct cedrus_run *run)
+{
+ const struct v4l2_ctrl_h264_slice_params *slice = run->h264.slice_params;
+
+ _cedrus_write_ref_list(ctx, run,
+ slice->ref_pic_list0,
+ slice->num_ref_idx_l0_active_minus1 + 1,
+ CEDRUS_SRAM_H264_REF_LIST_0);
+}
+
+static void cedrus_write_ref_list1(struct cedrus_ctx *ctx,
+ struct cedrus_run *run)
+{
+ const struct v4l2_ctrl_h264_slice_params *slice = run->h264.slice_params;
+
+ _cedrus_write_ref_list(ctx, run,
+ slice->ref_pic_list1,
+ slice->num_ref_idx_l1_active_minus1 + 1,
+ CEDRUS_SRAM_H264_REF_LIST_1);
+}
+
+static void cedrus_write_scaling_lists(struct cedrus_ctx *ctx,
+ struct cedrus_run *run)
+{
+ const struct v4l2_ctrl_h264_scaling_matrix *scaling =
+ run->h264.scaling_matrix;
+ struct cedrus_dev *dev = ctx->dev;
+
+ cedrus_h264_write_sram(dev, CEDRUS_SRAM_H264_SCALING_LIST_8x8_0,
+ scaling->scaling_list_8x8[0],
+ sizeof(scaling->scaling_list_8x8[0]));
+
+ cedrus_h264_write_sram(dev, CEDRUS_SRAM_H264_SCALING_LIST_8x8_1,
+ scaling->scaling_list_8x8[3],
+ sizeof(scaling->scaling_list_8x8[3]));
+
+ cedrus_h264_write_sram(dev, CEDRUS_SRAM_H264_SCALING_LIST_4x4,
+ scaling->scaling_list_4x4,
+ sizeof(scaling->scaling_list_4x4));
+}
+
+static void cedrus_write_pred_weight_table(struct cedrus_ctx *ctx,
+ struct cedrus_run *run)
+{
+ const struct v4l2_ctrl_h264_slice_params *slice =
+ run->h264.slice_params;
+ const struct v4l2_h264_pred_weight_table *pred_weight =
+ &slice->pred_weight_table;
+ struct cedrus_dev *dev = ctx->dev;
+ int i, j, k;
+
+ cedrus_write(dev, VE_H264_SHS_WP,
+ ((pred_weight->chroma_log2_weight_denom & 0x7) << 4) |
+ ((pred_weight->luma_log2_weight_denom & 0x7) << 0));
+
+ cedrus_write(dev, VE_AVC_SRAM_PORT_OFFSET,
+ CEDRUS_SRAM_H264_PRED_WEIGHT_TABLE << 2);
+
+ for (i = 0; i < ARRAY_SIZE(pred_weight->weight_factors); i++) {
+ const struct v4l2_h264_weight_factors *factors =
+ &pred_weight->weight_factors[i];
+
+ for (j = 0; j < ARRAY_SIZE(factors->luma_weight); j++) {
+ u32 val;
+
+ val = (((u32)factors->luma_offset[j] & 0x1ff) << 16) |
+ (factors->luma_weight[j] & 0x1ff);
+ cedrus_write(dev, VE_AVC_SRAM_PORT_DATA, val);
+ }
+
+ for (j = 0; j < ARRAY_SIZE(factors->chroma_weight); j++) {
+ for (k = 0; k < ARRAY_SIZE(factors->chroma_weight[0]); k++) {
+ u32 val;
+
+ val = (((u32)factors->chroma_offset[j][k] & 0x1ff) << 16) |
+ (factors->chroma_weight[j][k] & 0x1ff);
+ cedrus_write(dev, VE_AVC_SRAM_PORT_DATA, val);
+ }
+ }
+ }
+}
+
+static void cedrus_set_params(struct cedrus_ctx *ctx,
+ struct cedrus_run *run)
+{
+ const struct v4l2_ctrl_h264_decode_params *decode = run->h264.decode_params;
+ const struct v4l2_ctrl_h264_slice_params *slice = run->h264.slice_params;
+ const struct v4l2_ctrl_h264_pps *pps = run->h264.pps;
+ const struct v4l2_ctrl_h264_sps *sps = run->h264.sps;
+ struct vb2_buffer *src_buf = &run->src->vb2_buf;
+ struct cedrus_dev *dev = ctx->dev;
+ dma_addr_t src_buf_addr;
+ u32 offset = slice->header_bit_size;
+ u32 len = (slice->size * 8) - offset;
+ u32 reg;
+
+ cedrus_write(dev, VE_H264_VLD_LEN, len);
+ cedrus_write(dev, VE_H264_VLD_OFFSET, offset);
+
+ src_buf_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+ cedrus_write(dev, VE_H264_VLD_END,
+ src_buf_addr + vb2_get_plane_payload(src_buf, 0));
+ cedrus_write(dev, VE_H264_VLD_ADDR,
+ VE_H264_VLD_ADDR_VAL(src_buf_addr) |
+ VE_H264_VLD_ADDR_FIRST | VE_H264_VLD_ADDR_VALID |
+ VE_H264_VLD_ADDR_LAST);
+
+ /*
+ * FIXME: Since the bitstream parsing is done in software, and
+ * in userspace, this shouldn't be needed anymore. But it
+ * turns out that removing it breaks the decoding process,
+ * without any clear indication why.
+ */
+ cedrus_write(dev, VE_H264_TRIGGER_TYPE,
+ VE_H264_TRIGGER_TYPE_INIT_SWDEC);
+
+ if (((pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED) &&
+ (slice->slice_type == V4L2_H264_SLICE_TYPE_P ||
+ slice->slice_type == V4L2_H264_SLICE_TYPE_SP)) ||
+ (pps->weighted_bipred_idc == 1 &&
+ slice->slice_type == V4L2_H264_SLICE_TYPE_B))
+ cedrus_write_pred_weight_table(ctx, run);
+
+ if ((slice->slice_type == V4L2_H264_SLICE_TYPE_P) ||
+ (slice->slice_type == V4L2_H264_SLICE_TYPE_SP) ||
+ (slice->slice_type == V4L2_H264_SLICE_TYPE_B))
+ cedrus_write_ref_list0(ctx, run);
+
+ if (slice->slice_type == V4L2_H264_SLICE_TYPE_B)
+ cedrus_write_ref_list1(ctx, run);
+
+ // picture parameters
+ reg = 0;
+ /*
+ * FIXME: the kernel headers are allowing the default value to
+ * be passed, but the libva doesn't give us that.
+ */
+ reg |= (slice->num_ref_idx_l0_active_minus1 & 0x1f) << 10;
+ reg |= (slice->num_ref_idx_l1_active_minus1 & 0x1f) << 5;
+ reg |= (pps->weighted_bipred_idc & 0x3) << 2;
+ if (pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE)
+ reg |= VE_H264_PPS_ENTROPY_CODING_MODE;
+ if (pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED)
+ reg |= VE_H264_PPS_WEIGHTED_PRED;
+ if (pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED)
+ reg |= VE_H264_PPS_CONSTRAINED_INTRA_PRED;
+ if (pps->flags & V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE)
+ reg |= VE_H264_PPS_TRANSFORM_8X8_MODE;
+ cedrus_write(dev, VE_H264_PPS, reg);
+
+ // sequence parameters
+ reg = 0;
+ reg |= (sps->chroma_format_idc & 0x7) << 19;
+ reg |= (sps->pic_width_in_mbs_minus1 & 0xff) << 8;
+ reg |= sps->pic_height_in_map_units_minus1 & 0xff;
+ if (sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY)
+ reg |= VE_H264_SPS_MBS_ONLY;
+ if (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD)
+ reg |= VE_H264_SPS_MB_ADAPTIVE_FRAME_FIELD;
+ if (sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE)
+ reg |= VE_H264_SPS_DIRECT_8X8_INFERENCE;
+ cedrus_write(dev, VE_H264_SPS, reg);
+
+ // slice parameters
+ reg = 0;
+ reg |= decode->nal_ref_idc ? BIT(12) : 0;
+ reg |= (slice->slice_type & 0xf) << 8;
+ reg |= slice->cabac_init_idc & 0x3;
+ reg |= VE_H264_SHS_FIRST_SLICE_IN_PIC;
+ if (slice->flags & V4L2_H264_SLICE_FLAG_FIELD_PIC)
+ reg |= VE_H264_SHS_FIELD_PIC;
+ if (slice->flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD)
+ reg |= VE_H264_SHS_BOTTOM_FIELD;
+ if (slice->flags & V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED)
+ reg |= VE_H264_SHS_DIRECT_SPATIAL_MV_PRED;
+ cedrus_write(dev, VE_H264_SHS, reg);
+
+ reg = 0;
+ reg |= VE_H264_SHS2_NUM_REF_IDX_ACTIVE_OVRD;
+ reg |= (slice->num_ref_idx_l0_active_minus1 & 0x1f) << 24;
+ reg |= (slice->num_ref_idx_l1_active_minus1 & 0x1f) << 16;
+ reg |= (slice->disable_deblocking_filter_idc & 0x3) << 8;
+ reg |= (slice->slice_alpha_c0_offset_div2 & 0xf) << 4;
+ reg |= slice->slice_beta_offset_div2 & 0xf;
+ cedrus_write(dev, VE_H264_SHS2, reg);
+
+ reg = 0;
+ reg |= (pps->second_chroma_qp_index_offset & 0x3f) << 16;
+ reg |= (pps->chroma_qp_index_offset & 0x3f) << 8;
+ reg |= (pps->pic_init_qp_minus26 + 26 + slice->slice_qp_delta) & 0x3f;
+ cedrus_write(dev, VE_H264_SHS_QP, reg);
+
+ // clear status flags
+ cedrus_write(dev, VE_H264_STATUS, cedrus_read(dev, VE_H264_STATUS));
+
+ // enable int
+ cedrus_write(dev, VE_H264_CTRL,
+ VE_H264_CTRL_SLICE_DECODE_INT |
+ VE_H264_CTRL_DECODE_ERR_INT |
+ VE_H264_CTRL_VLD_DATA_REQ_INT);
+}
+
+static enum cedrus_irq_status
+cedrus_h264_irq_status(struct cedrus_ctx *ctx)
+{
+ struct cedrus_dev *dev = ctx->dev;
+ u32 reg = cedrus_read(dev, VE_H264_STATUS);
+
+ if (reg & (VE_H264_STATUS_DECODE_ERR_INT |
+ VE_H264_STATUS_VLD_DATA_REQ_INT))
+ return CEDRUS_IRQ_ERROR;
+
+ if (reg & VE_H264_CTRL_SLICE_DECODE_INT)
+ return CEDRUS_IRQ_OK;
+
+ return CEDRUS_IRQ_NONE;
+}
+
+static void cedrus_h264_irq_clear(struct cedrus_ctx *ctx)
+{
+ struct cedrus_dev *dev = ctx->dev;
+
+ cedrus_write(dev, VE_H264_STATUS,
+ VE_H264_STATUS_INT_MASK);
+}
+
+static void cedrus_h264_irq_disable(struct cedrus_ctx *ctx)
+{
+ struct cedrus_dev *dev = ctx->dev;
+ u32 reg = cedrus_read(dev, VE_H264_CTRL);
+
+ cedrus_write(dev, VE_H264_CTRL,
+ reg & ~VE_H264_CTRL_INT_MASK);
+}
+
+static void cedrus_h264_setup(struct cedrus_ctx *ctx,
+ struct cedrus_run *run)
+{
+ struct cedrus_dev *dev = ctx->dev;
+
+ cedrus_engine_enable(dev, CEDRUS_CODEC_H264);
+
+ cedrus_write(dev, VE_H264_SDROT_CTRL, 0);
+ cedrus_write(dev, VE_H264_EXTRA_BUFFER1,
+ ctx->codec.h264.pic_info_buf_dma);
+ cedrus_write(dev, VE_H264_EXTRA_BUFFER2,
+ ctx->codec.h264.neighbor_info_buf_dma);
+
+ cedrus_write_scaling_lists(ctx, run);
+ cedrus_write_frame_list(ctx, run);
+
+ cedrus_set_params(ctx, run);
+}
+
+static int cedrus_h264_start(struct cedrus_ctx *ctx)
+{
+ struct cedrus_dev *dev = ctx->dev;
+ unsigned int field_size;
+ unsigned int mv_col_size;
+ int ret;
+
+ /*
+ * FIXME: It seems that the H6 cedarX code is using a formula
+ * here based on the size of the frame, while all the older
+ * code is using a fixed size, so that might need to be
+ * changed at some point.
+ */
+ ctx->codec.h264.pic_info_buf =
+ dma_alloc_coherent(dev->dev, CEDRUS_PIC_INFO_BUF_SIZE,
+ &ctx->codec.h264.pic_info_buf_dma,
+ GFP_KERNEL);
+ if (!ctx->codec.h264.pic_info_buf)
+ return -ENOMEM;
+
+ /*
+ * That buffer is supposed to be 16kiB in size, and be aligned
+ * on 16kiB as well. However, dma_alloc_coherent provides the
+ * guarantee that we'll have a CPU and DMA address aligned on
+ * the smallest page order that is greater to the requested
+ * size, so we don't have to overallocate.
+ */
+ ctx->codec.h264.neighbor_info_buf =
+ dma_alloc_coherent(dev->dev, CEDRUS_NEIGHBOR_INFO_BUF_SIZE,
+ &ctx->codec.h264.neighbor_info_buf_dma,
+ GFP_KERNEL);
+ if (!ctx->codec.h264.neighbor_info_buf) {
+ ret = -ENOMEM;
+ goto err_pic_buf;
+ }
+
+ field_size = DIV_ROUND_UP(ctx->src_fmt.width, 16) *
+ DIV_ROUND_UP(ctx->src_fmt.height, 16) * 16;
+
+ /*
+ * FIXME: This is actually conditional to
+ * V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE not being set, we
+ * might have to rework this if memory efficiency ever is
+ * something we need to work on.
+ */
+ field_size = field_size * 2;
+
+ /*
+ * FIXME: This is actually conditional to
+ * V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY not being set, we might
+ * have to rework this if memory efficiency ever is something
+ * we need to work on.
+ */
+ field_size = field_size * 2;
+ ctx->codec.h264.mv_col_buf_field_size = field_size;
+
+ mv_col_size = field_size * 2 * CEDRUS_H264_FRAME_NUM;
+ ctx->codec.h264.mv_col_buf_size = mv_col_size;
+ ctx->codec.h264.mv_col_buf = dma_alloc_coherent(dev->dev,
+ ctx->codec.h264.mv_col_buf_size,
+ &ctx->codec.h264.mv_col_buf_dma,
+ GFP_KERNEL);
+ if (!ctx->codec.h264.mv_col_buf) {
+ ret = -ENOMEM;
+ goto err_neighbor_buf;
+ }
+
+ return 0;
+
+err_neighbor_buf:
+ dma_free_coherent(dev->dev, CEDRUS_NEIGHBOR_INFO_BUF_SIZE,
+ ctx->codec.h264.neighbor_info_buf,
+ ctx->codec.h264.neighbor_info_buf_dma);
+
+err_pic_buf:
+ dma_free_coherent(dev->dev, CEDRUS_PIC_INFO_BUF_SIZE,
+ ctx->codec.h264.pic_info_buf,
+ ctx->codec.h264.pic_info_buf_dma);
+ return ret;
+}
+
+static void cedrus_h264_stop(struct cedrus_ctx *ctx)
+{
+ struct cedrus_dev *dev = ctx->dev;
+
+ dma_free_coherent(dev->dev, ctx->codec.h264.mv_col_buf_size,
+ ctx->codec.h264.mv_col_buf,
+ ctx->codec.h264.mv_col_buf_dma);
+ dma_free_coherent(dev->dev, CEDRUS_NEIGHBOR_INFO_BUF_SIZE,
+ ctx->codec.h264.neighbor_info_buf,
+ ctx->codec.h264.neighbor_info_buf_dma);
+ dma_free_coherent(dev->dev, CEDRUS_PIC_INFO_BUF_SIZE,
+ ctx->codec.h264.pic_info_buf,
+ ctx->codec.h264.pic_info_buf_dma);
+}
+
+static void cedrus_h264_trigger(struct cedrus_ctx *ctx)
+{
+ struct cedrus_dev *dev = ctx->dev;
+
+ cedrus_write(dev, VE_H264_TRIGGER_TYPE,
+ VE_H264_TRIGGER_TYPE_AVC_SLICE_DECODE);
+}
+
+struct cedrus_dec_ops cedrus_dec_ops_h264 = {
+ .irq_clear = cedrus_h264_irq_clear,
+ .irq_disable = cedrus_h264_irq_disable,
+ .irq_status = cedrus_h264_irq_status,
+ .setup = cedrus_h264_setup,
+ .start = cedrus_h264_start,
+ .stop = cedrus_h264_stop,
+ .trigger = cedrus_h264_trigger,
+};
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
index fbfff7c1c771..c34aec7c6e40 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
@@ -46,6 +46,10 @@ int cedrus_engine_enable(struct cedrus_dev *dev, enum cedrus_codec codec)
reg |= VE_MODE_DEC_MPEG;
break;
+ case CEDRUS_CODEC_H264:
+ reg |= VE_MODE_DEC_H264;
+ break;
+
default:
return -EINVAL;
}
@@ -236,7 +240,7 @@ int cedrus_hw_probe(struct cedrus_dev *dev)
goto err_sram;
}
- ret = clk_set_rate(dev->mod_clk, CEDRUS_CLOCK_RATE_DEFAULT);
+ ret = clk_set_rate(dev->mod_clk, variant->mod_rate);
if (ret) {
dev_err(dev->dev, "Failed to set clock rate\n");
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.h b/drivers/staging/media/sunxi/cedrus/cedrus_hw.h
index b43c77d54b95..27d0882397aa 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.h
@@ -16,8 +16,6 @@
#ifndef _CEDRUS_HW_H_
#define _CEDRUS_HW_H_
-#define CEDRUS_CLOCK_RATE_DEFAULT 320000000
-
int cedrus_engine_enable(struct cedrus_dev *dev, enum cedrus_codec codec);
void cedrus_engine_disable(struct cedrus_dev *dev);
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
index de2d6b6f64bf..3e9931416e45 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
@@ -232,4 +232,95 @@
#define VE_DEC_MPEG_ROT_LUMA (VE_ENGINE_DEC_MPEG + 0xcc)
#define VE_DEC_MPEG_ROT_CHROMA (VE_ENGINE_DEC_MPEG + 0xd0)
+#define VE_H264_SPS 0x200
+#define VE_H264_SPS_MBS_ONLY BIT(18)
+#define VE_H264_SPS_MB_ADAPTIVE_FRAME_FIELD BIT(17)
+#define VE_H264_SPS_DIRECT_8X8_INFERENCE BIT(16)
+
+#define VE_H264_PPS 0x204
+#define VE_H264_PPS_ENTROPY_CODING_MODE BIT(15)
+#define VE_H264_PPS_WEIGHTED_PRED BIT(4)
+#define VE_H264_PPS_CONSTRAINED_INTRA_PRED BIT(1)
+#define VE_H264_PPS_TRANSFORM_8X8_MODE BIT(0)
+
+#define VE_H264_SHS 0x208
+#define VE_H264_SHS_FIRST_SLICE_IN_PIC BIT(5)
+#define VE_H264_SHS_FIELD_PIC BIT(4)
+#define VE_H264_SHS_BOTTOM_FIELD BIT(3)
+#define VE_H264_SHS_DIRECT_SPATIAL_MV_PRED BIT(2)
+
+#define VE_H264_SHS2 0x20c
+#define VE_H264_SHS2_NUM_REF_IDX_ACTIVE_OVRD BIT(12)
+
+#define VE_H264_SHS_WP 0x210
+
+#define VE_H264_SHS_QP 0x21c
+#define VE_H264_SHS_QP_SCALING_MATRIX_DEFAULT BIT(24)
+
+#define VE_H264_CTRL 0x220
+#define VE_H264_CTRL_VLD_DATA_REQ_INT BIT(2)
+#define VE_H264_CTRL_DECODE_ERR_INT BIT(1)
+#define VE_H264_CTRL_SLICE_DECODE_INT BIT(0)
+
+#define VE_H264_CTRL_INT_MASK (VE_H264_CTRL_VLD_DATA_REQ_INT | \
+ VE_H264_CTRL_DECODE_ERR_INT | \
+ VE_H264_CTRL_SLICE_DECODE_INT)
+
+#define VE_H264_TRIGGER_TYPE 0x224
+#define VE_H264_TRIGGER_TYPE_AVC_SLICE_DECODE (8 << 0)
+#define VE_H264_TRIGGER_TYPE_INIT_SWDEC (7 << 0)
+
+#define VE_H264_STATUS 0x228
+#define VE_H264_STATUS_VLD_DATA_REQ_INT VE_H264_CTRL_VLD_DATA_REQ_INT
+#define VE_H264_STATUS_DECODE_ERR_INT VE_H264_CTRL_DECODE_ERR_INT
+#define VE_H264_STATUS_SLICE_DECODE_INT VE_H264_CTRL_SLICE_DECODE_INT
+
+#define VE_H264_STATUS_INT_MASK VE_H264_CTRL_INT_MASK
+
+#define VE_H264_CUR_MB_NUM 0x22c
+
+#define VE_H264_VLD_ADDR 0x230
+#define VE_H264_VLD_ADDR_FIRST BIT(30)
+#define VE_H264_VLD_ADDR_LAST BIT(29)
+#define VE_H264_VLD_ADDR_VALID BIT(28)
+#define VE_H264_VLD_ADDR_VAL(x) (((x) & 0x0ffffff0) | ((x) >> 28))
+
+#define VE_H264_VLD_OFFSET 0x234
+#define VE_H264_VLD_LEN 0x238
+#define VE_H264_VLD_END 0x23c
+#define VE_H264_SDROT_CTRL 0x240
+#define VE_H264_OUTPUT_FRAME_IDX 0x24c
+#define VE_H264_EXTRA_BUFFER1 0x250
+#define VE_H264_EXTRA_BUFFER2 0x254
+#define VE_H264_BASIC_BITS 0x2dc
+#define VE_AVC_SRAM_PORT_OFFSET 0x2e0
+#define VE_AVC_SRAM_PORT_DATA 0x2e4
+
+#define VE_ISP_INPUT_SIZE 0xa00
+#define VE_ISP_INPUT_STRIDE 0xa04
+#define VE_ISP_CTRL 0xa08
+#define VE_ISP_INPUT_LUMA 0xa78
+#define VE_ISP_INPUT_CHROMA 0xa7c
+
+#define VE_AVC_PARAM 0xb04
+#define VE_AVC_QP 0xb08
+#define VE_AVC_MOTION_EST 0xb10
+#define VE_AVC_CTRL 0xb14
+#define VE_AVC_TRIGGER 0xb18
+#define VE_AVC_STATUS 0xb1c
+#define VE_AVC_BASIC_BITS 0xb20
+#define VE_AVC_UNK_BUF 0xb60
+#define VE_AVC_VLE_ADDR 0xb80
+#define VE_AVC_VLE_END 0xb84
+#define VE_AVC_VLE_OFFSET 0xb88
+#define VE_AVC_VLE_MAX 0xb8c
+#define VE_AVC_VLE_LENGTH 0xb90
+#define VE_AVC_REF_LUMA 0xba0
+#define VE_AVC_REF_CHROMA 0xba4
+#define VE_AVC_REC_LUMA 0xbb0
+#define VE_AVC_REC_CHROMA 0xbb4
+#define VE_AVC_REF_SLUMA 0xbb8
+#define VE_AVC_REC_SLUMA 0xbbc
+#define VE_AVC_MB_INFO 0xbc0
+
#endif
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
index 9673874ece10..e2b530b1a956 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
@@ -38,6 +38,10 @@ static struct cedrus_format cedrus_formats[] = {
.directions = CEDRUS_DECODE_SRC,
},
{
+ .pixelformat = V4L2_PIX_FMT_H264_SLICE_RAW,
+ .directions = CEDRUS_DECODE_SRC,
+ },
+ {
.pixelformat = V4L2_PIX_FMT_SUNXI_TILED_NV12,
.directions = CEDRUS_DECODE_DST,
},
@@ -100,6 +104,7 @@ static void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt)
switch (pix_fmt->pixelformat) {
case V4L2_PIX_FMT_MPEG2_SLICE:
+ case V4L2_PIX_FMT_H264_SLICE_RAW:
/* Zero bytes per line for encoded source. */
bytesperline = 0;
@@ -464,6 +469,10 @@ static int cedrus_start_streaming(struct vb2_queue *vq, unsigned int count)
ctx->current_codec = CEDRUS_CODEC_MPEG2;
break;
+ case V4L2_PIX_FMT_H264_SLICE_RAW:
+ ctx->current_codec = CEDRUS_CODEC_H264;
+ break;
+
default:
return -EINVAL;
}
diff --git a/drivers/staging/media/tegra-vde/Kconfig b/drivers/staging/media/tegra-vde/Kconfig
index ff8e846cd15d..2e7f644ae591 100644
--- a/drivers/staging/media/tegra-vde/Kconfig
+++ b/drivers/staging/media/tegra-vde/Kconfig
@@ -3,6 +3,7 @@ config TEGRA_VDE
tristate "NVIDIA Tegra Video Decoder Engine driver"
depends on ARCH_TEGRA || COMPILE_TEST
select DMA_SHARED_BUFFER
+ select IOMMU_IOVA if IOMMU_SUPPORT
select SRAM
help
Say Y here to enable support for the NVIDIA Tegra video decoder
diff --git a/drivers/staging/media/tegra-vde/Makefile b/drivers/staging/media/tegra-vde/Makefile
index 7f9020e634f3..2827f7601de8 100644
--- a/drivers/staging/media/tegra-vde/Makefile
+++ b/drivers/staging/media/tegra-vde/Makefile
@@ -1,2 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
+tegra-vde-y := vde.o iommu.o dmabuf-cache.o
obj-$(CONFIG_TEGRA_VDE) += tegra-vde.o
diff --git a/drivers/staging/media/tegra-vde/dmabuf-cache.c b/drivers/staging/media/tegra-vde/dmabuf-cache.c
new file mode 100644
index 000000000000..a93b317885bf
--- /dev/null
+++ b/drivers/staging/media/tegra-vde/dmabuf-cache.c
@@ -0,0 +1,226 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * NVIDIA Tegra Video decoder driver
+ *
+ * Copyright (C) 2016-2019 GRATE-DRIVER project
+ */
+
+#include <linux/dma-buf.h>
+#include <linux/iova.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+
+#include "vde.h"
+
+struct tegra_vde_cache_entry {
+ enum dma_data_direction dma_dir;
+ struct dma_buf_attachment *a;
+ struct delayed_work dwork;
+ struct tegra_vde *vde;
+ struct list_head list;
+ struct sg_table *sgt;
+ struct iova *iova;
+ unsigned int refcnt;
+};
+
+static void tegra_vde_release_entry(struct tegra_vde_cache_entry *entry)
+{
+ struct dma_buf *dmabuf = entry->a->dmabuf;
+
+ WARN_ON_ONCE(entry->refcnt);
+
+ if (entry->vde->domain)
+ tegra_vde_iommu_unmap(entry->vde, entry->iova);
+
+ dma_buf_unmap_attachment(entry->a, entry->sgt, entry->dma_dir);
+ dma_buf_detach(dmabuf, entry->a);
+ dma_buf_put(dmabuf);
+
+ list_del(&entry->list);
+ kfree(entry);
+}
+
+static void tegra_vde_delayed_unmap(struct work_struct *work)
+{
+ struct tegra_vde_cache_entry *entry;
+ struct tegra_vde *vde;
+
+ entry = container_of(work, struct tegra_vde_cache_entry,
+ dwork.work);
+ vde = entry->vde;
+
+ mutex_lock(&vde->map_lock);
+ tegra_vde_release_entry(entry);
+ mutex_unlock(&vde->map_lock);
+}
+
+int tegra_vde_dmabuf_cache_map(struct tegra_vde *vde,
+ struct dma_buf *dmabuf,
+ enum dma_data_direction dma_dir,
+ struct dma_buf_attachment **ap,
+ dma_addr_t *addrp)
+{
+ struct device *dev = vde->miscdev.parent;
+ struct dma_buf_attachment *attachment;
+ struct tegra_vde_cache_entry *entry;
+ struct sg_table *sgt;
+ struct iova *iova;
+ int err;
+
+ mutex_lock(&vde->map_lock);
+
+ list_for_each_entry(entry, &vde->map_list, list) {
+ if (entry->a->dmabuf != dmabuf)
+ continue;
+
+ if (!cancel_delayed_work(&entry->dwork))
+ continue;
+
+ if (entry->dma_dir != dma_dir)
+ entry->dma_dir = DMA_BIDIRECTIONAL;
+
+ dma_buf_put(dmabuf);
+
+ if (vde->domain)
+ *addrp = iova_dma_addr(&vde->iova, entry->iova);
+ else
+ *addrp = sg_dma_address(entry->sgt->sgl);
+
+ goto ref;
+ }
+
+ attachment = dma_buf_attach(dmabuf, dev);
+ if (IS_ERR(attachment)) {
+ dev_err(dev, "Failed to attach dmabuf\n");
+ err = PTR_ERR(attachment);
+ goto err_unlock;
+ }
+
+ sgt = dma_buf_map_attachment(attachment, dma_dir);
+ if (IS_ERR(sgt)) {
+ dev_err(dev, "Failed to get dmabufs sg_table\n");
+ err = PTR_ERR(sgt);
+ goto err_detach;
+ }
+
+ if (!vde->domain && sgt->nents > 1) {
+ dev_err(dev, "Sparse DMA region is unsupported, please enable IOMMU\n");
+ err = -EINVAL;
+ goto err_unmap;
+ }
+
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry) {
+ err = -ENOMEM;
+ goto err_unmap;
+ }
+
+ if (vde->domain) {
+ err = tegra_vde_iommu_map(vde, sgt, &iova, dmabuf->size);
+ if (err)
+ goto err_free;
+
+ *addrp = iova_dma_addr(&vde->iova, iova);
+ } else {
+ *addrp = sg_dma_address(sgt->sgl);
+ iova = NULL;
+ }
+
+ INIT_DELAYED_WORK(&entry->dwork, tegra_vde_delayed_unmap);
+ list_add(&entry->list, &vde->map_list);
+
+ entry->dma_dir = dma_dir;
+ entry->iova = iova;
+ entry->vde = vde;
+ entry->sgt = sgt;
+ entry->a = attachment;
+ref:
+ entry->refcnt++;
+
+ *ap = entry->a;
+
+ mutex_unlock(&vde->map_lock);
+
+ return 0;
+
+err_free:
+ kfree(entry);
+err_unmap:
+ dma_buf_unmap_attachment(attachment, sgt, dma_dir);
+err_detach:
+ dma_buf_detach(dmabuf, attachment);
+err_unlock:
+ mutex_unlock(&vde->map_lock);
+
+ return err;
+}
+
+void tegra_vde_dmabuf_cache_unmap(struct tegra_vde *vde,
+ struct dma_buf_attachment *a,
+ bool release)
+{
+ struct tegra_vde_cache_entry *entry;
+
+ mutex_lock(&vde->map_lock);
+
+ list_for_each_entry(entry, &vde->map_list, list) {
+ if (entry->a != a)
+ continue;
+
+ WARN_ON_ONCE(!entry->refcnt);
+
+ if (--entry->refcnt == 0) {
+ if (release)
+ tegra_vde_release_entry(entry);
+ else
+ schedule_delayed_work(&entry->dwork, 5 * HZ);
+ }
+ break;
+ }
+
+ mutex_unlock(&vde->map_lock);
+}
+
+void tegra_vde_dmabuf_cache_unmap_sync(struct tegra_vde *vde)
+{
+ struct tegra_vde_cache_entry *entry, *tmp;
+
+ mutex_lock(&vde->map_lock);
+
+ list_for_each_entry_safe(entry, tmp, &vde->map_list, list) {
+ if (entry->refcnt)
+ continue;
+
+ if (!cancel_delayed_work(&entry->dwork))
+ continue;
+
+ tegra_vde_release_entry(entry);
+ }
+
+ mutex_unlock(&vde->map_lock);
+}
+
+void tegra_vde_dmabuf_cache_unmap_all(struct tegra_vde *vde)
+{
+ struct tegra_vde_cache_entry *entry, *tmp;
+
+ mutex_lock(&vde->map_lock);
+
+ while (!list_empty(&vde->map_list)) {
+ list_for_each_entry_safe(entry, tmp, &vde->map_list, list) {
+ if (!cancel_delayed_work(&entry->dwork))
+ continue;
+
+ tegra_vde_release_entry(entry);
+ }
+
+ mutex_unlock(&vde->map_lock);
+ schedule();
+ mutex_lock(&vde->map_lock);
+ }
+
+ mutex_unlock(&vde->map_lock);
+}
diff --git a/drivers/staging/media/tegra-vde/iommu.c b/drivers/staging/media/tegra-vde/iommu.c
new file mode 100644
index 000000000000..6af863d92123
--- /dev/null
+++ b/drivers/staging/media/tegra-vde/iommu.c
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * NVIDIA Tegra Video decoder driver
+ *
+ * Copyright (C) 2016-2019 GRATE-DRIVER project
+ */
+
+#include <linux/iommu.h>
+#include <linux/iova.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)
+#include <asm/dma-iommu.h>
+#endif
+
+#include "vde.h"
+
+int tegra_vde_iommu_map(struct tegra_vde *vde,
+ struct sg_table *sgt,
+ struct iova **iovap,
+ size_t size)
+{
+ struct iova *iova;
+ unsigned long shift;
+ unsigned long end;
+ dma_addr_t addr;
+
+ end = vde->domain->geometry.aperture_end;
+ size = iova_align(&vde->iova, size);
+ shift = iova_shift(&vde->iova);
+
+ iova = alloc_iova(&vde->iova, size >> shift, end >> shift, true);
+ if (!iova)
+ return -ENOMEM;
+
+ addr = iova_dma_addr(&vde->iova, iova);
+
+ size = iommu_map_sg(vde->domain, addr, sgt->sgl, sgt->nents,
+ IOMMU_READ | IOMMU_WRITE);
+ if (!size) {
+ __free_iova(&vde->iova, iova);
+ return -ENXIO;
+ }
+
+ *iovap = iova;
+
+ return 0;
+}
+
+void tegra_vde_iommu_unmap(struct tegra_vde *vde, struct iova *iova)
+{
+ unsigned long shift = iova_shift(&vde->iova);
+ unsigned long size = iova_size(iova) << shift;
+ dma_addr_t addr = iova_dma_addr(&vde->iova, iova);
+
+ iommu_unmap(vde->domain, addr, size);
+ __free_iova(&vde->iova, iova);
+}
+
+int tegra_vde_iommu_init(struct tegra_vde *vde)
+{
+ struct device *dev = vde->miscdev.parent;
+ struct iova *iova;
+ unsigned long order;
+ unsigned long shift;
+ int err;
+
+ vde->group = iommu_group_get(dev);
+ if (!vde->group)
+ return 0;
+
+#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)
+ if (dev->archdata.mapping) {
+ struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
+
+ arm_iommu_detach_device(dev);
+ arm_iommu_release_mapping(mapping);
+ }
+#endif
+ vde->domain = iommu_domain_alloc(&platform_bus_type);
+ if (!vde->domain) {
+ err = -ENOMEM;
+ goto put_group;
+ }
+
+ err = iova_cache_get();
+ if (err)
+ goto free_domain;
+
+ order = __ffs(vde->domain->pgsize_bitmap);
+ init_iova_domain(&vde->iova, 1UL << order, 0);
+
+ err = iommu_attach_group(vde->domain, vde->group);
+ if (err)
+ goto put_iova;
+
+ /*
+ * We're using some static addresses that are not accessible by VDE
+ * to trap invalid memory accesses.
+ */
+ shift = iova_shift(&vde->iova);
+ iova = reserve_iova(&vde->iova, 0x60000000 >> shift,
+ 0x70000000 >> shift);
+ if (!iova) {
+ err = -ENOMEM;
+ goto detach_group;
+ }
+
+ vde->iova_resv_static_addresses = iova;
+
+ /*
+ * BSEV's end-address wraps around due to integer overflow during
+ * of hardware context preparation if IOVA is allocated at the end
+ * of address space and VDE can't handle that. Hence simply reserve
+ * the last page to avoid the problem.
+ */
+ iova = reserve_iova(&vde->iova, 0xffffffff >> shift,
+ (0xffffffff >> shift) + 1);
+ if (!iova) {
+ err = -ENOMEM;
+ goto unreserve_iova;
+ }
+
+ vde->iova_resv_last_page = iova;
+
+ return 0;
+
+unreserve_iova:
+ __free_iova(&vde->iova, vde->iova_resv_static_addresses);
+detach_group:
+ iommu_detach_group(vde->domain, vde->group);
+put_iova:
+ put_iova_domain(&vde->iova);
+ iova_cache_put();
+free_domain:
+ iommu_domain_free(vde->domain);
+put_group:
+ iommu_group_put(vde->group);
+
+ return err;
+}
+
+void tegra_vde_iommu_deinit(struct tegra_vde *vde)
+{
+ if (vde->domain) {
+ __free_iova(&vde->iova, vde->iova_resv_last_page);
+ __free_iova(&vde->iova, vde->iova_resv_static_addresses);
+ iommu_detach_group(vde->domain, vde->group);
+ put_iova_domain(&vde->iova);
+ iova_cache_put();
+ iommu_domain_free(vde->domain);
+ iommu_group_put(vde->group);
+
+ vde->domain = NULL;
+ }
+}
diff --git a/drivers/staging/media/tegra-vde/trace.h b/drivers/staging/media/tegra-vde/trace.h
index 85e2f7e2d4d0..e5714107db58 100644
--- a/drivers/staging/media/tegra-vde/trace.h
+++ b/drivers/staging/media/tegra-vde/trace.h
@@ -8,6 +8,8 @@
#include <linux/tracepoint.h>
+#include "vde.h"
+
DECLARE_EVENT_CLASS(register_access,
TP_PROTO(struct tegra_vde *vde, void __iomem *base,
u32 offset, u32 value),
diff --git a/drivers/staging/media/tegra-vde/uapi.h b/drivers/staging/media/tegra-vde/uapi.h
index a0dad1ed94ef..ffb4983e5bb6 100644
--- a/drivers/staging/media/tegra-vde/uapi.h
+++ b/drivers/staging/media/tegra-vde/uapi.h
@@ -6,8 +6,8 @@
#include <linux/types.h>
#include <asm/ioctl.h>
-#define FLAG_B_FRAME BIT(0)
-#define FLAG_REFERENCE BIT(1)
+#define FLAG_B_FRAME 0x1
+#define FLAG_REFERENCE 0x2
struct tegra_vde_h264_frame {
__s32 y_fd;
@@ -21,40 +21,42 @@ struct tegra_vde_h264_frame {
__u32 frame_num;
__u32 flags;
- __u32 reserved;
-} __attribute__((packed));
+ // Must be zero'ed
+ __u32 reserved[6];
+};
struct tegra_vde_h264_decoder_ctx {
__s32 bitstream_data_fd;
__u32 bitstream_data_offset;
__u64 dpb_frames_ptr;
- __u8 dpb_frames_nb;
- __u8 dpb_ref_frames_with_earlier_poc_nb;
+ __u32 dpb_frames_nb;
+ __u32 dpb_ref_frames_with_earlier_poc_nb;
// SPS
- __u8 baseline_profile;
- __u8 level_idc;
- __u8 log2_max_pic_order_cnt_lsb;
- __u8 log2_max_frame_num;
- __u8 pic_order_cnt_type;
- __u8 direct_8x8_inference_flag;
- __u8 pic_width_in_mbs;
- __u8 pic_height_in_mbs;
+ __u32 baseline_profile;
+ __u32 level_idc;
+ __u32 log2_max_pic_order_cnt_lsb;
+ __u32 log2_max_frame_num;
+ __u32 pic_order_cnt_type;
+ __u32 direct_8x8_inference_flag;
+ __u32 pic_width_in_mbs;
+ __u32 pic_height_in_mbs;
// PPS
- __u8 pic_init_qp;
- __u8 deblocking_filter_control_present_flag;
- __u8 constrained_intra_pred_flag;
- __u8 chroma_qp_index_offset;
- __u8 pic_order_present_flag;
+ __u32 pic_init_qp;
+ __u32 deblocking_filter_control_present_flag;
+ __u32 constrained_intra_pred_flag;
+ __u32 chroma_qp_index_offset;
+ __u32 pic_order_present_flag;
// Slice header
- __u8 num_ref_idx_l0_active_minus1;
- __u8 num_ref_idx_l1_active_minus1;
+ __u32 num_ref_idx_l0_active_minus1;
+ __u32 num_ref_idx_l1_active_minus1;
- __u32 reserved;
-} __attribute__((packed));
+ // Must be zero'ed
+ __u32 reserved[11];
+};
#define VDE_IOCTL_BASE ('v' + 0x20)
diff --git a/drivers/staging/media/tegra-vde/tegra-vde.c b/drivers/staging/media/tegra-vde/vde.c
index a5020dbf6eef..3466daddf663 100644
--- a/drivers/staging/media/tegra-vde/tegra-vde.c
+++ b/drivers/staging/media/tegra-vde/vde.c
@@ -11,6 +11,7 @@
#include <linux/genalloc.h>
#include <linux/interrupt.h>
#include <linux/iopoll.h>
+#include <linux/list.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/of_device.h>
@@ -22,6 +23,10 @@
#include <soc/tegra/pmc.h>
#include "uapi.h"
+#include "vde.h"
+
+#define CREATE_TRACE_POINTS
+#include "trace.h"
#define ICMDQUE_WR 0x00
#define CMDQUE_CONTROL 0x08
@@ -37,10 +42,6 @@ struct video_frame {
struct dma_buf_attachment *cb_dmabuf_attachment;
struct dma_buf_attachment *cr_dmabuf_attachment;
struct dma_buf_attachment *aux_dmabuf_attachment;
- struct sg_table *y_sgt;
- struct sg_table *cb_sgt;
- struct sg_table *cr_sgt;
- struct sg_table *aux_sgt;
dma_addr_t y_addr;
dma_addr_t cb_addr;
dma_addr_t cr_addr;
@@ -49,63 +50,6 @@ struct video_frame {
u32 flags;
};
-struct tegra_vde {
- void __iomem *sxe;
- void __iomem *bsev;
- void __iomem *mbe;
- void __iomem *ppe;
- void __iomem *mce;
- void __iomem *tfe;
- void __iomem *ppb;
- void __iomem *vdma;
- void __iomem *frameid;
- struct mutex lock;
- struct miscdevice miscdev;
- struct reset_control *rst;
- struct reset_control *rst_mc;
- struct gen_pool *iram_pool;
- struct completion decode_completion;
- struct clk *clk;
- dma_addr_t iram_lists_addr;
- u32 *iram;
-};
-
-static __maybe_unused char const *
-tegra_vde_reg_base_name(struct tegra_vde *vde, void __iomem *base)
-{
- if (vde->sxe == base)
- return "SXE";
-
- if (vde->bsev == base)
- return "BSEV";
-
- if (vde->mbe == base)
- return "MBE";
-
- if (vde->ppe == base)
- return "PPE";
-
- if (vde->mce == base)
- return "MCE";
-
- if (vde->tfe == base)
- return "TFE";
-
- if (vde->ppb == base)
- return "PPB";
-
- if (vde->vdma == base)
- return "VDMA";
-
- if (vde->frameid == base)
- return "FRAMEID";
-
- return "???";
-}
-
-#define CREATE_TRACE_POINTS
-#include "trace.h"
-
static void tegra_vde_writel(struct tegra_vde *vde,
u32 value, void __iomem *base, u32 offset)
{
@@ -543,31 +487,18 @@ static void tegra_vde_decode_frame(struct tegra_vde *vde,
vde->sxe, 0x00);
}
-static void tegra_vde_detach_and_put_dmabuf(struct dma_buf_attachment *a,
- struct sg_table *sgt,
- enum dma_data_direction dma_dir)
-{
- struct dma_buf *dmabuf = a->dmabuf;
-
- dma_buf_unmap_attachment(a, sgt, dma_dir);
- dma_buf_detach(dmabuf, a);
- dma_buf_put(dmabuf);
-}
-
-static int tegra_vde_attach_dmabuf(struct device *dev,
+static int tegra_vde_attach_dmabuf(struct tegra_vde *vde,
int fd,
unsigned long offset,
size_t min_size,
size_t align_size,
struct dma_buf_attachment **a,
- dma_addr_t *addr,
- struct sg_table **s,
+ dma_addr_t *addrp,
size_t *size,
enum dma_data_direction dma_dir)
{
- struct dma_buf_attachment *attachment;
+ struct device *dev = vde->miscdev.parent;
struct dma_buf *dmabuf;
- struct sg_table *sgt;
int err;
dmabuf = dma_buf_get(fd);
@@ -588,46 +519,24 @@ static int tegra_vde_attach_dmabuf(struct device *dev,
return -EINVAL;
}
- attachment = dma_buf_attach(dmabuf, dev);
- if (IS_ERR(attachment)) {
- dev_err(dev, "Failed to attach dmabuf\n");
- err = PTR_ERR(attachment);
+ err = tegra_vde_dmabuf_cache_map(vde, dmabuf, dma_dir, a, addrp);
+ if (err)
goto err_put;
- }
- sgt = dma_buf_map_attachment(attachment, dma_dir);
- if (IS_ERR(sgt)) {
- dev_err(dev, "Failed to get dmabufs sg_table\n");
- err = PTR_ERR(sgt);
- goto err_detach;
- }
-
- if (sgt->nents != 1) {
- dev_err(dev, "Sparse DMA region is unsupported\n");
- err = -EINVAL;
- goto err_unmap;
- }
-
- *addr = sg_dma_address(sgt->sgl) + offset;
- *a = attachment;
- *s = sgt;
+ *addrp = *addrp + offset;
if (size)
*size = dmabuf->size - offset;
return 0;
-err_unmap:
- dma_buf_unmap_attachment(attachment, sgt, dma_dir);
-err_detach:
- dma_buf_detach(dmabuf, attachment);
err_put:
dma_buf_put(dmabuf);
return err;
}
-static int tegra_vde_attach_dmabufs_to_frame(struct device *dev,
+static int tegra_vde_attach_dmabufs_to_frame(struct tegra_vde *vde,
struct video_frame *frame,
struct tegra_vde_h264_frame *src,
enum dma_data_direction dma_dir,
@@ -636,29 +545,26 @@ static int tegra_vde_attach_dmabufs_to_frame(struct device *dev,
{
int err;
- err = tegra_vde_attach_dmabuf(dev, src->y_fd,
+ err = tegra_vde_attach_dmabuf(vde, src->y_fd,
src->y_offset, lsize, SZ_256,
&frame->y_dmabuf_attachment,
&frame->y_addr,
- &frame->y_sgt,
NULL, dma_dir);
if (err)
return err;
- err = tegra_vde_attach_dmabuf(dev, src->cb_fd,
+ err = tegra_vde_attach_dmabuf(vde, src->cb_fd,
src->cb_offset, csize, SZ_256,
&frame->cb_dmabuf_attachment,
&frame->cb_addr,
- &frame->cb_sgt,
NULL, dma_dir);
if (err)
goto err_release_y;
- err = tegra_vde_attach_dmabuf(dev, src->cr_fd,
+ err = tegra_vde_attach_dmabuf(vde, src->cr_fd,
src->cr_offset, csize, SZ_256,
&frame->cr_dmabuf_attachment,
&frame->cr_addr,
- &frame->cr_sgt,
NULL, dma_dir);
if (err)
goto err_release_cb;
@@ -668,11 +574,10 @@ static int tegra_vde_attach_dmabufs_to_frame(struct device *dev,
return 0;
}
- err = tegra_vde_attach_dmabuf(dev, src->aux_fd,
+ err = tegra_vde_attach_dmabuf(vde, src->aux_fd,
src->aux_offset, csize, SZ_256,
&frame->aux_dmabuf_attachment,
&frame->aux_addr,
- &frame->aux_sgt,
NULL, dma_dir);
if (err)
goto err_release_cr;
@@ -680,34 +585,28 @@ static int tegra_vde_attach_dmabufs_to_frame(struct device *dev,
return 0;
err_release_cr:
- tegra_vde_detach_and_put_dmabuf(frame->cr_dmabuf_attachment,
- frame->cr_sgt, dma_dir);
+ tegra_vde_dmabuf_cache_unmap(vde, frame->cr_dmabuf_attachment, true);
err_release_cb:
- tegra_vde_detach_and_put_dmabuf(frame->cb_dmabuf_attachment,
- frame->cb_sgt, dma_dir);
+ tegra_vde_dmabuf_cache_unmap(vde, frame->cb_dmabuf_attachment, true);
err_release_y:
- tegra_vde_detach_and_put_dmabuf(frame->y_dmabuf_attachment,
- frame->y_sgt, dma_dir);
+ tegra_vde_dmabuf_cache_unmap(vde, frame->y_dmabuf_attachment, true);
return err;
}
-static void tegra_vde_release_frame_dmabufs(struct video_frame *frame,
+static void tegra_vde_release_frame_dmabufs(struct tegra_vde *vde,
+ struct video_frame *frame,
enum dma_data_direction dma_dir,
- bool baseline_profile)
+ bool baseline_profile,
+ bool release)
{
if (!baseline_profile)
- tegra_vde_detach_and_put_dmabuf(frame->aux_dmabuf_attachment,
- frame->aux_sgt, dma_dir);
+ tegra_vde_dmabuf_cache_unmap(vde, frame->aux_dmabuf_attachment,
+ release);
- tegra_vde_detach_and_put_dmabuf(frame->cr_dmabuf_attachment,
- frame->cr_sgt, dma_dir);
-
- tegra_vde_detach_and_put_dmabuf(frame->cb_dmabuf_attachment,
- frame->cb_sgt, dma_dir);
-
- tegra_vde_detach_and_put_dmabuf(frame->y_dmabuf_attachment,
- frame->y_sgt, dma_dir);
+ tegra_vde_dmabuf_cache_unmap(vde, frame->cr_dmabuf_attachment, release);
+ tegra_vde_dmabuf_cache_unmap(vde, frame->cb_dmabuf_attachment, release);
+ tegra_vde_dmabuf_cache_unmap(vde, frame->y_dmabuf_attachment, release);
}
static int tegra_vde_validate_frame(struct device *dev,
@@ -795,11 +694,10 @@ static int tegra_vde_ioctl_decode_h264(struct tegra_vde *vde,
{
struct device *dev = vde->miscdev.parent;
struct tegra_vde_h264_decoder_ctx ctx;
- struct tegra_vde_h264_frame frames[17];
+ struct tegra_vde_h264_frame *frames;
struct tegra_vde_h264_frame __user *frames_user;
struct video_frame *dpb_frames;
struct dma_buf_attachment *bitstream_data_dmabuf_attachment;
- struct sg_table *bitstream_sgt;
enum dma_data_direction dma_dir;
dma_addr_t bitstream_data_addr;
dma_addr_t bsev_ptr;
@@ -819,22 +717,27 @@ static int tegra_vde_ioctl_decode_h264(struct tegra_vde *vde,
if (ret)
return ret;
- ret = tegra_vde_attach_dmabuf(dev, ctx.bitstream_data_fd,
+ ret = tegra_vde_attach_dmabuf(vde, ctx.bitstream_data_fd,
ctx.bitstream_data_offset,
SZ_16K, SZ_16K,
&bitstream_data_dmabuf_attachment,
&bitstream_data_addr,
- &bitstream_sgt,
&bitstream_data_size,
DMA_TO_DEVICE);
if (ret)
return ret;
+ frames = kmalloc_array(ctx.dpb_frames_nb, sizeof(*frames), GFP_KERNEL);
+ if (!frames) {
+ ret = -ENOMEM;
+ goto release_bitstream_dmabuf;
+ }
+
dpb_frames = kcalloc(ctx.dpb_frames_nb, sizeof(*dpb_frames),
GFP_KERNEL);
if (!dpb_frames) {
ret = -ENOMEM;
- goto release_bitstream_dmabuf;
+ goto free_frames;
}
macroblocks_nb = ctx.pic_width_in_mbs * ctx.pic_height_in_mbs;
@@ -860,7 +763,7 @@ static int tegra_vde_ioctl_decode_h264(struct tegra_vde *vde,
dma_dir = (i == 0) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
- ret = tegra_vde_attach_dmabufs_to_frame(dev, &dpb_frames[i],
+ ret = tegra_vde_attach_dmabufs_to_frame(vde, &dpb_frames[i],
&frames[i], dma_dir,
ctx.baseline_profile,
lsize, csize);
@@ -948,16 +851,19 @@ release_dpb_frames:
while (i--) {
dma_dir = (i == 0) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
- tegra_vde_release_frame_dmabufs(&dpb_frames[i], dma_dir,
- ctx.baseline_profile);
+ tegra_vde_release_frame_dmabufs(vde, &dpb_frames[i], dma_dir,
+ ctx.baseline_profile, ret != 0);
}
free_dpb_frames:
kfree(dpb_frames);
+free_frames:
+ kfree(frames);
+
release_bitstream_dmabuf:
- tegra_vde_detach_and_put_dmabuf(bitstream_data_dmabuf_attachment,
- bitstream_sgt, DMA_TO_DEVICE);
+ tegra_vde_dmabuf_cache_unmap(vde, bitstream_data_dmabuf_attachment,
+ ret != 0);
return ret;
}
@@ -979,9 +885,21 @@ static long tegra_vde_unlocked_ioctl(struct file *filp,
return -ENOTTY;
}
+static int tegra_vde_release_file(struct inode *inode, struct file *filp)
+{
+ struct miscdevice *miscdev = filp->private_data;
+ struct tegra_vde *vde = container_of(miscdev, struct tegra_vde,
+ miscdev);
+
+ tegra_vde_dmabuf_cache_unmap_sync(vde);
+
+ return 0;
+}
+
static const struct file_operations tegra_vde_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = tegra_vde_unlocked_ioctl,
+ .release = tegra_vde_release_file,
};
static irqreturn_t tegra_vde_isr(int irq, void *data)
@@ -1159,6 +1077,8 @@ static int tegra_vde_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ INIT_LIST_HEAD(&vde->map_list);
+ mutex_init(&vde->map_lock);
mutex_init(&vde->lock);
init_completion(&vde->decode_completion);
@@ -1167,10 +1087,16 @@ static int tegra_vde_probe(struct platform_device *pdev)
vde->miscdev.fops = &tegra_vde_fops;
vde->miscdev.parent = dev;
+ err = tegra_vde_iommu_init(vde);
+ if (err) {
+ dev_err(dev, "Failed to initialize IOMMU: %d\n", err);
+ goto err_gen_free;
+ }
+
err = misc_register(&vde->miscdev);
if (err) {
dev_err(dev, "Failed to register misc device: %d\n", err);
- goto err_gen_free;
+ goto err_deinit_iommu;
}
pm_runtime_enable(dev);
@@ -1188,6 +1114,9 @@ static int tegra_vde_probe(struct platform_device *pdev)
err_misc_unreg:
misc_deregister(&vde->miscdev);
+err_deinit_iommu:
+ tegra_vde_iommu_deinit(vde);
+
err_gen_free:
gen_pool_free(vde->iram_pool, (unsigned long)vde->iram,
gen_pool_size(vde->iram_pool));
@@ -1212,6 +1141,9 @@ static int tegra_vde_remove(struct platform_device *pdev)
misc_deregister(&vde->miscdev);
+ tegra_vde_dmabuf_cache_unmap_all(vde);
+ tegra_vde_iommu_deinit(vde);
+
gen_pool_free(vde->iram_pool, (unsigned long)vde->iram,
gen_pool_size(vde->iram_pool));
diff --git a/drivers/staging/media/tegra-vde/vde.h b/drivers/staging/media/tegra-vde/vde.h
new file mode 100644
index 000000000000..d369f1466bc7
--- /dev/null
+++ b/drivers/staging/media/tegra-vde/vde.h
@@ -0,0 +1,107 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * NVIDIA Tegra Video decoder driver
+ *
+ * Copyright (C) 2016-2019 GRATE-DRIVER project
+ */
+
+#ifndef TEGRA_VDE_H
+#define TEGRA_VDE_H
+
+#include <linux/completion.h>
+#include <linux/dma-direction.h>
+#include <linux/list.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/iova.h>
+
+struct clk;
+struct dma_buf;
+struct gen_pool;
+struct iommu_group;
+struct iommu_domain;
+struct reset_control;
+struct dma_buf_attachment;
+
+struct tegra_vde {
+ void __iomem *sxe;
+ void __iomem *bsev;
+ void __iomem *mbe;
+ void __iomem *ppe;
+ void __iomem *mce;
+ void __iomem *tfe;
+ void __iomem *ppb;
+ void __iomem *vdma;
+ void __iomem *frameid;
+ struct mutex lock;
+ struct mutex map_lock;
+ struct list_head map_list;
+ struct miscdevice miscdev;
+ struct reset_control *rst;
+ struct reset_control *rst_mc;
+ struct gen_pool *iram_pool;
+ struct completion decode_completion;
+ struct clk *clk;
+ struct iommu_domain *domain;
+ struct iommu_group *group;
+ struct iova_domain iova;
+ struct iova *iova_resv_static_addresses;
+ struct iova *iova_resv_last_page;
+ dma_addr_t iram_lists_addr;
+ u32 *iram;
+};
+
+int tegra_vde_iommu_init(struct tegra_vde *vde);
+void tegra_vde_iommu_deinit(struct tegra_vde *vde);
+int tegra_vde_iommu_map(struct tegra_vde *vde,
+ struct sg_table *sgt,
+ struct iova **iovap,
+ size_t size);
+void tegra_vde_iommu_unmap(struct tegra_vde *vde, struct iova *iova);
+
+int tegra_vde_dmabuf_cache_map(struct tegra_vde *vde,
+ struct dma_buf *dmabuf,
+ enum dma_data_direction dma_dir,
+ struct dma_buf_attachment **ap,
+ dma_addr_t *addrp);
+void tegra_vde_dmabuf_cache_unmap(struct tegra_vde *vde,
+ struct dma_buf_attachment *a,
+ bool release);
+void tegra_vde_dmabuf_cache_unmap_sync(struct tegra_vde *vde);
+void tegra_vde_dmabuf_cache_unmap_all(struct tegra_vde *vde);
+
+static __maybe_unused char const *
+tegra_vde_reg_base_name(struct tegra_vde *vde, void __iomem *base)
+{
+ if (vde->sxe == base)
+ return "SXE";
+
+ if (vde->bsev == base)
+ return "BSEV";
+
+ if (vde->mbe == base)
+ return "MBE";
+
+ if (vde->ppe == base)
+ return "PPE";
+
+ if (vde->mce == base)
+ return "MCE";
+
+ if (vde->tfe == base)
+ return "TFE";
+
+ if (vde->ppb == base)
+ return "PPB";
+
+ if (vde->vdma == base)
+ return "VDMA";
+
+ if (vde->frameid == base)
+ return "FRAMEID";
+
+ return "???";
+}
+
+#endif /* TEGRA_VDE_H */
diff --git a/drivers/staging/most/Documentation/ABI/configfs-most.txt b/drivers/staging/most/Documentation/ABI/configfs-most.txt
index 25b3e18c4d91..2bf811449b0b 100644
--- a/drivers/staging/most/Documentation/ABI/configfs-most.txt
+++ b/drivers/staging/most/Documentation/ABI/configfs-most.txt
@@ -31,13 +31,13 @@ Description:
or output
dbr_size configure DBR data buffer size (this is used
- for MediaLB communiction only)
+ for MediaLB communication only)
packets_per_xact
configure the number of packets that will be
collected from the network before being
transmitted via USB (this is used for USB
- communiction only)
+ communication only)
device name of the device the link is to be attached to
@@ -75,13 +75,13 @@ Description:
or output
dbr_size configure DBR data buffer size (this is used
- for MediaLB communiction only)
+ for MediaLB communication only)
packets_per_xact
configure the number of packets that will be
collected from the network before being
transmitted via USB (this is used for USB
- communiction only)
+ communication only)
device name of the device the link is to be attached to
@@ -119,13 +119,13 @@ Description:
or output
dbr_size configure DBR data buffer size (this is used
- for MediaLB communiction only)
+ for MediaLB communication only)
packets_per_xact
configure the number of packets that will be
collected from the network before being
transmitted via USB (this is used for USB
- communiction only)
+ communication only)
device name of the device the link is to be attached to
@@ -173,13 +173,13 @@ Description:
or output
dbr_size configure DBR data buffer size (this is used
- for MediaLB communiction only)
+ for MediaLB communication only)
packets_per_xact
configure the number of packets that will be
collected from the network before being
transmitted via USB (this is used for USB
- communiction only)
+ communication only)
device name of the device the link is to be attached to
diff --git a/drivers/staging/most/Documentation/driver_usage.txt b/drivers/staging/most/Documentation/driver_usage.txt
index 56d79195bb3c..2fa8dea1da4d 100644
--- a/drivers/staging/most/Documentation/driver_usage.txt
+++ b/drivers/staging/most/Documentation/driver_usage.txt
@@ -42,7 +42,7 @@ the attached network interface controller hardware. Hence, a given module
of this layer is designed to handle exactly one of the peripheral
interfaces (e.g. USB, MediaLB, I2C) the hardware provides.
-A module of the application layer is referred to as a core comoponent,
+A module of the application layer is referred to as a core component,
which kind of extends the core by providing connectivity to the user space.
Applications, then, can access a MOST network via character devices, an
ALSA soundcard, a Network adapter or a V4L2 capture device.
@@ -119,7 +119,7 @@ following components are available
The driver is to be configured via configfs. Each loaded component kernel
object (see section 1.3) registers a subsystem with configfs, which is used to
-configure and establish communiction pathways (links) to attached devices on
+configure and establish communication pathways (links) to attached devices on
the bus. To do so, the user has to descend into the component's configuration
directory and create a new directory (child config itmes). The name of this
directory will be used as a reference for the link and it will contain the
@@ -137,12 +137,12 @@ following attributes:
- direction
configure whether this link will be an input or output
- dbr_size
- configure DBR data buffer size (this is used for MediaLB communiction
+ configure DBR data buffer size (this is used for MediaLB communication
only)
- packets_per_xact
configure the number of packets that will be collected from the
network before being transmitted via USB (this is used for USB
- communiction only)
+ communication only)
- device
name of the device the link is to be attached to
- channel
diff --git a/drivers/staging/most/Kconfig b/drivers/staging/most/Kconfig
index db32ea7d1743..8948d5246409 100644
--- a/drivers/staging/most/Kconfig
+++ b/drivers/staging/most/Kconfig
@@ -3,7 +3,7 @@ menuconfig MOST
tristate "MOST support"
depends on HAS_DMA && CONFIGFS_FS
default n
- ---help---
+ help
Say Y here if you want to enable MOST support.
This driver needs at least one additional component to enable the
desired access from userspace (e.g. character devices) and one that
diff --git a/drivers/staging/most/configfs.c b/drivers/staging/most/configfs.c
index 1d8bf29e0ffb..025495657b68 100644
--- a/drivers/staging/most/configfs.c
+++ b/drivers/staging/most/configfs.c
@@ -35,56 +35,42 @@ static struct list_head mdev_link_list;
static int set_cfg_buffer_size(struct mdev_link *link)
{
- if (!link->buffer_size)
- return -ENODATA;
return most_set_cfg_buffer_size(link->device, link->channel,
link->buffer_size);
}
static int set_cfg_subbuffer_size(struct mdev_link *link)
{
- if (!link->subbuffer_size)
- return -ENODATA;
return most_set_cfg_subbuffer_size(link->device, link->channel,
link->subbuffer_size);
}
static int set_cfg_dbr_size(struct mdev_link *link)
{
- if (!link->dbr_size)
- return -ENODATA;
return most_set_cfg_dbr_size(link->device, link->channel,
link->dbr_size);
}
static int set_cfg_num_buffers(struct mdev_link *link)
{
- if (!link->num_buffers)
- return -ENODATA;
return most_set_cfg_num_buffers(link->device, link->channel,
link->num_buffers);
}
static int set_cfg_packets_xact(struct mdev_link *link)
{
- if (!link->packets_per_xact)
- return -ENODATA;
return most_set_cfg_packets_xact(link->device, link->channel,
link->packets_per_xact);
}
static int set_cfg_direction(struct mdev_link *link)
{
- if (!strlen(link->direction))
- return -ENODATA;
return most_set_cfg_direction(link->device, link->channel,
link->direction);
}
static int set_cfg_datatype(struct mdev_link *link)
{
- if (!strlen(link->datatype))
- return -ENODATA;
return most_set_cfg_datatype(link->device, link->channel,
link->datatype);
}
diff --git a/drivers/staging/most/core.c b/drivers/staging/most/core.c
index 86a8545c8d97..b9841adb7181 100644
--- a/drivers/staging/most/core.c
+++ b/drivers/staging/most/core.c
@@ -561,13 +561,6 @@ static int split_string(char *buf, char **a, char **b, char **c, char **d)
return 0;
}
-static int match_bus_dev(struct device *dev, void *data)
-{
- char *mdev_name = data;
-
- return !strcmp(dev_name(dev), mdev_name);
-}
-
/**
* get_channel - get pointer to channel
* @mdev: name of the device interface
@@ -579,7 +572,7 @@ static struct most_channel *get_channel(char *mdev, char *mdev_ch)
struct most_interface *iface;
struct most_channel *c, *tmp;
- dev = bus_find_device(&mc.bus, NULL, mdev, match_bus_dev);
+ dev = bus_find_device_by_name(&mc.bus, NULL, mdev);
if (!dev)
return NULL;
iface = to_most_interface(dev);
diff --git a/drivers/staging/most/net/net.c b/drivers/staging/most/net/net.c
index c8a64e209027..aababdf2be12 100644
--- a/drivers/staging/most/net/net.c
+++ b/drivers/staging/most/net/net.c
@@ -507,13 +507,24 @@ static struct core_component comp = {
static int __init most_net_init(void)
{
+ int err;
+
spin_lock_init(&list_lock);
mutex_init(&probe_disc_mt);
- return most_register_component(&comp);
+ err = most_register_component(&comp);
+ if (err)
+ return err;
+ err = most_register_configfs_subsys(&comp);
+ if (err) {
+ most_deregister_component(&comp);
+ return err;
+ }
+ return 0;
}
static void __exit most_net_exit(void)
{
+ most_deregister_configfs_subsys(&comp);
most_deregister_component(&comp);
}
diff --git a/drivers/staging/most/video/video.c b/drivers/staging/most/video/video.c
index adca250062e1..6f6e98ab0550 100644
--- a/drivers/staging/most/video/video.c
+++ b/drivers/staging/most/video/video.c
@@ -250,11 +250,6 @@ static int vidioc_querycap(struct file *file, void *priv,
strlcpy(cap->card, "MOST", sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info),
"%s", mdev->iface->description);
-
- cap->capabilities =
- V4L2_CAP_READWRITE |
- V4L2_CAP_TUNER |
- V4L2_CAP_VIDEO_CAPTURE;
return 0;
}
@@ -366,6 +361,7 @@ static const struct video_device comp_videodev_template = {
.release = video_device_release,
.ioctl_ops = &video_ioctl_ops,
.tvnorms = V4L2_STD_UNKNOWN,
+ .device_caps = V4L2_CAP_READWRITE | V4L2_CAP_VIDEO_CAPTURE,
};
/**************************************************************************/
@@ -540,8 +536,18 @@ static struct core_component comp = {
static int __init comp_init(void)
{
+ int err;
+
spin_lock_init(&list_lock);
- return most_register_component(&comp);
+ err = most_register_component(&comp);
+ if (err)
+ return err;
+ err = most_register_configfs_subsys(&comp);
+ if (err) {
+ most_deregister_component(&comp);
+ return err;
+ }
+ return 0;
}
static void __exit comp_exit(void)
@@ -566,6 +572,7 @@ static void __exit comp_exit(void)
}
spin_unlock_irq(&list_lock);
+ most_deregister_configfs_subsys(&comp);
most_deregister_component(&comp);
BUG_ON(!list_empty(&video_devices));
}
diff --git a/drivers/staging/mt7621-dma/mtk-hsdma.c b/drivers/staging/mt7621-dma/mtk-hsdma.c
index 0fbb9932d6bb..60db06768c8a 100644
--- a/drivers/staging/mt7621-dma/mtk-hsdma.c
+++ b/drivers/staging/mt7621-dma/mtk-hsdma.c
@@ -468,7 +468,7 @@ static struct dma_async_tx_descriptor *mtk_hsdma_prep_dma_memcpy(
if (len <= 0)
return NULL;
- desc = kzalloc(sizeof(struct mtk_hsdma_desc), GFP_ATOMIC);
+ desc = kzalloc(sizeof(*desc), GFP_ATOMIC);
if (!desc) {
dev_err(c->device->dev, "alloc memcpy decs error\n");
return NULL;
@@ -664,9 +664,8 @@ static int mtk_hsdma_probe(struct platform_device *pdev)
return -EINVAL;
hsdma = devm_kzalloc(&pdev->dev, sizeof(*hsdma), GFP_KERNEL);
- if (!hsdma) {
+ if (!hsdma)
return -EINVAL;
- }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
diff --git a/drivers/staging/mt7621-dts/Kconfig b/drivers/staging/mt7621-dts/Kconfig
index 3ea08ab9d0d3..6932ab7acadf 100644
--- a/drivers/staging/mt7621-dts/Kconfig
+++ b/drivers/staging/mt7621-dts/Kconfig
@@ -1,6 +1,11 @@
# SPDX-License-Identifier: GPL-2.0
config DTB_GNUBEE1
- bool "GnuBee1 NAS"
+ bool "GnuBee1 2.5inch NAS"
+ depends on SOC_MT7621 && DTB_RT_NONE
+ select BUILTIN_DTB
+
+config DTB_GNUBEE2
+ bool "GnuBee2 3.5inch NAS"
depends on SOC_MT7621 && DTB_RT_NONE
select BUILTIN_DTB
diff --git a/drivers/staging/mt7621-dts/Makefile b/drivers/staging/mt7621-dts/Makefile
index aeec48a4edc7..b4ab99fed932 100644
--- a/drivers/staging/mt7621-dts/Makefile
+++ b/drivers/staging/mt7621-dts/Makefile
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
dtb-$(CONFIG_DTB_GNUBEE1) += gbpc1.dtb
+dtb-$(CONFIG_DTB_GNUBEE2) += gbpc2.dtb
obj-y += $(patsubst %.dtb, %.dtb.o, $(dtb-y))
diff --git a/drivers/staging/mt7621-dts/TODO b/drivers/staging/mt7621-dts/TODO
index 15803132c1ea..1b758e5c84e0 100644
--- a/drivers/staging/mt7621-dts/TODO
+++ b/drivers/staging/mt7621-dts/TODO
@@ -2,4 +2,4 @@
- ensure all usage matches code
- ensure all features used are documented
-Cc: NeilBrown <neil@brown.name> \ No newline at end of file
+Cc: NeilBrown <neil@brown.name>
diff --git a/drivers/staging/mt7621-dts/gbpc1.dts b/drivers/staging/mt7621-dts/gbpc1.dts
index 250c15ace2a7..1fb560ff059c 100644
--- a/drivers/staging/mt7621-dts/gbpc1.dts
+++ b/drivers/staging/mt7621-dts/gbpc1.dts
@@ -119,7 +119,7 @@
&pinctrl {
state_default: pinctrl0 {
- gpio {
+ default_gpio: gpio {
groups = "wdt", "rgmii2", "uart3";
function = "gpio";
};
diff --git a/drivers/staging/mt7621-dts/gbpc2.dts b/drivers/staging/mt7621-dts/gbpc2.dts
new file mode 100644
index 000000000000..52760e7351f6
--- /dev/null
+++ b/drivers/staging/mt7621-dts/gbpc2.dts
@@ -0,0 +1,21 @@
+/dts-v1/;
+
+#include "gbpc1.dts"
+
+/ {
+ compatible = "gnubee,gb-pc2", "mediatek,mt7621-soc";
+ model = "GB-PC2";
+};
+
+&default_gpio {
+ groups = "wdt", "uart3";
+ function = "gpio";
+};
+
+&gmac1 {
+ status = "ok";
+};
+
+&phy_external {
+ status = "ok";
+};
diff --git a/drivers/staging/mt7621-dts/mt7621.dtsi b/drivers/staging/mt7621-dts/mt7621.dtsi
index 280ec33c8540..a4c08110094b 100644
--- a/drivers/staging/mt7621-dts/mt7621.dtsi
+++ b/drivers/staging/mt7621-dts/mt7621.dtsi
@@ -1,4 +1,5 @@
#include <dt-bindings/interrupt-controller/mips-gic.h>
+#include <dt-bindings/gpio/gpio.h>
/ {
#address-cells = <1>;
@@ -42,6 +43,30 @@
clock-frequency = <220000000>;
};
+ mmc_clock: mmc_clock@0 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <48000000>;
+ };
+
+ mmc_fixed_3v3: fixedregulator@0 {
+ compatible = "regulator-fixed";
+ regulator-name = "mmc_power";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ enable-active-high;
+ regulator-always-on;
+ };
+
+ mmc_fixed_1v8_io: fixedregulator@1 {
+ compatible = "regulator-fixed";
+ regulator-name = "mmc_io";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ enable-active-high;
+ regulator-always-on;
+ };
+
palmbus: palmbus@1E000000 {
compatible = "palmbus";
reg = <0x1E000000 0x100000>;
@@ -298,9 +323,24 @@
sdhci: sdhci@1E130000 {
status = "disabled";
- compatible = "ralink,mt7620-sdhci";
+ compatible = "mediatek,mt7620-mmc";
reg = <0x1E130000 0x4000>;
+ bus-width = <4>;
+ max-frequency = <48000000>;
+ cap-sd-highspeed;
+ cap-mmc-highspeed;
+ vmmc-supply = <&mmc_fixed_3v3>;
+ vqmmc-supply = <&mmc_fixed_1v8_io>;
+ disable-wp;
+
+ pinctrl-names = "default", "state_uhs";
+ pinctrl-0 = <&sdhci_pins>;
+ pinctrl-1 = <&sdhci_pins>;
+
+ clocks = <&mmc_clock &mmc_clock>;
+ clock-names = "source", "hclk";
+
interrupt-parent = <&gic>;
interrupts = <GIC_SHARED 20 IRQ_TYPE_LEVEL_HIGH>;
};
@@ -387,16 +427,20 @@
compatible = "mediatek,eth-mac";
reg = <1>;
status = "off";
- phy-mode = "rgmii";
- phy-handle = <&phy5>;
+ phy-mode = "rgmii-rxid";
+ phy-handle = <&phy_external>;
};
mdio-bus {
#address-cells = <1>;
#size-cells = <0>;
- phy5: ethernet-phy@5 {
+ phy_external: ethernet-phy@5 {
+ status = "off";
reg = <5>;
- phy-mode = "rgmii";
+ phy-mode = "rgmii-rxid";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&rgmii2_pins>;
};
switch0: switch0@0 {
@@ -468,6 +512,7 @@
#address-cells = <3>;
#size-cells = <2>;
+ perst-gpio = <&gpio 19 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&pcie_pins>;
diff --git a/drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c b/drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c
index 2576f179e30a..d2a07f145143 100644
--- a/drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c
+++ b/drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c
@@ -16,10 +16,6 @@
#include <mt7621.h>
#include <ralink_regs.h>
-#define RALINK_CLKCFG1 0x30
-
-#define PCIE_PORT_CLK_EN(x) BIT(24 + (x))
-
#define RG_PE1_PIPE_REG 0x02c
#define RG_PE1_PIPE_RST BIT(12)
#define RG_PE1_PIPE_CMD_FRC BIT(4)
@@ -286,10 +282,6 @@ static int mt7621_pci_phy_power_off(struct phy *phy)
static int mt7621_pci_phy_exit(struct phy *phy)
{
- struct mt7621_pci_phy_instance *instance = phy_get_drvdata(phy);
-
- rt_sysc_m32(PCIE_PORT_CLK_EN(instance->index), 0, RALINK_CLKCFG1);
-
return 0;
}
diff --git a/drivers/staging/mt7621-pci/mediatek,mt7621-pci.txt b/drivers/staging/mt7621-pci/mediatek,mt7621-pci.txt
index 5a6ee4103cd5..604ec813bd45 100644
--- a/drivers/staging/mt7621-pci/mediatek,mt7621-pci.txt
+++ b/drivers/staging/mt7621-pci/mediatek,mt7621-pci.txt
@@ -6,6 +6,7 @@ Required properties:
- reg: Base addresses and lengths of the PCIe subsys and root ports.
- bus-range: Range of bus numbers associated with this controller.
- #address-cells: Address representation for root ports (must be 3)
+- perst-gpio: PCIe reset signal line.
- pinctrl-names : The pin control state names.
- pinctrl-0: The "default" pinctrl state.
- #size-cells: Size representation for root ports (must be 2)
@@ -48,6 +49,7 @@ Example for MT7621:
#address-cells = <3>;
#size-cells = <2>;
+ perst-gpio = <&gpio 19 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&pcie_pins>;
diff --git a/drivers/staging/mt7621-pci/pci-mt7621.c b/drivers/staging/mt7621-pci/pci-mt7621.c
index 03d919a94552..89fa813142ab 100644
--- a/drivers/staging/mt7621-pci/pci-mt7621.c
+++ b/drivers/staging/mt7621-pci/pci-mt7621.c
@@ -17,6 +17,7 @@
#include <linux/bitops.h>
#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -35,14 +36,16 @@
/* sysctl */
#define MT7621_CHIP_REV_ID 0x0c
+#define MT7621_GPIO_MODE 0x60
#define CHIP_REV_MT7621_E2 0x0101
/* MediaTek specific configuration registers */
#define PCIE_FTS_NUM 0x70c
#define PCIE_FTS_NUM_MASK GENMASK(15, 8)
-#define PCIE_FTS_NUM_L0(x) ((x) & 0xff << 8)
+#define PCIE_FTS_NUM_L0(x) (((x) & 0xff) << 8)
/* rt_sysc_membase relative registers */
+#define RALINK_CLKCFG1 0x30
#define RALINK_PCIE_CLK_GEN 0x7c
#define RALINK_PCIE_CLK_GEN1 0x80
@@ -81,7 +84,6 @@
#define PCIE_BAR_ENABLE BIT(0)
#define PCIE_PORT_INT_EN(x) BIT(20 + (x))
#define PCIE_PORT_CLK_EN(x) BIT(24 + (x))
-#define PCIE_PORT_PERST(x) BIT(1 + (x))
#define PCIE_PORT_LINKUP BIT(0)
#define PCIE_CLK_GEN_EN BIT(31)
@@ -89,6 +91,9 @@
#define PCIE_CLK_GEN1_DIS GENMASK(30, 24)
#define PCIE_CLK_GEN1_EN (BIT(27) | BIT(25))
#define MEMORY_BASE 0x0
+#define PERST_MODE_MASK GENMASK(11, 10)
+#define PERST_MODE_GPIO BIT(10)
+#define PERST_DELAY_US 1000
/**
* struct mt7621_pcie_port - PCIe port information
@@ -119,6 +124,7 @@ struct mt7621_pcie_port {
* @offset: IO / Memory offset
* @dev: Pointer to PCIe device
* @ports: pointer to PCIe port information
+ * @perst: gpio reset
* @rst: pointer to pcie reset
*/
struct mt7621_pcie {
@@ -132,6 +138,7 @@ struct mt7621_pcie {
resource_size_t io;
} offset;
struct list_head ports;
+ struct gpio_desc *perst;
struct reset_control *rst;
};
@@ -198,6 +205,28 @@ static void write_config(struct mt7621_pcie *pcie, unsigned int dev,
pcie_write(pcie, val, RALINK_PCI_CONFIG_DATA);
}
+static inline void mt7621_perst_gpio_pcie_assert(struct mt7621_pcie *pcie)
+{
+ gpiod_set_value(pcie->perst, 0);
+ mdelay(PERST_DELAY_US);
+}
+
+static inline void mt7621_perst_gpio_pcie_deassert(struct mt7621_pcie *pcie)
+{
+ gpiod_set_value(pcie->perst, 1);
+ mdelay(PERST_DELAY_US);
+}
+
+static inline bool mt7621_pcie_port_is_linkup(struct mt7621_pcie_port *port)
+{
+ return (pcie_port_read(port, RALINK_PCI_STATUS) & PCIE_PORT_LINKUP) != 0;
+}
+
+static inline void mt7621_pcie_port_clk_disable(struct mt7621_pcie_port *port)
+{
+ rt_sysc_m32(PCIE_PORT_CLK_EN(port->slot), 0, RALINK_CLKCFG1);
+}
+
static inline void mt7621_control_assert(struct mt7621_pcie_port *port)
{
u32 chip_rev_id = rt_sysc_r32(MT7621_CHIP_REV_ID);
@@ -344,6 +373,12 @@ static int mt7621_pcie_parse_dt(struct mt7621_pcie *pcie)
struct resource regs;
int err;
+ pcie->perst = devm_gpiod_get(dev, "perst", GPIOD_OUT_HIGH);
+ if (IS_ERR(pcie->perst)) {
+ dev_err(dev, "failed to get gpio perst\n");
+ return PTR_ERR(pcie->perst);
+ }
+
err = of_address_to_resource(node, 0, &regs);
if (err) {
dev_err(dev, "missing \"reg\" property\n");
@@ -384,7 +419,6 @@ static int mt7621_pcie_init_port(struct mt7621_pcie_port *port)
struct mt7621_pcie *pcie = port->pcie;
struct device *dev = pcie->dev;
u32 slot = port->slot;
- u32 val = 0;
int err;
/*
@@ -393,47 +427,35 @@ static int mt7621_pcie_init_port(struct mt7621_pcie_port *port)
*/
mt7621_reset_port(port);
- val = read_config(pcie, slot, PCIE_FTS_NUM);
- dev_info(dev, "Port %d N_FTS = %x\n", (unsigned int)val, slot);
-
err = phy_init(port->phy);
if (err) {
dev_err(dev, "failed to initialize port%d phy\n", slot);
- goto err_phy_init;
+ return err;
}
err = phy_power_on(port->phy);
if (err) {
dev_err(dev, "failed to power on port%d phy\n", slot);
- goto err_phy_on;
- }
-
- if ((pcie_port_read(port, RALINK_PCI_STATUS) & PCIE_PORT_LINKUP) == 0) {
- dev_err(dev, "pcie%d no card, disable it (RST & CLK)\n", slot);
- mt7621_control_assert(port);
- port->enabled = false;
- err = -ENODEV;
- goto err_no_link_up;
+ phy_exit(port->phy);
+ return err;
}
port->enabled = true;
return 0;
-
-err_no_link_up:
- phy_power_off(port->phy);
-err_phy_on:
- phy_exit(port->phy);
-err_phy_init:
- return err;
}
static void mt7621_pcie_init_ports(struct mt7621_pcie *pcie)
{
struct device *dev = pcie->dev;
struct mt7621_pcie_port *port, *tmp;
+ u32 val = 0;
int err;
+ rt_sysc_m32(PERST_MODE_MASK, PERST_MODE_GPIO, MT7621_GPIO_MODE);
+
+ mt7621_perst_gpio_pcie_assert(pcie);
+
list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
u32 slot = port->slot;
@@ -441,10 +463,30 @@ static void mt7621_pcie_init_ports(struct mt7621_pcie *pcie)
if (err) {
dev_err(dev, "Initiating port %d failed\n", slot);
list_del(&port->list);
+ } else {
+ val = read_config(pcie, slot, PCIE_FTS_NUM);
+ dev_info(dev, "Port %d N_FTS = %x\n", slot,
+ (unsigned int)val);
}
}
reset_control_assert(pcie->rst);
+
+ mt7621_perst_gpio_pcie_deassert(pcie);
+
+ list_for_each_entry(port, &pcie->ports, list) {
+ u32 slot = port->slot;
+
+ if (!mt7621_pcie_port_is_linkup(port)) {
+ dev_err(dev, "pcie%d no card, disable it (RST & CLK)\n",
+ slot);
+ phy_power_off(port->phy);
+ mt7621_control_assert(port);
+ mt7621_pcie_port_clk_disable(port);
+ port->enabled = false;
+ }
+ }
+
rt_sysc_m32(0x30, 2 << 4, SYSC_REG_SYSTEM_CONFIG1);
rt_sysc_m32(PCIE_CLK_GEN_EN, PCIE_CLK_GEN_DIS, RALINK_PCIE_CLK_GEN);
rt_sysc_m32(PCIE_CLK_GEN1_DIS, PCIE_CLK_GEN1_EN, RALINK_PCIE_CLK_GEN1);
@@ -453,30 +495,12 @@ static void mt7621_pcie_init_ports(struct mt7621_pcie *pcie)
reset_control_deassert(pcie->rst);
}
-static int mt7621_pcie_enable_port(struct mt7621_pcie_port *port)
+static void mt7621_pcie_enable_port(struct mt7621_pcie_port *port)
{
struct mt7621_pcie *pcie = port->pcie;
u32 slot = port->slot;
u32 offset = MT7621_PCIE_OFFSET + (slot * MT7621_NEXT_PORT);
u32 val;
- int err;
-
- /* assert port PERST_N */
- val = pcie_read(pcie, RALINK_PCI_PCICFG_ADDR);
- val |= PCIE_PORT_PERST(slot);
- pcie_write(pcie, val, RALINK_PCI_PCICFG_ADDR);
-
- /* de-assert port PERST_N */
- val = pcie_read(pcie, RALINK_PCI_PCICFG_ADDR);
- val &= ~PCIE_PORT_PERST(slot);
- pcie_write(pcie, val, RALINK_PCI_PCICFG_ADDR);
-
- /* 100ms timeout value should be enough for Gen1 training */
- err = readl_poll_timeout(port->base + RALINK_PCI_STATUS,
- val, !!(val & PCIE_PORT_LINKUP),
- 20, 100 * USEC_PER_MSEC);
- if (err)
- return -ETIMEDOUT;
/* enable pcie interrupt */
val = pcie_read(pcie, RALINK_PCI_PCIMSK_ADDR);
@@ -492,8 +516,6 @@ static int mt7621_pcie_enable_port(struct mt7621_pcie_port *port)
/* configure class code and revision ID */
pcie_write(pcie, PCIE_CLASS_CODE | PCIE_REVISION_ID,
offset + RALINK_PCI_CLASS);
-
- return 0;
}
static void mt7621_pcie_enable_ports(struct mt7621_pcie *pcie)
@@ -506,12 +528,8 @@ static void mt7621_pcie_enable_ports(struct mt7621_pcie *pcie)
list_for_each_entry(port, &pcie->ports, list) {
if (port->enabled) {
- if (mt7621_pcie_enable_port(port)) {
- dev_err(dev, "de-assert port %d PERST_N\n",
- port->slot);
- continue;
- }
- dev_info(dev, "PCIE%d enabled\n", slot);
+ mt7621_pcie_enable_port(port);
+ dev_info(dev, "PCIE%d enabled\n", num_slots_enabled);
num_slots_enabled++;
}
}
@@ -709,4 +727,4 @@ static int __init mt7621_pci_init(void)
return platform_driver_register(&mt7621_pci_driver);
}
-arch_initcall(mt7621_pci_init);
+module_init(mt7621_pci_init);
diff --git a/drivers/staging/netlogic/xlr_net.c b/drivers/staging/netlogic/xlr_net.c
index 07a06c532dee..05079f7be841 100644
--- a/drivers/staging/netlogic/xlr_net.c
+++ b/drivers/staging/netlogic/xlr_net.c
@@ -385,7 +385,7 @@ static void *xlr_config_spill(struct xlr_net_priv *priv, int reg_start_0,
base = priv->base_addr;
spill_size = size;
- spill = kmalloc(spill_size + SMP_CACHE_BYTES, GFP_ATOMIC);
+ spill = kmalloc(spill_size + SMP_CACHE_BYTES, GFP_KERNEL);
if (!spill)
return ZERO_SIZE_PTR;
diff --git a/drivers/staging/octeon-usb/octeon-hcd.c b/drivers/staging/octeon-usb/octeon-hcd.c
index aeec16314e0d..cd2b777073c4 100644
--- a/drivers/staging/octeon-usb/octeon-hcd.c
+++ b/drivers/staging/octeon-usb/octeon-hcd.c
@@ -521,8 +521,7 @@ static void octeon_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
*/
static inline u32 cvmx_usb_read_csr32(struct octeon_hcd *usb, u64 address)
{
- u32 result = cvmx_read64_uint32(address ^ 4);
- return result;
+ return cvmx_read64_uint32(address ^ 4);
}
/**
diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c
index c889f0bdf424..40c6f4e7632f 100644
--- a/drivers/staging/pi433/pi433_if.c
+++ b/drivers/staging/pi433/pi433_if.c
@@ -871,7 +871,6 @@ abort:
static long
pi433_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
- int retval = 0;
struct pi433_instance *instance;
struct pi433_device *device;
struct pi433_tx_cfg tx_cfg;
@@ -923,10 +922,10 @@ pi433_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
mutex_unlock(&device->rx_lock);
break;
default:
- retval = -EINVAL;
+ return -EINVAL;
}
- return retval;
+ return 0;
}
#ifdef CONFIG_COMPAT
diff --git a/drivers/staging/pi433/rf69.c b/drivers/staging/pi433/rf69.c
index 4cd16257f0aa..7d86bb8be245 100644
--- a/drivers/staging/pi433/rf69.c
+++ b/drivers/staging/pi433/rf69.c
@@ -722,10 +722,10 @@ int rf69_set_packet_format(struct spi_device *spi,
switch (packet_format) {
case packet_length_var:
return rf69_set_bit(spi, REG_PACKETCONFIG1,
- MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE);
+ MASK_PACKETCONFIG1_PACKET_FORMAT_VARIABLE);
case packet_length_fix:
return rf69_clear_bit(spi, REG_PACKETCONFIG1,
- MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE);
+ MASK_PACKETCONFIG1_PACKET_FORMAT_VARIABLE);
default:
dev_dbg(&spi->dev, "set: illegal input param");
return -EINVAL;
diff --git a/drivers/staging/pi433/rf69_registers.h b/drivers/staging/pi433/rf69_registers.h
index f925a83c3247..be5497cdace0 100644
--- a/drivers/staging/pi433/rf69_registers.h
+++ b/drivers/staging/pi433/rf69_registers.h
@@ -395,7 +395,7 @@
#define MASK_SYNC_CONFIG_SYNC_TOLERANCE 0x07
/* RegPacketConfig1 */
-#define MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE 0x80
+#define MASK_PACKETCONFIG1_PACKET_FORMAT_VARIABLE 0x80
#define MASK_PACKETCONFIG1_DCFREE 0x60
#define MASK_PACKETCONFIG1_CRC_ON 0x10 /* default */
#define MASK_PACKETCONFIG1_CRCAUTOCLEAR_OFF 0x08
diff --git a/drivers/staging/ralink-gdma/ralink-gdma.c b/drivers/staging/ralink-gdma/ralink-gdma.c
index de3e357b2640..5854551d0a52 100644
--- a/drivers/staging/ralink-gdma/ralink-gdma.c
+++ b/drivers/staging/ralink-gdma/ralink-gdma.c
@@ -814,9 +814,8 @@ static int gdma_dma_probe(struct platform_device *pdev)
dma_dev = devm_kzalloc(&pdev->dev,
struct_size(dma_dev, chan, data->chancnt),
GFP_KERNEL);
- if (!dma_dev) {
+ if (!dma_dev)
return -EINVAL;
- }
dma_dev->data = data;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/staging/rtl8188eu/Kconfig b/drivers/staging/rtl8188eu/Kconfig
index 4f7ef287a0f2..970d5abd6336 100644
--- a/drivers/staging/rtl8188eu/Kconfig
+++ b/drivers/staging/rtl8188eu/Kconfig
@@ -8,7 +8,7 @@ config R8188EU
select LIB80211
select LIB80211_CRYPT_WEP
select LIB80211_CRYPT_CCMP
- ---help---
+ help
This option adds the Realtek RTL8188EU USB device such as TP-Link TL-WN725N.
If built as a module, it will be called r8188eu.
@@ -17,7 +17,7 @@ if R8188EU
config 88EU_AP_MODE
bool "Realtek RTL8188EU AP mode"
default y
- ---help---
+ help
This option enables Access Point mode. Unless you know that your system
will never be used as an AP, or the target system has limited memory,
"Y" should be selected.
diff --git a/drivers/staging/rtl8188eu/core/rtw_ieee80211.c b/drivers/staging/rtl8188eu/core/rtw_ieee80211.c
index 797ffa6e64d5..28b3cdd10397 100644
--- a/drivers/staging/rtl8188eu/core/rtw_ieee80211.c
+++ b/drivers/staging/rtl8188eu/core/rtw_ieee80211.c
@@ -482,7 +482,7 @@ int rtw_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher, int *pairwi
return ret;
}
-int rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie, u16 *wpa_len)
+void rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie, u16 *wpa_len)
{
u8 authmode, sec_idx, i;
u8 wpa_oui[4] = {0x0, 0x50, 0xf2, 0x01};
@@ -539,8 +539,6 @@ int rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie,
}
}
}
-
- return *rsn_len + *wpa_len;
}
u8 rtw_is_wps_ie(u8 *ie_ptr, uint *wps_ielen)
diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme.c b/drivers/staging/rtl8188eu/core/rtw_mlme.c
index 9a4aad5ec365..d2f7a88e992e 100644
--- a/drivers/staging/rtl8188eu/core/rtw_mlme.c
+++ b/drivers/staging/rtl8188eu/core/rtw_mlme.c
@@ -159,7 +159,8 @@ static void _rtw_free_network(struct mlme_priv *pmlmepriv, struct wlan_network *
spin_unlock_bh(&free_queue->lock);
}
-void _rtw_free_network_nolock(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork)
+static void rtw_free_network_nolock(struct mlme_priv *pmlmepriv,
+ struct wlan_network *pnetwork)
{
struct __queue *free_queue = &pmlmepriv->free_bss_pool;
@@ -276,12 +277,6 @@ static struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv)
return _rtw_alloc_network(pmlmepriv);
}
-static void rtw_free_network_nolock(struct mlme_priv *pmlmepriv,
- struct wlan_network *pnetwork)
-{
- _rtw_free_network_nolock(pmlmepriv, pnetwork);
-}
-
int rtw_is_same_ibss(struct adapter *adapter, struct wlan_network *pnetwork)
{
int ret = true;
@@ -1330,11 +1325,10 @@ void _rtw_join_timeout_handler (struct timer_list *t)
continue;
}
break;
- } else {
- DBG_88E("%s We've try roaming but fail\n", __func__);
- rtw_indicate_disconnect(adapter);
- break;
}
+ DBG_88E("%s We've try roaming but fail\n", __func__);
+ rtw_indicate_disconnect(adapter);
+ break;
}
} else {
rtw_indicate_disconnect(adapter);
@@ -2058,17 +2052,16 @@ void _rtw_roaming(struct adapter *padapter, struct wlan_network *tgt_network)
do_join_r = rtw_do_join(padapter);
if (do_join_r == _SUCCESS) {
break;
- } else {
- DBG_88E("roaming do_join return %d\n", do_join_r);
- pmlmepriv->to_roaming--;
+ }
+ DBG_88E("roaming do_join return %d\n", do_join_r);
+ pmlmepriv->to_roaming--;
- if (pmlmepriv->to_roaming > 0) {
- continue;
- } else {
- DBG_88E("%s(%d) -to roaming fail, indicate_disconnect\n", __func__, __LINE__);
- rtw_indicate_disconnect(padapter);
- break;
- }
+ if (pmlmepriv->to_roaming > 0) {
+ continue;
+ } else {
+ DBG_88E("%s(%d) -to roaming fail, indicate_disconnect\n", __func__, __LINE__);
+ rtw_indicate_disconnect(padapter);
+ break;
}
}
}
diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
index 8f28aefbe6f9..6f3c03201f64 100644
--- a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
+++ b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
@@ -5322,7 +5322,7 @@ u8 set_tx_beacon_cmd(struct adapter *padapter)
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
- u8 res = _SUCCESS;
+ u8 res;
int len_diff = 0;
ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
diff --git a/drivers/staging/rtl8188eu/core/rtw_recv.c b/drivers/staging/rtl8188eu/core/rtw_recv.c
index 087f6c9a5826..9caf7041ad60 100644
--- a/drivers/staging/rtl8188eu/core/rtw_recv.c
+++ b/drivers/staging/rtl8188eu/core/rtw_recv.c
@@ -450,7 +450,7 @@ static struct recv_frame *portctrl(struct adapter *adapter,
memcpy(&be_tmp, ptr, 2);
ether_type = ntohs(be_tmp);
- if ((psta != NULL) && (psta->ieee8021x_blocked)) {
+ if (psta && (psta->ieee8021x_blocked)) {
/* blocked */
/* only accept EAPOL frame */
RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########%s:psta->ieee8021x_blocked==1\n", __func__));
@@ -700,7 +700,7 @@ static int sta2sta_data_frame(struct adapter *adapter,
else
*psta = rtw_get_stainfo(pstapriv, sta_addr); /* get ap_info */
- if (*psta == NULL) {
+ if (!*psta) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under %s ; drop pkt\n", __func__));
ret = _FAIL;
goto exit;
@@ -764,7 +764,7 @@ static int ap2sta_data_frame(
else
*psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get ap_info */
- if (*psta == NULL) {
+ if (!*psta) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("ap2sta: can't get psta under STATION_MODE ; drop pkt\n"));
ret = _FAIL;
goto exit;
@@ -786,7 +786,7 @@ static int ap2sta_data_frame(
} else {
if (!memcmp(myhwaddr, pattrib->dst, ETH_ALEN) && !mcast) {
*psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get sta_info */
- if (*psta == NULL) {
+ if (!*psta) {
DBG_88E("issue_deauth to the ap =%pM for the reason(7)\n", (pattrib->bssid));
issue_deauth(adapter, pattrib->bssid, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
@@ -820,7 +820,7 @@ static int sta2ap_data_frame(struct adapter *adapter,
}
*psta = rtw_get_stainfo(pstapriv, pattrib->src);
- if (*psta == NULL) {
+ if (!*psta) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under AP_MODE; drop pkt\n"));
DBG_88E("issue_deauth to sta=%pM for the reason(7)\n", (pattrib->src));
@@ -883,7 +883,7 @@ static int validate_recv_ctrl_frame(struct adapter *padapter,
aid = GetAid(pframe);
psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe));
- if ((psta == NULL) || (psta->aid != aid))
+ if ((!psta) || (psta->aid != aid))
return _FAIL;
/* for rx pkt statistics */
@@ -1479,7 +1479,7 @@ struct recv_frame *recvframe_chk_defrag(struct adapter *padapter,
}
}
- if ((prtnframe != NULL) && (prtnframe->attrib.privacy)) {
+ if (prtnframe && (prtnframe->attrib.privacy)) {
/* after defrag we must check tkip mic code */
if (recvframe_chkmic(padapter, prtnframe) == _FAIL) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvframe_chkmic(padapter, prtnframe)==_FAIL\n"));
diff --git a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c
index f404370d6631..7bfc5b7c2757 100644
--- a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c
+++ b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c
@@ -27,9 +27,6 @@ static const u8 EPIGRAM_OUI[] = {0x00, 0x90, 0x4c};
u8 REALTEK_96B_IE[] = {0x00, 0xe0, 0x4c, 0x02, 0x01, 0x20};
-#define R2T_PHY_DELAY (0)
-
-/* define WAIT_FOR_BCN_TO_M (3000) */
#define WAIT_FOR_BCN_TO_MIN (6000)
#define WAIT_FOR_BCN_TO_MAX (20000)
@@ -349,16 +346,6 @@ void set_channel_bwmode(struct adapter *padapter, unsigned char channel, unsigne
SetBWMode(padapter, bwmode, channel_offset);
}
-int get_bsstype(unsigned short capability)
-{
- if (capability & BIT(0))
- return WIFI_FW_AP_STATE;
- else if (capability & BIT(1))
- return WIFI_FW_ADHOC_STATE;
- else
- return 0;
-}
-
u16 get_beacon_interval(struct wlan_bssid_ex *bss)
{
__le16 val;
@@ -1041,7 +1028,6 @@ void update_beacon_info(struct adapter *padapter, u8 *pframe, uint pkt_len, stru
switch (pIE->ElementID) {
case _HT_EXTRA_INFO_IE_: /* HT info */
- /* HT_info_handler(padapter, pIE); */
bwmode_update_check(padapter, pIE);
break;
case _ERPINFO_IE_:
@@ -1088,36 +1074,6 @@ unsigned int is_ap_in_tkip(struct adapter *padapter)
}
}
-unsigned int is_ap_in_wep(struct adapter *padapter)
-{
- u32 i;
- struct ndis_802_11_var_ie *pIE;
- struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
- struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
- struct wlan_bssid_ex *cur_network = &pmlmeinfo->network;
-
- if (rtw_get_capability((struct wlan_bssid_ex *)cur_network) & WLAN_CAPABILITY_PRIVACY) {
- for (i = sizeof(struct ndis_802_11_fixed_ie); i < pmlmeinfo->network.ie_length;) {
- pIE = (struct ndis_802_11_var_ie *)(pmlmeinfo->network.ies + i);
-
- switch (pIE->ElementID) {
- case _VENDOR_SPECIFIC_IE_:
- if (!memcmp(pIE->data, RTW_WPA_OUI, 4))
- return false;
- break;
- case _RSN_IE_2_:
- return false;
- default:
- break;
- }
- i += (pIE->Length + 2);
- }
- return true;
- } else {
- return false;
- }
-}
-
static int wifirate2_ratetbl_inx(unsigned char rate)
{
rate = rate & 0x7f;
@@ -1346,8 +1302,6 @@ void update_IOT_info(struct adapter *padapter)
false);
break;
case HT_IOT_PEER_REALTEK:
- /* rtw_write16(padapter, 0x4cc, 0xffff); */
- /* rtw_write16(padapter, 0x546, 0x01c0); */
/* disable high power */
Switch_DM_Func(padapter, (u32)(~DYNAMIC_BB_DYNAMIC_TXPWR),
false);
diff --git a/drivers/staging/rtl8188eu/hal/hal_com.c b/drivers/staging/rtl8188eu/hal/hal_com.c
index ff481fbd074c..95f1b1431373 100644
--- a/drivers/staging/rtl8188eu/hal/hal_com.c
+++ b/drivers/staging/rtl8188eu/hal/hal_com.c
@@ -283,9 +283,3 @@ bool hal_mapping_out_pipe(struct adapter *adapter, u8 numoutpipe)
}
return result;
}
-
-void hal_init_macaddr(struct adapter *adapter)
-{
- rtw_hal_set_hwreg(adapter, HW_VAR_MAC_ADDR,
- adapter->eeprompriv.mac_addr);
-}
diff --git a/drivers/staging/rtl8188eu/hal/odm.c b/drivers/staging/rtl8188eu/hal/odm.c
index 74f7c9c81bf6..4e2f6cb55a75 100644
--- a/drivers/staging/rtl8188eu/hal/odm.c
+++ b/drivers/staging/rtl8188eu/hal/odm.c
@@ -943,11 +943,6 @@ void odm_RSSIMonitorCheckCE(struct odm_dm_struct *pDM_Odm)
void odm_TXPowerTrackingInit(struct odm_dm_struct *pDM_Odm)
{
- odm_TXPowerTrackingThermalMeterInit(pDM_Odm);
-}
-
-void odm_TXPowerTrackingThermalMeterInit(struct odm_dm_struct *pDM_Odm)
-{
pDM_Odm->RFCalibrateInfo.bTXPowerTracking = true;
pDM_Odm->RFCalibrateInfo.TXPowercount = 0;
if (*(pDM_Odm->mp_mode) != 1)
@@ -962,11 +957,6 @@ void ODM_TXPowerTrackingCheck(struct odm_dm_struct *pDM_Odm)
/* 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate */
/* at the same time. In the stage2/3, we need to prive universal interface and merge all */
/* HW dynamic mechanism. */
- odm_TXPowerTrackingCheckCE(pDM_Odm);
-}
-
-void odm_TXPowerTrackingCheckCE(struct odm_dm_struct *pDM_Odm)
-{
struct adapter *Adapter = pDM_Odm->Adapter;
if (!(pDM_Odm->SupportAbility & ODM_RF_TX_PWR_TRACK))
diff --git a/drivers/staging/rtl8188eu/hal/odm_hwconfig.c b/drivers/staging/rtl8188eu/hal/odm_hwconfig.c
index 149b0009ad66..d5a9ac51e907 100644
--- a/drivers/staging/rtl8188eu/hal/odm_hwconfig.c
+++ b/drivers/staging/rtl8188eu/hal/odm_hwconfig.c
@@ -387,10 +387,9 @@ static void odm_Process_RSSIForDM(struct odm_dm_struct *dm_odm,
}
/* Endianness before calling this API */
-static void ODM_PhyStatusQuery_92CSeries(struct odm_dm_struct *dm_odm,
- struct odm_phy_status_info *pPhyInfo,
- u8 *pPhyStatus,
- struct odm_per_pkt_info *pPktinfo)
+void ODM_PhyStatusQuery(struct odm_dm_struct *dm_odm,
+ struct odm_phy_status_info *pPhyInfo,
+ u8 *pPhyStatus, struct odm_per_pkt_info *pPktinfo)
{
odm_RxPhyStatus92CSeries_Parsing(dm_odm, pPhyInfo, pPhyStatus,
pPktinfo);
@@ -398,12 +397,4 @@ static void ODM_PhyStatusQuery_92CSeries(struct odm_dm_struct *dm_odm,
;/* Select the packets to do RSSI checking for antenna switching. */
else
odm_Process_RSSIForDM(dm_odm, pPhyInfo, pPktinfo);
-
-}
-
-void ODM_PhyStatusQuery(struct odm_dm_struct *dm_odm,
- struct odm_phy_status_info *pPhyInfo,
- u8 *pPhyStatus, struct odm_per_pkt_info *pPktinfo)
-{
- ODM_PhyStatusQuery_92CSeries(dm_odm, pPhyInfo, pPhyStatus, pPktinfo);
}
diff --git a/drivers/staging/rtl8188eu/hal/usb_halinit.c b/drivers/staging/rtl8188eu/hal/usb_halinit.c
index 70c02c49b177..ac5552050752 100644
--- a/drivers/staging/rtl8188eu/hal/usb_halinit.c
+++ b/drivers/staging/rtl8188eu/hal/usb_halinit.c
@@ -469,10 +469,7 @@ static void usb_AggSettingTxUpdate(struct adapter *Adapter)
*
*---------------------------------------------------------------------------
*/
-static void
-usb_AggSettingRxUpdate(
- struct adapter *Adapter
- )
+static void usb_AggSettingRxUpdate(struct adapter *Adapter)
{
struct hal_data_8188e *haldata = Adapter->HalData;
u8 valueDMA;
@@ -749,7 +746,8 @@ u32 rtl8188eu_hal_init(struct adapter *Adapter)
_InitDriverInfoSize(Adapter, DRVINFO_SZ);
_InitInterrupt(Adapter);
- hal_init_macaddr(Adapter);/* set mac_address */
+ rtw_hal_set_hwreg(Adapter, HW_VAR_MAC_ADDR,
+ Adapter->eeprompriv.mac_addr);
_InitNetworkType(Adapter);/* set msr */
_InitWMACSetting(Adapter);
_InitAdaptiveCtrl(Adapter);
@@ -1044,10 +1042,7 @@ static void Hal_EfuseParseMACAddr_8188EU(struct adapter *adapt, u8 *hwinfo, bool
eeprom->mac_addr));
}
-static void
-readAdapterInfo_8188EU(
- struct adapter *adapt
- )
+static void readAdapterInfo_8188EU(struct adapter *adapt)
{
struct eeprom_priv *eeprom = GET_EEPROM_EFUSE_PRIV(adapt);
@@ -1067,9 +1062,7 @@ readAdapterInfo_8188EU(
Hal_ReadThermalMeter_88E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag);
}
-static void _ReadPROMContent(
- struct adapter *Adapter
- )
+static void _ReadPROMContent(struct adapter *Adapter)
{
struct eeprom_priv *eeprom = GET_EEPROM_EFUSE_PRIV(Adapter);
u8 eeValue;
@@ -1782,11 +1775,8 @@ void rtw_hal_get_hwreg(struct adapter *Adapter, u8 variable, u8 *val)
/* Description: */
/* Query setting of specified variable. */
/* */
-u8 rtw_hal_get_def_var(
- struct adapter *Adapter,
- enum hal_def_variable eVariable,
- void *pValue
- )
+u8 rtw_hal_get_def_var(struct adapter *Adapter, enum hal_def_variable eVariable,
+ void *pValue)
{
struct hal_data_8188e *haldata = Adapter->HalData;
u8 bResult = _SUCCESS;
diff --git a/drivers/staging/rtl8188eu/include/hal_com.h b/drivers/staging/rtl8188eu/include/hal_com.h
index 2f7bdade40a5..93cbbe7ba1fd 100644
--- a/drivers/staging/rtl8188eu/include/hal_com.h
+++ b/drivers/staging/rtl8188eu/include/hal_com.h
@@ -148,5 +148,4 @@ void hal_set_brate_cfg(u8 *brates, u16 *rate_cfg);
bool hal_mapping_out_pipe(struct adapter *adapter, u8 numoutpipe);
-void hal_init_macaddr(struct adapter *adapter);
#endif /* __HAL_COMMON_H__ */
diff --git a/drivers/staging/rtl8188eu/include/ieee80211.h b/drivers/staging/rtl8188eu/include/ieee80211.h
index c60b833ca110..d569fe5ed8e6 100644
--- a/drivers/staging/rtl8188eu/include/ieee80211.h
+++ b/drivers/staging/rtl8188eu/include/ieee80211.h
@@ -12,12 +12,6 @@
#include "wifi.h"
#include <linux/wireless.h>
-#define MGMT_QUEUE_NUM 5
-
-#define ETH_ALEN 6
-#define ETH_TYPE_LEN 2
-#define PAYLOAD_TYPE_LEN 1
-
#ifdef CONFIG_88EU_AP_MODE
#define RTL_IOCTL_HOSTAPD (SIOCIWFIRSTPRIV + 28)
@@ -749,8 +743,8 @@ int rtw_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher,
int rtw_parse_wpa2_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher,
int *pairwise_cipher, int *is_8021x);
-int rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len,
- u8 *wpa_ie, u16 *wpa_len);
+void rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len,
+ u8 *wpa_ie, u16 *wpa_len);
u8 rtw_is_wps_ie(u8 *ie_ptr, uint *wps_ielen);
u8 *rtw_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen);
diff --git a/drivers/staging/rtl8188eu/include/odm_precomp.h b/drivers/staging/rtl8188eu/include/odm_precomp.h
index df096c37f5eb..5254d875f96b 100644
--- a/drivers/staging/rtl8188eu/include/odm_precomp.h
+++ b/drivers/staging/rtl8188eu/include/odm_precomp.h
@@ -59,9 +59,7 @@ void odm_RefreshRateAdaptiveMaskCE(struct odm_dm_struct *pDM_Odm);
void odm_RefreshRateAdaptiveMaskAPADSL(struct odm_dm_struct *pDM_Odm);
void odm_DynamicTxPowerNIC(struct odm_dm_struct *pDM_Odm);
void odm_RSSIMonitorCheckCE(struct odm_dm_struct *pDM_Odm);
-void odm_TXPowerTrackingThermalMeterInit(struct odm_dm_struct *pDM_Odm);
void odm_EdcaTurboCheckCE(struct odm_dm_struct *pDM_Odm);
-void odm_TXPowerTrackingCheckCE(struct odm_dm_struct *pDM_Odm);
void odm_SwAntDivChkAntSwitchCallback(void *FunctionContext);
void odm_InitHybridAntDiv(struct odm_dm_struct *pDM_Odm);
void odm_HwAntDiv(struct odm_dm_struct *pDM_Odm);
diff --git a/drivers/staging/rtl8188eu/include/rtw_eeprom.h b/drivers/staging/rtl8188eu/include/rtw_eeprom.h
index db25eb580c98..10525493129b 100644
--- a/drivers/staging/rtl8188eu/include/rtw_eeprom.h
+++ b/drivers/staging/rtl8188eu/include/rtw_eeprom.h
@@ -111,10 +111,4 @@ struct eeprom_priv {
u8 efuse_eeprom_data[HWSET_MAX_SIZE_512];
};
-void eeprom_write16(struct adapter *padapter, u16 reg, u16 data);
-u16 eeprom_read16(struct adapter *padapter, u16 reg);
-void read_eeprom_content(struct adapter *padapter);
-void eeprom_read_sz(struct adapter *adapt, u16 reg, u8 *data, u32 sz);
-void read_eeprom_content_by_attrib(struct adapter *padapter);
-
#endif /* __RTL871X_EEPROM_H__ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_mlme.h b/drivers/staging/rtl8188eu/include/rtw_mlme.h
index bfef66525944..9abb7c320192 100644
--- a/drivers/staging/rtl8188eu/include/rtw_mlme.h
+++ b/drivers/staging/rtl8188eu/include/rtw_mlme.h
@@ -335,9 +335,6 @@ void rtw_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv);
struct wlan_network *_rtw_alloc_network(struct mlme_priv *pmlmepriv);
-void _rtw_free_network_nolock(struct mlme_priv *pmlmepriv,
- struct wlan_network *pnetwork);
-
int rtw_if_up(struct adapter *padapter);
u8 *rtw_get_capability_from_ie(u8 *ie);
diff --git a/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h b/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h
index 1fb2349bd0a0..327f7d1bc20c 100644
--- a/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h
+++ b/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h
@@ -485,7 +485,6 @@ void flush_all_cam_entry(struct adapter *padapter);
void update_network(struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src,
struct adapter *adapter, bool update_ie);
-int get_bsstype(unsigned short capability);
u16 get_beacon_interval(struct wlan_bssid_ex *bss);
int is_client_associated_to_ap(struct adapter *padapter);
@@ -526,7 +525,6 @@ void set_sta_rate(struct adapter *padapter, struct sta_info *psta);
unsigned char get_highest_rate_idx(u32 mask);
int support_short_GI(struct adapter *padapter, struct ieee80211_ht_cap *caps);
unsigned int is_ap_in_tkip(struct adapter *padapter);
-unsigned int is_ap_in_wep(struct adapter *padapter);
void report_join_res(struct adapter *padapter, int res);
void report_survey_event(struct adapter *padapter,
diff --git a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
index eaa4adb32a0d..ec5835d1aa8c 100644
--- a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
+++ b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
@@ -1686,7 +1686,7 @@ static int rtw_wx_get_enc(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *keybuf)
{
- uint key, ret = 0;
+ uint key;
struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
struct iw_point *erq = &(wrqu->encoding);
struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
@@ -1744,7 +1744,7 @@ static int rtw_wx_get_enc(struct net_device *dev,
break;
}
- return ret;
+ return 0;
}
static int rtw_wx_get_power(struct net_device *dev,
@@ -2508,7 +2508,6 @@ static int rtw_add_sta(struct net_device *dev, struct ieee_param *param)
static int rtw_del_sta(struct net_device *dev, struct ieee_param *param)
{
- int ret = 0;
struct sta_info *psta = NULL;
struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
@@ -2538,7 +2537,7 @@ static int rtw_del_sta(struct net_device *dev, struct ieee_param *param)
DBG_88E("rtw_del_sta(), sta has already been removed or never been added\n");
}
- return ret;
+ return 0;
}
static int rtw_ioctl_get_sta_data(struct net_device *dev, struct ieee_param *param, int len)
@@ -2636,7 +2635,6 @@ static int rtw_get_sta_wpaie(struct net_device *dev, struct ieee_param *param)
static int rtw_set_wps_beacon(struct net_device *dev, struct ieee_param *param, int len)
{
- int ret = 0;
unsigned char wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
@@ -2668,12 +2666,11 @@ static int rtw_set_wps_beacon(struct net_device *dev, struct ieee_param *param,
pmlmeext->bstart_bss = true;
}
- return ret;
+ return 0;
}
static int rtw_set_wps_probe_resp(struct net_device *dev, struct ieee_param *param, int len)
{
- int ret = 0;
struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
int ie_len;
@@ -2698,12 +2695,11 @@ static int rtw_set_wps_probe_resp(struct net_device *dev, struct ieee_param *par
memcpy(pmlmepriv->wps_probe_resp_ie, param->u.bcn_ie.buf, ie_len);
}
- return ret;
+ return 0;
}
static int rtw_set_wps_assoc_resp(struct net_device *dev, struct ieee_param *param, int len)
{
- int ret = 0;
struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
int ie_len;
@@ -2729,12 +2725,11 @@ static int rtw_set_wps_assoc_resp(struct net_device *dev, struct ieee_param *par
memcpy(pmlmepriv->wps_assoc_resp_ie, param->u.bcn_ie.buf, ie_len);
}
- return ret;
+ return 0;
}
static int rtw_set_hidden_ssid(struct net_device *dev, struct ieee_param *param, int len)
{
- int ret = 0;
struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
@@ -2754,7 +2749,7 @@ static int rtw_set_hidden_ssid(struct net_device *dev, struct ieee_param *param,
value = 0;
DBG_88E("%s value(%u)\n", __func__, value);
pmlmeinfo->hidden_ssid_mode = value;
- return ret;
+ return 0;
}
static int rtw_ioctl_acl_remove_sta(struct net_device *dev, struct ieee_param *param, int len)
@@ -2787,7 +2782,6 @@ static int rtw_ioctl_acl_add_sta(struct net_device *dev, struct ieee_param *para
static int rtw_ioctl_set_macaddr_acl(struct net_device *dev, struct ieee_param *param, int len)
{
- int ret = 0;
struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
@@ -2796,7 +2790,7 @@ static int rtw_ioctl_set_macaddr_acl(struct net_device *dev, struct ieee_param *
rtw_set_macaddr_acl(padapter, param->u.mlme.command);
- return ret;
+ return 0;
}
static int rtw_hostapd_ioctl(struct net_device *dev, struct iw_point *p)
diff --git a/drivers/staging/rtl8188eu/os_dep/mlme_linux.c b/drivers/staging/rtl8188eu/os_dep/mlme_linux.c
index 9db11b16cb93..e660bd4d91ef 100644
--- a/drivers/staging/rtl8188eu/os_dep/mlme_linux.c
+++ b/drivers/staging/rtl8188eu/os_dep/mlme_linux.c
@@ -93,11 +93,11 @@ void rtw_report_sec_ie(struct adapter *adapter, u8 authmode, u8 *sec_ie)
union iwreq_data wrqu;
RT_TRACE(_module_mlme_osdep_c_, _drv_info_,
- ("+rtw_report_sec_ie, authmode=%d\n", authmode));
+ ("+%s, authmode=%d\n", __func__, authmode));
buff = NULL;
if (authmode == _WPA_IE_ID_) {
RT_TRACE(_module_mlme_osdep_c_, _drv_info_,
- ("rtw_report_sec_ie, authmode=%d\n", authmode));
+ ("%s, authmode=%d\n", __func__, authmode));
buff = rtw_malloc(IW_CUSTOM_MAX);
if (!buff)
return;
@@ -149,7 +149,7 @@ void rtw_indicate_sta_assoc_event(struct adapter *padapter, struct sta_info *pst
memcpy(wrqu.addr.sa_data, psta->hwaddr, ETH_ALEN);
- DBG_88E("+rtw_indicate_sta_assoc_event\n");
+ DBG_88E("+%s\n", __func__);
wireless_send_event(padapter->pnetdev, IWEVREGISTERED, &wrqu, NULL);
}
@@ -172,7 +172,7 @@ void rtw_indicate_sta_disassoc_event(struct adapter *padapter, struct sta_info *
memcpy(wrqu.addr.sa_data, psta->hwaddr, ETH_ALEN);
- DBG_88E("+rtw_indicate_sta_disassoc_event\n");
+ DBG_88E("+%s\n", __func__);
wireless_send_event(padapter->pnetdev, IWEVEXPIRED, &wrqu, NULL);
}
diff --git a/drivers/staging/rtl8188eu/os_dep/os_intfs.c b/drivers/staging/rtl8188eu/os_dep/os_intfs.c
index 2c088af44c8b..8907bf6bb7ff 100644
--- a/drivers/staging/rtl8188eu/os_dep/os_intfs.c
+++ b/drivers/staging/rtl8188eu/os_dep/os_intfs.c
@@ -19,6 +19,7 @@ MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Realtek Wireless Lan Driver");
MODULE_AUTHOR("Realtek Semiconductor Corp.");
MODULE_VERSION(DRIVERVERSION);
+MODULE_FIRMWARE("rtlwifi/rtl8188eufw.bin");
#define RTW_NOTCH_FILTER 0 /* 0:Disable, 1:Enable, */
diff --git a/drivers/staging/rtl8188eu/os_dep/rtw_android.c b/drivers/staging/rtl8188eu/os_dep/rtw_android.c
index 7a090615dcbc..daf6db354982 100644
--- a/drivers/staging/rtl8188eu/os_dep/rtw_android.c
+++ b/drivers/staging/rtl8188eu/os_dep/rtw_android.c
@@ -67,7 +67,7 @@ int rtw_android_cmdstr_to_num(char *cmdstr)
int cmd_num;
for (cmd_num = 0; cmd_num < ANDROID_WIFI_CMD_MAX; cmd_num++)
- if (0 == strncasecmp(cmdstr, android_wifi_cmd_str[cmd_num],
+ if (!strncasecmp(cmdstr, android_wifi_cmd_str[cmd_num],
strlen(android_wifi_cmd_str[cmd_num])))
break;
return cmd_num;
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c
index 5215a0b5fd45..7d78f16efc1d 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c
+++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c
@@ -1427,7 +1427,7 @@ static bool _rtl92e_set_rf_power_state(struct net_device *dev,
"_rtl92e_set_rf_power_state() eRfOn!\n");
if ((priv->rtllib->eRFPowerState == eRfOff) &&
RT_IN_PS_LEVEL(pPSC, RT_RF_OFF_LEVL_HALT_NIC)) {
- bool rtstatus = true;
+ bool rtstatus;
u32 InitilizeCount = 3;
do {
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
index 55d857926bba..1b7e3fda7905 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
@@ -334,7 +334,7 @@ static void _rtl92e_dm_check_rate_adaptive(struct net_device *dev)
if (!priv->up) {
RT_TRACE(COMP_RATE,
- "<---- _rtl92e_dm_check_rate_adaptive(): driver is going to unload\n");
+ "<---- %s: driver is going to unload\n", __func__);
return;
}
@@ -1178,7 +1178,7 @@ void rtl92e_dm_restore_state(struct net_device *dev)
if (!priv->up) {
RT_TRACE(COMP_RATE,
- "<---- rtl92e_dm_restore_state(): driver is going to unload\n");
+ "<---- %s: driver is going to unload\n", __func__);
return;
}
diff --git a/drivers/staging/rtl8192e/rtllib_module.c b/drivers/staging/rtl8192e/rtllib_module.c
index bb13b1de2797..64d9feee1f39 100644
--- a/drivers/staging/rtl8192e/rtllib_module.c
+++ b/drivers/staging/rtl8192e/rtllib_module.c
@@ -83,7 +83,6 @@ struct net_device *alloc_rtllib(int sizeof_priv)
return NULL;
}
ieee = (struct rtllib_device *)netdev_priv_rsl(dev);
- memset(ieee, 0, sizeof(struct rtllib_device) + sizeof_priv);
ieee->dev = dev;
err = rtllib_networks_allocate(ieee);
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c
index d7975aa335b2..4a6c3f674431 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c
@@ -109,7 +109,6 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
}
ieee = netdev_priv(dev);
- memset(ieee, 0, sizeof(struct ieee80211_device) + sizeof_priv);
ieee->dev = dev;
err = ieee80211_networks_allocate(ieee);
@@ -155,7 +154,7 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
ieee80211_softmac_init(ieee);
ieee->pHTInfo = kzalloc(sizeof(RT_HIGH_THROUGHPUT), GFP_KERNEL);
- if (ieee->pHTInfo == NULL) {
+ if (!ieee->pHTInfo) {
IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't alloc memory for HTInfo\n");
/* By this point in code ieee80211_networks_allocate() has been
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
index 0e762e559675..0a3e478fccd6 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
@@ -67,7 +67,7 @@ ieee80211_frag_cache_find(struct ieee80211_device *ieee, unsigned int seq,
for (i = 0; i < IEEE80211_FRAG_CACHE_LEN; i++) {
entry = &ieee->frag_cache[tid][i];
- if (entry->skb != NULL &&
+ if (entry->skb &&
time_after(jiffies, entry->first_frag_time + 2 * HZ)) {
IEEE80211_DEBUG_FRAG(
"expiring fragment cache entry "
@@ -77,7 +77,7 @@ ieee80211_frag_cache_find(struct ieee80211_device *ieee, unsigned int seq,
entry->skb = NULL;
}
- if (entry->skb != NULL && entry->seq == seq &&
+ if (entry->skb && entry->seq == seq &&
(entry->last_frag + 1 == frag || frag == -1) &&
memcmp(entry->src_addr, src, ETH_ALEN) == 0 &&
memcmp(entry->dst_addr, dst, ETH_ALEN) == 0)
@@ -102,7 +102,7 @@ ieee80211_frag_cache_get(struct ieee80211_device *ieee,
struct rtl_80211_hdr_4addrqos *hdr_4addrqos;
u8 tid;
- if (((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS)&&IEEE80211_QOS_HAS_SEQ(fc)) {
+ if (((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS) && IEEE80211_QOS_HAS_SEQ(fc)) {
hdr_4addrqos = (struct rtl_80211_hdr_4addrqos *)hdr;
tid = le16_to_cpu(hdr_4addrqos->qos_ctl) & IEEE80211_QCTL_TID;
tid = UP2AC(tid);
@@ -133,7 +133,7 @@ ieee80211_frag_cache_get(struct ieee80211_device *ieee,
if (ieee->frag_next_idx[tid] >= IEEE80211_FRAG_CACHE_LEN)
ieee->frag_next_idx[tid] = 0;
- if (entry->skb != NULL)
+ if (entry->skb)
dev_kfree_skb_any(entry->skb);
entry->first_frag_time = jiffies;
@@ -169,7 +169,7 @@ static int ieee80211_frag_cache_invalidate(struct ieee80211_device *ieee,
struct rtl_80211_hdr_4addrqos *hdr_4addrqos;
u8 tid;
- if(((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS)&&IEEE80211_QOS_HAS_SEQ(fc)) {
+ if(((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS) && IEEE80211_QOS_HAS_SEQ(fc)) {
hdr_4addrqos = (struct rtl_80211_hdr_4addrqos *)hdr;
tid = le16_to_cpu(hdr_4addrqos->qos_ctl) & IEEE80211_QCTL_TID;
tid = UP2AC(tid);
@@ -426,7 +426,7 @@ static int is_duplicate_packet(struct ieee80211_device *ieee,
//TO2DS and QoS
- if(((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS)&&IEEE80211_QOS_HAS_SEQ(fc)) {
+ if(((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS) && IEEE80211_QOS_HAS_SEQ(fc)) {
hdr_4addrqos = (struct rtl_80211_hdr_4addrqos *)header;
tid = le16_to_cpu(hdr_4addrqos->qos_ctl) & IEEE80211_QCTL_TID;
tid = UP2AC(tid);
@@ -557,7 +557,7 @@ void ieee80211_indicate_packets(struct ieee80211_device *ieee, struct ieee80211_
//stats->rx_packets++;
//stats->rx_bytes += sub_skb->len;
- /* Indicat the packets to upper layer */
+ /* Indicate the packets to upper layer */
if (sub_skb) {
sub_skb->protocol = eth_type_trans(sub_skb, ieee->dev);
memset(sub_skb->cb, 0, sizeof(sub_skb->cb));
@@ -773,7 +773,7 @@ static u8 parse_subframe(struct sk_buff *skb,
/* just for debug purpose */
SeqNum = WLAN_GET_SEQ_SEQ(le16_to_cpu(hdr->seq_ctl));
- if ((IEEE80211_QOS_HAS_SEQ(fc))&&\
+ if ((IEEE80211_QOS_HAS_SEQ(fc)) && \
(((frameqos *)(skb->data + IEEE80211_3ADDR_LEN))->field.reserved)) {
bIsAggregateFrame = true;
}
@@ -1092,7 +1092,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
ieee->iw_mode == IW_MODE_REPEAT) &&
!from_assoc_ap) {
switch (hostap_handle_sta_rx(ieee, dev, skb, rx_stats,
- wds != NULL)) {
+ wds)) {
case AP_RX_CONTINUE_NOT_AUTHORIZED:
case AP_RX_CONTINUE:
break;
@@ -1109,7 +1109,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
if (stype != IEEE80211_STYPE_DATA &&
stype != IEEE80211_STYPE_DATA_CFACK &&
stype != IEEE80211_STYPE_DATA_CFPOLL &&
- stype != IEEE80211_STYPE_DATA_CFACKPOLL&&
+ stype != IEEE80211_STYPE_DATA_CFACKPOLL &&
stype != IEEE80211_STYPE_QOS_DATA//add by David,2006.8.4
) {
if (stype != IEEE80211_STYPE_NULLFUNC)
@@ -1311,7 +1311,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
stats->multicast++;
}
- /* Indicat the packets to upper layer */
+ /* Indicate the packets to upper layer */
sub_skb->protocol = eth_type_trans(sub_skb, dev);
memset(sub_skb->cb, 0, sizeof(sub_skb->cb));
sub_skb->dev = dev;
@@ -1388,7 +1388,7 @@ static int ieee80211_read_qos_param_element(struct ieee80211_qos_parameter_info
int ret = 0;
u16 size = sizeof(struct ieee80211_qos_parameter_info) - 2;
- if ((info_element == NULL) || (element_param == NULL))
+ if (!info_element || !element_param)
return -1;
if (info_element->id == QOS_ELEMENT_ID && info_element->len == size) {
@@ -2508,7 +2508,7 @@ static inline void ieee80211_process_probe_response(
list_for_each_entry(target, &ieee->network_list, list) {
if (is_same_network(target, network, ieee))
break;
- if ((oldest == NULL) ||
+ if (!oldest ||
(target->last_scanned < oldest->last_scanned))
oldest = target;
}
@@ -2565,7 +2565,7 @@ static inline void ieee80211_process_probe_response(
// printk("====>2 network->ssid=%s FLAG=%d target.ssid=%s FLAG=%d\n", network->ssid, network->flags, target->ssid, target->flags);
if(((network->flags & NETWORK_EMPTY_ESSID) == NETWORK_EMPTY_ESSID) \
&& (((network->ssid_len > 0) && (strncmp(target->ssid, network->ssid, network->ssid_len)))\
- ||((ieee->current_network.ssid_len == network->ssid_len)&&(strncmp(ieee->current_network.ssid, network->ssid, network->ssid_len) == 0)&&(ieee->state == IEEE80211_NOLINK))))
+ ||((ieee->current_network.ssid_len == network->ssid_len) && (strncmp(ieee->current_network.ssid, network->ssid, network->ssid_len) == 0) && (ieee->state == IEEE80211_NOLINK))))
renew = 1;
//YJ,add,080819,for hidden ap,end
@@ -2575,11 +2575,10 @@ static inline void ieee80211_process_probe_response(
}
spin_unlock_irqrestore(&ieee->lock, flags);
- if (is_beacon(beacon->header.frame_ctl)&&is_same_network(&ieee->current_network, network, ieee)&&\
+ if (is_beacon(beacon->header.frame_ctl) && is_same_network(&ieee->current_network, network, ieee) && \
(ieee->state == IEEE80211_LINKED)) {
- if (ieee->handle_beacon != NULL) {
+ if (ieee->handle_beacon)
ieee->handle_beacon(ieee->dev,beacon,&ieee->current_network);
- }
}
out:
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
index 944c8894f9ff..e0da0900a4f7 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
@@ -1796,7 +1796,7 @@ static void ieee80211_process_action(struct ieee80211_device *ieee,
u8 *act = ieee80211_get_payload(header);
u8 tmp = 0;
// IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len);
- if (act == NULL) {
+ if (!act) {
IEEE80211_DEBUG(IEEE80211_DL_ERR, "error to get payload of action frame\n");
return;
}
@@ -1929,7 +1929,7 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
memcpy(ieee->pHTInfo->PeerHTCapBuf, network->bssht.bdHTCapBuf, network->bssht.bdHTCapLen);
memcpy(ieee->pHTInfo->PeerHTInfoBuf, network->bssht.bdHTInfoBuf, network->bssht.bdHTInfoLen);
}
- if (ieee->handle_assoc_response != NULL)
+ if (ieee->handle_assoc_response)
ieee->handle_assoc_response(ieee->dev, (struct ieee80211_assoc_response_frame *)header, network);
}
ieee80211_associate_complete(ieee);
@@ -2659,14 +2659,13 @@ static int ieee80211_wpa_set_wpa_ie(struct ieee80211_device *ieee,
{
u8 *buf;
- if (param->u.wpa_ie.len > MAX_WPA_IE_LEN ||
- (param->u.wpa_ie.len && param->u.wpa_ie.data == NULL))
+ if (param->u.wpa_ie.len > MAX_WPA_IE_LEN)
return -EINVAL;
if (param->u.wpa_ie.len) {
buf = kmemdup(param->u.wpa_ie.data, param->u.wpa_ie.len,
GFP_KERNEL);
- if (buf == NULL)
+ if (!buf)
return -ENOMEM;
kfree(ieee->wpa_ie);
@@ -2856,7 +2855,7 @@ static int ieee80211_wpa_set_encryption(struct ieee80211_device *ieee,
goto done;
}
- if (*crypt == NULL || (*crypt)->ops != ops) {
+ if (!*crypt || (*crypt)->ops != ops) {
struct ieee80211_crypt_data *new_crypt;
ieee80211_crypt_delayed_deinit(ieee, crypt);
@@ -2871,7 +2870,7 @@ static int ieee80211_wpa_set_encryption(struct ieee80211_device *ieee,
new_crypt->priv =
new_crypt->ops->init(param->u.crypt.idx);
- if (new_crypt->priv == NULL) {
+ if (!new_crypt->priv) {
kfree(new_crypt);
param->u.crypt.err = IEEE_CRYPT_ERR_CRYPT_INIT_FAILED;
ret = -EINVAL;
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c
index aab1586fe0dd..4a8d16a45fc5 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c
@@ -244,9 +244,9 @@ int ieee80211_wx_set_rts(struct ieee80211_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- if (wrqu->rts.disabled || !wrqu->rts.fixed)
+ if (wrqu->rts.disabled || !wrqu->rts.fixed) {
ieee->rts = DEFAULT_RTS_THRESHOLD;
- else {
+ } else {
if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
wrqu->rts.value > MAX_RTS_THRESHOLD)
return -EINVAL;
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
index 8e1ec4409b4f..fc6eb97801e1 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
@@ -169,8 +169,7 @@ int ieee80211_encrypt_fragment(
struct ieee80211_crypt_data *crypt = ieee->crypt[ieee->tx_keyidx];
int res;
- if (!(crypt && crypt->ops))
- {
+ if (!(crypt && crypt->ops)) {
printk("=========>%s(), crypt is null\n", __func__);
return -1;
}
@@ -309,32 +308,25 @@ static void ieee80211_tx_query_agg_cap(struct ieee80211_device *ieee,
if (!Adapter->HalFunc.GetNmodeSupportBySecCfgHandler(Adapter))
return;
#endif
- if (!ieee->GetNmodeSupportBySecCfg(ieee->dev))
- {
+ if (!ieee->GetNmodeSupportBySecCfg(ieee->dev)) {
return;
}
- if (pHTInfo->bCurrentAMPDUEnable)
- {
- if (!GetTs(ieee, (struct ts_common_info **)(&pTxTs), hdr->addr1, skb->priority, TX_DIR, true))
- {
+ if (pHTInfo->bCurrentAMPDUEnable) {
+ if (!GetTs(ieee, (struct ts_common_info **)(&pTxTs), hdr->addr1, skb->priority, TX_DIR, true)) {
printk("===>can't get TS\n");
return;
}
- if (!pTxTs->tx_admitted_ba_record.valid)
- {
+ if (!pTxTs->tx_admitted_ba_record.valid) {
TsStartAddBaProcess(ieee, pTxTs);
goto FORCED_AGG_SETTING;
- }
- else if (!pTxTs->using_ba)
- {
+ } else if (!pTxTs->using_ba) {
if (SN_LESS(pTxTs->tx_admitted_ba_record.start_seq_ctrl.field.seq_num, (pTxTs->tx_cur_seq + 1) % 4096))
pTxTs->using_ba = true;
else
goto FORCED_AGG_SETTING;
}
- if (ieee->iw_mode == IW_MODE_INFRA)
- {
+ if (ieee->iw_mode == IW_MODE_INFRA) {
tcb_desc->bAMPDUEnable = true;
tcb_desc->ampdu_factor = pHTInfo->CurrentAMPDUFactor;
tcb_desc->ampdu_density = pHTInfo->CurrentMPDUDensity;
@@ -366,12 +358,9 @@ static void ieee80211_qurey_ShortPreambleMode(struct ieee80211_device *ieee,
struct cb_desc *tcb_desc)
{
tcb_desc->bUseShortPreamble = false;
- if (tcb_desc->data_rate == 2)
- {//// 1M can only use Long Preamble. 11B spec
+ if (tcb_desc->data_rate == 2) {//// 1M can only use Long Preamble. 11B spec
return;
- }
- else if (ieee->current_network.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
- {
+ } else if (ieee->current_network.capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {
tcb_desc->bUseShortPreamble = true;
}
return;
@@ -386,8 +375,7 @@ ieee80211_query_HTCapShortGI(struct ieee80211_device *ieee, struct cb_desc *tcb_
if (!pHTInfo->bCurrentHTSupport||!pHTInfo->bEnableHT)
return;
- if (pHTInfo->bForcedShortGI)
- {
+ if (pHTInfo->bForcedShortGI) {
tcb_desc->bUseShortGI = true;
return;
}
@@ -535,27 +523,25 @@ static void ieee80211_txrate_selectmode(struct ieee80211_device *ieee,
struct cb_desc *tcb_desc)
{
#ifdef TO_DO_LIST
- if(!IsDataFrame(pFrame))
- {
+ if (!IsDataFrame(pFrame)) {
pTcb->bTxDisableRateFallBack = true;
pTcb->bTxUseDriverAssingedRate = true;
pTcb->RATRIndex = 7;
return;
}
- if(pMgntInfo->ForcedDataRate!= 0)
- {
+ if (pMgntInfo->ForcedDataRate!= 0) {
pTcb->bTxDisableRateFallBack = true;
pTcb->bTxUseDriverAssingedRate = true;
return;
}
#endif
- if(ieee->bTxDisableRateFallBack)
+ if (ieee->bTxDisableRateFallBack)
tcb_desc->bTxDisableRateFallBack = true;
- if(ieee->bTxUseDriverAssingedRate)
+ if (ieee->bTxUseDriverAssingedRate)
tcb_desc->bTxUseDriverAssingedRate = true;
- if(!tcb_desc->bTxDisableRateFallBack || !tcb_desc->bTxUseDriverAssingedRate)
+ if (!tcb_desc->bTxDisableRateFallBack || !tcb_desc->bTxUseDriverAssingedRate)
{
if (ieee->iw_mode == IW_MODE_INFRA || ieee->iw_mode == IW_MODE_ADHOC)
tcb_desc->RATRIndex = 0;
@@ -614,7 +600,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
}
- if(likely(ieee->raw_tx == 0)){
+ if (likely(ieee->raw_tx == 0)) {
if (unlikely(skb->len < SNAP_SIZE + sizeof(u16))) {
printk(KERN_WARNING "%s: skb too small (%d).\n",
ieee->dev->name, skb->len);
@@ -690,15 +676,13 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
if (is_multicast_ether_addr(header.addr1)) {
frag_size = MAX_FRAG_THRESHOLD;
qos_ctl |= QOS_CTL_NOTCONTAIN_ACK;
- }
- else {
+ } else {
frag_size = ieee->fts;//default:392
qos_ctl = 0;
}
//if (ieee->current_network.QoS_Enable)
- if(qos_actived)
- {
+ if (qos_actived) {
hdr_len = IEEE80211_3ADDR_LEN + 2;
skb->priority = ieee80211_classify(skb, &ieee->current_network);
@@ -746,12 +730,10 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
txb->payload_size = __cpu_to_le16(bytes);
//if (ieee->current_network.QoS_Enable)
- if(qos_actived)
- {
+ if (qos_actived)
txb->queue_index = UP2AC(skb->priority);
- } else {
+ else
txb->queue_index = WME_AC_BK;
- }
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c
index dead134f6de0..be08cd1d37a7 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c
@@ -243,8 +243,7 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
list_for_each_entry(network, &ieee->network_list, list) {
i++;
- if((stop-ev)<200)
- {
+ if((stop-ev)<200) {
err = -E2BIG;
break;
}
@@ -312,7 +311,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
/* Check all the keys to see if any are still configured,
* and if no key index was provided, de-init them all */
for (i = 0; i < WEP_KEYS; i++) {
- if (ieee->crypt[i] != NULL) {
+ if (ieee->crypt[i]) {
if (key_provided)
break;
ieee80211_crypt_delayed_deinit(
@@ -334,14 +333,14 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
sec.enabled = 1;
sec.flags |= SEC_ENABLED;
- if (*crypt != NULL && (*crypt)->ops != NULL &&
+ if (*crypt && (*crypt)->ops &&
strcmp((*crypt)->ops->name, "WEP") != 0) {
/* changing to use WEP; deinit previously used algorithm
* on this key */
ieee80211_crypt_delayed_deinit(ieee, crypt);
}
- if (*crypt == NULL) {
+ if (!*crypt) {
struct ieee80211_crypt_data *new_crypt;
/* take WEP into use */
@@ -469,7 +468,7 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
crypt = ieee->crypt[key];
erq->flags = key + 1;
- if (crypt == NULL || crypt->ops == NULL) {
+ if (!crypt || !crypt->ops) {
erq->length = 0;
erq->flags |= IW_ENCODE_DISABLED;
return 0;
@@ -538,7 +537,7 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
for (i = 0; i < WEP_KEYS; i++)
- if (ieee->crypt[i] != NULL)
+ if (ieee->crypt[i])
break;
@@ -583,7 +582,7 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
goto done;
}
- if (*crypt == NULL || (*crypt)->ops != ops) {
+ if (!*crypt || (*crypt)->ops != ops) {
struct ieee80211_crypt_data *new_crypt;
ieee80211_crypt_delayed_deinit(ieee, crypt);
@@ -596,7 +595,7 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
new_crypt->ops = ops;
if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
new_crypt->priv = new_crypt->ops->init(idx);
- if (new_crypt->priv == NULL) {
+ if (!new_crypt->priv) {
kfree(new_crypt);
ret = -EINVAL;
goto done;
@@ -684,7 +683,7 @@ int ieee80211_wx_get_encode_ext(struct ieee80211_device *ieee,
encoding->flags = idx + 1;
memset(ext, 0, sizeof(*ext));
- if (crypt == NULL || crypt->ops == NULL ) {
+ if (!crypt || !crypt->ops) {
ext->alg = IW_ENCODE_ALG_NONE;
ext->key_len = 0;
encoding->flags |= IW_ENCODE_DISABLED;
@@ -761,8 +760,7 @@ int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
} else if (data->value & IW_AUTH_ALG_LEAP) {
ieee->open_wep = 1;
ieee->auth_mode = 2;
- }
- else
+ } else
return -EINVAL;
break;
@@ -787,28 +785,24 @@ int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
{
u8 *buf;
- if (len>MAX_WPA_IE_LEN || (len && ie == NULL))
- {
+ if (len>MAX_WPA_IE_LEN || (len && !ie)) {
// printk("return error out, len:%d\n", len);
return -EINVAL;
}
- if (len)
- {
- if (len != ie[1]+2)
- {
+ if (len) {
+ if (len != ie[1]+2) {
printk("len:%zu, ie:%d\n", len, ie[1]);
return -EINVAL;
}
buf = kmemdup(ie, len, GFP_KERNEL);
- if (buf == NULL)
+ if (!buf)
return -ENOMEM;
kfree(ieee->wpa_ie);
ieee->wpa_ie = buf;
ieee->wpa_ie_len = len;
- }
- else{
+ } else {
kfree(ieee->wpa_ie);
ieee->wpa_ie = NULL;
ieee->wpa_ie_len = 0;
diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
index 7cac668bfb0b..59d179ae7ad2 100644
--- a/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
+++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
@@ -51,7 +51,7 @@ static void RxPktPendingTimeout(struct timer_list *t)
if (SN_EQUAL(pReorderEntry->SeqNum, pRxTs->rx_indicate_seq))
pRxTs->rx_indicate_seq = (pRxTs->rx_indicate_seq + 1) % 4096;
- IEEE80211_DEBUG(IEEE80211_DL_REORDER, "RxPktPendingTimeout(): IndicateSeq: %d\n", pReorderEntry->SeqNum);
+ IEEE80211_DEBUG(IEEE80211_DL_REORDER, "%s: IndicateSeq: %d\n", __func__, pReorderEntry->SeqNum);
ieee->stats_IndicateArray[index] = pReorderEntry->prxb;
index++;
@@ -97,7 +97,7 @@ static void TsAddBaProcess(struct timer_list *t)
struct ieee80211_device *ieee = container_of(pTxTs, struct ieee80211_device, TxTsRecord[num]);
TsInitAddBA(ieee, pTxTs, BA_POLICY_IMMEDIATE, false);
- IEEE80211_DEBUG(IEEE80211_DL_BA, "TsAddBaProcess(): ADDBA Req is started!! \n");
+ IEEE80211_DEBUG(IEEE80211_DL_BA, "%s: ADDBA Req is started!! \n", __func__);
}
@@ -456,7 +456,7 @@ void RemovePeerTS(struct ieee80211_device *ieee, u8 *Addr)
{
struct ts_common_info *pTS, *pTmpTS;
- printk("===========>RemovePeerTS,%pM\n", Addr);
+ printk("===========>%s,%pM\n", __func__, Addr);
list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, list) {
if (memcmp(pTS->addr, Addr, 6) == 0) {
RemoveTsEntry(ieee, pTS, TX_DIR);
@@ -525,11 +525,11 @@ void TsStartAddBaProcess(struct ieee80211_device *ieee, struct tx_ts_record *pTx
if (!pTxTS->add_ba_req_in_progress) {
pTxTS->add_ba_req_in_progress = true;
if (pTxTS->add_ba_req_delayed) {
- IEEE80211_DEBUG(IEEE80211_DL_BA, "TsStartAddBaProcess(): Delayed Start ADDBA after 60 sec!!\n");
+ IEEE80211_DEBUG(IEEE80211_DL_BA, "%s: Delayed Start ADDBA after 60 sec!!\n", __func__);
mod_timer(&pTxTS->ts_add_ba_timer,
jiffies + msecs_to_jiffies(TS_ADDBA_DELAY));
} else {
- IEEE80211_DEBUG(IEEE80211_DL_BA, "TsStartAddBaProcess(): Immediately Start ADDBA now!!\n");
+ IEEE80211_DEBUG(IEEE80211_DL_BA, "%s: Immediately Start ADDBA now!!\n", __func__);
mod_timer(&pTxTS->ts_add_ba_timer, jiffies+10); //set 10 ticks
}
} else {
diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c
index 4065a4710142..fe1f279ca368 100644
--- a/drivers/staging/rtl8192u/r8192U_core.c
+++ b/drivers/staging/rtl8192u/r8192U_core.c
@@ -713,7 +713,7 @@ static u32 get_rxpacket_shiftbytes_819xusb(struct ieee80211_rx_stats *pstats)
+ pstats->RxBufShift);
}
-static int rtl8192_rx_initiate(struct net_device *dev)
+void rtl8192_rx_enable(struct net_device *dev)
{
struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev);
struct urb *entry;
@@ -763,8 +763,6 @@ static int rtl8192_rx_initiate(struct net_device *dev)
skb_queue_tail(&priv->rx_queue, skb);
usb_submit_urb(entry, GFP_KERNEL);
}
-
- return 0;
}
void rtl8192_set_rxconf(struct net_device *dev)
@@ -810,12 +808,6 @@ void rtl8192_set_rxconf(struct net_device *dev)
write_nic_dword(dev, RCR, rxconf);
}
-/* wait to be removed */
-void rtl8192_rx_enable(struct net_device *dev)
-{
- rtl8192_rx_initiate(dev);
-}
-
void rtl8192_rtx_disable(struct net_device *dev)
{
u8 cmd;
diff --git a/drivers/staging/rtl8192u/r8192U_dm.c b/drivers/staging/rtl8192u/r8192U_dm.c
index 2ba01041406b..ade14ef05730 100644
--- a/drivers/staging/rtl8192u/r8192U_dm.c
+++ b/drivers/staging/rtl8192u/r8192U_dm.c
@@ -99,8 +99,7 @@ static void dm_dynamic_txpower(struct net_device *dev);
static void dm_send_rssi_tofw(struct net_device *dev);
static void dm_ctstoself(struct net_device *dev);
/*---------------------------Define function prototype------------------------*/
-/*
- * ================================================================================
+/* ================================================================================
* HW Dynamic mechanism interface.
* ================================================================================
*
@@ -178,8 +177,7 @@ void dm_CheckRxAggregation(struct net_device *dev)
ulValue = (pHTInfo->UsbRxFwAggrEn<<24) | (pHTInfo->UsbRxFwAggrPageNum<<16) |
(pHTInfo->UsbRxFwAggrPacketNum<<8) | (pHTInfo->UsbRxFwAggrTimeout);
- /*
- * If usb rx firmware aggregation is enabled,
+ /* If usb rx firmware aggregation is enabled,
* when anyone of three threshold conditions above is reached,
* firmware will send aggregated packet to driver.
*/
@@ -219,8 +217,7 @@ void hal_dm_watchdog(struct net_device *dev)
#endif
} /* HalDmWatchDog */
-/*
- * Decide Rate Adaptive Set according to distance (signal strength)
+/* Decide Rate Adaptive Set according to distance (signal strength)
* 01/11/2008 MHC Modify input arguments and RATR table level.
* 01/16/2008 MHC RF_Type is assigned in ReadAdapterInfo(). We must call
* the function after making sure RF_Type.
@@ -246,8 +243,7 @@ void init_rate_adaptive(struct net_device *dev)
pra->ping_rssi_thresh_for_ra = 15;
if (priv->rf_type == RF_2T4R) {
- /*
- * 07/10/08 MH Modify for RA smooth scheme.
+ /* 07/10/08 MH Modify for RA smooth scheme.
* 2008/01/11 MH Modify 2T RATR table for different RSSI. 080515 porting by amy from windows code.
*/
pra->upper_rssi_threshold_ratr = 0x8f0f0000;
@@ -336,9 +332,10 @@ static void dm_check_rate_adaptive(struct net_device *dev)
((bshort_gi_enabled) ? BIT(31) : 0);
/* 2007/10/08 MH We support RA smooth scheme now. When it is the first
- time to link with AP. We will not change upper/lower threshold. If
- STA stay in high or low level, we must change two different threshold
- to prevent jumping frequently. */
+ * time to link with AP. We will not change upper/lower threshold. If
+ * STA stay in high or low level, we must change two different threshold
+ * to prevent jumping frequently.
+ */
if (pra->ratr_state == DM_RATR_STA_HIGH) {
HighRSSIThreshForRA = pra->high2low_rssi_thresh_for_ra;
LowRSSIThreshForRA = (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) ?
@@ -387,8 +384,7 @@ static void dm_check_rate_adaptive(struct net_device *dev)
}
}
- /*
- * 2008.04.01
+ /* 2008.04.01
* For RTL819X, if pairwisekey = wep/tkip, we support only MCS0~7.
*/
if (priv->ieee80211->GetHalfNmodeSupportByAPsHandler(dev))
@@ -683,8 +679,7 @@ static void dm_TXPowerTrackingCallback_ThermalMeter(struct net_device *dev)
return;
}
- /*
- * ==========================
+ /* ==========================
* this is only for test, should be masked
* ==========================
*/
@@ -850,8 +845,7 @@ static void dm_InitializeTXPowerTracking_TSSI(struct net_device *dev)
priv->txbbgain_table[36].txbb_iq_amplifygain = -24;
priv->txbbgain_table[36].txbbgain_value = 0x10000040;
- /*
- * ccktxbb_valuearray[0] is 0xA22 [1] is 0xA24 ...[7] is 0xA29
+ /* ccktxbb_valuearray[0] is 0xA22 [1] is 0xA24 ...[7] is 0xA29
* This Table is for CH1~CH13
*/
priv->cck_txbbgain_table[0].ccktxbb_valuearray[0] = 0x36;
@@ -1061,8 +1055,7 @@ static void dm_InitializeTXPowerTracking_TSSI(struct net_device *dev)
priv->cck_txbbgain_table[22].ccktxbb_valuearray[6] = 0x03;
priv->cck_txbbgain_table[22].ccktxbb_valuearray[7] = 0x01;
- /*
- * ccktxbb_valuearray[0] is 0xA22 [1] is 0xA24 ...[7] is 0xA29
+ /* ccktxbb_valuearray[0] is 0xA22 [1] is 0xA24 ...[7] is 0xA29
* This Table is for CH14
*/
priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[0] = 0x36;
@@ -1282,8 +1275,7 @@ static void dm_InitializeTXPowerTracking_ThermalMeter(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
- /*
- * Tx Power tracking by Thermal Meter requires Firmware R/W 3-wire. This mechanism
+ /* Tx Power tracking by Thermal Meter requires Firmware R/W 3-wire. This mechanism
* can be enabled only when Firmware R/W 3-wire is enabled. Otherwise, frequent r/w
* 3-wire by driver causes RF to go into a wrong state.
*/
@@ -1330,8 +1322,7 @@ static void dm_CheckTXPowerTracking_ThermalMeter(struct net_device *dev)
}
if (!TM_Trigger) {
- /*
- * Attention!! You have to write all 12bits of data to RF, or it may cause RF to crash
+ /* Attention!! You have to write all 12bits of data to RF, or it may cause RF to crash
* actually write reg0x02 bit1=0, then bit1=1.
* DbgPrint("Trigger ThermalMeter, write RF reg0x2 = 0x4d to 0x4f\n");
*/
@@ -1563,18 +1554,6 @@ static void dm_bb_initialgain_restore(struct net_device *dev)
} /* dm_BBInitialGainRestore */
-void dm_backup_dynamic_mechanism_state(struct net_device *dev)
-{
- struct r8192_priv *priv = ieee80211_priv(dev);
-
- /* Fsync to avoid reset */
- priv->bswitch_fsync = false;
- priv->bfsync_processing = false;
- /* Backup BB InitialGain */
- dm_bb_initialgain_backup(dev);
-
-} /* DM_BackupDynamicMechanismState */
-
static void dm_bb_initialgain_backup(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
@@ -1748,10 +1727,12 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm(
pHalData->UndecoratedSmoothedPWDB, DM_DigTable.RssiLowThresh,
DM_DigTable.RssiHighThresh, DM_DigTable.Dig_State);*/
/* 1. When RSSI decrease, We have to judge if it is smaller than a threshold
- and then execute the step below. */
+ * and then execute the step below.
+ */
if (priv->undecorated_smoothed_pwdb <= dm_digtable.rssi_low_thresh) {
/* 2008/02/05 MH When we execute silent reset, the DIG PHY parameters
- will be reset to init value. We must prevent the condition. */
+ * will be reset to init value. We must prevent the condition.
+ */
if (dm_digtable.dig_state == DM_STA_DIG_OFF &&
(priv->reset_count == reset_cnt)) {
return;
@@ -1773,8 +1754,7 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm(
/* 1.3 Lower PD_TH for OFDM. */
if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) {
- /*
- * 2008/01/11 MH 40MHZ 90/92 register are not the same.
+ /* 2008/01/11 MH 40MHZ 90/92 register are not the same.
* 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same.
*/
write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x00);
@@ -1797,7 +1777,8 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm(
}
/* 2. When RSSI increase, We have to judge if it is larger than a threshold
- and then execute the step below. */
+ * and then execute the step below.
+ */
if (priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_thresh) {
u8 reset_flag = 0;
@@ -1814,8 +1795,7 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm(
dm_digtable.dig_state = DM_STA_DIG_ON;
/*DbgPrint("DIG ON\n\r");*/
- /*
- * 2.1 Set initial gain.
+ /* 2.1 Set initial gain.
* 2008/02/26 MH SD3-Jerry suggest to prevent dirty environment.
*/
if (reset_flag == 1) {
@@ -1832,8 +1812,7 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm(
/* 2.2 Higher PD_TH for OFDM. */
if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) {
- /*
- * 2008/01/11 MH 40MHZ 90/92 register are not the same.
+ /* 2008/01/11 MH 40MHZ 90/92 register are not the same.
* 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same.
*/
write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20);
@@ -1850,8 +1829,7 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm(
/* 2.3 Higher CS ratio for CCK. */
write_nic_byte(dev, 0xa0a, 0xcd);
- /*
- * 2.4 Lower EDCCA.
+ /* 2.4 Lower EDCCA.
* 2008/01/11 MH 90/92 series are the same.
*/
/*PlatformEFIOWrite4Byte(pAdapter, rOFDM0_ECCAThreshold, 0x346);*/
@@ -1892,8 +1870,7 @@ static void dm_ctrl_initgain_byrssi_highpwr(
(priv->undecorated_smoothed_pwdb < dm_digtable.rssi_high_power_highthresh))
return;
- /*
- * 3. When RSSI >75% or <70%, it is a high power issue. We have to judge if
+ /* 3. When RSSI >75% or <70%, it is a high power issue. We have to judge if
* it is larger than a threshold and then execute the step below.
*
* 2008/02/05 MH SD3-Jerry Modify PD_TH for high power issue.
@@ -2042,8 +2019,7 @@ static void dm_pd_th(
if (dm_digtable.curpd_thstate == DIG_PD_AT_LOW_POWER) {
/* Lower PD_TH for OFDM. */
if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) {
- /*
- * 2008/01/11 MH 40MHZ 90/92 register are not the same.
+ /* 2008/01/11 MH 40MHZ 90/92 register are not the same.
* 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same.
*/
write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x00);
@@ -2055,8 +2031,7 @@ static void dm_pd_th(
} else if (dm_digtable.curpd_thstate == DIG_PD_AT_NORMAL_POWER) {
/* Higher PD_TH for OFDM. */
if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) {
- /*
- * 2008/01/11 MH 40MHZ 90/92 register are not the same.
+ /* 2008/01/11 MH 40MHZ 90/92 register are not the same.
* 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same.
*/
write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20);
@@ -2155,8 +2130,7 @@ static void dm_check_edca_turbo(
unsigned long curTxOkCnt = 0;
unsigned long curRxOkCnt = 0;
- /*
- * Do not be Turbo if it's under WiFi config and Qos Enabled, because the EDCA parameters
+ /* Do not be Turbo if it's under WiFi config and Qos Enabled, because the EDCA parameters
* should follow the settings from QAP. By Bruce, 2007-12-07.
*/
if (priv->ieee80211->state != IEEE80211_LINKED)
@@ -2188,8 +2162,7 @@ static void dm_check_edca_turbo(
priv->bcurrent_turbo_EDCA = true;
} else {
- /*
- * Turn Off EDCA turbo here.
+ /* Turn Off EDCA turbo here.
* Restore original EDCA according to the declaration of AP.
*/
if (priv->bcurrent_turbo_EDCA) {
@@ -2219,8 +2192,7 @@ static void dm_check_edca_turbo(
write_nic_dword(dev, EDCAPARA_BE, u4bAcParam);
- /*
- * Check ACM bit.
+ /* Check ACM bit.
* If it is set, immediately set ACM control bit to downgrading AC for passing WMM testplan. Annie, 2005-12-13.
*/
{
@@ -2272,11 +2244,10 @@ static void dm_ctstoself(struct net_device *dev)
pHTInfo->IOTAction &= ~HT_IOT_ACT_FORCED_CTS2SELF;
return;
}
- /*
- 1. Uplink
- 2. Linksys350/Linksys300N
- 3. <50 disable, >55 enable
- */
+ /* 1. Uplink
+ * 2. Linksys350/Linksys300N
+ * 3. <50 disable, >55 enable
+ */
if (pHTInfo->IOTPeer == HT_IOT_PEER_BROADCOM) {
curTxOkCnt = priv->stats.txbytesunicast - lastTxOkCnt;
@@ -2319,8 +2290,7 @@ static void dm_check_pbc_gpio(struct net_device *dev)
return;
if (tmp1byte & BIT(6) || tmp1byte & BIT(0)) {
- /*
- * Here we only set bPbcPressed to TRUE
+ /* Here we only set bPbcPressed to TRUE
* After trigger PBC, the variable will be set to FALSE
*/
RT_TRACE(COMP_IO, "CheckPbcGPIO - PBC is pressed\n");
@@ -2354,7 +2324,8 @@ void dm_rf_pathcheck_workitemcallback(struct work_struct *work)
u8 rfpath = 0, i;
/* 2008/01/30 MH After discussing with SD3 Jerry, 0xc04/0xd04 register will
- always be the same. We only read 0xc04 now. */
+ * always be the same. We only read 0xc04 now.
+ */
read_nic_byte(dev, 0xc04, &rfpath);
/* Check Bit 0-3, it means if RF A-D is enabled. */
@@ -2529,8 +2500,7 @@ static void dm_rxpath_sel_byrssi(struct net_device *dev)
}
}
- /*
- * Set CCK Rx path
+ /* Set CCK Rx path
* reg0xA07[3:2]=cck default rx path, reg0xa07[1:0]=cck optional rx path.
*/
update_cck_rx_path = 0;
@@ -3049,8 +3019,7 @@ static void dm_send_rssi_tofw(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
- /*
- * If we test chariot, we should stop the TX command ?
+ /* If we test chariot, we should stop the TX command ?
* Because 92E will always silent reset when we send tx command. We use register
* 0x1e0(byte) to notify driver.
*/
diff --git a/drivers/staging/rtl8192u/r8192U_dm.h b/drivers/staging/rtl8192u/r8192U_dm.h
index 0de0332906bd..0b2a1c688597 100644
--- a/drivers/staging/rtl8192u/r8192U_dm.h
+++ b/drivers/staging/rtl8192u/r8192U_dm.h
@@ -161,7 +161,6 @@ void hal_dm_watchdog(struct net_device *dev);
void init_rate_adaptive(struct net_device *dev);
void dm_txpower_trackingcallback(struct work_struct *work);
void dm_restore_dynamic_mechanism_state(struct net_device *dev);
-void dm_backup_dynamic_mechanism_state(struct net_device *dev);
void dm_force_tx_fw_info(struct net_device *dev,
u32 force_type, u32 force_value);
void dm_init_edca_turbo(struct net_device *dev);
diff --git a/drivers/staging/rtl8712/drv_types.h b/drivers/staging/rtl8712/drv_types.h
index 9ae86631fa8b..0c4325073c63 100644
--- a/drivers/staging/rtl8712/drv_types.h
+++ b/drivers/staging/rtl8712/drv_types.h
@@ -148,14 +148,9 @@ struct _adapter {
bool driver_stopped;
bool surprise_removed;
bool suspended;
- u32 IsrContent;
- u32 ImrContent;
- u8 EepromAddressSize;
+ u8 eeprom_address_size;
u8 hw_init_completed;
- struct task_struct *cmdThread;
- pid_t evtThread;
- struct task_struct *xmitThread;
- pid_t recvThread;
+ struct task_struct *cmd_thread;
uint (*dvobj_init)(struct _adapter *adapter);
void (*dvobj_deinit)(struct _adapter *adapter);
struct net_device *pnetdev;
@@ -163,9 +158,9 @@ struct _adapter {
struct net_device_stats stats;
struct iw_statistics iwstats;
int pid; /*process id from UI*/
- struct work_struct wkFilterRxFF0;
+ struct work_struct wk_filter_rx_ff0;
u8 blnEnableRxFF0Filter;
- spinlock_t lockRxFF0Filter;
+ spinlock_t lock_rx_ff0_filter;
const struct firmware *fw;
struct usb_interface *pusb_intf;
struct mutex mutex_start;
diff --git a/drivers/staging/rtl8712/hal_init.c b/drivers/staging/rtl8712/hal_init.c
index 401f0e442bcf..40145c0338e4 100644
--- a/drivers/staging/rtl8712/hal_init.c
+++ b/drivers/staging/rtl8712/hal_init.c
@@ -31,21 +31,21 @@
static void rtl871x_load_fw_cb(const struct firmware *firmware, void *context)
{
- struct _adapter *padapter = context;
+ struct _adapter *adapter = context;
- complete(&padapter->rtl8712_fw_ready);
+ complete(&adapter->rtl8712_fw_ready);
if (!firmware) {
- struct usb_device *udev = padapter->dvobjpriv.pusbdev;
- struct usb_interface *pusb_intf = padapter->pusb_intf;
+ struct usb_device *udev = adapter->dvobjpriv.pusbdev;
+ struct usb_interface *usb_intf = adapter->pusb_intf;
dev_err(&udev->dev, "r8712u: Firmware request failed\n");
usb_put_dev(udev);
- usb_set_intfdata(pusb_intf, NULL);
+ usb_set_intfdata(usb_intf, NULL);
return;
}
- padapter->fw = firmware;
+ adapter->fw = firmware;
/* firmware available - start netdev */
- register_netdev(padapter->pnetdev);
+ register_netdev(adapter->pnetdev);
}
static const char firmware_file[] = "rtlwifi/rtl8712u.bin";
@@ -65,47 +65,47 @@ int rtl871x_load_fw(struct _adapter *padapter)
}
MODULE_FIRMWARE("rtlwifi/rtl8712u.bin");
-static u32 rtl871x_open_fw(struct _adapter *padapter, const u8 **ppmappedfw)
+static u32 rtl871x_open_fw(struct _adapter *adapter, const u8 **mappedfw)
{
- const struct firmware **praw = &padapter->fw;
+ const struct firmware **raw = &adapter->fw;
- if (padapter->fw->size > 200000) {
- dev_err(&padapter->pnetdev->dev, "r8172u: Badfw->size of %d\n",
- (int)padapter->fw->size);
+ if (adapter->fw->size > 200000) {
+ dev_err(&adapter->pnetdev->dev, "r8172u: Badfw->size of %d\n",
+ (int)adapter->fw->size);
return 0;
}
- *ppmappedfw = (*praw)->data;
- return (*praw)->size;
+ *mappedfw = (*raw)->data;
+ return (*raw)->size;
}
-static void fill_fwpriv(struct _adapter *padapter, struct fw_priv *pfwpriv)
+static void fill_fwpriv(struct _adapter *adapter, struct fw_priv *fwpriv)
{
- struct dvobj_priv *pdvobj = &padapter->dvobjpriv;
- struct registry_priv *pregpriv = &padapter->registrypriv;
+ struct dvobj_priv *dvobj = &adapter->dvobjpriv;
+ struct registry_priv *regpriv = &adapter->registrypriv;
- memset(pfwpriv, 0, sizeof(struct fw_priv));
+ memset(fwpriv, 0, sizeof(struct fw_priv));
/* todo: check if needs endian conversion */
- pfwpriv->hci_sel = RTL8712_HCI_TYPE_72USB;
- pfwpriv->usb_ep_num = (u8)pdvobj->nr_endpoint;
- pfwpriv->bw_40MHz_en = pregpriv->cbw40_enable;
- switch (pregpriv->rf_config) {
+ fwpriv->hci_sel = RTL8712_HCI_TYPE_72USB;
+ fwpriv->usb_ep_num = (u8)dvobj->nr_endpoint;
+ fwpriv->bw_40MHz_en = regpriv->cbw40_enable;
+ switch (regpriv->rf_config) {
case RTL8712_RF_1T1R:
- pfwpriv->rf_config = RTL8712_RFC_1T1R;
+ fwpriv->rf_config = RTL8712_RFC_1T1R;
break;
case RTL8712_RF_2T2R:
- pfwpriv->rf_config = RTL8712_RFC_2T2R;
+ fwpriv->rf_config = RTL8712_RFC_2T2R;
break;
case RTL8712_RF_1T2R:
default:
- pfwpriv->rf_config = RTL8712_RFC_1T2R;
+ fwpriv->rf_config = RTL8712_RFC_1T2R;
}
- pfwpriv->mp_mode = (pregpriv->mp_mode == 1) ? 1 : 0;
+ fwpriv->mp_mode = (regpriv->mp_mode == 1) ? 1 : 0;
/* 0:off 1:on 2:auto */
- pfwpriv->vcs_type = pregpriv->vrtl_carrier_sense;
- pfwpriv->vcs_mode = pregpriv->vcs_type; /* 1:RTS/CTS 2:CTS to self */
+ fwpriv->vcs_type = regpriv->vrtl_carrier_sense;
+ fwpriv->vcs_mode = regpriv->vcs_type; /* 1:RTS/CTS 2:CTS to self */
/* default enable turbo_mode */
- pfwpriv->turbo_mode = ((pregpriv->wifi_test == 1) ? 0 : 1);
- pfwpriv->low_power_mode = pregpriv->low_power;
+ fwpriv->turbo_mode = ((regpriv->wifi_test == 1) ? 0 : 1);
+ fwpriv->low_power_mode = regpriv->low_power;
}
static void update_fwhdr(struct fw_hdr *pfwhdr, const u8 *pmappedfw)
@@ -141,7 +141,7 @@ static u8 chk_fwhdr(struct fw_hdr *pfwhdr, u32 ulfilelength)
return _SUCCESS;
}
-static u8 rtl8712_dl_fw(struct _adapter *padapter)
+static u8 rtl8712_dl_fw(struct _adapter *adapter)
{
sint i;
u8 tmp8, tmp8_a;
@@ -150,56 +150,56 @@ static u8 rtl8712_dl_fw(struct _adapter *padapter)
uint dump_imem_sz, imem_sz, dump_emem_sz, emem_sz; /* max = 49152; */
struct fw_hdr fwhdr;
u32 ulfilelength; /* FW file size */
- const u8 *pmappedfw = NULL;
- u8 *ptmpchar = NULL, *ppayload, *ptr;
- struct tx_desc *ptx_desc;
+ const u8 *mappedfw = NULL;
+ u8 *tmpchar = NULL, *payload, *ptr;
+ struct tx_desc *txdesc;
u32 txdscp_sz = sizeof(struct tx_desc);
u8 ret = _FAIL;
- ulfilelength = rtl871x_open_fw(padapter, &pmappedfw);
- if (pmappedfw && (ulfilelength > 0)) {
- update_fwhdr(&fwhdr, pmappedfw);
+ ulfilelength = rtl871x_open_fw(adapter, &mappedfw);
+ if (mappedfw && (ulfilelength > 0)) {
+ update_fwhdr(&fwhdr, mappedfw);
if (chk_fwhdr(&fwhdr, ulfilelength) == _FAIL)
return ret;
- fill_fwpriv(padapter, &fwhdr.fwpriv);
+ fill_fwpriv(adapter, &fwhdr.fwpriv);
/* firmware check ok */
maxlen = (fwhdr.img_IMEM_size > fwhdr.img_SRAM_size) ?
fwhdr.img_IMEM_size : fwhdr.img_SRAM_size;
maxlen += txdscp_sz;
- ptmpchar = kmalloc(maxlen + FWBUFF_ALIGN_SZ, GFP_KERNEL);
- if (!ptmpchar)
+ tmpchar = kmalloc(maxlen + FWBUFF_ALIGN_SZ, GFP_KERNEL);
+ if (!tmpchar)
return ret;
- ptx_desc = (struct tx_desc *)(ptmpchar + FWBUFF_ALIGN_SZ -
- ((addr_t)(ptmpchar) & (FWBUFF_ALIGN_SZ - 1)));
- ppayload = (u8 *)(ptx_desc) + txdscp_sz;
- ptr = (u8 *)pmappedfw + FIELD_OFFSET(struct fw_hdr, fwpriv) +
+ txdesc = (struct tx_desc *)(tmpchar + FWBUFF_ALIGN_SZ -
+ ((addr_t)(tmpchar) & (FWBUFF_ALIGN_SZ - 1)));
+ payload = (u8 *)(txdesc) + txdscp_sz;
+ ptr = (u8 *)mappedfw + FIELD_OFFSET(struct fw_hdr, fwpriv) +
fwhdr.fw_priv_sz;
/* Download FirmWare */
/* 1. determine IMEM code size and Load IMEM Code Section */
imem_sz = fwhdr.img_IMEM_size;
do {
- memset(ptx_desc, 0, TXDESC_SIZE);
+ memset(txdesc, 0, TXDESC_SIZE);
if (imem_sz > MAX_DUMP_FWSZ/*49152*/) {
dump_imem_sz = MAX_DUMP_FWSZ;
} else {
dump_imem_sz = imem_sz;
- ptx_desc->txdw0 |= cpu_to_le32(BIT(28));
+ txdesc->txdw0 |= cpu_to_le32(BIT(28));
}
- ptx_desc->txdw0 |= cpu_to_le32(dump_imem_sz &
+ txdesc->txdw0 |= cpu_to_le32(dump_imem_sz &
0x0000ffff);
- memcpy(ppayload, ptr, dump_imem_sz);
- r8712_write_mem(padapter, RTL8712_DMA_VOQ,
+ memcpy(payload, ptr, dump_imem_sz);
+ r8712_write_mem(adapter, RTL8712_DMA_VOQ,
dump_imem_sz + TXDESC_SIZE,
- (u8 *)ptx_desc);
+ (u8 *)txdesc);
ptr += dump_imem_sz;
imem_sz -= dump_imem_sz;
} while (imem_sz > 0);
i = 10;
- tmp16 = r8712_read16(padapter, TCR);
+ tmp16 = r8712_read16(adapter, TCR);
while (((tmp16 & _IMEM_CODE_DONE) == 0) && (i > 0)) {
usleep_range(10, 1000);
- tmp16 = r8712_read16(padapter, TCR);
+ tmp16 = r8712_read16(adapter, TCR);
i--;
}
if (i == 0 || (tmp16 & _IMEM_CHK_RPT) == 0)
@@ -208,94 +208,94 @@ static u8 rtl8712_dl_fw(struct _adapter *padapter)
/* 2.Download EMEM code size and Load EMEM Code Section */
emem_sz = fwhdr.img_SRAM_size;
do {
- memset(ptx_desc, 0, TXDESC_SIZE);
+ memset(txdesc, 0, TXDESC_SIZE);
if (emem_sz > MAX_DUMP_FWSZ) { /* max=48k */
dump_emem_sz = MAX_DUMP_FWSZ;
} else {
dump_emem_sz = emem_sz;
- ptx_desc->txdw0 |= cpu_to_le32(BIT(28));
+ txdesc->txdw0 |= cpu_to_le32(BIT(28));
}
- ptx_desc->txdw0 |= cpu_to_le32(dump_emem_sz &
+ txdesc->txdw0 |= cpu_to_le32(dump_emem_sz &
0x0000ffff);
- memcpy(ppayload, ptr, dump_emem_sz);
- r8712_write_mem(padapter, RTL8712_DMA_VOQ,
+ memcpy(payload, ptr, dump_emem_sz);
+ r8712_write_mem(adapter, RTL8712_DMA_VOQ,
dump_emem_sz + TXDESC_SIZE,
- (u8 *)ptx_desc);
+ (u8 *)txdesc);
ptr += dump_emem_sz;
emem_sz -= dump_emem_sz;
} while (emem_sz > 0);
i = 5;
- tmp16 = r8712_read16(padapter, TCR);
+ tmp16 = r8712_read16(adapter, TCR);
while (((tmp16 & _EMEM_CODE_DONE) == 0) && (i > 0)) {
usleep_range(10, 1000);
- tmp16 = r8712_read16(padapter, TCR);
+ tmp16 = r8712_read16(adapter, TCR);
i--;
}
if (i == 0 || (tmp16 & _EMEM_CHK_RPT) == 0)
goto exit_fail;
/* 3.Enable CPU */
- tmp8 = r8712_read8(padapter, SYS_CLKR);
- r8712_write8(padapter, SYS_CLKR, tmp8 | BIT(2));
- tmp8_a = r8712_read8(padapter, SYS_CLKR);
+ tmp8 = r8712_read8(adapter, SYS_CLKR);
+ r8712_write8(adapter, SYS_CLKR, tmp8 | BIT(2));
+ tmp8_a = r8712_read8(adapter, SYS_CLKR);
if (tmp8_a != (tmp8 | BIT(2)))
goto exit_fail;
- tmp8 = r8712_read8(padapter, SYS_FUNC_EN + 1);
- r8712_write8(padapter, SYS_FUNC_EN + 1, tmp8 | BIT(2));
- tmp8_a = r8712_read8(padapter, SYS_FUNC_EN + 1);
+ tmp8 = r8712_read8(adapter, SYS_FUNC_EN + 1);
+ r8712_write8(adapter, SYS_FUNC_EN + 1, tmp8 | BIT(2));
+ tmp8_a = r8712_read8(adapter, SYS_FUNC_EN + 1);
if (tmp8_a != (tmp8 | BIT(2)))
goto exit_fail;
- r8712_read32(padapter, TCR);
+ r8712_read32(adapter, TCR);
/* 4.polling IMEM Ready */
i = 100;
- tmp16 = r8712_read16(padapter, TCR);
+ tmp16 = r8712_read16(adapter, TCR);
while (((tmp16 & _IMEM_RDY) == 0) && (i > 0)) {
msleep(20);
- tmp16 = r8712_read16(padapter, TCR);
+ tmp16 = r8712_read16(adapter, TCR);
i--;
}
if (i == 0) {
- r8712_write16(padapter, 0x10250348, 0xc000);
- r8712_write16(padapter, 0x10250348, 0xc001);
- r8712_write16(padapter, 0x10250348, 0x2000);
- r8712_write16(padapter, 0x10250348, 0x2001);
- r8712_write16(padapter, 0x10250348, 0x2002);
- r8712_write16(padapter, 0x10250348, 0x2003);
+ r8712_write16(adapter, 0x10250348, 0xc000);
+ r8712_write16(adapter, 0x10250348, 0xc001);
+ r8712_write16(adapter, 0x10250348, 0x2000);
+ r8712_write16(adapter, 0x10250348, 0x2001);
+ r8712_write16(adapter, 0x10250348, 0x2002);
+ r8712_write16(adapter, 0x10250348, 0x2003);
goto exit_fail;
}
/* 5.Download DMEM code size and Load EMEM Code Section */
- memset(ptx_desc, 0, TXDESC_SIZE);
- ptx_desc->txdw0 |= cpu_to_le32(fwhdr.fw_priv_sz & 0x0000ffff);
- ptx_desc->txdw0 |= cpu_to_le32(BIT(28));
- memcpy(ppayload, &fwhdr.fwpriv, fwhdr.fw_priv_sz);
- r8712_write_mem(padapter, RTL8712_DMA_VOQ,
- fwhdr.fw_priv_sz + TXDESC_SIZE, (u8 *)ptx_desc);
+ memset(txdesc, 0, TXDESC_SIZE);
+ txdesc->txdw0 |= cpu_to_le32(fwhdr.fw_priv_sz & 0x0000ffff);
+ txdesc->txdw0 |= cpu_to_le32(BIT(28));
+ memcpy(payload, &fwhdr.fwpriv, fwhdr.fw_priv_sz);
+ r8712_write_mem(adapter, RTL8712_DMA_VOQ,
+ fwhdr.fw_priv_sz + TXDESC_SIZE, (u8 *)txdesc);
/* polling dmem code done */
i = 100;
- tmp16 = r8712_read16(padapter, TCR);
+ tmp16 = r8712_read16(adapter, TCR);
while (((tmp16 & _DMEM_CODE_DONE) == 0) && (i > 0)) {
msleep(20);
- tmp16 = r8712_read16(padapter, TCR);
+ tmp16 = r8712_read16(adapter, TCR);
i--;
}
if (i == 0)
goto exit_fail;
- tmp8 = r8712_read8(padapter, 0x1025000A);
+ tmp8 = r8712_read8(adapter, 0x1025000A);
if (tmp8 & BIT(4)) /* When boot from EEPROM,
* & FW need more time to read EEPROM
*/
i = 60;
else /* boot from EFUSE */
i = 30;
- tmp16 = r8712_read16(padapter, TCR);
+ tmp16 = r8712_read16(adapter, TCR);
while (((tmp16 & _FWRDY) == 0) && (i > 0)) {
msleep(100);
- tmp16 = r8712_read16(padapter, TCR);
+ tmp16 = r8712_read16(adapter, TCR);
i--;
}
if (i == 0)
@@ -306,7 +306,7 @@ static u8 rtl8712_dl_fw(struct _adapter *padapter)
ret = _SUCCESS;
exit_fail:
- kfree(ptmpchar);
+ kfree(tmpchar);
return ret;
}
diff --git a/drivers/staging/rtl8712/ieee80211.c b/drivers/staging/rtl8712/ieee80211.c
index 4cca7390c8ef..b4a099169c7c 100644
--- a/drivers/staging/rtl8712/ieee80211.c
+++ b/drivers/staging/rtl8712/ieee80211.c
@@ -156,13 +156,13 @@ static uint r8712_get_rateset_len(u8 *rateset)
return i;
}
-int r8712_generate_ie(struct registry_priv *pregistrypriv)
+int r8712_generate_ie(struct registry_priv *registrypriv)
{
int rate_len;
uint sz = 0;
- struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network;
- u8 *ie = pdev_network->IEs;
- u16 beaconPeriod = (u16)pdev_network->Configuration.BeaconPeriod;
+ struct wlan_bssid_ex *dev_network = &registrypriv->dev_network;
+ u8 *ie = dev_network->IEs;
+ u16 beaconPeriod = (u16)dev_network->Configuration.BeaconPeriod;
/*timestamp will be inserted by hardware*/
sz += 8;
@@ -174,65 +174,65 @@ int r8712_generate_ie(struct registry_priv *pregistrypriv)
/*capability info*/
*(u16 *)ie = 0;
*(__le16 *)ie |= cpu_to_le16(cap_IBSS);
- if (pregistrypriv->preamble == PREAMBLE_SHORT)
+ if (registrypriv->preamble == PREAMBLE_SHORT)
*(__le16 *)ie |= cpu_to_le16(cap_ShortPremble);
- if (pdev_network->Privacy)
+ if (dev_network->Privacy)
*(__le16 *)ie |= cpu_to_le16(cap_Privacy);
sz += 2;
ie += 2;
/*SSID*/
- ie = r8712_set_ie(ie, _SSID_IE_, pdev_network->Ssid.SsidLength,
- pdev_network->Ssid.Ssid, &sz);
+ ie = r8712_set_ie(ie, _SSID_IE_, dev_network->Ssid.SsidLength,
+ dev_network->Ssid.Ssid, &sz);
/*supported rates*/
- set_supported_rate(pdev_network->rates, pregistrypriv->wireless_mode);
- rate_len = r8712_get_rateset_len(pdev_network->rates);
+ set_supported_rate(dev_network->rates, registrypriv->wireless_mode);
+ rate_len = r8712_get_rateset_len(dev_network->rates);
if (rate_len > 8) {
ie = r8712_set_ie(ie, _SUPPORTEDRATES_IE_, 8,
- pdev_network->rates, &sz);
+ dev_network->rates, &sz);
ie = r8712_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8),
- (pdev_network->rates + 8), &sz);
+ (dev_network->rates + 8), &sz);
} else {
ie = r8712_set_ie(ie, _SUPPORTEDRATES_IE_,
- rate_len, pdev_network->rates, &sz);
+ rate_len, dev_network->rates, &sz);
}
/*DS parameter set*/
ie = r8712_set_ie(ie, _DSSET_IE_, 1,
- (u8 *)&pdev_network->Configuration.DSConfig, &sz);
+ (u8 *)&dev_network->Configuration.DSConfig, &sz);
/*IBSS Parameter Set*/
ie = r8712_set_ie(ie, _IBSS_PARA_IE_, 2,
- (u8 *)&pdev_network->Configuration.ATIMWindow, &sz);
+ (u8 *)&dev_network->Configuration.ATIMWindow, &sz);
return sz;
}
-unsigned char *r8712_get_wpa_ie(unsigned char *pie, uint *wpa_ie_len, int limit)
+unsigned char *r8712_get_wpa_ie(unsigned char *ie, uint *wpa_ie_len, int limit)
{
u32 len;
u16 val16;
unsigned char wpa_oui_type[] = {0x00, 0x50, 0xf2, 0x01};
- u8 *pbuf = pie;
+ u8 *buf = ie;
while (1) {
- pbuf = r8712_get_ie(pbuf, _WPA_IE_ID_, &len, limit);
- if (pbuf) {
+ buf = r8712_get_ie(buf, _WPA_IE_ID_, &len, limit);
+ if (buf) {
/*check if oui matches...*/
- if (memcmp((pbuf + 2), wpa_oui_type,
+ if (memcmp((buf + 2), wpa_oui_type,
sizeof(wpa_oui_type)))
goto check_next_ie;
/*check version...*/
- memcpy((u8 *)&val16, (pbuf + 6), sizeof(val16));
+ memcpy((u8 *)&val16, (buf + 6), sizeof(val16));
le16_to_cpus(&val16);
if (val16 != 0x0001)
goto check_next_ie;
- *wpa_ie_len = *(pbuf + 1);
- return pbuf;
+ *wpa_ie_len = *(buf + 1);
+ return buf;
}
*wpa_ie_len = 0;
return NULL;
check_next_ie:
- limit = limit - (pbuf - pie) - 2 - len;
+ limit = limit - (buf - ie) - 2 - len;
if (limit <= 0)
break;
- pbuf += (2 + len);
+ buf += (2 + len);
}
*wpa_ie_len = 0;
return NULL;
@@ -283,12 +283,12 @@ int r8712_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher,
if (wpa_ie_len <= 0) {
/* No WPA IE - fail silently */
- return _FAIL;
+ return -EINVAL;
}
if ((*wpa_ie != _WPA_IE_ID_) ||
(*(wpa_ie + 1) != (u8)(wpa_ie_len - 2)) ||
(memcmp(wpa_ie + 2, (void *)WPA_OUI_TYPE, WPA_SELECTOR_LEN)))
- return _FAIL;
+ return -EINVAL;
pos = wpa_ie;
pos += 8;
left = wpa_ie_len - 8;
@@ -298,7 +298,7 @@ int r8712_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher,
pos += WPA_SELECTOR_LEN;
left -= WPA_SELECTOR_LEN;
} else if (left > 0) {
- return _FAIL;
+ return -EINVAL;
}
/*pairwise_cipher*/
if (left >= 2) {
@@ -306,16 +306,16 @@ int r8712_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher,
pos += 2;
left -= 2;
if (count == 0 || left < count * WPA_SELECTOR_LEN)
- return _FAIL;
+ return -EINVAL;
for (i = 0; i < count; i++) {
*pairwise_cipher |= r8712_get_wpa_cipher_suite(pos);
pos += WPA_SELECTOR_LEN;
left -= WPA_SELECTOR_LEN;
}
} else if (left == 1) {
- return _FAIL;
+ return -EINVAL;
}
- return _SUCCESS;
+ return 0;
}
int r8712_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher,
@@ -327,11 +327,11 @@ int r8712_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher,
if (rsn_ie_len <= 0) {
/* No RSN IE - fail silently */
- return _FAIL;
+ return -EINVAL;
}
if ((*rsn_ie != _WPA2_IE_ID_) ||
(*(rsn_ie + 1) != (u8)(rsn_ie_len - 2)))
- return _FAIL;
+ return -EINVAL;
pos = rsn_ie;
pos += 4;
left = rsn_ie_len - 4;
@@ -341,7 +341,7 @@ int r8712_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher,
pos += RSN_SELECTOR_LEN;
left -= RSN_SELECTOR_LEN;
} else if (left > 0) {
- return _FAIL;
+ return -EINVAL;
}
/*pairwise_cipher*/
if (left >= 2) {
@@ -349,16 +349,16 @@ int r8712_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher,
pos += 2;
left -= 2;
if (count == 0 || left < count * RSN_SELECTOR_LEN)
- return _FAIL;
+ return -EINVAL;
for (i = 0; i < count; i++) {
*pairwise_cipher |= r8712_get_wpa2_cipher_suite(pos);
pos += RSN_SELECTOR_LEN;
left -= RSN_SELECTOR_LEN;
}
} else if (left == 1) {
- return _FAIL;
+ return -EINVAL;
}
- return _SUCCESS;
+ return 0;
}
int r8712_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len,
diff --git a/drivers/staging/rtl8712/mlme_linux.c b/drivers/staging/rtl8712/mlme_linux.c
index 4d473f008aa4..b9f5104f3bf7 100644
--- a/drivers/staging/rtl8712/mlme_linux.c
+++ b/drivers/staging/rtl8712/mlme_linux.c
@@ -60,22 +60,22 @@ static void wdg_timeout_handler (struct timer_list *t)
struct _adapter *adapter =
from_timer(adapter, t, mlmepriv.wdg_timer);
- _r8712_wdg_timeout_handler(adapter);
+ r8712_wdg_wk_cmd(adapter);
mod_timer(&adapter->mlmepriv.wdg_timer,
jiffies + msecs_to_jiffies(2000));
}
-void r8712_init_mlme_timer(struct _adapter *padapter)
+void r8712_init_mlme_timer(struct _adapter *adapter)
{
- struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct mlme_priv *mlmepriv = &adapter->mlmepriv;
- timer_setup(&pmlmepriv->assoc_timer, join_timeout_handler, 0);
- timer_setup(&pmlmepriv->sitesurveyctrl.sitesurvey_ctrl_timer,
+ timer_setup(&mlmepriv->assoc_timer, join_timeout_handler, 0);
+ timer_setup(&mlmepriv->sitesurveyctrl.sitesurvey_ctrl_timer,
sitesurvey_ctrl_handler, 0);
- timer_setup(&pmlmepriv->scan_to_timer, _scan_timeout_handler, 0);
- timer_setup(&pmlmepriv->dhcp_timer, dhcp_timeout_handler, 0);
- timer_setup(&pmlmepriv->wdg_timer, wdg_timeout_handler, 0);
+ timer_setup(&mlmepriv->scan_to_timer, _scan_timeout_handler, 0);
+ timer_setup(&mlmepriv->dhcp_timer, dhcp_timeout_handler, 0);
+ timer_setup(&mlmepriv->wdg_timer, wdg_timeout_handler, 0);
}
void r8712_os_indicate_connect(struct _adapter *adapter)
@@ -119,16 +119,16 @@ void r8712_os_indicate_disconnect(struct _adapter *adapter)
adapter->securitypriv.btkip_countermeasure =
backupTKIPCountermeasure;
} else { /*reset values in securitypriv*/
- struct security_priv *psec_priv = &adapter->securitypriv;
-
- psec_priv->AuthAlgrthm = 0; /*open system*/
- psec_priv->PrivacyAlgrthm = _NO_PRIVACY_;
- psec_priv->PrivacyKeyIndex = 0;
- psec_priv->XGrpPrivacy = _NO_PRIVACY_;
- psec_priv->XGrpKeyid = 1;
- psec_priv->ndisauthtype = Ndis802_11AuthModeOpen;
- psec_priv->ndisencryptstatus = Ndis802_11WEPDisabled;
- psec_priv->wps_phase = false;
+ struct security_priv *sec_priv = &adapter->securitypriv;
+
+ sec_priv->AuthAlgrthm = 0; /*open system*/
+ sec_priv->PrivacyAlgrthm = _NO_PRIVACY_;
+ sec_priv->PrivacyKeyIndex = 0;
+ sec_priv->XGrpPrivacy = _NO_PRIVACY_;
+ sec_priv->XGrpKeyid = 1;
+ sec_priv->ndisauthtype = Ndis802_11AuthModeOpen;
+ sec_priv->ndisencryptstatus = Ndis802_11WEPDisabled;
+ sec_priv->wps_phase = false;
}
}
diff --git a/drivers/staging/rtl8712/os_intfs.c b/drivers/staging/rtl8712/os_intfs.c
index c962696c9822..b554cf8bd679 100644
--- a/drivers/staging/rtl8712/os_intfs.c
+++ b/drivers/staging/rtl8712/os_intfs.c
@@ -221,9 +221,9 @@ struct net_device *r8712_init_netdev(void)
static u32 start_drv_threads(struct _adapter *padapter)
{
- padapter->cmdThread = kthread_run(r8712_cmd_thread, padapter, "%s",
+ padapter->cmd_thread = kthread_run(r8712_cmd_thread, padapter, "%s",
padapter->pnetdev->name);
- if (IS_ERR(padapter->cmdThread))
+ if (IS_ERR(padapter->cmd_thread))
return _FAIL;
return _SUCCESS;
}
@@ -235,7 +235,7 @@ void r8712_stop_drv_threads(struct _adapter *padapter)
/*Below is to terminate r8712_cmd_thread & event_thread...*/
complete(&padapter->cmdpriv.cmd_queue_comp);
- if (padapter->cmdThread)
+ if (padapter->cmd_thread)
wait_for_completion_interruptible(completion);
padapter->cmdpriv.cmd_seq = 1;
}
@@ -297,10 +297,10 @@ static u8 init_default_value(struct _adapter *padapter)
u8 r8712_init_drv_sw(struct _adapter *padapter)
{
- if ((r8712_init_cmd_priv(&padapter->cmdpriv)) == _FAIL)
+ if (r8712_init_cmd_priv(&padapter->cmdpriv))
return _FAIL;
padapter->cmdpriv.padapter = padapter;
- if ((r8712_init_evt_priv(&padapter->evtpriv)) == _FAIL)
+ if (r8712_init_evt_priv(&padapter->evtpriv))
return _FAIL;
if (r8712_init_mlme_priv(padapter) == _FAIL)
return _FAIL;
@@ -310,7 +310,8 @@ u8 r8712_init_drv_sw(struct _adapter *padapter)
sizeof(struct security_priv));
timer_setup(&padapter->securitypriv.tkip_timer,
r8712_use_tkipkey_handler, 0);
- _r8712_init_sta_priv(&padapter->stapriv);
+ if (_r8712_init_sta_priv(&padapter->stapriv))
+ return _FAIL;
padapter->stapriv.padapter = padapter;
r8712_init_bcmc_stainfo(padapter);
r8712_init_pwrctrl_priv(padapter);
diff --git a/drivers/staging/rtl8712/recv_linux.c b/drivers/staging/rtl8712/recv_linux.c
index 4e20cbafa9fb..84c4c8580f9a 100644
--- a/drivers/staging/rtl8712/recv_linux.c
+++ b/drivers/staging/rtl8712/recv_linux.c
@@ -72,11 +72,11 @@ int r8712_os_recvbuf_resource_free(struct _adapter *padapter,
return _SUCCESS;
}
-void r8712_handle_tkip_mic_err(struct _adapter *padapter, u8 bgroup)
+void r8712_handle_tkip_mic_err(struct _adapter *adapter, u8 bgroup)
{
union iwreq_data wrqu;
struct iw_michaelmicfailure ev;
- struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct mlme_priv *mlmepriv = &adapter->mlmepriv;
memset(&ev, 0x00, sizeof(ev));
if (bgroup)
@@ -84,54 +84,54 @@ void r8712_handle_tkip_mic_err(struct _adapter *padapter, u8 bgroup)
else
ev.flags |= IW_MICFAILURE_PAIRWISE;
ev.src_addr.sa_family = ARPHRD_ETHER;
- ether_addr_copy(ev.src_addr.sa_data, &pmlmepriv->assoc_bssid[0]);
+ ether_addr_copy(ev.src_addr.sa_data, &mlmepriv->assoc_bssid[0]);
memset(&wrqu, 0x00, sizeof(wrqu));
wrqu.data.length = sizeof(ev);
- wireless_send_event(padapter->pnetdev, IWEVMICHAELMICFAILURE, &wrqu,
+ wireless_send_event(adapter->pnetdev, IWEVMICHAELMICFAILURE, &wrqu,
(char *)&ev);
}
-void r8712_recv_indicatepkt(struct _adapter *padapter,
- union recv_frame *precv_frame)
+void r8712_recv_indicatepkt(struct _adapter *adapter,
+ union recv_frame *recvframe)
{
- struct recv_priv *precvpriv;
- struct __queue *pfree_recv_queue;
+ struct recv_priv *recvpriv;
+ struct __queue *free_recv_queue;
_pkt *skb;
- struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
+ struct rx_pkt_attrib *attrib = &recvframe->u.hdr.attrib;
- precvpriv = &padapter->recvpriv;
- pfree_recv_queue = &precvpriv->free_recv_queue;
- skb = precv_frame->u.hdr.pkt;
+ recvpriv = &adapter->recvpriv;
+ free_recv_queue = &recvpriv->free_recv_queue;
+ skb = recvframe->u.hdr.pkt;
if (!skb)
goto _recv_indicatepkt_drop;
- skb->data = precv_frame->u.hdr.rx_data;
- skb->len = precv_frame->u.hdr.len;
+ skb->data = recvframe->u.hdr.rx_data;
+ skb->len = recvframe->u.hdr.len;
skb_set_tail_pointer(skb, skb->len);
- if ((pattrib->tcpchk_valid == 1) && (pattrib->tcp_chkrpt == 1))
+ if ((attrib->tcpchk_valid == 1) && (attrib->tcp_chkrpt == 1))
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
skb->ip_summed = CHECKSUM_NONE;
- skb->dev = padapter->pnetdev;
- skb->protocol = eth_type_trans(skb, padapter->pnetdev);
+ skb->dev = adapter->pnetdev;
+ skb->protocol = eth_type_trans(skb, adapter->pnetdev);
netif_rx(skb);
- precv_frame->u.hdr.pkt = NULL; /* pointers to NULL before
+ recvframe->u.hdr.pkt = NULL; /* pointers to NULL before
* r8712_free_recvframe()
*/
- r8712_free_recvframe(precv_frame, pfree_recv_queue);
+ r8712_free_recvframe(recvframe, free_recv_queue);
return;
_recv_indicatepkt_drop:
/*enqueue back to free_recv_queue*/
- if (precv_frame)
- r8712_free_recvframe(precv_frame, pfree_recv_queue);
- precvpriv->rx_drop++;
+ if (recvframe)
+ r8712_free_recvframe(recvframe, free_recv_queue);
+ recvpriv->rx_drop++;
}
static void _r8712_reordering_ctrl_timeout_handler (struct timer_list *t)
{
- struct recv_reorder_ctrl *preorder_ctrl =
- from_timer(preorder_ctrl, t, reordering_ctrl_timer);
+ struct recv_reorder_ctrl *reorder_ctrl =
+ from_timer(reorder_ctrl, t, reordering_ctrl_timer);
- r8712_reordering_ctrl_timeout_handler(preorder_ctrl);
+ r8712_reordering_ctrl_timeout_handler(reorder_ctrl);
}
void r8712_init_recv_timer(struct recv_reorder_ctrl *preorder_ctrl)
diff --git a/drivers/staging/rtl8712/rtl8712_efuse.c b/drivers/staging/rtl8712/rtl8712_efuse.c
index 00babd011a62..4f3b54a7c3be 100644
--- a/drivers/staging/rtl8712/rtl8712_efuse.c
+++ b/drivers/staging/rtl8712/rtl8712_efuse.c
@@ -23,7 +23,7 @@
/* reserve 3 bytes for HW stop read */
static int efuse_available_max_size = EFUSE_MAX_SIZE - 3 /*0x1FD*/;
-static void efuse_reg_ctrl(struct _adapter *padapter, u8 bPowerOn)
+static void efuse_reg_ctrl(struct _adapter *adapter, u8 bPowerOn)
{
u8 tmpu8 = 0;
@@ -31,53 +31,53 @@ static void efuse_reg_ctrl(struct _adapter *padapter, u8 bPowerOn)
/* -----------------e-fuse pwr & clk reg ctrl ---------------
* Enable LDOE25 Macro Block
*/
- tmpu8 = r8712_read8(padapter, EFUSE_TEST + 3);
+ tmpu8 = r8712_read8(adapter, EFUSE_TEST + 3);
tmpu8 |= 0x80;
- r8712_write8(padapter, EFUSE_TEST + 3, tmpu8);
+ r8712_write8(adapter, EFUSE_TEST + 3, tmpu8);
msleep(20); /* for some platform , need some delay time */
/* Change Efuse Clock for write action to 40MHZ */
- r8712_write8(padapter, EFUSE_CLK_CTRL, 0x03);
+ r8712_write8(adapter, EFUSE_CLK_CTRL, 0x03);
msleep(20); /* for some platform , need some delay time */
} else {
/* -----------------e-fuse pwr & clk reg ctrl -----------------
* Disable LDOE25 Macro Block
*/
- tmpu8 = r8712_read8(padapter, EFUSE_TEST + 3);
+ tmpu8 = r8712_read8(adapter, EFUSE_TEST + 3);
tmpu8 &= 0x7F;
- r8712_write8(padapter, EFUSE_TEST + 3, tmpu8);
+ r8712_write8(adapter, EFUSE_TEST + 3, tmpu8);
/* Change Efuse Clock for write action to 500K */
- r8712_write8(padapter, EFUSE_CLK_CTRL, 0x02);
+ r8712_write8(adapter, EFUSE_CLK_CTRL, 0x02);
}
}
/*
* Before write E-Fuse, this function must be called.
*/
-u8 r8712_efuse_reg_init(struct _adapter *padapter)
+u8 r8712_efuse_reg_init(struct _adapter *adapter)
{
return true;
}
-void r8712_efuse_reg_uninit(struct _adapter *padapter)
+void r8712_efuse_reg_uninit(struct _adapter *adapter)
{
- efuse_reg_ctrl(padapter, false);
+ efuse_reg_ctrl(adapter, false);
}
-static u8 efuse_one_byte_read(struct _adapter *padapter, u16 addr, u8 *data)
+static u8 efuse_one_byte_read(struct _adapter *adapter, u16 addr, u8 *data)
{
u8 tmpidx = 0, bResult;
/* -----------------e-fuse reg ctrl --------------------------------- */
- r8712_write8(padapter, EFUSE_CTRL + 1, (u8)(addr & 0xFF)); /* address */
- r8712_write8(padapter, EFUSE_CTRL + 2, ((u8)((addr >> 8) & 0x03)) |
- (r8712_read8(padapter, EFUSE_CTRL + 2) & 0xFC));
- r8712_write8(padapter, EFUSE_CTRL + 3, 0x72); /* read cmd */
+ r8712_write8(adapter, EFUSE_CTRL + 1, (u8)(addr & 0xFF)); /* address */
+ r8712_write8(adapter, EFUSE_CTRL + 2, ((u8)((addr >> 8) & 0x03)) |
+ (r8712_read8(adapter, EFUSE_CTRL + 2) & 0xFC));
+ r8712_write8(adapter, EFUSE_CTRL + 3, 0x72); /* read cmd */
/* wait for complete */
- while (!(0x80 & r8712_read8(padapter, EFUSE_CTRL + 3)) &&
+ while (!(0x80 & r8712_read8(adapter, EFUSE_CTRL + 3)) &&
(tmpidx < 100))
tmpidx++;
if (tmpidx < 100) {
- *data = r8712_read8(padapter, EFUSE_CTRL);
+ *data = r8712_read8(adapter, EFUSE_CTRL);
bResult = true;
} else {
*data = 0xff;
@@ -86,18 +86,18 @@ static u8 efuse_one_byte_read(struct _adapter *padapter, u16 addr, u8 *data)
return bResult;
}
-static u8 efuse_one_byte_write(struct _adapter *padapter, u16 addr, u8 data)
+static u8 efuse_one_byte_write(struct _adapter *adapter, u16 addr, u8 data)
{
u8 tmpidx = 0, bResult;
/* -----------------e-fuse reg ctrl -------------------------------- */
- r8712_write8(padapter, EFUSE_CTRL + 1, (u8)(addr & 0xFF)); /* address */
- r8712_write8(padapter, EFUSE_CTRL + 2, ((u8)((addr >> 8) & 0x03)) |
- (r8712_read8(padapter, EFUSE_CTRL + 2) & 0xFC));
- r8712_write8(padapter, EFUSE_CTRL, data); /* data */
- r8712_write8(padapter, EFUSE_CTRL + 3, 0xF2); /* write cmd */
+ r8712_write8(adapter, EFUSE_CTRL + 1, (u8)(addr & 0xFF)); /* address */
+ r8712_write8(adapter, EFUSE_CTRL + 2, ((u8)((addr >> 8) & 0x03)) |
+ (r8712_read8(adapter, EFUSE_CTRL + 2) & 0xFC));
+ r8712_write8(adapter, EFUSE_CTRL, data); /* data */
+ r8712_write8(adapter, EFUSE_CTRL + 3, 0xF2); /* write cmd */
/* wait for complete */
- while ((0x80 & r8712_read8(padapter, EFUSE_CTRL + 3)) &&
+ while ((0x80 & r8712_read8(adapter, EFUSE_CTRL + 3)) &&
(tmpidx < 100))
tmpidx++;
if (tmpidx < 100)
@@ -107,32 +107,32 @@ static u8 efuse_one_byte_write(struct _adapter *padapter, u16 addr, u8 data)
return bResult;
}
-static u8 efuse_one_byte_rw(struct _adapter *padapter, u8 bRead, u16 addr,
+static u8 efuse_one_byte_rw(struct _adapter *adapter, u8 bRead, u16 addr,
u8 *data)
{
u8 tmpidx = 0, tmpv8 = 0, bResult;
/* -----------------e-fuse reg ctrl --------------------------------- */
- r8712_write8(padapter, EFUSE_CTRL + 1, (u8)(addr & 0xFF)); /* address */
+ r8712_write8(adapter, EFUSE_CTRL + 1, (u8)(addr & 0xFF)); /* address */
tmpv8 = ((u8)((addr >> 8) & 0x03)) |
- (r8712_read8(padapter, EFUSE_CTRL + 2) & 0xFC);
- r8712_write8(padapter, EFUSE_CTRL + 2, tmpv8);
+ (r8712_read8(adapter, EFUSE_CTRL + 2) & 0xFC);
+ r8712_write8(adapter, EFUSE_CTRL + 2, tmpv8);
if (bRead) {
- r8712_write8(padapter, EFUSE_CTRL + 3, 0x72); /* read cmd */
- while (!(0x80 & r8712_read8(padapter, EFUSE_CTRL + 3)) &&
+ r8712_write8(adapter, EFUSE_CTRL + 3, 0x72); /* read cmd */
+ while (!(0x80 & r8712_read8(adapter, EFUSE_CTRL + 3)) &&
(tmpidx < 100))
tmpidx++;
if (tmpidx < 100) {
- *data = r8712_read8(padapter, EFUSE_CTRL);
+ *data = r8712_read8(adapter, EFUSE_CTRL);
bResult = true;
} else {
*data = 0;
bResult = false;
}
} else {
- r8712_write8(padapter, EFUSE_CTRL, *data); /* data */
- r8712_write8(padapter, EFUSE_CTRL + 3, 0xF2); /* write cmd */
- while ((0x80 & r8712_read8(padapter, EFUSE_CTRL + 3)) &&
+ r8712_write8(adapter, EFUSE_CTRL, *data); /* data */
+ r8712_write8(adapter, EFUSE_CTRL + 3, 0xF2); /* write cmd */
+ while ((0x80 & r8712_read8(adapter, EFUSE_CTRL + 3)) &&
(tmpidx < 100))
tmpidx++;
if (tmpidx < 100)
@@ -143,12 +143,12 @@ static u8 efuse_one_byte_rw(struct _adapter *padapter, u8 bRead, u16 addr,
return bResult;
}
-static u8 efuse_is_empty(struct _adapter *padapter, u8 *empty)
+static u8 efuse_is_empty(struct _adapter *adapter, u8 *empty)
{
u8 value, ret = true;
/* read one byte to check if E-Fuse is empty */
- if (efuse_one_byte_rw(padapter, true, 0, &value)) {
+ if (efuse_one_byte_rw(adapter, true, 0, &value)) {
if (value == 0xFF)
*empty = true;
else
@@ -159,7 +159,7 @@ static u8 efuse_is_empty(struct _adapter *padapter, u8 *empty)
return ret;
}
-void r8712_efuse_change_max_size(struct _adapter *padapter)
+void r8712_efuse_change_max_size(struct _adapter *adapter)
{
u16 pre_pg_data_saddr = 0x1FB;
u16 i;
@@ -167,7 +167,7 @@ void r8712_efuse_change_max_size(struct _adapter *padapter)
u8 pre_pg_data[5];
for (i = 0; i < pre_pg_data_size; i++)
- efuse_one_byte_read(padapter, pre_pg_data_saddr + i,
+ efuse_one_byte_read(adapter, pre_pg_data_saddr + i,
&pre_pg_data[i]);
if ((pre_pg_data[0] == 0x03) && (pre_pg_data[1] == 0x00) &&
(pre_pg_data[2] == 0x00) && (pre_pg_data[3] == 0x00) &&
@@ -175,7 +175,7 @@ void r8712_efuse_change_max_size(struct _adapter *padapter)
efuse_available_max_size -= pre_pg_data_size;
}
-int r8712_efuse_get_max_size(struct _adapter *padapter)
+int r8712_efuse_get_max_size(struct _adapter *adapter)
{
return efuse_available_max_size;
}
@@ -206,14 +206,14 @@ static void pgpacket_copy_data(const u8 word_en, const u8 *sourdata,
}
}
-u16 r8712_efuse_get_current_size(struct _adapter *padapter)
+u16 r8712_efuse_get_current_size(struct _adapter *adapter)
{
int bContinual = true;
u16 efuse_addr = 0;
u8 hworden = 0;
u8 efuse_data, word_cnts = 0;
- while (bContinual && efuse_one_byte_read(padapter, efuse_addr,
+ while (bContinual && efuse_one_byte_read(adapter, efuse_addr,
&efuse_data) && (efuse_addr < efuse_available_max_size)) {
if (efuse_data != 0xFF) {
hworden = efuse_data & 0x0F;
@@ -227,7 +227,7 @@ u16 r8712_efuse_get_current_size(struct _adapter *padapter)
return efuse_addr;
}
-u8 r8712_efuse_pg_packet_read(struct _adapter *padapter, u8 offset, u8 *data)
+u8 r8712_efuse_pg_packet_read(struct _adapter *adapter, u8 offset, u8 *data)
{
u8 hoffset = 0, hworden = 0, word_cnts = 0;
u16 efuse_addr = 0;
@@ -242,7 +242,7 @@ u8 r8712_efuse_pg_packet_read(struct _adapter *padapter, u8 offset, u8 *data)
return false;
memset(data, 0xFF, sizeof(u8) * PGPKT_DATA_SIZE);
while (efuse_addr < efuse_available_max_size) {
- if (efuse_one_byte_read(padapter, efuse_addr, &efuse_data)) {
+ if (efuse_one_byte_read(adapter, efuse_addr, &efuse_data)) {
if (efuse_data == 0xFF)
break;
hoffset = (efuse_data >> 4) & 0x0F;
@@ -252,7 +252,7 @@ u8 r8712_efuse_pg_packet_read(struct _adapter *padapter, u8 offset, u8 *data)
memset(tmpdata, 0xFF, PGPKT_DATA_SIZE);
for (tmpidx = 0; tmpidx < word_cnts * 2;
tmpidx++) {
- if (efuse_one_byte_read(padapter,
+ if (efuse_one_byte_read(adapter,
efuse_addr + 1 + tmpidx,
&efuse_data)) {
tmpdata[tmpidx] = efuse_data;
@@ -271,7 +271,7 @@ u8 r8712_efuse_pg_packet_read(struct _adapter *padapter, u8 offset, u8 *data)
return ret;
}
-static u8 fix_header(struct _adapter *padapter, u8 header, u16 header_addr)
+static u8 fix_header(struct _adapter *adapter, u8 header, u16 header_addr)
{
struct PGPKT_STRUCT pkt;
u8 offset, word_en, value;
@@ -287,7 +287,7 @@ static u8 fix_header(struct _adapter *padapter, u8 header, u16 header_addr)
/* retrieve original data */
addr = 0;
while (addr < header_addr) {
- if (!efuse_one_byte_read(padapter, addr++, &value)) {
+ if (!efuse_one_byte_read(adapter, addr++, &value)) {
ret = false;
break;
}
@@ -301,13 +301,13 @@ static u8 fix_header(struct _adapter *padapter, u8 header, u16 header_addr)
if (BIT(i) & word_en) {
if (BIT(i) & pkt.word_en) {
if (efuse_one_byte_read(
- padapter, addr,
+ adapter, addr,
&value))
pkt.data[i * 2] = value;
else
return false;
if (efuse_one_byte_read(
- padapter,
+ adapter,
addr + 1,
&value))
pkt.data[i * 2 + 1] =
@@ -325,24 +325,24 @@ static u8 fix_header(struct _adapter *padapter, u8 header, u16 header_addr)
/* fill original data */
for (i = 0; i < PGPKG_MAX_WORDS; i++) {
if (BIT(i) & pkt.word_en) {
- efuse_one_byte_write(padapter, addr, pkt.data[i * 2]);
- efuse_one_byte_write(padapter, addr + 1,
+ efuse_one_byte_write(adapter, addr, pkt.data[i * 2]);
+ efuse_one_byte_write(adapter, addr + 1,
pkt.data[i * 2 + 1]);
/* additional check */
- if (!efuse_one_byte_read(padapter, addr, &value)) {
+ if (!efuse_one_byte_read(adapter, addr, &value)) {
ret = false;
} else if (pkt.data[i * 2] != value) {
ret = false;
if (value == 0xFF) /* write again */
- efuse_one_byte_write(padapter, addr,
+ efuse_one_byte_write(adapter, addr,
pkt.data[i * 2]);
}
- if (!efuse_one_byte_read(padapter, addr + 1, &value)) {
+ if (!efuse_one_byte_read(adapter, addr + 1, &value)) {
ret = false;
} else if (pkt.data[i * 2 + 1] != value) {
ret = false;
if (value == 0xFF) /* write again */
- efuse_one_byte_write(padapter, addr + 1,
+ efuse_one_byte_write(adapter, addr + 1,
pkt.data[i * 2 +
1]);
}
@@ -352,7 +352,7 @@ static u8 fix_header(struct _adapter *padapter, u8 header, u16 header_addr)
return ret;
}
-u8 r8712_efuse_pg_packet_write(struct _adapter *padapter, const u8 offset,
+u8 r8712_efuse_pg_packet_write(struct _adapter *adapter, const u8 offset,
const u8 word_en, const u8 *data)
{
u8 pg_header = 0;
@@ -363,7 +363,7 @@ u8 r8712_efuse_pg_packet_write(struct _adapter *padapter, const u8 offset,
u8 bResult = true;
/* check if E-Fuse Clock Enable and E-Fuse Clock is 40M */
- efuse_data = r8712_read8(padapter, EFUSE_CLK_CTRL);
+ efuse_data = r8712_read8(adapter, EFUSE_CLK_CTRL);
if (efuse_data != 0x03)
return false;
pg_header = MAKE_EFUSE_HEADER(offset, word_en);
@@ -371,15 +371,15 @@ u8 r8712_efuse_pg_packet_write(struct _adapter *padapter, const u8 offset,
repeat_times = 0;
efuse_addr = 0;
while (efuse_addr < efuse_available_max_size) {
- curr_size = r8712_efuse_get_current_size(padapter);
+ curr_size = r8712_efuse_get_current_size(adapter);
if ((curr_size + 1 + target_word_cnts * 2) >
efuse_available_max_size)
return false; /*target_word_cnts + pg header(1 byte)*/
efuse_addr = curr_size; /* current size is also the last addr*/
- efuse_one_byte_write(padapter, efuse_addr, pg_header); /*hdr*/
+ efuse_one_byte_write(adapter, efuse_addr, pg_header); /*hdr*/
sub_repeat = 0;
/* check if what we read is what we write */
- while (!efuse_one_byte_read(padapter, efuse_addr,
+ while (!efuse_one_byte_read(adapter, efuse_addr,
&efuse_data)) {
if (++sub_repeat > _REPEAT_THRESHOLD_) {
bResult = false; /* continue to blind write */
@@ -394,10 +394,10 @@ u8 r8712_efuse_pg_packet_write(struct _adapter *padapter, const u8 offset,
/* go to next address */
efuse_addr++;
for (i = 0; i < target_word_cnts * 2; i++) {
- efuse_one_byte_write(padapter,
+ efuse_one_byte_write(adapter,
efuse_addr + i,
*(data + i));
- if (!efuse_one_byte_read(padapter,
+ if (!efuse_one_byte_read(adapter,
efuse_addr + i,
&efuse_data))
bResult = false;
@@ -411,7 +411,7 @@ u8 r8712_efuse_pg_packet_write(struct _adapter *padapter, const u8 offset,
if (efuse_data == 0xFF)
return bResult; /* nothing damaged. */
/* call rescue procedure */
- if (!fix_header(padapter, efuse_data, efuse_addr))
+ if (!fix_header(adapter, efuse_data, efuse_addr))
return false; /* rescue fail */
if (++repeat_times > _REPEAT_THRESHOLD_) /* fail */
@@ -421,7 +421,7 @@ u8 r8712_efuse_pg_packet_write(struct _adapter *padapter, const u8 offset,
return bResult;
}
-u8 r8712_efuse_access(struct _adapter *padapter, u8 bRead, u16 start_addr,
+u8 r8712_efuse_access(struct _adapter *adapter, u8 bRead, u16 start_addr,
u16 cnts, u8 *data)
{
int i;
@@ -432,7 +432,7 @@ u8 r8712_efuse_access(struct _adapter *padapter, u8 bRead, u16 start_addr,
if (!bRead && ((start_addr + cnts) >
efuse_available_max_size))
return false;
- if (!bRead && !r8712_efuse_reg_init(padapter))
+ if (!bRead && !r8712_efuse_reg_init(adapter))
return false;
/* -----------------e-fuse one byte read / write ---------------------*/
for (i = 0; i < cnts; i++) {
@@ -440,17 +440,17 @@ u8 r8712_efuse_access(struct _adapter *padapter, u8 bRead, u16 start_addr,
res = false;
break;
}
- res = efuse_one_byte_rw(padapter, bRead, start_addr + i,
+ res = efuse_one_byte_rw(adapter, bRead, start_addr + i,
data + i);
if (!bRead && !res)
break;
}
if (!bRead)
- r8712_efuse_reg_uninit(padapter);
+ r8712_efuse_reg_uninit(adapter);
return res;
}
-u8 r8712_efuse_map_read(struct _adapter *padapter, u16 addr, u16 cnts, u8 *data)
+u8 r8712_efuse_map_read(struct _adapter *adapter, u16 addr, u16 cnts, u8 *data)
{
u8 offset, ret = true;
u8 pktdata[PGPKT_DATA_SIZE];
@@ -458,13 +458,13 @@ u8 r8712_efuse_map_read(struct _adapter *padapter, u16 addr, u16 cnts, u8 *data)
if ((addr + cnts) > EFUSE_MAP_MAX_SIZE)
return false;
- if (efuse_is_empty(padapter, &offset) && offset) {
+ if (efuse_is_empty(adapter, &offset) && offset) {
for (i = 0; i < cnts; i++)
data[i] = 0xFF;
return ret;
}
offset = (addr >> 3) & 0xF;
- ret = r8712_efuse_pg_packet_read(padapter, offset, pktdata);
+ ret = r8712_efuse_pg_packet_read(adapter, offset, pktdata);
i = addr & 0x7; /* pktdata index */
idx = 0; /* data index */
@@ -475,14 +475,14 @@ u8 r8712_efuse_map_read(struct _adapter *padapter, u16 addr, u16 cnts, u8 *data)
return ret;
}
offset++;
- if (!r8712_efuse_pg_packet_read(padapter, offset, pktdata))
+ if (!r8712_efuse_pg_packet_read(adapter, offset, pktdata))
ret = false;
i = 0;
} while (1);
return ret;
}
-u8 r8712_efuse_map_write(struct _adapter *padapter, u16 addr, u16 cnts,
+u8 r8712_efuse_map_write(struct _adapter *adapter, u16 addr, u16 cnts,
u8 *data)
{
u8 offset, word_en, empty;
@@ -492,10 +492,10 @@ u8 r8712_efuse_map_write(struct _adapter *padapter, u16 addr, u16 cnts,
if ((addr + cnts) > EFUSE_MAP_MAX_SIZE)
return false;
/* check if E-Fuse Clock Enable and E-Fuse Clock is 40M */
- empty = r8712_read8(padapter, EFUSE_CLK_CTRL);
+ empty = r8712_read8(adapter, EFUSE_CLK_CTRL);
if (empty != 0x03)
return false;
- if (efuse_is_empty(padapter, &empty)) {
+ if (efuse_is_empty(adapter, &empty)) {
if (empty)
memset(pktdata, 0xFF, PGPKT_DATA_SIZE);
} else {
@@ -503,7 +503,7 @@ u8 r8712_efuse_map_write(struct _adapter *padapter, u16 addr, u16 cnts,
}
offset = (addr >> 3) & 0xF;
if (!empty)
- if (!r8712_efuse_pg_packet_read(padapter, offset, pktdata))
+ if (!r8712_efuse_pg_packet_read(adapter, offset, pktdata))
return false;
word_en = 0xF;
memset(newdata, 0xFF, PGPKT_DATA_SIZE);
@@ -546,14 +546,14 @@ u8 r8712_efuse_map_write(struct _adapter *padapter, u16 addr, u16 cnts,
}
if (word_en != 0xF)
- if (!r8712_efuse_pg_packet_write(padapter, offset,
+ if (!r8712_efuse_pg_packet_write(adapter, offset,
word_en, newdata))
return false;
if (idx == cnts)
break;
offset++;
if (!empty)
- if (!r8712_efuse_pg_packet_read(padapter, offset,
+ if (!r8712_efuse_pg_packet_read(adapter, offset,
pktdata))
return false;
i = 0;
diff --git a/drivers/staging/rtl8712/rtl8712_xmit.c b/drivers/staging/rtl8712/rtl8712_xmit.c
index 7574a4b569a4..307b0e292976 100644
--- a/drivers/staging/rtl8712/rtl8712_xmit.c
+++ b/drivers/staging/rtl8712/rtl8712_xmit.c
@@ -419,7 +419,7 @@ static void update_txdesc(struct xmit_frame *pxmitframe, uint *pmem, int sz)
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
#endif
u8 blnSetTxDescOffset;
- sint bmcst = IS_MCAST(pattrib->ra);
+ bool bmcst = is_multicast_ether_addr(pattrib->ra);
struct ht_priv *phtpriv = &pmlmepriv->htpriv;
struct tx_desc txdesc_mp;
diff --git a/drivers/staging/rtl8712/rtl871x_cmd.c b/drivers/staging/rtl8712/rtl871x_cmd.c
index 05a78ac24987..26b618008fcf 100644
--- a/drivers/staging/rtl8712/rtl871x_cmd.c
+++ b/drivers/staging/rtl8712/rtl871x_cmd.c
@@ -43,7 +43,7 @@
* No irqsave is necessary.
*/
-static sint _init_cmd_priv(struct cmd_priv *pcmdpriv)
+int r8712_init_cmd_priv(struct cmd_priv *pcmdpriv)
{
init_completion(&pcmdpriv->cmd_queue_comp);
init_completion(&pcmdpriv->terminate_cmdthread_comp);
@@ -55,7 +55,7 @@ static sint _init_cmd_priv(struct cmd_priv *pcmdpriv)
pcmdpriv->cmd_allocated_buf = kmalloc(MAX_CMDSZ + CMDBUFF_ALIGN_SZ,
GFP_ATOMIC);
if (!pcmdpriv->cmd_allocated_buf)
- return _FAIL;
+ return -ENOMEM;
pcmdpriv->cmd_buf = pcmdpriv->cmd_allocated_buf + CMDBUFF_ALIGN_SZ -
((addr_t)(pcmdpriv->cmd_allocated_buf) &
(CMDBUFF_ALIGN_SZ - 1));
@@ -63,36 +63,36 @@ static sint _init_cmd_priv(struct cmd_priv *pcmdpriv)
if (!pcmdpriv->rsp_allocated_buf) {
kfree(pcmdpriv->cmd_allocated_buf);
pcmdpriv->cmd_allocated_buf = NULL;
- return _FAIL;
+ return -ENOMEM;
}
pcmdpriv->rsp_buf = pcmdpriv->rsp_allocated_buf + 4 -
((addr_t)(pcmdpriv->rsp_allocated_buf) & 3);
pcmdpriv->cmd_issued_cnt = 0;
pcmdpriv->cmd_done_cnt = 0;
pcmdpriv->rsp_cnt = 0;
- return _SUCCESS;
+ return 0;
}
-static sint _init_evt_priv(struct evt_priv *pevtpriv)
+int r8712_init_evt_priv(struct evt_priv *pevtpriv)
{
/* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
pevtpriv->event_seq = 0;
pevtpriv->evt_allocated_buf = kmalloc(MAX_EVTSZ + 4, GFP_ATOMIC);
if (!pevtpriv->evt_allocated_buf)
- return _FAIL;
+ return -ENOMEM;
pevtpriv->evt_buf = pevtpriv->evt_allocated_buf + 4 -
((addr_t)(pevtpriv->evt_allocated_buf) & 3);
pevtpriv->evt_done_cnt = 0;
- return _SUCCESS;
+ return 0;
}
-static void _free_evt_priv(struct evt_priv *pevtpriv)
+void r8712_free_evt_priv(struct evt_priv *pevtpriv)
{
kfree(pevtpriv->evt_allocated_buf);
}
-static void _free_cmd_priv(struct cmd_priv *pcmdpriv)
+void r8712_free_cmd_priv(struct cmd_priv *pcmdpriv)
{
if (pcmdpriv) {
kfree(pcmdpriv->cmd_allocated_buf);
@@ -103,26 +103,30 @@ static void _free_cmd_priv(struct cmd_priv *pcmdpriv)
/*
* Calling Context:
*
- * _enqueue_cmd can only be called between kernel thread,
+ * r8712_enqueue_cmd can only be called between kernel thread,
* since only spin_lock is used.
*
* ISR/Call-Back functions can't call this sub-function.
*
*/
-static sint _enqueue_cmd(struct __queue *queue, struct cmd_obj *obj)
+void r8712_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *obj)
{
+ struct __queue *queue;
unsigned long irqL;
+ if (pcmdpriv->padapter->eeprompriv.bautoload_fail_flag)
+ return;
if (!obj)
- return _SUCCESS;
+ return;
+ queue = &pcmdpriv->cmd_queue;
spin_lock_irqsave(&queue->lock, irqL);
list_add_tail(&obj->list, &queue->queue);
spin_unlock_irqrestore(&queue->lock, irqL);
- return _SUCCESS;
+ complete(&pcmdpriv->cmd_queue_comp);
}
-static struct cmd_obj *_dequeue_cmd(struct __queue *queue)
+struct cmd_obj *r8712_dequeue_cmd(struct __queue *queue)
{
unsigned long irqL;
struct cmd_obj *obj;
@@ -136,57 +140,20 @@ static struct cmd_obj *_dequeue_cmd(struct __queue *queue)
return obj;
}
-u32 r8712_init_cmd_priv(struct cmd_priv *pcmdpriv)
-{
- return _init_cmd_priv(pcmdpriv);
-}
-
-u32 r8712_init_evt_priv(struct evt_priv *pevtpriv)
-{
- return _init_evt_priv(pevtpriv);
-}
-
-void r8712_free_evt_priv(struct evt_priv *pevtpriv)
-{
- _free_evt_priv(pevtpriv);
-}
-
-void r8712_free_cmd_priv(struct cmd_priv *pcmdpriv)
-{
- _free_cmd_priv(pcmdpriv);
-}
-
-u32 r8712_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *obj)
-{
- int res;
-
- if (pcmdpriv->padapter->eeprompriv.bautoload_fail_flag)
- return _FAIL;
- res = _enqueue_cmd(&pcmdpriv->cmd_queue, obj);
- complete(&pcmdpriv->cmd_queue_comp);
- return res;
-}
-
-u32 r8712_enqueue_cmd_ex(struct cmd_priv *pcmdpriv, struct cmd_obj *obj)
+void r8712_enqueue_cmd_ex(struct cmd_priv *pcmdpriv, struct cmd_obj *obj)
{
unsigned long irqL;
struct __queue *queue;
if (!obj)
- return _SUCCESS;
+ return;
if (pcmdpriv->padapter->eeprompriv.bautoload_fail_flag)
- return _FAIL;
+ return;
queue = &pcmdpriv->cmd_queue;
spin_lock_irqsave(&queue->lock, irqL);
list_add_tail(&obj->list, &queue->queue);
spin_unlock_irqrestore(&queue->lock, irqL);
complete(&pcmdpriv->cmd_queue_comp);
- return _SUCCESS;
-}
-
-struct cmd_obj *r8712_dequeue_cmd(struct __queue *queue)
-{
- return _dequeue_cmd(queue);
}
void r8712_free_cmd_obj(struct cmd_obj *pcmd)
@@ -242,7 +209,7 @@ u8 r8712_sitesurvey_cmd(struct _adapter *padapter,
return _SUCCESS;
}
-u8 r8712_setdatarate_cmd(struct _adapter *padapter, u8 *rateset)
+int r8712_setdatarate_cmd(struct _adapter *padapter, u8 *rateset)
{
struct cmd_obj *ph2c;
struct setdatarate_parm *pbsetdataratepara;
@@ -250,21 +217,21 @@ u8 r8712_setdatarate_cmd(struct _adapter *padapter, u8 *rateset)
ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
if (!ph2c)
- return _FAIL;
+ return -ENOMEM;
pbsetdataratepara = kmalloc(sizeof(*pbsetdataratepara), GFP_ATOMIC);
if (!pbsetdataratepara) {
kfree(ph2c);
- return _FAIL;
+ return -ENOMEM;
}
init_h2fwcmd_w_parm_no_rsp(ph2c, pbsetdataratepara,
GEN_CMD_CODE(_SetDataRate));
pbsetdataratepara->mac_id = 5;
memcpy(pbsetdataratepara->datarates, rateset, NumRates);
r8712_enqueue_cmd(pcmdpriv, ph2c);
- return _SUCCESS;
+ return 0;
}
-u8 r8712_set_chplan_cmd(struct _adapter *padapter, int chplan)
+void r8712_set_chplan_cmd(struct _adapter *padapter, int chplan)
{
struct cmd_obj *ph2c;
struct SetChannelPlan_param *psetchplanpara;
@@ -272,81 +239,19 @@ u8 r8712_set_chplan_cmd(struct _adapter *padapter, int chplan)
ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
if (!ph2c)
- return _FAIL;
+ return;
psetchplanpara = kmalloc(sizeof(*psetchplanpara), GFP_ATOMIC);
if (!psetchplanpara) {
kfree(ph2c);
- return _FAIL;
+ return;
}
init_h2fwcmd_w_parm_no_rsp(ph2c, psetchplanpara,
GEN_CMD_CODE(_SetChannelPlan));
psetchplanpara->ChannelPlan = chplan;
r8712_enqueue_cmd(pcmdpriv, ph2c);
- return _SUCCESS;
-}
-
-u8 r8712_setbasicrate_cmd(struct _adapter *padapter, u8 *rateset)
-{
- struct cmd_obj *ph2c;
- struct setbasicrate_parm *pssetbasicratepara;
- struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
-
- ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
- if (!ph2c)
- return _FAIL;
- pssetbasicratepara = kmalloc(sizeof(*pssetbasicratepara), GFP_ATOMIC);
- if (!pssetbasicratepara) {
- kfree(ph2c);
- return _FAIL;
- }
- init_h2fwcmd_w_parm_no_rsp(ph2c, pssetbasicratepara,
- _SetBasicRate_CMD_);
- memcpy(pssetbasicratepara->basicrates, rateset, NumRates);
- r8712_enqueue_cmd(pcmdpriv, ph2c);
- return _SUCCESS;
-}
-
-u8 r8712_setfwdig_cmd(struct _adapter *padapter, u8 type)
-{
- struct cmd_obj *ph2c;
- struct writePTM_parm *pwriteptmparm;
- struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
-
- ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
- if (!ph2c)
- return _FAIL;
- pwriteptmparm = kmalloc(sizeof(*pwriteptmparm), GFP_ATOMIC);
- if (!pwriteptmparm) {
- kfree(ph2c);
- return _FAIL;
- }
- init_h2fwcmd_w_parm_no_rsp(ph2c, pwriteptmparm, GEN_CMD_CODE(_SetDIG));
- pwriteptmparm->type = type;
- r8712_enqueue_cmd(pcmdpriv, ph2c);
- return _SUCCESS;
-}
-
-u8 r8712_setfwra_cmd(struct _adapter *padapter, u8 type)
-{
- struct cmd_obj *ph2c;
- struct writePTM_parm *pwriteptmparm;
- struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
-
- ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
- if (!ph2c)
- return _FAIL;
- pwriteptmparm = kmalloc(sizeof(*pwriteptmparm), GFP_ATOMIC);
- if (!pwriteptmparm) {
- kfree(ph2c);
- return _FAIL;
- }
- init_h2fwcmd_w_parm_no_rsp(ph2c, pwriteptmparm, GEN_CMD_CODE(_SetRA));
- pwriteptmparm->type = type;
- r8712_enqueue_cmd(pcmdpriv, ph2c);
- return _SUCCESS;
}
-u8 r8712_setrfreg_cmd(struct _adapter *padapter, u8 offset, u32 val)
+int r8712_setrfreg_cmd(struct _adapter *padapter, u8 offset, u32 val)
{
struct cmd_obj *ph2c;
struct writeRF_parm *pwriterfparm;
@@ -354,20 +259,20 @@ u8 r8712_setrfreg_cmd(struct _adapter *padapter, u8 offset, u32 val)
ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
if (!ph2c)
- return _FAIL;
+ return -ENOMEM;
pwriterfparm = kmalloc(sizeof(*pwriterfparm), GFP_ATOMIC);
if (!pwriterfparm) {
kfree(ph2c);
- return _FAIL;
+ return -ENOMEM;
}
init_h2fwcmd_w_parm_no_rsp(ph2c, pwriterfparm, GEN_CMD_CODE(_SetRFReg));
pwriterfparm->offset = offset;
pwriterfparm->value = val;
r8712_enqueue_cmd(pcmdpriv, ph2c);
- return _SUCCESS;
+ return 0;
}
-u8 r8712_getrfreg_cmd(struct _adapter *padapter, u8 offset, u8 *pval)
+int r8712_getrfreg_cmd(struct _adapter *padapter, u8 offset, u8 *pval)
{
struct cmd_obj *ph2c;
struct readRF_parm *prdrfparm;
@@ -375,11 +280,11 @@ u8 r8712_getrfreg_cmd(struct _adapter *padapter, u8 offset, u8 *pval)
ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
if (!ph2c)
- return _FAIL;
+ return -ENOMEM;
prdrfparm = kmalloc(sizeof(*prdrfparm), GFP_ATOMIC);
if (!prdrfparm) {
kfree(ph2c);
- return _FAIL;
+ return -ENOMEM;
}
INIT_LIST_HEAD(&ph2c->list);
ph2c->cmdcode = GEN_CMD_CODE(_GetRFReg);
@@ -389,7 +294,7 @@ u8 r8712_getrfreg_cmd(struct _adapter *padapter, u8 offset, u8 *pval)
ph2c->rspsz = sizeof(struct readRF_rsp);
prdrfparm->offset = offset;
r8712_enqueue_cmd(pcmdpriv, ph2c);
- return _SUCCESS;
+ return 0;
}
void r8712_getbbrfreg_cmdrsp_callback(struct _adapter *padapter,
@@ -409,7 +314,7 @@ void r8712_readtssi_cmdrsp_callback(struct _adapter *padapter,
padapter->mppriv.workparam.bcompleted = true;
}
-u8 r8712_createbss_cmd(struct _adapter *padapter)
+int r8712_createbss_cmd(struct _adapter *padapter)
{
struct cmd_obj *pcmd;
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
@@ -419,7 +324,7 @@ u8 r8712_createbss_cmd(struct _adapter *padapter)
padapter->ledpriv.LedControlHandler(padapter, LED_CTL_START_TO_LINK);
pcmd = kmalloc(sizeof(*pcmd), GFP_ATOMIC);
if (!pcmd)
- return _FAIL;
+ return -ENOMEM;
INIT_LIST_HEAD(&pcmd->list);
pcmd->cmdcode = _CreateBss_CMD_;
pcmd->parmbuf = (unsigned char *)pdev_network;
@@ -431,10 +336,10 @@ u8 r8712_createbss_cmd(struct _adapter *padapter)
pdev_network->IELength = pdev_network->IELength;
pdev_network->Ssid.SsidLength = pdev_network->Ssid.SsidLength;
r8712_enqueue_cmd(pcmdpriv, pcmd);
- return _SUCCESS;
+ return 0;
}
-u8 r8712_joinbss_cmd(struct _adapter *padapter, struct wlan_network *pnetwork)
+int r8712_joinbss_cmd(struct _adapter *padapter, struct wlan_network *pnetwork)
{
struct wlan_bssid_ex *psecnetwork;
struct cmd_obj *pcmd;
@@ -449,7 +354,7 @@ u8 r8712_joinbss_cmd(struct _adapter *padapter, struct wlan_network *pnetwork)
padapter->ledpriv.LedControlHandler(padapter, LED_CTL_START_TO_LINK);
pcmd = kmalloc(sizeof(*pcmd), GFP_ATOMIC);
if (!pcmd)
- return _FAIL;
+ return -ENOMEM;
/* for hidden ap to set fw_state here */
if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_ADHOC_STATE) !=
@@ -468,10 +373,6 @@ u8 r8712_joinbss_cmd(struct _adapter *padapter, struct wlan_network *pnetwork)
}
}
psecnetwork = &psecuritypriv->sec_bss;
- if (!psecnetwork) {
- kfree(pcmd);
- return _FAIL;
- }
memcpy(psecnetwork, &pnetwork->network, sizeof(*psecnetwork));
psecuritypriv->authenticator_ie[0] = (unsigned char)
psecnetwork->IELength;
@@ -570,10 +471,10 @@ u8 r8712_joinbss_cmd(struct _adapter *padapter, struct wlan_network *pnetwork)
pcmd->rsp = NULL;
pcmd->rspsz = 0;
r8712_enqueue_cmd(pcmdpriv, pcmd);
- return _SUCCESS;
+ return 0;
}
-u8 r8712_disassoc_cmd(struct _adapter *padapter) /* for sta_mode */
+void r8712_disassoc_cmd(struct _adapter *padapter) /* for sta_mode */
{
struct cmd_obj *pdisconnect_cmd;
struct disconnect_parm *pdisconnect;
@@ -581,19 +482,18 @@ u8 r8712_disassoc_cmd(struct _adapter *padapter) /* for sta_mode */
pdisconnect_cmd = kmalloc(sizeof(*pdisconnect_cmd), GFP_ATOMIC);
if (!pdisconnect_cmd)
- return _FAIL;
+ return;
pdisconnect = kmalloc(sizeof(*pdisconnect), GFP_ATOMIC);
if (!pdisconnect) {
kfree(pdisconnect_cmd);
- return _FAIL;
+ return;
}
init_h2fwcmd_w_parm_no_rsp(pdisconnect_cmd, pdisconnect,
_DisConnect_CMD_);
r8712_enqueue_cmd(pcmdpriv, pdisconnect_cmd);
- return _SUCCESS;
}
-u8 r8712_setopmode_cmd(struct _adapter *padapter,
+void r8712_setopmode_cmd(struct _adapter *padapter,
enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype)
{
struct cmd_obj *ph2c;
@@ -603,19 +503,18 @@ u8 r8712_setopmode_cmd(struct _adapter *padapter,
ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
if (!ph2c)
- return _FAIL;
+ return;
psetop = kmalloc(sizeof(*psetop), GFP_ATOMIC);
if (!psetop) {
kfree(ph2c);
- return _FAIL;
+ return;
}
init_h2fwcmd_w_parm_no_rsp(ph2c, psetop, _SetOpMode_CMD_);
psetop->mode = (u8)networktype;
r8712_enqueue_cmd(pcmdpriv, ph2c);
- return _SUCCESS;
}
-u8 r8712_setstakey_cmd(struct _adapter *padapter, u8 *psta, u8 unicast_key)
+void r8712_setstakey_cmd(struct _adapter *padapter, u8 *psta, u8 unicast_key)
{
struct cmd_obj *ph2c;
struct set_stakey_parm *psetstakey_para;
@@ -627,17 +526,17 @@ u8 r8712_setstakey_cmd(struct _adapter *padapter, u8 *psta, u8 unicast_key)
ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
if (!ph2c)
- return _FAIL;
+ return;
psetstakey_para = kmalloc(sizeof(*psetstakey_para), GFP_ATOMIC);
if (!psetstakey_para) {
kfree(ph2c);
- return _FAIL;
+ return;
}
psetstakey_rsp = kmalloc(sizeof(*psetstakey_rsp), GFP_ATOMIC);
if (!psetstakey_rsp) {
kfree(ph2c);
kfree(psetstakey_para);
- return _FAIL;
+ return;
}
init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
ph2c->rsp = (u8 *) psetstakey_rsp;
@@ -656,53 +555,9 @@ u8 r8712_setstakey_cmd(struct _adapter *padapter, u8 *psta, u8 unicast_key)
&psecuritypriv->XGrpKey[
psecuritypriv->XGrpKeyid - 1]. skey, 16);
r8712_enqueue_cmd(pcmdpriv, ph2c);
- return _SUCCESS;
-}
-
-u8 r8712_setrfintfs_cmd(struct _adapter *padapter, u8 mode)
-{
- struct cmd_obj *ph2c;
- struct setrfintfs_parm *psetrfintfsparm;
- struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
-
- ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
- if (!ph2c)
- return _FAIL;
- psetrfintfsparm = kmalloc(sizeof(*psetrfintfsparm), GFP_ATOMIC);
- if (!psetrfintfsparm) {
- kfree(ph2c);
- return _FAIL;
- }
- init_h2fwcmd_w_parm_no_rsp(ph2c, psetrfintfsparm,
- GEN_CMD_CODE(_SetRFIntFs));
- psetrfintfsparm->rfintfs = mode;
- r8712_enqueue_cmd(pcmdpriv, ph2c);
- return _SUCCESS;
-}
-
-u8 r8712_setrttbl_cmd(struct _adapter *padapter,
- struct setratable_parm *prate_table)
-{
- struct cmd_obj *ph2c;
- struct setratable_parm *psetrttblparm;
- struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
-
- ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
- if (!ph2c)
- return _FAIL;
- psetrttblparm = kmalloc(sizeof(*psetrttblparm), GFP_ATOMIC);
- if (!psetrttblparm) {
- kfree(ph2c);
- return _FAIL;
- }
- init_h2fwcmd_w_parm_no_rsp(ph2c, psetrttblparm,
- GEN_CMD_CODE(_SetRaTable));
- memcpy(psetrttblparm, prate_table, sizeof(struct setratable_parm));
- r8712_enqueue_cmd(pcmdpriv, ph2c);
- return _SUCCESS;
}
-u8 r8712_setMacAddr_cmd(struct _adapter *padapter, u8 *mac_addr)
+void r8712_setMacAddr_cmd(struct _adapter *padapter, u8 *mac_addr)
{
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
struct cmd_obj *ph2c;
@@ -710,49 +565,19 @@ u8 r8712_setMacAddr_cmd(struct _adapter *padapter, u8 *mac_addr)
ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
if (!ph2c)
- return _FAIL;
+ return;
psetMacAddr_para = kmalloc(sizeof(*psetMacAddr_para), GFP_ATOMIC);
if (!psetMacAddr_para) {
kfree(ph2c);
- return _FAIL;
+ return;
}
init_h2fwcmd_w_parm_no_rsp(ph2c, psetMacAddr_para,
_SetMacAddress_CMD_);
ether_addr_copy(psetMacAddr_para->MacAddr, mac_addr);
r8712_enqueue_cmd(pcmdpriv, ph2c);
- return _SUCCESS;
-}
-
-u8 r8712_setassocsta_cmd(struct _adapter *padapter, u8 *mac_addr)
-{
- struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
- struct cmd_obj *ph2c;
- struct set_assocsta_parm *psetassocsta_para;
- struct set_assocsta_rsp *psetassocsta_rsp = NULL;
-
- ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
- if (!ph2c)
- return _FAIL;
- psetassocsta_para = kmalloc(sizeof(*psetassocsta_para), GFP_ATOMIC);
- if (!psetassocsta_para) {
- kfree(ph2c);
- return _FAIL;
- }
- psetassocsta_rsp = kmalloc(sizeof(*psetassocsta_rsp), GFP_ATOMIC);
- if (!psetassocsta_rsp) {
- kfree(ph2c);
- kfree(psetassocsta_para);
- return _FAIL;
- }
- init_h2fwcmd_w_parm_no_rsp(ph2c, psetassocsta_para, _SetAssocSta_CMD_);
- ph2c->rsp = (u8 *) psetassocsta_rsp;
- ph2c->rspsz = sizeof(struct set_assocsta_rsp);
- ether_addr_copy(psetassocsta_para->addr, mac_addr);
- r8712_enqueue_cmd(pcmdpriv, ph2c);
- return _SUCCESS;
}
-u8 r8712_addbareq_cmd(struct _adapter *padapter, u8 tid)
+void r8712_addbareq_cmd(struct _adapter *padapter, u8 tid)
{
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
struct cmd_obj *ph2c;
@@ -760,20 +585,19 @@ u8 r8712_addbareq_cmd(struct _adapter *padapter, u8 tid)
ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
if (!ph2c)
- return _FAIL;
+ return;
paddbareq_parm = kmalloc(sizeof(*paddbareq_parm), GFP_ATOMIC);
if (!paddbareq_parm) {
kfree(ph2c);
- return _FAIL;
+ return;
}
paddbareq_parm->tid = tid;
init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm,
GEN_CMD_CODE(_AddBAReq));
r8712_enqueue_cmd_ex(pcmdpriv, ph2c);
- return _SUCCESS;
}
-u8 r8712_wdg_wk_cmd(struct _adapter *padapter)
+void r8712_wdg_wk_cmd(struct _adapter *padapter)
{
struct cmd_obj *ph2c;
struct drvint_cmd_parm *pdrvintcmd_param;
@@ -781,18 +605,17 @@ u8 r8712_wdg_wk_cmd(struct _adapter *padapter)
ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
if (!ph2c)
- return _FAIL;
+ return;
pdrvintcmd_param = kmalloc(sizeof(*pdrvintcmd_param), GFP_ATOMIC);
if (!pdrvintcmd_param) {
kfree(ph2c);
- return _FAIL;
+ return;
}
pdrvintcmd_param->i_cid = WDG_WK_CID;
pdrvintcmd_param->sz = 0;
pdrvintcmd_param->pbuf = NULL;
init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvintcmd_param, _DRV_INT_CMD_);
r8712_enqueue_cmd_ex(pcmdpriv, ph2c);
- return _SUCCESS;
}
void r8712_survey_cmd_callback(struct _adapter *padapter, struct cmd_obj *pcmd)
@@ -949,7 +772,7 @@ void r8712_setassocsta_cmdrsp_callback(struct _adapter *padapter,
r8712_free_cmd_obj(pcmd);
}
-u8 r8712_disconnectCtrlEx_cmd(struct _adapter *adapter, u32 enableDrvCtrl,
+void r8712_disconnectCtrlEx_cmd(struct _adapter *adapter, u32 enableDrvCtrl,
u32 tryPktCnt, u32 tryPktInterval, u32 firstStageTO)
{
struct cmd_obj *ph2c;
@@ -958,11 +781,11 @@ u8 r8712_disconnectCtrlEx_cmd(struct _adapter *adapter, u32 enableDrvCtrl,
ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC);
if (!ph2c)
- return _FAIL;
+ return;
param = kzalloc(sizeof(*param), GFP_ATOMIC);
if (!param) {
kfree(ph2c);
- return _FAIL;
+ return;
}
param->EnableDrvCtrl = (unsigned char)enableDrvCtrl;
@@ -973,5 +796,4 @@ u8 r8712_disconnectCtrlEx_cmd(struct _adapter *adapter, u32 enableDrvCtrl,
init_h2fwcmd_w_parm_no_rsp(ph2c, param,
GEN_CMD_CODE(_DisconnectCtrlEx));
r8712_enqueue_cmd(pcmdpriv, ph2c);
- return _SUCCESS;
}
diff --git a/drivers/staging/rtl8712/rtl871x_cmd.h b/drivers/staging/rtl8712/rtl871x_cmd.h
index 262984c58efb..98d7fbfce1a5 100644
--- a/drivers/staging/rtl8712/rtl871x_cmd.h
+++ b/drivers/staging/rtl8712/rtl871x_cmd.h
@@ -79,14 +79,14 @@ do {\
pcmd->rspsz = 0;\
} while (0)
-u32 r8712_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *obj);
-u32 r8712_enqueue_cmd_ex(struct cmd_priv *pcmdpriv, struct cmd_obj *obj);
+void r8712_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *obj);
+void r8712_enqueue_cmd_ex(struct cmd_priv *pcmdpriv, struct cmd_obj *obj);
struct cmd_obj *r8712_dequeue_cmd(struct __queue *queue);
void r8712_free_cmd_obj(struct cmd_obj *pcmd);
int r8712_cmd_thread(void *context);
-u32 r8712_init_cmd_priv(struct cmd_priv *pcmdpriv);
+int r8712_init_cmd_priv(struct cmd_priv *pcmdpriv);
void r8712_free_cmd_priv(struct cmd_priv *pcmdpriv);
-u32 r8712_init_evt_priv(struct evt_priv *pevtpriv);
+int r8712_init_evt_priv(struct evt_priv *pevtpriv);
void r8712_free_evt_priv(struct evt_priv *pevtpriv);
enum rtl871x_drvint_cid {
@@ -708,29 +708,22 @@ struct DisconnectCtrlEx_param {
#define H2C_CMD_OVERFLOW 0x06
#define H2C_RESERVED 0x07
-u8 r8712_setMacAddr_cmd(struct _adapter *padapter, u8 *mac_addr);
-u8 r8712_setassocsta_cmd(struct _adapter *padapter, u8 *mac_addr);
+void r8712_setMacAddr_cmd(struct _adapter *padapter, u8 *mac_addr);
u8 r8712_sitesurvey_cmd(struct _adapter *padapter,
struct ndis_802_11_ssid *pssid);
-u8 r8712_createbss_cmd(struct _adapter *padapter);
-u8 r8712_setstakey_cmd(struct _adapter *padapter, u8 *psta, u8 unicast_key);
-u8 r8712_joinbss_cmd(struct _adapter *padapter,
- struct wlan_network *pnetwork);
-u8 r8712_disassoc_cmd(struct _adapter *padapter);
-u8 r8712_setopmode_cmd(struct _adapter *padapter,
+int r8712_createbss_cmd(struct _adapter *padapter);
+void r8712_setstakey_cmd(struct _adapter *padapter, u8 *psta, u8 unicast_key);
+int r8712_joinbss_cmd(struct _adapter *padapter,
+ struct wlan_network *pnetwork);
+void r8712_disassoc_cmd(struct _adapter *padapter);
+void r8712_setopmode_cmd(struct _adapter *padapter,
enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype);
-u8 r8712_setdatarate_cmd(struct _adapter *padapter, u8 *rateset);
-u8 r8712_set_chplan_cmd(struct _adapter *padapter, int chplan);
-u8 r8712_setbasicrate_cmd(struct _adapter *padapter, u8 *rateset);
-u8 r8712_getrfreg_cmd(struct _adapter *padapter, u8 offset, u8 *pval);
-u8 r8712_setrfintfs_cmd(struct _adapter *padapter, u8 mode);
-u8 r8712_setrfreg_cmd(struct _adapter *padapter, u8 offset, u32 val);
-u8 r8712_setrttbl_cmd(struct _adapter *padapter,
- struct setratable_parm *prate_table);
-u8 r8712_setfwdig_cmd(struct _adapter *padapter, u8 type);
-u8 r8712_setfwra_cmd(struct _adapter *padapter, u8 type);
-u8 r8712_addbareq_cmd(struct _adapter *padapter, u8 tid);
-u8 r8712_wdg_wk_cmd(struct _adapter *padapter);
+int r8712_setdatarate_cmd(struct _adapter *padapter, u8 *rateset);
+void r8712_set_chplan_cmd(struct _adapter *padapter, int chplan);
+int r8712_getrfreg_cmd(struct _adapter *padapter, u8 offset, u8 *pval);
+int r8712_setrfreg_cmd(struct _adapter *padapter, u8 offset, u32 val);
+void r8712_addbareq_cmd(struct _adapter *padapter, u8 tid);
+void r8712_wdg_wk_cmd(struct _adapter *padapter);
void r8712_survey_cmd_callback(struct _adapter *padapter,
struct cmd_obj *pcmd);
void r8712_disassoc_cmd_callback(struct _adapter *padapter,
@@ -747,7 +740,7 @@ void r8712_setstaKey_cmdrsp_callback(struct _adapter *padapter,
struct cmd_obj *pcmd);
void r8712_setassocsta_cmdrsp_callback(struct _adapter *padapter,
struct cmd_obj *pcmd);
-u8 r8712_disconnectCtrlEx_cmd(struct _adapter *adapter, u32 enableDrvCtrl,
+void r8712_disconnectCtrlEx_cmd(struct _adapter *adapter, u32 enableDrvCtrl,
u32 tryPktCnt, u32 tryPktInterval, u32 firstStageTO);
struct _cmd_callback {
diff --git a/drivers/staging/rtl8712/rtl871x_eeprom.c b/drivers/staging/rtl8712/rtl871x_eeprom.c
index 0027d8eb22fa..221bf92e1b1c 100644
--- a/drivers/staging/rtl8712/rtl871x_eeprom.c
+++ b/drivers/staging/rtl8712/rtl871x_eeprom.c
@@ -150,7 +150,7 @@ void r8712_eeprom_write16(struct _adapter *padapter, u16 reg, u16 data)
x |= _EEM1 | _EECS;
r8712_write8(padapter, EE_9346CR, x);
shift_out_bits(padapter, EEPROM_EWEN_OPCODE, 5);
- if (padapter->EepromAddressSize == 8) /*CF+ and SDIO*/
+ if (padapter->eeprom_address_size == 8) /*CF+ and SDIO*/
shift_out_bits(padapter, 0, 6);
else /* USB */
shift_out_bits(padapter, 0, 4);
@@ -165,7 +165,7 @@ void r8712_eeprom_write16(struct _adapter *padapter, u16 reg, u16 data)
*/
shift_out_bits(padapter, EEPROM_WRITE_OPCODE, 3);
/* select which word in the EEPROM that we are writing to. */
- shift_out_bits(padapter, reg, padapter->EepromAddressSize);
+ shift_out_bits(padapter, reg, padapter->eeprom_address_size);
/* write the data to the selected EEPROM word. */
shift_out_bits(padapter, data, 16);
if (wait_eeprom_cmd_done(padapter)) {
@@ -207,7 +207,7 @@ u16 r8712_eeprom_read16(struct _adapter *padapter, u16 reg) /*ReadEEprom*/
* The opcode is 3bits in length, reg is 6 bits long
*/
shift_out_bits(padapter, EEPROM_READ_OPCODE, 3);
- shift_out_bits(padapter, reg, padapter->EepromAddressSize);
+ shift_out_bits(padapter, reg, padapter->eeprom_address_size);
/* Now read the data (16 bits) in from the selected EEPROM word */
data = shift_in_bits(padapter);
eeprom_clean(padapter);
diff --git a/drivers/staging/rtl8712/rtl871x_io.c b/drivers/staging/rtl8712/rtl871x_io.c
index 17dafeffd6f4..87024d6a465e 100644
--- a/drivers/staging/rtl8712/rtl871x_io.c
+++ b/drivers/staging/rtl8712/rtl871x_io.c
@@ -107,13 +107,11 @@ uint r8712_alloc_io_queue(struct _adapter *adapter)
INIT_LIST_HEAD(&pio_queue->processing);
INIT_LIST_HEAD(&pio_queue->pending);
spin_lock_init(&pio_queue->lock);
- pio_queue->pallocated_free_ioreqs_buf = kmalloc(NUM_IOREQ *
+ pio_queue->pallocated_free_ioreqs_buf = kzalloc(NUM_IOREQ *
(sizeof(struct io_req)) + 4,
GFP_ATOMIC);
if ((pio_queue->pallocated_free_ioreqs_buf) == NULL)
goto alloc_io_queue_fail;
- memset(pio_queue->pallocated_free_ioreqs_buf, 0,
- (NUM_IOREQ * (sizeof(struct io_req)) + 4));
pio_queue->free_ioreqs_buf = pio_queue->pallocated_free_ioreqs_buf + 4
- ((addr_t)(pio_queue->pallocated_free_ioreqs_buf)
& 3);
diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
index a7230c0c7b23..b08b9a191a34 100644
--- a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
+++ b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
@@ -124,10 +124,91 @@ static inline void handle_group_key(struct ieee_param *param,
}
}
-static noinline_for_stack char *translate_scan(struct _adapter *padapter,
- struct iw_request_info *info,
- struct wlan_network *pnetwork,
- char *start, char *stop)
+static noinline_for_stack char *translate_scan_wpa(struct iw_request_info *info,
+ struct wlan_network *pnetwork,
+ struct iw_event *iwe,
+ char *start, char *stop)
+{
+ /* parsing WPA/WPA2 IE */
+ u8 buf[MAX_WPA_IE_LEN];
+ u8 wpa_ie[255], rsn_ie[255];
+ u16 wpa_len = 0, rsn_len = 0;
+ int n, i;
+
+ r8712_get_sec_ie(pnetwork->network.IEs,
+ pnetwork->network.IELength, rsn_ie, &rsn_len,
+ wpa_ie, &wpa_len);
+ if (wpa_len > 0) {
+ memset(buf, 0, MAX_WPA_IE_LEN);
+ n = sprintf(buf, "wpa_ie=");
+ for (i = 0; i < wpa_len; i++) {
+ n += snprintf(buf + n, MAX_WPA_IE_LEN - n,
+ "%02x", wpa_ie[i]);
+ if (n >= MAX_WPA_IE_LEN)
+ break;
+ }
+ memset(iwe, 0, sizeof(*iwe));
+ iwe->cmd = IWEVCUSTOM;
+ iwe->u.data.length = (u16)strlen(buf);
+ start = iwe_stream_add_point(info, start, stop,
+ iwe, buf);
+ memset(iwe, 0, sizeof(*iwe));
+ iwe->cmd = IWEVGENIE;
+ iwe->u.data.length = (u16)wpa_len;
+ start = iwe_stream_add_point(info, start, stop,
+ iwe, wpa_ie);
+ }
+ if (rsn_len > 0) {
+ memset(buf, 0, MAX_WPA_IE_LEN);
+ n = sprintf(buf, "rsn_ie=");
+ for (i = 0; i < rsn_len; i++) {
+ n += snprintf(buf + n, MAX_WPA_IE_LEN - n,
+ "%02x", rsn_ie[i]);
+ if (n >= MAX_WPA_IE_LEN)
+ break;
+ }
+ memset(iwe, 0, sizeof(*iwe));
+ iwe->cmd = IWEVCUSTOM;
+ iwe->u.data.length = strlen(buf);
+ start = iwe_stream_add_point(info, start, stop,
+ iwe, buf);
+ memset(iwe, 0, sizeof(*iwe));
+ iwe->cmd = IWEVGENIE;
+ iwe->u.data.length = rsn_len;
+ start = iwe_stream_add_point(info, start, stop, iwe,
+ rsn_ie);
+ }
+
+ return start;
+}
+
+static noinline_for_stack char *translate_scan_wps(struct iw_request_info *info,
+ struct wlan_network *pnetwork,
+ struct iw_event *iwe,
+ char *start, char *stop)
+{
+ /* parsing WPS IE */
+ u8 wps_ie[512];
+ uint wps_ielen;
+
+ if (r8712_get_wps_ie(pnetwork->network.IEs,
+ pnetwork->network.IELength,
+ wps_ie, &wps_ielen)) {
+ if (wps_ielen > 2) {
+ iwe->cmd = IWEVGENIE;
+ iwe->u.data.length = (u16)wps_ielen;
+ start = iwe_stream_add_point(info, start, stop,
+ iwe, wps_ie);
+ }
+ }
+
+ return start;
+}
+
+static char *translate_scan(struct _adapter *padapter,
+ struct iw_request_info *info,
+ struct wlan_network *pnetwork,
+ char *start, char *stop)
{
struct iw_event iwe;
struct ieee80211_ht_cap *pht_capie;
@@ -240,73 +321,11 @@ static noinline_for_stack char *translate_scan(struct _adapter *padapter,
/* Check if we added any event */
if ((current_val - start) > iwe_stream_lcp_len(info))
start = current_val;
- /* parsing WPA/WPA2 IE */
- {
- u8 buf[MAX_WPA_IE_LEN];
- u8 wpa_ie[255], rsn_ie[255];
- u16 wpa_len = 0, rsn_len = 0;
- int n;
-
- r8712_get_sec_ie(pnetwork->network.IEs,
- pnetwork->network.IELength, rsn_ie, &rsn_len,
- wpa_ie, &wpa_len);
- if (wpa_len > 0) {
- memset(buf, 0, MAX_WPA_IE_LEN);
- n = sprintf(buf, "wpa_ie=");
- for (i = 0; i < wpa_len; i++) {
- n += snprintf(buf + n, MAX_WPA_IE_LEN - n,
- "%02x", wpa_ie[i]);
- if (n >= MAX_WPA_IE_LEN)
- break;
- }
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = (u16)strlen(buf);
- start = iwe_stream_add_point(info, start, stop,
- &iwe, buf);
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = (u16)wpa_len;
- start = iwe_stream_add_point(info, start, stop,
- &iwe, wpa_ie);
- }
- if (rsn_len > 0) {
- memset(buf, 0, MAX_WPA_IE_LEN);
- n = sprintf(buf, "rsn_ie=");
- for (i = 0; i < rsn_len; i++) {
- n += snprintf(buf + n, MAX_WPA_IE_LEN - n,
- "%02x", rsn_ie[i]);
- if (n >= MAX_WPA_IE_LEN)
- break;
- }
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = strlen(buf);
- start = iwe_stream_add_point(info, start, stop,
- &iwe, buf);
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = rsn_len;
- start = iwe_stream_add_point(info, start, stop, &iwe,
- rsn_ie);
- }
- }
- { /* parsing WPS IE */
- u8 wps_ie[512];
- uint wps_ielen;
+ start = translate_scan_wpa(info, pnetwork, &iwe, start, stop);
+
+ start = translate_scan_wps(info, pnetwork, &iwe, start, stop);
- if (r8712_get_wps_ie(pnetwork->network.IEs,
- pnetwork->network.IELength,
- wps_ie, &wps_ielen)) {
- if (wps_ielen > 2) {
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = (u16)wps_ielen;
- start = iwe_stream_add_point(info, start, stop,
- &iwe, wps_ie);
- }
- }
- }
/* Add quality statistics */
iwe.cmd = IWEVQUAL;
rssi = r8712_signal_scale_mapping(pnetwork->network.Rssi);
@@ -478,13 +497,13 @@ static int r871x_set_wpa_ie(struct _adapter *padapter, char *pie,
goto exit;
}
if (r8712_parse_wpa_ie(buf, ielen, &group_cipher,
- &pairwise_cipher) == _SUCCESS) {
+ &pairwise_cipher) == 0) {
padapter->securitypriv.AuthAlgrthm = 2;
padapter->securitypriv.ndisauthtype =
Ndis802_11AuthModeWPAPSK;
}
if (r8712_parse_wpa2_ie(buf, ielen, &group_cipher,
- &pairwise_cipher) == _SUCCESS) {
+ &pairwise_cipher) == 0) {
padapter->securitypriv.AuthAlgrthm = 2;
padapter->securitypriv.ndisauthtype =
Ndis802_11AuthModeWPA2PSK;
@@ -1309,7 +1328,7 @@ static int r8711_wx_set_rate(struct net_device *dev,
u32 ratevalue = 0;
u8 datarates[NumRates];
u8 mpdatarate[NumRates] = {11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0xff};
- int i, ret = 0;
+ int i;
if (target_rate == -1) {
ratevalue = 11;
@@ -1367,9 +1386,7 @@ set_rate:
datarates[i] = 0xff;
}
}
- if (r8712_setdatarate_cmd(padapter, datarates) != _SUCCESS)
- ret = -ENOMEM;
- return ret;
+ return r8712_setdatarate_cmd(padapter, datarates);
}
static int r8711_wx_get_rate(struct net_device *dev,
@@ -1577,7 +1594,7 @@ static int r8711_wx_get_enc(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *keybuf)
{
- uint key, ret = 0;
+ uint key;
struct _adapter *padapter = netdev_priv(dev);
struct iw_point *erq = &(wrqu->encoding);
struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
@@ -1633,7 +1650,7 @@ static int r8711_wx_get_enc(struct net_device *dev,
erq->flags |= IW_ENCODE_DISABLED;
break;
}
- return ret;
+ return 0;
}
static int r8711_wx_get_power(struct net_device *dev,
diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_rtl.c b/drivers/staging/rtl8712/rtl871x_ioctl_rtl.c
index 2dc20da21679..b78101afc93d 100644
--- a/drivers/staging/rtl8712/rtl871x_ioctl_rtl.c
+++ b/drivers/staging/rtl8712/rtl871x_ioctl_rtl.c
@@ -429,7 +429,7 @@ uint oid_rt_pro_rf_write_registry_hdl(struct oid_par_priv*
return RNDIS_STATUS_NOT_ACCEPTED;
if (poid_par_priv->information_buf_len ==
(sizeof(unsigned long) * 3)) {
- if (!r8712_setrfreg_cmd(Adapter,
+ if (r8712_setrfreg_cmd(Adapter,
*(unsigned char *)poid_par_priv->information_buf,
(unsigned long)(*((unsigned long *)
poid_par_priv->information_buf + 2))))
@@ -467,7 +467,7 @@ uint oid_rt_pro_rf_read_registry_hdl(struct oid_par_priv *poid_par_priv)
* RegDataWidth = *((unsigned long *)InformationBuffer+1);
* RegDataValue = *((unsigned long *)InformationBuffer+2);
*/
- if (!r8712_getrfreg_cmd(Adapter,
+ if (r8712_getrfreg_cmd(Adapter,
*(unsigned char *)poid_par_priv->information_buf,
(unsigned char *)&Adapter->mppriv.workparam.io_value
))
diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_set.c b/drivers/staging/rtl8712/rtl871x_ioctl_set.c
index 2622d5e3bff9..f3c0a9348f56 100644
--- a/drivers/staging/rtl8712/rtl871x_ioctl_set.c
+++ b/drivers/staging/rtl8712/rtl871x_ioctl_set.c
@@ -66,7 +66,7 @@ static u8 do_join(struct _adapter *padapter)
}
ret = r8712_select_and_join_from_scan(pmlmepriv);
- if (ret == _SUCCESS) {
+ if (!ret) {
mod_timer(&pmlmepriv->assoc_timer,
jiffies + msecs_to_jiffies(MAX_JOIN_TIMEOUT));
} else {
@@ -84,7 +84,7 @@ static u8 do_join(struct _adapter *padapter)
sizeof(struct ndis_802_11_ssid));
r8712_update_registrypriv_dev_network(padapter);
r8712_generate_random_ibss(pibss);
- if (r8712_createbss_cmd(padapter) != _SUCCESS)
+ if (r8712_createbss_cmd(padapter))
return false;
pmlmepriv->to_join = false;
} else {
diff --git a/drivers/staging/rtl8712/rtl871x_mlme.c b/drivers/staging/rtl8712/rtl871x_mlme.c
index 7c7267d0fc9e..0cc879a4d43f 100644
--- a/drivers/staging/rtl8712/rtl871x_mlme.c
+++ b/drivers/staging/rtl8712/rtl871x_mlme.c
@@ -29,7 +29,7 @@
static void update_ht_cap(struct _adapter *padapter, u8 *pie, uint ie_len);
-static sint _init_mlme_priv(struct _adapter *padapter)
+int r8712_init_mlme_priv(struct _adapter *padapter)
{
sint i;
u8 *pbuf;
@@ -129,8 +129,8 @@ static void free_network_nolock(struct mlme_priv *pmlmepriv,
* Shall be called under atomic context...
* to avoid possible racing condition...
*/
-static struct wlan_network *_r8712_find_network(struct __queue *scanned_queue,
- u8 *addr)
+static struct wlan_network *r8712_find_network(struct __queue *scanned_queue,
+ u8 *addr)
{
unsigned long irqL;
struct list_head *phead, *plist;
@@ -151,7 +151,7 @@ static struct wlan_network *_r8712_find_network(struct __queue *scanned_queue,
return pnetwork;
}
-static void _free_network_queue(struct _adapter *padapter)
+void r8712_free_network_queue(struct _adapter *padapter)
{
unsigned long irqL;
struct list_head *phead, *plist;
@@ -205,11 +205,6 @@ u8 *r8712_get_capability_from_ie(u8 *ie)
return ie + 8 + 2;
}
-int r8712_init_mlme_priv(struct _adapter *padapter)
-{
- return _init_mlme_priv(padapter);
-}
-
void r8712_free_mlme_priv(struct mlme_priv *pmlmepriv)
{
kfree(pmlmepriv->free_bss_buf);
@@ -220,25 +215,6 @@ static struct wlan_network *alloc_network(struct mlme_priv *pmlmepriv)
return _r8712_alloc_network(pmlmepriv);
}
-void r8712_free_network_queue(struct _adapter *dev)
-{
- _free_network_queue(dev);
-}
-
-/*
- * return the wlan_network with the matching addr
- * Shall be called under atomic context...
- * to avoid possible racing condition...
- */
-static struct wlan_network *r8712_find_network(struct __queue *scanned_queue,
- u8 *addr)
-{
- struct wlan_network *pnetwork = _r8712_find_network(scanned_queue,
- addr);
-
- return pnetwork;
-}
-
int r8712_is_same_ibss(struct _adapter *adapter, struct wlan_network *pnetwork)
{
int ret = true;
@@ -558,8 +534,7 @@ void r8712_surveydone_event_callback(struct _adapter *adapter, u8 *pbuf)
if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
- if (r8712_select_and_join_from_scan(pmlmepriv)
- == _SUCCESS) {
+ if (!r8712_select_and_join_from_scan(pmlmepriv)) {
mod_timer(&pmlmepriv->assoc_timer, jiffies +
msecs_to_jiffies(MAX_JOIN_TIMEOUT));
} else {
@@ -584,8 +559,7 @@ void r8712_surveydone_event_callback(struct _adapter *adapter, u8 *pbuf)
} else {
pmlmepriv->to_join = false;
set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
- if (r8712_select_and_join_from_scan(pmlmepriv) ==
- _SUCCESS)
+ if (!r8712_select_and_join_from_scan(pmlmepriv))
mod_timer(&pmlmepriv->assoc_timer, jiffies +
msecs_to_jiffies(MAX_JOIN_TIMEOUT));
else
@@ -1091,11 +1065,6 @@ void _r8712_dhcp_timeout_handler (struct _adapter *adapter)
adapter->registrypriv.smart_ps);
}
-void _r8712_wdg_timeout_handler(struct _adapter *adapter)
-{
- r8712_wdg_wk_cmd(adapter);
-}
-
int r8712_select_and_join_from_scan(struct mlme_priv *pmlmepriv)
{
struct list_head *phead;
@@ -1116,7 +1085,7 @@ int r8712_select_and_join_from_scan(struct mlme_priv *pmlmepriv)
pnetwork = pnetwork_max_rssi;
goto ask_for_joinbss;
}
- return _FAIL;
+ return -EINVAL;
}
pnetwork = container_of(pmlmepriv->pscanned,
struct wlan_network, list);
diff --git a/drivers/staging/rtl8712/rtl871x_mlme.h b/drivers/staging/rtl8712/rtl871x_mlme.h
index 8a54181f4816..a160107e9801 100644
--- a/drivers/staging/rtl8712/rtl871x_mlme.h
+++ b/drivers/staging/rtl8712/rtl871x_mlme.h
@@ -172,7 +172,7 @@ void r8712_wpspbc_event_callback(struct _adapter *adapter, u8 *pbuf);
void r8712_free_network_queue(struct _adapter *adapter);
int r8712_init_mlme_priv(struct _adapter *adapter);
void r8712_free_mlme_priv(struct mlme_priv *pmlmepriv);
-sint r8712_select_and_join_from_scan(struct mlme_priv *pmlmepriv);
+int r8712_select_and_join_from_scan(struct mlme_priv *pmlmepriv);
sint r8712_set_key(struct _adapter *adapter,
struct security_priv *psecuritypriv, sint keyid);
sint r8712_set_auth(struct _adapter *adapter,
@@ -195,7 +195,6 @@ void _r8712_sitesurvey_ctrl_handler(struct _adapter *adapter);
void _r8712_join_timeout_handler(struct _adapter *adapter);
void r8712_scan_timeout_handler(struct _adapter *adapter);
void _r8712_dhcp_timeout_handler(struct _adapter *adapter);
-void _r8712_wdg_timeout_handler(struct _adapter *adapter);
struct wlan_network *_r8712_alloc_network(struct mlme_priv *pmlmepriv);
sint r8712_if_up(struct _adapter *padapter);
void r8712_joinbss_reset(struct _adapter *padapter);
diff --git a/drivers/staging/rtl8712/rtl871x_mp.c b/drivers/staging/rtl8712/rtl871x_mp.c
index ba379506da3f..edd3da05fc06 100644
--- a/drivers/staging/rtl8712/rtl871x_mp.c
+++ b/drivers/staging/rtl8712/rtl871x_mp.c
@@ -709,20 +709,18 @@ static u32 GetPhyRxPktCounts(struct _adapter *pAdapter, u32 selbit)
u32 r8712_GetPhyRxPktReceived(struct _adapter *pAdapter)
{
- u32 OFDM_cnt = 0, CCK_cnt = 0, HT_cnt = 0;
+ u32 OFDM_cnt = GetPhyRxPktCounts(pAdapter, OFDM_MPDU_OK_BIT);
+ u32 CCK_cnt = GetPhyRxPktCounts(pAdapter, CCK_MPDU_OK_BIT);
+ u32 HT_cnt = GetPhyRxPktCounts(pAdapter, HT_MPDU_OK_BIT);
- OFDM_cnt = GetPhyRxPktCounts(pAdapter, OFDM_MPDU_OK_BIT);
- CCK_cnt = GetPhyRxPktCounts(pAdapter, CCK_MPDU_OK_BIT);
- HT_cnt = GetPhyRxPktCounts(pAdapter, HT_MPDU_OK_BIT);
return OFDM_cnt + CCK_cnt + HT_cnt;
}
u32 r8712_GetPhyRxPktCRC32Error(struct _adapter *pAdapter)
{
- u32 OFDM_cnt = 0, CCK_cnt = 0, HT_cnt = 0;
+ u32 OFDM_cnt = GetPhyRxPktCounts(pAdapter, OFDM_MPDU_FAIL_BIT);
+ u32 CCK_cnt = GetPhyRxPktCounts(pAdapter, CCK_MPDU_FAIL_BIT);
+ u32 HT_cnt = GetPhyRxPktCounts(pAdapter, HT_MPDU_FAIL_BIT);
- OFDM_cnt = GetPhyRxPktCounts(pAdapter, OFDM_MPDU_FAIL_BIT);
- CCK_cnt = GetPhyRxPktCounts(pAdapter, CCK_MPDU_FAIL_BIT);
- HT_cnt = GetPhyRxPktCounts(pAdapter, HT_MPDU_FAIL_BIT);
return OFDM_cnt + CCK_cnt + HT_cnt;
}
diff --git a/drivers/staging/rtl8712/rtl871x_mp_ioctl.c b/drivers/staging/rtl8712/rtl871x_mp_ioctl.c
index 588346da1412..aa8f8500cbb2 100644
--- a/drivers/staging/rtl8712/rtl871x_mp_ioctl.c
+++ b/drivers/staging/rtl8712/rtl871x_mp_ioctl.c
@@ -153,7 +153,7 @@ static int mp_start_test(struct _adapter *padapter)
struct sta_info *psta;
unsigned long length;
unsigned long irqL;
- int res = _SUCCESS;
+ int res = 0;
/* 3 1. initialize a new struct wlan_bssid_ex */
memcpy(bssid.MacAddress, pmppriv->network_macaddr, ETH_ALEN);
@@ -187,7 +187,7 @@ static int mp_start_test(struct _adapter *padapter)
r8712_free_stainfo(padapter, psta);
psta = r8712_alloc_stainfo(&padapter->stapriv, bssid.MacAddress);
if (psta == NULL) {
- res = _FAIL;
+ res = -ENOMEM;
goto end_of_mp_start_test;
}
/* 3 3. join pseudo AdHoc */
@@ -231,22 +231,6 @@ end_of_mp_stop_test:
return _SUCCESS;
}
-int mp_start_joinbss(struct _adapter *padapter, struct ndis_802_11_ssid *pssid)
-{
- struct mp_priv *pmppriv = &padapter->mppriv;
- struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
- unsigned char res = _SUCCESS;
-
- if (!check_fwstate(pmlmepriv, WIFI_MP_STATE))
- return _FAIL;
- if (!check_fwstate(pmlmepriv, _FW_LINKED))
- return _FAIL;
- _clr_fwstate_(pmlmepriv, _FW_LINKED);
- res = r8712_setassocsta_cmd(padapter, pmppriv->network_macaddr);
- set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
- return res;
-}
-
uint oid_rt_pro_set_data_rate_hdl(struct oid_par_priv
*poid_par_priv)
{
@@ -278,7 +262,7 @@ uint oid_rt_pro_start_test_hdl(struct oid_par_priv *poid_par_priv)
return RNDIS_STATUS_NOT_ACCEPTED;
mode = *((u32 *)poid_par_priv->information_buf);
Adapter->mppriv.mode = mode;/* 1 for loopback*/
- if (mp_start_test(Adapter) == _FAIL)
+ if (mp_start_test(Adapter))
status = RNDIS_STATUS_NOT_ACCEPTED;
r8712_write8(Adapter, MSR, 1); /* Link in ad hoc network, 0x1025004C */
r8712_write8(Adapter, RCR, 0); /* RCR : disable all pkt, 0x10250048 */
@@ -661,11 +645,6 @@ uint oid_rt_pro_write_register_hdl(struct oid_par_priv *poid_par_priv)
status = RNDIS_STATUS_NOT_ACCEPTED;
break;
}
-
- if ((status == RNDIS_STATUS_SUCCESS) &&
- (RegRWStruct->offset == HIMR) &&
- (RegRWStruct->width == 4))
- Adapter->ImrContent = RegRWStruct->value;
}
return status;
}
diff --git a/drivers/staging/rtl8712/rtl871x_mp_ioctl.h b/drivers/staging/rtl8712/rtl871x_mp_ioctl.h
index 44cd911f2aa1..64e2ae436625 100644
--- a/drivers/staging/rtl8712/rtl871x_mp_ioctl.h
+++ b/drivers/staging/rtl8712/rtl871x_mp_ioctl.h
@@ -71,8 +71,6 @@ struct DR_VARIABLE_STRUCT {
u32 variable;
};
-int mp_start_joinbss(struct _adapter *padapter, struct ndis_802_11_ssid *pssid);
-
/* oid_rtl_seg_87_11_00 */
uint oid_rt_pro_read_register_hdl(struct oid_par_priv *poid_par_priv);
uint oid_rt_pro_write_register_hdl(struct oid_par_priv *poid_par_priv);
diff --git a/drivers/staging/rtl8712/rtl871x_recv.c b/drivers/staging/rtl8712/rtl871x_recv.c
index 28f736913292..5298fe603437 100644
--- a/drivers/staging/rtl8712/rtl871x_recv.c
+++ b/drivers/staging/rtl8712/rtl871x_recv.c
@@ -151,7 +151,7 @@ sint r8712_recvframe_chkmic(struct _adapter *adapter,
if (prxattrib->encrypt == _TKIP_) {
/* calculate mic code */
if (stainfo != NULL) {
- if (IS_MCAST(prxattrib->ra)) {
+ if (is_multicast_ether_addr(prxattrib->ra)) {
iv = precvframe->u.hdr.rx_data +
prxattrib->hdrlen;
idx = iv[3];
@@ -180,12 +180,12 @@ sint r8712_recvframe_chkmic(struct _adapter *adapter,
if (bmic_err) {
if (prxattrib->bdecrypted)
r8712_handle_tkip_mic_err(adapter,
- (u8)IS_MCAST(prxattrib->ra));
+ (u8)is_multicast_ether_addr(prxattrib->ra));
res = _FAIL;
} else {
/* mic checked ok */
if (!psecuritypriv->bcheck_grpkey &&
- IS_MCAST(prxattrib->ra))
+ is_multicast_ether_addr(prxattrib->ra))
psecuritypriv->bcheck_grpkey = true;
}
recvframe_pull_tail(precvframe, 8);
@@ -305,7 +305,7 @@ static sint sta2sta_data_frame(struct _adapter *adapter,
u8 *mybssid = get_bssid(pmlmepriv);
u8 *myhwaddr = myid(&adapter->eeprompriv);
u8 *sta_addr = NULL;
- sint bmcast = IS_MCAST(pattrib->dst);
+ bool bmcast = is_multicast_ether_addr(pattrib->dst);
if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) ||
check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
@@ -331,7 +331,7 @@ static sint sta2sta_data_frame(struct _adapter *adapter,
/* For AP mode, if DA == MCAST, then BSSID should
* be also MCAST
*/
- if (!IS_MCAST(pattrib->bssid))
+ if (!is_multicast_ether_addr(pattrib->bssid))
return _FAIL;
} else { /* not mc-frame */
/* For AP mode, if DA is non-MCAST, then it must be
@@ -373,7 +373,7 @@ static sint ap2sta_data_frame(struct _adapter *adapter,
struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
u8 *mybssid = get_bssid(pmlmepriv);
u8 *myhwaddr = myid(&adapter->eeprompriv);
- sint bmcast = IS_MCAST(pattrib->dst);
+ bool bmcast = is_multicast_ether_addr(pattrib->dst);
if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) &&
check_fwstate(pmlmepriv, _FW_LINKED)) {
@@ -532,7 +532,7 @@ static sint validate_recv_data_frame(struct _adapter *adapter,
if (pattrib->privacy) {
GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt,
- IS_MCAST(pattrib->ra));
+ is_multicast_ether_addr(pattrib->ra));
SET_ICE_IV_LEN(pattrib->iv_len, pattrib->icv_len,
pattrib->encrypt);
} else {
diff --git a/drivers/staging/rtl8712/rtl871x_security.c b/drivers/staging/rtl8712/rtl871x_security.c
index f82645011d02..693008bba83e 100644
--- a/drivers/staging/rtl8712/rtl871x_security.c
+++ b/drivers/staging/rtl8712/rtl871x_security.c
@@ -665,7 +665,7 @@ u32 r8712_tkip_decrypt(struct _adapter *padapter, u8 *precvframe)
length = ((union recv_frame *)precvframe)->
u.hdr.len - prxattrib->hdrlen -
prxattrib->iv_len;
- if (IS_MCAST(prxattrib->ra)) {
+ if (is_multicast_ether_addr(prxattrib->ra)) {
idx = iv[3];
prwskey = &psecuritypriv->XGrpKey[
((idx >> 6) & 0x3) - 1].skey[0];
@@ -1368,7 +1368,7 @@ u32 r8712_aes_decrypt(struct _adapter *padapter, u8 *precvframe)
stainfo = r8712_get_stainfo(&padapter->stapriv,
&prxattrib->ta[0]);
if (stainfo != NULL) {
- if (IS_MCAST(prxattrib->ra)) {
+ if (is_multicast_ether_addr(prxattrib->ra)) {
iv = pframe + prxattrib->hdrlen;
idx = iv[3];
prwskey = &psecuritypriv->XGrpKey[
diff --git a/drivers/staging/rtl8712/rtl871x_sta_mgt.c b/drivers/staging/rtl8712/rtl871x_sta_mgt.c
index 7c30b9e68e70..653812c5d5a8 100644
--- a/drivers/staging/rtl8712/rtl871x_sta_mgt.c
+++ b/drivers/staging/rtl8712/rtl871x_sta_mgt.c
@@ -34,7 +34,7 @@ static void _init_stainfo(struct sta_info *psta)
INIT_LIST_HEAD(&psta->auth_list);
}
-u32 _r8712_init_sta_priv(struct sta_priv *pstapriv)
+int _r8712_init_sta_priv(struct sta_priv *pstapriv)
{
struct sta_info *psta;
s32 i;
@@ -42,7 +42,7 @@ u32 _r8712_init_sta_priv(struct sta_priv *pstapriv)
pstapriv->pallocated_stainfo_buf = kmalloc(sizeof(struct sta_info) *
NUM_STA + 4, GFP_ATOMIC);
if (!pstapriv->pallocated_stainfo_buf)
- return _FAIL;
+ return -ENOMEM;
pstapriv->pstainfo_buf = pstapriv->pallocated_stainfo_buf + 4 -
((addr_t)(pstapriv->pallocated_stainfo_buf) & 3);
_init_queue(&pstapriv->free_sta_queue);
@@ -59,7 +59,7 @@ u32 _r8712_init_sta_priv(struct sta_priv *pstapriv)
}
INIT_LIST_HEAD(&pstapriv->asoc_list);
INIT_LIST_HEAD(&pstapriv->auth_list);
- return _SUCCESS;
+ return 0;
}
/* this function is used to free the memory of lock || sema for all stainfos */
@@ -77,14 +77,13 @@ static void mfree_all_stainfo(struct sta_priv *pstapriv)
spin_unlock_irqrestore(&pstapriv->sta_hash_lock, irqL);
}
-u32 _r8712_free_sta_priv(struct sta_priv *pstapriv)
+void _r8712_free_sta_priv(struct sta_priv *pstapriv)
{
if (pstapriv) {
/* be done before free sta_hash_lock */
mfree_all_stainfo(pstapriv);
kfree(pstapriv->pallocated_stainfo_buf);
}
- return _SUCCESS;
}
struct sta_info *r8712_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr)
diff --git a/drivers/staging/rtl8712/rtl871x_xmit.c b/drivers/staging/rtl8712/rtl871x_xmit.c
index f6fe8ea12961..0a26d71e5340 100644
--- a/drivers/staging/rtl8712/rtl871x_xmit.c
+++ b/drivers/staging/rtl8712/rtl871x_xmit.c
@@ -133,13 +133,14 @@ sint _r8712_init_xmit_priv(struct xmit_priv *pxmitpriv,
pxmitbuf->pbuf = pxmitbuf->pallocated_buf + XMITBUF_ALIGN_SZ -
((addr_t) (pxmitbuf->pallocated_buf) &
(XMITBUF_ALIGN_SZ - 1));
- r8712_xmit_resource_alloc(padapter, pxmitbuf);
+ if (r8712_xmit_resource_alloc(padapter, pxmitbuf))
+ return _FAIL;
list_add_tail(&pxmitbuf->list,
&(pxmitpriv->free_xmitbuf_queue.queue));
pxmitbuf++;
}
pxmitpriv->free_xmitbuf_cnt = NR_XMITBUFF;
- INIT_WORK(&padapter->wkFilterRxFF0, r8712_SetFilter);
+ INIT_WORK(&padapter->wk_filter_rx_ff0, r8712_SetFilter);
alloc_hwxmits(padapter);
init_hwxmits(pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry);
tasklet_init(&pxmitpriv->xmit_tasklet,
@@ -181,7 +182,7 @@ sint r8712_update_attrib(struct _adapter *padapter, _pkt *pkt,
struct tx_cmd txdesc;
- sint bmcast;
+ bool bmcast;
struct sta_priv *pstapriv = &padapter->stapriv;
struct security_priv *psecuritypriv = &padapter->securitypriv;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
@@ -257,7 +258,7 @@ sint r8712_update_attrib(struct _adapter *padapter, _pkt *pkt,
}
}
}
- bmcast = IS_MCAST(pattrib->ra);
+ bmcast = is_multicast_ether_addr(pattrib->ra);
/* get sta_info*/
if (bmcast) {
psta = r8712_get_bcmc_stainfo(padapter);
@@ -353,7 +354,7 @@ static sint xmitframe_addmic(struct _adapter *padapter,
struct security_priv *psecuritypriv = &padapter->securitypriv;
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
u8 priority[4] = {0x0, 0x0, 0x0, 0x0};
- sint bmcst = IS_MCAST(pattrib->ra);
+ bool bmcst = is_multicast_ether_addr(pattrib->ra);
if (pattrib->psta)
stainfo = pattrib->psta;
@@ -523,7 +524,7 @@ static sint make_wlanhdr(struct _adapter *padapter, u8 *hdr,
/* Update Seq Num will be handled by f/w */
{
struct sta_info *psta;
- sint bmcst = IS_MCAST(pattrib->ra);
+ bool bmcst = is_multicast_ether_addr(pattrib->ra);
if (pattrib->psta) {
psta = pattrib->psta;
@@ -594,7 +595,7 @@ sint r8712_xmitframe_coalesce(struct _adapter *padapter, _pkt *pkt,
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
struct pkt_attrib *pattrib = &pxmitframe->attrib;
u8 *pbuf_start;
- sint bmcst = IS_MCAST(pattrib->ra);
+ bool bmcst = is_multicast_ether_addr(pattrib->ra);
if (pattrib->psta == NULL)
return _FAIL;
@@ -903,7 +904,7 @@ sint r8712_xmit_classifier(struct _adapter *padapter,
struct pkt_attrib *pattrib = &pxmitframe->attrib;
struct sta_priv *pstapriv = &padapter->stapriv;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
- sint bmcst = IS_MCAST(pattrib->ra);
+ bool bmcst = is_multicast_ether_addr(pattrib->ra);
if (pattrib->psta) {
psta = pattrib->psta;
diff --git a/drivers/staging/rtl8712/rtl871x_xmit.h b/drivers/staging/rtl8712/rtl871x_xmit.h
index 3bea2e374f13..4199cb586fb1 100644
--- a/drivers/staging/rtl8712/rtl871x_xmit.h
+++ b/drivers/staging/rtl8712/rtl871x_xmit.h
@@ -148,8 +148,8 @@ struct xmit_frame {
_pkt *pkt;
int frame_tag;
struct _adapter *padapter;
- u8 *buf_addr;
- struct xmit_buf *pxmitbuf;
+ u8 *buf_addr;
+ struct xmit_buf *pxmitbuf;
u8 *mem_addr;
u16 sz[8];
struct urb *pxmit_urb[8];
diff --git a/drivers/staging/rtl8712/sta_info.h b/drivers/staging/rtl8712/sta_info.h
index 45dbed10295f..d042d900f30c 100644
--- a/drivers/staging/rtl8712/sta_info.h
+++ b/drivers/staging/rtl8712/sta_info.h
@@ -119,8 +119,8 @@ static inline u32 wifi_mac_hash(u8 *mac)
return x;
}
-u32 _r8712_init_sta_priv(struct sta_priv *pstapriv);
-u32 _r8712_free_sta_priv(struct sta_priv *pstapriv);
+int _r8712_init_sta_priv(struct sta_priv *pstapriv);
+void _r8712_free_sta_priv(struct sta_priv *pstapriv);
struct sta_info *r8712_alloc_stainfo(struct sta_priv *pstapriv,
u8 *hwaddr);
void r8712_free_stainfo(struct _adapter *padapter, struct sta_info *psta);
diff --git a/drivers/staging/rtl8712/usb_halinit.c b/drivers/staging/rtl8712/usb_halinit.c
index 02e73c2412d4..6cc4a704c3a0 100644
--- a/drivers/staging/rtl8712/usb_halinit.c
+++ b/drivers/staging/rtl8712/usb_halinit.c
@@ -21,258 +21,258 @@
#include "usb_ops.h"
#include "usb_osintf.h"
-u8 r8712_usb_hal_bus_init(struct _adapter *padapter)
+u8 r8712_usb_hal_bus_init(struct _adapter *adapter)
{
u8 val8 = 0;
u8 ret = _SUCCESS;
int PollingCnt = 20;
- struct registry_priv *pregistrypriv = &padapter->registrypriv;
+ struct registry_priv *registrypriv = &adapter->registrypriv;
- if (pregistrypriv->chip_version == RTL8712_FPGA) {
+ if (registrypriv->chip_version == RTL8712_FPGA) {
val8 = 0x01;
/* switch to 80M clock */
- r8712_write8(padapter, SYS_CLKR, val8);
- val8 = r8712_read8(padapter, SPS1_CTRL);
+ r8712_write8(adapter, SYS_CLKR, val8);
+ val8 = r8712_read8(adapter, SPS1_CTRL);
val8 = val8 | 0x01;
/* enable VSPS12 LDO Macro block */
- r8712_write8(padapter, SPS1_CTRL, val8);
- val8 = r8712_read8(padapter, AFE_MISC);
+ r8712_write8(adapter, SPS1_CTRL, val8);
+ val8 = r8712_read8(adapter, AFE_MISC);
val8 = val8 | 0x01;
/* Enable AFE Macro Block's Bandgap */
- r8712_write8(padapter, AFE_MISC, val8);
- val8 = r8712_read8(padapter, LDOA15_CTRL);
+ r8712_write8(adapter, AFE_MISC, val8);
+ val8 = r8712_read8(adapter, LDOA15_CTRL);
val8 = val8 | 0x01;
/* enable LDOA15 block */
- r8712_write8(padapter, LDOA15_CTRL, val8);
- val8 = r8712_read8(padapter, SPS1_CTRL);
+ r8712_write8(adapter, LDOA15_CTRL, val8);
+ val8 = r8712_read8(adapter, SPS1_CTRL);
val8 = val8 | 0x02;
/* Enable VSPS12_SW Macro Block */
- r8712_write8(padapter, SPS1_CTRL, val8);
- val8 = r8712_read8(padapter, AFE_MISC);
+ r8712_write8(adapter, SPS1_CTRL, val8);
+ val8 = r8712_read8(adapter, AFE_MISC);
val8 = val8 | 0x02;
/* Enable AFE Macro Block's Mbias */
- r8712_write8(padapter, AFE_MISC, val8);
- val8 = r8712_read8(padapter, SYS_ISO_CTRL + 1);
+ r8712_write8(adapter, AFE_MISC, val8);
+ val8 = r8712_read8(adapter, SYS_ISO_CTRL + 1);
val8 = val8 | 0x08;
/* isolate PCIe Analog 1.2V to PCIe 3.3V and PCIE Digital */
- r8712_write8(padapter, SYS_ISO_CTRL + 1, val8);
- val8 = r8712_read8(padapter, SYS_ISO_CTRL + 1);
+ r8712_write8(adapter, SYS_ISO_CTRL + 1, val8);
+ val8 = r8712_read8(adapter, SYS_ISO_CTRL + 1);
val8 = val8 & 0xEF;
/* attatch AFE PLL to MACTOP/BB/PCIe Digital */
- r8712_write8(padapter, SYS_ISO_CTRL + 1, val8);
- val8 = r8712_read8(padapter, AFE_XTAL_CTRL + 1);
+ r8712_write8(adapter, SYS_ISO_CTRL + 1, val8);
+ val8 = r8712_read8(adapter, AFE_XTAL_CTRL + 1);
val8 = val8 & 0xFB;
/* enable AFE clock */
- r8712_write8(padapter, AFE_XTAL_CTRL + 1, val8);
- val8 = r8712_read8(padapter, AFE_PLL_CTRL);
+ r8712_write8(adapter, AFE_XTAL_CTRL + 1, val8);
+ val8 = r8712_read8(adapter, AFE_PLL_CTRL);
val8 = val8 | 0x01;
/* Enable AFE PLL Macro Block */
- r8712_write8(padapter, AFE_PLL_CTRL, val8);
+ r8712_write8(adapter, AFE_PLL_CTRL, val8);
val8 = 0xEE;
/* release isolation AFE PLL & MD */
- r8712_write8(padapter, SYS_ISO_CTRL, val8);
- val8 = r8712_read8(padapter, SYS_CLKR + 1);
+ r8712_write8(adapter, SYS_ISO_CTRL, val8);
+ val8 = r8712_read8(adapter, SYS_CLKR + 1);
val8 = val8 | 0x08;
/* enable MAC clock */
- r8712_write8(padapter, SYS_CLKR + 1, val8);
- val8 = r8712_read8(padapter, SYS_FUNC_EN + 1);
+ r8712_write8(adapter, SYS_CLKR + 1, val8);
+ val8 = r8712_read8(adapter, SYS_FUNC_EN + 1);
val8 = val8 | 0x08;
/* enable Core digital and enable IOREG R/W */
- r8712_write8(padapter, SYS_FUNC_EN + 1, val8);
+ r8712_write8(adapter, SYS_FUNC_EN + 1, val8);
val8 = val8 | 0x80;
/* enable REG_EN */
- r8712_write8(padapter, SYS_FUNC_EN + 1, val8);
- val8 = r8712_read8(padapter, SYS_CLKR + 1);
+ r8712_write8(adapter, SYS_FUNC_EN + 1, val8);
+ val8 = r8712_read8(adapter, SYS_CLKR + 1);
val8 = (val8 | 0x80) & 0xBF;
/* switch the control path */
- r8712_write8(padapter, SYS_CLKR + 1, val8);
+ r8712_write8(adapter, SYS_CLKR + 1, val8);
val8 = 0xFC;
- r8712_write8(padapter, CR, val8);
+ r8712_write8(adapter, CR, val8);
val8 = 0x37;
- r8712_write8(padapter, CR + 1, val8);
+ r8712_write8(adapter, CR + 1, val8);
/* reduce EndPoint & init it */
- r8712_write8(padapter, 0x102500ab, r8712_read8(padapter,
+ r8712_write8(adapter, 0x102500ab, r8712_read8(adapter,
0x102500ab) | BIT(6) | BIT(7));
/* consideration of power consumption - init */
- r8712_write8(padapter, 0x10250008, r8712_read8(padapter,
+ r8712_write8(adapter, 0x10250008, r8712_read8(adapter,
0x10250008) & 0xfffffffb);
- } else if (pregistrypriv->chip_version == RTL8712_1stCUT) {
+ } else if (registrypriv->chip_version == RTL8712_1stCUT) {
/* Initialization for power on sequence, */
- r8712_write8(padapter, SPS0_CTRL + 1, 0x53);
- r8712_write8(padapter, SPS0_CTRL, 0x57);
+ r8712_write8(adapter, SPS0_CTRL + 1, 0x53);
+ r8712_write8(adapter, SPS0_CTRL, 0x57);
/* Enable AFE Macro Block's Bandgap and Enable AFE Macro
* Block's Mbias
*/
- val8 = r8712_read8(padapter, AFE_MISC);
- r8712_write8(padapter, AFE_MISC, (val8 | AFE_MISC_BGEN |
+ val8 = r8712_read8(adapter, AFE_MISC);
+ r8712_write8(adapter, AFE_MISC, (val8 | AFE_MISC_BGEN |
AFE_MISC_MBEN));
/* Enable LDOA15 block */
- val8 = r8712_read8(padapter, LDOA15_CTRL);
- r8712_write8(padapter, LDOA15_CTRL, (val8 | LDA15_EN));
- val8 = r8712_read8(padapter, SPS1_CTRL);
- r8712_write8(padapter, SPS1_CTRL, (val8 | SPS1_LDEN));
+ val8 = r8712_read8(adapter, LDOA15_CTRL);
+ r8712_write8(adapter, LDOA15_CTRL, (val8 | LDA15_EN));
+ val8 = r8712_read8(adapter, SPS1_CTRL);
+ r8712_write8(adapter, SPS1_CTRL, (val8 | SPS1_LDEN));
msleep(20);
/* Enable Switch Regulator Block */
- val8 = r8712_read8(padapter, SPS1_CTRL);
- r8712_write8(padapter, SPS1_CTRL, (val8 | SPS1_SWEN));
- r8712_write32(padapter, SPS1_CTRL, 0x00a7b267);
- val8 = r8712_read8(padapter, SYS_ISO_CTRL + 1);
- r8712_write8(padapter, SYS_ISO_CTRL + 1, (val8 | 0x08));
+ val8 = r8712_read8(adapter, SPS1_CTRL);
+ r8712_write8(adapter, SPS1_CTRL, (val8 | SPS1_SWEN));
+ r8712_write32(adapter, SPS1_CTRL, 0x00a7b267);
+ val8 = r8712_read8(adapter, SYS_ISO_CTRL + 1);
+ r8712_write8(adapter, SYS_ISO_CTRL + 1, (val8 | 0x08));
/* Engineer Packet CP test Enable */
- val8 = r8712_read8(padapter, SYS_FUNC_EN + 1);
- r8712_write8(padapter, SYS_FUNC_EN + 1, (val8 | 0x20));
- val8 = r8712_read8(padapter, SYS_ISO_CTRL + 1);
- r8712_write8(padapter, SYS_ISO_CTRL + 1, (val8 & 0x6F));
+ val8 = r8712_read8(adapter, SYS_FUNC_EN + 1);
+ r8712_write8(adapter, SYS_FUNC_EN + 1, (val8 | 0x20));
+ val8 = r8712_read8(adapter, SYS_ISO_CTRL + 1);
+ r8712_write8(adapter, SYS_ISO_CTRL + 1, (val8 & 0x6F));
/* Enable AFE clock */
- val8 = r8712_read8(padapter, AFE_XTAL_CTRL + 1);
- r8712_write8(padapter, AFE_XTAL_CTRL + 1, (val8 & 0xfb));
+ val8 = r8712_read8(adapter, AFE_XTAL_CTRL + 1);
+ r8712_write8(adapter, AFE_XTAL_CTRL + 1, (val8 & 0xfb));
/* Enable AFE PLL Macro Block */
- val8 = r8712_read8(padapter, AFE_PLL_CTRL);
- r8712_write8(padapter, AFE_PLL_CTRL, (val8 | 0x11));
+ val8 = r8712_read8(adapter, AFE_PLL_CTRL);
+ r8712_write8(adapter, AFE_PLL_CTRL, (val8 | 0x11));
/* Attach AFE PLL to MACTOP/BB/PCIe Digital */
- val8 = r8712_read8(padapter, SYS_ISO_CTRL);
- r8712_write8(padapter, SYS_ISO_CTRL, (val8 & 0xEE));
+ val8 = r8712_read8(adapter, SYS_ISO_CTRL);
+ r8712_write8(adapter, SYS_ISO_CTRL, (val8 & 0xEE));
/* Switch to 40M clock */
- val8 = r8712_read8(padapter, SYS_CLKR);
- r8712_write8(padapter, SYS_CLKR, val8 & (~SYS_CLKSEL));
+ val8 = r8712_read8(adapter, SYS_CLKR);
+ r8712_write8(adapter, SYS_CLKR, val8 & (~SYS_CLKSEL));
/* SSC Disable */
- val8 = r8712_read8(padapter, SYS_CLKR);
+ val8 = r8712_read8(adapter, SYS_CLKR);
/* Enable MAC clock */
- val8 = r8712_read8(padapter, SYS_CLKR + 1);
- r8712_write8(padapter, SYS_CLKR + 1, (val8 | 0x18));
+ val8 = r8712_read8(adapter, SYS_CLKR + 1);
+ r8712_write8(adapter, SYS_CLKR + 1, (val8 | 0x18));
/* Revised POS, */
- r8712_write8(padapter, PMC_FSM, 0x02);
+ r8712_write8(adapter, PMC_FSM, 0x02);
/* Enable Core digital and enable IOREG R/W */
- val8 = r8712_read8(padapter, SYS_FUNC_EN + 1);
- r8712_write8(padapter, SYS_FUNC_EN + 1, (val8 | 0x08));
+ val8 = r8712_read8(adapter, SYS_FUNC_EN + 1);
+ r8712_write8(adapter, SYS_FUNC_EN + 1, (val8 | 0x08));
/* Enable REG_EN */
- val8 = r8712_read8(padapter, SYS_FUNC_EN + 1);
- r8712_write8(padapter, SYS_FUNC_EN + 1, (val8 | 0x80));
+ val8 = r8712_read8(adapter, SYS_FUNC_EN + 1);
+ r8712_write8(adapter, SYS_FUNC_EN + 1, (val8 | 0x80));
/* Switch the control path to FW */
- val8 = r8712_read8(padapter, SYS_CLKR + 1);
- r8712_write8(padapter, SYS_CLKR + 1, (val8 | 0x80) & 0xBF);
- r8712_write8(padapter, CR, 0xFC);
- r8712_write8(padapter, CR + 1, 0x37);
+ val8 = r8712_read8(adapter, SYS_CLKR + 1);
+ r8712_write8(adapter, SYS_CLKR + 1, (val8 | 0x80) & 0xBF);
+ r8712_write8(adapter, CR, 0xFC);
+ r8712_write8(adapter, CR + 1, 0x37);
/* Fix the RX FIFO issue(usb error), */
- val8 = r8712_read8(padapter, 0x1025FE5c);
- r8712_write8(padapter, 0x1025FE5c, (val8 | BIT(7)));
- val8 = r8712_read8(padapter, 0x102500ab);
- r8712_write8(padapter, 0x102500ab, (val8 | BIT(6) | BIT(7)));
+ val8 = r8712_read8(adapter, 0x1025FE5c);
+ r8712_write8(adapter, 0x1025FE5c, (val8 | BIT(7)));
+ val8 = r8712_read8(adapter, 0x102500ab);
+ r8712_write8(adapter, 0x102500ab, (val8 | BIT(6) | BIT(7)));
/* For power save, used this in the bit file after 970621 */
- val8 = r8712_read8(padapter, SYS_CLKR);
- r8712_write8(padapter, SYS_CLKR, val8 & (~CPU_CLKSEL));
- } else if (pregistrypriv->chip_version == RTL8712_2ndCUT ||
- pregistrypriv->chip_version == RTL8712_3rdCUT) {
+ val8 = r8712_read8(adapter, SYS_CLKR);
+ r8712_write8(adapter, SYS_CLKR, val8 & (~CPU_CLKSEL));
+ } else if (registrypriv->chip_version == RTL8712_2ndCUT ||
+ registrypriv->chip_version == RTL8712_3rdCUT) {
/* Initialization for power on sequence,
* E-Fuse leakage prevention sequence
*/
- r8712_write8(padapter, 0x37, 0xb0);
+ r8712_write8(adapter, 0x37, 0xb0);
msleep(20);
- r8712_write8(padapter, 0x37, 0x30);
+ r8712_write8(adapter, 0x37, 0x30);
/* Set control path switch to HW control and reset Digital Core,
* CPU Core and MAC I/O to solve FW download fail when system
* from resume sate.
*/
- val8 = r8712_read8(padapter, SYS_CLKR + 1);
+ val8 = r8712_read8(adapter, SYS_CLKR + 1);
if (val8 & 0x80) {
val8 &= 0x3f;
- r8712_write8(padapter, SYS_CLKR + 1, val8);
+ r8712_write8(adapter, SYS_CLKR + 1, val8);
}
- val8 = r8712_read8(padapter, SYS_FUNC_EN + 1);
+ val8 = r8712_read8(adapter, SYS_FUNC_EN + 1);
val8 &= 0x73;
- r8712_write8(padapter, SYS_FUNC_EN + 1, val8);
+ r8712_write8(adapter, SYS_FUNC_EN + 1, val8);
msleep(20);
/* Revised POS, */
/* Enable AFE Macro Block's Bandgap and Enable AFE Macro
* Block's Mbias
*/
- r8712_write8(padapter, SPS0_CTRL + 1, 0x53);
- r8712_write8(padapter, SPS0_CTRL, 0x57);
- val8 = r8712_read8(padapter, AFE_MISC);
+ r8712_write8(adapter, SPS0_CTRL + 1, 0x53);
+ r8712_write8(adapter, SPS0_CTRL, 0x57);
+ val8 = r8712_read8(adapter, AFE_MISC);
/*Bandgap*/
- r8712_write8(padapter, AFE_MISC, (val8 | AFE_MISC_BGEN));
- r8712_write8(padapter, AFE_MISC, (val8 | AFE_MISC_BGEN |
+ r8712_write8(adapter, AFE_MISC, (val8 | AFE_MISC_BGEN));
+ r8712_write8(adapter, AFE_MISC, (val8 | AFE_MISC_BGEN |
AFE_MISC_MBEN | AFE_MISC_I32_EN));
/* Enable PLL Power (LDOA15V) */
- val8 = r8712_read8(padapter, LDOA15_CTRL);
- r8712_write8(padapter, LDOA15_CTRL, (val8 | LDA15_EN));
+ val8 = r8712_read8(adapter, LDOA15_CTRL);
+ r8712_write8(adapter, LDOA15_CTRL, (val8 | LDA15_EN));
/* Enable LDOV12D block */
- val8 = r8712_read8(padapter, LDOV12D_CTRL);
- r8712_write8(padapter, LDOV12D_CTRL, (val8 | LDV12_EN));
- val8 = r8712_read8(padapter, SYS_ISO_CTRL + 1);
- r8712_write8(padapter, SYS_ISO_CTRL + 1, (val8 | 0x08));
+ val8 = r8712_read8(adapter, LDOV12D_CTRL);
+ r8712_write8(adapter, LDOV12D_CTRL, (val8 | LDV12_EN));
+ val8 = r8712_read8(adapter, SYS_ISO_CTRL + 1);
+ r8712_write8(adapter, SYS_ISO_CTRL + 1, (val8 | 0x08));
/* Engineer Packet CP test Enable */
- val8 = r8712_read8(padapter, SYS_FUNC_EN + 1);
- r8712_write8(padapter, SYS_FUNC_EN + 1, (val8 | 0x20));
+ val8 = r8712_read8(adapter, SYS_FUNC_EN + 1);
+ r8712_write8(adapter, SYS_FUNC_EN + 1, (val8 | 0x20));
/* Support 64k IMEM */
- val8 = r8712_read8(padapter, SYS_ISO_CTRL + 1);
- r8712_write8(padapter, SYS_ISO_CTRL + 1, (val8 & 0x68));
+ val8 = r8712_read8(adapter, SYS_ISO_CTRL + 1);
+ r8712_write8(adapter, SYS_ISO_CTRL + 1, (val8 & 0x68));
/* Enable AFE clock */
- val8 = r8712_read8(padapter, AFE_XTAL_CTRL + 1);
- r8712_write8(padapter, AFE_XTAL_CTRL + 1, (val8 & 0xfb));
+ val8 = r8712_read8(adapter, AFE_XTAL_CTRL + 1);
+ r8712_write8(adapter, AFE_XTAL_CTRL + 1, (val8 & 0xfb));
/* Enable AFE PLL Macro Block */
- val8 = r8712_read8(padapter, AFE_PLL_CTRL);
- r8712_write8(padapter, AFE_PLL_CTRL, (val8 | 0x11));
+ val8 = r8712_read8(adapter, AFE_PLL_CTRL);
+ r8712_write8(adapter, AFE_PLL_CTRL, (val8 | 0x11));
/* Some sample will download fw failure. The clock will be
* stable with 500 us delay after reset the PLL
* TODO: When usleep is added to kernel, change next 3
* udelay(500) to usleep(500)
*/
udelay(500);
- r8712_write8(padapter, AFE_PLL_CTRL, (val8 | 0x51));
+ r8712_write8(adapter, AFE_PLL_CTRL, (val8 | 0x51));
udelay(500);
- r8712_write8(padapter, AFE_PLL_CTRL, (val8 | 0x11));
+ r8712_write8(adapter, AFE_PLL_CTRL, (val8 | 0x11));
udelay(500);
/* Attach AFE PLL to MACTOP/BB/PCIe Digital */
- val8 = r8712_read8(padapter, SYS_ISO_CTRL);
- r8712_write8(padapter, SYS_ISO_CTRL, (val8 & 0xEE));
+ val8 = r8712_read8(adapter, SYS_ISO_CTRL);
+ r8712_write8(adapter, SYS_ISO_CTRL, (val8 & 0xEE));
/* Switch to 40M clock */
- r8712_write8(padapter, SYS_CLKR, 0x00);
+ r8712_write8(adapter, SYS_CLKR, 0x00);
/* CPU Clock and 80M Clock SSC Disable to overcome FW download
* fail timing issue.
*/
- val8 = r8712_read8(padapter, SYS_CLKR);
- r8712_write8(padapter, SYS_CLKR, (val8 | 0xa0));
+ val8 = r8712_read8(adapter, SYS_CLKR);
+ r8712_write8(adapter, SYS_CLKR, (val8 | 0xa0));
/* Enable MAC clock */
- val8 = r8712_read8(padapter, SYS_CLKR + 1);
- r8712_write8(padapter, SYS_CLKR + 1, (val8 | 0x18));
+ val8 = r8712_read8(adapter, SYS_CLKR + 1);
+ r8712_write8(adapter, SYS_CLKR + 1, (val8 | 0x18));
/* Revised POS, */
- r8712_write8(padapter, PMC_FSM, 0x02);
+ r8712_write8(adapter, PMC_FSM, 0x02);
/* Enable Core digital and enable IOREG R/W */
- val8 = r8712_read8(padapter, SYS_FUNC_EN + 1);
- r8712_write8(padapter, SYS_FUNC_EN + 1, (val8 | 0x08));
+ val8 = r8712_read8(adapter, SYS_FUNC_EN + 1);
+ r8712_write8(adapter, SYS_FUNC_EN + 1, (val8 | 0x08));
/* Enable REG_EN */
- val8 = r8712_read8(padapter, SYS_FUNC_EN + 1);
- r8712_write8(padapter, SYS_FUNC_EN + 1, (val8 | 0x80));
+ val8 = r8712_read8(adapter, SYS_FUNC_EN + 1);
+ r8712_write8(adapter, SYS_FUNC_EN + 1, (val8 | 0x80));
/* Switch the control path to FW */
- val8 = r8712_read8(padapter, SYS_CLKR + 1);
- r8712_write8(padapter, SYS_CLKR + 1, (val8 | 0x80) & 0xBF);
- r8712_write8(padapter, CR, 0xFC);
- r8712_write8(padapter, CR + 1, 0x37);
+ val8 = r8712_read8(adapter, SYS_CLKR + 1);
+ r8712_write8(adapter, SYS_CLKR + 1, (val8 | 0x80) & 0xBF);
+ r8712_write8(adapter, CR, 0xFC);
+ r8712_write8(adapter, CR + 1, 0x37);
/* Fix the RX FIFO issue(usb error), 970410 */
- val8 = r8712_read8(padapter, 0x1025FE5c);
- r8712_write8(padapter, 0x1025FE5c, (val8 | BIT(7)));
+ val8 = r8712_read8(adapter, 0x1025FE5c);
+ r8712_write8(adapter, 0x1025FE5c, (val8 | BIT(7)));
/* For power save, used this in the bit file after 970621 */
- val8 = r8712_read8(padapter, SYS_CLKR);
- r8712_write8(padapter, SYS_CLKR, val8 & (~CPU_CLKSEL));
+ val8 = r8712_read8(adapter, SYS_CLKR);
+ r8712_write8(adapter, SYS_CLKR, val8 & (~CPU_CLKSEL));
/* Revised for 8051 ROM code wrong operation. */
- r8712_write8(padapter, 0x1025fe1c, 0x80);
+ r8712_write8(adapter, 0x1025fe1c, 0x80);
/* To make sure that TxDMA can ready to download FW.
* We should reset TxDMA if IMEM RPT was not ready.
*/
do {
- val8 = r8712_read8(padapter, TCR);
+ val8 = r8712_read8(adapter, TCR);
if ((val8 & _TXDMA_INIT_VALUE) == _TXDMA_INIT_VALUE)
break;
udelay(5); /* PlatformStallExecution(5); */
} while (PollingCnt--); /* Delay 1ms */
if (PollingCnt <= 0) {
- val8 = r8712_read8(padapter, CR);
- r8712_write8(padapter, CR, val8 & (~_TXDMA_EN));
+ val8 = r8712_read8(adapter, CR);
+ r8712_write8(adapter, CR, val8 & (~_TXDMA_EN));
udelay(2); /* PlatformStallExecution(2); */
/* Reset TxDMA */
- r8712_write8(padapter, CR, val8 | _TXDMA_EN);
+ r8712_write8(adapter, CR, val8 | _TXDMA_EN);
}
} else {
ret = _FAIL;
@@ -280,28 +280,28 @@ u8 r8712_usb_hal_bus_init(struct _adapter *padapter)
return ret;
}
-unsigned int r8712_usb_inirp_init(struct _adapter *padapter)
+unsigned int r8712_usb_inirp_init(struct _adapter *adapter)
{
u8 i;
- struct recv_buf *precvbuf;
- struct intf_hdl *pintfhdl = &padapter->pio_queue->intf;
- struct recv_priv *precvpriv = &(padapter->recvpriv);
+ struct recv_buf *recvbuf;
+ struct intf_hdl *intfhdl = &adapter->pio_queue->intf;
+ struct recv_priv *recvpriv = &(adapter->recvpriv);
- precvpriv->ff_hwaddr = RTL8712_DMA_RX0FF; /* mapping rx fifo address */
+ recvpriv->ff_hwaddr = RTL8712_DMA_RX0FF; /* mapping rx fifo address */
/* issue Rx irp to receive data */
- precvbuf = (struct recv_buf *)precvpriv->precv_buf;
+ recvbuf = (struct recv_buf *)recvpriv->precv_buf;
for (i = 0; i < NR_RECVBUFF; i++) {
- if (r8712_usb_read_port(pintfhdl, precvpriv->ff_hwaddr, 0,
- (unsigned char *)precvbuf) == false)
+ if (r8712_usb_read_port(intfhdl, recvpriv->ff_hwaddr, 0,
+ (unsigned char *)recvbuf) == false)
return _FAIL;
- precvbuf++;
- precvpriv->free_recv_buf_queue_cnt--;
+ recvbuf++;
+ recvpriv->free_recv_buf_queue_cnt--;
}
return _SUCCESS;
}
-unsigned int r8712_usb_inirp_deinit(struct _adapter *padapter)
+unsigned int r8712_usb_inirp_deinit(struct _adapter *adapter)
{
- r8712_usb_read_port_cancel(padapter);
+ r8712_usb_read_port_cancel(adapter);
return _SUCCESS;
}
diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c
index 7478bbd3de78..d0daae0b8299 100644
--- a/drivers/staging/rtl8712/usb_intf.c
+++ b/drivers/staging/rtl8712/usb_intf.c
@@ -246,7 +246,7 @@ static uint r8712_usb_dvobj_init(struct _adapter *padapter)
struct usb_device *pusbd = pdvobjpriv->pusbdev;
pdvobjpriv->padapter = padapter;
- padapter->EepromAddressSize = 6;
+ padapter->eeprom_address_size = 6;
phost_iface = &pintf->altsetting[0];
piface_desc = &phost_iface->desc;
pdvobjpriv->nr_endpoint = piface_desc->bNumEndpoints;
@@ -571,7 +571,7 @@ static int r871xu_drv_init(struct usb_interface *pusb_intf,
/* step 6. Load the firmware asynchronously */
if (rtl871x_load_fw(padapter))
goto error;
- spin_lock_init(&padapter->lockRxFF0Filter);
+ spin_lock_init(&padapter->lock_rx_ff0_filter);
mutex_init(&padapter->mutex_start);
return 0;
error:
diff --git a/drivers/staging/rtl8712/usb_ops.c b/drivers/staging/rtl8712/usb_ops.c
index eef52d5c730a..e64845e6adf3 100644
--- a/drivers/staging/rtl8712/usb_ops.c
+++ b/drivers/staging/rtl8712/usb_ops.c
@@ -22,7 +22,7 @@
#include "usb_ops.h"
#include "recv_osdep.h"
-static u8 usb_read8(struct intf_hdl *pintfhdl, u32 addr)
+static u8 usb_read8(struct intf_hdl *intfhdl, u32 addr)
{
u8 request;
u8 requesttype;
@@ -30,19 +30,19 @@ static u8 usb_read8(struct intf_hdl *pintfhdl, u32 addr)
u16 index;
u16 len;
__le32 data;
- struct intf_priv *pintfpriv = pintfhdl->pintfpriv;
+ struct intf_priv *intfpriv = intfhdl->pintfpriv;
request = 0x05;
requesttype = 0x01; /* read_in */
index = 0;
wvalue = (u16)(addr & 0x0000ffff);
len = 1;
- r8712_usbctrl_vendorreq(pintfpriv, request, wvalue, index, &data, len,
- requesttype);
+ r8712_usbctrl_vendorreq(intfpriv, request, wvalue, index, &data, len,
+ requesttype);
return (u8)(le32_to_cpu(data) & 0x0ff);
}
-static u16 usb_read16(struct intf_hdl *pintfhdl, u32 addr)
+static u16 usb_read16(struct intf_hdl *intfhdl, u32 addr)
{
u8 request;
u8 requesttype;
@@ -50,19 +50,19 @@ static u16 usb_read16(struct intf_hdl *pintfhdl, u32 addr)
u16 index;
u16 len;
__le32 data;
- struct intf_priv *pintfpriv = pintfhdl->pintfpriv;
+ struct intf_priv *intfpriv = intfhdl->pintfpriv;
request = 0x05;
requesttype = 0x01; /* read_in */
index = 0;
wvalue = (u16)(addr & 0x0000ffff);
len = 2;
- r8712_usbctrl_vendorreq(pintfpriv, request, wvalue, index, &data, len,
- requesttype);
+ r8712_usbctrl_vendorreq(intfpriv, request, wvalue, index, &data, len,
+ requesttype);
return (u16)(le32_to_cpu(data) & 0xffff);
}
-static u32 usb_read32(struct intf_hdl *pintfhdl, u32 addr)
+static u32 usb_read32(struct intf_hdl *intfhdl, u32 addr)
{
u8 request;
u8 requesttype;
@@ -70,19 +70,19 @@ static u32 usb_read32(struct intf_hdl *pintfhdl, u32 addr)
u16 index;
u16 len;
__le32 data;
- struct intf_priv *pintfpriv = pintfhdl->pintfpriv;
+ struct intf_priv *intfpriv = intfhdl->pintfpriv;
request = 0x05;
requesttype = 0x01; /* read_in */
index = 0;
wvalue = (u16)(addr & 0x0000ffff);
len = 4;
- r8712_usbctrl_vendorreq(pintfpriv, request, wvalue, index, &data, len,
- requesttype);
+ r8712_usbctrl_vendorreq(intfpriv, request, wvalue, index, &data, len,
+ requesttype);
return le32_to_cpu(data);
}
-static void usb_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val)
+static void usb_write8(struct intf_hdl *intfhdl, u32 addr, u8 val)
{
u8 request;
u8 requesttype;
@@ -90,7 +90,7 @@ static void usb_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val)
u16 index;
u16 len;
__le32 data;
- struct intf_priv *pintfpriv = pintfhdl->pintfpriv;
+ struct intf_priv *intfpriv = intfhdl->pintfpriv;
request = 0x05;
requesttype = 0x00; /* write_out */
@@ -98,11 +98,11 @@ static void usb_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val)
wvalue = (u16)(addr & 0x0000ffff);
len = 1;
data = cpu_to_le32((u32)val & 0x000000ff);
- r8712_usbctrl_vendorreq(pintfpriv, request, wvalue, index, &data, len,
- requesttype);
+ r8712_usbctrl_vendorreq(intfpriv, request, wvalue, index, &data, len,
+ requesttype);
}
-static void usb_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val)
+static void usb_write16(struct intf_hdl *intfhdl, u32 addr, u16 val)
{
u8 request;
u8 requesttype;
@@ -110,7 +110,7 @@ static void usb_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val)
u16 index;
u16 len;
__le32 data;
- struct intf_priv *pintfpriv = pintfhdl->pintfpriv;
+ struct intf_priv *intfpriv = intfhdl->pintfpriv;
request = 0x05;
requesttype = 0x00; /* write_out */
@@ -118,11 +118,11 @@ static void usb_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val)
wvalue = (u16)(addr & 0x0000ffff);
len = 2;
data = cpu_to_le32((u32)val & 0x0000ffff);
- r8712_usbctrl_vendorreq(pintfpriv, request, wvalue, index, &data, len,
- requesttype);
+ r8712_usbctrl_vendorreq(intfpriv, request, wvalue, index, &data, len,
+ requesttype);
}
-static void usb_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val)
+static void usb_write32(struct intf_hdl *intfhdl, u32 addr, u32 val)
{
u8 request;
u8 requesttype;
@@ -130,7 +130,7 @@ static void usb_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val)
u16 index;
u16 len;
__le32 data;
- struct intf_priv *pintfpriv = pintfhdl->pintfpriv;
+ struct intf_priv *intfpriv = intfhdl->pintfpriv;
request = 0x05;
requesttype = 0x00; /* write_out */
@@ -138,13 +138,13 @@ static void usb_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val)
wvalue = (u16)(addr & 0x0000ffff);
len = 4;
data = cpu_to_le32(val);
- r8712_usbctrl_vendorreq(pintfpriv, request, wvalue, index, &data, len,
- requesttype);
+ r8712_usbctrl_vendorreq(intfpriv, request, wvalue, index, &data, len,
+ requesttype);
}
-void r8712_usb_set_intf_option(u32 *poption)
+void r8712_usb_set_intf_option(u32 *option)
{
- *poption = ((*poption) | _INTF_ASYNC_);
+ *option = ((*option) | _INTF_ASYNC_);
}
static void usb_intf_hdl_init(u8 *priv)
@@ -163,24 +163,24 @@ static void usb_intf_hdl_close(u8 *priv)
{
}
-void r8712_usb_set_intf_funs(struct intf_hdl *pintf_hdl)
+void r8712_usb_set_intf_funs(struct intf_hdl *intfhdl)
{
- pintf_hdl->intf_hdl_init = usb_intf_hdl_init;
- pintf_hdl->intf_hdl_unload = usb_intf_hdl_unload;
- pintf_hdl->intf_hdl_open = usb_intf_hdl_open;
- pintf_hdl->intf_hdl_close = usb_intf_hdl_close;
+ intfhdl->intf_hdl_init = usb_intf_hdl_init;
+ intfhdl->intf_hdl_unload = usb_intf_hdl_unload;
+ intfhdl->intf_hdl_open = usb_intf_hdl_open;
+ intfhdl->intf_hdl_close = usb_intf_hdl_close;
}
-void r8712_usb_set_intf_ops(struct _io_ops *pops)
+void r8712_usb_set_intf_ops(struct _io_ops *ops)
{
- memset((u8 *)pops, 0, sizeof(struct _io_ops));
- pops->_read8 = usb_read8;
- pops->_read16 = usb_read16;
- pops->_read32 = usb_read32;
- pops->_read_port = r8712_usb_read_port;
- pops->_write8 = usb_write8;
- pops->_write16 = usb_write16;
- pops->_write32 = usb_write32;
- pops->_write_mem = r8712_usb_write_mem;
- pops->_write_port = r8712_usb_write_port;
+ memset((u8 *)ops, 0, sizeof(struct _io_ops));
+ ops->_read8 = usb_read8;
+ ops->_read16 = usb_read16;
+ ops->_read32 = usb_read32;
+ ops->_read_port = r8712_usb_read_port;
+ ops->_write8 = usb_write8;
+ ops->_write16 = usb_write16;
+ ops->_write32 = usb_write32;
+ ops->_write_mem = r8712_usb_write_mem;
+ ops->_write_port = r8712_usb_write_port;
}
diff --git a/drivers/staging/rtl8712/wifi.h b/drivers/staging/rtl8712/wifi.h
index 77346debea03..1a5b966a167e 100644
--- a/drivers/staging/rtl8712/wifi.h
+++ b/drivers/staging/rtl8712/wifi.h
@@ -278,17 +278,6 @@ static inline unsigned char get_tofr_ds(unsigned char *pframe)
#define GetAddr4Ptr(pbuf) ((unsigned char *)((addr_t)(pbuf) + 24))
-
-
-static inline int IS_MCAST(unsigned char *da)
-{
- if ((*da) & 0x01)
- return true;
- else
- return false;
-}
-
-
static inline unsigned char *get_da(unsigned char *pframe)
{
unsigned char *da;
diff --git a/drivers/staging/rtl8712/xmit_linux.c b/drivers/staging/rtl8712/xmit_linux.c
index 8bcb0775411f..01d713d027b0 100644
--- a/drivers/staging/rtl8712/xmit_linux.c
+++ b/drivers/staging/rtl8712/xmit_linux.c
@@ -93,22 +93,22 @@ void r8712_set_qos(struct pkt_file *ppktfile, struct pkt_attrib *pattrib)
void r8712_SetFilter(struct work_struct *work)
{
- struct _adapter *padapter = container_of(work, struct _adapter,
- wkFilterRxFF0);
+ struct _adapter *adapter = container_of(work, struct _adapter,
+ wk_filter_rx_ff0);
u8 oldvalue = 0x00, newvalue = 0x00;
unsigned long irqL;
- oldvalue = r8712_read8(padapter, 0x117);
+ oldvalue = r8712_read8(adapter, 0x117);
newvalue = oldvalue & 0xfe;
- r8712_write8(padapter, 0x117, newvalue);
+ r8712_write8(adapter, 0x117, newvalue);
- spin_lock_irqsave(&padapter->lockRxFF0Filter, irqL);
- padapter->blnEnableRxFF0Filter = 1;
- spin_unlock_irqrestore(&padapter->lockRxFF0Filter, irqL);
+ spin_lock_irqsave(&adapter->lock_rx_ff0_filter, irqL);
+ adapter->blnEnableRxFF0Filter = 1;
+ spin_unlock_irqrestore(&adapter->lock_rx_ff0_filter, irqL);
do {
msleep(100);
- } while (padapter->blnEnableRxFF0Filter == 1);
- r8712_write8(padapter, 0x117, oldvalue);
+ } while (adapter->blnEnableRxFF0Filter == 1);
+ r8712_write8(adapter, 0x117, oldvalue);
}
int r8712_xmit_resource_alloc(struct _adapter *padapter,
@@ -120,11 +120,11 @@ int r8712_xmit_resource_alloc(struct _adapter *padapter,
pxmitbuf->pxmit_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
if (!pxmitbuf->pxmit_urb[i]) {
netdev_err(padapter->pnetdev, "pxmitbuf->pxmit_urb[i] == NULL\n");
- return _FAIL;
+ return -ENOMEM;
}
kmemleak_not_leak(pxmitbuf->pxmit_urb[i]);
}
- return _SUCCESS;
+ return 0;
}
void r8712_xmit_resource_free(struct _adapter *padapter,
@@ -147,36 +147,36 @@ void r8712_xmit_complete(struct _adapter *padapter, struct xmit_frame *pxframe)
pxframe->pkt = NULL;
}
-int r8712_xmit_entry(_pkt *pkt, struct net_device *pnetdev)
+int r8712_xmit_entry(_pkt *pkt, struct net_device *netdev)
{
- struct xmit_frame *pxmitframe = NULL;
- struct _adapter *padapter = netdev_priv(pnetdev);
- struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+ struct xmit_frame *xmitframe = NULL;
+ struct _adapter *adapter = netdev_priv(netdev);
+ struct xmit_priv *xmitpriv = &(adapter->xmitpriv);
- if (!r8712_if_up(padapter))
+ if (!r8712_if_up(adapter))
goto _xmit_entry_drop;
- pxmitframe = r8712_alloc_xmitframe(pxmitpriv);
- if (!pxmitframe)
+ xmitframe = r8712_alloc_xmitframe(xmitpriv);
+ if (!xmitframe)
goto _xmit_entry_drop;
- if ((!r8712_update_attrib(padapter, pkt, &pxmitframe->attrib)))
+ if ((!r8712_update_attrib(adapter, pkt, &xmitframe->attrib)))
goto _xmit_entry_drop;
- padapter->ledpriv.LedControlHandler(padapter, LED_CTL_TX);
- pxmitframe->pkt = pkt;
- if (r8712_pre_xmit(padapter, pxmitframe)) {
+ adapter->ledpriv.LedControlHandler(adapter, LED_CTL_TX);
+ xmitframe->pkt = pkt;
+ if (r8712_pre_xmit(adapter, xmitframe)) {
/*dump xmitframe directly or drop xframe*/
dev_kfree_skb_any(pkt);
- pxmitframe->pkt = NULL;
+ xmitframe->pkt = NULL;
}
- pxmitpriv->tx_pkts++;
- pxmitpriv->tx_bytes += pxmitframe->attrib.last_txcmdsz;
+ xmitpriv->tx_pkts++;
+ xmitpriv->tx_bytes += xmitframe->attrib.last_txcmdsz;
return 0;
_xmit_entry_drop:
- if (pxmitframe)
- r8712_free_xmitframe(pxmitpriv, pxmitframe);
- pxmitpriv->tx_drop++;
+ if (xmitframe)
+ r8712_free_xmitframe(xmitpriv, xmitframe);
+ xmitpriv->tx_drop++;
dev_kfree_skb_any(pkt);
return 0;
}
diff --git a/drivers/staging/rtl8723bs/Kconfig b/drivers/staging/rtl8723bs/Kconfig
index 744091d46f4c..a88467334dac 100644
--- a/drivers/staging/rtl8723bs/Kconfig
+++ b/drivers/staging/rtl8723bs/Kconfig
@@ -5,7 +5,7 @@ config RTL8723BS
depends on m
select WIRELESS_EXT
select WEXT_PRIV
- ---help---
+ help
This option enables support for RTL8723BS SDIO drivers, such as
the wifi found on the 1st gen Intel Compute Stick, the CHIP
and many other Intel Atom and ARM based devices.
diff --git a/drivers/staging/rtl8723bs/TODO b/drivers/staging/rtl8723bs/TODO
index 58e02f944b6d..45065fd3fd5d 100644
--- a/drivers/staging/rtl8723bs/TODO
+++ b/drivers/staging/rtl8723bs/TODO
@@ -12,5 +12,4 @@ TODO:
- switch to use MAC80211
Please send any patches to Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
-Bastien Nocera <hadess@hadess.net>, Hans de Goede <hdegoede@redhat.com>
-and Larry Finger <Larry.Finger@lwfinger.net>.
+Hans de Goede <hdegoede@redhat.com> and Larry Finger <Larry.Finger@lwfinger.net>.
diff --git a/drivers/staging/rtl8723bs/core/rtw_ap.c b/drivers/staging/rtl8723bs/core/rtw_ap.c
index bc0230672457..7bd5c61b055c 100644
--- a/drivers/staging/rtl8723bs/core/rtw_ap.c
+++ b/drivers/staging/rtl8723bs/core/rtw_ap.c
@@ -443,7 +443,7 @@ void add_RATid(struct adapter *padapter, struct sta_info *psta, u8 rssi_level)
}
psta->wireless_mode = sta_band;
- psta->raid = rtw_hal_networktype_to_raid(padapter, psta);
+ psta->raid = networktype_to_raid_ex(padapter, psta);
if (psta->aid < NUM_STA) {
u8 arg[4] = {0};
@@ -512,7 +512,7 @@ void update_bmc_sta(struct adapter *padapter)
rtw_hal_update_sta_rate_mask(padapter, psta);
tx_ra_bitmap = psta->ra_mask;
- psta->raid = rtw_hal_networktype_to_raid(padapter, psta);
+ psta->raid = networktype_to_raid_ex(padapter, psta);
/* ap mode */
rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, true);
@@ -1394,10 +1394,9 @@ int rtw_acl_add_sta(struct adapter *padapter, u8 *addr)
return ret;
}
-int rtw_acl_remove_sta(struct adapter *padapter, u8 *addr)
+void rtw_acl_remove_sta(struct adapter *padapter, u8 *addr)
{
struct list_head *plist, *phead;
- int ret = 0;
struct rtw_wlan_acl_node *paclnode;
struct sta_priv *pstapriv = &padapter->stapriv;
struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
@@ -1438,7 +1437,6 @@ int rtw_acl_remove_sta(struct adapter *padapter, u8 *addr)
DBG_871X("%s, acl_num =%d\n", __func__, pacl_list->num);
- return ret;
}
u8 rtw_ap_set_pairwise_key(struct adapter *padapter, struct sta_info *psta)
@@ -1504,8 +1502,6 @@ static int rtw_ap_set_key(
goto exit;
}
- memset(psetkeyparm, 0, sizeof(struct setkey_parm));
-
psetkeyparm->keyid = (u8)keyid;
if (is_wep_enc(alg))
padapter->securitypriv.key_mask |= BIT(psetkeyparm->keyid);
@@ -1914,7 +1910,7 @@ static int rtw_ht_operation_update(struct adapter *padapter)
void associated_clients_update(struct adapter *padapter, u8 updated)
{
- /* update associcated stations cap. */
+ /* update associated stations cap. */
if (updated) {
struct list_head *phead, *plist;
struct sta_info *psta = NULL;
@@ -2072,7 +2068,7 @@ void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta)
update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, true);
}
- /* update associcated stations cap. */
+ /* update associated stations cap. */
associated_clients_update(padapter, beacon_updated);
DBG_871X("%s, updated =%d\n", __func__, beacon_updated);
@@ -2136,7 +2132,7 @@ u8 bss_cap_update_on_sta_leave(struct adapter *padapter, struct sta_info *psta)
update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, true);
}
- /* update associcated stations cap. */
+ /* update associated stations cap. */
/* associated_clients_update(padapter, beacon_updated); //move it to avoid deadlock */
DBG_871X("%s, updated =%d\n", __func__, beacon_updated);
@@ -2156,7 +2152,7 @@ u8 ap_free_sta(
if (!psta)
return beacon_updated;
- if (active == true) {
+ if (active) {
/* tear down Rx AMPDU */
send_delba(padapter, 0, psta->hwaddr);/* recipient */
@@ -2189,10 +2185,9 @@ u8 ap_free_sta(
return beacon_updated;
}
-int rtw_sta_flush(struct adapter *padapter)
+void rtw_sta_flush(struct adapter *padapter)
{
struct list_head *phead, *plist;
- int ret = 0;
struct sta_info *psta = NULL;
struct sta_priv *pstapriv = &padapter->stapriv;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
@@ -2202,7 +2197,7 @@ int rtw_sta_flush(struct adapter *padapter)
DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev));
if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE)
- return ret;
+ return;
spin_lock_bh(&pstapriv->asoc_list_lock);
phead = &pstapriv->asoc_list;
@@ -2226,8 +2221,6 @@ int rtw_sta_flush(struct adapter *padapter)
issue_deauth(padapter, bc_addr, WLAN_REASON_DEAUTH_LEAVING);
associated_clients_update(padapter, true);
-
- return ret;
}
/* called > TSR LEVEL for USB or SDIO Interface*/
diff --git a/drivers/staging/rtl8723bs/core/rtw_btcoex.c b/drivers/staging/rtl8723bs/core/rtw_btcoex.c
index 35310e8e0806..44219b7b6123 100644
--- a/drivers/staging/rtl8723bs/core/rtw_btcoex.c
+++ b/drivers/staging/rtl8723bs/core/rtw_btcoex.c
@@ -9,42 +9,6 @@
#include <rtw_btcoex.h>
#include <hal_btcoex.h>
-
-void rtw_btcoex_Initialize(struct adapter *padapter)
-{
- hal_btcoex_Initialize(padapter);
-}
-
-void rtw_btcoex_PowerOnSetting(struct adapter *padapter)
-{
- hal_btcoex_PowerOnSetting(padapter);
-}
-
-void rtw_btcoex_HAL_Initialize(struct adapter *padapter, u8 bWifiOnly)
-{
- hal_btcoex_InitHwConfig(padapter, bWifiOnly);
-}
-
-void rtw_btcoex_IpsNotify(struct adapter *padapter, u8 type)
-{
- hal_btcoex_IpsNotify(padapter, type);
-}
-
-void rtw_btcoex_LpsNotify(struct adapter *padapter, u8 type)
-{
- hal_btcoex_LpsNotify(padapter, type);
-}
-
-void rtw_btcoex_ScanNotify(struct adapter *padapter, u8 type)
-{
- hal_btcoex_ScanNotify(padapter, type);
-}
-
-void rtw_btcoex_ConnectNotify(struct adapter *padapter, u8 action)
-{
- hal_btcoex_ConnectNotify(padapter, action);
-}
-
void rtw_btcoex_MediaStatusNotify(struct adapter *padapter, u8 mediaStatus)
{
if ((mediaStatus == RT_MEDIA_CONNECT)
@@ -55,26 +19,6 @@ void rtw_btcoex_MediaStatusNotify(struct adapter *padapter, u8 mediaStatus)
hal_btcoex_MediaStatusNotify(padapter, mediaStatus);
}
-void rtw_btcoex_SpecialPacketNotify(struct adapter *padapter, u8 pktType)
-{
- hal_btcoex_SpecialPacketNotify(padapter, pktType);
-}
-
-void rtw_btcoex_IQKNotify(struct adapter *padapter, u8 state)
-{
- hal_btcoex_IQKNotify(padapter, state);
-}
-
-void rtw_btcoex_BtInfoNotify(struct adapter *padapter, u8 length, u8 *tmpBuf)
-{
- hal_btcoex_BtInfoNotify(padapter, length, tmpBuf);
-}
-
-void rtw_btcoex_SuspendNotify(struct adapter *padapter, u8 state)
-{
- hal_btcoex_SuspendNotify(padapter, state);
-}
-
void rtw_btcoex_HaltNotify(struct adapter *padapter)
{
if (!padapter->bup) {
@@ -94,95 +38,6 @@ void rtw_btcoex_HaltNotify(struct adapter *padapter)
hal_btcoex_HaltNotify(padapter);
}
-u8 rtw_btcoex_IsBtDisabled(struct adapter *padapter)
-{
- return hal_btcoex_IsBtDisabled(padapter);
-}
-
-void rtw_btcoex_Handler(struct adapter *padapter)
-{
- hal_btcoex_Hanlder(padapter);
-}
-
-s32 rtw_btcoex_IsBTCoexCtrlAMPDUSize(struct adapter *padapter)
-{
- s32 coexctrl;
-
- coexctrl = hal_btcoex_IsBTCoexCtrlAMPDUSize(padapter);
-
- return coexctrl;
-}
-
-void rtw_btcoex_SetManualControl(struct adapter *padapter, u8 manual)
-{
- hal_btcoex_SetManualControl(padapter, manual);
-}
-
-u8 rtw_btcoex_IsBtControlLps(struct adapter *padapter)
-{
- return hal_btcoex_IsBtControlLps(padapter);
-}
-
-u8 rtw_btcoex_IsLpsOn(struct adapter *padapter)
-{
- return hal_btcoex_IsLpsOn(padapter);
-}
-
-u8 rtw_btcoex_RpwmVal(struct adapter *padapter)
-{
- return hal_btcoex_RpwmVal(padapter);
-}
-
-u8 rtw_btcoex_LpsVal(struct adapter *padapter)
-{
- return hal_btcoex_LpsVal(padapter);
-}
-
-void rtw_btcoex_SetBTCoexist(struct adapter *padapter, u8 bBtExist)
-{
- hal_btcoex_SetBTCoexist(padapter, bBtExist);
-}
-
-void rtw_btcoex_SetChipType(struct adapter *padapter, u8 chipType)
-{
- hal_btcoex_SetChipType(padapter, chipType);
-}
-
-void rtw_btcoex_SetPGAntNum(struct adapter *padapter, u8 antNum)
-{
- hal_btcoex_SetPgAntNum(padapter, antNum);
-}
-
-void rtw_btcoex_SetSingleAntPath(struct adapter *padapter, u8 singleAntPath)
-{
- hal_btcoex_SetSingleAntPath(padapter, singleAntPath);
-}
-
-u32 rtw_btcoex_GetRaMask(struct adapter *padapter)
-{
- return hal_btcoex_GetRaMask(padapter);
-}
-
-void rtw_btcoex_RecordPwrMode(struct adapter *padapter, u8 *pCmdBuf, u8 cmdLen)
-{
- hal_btcoex_RecordPwrMode(padapter, pCmdBuf, cmdLen);
-}
-
-void rtw_btcoex_DisplayBtCoexInfo(struct adapter *padapter, u8 *pbuf, u32 bufsize)
-{
- hal_btcoex_DisplayBtCoexInfo(padapter, pbuf, bufsize);
-}
-
-void rtw_btcoex_SetDBG(struct adapter *padapter, u32 *pDbgModule)
-{
- hal_btcoex_SetDBG(padapter, pDbgModule);
-}
-
-u32 rtw_btcoex_GetDBG(struct adapter *padapter, u8 *pStrBuf, u32 bufSize)
-{
- return hal_btcoex_GetDBG(padapter, pStrBuf, bufSize);
-}
-
/* ================================================== */
/* Below Functions are called by BT-Coex */
/* ================================================== */
@@ -212,7 +67,7 @@ void rtw_btcoex_LPS_Enter(struct adapter *padapter)
pwrpriv = adapter_to_pwrctl(padapter);
pwrpriv->bpower_saving = true;
- lpsVal = rtw_btcoex_LpsVal(padapter);
+ lpsVal = hal_btcoex_LpsVal(padapter);
rtw_set_ps_mode(padapter, PS_MODE_MIN, 0, lpsVal, "BTCOEX");
}
diff --git a/drivers/staging/rtl8723bs/core/rtw_cmd.c b/drivers/staging/rtl8723bs/core/rtw_cmd.c
index ecaa769f12e6..addc55706a3c 100644
--- a/drivers/staging/rtl8723bs/core/rtw_cmd.c
+++ b/drivers/staging/rtl8723bs/core/rtw_cmd.c
@@ -8,6 +8,7 @@
#include <drv_types.h>
#include <rtw_debug.h>
+#include <hal_btcoex.h>
#include <linux/jiffies.h>
static struct _cmd_callback rtw_cmd_callback[] = {
@@ -1439,7 +1440,7 @@ static void dynamic_chk_wk_hdl(struct adapter *padapter)
/* */
/* BT-Coexist */
/* */
- rtw_btcoex_Handler(padapter);
+ hal_btcoex_Handler(padapter);
/* always call rtw_ps_processor() at last one. */
@@ -1462,7 +1463,7 @@ void lps_ctrl_wk_hdl(struct adapter *padapter, u8 lps_ctrl_type)
switch (lps_ctrl_type) {
case LPS_CTRL_SCAN:
/* DBG_871X("LPS_CTRL_SCAN\n"); */
- rtw_btcoex_ScanNotify(padapter, true);
+ hal_btcoex_ScanNotify(padapter, true);
if (check_fwstate(pmlmepriv, _FW_LINKED) == true) {
/* connect */
@@ -1491,7 +1492,7 @@ void lps_ctrl_wk_hdl(struct adapter *padapter, u8 lps_ctrl_type)
case LPS_CTRL_SPECIAL_PACKET:
/* DBG_871X("LPS_CTRL_SPECIAL_PACKET\n"); */
pwrpriv->DelayLPSLastTimeStamp = jiffies;
- rtw_btcoex_SpecialPacketNotify(padapter, PACKET_DHCP);
+ hal_btcoex_SpecialPacketNotify(padapter, PACKET_DHCP);
LPS_Leave(padapter, "LPS_CTRL_SPECIAL_PACKET");
break;
case LPS_CTRL_LEAVE:
@@ -1594,7 +1595,7 @@ static void rtw_lps_change_dtim_hdl(struct adapter *padapter, u8 dtim)
if (dtim <= 0 || dtim > 16)
return;
- if (rtw_btcoex_IsBtControlLps(padapter) == true)
+ if (hal_btcoex_IsBtControlLps(padapter) == true)
return;
mutex_lock(&pwrpriv->lock);
@@ -1660,22 +1661,6 @@ exit:
}
-static void power_saving_wk_hdl(struct adapter *padapter)
-{
- rtw_ps_processor(padapter);
-}
-
-/* add for CONFIG_IEEE80211W, none 11w can use it */
-static void reset_securitypriv_hdl(struct adapter *padapter)
-{
- rtw_reset_securitypriv(padapter);
-}
-
-static void free_assoc_resources_hdl(struct adapter *padapter)
-{
- rtw_free_assoc_resources(padapter, 1);
-}
-
u8 rtw_ps_cmd(struct adapter *padapter)
{
struct cmd_obj *ppscmd;
@@ -1738,7 +1723,7 @@ static void rtw_chk_hi_queue_hdl(struct adapter *padapter)
pstapriv->tim_bitmap &= ~BIT(0);
pstapriv->sta_dz_bitmap &= ~BIT(0);
- if (update_tim == true)
+ if (update_tim)
update_beacon(padapter, _TIM_IE_, NULL, true);
} else {/* re check again */
rtw_chk_hi_queue_cmd(padapter);
@@ -1844,7 +1829,7 @@ static void rtw_btinfo_hdl(struct adapter *adapter, u8 *buf, u16 buf_len)
buf[1] = 0;
else if (cmd_idx == BTINFO_BT_AUTO_RPT)
buf[1] = 2;
- rtw_btcoex_BtInfoNotify(adapter, len+1, &buf[1]);
+ hal_btcoex_BtInfoNotify(adapter, len+1, &buf[1]);
}
u8 rtw_c2h_packet_wk_cmd(struct adapter *padapter, u8 *pbuf, u16 length)
@@ -1934,7 +1919,7 @@ static void c2h_wk_callback(_workitem *work)
c2h_evt = rtw_malloc(16);
if (c2h_evt != NULL) {
/* This C2H event is not read, read & clear now */
- if (rtw_hal_c2h_evt_read(adapter, c2h_evt) != _SUCCESS) {
+ if (c2h_evt_read_88xx(adapter, c2h_evt) != _SUCCESS) {
kfree(c2h_evt);
continue;
}
@@ -1977,7 +1962,7 @@ u8 rtw_drvextra_cmd_hdl(struct adapter *padapter, unsigned char *pbuf)
dynamic_chk_wk_hdl(padapter);
break;
case POWER_SAVING_CTRL_WK_CID:
- power_saving_wk_hdl(padapter);
+ rtw_ps_processor(padapter);
break;
case LPS_CTRL_WK_CID:
lps_ctrl_wk_hdl(padapter, (u8)pdrvextra_cmd->type);
@@ -1993,10 +1978,10 @@ u8 rtw_drvextra_cmd_hdl(struct adapter *padapter, unsigned char *pbuf)
break;
/* add for CONFIG_IEEE80211W, none 11w can use it */
case RESET_SECURITYPRIV:
- reset_securitypriv_hdl(padapter);
+ rtw_reset_securitypriv(padapter);
break;
case FREE_ASSOC_RESOURCES:
- free_assoc_resources_hdl(padapter);
+ rtw_free_assoc_resources(padapter, 1);
break;
case C2H_WK_CID:
rtw_hal_set_hwreg_with_buf(padapter, HW_VAR_C2H_HANDLE, pdrvextra_cmd->pbuf, pdrvextra_cmd->size);
diff --git a/drivers/staging/rtl8723bs/core/rtw_debug.c b/drivers/staging/rtl8723bs/core/rtw_debug.c
index 9f8446ccf771..695a85999270 100644
--- a/drivers/staging/rtl8723bs/core/rtw_debug.c
+++ b/drivers/staging/rtl8723bs/core/rtw_debug.c
@@ -8,6 +8,7 @@
#include <drv_types.h>
#include <rtw_debug.h>
+#include <hal_btcoex.h>
u32 GlobalDebugLevel = _drv_err_;
@@ -1350,7 +1351,7 @@ int proc_get_btcoex_dbg(struct seq_file *m, void *v)
char buf[512] = {0};
padapter = (struct adapter *)rtw_netdev_priv(dev);
- rtw_btcoex_GetDBG(padapter, buf, 512);
+ hal_btcoex_GetDBG(padapter, buf, 512);
DBG_871X_SEL(m, "%s", buf);
@@ -1410,7 +1411,7 @@ ssize_t proc_set_btcoex_dbg(struct file *file, const char __user *buffer, size_t
DBG_871X(FUNC_ADPT_FMT ": input 0x%08X 0x%08X\n",
FUNC_ADPT_ARG(padapter), module[0], module[1]);
- rtw_btcoex_SetDBG(padapter, module);
+ hal_btcoex_SetDBG(padapter, module);
return count;
}
@@ -1428,7 +1429,7 @@ int proc_get_btcoex_info(struct seq_file *m, void *v)
if (!pbuf)
return -ENOMEM;
- rtw_btcoex_DisplayBtCoexInfo(padapter, pbuf, bufsize);
+ hal_btcoex_DisplayBtCoexInfo(padapter, pbuf, bufsize);
DBG_871X_SEL(m, "%s\n", pbuf);
diff --git a/drivers/staging/rtl8723bs/core/rtw_eeprom.c b/drivers/staging/rtl8723bs/core/rtw_eeprom.c
index 5eea02cfce1f..3cbd65dee741 100644
--- a/drivers/staging/rtl8723bs/core/rtw_eeprom.c
+++ b/drivers/staging/rtl8723bs/core/rtw_eeprom.c
@@ -118,25 +118,6 @@ _func_enter_;
_func_exit_;
}
-u16 wait_eeprom_cmd_done(_adapter *padapter)
-{
- u8 x;
- u16 i, res = false;
-_func_enter_;
- standby(padapter);
- for (i = 0; i < 200; i++) {
- x = rtw_read8(padapter, EE_9346CR);
- if (x & _EEDO) {
- res = true;
- goto exit;
- }
- udelay(CLOCK_RATE);
- }
-exit:
-_func_exit_;
- return res;
-}
-
void eeprom_clean(_adapter *padapter)
{
u16 x;
@@ -166,68 +147,6 @@ out:
_func_exit_;
}
-void eeprom_write16(_adapter *padapter, u16 reg, u16 data)
-{
- u8 x;
-
-_func_enter_;
-
- x = rtw_read8(padapter, EE_9346CR);
-
- x &= ~(_EEDI | _EEDO | _EESK | _EEM0);
- x |= _EEM1 | _EECS;
- rtw_write8(padapter, EE_9346CR, x);
-
- shift_out_bits(padapter, EEPROM_EWEN_OPCODE, 5);
-
- if (padapter->EepromAddressSize == 8) /*CF+ and SDIO*/
- shift_out_bits(padapter, 0, 6);
- else /*USB*/
- shift_out_bits(padapter, 0, 4);
-
- standby(padapter);
-
-/* Commented out by rcnjko, 2004.0
-* Erase this particular word. Write the erase opcode and register
-* number in that order. The opcode is 3bits in length; reg is 6 bits long.
-* shift_out_bits(Adapter, EEPROM_ERASE_OPCODE, 3);
-* shift_out_bits(Adapter, reg, Adapter->EepromAddressSize);
-*
-* if (wait_eeprom_cmd_done(Adapter ) == false)
-* {
-* return;
-* }
-*/
-
- standby(padapter);
-
- /* write the new word to the EEPROM*/
-
- /* send the write opcode the EEPORM*/
- shift_out_bits(padapter, EEPROM_WRITE_OPCODE, 3);
-
- /* select which word in the EEPROM that we are writing to.*/
- shift_out_bits(padapter, reg, padapter->EepromAddressSize);
-
- /* write the data to the selected EEPROM word.*/
- shift_out_bits(padapter, data, 16);
-
- if (wait_eeprom_cmd_done(padapter) == false) {
-
- goto exit;
- }
-
- standby(padapter);
-
- shift_out_bits(padapter, EEPROM_EWDS_OPCODE, 5);
- shift_out_bits(padapter, reg, 4);
-
- eeprom_clean(padapter);
-exit:
-_func_exit_;
- return;
-}
-
u16 eeprom_read16(_adapter *padapter, u16 reg) /*ReadEEprom*/
{
@@ -268,53 +187,6 @@ _func_exit_;
}
-
-
-
-/*From even offset*/
-void eeprom_read_sz(_adapter *padapter, u16 reg, u8 *data, u32 sz)
-{
-
- u16 x, data16;
- u32 i;
-_func_enter_;
- if (padapter->bSurpriseRemoved == true) {
- RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==true"));
- goto out;
- }
- /* select EEPROM, reset bits, set _EECS*/
- x = rtw_read8(padapter, EE_9346CR);
-
- if (padapter->bSurpriseRemoved == true) {
- RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==true"));
- goto out;
- }
-
- x &= ~(_EEDI | _EEDO | _EESK | _EEM0);
- x |= _EEM1 | _EECS;
- rtw_write8(padapter, EE_9346CR, (unsigned char)x);
-
- /* write the read opcode and register number in that order*/
- /* The opcode is 3bits in length, reg is 6 bits long*/
- shift_out_bits(padapter, EEPROM_READ_OPCODE, 3);
- shift_out_bits(padapter, reg, padapter->EepromAddressSize);
-
-
- for (i = 0; i < sz; i += 2) {
- data16 = shift_in_bits(padapter);
- data[i] = data16 & 0xff;
- data[i+1] = data16 >> 8;
- }
-
- eeprom_clean(padapter);
-out:
-_func_exit_;
-
-
-
-}
-
-
/*addr_off : address offset of the entry in eeprom (not the tuple number of eeprom (reg); that is addr_off !=reg)*/
u8 eeprom_read(_adapter *padapter, u32 addr_off, u8 sz, u8 *rbuf)
{
@@ -348,14 +220,3 @@ _func_enter_;
_func_exit_;
return true;
}
-
-
-
-void read_eeprom_content(_adapter *padapter)
-{
-
-_func_enter_;
-
-
-_func_exit_;
-}
diff --git a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c
index aaf27438cd81..6018d877a8a6 100644
--- a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c
+++ b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c
@@ -654,7 +654,7 @@ int rtw_get_wapi_ie(u8 *in_ie, uint in_len, u8 *wapi_ie, u16 *wapi_len)
}
/* endif */
-int rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie, u16 *wpa_len)
+void rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie, u16 *wpa_len)
{
u8 authmode, sec_idx, i;
u8 wpa_oui[4] = {0x0, 0x50, 0xf2, 0x01};
@@ -705,8 +705,6 @@ int rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie,
}
}
}
-
- return *rsn_len + *wpa_len;
}
u8 rtw_is_wps_ie(u8 *ie_ptr, uint *wps_ielen)
diff --git a/drivers/staging/rtl8723bs/core/rtw_ioctl_set.c b/drivers/staging/rtl8723bs/core/rtw_ioctl_set.c
index bd75bca1ac6e..8eb0ff57925f 100644
--- a/drivers/staging/rtl8723bs/core/rtw_ioctl_set.c
+++ b/drivers/staging/rtl8723bs/core/rtw_ioctl_set.c
@@ -357,7 +357,7 @@ u8 rtw_set_802_11_connect(struct adapter *padapter, u8 *bssid, struct ndis_802_1
if (!bssid || rtw_validate_bssid(bssid) == false)
bssid_valid = false;
- if (ssid_valid == false && bssid_valid == false) {
+ if (!ssid_valid && !bssid_valid) {
DBG_871X(FUNC_ADPT_FMT" ssid:%p, ssid_valid:%d, bssid:%p, bssid_valid:%d\n",
FUNC_ADPT_ARG(padapter), ssid, ssid_valid, bssid, bssid_valid);
status = _FAIL;
diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c
index 5f78f1eaa7aa..34adf5789c98 100644
--- a/drivers/staging/rtl8723bs/core/rtw_mlme.c
+++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c
@@ -9,6 +9,7 @@
#include <linux/etherdevice.h>
#include <drv_types.h>
#include <rtw_debug.h>
+#include <hal_btcoex.h>
#include <linux/jiffies.h>
extern u8 rtw_do_join(struct adapter *padapter);
@@ -275,7 +276,7 @@ exit:
return pnetwork;
}
-void _rtw_free_network_queue(struct adapter *padapter, u8 isfreeall)
+void rtw_free_network_queue(struct adapter *padapter, u8 isfreeall)
{
struct list_head *phead, *plist;
struct wlan_network *pnetwork;
@@ -375,12 +376,6 @@ void rtw_free_network_nolock(struct adapter *padapter, struct wlan_network *pnet
rtw_cfg80211_unlink_bss(padapter, pnetwork);
}
-
-void rtw_free_network_queue(struct adapter *dev, u8 isfreeall)
-{
- _rtw_free_network_queue(dev, isfreeall);
-}
-
/*
return the wlan_network with the matching addr
@@ -1192,7 +1187,7 @@ static struct sta_info *rtw_joinbss_update_stainfo(struct adapter *padapter, str
rtw_hal_update_sta_rate_mask(padapter, psta);
psta->wireless_mode = pmlmeext->cur_wireless_mode;
- psta->raid = rtw_hal_networktype_to_raid(padapter, psta);
+ psta->raid = networktype_to_raid_ex(padapter, psta);
/* sta mode */
@@ -1672,7 +1667,7 @@ void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf)
roam_target = pmlmepriv->roam_network;
}
- if (roam == true) {
+ if (roam) {
if (rtw_to_roam(adapter) > 0)
rtw_dec_to_roam(adapter); /* this stadel_event is caused by roaming, decrease to_roam */
else if (rtw_to_roam(adapter) == 0)
@@ -1894,10 +1889,10 @@ void rtw_dynamic_check_timer_handler(struct adapter *adapter)
return;
if (is_primary_adapter(adapter))
- DBG_871X("IsBtDisabled =%d, IsBtControlLps =%d\n", rtw_btcoex_IsBtDisabled(adapter), rtw_btcoex_IsBtControlLps(adapter));
+ DBG_871X("IsBtDisabled =%d, IsBtControlLps =%d\n", hal_btcoex_IsBtDisabled(adapter), hal_btcoex_IsBtControlLps(adapter));
if ((adapter_to_pwrctl(adapter)->bFwCurrentInPSMode == true)
- && (rtw_btcoex_IsBtControlLps(adapter) == false)
+ && (hal_btcoex_IsBtControlLps(adapter) == false)
) {
u8 bEnterPS;
@@ -1936,11 +1931,6 @@ inline void rtw_clear_scan_deny(struct adapter *adapter)
DBG_871X(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(adapter));
}
-void rtw_set_scan_deny_timer_hdl(struct adapter *adapter)
-{
- rtw_clear_scan_deny(adapter);
-}
-
void rtw_set_scan_deny(struct adapter *adapter, u32 ms)
{
struct mlme_priv *mlmepriv = &adapter->mlmepriv;
@@ -2229,7 +2219,6 @@ sint rtw_set_auth(struct adapter *adapter, struct security_priv *psecuritypriv)
goto exit;
}
- memset(psetauthparm, 0, sizeof(struct setauth_parm));
psetauthparm->mode = (unsigned char)psecuritypriv->dot11AuthAlgrthm;
pcmd->cmdcode = _SetAuth_CMD_;
@@ -2262,7 +2251,6 @@ sint rtw_set_key(struct adapter *adapter, struct security_priv *psecuritypriv, s
res = _FAIL;
goto exit;
}
- memset(psetkeyparm, 0, sizeof(struct setkey_parm));
if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) {
psetkeyparm->algorithm = (unsigned char)psecuritypriv->dot118021XGrpPrivacy;
diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
index d110d4514771..4285844420cb 100644
--- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
+++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
@@ -9,9 +9,9 @@
#include <drv_types.h>
#include <rtw_debug.h>
#include <rtw_wifi_regd.h>
+#include <hal_btcoex.h>
#include <linux/kernel.h>
-
static struct mlme_handler mlme_sta_tbl[] = {
{WIFI_ASSOCREQ, "OnAssocReq", &OnAssocReq},
{WIFI_ASSOCRSP, "OnAssocRsp", &OnAssocRsp},
@@ -51,7 +51,6 @@ static struct action_handler OnAction_tbl[] = {
{RTW_WLAN_CATEGORY_P2P, "ACTION_P2P", &DoReserved},
};
-
static u8 null_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
/**************************************************
@@ -279,7 +278,7 @@ void init_mlme_default_rate_set(struct adapter *padapter)
static void init_mlme_ext_priv_value(struct adapter *padapter)
{
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
- struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
atomic_set(&pmlmeext->event_seq, 0);
pmlmeext->mgnt_seq = 0;/* reset to zero when disconnect at client mode */
@@ -372,9 +371,8 @@ static void init_channel_list(struct adapter *padapter, RT_CHANNEL_INFO *channel
struct p2p_reg_class *reg = NULL;
for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
- if (!has_channel(channel_set, chanset_size, ch)) {
+ if (!has_channel(channel_set, chanset_size, ch))
continue;
- }
if ((0 == padapter->registrypriv.ht_enable) && (8 == o->inc))
continue;
@@ -383,7 +381,7 @@ static void init_channel_list(struct adapter *padapter, RT_CHANNEL_INFO *channel
((BW40MINUS == o->bw) || (BW40PLUS == o->bw)))
continue;
- if (reg == NULL) {
+ if (!reg) {
reg = &channel_list->reg_class[cla];
cla++;
reg->reg_class = o->op_class;
@@ -466,8 +464,8 @@ int init_mlme_ext_priv(struct adapter *padapter)
int res = _SUCCESS;
struct registry_priv *pregistrypriv = &padapter->registrypriv;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
- struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
- struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
pmlmeext->padapter = padapter;
@@ -611,8 +609,8 @@ unsigned int OnProbeReq(struct adapter *padapter, union recv_frame *precv_frame)
unsigned char *p;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
- struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
- struct wlan_bssid_ex *cur = &(pmlmeinfo->network);
+ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+ struct wlan_bssid_ex *cur = &pmlmeinfo->network;
u8 *pframe = precv_frame->u.hdr.rx_data;
uint len = precv_frame->u.hdr.len;
u8 is_valid_p2p_probereq = false;
@@ -661,7 +659,7 @@ unsigned int OnProbeReq(struct adapter *padapter, union recv_frame *precv_frame)
/* allocate a new one */
DBG_871X("going to alloc stainfo for rc ="MAC_FMT"\n", MAC_ARG(get_sa(pframe)));
psta = rtw_alloc_stainfo(pstapriv, get_sa(pframe));
- if (psta == NULL) {
+ if (!psta) {
/* TODO: */
DBG_871X(" Exceed the upper limit of supported clients...\n");
return _SUCCESS;
@@ -1219,7 +1217,7 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame)
}
pstat = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe));
- if (pstat == NULL) {
+ if (!pstat) {
status = _RSON_CLS2_;
goto asoc_class2_error;
}
@@ -1261,7 +1259,6 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame)
goto OnAssocReqFail;
}
-
/* now we should check all the fields... */
/* checking SSID */
p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _SSID_IE_, &ie_len,
@@ -1280,7 +1277,7 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame)
status = _STATS_FAILURE_;
}
- if (_STATS_SUCCESSFUL_ != status)
+ if (status != _STATS_SUCCESSFUL_)
goto OnAssocReqFail;
/* check if the supported rate is ok */
@@ -1376,11 +1373,11 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame)
wpa_ie_len = 0;
}
- if (_STATS_SUCCESSFUL_ != status)
+ if (status != _STATS_SUCCESSFUL_)
goto OnAssocReqFail;
pstat->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
- if (wpa_ie == NULL) {
+ if (!wpa_ie) {
if (elems.wps_ie) {
DBG_871X("STA included WPS IE in "
"(Re)Association Request - assume WPS is "
@@ -1946,16 +1943,15 @@ unsigned int OnAction_back(struct adapter *padapter, union recv_frame *precv_fra
addr = GetAddr2Ptr(pframe);
psta = rtw_get_stainfo(pstapriv, addr);
- if (psta == NULL)
+ if (!psta)
return _SUCCESS;
frame_body = (unsigned char *)(pframe + sizeof(struct ieee80211_hdr_3addr));
category = frame_body[0];
if (category == RTW_WLAN_CATEGORY_BACK) {/* representing Block Ack */
- if (!pmlmeinfo->HT_enable) {
+ if (!pmlmeinfo->HT_enable)
return _SUCCESS;
- }
action = frame_body[1];
DBG_871X("%s, action =%d\n", __func__, action);
@@ -2400,9 +2396,8 @@ s32 dump_mgntframe_and_wait_ack(struct adapter *padapter, struct xmit_frame *pmg
pxmitpriv->ack_tx = true;
pxmitpriv->seq_no = seq_no++;
pmgntframe->ack_report = 1;
- if (rtw_hal_mgnt_xmit(padapter, pmgntframe) == _SUCCESS) {
+ if (rtw_hal_mgnt_xmit(padapter, pmgntframe) == _SUCCESS)
ret = rtw_ack_tx_wait(pxmitpriv, timeout_ms);
- }
pxmitpriv->ack_tx = false;
mutex_unlock(&pxmitpriv->ack_tx_mutex);
@@ -2465,7 +2460,7 @@ void issue_beacon(struct adapter *padapter, int timeout_ms)
/* DBG_871X("%s\n", __func__); */
pmgntframe = alloc_mgtxmitframe(pxmitpriv);
- if (pmgntframe == NULL) {
+ if (!pmgntframe) {
DBG_871X("%s, alloc mgnt frame fail\n", __func__);
return;
}
@@ -2846,7 +2841,7 @@ static int _issue_probereq(struct adapter *padapter,
RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+issue_probereq\n"));
pmgntframe = alloc_mgtxmitframe(pxmitpriv);
- if (pmgntframe == NULL)
+ if (!pmgntframe)
goto exit;
/* update attribute */
@@ -3219,7 +3214,6 @@ void issue_asocrsp(struct adapter *padapter, unsigned short status, struct sta_i
}
-
if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK) {
pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, 6, REALTEK_96B_IE, &(pattrib->pktlen));
}
@@ -3264,7 +3258,6 @@ void issue_assocreq(struct adapter *padapter)
pattrib = &pmgntframe->attrib;
update_mgntframe_attrib(padapter, pattrib);
-
memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
@@ -3914,7 +3907,7 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch
DBG_871X("%s, category =%d, action =%d, status =%d\n", __func__, category, action, status);
pmgntframe = alloc_mgtxmitframe(pxmitpriv);
- if (pmgntframe == NULL)
+ if (!pmgntframe)
return;
/* update attribute */
@@ -3952,7 +3945,7 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch
} while (pmlmeinfo->dialogToken == 0);
pframe = rtw_set_fixed_ie(pframe, 1, &(pmlmeinfo->dialogToken), &(pattrib->pktlen));
- if (rtw_btcoex_IsBTCoexCtrlAMPDUSize(padapter)) {
+ if (hal_btcoex_IsBTCoexCtrlAMPDUSize(padapter)) {
/* A-MSDU NOT Supported */
BA_para_set = 0;
/* immediate Block Ack */
@@ -4008,7 +4001,7 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch
else
BA_para_set = ((le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x1000); /* 64 buffer size */
- if (rtw_btcoex_IsBTCoexCtrlAMPDUSize(padapter) &&
+ if (hal_btcoex_IsBTCoexCtrlAMPDUSize(padapter) &&
padapter->driver_rx_ampdu_factor == 0xFF) {
/* max buffer size is 8 MSDU */
BA_para_set &= ~RTW_IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK;
@@ -5038,12 +5031,12 @@ void report_survey_event(struct adapter *padapter, union recv_frame *precv_frame
pcmdpriv = &padapter->cmdpriv;
pcmd_obj = rtw_zmalloc(sizeof(struct cmd_obj));
- if (pcmd_obj == NULL)
+ if (!pcmd_obj)
return;
cmdsz = (sizeof(struct survey_event) + sizeof(struct C2HEvent_Header));
pevtcmd = rtw_zmalloc(cmdsz);
- if (pevtcmd == NULL) {
+ if (!pevtcmd) {
kfree(pcmd_obj);
return;
}
@@ -5091,12 +5084,12 @@ void report_surveydone_event(struct adapter *padapter)
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
pcmd_obj = rtw_zmalloc(sizeof(struct cmd_obj));
- if (pcmd_obj == NULL)
+ if (!pcmd_obj)
return;
cmdsz = (sizeof(struct surveydone_event) + sizeof(struct C2HEvent_Header));
pevtcmd = rtw_zmalloc(cmdsz);
- if (pevtcmd == NULL) {
+ if (!pevtcmd) {
kfree(pcmd_obj);
return;
}
@@ -5138,12 +5131,12 @@ void report_join_res(struct adapter *padapter, int res)
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
pcmd_obj = rtw_zmalloc(sizeof(struct cmd_obj));
- if (pcmd_obj == NULL)
+ if (!pcmd_obj)
return;
cmdsz = (sizeof(struct joinbss_event) + sizeof(struct C2HEvent_Header));
pevtcmd = rtw_zmalloc(cmdsz);
- if (pevtcmd == NULL) {
+ if (!pevtcmd) {
kfree(pcmd_obj);
return;
}
@@ -5189,12 +5182,12 @@ void report_wmm_edca_update(struct adapter *padapter)
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
pcmd_obj = rtw_zmalloc(sizeof(struct cmd_obj));
- if (pcmd_obj == NULL)
+ if (!pcmd_obj)
return;
cmdsz = (sizeof(struct wmm_event) + sizeof(struct C2HEvent_Header));
pevtcmd = rtw_zmalloc(cmdsz);
- if (pevtcmd == NULL) {
+ if (!pevtcmd) {
kfree(pcmd_obj);
return;
}
@@ -5571,7 +5564,7 @@ void mlmeext_sta_add_event_callback(struct adapter *padapter, struct sta_info *p
/* ToDo: HT for Ad-hoc */
psta->wireless_mode = rtw_check_network_type(psta->bssrateset, psta->bssratelen, pmlmeext->cur_channel);
- psta->raid = rtw_hal_networktype_to_raid(padapter, psta);
+ psta->raid = networktype_to_raid_ex(padapter, psta);
/* rate radaptive */
Update_RA_Entry(padapter, psta);
@@ -6044,7 +6037,7 @@ u8 setopmode_hdl(struct adapter *padapter, u8 *pbuf)
}
rtw_hal_set_hwreg(padapter, HW_VAR_SET_OPMODE, (u8 *)(&type));
- /* Set_NETYPE0_MSR(padapter, type); */
+ /* Set_MSR(padapter, type); */
#ifdef CONFIG_AUTO_AP_MODE
@@ -6436,9 +6429,8 @@ u8 setauth_hdl(struct adapter *padapter, unsigned char *pbuf)
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
- if (pparm->mode < 4) {
+ if (pparm->mode < 4)
pmlmeinfo->auth_algo = pparm->mode;
- }
return H2C_SUCCESS;
}
@@ -6772,7 +6764,7 @@ int rtw_chk_start_clnt_join(struct adapter *padapter, u8 *ch, u8 *bw, u8 *offset
*offset = cur_ch_offset;
}
- return connect_allow == true ? _SUCCESS : _FAIL;
+ return connect_allow ? _SUCCESS : _FAIL;
}
/* Find union about ch, bw, ch_offset of all linked/linking interfaces */
@@ -6780,10 +6772,6 @@ int rtw_get_ch_setting_union(struct adapter *adapter, u8 *ch, u8 *bw, u8 *offset
{
struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
struct adapter *iface;
- struct mlme_ext_priv *mlmeext;
- u8 ch_ret = 0;
- u8 bw_ret = CHANNEL_WIDTH_20;
- u8 offset_ret = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
if (ch)
*ch = 0;
@@ -6793,15 +6781,10 @@ int rtw_get_ch_setting_union(struct adapter *adapter, u8 *ch, u8 *bw, u8 *offset
*offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
iface = dvobj->padapters;
- mlmeext = &iface->mlmeextpriv;
if (!check_fwstate(&iface->mlmepriv, _FW_LINKED|_FW_UNDER_LINKING))
return 0;
- ch_ret = mlmeext->cur_channel;
- bw_ret = mlmeext->cur_bwmode;
- offset_ret = mlmeext->cur_ch_offset;
-
return 1;
}
diff --git a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c
index 5c468c5057b1..ae7fb7046c93 100644
--- a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c
+++ b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c
@@ -43,7 +43,7 @@ void ips_enter(struct adapter *padapter)
struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
- rtw_btcoex_IpsNotify(padapter, pwrpriv->ips_mode_req);
+ hal_btcoex_IpsNotify(padapter, pwrpriv->ips_mode_req);
mutex_lock(&pwrpriv->lock);
_ips_enter(padapter);
@@ -90,7 +90,7 @@ int ips_leave(struct adapter *padapter)
mutex_unlock(&pwrpriv->lock);
if (_SUCCESS == ret)
- rtw_btcoex_IpsNotify(padapter, IPS_NONE);
+ hal_btcoex_IpsNotify(padapter, IPS_NONE);
return ret;
}
@@ -178,7 +178,7 @@ void rtw_ps_processor(struct adapter *padapter)
if (pwrpriv->ips_mode_req == IPS_NONE)
goto exit;
- if (rtw_pwr_unassociated_idle(padapter) == false)
+ if (!rtw_pwr_unassociated_idle(padapter))
goto exit;
if ((pwrpriv->rf_pwrstate == rf_on) && ((pwrpriv->pwr_state_check_cnts%4) == 0)) {
@@ -221,7 +221,7 @@ void traffic_check_for_leave_lps(struct adapter *padapter, u8 tx, u32 tx_packets
if (xmit_cnt > 8) {
if ((adapter_to_pwrctl(padapter)->bLeisurePs)
&& (adapter_to_pwrctl(padapter)->pwr_mode != PS_MODE_ACTIVE)
- && (rtw_btcoex_IsBtControlLps(padapter) == false)
+ && (hal_btcoex_IsBtControlLps(padapter) == false)
) {
DBG_871X("leave lps via Tx = %d\n", xmit_cnt);
bLeaveLPS = true;
@@ -236,7 +236,7 @@ void traffic_check_for_leave_lps(struct adapter *padapter, u8 tx, u32 tx_packets
if (pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod > 4/*2*/) {
if ((adapter_to_pwrctl(padapter)->bLeisurePs)
&& (adapter_to_pwrctl(padapter)->pwr_mode != PS_MODE_ACTIVE)
- && (rtw_btcoex_IsBtControlLps(padapter) == false)
+ && (hal_btcoex_IsBtControlLps(padapter) == false)
) {
DBG_871X("leave lps via Rx = %d\n", pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod);
bLeaveLPS = true;
@@ -418,10 +418,10 @@ void rtw_set_ps_mode(struct adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_a
/* if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) */
if (ps_mode == PS_MODE_ACTIVE) {
if (1
- && (((rtw_btcoex_IsBtControlLps(padapter) == false)
+ && (((hal_btcoex_IsBtControlLps(padapter) == false)
)
- || ((rtw_btcoex_IsBtControlLps(padapter) == true)
- && (rtw_btcoex_IsLpsOn(padapter) == false))
+ || ((hal_btcoex_IsBtControlLps(padapter) == true)
+ && (hal_btcoex_IsLpsOn(padapter) == false))
)
) {
DBG_871X(FUNC_ADPT_FMT" Leave 802.11 power save - %s\n",
@@ -457,19 +457,19 @@ void rtw_set_ps_mode(struct adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_a
rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode));
pwrpriv->bFwCurrentInPSMode = false;
- rtw_btcoex_LpsNotify(padapter, ps_mode);
+ hal_btcoex_LpsNotify(padapter, ps_mode);
}
} else {
if ((PS_RDY_CHECK(padapter) && check_fwstate(&padapter->mlmepriv, WIFI_ASOC_STATE))
- || ((rtw_btcoex_IsBtControlLps(padapter) == true)
- && (rtw_btcoex_IsLpsOn(padapter) == true))
+ || ((hal_btcoex_IsBtControlLps(padapter) == true)
+ && (hal_btcoex_IsLpsOn(padapter) == true))
) {
u8 pslv;
DBG_871X(FUNC_ADPT_FMT" Enter 802.11 power save - %s\n",
FUNC_ADPT_ARG(padapter), msg);
- rtw_btcoex_LpsNotify(padapter, ps_mode);
+ hal_btcoex_LpsNotify(padapter, ps_mode);
pwrpriv->bFwCurrentInPSMode = true;
pwrpriv->pwr_mode = ps_mode;
@@ -481,11 +481,11 @@ void rtw_set_ps_mode(struct adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_a
if (pwrpriv->alives == 0)
pslv = PS_STATE_S0;
- if ((rtw_btcoex_IsBtDisabled(padapter) == false)
- && (rtw_btcoex_IsBtControlLps(padapter) == true)) {
+ if ((hal_btcoex_IsBtDisabled(padapter) == false)
+ && (hal_btcoex_IsBtControlLps(padapter) == true)) {
u8 val8;
- val8 = rtw_btcoex_LpsVal(padapter);
+ val8 = hal_btcoex_LpsVal(padapter);
if (val8 & BIT(4))
pslv = PS_STATE_S2;
}
@@ -544,7 +544,7 @@ void LPS_Enter(struct adapter *padapter, const char *msg)
int n_assoc_iface = 0;
char buf[32] = {0};
- if (rtw_btcoex_IsBtControlLps(padapter) == true)
+ if (hal_btcoex_IsBtControlLps(padapter) == true)
return;
/* Skip lps enter request if number of assocated adapters is not 1 */
@@ -589,7 +589,7 @@ void LPS_Leave(struct adapter *padapter, const char *msg)
/* DBG_871X("+LeisurePSLeave\n"); */
- if (rtw_btcoex_IsBtControlLps(padapter) == true)
+ if (hal_btcoex_IsBtControlLps(padapter) == true)
return;
if (pwrpriv->bLeisurePs) {
@@ -910,11 +910,11 @@ void rtw_unregister_task_alive(struct adapter *padapter, u32 task)
pwrctrl = adapter_to_pwrctl(padapter);
pslv = PS_STATE_S0;
- if ((rtw_btcoex_IsBtDisabled(padapter) == false)
- && (rtw_btcoex_IsBtControlLps(padapter) == true)) {
+ if ((hal_btcoex_IsBtDisabled(padapter) == false)
+ && (hal_btcoex_IsBtControlLps(padapter) == true)) {
u8 val8;
- val8 = rtw_btcoex_LpsVal(padapter);
+ val8 = hal_btcoex_LpsVal(padapter);
if (val8 & BIT(4))
pslv = PS_STATE_S2;
}
@@ -1051,11 +1051,11 @@ void rtw_unregister_tx_alive(struct adapter *padapter)
pwrctrl = adapter_to_pwrctl(padapter);
pslv = PS_STATE_S0;
- if ((rtw_btcoex_IsBtDisabled(padapter) == false)
- && (rtw_btcoex_IsBtControlLps(padapter) == true)) {
+ if ((hal_btcoex_IsBtDisabled(padapter) == false)
+ && (hal_btcoex_IsBtControlLps(padapter) == true)) {
u8 val8;
- val8 = rtw_btcoex_LpsVal(padapter);
+ val8 = hal_btcoex_LpsVal(padapter);
if (val8 & BIT(4))
pslv = PS_STATE_S2;
}
@@ -1093,11 +1093,11 @@ void rtw_unregister_cmd_alive(struct adapter *padapter)
pwrctrl = adapter_to_pwrctl(padapter);
pslv = PS_STATE_S0;
- if ((rtw_btcoex_IsBtDisabled(padapter) == false)
- && (rtw_btcoex_IsBtControlLps(padapter) == true)) {
+ if ((hal_btcoex_IsBtDisabled(padapter) == false)
+ && (hal_btcoex_IsBtControlLps(padapter) == true)) {
u8 val8;
- val8 = rtw_btcoex_LpsVal(padapter);
+ val8 = hal_btcoex_LpsVal(padapter);
if (val8 & BIT(4))
pslv = PS_STATE_S2;
}
diff --git a/drivers/staging/rtl8723bs/core/rtw_recv.c b/drivers/staging/rtl8723bs/core/rtw_recv.c
index b543e9768e88..687ff3c6f09f 100644
--- a/drivers/staging/rtl8723bs/core/rtw_recv.c
+++ b/drivers/staging/rtl8723bs/core/rtw_recv.c
@@ -50,7 +50,7 @@ sint _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter)
precvpriv->pallocated_frame_buf = vzalloc(NR_RECVFRAME * sizeof(union recv_frame) + RXFRAME_ALIGN_SZ);
- if (precvpriv->pallocated_frame_buf == NULL) {
+ if (!precvpriv->pallocated_frame_buf) {
res = _FAIL;
goto exit;
}
@@ -67,7 +67,7 @@ sint _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter)
list_add_tail(&(precvframe->u.list), &(precvpriv->free_recv_queue.queue));
- res = rtw_os_recv_resource_alloc(padapter, precvframe);
+ rtw_os_recv_resource_alloc(padapter, precvframe);
precvframe->u.hdr.len = 0;
@@ -122,7 +122,7 @@ union recv_frame *_rtw_alloc_recvframe(struct __queue *pfree_recv_queue)
list_del_init(&precvframe->u.hdr.list);
padapter = precvframe->u.hdr.adapter;
- if (padapter != NULL) {
+ if (padapter) {
precvpriv = &padapter->recvpriv;
if (pfree_recv_queue == &precvpriv->free_recv_queue)
precvpriv->free_recvframe_cnt--;
@@ -160,7 +160,7 @@ int rtw_free_recvframe(union recv_frame *precvframe, struct __queue *pfree_recv_
list_add_tail(&(precvframe->u.hdr.list), get_list_head(pfree_recv_queue));
- if (padapter != NULL) {
+ if (padapter) {
if (pfree_recv_queue == &precvpriv->free_recv_queue)
precvpriv->free_recvframe_cnt++;
}
@@ -183,7 +183,7 @@ sint _rtw_enqueue_recvframe(union recv_frame *precvframe, struct __queue *queue)
list_add_tail(&(precvframe->u.hdr.list), get_list_head(queue));
- if (padapter != NULL)
+ if (padapter)
if (queue == &precvpriv->free_recv_queue)
precvpriv->free_recvframe_cnt++;
@@ -334,7 +334,7 @@ sint recvframe_chkmic(struct adapter *adapter, union recv_frame *precvframe)
prxattrib->ra[0], prxattrib->ra[1], prxattrib->ra[2], prxattrib->ra[3], prxattrib->ra[4], prxattrib->ra[5]));
/* calculate mic code */
- if (stainfo != NULL) {
+ if (stainfo) {
if (IS_MCAST(prxattrib->ra)) {
/* mickey =&psecuritypriv->dot118021XGrprxmickey.skey[0]; */
/* iv = precvframe->u.hdr.rx_data+prxattrib->hdrlen; */
@@ -570,7 +570,7 @@ union recv_frame *portctrl(struct adapter *adapter, union recv_frame *precv_fram
RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:adapter->securitypriv.dot11AuthAlgrthm =%d\n", adapter->securitypriv.dot11AuthAlgrthm));
if (auth_alg == 2) {
- if ((psta != NULL) && (psta->ieee8021x_blocked)) {
+ if ((psta) && (psta->ieee8021x_blocked)) {
__be16 be_tmp;
/* blocked */
@@ -859,7 +859,7 @@ sint sta2sta_data_frame(
else
*psta = rtw_get_stainfo(pstapriv, sta_addr); /* get ap_info */
- if (*psta == NULL) {
+ if (!*psta) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under sta2sta_data_frame ; drop pkt\n"));
ret = _FAIL;
goto exit;
@@ -942,7 +942,7 @@ sint ap2sta_data_frame(
else
*psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get ap_info */
- if (*psta == NULL) {
+ if (!*psta) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("ap2sta: can't get psta under STATION_MODE ; drop pkt\n"));
#ifdef DBG_RX_DROP_FRAME
DBG_871X("DBG_RX_DROP_FRAME %s can't get psta under STATION_MODE ; drop pkt\n", __func__);
@@ -974,7 +974,7 @@ sint ap2sta_data_frame(
*psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get sta_info */
- if (*psta == NULL) {
+ if (!*psta) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under MP_MODE ; drop pkt\n"));
#ifdef DBG_RX_DROP_FRAME
DBG_871X("DBG_RX_DROP_FRAME %s can't get psta under WIFI_MP_STATE ; drop pkt\n", __func__);
@@ -991,7 +991,7 @@ sint ap2sta_data_frame(
} else {
if (!memcmp(myhwaddr, pattrib->dst, ETH_ALEN) && (!bmcast)) {
*psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get sta_info */
- if (*psta == NULL) {
+ if (!*psta) {
/* for AP multicast issue , modify by yiwei */
static unsigned long send_issue_deauth_time;
@@ -1042,7 +1042,7 @@ sint sta2ap_data_frame(
}
*psta = rtw_get_stainfo(pstapriv, pattrib->src);
- if (*psta == NULL) {
+ if (!*psta) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under AP_MODE; drop pkt\n"));
DBG_871X("issue_deauth to sta =" MAC_FMT " for the reason(7)\n", MAC_ARG(pattrib->src));
@@ -1099,7 +1099,7 @@ sint validate_recv_ctrl_frame(struct adapter *padapter, union recv_frame *precv_
return _FAIL;
psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe));
- if (psta == NULL)
+ if (!psta)
return _FAIL;
/* for rx pkt statistics */
@@ -1226,7 +1226,7 @@ sint validate_recv_mgnt_frame(struct adapter *padapter, union recv_frame *precv_
RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("+validate_recv_mgnt_frame\n"));
precv_frame = recvframe_chk_defrag(padapter, precv_frame);
- if (precv_frame == NULL) {
+ if (!precv_frame) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("%s: fragment packet\n", __func__));
return _SUCCESS;
}
@@ -1274,7 +1274,7 @@ sint validate_recv_data_frame(struct adapter *adapter, union recv_frame *precv_f
psa = get_sa(ptr);
pbssid = get_hdr_bssid(ptr);
- if (pbssid == NULL) {
+ if (!pbssid) {
#ifdef DBG_RX_DROP_FRAME
DBG_871X("DBG_RX_DROP_FRAME %s pbssid == NULL\n", __func__);
#endif
@@ -1329,7 +1329,7 @@ sint validate_recv_data_frame(struct adapter *adapter, union recv_frame *precv_f
}
- if (psta == NULL) {
+ if (!psta) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" after to_fr_ds_chk; psta == NULL\n"));
#ifdef DBG_RX_DROP_FRAME
DBG_871X("DBG_RX_DROP_FRAME %s psta == NULL\n", __func__);
@@ -1426,7 +1426,7 @@ static sint validate_80211w_mgmt(struct adapter *adapter, union recv_frame *prec
/* actual management data frame body */
data_len = pattrib->pkt_len - pattrib->hdrlen - pattrib->iv_len - pattrib->icv_len;
mgmt_DATA = rtw_zmalloc(data_len);
- if (mgmt_DATA == NULL) {
+ if (!mgmt_DATA) {
DBG_871X("%s mgmt allocate fail !!!!!!!!!\n", __func__);
goto validate_80211w_fail;
}
@@ -1615,7 +1615,6 @@ sint wlanhdr_to_ethhdr(union recv_frame *precvframe)
u8 *psnap_type;
struct ieee80211_snap_hdr *psnap;
__be16 be_tmp;
- sint ret = _SUCCESS;
struct adapter *adapter = precvframe->u.hdr.adapter;
struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
u8 *ptr = get_recvframe_data(precvframe) ; /* point to frame_ctrl field */
@@ -1702,7 +1701,7 @@ sint wlanhdr_to_ethhdr(union recv_frame *precvframe)
memcpy(ptr+12, &be_tmp, 2);
}
- return ret;
+ return _SUCCESS;
}
/* perform defrag */
@@ -1812,7 +1811,7 @@ union recv_frame *recvframe_chk_defrag(struct adapter *padapter, union recv_fram
psta_addr = pfhdr->attrib.ta;
psta = rtw_get_stainfo(pstapriv, psta_addr);
- if (psta == NULL) {
+ if (!psta) {
u8 type = GetFrameType(pfhdr->rx_data);
if (type != WIFI_DATA_TYPE) {
psta = rtw_get_bcmc_stainfo(padapter);
@@ -1828,7 +1827,7 @@ union recv_frame *recvframe_chk_defrag(struct adapter *padapter, union recv_fram
if (ismfrag == 1) {
/* 0~(n-1) fragment frame */
/* enqueue to defraf_g */
- if (pdefrag_q != NULL) {
+ if (pdefrag_q) {
if (fragnum == 0)
/* the first fragment */
if (!list_empty(&pdefrag_q->queue))
@@ -1859,7 +1858,7 @@ union recv_frame *recvframe_chk_defrag(struct adapter *padapter, union recv_fram
if ((ismfrag == 0) && (fragnum != 0)) {
/* the last fragment frame */
/* enqueue the last fragment */
- if (pdefrag_q != NULL) {
+ if (pdefrag_q) {
/* spin_lock(&pdefrag_q->lock); */
phead = get_list_head(pdefrag_q);
list_add_tail(&pfhdr->list, phead);
@@ -1880,7 +1879,7 @@ union recv_frame *recvframe_chk_defrag(struct adapter *padapter, union recv_fram
}
- if ((prtnframe != NULL) && (prtnframe->u.hdr.attrib.privacy)) {
+ if ((prtnframe) && (prtnframe->u.hdr.attrib.privacy)) {
/* after defrag we must check tkip mic code */
if (recvframe_chkmic(padapter, prtnframe) == _FAIL) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvframe_chkmic(padapter, prtnframe) == _FAIL\n"));
@@ -1900,7 +1899,6 @@ static int amsdu_to_msdu(struct adapter *padapter, union recv_frame *prframe)
_pkt *sub_pkt, *subframes[MAX_SUBFRAME_COUNT];
struct recv_priv *precvpriv = &padapter->recvpriv;
struct __queue *pfree_recv_queue = &(precvpriv->free_recv_queue);
- int ret = _SUCCESS;
nr_subframes = 0;
@@ -1924,7 +1922,7 @@ static int amsdu_to_msdu(struct adapter *padapter, union recv_frame *prframe)
}
sub_pkt = rtw_os_alloc_msdu_pkt(prframe, nSubframe_Length, pdata);
- if (sub_pkt == NULL) {
+ if (!sub_pkt) {
DBG_871X("%s(): allocate sub packet fail !!!\n", __func__);
break;
}
@@ -1969,7 +1967,7 @@ static int amsdu_to_msdu(struct adapter *padapter, union recv_frame *prframe)
prframe->u.hdr.len = 0;
rtw_free_recvframe(prframe, pfree_recv_queue);/* free this recv_frame */
- return ret;
+ return _SUCCESS;
}
int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_num);
@@ -2453,7 +2451,7 @@ static int recv_func_posthandle(struct adapter *padapter, union recv_frame *prfr
DBG_COUNTER(padapter->rx_logs.core_rx_post);
prframe = decryptor(padapter, prframe);
- if (prframe == NULL) {
+ if (!prframe) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("decryptor: drop pkt\n"));
#ifdef DBG_RX_DROP_FRAME
DBG_871X("DBG_RX_DROP_FRAME %s decryptor: drop pkt\n", __func__);
@@ -2464,7 +2462,7 @@ static int recv_func_posthandle(struct adapter *padapter, union recv_frame *prfr
}
prframe = recvframe_chk_defrag(padapter, prframe);
- if (prframe == NULL) {
+ if (!prframe) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvframe_chk_defrag: drop pkt\n"));
#ifdef DBG_RX_DROP_FRAME
DBG_871X("DBG_RX_DROP_FRAME %s recvframe_chk_defrag: drop pkt\n", __func__);
@@ -2474,7 +2472,7 @@ static int recv_func_posthandle(struct adapter *padapter, union recv_frame *prfr
}
prframe = portctrl(padapter, prframe);
- if (prframe == NULL) {
+ if (!prframe) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("portctrl: drop pkt\n"));
#ifdef DBG_RX_DROP_FRAME
DBG_871X("DBG_RX_DROP_FRAME %s portctrl: drop pkt\n", __func__);
diff --git a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c
index fdbf967812f9..76c50377f0fe 100644
--- a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c
+++ b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c
@@ -302,14 +302,9 @@ void Switch_DM_Func(struct adapter *padapter, u32 mode, u8 enable)
rtw_hal_set_hwreg(padapter, HW_VAR_DM_FUNC_CLR, (u8 *)(&mode));
}
-static void Set_NETYPE0_MSR(struct adapter *padapter, u8 type)
-{
- rtw_hal_set_hwreg(padapter, HW_VAR_MEDIA_STATUS, (u8 *)(&type));
-}
-
void Set_MSR(struct adapter *padapter, u8 type)
{
- Set_NETYPE0_MSR(padapter, type);
+ rtw_hal_set_hwreg(padapter, HW_VAR_MEDIA_STATUS, (u8 *)(&type));
}
inline u8 rtw_get_oper_ch(struct adapter *adapter)
@@ -745,7 +740,7 @@ s16 rtw_camid_alloc(struct adapter *adapter, struct sta_info *sta, u8 kid)
i = _rtw_camid_search(adapter, addr, kid);
if (i >= 0) {
/* Fix issue that pairwise and group key have same key id. Pairwise key first, group key can overwirte group only(ex: rekey) */
- if (sta || _rtw_camid_is_gk(adapter, i) == true)
+ if (sta || _rtw_camid_is_gk(adapter, i))
cam_id = i;
else
DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" group key id:%u the same key id as pairwise key\n"
@@ -1620,16 +1615,10 @@ void Update_RA_Entry(struct adapter *padapter, struct sta_info *psta)
rtw_hal_update_ra_mask(psta, 0);
}
-void enable_rate_adaptive(struct adapter *padapter, struct sta_info *psta);
-void enable_rate_adaptive(struct adapter *padapter, struct sta_info *psta)
-{
- Update_RA_Entry(padapter, psta);
-}
-
void set_sta_rate(struct adapter *padapter, struct sta_info *psta)
{
/* rate adaptive */
- enable_rate_adaptive(padapter, psta);
+ Update_RA_Entry(padapter, psta);
}
unsigned char check_assoc_AP(u8 *pframe, uint len)
@@ -1943,7 +1932,7 @@ void adaptive_early_32k(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len)
/* delay = (timestamp mod 1024*100)/1000 (unit: ms) */
/* delay_ms = do_div(tsf, (pmlmeinfo->bcn_interval*1024))/1000; */
- delay_ms = rtw_modular64(tsf, (pmlmeinfo->bcn_interval*1024));
+ delay_ms = do_div(tsf, (pmlmeinfo->bcn_interval*1024));
delay_ms = delay_ms/1000;
if (delay_ms >= 8)
diff --git a/drivers/staging/rtl8723bs/core/rtw_xmit.c b/drivers/staging/rtl8723bs/core/rtw_xmit.c
index 2bb679e54dc7..b5dcb78fb4f4 100644
--- a/drivers/staging/rtl8723bs/core/rtw_xmit.c
+++ b/drivers/staging/rtl8723bs/core/rtw_xmit.c
@@ -76,7 +76,7 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter)
pxmitpriv->pallocated_frame_buf = vzalloc(NR_XMITFRAME * sizeof(struct xmit_frame) + 4);
- if (pxmitpriv->pallocated_frame_buf == NULL) {
+ if (!pxmitpriv->pallocated_frame_buf) {
pxmitpriv->pxmit_frame_buf = NULL;
RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_frame fail!\n"));
res = _FAIL;
@@ -115,7 +115,7 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter)
pxmitpriv->pallocated_xmitbuf = vzalloc(NR_XMITBUFF * sizeof(struct xmit_buf) + 4);
- if (pxmitpriv->pallocated_xmitbuf == NULL) {
+ if (!pxmitpriv->pallocated_xmitbuf) {
RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_buf fail!\n"));
res = _FAIL;
goto exit;
@@ -166,7 +166,7 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter)
pxmitpriv->xframe_ext_alloc_addr = vzalloc(NR_XMIT_EXTBUFF * sizeof(struct xmit_frame) + 4);
- if (pxmitpriv->xframe_ext_alloc_addr == NULL) {
+ if (!pxmitpriv->xframe_ext_alloc_addr) {
pxmitpriv->xframe_ext = NULL;
RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xframe_ext fail!\n"));
res = _FAIL;
@@ -199,7 +199,7 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter)
pxmitpriv->pallocated_xmit_extbuf = vzalloc(NR_XMIT_EXTBUFF * sizeof(struct xmit_buf) + 4);
- if (pxmitpriv->pallocated_xmit_extbuf == NULL) {
+ if (!pxmitpriv->pallocated_xmit_extbuf) {
RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_extbuf fail!\n"));
res = _FAIL;
goto exit;
@@ -288,7 +288,7 @@ void _rtw_free_xmit_priv(struct xmit_priv *pxmitpriv)
rtw_hal_free_xmit_priv(padapter);
- if (pxmitpriv->pxmit_frame_buf == NULL)
+ if (!pxmitpriv->pxmit_frame_buf)
return;
for (i = 0; i < NR_XMITFRAME; i++) {
@@ -335,7 +335,7 @@ void _rtw_free_xmit_priv(struct xmit_priv *pxmitpriv)
for (i = 0; i < CMDBUF_MAX; i++) {
pxmitbuf = &pxmitpriv->pcmd_xmitbuf[i];
- if (pxmitbuf != NULL)
+ if (pxmitbuf)
rtw_os_xmit_resource_free(padapter, pxmitbuf, MAX_CMDBUF_SZ+XMITBUF_ALIGN_SZ, true);
}
@@ -625,13 +625,11 @@ exit:
u8 qos_acm(u8 acm_mask, u8 priority)
{
- u8 change_priority = priority;
-
switch (priority) {
case 0:
case 3:
if (acm_mask & BIT(1))
- change_priority = 1;
+ priority = 1;
break;
case 1:
case 2:
@@ -639,19 +637,19 @@ u8 qos_acm(u8 acm_mask, u8 priority)
case 4:
case 5:
if (acm_mask & BIT(2))
- change_priority = 0;
+ priority = 0;
break;
case 6:
case 7:
if (acm_mask & BIT(3))
- change_priority = 5;
+ priority = 5;
break;
default:
DBG_871X("qos_acm(): invalid pattrib->priority: %d!!!\n", priority);
break;
}
- return change_priority;
+ return priority;
}
static void set_qos(struct pkt_file *ppktfile, struct pkt_attrib *pattrib)
@@ -774,7 +772,7 @@ static s32 update_attrib(struct adapter *padapter, _pkt *pkt, struct pkt_attrib
psta = rtw_get_bcmc_stainfo(padapter);
} else {
psta = rtw_get_stainfo(pstapriv, pattrib->ra);
- if (psta == NULL) { /* if we cannot get psta => drop the pkt */
+ if (!psta) { /* if we cannot get psta => drop the pkt */
DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_err_ucast_sta);
RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("\nupdate_attrib => get sta_info fail, ra:" MAC_FMT"\n", MAC_ARG(pattrib->ra)));
#ifdef DBG_TX_DROP_FRAME
@@ -789,7 +787,7 @@ static s32 update_attrib(struct adapter *padapter, _pkt *pkt, struct pkt_attrib
}
}
- if (psta == NULL) {
+ if (!psta) {
/* if we cannot get psta => drop the pkt */
DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_err_sta);
RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("\nupdate_attrib => get sta_info fail, ra:" MAC_FMT "\n", MAC_ARG(pattrib->ra)));
@@ -1098,7 +1096,7 @@ s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr, struct pkt_attrib *pattr
return _FAIL;
}
- if (psta == NULL) {
+ if (!psta) {
DBG_871X("%s, psta ==NUL\n", __func__);
return _FAIL;
}
@@ -1241,7 +1239,7 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, _pkt *pkt, struct xmit_fram
return _FAIL;
}
*/
- if (pxmitframe->buf_addr == NULL) {
+ if (!pxmitframe->buf_addr) {
DBG_8192C("==> %s buf_addr == NULL\n", __func__);
return _FAIL;
}
@@ -1376,7 +1374,7 @@ s32 rtw_mgmt_xmitframe_coalesce(struct adapter *padapter, _pkt *pkt, struct xmit
tmp_buf = BIP_AAD = rtw_zmalloc(ori_len);
subtype = GetFrameSubType(pframe); /* bit(7)~bit(2) */
- if (BIP_AAD == NULL)
+ if (!BIP_AAD)
return _FAIL;
spin_lock_bh(&padapter->security_key_mutex);
@@ -1442,13 +1440,13 @@ s32 rtw_mgmt_xmitframe_coalesce(struct adapter *padapter, _pkt *pkt, struct xmit
else
psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra);
- if (psta == NULL) {
+ if (!psta) {
DBG_871X("%s, psta ==NUL\n", __func__);
goto xmitframe_coalesce_fail;
}
- if (!(psta->state & _FW_LINKED) || pxmitframe->buf_addr == NULL) {
+ if (!(psta->state & _FW_LINKED) || !pxmitframe->buf_addr) {
DBG_871X("%s, not _FW_LINKED or addr null\n", __func__);
goto xmitframe_coalesce_fail;
}
@@ -1570,7 +1568,7 @@ void rtw_update_protection(struct adapter *padapter, u8 *ie, uint ie_len)
case AUTO_VCS:
default:
perp = rtw_get_ie(ie, _ERPINFO_IE_, &erp_len, ie_len);
- if (perp == NULL)
+ if (!perp)
pxmitpriv->vcs = NONE_VCS;
else {
protection = (*(perp + 2)) & BIT(1);
@@ -1622,7 +1620,7 @@ static struct xmit_buf *__rtw_alloc_cmd_xmitbuf(struct xmit_priv *pxmitpriv,
struct xmit_buf *pxmitbuf = NULL;
pxmitbuf = &pxmitpriv->pcmd_xmitbuf[buf_type];
- if (pxmitbuf != NULL) {
+ if (pxmitbuf) {
pxmitbuf->priv_data = NULL;
pxmitbuf->len = 0;
@@ -1647,13 +1645,13 @@ struct xmit_frame *__rtw_alloc_cmdxmitframe(struct xmit_priv *pxmitpriv,
struct xmit_buf *pxmitbuf;
pcmdframe = rtw_alloc_xmitframe(pxmitpriv);
- if (pcmdframe == NULL) {
+ if (!pcmdframe) {
DBG_871X("%s, alloc xmitframe fail\n", __func__);
return NULL;
}
pxmitbuf = __rtw_alloc_cmd_xmitbuf(pxmitpriv, buf_type);
- if (pxmitbuf == NULL) {
+ if (!pxmitbuf) {
DBG_871X("%s, alloc xmitbuf fail\n", __func__);
rtw_free_xmitframe(pxmitpriv, pcmdframe);
return NULL;
@@ -1693,7 +1691,7 @@ struct xmit_buf *rtw_alloc_xmitbuf_ext(struct xmit_priv *pxmitpriv)
list_del_init(&(pxmitbuf->list));
}
- if (pxmitbuf != NULL) {
+ if (pxmitbuf) {
pxmitpriv->free_xmit_extbuf_cnt--;
#ifdef DBG_XMIT_BUF_EXT
DBG_871X("DBG_XMIT_BUF_EXT ALLOC no =%d, free_xmit_extbuf_cnt =%d\n", pxmitbuf->no, pxmitpriv->free_xmit_extbuf_cnt);
@@ -1723,7 +1721,7 @@ s32 rtw_free_xmitbuf_ext(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf)
_irqL irqL;
struct __queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue;
- if (pxmitbuf == NULL)
+ if (!pxmitbuf)
return _FAIL;
spin_lock_irqsave(&pfree_queue->lock, irqL);
@@ -1765,7 +1763,7 @@ struct xmit_buf *rtw_alloc_xmitbuf(struct xmit_priv *pxmitpriv)
list_del_init(&(pxmitbuf->list));
}
- if (pxmitbuf != NULL) {
+ if (pxmitbuf) {
pxmitpriv->free_xmitbuf_cnt--;
#ifdef DBG_XMIT_BUF
DBG_871X("DBG_XMIT_BUF ALLOC no =%d, free_xmitbuf_cnt =%d\n", pxmitbuf->no, pxmitpriv->free_xmitbuf_cnt);
@@ -1801,7 +1799,7 @@ s32 rtw_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf)
/* DBG_871X("+rtw_free_xmitbuf\n"); */
- if (pxmitbuf == NULL)
+ if (!pxmitbuf)
return _FAIL;
if (pxmitbuf->sctx) {
@@ -1831,7 +1829,7 @@ s32 rtw_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf)
static void rtw_init_xmitframe(struct xmit_frame *pxframe)
{
- if (pxframe != NULL) { /* default value setting */
+ if (pxframe) { /* default value setting */
pxframe->buf_addr = NULL;
pxframe->pxmitbuf = NULL;
@@ -1927,7 +1925,7 @@ struct xmit_frame *rtw_alloc_xmitframe_once(struct xmit_priv *pxmitpriv)
alloc_addr = rtw_zmalloc(sizeof(struct xmit_frame) + 4);
- if (alloc_addr == NULL)
+ if (!alloc_addr)
goto exit;
pxframe = (struct xmit_frame *)N_BYTE_ALIGMENT((SIZE_PTR)(alloc_addr), 4);
@@ -1955,7 +1953,7 @@ s32 rtw_free_xmitframe(struct xmit_priv *pxmitpriv, struct xmit_frame *pxmitfram
struct adapter *padapter = pxmitpriv->adapter;
_pkt *pndis_pkt = NULL;
- if (pxmitframe == NULL) {
+ if (!pxmitframe) {
RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("======rtw_free_xmitframe():pxmitframe == NULL!!!!!!!!!!\n"));
goto exit;
}
@@ -2109,7 +2107,7 @@ s32 rtw_xmit_classifier(struct adapter *padapter, struct xmit_frame *pxmitframe)
return _FAIL;
}
- if (psta == NULL) {
+ if (!psta) {
DBG_COUNTER(padapter->tx_logs.core_tx_enqueue_class_err_nosta);
res = _FAIL;
DBG_8192C("rtw_xmit_classifier: psta == NULL\n");
@@ -2310,7 +2308,7 @@ s32 rtw_xmit(struct adapter *padapter, _pkt **ppkt)
drop_cnt = 0;
}
- if (pxmitframe == NULL) {
+ if (!pxmitframe) {
drop_cnt++;
RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit: no more pxmitframe\n"));
DBG_COUNTER(padapter->tx_logs.core_tx_err_pxmitframe);
@@ -2409,7 +2407,7 @@ sint xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_fr
return false;
}
- if (psta == NULL) {
+ if (!psta) {
DBG_COUNTER(padapter->tx_logs.core_tx_ap_enqueue_warn_nosta);
DBG_871X("%s, psta ==NUL\n", __func__);
return false;
@@ -2426,7 +2424,7 @@ sint xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_fr
/* DBG_871X("directly xmit pspoll_triggered packet\n"); */
/* pattrib->triggered = 0; */
- if (bmcst && xmitframe_hiq_filter(pxmitframe) == true)
+ if (bmcst && xmitframe_hiq_filter(pxmitframe))
pattrib->qsel = 0x11;/* HIQ */
return ret;
@@ -2455,7 +2453,7 @@ sint xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_fr
/* DBG_871X("enqueue, sq_len =%d, tim =%x\n", psta->sleepq_len, pstapriv->tim_bitmap); */
- if (update_tim == true) {
+ if (update_tim) {
update_beacon(padapter, _TIM_IE_, NULL, true);
} else {
chk_bmc_sleepq_cmd(padapter);
@@ -2521,7 +2519,7 @@ sint xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_fr
/* DBG_871X("enqueue, sq_len =%d, tim =%x\n", psta->sleepq_len, pstapriv->tim_bitmap); */
- if (update_tim == true)
+ if (update_tim)
/* DBG_871X("sleepq_len == 1, update BCNTIM\n"); */
/* upate BCN for TIM IE */
update_beacon(padapter, _TIM_IE_, NULL, true);
diff --git a/drivers/staging/rtl8723bs/hal/HalBtc8723b1Ant.c b/drivers/staging/rtl8723bs/hal/HalBtc8723b1Ant.c
index eb6e07ef5dad..8e4caeeb4070 100644
--- a/drivers/staging/rtl8723bs/hal/HalBtc8723b1Ant.c
+++ b/drivers/staging/rtl8723bs/hal/HalBtc8723b1Ant.c
@@ -1421,7 +1421,7 @@ static void halbtc8723b1ant_PsTdma(
if (bTurnOn) {
- if (pBtLinkInfo->bSlaveRole == true)
+ if (pBtLinkInfo->bSlaveRole)
psTdmaByte4Val = psTdmaByte4Val | 0x1; /* 0x778 = 0x1 at wifi slot (no blocking BT Low-Pri pkts) */
@@ -2337,9 +2337,9 @@ static void halbtc8723b1ant_ActionWifiConnected(PBTC_COEXIST pBtCoexist)
);
}
} else if (
- (pCoexSta->bPanExist == false) &&
- (pCoexSta->bA2dpExist == false) &&
- (pCoexSta->bHidExist == false)
+ (!pCoexSta->bPanExist) &&
+ (!pCoexSta->bA2dpExist) &&
+ (!pCoexSta->bHidExist)
)
halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0);
else
diff --git a/drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.c b/drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.c
index cb62fc0a0f9c..02da0a883594 100644
--- a/drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.c
+++ b/drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.c
@@ -7,6 +7,13 @@
#include "Mp_Precomp.h"
+/* defines */
+#define HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(val) \
+do { \
+ halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, val); \
+ pCoexDm->psTdmaDuAdjType = val; \
+} while (0)
+
/* Global variables, these are static variables */
static COEX_DM_8723B_2ANT GLCoexDm8723b2Ant;
static PCOEX_DM_8723B_2ANT pCoexDm = &GLCoexDm8723b2Ant;
@@ -1599,63 +1606,43 @@ static void halbtc8723b2ant_TdmaDurationAdjust(
{
if (bScoHid) {
if (bTxPause) {
- if (maxInterval == 1) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 13);
- pCoexDm->psTdmaDuAdjType = 13;
- } else if (maxInterval == 2) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14);
- pCoexDm->psTdmaDuAdjType = 14;
- } else if (maxInterval == 3) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
- pCoexDm->psTdmaDuAdjType = 15;
- } else {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
- pCoexDm->psTdmaDuAdjType = 15;
- }
+ if (maxInterval == 1)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(13);
+ else if (maxInterval == 2)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(14);
+ else if (maxInterval == 3)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
+ else
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
} else {
- if (maxInterval == 1) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 9);
- pCoexDm->psTdmaDuAdjType = 9;
- } else if (maxInterval == 2) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10);
- pCoexDm->psTdmaDuAdjType = 10;
- } else if (maxInterval == 3) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
- pCoexDm->psTdmaDuAdjType = 11;
- } else {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
- pCoexDm->psTdmaDuAdjType = 11;
- }
+ if (maxInterval == 1)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(9);
+ else if (maxInterval == 2)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(10);
+ else if (maxInterval == 3)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
+ else
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
}
} else {
if (bTxPause) {
- if (maxInterval == 1) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 5);
- pCoexDm->psTdmaDuAdjType = 5;
- } else if (maxInterval == 2) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6);
- pCoexDm->psTdmaDuAdjType = 6;
- } else if (maxInterval == 3) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
- pCoexDm->psTdmaDuAdjType = 7;
- } else {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
- pCoexDm->psTdmaDuAdjType = 7;
- }
+ if (maxInterval == 1)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(5);
+ else if (maxInterval == 2)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(6);
+ else if (maxInterval == 3)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
+ else
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
} else {
- if (maxInterval == 1) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 1);
- pCoexDm->psTdmaDuAdjType = 1;
- } else if (maxInterval == 2) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2);
- pCoexDm->psTdmaDuAdjType = 2;
- } else if (maxInterval == 3) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
- pCoexDm->psTdmaDuAdjType = 3;
- } else {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
- pCoexDm->psTdmaDuAdjType = 3;
- }
+ if (maxInterval == 1)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(1);
+ else if (maxInterval == 2)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(2);
+ else if (maxInterval == 3)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
+ else
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
}
}
}
@@ -1741,442 +1728,295 @@ static void halbtc8723b2ant_TdmaDurationAdjust(
if (bTxPause) {
BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 1\n"));
- if (pCoexDm->curPsTdma == 71) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 5);
- pCoexDm->psTdmaDuAdjType = 5;
- } else if (pCoexDm->curPsTdma == 1) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 5);
- pCoexDm->psTdmaDuAdjType = 5;
- } else if (pCoexDm->curPsTdma == 2) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6);
- pCoexDm->psTdmaDuAdjType = 6;
- } else if (pCoexDm->curPsTdma == 3) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
- pCoexDm->psTdmaDuAdjType = 7;
- } else if (pCoexDm->curPsTdma == 4) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 8);
- pCoexDm->psTdmaDuAdjType = 8;
- }
-
- if (pCoexDm->curPsTdma == 9) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 13);
- pCoexDm->psTdmaDuAdjType = 13;
- } else if (pCoexDm->curPsTdma == 10) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14);
- pCoexDm->psTdmaDuAdjType = 14;
- } else if (pCoexDm->curPsTdma == 11) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
- pCoexDm->psTdmaDuAdjType = 15;
- } else if (pCoexDm->curPsTdma == 12) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 16);
- pCoexDm->psTdmaDuAdjType = 16;
- }
+ if (pCoexDm->curPsTdma == 71)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(5);
+ else if (pCoexDm->curPsTdma == 1)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(5);
+ else if (pCoexDm->curPsTdma == 2)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(6);
+ else if (pCoexDm->curPsTdma == 3)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
+ else if (pCoexDm->curPsTdma == 4)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(8);
+
+ if (pCoexDm->curPsTdma == 9)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(13);
+ else if (pCoexDm->curPsTdma == 10)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(14);
+ else if (pCoexDm->curPsTdma == 11)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
+ else if (pCoexDm->curPsTdma == 12)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(16);
if (result == -1) {
- if (pCoexDm->curPsTdma == 5) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6);
- pCoexDm->psTdmaDuAdjType = 6;
- } else if (pCoexDm->curPsTdma == 6) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
- pCoexDm->psTdmaDuAdjType = 7;
- } else if (pCoexDm->curPsTdma == 7) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 8);
- pCoexDm->psTdmaDuAdjType = 8;
- } else if (pCoexDm->curPsTdma == 13) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14);
- pCoexDm->psTdmaDuAdjType = 14;
- } else if (pCoexDm->curPsTdma == 14) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
- pCoexDm->psTdmaDuAdjType = 15;
- } else if (pCoexDm->curPsTdma == 15) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 16);
- pCoexDm->psTdmaDuAdjType = 16;
- }
+ if (pCoexDm->curPsTdma == 5)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(6);
+ else if (pCoexDm->curPsTdma == 6)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
+ else if (pCoexDm->curPsTdma == 7)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(8);
+ else if (pCoexDm->curPsTdma == 13)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(14);
+ else if (pCoexDm->curPsTdma == 14)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
+ else if (pCoexDm->curPsTdma == 15)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(16);
} else if (result == 1) {
- if (pCoexDm->curPsTdma == 8) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
- pCoexDm->psTdmaDuAdjType = 7;
- } else if (pCoexDm->curPsTdma == 7) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6);
- pCoexDm->psTdmaDuAdjType = 6;
- } else if (pCoexDm->curPsTdma == 6) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 5);
- pCoexDm->psTdmaDuAdjType = 5;
- } else if (pCoexDm->curPsTdma == 16) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
- pCoexDm->psTdmaDuAdjType = 15;
- } else if (pCoexDm->curPsTdma == 15) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14);
- pCoexDm->psTdmaDuAdjType = 14;
- } else if (pCoexDm->curPsTdma == 14) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 13);
- pCoexDm->psTdmaDuAdjType = 13;
- }
+ if (pCoexDm->curPsTdma == 8)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
+ else if (pCoexDm->curPsTdma == 7)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(6);
+ else if (pCoexDm->curPsTdma == 6)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(5);
+ else if (pCoexDm->curPsTdma == 16)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
+ else if (pCoexDm->curPsTdma == 15)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(14);
+ else if (pCoexDm->curPsTdma == 14)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(13);
}
} else {
BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 0\n"));
- if (pCoexDm->curPsTdma == 5) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 71);
- pCoexDm->psTdmaDuAdjType = 71;
- } else if (pCoexDm->curPsTdma == 6) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2);
- pCoexDm->psTdmaDuAdjType = 2;
- } else if (pCoexDm->curPsTdma == 7) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
- pCoexDm->psTdmaDuAdjType = 3;
- } else if (pCoexDm->curPsTdma == 8) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 4);
- pCoexDm->psTdmaDuAdjType = 4;
- }
-
- if (pCoexDm->curPsTdma == 13) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 9);
- pCoexDm->psTdmaDuAdjType = 9;
- } else if (pCoexDm->curPsTdma == 14) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10);
- pCoexDm->psTdmaDuAdjType = 10;
- } else if (pCoexDm->curPsTdma == 15) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
- pCoexDm->psTdmaDuAdjType = 11;
- } else if (pCoexDm->curPsTdma == 16) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 12);
- pCoexDm->psTdmaDuAdjType = 12;
- }
+ if (pCoexDm->curPsTdma == 5)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(71);
+ else if (pCoexDm->curPsTdma == 6)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(2);
+ else if (pCoexDm->curPsTdma == 7)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
+ else if (pCoexDm->curPsTdma == 8)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(4);
+
+ if (pCoexDm->curPsTdma == 13)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(9);
+ else if (pCoexDm->curPsTdma == 14)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(10);
+ else if (pCoexDm->curPsTdma == 15)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
+ else if (pCoexDm->curPsTdma == 16)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(12);
if (result == -1) {
- if (pCoexDm->curPsTdma == 71) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 1);
- pCoexDm->psTdmaDuAdjType = 1;
- } else if (pCoexDm->curPsTdma == 1) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2);
- pCoexDm->psTdmaDuAdjType = 2;
- } else if (pCoexDm->curPsTdma == 2) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
- pCoexDm->psTdmaDuAdjType = 3;
- } else if (pCoexDm->curPsTdma == 3) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 4);
- pCoexDm->psTdmaDuAdjType = 4;
- } else if (pCoexDm->curPsTdma == 9) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10);
- pCoexDm->psTdmaDuAdjType = 10;
- } else if (pCoexDm->curPsTdma == 10) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
- pCoexDm->psTdmaDuAdjType = 11;
- } else if (pCoexDm->curPsTdma == 11) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 12);
- pCoexDm->psTdmaDuAdjType = 12;
- }
+ if (pCoexDm->curPsTdma == 71)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(1);
+ else if (pCoexDm->curPsTdma == 1)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(2);
+ else if (pCoexDm->curPsTdma == 2)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
+ else if (pCoexDm->curPsTdma == 3)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(4);
+ else if (pCoexDm->curPsTdma == 9)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(10);
+ else if (pCoexDm->curPsTdma == 10)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
+ else if (pCoexDm->curPsTdma == 11)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(12);
} else if (result == 1) {
- if (pCoexDm->curPsTdma == 4) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
- pCoexDm->psTdmaDuAdjType = 3;
- } else if (pCoexDm->curPsTdma == 3) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2);
- pCoexDm->psTdmaDuAdjType = 2;
- } else if (pCoexDm->curPsTdma == 2) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 1);
- pCoexDm->psTdmaDuAdjType = 1;
- } else if (pCoexDm->curPsTdma == 1) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 71);
- pCoexDm->psTdmaDuAdjType = 71;
- } else if (pCoexDm->curPsTdma == 12) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
- pCoexDm->psTdmaDuAdjType = 11;
- } else if (pCoexDm->curPsTdma == 11) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10);
- pCoexDm->psTdmaDuAdjType = 10;
- } else if (pCoexDm->curPsTdma == 10) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 9);
- pCoexDm->psTdmaDuAdjType = 9;
- }
+ if (pCoexDm->curPsTdma == 4)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
+ else if (pCoexDm->curPsTdma == 3)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(2);
+ else if (pCoexDm->curPsTdma == 2)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(1);
+ else if (pCoexDm->curPsTdma == 1)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(71);
+ else if (pCoexDm->curPsTdma == 12)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
+ else if (pCoexDm->curPsTdma == 11)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(10);
+ else if (pCoexDm->curPsTdma == 10)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(9);
}
}
} else if (maxInterval == 2) {
if (bTxPause) {
BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 1\n"));
- if (pCoexDm->curPsTdma == 1) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6);
- pCoexDm->psTdmaDuAdjType = 6;
- } else if (pCoexDm->curPsTdma == 2) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6);
- pCoexDm->psTdmaDuAdjType = 6;
- } else if (pCoexDm->curPsTdma == 3) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
- pCoexDm->psTdmaDuAdjType = 7;
- } else if (pCoexDm->curPsTdma == 4) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 8);
- pCoexDm->psTdmaDuAdjType = 8;
- }
-
- if (pCoexDm->curPsTdma == 9) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14);
- pCoexDm->psTdmaDuAdjType = 14;
- } else if (pCoexDm->curPsTdma == 10) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14);
- pCoexDm->psTdmaDuAdjType = 14;
- } else if (pCoexDm->curPsTdma == 11) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
- pCoexDm->psTdmaDuAdjType = 15;
- } else if (pCoexDm->curPsTdma == 12) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 16);
- pCoexDm->psTdmaDuAdjType = 16;
- }
+ if (pCoexDm->curPsTdma == 1)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(6);
+ else if (pCoexDm->curPsTdma == 2)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(6);
+ else if (pCoexDm->curPsTdma == 3)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
+ else if (pCoexDm->curPsTdma == 4)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(8);
+
+ if (pCoexDm->curPsTdma == 9)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(14);
+ else if (pCoexDm->curPsTdma == 10)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(14);
+ else if (pCoexDm->curPsTdma == 11)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
+ else if (pCoexDm->curPsTdma == 12)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(16);
if (result == -1) {
- if (pCoexDm->curPsTdma == 5) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6);
- pCoexDm->psTdmaDuAdjType = 6;
- } else if (pCoexDm->curPsTdma == 6) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
- pCoexDm->psTdmaDuAdjType = 7;
- } else if (pCoexDm->curPsTdma == 7) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 8);
- pCoexDm->psTdmaDuAdjType = 8;
- } else if (pCoexDm->curPsTdma == 13) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14);
- pCoexDm->psTdmaDuAdjType = 14;
- } else if (pCoexDm->curPsTdma == 14) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
- pCoexDm->psTdmaDuAdjType = 15;
- } else if (pCoexDm->curPsTdma == 15) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 16);
- pCoexDm->psTdmaDuAdjType = 16;
- }
+ if (pCoexDm->curPsTdma == 5)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(6);
+ else if (pCoexDm->curPsTdma == 6)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
+ else if (pCoexDm->curPsTdma == 7)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(8);
+ else if (pCoexDm->curPsTdma == 13)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(14);
+ else if (pCoexDm->curPsTdma == 14)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
+ else if (pCoexDm->curPsTdma == 15)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(16);
} else if (result == 1) {
- if (pCoexDm->curPsTdma == 8) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
- pCoexDm->psTdmaDuAdjType = 7;
- } else if (pCoexDm->curPsTdma == 7) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6);
- pCoexDm->psTdmaDuAdjType = 6;
- } else if (pCoexDm->curPsTdma == 6) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 6);
- pCoexDm->psTdmaDuAdjType = 6;
- } else if (pCoexDm->curPsTdma == 16) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
- pCoexDm->psTdmaDuAdjType = 15;
- } else if (pCoexDm->curPsTdma == 15) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14);
- pCoexDm->psTdmaDuAdjType = 14;
- } else if (pCoexDm->curPsTdma == 14) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 14);
- pCoexDm->psTdmaDuAdjType = 14;
- }
+ if (pCoexDm->curPsTdma == 8)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
+ else if (pCoexDm->curPsTdma == 7)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(6);
+ else if (pCoexDm->curPsTdma == 6)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(6);
+ else if (pCoexDm->curPsTdma == 16)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
+ else if (pCoexDm->curPsTdma == 15)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(14);
+ else if (pCoexDm->curPsTdma == 14)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(14);
}
} else {
BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 0\n"));
- if (pCoexDm->curPsTdma == 5) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2);
- pCoexDm->psTdmaDuAdjType = 2;
- } else if (pCoexDm->curPsTdma == 6) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2);
- pCoexDm->psTdmaDuAdjType = 2;
- } else if (pCoexDm->curPsTdma == 7) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
- pCoexDm->psTdmaDuAdjType = 3;
- } else if (pCoexDm->curPsTdma == 8) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 4);
- pCoexDm->psTdmaDuAdjType = 4;
- }
-
- if (pCoexDm->curPsTdma == 13) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10);
- pCoexDm->psTdmaDuAdjType = 10;
- } else if (pCoexDm->curPsTdma == 14) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10);
- pCoexDm->psTdmaDuAdjType = 10;
- } else if (pCoexDm->curPsTdma == 15) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
- pCoexDm->psTdmaDuAdjType = 11;
- } else if (pCoexDm->curPsTdma == 16) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 12);
- pCoexDm->psTdmaDuAdjType = 12;
- }
+ if (pCoexDm->curPsTdma == 5)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(2);
+ else if (pCoexDm->curPsTdma == 6)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(2);
+ else if (pCoexDm->curPsTdma == 7)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
+ else if (pCoexDm->curPsTdma == 8)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(4);
+
+ if (pCoexDm->curPsTdma == 13)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(10);
+ else if (pCoexDm->curPsTdma == 14)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(10);
+ else if (pCoexDm->curPsTdma == 15)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
+ else if (pCoexDm->curPsTdma == 16)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(12);
if (result == -1) {
- if (pCoexDm->curPsTdma == 1) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2);
- pCoexDm->psTdmaDuAdjType = 2;
- } else if (pCoexDm->curPsTdma == 2) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
- pCoexDm->psTdmaDuAdjType = 3;
- } else if (pCoexDm->curPsTdma == 3) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 4);
- pCoexDm->psTdmaDuAdjType = 4;
- } else if (pCoexDm->curPsTdma == 9) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10);
- pCoexDm->psTdmaDuAdjType = 10;
- } else if (pCoexDm->curPsTdma == 10) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
- pCoexDm->psTdmaDuAdjType = 11;
- } else if (pCoexDm->curPsTdma == 11) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 12);
- pCoexDm->psTdmaDuAdjType = 12;
- }
+ if (pCoexDm->curPsTdma == 1)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(2);
+ else if (pCoexDm->curPsTdma == 2)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
+ else if (pCoexDm->curPsTdma == 3)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(4);
+ else if (pCoexDm->curPsTdma == 9)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(10);
+ else if (pCoexDm->curPsTdma == 10)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
+ else if (pCoexDm->curPsTdma == 11)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(12);
} else if (result == 1) {
- if (pCoexDm->curPsTdma == 4) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
- pCoexDm->psTdmaDuAdjType = 3;
- } else if (pCoexDm->curPsTdma == 3) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2);
- pCoexDm->psTdmaDuAdjType = 2;
- } else if (pCoexDm->curPsTdma == 2) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2);
- pCoexDm->psTdmaDuAdjType = 2;
- } else if (pCoexDm->curPsTdma == 12) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
- pCoexDm->psTdmaDuAdjType = 11;
- } else if (pCoexDm->curPsTdma == 11) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10);
- pCoexDm->psTdmaDuAdjType = 10;
- } else if (pCoexDm->curPsTdma == 10) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 10);
- pCoexDm->psTdmaDuAdjType = 10;
- }
+ if (pCoexDm->curPsTdma == 4)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
+ else if (pCoexDm->curPsTdma == 3)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(2);
+ else if (pCoexDm->curPsTdma == 2)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(2);
+ else if (pCoexDm->curPsTdma == 12)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
+ else if (pCoexDm->curPsTdma == 11)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(10);
+ else if (pCoexDm->curPsTdma == 10)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(10);
}
}
} else if (maxInterval == 3) {
if (bTxPause) {
BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 1\n"));
- if (pCoexDm->curPsTdma == 1) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
- pCoexDm->psTdmaDuAdjType = 7;
- } else if (pCoexDm->curPsTdma == 2) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
- pCoexDm->psTdmaDuAdjType = 7;
- } else if (pCoexDm->curPsTdma == 3) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
- pCoexDm->psTdmaDuAdjType = 7;
- } else if (pCoexDm->curPsTdma == 4) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 8);
- pCoexDm->psTdmaDuAdjType = 8;
- }
-
- if (pCoexDm->curPsTdma == 9) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
- pCoexDm->psTdmaDuAdjType = 15;
- } else if (pCoexDm->curPsTdma == 10) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
- pCoexDm->psTdmaDuAdjType = 15;
- } else if (pCoexDm->curPsTdma == 11) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
- pCoexDm->psTdmaDuAdjType = 15;
- } else if (pCoexDm->curPsTdma == 12) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 16);
- pCoexDm->psTdmaDuAdjType = 16;
- }
+ if (pCoexDm->curPsTdma == 1)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
+ else if (pCoexDm->curPsTdma == 2)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
+ else if (pCoexDm->curPsTdma == 3)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
+ else if (pCoexDm->curPsTdma == 4)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(8);
+
+ if (pCoexDm->curPsTdma == 9)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
+ else if (pCoexDm->curPsTdma == 10)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
+ else if (pCoexDm->curPsTdma == 11)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
+ else if (pCoexDm->curPsTdma == 12)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(16);
if (result == -1) {
- if (pCoexDm->curPsTdma == 5) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
- pCoexDm->psTdmaDuAdjType = 7;
- } else if (pCoexDm->curPsTdma == 6) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
- pCoexDm->psTdmaDuAdjType = 7;
- } else if (pCoexDm->curPsTdma == 7) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 8);
- pCoexDm->psTdmaDuAdjType = 8;
- } else if (pCoexDm->curPsTdma == 13) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
- pCoexDm->psTdmaDuAdjType = 15;
- } else if (pCoexDm->curPsTdma == 14) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
- pCoexDm->psTdmaDuAdjType = 15;
- } else if (pCoexDm->curPsTdma == 15) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 16);
- pCoexDm->psTdmaDuAdjType = 16;
- }
+ if (pCoexDm->curPsTdma == 5)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
+ else if (pCoexDm->curPsTdma == 6)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
+ else if (pCoexDm->curPsTdma == 7)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(8);
+ else if (pCoexDm->curPsTdma == 13)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
+ else if (pCoexDm->curPsTdma == 14)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
+ else if (pCoexDm->curPsTdma == 15)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(16);
} else if (result == 1) {
- if (pCoexDm->curPsTdma == 8) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
- pCoexDm->psTdmaDuAdjType = 7;
- } else if (pCoexDm->curPsTdma == 7) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
- pCoexDm->psTdmaDuAdjType = 7;
- } else if (pCoexDm->curPsTdma == 6) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 7);
- pCoexDm->psTdmaDuAdjType = 7;
- } else if (pCoexDm->curPsTdma == 16) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
- pCoexDm->psTdmaDuAdjType = 15;
- } else if (pCoexDm->curPsTdma == 15) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
- pCoexDm->psTdmaDuAdjType = 15;
- } else if (pCoexDm->curPsTdma == 14) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 15);
- pCoexDm->psTdmaDuAdjType = 15;
- }
+ if (pCoexDm->curPsTdma == 8)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
+ else if (pCoexDm->curPsTdma == 7)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
+ else if (pCoexDm->curPsTdma == 6)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
+ else if (pCoexDm->curPsTdma == 16)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
+ else if (pCoexDm->curPsTdma == 15)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
+ else if (pCoexDm->curPsTdma == 14)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
}
} else {
BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 0\n"));
- if (pCoexDm->curPsTdma == 5) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
- pCoexDm->psTdmaDuAdjType = 3;
- } else if (pCoexDm->curPsTdma == 6) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
- pCoexDm->psTdmaDuAdjType = 3;
- } else if (pCoexDm->curPsTdma == 7) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
- pCoexDm->psTdmaDuAdjType = 3;
- } else if (pCoexDm->curPsTdma == 8) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 4);
- pCoexDm->psTdmaDuAdjType = 4;
- }
-
- if (pCoexDm->curPsTdma == 13) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
- pCoexDm->psTdmaDuAdjType = 11;
- } else if (pCoexDm->curPsTdma == 14) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
- pCoexDm->psTdmaDuAdjType = 11;
- } else if (pCoexDm->curPsTdma == 15) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
- pCoexDm->psTdmaDuAdjType = 11;
- } else if (pCoexDm->curPsTdma == 16) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 12);
- pCoexDm->psTdmaDuAdjType = 12;
- }
+ if (pCoexDm->curPsTdma == 5)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
+ else if (pCoexDm->curPsTdma == 6)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
+ else if (pCoexDm->curPsTdma == 7)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
+ else if (pCoexDm->curPsTdma == 8)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(4);
+
+ if (pCoexDm->curPsTdma == 13)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
+ else if (pCoexDm->curPsTdma == 14)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
+ else if (pCoexDm->curPsTdma == 15)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
+ else if (pCoexDm->curPsTdma == 16)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(12);
if (result == -1) {
- if (pCoexDm->curPsTdma == 1) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
- pCoexDm->psTdmaDuAdjType = 3;
- } else if (pCoexDm->curPsTdma == 2) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
- pCoexDm->psTdmaDuAdjType = 3;
- } else if (pCoexDm->curPsTdma == 3) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 4);
- pCoexDm->psTdmaDuAdjType = 4;
- } else if (pCoexDm->curPsTdma == 9) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
- pCoexDm->psTdmaDuAdjType = 11;
- } else if (pCoexDm->curPsTdma == 10) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
- pCoexDm->psTdmaDuAdjType = 11;
- } else if (pCoexDm->curPsTdma == 11) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 12);
- pCoexDm->psTdmaDuAdjType = 12;
- }
+ if (pCoexDm->curPsTdma == 1)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
+ else if (pCoexDm->curPsTdma == 2)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
+ else if (pCoexDm->curPsTdma == 3)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(4);
+ else if (pCoexDm->curPsTdma == 9)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
+ else if (pCoexDm->curPsTdma == 10)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
+ else if (pCoexDm->curPsTdma == 11)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(12);
} else if (result == 1) {
- if (pCoexDm->curPsTdma == 4) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
- pCoexDm->psTdmaDuAdjType = 3;
- } else if (pCoexDm->curPsTdma == 3) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
- pCoexDm->psTdmaDuAdjType = 3;
- } else if (pCoexDm->curPsTdma == 2) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 3);
- pCoexDm->psTdmaDuAdjType = 3;
- } else if (pCoexDm->curPsTdma == 12) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
- pCoexDm->psTdmaDuAdjType = 11;
- } else if (pCoexDm->curPsTdma == 11) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
- pCoexDm->psTdmaDuAdjType = 11;
- } else if (pCoexDm->curPsTdma == 10) {
- halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 11);
- pCoexDm->psTdmaDuAdjType = 11;
- }
+ if (pCoexDm->curPsTdma == 4)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
+ else if (pCoexDm->curPsTdma == 3)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
+ else if (pCoexDm->curPsTdma == 2)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
+ else if (pCoexDm->curPsTdma == 12)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
+ else if (pCoexDm->curPsTdma == 11)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
+ else if (pCoexDm->curPsTdma == 10)
+ HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(11);
}
}
}
diff --git a/drivers/staging/rtl8723bs/hal/HalHWImg8723B_BB.c b/drivers/staging/rtl8723bs/hal/HalHWImg8723B_BB.c
index bae59e515348..19856e806b1f 100644
--- a/drivers/staging/rtl8723bs/hal/HalHWImg8723B_BB.c
+++ b/drivers/staging/rtl8723bs/hal/HalHWImg8723B_BB.c
@@ -299,7 +299,7 @@ void ODM_ReadAndConfig_MP_8723B_AGC_TAB(PDM_ODM_T pDM_Odm)
READ_NEXT_PAIR(v1, v2, i);
}
- if (bMatched == false) {
+ if (!bMatched) {
/* Condition isn't matched.
* Discard the following (offset, data) pairs.
*/
@@ -568,7 +568,7 @@ void ODM_ReadAndConfig_MP_8723B_PHY_REG(PDM_ODM_T pDM_Odm)
READ_NEXT_PAIR(v1, v2, i);
}
- if (bMatched == false) {
+ if (!bMatched) {
/* Condition isn't matched.
* Discard the following (offset, data) pairs.
*/
diff --git a/drivers/staging/rtl8723bs/hal/HalHWImg8723B_MAC.c b/drivers/staging/rtl8723bs/hal/HalHWImg8723B_MAC.c
index 3c8e26aba406..b80c5b11796b 100644
--- a/drivers/staging/rtl8723bs/hal/HalHWImg8723B_MAC.c
+++ b/drivers/staging/rtl8723bs/hal/HalHWImg8723B_MAC.c
@@ -270,7 +270,7 @@ void ODM_ReadAndConfig_MP_8723B_MAC_REG(PDM_ODM_T pDM_Odm)
READ_NEXT_PAIR(v1, v2, i);
}
- if (bMatched == false) {
+ if (!bMatched) {
/* Condition isn't matched. Discard the following (offset, data) pairs. */
while (v1 < 0x40000000 && i < ArrayLen-2)
READ_NEXT_PAIR(v1, v2, i);
diff --git a/drivers/staging/rtl8723bs/hal/HalHWImg8723B_RF.c b/drivers/staging/rtl8723bs/hal/HalHWImg8723B_RF.c
index ba42b4d2a9c4..426f68b8f0d2 100644
--- a/drivers/staging/rtl8723bs/hal/HalHWImg8723B_RF.c
+++ b/drivers/staging/rtl8723bs/hal/HalHWImg8723B_RF.c
@@ -301,7 +301,7 @@ void ODM_ReadAndConfig_MP_8723B_RadioA(PDM_ODM_T pDM_Odm)
READ_NEXT_PAIR(v1, v2, i);
}
- if (bMatched == false) {
+ if (!bMatched) {
/* Condition isn't matched.
* Discard the following (offset, data) pairs.
*/
diff --git a/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.c b/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.c
index 53d3bdf21a6f..3239d37087c8 100644
--- a/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.c
+++ b/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.c
@@ -1292,7 +1292,7 @@ static void _PHY_SaveADDARegisters8723B(
struct hal_com_data *pHalData = GET_HAL_DATA(padapter);
PDM_ODM_T pDM_Odm = &pHalData->odmpriv;
- if (ODM_CheckPowerStatus(padapter) == false)
+ if (!ODM_CheckPowerStatus(padapter))
return;
ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Save ADDA parameters.\n"));
@@ -1363,7 +1363,7 @@ static void _PHY_PathADDAOn8723B(
ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("ADDA ON.\n"));
pathOn = 0x01c00014;
- if (false == is2T) {
+ if (!is2T) {
pathOn = 0x01c00014;
PHY_SetBBReg(pDM_Odm->Adapter, ADDAReg[0], bMaskDWord, 0x01c00014);
} else {
@@ -1811,7 +1811,7 @@ void PHY_IQCalibrate_8723B(
u32 StartTime;
s32 ProgressingTime;
- if (ODM_CheckPowerStatus(padapter) == false)
+ if (!ODM_CheckPowerStatus(padapter))
return;
if (!(pDM_Odm->SupportAbility & ODM_RF_CALIBRATION))
diff --git a/drivers/staging/rtl8723bs/hal/hal_btcoex.c b/drivers/staging/rtl8723bs/hal/hal_btcoex.c
index 6caddd7834a1..5257287b4f4d 100644
--- a/drivers/staging/rtl8723bs/hal/hal_btcoex.c
+++ b/drivers/staging/rtl8723bs/hal/hal_btcoex.c
@@ -112,9 +112,9 @@ void DBG_BT_INFO(u8 *dbgmsg)
/* */
static u8 halbtcoutsrc_IsBtCoexistAvailable(PBTC_COEXIST pBtCoexist)
{
- if (!pBtCoexist->bBinded || !pBtCoexist->Adapter){
+ if (!pBtCoexist->bBinded || !pBtCoexist->Adapter)
return false;
- }
+
return true;
}
@@ -195,7 +195,6 @@ static void halbtcoutsrc_NormalLps(PBTC_COEXIST pBtCoexist)
static void halbtcoutsrc_LeaveLowPower(PBTC_COEXIST pBtCoexist)
{
struct adapter *padapter;
- struct hal_com_data *pHalData;
s32 ready;
unsigned long stime;
unsigned long utime;
@@ -203,7 +202,6 @@ static void halbtcoutsrc_LeaveLowPower(PBTC_COEXIST pBtCoexist)
padapter = pBtCoexist->Adapter;
- pHalData = GET_HAL_DATA(padapter);
ready = _FAIL;
#ifdef LPS_RPWM_WAIT_MS
timeout = LPS_RPWM_WAIT_MS;
@@ -256,13 +254,11 @@ static void halbtcoutsrc_AggregationCheck(PBTC_COEXIST pBtCoexist)
padapter = pBtCoexist->Adapter;
bNeedToAct = false;
- if (pBtCoexist->btInfo.bRejectAggPkt)
+ if (pBtCoexist->btInfo.bRejectAggPkt) {
rtw_btcoex_RejectApAggregatedPacket(padapter, true);
- else {
-
+ } else {
if (pBtCoexist->btInfo.bPreBtCtrlAggBufSize !=
- pBtCoexist->btInfo.bBtCtrlAggBufSize){
-
+ pBtCoexist->btInfo.bBtCtrlAggBufSize) {
bNeedToAct = true;
pBtCoexist->btInfo.bPreBtCtrlAggBufSize = pBtCoexist->btInfo.bBtCtrlAggBufSize;
}
@@ -292,7 +288,7 @@ static u8 halbtcoutsrc_IsWifiBusy(struct adapter *padapter)
if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE) == true) {
if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true)
return true;
- if (true == pmlmepriv->LinkDetectInfo.bBusyTraffic)
+ if (pmlmepriv->LinkDetectInfo.bBusyTraffic)
return true;
}
@@ -312,12 +308,12 @@ static u32 _halbtcoutsrc_GetWifiLinkStatus(struct adapter *padapter)
if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE) == true) {
if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) {
- if (true == bp2p)
+ if (bp2p)
portConnectedStatus |= WIFI_P2P_GO_CONNECTED;
else
portConnectedStatus |= WIFI_AP_CONNECTED;
} else {
- if (true == bp2p)
+ if (bp2p)
portConnectedStatus |= WIFI_P2P_GC_CONNECTED;
else
portConnectedStatus |= WIFI_STA_CONNECTED;
@@ -362,15 +358,9 @@ static u32 halbtcoutsrc_GetBtPatchVer(PBTC_COEXIST pBtCoexist)
static s32 halbtcoutsrc_GetWifiRssi(struct adapter *padapter)
{
- struct hal_com_data *pHalData;
- s32 UndecoratedSmoothedPWDB = 0;
+ struct hal_com_data *pHalData = GET_HAL_DATA(padapter);
-
- pHalData = GET_HAL_DATA(padapter);
-
- UndecoratedSmoothedPWDB = pHalData->dmpriv.EntryMinUndecoratedSmoothedPWDB;
-
- return UndecoratedSmoothedPWDB;
+ return pHalData->dmpriv.EntryMinUndecoratedSmoothedPWDB;
}
static u8 halbtcoutsrc_GetWifiScanAPNum(struct adapter *padapter)
@@ -380,7 +370,7 @@ static u8 halbtcoutsrc_GetWifiScanAPNum(struct adapter *padapter)
pmlmeext = &padapter->mlmeextpriv;
- if (GLBtcWiFiInScanState == false) {
+ if (!GLBtcWiFiInScanState) {
if (pmlmeext->sitesurvey_res.bss_cnt > 0xFF)
scan_AP_num = 0xFF;
else
@@ -566,18 +556,14 @@ static u8 halbtcoutsrc_Set(void *pBtcContext, u8 setType, void *pInBuf)
{
PBTC_COEXIST pBtCoexist;
struct adapter *padapter;
- struct hal_com_data *pHalData;
u8 *pu8;
- u8 *pU1Tmp;
u32 *pU4Tmp;
u8 ret;
pBtCoexist = (PBTC_COEXIST)pBtcContext;
padapter = pBtCoexist->Adapter;
- pHalData = GET_HAL_DATA(padapter);
pu8 = pInBuf;
- pU1Tmp = pInBuf;
pU4Tmp = pInBuf;
ret = true;
@@ -620,11 +606,11 @@ static u8 halbtcoutsrc_Set(void *pBtcContext, u8 setType, void *pInBuf)
/* set some u8 type variables. */
case BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON:
- pBtCoexist->btInfo.rssiAdjustForAgcTableOn = *pU1Tmp;
+ pBtCoexist->btInfo.rssiAdjustForAgcTableOn = *pu8;
break;
case BTC_SET_U1_AGG_BUF_SIZE:
- pBtCoexist->btInfo.aggBufSize = *pU1Tmp;
+ pBtCoexist->btInfo.aggBufSize = *pu8;
break;
/* the following are some action which will be triggered */
@@ -639,15 +625,15 @@ static u8 halbtcoutsrc_Set(void *pBtcContext, u8 setType, void *pInBuf)
/* 1Ant =========== */
/* set some u8 type variables. */
case BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE:
- pBtCoexist->btInfo.rssiAdjustFor1AntCoexType = *pU1Tmp;
+ pBtCoexist->btInfo.rssiAdjustFor1AntCoexType = *pu8;
break;
case BTC_SET_U1_LPS_VAL:
- pBtCoexist->btInfo.lpsVal = *pU1Tmp;
+ pBtCoexist->btInfo.lpsVal = *pu8;
break;
case BTC_SET_U1_RPWM_VAL:
- pBtCoexist->btInfo.rpwmVal = *pU1Tmp;
+ pBtCoexist->btInfo.rpwmVal = *pu8;
break;
/* the following are some action which will be triggered */
@@ -822,11 +808,10 @@ static void halbtcoutsrc_WriteLocalReg1Byte(void *pBtcContext, u32 RegAddr, u8 D
PBTC_COEXIST pBtCoexist = (PBTC_COEXIST)pBtcContext;
struct adapter *Adapter = pBtCoexist->Adapter;
- if (BTC_INTF_SDIO == pBtCoexist->chipInterface) {
+ if (BTC_INTF_SDIO == pBtCoexist->chipInterface)
rtw_write8(Adapter, SDIO_LOCAL_BASE | RegAddr, Data);
- } else {
+ else
rtw_write8(Adapter, RegAddr, Data);
- }
}
static void halbtcoutsrc_SetBbReg(void *pBtcContext, u32 RegAddr, u32 BitMask, u32 Data)
@@ -1202,14 +1187,13 @@ void EXhalbtcoutsrc_SpecialPacketNotify(PBTC_COEXIST pBtCoexist, u8 pktType)
if (pBtCoexist->bManualControl)
return;
- if (PACKET_DHCP == pktType)
+ if (PACKET_DHCP == pktType) {
packetType = BTC_PACKET_DHCP;
- else if (PACKET_EAPOL == pktType)
+ } else if (PACKET_EAPOL == pktType) {
packetType = BTC_PACKET_EAPOL;
- else if (PACKET_ARP == pktType)
+ } else if (PACKET_ARP == pktType) {
packetType = BTC_PACKET_ARP;
- else {
- packetType = BTC_PACKET_UNKNOWN;
+ } else {
return;
}
@@ -1362,7 +1346,7 @@ u8 hal_btcoex_IsBtExist(struct adapter *padapter)
return pHalData->bt_coexist.bBtExist;
}
-u8 hal_btcoex_IsBtDisabled(struct adapter *padapter)
+bool hal_btcoex_IsBtDisabled(struct adapter *padapter)
{
if (!hal_btcoex_IsBtExist(padapter))
return true;
@@ -1457,7 +1441,7 @@ void hal_btcoex_IQKNotify(struct adapter *padapter, u8 state)
void hal_btcoex_BtInfoNotify(struct adapter *padapter, u8 length, u8 *tmpBuf)
{
- if (GLBtcWiFiInIQKState == true)
+ if (GLBtcWiFiInIQKState)
return;
EXhalbtcoutsrc_BtInfoNotify(&GLBtCoexist, tmpBuf, length);
@@ -1478,7 +1462,7 @@ void hal_btcoex_HaltNotify(struct adapter *padapter)
EXhalbtcoutsrc_HaltNotify(&GLBtCoexist);
}
-void hal_btcoex_Hanlder(struct adapter *padapter)
+void hal_btcoex_Handler(struct adapter *padapter)
{
EXhalbtcoutsrc_Periodical(&GLBtCoexist);
}
diff --git a/drivers/staging/rtl8723bs/hal/hal_com.c b/drivers/staging/rtl8723bs/hal/hal_com.c
index e5f1153527b9..638b12ae6ee9 100644
--- a/drivers/staging/rtl8723bs/hal/hal_com.c
+++ b/drivers/staging/rtl8723bs/hal/hal_com.c
@@ -125,7 +125,7 @@ u8 hal_com_config_channel_plan(
if (0xFF == hw_channel_plan)
AutoLoadFail = true;
- if (false == AutoLoadFail) {
+ if (!AutoLoadFail) {
u8 hw_chnlPlan;
hw_chnlPlan = hw_channel_plan & (~EEPROM_CHANNEL_PLAN_BY_HW_MASK);
@@ -963,12 +963,6 @@ exit:
return ret;
}
-
-u8 rtw_hal_networktype_to_raid(struct adapter *adapter, struct sta_info *psta)
-{
- return networktype_to_raid_ex(adapter, psta);
-}
-
u8 rtw_get_mgntframe_raid(struct adapter *adapter, unsigned char network_type)
{
diff --git a/drivers/staging/rtl8723bs/hal/hal_intf.c b/drivers/staging/rtl8723bs/hal/hal_intf.c
index 4a4d17b44ba6..acb25978a46c 100644
--- a/drivers/staging/rtl8723bs/hal/hal_intf.c
+++ b/drivers/staging/rtl8723bs/hal/hal_intf.c
@@ -400,11 +400,6 @@ bool rtw_hal_c2h_valid(struct adapter *adapter, u8 *buf)
return c2h_evt_valid((struct c2h_evt_hdr_88xx *)buf);
}
-s32 rtw_hal_c2h_evt_read(struct adapter *adapter, u8 *buf)
-{
- return c2h_evt_read_88xx(adapter, buf);
-}
-
s32 rtw_hal_c2h_handler(struct adapter *adapter, u8 *c2h_evt)
{
s32 ret = _FAIL;
diff --git a/drivers/staging/rtl8723bs/hal/hal_phy.c b/drivers/staging/rtl8723bs/hal/hal_phy.c
index ebaefcaf5f2a..24a9d8f783f0 100644
--- a/drivers/staging/rtl8723bs/hal/hal_phy.c
+++ b/drivers/staging/rtl8723bs/hal/hal_phy.c
@@ -8,30 +8,6 @@
#include <drv_types.h>
-/**
-* Function: PHY_CalculateBitShift
-*
-* OverView: Get shifted position of the BitMask
-*
-* Input:
-* u32 BitMask,
-*
-* Output: none
-* Return: u32 Return the shift bit bit position of the mask
-*/
-u32 PHY_CalculateBitShift(u32 BitMask)
-{
- u32 i;
-
- for (i = 0; i <= 31; i++) {
- if (((BitMask>>i) & 0x1) == 1)
- break;
- }
-
- return i;
-}
-
-
/* */
/* ==> RF shadow Operation API Code Section!!! */
/* */
@@ -179,38 +155,3 @@ void PHY_RFShadowCompareFlagSetAll(IN PADAPTER Adapter)
}
} /* PHY_RFShadowCompareFlagSetAll */
-
-
-void PHY_RFShadowRecorverFlagSetAll(IN PADAPTER Adapter)
-{
- u8 eRFPath = 0;
- u32 Offset = 0, maxReg = GET_RF6052_REAL_MAX_REG(Adapter);
-
- for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) {
- for (Offset = 0; Offset < maxReg; Offset++) {
- /* 2008/11/20 MH For S3S4 test, we only check reg 26/27 now!!!! */
- if (Offset != 0x26 && Offset != 0x27)
- PHY_RFShadowRecorverFlagSet(Adapter, eRFPath, Offset, false);
- else
- PHY_RFShadowRecorverFlagSet(Adapter, eRFPath, Offset, true);
- }
- }
-
-} /* PHY_RFShadowCompareFlagSetAll */
-
-void PHY_RFShadowRefresh(IN PADAPTER Adapter)
-{
- u8 eRFPath = 0;
- u32 Offset = 0, maxReg = GET_RF6052_REAL_MAX_REG(Adapter);
-
- for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) {
- for (Offset = 0; Offset < maxReg; Offset++) {
- RF_Shadow[eRFPath][Offset].Value = 0;
- RF_Shadow[eRFPath][Offset].Compare = false;
- RF_Shadow[eRFPath][Offset].Recorver = false;
- RF_Shadow[eRFPath][Offset].ErrorOrNot = false;
- RF_Shadow[eRFPath][Offset].Driver_Write = false;
- }
- }
-
-} /* PHY_RFShadowRead */
diff --git a/drivers/staging/rtl8723bs/hal/odm_AntDiv.c b/drivers/staging/rtl8723bs/hal/odm_AntDiv.c
deleted file mode 100644
index d5415eecdd7f..000000000000
--- a/drivers/staging/rtl8723bs/hal/odm_AntDiv.c
+++ /dev/null
@@ -1,62 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
- *
- ******************************************************************************/
-
-//============================================================
-// include files
-//============================================================
-
-#include "odm_precomp.h"
-
-//======================================================
-// when antenna test utility is on or some testing
-// need to disable antenna diversity
-// call this function to disable all ODM related mechanisms
-// which will switch antenna.
-//======================================================
-void ODM_StopAntennaSwitchDm(PDM_ODM_T pDM_Odm)
-{
- // disable ODM antenna diversity
- pDM_Odm->SupportAbility &= ~ODM_BB_ANT_DIV;
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_ANT_DIV,
- ODM_DBG_LOUD,
- ("STOP Antenna Diversity\n")
- );
-}
-
-void ODM_SetAntConfig(PDM_ODM_T pDM_Odm, u8 antSetting)// 0=A, 1=B, 2=C, ....
-{
- if (antSetting == 0) // ant A
- PHY_SetBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord, 0x00000000);
- else if (antSetting == 1)
- PHY_SetBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord, 0x00000280);
-}
-
-//======================================================
-
-
-void ODM_SwAntDivRestAfterLink(PDM_ODM_T pDM_Odm)
-{
- pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table;
- pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable;
- u32 i;
-
- pDM_Odm->RSSI_test = false;
- pDM_SWAT_Table->try_flag = 0xff;
- pDM_SWAT_Table->RSSI_Trying = 0;
- pDM_SWAT_Table->Double_chk_flag = 0;
-
- pDM_FatTable->RxIdleAnt = MAIN_ANT;
-
- for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) {
- pDM_FatTable->MainAnt_Sum[i] = 0;
- pDM_FatTable->AuxAnt_Sum[i] = 0;
- pDM_FatTable->MainAnt_Cnt[i] = 0;
- pDM_FatTable->AuxAnt_Cnt[i] = 0;
- }
-}
diff --git a/drivers/staging/rtl8723bs/hal/odm_AntDiv.h b/drivers/staging/rtl8723bs/hal/odm_AntDiv.h
deleted file mode 100644
index c9496d561c91..000000000000
--- a/drivers/staging/rtl8723bs/hal/odm_AntDiv.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
- *
- ******************************************************************************/
-
-#ifndef __ODMANTDIV_H__
-#define __ODMANTDIV_H__
-
-
-
-#define ANT1_2G 0 /* = ANT2_5G */
-#define ANT2_2G 1 /* = ANT1_5G */
-
-/* Antenna Diversty Control Type */
-#define ODM_AUTO_ANT 0
-#define ODM_FIX_MAIN_ANT 1
-#define ODM_FIX_AUX_ANT 2
-
-#define TX_BY_REG 0
-
-#define ANTDIV_ON 1
-#define ANTDIV_OFF 0
-
-#define INIT_ANTDIV_TIMMER 0
-#define CANCEL_ANTDIV_TIMMER 1
-#define RELEASE_ANTDIV_TIMMER 2
-
-#endif /* ifndef __ODMANTDIV_H__ */
diff --git a/drivers/staging/rtl8723bs/hal/odm_DIG.c b/drivers/staging/rtl8723bs/hal/odm_DIG.c
index 4fa6cd315cf7..70d98c58ca97 100644
--- a/drivers/staging/rtl8723bs/hal/odm_DIG.c
+++ b/drivers/staging/rtl8723bs/hal/odm_DIG.c
@@ -496,13 +496,8 @@ void odm_DIGInit(void *pDM_VOID)
/* To Initi BT30 IGI */
pDM_DigTable->BT30_CurIGI = 0x32;
- if (pDM_Odm->BoardType & (ODM_BOARD_EXT_PA|ODM_BOARD_EXT_LNA)) {
- pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC;
- pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC;
- } else {
- pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC;
- pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC;
- }
+ pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC;
+ pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC;
}
@@ -525,7 +520,7 @@ void odm_DIG(void *pDM_VOID)
bool bDFSBand = false;
bool bPerformance = true, bFirstTpTarget = false, bFirstCoverage = false;
- if (odm_DigAbort(pDM_Odm) == true)
+ if (odm_DigAbort(pDM_Odm))
return;
ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() ===========================>\n\n"));
diff --git a/drivers/staging/rtl8723bs/hal/odm_HWConfig.c b/drivers/staging/rtl8723bs/hal/odm_HWConfig.c
index d802a1fde58f..49fa814068b8 100644
--- a/drivers/staging/rtl8723bs/hal/odm_HWConfig.c
+++ b/drivers/staging/rtl8723bs/hal/odm_HWConfig.c
@@ -23,7 +23,7 @@ static u8 odm_QueryRxPwrPercentage(s8 AntPower)
}
-static s32 odm_SignalScaleMapping_92CSeries(PDM_ODM_T pDM_Odm, s32 CurrSig)
+s32 odm_SignalScaleMapping(PDM_ODM_T pDM_Odm, s32 CurrSig)
{
s32 RetSig = 0;
@@ -49,11 +49,6 @@ static s32 odm_SignalScaleMapping_92CSeries(PDM_ODM_T pDM_Odm, s32 CurrSig)
return RetSig;
}
-s32 odm_SignalScaleMapping(PDM_ODM_T pDM_Odm, s32 CurrSig)
-{
- return odm_SignalScaleMapping_92CSeries(pDM_Odm, CurrSig);
-}
-
static u8 odm_EVMdbToPercentage(s8 Value)
{
/* */
@@ -496,32 +491,3 @@ HAL_STATUS ODM_ConfigBBWithHeaderFile(
return HAL_STATUS_SUCCESS;
}
-HAL_STATUS ODM_ConfigMACWithHeaderFile(PDM_ODM_T pDM_Odm)
-{
- u8 result = HAL_STATUS_SUCCESS;
-
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_INIT,
- ODM_DBG_LOUD,
- (
- "===>ODM_ConfigMACWithHeaderFile (%s)\n",
- (pDM_Odm->bIsMPChip) ? "MPChip" : "TestChip"
- )
- );
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_INIT,
- ODM_DBG_LOUD,
- (
- "pDM_Odm->SupportPlatform: 0x%X, pDM_Odm->SupportInterface: 0x%X, pDM_Odm->BoardType: 0x%X\n",
- pDM_Odm->SupportPlatform,
- pDM_Odm->SupportInterface,
- pDM_Odm->BoardType
- )
- );
-
- READ_AND_CONFIG(8723B, _MAC_REG);
-
- return result;
-}
diff --git a/drivers/staging/rtl8723bs/hal/odm_HWConfig.h b/drivers/staging/rtl8723bs/hal/odm_HWConfig.h
index d3af1caaa73c..945366bc37ce 100644
--- a/drivers/staging/rtl8723bs/hal/odm_HWConfig.h
+++ b/drivers/staging/rtl8723bs/hal/odm_HWConfig.h
@@ -140,8 +140,6 @@ HAL_STATUS ODM_ConfigBBWithHeaderFile(
PDM_ODM_T pDM_Odm, ODM_BB_Config_Type ConfigType
);
-HAL_STATUS ODM_ConfigMACWithHeaderFile(PDM_ODM_T pDM_Odm);
-
HAL_STATUS ODM_ConfigFWWithHeaderFile(
PDM_ODM_T pDM_Odm,
ODM_FW_Config_Type ConfigType,
diff --git a/drivers/staging/rtl8723bs/hal/odm_RegConfig8723B.h b/drivers/staging/rtl8723bs/hal/odm_RegConfig8723B.h
index 12dfc58a6da0..07b585950cf9 100644
--- a/drivers/staging/rtl8723bs/hal/odm_RegConfig8723B.h
+++ b/drivers/staging/rtl8723bs/hal/odm_RegConfig8723B.h
@@ -7,51 +7,46 @@
#ifndef __INC_ODM_REGCONFIG_H_8723B
#define __INC_ODM_REGCONFIG_H_8723B
-void odm_ConfigRFReg_8723B(
- PDM_ODM_T pDM_Odm,
- u32 Addr,
- u32 Data,
- ODM_RF_RADIO_PATH_E RF_PATH,
- u32 RegAddr
+void odm_ConfigRFReg_8723B(PDM_ODM_T pDM_Odm,
+ u32 Addr,
+ u32 Data,
+ ODM_RF_RADIO_PATH_E RF_PATH,
+ u32 RegAddr
);
void odm_ConfigRF_RadioA_8723B(PDM_ODM_T pDM_Odm, u32 Addr, u32 Data);
void odm_ConfigMAC_8723B(PDM_ODM_T pDM_Odm, u32 Addr, u8 Data);
-void odm_ConfigBB_AGC_8723B(
- PDM_ODM_T pDM_Odm,
- u32 Addr,
- u32 Bitmask,
- u32 Data
+void odm_ConfigBB_AGC_8723B(PDM_ODM_T pDM_Odm,
+ u32 Addr,
+ u32 Bitmask,
+ u32 Data
);
-void odm_ConfigBB_PHY_REG_PG_8723B(
- PDM_ODM_T pDM_Odm,
- u32 Band,
- u32 RfPath,
- u32 TxNum,
- u32 Addr,
- u32 Bitmask,
- u32 Data
+void odm_ConfigBB_PHY_REG_PG_8723B(PDM_ODM_T pDM_Odm,
+ u32 Band,
+ u32 RfPath,
+ u32 TxNum,
+ u32 Addr,
+ u32 Bitmask,
+ u32 Data
);
-void odm_ConfigBB_PHY_8723B(
- PDM_ODM_T pDM_Odm,
- u32 Addr,
- u32 Bitmask,
- u32 Data
+void odm_ConfigBB_PHY_8723B(PDM_ODM_T pDM_Odm,
+ u32 Addr,
+ u32 Bitmask,
+ u32 Data
);
-void odm_ConfigBB_TXPWR_LMT_8723B(
- PDM_ODM_T pDM_Odm,
- u8 *Regulation,
- u8 *Band,
- u8 *Bandwidth,
- u8 *RateSection,
- u8 *RfPath,
- u8 *Channel,
- u8 *PowerLimit
+void odm_ConfigBB_TXPWR_LMT_8723B(PDM_ODM_T pDM_Odm,
+ u8 *Regulation,
+ u8 *Band,
+ u8 *Bandwidth,
+ u8 *RateSection,
+ u8 *RfPath,
+ u8 *Channel,
+ u8 *PowerLimit
);
#endif
diff --git a/drivers/staging/rtl8723bs/hal/odm_precomp.h b/drivers/staging/rtl8723bs/hal/odm_precomp.h
index b5b0c0ed02fc..d48d681472d5 100644
--- a/drivers/staging/rtl8723bs/hal/odm_precomp.h
+++ b/drivers/staging/rtl8723bs/hal/odm_precomp.h
@@ -29,7 +29,6 @@
#include "odm_HWConfig.h"
#include "odm_debug.h"
#include "odm_RegDefine11N.h"
-#include "odm_AntDiv.h"
#include "odm_EdcaTurboCheck.h"
#include "odm_DIG.h"
#include "odm_PathDiv.h"
diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c b/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c
index fe3891106a6d..080e974914b6 100644
--- a/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c
+++ b/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c
@@ -73,7 +73,7 @@ s32 FillH2CCmd8723B(struct adapter *padapter, u8 ElementID, u32 CmdLen, u8 *pCmd
goto exit;
}
- if (padapter->bSurpriseRemoved == true)
+ if (padapter->bSurpriseRemoved)
goto exit;
/* pay attention to if race condition happened in H2C cmd setting. */
@@ -297,7 +297,7 @@ static void ConstructNullFunctionData(
SetSeqNum(pwlanhdr, 0);
- if (bQoS == true) {
+ if (bQoS) {
struct ieee80211_qos_hdr *pwlanqoshdr;
SetFrameSubType(pframe, WIFI_QOS_DATA_NULL);
@@ -436,7 +436,7 @@ static void ConstructARPResponse(
DBG_871X("%s(): Add MIC\n", __func__);
psta = rtw_get_stainfo(&padapter->stapriv, get_my_bssid(&(pmlmeinfo->network)));
- if (psta != NULL) {
+ if (psta) {
if (!memcmp(&psta->dot11tkiptxmickey.skey[0], null_key, 16)) {
DBG_871X("%s(): STA dot11tkiptxmickey == 0\n", __func__);
}
@@ -674,10 +674,6 @@ static void ConstructProbeReq(struct adapter *padapter, u8 *pframe, u32 *pLength
u32 pktlen;
unsigned char *mac;
unsigned char bssrate[NumRates];
- struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
- struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
- struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
- struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
int bssrate_len = 0;
u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
@@ -757,7 +753,7 @@ static void ConstructProbeRsp(struct adapter *padapter, u8 *pframe, u32 *pLength
cur_network->IELength-_FIXED_IE_LENGTH_, NULL, &wps_ielen);
/* inerset & update wps_probe_resp_ie */
- if ((pmlmepriv->wps_probe_resp_ie != NULL) && pwps_ie && (wps_ielen > 0)) {
+ if (pmlmepriv->wps_probe_resp_ie && pwps_ie && (wps_ielen > 0)) {
uint wps_offset, remainder_ielen;
u8 *premainder_ie;
@@ -995,7 +991,7 @@ void rtl8723b_set_FwMacIdConfig_cmd(struct adapter *padapter, u8 mac_id, u8 raid
FillH2CCmd8723B(padapter, H2C_8723B_MACID_CFG, H2C_MACID_CFG_LEN, u1H2CMacIdConfigParm);
}
-static void rtl8723b_set_FwRssiSetting_cmd(struct adapter *padapter, u8 *param)
+void rtl8723b_set_rssi_cmd(struct adapter *padapter, u8 *param)
{
u8 u1H2CRssiSettingParm[H2C_RSSI_SETTING_LEN] = {0};
u8 mac_id = *param;
@@ -1048,9 +1044,9 @@ void rtl8723b_set_FwPwrMode_cmd(struct adapter *padapter, u8 psmode)
}
if (psmode > 0) {
- if (rtw_btcoex_IsBtControlLps(padapter) == true) {
- PowerState = rtw_btcoex_RpwmVal(padapter);
- byte5 = rtw_btcoex_LpsVal(padapter);
+ if (hal_btcoex_IsBtControlLps(padapter) == true) {
+ PowerState = hal_btcoex_RpwmVal(padapter);
+ byte5 = hal_btcoex_LpsVal(padapter);
if ((rlbm == 2) && (byte5 & BIT(4))) {
/* Keep awake interval to 1 to prevent from */
@@ -1075,7 +1071,7 @@ void rtl8723b_set_FwPwrMode_cmd(struct adapter *padapter, u8 psmode)
SET_8723B_H2CCMD_PWRMODE_PARM_PWR_STATE(u1H2CPwrModeParm, PowerState);
SET_8723B_H2CCMD_PWRMODE_PARM_BYTE5(u1H2CPwrModeParm, byte5);
if (psmode != PS_MODE_ACTIVE) {
- if (pmlmeext->adaptive_tsf_done == false && pmlmeext->bcn_cnt > 0) {
+ if (!pmlmeext->adaptive_tsf_done && pmlmeext->bcn_cnt > 0) {
u8 ratio_20_delay, ratio_80_delay;
/* byte 6 for adaptive_early_32k */
@@ -1137,7 +1133,7 @@ void rtl8723b_set_FwPwrMode_cmd(struct adapter *padapter, u8 psmode)
}
- rtw_btcoex_RecordPwrMode(padapter, u1H2CPwrModeParm, H2C_PWRMODE_LEN);
+ hal_btcoex_RecordPwrMode(padapter, u1H2CPwrModeParm, H2C_PWRMODE_LEN);
RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CPwrModeParm:", u1H2CPwrModeParm, H2C_PWRMODE_LEN);
@@ -1256,7 +1252,7 @@ static void rtl8723b_set_FwRemoteWakeCtrl_Cmd(struct adapter *padapter, u8 benab
FillH2CCmd8723B(padapter, H2C_8723B_REMOTE_WAKE_CTRL,
H2C_REMOTE_WAKE_CTRL_LEN, u1H2CRemoteWakeCtrlParm);
#ifdef CONFIG_PNO_SUPPORT
- if (ppwrpriv->wowlan_pno_enable && ppwrpriv->pno_in_resume == false) {
+ if (ppwrpriv->wowlan_pno_enable && !ppwrpriv->pno_in_resume) {
res = rtw_read8(padapter, REG_PNO_STATUS);
DBG_871X("cmd: 0x81 REG_PNO_STATUS: 0x%02x\n", res);
while (!(res&BIT(7)) && count < 25) {
@@ -1288,8 +1284,6 @@ static void rtl8723b_set_FwAOACGlobalInfo_Cmd(struct adapter *padapter, u8 grou
static void rtl8723b_set_FwScanOffloadInfo_cmd(struct adapter *padapter, PRSVDPAGE_LOC rsvdpageloc, u8 enable)
{
u8 u1H2CScanOffloadInfoParm[H2C_SCAN_OFFLOAD_CTRL_LEN] = {0};
- u8 res = 0, count = 0;
- struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
DBG_871X("%s: loc_probe_packet:%d, loc_scan_info: %d loc_ssid_info:%d\n",
__func__, rsvdpageloc->LocProbePacket, rsvdpageloc->LocScanInfo, rsvdpageloc->LocSSIDInfo);
@@ -1322,7 +1316,7 @@ static void rtl8723b_set_FwWoWlanRelated_cmd(struct adapter *padapter, u8 enable
if (!(ppwrpriv->wowlan_pno_enable)) {
psta = rtw_get_stainfo(&padapter->stapriv, get_bssid(pmlmepriv));
- if (psta != NULL)
+ if (psta)
rtl8723b_set_FwMediaStatusRpt_cmd(padapter, RT_MEDIA_CONNECT, psta->mac_id);
} else
DBG_871X("%s(): Disconnected, no FwMediaStatusRpt CONNECT\n", __func__);
@@ -1440,7 +1434,6 @@ static void rtl8723b_set_FwRsvdPagePkt(
struct adapter *padapter, bool bDLFinished
)
{
- struct hal_com_data *pHalData;
struct xmit_frame *pcmdframe;
struct pkt_attrib *pattrib;
struct xmit_priv *pxmitpriv;
@@ -1470,7 +1463,6 @@ static void rtl8723b_set_FwRsvdPagePkt(
/* DBG_871X("%s---->\n", __func__); */
- pHalData = GET_HAL_DATA(padapter);
pxmitpriv = &padapter->xmitpriv;
pmlmeext = &padapter->mlmeextpriv;
pmlmeinfo = &pmlmeext->mlmext_info;
@@ -1677,7 +1669,7 @@ static void rtl8723b_set_FwRsvdPagePkt(
#endif /* CONFIG_WOWLAN */
{
#ifdef CONFIG_PNO_SUPPORT
- if (pwrctl->pno_in_resume == false && pwrctl->pno_inited == true) {
+ if (!pwrctl->pno_in_resume && pwrctl->pno_inited) {
/* Probe Request */
RsvdPageLoc.LocProbePacket = TotalPageNum;
ConstructProbeReq(
@@ -2036,11 +2028,6 @@ void rtl8723b_download_rsvd_page(struct adapter *padapter, u8 mstatus)
}
}
-void rtl8723b_set_rssi_cmd(struct adapter *padapter, u8 *param)
-{
- rtl8723b_set_FwRssiSetting_cmd(padapter, param);
-}
-
void rtl8723b_set_FwJoinBssRpt_cmd(struct adapter *padapter, u8 mstatus)
{
if (mstatus == 1)
@@ -2125,7 +2112,7 @@ static void ConstructBtNullFunctionData(
SetDuration(pwlanhdr, 0);
SetSeqNum(pwlanhdr, 0);
- if (bQoS == true) {
+ if (bQoS) {
struct ieee80211_qos_hdr *pwlanqoshdr;
SetFrameSubType(pframe, WIFI_QOS_DATA_NULL);
@@ -2313,7 +2300,7 @@ void rtl8723b_download_BTCoex_AP_mode_rsvd_page(struct adapter *padapter)
} while (!bcn_valid && (poll%10) != 0 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped);
} while (!bcn_valid && (DLBcnCount <= 100) && !padapter->bSurpriseRemoved && !padapter->bDriverStopped);
- if (true == bcn_valid) {
+ if (bcn_valid) {
struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter);
pwrctl->fw_psmode_iface_id = padapter->iface_id;
DBG_8192C(ADPT_FMT": DL RSVD page success! DLBcnCount:%d, poll:%d\n",
diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_dm.c b/drivers/staging/rtl8723bs/hal/rtl8723b_dm.c
index 65781477cac9..c514cb735afd 100644
--- a/drivers/staging/rtl8723bs/hal/rtl8723b_dm.c
+++ b/drivers/staging/rtl8723bs/hal/rtl8723b_dm.c
@@ -173,7 +173,7 @@ void rtl8723b_HalDmWatchDog(struct adapter *Adapter)
if (hw_init_completed == true) {
u8 bLinked = false;
u8 bsta_state = false;
- u8 bBtDisabled = true;
+ bool bBtDisabled = true;
if (rtw_linked_check(Adapter)) {
bLinked = true;
@@ -186,7 +186,7 @@ void rtl8723b_HalDmWatchDog(struct adapter *Adapter)
/* ODM_CmnInfoUpdate(&pHalData->odmpriv , ODM_CMNINFO_RSSI_MIN, pdmpriv->MinUndecoratedPWDBForDM); */
- bBtDisabled = rtw_btcoex_IsBtDisabled(Adapter);
+ bBtDisabled = hal_btcoex_IsBtDisabled(Adapter);
ODM_CmnInfoUpdate(&pHalData->odmpriv, ODM_CMNINFO_BT_ENABLED, ((bBtDisabled == true)?false:true));
diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c
index caa8e2f39448..faeaf24fa833 100644
--- a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c
+++ b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c
@@ -217,7 +217,7 @@ void _8051Reset8723(struct adapter *padapter)
DBG_8192C("%s: Finish\n", __func__);
}
-u8 g_fwdl_chksum_fail = 0;
+u8 g_fwdl_chksum_fail;
static s32 polling_fwdl_chksum(
struct adapter *adapter, u32 min_cnt, u32 timeout_ms
@@ -262,7 +262,7 @@ exit:
return ret;
}
-u8 g_fwdl_wintint_rdy_fail = 0;
+u8 g_fwdl_wintint_rdy_fail;
static s32 _FWFreeToGo(struct adapter *adapter, u32 min_cnt, u32 timeout_ms)
{
@@ -742,7 +742,7 @@ static void Hal_BT_EfusePowerSwitch(
)
{
u8 tempval;
- if (PwrState == true) {
+ if (PwrState) {
/* enable BT power cut */
/* 0x6A[14] = 1 */
tempval = rtw_read8(padapter, 0x6B);
@@ -783,7 +783,7 @@ static void Hal_EfusePowerSwitch(
u16 tmpV16;
- if (PwrState == true) {
+ if (PwrState) {
/* To avoid cannot access efuse regsiters after disable/enable several times during DTM test. */
/* Suggested by SD1 IsaacHsu. 2013.07.08, added by tynli. */
tempval = rtw_read8(padapter, SDIO_LOCAL_BASE|SDIO_REG_HSUS_CTRL);
@@ -833,7 +833,7 @@ static void Hal_EfusePowerSwitch(
rtw_write16(padapter, REG_SYS_CLKR, tmpV16);
}
- if (bWrite == true) {
+ if (bWrite) {
/* Enable LDO 2.5V before read/write action */
tempval = rtw_read8(padapter, EFUSE_TEST+3);
tempval &= 0x0F;
@@ -845,7 +845,7 @@ static void Hal_EfusePowerSwitch(
} else {
rtw_write8(padapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_OFF);
- if (bWrite == true) {
+ if (bWrite) {
/* Disable LDO 2.5V after read/write action */
tempval = rtw_read8(padapter, EFUSE_TEST+3);
rtw_write8(padapter, EFUSE_TEST+3, (tempval & 0x7F));
@@ -1023,7 +1023,7 @@ static void hal_ReadEFuse_BT(
}
efuseTbl = rtw_malloc(EFUSE_BT_MAP_LEN);
- if (efuseTbl == NULL) {
+ if (!efuseTbl) {
DBG_8192C("%s: efuseTbl malloc fail!\n", __func__);
return;
}
@@ -2139,7 +2139,7 @@ static void UpdateHalRAMask8723B(struct adapter *padapter, u32 mac_id, u8 rssi_l
return;
psta = pmlmeinfo->FW_sta_info[mac_id].psta;
- if (psta == NULL)
+ if (!psta)
return;
shortGIrate = query_ra_short_GI(psta);
@@ -2153,7 +2153,7 @@ static void UpdateHalRAMask8723B(struct adapter *padapter, u32 mac_id, u8 rssi_l
mask &= rate_bitmap;
- rate_bitmap = rtw_btcoex_GetRaMask(padapter);
+ rate_bitmap = hal_btcoex_GetRaMask(padapter);
mask &= ~rate_bitmap;
#ifdef CONFIG_CMCC_TEST
@@ -2166,7 +2166,7 @@ static void UpdateHalRAMask8723B(struct adapter *padapter, u32 mac_id, u8 rssi_l
}
#endif
- if (pHalData->fw_ractrl == true) {
+ if (pHalData->fw_ractrl) {
rtl8723b_set_FwMacIdConfig_cmd(padapter, mac_id, psta->raid, psta->bw_mode, shortGIrate, mask);
}
@@ -2428,7 +2428,7 @@ void Hal_InitPGData(struct adapter *padapter, u8 *PROMContent)
{
struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter);
- if (false == pEEPROM->bautoload_fail_flag) { /* autoload OK. */
+ if (!pEEPROM->bautoload_fail_flag) { /* autoload OK. */
if (!pEEPROM->EepromOrEfuse) {
/* Read EFUSE real map to shadow. */
EFUSE_ShadowMapUpdate(padapter, EFUSE_WIFI, false);
@@ -2436,7 +2436,7 @@ void Hal_InitPGData(struct adapter *padapter, u8 *PROMContent)
}
} else {/* autoload fail */
RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("AutoLoad Fail reported from CR9346!!\n"));
- if (false == pEEPROM->EepromOrEfuse)
+ if (!pEEPROM->EepromOrEfuse)
EFUSE_ShadowMapUpdate(padapter, EFUSE_WIFI, false);
memcpy((void *)PROMContent, (void *)pEEPROM->efuse_eeprom_data, HWSET_MAX_SIZE_8723B);
}
@@ -2694,11 +2694,11 @@ void Hal_EfuseParseBTCoexistInfo_8723B(
}
}
- rtw_btcoex_SetBTCoexist(padapter, pHalData->EEPROMBluetoothCoexist);
- rtw_btcoex_SetChipType(padapter, pHalData->EEPROMBluetoothType);
- rtw_btcoex_SetPGAntNum(padapter, pHalData->EEPROMBluetoothAntNum == Ant_x2 ? 2 : 1);
+ hal_btcoex_SetBTCoexist(padapter, pHalData->EEPROMBluetoothCoexist);
+ hal_btcoex_SetChipType(padapter, pHalData->EEPROMBluetoothType);
+ hal_btcoex_SetPgAntNum(padapter, pHalData->EEPROMBluetoothAntNum == Ant_x2 ? 2 : 1);
if (pHalData->EEPROMBluetoothAntNum == Ant_x1)
- rtw_btcoex_SetSingleAntPath(padapter, pHalData->ant_path);
+ hal_btcoex_SetSingleAntPath(padapter, pHalData->ant_path);
DBG_8192C(
"%s: %s BT-coex, ant_num =%d\n",
@@ -2842,12 +2842,12 @@ void Hal_EfuseParseThermalMeter_8723B(
/* */
/* ThermalMeter from EEPROM */
/* */
- if (false == AutoLoadFail)
+ if (!AutoLoadFail)
pHalData->EEPROMThermalMeter = PROMContent[EEPROM_THERMAL_METER_8723B];
else
pHalData->EEPROMThermalMeter = EEPROM_Default_ThermalMeter_8723B;
- if ((pHalData->EEPROMThermalMeter == 0xff) || (true == AutoLoadFail)) {
+ if ((pHalData->EEPROMThermalMeter == 0xff) || AutoLoadFail) {
pHalData->bAPKThermalMeterIgnore = true;
pHalData->EEPROMThermalMeter = EEPROM_Default_ThermalMeter_8723B;
}
@@ -3094,12 +3094,12 @@ static void rtl8723b_fill_default_txdesc(
(pattrib->dhcp_pkt != 1) &&
(drv_userate != 1)
#ifdef CONFIG_AUTO_AP_MODE
- && (pattrib->pctrl != true)
+ && (!pattrib->pctrl)
#endif
) {
/* Non EAP & ARP & DHCP type data packet */
- if (pattrib->ampdu_en == true) {
+ if (pattrib->ampdu_en) {
ptxdesc->agg_en = 1; /* AGG EN */
ptxdesc->max_agg_num = 0x1f;
ptxdesc->ampdu_density = pattrib->ampdu_spacing;
@@ -3110,7 +3110,7 @@ static void rtl8723b_fill_default_txdesc(
ptxdesc->data_ratefb_lmt = 0x1F;
- if (pHalData->fw_ractrl == false) {
+ if (!pHalData->fw_ractrl) {
ptxdesc->userate = 1;
if (pHalData->dmpriv.INIDATA_RATE[pattrib->mac_id] & BIT(7))
@@ -3162,7 +3162,7 @@ static void rtl8723b_fill_default_txdesc(
ptxdesc->mbssid = pattrib->mbssid & 0xF;
ptxdesc->rty_lmt_en = 1; /* retry limit enable */
- if (pattrib->retry_ctrl == true) {
+ if (pattrib->retry_ctrl) {
ptxdesc->data_rt_lmt = 6;
} else {
ptxdesc->data_rt_lmt = 12;
@@ -3265,14 +3265,14 @@ void rtl8723b_fill_fake_txdesc(
SET_TX_DESC_QUEUE_SEL_8723B(pDesc, QSLT_MGNT); /* Fixed queue of Mgnt queue */
/* Set NAVUSEHDR to prevent Ps-poll AId filed to be changed to error vlaue by Hw. */
- if (true == IsPsPoll) {
+ if (IsPsPoll) {
SET_TX_DESC_NAV_USE_HDR_8723B(pDesc, 1);
} else {
SET_TX_DESC_HWSEQ_EN_8723B(pDesc, 1); /* Hw set sequence number */
SET_TX_DESC_HWSEQ_SEL_8723B(pDesc, 0);
}
- if (true == IsBTQosNull) {
+ if (IsBTQosNull) {
SET_TX_DESC_BT_INT_8723B(pDesc, 1);
}
@@ -3284,7 +3284,7 @@ void rtl8723b_fill_fake_txdesc(
/* */
/* Encrypt the data frame if under security mode excepct null data. Suggested by CCW. */
/* */
- if (true == bDataFrame) {
+ if (bDataFrame) {
u32 EncAlg;
EncAlg = padapter->securitypriv.dot11PrivacyAlgrthm;
@@ -3463,7 +3463,7 @@ static void hw_var_set_correct_tsf(struct adapter *padapter, u8 variable, u8 *va
pmlmeext = &padapter->mlmeextpriv;
pmlmeinfo = &pmlmeext->mlmext_info;
- tsf = pmlmeext->TSFValue-rtw_modular64(pmlmeext->TSFValue, (pmlmeinfo->bcn_interval*1024))-1024; /* us */
+ tsf = pmlmeext->TSFValue-do_div(pmlmeext->TSFValue, (pmlmeinfo->bcn_interval*1024))-1024; /* us */
if (
((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) ||
@@ -3579,14 +3579,12 @@ static void hw_var_set_mlme_join(struct adapter *padapter, u8 variable, u8 *val)
u32 val32;
u8 RetryLimit;
u8 type;
- struct hal_com_data *pHalData;
struct mlme_priv *pmlmepriv;
struct eeprom_priv *pEEPROM;
RetryLimit = 0x30;
type = *(u8 *)val;
- pHalData = GET_HAL_DATA(padapter);
pmlmepriv = &padapter->mlmepriv;
pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter);
@@ -3695,7 +3693,7 @@ s32 c2h_handler_8723b(struct adapter *padapter, u8 *buf)
break;
case C2H_8723B_BT_INFO:
- rtw_btcoex_BtInfoNotify(padapter, pC2hEvent->plen, pC2hEvent->payload);
+ hal_btcoex_BtInfoNotify(padapter, pC2hEvent->plen, pC2hEvent->payload);
break;
default:
@@ -3744,7 +3742,7 @@ static void process_c2h_event(struct adapter *padapter, PC2H_EVT_HDR pC2hEvent,
break;
case C2H_8723B_BT_INFO:
- rtw_btcoex_BtInfoNotify(padapter, pC2hEvent->CmdLen, c2hBuf);
+ hal_btcoex_BtInfoNotify(padapter, pC2hEvent->CmdLen, c2hBuf);
break;
default:
@@ -3759,7 +3757,7 @@ void C2HPacketHandler_8723B(struct adapter *padapter, u8 *pbuffer, u16 length)
#ifdef CONFIG_WOWLAN
struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
- if (pwrpriv->wowlan_mode == true) {
+ if (pwrpriv->wowlan_mode) {
DBG_871X("%s(): return because wowolan_mode ==true! CMDID =%d\n", __func__, pbuffer[0]);
return;
}
@@ -3878,7 +3876,7 @@ void SetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val)
case HW_VAR_MLME_SITESURVEY:
hw_var_set_mlme_sitesurvey(padapter, variable, val);
- rtw_btcoex_ScanNotify(padapter, *val?true:false);
+ hal_btcoex_ScanNotify(padapter, *val?true:false);
break;
case HW_VAR_MLME_JOIN:
@@ -3887,11 +3885,11 @@ void SetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val)
switch (*val) {
case 0:
/* prepare to join */
- rtw_btcoex_ConnectNotify(padapter, true);
+ hal_btcoex_ConnectNotify(padapter, true);
break;
case 1:
/* joinbss_event callback when join res < 0 */
- rtw_btcoex_ConnectNotify(padapter, false);
+ hal_btcoex_ConnectNotify(padapter, false);
break;
case 2:
/* sta add event callback */
@@ -4119,7 +4117,7 @@ void SetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val)
/* keep sn */
padapter->xmitpriv.nqos_ssn = rtw_read16(padapter, REG_NQOS_SEQ);
- if (pwrpriv->bkeepfwalive != true) {
+ if (!pwrpriv->bkeepfwalive) {
/* RX DMA stop */
val32 = rtw_read32(padapter, REG_RXPKT_NUM);
val32 |= RW_RELEASE_EN;
@@ -4274,7 +4272,7 @@ void GetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val)
u32 valRCR;
if (
- (padapter->bSurpriseRemoved == true) ||
+ padapter->bSurpriseRemoved ||
(adapter_to_pwrctl(padapter)->rf_pwrstate == rf_off)
) {
/* If it is in HW/SW Radio OFF or IPS state, we do not check Fw LPS Leave, */
@@ -4345,11 +4343,8 @@ void GetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val)
*/
u8 SetHalDefVar8723B(struct adapter *padapter, enum HAL_DEF_VARIABLE variable, void *pval)
{
- struct hal_com_data *pHalData;
u8 bResult;
-
- pHalData = GET_HAL_DATA(padapter);
bResult = _SUCCESS;
switch (variable) {
@@ -4367,11 +4362,8 @@ u8 SetHalDefVar8723B(struct adapter *padapter, enum HAL_DEF_VARIABLE variable, v
*/
u8 GetHalDefVar8723B(struct adapter *padapter, enum HAL_DEF_VARIABLE variable, void *pval)
{
- struct hal_com_data *pHalData;
u8 bResult;
-
- pHalData = GET_HAL_DATA(padapter);
bResult = _SUCCESS;
switch (variable) {
diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c b/drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c
index 4f2ad54af398..25c75b977666 100644
--- a/drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c
+++ b/drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c
@@ -45,7 +45,7 @@ static u32 phy_CalculateBitShift(u32 BitMask)
/**
* Function: PHY_QueryBBReg
*
-* OverView: Read "sepcific bits" from BB register
+* OverView: Read "specific bits" from BB register
*
* Input:
* struct adapter * Adapter,
@@ -375,7 +375,7 @@ s32 PHY_MACConfig8723B(struct adapter *Adapter)
/* */
rtStatus = phy_ConfigMACWithParaFile(Adapter, pszMACRegFile);
if (rtStatus == _FAIL) {
- ODM_ConfigMACWithHeaderFile(&pHalData->odmpriv);
+ ODM_ReadAndConfig_MP_8723B_MAC_REG(&pHalData->odmpriv);
rtStatus = _SUCCESS;
}
diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_rf6052.c b/drivers/staging/rtl8723bs/hal/rtl8723b_rf6052.c
index aa45a8421ebe..d0ffe0af5339 100644
--- a/drivers/staging/rtl8723bs/hal/rtl8723b_rf6052.c
+++ b/drivers/staging/rtl8723bs/hal/rtl8723b_rf6052.c
@@ -114,12 +114,12 @@ static int phy_RF6052_Config_ParaFile(struct adapter *Adapter)
break;
case RF_PATH_B:
case RF_PATH_D:
- u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV<<16);
+ u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV << 16);
break;
}
/*----Set RF_ENV enable----*/
- PHY_SetBBReg(Adapter, pPhyReg->rfintfe, bRFSI_RFENV<<16, 0x1);
+ PHY_SetBBReg(Adapter, pPhyReg->rfintfe, bRFSI_RFENV << 16, 0x1);
udelay(1);/* PlatformStallExecution(1); */
/*----Set RF_ENV output high----*/
@@ -163,7 +163,7 @@ static int phy_RF6052_Config_ParaFile(struct adapter *Adapter)
break;
case RF_PATH_B:
case RF_PATH_D:
- PHY_SetBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV<<16, u4RegValue);
+ PHY_SetBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV << 16, u4RegValue);
break;
}
@@ -194,7 +194,6 @@ phy_RF6052_Config_ParaFile_Fail:
int PHY_RF6052_Config8723B(struct adapter *Adapter)
{
struct hal_com_data *pHalData = GET_HAL_DATA(Adapter);
- int rtStatus = _SUCCESS;
/* */
/* Initialize general global value */
@@ -208,8 +207,7 @@ int PHY_RF6052_Config8723B(struct adapter *Adapter)
/* */
/* Config BB and RF */
/* */
- rtStatus = phy_RF6052_Config_ParaFile(Adapter);
- return rtStatus;
+ return phy_RF6052_Config_ParaFile(Adapter);
}
diff --git a/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c b/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c
index b269de52e535..e23b39ab16c5 100644
--- a/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c
+++ b/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c
@@ -10,14 +10,12 @@
#include <rtw_debug.h>
#include <rtl8723b_hal.h>
-static s32 initrecvbuf(struct recv_buf *precvbuf, struct adapter *padapter)
+static void initrecvbuf(struct recv_buf *precvbuf, struct adapter *padapter)
{
INIT_LIST_HEAD(&precvbuf->list);
spin_lock_init(&precvbuf->recvbuf_lock);
precvbuf->adapter = padapter;
-
- return _SUCCESS;
}
static void update_recvframe_attrib(struct adapter *padapter,
@@ -177,7 +175,7 @@ static void rtl8723bs_c2h_packet_handler(struct adapter *padapter,
res = rtw_c2h_packet_wk_cmd(padapter, tmp, length);
- if (res == false)
+ if (!res)
kfree(tmp);
/* DBG_871X("-%s res(%d)\n", __func__, res); */
@@ -435,9 +433,7 @@ s32 rtl8723bs_init_recv_priv(struct adapter *padapter)
/* init each recv buffer */
precvbuf = (struct recv_buf *)precvpriv->precv_buf;
for (i = 0; i < NR_RECVBUFF; i++) {
- res = initrecvbuf(precvbuf, padapter);
- if (res == _FAIL)
- break;
+ initrecvbuf(precvbuf, padapter);
if (!precvbuf->pskb) {
SIZE_PTR tmpaddr = 0;
diff --git a/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c b/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c
index 7b06aab04ee6..b44e902ed338 100644
--- a/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c
+++ b/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c
@@ -17,8 +17,8 @@ static u8 rtw_sdio_wait_enough_TxOQT_space(struct adapter *padapter, u8 agg_num)
while (pHalData->SdioTxOQTFreeSpace < agg_num) {
if (
- (padapter->bSurpriseRemoved == true) ||
- (padapter->bDriverStopped == true)
+ (padapter->bSurpriseRemoved) ||
+ (padapter->bDriverStopped)
) {
DBG_871X("%s: bSurpriseRemoved or bDriverStopped (wait TxOQT)\n", __func__);
return false;
@@ -58,7 +58,7 @@ static s32 rtl8723_dequeue_writeport(struct adapter *padapter)
ret = ret || check_fwstate(pmlmepriv, _FW_UNDER_SURVEY);
- if (ret == true)
+ if (ret)
pxmitbuf = dequeue_pending_xmitbuf_under_survey(pxmitpriv);
else
pxmitbuf = dequeue_pending_xmitbuf(pxmitpriv);
@@ -85,7 +85,7 @@ static s32 rtl8723_dequeue_writeport(struct adapter *padapter)
query_free_page:
/* check if hardware tx fifo page is enough */
- if (false == rtw_hal_sdio_query_tx_freepage(pri_padapter, PageIdx, pxmitbuf->pg_num)) {
+ if (!rtw_hal_sdio_query_tx_freepage(pri_padapter, PageIdx, pxmitbuf->pg_num)) {
if (!bUpdatePageNum) {
/* Total number of page is NOT available, so update current FIFO status */
HalQueryTxBufferStatus8723BSdio(padapter);
@@ -99,8 +99,8 @@ query_free_page:
}
if (
- (padapter->bSurpriseRemoved == true) ||
- (padapter->bDriverStopped == true)
+ (padapter->bSurpriseRemoved) ||
+ (padapter->bDriverStopped)
) {
RT_TRACE(
_module_hal_xmit_c_,
@@ -153,7 +153,7 @@ s32 rtl8723bs_xmit_buf_handler(struct adapter *padapter)
return _FAIL;
}
- ret = (padapter->bDriverStopped == true) || (padapter->bSurpriseRemoved == true);
+ ret = (padapter->bDriverStopped) || (padapter->bSurpriseRemoved);
if (ret) {
RT_TRACE(
_module_hal_xmit_c_,
@@ -170,7 +170,7 @@ s32 rtl8723bs_xmit_buf_handler(struct adapter *padapter)
queue_pending = check_pending_xmitbuf(pxmitpriv);
- if (queue_pending == false)
+ if (!queue_pending)
return _SUCCESS;
ret = rtw_register_tx_alive(padapter);
@@ -202,7 +202,7 @@ static s32 xmit_xmitframes(struct adapter *padapter, struct xmit_priv *pxmitpriv
s32 err, ret;
u32 k = 0;
struct hw_xmit *hwxmits, *phwxmit;
- u8 no_res, idx, hwentry;
+ u8 idx, hwentry;
struct tx_servq *ptxservq;
struct list_head *sta_plist, *sta_phead, *frame_plist, *frame_phead;
struct xmit_frame *pxmitframe;
@@ -213,7 +213,6 @@ static s32 xmit_xmitframes(struct adapter *padapter, struct xmit_priv *pxmitpriv
int inx[4];
err = 0;
- no_res = false;
hwxmits = pxmitpriv->hwxmits;
hwentry = pxmitpriv->hwxmit_entry;
ptxservq = NULL;
@@ -236,8 +235,8 @@ static s32 xmit_xmitframes(struct adapter *padapter, struct xmit_priv *pxmitpriv
phwxmit = hwxmits + inx[idx];
if (
- (check_pending_xmitbuf(pxmitpriv) == true) &&
- (padapter->mlmepriv.LinkDetectInfo.bHigherBusyTxTraffic == true)
+ (check_pending_xmitbuf(pxmitpriv)) &&
+ (padapter->mlmepriv.LinkDetectInfo.bHigherBusyTxTraffic)
) {
if ((phwxmit->accnt > 0) && (phwxmit->accnt < 5)) {
err = -2;
@@ -285,7 +284,7 @@ static s32 xmit_xmitframes(struct adapter *padapter, struct xmit_priv *pxmitpriv
txlen = txdesc_size + rtw_wlan_pkt_size(pxmitframe);
if( !pxmitbuf ||
((_RND(pxmitbuf->len, 8) + txlen) > max_xmit_len) ||
- (k >= (rtw_hal_sdio_max_txoqt_free_space(padapter)-1))
+ (k >= (rtw_hal_sdio_max_txoqt_free_space(padapter) - 1))
) {
if (pxmitbuf) {
/* pxmitbuf->priv_data will be NULL, and will crash here */
@@ -356,8 +355,8 @@ static s32 xmit_xmitframes(struct adapter *padapter, struct xmit_priv *pxmitpriv
rtw_count_tx_stats(padapter, pxmitframe, pxmitframe->attrib.last_txcmdsz);
txlen = txdesc_size + pxmitframe->attrib.last_txcmdsz;
- pxmitframe->pg_num = (txlen + 127)/128;
- pxmitbuf->pg_num += (txlen + 127)/128;
+ pxmitframe->pg_num = (txlen + 127) / 128;
+ pxmitbuf->pg_num += (txlen + 127) / 128;
/* if (k != 1) */
/* ((struct xmit_frame*)pxmitbuf->priv_data)->pg_num += pxmitframe->pg_num; */
pxmitbuf->ptail += _RND(txlen, 8); /* round to 8 bytes alignment */
@@ -426,8 +425,8 @@ static s32 rtl8723bs_xmit_handler(struct adapter *padapter)
next:
if (
- (padapter->bDriverStopped == true) ||
- (padapter->bSurpriseRemoved == true)
+ (padapter->bDriverStopped) ||
+ (padapter->bSurpriseRemoved)
) {
RT_TRACE(
_module_hal_xmit_c_,
@@ -523,7 +522,7 @@ s32 rtl8723bs_mgnt_xmit(
rtl8723b_update_txdesc(pmgntframe, pmgntframe->buf_addr);
pxmitbuf->len = txdesc_size + pattrib->last_txcmdsz;
- pxmitbuf->pg_num = (pxmitbuf->len + 127)/128; /* 128 is tx page size */
+ pxmitbuf->pg_num = (pxmitbuf->len + 127) / 128; /* 128 is tx page size */
pxmitbuf->ptail = pmgntframe->buf_addr + pxmitbuf->len;
pxmitbuf->ff_hwaddr = rtw_get_ff_hwaddr(pmgntframe);
@@ -570,7 +569,7 @@ s32 rtl8723bs_hal_xmit(
(pxmitframe->attrib.ether_type != 0x888e) &&
(pxmitframe->attrib.dhcp_pkt != 1)
) {
- if (padapter->mlmepriv.LinkDetectInfo.bBusyTraffic == true)
+ if (padapter->mlmepriv.LinkDetectInfo.bBusyTraffic)
rtw_issue_addbareq_cmd(padapter, pxmitframe);
}
@@ -637,7 +636,6 @@ s32 rtl8723bs_init_xmit_priv(struct adapter *padapter)
void rtl8723bs_free_xmit_priv(struct adapter *padapter)
{
- struct hal_com_data *phal;
struct xmit_priv *pxmitpriv;
struct xmit_buf *pxmitbuf;
struct __queue *pqueue;
@@ -645,7 +643,6 @@ void rtl8723bs_free_xmit_priv(struct adapter *padapter)
struct list_head tmplist;
- phal = GET_HAL_DATA(padapter);
pxmitpriv = &padapter->xmitpriv;
pqueue = &pxmitpriv->pending_xmitbuf_queue;
phead = get_list_head(pqueue);
diff --git a/drivers/staging/rtl8723bs/hal/sdio_halinit.c b/drivers/staging/rtl8723bs/hal/sdio_halinit.c
index 3c65a9c02bbd..0f5dd4629e6f 100644
--- a/drivers/staging/rtl8723bs/hal/sdio_halinit.c
+++ b/drivers/staging/rtl8723bs/hal/sdio_halinit.c
@@ -26,7 +26,7 @@ static u8 CardEnable(struct adapter *padapter)
rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn);
- if (bMacPwrCtrlOn == false) {
+ if (!bMacPwrCtrlOn) {
/* RSV_CTRL 0x1C[7:0] = 0x00 */
/* unlock ISO/CLK/Power control register */
rtw_write8(padapter, REG_RSV_CTRL, 0x0);
@@ -112,22 +112,22 @@ u8 _InitPowerOn_8723BS(struct adapter *padapter)
/* all of these MUST be configured before power on */
#ifdef CONFIG_EXT_CLK
/* Use external crystal(XTAL) */
- value8 = rtw_read8(padapter, REG_PAD_CTRL1_8723B+2);
+ value8 = rtw_read8(padapter, REG_PAD_CTRL1_8723B + 2);
value8 |= BIT(7);
- rtw_write8(padapter, REG_PAD_CTRL1_8723B+2, value8);
+ rtw_write8(padapter, REG_PAD_CTRL1_8723B + 2, value8);
/* CLK_REQ High active or Low Active */
/* Request GPIO polarity: */
/* 0: low active */
/* 1: high active */
- value8 = rtw_read8(padapter, REG_MULTI_FUNC_CTRL+1);
+ value8 = rtw_read8(padapter, REG_MULTI_FUNC_CTRL + 1);
value8 |= BIT(5);
- rtw_write8(padapter, REG_MULTI_FUNC_CTRL+1, value8);
+ rtw_write8(padapter, REG_MULTI_FUNC_CTRL + 1, value8);
#endif /* CONFIG_EXT_CLK */
/* only cmd52 can be used before power on(card enable) */
ret = CardEnable(padapter);
- if (ret == false) {
+ if (!ret) {
RT_TRACE(
_module_hci_hal_init_c_,
_drv_emerg_,
@@ -137,12 +137,12 @@ u8 _InitPowerOn_8723BS(struct adapter *padapter)
}
/* Radio-Off Pin Trigger */
- value8 = rtw_read8(padapter, REG_GPIO_INTM+1);
+ value8 = rtw_read8(padapter, REG_GPIO_INTM + 1);
value8 |= BIT(1); /* Enable falling edge triggering interrupt */
- rtw_write8(padapter, REG_GPIO_INTM+1, value8);
- value8 = rtw_read8(padapter, REG_GPIO_IO_SEL_2+1);
+ rtw_write8(padapter, REG_GPIO_INTM + 1, value8);
+ value8 = rtw_read8(padapter, REG_GPIO_IO_SEL_2 + 1);
value8 |= BIT(1);
- rtw_write8(padapter, REG_GPIO_IO_SEL_2+1, value8);
+ rtw_write8(padapter, REG_GPIO_IO_SEL_2 + 1, value8);
/* Enable power down and GPIO interrupt */
value16 = rtw_read16(padapter, REG_APS_FSMCO);
@@ -168,7 +168,7 @@ u8 _InitPowerOn_8723BS(struct adapter *padapter)
);
rtw_write16(padapter, REG_CR, value16);
- rtw_btcoex_PowerOnSetting(padapter);
+ hal_btcoex_PowerOnSetting(padapter);
/* external switch to S1 */
/* 0x38[11] = 0x1 */
@@ -203,13 +203,13 @@ static void _init_available_page_threshold(struct adapter *padapter, u8 numHQ, u
u16 HQ_threshold, NQ_threshold, LQ_threshold;
HQ_threshold = (numPubQ + numHQ + 1) >> 1;
- HQ_threshold |= (HQ_threshold<<8);
+ HQ_threshold |= (HQ_threshold << 8);
NQ_threshold = (numPubQ + numNQ + 1) >> 1;
- NQ_threshold |= (NQ_threshold<<8);
+ NQ_threshold |= (NQ_threshold << 8);
LQ_threshold = (numPubQ + numLQ + 1) >> 1;
- LQ_threshold |= (LQ_threshold<<8);
+ LQ_threshold |= (LQ_threshold << 8);
rtw_write16(padapter, 0x218, HQ_threshold);
rtw_write16(padapter, 0x21A, NQ_threshold);
@@ -271,7 +271,7 @@ static void _InitTxBufferBoundary(struct adapter *padapter)
rtw_write8(padapter, REG_TXPKTBUF_MGQ_BDNY_8723B, txpktbuf_bndy);
rtw_write8(padapter, REG_TXPKTBUF_WMAC_LBK_BF_HD_8723B, txpktbuf_bndy);
rtw_write8(padapter, REG_TRXFF_BNDY, txpktbuf_bndy);
- rtw_write8(padapter, REG_TDECTRL+1, txpktbuf_bndy);
+ rtw_write8(padapter, REG_TDECTRL + 1, txpktbuf_bndy);
}
static void _InitNormalChipRegPriority(
@@ -397,7 +397,7 @@ static void _InitNormalChipThreeOutEpPriority(struct adapter *padapter)
_InitNormalChipRegPriority(padapter, beQ, bkQ, viQ, voQ, mgtQ, hiQ);
}
-static void _InitNormalChipQueuePriority(struct adapter *Adapter)
+static void _InitQueuePriority(struct adapter *Adapter)
{
struct hal_com_data *pHalData = GET_HAL_DATA(Adapter);
@@ -419,11 +419,6 @@ static void _InitNormalChipQueuePriority(struct adapter *Adapter)
}
-static void _InitQueuePriority(struct adapter *padapter)
-{
- _InitNormalChipQueuePriority(padapter);
-}
-
static void _InitPageBoundary(struct adapter *padapter)
{
/* RX Page Boundary */
@@ -569,7 +564,7 @@ static void HalRxAggr8723BSdio(struct adapter *padapter)
valueDMAPageCount = 0x06;
}
- rtw_write8(padapter, REG_RXDMA_AGG_PG_TH+1, valueDMATimeout);
+ rtw_write8(padapter, REG_RXDMA_AGG_PG_TH + 1, valueDMATimeout);
rtw_write8(padapter, REG_RXDMA_AGG_PG_TH, valueDMAPageCount);
}
@@ -588,8 +583,8 @@ static void sdio_AggSettingRxUpdate(struct adapter *padapter)
rtw_write8(padapter, REG_TRXDMA_CTRL, valueDMA);
valueRxAggCtrl |= RXDMA_AGG_MODE_EN;
- valueRxAggCtrl |= ((aggBurstNum<<2) & 0x0C);
- valueRxAggCtrl |= ((aggBurstSize<<4) & 0x30);
+ valueRxAggCtrl |= ((aggBurstNum << 2) & 0x0C);
+ valueRxAggCtrl |= ((aggBurstSize << 4) & 0x30);
rtw_write8(padapter, REG_RXDMA_MODE_CTRL_8723B, valueRxAggCtrl);/* RxAggLowThresh = 4*1K */
}
@@ -611,12 +606,9 @@ static void _initSdioAggregationSetting(struct adapter *padapter)
static void _InitOperationMode(struct adapter *padapter)
{
- struct hal_com_data *pHalData;
struct mlme_ext_priv *pmlmeext;
u8 regBwOpMode = 0;
- u32 regRATR = 0, regRRSR = 0;
- pHalData = GET_HAL_DATA(padapter);
pmlmeext = &padapter->mlmeextpriv;
/* 1 This part need to modified according to the rate set we filtered!! */
@@ -626,34 +618,24 @@ static void _InitOperationMode(struct adapter *padapter)
switch (pmlmeext->cur_wireless_mode) {
case WIRELESS_MODE_B:
regBwOpMode = BW_OPMODE_20MHZ;
- regRATR = RATE_ALL_CCK;
- regRRSR = RATE_ALL_CCK;
break;
case WIRELESS_MODE_A:
/* RT_ASSERT(false, ("Error wireless a mode\n")); */
break;
case WIRELESS_MODE_G:
regBwOpMode = BW_OPMODE_20MHZ;
- regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
- regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
break;
case WIRELESS_MODE_AUTO:
regBwOpMode = BW_OPMODE_20MHZ;
- regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS;
- regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
break;
case WIRELESS_MODE_N_24G:
/* It support CCK rate by default. */
/* CCK rate will be filtered out only when associated AP does not support it. */
regBwOpMode = BW_OPMODE_20MHZ;
- regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS;
- regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
break;
case WIRELESS_MODE_N_5G:
/* RT_ASSERT(false, ("Error wireless mode")); */
regBwOpMode = BW_OPMODE_5G;
- regRATR = RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS;
- regRRSR = RATE_ALL_OFDM_AG;
break;
default: /* for MacOSX compiler warning. */
@@ -754,11 +736,11 @@ static u32 rtl8723bs_hal_init(struct adapter *padapter)
rtw_hal_get_hwreg(padapter, HW_VAR_CPWM, &cpwm_orig);
/* ser rpwm */
- val8 = rtw_read8(padapter, SDIO_LOCAL_BASE|SDIO_REG_HRPWM1);
+ val8 = rtw_read8(padapter, SDIO_LOCAL_BASE | SDIO_REG_HRPWM1);
val8 &= 0x80;
val8 += 0x80;
val8 |= BIT(6);
- rtw_write8(padapter, SDIO_LOCAL_BASE|SDIO_REG_HRPWM1, val8);
+ rtw_write8(padapter, SDIO_LOCAL_BASE | SDIO_REG_HRPWM1, val8);
DBG_871X("%s: write rpwm =%02x\n", __func__, val8);
adapter_to_pwrctl(padapter)->tog = (val8 + 0x80) & 0x80;
@@ -782,13 +764,13 @@ static u32 rtl8723bs_hal_init(struct adapter *padapter)
rtw_hal_set_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn);
- rtw_btcoex_HAL_Initialize(padapter, false);
+ hal_btcoex_InitHwConfig(padapter, false);
return _SUCCESS;
}
#ifdef CONFIG_WOWLAN
- if (rtw_read8(padapter, REG_MCUFWDL)&BIT7) {
+ if (rtw_read8(padapter, REG_MCUFWDL) & BIT7) {
u8 reg_val = 0;
DBG_871X("+Reset Entry+\n");
rtw_write8(padapter, REG_MCUFWDL, 0x00);
@@ -802,12 +784,12 @@ static u32 rtl8723bs_hal_init(struct adapter *padapter)
/* reset TRX path */
rtw_write16(padapter, REG_CR, 0);
/* reset MAC, Digital Core */
- reg_val = rtw_read8(padapter, REG_SYS_FUNC_EN+1);
+ reg_val = rtw_read8(padapter, REG_SYS_FUNC_EN + 1);
reg_val &= ~(BIT(4) | BIT(7));
- rtw_write8(padapter, REG_SYS_FUNC_EN+1, reg_val);
- reg_val = rtw_read8(padapter, REG_SYS_FUNC_EN+1);
+ rtw_write8(padapter, REG_SYS_FUNC_EN + 1, reg_val);
+ reg_val = rtw_read8(padapter, REG_SYS_FUNC_EN + 1);
reg_val |= BIT(4) | BIT(7);
- rtw_write8(padapter, REG_SYS_FUNC_EN+1, reg_val);
+ rtw_write8(padapter, REG_SYS_FUNC_EN + 1, reg_val);
DBG_871X("-Reset Entry-\n");
}
#endif /* CONFIG_WOWLAN */
@@ -838,7 +820,7 @@ static u32 rtl8723bs_hal_init(struct adapter *padapter)
/* SIC_Init(padapter); */
- if (pwrctrlpriv->reg_rfoff == true)
+ if (pwrctrlpriv->reg_rfoff)
pwrctrlpriv->rf_pwrstate = rf_off;
/* 2010/08/09 MH We need to check if we need to turnon or off RF after detecting */
@@ -955,7 +937,7 @@ static u32 rtl8723bs_hal_init(struct adapter *padapter)
/* Configure SDIO TxRx Control to enable Rx DMA timer masking. */
/* 2010.02.24. */
/* */
- rtw_write32(padapter, SDIO_LOCAL_BASE|SDIO_REG_TX_CTRL, 0);
+ rtw_write32(padapter, SDIO_LOCAL_BASE | SDIO_REG_TX_CTRL, 0);
_RfPowerSave(padapter);
@@ -979,7 +961,7 @@ static u32 rtl8723bs_hal_init(struct adapter *padapter)
rtw_hal_set_hwreg(padapter, HW_VAR_NAV_UPPER, (u8 *)&NavUpper);
/* ack for xmit mgmt frames. */
- rtw_write32(padapter, REG_FWHW_TXQ_CTRL, rtw_read32(padapter, REG_FWHW_TXQ_CTRL)|BIT(12));
+ rtw_write32(padapter, REG_FWHW_TXQ_CTRL, rtw_read32(padapter, REG_FWHW_TXQ_CTRL) | BIT(12));
/* pHalData->PreRpwmVal = SdioLocalCmd52Read1Byte(padapter, SDIO_REG_HRPWM1) & 0x80; */
@@ -1009,14 +991,14 @@ static u32 rtl8723bs_hal_init(struct adapter *padapter)
msleep(50);
} while (jiffies_to_msecs(jiffies - start_time) <= 400);
- rtw_btcoex_IQKNotify(padapter, true);
+ hal_btcoex_IQKNotify(padapter, true);
restore_iqk_rst = pwrpriv->bips_processing;
b2Ant = pHalData->EEPROMBluetoothAntNum == Ant_x2;
PHY_IQCalibrate_8723B(padapter, false, restore_iqk_rst, b2Ant, pHalData->ant_path);
pHalData->odmpriv.RFCalibrateInfo.bIQKInitialized = true;
- rtw_btcoex_IQKNotify(padapter, false);
+ hal_btcoex_IQKNotify(padapter, false);
/* Inform WiFi FW that it is the finish of IQK */
h2cCmdBuf = 0;
@@ -1027,7 +1009,7 @@ static u32 rtl8723bs_hal_init(struct adapter *padapter)
}
/* Init BT hw config. */
- rtw_btcoex_HAL_Initialize(padapter, false);
+ hal_btcoex_InitHwConfig(padapter, false);
RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("-%s\n", __func__));
@@ -1059,19 +1041,19 @@ static void CardDisableRTL8723BSdio(struct adapter *padapter)
rtl8723b_FirmwareSelfReset(padapter);
/* Reset MCU 0x2[10]= 0. Suggested by Filen. 2011.01.26. by tynli. */
- u1bTmp = rtw_read8(padapter, REG_SYS_FUNC_EN+1);
+ u1bTmp = rtw_read8(padapter, REG_SYS_FUNC_EN + 1);
u1bTmp &= ~BIT(2); /* 0x2[10], FEN_CPUEN */
- rtw_write8(padapter, REG_SYS_FUNC_EN+1, u1bTmp);
+ rtw_write8(padapter, REG_SYS_FUNC_EN + 1, u1bTmp);
/* MCUFWDL 0x80[1:0]= 0 */
/* reset MCU ready status */
rtw_write8(padapter, REG_MCUFWDL, 0);
/* Reset MCU IO Wrapper, added by Roger, 2011.08.30 */
- u1bTmp = rtw_read8(padapter, REG_RSV_CTRL+1);
+ u1bTmp = rtw_read8(padapter, REG_RSV_CTRL + 1);
u1bTmp &= ~BIT(0);
- rtw_write8(padapter, REG_RSV_CTRL+1, u1bTmp);
- u1bTmp = rtw_read8(padapter, REG_RSV_CTRL+1);
+ rtw_write8(padapter, REG_RSV_CTRL + 1, u1bTmp);
+ u1bTmp = rtw_read8(padapter, REG_RSV_CTRL + 1);
u1bTmp |= BIT(0);
rtw_write8(padapter, REG_RSV_CTRL+1, u1bTmp);
@@ -1081,7 +1063,7 @@ static void CardDisableRTL8723BSdio(struct adapter *padapter)
ret = false;
rtw_hal_set_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn);
ret = HalPwrSeqCmdParsing(padapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, rtl8723B_card_disable_flow);
- if (ret == false) {
+ if (!ret) {
DBG_8192C(KERN_ERR "%s: run CARD DISABLE flow fail!\n", __func__);
}
}
@@ -1091,9 +1073,9 @@ static u32 rtl8723bs_hal_deinit(struct adapter *padapter)
struct dvobj_priv *psdpriv = padapter->dvobj;
struct debug_priv *pdbgpriv = &psdpriv->drv_dbg;
- if (padapter->hw_init_completed == true) {
- if (adapter_to_pwrctl(padapter)->bips_processing == true) {
- if (padapter->netif_up == true) {
+ if (padapter->hw_init_completed) {
+ if (adapter_to_pwrctl(padapter)->bips_processing) {
+ if (padapter->netif_up) {
int cnt = 0;
u8 val8 = 0;
@@ -1110,10 +1092,10 @@ static u32 rtl8723bs_hal_deinit(struct adapter *padapter)
/* H2C done, enter 32k */
if (val8 == 0) {
/* ser rpwm to enter 32k */
- val8 = rtw_read8(padapter, SDIO_LOCAL_BASE|SDIO_REG_HRPWM1);
+ val8 = rtw_read8(padapter, SDIO_LOCAL_BASE | SDIO_REG_HRPWM1);
val8 += 0x80;
val8 |= BIT(0);
- rtw_write8(padapter, SDIO_LOCAL_BASE|SDIO_REG_HRPWM1, val8);
+ rtw_write8(padapter, SDIO_LOCAL_BASE | SDIO_REG_HRPWM1, val8);
DBG_871X("%s: write rpwm =%02x\n", __func__, val8);
adapter_to_pwrctl(padapter)->tog = (val8 + 0x80) & 0x80;
cnt = val8 = 0;
@@ -1205,7 +1187,7 @@ static void rtl8723bs_interface_configure(struct adapter *padapter)
switch (pHalData->OutEpNumber) {
case 3:
- pHalData->OutEpQueueSel = TX_SELE_HQ | TX_SELE_LQ|TX_SELE_NQ;
+ pHalData->OutEpQueueSel = TX_SELE_HQ | TX_SELE_LQ | TX_SELE_NQ;
break;
case 2:
pHalData->OutEpQueueSel = TX_SELE_HQ | TX_SELE_NQ;
@@ -1292,7 +1274,7 @@ static void Hal_EfuseParseBoardType_8723BS(
if (!AutoLoadFail) {
pHalData->BoardType = (hwinfo[EEPROM_RF_BOARD_OPTION_8723B] & 0xE0) >> 5;
if (pHalData->BoardType == 0xFF)
- pHalData->BoardType = (EEPROM_DEFAULT_BOARD_OPTION&0xE0)>>5;
+ pHalData->BoardType = (EEPROM_DEFAULT_BOARD_OPTION & 0xE0) >> 5;
} else
pHalData->BoardType = 0;
RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("Board Type: 0x%2x\n", pHalData->BoardType));
@@ -1387,7 +1369,7 @@ static s32 _ReadAdapterInfo8723BS(struct adapter *padapter)
RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("+_ReadAdapterInfo8723BS\n"));
/* before access eFuse, make sure card enable has been called */
- if (padapter->hw_init_completed == false)
+ if (!padapter->hw_init_completed)
_InitPowerOn_8723BS(padapter);
@@ -1404,7 +1386,7 @@ static s32 _ReadAdapterInfo8723BS(struct adapter *padapter)
_ReadPROMContent(padapter);
_InitOtherVariable(padapter);
- if (padapter->hw_init_completed == false) {
+ if (!padapter->hw_init_completed) {
rtw_write8(padapter, 0x67, 0x00); /* for BT, Switch Ant control to BT */
CardDisableRTL8723BSdio(padapter);/* for the power consumption issue, wifi ko module is loaded during booting, but wifi GUI is off */
}
@@ -1429,7 +1411,6 @@ static void ReadAdapterInfo8723BS(struct adapter *padapter)
*/
static void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val)
{
- struct hal_com_data *pHalData;
u8 val8;
#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN)
@@ -1449,8 +1430,6 @@ static void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val)
#endif
#endif
- pHalData = GET_HAL_DATA(padapter);
-
switch (variable) {
case HW_VAR_SET_RPWM:
/* rpwm value only use BIT0(clock bit) , BIT6(Ack bit), and BIT7(Toggle bit) */
@@ -1460,7 +1439,7 @@ static void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val)
{
val8 = *val;
val8 &= 0xC1;
- rtw_write8(padapter, SDIO_LOCAL_BASE|SDIO_REG_HRPWM1, val8);
+ rtw_write8(padapter, SDIO_LOCAL_BASE | SDIO_REG_HRPWM1, val8);
}
break;
case HW_VAR_SET_REQ_FW_PS:
@@ -1496,9 +1475,9 @@ static void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val)
/* 2. RX DMA stop */
DBG_871X_LEVEL(_drv_always_, "Pause DMA\n");
- rtw_write32(padapter, REG_RXPKT_NUM, (rtw_read32(padapter, REG_RXPKT_NUM)|RW_RELEASE_EN));
+ rtw_write32(padapter, REG_RXPKT_NUM, (rtw_read32(padapter, REG_RXPKT_NUM) | RW_RELEASE_EN));
do {
- if ((rtw_read32(padapter, REG_RXPKT_NUM)&RXDMA_IDLE)) {
+ if ((rtw_read32(padapter, REG_RXPKT_NUM) & RXDMA_IDLE)) {
DBG_871X_LEVEL(_drv_always_, "RX_DMA_IDLE is true\n");
break;
} else {
@@ -1530,7 +1509,7 @@ static void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val)
sdio_local_read(padapter, SDIO_REG_HIMR, 4, (u8 *)&tmp);
DBG_871X("DisableInterruptButCpwm28723BSdio(): Read SDIO_REG_HIMR: 0x%08x\n", tmp);
- himr = cpu_to_le32(SDIO_HIMR_DISABLED)|SDIO_HIMR_CPWM2_MSK;
+ himr = cpu_to_le32(SDIO_HIMR_DISABLED) | SDIO_HIMR_CPWM2_MSK;
sdio_local_write(padapter, SDIO_REG_HIMR, 4, (u8 *)&himr);
sdio_local_read(padapter, SDIO_REG_HIMR, 4, (u8 *)&tmp);
@@ -1545,7 +1524,7 @@ static void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val)
DBG_871X_LEVEL(_drv_always_, "Check EnableWoWlan CMD is ready\n");
mstatus = rtw_read8(padapter, REG_WOW_CTRL);
trycnt = 10;
- while (!(mstatus&BIT1) && trycnt > 1) {
+ while (!(mstatus & BIT1) && trycnt > 1) {
mstatus = rtw_read8(padapter, REG_WOW_CTRL);
DBG_871X("Loop index: %d :0x%02x\n", trycnt, mstatus);
trycnt--;
@@ -1558,7 +1537,7 @@ static void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val)
DBG_871X_LEVEL(_drv_always_, "WOWLAN_DISABLE\n");
psta = rtw_get_stainfo(&padapter->stapriv, get_bssid(pmlmepriv));
- if (psta != NULL)
+ if (psta)
rtl8723b_set_FwMediaStatusRpt_cmd(padapter, RT_MEDIA_DISCONNECT, psta->mac_id);
else
DBG_871X("psta is null\n");
@@ -1603,7 +1582,7 @@ static void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val)
DBG_871X_LEVEL(_drv_always_, "Check DisableWoWlan CMD is ready\n");
mstatus = rtw_read8(padapter, REG_WOW_CTRL);
trycnt = 50;
- while (mstatus&BIT1 && trycnt > 1) {
+ while (mstatus & BIT1 && trycnt > 1) {
mstatus = rtw_read8(padapter, REG_WOW_CTRL);
DBG_871X_LEVEL(_drv_always_, "Loop index: %d :0x%02x\n", trycnt, mstatus);
trycnt--;
@@ -1613,9 +1592,9 @@ static void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val)
if (mstatus & BIT1) {
DBG_871X_LEVEL(_drv_always_, "Disable WOW mode fail!!\n");
DBG_871X("Set 0x690 = 0x00\n");
- rtw_write8(padapter, REG_WOW_CTRL, (rtw_read8(padapter, REG_WOW_CTRL)&0xf0));
+ rtw_write8(padapter, REG_WOW_CTRL, (rtw_read8(padapter, REG_WOW_CTRL) & 0xf0));
DBG_871X_LEVEL(_drv_always_, "Release RXDMA\n");
- rtw_write32(padapter, REG_RXPKT_NUM, (rtw_read32(padapter, REG_RXPKT_NUM)&(~RW_RELEASE_EN)));
+ rtw_write32(padapter, REG_RXPKT_NUM, (rtw_read32(padapter, REG_RXPKT_NUM) & (~RW_RELEASE_EN)));
}
/* 3.1 read fw iv */
@@ -1673,7 +1652,7 @@ static void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val)
(pwrctl->wowlan_wake_reason != Rx_DeAuth)
) {
rtl8723b_set_FwJoinBssRpt_cmd(padapter, RT_MEDIA_CONNECT);
- if (psta != NULL)
+ if (psta)
rtl8723b_set_FwMediaStatusRpt_cmd(padapter, RT_MEDIA_CONNECT, psta->mac_id);
}
#ifdef CONFIG_PNO_SUPPORT
@@ -1706,9 +1685,9 @@ static void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val)
/* 2. RX DMA stop */
DBG_871X_LEVEL(_drv_always_, "Pause DMA\n");
rtw_write32(padapter, REG_RXPKT_NUM,
- (rtw_read32(padapter, REG_RXPKT_NUM)|RW_RELEASE_EN));
+ (rtw_read32(padapter, REG_RXPKT_NUM) | RW_RELEASE_EN));
do {
- if ((rtw_read32(padapter, REG_RXPKT_NUM)&RXDMA_IDLE)) {
+ if ((rtw_read32(padapter, REG_RXPKT_NUM) & RXDMA_IDLE)) {
DBG_871X_LEVEL(_drv_always_, "RX_DMA_IDLE is true\n");
break;
} else {
@@ -1742,7 +1721,7 @@ static void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val)
sdio_local_read(padapter, SDIO_REG_HIMR, 4, (u8 *)&tmp);
DBG_871X("DisableInterruptButCpwm28723BSdio(): Read SDIO_REG_HIMR: 0x%08x\n", tmp);
- himr = cpu_to_le32(SDIO_HIMR_DISABLED)|SDIO_HIMR_CPWM2_MSK;
+ himr = cpu_to_le32(SDIO_HIMR_DISABLED) | SDIO_HIMR_CPWM2_MSK;
sdio_local_write(padapter, SDIO_REG_HIMR, 4, (u8 *)&himr);
sdio_local_read(padapter, SDIO_REG_HIMR, 4, (u8 *)&tmp);
@@ -1808,7 +1787,7 @@ static void GetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val)
{
switch (variable) {
case HW_VAR_CPWM:
- *val = rtw_read8(padapter, SDIO_LOCAL_BASE|SDIO_REG_HCPWM1_8723B);
+ *val = rtw_read8(padapter, SDIO_LOCAL_BASE | SDIO_REG_HCPWM1_8723B);
break;
case HW_VAR_FW_PS_STATE:
diff --git a/drivers/staging/rtl8723bs/hal/sdio_ops.c b/drivers/staging/rtl8723bs/hal/sdio_ops.c
index a60162046e5a..301d327d0624 100644
--- a/drivers/staging/rtl8723bs/hal/sdio_ops.c
+++ b/drivers/staging/rtl8723bs/hal/sdio_ops.c
@@ -214,7 +214,7 @@ static u32 sdio_read32(struct intf_hdl *intfhdl, u32 addr)
ftaddr &= ~(u16)0x3;
sd_read(intfhdl, ftaddr, 8, tmpbuf);
- memcpy(&le_tmp, tmpbuf+shift, 4);
+ memcpy(&le_tmp, tmpbuf + shift, 4);
val = le32_to_cpu(le_tmp);
kfree(tmpbuf);
@@ -261,7 +261,7 @@ static s32 sdio_readN(struct intf_hdl *intfhdl, u32 addr, u32 cnt, u8 *buf)
err = sd_read(intfhdl, ftaddr, n, tmpbuf);
if (!err)
- memcpy(buf, tmpbuf+shift, cnt);
+ memcpy(buf, tmpbuf + shift, cnt);
kfree(tmpbuf);
}
return err;
@@ -366,7 +366,7 @@ static s32 sdio_writeN(struct intf_hdl *intfhdl, u32 addr, u32 cnt, u8 *buf)
kfree(tmpbuf);
return err;
}
- memcpy(tmpbuf+shift, buf, cnt);
+ memcpy(tmpbuf + shift, buf, cnt);
err = sd_write(intfhdl, ftaddr, n, tmpbuf);
kfree(tmpbuf);
}
@@ -727,8 +727,8 @@ static s32 ReadInterrupt8723BSdio(struct adapter *adapter, u32 *phisr)
hisr = 0;
while (hisr_len != 0) {
hisr_len--;
- val8 = SdioLocalCmd52Read1Byte(adapter, SDIO_REG_HISR+hisr_len);
- hisr |= (val8 << (8*hisr_len));
+ val8 = SdioLocalCmd52Read1Byte(adapter, SDIO_REG_HISR + hisr_len);
+ hisr |= (val8 << (8 * hisr_len));
}
*phisr = hisr;
@@ -795,38 +795,6 @@ void InitSysInterrupt8723BSdio(struct adapter *adapter)
0);
}
-#ifdef CONFIG_WOWLAN
-/* */
-/* Description: */
-/* Clear corresponding SDIO Host ISR interrupt service. */
-/* */
-/* Assumption: */
-/* Using SDIO Local register ONLY for configuration. */
-/* */
-/* Created by Roger, 2011.02.11. */
-/* */
-void clearinterrupt8723bsdio(struct adapter *adapter)
-{
- struct hal_com_data *haldata;
- u8 *clear;
-
- if (adapter->bSurpriseRemoved)
- return;
-
- haldata = GET_HAL_DATA(adapter);
- clear = rtw_zmalloc(4);
-
- /* Clear corresponding HISR Content if needed */
- *(__le32 *)clear = cpu_to_le32(haldata->sdio_hisr & MASK_SDIO_HISR_CLEAR);
- if (*(__le32 *)clear) {
- /* Perform write one clear operation */
- sdio_local_write(padapter, SDIO_REG_HISR, 4, clear);
- }
-
- kfree(clear);
-}
-#endif
-
/* */
/* Description: */
/* Enalbe SDIO Host Interrupt Mask configuration on SDIO local domain. */
@@ -952,7 +920,7 @@ static struct recv_buf *sd_recv_rxfifo(struct adapter *adapter, u32 size)
recvbuf->pskb->dev = adapter->pnetdev;
tmpaddr = (SIZE_PTR)recvbuf->pskb->data;
- alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1);
+ alignment = tmpaddr & (RECVBUFF_ALIGN_SZ - 1);
skb_reserve(recvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment));
}
@@ -1045,21 +1013,19 @@ void sd_int_dpc(struct adapter *adapter)
}
}
- if (hal->sdio_hisr & SDIO_HISR_TXBCNOK) {
+ if (hal->sdio_hisr & SDIO_HISR_TXBCNOK)
DBG_8192C("%s: SDIO_HISR_TXBCNOK\n", __func__);
- }
- if (hal->sdio_hisr & SDIO_HISR_TXBCNERR) {
+ if (hal->sdio_hisr & SDIO_HISR_TXBCNERR)
DBG_8192C("%s: SDIO_HISR_TXBCNERR\n", __func__);
- }
#ifndef CONFIG_C2H_PACKET_EN
if (hal->sdio_hisr & SDIO_HISR_C2HCMD) {
struct c2h_evt_hdr_88xx *c2h_evt;
DBG_8192C("%s: C2H Command\n", __func__);
c2h_evt = rtw_zmalloc(16);
- if (c2h_evt != NULL) {
- if (rtw_hal_c2h_evt_read(adapter, (u8 *)c2h_evt) == _SUCCESS) {
+ if (c2h_evt) {
+ if (c2h_evt_read_88xx(adapter, (u8 *)c2h_evt) == _SUCCESS) {
if (c2h_id_filter_ccx_8723b((u8 *)c2h_evt)) {
/* Handle CCX report here */
rtw_hal_c2h_handler(adapter, (u8 *)c2h_evt);
@@ -1077,13 +1043,12 @@ void sd_int_dpc(struct adapter *adapter)
}
#endif
- if (hal->sdio_hisr & SDIO_HISR_RXFOVW) {
+ if (hal->sdio_hisr & SDIO_HISR_RXFOVW)
DBG_8192C("%s: Rx Overflow\n", __func__);
- }
- if (hal->sdio_hisr & SDIO_HISR_RXERR) {
+ if (hal->sdio_hisr & SDIO_HISR_RXERR)
DBG_8192C("%s: Rx Error\n", __func__);
- }
+
if (hal->sdio_hisr & SDIO_HISR_RX_REQUEST) {
struct recv_buf *recvbuf;
@@ -1143,9 +1108,8 @@ void sd_int_hdl(struct adapter *adapter)
/* clear HISR */
v32 = hal->sdio_hisr & MASK_SDIO_HISR_CLEAR;
- if (v32) {
+ if (v32)
SdioLocalCmd52Write4Byte(adapter, SDIO_REG_HISR, v32);
- }
sd_int_dpc(adapter);
} else {
@@ -1194,12 +1158,11 @@ u8 HalQueryTxBufferStatus8723BSdio(struct adapter *adapter)
/* Description: */
/* Query SDIO Local register to get the current number of TX OQT Free Space. */
/* */
-u8 HalQueryTxOQTBufferStatus8723BSdio(struct adapter *adapter)
+void HalQueryTxOQTBufferStatus8723BSdio(struct adapter *adapter)
{
struct hal_com_data *haldata = GET_HAL_DATA(adapter);
haldata->SdioTxOQTFreeSpace = SdioLocalCmd52Read1Byte(adapter, SDIO_REG_OQT_FREE_PG);
- return true;
}
#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN)
@@ -1207,7 +1170,6 @@ u8 RecvOnePkt(struct adapter *adapter, u32 size)
{
struct recv_buf *recvbuf;
struct dvobj_priv *sddev;
- struct sdio_data *psdio;
struct sdio_func *func;
u8 res = false;
diff --git a/drivers/staging/rtl8723bs/include/drv_types.h b/drivers/staging/rtl8723bs/include/drv_types.h
index 0fd84c93e72b..96346ce064aa 100644
--- a/drivers/staging/rtl8723bs/include/drv_types.h
+++ b/drivers/staging/rtl8723bs/include/drv_types.h
@@ -673,7 +673,7 @@ int rtw_config_gpio(struct net_device *netdev, int gpio_num, bool isOutput);
#endif
#ifdef CONFIG_WOWLAN
-int rtw_suspend_wow(struct adapter *padapter);
+void rtw_suspend_wow(struct adapter *padapter);
int rtw_resume_process_wow(struct adapter *padapter);
#endif
diff --git a/drivers/staging/rtl8723bs/include/hal_btcoex.h b/drivers/staging/rtl8723bs/include/hal_btcoex.h
index 4066b0a1450c..6f7514be998f 100644
--- a/drivers/staging/rtl8723bs/include/hal_btcoex.h
+++ b/drivers/staging/rtl8723bs/include/hal_btcoex.h
@@ -23,7 +23,7 @@ void DBG_BT_INFO(u8 *dbgmsg);
void hal_btcoex_SetBTCoexist(struct adapter *padapter, u8 bBtExist);
u8 hal_btcoex_IsBtExist(struct adapter *padapter);
-u8 hal_btcoex_IsBtDisabled(struct adapter *);
+bool hal_btcoex_IsBtDisabled(struct adapter *);
void hal_btcoex_SetChipType(struct adapter *padapter, u8 chipType);
void hal_btcoex_SetPgAntNum(struct adapter *padapter, u8 antNum);
void hal_btcoex_SetSingleAntPath(struct adapter *padapter, u8 singleAntPath);
@@ -43,7 +43,7 @@ void hal_btcoex_BtInfoNotify(struct adapter *padapter, u8 length, u8 *tmpBuf);
void hal_btcoex_SuspendNotify(struct adapter *padapter, u8 state);
void hal_btcoex_HaltNotify(struct adapter *padapter);
-void hal_btcoex_Hanlder(struct adapter *padapter);
+void hal_btcoex_Handler(struct adapter *padapter);
s32 hal_btcoex_IsBTCoexCtrlAMPDUSize(struct adapter *padapter);
void hal_btcoex_SetManualControl(struct adapter *padapter, u8 bmanual);
diff --git a/drivers/staging/rtl8723bs/include/hal_com.h b/drivers/staging/rtl8723bs/include/hal_com.h
index d1c5b3193043..f5c3ce5da70c 100644
--- a/drivers/staging/rtl8723bs/include/hal_com.h
+++ b/drivers/staging/rtl8723bs/include/hal_com.h
@@ -232,7 +232,6 @@ void rtw_init_hal_com_default_value(struct adapter * Adapter);
void c2h_evt_clear(struct adapter *adapter);
s32 c2h_evt_read_88xx(struct adapter *adapter, u8 *buf);
-u8 rtw_hal_networktype_to_raid(struct adapter *adapter, struct sta_info *psta);
u8 rtw_get_mgntframe_raid(struct adapter *adapter, unsigned char network_type);
void rtw_hal_update_sta_rate_mask(struct adapter *padapter, struct sta_info *psta);
diff --git a/drivers/staging/rtl8723bs/include/hal_intf.h b/drivers/staging/rtl8723bs/include/hal_intf.h
index 19ceb4aa753e..3a0c3d079d50 100644
--- a/drivers/staging/rtl8723bs/include/hal_intf.h
+++ b/drivers/staging/rtl8723bs/include/hal_intf.h
@@ -388,7 +388,6 @@ void rtw_hal_notch_filter(struct adapter * adapter, bool enable);
void rtw_hal_reset_security_engine(struct adapter * adapter);
bool rtw_hal_c2h_valid(struct adapter *adapter, u8 *buf);
-s32 rtw_hal_c2h_evt_read(struct adapter *adapter, u8 *buf);
s32 rtw_hal_c2h_handler(struct adapter *adapter, u8 *c2h_evt);
c2h_id_filter rtw_hal_c2h_id_filter_ccx(struct adapter *adapter);
diff --git a/drivers/staging/rtl8723bs/include/ieee80211.h b/drivers/staging/rtl8723bs/include/ieee80211.h
index 74c028fbe8f7..2110552b8e59 100644
--- a/drivers/staging/rtl8723bs/include/ieee80211.h
+++ b/drivers/staging/rtl8723bs/include/ieee80211.h
@@ -1138,7 +1138,7 @@ int rtw_get_wapi_ie(u8 *in_ie, uint in_len, u8 *wapi_ie, u16 *wapi_len);
int rtw_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x);
int rtw_parse_wpa2_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x);
-int rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie, u16 *wpa_len);
+void rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie, u16 *wpa_len);
u8 rtw_is_wps_ie(u8 *ie_ptr, uint *wps_ielen);
u8 *rtw_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen);
diff --git a/drivers/staging/rtl8723bs/include/osdep_intf.h b/drivers/staging/rtl8723bs/include/osdep_intf.h
index 0ea91a111da3..40313d17a242 100644
--- a/drivers/staging/rtl8723bs/include/osdep_intf.h
+++ b/drivers/staging/rtl8723bs/include/osdep_intf.h
@@ -46,7 +46,7 @@ void devobj_deinit(struct dvobj_priv *pdvobj);
u8 rtw_init_drv_sw(struct adapter *padapter);
u8 rtw_free_drv_sw(struct adapter *padapter);
-u8 rtw_reset_drv_sw(struct adapter *padapter);
+void rtw_reset_drv_sw(struct adapter *padapter);
void rtw_dev_unload(struct adapter *padapter);
u32 rtw_start_drv_threads(struct adapter *padapter);
diff --git a/drivers/staging/rtl8723bs/include/osdep_service.h b/drivers/staging/rtl8723bs/include/osdep_service.h
index 76d619585046..d2616af95ffa 100644
--- a/drivers/staging/rtl8723bs/include/osdep_service.h
+++ b/drivers/staging/rtl8723bs/include/osdep_service.h
@@ -178,8 +178,6 @@ extern int rtw_retrive_from_file(char *path, u8 *buf, u32 sz);
extern void rtw_free_netdev(struct net_device * netdev);
-extern u64 rtw_modular64(u64 x, u64 y);
-
/* Macros for handling unaligned memory accesses */
#define RTW_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1]))
diff --git a/drivers/staging/rtl8723bs/include/recv_osdep.h b/drivers/staging/rtl8723bs/include/recv_osdep.h
index 6fea0e948271..1056f615d0f9 100644
--- a/drivers/staging/rtl8723bs/include/recv_osdep.h
+++ b/drivers/staging/rtl8723bs/include/recv_osdep.h
@@ -22,14 +22,14 @@ int rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter);
void rtw_free_recv_priv (struct recv_priv *precvpriv);
-int rtw_os_recv_resource_alloc(struct adapter *padapter, union recv_frame *precvframe);
+void rtw_os_recv_resource_alloc(struct adapter *padapter, union recv_frame *precvframe);
void rtw_os_recv_resource_free(struct recv_priv *precvpriv);
void rtw_os_free_recvframe(union recv_frame *precvframe);
-int rtw_os_recvbuf_resource_free(struct adapter *padapter, struct recv_buf *precvbuf);
+void rtw_os_recvbuf_resource_free(struct adapter *padapter, struct recv_buf *precvbuf);
_pkt *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8 *pdata);
void rtw_os_recv_indicate_pkt(struct adapter *padapter, _pkt *pkt, struct rx_pkt_attrib *pattrib);
diff --git a/drivers/staging/rtl8723bs/include/rtw_ap.h b/drivers/staging/rtl8723bs/include/rtw_ap.h
index fd56c9db16a9..4a1ed9eff83a 100644
--- a/drivers/staging/rtl8723bs/include/rtw_ap.h
+++ b/drivers/staging/rtl8723bs/include/rtw_ap.h
@@ -19,7 +19,7 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len);
void rtw_ap_restore_network(struct adapter *padapter);
void rtw_set_macaddr_acl(struct adapter *padapter, int mode);
int rtw_acl_add_sta(struct adapter *padapter, u8 *addr);
-int rtw_acl_remove_sta(struct adapter *padapter, u8 *addr);
+void rtw_acl_remove_sta(struct adapter *padapter, u8 *addr);
u8 rtw_ap_set_pairwise_key(struct adapter *padapter, struct sta_info *psta);
int rtw_ap_set_group_key(struct adapter *padapter, u8 *key, u8 alg, int keyid);
@@ -31,7 +31,7 @@ u8 bss_cap_update_on_sta_leave(struct adapter *padapter, struct sta_info *psta);
void sta_info_update(struct adapter *padapter, struct sta_info *psta);
void ap_sta_info_defer_update(struct adapter *padapter, struct sta_info *psta);
u8 ap_free_sta(struct adapter *padapter, struct sta_info *psta, bool active, u16 reason);
-int rtw_sta_flush(struct adapter *padapter);
+void rtw_sta_flush(struct adapter *padapter);
void start_ap_mode(struct adapter *padapter);
void stop_ap_mode(struct adapter *padapter);
diff --git a/drivers/staging/rtl8723bs/include/rtw_btcoex.h b/drivers/staging/rtl8723bs/include/rtw_btcoex.h
index 53f49c6b2fcd..19764c80b8ba 100644
--- a/drivers/staging/rtl8723bs/include/rtw_btcoex.h
+++ b/drivers/staging/rtl8723bs/include/rtw_btcoex.h
@@ -15,36 +15,8 @@
#define PACKET_ARP 2
#define PACKET_EAPOL 3
-void rtw_btcoex_Initialize(struct adapter *);
-void rtw_btcoex_PowerOnSetting(struct adapter *padapter);
-void rtw_btcoex_HAL_Initialize(struct adapter *padapter, u8 bWifiOnly);
-void rtw_btcoex_IpsNotify(struct adapter *, u8 type);
-void rtw_btcoex_LpsNotify(struct adapter *, u8 type);
-void rtw_btcoex_ScanNotify(struct adapter *, u8 type);
-void rtw_btcoex_ConnectNotify(struct adapter *, u8 action);
void rtw_btcoex_MediaStatusNotify(struct adapter *, u8 mediaStatus);
-void rtw_btcoex_SpecialPacketNotify(struct adapter *, u8 pktType);
-void rtw_btcoex_IQKNotify(struct adapter *padapter, u8 state);
-void rtw_btcoex_BtInfoNotify(struct adapter *, u8 length, u8 *tmpBuf);
-void rtw_btcoex_SuspendNotify(struct adapter *, u8 state);
void rtw_btcoex_HaltNotify(struct adapter *);
-u8 rtw_btcoex_IsBtDisabled(struct adapter *);
-void rtw_btcoex_Handler(struct adapter *);
-s32 rtw_btcoex_IsBTCoexCtrlAMPDUSize(struct adapter *);
-void rtw_btcoex_SetManualControl(struct adapter *, u8 bmanual);
-u8 rtw_btcoex_IsBtControlLps(struct adapter *);
-u8 rtw_btcoex_IsLpsOn(struct adapter *);
-u8 rtw_btcoex_RpwmVal(struct adapter *);
-u8 rtw_btcoex_LpsVal(struct adapter *);
-void rtw_btcoex_SetBTCoexist(struct adapter *, u8 bBtExist);
-void rtw_btcoex_SetChipType(struct adapter *, u8 chipType);
-void rtw_btcoex_SetPGAntNum(struct adapter *, u8 antNum);
-void rtw_btcoex_SetSingleAntPath(struct adapter *padapter, u8 singleAntPath);
-u32 rtw_btcoex_GetRaMask(struct adapter *);
-void rtw_btcoex_RecordPwrMode(struct adapter *, u8 *pCmdBuf, u8 cmdLen);
-void rtw_btcoex_DisplayBtCoexInfo(struct adapter *, u8 *pbuf, u32 bufsize);
-void rtw_btcoex_SetDBG(struct adapter *, u32 *pDbgModule);
-u32 rtw_btcoex_GetDBG(struct adapter *, u8 *pStrBuf, u32 bufSize);
/* ================================================== */
/* Below Functions are called by BT-Coex */
diff --git a/drivers/staging/rtl8723bs/include/rtw_mlme.h b/drivers/staging/rtl8723bs/include/rtw_mlme.h
index 2693b554f414..d3c07d1c36e9 100644
--- a/drivers/staging/rtl8723bs/include/rtw_mlme.h
+++ b/drivers/staging/rtl8723bs/include/rtw_mlme.h
@@ -589,7 +589,6 @@ extern void rtw_scan_timeout_handler(struct timer_list *t);
extern void rtw_dynamic_check_timer_handler(struct adapter *adapter);
bool rtw_is_scan_deny(struct adapter *adapter);
void rtw_clear_scan_deny(struct adapter *adapter);
-void rtw_set_scan_deny_timer_hdl(struct adapter *adapter);
void rtw_set_scan_deny(struct adapter *adapter, u32 ms);
void rtw_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv);
@@ -607,8 +606,6 @@ extern void _rtw_free_network_nolock(struct mlme_priv *pmlmepriv, struct wlan_ne
extern struct wlan_network* _rtw_find_network(struct __queue *scanned_queue, u8 *addr);
-extern void _rtw_free_network_queue(struct adapter *padapter, u8 isfreeall);
-
extern sint rtw_if_up(struct adapter *padapter);
sint rtw_linked_check(struct adapter *padapter);
diff --git a/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h b/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h
index f6eabad4bbe0..733bb9425448 100644
--- a/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h
+++ b/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h
@@ -544,7 +544,7 @@ extern struct xmit_frame *alloc_mgtxmitframe(struct xmit_priv *pxmitpriv);
/* void fill_fwpriv(struct adapter *padapter, struct fw_priv *pfwpriv); */
-unsigned char networktype_to_raid_ex(struct adapter *adapter, struct sta_info *psta);
+u8 networktype_to_raid_ex(struct adapter *adapter, struct sta_info *psta);
void get_rate_set(struct adapter *padapter, unsigned char *pbssrate, int *bssrate_len);
void set_mcs_rate_by_mask(u8 *mcs_set, u32 mask);
diff --git a/drivers/staging/rtl8723bs/include/sdio_ops.h b/drivers/staging/rtl8723bs/include/sdio_ops.h
index 0f117ff1fbbe..6b0446be6d19 100644
--- a/drivers/staging/rtl8723bs/include/sdio_ops.h
+++ b/drivers/staging/rtl8723bs/include/sdio_ops.h
@@ -33,7 +33,7 @@ extern void InitSysInterrupt8723BSdio(struct adapter *padapter);
extern void EnableInterrupt8723BSdio(struct adapter *padapter);
extern void DisableInterrupt8723BSdio(struct adapter *padapter);
extern u8 HalQueryTxBufferStatus8723BSdio(struct adapter *padapter);
-extern u8 HalQueryTxOQTBufferStatus8723BSdio(struct adapter *padapter);
+extern void HalQueryTxOQTBufferStatus8723BSdio(struct adapter *padapter);
#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN)
extern void ClearInterrupt8723BSdio(struct adapter *padapter);
#endif /* CONFIG_WOWLAN */
diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
index db553f2e4c0b..9bc685632651 100644
--- a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
+++ b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
@@ -1650,7 +1650,7 @@ static int cfg80211_rtw_scan(struct wiphy *wiphy
}
check_need_indicate_scan_done:
- if (true == need_indicate_scan_done)
+ if (need_indicate_scan_done)
{
rtw_cfg80211_surveydone_event_callback(padapter);
rtw_cfg80211_indicate_scan_done(padapter, false);
@@ -2439,23 +2439,7 @@ void rtw_cfg80211_indicate_sta_disassoc(struct adapter *padapter, unsigned char
cfg80211_del_sta(ndev, da, GFP_ATOMIC);
}
-static int rtw_cfg80211_monitor_if_open(struct net_device *ndev)
-{
- int ret = 0;
-
- DBG_8192C("%s\n", __func__);
-
- return ret;
-}
-
-static int rtw_cfg80211_monitor_if_close(struct net_device *ndev)
-{
- int ret = 0;
-
- DBG_8192C("%s\n", __func__);
- return ret;
-}
static netdev_tx_t rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb, struct net_device *ndev)
{
@@ -2604,20 +2588,10 @@ fail:
}
-static int rtw_cfg80211_monitor_if_set_mac_address(struct net_device *ndev, void *addr)
-{
- int ret = 0;
- DBG_8192C("%s\n", __func__);
-
- return ret;
-}
static const struct net_device_ops rtw_cfg80211_monitor_if_ops = {
- .ndo_open = rtw_cfg80211_monitor_if_open,
- .ndo_stop = rtw_cfg80211_monitor_if_close,
- .ndo_start_xmit = rtw_cfg80211_monitor_if_xmit_entry,
- .ndo_set_mac_address = rtw_cfg80211_monitor_if_set_mac_address,
+ .ndo_start_xmit = rtw_cfg80211_monitor_if_xmit_entry,
};
static int rtw_cfg80211_add_monitor_if (struct adapter *padapter, char *name, struct net_device **ndev)
@@ -2896,9 +2870,9 @@ static int cfg80211_rtw_del_station(struct wiphy *wiphy, struct net_device *ndev
flush_all_cam_entry(padapter); /* clear CAM */
- ret = rtw_sta_flush(padapter);
+ rtw_sta_flush(padapter);
- return ret;
+ return 0;
}
diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c
index e3d356952875..99e6b1028f71 100644
--- a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c
+++ b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c
@@ -10,6 +10,7 @@
#include <drv_types.h>
#include <rtw_debug.h>
#include <rtw_mp.h>
+#include <hal_btcoex.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
@@ -55,7 +56,7 @@ void rtw_indicate_wx_assoc_event(struct adapter *padapter)
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
- struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex*)(&(pmlmeinfo->network));
+ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&(pmlmeinfo->network));
memset(&wrqu, 0, sizeof(union iwreq_data));
@@ -235,8 +236,7 @@ static char *translate_scan(struct adapter *padapter,
u8 wpa_ie[255], rsn_ie[255];
u16 wpa_len = 0, rsn_len = 0;
u8 *p;
- sint out_len = 0;
- out_len =rtw_get_sec_ie(pnetwork->network.IEs , pnetwork->network.IELength, rsn_ie,&rsn_len, wpa_ie,&wpa_len);
+ rtw_get_sec_ie(pnetwork->network.IEs, pnetwork->network.IELength, rsn_ie, &rsn_len, wpa_ie, &wpa_len);
RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_scan: ssid =%s\n", pnetwork->network.Ssid.Ssid));
RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_scan: wpa_len =%d rsn_len =%d\n", wpa_len, rsn_len));
@@ -478,14 +478,12 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param,
if (wep_key_len > 0) {
wep_key_len = wep_key_len <= 5 ? 5 : 13;
wep_total_len = wep_key_len + FIELD_OFFSET(struct ndis_802_11_wep, KeyMaterial);
- pwep = rtw_malloc(wep_total_len);
+ pwep = kzalloc(wep_total_len, GFP_KERNEL);
if (pwep == NULL) {
RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, (" wpa_set_encryption: pwep allocate fail !!!\n"));
goto exit;
}
- memset(pwep, 0, wep_total_len);
-
pwep->KeyLength = wep_key_len;
pwep->Length = wep_total_len;
@@ -617,7 +615,7 @@ exit:
static int rtw_set_wpa_ie(struct adapter *padapter, char *pie, unsigned short ielen)
{
- u8 *buf = NULL, *pos = NULL;
+ u8 *buf = NULL;
int group_cipher = 0, pairwise_cipher = 0;
int ret = 0;
u8 null_addr[]= {0, 0, 0, 0, 0, 0};
@@ -647,7 +645,6 @@ static int rtw_set_wpa_ie(struct adapter *padapter, char *pie, unsigned short ie
DBG_871X("0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n", buf[i], buf[i+1], buf[i+2], buf[i+3], buf[i+4], buf[i+5], buf[i+6], buf[i+7]);
}
- pos = buf;
if (ielen < RSN_HEADER_LEN) {
RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("Ie len too short %d\n", ielen));
ret = -1;
@@ -946,7 +943,7 @@ static int rtw_wx_set_pmkid(struct net_device *dev,
u8 j, blInserted = false;
int intReturn = false;
struct security_priv *psecuritypriv = &padapter->securitypriv;
- struct iw_pmksa* pPMK = (struct iw_pmksa*)extra;
+ struct iw_pmksa* pPMK = (struct iw_pmksa *)extra;
u8 strZeroMacAddress[ ETH_ALEN ] = { 0x00 };
u8 strIssueBssid[ ETH_ALEN ] = { 0x00 };
@@ -1183,7 +1180,7 @@ static int rtw_wx_set_wap(struct net_device *dev,
spin_unlock_bh(&queue->lock);
goto exit;
}
- break;
+ break;
}
}
@@ -1671,45 +1668,45 @@ static int rtw_wx_set_rate(struct net_device *dev,
target_rate = target_rate/100000;
switch (target_rate) {
- case 10:
- ratevalue = 0;
- break;
- case 20:
- ratevalue = 1;
- break;
- case 55:
- ratevalue = 2;
- break;
- case 60:
- ratevalue = 3;
- break;
- case 90:
- ratevalue = 4;
- break;
- case 110:
- ratevalue = 5;
- break;
- case 120:
- ratevalue = 6;
- break;
- case 180:
- ratevalue = 7;
- break;
- case 240:
- ratevalue = 8;
- break;
- case 360:
- ratevalue = 9;
- break;
- case 480:
- ratevalue = 10;
- break;
- case 540:
- ratevalue = 11;
- break;
- default:
- ratevalue = 11;
- break;
+ case 10:
+ ratevalue = 0;
+ break;
+ case 20:
+ ratevalue = 1;
+ break;
+ case 55:
+ ratevalue = 2;
+ break;
+ case 60:
+ ratevalue = 3;
+ break;
+ case 90:
+ ratevalue = 4;
+ break;
+ case 110:
+ ratevalue = 5;
+ break;
+ case 120:
+ ratevalue = 6;
+ break;
+ case 180:
+ ratevalue = 7;
+ break;
+ case 240:
+ ratevalue = 8;
+ break;
+ case 360:
+ ratevalue = 9;
+ break;
+ case 480:
+ ratevalue = 10;
+ break;
+ case 540:
+ ratevalue = 11;
+ break;
+ default:
+ ratevalue = 11;
+ break;
}
set_rate:
@@ -2054,7 +2051,7 @@ static int rtw_wx_set_auth(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct iw_param *param = (struct iw_param*)&(wrqu->param);
+ struct iw_param *param = (struct iw_param *)&(wrqu->param);
int ret = 0;
switch (param->flags & IW_AUTH_INDEX) {
@@ -2144,12 +2141,10 @@ static int rtw_wx_set_enc_ext(struct net_device *dev,
int ret = 0;
param_len = sizeof(struct ieee_param) + pext->key_len;
- param = rtw_malloc(param_len);
+ param = kzalloc(param_len, GFP_KERNEL);
if (param == NULL)
return -1;
- memset(param, 0, param_len);
-
param->cmd = IEEE_CMD_SET_ENCRYPTION;
memset(param->sta_addr, 0xff, ETH_ALEN);
@@ -2267,22 +2262,22 @@ static int rtw_wx_read32(struct net_device *dev,
sscanf(ptmp, "%d,%x", &bytes, &addr);
switch (bytes) {
- case 1:
- data32 = rtw_read8(padapter, addr);
- sprintf(extra, "0x%02X", data32);
- break;
- case 2:
- data32 = rtw_read16(padapter, addr);
- sprintf(extra, "0x%04X", data32);
- break;
- case 4:
- data32 = rtw_read32(padapter, addr);
- sprintf(extra, "0x%08X", data32);
- break;
- default:
- DBG_871X(KERN_INFO "%s: usage> read [bytes],[address(hex)]\n", __func__);
- ret = -EINVAL;
- goto exit;
+ case 1:
+ data32 = rtw_read8(padapter, addr);
+ sprintf(extra, "0x%02X", data32);
+ break;
+ case 2:
+ data32 = rtw_read16(padapter, addr);
+ sprintf(extra, "0x%04X", data32);
+ break;
+ case 4:
+ data32 = rtw_read32(padapter, addr);
+ sprintf(extra, "0x%08X", data32);
+ break;
+ default:
+ DBG_871X(KERN_INFO "%s: usage> read [bytes],[address(hex)]\n", __func__);
+ ret = -EINVAL;
+ goto exit;
}
DBG_871X(KERN_INFO "%s: addr = 0x%08X data =%s\n", __func__, addr, extra);
@@ -2309,21 +2304,21 @@ static int rtw_wx_write32(struct net_device *dev,
sscanf(extra, "%d,%x,%x", &bytes, &addr, &data32);
switch (bytes) {
- case 1:
- rtw_write8(padapter, addr, (u8)data32);
- DBG_871X(KERN_INFO "%s: addr = 0x%08X data = 0x%02X\n", __func__, addr, (u8)data32);
- break;
- case 2:
- rtw_write16(padapter, addr, (u16)data32);
- DBG_871X(KERN_INFO "%s: addr = 0x%08X data = 0x%04X\n", __func__, addr, (u16)data32);
- break;
- case 4:
- rtw_write32(padapter, addr, data32);
- DBG_871X(KERN_INFO "%s: addr = 0x%08X data = 0x%08X\n", __func__, addr, data32);
- break;
- default:
- DBG_871X(KERN_INFO "%s: usage> write [bytes],[address(hex)],[data(hex)]\n", __func__);
- return -EINVAL;
+ case 1:
+ rtw_write8(padapter, addr, (u8)data32);
+ DBG_871X(KERN_INFO "%s: addr = 0x%08X data = 0x%02X\n", __func__, addr, (u8)data32);
+ break;
+ case 2:
+ rtw_write16(padapter, addr, (u16)data32);
+ DBG_871X(KERN_INFO "%s: addr = 0x%08X data = 0x%04X\n", __func__, addr, (u16)data32);
+ break;
+ case 4:
+ rtw_write32(padapter, addr, data32);
+ DBG_871X(KERN_INFO "%s: addr = 0x%08X data = 0x%08X\n", __func__, addr, data32);
+ break;
+ default:
+ DBG_871X(KERN_INFO "%s: usage> write [bytes],[address(hex)],[data(hex)]\n", __func__);
+ return -EINVAL;
}
return 0;
@@ -2337,8 +2332,8 @@ static int rtw_wx_read_rf(struct net_device *dev,
u32 path, addr, data32;
- path = *(u32*)extra;
- addr = *((u32*)extra + 1);
+ path = *(u32 *)extra;
+ addr = *((u32 *)extra + 1);
data32 = rtw_hal_read_rfreg(padapter, path, addr, 0xFFFFF);
/*
* IMPORTANT!!
@@ -2358,9 +2353,9 @@ static int rtw_wx_write_rf(struct net_device *dev,
u32 path, addr, data32;
- path = *(u32*)extra;
- addr = *((u32*)extra + 1);
- data32 = *((u32*)extra + 2);
+ path = *(u32 *)extra;
+ addr = *((u32 *)extra + 1);
+ data32 = *((u32 *)extra + 2);
/* DBG_871X("%s: path =%d addr = 0x%02x data = 0x%05x\n", __func__, path, addr, data32); */
rtw_hal_write_rfreg(padapter, path, addr, 0xFFFFF, data32);
@@ -2584,7 +2579,7 @@ static int rtw_wps_start(struct net_device *dev,
goto exit;
}
- uintRet = copy_from_user((void*)&u32wps_start, pdata->pointer, 4);
+ uintRet = copy_from_user((void *)&u32wps_start, pdata->pointer, 4);
if (u32wps_start == 0)
u32wps_start = *extra;
@@ -2601,9 +2596,7 @@ static int rtw_p2p_set(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
- int ret = 0;
-
- return ret;
+ return 0;
}
@@ -2612,9 +2605,7 @@ static int rtw_p2p_get(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
- int ret = 0;
-
- return ret;
+ return 0;
}
@@ -2623,9 +2614,7 @@ static int rtw_p2p_get2(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
- int ret = 0;
-
- return ret;
+ return 0;
}
@@ -2682,7 +2671,6 @@ static int rtw_dbg_port(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- int ret = 0;
u8 major_cmd, minor_cmd;
u16 arg;
u32 extra_arg, *pdata, val32;
@@ -2695,7 +2683,7 @@ static int rtw_dbg_port(struct net_device *dev,
struct sta_priv *pstapriv = &padapter->stapriv;
- pdata = (u32*)&wrqu->data;
+ pdata = (u32 *)&wrqu->data;
val32 = *pdata;
arg = (u16)(val32&0x0000ffff);
@@ -3097,7 +3085,7 @@ static int rtw_dbg_port(struct net_device *dev,
DBG_871X("enable driver ctrl ampdu density = %d\n", extra_arg);
- if ((extra_arg & 0x07) > 0x07)
+ if (extra_arg > 0x07)
padapter->driver_ampdu_spacing = 0xFF;
else
padapter->driver_ampdu_spacing = extra_arg;
@@ -3263,7 +3251,7 @@ static int rtw_dbg_port(struct net_device *dev,
}
- return ret;
+ return 0;
}
@@ -3366,23 +3354,23 @@ static int wpa_mlme(struct net_device *dev, u32 command, u32 reason)
struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
switch (command) {
- case IEEE_MLME_STA_DEAUTH:
+ case IEEE_MLME_STA_DEAUTH:
- if (!rtw_set_802_11_disassociate(padapter))
- ret = -1;
+ if (!rtw_set_802_11_disassociate(padapter))
+ ret = -1;
- break;
+ break;
- case IEEE_MLME_STA_DISASSOC:
+ case IEEE_MLME_STA_DISASSOC:
- if (!rtw_set_802_11_disassociate(padapter))
- ret = -1;
+ if (!rtw_set_802_11_disassociate(padapter))
+ ret = -1;
- break;
+ break;
- default:
- ret = -EOPNOTSUPP;
- break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
}
return ret;
@@ -3421,7 +3409,7 @@ static int wpa_supplicant_ioctl(struct net_device *dev, struct iw_point *p)
case IEEE_CMD_SET_WPA_IE:
/* ret = wpa_set_wpa_ie(dev, param, p->length); */
- ret = rtw_set_wpa_ie((struct adapter *)rtw_netdev_priv(dev), (char*)param->u.wpa_ie.data, (u16)param->u.wpa_ie.len);
+ ret = rtw_set_wpa_ie((struct adapter *)rtw_netdev_priv(dev), (char *)param->u.wpa_ie.data, (u16)param->u.wpa_ie.len);
break;
case IEEE_CMD_SET_ENCRYPTION:
@@ -3522,14 +3510,12 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param,
if (wep_key_len > 0) {
wep_key_len = wep_key_len <= 5 ? 5 : 13;
wep_total_len = wep_key_len + FIELD_OFFSET(struct ndis_802_11_wep, KeyMaterial);
- pwep = rtw_malloc(wep_total_len);
+ pwep = kzalloc(wep_total_len, GFP_KERNEL);
if (pwep == NULL) {
DBG_871X(" r871x_set_encryption: pwep allocate fail !!!\n");
goto exit;
}
- memset(pwep, 0, wep_total_len);
-
pwep->KeyLength = wep_key_len;
pwep->Length = wep_total_len;
@@ -3754,7 +3740,7 @@ static int rtw_set_beacon(struct net_device *dev, struct ieee_param *param, int
}
-static int rtw_hostapd_sta_flush(struct net_device *dev)
+static void rtw_hostapd_sta_flush(struct net_device *dev)
{
/* _irqL irqL; */
/* struct list_head *phead, *plist; */
@@ -3766,8 +3752,7 @@ static int rtw_hostapd_sta_flush(struct net_device *dev)
flush_all_cam_entry(padapter); /* clear CAM */
- return rtw_sta_flush(padapter);
-
+ rtw_sta_flush(padapter);
}
static int rtw_add_sta(struct net_device *dev, struct ieee_param *param)
@@ -3826,7 +3811,7 @@ static int rtw_add_sta(struct net_device *dev, struct ieee_param *param)
if (WLAN_STA_HT&flags) {
psta->htpriv.ht_option = true;
psta->qos_option = 1;
- memcpy((void*)&psta->htpriv.ht_cap, (void*)&param->u.add_sta.ht_cap, sizeof(struct rtw_ieee80211_ht_cap));
+ memcpy((void *)&psta->htpriv.ht_cap, (void *)&param->u.add_sta.ht_cap, sizeof(struct rtw_ieee80211_ht_cap));
} else {
psta->htpriv.ht_option = false;
}
@@ -4176,7 +4161,8 @@ static int rtw_ioctl_acl_remove_sta(struct net_device *dev, struct ieee_param *p
return -EINVAL;
}
- return rtw_acl_remove_sta(padapter, param->sta_addr);
+ rtw_acl_remove_sta(padapter, param->sta_addr);
+ return 0;
}
@@ -4252,94 +4238,94 @@ static int rtw_hostapd_ioctl(struct net_device *dev, struct iw_point *p)
/* DBG_871X("%s, cmd =%d\n", __func__, param->cmd); */
switch (param->cmd) {
- case RTL871X_HOSTAPD_FLUSH:
+ case RTL871X_HOSTAPD_FLUSH:
- ret = rtw_hostapd_sta_flush(dev);
+ rtw_hostapd_sta_flush(dev);
- break;
+ break;
- case RTL871X_HOSTAPD_ADD_STA:
+ case RTL871X_HOSTAPD_ADD_STA:
- ret = rtw_add_sta(dev, param);
+ ret = rtw_add_sta(dev, param);
- break;
+ break;
- case RTL871X_HOSTAPD_REMOVE_STA:
+ case RTL871X_HOSTAPD_REMOVE_STA:
- ret = rtw_del_sta(dev, param);
+ ret = rtw_del_sta(dev, param);
- break;
+ break;
- case RTL871X_HOSTAPD_SET_BEACON:
+ case RTL871X_HOSTAPD_SET_BEACON:
- ret = rtw_set_beacon(dev, param, p->length);
+ ret = rtw_set_beacon(dev, param, p->length);
- break;
+ break;
- case RTL871X_SET_ENCRYPTION:
+ case RTL871X_SET_ENCRYPTION:
- ret = rtw_set_encryption(dev, param, p->length);
+ ret = rtw_set_encryption(dev, param, p->length);
- break;
+ break;
- case RTL871X_HOSTAPD_GET_WPAIE_STA:
+ case RTL871X_HOSTAPD_GET_WPAIE_STA:
- ret = rtw_get_sta_wpaie(dev, param);
+ ret = rtw_get_sta_wpaie(dev, param);
- break;
+ break;
- case RTL871X_HOSTAPD_SET_WPS_BEACON:
+ case RTL871X_HOSTAPD_SET_WPS_BEACON:
- ret = rtw_set_wps_beacon(dev, param, p->length);
+ ret = rtw_set_wps_beacon(dev, param, p->length);
- break;
+ break;
- case RTL871X_HOSTAPD_SET_WPS_PROBE_RESP:
+ case RTL871X_HOSTAPD_SET_WPS_PROBE_RESP:
- ret = rtw_set_wps_probe_resp(dev, param, p->length);
+ ret = rtw_set_wps_probe_resp(dev, param, p->length);
- break;
+ break;
- case RTL871X_HOSTAPD_SET_WPS_ASSOC_RESP:
+ case RTL871X_HOSTAPD_SET_WPS_ASSOC_RESP:
- ret = rtw_set_wps_assoc_resp(dev, param, p->length);
+ ret = rtw_set_wps_assoc_resp(dev, param, p->length);
- break;
+ break;
- case RTL871X_HOSTAPD_SET_HIDDEN_SSID:
+ case RTL871X_HOSTAPD_SET_HIDDEN_SSID:
- ret = rtw_set_hidden_ssid(dev, param, p->length);
+ ret = rtw_set_hidden_ssid(dev, param, p->length);
- break;
+ break;
- case RTL871X_HOSTAPD_GET_INFO_STA:
+ case RTL871X_HOSTAPD_GET_INFO_STA:
- ret = rtw_ioctl_get_sta_data(dev, param, p->length);
+ ret = rtw_ioctl_get_sta_data(dev, param, p->length);
- break;
+ break;
- case RTL871X_HOSTAPD_SET_MACADDR_ACL:
+ case RTL871X_HOSTAPD_SET_MACADDR_ACL:
- ret = rtw_ioctl_set_macaddr_acl(dev, param, p->length);
+ ret = rtw_ioctl_set_macaddr_acl(dev, param, p->length);
- break;
+ break;
- case RTL871X_HOSTAPD_ACL_ADD_STA:
+ case RTL871X_HOSTAPD_ACL_ADD_STA:
- ret = rtw_ioctl_acl_add_sta(dev, param, p->length);
+ ret = rtw_ioctl_acl_add_sta(dev, param, p->length);
- break;
+ break;
- case RTL871X_HOSTAPD_ACL_REMOVE_STA:
+ case RTL871X_HOSTAPD_ACL_REMOVE_STA:
- ret = rtw_ioctl_acl_remove_sta(dev, param, p->length);
+ ret = rtw_ioctl_acl_remove_sta(dev, param, p->length);
- break;
+ break;
- default:
- DBG_871X("Unknown hostapd request: %d\n", param->cmd);
- ret = -EOPNOTSUPP;
- break;
+ default:
+ DBG_871X("Unknown hostapd request: %d\n", param->cmd);
+ ret = -EOPNOTSUPP;
+ break;
}
@@ -4370,7 +4356,7 @@ static int rtw_wx_set_priv(struct net_device *dev,
char *ext;
struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct iw_point *dwrq = (struct iw_point*)awrq;
+ struct iw_point *dwrq = (struct iw_point *)awrq;
/* RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_notice_, ("+rtw_wx_set_priv\n")); */
if (dwrq->length == 0)
@@ -4542,7 +4528,7 @@ static int rtw_test(
}
DBG_871X("%s: string =\"%s\"\n", __func__, pbuf);
- ptmp = (char*)pbuf;
+ ptmp = (char *)pbuf;
pch = strsep(&ptmp, delim);
if ((pch == NULL) || (strlen(pch) == 0)) {
kfree(pbuf);
@@ -4551,10 +4537,10 @@ static int rtw_test(
}
if (strcmp(pch, "bton") == 0)
- rtw_btcoex_SetManualControl(padapter, false);
+ hal_btcoex_SetManualControl(padapter, false);
if (strcmp(pch, "btoff") == 0)
- rtw_btcoex_SetManualControl(padapter, true);
+ hal_btcoex_SetManualControl(padapter, true);
if (strcmp(pch, "h2c") == 0) {
u8 param[8];
@@ -5015,62 +5001,62 @@ static int rtw_ioctl_wext_private(struct net_device *dev, union iwreq_data *wrq_
u8 *str;
switch (priv_args[k].set_args & IW_PRIV_TYPE_MASK) {
- case IW_PRIV_TYPE_BYTE:
- /* Fetch args */
- count = 0;
- do {
- str = strsep(&ptr, delim);
- if (NULL == str) break;
- sscanf(str, "%i", &temp);
- buffer[count++] = (u8)temp;
- } while (1);
- buffer_len = count;
-
- /* Number of args to fetch */
- wdata.data.length = count;
- if (wdata.data.length > (priv_args[k].set_args & IW_PRIV_SIZE_MASK))
- wdata.data.length = priv_args[k].set_args & IW_PRIV_SIZE_MASK;
+ case IW_PRIV_TYPE_BYTE:
+ /* Fetch args */
+ count = 0;
+ do {
+ str = strsep(&ptr, delim);
+ if (NULL == str) break;
+ sscanf(str, "%i", &temp);
+ buffer[count++] = (u8)temp;
+ } while (1);
+ buffer_len = count;
+
+ /* Number of args to fetch */
+ wdata.data.length = count;
+ if (wdata.data.length > (priv_args[k].set_args & IW_PRIV_SIZE_MASK))
+ wdata.data.length = priv_args[k].set_args & IW_PRIV_SIZE_MASK;
- break;
+ break;
- case IW_PRIV_TYPE_INT:
- /* Fetch args */
- count = 0;
- do {
- str = strsep(&ptr, delim);
- if (NULL == str) break;
- sscanf(str, "%i", &temp);
- ((s32*)buffer)[count++] = (s32)temp;
- } while (1);
- buffer_len = count * sizeof(s32);
-
- /* Number of args to fetch */
- wdata.data.length = count;
- if (wdata.data.length > (priv_args[k].set_args & IW_PRIV_SIZE_MASK))
- wdata.data.length = priv_args[k].set_args & IW_PRIV_SIZE_MASK;
+ case IW_PRIV_TYPE_INT:
+ /* Fetch args */
+ count = 0;
+ do {
+ str = strsep(&ptr, delim);
+ if (NULL == str) break;
+ sscanf(str, "%i", &temp);
+ ((s32 *)buffer)[count++] = (s32)temp;
+ } while (1);
+ buffer_len = count * sizeof(s32);
+
+ /* Number of args to fetch */
+ wdata.data.length = count;
+ if (wdata.data.length > (priv_args[k].set_args & IW_PRIV_SIZE_MASK))
+ wdata.data.length = priv_args[k].set_args & IW_PRIV_SIZE_MASK;
- break;
+ break;
- case IW_PRIV_TYPE_CHAR:
- if (len > 0) {
- /* Size of the string to fetch */
- wdata.data.length = len;
- if (wdata.data.length > (priv_args[k].set_args & IW_PRIV_SIZE_MASK))
- wdata.data.length = priv_args[k].set_args & IW_PRIV_SIZE_MASK;
+ case IW_PRIV_TYPE_CHAR:
+ if (len > 0) {
+ /* Size of the string to fetch */
+ wdata.data.length = len;
+ if (wdata.data.length > (priv_args[k].set_args & IW_PRIV_SIZE_MASK))
+ wdata.data.length = priv_args[k].set_args & IW_PRIV_SIZE_MASK;
- /* Fetch string */
- memcpy(buffer, ptr, wdata.data.length);
- } else {
- wdata.data.length = 1;
- buffer[0] = '\0';
- }
- buffer_len = wdata.data.length;
- break;
+ /* Fetch string */
+ memcpy(buffer, ptr, wdata.data.length);
+ } else {
+ wdata.data.length = 1;
+ buffer[0] = '\0';
+ }
+ buffer_len = wdata.data.length;
+ break;
- default:
- DBG_8192C("%s: Not yet implemented...\n", __func__);
- err = -1;
- goto exit;
+ default:
+ DBG_8192C("%s: Not yet implemented...\n", __func__);
+ err = -1;
+ goto exit;
}
if ((priv_args[k].set_args & IW_PRIV_SIZE_FIXED) &&
@@ -5162,43 +5148,43 @@ static int rtw_ioctl_wext_private(struct net_device *dev, union iwreq_data *wrq_
}
switch (priv_args[k].get_args & IW_PRIV_TYPE_MASK) {
- case IW_PRIV_TYPE_BYTE:
- /* Display args */
- for (j = 0; j < n; j++) {
- sprintf(str, "%d ", extra[j]);
- len = strlen(str);
- output_len = strlen(output);
- if ((output_len + len + 1) > 4096) {
- err = -E2BIG;
- goto exit;
- }
- memcpy(output+output_len, str, len);
+ case IW_PRIV_TYPE_BYTE:
+ /* Display args */
+ for (j = 0; j < n; j++) {
+ sprintf(str, "%d ", extra[j]);
+ len = strlen(str);
+ output_len = strlen(output);
+ if ((output_len + len + 1) > 4096) {
+ err = -E2BIG;
+ goto exit;
}
- break;
+ memcpy(output+output_len, str, len);
+ }
+ break;
- case IW_PRIV_TYPE_INT:
- /* Display args */
- for (j = 0; j < n; j++) {
- sprintf(str, "%d ", ((__s32*)extra)[j]);
- len = strlen(str);
- output_len = strlen(output);
- if ((output_len + len + 1) > 4096) {
- err = -E2BIG;
- goto exit;
- }
- memcpy(output+output_len, str, len);
+ case IW_PRIV_TYPE_INT:
+ /* Display args */
+ for (j = 0; j < n; j++) {
+ sprintf(str, "%d ", ((__s32 *)extra)[j]);
+ len = strlen(str);
+ output_len = strlen(output);
+ if ((output_len + len + 1) > 4096) {
+ err = -E2BIG;
+ goto exit;
}
- break;
+ memcpy(output+output_len, str, len);
+ }
+ break;
- case IW_PRIV_TYPE_CHAR:
- /* Display args */
- memcpy(output, extra, n);
- break;
+ case IW_PRIV_TYPE_CHAR:
+ /* Display args */
+ memcpy(output, extra, n);
+ break;
- default:
- DBG_8192C("%s: Not yet implemented...\n", __func__);
- err = -1;
- goto exit;
+ default:
+ DBG_8192C("%s: Not yet implemented...\n", __func__);
+ err = -1;
+ goto exit;
}
output_len = strlen(output) + 1;
@@ -5225,18 +5211,18 @@ int rtw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
int ret = 0;
switch (cmd) {
- case RTL_IOCTL_WPA_SUPPLICANT:
- ret = wpa_supplicant_ioctl(dev, &wrq->u.data);
- break;
- case RTL_IOCTL_HOSTAPD:
- ret = rtw_hostapd_ioctl(dev, &wrq->u.data);
- break;
- case SIOCDEVPRIVATE:
- ret = rtw_ioctl_wext_private(dev, &wrq->u);
- break;
- default:
- ret = -EOPNOTSUPP;
- break;
+ case RTL_IOCTL_WPA_SUPPLICANT:
+ ret = wpa_supplicant_ioctl(dev, &wrq->u.data);
+ break;
+ case RTL_IOCTL_HOSTAPD:
+ ret = rtw_hostapd_ioctl(dev, &wrq->u.data);
+ break;
+ case SIOCDEVPRIVATE:
+ ret = rtw_ioctl_wext_private(dev, &wrq->u);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
}
return ret;
diff --git a/drivers/staging/rtl8723bs/os_dep/mlme_linux.c b/drivers/staging/rtl8723bs/os_dep/mlme_linux.c
index da4bd5292b0a..52a5b3156b28 100644
--- a/drivers/staging/rtl8723bs/os_dep/mlme_linux.c
+++ b/drivers/staging/rtl8723bs/os_dep/mlme_linux.c
@@ -26,7 +26,7 @@ static void _rtw_set_scan_deny_timer_hdl(struct timer_list *t)
struct adapter *adapter =
from_timer(adapter, t, mlmepriv.set_scan_deny_timer);
- rtw_set_scan_deny_timer_hdl(adapter);
+ rtw_clear_scan_deny(adapter);
}
void rtw_init_mlme_timer(struct adapter *padapter)
@@ -46,11 +46,9 @@ void rtw_os_indicate_connect(struct adapter *adapter)
struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) ||
- (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true))
- {
+ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true)) {
rtw_cfg80211_ibss_indicate_connect(adapter);
- }
- else
+ } else
rtw_cfg80211_indicate_connect(adapter);
rtw_indicate_wx_assoc_event(adapter);
@@ -77,8 +75,8 @@ void rtw_reset_securitypriv(struct adapter *adapter)
spin_lock_bh(&adapter->security_key_mutex);
- if (adapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)/* 802.1x */
- {
+ if (adapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) {
+ /* 802.1x */
/* Added by Albert 2009/02/18 */
/* We have to backup the PMK information for WiFi PMK Caching test item. */
/* */
@@ -105,9 +103,8 @@ void rtw_reset_securitypriv(struct adapter *adapter)
adapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen;
adapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled;
- }
- else /* reset values in securitypriv */
- {
+ } else {
+ /* reset values in securitypriv */
/* if (adapter->mlmepriv.fw_state & WIFI_STATION_STATE) */
/* */
struct security_priv *psec_priv = &adapter->securitypriv;
@@ -150,8 +147,7 @@ void rtw_report_sec_ie(struct adapter *adapter, u8 authmode, u8 *sec_ie)
RT_TRACE(_module_mlme_osdep_c_, _drv_info_, ("+rtw_report_sec_ie, authmode =%d\n", authmode));
buff = NULL;
- if (authmode == _WPA_IE_ID_)
- {
+ if (authmode == _WPA_IE_ID_) {
RT_TRACE(_module_mlme_osdep_c_, _drv_info_, ("rtw_report_sec_ie, authmode =%d\n", authmode));
buff = rtw_zmalloc(IW_CUSTOM_MAX);
diff --git a/drivers/staging/rtl8723bs/os_dep/os_intfs.c b/drivers/staging/rtl8723bs/os_dep/os_intfs.c
index 8a9d838af24e..544e799d0a03 100644
--- a/drivers/staging/rtl8723bs/os_dep/os_intfs.c
+++ b/drivers/staging/rtl8723bs/os_dep/os_intfs.c
@@ -223,9 +223,8 @@ int _netdev_open(struct net_device *pnetdev);
int netdev_open (struct net_device *pnetdev);
static int netdev_close (struct net_device *pnetdev);
-static uint loadparam(struct adapter *padapter, _nic_hdl pnetdev)
+static void loadparam(struct adapter *padapter, _nic_hdl pnetdev)
{
- uint status = _SUCCESS;
struct registry_priv *registry_par = &padapter->registrypriv;
registry_par->chip_version = (u8)rtw_chip_version;
@@ -330,7 +329,6 @@ static uint loadparam(struct adapter *padapter, _nic_hdl pnetdev)
registry_par->qos_opt_enable = (u8)rtw_qos_opt_enable;
registry_par->hiq_filter = (u8)rtw_hiq_filter;
- return status;
}
static int rtw_net_set_mac_address(struct net_device *pnetdev, void *p)
@@ -601,9 +599,8 @@ void rtw_stop_drv_threads (struct adapter *padapter)
rtw_hal_stop_thread(padapter);
}
-static u8 rtw_init_default_value(struct adapter *padapter)
+static void rtw_init_default_value(struct adapter *padapter)
{
- u8 ret = _SUCCESS;
struct registry_priv *pregistrypriv = &padapter->registrypriv;
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
@@ -665,7 +662,6 @@ static u8 rtw_init_default_value(struct adapter *padapter)
padapter->driver_ampdu_spacing = 0xFF;
padapter->driver_rx_ampdu_factor = 0xFF;
- return ret;
}
struct dvobj_priv *devobj_init(void)
@@ -707,9 +703,8 @@ void devobj_deinit(struct dvobj_priv *pdvobj)
kfree(pdvobj);
}
-u8 rtw_reset_drv_sw(struct adapter *padapter)
+void rtw_reset_drv_sw(struct adapter *padapter)
{
- u8 ret8 = _SUCCESS;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter);
@@ -739,7 +734,6 @@ u8 rtw_reset_drv_sw(struct adapter *padapter)
rtw_set_signal_stat_timer(&padapter->recvpriv);
- return ret8;
}
@@ -749,7 +743,7 @@ u8 rtw_init_drv_sw(struct adapter *padapter)
RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_init_drv_sw\n"));
- ret8 = rtw_init_default_value(padapter);
+ rtw_init_default_value(padapter);
rtw_init_hal_com_default_value(padapter);
@@ -1214,7 +1208,7 @@ void rtw_dev_unload(struct adapter *padapter)
}
if (padapter->bSurpriseRemoved == false) {
- rtw_btcoex_IpsNotify(padapter, pwrctl->ips_mode_req);
+ hal_btcoex_IpsNotify(padapter, pwrctl->ips_mode_req);
#ifdef CONFIG_WOWLAN
if (pwrctl->bSupportRemoteWakeup == true &&
pwrctl->wowlan_mode == true) {
@@ -1289,14 +1283,13 @@ static int rtw_suspend_free_assoc_resource(struct adapter *padapter)
}
#ifdef CONFIG_WOWLAN
-int rtw_suspend_wow(struct adapter *padapter)
+void rtw_suspend_wow(struct adapter *padapter)
{
u8 ch, bw, offset;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct net_device *pnetdev = padapter->pnetdev;
struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
struct wowlan_ioctl_param poidparam;
- int ret = _SUCCESS;
DBG_871X("==> " FUNC_ADPT_FMT " entry....\n", FUNC_ADPT_ARG(padapter));
@@ -1364,7 +1357,6 @@ int rtw_suspend_wow(struct adapter *padapter)
DBG_871X_LEVEL(_drv_always_, "%s: ### ERROR ### wowlan_mode =%d\n", __func__, pwrpriv->wowlan_mode);
}
DBG_871X("<== " FUNC_ADPT_FMT " exit....\n", FUNC_ADPT_ARG(padapter));
- return ret;
}
#endif /* ifdef CONFIG_WOWLAN */
@@ -1422,10 +1414,9 @@ int rtw_suspend_ap_wow(struct adapter *padapter)
#endif /* ifdef CONFIG_AP_WOWLAN */
-static int rtw_suspend_normal(struct adapter *padapter)
+static void rtw_suspend_normal(struct adapter *padapter)
{
struct net_device *pnetdev = padapter->pnetdev;
- int ret = _SUCCESS;
DBG_871X("==> " FUNC_ADPT_FMT " entry....\n", FUNC_ADPT_ARG(padapter));
if (pnetdev) {
@@ -1447,7 +1438,6 @@ static int rtw_suspend_normal(struct adapter *padapter)
padapter->intf_deinit(adapter_to_dvobj(padapter));
DBG_871X("<== " FUNC_ADPT_FMT " exit....\n", FUNC_ADPT_ARG(padapter));
- return ret;
}
int rtw_suspend_common(struct adapter *padapter)
@@ -1485,10 +1475,10 @@ int rtw_suspend_common(struct adapter *padapter)
/* wait for the latest FW to remove this condition. */
if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) {
- rtw_btcoex_SuspendNotify(padapter, 0);
+ hal_btcoex_SuspendNotify(padapter, 0);
DBG_871X("WIFI_AP_STATE\n");
} else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) {
- rtw_btcoex_SuspendNotify(padapter, 1);
+ hal_btcoex_SuspendNotify(padapter, 1);
DBG_871X("STATION\n");
}
@@ -1839,7 +1829,7 @@ int rtw_resume_common(struct adapter *padapter)
rtw_resume_process_normal(padapter);
}
- rtw_btcoex_SuspendNotify(padapter, 0);
+ hal_btcoex_SuspendNotify(padapter, 0);
if (pwrpriv) {
pwrpriv->bInSuspend = false;
diff --git a/drivers/staging/rtl8723bs/os_dep/osdep_service.c b/drivers/staging/rtl8723bs/os_dep/osdep_service.c
index a5a5a5c8226a..62fdd24ba427 100644
--- a/drivers/staging/rtl8723bs/os_dep/osdep_service.c
+++ b/drivers/staging/rtl8723bs/os_dep/osdep_service.c
@@ -77,13 +77,13 @@ static int openFile(struct file **fpp, char *path, int flag, int mode)
{
struct file *fp;
- fp =filp_open(path, flag, mode);
+ fp = filp_open(path, flag, mode);
if (IS_ERR(fp)) {
*fpp = NULL;
return PTR_ERR(fp);
}
else {
- *fpp =fp;
+ *fpp = fp;
return 0;
}
}
@@ -106,10 +106,10 @@ static int readFile(struct file *fp, char *buf, int len)
if (!fp->f_op || !fp->f_op->read)
return -EPERM;
- while (sum<len) {
+ while (sum < len) {
rlen = kernel_read(fp, buf + sum, len - sum, &fp->f_pos);
- if (rlen>0)
- sum+=rlen;
+ if (rlen > 0)
+ sum += rlen;
else if (0 != rlen)
return rlen;
else
@@ -131,7 +131,7 @@ static int isFileReadable(char *path)
int ret = 0;
char buf;
- fp =filp_open(path, O_RDONLY, 0);
+ fp = filp_open(path, O_RDONLY, 0);
if (IS_ERR(fp))
return PTR_ERR(fp);
@@ -151,7 +151,7 @@ static int isFileReadable(char *path)
*/
static int retriveFromFile(char *path, u8 *buf, u32 sz)
{
- int ret =-1;
+ int ret = -1;
struct file *fp;
if (path && buf) {
@@ -160,7 +160,7 @@ static int retriveFromFile(char *path, u8 *buf, u32 sz)
if (ret == 0) {
DBG_871X("%s openFile path:%s fp =%p\n", __func__, path , fp);
- ret =readFile(fp, buf, sz);
+ ret = readFile(fp, buf, sz);
closeFile(fp);
DBG_871X("%s readFile, ret:%d\n", __func__, ret);
@@ -197,8 +197,8 @@ int rtw_is_file_readable(char *path)
*/
int rtw_retrive_from_file(char *path, u8 *buf, u32 sz)
{
- int ret =retriveFromFile(path, buf, sz);
- return ret>= 0?ret:0;
+ int ret = retriveFromFile(path, buf, sz);
+ return ret >= 0 ? ret : 0;
}
struct net_device *rtw_alloc_etherdev_with_old_priv(int sizeof_priv, void *old_priv)
@@ -211,8 +211,8 @@ struct net_device *rtw_alloc_etherdev_with_old_priv(int sizeof_priv, void *old_p
goto RETURN;
pnpi = netdev_priv(pnetdev);
- pnpi->priv =old_priv;
- pnpi->sizeof_priv =sizeof_priv;
+ pnpi->priv = old_priv;
+ pnpi->sizeof_priv = sizeof_priv;
RETURN:
return pnetdev;
@@ -236,7 +236,7 @@ struct net_device *rtw_alloc_etherdev(int sizeof_priv)
goto RETURN;
}
- pnpi->sizeof_priv =sizeof_priv;
+ pnpi->sizeof_priv = sizeof_priv;
RETURN:
return pnetdev;
}
@@ -284,7 +284,7 @@ int rtw_change_ifname(struct adapter *padapter, const char *ifname)
else
unregister_netdevice(cur_pnetdev);
- rereg_priv->old_pnetdev =cur_pnetdev;
+ rereg_priv->old_pnetdev = cur_pnetdev;
pnetdev = rtw_init_netdev(padapter);
if (!pnetdev) {
@@ -316,11 +316,6 @@ error:
}
-u64 rtw_modular64(u64 x, u64 y)
-{
- return do_div(x, y);
-}
-
void rtw_buf_free(u8 **buf, u32 *buf_len)
{
u32 ori_len;
@@ -379,7 +374,7 @@ keep_ori:
*/
inline bool rtw_cbuf_full(struct rtw_cbuf *cbuf)
{
- return (cbuf->write == cbuf->read-1)? true : false;
+ return (cbuf->write == cbuf->read - 1) ? true : false;
}
/**
@@ -390,7 +385,7 @@ inline bool rtw_cbuf_full(struct rtw_cbuf *cbuf)
*/
inline bool rtw_cbuf_empty(struct rtw_cbuf *cbuf)
{
- return (cbuf->write == cbuf->read)? true : false;
+ return (cbuf->write == cbuf->read) ? true : false;
}
/**
@@ -408,7 +403,7 @@ bool rtw_cbuf_push(struct rtw_cbuf *cbuf, void *buf)
DBG_871X("%s on %u\n", __func__, cbuf->write);
cbuf->bufs[cbuf->write] = buf;
- cbuf->write = (cbuf->write+1)%cbuf->size;
+ cbuf->write = (cbuf->write + 1) % cbuf->size;
return _SUCCESS;
}
@@ -428,7 +423,7 @@ void *rtw_cbuf_pop(struct rtw_cbuf *cbuf)
DBG_871X("%s on %u\n", __func__, cbuf->read);
buf = cbuf->bufs[cbuf->read];
- cbuf->read = (cbuf->read+1)%cbuf->size;
+ cbuf->read = (cbuf->read + 1) % cbuf->size;
return buf;
}
diff --git a/drivers/staging/rtl8723bs/os_dep/recv_linux.c b/drivers/staging/rtl8723bs/os_dep/recv_linux.c
index 67ec336264e5..643caccc3069 100644
--- a/drivers/staging/rtl8723bs/os_dep/recv_linux.c
+++ b/drivers/staging/rtl8723bs/os_dep/recv_linux.c
@@ -12,8 +12,7 @@
void rtw_os_free_recvframe(union recv_frame *precvframe)
{
- if (precvframe->u.hdr.pkt)
- {
+ if (precvframe->u.hdr.pkt) {
dev_kfree_skb_any(precvframe->u.hdr.pkt);/* free skb by driver */
precvframe->u.hdr.pkt = NULL;
@@ -21,13 +20,9 @@ void rtw_os_free_recvframe(union recv_frame *precvframe)
}
/* alloc os related resource in union recv_frame */
-int rtw_os_recv_resource_alloc(struct adapter *padapter, union recv_frame *precvframe)
+void rtw_os_recv_resource_alloc(struct adapter *padapter, union recv_frame *precvframe)
{
- int res = _SUCCESS;
-
precvframe->u.hdr.pkt_newalloc = precvframe->u.hdr.pkt = NULL;
-
- return res;
}
/* free os related resource in union recv_frame */
@@ -38,10 +33,8 @@ void rtw_os_recv_resource_free(struct recv_priv *precvpriv)
precvframe = (union recv_frame*) precvpriv->precv_frame_buf;
- for (i = 0; i < NR_RECVFRAME; i++)
- {
- if (precvframe->u.hdr.pkt)
- {
+ for (i = 0; i < NR_RECVFRAME; i++) {
+ if (precvframe->u.hdr.pkt) {
dev_kfree_skb_any(precvframe->u.hdr.pkt);/* free skb by driver */
precvframe->u.hdr.pkt = NULL;
}
@@ -50,16 +43,11 @@ void rtw_os_recv_resource_free(struct recv_priv *precvpriv)
}
/* free os related resource in struct recv_buf */
-int rtw_os_recvbuf_resource_free(struct adapter *padapter, struct recv_buf *precvbuf)
+void rtw_os_recvbuf_resource_free(struct adapter *padapter, struct recv_buf *precvbuf)
{
- int ret = _SUCCESS;
-
- if (precvbuf->pskb)
- {
+ if (precvbuf->pskb) {
dev_kfree_skb_any(precvbuf->pskb);
}
- return ret;
-
}
_pkt *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8 *pdata)
@@ -71,22 +59,16 @@ _pkt *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8
pattrib = &prframe->u.hdr.attrib;
sub_skb = rtw_skb_alloc(nSubframe_Length + 12);
- if (sub_skb)
- {
+ if (sub_skb) {
skb_reserve(sub_skb, 12);
skb_put_data(sub_skb, (pdata + ETH_HLEN), nSubframe_Length);
- }
- else
- {
+ } else {
sub_skb = rtw_skb_clone(prframe->u.hdr.pkt);
- if (sub_skb)
- {
+ if (sub_skb) {
sub_skb->data = pdata + ETH_HLEN;
sub_skb->len = nSubframe_Length;
skb_set_tail_pointer(sub_skb, nSubframe_Length);
- }
- else
- {
+ } else {
DBG_871X("%s(): rtw_skb_clone() Fail!!!\n", __func__);
return NULL;
}
@@ -121,8 +103,7 @@ void rtw_os_recv_indicate_pkt(struct adapter *padapter, _pkt *pkt, struct rx_pkt
/* Indicat the packets to upper layer */
if (pkt) {
- if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true)
- {
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) {
_pkt *pskb2 = NULL;
struct sta_info *psta = NULL;
struct sta_priv *pstapriv = &padapter->stapriv;
@@ -130,20 +111,17 @@ void rtw_os_recv_indicate_pkt(struct adapter *padapter, _pkt *pkt, struct rx_pkt
/* DBG_871X("bmcast =%d\n", bmcast); */
- if (memcmp(pattrib->dst, myid(&padapter->eeprompriv), ETH_ALEN))
- {
+ if (memcmp(pattrib->dst, myid(&padapter->eeprompriv), ETH_ALEN)) {
/* DBG_871X("not ap psta =%p, addr =%pM\n", psta, pattrib->dst); */
- if (bmcast)
- {
+ if (bmcast) {
psta = rtw_get_bcmc_stainfo(padapter);
pskb2 = rtw_skb_clone(pkt);
} else {
psta = rtw_get_stainfo(pstapriv, pattrib->dst);
}
- if (psta)
- {
+ if (psta) {
struct net_device *pnetdev = (struct net_device*)padapter->pnetdev;
/* DBG_871X("directly forwarding to the rtw_xmit_entry\n"); */
@@ -162,9 +140,8 @@ void rtw_os_recv_indicate_pkt(struct adapter *padapter, _pkt *pkt, struct rx_pkt
return;
}
}
- }
- else/* to APself */
- {
+ } else {
+ /* to APself */
/* DBG_871X("to APSelf\n"); */
DBG_COUNTER(padapter->rx_logs.os_indicate_ap_self);
}
@@ -200,32 +177,23 @@ void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup)
struct security_priv *psecuritypriv = &padapter->securitypriv;
unsigned long cur_time = 0;
- if (psecuritypriv->last_mic_err_time == 0)
- {
+ if (psecuritypriv->last_mic_err_time == 0) {
psecuritypriv->last_mic_err_time = jiffies;
- }
- else
- {
+ } else {
cur_time = jiffies;
- if (cur_time - psecuritypriv->last_mic_err_time < 60*HZ)
- {
+ if (cur_time - psecuritypriv->last_mic_err_time < 60*HZ) {
psecuritypriv->btkip_countermeasure = true;
psecuritypriv->last_mic_err_time = 0;
psecuritypriv->btkip_countermeasure_time = cur_time;
- }
- else
- {
+ } else {
psecuritypriv->last_mic_err_time = jiffies;
}
}
- if (bgroup)
- {
+ if (bgroup) {
key_type |= NL80211_KEYTYPE_GROUP;
- }
- else
- {
+ } else {
key_type |= NL80211_KEYTYPE_PAIRWISE;
}
@@ -233,13 +201,10 @@ void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup)
NULL, GFP_ATOMIC);
memset(&ev, 0x00, sizeof(ev));
- if (bgroup)
- {
- ev.flags |= IW_MICFAILURE_GROUP;
- }
- else
- {
- ev.flags |= IW_MICFAILURE_PAIRWISE;
+ if (bgroup) {
+ ev.flags |= IW_MICFAILURE_GROUP;
+ } else {
+ ev.flags |= IW_MICFAILURE_PAIRWISE;
}
ev.src_addr.sa_family = ARPHRD_ETHER;
@@ -258,8 +223,7 @@ static void rtw_os_ksocket_send(struct adapter *padapter, union recv_frame *prec
DBG_871X("eth rx: got eth_type = 0x%x\n", pattrib->eth_type);
- if (psta && psta->isrc && psta->pid>0)
- {
+ if (psta && psta->isrc && psta->pid>0) {
u16 rx_pid;
rx_pid = *(u16*)(skb->data+ETH_HLEN);
@@ -267,8 +231,7 @@ static void rtw_os_ksocket_send(struct adapter *padapter, union recv_frame *prec
DBG_871X("eth rx(pid = 0x%x): sta("MAC_FMT") pid = 0x%x\n",
rx_pid, MAC_ARG(psta->hwaddr), psta->pid);
- if (rx_pid == psta->pid)
- {
+ if (rx_pid == psta->pid) {
int i;
u16 len = *(u16*)(skb->data+ETH_HLEN+2);
/* u16 ctrl_type = *(u16*)(skb->data+ETH_HLEN+4); */
@@ -301,8 +264,7 @@ int rtw_recv_indicatepkt(struct adapter *padapter, union recv_frame *precv_frame
pfree_recv_queue = &(precvpriv->free_recv_queue);
skb = precv_frame->u.hdr.pkt;
- if (skb == NULL)
- {
+ if (skb == NULL) {
RT_TRACE(_module_recv_osdep_c_, _drv_err_, ("rtw_recv_indicatepkt():skb == NULL something wrong!!!!\n"));
goto _recv_indicatepkt_drop;
}
@@ -320,8 +282,7 @@ int rtw_recv_indicatepkt(struct adapter *padapter, union recv_frame *precv_frame
RT_TRACE(_module_recv_osdep_c_, _drv_info_, ("\n skb->head =%p skb->data =%p skb->tail =%p skb->end =%p skb->len =%d\n", skb->head, skb->data, skb_tail_pointer(skb), skb_end_pointer(skb), skb->len));
#ifdef CONFIG_AUTO_AP_MODE
- if (0x8899 == pattrib->eth_type)
- {
+ if (0x8899 == pattrib->eth_type) {
rtw_os_ksocket_send(padapter, precv_frame);
/* goto _recv_indicatepkt_drop; */
@@ -336,7 +297,7 @@ int rtw_recv_indicatepkt(struct adapter *padapter, union recv_frame *precv_frame
RT_TRACE(_module_recv_osdep_c_, _drv_info_, ("\n rtw_recv_indicatepkt :after rtw_os_recv_indicate_pkt!!!!\n"));
- return _SUCCESS;
+ return _SUCCESS;
_recv_indicatepkt_drop:
diff --git a/drivers/staging/rtl8723bs/os_dep/rtw_proc.c b/drivers/staging/rtl8723bs/os_dep/rtw_proc.c
index d8e7ad1ed842..5f950fda48ea 100644
--- a/drivers/staging/rtl8723bs/os_dep/rtw_proc.c
+++ b/drivers/staging/rtl8723bs/os_dep/rtw_proc.c
@@ -63,8 +63,7 @@ static ssize_t proc_set_log_level(struct file *file, const char __user *buffer,
if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
sscanf(tmp, "%d ", &log_level);
- if (log_level >= _drv_always_ && log_level <= _drv_debug_)
- {
+ if (log_level >= _drv_always_ && log_level <= _drv_debug_) {
GlobalDebugLevel = log_level;
printk("%d\n", GlobalDebugLevel);
}
@@ -122,14 +121,14 @@ int rtw_drv_proc_init(void)
ssize_t i;
struct proc_dir_entry *entry = NULL;
- if (rtw_proc != NULL) {
+ if (rtw_proc) {
rtw_warn_on(1);
goto exit;
}
rtw_proc = rtw_proc_create_dir(RTW_PROC_NAME, get_proc_net, NULL);
- if (rtw_proc == NULL) {
+ if (!rtw_proc) {
rtw_warn_on(1);
goto exit;
}
@@ -152,7 +151,7 @@ void rtw_drv_proc_deinit(void)
{
int i;
- if (rtw_proc == NULL)
+ if (!rtw_proc)
return;
for (i = 0; i < drv_proc_hdls_num; i++)
@@ -224,8 +223,7 @@ static ssize_t proc_set_linked_info_dump(struct file *file, const char __user *b
return -EFAULT;
if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
- if (padapter)
- {
+ if (padapter) {
/* padapter->bLinkInfoDump = mode; */
/* DBG_871X("linked_info_dump =%s\n", (padapter->bLinkInfoDump)?"enable":"disable"); */
linked_info_dump(padapter, mode);
@@ -637,18 +635,18 @@ static struct proc_dir_entry *rtw_odm_proc_init(struct net_device *dev)
struct adapter *adapter = rtw_netdev_priv(dev);
ssize_t i;
- if (adapter->dir_dev == NULL) {
+ if (!adapter->dir_dev) {
rtw_warn_on(1);
goto exit;
}
- if (adapter->dir_odm != NULL) {
+ if (adapter->dir_odm) {
rtw_warn_on(1);
goto exit;
}
dir_odm = rtw_proc_create_dir("odm", adapter->dir_dev, dev);
- if (dir_odm == NULL) {
+ if (!dir_odm) {
rtw_warn_on(1);
goto exit;
}
@@ -674,7 +672,7 @@ static void rtw_odm_proc_deinit(struct adapter *adapter)
dir_odm = adapter->dir_odm;
- if (dir_odm == NULL) {
+ if (!dir_odm) {
rtw_warn_on(1);
return;
}
@@ -695,18 +693,18 @@ struct proc_dir_entry *rtw_adapter_proc_init(struct net_device *dev)
struct adapter *adapter = rtw_netdev_priv(dev);
ssize_t i;
- if (drv_proc == NULL) {
+ if (!drv_proc) {
rtw_warn_on(1);
goto exit;
}
- if (adapter->dir_dev != NULL) {
+ if (adapter->dir_dev) {
rtw_warn_on(1);
goto exit;
}
dir_dev = rtw_proc_create_dir(dev->name, drv_proc, dev);
- if (dir_dev == NULL) {
+ if (!dir_dev) {
rtw_warn_on(1);
goto exit;
}
@@ -736,7 +734,7 @@ void rtw_adapter_proc_deinit(struct net_device *dev)
dir_dev = adapter->dir_dev;
- if (dir_dev == NULL) {
+ if (!dir_dev) {
rtw_warn_on(1);
return;
}
@@ -760,7 +758,7 @@ void rtw_adapter_proc_replace(struct net_device *dev)
dir_dev = adapter->dir_dev;
- if (dir_dev == NULL) {
+ if (!dir_dev) {
rtw_warn_on(1);
return;
}
diff --git a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c
index 052482554f74..540a7eed621d 100644
--- a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c
+++ b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c
@@ -8,6 +8,7 @@
#include <drv_types.h>
#include <rtw_debug.h>
+#include <hal_btcoex.h>
#include <linux/jiffies.h>
#ifndef dev_to_sdio_func
@@ -84,13 +85,10 @@ static int sdio_alloc_irq(struct dvobj_priv *dvobj)
sdio_claim_host(func);
err = sdio_claim_irq(func, &sd_sync_int_hdl);
- if (err)
- {
+ if (err) {
dvobj->drv_dbg.dbg_sdio_alloc_irq_error_cnt++;
printk(KERN_CRIT "%s: sdio_claim_irq FAIL(%d)!\n", __func__, err);
- }
- else
- {
+ } else {
dvobj->drv_dbg.dbg_sdio_alloc_irq_cnt++;
dvobj->irq_alloc = 1;
}
@@ -102,28 +100,26 @@ static int sdio_alloc_irq(struct dvobj_priv *dvobj)
static void sdio_free_irq(struct dvobj_priv *dvobj)
{
- struct sdio_data *psdio_data;
- struct sdio_func *func;
- int err;
-
- if (dvobj->irq_alloc) {
- psdio_data = &dvobj->intf_data;
- func = psdio_data->func;
-
- if (func) {
- sdio_claim_host(func);
- err = sdio_release_irq(func);
- if (err)
- {
+ struct sdio_data *psdio_data;
+ struct sdio_func *func;
+ int err;
+
+ if (dvobj->irq_alloc) {
+ psdio_data = &dvobj->intf_data;
+ func = psdio_data->func;
+
+ if (func) {
+ sdio_claim_host(func);
+ err = sdio_release_irq(func);
+ if (err) {
dvobj->drv_dbg.dbg_sdio_free_irq_error_cnt++;
DBG_871X_LEVEL(_drv_err_,"%s: sdio_release_irq FAIL(%d)!\n", __func__, err);
- }
- else
- dvobj->drv_dbg.dbg_sdio_free_irq_cnt++;
- sdio_release_host(func);
- }
- dvobj->irq_alloc = 0;
- }
+ } else
+ dvobj->drv_dbg.dbg_sdio_free_irq_cnt++;
+ sdio_release_host(func);
+ }
+ dvobj->irq_alloc = 0;
+ }
}
#ifdef CONFIG_GPIO_WAKEUP
@@ -224,20 +220,17 @@ static void sdio_deinit(struct dvobj_priv *dvobj)
if (func) {
sdio_claim_host(func);
err = sdio_disable_func(func);
- if (err)
- {
+ if (err) {
dvobj->drv_dbg.dbg_sdio_deinit_error_cnt++;
DBG_8192C(KERN_ERR "%s: sdio_disable_func(%d)\n", __func__, err);
}
if (dvobj->irq_alloc) {
err = sdio_release_irq(func);
- if (err)
- {
+ if (err) {
dvobj->drv_dbg.dbg_sdio_free_irq_error_cnt++;
DBG_8192C(KERN_ERR "%s: sdio_release_irq(%d)\n", __func__, err);
- }
- else
+ } else
dvobj->drv_dbg.dbg_sdio_free_irq_cnt++;
}
@@ -368,8 +361,7 @@ static struct adapter *rtw_sdio_if1_init(struct dvobj_priv *dvobj, const struct
padapter->intf_alloc_irq = &sdio_alloc_irq;
padapter->intf_free_irq = &sdio_free_irq;
- if (rtw_init_io_priv(padapter, sdio_set_intf_ops) == _FAIL)
- {
+ if (rtw_init_io_priv(padapter, sdio_set_intf_ops) == _FAIL) {
RT_TRACE(_module_hci_intfs_c_, _drv_err_,
("rtw_drv_init: Can't init io_priv\n"));
goto free_hal_data;
@@ -379,7 +371,7 @@ static struct adapter *rtw_sdio_if1_init(struct dvobj_priv *dvobj, const struct
rtw_hal_chip_configure(padapter);
- rtw_btcoex_Initialize(padapter);
+ hal_btcoex_Initialize(padapter);
/* 3 6. read efuse/eeprom data */
rtw_hal_read_chip_info(padapter);
@@ -489,9 +481,8 @@ static int rtw_drv_init(
/* dev_alloc_name && register_netdev */
status = rtw_drv_register_netdev(if1);
- if (status != _SUCCESS) {
+ if (status != _SUCCESS)
goto free_if2;
- }
if (sdio_alloc_irq(dvobj) != _SUCCESS)
goto free_if2;
@@ -569,14 +560,12 @@ static int rtw_sdio_suspend(struct device *dev)
struct adapter *padapter = psdpriv->if1;
struct debug_priv *pdbgpriv = &psdpriv->drv_dbg;
- if (padapter->bDriverStopped == true)
- {
+ if (padapter->bDriverStopped == true) {
DBG_871X("%s bDriverStopped = %d\n", __func__, padapter->bDriverStopped);
return 0;
}
- if (pwrpriv->bInSuspend == true)
- {
+ if (pwrpriv->bInSuspend == true) {
DBG_871X("%s bInSuspend = %d\n", __func__, pwrpriv->bInSuspend);
pdbgpriv->dbg_suspend_error_cnt++;
return 0;
@@ -591,8 +580,7 @@ static int rtw_resume_process(struct adapter *padapter)
struct dvobj_priv *psdpriv = padapter->dvobj;
struct debug_priv *pdbgpriv = &psdpriv->drv_dbg;
- if (pwrpriv->bInSuspend == false)
- {
+ if (pwrpriv->bInSuspend == false) {
pdbgpriv->dbg_resume_error_cnt++;
DBG_871X("%s bInSuspend = %d\n", __func__, pwrpriv->bInSuspend);
return -1;
@@ -635,8 +623,7 @@ static int __init rtw_drv_entry(void)
rtw_drv_proc_init();
ret = sdio_register_driver(&sdio_drvpriv.r871xs_drv);
- if (ret != 0)
- {
+ if (ret != 0) {
sdio_drvpriv.drv_registered = false;
rtw_drv_proc_deinit();
rtw_ndev_notifier_unregister();
diff --git a/drivers/staging/rtl8723bs/os_dep/sdio_ops_linux.c b/drivers/staging/rtl8723bs/os_dep/sdio_ops_linux.c
index 1787534487b4..50b89340465b 100644
--- a/drivers/staging/rtl8723bs/os_dep/sdio_ops_linux.c
+++ b/drivers/staging/rtl8723bs/os_dep/sdio_ops_linux.c
@@ -257,15 +257,13 @@ u32 sd_read32(struct intf_hdl *pintfhdl, u32 addr, s32 *err)
if (claim_needed)
sdio_release_host(func);
- if (err && *err)
- {
+ if (err && *err) {
int i;
DBG_871X(KERN_ERR "%s: (%d) addr = 0x%05x, val = 0x%x\n", __func__, *err, addr, v);
*err = 0;
- for (i = 0; i < SD_IO_TRY_CNT; i++)
- {
+ for (i = 0; i < SD_IO_TRY_CNT; i++) {
if (claim_needed) sdio_claim_host(func);
v = sdio_readl(func, addr, err);
if (claim_needed) sdio_release_host(func);
@@ -350,15 +348,13 @@ void sd_write32(struct intf_hdl *pintfhdl, u32 addr, u32 v, s32 *err)
if (claim_needed)
sdio_release_host(func);
- if (err && *err)
- {
+ if (err && *err) {
int i;
DBG_871X(KERN_ERR "%s: (%d) addr = 0x%05x val = 0x%08x\n", __func__, *err, addr, v);
*err = 0;
- for (i = 0; i < SD_IO_TRY_CNT; i++)
- {
+ for (i = 0; i < SD_IO_TRY_CNT; i++) {
if (claim_needed) sdio_claim_host(func);
sdio_writel(func, v, addr, err);
if (claim_needed) sdio_release_host(func);
@@ -420,13 +416,11 @@ s32 _sd_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata)
func = psdio->func;
- if (unlikely((cnt == 1) || (cnt == 2)))
- {
+ if (unlikely((cnt == 1) || (cnt == 2))) {
int i;
u8 *pbuf = pdata;
- for (i = 0; i < cnt; i++)
- {
+ for (i = 0; i < cnt; i++) {
*(pbuf+i) = sdio_readb(func, addr+i, &err);
if (err) {
@@ -523,13 +517,11 @@ s32 _sd_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, void *pdata)
func = psdio->func;
/* size = sdio_align_size(func, cnt); */
- if (unlikely((cnt == 1) || (cnt == 2)))
- {
+ if (unlikely((cnt == 1) || (cnt == 2))) {
int i;
u8 *pbuf = pdata;
- for (i = 0; i < cnt; i++)
- {
+ for (i = 0; i < cnt; i++) {
sdio_writeb(func, *(pbuf+i), addr+i, &err);
if (err) {
DBG_871X(KERN_ERR "%s: FAIL!(%d) addr = 0x%05x val = 0x%02x\n", __func__, err, addr, *(pbuf+i));
diff --git a/drivers/staging/rtl8723bs/os_dep/xmit_linux.c b/drivers/staging/rtl8723bs/os_dep/xmit_linux.c
index 4e4e565d991c..4e81bc13e57d 100644
--- a/drivers/staging/rtl8723bs/os_dep/xmit_linux.c
+++ b/drivers/staging/rtl8723bs/os_dep/xmit_linux.c
@@ -32,7 +32,7 @@ uint _rtw_pktfile_read (struct pkt_file *pfile, u8 *rmem, uint rlen)
len = (rlen > len) ? len : rlen;
if (rmem)
- skb_copy_bits(pfile->pkt, pfile->buf_len-pfile->pkt_len, rmem, len);
+ skb_copy_bits(pfile->pkt, pfile->buf_len - pfile->pkt_len, rmem, len);
pfile->cur_addr += len;
pfile->pkt_len -= len;
@@ -50,7 +50,7 @@ int rtw_os_xmit_resource_alloc(struct adapter *padapter, struct xmit_buf *pxmitb
{
if (alloc_sz > 0) {
pxmitbuf->pallocated_buf = rtw_zmalloc(alloc_sz);
- if (pxmitbuf->pallocated_buf == NULL)
+ if (!pxmitbuf->pallocated_buf)
return _FAIL;
pxmitbuf->pbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitbuf->pallocated_buf), XMITBUF_ALIGN_SZ);
@@ -65,7 +65,7 @@ void rtw_os_xmit_resource_free(struct adapter *padapter, struct xmit_buf *pxmitb
kfree(pxmitbuf->pallocated_buf);
}
-#define WMM_XMIT_THRESHOLD (NR_XMITFRAME*2/5)
+#define WMM_XMIT_THRESHOLD (NR_XMITFRAME * 2 / 5)
void rtw_os_pkt_complete(struct adapter *padapter, _pkt *pkt)
{
@@ -229,9 +229,9 @@ int _rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev)
#endif
)
&& padapter->registrypriv.wifi_spec == 0) {
- if (pxmitpriv->free_xmitframe_cnt > (NR_XMITFRAME/4)) {
+ if (pxmitpriv->free_xmitframe_cnt > (NR_XMITFRAME / 4)) {
res = rtw_mlcst2unicst(padapter, pkt);
- if (res == true)
+ if (res)
goto exit;
} else {
/* DBG_871X("Stop M2U(%d, %d)! ", pxmitpriv->free_xmitframe_cnt, pxmitpriv->free_xmitbuf_cnt); */
diff --git a/drivers/staging/rts5208/TODO b/drivers/staging/rts5208/TODO
index 57bcf5834c0c..9cec0d8dd0b6 100644
--- a/drivers/staging/rts5208/TODO
+++ b/drivers/staging/rts5208/TODO
@@ -4,4 +4,4 @@ TODO:
- We will use the stack in drivers/mmc to implement
rts5208/5288 in the future
-Micky Ching <micky_ching@realsil.com.cn> \ No newline at end of file
+Micky Ching <micky_ching@realsil.com.cn>
diff --git a/drivers/staging/rts5208/rtsx_chip.c b/drivers/staging/rts5208/rtsx_chip.c
index 76c35f3c0208..17c4131f5f62 100644
--- a/drivers/staging/rts5208/rtsx_chip.c
+++ b/drivers/staging/rts5208/rtsx_chip.c
@@ -598,38 +598,38 @@ nextcard:
return STATUS_SUCCESS;
}
-static inline int check_sd_speed_prior(u32 sd_speed_prior)
+static inline int valid_sd_speed_prior(u32 sd_speed_prior)
{
- bool fake_para = false;
+ bool valid_para = true;
int i;
for (i = 0; i < 4; i++) {
u8 tmp = (u8)(sd_speed_prior >> (i * 8));
if ((tmp < 0x01) || (tmp > 0x04)) {
- fake_para = true;
+ valid_para = false;
break;
}
}
- return !fake_para;
+ return valid_para;
}
-static inline int check_sd_current_prior(u32 sd_current_prior)
+static inline int valid_sd_current_prior(u32 sd_current_prior)
{
- bool fake_para = false;
+ bool valid_para = true;
int i;
for (i = 0; i < 4; i++) {
u8 tmp = (u8)(sd_current_prior >> (i * 8));
if (tmp > 0x03) {
- fake_para = true;
+ valid_para = false;
break;
}
}
- return !fake_para;
+ return valid_para;
}
static int rts5208_init(struct rtsx_chip *chip)
@@ -796,13 +796,13 @@ int rtsx_init_chip(struct rtsx_chip *chip)
chip->rw_fail_cnt[i] = 0;
}
- if (!check_sd_speed_prior(chip->sd_speed_prior))
+ if (!valid_sd_speed_prior(chip->sd_speed_prior))
chip->sd_speed_prior = 0x01040203;
dev_dbg(rtsx_dev(chip), "sd_speed_prior = 0x%08x\n",
chip->sd_speed_prior);
- if (!check_sd_current_prior(chip->sd_current_prior))
+ if (!valid_sd_current_prior(chip->sd_current_prior))
chip->sd_current_prior = 0x00010203;
dev_dbg(rtsx_dev(chip), "sd_current_prior = 0x%08x\n",
diff --git a/drivers/staging/rts5208/sd.c b/drivers/staging/rts5208/sd.c
index c256a2398651..a06045344301 100644
--- a/drivers/staging/rts5208/sd.c
+++ b/drivers/staging/rts5208/sd.c
@@ -3580,11 +3580,6 @@ RW_FAIL:
}
#ifdef SUPPORT_CPRM
-int soft_reset_sd_card(struct rtsx_chip *chip)
-{
- return reset_sd(chip);
-}
-
int ext_sd_send_cmd_get_rsp(struct rtsx_chip *chip, u8 cmd_idx, u32 arg,
u8 rsp_type, u8 *rsp, int rsp_len,
bool special_check)
@@ -4512,20 +4507,19 @@ int sd_execute_write_data(struct scsi_cmnd *srb, struct rtsx_chip *chip)
sd_lock_state, sd_card->sd_lock_status);
if (sd_lock_state ^ (sd_card->sd_lock_status & SD_LOCKED)) {
sd_card->sd_lock_notify = 1;
- if (sd_lock_state) {
- if (sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) {
- sd_card->sd_lock_status |= (
- SD_UNLOCK_POW_ON | SD_SDR_RST);
- if (CHK_SD(sd_card)) {
- retval = reset_sd(chip);
- if (retval != STATUS_SUCCESS) {
- sd_card->sd_lock_status &= ~(SD_UNLOCK_POW_ON | SD_SDR_RST);
- goto sd_execute_write_cmd_failed;
- }
+ if (sd_lock_state &&
+ (sd_card->sd_lock_status & SD_LOCK_1BIT_MODE)) {
+ sd_card->sd_lock_status |= (
+ SD_UNLOCK_POW_ON | SD_SDR_RST);
+ if (CHK_SD(sd_card)) {
+ retval = reset_sd(chip);
+ if (retval != STATUS_SUCCESS) {
+ sd_card->sd_lock_status &= ~(SD_UNLOCK_POW_ON | SD_SDR_RST);
+ goto sd_execute_write_cmd_failed;
}
-
- sd_card->sd_lock_status &= ~(SD_UNLOCK_POW_ON | SD_SDR_RST);
}
+
+ sd_card->sd_lock_status &= ~(SD_UNLOCK_POW_ON | SD_SDR_RST);
}
}
}
@@ -4639,7 +4633,7 @@ int sd_hw_rst(struct scsi_cmnd *srb, struct rtsx_chip *chip)
break;
case 1:
- retval = soft_reset_sd_card(chip);
+ retval = reset_sd(chip);
if (retval != STATUS_SUCCESS) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
sd_card->pre_cmd_err = 1;
diff --git a/drivers/staging/rts5208/sd.h b/drivers/staging/rts5208/sd.h
index e124526360b2..dc9e8cad7a74 100644
--- a/drivers/staging/rts5208/sd.h
+++ b/drivers/staging/rts5208/sd.h
@@ -273,7 +273,6 @@ void sd_cleanup_work(struct rtsx_chip *chip);
int sd_power_off_card3v3(struct rtsx_chip *chip);
int release_sd_card(struct rtsx_chip *chip);
#ifdef SUPPORT_CPRM
-int soft_reset_sd_card(struct rtsx_chip *chip);
int ext_sd_send_cmd_get_rsp(struct rtsx_chip *chip, u8 cmd_idx,
u32 arg, u8 rsp_type, u8 *rsp, int rsp_len,
bool special_check);
diff --git a/drivers/staging/rts5208/xd.c b/drivers/staging/rts5208/xd.c
index c5ee04ecd1c9..f3dc96a4c59d 100644
--- a/drivers/staging/rts5208/xd.c
+++ b/drivers/staging/rts5208/xd.c
@@ -1155,10 +1155,10 @@ static int xd_copy_page(struct rtsx_chip *chip, u32 old_blk, u32 new_blk,
return STATUS_FAIL;
}
- if (((reg & (XD_ECC1_ERROR | XD_ECC1_UNCORRECTABLE)) ==
- (XD_ECC1_ERROR | XD_ECC1_UNCORRECTABLE)) ||
- ((reg & (XD_ECC2_ERROR | XD_ECC2_UNCORRECTABLE)) ==
- (XD_ECC2_ERROR | XD_ECC2_UNCORRECTABLE))) {
+ if (((reg & XD_ECC1_ERROR) &&
+ (reg & XD_ECC1_UNCORRECTABLE)) ||
+ ((reg & XD_ECC2_ERROR) &&
+ (reg & XD_ECC2_UNCORRECTABLE))) {
rtsx_write_register(chip,
XD_PAGE_STATUS,
0xFF,
diff --git a/drivers/staging/sm750fb/Kconfig b/drivers/staging/sm750fb/Kconfig
index fb5a086bf9b1..8c0d8a873d5b 100644
--- a/drivers/staging/sm750fb/Kconfig
+++ b/drivers/staging/sm750fb/Kconfig
@@ -12,4 +12,4 @@ config FB_SM750
This driver is also available as a module. The module will be
called sm750fb. If you want to compile it as a module, say M
- here and read <file:Documentation/kbuild/modules.txt>.
+ here and read <file:Documentation/kbuild/modules.rst>.
diff --git a/drivers/staging/speakup/serialio.h b/drivers/staging/speakup/serialio.h
index aa691e4a6916..6f8f86f161bb 100644
--- a/drivers/staging/speakup/serialio.h
+++ b/drivers/staging/speakup/serialio.h
@@ -4,9 +4,6 @@
#include <linux/serial.h> /* for rs_table, serial constants */
#include <linux/serial_reg.h> /* for more serial constants */
-#ifndef __sparc__
-#include <linux/serial.h>
-#endif
#include <linux/serial_core.h>
#include "spk_priv.h"
diff --git a/drivers/staging/unisys/Documentation/overview.txt b/drivers/staging/unisys/Documentation/overview.txt
index 9ab30af265a5..f8a4144b239c 100644
--- a/drivers/staging/unisys/Documentation/overview.txt
+++ b/drivers/staging/unisys/Documentation/overview.txt
@@ -15,7 +15,7 @@ normally be unsharable, specifically:
* visorinput - keyboard and mouse
These drivers conform to the standard Linux bus/device model described
-within Documentation/driver-model/, and utilize a driver named visorbus to
+within Documentation/driver-api/driver-model/, and utilize a driver named visorbus to
present the virtual busses involved. Drivers in the 'visor*' driver set are
commonly referred to as "guest drivers" or "client drivers". All drivers
except visorbus expose a device of a specific usable class to the Linux guest
@@ -141,7 +141,7 @@ called automatically by the visorbus driver at appropriate times:
-----------------------------------
Because visorbus is a standard Linux bus driver in the model described in
-Documentation/driver-model/, the hierarchy of s-Par virtual devices is
+Documentation/driver-api/driver-model/, the hierarchy of s-Par virtual devices is
published in the sysfs tree beneath /bus/visorbus/, e.g.,
/sys/bus/visorbus/devices/ might look like:
diff --git a/drivers/staging/unisys/Kconfig b/drivers/staging/unisys/Kconfig
index dc5e1bddc085..43fe1ce538e1 100644
--- a/drivers/staging/unisys/Kconfig
+++ b/drivers/staging/unisys/Kconfig
@@ -4,8 +4,8 @@
#
menuconfig UNISYSSPAR
bool "Unisys SPAR driver support"
- ---help---
- Support for the Unisys SPAR drivers
+ help
+ Support for the Unisys SPAR drivers
if UNISYSSPAR
diff --git a/drivers/staging/unisys/visorhba/visorhba_main.c b/drivers/staging/unisys/visorhba/visorhba_main.c
index 2dad36a05518..dd979ee4dcf1 100644
--- a/drivers/staging/unisys/visorhba/visorhba_main.c
+++ b/drivers/staging/unisys/visorhba/visorhba_main.c
@@ -871,12 +871,11 @@ static void do_scsi_nolinuxstat(struct uiscmdrsp *cmdrsp,
return;
}
- sg = scsi_sglist(scsicmd);
- for (i = 0; i < scsi_sg_count(scsicmd); i++) {
- this_page_orig = kmap_atomic(sg_page(sg + i));
+ scsi_for_each_sg(scsicmd, sg, scsi_sg_count(scsicmd), i) {
+ this_page_orig = kmap_atomic(sg_page(sg));
this_page = (void *)((unsigned long)this_page_orig |
- sg[i].offset);
- memcpy(this_page, buf + bufind, sg[i].length);
+ sg->offset);
+ memcpy(this_page, buf + bufind, sg->length);
kunmap_atomic(this_page_orig);
}
kfree(buf);
diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c
index 1c1a470d2e50..9d4f1dab0968 100644
--- a/drivers/staging/unisys/visornic/visornic_main.c
+++ b/drivers/staging/unisys/visornic/visornic_main.c
@@ -1861,12 +1861,12 @@ static int visornic_probe(struct visor_device *dev)
skb_queue_head_init(&devdata->xmitbufhead);
/* create a cmdrsp we can use to post and unpost rcv buffers */
- devdata->cmdrsp_rcv = kmalloc(SIZEOF_CMDRSP, GFP_ATOMIC);
+ devdata->cmdrsp_rcv = kmalloc(SIZEOF_CMDRSP, GFP_KERNEL);
if (!devdata->cmdrsp_rcv) {
err = -ENOMEM;
goto cleanup_rcvbuf;
}
- devdata->xmit_cmdrsp = kmalloc(SIZEOF_CMDRSP, GFP_ATOMIC);
+ devdata->xmit_cmdrsp = kmalloc(SIZEOF_CMDRSP, GFP_KERNEL);
if (!devdata->xmit_cmdrsp) {
err = -ENOMEM;
goto cleanup_cmdrsp_rcv;
diff --git a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
index 68f08dc18da9..ea54cc27e645 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
@@ -4,10 +4,11 @@
*
* Copyright © 2013 Raspberry Pi (Trading) Ltd.
*
- * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
- * Dave Stevenson <dsteve@broadcom.com>
- * Simon Mellor <simellor@broadcom.com>
- * Luke Diamand <luked@broadcom.com>
+ * Authors: Vincent Sanders @ Collabora
+ * Dave Stevenson @ Broadcom
+ * (now dave.stevenson@raspberrypi.org)
+ * Simon Mellor @ Broadcom
+ * Luke Diamand @ Broadcom
*/
#include <linux/errno.h>
@@ -79,7 +80,7 @@ static struct mmal_fmt formats[] = {
.flags = 0,
.mmal = MMAL_ENCODING_I420,
.depth = 12,
- .mmal_component = MMAL_COMPONENT_CAMERA,
+ .mmal_component = COMP_CAMERA,
.ybbp = 1,
.remove_padding = 1,
}, {
@@ -88,7 +89,7 @@ static struct mmal_fmt formats[] = {
.flags = 0,
.mmal = MMAL_ENCODING_YUYV,
.depth = 16,
- .mmal_component = MMAL_COMPONENT_CAMERA,
+ .mmal_component = COMP_CAMERA,
.ybbp = 2,
.remove_padding = 0,
}, {
@@ -97,7 +98,7 @@ static struct mmal_fmt formats[] = {
.flags = 0,
.mmal = MMAL_ENCODING_RGB24,
.depth = 24,
- .mmal_component = MMAL_COMPONENT_CAMERA,
+ .mmal_component = COMP_CAMERA,
.ybbp = 3,
.remove_padding = 0,
}, {
@@ -106,7 +107,7 @@ static struct mmal_fmt formats[] = {
.flags = V4L2_FMT_FLAG_COMPRESSED,
.mmal = MMAL_ENCODING_JPEG,
.depth = 8,
- .mmal_component = MMAL_COMPONENT_IMAGE_ENCODE,
+ .mmal_component = COMP_IMAGE_ENCODE,
.ybbp = 0,
.remove_padding = 0,
}, {
@@ -115,7 +116,7 @@ static struct mmal_fmt formats[] = {
.flags = V4L2_FMT_FLAG_COMPRESSED,
.mmal = MMAL_ENCODING_H264,
.depth = 8,
- .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE,
+ .mmal_component = COMP_VIDEO_ENCODE,
.ybbp = 0,
.remove_padding = 0,
}, {
@@ -124,7 +125,7 @@ static struct mmal_fmt formats[] = {
.flags = V4L2_FMT_FLAG_COMPRESSED,
.mmal = MMAL_ENCODING_MJPEG,
.depth = 8,
- .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE,
+ .mmal_component = COMP_VIDEO_ENCODE,
.ybbp = 0,
.remove_padding = 0,
}, {
@@ -133,7 +134,7 @@ static struct mmal_fmt formats[] = {
.flags = 0,
.mmal = MMAL_ENCODING_YVYU,
.depth = 16,
- .mmal_component = MMAL_COMPONENT_CAMERA,
+ .mmal_component = COMP_CAMERA,
.ybbp = 2,
.remove_padding = 0,
}, {
@@ -142,7 +143,7 @@ static struct mmal_fmt formats[] = {
.flags = 0,
.mmal = MMAL_ENCODING_VYUY,
.depth = 16,
- .mmal_component = MMAL_COMPONENT_CAMERA,
+ .mmal_component = COMP_CAMERA,
.ybbp = 2,
.remove_padding = 0,
}, {
@@ -151,7 +152,7 @@ static struct mmal_fmt formats[] = {
.flags = 0,
.mmal = MMAL_ENCODING_UYVY,
.depth = 16,
- .mmal_component = MMAL_COMPONENT_CAMERA,
+ .mmal_component = COMP_CAMERA,
.ybbp = 2,
.remove_padding = 0,
}, {
@@ -160,7 +161,7 @@ static struct mmal_fmt formats[] = {
.flags = 0,
.mmal = MMAL_ENCODING_NV12,
.depth = 12,
- .mmal_component = MMAL_COMPONENT_CAMERA,
+ .mmal_component = COMP_CAMERA,
.ybbp = 1,
.remove_padding = 1,
}, {
@@ -169,7 +170,7 @@ static struct mmal_fmt formats[] = {
.flags = 0,
.mmal = MMAL_ENCODING_BGR24,
.depth = 24,
- .mmal_component = MMAL_COMPONENT_CAMERA,
+ .mmal_component = COMP_CAMERA,
.ybbp = 3,
.remove_padding = 0,
}, {
@@ -178,7 +179,7 @@ static struct mmal_fmt formats[] = {
.flags = 0,
.mmal = MMAL_ENCODING_YV12,
.depth = 12,
- .mmal_component = MMAL_COMPONENT_CAMERA,
+ .mmal_component = COMP_CAMERA,
.ybbp = 1,
.remove_padding = 1,
}, {
@@ -187,7 +188,7 @@ static struct mmal_fmt formats[] = {
.flags = 0,
.mmal = MMAL_ENCODING_NV21,
.depth = 12,
- .mmal_component = MMAL_COMPONENT_CAMERA,
+ .mmal_component = COMP_CAMERA,
.ybbp = 1,
.remove_padding = 1,
}, {
@@ -196,7 +197,7 @@ static struct mmal_fmt formats[] = {
.flags = 0,
.mmal = MMAL_ENCODING_BGRA,
.depth = 32,
- .mmal_component = MMAL_COMPONENT_CAMERA,
+ .mmal_component = COMP_CAMERA,
.ybbp = 4,
.remove_padding = 0,
},
@@ -235,6 +236,22 @@ static int queue_setup(struct vb2_queue *vq,
return -EINVAL;
}
+ /* Handle CREATE_BUFS situation - *nplanes != 0 */
+ if (*nplanes) {
+ if (*nplanes != 1 ||
+ sizes[0] < dev->capture.port->current_buffer.size) {
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "%s: dev:%p Invalid buffer request from CREATE_BUFS, size %u < %u, nplanes %u != 1\n",
+ __func__, dev, sizes[0],
+ dev->capture.port->current_buffer.size,
+ *nplanes);
+ return -EINVAL;
+ } else {
+ return 0;
+ }
+ }
+
+ /* Handle REQBUFS situation */
size = dev->capture.port->current_buffer.size;
if (size == 0) {
v4l2_err(&dev->v4l2_dev,
@@ -312,7 +329,7 @@ static void buffer_cleanup(struct vb2_buffer *vb)
static inline bool is_capturing(struct bm2835_mmal_dev *dev)
{
return dev->capture.camera_port ==
- &dev->component[MMAL_COMPONENT_CAMERA]->output[MMAL_CAMERA_PORT_CAPTURE];
+ &dev->component[COMP_CAMERA]->output[CAM_PORT_CAPTURE];
}
static void buffer_cb(struct vchiq_mmal_instance *instance,
@@ -327,25 +344,24 @@ static void buffer_cb(struct vchiq_mmal_instance *instance,
"%s: status:%d, buf:%p, length:%lu, flags %u, pts %lld\n",
__func__, status, buf, length, mmal_flags, pts);
- if (status != 0) {
+ if (status) {
/* error in transfer */
if (buf) {
/* there was a buffer with the error so return it */
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
}
return;
- } else if (length == 0) {
+ }
+
+ if (length == 0) {
/* stream ended */
- if (buf) {
- /* this should only ever happen if the port is
- * disabled and there are buffers still queued
+ if (dev->capture.frame_count) {
+ /* empty buffer whilst capturing - expected to be an
+ * EOS, so grab another frame
*/
- vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
- pr_debug("Empty buffer");
- } else if (dev->capture.frame_count) {
- /* grab another frame */
if (is_capturing(dev)) {
- pr_debug("Grab another frame");
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "Grab another frame");
vchiq_mmal_port_parameter_set(
instance,
dev->capture.camera_port,
@@ -353,48 +369,60 @@ static void buffer_cb(struct vchiq_mmal_instance *instance,
&dev->capture.frame_count,
sizeof(dev->capture.frame_count));
}
+ if (vchiq_mmal_submit_buffer(instance, port, buf))
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "Failed to return EOS buffer");
} else {
- /* signal frame completion */
+ /* stopping streaming.
+ * return buffer, and signal frame completion
+ */
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
complete(&dev->capture.frame_cmplt);
}
+ return;
+ }
+
+ if (!dev->capture.frame_count) {
+ /* signal frame completion */
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+ complete(&dev->capture.frame_cmplt);
+ return;
+ }
+
+ if (dev->capture.vc_start_timestamp != -1 && pts) {
+ ktime_t timestamp;
+ s64 runtime_us = pts -
+ dev->capture.vc_start_timestamp;
+ timestamp = ktime_add_us(dev->capture.kernel_start_ts,
+ runtime_us);
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "Convert start time %llu and %llu with offset %llu to %llu\n",
+ ktime_to_ns(dev->capture.kernel_start_ts),
+ dev->capture.vc_start_timestamp, pts,
+ ktime_to_ns(timestamp));
+ buf->vb.vb2_buf.timestamp = ktime_to_ns(timestamp);
} else {
- if (dev->capture.frame_count) {
- if (dev->capture.vc_start_timestamp != -1 &&
- pts != 0) {
- ktime_t timestamp;
- s64 runtime_us = pts -
- dev->capture.vc_start_timestamp;
- timestamp = ktime_add_us(dev->capture.kernel_start_ts,
- runtime_us);
- v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
- "Convert start time %llu and %llu with offset %llu to %llu\n",
- ktime_to_ns(dev->capture.kernel_start_ts),
- dev->capture.vc_start_timestamp, pts,
- ktime_to_ns(timestamp));
- buf->vb.vb2_buf.timestamp = ktime_to_ns(timestamp);
- } else {
- buf->vb.vb2_buf.timestamp = ktime_get_ns();
- }
+ buf->vb.vb2_buf.timestamp = ktime_get_ns();
+ }
+ buf->vb.sequence = dev->capture.sequence++;
+ buf->vb.field = V4L2_FIELD_NONE;
- vb2_set_plane_payload(&buf->vb.vb2_buf, 0, length);
- vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
+ vb2_set_plane_payload(&buf->vb.vb2_buf, 0, length);
+ if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME)
+ buf->vb.flags |= V4L2_BUF_FLAG_KEYFRAME;
- if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS &&
- is_capturing(dev)) {
- v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
- "Grab another frame as buffer has EOS");
- vchiq_mmal_port_parameter_set(
- instance,
- dev->capture.camera_port,
- MMAL_PARAMETER_CAPTURE,
- &dev->capture.frame_count,
- sizeof(dev->capture.frame_count));
- }
- } else {
- /* signal frame completion */
- vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
- complete(&dev->capture.frame_cmplt);
- }
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
+
+ if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS &&
+ is_capturing(dev)) {
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "Grab another frame as buffer has EOS");
+ vchiq_mmal_port_parameter_set(
+ instance,
+ dev->capture.camera_port,
+ MMAL_PARAMETER_CAPTURE,
+ &dev->capture.frame_count,
+ sizeof(dev->capture.frame_count));
}
}
@@ -405,7 +433,7 @@ static int enable_camera(struct bm2835_mmal_dev *dev)
if (!dev->camera_use_count) {
ret = vchiq_mmal_port_parameter_set(
dev->instance,
- &dev->component[MMAL_COMPONENT_CAMERA]->control,
+ &dev->component[COMP_CAMERA]->control,
MMAL_PARAMETER_CAMERA_NUM, &dev->camera_num,
sizeof(dev->camera_num));
if (ret < 0) {
@@ -416,7 +444,7 @@ static int enable_camera(struct bm2835_mmal_dev *dev)
ret = vchiq_mmal_component_enable(
dev->instance,
- dev->component[MMAL_COMPONENT_CAMERA]);
+ dev->component[COMP_CAMERA]);
if (ret < 0) {
v4l2_err(&dev->v4l2_dev,
"Failed enabling camera, ret %d\n", ret);
@@ -448,7 +476,7 @@ static int disable_camera(struct bm2835_mmal_dev *dev)
ret =
vchiq_mmal_component_disable(
dev->instance,
- dev->component[MMAL_COMPONENT_CAMERA]);
+ dev->component[COMP_CAMERA]);
if (ret < 0) {
v4l2_err(&dev->v4l2_dev,
"Failed disabling camera, ret %d\n", ret);
@@ -456,7 +484,7 @@ static int disable_camera(struct bm2835_mmal_dev *dev)
}
vchiq_mmal_port_parameter_set(
dev->instance,
- &dev->component[MMAL_COMPONENT_CAMERA]->control,
+ &dev->component[COMP_CAMERA]->control,
MMAL_PARAMETER_CAMERA_NUM, &i,
sizeof(i));
}
@@ -505,10 +533,13 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
/* enable frame capture */
dev->capture.frame_count = 1;
+ /* reset sequence number */
+ dev->capture.sequence = 0;
+
/* if the preview is not already running, wait for a few frames for AGC
* to settle down.
*/
- if (!dev->component[MMAL_COMPONENT_PREVIEW]->enabled)
+ if (!dev->component[COMP_PREVIEW]->enabled)
msleep(300);
/* enable the connection from camera to encoder (if applicable) */
@@ -536,10 +567,11 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
/* Flag to indicate just to rely on kernel timestamps */
dev->capture.vc_start_timestamp = -1;
- } else
+ } else {
v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
"Start time %lld size %d\n",
dev->capture.vc_start_timestamp, parameter_size);
+ }
dev->capture.kernel_start_ts = ktime_get();
@@ -549,8 +581,8 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
vchiq_mmal_port_enable(dev->instance, dev->capture.port, buffer_cb);
if (ret) {
v4l2_err(&dev->v4l2_dev,
- "Failed to enable capture port - error %d. Disabling camera port again\n",
- ret);
+ "Failed to enable capture port - error %d. Disabling camera port again\n",
+ ret);
vchiq_mmal_port_disable(dev->instance,
dev->capture.camera_port);
@@ -576,6 +608,7 @@ static void stop_streaming(struct vb2_queue *vq)
int ret;
unsigned long timeout;
struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq);
+ struct vchiq_mmal_port *port = dev->capture.port;
v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p\n",
__func__, dev);
@@ -599,12 +632,6 @@ static void stop_streaming(struct vb2_queue *vq)
&dev->capture.frame_count,
sizeof(dev->capture.frame_count));
- /* wait for last frame to complete */
- timeout = wait_for_completion_timeout(&dev->capture.frame_cmplt, HZ);
- if (timeout == 0)
- v4l2_err(&dev->v4l2_dev,
- "timed out waiting for frame completion\n");
-
v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
"disabling connection\n");
@@ -619,6 +646,21 @@ static void stop_streaming(struct vb2_queue *vq)
ret);
}
+ /* wait for all buffers to be returned */
+ while (atomic_read(&port->buffers_with_vpu)) {
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "%s: Waiting for buffers to be returned - %d outstanding\n",
+ __func__, atomic_read(&port->buffers_with_vpu));
+ timeout = wait_for_completion_timeout(&dev->capture.frame_cmplt,
+ HZ);
+ if (timeout == 0) {
+ v4l2_err(&dev->v4l2_dev, "%s: Timeout waiting for buffers to be returned - %d outstanding\n",
+ __func__,
+ atomic_read(&port->buffers_with_vpu));
+ break;
+ }
+ }
+
if (disable_camera(dev) < 0)
v4l2_err(&dev->v4l2_dev, "Failed to disable camera\n");
}
@@ -730,9 +772,9 @@ static int vidioc_s_fmt_vid_overlay(struct file *file, void *priv,
vidioc_try_fmt_vid_overlay(file, priv, f);
dev->overlay = f->fmt.win;
- if (dev->component[MMAL_COMPONENT_PREVIEW]->enabled) {
+ if (dev->component[COMP_PREVIEW]->enabled) {
set_overlay_params(dev,
- &dev->component[MMAL_COMPONENT_PREVIEW]->input[0]);
+ &dev->component[COMP_PREVIEW]->input[0]);
}
return 0;
@@ -745,12 +787,12 @@ static int vidioc_overlay(struct file *file, void *f, unsigned int on)
struct vchiq_mmal_port *src;
struct vchiq_mmal_port *dst;
- if ((on && dev->component[MMAL_COMPONENT_PREVIEW]->enabled) ||
- (!on && !dev->component[MMAL_COMPONENT_PREVIEW]->enabled))
+ if ((on && dev->component[COMP_PREVIEW]->enabled) ||
+ (!on && !dev->component[COMP_PREVIEW]->enabled))
return 0; /* already in requested state */
src =
- &dev->component[MMAL_COMPONENT_CAMERA]->output[MMAL_CAMERA_PORT_PREVIEW];
+ &dev->component[COMP_CAMERA]->output[CAM_PORT_PREVIEW];
if (!on) {
/* disconnect preview ports and disable component */
@@ -762,39 +804,39 @@ static int vidioc_overlay(struct file *file, void *f, unsigned int on)
if (ret >= 0)
ret = vchiq_mmal_component_disable(
dev->instance,
- dev->component[MMAL_COMPONENT_PREVIEW]);
+ dev->component[COMP_PREVIEW]);
disable_camera(dev);
return ret;
}
/* set preview port format and connect it to output */
- dst = &dev->component[MMAL_COMPONENT_PREVIEW]->input[0];
+ dst = &dev->component[COMP_PREVIEW]->input[0];
ret = vchiq_mmal_port_set_format(dev->instance, src);
if (ret < 0)
- goto error;
+ return ret;
ret = set_overlay_params(dev, dst);
if (ret < 0)
- goto error;
+ return ret;
if (enable_camera(dev) < 0)
- goto error;
+ return -EINVAL;
ret = vchiq_mmal_component_enable(
dev->instance,
- dev->component[MMAL_COMPONENT_PREVIEW]);
+ dev->component[COMP_PREVIEW]);
if (ret < 0)
- goto error;
+ return ret;
v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "connecting %p to %p\n",
src, dst);
ret = vchiq_mmal_port_connect_tunnel(dev->instance, src, dst);
- if (!ret)
- ret = vchiq_mmal_port_enable(dev->instance, src, NULL);
-error:
- return ret;
+ if (ret)
+ return ret;
+
+ return vchiq_mmal_port_enable(dev->instance, src, NULL);
}
static int vidioc_g_fbuf(struct file *file, void *fh,
@@ -805,7 +847,7 @@ static int vidioc_g_fbuf(struct file *file, void *fh,
*/
struct bm2835_mmal_dev *dev = video_drvdata(file);
struct vchiq_mmal_port *preview_port =
- &dev->component[MMAL_COMPONENT_CAMERA]->output[MMAL_CAMERA_PORT_PREVIEW];
+ &dev->component[COMP_CAMERA]->output[CAM_PORT_PREVIEW];
a->capability = V4L2_FBUF_CAP_EXTERNOVERLAY |
V4L2_FBUF_CAP_GLOBAL_ALPHA;
@@ -826,7 +868,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
struct v4l2_input *inp)
{
/* only a single camera input */
- if (inp->index != 0)
+ if (inp->index)
return -EINVAL;
inp->type = V4L2_INPUT_TYPE_CAMERA;
@@ -842,7 +884,7 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
{
- if (i != 0)
+ if (i)
return -EINVAL;
return 0;
@@ -864,10 +906,6 @@ static int vidioc_querycap(struct file *file, void *priv,
snprintf((char *)cap->bus_info, sizeof(cap->bus_info),
"platform:%s", dev->v4l2_dev.name);
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY |
- V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
-
return 0;
}
@@ -939,14 +977,27 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
1, 0);
f->fmt.pix.bytesperline = f->fmt.pix.width * mfmt->ybbp;
if (!mfmt->remove_padding) {
- int align_mask = ((32 * mfmt->depth) >> 3) - 1;
- /* GPU isn't removing padding, so stride is aligned to 32 */
- f->fmt.pix.bytesperline =
- (f->fmt.pix.bytesperline + align_mask) & ~align_mask;
+ if (mfmt->depth == 24) {
+ /*
+ * 24bpp is a pain as we can't use simple masking.
+ * Min stride is width aligned to 16, times 24bpp.
+ */
+ f->fmt.pix.bytesperline =
+ ((f->fmt.pix.width + 15) & ~15) * 3;
+ } else {
+ /*
+ * GPU isn't removing padding, so stride is aligned to
+ * 32
+ */
+ int align_mask = ((32 * mfmt->depth) >> 3) - 1;
+
+ f->fmt.pix.bytesperline =
+ (f->fmt.pix.bytesperline + align_mask) &
+ ~align_mask;
+ }
v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
- "Not removing padding, so bytes/line = %d, "
- "(align_mask %d)\n",
- f->fmt.pix.bytesperline, align_mask);
+ "Not removing padding, so bytes/line = %d\n",
+ f->fmt.pix.bytesperline);
}
/* Image buffer has to be padded to allow for alignment, even though
@@ -1007,27 +1058,28 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev,
}
/* format dependent port setup */
switch (mfmt->mmal_component) {
- case MMAL_COMPONENT_CAMERA:
+ case COMP_CAMERA:
/* Make a further decision on port based on resolution */
if (f->fmt.pix.width <= max_video_width &&
f->fmt.pix.height <= max_video_height)
- camera_port = port =
- &dev->component[MMAL_COMPONENT_CAMERA]->output[MMAL_CAMERA_PORT_VIDEO];
+ camera_port =
+ &dev->component[COMP_CAMERA]->output[CAM_PORT_VIDEO];
else
- camera_port = port =
- &dev->component[MMAL_COMPONENT_CAMERA]->output[MMAL_CAMERA_PORT_CAPTURE];
+ camera_port =
+ &dev->component[COMP_CAMERA]->output[CAM_PORT_CAPTURE];
+ port = camera_port;
break;
- case MMAL_COMPONENT_IMAGE_ENCODE:
- encode_component = dev->component[MMAL_COMPONENT_IMAGE_ENCODE];
- port = &dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->output[0];
+ case COMP_IMAGE_ENCODE:
+ encode_component = dev->component[COMP_IMAGE_ENCODE];
+ port = &dev->component[COMP_IMAGE_ENCODE]->output[0];
camera_port =
- &dev->component[MMAL_COMPONENT_CAMERA]->output[MMAL_CAMERA_PORT_CAPTURE];
+ &dev->component[COMP_CAMERA]->output[CAM_PORT_CAPTURE];
break;
- case MMAL_COMPONENT_VIDEO_ENCODE:
- encode_component = dev->component[MMAL_COMPONENT_VIDEO_ENCODE];
- port = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
+ case COMP_VIDEO_ENCODE:
+ encode_component = dev->component[COMP_VIDEO_ENCODE];
+ port = &dev->component[COMP_VIDEO_ENCODE]->output[0];
camera_port =
- &dev->component[MMAL_COMPONENT_CAMERA]->output[MMAL_CAMERA_PORT_VIDEO];
+ &dev->component[COMP_CAMERA]->output[CAM_PORT_VIDEO];
break;
default:
break;
@@ -1067,13 +1119,13 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev,
ret = vchiq_mmal_port_set_format(dev->instance, camera_port);
- if (!ret &&
- camera_port ==
- &dev->component[MMAL_COMPONENT_CAMERA]->output[MMAL_CAMERA_PORT_VIDEO]) {
+ if (!ret
+ && camera_port ==
+ &dev->component[COMP_CAMERA]->output[CAM_PORT_VIDEO]) {
bool overlay_enabled =
- !!dev->component[MMAL_COMPONENT_PREVIEW]->enabled;
+ !!dev->component[COMP_PREVIEW]->enabled;
struct vchiq_mmal_port *preview_port =
- &dev->component[MMAL_COMPONENT_CAMERA]->output[MMAL_CAMERA_PORT_PREVIEW];
+ &dev->component[COMP_CAMERA]->output[CAM_PORT_PREVIEW];
/* Preview and encode ports need to match on resolution */
if (overlay_enabled) {
/* Need to disable the overlay before we can update
@@ -1104,7 +1156,7 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev,
ret = vchiq_mmal_port_connect_tunnel(
dev->instance,
preview_port,
- &dev->component[MMAL_COMPONENT_PREVIEW]->input[0]);
+ &dev->component[COMP_PREVIEW]->input[0]);
if (!ret)
ret = vchiq_mmal_port_enable(dev->instance,
preview_port,
@@ -1158,11 +1210,11 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev,
port->format.encoding_variant = 0;
/* Set any encoding specific parameters */
switch (mfmt->mmal_component) {
- case MMAL_COMPONENT_VIDEO_ENCODE:
+ case COMP_VIDEO_ENCODE:
port->format.bitrate =
dev->capture.encode_bitrate;
break;
- case MMAL_COMPONENT_IMAGE_ENCODE:
+ case COMP_IMAGE_ENCODE:
/* Could set EXIF parameters here */
break;
default:
@@ -1206,9 +1258,8 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev,
port->current_buffer.size);
port->current_buffer.size =
(f->fmt.pix.sizeimage <
- (100 << 10))
- ? (100 << 10)
- : f->fmt.pix.sizeimage;
+ (100 << 10)) ?
+ (100 << 10) : f->fmt.pix.sizeimage;
}
v4l2_dbg(1, bcm2835_v4l2_debug,
&dev->v4l2_dev,
@@ -1281,7 +1332,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
}
ret = mmal_setup_components(dev, f);
- if (ret != 0) {
+ if (ret) {
v4l2_err(&dev->v4l2_dev,
"%s: failed to setup mmal components: %d\n",
__func__, ret);
@@ -1292,7 +1343,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
}
static int vidioc_enum_framesizes(struct file *file, void *fh,
- struct v4l2_frmsizeenum *fsize)
+ struct v4l2_frmsizeenum *fsize)
{
struct bm2835_mmal_dev *dev = video_drvdata(file);
static const struct v4l2_frmsize_stepwise sizes = {
@@ -1446,6 +1497,8 @@ static const struct video_device vdev_template = {
.fops = &camera0_fops,
.ioctl_ops = &camera0_ioctl_ops,
.release = video_device_release_empty,
+ .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY |
+ V4L2_CAP_STREAMING | V4L2_CAP_READWRITE,
};
/* Returns the number of cameras, and also the max resolution supported
@@ -1531,14 +1584,14 @@ static int mmal_init(struct bm2835_mmal_dev *dev)
/* get the camera component ready */
ret = vchiq_mmal_component_init(dev->instance, "ril.camera",
- &dev->component[MMAL_COMPONENT_CAMERA]);
+ &dev->component[COMP_CAMERA]);
if (ret < 0)
goto unreg_mmal;
- camera = dev->component[MMAL_COMPONENT_CAMERA];
- if (camera->outputs < MMAL_CAMERA_PORT_COUNT) {
+ camera = dev->component[COMP_CAMERA];
+ if (camera->outputs < CAM_PORT_COUNT) {
v4l2_err(&dev->v4l2_dev, "%s: too few camera outputs %d needed %d\n",
- __func__, camera->outputs, MMAL_CAMERA_PORT_COUNT);
+ __func__, camera->outputs, CAM_PORT_COUNT);
ret = -EINVAL;
goto unreg_camera;
}
@@ -1560,7 +1613,7 @@ static int mmal_init(struct bm2835_mmal_dev *dev)
dev->rgb_bgr_swapped = true;
param_size = sizeof(supported_encodings);
ret = vchiq_mmal_port_parameter_get(dev->instance,
- &camera->output[MMAL_CAMERA_PORT_CAPTURE],
+ &camera->output[CAM_PORT_CAPTURE],
MMAL_PARAMETER_SUPPORTED_ENCODINGS,
&supported_encodings,
&param_size);
@@ -1581,7 +1634,7 @@ static int mmal_init(struct bm2835_mmal_dev *dev)
}
}
}
- format = &camera->output[MMAL_CAMERA_PORT_PREVIEW].format;
+ format = &camera->output[CAM_PORT_PREVIEW].format;
format->encoding = MMAL_ENCODING_OPAQUE;
format->encoding_variant = MMAL_ENCODING_I420;
@@ -1595,7 +1648,7 @@ static int mmal_init(struct bm2835_mmal_dev *dev)
format->es->video.frame_rate.num = 0; /* Rely on fps_range */
format->es->video.frame_rate.den = 1;
- format = &camera->output[MMAL_CAMERA_PORT_VIDEO].format;
+ format = &camera->output[CAM_PORT_VIDEO].format;
format->encoding = MMAL_ENCODING_OPAQUE;
format->encoding_variant = MMAL_ENCODING_I420;
@@ -1609,7 +1662,7 @@ static int mmal_init(struct bm2835_mmal_dev *dev)
format->es->video.frame_rate.num = 0; /* Rely on fps_range */
format->es->video.frame_rate.den = 1;
- format = &camera->output[MMAL_CAMERA_PORT_CAPTURE].format;
+ format = &camera->output[CAM_PORT_CAPTURE].format;
format->encoding = MMAL_ENCODING_OPAQUE;
@@ -1633,49 +1686,49 @@ static int mmal_init(struct bm2835_mmal_dev *dev)
/* get the preview component ready */
ret = vchiq_mmal_component_init(
dev->instance, "ril.video_render",
- &dev->component[MMAL_COMPONENT_PREVIEW]);
+ &dev->component[COMP_PREVIEW]);
if (ret < 0)
goto unreg_camera;
- if (dev->component[MMAL_COMPONENT_PREVIEW]->inputs < 1) {
+ if (dev->component[COMP_PREVIEW]->inputs < 1) {
ret = -EINVAL;
v4l2_err(&dev->v4l2_dev, "%s: too few input ports %d needed %d\n",
- __func__, dev->component[MMAL_COMPONENT_PREVIEW]->inputs, 1);
+ __func__, dev->component[COMP_PREVIEW]->inputs, 1);
goto unreg_preview;
}
/* get the image encoder component ready */
ret = vchiq_mmal_component_init(
dev->instance, "ril.image_encode",
- &dev->component[MMAL_COMPONENT_IMAGE_ENCODE]);
+ &dev->component[COMP_IMAGE_ENCODE]);
if (ret < 0)
goto unreg_preview;
- if (dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->inputs < 1) {
+ if (dev->component[COMP_IMAGE_ENCODE]->inputs < 1) {
ret = -EINVAL;
v4l2_err(&dev->v4l2_dev, "%s: too few input ports %d needed %d\n",
- __func__, dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->inputs,
+ __func__, dev->component[COMP_IMAGE_ENCODE]->inputs,
1);
goto unreg_image_encoder;
}
/* get the video encoder component ready */
ret = vchiq_mmal_component_init(dev->instance, "ril.video_encode",
- &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]);
+ &dev->component[COMP_VIDEO_ENCODE]);
if (ret < 0)
goto unreg_image_encoder;
- if (dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->inputs < 1) {
+ if (dev->component[COMP_VIDEO_ENCODE]->inputs < 1) {
ret = -EINVAL;
v4l2_err(&dev->v4l2_dev, "%s: too few input ports %d needed %d\n",
- __func__, dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->inputs,
+ __func__, dev->component[COMP_VIDEO_ENCODE]->inputs,
1);
goto unreg_vid_encoder;
}
{
struct vchiq_mmal_port *encoder_port =
- &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
+ &dev->component[COMP_VIDEO_ENCODE]->output[0];
encoder_port->format.encoding = MMAL_ENCODING_H264;
ret = vchiq_mmal_port_set_format(dev->instance,
encoder_port);
@@ -1686,12 +1739,12 @@ static int mmal_init(struct bm2835_mmal_dev *dev)
vchiq_mmal_port_parameter_set(
dev->instance,
- &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->control,
+ &dev->component[COMP_VIDEO_ENCODE]->control,
MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT,
&enable, sizeof(enable));
vchiq_mmal_port_parameter_set(dev->instance,
- &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->control,
+ &dev->component[COMP_VIDEO_ENCODE]->control,
MMAL_PARAMETER_MINIMISE_FRAGMENTATION,
&enable,
sizeof(enable));
@@ -1709,23 +1762,23 @@ unreg_vid_encoder:
pr_err("Cleanup: Destroy video encoder\n");
vchiq_mmal_component_finalise(
dev->instance,
- dev->component[MMAL_COMPONENT_VIDEO_ENCODE]);
+ dev->component[COMP_VIDEO_ENCODE]);
unreg_image_encoder:
pr_err("Cleanup: Destroy image encoder\n");
vchiq_mmal_component_finalise(
dev->instance,
- dev->component[MMAL_COMPONENT_IMAGE_ENCODE]);
+ dev->component[COMP_IMAGE_ENCODE]);
unreg_preview:
pr_err("Cleanup: Destroy video render\n");
vchiq_mmal_component_finalise(dev->instance,
- dev->component[MMAL_COMPONENT_PREVIEW]);
+ dev->component[COMP_PREVIEW]);
unreg_camera:
pr_err("Cleanup: Destroy camera\n");
vchiq_mmal_component_finalise(dev->instance,
- dev->component[MMAL_COMPONENT_CAMERA]);
+ dev->component[COMP_CAMERA]);
unreg_mmal:
vchiq_mmal_finalise(dev->instance);
@@ -1781,19 +1834,19 @@ static void bcm2835_cleanup_instance(struct bm2835_mmal_dev *dev)
dev->capture.encode_component);
}
vchiq_mmal_component_disable(dev->instance,
- dev->component[MMAL_COMPONENT_CAMERA]);
+ dev->component[COMP_CAMERA]);
vchiq_mmal_component_finalise(dev->instance,
- dev->component[MMAL_COMPONENT_VIDEO_ENCODE]);
+ dev->component[COMP_VIDEO_ENCODE]);
vchiq_mmal_component_finalise(dev->instance,
- dev->component[MMAL_COMPONENT_IMAGE_ENCODE]);
+ dev->component[COMP_IMAGE_ENCODE]);
vchiq_mmal_component_finalise(dev->instance,
- dev->component[MMAL_COMPONENT_PREVIEW]);
+ dev->component[COMP_PREVIEW]);
vchiq_mmal_component_finalise(dev->instance,
- dev->component[MMAL_COMPONENT_CAMERA]);
+ dev->component[COMP_CAMERA]);
v4l2_ctrl_handler_free(&dev->ctrl_handler);
diff --git a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h
index 2b5679eb5b4a..b5fce38de038 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h
+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h
@@ -4,10 +4,11 @@
*
* Copyright © 2013 Raspberry Pi (Trading) Ltd.
*
- * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
- * Dave Stevenson <dsteve@broadcom.com>
- * Simon Mellor <simellor@broadcom.com>
- * Luke Diamand <luked@broadcom.com>
+ * Authors: Vincent Sanders @ Collabora
+ * Dave Stevenson @ Broadcom
+ * (now dave.stevenson@raspberrypi.org)
+ * Simon Mellor @ Broadcom
+ * Luke Diamand @ Broadcom
*
* core driver device
*/
@@ -15,18 +16,18 @@
#define V4L2_CTRL_COUNT 29 /* number of v4l controls */
enum {
- MMAL_COMPONENT_CAMERA = 0,
- MMAL_COMPONENT_PREVIEW,
- MMAL_COMPONENT_IMAGE_ENCODE,
- MMAL_COMPONENT_VIDEO_ENCODE,
- MMAL_COMPONENT_COUNT
+ COMP_CAMERA = 0,
+ COMP_PREVIEW,
+ COMP_IMAGE_ENCODE,
+ COMP_VIDEO_ENCODE,
+ COMP_COUNT
};
enum {
- MMAL_CAMERA_PORT_PREVIEW = 0,
- MMAL_CAMERA_PORT_VIDEO,
- MMAL_CAMERA_PORT_CAPTURE,
- MMAL_CAMERA_PORT_COUNT
+ CAM_PORT_PREVIEW = 0,
+ CAM_PORT_VIDEO,
+ CAM_PORT_CAPTURE,
+ CAM_PORT_COUNT
};
#define PREVIEW_LAYER 2
@@ -60,7 +61,7 @@ struct bm2835_mmal_dev {
/* allocated mmal instance and components */
struct vchiq_mmal_instance *instance;
- struct vchiq_mmal_component *component[MMAL_COMPONENT_COUNT];
+ struct vchiq_mmal_component *component[COMP_COUNT];
int camera_use_count;
struct v4l2_window overlay;
@@ -90,6 +91,8 @@ struct bm2835_mmal_dev {
s64 vc_start_timestamp;
/* Kernel start timestamp for streaming */
ktime_t kernel_start_ts;
+ /* Sequence number of last buffer */
+ u32 sequence;
struct vchiq_mmal_port *port; /* port being used for capture */
/* camera port being used for capture */
@@ -127,6 +130,7 @@ int set_framerate_params(struct bm2835_mmal_dev *dev);
(pix_fmt)->pixelformat, (pix_fmt)->bytesperline, \
(pix_fmt)->sizeimage, (pix_fmt)->colorspace, (pix_fmt)->priv); \
}
+
#define v4l2_dump_win_format(level, debug, dev, win_fmt, desc) \
{ \
v4l2_dbg(level, debug, dev, \
diff --git a/drivers/staging/vc04_services/bcm2835-camera/controls.c b/drivers/staging/vc04_services/bcm2835-camera/controls.c
index dade79738a29..89786c264867 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
+++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
@@ -4,10 +4,11 @@
*
* Copyright © 2013 Raspberry Pi (Trading) Ltd.
*
- * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
- * Dave Stevenson <dsteve@broadcom.com>
- * Simon Mellor <simellor@broadcom.com>
- * Luke Diamand <luked@broadcom.com>
+ * Authors: Vincent Sanders @ Collabora
+ * Dave Stevenson @ Broadcom
+ * (now dave.stevenson@raspberrypi.org)
+ * Simon Mellor @ Broadcom
+ * Luke Diamand @ Broadcom
*/
#include <linux/errno.h>
@@ -52,21 +53,9 @@ static const s64 ev_bias_qmenu[] = {
static const s64 iso_qmenu[] = {
0, 100000, 200000, 400000, 800000,
};
-static const uint32_t iso_values[] = {
- 0, 100, 200, 400, 800,
-};
-static const s64 mains_freq_qmenu[] = {
- V4L2_CID_POWER_LINE_FREQUENCY_DISABLED,
- V4L2_CID_POWER_LINE_FREQUENCY_50HZ,
- V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
- V4L2_CID_POWER_LINE_FREQUENCY_AUTO
-};
-
-/* Supported video encode modes */
-static const s64 bitrate_mode_qmenu[] = {
- (s64)V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
- (s64)V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
+static const u32 iso_values[] = {
+ 0, 100, 200, 400, 800,
};
enum bm2835_mmal_ctrl_type {
@@ -89,10 +78,10 @@ struct bm2835_mmal_v4l2_ctrl {
/* control minimum value or
* mask for MMAL_CONTROL_TYPE_STD_MENU
*/
- s32 min;
- s32 max; /* maximum value of control */
- s32 def; /* default value of control */
- s32 step; /* step size of the control */
+ s64 min;
+ s64 max; /* maximum value of control */
+ s64 def; /* default value of control */
+ u64 step; /* step size of the control */
const s64 *imenu; /* integer menu array */
u32 mmal_id; /* mmal parameter id */
bm2835_mmal_v4l2_ctrl_cb *setter;
@@ -175,7 +164,7 @@ static int ctrl_set_rational(struct bm2835_mmal_dev *dev,
struct mmal_parameter_rational rational_value;
struct vchiq_mmal_port *control;
- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+ control = &dev->component[COMP_CAMERA]->control;
rational_value.num = ctrl->val;
rational_value.den = 100;
@@ -193,7 +182,7 @@ static int ctrl_set_value(struct bm2835_mmal_dev *dev,
u32 u32_value;
struct vchiq_mmal_port *control;
- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+ control = &dev->component[COMP_CAMERA]->control;
u32_value = ctrl->val;
@@ -218,7 +207,7 @@ static int ctrl_set_iso(struct bm2835_mmal_dev *dev,
dev->manual_iso_enabled =
(ctrl->val == V4L2_ISO_SENSITIVITY_MANUAL);
- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+ control = &dev->component[COMP_CAMERA]->control;
if (dev->manual_iso_enabled)
u32_value = dev->iso;
@@ -237,7 +226,7 @@ static int ctrl_set_value_ev(struct bm2835_mmal_dev *dev,
s32 s32_value;
struct vchiq_mmal_port *control;
- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+ control = &dev->component[COMP_CAMERA]->control;
s32_value = (ctrl->val - 12) * 2; /* Convert from index to 1/6ths */
@@ -254,7 +243,7 @@ static int ctrl_set_rotate(struct bm2835_mmal_dev *dev,
u32 u32_value;
struct vchiq_mmal_component *camera;
- camera = dev->component[MMAL_COMPONENT_CAMERA];
+ camera = dev->component[COMP_CAMERA];
u32_value = ((ctrl->val % 360) / 90) * 90;
@@ -288,7 +277,7 @@ static int ctrl_set_flip(struct bm2835_mmal_dev *dev,
else
dev->vflip = ctrl->val;
- camera = dev->component[MMAL_COMPONENT_CAMERA];
+ camera = dev->component[COMP_CAMERA];
if (dev->hflip && dev->vflip)
u32_value = MMAL_PARAM_MIRROR_BOTH;
@@ -325,7 +314,7 @@ static int ctrl_set_exposure(struct bm2835_mmal_dev *dev,
struct vchiq_mmal_port *control;
int ret = 0;
- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+ control = &dev->component[COMP_CAMERA]->control;
if (mmal_ctrl->mmal_id == MMAL_PARAMETER_SHUTTER_SPEED) {
/* V4L2 is in 100usec increments.
@@ -400,13 +389,14 @@ static int ctrl_set_metering_mode(struct bm2835_mmal_dev *dev,
struct vchiq_mmal_port *control;
u32 u32_value = dev->metering_mode;
- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+ control = &dev->component[COMP_CAMERA]->control;
return vchiq_mmal_port_parameter_set(dev->instance, control,
mmal_ctrl->mmal_id,
&u32_value, sizeof(u32_value));
- } else
+ } else {
return 0;
+ }
}
static int ctrl_set_flicker_avoidance(struct bm2835_mmal_dev *dev,
@@ -416,7 +406,7 @@ static int ctrl_set_flicker_avoidance(struct bm2835_mmal_dev *dev,
u32 u32_value;
struct vchiq_mmal_port *control;
- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+ control = &dev->component[COMP_CAMERA]->control;
switch (ctrl->val) {
case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED:
@@ -445,7 +435,7 @@ static int ctrl_set_awb_mode(struct bm2835_mmal_dev *dev,
u32 u32_value;
struct vchiq_mmal_port *control;
- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+ control = &dev->component[COMP_CAMERA]->control;
switch (ctrl->val) {
case V4L2_WHITE_BALANCE_MANUAL:
@@ -501,7 +491,7 @@ static int ctrl_set_awb_gains(struct bm2835_mmal_dev *dev,
struct vchiq_mmal_port *control;
struct mmal_parameter_awbgains gains;
- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+ control = &dev->component[COMP_CAMERA]->control;
if (ctrl->id == V4L2_CID_RED_BALANCE)
dev->red_gain = ctrl->val;
@@ -549,7 +539,7 @@ static int ctrl_set_image_effect(struct bm2835_mmal_dev *dev,
v4l2_to_mmal_effects_values[i].v;
}
- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+ control = &dev->component[COMP_CAMERA]->control;
ret = vchiq_mmal_port_parameter_set(
dev->instance, control,
@@ -579,13 +569,13 @@ static int ctrl_set_colfx(struct bm2835_mmal_dev *dev,
struct v4l2_ctrl *ctrl,
const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
{
- int ret = -EINVAL;
+ int ret;
struct vchiq_mmal_port *control;
- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+ control = &dev->component[COMP_CAMERA]->control;
- dev->colourfx.enable = (ctrl->val & 0xff00) >> 8;
- dev->colourfx.enable = ctrl->val & 0xff;
+ dev->colourfx.u = (ctrl->val & 0xff00) >> 8;
+ dev->colourfx.v = ctrl->val & 0xff;
ret = vchiq_mmal_port_parameter_set(dev->instance, control,
MMAL_PARAMETER_COLOUR_EFFECT,
@@ -603,15 +593,28 @@ static int ctrl_set_bitrate(struct bm2835_mmal_dev *dev,
struct v4l2_ctrl *ctrl,
const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
{
+ int ret;
struct vchiq_mmal_port *encoder_out;
dev->capture.encode_bitrate = ctrl->val;
- encoder_out = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
+ encoder_out = &dev->component[COMP_VIDEO_ENCODE]->output[0];
- return vchiq_mmal_port_parameter_set(dev->instance, encoder_out,
- mmal_ctrl->mmal_id, &ctrl->val,
- sizeof(ctrl->val));
+ ret = vchiq_mmal_port_parameter_set(dev->instance, encoder_out,
+ mmal_ctrl->mmal_id, &ctrl->val,
+ sizeof(ctrl->val));
+
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "%s: After: mmal_ctrl:%p ctrl id:0x%x ctrl val:%d ret %d(%d)\n",
+ __func__, mmal_ctrl, ctrl->id, ctrl->val, ret,
+ (ret == 0 ? 0 : -EINVAL));
+
+ /*
+ * Older firmware versions (pre July 2019) have a bug in handling
+ * MMAL_PARAMETER_VIDEO_BIT_RATE that result in the call
+ * returning -MMAL_MSG_STATUS_EINVAL. So ignore errors from this call.
+ */
+ return 0;
}
static int ctrl_set_bitrate_mode(struct bm2835_mmal_dev *dev,
@@ -621,7 +624,7 @@ static int ctrl_set_bitrate_mode(struct bm2835_mmal_dev *dev,
u32 bitrate_mode;
struct vchiq_mmal_port *encoder_out;
- encoder_out = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
+ encoder_out = &dev->component[COMP_VIDEO_ENCODE]->output[0];
dev->capture.encode_bitrate_mode = ctrl->val;
switch (ctrl->val) {
@@ -648,7 +651,7 @@ static int ctrl_set_image_encode_output(struct bm2835_mmal_dev *dev,
u32 u32_value;
struct vchiq_mmal_port *jpeg_out;
- jpeg_out = &dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->output[0];
+ jpeg_out = &dev->component[COMP_IMAGE_ENCODE]->output[0];
u32_value = ctrl->val;
@@ -664,7 +667,7 @@ static int ctrl_set_video_encode_param_output(struct bm2835_mmal_dev *dev,
u32 u32_value;
struct vchiq_mmal_port *vid_enc_ctl;
- vid_enc_ctl = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
+ vid_enc_ctl = &dev->component[COMP_VIDEO_ENCODE]->output[0];
u32_value = ctrl->val;
@@ -777,7 +780,7 @@ static int ctrl_set_video_encode_profile_level(struct bm2835_mmal_dev *dev,
}
ret = vchiq_mmal_port_parameter_set(dev->instance,
- &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0],
+ &dev->component[COMP_VIDEO_ENCODE]->output[0],
mmal_ctrl->mmal_id,
&param, sizeof(param));
}
@@ -795,7 +798,7 @@ static int ctrl_set_scene_mode(struct bm2835_mmal_dev *dev,
v4l2_dbg(0, bcm2835_v4l2_debug, &dev->v4l2_dev,
"scene mode selected %d, was %d\n", ctrl->val,
dev->scene_mode);
- control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+ control = &dev->component[COMP_CAMERA]->control;
if (ctrl->val == dev->scene_mode)
return 0;
@@ -956,8 +959,8 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = {
},
{
V4L2_CID_ISO_SENSITIVITY_AUTO, MMAL_CONTROL_TYPE_STD_MENU,
- 0, 1, V4L2_ISO_SENSITIVITY_AUTO, 1, NULL,
- MMAL_PARAMETER_ISO,
+ 0, V4L2_ISO_SENSITIVITY_AUTO, V4L2_ISO_SENSITIVITY_AUTO, 1,
+ NULL, MMAL_PARAMETER_ISO,
ctrl_set_iso,
false
},
@@ -968,22 +971,13 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = {
ctrl_set_value,
false
},
-/* {
- * 0, MMAL_CONTROL_TYPE_CLUSTER, 3, 1, 0, NULL, 0, NULL
- * },
- */
{
V4L2_CID_EXPOSURE_AUTO, MMAL_CONTROL_TYPE_STD_MENU,
- ~0x03, 3, V4L2_EXPOSURE_AUTO, 0, NULL,
- MMAL_PARAMETER_EXPOSURE_MODE,
+ ~0x03, V4L2_EXPOSURE_APERTURE_PRIORITY, V4L2_EXPOSURE_AUTO, 0,
+ NULL, MMAL_PARAMETER_EXPOSURE_MODE,
ctrl_set_exposure,
false
},
-/* todo this needs mixing in with set exposure
- * {
- * V4L2_CID_SCENE_MODE, MMAL_CONTROL_TYPE_STD_MENU,
- * },
- */
{
V4L2_CID_EXPOSURE_ABSOLUTE, MMAL_CONTROL_TYPE_STD,
/* Units of 100usecs */
@@ -1011,7 +1005,8 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = {
{
V4L2_CID_EXPOSURE_METERING,
MMAL_CONTROL_TYPE_STD_MENU,
- ~0x7, 2, V4L2_EXPOSURE_METERING_AVERAGE, 0, NULL,
+ ~0x7, V4L2_EXPOSURE_METERING_SPOT,
+ V4L2_EXPOSURE_METERING_AVERAGE, 0, NULL,
MMAL_PARAMETER_EXP_METERING_MODE,
ctrl_set_metering_mode,
false
@@ -1019,7 +1014,8 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = {
{
V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
MMAL_CONTROL_TYPE_STD_MENU,
- ~0x3ff, 9, V4L2_WHITE_BALANCE_AUTO, 0, NULL,
+ ~0x3ff, V4L2_WHITE_BALANCE_SHADE, V4L2_WHITE_BALANCE_AUTO, 0,
+ NULL,
MMAL_PARAMETER_AWB_MODE,
ctrl_set_awb_mode,
false
@@ -1040,7 +1036,7 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = {
},
{
V4L2_CID_COLORFX, MMAL_CONTROL_TYPE_STD_MENU,
- 0, 15, V4L2_COLORFX_NONE, 0, NULL,
+ 0, V4L2_COLORFX_SET_CBCR, V4L2_COLORFX_NONE, 0, NULL,
MMAL_PARAMETER_IMAGE_EFFECT,
ctrl_set_image_effect,
false
@@ -1075,8 +1071,8 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = {
},
{
V4L2_CID_MPEG_VIDEO_BITRATE_MODE, MMAL_CONTROL_TYPE_STD_MENU,
- 0, ARRAY_SIZE(bitrate_mode_qmenu) - 1,
- 0, 0, bitrate_mode_qmenu,
+ 0, V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
+ 0, 0, NULL,
MMAL_PARAMETER_RATECONTROL,
ctrl_set_bitrate_mode,
false
@@ -1098,8 +1094,8 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = {
},
{
V4L2_CID_POWER_LINE_FREQUENCY, MMAL_CONTROL_TYPE_STD_MENU,
- 0, ARRAY_SIZE(mains_freq_qmenu) - 1,
- 1, 1, mains_freq_qmenu,
+ 0, V4L2_CID_POWER_LINE_FREQUENCY_AUTO,
+ 1, 1, NULL,
MMAL_PARAMETER_FLICKER_AVOID,
ctrl_set_flicker_avoidance,
false
@@ -1110,15 +1106,15 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = {
0, 1, NULL,
MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER,
ctrl_set_video_encode_param_output,
- true /* Errors ignored as requires latest firmware to work */
+ false
},
{
V4L2_CID_MPEG_VIDEO_H264_PROFILE,
MMAL_CONTROL_TYPE_STD_MENU,
- ~((1<<V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
- (1<<V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) |
- (1<<V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
- (1<<V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)),
+ ~(BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) |
+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)),
V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, 1, NULL,
MMAL_PARAMETER_PROFILE,
@@ -1127,18 +1123,18 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = {
},
{
V4L2_CID_MPEG_VIDEO_H264_LEVEL, MMAL_CONTROL_TYPE_STD_MENU,
- ~((1<<V4L2_MPEG_VIDEO_H264_LEVEL_1_0) |
- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_1B) |
- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_1_1) |
- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_1_2) |
- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_1_3) |
- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_2_1) |
- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_2_2) |
- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
- (1<<V4L2_MPEG_VIDEO_H264_LEVEL_4_0)),
+ ~(BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0)),
V4L2_MPEG_VIDEO_H264_LEVEL_4_0,
V4L2_MPEG_VIDEO_H264_LEVEL_4_0, 1, NULL,
MMAL_PARAMETER_PROFILE,
@@ -1147,7 +1143,7 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = {
},
{
V4L2_CID_SCENE_MODE, MMAL_CONTROL_TYPE_STD_MENU,
- -1, /* Min is computed at runtime */
+ -1, /* Min (mask) is computed at runtime */
V4L2_SCENE_MODE_TEXT,
V4L2_SCENE_MODE_NONE, 1, NULL,
MMAL_PARAMETER_PROFILE,
@@ -1213,18 +1209,15 @@ int set_framerate_params(struct bm2835_mmal_dev *dev)
fps_range.fps_high.den);
ret = vchiq_mmal_port_parameter_set(dev->instance,
- &dev->component[MMAL_COMPONENT_CAMERA]->
- output[MMAL_CAMERA_PORT_PREVIEW],
+ &dev->component[COMP_CAMERA]->output[CAM_PORT_PREVIEW],
MMAL_PARAMETER_FPS_RANGE,
&fps_range, sizeof(fps_range));
ret += vchiq_mmal_port_parameter_set(dev->instance,
- &dev->component[MMAL_COMPONENT_CAMERA]->
- output[MMAL_CAMERA_PORT_VIDEO],
+ &dev->component[COMP_CAMERA]->output[CAM_PORT_VIDEO],
MMAL_PARAMETER_FPS_RANGE,
&fps_range, sizeof(fps_range));
ret += vchiq_mmal_port_parameter_set(dev->instance,
- &dev->component[MMAL_COMPONENT_CAMERA]->
- output[MMAL_CAMERA_PORT_CAPTURE],
+ &dev->component[COMP_CAMERA]->output[CAM_PORT_CAPTURE],
MMAL_PARAMETER_FPS_RANGE,
&fps_range, sizeof(fps_range));
if (ret)
@@ -1247,14 +1240,17 @@ int bm2835_mmal_init_controls(struct bm2835_mmal_dev *dev,
switch (ctrl->type) {
case MMAL_CONTROL_TYPE_STD:
- dev->ctrls[c] = v4l2_ctrl_new_std(hdl,
- &bm2835_mmal_ctrl_ops, ctrl->id,
- ctrl->min, ctrl->max, ctrl->step, ctrl->def);
+ dev->ctrls[c] =
+ v4l2_ctrl_new_std(hdl,
+ &bm2835_mmal_ctrl_ops,
+ ctrl->id, ctrl->min,
+ ctrl->max, ctrl->step,
+ ctrl->def);
break;
case MMAL_CONTROL_TYPE_STD_MENU:
{
- int mask = ctrl->min;
+ u64 mask = ctrl->min;
if (ctrl->id == V4L2_CID_SCENE_MODE) {
/* Special handling to work out the mask
@@ -1264,25 +1260,29 @@ int bm2835_mmal_init_controls(struct bm2835_mmal_dev *dev,
*/
int i;
- mask = 1 << V4L2_SCENE_MODE_NONE;
+ mask = BIT(V4L2_SCENE_MODE_NONE);
for (i = 0;
i < ARRAY_SIZE(scene_configs);
i++) {
- mask |= 1 << scene_configs[i].v4l2_scene;
+ mask |= BIT(scene_configs[i].v4l2_scene);
}
mask = ~mask;
}
- dev->ctrls[c] = v4l2_ctrl_new_std_menu(hdl,
- &bm2835_mmal_ctrl_ops, ctrl->id,
- ctrl->max, mask, ctrl->def);
+ dev->ctrls[c] =
+ v4l2_ctrl_new_std_menu(hdl,
+ &bm2835_mmal_ctrl_ops,
+ ctrl->id, ctrl->max,
+ mask, ctrl->def);
break;
}
case MMAL_CONTROL_TYPE_INT_MENU:
- dev->ctrls[c] = v4l2_ctrl_new_int_menu(hdl,
- &bm2835_mmal_ctrl_ops, ctrl->id,
- ctrl->max, ctrl->def, ctrl->imenu);
+ dev->ctrls[c] =
+ v4l2_ctrl_new_int_menu(hdl,
+ &bm2835_mmal_ctrl_ops,
+ ctrl->id, ctrl->max,
+ ctrl->def, ctrl->imenu);
break;
case MMAL_CONTROL_TYPE_CLUSTER:
diff --git a/drivers/staging/vc04_services/bcm2835-camera/mmal-common.h b/drivers/staging/vc04_services/bcm2835-camera/mmal-common.h
index a20bf274a4fd..6f56c517d850 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-common.h
+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-common.h
@@ -4,14 +4,17 @@
*
* Copyright © 2013 Raspberry Pi (Trading) Ltd.
*
- * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
- * Dave Stevenson <dsteve@broadcom.com>
- * Simon Mellor <simellor@broadcom.com>
- * Luke Diamand <luked@broadcom.com>
+ * Authors: Vincent Sanders @ Collabora
+ * Dave Stevenson @ Broadcom
+ * (now dave.stevenson@raspberrypi.org)
+ * Simon Mellor @ Broadcom
+ * Luke Diamand @ Broadcom
*
* MMAL structures
*
*/
+#ifndef MMAL_COMMON_H
+#define MMAL_COMMON_H
#define MMAL_FOURCC(a, b, c, d) ((a) | (b << 8) | (c << 16) | (d << 24))
#define MMAL_MAGIC MMAL_FOURCC('m', 'm', 'a', 'l')
@@ -55,3 +58,4 @@ struct mmal_colourfx {
u32 u;
u32 v;
};
+#endif
diff --git a/drivers/staging/vc04_services/bcm2835-camera/mmal-encodings.h b/drivers/staging/vc04_services/bcm2835-camera/mmal-encodings.h
index 129203597f91..2be9941a1f30 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-encodings.h
+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-encodings.h
@@ -4,10 +4,11 @@
*
* Copyright © 2013 Raspberry Pi (Trading) Ltd.
*
- * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
- * Dave Stevenson <dsteve@broadcom.com>
- * Simon Mellor <simellor@broadcom.com>
- * Luke Diamand <luked@broadcom.com>
+ * Authors: Vincent Sanders @ Collabora
+ * Dave Stevenson @ Broadcom
+ * (now dave.stevenson@raspberrypi.org)
+ * Simon Mellor @ Broadcom
+ * Luke Diamand @ Broadcom
*/
#ifndef MMAL_ENCODINGS_H
#define MMAL_ENCODINGS_H
diff --git a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-common.h b/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-common.h
index ec8455639d49..342c9b670f7e 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-common.h
+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-common.h
@@ -4,10 +4,11 @@
*
* Copyright © 2013 Raspberry Pi (Trading) Ltd.
*
- * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
- * Dave Stevenson <dsteve@broadcom.com>
- * Simon Mellor <simellor@broadcom.com>
- * Luke Diamand <luked@broadcom.com>
+ * Authors: Vincent Sanders @ Collabora
+ * Dave Stevenson @ Broadcom
+ * (now dave.stevenson@raspberrypi.org)
+ * Simon Mellor @ Broadcom
+ * Luke Diamand @ Broadcom
*/
#ifndef MMAL_MSG_COMMON_H
diff --git a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-format.h b/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-format.h
index c9d6fbe25fe4..a118efd21d98 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-format.h
+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-format.h
@@ -4,10 +4,11 @@
*
* Copyright © 2013 Raspberry Pi (Trading) Ltd.
*
- * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
- * Dave Stevenson <dsteve@broadcom.com>
- * Simon Mellor <simellor@broadcom.com>
- * Luke Diamand <luked@broadcom.com>
+ * Authors: Vincent Sanders @ Collabora
+ * Dave Stevenson @ Broadcom
+ * (now dave.stevenson@raspberrypi.org)
+ * Simon Mellor @ Broadcom
+ * Luke Diamand @ Broadcom
*/
#ifndef MMAL_MSG_FORMAT_H
@@ -18,22 +19,23 @@
/* MMAL_ES_FORMAT_T */
struct mmal_audio_format {
- u32 channels; /**< Number of audio channels */
- u32 sample_rate; /**< Sample rate */
+ u32 channels; /* Number of audio channels */
+ u32 sample_rate; /* Sample rate */
- u32 bits_per_sample; /**< Bits per sample */
- u32 block_align; /**< Size of a block of data */
+ u32 bits_per_sample; /* Bits per sample */
+ u32 block_align; /* Size of a block of data */
};
struct mmal_video_format {
- u32 width; /**< Width of frame in pixels */
- u32 height; /**< Height of frame in rows of pixels */
- struct mmal_rect crop; /**< Visible region of the frame */
- struct mmal_rational frame_rate; /**< Frame rate */
- struct mmal_rational par; /**< Pixel aspect ratio */
-
- /* FourCC specifying the color space of the video stream. See the
- * \ref MmalColorSpace "pre-defined color spaces" for some examples.
+ u32 width; /* Width of frame in pixels */
+ u32 height; /* Height of frame in rows of pixels */
+ struct mmal_rect crop; /* Visible region of the frame */
+ struct mmal_rational frame_rate; /* Frame rate */
+ struct mmal_rational par; /* Pixel aspect ratio */
+
+ /*
+ * FourCC specifying the color space of the video stream. See the
+ * MmalColorSpace "pre-defined color spaces" for some examples.
*/
u32 color_space;
};
@@ -49,48 +51,56 @@ union mmal_es_specific_format {
struct mmal_subpicture_format subpicture;
};
-/** Definition of an elementary stream format (MMAL_ES_FORMAT_T) */
+/* Definition of an elementary stream format (MMAL_ES_FORMAT_T) */
struct mmal_es_format_local {
- u32 type; /* enum mmal_es_type */
-
- u32 encoding; /* FourCC specifying encoding of the elementary stream.*/
- u32 encoding_variant; /* FourCC specifying the specific
- * encoding variant of the elementary
- * stream.
- */
-
- union mmal_es_specific_format *es; /* Type specific
- * information for the
- * elementary stream
- */
-
- u32 bitrate; /**< Bitrate in bits per second */
- u32 flags; /**< Flags describing properties of the elementary stream. */
-
- u32 extradata_size; /**< Size of the codec specific data */
- u8 *extradata; /**< Codec specific data */
+ u32 type; /* enum mmal_es_type */
+
+ u32 encoding; /* FourCC specifying encoding of the elementary
+ * stream.
+ */
+ u32 encoding_variant; /* FourCC specifying the specific
+ * encoding variant of the elementary
+ * stream.
+ */
+
+ union mmal_es_specific_format *es; /* Type specific
+ * information for the
+ * elementary stream
+ */
+
+ u32 bitrate; /* Bitrate in bits per second */
+ u32 flags; /* Flags describing properties of the elementary
+ * stream.
+ */
+
+ u32 extradata_size; /* Size of the codec specific data */
+ u8 *extradata; /* Codec specific data */
};
-/** Remote definition of an elementary stream format (MMAL_ES_FORMAT_T) */
+/* Remote definition of an elementary stream format (MMAL_ES_FORMAT_T) */
struct mmal_es_format {
- u32 type; /* enum mmal_es_type */
+ u32 type; /* enum mmal_es_type */
- u32 encoding; /* FourCC specifying encoding of the elementary stream.*/
- u32 encoding_variant; /* FourCC specifying the specific
- * encoding variant of the elementary
- * stream.
- */
+ u32 encoding; /* FourCC specifying encoding of the elementary
+ * stream.
+ */
+ u32 encoding_variant; /* FourCC specifying the specific
+ * encoding variant of the elementary
+ * stream.
+ */
- u32 es; /* Type specific
+ u32 es; /* Type specific
* information for the
* elementary stream
*/
- u32 bitrate; /**< Bitrate in bits per second */
- u32 flags; /**< Flags describing properties of the elementary stream. */
+ u32 bitrate; /* Bitrate in bits per second */
+ u32 flags; /* Flags describing properties of the elementary
+ * stream.
+ */
- u32 extradata_size; /**< Size of the codec specific data */
- u32 extradata; /**< Codec specific data */
+ u32 extradata_size; /* Size of the codec specific data */
+ u32 extradata; /* Codec specific data */
};
#endif /* MMAL_MSG_FORMAT_H */
diff --git a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-port.h b/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-port.h
index 3b3ed79cadd9..3fa3f2a578f0 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-port.h
+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-port.h
@@ -4,36 +4,40 @@
*
* Copyright © 2013 Raspberry Pi (Trading) Ltd.
*
- * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
- * Dave Stevenson <dsteve@broadcom.com>
- * Simon Mellor <simellor@broadcom.com>
- * Luke Diamand <luked@broadcom.com>
+ * Authors: Vincent Sanders @ Collabora
+ * Dave Stevenson @ Broadcom
+ * (now dave.stevenson@raspberrypi.org)
+ * Simon Mellor @ Broadcom
+ * Luke Diamand @ Broadcom
*/
/* MMAL_PORT_TYPE_T */
enum mmal_port_type {
- MMAL_PORT_TYPE_UNKNOWN = 0, /**< Unknown port type */
- MMAL_PORT_TYPE_CONTROL, /**< Control port */
- MMAL_PORT_TYPE_INPUT, /**< Input port */
- MMAL_PORT_TYPE_OUTPUT, /**< Output port */
- MMAL_PORT_TYPE_CLOCK, /**< Clock port */
+ MMAL_PORT_TYPE_UNKNOWN = 0, /* Unknown port type */
+ MMAL_PORT_TYPE_CONTROL, /* Control port */
+ MMAL_PORT_TYPE_INPUT, /* Input port */
+ MMAL_PORT_TYPE_OUTPUT, /* Output port */
+ MMAL_PORT_TYPE_CLOCK, /* Clock port */
};
-/** The port is pass-through and doesn't need buffer headers allocated */
+/* The port is pass-through and doesn't need buffer headers allocated */
#define MMAL_PORT_CAPABILITY_PASSTHROUGH 0x01
-/** The port wants to allocate the buffer payloads.
+/*
+ *The port wants to allocate the buffer payloads.
* This signals a preference that payload allocation should be done
* on this port for efficiency reasons.
*/
#define MMAL_PORT_CAPABILITY_ALLOCATION 0x02
-/** The port supports format change events.
+/*
+ * The port supports format change events.
* This applies to input ports and is used to let the client know
* whether the port supports being reconfigured via a format
* change event (i.e. without having to disable the port).
*/
#define MMAL_PORT_CAPABILITY_SUPPORTS_EVENT_FORMAT_CHANGE 0x04
-/* mmal port structure (MMAL_PORT_T)
+/*
+ * mmal port structure (MMAL_PORT_T)
*
* most elements are informational only, the pointer values for
* interogation messages are generally provided as additional
@@ -41,50 +45,50 @@ enum mmal_port_type {
* buffer_num, buffer_size and userdata parameters are writable.
*/
struct mmal_port {
- u32 priv; /* Private member used by the framework */
- u32 name; /* Port name. Used for debugging purposes (RO) */
-
- u32 type; /* Type of the port (RO) enum mmal_port_type */
- u16 index; /* Index of the port in its type list (RO) */
- u16 index_all; /* Index of the port in the list of all ports (RO) */
-
- u32 is_enabled; /* Indicates whether the port is enabled or not (RO) */
- u32 format; /* Format of the elementary stream */
-
- u32 buffer_num_min; /* Minimum number of buffers the port
- * requires (RO). This is set by the
- * component.
- */
-
- u32 buffer_size_min; /* Minimum size of buffers the port
- * requires (RO). This is set by the
- * component.
- */
-
- u32 buffer_alignment_min; /* Minimum alignment requirement for
- * the buffers (RO). A value of
- * zero means no special alignment
- * requirements. This is set by the
- * component.
- */
-
- u32 buffer_num_recommended; /* Number of buffers the port
- * recommends for optimal
- * performance (RO). A value of
- * zero means no special
- * recommendation. This is set
- * by the component.
- */
-
- u32 buffer_size_recommended; /* Size of buffers the port
- * recommends for optimal
- * performance (RO). A value of
- * zero means no special
- * recommendation. This is set
- * by the component.
- */
-
- u32 buffer_num; /* Actual number of buffers the port will use.
+ u32 priv; /* Private member used by the framework */
+ u32 name; /* Port name. Used for debugging purposes (RO) */
+
+ u32 type; /* Type of the port (RO) enum mmal_port_type */
+ u16 index; /* Index of the port in its type list (RO) */
+ u16 index_all; /* Index of the port in the list of all ports (RO) */
+
+ u32 is_enabled; /* Indicates whether the port is enabled or not (RO) */
+ u32 format; /* Format of the elementary stream */
+
+ u32 buffer_num_min; /* Minimum number of buffers the port
+ * requires (RO). This is set by the
+ * component.
+ */
+
+ u32 buffer_size_min; /* Minimum size of buffers the port
+ * requires (RO). This is set by the
+ * component.
+ */
+
+ u32 buffer_alignment_min;/* Minimum alignment requirement for
+ * the buffers (RO). A value of
+ * zero means no special alignment
+ * requirements. This is set by the
+ * component.
+ */
+
+ u32 buffer_num_recommended; /* Number of buffers the port
+ * recommends for optimal
+ * performance (RO). A value of
+ * zero means no special
+ * recommendation. This is set
+ * by the component.
+ */
+
+ u32 buffer_size_recommended; /* Size of buffers the port
+ * recommends for optimal
+ * performance (RO). A value of
+ * zero means no special
+ * recommendation. This is set
+ * by the component.
+ */
+
+ u32 buffer_num; /* Actual number of buffers the port will use.
* This is set by the client.
*/
@@ -93,14 +97,13 @@ struct mmal_port {
* the client.
*/
- u32 component; /* Component this port belongs to (Read Only) */
-
- u32 userdata; /* Field reserved for use by the client */
+ u32 component; /* Component this port belongs to (Read Only) */
- u32 capabilities; /* Flags describing the capabilities of a
- * port (RO). Bitwise combination of \ref
- * portcapabilities "Port capabilities"
- * values.
- */
+ u32 userdata; /* Field reserved for use by the client */
+ u32 capabilities; /* Flags describing the capabilities of a
+ * port (RO). Bitwise combination of \ref
+ * portcapabilities "Port capabilities"
+ * values.
+ */
};
diff --git a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg.h b/drivers/staging/vc04_services/bcm2835-camera/mmal-msg.h
index d1c57edbe2b8..43cc59316f90 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg.h
+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-msg.h
@@ -4,13 +4,15 @@
*
* Copyright © 2013 Raspberry Pi (Trading) Ltd.
*
- * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
- * Dave Stevenson <dsteve@broadcom.com>
- * Simon Mellor <simellor@broadcom.com>
- * Luke Diamand <luked@broadcom.com>
+ * Authors: Vincent Sanders @ Collabora
+ * Dave Stevenson @ Broadcom
+ * (now dave.stevenson@raspberrypi.org)
+ * Simon Mellor @ Broadcom
+ * Luke Diamand @ Broadcom
*/
-/* all the data structures which serialise the MMAL protocol. note
+/*
+ * all the data structures which serialise the MMAL protocol. note
* these are directly mapped onto the recived message data.
*
* BEWARE: They seem to *assume* pointers are u32 and that there is no
@@ -21,6 +23,8 @@
* implementation uses fixed size types and not the enums (though the
* comments have the actual enum type
*/
+#ifndef MMAL_MSG_H
+#define MMAL_MSG_H
#define VC_MMAL_VER 15
#define VC_MMAL_MIN_VER 10
@@ -40,51 +44,51 @@ enum mmal_msg_type {
MMAL_MSG_TYPE_SERVICE_CLOSED,
MMAL_MSG_TYPE_GET_VERSION,
MMAL_MSG_TYPE_COMPONENT_CREATE,
- MMAL_MSG_TYPE_COMPONENT_DESTROY, /* 5 */
+ MMAL_MSG_TYPE_COMPONENT_DESTROY, /* 5 */
MMAL_MSG_TYPE_COMPONENT_ENABLE,
MMAL_MSG_TYPE_COMPONENT_DISABLE,
MMAL_MSG_TYPE_PORT_INFO_GET,
MMAL_MSG_TYPE_PORT_INFO_SET,
- MMAL_MSG_TYPE_PORT_ACTION, /* 10 */
+ MMAL_MSG_TYPE_PORT_ACTION, /* 10 */
MMAL_MSG_TYPE_BUFFER_FROM_HOST,
MMAL_MSG_TYPE_BUFFER_TO_HOST,
MMAL_MSG_TYPE_GET_STATS,
MMAL_MSG_TYPE_PORT_PARAMETER_SET,
- MMAL_MSG_TYPE_PORT_PARAMETER_GET, /* 15 */
+ MMAL_MSG_TYPE_PORT_PARAMETER_GET, /* 15 */
MMAL_MSG_TYPE_EVENT_TO_HOST,
MMAL_MSG_TYPE_GET_CORE_STATS_FOR_PORT,
MMAL_MSG_TYPE_OPAQUE_ALLOCATOR,
MMAL_MSG_TYPE_CONSUME_MEM,
- MMAL_MSG_TYPE_LMK, /* 20 */
+ MMAL_MSG_TYPE_LMK, /* 20 */
MMAL_MSG_TYPE_OPAQUE_ALLOCATOR_DESC,
MMAL_MSG_TYPE_DRM_GET_LHS32,
MMAL_MSG_TYPE_DRM_GET_TIME,
MMAL_MSG_TYPE_BUFFER_FROM_HOST_ZEROLEN,
- MMAL_MSG_TYPE_PORT_FLUSH, /* 25 */
+ MMAL_MSG_TYPE_PORT_FLUSH, /* 25 */
MMAL_MSG_TYPE_HOST_LOG,
MMAL_MSG_TYPE_MSG_LAST
};
/* port action request messages differ depending on the action type */
enum mmal_msg_port_action_type {
- MMAL_MSG_PORT_ACTION_TYPE_UNKNOWN = 0, /* Unknown action */
- MMAL_MSG_PORT_ACTION_TYPE_ENABLE, /* Enable a port */
- MMAL_MSG_PORT_ACTION_TYPE_DISABLE, /* Disable a port */
- MMAL_MSG_PORT_ACTION_TYPE_FLUSH, /* Flush a port */
- MMAL_MSG_PORT_ACTION_TYPE_CONNECT, /* Connect ports */
- MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT, /* Disconnect ports */
+ MMAL_MSG_PORT_ACTION_TYPE_UNKNOWN = 0, /* Unknown action */
+ MMAL_MSG_PORT_ACTION_TYPE_ENABLE, /* Enable a port */
+ MMAL_MSG_PORT_ACTION_TYPE_DISABLE, /* Disable a port */
+ MMAL_MSG_PORT_ACTION_TYPE_FLUSH, /* Flush a port */
+ MMAL_MSG_PORT_ACTION_TYPE_CONNECT, /* Connect ports */
+ MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT, /* Disconnect ports */
MMAL_MSG_PORT_ACTION_TYPE_SET_REQUIREMENTS, /* Set buffer requirements*/
};
struct mmal_msg_header {
u32 magic;
- u32 type; /** enum mmal_msg_type */
+ u32 type; /* enum mmal_msg_type */
/* Opaque handle to the control service */
u32 control_service;
- u32 context; /** a u32 per message context */
- u32 status; /** The status of the vchiq operation */
+ u32 context; /* a u32 per message context */
+ u32 status; /* The status of the vchiq operation */
u32 padding;
};
@@ -98,9 +102,9 @@ struct mmal_msg_version {
/* request to VC to create component */
struct mmal_msg_component_create {
- u32 client_component; /* component context */
+ u32 client_component; /* component context */
char name[128];
- u32 pid; /* For debug */
+ u32 pid; /* For debug */
};
/* reply from VC to component creation request */
@@ -120,7 +124,7 @@ struct mmal_msg_component_destroy {
};
struct mmal_msg_component_destroy_reply {
- u32 status; /** The component destruction status */
+ u32 status; /* The component destruction status */
};
/* request and reply to VC to enable a component */
@@ -129,7 +133,7 @@ struct mmal_msg_component_enable {
};
struct mmal_msg_component_enable_reply {
- u32 status; /** The component enable status */
+ u32 status; /* The component enable status */
};
/* request and reply to VC to disable a component */
@@ -138,7 +142,7 @@ struct mmal_msg_component_disable {
};
struct mmal_msg_component_disable_reply {
- u32 status; /** The component disable status */
+ u32 status; /* The component disable status */
};
/* request to VC to get port information */
@@ -150,12 +154,12 @@ struct mmal_msg_port_info_get {
/* reply from VC to get port info request */
struct mmal_msg_port_info_get_reply {
- u32 status; /** enum mmal_msg_status */
- u32 component_handle; /* component handle port is associated with */
- u32 port_type; /* enum mmal_msg_port_type */
- u32 port_index; /* port indexed in query */
- s32 found; /* unused */
- u32 port_handle; /**< Handle to use for this port */
+ u32 status; /* enum mmal_msg_status */
+ u32 component_handle; /* component handle port is associated with */
+ u32 port_type; /* enum mmal_msg_port_type */
+ u32 port_index; /* port indexed in query */
+ s32 found; /* unused */
+ u32 port_handle; /* Handle to use for this port */
struct mmal_port port;
struct mmal_es_format format; /* elementary stream format */
union mmal_es_specific_format es; /* es type specific data */
@@ -165,8 +169,8 @@ struct mmal_msg_port_info_get_reply {
/* request to VC to set port information */
struct mmal_msg_port_info_set {
u32 component_handle;
- u32 port_type; /* enum mmal_msg_port_type */
- u32 port_index; /* port indexed in query */
+ u32 port_type; /* enum mmal_msg_port_type */
+ u32 port_index; /* port indexed in query */
struct mmal_port port;
struct mmal_es_format format;
union mmal_es_specific_format es;
@@ -176,11 +180,11 @@ struct mmal_msg_port_info_set {
/* reply from VC to port info set request */
struct mmal_msg_port_info_set_reply {
u32 status;
- u32 component_handle; /* component handle port is associated with */
- u32 port_type; /* enum mmal_msg_port_type */
- u32 index; /* port indexed in query */
- s32 found; /* unused */
- u32 port_handle; /**< Handle to use for this port */
+ u32 component_handle; /* component handle port is associated with */
+ u32 port_type; /* enum mmal_msg_port_type */
+ u32 index; /* port indexed in query */
+ s32 found; /* unused */
+ u32 port_handle; /* Handle to use for this port */
struct mmal_port port;
struct mmal_es_format format;
union mmal_es_specific_format es;
@@ -191,7 +195,7 @@ struct mmal_msg_port_info_set_reply {
struct mmal_msg_port_action_port {
u32 component_handle;
u32 port_handle;
- u32 action; /* enum mmal_msg_port_action_type */
+ u32 action; /* enum mmal_msg_port_action_type */
struct mmal_port port;
};
@@ -199,50 +203,54 @@ struct mmal_msg_port_action_port {
struct mmal_msg_port_action_handle {
u32 component_handle;
u32 port_handle;
- u32 action; /* enum mmal_msg_port_action_type */
+ u32 action; /* enum mmal_msg_port_action_type */
u32 connect_component_handle;
u32 connect_port_handle;
};
struct mmal_msg_port_action_reply {
- u32 status; /** The port action operation status */
+ u32 status; /* The port action operation status */
};
/* MMAL buffer transfer */
-/** Size of space reserved in a buffer message for short messages. */
+/* Size of space reserved in a buffer message for short messages. */
#define MMAL_VC_SHORT_DATA 128
-/** Signals that the current payload is the end of the stream of data */
+/* Signals that the current payload is the end of the stream of data */
#define MMAL_BUFFER_HEADER_FLAG_EOS BIT(0)
-/** Signals that the start of the current payload starts a frame */
+/* Signals that the start of the current payload starts a frame */
#define MMAL_BUFFER_HEADER_FLAG_FRAME_START BIT(1)
-/** Signals that the end of the current payload ends a frame */
+/* Signals that the end of the current payload ends a frame */
#define MMAL_BUFFER_HEADER_FLAG_FRAME_END BIT(2)
-/** Signals that the current payload contains only complete frames (>1) */
+/* Signals that the current payload contains only complete frames (>1) */
#define MMAL_BUFFER_HEADER_FLAG_FRAME \
- (MMAL_BUFFER_HEADER_FLAG_FRAME_START|MMAL_BUFFER_HEADER_FLAG_FRAME_END)
-/** Signals that the current payload is a keyframe (i.e. self decodable) */
+ (MMAL_BUFFER_HEADER_FLAG_FRAME_START | \
+ MMAL_BUFFER_HEADER_FLAG_FRAME_END)
+/* Signals that the current payload is a keyframe (i.e. self decodable) */
#define MMAL_BUFFER_HEADER_FLAG_KEYFRAME BIT(3)
-/** Signals a discontinuity in the stream of data (e.g. after a seek).
+/*
+ * Signals a discontinuity in the stream of data (e.g. after a seek).
* Can be used for instance by a decoder to reset its state
*/
#define MMAL_BUFFER_HEADER_FLAG_DISCONTINUITY BIT(4)
-/** Signals a buffer containing some kind of config data for the component
+/*
+ * Signals a buffer containing some kind of config data for the component
* (e.g. codec config data)
*/
#define MMAL_BUFFER_HEADER_FLAG_CONFIG BIT(5)
-/** Signals an encrypted payload */
+/* Signals an encrypted payload */
#define MMAL_BUFFER_HEADER_FLAG_ENCRYPTED BIT(6)
-/** Signals a buffer containing side information */
+/* Signals a buffer containing side information */
#define MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO BIT(7)
-/** Signals a buffer which is the snapshot/postview image from a stills
+/*
+ * Signals a buffer which is the snapshot/postview image from a stills
* capture
*/
#define MMAL_BUFFER_HEADER_FLAGS_SNAPSHOT BIT(8)
-/** Signals a buffer which contains data known to be corrupted */
+/* Signals a buffer which contains data known to be corrupted */
#define MMAL_BUFFER_HEADER_FLAG_CORRUPTED BIT(9)
-/** Signals that a buffer failed to be transmitted */
+/* Signals that a buffer failed to be transmitted */
#define MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED BIT(10)
struct mmal_driver_buffer {
@@ -254,8 +262,8 @@ struct mmal_driver_buffer {
/* buffer header */
struct mmal_buffer_header {
- u32 next; /* next header */
- u32 priv; /* framework private data */
+ u32 next; /* next header */
+ u32 priv; /* framework private data */
u32 cmd;
u32 data;
u32 alloc_size;
@@ -280,7 +288,8 @@ struct mmal_buffer_header_type_specific {
};
struct mmal_msg_buffer_from_host {
- /* The front 32 bytes of the buffer header are copied
+ /*
+ *The front 32 bytes of the buffer header are copied
* back to us in the reply to allow for context. This
* area is used to store two mmal_driver_buffer structures to
* allow for multiple concurrent service users.
@@ -295,7 +304,7 @@ struct mmal_msg_buffer_from_host {
s32 is_zero_copy;
s32 has_reference;
- /** allows short data to be xfered in control message */
+ /* allows short data to be xfered in control message */
u32 payload_in_message;
u8 short_data[MMAL_VC_SHORT_DATA];
};
@@ -305,11 +314,11 @@ struct mmal_msg_buffer_from_host {
#define MMAL_WORKER_PORT_PARAMETER_SPACE 96
struct mmal_msg_port_parameter_set {
- u32 component_handle; /* component */
- u32 port_handle; /* port */
- u32 id; /* Parameter ID */
- u32 size; /* Parameter size */
- uint32_t value[MMAL_WORKER_PORT_PARAMETER_SPACE];
+ u32 component_handle; /* component */
+ u32 port_handle; /* port */
+ u32 id; /* Parameter ID */
+ u32 size; /* Parameter size */
+ u32 value[MMAL_WORKER_PORT_PARAMETER_SPACE];
};
struct mmal_msg_port_parameter_set_reply {
@@ -321,24 +330,24 @@ struct mmal_msg_port_parameter_set_reply {
/* port parameter getting */
struct mmal_msg_port_parameter_get {
- u32 component_handle; /* component */
- u32 port_handle; /* port */
- u32 id; /* Parameter ID */
- u32 size; /* Parameter size */
+ u32 component_handle; /* component */
+ u32 port_handle; /* port */
+ u32 id; /* Parameter ID */
+ u32 size; /* Parameter size */
};
struct mmal_msg_port_parameter_get_reply {
- u32 status; /* Status of mmal_port_parameter_get call */
- u32 id; /* Parameter ID */
- u32 size; /* Parameter size */
- uint32_t value[MMAL_WORKER_PORT_PARAMETER_SPACE];
+ u32 status; /* Status of mmal_port_parameter_get call */
+ u32 id; /* Parameter ID */
+ u32 size; /* Parameter size */
+ u32 value[MMAL_WORKER_PORT_PARAMETER_SPACE];
};
/* event messages */
#define MMAL_WORKER_EVENT_SPACE 256
struct mmal_msg_event_to_host {
- u32 client_component; /* component context */
+ u32 client_component; /* component context */
u32 port_type;
u32 port_num;
@@ -394,3 +403,4 @@ struct mmal_msg {
u8 payload[MMAL_MSG_MAX_PAYLOAD];
} u;
};
+#endif
diff --git a/drivers/staging/vc04_services/bcm2835-camera/mmal-parameters.h b/drivers/staging/vc04_services/bcm2835-camera/mmal-parameters.h
index 184024dfb8b7..80a99128f5f3 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-parameters.h
+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-parameters.h
@@ -4,10 +4,11 @@
*
* Copyright © 2013 Raspberry Pi (Trading) Ltd.
*
- * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
- * Dave Stevenson <dsteve@broadcom.com>
- * Simon Mellor <simellor@broadcom.com>
- * Luke Diamand <luked@broadcom.com>
+ * Authors: Vincent Sanders @ Collabora
+ * Dave Stevenson @ Broadcom
+ * (now dave.stevenson@raspberrypi.org)
+ * Simon Mellor @ Broadcom
+ * Luke Diamand @ Broadcom
*/
/* common parameters */
@@ -18,152 +19,208 @@
* @{
*/
-#ifndef __MMAL_PARAMETERS_H
-#define __MMAL_PARAMETERS_H
+#ifndef MMAL_PARAMETERS_H
+#define MMAL_PARAMETERS_H
/** Common parameter ID group, used with many types of component. */
-#define MMAL_PARAMETER_GROUP_COMMON (0<<16)
+#define MMAL_PARAMETER_GROUP_COMMON (0 << 16)
/** Camera-specific parameter ID group. */
-#define MMAL_PARAMETER_GROUP_CAMERA (1<<16)
+#define MMAL_PARAMETER_GROUP_CAMERA (1 << 16)
/** Video-specific parameter ID group. */
-#define MMAL_PARAMETER_GROUP_VIDEO (2<<16)
+#define MMAL_PARAMETER_GROUP_VIDEO (2 << 16)
/** Audio-specific parameter ID group. */
-#define MMAL_PARAMETER_GROUP_AUDIO (3<<16)
+#define MMAL_PARAMETER_GROUP_AUDIO (3 << 16)
/** Clock-specific parameter ID group. */
-#define MMAL_PARAMETER_GROUP_CLOCK (4<<16)
+#define MMAL_PARAMETER_GROUP_CLOCK (4 << 16)
/** Miracast-specific parameter ID group. */
-#define MMAL_PARAMETER_GROUP_MIRACAST (5<<16)
+#define MMAL_PARAMETER_GROUP_MIRACAST (5 << 16)
/* Common parameters */
enum mmal_parameter_common_type {
- MMAL_PARAMETER_UNUSED /**< Never a valid parameter ID */
- = MMAL_PARAMETER_GROUP_COMMON,
- MMAL_PARAMETER_SUPPORTED_ENCODINGS, /**< MMAL_PARAMETER_ENCODING_T */
- MMAL_PARAMETER_URI, /**< MMAL_PARAMETER_URI_T */
-
- /** MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T */
+ /**< Never a valid parameter ID */
+ MMAL_PARAMETER_UNUSED = MMAL_PARAMETER_GROUP_COMMON,
+
+ /**< MMAL_PARAMETER_ENCODING_T */
+ MMAL_PARAMETER_SUPPORTED_ENCODINGS,
+ /**< MMAL_PARAMETER_URI_T */
+ MMAL_PARAMETER_URI,
+ /** MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T */
MMAL_PARAMETER_CHANGE_EVENT_REQUEST,
-
- /** MMAL_PARAMETER_BOOLEAN_T */
+ /** MMAL_PARAMETER_BOOLEAN_T */
MMAL_PARAMETER_ZERO_COPY,
-
- /**< MMAL_PARAMETER_BUFFER_REQUIREMENTS_T */
+ /**< MMAL_PARAMETER_BUFFER_REQUIREMENTS_T */
MMAL_PARAMETER_BUFFER_REQUIREMENTS,
-
- MMAL_PARAMETER_STATISTICS, /**< MMAL_PARAMETER_STATISTICS_T */
- MMAL_PARAMETER_CORE_STATISTICS, /**< MMAL_PARAMETER_CORE_STATISTICS_T */
- MMAL_PARAMETER_MEM_USAGE, /**< MMAL_PARAMETER_MEM_USAGE_T */
- MMAL_PARAMETER_BUFFER_FLAG_FILTER, /**< MMAL_PARAMETER_UINT32_T */
- MMAL_PARAMETER_SEEK, /**< MMAL_PARAMETER_SEEK_T */
- MMAL_PARAMETER_POWERMON_ENABLE, /**< MMAL_PARAMETER_BOOLEAN_T */
- MMAL_PARAMETER_LOGGING, /**< MMAL_PARAMETER_LOGGING_T */
- MMAL_PARAMETER_SYSTEM_TIME, /**< MMAL_PARAMETER_UINT64_T */
- MMAL_PARAMETER_NO_IMAGE_PADDING /**< MMAL_PARAMETER_BOOLEAN_T */
+ /**< MMAL_PARAMETER_STATISTICS_T */
+ MMAL_PARAMETER_STATISTICS,
+ /**< MMAL_PARAMETER_CORE_STATISTICS_T */
+ MMAL_PARAMETER_CORE_STATISTICS,
+ /**< MMAL_PARAMETER_MEM_USAGE_T */
+ MMAL_PARAMETER_MEM_USAGE,
+ /**< MMAL_PARAMETER_UINT32_T */
+ MMAL_PARAMETER_BUFFER_FLAG_FILTER,
+ /**< MMAL_PARAMETER_SEEK_T */
+ MMAL_PARAMETER_SEEK,
+ /**< MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_POWERMON_ENABLE,
+ /**< MMAL_PARAMETER_LOGGING_T */
+ MMAL_PARAMETER_LOGGING,
+ /**< MMAL_PARAMETER_UINT64_T */
+ MMAL_PARAMETER_SYSTEM_TIME,
+ /**< MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_NO_IMAGE_PADDING,
};
/* camera parameters */
enum mmal_parameter_camera_type {
/* 0 */
- /** @ref MMAL_PARAMETER_THUMBNAIL_CONFIG_T */
- MMAL_PARAMETER_THUMBNAIL_CONFIGURATION
- = MMAL_PARAMETER_GROUP_CAMERA,
- MMAL_PARAMETER_CAPTURE_QUALITY, /**< Unused? */
- MMAL_PARAMETER_ROTATION, /**< @ref MMAL_PARAMETER_INT32_T */
- MMAL_PARAMETER_EXIF_DISABLE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
- MMAL_PARAMETER_EXIF, /**< @ref MMAL_PARAMETER_EXIF_T */
- MMAL_PARAMETER_AWB_MODE, /**< @ref MMAL_PARAM_AWBMODE_T */
- MMAL_PARAMETER_IMAGE_EFFECT, /**< @ref MMAL_PARAMETER_IMAGEFX_T */
- MMAL_PARAMETER_COLOUR_EFFECT, /**< @ref MMAL_PARAMETER_COLOURFX_T */
- MMAL_PARAMETER_FLICKER_AVOID, /**< @ref MMAL_PARAMETER_FLICKERAVOID_T */
- MMAL_PARAMETER_FLASH, /**< @ref MMAL_PARAMETER_FLASH_T */
- MMAL_PARAMETER_REDEYE, /**< @ref MMAL_PARAMETER_REDEYE_T */
- MMAL_PARAMETER_FOCUS, /**< @ref MMAL_PARAMETER_FOCUS_T */
- MMAL_PARAMETER_FOCAL_LENGTHS, /**< Unused? */
- MMAL_PARAMETER_EXPOSURE_COMP, /**< @ref MMAL_PARAMETER_INT32_T */
- MMAL_PARAMETER_ZOOM, /**< @ref MMAL_PARAMETER_SCALEFACTOR_T */
- MMAL_PARAMETER_MIRROR, /**< @ref MMAL_PARAMETER_MIRROR_T */
+ /** @ref MMAL_PARAMETER_THUMBNAIL_CONFIG_T */
+ MMAL_PARAMETER_THUMBNAIL_CONFIGURATION =
+ MMAL_PARAMETER_GROUP_CAMERA,
+ /**< Unused? */
+ MMAL_PARAMETER_CAPTURE_QUALITY,
+ /**< @ref MMAL_PARAMETER_INT32_T */
+ MMAL_PARAMETER_ROTATION,
+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_EXIF_DISABLE,
+ /**< @ref MMAL_PARAMETER_EXIF_T */
+ MMAL_PARAMETER_EXIF,
+ /**< @ref MMAL_PARAM_AWBMODE_T */
+ MMAL_PARAMETER_AWB_MODE,
+ /**< @ref MMAL_PARAMETER_IMAGEFX_T */
+ MMAL_PARAMETER_IMAGE_EFFECT,
+ /**< @ref MMAL_PARAMETER_COLOURFX_T */
+ MMAL_PARAMETER_COLOUR_EFFECT,
+ /**< @ref MMAL_PARAMETER_FLICKERAVOID_T */
+ MMAL_PARAMETER_FLICKER_AVOID,
+ /**< @ref MMAL_PARAMETER_FLASH_T */
+ MMAL_PARAMETER_FLASH,
+ /**< @ref MMAL_PARAMETER_REDEYE_T */
+ MMAL_PARAMETER_REDEYE,
+ /**< @ref MMAL_PARAMETER_FOCUS_T */
+ MMAL_PARAMETER_FOCUS,
+ /**< Unused? */
+ MMAL_PARAMETER_FOCAL_LENGTHS,
+ /**< @ref MMAL_PARAMETER_INT32_T */
+ MMAL_PARAMETER_EXPOSURE_COMP,
+ /**< @ref MMAL_PARAMETER_SCALEFACTOR_T */
+ MMAL_PARAMETER_ZOOM,
+ /**< @ref MMAL_PARAMETER_MIRROR_T */
+ MMAL_PARAMETER_MIRROR,
/* 0x10 */
- MMAL_PARAMETER_CAMERA_NUM, /**< @ref MMAL_PARAMETER_UINT32_T */
- MMAL_PARAMETER_CAPTURE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
- MMAL_PARAMETER_EXPOSURE_MODE, /**< @ref MMAL_PARAMETER_EXPOSUREMODE_T */
- MMAL_PARAMETER_EXP_METERING_MODE, /**< @ref MMAL_PARAMETER_EXPOSUREMETERINGMODE_T */
- MMAL_PARAMETER_FOCUS_STATUS, /**< @ref MMAL_PARAMETER_FOCUS_STATUS_T */
- MMAL_PARAMETER_CAMERA_CONFIG, /**< @ref MMAL_PARAMETER_CAMERA_CONFIG_T */
- MMAL_PARAMETER_CAPTURE_STATUS, /**< @ref MMAL_PARAMETER_CAPTURE_STATUS_T */
- MMAL_PARAMETER_FACE_TRACK, /**< @ref MMAL_PARAMETER_FACE_TRACK_T */
- MMAL_PARAMETER_DRAW_BOX_FACES_AND_FOCUS, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
- MMAL_PARAMETER_JPEG_Q_FACTOR, /**< @ref MMAL_PARAMETER_UINT32_T */
- MMAL_PARAMETER_FRAME_RATE, /**< @ref MMAL_PARAMETER_FRAME_RATE_T */
- MMAL_PARAMETER_USE_STC, /**< @ref MMAL_PARAMETER_CAMERA_STC_MODE_T */
- MMAL_PARAMETER_CAMERA_INFO, /**< @ref MMAL_PARAMETER_CAMERA_INFO_T */
- MMAL_PARAMETER_VIDEO_STABILISATION, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
- MMAL_PARAMETER_FACE_TRACK_RESULTS, /**< @ref MMAL_PARAMETER_FACE_TRACK_RESULTS_T */
- MMAL_PARAMETER_ENABLE_RAW_CAPTURE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ /**< @ref MMAL_PARAMETER_UINT32_T */
+ MMAL_PARAMETER_CAMERA_NUM,
+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_CAPTURE,
+ /**< @ref MMAL_PARAMETER_EXPOSUREMODE_T */
+ MMAL_PARAMETER_EXPOSURE_MODE,
+ /**< @ref MMAL_PARAMETER_EXPOSUREMETERINGMODE_T */
+ MMAL_PARAMETER_EXP_METERING_MODE,
+ /**< @ref MMAL_PARAMETER_FOCUS_STATUS_T */
+ MMAL_PARAMETER_FOCUS_STATUS,
+ /**< @ref MMAL_PARAMETER_CAMERA_CONFIG_T */
+ MMAL_PARAMETER_CAMERA_CONFIG,
+ /**< @ref MMAL_PARAMETER_CAPTURE_STATUS_T */
+ MMAL_PARAMETER_CAPTURE_STATUS,
+ /**< @ref MMAL_PARAMETER_FACE_TRACK_T */
+ MMAL_PARAMETER_FACE_TRACK,
+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_DRAW_BOX_FACES_AND_FOCUS,
+ /**< @ref MMAL_PARAMETER_UINT32_T */
+ MMAL_PARAMETER_JPEG_Q_FACTOR,
+ /**< @ref MMAL_PARAMETER_FRAME_RATE_T */
+ MMAL_PARAMETER_FRAME_RATE,
+ /**< @ref MMAL_PARAMETER_CAMERA_STC_MODE_T */
+ MMAL_PARAMETER_USE_STC,
+ /**< @ref MMAL_PARAMETER_CAMERA_INFO_T */
+ MMAL_PARAMETER_CAMERA_INFO,
+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_VIDEO_STABILISATION,
+ /**< @ref MMAL_PARAMETER_FACE_TRACK_RESULTS_T */
+ MMAL_PARAMETER_FACE_TRACK_RESULTS,
+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_ENABLE_RAW_CAPTURE,
/* 0x20 */
- MMAL_PARAMETER_DPF_FILE, /**< @ref MMAL_PARAMETER_URI_T */
- MMAL_PARAMETER_ENABLE_DPF_FILE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
- MMAL_PARAMETER_DPF_FAIL_IS_FATAL, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
- MMAL_PARAMETER_CAPTURE_MODE, /**< @ref MMAL_PARAMETER_CAPTUREMODE_T */
- MMAL_PARAMETER_FOCUS_REGIONS, /**< @ref MMAL_PARAMETER_FOCUS_REGIONS_T */
- MMAL_PARAMETER_INPUT_CROP, /**< @ref MMAL_PARAMETER_INPUT_CROP_T */
- MMAL_PARAMETER_SENSOR_INFORMATION, /**< @ref MMAL_PARAMETER_SENSOR_INFORMATION_T */
- MMAL_PARAMETER_FLASH_SELECT, /**< @ref MMAL_PARAMETER_FLASH_SELECT_T */
- MMAL_PARAMETER_FIELD_OF_VIEW, /**< @ref MMAL_PARAMETER_FIELD_OF_VIEW_T */
- MMAL_PARAMETER_HIGH_DYNAMIC_RANGE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
- MMAL_PARAMETER_DYNAMIC_RANGE_COMPRESSION, /**< @ref MMAL_PARAMETER_DRC_T */
- MMAL_PARAMETER_ALGORITHM_CONTROL, /**< @ref MMAL_PARAMETER_ALGORITHM_CONTROL_T */
- MMAL_PARAMETER_SHARPNESS, /**< @ref MMAL_PARAMETER_RATIONAL_T */
- MMAL_PARAMETER_CONTRAST, /**< @ref MMAL_PARAMETER_RATIONAL_T */
- MMAL_PARAMETER_BRIGHTNESS, /**< @ref MMAL_PARAMETER_RATIONAL_T */
- MMAL_PARAMETER_SATURATION, /**< @ref MMAL_PARAMETER_RATIONAL_T */
+ /**< @ref MMAL_PARAMETER_URI_T */
+ MMAL_PARAMETER_DPF_FILE,
+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_ENABLE_DPF_FILE,
+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_DPF_FAIL_IS_FATAL,
+ /**< @ref MMAL_PARAMETER_CAPTUREMODE_T */
+ MMAL_PARAMETER_CAPTURE_MODE,
+ /**< @ref MMAL_PARAMETER_FOCUS_REGIONS_T */
+ MMAL_PARAMETER_FOCUS_REGIONS,
+ /**< @ref MMAL_PARAMETER_INPUT_CROP_T */
+ MMAL_PARAMETER_INPUT_CROP,
+ /**< @ref MMAL_PARAMETER_SENSOR_INFORMATION_T */
+ MMAL_PARAMETER_SENSOR_INFORMATION,
+ /**< @ref MMAL_PARAMETER_FLASH_SELECT_T */
+ MMAL_PARAMETER_FLASH_SELECT,
+ /**< @ref MMAL_PARAMETER_FIELD_OF_VIEW_T */
+ MMAL_PARAMETER_FIELD_OF_VIEW,
+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_HIGH_DYNAMIC_RANGE,
+ /**< @ref MMAL_PARAMETER_DRC_T */
+ MMAL_PARAMETER_DYNAMIC_RANGE_COMPRESSION,
+ /**< @ref MMAL_PARAMETER_ALGORITHM_CONTROL_T */
+ MMAL_PARAMETER_ALGORITHM_CONTROL,
+ /**< @ref MMAL_PARAMETER_RATIONAL_T */
+ MMAL_PARAMETER_SHARPNESS,
+ /**< @ref MMAL_PARAMETER_RATIONAL_T */
+ MMAL_PARAMETER_CONTRAST,
+ /**< @ref MMAL_PARAMETER_RATIONAL_T */
+ MMAL_PARAMETER_BRIGHTNESS,
+ /**< @ref MMAL_PARAMETER_RATIONAL_T */
+ MMAL_PARAMETER_SATURATION,
/* 0x30 */
- MMAL_PARAMETER_ISO, /**< @ref MMAL_PARAMETER_UINT32_T */
- MMAL_PARAMETER_ANTISHAKE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
-
- /** @ref MMAL_PARAMETER_IMAGEFX_PARAMETERS_T */
+ /**< @ref MMAL_PARAMETER_UINT32_T */
+ MMAL_PARAMETER_ISO,
+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_ANTISHAKE,
+ /** @ref MMAL_PARAMETER_IMAGEFX_PARAMETERS_T */
MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS,
-
- /** @ref MMAL_PARAMETER_BOOLEAN_T */
+ /** @ref MMAL_PARAMETER_BOOLEAN_T */
MMAL_PARAMETER_CAMERA_BURST_CAPTURE,
-
- /** @ref MMAL_PARAMETER_UINT32_T */
+ /** @ref MMAL_PARAMETER_UINT32_T */
MMAL_PARAMETER_CAMERA_MIN_ISO,
-
- /** @ref MMAL_PARAMETER_CAMERA_USE_CASE_T */
+ /** @ref MMAL_PARAMETER_CAMERA_USE_CASE_T */
MMAL_PARAMETER_CAMERA_USE_CASE,
-
- /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
MMAL_PARAMETER_CAPTURE_STATS_PASS,
-
- /** @ref MMAL_PARAMETER_UINT32_T */
+ /** @ref MMAL_PARAMETER_UINT32_T */
MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG,
-
- /** @ref MMAL_PARAMETER_BOOLEAN_T */
+ /** @ref MMAL_PARAMETER_BOOLEAN_T */
MMAL_PARAMETER_ENABLE_REGISTER_FILE,
-
- /** @ref MMAL_PARAMETER_BOOLEAN_T */
+ /** @ref MMAL_PARAMETER_BOOLEAN_T */
MMAL_PARAMETER_REGISTER_FAIL_IS_FATAL,
-
- /** @ref MMAL_PARAMETER_CONFIGFILE_T */
+ /** @ref MMAL_PARAMETER_CONFIGFILE_T */
MMAL_PARAMETER_CONFIGFILE_REGISTERS,
-
- /** @ref MMAL_PARAMETER_CONFIGFILE_CHUNK_T */
+ /** @ref MMAL_PARAMETER_CONFIGFILE_CHUNK_T */
MMAL_PARAMETER_CONFIGFILE_CHUNK_REGISTERS,
- MMAL_PARAMETER_JPEG_ATTACH_LOG, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
- MMAL_PARAMETER_ZERO_SHUTTER_LAG, /**< @ref MMAL_PARAMETER_ZEROSHUTTERLAG_T */
- MMAL_PARAMETER_FPS_RANGE, /**< @ref MMAL_PARAMETER_FPS_RANGE_T */
- MMAL_PARAMETER_CAPTURE_EXPOSURE_COMP, /**< @ref MMAL_PARAMETER_INT32_T */
+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_JPEG_ATTACH_LOG,
+ /**< @ref MMAL_PARAMETER_ZEROSHUTTERLAG_T */
+ MMAL_PARAMETER_ZERO_SHUTTER_LAG,
+ /**< @ref MMAL_PARAMETER_FPS_RANGE_T */
+ MMAL_PARAMETER_FPS_RANGE,
+ /**< @ref MMAL_PARAMETER_INT32_T */
+ MMAL_PARAMETER_CAPTURE_EXPOSURE_COMP,
/* 0x40 */
- MMAL_PARAMETER_SW_SHARPEN_DISABLE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
- MMAL_PARAMETER_FLASH_REQUIRED, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
- MMAL_PARAMETER_SW_SATURATION_DISABLE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
- MMAL_PARAMETER_SHUTTER_SPEED, /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
- MMAL_PARAMETER_CUSTOM_AWB_GAINS, /**< Takes a @ref MMAL_PARAMETER_AWB_GAINS_T */
+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_SW_SHARPEN_DISABLE,
+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_FLASH_REQUIRED,
+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_SW_SATURATION_DISABLE,
+ /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
+ MMAL_PARAMETER_SHUTTER_SPEED,
+ /**< Takes a @ref MMAL_PARAMETER_AWB_GAINS_T */
+ MMAL_PARAMETER_CUSTOM_AWB_GAINS,
};
struct mmal_parameter_rational {
@@ -410,7 +467,8 @@ enum mmal_parameter_video_type {
MMAL_PARAMETER_MINIMISE_FRAGMENTATION,
/** @ref MMAL_PARAMETER_UINT32_T.
- * Setting the value to zero resets to the default (one slice per frame).
+ * Setting the value to zero resets to the default (one slice per
+ * frame).
*/
MMAL_PARAMETER_MB_ROWS_PER_SLICE,
diff --git a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
index 16af735af5c3..1c180ead4a20 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
@@ -4,10 +4,11 @@
*
* Copyright © 2013 Raspberry Pi (Trading) Ltd.
*
- * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
- * Dave Stevenson <dsteve@broadcom.com>
- * Simon Mellor <simellor@broadcom.com>
- * Luke Diamand <luked@broadcom.com>
+ * Authors: Vincent Sanders @ Collabora
+ * Dave Stevenson @ Broadcom
+ * (now dave.stevenson@raspberrypi.org)
+ * Simon Mellor @ Broadcom
+ * Luke Diamand @ Broadcom
*
* V4L2 driver MMAL vchiq interface code
*/
@@ -117,8 +118,10 @@ struct mmal_msg_context {
union {
struct {
- /* work struct for defered callback - must come first */
+ /* work struct for buffer_cb callback */
struct work_struct work;
+ /* work struct for deferred callback */
+ struct work_struct buffer_to_host_work;
/* mmal instance */
struct vchiq_mmal_instance *instance;
/* mmal port */
@@ -161,11 +164,15 @@ struct vchiq_mmal_instance {
void *bulk_scratch;
struct idr context_map;
- spinlock_t context_map_lock;
+ /* protect accesses to context_map */
+ struct mutex context_map_lock;
/* component to use next */
int component_idx;
struct vchiq_mmal_component component[VCHIQ_MMAL_MAX_COMPONENTS];
+
+ /* ordered workqueue to process all bulk operations */
+ struct workqueue_struct *bulk_wq;
};
static struct mmal_msg_context *
@@ -184,10 +191,10 @@ get_msg_context(struct vchiq_mmal_instance *instance)
* that when we service the VCHI reply, we can look up what
* message is being replied to.
*/
- spin_lock(&instance->context_map_lock);
+ mutex_lock(&instance->context_map_lock);
handle = idr_alloc(&instance->context_map, msg_context,
0, 0, GFP_KERNEL);
- spin_unlock(&instance->context_map_lock);
+ mutex_unlock(&instance->context_map_lock);
if (handle < 0) {
kfree(msg_context);
@@ -211,9 +218,9 @@ release_msg_context(struct mmal_msg_context *msg_context)
{
struct vchiq_mmal_instance *instance = msg_context->instance;
- spin_lock(&instance->context_map_lock);
+ mutex_lock(&instance->context_map_lock);
idr_remove(&instance->context_map, msg_context->handle);
- spin_unlock(&instance->context_map_lock);
+ mutex_unlock(&instance->context_map_lock);
kfree(msg_context);
}
@@ -239,6 +246,8 @@ static void buffer_work_cb(struct work_struct *work)
struct mmal_msg_context *msg_context =
container_of(work, struct mmal_msg_context, u.bulk.work);
+ atomic_dec(&msg_context->u.bulk.port->buffers_with_vpu);
+
msg_context->u.bulk.port->buffer_cb(msg_context->u.bulk.instance,
msg_context->u.bulk.port,
msg_context->u.bulk.status,
@@ -247,7 +256,44 @@ static void buffer_work_cb(struct work_struct *work)
msg_context->u.bulk.mmal_flags,
msg_context->u.bulk.dts,
msg_context->u.bulk.pts);
+}
+
+/* workqueue scheduled callback to handle receiving buffers
+ *
+ * VCHI will allow up to 4 bulk receives to be scheduled before blocking.
+ * If we block in the service_callback context then we can't process the
+ * VCHI_CALLBACK_BULK_RECEIVED message that would otherwise allow the blocked
+ * vchi_bulk_queue_receive() call to complete.
+ */
+static void buffer_to_host_work_cb(struct work_struct *work)
+{
+ struct mmal_msg_context *msg_context =
+ container_of(work, struct mmal_msg_context,
+ u.bulk.buffer_to_host_work);
+ struct vchiq_mmal_instance *instance = msg_context->instance;
+ unsigned long len = msg_context->u.bulk.buffer_used;
+ int ret;
+ if (!len)
+ /* Dummy receive to ensure the buffers remain in order */
+ len = 8;
+ /* queue the bulk submission */
+ vchi_service_use(instance->handle);
+ ret = vchi_bulk_queue_receive(instance->handle,
+ msg_context->u.bulk.buffer->buffer,
+ /* Actual receive needs to be a multiple
+ * of 4 bytes
+ */
+ (len + 3) & ~3,
+ VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE |
+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
+ msg_context);
+
+ vchi_service_release(instance->handle);
+
+ if (ret != 0)
+ pr_err("%s: ctx: %p, vchi_bulk_queue_receive failed %d\n",
+ __func__, msg_context, ret);
}
/* enqueue a bulk receive for a given message context */
@@ -256,7 +302,6 @@ static int bulk_receive(struct vchiq_mmal_instance *instance,
struct mmal_msg_context *msg_context)
{
unsigned long rd_len;
- int ret;
rd_len = msg->u.buffer_from_host.buffer_header.length;
@@ -287,50 +332,13 @@ static int bulk_receive(struct vchiq_mmal_instance *instance,
/* store length */
msg_context->u.bulk.buffer_used = rd_len;
- msg_context->u.bulk.mmal_flags =
- msg->u.buffer_from_host.buffer_header.flags;
msg_context->u.bulk.dts = msg->u.buffer_from_host.buffer_header.dts;
msg_context->u.bulk.pts = msg->u.buffer_from_host.buffer_header.pts;
- /* queue the bulk submission */
- vchi_service_use(instance->handle);
- ret = vchi_bulk_queue_receive(instance->handle,
- msg_context->u.bulk.buffer->buffer,
- /* Actual receive needs to be a multiple
- * of 4 bytes
- */
- (rd_len + 3) & ~3,
- VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE |
- VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
- msg_context);
-
- vchi_service_release(instance->handle);
-
- return ret;
-}
-
-/* enque a dummy bulk receive for a given message context */
-static int dummy_bulk_receive(struct vchiq_mmal_instance *instance,
- struct mmal_msg_context *msg_context)
-{
- int ret;
-
- /* zero length indicates this was a dummy transfer */
- msg_context->u.bulk.buffer_used = 0;
-
- /* queue the bulk submission */
- vchi_service_use(instance->handle);
-
- ret = vchi_bulk_queue_receive(instance->handle,
- instance->bulk_scratch,
- 8,
- VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE |
- VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
- msg_context);
+ queue_work(msg_context->instance->bulk_wq,
+ &msg_context->u.bulk.buffer_to_host_work);
- vchi_service_release(instance->handle);
-
- return ret;
+ return 0;
}
/* data in message, memcpy from packet into output buffer */
@@ -378,6 +386,10 @@ buffer_from_host(struct vchiq_mmal_instance *instance,
/* initialise work structure ready to schedule callback */
INIT_WORK(&msg_context->u.bulk.work, buffer_work_cb);
+ INIT_WORK(&msg_context->u.bulk.buffer_to_host_work,
+ buffer_to_host_work_cb);
+
+ atomic_inc(&port->buffers_with_vpu);
/* prep the buffer from host message */
memset(&m, 0xbc, sizeof(m)); /* just to make debug clearer */
@@ -447,6 +459,9 @@ static void buffer_to_host_cb(struct vchiq_mmal_instance *instance,
return;
}
+ msg_context->u.bulk.mmal_flags =
+ msg->u.buffer_from_host.buffer_header.flags;
+
if (msg->h.status != MMAL_MSG_STATUS_SUCCESS) {
/* message reception had an error */
pr_warn("error %d in reply\n", msg->h.status);
@@ -458,7 +473,7 @@ static void buffer_to_host_cb(struct vchiq_mmal_instance *instance,
if (msg->u.buffer_from_host.buffer_header.flags &
MMAL_BUFFER_HEADER_FLAG_EOS) {
msg_context->u.bulk.status =
- dummy_bulk_receive(instance, msg_context);
+ bulk_receive(instance, msg, msg_context);
if (msg_context->u.bulk.status == 0)
return; /* successful bulk submission, bulk
* completion will trigger callback
@@ -635,7 +650,7 @@ static int send_synchronous_mmal_msg(struct vchiq_mmal_instance *instance,
if (payload_len >
(MMAL_MSG_MAX_SIZE - sizeof(struct mmal_msg_header))) {
pr_err("payload length %d exceeds max:%d\n", payload_len,
- (int)(MMAL_MSG_MAX_SIZE -
+ (int)(MMAL_MSG_MAX_SIZE -
sizeof(struct mmal_msg_header)));
return -EINVAL;
}
@@ -838,9 +853,9 @@ static int port_info_get(struct vchiq_mmal_instance *instance,
goto release_msg;
if (rmsg->u.port_info_get_reply.port.is_enabled == 0)
- port->enabled = false;
+ port->enabled = 0;
else
- port->enabled = true;
+ port->enabled = 1;
/* copy the values out of the message */
port->handle = rmsg->u.port_info_get_reply.port_handle;
@@ -1252,9 +1267,10 @@ static int port_parameter_get(struct vchiq_mmal_instance *instance,
memcpy(value, &rmsg->u.port_parameter_get_reply.value,
*value_size);
*value_size = rmsg->u.port_parameter_get_reply.size;
- } else
+ } else {
memcpy(value, &rmsg->u.port_parameter_get_reply.value,
rmsg->u.port_parameter_get_reply.size);
+ }
pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n", __func__,
ret, port->component->handle, port->handle, parameter_id);
@@ -1276,7 +1292,7 @@ static int port_disable(struct vchiq_mmal_instance *instance,
if (!port->enabled)
return 0;
- port->enabled = false;
+ port->enabled = 0;
ret = port_action_port(instance, port,
MMAL_MSG_PORT_ACTION_TYPE_DISABLE);
@@ -1323,22 +1339,12 @@ static int port_enable(struct vchiq_mmal_instance *instance,
if (port->enabled)
return 0;
- /* ensure there are enough buffers queued to cover the buffer headers */
- if (port->buffer_cb) {
- hdr_count = 0;
- list_for_each(buf_head, &port->buffers) {
- hdr_count++;
- }
- if (hdr_count < port->current_buffer.num)
- return -ENOSPC;
- }
-
ret = port_action_port(instance, port,
MMAL_MSG_PORT_ACTION_TYPE_ENABLE);
if (ret)
goto done;
- port->enabled = true;
+ port->enabled = 1;
if (port->buffer_cb) {
/* send buffer headers to videocore */
@@ -1505,7 +1511,7 @@ int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance,
pr_err("failed disconnecting src port\n");
goto release_unlock;
}
- src->connected->enabled = false;
+ src->connected->enabled = 0;
src->connected = NULL;
}
@@ -1752,7 +1758,7 @@ int vchiq_mmal_component_disable(struct vchiq_mmal_instance *instance,
ret = disable_component(instance, component);
if (ret == 0)
- component->enabled = false;
+ component->enabled = 0;
mutex_unlock(&instance->vchiq_mutex);
@@ -1792,6 +1798,9 @@ int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance)
mutex_unlock(&instance->vchiq_mutex);
+ flush_workqueue(instance->bulk_wq);
+ destroy_workqueue(instance->bulk_wq);
+
vfree(instance->bulk_scratch);
idr_destroy(&instance->context_map);
@@ -1849,11 +1858,16 @@ int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance)
instance->bulk_scratch = vmalloc(PAGE_SIZE);
- spin_lock_init(&instance->context_map_lock);
+ mutex_init(&instance->context_map_lock);
idr_init_base(&instance->context_map, 1);
params.callback_param = instance;
+ instance->bulk_wq = alloc_ordered_workqueue("mmal-vchiq",
+ WQ_MEM_RECLAIM);
+ if (!instance->bulk_wq)
+ goto err_free;
+
status = vchi_service_open(vchi_instance, &params, &instance->handle);
if (status) {
pr_err("Failed to open VCHI service connection (status=%d)\n",
@@ -1868,8 +1882,9 @@ int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance)
return 0;
err_close_services:
-
vchi_service_close(instance->handle);
+ destroy_workqueue(instance->bulk_wq);
+err_free:
vfree(instance->bulk_scratch);
kfree(instance);
return -ENODEV;
diff --git a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h
index 22b839ecd5f0..f738e7f99e96 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h
+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h
@@ -4,10 +4,11 @@
*
* Copyright © 2013 Raspberry Pi (Trading) Ltd.
*
- * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
- * Dave Stevenson <dsteve@broadcom.com>
- * Simon Mellor <simellor@broadcom.com>
- * Luke Diamand <luked@broadcom.com>
+ * Authors: Vincent Sanders @ Collabora
+ * Dave Stevenson @ Broadcom
+ * (now dave.stevenson@raspberrypi.org)
+ * Simon Mellor @ Broadcom
+ * Luke Diamand @ Broadcom
*
* MMAL interface to VCHIQ message passing
*/
@@ -47,7 +48,7 @@ typedef void (*vchiq_mmal_buffer_cb)(
unsigned long length, u32 mmal_flags, s64 dts, s64 pts);
struct vchiq_mmal_port {
- bool enabled;
+ u32 enabled:1;
u32 handle;
u32 type; /* port type, cached to use on port info set */
u32 index; /* port index, cached to use on port info set */
@@ -71,6 +72,9 @@ struct vchiq_mmal_port {
struct list_head buffers;
/* lock to serialise adding and removing buffers from list */
spinlock_t slock;
+
+ /* Count of buffers the VPU has yet to return */
+ atomic_t buffers_with_vpu;
/* callback on buffer completion */
vchiq_mmal_buffer_cb buffer_cb;
/* callback context */
@@ -78,7 +82,7 @@ struct vchiq_mmal_port {
};
struct vchiq_mmal_component {
- bool enabled;
+ u32 enabled:1;
u32 handle; /* VideoCore handle for component */
u32 inputs; /* Number of input ports */
u32 outputs; /* Number of output ports */
@@ -127,7 +131,7 @@ int vchiq_mmal_port_enable(
* disable a port will dequeue any pending buffers
*/
int vchiq_mmal_port_disable(struct vchiq_mmal_instance *instance,
- struct vchiq_mmal_port *port);
+ struct vchiq_mmal_port *port);
int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance,
struct vchiq_mmal_port *port,
@@ -145,8 +149,8 @@ int vchiq_mmal_port_set_format(struct vchiq_mmal_instance *instance,
struct vchiq_mmal_port *port);
int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance,
- struct vchiq_mmal_port *src,
- struct vchiq_mmal_port *dst);
+ struct vchiq_mmal_port *src,
+ struct vchiq_mmal_port *dst);
int vchiq_mmal_version(struct vchiq_mmal_instance *instance,
u32 *major_out,
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
index c557c9953724..61c69f353cdb 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
@@ -523,7 +523,7 @@ create_pagelist(char __user *buf, size_t count, unsigned short type)
(g_cache_line_size - 1)))) {
char *fragments;
- if (down_killable(&g_free_fragments_sema)) {
+ if (down_interruptible(&g_free_fragments_sema)) {
cleanup_pagelistinfo(pagelistinfo);
return NULL;
}
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
index ab7d6a0ce94c..cc4383d1ec3e 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
@@ -238,7 +238,7 @@ VCHIQ_STATUS_T vchiq_shutdown(VCHIQ_INSTANCE_T instance)
vchiq_log_trace(vchiq_core_log_level,
"%s(%p) called", __func__, instance);
- if (mutex_lock_killable(&state->mutex) != 0)
+ if (mutex_lock_killable(&state->mutex))
return VCHIQ_RETRY;
/* Remove all services */
@@ -280,7 +280,7 @@ VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance)
vchiq_log_trace(vchiq_core_log_level,
"%s(%p) called", __func__, instance);
- if (mutex_lock_killable(&state->mutex) != 0) {
+ if (mutex_lock_killable(&state->mutex)) {
vchiq_log_trace(vchiq_core_log_level,
"%s: call to mutex_lock failed", __func__);
status = VCHIQ_RETRY;
@@ -532,7 +532,8 @@ add_completion(VCHIQ_INSTANCE_T instance, VCHIQ_REASON_T reason,
vchiq_log_trace(vchiq_arm_log_level,
"%s - completion queue full", __func__);
DEBUG_COUNT(COMPLETION_QUEUE_FULL_COUNT);
- if (wait_for_completion_killable(&instance->remove_event)) {
+ if (wait_for_completion_interruptible(
+ &instance->remove_event)) {
vchiq_log_info(vchiq_arm_log_level,
"service_callback interrupted");
return VCHIQ_RETRY;
@@ -643,9 +644,8 @@ service_callback(VCHIQ_REASON_T reason, struct vchiq_header *header,
}
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
- if (wait_for_completion_killable(
- &user_service->remove_event)
- != 0) {
+ if (wait_for_completion_interruptible(
+ &user_service->remove_event)) {
vchiq_log_info(vchiq_arm_log_level,
"%s interrupted", __func__);
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
@@ -849,7 +849,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
}
rc = mutex_lock_killable(&instance->state->mutex);
- if (rc != 0) {
+ if (rc) {
vchiq_log_error(vchiq_arm_log_level,
"vchiq: connect: could not lock mutex for "
"state %d: %d",
@@ -873,9 +873,8 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
void *userdata;
int srvstate;
- if (copy_from_user
- (&args, (const void __user *)arg,
- sizeof(args)) != 0) {
+ if (copy_from_user(&args, (const void __user *)arg,
+ sizeof(args))) {
ret = -EFAULT;
break;
}
@@ -939,7 +938,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
&(((struct vchiq_create_service __user *)
arg)->handle),
(const void *)&service->handle,
- sizeof(service->handle)) != 0) {
+ sizeof(service->handle))) {
ret = -EFAULT;
vchiq_remove_service(service->handle);
}
@@ -978,7 +977,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
has been closed until the client library calls the
CLOSE_DELIVERED ioctl, signalling close_event. */
if (user_service->close_pending &&
- wait_for_completion_killable(
+ wait_for_completion_interruptible(
&user_service->close_event))
status = VCHIQ_RETRY;
break;
@@ -1014,9 +1013,8 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case VCHIQ_IOC_QUEUE_MESSAGE: {
struct vchiq_queue_message args;
- if (copy_from_user
- (&args, (const void __user *)arg,
- sizeof(args)) != 0) {
+ if (copy_from_user(&args, (const void __user *)arg,
+ sizeof(args))) {
ret = -EFAULT;
break;
}
@@ -1048,9 +1046,8 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
(cmd == VCHIQ_IOC_QUEUE_BULK_TRANSMIT) ?
VCHIQ_BULK_TRANSMIT : VCHIQ_BULK_RECEIVE;
- if (copy_from_user
- (&args, (const void __user *)arg,
- sizeof(args)) != 0) {
+ if (copy_from_user(&args, (const void __user *)arg,
+ sizeof(args))) {
ret = -EFAULT;
break;
}
@@ -1124,7 +1121,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
&(((struct vchiq_queue_bulk_transfer __user *)
arg)->mode),
(const void *)&mode_waiting,
- sizeof(mode_waiting)) != 0)
+ sizeof(mode_waiting)))
ret = -EFAULT;
}
} break;
@@ -1139,7 +1136,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}
if (copy_from_user(&args, (const void __user *)arg,
- sizeof(args)) != 0) {
+ sizeof(args))) {
ret = -EFAULT;
break;
}
@@ -1154,10 +1151,10 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
DEBUG_TRACE(AWAIT_COMPLETION_LINE);
mutex_unlock(&instance->completion_mutex);
- rc = wait_for_completion_killable(
+ rc = wait_for_completion_interruptible(
&instance->insert_event);
mutex_lock(&instance->completion_mutex);
- if (rc != 0) {
+ if (rc) {
DEBUG_TRACE(AWAIT_COMPLETION_LINE);
vchiq_log_info(vchiq_arm_log_level,
"AWAIT_COMPLETION interrupted");
@@ -1223,7 +1220,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (copy_from_user(&msgbuf,
(const void __user *)
&args.msgbufs[msgbufcount],
- sizeof(msgbuf)) != 0) {
+ sizeof(msgbuf))) {
if (ret == 0)
ret = -EFAULT;
break;
@@ -1231,7 +1228,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
/* Copy the message to user space */
if (copy_to_user(msgbuf, header,
- msglen) != 0) {
+ msglen)) {
if (ret == 0)
ret = -EFAULT;
break;
@@ -1256,8 +1253,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
(size_t)args.buf + ret *
sizeof(struct vchiq_completion_data)),
completion,
- sizeof(struct vchiq_completion_data))
- != 0) {
+ sizeof(struct vchiq_completion_data))) {
if (ret == 0)
ret = -EFAULT;
break;
@@ -1277,13 +1273,13 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
&((struct vchiq_await_completion *)arg)
->msgbufcount,
&msgbufcount,
- sizeof(msgbufcount)) != 0) {
+ sizeof(msgbufcount))) {
ret = -EFAULT;
}
}
}
- if (ret != 0)
+ if (ret)
complete(&instance->remove_event);
mutex_unlock(&instance->completion_mutex);
DEBUG_TRACE(AWAIT_COMPLETION_LINE);
@@ -1295,9 +1291,8 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
struct vchiq_header *header;
DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
- if (copy_from_user
- (&args, (const void __user *)arg,
- sizeof(args)) != 0) {
+ if (copy_from_user(&args, (const void __user *)arg,
+ sizeof(args))) {
ret = -EFAULT;
break;
}
@@ -1324,7 +1319,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
do {
spin_unlock(&msg_queue_spinlock);
DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
- if (wait_for_completion_killable(
+ if (wait_for_completion_interruptible(
&user_service->insert_event)) {
vchiq_log_info(vchiq_arm_log_level,
"DEQUEUE_MESSAGE interrupted");
@@ -1383,7 +1378,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
struct vchiq_config config;
if (copy_from_user(&args, (const void __user *)arg,
- sizeof(args)) != 0) {
+ sizeof(args))) {
ret = -EFAULT;
break;
}
@@ -1402,9 +1397,8 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case VCHIQ_IOC_SET_SERVICE_OPTION: {
struct vchiq_set_service_option args;
- if (copy_from_user(
- &args, (const void __user *)arg,
- sizeof(args)) != 0) {
+ if (copy_from_user(&args, (const void __user *)arg,
+ sizeof(args))) {
ret = -EFAULT;
break;
}
@@ -2328,8 +2322,7 @@ vchiq_keepalive_thread_func(void *v)
while (1) {
long rc = 0, uc = 0;
- if (wait_for_completion_killable(&arm_state->ka_evt)
- != 0) {
+ if (wait_for_completion_interruptible(&arm_state->ka_evt)) {
vchiq_log_error(vchiq_susp_log_level,
"%s interrupted", __func__);
flush_signals(current);
@@ -2561,72 +2554,6 @@ need_resume(struct vchiq_state *state)
vchiq_videocore_wanted(state);
}
-static int
-block_resume(struct vchiq_arm_state *arm_state)
-{
- int status = VCHIQ_SUCCESS;
- const unsigned long timeout_val =
- msecs_to_jiffies(FORCE_SUSPEND_TIMEOUT_MS);
- int resume_count = 0;
-
- /* Allow any threads which were blocked by the last force suspend to
- * complete if they haven't already. Only give this one shot; if
- * blocked_count is incremented after blocked_blocker is completed
- * (which only happens when blocked_count hits 0) then those threads
- * will have to wait until next time around */
- if (arm_state->blocked_count) {
- reinit_completion(&arm_state->blocked_blocker);
- write_unlock_bh(&arm_state->susp_res_lock);
- vchiq_log_info(vchiq_susp_log_level, "%s wait for previously "
- "blocked clients", __func__);
- if (wait_for_completion_killable_timeout(
- &arm_state->blocked_blocker, timeout_val)
- <= 0) {
- vchiq_log_error(vchiq_susp_log_level, "%s wait for "
- "previously blocked clients failed", __func__);
- status = VCHIQ_ERROR;
- write_lock_bh(&arm_state->susp_res_lock);
- goto out;
- }
- vchiq_log_info(vchiq_susp_log_level, "%s previously blocked "
- "clients resumed", __func__);
- write_lock_bh(&arm_state->susp_res_lock);
- }
-
- /* We need to wait for resume to complete if it's in process */
- while (arm_state->vc_resume_state != VC_RESUME_RESUMED &&
- arm_state->vc_resume_state > VC_RESUME_IDLE) {
- if (resume_count > 1) {
- status = VCHIQ_ERROR;
- vchiq_log_error(vchiq_susp_log_level, "%s waited too "
- "many times for resume", __func__);
- goto out;
- }
- write_unlock_bh(&arm_state->susp_res_lock);
- vchiq_log_info(vchiq_susp_log_level, "%s wait for resume",
- __func__);
- if (wait_for_completion_killable_timeout(
- &arm_state->vc_resume_complete, timeout_val)
- <= 0) {
- vchiq_log_error(vchiq_susp_log_level, "%s wait for "
- "resume failed (%s)", __func__,
- resume_state_names[arm_state->vc_resume_state +
- VC_RESUME_NUM_OFFSET]);
- status = VCHIQ_ERROR;
- write_lock_bh(&arm_state->susp_res_lock);
- goto out;
- }
- vchiq_log_info(vchiq_susp_log_level, "%s resumed", __func__);
- write_lock_bh(&arm_state->susp_res_lock);
- resume_count++;
- }
- reinit_completion(&arm_state->resume_blocker);
- arm_state->resume_blocked = 1;
-
-out:
- return status;
-}
-
static inline void
unblock_resume(struct vchiq_arm_state *arm_state)
{
@@ -2712,162 +2639,6 @@ out:
return;
}
-static void
-output_timeout_error(struct vchiq_state *state)
-{
- struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state);
- char err[50] = "";
- int vc_use_count = arm_state->videocore_use_count;
- int active_services = state->unused_service;
- int i;
-
- if (!arm_state->videocore_use_count) {
- snprintf(err, sizeof(err), " Videocore usecount is 0");
- goto output_msg;
- }
- for (i = 0; i < active_services; i++) {
- struct vchiq_service *service_ptr = state->services[i];
-
- if (service_ptr && service_ptr->service_use_count &&
- (service_ptr->srvstate != VCHIQ_SRVSTATE_FREE)) {
- snprintf(err, sizeof(err), " %c%c%c%c(%d) service has "
- "use count %d%s", VCHIQ_FOURCC_AS_4CHARS(
- service_ptr->base.fourcc),
- service_ptr->client_id,
- service_ptr->service_use_count,
- service_ptr->service_use_count ==
- vc_use_count ? "" : " (+ more)");
- break;
- }
- }
-
-output_msg:
- vchiq_log_error(vchiq_susp_log_level,
- "timed out waiting for vc suspend (%d).%s",
- arm_state->autosuspend_override, err);
-
-}
-
-/* Try to get videocore into suspended state, regardless of autosuspend state.
-** We don't actually force suspend, since videocore may get into a bad state
-** if we force suspend at a bad time. Instead, we wait for autosuspend to
-** determine a good point to suspend. If this doesn't happen within 100ms we
-** report failure.
-**
-** Returns VCHIQ_SUCCESS if videocore suspended successfully, VCHIQ_RETRY if
-** videocore failed to suspend in time or VCHIQ_ERROR if interrupted.
-*/
-VCHIQ_STATUS_T
-vchiq_arm_force_suspend(struct vchiq_state *state)
-{
- struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state);
- VCHIQ_STATUS_T status = VCHIQ_ERROR;
- long rc = 0;
- int repeat = -1;
-
- if (!arm_state)
- goto out;
-
- vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-
- write_lock_bh(&arm_state->susp_res_lock);
-
- status = block_resume(arm_state);
- if (status != VCHIQ_SUCCESS)
- goto unlock;
- if (arm_state->vc_suspend_state == VC_SUSPEND_SUSPENDED) {
- /* Already suspended - just block resume and exit */
- vchiq_log_info(vchiq_susp_log_level, "%s already suspended",
- __func__);
- status = VCHIQ_SUCCESS;
- goto unlock;
- } else if (arm_state->vc_suspend_state <= VC_SUSPEND_IDLE) {
- /* initiate suspend immediately in the case that we're waiting
- * for the timeout */
- stop_suspend_timer(arm_state);
- if (!vchiq_videocore_wanted(state)) {
- vchiq_log_info(vchiq_susp_log_level, "%s videocore "
- "idle, initiating suspend", __func__);
- status = vchiq_arm_vcsuspend(state);
- } else if (arm_state->autosuspend_override <
- FORCE_SUSPEND_FAIL_MAX) {
- vchiq_log_info(vchiq_susp_log_level, "%s letting "
- "videocore go idle", __func__);
- status = VCHIQ_SUCCESS;
- } else {
- vchiq_log_warning(vchiq_susp_log_level, "%s failed too "
- "many times - attempting suspend", __func__);
- status = vchiq_arm_vcsuspend(state);
- }
- } else {
- vchiq_log_info(vchiq_susp_log_level, "%s videocore suspend "
- "in progress - wait for completion", __func__);
- status = VCHIQ_SUCCESS;
- }
-
- /* Wait for suspend to happen due to system idle (not forced..) */
- if (status != VCHIQ_SUCCESS)
- goto unblock_resume;
-
- do {
- write_unlock_bh(&arm_state->susp_res_lock);
-
- rc = wait_for_completion_killable_timeout(
- &arm_state->vc_suspend_complete,
- msecs_to_jiffies(FORCE_SUSPEND_TIMEOUT_MS));
-
- write_lock_bh(&arm_state->susp_res_lock);
- if (rc < 0) {
- vchiq_log_warning(vchiq_susp_log_level, "%s "
- "interrupted waiting for suspend", __func__);
- status = VCHIQ_ERROR;
- goto unblock_resume;
- } else if (rc == 0) {
- if (arm_state->vc_suspend_state > VC_SUSPEND_IDLE) {
- /* Repeat timeout once if in progress */
- if (repeat < 0) {
- repeat = 1;
- continue;
- }
- }
- arm_state->autosuspend_override++;
- output_timeout_error(state);
-
- status = VCHIQ_RETRY;
- goto unblock_resume;
- }
- } while (0 < (repeat--));
-
- /* Check and report state in case we need to abort ARM suspend */
- if (arm_state->vc_suspend_state != VC_SUSPEND_SUSPENDED) {
- status = VCHIQ_RETRY;
- vchiq_log_error(vchiq_susp_log_level,
- "%s videocore suspend failed (state %s)", __func__,
- suspend_state_names[arm_state->vc_suspend_state +
- VC_SUSPEND_NUM_OFFSET]);
- /* Reset the state only if it's still in an error state.
- * Something could have already initiated another suspend. */
- if (arm_state->vc_suspend_state < VC_SUSPEND_IDLE)
- set_suspend_state(arm_state, VC_SUSPEND_IDLE);
-
- goto unblock_resume;
- }
-
- /* successfully suspended - unlock and exit */
- goto unlock;
-
-unblock_resume:
- /* all error states need to unblock resume before exit */
- unblock_resume(arm_state);
-
-unlock:
- write_unlock_bh(&arm_state->susp_res_lock);
-
-out:
- vchiq_log_trace(vchiq_susp_log_level, "%s exit %d", __func__, status);
- return status;
-}
-
void
vchiq_check_suspend(struct vchiq_state *state)
{
@@ -2890,49 +2661,6 @@ out:
vchiq_log_trace(vchiq_susp_log_level, "%s exit", __func__);
}
-int
-vchiq_arm_allow_resume(struct vchiq_state *state)
-{
- struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state);
- int resume = 0;
- int ret = -1;
-
- if (!arm_state)
- goto out;
-
- vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-
- write_lock_bh(&arm_state->susp_res_lock);
- unblock_resume(arm_state);
- resume = vchiq_check_resume(state);
- write_unlock_bh(&arm_state->susp_res_lock);
-
- if (resume) {
- if (wait_for_completion_killable(
- &arm_state->vc_resume_complete) < 0) {
- vchiq_log_error(vchiq_susp_log_level,
- "%s interrupted", __func__);
- /* failed, cannot accurately derive suspend
- * state, so exit early. */
- goto out;
- }
- }
-
- read_lock_bh(&arm_state->susp_res_lock);
- if (arm_state->vc_suspend_state == VC_SUSPEND_SUSPENDED) {
- vchiq_log_info(vchiq_susp_log_level,
- "%s: Videocore remains suspended", __func__);
- } else {
- vchiq_log_info(vchiq_susp_log_level,
- "%s: Videocore resumed", __func__);
- ret = 0;
- }
- read_unlock_bh(&arm_state->susp_res_lock);
-out:
- vchiq_log_trace(vchiq_susp_log_level, "%s exit %d", __func__, ret);
- return ret;
-}
-
/* This function should be called with the write lock held */
int
vchiq_check_resume(struct vchiq_state *state)
@@ -3010,7 +2738,7 @@ vchiq_use_internal(struct vchiq_state *state, struct vchiq_service *service,
vchiq_log_info(vchiq_susp_log_level, "%s %s resume "
"blocked - waiting...", __func__, entity);
if (wait_for_completion_killable(
- &arm_state->resume_blocker) != 0) {
+ &arm_state->resume_blocker)) {
vchiq_log_error(vchiq_susp_log_level, "%s %s "
"wait for resume blocker interrupted",
__func__, entity);
@@ -3059,7 +2787,7 @@ vchiq_use_internal(struct vchiq_state *state, struct vchiq_service *service,
vchiq_log_info(vchiq_susp_log_level, "%s %s wait for resume",
__func__, entity);
if (wait_for_completion_killable(
- &arm_state->vc_resume_complete) != 0) {
+ &arm_state->vc_resume_complete)) {
vchiq_log_error(vchiq_susp_log_level, "%s %s wait for "
"resume interrupted", __func__, entity);
ret = VCHIQ_ERROR;
@@ -3243,20 +2971,6 @@ static void suspend_timer_callback(struct timer_list *t)
}
VCHIQ_STATUS_T
-vchiq_use_service_no_resume(VCHIQ_SERVICE_HANDLE_T handle)
-{
- VCHIQ_STATUS_T ret = VCHIQ_ERROR;
- struct vchiq_service *service = find_service_by_handle(handle);
-
- if (service) {
- ret = vchiq_use_internal(service->state, service,
- USE_TYPE_SERVICE_NO_RESUME);
- unlock_service(service);
- }
- return ret;
-}
-
-VCHIQ_STATUS_T
vchiq_use_service(VCHIQ_SERVICE_HANDLE_T handle)
{
VCHIQ_STATUS_T ret = VCHIQ_ERROR;
@@ -3504,13 +3218,13 @@ static int vchiq_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, drvdata);
err = vchiq_platform_init(pdev, &g_state);
- if (err != 0)
+ if (err)
goto failed_platform_init;
cdev_init(&vchiq_cdev, &vchiq_fops);
vchiq_cdev.owner = THIS_MODULE;
err = cdev_add(&vchiq_cdev, vchiq_devid, 1);
- if (err != 0) {
+ if (err) {
vchiq_log_error(vchiq_arm_log_level,
"Unable to register device");
goto failed_platform_init;
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
index c1d5a9d17071..b424323e9613 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
@@ -113,12 +113,6 @@ extern VCHIQ_STATUS_T
vchiq_arm_vcsuspend(struct vchiq_state *state);
extern VCHIQ_STATUS_T
-vchiq_arm_force_suspend(struct vchiq_state *state);
-
-extern int
-vchiq_arm_allow_resume(struct vchiq_state *state);
-
-extern VCHIQ_STATUS_T
vchiq_arm_vcresume(struct vchiq_state *state);
extern VCHIQ_STATUS_T
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c
index e87e6619695e..1640906e3929 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c
@@ -41,7 +41,7 @@ void vchiq_add_connected_callback(VCHIQ_CONNECTED_CALLBACK_T callback)
{
connected_init();
- if (mutex_lock_killable(&g_connected_mutex) != 0)
+ if (mutex_lock_killable(&g_connected_mutex))
return;
if (g_connected)
@@ -76,7 +76,7 @@ void vchiq_call_connected_callbacks(void)
connected_init();
- if (mutex_lock_killable(&g_connected_mutex) != 0)
+ if (mutex_lock_killable(&g_connected_mutex))
return;
for (i = 0; i < g_num_deferred_callbacks; i++)
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
index 0c387b6473a5..183f5cf887e0 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
@@ -395,13 +395,21 @@ remote_event_create(wait_queue_head_t *wq, struct remote_event *event)
init_waitqueue_head(wq);
}
+/*
+ * All the event waiting routines in VCHIQ used a custom semaphore
+ * implementation that filtered most signals. This achieved a behaviour similar
+ * to the "killable" family of functions. While cleaning up this code all the
+ * routines where switched to the "interruptible" family of functions, as the
+ * former was deemed unjustified and the use "killable" set all VCHIQ's
+ * threads in D state.
+ */
static inline int
remote_event_wait(wait_queue_head_t *wq, struct remote_event *event)
{
if (!event->fired) {
event->armed = 1;
dsb(sy);
- if (wait_event_killable(*wq, event->fired)) {
+ if (wait_event_interruptible(*wq, event->fired)) {
event->armed = 0;
return 0;
}
@@ -560,7 +568,7 @@ reserve_space(struct vchiq_state *state, size_t space, int is_blocking)
remote_event_signal(&state->remote->trigger);
if (!is_blocking ||
- (wait_for_completion_killable(
+ (wait_for_completion_interruptible(
&state->slot_available_event)))
return NULL; /* No space available */
}
@@ -792,7 +800,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
WARN_ON(!(stride <= VCHIQ_SLOT_SIZE));
if (!(flags & QMFLAGS_NO_MUTEX_LOCK) &&
- (mutex_lock_killable(&state->slot_mutex) != 0))
+ mutex_lock_killable(&state->slot_mutex))
return VCHIQ_RETRY;
if (type == VCHIQ_MSG_DATA) {
@@ -804,8 +812,8 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
return VCHIQ_ERROR;
}
- WARN_ON((flags & (QMFLAGS_NO_MUTEX_LOCK |
- QMFLAGS_NO_MUTEX_UNLOCK)) != 0);
+ WARN_ON(flags & (QMFLAGS_NO_MUTEX_LOCK |
+ QMFLAGS_NO_MUTEX_UNLOCK));
if (service->closing) {
/* The service has been closed */
@@ -830,7 +838,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
spin_unlock(&quota_spinlock);
mutex_unlock(&state->slot_mutex);
- if (wait_for_completion_killable(
+ if (wait_for_completion_interruptible(
&state->data_quota_event))
return VCHIQ_RETRY;
@@ -861,12 +869,12 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
service_quota->slot_use_count);
VCHIQ_SERVICE_STATS_INC(service, quota_stalls);
mutex_unlock(&state->slot_mutex);
- if (wait_for_completion_killable(
+ if (wait_for_completion_interruptible(
&service_quota->quota_event))
return VCHIQ_RETRY;
if (service->closing)
return VCHIQ_ERROR;
- if (mutex_lock_killable(&state->slot_mutex) != 0)
+ if (mutex_lock_killable(&state->slot_mutex))
return VCHIQ_RETRY;
if (service->srvstate != VCHIQ_SRVSTATE_OPEN) {
/* The service has been closed */
@@ -904,8 +912,8 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
header, size, VCHIQ_MSG_SRCPORT(msgid),
VCHIQ_MSG_DSTPORT(msgid));
- WARN_ON((flags & (QMFLAGS_NO_MUTEX_LOCK |
- QMFLAGS_NO_MUTEX_UNLOCK)) != 0);
+ WARN_ON(flags & (QMFLAGS_NO_MUTEX_LOCK |
+ QMFLAGS_NO_MUTEX_UNLOCK));
callback_result =
copy_message_data(copy_callback, context,
@@ -1032,8 +1040,8 @@ queue_message_sync(struct vchiq_state *state, struct vchiq_service *service,
local = state->local;
- if ((VCHIQ_MSG_TYPE(msgid) != VCHIQ_MSG_RESUME) &&
- (mutex_lock_killable(&state->sync_mutex) != 0))
+ if (VCHIQ_MSG_TYPE(msgid) != VCHIQ_MSG_RESUME &&
+ mutex_lock_killable(&state->sync_mutex))
return VCHIQ_RETRY;
remote_event_wait(&state->sync_release_event, &local->sync_release);
@@ -2428,7 +2436,7 @@ vchiq_open_service_internal(struct vchiq_service *service, int client_id)
QMFLAGS_IS_BLOCKING);
if (status == VCHIQ_SUCCESS) {
/* Wait for the ACK/NAK */
- if (wait_for_completion_killable(&service->remove_event)) {
+ if (wait_for_completion_interruptible(&service->remove_event)) {
status = VCHIQ_RETRY;
vchiq_release_service_internal(service);
} else if ((service->srvstate != VCHIQ_SRVSTATE_OPEN) &&
@@ -2514,7 +2522,7 @@ do_abort_bulks(struct vchiq_service *service)
VCHIQ_STATUS_T status;
/* Abort any outstanding bulk transfers */
- if (mutex_lock_killable(&service->bulk_mutex) != 0)
+ if (mutex_lock_killable(&service->bulk_mutex))
return 0;
abort_outstanding_bulks(service, &service->bulk_tx);
abort_outstanding_bulks(service, &service->bulk_rx);
@@ -2795,7 +2803,7 @@ vchiq_connect_internal(struct vchiq_state *state, VCHIQ_INSTANCE_T instance)
}
if (state->conn_state == VCHIQ_CONNSTATE_CONNECTING) {
- if (wait_for_completion_killable(&state->connect))
+ if (wait_for_completion_interruptible(&state->connect))
return VCHIQ_RETRY;
vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED);
@@ -2823,45 +2831,6 @@ vchiq_shutdown_internal(struct vchiq_state *state, VCHIQ_INSTANCE_T instance)
}
VCHIQ_STATUS_T
-vchiq_pause_internal(struct vchiq_state *state)
-{
- VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
-
- switch (state->conn_state) {
- case VCHIQ_CONNSTATE_CONNECTED:
- /* Request a pause */
- vchiq_set_conn_state(state, VCHIQ_CONNSTATE_PAUSING);
- request_poll(state, NULL, 0);
- break;
- default:
- vchiq_log_error(vchiq_core_log_level,
- "%s in state %s\n",
- __func__, conn_state_names[state->conn_state]);
- status = VCHIQ_ERROR;
- VCHIQ_STATS_INC(state, error_count);
- break;
- }
-
- return status;
-}
-
-VCHIQ_STATUS_T
-vchiq_resume_internal(struct vchiq_state *state)
-{
- VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
-
- if (state->conn_state == VCHIQ_CONNSTATE_PAUSED) {
- vchiq_set_conn_state(state, VCHIQ_CONNSTATE_RESUMING);
- request_poll(state, NULL, 0);
- } else {
- status = VCHIQ_ERROR;
- VCHIQ_STATS_INC(state, error_count);
- }
-
- return status;
-}
-
-VCHIQ_STATUS_T
vchiq_close_service(VCHIQ_SERVICE_HANDLE_T handle)
{
/* Unregister the service */
@@ -2894,7 +2863,7 @@ vchiq_close_service(VCHIQ_SERVICE_HANDLE_T handle)
}
while (1) {
- if (wait_for_completion_killable(&service->remove_event)) {
+ if (wait_for_completion_interruptible(&service->remove_event)) {
status = VCHIQ_RETRY;
break;
}
@@ -2955,7 +2924,7 @@ vchiq_remove_service(VCHIQ_SERVICE_HANDLE_T handle)
request_poll(service->state, service, VCHIQ_POLL_REMOVE);
}
while (1) {
- if (wait_for_completion_killable(&service->remove_event)) {
+ if (wait_for_completion_interruptible(&service->remove_event)) {
status = VCHIQ_RETRY;
break;
}
@@ -3029,7 +2998,7 @@ VCHIQ_STATUS_T vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle,
queue = (dir == VCHIQ_BULK_TRANSMIT) ?
&service->bulk_tx : &service->bulk_rx;
- if (mutex_lock_killable(&service->bulk_mutex) != 0) {
+ if (mutex_lock_killable(&service->bulk_mutex)) {
status = VCHIQ_RETRY;
goto error_exit;
}
@@ -3038,13 +3007,12 @@ VCHIQ_STATUS_T vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle,
VCHIQ_SERVICE_STATS_INC(service, bulk_stalls);
do {
mutex_unlock(&service->bulk_mutex);
- if (wait_for_completion_killable(
+ if (wait_for_completion_interruptible(
&service->bulk_remove_event)) {
status = VCHIQ_RETRY;
goto error_exit;
}
- if (mutex_lock_killable(&service->bulk_mutex)
- != 0) {
+ if (mutex_lock_killable(&service->bulk_mutex)) {
status = VCHIQ_RETRY;
goto error_exit;
}
@@ -3072,7 +3040,7 @@ VCHIQ_STATUS_T vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle,
/* The slot mutex must be held when the service is being closed, so
claim it here to ensure that isn't happening */
- if (mutex_lock_killable(&state->slot_mutex) != 0) {
+ if (mutex_lock_killable(&state->slot_mutex)) {
status = VCHIQ_RETRY;
goto cancel_bulk_error_exit;
}
@@ -3093,9 +3061,8 @@ VCHIQ_STATUS_T vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle,
QMFLAGS_IS_BLOCKING |
QMFLAGS_NO_MUTEX_LOCK |
QMFLAGS_NO_MUTEX_UNLOCK);
- if (status != VCHIQ_SUCCESS) {
+ if (status != VCHIQ_SUCCESS)
goto unlock_both_error_exit;
- }
queue->local_insert++;
@@ -3115,7 +3082,7 @@ waiting:
if (bulk_waiter) {
bulk_waiter->bulk = bulk;
- if (wait_for_completion_killable(&bulk_waiter->event))
+ if (wait_for_completion_interruptible(&bulk_waiter->event))
status = VCHIQ_RETRY;
else if (bulk_waiter->actual == VCHIQ_BULK_ACTUAL_ABORTED)
status = VCHIQ_ERROR;
@@ -3571,17 +3538,6 @@ VCHIQ_STATUS_T vchiq_send_remote_use(struct vchiq_state *state)
return status;
}
-VCHIQ_STATUS_T vchiq_send_remote_release(struct vchiq_state *state)
-{
- VCHIQ_STATUS_T status = VCHIQ_RETRY;
-
- if (state->conn_state != VCHIQ_CONNSTATE_DISCONNECTED)
- status = queue_message(state, NULL,
- VCHIQ_MAKE_MSG(VCHIQ_MSG_REMOTE_RELEASE, 0, 0),
- NULL, NULL, 0, 0);
- return status;
-}
-
VCHIQ_STATUS_T vchiq_send_remote_use_active(struct vchiq_state *state)
{
VCHIQ_STATUS_T status = VCHIQ_RETRY;
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h
index aee2d362e88d..63f71b2a492f 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h
@@ -518,12 +518,6 @@ vchiq_free_service_internal(struct vchiq_service *service);
extern VCHIQ_STATUS_T
vchiq_shutdown_internal(struct vchiq_state *state, VCHIQ_INSTANCE_T instance);
-extern VCHIQ_STATUS_T
-vchiq_pause_internal(struct vchiq_state *state);
-
-extern VCHIQ_STATUS_T
-vchiq_resume_internal(struct vchiq_state *state);
-
extern void
remote_event_pollall(struct vchiq_state *state);
@@ -646,9 +640,6 @@ extern VCHIQ_STATUS_T
vchiq_send_remote_use(struct vchiq_state *state);
extern VCHIQ_STATUS_T
-vchiq_send_remote_release(struct vchiq_state *state);
-
-extern VCHIQ_STATUS_T
vchiq_send_remote_use_active(struct vchiq_state *state);
extern void
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
index 2bb9120883fd..f217b78d95a0 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
@@ -86,7 +86,7 @@ static ssize_t debugfs_log_write(struct file *file,
if (count >= DEBUGFS_WRITE_BUF_SIZE)
count = DEBUGFS_WRITE_BUF_SIZE;
- if (copy_from_user(kbuf, buffer, count) != 0)
+ if (copy_from_user(kbuf, buffer, count))
return -EFAULT;
kbuf[count - 1] = 0;
@@ -151,7 +151,7 @@ static ssize_t debugfs_trace_write(struct file *file,
VCHIQ_INSTANCE_T instance = f->private;
char firstchar;
- if (copy_from_user(&firstchar, buffer, 1) != 0)
+ if (copy_from_user(&firstchar, buffer, 1))
return -EFAULT;
switch (firstchar) {
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h
index 5445f201e284..c23bd105c40f 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h
@@ -107,8 +107,6 @@ extern VCHIQ_STATUS_T vchiq_open_service(VCHIQ_INSTANCE_T instance,
extern VCHIQ_STATUS_T vchiq_close_service(VCHIQ_SERVICE_HANDLE_T service);
extern VCHIQ_STATUS_T vchiq_remove_service(VCHIQ_SERVICE_HANDLE_T service);
extern VCHIQ_STATUS_T vchiq_use_service(VCHIQ_SERVICE_HANDLE_T service);
-extern VCHIQ_STATUS_T vchiq_use_service_no_resume(
- VCHIQ_SERVICE_HANDLE_T service);
extern VCHIQ_STATUS_T vchiq_release_service(VCHIQ_SERVICE_HANDLE_T service);
extern VCHIQ_STATUS_T
vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T handle,
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_shim.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_shim.c
index 13910d205fce..17a4f2c8d8b1 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_shim.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_shim.c
@@ -639,10 +639,8 @@ int32_t vchi_service_close(const VCHI_SERVICE_HANDLE_T handle)
if (service) {
VCHIQ_STATUS_T status = vchiq_close_service(service->handle);
- if (status == VCHIQ_SUCCESS) {
+ if (status == VCHIQ_SUCCESS)
service_free(service);
- service = NULL;
- }
ret = vchiq_status_to_vchi(status);
}
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.c
index 6c519d8e48cb..5e6d3035dc05 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.c
@@ -39,18 +39,13 @@ int vchiu_queue_is_empty(struct vchiu_queue *queue)
return queue->read == queue->write;
}
-int vchiu_queue_is_full(struct vchiu_queue *queue)
-{
- return queue->write == queue->read + queue->size;
-}
-
void vchiu_queue_push(struct vchiu_queue *queue, struct vchiq_header *header)
{
if (!queue->initialized)
return;
while (queue->write == queue->read + queue->size) {
- if (wait_for_completion_killable(&queue->pop))
+ if (wait_for_completion_interruptible(&queue->pop))
flush_signals(current);
}
@@ -63,7 +58,7 @@ void vchiu_queue_push(struct vchiu_queue *queue, struct vchiq_header *header)
struct vchiq_header *vchiu_queue_peek(struct vchiu_queue *queue)
{
while (queue->write == queue->read) {
- if (wait_for_completion_killable(&queue->push))
+ if (wait_for_completion_interruptible(&queue->push))
flush_signals(current);
}
@@ -77,7 +72,7 @@ struct vchiq_header *vchiu_queue_pop(struct vchiu_queue *queue)
struct vchiq_header *header;
while (queue->write == queue->read) {
- if (wait_for_completion_killable(&queue->push))
+ if (wait_for_completion_interruptible(&queue->push))
flush_signals(current);
}
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.h
index ee1459468171..f03a4250de0d 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.h
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.h
@@ -40,7 +40,6 @@ extern int vchiu_queue_init(struct vchiu_queue *queue, int size);
extern void vchiu_queue_delete(struct vchiu_queue *queue);
extern int vchiu_queue_is_empty(struct vchiu_queue *queue);
-extern int vchiu_queue_is_full(struct vchiu_queue *queue);
extern void vchiu_queue_push(struct vchiu_queue *queue,
struct vchiq_header *header);
diff --git a/drivers/staging/vt6655/Kconfig b/drivers/staging/vt6655/Kconfig
index e4b224fedf5b..d1cd5de46dcf 100644
--- a/drivers/staging/vt6655/Kconfig
+++ b/drivers/staging/vt6655/Kconfig
@@ -2,6 +2,5 @@
config VT6655
tristate "VIA Technologies VT6655 support"
depends on PCI && MAC80211 && m
- ---help---
- This is a vendor-written driver for VIA VT6655.
-
+ help
+ This is a vendor-written driver for VIA VT6655.
diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c
index 6ecbe925026d..eba4ee0750dc 100644
--- a/drivers/staging/vt6655/card.c
+++ b/drivers/staging/vt6655/card.c
@@ -409,14 +409,11 @@ bool CARDbSetBeaconPeriod(struct vnt_private *priv,
* Out:
* none
*
- * Return Value: true if success; otherwise false
*/
-bool CARDbRadioPowerOff(struct vnt_private *priv)
+void CARDbRadioPowerOff(struct vnt_private *priv)
{
- bool bResult = true;
-
if (priv->bRadioOff)
- return true;
+ return;
switch (priv->byRFType) {
case RF_RFMD2959:
@@ -444,7 +441,6 @@ bool CARDbRadioPowerOff(struct vnt_private *priv)
pr_debug("chester power off\n");
MACvRegBitsOn(priv->PortOffset, MAC_REG_GPIOCTL0,
LED_ACTSET); /* LED issue */
- return bResult;
}
/*
diff --git a/drivers/staging/vt6655/card.h b/drivers/staging/vt6655/card.h
index f422fb3c78bd..887c1692e05b 100644
--- a/drivers/staging/vt6655/card.h
+++ b/drivers/staging/vt6655/card.h
@@ -57,7 +57,7 @@ u64 CARDqGetTSFOffset(unsigned char byRxRate, u64 qwTSF1, u64 qwTSF2);
unsigned char CARDbyGetPktType(struct vnt_private *priv);
void CARDvSafeResetTx(struct vnt_private *priv);
void CARDvSafeResetRx(struct vnt_private *priv);
-bool CARDbRadioPowerOff(struct vnt_private *priv);
+void CARDbRadioPowerOff(struct vnt_private *priv);
bool CARDbRadioPowerOn(struct vnt_private *priv);
bool CARDbSetPhyParameter(struct vnt_private *priv, u8 bb_type);
bool CARDbUpdateTSF(struct vnt_private *priv, unsigned char byRxRate,
diff --git a/drivers/staging/vt6655/test b/drivers/staging/vt6655/test
index 039f7d71c537..ba6dec774478 100644
--- a/drivers/staging/vt6655/test
+++ b/drivers/staging/vt6655/test
@@ -6,4 +6,4 @@ KSP := /lib/modules/$(shell uname -r)/build \
# /usr/src/linux-$(shell uname -r | sed 's/\([0-9]*\.[0-9]*\)\..*/\1/') \
# /usr/src/linux /home/plice
test_dir = $(shell [ -e $(dir)/include/linux ] && echo $(dir))
-KSP := $(foreach dir, $(KSP), $(test_dir)) \ No newline at end of file
+KSP := $(foreach dir, $(KSP), $(test_dir))
diff --git a/drivers/staging/vt6656/Kconfig b/drivers/staging/vt6656/Kconfig
index 51e295265ba6..f52a3f1d9a2e 100644
--- a/drivers/staging/vt6656/Kconfig
+++ b/drivers/staging/vt6656/Kconfig
@@ -3,6 +3,5 @@ config VT6656
tristate "VIA Technologies VT6656 support"
depends on MAC80211 && USB && WLAN && m
select FW_LOADER
- ---help---
- This is a vendor-written driver for VIA VT6656.
-
+ help
+ This is a vendor-written driver for VIA VT6656.
diff --git a/drivers/staging/vt6656/baseband.c b/drivers/staging/vt6656/baseband.c
index b29ba237fa29..8d19ae71e7cc 100644
--- a/drivers/staging/vt6656/baseband.c
+++ b/drivers/staging/vt6656/baseband.c
@@ -329,7 +329,7 @@ void vnt_get_phy_field(struct vnt_private *priv, u32 frame_length,
* Return Value: none
*
*/
-void vnt_set_antenna_mode(struct vnt_private *priv, u8 antenna_mode)
+int vnt_set_antenna_mode(struct vnt_private *priv, u8 antenna_mode)
{
switch (antenna_mode) {
case ANT_TXA:
@@ -344,8 +344,8 @@ void vnt_set_antenna_mode(struct vnt_private *priv, u8 antenna_mode)
break;
}
- vnt_control_out(priv, MESSAGE_TYPE_SET_ANTMD,
- (u16)antenna_mode, 0, 0, NULL);
+ return vnt_control_out(priv, MESSAGE_TYPE_SET_ANTMD,
+ (u16)antenna_mode, 0, 0, NULL);
}
/*
@@ -364,7 +364,7 @@ void vnt_set_antenna_mode(struct vnt_private *priv, u8 antenna_mode)
int vnt_vt3184_init(struct vnt_private *priv)
{
- int status;
+ int ret = 0;
u16 length;
u8 *addr;
u8 *agc;
@@ -372,11 +372,10 @@ int vnt_vt3184_init(struct vnt_private *priv)
u8 array[256];
u8 data;
- status = vnt_control_in(priv, MESSAGE_TYPE_READ, 0,
- MESSAGE_REQUEST_EEPROM, EEP_MAX_CONTEXT_SIZE,
- priv->eeprom);
- if (status != STATUS_SUCCESS)
- return false;
+ ret = vnt_control_in(priv, MESSAGE_TYPE_READ, 0, MESSAGE_REQUEST_EEPROM,
+ EEP_MAX_CONTEXT_SIZE, priv->eeprom);
+ if (ret)
+ goto end;
priv->rf_type = priv->eeprom[EEP_OFS_RFTYPE];
@@ -423,8 +422,10 @@ int vnt_vt3184_init(struct vnt_private *priv)
priv->bb_vga[3] = 0x0;
/* Fix VT3226 DFC system timing issue */
- vnt_mac_reg_bits_on(priv, MAC_REG_SOFTPWRCTL2,
- SOFTPWRCTL_RFLEOPT);
+ ret = vnt_mac_reg_bits_on(priv, MAC_REG_SOFTPWRCTL2,
+ SOFTPWRCTL_RFLEOPT);
+ if (ret)
+ goto end;
} else if (priv->rf_type == RF_VT3342A0) {
priv->bb_rx_conf = vnt_vt3184_vt3226d0[10];
length = sizeof(vnt_vt3184_vt3226d0);
@@ -438,48 +439,74 @@ int vnt_vt3184_init(struct vnt_private *priv)
priv->bb_vga[3] = 0x0;
/* Fix VT3226 DFC system timing issue */
- vnt_mac_reg_bits_on(priv, MAC_REG_SOFTPWRCTL2,
- SOFTPWRCTL_RFLEOPT);
+ ret = vnt_mac_reg_bits_on(priv, MAC_REG_SOFTPWRCTL2,
+ SOFTPWRCTL_RFLEOPT);
+ if (ret)
+ goto end;
} else {
- return true;
+ goto end;
}
memcpy(array, addr, length);
- vnt_control_out(priv, MESSAGE_TYPE_WRITE, 0,
- MESSAGE_REQUEST_BBREG, length, array);
+ ret = vnt_control_out(priv, MESSAGE_TYPE_WRITE, 0,
+ MESSAGE_REQUEST_BBREG, length, array);
+ if (ret)
+ goto end;
memcpy(array, agc, length_agc);
- vnt_control_out(priv, MESSAGE_TYPE_WRITE, 0,
- MESSAGE_REQUEST_BBAGC, length_agc, array);
+ ret = vnt_control_out(priv, MESSAGE_TYPE_WRITE, 0,
+ MESSAGE_REQUEST_BBAGC, length_agc, array);
+ if (ret)
+ goto end;
if ((priv->rf_type == RF_VT3226) ||
(priv->rf_type == RF_VT3342A0)) {
- vnt_control_out_u8(priv, MESSAGE_REQUEST_MACREG,
- MAC_REG_ITRTMSET, 0x23);
- vnt_mac_reg_bits_on(priv, MAC_REG_PAPEDELAY, 0x01);
+ ret = vnt_control_out_u8(priv, MESSAGE_REQUEST_MACREG,
+ MAC_REG_ITRTMSET, 0x23);
+ if (ret)
+ goto end;
+
+ ret = vnt_mac_reg_bits_on(priv, MAC_REG_PAPEDELAY, 0x01);
+ if (ret)
+ goto end;
} else if (priv->rf_type == RF_VT3226D0) {
- vnt_control_out_u8(priv, MESSAGE_REQUEST_MACREG,
- MAC_REG_ITRTMSET, 0x11);
- vnt_mac_reg_bits_on(priv, MAC_REG_PAPEDELAY, 0x01);
+ ret = vnt_control_out_u8(priv, MESSAGE_REQUEST_MACREG,
+ MAC_REG_ITRTMSET, 0x11);
+ if (ret)
+ goto end;
+
+ ret = vnt_mac_reg_bits_on(priv, MAC_REG_PAPEDELAY, 0x01);
+ if (ret)
+ goto end;
}
- vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x04, 0x7f);
- vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0d, 0x01);
+ ret = vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x04, 0x7f);
+ if (ret)
+ goto end;
- vnt_rf_table_download(priv);
+ ret = vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0d, 0x01);
+ if (ret)
+ goto end;
+
+ ret = vnt_rf_table_download(priv);
+ if (ret)
+ goto end;
/* Fix for TX USB resets from vendors driver */
- vnt_control_in(priv, MESSAGE_TYPE_READ, USB_REG4,
- MESSAGE_REQUEST_MEM, sizeof(data), &data);
+ ret = vnt_control_in(priv, MESSAGE_TYPE_READ, USB_REG4,
+ MESSAGE_REQUEST_MEM, sizeof(data), &data);
+ if (ret)
+ goto end;
data |= 0x2;
- vnt_control_out(priv, MESSAGE_TYPE_WRITE, USB_REG4,
- MESSAGE_REQUEST_MEM, sizeof(data), &data);
+ ret = vnt_control_out(priv, MESSAGE_TYPE_WRITE, USB_REG4,
+ MESSAGE_REQUEST_MEM, sizeof(data), &data);
- return true;
+end:
+ return ret;
}
/*
@@ -494,8 +521,9 @@ int vnt_vt3184_init(struct vnt_private *priv)
* Return Value: none
*
*/
-void vnt_set_short_slot_time(struct vnt_private *priv)
+int vnt_set_short_slot_time(struct vnt_private *priv)
{
+ int ret = 0;
u8 bb_vga = 0;
if (priv->short_slot_time)
@@ -503,12 +531,18 @@ void vnt_set_short_slot_time(struct vnt_private *priv)
else
priv->bb_rx_conf |= 0x20;
- vnt_control_in_u8(priv, MESSAGE_REQUEST_BBREG, 0xe7, &bb_vga);
+ ret = vnt_control_in_u8(priv, MESSAGE_REQUEST_BBREG, 0xe7, &bb_vga);
+ if (ret)
+ goto end;
if (bb_vga == priv->bb_vga[0])
priv->bb_rx_conf |= 0x20;
- vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0a, priv->bb_rx_conf);
+ ret = vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0a,
+ priv->bb_rx_conf);
+
+end:
+ return ret;
}
void vnt_set_vga_gain_offset(struct vnt_private *priv, u8 data)
@@ -536,16 +570,30 @@ void vnt_set_vga_gain_offset(struct vnt_private *priv, u8 data)
* Return Value: none
*
*/
-void vnt_set_deep_sleep(struct vnt_private *priv)
+int vnt_set_deep_sleep(struct vnt_private *priv)
{
- vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0c, 0x17);/* CR12 */
- vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0d, 0xB9);/* CR13 */
+ int ret = 0;
+
+ /* CR12 */
+ ret = vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0c, 0x17);
+ if (ret)
+ return ret;
+
+ /* CR13 */
+ return vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0d, 0xB9);
}
-void vnt_exit_deep_sleep(struct vnt_private *priv)
+int vnt_exit_deep_sleep(struct vnt_private *priv)
{
- vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0c, 0x00);/* CR12 */
- vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0d, 0x01);/* CR13 */
+ int ret = 0;
+
+ /* CR12 */
+ ret = vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0c, 0x00);
+ if (ret)
+ return ret;
+
+ /* CR13 */
+ return vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0d, 0x01);
}
void vnt_update_pre_ed_threshold(struct vnt_private *priv, int scanning)
diff --git a/drivers/staging/vt6656/baseband.h b/drivers/staging/vt6656/baseband.h
index c3b8bbdb3ea1..dc42aa6ae1d9 100644
--- a/drivers/staging/vt6656/baseband.h
+++ b/drivers/staging/vt6656/baseband.h
@@ -79,12 +79,12 @@ unsigned int vnt_get_frame_time(u8 preamble_type, u8 pkt_type,
void vnt_get_phy_field(struct vnt_private *priv, u32 frame_length,
u16 tx_rate, u8 pkt_type, struct vnt_phy_field *phy);
-void vnt_set_short_slot_time(struct vnt_private *priv);
+int vnt_set_short_slot_time(struct vnt_private *priv);
void vnt_set_vga_gain_offset(struct vnt_private *priv, u8 data);
-void vnt_set_antenna_mode(struct vnt_private *priv, u8 antenna_mode);
+int vnt_set_antenna_mode(struct vnt_private *priv, u8 antenna_mode);
int vnt_vt3184_init(struct vnt_private *priv);
-void vnt_set_deep_sleep(struct vnt_private *priv);
-void vnt_exit_deep_sleep(struct vnt_private *priv);
+int vnt_set_deep_sleep(struct vnt_private *priv);
+int vnt_exit_deep_sleep(struct vnt_private *priv);
void vnt_update_pre_ed_threshold(struct vnt_private *priv, int scanning);
#endif /* __BASEBAND_H__ */
diff --git a/drivers/staging/vt6656/card.c b/drivers/staging/vt6656/card.c
index 501f482b41c4..56cd77fd9ea0 100644
--- a/drivers/staging/vt6656/card.c
+++ b/drivers/staging/vt6656/card.c
@@ -166,7 +166,7 @@ static void vnt_calculate_ofdm_rate(u16 rate, u8 bb_type,
*tx_rate = 0x8b;
*rsv_time = 30;
}
- break;
+ break;
case RATE_9M:
if (bb_type == BB_TYPE_11A) {
*tx_rate = 0x9f;
@@ -674,7 +674,7 @@ void vnt_update_next_tbtt(struct vnt_private *priv, u64 tsf,
*/
int vnt_radio_power_off(struct vnt_private *priv)
{
- int ret = true;
+ int ret = 0;
switch (priv->rf_type) {
case RF_AL2230:
@@ -683,17 +683,25 @@ int vnt_radio_power_off(struct vnt_private *priv)
case RF_VT3226:
case RF_VT3226D0:
case RF_VT3342A0:
- vnt_mac_reg_bits_off(priv, MAC_REG_SOFTPWRCTL,
- (SOFTPWRCTL_SWPE2 | SOFTPWRCTL_SWPE3));
+ ret = vnt_mac_reg_bits_off(priv, MAC_REG_SOFTPWRCTL,
+ (SOFTPWRCTL_SWPE2 | SOFTPWRCTL_SWPE3));
break;
}
- vnt_mac_reg_bits_off(priv, MAC_REG_HOSTCR, HOSTCR_RXON);
+ if (ret)
+ goto end;
+
+ ret = vnt_mac_reg_bits_off(priv, MAC_REG_HOSTCR, HOSTCR_RXON);
+ if (ret)
+ goto end;
- vnt_set_deep_sleep(priv);
+ ret = vnt_set_deep_sleep(priv);
+ if (ret)
+ goto end;
- vnt_mac_reg_bits_on(priv, MAC_REG_GPIOCTL1, GPIO3_INTMD);
+ ret = vnt_mac_reg_bits_on(priv, MAC_REG_GPIOCTL1, GPIO3_INTMD);
+end:
return ret;
}
diff --git a/drivers/staging/vt6656/firmware.c b/drivers/staging/vt6656/firmware.c
index 38521c338917..60a00af250bf 100644
--- a/drivers/staging/vt6656/firmware.c
+++ b/drivers/staging/vt6656/firmware.c
@@ -30,98 +30,87 @@ int vnt_download_firmware(struct vnt_private *priv)
{
struct device *dev = &priv->usb->dev;
const struct firmware *fw;
- int status;
void *buffer = NULL;
- bool result = false;
u16 length;
- int ii, rc;
+ int ii;
+ int ret = 0;
dev_dbg(dev, "---->Download firmware\n");
- rc = request_firmware(&fw, FIRMWARE_NAME, dev);
- if (rc) {
+ ret = request_firmware(&fw, FIRMWARE_NAME, dev);
+ if (ret) {
dev_err(dev, "firmware file %s request failed (%d)\n",
- FIRMWARE_NAME, rc);
- goto out;
+ FIRMWARE_NAME, ret);
+ goto end;
}
buffer = kmalloc(FIRMWARE_CHUNK_SIZE, GFP_KERNEL);
- if (!buffer)
+ if (!buffer) {
+ ret = -ENOMEM;
goto free_fw;
+ }
for (ii = 0; ii < fw->size; ii += FIRMWARE_CHUNK_SIZE) {
length = min_t(int, fw->size - ii, FIRMWARE_CHUNK_SIZE);
memcpy(buffer, fw->data + ii, length);
- status = vnt_control_out(priv,
- 0,
- 0x1200 + ii,
- 0x0000,
- length,
- buffer);
+ ret = vnt_control_out(priv, 0, 0x1200 + ii, 0x0000, length,
+ buffer);
+ if (ret)
+ goto free_buffer;
dev_dbg(dev, "Download firmware...%d %zu\n", ii, fw->size);
-
- if (status != STATUS_SUCCESS)
- goto free_fw;
}
- result = true;
+free_buffer:
+ kfree(buffer);
free_fw:
release_firmware(fw);
-
-out:
- kfree(buffer);
-
- return result;
+end:
+ return ret;
}
MODULE_FIRMWARE(FIRMWARE_NAME);
int vnt_firmware_branch_to_sram(struct vnt_private *priv)
{
- int status;
-
dev_dbg(&priv->usb->dev, "---->Branch to Sram\n");
- status = vnt_control_out(priv,
- 1,
- 0x1200,
- 0x0000,
- 0,
- NULL);
- return status == STATUS_SUCCESS;
+ return vnt_control_out(priv, 1, 0x1200, 0x0000, 0, NULL);
}
int vnt_check_firmware_version(struct vnt_private *priv)
{
- int status;
-
- status = vnt_control_in(priv,
- MESSAGE_TYPE_READ,
- 0,
- MESSAGE_REQUEST_VERSION,
- 2,
- (u8 *)&priv->firmware_version);
+ int ret = 0;
+
+ ret = vnt_control_in(priv, MESSAGE_TYPE_READ, 0,
+ MESSAGE_REQUEST_VERSION, 2,
+ (u8 *)&priv->firmware_version);
+ if (ret) {
+ dev_dbg(&priv->usb->dev,
+ "Could not get firmware version: %d.\n", ret);
+ goto end;
+ }
dev_dbg(&priv->usb->dev, "Firmware Version [%04x]\n",
priv->firmware_version);
- if (status != STATUS_SUCCESS) {
- dev_dbg(&priv->usb->dev, "Firmware Invalid.\n");
- return false;
- }
if (priv->firmware_version == 0xFFFF) {
dev_dbg(&priv->usb->dev, "In Loader.\n");
- return false;
+ ret = -EINVAL;
+ goto end;
}
- dev_dbg(&priv->usb->dev, "Firmware Version [%04x]\n",
- priv->firmware_version);
-
if (priv->firmware_version < FIRMWARE_VERSION) {
/* branch to loader for download new firmware */
- vnt_firmware_branch_to_sram(priv);
- return false;
+ ret = vnt_firmware_branch_to_sram(priv);
+ if (ret) {
+ dev_dbg(&priv->usb->dev,
+ "Could not branch to SRAM: %d.\n", ret);
+ } else {
+ ret = -EINVAL;
+ }
}
- return true;
+
+end:
+ return ret;
}
diff --git a/drivers/staging/vt6656/int.c b/drivers/staging/vt6656/int.c
index 504424b19fcf..f40947955675 100644
--- a/drivers/staging/vt6656/int.c
+++ b/drivers/staging/vt6656/int.c
@@ -39,18 +39,20 @@ static const u8 fallback_rate1[5][5] = {
{RATE_54M, RATE_54M, RATE_36M, RATE_18M, RATE_18M}
};
-void vnt_int_start_interrupt(struct vnt_private *priv)
+int vnt_int_start_interrupt(struct vnt_private *priv)
{
+ int ret = 0;
unsigned long flags;
- int status;
dev_dbg(&priv->usb->dev, "---->Interrupt Polling Thread\n");
spin_lock_irqsave(&priv->lock, flags);
- status = vnt_start_interrupt_urb(priv);
+ ret = vnt_start_interrupt_urb(priv);
spin_unlock_irqrestore(&priv->lock, flags);
+
+ return ret;
}
static int vnt_int_report_rate(struct vnt_private *priv, u8 pkt_no, u8 tsr)
diff --git a/drivers/staging/vt6656/int.h b/drivers/staging/vt6656/int.h
index 987c454e99e9..8a6d60569ceb 100644
--- a/drivers/staging/vt6656/int.h
+++ b/drivers/staging/vt6656/int.h
@@ -41,7 +41,7 @@ struct vnt_interrupt_data {
u8 sw[2];
} __packed;
-void vnt_int_start_interrupt(struct vnt_private *priv);
+int vnt_int_start_interrupt(struct vnt_private *priv);
void vnt_int_process_data(struct vnt_private *priv);
#endif /* __INT_H__ */
diff --git a/drivers/staging/vt6656/mac.c b/drivers/staging/vt6656/mac.c
index 0b543854ea97..5cacf6e60e90 100644
--- a/drivers/staging/vt6656/mac.c
+++ b/drivers/staging/vt6656/mac.c
@@ -129,27 +129,26 @@ void vnt_mac_set_keyentry(struct vnt_private *priv, u16 key_ctl, u32 entry_idx,
(u8 *)&set_key);
}
-void vnt_mac_reg_bits_off(struct vnt_private *priv, u8 reg_ofs, u8 bits)
+int vnt_mac_reg_bits_off(struct vnt_private *priv, u8 reg_ofs, u8 bits)
{
u8 data[2];
data[0] = 0;
data[1] = bits;
- vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK,
- reg_ofs, MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data),
- data);
+ return vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, reg_ofs,
+ MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data);
}
-void vnt_mac_reg_bits_on(struct vnt_private *priv, u8 reg_ofs, u8 bits)
+int vnt_mac_reg_bits_on(struct vnt_private *priv, u8 reg_ofs, u8 bits)
{
u8 data[2];
data[0] = bits;
data[1] = bits;
- vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, reg_ofs,
- MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data);
+ return vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, reg_ofs,
+ MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data);
}
void vnt_mac_write_word(struct vnt_private *priv, u8 reg_ofs, u16 word)
@@ -224,13 +223,13 @@ void vnt_mac_set_beacon_interval(struct vnt_private *priv, u16 interval)
MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data);
}
-void vnt_mac_set_led(struct vnt_private *priv, u8 state, u8 led)
+int vnt_mac_set_led(struct vnt_private *priv, u8 state, u8 led)
{
u8 data[2];
data[0] = led;
data[1] = state;
- vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, MAC_REG_PAPEDELAY,
- MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data);
+ return vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, MAC_REG_PAPEDELAY,
+ MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data);
}
diff --git a/drivers/staging/vt6656/mac.h b/drivers/staging/vt6656/mac.h
index 3fd87f95c524..0a42308b81e9 100644
--- a/drivers/staging/vt6656/mac.h
+++ b/drivers/staging/vt6656/mac.h
@@ -360,8 +360,8 @@ void vnt_mac_set_bb_type(struct vnt_private *priv, u8 type);
void vnt_mac_disable_keyentry(struct vnt_private *priv, u8 entry_idx);
void vnt_mac_set_keyentry(struct vnt_private *priv, u16 key_ctl, u32 entry_idx,
u32 key_idx, u8 *addr, u8 *key);
-void vnt_mac_reg_bits_off(struct vnt_private *priv, u8 reg_ofs, u8 bits);
-void vnt_mac_reg_bits_on(struct vnt_private *priv, u8 reg_ofs, u8 bits);
+int vnt_mac_reg_bits_off(struct vnt_private *priv, u8 reg_ofs, u8 bits);
+int vnt_mac_reg_bits_on(struct vnt_private *priv, u8 reg_ofs, u8 bits);
void vnt_mac_write_word(struct vnt_private *priv, u8 reg_ofs, u16 word);
void vnt_mac_set_bssid_addr(struct vnt_private *priv, u8 *addr);
void vnt_mac_enable_protect_mode(struct vnt_private *priv);
@@ -369,6 +369,6 @@ void vnt_mac_disable_protect_mode(struct vnt_private *priv);
void vnt_mac_enable_barker_preamble_mode(struct vnt_private *priv);
void vnt_mac_disable_barker_preamble_mode(struct vnt_private *priv);
void vnt_mac_set_beacon_interval(struct vnt_private *priv, u16 interval);
-void vnt_mac_set_led(struct vnt_private *privpriv, u8 state, u8 led);
+int vnt_mac_set_led(struct vnt_private *privpriv, u8 state, u8 led);
#endif /* __MAC_H__ */
diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c
index ccafcc2c87ac..856ba97aec4f 100644
--- a/drivers/staging/vt6656/main_usb.c
+++ b/drivers/staging/vt6656/main_usb.c
@@ -109,33 +109,38 @@ static void vnt_set_options(struct vnt_private *priv)
*/
static int vnt_init_registers(struct vnt_private *priv)
{
+ int ret = 0;
struct vnt_cmd_card_init *init_cmd = &priv->init_command;
struct vnt_rsp_card_init *init_rsp = &priv->init_response;
u8 antenna;
int ii;
- int status = STATUS_SUCCESS;
u8 tmp;
u8 calib_tx_iq = 0, calib_tx_dc = 0, calib_rx_iq = 0;
dev_dbg(&priv->usb->dev, "---->INIbInitAdapter. [%d][%d]\n",
DEVICE_INIT_COLD, priv->packet_type);
- if (!vnt_check_firmware_version(priv)) {
- if (vnt_download_firmware(priv) == true) {
- if (vnt_firmware_branch_to_sram(priv) == false) {
- dev_dbg(&priv->usb->dev,
- " vnt_firmware_branch_to_sram fail\n");
- return false;
- }
- } else {
- dev_dbg(&priv->usb->dev, "FIRMWAREbDownload fail\n");
- return false;
+ ret = vnt_check_firmware_version(priv);
+ if (ret) {
+ ret = vnt_download_firmware(priv);
+ if (ret) {
+ dev_dbg(&priv->usb->dev,
+ "Could not download firmware: %d.\n", ret);
+ goto end;
+ }
+
+ ret = vnt_firmware_branch_to_sram(priv);
+ if (ret) {
+ dev_dbg(&priv->usb->dev,
+ "Could not branch to SRAM: %d.\n", ret);
+ goto end;
}
}
- if (!vnt_vt3184_init(priv)) {
+ ret = vnt_vt3184_init(priv);
+ if (ret) {
dev_dbg(&priv->usb->dev, "vnt_vt3184_init fail\n");
- return false;
+ goto end;
}
init_cmd->init_class = DEVICE_INIT_COLD;
@@ -146,28 +151,27 @@ static int vnt_init_registers(struct vnt_private *priv)
init_cmd->long_retry_limit = priv->long_retry_limit;
/* issue card_init command to device */
- status = vnt_control_out(priv, MESSAGE_TYPE_CARDINIT, 0, 0,
- sizeof(struct vnt_cmd_card_init),
- (u8 *)init_cmd);
- if (status != STATUS_SUCCESS) {
+ ret = vnt_control_out(priv, MESSAGE_TYPE_CARDINIT, 0, 0,
+ sizeof(struct vnt_cmd_card_init),
+ (u8 *)init_cmd);
+ if (ret) {
dev_dbg(&priv->usb->dev, "Issue Card init fail\n");
- return false;
+ goto end;
}
- status = vnt_control_in(priv, MESSAGE_TYPE_INIT_RSP, 0, 0,
- sizeof(struct vnt_rsp_card_init),
- (u8 *)init_rsp);
- if (status != STATUS_SUCCESS) {
- dev_dbg(&priv->usb->dev,
- "Cardinit request in status fail!\n");
- return false;
+ ret = vnt_control_in(priv, MESSAGE_TYPE_INIT_RSP, 0, 0,
+ sizeof(struct vnt_rsp_card_init),
+ (u8 *)init_rsp);
+ if (ret) {
+ dev_dbg(&priv->usb->dev, "Cardinit request in status fail!\n");
+ goto end;
}
/* local ID for AES functions */
- status = vnt_control_in(priv, MESSAGE_TYPE_READ, MAC_REG_LOCALID,
- MESSAGE_REQUEST_MACREG, 1, &priv->local_id);
- if (status != STATUS_SUCCESS)
- return false;
+ ret = vnt_control_in(priv, MESSAGE_TYPE_READ, MAC_REG_LOCALID,
+ MESSAGE_REQUEST_MACREG, 1, &priv->local_id);
+ if (ret)
+ goto end;
/* do MACbSoftwareReset in MACvInitialize */
@@ -253,7 +257,9 @@ static int vnt_init_registers(struct vnt_private *priv)
}
/* Set initial antenna mode */
- vnt_set_antenna_mode(priv, priv->rx_antenna_mode);
+ ret = vnt_set_antenna_mode(priv, priv->rx_antenna_mode);
+ if (ret)
+ goto end;
/* get Auto Fall Back type */
priv->auto_fb_ctrl = AUTO_FB_0;
@@ -275,33 +281,41 @@ static int vnt_init_registers(struct vnt_private *priv)
/* CR255, enable TX/RX IQ and
* DC compensation mode
*/
- vnt_control_out_u8(priv,
- MESSAGE_REQUEST_BBREG,
- 0xff,
- 0x03);
+ ret = vnt_control_out_u8(priv,
+ MESSAGE_REQUEST_BBREG,
+ 0xff, 0x03);
+ if (ret)
+ goto end;
+
/* CR251, TX I/Q Imbalance Calibration */
- vnt_control_out_u8(priv,
- MESSAGE_REQUEST_BBREG,
- 0xfb,
- calib_tx_iq);
+ ret = vnt_control_out_u8(priv,
+ MESSAGE_REQUEST_BBREG,
+ 0xfb, calib_tx_iq);
+ if (ret)
+ goto end;
+
/* CR252, TX DC-Offset Calibration */
- vnt_control_out_u8(priv,
- MESSAGE_REQUEST_BBREG,
- 0xfC,
- calib_tx_dc);
+ ret = vnt_control_out_u8(priv,
+ MESSAGE_REQUEST_BBREG,
+ 0xfC, calib_tx_dc);
+ if (ret)
+ goto end;
+
/* CR253, RX I/Q Imbalance Calibration */
- vnt_control_out_u8(priv,
- MESSAGE_REQUEST_BBREG,
- 0xfd,
- calib_rx_iq);
+ ret = vnt_control_out_u8(priv,
+ MESSAGE_REQUEST_BBREG,
+ 0xfd, calib_rx_iq);
+ if (ret)
+ goto end;
} else {
/* CR255, turn off
* BB Calibration compensation
*/
- vnt_control_out_u8(priv,
- MESSAGE_REQUEST_BBREG,
- 0xff,
- 0x0);
+ ret = vnt_control_out_u8(priv,
+ MESSAGE_REQUEST_BBREG,
+ 0xff, 0x0);
+ if (ret)
+ goto end;
}
}
}
@@ -323,37 +337,52 @@ static int vnt_init_registers(struct vnt_private *priv)
else
priv->short_slot_time = false;
- vnt_set_short_slot_time(priv);
+ ret = vnt_set_short_slot_time(priv);
+ if (ret)
+ goto end;
priv->radio_ctl = priv->eeprom[EEP_OFS_RADIOCTL];
if ((priv->radio_ctl & EEP_RADIOCTL_ENABLE) != 0) {
- status = vnt_control_in(priv, MESSAGE_TYPE_READ,
- MAC_REG_GPIOCTL1,
- MESSAGE_REQUEST_MACREG, 1, &tmp);
-
- if (status != STATUS_SUCCESS)
- return false;
+ ret = vnt_control_in(priv, MESSAGE_TYPE_READ,
+ MAC_REG_GPIOCTL1, MESSAGE_REQUEST_MACREG,
+ 1, &tmp);
+ if (ret)
+ goto end;
+
+ if ((tmp & GPIO3_DATA) == 0) {
+ ret = vnt_mac_reg_bits_on(priv, MAC_REG_GPIOCTL1,
+ GPIO3_INTMD);
+ } else {
+ ret = vnt_mac_reg_bits_off(priv, MAC_REG_GPIOCTL1,
+ GPIO3_INTMD);
+ }
- if ((tmp & GPIO3_DATA) == 0)
- vnt_mac_reg_bits_on(priv, MAC_REG_GPIOCTL1,
- GPIO3_INTMD);
- else
- vnt_mac_reg_bits_off(priv, MAC_REG_GPIOCTL1,
- GPIO3_INTMD);
+ if (ret)
+ goto end;
}
- vnt_mac_set_led(priv, LEDSTS_TMLEN, 0x38);
- vnt_mac_set_led(priv, LEDSTS_STS, LEDSTS_SLOW);
+ ret = vnt_mac_set_led(priv, LEDSTS_TMLEN, 0x38);
+ if (ret)
+ goto end;
+
+ ret = vnt_mac_set_led(priv, LEDSTS_STS, LEDSTS_SLOW);
+ if (ret)
+ goto end;
- vnt_mac_reg_bits_on(priv, MAC_REG_GPIOCTL0, 0x01);
+ ret = vnt_mac_reg_bits_on(priv, MAC_REG_GPIOCTL0, 0x01);
+ if (ret)
+ goto end;
- vnt_radio_power_on(priv);
+ ret = vnt_radio_power_on(priv);
+ if (ret)
+ goto end;
dev_dbg(&priv->usb->dev, "<----INIbInitAdapter Exit\n");
- return true;
+end:
+ return ret;
}
static void vnt_free_tx_bufs(struct vnt_private *priv)
@@ -363,6 +392,9 @@ static void vnt_free_tx_bufs(struct vnt_private *priv)
for (ii = 0; ii < priv->num_tx_context; ii++) {
tx_context = priv->tx_context[ii];
+ if (!tx_context)
+ continue;
+
/* deallocate URBs */
if (tx_context->urb) {
usb_kill_urb(tx_context->urb);
@@ -402,16 +434,19 @@ static void vnt_free_int_bufs(struct vnt_private *priv)
kfree(priv->int_buf.data_buf);
}
-static bool vnt_alloc_bufs(struct vnt_private *priv)
+static int vnt_alloc_bufs(struct vnt_private *priv)
{
+ int ret = 0;
struct vnt_usb_send_context *tx_context;
struct vnt_rcb *rcb;
int ii;
for (ii = 0; ii < priv->num_tx_context; ii++) {
tx_context = kmalloc(sizeof(*tx_context), GFP_KERNEL);
- if (!tx_context)
+ if (!tx_context) {
+ ret = -ENOMEM;
goto free_tx;
+ }
priv->tx_context[ii] = tx_context;
tx_context->priv = priv;
@@ -419,16 +454,20 @@ static bool vnt_alloc_bufs(struct vnt_private *priv)
/* allocate URBs */
tx_context->urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!tx_context->urb)
+ if (!tx_context->urb) {
+ ret = -ENOMEM;
goto free_tx;
+ }
tx_context->in_use = false;
}
for (ii = 0; ii < priv->num_rcb; ii++) {
priv->rcb[ii] = kzalloc(sizeof(*priv->rcb[ii]), GFP_KERNEL);
- if (!priv->rcb[ii])
+ if (!priv->rcb[ii]) {
+ ret = -ENOMEM;
goto free_rx_tx;
+ }
rcb = priv->rcb[ii];
@@ -436,39 +475,46 @@ static bool vnt_alloc_bufs(struct vnt_private *priv)
/* allocate URBs */
rcb->urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!rcb->urb)
+ if (!rcb->urb) {
+ ret = -ENOMEM;
goto free_rx_tx;
+ }
rcb->skb = dev_alloc_skb(priv->rx_buf_sz);
- if (!rcb->skb)
+ if (!rcb->skb) {
+ ret = -ENOMEM;
goto free_rx_tx;
+ }
rcb->in_use = false;
/* submit rx urb */
- if (vnt_submit_rx_urb(priv, rcb))
+ ret = vnt_submit_rx_urb(priv, rcb);
+ if (ret)
goto free_rx_tx;
}
priv->interrupt_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!priv->interrupt_urb)
+ if (!priv->interrupt_urb) {
+ ret = -ENOMEM;
goto free_rx_tx;
+ }
priv->int_buf.data_buf = kmalloc(MAX_INTERRUPT_SIZE, GFP_KERNEL);
if (!priv->int_buf.data_buf) {
- usb_free_urb(priv->interrupt_urb);
- goto free_rx_tx;
+ ret = -ENOMEM;
+ goto free_rx_tx_urb;
}
- return true;
+ return 0;
+free_rx_tx_urb:
+ usb_free_urb(priv->interrupt_urb);
free_rx_tx:
vnt_free_rx_bufs(priv);
-
free_tx:
vnt_free_tx_bufs(priv);
-
- return false;
+ return ret;
}
static void vnt_tx_80211(struct ieee80211_hw *hw,
@@ -483,28 +529,34 @@ static void vnt_tx_80211(struct ieee80211_hw *hw,
static int vnt_start(struct ieee80211_hw *hw)
{
+ int ret = 0;
struct vnt_private *priv = hw->priv;
priv->rx_buf_sz = MAX_TOTAL_SIZE_WITH_ALL_HEADERS;
- if (!vnt_alloc_bufs(priv)) {
+ ret = vnt_alloc_bufs(priv);
+ if (ret) {
dev_dbg(&priv->usb->dev, "vnt_alloc_bufs fail...\n");
- return -ENOMEM;
+ goto err;
}
clear_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags);
- if (vnt_init_registers(priv) == false) {
+ ret = vnt_init_registers(priv);
+ if (ret) {
dev_dbg(&priv->usb->dev, " init register fail\n");
goto free_all;
}
- if (vnt_key_init_table(priv))
+ ret = vnt_key_init_table(priv);
+ if (ret)
goto free_all;
priv->int_interval = 1; /* bInterval is set to 1 */
- vnt_int_start_interrupt(priv);
+ ret = vnt_int_start_interrupt(priv);
+ if (ret)
+ goto free_all;
ieee80211_wake_queues(hw);
@@ -517,8 +569,8 @@ free_all:
usb_kill_urb(priv->interrupt_urb);
usb_free_urb(priv->interrupt_urb);
-
- return -ENOMEM;
+err:
+ return ret;
}
static void vnt_stop(struct ieee80211_hw *hw)
diff --git a/drivers/staging/vt6656/rf.c b/drivers/staging/vt6656/rf.c
index 18f75dcc65d2..43237b7e1dbe 100644
--- a/drivers/staging/vt6656/rf.c
+++ b/drivers/staging/vt6656/rf.c
@@ -811,8 +811,9 @@ void vnt_rf_rssi_to_dbm(struct vnt_private *priv, u8 rssi, long *dbm)
*dbm = -1 * (a + b * 2);
}
-void vnt_rf_table_download(struct vnt_private *priv)
+int vnt_rf_table_download(struct vnt_private *priv)
{
+ int ret = 0;
u16 length1 = 0, length2 = 0, length3 = 0;
u8 *addr1 = NULL, *addr2 = NULL, *addr3 = NULL;
u16 length, value;
@@ -865,8 +866,10 @@ void vnt_rf_table_download(struct vnt_private *priv)
/* Init Table */
memcpy(array, addr1, length1);
- vnt_control_out(priv, MESSAGE_TYPE_WRITE, 0,
- MESSAGE_REQUEST_RF_INIT, length1, array);
+ ret = vnt_control_out(priv, MESSAGE_TYPE_WRITE, 0,
+ MESSAGE_REQUEST_RF_INIT, length1, array);
+ if (ret)
+ goto end;
/* Channel Table 0 */
value = 0;
@@ -878,8 +881,10 @@ void vnt_rf_table_download(struct vnt_private *priv)
memcpy(array, addr2, length);
- vnt_control_out(priv, MESSAGE_TYPE_WRITE,
- value, MESSAGE_REQUEST_RF_CH0, length, array);
+ ret = vnt_control_out(priv, MESSAGE_TYPE_WRITE, value,
+ MESSAGE_REQUEST_RF_CH0, length, array);
+ if (ret)
+ goto end;
length2 -= length;
value += length;
@@ -896,8 +901,10 @@ void vnt_rf_table_download(struct vnt_private *priv)
memcpy(array, addr3, length);
- vnt_control_out(priv, MESSAGE_TYPE_WRITE,
- value, MESSAGE_REQUEST_RF_CH1, length, array);
+ ret = vnt_control_out(priv, MESSAGE_TYPE_WRITE, value,
+ MESSAGE_REQUEST_RF_CH1, length, array);
+ if (ret)
+ goto end;
length3 -= length;
value += length;
@@ -913,8 +920,10 @@ void vnt_rf_table_download(struct vnt_private *priv)
memcpy(array, addr1, length1);
/* Init Table 2 */
- vnt_control_out(priv, MESSAGE_TYPE_WRITE,
- 0, MESSAGE_REQUEST_RF_INIT2, length1, array);
+ ret = vnt_control_out(priv, MESSAGE_TYPE_WRITE, 0,
+ MESSAGE_REQUEST_RF_INIT2, length1, array);
+ if (ret)
+ goto end;
/* Channel Table 0 */
value = 0;
@@ -926,13 +935,18 @@ void vnt_rf_table_download(struct vnt_private *priv)
memcpy(array, addr2, length);
- vnt_control_out(priv, MESSAGE_TYPE_WRITE,
- value, MESSAGE_REQUEST_RF_CH2,
- length, array);
+ ret = vnt_control_out(priv, MESSAGE_TYPE_WRITE, value,
+ MESSAGE_REQUEST_RF_CH2, length,
+ array);
+ if (ret)
+ goto end;
length2 -= length;
value += length;
addr2 += length;
}
}
+
+end:
+ return ret;
}
diff --git a/drivers/staging/vt6656/rf.h b/drivers/staging/vt6656/rf.h
index 6103117d6df5..7494546d71b8 100644
--- a/drivers/staging/vt6656/rf.h
+++ b/drivers/staging/vt6656/rf.h
@@ -44,6 +44,6 @@ int vnt_rf_write_embedded(struct vnt_private *priv, u32 data);
int vnt_rf_setpower(struct vnt_private *priv, u32 rate, u32 channel);
int vnt_rf_set_txpower(struct vnt_private *priv, u8 power, u32 rate);
void vnt_rf_rssi_to_dbm(struct vnt_private *priv, u8 rssi, long *dbm);
-void vnt_rf_table_download(struct vnt_private *priv);
+int vnt_rf_table_download(struct vnt_private *priv);
#endif /* __RF_H__ */
diff --git a/drivers/staging/vt6656/usbpipe.c b/drivers/staging/vt6656/usbpipe.c
index 5bbc56f8779e..ff351a7a0876 100644
--- a/drivers/staging/vt6656/usbpipe.c
+++ b/drivers/staging/vt6656/usbpipe.c
@@ -36,80 +36,86 @@
int vnt_control_out(struct vnt_private *priv, u8 request, u16 value,
u16 index, u16 length, u8 *buffer)
{
- int status = 0;
+ int ret = 0;
u8 *usb_buffer;
- if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags))
- return STATUS_FAILURE;
+ if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) {
+ ret = -EINVAL;
+ goto end;
+ }
mutex_lock(&priv->usb_lock);
usb_buffer = kmemdup(buffer, length, GFP_KERNEL);
if (!usb_buffer) {
- mutex_unlock(&priv->usb_lock);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto end_unlock;
}
- status = usb_control_msg(priv->usb,
- usb_sndctrlpipe(priv->usb, 0),
- request, 0x40, value,
- index, usb_buffer, length, USB_CTL_WAIT);
+ ret = usb_control_msg(priv->usb,
+ usb_sndctrlpipe(priv->usb, 0),
+ request, 0x40, value,
+ index, usb_buffer, length, USB_CTL_WAIT);
kfree(usb_buffer);
- mutex_unlock(&priv->usb_lock);
+ if (ret >= 0 && ret < (int)length)
+ ret = -EIO;
- if (status < (int)length)
- return STATUS_FAILURE;
-
- return STATUS_SUCCESS;
+end_unlock:
+ mutex_unlock(&priv->usb_lock);
+end:
+ return ret;
}
-void vnt_control_out_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 data)
+int vnt_control_out_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 data)
{
- vnt_control_out(priv, MESSAGE_TYPE_WRITE,
- reg_off, reg, sizeof(u8), &data);
+ return vnt_control_out(priv, MESSAGE_TYPE_WRITE,
+ reg_off, reg, sizeof(u8), &data);
}
int vnt_control_in(struct vnt_private *priv, u8 request, u16 value,
u16 index, u16 length, u8 *buffer)
{
- int status;
+ int ret = 0;
u8 *usb_buffer;
- if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags))
- return STATUS_FAILURE;
+ if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) {
+ ret = -EINVAL;
+ goto end;
+ }
mutex_lock(&priv->usb_lock);
usb_buffer = kmalloc(length, GFP_KERNEL);
if (!usb_buffer) {
- mutex_unlock(&priv->usb_lock);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto end_unlock;
}
- status = usb_control_msg(priv->usb,
- usb_rcvctrlpipe(priv->usb, 0),
- request, 0xc0, value,
- index, usb_buffer, length, USB_CTL_WAIT);
+ ret = usb_control_msg(priv->usb,
+ usb_rcvctrlpipe(priv->usb, 0),
+ request, 0xc0, value,
+ index, usb_buffer, length, USB_CTL_WAIT);
- if (status == length)
+ if (ret == length)
memcpy(buffer, usb_buffer, length);
kfree(usb_buffer);
- mutex_unlock(&priv->usb_lock);
+ if (ret >= 0 && ret < (int)length)
+ ret = -EIO;
- if (status < (int)length)
- return STATUS_FAILURE;
-
- return STATUS_SUCCESS;
+end_unlock:
+ mutex_unlock(&priv->usb_lock);
+end:
+ return ret;
}
-void vnt_control_in_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 *data)
+int vnt_control_in_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 *data)
{
- vnt_control_in(priv, MESSAGE_TYPE_READ,
- reg_off, reg, sizeof(u8), data);
+ return vnt_control_in(priv, MESSAGE_TYPE_READ,
+ reg_off, reg, sizeof(u8), data);
}
static void vnt_start_interrupt_urb_complete(struct urb *urb)
@@ -147,10 +153,12 @@ static void vnt_start_interrupt_urb_complete(struct urb *urb)
int vnt_start_interrupt_urb(struct vnt_private *priv)
{
- int status = STATUS_FAILURE;
+ int ret = 0;
- if (priv->int_buf.in_use)
- return STATUS_FAILURE;
+ if (priv->int_buf.in_use) {
+ ret = -EBUSY;
+ goto err;
+ }
priv->int_buf.in_use = true;
@@ -163,13 +171,18 @@ int vnt_start_interrupt_urb(struct vnt_private *priv)
priv,
priv->int_interval);
- status = usb_submit_urb(priv->interrupt_urb, GFP_ATOMIC);
- if (status) {
- dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", status);
- priv->int_buf.in_use = false;
+ ret = usb_submit_urb(priv->interrupt_urb, GFP_ATOMIC);
+ if (ret) {
+ dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", ret);
+ goto err_submit;
}
- return status;
+ return 0;
+
+err_submit:
+ priv->int_buf.in_use = false;
+err:
+ return ret;
}
static void vnt_submit_rx_urb_complete(struct urb *urb)
@@ -215,12 +228,13 @@ static void vnt_submit_rx_urb_complete(struct urb *urb)
int vnt_submit_rx_urb(struct vnt_private *priv, struct vnt_rcb *rcb)
{
- int status = 0;
+ int ret = 0;
struct urb *urb = rcb->urb;
if (!rcb->skb) {
dev_dbg(&priv->usb->dev, "rcb->skb is null\n");
- return status;
+ ret = -EINVAL;
+ goto end;
}
usb_fill_bulk_urb(urb,
@@ -231,15 +245,16 @@ int vnt_submit_rx_urb(struct vnt_private *priv, struct vnt_rcb *rcb)
vnt_submit_rx_urb_complete,
rcb);
- status = usb_submit_urb(urb, GFP_ATOMIC);
- if (status) {
- dev_dbg(&priv->usb->dev, "Submit Rx URB failed %d\n", status);
- return STATUS_FAILURE;
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (ret) {
+ dev_dbg(&priv->usb->dev, "Submit Rx URB failed %d\n", ret);
+ goto end;
}
rcb->in_use = true;
- return status;
+end:
+ return ret;
}
static void vnt_tx_context_complete(struct urb *urb)
diff --git a/drivers/staging/vt6656/usbpipe.h b/drivers/staging/vt6656/usbpipe.h
index 2910ca54886e..95147ec7b96a 100644
--- a/drivers/staging/vt6656/usbpipe.h
+++ b/drivers/staging/vt6656/usbpipe.h
@@ -23,8 +23,8 @@ int vnt_control_out(struct vnt_private *priv, u8 request, u16 value,
int vnt_control_in(struct vnt_private *priv, u8 request, u16 value,
u16 index, u16 length, u8 *buffer);
-void vnt_control_out_u8(struct vnt_private *priv, u8 reg, u8 ref_off, u8 data);
-void vnt_control_in_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 *data);
+int vnt_control_out_u8(struct vnt_private *priv, u8 reg, u8 ref_off, u8 data);
+int vnt_control_in_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 *data);
int vnt_start_interrupt_urb(struct vnt_private *priv);
int vnt_submit_rx_urb(struct vnt_private *priv, struct vnt_rcb *rcb);
diff --git a/drivers/staging/wilc1000/Makefile b/drivers/staging/wilc1000/Makefile
index 2ad3feed9725..a5a8e806b98e 100644
--- a/drivers/staging/wilc1000/Makefile
+++ b/drivers/staging/wilc1000/Makefile
@@ -5,7 +5,7 @@ ccflags-y += -DFIRMWARE_1002=\"atmel/wilc1002_firmware.bin\" \
-DFIRMWARE_1003=\"atmel/wilc1003_firmware.bin\"
wilc1000-objs := wilc_wfi_cfgoperations.o wilc_netdev.o wilc_mon.o \
- host_interface.o wilc_wlan_cfg.o wilc_wlan.o
+ wilc_hif.o wilc_wlan_cfg.o wilc_wlan.o
obj-$(CONFIG_WILC1000_SDIO) += wilc1000-sdio.o
wilc1000-sdio-objs += wilc_sdio.o
diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/wilc_hif.c
index ed15bd1bcd56..9345cabe3c93 100644
--- a/drivers/staging/wilc1000/host_interface.c
+++ b/drivers/staging/wilc1000/wilc_hif.c
@@ -6,7 +6,7 @@
#include "wilc_wfi_netdevice.h"
-#define WILC_HIF_SCAN_TIMEOUT_MS 4000
+#define WILC_HIF_SCAN_TIMEOUT_MS 5000
#define WILC_HIF_CONNECT_TIMEOUT_MS 9500
#define WILC_FALSE_FRMWR_CHANNEL 100
@@ -205,9 +205,7 @@ static int handle_scan_done(struct wilc_vif *vif, enum scan_event evt)
wid.val = (s8 *)&abort_running_scan;
wid.size = sizeof(char);
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
-
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
if (result) {
netdev_err(vif->ndev, "Failed to set abort running\n");
result = -EFAULT;
@@ -237,7 +235,7 @@ int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type,
int result = 0;
struct wid wid_list[5];
u32 index = 0;
- u32 i;
+ u32 i, scan_timeout;
u8 *buffer;
u8 valuesize = 0;
u8 *search_ssid_vals = NULL;
@@ -293,6 +291,18 @@ int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type,
wid_list[index].val = (s8 *)&scan_type;
index++;
+ if (scan_type == WILC_FW_PASSIVE_SCAN && request->duration) {
+ wid_list[index].id = WID_PASSIVE_SCAN_TIME;
+ wid_list[index].type = WID_SHORT;
+ wid_list[index].size = sizeof(u16);
+ wid_list[index].val = (s8 *)&request->duration;
+ index++;
+
+ scan_timeout = (request->duration * ch_list_len) + 500;
+ } else {
+ scan_timeout = WILC_HIF_SCAN_TIMEOUT_MS;
+ }
+
wid_list[index].id = WID_SCAN_CHANNEL_LIST;
wid_list[index].type = WID_BIN_DATA;
@@ -316,9 +326,7 @@ int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type,
hif_drv->usr_scan_req.scan_result = scan_result_fn;
hif_drv->usr_scan_req.arg = user_arg;
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,
- index,
- wilc_get_vif_idx(vif));
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, index);
if (result) {
netdev_err(vif->ndev, "Failed to send scan parameters\n");
goto error;
@@ -326,7 +334,7 @@ int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type,
hif_drv->scan_timer_vif = vif;
mod_timer(&hif_drv->scan_timer,
- jiffies + msecs_to_jiffies(WILC_HIF_SCAN_TIMEOUT_MS));
+ jiffies + msecs_to_jiffies(scan_timeout));
error:
@@ -368,9 +376,7 @@ static int wilc_send_connect_wid(struct wilc_vif *vif)
wid_list[wid_cnt].val = (u8 *)bss_param;
wid_cnt++;
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,
- wid_cnt,
- wilc_get_vif_idx(vif));
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, wid_cnt);
if (result) {
netdev_err(vif->ndev, "failed to send config packet\n");
goto error;
@@ -418,8 +424,7 @@ static void handle_connect_timeout(struct work_struct *work)
wid.val = (s8 *)&dummy_reason_code;
wid.size = sizeof(char);
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
if (result)
netdev_err(vif->ndev, "Failed to send disconnect\n");
@@ -607,8 +612,7 @@ static void host_int_get_assoc_res_info(struct wilc_vif *vif,
wid.val = assoc_resp_info;
wid.size = max_assoc_resp_info_len;
- result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
+ result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);
if (result) {
*rcvd_assoc_resp_info_len = 0;
netdev_err(vif->ndev, "Failed to send association response\n");
@@ -771,8 +775,7 @@ int wilc_disconnect(struct wilc_vif *vif)
vif->obtaining_ip = false;
wilc_set_power_mgmt(vif, 0, 0);
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
if (result) {
netdev_err(vif->ndev, "Failed to send disconnect\n");
return result;
@@ -852,10 +855,7 @@ int wilc_get_statistics(struct wilc_vif *vif, struct rf_info *stats)
wid_list[wid_cnt].val = (s8 *)&stats->tx_fail_cnt;
wid_cnt++;
- result = wilc_send_config_pkt(vif, WILC_GET_CFG, wid_list,
- wid_cnt,
- wilc_get_vif_idx(vif));
-
+ result = wilc_send_config_pkt(vif, WILC_GET_CFG, wid_list, wid_cnt);
if (result) {
netdev_err(vif->ndev, "Failed to send scan parameters\n");
return result;
@@ -938,8 +938,7 @@ static int handle_remain_on_chan(struct wilc_vif *vif,
wid.val[0] = remain_on_chan_flag;
wid.val[1] = (s8)hif_remain_ch->ch;
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
kfree(wid.val);
if (result)
return -EBUSY;
@@ -953,11 +952,8 @@ static int handle_remain_on_chan(struct wilc_vif *vif,
return 0;
}
-static void handle_listen_state_expired(struct work_struct *work)
+static int wilc_handle_roc_expired(struct wilc_vif *vif, u64 cookie)
{
- struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
- struct wilc_vif *vif = msg->vif;
- struct wilc_remain_ch *hif_remain_ch = &msg->body.remain_on_ch;
u8 remain_on_chan_flag;
struct wid wid;
int result;
@@ -969,31 +965,37 @@ static void handle_listen_state_expired(struct work_struct *work)
wid.id = WID_REMAIN_ON_CHAN;
wid.type = WID_STR;
wid.size = 2;
- wid.val = kmalloc(wid.size, GFP_KERNEL);
+ wid.val = kmalloc(wid.size, GFP_KERNEL);
if (!wid.val)
- goto free_msg;
+ return -ENOMEM;
wid.val[0] = remain_on_chan_flag;
wid.val[1] = WILC_FALSE_FRMWR_CHANNEL;
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
kfree(wid.val);
if (result != 0) {
netdev_err(vif->ndev, "Failed to set remain channel\n");
- goto free_msg;
+ return -EINVAL;
}
if (hif_drv->remain_on_ch.expired) {
hif_drv->remain_on_ch.expired(hif_drv->remain_on_ch.arg,
- hif_remain_ch->cookie);
+ cookie);
}
} else {
netdev_dbg(vif->ndev, "Not in listen state\n");
}
-free_msg:
+ return 0;
+}
+
+static void wilc_handle_listen_state_expired(struct work_struct *work)
+{
+ struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
+
+ wilc_handle_roc_expired(msg->vif, msg->body.remain_on_ch.cookie);
kfree(msg);
}
@@ -1007,7 +1009,7 @@ static void listen_timer_cb(struct timer_list *t)
del_timer(&vif->hif_drv->remain_on_ch_timer);
- msg = wilc_alloc_work(vif, handle_listen_state_expired, false);
+ msg = wilc_alloc_work(vif, wilc_handle_listen_state_expired, false);
if (IS_ERR(msg))
return;
@@ -1046,8 +1048,7 @@ static void handle_set_mcast_filter(struct work_struct *work)
if (set_mc->cnt > 0 && set_mc->mc_list)
memcpy(cur_byte, set_mc->mc_list, set_mc->cnt * ETH_ALEN);
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
if (result)
netdev_err(vif->ndev, "Failed to send setup multicast\n");
@@ -1123,8 +1124,7 @@ int wilc_remove_wep_key(struct wilc_vif *vif, u8 index)
wid.size = sizeof(char);
wid.val = &index;
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
if (result)
netdev_err(vif->ndev,
"Failed to send remove wep key config packet\n");
@@ -1140,8 +1140,7 @@ int wilc_set_wep_default_keyid(struct wilc_vif *vif, u8 index)
wid.type = WID_CHAR;
wid.size = sizeof(char);
wid.val = &index;
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
if (result)
netdev_err(vif->ndev,
"Failed to send wep default key config packet\n");
@@ -1169,8 +1168,7 @@ int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len,
wep_key->key_len = len;
memcpy(wep_key->key, key, len);
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
if (result)
netdev_err(vif->ndev,
"Failed to add wep key config packet\n");
@@ -1209,8 +1207,7 @@ int wilc_add_wep_key_bss_ap(struct wilc_vif *vif, const u8 *key, u8 len,
wep_key->key_len = len;
memcpy(wep_key->key, key, len);
result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,
- ARRAY_SIZE(wid_list),
- wilc_get_vif_idx(vif));
+ ARRAY_SIZE(wid_list));
if (result)
netdev_err(vif->ndev,
"Failed to add wep ap key config packet\n");
@@ -1257,8 +1254,7 @@ int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len,
wid_list[1].size = sizeof(*key_buf) + t_key_len;
wid_list[1].val = (u8 *)key_buf;
result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,
- ARRAY_SIZE(wid_list),
- wilc_get_vif_idx(vif));
+ ARRAY_SIZE(wid_list));
kfree(key_buf);
} else if (mode == WILC_STATION_MODE) {
struct wid wid;
@@ -1284,8 +1280,7 @@ int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len,
wid.type = WID_STR;
wid.size = sizeof(*key_buf) + t_key_len;
wid.val = (s8 *)key_buf;
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
kfree(key_buf);
}
@@ -1337,8 +1332,7 @@ int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len,
wid_list[1].val = (u8 *)gtk_key;
result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,
- ARRAY_SIZE(wid_list),
- wilc_get_vif_idx(vif));
+ ARRAY_SIZE(wid_list));
} else if (mode == WILC_STATION_MODE) {
struct wid wid;
@@ -1346,8 +1340,7 @@ int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len,
wid.type = WID_STR;
wid.size = sizeof(*gtk_key) + t_key_len;
wid.val = (u8 *)gtk_key;
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
}
kfree(gtk_key);
@@ -1363,8 +1356,7 @@ int wilc_set_pmkid_info(struct wilc_vif *vif, struct wilc_pmkid_attr *pmkid)
wid.size = (pmkid->numpmkid * sizeof(struct wilc_pmkid)) + 1;
wid.val = (u8 *)pmkid;
- return wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
+ return wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
}
int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr)
@@ -1377,8 +1369,7 @@ int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr)
wid.size = ETH_ALEN;
wid.val = mac_addr;
- result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
+ result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);
if (result)
netdev_err(vif->ndev, "Failed to get mac address\n");
@@ -1428,8 +1419,7 @@ int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel)
wid.size = sizeof(char);
wid.val = &channel;
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
if (result)
netdev_err(vif->ndev, "Failed to set channel\n");
@@ -1455,8 +1445,7 @@ int wilc_set_wfi_drv_handler(struct wilc_vif *vif, int index, u8 mode,
drv.handler = cpu_to_le32(index);
drv.mode = (ifc_id | (mode << 1));
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
- hif_drv->driver_handler_id);
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
if (result)
netdev_err(vif->ndev, "Failed to set driver handler\n");
@@ -1476,8 +1465,7 @@ int wilc_set_operation_mode(struct wilc_vif *vif, u32 mode)
op_mode.mode = cpu_to_le32(mode);
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
if (result)
netdev_err(vif->ndev, "Failed to set operation mode\n");
@@ -1497,8 +1485,7 @@ s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac, u32 *out_val)
return -ENOMEM;
ether_addr_copy(wid.val, mac);
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
kfree(wid.val);
if (result) {
netdev_err(vif->ndev, "Failed to set inactive mac\n");
@@ -1509,8 +1496,7 @@ s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac, u32 *out_val)
wid.type = WID_INT;
wid.val = (s8 *)out_val;
wid.size = sizeof(u32);
- result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
+ result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);
if (result)
netdev_err(vif->ndev, "Failed to get inactive time\n");
@@ -1531,8 +1517,7 @@ int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level)
wid.type = WID_CHAR;
wid.size = sizeof(char);
wid.val = rssi_level;
- result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
+ result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);
if (result)
netdev_err(vif->ndev, "Failed to get RSSI value\n");
@@ -1594,8 +1579,7 @@ int wilc_hif_set_cfg(struct wilc_vif *vif, struct cfg_param_attr *param)
i++;
}
- return wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,
- i, wilc_get_vif_idx(vif));
+ return wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, i);
}
static void get_periodic_rssi(struct timer_list *t)
@@ -1618,20 +1602,14 @@ int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler)
struct host_if_drv *hif_drv;
struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wilc = vif->wilc;
- int i;
hif_drv = kzalloc(sizeof(*hif_drv), GFP_KERNEL);
if (!hif_drv)
return -ENOMEM;
*hif_drv_handler = hif_drv;
- for (i = 0; i < wilc->vif_num; i++)
- if (dev == wilc->vif[i]->ndev) {
- wilc->vif[i]->hif_drv = hif_drv;
- hif_drv->driver_handler_id = i + 1;
- break;
- }
+ vif->hif_drv = hif_drv;
vif->obtaining_ip = false;
if (wilc->clients_count == 0)
@@ -1829,30 +1807,14 @@ int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie,
int wilc_listen_state_expired(struct wilc_vif *vif, u64 cookie)
{
- int result;
- struct host_if_msg *msg;
- struct host_if_drv *hif_drv = vif->hif_drv;
-
- if (!hif_drv) {
+ if (!vif->hif_drv) {
netdev_err(vif->ndev, "%s: hif driver is NULL", __func__);
return -EFAULT;
}
- del_timer(&hif_drv->remain_on_ch_timer);
-
- msg = wilc_alloc_work(vif, handle_listen_state_expired, false);
- if (IS_ERR(msg))
- return PTR_ERR(msg);
-
- msg->body.remain_on_ch.cookie = cookie;
-
- result = wilc_enqueue_work(msg);
- if (result) {
- netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
- kfree(msg);
- }
+ del_timer(&vif->hif_drv->remain_on_ch_timer);
- return result;
+ return wilc_handle_roc_expired(vif, cookie);
}
void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg)
@@ -1882,8 +1844,7 @@ void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg)
break;
}
reg_frame.frame_type = cpu_to_le16(frame_type);
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
if (result)
netdev_err(vif->ndev, "Failed to frame register\n");
}
@@ -1920,8 +1881,7 @@ int wilc_add_beacon(struct wilc_vif *vif, u32 interval, u32 dtim_period,
if (params->tail_len > 0)
memcpy(cur_byte, params->tail, params->tail_len);
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
if (result)
netdev_err(vif->ndev, "Failed to send add beacon\n");
@@ -1941,8 +1901,7 @@ int wilc_del_beacon(struct wilc_vif *vif)
wid.size = sizeof(char);
wid.val = &del_beacon;
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
if (result)
netdev_err(vif->ndev, "Failed to send delete beacon\n");
@@ -1966,8 +1925,7 @@ int wilc_add_station(struct wilc_vif *vif, const u8 *mac,
cur_byte = wid.val;
wilc_hif_pack_sta_param(cur_byte, mac, params);
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
if (result != 0)
netdev_err(vif->ndev, "Failed to send add station\n");
@@ -1993,8 +1951,7 @@ int wilc_del_station(struct wilc_vif *vif, const u8 *mac_addr)
else
ether_addr_copy(wid.val, mac_addr);
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
if (result)
netdev_err(vif->ndev, "Failed to del station\n");
@@ -2029,8 +1986,7 @@ int wilc_del_allstation(struct wilc_vif *vif, u8 mac_addr[][ETH_ALEN])
wid.size = (assoc_sta * ETH_ALEN) + 1;
wid.val = (u8 *)&del_sta;
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
if (result)
netdev_err(vif->ndev, "Failed to send delete all station\n");
@@ -2054,8 +2010,7 @@ int wilc_edit_station(struct wilc_vif *vif, const u8 *mac,
cur_byte = wid.val;
wilc_hif_pack_sta_param(cur_byte, mac, params);
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
if (result)
netdev_err(vif->ndev, "Failed to send edit station\n");
@@ -2080,8 +2035,7 @@ int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout)
wid.id = WID_POWER_MANAGEMENT;
wid.val = &power_mode;
wid.size = sizeof(char);
- result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
+ result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
if (result)
netdev_err(vif->ndev, "Failed to send power management\n");
@@ -2119,8 +2073,7 @@ int wilc_set_tx_power(struct wilc_vif *vif, u8 tx_power)
wid.val = &tx_power;
wid.size = sizeof(char);
- return wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
+ return wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
}
int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power)
@@ -2132,6 +2085,5 @@ int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power)
wid.val = tx_power;
wid.size = sizeof(char);
- return wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
+ return wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);
}
diff --git a/drivers/staging/wilc1000/host_interface.h b/drivers/staging/wilc1000/wilc_hif.h
index a907c6d33012..be1d2497cde9 100644
--- a/drivers/staging/wilc1000/host_interface.h
+++ b/drivers/staging/wilc1000/wilc_hif.h
@@ -115,7 +115,6 @@ struct wilc_rcvd_net_info {
struct ieee80211_mgmt *mgmt;
};
-
struct wilc_user_scan_req {
void (*scan_result)(enum scan_event evt,
struct wilc_rcvd_net_info *info, void *priv);
@@ -167,7 +166,6 @@ struct host_if_drv {
struct wilc_vif *remain_on_ch_timer_vif;
bool ifc_up;
- int driver_handler_id;
u8 assoc_resp[WILC_MAX_ASSOC_RESP_FRAME_SIZE];
};
diff --git a/drivers/staging/wilc1000/wilc_mon.c b/drivers/staging/wilc1000/wilc_mon.c
index 9fe19a3e1dd4..7d7933d40924 100644
--- a/drivers/staging/wilc1000/wilc_mon.c
+++ b/drivers/staging/wilc1000/wilc_mon.c
@@ -233,6 +233,7 @@ struct net_device *wilc_wfi_init_mon_interface(struct wilc *wl,
strncpy(wl->monitor_dev->name, name, IFNAMSIZ);
wl->monitor_dev->name[IFNAMSIZ - 1] = 0;
wl->monitor_dev->netdev_ops = &wilc_wfi_netdev_ops;
+ wl->monitor_dev->needs_free_netdev = true;
if (register_netdevice(wl->monitor_dev)) {
netdev_err(real_dev, "register_netdevice failed\n");
@@ -247,12 +248,14 @@ struct net_device *wilc_wfi_init_mon_interface(struct wilc *wl,
return wl->monitor_dev;
}
-void wilc_wfi_deinit_mon_interface(struct wilc *wl)
+void wilc_wfi_deinit_mon_interface(struct wilc *wl, bool rtnl_locked)
{
if (!wl->monitor_dev)
return;
- unregister_netdev(wl->monitor_dev);
- free_netdev(wl->monitor_dev);
+ if (rtnl_locked)
+ unregister_netdevice(wl->monitor_dev);
+ else
+ unregister_netdev(wl->monitor_dev);
wl->monitor_dev = NULL;
}
diff --git a/drivers/staging/wilc1000/wilc_netdev.c b/drivers/staging/wilc1000/wilc_netdev.c
index ba78c08a17f1..565e2b5d0616 100644
--- a/drivers/staging/wilc1000/wilc_netdev.c
+++ b/drivers/staging/wilc1000/wilc_netdev.c
@@ -97,22 +97,29 @@ static struct net_device *get_if_handler(struct wilc *wilc, u8 *mac_header)
{
u8 *bssid, *bssid1;
int i = 0;
+ struct net_device *ndev = NULL;
bssid = mac_header + 10;
bssid1 = mac_header + 4;
+ mutex_lock(&wilc->vif_mutex);
for (i = 0; i < wilc->vif_num; i++) {
if (wilc->vif[i]->mode == WILC_STATION_MODE)
if (ether_addr_equal_unaligned(bssid,
- wilc->vif[i]->bssid))
- return wilc->vif[i]->ndev;
+ wilc->vif[i]->bssid)) {
+ ndev = wilc->vif[i]->ndev;
+ goto out;
+ }
if (wilc->vif[i]->mode == WILC_AP_MODE)
if (ether_addr_equal_unaligned(bssid1,
- wilc->vif[i]->bssid))
- return wilc->vif[i]->ndev;
+ wilc->vif[i]->bssid)) {
+ ndev = wilc->vif[i]->ndev;
+ goto out;
+ }
}
-
- return NULL;
+out:
+ mutex_unlock(&wilc->vif_mutex);
+ return ndev;
}
void wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode)
@@ -143,9 +150,7 @@ static int wilc_txq_task(void *vp)
{
int ret;
u32 txq_count;
- struct net_device *dev = vp;
- struct wilc_vif *vif = netdev_priv(dev);
- struct wilc *wl = vif->wilc;
+ struct wilc *wl = vp;
complete(&wl->txq_thread_started);
while (1) {
@@ -159,14 +164,18 @@ static int wilc_txq_task(void *vp)
break;
}
do {
- ret = wilc_wlan_handle_txq(dev, &txq_count);
+ ret = wilc_wlan_handle_txq(wl, &txq_count);
if (txq_count < FLOW_CONTROL_LOWER_THRESHOLD) {
- if (wl->vif[0]->mac_opened &&
- netif_queue_stopped(wl->vif[0]->ndev))
- netif_wake_queue(wl->vif[0]->ndev);
- if (wl->vif[1]->mac_opened &&
- netif_queue_stopped(wl->vif[1]->ndev))
- netif_wake_queue(wl->vif[1]->ndev);
+ int i;
+ struct wilc_vif *ifc;
+
+ mutex_lock(&wl->vif_mutex);
+ for (i = 0; i < wl->vif_num; i++) {
+ ifc = wl->vif[i];
+ if (ifc->mac_opened && ifc->ndev)
+ netif_wake_queue(ifc->ndev);
+ }
+ mutex_unlock(&wl->vif_mutex);
}
} while (ret == -ENOBUFS && !wl->close);
}
@@ -245,14 +254,13 @@ static int wilc1000_firmware_download(struct net_device *dev)
static int wilc_init_fw_config(struct net_device *dev, struct wilc_vif *vif)
{
- struct wilc_priv *priv;
+ struct wilc_priv *priv = &vif->priv;
struct host_if_drv *hif_drv;
u8 b;
u16 hw;
u32 w;
netdev_dbg(dev, "Start configuring Firmware\n");
- priv = wiphy_priv(dev->ieee80211_ptr->wiphy);
hif_drv = (struct host_if_drv *)priv->hif_drv;
netdev_dbg(dev, "Host = %p\n", hif_drv);
@@ -424,6 +432,7 @@ static void wlan_deinit_locks(struct net_device *dev)
mutex_destroy(&wilc->rxq_cs);
mutex_destroy(&wilc->cfg_cmd_lock);
mutex_destroy(&wilc->txq_add_to_head_cs);
+ mutex_destroy(&wilc->vif_mutex);
}
static void wlan_deinitialize_threads(struct net_device *dev)
@@ -477,31 +486,12 @@ static void wilc_wlan_deinitialize(struct net_device *dev)
}
}
-static void wlan_init_locks(struct net_device *dev)
-{
- struct wilc_vif *vif = netdev_priv(dev);
- struct wilc *wl = vif->wilc;
-
- mutex_init(&wl->hif_cs);
- mutex_init(&wl->rxq_cs);
- mutex_init(&wl->cfg_cmd_lock);
-
- spin_lock_init(&wl->txq_spinlock);
- mutex_init(&wl->txq_add_to_head_cs);
-
- init_completion(&wl->txq_event);
-
- init_completion(&wl->cfg_event);
- init_completion(&wl->sync_event);
- init_completion(&wl->txq_thread_started);
-}
-
static int wlan_initialize_threads(struct net_device *dev)
{
struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wilc = vif->wilc;
- wilc->txq_thread = kthread_run(wilc_txq_task, (void *)dev,
+ wilc->txq_thread = kthread_run(wilc_txq_task, (void *)wilc,
"K_TXQ_TASK");
if (IS_ERR(wilc->txq_thread)) {
netdev_err(dev, "couldn't create TXQ thread\n");
@@ -513,6 +503,12 @@ static int wlan_initialize_threads(struct net_device *dev)
return 0;
}
+static int dev_state_ev_handler(struct notifier_block *this,
+ unsigned long event, void *ptr);
+static struct notifier_block g_dev_notifier = {
+ .notifier_call = dev_state_ev_handler
+};
+
static int wilc_wlan_initialize(struct net_device *dev, struct wilc_vif *vif)
{
int ret = 0;
@@ -522,23 +518,19 @@ static int wilc_wlan_initialize(struct net_device *dev, struct wilc_vif *vif)
wl->mac_status = WILC_MAC_STATUS_INIT;
wl->close = 0;
- wlan_init_locks(dev);
-
ret = wilc_wlan_init(dev);
+ if (ret < 0)
+ return -EIO;
+
+ ret = wlan_initialize_threads(dev);
if (ret < 0) {
ret = -EIO;
- goto fail_locks;
+ goto fail_wilc_wlan;
}
if (wl->gpio_irq && init_irq(dev)) {
ret = -EIO;
- goto fail_locks;
- }
-
- ret = wlan_initialize_threads(dev);
- if (ret < 0) {
- ret = -EIO;
- goto fail_wilc_wlan;
+ goto fail_threads;
}
if (!wl->dev_irq_num &&
@@ -582,7 +574,7 @@ static int wilc_wlan_initialize(struct net_device *dev, struct wilc_vif *vif)
ret = -EIO;
goto fail_fw_start;
}
-
+ register_inetaddr_notifier(&g_dev_notifier);
wl->initialized = true;
return 0;
@@ -596,12 +588,10 @@ fail_irq_enable:
fail_irq_init:
if (wl->dev_irq_num)
deinit_irq(dev);
-
+fail_threads:
wlan_deinitialize_threads(dev);
fail_wilc_wlan:
wilc_wlan_cleanup(dev);
-fail_locks:
- wlan_deinit_locks(dev);
netdev_err(dev, "WLAN initialization FAILED\n");
} else {
netdev_dbg(dev, "wilc1000 already initialized\n");
@@ -624,7 +614,6 @@ static int wilc_mac_open(struct net_device *ndev)
struct wilc_priv *priv = wdev_priv(vif->ndev->ieee80211_ptr);
unsigned char mac_add[ETH_ALEN] = {0};
int ret = 0;
- int i = 0;
if (!wl || !wl->dev) {
netdev_err(ndev, "device not ready\n");
@@ -643,19 +632,13 @@ static int wilc_mac_open(struct net_device *ndev)
return ret;
}
- for (i = 0; i < wl->vif_num; i++) {
- if (ndev == wl->vif[i]->ndev) {
- wilc_set_wfi_drv_handler(vif, wilc_get_vif_idx(vif),
- vif->iftype, vif->ifc_id);
- wilc_set_operation_mode(vif, vif->iftype);
- break;
- }
- }
+ wilc_set_wfi_drv_handler(vif, wilc_get_vif_idx(vif), vif->iftype,
+ vif->idx);
+ wilc_set_operation_mode(vif, vif->iftype);
wilc_get_mac_address(vif, mac_add);
netdev_dbg(ndev, "Mac address: %pM\n", mac_add);
- memcpy(wl->vif[i]->src_addr, mac_add, ETH_ALEN);
- memcpy(ndev->dev_addr, wl->vif[i]->src_addr, ETH_ALEN);
+ ether_addr_copy(ndev->dev_addr, mac_add);
if (!is_valid_ether_addr(ndev->dev_addr)) {
netdev_err(ndev, "Wrong MAC address\n");
@@ -758,16 +741,19 @@ netdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *ndev)
vif->netstats.tx_packets++;
vif->netstats.tx_bytes += tx_data->size;
- tx_data->bssid = wilc->vif[vif->idx]->bssid;
queue_count = wilc_wlan_txq_add_net_pkt(ndev, (void *)tx_data,
tx_data->buff, tx_data->size,
wilc_tx_complete);
if (queue_count > FLOW_CONTROL_UPPER_THRESHOLD) {
- if (wilc->vif[0]->mac_opened)
- netif_stop_queue(wilc->vif[0]->ndev);
- if (wilc->vif[1]->mac_opened)
- netif_stop_queue(wilc->vif[1]->ndev);
+ int i;
+
+ mutex_lock(&wilc->vif_mutex);
+ for (i = 0; i < wilc->vif_num; i++) {
+ if (wilc->vif[i]->mac_opened)
+ netif_stop_queue(wilc->vif[i]->ndev);
+ }
+ mutex_unlock(&wilc->vif_mutex);
}
return 0;
@@ -794,6 +780,7 @@ static int wilc_mac_close(struct net_device *ndev)
if (wl->open_ifcs == 0) {
netdev_dbg(ndev, "Deinitializing wilc1000\n");
wl->close = 1;
+ unregister_inetaddr_notifier(&g_dev_notifier);
wilc_wlan_deinitialize(ndev);
}
@@ -848,18 +835,23 @@ void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size)
int i = 0;
struct wilc_vif *vif;
+ mutex_lock(&wilc->vif_mutex);
for (i = 0; i < wilc->vif_num; i++) {
+ u16 type = le16_to_cpup((__le16 *)buff);
+
vif = netdev_priv(wilc->vif[i]->ndev);
+ if ((type == vif->frame_reg[0].type && vif->frame_reg[0].reg) ||
+ (type == vif->frame_reg[1].type && vif->frame_reg[1].reg)) {
+ wilc_wfi_p2p_rx(vif, buff, size);
+ break;
+ }
+
if (vif->monitor_flag) {
wilc_wfi_monitor_rx(wilc->monitor_dev, buff, size);
- return;
+ break;
}
}
-
- vif = netdev_priv(wilc->vif[1]->ndev);
- if ((buff[0] == vif->frame_reg[0].type && vif->frame_reg[0].reg) ||
- (buff[0] == vif->frame_reg[1].type && vif->frame_reg[1].reg))
- wilc_wfi_p2p_rx(wilc->vif[1]->ndev, buff, size);
+ mutex_unlock(&wilc->vif_mutex);
}
static const struct net_device_ops wilc_netdev_ops = {
@@ -890,14 +882,10 @@ static int dev_state_ev_handler(struct notifier_block *this,
if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy)
return NOTIFY_DONE;
- priv = wiphy_priv(dev->ieee80211_ptr->wiphy);
- if (!priv)
- return NOTIFY_DONE;
+ vif = netdev_priv(dev);
+ priv = &vif->priv;
hif_drv = (struct host_if_drv *)priv->hif_drv;
- vif = netdev_priv(dev);
- if (!vif || !hif_drv)
- return NOTIFY_DONE;
switch (event) {
case NETDEV_UP:
@@ -932,10 +920,6 @@ static int dev_state_ev_handler(struct notifier_block *this,
return NOTIFY_DONE;
}
-static struct notifier_block g_dev_notifier = {
- .notifier_call = dev_state_ev_handler
-};
-
void wilc_netdev_cleanup(struct wilc *wilc)
{
int i;
@@ -943,137 +927,71 @@ void wilc_netdev_cleanup(struct wilc *wilc)
if (!wilc)
return;
- if (wilc->vif[0]->ndev || wilc->vif[1]->ndev)
- unregister_inetaddr_notifier(&g_dev_notifier);
-
if (wilc->firmware) {
release_firmware(wilc->firmware);
wilc->firmware = NULL;
}
- for (i = 0; i < WILC_NUM_CONCURRENT_IFC; i++) {
- if (wilc->vif[i] && wilc->vif[i]->ndev) {
+ for (i = 0; i < wilc->vif_num; i++) {
+ if (wilc->vif[i] && wilc->vif[i]->ndev)
unregister_netdev(wilc->vif[i]->ndev);
- wilc_free_wiphy(wilc->vif[i]->ndev);
- free_netdev(wilc->vif[i]->ndev);
- }
}
- wilc_wfi_deinit_mon_interface(wilc);
+ wilc_wfi_deinit_mon_interface(wilc, false);
flush_workqueue(wilc->hif_workqueue);
destroy_workqueue(wilc->hif_workqueue);
wilc_wlan_cfg_deinit(wilc);
kfree(wilc->bus_data);
- kfree(wilc);
+ wiphy_unregister(wilc->wiphy);
+ wiphy_free(wilc->wiphy);
}
EXPORT_SYMBOL_GPL(wilc_netdev_cleanup);
-int wilc_netdev_init(struct wilc **wilc, struct device *dev, int io_type,
- const struct wilc_hif_func *ops)
+struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name,
+ int vif_type, enum nl80211_iftype type,
+ bool rtnl_locked)
{
- int i, ret;
- struct wilc_vif *vif;
struct net_device *ndev;
- struct wilc *wl;
-
- wl = kzalloc(sizeof(*wl), GFP_KERNEL);
- if (!wl)
- return -ENOMEM;
-
- ret = wilc_wlan_cfg_init(wl);
- if (ret)
- goto free_wl;
-
- *wilc = wl;
- wl->io_type = io_type;
- wl->hif_func = ops;
- wl->enable_ps = true;
- wl->chip_ps_state = WILC_CHIP_WAKEDUP;
- INIT_LIST_HEAD(&wl->txq_head.list);
- INIT_LIST_HEAD(&wl->rxq_head.list);
-
- wl->hif_workqueue = create_singlethread_workqueue("WILC_wq");
- if (!wl->hif_workqueue) {
- ret = -ENOMEM;
- goto free_cfg;
- }
-
- register_inetaddr_notifier(&g_dev_notifier);
-
- for (i = 0; i < WILC_NUM_CONCURRENT_IFC; i++) {
- struct wireless_dev *wdev;
+ struct wilc_vif *vif;
+ int ret;
- ndev = alloc_etherdev(sizeof(struct wilc_vif));
- if (!ndev) {
- ret = -ENOMEM;
- goto free_ndev;
- }
+ ndev = alloc_etherdev(sizeof(*vif));
+ if (!ndev)
+ return ERR_PTR(-ENOMEM);
- vif = netdev_priv(ndev);
- memset(vif, 0, sizeof(struct wilc_vif));
+ vif = netdev_priv(ndev);
+ ndev->ieee80211_ptr = &vif->priv.wdev;
+ strcpy(ndev->name, name);
+ vif->wilc = wl;
+ vif->ndev = ndev;
+ ndev->ml_priv = vif;
- if (i == 0) {
- strcpy(ndev->name, "wlan%d");
- vif->ifc_id = 1;
- } else {
- strcpy(ndev->name, "p2p%d");
- vif->ifc_id = 0;
- }
- vif->wilc = *wilc;
- vif->ndev = ndev;
- wl->vif[i] = vif;
- wl->vif_num = i + 1;
- vif->idx = i;
-
- ndev->netdev_ops = &wilc_netdev_ops;
-
- wdev = wilc_create_wiphy(ndev, dev);
- if (!wdev) {
- netdev_err(ndev, "Can't register WILC Wiphy\n");
- ret = -ENOMEM;
- goto free_ndev;
- }
+ ndev->netdev_ops = &wilc_netdev_ops;
- SET_NETDEV_DEV(ndev, dev);
+ SET_NETDEV_DEV(ndev, wiphy_dev(wl->wiphy));
- vif->ndev->ieee80211_ptr = wdev;
- vif->ndev->ml_priv = vif;
- wdev->netdev = vif->ndev;
- vif->netstats.rx_packets = 0;
- vif->netstats.tx_packets = 0;
- vif->netstats.rx_bytes = 0;
- vif->netstats.tx_bytes = 0;
+ vif->priv.wdev.wiphy = wl->wiphy;
+ vif->priv.wdev.netdev = ndev;
+ vif->priv.wdev.iftype = type;
+ vif->priv.dev = ndev;
+ if (rtnl_locked)
+ ret = register_netdevice(ndev);
+ else
ret = register_netdev(ndev);
- if (ret)
- goto free_ndev;
- vif->iftype = WILC_STATION_MODE;
- vif->mac_opened = 0;
+ if (ret) {
+ free_netdev(ndev);
+ return ERR_PTR(-EFAULT);
}
- return 0;
-
-free_ndev:
- for (; i >= 0; i--) {
- if (wl->vif[i]) {
- if (wl->vif[i]->iftype == WILC_STATION_MODE)
- unregister_netdev(wl->vif[i]->ndev);
-
- if (wl->vif[i]->ndev) {
- wilc_free_wiphy(wl->vif[i]->ndev);
- free_netdev(wl->vif[i]->ndev);
- }
- }
- }
- unregister_inetaddr_notifier(&g_dev_notifier);
- destroy_workqueue(wl->hif_workqueue);
-free_cfg:
- wilc_wlan_cfg_deinit(wl);
-free_wl:
- kfree(wl);
- return ret;
+ ndev->needs_free_netdev = true;
+ vif->iftype = vif_type;
+ vif->wilc->vif[wl->vif_num] = vif;
+ vif->idx = wl->vif_num;
+ wl->vif_num += 1;
+ vif->mac_opened = 0;
+ return vif;
}
-EXPORT_SYMBOL_GPL(wilc_netdev_init);
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/wilc1000/wilc_sdio.c b/drivers/staging/wilc1000/wilc_sdio.c
index b789c57d7e80..4c1c81fed11f 100644
--- a/drivers/staging/wilc1000/wilc_sdio.c
+++ b/drivers/staging/wilc1000/wilc_sdio.c
@@ -8,6 +8,7 @@
#include <linux/mmc/host.h>
#include "wilc_wfi_netdevice.h"
+#include "wilc_wfi_cfgoperations.h"
#define SDIO_MODALIAS "wilc1000_sdio"
@@ -139,11 +140,9 @@ static int wilc_sdio_probe(struct sdio_func *func,
}
}
- dev_dbg(&func->dev, "Initializing netdev\n");
- ret = wilc_netdev_init(&wilc, &func->dev, WILC_HIF_SDIO,
- &wilc_hif_sdio);
+ ret = wilc_cfg80211_init(&wilc, &func->dev, WILC_HIF_SDIO,
+ &wilc_hif_sdio);
if (ret) {
- dev_err(&func->dev, "Couldn't initialize netdev\n");
kfree(sdio_priv);
return ret;
}
diff --git a/drivers/staging/wilc1000/wilc_spi.c b/drivers/staging/wilc1000/wilc_spi.c
index d8910bf9cb75..3c1ae9e9f9aa 100644
--- a/drivers/staging/wilc1000/wilc_spi.c
+++ b/drivers/staging/wilc1000/wilc_spi.c
@@ -7,6 +7,7 @@
#include <linux/spi/spi.h>
#include "wilc_wfi_netdevice.h"
+#include "wilc_wfi_cfgoperations.h"
struct wilc_spi {
int crc_off;
@@ -120,7 +121,7 @@ static int wilc_bus_probe(struct spi_device *spi)
dev_err(&spi->dev, "failed to get the irq gpio\n");
}
- ret = wilc_netdev_init(&wilc, NULL, WILC_HIF_SPI, &wilc_hif_spi);
+ ret = wilc_cfg80211_init(&wilc, &spi->dev, WILC_HIF_SPI, &wilc_hif_spi);
if (ret) {
kfree(spi_priv);
return ret;
diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c
index f6825727bf77..d72fdd333050 100644
--- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c
+++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c
@@ -183,47 +183,67 @@ static void cfg_connect_result(enum conn_event conn_disconn_evt, u8 mac_status,
eth_zero_addr(priv->associated_bss);
wilc_wlan_set_bssid(priv->dev, NULL, WILC_STATION_MODE);
- if (vif->iftype != WILC_CLIENT_MODE)
+ if (vif->iftype != WILC_CLIENT_MODE) {
wl->sta_ch = WILC_INVALID_CHANNEL;
-
- if (wfi_drv->ifc_up && dev == wl->vif[1]->ndev)
- reason = 3;
- else if (!wfi_drv->ifc_up && dev == wl->vif[1]->ndev)
- reason = 1;
+ } else {
+ if (wfi_drv->ifc_up)
+ reason = 3;
+ else
+ reason = 1;
+ }
cfg80211_disconnected(dev, reason, NULL, 0, false, GFP_KERNEL);
}
}
+static struct wilc_vif *wilc_get_wl_to_vif(struct wilc *wl)
+{
+ int i;
+
+ for (i = 0; i < wl->vif_num; i++)
+ if (wl->vif[i])
+ return wl->vif[i];
+
+ return ERR_PTR(-EINVAL);
+}
+
static int set_channel(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef)
{
- u32 channelnum = 0;
- struct wilc_priv *priv = wiphy_priv(wiphy);
- struct wilc_vif *vif = netdev_priv(priv->dev);
- int result = 0;
+ struct wilc *wl = wiphy_priv(wiphy);
+ struct wilc_vif *vif;
+ u32 channelnum;
+ int result;
+
+ mutex_lock(&wl->vif_mutex);
+ vif = wilc_get_wl_to_vif(wl);
+ if (IS_ERR(vif)) {
+ mutex_unlock(&wl->vif_mutex);
+ return PTR_ERR(vif);
+ }
channelnum = ieee80211_frequency_to_channel(chandef->chan->center_freq);
- vif->wilc->op_ch = channelnum;
+ wl->op_ch = channelnum;
result = wilc_set_mac_chnl_num(vif, channelnum);
+ if (result)
+ netdev_err(vif->ndev, "Error in setting channel\n");
- if (result != 0)
- netdev_err(priv->dev, "Error in setting channel\n");
-
+ mutex_unlock(&wl->vif_mutex);
return result;
}
static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
{
- struct wilc_priv *priv = wiphy_priv(wiphy);
- struct wilc_vif *vif = netdev_priv(priv->dev);
+ struct wilc_vif *vif = netdev_priv(request->wdev->netdev);
+ struct wilc_priv *priv = &vif->priv;
u32 i;
int ret = 0;
u8 scan_ch_list[WILC_MAX_NUM_SCANNED_CH];
+ u8 scan_type;
if (request->n_channels > WILC_MAX_NUM_SCANNED_CH) {
- netdev_err(priv->dev, "Requested scanned channels over\n");
+ netdev_err(vif->ndev, "Requested scanned channels over\n");
return -EINVAL;
}
@@ -235,9 +255,14 @@ static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
scan_ch_list[i] = ieee80211_frequency_to_channel(freq);
}
- ret = wilc_scan(vif, WILC_FW_USER_SCAN, WILC_FW_ACTIVE_SCAN,
- scan_ch_list, request->n_channels, cfg_scan_result,
- (void *)priv, request);
+ if (request->n_ssids)
+ scan_type = WILC_FW_ACTIVE_SCAN;
+ else
+ scan_type = WILC_FW_PASSIVE_SCAN;
+
+ ret = wilc_scan(vif, WILC_FW_USER_SCAN, scan_type, scan_ch_list,
+ request->n_channels, cfg_scan_result, (void *)priv,
+ request);
if (ret) {
priv->scan_req = NULL;
@@ -250,8 +275,8 @@ static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
static int connect(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_connect_params *sme)
{
- struct wilc_priv *priv = wiphy_priv(wiphy);
- struct wilc_vif *vif = netdev_priv(priv->dev);
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc_priv *priv = &vif->priv;
struct host_if_drv *wfi_drv = priv->hif_drv;
int ret;
u32 i;
@@ -404,8 +429,8 @@ out_error:
static int disconnect(struct wiphy *wiphy, struct net_device *dev,
u16 reason_code)
{
- struct wilc_priv *priv = wiphy_priv(wiphy);
- struct wilc_vif *vif = netdev_priv(priv->dev);
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc_priv *priv = &vif->priv;
struct wilc *wilc = vif->wilc;
int ret;
@@ -495,17 +520,17 @@ static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
{
int ret = 0, keylen = params->key_len;
- struct wilc_priv *priv = wiphy_priv(wiphy);
const u8 *rx_mic = NULL;
const u8 *tx_mic = NULL;
u8 mode = WILC_FW_SEC_NO;
u8 op_mode;
struct wilc_vif *vif = netdev_priv(netdev);
+ struct wilc_priv *priv = &vif->priv;
switch (params->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
- if (priv->wdev->iftype == NL80211_IFTYPE_AP) {
+ if (priv->wdev.iftype == NL80211_IFTYPE_AP) {
wilc_wfi_cfg_copy_wep_info(priv, key_index, params);
if (params->cipher == WLAN_CIPHER_SUITE_WEP40)
@@ -532,8 +557,8 @@ static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
case WLAN_CIPHER_SUITE_TKIP:
case WLAN_CIPHER_SUITE_CCMP:
- if (priv->wdev->iftype == NL80211_IFTYPE_AP ||
- priv->wdev->iftype == NL80211_IFTYPE_P2P_GO) {
+ if (priv->wdev.iftype == NL80211_IFTYPE_AP ||
+ priv->wdev.iftype == NL80211_IFTYPE_P2P_GO) {
struct wilc_wfi_key *key;
ret = wilc_wfi_cfg_allocate_wpa_entry(priv, key_index);
@@ -605,9 +630,9 @@ static int del_key(struct wiphy *wiphy, struct net_device *netdev,
bool pairwise,
const u8 *mac_addr)
{
- struct wilc_priv *priv = wiphy_priv(wiphy);
+ struct wilc *wl = wiphy_priv(wiphy);
struct wilc_vif *vif = netdev_priv(netdev);
- struct wilc *wl = vif->wilc;
+ struct wilc_priv *priv = &vif->priv;
if (netdev == wl->vif[0]->ndev) {
if (priv->wilc_gtk[key_index]) {
@@ -644,7 +669,8 @@ static int get_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
bool pairwise, const u8 *mac_addr, void *cookie,
void (*callback)(void *cookie, struct key_params *))
{
- struct wilc_priv *priv = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(netdev);
+ struct wilc_priv *priv = &vif->priv;
struct key_params key_params;
if (!pairwise) {
@@ -669,8 +695,7 @@ static int get_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
static int set_default_key(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index, bool unicast, bool multicast)
{
- struct wilc_priv *priv = wiphy_priv(wiphy);
- struct wilc_vif *vif = netdev_priv(priv->dev);
+ struct wilc_vif *vif = netdev_priv(netdev);
wilc_set_wep_default_keyid(vif, key_index);
@@ -680,8 +705,8 @@ static int set_default_key(struct wiphy *wiphy, struct net_device *netdev,
static int get_station(struct wiphy *wiphy, struct net_device *dev,
const u8 *mac, struct station_info *sinfo)
{
- struct wilc_priv *priv = wiphy_priv(wiphy);
struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc_priv *priv = &vif->priv;
u32 i = 0;
u32 associatedsta = ~0;
u32 inactive_time = 0;
@@ -737,13 +762,35 @@ static int change_bss(struct wiphy *wiphy, struct net_device *dev,
return 0;
}
+struct wilc_vif *wilc_get_interface(struct wilc *wl)
+{
+ int i;
+ struct wilc_vif *vif = NULL;
+
+ mutex_lock(&wl->vif_mutex);
+ for (i = 0; i < wl->vif_num; i++) {
+ if (wl->vif[i]) {
+ vif = wl->vif[i];
+ break;
+ }
+ }
+ mutex_unlock(&wl->vif_mutex);
+ return vif;
+}
+
static int set_wiphy_params(struct wiphy *wiphy, u32 changed)
{
int ret;
struct cfg_param_attr cfg_param_val;
- struct wilc_priv *priv = wiphy_priv(wiphy);
- struct wilc_vif *vif = netdev_priv(priv->dev);
+ struct wilc *wl = wiphy_priv(wiphy);
+ struct wilc_vif *vif;
+ struct wilc_priv *priv;
+
+ vif = wilc_get_interface(wl);
+ if (!vif)
+ return -EINVAL;
+ priv = &vif->priv;
cfg_param_val.flag = 0;
if (changed & WIPHY_PARAM_RETRY_SHORT) {
@@ -798,8 +845,8 @@ static int set_wiphy_params(struct wiphy *wiphy, u32 changed)
static int set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
struct cfg80211_pmksa *pmksa)
{
- struct wilc_priv *priv = wiphy_priv(wiphy);
- struct wilc_vif *vif = netdev_priv(priv->dev);
+ struct wilc_vif *vif = netdev_priv(netdev);
+ struct wilc_priv *priv = &vif->priv;
u32 i;
int ret = 0;
u8 flag = 0;
@@ -834,7 +881,8 @@ static int del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
{
u32 i;
int ret = 0;
- struct wilc_priv *priv = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(netdev);
+ struct wilc_priv *priv = &vif->priv;
for (i = 0; i < priv->pmkid_list.numpmkid; i++) {
if (!memcmp(pmksa->bssid, priv->pmkid_list.pmkidlist[i].bssid,
@@ -864,9 +912,9 @@ static int del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
static int flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
{
- struct wilc_priv *priv = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(netdev);
- memset(&priv->pmkid_list, 0, sizeof(struct wilc_pmkid_attr));
+ memset(&vif->priv.pmkid_list, 0, sizeof(struct wilc_pmkid_attr));
return 0;
}
@@ -981,12 +1029,11 @@ static void wilc_wfi_cfg_parse_rx_vendor_spec(struct wilc_priv *priv, u8 *buff,
}
}
-void wilc_wfi_p2p_rx(struct net_device *dev, u8 *buff, u32 size)
+void wilc_wfi_p2p_rx(struct wilc_vif *vif, u8 *buff, u32 size)
{
- struct wilc_priv *priv = wiphy_priv(dev->ieee80211_ptr->wiphy);
- struct host_if_drv *wfi_drv = priv->hif_drv;
- struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wl = vif->wilc;
+ struct wilc_priv *priv = &vif->priv;
+ struct host_if_drv *wfi_drv = priv->hif_drv;
u32 header, pkt_offset;
s32 freq;
__le16 fc;
@@ -1002,8 +1049,8 @@ void wilc_wfi_p2p_rx(struct net_device *dev, u8 *buff, u32 size)
pkt_offset & IS_MGMT_STATUS_SUCCES)
ack = true;
- cfg80211_mgmt_tx_status(priv->wdev, priv->tx_cookie, buff, size,
- ack, GFP_KERNEL);
+ cfg80211_mgmt_tx_status(&priv->wdev, priv->tx_cookie, buff,
+ size, ack, GFP_KERNEL);
return;
}
@@ -1011,13 +1058,13 @@ void wilc_wfi_p2p_rx(struct net_device *dev, u8 *buff, u32 size)
fc = ((struct ieee80211_hdr *)buff)->frame_control;
if (!ieee80211_is_action(fc)) {
- cfg80211_rx_mgmt(priv->wdev, freq, 0, buff, size, 0);
+ cfg80211_rx_mgmt(&priv->wdev, freq, 0, buff, size, 0);
return;
}
if (priv->cfg_scanning &&
time_after_eq(jiffies, (unsigned long)wfi_drv->p2p_timeout)) {
- netdev_dbg(dev, "Receiving action wrong ch\n");
+ netdev_dbg(vif->ndev, "Receiving action wrong ch\n");
return;
}
if (buff[ACTION_CAT_ID] == PUB_ACTION_ATTR_ID) {
@@ -1040,14 +1087,14 @@ void wilc_wfi_p2p_rx(struct net_device *dev, u8 *buff, u32 size)
break;
default:
- netdev_dbg(dev,
+ netdev_dbg(vif->ndev,
"%s: Not handled action frame type:%x\n",
__func__, buff[ACTION_SUBTYPE_ID]);
break;
}
}
- cfg80211_rx_mgmt(priv->wdev, freq, 0, buff, size, 0);
+ cfg80211_rx_mgmt(&priv->wdev, freq, 0, buff, size, 0);
}
static void wilc_wfi_mgmt_tx_complete(void *priv, int status)
@@ -1060,7 +1107,8 @@ static void wilc_wfi_mgmt_tx_complete(void *priv, int status)
static void wilc_wfi_remain_on_channel_expired(void *data, u64 cookie)
{
- struct wilc_priv *priv = data;
+ struct wilc_vif *vif = data;
+ struct wilc_priv *priv = &vif->priv;
struct wilc_wfi_p2p_listen_params *params = &priv->remain_on_ch_params;
if (cookie != params->listen_cookie)
@@ -1068,7 +1116,7 @@ static void wilc_wfi_remain_on_channel_expired(void *data, u64 cookie)
priv->p2p_listen_state = false;
- cfg80211_remain_on_channel_expired(priv->wdev, params->listen_cookie,
+ cfg80211_remain_on_channel_expired(&priv->wdev, params->listen_cookie,
params->listen_ch, GFP_KERNEL);
}
@@ -1078,8 +1126,8 @@ static int remain_on_channel(struct wiphy *wiphy,
unsigned int duration, u64 *cookie)
{
int ret = 0;
- struct wilc_priv *priv = wiphy_priv(wiphy);
- struct wilc_vif *vif = netdev_priv(priv->dev);
+ struct wilc_vif *vif = netdev_priv(wdev->netdev);
+ struct wilc_priv *priv = &vif->priv;
u64 id;
if (wdev->iftype == NL80211_IFTYPE_AP) {
@@ -1093,7 +1141,7 @@ static int remain_on_channel(struct wiphy *wiphy,
ret = wilc_remain_on_channel(vif, id, duration, chan->hw_value,
wilc_wfi_remain_on_channel_expired,
- (void *)priv);
+ (void *)vif);
if (ret)
return ret;
@@ -1116,8 +1164,8 @@ static int cancel_remain_on_channel(struct wiphy *wiphy,
struct wireless_dev *wdev,
u64 cookie)
{
- struct wilc_priv *priv = wiphy_priv(wiphy);
- struct wilc_vif *vif = netdev_priv(priv->dev);
+ struct wilc_vif *vif = netdev_priv(wdev->netdev);
+ struct wilc_priv *priv = &vif->priv;
if (cookie != priv->remain_on_ch_params.listen_cookie)
return -ENOENT;
@@ -1187,9 +1235,9 @@ static int mgmt_tx(struct wiphy *wiphy,
size_t len = params->len;
const struct ieee80211_mgmt *mgmt;
struct wilc_p2p_mgmt_data *mgmt_tx;
- struct wilc_priv *priv = wiphy_priv(wiphy);
- struct host_if_drv *wfi_drv = priv->hif_drv;
struct wilc_vif *vif = netdev_priv(wdev->netdev);
+ struct wilc_priv *priv = &vif->priv;
+ struct host_if_drv *wfi_drv = priv->hif_drv;
u32 buf_len = len + sizeof(p2p_vendor_spec) +
sizeof(priv->p2p.local_random);
int ret = 0;
@@ -1273,7 +1321,8 @@ static int mgmt_tx_cancel_wait(struct wiphy *wiphy,
struct wireless_dev *wdev,
u64 cookie)
{
- struct wilc_priv *priv = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(wdev->netdev);
+ struct wilc_priv *priv = &vif->priv;
struct host_if_drv *wfi_drv = priv->hif_drv;
wfi_drv->p2p_timeout = jiffies;
@@ -1283,7 +1332,7 @@ static int mgmt_tx_cancel_wait(struct wiphy *wiphy,
params = &priv->remain_on_ch_params;
- cfg80211_remain_on_channel_expired(priv->wdev,
+ cfg80211_remain_on_channel_expired(wdev,
params->listen_cookie,
params->listen_ch,
GFP_KERNEL);
@@ -1295,9 +1344,8 @@ static int mgmt_tx_cancel_wait(struct wiphy *wiphy,
void wilc_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev,
u16 frame_type, bool reg)
{
- struct wilc_priv *priv = wiphy_priv(wiphy);
- struct wilc_vif *vif = netdev_priv(priv->wdev->netdev);
- struct wilc *wl = vif->wilc;
+ struct wilc *wl = wiphy_priv(wiphy);
+ struct wilc_vif *vif = netdev_priv(wdev->netdev);
if (!frame_type)
return;
@@ -1331,8 +1379,7 @@ static int set_cqm_rssi_config(struct wiphy *wiphy, struct net_device *dev,
static int dump_station(struct wiphy *wiphy, struct net_device *dev,
int idx, u8 *mac, struct station_info *sinfo)
{
- struct wilc_priv *priv = wiphy_priv(wiphy);
- struct wilc_vif *vif = netdev_priv(priv->dev);
+ struct wilc_vif *vif = netdev_priv(dev);
int ret;
if (idx != 0)
@@ -1344,15 +1391,15 @@ static int dump_station(struct wiphy *wiphy, struct net_device *dev,
if (ret)
return ret;
- memcpy(mac, priv->associated_bss, ETH_ALEN);
+ memcpy(mac, vif->priv.associated_bss, ETH_ALEN);
return 0;
}
static int set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
bool enabled, int timeout)
{
- struct wilc_priv *priv = wiphy_priv(wiphy);
- struct wilc_vif *vif = netdev_priv(priv->dev);
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc_priv *priv = &vif->priv;
if (!priv->hif_drv)
return -EIO;
@@ -1367,9 +1414,9 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
enum nl80211_iftype type,
struct vif_params *params)
{
- struct wilc_priv *priv = wiphy_priv(wiphy);
+ struct wilc *wl = wiphy_priv(wiphy);
struct wilc_vif *vif = netdev_priv(dev);
- struct wilc *wl = vif->wilc;
+ struct wilc_priv *priv = &vif->priv;
priv->p2p.local_random = 0x01;
priv->p2p.recv_random = 0x00;
@@ -1381,8 +1428,10 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
case NL80211_IFTYPE_STATION:
vif->connecting = false;
dev->ieee80211_ptr->iftype = type;
- priv->wdev->iftype = type;
+ priv->wdev.iftype = type;
vif->monitor_flag = 0;
+ if (vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE)
+ wilc_wfi_deinit_mon_interface(wl, true);
vif->iftype = WILC_STATION_MODE;
wilc_set_operation_mode(vif, WILC_STATION_MODE);
@@ -1396,7 +1445,7 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
case NL80211_IFTYPE_P2P_CLIENT:
vif->connecting = false;
dev->ieee80211_ptr->iftype = type;
- priv->wdev->iftype = type;
+ priv->wdev.iftype = type;
vif->monitor_flag = 0;
vif->iftype = WILC_CLIENT_MODE;
wilc_set_operation_mode(vif, WILC_STATION_MODE);
@@ -1408,12 +1457,12 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
case NL80211_IFTYPE_AP:
wl->enable_ps = false;
dev->ieee80211_ptr->iftype = type;
- priv->wdev->iftype = type;
+ priv->wdev.iftype = type;
vif->iftype = WILC_AP_MODE;
if (wl->initialized) {
wilc_set_wfi_drv_handler(vif, wilc_get_vif_idx(vif),
- 0, vif->ifc_id);
+ 0, vif->idx);
wilc_set_operation_mode(vif, WILC_AP_MODE);
wilc_set_power_mgmt(vif, 0, 0);
}
@@ -1425,7 +1474,7 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
jiffies + msecs_to_jiffies(WILC_IP_TIMEOUT_MS));
wilc_set_operation_mode(vif, WILC_AP_MODE);
dev->ieee80211_ptr->iftype = type;
- priv->wdev->iftype = type;
+ priv->wdev.iftype = type;
vif->iftype = WILC_GO_MODE;
wl->enable_ps = false;
@@ -1444,14 +1493,13 @@ static int start_ap(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_ap_settings *settings)
{
struct wilc_vif *vif = netdev_priv(dev);
- struct wilc *wl = vif->wilc;
int ret;
ret = set_channel(wiphy, &settings->chandef);
if (ret != 0)
netdev_err(dev, "Error in setting channel\n");
- wilc_wlan_set_bssid(dev, wl->vif[vif->idx]->src_addr, WILC_AP_MODE);
+ wilc_wlan_set_bssid(dev, dev->dev_addr, WILC_AP_MODE);
wilc_set_power_mgmt(vif, 0, 0);
return wilc_add_beacon(vif, settings->beacon_interval,
@@ -1461,8 +1509,7 @@ static int start_ap(struct wiphy *wiphy, struct net_device *dev,
static int change_beacon(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_beacon_data *beacon)
{
- struct wilc_priv *priv = wiphy_priv(wiphy);
- struct wilc_vif *vif = netdev_priv(priv->dev);
+ struct wilc_vif *vif = netdev_priv(dev);
return wilc_add_beacon(vif, 0, 0, beacon);
}
@@ -1470,8 +1517,7 @@ static int change_beacon(struct wiphy *wiphy, struct net_device *dev,
static int stop_ap(struct wiphy *wiphy, struct net_device *dev)
{
int ret;
- struct wilc_priv *priv = wiphy_priv(wiphy);
- struct wilc_vif *vif = netdev_priv(priv->dev);
+ struct wilc_vif *vif = netdev_priv(dev);
wilc_wlan_set_bssid(dev, NULL, WILC_AP_MODE);
@@ -1487,8 +1533,8 @@ static int add_station(struct wiphy *wiphy, struct net_device *dev,
const u8 *mac, struct station_parameters *params)
{
int ret = 0;
- struct wilc_priv *priv = wiphy_priv(wiphy);
struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc_priv *priv = &vif->priv;
if (vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE) {
memcpy(priv->assoc_stainfo.sta_associated_bss[params->aid], mac,
@@ -1507,8 +1553,8 @@ static int del_station(struct wiphy *wiphy, struct net_device *dev,
{
const u8 *mac = params->mac;
int ret = 0;
- struct wilc_priv *priv = wiphy_priv(wiphy);
struct wilc_vif *vif = netdev_priv(dev);
+ struct wilc_priv *priv = &vif->priv;
struct sta_info *info;
if (!(vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE))
@@ -1539,60 +1585,157 @@ static int change_station(struct wiphy *wiphy, struct net_device *dev,
return ret;
}
+static int wilc_get_vif_from_type(struct wilc *wl, int type)
+{
+ int i;
+
+ mutex_lock(&wl->vif_mutex);
+ for (i = 0; i < wl->vif_num; i++) {
+ if (wl->vif[i]->iftype == type) {
+ mutex_unlock(&wl->vif_mutex);
+ return i;
+ }
+ }
+ mutex_unlock(&wl->vif_mutex);
+
+ return -EINVAL;
+}
+
static struct wireless_dev *add_virtual_intf(struct wiphy *wiphy,
const char *name,
unsigned char name_assign_type,
enum nl80211_iftype type,
struct vif_params *params)
{
- struct wilc_priv *priv = wiphy_priv(wiphy);
- struct wilc_vif *vif = netdev_priv(priv->wdev->netdev);
- struct net_device *new_ifc;
+ struct wilc *wl = wiphy_priv(wiphy);
+ struct wilc_vif *vif;
+ struct wireless_dev *wdev;
+ int iftype;
+ int ret;
if (type == NL80211_IFTYPE_MONITOR) {
- new_ifc = wilc_wfi_init_mon_interface(vif->wilc, name,
- vif->ndev);
- if (new_ifc) {
- vif = netdev_priv(priv->wdev->netdev);
- vif->monitor_flag = 1;
+ struct net_device *ndev;
+ int ap_index = wilc_get_vif_from_type(wl, WILC_AP_MODE);
+
+ if (ap_index < 0) {
+ ap_index = wilc_get_vif_from_type(wl, WILC_GO_MODE);
+ if (ap_index < 0)
+ goto validate_interface;
}
+
+ vif = wl->vif[ap_index];
+ if (vif->monitor_flag)
+ goto validate_interface;
+
+ ndev = wilc_wfi_init_mon_interface(wl, name, vif->ndev);
+ if (ndev)
+ vif->monitor_flag = 1;
+ else
+ return ERR_PTR(-EINVAL);
+
+ wdev = &vif->priv.wdev;
+ return wdev;
+ }
+
+validate_interface:
+ mutex_lock(&wl->vif_mutex);
+ if (wl->vif_num == WILC_NUM_CONCURRENT_IFC) {
+ pr_err("Reached maximum number of interface\n");
+ ret = -EINVAL;
+ goto out_err;
}
- return priv->wdev;
+
+ switch (type) {
+ case NL80211_IFTYPE_STATION:
+ iftype = WILC_STATION_MODE;
+ break;
+ case NL80211_IFTYPE_AP:
+ iftype = WILC_AP_MODE;
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ goto out_err;
+ }
+
+ vif = wilc_netdev_ifc_init(wl, name, iftype, type, true);
+ if (IS_ERR(vif)) {
+ ret = PTR_ERR(vif);
+ goto out_err;
+ }
+
+ mutex_unlock(&wl->vif_mutex);
+
+ return &vif->priv.wdev;
+
+out_err:
+ mutex_unlock(&wl->vif_mutex);
+ return ERR_PTR(ret);
}
static int del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
{
+ struct wilc *wl = wiphy_priv(wiphy);
+ struct wilc_vif *vif;
+ int i;
+
+ if (wdev->iftype == NL80211_IFTYPE_AP ||
+ wdev->iftype == NL80211_IFTYPE_P2P_GO)
+ wilc_wfi_deinit_mon_interface(wl, true);
+ vif = netdev_priv(wdev->netdev);
+ cfg80211_stop_iface(wiphy, wdev, GFP_KERNEL);
+ unregister_netdevice(vif->ndev);
+ vif->monitor_flag = 0;
+
+ mutex_lock(&wl->vif_mutex);
+ wilc_set_wfi_drv_handler(vif, 0, 0, 0);
+ for (i = vif->idx; i < wl->vif_num ; i++) {
+ if ((i + 1) >= wl->vif_num) {
+ wl->vif[i] = NULL;
+ } else {
+ vif = wl->vif[i + 1];
+ vif->idx = i;
+ wl->vif[i] = vif;
+ wilc_set_wfi_drv_handler(vif, wilc_get_vif_idx(vif),
+ vif->iftype, vif->idx);
+ }
+ }
+ wl->vif_num--;
+ mutex_unlock(&wl->vif_mutex);
+
return 0;
}
static int wilc_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow)
{
- struct wilc_priv *priv = wiphy_priv(wiphy);
- struct wilc_vif *vif = netdev_priv(priv->dev);
+ struct wilc *wl = wiphy_priv(wiphy);
- if (!wow && wilc_wlan_get_num_conn_ifcs(vif->wilc))
- vif->wilc->suspend_event = true;
+ if (!wow && wilc_wlan_get_num_conn_ifcs(wl))
+ wl->suspend_event = true;
else
- vif->wilc->suspend_event = false;
+ wl->suspend_event = false;
return 0;
}
static int wilc_resume(struct wiphy *wiphy)
{
- struct wilc_priv *priv = wiphy_priv(wiphy);
- struct wilc_vif *vif = netdev_priv(priv->dev);
-
- netdev_info(vif->ndev, "cfg resume\n");
return 0;
}
static void wilc_set_wakeup(struct wiphy *wiphy, bool enabled)
{
- struct wilc_priv *priv = wiphy_priv(wiphy);
- struct wilc_vif *vif = netdev_priv(priv->dev);
+ struct wilc *wl = wiphy_priv(wiphy);
+ struct wilc_vif *vif;
+
+ mutex_lock(&wl->vif_mutex);
+ vif = wilc_get_wl_to_vif(wl);
+ if (IS_ERR(vif)) {
+ mutex_unlock(&wl->vif_mutex);
+ return;
+ }
netdev_info(vif->ndev, "cfg set wake up = %d\n", enabled);
+ mutex_unlock(&wl->vif_mutex);
}
static int set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
@@ -1600,8 +1743,7 @@ static int set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
{
int ret;
s32 tx_power = MBM_TO_DBM(mbm);
- struct wilc_priv *priv = wiphy_priv(wiphy);
- struct wilc_vif *vif = netdev_priv(priv->dev);
+ struct wilc_vif *vif = netdev_priv(wdev->netdev);
if (tx_power < 0)
tx_power = 0;
@@ -1618,8 +1760,7 @@ static int get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
int *dbm)
{
int ret;
- struct wilc_priv *priv = wiphy_priv(wiphy);
- struct wilc_vif *vif = netdev_priv(priv->dev);
+ struct wilc_vif *vif = netdev_priv(wdev->netdev);
struct wilc *wl = vif->wilc;
/* If firmware is not started, return. */
@@ -1676,98 +1817,137 @@ static const struct cfg80211_ops wilc_cfg80211_ops = {
};
-static struct wireless_dev *wilc_wfi_cfg_alloc(void)
+static void wlan_init_locks(struct wilc *wl)
{
- struct wireless_dev *wdev;
+ mutex_init(&wl->hif_cs);
+ mutex_init(&wl->rxq_cs);
+ mutex_init(&wl->cfg_cmd_lock);
+ mutex_init(&wl->vif_mutex);
+
+ spin_lock_init(&wl->txq_spinlock);
+ mutex_init(&wl->txq_add_to_head_cs);
+
+ init_completion(&wl->txq_event);
+ init_completion(&wl->cfg_event);
+ init_completion(&wl->sync_event);
+ init_completion(&wl->txq_thread_started);
+}
- wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
- if (!wdev)
- goto out;
+int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type,
+ const struct wilc_hif_func *ops)
+{
+ struct wilc *wl;
+ struct wilc_vif *vif;
+ int ret;
- wdev->wiphy = wiphy_new(&wilc_cfg80211_ops, sizeof(struct wilc_priv));
- if (!wdev->wiphy)
- goto free_mem;
+ wl = wilc_create_wiphy(dev);
+ if (!wl)
+ return -EINVAL;
- return wdev;
+ ret = wilc_wlan_cfg_init(wl);
+ if (ret)
+ goto free_wl;
+
+ *wilc = wl;
+ wl->io_type = io_type;
+ wl->hif_func = ops;
+ wl->enable_ps = false;
+ wl->chip_ps_state = WILC_CHIP_WAKEDUP;
+ INIT_LIST_HEAD(&wl->txq_head.list);
+ INIT_LIST_HEAD(&wl->rxq_head.list);
+
+ wl->hif_workqueue = create_singlethread_workqueue("WILC_wq");
+ if (!wl->hif_workqueue) {
+ ret = -ENOMEM;
+ goto free_cfg;
+ }
+ vif = wilc_netdev_ifc_init(wl, "wlan%d", WILC_STATION_MODE,
+ NL80211_IFTYPE_STATION, false);
+ if (IS_ERR(vif)) {
+ ret = PTR_ERR(vif);
+ goto free_hq;
+ }
-free_mem:
- kfree(wdev);
-out:
- return NULL;
+ wlan_init_locks(wl);
+
+ return 0;
+
+free_hq:
+ destroy_workqueue(wl->hif_workqueue);
+
+free_cfg:
+ wilc_wlan_cfg_deinit(wl);
+
+free_wl:
+ wiphy_unregister(wl->wiphy);
+ wiphy_free(wl->wiphy);
+ return ret;
}
+EXPORT_SYMBOL_GPL(wilc_cfg80211_init);
-struct wireless_dev *wilc_create_wiphy(struct net_device *net,
- struct device *dev)
+struct wilc *wilc_create_wiphy(struct device *dev)
{
- struct wilc_priv *priv;
- struct wireless_dev *wdev;
+ struct wiphy *wiphy;
+ struct wilc *wl;
int ret;
- wdev = wilc_wfi_cfg_alloc();
- if (!wdev) {
- netdev_err(net, "wiphy new allocate failed\n");
+ wiphy = wiphy_new(&wilc_cfg80211_ops, sizeof(*wl));
+ if (!wiphy)
return NULL;
- }
- priv = wdev_priv(wdev);
- priv->wdev = wdev;
+ wl = wiphy_priv(wiphy);
- memcpy(priv->bitrates, wilc_bitrates, sizeof(wilc_bitrates));
- memcpy(priv->channels, wilc_2ghz_channels, sizeof(wilc_2ghz_channels));
- priv->band.bitrates = priv->bitrates;
- priv->band.n_bitrates = ARRAY_SIZE(priv->bitrates);
- priv->band.channels = priv->channels;
- priv->band.n_channels = ARRAY_SIZE(wilc_2ghz_channels);
+ memcpy(wl->bitrates, wilc_bitrates, sizeof(wilc_bitrates));
+ memcpy(wl->channels, wilc_2ghz_channels, sizeof(wilc_2ghz_channels));
+ wl->band.bitrates = wl->bitrates;
+ wl->band.n_bitrates = ARRAY_SIZE(wl->bitrates);
+ wl->band.channels = wl->channels;
+ wl->band.n_channels = ARRAY_SIZE(wilc_2ghz_channels);
- priv->band.ht_cap.ht_supported = 1;
- priv->band.ht_cap.cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
- priv->band.ht_cap.mcs.rx_mask[0] = 0xff;
- priv->band.ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K;
- priv->band.ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE;
+ wl->band.ht_cap.ht_supported = 1;
+ wl->band.ht_cap.cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
+ wl->band.ht_cap.mcs.rx_mask[0] = 0xff;
+ wl->band.ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K;
+ wl->band.ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE;
- wdev->wiphy->bands[NL80211_BAND_2GHZ] = &priv->band;
+ wiphy->bands[NL80211_BAND_2GHZ] = &wl->band;
- wdev->wiphy->max_scan_ssids = WILC_MAX_NUM_PROBED_SSID;
+ wiphy->max_scan_ssids = WILC_MAX_NUM_PROBED_SSID;
#ifdef CONFIG_PM
- wdev->wiphy->wowlan = &wowlan_support;
+ wiphy->wowlan = &wowlan_support;
#endif
- wdev->wiphy->max_num_pmkids = WILC_MAX_NUM_PMKIDS;
- wdev->wiphy->max_scan_ie_len = 1000;
- wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
- memcpy(priv->cipher_suites, wilc_cipher_suites,
+ wiphy->max_num_pmkids = WILC_MAX_NUM_PMKIDS;
+ wiphy->max_scan_ie_len = 1000;
+ wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+ memcpy(wl->cipher_suites, wilc_cipher_suites,
sizeof(wilc_cipher_suites));
- wdev->wiphy->cipher_suites = priv->cipher_suites;
- wdev->wiphy->n_cipher_suites = ARRAY_SIZE(wilc_cipher_suites);
- wdev->wiphy->mgmt_stypes = wilc_wfi_cfg80211_mgmt_types;
-
- wdev->wiphy->max_remain_on_channel_duration = 500;
- wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_AP) |
- BIT(NL80211_IFTYPE_MONITOR) |
- BIT(NL80211_IFTYPE_P2P_GO) |
- BIT(NL80211_IFTYPE_P2P_CLIENT);
- wdev->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
- wdev->iftype = NL80211_IFTYPE_STATION;
-
- set_wiphy_dev(wdev->wiphy, dev);
-
- ret = wiphy_register(wdev->wiphy);
+ wiphy->cipher_suites = wl->cipher_suites;
+ wiphy->n_cipher_suites = ARRAY_SIZE(wilc_cipher_suites);
+ wiphy->mgmt_stypes = wilc_wfi_cfg80211_mgmt_types;
+
+ wiphy->max_remain_on_channel_duration = 500;
+ wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_MONITOR) |
+ BIT(NL80211_IFTYPE_P2P_GO) |
+ BIT(NL80211_IFTYPE_P2P_CLIENT);
+ wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+
+ set_wiphy_dev(wiphy, dev);
+ wl->wiphy = wiphy;
+ ret = wiphy_register(wiphy);
if (ret) {
- netdev_err(net, "Cannot register wiphy device\n");
- wiphy_free(wdev->wiphy);
- kfree(wdev);
+ wiphy_free(wiphy);
return NULL;
}
-
- priv->dev = net;
- return wdev;
+ return wl;
}
int wilc_init_host_int(struct net_device *net)
{
int ret;
- struct wilc_priv *priv = wdev_priv(net->ieee80211_ptr);
- struct wilc_vif *vif = netdev_priv(priv->dev);
+ struct wilc_vif *vif = netdev_priv(net);
+ struct wilc_priv *priv = &vif->priv;
timer_setup(&vif->during_ip_timer, clear_during_ip, 0);
@@ -1784,8 +1964,8 @@ int wilc_init_host_int(struct net_device *net)
void wilc_deinit_host_int(struct net_device *net)
{
int ret;
- struct wilc_priv *priv = wdev_priv(net->ieee80211_ptr);
- struct wilc_vif *vif = netdev_priv(priv->dev);
+ struct wilc_vif *vif = netdev_priv(net);
+ struct wilc_priv *priv = &vif->priv;
priv->p2p_listen_state = false;
@@ -1798,19 +1978,3 @@ void wilc_deinit_host_int(struct net_device *net)
netdev_err(net, "Error while deinitializing host interface\n");
}
-void wilc_free_wiphy(struct net_device *net)
-{
- if (!net)
- return;
-
- if (!net->ieee80211_ptr)
- return;
-
- if (!net->ieee80211_ptr->wiphy)
- return;
-
- wiphy_unregister(net->ieee80211_ptr->wiphy);
-
- wiphy_free(net->ieee80211_ptr->wiphy);
- kfree(net->ieee80211_ptr);
-}
diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.h b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.h
index 31dfa1f141f1..234faaabdb82 100644
--- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.h
+++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.h
@@ -8,17 +8,20 @@
#define NM_WFI_CFGOPERATIONS
#include "wilc_wfi_netdevice.h"
-struct wireless_dev *wilc_create_wiphy(struct net_device *net,
- struct device *dev);
-void wilc_free_wiphy(struct net_device *net);
+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);
-void wilc_wfi_deinit_mon_interface(struct wilc *wl);
+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,
struct net_device *real_dev);
void wilc_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev,
u16 frame_type, bool reg);
-
+struct wilc_vif *wilc_get_interface(struct wilc *wl);
#endif
diff --git a/drivers/staging/wilc1000/wilc_wfi_netdevice.h b/drivers/staging/wilc1000/wilc_wfi_netdevice.h
index df00762487c0..1e74a08e7cf1 100644
--- a/drivers/staging/wilc1000/wilc_wfi_netdevice.h
+++ b/drivers/staging/wilc1000/wilc_wfi_netdevice.h
@@ -14,7 +14,7 @@
#include <linux/if_arp.h>
#include <linux/gpio/consumer.h>
-#include "host_interface.h"
+#include "wilc_hif.h"
#include "wilc_wlan.h"
#include "wilc_wlan_cfg.h"
@@ -129,7 +129,7 @@ static struct ieee80211_rate wilc_bitrates[] = {
};
struct wilc_priv {
- struct wireless_dev *wdev;
+ struct wireless_dev wdev;
struct cfg80211_scan_request *scan_req;
struct wilc_wfi_p2p_listen_params remain_on_ch_params;
@@ -156,10 +156,6 @@ struct wilc_priv {
int scanned_cnt;
struct wilc_p2p_var p2p;
- struct ieee80211_channel channels[ARRAY_SIZE(wilc_2ghz_channels)];
- struct ieee80211_rate bitrates[ARRAY_SIZE(wilc_bitrates)];
- struct ieee80211_supported_band band;
- u32 cipher_suites[ARRAY_SIZE(wilc_cipher_suites)];
u64 inc_roc_cookie;
};
@@ -202,21 +198,21 @@ struct wilc_vif {
struct frame_reg frame_reg[NUM_REG_FRAME];
struct net_device_stats netstats;
struct wilc *wilc;
- u8 src_addr[ETH_ALEN];
u8 bssid[ETH_ALEN];
struct host_if_drv *hif_drv;
struct net_device *ndev;
u8 mode;
- u8 ifc_id;
struct timer_list during_ip_timer;
bool obtaining_ip;
struct timer_list periodic_rssi;
struct rf_info periodic_stat;
struct tcp_ack_filter ack_filter;
bool connecting;
+ struct wilc_priv priv;
};
struct wilc {
+ struct wiphy *wiphy;
const struct wilc_hif_func *hif_func;
int io_type;
s8 mac_status;
@@ -226,6 +222,8 @@ struct wilc {
int close;
u8 vif_num;
struct wilc_vif *vif[WILC_NUM_CONCURRENT_IFC];
+ /*protect vif list*/
+ struct mutex vif_mutex;
u8 open_ifcs;
/*protect head of transmit queue*/
struct mutex txq_add_to_head_cs;
@@ -275,6 +273,10 @@ struct wilc {
struct mutex deinit_lock;
u8 sta_ch;
u8 op_ch;
+ struct ieee80211_channel channels[ARRAY_SIZE(wilc_2ghz_channels)];
+ struct ieee80211_rate bitrates[ARRAY_SIZE(wilc_bitrates)];
+ struct ieee80211_supported_band band;
+ u32 cipher_suites[ARRAY_SIZE(wilc_cipher_suites)];
};
struct wilc_wfi_mon_priv {
@@ -284,9 +286,9 @@ struct wilc_wfi_mon_priv {
void wilc_frmw_to_host(struct wilc *wilc, u8 *buff, u32 size, u32 pkt_offset);
void wilc_mac_indicate(struct wilc *wilc);
void wilc_netdev_cleanup(struct wilc *wilc);
-int wilc_netdev_init(struct wilc **wilc, struct device *dev, int io_type,
- const struct wilc_hif_func *ops);
void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size);
void wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode);
-
+struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name,
+ int vif_type, enum nl80211_iftype type,
+ bool rtnl_locked);
#endif
diff --git a/drivers/staging/wilc1000/wilc_wlan.c b/drivers/staging/wilc1000/wilc_wlan.c
index 95eaf8fdf4f2..d46876edcfeb 100644
--- a/drivers/staging/wilc1000/wilc_wlan.c
+++ b/drivers/staging/wilc1000/wilc_wlan.c
@@ -6,7 +6,7 @@
#include <linux/if_ether.h>
#include <linux/ip.h>
-#include "wilc_wfi_netdevice.h"
+#include "wilc_wfi_cfgoperations.h"
#include "wilc_wlan_cfg.h"
static inline bool is_wilc1000(u32 id)
@@ -267,6 +267,7 @@ static int wilc_wlan_txq_add_cfg_pkt(struct wilc_vif *vif, u8 *buffer,
tqe->tx_complete_func = NULL;
tqe->priv = NULL;
tqe->ack_idx = NOT_TCP_ACK;
+ tqe->vif = vif;
wilc_wlan_txq_add_to_head(vif, tqe);
@@ -295,6 +296,7 @@ int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer,
tqe->buffer_size = buffer_size;
tqe->tx_complete_func = tx_complete_fn;
tqe->priv = priv;
+ tqe->vif = vif;
tqe->ack_idx = NOT_TCP_ACK;
if (vif->ack_filter.enabled)
@@ -326,6 +328,7 @@ int wilc_wlan_txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer,
tqe->tx_complete_func = tx_complete_fn;
tqe->priv = priv;
tqe->ack_idx = NOT_TCP_ACK;
+ tqe->vif = vif;
wilc_wlan_txq_add_to_tail(dev, tqe);
return 1;
}
@@ -482,7 +485,7 @@ void host_sleep_notify(struct wilc *wilc)
}
EXPORT_SYMBOL_GPL(host_sleep_notify);
-int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count)
+int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
{
int i, entries = 0;
u32 sum;
@@ -494,17 +497,20 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count)
int counter;
int timeout;
u32 vmm_table[WILC_VMM_TBL_SIZE];
- struct wilc_vif *vif = netdev_priv(dev);
- struct wilc *wilc = vif->wilc;
const struct wilc_hif_func *func;
u8 *txb = wilc->tx_buffer;
+ struct net_device *dev;
+ struct wilc_vif *vif;
if (wilc->quit)
goto out;
mutex_lock(&wilc->txq_add_to_head_cs);
- wilc_wlan_txq_filter_dup_tcp_ack(dev);
tqe = wilc_wlan_txq_get_first(wilc);
+ if (!tqe)
+ goto out;
+ dev = tqe->vif->ndev;
+ wilc_wlan_txq_filter_dup_tcp_ack(dev);
i = 0;
sum = 0;
do {
@@ -629,6 +635,7 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count)
if (!tqe)
break;
+ vif = tqe->vif;
if (vmm_table[i] == 0)
break;
@@ -648,8 +655,7 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count)
if (tqe->type == WILC_CFG_PKT) {
buffer_offset = ETH_CONFIG_PKT_HDR_OFFSET;
} else if (tqe->type == WILC_NET_PKT) {
- bssid = ((struct tx_complete_data *)(tqe->priv))->bssid;
-
+ bssid = tqe->vif->bssid;
buffer_offset = ETH_ETHERNET_HDR_OFFSET;
memcpy(&txb[offset + 8], bssid, 6);
} else {
@@ -709,9 +715,6 @@ static void wilc_wlan_handle_rx_buff(struct wilc *wilc, u8 *buffer, int size)
break;
if (pkt_offset & IS_MANAGMEMENT) {
- pkt_offset &= ~(IS_MANAGMEMENT |
- IS_MANAGMEMENT_CALLBACK |
- IS_MGMT_STATUS_SUCCES);
buff_ptr += HOST_HDR_OFFSET;
wilc_wfi_mgmt_rx(wilc, buff_ptr, pkt_len);
} else {
@@ -1199,10 +1202,11 @@ int wilc_wlan_cfg_get_val(struct wilc *wl, u16 wid, u8 *buffer, u32 buffer_size)
}
int wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids,
- u32 count, u32 drv)
+ u32 count)
{
int i;
int ret = 0;
+ u32 drv = wilc_get_vif_idx(vif);
if (mode == WILC_GET_CFG) {
for (i = 0; i < count; i++) {
diff --git a/drivers/staging/wilc1000/wilc_wlan.h b/drivers/staging/wilc1000/wilc_wlan.h
index 1a27f62589a2..d2eef7b4c3b7 100644
--- a/drivers/staging/wilc1000/wilc_wlan.h
+++ b/drivers/staging/wilc1000/wilc_wlan.h
@@ -216,6 +216,7 @@ struct txq_entry_t {
int buffer_size;
void *priv;
int status;
+ struct wilc_vif *vif;
void (*tx_complete_func)(void *priv, int status);
};
@@ -253,7 +254,6 @@ struct wilc_hif_func {
struct tx_complete_data {
int size;
void *buff;
- u8 *bssid;
struct sk_buff *skb;
};
@@ -284,7 +284,7 @@ int wilc_wlan_stop(struct wilc *wilc);
int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer,
u32 buffer_size,
void (*tx_complete_fn)(void *, int));
-int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count);
+int wilc_wlan_handle_txq(struct wilc *wl, u32 *txq_count);
void wilc_handle_isr(struct wilc *wilc);
void wilc_wlan_cleanup(struct net_device *dev);
int wilc_wlan_cfg_set(struct wilc_vif *vif, int start, u16 wid, u8 *buffer,
@@ -301,13 +301,13 @@ void wilc_enable_tcp_ack_filter(struct wilc_vif *vif, bool value);
int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc);
netdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *dev);
-void wilc_wfi_p2p_rx(struct net_device *dev, u8 *buff, u32 size);
+void wilc_wfi_p2p_rx(struct wilc_vif *vif, u8 *buff, u32 size);
void host_wakeup_notify(struct wilc *wilc);
void host_sleep_notify(struct wilc *wilc);
void chip_allow_sleep(struct wilc *wilc);
void chip_wakeup(struct wilc *wilc);
int wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids,
- u32 count, u32 drv);
+ u32 count);
int wilc_wlan_init(struct net_device *dev);
u32 wilc_get_chipid(struct wilc *wilc, bool update);
#endif
diff --git a/drivers/staging/wilc1000/wilc_wlan_if.h b/drivers/staging/wilc1000/wilc_wlan_if.h
index b15de36e32e0..b89d0e0f04cc 100644
--- a/drivers/staging/wilc1000/wilc_wlan_if.h
+++ b/drivers/staging/wilc1000/wilc_wlan_if.h
@@ -684,7 +684,7 @@ enum {
WID_LONG_RETRY_LIMIT = 0x1003,
WID_BEACON_INTERVAL = 0x1006,
WID_MEMORY_ACCESS_16BIT = 0x1008,
-
+ WID_PASSIVE_SCAN_TIME = 0x100D,
WID_JOIN_START_TIMEOUT = 0x100F,
WID_ASOC_TIMEOUT = 0x1011,
WID_11I_PROTOCOL_TIMEOUT = 0x1012,
diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c
index 8a862f718d5c..eee1998c4b18 100644
--- a/drivers/staging/wlan-ng/cfg80211.c
+++ b/drivers/staging/wlan-ng/cfg80211.c
@@ -231,17 +231,9 @@ static int prism2_set_default_key(struct wiphy *wiphy, struct net_device *dev,
{
struct wlandevice *wlandev = dev->ml_priv;
- int err = 0;
- int result = 0;
-
- result = prism2_domibset_uint32(wlandev,
- DIDMIB_DOT11SMT_PRIVACYTABLE_WEPDEFAULTKEYID,
- key_index);
-
- if (result)
- err = -EFAULT;
-
- return err;
+ return prism2_domibset_uint32(wlandev,
+ DIDMIB_DOT11SMT_PRIVACYTABLE_WEPDEFAULTKEYID,
+ key_index);
}
static int prism2_get_station(struct wiphy *wiphy, struct net_device *dev,
diff --git a/drivers/target/iscsi/cxgbit/cxgbit.h b/drivers/target/iscsi/cxgbit/cxgbit.h
index 3cca22e19964..c04cd0832dec 100644
--- a/drivers/target/iscsi/cxgbit/cxgbit.h
+++ b/drivers/target/iscsi/cxgbit/cxgbit.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2016 Chelsio Communications, 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.
*/
#ifndef __CXGBIT_H__
diff --git a/drivers/target/iscsi/cxgbit/cxgbit_cm.c b/drivers/target/iscsi/cxgbit/cxgbit_cm.c
index dab09b610723..22dd4c457d6a 100644
--- a/drivers/target/iscsi/cxgbit/cxgbit_cm.c
+++ b/drivers/target/iscsi/cxgbit/cxgbit_cm.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2016 Chelsio Communications, 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.
*/
#include <linux/module.h>
diff --git a/drivers/target/iscsi/cxgbit/cxgbit_ddp.c b/drivers/target/iscsi/cxgbit/cxgbit_ddp.c
index d57fd3ed3fa5..54bb1ebd8eb5 100644
--- a/drivers/target/iscsi/cxgbit/cxgbit_ddp.c
+++ b/drivers/target/iscsi/cxgbit/cxgbit_ddp.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2016 Chelsio Communications, 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.
*/
#include "cxgbit.h"
@@ -318,8 +315,10 @@ int cxgbit_ddp_init(struct cxgbit_device *cdev)
ret = cxgbi_ppm_init(lldi->iscsi_ppm, cdev->lldi.ports[0],
cdev->lldi.pdev, &cdev->lldi, &tformat,
- ppmax, lldi->iscsi_llimit,
- lldi->vr->iscsi.start, 2);
+ lldi->vr->iscsi.size, lldi->iscsi_llimit,
+ lldi->vr->iscsi.start, 2,
+ lldi->vr->ppod_edram.start,
+ lldi->vr->ppod_edram.size);
if (ret >= 0) {
struct cxgbi_ppm *ppm = (struct cxgbi_ppm *)(*lldi->iscsi_ppm);
diff --git a/drivers/target/iscsi/cxgbit/cxgbit_main.c b/drivers/target/iscsi/cxgbit/cxgbit_main.c
index 4a7bb0b49d17..343b129c2cfa 100644
--- a/drivers/target/iscsi/cxgbit/cxgbit_main.c
+++ b/drivers/target/iscsi/cxgbit/cxgbit_main.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2016 Chelsio Communications, 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.
*/
#define DRV_NAME "cxgbit"
diff --git a/drivers/target/iscsi/cxgbit/cxgbit_target.c b/drivers/target/iscsi/cxgbit/cxgbit_target.c
index 29b350a0b58f..24309d937d8c 100644
--- a/drivers/target/iscsi/cxgbit/cxgbit_target.c
+++ b/drivers/target/iscsi/cxgbit/cxgbit_target.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2016 Chelsio Communications, 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.
*/
#include <linux/workqueue.h>
diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c
index b6e4862cc242..51ddca2033e0 100644
--- a/drivers/target/iscsi/iscsi_target_auth.c
+++ b/drivers/target/iscsi/iscsi_target_auth.c
@@ -81,6 +81,12 @@ out:
return CHAP_DIGEST_UNKNOWN;
}
+static void chap_close(struct iscsi_conn *conn)
+{
+ kfree(conn->auth_protocol);
+ conn->auth_protocol = NULL;
+}
+
static struct iscsi_chap *chap_server_open(
struct iscsi_conn *conn,
struct iscsi_node_auth *auth,
@@ -118,7 +124,7 @@ static struct iscsi_chap *chap_server_open(
case CHAP_DIGEST_UNKNOWN:
default:
pr_err("Unsupported CHAP_A value\n");
- kfree(conn->auth_protocol);
+ chap_close(conn);
return NULL;
}
@@ -133,19 +139,13 @@ static struct iscsi_chap *chap_server_open(
* Generate Challenge.
*/
if (chap_gen_challenge(conn, 1, aic_str, aic_len) < 0) {
- kfree(conn->auth_protocol);
+ chap_close(conn);
return NULL;
}
return chap;
}
-static void chap_close(struct iscsi_conn *conn)
-{
- kfree(conn->auth_protocol);
- conn->auth_protocol = NULL;
-}
-
static int chap_server_compute_md5(
struct iscsi_conn *conn,
struct iscsi_node_auth *auth,
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c
index 181a32a6f391..685d771b51d4 100644
--- a/drivers/target/iscsi/iscsi_target_nego.c
+++ b/drivers/target/iscsi/iscsi_target_nego.c
@@ -152,22 +152,11 @@ static u32 iscsi_handle_authentication(
if (strstr("None", authtype))
return 1;
-#ifdef CANSRP
- else if (strstr("SRP", authtype))
- return srp_main_loop(conn, auth, in_buf, out_buf,
- &in_length, out_length);
-#endif
else if (strstr("CHAP", authtype))
return chap_main_loop(conn, auth, in_buf, out_buf,
&in_length, out_length);
- else if (strstr("SPKM1", authtype))
- return 2;
- else if (strstr("SPKM2", authtype))
- return 2;
- else if (strstr("KRB5", authtype))
- return 2;
- else
- return 2;
+ /* SRP, SPKM1, SPKM2 and KRB5 are unsupported */
+ return 2;
}
static void iscsi_remove_failed_auth_entry(struct iscsi_conn *conn)
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c
index f4a075303e9a..6949ea8bc387 100644
--- a/drivers/target/target_core_iblock.c
+++ b/drivers/target/target_core_iblock.c
@@ -502,7 +502,7 @@ iblock_execute_write_same(struct se_cmd *cmd)
/* Always in 512 byte units for Linux/Block */
block_lba += sg->length >> SECTOR_SHIFT;
- sectors -= 1;
+ sectors -= sg->length >> SECTOR_SHIFT;
}
iblock_submit_bios(&list);
diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c
index b43d6385a1a0..04eda111920e 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -1824,20 +1824,18 @@ static int tcmu_update_uio_info(struct tcmu_dev *udev)
{
struct tcmu_hba *hba = udev->hba->hba_ptr;
struct uio_info *info;
- size_t size, used;
char *str;
info = &udev->uio_info;
- size = snprintf(NULL, 0, "tcm-user/%u/%s/%s", hba->host_id, udev->name,
- udev->dev_config);
- size += 1; /* for \0 */
- str = kmalloc(size, GFP_KERNEL);
- if (!str)
- return -ENOMEM;
- used = snprintf(str, size, "tcm-user/%u/%s", hba->host_id, udev->name);
if (udev->dev_config[0])
- snprintf(str + used, size - used, "/%s", udev->dev_config);
+ str = kasprintf(GFP_KERNEL, "tcm-user/%u/%s/%s", hba->host_id,
+ udev->name, udev->dev_config);
+ else
+ str = kasprintf(GFP_KERNEL, "tcm-user/%u/%s", hba->host_id,
+ udev->name);
+ if (!str)
+ return -ENOMEM;
/* If the old string exists, free it */
kfree(info->name);
diff --git a/drivers/thermal/broadcom/bcm2835_thermal.c b/drivers/thermal/broadcom/bcm2835_thermal.c
index ba39647a690c..3199977f1e73 100644
--- a/drivers/thermal/broadcom/bcm2835_thermal.c
+++ b/drivers/thermal/broadcom/bcm2835_thermal.c
@@ -123,8 +123,6 @@ static void bcm2835_thermal_debugfs(struct platform_device *pdev)
struct debugfs_regset32 *regset;
data->debugfsdir = debugfs_create_dir("bcm2835_thermal", NULL);
- if (!data->debugfsdir)
- return;
regset = devm_kzalloc(&pdev->dev, sizeof(*regset), GFP_KERNEL);
if (!regset)
diff --git a/drivers/thermal/broadcom/ns-thermal.c b/drivers/thermal/broadcom/ns-thermal.c
index 322e741a2463..c9468ba9d449 100644
--- a/drivers/thermal/broadcom/ns-thermal.c
+++ b/drivers/thermal/broadcom/ns-thermal.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2017 Rafał Miłecki <rafal@milecki.pl>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/thermal/fair_share.c b/drivers/thermal/fair_share.c
index 8ff109fb77e1..afd99f668c65 100644
--- a/drivers/thermal/fair_share.c
+++ b/drivers/thermal/fair_share.c
@@ -117,14 +117,4 @@ static struct thermal_governor thermal_gov_fair_share = {
.name = "fair_share",
.throttle = fair_share_throttle,
};
-
-int thermal_gov_fair_share_register(void)
-{
- return thermal_register_governor(&thermal_gov_fair_share);
-}
-
-void thermal_gov_fair_share_unregister(void)
-{
- thermal_unregister_governor(&thermal_gov_fair_share);
-}
-
+THERMAL_GOVERNOR_DECLARE(thermal_gov_fair_share);
diff --git a/drivers/thermal/gov_bang_bang.c b/drivers/thermal/gov_bang_bang.c
index 632fb925e975..e0575d29023a 100644
--- a/drivers/thermal/gov_bang_bang.c
+++ b/drivers/thermal/gov_bang_bang.c
@@ -116,13 +116,4 @@ static struct thermal_governor thermal_gov_bang_bang = {
.name = "bang_bang",
.throttle = bang_bang_control,
};
-
-int thermal_gov_bang_bang_register(void)
-{
- return thermal_register_governor(&thermal_gov_bang_bang);
-}
-
-void thermal_gov_bang_bang_unregister(void)
-{
- thermal_unregister_governor(&thermal_gov_bang_bang);
-}
+THERMAL_GOVERNOR_DECLARE(thermal_gov_bang_bang);
diff --git a/drivers/thermal/intel/int340x_thermal/Kconfig b/drivers/thermal/intel/int340x_thermal/Kconfig
index 5333e018c88c..797907542e43 100644
--- a/drivers/thermal/intel/int340x_thermal/Kconfig
+++ b/drivers/thermal/intel/int340x_thermal/Kconfig
@@ -40,4 +40,10 @@ config INT3406_THERMAL
brightness in order to address a thermal condition or to reduce
power consumed by display device.
+config PROC_THERMAL_MMIO_RAPL
+ bool
+ depends on 64BIT
+ depends on POWERCAP
+ select INTEL_RAPL_CORE
+ default y
endif
diff --git a/drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c b/drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c
index 7c71ffb733a1..9716bc3abaf9 100644
--- a/drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c
+++ b/drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c
@@ -1,11 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* acpi_thermal_rel.c driver for exporting ACPI thermal relationship
*
* Copyright (c) 2014 Intel Corp
- *
- * 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.
- *
*/
/*
diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
index 5f3ed24e26ec..3517883b5cdb 100644
--- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
+++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* INT3400 thermal driver
*
* Copyright (C) 2014, Intel Corporation
* Authors: Zhang Rui <rui.zhang@intel.com>
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/thermal/intel/int340x_thermal/int3402_thermal.c b/drivers/thermal/intel/int340x_thermal/int3402_thermal.c
index 8e90b3151a42..43fa351e2b9e 100644
--- a/drivers/thermal/intel/int340x_thermal/int3402_thermal.c
+++ b/drivers/thermal/intel/int340x_thermal/int3402_thermal.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* INT3402 thermal driver for memory temperature reporting
*
* Copyright (C) 2014, Intel Corporation
* Authors: Aaron Lu <aaron.lu@intel.com>
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/thermal/intel/int340x_thermal/int3406_thermal.c b/drivers/thermal/intel/int340x_thermal/int3406_thermal.c
index f69ab026ba24..f5e42fc2acc0 100644
--- a/drivers/thermal/intel/int340x_thermal/int3406_thermal.c
+++ b/drivers/thermal/intel/int340x_thermal/int3406_thermal.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* INT3406 thermal driver for display participant device
*
* Copyright (C) 2016, Intel Corporation
* Authors: Aaron Lu <aaron.lu@intel.com>
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
index 53c84fa498ce..213ab3cc6b80 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
@@ -11,6 +11,8 @@
#include <linux/platform_device.h>
#include <linux/acpi.h>
#include <linux/thermal.h>
+#include <linux/cpuhotplug.h>
+#include <linux/intel_rapl.h>
#include "int340x_thermal_zone.h"
#include "../intel_soc_dts_iosf.h"
@@ -37,6 +39,8 @@
/* GeminiLake thermal reporting device */
#define PCI_DEVICE_ID_PROC_GLK_THERMAL 0x318C
+#define DRV_NAME "proc_thermal"
+
struct power_config {
u32 index;
u32 min_uw;
@@ -52,6 +56,7 @@ struct proc_thermal_device {
struct power_config power_limits[2];
struct int34x_thermal_zone *int340x_zone;
struct intel_soc_dts_sensors *soc_dts;
+ void __iomem *mmio_base;
};
enum proc_thermal_emum_mode_type {
@@ -60,6 +65,12 @@ enum proc_thermal_emum_mode_type {
PROC_THERMAL_PLATFORM_DEV
};
+struct rapl_mmio_regs {
+ u64 reg_unit;
+ u64 regs[RAPL_DOMAIN_MAX][RAPL_DOMAIN_REG_MAX];
+ int limits[RAPL_DOMAIN_MAX];
+};
+
/*
* We can have only one type of enumeration, PCI or Platform,
* not both. So we don't need instance specific data.
@@ -367,8 +378,151 @@ static irqreturn_t proc_thermal_pci_msi_irq(int irq, void *devid)
return IRQ_HANDLED;
}
+#ifdef CONFIG_PROC_THERMAL_MMIO_RAPL
+
+#define MCHBAR 0
+
+/* RAPL Support via MMIO interface */
+static struct rapl_if_priv rapl_mmio_priv;
+
+static int rapl_mmio_cpu_online(unsigned int cpu)
+{
+ struct rapl_package *rp;
+
+ /* mmio rapl supports package 0 only for now */
+ if (topology_physical_package_id(cpu))
+ return 0;
+
+ rp = rapl_find_package_domain(cpu, &rapl_mmio_priv);
+ if (!rp) {
+ rp = rapl_add_package(cpu, &rapl_mmio_priv);
+ if (IS_ERR(rp))
+ return PTR_ERR(rp);
+ }
+ cpumask_set_cpu(cpu, &rp->cpumask);
+ return 0;
+}
+
+static int rapl_mmio_cpu_down_prep(unsigned int cpu)
+{
+ struct rapl_package *rp;
+ int lead_cpu;
+
+ rp = rapl_find_package_domain(cpu, &rapl_mmio_priv);
+ if (!rp)
+ return 0;
+
+ cpumask_clear_cpu(cpu, &rp->cpumask);
+ lead_cpu = cpumask_first(&rp->cpumask);
+ if (lead_cpu >= nr_cpu_ids)
+ rapl_remove_package(rp);
+ else if (rp->lead_cpu == cpu)
+ rp->lead_cpu = lead_cpu;
+ return 0;
+}
+
+static int rapl_mmio_read_raw(int cpu, struct reg_action *ra)
+{
+ if (!ra->reg)
+ return -EINVAL;
+
+ ra->value = readq((void __iomem *)ra->reg);
+ ra->value &= ra->mask;
+ return 0;
+}
+
+static int rapl_mmio_write_raw(int cpu, struct reg_action *ra)
+{
+ u64 val;
+
+ if (!ra->reg)
+ return -EINVAL;
+
+ val = readq((void __iomem *)ra->reg);
+ val &= ~ra->mask;
+ val |= ra->value;
+ writeq(val, (void __iomem *)ra->reg);
+ return 0;
+}
+
+static int proc_thermal_rapl_add(struct pci_dev *pdev,
+ struct proc_thermal_device *proc_priv,
+ struct rapl_mmio_regs *rapl_regs)
+{
+ enum rapl_domain_reg_id reg;
+ enum rapl_domain_type domain;
+ int ret;
+
+ if (!rapl_regs)
+ return 0;
+
+ ret = pcim_iomap_regions(pdev, 1 << MCHBAR, DRV_NAME);
+ if (ret) {
+ dev_err(&pdev->dev, "cannot reserve PCI memory region\n");
+ return -ENOMEM;
+ }
+
+ proc_priv->mmio_base = pcim_iomap_table(pdev)[MCHBAR];
+
+ for (domain = RAPL_DOMAIN_PACKAGE; domain < RAPL_DOMAIN_MAX; domain++) {
+ for (reg = RAPL_DOMAIN_REG_LIMIT; reg < RAPL_DOMAIN_REG_MAX; reg++)
+ if (rapl_regs->regs[domain][reg])
+ rapl_mmio_priv.regs[domain][reg] =
+ (u64)proc_priv->mmio_base +
+ rapl_regs->regs[domain][reg];
+ rapl_mmio_priv.limits[domain] = rapl_regs->limits[domain];
+ }
+ rapl_mmio_priv.reg_unit = (u64)proc_priv->mmio_base + rapl_regs->reg_unit;
+
+ rapl_mmio_priv.read_raw = rapl_mmio_read_raw;
+ rapl_mmio_priv.write_raw = rapl_mmio_write_raw;
+
+ rapl_mmio_priv.control_type = powercap_register_control_type(NULL, "intel-rapl-mmio", NULL);
+ if (IS_ERR(rapl_mmio_priv.control_type)) {
+ pr_debug("failed to register powercap control_type.\n");
+ return PTR_ERR(rapl_mmio_priv.control_type);
+ }
+
+ ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "powercap/rapl:online",
+ rapl_mmio_cpu_online, rapl_mmio_cpu_down_prep);
+ if (ret < 0) {
+ powercap_unregister_control_type(rapl_mmio_priv.control_type);
+ return ret;
+ }
+ rapl_mmio_priv.pcap_rapl_online = ret;
+
+ return 0;
+}
+
+static void proc_thermal_rapl_remove(void)
+{
+ cpuhp_remove_state(rapl_mmio_priv.pcap_rapl_online);
+ powercap_unregister_control_type(rapl_mmio_priv.control_type);
+}
+
+static const struct rapl_mmio_regs rapl_mmio_hsw = {
+ .reg_unit = 0x5938,
+ .regs[RAPL_DOMAIN_PACKAGE] = { 0x59a0, 0x593c, 0x58f0, 0, 0x5930},
+ .regs[RAPL_DOMAIN_DRAM] = { 0x58e0, 0x58e8, 0x58ec, 0, 0},
+ .limits[RAPL_DOMAIN_PACKAGE] = 2,
+ .limits[RAPL_DOMAIN_DRAM] = 2,
+};
+
+#else
+
+static int proc_thermal_rapl_add(struct pci_dev *pdev,
+ struct proc_thermal_device *proc_priv,
+ struct rapl_mmio_regs *rapl_regs)
+{
+ return 0;
+}
+static void proc_thermal_rapl_remove(void) {}
+static const struct rapl_mmio_regs rapl_mmio_hsw;
+
+#endif /* CONFIG_MMIO_RAPL */
+
static int proc_thermal_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *unused)
+ const struct pci_device_id *id)
{
struct proc_thermal_device *proc_priv;
int ret;
@@ -378,15 +532,21 @@ static int proc_thermal_pci_probe(struct pci_dev *pdev,
return -ENODEV;
}
- ret = pci_enable_device(pdev);
+ ret = pcim_enable_device(pdev);
if (ret < 0) {
dev_err(&pdev->dev, "error: could not enable device\n");
return ret;
}
ret = proc_thermal_add(&pdev->dev, &proc_priv);
+ if (ret)
+ return ret;
+
+ ret = proc_thermal_rapl_add(pdev, proc_priv,
+ (struct rapl_mmio_regs *)id->driver_data);
if (ret) {
- pci_disable_device(pdev);
+ dev_err(&pdev->dev, "failed to add RAPL MMIO interface\n");
+ proc_thermal_remove(proc_priv);
return ret;
}
@@ -439,14 +599,31 @@ static void proc_thermal_pci_remove(struct pci_dev *pdev)
pci_disable_msi(pdev);
}
}
+ proc_thermal_rapl_remove();
proc_thermal_remove(proc_priv);
- pci_disable_device(pdev);
}
+#ifdef CONFIG_PM_SLEEP
+static int proc_thermal_resume(struct device *dev)
+{
+ struct proc_thermal_device *proc_dev;
+
+ proc_dev = dev_get_drvdata(dev);
+ proc_thermal_read_ppcc(proc_dev);
+
+ return 0;
+}
+#else
+#define proc_thermal_resume NULL
+#endif
+
+static SIMPLE_DEV_PM_OPS(proc_thermal_pm, NULL, proc_thermal_resume);
+
static const struct pci_device_id proc_thermal_pci_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BDW_THERMAL)},
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_HSB_THERMAL)},
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_SKL_THERMAL)},
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_SKL_THERMAL),
+ .driver_data = (kernel_ulong_t)&rapl_mmio_hsw, },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BSW_THERMAL)},
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BXT0_THERMAL)},
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BXT1_THERMAL)},
@@ -461,10 +638,11 @@ static const struct pci_device_id proc_thermal_pci_ids[] = {
MODULE_DEVICE_TABLE(pci, proc_thermal_pci_ids);
static struct pci_driver proc_thermal_pci_driver = {
- .name = "proc_thermal",
+ .name = DRV_NAME,
.probe = proc_thermal_pci_probe,
.remove = proc_thermal_pci_remove,
.id_table = proc_thermal_pci_ids,
+ .driver.pm = &proc_thermal_pm,
};
static const struct acpi_device_id int3401_device_ids[] = {
@@ -479,6 +657,7 @@ static struct platform_driver int3401_driver = {
.driver = {
.name = "int3401 thermal",
.acpi_match_table = int3401_device_ids,
+ .pm = &proc_thermal_pm,
},
};
diff --git a/drivers/thermal/intel/intel_powerclamp.c b/drivers/thermal/intel/intel_powerclamp.c
index 79d214b7291c..5149a817456b 100644
--- a/drivers/thermal/intel/intel_powerclamp.c
+++ b/drivers/thermal/intel/intel_powerclamp.c
@@ -698,17 +698,9 @@ DEFINE_SHOW_ATTRIBUTE(powerclamp_debug);
static inline void powerclamp_create_debug_files(void)
{
debug_dir = debugfs_create_dir("intel_powerclamp", NULL);
- if (!debug_dir)
- return;
-
- if (!debugfs_create_file("powerclamp_calib", S_IRUGO, debug_dir,
- cal_data, &powerclamp_debug_fops))
- goto file_error;
- return;
-
-file_error:
- debugfs_remove_recursive(debug_dir);
+ debugfs_create_file("powerclamp_calib", S_IRUGO, debug_dir, cal_data,
+ &powerclamp_debug_fops);
}
static enum cpuhp_state hp_state;
diff --git a/drivers/thermal/intel/x86_pkg_temp_thermal.c b/drivers/thermal/intel/x86_pkg_temp_thermal.c
index 319b77126168..ddb4a973c698 100644
--- a/drivers/thermal/intel/x86_pkg_temp_thermal.c
+++ b/drivers/thermal/intel/x86_pkg_temp_thermal.c
@@ -43,7 +43,7 @@ MODULE_PARM_DESC(notify_delay_ms,
*/
#define MAX_NUMBER_OF_TRIPS 2
-struct pkg_device {
+struct zone_device {
int cpu;
bool work_scheduled;
u32 tj_max;
@@ -58,10 +58,10 @@ static struct thermal_zone_params pkg_temp_tz_params = {
.no_hwmon = true,
};
-/* Keep track of how many package pointers we allocated in init() */
-static int max_packages __read_mostly;
-/* Array of package pointers */
-static struct pkg_device **packages;
+/* Keep track of how many zone pointers we allocated in init() */
+static int max_id __read_mostly;
+/* Array of zone pointers */
+static struct zone_device **zones;
/* Serializes interrupt notification, work and hotplug */
static DEFINE_SPINLOCK(pkg_temp_lock);
/* Protects zone operation in the work function against hotplug removal */
@@ -75,29 +75,14 @@ static struct dentry *debugfs;
static unsigned int pkg_interrupt_cnt;
static unsigned int pkg_work_cnt;
-static int pkg_temp_debugfs_init(void)
+static void pkg_temp_debugfs_init(void)
{
- struct dentry *d;
-
debugfs = debugfs_create_dir("pkg_temp_thermal", NULL);
- if (!debugfs)
- return -ENOENT;
-
- d = debugfs_create_u32("pkg_thres_interrupt", S_IRUGO, debugfs,
- &pkg_interrupt_cnt);
- if (!d)
- goto err_out;
-
- d = debugfs_create_u32("pkg_thres_work", S_IRUGO, debugfs,
- &pkg_work_cnt);
- if (!d)
- goto err_out;
- return 0;
-
-err_out:
- debugfs_remove_recursive(debugfs);
- return -ENOENT;
+ debugfs_create_u32("pkg_thres_interrupt", S_IRUGO, debugfs,
+ &pkg_interrupt_cnt);
+ debugfs_create_u32("pkg_thres_work", S_IRUGO, debugfs,
+ &pkg_work_cnt);
}
/*
@@ -108,12 +93,12 @@ err_out:
*
* - Other callsites: Must hold pkg_temp_lock
*/
-static struct pkg_device *pkg_temp_thermal_get_dev(unsigned int cpu)
+static struct zone_device *pkg_temp_thermal_get_dev(unsigned int cpu)
{
- int pkgid = topology_logical_package_id(cpu);
+ int id = topology_logical_die_id(cpu);
- if (pkgid >= 0 && pkgid < max_packages)
- return packages[pkgid];
+ if (id >= 0 && id < max_id)
+ return zones[id];
return NULL;
}
@@ -138,12 +123,13 @@ static int get_tj_max(int cpu, u32 *tj_max)
static int sys_get_curr_temp(struct thermal_zone_device *tzd, int *temp)
{
- struct pkg_device *pkgdev = tzd->devdata;
+ struct zone_device *zonedev = tzd->devdata;
u32 eax, edx;
- rdmsr_on_cpu(pkgdev->cpu, MSR_IA32_PACKAGE_THERM_STATUS, &eax, &edx);
+ rdmsr_on_cpu(zonedev->cpu, MSR_IA32_PACKAGE_THERM_STATUS,
+ &eax, &edx);
if (eax & 0x80000000) {
- *temp = pkgdev->tj_max - ((eax >> 16) & 0x7f) * 1000;
+ *temp = zonedev->tj_max - ((eax >> 16) & 0x7f) * 1000;
pr_debug("sys_get_curr_temp %d\n", *temp);
return 0;
}
@@ -153,7 +139,7 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd, int *temp)
static int sys_get_trip_temp(struct thermal_zone_device *tzd,
int trip, int *temp)
{
- struct pkg_device *pkgdev = tzd->devdata;
+ struct zone_device *zonedev = tzd->devdata;
unsigned long thres_reg_value;
u32 mask, shift, eax, edx;
int ret;
@@ -169,14 +155,14 @@ static int sys_get_trip_temp(struct thermal_zone_device *tzd,
shift = THERM_SHIFT_THRESHOLD0;
}
- ret = rdmsr_on_cpu(pkgdev->cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT,
+ ret = rdmsr_on_cpu(zonedev->cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT,
&eax, &edx);
if (ret < 0)
return ret;
thres_reg_value = (eax & mask) >> shift;
if (thres_reg_value)
- *temp = pkgdev->tj_max - thres_reg_value * 1000;
+ *temp = zonedev->tj_max - thres_reg_value * 1000;
else
*temp = 0;
pr_debug("sys_get_trip_temp %d\n", *temp);
@@ -187,14 +173,14 @@ static int sys_get_trip_temp(struct thermal_zone_device *tzd,
static int
sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, int temp)
{
- struct pkg_device *pkgdev = tzd->devdata;
+ struct zone_device *zonedev = tzd->devdata;
u32 l, h, mask, shift, intr;
int ret;
- if (trip >= MAX_NUMBER_OF_TRIPS || temp >= pkgdev->tj_max)
+ if (trip >= MAX_NUMBER_OF_TRIPS || temp >= zonedev->tj_max)
return -EINVAL;
- ret = rdmsr_on_cpu(pkgdev->cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT,
+ ret = rdmsr_on_cpu(zonedev->cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT,
&l, &h);
if (ret < 0)
return ret;
@@ -216,11 +202,12 @@ sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, int temp)
if (!temp) {
l &= ~intr;
} else {
- l |= (pkgdev->tj_max - temp)/1000 << shift;
+ l |= (zonedev->tj_max - temp)/1000 << shift;
l |= intr;
}
- return wrmsr_on_cpu(pkgdev->cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
+ return wrmsr_on_cpu(zonedev->cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT,
+ l, h);
}
static int sys_get_trip_type(struct thermal_zone_device *thermal, int trip,
@@ -275,26 +262,26 @@ static void pkg_temp_thermal_threshold_work_fn(struct work_struct *work)
{
struct thermal_zone_device *tzone = NULL;
int cpu = smp_processor_id();
- struct pkg_device *pkgdev;
+ struct zone_device *zonedev;
u64 msr_val, wr_val;
mutex_lock(&thermal_zone_mutex);
spin_lock_irq(&pkg_temp_lock);
++pkg_work_cnt;
- pkgdev = pkg_temp_thermal_get_dev(cpu);
- if (!pkgdev) {
+ zonedev = pkg_temp_thermal_get_dev(cpu);
+ if (!zonedev) {
spin_unlock_irq(&pkg_temp_lock);
mutex_unlock(&thermal_zone_mutex);
return;
}
- pkgdev->work_scheduled = false;
+ zonedev->work_scheduled = false;
rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_val);
wr_val = msr_val & ~(THERM_LOG_THRESHOLD0 | THERM_LOG_THRESHOLD1);
if (wr_val != msr_val) {
wrmsrl(MSR_IA32_PACKAGE_THERM_STATUS, wr_val);
- tzone = pkgdev->tzone;
+ tzone = zonedev->tzone;
}
enable_pkg_thres_interrupt();
@@ -320,7 +307,7 @@ static void pkg_thermal_schedule_work(int cpu, struct delayed_work *work)
static int pkg_thermal_notify(u64 msr_val)
{
int cpu = smp_processor_id();
- struct pkg_device *pkgdev;
+ struct zone_device *zonedev;
unsigned long flags;
spin_lock_irqsave(&pkg_temp_lock, flags);
@@ -329,10 +316,10 @@ static int pkg_thermal_notify(u64 msr_val)
disable_pkg_thres_interrupt();
/* Work is per package, so scheduling it once is enough. */
- pkgdev = pkg_temp_thermal_get_dev(cpu);
- if (pkgdev && !pkgdev->work_scheduled) {
- pkgdev->work_scheduled = true;
- pkg_thermal_schedule_work(pkgdev->cpu, &pkgdev->work);
+ zonedev = pkg_temp_thermal_get_dev(cpu);
+ if (zonedev && !zonedev->work_scheduled) {
+ zonedev->work_scheduled = true;
+ pkg_thermal_schedule_work(zonedev->cpu, &zonedev->work);
}
spin_unlock_irqrestore(&pkg_temp_lock, flags);
@@ -341,12 +328,12 @@ static int pkg_thermal_notify(u64 msr_val)
static int pkg_temp_thermal_device_add(unsigned int cpu)
{
- int pkgid = topology_logical_package_id(cpu);
+ int id = topology_logical_die_id(cpu);
u32 tj_max, eax, ebx, ecx, edx;
- struct pkg_device *pkgdev;
+ struct zone_device *zonedev;
int thres_count, err;
- if (pkgid >= max_packages)
+ if (id >= max_id)
return -ENOMEM;
cpuid(6, &eax, &ebx, &ecx, &edx);
@@ -360,51 +347,51 @@ static int pkg_temp_thermal_device_add(unsigned int cpu)
if (err)
return err;
- pkgdev = kzalloc(sizeof(*pkgdev), GFP_KERNEL);
- if (!pkgdev)
+ zonedev = kzalloc(sizeof(*zonedev), GFP_KERNEL);
+ if (!zonedev)
return -ENOMEM;
- INIT_DELAYED_WORK(&pkgdev->work, pkg_temp_thermal_threshold_work_fn);
- pkgdev->cpu = cpu;
- pkgdev->tj_max = tj_max;
- pkgdev->tzone = thermal_zone_device_register("x86_pkg_temp",
+ INIT_DELAYED_WORK(&zonedev->work, pkg_temp_thermal_threshold_work_fn);
+ zonedev->cpu = cpu;
+ zonedev->tj_max = tj_max;
+ zonedev->tzone = thermal_zone_device_register("x86_pkg_temp",
thres_count,
(thres_count == MAX_NUMBER_OF_TRIPS) ? 0x03 : 0x01,
- pkgdev, &tzone_ops, &pkg_temp_tz_params, 0, 0);
- if (IS_ERR(pkgdev->tzone)) {
- err = PTR_ERR(pkgdev->tzone);
- kfree(pkgdev);
+ zonedev, &tzone_ops, &pkg_temp_tz_params, 0, 0);
+ if (IS_ERR(zonedev->tzone)) {
+ err = PTR_ERR(zonedev->tzone);
+ kfree(zonedev);
return err;
}
/* Store MSR value for package thermal interrupt, to restore at exit */
- rdmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, pkgdev->msr_pkg_therm_low,
- pkgdev->msr_pkg_therm_high);
+ rdmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, zonedev->msr_pkg_therm_low,
+ zonedev->msr_pkg_therm_high);
- cpumask_set_cpu(cpu, &pkgdev->cpumask);
+ cpumask_set_cpu(cpu, &zonedev->cpumask);
spin_lock_irq(&pkg_temp_lock);
- packages[pkgid] = pkgdev;
+ zones[id] = zonedev;
spin_unlock_irq(&pkg_temp_lock);
return 0;
}
static int pkg_thermal_cpu_offline(unsigned int cpu)
{
- struct pkg_device *pkgdev = pkg_temp_thermal_get_dev(cpu);
+ struct zone_device *zonedev = pkg_temp_thermal_get_dev(cpu);
bool lastcpu, was_target;
int target;
- if (!pkgdev)
+ if (!zonedev)
return 0;
- target = cpumask_any_but(&pkgdev->cpumask, cpu);
- cpumask_clear_cpu(cpu, &pkgdev->cpumask);
+ target = cpumask_any_but(&zonedev->cpumask, cpu);
+ cpumask_clear_cpu(cpu, &zonedev->cpumask);
lastcpu = target >= nr_cpu_ids;
/*
* Remove the sysfs files, if this is the last cpu in the package
* before doing further cleanups.
*/
if (lastcpu) {
- struct thermal_zone_device *tzone = pkgdev->tzone;
+ struct thermal_zone_device *tzone = zonedev->tzone;
/*
* We must protect against a work function calling
@@ -413,7 +400,7 @@ static int pkg_thermal_cpu_offline(unsigned int cpu)
* won't try to call.
*/
mutex_lock(&thermal_zone_mutex);
- pkgdev->tzone = NULL;
+ zonedev->tzone = NULL;
mutex_unlock(&thermal_zone_mutex);
thermal_zone_device_unregister(tzone);
@@ -427,8 +414,8 @@ static int pkg_thermal_cpu_offline(unsigned int cpu)
* one. When we drop the lock, then the interrupt notify function
* will see the new target.
*/
- was_target = pkgdev->cpu == cpu;
- pkgdev->cpu = target;
+ was_target = zonedev->cpu == cpu;
+ zonedev->cpu = target;
/*
* If this is the last CPU in the package remove the package
@@ -437,23 +424,23 @@ static int pkg_thermal_cpu_offline(unsigned int cpu)
* worker will see the package anymore.
*/
if (lastcpu) {
- packages[topology_logical_package_id(cpu)] = NULL;
+ zones[topology_logical_die_id(cpu)] = NULL;
/* After this point nothing touches the MSR anymore. */
wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT,
- pkgdev->msr_pkg_therm_low, pkgdev->msr_pkg_therm_high);
+ zonedev->msr_pkg_therm_low, zonedev->msr_pkg_therm_high);
}
/*
* Check whether there is work scheduled and whether the work is
* targeted at the outgoing CPU.
*/
- if (pkgdev->work_scheduled && was_target) {
+ if (zonedev->work_scheduled && was_target) {
/*
* To cancel the work we need to drop the lock, otherwise
* we might deadlock if the work needs to be flushed.
*/
spin_unlock_irq(&pkg_temp_lock);
- cancel_delayed_work_sync(&pkgdev->work);
+ cancel_delayed_work_sync(&zonedev->work);
spin_lock_irq(&pkg_temp_lock);
/*
* If this is not the last cpu in the package and the work
@@ -461,21 +448,21 @@ static int pkg_thermal_cpu_offline(unsigned int cpu)
* need to reschedule the work, otherwise the interrupt
* stays disabled forever.
*/
- if (!lastcpu && pkgdev->work_scheduled)
- pkg_thermal_schedule_work(target, &pkgdev->work);
+ if (!lastcpu && zonedev->work_scheduled)
+ pkg_thermal_schedule_work(target, &zonedev->work);
}
spin_unlock_irq(&pkg_temp_lock);
/* Final cleanup if this is the last cpu */
if (lastcpu)
- kfree(pkgdev);
+ kfree(zonedev);
return 0;
}
static int pkg_thermal_cpu_online(unsigned int cpu)
{
- struct pkg_device *pkgdev = pkg_temp_thermal_get_dev(cpu);
+ struct zone_device *zonedev = pkg_temp_thermal_get_dev(cpu);
struct cpuinfo_x86 *c = &cpu_data(cpu);
/* Paranoia check */
@@ -483,8 +470,8 @@ static int pkg_thermal_cpu_online(unsigned int cpu)
return -ENODEV;
/* If the package exists, nothing to do */
- if (pkgdev) {
- cpumask_set_cpu(cpu, &pkgdev->cpumask);
+ if (zonedev) {
+ cpumask_set_cpu(cpu, &zonedev->cpumask);
return 0;
}
return pkg_temp_thermal_device_add(cpu);
@@ -503,10 +490,10 @@ static int __init pkg_temp_thermal_init(void)
if (!x86_match_cpu(pkg_temp_thermal_ids))
return -ENODEV;
- max_packages = topology_max_packages();
- packages = kcalloc(max_packages, sizeof(struct pkg_device *),
+ max_id = topology_max_packages() * topology_max_die_per_package();
+ zones = kcalloc(max_id, sizeof(struct zone_device *),
GFP_KERNEL);
- if (!packages)
+ if (!zones)
return -ENOMEM;
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "thermal/x86_pkg:online",
@@ -525,7 +512,7 @@ static int __init pkg_temp_thermal_init(void)
return 0;
err:
- kfree(packages);
+ kfree(zones);
return ret;
}
module_init(pkg_temp_thermal_init)
@@ -537,7 +524,7 @@ static void __exit pkg_temp_thermal_exit(void)
cpuhp_remove_state(pkg_thermal_hp_state);
debugfs_remove_recursive(debugfs);
- kfree(packages);
+ kfree(zones);
}
module_exit(pkg_temp_thermal_exit)
diff --git a/drivers/thermal/power_allocator.c b/drivers/thermal/power_allocator.c
index 3055f9a12a17..44636475b2a3 100644
--- a/drivers/thermal/power_allocator.c
+++ b/drivers/thermal/power_allocator.c
@@ -651,13 +651,4 @@ static struct thermal_governor thermal_gov_power_allocator = {
.unbind_from_tz = power_allocator_unbind,
.throttle = power_allocator_throttle,
};
-
-int thermal_gov_power_allocator_register(void)
-{
- return thermal_register_governor(&thermal_gov_power_allocator);
-}
-
-void thermal_gov_power_allocator_unregister(void)
-{
- thermal_unregister_governor(&thermal_gov_power_allocator);
-}
+THERMAL_GOVERNOR_DECLARE(thermal_gov_power_allocator);
diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c
index 81a183befd48..6e051cbd824f 100644
--- a/drivers/thermal/step_wise.c
+++ b/drivers/thermal/step_wise.c
@@ -206,13 +206,4 @@ static struct thermal_governor thermal_gov_step_wise = {
.name = "step_wise",
.throttle = step_wise_throttle,
};
-
-int thermal_gov_step_wise_register(void)
-{
- return thermal_register_governor(&thermal_gov_step_wise);
-}
-
-void thermal_gov_step_wise_unregister(void)
-{
- thermal_unregister_governor(&thermal_gov_step_wise);
-}
+THERMAL_GOVERNOR_DECLARE(thermal_gov_step_wise);
diff --git a/drivers/thermal/tegra/soctherm.c b/drivers/thermal/tegra/soctherm.c
index fcf70a3728b6..43941eb734eb 100644
--- a/drivers/thermal/tegra/soctherm.c
+++ b/drivers/thermal/tegra/soctherm.c
@@ -1485,23 +1485,13 @@ DEFINE_SHOW_ATTRIBUTE(regs);
static void soctherm_debug_init(struct platform_device *pdev)
{
struct tegra_soctherm *tegra = platform_get_drvdata(pdev);
- struct dentry *root, *file;
+ struct dentry *root;
root = debugfs_create_dir("soctherm", NULL);
- if (!root) {
- dev_err(&pdev->dev, "failed to create debugfs directory\n");
- return;
- }
tegra->debugfs_dir = root;
- file = debugfs_create_file("reg_contents", 0644, root,
- pdev, &regs_fops);
- if (!file) {
- dev_err(&pdev->dev, "failed to create debugfs file\n");
- debugfs_remove_recursive(tegra->debugfs_dir);
- tegra->debugfs_dir = NULL;
- }
+ debugfs_create_file("reg_contents", 0644, root, pdev, &regs_fops);
}
#else
static inline void soctherm_debug_init(struct platform_device *pdev) {}
diff --git a/drivers/thermal/thermal-generic-adc.c b/drivers/thermal/thermal-generic-adc.c
index deb244f12de4..dcecf2e8dc8e 100644
--- a/drivers/thermal/thermal-generic-adc.c
+++ b/drivers/thermal/thermal-generic-adc.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic ADC thermal driver
*
* Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved.
*
* Author: Laxman Dewangan <ldewangan@nvidia.com>
- *
- * 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.
*/
#include <linux/iio/consumer.h>
#include <linux/kernel.h>
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 46cfb7de4eb2..6bab66e84eb5 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -243,36 +243,42 @@ int thermal_build_list_of_policies(char *buf)
return count;
}
-static int __init thermal_register_governors(void)
+static void __init thermal_unregister_governors(void)
{
- int result;
+ struct thermal_governor **governor;
- result = thermal_gov_step_wise_register();
- if (result)
- return result;
+ for_each_governor_table(governor)
+ thermal_unregister_governor(*governor);
+}
- result = thermal_gov_fair_share_register();
- if (result)
- return result;
+static int __init thermal_register_governors(void)
+{
+ int ret = 0;
+ struct thermal_governor **governor;
- result = thermal_gov_bang_bang_register();
- if (result)
- return result;
+ for_each_governor_table(governor) {
+ ret = thermal_register_governor(*governor);
+ if (ret) {
+ pr_err("Failed to register governor: '%s'",
+ (*governor)->name);
+ break;
+ }
- result = thermal_gov_user_space_register();
- if (result)
- return result;
+ pr_info("Registered thermal governor '%s'",
+ (*governor)->name);
+ }
- return thermal_gov_power_allocator_register();
-}
+ if (ret) {
+ struct thermal_governor **gov;
-static void __init thermal_unregister_governors(void)
-{
- thermal_gov_step_wise_unregister();
- thermal_gov_fair_share_unregister();
- thermal_gov_bang_bang_unregister();
- thermal_gov_user_space_unregister();
- thermal_gov_power_allocator_unregister();
+ for_each_governor_table(gov) {
+ if (gov == governor)
+ break;
+ thermal_unregister_governor(*gov);
+ }
+ }
+
+ return ret;
}
/*
diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
index 0df190ed82a7..207b0cda70da 100644
--- a/drivers/thermal/thermal_core.h
+++ b/drivers/thermal/thermal_core.h
@@ -15,6 +15,21 @@
/* Initial state of a cooling device during binding */
#define THERMAL_NO_TARGET -1UL
+/* Init section thermal table */
+extern struct thermal_governor *__governor_thermal_table[];
+extern struct thermal_governor *__governor_thermal_table_end[];
+
+#define THERMAL_TABLE_ENTRY(table, name) \
+ static typeof(name) *__thermal_table_entry_##name \
+ __used __section(__##table##_thermal_table) = &name
+
+#define THERMAL_GOVERNOR_DECLARE(name) THERMAL_TABLE_ENTRY(governor, name)
+
+#define for_each_governor_table(__governor) \
+ for (__governor = __governor_thermal_table; \
+ __governor < __governor_thermal_table_end; \
+ __governor++)
+
/*
* This structure is used to describe the behavior of
* a certain cooling device on a certain trip point
@@ -74,46 +89,6 @@ thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev,
unsigned long new_state) {}
#endif /* CONFIG_THERMAL_STATISTICS */
-#ifdef CONFIG_THERMAL_GOV_STEP_WISE
-int thermal_gov_step_wise_register(void);
-void thermal_gov_step_wise_unregister(void);
-#else
-static inline int thermal_gov_step_wise_register(void) { return 0; }
-static inline void thermal_gov_step_wise_unregister(void) {}
-#endif /* CONFIG_THERMAL_GOV_STEP_WISE */
-
-#ifdef CONFIG_THERMAL_GOV_FAIR_SHARE
-int thermal_gov_fair_share_register(void);
-void thermal_gov_fair_share_unregister(void);
-#else
-static inline int thermal_gov_fair_share_register(void) { return 0; }
-static inline void thermal_gov_fair_share_unregister(void) {}
-#endif /* CONFIG_THERMAL_GOV_FAIR_SHARE */
-
-#ifdef CONFIG_THERMAL_GOV_BANG_BANG
-int thermal_gov_bang_bang_register(void);
-void thermal_gov_bang_bang_unregister(void);
-#else
-static inline int thermal_gov_bang_bang_register(void) { return 0; }
-static inline void thermal_gov_bang_bang_unregister(void) {}
-#endif /* CONFIG_THERMAL_GOV_BANG_BANG */
-
-#ifdef CONFIG_THERMAL_GOV_USER_SPACE
-int thermal_gov_user_space_register(void);
-void thermal_gov_user_space_unregister(void);
-#else
-static inline int thermal_gov_user_space_register(void) { return 0; }
-static inline void thermal_gov_user_space_unregister(void) {}
-#endif /* CONFIG_THERMAL_GOV_USER_SPACE */
-
-#ifdef CONFIG_THERMAL_GOV_POWER_ALLOCATOR
-int thermal_gov_power_allocator_register(void);
-void thermal_gov_power_allocator_unregister(void);
-#else
-static inline int thermal_gov_power_allocator_register(void) { return 0; }
-static inline void thermal_gov_power_allocator_unregister(void) {}
-#endif /* CONFIG_THERMAL_GOV_POWER_ALLOCATOR */
-
/* device tree support */
#ifdef CONFIG_THERMAL_OF
int of_parse_thermal_zones(void);
diff --git a/drivers/thermal/user_space.c b/drivers/thermal/user_space.c
index d62a99fc60a6..962873fd9242 100644
--- a/drivers/thermal/user_space.c
+++ b/drivers/thermal/user_space.c
@@ -44,14 +44,4 @@ static struct thermal_governor thermal_gov_user_space = {
.name = "user_space",
.throttle = notify_user_space,
};
-
-int thermal_gov_user_space_register(void)
-{
- return thermal_register_governor(&thermal_gov_user_space);
-}
-
-void thermal_gov_user_space_unregister(void)
-{
- thermal_unregister_governor(&thermal_gov_user_space);
-}
-
+THERMAL_GOVERNOR_DECLARE(thermal_gov_user_space);
diff --git a/drivers/thunderbolt/icm.c b/drivers/thunderbolt/icm.c
index f1c10378fa3e..fbdcef56a676 100644
--- a/drivers/thunderbolt/icm.c
+++ b/drivers/thunderbolt/icm.c
@@ -56,6 +56,7 @@
* @max_boot_acl: Maximum number of preboot ACL entries (%0 if not supported)
* @rpm: Does the controller support runtime PM (RTD3)
* @is_supported: Checks if we can support ICM on this controller
+ * @cio_reset: Trigger CIO reset
* @get_mode: Read and return the ICM firmware mode (optional)
* @get_route: Find a route string for given switch
* @save_devices: Ask ICM to save devices to ACL when suspending (optional)
@@ -74,6 +75,7 @@ struct icm {
bool safe_mode;
bool rpm;
bool (*is_supported)(struct tb *tb);
+ int (*cio_reset)(struct tb *tb);
int (*get_mode)(struct tb *tb);
int (*get_route)(struct tb *tb, u8 link, u8 depth, u64 *route);
void (*save_devices)(struct tb *tb);
@@ -166,6 +168,65 @@ static inline u64 get_parent_route(u64 route)
return depth ? route & ~(0xffULL << (depth - 1) * TB_ROUTE_SHIFT) : 0;
}
+static int pci2cio_wait_completion(struct icm *icm, unsigned long timeout_msec)
+{
+ unsigned long end = jiffies + msecs_to_jiffies(timeout_msec);
+ u32 cmd;
+
+ do {
+ pci_read_config_dword(icm->upstream_port,
+ icm->vnd_cap + PCIE2CIO_CMD, &cmd);
+ if (!(cmd & PCIE2CIO_CMD_START)) {
+ if (cmd & PCIE2CIO_CMD_TIMEOUT)
+ break;
+ return 0;
+ }
+
+ msleep(50);
+ } while (time_before(jiffies, end));
+
+ return -ETIMEDOUT;
+}
+
+static int pcie2cio_read(struct icm *icm, enum tb_cfg_space cs,
+ unsigned int port, unsigned int index, u32 *data)
+{
+ struct pci_dev *pdev = icm->upstream_port;
+ int ret, vnd_cap = icm->vnd_cap;
+ u32 cmd;
+
+ cmd = index;
+ cmd |= (port << PCIE2CIO_CMD_PORT_SHIFT) & PCIE2CIO_CMD_PORT_MASK;
+ cmd |= (cs << PCIE2CIO_CMD_CS_SHIFT) & PCIE2CIO_CMD_CS_MASK;
+ cmd |= PCIE2CIO_CMD_START;
+ pci_write_config_dword(pdev, vnd_cap + PCIE2CIO_CMD, cmd);
+
+ ret = pci2cio_wait_completion(icm, 5000);
+ if (ret)
+ return ret;
+
+ pci_read_config_dword(pdev, vnd_cap + PCIE2CIO_RDDATA, data);
+ return 0;
+}
+
+static int pcie2cio_write(struct icm *icm, enum tb_cfg_space cs,
+ unsigned int port, unsigned int index, u32 data)
+{
+ struct pci_dev *pdev = icm->upstream_port;
+ int vnd_cap = icm->vnd_cap;
+ u32 cmd;
+
+ pci_write_config_dword(pdev, vnd_cap + PCIE2CIO_WRDATA, data);
+
+ cmd = index;
+ cmd |= (port << PCIE2CIO_CMD_PORT_SHIFT) & PCIE2CIO_CMD_PORT_MASK;
+ cmd |= (cs << PCIE2CIO_CMD_CS_SHIFT) & PCIE2CIO_CMD_CS_MASK;
+ cmd |= PCIE2CIO_CMD_WRITE | PCIE2CIO_CMD_START;
+ pci_write_config_dword(pdev, vnd_cap + PCIE2CIO_CMD, cmd);
+
+ return pci2cio_wait_completion(icm, 5000);
+}
+
static bool icm_match(const struct tb_cfg_request *req,
const struct ctl_pkg *pkg)
{
@@ -484,6 +545,7 @@ static void add_switch(struct tb_switch *parent_sw, u64 route,
sw->authorized = authorized;
sw->security_level = security_level;
sw->boot = boot;
+ init_completion(&sw->rpm_complete);
vss = parse_intel_vss(ep_name, ep_name_size);
if (vss)
@@ -523,6 +585,9 @@ static void update_switch(struct tb_switch *parent_sw, struct tb_switch *sw,
/* This switch still exists */
sw->is_unplugged = false;
+
+ /* Runtime resume is now complete */
+ complete(&sw->rpm_complete);
}
static void remove_switch(struct tb_switch *sw)
@@ -834,6 +899,11 @@ icm_fr_xdomain_disconnected(struct tb *tb, const struct icm_pkg_header *hdr)
}
}
+static int icm_tr_cio_reset(struct tb *tb)
+{
+ return pcie2cio_write(tb_priv(tb), TB_CFG_SWITCH, 0, 0x777, BIT(1));
+}
+
static int
icm_tr_driver_ready(struct tb *tb, enum tb_security_level *security_level,
size_t *nboot_acl, bool *rpm)
@@ -1240,6 +1310,11 @@ static bool icm_ar_is_supported(struct tb *tb)
return false;
}
+static int icm_ar_cio_reset(struct tb *tb)
+{
+ return pcie2cio_write(tb_priv(tb), TB_CFG_SWITCH, 0, 0x50, BIT(9));
+}
+
static int icm_ar_get_mode(struct tb *tb)
{
struct tb_nhi *nhi = tb->nhi;
@@ -1477,65 +1552,6 @@ __icm_driver_ready(struct tb *tb, enum tb_security_level *security_level,
return -ETIMEDOUT;
}
-static int pci2cio_wait_completion(struct icm *icm, unsigned long timeout_msec)
-{
- unsigned long end = jiffies + msecs_to_jiffies(timeout_msec);
- u32 cmd;
-
- do {
- pci_read_config_dword(icm->upstream_port,
- icm->vnd_cap + PCIE2CIO_CMD, &cmd);
- if (!(cmd & PCIE2CIO_CMD_START)) {
- if (cmd & PCIE2CIO_CMD_TIMEOUT)
- break;
- return 0;
- }
-
- msleep(50);
- } while (time_before(jiffies, end));
-
- return -ETIMEDOUT;
-}
-
-static int pcie2cio_read(struct icm *icm, enum tb_cfg_space cs,
- unsigned int port, unsigned int index, u32 *data)
-{
- struct pci_dev *pdev = icm->upstream_port;
- int ret, vnd_cap = icm->vnd_cap;
- u32 cmd;
-
- cmd = index;
- cmd |= (port << PCIE2CIO_CMD_PORT_SHIFT) & PCIE2CIO_CMD_PORT_MASK;
- cmd |= (cs << PCIE2CIO_CMD_CS_SHIFT) & PCIE2CIO_CMD_CS_MASK;
- cmd |= PCIE2CIO_CMD_START;
- pci_write_config_dword(pdev, vnd_cap + PCIE2CIO_CMD, cmd);
-
- ret = pci2cio_wait_completion(icm, 5000);
- if (ret)
- return ret;
-
- pci_read_config_dword(pdev, vnd_cap + PCIE2CIO_RDDATA, data);
- return 0;
-}
-
-static int pcie2cio_write(struct icm *icm, enum tb_cfg_space cs,
- unsigned int port, unsigned int index, u32 data)
-{
- struct pci_dev *pdev = icm->upstream_port;
- int vnd_cap = icm->vnd_cap;
- u32 cmd;
-
- pci_write_config_dword(pdev, vnd_cap + PCIE2CIO_WRDATA, data);
-
- cmd = index;
- cmd |= (port << PCIE2CIO_CMD_PORT_SHIFT) & PCIE2CIO_CMD_PORT_MASK;
- cmd |= (cs << PCIE2CIO_CMD_CS_SHIFT) & PCIE2CIO_CMD_CS_MASK;
- cmd |= PCIE2CIO_CMD_WRITE | PCIE2CIO_CMD_START;
- pci_write_config_dword(pdev, vnd_cap + PCIE2CIO_CMD, cmd);
-
- return pci2cio_wait_completion(icm, 5000);
-}
-
static int icm_firmware_reset(struct tb *tb, struct tb_nhi *nhi)
{
struct icm *icm = tb_priv(tb);
@@ -1556,7 +1572,7 @@ static int icm_firmware_reset(struct tb *tb, struct tb_nhi *nhi)
iowrite32(val, nhi->iobase + REG_FW_STS);
/* Trigger CIO reset now */
- return pcie2cio_write(icm, TB_CFG_SWITCH, 0, 0x50, BIT(9));
+ return icm->cio_reset(tb);
}
static int icm_firmware_start(struct tb *tb, struct tb_nhi *nhi)
@@ -1770,6 +1786,32 @@ static void icm_unplug_children(struct tb_switch *sw)
}
}
+static int complete_rpm(struct device *dev, void *data)
+{
+ struct tb_switch *sw = tb_to_switch(dev);
+
+ if (sw)
+ complete(&sw->rpm_complete);
+ return 0;
+}
+
+static void remove_unplugged_switch(struct tb_switch *sw)
+{
+ pm_runtime_get_sync(sw->dev.parent);
+
+ /*
+ * Signal this and switches below for rpm_complete because
+ * tb_switch_remove() calls pm_runtime_get_sync() that then waits
+ * for it.
+ */
+ complete_rpm(&sw->dev, NULL);
+ bus_for_each_dev(&tb_bus_type, &sw->dev, NULL, complete_rpm);
+ tb_switch_remove(sw);
+
+ pm_runtime_mark_last_busy(sw->dev.parent);
+ pm_runtime_put_autosuspend(sw->dev.parent);
+}
+
static void icm_free_unplugged_children(struct tb_switch *sw)
{
unsigned int i;
@@ -1782,7 +1824,7 @@ static void icm_free_unplugged_children(struct tb_switch *sw)
port->xdomain = NULL;
} else if (tb_port_has_remote(port)) {
if (port->remote->sw->is_unplugged) {
- tb_switch_remove(port->remote->sw);
+ remove_unplugged_switch(port->remote->sw);
port->remote = NULL;
} else {
icm_free_unplugged_children(port->remote->sw);
@@ -1831,6 +1873,24 @@ static int icm_runtime_suspend(struct tb *tb)
return 0;
}
+static int icm_runtime_suspend_switch(struct tb_switch *sw)
+{
+ if (tb_route(sw))
+ reinit_completion(&sw->rpm_complete);
+ return 0;
+}
+
+static int icm_runtime_resume_switch(struct tb_switch *sw)
+{
+ if (tb_route(sw)) {
+ if (!wait_for_completion_timeout(&sw->rpm_complete,
+ msecs_to_jiffies(500))) {
+ dev_dbg(&sw->dev, "runtime resuming timed out\n");
+ }
+ }
+ return 0;
+}
+
static int icm_runtime_resume(struct tb *tb)
{
/*
@@ -1910,6 +1970,8 @@ static const struct tb_cm_ops icm_ar_ops = {
.complete = icm_complete,
.runtime_suspend = icm_runtime_suspend,
.runtime_resume = icm_runtime_resume,
+ .runtime_suspend_switch = icm_runtime_suspend_switch,
+ .runtime_resume_switch = icm_runtime_resume_switch,
.handle_event = icm_handle_event,
.get_boot_acl = icm_ar_get_boot_acl,
.set_boot_acl = icm_ar_set_boot_acl,
@@ -1930,6 +1992,8 @@ static const struct tb_cm_ops icm_tr_ops = {
.complete = icm_complete,
.runtime_suspend = icm_runtime_suspend,
.runtime_resume = icm_runtime_resume,
+ .runtime_suspend_switch = icm_runtime_suspend_switch,
+ .runtime_resume_switch = icm_runtime_resume_switch,
.handle_event = icm_handle_event,
.get_boot_acl = icm_ar_get_boot_acl,
.set_boot_acl = icm_ar_set_boot_acl,
@@ -1975,6 +2039,7 @@ struct tb *icm_probe(struct tb_nhi *nhi)
case PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_2C_NHI:
icm->max_boot_acl = ICM_AR_PREBOOT_ACL_ENTRIES;
icm->is_supported = icm_ar_is_supported;
+ icm->cio_reset = icm_ar_cio_reset;
icm->get_mode = icm_ar_get_mode;
icm->get_route = icm_ar_get_route;
icm->save_devices = icm_fr_save_devices;
@@ -1990,6 +2055,7 @@ struct tb *icm_probe(struct tb_nhi *nhi)
case PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_NHI:
icm->max_boot_acl = ICM_AR_PREBOOT_ACL_ENTRIES;
icm->is_supported = icm_ar_is_supported;
+ icm->cio_reset = icm_tr_cio_reset;
icm->get_mode = icm_ar_get_mode;
icm->driver_ready = icm_tr_driver_ready;
icm->device_connected = icm_tr_device_connected;
diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index c1b016574fb4..5668a44e0653 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -239,7 +239,16 @@ static int tb_switch_nvm_read(void *priv, unsigned int offset, void *val,
int ret;
pm_runtime_get_sync(&sw->dev);
+
+ if (!mutex_trylock(&sw->tb->lock)) {
+ ret = restart_syscall();
+ goto out;
+ }
+
ret = dma_port_flash_read(sw->dma_port, offset, val, bytes);
+ mutex_unlock(&sw->tb->lock);
+
+out:
pm_runtime_mark_last_busy(&sw->dev);
pm_runtime_put_autosuspend(&sw->dev);
@@ -1019,7 +1028,6 @@ static int tb_switch_set_authorized(struct tb_switch *sw, unsigned int val)
* the new tunnel too early.
*/
pci_lock_rescan_remove();
- pm_runtime_get_sync(&sw->dev);
switch (val) {
/* Approve switch */
@@ -1040,8 +1048,6 @@ static int tb_switch_set_authorized(struct tb_switch *sw, unsigned int val)
break;
}
- pm_runtime_mark_last_busy(&sw->dev);
- pm_runtime_put_autosuspend(&sw->dev);
pci_unlock_rescan_remove();
if (!ret) {
@@ -1069,7 +1075,10 @@ static ssize_t authorized_store(struct device *dev,
if (val > 2)
return -EINVAL;
+ pm_runtime_get_sync(&sw->dev);
ret = tb_switch_set_authorized(sw, val);
+ pm_runtime_mark_last_busy(&sw->dev);
+ pm_runtime_put_autosuspend(&sw->dev);
return ret ? ret : count;
}
@@ -1195,8 +1204,12 @@ static ssize_t nvm_authenticate_store(struct device *dev,
bool val;
int ret;
- if (!mutex_trylock(&sw->tb->lock))
- return restart_syscall();
+ pm_runtime_get_sync(&sw->dev);
+
+ if (!mutex_trylock(&sw->tb->lock)) {
+ ret = restart_syscall();
+ goto exit_rpm;
+ }
/* If NVMem devices are not yet added */
if (!sw->nvm) {
@@ -1217,13 +1230,9 @@ static ssize_t nvm_authenticate_store(struct device *dev,
goto exit_unlock;
}
- pm_runtime_get_sync(&sw->dev);
ret = nvm_validate_and_write(sw);
- if (ret) {
- pm_runtime_mark_last_busy(&sw->dev);
- pm_runtime_put_autosuspend(&sw->dev);
+ if (ret)
goto exit_unlock;
- }
sw->nvm->authenticating = true;
@@ -1239,12 +1248,13 @@ static ssize_t nvm_authenticate_store(struct device *dev,
} else {
ret = nvm_authenticate_device(sw);
}
- pm_runtime_mark_last_busy(&sw->dev);
- pm_runtime_put_autosuspend(&sw->dev);
}
exit_unlock:
mutex_unlock(&sw->tb->lock);
+exit_rpm:
+ pm_runtime_mark_last_busy(&sw->dev);
+ pm_runtime_put_autosuspend(&sw->dev);
if (ret)
return ret;
@@ -1380,11 +1390,22 @@ static void tb_switch_release(struct device *dev)
*/
static int __maybe_unused tb_switch_runtime_suspend(struct device *dev)
{
+ struct tb_switch *sw = tb_to_switch(dev);
+ const struct tb_cm_ops *cm_ops = sw->tb->cm_ops;
+
+ if (cm_ops->runtime_suspend_switch)
+ return cm_ops->runtime_suspend_switch(sw);
+
return 0;
}
static int __maybe_unused tb_switch_runtime_resume(struct device *dev)
{
+ struct tb_switch *sw = tb_to_switch(dev);
+ const struct tb_cm_ops *cm_ops = sw->tb->cm_ops;
+
+ if (cm_ops->runtime_resume_switch)
+ return cm_ops->runtime_resume_switch(sw);
return 0;
}
@@ -1946,10 +1967,10 @@ struct tb_sw_lookup {
u64 route;
};
-static int tb_switch_match(struct device *dev, void *data)
+static int tb_switch_match(struct device *dev, const void *data)
{
struct tb_switch *sw = tb_to_switch(dev);
- struct tb_sw_lookup *lookup = data;
+ const struct tb_sw_lookup *lookup = data;
if (!sw)
return 0;
diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
index b12c8f33d89c..6407d529871d 100644
--- a/drivers/thunderbolt/tb.h
+++ b/drivers/thunderbolt/tb.h
@@ -79,6 +79,8 @@ struct tb_switch_nvm {
* @connection_key: Connection key used with ICM messaging
* @link: Root switch link this switch is connected (ICM only)
* @depth: Depth in the chain this switch is connected (ICM only)
+ * @rpm_complete: Completion used to wait for runtime resume to
+ * complete (ICM only)
*
* When the switch is being added or removed to the domain (other
* switches) you need to have domain lock held.
@@ -112,6 +114,7 @@ struct tb_switch {
u8 connection_key;
u8 link;
u8 depth;
+ struct completion rpm_complete;
};
/**
@@ -250,6 +253,8 @@ struct tb_path {
* @complete: Connection manager specific complete
* @runtime_suspend: Connection manager specific runtime_suspend
* @runtime_resume: Connection manager specific runtime_resume
+ * @runtime_suspend_switch: Runtime suspend a switch
+ * @runtime_resume_switch: Runtime resume a switch
* @handle_event: Handle thunderbolt event
* @get_boot_acl: Get boot ACL list
* @set_boot_acl: Set boot ACL list
@@ -270,6 +275,8 @@ struct tb_cm_ops {
void (*complete)(struct tb *tb);
int (*runtime_suspend)(struct tb *tb);
int (*runtime_resume)(struct tb *tb);
+ int (*runtime_suspend_switch)(struct tb_switch *sw);
+ int (*runtime_resume_switch)(struct tb_switch *sw);
void (*handle_event)(struct tb *tb, enum tb_cfg_pkg_type,
const void *buf, size_t size);
int (*get_boot_acl)(struct tb *tb, uuid_t *uuids, size_t nuuids);
diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig
index 3b1d312bb175..c7623f99ac0f 100644
--- a/drivers/tty/Kconfig
+++ b/drivers/tty/Kconfig
@@ -93,9 +93,9 @@ config VT_HW_CONSOLE_BINDING
select the console driver that will serve as the backend for the
virtual terminals.
- See <file:Documentation/console/console.txt> for more
+ See <file:Documentation/driver-api/console.rst> for more
information. For framebuffer console users, please refer to
- <file:Documentation/fb/fbcon.txt>.
+ <file:Documentation/fb/fbcon.rst>.
config UNIX98_PTYS
bool "Unix98 PTY support" if EXPERT
@@ -175,7 +175,7 @@ config ROCKETPORT
This driver supports Comtrol RocketPort and RocketModem PCI boards.
These boards provide 2, 4, 8, 16, or 32 high-speed serial ports or
modems. For information about the RocketPort/RocketModem boards
- and this driver read <file:Documentation/serial/rocket.rst>.
+ and this driver read <file:Documentation/driver-api/serial/rocket.rst>.
To compile this driver as a module, choose M here: the
module will be called rocket.
@@ -193,7 +193,7 @@ config CYCLADES
your Linux box, for instance in order to become a dial-in server.
For information about the Cyclades-Z card, read
- <file:Documentation/serial/cyclades_z.rst>.
+ <file:Documentation/driver-api/serial/cyclades_z.rst>.
To compile this driver as a module, choose M here: the
module will be called cyclades.
diff --git a/drivers/tty/hvc/hvc_vio.c b/drivers/tty/hvc/hvc_vio.c
index 6de6d4a1a221..7af54d6ed5b8 100644
--- a/drivers/tty/hvc/hvc_vio.c
+++ b/drivers/tty/hvc/hvc_vio.c
@@ -107,6 +107,14 @@ static int hvterm_raw_get_chars(uint32_t vtermno, char *buf, int count)
return got;
}
+/**
+ * hvterm_raw_put_chars: send characters to firmware for given vterm adapter
+ * @vtermno: The virtual terminal number.
+ * @buf: The characters to send. Because of the underlying hypercall in
+ * hvc_put_chars(), this buffer must be at least 16 bytes long, even if
+ * you are sending fewer chars.
+ * @count: number of chars to send.
+ */
static int hvterm_raw_put_chars(uint32_t vtermno, const char *buf, int count)
{
struct hvterm_priv *pv = hvterm_privs[vtermno];
@@ -219,6 +227,7 @@ static const struct hv_ops hvterm_hvsi_ops = {
static void udbg_hvc_putc(char c)
{
int count = -1;
+ unsigned char bounce_buffer[16];
if (!hvterm_privs[0])
return;
@@ -229,7 +238,12 @@ static void udbg_hvc_putc(char c)
do {
switch(hvterm_privs[0]->proto) {
case HV_PROTOCOL_RAW:
- count = hvterm_raw_put_chars(0, &c, 1);
+ /*
+ * hvterm_raw_put_chars requires at least a 16-byte
+ * buffer, so go via the bounce buffer
+ */
+ bounce_buffer[0] = c;
+ count = hvterm_raw_put_chars(0, bounce_buffer, 1);
break;
case HV_PROTOCOL_HVSI:
count = hvterm_hvsi_put_chars(0, &c, 1);
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index ebfb0bd5bef5..33ad9d6de532 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -11,6 +11,8 @@
#include <linux/serial_reg.h>
#include <linux/dmaengine.h>
+#include "../serial_mctrl_gpio.h"
+
struct uart_8250_dma {
int (*tx_dma)(struct uart_8250_port *p);
int (*rx_dma)(struct uart_8250_port *p);
@@ -128,6 +130,24 @@ static inline void serial_dl_write(struct uart_8250_port *up, int value)
up->dl_write(up, value);
}
+static inline bool serial8250_set_THRI(struct uart_8250_port *up)
+{
+ if (up->ier & UART_IER_THRI)
+ return false;
+ up->ier |= UART_IER_THRI;
+ serial_out(up, UART_IER, up->ier);
+ return true;
+}
+
+static inline bool serial8250_clear_THRI(struct uart_8250_port *up)
+{
+ if (!(up->ier & UART_IER_THRI))
+ return false;
+ up->ier &= ~UART_IER_THRI;
+ serial_out(up, UART_IER, up->ier);
+ return true;
+}
+
struct uart_8250_port *serial8250_get_port(int line);
void serial8250_rpm_get(struct uart_8250_port *p);
@@ -139,14 +159,82 @@ void serial8250_rpm_put_tx(struct uart_8250_port *p);
int serial8250_em485_init(struct uart_8250_port *p);
void serial8250_em485_destroy(struct uart_8250_port *p);
+/* MCR <-> TIOCM conversion */
+static inline int serial8250_TIOCM_to_MCR(int tiocm)
+{
+ int mcr = 0;
+
+ if (tiocm & TIOCM_RTS)
+ mcr |= UART_MCR_RTS;
+ if (tiocm & TIOCM_DTR)
+ mcr |= UART_MCR_DTR;
+ if (tiocm & TIOCM_OUT1)
+ mcr |= UART_MCR_OUT1;
+ if (tiocm & TIOCM_OUT2)
+ mcr |= UART_MCR_OUT2;
+ if (tiocm & TIOCM_LOOP)
+ mcr |= UART_MCR_LOOP;
+
+ return mcr;
+}
+
+static inline int serial8250_MCR_to_TIOCM(int mcr)
+{
+ int tiocm = 0;
+
+ if (mcr & UART_MCR_RTS)
+ tiocm |= TIOCM_RTS;
+ if (mcr & UART_MCR_DTR)
+ tiocm |= TIOCM_DTR;
+ if (mcr & UART_MCR_OUT1)
+ tiocm |= TIOCM_OUT1;
+ if (mcr & UART_MCR_OUT2)
+ tiocm |= TIOCM_OUT2;
+ if (mcr & UART_MCR_LOOP)
+ tiocm |= TIOCM_LOOP;
+
+ return tiocm;
+}
+
+/* MSR <-> TIOCM conversion */
+static inline int serial8250_MSR_to_TIOCM(int msr)
+{
+ int tiocm = 0;
+
+ if (msr & UART_MSR_DCD)
+ tiocm |= TIOCM_CAR;
+ if (msr & UART_MSR_RI)
+ tiocm |= TIOCM_RNG;
+ if (msr & UART_MSR_DSR)
+ tiocm |= TIOCM_DSR;
+ if (msr & UART_MSR_CTS)
+ tiocm |= TIOCM_CTS;
+
+ return tiocm;
+}
+
static inline void serial8250_out_MCR(struct uart_8250_port *up, int value)
{
serial_out(up, UART_MCR, value);
+
+ if (up->gpios)
+ mctrl_gpio_set(up->gpios, serial8250_MCR_to_TIOCM(value));
}
static inline int serial8250_in_MCR(struct uart_8250_port *up)
{
- return serial_in(up, UART_MCR);
+ int mctrl;
+
+ mctrl = serial_in(up, UART_MCR);
+
+ if (up->gpios) {
+ unsigned int mctrl_gpio = 0;
+
+ mctrl_gpio = mctrl_gpio_get_outputs(up->gpios, &mctrl_gpio);
+ mctrl |= serial8250_TIOCM_to_MCR(mctrl_gpio);
+ }
+
+ return mctrl;
}
#if defined(__alpha__) && !defined(CONFIG_PCI)
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index e441221e04b9..df3bcc0b2d74 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -14,6 +14,7 @@
* serial8250_register_8250_port() ports
*/
+#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/ioport.h>
@@ -982,6 +983,8 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
uart = serial8250_find_match_or_unused(&up->port);
if (uart && uart->port.type != PORT_8250_CIR) {
+ struct mctrl_gpios *gpios;
+
if (uart->port.dev)
uart_remove_one_port(&serial8250_reg, &uart->port);
@@ -1016,6 +1019,22 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
if (up->port.flags & UPF_FIXED_TYPE)
uart->port.type = up->port.type;
+ /*
+ * Only call mctrl_gpio_init(), if the device has no ACPI
+ * companion device
+ */
+ if (!has_acpi_companion(uart->port.dev)) {
+ gpios = mctrl_gpio_init(&uart->port, 0);
+ if (IS_ERR(gpios)) {
+ if (PTR_ERR(gpios) != -ENOSYS) {
+ ret = PTR_ERR(gpios);
+ goto out_unlock;
+ }
+ } else {
+ uart->gpios = gpios;
+ }
+ }
+
serial8250_set_defaults(uart);
/* Possibly override default I/O functions. */
@@ -1082,6 +1101,7 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
}
}
+out_unlock:
mutex_unlock(&serial_mutex);
return ret;
diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c
index bfa1a857f3ff..890fa7ddaa7f 100644
--- a/drivers/tty/serial/8250/8250_dma.c
+++ b/drivers/tty/serial/8250/8250_dma.c
@@ -34,10 +34,8 @@ static void __dma_tx_complete(void *param)
uart_write_wakeup(&p->port);
ret = serial8250_tx_dma(p);
- if (ret) {
- p->ier |= UART_IER_THRI;
- serial_port_out(&p->port, UART_IER, p->ier);
- }
+ if (ret)
+ serial8250_set_THRI(p);
spin_unlock_irqrestore(&p->port.lock, flags);
}
@@ -100,10 +98,7 @@ int serial8250_tx_dma(struct uart_8250_port *p)
dma_async_issue_pending(dma->txchan);
if (dma->tx_err) {
dma->tx_err = 0;
- if (p->ier & UART_IER_THRI) {
- p->ier &= ~UART_IER_THRI;
- serial_out(p, UART_IER, p->ier);
- }
+ serial8250_clear_THRI(p);
}
return 0;
err:
diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c
index 417c7c810df9..b411ba4eb5e9 100644
--- a/drivers/tty/serial/8250/8250_mtk.c
+++ b/drivers/tty/serial/8250/8250_mtk.c
@@ -10,6 +10,7 @@
#include <linux/module.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/serial_8250.h>
@@ -47,7 +48,6 @@
#define MTK_UART_DMA_EN_RX 0x5
#define MTK_UART_ESCAPE_CHAR 0x77 /* Escape char added under sw fc */
-#define MTK_UART_TX_SIZE UART_XMIT_SIZE
#define MTK_UART_RX_SIZE 0x8000
#define MTK_UART_TX_TRIGGER 1
#define MTK_UART_RX_TRIGGER MTK_UART_RX_SIZE
@@ -70,6 +70,7 @@ struct mtk8250_data {
#ifdef CONFIG_SERIAL_8250_DMA
enum dma_rx_status rx_status;
#endif
+ int rx_wakeup_irq;
};
/* flow control mode */
@@ -89,28 +90,30 @@ static void mtk8250_dma_rx_complete(void *param)
struct mtk8250_data *data = up->port.private_data;
struct tty_port *tty_port = &up->port.state->port;
struct dma_tx_state state;
+ int copied, total, cnt;
unsigned char *ptr;
- int copied;
- dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr,
- dma->rx_size, DMA_FROM_DEVICE);
+ if (data->rx_status == DMA_RX_SHUTDOWN)
+ return;
dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
+ total = dma->rx_size - state.residue;
+ cnt = total;
- if (data->rx_status == DMA_RX_SHUTDOWN)
- return;
+ if ((data->rx_pos + cnt) > dma->rx_size)
+ cnt = dma->rx_size - data->rx_pos;
- if ((data->rx_pos + state.residue) <= dma->rx_size) {
- ptr = (unsigned char *)(data->rx_pos + dma->rx_buf);
- copied = tty_insert_flip_string(tty_port, ptr, state.residue);
- } else {
- ptr = (unsigned char *)(data->rx_pos + dma->rx_buf);
- copied = tty_insert_flip_string(tty_port, ptr,
- dma->rx_size - data->rx_pos);
+ ptr = (unsigned char *)(data->rx_pos + dma->rx_buf);
+ copied = tty_insert_flip_string(tty_port, ptr, cnt);
+ data->rx_pos += cnt;
+
+ if (total > cnt) {
ptr = (unsigned char *)(dma->rx_buf);
- copied += tty_insert_flip_string(tty_port, ptr,
- data->rx_pos + state.residue - dma->rx_size);
+ cnt = total - cnt;
+ copied += tty_insert_flip_string(tty_port, ptr, cnt);
+ data->rx_pos = cnt;
}
+
up->port.icount.rx += copied;
tty_flip_buffer_push(tty_port);
@@ -121,9 +124,7 @@ static void mtk8250_dma_rx_complete(void *param)
static void mtk8250_rx_dma(struct uart_8250_port *up)
{
struct uart_8250_dma *dma = up->dma;
- struct mtk8250_data *data = up->port.private_data;
struct dma_async_tx_descriptor *desc;
- struct dma_tx_state state;
desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr,
dma->rx_size, DMA_DEV_TO_MEM,
@@ -138,12 +139,6 @@ static void mtk8250_rx_dma(struct uart_8250_port *up)
dma->rx_cookie = dmaengine_submit(desc);
- dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
- data->rx_pos = state.residue;
-
- dma_sync_single_for_device(dma->rxchan->device->dev, dma->rx_addr,
- dma->rx_size, DMA_FROM_DEVICE);
-
dma_async_issue_pending(dma->rxchan);
}
@@ -156,13 +151,11 @@ static void mtk8250_dma_enable(struct uart_8250_port *up)
if (data->rx_status != DMA_RX_START)
return;
- dma->rxconf.direction = DMA_DEV_TO_MEM;
- dma->rxconf.src_addr_width = dma->rx_size / 1024;
- dma->rxconf.src_addr = dma->rx_addr;
+ dma->rxconf.src_port_window_size = dma->rx_size;
+ dma->rxconf.src_addr = dma->rx_addr;
- dma->txconf.direction = DMA_MEM_TO_DEV;
- dma->txconf.dst_addr_width = MTK_UART_TX_SIZE / 1024;
- dma->txconf.dst_addr = dma->tx_addr;
+ dma->txconf.dst_port_window_size = UART_XMIT_SIZE;
+ dma->txconf.dst_addr = dma->tx_addr;
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR |
UART_FCR_CLEAR_XMIT);
@@ -551,6 +544,8 @@ static int mtk8250_probe(struct platform_device *pdev)
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
+ data->rx_wakeup_irq = platform_get_irq(pdev, 1);
+
return 0;
}
@@ -572,15 +567,35 @@ static int mtk8250_remove(struct platform_device *pdev)
static int __maybe_unused mtk8250_suspend(struct device *dev)
{
struct mtk8250_data *data = dev_get_drvdata(dev);
+ int irq = data->rx_wakeup_irq;
+ int err;
serial8250_suspend_port(data->line);
+ pinctrl_pm_select_sleep_state(dev);
+ if (irq >= 0) {
+ err = enable_irq_wake(irq);
+ if (err) {
+ dev_err(dev,
+ "failed to enable irq wake on IRQ %d: %d\n",
+ irq, err);
+ pinctrl_pm_select_default_state(dev);
+ serial8250_resume_port(data->line);
+ return err;
+ }
+ }
+
return 0;
}
static int __maybe_unused mtk8250_resume(struct device *dev)
{
struct mtk8250_data *data = dev_get_drvdata(dev);
+ int irq = data->rx_wakeup_irq;
+
+ if (irq >= 0)
+ disable_irq_wake(irq);
+ pinctrl_pm_select_default_state(dev);
serial8250_resume_port(data->line);
diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c
index 0277479c87e9..0826cfdbd406 100644
--- a/drivers/tty/serial/8250/8250_of.c
+++ b/drivers/tty/serial/8250/8250_of.c
@@ -70,9 +70,10 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
/* Get clk rate through clk driver if present */
info->clk = devm_clk_get(&ofdev->dev, NULL);
if (IS_ERR(info->clk)) {
- dev_warn(&ofdev->dev,
- "clk or clock-frequency not defined\n");
ret = PTR_ERR(info->clk);
+ if (ret != -EPROBE_DEFER)
+ dev_warn(&ofdev->dev,
+ "failed to get clock: %d\n", ret);
goto err_pmruntime;
}
@@ -205,18 +206,16 @@ err_pmruntime:
/*
* Try to register a serial port
*/
-static const struct of_device_id of_platform_serial_table[];
static int of_platform_serial_probe(struct platform_device *ofdev)
{
- const struct of_device_id *match;
struct of_serial_info *info;
struct uart_8250_port port8250;
+ unsigned int port_type;
u32 tx_threshold;
- int port_type;
int ret;
- match = of_match_device(of_platform_serial_table, &ofdev->dev);
- if (!match)
+ port_type = (unsigned long)of_device_get_match_data(&ofdev->dev);
+ if (port_type == PORT_UNKNOWN)
return -EINVAL;
if (of_property_read_bool(ofdev->dev.of_node, "used-by-rtas"))
@@ -226,7 +225,6 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
if (info == NULL)
return -ENOMEM;
- port_type = (unsigned long)match->data;
memset(&port8250, 0, sizeof(port8250));
ret = of_platform_serial_setup(ofdev, port_type, &port8250.port, info);
if (ret)
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 0a8316632d75..3ef65cbd2478 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -141,18 +141,20 @@ static void omap8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
serial8250_do_set_mctrl(port, mctrl);
- /*
- * Turn off autoRTS if RTS is lowered and restore autoRTS setting
- * if RTS is raised
- */
- lcr = serial_in(up, UART_LCR);
- serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
- if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
- priv->efr |= UART_EFR_RTS;
- else
- priv->efr &= ~UART_EFR_RTS;
- serial_out(up, UART_EFR, priv->efr);
- serial_out(up, UART_LCR, lcr);
+ if (!up->gpios) {
+ /*
+ * Turn off autoRTS if RTS is lowered and restore autoRTS
+ * setting if RTS is raised
+ */
+ lcr = serial_in(up, UART_LCR);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+ if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
+ priv->efr |= UART_EFR_RTS;
+ else
+ priv->efr &= ~UART_EFR_RTS;
+ serial_out(up, UART_EFR, priv->efr);
+ serial_out(up, UART_LCR, lcr);
+ }
}
/*
@@ -453,7 +455,8 @@ static void omap_8250_set_termios(struct uart_port *port,
priv->efr = 0;
up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF);
- if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {
+ if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW &&
+ !up->gpios) {
/* Enable AUTOCTS (autoRTS is enabled when RTS is raised) */
up->port.status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
priv->efr |= UART_EFR_CTS;
@@ -923,15 +926,13 @@ static void omap_8250_dma_tx_complete(void *param)
ret = omap_8250_tx_dma(p);
if (ret)
en_thri = true;
-
} else if (p->capabilities & UART_CAP_RPM) {
en_thri = true;
}
if (en_thri) {
dma->tx_err = 1;
- p->ier |= UART_IER_THRI;
- serial_port_out(&p->port, UART_IER, p->ier);
+ serial8250_set_THRI(p);
}
spin_unlock_irqrestore(&p->port.lock, flags);
@@ -959,10 +960,7 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
ret = -EBUSY;
goto err;
}
- if (p->ier & UART_IER_THRI) {
- p->ier &= ~UART_IER_THRI;
- serial_out(p, UART_IER, p->ier);
- }
+ serial8250_clear_THRI(p);
return 0;
}
@@ -1020,10 +1018,7 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
if (dma->tx_err)
dma->tx_err = 0;
- if (p->ier & UART_IER_THRI) {
- p->ier &= ~UART_IER_THRI;
- serial_out(p, UART_IER, p->ier);
- }
+ serial8250_clear_THRI(p);
if (skip_byte)
serial_out(p, UART_TX, xmit->buf[xmit->tail]);
return 0;
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index df41397de478..7f740b37700b 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -1326,7 +1326,36 @@ static int pci_default_setup(struct serial_private *priv,
return setup_port(priv, port, bar, offset, board->reg_shift);
}
-
+static void
+pericom_do_set_divisor(struct uart_port *port, unsigned int baud,
+ unsigned int quot, unsigned int quot_frac)
+{
+ int scr;
+ int lcr;
+ int actual_baud;
+ int tolerance;
+
+ for (scr = 5 ; scr <= 15 ; scr++) {
+ actual_baud = 921600 * 16 / scr;
+ tolerance = actual_baud / 50;
+
+ if ((baud < actual_baud + tolerance) &&
+ (baud > actual_baud - tolerance)) {
+
+ lcr = serial_port_in(port, UART_LCR);
+ serial_port_out(port, UART_LCR, lcr | 0x80);
+
+ serial_port_out(port, UART_DLL, 1);
+ serial_port_out(port, UART_DLM, 0);
+ serial_port_out(port, 2, 16 - scr);
+ serial_port_out(port, UART_LCR, lcr);
+ return;
+ } else if (baud > actual_baud) {
+ break;
+ }
+ }
+ serial8250_do_set_divisor(port, baud, quot, quot_frac);
+}
static int pci_pericom_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_8250_port *port, int idx)
@@ -1339,6 +1368,30 @@ static int pci_pericom_setup(struct serial_private *priv,
else
offset += idx * board->uart_offset;
+
+ maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >>
+ (board->reg_shift + 3);
+
+ if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr)
+ return 1;
+
+ port->port.set_divisor = pericom_do_set_divisor;
+
+ return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+static int pci_pericom_setup_four_at_eight(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ unsigned int bar, offset = board->first_offset, maxnr;
+
+ bar = FL_GET_BASE(board->flags);
+ if (board->flags & FL_BASE_BARS)
+ bar += idx;
+ else
+ offset += idx * board->uart_offset;
+
if (idx==3)
offset = 0x38;
@@ -1348,6 +1401,8 @@ static int pci_pericom_setup(struct serial_private *priv,
if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr)
return 1;
+ port->port.set_divisor = pericom_do_set_divisor;
+
return setup_port(priv, port, bar, offset, board->reg_shift);
}
@@ -1995,7 +2050,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.device = PCI_DEVICE_ID_PERICOM_PI7C9X7954,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .setup = pci_pericom_setup,
+ .setup = pci_pericom_setup_four_at_eight,
},
/*
* PLX
@@ -2032,107 +2087,113 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.device = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SDB,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .setup = pci_pericom_setup,
+ .setup = pci_pericom_setup_four_at_eight,
},
{
.vendor = PCI_VENDOR_ID_ACCESIO,
.device = PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4S,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .setup = pci_pericom_setup,
+ .setup = pci_pericom_setup_four_at_eight,
},
{
.vendor = PCI_VENDOR_ID_ACCESIO,
.device = PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4DB,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .setup = pci_pericom_setup,
+ .setup = pci_pericom_setup_four_at_eight,
},
{
.vendor = PCI_VENDOR_ID_ACCESIO,
.device = PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_4,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .setup = pci_pericom_setup,
+ .setup = pci_pericom_setup_four_at_eight,
},
{
.vendor = PCI_VENDOR_ID_ACCESIO,
.device = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SMDB,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .setup = pci_pericom_setup,
+ .setup = pci_pericom_setup_four_at_eight,
},
{
.vendor = PCI_VENDOR_ID_ACCESIO,
.device = PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4SM,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .setup = pci_pericom_setup,
+ .setup = pci_pericom_setup_four_at_eight,
},
{
.vendor = PCI_VENDOR_ID_ACCESIO,
.device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_4,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .setup = pci_pericom_setup,
+ .setup = pci_pericom_setup_four_at_eight,
},
{
.vendor = PCI_VENDOR_ID_ACCESIO,
.device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_4,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .setup = pci_pericom_setup,
+ .setup = pci_pericom_setup_four_at_eight,
},
{
.vendor = PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S,
.device = PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_4,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .setup = pci_pericom_setup,
+ .setup = pci_pericom_setup_four_at_eight,
},
{
.vendor = PCI_VENDOR_ID_ACCESIO,
.device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_4,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .setup = pci_pericom_setup,
+ .setup = pci_pericom_setup_four_at_eight,
},
{
.vendor = PCI_VENDOR_ID_ACCESIO,
.device = PCI_DEVICE_ID_ACCESIO_PCIE_COM422_4,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .setup = pci_pericom_setup,
+ .setup = pci_pericom_setup_four_at_eight,
},
{
.vendor = PCI_VENDOR_ID_ACCESIO,
.device = PCI_DEVICE_ID_ACCESIO_PCIE_COM485_4,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .setup = pci_pericom_setup,
+ .setup = pci_pericom_setup_four_at_eight,
},
{
.vendor = PCI_VENDOR_ID_ACCESIO,
.device = PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .setup = pci_pericom_setup,
+ .setup = pci_pericom_setup_four_at_eight,
},
{
.vendor = PCI_VENDOR_ID_ACCESIO,
.device = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SM,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .setup = pci_pericom_setup,
+ .setup = pci_pericom_setup_four_at_eight,
},
{
.vendor = PCI_VENDOR_ID_ACCESIO,
.device = PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .setup = pci_pericom_setup,
+ .setup = pci_pericom_setup_four_at_eight,
},
- /*
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup,
+ }, /*
* SBS Technologies, Inc., PMC-OCTALPRO 232
*/
{
diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c
index 431e69a5a6a0..dfca33141fcc 100644
--- a/drivers/tty/serial/8250/8250_pnp.c
+++ b/drivers/tty/serial/8250/8250_pnp.c
@@ -462,8 +462,8 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
return -ENODEV;
dev_dbg(&dev->dev,
- "Setup PNP port: port %lx, mem %pa, irq %d, type %d\n",
- uart.port.iobase, &uart.port.mapbase,
+ "Setup PNP port: port %#lx, mem %#llx, irq %u, type %u\n",
+ uart.port.iobase, (unsigned long long)uart.port.mapbase,
uart.port.irq, uart.port.iotype);
if (flags & CIR_PORT) {
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index d2f3310abe54..c1cec808571b 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -1502,11 +1502,8 @@ static void __stop_tx_rs485(struct uart_8250_port *p)
static inline void __do_stop_tx(struct uart_8250_port *p)
{
- if (p->ier & UART_IER_THRI) {
- p->ier &= ~UART_IER_THRI;
- serial_out(p, UART_IER, p->ier);
+ if (serial8250_clear_THRI(p))
serial8250_rpm_put_tx(p);
- }
}
static inline void __stop_tx(struct uart_8250_port *p)
@@ -1555,10 +1552,7 @@ static inline void __start_tx(struct uart_port *port)
if (up->dma && !up->dma->tx_dma(up))
return;
- if (!(up->ier & UART_IER_THRI)) {
- up->ier |= UART_IER_THRI;
- serial_port_out(port, UART_IER, up->ier);
-
+ if (serial8250_set_THRI(up)) {
if (up->bugs & UART_BUG_TXEN) {
unsigned char lsr;
@@ -1662,6 +1656,8 @@ static void serial8250_disable_ms(struct uart_port *port)
if (up->bugs & UART_BUG_NOMSR)
return;
+ mctrl_gpio_disable_ms(up->gpios);
+
up->ier &= ~UART_IER_MSI;
serial_port_out(port, UART_IER, up->ier);
}
@@ -1674,6 +1670,8 @@ static void serial8250_enable_ms(struct uart_port *port)
if (up->bugs & UART_BUG_NOMSR)
return;
+ mctrl_gpio_enable_ms(up->gpios);
+
up->ier |= UART_IER_MSI;
serial8250_rpm_get(up);
@@ -1869,13 +1867,13 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
status = serial_port_in(port, UART_LSR);
- if (status & (UART_LSR_DR | UART_LSR_BI) &&
- iir & UART_IIR_RDI) {
+ if (status & (UART_LSR_DR | UART_LSR_BI)) {
if (!up->dma || handle_rx_dma(up, iir))
status = serial8250_rx_chars(up, status);
}
serial8250_modem_status(up);
- if ((!up->dma || up->dma->tx_err) && (status & UART_LSR_THRE))
+ if ((!up->dma || up->dma->tx_err) && (status & UART_LSR_THRE) &&
+ (up->ier & UART_IER_THRI))
serial8250_tx_chars(up);
uart_unlock_and_check_sysrq(port, flags);
@@ -1944,22 +1942,17 @@ unsigned int serial8250_do_get_mctrl(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
unsigned int status;
- unsigned int ret;
+ unsigned int val;
serial8250_rpm_get(up);
status = serial8250_modem_status(up);
serial8250_rpm_put(up);
- ret = 0;
- if (status & UART_MSR_DCD)
- ret |= TIOCM_CAR;
- if (status & UART_MSR_RI)
- ret |= TIOCM_RNG;
- if (status & UART_MSR_DSR)
- ret |= TIOCM_DSR;
- if (status & UART_MSR_CTS)
- ret |= TIOCM_CTS;
- return ret;
+ val = serial8250_MSR_to_TIOCM(status);
+ if (up->gpios)
+ return mctrl_gpio_get(up->gpios, &val);
+
+ return val;
}
EXPORT_SYMBOL_GPL(serial8250_do_get_mctrl);
@@ -1973,18 +1966,9 @@ static unsigned int serial8250_get_mctrl(struct uart_port *port)
void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct uart_8250_port *up = up_to_u8250p(port);
- unsigned char mcr = 0;
+ unsigned char mcr;
- if (mctrl & TIOCM_RTS)
- mcr |= UART_MCR_RTS;
- if (mctrl & TIOCM_DTR)
- mcr |= UART_MCR_DTR;
- if (mctrl & TIOCM_OUT1)
- mcr |= UART_MCR_OUT1;
- if (mctrl & TIOCM_OUT2)
- mcr |= UART_MCR_OUT2;
- if (mctrl & TIOCM_LOOP)
- mcr |= UART_MCR_LOOP;
+ mcr = serial8250_TIOCM_to_MCR(mctrl);
mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr;
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 296115f6a4d8..509f6a3bb9ff 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -8,6 +8,7 @@ config SERIAL_8250
tristate "8250/16550 and compatible serial support"
depends on !S390
select SERIAL_CORE
+ select SERIAL_MCTRL_GPIO if GPIOLIB
---help---
This selects whether you want to include the driver for the standard
serial ports. The standard answer is Y. People who might say N
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 0d31251e04cc..04c23951b831 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -457,20 +457,6 @@ config SERIAL_21285_CONSOLE
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
-config SERIAL_MPSC
- bool "Marvell MPSC serial port support"
- depends on MV64X60
- select SERIAL_CORE
- help
- Say Y here if you want to use the Marvell MPSC serial controller.
-
-config SERIAL_MPSC_CONSOLE
- bool "Support for console on Marvell MPSC serial port"
- depends on SERIAL_MPSC
- select SERIAL_CORE_CONSOLE
- help
- Say Y here if you want to support a serial console on a Marvell MPSC.
-
config SERIAL_PXA
bool "PXA serial port support (DEPRECATED)"
depends on ARCH_PXA || ARCH_MMP
@@ -514,7 +500,7 @@ config SERIAL_SA1100
help
If you have a machine based on a SA1100/SA1110 StrongARM(R) CPU you
can enable its onboard serial port by enabling this option.
- Please read <file:Documentation/arm/SA1100/serial_UART> for further
+ Please read <file:Documentation/arm/sa1100/serial_uart.rst> for further
info.
config SERIAL_SA1100_CONSOLE
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 79c3d513db7e..7cd7cabfa6c4 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -46,7 +46,6 @@ obj-$(CONFIG_SERIAL_CPM) += cpm_uart/
obj-$(CONFIG_SERIAL_IMX) += imx.o
obj-$(CONFIG_SERIAL_MPC52xx) += mpc52xx_uart.o
obj-$(CONFIG_SERIAL_ICOM) += icom.o
-obj-$(CONFIG_SERIAL_MPSC) += mpsc.o
obj-$(CONFIG_SERIAL_MESON) += meson_uart.o
obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 89ade213a1a9..5921a33b2a07 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1717,7 +1717,7 @@ static int pl011_allocate_irq(struct uart_amba_port *uap)
{
pl011_write(uap->im, uap, REG_IMSC);
- return request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap);
+ return request_irq(uap->port.irq, pl011_int, IRQF_SHARED, "uart-pl011", uap);
}
/*
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
index b929c7ae3a27..de6d02f7abe2 100644
--- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
@@ -407,7 +407,16 @@ static int cpm_uart_startup(struct uart_port *port)
clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_RX);
}
cpm_uart_initbd(pinfo);
- cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
+ if (IS_SMC(pinfo)) {
+ out_be32(&pinfo->smcup->smc_rstate, 0);
+ out_be32(&pinfo->smcup->smc_tstate, 0);
+ out_be16(&pinfo->smcup->smc_rbptr,
+ in_be16(&pinfo->smcup->smc_rbase));
+ out_be16(&pinfo->smcup->smc_tbptr,
+ in_be16(&pinfo->smcup->smc_tbase));
+ } else {
+ cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
+ }
}
/* Install interrupt handler. */
retval = request_irq(port->irq, cpm_uart_int, 0, "cpm_uart", port);
@@ -567,8 +576,6 @@ static void cpm_uart_set_termios(struct uart_port *port,
/*
* Set up parity check flag
*/
-#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-
port->read_status_mask = (BD_SC_EMPTY | BD_SC_OV);
if (termios->c_iflag & INPCK)
port->read_status_mask |= BD_SC_FR | BD_SC_PR;
@@ -861,16 +868,14 @@ static void cpm_uart_init_smc(struct uart_cpm_port *pinfo)
(u8 __iomem *)pinfo->tx_bd_base - DPRAM_BASE);
/*
- * In case SMC1 is being relocated...
+ * In case SMC is being relocated...
*/
-#if defined (CONFIG_I2C_SPI_SMC1_UCODE_PATCH)
out_be16(&up->smc_rbptr, in_be16(&pinfo->smcup->smc_rbase));
out_be16(&up->smc_tbptr, in_be16(&pinfo->smcup->smc_tbase));
out_be32(&up->smc_rstate, 0);
out_be32(&up->smc_tstate, 0);
out_be16(&up->smc_brkcr, 1); /* number of break chars */
out_be16(&up->smc_brkec, 0);
-#endif
/* Set up the uart parameters in the
* parameter ram.
@@ -884,8 +889,6 @@ static void cpm_uart_init_smc(struct uart_cpm_port *pinfo)
out_be16(&up->smc_brkec, 0);
out_be16(&up->smc_brkcr, 1);
- cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
-
/* Set UART mode, 8 bit, no parity, one stop.
* Enable receive and transmit.
*/
diff --git a/drivers/tty/serial/digicolor-usart.c b/drivers/tty/serial/digicolor-usart.c
index f460cca139e2..13ac36e2da4f 100644
--- a/drivers/tty/serial/digicolor-usart.c
+++ b/drivers/tty/serial/digicolor-usart.c
@@ -541,7 +541,11 @@ static int __init digicolor_uart_init(void)
if (ret)
return ret;
- return platform_driver_register(&digicolor_uart_platform);
+ ret = platform_driver_register(&digicolor_uart_platform);
+ if (ret)
+ uart_unregister_driver(&digicolor_uart);
+
+ return ret;
}
module_init(digicolor_uart_init);
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index ea1c85e3b432..92dad2b4ec36 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -234,9 +234,18 @@
static DEFINE_IDA(fsl_lpuart_ida);
+enum lpuart_type {
+ VF610_LPUART,
+ LS1021A_LPUART,
+ IMX7ULP_LPUART,
+ IMX8QXP_LPUART,
+};
+
struct lpuart_port {
struct uart_port port;
- struct clk *clk;
+ enum lpuart_type devtype;
+ struct clk *ipg_clk;
+ struct clk *baud_clk;
unsigned int txfifo_size;
unsigned int rxfifo_size;
@@ -261,19 +270,29 @@ struct lpuart_port {
};
struct lpuart_soc_data {
- char iotype;
- u8 reg_off;
+ enum lpuart_type devtype;
+ char iotype;
+ u8 reg_off;
};
static const struct lpuart_soc_data vf_data = {
+ .devtype = VF610_LPUART,
.iotype = UPIO_MEM,
};
static const struct lpuart_soc_data ls_data = {
+ .devtype = LS1021A_LPUART,
.iotype = UPIO_MEM32BE,
};
-static struct lpuart_soc_data imx_data = {
+static struct lpuart_soc_data imx7ulp_data = {
+ .devtype = IMX7ULP_LPUART,
+ .iotype = UPIO_MEM32,
+ .reg_off = IMX_REG_OFF,
+};
+
+static struct lpuart_soc_data imx8qxp_data = {
+ .devtype = IMX8QXP_LPUART,
.iotype = UPIO_MEM32,
.reg_off = IMX_REG_OFF,
};
@@ -281,7 +300,8 @@ static struct lpuart_soc_data imx_data = {
static const struct of_device_id lpuart_dt_ids[] = {
{ .compatible = "fsl,vf610-lpuart", .data = &vf_data, },
{ .compatible = "fsl,ls1021a-lpuart", .data = &ls_data, },
- { .compatible = "fsl,imx7ulp-lpuart", .data = &imx_data, },
+ { .compatible = "fsl,imx7ulp-lpuart", .data = &imx7ulp_data, },
+ { .compatible = "fsl,imx8qxp-lpuart", .data = &imx8qxp_data, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
@@ -289,6 +309,11 @@ MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
/* Forward declare this for the dma callbacks*/
static void lpuart_dma_tx_complete(void *arg);
+static inline bool is_imx8qxp_lpuart(struct lpuart_port *sport)
+{
+ return sport->devtype == IMX8QXP_LPUART;
+}
+
static inline u32 lpuart32_read(struct uart_port *port, u32 off)
{
switch (port->iotype) {
@@ -314,6 +339,39 @@ static inline void lpuart32_write(struct uart_port *port, u32 val,
}
}
+static int __lpuart_enable_clks(struct lpuart_port *sport, bool is_en)
+{
+ int ret = 0;
+
+ if (is_en) {
+ ret = clk_prepare_enable(sport->ipg_clk);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(sport->baud_clk);
+ if (ret) {
+ clk_disable_unprepare(sport->ipg_clk);
+ return ret;
+ }
+ } else {
+ clk_disable_unprepare(sport->baud_clk);
+ clk_disable_unprepare(sport->ipg_clk);
+ }
+
+ return 0;
+}
+
+static unsigned int lpuart_get_baud_clk_rate(struct lpuart_port *sport)
+{
+ if (is_imx8qxp_lpuart(sport))
+ return clk_get_rate(sport->baud_clk);
+
+ return clk_get_rate(sport->ipg_clk);
+}
+
+#define lpuart_enable_clks(x) __lpuart_enable_clks(x, true)
+#define lpuart_disable_clks(x) __lpuart_enable_clks(x, false)
+
static void lpuart_stop_tx(struct uart_port *port)
{
unsigned char temp;
@@ -1040,10 +1098,8 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
sport->rx_dma_rng_buf_len = 16;
ring->buf = kmalloc(sport->rx_dma_rng_buf_len, GFP_ATOMIC);
- if (!ring->buf) {
- dev_err(sport->port.dev, "Ring buf alloc failed\n");
+ if (!ring->buf)
return -ENOMEM;
- }
sg_init_one(&sport->rx_sgl, ring->buf, sport->rx_dma_rng_buf_len);
sg_set_buf(&sport->rx_sgl, ring->buf, sport->rx_dma_rng_buf_len);
@@ -2071,14 +2127,14 @@ lpuart_console_get_options(struct lpuart_port *sport, int *baud,
brfa = readb(sport->port.membase + UARTCR4);
brfa &= UARTCR4_BRFA_MASK;
- uartclk = clk_get_rate(sport->clk);
+ uartclk = lpuart_get_baud_clk_rate(sport);
/*
* baud = mod_clk/(16*(sbr[13]+(brfa)/32)
*/
baud_raw = uartclk / (16 * (sbr + brfa / 32));
if (*baud != baud_raw)
- printk(KERN_INFO "Serial: Console lpuart rounded baud rate"
+ dev_info(sport->port.dev, "Serial: Console lpuart rounded baud rate"
"from %d to %d\n", baud_raw, *baud);
}
@@ -2114,14 +2170,14 @@ lpuart32_console_get_options(struct lpuart_port *sport, int *baud,
bd = lpuart32_read(&sport->port, UARTBAUD);
bd &= UARTBAUD_SBR_MASK;
sbr = bd;
- uartclk = clk_get_rate(sport->clk);
+ uartclk = lpuart_get_baud_clk_rate(sport);
/*
* baud = mod_clk/(16*(sbr[13]+(brfa)/32)
*/
baud_raw = uartclk / (16 * sbr);
if (*baud != baud_raw)
- printk(KERN_INFO "Serial: Console lpuart rounded baud rate"
+ dev_info(sport->port.dev, "Serial: Console lpuart rounded baud rate"
"from %d to %d\n", baud_raw, *baud);
}
@@ -2288,6 +2344,7 @@ static int lpuart_probe(struct platform_device *pdev)
sport->port.mapbase = res->start;
sport->port.dev = &pdev->dev;
sport->port.type = PORT_LPUART;
+ sport->devtype = sdata->devtype;
ret = platform_get_irq(pdev, 0);
if (ret < 0) {
dev_err(&pdev->dev, "cannot obtain irq\n");
@@ -2303,20 +2360,27 @@ static int lpuart_probe(struct platform_device *pdev)
sport->port.rs485_config = lpuart_config_rs485;
- sport->clk = devm_clk_get(&pdev->dev, "ipg");
- if (IS_ERR(sport->clk)) {
- ret = PTR_ERR(sport->clk);
- dev_err(&pdev->dev, "failed to get uart clk: %d\n", ret);
+ sport->ipg_clk = devm_clk_get(&pdev->dev, "ipg");
+ if (IS_ERR(sport->ipg_clk)) {
+ ret = PTR_ERR(sport->ipg_clk);
+ dev_err(&pdev->dev, "failed to get uart ipg clk: %d\n", ret);
return ret;
}
- ret = clk_prepare_enable(sport->clk);
- if (ret) {
- dev_err(&pdev->dev, "failed to enable uart clk: %d\n", ret);
- return ret;
+ sport->baud_clk = NULL;
+ if (is_imx8qxp_lpuart(sport)) {
+ sport->baud_clk = devm_clk_get(&pdev->dev, "baud");
+ if (IS_ERR(sport->baud_clk)) {
+ ret = PTR_ERR(sport->baud_clk);
+ dev_err(&pdev->dev, "failed to get uart baud clk: %d\n", ret);
+ return ret;
+ }
}
- sport->port.uartclk = clk_get_rate(sport->clk);
+ ret = lpuart_enable_clks(sport);
+ if (ret)
+ return ret;
+ sport->port.uartclk = lpuart_get_baud_clk_rate(sport);
lpuart_ports[sport->port.line] = sport;
@@ -2364,7 +2428,7 @@ static int lpuart_probe(struct platform_device *pdev)
failed_attach_port:
failed_irq_request:
- clk_disable_unprepare(sport->clk);
+ lpuart_disable_clks(sport);
return ret;
}
@@ -2376,7 +2440,7 @@ static int lpuart_remove(struct platform_device *pdev)
ida_simple_remove(&fsl_lpuart_ida, sport->port.line);
- clk_disable_unprepare(sport->clk);
+ lpuart_disable_clks(sport);
if (sport->dma_tx_chan)
dma_release_channel(sport->dma_tx_chan);
@@ -2441,7 +2505,7 @@ static int lpuart_suspend(struct device *dev)
}
if (sport->port.suspended && !irq_wake)
- clk_disable_unprepare(sport->clk);
+ lpuart_disable_clks(sport);
return 0;
}
@@ -2453,7 +2517,7 @@ static int lpuart_resume(struct device *dev)
unsigned long temp;
if (sport->port.suspended && !irq_wake)
- clk_prepare_enable(sport->clk);
+ lpuart_enable_clks(sport);
if (lpuart_is_32(sport)) {
lpuart32_setup_watermark(sport);
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 8b752e895053..57d6e6ba556e 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -383,6 +383,7 @@ static void imx_uart_ucrs_restore(struct imx_port *sport,
}
#endif
+/* called with port.lock taken and irqs caller dependent */
static void imx_uart_rts_active(struct imx_port *sport, u32 *ucr2)
{
*ucr2 &= ~(UCR2_CTSC | UCR2_CTS);
@@ -391,6 +392,7 @@ static void imx_uart_rts_active(struct imx_port *sport, u32 *ucr2)
mctrl_gpio_set(sport->gpios, sport->port.mctrl);
}
+/* called with port.lock taken and irqs caller dependent */
static void imx_uart_rts_inactive(struct imx_port *sport, u32 *ucr2)
{
*ucr2 &= ~UCR2_CTSC;
@@ -400,6 +402,7 @@ static void imx_uart_rts_inactive(struct imx_port *sport, u32 *ucr2)
mctrl_gpio_set(sport->gpios, sport->port.mctrl);
}
+/* called with port.lock taken and irqs caller dependent */
static void imx_uart_rts_auto(struct imx_port *sport, u32 *ucr2)
{
*ucr2 |= UCR2_CTSC;
@@ -1549,40 +1552,46 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios,
old_csize = CS8;
}
+ del_timer_sync(&sport->timer);
+
+ /*
+ * Ask the core to calculate the divisor for us.
+ */
+ baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16);
+ quot = uart_get_divisor(port, baud);
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+
+ /*
+ * Read current UCR2 and save it for future use, then clear all the bits
+ * except those we will or may need to preserve.
+ */
+ old_ucr2 = imx_uart_readl(sport, UCR2);
+ ucr2 = old_ucr2 & (UCR2_TXEN | UCR2_RXEN | UCR2_ATEN | UCR2_CTS);
+
+ ucr2 |= UCR2_SRST | UCR2_IRTS;
if ((termios->c_cflag & CSIZE) == CS8)
- ucr2 = UCR2_WS | UCR2_SRST | UCR2_IRTS;
- else
- ucr2 = UCR2_SRST | UCR2_IRTS;
-
- if (termios->c_cflag & CRTSCTS) {
- if (sport->have_rtscts) {
- ucr2 &= ~UCR2_IRTS;
-
- if (port->rs485.flags & SER_RS485_ENABLED) {
- /*
- * RTS is mandatory for rs485 operation, so keep
- * it under manual control and keep transmitter
- * disabled.
- */
- if (port->rs485.flags &
- SER_RS485_RTS_AFTER_SEND)
- imx_uart_rts_active(sport, &ucr2);
- else
- imx_uart_rts_inactive(sport, &ucr2);
- } else {
- imx_uart_rts_auto(sport, &ucr2);
- }
- } else {
- termios->c_cflag &= ~CRTSCTS;
- }
- } else if (port->rs485.flags & SER_RS485_ENABLED) {
- /* disable transmitter */
+ ucr2 |= UCR2_WS;
+
+ if (!sport->have_rtscts)
+ termios->c_cflag &= ~CRTSCTS;
+
+ if (port->rs485.flags & SER_RS485_ENABLED) {
+ /*
+ * RTS is mandatory for rs485 operation, so keep
+ * it under manual control and keep transmitter
+ * disabled.
+ */
if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
imx_uart_rts_active(sport, &ucr2);
else
imx_uart_rts_inactive(sport, &ucr2);
- }
+ } else if (termios->c_cflag & CRTSCTS)
+ imx_uart_rts_auto(sport, &ucr2);
+
+ if (termios->c_cflag & CRTSCTS)
+ ucr2 &= ~UCR2_IRTS;
if (termios->c_cflag & CSTOPB)
ucr2 |= UCR2_STPB;
@@ -1592,16 +1601,6 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios,
ucr2 |= UCR2_PROE;
}
- del_timer_sync(&sport->timer);
-
- /*
- * Ask the core to calculate the divisor for us.
- */
- baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16);
- quot = uart_get_divisor(port, baud);
-
- spin_lock_irqsave(&sport->port.lock, flags);
-
sport->port.read_status_mask = 0;
if (termios->c_iflag & INPCK)
sport->port.read_status_mask |= (URXD_FRMERR | URXD_PRERR);
@@ -1639,7 +1638,6 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios,
imx_uart_writel(sport,
old_ucr1 & ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN),
UCR1);
- old_ucr2 = imx_uart_readl(sport, UCR2);
imx_uart_writel(sport, old_ucr2 & ~UCR2_ATEN, UCR2);
while (!(imx_uart_readl(sport, USR2) & USR2_TXDC))
@@ -1647,7 +1645,6 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios,
/* then, disable everything */
imx_uart_writel(sport, old_ucr2 & ~(UCR2_TXEN | UCR2_RXEN | UCR2_ATEN), UCR2);
- old_ucr2 &= (UCR2_TXEN | UCR2_RXEN | UCR2_ATEN);
/* custom-baudrate handling */
div = sport->port.uartclk / (baud * 16);
@@ -1685,8 +1682,7 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios,
imx_uart_writel(sport, old_ucr1, UCR1);
- /* set the parity, stop bits and data size */
- imx_uart_writel(sport, ucr2 | old_ucr2, UCR2);
+ imx_uart_writel(sport, ucr2, UCR2);
if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
imx_uart_enable_ms(&sport->port);
@@ -2015,7 +2011,7 @@ imx_uart_console_get_options(struct imx_port *sport, int *baud,
}
if (*baud != baud_raw)
- pr_info("Console IMX rounded baud rate from %d to %d\n",
+ dev_info(sport->port.dev, "Console IMX rounded baud rate from %d to %d\n",
baud_raw, *baud);
}
}
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index e5aebbf5f302..e6c48a99bd85 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -258,12 +258,17 @@ struct max310x_one {
struct work_struct tx_work;
struct work_struct md_work;
struct work_struct rs_work;
+
+ u8 wr_header;
+ u8 rd_header;
+ u8 rx_buf[MAX310X_FIFO_SIZE];
};
+#define to_max310x_port(_port) \
+ container_of(_port, struct max310x_one, port)
struct max310x_port {
struct max310x_devtype *devtype;
struct regmap *regmap;
- struct mutex mutex;
struct clk *clk;
#ifdef CONFIG_GPIOLIB
struct gpio_chip gpio;
@@ -496,37 +501,48 @@ static bool max310x_reg_precious(struct device *dev, unsigned int reg)
static int max310x_set_baud(struct uart_port *port, int baud)
{
- unsigned int mode = 0, clk = port->uartclk, div = clk / baud;
-
- /* Check for minimal value for divider */
- if (div < 16)
- div = 16;
+ unsigned int mode = 0, div = 0, frac = 0, c = 0, F = 0;
- if (clk % baud && (div / 16) < 0x8000) {
+ /*
+ * Calculate the integer divisor first. Select a proper mode
+ * in case if the requested baud is too high for the pre-defined
+ * clocks frequency.
+ */
+ div = port->uartclk / baud;
+ if (div < 8) {
+ /* Mode x4 */
+ c = 4;
+ mode = MAX310X_BRGCFG_4XMODE_BIT;
+ } else if (div < 16) {
/* Mode x2 */
+ c = 8;
mode = MAX310X_BRGCFG_2XMODE_BIT;
- clk = port->uartclk * 2;
- div = clk / baud;
-
- if (clk % baud && (div / 16) < 0x8000) {
- /* Mode x4 */
- mode = MAX310X_BRGCFG_4XMODE_BIT;
- clk = port->uartclk * 4;
- div = clk / baud;
- }
+ } else {
+ c = 16;
}
- max310x_port_write(port, MAX310X_BRGDIVMSB_REG, (div / 16) >> 8);
- max310x_port_write(port, MAX310X_BRGDIVLSB_REG, div / 16);
- max310x_port_write(port, MAX310X_BRGCFG_REG, (div % 16) | mode);
+ /* Calculate the divisor in accordance with the fraction coefficient */
+ div /= c;
+ F = c*baud;
- return DIV_ROUND_CLOSEST(clk, div);
+ /* Calculate the baud rate fraction */
+ if (div > 0)
+ frac = (16*(port->uartclk % F)) / F;
+ else
+ div = 1;
+
+ max310x_port_write(port, MAX310X_BRGDIVMSB_REG, div >> 8);
+ max310x_port_write(port, MAX310X_BRGDIVLSB_REG, div);
+ max310x_port_write(port, MAX310X_BRGCFG_REG, frac | mode);
+
+ /* Return the actual baud rate we just programmed */
+ return (16*port->uartclk) / (c*(16*div + frac));
}
static int max310x_update_best_err(unsigned long f, long *besterr)
{
/* Use baudrate 115200 for calculate error */
- long err = f % (115200 * 16);
+ long err = f % (460800 * 16);
if ((*besterr < 0) || (*besterr > err)) {
*besterr = err;
@@ -607,11 +623,11 @@ static int max310x_set_ref_clk(struct device *dev, struct max310x_port *s,
static void max310x_batch_write(struct uart_port *port, u8 *txbuf, unsigned int len)
{
- u8 header[] = { (port->iobase + MAX310X_THR_REG) | MAX310X_WRITE_BIT };
+ struct max310x_one *one = to_max310x_port(port);
struct spi_transfer xfer[] = {
{
- .tx_buf = &header,
- .len = sizeof(header),
+ .tx_buf = &one->wr_header,
+ .len = sizeof(one->wr_header),
}, {
.tx_buf = txbuf,
.len = len,
@@ -622,11 +638,11 @@ static void max310x_batch_write(struct uart_port *port, u8 *txbuf, unsigned int
static void max310x_batch_read(struct uart_port *port, u8 *rxbuf, unsigned int len)
{
- u8 header[] = { port->iobase + MAX310X_RHR_REG };
+ struct max310x_one *one = to_max310x_port(port);
struct spi_transfer xfer[] = {
{
- .tx_buf = &header,
- .len = sizeof(header),
+ .tx_buf = &one->rd_header,
+ .len = sizeof(one->rd_header),
}, {
.rx_buf = rxbuf,
.len = len,
@@ -637,8 +653,8 @@ static void max310x_batch_read(struct uart_port *port, u8 *rxbuf, unsigned int l
static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
{
+ struct max310x_one *one = to_max310x_port(port);
unsigned int sts, ch, flag, i;
- u8 buf[MAX310X_FIFO_SIZE];
if (port->read_status_mask == MAX310X_LSR_RXOVR_BIT) {
/* We are just reading, happily ignoring any error conditions.
@@ -653,7 +669,7 @@ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
* */
sts = max310x_port_read(port, MAX310X_LSR_IRQSTS_REG);
- max310x_batch_read(port, buf, rxlen);
+ max310x_batch_read(port, one->rx_buf, rxlen);
port->icount.rx += rxlen;
flag = TTY_NORMAL;
@@ -664,9 +680,16 @@ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
port->icount.overrun++;
}
- for (i = 0; i < rxlen; ++i) {
- uart_insert_char(port, sts, MAX310X_LSR_RXOVR_BIT, buf[i], flag);
- }
+ for (i = 0; i < (rxlen - 1); ++i)
+ uart_insert_char(port, sts, 0, one->rx_buf[i], flag);
+
+ /*
+ * Handle the overrun case for the last character only, since
+ * the RxFIFO overflow happens after it is pushed to the FIFO
+ * tail.
+ */
+ uart_insert_char(port, sts, MAX310X_LSR_RXOVR_BIT,
+ one->rx_buf[rxlen], flag);
} else {
if (unlikely(rxlen >= port->fifosize)) {
@@ -766,10 +789,9 @@ static void max310x_handle_tx(struct uart_port *port)
static void max310x_start_tx(struct uart_port *port)
{
- struct max310x_one *one = container_of(port, struct max310x_one, port);
+ struct max310x_one *one = to_max310x_port(port);
- if (!work_pending(&one->tx_work))
- schedule_work(&one->tx_work);
+ schedule_work(&one->tx_work);
}
static irqreturn_t max310x_port_irq(struct max310x_port *s, int portno)
@@ -826,14 +848,11 @@ static irqreturn_t max310x_ist(int irq, void *dev_id)
return IRQ_RETVAL(handled);
}
-static void max310x_wq_proc(struct work_struct *ws)
+static void max310x_tx_proc(struct work_struct *ws)
{
struct max310x_one *one = container_of(ws, struct max310x_one, tx_work);
- struct max310x_port *s = dev_get_drvdata(one->port.dev);
- mutex_lock(&s->mutex);
max310x_handle_tx(&one->port);
- mutex_unlock(&s->mutex);
}
static unsigned int max310x_tx_empty(struct uart_port *port)
@@ -863,7 +882,7 @@ static void max310x_md_proc(struct work_struct *ws)
static void max310x_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
- struct max310x_one *one = container_of(port, struct max310x_one, port);
+ struct max310x_one *one = to_max310x_port(port);
schedule_work(&one->md_work);
}
@@ -962,37 +981,36 @@ static void max310x_set_termios(struct uart_port *port,
static void max310x_rs_proc(struct work_struct *ws)
{
struct max310x_one *one = container_of(ws, struct max310x_one, rs_work);
- unsigned int val;
+ unsigned int delay, mode1 = 0, mode2 = 0;
- val = (one->port.rs485.delay_rts_before_send << 4) |
+ delay = (one->port.rs485.delay_rts_before_send << 4) |
one->port.rs485.delay_rts_after_send;
- max310x_port_write(&one->port, MAX310X_HDPIXDELAY_REG, val);
+ max310x_port_write(&one->port, MAX310X_HDPIXDELAY_REG, delay);
if (one->port.rs485.flags & SER_RS485_ENABLED) {
- max310x_port_update(&one->port, MAX310X_MODE1_REG,
- MAX310X_MODE1_TRNSCVCTRL_BIT,
- MAX310X_MODE1_TRNSCVCTRL_BIT);
- max310x_port_update(&one->port, MAX310X_MODE2_REG,
- MAX310X_MODE2_ECHOSUPR_BIT,
- MAX310X_MODE2_ECHOSUPR_BIT);
- } else {
- max310x_port_update(&one->port, MAX310X_MODE1_REG,
- MAX310X_MODE1_TRNSCVCTRL_BIT, 0);
- max310x_port_update(&one->port, MAX310X_MODE2_REG,
- MAX310X_MODE2_ECHOSUPR_BIT, 0);
+ mode1 = MAX310X_MODE1_TRNSCVCTRL_BIT;
+
+ if (!(one->port.rs485.flags & SER_RS485_RX_DURING_TX))
+ mode2 = MAX310X_MODE2_ECHOSUPR_BIT;
}
+
+ max310x_port_update(&one->port, MAX310X_MODE1_REG,
+ MAX310X_MODE1_TRNSCVCTRL_BIT, mode1);
+ max310x_port_update(&one->port, MAX310X_MODE2_REG,
+ MAX310X_MODE2_ECHOSUPR_BIT, mode2);
}
static int max310x_rs485_config(struct uart_port *port,
struct serial_rs485 *rs485)
{
- struct max310x_one *one = container_of(port, struct max310x_one, port);
+ struct max310x_one *one = to_max310x_port(port);
if ((rs485->delay_rts_before_send > 0x0f) ||
(rs485->delay_rts_after_send > 0x0f))
return -ERANGE;
- rs485->flags &= SER_RS485_RTS_ON_SEND | SER_RS485_ENABLED;
+ rs485->flags &= SER_RS485_RTS_ON_SEND | SER_RS485_RX_DURING_TX |
+ SER_RS485_ENABLED;
memset(rs485->padding, 0, sizeof(rs485->padding));
port->rs485 = *rs485;
@@ -1018,6 +1036,22 @@ static int max310x_startup(struct uart_port *port)
max310x_port_update(port, MAX310X_MODE2_REG,
MAX310X_MODE2_FIFORST_BIT, 0);
+ /* Configure mode1/mode2 to have rs485/rs232 enabled at startup */
+ val = (clamp(port->rs485.delay_rts_before_send, 0U, 15U) << 4) |
+ clamp(port->rs485.delay_rts_after_send, 0U, 15U);
+ max310x_port_write(port, MAX310X_HDPIXDELAY_REG, val);
+
+ if (port->rs485.flags & SER_RS485_ENABLED) {
+ max310x_port_update(port, MAX310X_MODE1_REG,
+ MAX310X_MODE1_TRNSCVCTRL_BIT,
+ MAX310X_MODE1_TRNSCVCTRL_BIT);
+
+ if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
+ max310x_port_update(port, MAX310X_MODE2_REG,
+ MAX310X_MODE2_ECHOSUPR_BIT,
+ MAX310X_MODE2_ECHOSUPR_BIT);
+ }
+
/* Configure flow control levels */
/* Flow control halt level 96, resume level 48 */
max310x_port_write(port, MAX310X_FLOWLVL_REG,
@@ -1269,8 +1303,6 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
uartclk = max310x_set_ref_clk(dev, s, freq, xtal);
dev_dbg(dev, "Reference clock set to %i Hz\n", uartclk);
- mutex_init(&s->mutex);
-
for (i = 0; i < devtype->nr; i++) {
unsigned int line;
@@ -1298,11 +1330,15 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
/* Clear IRQ status register */
max310x_port_read(&s->p[i].port, MAX310X_IRQSTS_REG);
/* Initialize queue for start TX */
- INIT_WORK(&s->p[i].tx_work, max310x_wq_proc);
+ INIT_WORK(&s->p[i].tx_work, max310x_tx_proc);
/* Initialize queue for changing LOOPBACK mode */
INIT_WORK(&s->p[i].md_work, max310x_md_proc);
/* Initialize queue for changing RS485 mode */
INIT_WORK(&s->p[i].rs_work, max310x_rs_proc);
+ /* Initialize SPI-transfer buffers */
+ s->p[i].wr_header = (s->p[i].port.iobase + MAX310X_THR_REG) |
+ MAX310X_WRITE_BIT;
+ s->p[i].rd_header = (s->p[i].port.iobase + MAX310X_RHR_REG);
/* Register port */
ret = uart_add_one_port(&max310x_uart, &s->p[i].port);
@@ -1350,8 +1386,6 @@ out_uart:
}
}
- mutex_destroy(&s->mutex);
-
out_clk:
clk_disable_unprepare(s->clk);
@@ -1372,7 +1406,6 @@ static int max310x_remove(struct device *dev)
s->devtype->power(&s->p[i].port, 0);
}
- mutex_destroy(&s->mutex);
clk_disable_unprepare(s->clk);
return 0;
diff --git a/drivers/tty/serial/mpsc.c b/drivers/tty/serial/mpsc.c
deleted file mode 100644
index 1f60d6fe4ff2..000000000000
--- a/drivers/tty/serial/mpsc.c
+++ /dev/null
@@ -1,2138 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Generic driver for the MPSC (UART mode) on Marvell parts (e.g., GT64240,
- * GT64260, MV64340, MV64360, GT96100, ... ).
- *
- * Author: Mark A. Greer <mgreer@mvista.com>
- *
- * Based on an old MPSC driver that was in the linuxppc tree. It appears to
- * have been created by Chris Zankel (formerly of MontaVista) but there
- * is no proper Copyright so I'm not sure. Apparently, parts were also
- * taken from PPCBoot (now U-Boot). Also based on drivers/serial/8250.c
- * by Russell King.
- *
- * 2004 (c) MontaVista, Software, Inc.
- */
-/*
- * The MPSC interface is much like a typical network controller's interface.
- * That is, you set up separate rings of descriptors for transmitting and
- * receiving data. There is also a pool of buffers with (one buffer per
- * descriptor) that incoming data are dma'd into or outgoing data are dma'd
- * out of.
- *
- * The MPSC requires two other controllers to be able to work. The Baud Rate
- * Generator (BRG) provides a clock at programmable frequencies which determines
- * the baud rate. The Serial DMA Controller (SDMA) takes incoming data from the
- * MPSC and DMA's it into memory or DMA's outgoing data and passes it to the
- * MPSC. It is actually the SDMA interrupt that the driver uses to keep the
- * transmit and receive "engines" going (i.e., indicate data has been
- * transmitted or received).
- *
- * NOTES:
- *
- * 1) Some chips have an erratum where several regs cannot be
- * read. To work around that, we keep a local copy of those regs in
- * 'mpsc_port_info'.
- *
- * 2) Some chips have an erratum where the ctlr will hang when the SDMA ctlr
- * accesses system mem with coherency enabled. For that reason, the driver
- * assumes that coherency for that ctlr has been disabled. This means
- * that when in a cache coherent system, the driver has to manually manage
- * the data cache on the areas that it touches because the dma_* macro are
- * basically no-ops.
- *
- * 3) There is an erratum (on PPC) where you can't use the instruction to do
- * a DMA_TO_DEVICE/cache clean so DMA_BIDIRECTIONAL/flushes are used in places
- * where a DMA_TO_DEVICE/clean would have [otherwise] sufficed.
- *
- * 4) AFAICT, hardware flow control isn't supported by the controller --MAG.
- */
-
-
-#if defined(CONFIG_SERIAL_MPSC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/mv643xx.h>
-#include <linux/platform_device.h>
-#include <linux/gfp.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#define MPSC_NUM_CTLRS 2
-
-/*
- * Descriptors and buffers must be cache line aligned.
- * Buffers lengths must be multiple of cache line size.
- * Number of Tx & Rx descriptors must be powers of 2.
- */
-#define MPSC_RXR_ENTRIES 32
-#define MPSC_RXRE_SIZE dma_get_cache_alignment()
-#define MPSC_RXR_SIZE (MPSC_RXR_ENTRIES * MPSC_RXRE_SIZE)
-#define MPSC_RXBE_SIZE dma_get_cache_alignment()
-#define MPSC_RXB_SIZE (MPSC_RXR_ENTRIES * MPSC_RXBE_SIZE)
-
-#define MPSC_TXR_ENTRIES 32
-#define MPSC_TXRE_SIZE dma_get_cache_alignment()
-#define MPSC_TXR_SIZE (MPSC_TXR_ENTRIES * MPSC_TXRE_SIZE)
-#define MPSC_TXBE_SIZE dma_get_cache_alignment()
-#define MPSC_TXB_SIZE (MPSC_TXR_ENTRIES * MPSC_TXBE_SIZE)
-
-#define MPSC_DMA_ALLOC_SIZE (MPSC_RXR_SIZE + MPSC_RXB_SIZE + MPSC_TXR_SIZE \
- + MPSC_TXB_SIZE + dma_get_cache_alignment() /* for alignment */)
-
-/* Rx and Tx Ring entry descriptors -- assume entry size is <= cacheline size */
-struct mpsc_rx_desc {
- u16 bufsize;
- u16 bytecnt;
- u32 cmdstat;
- u32 link;
- u32 buf_ptr;
-} __attribute((packed));
-
-struct mpsc_tx_desc {
- u16 bytecnt;
- u16 shadow;
- u32 cmdstat;
- u32 link;
- u32 buf_ptr;
-} __attribute((packed));
-
-/*
- * Some regs that have the erratum that you can't read them are are shared
- * between the two MPSC controllers. This struct contains those shared regs.
- */
-struct mpsc_shared_regs {
- phys_addr_t mpsc_routing_base_p;
- phys_addr_t sdma_intr_base_p;
-
- void __iomem *mpsc_routing_base;
- void __iomem *sdma_intr_base;
-
- u32 MPSC_MRR_m;
- u32 MPSC_RCRR_m;
- u32 MPSC_TCRR_m;
- u32 SDMA_INTR_CAUSE_m;
- u32 SDMA_INTR_MASK_m;
-};
-
-/* The main driver data structure */
-struct mpsc_port_info {
- struct uart_port port; /* Overlay uart_port structure */
-
- /* Internal driver state for this ctlr */
- u8 ready;
- u8 rcv_data;
-
- /* Info passed in from platform */
- u8 mirror_regs; /* Need to mirror regs? */
- u8 cache_mgmt; /* Need manual cache mgmt? */
- u8 brg_can_tune; /* BRG has baud tuning? */
- u32 brg_clk_src;
- u16 mpsc_max_idle;
- int default_baud;
- int default_bits;
- int default_parity;
- int default_flow;
-
- /* Physical addresses of various blocks of registers (from platform) */
- phys_addr_t mpsc_base_p;
- phys_addr_t sdma_base_p;
- phys_addr_t brg_base_p;
-
- /* Virtual addresses of various blocks of registers (from platform) */
- void __iomem *mpsc_base;
- void __iomem *sdma_base;
- void __iomem *brg_base;
-
- /* Descriptor ring and buffer allocations */
- void *dma_region;
- dma_addr_t dma_region_p;
-
- dma_addr_t rxr; /* Rx descriptor ring */
- dma_addr_t rxr_p; /* Phys addr of rxr */
- u8 *rxb; /* Rx Ring I/O buf */
- u8 *rxb_p; /* Phys addr of rxb */
- u32 rxr_posn; /* First desc w/ Rx data */
-
- dma_addr_t txr; /* Tx descriptor ring */
- dma_addr_t txr_p; /* Phys addr of txr */
- u8 *txb; /* Tx Ring I/O buf */
- u8 *txb_p; /* Phys addr of txb */
- int txr_head; /* Where new data goes */
- int txr_tail; /* Where sent data comes off */
- spinlock_t tx_lock; /* transmit lock */
-
- /* Mirrored values of regs we can't read (if 'mirror_regs' set) */
- u32 MPSC_MPCR_m;
- u32 MPSC_CHR_1_m;
- u32 MPSC_CHR_2_m;
- u32 MPSC_CHR_10_m;
- u32 BRG_BCR_m;
- struct mpsc_shared_regs *shared_regs;
-};
-
-/* Hooks to platform-specific code */
-int mpsc_platform_register_driver(void);
-void mpsc_platform_unregister_driver(void);
-
-/* Hooks back in to mpsc common to be called by platform-specific code */
-struct mpsc_port_info *mpsc_device_probe(int index);
-struct mpsc_port_info *mpsc_device_remove(int index);
-
-/* Main MPSC Configuration Register Offsets */
-#define MPSC_MMCRL 0x0000
-#define MPSC_MMCRH 0x0004
-#define MPSC_MPCR 0x0008
-#define MPSC_CHR_1 0x000c
-#define MPSC_CHR_2 0x0010
-#define MPSC_CHR_3 0x0014
-#define MPSC_CHR_4 0x0018
-#define MPSC_CHR_5 0x001c
-#define MPSC_CHR_6 0x0020
-#define MPSC_CHR_7 0x0024
-#define MPSC_CHR_8 0x0028
-#define MPSC_CHR_9 0x002c
-#define MPSC_CHR_10 0x0030
-#define MPSC_CHR_11 0x0034
-
-#define MPSC_MPCR_FRZ (1 << 9)
-#define MPSC_MPCR_CL_5 0
-#define MPSC_MPCR_CL_6 1
-#define MPSC_MPCR_CL_7 2
-#define MPSC_MPCR_CL_8 3
-#define MPSC_MPCR_SBL_1 0
-#define MPSC_MPCR_SBL_2 1
-
-#define MPSC_CHR_2_TEV (1<<1)
-#define MPSC_CHR_2_TA (1<<7)
-#define MPSC_CHR_2_TTCS (1<<9)
-#define MPSC_CHR_2_REV (1<<17)
-#define MPSC_CHR_2_RA (1<<23)
-#define MPSC_CHR_2_CRD (1<<25)
-#define MPSC_CHR_2_EH (1<<31)
-#define MPSC_CHR_2_PAR_ODD 0
-#define MPSC_CHR_2_PAR_SPACE 1
-#define MPSC_CHR_2_PAR_EVEN 2
-#define MPSC_CHR_2_PAR_MARK 3
-
-/* MPSC Signal Routing */
-#define MPSC_MRR 0x0000
-#define MPSC_RCRR 0x0004
-#define MPSC_TCRR 0x0008
-
-/* Serial DMA Controller Interface Registers */
-#define SDMA_SDC 0x0000
-#define SDMA_SDCM 0x0008
-#define SDMA_RX_DESC 0x0800
-#define SDMA_RX_BUF_PTR 0x0808
-#define SDMA_SCRDP 0x0810
-#define SDMA_TX_DESC 0x0c00
-#define SDMA_SCTDP 0x0c10
-#define SDMA_SFTDP 0x0c14
-
-#define SDMA_DESC_CMDSTAT_PE (1<<0)
-#define SDMA_DESC_CMDSTAT_CDL (1<<1)
-#define SDMA_DESC_CMDSTAT_FR (1<<3)
-#define SDMA_DESC_CMDSTAT_OR (1<<6)
-#define SDMA_DESC_CMDSTAT_BR (1<<9)
-#define SDMA_DESC_CMDSTAT_MI (1<<10)
-#define SDMA_DESC_CMDSTAT_A (1<<11)
-#define SDMA_DESC_CMDSTAT_AM (1<<12)
-#define SDMA_DESC_CMDSTAT_CT (1<<13)
-#define SDMA_DESC_CMDSTAT_C (1<<14)
-#define SDMA_DESC_CMDSTAT_ES (1<<15)
-#define SDMA_DESC_CMDSTAT_L (1<<16)
-#define SDMA_DESC_CMDSTAT_F (1<<17)
-#define SDMA_DESC_CMDSTAT_P (1<<18)
-#define SDMA_DESC_CMDSTAT_EI (1<<23)
-#define SDMA_DESC_CMDSTAT_O (1<<31)
-
-#define SDMA_DESC_DFLT (SDMA_DESC_CMDSTAT_O \
- | SDMA_DESC_CMDSTAT_EI)
-
-#define SDMA_SDC_RFT (1<<0)
-#define SDMA_SDC_SFM (1<<1)
-#define SDMA_SDC_BLMR (1<<6)
-#define SDMA_SDC_BLMT (1<<7)
-#define SDMA_SDC_POVR (1<<8)
-#define SDMA_SDC_RIFB (1<<9)
-
-#define SDMA_SDCM_ERD (1<<7)
-#define SDMA_SDCM_AR (1<<15)
-#define SDMA_SDCM_STD (1<<16)
-#define SDMA_SDCM_TXD (1<<23)
-#define SDMA_SDCM_AT (1<<31)
-
-#define SDMA_0_CAUSE_RXBUF (1<<0)
-#define SDMA_0_CAUSE_RXERR (1<<1)
-#define SDMA_0_CAUSE_TXBUF (1<<2)
-#define SDMA_0_CAUSE_TXEND (1<<3)
-#define SDMA_1_CAUSE_RXBUF (1<<8)
-#define SDMA_1_CAUSE_RXERR (1<<9)
-#define SDMA_1_CAUSE_TXBUF (1<<10)
-#define SDMA_1_CAUSE_TXEND (1<<11)
-
-#define SDMA_CAUSE_RX_MASK (SDMA_0_CAUSE_RXBUF | SDMA_0_CAUSE_RXERR \
- | SDMA_1_CAUSE_RXBUF | SDMA_1_CAUSE_RXERR)
-#define SDMA_CAUSE_TX_MASK (SDMA_0_CAUSE_TXBUF | SDMA_0_CAUSE_TXEND \
- | SDMA_1_CAUSE_TXBUF | SDMA_1_CAUSE_TXEND)
-
-/* SDMA Interrupt registers */
-#define SDMA_INTR_CAUSE 0x0000
-#define SDMA_INTR_MASK 0x0080
-
-/* Baud Rate Generator Interface Registers */
-#define BRG_BCR 0x0000
-#define BRG_BTR 0x0004
-
-/*
- * Define how this driver is known to the outside (we've been assigned a
- * range on the "Low-density serial ports" major).
- */
-#define MPSC_MAJOR 204
-#define MPSC_MINOR_START 44
-#define MPSC_DRIVER_NAME "MPSC"
-#define MPSC_DEV_NAME "ttyMM"
-#define MPSC_VERSION "1.00"
-
-static struct mpsc_port_info mpsc_ports[MPSC_NUM_CTLRS];
-static struct mpsc_shared_regs mpsc_shared_regs;
-static struct uart_driver mpsc_reg;
-
-static void mpsc_start_rx(struct mpsc_port_info *pi);
-static void mpsc_free_ring_mem(struct mpsc_port_info *pi);
-static void mpsc_release_port(struct uart_port *port);
-/*
- ******************************************************************************
- *
- * Baud Rate Generator Routines (BRG)
- *
- ******************************************************************************
- */
-static void mpsc_brg_init(struct mpsc_port_info *pi, u32 clk_src)
-{
- u32 v;
-
- v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR);
- v = (v & ~(0xf << 18)) | ((clk_src & 0xf) << 18);
-
- if (pi->brg_can_tune)
- v &= ~(1 << 25);
-
- if (pi->mirror_regs)
- pi->BRG_BCR_m = v;
- writel(v, pi->brg_base + BRG_BCR);
-
- writel(readl(pi->brg_base + BRG_BTR) & 0xffff0000,
- pi->brg_base + BRG_BTR);
-}
-
-static void mpsc_brg_enable(struct mpsc_port_info *pi)
-{
- u32 v;
-
- v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR);
- v |= (1 << 16);
-
- if (pi->mirror_regs)
- pi->BRG_BCR_m = v;
- writel(v, pi->brg_base + BRG_BCR);
-}
-
-static void mpsc_brg_disable(struct mpsc_port_info *pi)
-{
- u32 v;
-
- v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR);
- v &= ~(1 << 16);
-
- if (pi->mirror_regs)
- pi->BRG_BCR_m = v;
- writel(v, pi->brg_base + BRG_BCR);
-}
-
-/*
- * To set the baud, we adjust the CDV field in the BRG_BCR reg.
- * From manual: Baud = clk / ((CDV+1)*2) ==> CDV = (clk / (baud*2)) - 1.
- * However, the input clock is divided by 16 in the MPSC b/c of how
- * 'MPSC_MMCRH' was set up so we have to divide the 'clk' used in our
- * calculation by 16 to account for that. So the real calculation
- * that accounts for the way the mpsc is set up is:
- * CDV = (clk / (baud*2*16)) - 1 ==> CDV = (clk / (baud << 5)) - 1.
- */
-static void mpsc_set_baudrate(struct mpsc_port_info *pi, u32 baud)
-{
- u32 cdv = (pi->port.uartclk / (baud << 5)) - 1;
- u32 v;
-
- mpsc_brg_disable(pi);
- v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR);
- v = (v & 0xffff0000) | (cdv & 0xffff);
-
- if (pi->mirror_regs)
- pi->BRG_BCR_m = v;
- writel(v, pi->brg_base + BRG_BCR);
- mpsc_brg_enable(pi);
-}
-
-/*
- ******************************************************************************
- *
- * Serial DMA Routines (SDMA)
- *
- ******************************************************************************
- */
-
-static void mpsc_sdma_burstsize(struct mpsc_port_info *pi, u32 burst_size)
-{
- u32 v;
-
- pr_debug("mpsc_sdma_burstsize[%d]: burst_size: %d\n",
- pi->port.line, burst_size);
-
- burst_size >>= 3; /* Divide by 8 b/c reg values are 8-byte chunks */
-
- if (burst_size < 2)
- v = 0x0; /* 1 64-bit word */
- else if (burst_size < 4)
- v = 0x1; /* 2 64-bit words */
- else if (burst_size < 8)
- v = 0x2; /* 4 64-bit words */
- else
- v = 0x3; /* 8 64-bit words */
-
- writel((readl(pi->sdma_base + SDMA_SDC) & (0x3 << 12)) | (v << 12),
- pi->sdma_base + SDMA_SDC);
-}
-
-static void mpsc_sdma_init(struct mpsc_port_info *pi, u32 burst_size)
-{
- pr_debug("mpsc_sdma_init[%d]: burst_size: %d\n", pi->port.line,
- burst_size);
-
- writel((readl(pi->sdma_base + SDMA_SDC) & 0x3ff) | 0x03f,
- pi->sdma_base + SDMA_SDC);
- mpsc_sdma_burstsize(pi, burst_size);
-}
-
-static u32 mpsc_sdma_intr_mask(struct mpsc_port_info *pi, u32 mask)
-{
- u32 old, v;
-
- pr_debug("mpsc_sdma_intr_mask[%d]: mask: 0x%x\n", pi->port.line, mask);
-
- old = v = (pi->mirror_regs) ? pi->shared_regs->SDMA_INTR_MASK_m :
- readl(pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK);
-
- mask &= 0xf;
- if (pi->port.line)
- mask <<= 8;
- v &= ~mask;
-
- if (pi->mirror_regs)
- pi->shared_regs->SDMA_INTR_MASK_m = v;
- writel(v, pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK);
-
- if (pi->port.line)
- old >>= 8;
- return old & 0xf;
-}
-
-static void mpsc_sdma_intr_unmask(struct mpsc_port_info *pi, u32 mask)
-{
- u32 v;
-
- pr_debug("mpsc_sdma_intr_unmask[%d]: mask: 0x%x\n", pi->port.line,mask);
-
- v = (pi->mirror_regs) ? pi->shared_regs->SDMA_INTR_MASK_m
- : readl(pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK);
-
- mask &= 0xf;
- if (pi->port.line)
- mask <<= 8;
- v |= mask;
-
- if (pi->mirror_regs)
- pi->shared_regs->SDMA_INTR_MASK_m = v;
- writel(v, pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK);
-}
-
-static void mpsc_sdma_intr_ack(struct mpsc_port_info *pi)
-{
- pr_debug("mpsc_sdma_intr_ack[%d]: Acknowledging IRQ\n", pi->port.line);
-
- if (pi->mirror_regs)
- pi->shared_regs->SDMA_INTR_CAUSE_m = 0;
- writeb(0x00, pi->shared_regs->sdma_intr_base + SDMA_INTR_CAUSE
- + pi->port.line);
-}
-
-static void mpsc_sdma_set_rx_ring(struct mpsc_port_info *pi,
- struct mpsc_rx_desc *rxre_p)
-{
- pr_debug("mpsc_sdma_set_rx_ring[%d]: rxre_p: 0x%x\n",
- pi->port.line, (u32)rxre_p);
-
- writel((u32)rxre_p, pi->sdma_base + SDMA_SCRDP);
-}
-
-static void mpsc_sdma_set_tx_ring(struct mpsc_port_info *pi,
- struct mpsc_tx_desc *txre_p)
-{
- writel((u32)txre_p, pi->sdma_base + SDMA_SFTDP);
- writel((u32)txre_p, pi->sdma_base + SDMA_SCTDP);
-}
-
-static void mpsc_sdma_cmd(struct mpsc_port_info *pi, u32 val)
-{
- u32 v;
-
- v = readl(pi->sdma_base + SDMA_SDCM);
- if (val)
- v |= val;
- else
- v = 0;
- wmb();
- writel(v, pi->sdma_base + SDMA_SDCM);
- wmb();
-}
-
-static uint mpsc_sdma_tx_active(struct mpsc_port_info *pi)
-{
- return readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_TXD;
-}
-
-static void mpsc_sdma_start_tx(struct mpsc_port_info *pi)
-{
- struct mpsc_tx_desc *txre, *txre_p;
-
- /* If tx isn't running & there's a desc ready to go, start it */
- if (!mpsc_sdma_tx_active(pi)) {
- txre = (struct mpsc_tx_desc *)(pi->txr
- + (pi->txr_tail * MPSC_TXRE_SIZE));
- dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE,
- DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
- if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
- invalidate_dcache_range((ulong)txre,
- (ulong)txre + MPSC_TXRE_SIZE);
-#endif
-
- if (be32_to_cpu(txre->cmdstat) & SDMA_DESC_CMDSTAT_O) {
- txre_p = (struct mpsc_tx_desc *)
- (pi->txr_p + (pi->txr_tail * MPSC_TXRE_SIZE));
-
- mpsc_sdma_set_tx_ring(pi, txre_p);
- mpsc_sdma_cmd(pi, SDMA_SDCM_STD | SDMA_SDCM_TXD);
- }
- }
-}
-
-static void mpsc_sdma_stop(struct mpsc_port_info *pi)
-{
- pr_debug("mpsc_sdma_stop[%d]: Stopping SDMA\n", pi->port.line);
-
- /* Abort any SDMA transfers */
- mpsc_sdma_cmd(pi, 0);
- mpsc_sdma_cmd(pi, SDMA_SDCM_AR | SDMA_SDCM_AT);
-
- /* Clear the SDMA current and first TX and RX pointers */
- mpsc_sdma_set_tx_ring(pi, NULL);
- mpsc_sdma_set_rx_ring(pi, NULL);
-
- /* Disable interrupts */
- mpsc_sdma_intr_mask(pi, 0xf);
- mpsc_sdma_intr_ack(pi);
-}
-
-/*
- ******************************************************************************
- *
- * Multi-Protocol Serial Controller Routines (MPSC)
- *
- ******************************************************************************
- */
-
-static void mpsc_hw_init(struct mpsc_port_info *pi)
-{
- u32 v;
-
- pr_debug("mpsc_hw_init[%d]: Initializing hardware\n", pi->port.line);
-
- /* Set up clock routing */
- if (pi->mirror_regs) {
- v = pi->shared_regs->MPSC_MRR_m;
- v &= ~0x1c7;
- pi->shared_regs->MPSC_MRR_m = v;
- writel(v, pi->shared_regs->mpsc_routing_base + MPSC_MRR);
-
- v = pi->shared_regs->MPSC_RCRR_m;
- v = (v & ~0xf0f) | 0x100;
- pi->shared_regs->MPSC_RCRR_m = v;
- writel(v, pi->shared_regs->mpsc_routing_base + MPSC_RCRR);
-
- v = pi->shared_regs->MPSC_TCRR_m;
- v = (v & ~0xf0f) | 0x100;
- pi->shared_regs->MPSC_TCRR_m = v;
- writel(v, pi->shared_regs->mpsc_routing_base + MPSC_TCRR);
- } else {
- v = readl(pi->shared_regs->mpsc_routing_base + MPSC_MRR);
- v &= ~0x1c7;
- writel(v, pi->shared_regs->mpsc_routing_base + MPSC_MRR);
-
- v = readl(pi->shared_regs->mpsc_routing_base + MPSC_RCRR);
- v = (v & ~0xf0f) | 0x100;
- writel(v, pi->shared_regs->mpsc_routing_base + MPSC_RCRR);
-
- v = readl(pi->shared_regs->mpsc_routing_base + MPSC_TCRR);
- v = (v & ~0xf0f) | 0x100;
- writel(v, pi->shared_regs->mpsc_routing_base + MPSC_TCRR);
- }
-
- /* Put MPSC in UART mode & enabel Tx/Rx egines */
- writel(0x000004c4, pi->mpsc_base + MPSC_MMCRL);
-
- /* No preamble, 16x divider, low-latency, */
- writel(0x04400400, pi->mpsc_base + MPSC_MMCRH);
- mpsc_set_baudrate(pi, pi->default_baud);
-
- if (pi->mirror_regs) {
- pi->MPSC_CHR_1_m = 0;
- pi->MPSC_CHR_2_m = 0;
- }
- writel(0, pi->mpsc_base + MPSC_CHR_1);
- writel(0, pi->mpsc_base + MPSC_CHR_2);
- writel(pi->mpsc_max_idle, pi->mpsc_base + MPSC_CHR_3);
- writel(0, pi->mpsc_base + MPSC_CHR_4);
- writel(0, pi->mpsc_base + MPSC_CHR_5);
- writel(0, pi->mpsc_base + MPSC_CHR_6);
- writel(0, pi->mpsc_base + MPSC_CHR_7);
- writel(0, pi->mpsc_base + MPSC_CHR_8);
- writel(0, pi->mpsc_base + MPSC_CHR_9);
- writel(0, pi->mpsc_base + MPSC_CHR_10);
-}
-
-static void mpsc_enter_hunt(struct mpsc_port_info *pi)
-{
- pr_debug("mpsc_enter_hunt[%d]: Hunting...\n", pi->port.line);
-
- if (pi->mirror_regs) {
- writel(pi->MPSC_CHR_2_m | MPSC_CHR_2_EH,
- pi->mpsc_base + MPSC_CHR_2);
- /* Erratum prevents reading CHR_2 so just delay for a while */
- udelay(100);
- } else {
- writel(readl(pi->mpsc_base + MPSC_CHR_2) | MPSC_CHR_2_EH,
- pi->mpsc_base + MPSC_CHR_2);
-
- while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_EH)
- udelay(10);
- }
-}
-
-static void mpsc_freeze(struct mpsc_port_info *pi)
-{
- u32 v;
-
- pr_debug("mpsc_freeze[%d]: Freezing\n", pi->port.line);
-
- v = (pi->mirror_regs) ? pi->MPSC_MPCR_m :
- readl(pi->mpsc_base + MPSC_MPCR);
- v |= MPSC_MPCR_FRZ;
-
- if (pi->mirror_regs)
- pi->MPSC_MPCR_m = v;
- writel(v, pi->mpsc_base + MPSC_MPCR);
-}
-
-static void mpsc_unfreeze(struct mpsc_port_info *pi)
-{
- u32 v;
-
- v = (pi->mirror_regs) ? pi->MPSC_MPCR_m :
- readl(pi->mpsc_base + MPSC_MPCR);
- v &= ~MPSC_MPCR_FRZ;
-
- if (pi->mirror_regs)
- pi->MPSC_MPCR_m = v;
- writel(v, pi->mpsc_base + MPSC_MPCR);
-
- pr_debug("mpsc_unfreeze[%d]: Unfrozen\n", pi->port.line);
-}
-
-static void mpsc_set_char_length(struct mpsc_port_info *pi, u32 len)
-{
- u32 v;
-
- pr_debug("mpsc_set_char_length[%d]: char len: %d\n", pi->port.line,len);
-
- v = (pi->mirror_regs) ? pi->MPSC_MPCR_m :
- readl(pi->mpsc_base + MPSC_MPCR);
- v = (v & ~(0x3 << 12)) | ((len & 0x3) << 12);
-
- if (pi->mirror_regs)
- pi->MPSC_MPCR_m = v;
- writel(v, pi->mpsc_base + MPSC_MPCR);
-}
-
-static void mpsc_set_stop_bit_length(struct mpsc_port_info *pi, u32 len)
-{
- u32 v;
-
- pr_debug("mpsc_set_stop_bit_length[%d]: stop bits: %d\n",
- pi->port.line, len);
-
- v = (pi->mirror_regs) ? pi->MPSC_MPCR_m :
- readl(pi->mpsc_base + MPSC_MPCR);
-
- v = (v & ~(1 << 14)) | ((len & 0x1) << 14);
-
- if (pi->mirror_regs)
- pi->MPSC_MPCR_m = v;
- writel(v, pi->mpsc_base + MPSC_MPCR);
-}
-
-static void mpsc_set_parity(struct mpsc_port_info *pi, u32 p)
-{
- u32 v;
-
- pr_debug("mpsc_set_parity[%d]: parity bits: 0x%x\n", pi->port.line, p);
-
- v = (pi->mirror_regs) ? pi->MPSC_CHR_2_m :
- readl(pi->mpsc_base + MPSC_CHR_2);
-
- p &= 0x3;
- v = (v & ~0xc000c) | (p << 18) | (p << 2);
-
- if (pi->mirror_regs)
- pi->MPSC_CHR_2_m = v;
- writel(v, pi->mpsc_base + MPSC_CHR_2);
-}
-
-/*
- ******************************************************************************
- *
- * Driver Init Routines
- *
- ******************************************************************************
- */
-
-static void mpsc_init_hw(struct mpsc_port_info *pi)
-{
- pr_debug("mpsc_init_hw[%d]: Initializing\n", pi->port.line);
-
- mpsc_brg_init(pi, pi->brg_clk_src);
- mpsc_brg_enable(pi);
- mpsc_sdma_init(pi, dma_get_cache_alignment()); /* burst a cacheline */
- mpsc_sdma_stop(pi);
- mpsc_hw_init(pi);
-}
-
-static int mpsc_alloc_ring_mem(struct mpsc_port_info *pi)
-{
- int rc = 0;
-
- pr_debug("mpsc_alloc_ring_mem[%d]: Allocating ring mem\n",
- pi->port.line);
-
- if (!pi->dma_region) {
- if (!dma_set_mask(pi->port.dev, 0xffffffff)) {
- printk(KERN_ERR "MPSC: Inadequate DMA support\n");
- rc = -ENXIO;
- } else if ((pi->dma_region = dma_alloc_attrs(pi->port.dev,
- MPSC_DMA_ALLOC_SIZE,
- &pi->dma_region_p, GFP_KERNEL,
- DMA_ATTR_NON_CONSISTENT))
- == NULL) {
- printk(KERN_ERR "MPSC: Can't alloc Desc region\n");
- rc = -ENOMEM;
- }
- }
-
- return rc;
-}
-
-static void mpsc_free_ring_mem(struct mpsc_port_info *pi)
-{
- pr_debug("mpsc_free_ring_mem[%d]: Freeing ring mem\n", pi->port.line);
-
- if (pi->dma_region) {
- dma_free_attrs(pi->port.dev, MPSC_DMA_ALLOC_SIZE,
- pi->dma_region, pi->dma_region_p,
- DMA_ATTR_NON_CONSISTENT);
- pi->dma_region = NULL;
- pi->dma_region_p = (dma_addr_t)NULL;
- }
-}
-
-static void mpsc_init_rings(struct mpsc_port_info *pi)
-{
- struct mpsc_rx_desc *rxre;
- struct mpsc_tx_desc *txre;
- dma_addr_t dp, dp_p;
- u8 *bp, *bp_p;
- int i;
-
- pr_debug("mpsc_init_rings[%d]: Initializing rings\n", pi->port.line);
-
- BUG_ON(pi->dma_region == NULL);
-
- memset(pi->dma_region, 0, MPSC_DMA_ALLOC_SIZE);
-
- /*
- * Descriptors & buffers are multiples of cacheline size and must be
- * cacheline aligned.
- */
- dp = ALIGN((u32)pi->dma_region, dma_get_cache_alignment());
- dp_p = ALIGN((u32)pi->dma_region_p, dma_get_cache_alignment());
-
- /*
- * Partition dma region into rx ring descriptor, rx buffers,
- * tx ring descriptors, and tx buffers.
- */
- pi->rxr = dp;
- pi->rxr_p = dp_p;
- dp += MPSC_RXR_SIZE;
- dp_p += MPSC_RXR_SIZE;
-
- pi->rxb = (u8 *)dp;
- pi->rxb_p = (u8 *)dp_p;
- dp += MPSC_RXB_SIZE;
- dp_p += MPSC_RXB_SIZE;
-
- pi->rxr_posn = 0;
-
- pi->txr = dp;
- pi->txr_p = dp_p;
- dp += MPSC_TXR_SIZE;
- dp_p += MPSC_TXR_SIZE;
-
- pi->txb = (u8 *)dp;
- pi->txb_p = (u8 *)dp_p;
-
- pi->txr_head = 0;
- pi->txr_tail = 0;
-
- /* Init rx ring descriptors */
- dp = pi->rxr;
- dp_p = pi->rxr_p;
- bp = pi->rxb;
- bp_p = pi->rxb_p;
-
- for (i = 0; i < MPSC_RXR_ENTRIES; i++) {
- rxre = (struct mpsc_rx_desc *)dp;
-
- rxre->bufsize = cpu_to_be16(MPSC_RXBE_SIZE);
- rxre->bytecnt = cpu_to_be16(0);
- rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O
- | SDMA_DESC_CMDSTAT_EI | SDMA_DESC_CMDSTAT_F
- | SDMA_DESC_CMDSTAT_L);
- rxre->link = cpu_to_be32(dp_p + MPSC_RXRE_SIZE);
- rxre->buf_ptr = cpu_to_be32(bp_p);
-
- dp += MPSC_RXRE_SIZE;
- dp_p += MPSC_RXRE_SIZE;
- bp += MPSC_RXBE_SIZE;
- bp_p += MPSC_RXBE_SIZE;
- }
- rxre->link = cpu_to_be32(pi->rxr_p); /* Wrap last back to first */
-
- /* Init tx ring descriptors */
- dp = pi->txr;
- dp_p = pi->txr_p;
- bp = pi->txb;
- bp_p = pi->txb_p;
-
- for (i = 0; i < MPSC_TXR_ENTRIES; i++) {
- txre = (struct mpsc_tx_desc *)dp;
-
- txre->link = cpu_to_be32(dp_p + MPSC_TXRE_SIZE);
- txre->buf_ptr = cpu_to_be32(bp_p);
-
- dp += MPSC_TXRE_SIZE;
- dp_p += MPSC_TXRE_SIZE;
- bp += MPSC_TXBE_SIZE;
- bp_p += MPSC_TXBE_SIZE;
- }
- txre->link = cpu_to_be32(pi->txr_p); /* Wrap last back to first */
-
- dma_cache_sync(pi->port.dev, (void *)pi->dma_region,
- MPSC_DMA_ALLOC_SIZE, DMA_BIDIRECTIONAL);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
- if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
- flush_dcache_range((ulong)pi->dma_region,
- (ulong)pi->dma_region
- + MPSC_DMA_ALLOC_SIZE);
-#endif
-
- return;
-}
-
-static void mpsc_uninit_rings(struct mpsc_port_info *pi)
-{
- pr_debug("mpsc_uninit_rings[%d]: Uninitializing rings\n",pi->port.line);
-
- BUG_ON(pi->dma_region == NULL);
-
- pi->rxr = 0;
- pi->rxr_p = 0;
- pi->rxb = NULL;
- pi->rxb_p = NULL;
- pi->rxr_posn = 0;
-
- pi->txr = 0;
- pi->txr_p = 0;
- pi->txb = NULL;
- pi->txb_p = NULL;
- pi->txr_head = 0;
- pi->txr_tail = 0;
-}
-
-static int mpsc_make_ready(struct mpsc_port_info *pi)
-{
- int rc;
-
- pr_debug("mpsc_make_ready[%d]: Making cltr ready\n", pi->port.line);
-
- if (!pi->ready) {
- mpsc_init_hw(pi);
- rc = mpsc_alloc_ring_mem(pi);
- if (rc)
- return rc;
- mpsc_init_rings(pi);
- pi->ready = 1;
- }
-
- return 0;
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-static int serial_polled;
-#endif
-
-/*
- ******************************************************************************
- *
- * Interrupt Handling Routines
- *
- ******************************************************************************
- */
-
-static int mpsc_rx_intr(struct mpsc_port_info *pi, unsigned long *flags)
-{
- struct mpsc_rx_desc *rxre;
- struct tty_port *port = &pi->port.state->port;
- u32 cmdstat, bytes_in, i;
- int rc = 0;
- u8 *bp;
- char flag = TTY_NORMAL;
-
- pr_debug("mpsc_rx_intr[%d]: Handling Rx intr\n", pi->port.line);
-
- rxre = (struct mpsc_rx_desc *)(pi->rxr + (pi->rxr_posn*MPSC_RXRE_SIZE));
-
- dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE,
- DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
- if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
- invalidate_dcache_range((ulong)rxre,
- (ulong)rxre + MPSC_RXRE_SIZE);
-#endif
-
- /*
- * Loop through Rx descriptors handling ones that have been completed.
- */
- while (!((cmdstat = be32_to_cpu(rxre->cmdstat))
- & SDMA_DESC_CMDSTAT_O)) {
- bytes_in = be16_to_cpu(rxre->bytecnt);
-#ifdef CONFIG_CONSOLE_POLL
- if (unlikely(serial_polled)) {
- serial_polled = 0;
- return 0;
- }
-#endif
- /* Following use of tty struct directly is deprecated */
- if (tty_buffer_request_room(port, bytes_in) < bytes_in) {
- if (port->low_latency) {
- spin_unlock_irqrestore(&pi->port.lock, *flags);
- tty_flip_buffer_push(port);
- spin_lock_irqsave(&pi->port.lock, *flags);
- }
- /*
- * If this failed then we will throw away the bytes
- * but must do so to clear interrupts.
- */
- }
-
- bp = pi->rxb + (pi->rxr_posn * MPSC_RXBE_SIZE);
- dma_cache_sync(pi->port.dev, (void *)bp, MPSC_RXBE_SIZE,
- DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
- if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
- invalidate_dcache_range((ulong)bp,
- (ulong)bp + MPSC_RXBE_SIZE);
-#endif
-
- /*
- * Other than for parity error, the manual provides little
- * info on what data will be in a frame flagged by any of
- * these errors. For parity error, it is the last byte in
- * the buffer that had the error. As for the rest, I guess
- * we'll assume there is no data in the buffer.
- * If there is...it gets lost.
- */
- if (unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR
- | SDMA_DESC_CMDSTAT_FR
- | SDMA_DESC_CMDSTAT_OR))) {
-
- pi->port.icount.rx++;
-
- if (cmdstat & SDMA_DESC_CMDSTAT_BR) { /* Break */
- pi->port.icount.brk++;
-
- if (uart_handle_break(&pi->port))
- goto next_frame;
- } else if (cmdstat & SDMA_DESC_CMDSTAT_FR) {
- pi->port.icount.frame++;
- } else if (cmdstat & SDMA_DESC_CMDSTAT_OR) {
- pi->port.icount.overrun++;
- }
-
- cmdstat &= pi->port.read_status_mask;
-
- if (cmdstat & SDMA_DESC_CMDSTAT_BR)
- flag = TTY_BREAK;
- else if (cmdstat & SDMA_DESC_CMDSTAT_FR)
- flag = TTY_FRAME;
- else if (cmdstat & SDMA_DESC_CMDSTAT_OR)
- flag = TTY_OVERRUN;
- else if (cmdstat & SDMA_DESC_CMDSTAT_PE)
- flag = TTY_PARITY;
- }
-
- if (uart_handle_sysrq_char(&pi->port, *bp)) {
- bp++;
- bytes_in--;
-#ifdef CONFIG_CONSOLE_POLL
- if (unlikely(serial_polled)) {
- serial_polled = 0;
- return 0;
- }
-#endif
- goto next_frame;
- }
-
- if ((unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR
- | SDMA_DESC_CMDSTAT_FR
- | SDMA_DESC_CMDSTAT_OR)))
- && !(cmdstat & pi->port.ignore_status_mask)) {
- tty_insert_flip_char(port, *bp, flag);
- } else {
- for (i=0; i<bytes_in; i++)
- tty_insert_flip_char(port, *bp++, TTY_NORMAL);
-
- pi->port.icount.rx += bytes_in;
- }
-
-next_frame:
- rxre->bytecnt = cpu_to_be16(0);
- wmb();
- rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O
- | SDMA_DESC_CMDSTAT_EI | SDMA_DESC_CMDSTAT_F
- | SDMA_DESC_CMDSTAT_L);
- wmb();
- dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE,
- DMA_BIDIRECTIONAL);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
- if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
- flush_dcache_range((ulong)rxre,
- (ulong)rxre + MPSC_RXRE_SIZE);
-#endif
-
- /* Advance to next descriptor */
- pi->rxr_posn = (pi->rxr_posn + 1) & (MPSC_RXR_ENTRIES - 1);
- rxre = (struct mpsc_rx_desc *)
- (pi->rxr + (pi->rxr_posn * MPSC_RXRE_SIZE));
- dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE,
- DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
- if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
- invalidate_dcache_range((ulong)rxre,
- (ulong)rxre + MPSC_RXRE_SIZE);
-#endif
- rc = 1;
- }
-
- /* Restart rx engine, if its stopped */
- if ((readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_ERD) == 0)
- mpsc_start_rx(pi);
-
- spin_unlock_irqrestore(&pi->port.lock, *flags);
- tty_flip_buffer_push(port);
- spin_lock_irqsave(&pi->port.lock, *flags);
- return rc;
-}
-
-static void mpsc_setup_tx_desc(struct mpsc_port_info *pi, u32 count, u32 intr)
-{
- struct mpsc_tx_desc *txre;
-
- txre = (struct mpsc_tx_desc *)(pi->txr
- + (pi->txr_head * MPSC_TXRE_SIZE));
-
- txre->bytecnt = cpu_to_be16(count);
- txre->shadow = txre->bytecnt;
- wmb(); /* ensure cmdstat is last field updated */
- txre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O | SDMA_DESC_CMDSTAT_F
- | SDMA_DESC_CMDSTAT_L
- | ((intr) ? SDMA_DESC_CMDSTAT_EI : 0));
- wmb();
- dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE,
- DMA_BIDIRECTIONAL);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
- if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
- flush_dcache_range((ulong)txre,
- (ulong)txre + MPSC_TXRE_SIZE);
-#endif
-}
-
-static void mpsc_copy_tx_data(struct mpsc_port_info *pi)
-{
- struct circ_buf *xmit = &pi->port.state->xmit;
- u8 *bp;
- u32 i;
-
- /* Make sure the desc ring isn't full */
- while (CIRC_CNT(pi->txr_head, pi->txr_tail, MPSC_TXR_ENTRIES)
- < (MPSC_TXR_ENTRIES - 1)) {
- if (pi->port.x_char) {
- /*
- * Ideally, we should use the TCS field in
- * CHR_1 to put the x_char out immediately but
- * errata prevents us from being able to read
- * CHR_2 to know that its safe to write to
- * CHR_1. Instead, just put it in-band with
- * all the other Tx data.
- */
- bp = pi->txb + (pi->txr_head * MPSC_TXBE_SIZE);
- *bp = pi->port.x_char;
- pi->port.x_char = 0;
- i = 1;
- } else if (!uart_circ_empty(xmit)
- && !uart_tx_stopped(&pi->port)) {
- i = min((u32)MPSC_TXBE_SIZE,
- (u32)uart_circ_chars_pending(xmit));
- i = min(i, (u32)CIRC_CNT_TO_END(xmit->head, xmit->tail,
- UART_XMIT_SIZE));
- bp = pi->txb + (pi->txr_head * MPSC_TXBE_SIZE);
- memcpy(bp, &xmit->buf[xmit->tail], i);
- xmit->tail = (xmit->tail + i) & (UART_XMIT_SIZE - 1);
-
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(&pi->port);
- } else { /* All tx data copied into ring bufs */
- return;
- }
-
- dma_cache_sync(pi->port.dev, (void *)bp, MPSC_TXBE_SIZE,
- DMA_BIDIRECTIONAL);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
- if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
- flush_dcache_range((ulong)bp,
- (ulong)bp + MPSC_TXBE_SIZE);
-#endif
- mpsc_setup_tx_desc(pi, i, 1);
-
- /* Advance to next descriptor */
- pi->txr_head = (pi->txr_head + 1) & (MPSC_TXR_ENTRIES - 1);
- }
-}
-
-static int mpsc_tx_intr(struct mpsc_port_info *pi)
-{
- struct mpsc_tx_desc *txre;
- int rc = 0;
- unsigned long iflags;
-
- spin_lock_irqsave(&pi->tx_lock, iflags);
-
- if (!mpsc_sdma_tx_active(pi)) {
- txre = (struct mpsc_tx_desc *)(pi->txr
- + (pi->txr_tail * MPSC_TXRE_SIZE));
-
- dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE,
- DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
- if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
- invalidate_dcache_range((ulong)txre,
- (ulong)txre + MPSC_TXRE_SIZE);
-#endif
-
- while (!(be32_to_cpu(txre->cmdstat) & SDMA_DESC_CMDSTAT_O)) {
- rc = 1;
- pi->port.icount.tx += be16_to_cpu(txre->bytecnt);
- pi->txr_tail = (pi->txr_tail+1) & (MPSC_TXR_ENTRIES-1);
-
- /* If no more data to tx, fall out of loop */
- if (pi->txr_head == pi->txr_tail)
- break;
-
- txre = (struct mpsc_tx_desc *)(pi->txr
- + (pi->txr_tail * MPSC_TXRE_SIZE));
- dma_cache_sync(pi->port.dev, (void *)txre,
- MPSC_TXRE_SIZE, DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
- if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
- invalidate_dcache_range((ulong)txre,
- (ulong)txre + MPSC_TXRE_SIZE);
-#endif
- }
-
- mpsc_copy_tx_data(pi);
- mpsc_sdma_start_tx(pi); /* start next desc if ready */
- }
-
- spin_unlock_irqrestore(&pi->tx_lock, iflags);
- return rc;
-}
-
-/*
- * This is the driver's interrupt handler. To avoid a race, we first clear
- * the interrupt, then handle any completed Rx/Tx descriptors. When done
- * handling those descriptors, we restart the Rx/Tx engines if they're stopped.
- */
-static irqreturn_t mpsc_sdma_intr(int irq, void *dev_id)
-{
- struct mpsc_port_info *pi = dev_id;
- ulong iflags;
- int rc = IRQ_NONE;
-
- pr_debug("mpsc_sdma_intr[%d]: SDMA Interrupt Received\n",pi->port.line);
-
- spin_lock_irqsave(&pi->port.lock, iflags);
- mpsc_sdma_intr_ack(pi);
- if (mpsc_rx_intr(pi, &iflags))
- rc = IRQ_HANDLED;
- if (mpsc_tx_intr(pi))
- rc = IRQ_HANDLED;
- spin_unlock_irqrestore(&pi->port.lock, iflags);
-
- pr_debug("mpsc_sdma_intr[%d]: SDMA Interrupt Handled\n", pi->port.line);
- return rc;
-}
-
-/*
- ******************************************************************************
- *
- * serial_core.c Interface routines
- *
- ******************************************************************************
- */
-static uint mpsc_tx_empty(struct uart_port *port)
-{
- struct mpsc_port_info *pi =
- container_of(port, struct mpsc_port_info, port);
- ulong iflags;
- uint rc;
-
- spin_lock_irqsave(&pi->port.lock, iflags);
- rc = mpsc_sdma_tx_active(pi) ? 0 : TIOCSER_TEMT;
- spin_unlock_irqrestore(&pi->port.lock, iflags);
-
- return rc;
-}
-
-static void mpsc_set_mctrl(struct uart_port *port, uint mctrl)
-{
- /* Have no way to set modem control lines AFAICT */
-}
-
-static uint mpsc_get_mctrl(struct uart_port *port)
-{
- struct mpsc_port_info *pi =
- container_of(port, struct mpsc_port_info, port);
- u32 mflags, status;
-
- status = (pi->mirror_regs) ? pi->MPSC_CHR_10_m
- : readl(pi->mpsc_base + MPSC_CHR_10);
-
- mflags = 0;
- if (status & 0x1)
- mflags |= TIOCM_CTS;
- if (status & 0x2)
- mflags |= TIOCM_CAR;
-
- return mflags | TIOCM_DSR; /* No way to tell if DSR asserted */
-}
-
-static void mpsc_stop_tx(struct uart_port *port)
-{
- struct mpsc_port_info *pi =
- container_of(port, struct mpsc_port_info, port);
-
- pr_debug("mpsc_stop_tx[%d]\n", port->line);
-
- mpsc_freeze(pi);
-}
-
-static void mpsc_start_tx(struct uart_port *port)
-{
- struct mpsc_port_info *pi =
- container_of(port, struct mpsc_port_info, port);
- unsigned long iflags;
-
- spin_lock_irqsave(&pi->tx_lock, iflags);
-
- mpsc_unfreeze(pi);
- mpsc_copy_tx_data(pi);
- mpsc_sdma_start_tx(pi);
-
- spin_unlock_irqrestore(&pi->tx_lock, iflags);
-
- pr_debug("mpsc_start_tx[%d]\n", port->line);
-}
-
-static void mpsc_start_rx(struct mpsc_port_info *pi)
-{
- pr_debug("mpsc_start_rx[%d]: Starting...\n", pi->port.line);
-
- if (pi->rcv_data) {
- mpsc_enter_hunt(pi);
- mpsc_sdma_cmd(pi, SDMA_SDCM_ERD);
- }
-}
-
-static void mpsc_stop_rx(struct uart_port *port)
-{
- struct mpsc_port_info *pi =
- container_of(port, struct mpsc_port_info, port);
-
- pr_debug("mpsc_stop_rx[%d]: Stopping...\n", port->line);
-
- if (pi->mirror_regs) {
- writel(pi->MPSC_CHR_2_m | MPSC_CHR_2_RA,
- pi->mpsc_base + MPSC_CHR_2);
- /* Erratum prevents reading CHR_2 so just delay for a while */
- udelay(100);
- } else {
- writel(readl(pi->mpsc_base + MPSC_CHR_2) | MPSC_CHR_2_RA,
- pi->mpsc_base + MPSC_CHR_2);
-
- while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_RA)
- udelay(10);
- }
-
- mpsc_sdma_cmd(pi, SDMA_SDCM_AR);
-}
-
-static void mpsc_break_ctl(struct uart_port *port, int ctl)
-{
- struct mpsc_port_info *pi =
- container_of(port, struct mpsc_port_info, port);
- ulong flags;
- u32 v;
-
- v = ctl ? 0x00ff0000 : 0;
-
- spin_lock_irqsave(&pi->port.lock, flags);
- if (pi->mirror_regs)
- pi->MPSC_CHR_1_m = v;
- writel(v, pi->mpsc_base + MPSC_CHR_1);
- spin_unlock_irqrestore(&pi->port.lock, flags);
-}
-
-static int mpsc_startup(struct uart_port *port)
-{
- struct mpsc_port_info *pi =
- container_of(port, struct mpsc_port_info, port);
- u32 flag = 0;
- int rc;
-
- pr_debug("mpsc_startup[%d]: Starting up MPSC, irq: %d\n",
- port->line, pi->port.irq);
-
- if ((rc = mpsc_make_ready(pi)) == 0) {
- /* Setup IRQ handler */
- mpsc_sdma_intr_ack(pi);
-
- /* If irq's are shared, need to set flag */
- if (mpsc_ports[0].port.irq == mpsc_ports[1].port.irq)
- flag = IRQF_SHARED;
-
- if (request_irq(pi->port.irq, mpsc_sdma_intr, flag,
- "mpsc-sdma", pi))
- printk(KERN_ERR "MPSC: Can't get SDMA IRQ %d\n",
- pi->port.irq);
-
- mpsc_sdma_intr_unmask(pi, 0xf);
- mpsc_sdma_set_rx_ring(pi, (struct mpsc_rx_desc *)(pi->rxr_p
- + (pi->rxr_posn * MPSC_RXRE_SIZE)));
- }
-
- return rc;
-}
-
-static void mpsc_shutdown(struct uart_port *port)
-{
- struct mpsc_port_info *pi =
- container_of(port, struct mpsc_port_info, port);
-
- pr_debug("mpsc_shutdown[%d]: Shutting down MPSC\n", port->line);
-
- mpsc_sdma_stop(pi);
- free_irq(pi->port.irq, pi);
-}
-
-static void mpsc_set_termios(struct uart_port *port, struct ktermios *termios,
- struct ktermios *old)
-{
- struct mpsc_port_info *pi =
- container_of(port, struct mpsc_port_info, port);
- u32 baud;
- ulong flags;
- u32 chr_bits, stop_bits, par;
-
- switch (termios->c_cflag & CSIZE) {
- case CS5:
- chr_bits = MPSC_MPCR_CL_5;
- break;
- case CS6:
- chr_bits = MPSC_MPCR_CL_6;
- break;
- case CS7:
- chr_bits = MPSC_MPCR_CL_7;
- break;
- case CS8:
- default:
- chr_bits = MPSC_MPCR_CL_8;
- break;
- }
-
- if (termios->c_cflag & CSTOPB)
- stop_bits = MPSC_MPCR_SBL_2;
- else
- stop_bits = MPSC_MPCR_SBL_1;
-
- par = MPSC_CHR_2_PAR_EVEN;
- if (termios->c_cflag & PARENB)
- if (termios->c_cflag & PARODD)
- par = MPSC_CHR_2_PAR_ODD;
-#ifdef CMSPAR
- if (termios->c_cflag & CMSPAR) {
- if (termios->c_cflag & PARODD)
- par = MPSC_CHR_2_PAR_MARK;
- else
- par = MPSC_CHR_2_PAR_SPACE;
- }
-#endif
-
- baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk);
-
- spin_lock_irqsave(&pi->port.lock, flags);
-
- uart_update_timeout(port, termios->c_cflag, baud);
-
- mpsc_set_char_length(pi, chr_bits);
- mpsc_set_stop_bit_length(pi, stop_bits);
- mpsc_set_parity(pi, par);
- mpsc_set_baudrate(pi, baud);
-
- /* Characters/events to read */
- pi->port.read_status_mask = SDMA_DESC_CMDSTAT_OR;
-
- if (termios->c_iflag & INPCK)
- pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_PE
- | SDMA_DESC_CMDSTAT_FR;
-
- if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
- pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_BR;
-
- /* Characters/events to ignore */
- pi->port.ignore_status_mask = 0;
-
- if (termios->c_iflag & IGNPAR)
- pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_PE
- | SDMA_DESC_CMDSTAT_FR;
-
- if (termios->c_iflag & IGNBRK) {
- pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_BR;
-
- if (termios->c_iflag & IGNPAR)
- pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_OR;
- }
-
- if ((termios->c_cflag & CREAD)) {
- if (!pi->rcv_data) {
- pi->rcv_data = 1;
- mpsc_start_rx(pi);
- }
- } else if (pi->rcv_data) {
- mpsc_stop_rx(port);
- pi->rcv_data = 0;
- }
-
- spin_unlock_irqrestore(&pi->port.lock, flags);
-}
-
-static const char *mpsc_type(struct uart_port *port)
-{
- pr_debug("mpsc_type[%d]: port type: %s\n", port->line,MPSC_DRIVER_NAME);
- return MPSC_DRIVER_NAME;
-}
-
-static int mpsc_request_port(struct uart_port *port)
-{
- /* Should make chip/platform specific call */
- return 0;
-}
-
-static void mpsc_release_port(struct uart_port *port)
-{
- struct mpsc_port_info *pi =
- container_of(port, struct mpsc_port_info, port);
-
- if (pi->ready) {
- mpsc_uninit_rings(pi);
- mpsc_free_ring_mem(pi);
- pi->ready = 0;
- }
-}
-
-static void mpsc_config_port(struct uart_port *port, int flags)
-{
-}
-
-static int mpsc_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
- struct mpsc_port_info *pi =
- container_of(port, struct mpsc_port_info, port);
- int rc = 0;
-
- pr_debug("mpsc_verify_port[%d]: Verifying port data\n", pi->port.line);
-
- if (ser->type != PORT_UNKNOWN && ser->type != PORT_MPSC)
- rc = -EINVAL;
- else if (pi->port.irq != ser->irq)
- rc = -EINVAL;
- else if (ser->io_type != SERIAL_IO_MEM)
- rc = -EINVAL;
- else if (pi->port.uartclk / 16 != ser->baud_base) /* Not sure */
- rc = -EINVAL;
- else if ((void *)pi->port.mapbase != ser->iomem_base)
- rc = -EINVAL;
- else if (pi->port.iobase != ser->port)
- rc = -EINVAL;
- else if (ser->hub6 != 0)
- rc = -EINVAL;
-
- return rc;
-}
-#ifdef CONFIG_CONSOLE_POLL
-/* Serial polling routines for writing and reading from the uart while
- * in an interrupt or debug context.
- */
-
-static char poll_buf[2048];
-static int poll_ptr;
-static int poll_cnt;
-static void mpsc_put_poll_char(struct uart_port *port,
- unsigned char c);
-
-static int mpsc_get_poll_char(struct uart_port *port)
-{
- struct mpsc_port_info *pi =
- container_of(port, struct mpsc_port_info, port);
- struct mpsc_rx_desc *rxre;
- u32 cmdstat, bytes_in, i;
- u8 *bp;
-
- if (!serial_polled)
- serial_polled = 1;
-
- pr_debug("mpsc_rx_intr[%d]: Handling Rx intr\n", pi->port.line);
-
- if (poll_cnt) {
- poll_cnt--;
- return poll_buf[poll_ptr++];
- }
- poll_ptr = 0;
- poll_cnt = 0;
-
- while (poll_cnt == 0) {
- rxre = (struct mpsc_rx_desc *)(pi->rxr +
- (pi->rxr_posn*MPSC_RXRE_SIZE));
- dma_cache_sync(pi->port.dev, (void *)rxre,
- MPSC_RXRE_SIZE, DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
- if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
- invalidate_dcache_range((ulong)rxre,
- (ulong)rxre + MPSC_RXRE_SIZE);
-#endif
- /*
- * Loop through Rx descriptors handling ones that have
- * been completed.
- */
- while (poll_cnt == 0 &&
- !((cmdstat = be32_to_cpu(rxre->cmdstat)) &
- SDMA_DESC_CMDSTAT_O)){
- bytes_in = be16_to_cpu(rxre->bytecnt);
- bp = pi->rxb + (pi->rxr_posn * MPSC_RXBE_SIZE);
- dma_cache_sync(pi->port.dev, (void *) bp,
- MPSC_RXBE_SIZE, DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
- if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
- invalidate_dcache_range((ulong)bp,
- (ulong)bp + MPSC_RXBE_SIZE);
-#endif
- if ((unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR |
- SDMA_DESC_CMDSTAT_FR | SDMA_DESC_CMDSTAT_OR))) &&
- !(cmdstat & pi->port.ignore_status_mask)) {
- poll_buf[poll_cnt] = *bp;
- poll_cnt++;
- } else {
- for (i = 0; i < bytes_in; i++) {
- poll_buf[poll_cnt] = *bp++;
- poll_cnt++;
- }
- pi->port.icount.rx += bytes_in;
- }
- rxre->bytecnt = cpu_to_be16(0);
- wmb();
- rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O |
- SDMA_DESC_CMDSTAT_EI |
- SDMA_DESC_CMDSTAT_F |
- SDMA_DESC_CMDSTAT_L);
- wmb();
- dma_cache_sync(pi->port.dev, (void *)rxre,
- MPSC_RXRE_SIZE, DMA_BIDIRECTIONAL);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
- if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
- flush_dcache_range((ulong)rxre,
- (ulong)rxre + MPSC_RXRE_SIZE);
-#endif
-
- /* Advance to next descriptor */
- pi->rxr_posn = (pi->rxr_posn + 1) &
- (MPSC_RXR_ENTRIES - 1);
- rxre = (struct mpsc_rx_desc *)(pi->rxr +
- (pi->rxr_posn * MPSC_RXRE_SIZE));
- dma_cache_sync(pi->port.dev, (void *)rxre,
- MPSC_RXRE_SIZE, DMA_FROM_DEVICE);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
- if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
- invalidate_dcache_range((ulong)rxre,
- (ulong)rxre + MPSC_RXRE_SIZE);
-#endif
- }
-
- /* Restart rx engine, if its stopped */
- if ((readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_ERD) == 0)
- mpsc_start_rx(pi);
- }
- if (poll_cnt) {
- poll_cnt--;
- return poll_buf[poll_ptr++];
- }
-
- return 0;
-}
-
-
-static void mpsc_put_poll_char(struct uart_port *port,
- unsigned char c)
-{
- struct mpsc_port_info *pi =
- container_of(port, struct mpsc_port_info, port);
- u32 data;
-
- data = readl(pi->mpsc_base + MPSC_MPCR);
- writeb(c, pi->mpsc_base + MPSC_CHR_1);
- mb();
- data = readl(pi->mpsc_base + MPSC_CHR_2);
- data |= MPSC_CHR_2_TTCS;
- writel(data, pi->mpsc_base + MPSC_CHR_2);
- mb();
-
- while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_TTCS);
-}
-#endif
-
-static const struct uart_ops mpsc_pops = {
- .tx_empty = mpsc_tx_empty,
- .set_mctrl = mpsc_set_mctrl,
- .get_mctrl = mpsc_get_mctrl,
- .stop_tx = mpsc_stop_tx,
- .start_tx = mpsc_start_tx,
- .stop_rx = mpsc_stop_rx,
- .break_ctl = mpsc_break_ctl,
- .startup = mpsc_startup,
- .shutdown = mpsc_shutdown,
- .set_termios = mpsc_set_termios,
- .type = mpsc_type,
- .release_port = mpsc_release_port,
- .request_port = mpsc_request_port,
- .config_port = mpsc_config_port,
- .verify_port = mpsc_verify_port,
-#ifdef CONFIG_CONSOLE_POLL
- .poll_get_char = mpsc_get_poll_char,
- .poll_put_char = mpsc_put_poll_char,
-#endif
-};
-
-/*
- ******************************************************************************
- *
- * Console Interface Routines
- *
- ******************************************************************************
- */
-
-#ifdef CONFIG_SERIAL_MPSC_CONSOLE
-static void mpsc_console_write(struct console *co, const char *s, uint count)
-{
- struct mpsc_port_info *pi = &mpsc_ports[co->index];
- u8 *bp, *dp, add_cr = 0;
- int i;
- unsigned long iflags;
-
- spin_lock_irqsave(&pi->tx_lock, iflags);
-
- while (pi->txr_head != pi->txr_tail) {
- while (mpsc_sdma_tx_active(pi))
- udelay(100);
- mpsc_sdma_intr_ack(pi);
- mpsc_tx_intr(pi);
- }
-
- while (mpsc_sdma_tx_active(pi))
- udelay(100);
-
- while (count > 0) {
- bp = dp = pi->txb + (pi->txr_head * MPSC_TXBE_SIZE);
-
- for (i = 0; i < MPSC_TXBE_SIZE; i++) {
- if (count == 0)
- break;
-
- if (add_cr) {
- *(dp++) = '\r';
- add_cr = 0;
- } else {
- *(dp++) = *s;
-
- if (*(s++) == '\n') { /* add '\r' after '\n' */
- add_cr = 1;
- count++;
- }
- }
-
- count--;
- }
-
- dma_cache_sync(pi->port.dev, (void *)bp, MPSC_TXBE_SIZE,
- DMA_BIDIRECTIONAL);
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
- if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
- flush_dcache_range((ulong)bp,
- (ulong)bp + MPSC_TXBE_SIZE);
-#endif
- mpsc_setup_tx_desc(pi, i, 0);
- pi->txr_head = (pi->txr_head + 1) & (MPSC_TXR_ENTRIES - 1);
- mpsc_sdma_start_tx(pi);
-
- while (mpsc_sdma_tx_active(pi))
- udelay(100);
-
- pi->txr_tail = (pi->txr_tail + 1) & (MPSC_TXR_ENTRIES - 1);
- }
-
- spin_unlock_irqrestore(&pi->tx_lock, iflags);
-}
-
-static int __init mpsc_console_setup(struct console *co, char *options)
-{
- struct mpsc_port_info *pi;
- int baud, bits, parity, flow;
-
- pr_debug("mpsc_console_setup[%d]: options: %s\n", co->index, options);
-
- if (co->index >= MPSC_NUM_CTLRS)
- co->index = 0;
-
- pi = &mpsc_ports[co->index];
-
- baud = pi->default_baud;
- bits = pi->default_bits;
- parity = pi->default_parity;
- flow = pi->default_flow;
-
- if (!pi->port.ops)
- return -ENODEV;
-
- spin_lock_init(&pi->port.lock); /* Temporary fix--copied from 8250.c */
-
- if (options)
- uart_parse_options(options, &baud, &parity, &bits, &flow);
-
- return uart_set_options(&pi->port, co, baud, parity, bits, flow);
-}
-
-static struct console mpsc_console = {
- .name = MPSC_DEV_NAME,
- .write = mpsc_console_write,
- .device = uart_console_device,
- .setup = mpsc_console_setup,
- .flags = CON_PRINTBUFFER,
- .index = -1,
- .data = &mpsc_reg,
-};
-
-static int __init mpsc_late_console_init(void)
-{
- pr_debug("mpsc_late_console_init: Enter\n");
-
- if (!(mpsc_console.flags & CON_ENABLED))
- register_console(&mpsc_console);
- return 0;
-}
-
-late_initcall(mpsc_late_console_init);
-
-#define MPSC_CONSOLE &mpsc_console
-#else
-#define MPSC_CONSOLE NULL
-#endif
-/*
- ******************************************************************************
- *
- * Dummy Platform Driver to extract & map shared register regions
- *
- ******************************************************************************
- */
-static void mpsc_resource_err(char *s)
-{
- printk(KERN_WARNING "MPSC: Platform device resource error in %s\n", s);
-}
-
-static int mpsc_shared_map_regs(struct platform_device *pd)
-{
- struct resource *r;
-
- if ((r = platform_get_resource(pd, IORESOURCE_MEM,
- MPSC_ROUTING_BASE_ORDER))
- && request_mem_region(r->start,
- MPSC_ROUTING_REG_BLOCK_SIZE,
- "mpsc_routing_regs")) {
- mpsc_shared_regs.mpsc_routing_base = ioremap(r->start,
- MPSC_ROUTING_REG_BLOCK_SIZE);
- mpsc_shared_regs.mpsc_routing_base_p = r->start;
- } else {
- mpsc_resource_err("MPSC routing base");
- return -ENOMEM;
- }
-
- if ((r = platform_get_resource(pd, IORESOURCE_MEM,
- MPSC_SDMA_INTR_BASE_ORDER))
- && request_mem_region(r->start,
- MPSC_SDMA_INTR_REG_BLOCK_SIZE,
- "sdma_intr_regs")) {
- mpsc_shared_regs.sdma_intr_base = ioremap(r->start,
- MPSC_SDMA_INTR_REG_BLOCK_SIZE);
- mpsc_shared_regs.sdma_intr_base_p = r->start;
- } else {
- iounmap(mpsc_shared_regs.mpsc_routing_base);
- release_mem_region(mpsc_shared_regs.mpsc_routing_base_p,
- MPSC_ROUTING_REG_BLOCK_SIZE);
- mpsc_resource_err("SDMA intr base");
- return -ENOMEM;
- }
-
- return 0;
-}
-
-static void mpsc_shared_unmap_regs(void)
-{
- if (mpsc_shared_regs.mpsc_routing_base) {
- iounmap(mpsc_shared_regs.mpsc_routing_base);
- release_mem_region(mpsc_shared_regs.mpsc_routing_base_p,
- MPSC_ROUTING_REG_BLOCK_SIZE);
- }
- if (mpsc_shared_regs.sdma_intr_base) {
- iounmap(mpsc_shared_regs.sdma_intr_base);
- release_mem_region(mpsc_shared_regs.sdma_intr_base_p,
- MPSC_SDMA_INTR_REG_BLOCK_SIZE);
- }
-
- mpsc_shared_regs.mpsc_routing_base = NULL;
- mpsc_shared_regs.sdma_intr_base = NULL;
-
- mpsc_shared_regs.mpsc_routing_base_p = 0;
- mpsc_shared_regs.sdma_intr_base_p = 0;
-}
-
-static int mpsc_shared_drv_probe(struct platform_device *dev)
-{
- struct mpsc_shared_pdata *pdata;
- int rc;
-
- if (dev->id != 0)
- return -ENODEV;
-
- rc = mpsc_shared_map_regs(dev);
- if (rc)
- return rc;
-
- pdata = dev_get_platdata(&dev->dev);
-
- mpsc_shared_regs.MPSC_MRR_m = pdata->mrr_val;
- mpsc_shared_regs.MPSC_RCRR_m= pdata->rcrr_val;
- mpsc_shared_regs.MPSC_TCRR_m= pdata->tcrr_val;
- mpsc_shared_regs.SDMA_INTR_CAUSE_m = pdata->intr_cause_val;
- mpsc_shared_regs.SDMA_INTR_MASK_m = pdata->intr_mask_val;
-
- return 0;
-}
-
-static int mpsc_shared_drv_remove(struct platform_device *dev)
-{
- if (dev->id != 0)
- return -ENODEV;
-
- mpsc_shared_unmap_regs();
- mpsc_shared_regs.MPSC_MRR_m = 0;
- mpsc_shared_regs.MPSC_RCRR_m = 0;
- mpsc_shared_regs.MPSC_TCRR_m = 0;
- mpsc_shared_regs.SDMA_INTR_CAUSE_m = 0;
- mpsc_shared_regs.SDMA_INTR_MASK_m = 0;
-
- return 0;
-}
-
-static struct platform_driver mpsc_shared_driver = {
- .probe = mpsc_shared_drv_probe,
- .remove = mpsc_shared_drv_remove,
- .driver = {
- .name = MPSC_SHARED_NAME,
- },
-};
-
-/*
- ******************************************************************************
- *
- * Driver Interface Routines
- *
- ******************************************************************************
- */
-static struct uart_driver mpsc_reg = {
- .owner = THIS_MODULE,
- .driver_name = MPSC_DRIVER_NAME,
- .dev_name = MPSC_DEV_NAME,
- .major = MPSC_MAJOR,
- .minor = MPSC_MINOR_START,
- .nr = MPSC_NUM_CTLRS,
- .cons = MPSC_CONSOLE,
-};
-
-static int mpsc_drv_map_regs(struct mpsc_port_info *pi,
- struct platform_device *pd)
-{
- struct resource *r;
-
- if ((r = platform_get_resource(pd, IORESOURCE_MEM, MPSC_BASE_ORDER))
- && request_mem_region(r->start, MPSC_REG_BLOCK_SIZE,
- "mpsc_regs")) {
- pi->mpsc_base = ioremap(r->start, MPSC_REG_BLOCK_SIZE);
- pi->mpsc_base_p = r->start;
- } else {
- mpsc_resource_err("MPSC base");
- goto err;
- }
-
- if ((r = platform_get_resource(pd, IORESOURCE_MEM,
- MPSC_SDMA_BASE_ORDER))
- && request_mem_region(r->start,
- MPSC_SDMA_REG_BLOCK_SIZE, "sdma_regs")) {
- pi->sdma_base = ioremap(r->start,MPSC_SDMA_REG_BLOCK_SIZE);
- pi->sdma_base_p = r->start;
- } else {
- mpsc_resource_err("SDMA base");
- goto err;
- }
-
- if ((r = platform_get_resource(pd,IORESOURCE_MEM,MPSC_BRG_BASE_ORDER))
- && request_mem_region(r->start,
- MPSC_BRG_REG_BLOCK_SIZE, "brg_regs")) {
- pi->brg_base = ioremap(r->start, MPSC_BRG_REG_BLOCK_SIZE);
- pi->brg_base_p = r->start;
- } else {
- mpsc_resource_err("BRG base");
- goto err;
- }
- return 0;
-
-err:
- if (pi->sdma_base) {
- iounmap(pi->sdma_base);
- pi->sdma_base = NULL;
- }
- if (pi->mpsc_base) {
- iounmap(pi->mpsc_base);
- pi->mpsc_base = NULL;
- }
- return -ENOMEM;
-}
-
-static void mpsc_drv_unmap_regs(struct mpsc_port_info *pi)
-{
- if (pi->mpsc_base) {
- iounmap(pi->mpsc_base);
- release_mem_region(pi->mpsc_base_p, MPSC_REG_BLOCK_SIZE);
- }
- if (pi->sdma_base) {
- iounmap(pi->sdma_base);
- release_mem_region(pi->sdma_base_p, MPSC_SDMA_REG_BLOCK_SIZE);
- }
- if (pi->brg_base) {
- iounmap(pi->brg_base);
- release_mem_region(pi->brg_base_p, MPSC_BRG_REG_BLOCK_SIZE);
- }
-
- pi->mpsc_base = NULL;
- pi->sdma_base = NULL;
- pi->brg_base = NULL;
-
- pi->mpsc_base_p = 0;
- pi->sdma_base_p = 0;
- pi->brg_base_p = 0;
-}
-
-static void mpsc_drv_get_platform_data(struct mpsc_port_info *pi,
- struct platform_device *pd, int num)
-{
- struct mpsc_pdata *pdata;
-
- pdata = dev_get_platdata(&pd->dev);
-
- pi->port.uartclk = pdata->brg_clk_freq;
- pi->port.iotype = UPIO_MEM;
- pi->port.line = num;
- pi->port.type = PORT_MPSC;
- pi->port.fifosize = MPSC_TXBE_SIZE;
- pi->port.membase = pi->mpsc_base;
- pi->port.mapbase = (ulong)pi->mpsc_base;
- pi->port.ops = &mpsc_pops;
-
- pi->mirror_regs = pdata->mirror_regs;
- pi->cache_mgmt = pdata->cache_mgmt;
- pi->brg_can_tune = pdata->brg_can_tune;
- pi->brg_clk_src = pdata->brg_clk_src;
- pi->mpsc_max_idle = pdata->max_idle;
- pi->default_baud = pdata->default_baud;
- pi->default_bits = pdata->default_bits;
- pi->default_parity = pdata->default_parity;
- pi->default_flow = pdata->default_flow;
-
- /* Initial values of mirrored regs */
- pi->MPSC_CHR_1_m = pdata->chr_1_val;
- pi->MPSC_CHR_2_m = pdata->chr_2_val;
- pi->MPSC_CHR_10_m = pdata->chr_10_val;
- pi->MPSC_MPCR_m = pdata->mpcr_val;
- pi->BRG_BCR_m = pdata->bcr_val;
-
- pi->shared_regs = &mpsc_shared_regs;
-
- pi->port.irq = platform_get_irq(pd, 0);
-}
-
-static int mpsc_drv_probe(struct platform_device *dev)
-{
- struct mpsc_port_info *pi;
- int rc;
-
- dev_dbg(&dev->dev, "mpsc_drv_probe: Adding MPSC %d\n", dev->id);
-
- if (dev->id >= MPSC_NUM_CTLRS)
- return -ENODEV;
-
- pi = &mpsc_ports[dev->id];
-
- rc = mpsc_drv_map_regs(pi, dev);
- if (rc)
- return rc;
-
- mpsc_drv_get_platform_data(pi, dev, dev->id);
- pi->port.dev = &dev->dev;
-
- rc = mpsc_make_ready(pi);
- if (rc)
- goto err_unmap;
-
- spin_lock_init(&pi->tx_lock);
- rc = uart_add_one_port(&mpsc_reg, &pi->port);
- if (rc)
- goto err_relport;
-
- return 0;
-err_relport:
- mpsc_release_port(&pi->port);
-err_unmap:
- mpsc_drv_unmap_regs(pi);
- return rc;
-}
-
-static struct platform_driver mpsc_driver = {
- .probe = mpsc_drv_probe,
- .driver = {
- .name = MPSC_CTLR_NAME,
- .suppress_bind_attrs = true,
- },
-};
-
-static int __init mpsc_drv_init(void)
-{
- int rc;
-
- printk(KERN_INFO "Serial: MPSC driver\n");
-
- memset(mpsc_ports, 0, sizeof(mpsc_ports));
- memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs));
-
- rc = uart_register_driver(&mpsc_reg);
- if (rc)
- return rc;
-
- rc = platform_driver_register(&mpsc_shared_driver);
- if (rc)
- goto err_unreg_uart;
-
- rc = platform_driver_register(&mpsc_driver);
- if (rc)
- goto err_unreg_plat;
-
- return 0;
-err_unreg_plat:
- platform_driver_unregister(&mpsc_shared_driver);
-err_unreg_uart:
- uart_unregister_driver(&mpsc_reg);
- return rc;
-}
-device_initcall(mpsc_drv_init);
-
-/*
-MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>");
-MODULE_DESCRIPTION("Generic Marvell MPSC serial/UART driver");
-MODULE_LICENSE("GPL");
-*/
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index 23833ad952ba..3657a24913fc 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -383,10 +383,14 @@ no_rx:
static inline void msm_wait_for_xmitr(struct uart_port *port)
{
+ unsigned int timeout = 500000;
+
while (!(msm_read(port, UART_SR) & UART_SR_TX_EMPTY)) {
if (msm_read(port, UART_ISR) & UART_ISR_TX_READY)
break;
udelay(1);
+ if (!timeout--)
+ break;
}
msm_write(port, UART_CR_CMD_RESET_TX_READY, UART_CR);
}
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 83f4dd0bfd74..4223cb496764 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -1777,6 +1777,7 @@ static int uart_port_activate(struct tty_port *port, struct tty_struct *tty)
{
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport;
+ int ret;
uport = uart_port_check(state);
if (!uport || uport->flags & UPF_DEAD)
@@ -1787,7 +1788,11 @@ static int uart_port_activate(struct tty_port *port, struct tty_struct *tty)
/*
* Start up the serial port.
*/
- return uart_startup(tty, state, 0);
+ ret = uart_startup(tty, state, 0);
+ if (ret > 0)
+ tty_port_set_active(port, 1);
+
+ return ret;
}
static const char *uart_type(struct uart_port *port)
diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c
index 39ed56214cd3..2b400189be91 100644
--- a/drivers/tty/serial/serial_mctrl_gpio.c
+++ b/drivers/tty/serial/serial_mctrl_gpio.c
@@ -12,6 +12,7 @@
#include <linux/termios.h>
#include <linux/serial_core.h>
#include <linux/module.h>
+#include <linux/property.h>
#include "serial_mctrl_gpio.h"
@@ -116,6 +117,19 @@ struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx)
for (i = 0; i < UART_GPIO_MAX; i++) {
enum gpiod_flags flags;
+ char *gpio_str;
+ bool present;
+
+ /* Check if GPIO property exists and continue if not */
+ gpio_str = kasprintf(GFP_KERNEL, "%s-gpios",
+ mctrl_gpios_desc[i].name);
+ if (!gpio_str)
+ continue;
+
+ present = device_property_present(dev, gpio_str);
+ kfree(gpio_str);
+ if (!present)
+ continue;
if (mctrl_gpios_desc[i].dir_out)
flags = GPIOD_OUT_LOW;
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index abc705716aa0..d18c680aa64b 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -1398,6 +1398,7 @@ static void sci_dma_tx_work_fn(struct work_struct *work)
struct circ_buf *xmit = &port->state->xmit;
unsigned long flags;
dma_addr_t buf;
+ int head, tail;
/*
* DMA is idle now.
@@ -1407,16 +1408,23 @@ static void sci_dma_tx_work_fn(struct work_struct *work)
* consistent xmit buffer state.
*/
spin_lock_irq(&port->lock);
- buf = s->tx_dma_addr + (xmit->tail & (UART_XMIT_SIZE - 1));
+ head = xmit->head;
+ tail = xmit->tail;
+ buf = s->tx_dma_addr + (tail & (UART_XMIT_SIZE - 1));
s->tx_dma_len = min_t(unsigned int,
- CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE),
- CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE));
- spin_unlock_irq(&port->lock);
+ CIRC_CNT(head, tail, UART_XMIT_SIZE),
+ CIRC_CNT_TO_END(head, tail, UART_XMIT_SIZE));
+ if (!s->tx_dma_len) {
+ /* Transmit buffer has been flushed */
+ spin_unlock_irq(&port->lock);
+ return;
+ }
desc = dmaengine_prep_slave_single(chan, buf, s->tx_dma_len,
DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) {
+ spin_unlock_irq(&port->lock);
dev_warn(port->dev, "Failed preparing Tx DMA descriptor\n");
goto switch_to_pio;
}
@@ -1424,18 +1432,18 @@ static void sci_dma_tx_work_fn(struct work_struct *work)
dma_sync_single_for_device(chan->device->dev, buf, s->tx_dma_len,
DMA_TO_DEVICE);
- spin_lock_irq(&port->lock);
desc->callback = sci_dma_tx_complete;
desc->callback_param = s;
- spin_unlock_irq(&port->lock);
s->cookie_tx = dmaengine_submit(desc);
if (dma_submit_error(s->cookie_tx)) {
+ spin_unlock_irq(&port->lock);
dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n");
goto switch_to_pio;
}
+ spin_unlock_irq(&port->lock);
dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n",
- __func__, xmit->buf, xmit->tail, xmit->head, s->cookie_tx);
+ __func__, xmit->buf, tail, head, s->cookie_tx);
dma_async_issue_pending(chan);
return;
@@ -1648,11 +1656,18 @@ static void sci_free_dma(struct uart_port *port)
static void sci_flush_buffer(struct uart_port *port)
{
+ struct sci_port *s = to_sci_port(port);
+
/*
* In uart_flush_buffer(), the xmit circular buffer has just been
- * cleared, so we have to reset tx_dma_len accordingly.
+ * cleared, so we have to reset tx_dma_len accordingly, and stop any
+ * pending transfers
*/
- to_sci_port(port)->tx_dma_len = 0;
+ s->tx_dma_len = 0;
+ if (s->chan_tx) {
+ dmaengine_terminate_async(s->chan_tx);
+ s->cookie_tx = -EINVAL;
+ }
}
#else /* !CONFIG_SERIAL_SH_SCI_DMA */
static inline void sci_request_dma(struct uart_port *port)
diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index e8d7a7bb4339..24a2261f879a 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -105,9 +105,7 @@ static int stm32_config_rs485(struct uart_port *port,
struct stm32_usart_config *cfg = &stm32_port->info->cfg;
u32 usartdiv, baud, cr1, cr3;
bool over8;
- unsigned long flags;
- spin_lock_irqsave(&port->lock, flags);
stm32_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
port->rs485 = *rs485conf;
@@ -147,7 +145,6 @@ static int stm32_config_rs485(struct uart_port *port,
}
stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
- spin_unlock_irqrestore(&port->lock, flags);
return 0;
}
@@ -194,8 +191,8 @@ static int stm32_pending_rx(struct uart_port *port, u32 *sr, int *last_res,
return 0;
}
-static unsigned long
-stm32_get_char(struct uart_port *port, u32 *sr, int *last_res)
+static unsigned long stm32_get_char(struct uart_port *port, u32 *sr,
+ int *last_res)
{
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
@@ -205,10 +202,13 @@ stm32_get_char(struct uart_port *port, u32 *sr, int *last_res)
c = stm32_port->rx_buf[RX_BUF_L - (*last_res)--];
if ((*last_res) == 0)
*last_res = RX_BUF_L;
- return c;
} else {
- return readl_relaxed(port->membase + ofs->rdr);
+ c = readl_relaxed(port->membase + ofs->rdr);
+ /* apply RDR data mask */
+ c &= stm32_port->rdr_mask;
}
+
+ return c;
}
static void stm32_receive_chars(struct uart_port *port, bool threaded)
@@ -225,35 +225,51 @@ static void stm32_receive_chars(struct uart_port *port, bool threaded)
while (stm32_pending_rx(port, &sr, &stm32_port->last_res, threaded)) {
sr |= USART_SR_DUMMY_RX;
- c = stm32_get_char(port, &sr, &stm32_port->last_res);
flag = TTY_NORMAL;
- port->icount.rx++;
+ /*
+ * Status bits has to be cleared before reading the RDR:
+ * In FIFO mode, reading the RDR will pop the next data
+ * (if any) along with its status bits into the SR.
+ * Not doing so leads to misalignement between RDR and SR,
+ * and clear status bits of the next rx data.
+ *
+ * Clear errors flags for stm32f7 and stm32h7 compatible
+ * devices. On stm32f4 compatible devices, the error bit is
+ * cleared by the sequence [read SR - read DR].
+ */
+ if ((sr & USART_SR_ERR_MASK) && ofs->icr != UNDEF_REG)
+ stm32_clr_bits(port, ofs->icr, USART_ICR_ORECF |
+ USART_ICR_PECF | USART_ICR_FECF);
+
+ c = stm32_get_char(port, &sr, &stm32_port->last_res);
+ port->icount.rx++;
if (sr & USART_SR_ERR_MASK) {
- if (sr & USART_SR_LBD) {
- port->icount.brk++;
- if (uart_handle_break(port))
- continue;
- } else if (sr & USART_SR_ORE) {
- if (ofs->icr != UNDEF_REG)
- writel_relaxed(USART_ICR_ORECF,
- port->membase +
- ofs->icr);
+ if (sr & USART_SR_ORE) {
port->icount.overrun++;
} else if (sr & USART_SR_PE) {
port->icount.parity++;
} else if (sr & USART_SR_FE) {
- port->icount.frame++;
+ /* Break detection if character is null */
+ if (!c) {
+ port->icount.brk++;
+ if (uart_handle_break(port))
+ continue;
+ } else {
+ port->icount.frame++;
+ }
}
sr &= port->read_status_mask;
- if (sr & USART_SR_LBD)
- flag = TTY_BREAK;
- else if (sr & USART_SR_PE)
+ if (sr & USART_SR_PE) {
flag = TTY_PARITY;
- else if (sr & USART_SR_FE)
- flag = TTY_FRAME;
+ } else if (sr & USART_SR_FE) {
+ if (!c)
+ flag = TTY_BREAK;
+ else
+ flag = TTY_FRAME;
+ }
}
if (uart_handle_sysrq_char(port, c))
@@ -271,21 +287,6 @@ static void stm32_tx_dma_complete(void *arg)
struct uart_port *port = arg;
struct stm32_port *stm32port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32port->info->ofs;
- unsigned int isr;
- int ret;
-
- ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr,
- isr,
- (isr & USART_SR_TC),
- 10, 100000);
-
- if (ret)
- dev_err(port->dev, "terminal count not set\n");
-
- if (ofs->icr == UNDEF_REG)
- stm32_clr_bits(port, ofs->isr, USART_SR_TC);
- else
- stm32_set_bits(port, ofs->icr, USART_CR_TC);
stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
stm32port->tx_dma_busy = false;
@@ -294,32 +295,57 @@ static void stm32_tx_dma_complete(void *arg)
stm32_transmit_chars(port);
}
+static void stm32_tx_interrupt_enable(struct uart_port *port)
+{
+ struct stm32_port *stm32_port = to_stm32_port(port);
+ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
+
+ /*
+ * Enables TX FIFO threashold irq when FIFO is enabled,
+ * or TX empty irq when FIFO is disabled
+ */
+ if (stm32_port->fifoen)
+ stm32_set_bits(port, ofs->cr3, USART_CR3_TXFTIE);
+ else
+ stm32_set_bits(port, ofs->cr1, USART_CR1_TXEIE);
+}
+
+static void stm32_tx_interrupt_disable(struct uart_port *port)
+{
+ struct stm32_port *stm32_port = to_stm32_port(port);
+ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
+
+ if (stm32_port->fifoen)
+ stm32_clr_bits(port, ofs->cr3, USART_CR3_TXFTIE);
+ else
+ stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE);
+}
+
static void stm32_transmit_chars_pio(struct uart_port *port)
{
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
struct circ_buf *xmit = &port->state->xmit;
- unsigned int isr;
- int ret;
if (stm32_port->tx_dma_busy) {
stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
stm32_port->tx_dma_busy = false;
}
- ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr,
- isr,
- (isr & USART_SR_TXE),
- 10, 100000);
-
- if (ret)
- dev_err(port->dev, "tx empty not set\n");
-
- stm32_set_bits(port, ofs->cr1, USART_CR1_TXEIE);
+ while (!uart_circ_empty(xmit)) {
+ /* Check that TDR is empty before filling FIFO */
+ if (!(readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE))
+ break;
+ writel_relaxed(xmit->buf[xmit->tail], port->membase + ofs->tdr);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ }
- writel_relaxed(xmit->buf[xmit->tail], port->membase + ofs->tdr);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
+ /* rely on TXE irq (mask or unmask) for sending remaining data */
+ if (uart_circ_empty(xmit))
+ stm32_tx_interrupt_disable(port);
+ else
+ stm32_tx_interrupt_enable(port);
}
static void stm32_transmit_chars_dma(struct uart_port *port)
@@ -377,7 +403,6 @@ static void stm32_transmit_chars_dma(struct uart_port *port)
/* Issue pending DMA TX requests */
dma_async_issue_pending(stm32port->tx_ch);
- stm32_clr_bits(port, ofs->isr, USART_SR_TC);
stm32_set_bits(port, ofs->cr3, USART_CR3_DMAT);
xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
@@ -401,15 +426,15 @@ static void stm32_transmit_chars(struct uart_port *port)
return;
}
- if (uart_tx_stopped(port)) {
- stm32_stop_tx(port);
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ stm32_tx_interrupt_disable(port);
return;
}
- if (uart_circ_empty(xmit)) {
- stm32_stop_tx(port);
- return;
- }
+ if (ofs->icr == UNDEF_REG)
+ stm32_clr_bits(port, ofs->isr, USART_SR_TC);
+ else
+ stm32_set_bits(port, ofs->icr, USART_ICR_TCCF);
if (stm32_port->tx_ch)
stm32_transmit_chars_dma(port);
@@ -420,7 +445,7 @@ static void stm32_transmit_chars(struct uart_port *port)
uart_write_wakeup(port);
if (uart_circ_empty(xmit))
- stm32_stop_tx(port);
+ stm32_tx_interrupt_disable(port);
}
static irqreturn_t stm32_interrupt(int irq, void *ptr)
@@ -434,6 +459,10 @@ static irqreturn_t stm32_interrupt(int irq, void *ptr)
sr = readl_relaxed(port->membase + ofs->isr);
+ if ((sr & USART_SR_RTOF) && ofs->icr != UNDEF_REG)
+ writel_relaxed(USART_ICR_RTOCF,
+ port->membase + ofs->icr);
+
if ((sr & USART_SR_WUF) && (ofs->icr != UNDEF_REG))
writel_relaxed(USART_ICR_WUCF,
port->membase + ofs->icr);
@@ -495,10 +524,7 @@ static unsigned int stm32_get_mctrl(struct uart_port *port)
/* Transmit stop */
static void stm32_stop_tx(struct uart_port *port)
{
- struct stm32_port *stm32_port = to_stm32_port(port);
- struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
-
- stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE);
+ stm32_tx_interrupt_disable(port);
}
/* There are probably characters waiting to be transmitted. */
@@ -520,7 +546,10 @@ static void stm32_throttle(struct uart_port *port)
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
- stm32_clr_bits(port, ofs->cr1, USART_CR1_RXNEIE);
+ stm32_clr_bits(port, ofs->cr1, stm32_port->cr1_irq);
+ if (stm32_port->cr3_irq)
+ stm32_clr_bits(port, ofs->cr3, stm32_port->cr3_irq);
+
spin_unlock_irqrestore(&port->lock, flags);
}
@@ -532,7 +561,10 @@ static void stm32_unthrottle(struct uart_port *port)
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
- stm32_set_bits(port, ofs->cr1, USART_CR1_RXNEIE);
+ stm32_set_bits(port, ofs->cr1, stm32_port->cr1_irq);
+ if (stm32_port->cr3_irq)
+ stm32_set_bits(port, ofs->cr3, stm32_port->cr3_irq);
+
spin_unlock_irqrestore(&port->lock, flags);
}
@@ -542,7 +574,10 @@ static void stm32_stop_rx(struct uart_port *port)
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
- stm32_clr_bits(port, ofs->cr1, USART_CR1_RXNEIE);
+ stm32_clr_bits(port, ofs->cr1, stm32_port->cr1_irq);
+ if (stm32_port->cr3_irq)
+ stm32_clr_bits(port, ofs->cr3, stm32_port->cr3_irq);
+
}
/* Handle breaks - ignored by us */
@@ -554,7 +589,6 @@ static int stm32_startup(struct uart_port *port)
{
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
- struct stm32_usart_config *cfg = &stm32_port->info->cfg;
const char *name = to_platform_device(port->dev)->name;
u32 val;
int ret;
@@ -565,16 +599,21 @@ static int stm32_startup(struct uart_port *port)
if (ret)
return ret;
- if (cfg->has_wakeup && stm32_port->wakeirq >= 0) {
- ret = dev_pm_set_dedicated_wake_irq(port->dev,
- stm32_port->wakeirq);
- if (ret) {
- free_irq(port->irq, port);
- return ret;
- }
+ /* RX FIFO Flush */
+ if (ofs->rqr != UNDEF_REG)
+ stm32_set_bits(port, ofs->rqr, USART_RQR_RXFRQ);
+
+ /* Tx and RX FIFO configuration */
+ if (stm32_port->fifoen) {
+ val = readl_relaxed(port->membase + ofs->cr3);
+ val &= ~(USART_CR3_TXFTCFG_MASK | USART_CR3_RXFTCFG_MASK);
+ val |= USART_CR3_TXFTCFG_HALF << USART_CR3_TXFTCFG_SHIFT;
+ val |= USART_CR3_RXFTCFG_HALF << USART_CR3_RXFTCFG_SHIFT;
+ writel_relaxed(val, port->membase + ofs->cr3);
}
- val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
+ /* RX FIFO enabling */
+ val = stm32_port->cr1_irq | USART_CR1_RE;
if (stm32_port->fifoen)
val |= USART_CR1_FIFOEN;
stm32_set_bits(port, ofs->cr1, val);
@@ -587,18 +626,57 @@ static void stm32_shutdown(struct uart_port *port)
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
struct stm32_usart_config *cfg = &stm32_port->info->cfg;
- u32 val;
+ u32 val, isr;
+ int ret;
- val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
+ val = USART_CR1_TXEIE | USART_CR1_TE;
+ val |= stm32_port->cr1_irq | USART_CR1_RE;
val |= BIT(cfg->uart_enable_bit);
if (stm32_port->fifoen)
val |= USART_CR1_FIFOEN;
+
+ ret = readl_relaxed_poll_timeout(port->membase + ofs->isr,
+ isr, (isr & USART_SR_TC),
+ 10, 100000);
+
+ if (ret)
+ dev_err(port->dev, "transmission complete not set\n");
+
stm32_clr_bits(port, ofs->cr1, val);
- dev_pm_clear_wake_irq(port->dev);
free_irq(port->irq, port);
}
+static unsigned int stm32_get_databits(struct ktermios *termios)
+{
+ unsigned int bits;
+
+ tcflag_t cflag = termios->c_cflag;
+
+ switch (cflag & CSIZE) {
+ /*
+ * CSIZE settings are not necessarily supported in hardware.
+ * CSIZE unsupported configurations are handled here to set word length
+ * to 8 bits word as default configuration and to print debug message.
+ */
+ case CS5:
+ bits = 5;
+ break;
+ case CS6:
+ bits = 6;
+ break;
+ case CS7:
+ bits = 7;
+ break;
+ /* default including CS8 */
+ default:
+ bits = 8;
+ break;
+ }
+
+ return bits;
+}
+
static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
@@ -606,7 +684,7 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
struct stm32_usart_config *cfg = &stm32_port->info->cfg;
struct serial_rs485 *rs485conf = &port->rs485;
- unsigned int baud;
+ unsigned int baud, bits;
u32 usartdiv, mantissa, fraction, oversampling;
tcflag_t cflag = termios->c_cflag;
u32 cr1, cr2, cr3;
@@ -622,26 +700,64 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
/* Stop serial port and reset value */
writel_relaxed(0, port->membase + ofs->cr1);
- cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE;
+ /* flush RX & TX FIFO */
+ if (ofs->rqr != UNDEF_REG)
+ stm32_set_bits(port, ofs->rqr,
+ USART_RQR_TXFRQ | USART_RQR_RXFRQ);
+ cr1 = USART_CR1_TE | USART_CR1_RE;
if (stm32_port->fifoen)
cr1 |= USART_CR1_FIFOEN;
cr2 = 0;
- cr3 = 0;
+ cr3 = readl_relaxed(port->membase + ofs->cr3);
+ cr3 &= USART_CR3_TXFTIE | USART_CR3_RXFTCFG_MASK | USART_CR3_RXFTIE
+ | USART_CR3_TXFTCFG_MASK;
if (cflag & CSTOPB)
cr2 |= USART_CR2_STOP_2B;
+ bits = stm32_get_databits(termios);
+ stm32_port->rdr_mask = (BIT(bits) - 1);
+
if (cflag & PARENB) {
+ bits++;
cr1 |= USART_CR1_PCE;
- if ((cflag & CSIZE) == CS8) {
- if (cfg->has_7bits_data)
- cr1 |= USART_CR1_M0;
- else
- cr1 |= USART_CR1_M;
- }
}
+ /*
+ * Word length configuration:
+ * CS8 + parity, 9 bits word aka [M1:M0] = 0b01
+ * CS7 or (CS6 + parity), 7 bits word aka [M1:M0] = 0b10
+ * CS8 or (CS7 + parity), 8 bits word aka [M1:M0] = 0b00
+ * M0 and M1 already cleared by cr1 initialization.
+ */
+ if (bits == 9)
+ cr1 |= USART_CR1_M0;
+ else if ((bits == 7) && cfg->has_7bits_data)
+ cr1 |= USART_CR1_M1;
+ else if (bits != 8)
+ dev_dbg(port->dev, "Unsupported data bits config: %u bits\n"
+ , bits);
+
+ if (ofs->rtor != UNDEF_REG && (stm32_port->rx_ch ||
+ stm32_port->fifoen)) {
+ if (cflag & CSTOPB)
+ bits = bits + 3; /* 1 start bit + 2 stop bits */
+ else
+ bits = bits + 2; /* 1 start bit + 1 stop bit */
+
+ /* RX timeout irq to occur after last stop bit + bits */
+ stm32_port->cr1_irq = USART_CR1_RTOIE;
+ writel_relaxed(bits, port->membase + ofs->rtor);
+ cr2 |= USART_CR2_RTOEN;
+ /* Not using dma, enable fifo threshold irq */
+ if (!stm32_port->rx_ch)
+ stm32_port->cr3_irq = USART_CR3_RXFTIE;
+ }
+
+ cr1 |= stm32_port->cr1_irq;
+ cr3 |= stm32_port->cr3_irq;
+
if (cflag & PARODD)
cr1 |= USART_CR1_PS;
@@ -679,14 +795,14 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
if (termios->c_iflag & INPCK)
port->read_status_mask |= USART_SR_PE | USART_SR_FE;
if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
- port->read_status_mask |= USART_SR_LBD;
+ port->read_status_mask |= USART_SR_FE;
/* Characters to ignore */
port->ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask = USART_SR_PE | USART_SR_FE;
if (termios->c_iflag & IGNBRK) {
- port->ignore_status_mask |= USART_SR_LBD;
+ port->ignore_status_mask |= USART_SR_FE;
/*
* If we're ignoring parity and break indicators,
* ignore overruns too (for real raw support).
@@ -808,12 +924,32 @@ static int stm32_init_port(struct stm32_port *stm32port,
port->flags = UPF_BOOT_AUTOCONF;
port->ops = &stm32_uart_ops;
port->dev = &pdev->dev;
- port->irq = platform_get_irq(pdev, 0);
+ port->fifosize = stm32port->info->cfg.fifosize;
+
+ ret = platform_get_irq(pdev, 0);
+ if (ret <= 0) {
+ if (ret != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Can't get event IRQ: %d\n", ret);
+ return ret ? ret : -ENODEV;
+ }
+ port->irq = ret;
+
port->rs485_config = stm32_config_rs485;
stm32_init_rs485(port, pdev);
- stm32port->wakeirq = platform_get_irq(pdev, 1);
+ if (stm32port->info->cfg.has_wakeup) {
+ stm32port->wakeirq = platform_get_irq(pdev, 1);
+ if (stm32port->wakeirq <= 0 && stm32port->wakeirq != -ENXIO) {
+ if (stm32port->wakeirq != -EPROBE_DEFER)
+ dev_err(&pdev->dev,
+ "Can't get event wake IRQ: %d\n",
+ stm32port->wakeirq);
+ return stm32port->wakeirq ? stm32port->wakeirq :
+ -ENODEV;
+ }
+ }
+
stm32port->fifoen = stm32port->info->cfg.has_fifo;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -862,6 +998,8 @@ static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev)
stm32_ports[id].hw_flow_control = of_property_read_bool(np,
"st,hw-flow-ctrl");
stm32_ports[id].port.line = id;
+ stm32_ports[id].cr1_irq = USART_CR1_RXNEIE;
+ stm32_ports[id].cr3_irq = 0;
stm32_ports[id].last_res = RX_BUF_L;
return &stm32_ports[id];
}
@@ -1020,15 +1158,22 @@ static int stm32_serial_probe(struct platform_device *pdev)
if (ret)
return ret;
- if (stm32port->info->cfg.has_wakeup && stm32port->wakeirq >= 0) {
+ if (stm32port->wakeirq > 0) {
ret = device_init_wakeup(&pdev->dev, true);
if (ret)
goto err_uninit;
+
+ ret = dev_pm_set_dedicated_wake_irq(&pdev->dev,
+ stm32port->wakeirq);
+ if (ret)
+ goto err_nowup;
+
+ device_set_wakeup_enable(&pdev->dev, false);
}
ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port);
if (ret)
- goto err_nowup;
+ goto err_wirq;
ret = stm32_of_dma_rx_probe(stm32port, pdev);
if (ret)
@@ -1042,8 +1187,12 @@ static int stm32_serial_probe(struct platform_device *pdev)
return 0;
+err_wirq:
+ if (stm32port->wakeirq > 0)
+ dev_pm_clear_wake_irq(&pdev->dev);
+
err_nowup:
- if (stm32port->info->cfg.has_wakeup && stm32port->wakeirq >= 0)
+ if (stm32port->wakeirq > 0)
device_init_wakeup(&pdev->dev, false);
err_uninit:
@@ -1057,7 +1206,6 @@ static int stm32_serial_remove(struct platform_device *pdev)
struct uart_port *port = platform_get_drvdata(pdev);
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
- struct stm32_usart_config *cfg = &stm32_port->info->cfg;
stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAR);
@@ -1079,8 +1227,10 @@ static int stm32_serial_remove(struct platform_device *pdev)
TX_BUF_L, stm32_port->tx_buf,
stm32_port->tx_dma_buf);
- if (cfg->has_wakeup && stm32_port->wakeirq >= 0)
+ if (stm32_port->wakeirq > 0) {
+ dev_pm_clear_wake_irq(&pdev->dev);
device_init_wakeup(&pdev->dev, false);
+ }
clk_disable_unprepare(stm32_port->clk);
@@ -1195,7 +1345,7 @@ static void stm32_serial_enable_wakeup(struct uart_port *port, bool enable)
struct stm32_usart_config *cfg = &stm32_port->info->cfg;
u32 val;
- if (!cfg->has_wakeup || stm32_port->wakeirq < 0)
+ if (stm32_port->wakeirq <= 0)
return;
if (enable) {
diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h
index 6f294e280ea3..a175c1094dc8 100644
--- a/drivers/tty/serial/stm32-usart.h
+++ b/drivers/tty/serial/stm32-usart.h
@@ -27,6 +27,7 @@ struct stm32_usart_config {
bool has_7bits_data;
bool has_wakeup;
bool has_fifo;
+ int fifosize;
};
struct stm32_usart_info {
@@ -54,6 +55,7 @@ struct stm32_usart_info stm32f4_info = {
.cfg = {
.uart_enable_bit = 13,
.has_7bits_data = false,
+ .fifosize = 1,
}
};
@@ -74,6 +76,7 @@ struct stm32_usart_info stm32f7_info = {
.cfg = {
.uart_enable_bit = 0,
.has_7bits_data = true,
+ .fifosize = 1,
}
};
@@ -96,6 +99,7 @@ struct stm32_usart_info stm32h7_info = {
.has_7bits_data = true,
.has_wakeup = true,
.has_fifo = true,
+ .fifosize = 16,
}
};
@@ -108,7 +112,6 @@ struct stm32_usart_info stm32h7_info = {
#define USART_SR_RXNE BIT(5)
#define USART_SR_TC BIT(6)
#define USART_SR_TXE BIT(7)
-#define USART_SR_LBD BIT(8)
#define USART_SR_CTSIF BIT(9)
#define USART_SR_CTS BIT(10) /* F7 */
#define USART_SR_RTOF BIT(11) /* F7 */
@@ -120,8 +123,7 @@ struct stm32_usart_info stm32h7_info = {
#define USART_SR_SBKF BIT(18) /* F7 */
#define USART_SR_WUF BIT(20) /* H7 */
#define USART_SR_TEACK BIT(21) /* F7 */
-#define USART_SR_ERR_MASK (USART_SR_LBD | USART_SR_ORE | \
- USART_SR_FE | USART_SR_PE)
+#define USART_SR_ERR_MASK (USART_SR_ORE | USART_SR_FE | USART_SR_PE)
/* Dummy bits */
#define USART_SR_DUMMY_RX BIT(16)
@@ -151,8 +153,7 @@ struct stm32_usart_info stm32h7_info = {
#define USART_CR1_PS BIT(9)
#define USART_CR1_PCE BIT(10)
#define USART_CR1_WAKE BIT(11)
-#define USART_CR1_M BIT(12)
-#define USART_CR1_M0 BIT(12) /* F7 */
+#define USART_CR1_M0 BIT(12) /* F7 (CR1_M for F4) */
#define USART_CR1_MME BIT(13) /* F7 */
#define USART_CR1_CMIE BIT(14) /* F7 */
#define USART_CR1_OVER8 BIT(15)
@@ -169,8 +170,6 @@ struct stm32_usart_info stm32h7_info = {
/* USART_CR2 */
#define USART_CR2_ADD_MASK GENMASK(3, 0) /* F4 */
#define USART_CR2_ADDM7 BIT(4) /* F7 */
-#define USART_CR2_LBDL BIT(5)
-#define USART_CR2_LBDIE BIT(6)
#define USART_CR2_LBCL BIT(8)
#define USART_CR2_CPHA BIT(9)
#define USART_CR2_CPOL BIT(10)
@@ -209,6 +208,19 @@ struct stm32_usart_info stm32h7_info = {
#define USART_CR3_WUS_MASK GENMASK(21, 20) /* H7 */
#define USART_CR3_WUS_START_BIT BIT(21) /* H7 */
#define USART_CR3_WUFIE BIT(22) /* H7 */
+#define USART_CR3_TXFTIE BIT(23) /* H7 */
+#define USART_CR3_TCBGTIE BIT(24) /* H7 */
+#define USART_CR3_RXFTCFG_MASK GENMASK(27, 25) /* H7 */
+#define USART_CR3_RXFTCFG_SHIFT 25 /* H7 */
+#define USART_CR3_RXFTIE BIT(28) /* H7 */
+#define USART_CR3_TXFTCFG_MASK GENMASK(31, 29) /* H7 */
+#define USART_CR3_TXFTCFG_SHIFT 29 /* H7 */
+
+/* TX FIFO threashold set to half of its depth */
+#define USART_CR3_TXFTCFG_HALF 0x2
+
+/* RX FIFO threashold set to half of its depth */
+#define USART_CR3_RXFTCFG_HALF 0x2
/* USART_GTPR */
#define USART_GTPR_PSC_MASK GENMASK(7, 0)
@@ -227,12 +239,10 @@ struct stm32_usart_info stm32h7_info = {
/* USART_ICR */
#define USART_ICR_PECF BIT(0) /* F7 */
-#define USART_ICR_FFECF BIT(1) /* F7 */
-#define USART_ICR_NCF BIT(2) /* F7 */
+#define USART_ICR_FECF BIT(1) /* F7 */
#define USART_ICR_ORECF BIT(3) /* F7 */
#define USART_ICR_IDLECF BIT(4) /* F7 */
#define USART_ICR_TCCF BIT(6) /* F7 */
-#define USART_ICR_LBDCF BIT(8) /* F7 */
#define USART_ICR_CTSCF BIT(9) /* F7 */
#define USART_ICR_RTOCF BIT(11) /* F7 */
#define USART_ICR_EOBCF BIT(12) /* F7 */
@@ -256,11 +266,14 @@ struct stm32_port {
struct dma_chan *tx_ch; /* dma tx channel */
dma_addr_t tx_dma_buf; /* dma tx buffer bus address */
unsigned char *tx_buf; /* dma tx buffer cpu address */
+ u32 cr1_irq; /* USART_CR1_RXNEIE or RTOIE */
+ u32 cr3_irq; /* USART_CR3_RXFTIE */
int last_res;
bool tx_dma_busy; /* dma tx busy */
bool hw_flow_control;
bool fifoen;
int wakeirq;
+ int rdr_mask; /* receive data register mask */
};
static struct stm32_port stm32_ports[STM32_MAX_PORTS];
diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c
index 63e34d868de8..f8503f8fc44e 100644
--- a/drivers/tty/serial/sunhv.c
+++ b/drivers/tty/serial/sunhv.c
@@ -397,7 +397,7 @@ static const struct uart_ops sunhv_pops = {
static struct uart_driver sunhv_reg = {
.owner = THIS_MODULE,
.driver_name = "sunhv",
- .dev_name = "ttyS",
+ .dev_name = "ttyHV",
.major = TTY_MAJOR,
};
diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c
index 6e3c66ab0e62..a0555ae2b1ef 100644
--- a/drivers/tty/serial/ucc_uart.c
+++ b/drivers/tty/serial/ucc_uart.c
@@ -1081,7 +1081,7 @@ static int qe_uart_verify_port(struct uart_port *port,
}
/* UART operations
*
- * Details on these functions can be found in Documentation/serial/driver.rst
+ * Details on these functions can be found in Documentation/driver-api/serial/driver.rst
*/
static const struct uart_ops qe_uart_pops = {
.tx_empty = qe_uart_tx_empty,
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index 605354fd60b1..f145946f659b 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -26,21 +26,23 @@
#include <linux/of.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
+#include <linux/iopoll.h>
#define CDNS_UART_TTY_NAME "ttyPS"
#define CDNS_UART_NAME "xuartps"
-#define CDNS_UART_MAJOR 0 /* use dynamic node allocation */
#define CDNS_UART_FIFO_SIZE 64 /* FIFO size */
#define CDNS_UART_REGISTER_SPACE 0x1000
+#define TX_TIMEOUT 500000
/* Rx Trigger level */
static int rx_trigger_level = 56;
-module_param(rx_trigger_level, uint, S_IRUGO);
+static int uartps_major;
+module_param(rx_trigger_level, uint, 0444);
MODULE_PARM_DESC(rx_trigger_level, "Rx trigger level, 1-63 bytes");
/* Rx Timeout */
static int rx_timeout = 10;
-module_param(rx_timeout, uint, S_IRUGO);
+module_param(rx_timeout, uint, 0444);
MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
/* Register offsets for the UART. */
@@ -199,7 +201,7 @@ struct cdns_platform_data {
u32 quirks;
};
#define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \
- clk_rate_change_nb);
+ clk_rate_change_nb)
/**
* cdns_uart_handle_rx - Handle the received bytes along with Rx errors.
@@ -312,15 +314,16 @@ static void cdns_uart_handle_tx(void *dev_id)
} else {
numbytes = port->fifosize;
while (numbytes && !uart_circ_empty(&port->state->xmit) &&
- !(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL)) {
+ !(readl(port->membase + CDNS_UART_SR) &
+ CDNS_UART_SR_TXFULL)) {
/*
* Get the data from the UART circular buffer
* and write it to the cdns_uart's TX_FIFO
* register.
*/
writel(
- port->state->xmit.buf[port->state->xmit.
- tail], port->membase + CDNS_UART_FIFO);
+ port->state->xmit.buf[port->state->xmit.tail],
+ port->membase + CDNS_UART_FIFO);
port->icount.tx++;
@@ -684,18 +687,21 @@ static void cdns_uart_set_termios(struct uart_port *port,
unsigned int cval = 0;
unsigned int baud, minbaud, maxbaud;
unsigned long flags;
- unsigned int ctrl_reg, mode_reg;
-
- spin_lock_irqsave(&port->lock, flags);
+ unsigned int ctrl_reg, mode_reg, val;
+ int err;
/* Wait for the transmit FIFO to empty before making changes */
if (!(readl(port->membase + CDNS_UART_CR) &
CDNS_UART_CR_TX_DIS)) {
- while (!(readl(port->membase + CDNS_UART_SR) &
- CDNS_UART_SR_TXEMPTY)) {
- cpu_relax();
+ err = readl_poll_timeout(port->membase + CDNS_UART_SR,
+ val, (val & CDNS_UART_SR_TXEMPTY),
+ 1000, TX_TIMEOUT);
+ if (err) {
+ dev_err(port->dev, "timed out waiting for tx empty");
+ return;
}
}
+ spin_lock_irqsave(&port->lock, flags);
/* Disable the TX and RX to set baud rate */
ctrl_reg = readl(port->membase + CDNS_UART_CR);
@@ -1073,8 +1079,6 @@ static void cdns_uart_poll_put_char(struct uart_port *port, unsigned char c)
cpu_relax();
spin_unlock_irqrestore(&port->lock, flags);
-
- return;
}
#endif
@@ -1517,7 +1521,7 @@ static int cdns_uart_probe(struct platform_device *pdev)
cdns_uart_uart_driver->owner = THIS_MODULE;
cdns_uart_uart_driver->driver_name = driver_name;
cdns_uart_uart_driver->dev_name = CDNS_UART_TTY_NAME;
- cdns_uart_uart_driver->major = CDNS_UART_MAJOR;
+ cdns_uart_uart_driver->major = uartps_major;
cdns_uart_uart_driver->minor = cdns_uart_data->id;
cdns_uart_uart_driver->nr = 1;
@@ -1546,6 +1550,7 @@ static int cdns_uart_probe(struct platform_device *pdev)
goto err_out_id;
}
+ uartps_major = cdns_uart_uart_driver->tty_driver->major;
cdns_uart_data->cdns_uart_driver = cdns_uart_uart_driver;
/*
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 033ac7e6a70d..566728fbaf3c 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -1837,7 +1837,7 @@ static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp)
static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,
int *index)
{
- struct tty_driver *driver;
+ struct tty_driver *driver = NULL;
switch (device) {
#ifdef CONFIG_VT
@@ -1858,6 +1858,8 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,
break;
}
}
+ if (driver)
+ tty_driver_kref_put(driver);
return ERR_PTR(-ENODEV);
}
default:
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index e38f104db174..4c49f53afa3e 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -487,7 +487,7 @@ static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld)
static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
{
- lockdep_assert_held_exclusive(&tty->ldisc_sem);
+ lockdep_assert_held_write(&tty->ldisc_sem);
WARN_ON(!test_bit(TTY_LDISC_OPEN, &tty->flags));
clear_bit(TTY_LDISC_OPEN, &tty->flags);
if (ld->ops->close)
@@ -509,7 +509,7 @@ static int tty_ldisc_failto(struct tty_struct *tty, int ld)
struct tty_ldisc *disc = tty_ldisc_get(tty, ld);
int r;
- lockdep_assert_held_exclusive(&tty->ldisc_sem);
+ lockdep_assert_held_write(&tty->ldisc_sem);
if (IS_ERR(disc))
return PTR_ERR(disc);
tty->ldisc = disc;
@@ -633,7 +633,7 @@ EXPORT_SYMBOL_GPL(tty_set_ldisc);
*/
static void tty_ldisc_kill(struct tty_struct *tty)
{
- lockdep_assert_held_exclusive(&tty->ldisc_sem);
+ lockdep_assert_held_write(&tty->ldisc_sem);
if (!tty->ldisc)
return;
/*
@@ -681,7 +681,7 @@ int tty_ldisc_reinit(struct tty_struct *tty, int disc)
struct tty_ldisc *ld;
int retval;
- lockdep_assert_held_exclusive(&tty->ldisc_sem);
+ lockdep_assert_held_write(&tty->ldisc_sem);
ld = tty_ldisc_get(tty, disc);
if (IS_ERR(ld)) {
BUG_ON(disc == N_TTY);
@@ -855,8 +855,6 @@ void tty_ldisc_deinit(struct tty_struct *tty)
tty->ldisc = NULL;
}
-static int zero;
-static int one = 1;
static struct ctl_table tty_table[] = {
{
.procname = "ldisc_autoload",
@@ -864,8 +862,8 @@ static struct ctl_table tty_table[] = {
.maxlen = sizeof(tty_ldisc_autoload),
.mode = 0644,
.proc_handler = proc_dointvec,
- .extra1 = &zero,
- .extra2 = &one,
+ .extra1 = SYSCTL_ZERO,
+ .extra2 = SYSCTL_ONE,
},
{ }
};
diff --git a/drivers/uio/uio_dmem_genirq.c b/drivers/uio/uio_dmem_genirq.c
index 003badaef5f3..f32cef94aa82 100644
--- a/drivers/uio/uio_dmem_genirq.c
+++ b/drivers/uio/uio_dmem_genirq.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/uio/uio_dmem_genirq.c
*
@@ -6,10 +7,6 @@
* Copyright (C) 2012 Damian Hobson-Garcia
*
* Based on uio_pdrv_genirq.c by Magnus Damm
- *
- * 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.
*/
#include <linux/platform_device.h>
diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c
index 6c759934bff3..10688d79d180 100644
--- a/drivers/uio/uio_pdrv_genirq.c
+++ b/drivers/uio/uio_pdrv_genirq.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/uio/uio_pdrv_genirq.c
*
@@ -8,10 +9,6 @@
* Based on uio_pdrv.c by Uwe Kleine-Koenig,
* Copyright (C) 2008 by Digi International Inc.
* All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#include <linux/platform_device.h>
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index e4b27413f528..6e59d370ef81 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -45,6 +45,7 @@ config USB_ARCH_HAS_HCD
config USB
tristate "Support for Host-side USB"
depends on USB_ARCH_HAS_HCD
+ select GENERIC_ALLOCATOR
select USB_COMMON
select NLS # for UTF-8 strings
---help---
@@ -74,7 +75,7 @@ config USB
After choosing your HCD, then select drivers for the USB peripherals
you'll be using. You may want to check out the information provided
in <file:Documentation/usb/> and especially the links given in
- <file:Documentation/usb/usb-help.txt>.
+ <file:Documentation/usb/usb-help.rst>.
To compile this driver as a module, choose M here: the
module will be called usbcore.
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 7d1b8c82b208..ecc2de1ffaae 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -5,6 +5,7 @@
# Object files in subdirectories
+obj-$(CONFIG_USB_COMMON) += common/
obj-$(CONFIG_USB) += core/
obj-$(CONFIG_USB_SUPPORT) += phy/
@@ -60,8 +61,6 @@ obj-$(CONFIG_USB_CHIPIDEA) += chipidea/
obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs/
obj-$(CONFIG_USB_GADGET) += gadget/
-obj-$(CONFIG_USB_COMMON) += common/
-
obj-$(CONFIG_USBIP_CORE) += usbip/
obj-$(CONFIG_TYPEC) += typec/
diff --git a/drivers/usb/atm/Kconfig b/drivers/usb/atm/Kconfig
index 989aaa3b080d..3d958a1a1a71 100644
--- a/drivers/usb/atm/Kconfig
+++ b/drivers/usb/atm/Kconfig
@@ -7,7 +7,6 @@ menuconfig USB_ATM
tristate "USB DSL modem support"
depends on ATM
select CRC32
- default n
help
Say Y here if you want to connect a USB Digital Subscriber Line (DSL)
modem to your computer's USB port. You will then need to choose your
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index 2754b4ce7136..8faa51b1a520 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -1,55 +1,11 @@
-// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
-/*-
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-2-Clause)
+/*
* Copyright (c) 2003, 2004
* Damien Bergamini <damien.bergamini@free.fr>. All rights reserved.
*
* Copyright (c) 2005-2007 Matthieu Castet <castet.matthieu@free.fr>
* Copyright (c) 2005-2007 Stanislaw Gruszka <stf_xl@wp.pl>
*
- * This software is available to you under a choice of one of two
- * licenses. You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * BSD license below:
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice unmodified, this list of conditions, and the following
- * disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * GPL license :
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- *
* HISTORY : some part of the code was base on ueagle 1.3 BSD driver,
* Damien Bergamini agree to put his code under a DUAL GPL/BSD license.
*
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c
index ceec8d5985d4..b5abfe89190c 100644
--- a/drivers/usb/chipidea/ci_hdrc_imx.c
+++ b/drivers/usb/chipidea/ci_hdrc_imx.c
@@ -13,6 +13,7 @@
#include <linux/usb/of.h>
#include <linux/clk.h>
#include <linux/pinctrl/consumer.h>
+#include <linux/pm_qos.h>
#include "ci.h"
#include "ci_hdrc_imx.h"
@@ -63,6 +64,11 @@ static const struct ci_hdrc_imx_platform_flag imx7d_usb_data = {
.flags = CI_HDRC_SUPPORTS_RUNTIME_PM,
};
+static const struct ci_hdrc_imx_platform_flag imx7ulp_usb_data = {
+ .flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
+ CI_HDRC_PMQOS,
+};
+
static const struct of_device_id ci_hdrc_imx_dt_ids[] = {
{ .compatible = "fsl,imx23-usb", .data = &imx23_usb_data},
{ .compatible = "fsl,imx28-usb", .data = &imx28_usb_data},
@@ -72,6 +78,7 @@ static const struct of_device_id ci_hdrc_imx_dt_ids[] = {
{ .compatible = "fsl,imx6sx-usb", .data = &imx6sx_usb_data},
{ .compatible = "fsl,imx6ul-usb", .data = &imx6ul_usb_data},
{ .compatible = "fsl,imx7d-usb", .data = &imx7d_usb_data},
+ { .compatible = "fsl,imx7ulp-usb", .data = &imx7ulp_usb_data},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, ci_hdrc_imx_dt_ids);
@@ -93,6 +100,8 @@ struct ci_hdrc_imx_data {
struct clk *clk_ahb;
struct clk *clk_per;
/* --------------------------------- */
+ struct pm_qos_request pm_qos_req;
+ const struct ci_hdrc_imx_platform_flag *plat_data;
};
/* Common functions shared by usbmisc drivers */
@@ -309,6 +318,8 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
if (!data)
return -ENOMEM;
+ data->plat_data = imx_platform_flag;
+ pdata.flags |= imx_platform_flag->flags;
platform_set_drvdata(pdev, data);
data->usbmisc_data = usbmisc_get_init_data(dev);
if (IS_ERR(data->usbmisc_data))
@@ -369,6 +380,11 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
}
}
}
+
+ if (pdata.flags & CI_HDRC_PMQOS)
+ pm_qos_add_request(&data->pm_qos_req,
+ PM_QOS_CPU_DMA_LATENCY, 0);
+
ret = imx_get_clks(dev);
if (ret)
goto disable_hsic_regulator;
@@ -382,8 +398,9 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
ret = PTR_ERR(data->phy);
/* Return -EINVAL if no usbphy is available */
if (ret == -ENODEV)
- ret = -EINVAL;
- goto err_clk;
+ data->phy = NULL;
+ else
+ goto err_clk;
}
pdata.usb_phy = data->phy;
@@ -396,7 +413,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
usb_phy_init(pdata.usb_phy);
}
- pdata.flags |= imx_platform_flag->flags;
if (pdata.flags & CI_HDRC_SUPPORTS_RUNTIME_PM)
data->supports_runtime_pm = true;
@@ -439,6 +455,8 @@ err_clk:
disable_hsic_regulator:
if (data->hsic_pad_regulator)
ret = regulator_disable(data->hsic_pad_regulator);
+ if (pdata.flags & CI_HDRC_PMQOS)
+ pm_qos_remove_request(&data->pm_qos_req);
return ret;
}
@@ -455,6 +473,8 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev)
if (data->override_phy_control)
usb_phy_shutdown(data->phy);
imx_disable_unprepare_clks(&pdev->dev);
+ if (data->plat_data->flags & CI_HDRC_PMQOS)
+ pm_qos_remove_request(&data->pm_qos_req);
if (data->hsic_pad_regulator)
regulator_disable(data->hsic_pad_regulator);
@@ -480,6 +500,9 @@ static int __maybe_unused imx_controller_suspend(struct device *dev)
}
imx_disable_unprepare_clks(dev);
+ if (data->plat_data->flags & CI_HDRC_PMQOS)
+ pm_qos_remove_request(&data->pm_qos_req);
+
data->in_lpm = true;
return 0;
@@ -497,6 +520,10 @@ static int __maybe_unused imx_controller_resume(struct device *dev)
return 0;
}
+ if (data->plat_data->flags & CI_HDRC_PMQOS)
+ pm_qos_add_request(&data->pm_qos_req,
+ PM_QOS_CPU_DMA_LATENCY, 0);
+
ret = imx_prepare_enable_clks(dev);
if (ret)
return ret;
diff --git a/drivers/usb/chipidea/ci_hdrc_msm.c b/drivers/usb/chipidea/ci_hdrc_msm.c
index b8b3caad889c..bb4645a8ca46 100644
--- a/drivers/usb/chipidea/ci_hdrc_msm.c
+++ b/drivers/usb/chipidea/ci_hdrc_msm.c
@@ -175,7 +175,6 @@ static int ci_hdrc_msm_probe(struct platform_device *pdev)
struct platform_device *plat_ci;
struct clk *clk;
struct reset_control *reset;
- struct resource *res;
int ret;
struct device_node *ulpi_node, *phy_node;
@@ -209,8 +208,7 @@ static int ci_hdrc_msm_probe(struct platform_device *pdev)
if (IS_ERR(clk))
return PTR_ERR(clk);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- ci->base = devm_ioremap_resource(&pdev->dev, res);
+ ci->base = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(ci->base))
return PTR_ERR(ci->base);
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 27749ace2d93..26062d610c20 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -523,8 +523,9 @@ int hw_device_reset(struct ci_hdrc *ci)
hw_write(ci, OP_USBMODE, USBMODE_SLOM, USBMODE_SLOM);
if (hw_read(ci, OP_USBMODE, USBMODE_CM) != USBMODE_CM_DC) {
- pr_err("cannot enter in %s device mode", ci_role(ci)->name);
- pr_err("lpm = %i", ci->hw_bank.lpm);
+ dev_err(ci->dev, "cannot enter in %s device mode\n",
+ ci_role(ci)->name);
+ dev_err(ci->dev, "lpm = %i\n", ci->hw_bank.lpm);
return -ENODEV;
}
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 829e947cabf5..6a5ee8e6da10 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -1622,6 +1622,25 @@ static int ci_udc_pullup(struct usb_gadget *_gadget, int is_on)
static int ci_udc_start(struct usb_gadget *gadget,
struct usb_gadget_driver *driver);
static int ci_udc_stop(struct usb_gadget *gadget);
+
+/* Match ISOC IN from the highest endpoint */
+static struct usb_ep *ci_udc_match_ep(struct usb_gadget *gadget,
+ struct usb_endpoint_descriptor *desc,
+ struct usb_ss_ep_comp_descriptor *comp_desc)
+{
+ struct ci_hdrc *ci = container_of(gadget, struct ci_hdrc, gadget);
+ struct usb_ep *ep;
+
+ if (usb_endpoint_xfer_isoc(desc) && usb_endpoint_dir_in(desc)) {
+ list_for_each_entry_reverse(ep, &ci->gadget.ep_list, ep_list) {
+ if (ep->caps.dir_in && !ep->claimed)
+ return ep;
+ }
+ }
+
+ return NULL;
+}
+
/**
* Device operations part of the API to the USB controller hardware,
* which don't involve endpoints (or i/o)
@@ -1635,6 +1654,7 @@ static const struct usb_gadget_ops usb_gadget_ops = {
.vbus_draw = ci_udc_vbus_draw,
.udc_start = ci_udc_start,
.udc_stop = ci_udc_stop,
+ .match_ep = ci_udc_match_ep,
};
static int init_eps(struct ci_hdrc *ci)
diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c
index d8b67e150b12..078c1fdce493 100644
--- a/drivers/usb/chipidea/usbmisc_imx.c
+++ b/drivers/usb/chipidea/usbmisc_imx.c
@@ -763,13 +763,16 @@ static const struct of_device_id usbmisc_imx_dt_ids[] = {
.compatible = "fsl,imx7d-usbmisc",
.data = &imx7d_usbmisc_ops,
},
+ {
+ .compatible = "fsl,imx7ulp-usbmisc",
+ .data = &imx7d_usbmisc_ops,
+ },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids);
static int usbmisc_imx_probe(struct platform_device *pdev)
{
- struct resource *res;
struct imx_usbmisc *data;
const struct of_device_id *of_id;
@@ -783,8 +786,7 @@ static int usbmisc_imx_probe(struct platform_device *pdev)
spin_lock_init(&data->lock);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- data->base = devm_ioremap_resource(&pdev->dev, res);
+ data->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(data->base))
return PTR_ERR(data->base);
diff --git a/drivers/usb/class/Kconfig b/drivers/usb/class/Kconfig
index 52f3a531a82f..f8a798900093 100644
--- a/drivers/usb/class/Kconfig
+++ b/drivers/usb/class/Kconfig
@@ -10,7 +10,7 @@ config USB_ACM
---help---
This driver supports USB modems and ISDN adapters which support the
Communication Device Class Abstract Control Model interface.
- Please read <file:Documentation/usb/acm.txt> for details.
+ Please read <file:Documentation/usb/acm.rst> for details.
If your modem only reports "Cls=ff(vend.)" in the descriptors in
/sys/kernel/debug/usb/devices, then your modem will not work with this
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index 9e9caff905d5..a7824a51f86d 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -949,7 +949,7 @@ struct usb_driver *usb_cdc_wdm_register(struct usb_interface *intf,
int bufsize,
int (*manage_power)(struct usb_interface *, int))
{
- int rv = -EINVAL;
+ int rv;
rv = wdm_create(intf, ep, bufsize, manage_power);
if (rv < 0)
diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c
index 18f5dcf58b0d..1433260d99b4 100644
--- a/drivers/usb/common/common.c
+++ b/drivers/usb/common/common.c
@@ -15,6 +15,8 @@
#include <linux/usb/of.h>
#include <linux/usb/otg.h>
#include <linux/of_platform.h>
+#include <linux/debugfs.h>
+#include "common.h"
static const char *const ep_type_names[] = {
[USB_ENDPOINT_XFER_CONTROL] = "ctrl",
@@ -291,4 +293,23 @@ struct device *usb_of_get_companion_dev(struct device *dev)
EXPORT_SYMBOL_GPL(usb_of_get_companion_dev);
#endif
+struct dentry *usb_debug_root;
+EXPORT_SYMBOL_GPL(usb_debug_root);
+
+static int __init usb_common_init(void)
+{
+ usb_debug_root = debugfs_create_dir("usb", NULL);
+ ledtrig_usb_init();
+ return 0;
+}
+
+static void __exit usb_common_exit(void)
+{
+ ledtrig_usb_exit();
+ debugfs_remove_recursive(usb_debug_root);
+}
+
+subsys_initcall(usb_common_init);
+module_exit(usb_common_exit);
+
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/common/common.h b/drivers/usb/common/common.h
new file mode 100644
index 000000000000..424a91316a4b
--- /dev/null
+++ b/drivers/usb/common/common.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __LINUX_USB_COMMON_H
+#define __LINUX_USB_COMMON_H
+
+#if defined(CONFIG_USB_LED_TRIG)
+void ledtrig_usb_init(void);
+void ledtrig_usb_exit(void);
+#else
+static inline void ledtrig_usb_init(void) { }
+static inline void ledtrig_usb_exit(void) { }
+#endif
+
+#endif /* __LINUX_USB_COMMON_H */
diff --git a/drivers/usb/common/led.c b/drivers/usb/common/led.c
index 7bd81166b77d..0865dd44a80a 100644
--- a/drivers/usb/common/led.c
+++ b/drivers/usb/common/led.c
@@ -10,6 +10,7 @@
#include <linux/init.h>
#include <linux/leds.h>
#include <linux/usb.h>
+#include "common.h"
#define BLINK_DELAY 30
@@ -36,18 +37,14 @@ void usb_led_activity(enum usb_led_event ev)
EXPORT_SYMBOL_GPL(usb_led_activity);
-static int __init ledtrig_usb_init(void)
+void __init ledtrig_usb_init(void)
{
led_trigger_register_simple("usb-gadget", &ledtrig_usb_gadget);
led_trigger_register_simple("usb-host", &ledtrig_usb_host);
- return 0;
}
-static void __exit ledtrig_usb_exit(void)
+void __exit ledtrig_usb_exit(void)
{
led_trigger_unregister_simple(ledtrig_usb_gadget);
led_trigger_unregister_simple(ledtrig_usb_host);
}
-
-module_init(ledtrig_usb_init);
-module_exit(ledtrig_usb_exit);
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index bdb6bd0b63a6..ecaacc8ed311 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -45,7 +45,6 @@ config USB_DYNAMIC_MINORS
config USB_OTG
bool "OTG support"
depends on PM
- default n
help
The most notable feature of USB OTG is support for a
"Dual-Role" device, which can act as either a device
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
index f641342cdec0..1359b78a624e 100644
--- a/drivers/usb/core/buffer.c
+++ b/drivers/usb/core/buffer.c
@@ -16,6 +16,7 @@
#include <linux/io.h>
#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
+#include <linux/genalloc.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
@@ -67,7 +68,7 @@ int hcd_buffer_create(struct usb_hcd *hcd)
if (!IS_ENABLED(CONFIG_HAS_DMA) ||
(!is_device_dma_capable(hcd->self.sysdev) &&
- !(hcd->driver->flags & HCD_LOCAL_MEM)))
+ !hcd->localmem_pool))
return 0;
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
@@ -124,10 +125,12 @@ void *hcd_buffer_alloc(
if (size == 0)
return NULL;
+ if (hcd->localmem_pool)
+ return gen_pool_dma_alloc(hcd->localmem_pool, size, dma);
+
/* some USB hosts just use PIO */
if (!IS_ENABLED(CONFIG_HAS_DMA) ||
- (!is_device_dma_capable(bus->sysdev) &&
- !(hcd->driver->flags & HCD_LOCAL_MEM))) {
+ !is_device_dma_capable(bus->sysdev)) {
*dma = ~(dma_addr_t) 0;
return kmalloc(size, mem_flags);
}
@@ -152,9 +155,13 @@ void hcd_buffer_free(
if (!addr)
return;
+ if (hcd->localmem_pool) {
+ gen_pool_free(hcd->localmem_pool, (unsigned long)addr, size);
+ return;
+ }
+
if (!IS_ENABLED(CONFIG_HAS_DMA) ||
- (!is_device_dma_capable(bus->sysdev) &&
- !(hcd->driver->flags & HCD_LOCAL_MEM))) {
+ !is_device_dma_capable(bus->sysdev)) {
kfree(addr);
return;
}
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index fa783531ee88..b265ab5405f9 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -48,9 +48,6 @@
#define USB_DEVICE_MAX (USB_MAXBUS * 128)
#define USB_SG_SIZE 16384 /* split-size for large txs */
-/* Mutual exclusion for removal, open, and release */
-DEFINE_MUTEX(usbfs_mutex);
-
struct usb_dev_state {
struct list_head list; /* state list */
struct usb_device *dev;
@@ -63,7 +60,7 @@ struct usb_dev_state {
unsigned int discsignr;
struct pid *disc_pid;
const struct cred *cred;
- void __user *disccontext;
+ sigval_t disccontext;
unsigned long ifclaimed;
u32 disabled_bulk_eps;
bool privileges_dropped;
@@ -90,6 +87,7 @@ struct async {
unsigned int ifnum;
void __user *userbuffer;
void __user *userurb;
+ sigval_t userurb_sigval;
struct urb *urb;
struct usb_memory *usbm;
unsigned int mem_usage;
@@ -582,22 +580,19 @@ static void async_completed(struct urb *urb)
{
struct async *as = urb->context;
struct usb_dev_state *ps = as->ps;
- struct kernel_siginfo sinfo;
struct pid *pid = NULL;
const struct cred *cred = NULL;
unsigned long flags;
- int signr;
+ sigval_t addr;
+ int signr, errno;
spin_lock_irqsave(&ps->lock, flags);
list_move_tail(&as->asynclist, &ps->async_completed);
as->status = urb->status;
signr = as->signr;
if (signr) {
- clear_siginfo(&sinfo);
- sinfo.si_signo = as->signr;
- sinfo.si_errno = as->status;
- sinfo.si_code = SI_ASYNCIO;
- sinfo.si_addr = as->userurb;
+ errno = as->status;
+ addr = as->userurb_sigval;
pid = get_pid(as->pid);
cred = get_cred(as->cred);
}
@@ -615,7 +610,7 @@ static void async_completed(struct urb *urb)
spin_unlock_irqrestore(&ps->lock, flags);
if (signr) {
- kill_pid_info_as_cred(sinfo.si_signo, &sinfo, pid, cred);
+ kill_pid_usb_asyncio(signr, errno, addr, pid, cred);
put_pid(pid);
put_cred(cred);
}
@@ -947,9 +942,9 @@ error:
return ret;
}
-static int match_devt(struct device *dev, void *data)
+static int match_devt(struct device *dev, const void *data)
{
- return dev->devt == (dev_t) (unsigned long) data;
+ return dev->devt == (dev_t)(unsigned long)(void *)data;
}
static struct usb_device *usbdev_lookup_by_devt(dev_t devt)
@@ -979,15 +974,9 @@ static int usbdev_open(struct inode *inode, struct file *file)
ret = -ENODEV;
- /* Protect against simultaneous removal or release */
- mutex_lock(&usbfs_mutex);
-
/* usbdev device-node */
if (imajor(inode) == USB_DEVICE_MAJOR)
dev = usbdev_lookup_by_devt(inode->i_rdev);
-
- mutex_unlock(&usbfs_mutex);
-
if (!dev)
goto out_free_ps;
@@ -1308,6 +1297,39 @@ static int proc_connectinfo(struct usb_dev_state *ps, void __user *arg)
return 0;
}
+static int proc_conninfo_ex(struct usb_dev_state *ps,
+ void __user *arg, size_t size)
+{
+ struct usbdevfs_conninfo_ex ci;
+ struct usb_device *udev = ps->dev;
+
+ if (size < sizeof(ci.size))
+ return -EINVAL;
+
+ memset(&ci, 0, sizeof(ci));
+ ci.size = sizeof(ci);
+ ci.busnum = udev->bus->busnum;
+ ci.devnum = udev->devnum;
+ ci.speed = udev->speed;
+
+ while (udev && udev->portnum != 0) {
+ if (++ci.num_ports <= ARRAY_SIZE(ci.ports))
+ ci.ports[ARRAY_SIZE(ci.ports) - ci.num_ports] =
+ udev->portnum;
+ udev = udev->parent;
+ }
+
+ if (ci.num_ports < ARRAY_SIZE(ci.ports))
+ memmove(&ci.ports[0],
+ &ci.ports[ARRAY_SIZE(ci.ports) - ci.num_ports],
+ ci.num_ports);
+
+ if (copy_to_user(arg, &ci, min(sizeof(ci), size)))
+ return -EFAULT;
+
+ return 0;
+}
+
static int proc_resetdevice(struct usb_dev_state *ps)
{
struct usb_host_config *actconfig = ps->dev->actconfig;
@@ -1427,7 +1449,7 @@ find_memory_area(struct usb_dev_state *ps, const struct usbdevfs_urb *uurb)
static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb,
struct usbdevfs_iso_packet_desc __user *iso_frame_desc,
- void __user *arg)
+ void __user *arg, sigval_t userurb_sigval)
{
struct usbdevfs_iso_packet_desc *isopkt = NULL;
struct usb_host_endpoint *ep;
@@ -1486,15 +1508,15 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
ret = -EFAULT;
goto error;
}
- if (uurb->buffer_length < (le16_to_cpup(&dr->wLength) + 8)) {
+ if (uurb->buffer_length < (le16_to_cpu(dr->wLength) + 8)) {
ret = -EINVAL;
goto error;
}
ret = check_ctrlrecip(ps, dr->bRequestType, dr->bRequest,
- le16_to_cpup(&dr->wIndex));
+ le16_to_cpu(dr->wIndex));
if (ret)
goto error;
- uurb->buffer_length = le16_to_cpup(&dr->wLength);
+ uurb->buffer_length = le16_to_cpu(dr->wLength);
uurb->buffer += 8;
if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) {
is_in = 1;
@@ -1509,9 +1531,9 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
"bRequest=%02x wValue=%04x "
"wIndex=%04x wLength=%04x\n",
dr->bRequestType, dr->bRequest,
- __le16_to_cpup(&dr->wValue),
- __le16_to_cpup(&dr->wIndex),
- __le16_to_cpup(&dr->wLength));
+ __le16_to_cpu(dr->wValue),
+ __le16_to_cpu(dr->wIndex),
+ __le16_to_cpu(dr->wLength));
u = sizeof(struct usb_ctrlrequest);
break;
@@ -1727,6 +1749,7 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
isopkt = NULL;
as->ps = ps;
as->userurb = arg;
+ as->userurb_sigval = userurb_sigval;
if (as->usbm) {
unsigned long uurb_start = (unsigned long)uurb->buffer;
@@ -1801,13 +1824,17 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
static int proc_submiturb(struct usb_dev_state *ps, void __user *arg)
{
struct usbdevfs_urb uurb;
+ sigval_t userurb_sigval;
if (copy_from_user(&uurb, arg, sizeof(uurb)))
return -EFAULT;
+ memset(&userurb_sigval, 0, sizeof(userurb_sigval));
+ userurb_sigval.sival_ptr = arg;
+
return proc_do_submiturb(ps, &uurb,
(((struct usbdevfs_urb __user *)arg)->iso_frame_desc),
- arg);
+ arg, userurb_sigval);
}
static int proc_unlinkurb(struct usb_dev_state *ps, void __user *arg)
@@ -1977,7 +2004,7 @@ static int proc_disconnectsignal_compat(struct usb_dev_state *ps, void __user *a
if (copy_from_user(&ds, arg, sizeof(ds)))
return -EFAULT;
ps->discsignr = ds.signr;
- ps->disccontext = compat_ptr(ds.context);
+ ps->disccontext.sival_int = ds.context;
return 0;
}
@@ -2005,13 +2032,17 @@ static int get_urb32(struct usbdevfs_urb *kurb,
static int proc_submiturb_compat(struct usb_dev_state *ps, void __user *arg)
{
struct usbdevfs_urb uurb;
+ sigval_t userurb_sigval;
if (get_urb32(&uurb, (struct usbdevfs_urb32 __user *)arg))
return -EFAULT;
+ memset(&userurb_sigval, 0, sizeof(userurb_sigval));
+ userurb_sigval.sival_int = ptr_to_compat(arg);
+
return proc_do_submiturb(ps, &uurb,
((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc,
- arg);
+ arg, userurb_sigval);
}
static int processcompl_compat(struct async *as, void __user * __user *arg)
@@ -2092,7 +2123,7 @@ static int proc_disconnectsignal(struct usb_dev_state *ps, void __user *arg)
if (copy_from_user(&ds, arg, sizeof(ds)))
return -EFAULT;
ps->discsignr = ds.signr;
- ps->disccontext = ds.context;
+ ps->disccontext.sival_ptr = ds.context;
return 0;
}
@@ -2130,6 +2161,9 @@ static int proc_ioctl(struct usb_dev_state *ps, struct usbdevfs_ioctl *ctl)
if (ps->privileges_dropped)
return -EACCES;
+ if (!connected(ps))
+ return -ENODEV;
+
/* alloc buffer */
size = _IOC_SIZE(ctl->ioctl_code);
if (size > 0) {
@@ -2146,11 +2180,6 @@ static int proc_ioctl(struct usb_dev_state *ps, struct usbdevfs_ioctl *ctl)
}
}
- if (!connected(ps)) {
- kfree(buf);
- return -ENODEV;
- }
-
if (ps->dev->state != USB_STATE_CONFIGURED)
retval = -EHOSTUNREACH;
else if (!(intf = usb_ifnum_to_if(ps->dev, ctl->ifno)))
@@ -2252,7 +2281,7 @@ static int proc_get_capabilities(struct usb_dev_state *ps, void __user *arg)
caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM |
USBDEVFS_CAP_REAP_AFTER_DISCONNECT | USBDEVFS_CAP_MMAP |
- USBDEVFS_CAP_DROP_PRIVILEGES;
+ USBDEVFS_CAP_DROP_PRIVILEGES | USBDEVFS_CAP_CONNINFO_EX;
if (!ps->dev->bus->no_stop_on_short)
caps |= USBDEVFS_CAP_BULK_CONTINUATION;
if (ps->dev->bus->sg_tablesize)
@@ -2551,6 +2580,13 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
break;
}
+ /* Handle variable-length commands */
+ switch (cmd & ~IOCSIZE_MASK) {
+ case USBDEVFS_CONNINFO_EX(0):
+ ret = proc_conninfo_ex(ps, p, _IOC_SIZE(cmd));
+ break;
+ }
+
done:
usb_unlock_device(dev);
if (ret >= 0)
@@ -2614,22 +2650,15 @@ const struct file_operations usbdev_file_operations = {
static void usbdev_remove(struct usb_device *udev)
{
struct usb_dev_state *ps;
- struct kernel_siginfo sinfo;
while (!list_empty(&udev->filelist)) {
ps = list_entry(udev->filelist.next, struct usb_dev_state, list);
destroy_all_async(ps);
wake_up_all(&ps->wait);
list_del_init(&ps->list);
- if (ps->discsignr) {
- clear_siginfo(&sinfo);
- sinfo.si_signo = ps->discsignr;
- sinfo.si_errno = EPIPE;
- sinfo.si_code = SI_ASYNCIO;
- sinfo.si_addr = ps->disccontext;
- kill_pid_info_as_cred(ps->discsignr, &sinfo,
- ps->disc_pid, ps->cred);
- }
+ if (ps->discsignr)
+ kill_pid_usb_asyncio(ps->discsignr, EPIPE, ps->disccontext,
+ ps->disc_pid, ps->cred);
}
}
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 94d22551fc1b..88533938ce19 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -29,6 +29,8 @@
#include <linux/workqueue.h>
#include <linux/pm_runtime.h>
#include <linux/types.h>
+#include <linux/genalloc.h>
+#include <linux/io.h>
#include <linux/phy/phy.h>
#include <linux/usb.h>
@@ -1345,14 +1347,14 @@ EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep);
* using regular system memory - like pci devices doing bus mastering.
*
* To support host controllers with limited dma capabilities we provide dma
- * bounce buffers. This feature can be enabled using the HCD_LOCAL_MEM flag.
+ * bounce buffers. This feature can be enabled by initializing
+ * hcd->localmem_pool using usb_hcd_setup_local_mem().
* For this to work properly the host controller code must first use the
* function dma_declare_coherent_memory() to point out which memory area
* that should be used for dma allocations.
*
- * The HCD_LOCAL_MEM flag then tells the usb code to allocate all data for
- * dma using dma_alloc_coherent() which in turn allocates from the memory
- * area pointed out with dma_declare_coherent_memory().
+ * The initialized hcd->localmem_pool then tells the usb code to allocate all
+ * data for dma using the genalloc API.
*
* So, to summarize...
*
@@ -1362,9 +1364,6 @@ EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep);
* (a) "normal" kernel memory is no good, and
* (b) there's not enough to share
*
- * - The only *portable* hook for such stuff in the
- * DMA framework is dma_declare_coherent_memory()
- *
* - So we use that, even though the primary requirement
* is that the memory be "local" (hence addressable
* by that device), not "coherent".
@@ -1531,7 +1530,7 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
urb->setup_dma))
return -EAGAIN;
urb->transfer_flags |= URB_SETUP_MAP_SINGLE;
- } else if (hcd->driver->flags & HCD_LOCAL_MEM) {
+ } else if (hcd->localmem_pool) {
ret = hcd_alloc_coherent(
urb->dev->bus, mem_flags,
&urb->setup_dma,
@@ -1601,7 +1600,7 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
else
urb->transfer_flags |= URB_DMA_MAP_SINGLE;
}
- } else if (hcd->driver->flags & HCD_LOCAL_MEM) {
+ } else if (hcd->localmem_pool) {
ret = hcd_alloc_coherent(
urb->dev->bus, mem_flags,
&urb->transfer_dma,
@@ -3039,6 +3038,40 @@ usb_hcd_platform_shutdown(struct platform_device *dev)
}
EXPORT_SYMBOL_GPL(usb_hcd_platform_shutdown);
+int usb_hcd_setup_local_mem(struct usb_hcd *hcd, phys_addr_t phys_addr,
+ dma_addr_t dma, size_t size)
+{
+ int err;
+ void *local_mem;
+
+ hcd->localmem_pool = devm_gen_pool_create(hcd->self.sysdev, 4,
+ dev_to_node(hcd->self.sysdev),
+ dev_name(hcd->self.sysdev));
+ if (IS_ERR(hcd->localmem_pool))
+ return PTR_ERR(hcd->localmem_pool);
+
+ local_mem = devm_memremap(hcd->self.sysdev, phys_addr,
+ size, MEMREMAP_WC);
+ if (!local_mem)
+ return -ENOMEM;
+
+ /*
+ * Here we pass a dma_addr_t but the arg type is a phys_addr_t.
+ * It's not backed by system memory and thus there's no kernel mapping
+ * for it.
+ */
+ err = gen_pool_add_virt(hcd->localmem_pool, (unsigned long)local_mem,
+ dma, size, dev_to_node(hcd->self.sysdev));
+ if (err < 0) {
+ dev_err(hcd->self.sysdev, "gen_pool_add_virt failed with %d\n",
+ err);
+ return err;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_hcd_setup_local_mem);
+
/*-------------------------------------------------------------------------*/
#if IS_ENABLED(CONFIG_USB_MON)
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 2f94568ba385..236313f41f4a 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -873,7 +873,7 @@ int usb_hub_clear_tt_buffer(struct urb *urb)
/* info that CLEAR_TT_BUFFER needs */
clear->tt = tt->multi ? udev->ttport : 1;
clear->devinfo = usb_pipeendpoint (pipe);
- clear->devinfo |= udev->devnum << 4;
+ clear->devinfo |= ((u16)udev->devaddr) << 4;
clear->devinfo |= usb_pipecontrol(pipe)
? (USB_ENDPOINT_XFER_CONTROL << 11)
: (USB_ENDPOINT_XFER_BULK << 11);
@@ -2125,6 +2125,8 @@ static void update_devnum(struct usb_device *udev, int devnum)
/* The address for a WUSB device is managed by wusbcore. */
if (!udev->wusb)
udev->devnum = devnum;
+ if (!udev->devaddr)
+ udev->devaddr = (u8)devnum;
}
static void hub_free_dev(struct usb_device *udev)
@@ -2719,7 +2721,7 @@ static bool use_new_scheme(struct usb_device *udev, int retry,
}
/* Is a USB 3.0 port in the Inactive or Compliance Mode state?
- * Port worm reset is required to recover
+ * Port warm reset is required to recover
*/
static bool hub_port_warm_reset_required(struct usb_hub *hub, int port1,
u16 portstatus)
@@ -3617,6 +3619,7 @@ static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port,
struct usb_device *hdev;
struct usb_device *udev;
int connect_change = 0;
+ u16 link_state;
int ret;
hdev = hub->hdev;
@@ -3626,9 +3629,11 @@ static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port,
return 0;
usb_clear_port_feature(hdev, port, USB_PORT_FEAT_C_SUSPEND);
} else {
+ link_state = portstatus & USB_PORT_STAT_LINK_STATE;
if (!udev || udev->state != USB_STATE_SUSPENDED ||
- (portstatus & USB_PORT_STAT_LINK_STATE) !=
- USB_SS_PORT_LS_U0)
+ (link_state != USB_SS_PORT_LS_U0 &&
+ link_state != USB_SS_PORT_LS_U1 &&
+ link_state != USB_SS_PORT_LS_U2))
return 0;
}
@@ -3999,6 +4004,9 @@ static int usb_set_lpm_timeout(struct usb_device *udev,
* control transfers to set the hub timeout or enable device-initiated U1/U2
* will be successful.
*
+ * If the control transfer to enable device-initiated U1/U2 entry fails, then
+ * hub-initiated U1/U2 will be disabled.
+ *
* If we cannot set the parent hub U1/U2 timeout, we attempt to let the xHCI
* driver know about it. If that call fails, it should be harmless, and just
* take up more slightly more bus bandwidth for unnecessary U1/U2 exit latency.
@@ -4053,23 +4061,24 @@ static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
* host know that this link state won't be enabled.
*/
hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state);
- } else {
- /* Only a configured device will accept the Set Feature
- * U1/U2_ENABLE
- */
- if (udev->actconfig)
- usb_set_device_initiated_lpm(udev, state, true);
+ return;
+ }
- /* As soon as usb_set_lpm_timeout(timeout) returns 0, the
- * hub-initiated LPM is enabled. Thus, LPM is enabled no
- * matter the result of usb_set_device_initiated_lpm().
- * The only difference is whether device is able to initiate
- * LPM.
- */
+ /* Only a configured device will accept the Set Feature
+ * U1/U2_ENABLE
+ */
+ if (udev->actconfig &&
+ usb_set_device_initiated_lpm(udev, state, true) == 0) {
if (state == USB3_LPM_U1)
udev->usb3_lpm_u1_enabled = 1;
else if (state == USB3_LPM_U2)
udev->usb3_lpm_u2_enabled = 1;
+ } else {
+ /* Don't request U1/U2 entry if the device
+ * cannot transition to U1/U2.
+ */
+ usb_set_lpm_timeout(udev, state, 0);
+ hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state);
}
}
@@ -4139,7 +4148,7 @@ int usb_disable_lpm(struct usb_device *udev)
if (!udev || !udev->parent ||
udev->speed < USB_SPEED_SUPER ||
!udev->lpm_capable ||
- udev->state < USB_STATE_DEFAULT)
+ udev->state < USB_STATE_CONFIGURED)
return 0;
hcd = bus_to_hcd(udev->bus);
@@ -4198,7 +4207,7 @@ void usb_enable_lpm(struct usb_device *udev)
if (!udev || !udev->parent ||
udev->speed < USB_SPEED_SUPER ||
!udev->lpm_capable ||
- udev->state < USB_STATE_DEFAULT)
+ udev->state < USB_STATE_CONFIGURED)
return;
udev->lpm_disable_count--;
diff --git a/drivers/usb/core/notify.c b/drivers/usb/core/notify.c
index ab474b11523e..e6143663778f 100644
--- a/drivers/usb/core/notify.c
+++ b/drivers/usb/core/notify.c
@@ -53,11 +53,8 @@ void usb_notify_add_device(struct usb_device *udev)
void usb_notify_remove_device(struct usb_device *udev)
{
- /* Protect against simultaneous usbfs open */
- mutex_lock(&usbfs_mutex);
blocking_notifier_call_chain(&usb_notifier_list,
USB_DEVICE_REMOVE, udev);
- mutex_unlock(&usbfs_mutex);
}
void usb_notify_add_bus(struct usb_bus *ubus)
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 7fcb9f782931..0ab8738047da 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -325,9 +325,9 @@ struct find_interface_arg {
struct device_driver *drv;
};
-static int __find_interface(struct device *dev, void *data)
+static int __find_interface(struct device *dev, const void *data)
{
- struct find_interface_arg *arg = data;
+ const struct find_interface_arg *arg = data;
struct usb_interface *intf;
if (!is_usb_interface(dev))
@@ -1185,19 +1185,17 @@ static struct notifier_block usb_bus_nb = {
.notifier_call = usb_bus_notify,
};
-struct dentry *usb_debug_root;
-EXPORT_SYMBOL_GPL(usb_debug_root);
+static struct dentry *usb_devices_root;
static void usb_debugfs_init(void)
{
- usb_debug_root = debugfs_create_dir("usb", NULL);
- debugfs_create_file("devices", 0444, usb_debug_root, NULL,
- &usbfs_devices_fops);
+ usb_devices_root = debugfs_create_file("devices", 0444, usb_debug_root,
+ NULL, &usbfs_devices_fops);
}
static void usb_debugfs_cleanup(void)
{
- debugfs_remove_recursive(usb_debug_root);
+ debugfs_remove(usb_devices_root);
}
/*
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index d95a5358f73d..bd8d01f85a13 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -169,7 +169,6 @@ extern const struct attribute_group *usb_device_groups[];
extern const struct attribute_group *usb_interface_groups[];
/* usbfs stuff */
-extern struct mutex usbfs_mutex;
extern struct usb_driver usbfs_driver;
extern const struct file_operations usbfs_devices_fops;
extern const struct file_operations usbdev_file_operations;
diff --git a/drivers/usb/dwc2/Kconfig b/drivers/usb/dwc2/Kconfig
index 68d095ae2865..16e1aa304edc 100644
--- a/drivers/usb/dwc2/Kconfig
+++ b/drivers/usb/dwc2/Kconfig
@@ -58,7 +58,6 @@ config USB_DWC2_PCI
tristate "DWC2 PCI"
depends on USB_PCI
depends on USB_GADGET || !USB_GADGET
- default n
select NOP_USB_XCEIV
help
The Designware USB2.0 PCI interface module for controllers
diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
index 8b499d643461..8e41d70fd298 100644
--- a/drivers/usb/dwc2/core.c
+++ b/drivers/usb/dwc2/core.c
@@ -531,7 +531,7 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait)
}
/* Wait for AHB master IDLE state */
- if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 50)) {
+ if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 10000)) {
dev_warn(hsotg->dev, "%s: HANG! AHB Idle timeout GRSTCTL GRSTCTL_AHBIDLE\n",
__func__);
return -EBUSY;
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index 152ac41dfb2d..d08d070a0fb6 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -861,6 +861,9 @@ struct dwc2_hregs_backup {
* @hibernated: True if core is hibernated
* @reset_phy_on_wake: Quirk saying that we should assert PHY reset on a
* remote wakeup.
+ * @phy_off_for_suspend: Status of whether we turned the PHY off at suspend.
+ * @need_phy_for_wake: Quirk saying that we should keep the PHY on at
+ * suspend if we need USB to wake us up.
* @frame_number: Frame number read from the core. For both device
* and host modes. The value ranges are from 0
* to HFNUM_MAX_FRNUM.
@@ -1049,6 +1052,8 @@ struct dwc2_hsotg {
unsigned int ll_hw_enabled:1;
unsigned int hibernated:1;
unsigned int reset_phy_on_wake:1;
+ unsigned int need_phy_for_wake:1;
+ unsigned int phy_off_for_suspend:1;
u16 frame_number;
struct phy *phy;
@@ -1438,6 +1443,7 @@ int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg);
int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg);
int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg,
int rem_wakeup, int reset);
+bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2);
static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg)
{ schedule_work(&hsotg->phy_reset_work); }
#else
@@ -1463,6 +1469,8 @@ static inline int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg)
static inline int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg,
int rem_wakeup, int reset)
{ return 0; }
+static inline bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2)
+{ return false; }
static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg) {}
#endif
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 2192a2873c7c..ee144ff8af5b 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -4685,7 +4685,6 @@ fail2:
spin_unlock_irqrestore(&hsotg->lock, flags);
urb->hcpriv = NULL;
kfree(qtd);
- qtd = NULL;
fail1:
if (qh_allocated) {
struct dwc2_qtd *qtd2, *qtd2_tmp;
@@ -5587,3 +5586,22 @@ int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup,
dev_dbg(hsotg->dev, "Host hibernation restore complete\n");
return ret;
}
+
+bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2)
+{
+ struct usb_device *root_hub = dwc2_hsotg_to_hcd(dwc2)->self.root_hub;
+
+ /* If the controller isn't allowed to wakeup then we can power off. */
+ if (!device_may_wakeup(dwc2->dev))
+ return true;
+
+ /*
+ * We don't want to power off the PHY if something under the
+ * root hub has wakeup enabled.
+ */
+ if (usb_wakeup_enabled_descendants(root_hub))
+ return false;
+
+ /* No reason to keep the PHY powered, so allow poweroff */
+ return true;
+}
diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h
index ce6445a06588..8ca6d12a6f57 100644
--- a/drivers/usb/dwc2/hcd.h
+++ b/drivers/usb/dwc2/hcd.h
@@ -582,7 +582,6 @@ static inline void dwc2_hcd_qtd_unlink_and_free(struct dwc2_hsotg *hsotg,
{
list_del(&qtd->qtd_list_entry);
kfree(qtd);
- qtd = NULL;
}
/* Descriptor DMA support functions */
diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c
index 6900eea57526..55f841a54015 100644
--- a/drivers/usb/dwc2/params.c
+++ b/drivers/usb/dwc2/params.c
@@ -76,6 +76,7 @@ static void dwc2_set_s3c6400_params(struct dwc2_hsotg *hsotg)
struct dwc2_core_params *p = &hsotg->params;
p->power_down = 0;
+ p->phy_utmi_width = 8;
}
static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg)
@@ -253,6 +254,15 @@ static void dwc2_set_param_phy_utmi_width(struct dwc2_hsotg *hsotg)
val = (hsotg->hw_params.utmi_phy_data_width ==
GHWCFG4_UTMI_PHY_DATA_WIDTH_8) ? 8 : 16;
+ if (hsotg->phy) {
+ /*
+ * If using the generic PHY framework, check if the PHY bus
+ * width is 8-bit and set the phyif appropriately.
+ */
+ if (phy_get_bus_width(hsotg->phy) == 8)
+ val = 8;
+ }
+
hsotg->params.phy_utmi_width = val;
}
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index d10a7f8daec3..80fd3c6dcd1c 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -271,15 +271,6 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
hsotg->plat = dev_get_platdata(hsotg->dev);
- if (hsotg->phy) {
- /*
- * If using the generic PHY framework, check if the PHY bus
- * width is 8-bit and set the phyif appropriately.
- */
- if (phy_get_bus_width(hsotg->phy) == 8)
- hsotg->params.phy_utmi_width = 8;
- }
-
/* Clock */
hsotg->clk = devm_clk_get_optional(hsotg->dev, "otg");
if (IS_ERR(hsotg->clk)) {
@@ -447,6 +438,10 @@ static int dwc2_driver_probe(struct platform_device *dev)
if (retval)
goto error;
+ hsotg->need_phy_for_wake =
+ of_property_read_bool(dev->dev.of_node,
+ "snps,need-phy-for-wake");
+
/*
* Reset before dwc2_get_hwparams() then it could get power-on real
* reset value form registers.
@@ -478,6 +473,14 @@ static int dwc2_driver_probe(struct platform_device *dev)
hsotg->gadget_enabled = 1;
}
+ /*
+ * If we need PHY for wakeup we must be wakeup capable.
+ * When we have a device that can wake without the PHY we
+ * can adjust this condition.
+ */
+ if (hsotg->need_phy_for_wake)
+ device_set_wakeup_capable(&dev->dev, true);
+
hsotg->reset_phy_on_wake =
of_property_read_bool(dev->dev.of_node,
"snps,reset-phy-on-wake");
@@ -516,13 +519,17 @@ error:
static int __maybe_unused dwc2_suspend(struct device *dev)
{
struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
+ bool is_device_mode = dwc2_is_device_mode(dwc2);
int ret = 0;
- if (dwc2_is_device_mode(dwc2))
+ if (is_device_mode)
dwc2_hsotg_suspend(dwc2);
- if (dwc2->ll_hw_enabled)
+ if (dwc2->ll_hw_enabled &&
+ (is_device_mode || dwc2_host_can_poweroff_phy(dwc2))) {
ret = __dwc2_lowlevel_hw_disable(dwc2);
+ dwc2->phy_off_for_suspend = true;
+ }
return ret;
}
@@ -532,11 +539,12 @@ static int __maybe_unused dwc2_resume(struct device *dev)
struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
int ret = 0;
- if (dwc2->ll_hw_enabled) {
+ if (dwc2->phy_off_for_suspend && dwc2->ll_hw_enabled) {
ret = __dwc2_lowlevel_hw_enable(dwc2);
if (ret)
return ret;
}
+ dwc2->phy_off_for_suspend = false;
if (dwc2_is_device_mode(dwc2))
ret = dwc2_hsotg_resume(dwc2);
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index 4a62045cc812..89abc6078703 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -128,7 +128,7 @@ config USB_DWC3_QCOM
tristate "Qualcomm Platform"
depends on ARCH_QCOM || COMPILE_TEST
depends on EXTCON || !EXTCON
- depends on OF
+ depends on (OF || ACPI)
default USB_DWC3
help
Some Qualcomm SoCs use DesignWare Core IP for USB2/3
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 4aff1d8dbc4f..c9bb93a2c81e 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -1282,6 +1282,10 @@ static void dwc3_get_properties(struct dwc3 *dwc)
"snps,dis_u2_susphy_quirk");
dwc->dis_enblslpm_quirk = device_property_read_bool(dev,
"snps,dis_enblslpm_quirk");
+ dwc->dis_u1_entry_quirk = device_property_read_bool(dev,
+ "snps,dis-u1-entry-quirk");
+ dwc->dis_u2_entry_quirk = device_property_read_bool(dev,
+ "snps,dis-u2-entry-quirk");
dwc->dis_rxdet_inp3_quirk = device_property_read_bool(dev,
"snps,dis_rxdet_inp3_quirk");
dwc->dis_u2_freeclk_exists_quirk = device_property_read_bool(dev,
@@ -1423,11 +1427,6 @@ static int dwc3_probe(struct platform_device *pdev)
dwc->regs = regs;
dwc->regs_size = resource_size(&dwc_res);
- if (!dwc3_core_is_valid(dwc)) {
- dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
- return -ENODEV;
- }
-
dwc3_get_properties(dwc);
dwc->reset = devm_reset_control_get_optional_shared(dev, NULL);
@@ -1460,6 +1459,12 @@ static int dwc3_probe(struct platform_device *pdev)
if (ret)
goto unprepare_clks;
+ if (!dwc3_core_is_valid(dwc)) {
+ dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
+ ret = -ENODEV;
+ goto disable_clks;
+ }
+
platform_set_drvdata(pdev, dwc);
dwc3_cache_hwparams(dwc);
@@ -1525,6 +1530,7 @@ err1:
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
+disable_clks:
clk_bulk_disable(dwc->num_clks, dwc->clks);
unprepare_clks:
clk_bulk_unprepare(dwc->num_clks, dwc->clks);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index f19cbeb01087..3dd783b889cb 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -649,7 +649,6 @@ struct dwc3_event_buffer {
* @cancelled_list: list of cancelled requests for this endpoint
* @pending_list: list of pending requests for this endpoint
* @started_list: list of started requests on this endpoint
- * @lock: spinlock for endpoint request queue traversal
* @regs: pointer to first endpoint register
* @trb_pool: array of transaction buffers
* @trb_pool_dma: dma address of @trb_pool
@@ -677,7 +676,6 @@ struct dwc3_ep {
struct list_head pending_list;
struct list_head started_list;
- spinlock_t lock;
void __iomem *regs;
struct dwc3_trb *trb_pool;
@@ -1014,6 +1012,8 @@ struct dwc3_scratchpad_array {
* @dis_u2_susphy_quirk: set if we disable usb2 suspend phy
* @dis_enblslpm_quirk: set if we clear enblslpm in GUSB2PHYCFG,
* disabling the suspend signal to the PHY.
+ * @dis_u1_entry_quirk: set if link entering into U1 state needs to be disabled.
+ * @dis_u2_entry_quirk: set if link entering into U2 state needs to be disabled.
* @dis_rxdet_inp3_quirk: set if we disable Rx.Detect in P3
* @dis_u2_freeclk_exists_quirk : set if we clear u2_freeclk_exists
* in GUSB2PHYCFG, specify that USB2 PHY doesn't
@@ -1205,6 +1205,8 @@ struct dwc3 {
unsigned dis_u3_susphy_quirk:1;
unsigned dis_u2_susphy_quirk:1;
unsigned dis_enblslpm_quirk:1;
+ unsigned dis_u1_entry_quirk:1;
+ unsigned dis_u2_entry_quirk:1;
unsigned dis_rxdet_inp3_quirk:1;
unsigned dis_u2_freeclk_exists_quirk:1;
unsigned dis_del_phy_power_chg_quirk:1;
diff --git a/drivers/usb/dwc3/dwc3-meson-g12a.c b/drivers/usb/dwc3/dwc3-meson-g12a.c
index 2aec31a2eacb..bca7e92a10e9 100644
--- a/drivers/usb/dwc3/dwc3-meson-g12a.c
+++ b/drivers/usb/dwc3/dwc3-meson-g12a.c
@@ -11,9 +11,7 @@
* - Control registers for each USB2 Ports
* - Control registers for the USB PHY layer
* - SuperSpeed PHY can be enabled only if port is used
- *
- * TOFIX:
- * - Add dynamic OTG switching with ID change interrupt
+ * - Dynamic OTG switching with ID change interrupt
*/
#include <linux/module.h>
@@ -348,6 +346,22 @@ static enum usb_role dwc3_meson_g12a_role_get(struct device *dev)
USB_ROLE_HOST : USB_ROLE_DEVICE;
}
+static irqreturn_t dwc3_meson_g12a_irq_thread(int irq, void *data)
+{
+ struct dwc3_meson_g12a *priv = data;
+ enum phy_mode otg_id;
+
+ otg_id = dwc3_meson_g12a_get_id(priv);
+ if (otg_id != priv->otg_phy_mode) {
+ if (dwc3_meson_g12a_otg_mode_set(priv, otg_id))
+ dev_warn(priv->dev, "Failed to switch OTG mode\n");
+ }
+
+ regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_IRQ, 0);
+
+ return IRQ_HANDLED;
+}
+
static struct device *dwc3_meson_g12_find_child(struct device *dev,
const char *compatible)
{
@@ -374,7 +388,7 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev)
void __iomem *base;
struct resource *res;
enum phy_mode otg_id;
- int ret, i;
+ int ret, i, irq;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -436,6 +450,19 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev)
/* Get dr_mode */
priv->otg_mode = usb_get_dr_mode(dev);
+ if (priv->otg_mode == USB_DR_MODE_OTG) {
+ /* Ack irq before registering */
+ regmap_update_bits(priv->regmap, USB_R5,
+ USB_R5_ID_DIG_IRQ, 0);
+
+ irq = platform_get_irq(pdev, 0);
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ dwc3_meson_g12a_irq_thread,
+ IRQF_ONESHOT, pdev->name, priv);
+ if (ret)
+ return ret;
+ }
+
dwc3_meson_g12a_usb_init(priv);
/* Init PHYs */
@@ -460,7 +487,6 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev)
/* Setup OTG mode corresponding to the ID pin */
if (priv->otg_mode == USB_DR_MODE_OTG) {
- /* TOFIX Handle ID mode toggling via IRQ */
otg_id = dwc3_meson_g12a_get_id(priv);
if (otg_id != priv->otg_phy_mode) {
if (dwc3_meson_g12a_otg_mode_set(priv, otg_id))
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index 8cced3609e24..5e8e18222f92 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -34,6 +34,8 @@
#define PCI_DEVICE_ID_INTEL_CNPLP 0x9dee
#define PCI_DEVICE_ID_INTEL_CNPH 0xa36e
#define PCI_DEVICE_ID_INTEL_ICLLP 0x34ee
+#define PCI_DEVICE_ID_INTEL_EHLLP 0x4b7e
+#define PCI_DEVICE_ID_INTEL_TGPLP 0xa0ee
#define PCI_INTEL_BXT_DSM_GUID "732b85d5-b7a7-4a1b-9ba0-4bbd00ffd511"
#define PCI_INTEL_BXT_FUNC_PMU_PWR 4
@@ -339,6 +341,12 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICLLP),
(kernel_ulong_t) &dwc3_pci_intel_properties, },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_EHLLP),
+ (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGPLP),
+ (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_NL_USB),
(kernel_ulong_t) &dwc3_pci_amd_properties, },
{ } /* Terminating Entry */
diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c
index 184df4daa590..261af9e38ddd 100644
--- a/drivers/usb/dwc3/dwc3-qcom.c
+++ b/drivers/usb/dwc3/dwc3-qcom.c
@@ -4,6 +4,7 @@
* Inspired by dwc3-of-simple.c
*/
+#include <linux/acpi.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/clk.h>
@@ -38,6 +39,20 @@
#define PWR_EVNT_LPM_IN_L2_MASK BIT(4)
#define PWR_EVNT_LPM_OUT_L2_MASK BIT(5)
+#define SDM845_QSCRATCH_BASE_OFFSET 0xf8800
+#define SDM845_QSCRATCH_SIZE 0x400
+#define SDM845_DWC3_CORE_SIZE 0xcd00
+
+struct dwc3_acpi_pdata {
+ u32 qscratch_base_offset;
+ u32 qscratch_base_size;
+ u32 dwc3_core_base_size;
+ int hs_phy_irq_index;
+ int dp_hs_phy_irq_index;
+ int dm_hs_phy_irq_index;
+ int ss_phy_irq_index;
+};
+
struct dwc3_qcom {
struct device *dev;
void __iomem *qscratch_base;
@@ -56,6 +71,8 @@ struct dwc3_qcom {
struct notifier_block vbus_nb;
struct notifier_block host_nb;
+ const struct dwc3_acpi_pdata *acpi_pdata;
+
enum usb_dr_mode mode;
bool is_suspended;
bool pm_suspended;
@@ -300,12 +317,27 @@ static void dwc3_qcom_select_utmi_clk(struct dwc3_qcom *qcom)
PIPE_UTMI_CLK_DIS);
}
+static int dwc3_qcom_get_irq(struct platform_device *pdev,
+ const char *name, int num)
+{
+ struct device_node *np = pdev->dev.of_node;
+ int ret;
+
+ if (np)
+ ret = platform_get_irq_byname(pdev, name);
+ else
+ ret = platform_get_irq(pdev, num);
+
+ return ret;
+}
+
static int dwc3_qcom_setup_irq(struct platform_device *pdev)
{
struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
+ const struct dwc3_acpi_pdata *pdata = qcom->acpi_pdata;
int irq, ret;
-
- irq = platform_get_irq_byname(pdev, "hs_phy_irq");
+ irq = dwc3_qcom_get_irq(pdev, "hs_phy_irq",
+ pdata ? pdata->hs_phy_irq_index : -1);
if (irq > 0) {
/* Keep wakeup interrupts disabled until suspend */
irq_set_status_flags(irq, IRQ_NOAUTOEN);
@@ -320,7 +352,8 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev)
qcom->hs_phy_irq = irq;
}
- irq = platform_get_irq_byname(pdev, "dp_hs_phy_irq");
+ irq = dwc3_qcom_get_irq(pdev, "dp_hs_phy_irq",
+ pdata ? pdata->dp_hs_phy_irq_index : -1);
if (irq > 0) {
irq_set_status_flags(irq, IRQ_NOAUTOEN);
ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
@@ -334,7 +367,8 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev)
qcom->dp_hs_phy_irq = irq;
}
- irq = platform_get_irq_byname(pdev, "dm_hs_phy_irq");
+ irq = dwc3_qcom_get_irq(pdev, "dm_hs_phy_irq",
+ pdata ? pdata->dm_hs_phy_irq_index : -1);
if (irq > 0) {
irq_set_status_flags(irq, IRQ_NOAUTOEN);
ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
@@ -348,7 +382,8 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev)
qcom->dm_hs_phy_irq = irq;
}
- irq = platform_get_irq_byname(pdev, "ss_phy_irq");
+ irq = dwc3_qcom_get_irq(pdev, "ss_phy_irq",
+ pdata ? pdata->ss_phy_irq_index : -1);
if (irq > 0) {
irq_set_status_flags(irq, IRQ_NOAUTOEN);
ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
@@ -371,11 +406,14 @@ static int dwc3_qcom_clk_init(struct dwc3_qcom *qcom, int count)
struct device_node *np = dev->of_node;
int i;
- qcom->num_clocks = count;
-
- if (!count)
+ if (!np || !count)
return 0;
+ if (count < 0)
+ return count;
+
+ qcom->num_clocks = count;
+
qcom->clks = devm_kcalloc(dev, qcom->num_clocks,
sizeof(struct clk *), GFP_KERNEL);
if (!qcom->clks)
@@ -409,12 +447,115 @@ static int dwc3_qcom_clk_init(struct dwc3_qcom *qcom, int count)
return 0;
}
-static int dwc3_qcom_probe(struct platform_device *pdev)
+static const struct property_entry dwc3_qcom_acpi_properties[] = {
+ PROPERTY_ENTRY_STRING("dr_mode", "host"),
+ {}
+};
+
+static int dwc3_qcom_acpi_register_core(struct platform_device *pdev)
+{
+ struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
+ struct device *dev = &pdev->dev;
+ struct resource *res, *child_res = NULL;
+ int irq;
+ int ret;
+
+ qcom->dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
+ if (!qcom->dwc3)
+ return -ENOMEM;
+
+ qcom->dwc3->dev.parent = dev;
+ qcom->dwc3->dev.type = dev->type;
+ qcom->dwc3->dev.dma_mask = dev->dma_mask;
+ qcom->dwc3->dev.dma_parms = dev->dma_parms;
+ qcom->dwc3->dev.coherent_dma_mask = dev->coherent_dma_mask;
+
+ child_res = kcalloc(2, sizeof(*child_res), GFP_KERNEL);
+ if (!child_res)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to get memory resource\n");
+ ret = -ENODEV;
+ goto out;
+ }
+
+ child_res[0].flags = res->flags;
+ child_res[0].start = res->start;
+ child_res[0].end = child_res[0].start +
+ qcom->acpi_pdata->dwc3_core_base_size;
+
+ irq = platform_get_irq(pdev, 0);
+ child_res[1].flags = IORESOURCE_IRQ;
+ child_res[1].start = child_res[1].end = irq;
+
+ ret = platform_device_add_resources(qcom->dwc3, child_res, 2);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add resources\n");
+ goto out;
+ }
+
+ ret = platform_device_add_properties(qcom->dwc3,
+ dwc3_qcom_acpi_properties);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to add properties\n");
+ goto out;
+ }
+
+ ret = platform_device_add(qcom->dwc3);
+ if (ret)
+ dev_err(&pdev->dev, "failed to add device\n");
+
+out:
+ kfree(child_res);
+ return ret;
+}
+
+static int dwc3_qcom_of_register_core(struct platform_device *pdev)
{
+ struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
struct device_node *np = pdev->dev.of_node, *dwc3_np;
struct device *dev = &pdev->dev;
+ int ret;
+
+ dwc3_np = of_get_child_by_name(np, "dwc3");
+ if (!dwc3_np) {
+ dev_err(dev, "failed to find dwc3 core child\n");
+ return -ENODEV;
+ }
+
+ ret = of_platform_populate(np, NULL, NULL, dev);
+ if (ret) {
+ dev_err(dev, "failed to register dwc3 core - %d\n", ret);
+ return ret;
+ }
+
+ qcom->dwc3 = of_find_device_by_node(dwc3_np);
+ if (!qcom->dwc3) {
+ dev_err(dev, "failed to get dwc3 platform device\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static const struct dwc3_acpi_pdata sdm845_acpi_pdata = {
+ .qscratch_base_offset = SDM845_QSCRATCH_BASE_OFFSET,
+ .qscratch_base_size = SDM845_QSCRATCH_SIZE,
+ .dwc3_core_base_size = SDM845_DWC3_CORE_SIZE,
+ .hs_phy_irq_index = 1,
+ .dp_hs_phy_irq_index = 4,
+ .dm_hs_phy_irq_index = 3,
+ .ss_phy_irq_index = 2
+};
+
+static int dwc3_qcom_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
struct dwc3_qcom *qcom;
- struct resource *res;
+ struct resource *res, *parent_res = NULL;
int ret, i;
bool ignore_pipe_clk;
@@ -425,6 +566,14 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, qcom);
qcom->dev = &pdev->dev;
+ if (has_acpi_companion(dev)) {
+ qcom->acpi_pdata = acpi_device_get_match_data(dev);
+ if (!qcom->acpi_pdata) {
+ dev_err(&pdev->dev, "no supporting ACPI device data\n");
+ return -EINVAL;
+ }
+ }
+
qcom->resets = devm_reset_control_array_get_optional_exclusive(dev);
if (IS_ERR(qcom->resets)) {
ret = PTR_ERR(qcom->resets);
@@ -446,15 +595,28 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
goto reset_assert;
}
- ret = dwc3_qcom_clk_init(qcom, of_count_phandle_with_args(np,
- "clocks", "#clock-cells"));
+ ret = dwc3_qcom_clk_init(qcom, of_clk_get_parent_count(np));
if (ret) {
dev_err(dev, "failed to get clocks\n");
goto reset_assert;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- qcom->qscratch_base = devm_ioremap_resource(dev, res);
+
+ if (np) {
+ parent_res = res;
+ } else {
+ parent_res = kmemdup(res, sizeof(struct resource), GFP_KERNEL);
+ if (!parent_res)
+ return -ENOMEM;
+
+ parent_res->start = res->start +
+ qcom->acpi_pdata->qscratch_base_offset;
+ parent_res->end = parent_res->start +
+ qcom->acpi_pdata->qscratch_base_size;
+ }
+
+ qcom->qscratch_base = devm_ioremap_resource(dev, parent_res);
if (IS_ERR(qcom->qscratch_base)) {
dev_err(dev, "failed to map qscratch, err=%d\n", ret);
ret = PTR_ERR(qcom->qscratch_base);
@@ -462,13 +624,8 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
}
ret = dwc3_qcom_setup_irq(pdev);
- if (ret)
- goto clk_disable;
-
- dwc3_np = of_get_child_by_name(np, "dwc3");
- if (!dwc3_np) {
- dev_err(dev, "failed to find dwc3 core child\n");
- ret = -ENODEV;
+ if (ret) {
+ dev_err(dev, "failed to setup IRQs, err=%d\n", ret);
goto clk_disable;
}
@@ -481,16 +638,13 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
if (ignore_pipe_clk)
dwc3_qcom_select_utmi_clk(qcom);
- ret = of_platform_populate(np, NULL, NULL, dev);
- if (ret) {
- dev_err(dev, "failed to register dwc3 core - %d\n", ret);
- goto clk_disable;
- }
+ if (np)
+ ret = dwc3_qcom_of_register_core(pdev);
+ else
+ ret = dwc3_qcom_acpi_register_core(pdev);
- qcom->dwc3 = of_find_device_by_node(dwc3_np);
- if (!qcom->dwc3) {
- dev_err(&pdev->dev, "failed to get dwc3 platform device\n");
- ret = -ENODEV;
+ if (ret) {
+ dev_err(dev, "failed to register DWC3 Core, err=%d\n", ret);
goto depopulate;
}
@@ -514,7 +668,10 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
return 0;
depopulate:
- of_platform_depopulate(&pdev->dev);
+ if (np)
+ of_platform_depopulate(&pdev->dev);
+ else
+ platform_device_put(pdev);
clk_disable:
for (i = qcom->num_clocks - 1; i >= 0; i--) {
clk_disable_unprepare(qcom->clks[i]);
@@ -601,6 +758,12 @@ static const struct of_device_id dwc3_qcom_of_match[] = {
};
MODULE_DEVICE_TABLE(of, dwc3_qcom_of_match);
+static const struct acpi_device_id dwc3_qcom_acpi_match[] = {
+ { "QCOM2430", (unsigned long)&sdm845_acpi_pdata },
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, dwc3_qcom_acpi_match);
+
static struct platform_driver dwc3_qcom_driver = {
.probe = dwc3_qcom_probe,
.remove = dwc3_qcom_remove,
@@ -608,6 +771,7 @@ static struct platform_driver dwc3_qcom_driver = {
.name = "dwc3-qcom",
.pm = &dwc3_qcom_dev_pm_ops,
.of_match_table = dwc3_qcom_of_match,
+ .acpi_match_table = ACPI_PTR(dwc3_qcom_acpi_match),
},
};
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 8efde178eef4..3996b9c4ff8d 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -379,6 +379,8 @@ static int dwc3_ep0_handle_u1(struct dwc3 *dwc, enum usb_device_state state,
if ((dwc->speed != DWC3_DSTS_SUPERSPEED) &&
(dwc->speed != DWC3_DSTS_SUPERSPEED_PLUS))
return -EINVAL;
+ if (set && dwc->dis_u1_entry_quirk)
+ return -EINVAL;
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
if (set)
@@ -401,6 +403,8 @@ static int dwc3_ep0_handle_u2(struct dwc3 *dwc, enum usb_device_state state,
if ((dwc->speed != DWC3_DSTS_SUPERSPEED) &&
(dwc->speed != DWC3_DSTS_SUPERSPEED_PLUS))
return -EINVAL;
+ if (set && dwc->dis_u2_entry_quirk)
+ return -EINVAL;
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
if (set)
@@ -626,7 +630,10 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
* nothing is pending from application.
*/
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
- reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA);
+ if (!dwc->dis_u1_entry_quirk)
+ reg |= DWC3_DCTL_ACCEPTU1ENA;
+ if (!dwc->dis_u2_entry_quirk)
+ reg |= DWC3_DCTL_ACCEPTU2ENA;
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
}
break;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index d67655384eb2..173f5329d3d9 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2073,6 +2073,25 @@ out:
return 0;
}
+static void dwc3_gadget_config_params(struct usb_gadget *g,
+ struct usb_dcd_config_params *params)
+{
+ struct dwc3 *dwc = gadget_to_dwc(g);
+
+ /* U1 Device exit Latency */
+ if (dwc->dis_u1_entry_quirk)
+ params->bU1devExitLat = 0;
+ else
+ params->bU1devExitLat = DWC3_DEFAULT_U1_DEV_EXIT_LAT;
+
+ /* U2 Device exit Latency */
+ if (dwc->dis_u2_entry_quirk)
+ params->bU2DevExitLat = 0;
+ else
+ params->bU2DevExitLat =
+ cpu_to_le16(DWC3_DEFAULT_U2_DEV_EXIT_LAT);
+}
+
static void dwc3_gadget_set_speed(struct usb_gadget *g,
enum usb_device_speed speed)
{
@@ -2142,6 +2161,7 @@ static const struct usb_gadget_ops dwc3_gadget_ops = {
.udc_start = dwc3_gadget_start,
.udc_stop = dwc3_gadget_stop,
.udc_set_speed = dwc3_gadget_set_speed,
+ .get_config_params = dwc3_gadget_config_params,
};
/* -------------------------------------------------------------------------- */
@@ -2251,8 +2271,6 @@ static int dwc3_gadget_init_endpoint(struct dwc3 *dwc, u8 epnum)
dep->endpoint.comp_desc = NULL;
}
- spin_lock_init(&dep->lock);
-
if (num == 0)
ret = dwc3_gadget_init_control_endpoint(dep);
else if (direction)
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
index 3ed738e86ea7..5faf4d1249e0 100644
--- a/drivers/usb/dwc3/gadget.h
+++ b/drivers/usb/dwc3/gadget.h
@@ -48,6 +48,12 @@ struct dwc3;
/* DEPXFERCFG parameter 0 */
#define DWC3_DEPXFERCFG_NUM_XFER_RES(n) ((n) & 0xffff)
+/* U1 Device exit Latency */
+#define DWC3_DEFAULT_U1_DEV_EXIT_LAT 0x0A /* Less then 10 microsec */
+
+/* U2 Device exit Latency */
+#define DWC3_DEFAULT_U2_DEV_EXIT_LAT 0x1FF /* Less then 511 microsec */
+
/* -------------------------------------------------------------------------- */
#define to_dwc3_request(r) (container_of(r, struct dwc3_request, request))
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index ec189d7855a0..02ff850278b1 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -228,7 +228,7 @@ config USB_CONFIGFS
specified simply by creating appropriate directories in configfs.
Associating functions with configurations is done by creating
appropriate symbolic links.
- For more information see Documentation/usb/gadget_configfs.txt.
+ For more information see Documentation/usb/gadget_configfs.rst.
config USB_CONFIGFS_SERIAL
bool "Generic serial bulk in/out"
@@ -441,7 +441,7 @@ config USB_CONFIGFS_F_HID
The HID function driver provides generic emulation of USB
Human Interface Devices (HID).
- For more information, see Documentation/usb/gadget_hid.txt.
+ For more information, see Documentation/usb/gadget_hid.rst.
config USB_CONFIGFS_F_UVC
bool "USB Webcam function"
@@ -466,7 +466,7 @@ config USB_CONFIGFS_F_PRINTER
receive or send printer data. It can use ioctl calls to
the device file to get or set printer status.
- For more information, see Documentation/usb/gadget_printer.txt
+ For more information, see Documentation/usb/gadget_printer.rst
which includes sample code for accessing the device file.
config USB_CONFIGFS_F_TCM
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index b8a15840b4ff..9118b42c70b6 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -653,7 +653,7 @@ static int bos_desc(struct usb_composite_dev *cdev)
/* Get Controller configuration */
if (cdev->gadget->ops->get_config_params) {
- cdev->gadget->ops->get_config_params(
+ cdev->gadget->ops->get_config_params(cdev->gadget,
&dcd_config_params);
} else {
dcd_config_params.bU1devExitLat =
diff --git a/drivers/usb/gadget/function/f_eem.c b/drivers/usb/gadget/function/f_eem.c
index c13befa31110..b81a91d504bd 100644
--- a/drivers/usb/gadget/function/f_eem.c
+++ b/drivers/usb/gadget/function/f_eem.c
@@ -166,7 +166,6 @@ static struct usb_gadget_strings *eem_strings[] = {
static int eem_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
{
struct usb_composite_dev *cdev = f->config->cdev;
- int value = -EOPNOTSUPP;
u16 w_index = le16_to_cpu(ctrl->wIndex);
u16 w_value = le16_to_cpu(ctrl->wValue);
u16 w_length = le16_to_cpu(ctrl->wLength);
@@ -176,7 +175,7 @@ static int eem_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
w_value, w_index, w_length);
/* device either stalls (value < 0) or reports success */
- return value;
+ return -EOPNOTSUPP;
}
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 47be961f1bf3..213ff03c8a9f 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -997,7 +997,6 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
* earlier
*/
gadget = epfile->ffs->gadget;
- io_data->use_sg = gadget->sg_supported && data_len > PAGE_SIZE;
spin_lock_irq(&epfile->ffs->eps_lock);
/* In the meantime, endpoint got disabled or changed. */
@@ -1012,6 +1011,8 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
*/
if (io_data->read)
data_len = usb_ep_align_maybe(gadget, ep->ep, data_len);
+
+ io_data->use_sg = gadget->sg_supported && data_len > PAGE_SIZE;
spin_unlock_irq(&epfile->ffs->eps_lock);
data = ffs_alloc_buffer(io_data, data_len);
@@ -1182,11 +1183,12 @@ static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from)
ENTER();
if (!is_sync_kiocb(kiocb)) {
- p = kmalloc(sizeof(io_data), GFP_KERNEL);
+ p = kzalloc(sizeof(io_data), GFP_KERNEL);
if (unlikely(!p))
return -ENOMEM;
p->aio = true;
} else {
+ memset(p, 0, sizeof(*p));
p->aio = false;
}
@@ -1218,11 +1220,12 @@ static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to)
ENTER();
if (!is_sync_kiocb(kiocb)) {
- p = kmalloc(sizeof(io_data), GFP_KERNEL);
+ p = kzalloc(sizeof(io_data), GFP_KERNEL);
if (unlikely(!p))
return -ENOMEM;
p->aio = true;
} else {
+ memset(p, 0, sizeof(*p));
p->aio = false;
}
diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c
index 043f97ad8f22..29cc5693e05c 100644
--- a/drivers/usb/gadget/function/f_mass_storage.c
+++ b/drivers/usb/gadget/function/f_mass_storage.c
@@ -47,7 +47,7 @@
*
* For more information about MSF and in particular its module
* parameters and sysfs interface read the
- * <Documentation/usb/mass-storage.txt> file.
+ * <Documentation/usb/mass-storage.rst> file.
*/
/*
diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index 8c99392df593..fb0a892687c0 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -423,6 +423,7 @@ uvc_register_video(struct uvc_device *uvc)
uvc->vdev.release = video_device_release_empty;
uvc->vdev.vfl_dir = VFL_DIR_TX;
uvc->vdev.lock = &uvc->video.mutex;
+ uvc->vdev.device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
strlcpy(uvc->vdev.name, cdev->gadget->name, sizeof(uvc->vdev.name));
video_set_drvdata(&uvc->vdev, uvc);
diff --git a/drivers/usb/gadget/function/u_audio.c b/drivers/usb/gadget/function/u_audio.c
index fb5ed97572e5..56906d15fb55 100644
--- a/drivers/usb/gadget/function/u_audio.c
+++ b/drivers/usb/gadget/function/u_audio.c
@@ -40,7 +40,7 @@ struct uac_rtd_params {
void *rbuf;
- unsigned max_psize; /* MaxPacketSize of endpoint */
+ unsigned int max_psize; /* MaxPacketSize of endpoint */
struct uac_req *ureq;
spinlock_t lock;
@@ -78,7 +78,7 @@ static const struct snd_pcm_hardware uac_pcm_hardware = {
static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req)
{
- unsigned pending;
+ unsigned int pending;
unsigned long flags, flags2;
unsigned int hw_ptr;
int status = req->status;
diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
index 737bd77a575d..fbe96ef1ac7a 100644
--- a/drivers/usb/gadget/function/u_ether.c
+++ b/drivers/usb/gadget/function/u_ether.c
@@ -186,11 +186,12 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
out = dev->port_usb->out_ep;
else
out = NULL;
- spin_unlock_irqrestore(&dev->lock, flags);
if (!out)
+ {
+ spin_unlock_irqrestore(&dev->lock, flags);
return -ENOTCONN;
-
+ }
/* Padding up to RX_EXTRA handles minor disagreements with host.
* Normally we use the USB "terminate on short read" convention;
@@ -214,6 +215,7 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
if (dev->port_usb->is_fixed)
size = max_t(size_t, size, dev->port_usb->fixed_out_len);
+ spin_unlock_irqrestore(&dev->lock, flags);
skb = __netdev_alloc_skb(dev->net, size + NET_IP_ALIGN, gfp_flags);
if (skb == NULL) {
@@ -1004,9 +1006,9 @@ int gether_get_ifname(struct net_device *net, char *name, int len)
int ret;
rtnl_lock();
- ret = snprintf(name, len, "%s\n", netdev_name(net));
+ ret = scnprintf(name, len, "%s\n", netdev_name(net));
rtnl_unlock();
- return ret < len ? ret : len;
+ return ret;
}
EXPORT_SYMBOL_GPL(gether_get_ifname);
diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c
index a1183eccee22..495f0ec663ea 100644
--- a/drivers/usb/gadget/function/uvc_v4l2.c
+++ b/drivers/usb/gadget/function/uvc_v4l2.c
@@ -71,10 +71,6 @@ uvc_v4l2_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
strlcpy(cap->card, cdev->gadget->name, sizeof(cap->card));
strlcpy(cap->bus_info, dev_name(&cdev->gadget->dev),
sizeof(cap->bus_info));
-
- cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
-
return 0;
}
diff --git a/drivers/usb/gadget/legacy/Kconfig b/drivers/usb/gadget/legacy/Kconfig
index d7c9e4fca895..69ff7f8c86f5 100644
--- a/drivers/usb/gadget/legacy/Kconfig
+++ b/drivers/usb/gadget/legacy/Kconfig
@@ -153,7 +153,6 @@ config USB_ETH_EEM
depends on USB_ETH
select USB_LIBCOMPOSITE
select USB_F_EEM
- default n
help
CDC EEM is a newer USB standard that is somewhat simpler than CDC ECM
and therefore can be supported by more hardware. Technically ECM and
@@ -288,7 +287,7 @@ config USB_G_SERIAL
Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "g_serial".
- For more information, see Documentation/usb/gadget_serial.txt
+ For more information, see Documentation/usb/gadget_serial.rst
which includes instructions and a "driver info file" needed to
make MS-Windows work with CDC ACM.
@@ -322,7 +321,7 @@ config USB_G_PRINTER
Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "g_printer".
- For more information, see Documentation/usb/gadget_printer.txt
+ For more information, see Documentation/usb/gadget_printer.rst
which includes sample code for accessing the device file.
if TTY
@@ -419,7 +418,6 @@ config USB_G_MULTI_RNDIS
config USB_G_MULTI_CDC
bool "CDC Ethernet + CDC Serial + Storage configuration"
depends on USB_G_MULTI
- default n
select USB_F_ECM
help
This option enables a configuration with CDC Ethernet (ECM), CDC
@@ -438,7 +436,7 @@ config USB_G_HID
The HID gadget driver provides generic emulation of USB
Human Interface Devices (HID).
- For more information, see Documentation/usb/gadget_hid.txt which
+ For more information, see Documentation/usb/gadget_hid.rst which
includes sample code for accessing the device files.
Say "y" to link the driver statically, or "m" to build a
diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c
index 249277d0e53f..b47938dff1a2 100644
--- a/drivers/usb/gadget/legacy/inode.c
+++ b/drivers/usb/gadget/legacy/inode.c
@@ -12,6 +12,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
+#include <linux/fs_context.h>
#include <linux/pagemap.h>
#include <linux/uts.h>
#include <linux/wait.h>
@@ -1990,7 +1991,7 @@ static const struct super_operations gadget_fs_operations = {
};
static int
-gadgetfs_fill_super (struct super_block *sb, void *opts, int silent)
+gadgetfs_fill_super (struct super_block *sb, struct fs_context *fc)
{
struct inode *inode;
struct dev_data *dev;
@@ -2044,11 +2045,19 @@ Enomem:
}
/* "mount -t gadgetfs path /dev/gadget" ends up here */
-static struct dentry *
-gadgetfs_mount (struct file_system_type *t, int flags,
- const char *path, void *opts)
+static int gadgetfs_get_tree(struct fs_context *fc)
{
- return mount_single (t, flags, opts, gadgetfs_fill_super);
+ return get_tree_single(fc, gadgetfs_fill_super);
+}
+
+static const struct fs_context_operations gadgetfs_context_ops = {
+ .get_tree = gadgetfs_get_tree,
+};
+
+static int gadgetfs_init_fs_context(struct fs_context *fc)
+{
+ fc->ops = &gadgetfs_context_ops;
+ return 0;
}
static void
@@ -2068,7 +2077,7 @@ gadgetfs_kill_sb (struct super_block *sb)
static struct file_system_type gadgetfs_type = {
.owner = THIS_MODULE,
.name = shortname,
- .mount = gadgetfs_mount,
+ .init_fs_context = gadgetfs_init_fs_context,
.kill_sb = gadgetfs_kill_sb,
};
MODULE_ALIAS_FS("gadgetfs");
diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c
index 03959dc86cfd..194ffb1ed462 100644
--- a/drivers/usb/gadget/udc/at91_udc.c
+++ b/drivers/usb/gadget/udc/at91_udc.c
@@ -799,7 +799,6 @@ static int at91_wakeup(struct usb_gadget *gadget)
{
struct at91_udc *udc = to_udc(gadget);
u32 glbstate;
- int status = -EINVAL;
unsigned long flags;
DBG("%s\n", __func__ );
@@ -818,7 +817,7 @@ static int at91_wakeup(struct usb_gadget *gadget)
done:
spin_unlock_irqrestore(&udc->lock, flags);
- return status;
+ return 0;
}
/* reinit == restore initial software state */
diff --git a/drivers/usb/gadget/udc/fotg210-udc.c b/drivers/usb/gadget/udc/fotg210-udc.c
index cec49294bac6..21f3e6c4e4d6 100644
--- a/drivers/usb/gadget/udc/fotg210-udc.c
+++ b/drivers/usb/gadget/udc/fotg210-udc.c
@@ -481,7 +481,6 @@ static int fotg210_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedge)
struct fotg210_ep *ep;
struct fotg210_udc *fotg210;
unsigned long flags;
- int ret = 0;
ep = container_of(_ep, struct fotg210_ep, ep);
@@ -504,7 +503,7 @@ static int fotg210_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedge)
}
spin_unlock_irqrestore(&ep->fotg210->lock, flags);
- return ret;
+ return 0;
}
static int fotg210_ep_set_halt(struct usb_ep *_ep, int value)
diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c
index 564aeee1a1fe..247de0faaeb7 100644
--- a/drivers/usb/gadget/udc/net2272.c
+++ b/drivers/usb/gadget/udc/net2272.c
@@ -1178,11 +1178,6 @@ registers_show(struct device *_dev, struct device_attribute *attr, char *buf)
size = PAGE_SIZE;
spin_lock_irqsave(&dev->lock, flags);
- if (dev->driver)
- s = dev->driver->driver.name;
- else
- s = "(none)";
-
/* Main Control Registers */
t = scnprintf(next, size, "%s version %s,"
"chiprev %02x, locctl %02x\n"
diff --git a/drivers/usb/gadget/udc/omap_udc.c b/drivers/usb/gadget/udc/omap_udc.c
index fcf13ef33b31..f36f0730afab 100644
--- a/drivers/usb/gadget/udc/omap_udc.c
+++ b/drivers/usb/gadget/udc/omap_udc.c
@@ -2103,7 +2103,6 @@ done:
static int omap_udc_stop(struct usb_gadget *g)
{
unsigned long flags;
- int status = -ENODEV;
if (udc->dc_clk != NULL)
omap_udc_enable_clock(1);
@@ -2125,7 +2124,7 @@ static int omap_udc_stop(struct usb_gadget *g)
if (udc->dc_clk != NULL)
omap_udc_enable_clock(0);
- return status;
+ return 0;
}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c
index 7dc248546fd4..87062d22134d 100644
--- a/drivers/usb/gadget/udc/renesas_usb3.c
+++ b/drivers/usb/gadget/udc/renesas_usb3.c
@@ -351,6 +351,8 @@ struct renesas_usb3 {
int disabled_count;
struct usb_request *ep0_req;
+
+ enum usb_role connection_state;
u16 test_mode;
u8 ep0_buf[USB3_EP0_BUF_SIZE];
bool softconnect;
@@ -359,6 +361,7 @@ struct renesas_usb3 {
bool extcon_usb; /* check vbus and set EXTCON_USB */
bool forced_b_device;
bool start_to_connect;
+ bool role_sw_by_connector;
};
#define gadget_to_renesas_usb3(_gadget) \
@@ -699,8 +702,11 @@ static void usb3_mode_config(struct renesas_usb3 *usb3, bool host, bool a_dev)
unsigned long flags;
spin_lock_irqsave(&usb3->lock, flags);
- usb3_set_mode_by_role_sw(usb3, host);
- usb3_vbus_out(usb3, a_dev);
+ if (!usb3->role_sw_by_connector ||
+ usb3->connection_state != USB_ROLE_NONE) {
+ usb3_set_mode_by_role_sw(usb3, host);
+ usb3_vbus_out(usb3, a_dev);
+ }
/* for A-Peripheral or forced B-device mode */
if ((!host && a_dev) || usb3->start_to_connect)
usb3_connect(usb3);
@@ -716,7 +722,8 @@ static void usb3_check_id(struct renesas_usb3 *usb3)
{
usb3->extcon_host = usb3_is_a_device(usb3);
- if (usb3->extcon_host && !usb3->forced_b_device)
+ if ((!usb3->role_sw_by_connector && usb3->extcon_host &&
+ !usb3->forced_b_device) || usb3->connection_state == USB_ROLE_HOST)
usb3_mode_config(usb3, true, true);
else
usb3_mode_config(usb3, false, false);
@@ -1161,7 +1168,7 @@ static void usb3_set_status_stage(struct renesas_usb3_ep *usb3_ep,
static void usb3_p0_xfer(struct renesas_usb3_ep *usb3_ep,
struct renesas_usb3_request *usb3_req)
{
- int ret = -EAGAIN;
+ int ret;
if (usb3_ep->dir_in)
ret = usb3_write_pipe(usb3_ep, usb3_req, USB3_P0_WRITE);
@@ -2343,14 +2350,65 @@ static enum usb_role renesas_usb3_role_switch_get(struct device *dev)
return cur_role;
}
-static int renesas_usb3_role_switch_set(struct device *dev,
- enum usb_role role)
+static void handle_ext_role_switch_states(struct device *dev,
+ enum usb_role role)
+{
+ struct renesas_usb3 *usb3 = dev_get_drvdata(dev);
+ struct device *host = usb3->host_dev;
+ enum usb_role cur_role = renesas_usb3_role_switch_get(dev);
+
+ switch (role) {
+ case USB_ROLE_NONE:
+ usb3->connection_state = USB_ROLE_NONE;
+ if (usb3->driver)
+ usb3_disconnect(usb3);
+ usb3_vbus_out(usb3, false);
+ break;
+ case USB_ROLE_DEVICE:
+ if (usb3->connection_state == USB_ROLE_NONE) {
+ usb3->connection_state = USB_ROLE_DEVICE;
+ usb3_set_mode(usb3, false);
+ if (usb3->driver)
+ usb3_connect(usb3);
+ } else if (cur_role == USB_ROLE_HOST) {
+ device_release_driver(host);
+ usb3_set_mode(usb3, false);
+ if (usb3->driver)
+ usb3_connect(usb3);
+ }
+ usb3_vbus_out(usb3, false);
+ break;
+ case USB_ROLE_HOST:
+ if (usb3->connection_state == USB_ROLE_NONE) {
+ if (usb3->driver)
+ usb3_disconnect(usb3);
+
+ usb3->connection_state = USB_ROLE_HOST;
+ usb3_set_mode(usb3, true);
+ usb3_vbus_out(usb3, true);
+ if (device_attach(host) < 0)
+ dev_err(dev, "device_attach(host) failed\n");
+ } else if (cur_role == USB_ROLE_DEVICE) {
+ usb3_disconnect(usb3);
+ /* Must set the mode before device_attach of the host */
+ usb3_set_mode(usb3, true);
+ /* This device_attach() might sleep */
+ if (device_attach(host) < 0)
+ dev_err(dev, "device_attach(host) failed\n");
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void handle_role_switch_states(struct device *dev,
+ enum usb_role role)
{
struct renesas_usb3 *usb3 = dev_get_drvdata(dev);
struct device *host = usb3->host_dev;
enum usb_role cur_role = renesas_usb3_role_switch_get(dev);
- pm_runtime_get_sync(dev);
if (cur_role == USB_ROLE_HOST && role == USB_ROLE_DEVICE) {
device_release_driver(host);
usb3_set_mode(usb3, false);
@@ -2361,6 +2419,20 @@ static int renesas_usb3_role_switch_set(struct device *dev,
if (device_attach(host) < 0)
dev_err(dev, "device_attach(host) failed\n");
}
+}
+
+static int renesas_usb3_role_switch_set(struct device *dev,
+ enum usb_role role)
+{
+ struct renesas_usb3 *usb3 = dev_get_drvdata(dev);
+
+ pm_runtime_get_sync(dev);
+
+ if (usb3->role_sw_by_connector)
+ handle_ext_role_switch_states(dev, role);
+ else
+ handle_role_switch_states(dev, role);
+
pm_runtime_put(dev);
return 0;
@@ -2650,7 +2722,7 @@ static const unsigned int renesas_usb3_cable[] = {
EXTCON_NONE,
};
-static const struct usb_role_switch_desc renesas_usb3_role_switch_desc = {
+static struct usb_role_switch_desc renesas_usb3_role_switch_desc = {
.set = renesas_usb3_role_switch_set,
.get = renesas_usb3_role_switch_get,
.allow_userspace_control = true,
@@ -2741,6 +2813,11 @@ static int renesas_usb3_probe(struct platform_device *pdev)
if (ret < 0)
goto err_dev_create;
+ if (device_property_read_bool(&pdev->dev, "usb-role-switch")) {
+ usb3->role_sw_by_connector = true;
+ renesas_usb3_role_switch_desc.fwnode = dev_fwnode(&pdev->dev);
+ }
+
INIT_WORK(&usb3->role_work, renesas_usb3_role_work);
usb3->role_sw = usb_role_switch_register(&pdev->dev,
&renesas_usb3_role_switch_desc);
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index d809671c5fea..40b5de597112 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -114,7 +114,7 @@ config USB_EHCI_HCD
Controller Driver or UHCI (for Via motherboards) Host Controller
Driver too.
- You may want to read <file:Documentation/usb/ehci.txt>.
+ You may want to read <file:Documentation/usb/ehci.rst>.
To compile this driver as a module, choose M here: the
module will be called ehci-hcd.
@@ -161,7 +161,6 @@ config USB_EHCI_PCI
config USB_EHCI_HCD_PMC_MSP
tristate "EHCI support for on-chip PMC MSP71xx USB controller"
depends on MSP_HAS_USB
- default n
select USB_EHCI_BIG_ENDIAN_DESC
select USB_EHCI_BIG_ENDIAN_MMIO
---help---
@@ -308,7 +307,6 @@ config USB_CNS3XXX_EHCI
config USB_EHCI_HCD_PLATFORM
tristate "Generic EHCI driver for a platform device"
- default n
---help---
Adds an EHCI host driver for a generic platform device, which
provides a memory space and an irq.
@@ -318,7 +316,6 @@ config USB_EHCI_HCD_PLATFORM
config USB_OCTEON_EHCI
bool "Octeon on-chip EHCI support (DEPRECATED)"
depends on CAVIUM_OCTEON_SOC
- default n
select USB_EHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN
select USB_EHCI_HCD_PLATFORM
help
@@ -526,7 +523,6 @@ config USB_OHCI_HCD_SSB
depends on (SSB = y || SSB = USB_OHCI_HCD)
select USB_HCD_SSB
select USB_OHCI_HCD_PLATFORM
- default n
---help---
This option is deprecated now and the driver was removed, use
USB_HCD_SSB and USB_OHCI_HCD_PLATFORM instead.
@@ -569,7 +565,6 @@ config USB_CNS3XXX_OHCI
config USB_OHCI_HCD_PLATFORM
tristate "Generic OHCI driver for a platform device"
- default n
---help---
Adds an OHCI host driver for a generic platform device, which
provides a memory space and an irq.
diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c
index 8e3bab1e0c1f..3a29a1a8519c 100644
--- a/drivers/usb/host/ehci-exynos.c
+++ b/drivers/usb/host/ehci-exynos.c
@@ -39,6 +39,7 @@ static struct hc_driver __read_mostly exynos_ehci_hc_driver;
struct exynos_ehci_hcd {
struct clk *clk;
+ struct device_node *of_node;
struct phy *phy[PHY_NUMBER];
};
@@ -203,6 +204,13 @@ static int exynos_ehci_probe(struct platform_device *pdev)
ehci = hcd_to_ehci(hcd);
ehci->caps = hcd->regs;
+ /*
+ * Workaround: reset of_node pointer to avoid conflict between Exynos
+ * EHCI port subnodes and generic USB device bindings
+ */
+ exynos_ehci->of_node = pdev->dev.of_node;
+ pdev->dev.of_node = NULL;
+
/* DMA burst Enable */
writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
@@ -219,6 +227,7 @@ static int exynos_ehci_probe(struct platform_device *pdev)
fail_add_hcd:
exynos_ehci_phy_disable(&pdev->dev);
+ pdev->dev.of_node = exynos_ehci->of_node;
fail_io:
clk_disable_unprepare(exynos_ehci->clk);
fail_clk:
@@ -231,6 +240,8 @@ static int exynos_ehci_remove(struct platform_device *pdev)
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct exynos_ehci_hcd *exynos_ehci = to_exynos_ehci(hcd);
+ pdev->dev.of_node = exynos_ehci->of_node;
+
usb_remove_hcd(hcd);
exynos_ehci_phy_disable(&pdev->dev);
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index e3d0c1c25160..9e9c232e896f 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -122,6 +122,12 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev)
tmp |= 0x4;
iowrite32be(tmp, hcd->regs + FSL_SOC_USB_CTRL);
}
+
+ /* Set USB_EN bit to select ULPI phy for USB controller version 2.5 */
+ if (pdata->controller_ver == FSL_USB_VER_2_5 &&
+ pdata->phy_mode == FSL_USB2_PHY_ULPI)
+ iowrite32be(USB_CTRL_USB_EN, hcd->regs + FSL_SOC_USB_CTRL);
+
/*
* Enable UTMI phy and program PTS field in UTMI mode before asserting
* controller reset for USB Controller version 2.5
@@ -177,6 +183,17 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev)
return retval;
}
+static bool usb_phy_clk_valid(struct usb_hcd *hcd)
+{
+ void __iomem *non_ehci = hcd->regs;
+ bool ret = true;
+
+ if (!(ioread32be(non_ehci + FSL_SOC_USB_CTRL) & PHY_CLK_VALID))
+ ret = false;
+
+ return ret;
+}
+
static int ehci_fsl_setup_phy(struct usb_hcd *hcd,
enum fsl_usb2_phy_modes phy_mode,
unsigned int port_offset)
@@ -219,7 +236,26 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd,
portsc |= PORT_PTS_PTW;
/* fall through */
case FSL_USB2_PHY_UTMI:
+ /* Presence of this node "has_fsl_erratum_a006918"
+ * in device-tree is used to stop USB controller
+ * initialization in Linux
+ */
+ if (pdata->has_fsl_erratum_a006918) {
+ dev_warn(dev, "USB PHY clock invalid\n");
+ return -EINVAL;
+ }
+ /* fall through */
case FSL_USB2_PHY_UTMI_DUAL:
+ /* PHY_CLK_VALID bit is de-featured from all controller
+ * versions below 2.4 and is to be checked only for
+ * internal UTMI phy
+ */
+ if (pdata->controller_ver > FSL_USB_VER_2_4 &&
+ pdata->have_sysif_regs && !usb_phy_clk_valid(hcd)) {
+ dev_err(dev, "USB PHY clock invalid\n");
+ return -EINVAL;
+ }
+
if (pdata->have_sysif_regs && pdata->controller_ver) {
/* controller version 1.6 or above */
tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL);
@@ -243,17 +279,11 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd,
break;
}
- /*
- * check PHY_CLK_VALID to determine phy clock presence before writing
- * to portsc
- */
- if (pdata->check_phy_clk_valid) {
- if (!(ioread32be(non_ehci + FSL_SOC_USB_CTRL) &
- PHY_CLK_VALID)) {
- dev_warn(hcd->self.controller,
- "USB PHY clock invalid\n");
- return -EINVAL;
- }
+ if (pdata->have_sysif_regs &&
+ pdata->controller_ver > FSL_USB_VER_1_6 &&
+ !usb_phy_clk_valid(hcd)) {
+ dev_warn(hcd->self.controller, "USB PHY clock invalid\n");
+ return -EINVAL;
}
ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]);
diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h
index cbc422032e50..9d18c6e6ab27 100644
--- a/drivers/usb/host/ehci-fsl.h
+++ b/drivers/usb/host/ehci-fsl.h
@@ -50,4 +50,7 @@
#define UTMI_PHY_EN (1<<9)
#define ULPI_PHY_CLK_SEL (1<<10)
#define PHY_CLK_VALID (1<<17)
+
+/* Retry count for checking UTMI PHY CLK validity */
+#define UTMI_PHY_CLK_VALID_CHK_RETRY 5
#endif /* _EHCI_FSL_H */
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index cdafa97f632d..9da7e22848c9 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -559,7 +559,7 @@ static int ehci_init(struct usb_hcd *hcd)
ehci->command = temp;
/* Accept arbitrarily long scatter-gather lists */
- if (!(hcd->driver->flags & HCD_LOCAL_MEM))
+ if (!hcd->localmem_pool)
hcd->self.sg_tablesize = ~0;
/* Prepare for unlinking active QHs */
diff --git a/drivers/usb/host/ehci-st.c b/drivers/usb/host/ehci-st.c
index dc42981047c9..ccb4e611001d 100644
--- a/drivers/usb/host/ehci-st.c
+++ b/drivers/usb/host/ehci-st.c
@@ -152,7 +152,6 @@ static int st_ehci_platform_probe(struct platform_device *dev)
struct resource *res_mem;
struct usb_ehci_pdata *pdata = &ehci_platform_defaults;
struct st_ehci_platform_priv *priv;
- struct ehci_hcd *ehci;
int err, irq, clk = 0;
if (usb_disabled())
@@ -177,7 +176,6 @@ static int st_ehci_platform_probe(struct platform_device *dev)
platform_set_drvdata(dev, hcd);
dev->dev.platform_data = pdata;
priv = hcd_to_ehci_priv(hcd);
- ehci = hcd_to_ehci(hcd);
priv->phy = devm_phy_get(&dev->dev, "usb");
if (IS_ERR(priv->phy)) {
diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c
index 0da68df259c8..77cc36efae95 100644
--- a/drivers/usb/host/fotg210-hcd.c
+++ b/drivers/usb/host/fotg210-hcd.c
@@ -10,6 +10,7 @@
* Most of code borrowed from the Linux-3.7 EHCI driver
*/
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/device.h>
#include <linux/dmapool.h>
#include <linux/kernel.h>
@@ -4995,7 +4996,7 @@ static int hcd_fotg210_init(struct usb_hcd *hcd)
fotg210->command = temp;
/* Accept arbitrarily long scatter-gather lists */
- if (!(hcd->driver->flags & HCD_LOCAL_MEM))
+ if (!hcd->localmem_pool)
hcd->self.sg_tablesize = ~0;
return 0;
}
@@ -5669,9 +5670,18 @@ static int fotg210_hcd_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_OF
+static const struct of_device_id fotg210_of_match[] = {
+ { .compatible = "faraday,fotg210" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, fotg210_of_match);
+#endif
+
static struct platform_driver fotg210_hcd_driver = {
.driver = {
.name = "fotg210-hcd",
+ .of_match_table = of_match_ptr(fotg210_of_match),
},
.probe = fotg210_hcd_probe,
.remove = fotg210_hcd_remove,
diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c
index 4f8b8a08c914..ae8f60f6e6a5 100644
--- a/drivers/usb/host/fsl-mph-dr-of.c
+++ b/drivers/usb/host/fsl-mph-dr-of.c
@@ -224,12 +224,10 @@ static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev)
of_property_read_bool(np, "fsl,usb-erratum-a005275");
pdata->has_fsl_erratum_a005697 =
of_property_read_bool(np, "fsl,usb_erratum-a005697");
-
- if (of_get_property(np, "fsl,usb_erratum_14", NULL))
- pdata->has_fsl_erratum_14 = 1;
- else
- pdata->has_fsl_erratum_14 = 0;
-
+ pdata->has_fsl_erratum_a006918 =
+ of_property_read_bool(np, "fsl,usb_erratum-a006918");
+ pdata->has_fsl_erratum_14 =
+ of_property_read_bool(np, "fsl,usb_erratum-14");
/*
* Determine whether phy_clk_valid needs to be checked
diff --git a/drivers/usb/host/isp1362.h b/drivers/usb/host/isp1362.h
index 650240846ee2..4c49688a069d 100644
--- a/drivers/usb/host/isp1362.h
+++ b/drivers/usb/host/isp1362.h
@@ -11,7 +11,7 @@
#define USE_32BIT 0
-/* These options are mutually eclusive */
+/* These options are mutually exclusive */
#define USE_PLATFORM_DELAY 0
#define USE_NDELAY 0
diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c
index c0c4dcca6f3c..905c6317e0c3 100644
--- a/drivers/usb/host/ohci-exynos.c
+++ b/drivers/usb/host/ohci-exynos.c
@@ -30,6 +30,7 @@ static struct hc_driver __read_mostly exynos_ohci_hc_driver;
struct exynos_ohci_hcd {
struct clk *clk;
+ struct device_node *of_node;
struct phy *phy[PHY_NUMBER];
};
@@ -170,6 +171,13 @@ static int exynos_ohci_probe(struct platform_device *pdev)
goto fail_io;
}
+ /*
+ * Workaround: reset of_node pointer to avoid conflict between Exynos
+ * OHCI port subnodes and generic USB device bindings
+ */
+ exynos_ohci->of_node = pdev->dev.of_node;
+ pdev->dev.of_node = NULL;
+
err = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (err) {
dev_err(&pdev->dev, "Failed to add USB HCD\n");
@@ -180,6 +188,7 @@ static int exynos_ohci_probe(struct platform_device *pdev)
fail_add_hcd:
exynos_ohci_phy_disable(&pdev->dev);
+ pdev->dev.of_node = exynos_ohci->of_node;
fail_io:
clk_disable_unprepare(exynos_ohci->clk);
fail_clk:
@@ -192,6 +201,8 @@ static int exynos_ohci_remove(struct platform_device *pdev)
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct exynos_ohci_hcd *exynos_ohci = to_exynos_ohci(hcd);
+ pdev->dev.of_node = exynos_ohci->of_node;
+
usb_remove_hcd(hcd);
exynos_ohci_phy_disable(&pdev->dev);
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 210181fd98d2..b457fdaff297 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -40,6 +40,7 @@
#include <linux/dmapool.h>
#include <linux/workqueue.h>
#include <linux/debugfs.h>
+#include <linux/genalloc.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -447,7 +448,7 @@ static int ohci_init (struct ohci_hcd *ohci)
struct usb_hcd *hcd = ohci_to_hcd(ohci);
/* Accept arbitrarily long scatter-gather lists */
- if (!(hcd->driver->flags & HCD_LOCAL_MEM))
+ if (!hcd->localmem_pool)
hcd->self.sg_tablesize = ~0;
if (distrust_firmware)
@@ -505,8 +506,15 @@ static int ohci_init (struct ohci_hcd *ohci)
timer_setup(&ohci->io_watchdog, io_watchdog_func, 0);
ohci->prev_frame_no = IO_WATCHDOG_OFF;
- ohci->hcca = dma_alloc_coherent (hcd->self.controller,
- sizeof(*ohci->hcca), &ohci->hcca_dma, GFP_KERNEL);
+ if (hcd->localmem_pool)
+ ohci->hcca = gen_pool_dma_alloc_align(hcd->localmem_pool,
+ sizeof(*ohci->hcca),
+ &ohci->hcca_dma, 256);
+ else
+ ohci->hcca = dma_alloc_coherent(hcd->self.controller,
+ sizeof(*ohci->hcca),
+ &ohci->hcca_dma,
+ GFP_KERNEL);
if (!ohci->hcca)
return -ENOMEM;
@@ -990,9 +998,14 @@ static void ohci_stop (struct usb_hcd *hcd)
remove_debug_files (ohci);
ohci_mem_cleanup (ohci);
if (ohci->hcca) {
- dma_free_coherent (hcd->self.controller,
- sizeof *ohci->hcca,
- ohci->hcca, ohci->hcca_dma);
+ if (hcd->localmem_pool)
+ gen_pool_free(hcd->localmem_pool,
+ (unsigned long)ohci->hcca,
+ sizeof(*ohci->hcca));
+ else
+ dma_free_coherent(hcd->self.controller,
+ sizeof(*ohci->hcca),
+ ohci->hcca, ohci->hcca_dma);
ohci->hcca = NULL;
ohci->hcca_dma = 0;
}
diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c
index 3965ac0341eb..1425335c6baf 100644
--- a/drivers/usb/host/ohci-mem.c
+++ b/drivers/usb/host/ohci-mem.c
@@ -36,6 +36,13 @@ static void ohci_hcd_init (struct ohci_hcd *ohci)
static int ohci_mem_init (struct ohci_hcd *ohci)
{
+ /*
+ * HCs with local memory allocate from localmem_pool so there's
+ * no need to create the below dma pools.
+ */
+ if (ohci_to_hcd(ohci)->localmem_pool)
+ return 0;
+
ohci->td_cache = dma_pool_create ("ohci_td",
ohci_to_hcd(ohci)->self.controller,
sizeof (struct td),
@@ -84,8 +91,13 @@ td_alloc (struct ohci_hcd *hc, gfp_t mem_flags)
{
dma_addr_t dma;
struct td *td;
+ struct usb_hcd *hcd = ohci_to_hcd(hc);
- td = dma_pool_zalloc (hc->td_cache, mem_flags, &dma);
+ if (hcd->localmem_pool)
+ td = gen_pool_dma_zalloc_align(hcd->localmem_pool,
+ sizeof(*td), &dma, 32);
+ else
+ td = dma_pool_zalloc(hc->td_cache, mem_flags, &dma);
if (td) {
/* in case hc fetches it, make it look dead */
td->hwNextTD = cpu_to_hc32 (hc, dma);
@@ -99,6 +111,7 @@ static void
td_free (struct ohci_hcd *hc, struct td *td)
{
struct td **prev = &hc->td_hash [TD_HASH_FUNC (td->td_dma)];
+ struct usb_hcd *hcd = ohci_to_hcd(hc);
while (*prev && *prev != td)
prev = &(*prev)->td_hash;
@@ -106,7 +119,12 @@ td_free (struct ohci_hcd *hc, struct td *td)
*prev = td->td_hash;
else if ((td->hwINFO & cpu_to_hc32(hc, TD_DONE)) != 0)
ohci_dbg (hc, "no hash for td %p\n", td);
- dma_pool_free (hc->td_cache, td, td->td_dma);
+
+ if (hcd->localmem_pool)
+ gen_pool_free(hcd->localmem_pool, (unsigned long)td,
+ sizeof(*td));
+ else
+ dma_pool_free(hc->td_cache, td, td->td_dma);
}
/*-------------------------------------------------------------------------*/
@@ -117,8 +135,13 @@ ed_alloc (struct ohci_hcd *hc, gfp_t mem_flags)
{
dma_addr_t dma;
struct ed *ed;
+ struct usb_hcd *hcd = ohci_to_hcd(hc);
- ed = dma_pool_zalloc (hc->ed_cache, mem_flags, &dma);
+ if (hcd->localmem_pool)
+ ed = gen_pool_dma_zalloc_align(hcd->localmem_pool,
+ sizeof(*ed), &dma, 16);
+ else
+ ed = dma_pool_zalloc(hc->ed_cache, mem_flags, &dma);
if (ed) {
INIT_LIST_HEAD (&ed->td_list);
ed->dma = dma;
@@ -129,6 +152,12 @@ ed_alloc (struct ohci_hcd *hc, gfp_t mem_flags)
static void
ed_free (struct ohci_hcd *hc, struct ed *ed)
{
- dma_pool_free (hc->ed_cache, ed, ed->dma);
+ struct usb_hcd *hcd = ohci_to_hcd(hc);
+
+ if (hcd->localmem_pool)
+ gen_pool_free(hcd->localmem_pool, (unsigned long)ed,
+ sizeof(*ed));
+ else
+ dma_pool_free(hc->ed_cache, ed, ed->dma);
}
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index fbcd34911025..a033f7d855e0 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -274,7 +274,7 @@ static const struct ohci_driver_overrides pci_overrides __initconst = {
.reset = ohci_pci_reset,
};
-static const struct pci_device_id pci_ids [] = { {
+static const struct pci_device_id pci_ids[] = { {
/* handle any USB OHCI controller */
PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_OHCI, ~0),
.driver_data = (unsigned long) &ohci_pci_hc_driver,
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index 4511e27e9da8..d961097c90f0 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -293,7 +293,6 @@ static int ohci_s3c2410_hub_control(
static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc)
{
struct s3c2410_hcd_port *port;
- struct usb_hcd *hcd;
unsigned long flags;
int portno;
@@ -301,7 +300,6 @@ static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc)
return;
port = &info->port[0];
- hcd = info->hcd;
local_irq_save(flags);
diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c
index c26228c25f99..c158cda9e4b9 100644
--- a/drivers/usb/host/ohci-sm501.c
+++ b/drivers/usb/host/ohci-sm501.c
@@ -49,7 +49,7 @@ static const struct hc_driver ohci_sm501_hc_driver = {
* generic hardware linkage
*/
.irq = ohci_irq,
- .flags = HCD_USB11 | HCD_MEMORY | HCD_LOCAL_MEM,
+ .flags = HCD_USB11 | HCD_MEMORY,
/*
* basic lifecycle operations
@@ -110,40 +110,18 @@ static int ohci_hcd_sm501_drv_probe(struct platform_device *pdev)
goto err0;
}
- /* The sm501 chip is equipped with local memory that may be used
- * by on-chip devices such as the video controller and the usb host.
- * This driver uses dma_declare_coherent_memory() to make sure
- * usb allocations with dma_alloc_coherent() allocate from
- * this local memory. The dma_handle returned by dma_alloc_coherent()
- * will be an offset starting from 0 for the first local memory byte.
- *
- * So as long as data is allocated using dma_alloc_coherent() all is
- * fine. This is however not always the case - buffers may be allocated
- * using kmalloc() - so the usb core needs to be told that it must copy
- * data into our local memory if the buffers happen to be placed in
- * regular memory. The HCD_LOCAL_MEM flag does just that.
- */
-
- retval = dma_declare_coherent_memory(dev, mem->start,
- mem->start - mem->parent->start,
- resource_size(mem));
- if (retval) {
- dev_err(dev, "cannot declare coherent memory\n");
- goto err1;
- }
-
/* allocate, reserve and remap resources for registers */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
dev_err(dev, "no resource definition for registers\n");
retval = -ENOENT;
- goto err2;
+ goto err1;
}
hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
if (!hcd) {
retval = -ENOMEM;
- goto err2;
+ goto err1;
}
hcd->rsrc_start = res->start;
@@ -164,6 +142,25 @@ static int ohci_hcd_sm501_drv_probe(struct platform_device *pdev)
ohci_hcd_init(hcd_to_ohci(hcd));
+ /* The sm501 chip is equipped with local memory that may be used
+ * by on-chip devices such as the video controller and the usb host.
+ * This driver uses genalloc so that usb allocations with
+ * gen_pool_dma_alloc() allocate from this local memory. The dma_handle
+ * returned by gen_pool_dma_alloc() will be an offset starting from 0
+ * for the first local memory byte.
+ *
+ * So as long as data is allocated using gen_pool_dma_alloc() all is
+ * fine. This is however not always the case - buffers may be allocated
+ * using kmalloc() - so the usb core needs to be told that it must copy
+ * data into our local memory if the buffers happen to be placed in
+ * regular memory. A non-null hcd->localmem_pool initialized by the
+ * the call to usb_hcd_setup_local_mem() below does just that.
+ */
+
+ if (usb_hcd_setup_local_mem(hcd, mem->start,
+ mem->start - mem->parent->start,
+ resource_size(mem)) < 0)
+ goto err5;
retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (retval)
goto err5;
@@ -181,8 +178,6 @@ err4:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
err3:
usb_put_hcd(hcd);
-err2:
- dma_release_declared_memory(dev);
err1:
release_mem_region(mem->start, resource_size(mem));
err0:
@@ -197,7 +192,6 @@ static int ohci_hcd_sm501_drv_remove(struct platform_device *pdev)
usb_remove_hcd(hcd);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
- dma_release_declared_memory(&pdev->dev);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (mem)
release_mem_region(mem->start, resource_size(mem));
diff --git a/drivers/usb/host/ohci-spear.c b/drivers/usb/host/ohci-spear.c
index 69fa04697793..5cc05449281c 100644
--- a/drivers/usb/host/ohci-spear.c
+++ b/drivers/usb/host/ohci-spear.c
@@ -35,7 +35,6 @@ static struct hc_driver __read_mostly ohci_spear_hc_driver;
static int spear_ohci_hcd_drv_probe(struct platform_device *pdev)
{
const struct hc_driver *driver = &ohci_spear_hc_driver;
- struct ohci_hcd *ohci;
struct usb_hcd *hcd = NULL;
struct clk *usbh_clk;
struct spear_ohci *sohci_p;
@@ -85,8 +84,6 @@ static int spear_ohci_hcd_drv_probe(struct platform_device *pdev)
clk_prepare_enable(sohci_p->clk);
- ohci = hcd_to_ohci(hcd);
-
retval = usb_add_hcd(hcd, platform_get_irq(pdev, 0), 0);
if (retval == 0) {
device_wakeup_enable(hcd->self.controller);
diff --git a/drivers/usb/host/ohci-st.c b/drivers/usb/host/ohci-st.c
index 992807c9850a..638a92bd2cdc 100644
--- a/drivers/usb/host/ohci-st.c
+++ b/drivers/usb/host/ohci-st.c
@@ -132,7 +132,6 @@ static int st_ohci_platform_probe(struct platform_device *dev)
struct resource *res_mem;
struct usb_ohci_pdata *pdata = &ohci_platform_defaults;
struct st_ohci_platform_priv *priv;
- struct ohci_hcd *ohci;
int err, irq, clk = 0;
if (usb_disabled())
@@ -158,7 +157,6 @@ static int st_ohci_platform_probe(struct platform_device *dev)
platform_set_drvdata(dev, hcd);
dev->dev.platform_data = pdata;
priv = hcd_to_ohci_priv(hcd);
- ohci = hcd_to_ohci(hcd);
priv->phy = devm_phy_get(&dev->dev, "usb");
if (IS_ERR(priv->phy)) {
diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c
index f88a0370659f..d5a293a707b6 100644
--- a/drivers/usb/host/ohci-tmio.c
+++ b/drivers/usb/host/ohci-tmio.c
@@ -153,7 +153,7 @@ static const struct hc_driver ohci_tmio_hc_driver = {
/* generic hardware linkage */
.irq = ohci_irq,
- .flags = HCD_USB11 | HCD_MEMORY | HCD_LOCAL_MEM,
+ .flags = HCD_USB11 | HCD_MEMORY,
/* basic lifecycle operations */
.start = ohci_tmio_start,
@@ -224,11 +224,6 @@ static int ohci_hcd_tmio_drv_probe(struct platform_device *dev)
goto err_ioremap_regs;
}
- ret = dma_declare_coherent_memory(&dev->dev, sram->start, sram->start,
- resource_size(sram));
- if (ret)
- goto err_dma_declare;
-
if (cell->enable) {
ret = cell->enable(dev);
if (ret)
@@ -239,6 +234,11 @@ static int ohci_hcd_tmio_drv_probe(struct platform_device *dev)
ohci = hcd_to_ohci(hcd);
ohci_hcd_init(ohci);
+ ret = usb_hcd_setup_local_mem(hcd, sram->start, sram->start,
+ resource_size(sram));
+ if (ret < 0)
+ goto err_enable;
+
ret = usb_add_hcd(hcd, irq, 0);
if (ret)
goto err_add_hcd;
@@ -254,8 +254,6 @@ err_add_hcd:
if (cell->disable)
cell->disable(dev);
err_enable:
- dma_release_declared_memory(&dev->dev);
-err_dma_declare:
iounmap(hcd->regs);
err_ioremap_regs:
iounmap(tmio->ccr);
@@ -276,7 +274,6 @@ static int ohci_hcd_tmio_drv_remove(struct platform_device *dev)
tmio_stop_hc(dev);
if (cell->disable)
cell->disable(dev);
- dma_release_declared_memory(&dev->dev);
iounmap(hcd->regs);
iounmap(tmio->ccr);
usb_put_hcd(hcd);
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index ef4813bfc5bf..b015b00774b2 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -385,6 +385,8 @@ struct ohci_hcd {
/*
* memory management for queue data structures
+ *
+ * @td_cache and @ed_cache are %NULL if &usb_hcd.localmem_pool is used.
*/
struct dma_pool *td_cache;
struct dma_pool *ed_cache;
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index 4a5c9b599c57..400c40bc43a6 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -2554,10 +2554,9 @@ static int u132_get_frame(struct usb_hcd *hcd)
dev_err(&u132->platform_dev->dev, "device is being removed\n");
return -ESHUTDOWN;
} else {
- int frame = 0;
dev_err(&u132->platform_dev->dev, "TODO: u132_get_frame\n");
mdelay(100);
- return frame;
+ return 0;
}
}
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 98deb5f64268..03bc59755123 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -581,7 +581,7 @@ static int uhci_start(struct usb_hcd *hcd)
hcd->uses_new_polling = 1;
/* Accept arbitrarily long scatter-gather lists */
- if (!(hcd->driver->flags & HCD_LOCAL_MEM))
+ if (!hcd->localmem_pool)
hcd->self.sg_tablesize = ~0;
spin_lock_init(&uhci->lock);
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index feffceb31e8a..9741cdeea9d7 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -399,7 +399,7 @@ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci,
* stream once the endpoint is on the HW schedule.
*/
if ((ep_state & EP_STOP_CMD_PENDING) || (ep_state & SET_DEQ_PENDING) ||
- (ep_state & EP_HALTED))
+ (ep_state & EP_HALTED) || (ep_state & EP_CLEARING_TT))
return;
writel(DB_VALUE(ep_index, stream_id), db_addr);
/* The CPU has better things to do at this point than wait for a
@@ -433,6 +433,13 @@ static void ring_doorbell_for_active_rings(struct xhci_hcd *xhci,
}
}
+void xhci_ring_doorbell_for_active_rings(struct xhci_hcd *xhci,
+ unsigned int slot_id,
+ unsigned int ep_index)
+{
+ ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
+}
+
/* Get the right ring for the given slot_id, ep_index and stream_id.
* If the endpoint supports streams, boundary check the URB's stream ID.
* If the endpoint doesn't support streams, return the singular endpoint ring.
@@ -1612,8 +1619,13 @@ static void handle_port_status(struct xhci_hcd *xhci,
usb_hcd_resume_root_hub(hcd);
}
- if (hcd->speed >= HCD_USB3 && (portsc & PORT_PLS_MASK) == XDEV_INACTIVE)
+ if (hcd->speed >= HCD_USB3 &&
+ (portsc & PORT_PLS_MASK) == XDEV_INACTIVE) {
+ slot_id = xhci_find_slot_id_by_port(hcd, xhci, hcd_portnum + 1);
+ if (slot_id && xhci->devs[slot_id])
+ xhci->devs[slot_id]->flags |= VDEV_PORT_ERROR;
bus_state->port_remote_wakeup &= ~(1 << hcd_portnum);
+ }
if ((portsc & PORT_PLC) && (portsc & PORT_PLS_MASK) == XDEV_RESUME) {
xhci_dbg(xhci, "port resume event for port %d\n", port_id);
@@ -1794,6 +1806,23 @@ struct xhci_segment *trb_in_td(struct xhci_hcd *xhci,
return NULL;
}
+static void xhci_clear_hub_tt_buffer(struct xhci_hcd *xhci, struct xhci_td *td,
+ struct xhci_virt_ep *ep)
+{
+ /*
+ * As part of low/full-speed endpoint-halt processing
+ * we must clear the TT buffer (USB 2.0 specification 11.17.5).
+ */
+ if (td->urb->dev->tt && !usb_pipeint(td->urb->pipe) &&
+ (td->urb->dev->tt->hub != xhci_to_hcd(xhci)->self.root_hub) &&
+ !(ep->ep_state & EP_CLEARING_TT)) {
+ ep->ep_state |= EP_CLEARING_TT;
+ td->urb->ep->hcpriv = td->urb->dev;
+ if (usb_hub_clear_tt_buffer(td->urb))
+ ep->ep_state &= ~EP_CLEARING_TT;
+ }
+}
+
static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci,
unsigned int slot_id, unsigned int ep_index,
unsigned int stream_id, struct xhci_td *td,
@@ -1801,6 +1830,14 @@ static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci,
{
struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index];
struct xhci_command *command;
+
+ /*
+ * Avoid resetting endpoint if link is inactive. Can cause host hang.
+ * Device will be reset soon to recover the link so don't do anything
+ */
+ if (xhci->devs[slot_id]->flags & VDEV_PORT_ERROR)
+ return;
+
command = xhci_alloc_command(xhci, false, GFP_ATOMIC);
if (!command)
return;
@@ -1812,6 +1849,7 @@ static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci,
if (reset_type == EP_HARD_RESET) {
ep->ep_state |= EP_HARD_CLEAR_TOGGLE;
xhci_cleanup_stalled_ring(xhci, ep_index, stream_id, td);
+ xhci_clear_hub_tt_buffer(xhci, td, ep);
}
xhci_ring_cmd_db(xhci);
}
diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c
index 294158113d62..dafc65911fc0 100644
--- a/drivers/usb/host/xhci-tegra.c
+++ b/drivers/usb/host/xhci-tegra.c
@@ -354,29 +354,6 @@ enum tegra_xusb_mbox_cmd {
MBOX_CMD_NAK
};
-static const char * const mbox_cmd_name[] = {
- [ 1] = "MSG_ENABLE",
- [ 2] = "INC_FALCON_CLOCK",
- [ 3] = "DEC_FALCON_CLOCK",
- [ 4] = "INC_SSPI_CLOCK",
- [ 5] = "DEC_SSPI_CLOCK",
- [ 6] = "SET_BW",
- [ 7] = "SET_SS_PWR_GATING",
- [ 8] = "SET_SS_PWR_UNGATING",
- [ 9] = "SAVE_DFE_CTLE_CTX",
- [ 10] = "AIRPLANE_MODE_ENABLED",
- [ 11] = "AIRPLANE_MODE_DISABLED",
- [ 12] = "START_HSIC_IDLE",
- [ 13] = "STOP_HSIC_IDLE",
- [ 14] = "DBC_WAKE_STACK",
- [ 15] = "HSIC_PRETEND_CONNECT",
- [ 16] = "RESET_SSPI",
- [ 17] = "DISABLE_SS_LFPS_DETECTION",
- [ 18] = "ENABLE_SS_LFPS_DETECTION",
- [128] = "ACK",
- [129] = "NAK",
-};
-
struct tegra_xusb_mbox_msg {
u32 cmd;
u32 data;
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 20db378a6012..248cd7a8b163 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1466,6 +1466,10 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag
xhci_dbg(xhci, "urb submitted during PCI suspend\n");
return -ESHUTDOWN;
}
+ if (xhci->devs[slot_id]->flags & VDEV_PORT_ERROR) {
+ xhci_dbg(xhci, "Can't queue urb, port error, link inactive\n");
+ return -ENODEV;
+ }
if (usb_endpoint_xfer_isoc(&urb->ep->desc))
num_tds = urb->number_of_packets;
@@ -3754,6 +3758,7 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd,
}
/* If necessary, update the number of active TTs on this root port */
xhci_update_tt_active_eps(xhci, virt_dev, old_active_eps);
+ virt_dev->flags = 0;
ret = 0;
command_cleanup:
@@ -4125,6 +4130,8 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
/* Zero the input context control for later use */
ctrl_ctx->add_flags = 0;
ctrl_ctx->drop_flags = 0;
+ slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx);
+ udev->devaddr = (u8)(le32_to_cpu(slot_ctx->dev_state) & DEV_ADDR_MASK);
xhci_dbg_trace(xhci, trace_xhci_dbg_address,
"Internal device address = %d",
@@ -5060,16 +5067,26 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
} else {
/*
* Some 3.1 hosts return sbrn 0x30, use xhci supported protocol
- * minor revision instead of sbrn
+ * minor revision instead of sbrn. Minor revision is a two digit
+ * BCD containing minor and sub-minor numbers, only show minor.
*/
- minor_rev = xhci->usb3_rhub.min_rev;
- if (minor_rev) {
+ minor_rev = xhci->usb3_rhub.min_rev / 0x10;
+
+ switch (minor_rev) {
+ case 2:
+ hcd->speed = HCD_USB32;
+ hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS;
+ hcd->self.root_hub->rx_lanes = 2;
+ hcd->self.root_hub->tx_lanes = 2;
+ break;
+ case 1:
hcd->speed = HCD_USB31;
hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS;
+ break;
}
- xhci_info(xhci, "Host supports USB 3.%x %s SuperSpeed\n",
+ xhci_info(xhci, "Host supports USB 3.%x %sSuperSpeed\n",
minor_rev,
- minor_rev ? "Enhanced" : "");
+ minor_rev ? "Enhanced " : "");
xhci->usb3_rhub.hcd = hcd;
/* xHCI private pointer was set in xhci_pci_probe for the second
@@ -5161,6 +5178,26 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
}
EXPORT_SYMBOL_GPL(xhci_gen_setup);
+static void xhci_clear_tt_buffer_complete(struct usb_hcd *hcd,
+ struct usb_host_endpoint *ep)
+{
+ struct xhci_hcd *xhci;
+ struct usb_device *udev;
+ unsigned int slot_id;
+ unsigned int ep_index;
+ unsigned long flags;
+
+ xhci = hcd_to_xhci(hcd);
+ udev = (struct usb_device *)ep->hcpriv;
+ slot_id = udev->slot_id;
+ ep_index = xhci_get_endpoint_index(&ep->desc);
+
+ spin_lock_irqsave(&xhci->lock, flags);
+ xhci->devs[slot_id]->eps[ep_index].ep_state &= ~EP_CLEARING_TT;
+ xhci_ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+}
+
static const struct hc_driver xhci_hc_driver = {
.description = "xhci-hcd",
.product_desc = "xHCI Host Controller",
@@ -5222,6 +5259,7 @@ static const struct hc_driver xhci_hc_driver = {
.enable_usb3_lpm_timeout = xhci_enable_usb3_lpm_timeout,
.disable_usb3_lpm_timeout = xhci_disable_usb3_lpm_timeout,
.find_raw_port_number = xhci_find_raw_port_number,
+ .clear_tt_buffer_complete = xhci_clear_tt_buffer_complete,
};
void xhci_init_driver(struct hc_driver *drv,
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 7f8b950d1a73..7a264962a1a9 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -936,6 +936,8 @@ struct xhci_virt_ep {
#define EP_GETTING_NO_STREAMS (1 << 5)
#define EP_HARD_CLEAR_TOGGLE (1 << 6)
#define EP_SOFT_CLEAR_TOGGLE (1 << 7)
+/* usb_hub_clear_tt_buffer is in progress */
+#define EP_CLEARING_TT (1 << 8)
/* ---- Related to URB cancellation ---- */
struct list_head cancelled_td_list;
/* Watchdog timer for stop endpoint command to cancel URBs */
@@ -1010,6 +1012,15 @@ struct xhci_virt_device {
u8 real_port;
struct xhci_interval_bw_table *bw_table;
struct xhci_tt_bw_info *tt_info;
+ /*
+ * flags for state tracking based on events and issued commands.
+ * Software can not rely on states from output contexts because of
+ * latency between events and xHC updating output context values.
+ * See xhci 1.1 section 4.8.3 for more details
+ */
+ unsigned long flags;
+#define VDEV_PORT_ERROR BIT(0) /* Port error, link inactive */
+
/* The current max exit latency for the enabled USB3 link states. */
u16 current_mel;
/* Used for the debugfs interfaces. */
@@ -2102,6 +2113,9 @@ void xhci_handle_command_timeout(struct work_struct *work);
void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id,
unsigned int ep_index, unsigned int stream_id);
+void xhci_ring_doorbell_for_active_rings(struct xhci_hcd *xhci,
+ unsigned int slot_id,
+ unsigned int ep_index);
void xhci_cleanup_command_queue(struct xhci_hcd *xhci);
void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring);
unsigned int count_trbs(u64 addr, u64 len);
diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
index 607be1f4fe27..0a57c2cc8e5a 100644
--- a/drivers/usb/image/microtek.c
+++ b/drivers/usb/image/microtek.c
@@ -488,7 +488,6 @@ static void mts_command_done( struct urb *transfer )
static void mts_do_sg (struct urb* transfer)
{
- struct scatterlist * sg;
int status = transfer->status;
MTS_INT_INIT();
@@ -500,13 +499,12 @@ static void mts_do_sg (struct urb* transfer)
mts_transfer_cleanup(transfer);
}
- sg = scsi_sglist(context->srb);
- context->fragment++;
+ context->curr_sg = sg_next(context->curr_sg);
mts_int_submit_urb(transfer,
context->data_pipe,
- sg_virt(&sg[context->fragment]),
- sg[context->fragment].length,
- context->fragment + 1 == scsi_sg_count(context->srb) ?
+ sg_virt(context->curr_sg),
+ context->curr_sg->length,
+ sg_is_last(context->curr_sg) ?
mts_data_done : mts_do_sg);
}
@@ -526,22 +524,20 @@ static void
mts_build_transfer_context(struct scsi_cmnd *srb, struct mts_desc* desc)
{
int pipe;
- struct scatterlist * sg;
-
+
MTS_DEBUG_GOT_HERE();
desc->context.instance = desc;
desc->context.srb = srb;
- desc->context.fragment = 0;
if (!scsi_bufflen(srb)) {
desc->context.data = NULL;
desc->context.data_length = 0;
return;
} else {
- sg = scsi_sglist(srb);
- desc->context.data = sg_virt(&sg[0]);
- desc->context.data_length = sg[0].length;
+ desc->context.curr_sg = scsi_sglist(srb);
+ desc->context.data = sg_virt(desc->context.curr_sg);
+ desc->context.data_length = desc->context.curr_sg->length;
}
diff --git a/drivers/usb/image/microtek.h b/drivers/usb/image/microtek.h
index 66685e59241a..7bd5f4639c4a 100644
--- a/drivers/usb/image/microtek.h
+++ b/drivers/usb/image/microtek.h
@@ -21,7 +21,7 @@ struct mts_transfer_context
void *data;
unsigned data_length;
int data_pipe;
- int fragment;
+ struct scatterlist *curr_sg;
u8 *scsi_status; /* status returned from ep_response after command completion */
};
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index c97f270338bf..bdae62b2ffe0 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -16,7 +16,7 @@ config USB_EMI62
This code is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called audio. If you want to compile it as a
- module, say M here and read <file:Documentation/kbuild/modules.txt>.
+ module, say M here and read <file:Documentation/kbuild/modules.rst>.
config USB_EMI26
tristate "EMI 2|6 USB Audio interface support"
@@ -51,7 +51,7 @@ config USB_RIO500
tristate "USB Diamond Rio500 support"
help
Say Y here if you want to connect a USB Rio500 mp3 player to your
- computer's USB port. Please read <file:Documentation/usb/rio.txt>
+ computer's USB port. Please read <file:Documentation/usb/rio.rst>
for more information.
To compile this driver as a module, choose M here: the
@@ -67,7 +67,7 @@ config USB_LEGOTOWER
inserted in and removed from the running kernel whenever you want).
The module will be called legousbtower. If you want to compile it as
a module, say M here and read
- <file:Documentation/kbuild/modules.txt>.
+ <file:Documentation/kbuild/modules.rst>.
config USB_LCD
tristate "USB LCD driver support"
diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c
index 9465fb95d70a..344d523b0502 100644
--- a/drivers/usb/misc/adutux.c
+++ b/drivers/usb/misc/adutux.c
@@ -343,7 +343,6 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
struct adu_device *dev;
size_t bytes_read = 0;
size_t bytes_to_read = count;
- int i;
int retval = 0;
int timeout = 0;
int should_submit = 0;
@@ -371,23 +370,22 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
timeout = COMMAND_TIMEOUT;
dev_dbg(&dev->udev->dev, "%s : about to start looping\n", __func__);
while (bytes_to_read) {
- int data_in_secondary = dev->secondary_tail - dev->secondary_head;
+ size_t data_in_secondary = dev->secondary_tail - dev->secondary_head;
dev_dbg(&dev->udev->dev,
- "%s : while, data_in_secondary=%d, status=%d\n",
+ "%s : while, data_in_secondary=%zu, status=%d\n",
__func__, data_in_secondary,
dev->interrupt_in_urb->status);
if (data_in_secondary) {
/* drain secondary buffer */
- int amount = bytes_to_read < data_in_secondary ? bytes_to_read : data_in_secondary;
- i = copy_to_user(buffer, dev->read_buffer_secondary+dev->secondary_head, amount);
- if (i) {
+ size_t amount = min(bytes_to_read, data_in_secondary);
+ if (copy_to_user(buffer, dev->read_buffer_secondary+dev->secondary_head, amount)) {
retval = -EFAULT;
goto exit;
}
- dev->secondary_head += (amount - i);
- bytes_read += (amount - i);
- bytes_to_read -= (amount - i);
+ dev->secondary_head += amount;
+ bytes_read += amount;
+ bytes_to_read -= amount;
} else {
/* we check the primary buffer */
spin_lock_irqsave (&dev->buflock, flags);
diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c
index 257efacf3551..cdee3af33ad7 100644
--- a/drivers/usb/misc/ftdi-elan.c
+++ b/drivers/usb/misc/ftdi-elan.c
@@ -2023,13 +2023,6 @@ static int ftdi_elan_synchronize(struct usb_ftdi *ftdi)
goto read;
} else
goto reset;
- } else if (s1 == 0x31 && s2 == 0x60) {
- if (read_stop-- > 0) {
- goto read;
- } else {
- dev_err(&ftdi->udev->dev, "retry limit reached\n");
- continue;
- }
} else {
if (read_stop-- > 0) {
goto read;
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index ea06f1fed6fa..2ab9600d0898 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -1747,10 +1747,10 @@ static int sisusb_setup_screen(struct sisusb_usb_data *sisusb,
return ret;
}
-static int sisusb_set_default_mode(struct sisusb_usb_data *sisusb,
+static void sisusb_set_default_mode(struct sisusb_usb_data *sisusb,
int touchengines)
{
- int ret = 0, i, j, modex, bpp, du;
+ int i, j, modex, bpp, du;
u8 sr31, cr63, tmp8;
static const char attrdata[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
@@ -1873,8 +1873,6 @@ static int sisusb_set_default_mode(struct sisusb_usb_data *sisusb,
}
SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */
-
- return ret;
}
static int sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
@@ -2019,7 +2017,7 @@ static int sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
ret |= SETIREG(SISCR, 0x83, 0x00);
- ret |= sisusb_set_default_mode(sisusb, 0);
+ sisusb_set_default_mode(sisusb, 0);
ret |= SETIREGAND(SISSR, 0x21, 0xdf);
ret |= SETIREGOR(SISSR, 0x01, 0x20);
@@ -2246,7 +2244,7 @@ static int sisusb_init_gfxdevice(struct sisusb_usb_data *sisusb, int initscreen)
if (sisusb_init_gfxcore(sisusb) == 0) {
sisusb->gfxinit = 1;
sisusb_get_ramconfig(sisusb);
- ret |= sisusb_set_default_mode(sisusb, 1);
+ sisusb_set_default_mode(sisusb, 1);
ret |= sisusb_setup_screen(sisusb, 1, initscreen);
}
}
diff --git a/drivers/usb/mon/Kconfig b/drivers/usb/mon/Kconfig
index 48f1b2dadb24..ffc7cd422874 100644
--- a/drivers/usb/mon/Kconfig
+++ b/drivers/usb/mon/Kconfig
@@ -8,6 +8,6 @@ config USB_MON
help
If you select this option, a component which captures the USB traffic
between peripheral-specific drivers and HC drivers will be built.
- For more information, see <file:Documentation/usb/usbmon.txt>.
+ For more information, see <file:Documentation/usb/usbmon.rst>.
If unsure, say Y, if allowed, otherwise M.
diff --git a/drivers/usb/mtu3/mtu3_debugfs.c b/drivers/usb/mtu3/mtu3_debugfs.c
index b7c86ccd50b4..62c57ddc554e 100644
--- a/drivers/usb/mtu3/mtu3_debugfs.c
+++ b/drivers/usb/mtu3/mtu3_debugfs.c
@@ -528,7 +528,8 @@ void ssusb_dr_debugfs_init(struct ssusb_mtk *ssusb)
void ssusb_debugfs_create_root(struct ssusb_mtk *ssusb)
{
- ssusb->dbgfs_root = debugfs_create_dir(dev_name(ssusb->dev), NULL);
+ ssusb->dbgfs_root =
+ debugfs_create_dir(dev_name(ssusb->dev), usb_debug_root);
}
void ssusb_debugfs_remove_root(struct ssusb_mtk *ssusb)
diff --git a/drivers/usb/phy/phy-am335x-control.c b/drivers/usb/phy/phy-am335x-control.c
index a3cb25cb74f8..d16dfc320faa 100644
--- a/drivers/usb/phy/phy-am335x-control.c
+++ b/drivers/usb/phy/phy-am335x-control.c
@@ -118,9 +118,9 @@ static const struct of_device_id omap_control_usb_id_table[] = {
MODULE_DEVICE_TABLE(of, omap_control_usb_id_table);
static struct platform_driver am335x_control_driver;
-static int match(struct device *dev, void *data)
+static int match(struct device *dev, const void *data)
{
- struct device_node *node = (struct device_node *)data;
+ const struct device_node *node = (const struct device_node *)data;
return dev->of_node == node &&
dev->driver == &am335x_control_driver.driver;
}
diff --git a/drivers/usb/phy/phy-isp1301.c b/drivers/usb/phy/phy-isp1301.c
index 93b7d6a30aad..6cf6fbd39237 100644
--- a/drivers/usb/phy/phy-isp1301.c
+++ b/drivers/usb/phy/phy-isp1301.c
@@ -142,9 +142,9 @@ static struct i2c_driver isp1301_driver = {
module_i2c_driver(isp1301_driver);
-static int match(struct device *dev, void *data)
+static int match(struct device *dev, const void *data)
{
- struct device_node *node = (struct device_node *)data;
+ const struct device_node *node = (const struct device_node *)data;
return (dev->of_node == node) &&
(dev->driver == &isp1301_driver.driver);
}
diff --git a/drivers/usb/phy/phy-mv-usb.c b/drivers/usb/phy/phy-mv-usb.c
index cfd9add10bf4..cf7ecdc9a9d4 100644
--- a/drivers/usb/phy/phy-mv-usb.c
+++ b/drivers/usb/phy/phy-mv-usb.c
@@ -401,7 +401,6 @@ static void mv_otg_update_state(struct mv_otg *mvotg)
static void mv_otg_work(struct work_struct *work)
{
struct mv_otg *mvotg;
- struct usb_phy *phy;
struct usb_otg *otg;
int old_state;
@@ -409,7 +408,6 @@ static void mv_otg_work(struct work_struct *work)
run:
/* work queue is single thread, or we need spin_lock to protect */
- phy = &mvotg->phy;
otg = mvotg->phy.otg;
old_state = otg->state;
diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c
index 6fa16ab31e2e..70b8c8248caf 100644
--- a/drivers/usb/phy/phy-mxs-usb.c
+++ b/drivers/usb/phy/phy-mxs-usb.c
@@ -17,9 +17,11 @@
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
+#include <linux/iopoll.h>
#define DRIVER_NAME "mxs_phy"
+/* Register Macro */
#define HW_USBPHY_PWD 0x00
#define HW_USBPHY_TX 0x10
#define HW_USBPHY_CTRL 0x30
@@ -37,6 +39,11 @@
#define GM_USBPHY_TX_TXCAL45DN(x) (((x) & 0xf) << 8)
#define GM_USBPHY_TX_D_CAL(x) (((x) & 0xf) << 0)
+/* imx7ulp */
+#define HW_USBPHY_PLL_SIC 0xa0
+#define HW_USBPHY_PLL_SIC_SET 0xa4
+#define HW_USBPHY_PLL_SIC_CLR 0xa8
+
#define BM_USBPHY_CTRL_SFTRST BIT(31)
#define BM_USBPHY_CTRL_CLKGATE BIT(30)
#define BM_USBPHY_CTRL_OTG_ID_VALUE BIT(27)
@@ -55,6 +62,12 @@
#define BM_USBPHY_IP_FIX (BIT(17) | BIT(18))
#define BM_USBPHY_DEBUG_CLKGATE BIT(30)
+/* imx7ulp */
+#define BM_USBPHY_PLL_LOCK BIT(31)
+#define BM_USBPHY_PLL_REG_ENABLE BIT(21)
+#define BM_USBPHY_PLL_BYPASS BIT(16)
+#define BM_USBPHY_PLL_POWER BIT(12)
+#define BM_USBPHY_PLL_EN_USB_CLKS BIT(6)
/* Anatop Registers */
#define ANADIG_ANA_MISC0 0x150
@@ -168,6 +181,9 @@ static const struct mxs_phy_data imx6ul_phy_data = {
.flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS,
};
+static const struct mxs_phy_data imx7ulp_phy_data = {
+};
+
static const struct of_device_id mxs_phy_dt_ids[] = {
{ .compatible = "fsl,imx6sx-usbphy", .data = &imx6sx_phy_data, },
{ .compatible = "fsl,imx6sl-usbphy", .data = &imx6sl_phy_data, },
@@ -175,6 +191,7 @@ static const struct of_device_id mxs_phy_dt_ids[] = {
{ .compatible = "fsl,imx23-usbphy", .data = &imx23_phy_data, },
{ .compatible = "fsl,vf610-usbphy", .data = &vf610_phy_data, },
{ .compatible = "fsl,imx6ul-usbphy", .data = &imx6ul_phy_data, },
+ { .compatible = "fsl,imx7ulp-usbphy", .data = &imx7ulp_phy_data, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mxs_phy_dt_ids);
@@ -199,6 +216,11 @@ static inline bool is_imx6sl_phy(struct mxs_phy *mxs_phy)
return mxs_phy->data == &imx6sl_phy_data;
}
+static inline bool is_imx7ulp_phy(struct mxs_phy *mxs_phy)
+{
+ return mxs_phy->data == &imx7ulp_phy_data;
+}
+
/*
* PHY needs some 32K cycles to switch from 32K clock to
* bus (such as AHB/AXI, etc) clock.
@@ -222,14 +244,49 @@ static void mxs_phy_tx_init(struct mxs_phy *mxs_phy)
}
}
+static int mxs_phy_pll_enable(void __iomem *base, bool enable)
+{
+ int ret = 0;
+
+ if (enable) {
+ u32 value;
+
+ writel(BM_USBPHY_PLL_REG_ENABLE, base + HW_USBPHY_PLL_SIC_SET);
+ writel(BM_USBPHY_PLL_BYPASS, base + HW_USBPHY_PLL_SIC_CLR);
+ writel(BM_USBPHY_PLL_POWER, base + HW_USBPHY_PLL_SIC_SET);
+ ret = readl_poll_timeout(base + HW_USBPHY_PLL_SIC,
+ value, (value & BM_USBPHY_PLL_LOCK) != 0,
+ 100, 10000);
+ if (ret)
+ return ret;
+
+ writel(BM_USBPHY_PLL_EN_USB_CLKS, base +
+ HW_USBPHY_PLL_SIC_SET);
+ } else {
+ writel(BM_USBPHY_PLL_EN_USB_CLKS, base +
+ HW_USBPHY_PLL_SIC_CLR);
+ writel(BM_USBPHY_PLL_POWER, base + HW_USBPHY_PLL_SIC_CLR);
+ writel(BM_USBPHY_PLL_BYPASS, base + HW_USBPHY_PLL_SIC_SET);
+ writel(BM_USBPHY_PLL_REG_ENABLE, base + HW_USBPHY_PLL_SIC_CLR);
+ }
+
+ return ret;
+}
+
static int mxs_phy_hw_init(struct mxs_phy *mxs_phy)
{
int ret;
void __iomem *base = mxs_phy->phy.io_priv;
+ if (is_imx7ulp_phy(mxs_phy)) {
+ ret = mxs_phy_pll_enable(base, true);
+ if (ret)
+ return ret;
+ }
+
ret = stmp_reset_block(base + HW_USBPHY_CTRL);
if (ret)
- return ret;
+ goto disable_pll;
/* Power up the PHY */
writel(0, base + HW_USBPHY_PWD);
@@ -267,6 +324,11 @@ static int mxs_phy_hw_init(struct mxs_phy *mxs_phy)
mxs_phy_tx_init(mxs_phy);
return 0;
+
+disable_pll:
+ if (is_imx7ulp_phy(mxs_phy))
+ mxs_phy_pll_enable(base, false);
+ return ret;
}
/* Return true if the vbus is there */
@@ -388,6 +450,9 @@ static void mxs_phy_shutdown(struct usb_phy *phy)
writel(BM_USBPHY_CTRL_CLKGATE,
phy->io_priv + HW_USBPHY_CTRL_SET);
+ if (is_imx7ulp_phy(mxs_phy))
+ mxs_phy_pll_enable(phy->io_priv, false);
+
clk_disable_unprepare(mxs_phy->clk);
}
diff --git a/drivers/usb/renesas_usbhs/Kconfig b/drivers/usb/renesas_usbhs/Kconfig
index 7fdbff23ae8b..d6b3fef3e55b 100644
--- a/drivers/usb/renesas_usbhs/Kconfig
+++ b/drivers/usb/renesas_usbhs/Kconfig
@@ -8,7 +8,6 @@ config USB_RENESAS_USBHS
depends on USB_GADGET
depends on ARCH_RENESAS || SUPERH || COMPILE_TEST
depends on EXTCON || !EXTCON # if EXTCON=m, USBHS cannot be built-in
- default n
help
Renesas USBHS is a discrete USB host and peripheral controller chip
that supports both full and high speed USB 2.0 data transfers.
diff --git a/drivers/usb/renesas_usbhs/Makefile b/drivers/usb/renesas_usbhs/Makefile
index 5c5b51bb48ef..a1fed56b0957 100644
--- a/drivers/usb/renesas_usbhs/Makefile
+++ b/drivers/usb/renesas_usbhs/Makefile
@@ -5,7 +5,7 @@
obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs.o
-renesas_usbhs-y := common.o mod.o pipe.o fifo.o rcar2.o rcar3.o rza.o
+renesas_usbhs-y := common.o mod.o pipe.o fifo.o rcar2.o rcar3.o rza.o rza2.o
ifneq ($(CONFIG_USB_RENESAS_USBHS_HCD),)
renesas_usbhs-y += mod_host.o
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
index 249fbee97f3f..4c3de777ef6c 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -3,6 +3,7 @@
* Renesas USB driver
*
* Copyright (C) 2011 Renesas Solutions Corp.
+ * Copyright (C) 2019 Renesas Electronics Corporation
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*/
#include <linux/clk.h>
@@ -43,15 +44,6 @@
* | .... | +-----------+
*/
-
-#define USBHSF_RUNTIME_PWCTRL (1 << 0)
-
-/* status */
-#define usbhsc_flags_init(p) do {(p)->flags = 0; } while (0)
-#define usbhsc_flags_set(p, b) ((p)->flags |= (b))
-#define usbhsc_flags_clr(p, b) ((p)->flags &= ~(b))
-#define usbhsc_flags_has(p, b) ((p)->flags & (b))
-
/*
* platform call back
*
@@ -61,8 +53,8 @@
*/
#define usbhs_platform_call(priv, func, args...)\
(!(priv) ? -ENODEV : \
- !((priv)->pfunc.func) ? 0 : \
- (priv)->pfunc.func(args))
+ !((priv)->pfunc->func) ? 0 : \
+ (priv)->pfunc->func(args))
/*
* common functions
@@ -92,6 +84,11 @@ struct usbhs_priv *usbhs_pdev_to_priv(struct platform_device *pdev)
return dev_get_drvdata(&pdev->dev);
}
+int usbhs_get_id_as_gadget(struct platform_device *pdev)
+{
+ return USBHS_GADGET;
+}
+
/*
* syscfg functions
*/
@@ -104,10 +101,6 @@ void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable)
{
u16 mask = DCFM | DRPD | DPRPU | HSE | USBE;
u16 val = DCFM | DRPD | HSE | USBE;
- int has_otg = usbhs_get_dparam(priv, has_otg);
-
- if (has_otg)
- usbhs_bset(priv, DVSTCTR, (EXTLP | PWEN), (EXTLP | PWEN));
/*
* if enable
@@ -123,6 +116,12 @@ void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable)
u16 mask = DCFM | DRPD | DPRPU | HSE | USBE;
u16 val = HSE | USBE;
+ /* CNEN bit is required for function operation */
+ if (usbhs_get_dparam(priv, has_cnen)) {
+ mask |= CNEN;
+ val |= CNEN;
+ }
+
/*
* if enable
*
@@ -294,11 +293,7 @@ static void usbhsc_set_buswait(struct usbhs_priv *priv)
static bool usbhsc_is_multi_clks(struct usbhs_priv *priv)
{
- if (priv->dparam.type == USBHS_TYPE_RCAR_GEN3 ||
- priv->dparam.type == USBHS_TYPE_RCAR_GEN3_WITH_PLL)
- return true;
-
- return false;
+ return priv->dparam.multi_clks;
}
static int usbhsc_clk_get(struct device *dev, struct usbhs_priv *priv)
@@ -307,7 +302,7 @@ static int usbhsc_clk_get(struct device *dev, struct usbhs_priv *priv)
return 0;
/* The first clock should exist */
- priv->clks[0] = of_clk_get(dev->of_node, 0);
+ priv->clks[0] = of_clk_get(dev_of_node(dev), 0);
if (IS_ERR(priv->clks[0]))
return PTR_ERR(priv->clks[0]);
@@ -315,7 +310,7 @@ static int usbhsc_clk_get(struct device *dev, struct usbhs_priv *priv)
* To backward compatibility with old DT, this driver checks the return
* value if it's -ENOENT or not.
*/
- priv->clks[1] = of_clk_get(dev->of_node, 1);
+ priv->clks[1] = of_clk_get(dev_of_node(dev), 1);
if (PTR_ERR(priv->clks[1]) == -ENOENT)
priv->clks[1] = NULL;
else if (IS_ERR(priv->clks[1]))
@@ -454,7 +449,7 @@ static void usbhsc_hotplug(struct usbhs_priv *priv)
/*
* get vbus status from platform
*/
- enable = usbhs_platform_call(priv, get_vbus, pdev);
+ enable = usbhs_mod_info_call(priv, get_vbus, pdev);
/*
* get id from platform
@@ -479,7 +474,7 @@ static void usbhsc_hotplug(struct usbhs_priv *priv)
dev_dbg(&pdev->dev, "%s enable\n", __func__);
/* power on */
- if (usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL))
+ if (usbhs_get_dparam(priv, runtime_pwctrl))
usbhsc_power_ctrl(priv, enable);
/* bus init */
@@ -499,7 +494,7 @@ static void usbhsc_hotplug(struct usbhs_priv *priv)
usbhsc_bus_init(priv);
/* power off */
- if (usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL))
+ if (usbhs_get_dparam(priv, runtime_pwctrl))
usbhsc_power_ctrl(priv, enable);
usbhs_mod_change(priv, -1);
@@ -520,7 +515,7 @@ static void usbhsc_notify_hotplug(struct work_struct *work)
usbhsc_hotplug(priv);
}
-static int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev)
+int usbhsc_schedule_notify_hotplug(struct platform_device *pdev)
{
struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
int delay = usbhs_get_dparam(priv, detection_delay);
@@ -541,115 +536,86 @@ static int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev)
static const struct of_device_id usbhs_of_match[] = {
{
.compatible = "renesas,usbhs-r8a774c0",
- .data = (void *)USBHS_TYPE_RCAR_GEN3_WITH_PLL,
+ .data = &usbhs_rcar_gen3_with_pll_plat_info,
},
{
.compatible = "renesas,usbhs-r8a7790",
- .data = (void *)USBHS_TYPE_RCAR_GEN2,
+ .data = &usbhs_rcar_gen2_plat_info,
},
{
.compatible = "renesas,usbhs-r8a7791",
- .data = (void *)USBHS_TYPE_RCAR_GEN2,
+ .data = &usbhs_rcar_gen2_plat_info,
},
{
.compatible = "renesas,usbhs-r8a7794",
- .data = (void *)USBHS_TYPE_RCAR_GEN2,
+ .data = &usbhs_rcar_gen2_plat_info,
},
{
.compatible = "renesas,usbhs-r8a7795",
- .data = (void *)USBHS_TYPE_RCAR_GEN3,
+ .data = &usbhs_rcar_gen3_plat_info,
},
{
.compatible = "renesas,usbhs-r8a7796",
- .data = (void *)USBHS_TYPE_RCAR_GEN3,
+ .data = &usbhs_rcar_gen3_plat_info,
},
{
.compatible = "renesas,usbhs-r8a77990",
- .data = (void *)USBHS_TYPE_RCAR_GEN3_WITH_PLL,
+ .data = &usbhs_rcar_gen3_with_pll_plat_info,
},
{
.compatible = "renesas,usbhs-r8a77995",
- .data = (void *)USBHS_TYPE_RCAR_GEN3_WITH_PLL,
+ .data = &usbhs_rcar_gen3_with_pll_plat_info,
},
{
.compatible = "renesas,rcar-gen2-usbhs",
- .data = (void *)USBHS_TYPE_RCAR_GEN2,
+ .data = &usbhs_rcar_gen2_plat_info,
},
{
.compatible = "renesas,rcar-gen3-usbhs",
- .data = (void *)USBHS_TYPE_RCAR_GEN3,
+ .data = &usbhs_rcar_gen3_plat_info,
},
{
.compatible = "renesas,rza1-usbhs",
- .data = (void *)USBHS_TYPE_RZA1,
+ .data = &usbhs_rza1_plat_info,
+ },
+ {
+ .compatible = "renesas,rza2-usbhs",
+ .data = &usbhs_rza2_plat_info,
},
{ },
};
MODULE_DEVICE_TABLE(of, usbhs_of_match);
-static struct renesas_usbhs_platform_info *usbhs_parse_dt(struct device *dev)
-{
- struct renesas_usbhs_platform_info *info;
- struct renesas_usbhs_driver_param *dparam;
- u32 tmp;
- int gpio;
-
- info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
- if (!info)
- return NULL;
-
- dparam = &info->driver_param;
- dparam->type = (uintptr_t)of_device_get_match_data(dev);
- if (!of_property_read_u32(dev->of_node, "renesas,buswait", &tmp))
- dparam->buswait_bwait = tmp;
- gpio = of_get_named_gpio_flags(dev->of_node, "renesas,enable-gpio", 0,
- NULL);
- if (gpio > 0)
- dparam->enable_gpio = gpio;
-
- if (dparam->type == USBHS_TYPE_RCAR_GEN2 ||
- dparam->type == USBHS_TYPE_RCAR_GEN3 ||
- dparam->type == USBHS_TYPE_RCAR_GEN3_WITH_PLL) {
- dparam->has_usb_dmac = 1;
- dparam->pipe_configs = usbhsc_new_pipe;
- dparam->pipe_size = ARRAY_SIZE(usbhsc_new_pipe);
- }
-
- if (dparam->type == USBHS_TYPE_RZA1) {
- dparam->pipe_configs = usbhsc_new_pipe;
- dparam->pipe_size = ARRAY_SIZE(usbhsc_new_pipe);
- }
-
- return info;
-}
-
static int usbhs_probe(struct platform_device *pdev)
{
- struct renesas_usbhs_platform_info *info = renesas_usbhs_get_info(pdev);
- struct renesas_usbhs_driver_callback *dfunc;
+ const struct renesas_usbhs_platform_info *info;
struct usbhs_priv *priv;
struct resource *res, *irq_res;
- int ret;
+ struct device *dev = &pdev->dev;
+ int ret, gpio;
+ u32 tmp;
/* check device node */
- if (pdev->dev.of_node)
- info = pdev->dev.platform_data = usbhs_parse_dt(&pdev->dev);
+ if (dev_of_node(dev))
+ info = of_device_get_match_data(dev);
+ else
+ info = renesas_usbhs_get_info(pdev);
/* check platform information */
if (!info) {
- dev_err(&pdev->dev, "no platform information\n");
+ dev_err(dev, "no platform information\n");
return -EINVAL;
}
/* platform data */
irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!irq_res) {
- dev_err(&pdev->dev, "Not enough Renesas USB platform resources.\n");
+ dev_err(dev, "Not enough Renesas USB platform resources.\n");
return -ENODEV;
}
/* usb private data */
- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -658,13 +624,13 @@ static int usbhs_probe(struct platform_device *pdev)
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
- if (of_property_read_bool(pdev->dev.of_node, "extcon")) {
- priv->edev = extcon_get_edev_by_phandle(&pdev->dev, 0);
+ if (of_property_read_bool(dev_of_node(dev), "extcon")) {
+ priv->edev = extcon_get_edev_by_phandle(dev, 0);
if (IS_ERR(priv->edev))
return PTR_ERR(priv->edev);
}
- priv->rsts = devm_reset_control_array_get_optional_shared(&pdev->dev);
+ priv->rsts = devm_reset_control_array_get_optional_shared(dev);
if (IS_ERR(priv->rsts))
return PTR_ERR(priv->rsts);
@@ -672,50 +638,35 @@ static int usbhs_probe(struct platform_device *pdev)
* care platform info
*/
- memcpy(&priv->dparam,
- &info->driver_param,
- sizeof(struct renesas_usbhs_driver_param));
+ priv->dparam = info->driver_param;
- switch (priv->dparam.type) {
- case USBHS_TYPE_RCAR_GEN2:
- priv->pfunc = usbhs_rcar2_ops;
- break;
- case USBHS_TYPE_RCAR_GEN3:
- priv->pfunc = usbhs_rcar3_ops;
- break;
- case USBHS_TYPE_RCAR_GEN3_WITH_PLL:
- priv->pfunc = usbhs_rcar3_with_pll_ops;
- break;
- case USBHS_TYPE_RZA1:
- priv->pfunc = usbhs_rza1_ops;
- break;
- default:
- if (!info->platform_callback.get_id) {
- dev_err(&pdev->dev, "no platform callbacks");
- return -EINVAL;
- }
- memcpy(&priv->pfunc,
- &info->platform_callback,
- sizeof(struct renesas_usbhs_platform_callback));
- break;
+ if (!info->platform_callback.get_id) {
+ dev_err(dev, "no platform callbacks\n");
+ return -EINVAL;
}
-
- /* set driver callback functions for platform */
- dfunc = &info->driver_callback;
- dfunc->notify_hotplug = usbhsc_drvcllbck_notify_hotplug;
+ priv->pfunc = &info->platform_callback;
/* set default param if platform doesn't have */
- if (!priv->dparam.pipe_configs) {
+ if (usbhs_get_dparam(priv, has_new_pipe_configs)) {
+ priv->dparam.pipe_configs = usbhsc_new_pipe;
+ priv->dparam.pipe_size = ARRAY_SIZE(usbhsc_new_pipe);
+ } else if (!priv->dparam.pipe_configs) {
priv->dparam.pipe_configs = usbhsc_default_pipe;
priv->dparam.pipe_size = ARRAY_SIZE(usbhsc_default_pipe);
}
if (!priv->dparam.pio_dma_border)
priv->dparam.pio_dma_border = 64; /* 64byte */
+ if (!of_property_read_u32(dev_of_node(dev), "renesas,buswait", &tmp))
+ priv->dparam.buswait_bwait = tmp;
+ gpio = of_get_named_gpio_flags(dev_of_node(dev), "renesas,enable-gpio",
+ 0, NULL);
+ if (gpio > 0)
+ priv->dparam.enable_gpio = gpio;
/* FIXME */
/* runtime power control ? */
- if (priv->pfunc.get_vbus)
- usbhsc_flags_set(priv, USBHSF_RUNTIME_PWCTRL);
+ if (priv->pfunc->get_vbus)
+ usbhs_get_dparam(priv, runtime_pwctrl) = 1;
/*
* priv settings
@@ -747,7 +698,7 @@ static int usbhs_probe(struct platform_device *pdev)
if (ret)
goto probe_fail_rst;
- ret = usbhsc_clk_get(&pdev->dev, priv);
+ ret = usbhsc_clk_get(dev, priv);
if (ret)
goto probe_fail_clks;
@@ -763,8 +714,7 @@ static int usbhs_probe(struct platform_device *pdev)
ret = !gpio_get_value(priv->dparam.enable_gpio);
gpio_free(priv->dparam.enable_gpio);
if (ret) {
- dev_warn(&pdev->dev,
- "USB function not selected (GPIO %d)\n",
+ dev_warn(dev, "USB function not selected (GPIO %d)\n",
priv->dparam.enable_gpio);
ret = -ENOTSUPP;
goto probe_end_mod_exit;
@@ -780,7 +730,7 @@ static int usbhs_probe(struct platform_device *pdev)
*/
ret = usbhs_platform_call(priv, hardware_init, pdev);
if (ret < 0) {
- dev_err(&pdev->dev, "platform init failed.\n");
+ dev_err(dev, "platform init failed.\n");
goto probe_end_mod_exit;
}
@@ -788,18 +738,20 @@ static int usbhs_probe(struct platform_device *pdev)
usbhs_platform_call(priv, phy_reset, pdev);
/* power control */
- pm_runtime_enable(&pdev->dev);
- if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL)) {
+ pm_runtime_enable(dev);
+ if (!usbhs_get_dparam(priv, runtime_pwctrl)) {
usbhsc_power_ctrl(priv, 1);
usbhs_mod_autonomy_mode(priv);
+ } else {
+ usbhs_mod_non_autonomy_mode(priv);
}
/*
* manual call notify_hotplug for cold plug
*/
- usbhsc_drvcllbck_notify_hotplug(pdev);
+ usbhsc_schedule_notify_hotplug(pdev);
- dev_info(&pdev->dev, "probed\n");
+ dev_info(dev, "probed\n");
return ret;
@@ -814,7 +766,7 @@ probe_end_fifo_exit:
probe_end_pipe_exit:
usbhs_pipe_remove(priv);
- dev_info(&pdev->dev, "probe failed (%d)\n", ret);
+ dev_info(dev, "probe failed (%d)\n", ret);
return ret;
}
@@ -822,15 +774,11 @@ probe_end_pipe_exit:
static int usbhs_remove(struct platform_device *pdev)
{
struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
- struct renesas_usbhs_platform_info *info = renesas_usbhs_get_info(pdev);
- struct renesas_usbhs_driver_callback *dfunc = &info->driver_callback;
dev_dbg(&pdev->dev, "usb remove\n");
- dfunc->notify_hotplug = NULL;
-
/* power off */
- if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL))
+ if (!usbhs_get_dparam(priv, runtime_pwctrl))
usbhsc_power_ctrl(priv, 0);
pm_runtime_disable(&pdev->dev);
@@ -855,7 +803,7 @@ static __maybe_unused int usbhsc_suspend(struct device *dev)
usbhs_mod_change(priv, -1);
}
- if (mod || !usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL))
+ if (mod || !usbhs_get_dparam(priv, runtime_pwctrl))
usbhsc_power_ctrl(priv, 0);
return 0;
@@ -866,14 +814,14 @@ static __maybe_unused int usbhsc_resume(struct device *dev)
struct usbhs_priv *priv = dev_get_drvdata(dev);
struct platform_device *pdev = usbhs_priv_to_pdev(priv);
- if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL)) {
+ if (!usbhs_get_dparam(priv, runtime_pwctrl)) {
usbhsc_power_ctrl(priv, 1);
usbhs_mod_autonomy_mode(priv);
}
usbhs_platform_call(priv, phy_reset, pdev);
- usbhsc_drvcllbck_notify_hotplug(pdev);
+ usbhsc_schedule_notify_hotplug(pdev);
return 0;
}
diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h
index 3777af848a35..d1a0a35ecfff 100644
--- a/drivers/usb/renesas_usbhs/common.h
+++ b/drivers/usb/renesas_usbhs/common.h
@@ -3,6 +3,7 @@
* Renesas USB driver
*
* Copyright (C) 2011 Renesas Solutions Corp.
+ * Copyright (C) 2019 Renesas Electronics Corporation
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*/
#ifndef RENESAS_USB_DRIVER_H
@@ -104,6 +105,7 @@ struct usbhs_priv;
/* SYSCFG */
#define SCKE (1 << 10) /* USB Module Clock Enable */
+#define CNEN (1 << 8) /* Single-ended receiver operation Enable */
#define HSE (1 << 7) /* High-Speed Operation Enable */
#define DCFM (1 << 6) /* Controller Function Select */
#define DRPD (1 << 5) /* D+ Line/D- Line Resistance Control */
@@ -250,7 +252,7 @@ struct usbhs_priv {
unsigned int irq;
unsigned long irqflags;
- struct renesas_usbhs_platform_callback pfunc;
+ const struct renesas_usbhs_platform_callback *pfunc;
struct renesas_usbhs_driver_param dparam;
struct delayed_work notify_hotplug_work;
@@ -260,8 +262,6 @@ struct usbhs_priv {
spinlock_t lock;
- u32 flags;
-
/*
* module control
*/
@@ -292,6 +292,8 @@ void usbhs_bset(struct usbhs_priv *priv, u32 reg, u16 mask, u16 data);
#define usbhs_lock(p, f) spin_lock_irqsave(usbhs_priv_to_lock(p), f)
#define usbhs_unlock(p, f) spin_unlock_irqrestore(usbhs_priv_to_lock(p), f)
+int usbhs_get_id_as_gadget(struct platform_device *pdev);
+
/*
* sysconfig
*/
@@ -313,6 +315,7 @@ void usbhs_bus_send_sof_enable(struct usbhs_priv *priv);
void usbhs_bus_send_reset(struct usbhs_priv *priv);
int usbhs_bus_get_speed(struct usbhs_priv *priv);
int usbhs_vbus_ctrl(struct usbhs_priv *priv, int enable);
+int usbhsc_schedule_notify_hotplug(struct platform_device *pdev);
/*
* frame
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c
index 39fa2fc1b8b7..2a01ceb71641 100644
--- a/drivers/usb/renesas_usbhs/fifo.c
+++ b/drivers/usb/renesas_usbhs/fifo.c
@@ -3,6 +3,7 @@
* Renesas USB driver
*
* Copyright (C) 2011 Renesas Solutions Corp.
+ * Copyright (C) 2019 Renesas Electronics Corporation
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*/
#include <linux/delay.h>
@@ -12,7 +13,6 @@
#include "pipe.h"
#define usbhsf_get_cfifo(p) (&((p)->fifo_info.cfifo))
-#define usbhsf_is_cfifo(p, f) (usbhsf_get_cfifo(p) == f)
#define usbhsf_fifo_is_busy(f) ((f)->pipe) /* see usbhs_pipe_select_fifo */
@@ -325,10 +325,7 @@ static int usbhsf_fifo_select(struct usbhs_pipe *pipe,
}
/* "base" will be used below */
- if (usbhs_get_dparam(priv, has_sudmac) && !usbhsf_is_cfifo(priv, fifo))
- usbhs_write(priv, fifo->sel, base);
- else
- usbhs_write(priv, fifo->sel, base | MBW_32);
+ usbhs_write(priv, fifo->sel, base | MBW_32);
/* check ISEL and CURPIPE value */
while (timeout--) {
@@ -543,8 +540,13 @@ static int usbhsf_pio_try_push(struct usbhs_pkt *pkt, int *is_done)
}
/* the rest operation */
- for (i = 0; i < len; i++)
- iowrite8(buf[i], addr + (0x03 - (i & 0x03)));
+ if (usbhs_get_dparam(priv, cfifo_byte_addr)) {
+ for (i = 0; i < len; i++)
+ iowrite8(buf[i], addr + (i & 0x03));
+ } else {
+ for (i = 0; i < len; i++)
+ iowrite8(buf[i], addr + (0x03 - (i & 0x03)));
+ }
/*
* variable update
@@ -802,9 +804,8 @@ static int __usbhsf_dma_map_ctrl(struct usbhs_pkt *pkt, int map)
}
static void usbhsf_dma_complete(void *arg);
-static void xfer_work(struct work_struct *work)
+static void usbhsf_dma_xfer_preparing(struct usbhs_pkt *pkt)
{
- struct usbhs_pkt *pkt = container_of(work, struct usbhs_pkt, work);
struct usbhs_pipe *pipe = pkt->pipe;
struct usbhs_fifo *fifo;
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
@@ -812,12 +813,10 @@ static void xfer_work(struct work_struct *work)
struct dma_chan *chan;
struct device *dev = usbhs_priv_to_dev(priv);
enum dma_transfer_direction dir;
- unsigned long flags;
- usbhs_lock(priv, flags);
fifo = usbhs_pipe_to_fifo(pipe);
if (!fifo)
- goto xfer_work_end;
+ return;
chan = usbhsf_dma_chan_get(fifo, pkt);
dir = usbhs_pipe_is_dir_in(pipe) ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
@@ -826,7 +825,7 @@ static void xfer_work(struct work_struct *work)
pkt->trans, dir,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc)
- goto xfer_work_end;
+ return;
desc->callback = usbhsf_dma_complete;
desc->callback_param = pipe;
@@ -834,7 +833,7 @@ static void xfer_work(struct work_struct *work)
pkt->cookie = dmaengine_submit(desc);
if (pkt->cookie < 0) {
dev_err(dev, "Failed to submit dma descriptor\n");
- goto xfer_work_end;
+ return;
}
dev_dbg(dev, " %s %d (%d/ %d)\n",
@@ -845,8 +844,17 @@ static void xfer_work(struct work_struct *work)
dma_async_issue_pending(chan);
usbhsf_dma_start(pipe, fifo);
usbhs_pipe_enable(pipe);
+}
-xfer_work_end:
+static void xfer_work(struct work_struct *work)
+{
+ struct usbhs_pkt *pkt = container_of(work, struct usbhs_pkt, work);
+ struct usbhs_pipe *pipe = pkt->pipe;
+ struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
+ unsigned long flags;
+
+ usbhs_lock(priv, flags);
+ usbhsf_dma_xfer_preparing(pkt);
usbhs_unlock(priv, flags);
}
@@ -899,8 +907,13 @@ static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done)
pkt->trans = len;
usbhsf_tx_irq_ctrl(pipe, 0);
- INIT_WORK(&pkt->work, xfer_work);
- schedule_work(&pkt->work);
+ /* FIXME: Workaound for usb dmac that driver can be used in atomic */
+ if (usbhs_get_dparam(priv, has_usb_dmac)) {
+ usbhsf_dma_xfer_preparing(pkt);
+ } else {
+ INIT_WORK(&pkt->work, xfer_work);
+ schedule_work(&pkt->work);
+ }
return 0;
@@ -1006,8 +1019,7 @@ static int usbhsf_dma_prepare_pop_with_usb_dmac(struct usbhs_pkt *pkt,
pkt->trans = pkt->length;
- INIT_WORK(&pkt->work, xfer_work);
- schedule_work(&pkt->work);
+ usbhsf_dma_xfer_preparing(pkt);
return 0;
@@ -1276,7 +1288,7 @@ static void usbhsf_dma_init(struct usbhs_priv *priv, struct usbhs_fifo *fifo,
{
struct device *dev = usbhs_priv_to_dev(priv);
- if (dev->of_node)
+ if (dev_of_node(dev))
usbhsf_dma_init_dt(dev, fifo, channel);
else
usbhsf_dma_init_pdev(fifo);
diff --git a/drivers/usb/renesas_usbhs/mod.c b/drivers/usb/renesas_usbhs/mod.c
index 7475c4f64724..10fc65596014 100644
--- a/drivers/usb/renesas_usbhs/mod.c
+++ b/drivers/usb/renesas_usbhs/mod.c
@@ -3,6 +3,7 @@
* Renesas USB driver
*
* Copyright (C) 2011 Renesas Solutions Corp.
+ * Copyright (C) 2019 Renesas Electronics Corporation
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*/
#include <linux/interrupt.h>
@@ -10,15 +11,6 @@
#include "common.h"
#include "mod.h"
-#define usbhs_priv_to_modinfo(priv) (&priv->mod_info)
-#define usbhs_mod_info_call(priv, func, param...) \
-({ \
- struct usbhs_mod_info *info; \
- info = usbhs_priv_to_modinfo(priv); \
- !info->func ? 0 : \
- info->func(param); \
-})
-
/*
* autonomy
*
@@ -41,7 +33,7 @@ static int usbhsm_autonomy_irq_vbus(struct usbhs_priv *priv,
{
struct platform_device *pdev = usbhs_priv_to_pdev(priv);
- renesas_usbhs_call_notify_hotplug(pdev);
+ usbhsc_schedule_notify_hotplug(pdev);
return 0;
}
@@ -50,12 +42,19 @@ void usbhs_mod_autonomy_mode(struct usbhs_priv *priv)
{
struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
- info->irq_vbus = usbhsm_autonomy_irq_vbus;
- priv->pfunc.get_vbus = usbhsm_autonomy_get_vbus;
+ info->irq_vbus = usbhsm_autonomy_irq_vbus;
+ info->get_vbus = usbhsm_autonomy_get_vbus;
usbhs_irq_callback_update(priv, NULL);
}
+void usbhs_mod_non_autonomy_mode(struct usbhs_priv *priv)
+{
+ struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
+
+ info->get_vbus = priv->pfunc->get_vbus;
+}
+
/*
* host / gadget functions
*
diff --git a/drivers/usb/renesas_usbhs/mod.h b/drivers/usb/renesas_usbhs/mod.h
index a4a61d6b82a1..65dc19ca528e 100644
--- a/drivers/usb/renesas_usbhs/mod.h
+++ b/drivers/usb/renesas_usbhs/mod.h
@@ -3,6 +3,7 @@
* Renesas USB driver
*
* Copyright (C) 2011 Renesas Solutions Corp.
+ * Copyright (C) 2019 Renesas Electronics Corporation
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*/
#ifndef RENESAS_USB_MOD_H
@@ -84,15 +85,20 @@ struct usbhs_mod_info {
/*
* INTSTS0 :: VBINT
*
- * This function will be used as autonomy mode
- * when platform cannot call notify_hotplug.
+ * This function will be used as autonomy mode (runtime_pwctrl == 0)
+ * when the platform doesn't have own get_vbus function.
*
- * This callback cannot be member of "struct usbhs_mod"
- * because it will be used even though
- * host/gadget has not been selected.
+ * This callback cannot be member of "struct usbhs_mod" because it
+ * will be used even though host/gadget has not been selected.
*/
int (*irq_vbus)(struct usbhs_priv *priv,
struct usbhs_irq_state *irq_state);
+
+ /*
+ * This function will be used on any gadget mode. To simplify the code,
+ * this member is in here.
+ */
+ int (*get_vbus)(struct platform_device *pdev);
};
/*
@@ -107,6 +113,7 @@ int usbhs_mod_probe(struct usbhs_priv *priv);
void usbhs_mod_remove(struct usbhs_priv *priv);
void usbhs_mod_autonomy_mode(struct usbhs_priv *priv);
+void usbhs_mod_non_autonomy_mode(struct usbhs_priv *priv);
/*
* status functions
@@ -129,6 +136,15 @@ void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod);
mod->func(param); \
})
+#define usbhs_priv_to_modinfo(priv) (&priv->mod_info)
+#define usbhs_mod_info_call(priv, func, param...) \
+({ \
+ struct usbhs_mod_info *info; \
+ info = usbhs_priv_to_modinfo(priv); \
+ !info->func ? 0 : \
+ info->func(param); \
+})
+
/*
* host / gadget control
*/
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index 59cac40aafcc..4d571a5205e2 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -3,6 +3,7 @@
* Renesas USB driver
*
* Copyright (C) 2011 Renesas Solutions Corp.
+ * Copyright (C) 2019 Renesas Electronics Corporation
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*/
#include <linux/delay.h>
@@ -914,8 +915,8 @@ static void usbhs_mod_phy_mode(struct usbhs_priv *priv)
{
struct usbhs_mod_info *info = &priv->mod_info;
- info->irq_vbus = NULL;
- priv->pfunc.get_vbus = usbhsm_phy_get_vbus;
+ info->irq_vbus = NULL;
+ info->get_vbus = usbhsm_phy_get_vbus;
usbhs_irq_callback_update(priv, NULL);
}
@@ -1023,7 +1024,7 @@ static int usbhsg_vbus_session(struct usb_gadget *gadget, int is_active)
gpriv->vbus_active = !!is_active;
- renesas_usbhs_call_notify_hotplug(pdev);
+ usbhsc_schedule_notify_hotplug(pdev);
return 0;
}
diff --git a/drivers/usb/renesas_usbhs/rcar2.c b/drivers/usb/renesas_usbhs/rcar2.c
index 0027092b1118..440d213e1749 100644
--- a/drivers/usb/renesas_usbhs/rcar2.c
+++ b/drivers/usb/renesas_usbhs/rcar2.c
@@ -3,6 +3,7 @@
* Renesas USB driver R-Car Gen. 2 initialization and power control
*
* Copyright (C) 2014 Ulrich Hecht
+ * Copyright (C) 2019 Renesas Electronics Corporation
*/
#include <linux/gpio.h>
@@ -62,14 +63,15 @@ static int usbhs_rcar2_power_ctrl(struct platform_device *pdev,
return retval;
}
-static int usbhs_rcar2_get_id(struct platform_device *pdev)
-{
- return USBHS_GADGET;
-}
-
-const struct renesas_usbhs_platform_callback usbhs_rcar2_ops = {
- .hardware_init = usbhs_rcar2_hardware_init,
- .hardware_exit = usbhs_rcar2_hardware_exit,
- .power_ctrl = usbhs_rcar2_power_ctrl,
- .get_id = usbhs_rcar2_get_id,
+const struct renesas_usbhs_platform_info usbhs_rcar_gen2_plat_info = {
+ .platform_callback = {
+ .hardware_init = usbhs_rcar2_hardware_init,
+ .hardware_exit = usbhs_rcar2_hardware_exit,
+ .power_ctrl = usbhs_rcar2_power_ctrl,
+ .get_id = usbhs_get_id_as_gadget,
+ },
+ .driver_param = {
+ .has_usb_dmac = 1,
+ .has_new_pipe_configs = 1,
+ },
};
diff --git a/drivers/usb/renesas_usbhs/rcar2.h b/drivers/usb/renesas_usbhs/rcar2.h
index 45e3526cedeb..7d88732c5bff 100644
--- a/drivers/usb/renesas_usbhs/rcar2.h
+++ b/drivers/usb/renesas_usbhs/rcar2.h
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
#include "common.h"
-extern const struct renesas_usbhs_platform_callback
- usbhs_rcar2_ops;
+extern const struct renesas_usbhs_platform_info usbhs_rcar_gen2_plat_info;
diff --git a/drivers/usb/renesas_usbhs/rcar3.c b/drivers/usb/renesas_usbhs/rcar3.c
index 5e730e9b40ef..c181b2a0b9d3 100644
--- a/drivers/usb/renesas_usbhs/rcar3.c
+++ b/drivers/usb/renesas_usbhs/rcar3.c
@@ -2,7 +2,7 @@
/*
* Renesas USB driver R-Car Gen. 3 initialization and power control
*
- * Copyright (C) 2016 Renesas Electronics Corporation
+ * Copyright (C) 2016-2019 Renesas Electronics Corporation
*/
#include <linux/delay.h>
@@ -95,17 +95,26 @@ static int usbhs_rcar3_power_and_pll_ctrl(struct platform_device *pdev,
return 0;
}
-static int usbhs_rcar3_get_id(struct platform_device *pdev)
-{
- return USBHS_GADGET;
-}
-
-const struct renesas_usbhs_platform_callback usbhs_rcar3_ops = {
- .power_ctrl = usbhs_rcar3_power_ctrl,
- .get_id = usbhs_rcar3_get_id,
+const struct renesas_usbhs_platform_info usbhs_rcar_gen3_plat_info = {
+ .platform_callback = {
+ .power_ctrl = usbhs_rcar3_power_ctrl,
+ .get_id = usbhs_get_id_as_gadget,
+ },
+ .driver_param = {
+ .has_usb_dmac = 1,
+ .multi_clks = 1,
+ .has_new_pipe_configs = 1,
+ },
};
-const struct renesas_usbhs_platform_callback usbhs_rcar3_with_pll_ops = {
- .power_ctrl = usbhs_rcar3_power_and_pll_ctrl,
- .get_id = usbhs_rcar3_get_id,
+const struct renesas_usbhs_platform_info usbhs_rcar_gen3_with_pll_plat_info = {
+ .platform_callback = {
+ .power_ctrl = usbhs_rcar3_power_and_pll_ctrl,
+ .get_id = usbhs_get_id_as_gadget,
+ },
+ .driver_param = {
+ .has_usb_dmac = 1,
+ .multi_clks = 1,
+ .has_new_pipe_configs = 1,
+ },
};
diff --git a/drivers/usb/renesas_usbhs/rcar3.h b/drivers/usb/renesas_usbhs/rcar3.h
index 49e535a31771..c7c5ec1e3af2 100644
--- a/drivers/usb/renesas_usbhs/rcar3.h
+++ b/drivers/usb/renesas_usbhs/rcar3.h
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
#include "common.h"
-extern const struct renesas_usbhs_platform_callback usbhs_rcar3_ops;
-extern const struct renesas_usbhs_platform_callback usbhs_rcar3_with_pll_ops;
+extern const struct renesas_usbhs_platform_info usbhs_rcar_gen3_plat_info;
+extern const struct renesas_usbhs_platform_info
+ usbhs_rcar_gen3_with_pll_plat_info;
diff --git a/drivers/usb/renesas_usbhs/rza.c b/drivers/usb/renesas_usbhs/rza.c
index 8c739bd24acd..24de64edb674 100644
--- a/drivers/usb/renesas_usbhs/rza.c
+++ b/drivers/usb/renesas_usbhs/rza.c
@@ -3,7 +3,7 @@
* Renesas USB driver RZ/A initialization and power control
*
* Copyright (C) 2018 Chris Brandt
- * Copyright (C) 2018 Renesas Electronics Corporation
+ * Copyright (C) 2018-2019 Renesas Electronics Corporation
*/
#include <linux/delay.h>
@@ -41,12 +41,12 @@ static int usbhs_rza1_hardware_init(struct platform_device *pdev)
return 0;
}
-static int usbhs_rza_get_id(struct platform_device *pdev)
-{
- return USBHS_GADGET;
-}
-
-const struct renesas_usbhs_platform_callback usbhs_rza1_ops = {
- .hardware_init = usbhs_rza1_hardware_init,
- .get_id = usbhs_rza_get_id,
+const struct renesas_usbhs_platform_info usbhs_rza1_plat_info = {
+ .platform_callback = {
+ .hardware_init = usbhs_rza1_hardware_init,
+ .get_id = usbhs_get_id_as_gadget,
+ },
+ .driver_param = {
+ .has_new_pipe_configs = 1,
+ },
};
diff --git a/drivers/usb/renesas_usbhs/rza.h b/drivers/usb/renesas_usbhs/rza.h
index ca917ca54f6d..1ca42a6fd480 100644
--- a/drivers/usb/renesas_usbhs/rza.h
+++ b/drivers/usb/renesas_usbhs/rza.h
@@ -1,4 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
#include "common.h"
-extern const struct renesas_usbhs_platform_callback usbhs_rza1_ops;
+extern const struct renesas_usbhs_platform_info usbhs_rza1_plat_info;
+extern const struct renesas_usbhs_platform_info usbhs_rza2_plat_info;
diff --git a/drivers/usb/renesas_usbhs/rza2.c b/drivers/usb/renesas_usbhs/rza2.c
new file mode 100644
index 000000000000..021749594389
--- /dev/null
+++ b/drivers/usb/renesas_usbhs/rza2.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas USB driver RZ/A2 initialization and power control
+ *
+ * Copyright (C) 2019 Chris Brandt
+ * Copyright (C) 2019 Renesas Electronics Corporation
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of_device.h>
+#include <linux/phy/phy.h>
+#include "common.h"
+#include "rza.h"
+
+static int usbhs_rza2_hardware_init(struct platform_device *pdev)
+{
+ struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
+ struct phy *phy = phy_get(&pdev->dev, "usb");
+
+ if (IS_ERR(phy))
+ return PTR_ERR(phy);
+
+ priv->phy = phy;
+ return 0;
+}
+
+static int usbhs_rza2_hardware_exit(struct platform_device *pdev)
+{
+ struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
+
+ phy_put(priv->phy);
+ priv->phy = NULL;
+
+ return 0;
+}
+
+static int usbhs_rza2_power_ctrl(struct platform_device *pdev,
+ void __iomem *base, int enable)
+{
+ struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
+ int retval = 0;
+
+ if (!priv->phy)
+ return -ENODEV;
+
+ if (enable) {
+ retval = phy_init(priv->phy);
+ usbhs_bset(priv, SUSPMODE, SUSPM, SUSPM);
+ udelay(100); /* Wait for PLL to become stable */
+ if (!retval)
+ retval = phy_power_on(priv->phy);
+ } else {
+ usbhs_bset(priv, SUSPMODE, SUSPM, 0);
+ phy_power_off(priv->phy);
+ phy_exit(priv->phy);
+ }
+
+ return retval;
+}
+
+const struct renesas_usbhs_platform_info usbhs_rza2_plat_info = {
+ .platform_callback = {
+ .hardware_init = usbhs_rza2_hardware_init,
+ .hardware_exit = usbhs_rza2_hardware_exit,
+ .power_ctrl = usbhs_rza2_power_ctrl,
+ .get_id = usbhs_get_id_as_gadget,
+ },
+ .driver_param = {
+ .has_cnen = 1,
+ .cfifo_byte_addr = 1,
+ .has_new_pipe_configs = 1,
+ },
+};
diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c
index f45d8df5cfb8..86defca6623e 100644
--- a/drivers/usb/roles/class.c
+++ b/drivers/usb/roles/class.c
@@ -101,7 +101,7 @@ static void *usb_role_switch_match(struct device_connection *con, int ep,
struct device *dev;
if (con->fwnode) {
- if (!fwnode_property_present(con->fwnode, con->id))
+ if (con->id && !fwnode_property_present(con->fwnode, con->id))
return NULL;
dev = class_find_device(role_class, NULL, con->fwnode,
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 7d031911d04e..67279c6bce33 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -11,7 +11,7 @@ menuconfig USB_SERIAL
ports, or acts like a serial device, and you want to connect it to
your USB bus.
- Please read <file:Documentation/usb/usb-serial.txt> for more
+ Please read <file:Documentation/usb/usb-serial.rst> for more
information on the specifics of the different devices that are
supported, and on how to use them.
@@ -47,7 +47,7 @@ config USB_SERIAL_GENERIC
bool "USB Generic Serial Driver"
help
Say Y here if you want to use the generic USB serial driver. Please
- read <file:Documentation/usb/usb-serial.txt> for more information on
+ read <file:Documentation/usb/usb-serial.rst> for more information on
using this driver. It is recommended that the "USB Serial converter
support" be compiled as a module for this driver to be used
properly.
@@ -163,7 +163,7 @@ config USB_SERIAL_EMPEG
help
Say Y here if you want to connect to your Empeg empeg-car Mark I/II
mp3 player via USB. The driver uses a single ttyUSB{0,1,2,...}
- device node. See <file:Documentation/usb/usb-serial.txt> for more
+ device node. See <file:Documentation/usb/usb-serial.rst> for more
tidbits of information.
To compile this driver as a module, choose M here: the
@@ -199,7 +199,7 @@ config USB_SERIAL_IPAQ
Say Y here if you want to connect to your Compaq iPAQ, HP Jornada
or any other PDA running Windows CE 3.0 or PocketPC 2002
using a USB cradle/cable. For information on using the driver,
- read <file:Documentation/usb/usb-serial.txt>.
+ read <file:Documentation/usb/usb-serial.rst>.
To compile this driver as a module, choose M here: the
module will be called ipaq.
@@ -334,7 +334,7 @@ config USB_SERIAL_KLSI
adapter sold by Palm Inc. for use with their Palm III and Palm V
series PDAs.
- Please read <file:Documentation/usb/usb-serial.txt> for more
+ Please read <file:Documentation/usb/usb-serial.rst> for more
information.
To compile this driver as a module, choose M here: the
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index c1235d5b9fba..9bb123ab9bc9 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -10,7 +10,7 @@
* and associated source files. Please see the usb/serial files for
* individual credits and copyrights.
*
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
* driver
*
* TODO:
diff --git a/drivers/usb/serial/belkin_sa.h b/drivers/usb/serial/belkin_sa.h
index 51bc06287603..a13a98d284f2 100644
--- a/drivers/usb/serial/belkin_sa.h
+++ b/drivers/usb/serial/belkin_sa.h
@@ -9,7 +9,7 @@
* and associated source files. Please see the usb/serial files for
* individual credits and copyrights.
*
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
* driver
*
* 12-Mar-2001 gkh
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index 72d3ae1ebc64..216edd5826ca 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -7,7 +7,7 @@
* Copyright (C) 2003,2004
* Neil Whelchel (koyama@firstlight.net)
*
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
* driver
*
* See http://geocities.com/i0xox0i for information on this driver and the
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index d680bec62547..405e835e93dd 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -8,7 +8,7 @@
* Copyright (C) 1999 - 2001
* Greg Kroah-Hartman (greg@kroah.com)
*
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
* driver
*/
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 1d8461ae2c34..4b3a049561f3 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -10,7 +10,7 @@
* Copyright (C) 2002
* Kuba Ober (kuba@mareimbrium.org)
*
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
* driver
*
* See http://ftdi-usb-sio.sourceforge.net for up to date testing info
@@ -1029,6 +1029,7 @@ static const struct usb_device_id id_table_combined[] = {
{ USB_DEVICE(AIRBUS_DS_VID, AIRBUS_DS_P8GR) },
/* EZPrototypes devices */
{ USB_DEVICE(EZPROTOTYPES_VID, HJELMSLUND_USB485_ISO_PID) },
+ { USB_DEVICE_INTERFACE_NUMBER(UNJO_VID, UNJO_ISODEBUG_V1_PID, 1) },
{ } /* Terminating entry */
};
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index 5755f0df0025..f12d806220b4 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -1543,3 +1543,9 @@
#define CHETCO_SEASMART_DISPLAY_PID 0xA5AD /* SeaSmart NMEA2000 Display */
#define CHETCO_SEASMART_LITE_PID 0xA5AE /* SeaSmart Lite USB Adapter */
#define CHETCO_SEASMART_ANALOG_PID 0xA5AF /* SeaSmart Analog Adapter */
+
+/*
+ * Unjo AB
+ */
+#define UNJO_VID 0x22B7
+#define UNJO_ISODEBUG_V1_PID 0x150D
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 7643716b5299..302eb9530859 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -16,7 +16,7 @@
* was written by Roman Weissgaerber <weissg@vienna.at>, Dag Brattli
* <dag@brattli.net>, and Jean Tourrilhes <jt@hpl.hp.com>
*
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
* driver
*/
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 38d43c4b7ce5..bf988f77d400 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -6,7 +6,7 @@
* Copyright (C) 1999, 2000 Brian Warner <warner@lothar.com>
* Copyright (C) 2000 Al Borchers <borchers@steinerpoint.com>
*
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
* driver
*/
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index e51c9464ea42..5b6e982a9376 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -4,7 +4,7 @@
*
* Copyright (C) 2013,2017 Johan Hovold <johan@kernel.org>
*
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
* driver
*
* Please report both successes and troubles to the author at omninet@kroah.com
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index a0aaf0635359..c1582fbd1150 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -1343,6 +1343,7 @@ static const struct usb_device_id option_ids[] = {
.driver_info = RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0414, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0417, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_INTERFACE_CLASS(ZTE_VENDOR_ID, 0x0601, 0xff) }, /* GosunCn ZTE WeLink ME3630 (RNDIS mode) */
{ USB_DEVICE_INTERFACE_CLASS(ZTE_VENDOR_ID, 0x0602, 0xff) }, /* GosunCn ZTE WeLink ME3630 (MBIM mode) */
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff),
.driver_info = RSVD(4) },
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index 38ae0fc826cc..8151dd7a45e8 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -22,7 +22,7 @@
* So, THIS CODE CAN DESTROY OTi-6858 AND ANY OTHER DEVICES, THAT ARE
* CONNECTED TO IT!
*
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
* driver
*
* TODO:
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index d7abde14b3cf..9d27b76c5c6e 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -7,7 +7,7 @@
*
* Original driver for 2.2.x by anonymous
*
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
* driver
*/
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 676c296103a2..a3179fea38c8 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -10,7 +10,7 @@
* This driver was originally based on the ACM driver by Armin Fuerst (which was
* based on a driver by Brad Keryan)
*
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
* driver
*/
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 8ddbecc25d89..4412834db21c 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -6,7 +6,7 @@
* Copyright (C) 1999 - 2004
* Greg Kroah-Hartman (greg@kroah.com)
*
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
* driver
*
*/
diff --git a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h
index fe290243f1ce..4bd69d047036 100644
--- a/drivers/usb/serial/visor.h
+++ b/drivers/usb/serial/visor.h
@@ -5,7 +5,7 @@
* Copyright (C) 1999 - 2003
* Greg Kroah-Hartman (greg@kroah.com)
*
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
* driver.
*
*/
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index aefd84f88b59..79314d8c94a4 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -8,7 +8,7 @@
* Copyright (C) 1999 - 2001
* Greg Kroah-Hartman (greg@kroah.com)
*
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
* driver
*/
diff --git a/drivers/usb/serial/whiteheat.h b/drivers/usb/serial/whiteheat.h
index 72c1b0cf4063..00398149cd8d 100644
--- a/drivers/usb/serial/whiteheat.h
+++ b/drivers/usb/serial/whiteheat.h
@@ -8,7 +8,7 @@
* Copyright (C) 1999, 2000
* Greg Kroah-Hartman (greg@kroah.com)
*
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
* driver
*
*/
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index 59190d88fa9f..30790240aec6 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -195,8 +195,11 @@ static int slave_configure(struct scsi_device *sdev)
*/
sdev->skip_ms_page_8 = 1;
- /* Some devices don't handle VPD pages correctly */
- sdev->skip_vpd_pages = 1;
+ /*
+ * Some devices don't handle VPD pages correctly, so skip vpd
+ * pages if not forced by SCSI layer.
+ */
+ sdev->skip_vpd_pages = !sdev->try_vpd_pages;
/* Do not attempt to use REPORT SUPPORTED OPERATION CODES */
sdev->no_report_opcodes = 1;
diff --git a/drivers/usb/typec/bus.h b/drivers/usb/typec/bus.h
index db40e61d8b72..0c9661c96473 100644
--- a/drivers/usb/typec/bus.h
+++ b/drivers/usb/typec/bus.h
@@ -35,4 +35,19 @@ extern const struct device_type typec_port_dev_type;
#define is_typec_altmode(_dev_) (_dev_->type == &typec_altmode_dev_type)
#define is_typec_port(_dev_) (_dev_->type == &typec_port_dev_type)
+extern struct class typec_mux_class;
+
+struct typec_switch {
+ struct device dev;
+ typec_switch_set_fn_t set;
+};
+
+struct typec_mux {
+ struct device dev;
+ typec_mux_set_fn_t set;
+};
+
+#define to_typec_switch(_dev_) container_of(_dev_, struct typec_switch, dev)
+#define to_typec_mux(_dev_) container_of(_dev_, struct typec_mux, dev)
+
#endif /* __USB_TYPEC_ALTMODE_H__ */
diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
index 2eb623841847..a18285a990a8 100644
--- a/drivers/usb/typec/class.c
+++ b/drivers/usb/typec/class.c
@@ -1646,13 +1646,25 @@ static int __init typec_init(void)
if (ret)
return ret;
+ ret = class_register(&typec_mux_class);
+ if (ret)
+ goto err_unregister_bus;
+
typec_class = class_create(THIS_MODULE, "typec");
if (IS_ERR(typec_class)) {
- bus_unregister(&typec_bus);
- return PTR_ERR(typec_class);
+ ret = PTR_ERR(typec_class);
+ goto err_unregister_mux_class;
}
return 0;
+
+err_unregister_mux_class:
+ class_unregister(&typec_mux_class);
+
+err_unregister_bus:
+ bus_unregister(&typec_bus);
+
+ return ret;
}
subsys_initcall(typec_init);
@@ -1661,6 +1673,7 @@ static void __exit typec_exit(void)
class_destroy(typec_class);
ida_destroy(&typec_index_ida);
bus_unregister(&typec_bus);
+ class_unregister(&typec_mux_class);
}
module_exit(typec_exit);
diff --git a/drivers/usb/typec/mux.c b/drivers/usb/typec/mux.c
index 2ce54f3fc79c..61b7bc58dd81 100644
--- a/drivers/usb/typec/mux.c
+++ b/drivers/usb/typec/mux.c
@@ -15,35 +15,47 @@
#include <linux/slab.h>
#include <linux/usb/typec_mux.h>
-static DEFINE_MUTEX(switch_lock);
-static DEFINE_MUTEX(mux_lock);
-static LIST_HEAD(switch_list);
-static LIST_HEAD(mux_list);
+#include "bus.h"
+
+static int name_match(struct device *dev, const void *name)
+{
+ return !strcmp((const char *)name, dev_name(dev));
+}
+
+static bool dev_name_ends_with(struct device *dev, const char *suffix)
+{
+ const char *name = dev_name(dev);
+ const int name_len = strlen(name);
+ const int suffix_len = strlen(suffix);
+
+ if (suffix_len > name_len)
+ return false;
+
+ return strcmp(name + (name_len - suffix_len), suffix) == 0;
+}
+
+static int switch_fwnode_match(struct device *dev, const void *fwnode)
+{
+ return dev_fwnode(dev) == fwnode && dev_name_ends_with(dev, "-switch");
+}
static void *typec_switch_match(struct device_connection *con, int ep,
void *data)
{
- struct typec_switch *sw;
-
- if (!con->fwnode) {
- list_for_each_entry(sw, &switch_list, entry)
- if (!strcmp(con->endpoint[ep], dev_name(sw->dev)))
- return sw;
- return ERR_PTR(-EPROBE_DEFER);
- }
+ struct device *dev;
- /*
- * With OF graph the mux node must have a boolean device property named
- * "orientation-switch".
- */
- if (con->id && !fwnode_property_present(con->fwnode, con->id))
- return NULL;
+ if (con->fwnode) {
+ if (con->id && !fwnode_property_present(con->fwnode, con->id))
+ return NULL;
- list_for_each_entry(sw, &switch_list, entry)
- if (dev_fwnode(sw->dev) == con->fwnode)
- return sw;
+ dev = class_find_device(&typec_mux_class, NULL, con->fwnode,
+ switch_fwnode_match);
+ } else {
+ dev = class_find_device(&typec_mux_class, NULL,
+ con->endpoint[ep], name_match);
+ }
- return con->id ? ERR_PTR(-EPROBE_DEFER) : NULL;
+ return dev ? to_typec_switch(dev) : ERR_PTR(-EPROBE_DEFER);
}
/**
@@ -59,14 +71,10 @@ struct typec_switch *typec_switch_get(struct device *dev)
{
struct typec_switch *sw;
- mutex_lock(&switch_lock);
sw = device_connection_find_match(dev, "orientation-switch", NULL,
typec_switch_match);
- if (!IS_ERR_OR_NULL(sw)) {
- WARN_ON(!try_module_get(sw->dev->driver->owner));
- get_device(sw->dev);
- }
- mutex_unlock(&switch_lock);
+ if (!IS_ERR_OR_NULL(sw))
+ WARN_ON(!try_module_get(sw->dev.parent->driver->owner));
return sw;
}
@@ -81,28 +89,64 @@ EXPORT_SYMBOL_GPL(typec_switch_get);
void typec_switch_put(struct typec_switch *sw)
{
if (!IS_ERR_OR_NULL(sw)) {
- module_put(sw->dev->driver->owner);
- put_device(sw->dev);
+ module_put(sw->dev.parent->driver->owner);
+ put_device(&sw->dev);
}
}
EXPORT_SYMBOL_GPL(typec_switch_put);
+static void typec_switch_release(struct device *dev)
+{
+ kfree(to_typec_switch(dev));
+}
+
+static const struct device_type typec_switch_dev_type = {
+ .name = "orientation_switch",
+ .release = typec_switch_release,
+};
+
/**
* typec_switch_register - Register USB Type-C orientation switch
- * @sw: USB Type-C orientation switch
+ * @parent: Parent device
+ * @desc: Orientation switch description
*
* This function registers a switch that can be used for routing the correct
* data pairs depending on the cable plug orientation from the USB Type-C
* connector to the USB controllers. USB Type-C plugs can be inserted
* right-side-up or upside-down.
*/
-int typec_switch_register(struct typec_switch *sw)
+struct typec_switch *
+typec_switch_register(struct device *parent,
+ const struct typec_switch_desc *desc)
{
- mutex_lock(&switch_lock);
- list_add_tail(&sw->entry, &switch_list);
- mutex_unlock(&switch_lock);
+ struct typec_switch *sw;
+ int ret;
+
+ if (!desc || !desc->set)
+ return ERR_PTR(-EINVAL);
+
+ sw = kzalloc(sizeof(*sw), GFP_KERNEL);
+ if (!sw)
+ return ERR_PTR(-ENOMEM);
- return 0;
+ sw->set = desc->set;
+
+ device_initialize(&sw->dev);
+ sw->dev.parent = parent;
+ sw->dev.fwnode = desc->fwnode;
+ sw->dev.class = &typec_mux_class;
+ sw->dev.type = &typec_switch_dev_type;
+ sw->dev.driver_data = desc->drvdata;
+ dev_set_name(&sw->dev, "%s-switch", dev_name(parent));
+
+ ret = device_add(&sw->dev);
+ if (ret) {
+ dev_err(parent, "failed to register switch (%d)\n", ret);
+ put_device(&sw->dev);
+ return ERR_PTR(ret);
+ }
+
+ return sw;
}
EXPORT_SYMBOL_GPL(typec_switch_register);
@@ -114,28 +158,44 @@ EXPORT_SYMBOL_GPL(typec_switch_register);
*/
void typec_switch_unregister(struct typec_switch *sw)
{
- mutex_lock(&switch_lock);
- list_del(&sw->entry);
- mutex_unlock(&switch_lock);
+ if (!IS_ERR_OR_NULL(sw))
+ device_unregister(&sw->dev);
}
EXPORT_SYMBOL_GPL(typec_switch_unregister);
+void typec_switch_set_drvdata(struct typec_switch *sw, void *data)
+{
+ dev_set_drvdata(&sw->dev, data);
+}
+EXPORT_SYMBOL_GPL(typec_switch_set_drvdata);
+
+void *typec_switch_get_drvdata(struct typec_switch *sw)
+{
+ return dev_get_drvdata(&sw->dev);
+}
+EXPORT_SYMBOL_GPL(typec_switch_get_drvdata);
+
/* ------------------------------------------------------------------------- */
+static int mux_fwnode_match(struct device *dev, const void *fwnode)
+{
+ return dev_fwnode(dev) == fwnode && dev_name_ends_with(dev, "-mux");
+}
+
static void *typec_mux_match(struct device_connection *con, int ep, void *data)
{
const struct typec_altmode_desc *desc = data;
- struct typec_mux *mux;
- int nval;
+ struct device *dev;
bool match;
+ int nval;
u16 *val;
int i;
if (!con->fwnode) {
- list_for_each_entry(mux, &mux_list, entry)
- if (!strcmp(con->endpoint[ep], dev_name(mux->dev)))
- return mux;
- return ERR_PTR(-EPROBE_DEFER);
+ dev = class_find_device(&typec_mux_class, NULL,
+ con->endpoint[ep], name_match);
+
+ return dev ? to_typec_switch(dev) : ERR_PTR(-EPROBE_DEFER);
}
/*
@@ -180,11 +240,10 @@ static void *typec_mux_match(struct device_connection *con, int ep, void *data)
return NULL;
find_mux:
- list_for_each_entry(mux, &mux_list, entry)
- if (dev_fwnode(mux->dev) == con->fwnode)
- return mux;
+ dev = class_find_device(&typec_mux_class, NULL, con->fwnode,
+ mux_fwnode_match);
- return ERR_PTR(-EPROBE_DEFER);
+ return dev ? to_typec_switch(dev) : ERR_PTR(-EPROBE_DEFER);
}
/**
@@ -202,14 +261,10 @@ struct typec_mux *typec_mux_get(struct device *dev,
{
struct typec_mux *mux;
- mutex_lock(&mux_lock);
mux = device_connection_find_match(dev, "mode-switch", (void *)desc,
typec_mux_match);
- if (!IS_ERR_OR_NULL(mux)) {
- WARN_ON(!try_module_get(mux->dev->driver->owner));
- get_device(mux->dev);
- }
- mutex_unlock(&mux_lock);
+ if (!IS_ERR_OR_NULL(mux))
+ WARN_ON(!try_module_get(mux->dev.parent->driver->owner));
return mux;
}
@@ -224,28 +279,63 @@ EXPORT_SYMBOL_GPL(typec_mux_get);
void typec_mux_put(struct typec_mux *mux)
{
if (!IS_ERR_OR_NULL(mux)) {
- module_put(mux->dev->driver->owner);
- put_device(mux->dev);
+ module_put(mux->dev.parent->driver->owner);
+ put_device(&mux->dev);
}
}
EXPORT_SYMBOL_GPL(typec_mux_put);
+static void typec_mux_release(struct device *dev)
+{
+ kfree(to_typec_mux(dev));
+}
+
+static const struct device_type typec_mux_dev_type = {
+ .name = "mode_switch",
+ .release = typec_mux_release,
+};
+
/**
* typec_mux_register - Register Multiplexer routing USB Type-C pins
- * @mux: USB Type-C Connector Multiplexer/DeMultiplexer
+ * @parent: Parent device
+ * @desc: Multiplexer description
*
* USB Type-C connectors can be used for alternate modes of operation besides
* USB when Accessory/Alternate Modes are supported. With some of those modes,
* the pins on the connector need to be reconfigured. This function registers
* multiplexer switches routing the pins on the connector.
*/
-int typec_mux_register(struct typec_mux *mux)
+struct typec_mux *
+typec_mux_register(struct device *parent, const struct typec_mux_desc *desc)
{
- mutex_lock(&mux_lock);
- list_add_tail(&mux->entry, &mux_list);
- mutex_unlock(&mux_lock);
+ struct typec_mux *mux;
+ int ret;
+
+ if (!desc || !desc->set)
+ return ERR_PTR(-EINVAL);
+
+ mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+ if (!mux)
+ return ERR_PTR(-ENOMEM);
+
+ mux->set = desc->set;
+
+ device_initialize(&mux->dev);
+ mux->dev.parent = parent;
+ mux->dev.fwnode = desc->fwnode;
+ mux->dev.class = &typec_mux_class;
+ mux->dev.type = &typec_mux_dev_type;
+ mux->dev.driver_data = desc->drvdata;
+ dev_set_name(&mux->dev, "%s-mux", dev_name(parent));
+
+ ret = device_add(&mux->dev);
+ if (ret) {
+ dev_err(parent, "failed to register mux (%d)\n", ret);
+ put_device(&mux->dev);
+ return ERR_PTR(ret);
+ }
- return 0;
+ return mux;
}
EXPORT_SYMBOL_GPL(typec_mux_register);
@@ -257,8 +347,24 @@ EXPORT_SYMBOL_GPL(typec_mux_register);
*/
void typec_mux_unregister(struct typec_mux *mux)
{
- mutex_lock(&mux_lock);
- list_del(&mux->entry);
- mutex_unlock(&mux_lock);
+ if (!IS_ERR_OR_NULL(mux))
+ device_unregister(&mux->dev);
}
EXPORT_SYMBOL_GPL(typec_mux_unregister);
+
+void typec_mux_set_drvdata(struct typec_mux *mux, void *data)
+{
+ dev_set_drvdata(&mux->dev, data);
+}
+EXPORT_SYMBOL_GPL(typec_mux_set_drvdata);
+
+void *typec_mux_get_drvdata(struct typec_mux *mux)
+{
+ return dev_get_drvdata(&mux->dev);
+}
+EXPORT_SYMBOL_GPL(typec_mux_get_drvdata);
+
+struct class typec_mux_class = {
+ .name = "typec_mux",
+ .owner = THIS_MODULE,
+};
diff --git a/drivers/usb/typec/mux/pi3usb30532.c b/drivers/usb/typec/mux/pi3usb30532.c
index 9294e85fd34b..5585b109095b 100644
--- a/drivers/usb/typec/mux/pi3usb30532.c
+++ b/drivers/usb/typec/mux/pi3usb30532.c
@@ -23,8 +23,8 @@
struct pi3usb30532 {
struct i2c_client *client;
struct mutex lock; /* protects the cached conf register */
- struct typec_switch sw;
- struct typec_mux mux;
+ struct typec_switch *sw;
+ struct typec_mux *mux;
u8 conf;
};
@@ -48,7 +48,7 @@ static int pi3usb30532_set_conf(struct pi3usb30532 *pi, u8 new_conf)
static int pi3usb30532_sw_set(struct typec_switch *sw,
enum typec_orientation orientation)
{
- struct pi3usb30532 *pi = container_of(sw, struct pi3usb30532, sw);
+ struct pi3usb30532 *pi = typec_switch_get_drvdata(sw);
u8 new_conf;
int ret;
@@ -75,7 +75,7 @@ static int pi3usb30532_sw_set(struct typec_switch *sw,
static int pi3usb30532_mux_set(struct typec_mux *mux, int state)
{
- struct pi3usb30532 *pi = container_of(mux, struct pi3usb30532, mux);
+ struct pi3usb30532 *pi = typec_mux_get_drvdata(mux);
u8 new_conf;
int ret;
@@ -113,6 +113,8 @@ static int pi3usb30532_mux_set(struct typec_mux *mux, int state)
static int pi3usb30532_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
+ struct typec_switch_desc sw_desc;
+ struct typec_mux_desc mux_desc;
struct pi3usb30532 *pi;
int ret;
@@ -121,10 +123,6 @@ static int pi3usb30532_probe(struct i2c_client *client)
return -ENOMEM;
pi->client = client;
- pi->sw.dev = dev;
- pi->sw.set = pi3usb30532_sw_set;
- pi->mux.dev = dev;
- pi->mux.set = pi3usb30532_mux_set;
mutex_init(&pi->lock);
ret = i2c_smbus_read_byte_data(client, PI3USB30532_CONF);
@@ -134,17 +132,27 @@ static int pi3usb30532_probe(struct i2c_client *client)
}
pi->conf = ret;
- ret = typec_switch_register(&pi->sw);
- if (ret) {
- dev_err(dev, "Error registering typec switch: %d\n", ret);
- return ret;
+ sw_desc.drvdata = pi;
+ sw_desc.fwnode = dev->fwnode;
+ sw_desc.set = pi3usb30532_sw_set;
+
+ pi->sw = typec_switch_register(dev, &sw_desc);
+ if (IS_ERR(pi->sw)) {
+ dev_err(dev, "Error registering typec switch: %ld\n",
+ PTR_ERR(pi->sw));
+ return PTR_ERR(pi->sw);
}
- ret = typec_mux_register(&pi->mux);
- if (ret) {
- typec_switch_unregister(&pi->sw);
- dev_err(dev, "Error registering typec mux: %d\n", ret);
- return ret;
+ mux_desc.drvdata = pi;
+ mux_desc.fwnode = dev->fwnode;
+ mux_desc.set = pi3usb30532_mux_set;
+
+ pi->mux = typec_mux_register(dev, &mux_desc);
+ if (IS_ERR(pi->mux)) {
+ typec_switch_unregister(pi->sw);
+ dev_err(dev, "Error registering typec mux: %ld\n",
+ PTR_ERR(pi->mux));
+ return PTR_ERR(pi->mux);
}
i2c_set_clientdata(client, pi);
@@ -155,8 +163,8 @@ static int pi3usb30532_remove(struct i2c_client *client)
{
struct pi3usb30532 *pi = i2c_get_clientdata(client);
- typec_mux_unregister(&pi->mux);
- typec_switch_unregister(&pi->sw);
+ typec_mux_unregister(pi->mux);
+ typec_switch_unregister(pi->sw);
return 0;
}
diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 7302f7501ec9..c524088246ee 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -1697,13 +1697,12 @@ static int fusb302_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct fusb302_chip *chip;
- struct i2c_adapter *adapter;
+ struct i2c_adapter *adapter = client->adapter;
struct device *dev = &client->dev;
const char *name;
int ret = 0;
u32 v;
- adapter = to_i2c_adapter(client->dev.parent);
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) {
dev_err(&client->dev,
"I2C/SMBus block functionality not supported!\n");
diff --git a/drivers/usb/typec/tps6598x.c b/drivers/usb/typec/tps6598x.c
index c674abe3cf99..a38d1409f15b 100644
--- a/drivers/usb/typec/tps6598x.c
+++ b/drivers/usb/typec/tps6598x.c
@@ -41,7 +41,7 @@
#define TPS_STATUS_VCONN(s) (!!((s) & BIT(7)))
/* TPS_REG_SYSTEM_CONF bits */
-#define TPS_SYSCONF_PORTINFO(c) ((c) & 3)
+#define TPS_SYSCONF_PORTINFO(c) ((c) & 7)
enum {
TPS_PORTINFO_SINK,
@@ -127,7 +127,7 @@ tps6598x_block_read(struct tps6598x *tps, u8 reg, void *val, size_t len)
}
static int tps6598x_block_write(struct tps6598x *tps, u8 reg,
- void *val, size_t len)
+ const void *val, size_t len)
{
u8 data[TPS_MAX_LEN + 1];
@@ -173,7 +173,7 @@ static inline int tps6598x_write64(struct tps6598x *tps, u8 reg, u64 val)
static inline int
tps6598x_write_4cc(struct tps6598x *tps, u8 reg, const char *val)
{
- return tps6598x_block_write(tps, reg, &val, sizeof(u32));
+ return tps6598x_block_write(tps, reg, val, 4);
}
static int tps6598x_read_partner_identity(struct tps6598x *tps)
diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
index 7850b851cecd..ba288b964dc8 100644
--- a/drivers/usb/typec/ucsi/ucsi.c
+++ b/drivers/usb/typec/ucsi/ucsi.c
@@ -206,7 +206,17 @@ int ucsi_send_command(struct ucsi *ucsi, struct ucsi_control *ctrl,
return ret;
}
+EXPORT_SYMBOL_GPL(ucsi_send_command);
+int ucsi_resume(struct ucsi *ucsi)
+{
+ struct ucsi_control ctrl;
+
+ /* Restore UCSI notification enable mask after system resume */
+ UCSI_CMD_SET_NTFY_ENABLE(ctrl, UCSI_ENABLE_NTFY_ALL);
+ return ucsi_send_command(ucsi, &ctrl, NULL, 0);
+}
+EXPORT_SYMBOL_GPL(ucsi_resume);
/* -------------------------------------------------------------------------- */
void ucsi_altmode_update_active(struct ucsi_connector *con)
diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h
index 1e2981aef629..de87d0b8319d 100644
--- a/drivers/usb/typec/ucsi/ucsi.h
+++ b/drivers/usb/typec/ucsi/ucsi.h
@@ -430,6 +430,7 @@ int ucsi_send_command(struct ucsi *ucsi, struct ucsi_control *ctrl,
void *retval, size_t size);
void ucsi_altmode_update_active(struct ucsi_connector *con);
+int ucsi_resume(struct ucsi *ucsi);
#if IS_ENABLED(CONFIG_TYPEC_DP_ALTMODE)
struct typec_altmode *
diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c
index bf63074675fc..f7a79a23ebed 100644
--- a/drivers/usb/typec/ucsi/ucsi_ccg.c
+++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
@@ -14,6 +14,8 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
#include <asm/unaligned.h>
#include "ucsi.h"
@@ -107,12 +109,21 @@ struct version_format {
__le16 build;
u8 patch;
u8 ver;
+#define CCG_VERSION_PATCH(x) ((x) << 16)
+#define CCG_VERSION(x) ((x) << 24)
#define CCG_VERSION_MIN_SHIFT (0)
#define CCG_VERSION_MIN_MASK (0xf << CCG_VERSION_MIN_SHIFT)
#define CCG_VERSION_MAJ_SHIFT (4)
#define CCG_VERSION_MAJ_MASK (0xf << CCG_VERSION_MAJ_SHIFT)
} __packed;
+/*
+ * Firmware version 3.1.10 or earlier, built for NVIDIA has known issue
+ * of missing interrupt when a device is connected for runtime resume
+ */
+#define CCG_FW_BUILD_NVIDIA (('n' << 8) | 'v')
+#define CCG_OLD_FW_VERSION (CCG_VERSION(0x31) | CCG_VERSION_PATCH(10))
+
struct version_info {
struct version_format base;
struct version_format app;
@@ -170,6 +181,7 @@ struct ucsi_ccg {
struct ccg_dev_info info;
/* version info for boot, primary and secondary */
struct version_info version[FW2 + 1];
+ u32 fw_version;
/* CCG HPI communication flags */
unsigned long flags;
#define RESET_PENDING 0
@@ -183,6 +195,8 @@ struct ucsi_ccg {
/* fw build with vendor information */
u16 fw_build;
+ bool run_isr; /* flag to call ISR routine during resume */
+ struct work_struct pm_work;
};
static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
@@ -210,6 +224,19 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
if (quirks && quirks->max_read_len)
max_read_len = quirks->max_read_len;
+ if (uc->fw_build == CCG_FW_BUILD_NVIDIA &&
+ uc->fw_version <= CCG_OLD_FW_VERSION) {
+ mutex_lock(&uc->lock);
+ /*
+ * Do not schedule pm_work to run ISR in
+ * ucsi_ccg_runtime_resume() after pm_runtime_get_sync()
+ * since we are already in ISR path.
+ */
+ uc->run_isr = false;
+ mutex_unlock(&uc->lock);
+ }
+
+ pm_runtime_get_sync(uc->dev);
while (rem_len > 0) {
msgs[1].buf = &data[len - rem_len];
rlen = min_t(u16, rem_len, max_read_len);
@@ -218,12 +245,14 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (status < 0) {
dev_err(uc->dev, "i2c_transfer failed %d\n", status);
+ pm_runtime_put_sync(uc->dev);
return status;
}
rab += rlen;
rem_len -= rlen;
}
+ pm_runtime_put_sync(uc->dev);
return 0;
}
@@ -249,13 +278,28 @@ static int ccg_write(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
msgs[0].len = len + sizeof(rab);
msgs[0].buf = buf;
+ if (uc->fw_build == CCG_FW_BUILD_NVIDIA &&
+ uc->fw_version <= CCG_OLD_FW_VERSION) {
+ mutex_lock(&uc->lock);
+ /*
+ * Do not schedule pm_work to run ISR in
+ * ucsi_ccg_runtime_resume() after pm_runtime_get_sync()
+ * since we are already in ISR path.
+ */
+ uc->run_isr = false;
+ mutex_unlock(&uc->lock);
+ }
+
+ pm_runtime_get_sync(uc->dev);
status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (status < 0) {
dev_err(uc->dev, "i2c_transfer failed %d\n", status);
+ pm_runtime_put_sync(uc->dev);
kfree(buf);
return status;
}
+ pm_runtime_put_sync(uc->dev);
kfree(buf);
return 0;
}
@@ -375,6 +419,13 @@ static irqreturn_t ccg_irq_handler(int irq, void *data)
return IRQ_HANDLED;
}
+static void ccg_pm_workaround_work(struct work_struct *pm_work)
+{
+ struct ucsi_ccg *uc = container_of(pm_work, struct ucsi_ccg, pm_work);
+
+ ucsi_notify(uc->ucsi);
+}
+
static int get_fw_info(struct ucsi_ccg *uc)
{
int err;
@@ -384,6 +435,9 @@ static int get_fw_info(struct ucsi_ccg *uc)
if (err < 0)
return err;
+ uc->fw_version = CCG_VERSION(uc->version[FW2].app.ver) |
+ CCG_VERSION_PATCH(uc->version[FW2].app.patch);
+
err = ccg_read(uc, CCGX_RAB_DEVICE_MODE, (u8 *)(&uc->info),
sizeof(uc->info));
if (err < 0)
@@ -732,11 +786,12 @@ static bool ccg_check_fw_version(struct ucsi_ccg *uc, const char *fw_name,
}
/* compare input version with FWCT version */
- cur_version = le16_to_cpu(app->build) | app->patch << 16 |
- app->ver << 24;
+ cur_version = le16_to_cpu(app->build) | CCG_VERSION_PATCH(app->patch) |
+ CCG_VERSION(app->ver);
- new_version = le16_to_cpu(fw_cfg.app.build) | fw_cfg.app.patch << 16 |
- fw_cfg.app.ver << 24;
+ new_version = le16_to_cpu(fw_cfg.app.build) |
+ CCG_VERSION_PATCH(fw_cfg.app.patch) |
+ CCG_VERSION(fw_cfg.app.ver);
if (!ccg_check_vendor_version(uc, app, &fw_cfg))
goto out_release_firmware;
@@ -1078,8 +1133,10 @@ static int ucsi_ccg_probe(struct i2c_client *client,
uc->ppm.sync = ucsi_ccg_sync;
uc->dev = dev;
uc->client = client;
+ uc->run_isr = true;
mutex_init(&uc->lock);
INIT_WORK(&uc->work, ccg_update_firmware);
+ INIT_WORK(&uc->pm_work, ccg_pm_workaround_work);
/* Only fail FW flashing when FW build information is not provided */
status = device_property_read_u16(dev, "ccgx,firmware-build",
@@ -1136,6 +1193,10 @@ static int ucsi_ccg_probe(struct i2c_client *client,
if (status)
dev_err(uc->dev, "cannot create sysfs group: %d\n", status);
+ pm_runtime_set_active(uc->dev);
+ pm_runtime_enable(uc->dev);
+ pm_runtime_idle(uc->dev);
+
return 0;
}
@@ -1143,8 +1204,10 @@ static int ucsi_ccg_remove(struct i2c_client *client)
{
struct ucsi_ccg *uc = i2c_get_clientdata(client);
+ cancel_work_sync(&uc->pm_work);
cancel_work_sync(&uc->work);
ucsi_unregister_ppm(uc->ucsi);
+ pm_runtime_disable(uc->dev);
free_irq(uc->irq, uc);
sysfs_remove_group(&uc->dev->kobj, &ucsi_ccg_attr_group);
@@ -1157,9 +1220,56 @@ static const struct i2c_device_id ucsi_ccg_device_id[] = {
};
MODULE_DEVICE_TABLE(i2c, ucsi_ccg_device_id);
+static int ucsi_ccg_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ucsi_ccg *uc = i2c_get_clientdata(client);
+
+ return ucsi_resume(uc->ucsi);
+}
+
+static int ucsi_ccg_runtime_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int ucsi_ccg_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ucsi_ccg *uc = i2c_get_clientdata(client);
+ bool schedule = true;
+
+ /*
+ * Firmware version 3.1.10 or earlier, built for NVIDIA has known issue
+ * of missing interrupt when a device is connected for runtime resume.
+ * Schedule a work to call ISR as a workaround.
+ */
+ if (uc->fw_build == CCG_FW_BUILD_NVIDIA &&
+ uc->fw_version <= CCG_OLD_FW_VERSION) {
+ mutex_lock(&uc->lock);
+ if (!uc->run_isr) {
+ uc->run_isr = true;
+ schedule = false;
+ }
+ mutex_unlock(&uc->lock);
+
+ if (schedule)
+ schedule_work(&uc->pm_work);
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops ucsi_ccg_pm = {
+ .resume = ucsi_ccg_resume,
+ .runtime_suspend = ucsi_ccg_runtime_suspend,
+ .runtime_resume = ucsi_ccg_runtime_resume,
+};
+
static struct i2c_driver ucsi_ccg_driver = {
.driver = {
.name = "ucsi_ccg",
+ .pm = &ucsi_ccg_pm,
},
.probe = ucsi_ccg_probe,
.remove = ucsi_ccg_remove,
diff --git a/drivers/usb/usbip/stub_main.c b/drivers/usb/usbip/stub_main.c
index bf8a5feb0ee9..2e4bfccd4bfc 100644
--- a/drivers/usb/usbip/stub_main.c
+++ b/drivers/usb/usbip/stub_main.c
@@ -201,7 +201,7 @@ static DRIVER_ATTR_RW(match_busid);
static int do_rebind(char *busid, struct bus_id_priv *busid_priv)
{
- int ret;
+ int ret = 0;
/* device_attach() callers should hold parent lock for USB */
if (busid_priv->udev->dev.parent)
@@ -209,11 +209,9 @@ static int do_rebind(char *busid, struct bus_id_priv *busid_priv)
ret = device_attach(&busid_priv->udev->dev);
if (busid_priv->udev->dev.parent)
device_unlock(busid_priv->udev->dev.parent);
- if (ret < 0) {
+ if (ret < 0)
dev_err(&busid_priv->udev->dev, "rebind failed\n");
- return ret;
- }
- return 0;
+ return ret;
}
static void stub_device_rebind(void)
diff --git a/drivers/usb/usbip/vhci_tx.c b/drivers/usb/usbip/vhci_tx.c
index 9aed15a358b7..2fa26d0578d7 100644
--- a/drivers/usb/usbip/vhci_tx.c
+++ b/drivers/usb/usbip/vhci_tx.c
@@ -144,16 +144,14 @@ static int vhci_send_cmd_unlink(struct vhci_device *vdev)
struct vhci_unlink *unlink = NULL;
struct msghdr msg;
- struct kvec iov[3];
+ struct kvec iov;
size_t txsize;
-
size_t total_size = 0;
while ((unlink = dequeue_from_unlink_tx(vdev)) != NULL) {
int ret;
struct usbip_header pdu_header;
- txsize = 0;
memset(&pdu_header, 0, sizeof(pdu_header));
memset(&msg, 0, sizeof(msg));
memset(&iov, 0, sizeof(iov));
@@ -169,11 +167,11 @@ static int vhci_send_cmd_unlink(struct vhci_device *vdev)
usbip_header_correct_endian(&pdu_header, 1);
- iov[0].iov_base = &pdu_header;
- iov[0].iov_len = sizeof(pdu_header);
- txsize += sizeof(pdu_header);
+ iov.iov_base = &pdu_header;
+ iov.iov_len = sizeof(pdu_header);
+ txsize = sizeof(pdu_header);
- ret = kernel_sendmsg(vdev->ud.tcp_socket, &msg, iov, 1, txsize);
+ ret = kernel_sendmsg(vdev->ud.tcp_socket, &msg, &iov, 1, txsize);
if (ret != txsize) {
pr_err("sendmsg failed!, ret=%d for %zd\n", ret,
txsize);
diff --git a/drivers/usb/wusbcore/Kconfig b/drivers/usb/wusbcore/Kconfig
index 12e89189ca7d..abc0f361021f 100644
--- a/drivers/usb/wusbcore/Kconfig
+++ b/drivers/usb/wusbcore/Kconfig
@@ -5,11 +5,9 @@
config USB_WUSB
tristate "Enable Wireless USB extensions"
depends on UWB
- select CRYPTO
- select CRYPTO_BLKCIPHER
- select CRYPTO_CBC
- select CRYPTO_MANAGER
- select CRYPTO_AES
+ select CRYPTO
+ select CRYPTO_AES
+ select CRYPTO_CCM
help
Enable the host-side support for Wireless USB.
diff --git a/drivers/usb/wusbcore/crypto.c b/drivers/usb/wusbcore/crypto.c
index edb7263bff40..9ee66483ee54 100644
--- a/drivers/usb/wusbcore/crypto.c
+++ b/drivers/usb/wusbcore/crypto.c
@@ -31,6 +31,9 @@
* funneled through AES are...16 bytes in size!
*/
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <crypto/hash.h>
#include <crypto/skcipher.h>
#include <linux/crypto.h>
#include <linux/module.h>
@@ -109,16 +112,6 @@ struct aes_ccm_a {
__be16 counter; /* Value of x */
} __attribute__((packed));
-static void bytewise_xor(void *_bo, const void *_bi1, const void *_bi2,
- size_t size)
-{
- u8 *bo = _bo;
- const u8 *bi1 = _bi1, *bi2 = _bi2;
- size_t itr;
- for (itr = 0; itr < size; itr++)
- bo[itr] = bi1[itr] ^ bi2[itr];
-}
-
/* Scratch space for MAC calculations. */
struct wusb_mac_scratch {
struct aes_ccm_b0 b0;
@@ -150,8 +143,7 @@ struct wusb_mac_scratch {
* @a: ASCII string, 14 bytes long (I guess zero padded if needed;
* we use exactly 14 bytes).
*
- * @b: data stream to be processed; cannot be a global or const local
- * (will confuse the scatterlists)
+ * @b: data stream to be processed
*
* @blen: size of b...
*
@@ -160,16 +152,10 @@ struct wusb_mac_scratch {
* @key. We bytewise xor B0 with B1 (1) and AES-crypt that. Then we
* take the payload and divide it in blocks (16 bytes), xor them with
* the previous crypto result (16 bytes) and crypt it, repeat the next
- * block with the output of the previous one, rinse wash (I guess this
- * is what AES CBC mode means...but I truly have no idea). So we use
- * the CBC(AES) blkcipher, that does precisely that. The IV (Initial
+ * block with the output of the previous one, rinse wash. So we use
+ * the CBC-MAC(AES) shash, that does precisely that. The IV (Initial
* Vector) is 16 bytes and is set to zero, so
*
- * See rfc3610. Linux crypto has a CBC implementation, but the
- * documentation is scarce, to say the least, and the example code is
- * so intricated that is difficult to understand how things work. Most
- * of this is guess work -- bite me.
- *
* (1) Created as 6.5 says, again, using as l(a) 'Blen + 14', and
* using the 14 bytes of @a to fill up
* b1.{mac_header,e0,security_reserved,padding}.
@@ -189,44 +175,24 @@ struct wusb_mac_scratch {
* NOTE: blen is not aligned to a block size, we'll pad zeros, that's
* what sg[4] is for. Maybe there is a smarter way to do this.
*/
-static int wusb_ccm_mac(struct crypto_sync_skcipher *tfm_cbc,
- struct crypto_cipher *tfm_aes,
+static int wusb_ccm_mac(struct crypto_shash *tfm_cbcmac,
struct wusb_mac_scratch *scratch,
void *mic,
const struct aes_ccm_nonce *n,
const struct aes_ccm_label *a, const void *b,
size_t blen)
{
- int result = 0;
- SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm_cbc);
- struct scatterlist sg[4], sg_dst;
- void *dst_buf;
- size_t dst_size;
- u8 *iv;
- size_t zero_padding;
+ SHASH_DESC_ON_STACK(desc, tfm_cbcmac);
+ u8 iv[AES_BLOCK_SIZE];
/*
* These checks should be compile time optimized out
* ensure @a fills b1's mac_header and following fields
*/
- WARN_ON(sizeof(*a) != sizeof(scratch->b1) - sizeof(scratch->b1.la));
- WARN_ON(sizeof(scratch->b0) != sizeof(struct aes_ccm_block));
- WARN_ON(sizeof(scratch->b1) != sizeof(struct aes_ccm_block));
- WARN_ON(sizeof(scratch->ax) != sizeof(struct aes_ccm_block));
-
- result = -ENOMEM;
- zero_padding = blen % sizeof(struct aes_ccm_block);
- if (zero_padding)
- zero_padding = sizeof(struct aes_ccm_block) - zero_padding;
- dst_size = blen + sizeof(scratch->b0) + sizeof(scratch->b1) +
- zero_padding;
- dst_buf = kzalloc(dst_size, GFP_KERNEL);
- if (!dst_buf)
- goto error_dst_buf;
-
- iv = kzalloc(crypto_sync_skcipher_ivsize(tfm_cbc), GFP_KERNEL);
- if (!iv)
- goto error_iv;
+ BUILD_BUG_ON(sizeof(*a) != sizeof(scratch->b1) - sizeof(scratch->b1.la));
+ BUILD_BUG_ON(sizeof(scratch->b0) != sizeof(struct aes_ccm_block));
+ BUILD_BUG_ON(sizeof(scratch->b1) != sizeof(struct aes_ccm_block));
+ BUILD_BUG_ON(sizeof(scratch->ax) != sizeof(struct aes_ccm_block));
/* Setup B0 */
scratch->b0.flags = 0x59; /* Format B0 */
@@ -243,46 +209,28 @@ static int wusb_ccm_mac(struct crypto_sync_skcipher *tfm_cbc,
scratch->b1.la = cpu_to_be16(blen + 14);
memcpy(&scratch->b1.mac_header, a, sizeof(*a));
- sg_init_table(sg, ARRAY_SIZE(sg));
- sg_set_buf(&sg[0], &scratch->b0, sizeof(scratch->b0));
- sg_set_buf(&sg[1], &scratch->b1, sizeof(scratch->b1));
- sg_set_buf(&sg[2], b, blen);
- /* 0 if well behaved :) */
- sg_set_page(&sg[3], ZERO_PAGE(0), zero_padding, 0);
- sg_init_one(&sg_dst, dst_buf, dst_size);
-
- skcipher_request_set_sync_tfm(req, tfm_cbc);
- skcipher_request_set_callback(req, 0, NULL, NULL);
- skcipher_request_set_crypt(req, sg, &sg_dst, dst_size, iv);
- result = crypto_skcipher_encrypt(req);
- skcipher_request_zero(req);
- if (result < 0) {
- printk(KERN_ERR "E: can't compute CBC-MAC tag (MIC): %d\n",
- result);
- goto error_cbc_crypt;
- }
+ desc->tfm = tfm_cbcmac;
+ crypto_shash_init(desc);
+ crypto_shash_update(desc, (u8 *)&scratch->b0, sizeof(scratch->b0) +
+ sizeof(scratch->b1));
+ crypto_shash_finup(desc, b, blen, iv);
/* Now we crypt the MIC Tag (*iv) with Ax -- values per WUSB1.0[6.5]
* The procedure is to AES crypt the A0 block and XOR the MIC
* Tag against it; we only do the first 8 bytes and place it
* directly in the destination buffer.
- *
- * POS Crypto API: size is assumed to be AES's block size.
- * Thanks for documenting it -- tip taken from airo.c
*/
scratch->ax.flags = 0x01; /* as per WUSB 1.0 spec */
scratch->ax.ccm_nonce = *n;
scratch->ax.counter = 0;
- crypto_cipher_encrypt_one(tfm_aes, (void *)&scratch->ax,
- (void *)&scratch->ax);
- bytewise_xor(mic, &scratch->ax, iv, 8);
- result = 8;
-error_cbc_crypt:
- kfree(iv);
-error_iv:
- kfree(dst_buf);
-error_dst_buf:
- return result;
+
+ /* reuse the CBC-MAC transform to perform the single block encryption */
+ crypto_shash_digest(desc, (u8 *)&scratch->ax, sizeof(scratch->ax),
+ (u8 *)&scratch->ax);
+
+ crypto_xor_cpy(mic, (u8 *)&scratch->ax, iv, 8);
+
+ return 8;
}
/*
@@ -298,45 +246,28 @@ ssize_t wusb_prf(void *out, size_t out_size,
{
ssize_t result, bytes = 0, bitr;
struct aes_ccm_nonce n = *_n;
- struct crypto_sync_skcipher *tfm_cbc;
- struct crypto_cipher *tfm_aes;
- struct wusb_mac_scratch *scratch;
+ struct crypto_shash *tfm_cbcmac;
+ struct wusb_mac_scratch scratch;
u64 sfn = 0;
__le64 sfn_le;
- tfm_cbc = crypto_alloc_sync_skcipher("cbc(aes)", 0, 0);
- if (IS_ERR(tfm_cbc)) {
- result = PTR_ERR(tfm_cbc);
- printk(KERN_ERR "E: can't load CBC(AES): %d\n", (int)result);
- goto error_alloc_cbc;
- }
- result = crypto_sync_skcipher_setkey(tfm_cbc, key, 16);
- if (result < 0) {
- printk(KERN_ERR "E: can't set CBC key: %d\n", (int)result);
- goto error_setkey_cbc;
+ tfm_cbcmac = crypto_alloc_shash("cbcmac(aes)", 0, 0);
+ if (IS_ERR(tfm_cbcmac)) {
+ result = PTR_ERR(tfm_cbcmac);
+ printk(KERN_ERR "E: can't load CBCMAC-AES: %d\n", (int)result);
+ goto error_alloc_cbcmac;
}
- tfm_aes = crypto_alloc_cipher("aes", 0, 0);
- if (IS_ERR(tfm_aes)) {
- result = PTR_ERR(tfm_aes);
- printk(KERN_ERR "E: can't load AES: %d\n", (int)result);
- goto error_alloc_aes;
- }
- result = crypto_cipher_setkey(tfm_aes, key, 16);
+ result = crypto_shash_setkey(tfm_cbcmac, key, AES_BLOCK_SIZE);
if (result < 0) {
- printk(KERN_ERR "E: can't set AES key: %d\n", (int)result);
- goto error_setkey_aes;
- }
- scratch = kmalloc(sizeof(*scratch), GFP_KERNEL);
- if (!scratch) {
- result = -ENOMEM;
- goto error_alloc_scratch;
+ printk(KERN_ERR "E: can't set CBCMAC-AES key: %d\n", (int)result);
+ goto error_setkey_cbcmac;
}
for (bitr = 0; bitr < (len + 63) / 64; bitr++) {
sfn_le = cpu_to_le64(sfn++);
memcpy(&n.sfn, &sfn_le, sizeof(n.sfn)); /* n.sfn++... */
- result = wusb_ccm_mac(tfm_cbc, tfm_aes, scratch, out + bytes,
+ result = wusb_ccm_mac(tfm_cbcmac, &scratch, out + bytes,
&n, a, b, blen);
if (result < 0)
goto error_ccm_mac;
@@ -344,15 +275,10 @@ ssize_t wusb_prf(void *out, size_t out_size,
}
result = bytes;
- kfree(scratch);
-error_alloc_scratch:
error_ccm_mac:
-error_setkey_aes:
- crypto_free_cipher(tfm_aes);
-error_alloc_aes:
-error_setkey_cbc:
- crypto_free_sync_skcipher(tfm_cbc);
-error_alloc_cbc:
+error_setkey_cbcmac:
+ crypto_free_shash(tfm_cbcmac);
+error_alloc_cbcmac:
return result;
}
@@ -377,12 +303,8 @@ static int wusb_oob_mic_verify(void)
{
int result;
u8 mic[8];
- /* WUSB1.0[A.2] test vectors
- *
- * Need to keep it in the local stack as GCC 4.1.3something
- * messes up and generates noise.
- */
- struct usb_handshake stv_hsmic_hs = {
+ /* WUSB1.0[A.2] test vectors */
+ static const struct usb_handshake stv_hsmic_hs = {
.bMessageNumber = 2,
.bStatus = 00,
.tTKID = { 0x76, 0x98, 0x01 },
@@ -457,11 +379,8 @@ static int wusb_key_derive_verify(void)
{
int result = 0;
struct wusb_keydvt_out keydvt_out;
- /* These come from WUSB1.0[A.1] + 2006/12 errata
- * NOTE: can't make this const or global -- somehow it seems
- * the scatterlists for crypto get confused and we get
- * bad data. There is no doc on this... */
- struct wusb_keydvt_in stv_keydvt_in_a1 = {
+ /* These come from WUSB1.0[A.1] + 2006/12 errata */
+ static const struct wusb_keydvt_in stv_keydvt_in_a1 = {
.hnonce = {
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
diff --git a/drivers/uwb/allocator.c b/drivers/uwb/allocator.c
index 6e3e713f0ef7..2e1590124d5f 100644
--- a/drivers/uwb/allocator.c
+++ b/drivers/uwb/allocator.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* UWB reservation management.
*
* Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
#include <linux/slab.h>
diff --git a/drivers/uwb/drp-avail.c b/drivers/uwb/drp-avail.c
index 40a540a5a72e..02392ab82a7d 100644
--- a/drivers/uwb/drp-avail.c
+++ b/drivers/uwb/drp-avail.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Ultra Wide Band
* DRP availability management
@@ -6,19 +7,6 @@
* Reinette Chatre <reinette.chatre@intel.com>
* Copyright (C) 2008 Cambridge Silicon Radio Ltd.
*
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- *
* Manage DRP Availability (the MAS available for DRP
* reservations). Thus:
*
diff --git a/drivers/uwb/drp-ie.c b/drivers/uwb/drp-ie.c
index ed993e363472..4b545b41161c 100644
--- a/drivers/uwb/drp-ie.c
+++ b/drivers/uwb/drp-ie.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* UWB DRP IE management.
*
* Copyright (C) 2005-2006 Intel Corporation
* Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
#include <linux/random.h>
diff --git a/drivers/uwb/drp.c b/drivers/uwb/drp.c
index 625f706b8160..869987bede7b 100644
--- a/drivers/uwb/drp.c
+++ b/drivers/uwb/drp.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Ultra Wide Band
* Dynamic Reservation Protocol handling
@@ -5,18 +6,6 @@
* Copyright (C) 2005-2006 Intel Corporation
* Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
* Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kthread.h>
#include <linux/freezer.h>
diff --git a/drivers/uwb/ie-rcv.c b/drivers/uwb/ie-rcv.c
index 5fac5744a699..51a4706e0dd3 100644
--- a/drivers/uwb/ie-rcv.c
+++ b/drivers/uwb/ie-rcv.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Ultra Wide Band
* IE Received notification handling.
*
* Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/errno.h>
diff --git a/drivers/uwb/pal.c b/drivers/uwb/pal.c
index 678e93741ae1..765fd426dbd1 100644
--- a/drivers/uwb/pal.c
+++ b/drivers/uwb/pal.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* UWB PAL support.
*
* Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
#include <linux/debugfs.h>
diff --git a/drivers/uwb/radio.c b/drivers/uwb/radio.c
index 2427e944883d..240dd755927e 100644
--- a/drivers/uwb/radio.c
+++ b/drivers/uwb/radio.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* UWB radio (channel) management.
*
* Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
#include <linux/uwb.h>
diff --git a/drivers/uwb/rsv.c b/drivers/uwb/rsv.c
index fe25a8cc6fa1..ec924deb0a32 100644
--- a/drivers/uwb/rsv.c
+++ b/drivers/uwb/rsv.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* UWB reservation management.
*
* Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
#include <linux/uwb.h>
diff --git a/drivers/vfio/Kconfig b/drivers/vfio/Kconfig
index e5a7a454fe17..fd17db9b432f 100644
--- a/drivers/vfio/Kconfig
+++ b/drivers/vfio/Kconfig
@@ -25,7 +25,7 @@ menuconfig VFIO
select VFIO_IOMMU_TYPE1 if (X86 || S390 || ARM || ARM64)
help
VFIO provides a framework for secure userspace device drivers.
- See Documentation/vfio.txt for more details.
+ See Documentation/driver-api/vfio.rst for more details.
If you don't know what to do here, say N.
diff --git a/drivers/vfio/mdev/Kconfig b/drivers/vfio/mdev/Kconfig
index ba94a076887f..5da27f2100f9 100644
--- a/drivers/vfio/mdev/Kconfig
+++ b/drivers/vfio/mdev/Kconfig
@@ -6,7 +6,7 @@ config VFIO_MDEV
default n
help
Provides a framework to virtualize devices.
- See Documentation/vfio-mediated-device.txt for more details.
+ See Documentation/driver-api/vfio-mediated-device.rst for more details.
If you don't know what do here, say N.
diff --git a/drivers/vfio/mdev/mdev_core.c b/drivers/vfio/mdev/mdev_core.c
index ae23151442cb..b558d4cfd082 100644
--- a/drivers/vfio/mdev/mdev_core.c
+++ b/drivers/vfio/mdev/mdev_core.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Mediated device Core Driver
*
* Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
* Author: Neo Jia <cjia@nvidia.com>
* Kirti Wankhede <kwankhede@nvidia.com>
- *
- * 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.
*/
#include <linux/module.h>
@@ -146,6 +143,8 @@ int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops)
{
int ret;
struct mdev_parent *parent;
+ char *env_string = "MDEV_STATE=registered";
+ char *envp[] = { env_string, NULL };
/* check for mandatory ops */
if (!ops || !ops->create || !ops->remove || !ops->supported_type_groups)
@@ -197,6 +196,8 @@ int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops)
mutex_unlock(&parent_list_lock);
dev_info(dev, "MDEV: Registered\n");
+ kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
+
return 0;
add_dev_err:
@@ -220,6 +221,8 @@ EXPORT_SYMBOL(mdev_register_device);
void mdev_unregister_device(struct device *dev)
{
struct mdev_parent *parent;
+ char *env_string = "MDEV_STATE=unregistered";
+ char *envp[] = { env_string, NULL };
mutex_lock(&parent_list_lock);
parent = __find_parent_device(dev);
@@ -243,6 +246,9 @@ void mdev_unregister_device(struct device *dev)
up_write(&parent->unreg_sem);
mdev_put_parent(parent);
+
+ /* We still have the caller's reference to use for the uevent */
+ kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
}
EXPORT_SYMBOL(mdev_unregister_device);
diff --git a/drivers/vfio/mdev/mdev_driver.c b/drivers/vfio/mdev/mdev_driver.c
index 6f0391f6f9b6..0d3223aee20b 100644
--- a/drivers/vfio/mdev/mdev_driver.c
+++ b/drivers/vfio/mdev/mdev_driver.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* MDEV driver
*
* Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
* Author: Neo Jia <cjia@nvidia.com>
* Kirti Wankhede <kwankhede@nvidia.com>
- *
- * 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.
*/
#include <linux/device.h>
diff --git a/drivers/vfio/mdev/mdev_private.h b/drivers/vfio/mdev/mdev_private.h
index 398767526276..7d922950caaf 100644
--- a/drivers/vfio/mdev/mdev_private.h
+++ b/drivers/vfio/mdev/mdev_private.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Mediated device interal definitions
*
* Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
* Author: Neo Jia <cjia@nvidia.com>
* Kirti Wankhede <kwankhede@nvidia.com>
- *
- * 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.
*/
#ifndef MDEV_PRIVATE_H
diff --git a/drivers/vfio/mdev/mdev_sysfs.c b/drivers/vfio/mdev/mdev_sysfs.c
index ffa3dcebf201..7570c7602ab4 100644
--- a/drivers/vfio/mdev/mdev_sysfs.c
+++ b/drivers/vfio/mdev/mdev_sysfs.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* File attributes for Mediated devices
*
* Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
* Author: Neo Jia <cjia@nvidia.com>
* Kirti Wankhede <kwankhede@nvidia.com>
- *
- * 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.
*/
#include <linux/sysfs.h>
diff --git a/drivers/vfio/mdev/vfio_mdev.c b/drivers/vfio/mdev/vfio_mdev.c
index d230620fe02d..30964a4e0a28 100644
--- a/drivers/vfio/mdev/vfio_mdev.c
+++ b/drivers/vfio/mdev/vfio_mdev.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* VFIO based driver for Mediated device
*
* Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
* Author: Neo Jia <cjia@nvidia.com>
* Kirti Wankhede <kwankhede@nvidia.com>
- *
- * 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.
*/
#include <linux/init.h>
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index cab71da46f4a..703948c9fbe1 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Red Hat, Inc. All rights reserved.
* Author: Alex Williamson <alex.williamson@redhat.com>
*
- * 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.
- *
* Derived from original vfio:
* Copyright 2010 Cisco Systems, Inc. All rights reserved.
* Author: Tom Lyon, pugs@cisco.com
diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c
index 52963a904790..f0891bd8444c 100644
--- a/drivers/vfio/pci/vfio_pci_config.c
+++ b/drivers/vfio/pci/vfio_pci_config.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* VFIO PCI config space virtualization
*
* Copyright (C) 2012 Red Hat, Inc. All rights reserved.
* Author: Alex Williamson <alex.williamson@redhat.com>
*
- * 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.
- *
* Derived from original vfio:
* Copyright 2010 Cisco Systems, Inc. All rights reserved.
* Author: Tom Lyon, pugs@cisco.com
diff --git a/drivers/vfio/pci/vfio_pci_igd.c b/drivers/vfio/pci/vfio_pci_igd.c
index 6394b168ef29..53d97f459252 100644
--- a/drivers/vfio/pci/vfio_pci_igd.c
+++ b/drivers/vfio/pci/vfio_pci_igd.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* VFIO PCI Intel Graphics support
*
* Copyright (C) 2016 Red Hat, Inc. All rights reserved.
* Author: Alex Williamson <alex.williamson@redhat.com>
*
- * 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.
- *
* Register a device specific region through which to provide read-only
* access to the Intel IGD opregion. The register defining the opregion
* address is also virtualized to prevent user modification.
diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c
index 1c46045b0e7f..3fa3f728fb39 100644
--- a/drivers/vfio/pci/vfio_pci_intrs.c
+++ b/drivers/vfio/pci/vfio_pci_intrs.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* VFIO PCI interrupt handling
*
* Copyright (C) 2012 Red Hat, Inc. All rights reserved.
* Author: Alex Williamson <alex.williamson@redhat.com>
*
- * 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.
- *
* Derived from original vfio:
* Copyright 2010 Cisco Systems, Inc. All rights reserved.
* Author: Tom Lyon, pugs@cisco.com
diff --git a/drivers/vfio/pci/vfio_pci_nvlink2.c b/drivers/vfio/pci/vfio_pci_nvlink2.c
index 50fe3c4f7feb..f2983f0f84be 100644
--- a/drivers/vfio/pci/vfio_pci_nvlink2.c
+++ b/drivers/vfio/pci/vfio_pci_nvlink2.c
@@ -161,8 +161,7 @@ static int vfio_pci_nvgpu_mmap(struct vfio_pci_device *vdev,
atomic_inc(&data->mm->mm_count);
ret = (int) mm_iommu_newdev(data->mm, data->useraddr,
- (vma->vm_end - vma->vm_start) >> PAGE_SHIFT,
- data->gpu_hpa, &data->mem);
+ vma_pages(vma), data->gpu_hpa, &data->mem);
trace_vfio_pci_nvgpu_mmap(vdev->pdev, data->gpu_hpa, data->useraddr,
vma->vm_end - vma->vm_start, ret);
diff --git a/drivers/vfio/pci/vfio_pci_private.h b/drivers/vfio/pci/vfio_pci_private.h
index 1812cf22fc4f..ee6ee91718a4 100644
--- a/drivers/vfio/pci/vfio_pci_private.h
+++ b/drivers/vfio/pci/vfio_pci_private.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2012 Red Hat, Inc. All rights reserved.
* Author: Alex Williamson <alex.williamson@redhat.com>
*
- * 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.
- *
* Derived from original vfio:
* Copyright 2010 Cisco Systems, Inc. All rights reserved.
* Author: Tom Lyon, pugs@cisco.com
diff --git a/drivers/vfio/pci/vfio_pci_rdwr.c b/drivers/vfio/pci/vfio_pci_rdwr.c
index a6029d0a5524..0120d8324a40 100644
--- a/drivers/vfio/pci/vfio_pci_rdwr.c
+++ b/drivers/vfio/pci/vfio_pci_rdwr.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* VFIO PCI I/O Port & MMIO access
*
* Copyright (C) 2012 Red Hat, Inc. All rights reserved.
* Author: Alex Williamson <alex.williamson@redhat.com>
*
- * 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.
- *
* Derived from original vfio:
* Copyright 2010 Cisco Systems, Inc. All rights reserved.
* Author: Tom Lyon, pugs@cisco.com
diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c
index 82fcf07fa9ea..388597930b64 100644
--- a/drivers/vfio/vfio.c
+++ b/drivers/vfio/vfio.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* VFIO core
*
* Copyright (C) 2012 Red Hat, Inc. All rights reserved.
* Author: Alex Williamson <alex.williamson@redhat.com>
*
- * 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.
- *
* Derived from original vfio:
* Copyright 2010 Cisco Systems, Inc. All rights reserved.
* Author: Tom Lyon, pugs@cisco.com
diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c
index 40ddc0c5f677..8ce9ad21129f 100644
--- a/drivers/vfio/vfio_iommu_spapr_tce.c
+++ b/drivers/vfio/vfio_iommu_spapr_tce.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* VFIO: IOMMU DMA mapping support for TCE on POWER
*
* Copyright (C) 2013 IBM Corp. All rights reserved.
* Author: Alexey Kardashevskiy <aik@ozlabs.ru>
*
- * 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.
- *
* Derived from original vfio_iommu_type1.c:
* Copyright (C) 2012 Red Hat, Inc. All rights reserved.
* Author: Alex Williamson <alex.williamson@redhat.com>
@@ -22,6 +19,7 @@
#include <linux/vmalloc.h>
#include <linux/sched/mm.h>
#include <linux/sched/signal.h>
+#include <linux/mm.h>
#include <asm/iommu.h>
#include <asm/tce.h>
@@ -34,51 +32,6 @@
static void tce_iommu_detach_group(void *iommu_data,
struct iommu_group *iommu_group);
-static long try_increment_locked_vm(struct mm_struct *mm, long npages)
-{
- long ret = 0, locked, lock_limit;
-
- if (WARN_ON_ONCE(!mm))
- return -EPERM;
-
- if (!npages)
- return 0;
-
- down_write(&mm->mmap_sem);
- locked = mm->locked_vm + npages;
- lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
- if (locked > lock_limit && !capable(CAP_IPC_LOCK))
- ret = -ENOMEM;
- else
- mm->locked_vm += npages;
-
- pr_debug("[%d] RLIMIT_MEMLOCK +%ld %ld/%ld%s\n", current->pid,
- npages << PAGE_SHIFT,
- mm->locked_vm << PAGE_SHIFT,
- rlimit(RLIMIT_MEMLOCK),
- ret ? " - exceeded" : "");
-
- up_write(&mm->mmap_sem);
-
- return ret;
-}
-
-static void decrement_locked_vm(struct mm_struct *mm, long npages)
-{
- if (!mm || !npages)
- return;
-
- down_write(&mm->mmap_sem);
- if (WARN_ON_ONCE(npages > mm->locked_vm))
- npages = mm->locked_vm;
- mm->locked_vm -= npages;
- pr_debug("[%d] RLIMIT_MEMLOCK -%ld %ld/%ld\n", current->pid,
- npages << PAGE_SHIFT,
- mm->locked_vm << PAGE_SHIFT,
- rlimit(RLIMIT_MEMLOCK));
- up_write(&mm->mmap_sem);
-}
-
/*
* VFIO IOMMU fd for SPAPR_TCE IOMMU implementation
*
@@ -336,7 +289,7 @@ static int tce_iommu_enable(struct tce_container *container)
return ret;
locked = table_group->tce32_size >> PAGE_SHIFT;
- ret = try_increment_locked_vm(container->mm, locked);
+ ret = account_locked_vm(container->mm, locked, true);
if (ret)
return ret;
@@ -355,7 +308,7 @@ static void tce_iommu_disable(struct tce_container *container)
container->enabled = false;
BUG_ON(!container->mm);
- decrement_locked_vm(container->mm, container->locked_pages);
+ account_locked_vm(container->mm, container->locked_pages, false);
}
static void *tce_iommu_open(unsigned long arg)
@@ -659,7 +612,7 @@ static long tce_iommu_create_table(struct tce_container *container,
if (!table_size)
return -EINVAL;
- ret = try_increment_locked_vm(container->mm, table_size >> PAGE_SHIFT);
+ ret = account_locked_vm(container->mm, table_size >> PAGE_SHIFT, true);
if (ret)
return ret;
@@ -678,7 +631,7 @@ static void tce_iommu_free_table(struct tce_container *container,
unsigned long pages = tbl->it_allocated_size >> PAGE_SHIFT;
iommu_tce_table_put(tbl);
- decrement_locked_vm(container->mm, pages);
+ account_locked_vm(container->mm, pages, false);
}
static long tce_iommu_create_window(struct tce_container *container,
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 3ddc375e7063..054391f30fa8 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* VFIO: IOMMU DMA mapping support for Type1 IOMMU
*
* Copyright (C) 2012 Red Hat, Inc. All rights reserved.
* Author: Alex Williamson <alex.williamson@redhat.com>
*
- * 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.
- *
* Derived from original vfio:
* Copyright 2010 Cisco Systems, Inc. All rights reserved.
* Author: Tom Lyon, pugs@cisco.com
@@ -275,21 +272,8 @@ static int vfio_lock_acct(struct vfio_dma *dma, long npage, bool async)
ret = down_write_killable(&mm->mmap_sem);
if (!ret) {
- if (npage > 0) {
- if (!dma->lock_cap) {
- unsigned long limit;
-
- limit = task_rlimit(dma->task,
- RLIMIT_MEMLOCK) >> PAGE_SHIFT;
-
- if (mm->locked_vm + npage > limit)
- ret = -ENOMEM;
- }
- }
-
- if (!ret)
- mm->locked_vm += npage;
-
+ ret = __account_locked_vm(mm, abs(npage), npage > 0, dma->task,
+ dma->lock_cap);
up_write(&mm->mmap_sem);
}
diff --git a/drivers/vfio/vfio_spapr_eeh.c b/drivers/vfio/vfio_spapr_eeh.c
index 1a742fe8f6db..67f55ac1d459 100644
--- a/drivers/vfio/vfio_spapr_eeh.c
+++ b/drivers/vfio/vfio_spapr_eeh.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* EEH functionality support for VFIO devices. The feature is only
* available on sPAPR compatible platforms.
*
* Copyright Gavin Shan, IBM Corporation 2014.
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/vfio/virqfd.c b/drivers/vfio/virqfd.c
index 2a1be859ee71..997cb5d0a657 100644
--- a/drivers/vfio/virqfd.c
+++ b/drivers/vfio/virqfd.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* VFIO generic eventfd code for IRQFD support.
* Derived from drivers/vfio/pci/vfio_pci_intrs.c
*
* Copyright (C) 2012 Red Hat, Inc. All rights reserved.
* Author: Alex Williamson <alex.williamson@redhat.com>
- *
- * 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.
*/
#include <linux/vfio.h>
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 2d9df786a9d3..1a2dd53caade 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -1,8 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2009 Red Hat, Inc.
* Author: Michael S. Tsirkin <mst@redhat.com>
*
- * This work is licensed under the terms of the GNU GPL, version 2.
- *
* virtio-net server in host kernel.
*/
@@ -36,7 +35,7 @@
#include "vhost.h"
-static int experimental_zcopytx = 1;
+static int experimental_zcopytx = 0;
module_param(experimental_zcopytx, int, 0444);
MODULE_PARM_DESC(experimental_zcopytx, "Enable Zero Copy TX;"
" 1 -Enable; 0 - Disable");
@@ -957,7 +956,7 @@ static void handle_tx(struct vhost_net *net)
if (!sock)
goto out;
- if (!vq_iotlb_prefetch(vq))
+ if (!vq_meta_prefetch(vq))
goto out;
vhost_disable_notify(&net->dev, vq);
@@ -1126,7 +1125,7 @@ static void handle_rx(struct vhost_net *net)
if (!sock)
goto out;
- if (!vq_iotlb_prefetch(vq))
+ if (!vq_meta_prefetch(vq))
goto out;
vhost_disable_notify(&net->dev, vq);
diff --git a/drivers/vhost/test.c b/drivers/vhost/test.c
index 40589850eb33..9e90e969af55 100644
--- a/drivers/vhost/test.c
+++ b/drivers/vhost/test.c
@@ -1,8 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2009 Red Hat, Inc.
* Author: Michael S. Tsirkin <mst@redhat.com>
*
- * This work is licensed under the terms of the GNU GPL, version 2.
- *
* test virtio server in host kernel.
*/
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index 3f3eac4bcc58..0536f8526359 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2009 Red Hat, Inc.
* Copyright (C) 2006 Rusty Russell IBM Corporation
*
@@ -6,8 +7,6 @@
* Inspiration, some code, and most witty comments come from
* Documentation/virtual/lguest/lguest.c, by Rusty Russell
*
- * This work is licensed under the terms of the GNU GPL, version 2.
- *
* Generic code for virtio server in host kernel.
*/
@@ -299,6 +298,160 @@ static void vhost_vq_meta_reset(struct vhost_dev *d)
__vhost_vq_meta_reset(d->vqs[i]);
}
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+static void vhost_map_unprefetch(struct vhost_map *map)
+{
+ kfree(map->pages);
+ map->pages = NULL;
+ map->npages = 0;
+ map->addr = NULL;
+}
+
+static void vhost_uninit_vq_maps(struct vhost_virtqueue *vq)
+{
+ struct vhost_map *map[VHOST_NUM_ADDRS];
+ int i;
+
+ spin_lock(&vq->mmu_lock);
+ for (i = 0; i < VHOST_NUM_ADDRS; i++) {
+ map[i] = rcu_dereference_protected(vq->maps[i],
+ lockdep_is_held(&vq->mmu_lock));
+ if (map[i])
+ rcu_assign_pointer(vq->maps[i], NULL);
+ }
+ spin_unlock(&vq->mmu_lock);
+
+ synchronize_rcu();
+
+ for (i = 0; i < VHOST_NUM_ADDRS; i++)
+ if (map[i])
+ vhost_map_unprefetch(map[i]);
+
+}
+
+static void vhost_reset_vq_maps(struct vhost_virtqueue *vq)
+{
+ int i;
+
+ vhost_uninit_vq_maps(vq);
+ for (i = 0; i < VHOST_NUM_ADDRS; i++)
+ vq->uaddrs[i].size = 0;
+}
+
+static bool vhost_map_range_overlap(struct vhost_uaddr *uaddr,
+ unsigned long start,
+ unsigned long end)
+{
+ if (unlikely(!uaddr->size))
+ return false;
+
+ return !(end < uaddr->uaddr || start > uaddr->uaddr - 1 + uaddr->size);
+}
+
+static void vhost_invalidate_vq_start(struct vhost_virtqueue *vq,
+ int index,
+ unsigned long start,
+ unsigned long end)
+{
+ struct vhost_uaddr *uaddr = &vq->uaddrs[index];
+ struct vhost_map *map;
+ int i;
+
+ if (!vhost_map_range_overlap(uaddr, start, end))
+ return;
+
+ spin_lock(&vq->mmu_lock);
+ ++vq->invalidate_count;
+
+ map = rcu_dereference_protected(vq->maps[index],
+ lockdep_is_held(&vq->mmu_lock));
+ if (map) {
+ if (uaddr->write) {
+ for (i = 0; i < map->npages; i++)
+ set_page_dirty(map->pages[i]);
+ }
+ rcu_assign_pointer(vq->maps[index], NULL);
+ }
+ spin_unlock(&vq->mmu_lock);
+
+ if (map) {
+ synchronize_rcu();
+ vhost_map_unprefetch(map);
+ }
+}
+
+static void vhost_invalidate_vq_end(struct vhost_virtqueue *vq,
+ int index,
+ unsigned long start,
+ unsigned long end)
+{
+ if (!vhost_map_range_overlap(&vq->uaddrs[index], start, end))
+ return;
+
+ spin_lock(&vq->mmu_lock);
+ --vq->invalidate_count;
+ spin_unlock(&vq->mmu_lock);
+}
+
+static int vhost_invalidate_range_start(struct mmu_notifier *mn,
+ const struct mmu_notifier_range *range)
+{
+ struct vhost_dev *dev = container_of(mn, struct vhost_dev,
+ mmu_notifier);
+ int i, j;
+
+ if (!mmu_notifier_range_blockable(range))
+ return -EAGAIN;
+
+ for (i = 0; i < dev->nvqs; i++) {
+ struct vhost_virtqueue *vq = dev->vqs[i];
+
+ for (j = 0; j < VHOST_NUM_ADDRS; j++)
+ vhost_invalidate_vq_start(vq, j,
+ range->start,
+ range->end);
+ }
+
+ return 0;
+}
+
+static void vhost_invalidate_range_end(struct mmu_notifier *mn,
+ const struct mmu_notifier_range *range)
+{
+ struct vhost_dev *dev = container_of(mn, struct vhost_dev,
+ mmu_notifier);
+ int i, j;
+
+ for (i = 0; i < dev->nvqs; i++) {
+ struct vhost_virtqueue *vq = dev->vqs[i];
+
+ for (j = 0; j < VHOST_NUM_ADDRS; j++)
+ vhost_invalidate_vq_end(vq, j,
+ range->start,
+ range->end);
+ }
+}
+
+static const struct mmu_notifier_ops vhost_mmu_notifier_ops = {
+ .invalidate_range_start = vhost_invalidate_range_start,
+ .invalidate_range_end = vhost_invalidate_range_end,
+};
+
+static void vhost_init_maps(struct vhost_dev *dev)
+{
+ struct vhost_virtqueue *vq;
+ int i, j;
+
+ dev->mmu_notifier.ops = &vhost_mmu_notifier_ops;
+
+ for (i = 0; i < dev->nvqs; ++i) {
+ vq = dev->vqs[i];
+ for (j = 0; j < VHOST_NUM_ADDRS; j++)
+ RCU_INIT_POINTER(vq->maps[j], NULL);
+ }
+}
+#endif
+
static void vhost_vq_reset(struct vhost_dev *dev,
struct vhost_virtqueue *vq)
{
@@ -327,7 +480,11 @@ static void vhost_vq_reset(struct vhost_dev *dev,
vq->busyloop_timeout = 0;
vq->umem = NULL;
vq->iotlb = NULL;
+ vq->invalidate_count = 0;
__vhost_vq_meta_reset(vq);
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+ vhost_reset_vq_maps(vq);
+#endif
}
static int vhost_worker(void *data)
@@ -428,6 +585,32 @@ bool vhost_exceeds_weight(struct vhost_virtqueue *vq,
}
EXPORT_SYMBOL_GPL(vhost_exceeds_weight);
+static size_t vhost_get_avail_size(struct vhost_virtqueue *vq,
+ unsigned int num)
+{
+ size_t event __maybe_unused =
+ vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
+
+ return sizeof(*vq->avail) +
+ sizeof(*vq->avail->ring) * num + event;
+}
+
+static size_t vhost_get_used_size(struct vhost_virtqueue *vq,
+ unsigned int num)
+{
+ size_t event __maybe_unused =
+ vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
+
+ return sizeof(*vq->used) +
+ sizeof(*vq->used->ring) * num + event;
+}
+
+static size_t vhost_get_desc_size(struct vhost_virtqueue *vq,
+ unsigned int num)
+{
+ return sizeof(*vq->desc) * num;
+}
+
void vhost_dev_init(struct vhost_dev *dev,
struct vhost_virtqueue **vqs, int nvqs,
int iov_limit, int weight, int byte_weight)
@@ -451,7 +634,9 @@ void vhost_dev_init(struct vhost_dev *dev,
INIT_LIST_HEAD(&dev->read_list);
INIT_LIST_HEAD(&dev->pending_list);
spin_lock_init(&dev->iotlb_lock);
-
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+ vhost_init_maps(dev);
+#endif
for (i = 0; i < dev->nvqs; ++i) {
vq = dev->vqs[i];
@@ -460,6 +645,7 @@ void vhost_dev_init(struct vhost_dev *dev,
vq->heads = NULL;
vq->dev = dev;
mutex_init(&vq->mutex);
+ spin_lock_init(&vq->mmu_lock);
vhost_vq_reset(dev, vq);
if (vq->handle_kick)
vhost_poll_init(&vq->poll, vq->handle_kick,
@@ -539,7 +725,18 @@ long vhost_dev_set_owner(struct vhost_dev *dev)
if (err)
goto err_cgroup;
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+ err = mmu_notifier_register(&dev->mmu_notifier, dev->mm);
+ if (err)
+ goto err_mmu_notifier;
+#endif
+
return 0;
+
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+err_mmu_notifier:
+ vhost_dev_free_iovecs(dev);
+#endif
err_cgroup:
kthread_stop(worker);
dev->worker = NULL;
@@ -630,6 +827,107 @@ static void vhost_clear_msg(struct vhost_dev *dev)
spin_unlock(&dev->iotlb_lock);
}
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+static void vhost_setup_uaddr(struct vhost_virtqueue *vq,
+ int index, unsigned long uaddr,
+ size_t size, bool write)
+{
+ struct vhost_uaddr *addr = &vq->uaddrs[index];
+
+ addr->uaddr = uaddr;
+ addr->size = size;
+ addr->write = write;
+}
+
+static void vhost_setup_vq_uaddr(struct vhost_virtqueue *vq)
+{
+ vhost_setup_uaddr(vq, VHOST_ADDR_DESC,
+ (unsigned long)vq->desc,
+ vhost_get_desc_size(vq, vq->num),
+ false);
+ vhost_setup_uaddr(vq, VHOST_ADDR_AVAIL,
+ (unsigned long)vq->avail,
+ vhost_get_avail_size(vq, vq->num),
+ false);
+ vhost_setup_uaddr(vq, VHOST_ADDR_USED,
+ (unsigned long)vq->used,
+ vhost_get_used_size(vq, vq->num),
+ true);
+}
+
+static int vhost_map_prefetch(struct vhost_virtqueue *vq,
+ int index)
+{
+ struct vhost_map *map;
+ struct vhost_uaddr *uaddr = &vq->uaddrs[index];
+ struct page **pages;
+ int npages = DIV_ROUND_UP(uaddr->size, PAGE_SIZE);
+ int npinned;
+ void *vaddr, *v;
+ int err;
+ int i;
+
+ spin_lock(&vq->mmu_lock);
+
+ err = -EFAULT;
+ if (vq->invalidate_count)
+ goto err;
+
+ err = -ENOMEM;
+ map = kmalloc(sizeof(*map), GFP_ATOMIC);
+ if (!map)
+ goto err;
+
+ pages = kmalloc_array(npages, sizeof(struct page *), GFP_ATOMIC);
+ if (!pages)
+ goto err_pages;
+
+ err = EFAULT;
+ npinned = __get_user_pages_fast(uaddr->uaddr, npages,
+ uaddr->write, pages);
+ if (npinned > 0)
+ release_pages(pages, npinned);
+ if (npinned != npages)
+ goto err_gup;
+
+ for (i = 0; i < npinned; i++)
+ if (PageHighMem(pages[i]))
+ goto err_gup;
+
+ vaddr = v = page_address(pages[0]);
+
+ /* For simplicity, fallback to userspace address if VA is not
+ * contigious.
+ */
+ for (i = 1; i < npinned; i++) {
+ v += PAGE_SIZE;
+ if (v != page_address(pages[i]))
+ goto err_gup;
+ }
+
+ map->addr = vaddr + (uaddr->uaddr & (PAGE_SIZE - 1));
+ map->npages = npages;
+ map->pages = pages;
+
+ rcu_assign_pointer(vq->maps[index], map);
+ /* No need for a synchronize_rcu(). This function should be
+ * called by dev->worker so we are serialized with all
+ * readers.
+ */
+ spin_unlock(&vq->mmu_lock);
+
+ return 0;
+
+err_gup:
+ kfree(pages);
+err_pages:
+ kfree(map);
+err:
+ spin_unlock(&vq->mmu_lock);
+ return err;
+}
+#endif
+
void vhost_dev_cleanup(struct vhost_dev *dev)
{
int i;
@@ -659,8 +957,16 @@ void vhost_dev_cleanup(struct vhost_dev *dev)
kthread_stop(dev->worker);
dev->worker = NULL;
}
- if (dev->mm)
+ if (dev->mm) {
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+ mmu_notifier_unregister(&dev->mmu_notifier, dev->mm);
+#endif
mmput(dev->mm);
+ }
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+ for (i = 0; i < dev->nvqs; i++)
+ vhost_uninit_vq_maps(dev->vqs[i]);
+#endif
dev->mm = NULL;
}
EXPORT_SYMBOL_GPL(vhost_dev_cleanup);
@@ -887,6 +1193,113 @@ static inline void __user *__vhost_get_user(struct vhost_virtqueue *vq,
ret; \
})
+static inline int vhost_put_avail_event(struct vhost_virtqueue *vq)
+{
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+ struct vhost_map *map;
+ struct vring_used *used;
+
+ if (!vq->iotlb) {
+ rcu_read_lock();
+
+ map = rcu_dereference(vq->maps[VHOST_ADDR_USED]);
+ if (likely(map)) {
+ used = map->addr;
+ *((__virtio16 *)&used->ring[vq->num]) =
+ cpu_to_vhost16(vq, vq->avail_idx);
+ rcu_read_unlock();
+ return 0;
+ }
+
+ rcu_read_unlock();
+ }
+#endif
+
+ return vhost_put_user(vq, cpu_to_vhost16(vq, vq->avail_idx),
+ vhost_avail_event(vq));
+}
+
+static inline int vhost_put_used(struct vhost_virtqueue *vq,
+ struct vring_used_elem *head, int idx,
+ int count)
+{
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+ struct vhost_map *map;
+ struct vring_used *used;
+ size_t size;
+
+ if (!vq->iotlb) {
+ rcu_read_lock();
+
+ map = rcu_dereference(vq->maps[VHOST_ADDR_USED]);
+ if (likely(map)) {
+ used = map->addr;
+ size = count * sizeof(*head);
+ memcpy(used->ring + idx, head, size);
+ rcu_read_unlock();
+ return 0;
+ }
+
+ rcu_read_unlock();
+ }
+#endif
+
+ return vhost_copy_to_user(vq, vq->used->ring + idx, head,
+ count * sizeof(*head));
+}
+
+static inline int vhost_put_used_flags(struct vhost_virtqueue *vq)
+
+{
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+ struct vhost_map *map;
+ struct vring_used *used;
+
+ if (!vq->iotlb) {
+ rcu_read_lock();
+
+ map = rcu_dereference(vq->maps[VHOST_ADDR_USED]);
+ if (likely(map)) {
+ used = map->addr;
+ used->flags = cpu_to_vhost16(vq, vq->used_flags);
+ rcu_read_unlock();
+ return 0;
+ }
+
+ rcu_read_unlock();
+ }
+#endif
+
+ return vhost_put_user(vq, cpu_to_vhost16(vq, vq->used_flags),
+ &vq->used->flags);
+}
+
+static inline int vhost_put_used_idx(struct vhost_virtqueue *vq)
+
+{
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+ struct vhost_map *map;
+ struct vring_used *used;
+
+ if (!vq->iotlb) {
+ rcu_read_lock();
+
+ map = rcu_dereference(vq->maps[VHOST_ADDR_USED]);
+ if (likely(map)) {
+ used = map->addr;
+ used->idx = cpu_to_vhost16(vq, vq->last_used_idx);
+ rcu_read_unlock();
+ return 0;
+ }
+
+ rcu_read_unlock();
+ }
+#endif
+
+ return vhost_put_user(vq, cpu_to_vhost16(vq, vq->last_used_idx),
+ &vq->used->idx);
+}
+
#define vhost_get_user(vq, x, ptr, type) \
({ \
int ret; \
@@ -925,6 +1338,155 @@ static void vhost_dev_unlock_vqs(struct vhost_dev *d)
mutex_unlock(&d->vqs[i]->mutex);
}
+static inline int vhost_get_avail_idx(struct vhost_virtqueue *vq,
+ __virtio16 *idx)
+{
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+ struct vhost_map *map;
+ struct vring_avail *avail;
+
+ if (!vq->iotlb) {
+ rcu_read_lock();
+
+ map = rcu_dereference(vq->maps[VHOST_ADDR_AVAIL]);
+ if (likely(map)) {
+ avail = map->addr;
+ *idx = avail->idx;
+ rcu_read_unlock();
+ return 0;
+ }
+
+ rcu_read_unlock();
+ }
+#endif
+
+ return vhost_get_avail(vq, *idx, &vq->avail->idx);
+}
+
+static inline int vhost_get_avail_head(struct vhost_virtqueue *vq,
+ __virtio16 *head, int idx)
+{
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+ struct vhost_map *map;
+ struct vring_avail *avail;
+
+ if (!vq->iotlb) {
+ rcu_read_lock();
+
+ map = rcu_dereference(vq->maps[VHOST_ADDR_AVAIL]);
+ if (likely(map)) {
+ avail = map->addr;
+ *head = avail->ring[idx & (vq->num - 1)];
+ rcu_read_unlock();
+ return 0;
+ }
+
+ rcu_read_unlock();
+ }
+#endif
+
+ return vhost_get_avail(vq, *head,
+ &vq->avail->ring[idx & (vq->num - 1)]);
+}
+
+static inline int vhost_get_avail_flags(struct vhost_virtqueue *vq,
+ __virtio16 *flags)
+{
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+ struct vhost_map *map;
+ struct vring_avail *avail;
+
+ if (!vq->iotlb) {
+ rcu_read_lock();
+
+ map = rcu_dereference(vq->maps[VHOST_ADDR_AVAIL]);
+ if (likely(map)) {
+ avail = map->addr;
+ *flags = avail->flags;
+ rcu_read_unlock();
+ return 0;
+ }
+
+ rcu_read_unlock();
+ }
+#endif
+
+ return vhost_get_avail(vq, *flags, &vq->avail->flags);
+}
+
+static inline int vhost_get_used_event(struct vhost_virtqueue *vq,
+ __virtio16 *event)
+{
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+ struct vhost_map *map;
+ struct vring_avail *avail;
+
+ if (!vq->iotlb) {
+ rcu_read_lock();
+ map = rcu_dereference(vq->maps[VHOST_ADDR_AVAIL]);
+ if (likely(map)) {
+ avail = map->addr;
+ *event = (__virtio16)avail->ring[vq->num];
+ rcu_read_unlock();
+ return 0;
+ }
+ rcu_read_unlock();
+ }
+#endif
+
+ return vhost_get_avail(vq, *event, vhost_used_event(vq));
+}
+
+static inline int vhost_get_used_idx(struct vhost_virtqueue *vq,
+ __virtio16 *idx)
+{
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+ struct vhost_map *map;
+ struct vring_used *used;
+
+ if (!vq->iotlb) {
+ rcu_read_lock();
+
+ map = rcu_dereference(vq->maps[VHOST_ADDR_USED]);
+ if (likely(map)) {
+ used = map->addr;
+ *idx = used->idx;
+ rcu_read_unlock();
+ return 0;
+ }
+
+ rcu_read_unlock();
+ }
+#endif
+
+ return vhost_get_used(vq, *idx, &vq->used->idx);
+}
+
+static inline int vhost_get_desc(struct vhost_virtqueue *vq,
+ struct vring_desc *desc, int idx)
+{
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+ struct vhost_map *map;
+ struct vring_desc *d;
+
+ if (!vq->iotlb) {
+ rcu_read_lock();
+
+ map = rcu_dereference(vq->maps[VHOST_ADDR_DESC]);
+ if (likely(map)) {
+ d = map->addr;
+ *desc = *(d + idx);
+ rcu_read_unlock();
+ return 0;
+ }
+
+ rcu_read_unlock();
+ }
+#endif
+
+ return vhost_copy_from_user(vq, desc, vq->desc + idx, sizeof(*desc));
+}
+
static int vhost_new_umem_range(struct vhost_umem *umem,
u64 start, u64 size, u64 end,
u64 userspace_addr, int perm)
@@ -1210,13 +1772,9 @@ static bool vq_access_ok(struct vhost_virtqueue *vq, unsigned int num,
struct vring_used __user *used)
{
- size_t s __maybe_unused = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
-
- return access_ok(desc, num * sizeof *desc) &&
- access_ok(avail,
- sizeof *avail + num * sizeof *avail->ring + s) &&
- access_ok(used,
- sizeof *used + num * sizeof *used->ring + s);
+ return access_ok(desc, vhost_get_desc_size(vq, num)) &&
+ access_ok(avail, vhost_get_avail_size(vq, num)) &&
+ access_ok(used, vhost_get_used_size(vq, num));
}
static void vhost_vq_meta_update(struct vhost_virtqueue *vq,
@@ -1266,26 +1824,42 @@ static bool iotlb_access_ok(struct vhost_virtqueue *vq,
return true;
}
-int vq_iotlb_prefetch(struct vhost_virtqueue *vq)
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+static void vhost_vq_map_prefetch(struct vhost_virtqueue *vq)
+{
+ struct vhost_map __rcu *map;
+ int i;
+
+ for (i = 0; i < VHOST_NUM_ADDRS; i++) {
+ rcu_read_lock();
+ map = rcu_dereference(vq->maps[i]);
+ rcu_read_unlock();
+ if (unlikely(!map))
+ vhost_map_prefetch(vq, i);
+ }
+}
+#endif
+
+int vq_meta_prefetch(struct vhost_virtqueue *vq)
{
- size_t s = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
unsigned int num = vq->num;
- if (!vq->iotlb)
+ if (!vq->iotlb) {
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+ vhost_vq_map_prefetch(vq);
+#endif
return 1;
+ }
return iotlb_access_ok(vq, VHOST_ACCESS_RO, (u64)(uintptr_t)vq->desc,
- num * sizeof(*vq->desc), VHOST_ADDR_DESC) &&
+ vhost_get_desc_size(vq, num), VHOST_ADDR_DESC) &&
iotlb_access_ok(vq, VHOST_ACCESS_RO, (u64)(uintptr_t)vq->avail,
- sizeof *vq->avail +
- num * sizeof(*vq->avail->ring) + s,
+ vhost_get_avail_size(vq, num),
VHOST_ADDR_AVAIL) &&
iotlb_access_ok(vq, VHOST_ACCESS_WO, (u64)(uintptr_t)vq->used,
- sizeof *vq->used +
- num * sizeof(*vq->used->ring) + s,
- VHOST_ADDR_USED);
+ vhost_get_used_size(vq, num), VHOST_ADDR_USED);
}
-EXPORT_SYMBOL_GPL(vq_iotlb_prefetch);
+EXPORT_SYMBOL_GPL(vq_meta_prefetch);
/* Can we log writes? */
/* Caller should have device mutex but not vq mutex */
@@ -1300,13 +1874,10 @@ EXPORT_SYMBOL_GPL(vhost_log_access_ok);
static bool vq_log_access_ok(struct vhost_virtqueue *vq,
void __user *log_base)
{
- size_t s = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
-
return vq_memory_access_ok(log_base, vq->umem,
vhost_has_feature(vq, VHOST_F_LOG_ALL)) &&
(!vq->log_used || log_access_ok(log_base, vq->log_addr,
- sizeof *vq->used +
- vq->num * sizeof *vq->used->ring + s));
+ vhost_get_used_size(vq, vq->num)));
}
/* Can we start vq? */
@@ -1406,6 +1977,121 @@ err:
return -EFAULT;
}
+static long vhost_vring_set_num(struct vhost_dev *d,
+ struct vhost_virtqueue *vq,
+ void __user *argp)
+{
+ struct vhost_vring_state s;
+
+ /* Resizing ring with an active backend?
+ * You don't want to do that. */
+ if (vq->private_data)
+ return -EBUSY;
+
+ if (copy_from_user(&s, argp, sizeof s))
+ return -EFAULT;
+
+ if (!s.num || s.num > 0xffff || (s.num & (s.num - 1)))
+ return -EINVAL;
+ vq->num = s.num;
+
+ return 0;
+}
+
+static long vhost_vring_set_addr(struct vhost_dev *d,
+ struct vhost_virtqueue *vq,
+ void __user *argp)
+{
+ struct vhost_vring_addr a;
+
+ if (copy_from_user(&a, argp, sizeof a))
+ return -EFAULT;
+ if (a.flags & ~(0x1 << VHOST_VRING_F_LOG))
+ return -EOPNOTSUPP;
+
+ /* For 32bit, verify that the top 32bits of the user
+ data are set to zero. */
+ if ((u64)(unsigned long)a.desc_user_addr != a.desc_user_addr ||
+ (u64)(unsigned long)a.used_user_addr != a.used_user_addr ||
+ (u64)(unsigned long)a.avail_user_addr != a.avail_user_addr)
+ return -EFAULT;
+
+ /* Make sure it's safe to cast pointers to vring types. */
+ BUILD_BUG_ON(__alignof__ *vq->avail > VRING_AVAIL_ALIGN_SIZE);
+ BUILD_BUG_ON(__alignof__ *vq->used > VRING_USED_ALIGN_SIZE);
+ if ((a.avail_user_addr & (VRING_AVAIL_ALIGN_SIZE - 1)) ||
+ (a.used_user_addr & (VRING_USED_ALIGN_SIZE - 1)) ||
+ (a.log_guest_addr & (VRING_USED_ALIGN_SIZE - 1)))
+ return -EINVAL;
+
+ /* We only verify access here if backend is configured.
+ * If it is not, we don't as size might not have been setup.
+ * We will verify when backend is configured. */
+ if (vq->private_data) {
+ if (!vq_access_ok(vq, vq->num,
+ (void __user *)(unsigned long)a.desc_user_addr,
+ (void __user *)(unsigned long)a.avail_user_addr,
+ (void __user *)(unsigned long)a.used_user_addr))
+ return -EINVAL;
+
+ /* Also validate log access for used ring if enabled. */
+ if ((a.flags & (0x1 << VHOST_VRING_F_LOG)) &&
+ !log_access_ok(vq->log_base, a.log_guest_addr,
+ sizeof *vq->used +
+ vq->num * sizeof *vq->used->ring))
+ return -EINVAL;
+ }
+
+ vq->log_used = !!(a.flags & (0x1 << VHOST_VRING_F_LOG));
+ vq->desc = (void __user *)(unsigned long)a.desc_user_addr;
+ vq->avail = (void __user *)(unsigned long)a.avail_user_addr;
+ vq->log_addr = a.log_guest_addr;
+ vq->used = (void __user *)(unsigned long)a.used_user_addr;
+
+ return 0;
+}
+
+static long vhost_vring_set_num_addr(struct vhost_dev *d,
+ struct vhost_virtqueue *vq,
+ unsigned int ioctl,
+ void __user *argp)
+{
+ long r;
+
+ mutex_lock(&vq->mutex);
+
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+ /* Unregister MMU notifer to allow invalidation callback
+ * can access vq->uaddrs[] without holding a lock.
+ */
+ if (d->mm)
+ mmu_notifier_unregister(&d->mmu_notifier, d->mm);
+
+ vhost_uninit_vq_maps(vq);
+#endif
+
+ switch (ioctl) {
+ case VHOST_SET_VRING_NUM:
+ r = vhost_vring_set_num(d, vq, argp);
+ break;
+ case VHOST_SET_VRING_ADDR:
+ r = vhost_vring_set_addr(d, vq, argp);
+ break;
+ default:
+ BUG();
+ }
+
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+ vhost_setup_vq_uaddr(vq);
+
+ if (d->mm)
+ mmu_notifier_register(&d->mmu_notifier, d->mm);
+#endif
+
+ mutex_unlock(&vq->mutex);
+
+ return r;
+}
long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *argp)
{
struct file *eventfp, *filep = NULL;
@@ -1415,7 +2101,6 @@ long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *arg
struct vhost_virtqueue *vq;
struct vhost_vring_state s;
struct vhost_vring_file f;
- struct vhost_vring_addr a;
u32 idx;
long r;
@@ -1428,26 +2113,14 @@ long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *arg
idx = array_index_nospec(idx, d->nvqs);
vq = d->vqs[idx];
+ if (ioctl == VHOST_SET_VRING_NUM ||
+ ioctl == VHOST_SET_VRING_ADDR) {
+ return vhost_vring_set_num_addr(d, vq, ioctl, argp);
+ }
+
mutex_lock(&vq->mutex);
switch (ioctl) {
- case VHOST_SET_VRING_NUM:
- /* Resizing ring with an active backend?
- * You don't want to do that. */
- if (vq->private_data) {
- r = -EBUSY;
- break;
- }
- if (copy_from_user(&s, argp, sizeof s)) {
- r = -EFAULT;
- break;
- }
- if (!s.num || s.num > 0xffff || (s.num & (s.num - 1))) {
- r = -EINVAL;
- break;
- }
- vq->num = s.num;
- break;
case VHOST_SET_VRING_BASE:
/* Moving base with an active backend?
* You don't want to do that. */
@@ -1473,62 +2146,6 @@ long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *arg
if (copy_to_user(argp, &s, sizeof s))
r = -EFAULT;
break;
- case VHOST_SET_VRING_ADDR:
- if (copy_from_user(&a, argp, sizeof a)) {
- r = -EFAULT;
- break;
- }
- if (a.flags & ~(0x1 << VHOST_VRING_F_LOG)) {
- r = -EOPNOTSUPP;
- break;
- }
- /* For 32bit, verify that the top 32bits of the user
- data are set to zero. */
- if ((u64)(unsigned long)a.desc_user_addr != a.desc_user_addr ||
- (u64)(unsigned long)a.used_user_addr != a.used_user_addr ||
- (u64)(unsigned long)a.avail_user_addr != a.avail_user_addr) {
- r = -EFAULT;
- break;
- }
-
- /* Make sure it's safe to cast pointers to vring types. */
- BUILD_BUG_ON(__alignof__ *vq->avail > VRING_AVAIL_ALIGN_SIZE);
- BUILD_BUG_ON(__alignof__ *vq->used > VRING_USED_ALIGN_SIZE);
- if ((a.avail_user_addr & (VRING_AVAIL_ALIGN_SIZE - 1)) ||
- (a.used_user_addr & (VRING_USED_ALIGN_SIZE - 1)) ||
- (a.log_guest_addr & (VRING_USED_ALIGN_SIZE - 1))) {
- r = -EINVAL;
- break;
- }
-
- /* We only verify access here if backend is configured.
- * If it is not, we don't as size might not have been setup.
- * We will verify when backend is configured. */
- if (vq->private_data) {
- if (!vq_access_ok(vq, vq->num,
- (void __user *)(unsigned long)a.desc_user_addr,
- (void __user *)(unsigned long)a.avail_user_addr,
- (void __user *)(unsigned long)a.used_user_addr)) {
- r = -EINVAL;
- break;
- }
-
- /* Also validate log access for used ring if enabled. */
- if ((a.flags & (0x1 << VHOST_VRING_F_LOG)) &&
- !log_access_ok(vq->log_base, a.log_guest_addr,
- sizeof *vq->used +
- vq->num * sizeof *vq->used->ring)) {
- r = -EINVAL;
- break;
- }
- }
-
- vq->log_used = !!(a.flags & (0x1 << VHOST_VRING_F_LOG));
- vq->desc = (void __user *)(unsigned long)a.desc_user_addr;
- vq->avail = (void __user *)(unsigned long)a.avail_user_addr;
- vq->log_addr = a.log_guest_addr;
- vq->used = (void __user *)(unsigned long)a.used_user_addr;
- break;
case VHOST_SET_VRING_KICK:
if (copy_from_user(&f, argp, sizeof f)) {
r = -EFAULT;
@@ -1712,7 +2329,7 @@ EXPORT_SYMBOL_GPL(vhost_dev_ioctl);
/* TODO: This is really inefficient. We need something like get_user()
* (instruction directly accesses the data, with an exception table entry
- * returning -EFAULT). See Documentation/x86/exception-tables.txt.
+ * returning -EFAULT). See Documentation/x86/exception-tables.rst.
*/
static int set_bit_to_user(int nr, void __user *addr)
{
@@ -1862,8 +2479,7 @@ EXPORT_SYMBOL_GPL(vhost_log_write);
static int vhost_update_used_flags(struct vhost_virtqueue *vq)
{
void __user *used;
- if (vhost_put_user(vq, cpu_to_vhost16(vq, vq->used_flags),
- &vq->used->flags) < 0)
+ if (vhost_put_used_flags(vq))
return -EFAULT;
if (unlikely(vq->log_used)) {
/* Make sure the flag is seen before log. */
@@ -1880,8 +2496,7 @@ static int vhost_update_used_flags(struct vhost_virtqueue *vq)
static int vhost_update_avail_event(struct vhost_virtqueue *vq, u16 avail_event)
{
- if (vhost_put_user(vq, cpu_to_vhost16(vq, vq->avail_idx),
- vhost_avail_event(vq)))
+ if (vhost_put_avail_event(vq))
return -EFAULT;
if (unlikely(vq->log_used)) {
void __user *used;
@@ -1917,7 +2532,7 @@ int vhost_vq_init_access(struct vhost_virtqueue *vq)
r = -EFAULT;
goto err;
}
- r = vhost_get_used(vq, last_used_idx, &vq->used->idx);
+ r = vhost_get_used_idx(vq, &last_used_idx);
if (r) {
vq_err(vq, "Can't access used idx at %p\n",
&vq->used->idx);
@@ -2116,7 +2731,7 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq,
last_avail_idx = vq->last_avail_idx;
if (vq->avail_idx == vq->last_avail_idx) {
- if (unlikely(vhost_get_avail(vq, avail_idx, &vq->avail->idx))) {
+ if (unlikely(vhost_get_avail_idx(vq, &avail_idx))) {
vq_err(vq, "Failed to access avail idx at %p\n",
&vq->avail->idx);
return -EFAULT;
@@ -2143,8 +2758,7 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq,
/* Grab the next descriptor number they're advertising, and increment
* the index we've seen. */
- if (unlikely(vhost_get_avail(vq, ring_head,
- &vq->avail->ring[last_avail_idx & (vq->num - 1)]))) {
+ if (unlikely(vhost_get_avail_head(vq, &ring_head, last_avail_idx))) {
vq_err(vq, "Failed to read head: idx %d address %p\n",
last_avail_idx,
&vq->avail->ring[last_avail_idx % vq->num]);
@@ -2179,8 +2793,7 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq,
i, vq->num, head);
return -EINVAL;
}
- ret = vhost_copy_from_user(vq, &desc, vq->desc + i,
- sizeof desc);
+ ret = vhost_get_desc(vq, &desc, i);
if (unlikely(ret)) {
vq_err(vq, "Failed to get descriptor: idx %d addr %p\n",
i, vq->desc + i);
@@ -2273,16 +2886,7 @@ static int __vhost_add_used_n(struct vhost_virtqueue *vq,
start = vq->last_used_idx & (vq->num - 1);
used = vq->used->ring + start;
- if (count == 1) {
- if (vhost_put_user(vq, heads[0].id, &used->id)) {
- vq_err(vq, "Failed to write used id");
- return -EFAULT;
- }
- if (vhost_put_user(vq, heads[0].len, &used->len)) {
- vq_err(vq, "Failed to write used len");
- return -EFAULT;
- }
- } else if (vhost_copy_to_user(vq, used, heads, count * sizeof *used)) {
+ if (vhost_put_used(vq, heads, start, count)) {
vq_err(vq, "Failed to write used");
return -EFAULT;
}
@@ -2324,8 +2928,7 @@ int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,
/* Make sure buffer is written before we update index. */
smp_wmb();
- if (vhost_put_user(vq, cpu_to_vhost16(vq, vq->last_used_idx),
- &vq->used->idx)) {
+ if (vhost_put_used_idx(vq)) {
vq_err(vq, "Failed to increment used idx");
return -EFAULT;
}
@@ -2358,7 +2961,7 @@ static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
if (!vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX)) {
__virtio16 flags;
- if (vhost_get_avail(vq, flags, &vq->avail->flags)) {
+ if (vhost_get_avail_flags(vq, &flags)) {
vq_err(vq, "Failed to get flags");
return true;
}
@@ -2372,7 +2975,7 @@ static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
if (unlikely(!v))
return true;
- if (vhost_get_avail(vq, event, vhost_used_event(vq))) {
+ if (vhost_get_used_event(vq, &event)) {
vq_err(vq, "Failed to get used event idx");
return true;
}
@@ -2417,7 +3020,7 @@ bool vhost_vq_avail_empty(struct vhost_dev *dev, struct vhost_virtqueue *vq)
if (vq->avail_idx != vq->last_avail_idx)
return false;
- r = vhost_get_avail(vq, avail_idx, &vq->avail->idx);
+ r = vhost_get_avail_idx(vq, &avail_idx);
if (unlikely(r))
return false;
vq->avail_idx = vhost16_to_cpu(vq, avail_idx);
@@ -2453,7 +3056,7 @@ bool vhost_enable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
/* They could have slipped one in as we were doing that: make
* sure it's written, then check again. */
smp_mb();
- r = vhost_get_avail(vq, avail_idx, &vq->avail->idx);
+ r = vhost_get_avail_idx(vq, &avail_idx);
if (r) {
vq_err(vq, "Failed to check avail idx at %p: %d\n",
&vq->avail->idx, r);
diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
index 27a78a9b8cc7..819296332913 100644
--- a/drivers/vhost/vhost.h
+++ b/drivers/vhost/vhost.h
@@ -12,6 +12,9 @@
#include <linux/virtio_config.h>
#include <linux/virtio_ring.h>
#include <linux/atomic.h>
+#include <linux/pagemap.h>
+#include <linux/mmu_notifier.h>
+#include <asm/cacheflush.h>
struct vhost_work;
typedef void (*vhost_work_fn_t)(struct vhost_work *work);
@@ -80,6 +83,24 @@ enum vhost_uaddr_type {
VHOST_NUM_ADDRS = 3,
};
+struct vhost_map {
+ int npages;
+ void *addr;
+ struct page **pages;
+};
+
+struct vhost_uaddr {
+ unsigned long uaddr;
+ size_t size;
+ bool write;
+};
+
+#if defined(CONFIG_MMU_NOTIFIER) && ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE == 0
+#define VHOST_ARCH_CAN_ACCEL_UACCESS 1
+#else
+#define VHOST_ARCH_CAN_ACCEL_UACCESS 0
+#endif
+
/* The virtqueue structure describes a queue attached to a device. */
struct vhost_virtqueue {
struct vhost_dev *dev;
@@ -90,7 +111,22 @@ struct vhost_virtqueue {
struct vring_desc __user *desc;
struct vring_avail __user *avail;
struct vring_used __user *used;
+
+#if VHOST_ARCH_CAN_ACCEL_UACCESS
+ /* Read by memory accessors, modified by meta data
+ * prefetching, MMU notifier and vring ioctl().
+ * Synchonrized through mmu_lock (writers) and RCU (writers
+ * and readers).
+ */
+ struct vhost_map __rcu *maps[VHOST_NUM_ADDRS];
+ /* Read by MMU notifier, modified by vring ioctl(),
+ * synchronized through MMU notifier
+ * registering/unregistering.
+ */
+ struct vhost_uaddr uaddrs[VHOST_NUM_ADDRS];
+#endif
const struct vhost_umem_node *meta_iotlb[VHOST_NUM_ADDRS];
+
struct file *kick;
struct eventfd_ctx *call_ctx;
struct eventfd_ctx *error_ctx;
@@ -145,6 +181,8 @@ struct vhost_virtqueue {
bool user_be;
#endif
u32 busyloop_timeout;
+ spinlock_t mmu_lock;
+ int invalidate_count;
};
struct vhost_msg_node {
@@ -158,6 +196,9 @@ struct vhost_msg_node {
struct vhost_dev {
struct mm_struct *mm;
+#ifdef CONFIG_MMU_NOTIFIER
+ struct mmu_notifier mmu_notifier;
+#endif
struct mutex mutex;
struct vhost_virtqueue **vqs;
int nvqs;
@@ -212,7 +253,7 @@ bool vhost_enable_notify(struct vhost_dev *, struct vhost_virtqueue *);
int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log,
unsigned int log_num, u64 len,
struct iovec *iov, int count);
-int vq_iotlb_prefetch(struct vhost_virtqueue *vq);
+int vq_meta_prefetch(struct vhost_virtqueue *vq);
struct vhost_msg_node *vhost_new_msg(struct vhost_virtqueue *vq, int type);
void vhost_enqueue_msg(struct vhost_dev *dev,
diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c
index 814bed72d793..6a50e1d0529c 100644
--- a/drivers/vhost/vsock.c
+++ b/drivers/vhost/vsock.c
@@ -1,11 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* vhost transport for vsock
*
* Copyright (C) 2013-2015 Red Hat, Inc.
* Author: Asias He <asias@redhat.com>
* Stefan Hajnoczi <stefanha@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.
*/
#include <linux/miscdevice.h>
#include <linux/atomic.h>
diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c
index 51e0c4be08df..20d96a5ac384 100644
--- a/drivers/video/backlight/88pm860x_bl.c
+++ b/drivers/video/backlight/88pm860x_bl.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Backlight driver for Marvell Semiconductor 88PM8606
*
* Copyright (C) 2009 Marvell International Ltd.
* Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- * 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.
*/
#include <linux/init.h>
diff --git a/drivers/video/backlight/apple_bl.c b/drivers/video/backlight/apple_bl.c
index 6a34ab936726..c0d9339cff87 100644
--- a/drivers/video/backlight/apple_bl.c
+++ b/drivers/video/backlight/apple_bl.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Backlight Driver for Intel-based Apples
*
@@ -7,10 +8,6 @@
* Copyright (C) 2006 Felipe Alfaro Solana <felipe_alfaro @linuxmail.org>
* Copyright (C) 2007 Julien BLACHE <jb@jblache.org>
*
- * 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.
- *
* This driver triggers SMIs which cause the firmware to change the
* backlight brightness. This is icky in many ways, but it's impractical to
* get at the firmware code in order to figure out what it's actually doing.
diff --git a/drivers/video/backlight/arcxcnn_bl.c b/drivers/video/backlight/arcxcnn_bl.c
index dec790de72ff..7b1c0a0e6cad 100644
--- a/drivers/video/backlight/arcxcnn_bl.c
+++ b/drivers/video/backlight/arcxcnn_bl.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Backlight driver for ArcticSand ARC_X_C_0N_0N Devices
*
* Copyright 2016 ArcticSand, Inc.
* Author : Brian Dodge <bdodge@arcticsand.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/backlight.h>
diff --git a/drivers/video/backlight/bd6107.c b/drivers/video/backlight/bd6107.c
index fdb2f7e2c6b5..d344fb03cb86 100644
--- a/drivers/video/backlight/bd6107.c
+++ b/drivers/video/backlight/bd6107.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ROHM Semiconductor BD6107 LED Driver
*
* Copyright (C) 2013 Ideas on board SPRL
*
* Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *
- * 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.
*/
#include <linux/backlight.h>
diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c
index f5574060f9c8..68f7592c5060 100644
--- a/drivers/video/backlight/corgi_lcd.c
+++ b/drivers/video/backlight/corgi_lcd.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LCD/Backlight Driver for Sharp Zaurus Handhelds (various models)
*
@@ -8,11 +9,6 @@
* Copyright (c) 2008 Marvell International Ltd.
* Converted to SPI device based LCD/Backlight device driver
* by Eric Miao <eric.miao@marvell.com>
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/video/backlight/da903x_bl.c b/drivers/video/backlight/da903x_bl.c
index f793738f06fb..62540e4bdedb 100644
--- a/drivers/video/backlight/da903x_bl.c
+++ b/drivers/video/backlight/da903x_bl.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Backlight driver for Dialog Semiconductor DA9030/DA9034
*
@@ -6,10 +7,6 @@
*
* Copyright (C) 2006-2008 Marvell International Ltd.
* Eric Miao <eric.miao@marvell.com>
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/video/backlight/ep93xx_bl.c b/drivers/video/backlight/ep93xx_bl.c
index 0067931821c6..4149e0b2f83c 100644
--- a/drivers/video/backlight/ep93xx_bl.c
+++ b/drivers/video/backlight/ep93xx_bl.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for the Cirrus EP93xx lcd backlight
*
* Copyright (c) 2010 H Hartley Sweeten <hsweeten@visionengravers.com>
*
- * 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.
- *
* This driver controls the pulse width modulated brightness control output,
* BRIGHT, on the Cirrus EP9307, EP9312, and EP9315 processors.
*/
diff --git a/drivers/video/backlight/generic_bl.c b/drivers/video/backlight/generic_bl.c
index 4dea91acea13..8fe63dbc8590 100644
--- a/drivers/video/backlight/generic_bl.c
+++ b/drivers/video/backlight/generic_bl.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic Backlight Driver
*
* Copyright (c) 2004-2008 Richard Purdie
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/video/backlight/gpio_backlight.c b/drivers/video/backlight/gpio_backlight.c
index e470da95d806..e84f3087e29f 100644
--- a/drivers/video/backlight/gpio_backlight.c
+++ b/drivers/video/backlight/gpio_backlight.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* gpio_backlight.c - Simple GPIO-controlled backlight
- *
- * 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.
*/
#include <linux/backlight.h>
@@ -18,6 +15,7 @@
#include <linux/of_gpio.h>
#include <linux/platform_data/gpio_backlight.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/slab.h>
struct gpio_backlight {
@@ -61,11 +59,10 @@ static int gpio_backlight_probe_dt(struct platform_device *pdev,
struct gpio_backlight *gbl)
{
struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
enum gpiod_flags flags;
int ret;
- gbl->def_value = of_property_read_bool(np, "default-on");
+ gbl->def_value = device_property_read_bool(dev, "default-on");
flags = gbl->def_value ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
gbl->gpiod = devm_gpiod_get(dev, NULL, flags);
@@ -89,26 +86,19 @@ static int gpio_backlight_probe(struct platform_device *pdev)
struct backlight_properties props;
struct backlight_device *bl;
struct gpio_backlight *gbl;
- struct device_node *np = pdev->dev.of_node;
int ret;
- if (!pdata && !np) {
- dev_err(&pdev->dev,
- "failed to find platform data or device tree node.\n");
- return -ENODEV;
- }
-
gbl = devm_kzalloc(&pdev->dev, sizeof(*gbl), GFP_KERNEL);
if (gbl == NULL)
return -ENOMEM;
gbl->dev = &pdev->dev;
- if (np) {
+ if (pdev->dev.fwnode) {
ret = gpio_backlight_probe_dt(pdev, gbl);
if (ret)
return ret;
- } else {
+ } else if (pdata) {
/*
* Legacy platform data GPIO retrieveal. Do not expand
* the use of this code path, currently only used by one
@@ -129,6 +119,10 @@ static int gpio_backlight_probe(struct platform_device *pdev)
gbl->gpiod = gpio_to_desc(pdata->gpio);
if (!gbl->gpiod)
return -EINVAL;
+ } else {
+ dev_err(&pdev->dev,
+ "failed to find platform data or device tree node.\n");
+ return -ENODEV;
}
memset(&props, 0, sizeof(props));
@@ -149,19 +143,17 @@ static int gpio_backlight_probe(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_OF
static struct of_device_id gpio_backlight_of_match[] = {
{ .compatible = "gpio-backlight" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, gpio_backlight_of_match);
-#endif
static struct platform_driver gpio_backlight_driver = {
.driver = {
.name = "gpio-backlight",
- .of_match_table = of_match_ptr(gpio_backlight_of_match),
+ .of_match_table = gpio_backlight_of_match,
},
.probe = gpio_backlight_probe,
};
diff --git a/drivers/video/backlight/ili9320.c b/drivers/video/backlight/ili9320.c
index 2cf39e6d519d..168ac79523d7 100644
--- a/drivers/video/backlight/ili9320.c
+++ b/drivers/video/backlight/ili9320.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* drivers/video/backlight/ili9320.c
*
* ILI9320 LCD controller driver core.
@@ -5,10 +6,6 @@
* Copyright 2007 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/video/backlight/ili9320.h b/drivers/video/backlight/ili9320.h
index 42329e7aa9a8..fc59e389d59a 100644
--- a/drivers/video/backlight/ili9320.h
+++ b/drivers/video/backlight/ili9320.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/* drivers/video/backlight/ili9320.h
*
* ILI9320 LCD controller driver core.
@@ -6,10 +7,6 @@
* Ben Dooks <ben@simtec.co.uk>
*
* http://armlinux.simtec.co.uk/
- *
- * 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.
*/
/* Holder for register and value pairs. */
diff --git a/drivers/video/backlight/ipaq_micro_bl.c b/drivers/video/backlight/ipaq_micro_bl.c
index 347dc11d4ceb..1123f67c12b3 100644
--- a/drivers/video/backlight/ipaq_micro_bl.c
+++ b/drivers/video/backlight/ipaq_micro_bl.c
@@ -1,7 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
- * 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.
*
* iPAQ microcontroller backlight support
* Author : Linus Walleij <linus.walleij@linaro.org>
diff --git a/drivers/video/backlight/kb3886_bl.c b/drivers/video/backlight/kb3886_bl.c
index 96312c3afc07..1dfe13c18925 100644
--- a/drivers/video/backlight/kb3886_bl.c
+++ b/drivers/video/backlight/kb3886_bl.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Backlight Driver for the KB3886 Backlight
*
* Copyright (c) 2007-2008 Claudio Nieder
*
* Based on corgi_bl.c by Richard Purdie and kb3886 driver by Robert Woerle
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c
index e6054e2492c5..8554b4aa980c 100644
--- a/drivers/video/backlight/l4f00242t03.c
+++ b/drivers/video/backlight/l4f00242t03.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* l4f00242t03.c -- support for Epson L4F00242T03 LCD
*
@@ -5,10 +6,6 @@
*
* Copyright (c) 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com>
* Inspired by Marek Vasut work in l4f00242t03.c
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/video/backlight/lm3630a_bl.c b/drivers/video/backlight/lm3630a_bl.c
index 75d996490cf0..b04b35d007a2 100644
--- a/drivers/video/backlight/lm3630a_bl.c
+++ b/drivers/video/backlight/lm3630a_bl.c
@@ -1,11 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Simple driver for Texas Instruments LM3630A Backlight driver chip
* Copyright (C) 2012 Texas Instruments
-*
-* 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.
-*
*/
#include <linux/module.h>
#include <linux/slab.h>
diff --git a/drivers/video/backlight/lm3639_bl.c b/drivers/video/backlight/lm3639_bl.c
index 086611c7bc03..48c04155a5f9 100644
--- a/drivers/video/backlight/lm3639_bl.c
+++ b/drivers/video/backlight/lm3639_bl.c
@@ -1,11 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Simple driver for Texas Instruments LM3639 Backlight + Flash LED driver chip
* Copyright (C) 2012 Texas Instruments
-*
-* 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.
-*
*/
#include <linux/module.h>
#include <linux/slab.h>
diff --git a/drivers/video/backlight/lms283gf05.c b/drivers/video/backlight/lms283gf05.c
index 4237aaa7f269..35bc012b22cc 100644
--- a/drivers/video/backlight/lms283gf05.c
+++ b/drivers/video/backlight/lms283gf05.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* lms283gf05.c -- support for Samsung LMS283GF05 LCD
*
* Copyright (c) 2009 Marek Vasut <marek.vasut@gmail.com>
- *
- * 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.
*/
#include <linux/device.h>
diff --git a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c
index 73612485ed07..f68920131a4a 100644
--- a/drivers/video/backlight/lp855x_bl.c
+++ b/drivers/video/backlight/lp855x_bl.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TI LP855x Backlight Driver
*
* Copyright (C) 2011 Texas Instruments
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/video/backlight/lp8788_bl.c b/drivers/video/backlight/lp8788_bl.c
index cf869ec90cce..ba42f3fe0c73 100644
--- a/drivers/video/backlight/lp8788_bl.c
+++ b/drivers/video/backlight/lp8788_bl.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TI LP8788 MFD - backlight driver
*
* Copyright 2012 Texas Instruments
*
* Author: Milo(Woogyom) Kim <milo.kim@ti.com>
- *
- * 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.
- *
*/
#include <linux/backlight.h>
diff --git a/drivers/video/backlight/ltv350qv.c b/drivers/video/backlight/ltv350qv.c
index 885612cc1008..5cbf621e48bd 100644
--- a/drivers/video/backlight/ltv350qv.c
+++ b/drivers/video/backlight/ltv350qv.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Power control for Samsung LTV350QV Quarter VGA LCD Panel
*
* Copyright (C) 2006, 2007 Atmel Corporation
- *
- * 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.
*/
#include <linux/delay.h>
#include <linux/err.h>
diff --git a/drivers/video/backlight/ltv350qv.h b/drivers/video/backlight/ltv350qv.h
index 189112e3fc7a..c70890776a94 100644
--- a/drivers/video/backlight/ltv350qv.h
+++ b/drivers/video/backlight/ltv350qv.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Register definitions for Samsung LTV350QV Quarter VGA LCD Panel
*
* Copyright (C) 2006, 2007 Atmel Corporation
- *
- * 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.
*/
#ifndef __LTV350QV_H
#define __LTV350QV_H
diff --git a/drivers/video/backlight/lv5207lp.c b/drivers/video/backlight/lv5207lp.c
index 8ab7297b118a..c6ad73a784e2 100644
--- a/drivers/video/backlight/lv5207lp.c
+++ b/drivers/video/backlight/lv5207lp.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Sanyo LV5207LP LED Driver
*
* Copyright (C) 2013 Ideas on board SPRL
*
* Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *
- * 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.
*/
#include <linux/backlight.h>
diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c
index f3aa6088f1d9..97cc260ff9d1 100644
--- a/drivers/video/backlight/max8925_bl.c
+++ b/drivers/video/backlight/max8925_bl.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Backlight driver for Maxim MAX8925
*
* Copyright (C) 2009 Marvell International Ltd.
* Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- * 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.
*/
#include <linux/init.h>
diff --git a/drivers/video/backlight/ot200_bl.c b/drivers/video/backlight/ot200_bl.c
index 3acdb9f646ed..23ee7106c72a 100644
--- a/drivers/video/backlight/ot200_bl.c
+++ b/drivers/video/backlight/ot200_bl.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Bachmann electronic GmbH
* Christian Gmeiner <christian.gmeiner@gmail.com>
*
* Backlight driver for ot200 visualisation device from
* Bachmann electronic GmbH.
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/video/backlight/pandora_bl.c b/drivers/video/backlight/pandora_bl.c
index 9618766e3866..f946470ce9f6 100644
--- a/drivers/video/backlight/pandora_bl.c
+++ b/drivers/video/backlight/pandora_bl.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Backlight driver for Pandora handheld.
* Pandora uses TWL4030 PWM0 -> TPS61161 combo for control backlight.
* Based on pwm_bl.c
*
* Copyright 2009,2012 Gražvydas Ignotas <notasas@gmail.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/video/backlight/platform_lcd.c b/drivers/video/backlight/platform_lcd.c
index 872a3bf21faf..b2bfbf070200 100644
--- a/drivers/video/backlight/platform_lcd.c
+++ b/drivers/video/backlight/platform_lcd.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* drivers/video/backlight/platform_lcd.c
*
* Copyright 2008 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* Generic platform-device LCD power control interface.
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index fb45f866b923..2201b8c78641 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -1,13 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
- * linux/drivers/video/backlight/pwm_bl.c
- *
- * simple PWM based backlight control, board code has to setup
+ * Simple PWM based backlight control, board code has to setup
* 1) pin configuration so PWM waveforms can output
* 2) platform_data being correctly configured
- *
- * 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.
*/
#include <linux/delay.h>
@@ -194,29 +189,17 @@ int pwm_backlight_brightness_default(struct device *dev,
struct platform_pwm_backlight_data *data,
unsigned int period)
{
- unsigned int counter = 0;
- unsigned int i, n;
+ unsigned int i;
u64 retval;
/*
- * Count the number of bits needed to represent the period number. The
- * number of bits is used to calculate the number of levels used for the
- * brightness-levels table, the purpose of this calculation is have a
- * pre-computed table with enough levels to get linear brightness
- * perception. The period is divided by the number of bits so for a
- * 8-bit PWM we have 255 / 8 = 32 brightness levels or for a 16-bit PWM
- * we have 65535 / 16 = 4096 brightness levels.
- *
- * Note that this method is based on empirical testing on different
- * devices with PWM of 8 and 16 bits of resolution.
+ * Once we have 4096 levels there's little point going much higher...
+ * neither interactive sliders nor animation benefits from having
+ * more values in the table.
*/
- n = period;
- while (n) {
- counter += n % 2;
- n >>= 1;
- }
+ data->max_brightness =
+ min((int)DIV_ROUND_UP(period, fls(period)), 4096);
- data->max_brightness = DIV_ROUND_UP(period, counter);
data->levels = devm_kcalloc(dev, data->max_brightness,
sizeof(*data->levels), GFP_KERNEL);
if (!data->levels)
@@ -708,5 +691,5 @@ static struct platform_driver pwm_backlight_driver = {
module_platform_driver(pwm_backlight_driver);
MODULE_DESCRIPTION("PWM based Backlight Driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:pwm-backlight");
diff --git a/drivers/video/backlight/sky81452-backlight.c b/drivers/video/backlight/sky81452-backlight.c
index d414c7a3acf5..2355f00f5773 100644
--- a/drivers/video/backlight/sky81452-backlight.c
+++ b/drivers/video/backlight/sky81452-backlight.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* sky81452-backlight.c SKY81452 backlight driver
*
* Copyright 2014 Skyworks Solutions Inc.
* Author : Gyungoh Yoo <jack.yoo@skyworksinc.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/backlight.h>
diff --git a/drivers/video/backlight/tosa_bl.c b/drivers/video/backlight/tosa_bl.c
index 97067597e6bf..1275e815bd86 100644
--- a/drivers/video/backlight/tosa_bl.c
+++ b/drivers/video/backlight/tosa_bl.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LCD / Backlight control code for Sharp SL-6000x (tosa)
*
* Copyright (c) 2005 Dirk Opfer
* Copyright (c) 2007,2008 Dmitry Baryshkov
- *
- * 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.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/video/backlight/tosa_lcd.c b/drivers/video/backlight/tosa_lcd.c
index 4dc5ee8debeb..65cb7578776f 100644
--- a/drivers/video/backlight/tosa_lcd.c
+++ b/drivers/video/backlight/tosa_lcd.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LCD / Backlight control code for Sharp SL-6000x (tosa)
*
* Copyright (c) 2005 Dirk Opfer
* Copyright (c) 2007,2008 Dmitry Baryshkov
- *
- * 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.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/video/backlight/vgg2432a4.c b/drivers/video/backlight/vgg2432a4.c
index 242a9948f57f..9bf277ca4ae9 100644
--- a/drivers/video/backlight/vgg2432a4.c
+++ b/drivers/video/backlight/vgg2432a4.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* drivers/video/backlight/vgg2432a4.c
*
* VGG2432A4 (ILI9320) LCD controller driver.
@@ -5,10 +6,6 @@
* Copyright 2007 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/video/backlight/wm831x_bl.c b/drivers/video/backlight/wm831x_bl.c
index 6eab0d6c262a..e55977d54c15 100644
--- a/drivers/video/backlight/wm831x_bl.c
+++ b/drivers/video/backlight/wm831x_bl.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Backlight driver for Wolfson Microelectronics WM831x PMICs
*
* Copyright 2009 Wolfson Microelectonics plc
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index 1b2f5f31fb6f..6b2de93bd302 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -31,7 +31,7 @@ menuconfig FB
in the /dev directory, i.e. /dev/fb*.
You need an utility program called fbset to make full use of frame
- buffer devices. Please read <file:Documentation/fb/framebuffer.txt>
+ buffer devices. Please read <file:Documentation/fb/framebuffer.rst>
and the Framebuffer-HOWTO at
<http://www.munted.org.uk/programming/Framebuffer-HOWTO-1.3.html> for more
information.
@@ -241,7 +241,7 @@ config FB_CIRRUS
If you have a PCI-based system, this enables support for these
chips: GD-543x, GD-544x, GD-5480.
- Please read the file <file:Documentation/fb/cirrusfb.txt>.
+ Please read the file <file:Documentation/fb/cirrusfb.rst>.
Say N unless you have such a graphics board or plan to get one
before you next recompile the kernel.
@@ -289,7 +289,7 @@ config FB_ARMCLCD
If you want to compile this as a module (=code which can be
inserted into and removed from the running kernel), say M
- here and read <file:Documentation/kbuild/modules.txt>. The module
+ here and read <file:Documentation/kbuild/modules.rst>. The module
will be called amba-clcd.
config FB_ACORN
@@ -332,7 +332,8 @@ config FB_SA1100
config FB_IMX
tristate "Freescale i.MX1/21/25/27 LCD support"
- depends on FB && ARCH_MXC
+ depends on FB && HAVE_CLK && HAS_IOMEM
+ depends on ARCH_MXC || COMPILE_TEST
select LCD_CLASS_DEVICE
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
@@ -614,7 +615,7 @@ config FB_UVESA
This driver generally provides more features than vesafb but
requires a userspace helper application called 'v86d'. See
- <file:Documentation/fb/uvesafb.txt> for more information.
+ <file:Documentation/fb/uvesafb.rst> for more information.
If unsure, say N.
@@ -629,7 +630,7 @@ config FB_VESA
This is the frame buffer device driver for generic VESA 2.0
compliant graphic cards. The older VESA 1.2 cards are not supported.
You will get a boot time penguin logo at no additional cost. Please
- read <file:Documentation/fb/vesafb.txt>. If unsure, say Y.
+ read <file:Documentation/fb/vesafb.rst>. If unsure, say Y.
config FB_EFI
bool "EFI-based Framebuffer Support"
@@ -670,7 +671,8 @@ config FB_HGA
config FB_GBE
bool "SGI Graphics Backend frame buffer support"
- depends on (FB = y) && SGI_IP32
+ depends on (FB = y) && HAS_IOMEM
+ depends on SGI_IP32 || COMPILE_TEST
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -808,7 +810,8 @@ config FB_XVR1000
config FB_PVR2
tristate "NEC PowerVR 2 display support"
- depends on FB && SH_DREAMCAST
+ depends on FB && HAS_IOMEM
+ depends on SH_DREAMCAST || COMPILE_TEST
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -825,7 +828,7 @@ config FB_PVR2
module load time. The parameters look like "video=pvr2:XXX", where
the meaning of XXX can be found at the end of the main source file
(<file:drivers/video/pvr2fb.c>). Please see the file
- <file:Documentation/fb/pvr2fb.txt>.
+ <file:Documentation/fb/pvr2fb.rst>.
config FB_OPENCORES
tristate "OpenCores VGA/LCD core 2.0 framebuffer support"
@@ -856,7 +859,8 @@ config FB_S1D13XXX
config FB_ATMEL
tristate "AT91 LCD Controller support"
- depends on FB && OF && HAVE_FB_ATMEL
+ depends on FB && OF && HAVE_CLK && HAS_IOMEM
+ depends on HAVE_FB_ATMEL || COMPILE_TEST
select FB_BACKLIGHT
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
@@ -987,7 +991,7 @@ config FB_I810
module will be called i810fb.
For more information, please read
- <file:Documentation/fb/intel810.txt>
+ <file:Documentation/fb/intel810.rst>
config FB_I810_GTF
bool "use VESA Generalized Timing Formula"
@@ -1057,7 +1061,7 @@ config FB_INTEL
To compile this driver as a module, choose M here: the
module will be called intelfb.
- For more information, please read <file:Documentation/fb/intelfb.txt>
+ For more information, please read <file:Documentation/fb/intelfb.rst>
config FB_INTEL_DEBUG
bool "Intel driver Debug Messages"
@@ -1094,7 +1098,7 @@ config FB_MATROX
You can pass several parameters to the driver at boot time or at
module load time. The parameters look like "video=matroxfb:XXX", and
- are described in <file:Documentation/fb/matroxfb.txt>.
+ are described in <file:Documentation/fb/matroxfb.rst>.
config FB_MATROX_MILLENIUM
bool "Millennium I/II support"
@@ -1245,7 +1249,7 @@ config FB_ATY128
help
This driver supports graphics boards with the ATI Rage128 chips.
Say Y if you have such a graphics board and read
- <file:Documentation/fb/aty128fb.txt>.
+ <file:Documentation/fb/aty128fb.rst>.
To compile this driver as a module, choose M here: the
module will be called aty128fb.
@@ -1507,7 +1511,7 @@ config FB_VOODOO1
WARNING: Do not use any application that uses the 3D engine
(namely glide) while using this driver.
- Please read the <file:Documentation/fb/sstfb.txt> for supported
+ Please read the <file:Documentation/fb/sstfb.rst> for supported
options and other important info support.
config FB_VT8623
@@ -1539,7 +1543,7 @@ config FB_TRIDENT
There are also integrated versions of these chips called CyberXXXX,
CyberImage or CyberBlade. These chips are mostly found in laptops
but also on some motherboards including early VIA EPIA motherboards.
- For more information, read <file:Documentation/fb/tridentfb.txt>
+ For more information, read <file:Documentation/fb/tridentfb.rst>
Say Y if you have such a graphics board.
@@ -1729,7 +1733,8 @@ config FB_68328
config FB_PXA168
tristate "PXA168/910 LCD framebuffer support"
- depends on FB && (CPU_PXA168 || CPU_PXA910)
+ depends on FB && HAVE_CLK && HAS_IOMEM
+ depends on CPU_PXA168 || CPU_PXA910 || COMPILE_TEST
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -1752,7 +1757,7 @@ config FB_PXA
This driver is also available as a module ( = code which can be
inserted and removed from the running kernel whenever you want). The
module will be called pxafb. If you want to compile it as a module,
- say M here and read <file:Documentation/kbuild/modules.txt>.
+ say M here and read <file:Documentation/kbuild/modules.rst>.
If unsure, say N.
@@ -1778,7 +1783,7 @@ config FB_PXA_PARAMETERS
single model of flatpanel then you can safely leave this
option disabled.
- <file:Documentation/fb/pxafb.txt> describes the available parameters.
+ <file:Documentation/fb/pxafb.rst> describes the available parameters.
config PXA3XX_GCU
tristate "PXA3xx 2D graphics accelerator driver"
@@ -1833,7 +1838,7 @@ config FB_W100
This driver is also available as a module ( = code which can be
inserted and removed from the running kernel whenever you want). The
module will be called w100fb. If you want to compile it as a module,
- say M here and read <file:Documentation/kbuild/modules.txt>.
+ say M here and read <file:Documentation/kbuild/modules.rst>.
If unsure, say N.
@@ -1862,7 +1867,7 @@ config FB_TMIO
This driver is also available as a module ( = code which can be
inserted and removed from the running kernel whenever you want). The
module will be called tmiofb. If you want to compile it as a module,
- say M here and read <file:Documentation/kbuild/modules.txt>.
+ say M here and read <file:Documentation/kbuild/modules.rst>.
If unsure, say N.
@@ -1873,7 +1878,8 @@ config FB_TMIO_ACCELL
config FB_S3C
tristate "Samsung S3C framebuffer support"
- depends on FB && (CPU_S3C2416 || ARCH_S3C64XX)
+ depends on FB && HAVE_CLK && HAS_IOMEM
+ depends on (CPU_S3C2416 || ARCH_S3C64XX) || COMPILE_TEST
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -1908,7 +1914,7 @@ config FB_S3C2410
This driver is also available as a module ( = code which can be
inserted and removed from the running kernel whenever you want). The
module will be called s3c2410fb. If you want to compile it as a module,
- say M here and read <file:Documentation/kbuild/modules.txt>.
+ say M here and read <file:Documentation/kbuild/modules.rst>.
If unsure, say N.
config FB_S3C2410_DEBUG
@@ -1945,7 +1951,7 @@ config FB_SM501
This driver is also available as a module ( = code which can be
inserted and removed from the running kernel whenever you want). The
module will be called sm501fb. If you want to compile it as a module,
- say M here and read <file:Documentation/kbuild/modules.txt>.
+ say M here and read <file:Documentation/kbuild/modules.rst>.
If unsure, say N.
@@ -2055,7 +2061,8 @@ config FB_SH7760
config FB_DA8XX
tristate "DA8xx/OMAP-L1xx/AM335x Framebuffer support"
- depends on FB && (ARCH_DAVINCI_DA8XX || SOC_AM33XX)
+ depends on FB && HAVE_CLK && HAS_IOMEM
+ depends on ARCH_DAVINCI_DA8XX || SOC_AM33XX || COMPILE_TEST
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -2172,7 +2179,7 @@ config FB_EP93XX
config FB_PRE_INIT_FB
bool "Don't reinitialize, use bootloader's GDC/Display configuration"
- depends on FB && (FB_MB862XX_LIME || FB_MXS)
+ depends on FB && FB_MB862XX_LIME
---help---
Select this option if display contents should be inherited as set by
the bootloader.
@@ -2213,17 +2220,6 @@ config FB_JZ4740
help
Framebuffer support for the JZ4740 SoC.
-config FB_MXS
- tristate "MXS LCD framebuffer support"
- depends on FB && (ARCH_MXS || ARCH_MXC)
- select FB_CFB_FILLRECT
- select FB_CFB_COPYAREA
- select FB_CFB_IMAGEBLIT
- select FB_MODE_HELPERS
- select VIDEOMODE_HELPERS
- help
- Framebuffer support for the MXS SoC.
-
config FB_PUV3_UNIGFX
tristate "PKUnity v3 Unigfx framebuffer support"
depends on FB && UNICORE32 && ARCH_PUV3
@@ -2288,7 +2284,7 @@ config FB_SM712
This driver is also available as a module. The module will be
called sm712fb. If you want to compile it as a module, say M
- here and read <file:Documentation/kbuild/modules.txt>.
+ here and read <file:Documentation/kbuild/modules.rst>.
source "drivers/video/fbdev/omap/Kconfig"
source "drivers/video/fbdev/omap2/Kconfig"
diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile
index 655f2537cac1..7dc4861a93e6 100644
--- a/drivers/video/fbdev/Makefile
+++ b/drivers/video/fbdev/Makefile
@@ -131,7 +131,6 @@ obj-$(CONFIG_FB_VGA16) += vga16fb.o
obj-$(CONFIG_FB_OF) += offb.o
obj-$(CONFIG_FB_MX3) += mx3fb.o
obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o
-obj-$(CONFIG_FB_MXS) += mxsfb.o
obj-$(CONFIG_FB_SSD1307) += ssd1307fb.o
obj-$(CONFIG_FB_SIMPLE) += simplefb.o
diff --git a/drivers/video/fbdev/acornfb.c b/drivers/video/fbdev/acornfb.c
index 0c325b4da61d..92f23e3bc27a 100644
--- a/drivers/video/fbdev/acornfb.c
+++ b/drivers/video/fbdev/acornfb.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/video/acornfb.c
*
* Copyright (C) 1998-2001 Russell King
*
- * 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.
- *
* Frame buffer code for Acorn platforms
*
* NOTE: Most of the modes with X!=640 will disappear shortly.
diff --git a/drivers/video/fbdev/acornfb.h b/drivers/video/fbdev/acornfb.h
index 175c8ff3367c..f8df4ecb4fd7 100644
--- a/drivers/video/fbdev/acornfb.h
+++ b/drivers/video/fbdev/acornfb.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/drivers/video/acornfb.h
*
* Copyright (C) 1998,1999 Russell King
*
- * 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.
- *
* Frame buffer code for Acorn platforms
*/
#if defined(HAS_VIDC20)
diff --git a/drivers/video/fbdev/amifb.c b/drivers/video/fbdev/amifb.c
index 758457026694..91ddc9602014 100644
--- a/drivers/video/fbdev/amifb.c
+++ b/drivers/video/fbdev/amifb.c
@@ -3554,10 +3554,8 @@ static int __init amifb_probe(struct platform_device *pdev)
custom.dmacon = DMAF_ALL | DMAF_MASTER;
info = framebuffer_alloc(sizeof(struct amifb_par), &pdev->dev);
- if (!info) {
- dev_err(&pdev->dev, "framebuffer_alloc failed\n");
+ if (!info)
return -ENOMEM;
- }
strcpy(info->fix.id, "Amiga ");
info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
diff --git a/drivers/video/fbdev/arkfb.c b/drivers/video/fbdev/arkfb.c
index 13ba371e70aa..f940e8b66b85 100644
--- a/drivers/video/fbdev/arkfb.c
+++ b/drivers/video/fbdev/arkfb.c
@@ -954,10 +954,8 @@ static int ark_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
/* Allocate and fill driver data structure */
info = framebuffer_alloc(sizeof(struct arkfb_info), &(dev->dev));
- if (! info) {
- dev_err(&(dev->dev), "cannot allocate memory\n");
+ if (!info)
return -ENOMEM;
- }
par = info->par;
mutex_init(&par->open_lock);
diff --git a/drivers/video/fbdev/atafb.c b/drivers/video/fbdev/atafb.c
index b986af2a8042..fc9dfb0a95af 100644
--- a/drivers/video/fbdev/atafb.c
+++ b/drivers/video/fbdev/atafb.c
@@ -77,29 +77,8 @@
#define SWITCH_SND7 0x80
#define SWITCH_NONE 0x00
-
#define up(x, r) (((x) + (r) - 1) & ~((r)-1))
- /*
- * Interface to the world
- */
-
-static int atafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info);
-static int atafb_set_par(struct fb_info *info);
-static int atafb_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
- unsigned int blue, unsigned int transp,
- struct fb_info *info);
-static int atafb_blank(int blank, struct fb_info *info);
-static int atafb_pan_display(struct fb_var_screeninfo *var,
- struct fb_info *info);
-static void atafb_fillrect(struct fb_info *info,
- const struct fb_fillrect *rect);
-static void atafb_copyarea(struct fb_info *info,
- const struct fb_copyarea *region);
-static void atafb_imageblit(struct fb_info *info, const struct fb_image *image);
-static int atafb_ioctl(struct fb_info *info, unsigned int cmd,
- unsigned long arg);
-
static int default_par; /* default resolution (0=none) */
diff --git a/drivers/video/fbdev/atmel_lcdfb.c b/drivers/video/fbdev/atmel_lcdfb.c
index e67dfd94bf1d..5ff8e0320d95 100644
--- a/drivers/video/fbdev/atmel_lcdfb.c
+++ b/drivers/video/fbdev/atmel_lcdfb.c
@@ -673,7 +673,7 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0);
/* Disable all interrupts */
- lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
+ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0U);
/* Enable FIFO & DMA errors */
lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
@@ -950,7 +950,7 @@ static int atmel_lcdfb_of_init(struct atmel_lcdfb_info *sinfo)
struct fb_videomode fb_vm;
struct gpio_desc *gpiod;
struct videomode vm;
- int ret = -ENOENT;
+ int ret;
int i;
sinfo->config = (struct atmel_lcdfb_config*)
@@ -1053,10 +1053,8 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
ret = -ENOMEM;
info = framebuffer_alloc(sizeof(struct atmel_lcdfb_info), dev);
- if (!info) {
- dev_err(dev, "cannot allocate memory\n");
+ if (!info)
goto out;
- }
sinfo = info->par;
sinfo->pdev = pdev;
@@ -1291,7 +1289,7 @@ static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg)
* We don't want to handle interrupts while the clock is
* stopped. It may take forever.
*/
- lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
+ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0U);
sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_CTR);
lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0);
diff --git a/drivers/video/fbdev/aty/aty128fb.c b/drivers/video/fbdev/aty/aty128fb.c
index b02e67528a99..8504e19437ff 100644
--- a/drivers/video/fbdev/aty/aty128fb.c
+++ b/drivers/video/fbdev/aty/aty128fb.c
@@ -2103,10 +2103,9 @@ static int aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* We have the resources. Now virtualize them */
info = framebuffer_alloc(sizeof(struct aty128fb_par), &pdev->dev);
- if (info == NULL) {
- printk(KERN_ERR "aty128fb: can't alloc fb_info_aty128\n");
+ if (!info)
goto err_free_mmio;
- }
+
par = info->par;
info->pseudo_palette = par->pseudo_palette;
diff --git a/drivers/video/fbdev/aty/atyfb_base.c b/drivers/video/fbdev/aty/atyfb_base.c
index eebb62d82a23..72bcfbe42e49 100644
--- a/drivers/video/fbdev/aty/atyfb_base.c
+++ b/drivers/video/fbdev/aty/atyfb_base.c
@@ -3550,10 +3550,9 @@ static int atyfb_pci_probe(struct pci_dev *pdev,
/* Allocate framebuffer */
info = framebuffer_alloc(sizeof(struct atyfb_par), &pdev->dev);
- if (!info) {
- PRINTKE("atyfb_pci_probe() can't alloc fb_info\n");
+ if (!info)
return -ENOMEM;
- }
+
par = info->par;
par->bus_type = PCI;
info->fix = atyfb_fix;
@@ -3643,10 +3642,9 @@ static int __init atyfb_atari_probe(void)
}
info = framebuffer_alloc(sizeof(struct atyfb_par), NULL);
- if (!info) {
- PRINTKE("atyfb_atari_probe() can't alloc fb_info\n");
+ if (!info)
return -ENOMEM;
- }
+
par = info->par;
info->fix = atyfb_fix;
diff --git a/drivers/video/fbdev/aty/radeon_backlight.c b/drivers/video/fbdev/aty/radeon_backlight.c
index 301d6d6aeead..d2c1263ad260 100644
--- a/drivers/video/fbdev/aty/radeon_backlight.c
+++ b/drivers/video/fbdev/aty/radeon_backlight.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Backlight code for ATI Radeon based graphic cards
*
* Copyright (c) 2000 Ani Joshi <ajoshi@kernel.crashing.org>
* Copyright (c) 2003 Benjamin Herrenschmidt <benh@kernel.crashing.org>
* Copyright (c) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
- *
- * 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.
*/
#include "radeonfb.h"
diff --git a/drivers/video/fbdev/aty/radeon_base.c b/drivers/video/fbdev/aty/radeon_base.c
index e8594bbaea60..6f891d82eebe 100644
--- a/drivers/video/fbdev/aty/radeon_base.c
+++ b/drivers/video/fbdev/aty/radeon_base.c
@@ -2294,8 +2294,6 @@ static int radeonfb_pci_register(struct pci_dev *pdev,
info = framebuffer_alloc(sizeof(struct radeonfb_info), &pdev->dev);
if (!info) {
- printk (KERN_ERR "radeonfb (%s): could not allocate memory\n",
- pci_name(pdev));
ret = -ENOMEM;
goto err_disable;
}
diff --git a/drivers/video/fbdev/au1100fb.c b/drivers/video/fbdev/au1100fb.c
index 0adf0683cf08..99941ae1f3a1 100644
--- a/drivers/video/fbdev/au1100fb.c
+++ b/drivers/video/fbdev/au1100fb.c
@@ -340,14 +340,12 @@ int au1100fb_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi)
*/
int au1100fb_fb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
{
- struct au1100fb_device *fbdev;
-
- fbdev = to_au1100fb_device(fbi);
+ struct au1100fb_device *fbdev = to_au1100fb_device(fbi);
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
pgprot_val(vma->vm_page_prot) |= (6 << 9); //CCA=6
- return vm_iomap_memory(vma, fbdev->fb_phys, fbdev->fb_len);
+ return dma_mmap_coherent(fbdev->dev, vma, fbdev->fb_mem, fbdev->fb_phys,
+ fbdev->fb_len);
}
static struct fb_ops au1100fb_ops =
@@ -412,7 +410,6 @@ static int au1100fb_drv_probe(struct platform_device *dev)
{
struct au1100fb_device *fbdev;
struct resource *regs_res;
- unsigned long page;
struct clk *c;
/* Allocate new device private */
@@ -424,6 +421,7 @@ static int au1100fb_drv_probe(struct platform_device *dev)
goto failed;
platform_set_drvdata(dev, (void *)fbdev);
+ fbdev->dev = &dev->dev;
/* Allocate region for our registers and map them */
regs_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
@@ -472,20 +470,6 @@ static int au1100fb_drv_probe(struct platform_device *dev)
au1100fb_fix.smem_start = fbdev->fb_phys;
au1100fb_fix.smem_len = fbdev->fb_len;
- /*
- * Set page reserved so that mmap will work. This is necessary
- * since we'll be remapping normal memory.
- */
- for (page = (unsigned long)fbdev->fb_mem;
- page < PAGE_ALIGN((unsigned long)fbdev->fb_mem + fbdev->fb_len);
- page += PAGE_SIZE) {
-#ifdef CONFIG_DMA_NONCOHERENT
- SetPageReserved(virt_to_page(CAC_ADDR((void *)page)));
-#else
- SetPageReserved(virt_to_page(page));
-#endif
- }
-
print_dbg("Framebuffer memory map at %p", fbdev->fb_mem);
print_dbg("phys=0x%08x, size=%dK", fbdev->fb_phys, fbdev->fb_len / 1024);
diff --git a/drivers/video/fbdev/au1100fb.h b/drivers/video/fbdev/au1100fb.h
index 9af19939a9c6..e7239bceefd3 100644
--- a/drivers/video/fbdev/au1100fb.h
+++ b/drivers/video/fbdev/au1100fb.h
@@ -110,6 +110,7 @@ struct au1100fb_device {
dma_addr_t fb_phys;
int panel_idx;
struct clk *lcdclk;
+ struct device *dev;
};
/********************************************************************/
diff --git a/drivers/video/fbdev/au1200fb.c b/drivers/video/fbdev/au1200fb.c
index 3872ccef4cb2..26caffb02b7e 100644
--- a/drivers/video/fbdev/au1200fb.c
+++ b/drivers/video/fbdev/au1200fb.c
@@ -147,6 +147,7 @@ struct au1200_lcd_iodata_t {
struct au1200fb_device {
struct fb_info *fb_info; /* FB driver info record */
struct au1200fb_platdata *pd;
+ struct device *dev;
int plane;
unsigned char* fb_mem; /* FrameBuffer memory map */
@@ -1232,10 +1233,8 @@ static int au1200fb_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
{
struct au1200fb_device *fbdev = info->par;
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- pgprot_val(vma->vm_page_prot) |= _CACHE_MASK; /* CCA=7 */
-
- return vm_iomap_memory(vma, fbdev->fb_phys, fbdev->fb_len);
+ return dma_mmap_attrs(fbdev->dev, vma, fbdev->fb_mem, fbdev->fb_phys,
+ fbdev->fb_len, DMA_ATTR_NON_CONSISTENT);
}
static void set_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata)
@@ -1647,7 +1646,6 @@ static int au1200fb_drv_probe(struct platform_device *dev)
struct au1200fb_device *fbdev;
struct au1200fb_platdata *pd;
struct fb_info *fbi = NULL;
- unsigned long page;
int bpp, plane, ret, irq;
print_info("" DRIVER_DESC "");
@@ -1685,6 +1683,7 @@ static int au1200fb_drv_probe(struct platform_device *dev)
fbdev = fbi->par;
fbdev->fb_info = fbi;
fbdev->pd = pd;
+ fbdev->dev = &dev->dev;
fbdev->plane = plane;
@@ -1702,16 +1701,6 @@ static int au1200fb_drv_probe(struct platform_device *dev)
goto failed;
}
- /*
- * Set page reserved so that mmap will work. This is necessary
- * since we'll be remapping normal memory.
- */
- for (page = (unsigned long)fbdev->fb_phys;
- page < PAGE_ALIGN((unsigned long)fbdev->fb_phys +
- fbdev->fb_len);
- page += PAGE_SIZE) {
- SetPageReserved(pfn_to_page(page >> PAGE_SHIFT)); /* LCD DMA is NOT coherent on Au1200 */
- }
print_dbg("Framebuffer memory map at %p", fbdev->fb_mem);
print_dbg("phys=0x%08x, size=%dK", fbdev->fb_phys, fbdev->fb_len / 1024);
diff --git a/drivers/video/fbdev/chipsfb.c b/drivers/video/fbdev/chipsfb.c
index ca549e1532e6..f4dc320dcafe 100644
--- a/drivers/video/fbdev/chipsfb.c
+++ b/drivers/video/fbdev/chipsfb.c
@@ -366,7 +366,6 @@ static int chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
p = framebuffer_alloc(0, &dp->dev);
if (p == NULL) {
- dev_err(&dp->dev, "Cannot allocate framebuffer structure\n");
rc = -ENOMEM;
goto err_disable;
}
diff --git a/drivers/video/fbdev/cirrusfb.c b/drivers/video/fbdev/cirrusfb.c
index b3be06dd2908..e4ce5667b125 100644
--- a/drivers/video/fbdev/cirrusfb.c
+++ b/drivers/video/fbdev/cirrusfb.c
@@ -2093,7 +2093,6 @@ static int cirrusfb_pci_register(struct pci_dev *pdev,
info = framebuffer_alloc(sizeof(struct cirrusfb_info), &pdev->dev);
if (!info) {
- printk(KERN_ERR "cirrusfb: could not allocate memory\n");
ret = -ENOMEM;
goto err_out;
}
@@ -2206,10 +2205,8 @@ static int cirrusfb_zorro_register(struct zorro_dev *z,
struct cirrusfb_info *cinfo;
info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev);
- if (!info) {
- printk(KERN_ERR "cirrusfb: could not allocate memory\n");
+ if (!info)
return -ENOMEM;
- }
zcl = (const struct zorrocl *)ent->driver_data;
btype = zcl->type;
diff --git a/drivers/video/fbdev/controlfb.c b/drivers/video/fbdev/controlfb.c
index 7af8db28bb80..9a680ef3ffc3 100644
--- a/drivers/video/fbdev/controlfb.c
+++ b/drivers/video/fbdev/controlfb.c
@@ -182,7 +182,7 @@ int init_module(void)
int ret = -ENXIO;
dp = of_find_node_by_name(NULL, "control");
- if (dp != 0 && !control_of_init(dp))
+ if (dp && !control_of_init(dp))
ret = 0;
of_node_put(dp);
@@ -580,7 +580,7 @@ static int __init control_init(void)
control_setup(option);
dp = of_find_node_by_name(NULL, "control");
- if (dp != 0 && !control_of_init(dp))
+ if (dp && !control_of_init(dp))
ret = 0;
of_node_put(dp);
@@ -683,8 +683,8 @@ static int __init control_of_init(struct device_node *dp)
return -ENXIO;
}
p = kzalloc(sizeof(*p), GFP_KERNEL);
- if (p == 0)
- return -ENXIO;
+ if (!p)
+ return -ENOMEM;
control_fb = p; /* save it for cleanups */
/* Map in frame buffer and registers */
diff --git a/drivers/video/fbdev/cyber2000fb.c b/drivers/video/fbdev/cyber2000fb.c
index 452ef07b3a06..3a2d9ff0aa42 100644
--- a/drivers/video/fbdev/cyber2000fb.c
+++ b/drivers/video/fbdev/cyber2000fb.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/video/cyber2000fb.c
*
@@ -9,10 +10,6 @@
* 32 bit support, text color and panning fixes for modes != 8 bit
* Copyright (C) 2002 Denis Oliver Kropp <dok@directfb.org>
*
- * 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.
- *
* Integraphics CyberPro 2000, 2010 and 5000 frame buffer device
*
* Based on cyberfb.c.
@@ -1641,10 +1638,6 @@ static void cyberpro_common_resume(struct cfb_info *cfb)
}
/*
- * PCI specific support.
- */
-#ifdef CONFIG_PCI
-/*
* We need to wake up the CyberPro, and make sure its in linear memory
* mode. Unfortunately, this is specific to the platform and card that
* we are running on.
@@ -1860,7 +1853,6 @@ static struct pci_driver cyberpro_driver = {
.resume = cyberpro_pci_resume,
.id_table = cyberpro_pci_table
};
-#endif
/*
* I don't think we can use the "module_init" stuff here because
diff --git a/drivers/video/fbdev/cyber2000fb.h b/drivers/video/fbdev/cyber2000fb.h
index bad69102e774..04641aa13acc 100644
--- a/drivers/video/fbdev/cyber2000fb.h
+++ b/drivers/video/fbdev/cyber2000fb.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/drivers/video/cyber2000fb.h
*
* Copyright (C) 1998-2000 Russell King
*
- * 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.
- *
* Integraphics Cyber2000 frame buffer device
*/
diff --git a/drivers/video/fbdev/da8xx-fb.c b/drivers/video/fbdev/da8xx-fb.c
index 9ea817ac1d81..b1cf248f3291 100644
--- a/drivers/video/fbdev/da8xx-fb.c
+++ b/drivers/video/fbdev/da8xx-fb.c
@@ -1387,7 +1387,6 @@ static int fb_probe(struct platform_device *device)
da8xx_fb_info = framebuffer_alloc(sizeof(struct da8xx_fb_par),
&device->dev);
if (!da8xx_fb_info) {
- dev_dbg(&device->dev, "Memory allocation failed for fb_info\n");
ret = -ENOMEM;
goto err_pm_runtime_disable;
}
diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c
index 9f39f0c360e0..04a22663b4fb 100644
--- a/drivers/video/fbdev/efifb.c
+++ b/drivers/video/fbdev/efifb.c
@@ -169,6 +169,11 @@ static void efifb_show_boot_graphics(struct fb_info *info)
return;
}
+ if (bgrt_tab.status & 0x06) {
+ pr_info("efifb: BGRT rotation bits set, not showing boot graphics\n");
+ return;
+ }
+
/* Avoid flashing the logo if we're going to print std probe messages */
if (console_loglevel > CONSOLE_LOGLEVEL_QUIET)
return;
@@ -448,7 +453,6 @@ static int efifb_probe(struct platform_device *dev)
info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
if (!info) {
- pr_err("efifb: cannot allocate framebuffer\n");
err = -ENOMEM;
goto err_release_mem;
}
diff --git a/drivers/video/fbdev/ep93xx-fb.c b/drivers/video/fbdev/ep93xx-fb.c
index 75f0db25d19f..d04a047094fc 100644
--- a/drivers/video/fbdev/ep93xx-fb.c
+++ b/drivers/video/fbdev/ep93xx-fb.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/video/ep93xx-fb.c
*
@@ -10,11 +11,6 @@
*
* Based on the Cirrus Logic ep93xxfb driver, and various other ep93xxfb
* drivers.
- *
- * 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.
- *
*/
#include <linux/platform_device.h>
diff --git a/drivers/video/fbdev/fb-puv3.c b/drivers/video/fbdev/fb-puv3.c
index 1bddcc20b2c0..fa62c4dff7d1 100644
--- a/drivers/video/fbdev/fb-puv3.c
+++ b/drivers/video/fbdev/fb-puv3.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Frame Buffer Driver for PKUnity-v3 Unigfx
* Code specific to PKUnity SoC and UniCore ISA
*
* Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
* Copyright (C) 2001-2010 Guan Xuetao
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/video/fbdev/gbefb.c b/drivers/video/fbdev/gbefb.c
index 3fcb33232ba3..b9f6a82a0495 100644
--- a/drivers/video/fbdev/gbefb.c
+++ b/drivers/video/fbdev/gbefb.c
@@ -39,9 +39,7 @@ struct gbefb_par {
int valid;
};
-#ifdef CONFIG_SGI_IP32
#define GBE_BASE 0x16000000 /* SGI O2 */
-#endif
/* macro for fastest write-though access to the framebuffer */
#ifdef CONFIG_MIPS
@@ -51,10 +49,6 @@ struct gbefb_par {
#define pgprot_fb(_prot) (((_prot) & (~_CACHE_MASK)) | _CACHE_CACHABLE_NO_WA)
#endif
#endif
-#ifdef CONFIG_X86
-#define pgprot_fb(_prot) (((_prot) & ~_PAGE_CACHE_MASK) | \
- cachemode2protval(_PAGE_CACHE_MODE_UC_MINUS))
-#endif
/*
* RAM we reserve for the frame buffer. This defines the maximum screen
@@ -279,7 +273,7 @@ static void gbe_turn_off(void)
val = 0;
SET_GBE_FIELD(VT_XY, FREEZE, val, 1);
gbe->vt_xy = val;
- udelay(10000);
+ mdelay(10);
for (i = 0; i < 10000; i++) {
val = gbe->vt_xy;
if (GET_GBE_FIELD(VT_XY, FREEZE, val) != 1)
@@ -294,7 +288,7 @@ static void gbe_turn_off(void)
val = gbe->dotclock;
SET_GBE_FIELD(DOTCLK, RUN, val, 0);
gbe->dotclock = val;
- udelay(10000);
+ mdelay(10);
for (i = 0; i < 10000; i++) {
val = gbe->dotclock;
if (GET_GBE_FIELD(DOTCLK, RUN, val))
@@ -331,7 +325,7 @@ static void gbe_turn_on(void)
val = gbe->dotclock;
SET_GBE_FIELD(DOTCLK, RUN, val, 1);
gbe->dotclock = val;
- udelay(10000);
+ mdelay(10);
for (i = 0; i < 10000; i++) {
val = gbe->dotclock;
if (GET_GBE_FIELD(DOTCLK, RUN, val) != 1)
@@ -346,7 +340,7 @@ static void gbe_turn_on(void)
val = 0;
SET_GBE_FIELD(VT_XY, FREEZE, val, 0);
gbe->vt_xy = val;
- udelay(10000);
+ mdelay(10);
for (i = 0; i < 10000; i++) {
val = gbe->vt_xy;
if (GET_GBE_FIELD(VT_XY, FREEZE, val))
@@ -547,7 +541,7 @@ static void gbe_set_timing_info(struct gbe_timing_info *timing)
SET_GBE_FIELD(DOTCLK, P, val, timing->pll_p);
SET_GBE_FIELD(DOTCLK, RUN, val, 0); /* do not start yet */
gbe->dotclock = val;
- udelay(10000);
+ mdelay(10);
/* setup pixel counter */
val = 0;
@@ -1018,9 +1012,10 @@ static int gbefb_mmap(struct fb_info *info,
/* remap using the fastest write-through mode on architecture */
/* try not polluting the cache when possible */
+#ifdef CONFIG_MIPS
pgprot_val(vma->vm_page_prot) =
pgprot_fb(pgprot_val(vma->vm_page_prot));
-
+#endif
/* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */
/* look for the starting tile */
diff --git a/drivers/video/fbdev/grvga.c b/drivers/video/fbdev/grvga.c
index df5d546e57e9..d22e8b0c906d 100644
--- a/drivers/video/fbdev/grvga.c
+++ b/drivers/video/fbdev/grvga.c
@@ -336,10 +336,8 @@ static int grvga_probe(struct platform_device *dev)
char *options = NULL, *mode_opt = NULL;
info = framebuffer_alloc(sizeof(struct grvga_par), &dev->dev);
- if (!info) {
- dev_err(&dev->dev, "framebuffer_alloc failed\n");
+ if (!info)
return -ENOMEM;
- }
/* Expecting: "grvga: modestring, [addr:<framebuffer physical address>], [size:<framebuffer size>]
*
diff --git a/drivers/video/fbdev/gxt4500.c b/drivers/video/fbdev/gxt4500.c
index 37527a10b954..c7502fd8f447 100644
--- a/drivers/video/fbdev/gxt4500.c
+++ b/drivers/video/fbdev/gxt4500.c
@@ -643,10 +643,9 @@ static int gxt4500_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
info = framebuffer_alloc(sizeof(struct gxt4500_par), &pdev->dev);
- if (!info) {
- dev_err(&pdev->dev, "gxt4500: cannot alloc FB info record\n");
+ if (!info)
goto err_free_fb;
- }
+
par = info->par;
cardtype = ent->driver_data;
par->refclk_ps = cardinfo[cardtype].refclk_ps;
diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
index 00f5bdcc6c6f..2dcb7c58b31e 100644
--- a/drivers/video/fbdev/hyperv_fb.c
+++ b/drivers/video/fbdev/hyperv_fb.c
@@ -762,10 +762,8 @@ static int hvfb_probe(struct hv_device *hdev,
int ret;
info = framebuffer_alloc(sizeof(struct hvfb_par), &hdev->device);
- if (!info) {
- pr_err("No memory for framebuffer info\n");
+ if (!info)
return -ENOMEM;
- }
par = info->par;
par->info = info;
diff --git a/drivers/video/fbdev/i740fb.c b/drivers/video/fbdev/i740fb.c
index 24d3280a5b5f..347cf8babc3e 100644
--- a/drivers/video/fbdev/i740fb.c
+++ b/drivers/video/fbdev/i740fb.c
@@ -1006,10 +1006,8 @@ static int i740fb_probe(struct pci_dev *dev, const struct pci_device_id *ent)
u8 *edid;
info = framebuffer_alloc(sizeof(struct i740fb_par), &(dev->dev));
- if (!info) {
- dev_err(&(dev->dev), "cannot allocate framebuffer\n");
+ if (!info)
return -ENOMEM;
- }
par = info->par;
mutex_init(&par->open_lock);
diff --git a/drivers/video/fbdev/imsttfb.c b/drivers/video/fbdev/imsttfb.c
index 35bba3c2036d..58b01c7d9056 100644
--- a/drivers/video/fbdev/imsttfb.c
+++ b/drivers/video/fbdev/imsttfb.c
@@ -1477,11 +1477,8 @@ static int imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
printk(KERN_ERR "imsttfb: no OF node for pci device\n");
info = framebuffer_alloc(sizeof(struct imstt_par), &pdev->dev);
-
- if (!info) {
- printk(KERN_ERR "imsttfb: Can't allocate memory\n");
+ if (!info)
return -ENOMEM;
- }
par = info->par;
diff --git a/drivers/video/fbdev/imxfb.c b/drivers/video/fbdev/imxfb.c
index c4eb8661f751..b3286d1fa543 100644
--- a/drivers/video/fbdev/imxfb.c
+++ b/drivers/video/fbdev/imxfb.c
@@ -974,10 +974,9 @@ static int imxfb_probe(struct platform_device *pdev)
}
fbi->map_size = PAGE_ALIGN(info->fix.smem_len);
- info->screen_base = dma_alloc_wc(&pdev->dev, fbi->map_size,
- &fbi->map_dma, GFP_KERNEL);
-
- if (!info->screen_base) {
+ info->screen_buffer = dma_alloc_wc(&pdev->dev, fbi->map_size,
+ &fbi->map_dma, GFP_KERNEL);
+ if (!info->screen_buffer) {
dev_err(&pdev->dev, "Failed to allocate video RAM: %d\n", ret);
ret = -ENOMEM;
goto failed_map;
@@ -1046,7 +1045,7 @@ failed_cmap:
if (pdata && pdata->exit)
pdata->exit(fbi->pdev);
failed_platform_init:
- dma_free_wc(&pdev->dev, fbi->map_size, info->screen_base,
+ dma_free_wc(&pdev->dev, fbi->map_size, info->screen_buffer,
fbi->map_dma);
failed_map:
iounmap(fbi->regs);
@@ -1077,7 +1076,7 @@ static int imxfb_remove(struct platform_device *pdev)
pdata = dev_get_platdata(&pdev->dev);
if (pdata && pdata->exit)
pdata->exit(fbi->pdev);
- dma_free_wc(&pdev->dev, fbi->map_size, info->screen_base,
+ dma_free_wc(&pdev->dev, fbi->map_size, info->screen_buffer,
fbi->map_dma);
iounmap(fbi->regs);
release_mem_region(res->start, resource_size(res));
diff --git a/drivers/video/fbdev/intelfb/intelfbdrv.c b/drivers/video/fbdev/intelfb/intelfbdrv.c
index d7463a2a5d83..a76c61512c60 100644
--- a/drivers/video/fbdev/intelfb/intelfbdrv.c
+++ b/drivers/video/fbdev/intelfb/intelfbdrv.c
@@ -491,10 +491,9 @@ static int intelfb_pci_register(struct pci_dev *pdev,
}
info = framebuffer_alloc(sizeof(struct intelfb_info), &pdev->dev);
- if (!info) {
- ERR_MSG("Could not allocate memory for intelfb_info.\n");
- return -ENODEV;
- }
+ if (!info)
+ return -ENOMEM;
+
if (fb_alloc_cmap(&info->cmap, 256, 1) < 0) {
ERR_MSG("Could not allocate cmap for intelfb_info.\n");
goto err_out_cmap;
diff --git a/drivers/video/fbdev/jz4740_fb.c b/drivers/video/fbdev/jz4740_fb.c
index 145095655cc2..0b6fa25f6924 100644
--- a/drivers/video/fbdev/jz4740_fb.c
+++ b/drivers/video/fbdev/jz4740_fb.c
@@ -457,7 +457,6 @@ static int jzfb_alloc_devmem(struct jzfb *jzfb)
{
int max_videosize = 0;
struct fb_videomode *mode = jzfb->pdata->modes;
- void *page;
int i;
for (i = 0; i < jzfb->pdata->num_modes; ++mode, ++i) {
@@ -482,12 +481,6 @@ static int jzfb_alloc_devmem(struct jzfb *jzfb)
if (!jzfb->vidmem)
goto err_free_framedesc;
- for (page = jzfb->vidmem;
- page < jzfb->vidmem + PAGE_ALIGN(jzfb->vidmem_size);
- page += PAGE_SIZE) {
- SetPageReserved(virt_to_page(page));
- }
-
jzfb->framedesc->next = jzfb->framedesc_phys;
jzfb->framedesc->addr = jzfb->vidmem_phys;
jzfb->framedesc->id = 0xdeafbead;
@@ -535,10 +528,8 @@ static int jzfb_probe(struct platform_device *pdev)
}
fb = framebuffer_alloc(sizeof(struct jzfb), &pdev->dev);
- if (!fb) {
- dev_err(&pdev->dev, "Failed to allocate framebuffer device\n");
+ if (!fb)
return -ENOMEM;
- }
fb->fbops = &jzfb_ops;
fb->flags = FBINFO_DEFAULT;
diff --git a/drivers/video/fbdev/matrox/matroxfb_base.c b/drivers/video/fbdev/matrox/matroxfb_base.c
index c76bef078c75..1a555f70923a 100644
--- a/drivers/video/fbdev/matrox/matroxfb_base.c
+++ b/drivers/video/fbdev/matrox/matroxfb_base.c
@@ -2502,7 +2502,7 @@ MODULE_PARM_DESC(nobios, "Disables ROM BIOS (0 or 1=disabled) (default=do not ch
module_param(noinit, int, 0);
MODULE_PARM_DESC(noinit, "Disables W/SG/SD-RAM and bus interface initialization (0 or 1=do not initialize) (default=0)");
module_param(memtype, int, 0);
-MODULE_PARM_DESC(memtype, "Memory type for G200/G400 (see Documentation/fb/matroxfb.txt for explanation) (default=3 for G200, 0 for G400)");
+MODULE_PARM_DESC(memtype, "Memory type for G200/G400 (see Documentation/fb/matroxfb.rst for explanation) (default=3 for G200, 0 for G400)");
module_param(mtrr, int, 0);
MODULE_PARM_DESC(mtrr, "This speeds up video memory accesses (0=disabled or 1) (default=1)");
module_param(sgram, int, 0);
diff --git a/drivers/video/fbdev/mb862xx/mb862xx-i2c.c b/drivers/video/fbdev/mb862xx/mb862xx-i2c.c
index ba96c44f2761..ffdb1597d303 100644
--- a/drivers/video/fbdev/mb862xx/mb862xx-i2c.c
+++ b/drivers/video/fbdev/mb862xx/mb862xx-i2c.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Coral-P(A)/Lime I2C adapter driver
*
* (C) 2011 DENX Software Engineering, Anatolij Gustschin <agust@denx.de>
- *
- * 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.
- *
*/
#include <linux/fb.h>
diff --git a/drivers/video/fbdev/mb862xx/mb862xxfb_accel.c b/drivers/video/fbdev/mb862xx/mb862xxfb_accel.c
index 8dd296d257dd..f58ff900e82a 100644
--- a/drivers/video/fbdev/mb862xx/mb862xxfb_accel.c
+++ b/drivers/video/fbdev/mb862xx/mb862xxfb_accel.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/mb862xx/mb862xxfb_accel.c
*
@@ -6,11 +7,6 @@
* (C) 2007 Alexander Shishkin <virtuoso@slind.org>
* (C) 2009 Valentin Sitdikov <v.sitdikov@gmail.com>
* (C) 2009 Siemens AG
- *
- * 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.
- *
*/
#include <linux/fb.h>
#include <linux/delay.h>
diff --git a/drivers/video/fbdev/mb862xx/mb862xxfbdrv.c b/drivers/video/fbdev/mb862xx/mb862xxfbdrv.c
index cd372527c9e4..962c0171d271 100644
--- a/drivers/video/fbdev/mb862xx/mb862xxfbdrv.c
+++ b/drivers/video/fbdev/mb862xx/mb862xxfbdrv.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/mb862xx/mb862xxfb.c
*
@@ -5,11 +6,6 @@
*
* (C) 2008 Anatolij Gustschin <agust@denx.de>
* DENX Software Engineering
- *
- * 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.
- *
*/
#undef DEBUG
@@ -684,10 +680,8 @@ static int of_platform_mb862xx_probe(struct platform_device *ofdev)
}
info = framebuffer_alloc(sizeof(struct mb862xxfb_par), dev);
- if (info == NULL) {
- dev_err(dev, "cannot allocate framebuffer\n");
+ if (!info)
return -ENOMEM;
- }
par = info->par;
par->info = info;
@@ -1009,7 +1003,6 @@ static int mb862xx_pci_probe(struct pci_dev *pdev,
info = framebuffer_alloc(sizeof(struct mb862xxfb_par), dev);
if (!info) {
- dev_err(dev, "framebuffer alloc failed\n");
ret = -ENOMEM;
goto dis_dev;
}
diff --git a/drivers/video/fbdev/mbx/mbxfb.c b/drivers/video/fbdev/mbx/mbxfb.c
index 6ded480a69b4..50935252b50b 100644
--- a/drivers/video/fbdev/mbx/mbxfb.c
+++ b/drivers/video/fbdev/mbx/mbxfb.c
@@ -899,10 +899,8 @@ static int mbxfb_probe(struct platform_device *dev)
}
fbi = framebuffer_alloc(sizeof(struct mbxfb_info), &dev->dev);
- if (fbi == NULL) {
- dev_err(&dev->dev, "framebuffer_alloc failed\n");
+ if (!fbi)
return -ENOMEM;
- }
mfbi = fbi->par;
fbi->pseudo_palette = mfbi->pseudo_palette;
diff --git a/drivers/video/fbdev/mmp/hw/mmp_ctrl.c b/drivers/video/fbdev/mmp/hw/mmp_ctrl.c
index 87d943f15a12..17174cd7a5bb 100644
--- a/drivers/video/fbdev/mmp/hw/mmp_ctrl.c
+++ b/drivers/video/fbdev/mmp/hw/mmp_ctrl.c
@@ -433,7 +433,7 @@ static int mmphw_probe(struct platform_device *pdev)
{
struct mmp_mach_plat_info *mi;
struct resource *res;
- int ret, i, size, irq;
+ int ret, i, irq;
struct mmphw_path_plat *path_plat;
struct mmphw_ctrl *ctrl = NULL;
@@ -461,9 +461,9 @@ static int mmphw_probe(struct platform_device *pdev)
}
/* allocate */
- size = sizeof(struct mmphw_ctrl) + sizeof(struct mmphw_path_plat) *
- mi->path_num;
- ctrl = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+ ctrl = devm_kzalloc(&pdev->dev,
+ struct_size(ctrl, path_plats, mi->path_num),
+ GFP_KERNEL);
if (!ctrl) {
ret = -ENOMEM;
goto failed;
diff --git a/drivers/video/fbdev/mx3fb.c b/drivers/video/fbdev/mx3fb.c
index 1c3c7ab26a95..bafd5f5fac5a 100644
--- a/drivers/video/fbdev/mx3fb.c
+++ b/drivers/video/fbdev/mx3fb.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2008
* Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
*
* Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/module.h>
diff --git a/drivers/video/fbdev/mxsfb.c b/drivers/video/fbdev/mxsfb.c
deleted file mode 100644
index d8bebe35b410..000000000000
--- a/drivers/video/fbdev/mxsfb.c
+++ /dev/null
@@ -1,1028 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2010 Juergen Beisert, Pengutronix
- *
- * This code is based on:
- * Author: Vitaly Wool <vital@embeddedalley.com>
- *
- * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-#define DRIVER_NAME "mxsfb"
-
-/**
- * @file
- * @brief LCDIF driver for i.MX23 and i.MX28
- *
- * The LCDIF support four modes of operation
- * - MPU interface (to drive smart displays) -> not supported yet
- * - VSYNC interface (like MPU interface plus Vsync) -> not supported yet
- * - Dotclock interface (to drive LC displays with RGB data and sync signals)
- * - DVI (to drive ITU-R BT656) -> not supported yet
- *
- * This driver depends on a correct setup of the pins used for this purpose
- * (platform specific).
- *
- * For the developer: Don't forget to set the data bus width to the display
- * in the imx_fb_videomode structure. You will else end up with ugly colours.
- * If you fight against jitter you can vary the clock delay. This is a feature
- * of the i.MX28 and you can vary it between 2 ns ... 8 ns in 2 ns steps. Give
- * the required value in the imx_fb_videomode structure.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/dma-mapping.h>
-#include <linux/io.h>
-#include <linux/fb.h>
-#include <linux/regulator/consumer.h>
-#include <video/of_display_timing.h>
-#include <video/of_videomode.h>
-#include <video/videomode.h>
-
-#define REG_SET 4
-#define REG_CLR 8
-
-#define LCDC_CTRL 0x00
-#define LCDC_CTRL1 0x10
-#define LCDC_V4_CTRL2 0x20
-#define LCDC_V3_TRANSFER_COUNT 0x20
-#define LCDC_V4_TRANSFER_COUNT 0x30
-#define LCDC_V4_CUR_BUF 0x40
-#define LCDC_V4_NEXT_BUF 0x50
-#define LCDC_V3_CUR_BUF 0x30
-#define LCDC_V3_NEXT_BUF 0x40
-#define LCDC_TIMING 0x60
-#define LCDC_VDCTRL0 0x70
-#define LCDC_VDCTRL1 0x80
-#define LCDC_VDCTRL2 0x90
-#define LCDC_VDCTRL3 0xa0
-#define LCDC_VDCTRL4 0xb0
-#define LCDC_DVICTRL0 0xc0
-#define LCDC_DVICTRL1 0xd0
-#define LCDC_DVICTRL2 0xe0
-#define LCDC_DVICTRL3 0xf0
-#define LCDC_DVICTRL4 0x100
-#define LCDC_V4_DATA 0x180
-#define LCDC_V3_DATA 0x1b0
-#define LCDC_V4_DEBUG0 0x1d0
-#define LCDC_V3_DEBUG0 0x1f0
-
-#define CTRL_SFTRST (1 << 31)
-#define CTRL_CLKGATE (1 << 30)
-#define CTRL_BYPASS_COUNT (1 << 19)
-#define CTRL_VSYNC_MODE (1 << 18)
-#define CTRL_DOTCLK_MODE (1 << 17)
-#define CTRL_DATA_SELECT (1 << 16)
-#define CTRL_SET_BUS_WIDTH(x) (((x) & 0x3) << 10)
-#define CTRL_GET_BUS_WIDTH(x) (((x) >> 10) & 0x3)
-#define CTRL_SET_WORD_LENGTH(x) (((x) & 0x3) << 8)
-#define CTRL_GET_WORD_LENGTH(x) (((x) >> 8) & 0x3)
-#define CTRL_MASTER (1 << 5)
-#define CTRL_DF16 (1 << 3)
-#define CTRL_DF18 (1 << 2)
-#define CTRL_DF24 (1 << 1)
-#define CTRL_RUN (1 << 0)
-
-#define CTRL1_FIFO_CLEAR (1 << 21)
-#define CTRL1_SET_BYTE_PACKAGING(x) (((x) & 0xf) << 16)
-#define CTRL1_GET_BYTE_PACKAGING(x) (((x) >> 16) & 0xf)
-
-#define TRANSFER_COUNT_SET_VCOUNT(x) (((x) & 0xffff) << 16)
-#define TRANSFER_COUNT_GET_VCOUNT(x) (((x) >> 16) & 0xffff)
-#define TRANSFER_COUNT_SET_HCOUNT(x) ((x) & 0xffff)
-#define TRANSFER_COUNT_GET_HCOUNT(x) ((x) & 0xffff)
-
-
-#define VDCTRL0_ENABLE_PRESENT (1 << 28)
-#define VDCTRL0_VSYNC_ACT_HIGH (1 << 27)
-#define VDCTRL0_HSYNC_ACT_HIGH (1 << 26)
-#define VDCTRL0_DOTCLK_ACT_FALLING (1 << 25)
-#define VDCTRL0_ENABLE_ACT_HIGH (1 << 24)
-#define VDCTRL0_VSYNC_PERIOD_UNIT (1 << 21)
-#define VDCTRL0_VSYNC_PULSE_WIDTH_UNIT (1 << 20)
-#define VDCTRL0_HALF_LINE (1 << 19)
-#define VDCTRL0_HALF_LINE_MODE (1 << 18)
-#define VDCTRL0_SET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff)
-#define VDCTRL0_GET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff)
-
-#define VDCTRL2_SET_HSYNC_PERIOD(x) ((x) & 0x3ffff)
-#define VDCTRL2_GET_HSYNC_PERIOD(x) ((x) & 0x3ffff)
-
-#define VDCTRL3_MUX_SYNC_SIGNALS (1 << 29)
-#define VDCTRL3_VSYNC_ONLY (1 << 28)
-#define SET_HOR_WAIT_CNT(x) (((x) & 0xfff) << 16)
-#define GET_HOR_WAIT_CNT(x) (((x) >> 16) & 0xfff)
-#define SET_VERT_WAIT_CNT(x) ((x) & 0xffff)
-#define GET_VERT_WAIT_CNT(x) ((x) & 0xffff)
-
-#define VDCTRL4_SET_DOTCLK_DLY(x) (((x) & 0x7) << 29) /* v4 only */
-#define VDCTRL4_GET_DOTCLK_DLY(x) (((x) >> 29) & 0x7) /* v4 only */
-#define VDCTRL4_SYNC_SIGNALS_ON (1 << 18)
-#define SET_DOTCLK_H_VALID_DATA_CNT(x) ((x) & 0x3ffff)
-
-#define DEBUG0_HSYNC (1 < 26)
-#define DEBUG0_VSYNC (1 < 25)
-
-#define MIN_XRES 120
-#define MIN_YRES 120
-
-#define RED 0
-#define GREEN 1
-#define BLUE 2
-#define TRANSP 3
-
-#define STMLCDIF_8BIT 1 /** pixel data bus to the display is of 8 bit width */
-#define STMLCDIF_16BIT 0 /** pixel data bus to the display is of 16 bit width */
-#define STMLCDIF_18BIT 2 /** pixel data bus to the display is of 18 bit width */
-#define STMLCDIF_24BIT 3 /** pixel data bus to the display is of 24 bit width */
-
-#define MXSFB_SYNC_DATA_ENABLE_HIGH_ACT (1 << 6)
-#define MXSFB_SYNC_DOTCLK_FALLING_ACT (1 << 7) /* negative edge sampling */
-
-enum mxsfb_devtype {
- MXSFB_V3,
- MXSFB_V4,
-};
-
-/* CPU dependent register offsets */
-struct mxsfb_devdata {
- unsigned transfer_count;
- unsigned cur_buf;
- unsigned next_buf;
- unsigned debug0;
- unsigned hs_wdth_mask;
- unsigned hs_wdth_shift;
- unsigned ipversion;
-};
-
-struct mxsfb_info {
- struct platform_device *pdev;
- struct clk *clk;
- struct clk *clk_axi;
- struct clk *clk_disp_axi;
- void __iomem *base; /* registers */
- unsigned allocated_size;
- int enabled;
- unsigned ld_intf_width;
- unsigned dotclk_delay;
- const struct mxsfb_devdata *devdata;
- u32 sync;
- struct regulator *reg_lcd;
- int pre_init;
-};
-
-#define mxsfb_is_v3(host) (host->devdata->ipversion == 3)
-#define mxsfb_is_v4(host) (host->devdata->ipversion == 4)
-
-static const struct mxsfb_devdata mxsfb_devdata[] = {
- [MXSFB_V3] = {
- .transfer_count = LCDC_V3_TRANSFER_COUNT,
- .cur_buf = LCDC_V3_CUR_BUF,
- .next_buf = LCDC_V3_NEXT_BUF,
- .debug0 = LCDC_V3_DEBUG0,
- .hs_wdth_mask = 0xff,
- .hs_wdth_shift = 24,
- .ipversion = 3,
- },
- [MXSFB_V4] = {
- .transfer_count = LCDC_V4_TRANSFER_COUNT,
- .cur_buf = LCDC_V4_CUR_BUF,
- .next_buf = LCDC_V4_NEXT_BUF,
- .debug0 = LCDC_V4_DEBUG0,
- .hs_wdth_mask = 0x3fff,
- .hs_wdth_shift = 18,
- .ipversion = 4,
- },
-};
-
-/* mask and shift depends on architecture */
-static inline u32 set_hsync_pulse_width(struct mxsfb_info *host, unsigned val)
-{
- return (val & host->devdata->hs_wdth_mask) <<
- host->devdata->hs_wdth_shift;
-}
-
-static inline u32 get_hsync_pulse_width(struct mxsfb_info *host, unsigned val)
-{
- return (val >> host->devdata->hs_wdth_shift) &
- host->devdata->hs_wdth_mask;
-}
-
-static const struct fb_bitfield def_rgb565[] = {
- [RED] = {
- .offset = 11,
- .length = 5,
- },
- [GREEN] = {
- .offset = 5,
- .length = 6,
- },
- [BLUE] = {
- .offset = 0,
- .length = 5,
- },
- [TRANSP] = { /* no support for transparency */
- .length = 0,
- }
-};
-
-static const struct fb_bitfield def_rgb888[] = {
- [RED] = {
- .offset = 16,
- .length = 8,
- },
- [GREEN] = {
- .offset = 8,
- .length = 8,
- },
- [BLUE] = {
- .offset = 0,
- .length = 8,
- },
- [TRANSP] = { /* no support for transparency */
- .length = 0,
- }
-};
-
-static inline unsigned chan_to_field(unsigned chan, struct fb_bitfield *bf)
-{
- chan &= 0xffff;
- chan >>= 16 - bf->length;
- return chan << bf->offset;
-}
-
-static int mxsfb_check_var(struct fb_var_screeninfo *var,
- struct fb_info *fb_info)
-{
- struct mxsfb_info *host = fb_info->par;
- const struct fb_bitfield *rgb = NULL;
-
- if (var->xres < MIN_XRES)
- var->xres = MIN_XRES;
- if (var->yres < MIN_YRES)
- var->yres = MIN_YRES;
-
- var->xres_virtual = var->xres;
-
- var->yres_virtual = var->yres;
-
- switch (var->bits_per_pixel) {
- case 16:
- /* always expect RGB 565 */
- rgb = def_rgb565;
- break;
- case 32:
- switch (host->ld_intf_width) {
- case STMLCDIF_8BIT:
- pr_debug("Unsupported LCD bus width mapping\n");
- break;
- case STMLCDIF_16BIT:
- case STMLCDIF_18BIT:
- case STMLCDIF_24BIT:
- /* real 24 bit */
- rgb = def_rgb888;
- break;
- }
- break;
- default:
- pr_err("Unsupported colour depth: %u\n", var->bits_per_pixel);
- return -EINVAL;
- }
-
- /*
- * Copy the RGB parameters for this display
- * from the machine specific parameters.
- */
- var->red = rgb[RED];
- var->green = rgb[GREEN];
- var->blue = rgb[BLUE];
- var->transp = rgb[TRANSP];
-
- return 0;
-}
-
-static inline void mxsfb_enable_axi_clk(struct mxsfb_info *host)
-{
- if (host->clk_axi)
- clk_prepare_enable(host->clk_axi);
-}
-
-static inline void mxsfb_disable_axi_clk(struct mxsfb_info *host)
-{
- if (host->clk_axi)
- clk_disable_unprepare(host->clk_axi);
-}
-
-static void mxsfb_enable_controller(struct fb_info *fb_info)
-{
- struct mxsfb_info *host = fb_info->par;
- u32 reg;
- int ret;
-
- dev_dbg(&host->pdev->dev, "%s\n", __func__);
-
- if (host->reg_lcd) {
- ret = regulator_enable(host->reg_lcd);
- if (ret) {
- dev_err(&host->pdev->dev,
- "lcd regulator enable failed: %d\n", ret);
- return;
- }
- }
-
- if (host->clk_disp_axi)
- clk_prepare_enable(host->clk_disp_axi);
- clk_prepare_enable(host->clk);
- clk_set_rate(host->clk, PICOS2KHZ(fb_info->var.pixclock) * 1000U);
-
- mxsfb_enable_axi_clk(host);
-
- /* if it was disabled, re-enable the mode again */
- writel(CTRL_DOTCLK_MODE, host->base + LCDC_CTRL + REG_SET);
-
- /* enable the SYNC signals first, then the DMA engine */
- reg = readl(host->base + LCDC_VDCTRL4);
- reg |= VDCTRL4_SYNC_SIGNALS_ON;
- writel(reg, host->base + LCDC_VDCTRL4);
-
- writel(CTRL_RUN, host->base + LCDC_CTRL + REG_SET);
-
- host->enabled = 1;
-}
-
-static void mxsfb_disable_controller(struct fb_info *fb_info)
-{
- struct mxsfb_info *host = fb_info->par;
- unsigned loop;
- u32 reg;
- int ret;
-
- dev_dbg(&host->pdev->dev, "%s\n", __func__);
-
- /*
- * Even if we disable the controller here, it will still continue
- * until its FIFOs are running out of data
- */
- writel(CTRL_DOTCLK_MODE, host->base + LCDC_CTRL + REG_CLR);
-
- loop = 1000;
- while (loop) {
- reg = readl(host->base + LCDC_CTRL);
- if (!(reg & CTRL_RUN))
- break;
- loop--;
- }
-
- reg = readl(host->base + LCDC_VDCTRL4);
- writel(reg & ~VDCTRL4_SYNC_SIGNALS_ON, host->base + LCDC_VDCTRL4);
-
- mxsfb_disable_axi_clk(host);
-
- clk_disable_unprepare(host->clk);
- if (host->clk_disp_axi)
- clk_disable_unprepare(host->clk_disp_axi);
-
- host->enabled = 0;
-
- if (host->reg_lcd) {
- ret = regulator_disable(host->reg_lcd);
- if (ret)
- dev_err(&host->pdev->dev,
- "lcd regulator disable failed: %d\n", ret);
- }
-}
-
-static int mxsfb_set_par(struct fb_info *fb_info)
-{
- struct mxsfb_info *host = fb_info->par;
- u32 ctrl, vdctrl0, vdctrl4;
- int line_size, fb_size;
- int reenable = 0;
-
- line_size = fb_info->var.xres * (fb_info->var.bits_per_pixel >> 3);
- fb_size = fb_info->var.yres_virtual * line_size;
-
- if (fb_size > fb_info->fix.smem_len)
- return -ENOMEM;
-
- fb_info->fix.line_length = line_size;
-
- if (host->pre_init) {
- mxsfb_enable_controller(fb_info);
- host->pre_init = 0;
- return 0;
- }
-
- /*
- * It seems, you can't re-program the controller if it is still running.
- * This may lead into shifted pictures (FIFO issue?).
- * So, first stop the controller and drain its FIFOs
- */
- if (host->enabled) {
- reenable = 1;
- mxsfb_disable_controller(fb_info);
- }
-
- mxsfb_enable_axi_clk(host);
-
- /* clear the FIFOs */
- writel(CTRL1_FIFO_CLEAR, host->base + LCDC_CTRL1 + REG_SET);
-
- ctrl = CTRL_BYPASS_COUNT | CTRL_MASTER |
- CTRL_SET_BUS_WIDTH(host->ld_intf_width);
-
- switch (fb_info->var.bits_per_pixel) {
- case 16:
- dev_dbg(&host->pdev->dev, "Setting up RGB565 mode\n");
- ctrl |= CTRL_SET_WORD_LENGTH(0);
- writel(CTRL1_SET_BYTE_PACKAGING(0xf), host->base + LCDC_CTRL1);
- break;
- case 32:
- dev_dbg(&host->pdev->dev, "Setting up RGB888/666 mode\n");
- ctrl |= CTRL_SET_WORD_LENGTH(3);
- switch (host->ld_intf_width) {
- case STMLCDIF_8BIT:
- mxsfb_disable_axi_clk(host);
- dev_err(&host->pdev->dev,
- "Unsupported LCD bus width mapping\n");
- return -EINVAL;
- case STMLCDIF_16BIT:
- case STMLCDIF_18BIT:
- case STMLCDIF_24BIT:
- /* real 24 bit */
- break;
- }
- /* do not use packed pixels = one pixel per word instead */
- writel(CTRL1_SET_BYTE_PACKAGING(0x7), host->base + LCDC_CTRL1);
- break;
- default:
- mxsfb_disable_axi_clk(host);
- dev_err(&host->pdev->dev, "Unhandled color depth of %u\n",
- fb_info->var.bits_per_pixel);
- return -EINVAL;
- }
-
- writel(ctrl, host->base + LCDC_CTRL);
-
- writel(TRANSFER_COUNT_SET_VCOUNT(fb_info->var.yres) |
- TRANSFER_COUNT_SET_HCOUNT(fb_info->var.xres),
- host->base + host->devdata->transfer_count);
-
- vdctrl0 = VDCTRL0_ENABLE_PRESENT | /* always in DOTCLOCK mode */
- VDCTRL0_VSYNC_PERIOD_UNIT |
- VDCTRL0_VSYNC_PULSE_WIDTH_UNIT |
- VDCTRL0_SET_VSYNC_PULSE_WIDTH(fb_info->var.vsync_len);
- if (fb_info->var.sync & FB_SYNC_HOR_HIGH_ACT)
- vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH;
- if (fb_info->var.sync & FB_SYNC_VERT_HIGH_ACT)
- vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH;
- if (host->sync & MXSFB_SYNC_DATA_ENABLE_HIGH_ACT)
- vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH;
- if (host->sync & MXSFB_SYNC_DOTCLK_FALLING_ACT)
- vdctrl0 |= VDCTRL0_DOTCLK_ACT_FALLING;
-
- writel(vdctrl0, host->base + LCDC_VDCTRL0);
-
- /* frame length in lines */
- writel(fb_info->var.upper_margin + fb_info->var.vsync_len +
- fb_info->var.lower_margin + fb_info->var.yres,
- host->base + LCDC_VDCTRL1);
-
- /* line length in units of clocks or pixels */
- writel(set_hsync_pulse_width(host, fb_info->var.hsync_len) |
- VDCTRL2_SET_HSYNC_PERIOD(fb_info->var.left_margin +
- fb_info->var.hsync_len + fb_info->var.right_margin +
- fb_info->var.xres),
- host->base + LCDC_VDCTRL2);
-
- writel(SET_HOR_WAIT_CNT(fb_info->var.left_margin +
- fb_info->var.hsync_len) |
- SET_VERT_WAIT_CNT(fb_info->var.upper_margin +
- fb_info->var.vsync_len),
- host->base + LCDC_VDCTRL3);
-
- vdctrl4 = SET_DOTCLK_H_VALID_DATA_CNT(fb_info->var.xres);
- if (mxsfb_is_v4(host))
- vdctrl4 |= VDCTRL4_SET_DOTCLK_DLY(host->dotclk_delay);
- writel(vdctrl4, host->base + LCDC_VDCTRL4);
-
- writel(fb_info->fix.smem_start +
- fb_info->fix.line_length * fb_info->var.yoffset,
- host->base + host->devdata->next_buf);
-
- mxsfb_disable_axi_clk(host);
-
- if (reenable)
- mxsfb_enable_controller(fb_info);
-
- return 0;
-}
-
-static int mxsfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp, struct fb_info *fb_info)
-{
- unsigned int val;
- int ret = -EINVAL;
-
- /*
- * If greyscale is true, then we convert the RGB value
- * to greyscale no matter what visual we are using.
- */
- if (fb_info->var.grayscale)
- red = green = blue = (19595 * red + 38470 * green +
- 7471 * blue) >> 16;
-
- switch (fb_info->fix.visual) {
- case FB_VISUAL_TRUECOLOR:
- /*
- * 12 or 16-bit True Colour. We encode the RGB value
- * according to the RGB bitfield information.
- */
- if (regno < 16) {
- u32 *pal = fb_info->pseudo_palette;
-
- val = chan_to_field(red, &fb_info->var.red);
- val |= chan_to_field(green, &fb_info->var.green);
- val |= chan_to_field(blue, &fb_info->var.blue);
-
- pal[regno] = val;
- ret = 0;
- }
- break;
-
- case FB_VISUAL_STATIC_PSEUDOCOLOR:
- case FB_VISUAL_PSEUDOCOLOR:
- break;
- }
-
- return ret;
-}
-
-static int mxsfb_blank(int blank, struct fb_info *fb_info)
-{
- struct mxsfb_info *host = fb_info->par;
-
- switch (blank) {
- case FB_BLANK_POWERDOWN:
- case FB_BLANK_VSYNC_SUSPEND:
- case FB_BLANK_HSYNC_SUSPEND:
- case FB_BLANK_NORMAL:
- if (host->enabled)
- mxsfb_disable_controller(fb_info);
- break;
-
- case FB_BLANK_UNBLANK:
- if (!host->enabled)
- mxsfb_enable_controller(fb_info);
- break;
- }
- return 0;
-}
-
-static int mxsfb_pan_display(struct fb_var_screeninfo *var,
- struct fb_info *fb_info)
-{
- struct mxsfb_info *host = fb_info->par;
- unsigned offset;
-
- if (var->xoffset != 0)
- return -EINVAL;
-
- offset = fb_info->fix.line_length * var->yoffset;
-
- mxsfb_enable_axi_clk(host);
-
- /* update on next VSYNC */
- writel(fb_info->fix.smem_start + offset,
- host->base + host->devdata->next_buf);
-
- mxsfb_disable_axi_clk(host);
-
- return 0;
-}
-
-static struct fb_ops mxsfb_ops = {
- .owner = THIS_MODULE,
- .fb_check_var = mxsfb_check_var,
- .fb_set_par = mxsfb_set_par,
- .fb_setcolreg = mxsfb_setcolreg,
- .fb_blank = mxsfb_blank,
- .fb_pan_display = mxsfb_pan_display,
- .fb_fillrect = cfb_fillrect,
- .fb_copyarea = cfb_copyarea,
- .fb_imageblit = cfb_imageblit,
-};
-
-static int mxsfb_restore_mode(struct fb_info *fb_info,
- struct fb_videomode *vmode)
-{
- struct mxsfb_info *host = fb_info->par;
- unsigned period;
- unsigned long pa, fbsize;
- int bits_per_pixel, ofs, ret = 0;
- u32 transfer_count, vdctrl0, vdctrl2, vdctrl3, vdctrl4, ctrl;
-
- mxsfb_enable_axi_clk(host);
-
- /* Only restore the mode when the controller is running */
- ctrl = readl(host->base + LCDC_CTRL);
- if (!(ctrl & CTRL_RUN)) {
- ret = -EINVAL;
- goto err;
- }
-
- vdctrl0 = readl(host->base + LCDC_VDCTRL0);
- vdctrl2 = readl(host->base + LCDC_VDCTRL2);
- vdctrl3 = readl(host->base + LCDC_VDCTRL3);
- vdctrl4 = readl(host->base + LCDC_VDCTRL4);
-
- transfer_count = readl(host->base + host->devdata->transfer_count);
-
- vmode->xres = TRANSFER_COUNT_GET_HCOUNT(transfer_count);
- vmode->yres = TRANSFER_COUNT_GET_VCOUNT(transfer_count);
-
- switch (CTRL_GET_WORD_LENGTH(ctrl)) {
- case 0:
- bits_per_pixel = 16;
- break;
- case 3:
- bits_per_pixel = 32;
- break;
- case 1:
- default:
- ret = -EINVAL;
- goto err;
- }
-
- fb_info->var.bits_per_pixel = bits_per_pixel;
-
- vmode->pixclock = KHZ2PICOS(clk_get_rate(host->clk) / 1000U);
- vmode->hsync_len = get_hsync_pulse_width(host, vdctrl2);
- vmode->left_margin = GET_HOR_WAIT_CNT(vdctrl3) - vmode->hsync_len;
- vmode->right_margin = VDCTRL2_GET_HSYNC_PERIOD(vdctrl2) -
- vmode->hsync_len - vmode->left_margin - vmode->xres;
- vmode->vsync_len = VDCTRL0_GET_VSYNC_PULSE_WIDTH(vdctrl0);
- period = readl(host->base + LCDC_VDCTRL1);
- vmode->upper_margin = GET_VERT_WAIT_CNT(vdctrl3) - vmode->vsync_len;
- vmode->lower_margin = period - vmode->vsync_len -
- vmode->upper_margin - vmode->yres;
-
- vmode->vmode = FB_VMODE_NONINTERLACED;
-
- vmode->sync = 0;
- if (vdctrl0 & VDCTRL0_HSYNC_ACT_HIGH)
- vmode->sync |= FB_SYNC_HOR_HIGH_ACT;
- if (vdctrl0 & VDCTRL0_VSYNC_ACT_HIGH)
- vmode->sync |= FB_SYNC_VERT_HIGH_ACT;
-
- pr_debug("Reconstructed video mode:\n");
- pr_debug("%dx%d, hsync: %u left: %u, right: %u, vsync: %u, upper: %u, lower: %u\n",
- vmode->xres, vmode->yres, vmode->hsync_len, vmode->left_margin,
- vmode->right_margin, vmode->vsync_len, vmode->upper_margin,
- vmode->lower_margin);
- pr_debug("pixclk: %ldkHz\n", PICOS2KHZ(vmode->pixclock));
-
- host->ld_intf_width = CTRL_GET_BUS_WIDTH(ctrl);
- host->dotclk_delay = VDCTRL4_GET_DOTCLK_DLY(vdctrl4);
-
- fb_info->fix.line_length = vmode->xres * (bits_per_pixel >> 3);
-
- pa = readl(host->base + host->devdata->cur_buf);
- fbsize = fb_info->fix.line_length * vmode->yres;
- if (pa < fb_info->fix.smem_start) {
- ret = -EINVAL;
- goto err;
- }
- if (pa + fbsize > fb_info->fix.smem_start + fb_info->fix.smem_len) {
- ret = -EINVAL;
- goto err;
- }
- ofs = pa - fb_info->fix.smem_start;
- if (ofs) {
- memmove(fb_info->screen_base, fb_info->screen_base + ofs, fbsize);
- writel(fb_info->fix.smem_start, host->base + host->devdata->next_buf);
- }
-
- fb_info->fix.ypanstep = 1;
-
- clk_prepare_enable(host->clk);
- host->enabled = 1;
-
-err:
- if (ret)
- mxsfb_disable_axi_clk(host);
-
- return ret;
-}
-
-static int mxsfb_init_fbinfo_dt(struct fb_info *fb_info,
- struct fb_videomode *vmode)
-{
- struct mxsfb_info *host = fb_info->par;
- struct fb_var_screeninfo *var = &fb_info->var;
- struct device *dev = &host->pdev->dev;
- struct device_node *np = host->pdev->dev.of_node;
- struct device_node *display_np;
- struct videomode vm;
- u32 width;
- int ret;
-
- display_np = of_parse_phandle(np, "display", 0);
- if (!display_np) {
- dev_err(dev, "failed to find display phandle\n");
- return -ENOENT;
- }
-
- ret = of_property_read_u32(display_np, "bus-width", &width);
- if (ret < 0) {
- dev_err(dev, "failed to get property bus-width\n");
- goto put_display_node;
- }
-
- switch (width) {
- case 8:
- host->ld_intf_width = STMLCDIF_8BIT;
- break;
- case 16:
- host->ld_intf_width = STMLCDIF_16BIT;
- break;
- case 18:
- host->ld_intf_width = STMLCDIF_18BIT;
- break;
- case 24:
- host->ld_intf_width = STMLCDIF_24BIT;
- break;
- default:
- dev_err(dev, "invalid bus-width value\n");
- ret = -EINVAL;
- goto put_display_node;
- }
-
- ret = of_property_read_u32(display_np, "bits-per-pixel",
- &var->bits_per_pixel);
- if (ret < 0) {
- dev_err(dev, "failed to get property bits-per-pixel\n");
- goto put_display_node;
- }
-
- ret = of_get_videomode(display_np, &vm, OF_USE_NATIVE_MODE);
- if (ret) {
- dev_err(dev, "failed to get videomode from DT\n");
- goto put_display_node;
- }
-
- ret = fb_videomode_from_videomode(&vm, vmode);
- if (ret < 0)
- goto put_display_node;
-
- if (vm.flags & DISPLAY_FLAGS_DE_HIGH)
- host->sync |= MXSFB_SYNC_DATA_ENABLE_HIGH_ACT;
-
- /*
- * The PIXDATA flags of the display_flags enum are controller
- * centric, e.g. NEGEDGE means drive data on negative edge.
- * However, the drivers flag is display centric: Sample the
- * data on negative (falling) edge. Therefore, check for the
- * POSEDGE flag:
- * drive on positive edge => sample on negative edge
- */
- if (vm.flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
- host->sync |= MXSFB_SYNC_DOTCLK_FALLING_ACT;
-
-put_display_node:
- of_node_put(display_np);
- return ret;
-}
-
-static int mxsfb_init_fbinfo(struct fb_info *fb_info,
- struct fb_videomode *vmode)
-{
- int ret;
- struct mxsfb_info *host = fb_info->par;
- struct device *dev = &host->pdev->dev;
- struct fb_var_screeninfo *var = &fb_info->var;
- dma_addr_t fb_phys;
- void *fb_virt;
- unsigned fb_size;
-
- fb_info->fbops = &mxsfb_ops;
- fb_info->flags = FBINFO_FLAG_DEFAULT | FBINFO_READS_FAST;
- strlcpy(fb_info->fix.id, "mxs", sizeof(fb_info->fix.id));
- fb_info->fix.type = FB_TYPE_PACKED_PIXELS;
- fb_info->fix.ypanstep = 1;
- fb_info->fix.visual = FB_VISUAL_TRUECOLOR,
- fb_info->fix.accel = FB_ACCEL_NONE;
-
- ret = mxsfb_init_fbinfo_dt(fb_info, vmode);
- if (ret)
- return ret;
-
- var->nonstd = 0;
- var->activate = FB_ACTIVATE_NOW;
- var->accel_flags = 0;
- var->vmode = FB_VMODE_NONINTERLACED;
-
- /* Memory allocation for framebuffer */
- fb_size = SZ_2M;
- fb_virt = dma_alloc_wc(dev, PAGE_ALIGN(fb_size), &fb_phys, GFP_KERNEL);
- if (!fb_virt)
- return -ENOMEM;
-
- fb_info->fix.smem_start = fb_phys;
- fb_info->screen_base = fb_virt;
- fb_info->screen_size = fb_info->fix.smem_len = fb_size;
-
- if (mxsfb_restore_mode(fb_info, vmode))
- memset(fb_virt, 0, fb_size);
-
- return 0;
-}
-
-static void mxsfb_free_videomem(struct fb_info *fb_info)
-{
- struct mxsfb_info *host = fb_info->par;
- struct device *dev = &host->pdev->dev;
-
- dma_free_wc(dev, fb_info->screen_size, fb_info->screen_base,
- fb_info->fix.smem_start);
-}
-
-static const struct platform_device_id mxsfb_devtype[] = {
- {
- .name = "imx23-fb",
- .driver_data = MXSFB_V3,
- }, {
- .name = "imx28-fb",
- .driver_data = MXSFB_V4,
- }, {
- /* sentinel */
- }
-};
-MODULE_DEVICE_TABLE(platform, mxsfb_devtype);
-
-static const struct of_device_id mxsfb_dt_ids[] = {
- { .compatible = "fsl,imx23-lcdif", .data = &mxsfb_devtype[0], },
- { .compatible = "fsl,imx28-lcdif", .data = &mxsfb_devtype[1], },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, mxsfb_dt_ids);
-
-static int mxsfb_probe(struct platform_device *pdev)
-{
- const struct of_device_id *of_id =
- of_match_device(mxsfb_dt_ids, &pdev->dev);
- struct resource *res;
- struct mxsfb_info *host;
- struct fb_info *fb_info;
- struct fb_videomode *mode;
- int ret;
-
- if (of_id)
- pdev->id_entry = of_id->data;
-
- fb_info = framebuffer_alloc(sizeof(struct mxsfb_info), &pdev->dev);
- if (!fb_info) {
- dev_err(&pdev->dev, "Failed to allocate fbdev\n");
- return -ENOMEM;
- }
-
- mode = devm_kzalloc(&pdev->dev, sizeof(struct fb_videomode),
- GFP_KERNEL);
- if (mode == NULL)
- return -ENOMEM;
-
- host = fb_info->par;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- host->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(host->base)) {
- ret = PTR_ERR(host->base);
- goto fb_release;
- }
-
- host->pdev = pdev;
- platform_set_drvdata(pdev, host);
-
- host->devdata = &mxsfb_devdata[pdev->id_entry->driver_data];
-
- host->clk = devm_clk_get(&host->pdev->dev, NULL);
- if (IS_ERR(host->clk)) {
- ret = PTR_ERR(host->clk);
- goto fb_release;
- }
-
- host->clk_axi = devm_clk_get(&host->pdev->dev, "axi");
- if (IS_ERR(host->clk_axi))
- host->clk_axi = NULL;
-
- host->clk_disp_axi = devm_clk_get(&host->pdev->dev, "disp_axi");
- if (IS_ERR(host->clk_disp_axi))
- host->clk_disp_axi = NULL;
-
- host->reg_lcd = devm_regulator_get(&pdev->dev, "lcd");
- if (IS_ERR(host->reg_lcd))
- host->reg_lcd = NULL;
-
-#if defined(CONFIG_FB_PRE_INIT_FB)
- host->pre_init = 1;
-#endif
-
- fb_info->pseudo_palette = devm_kcalloc(&pdev->dev, 16, sizeof(u32),
- GFP_KERNEL);
- if (!fb_info->pseudo_palette) {
- ret = -ENOMEM;
- goto fb_release;
- }
-
- ret = mxsfb_init_fbinfo(fb_info, mode);
- if (ret != 0)
- goto fb_release;
-
- fb_videomode_to_var(&fb_info->var, mode);
-
- /* init the color fields */
- mxsfb_check_var(&fb_info->var, fb_info);
-
- platform_set_drvdata(pdev, fb_info);
-
- ret = register_framebuffer(fb_info);
- if (ret != 0) {
- dev_err(&pdev->dev,"Failed to register framebuffer\n");
- goto fb_destroy;
- }
-
- if (!host->enabled) {
- mxsfb_enable_axi_clk(host);
- writel(0, host->base + LCDC_CTRL);
- mxsfb_disable_axi_clk(host);
- mxsfb_set_par(fb_info);
- mxsfb_enable_controller(fb_info);
- }
-
- host->pre_init = 0;
- dev_info(&pdev->dev, "initialized\n");
-
- return 0;
-
-fb_destroy:
- if (host->enabled)
- clk_disable_unprepare(host->clk);
-fb_release:
- framebuffer_release(fb_info);
-
- return ret;
-}
-
-static int mxsfb_remove(struct platform_device *pdev)
-{
- struct fb_info *fb_info = platform_get_drvdata(pdev);
- struct mxsfb_info *host = fb_info->par;
-
- if (host->enabled)
- mxsfb_disable_controller(fb_info);
-
- unregister_framebuffer(fb_info);
- mxsfb_free_videomem(fb_info);
-
- framebuffer_release(fb_info);
-
- return 0;
-}
-
-static void mxsfb_shutdown(struct platform_device *pdev)
-{
- struct fb_info *fb_info = platform_get_drvdata(pdev);
- struct mxsfb_info *host = fb_info->par;
-
- mxsfb_enable_axi_clk(host);
-
- /*
- * Force stop the LCD controller as keeping it running during reboot
- * might interfere with the BootROM's boot mode pads sampling.
- */
- writel(CTRL_RUN, host->base + LCDC_CTRL + REG_CLR);
-
- mxsfb_disable_axi_clk(host);
-}
-
-static struct platform_driver mxsfb_driver = {
- .probe = mxsfb_probe,
- .remove = mxsfb_remove,
- .shutdown = mxsfb_shutdown,
- .id_table = mxsfb_devtype,
- .driver = {
- .name = DRIVER_NAME,
- .of_match_table = mxsfb_dt_ids,
- },
-};
-
-module_platform_driver(mxsfb_driver);
-
-MODULE_DESCRIPTION("Freescale mxs framebuffer driver");
-MODULE_AUTHOR("Sascha Hauer, Pengutronix");
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/nvidia/nv_backlight.c b/drivers/video/fbdev/nvidia/nv_backlight.c
index 5c151b2ea683..e705a7872301 100644
--- a/drivers/video/fbdev/nvidia/nv_backlight.c
+++ b/drivers/video/fbdev/nvidia/nv_backlight.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Backlight code for nVidia based graphic cards
*
* Copyright 2004 Antonino Daplas <adaplas@pol.net>
* Copyright (c) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
- *
- * 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.
*/
#include <linux/backlight.h>
diff --git a/drivers/video/fbdev/omap/omapfb_main.c b/drivers/video/fbdev/omap/omapfb_main.c
index 406f972d2e42..90eca64e3144 100644
--- a/drivers/video/fbdev/omap/omapfb_main.c
+++ b/drivers/video/fbdev/omap/omapfb_main.c
@@ -1502,8 +1502,6 @@ static int planes_init(struct omapfb_device *fbdev)
fbi = framebuffer_alloc(sizeof(struct omapfb_plane_struct),
fbdev->dev);
if (fbi == NULL) {
- dev_err(fbdev->dev,
- "unable to allocate memory for plane info\n");
planes_cleanup(fbdev);
return -ENOMEM;
}
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/connector-analog-tv.c b/drivers/video/fbdev/omap2/omapfb/displays/connector-analog-tv.c
index 9d78411a3bf7..63bd13ba429e 100644
--- a/drivers/video/fbdev/omap2/omapfb/displays/connector-analog-tv.c
+++ b/drivers/video/fbdev/omap2/omapfb/displays/connector-analog-tv.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Analog TV Connector driver
*
* Copyright (C) 2013 Texas Instruments
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
- *
- * 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.
*/
#include <linux/slab.h>
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c b/drivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c
index 06e1db34541e..b4a1aefff766 100644
--- a/drivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c
+++ b/drivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic DVI Connector driver
*
* Copyright (C) 2013 Texas Instruments
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
- *
- * 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.
*/
#include <linux/i2c.h>
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/connector-hdmi.c b/drivers/video/fbdev/omap2/omapfb/displays/connector-hdmi.c
index 58d5803ede67..49551afbdbe0 100644
--- a/drivers/video/fbdev/omap2/omapfb/displays/connector-hdmi.c
+++ b/drivers/video/fbdev/omap2/omapfb/displays/connector-hdmi.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* HDMI Connector driver
*
* Copyright (C) 2013 Texas Instruments
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
- *
- * 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.
*/
#include <linux/slab.h>
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/encoder-opa362.c b/drivers/video/fbdev/omap2/omapfb/displays/encoder-opa362.c
index a9a67167cc3d..ba7ed4039f8a 100644
--- a/drivers/video/fbdev/omap2/omapfb/displays/encoder-opa362.c
+++ b/drivers/video/fbdev/omap2/omapfb/displays/encoder-opa362.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* OPA362 analog video amplifier with output/power control
*
@@ -8,10 +9,6 @@
*
* Copyright (C) 2013 Texas Instruments
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
- *
- * 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.
*/
#include <linux/gpio.h>
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/encoder-tfp410.c b/drivers/video/fbdev/omap2/omapfb/displays/encoder-tfp410.c
index 8c0953d069b7..09a59bd93d61 100644
--- a/drivers/video/fbdev/omap2/omapfb/displays/encoder-tfp410.c
+++ b/drivers/video/fbdev/omap2/omapfb/displays/encoder-tfp410.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TFP410 DPI-to-DVI encoder driver
*
* Copyright (C) 2013 Texas Instruments
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
- *
- * 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.
*/
#include <linux/gpio.h>
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c b/drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c
index 47f0459e3551..67f0c9250e9e 100644
--- a/drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c
+++ b/drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TPD12S015 HDMI ESD protection & level shifter chip driver
*
* Copyright (C) 2013 Texas Instruments
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
- *
- * 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.
*/
#include <linux/completion.h>
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-dpi.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-dpi.c
index ace3d818afe5..37c9f5bfaefe 100644
--- a/drivers/video/fbdev/omap2/omapfb/displays/panel-dpi.c
+++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-dpi.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic MIPI DPI Panel Driver
*
* Copyright (C) 2013 Texas Instruments
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
- *
- * 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.
*/
#include <linux/gpio.h>
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c
index 87497a00241f..4b0793abdd84 100644
--- a/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c
+++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic DSI Command Mode panel driver
*
* Copyright (C) 2013 Texas Instruments
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
- *
- * 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.
*/
/* #define DEBUG */
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-lgphilips-lb035q02.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-lgphilips-lb035q02.c
index 6cd759c01037..0f93a260e432 100644
--- a/drivers/video/fbdev/omap2/omapfb/displays/panel-lgphilips-lb035q02.c
+++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-lgphilips-lb035q02.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LG.Philips LB035Q02 LCD Panel driver
*
* Copyright (C) 2013 Texas Instruments
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
* Based on a driver by: Steve Sakoman <steve@sakoman.com>
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-sharp-ls037v7dw01.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-sharp-ls037v7dw01.c
index a8be18a87fa0..a3912fc8031f 100644
--- a/drivers/video/fbdev/omap2/omapfb/displays/panel-sharp-ls037v7dw01.c
+++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-sharp-ls037v7dw01.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LCD panel driver for Sharp LS037V7DW01
*
* Copyright (C) 2013 Texas Instruments
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c
index f2c2fef3db74..1293515e4b16 100644
--- a/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c
+++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Sony ACX565AKM LCD Panel driver
*
@@ -6,18 +7,6 @@
* Original Driver Author: Imre Deak <imre.deak@nokia.com>
* Based on panel-generic.c by Tomi Valkeinen <tomi.valkeinen@nokia.com>
* Adapted to new DSS2 framework: Roger Quadros <roger.quadros@nokia.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td028ttec1.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td028ttec1.c
index f6da8755b859..595ebd8bd5dc 100644
--- a/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td028ttec1.c
+++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td028ttec1.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Toppoly TD028TTEC1 panel support
*
@@ -10,18 +11,6 @@
*
* Ported and adapted from Neo 1973 U-Boot by:
* H. Nikolaus Schaller <hns@goldelico.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/Kconfig b/drivers/video/fbdev/omap2/omapfb/dss/Kconfig
index a34820e8ab97..36b97fee2d57 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/Kconfig
+++ b/drivers/video/fbdev/omap2/omapfb/dss/Kconfig
@@ -39,18 +39,6 @@ config FB_OMAP2_DSS_DPI
help
DPI Interface. This is the Parallel Display Interface.
-config FB_OMAP2_DSS_RFBI
- bool "RFBI support"
- depends on BROKEN
- help
- MIPI DBI support (RFBI, Remote Framebuffer Interface, in Texas
- Instrument's terminology).
-
- DBI is a bus between the host processor and a peripheral,
- such as a display or a framebuffer chip.
-
- See http://www.mipi.org/ for DBI specifications.
-
config FB_OMAP2_DSS_VENC
bool "VENC support"
default y
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/Makefile b/drivers/video/fbdev/omap2/omapfb/dss/Makefile
index 7318d5260e8d..eb3689ae8d87 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/Makefile
+++ b/drivers/video/fbdev/omap2/omapfb/dss/Makefile
@@ -8,7 +8,6 @@ omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \
omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \
dispc-compat.o display-sysfs.o
omapdss-$(CONFIG_FB_OMAP2_DSS_DPI) += dpi.o
-omapdss-$(CONFIG_FB_OMAP2_DSS_RFBI) += rfbi.o
omapdss-$(CONFIG_FB_OMAP2_DSS_VENC) += venc.o
omapdss-$(CONFIG_FB_OMAP2_DSS_SDI) += sdi.o
omapdss-$(CONFIG_FB_OMAP2_DSS_DSI) += dsi.o
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/apply.c b/drivers/video/fbdev/omap2/omapfb/dss/apply.c
index 2481f4871f66..c71021091828 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/apply.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/apply.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Texas Instruments
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "APPLY"
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/core.c b/drivers/video/fbdev/omap2/omapfb/dss/core.c
index b5956a1a30d4..37858be8be83 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/core.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/video/omap2/dss/core.c
*
@@ -6,18 +7,6 @@
*
* Some code and ideas taken from drivers/video/omap/ driver
* by Imre Deak.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "CORE"
@@ -218,9 +207,6 @@ static int (*dss_output_drv_reg_funcs[])(void) __initdata = {
#ifdef CONFIG_FB_OMAP2_DSS_SDI
sdi_init_platform_driver,
#endif
-#ifdef CONFIG_FB_OMAP2_DSS_RFBI
- rfbi_init_platform_driver,
-#endif
#ifdef CONFIG_FB_OMAP2_DSS_VENC
venc_init_platform_driver,
#endif
@@ -242,9 +228,6 @@ static void (*dss_output_drv_unreg_funcs[])(void) = {
#ifdef CONFIG_FB_OMAP2_DSS_VENC
venc_uninit_platform_driver,
#endif
-#ifdef CONFIG_FB_OMAP2_DSS_RFBI
- rfbi_uninit_platform_driver,
-#endif
#ifdef CONFIG_FB_OMAP2_DSS_SDI
sdi_uninit_platform_driver,
#endif
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dispc-compat.c b/drivers/video/fbdev/omap2/omapfb/dss/dispc-compat.c
index a864608c5df1..3417618310ff 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/dispc-compat.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/dispc-compat.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Texas Instruments
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "APPLY"
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dispc-compat.h b/drivers/video/fbdev/omap2/omapfb/dss/dispc-compat.h
index 14a69b3d4fb0..f51fe1a4a305 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/dispc-compat.h
+++ b/drivers/video/fbdev/omap2/omapfb/dss/dispc-compat.h
@@ -1,18 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2012 Texas Instruments
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __OMAP2_DSS_DISPC_COMPAT_H
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dispc.c b/drivers/video/fbdev/omap2/omapfb/dss/dispc.c
index a06d9c25765c..376ee5bc3ddc 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/dispc.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/dispc.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/video/omap2/dss/dispc.c
*
@@ -6,18 +7,6 @@
*
* Some code and ideas taken from drivers/video/omap/ driver
* by Imre Deak.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "DISPC"
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dispc.h b/drivers/video/fbdev/omap2/omapfb/dss/dispc.h
index e014d0419c58..65bba5420db7 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/dispc.h
+++ b/drivers/video/fbdev/omap2/omapfb/dss/dispc.h
@@ -1,21 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/drivers/video/omap2/dss/dispc.h
*
* Copyright (C) 2011 Texas Instruments
* Author: Archit Taneja <archit@ti.com>
- *
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __OMAP2_DISPC_REG_H
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dispc_coefs.c b/drivers/video/fbdev/omap2/omapfb/dss/dispc_coefs.c
index 59c9a5c47ca9..2c85ec9733b1 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/dispc_coefs.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/dispc_coefs.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/video/omap2/dss/dispc_coefs.c
*
* Copyright (C) 2011 Texas Instruments
* Author: Chandrabhanu Mahapatra <cmahapatra@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/display-sysfs.c b/drivers/video/fbdev/omap2/omapfb/dss/display-sysfs.c
index b3fdbfd0b82d..6dbe265b312d 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/display-sysfs.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/display-sysfs.c
@@ -1,21 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2009 Nokia Corporation
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
*
* Some code and ideas taken from drivers/video/omap/ driver
* by Imre Deak.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "DISPLAY"
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/display.c b/drivers/video/fbdev/omap2/omapfb/dss/display.c
index dd5468695c43..f91db94c9905 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/display.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/display.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/video/omap2/dss/display.c
*
@@ -6,18 +7,6 @@
*
* Some code and ideas taken from drivers/video/omap/ driver
* by Imre Deak.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "DISPLAY"
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dpi.c b/drivers/video/fbdev/omap2/omapfb/dss/dpi.c
index da09806b940c..e2e7fe6f89ee 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/dpi.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/dpi.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/video/omap2/dss/dpi.c
*
@@ -6,18 +7,6 @@
*
* Some code and ideas taken from drivers/video/omap/ driver
* by Imre Deak.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "DPI"
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dsi.c b/drivers/video/fbdev/omap2/omapfb/dss/dsi.c
index 8e1d60d48dbb..d620376216e1 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/dsi.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/dsi.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/video/omap2/dss/dsi.c
*
* Copyright (C) 2009 Nokia Corporation
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "DSI"
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dss.c b/drivers/video/fbdev/omap2/omapfb/dss/dss.c
index f0cac9e0eb94..7252d22dd117 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/dss.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/dss.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/video/omap2/dss/dss.c
*
@@ -6,18 +7,6 @@
*
* Some code and ideas taken from drivers/video/omap/ driver
* by Imre Deak.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "DSS"
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dss.h b/drivers/video/fbdev/omap2/omapfb/dss/dss.h
index b1a354494144..a2269008590f 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/dss.h
+++ b/drivers/video/fbdev/omap2/omapfb/dss/dss.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/drivers/video/omap2/dss/dss.h
*
@@ -6,18 +7,6 @@
*
* Some code and ideas taken from drivers/video/omap/ driver
* by Imre Deak.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __OMAP2_DSS_H
@@ -472,10 +461,6 @@ void hdmi4_uninit_platform_driver(void);
int hdmi5_init_platform_driver(void) __init;
void hdmi5_uninit_platform_driver(void);
-/* RFBI */
-int rfbi_init_platform_driver(void) __init;
-void rfbi_uninit_platform_driver(void);
-
#ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
static inline void dss_collect_irq_stats(u32 irqstatus, unsigned *irq_arr)
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dss_features.c b/drivers/video/fbdev/omap2/omapfb/dss/dss_features.c
index e8d428bc47e3..62c2d48d9e09 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/dss_features.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/dss_features.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/video/omap2/dss/dss_features.c
*
* Copyright (C) 2010 Texas Instruments
* Author: Archit Taneja <archit@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dss_features.h b/drivers/video/fbdev/omap2/omapfb/dss/dss_features.h
index 3d67d39f192f..6d66d6270c9d 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/dss_features.h
+++ b/drivers/video/fbdev/omap2/omapfb/dss/dss_features.h
@@ -1,20 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/drivers/video/omap2/dss/dss_features.h
*
* Copyright (C) 2010 Texas Instruments
* Author: Archit Taneja <archit@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __OMAP2_DSS_FEATURES_H
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi.h b/drivers/video/fbdev/omap2/omapfb/dss/hdmi.h
index f6de87e078b0..b9d4480ecfad 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/hdmi.h
+++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi.h
@@ -1,19 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* HDMI driver definition for TI OMAP4 Processor.
*
* Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _HDMI_H
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi4.c b/drivers/video/fbdev/omap2/omapfb/dss/hdmi4.c
index 28de56e21c74..7060ae56c062 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/hdmi4.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi4.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* HDMI interface DSS driver for TI's OMAP4 family of SoCs.
* Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
* Authors: Yong Zhi
* Mythri pk <mythripk@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "HDMI"
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi4_core.c b/drivers/video/fbdev/omap2/omapfb/dss/hdmi4_core.c
index d146793dd044..6b79b52d5fad 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/hdmi4_core.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi4_core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ti_hdmi_4xxx_ip.c
*
@@ -5,18 +6,6 @@
* Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
* Authors: Yong Zhi
* Mythri pk <mythripk@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "HDMICORE"
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi4_core.h b/drivers/video/fbdev/omap2/omapfb/dss/hdmi4_core.h
index a069f96ec6f6..f066d1f69132 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/hdmi4_core.h
+++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi4_core.h
@@ -1,19 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* HDMI header definition for OMAP4 HDMI core IP
*
* Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _HDMI4_CORE_H_
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi5.c b/drivers/video/fbdev/omap2/omapfb/dss/hdmi5.c
index 2e2fcc3d6d4f..ac49531e4732 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/hdmi5.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi5.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* HDMI driver for OMAP5
*
@@ -8,18 +9,6 @@
* Mythri pk
* Archit Taneja <archit@ti.com>
* Tomi Valkeinen <tomi.valkeinen@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "HDMI"
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi5_core.c b/drivers/video/fbdev/omap2/omapfb/dss/hdmi5_core.c
index bbfe7e2d4332..2f6ff14a48d9 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/hdmi5_core.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi5_core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* OMAP5 HDMI CORE IP driver library
*
@@ -8,18 +9,6 @@
* Mythri pk
* Archit Taneja <archit@ti.com>
* Tomi Valkeinen <tomi.valkeinen@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi5_core.h b/drivers/video/fbdev/omap2/omapfb/dss/hdmi5_core.h
index f2f1022c5516..f10b8a283011 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/hdmi5_core.h
+++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi5_core.h
@@ -1,19 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* HDMI driver definition for TI OMAP5 processors.
*
* Copyright (C) 2011-2012 Texas Instruments Incorporated - http://www.ti.com/
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _HDMI5_CORE_H_
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi_phy.c b/drivers/video/fbdev/omap2/omapfb/dss/hdmi_phy.c
index 11dbc05d5720..9c645adba9e2 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/hdmi_phy.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi_phy.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* HDMI PHY
*
* Copyright (C) 2013 Texas Instruments Incorporated
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi_pll.c b/drivers/video/fbdev/omap2/omapfb/dss/hdmi_pll.c
index bc591fc12aef..4991be031b0b 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/hdmi_pll.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi_pll.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* HDMI PLL
*
* Copyright (C) 2013 Texas Instruments Incorporated
- *
- * 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.
*/
#define DSS_SUBSYS_NAME "HDMIPLL"
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/hdmi_wp.c b/drivers/video/fbdev/omap2/omapfb/dss/hdmi_wp.c
index 4af6ba220744..41ad52b9d013 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/hdmi_wp.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/hdmi_wp.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* HDMI wrapper
*
* Copyright (C) 2013 Texas Instruments Incorporated
- *
- * 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.
*/
#define DSS_SUBSYS_NAME "HDMIWP"
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/manager-sysfs.c b/drivers/video/fbdev/omap2/omapfb/dss/manager-sysfs.c
index 44b96af4ef4e..b52cc1af0959 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/manager-sysfs.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/manager-sysfs.c
@@ -1,21 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2009 Nokia Corporation
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
*
* Some code and ideas taken from drivers/video/omap/ driver
* by Imre Deak.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "MANAGER"
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/manager.c b/drivers/video/fbdev/omap2/omapfb/dss/manager.c
index d21c641e1f3c..2c2da35345d0 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/manager.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/manager.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/video/omap2/dss/manager.c
*
@@ -6,18 +7,6 @@
*
* Some code and ideas taken from drivers/video/omap/ driver
* by Imre Deak.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "MANAGER"
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/omapdss-boot-init.c b/drivers/video/fbdev/omap2/omapfb/dss/omapdss-boot-init.c
index 5da7ed6d653e..0ae0cab252d3 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/omapdss-boot-init.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/omapdss-boot-init.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 Texas Instruments
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/output.c b/drivers/video/fbdev/omap2/omapfb/dss/output.c
index bed9a978269d..4e2992a0ce50 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/output.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/output.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Texas Instruments Ltd
* Author: Archit Taneja <archit@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/overlay-sysfs.c b/drivers/video/fbdev/omap2/omapfb/dss/overlay-sysfs.c
index f1f6c0aea752..36acf366213a 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/overlay-sysfs.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/overlay-sysfs.c
@@ -1,21 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2009 Nokia Corporation
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
*
* Some code and ideas taken from drivers/video/omap/ driver
* by Imre Deak.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "OVERLAY"
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/overlay.c b/drivers/video/fbdev/omap2/omapfb/dss/overlay.c
index be17a4785a5e..8c8e627da13d 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/overlay.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/overlay.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/video/omap2/dss/overlay.c
*
@@ -6,18 +7,6 @@
*
* Some code and ideas taken from drivers/video/omap/ driver
* by Imre Deak.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "OVERLAY"
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/pll.c b/drivers/video/fbdev/omap2/omapfb/dss/pll.c
index 0564c5606cd0..725194d52445 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/pll.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/pll.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 Texas Instruments Incorporated
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "PLL"
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/rfbi.c b/drivers/video/fbdev/omap2/omapfb/dss/rfbi.c
deleted file mode 100644
index 562b0c4ae0c6..000000000000
--- a/drivers/video/fbdev/omap2/omapfb/dss/rfbi.c
+++ /dev/null
@@ -1,1078 +0,0 @@
-/*
- * linux/drivers/video/omap2/dss/rfbi.c
- *
- * Copyright (C) 2009 Nokia Corporation
- * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
- *
- * Some code and ideas taken from drivers/video/omap/ driver
- * by Imre Deak.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#define DSS_SUBSYS_NAME "RFBI"
-
-#include <linux/kernel.h>
-#include <linux/dma-mapping.h>
-#include <linux/export.h>
-#include <linux/vmalloc.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/kfifo.h>
-#include <linux/ktime.h>
-#include <linux/hrtimer.h>
-#include <linux/seq_file.h>
-#include <linux/semaphore.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
-#include <linux/component.h>
-
-#include <video/omapfb_dss.h>
-#include "dss.h"
-
-struct rfbi_reg { u16 idx; };
-
-#define RFBI_REG(idx) ((const struct rfbi_reg) { idx })
-
-#define RFBI_REVISION RFBI_REG(0x0000)
-#define RFBI_SYSCONFIG RFBI_REG(0x0010)
-#define RFBI_SYSSTATUS RFBI_REG(0x0014)
-#define RFBI_CONTROL RFBI_REG(0x0040)
-#define RFBI_PIXEL_CNT RFBI_REG(0x0044)
-#define RFBI_LINE_NUMBER RFBI_REG(0x0048)
-#define RFBI_CMD RFBI_REG(0x004c)
-#define RFBI_PARAM RFBI_REG(0x0050)
-#define RFBI_DATA RFBI_REG(0x0054)
-#define RFBI_READ RFBI_REG(0x0058)
-#define RFBI_STATUS RFBI_REG(0x005c)
-
-#define RFBI_CONFIG(n) RFBI_REG(0x0060 + (n)*0x18)
-#define RFBI_ONOFF_TIME(n) RFBI_REG(0x0064 + (n)*0x18)
-#define RFBI_CYCLE_TIME(n) RFBI_REG(0x0068 + (n)*0x18)
-#define RFBI_DATA_CYCLE1(n) RFBI_REG(0x006c + (n)*0x18)
-#define RFBI_DATA_CYCLE2(n) RFBI_REG(0x0070 + (n)*0x18)
-#define RFBI_DATA_CYCLE3(n) RFBI_REG(0x0074 + (n)*0x18)
-
-#define RFBI_VSYNC_WIDTH RFBI_REG(0x0090)
-#define RFBI_HSYNC_WIDTH RFBI_REG(0x0094)
-
-#define REG_FLD_MOD(idx, val, start, end) \
- rfbi_write_reg(idx, FLD_MOD(rfbi_read_reg(idx), val, start, end))
-
-enum omap_rfbi_cycleformat {
- OMAP_DSS_RFBI_CYCLEFORMAT_1_1 = 0,
- OMAP_DSS_RFBI_CYCLEFORMAT_2_1 = 1,
- OMAP_DSS_RFBI_CYCLEFORMAT_3_1 = 2,
- OMAP_DSS_RFBI_CYCLEFORMAT_3_2 = 3,
-};
-
-enum omap_rfbi_datatype {
- OMAP_DSS_RFBI_DATATYPE_12 = 0,
- OMAP_DSS_RFBI_DATATYPE_16 = 1,
- OMAP_DSS_RFBI_DATATYPE_18 = 2,
- OMAP_DSS_RFBI_DATATYPE_24 = 3,
-};
-
-enum omap_rfbi_parallelmode {
- OMAP_DSS_RFBI_PARALLELMODE_8 = 0,
- OMAP_DSS_RFBI_PARALLELMODE_9 = 1,
- OMAP_DSS_RFBI_PARALLELMODE_12 = 2,
- OMAP_DSS_RFBI_PARALLELMODE_16 = 3,
-};
-
-static int rfbi_convert_timings(struct rfbi_timings *t);
-static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div);
-
-static struct {
- struct platform_device *pdev;
- void __iomem *base;
-
- unsigned long l4_khz;
-
- enum omap_rfbi_datatype datatype;
- enum omap_rfbi_parallelmode parallelmode;
-
- enum omap_rfbi_te_mode te_mode;
- int te_enabled;
-
- void (*framedone_callback)(void *data);
- void *framedone_callback_data;
-
- struct omap_dss_device *dssdev[2];
-
- struct semaphore bus_lock;
-
- struct omap_video_timings timings;
- int pixel_size;
- int data_lines;
- struct rfbi_timings intf_timings;
-
- struct omap_dss_device output;
-} rfbi;
-
-static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val)
-{
- __raw_writel(val, rfbi.base + idx.idx);
-}
-
-static inline u32 rfbi_read_reg(const struct rfbi_reg idx)
-{
- return __raw_readl(rfbi.base + idx.idx);
-}
-
-static int rfbi_runtime_get(void)
-{
- int r;
-
- DSSDBG("rfbi_runtime_get\n");
-
- r = pm_runtime_get_sync(&rfbi.pdev->dev);
- WARN_ON(r < 0);
- return r < 0 ? r : 0;
-}
-
-static void rfbi_runtime_put(void)
-{
- int r;
-
- DSSDBG("rfbi_runtime_put\n");
-
- r = pm_runtime_put_sync(&rfbi.pdev->dev);
- WARN_ON(r < 0 && r != -ENOSYS);
-}
-
-static void rfbi_bus_lock(void)
-{
- down(&rfbi.bus_lock);
-}
-
-static void rfbi_bus_unlock(void)
-{
- up(&rfbi.bus_lock);
-}
-
-static void rfbi_write_command(const void *buf, u32 len)
-{
- switch (rfbi.parallelmode) {
- case OMAP_DSS_RFBI_PARALLELMODE_8:
- {
- const u8 *b = buf;
- for (; len; len--)
- rfbi_write_reg(RFBI_CMD, *b++);
- break;
- }
-
- case OMAP_DSS_RFBI_PARALLELMODE_16:
- {
- const u16 *w = buf;
- BUG_ON(len & 1);
- for (; len; len -= 2)
- rfbi_write_reg(RFBI_CMD, *w++);
- break;
- }
-
- case OMAP_DSS_RFBI_PARALLELMODE_9:
- case OMAP_DSS_RFBI_PARALLELMODE_12:
- default:
- BUG();
- }
-}
-
-static void rfbi_read_data(void *buf, u32 len)
-{
- switch (rfbi.parallelmode) {
- case OMAP_DSS_RFBI_PARALLELMODE_8:
- {
- u8 *b = buf;
- for (; len; len--) {
- rfbi_write_reg(RFBI_READ, 0);
- *b++ = rfbi_read_reg(RFBI_READ);
- }
- break;
- }
-
- case OMAP_DSS_RFBI_PARALLELMODE_16:
- {
- u16 *w = buf;
- BUG_ON(len & ~1);
- for (; len; len -= 2) {
- rfbi_write_reg(RFBI_READ, 0);
- *w++ = rfbi_read_reg(RFBI_READ);
- }
- break;
- }
-
- case OMAP_DSS_RFBI_PARALLELMODE_9:
- case OMAP_DSS_RFBI_PARALLELMODE_12:
- default:
- BUG();
- }
-}
-
-static void rfbi_write_data(const void *buf, u32 len)
-{
- switch (rfbi.parallelmode) {
- case OMAP_DSS_RFBI_PARALLELMODE_8:
- {
- const u8 *b = buf;
- for (; len; len--)
- rfbi_write_reg(RFBI_PARAM, *b++);
- break;
- }
-
- case OMAP_DSS_RFBI_PARALLELMODE_16:
- {
- const u16 *w = buf;
- BUG_ON(len & 1);
- for (; len; len -= 2)
- rfbi_write_reg(RFBI_PARAM, *w++);
- break;
- }
-
- case OMAP_DSS_RFBI_PARALLELMODE_9:
- case OMAP_DSS_RFBI_PARALLELMODE_12:
- default:
- BUG();
-
- }
-}
-
-static void rfbi_write_pixels(const void __iomem *buf, int scr_width,
- u16 x, u16 y,
- u16 w, u16 h)
-{
- int start_offset = scr_width * y + x;
- int horiz_offset = scr_width - w;
- int i;
-
- if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_16 &&
- rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_8) {
- const u16 __iomem *pd = buf;
- pd += start_offset;
-
- for (; h; --h) {
- for (i = 0; i < w; ++i) {
- const u8 __iomem *b = (const u8 __iomem *)pd;
- rfbi_write_reg(RFBI_PARAM, __raw_readb(b+1));
- rfbi_write_reg(RFBI_PARAM, __raw_readb(b+0));
- ++pd;
- }
- pd += horiz_offset;
- }
- } else if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_24 &&
- rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_8) {
- const u32 __iomem *pd = buf;
- pd += start_offset;
-
- for (; h; --h) {
- for (i = 0; i < w; ++i) {
- const u8 __iomem *b = (const u8 __iomem *)pd;
- rfbi_write_reg(RFBI_PARAM, __raw_readb(b+2));
- rfbi_write_reg(RFBI_PARAM, __raw_readb(b+1));
- rfbi_write_reg(RFBI_PARAM, __raw_readb(b+0));
- ++pd;
- }
- pd += horiz_offset;
- }
- } else if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_16 &&
- rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_16) {
- const u16 __iomem *pd = buf;
- pd += start_offset;
-
- for (; h; --h) {
- for (i = 0; i < w; ++i) {
- rfbi_write_reg(RFBI_PARAM, __raw_readw(pd));
- ++pd;
- }
- pd += horiz_offset;
- }
- } else {
- BUG();
- }
-}
-
-static int rfbi_transfer_area(struct omap_dss_device *dssdev,
- void (*callback)(void *data), void *data)
-{
- u32 l;
- int r;
- struct omap_overlay_manager *mgr = rfbi.output.manager;
- u16 width = rfbi.timings.x_res;
- u16 height = rfbi.timings.y_res;
-
- /*BUG_ON(callback == 0);*/
- BUG_ON(rfbi.framedone_callback != NULL);
-
- DSSDBG("rfbi_transfer_area %dx%d\n", width, height);
-
- dss_mgr_set_timings(mgr, &rfbi.timings);
-
- r = dss_mgr_enable(mgr);
- if (r)
- return r;
-
- rfbi.framedone_callback = callback;
- rfbi.framedone_callback_data = data;
-
- rfbi_write_reg(RFBI_PIXEL_CNT, width * height);
-
- l = rfbi_read_reg(RFBI_CONTROL);
- l = FLD_MOD(l, 1, 0, 0); /* enable */
- if (!rfbi.te_enabled)
- l = FLD_MOD(l, 1, 4, 4); /* ITE */
-
- rfbi_write_reg(RFBI_CONTROL, l);
-
- return 0;
-}
-
-static void framedone_callback(void *data)
-{
- void (*callback)(void *data);
-
- DSSDBG("FRAMEDONE\n");
-
- REG_FLD_MOD(RFBI_CONTROL, 0, 0, 0);
-
- callback = rfbi.framedone_callback;
- rfbi.framedone_callback = NULL;
-
- if (callback != NULL)
- callback(rfbi.framedone_callback_data);
-}
-
-#if 1 /* VERBOSE */
-static void rfbi_print_timings(void)
-{
- u32 l;
- u32 time;
-
- l = rfbi_read_reg(RFBI_CONFIG(0));
- time = 1000000000 / rfbi.l4_khz;
- if (l & (1 << 4))
- time *= 2;
-
- DSSDBG("Tick time %u ps\n", time);
- l = rfbi_read_reg(RFBI_ONOFF_TIME(0));
- DSSDBG("CSONTIME %d, CSOFFTIME %d, WEONTIME %d, WEOFFTIME %d, "
- "REONTIME %d, REOFFTIME %d\n",
- l & 0x0f, (l >> 4) & 0x3f, (l >> 10) & 0x0f, (l >> 14) & 0x3f,
- (l >> 20) & 0x0f, (l >> 24) & 0x3f);
-
- l = rfbi_read_reg(RFBI_CYCLE_TIME(0));
- DSSDBG("WECYCLETIME %d, RECYCLETIME %d, CSPULSEWIDTH %d, "
- "ACCESSTIME %d\n",
- (l & 0x3f), (l >> 6) & 0x3f, (l >> 12) & 0x3f,
- (l >> 22) & 0x3f);
-}
-#else
-static void rfbi_print_timings(void) {}
-#endif
-
-
-
-
-static u32 extif_clk_period;
-
-static inline unsigned long round_to_extif_ticks(unsigned long ps, int div)
-{
- int bus_tick = extif_clk_period * div;
- return (ps + bus_tick - 1) / bus_tick * bus_tick;
-}
-
-static int calc_reg_timing(struct rfbi_timings *t, int div)
-{
- t->clk_div = div;
-
- t->cs_on_time = round_to_extif_ticks(t->cs_on_time, div);
-
- t->we_on_time = round_to_extif_ticks(t->we_on_time, div);
- t->we_off_time = round_to_extif_ticks(t->we_off_time, div);
- t->we_cycle_time = round_to_extif_ticks(t->we_cycle_time, div);
-
- t->re_on_time = round_to_extif_ticks(t->re_on_time, div);
- t->re_off_time = round_to_extif_ticks(t->re_off_time, div);
- t->re_cycle_time = round_to_extif_ticks(t->re_cycle_time, div);
-
- t->access_time = round_to_extif_ticks(t->access_time, div);
- t->cs_off_time = round_to_extif_ticks(t->cs_off_time, div);
- t->cs_pulse_width = round_to_extif_ticks(t->cs_pulse_width, div);
-
- DSSDBG("[reg]cson %d csoff %d reon %d reoff %d\n",
- t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time);
- DSSDBG("[reg]weon %d weoff %d recyc %d wecyc %d\n",
- t->we_on_time, t->we_off_time, t->re_cycle_time,
- t->we_cycle_time);
- DSSDBG("[reg]rdaccess %d cspulse %d\n",
- t->access_time, t->cs_pulse_width);
-
- return rfbi_convert_timings(t);
-}
-
-static int calc_extif_timings(struct rfbi_timings *t)
-{
- u32 max_clk_div;
- int div;
-
- rfbi_get_clk_info(&extif_clk_period, &max_clk_div);
- for (div = 1; div <= max_clk_div; div++) {
- if (calc_reg_timing(t, div) == 0)
- break;
- }
-
- if (div <= max_clk_div)
- return 0;
-
- DSSERR("can't setup timings\n");
- return -1;
-}
-
-
-static void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t)
-{
- int r;
-
- if (!t->converted) {
- r = calc_extif_timings(t);
- if (r < 0)
- DSSERR("Failed to calc timings\n");
- }
-
- BUG_ON(!t->converted);
-
- rfbi_write_reg(RFBI_ONOFF_TIME(rfbi_module), t->tim[0]);
- rfbi_write_reg(RFBI_CYCLE_TIME(rfbi_module), t->tim[1]);
-
- /* TIMEGRANULARITY */
- REG_FLD_MOD(RFBI_CONFIG(rfbi_module),
- (t->tim[2] ? 1 : 0), 4, 4);
-
- rfbi_print_timings();
-}
-
-static int ps_to_rfbi_ticks(int time, int div)
-{
- unsigned long tick_ps;
- int ret;
-
- /* Calculate in picosecs to yield more exact results */
- tick_ps = 1000000000 / (rfbi.l4_khz) * div;
-
- ret = (time + tick_ps - 1) / tick_ps;
-
- return ret;
-}
-
-static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div)
-{
- *clk_period = 1000000000 / rfbi.l4_khz;
- *max_clk_div = 2;
-}
-
-static int rfbi_convert_timings(struct rfbi_timings *t)
-{
- u32 l;
- int reon, reoff, weon, weoff, cson, csoff, cs_pulse;
- int actim, recyc, wecyc;
- int div = t->clk_div;
-
- if (div <= 0 || div > 2)
- return -1;
-
- /* Make sure that after conversion it still holds that:
- * weoff > weon, reoff > reon, recyc >= reoff, wecyc >= weoff,
- * csoff > cson, csoff >= max(weoff, reoff), actim > reon
- */
- weon = ps_to_rfbi_ticks(t->we_on_time, div);
- weoff = ps_to_rfbi_ticks(t->we_off_time, div);
- if (weoff <= weon)
- weoff = weon + 1;
- if (weon > 0x0f)
- return -1;
- if (weoff > 0x3f)
- return -1;
-
- reon = ps_to_rfbi_ticks(t->re_on_time, div);
- reoff = ps_to_rfbi_ticks(t->re_off_time, div);
- if (reoff <= reon)
- reoff = reon + 1;
- if (reon > 0x0f)
- return -1;
- if (reoff > 0x3f)
- return -1;
-
- cson = ps_to_rfbi_ticks(t->cs_on_time, div);
- csoff = ps_to_rfbi_ticks(t->cs_off_time, div);
- if (csoff <= cson)
- csoff = cson + 1;
- if (csoff < max(weoff, reoff))
- csoff = max(weoff, reoff);
- if (cson > 0x0f)
- return -1;
- if (csoff > 0x3f)
- return -1;
-
- l = cson;
- l |= csoff << 4;
- l |= weon << 10;
- l |= weoff << 14;
- l |= reon << 20;
- l |= reoff << 24;
-
- t->tim[0] = l;
-
- actim = ps_to_rfbi_ticks(t->access_time, div);
- if (actim <= reon)
- actim = reon + 1;
- if (actim > 0x3f)
- return -1;
-
- wecyc = ps_to_rfbi_ticks(t->we_cycle_time, div);
- if (wecyc < weoff)
- wecyc = weoff;
- if (wecyc > 0x3f)
- return -1;
-
- recyc = ps_to_rfbi_ticks(t->re_cycle_time, div);
- if (recyc < reoff)
- recyc = reoff;
- if (recyc > 0x3f)
- return -1;
-
- cs_pulse = ps_to_rfbi_ticks(t->cs_pulse_width, div);
- if (cs_pulse > 0x3f)
- return -1;
-
- l = wecyc;
- l |= recyc << 6;
- l |= cs_pulse << 12;
- l |= actim << 22;
-
- t->tim[1] = l;
-
- t->tim[2] = div - 1;
-
- t->converted = 1;
-
- return 0;
-}
-
-/* xxx FIX module selection missing */
-static int rfbi_setup_te(enum omap_rfbi_te_mode mode,
- unsigned hs_pulse_time, unsigned vs_pulse_time,
- int hs_pol_inv, int vs_pol_inv, int extif_div)
-{
- int hs, vs;
- int min;
- u32 l;
-
- hs = ps_to_rfbi_ticks(hs_pulse_time, 1);
- vs = ps_to_rfbi_ticks(vs_pulse_time, 1);
- if (hs < 2)
- return -EDOM;
- if (mode == OMAP_DSS_RFBI_TE_MODE_2)
- min = 2;
- else /* OMAP_DSS_RFBI_TE_MODE_1 */
- min = 4;
- if (vs < min)
- return -EDOM;
- if (vs == hs)
- return -EINVAL;
- rfbi.te_mode = mode;
- DSSDBG("setup_te: mode %d hs %d vs %d hs_inv %d vs_inv %d\n",
- mode, hs, vs, hs_pol_inv, vs_pol_inv);
-
- rfbi_write_reg(RFBI_HSYNC_WIDTH, hs);
- rfbi_write_reg(RFBI_VSYNC_WIDTH, vs);
-
- l = rfbi_read_reg(RFBI_CONFIG(0));
- if (hs_pol_inv)
- l &= ~(1 << 21);
- else
- l |= 1 << 21;
- if (vs_pol_inv)
- l &= ~(1 << 20);
- else
- l |= 1 << 20;
-
- return 0;
-}
-
-/* xxx FIX module selection missing */
-static int rfbi_enable_te(bool enable, unsigned line)
-{
- u32 l;
-
- DSSDBG("te %d line %d mode %d\n", enable, line, rfbi.te_mode);
- if (line > (1 << 11) - 1)
- return -EINVAL;
-
- l = rfbi_read_reg(RFBI_CONFIG(0));
- l &= ~(0x3 << 2);
- if (enable) {
- rfbi.te_enabled = 1;
- l |= rfbi.te_mode << 2;
- } else
- rfbi.te_enabled = 0;
- rfbi_write_reg(RFBI_CONFIG(0), l);
- rfbi_write_reg(RFBI_LINE_NUMBER, line);
-
- return 0;
-}
-
-static int rfbi_configure_bus(int rfbi_module, int bpp, int lines)
-{
- u32 l;
- int cycle1 = 0, cycle2 = 0, cycle3 = 0;
- enum omap_rfbi_cycleformat cycleformat;
- enum omap_rfbi_datatype datatype;
- enum omap_rfbi_parallelmode parallelmode;
-
- switch (bpp) {
- case 12:
- datatype = OMAP_DSS_RFBI_DATATYPE_12;
- break;
- case 16:
- datatype = OMAP_DSS_RFBI_DATATYPE_16;
- break;
- case 18:
- datatype = OMAP_DSS_RFBI_DATATYPE_18;
- break;
- case 24:
- datatype = OMAP_DSS_RFBI_DATATYPE_24;
- break;
- default:
- BUG();
- return 1;
- }
- rfbi.datatype = datatype;
-
- switch (lines) {
- case 8:
- parallelmode = OMAP_DSS_RFBI_PARALLELMODE_8;
- break;
- case 9:
- parallelmode = OMAP_DSS_RFBI_PARALLELMODE_9;
- break;
- case 12:
- parallelmode = OMAP_DSS_RFBI_PARALLELMODE_12;
- break;
- case 16:
- parallelmode = OMAP_DSS_RFBI_PARALLELMODE_16;
- break;
- default:
- BUG();
- return 1;
- }
- rfbi.parallelmode = parallelmode;
-
- if ((bpp % lines) == 0) {
- switch (bpp / lines) {
- case 1:
- cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_1_1;
- break;
- case 2:
- cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_2_1;
- break;
- case 3:
- cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_3_1;
- break;
- default:
- BUG();
- return 1;
- }
- } else if ((2 * bpp % lines) == 0) {
- if ((2 * bpp / lines) == 3)
- cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_3_2;
- else {
- BUG();
- return 1;
- }
- } else {
- BUG();
- return 1;
- }
-
- switch (cycleformat) {
- case OMAP_DSS_RFBI_CYCLEFORMAT_1_1:
- cycle1 = lines;
- break;
-
- case OMAP_DSS_RFBI_CYCLEFORMAT_2_1:
- cycle1 = lines;
- cycle2 = lines;
- break;
-
- case OMAP_DSS_RFBI_CYCLEFORMAT_3_1:
- cycle1 = lines;
- cycle2 = lines;
- cycle3 = lines;
- break;
-
- case OMAP_DSS_RFBI_CYCLEFORMAT_3_2:
- cycle1 = lines;
- cycle2 = (lines / 2) | ((lines / 2) << 16);
- cycle3 = (lines << 16);
- break;
- }
-
- REG_FLD_MOD(RFBI_CONTROL, 0, 3, 2); /* clear CS */
-
- l = 0;
- l |= FLD_VAL(parallelmode, 1, 0);
- l |= FLD_VAL(0, 3, 2); /* TRIGGERMODE: ITE */
- l |= FLD_VAL(0, 4, 4); /* TIMEGRANULARITY */
- l |= FLD_VAL(datatype, 6, 5);
- /* l |= FLD_VAL(2, 8, 7); */ /* L4FORMAT, 2pix/L4 */
- l |= FLD_VAL(0, 8, 7); /* L4FORMAT, 1pix/L4 */
- l |= FLD_VAL(cycleformat, 10, 9);
- l |= FLD_VAL(0, 12, 11); /* UNUSEDBITS */
- l |= FLD_VAL(0, 16, 16); /* A0POLARITY */
- l |= FLD_VAL(0, 17, 17); /* REPOLARITY */
- l |= FLD_VAL(0, 18, 18); /* WEPOLARITY */
- l |= FLD_VAL(0, 19, 19); /* CSPOLARITY */
- l |= FLD_VAL(1, 20, 20); /* TE_VSYNC_POLARITY */
- l |= FLD_VAL(1, 21, 21); /* HSYNCPOLARITY */
- rfbi_write_reg(RFBI_CONFIG(rfbi_module), l);
-
- rfbi_write_reg(RFBI_DATA_CYCLE1(rfbi_module), cycle1);
- rfbi_write_reg(RFBI_DATA_CYCLE2(rfbi_module), cycle2);
- rfbi_write_reg(RFBI_DATA_CYCLE3(rfbi_module), cycle3);
-
-
- l = rfbi_read_reg(RFBI_CONTROL);
- l = FLD_MOD(l, rfbi_module+1, 3, 2); /* Select CSx */
- l = FLD_MOD(l, 0, 1, 1); /* clear bypass */
- rfbi_write_reg(RFBI_CONTROL, l);
-
-
- DSSDBG("RFBI config: bpp %d, lines %d, cycles: 0x%x 0x%x 0x%x\n",
- bpp, lines, cycle1, cycle2, cycle3);
-
- return 0;
-}
-
-static int rfbi_configure(struct omap_dss_device *dssdev)
-{
- return rfbi_configure_bus(dssdev->phy.rfbi.channel, rfbi.pixel_size,
- rfbi.data_lines);
-}
-
-static int rfbi_update(struct omap_dss_device *dssdev, void (*callback)(void *),
- void *data)
-{
- return rfbi_transfer_area(dssdev, callback, data);
-}
-
-static void rfbi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h)
-{
- rfbi.timings.x_res = w;
- rfbi.timings.y_res = h;
-}
-
-static void rfbi_set_pixel_size(struct omap_dss_device *dssdev, int pixel_size)
-{
- rfbi.pixel_size = pixel_size;
-}
-
-static void rfbi_set_data_lines(struct omap_dss_device *dssdev, int data_lines)
-{
- rfbi.data_lines = data_lines;
-}
-
-static void rfbi_set_interface_timings(struct omap_dss_device *dssdev,
- struct rfbi_timings *timings)
-{
- rfbi.intf_timings = *timings;
-}
-
-static void rfbi_dump_regs(struct seq_file *s)
-{
-#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, rfbi_read_reg(r))
-
- if (rfbi_runtime_get())
- return;
-
- DUMPREG(RFBI_REVISION);
- DUMPREG(RFBI_SYSCONFIG);
- DUMPREG(RFBI_SYSSTATUS);
- DUMPREG(RFBI_CONTROL);
- DUMPREG(RFBI_PIXEL_CNT);
- DUMPREG(RFBI_LINE_NUMBER);
- DUMPREG(RFBI_CMD);
- DUMPREG(RFBI_PARAM);
- DUMPREG(RFBI_DATA);
- DUMPREG(RFBI_READ);
- DUMPREG(RFBI_STATUS);
-
- DUMPREG(RFBI_CONFIG(0));
- DUMPREG(RFBI_ONOFF_TIME(0));
- DUMPREG(RFBI_CYCLE_TIME(0));
- DUMPREG(RFBI_DATA_CYCLE1(0));
- DUMPREG(RFBI_DATA_CYCLE2(0));
- DUMPREG(RFBI_DATA_CYCLE3(0));
-
- DUMPREG(RFBI_CONFIG(1));
- DUMPREG(RFBI_ONOFF_TIME(1));
- DUMPREG(RFBI_CYCLE_TIME(1));
- DUMPREG(RFBI_DATA_CYCLE1(1));
- DUMPREG(RFBI_DATA_CYCLE2(1));
- DUMPREG(RFBI_DATA_CYCLE3(1));
-
- DUMPREG(RFBI_VSYNC_WIDTH);
- DUMPREG(RFBI_HSYNC_WIDTH);
-
- rfbi_runtime_put();
-#undef DUMPREG
-}
-
-static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev)
-{
- struct omap_overlay_manager *mgr = rfbi.output.manager;
- struct dss_lcd_mgr_config mgr_config;
-
- mgr_config.io_pad_mode = DSS_IO_PAD_MODE_RFBI;
-
- mgr_config.stallmode = true;
- /* Do we need fifohandcheck for RFBI? */
- mgr_config.fifohandcheck = false;
-
- mgr_config.video_port_width = rfbi.pixel_size;
- mgr_config.lcden_sig_polarity = 0;
-
- dss_mgr_set_lcd_config(mgr, &mgr_config);
-
- /*
- * Set rfbi.timings with default values, the x_res and y_res fields
- * are expected to be already configured by the panel driver via
- * omapdss_rfbi_set_size()
- */
- rfbi.timings.hsw = 1;
- rfbi.timings.hfp = 1;
- rfbi.timings.hbp = 1;
- rfbi.timings.vsw = 1;
- rfbi.timings.vfp = 0;
- rfbi.timings.vbp = 0;
-
- rfbi.timings.interlace = false;
- rfbi.timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
- rfbi.timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
- rfbi.timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
- rfbi.timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH;
- rfbi.timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE;
-
- dss_mgr_set_timings(mgr, &rfbi.timings);
-}
-
-static int rfbi_display_enable(struct omap_dss_device *dssdev)
-{
- struct omap_dss_device *out = &rfbi.output;
- int r;
-
- if (out->manager == NULL) {
- DSSERR("failed to enable display: no output/manager\n");
- return -ENODEV;
- }
-
- r = rfbi_runtime_get();
- if (r)
- return r;
-
- r = dss_mgr_register_framedone_handler(out->manager,
- framedone_callback, NULL);
- if (r) {
- DSSERR("can't get FRAMEDONE irq\n");
- goto err1;
- }
-
- rfbi_config_lcd_manager(dssdev);
-
- rfbi_configure_bus(dssdev->phy.rfbi.channel, rfbi.pixel_size,
- rfbi.data_lines);
-
- rfbi_set_timings(dssdev->phy.rfbi.channel, &rfbi.intf_timings);
-
- return 0;
-err1:
- rfbi_runtime_put();
- return r;
-}
-
-static void rfbi_display_disable(struct omap_dss_device *dssdev)
-{
- struct omap_dss_device *out = &rfbi.output;
-
- dss_mgr_unregister_framedone_handler(out->manager,
- framedone_callback, NULL);
-
- rfbi_runtime_put();
-}
-
-static int rfbi_init_display(struct omap_dss_device *dssdev)
-{
- rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev;
- return 0;
-}
-
-static void rfbi_init_output(struct platform_device *pdev)
-{
- struct omap_dss_device *out = &rfbi.output;
-
- out->dev = &pdev->dev;
- out->id = OMAP_DSS_OUTPUT_DBI;
- out->output_type = OMAP_DISPLAY_TYPE_DBI;
- out->name = "rfbi.0";
- out->dispc_channel = OMAP_DSS_CHANNEL_LCD;
- out->owner = THIS_MODULE;
-
- omapdss_register_output(out);
-}
-
-static void rfbi_uninit_output(struct platform_device *pdev)
-{
- struct omap_dss_device *out = &rfbi.output;
-
- omapdss_unregister_output(out);
-}
-
-/* RFBI HW IP initialisation */
-static int rfbi_bind(struct device *dev, struct device *master, void *data)
-{
- struct platform_device *pdev = to_platform_device(dev);
- u32 rev;
- struct resource *rfbi_mem;
- struct clk *clk;
- int r;
-
- rfbi.pdev = pdev;
-
- sema_init(&rfbi.bus_lock, 1);
-
- rfbi_mem = platform_get_resource(rfbi.pdev, IORESOURCE_MEM, 0);
- if (!rfbi_mem) {
- DSSERR("can't get IORESOURCE_MEM RFBI\n");
- return -EINVAL;
- }
-
- rfbi.base = devm_ioremap(&pdev->dev, rfbi_mem->start,
- resource_size(rfbi_mem));
- if (!rfbi.base) {
- DSSERR("can't ioremap RFBI\n");
- return -ENOMEM;
- }
-
- clk = clk_get(&pdev->dev, "ick");
- if (IS_ERR(clk)) {
- DSSERR("can't get ick\n");
- return PTR_ERR(clk);
- }
-
- rfbi.l4_khz = clk_get_rate(clk) / 1000;
-
- clk_put(clk);
-
- pm_runtime_enable(&pdev->dev);
-
- r = rfbi_runtime_get();
- if (r)
- goto err_runtime_get;
-
- msleep(10);
-
- rev = rfbi_read_reg(RFBI_REVISION);
- dev_dbg(&pdev->dev, "OMAP RFBI rev %d.%d\n",
- FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
-
- rfbi_runtime_put();
-
- dss_debugfs_create_file("rfbi", rfbi_dump_regs);
-
- rfbi_init_output(pdev);
-
- return 0;
-
-err_runtime_get:
- pm_runtime_disable(&pdev->dev);
- return r;
-}
-
-static void rfbi_unbind(struct device *dev, struct device *master, void *data)
-{
- struct platform_device *pdev = to_platform_device(dev);
-
- rfbi_uninit_output(pdev);
-
- pm_runtime_disable(&pdev->dev);
-
- return 0;
-}
-
-static const struct component_ops rfbi_component_ops = {
- .bind = rfbi_bind,
- .unbind = rfbi_unbind,
-};
-
-static int rfbi_probe(struct platform_device *pdev)
-{
- return component_add(&pdev->dev, &rfbi_component_ops);
-}
-
-static int rfbi_remove(struct platform_device *pdev)
-{
- component_del(&pdev->dev, &rfbi_component_ops);
- return 0;
-}
-
-static int rfbi_runtime_suspend(struct device *dev)
-{
- dispc_runtime_put();
-
- return 0;
-}
-
-static int rfbi_runtime_resume(struct device *dev)
-{
- int r;
-
- r = dispc_runtime_get();
- if (r < 0)
- return r;
-
- return 0;
-}
-
-static const struct dev_pm_ops rfbi_pm_ops = {
- .runtime_suspend = rfbi_runtime_suspend,
- .runtime_resume = rfbi_runtime_resume,
-};
-
-static struct platform_driver omap_rfbihw_driver = {
- .probe = rfbi_probe,
- .remove = rfbi_remove,
- .driver = {
- .name = "omapdss_rfbi",
- .pm = &rfbi_pm_ops,
- .suppress_bind_attrs = true,
- },
-};
-
-int __init rfbi_init_platform_driver(void)
-{
- return platform_driver_register(&omap_rfbihw_driver);
-}
-
-void rfbi_uninit_platform_driver(void)
-{
- platform_driver_unregister(&omap_rfbihw_driver);
-}
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/sdi.c b/drivers/video/fbdev/omap2/omapfb/dss/sdi.c
index c4be732a4714..002f07f5480f 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/sdi.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/sdi.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/video/omap2/dss/sdi.c
*
* Copyright (C) 2009 Nokia Corporation
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "SDI"
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/venc.c b/drivers/video/fbdev/omap2/omapfb/dss/venc.c
index 392464da12e4..f81e2a46366d 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/venc.c
+++ b/drivers/video/fbdev/omap2/omapfb/dss/venc.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/video/omap2/dss/venc.c
*
@@ -5,18 +6,6 @@
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
*
* VENC settings from TI's DSS driver
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "VENC"
diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c b/drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c
index 8e23160ec59f..56995f44e76d 100644
--- a/drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c
+++ b/drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/video/omap2/omapfb-ioctl.c
*
@@ -6,18 +7,6 @@
*
* Some code and ideas taken from drivers/video/omap/ driver
* by Imre Deak.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/fb.h>
diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c
index b8b5b4ac0e09..858c2c011d19 100644
--- a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/video/omap2/omapfb-main.c
*
@@ -6,18 +7,6 @@
*
* Some code and ideas taken from drivers/video/omap/ driver
* by Imre Deak.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
@@ -1892,12 +1881,8 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
fbi = framebuffer_alloc(sizeof(struct omapfb_info),
fbdev->dev);
-
- if (fbi == NULL) {
- dev_err(fbdev->dev,
- "unable to allocate memory for plane info\n");
+ if (!fbi)
return -ENOMEM;
- }
clear_fb_info(fbi);
diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c b/drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c
index bd0d20283372..4a5db170ef59 100644
--- a/drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c
+++ b/drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/video/omap2/omapfb-sysfs.c
*
@@ -6,18 +7,6 @@
*
* Some code and ideas taken from drivers/video/omap/ driver
* by Imre Deak.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/fb.h>
diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb.h b/drivers/video/fbdev/omap2/omapfb/omapfb.h
index 555487d6dbea..d27abccb37bc 100644
--- a/drivers/video/fbdev/omap2/omapfb/omapfb.h
+++ b/drivers/video/fbdev/omap2/omapfb/omapfb.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/drivers/video/omap2/omapfb.h
*
@@ -6,18 +7,6 @@
*
* Some code and ideas taken from drivers/video/omap/ driver
* by Imre Deak.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __DRIVERS_VIDEO_OMAP2_OMAPFB_H__
diff --git a/drivers/video/fbdev/platinumfb.c b/drivers/video/fbdev/platinumfb.c
index 76f299375a00..632b246ca35f 100644
--- a/drivers/video/fbdev/platinumfb.c
+++ b/drivers/video/fbdev/platinumfb.c
@@ -538,10 +538,9 @@ static int platinumfb_probe(struct platform_device* odev)
dev_info(&odev->dev, "Found Apple Platinum video hardware\n");
info = framebuffer_alloc(sizeof(*pinfo), &odev->dev);
- if (info == NULL) {
- dev_err(&odev->dev, "Failed to allocate fbdev !\n");
+ if (!info)
return -ENOMEM;
- }
+
pinfo = info->par;
if (of_address_to_resource(dp, 0, &pinfo->rsrc_reg) ||
diff --git a/drivers/video/fbdev/pmag-aa-fb.c b/drivers/video/fbdev/pmag-aa-fb.c
index ca7e9390d1e7..d1e78ce3a9c2 100644
--- a/drivers/video/fbdev/pmag-aa-fb.c
+++ b/drivers/video/fbdev/pmag-aa-fb.c
@@ -165,10 +165,8 @@ static int pmagaafb_probe(struct device *dev)
int err;
info = framebuffer_alloc(sizeof(struct aafb_par), dev);
- if (!info) {
- printk(KERN_ERR "%s: Cannot allocate memory\n", dev_name(dev));
+ if (!info)
return -ENOMEM;
- }
par = info->par;
dev_set_drvdata(dev, info);
diff --git a/drivers/video/fbdev/pmag-ba-fb.c b/drivers/video/fbdev/pmag-ba-fb.c
index 3b9249449ea6..56b912bb28de 100644
--- a/drivers/video/fbdev/pmag-ba-fb.c
+++ b/drivers/video/fbdev/pmag-ba-fb.c
@@ -150,10 +150,8 @@ static int pmagbafb_probe(struct device *dev)
int err;
info = framebuffer_alloc(sizeof(struct pmagbafb_par), dev);
- if (!info) {
- printk(KERN_ERR "%s: Cannot allocate memory\n", dev_name(dev));
+ if (!info)
return -ENOMEM;
- }
par = info->par;
dev_set_drvdata(dev, info);
diff --git a/drivers/video/fbdev/pmagb-b-fb.c b/drivers/video/fbdev/pmagb-b-fb.c
index e58df36233c4..2822b2225924 100644
--- a/drivers/video/fbdev/pmagb-b-fb.c
+++ b/drivers/video/fbdev/pmagb-b-fb.c
@@ -257,10 +257,8 @@ static int pmagbbfb_probe(struct device *dev)
int err;
info = framebuffer_alloc(sizeof(struct pmagbbfb_par), dev);
- if (!info) {
- printk(KERN_ERR "%s: Cannot allocate memory\n", dev_name(dev));
+ if (!info)
return -ENOMEM;
- }
par = info->par;
dev_set_drvdata(dev, info);
diff --git a/drivers/video/fbdev/pvr2fb.c b/drivers/video/fbdev/pvr2fb.c
index 73d92d8a85cc..7ff4b6b84282 100644
--- a/drivers/video/fbdev/pvr2fb.c
+++ b/drivers/video/fbdev/pvr2fb.c
@@ -140,7 +140,7 @@ static struct pvr2fb_par {
unsigned char is_doublescan; /* Are scanlines output twice? (doublescan) */
unsigned char is_lowres; /* Is horizontal pixel-doubling enabled? */
- unsigned long mmio_base; /* MMIO base */
+ void __iomem *mmio_base; /* MMIO base */
u32 palette[16];
} *currentpar;
@@ -194,39 +194,6 @@ static unsigned int shdma = PVR2_CASCADE_CHAN;
static unsigned int pvr2dma = ONCHIP_NR_DMA_CHANNELS;
#endif
-static int pvr2fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, unsigned int blue,
- unsigned int transp, struct fb_info *info);
-static int pvr2fb_blank(int blank, struct fb_info *info);
-static unsigned long get_line_length(int xres_virtual, int bpp);
-static void set_color_bitfields(struct fb_var_screeninfo *var);
-static int pvr2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info);
-static int pvr2fb_set_par(struct fb_info *info);
-static void pvr2_update_display(struct fb_info *info);
-static void pvr2_init_display(struct fb_info *info);
-static void pvr2_do_blank(void);
-static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id);
-static int pvr2_init_cable(void);
-static int pvr2_get_param(const struct pvr2_params *p, const char *s,
- int val, int size);
-#ifdef CONFIG_PVR2_DMA
-static ssize_t pvr2fb_write(struct fb_info *info, const char *buf,
- size_t count, loff_t *ppos);
-#endif
-
-static struct fb_ops pvr2fb_ops = {
- .owner = THIS_MODULE,
- .fb_setcolreg = pvr2fb_setcolreg,
- .fb_blank = pvr2fb_blank,
- .fb_check_var = pvr2fb_check_var,
- .fb_set_par = pvr2fb_set_par,
-#ifdef CONFIG_PVR2_DMA
- .fb_write = pvr2fb_write,
-#endif
- .fb_fillrect = cfb_fillrect,
- .fb_copyarea = cfb_copyarea,
- .fb_imageblit = cfb_imageblit,
-};
-
static struct fb_videomode pvr2_modedb[] = {
/*
* Broadcast video modes (PAL and NTSC). I'm unfamiliar with
@@ -354,6 +321,36 @@ static int pvr2fb_setcolreg(unsigned int regno, unsigned int red,
return 0;
}
+/*
+ * Determine the cable type and initialize the cable output format. Don't do
+ * anything if the cable type has been overidden (via "cable:XX").
+ */
+
+#define PCTRA ((void __iomem *)0xff80002c)
+#define PDTRA ((void __iomem *)0xff800030)
+#define VOUTC ((void __iomem *)0xa0702c00)
+
+static int pvr2_init_cable(void)
+{
+ if (cable_type < 0) {
+ fb_writel((fb_readl(PCTRA) & 0xfff0ffff) | 0x000a0000,
+ PCTRA);
+ cable_type = (fb_readw(PDTRA) >> 8) & 3;
+ }
+
+ /* Now select the output format (either composite or other) */
+ /* XXX: Save the previous val first, as this reg is also AICA
+ related */
+ if (cable_type == CT_COMPOSITE)
+ fb_writel(3 << 8, VOUTC);
+ else if (cable_type == CT_RGB)
+ fb_writel(1 << 9, VOUTC);
+ else
+ fb_writel(0, VOUTC);
+
+ return cable_type;
+}
+
static int pvr2fb_set_par(struct fb_info *info)
{
struct pvr2fb_par *par = (struct pvr2fb_par *)info->par;
@@ -623,7 +620,7 @@ static void pvr2_do_blank(void)
is_blanked = do_blank > 0 ? do_blank : 0;
}
-static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id)
+static irqreturn_t __maybe_unused pvr2fb_interrupt(int irq, void *dev_id)
{
struct fb_info *info = dev_id;
@@ -642,36 +639,6 @@ static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-/*
- * Determine the cable type and initialize the cable output format. Don't do
- * anything if the cable type has been overidden (via "cable:XX").
- */
-
-#define PCTRA 0xff80002c
-#define PDTRA 0xff800030
-#define VOUTC 0xa0702c00
-
-static int pvr2_init_cable(void)
-{
- if (cable_type < 0) {
- fb_writel((fb_readl(PCTRA) & 0xfff0ffff) | 0x000a0000,
- PCTRA);
- cable_type = (fb_readw(PDTRA) >> 8) & 3;
- }
-
- /* Now select the output format (either composite or other) */
- /* XXX: Save the previous val first, as this reg is also AICA
- related */
- if (cable_type == CT_COMPOSITE)
- fb_writel(3 << 8, VOUTC);
- else if (cable_type == CT_RGB)
- fb_writel(1 << 9, VOUTC);
- else
- fb_writel(0, VOUTC);
-
- return cable_type;
-}
-
#ifdef CONFIG_PVR2_DMA
static ssize_t pvr2fb_write(struct fb_info *info, const char *buf,
size_t count, loff_t *ppos)
@@ -742,6 +709,46 @@ out_unmap:
}
#endif /* CONFIG_PVR2_DMA */
+static struct fb_ops pvr2fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_setcolreg = pvr2fb_setcolreg,
+ .fb_blank = pvr2fb_blank,
+ .fb_check_var = pvr2fb_check_var,
+ .fb_set_par = pvr2fb_set_par,
+#ifdef CONFIG_PVR2_DMA
+ .fb_write = pvr2fb_write,
+#endif
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+};
+
+#ifndef MODULE
+static int pvr2_get_param_val(const struct pvr2_params *p, const char *s,
+ int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ if (!strncasecmp(p[i].name, s, strlen(s)))
+ return p[i].val;
+ }
+ return -1;
+}
+#endif
+
+static char *pvr2_get_param_name(const struct pvr2_params *p, int val,
+ int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ if (p[i].val == val)
+ return p[i].name;
+ }
+ return NULL;
+}
+
/**
* pvr2fb_common_init
*
@@ -760,7 +767,7 @@ out_unmap:
* in for flexibility anyways. Who knows, maybe someone has tv-out on a
* PCI-based version of these things ;-)
*/
-static int pvr2fb_common_init(void)
+static int __maybe_unused pvr2fb_common_init(void)
{
struct pvr2fb_par *par = currentpar;
unsigned long modememused, rev;
@@ -773,8 +780,8 @@ static int pvr2fb_common_init(void)
goto out_err;
}
- par->mmio_base = (unsigned long)ioremap_nocache(pvr2_fix.mmio_start,
- pvr2_fix.mmio_len);
+ par->mmio_base = ioremap_nocache(pvr2_fix.mmio_start,
+ pvr2_fix.mmio_len);
if (!par->mmio_base) {
printk(KERN_ERR "pvr2fb: Failed to remap mmio space\n");
goto out_err;
@@ -822,8 +829,8 @@ static int pvr2fb_common_init(void)
fb_info->var.xres, fb_info->var.yres,
fb_info->var.bits_per_pixel,
get_line_length(fb_info->var.xres, fb_info->var.bits_per_pixel),
- (char *)pvr2_get_param(cables, NULL, cable_type, 3),
- (char *)pvr2_get_param(outputs, NULL, video_output, 3));
+ pvr2_get_param_name(cables, cable_type, 3),
+ pvr2_get_param_name(outputs, video_output, 3));
#ifdef CONFIG_SH_STORE_QUEUES
fb_notice(fb_info, "registering with SQ API\n");
@@ -841,7 +848,7 @@ out_err:
if (fb_info->screen_base)
iounmap(fb_info->screen_base);
if (par->mmio_base)
- iounmap((void *)par->mmio_base);
+ iounmap(par->mmio_base);
return -ENXIO;
}
@@ -901,15 +908,15 @@ static int __init pvr2fb_dc_init(void)
return pvr2fb_common_init();
}
-static void __exit pvr2fb_dc_exit(void)
+static void pvr2fb_dc_exit(void)
{
if (fb_info->screen_base) {
iounmap(fb_info->screen_base);
fb_info->screen_base = NULL;
}
if (currentpar->mmio_base) {
- iounmap((void *)currentpar->mmio_base);
- currentpar->mmio_base = 0;
+ iounmap(currentpar->mmio_base);
+ currentpar->mmio_base = NULL;
}
free_irq(HW_EVENT_VSYNC, fb_info);
@@ -958,8 +965,8 @@ static void pvr2fb_pci_remove(struct pci_dev *pdev)
fb_info->screen_base = NULL;
}
if (currentpar->mmio_base) {
- iounmap((void *)currentpar->mmio_base);
- currentpar->mmio_base = 0;
+ iounmap(currentpar->mmio_base);
+ currentpar->mmio_base = NULL;
}
pci_release_regions(pdev);
@@ -985,29 +992,12 @@ static int __init pvr2fb_pci_init(void)
return pci_register_driver(&pvr2fb_pci_driver);
}
-static void __exit pvr2fb_pci_exit(void)
+static void pvr2fb_pci_exit(void)
{
pci_unregister_driver(&pvr2fb_pci_driver);
}
#endif /* CONFIG_PCI */
-static int pvr2_get_param(const struct pvr2_params *p, const char *s, int val,
- int size)
-{
- int i;
-
- for (i = 0 ; i < size ; i++ ) {
- if (s != NULL) {
- if (!strncasecmp(p[i].name, s, strlen(s)))
- return p[i].val;
- } else {
- if (p[i].val == val)
- return (int)p[i].name;
- }
- }
- return -1;
-}
-
/*
* Parse command arguments. Supported arguments are:
* inverse Use inverse color maps
@@ -1047,9 +1037,9 @@ static int __init pvr2fb_setup(char *options)
}
if (*cable_arg)
- cable_type = pvr2_get_param(cables, cable_arg, 0, 3);
+ cable_type = pvr2_get_param_val(cables, cable_arg, 3);
if (*output_arg)
- video_output = pvr2_get_param(outputs, output_arg, 0, 3);
+ video_output = pvr2_get_param_val(outputs, output_arg, 3);
return 0;
}
@@ -1082,12 +1072,8 @@ static int __init pvr2fb_init(void)
#endif
fb_info = framebuffer_alloc(sizeof(struct pvr2fb_par), NULL);
-
- if (!fb_info) {
- printk(KERN_ERR "Failed to allocate memory for fb_info\n");
+ if (!fb_info)
return -ENOMEM;
- }
-
currentpar = fb_info->par;
diff --git a/drivers/video/fbdev/pxafb.c b/drivers/video/fbdev/pxafb.c
index d59c8a59f582..4282cb117b92 100644
--- a/drivers/video/fbdev/pxafb.c
+++ b/drivers/video/fbdev/pxafb.c
@@ -2068,7 +2068,7 @@ static int __init pxafb_setup_options(void)
#define pxafb_setup_options() (0)
module_param_string(options, g_options, sizeof(g_options), 0);
-MODULE_PARM_DESC(options, "LCD parameters (see Documentation/fb/pxafb.txt)");
+MODULE_PARM_DESC(options, "LCD parameters (see Documentation/fb/pxafb.rst)");
#endif
#else
diff --git a/drivers/video/fbdev/riva/fbdev.c b/drivers/video/fbdev/riva/fbdev.c
index cc242ba057d3..ca593a3e41d7 100644
--- a/drivers/video/fbdev/riva/fbdev.c
+++ b/drivers/video/fbdev/riva/fbdev.c
@@ -1902,7 +1902,6 @@ static int rivafb_probe(struct pci_dev *pd, const struct pci_device_id *ent)
info = framebuffer_alloc(sizeof(struct riva_par), &pd->dev);
if (!info) {
- printk (KERN_ERR PFX "could not allocate memory\n");
ret = -ENOMEM;
goto err_ret;
}
diff --git a/drivers/video/fbdev/s3c-fb.c b/drivers/video/fbdev/s3c-fb.c
index 9ec85ccd0ce9..ba04d7a67829 100644
--- a/drivers/video/fbdev/s3c-fb.c
+++ b/drivers/video/fbdev/s3c-fb.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* linux/drivers/video/s3c-fb.c
*
* Copyright 2008 Openmoko Inc.
@@ -6,10 +7,6 @@
* http://armlinux.simtec.co.uk/
*
* Samsung SoC Framebuffer driver
- *
- * 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.
*/
#include <linux/kernel.h>
@@ -287,7 +284,7 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var,
/* 666 with one bit alpha/transparency */
var->transp.offset = 18;
var->transp.length = 1;
- /* drop through */
+ /* fall through */
case 18:
var->bits_per_pixel = 32;
@@ -315,7 +312,7 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var,
case 25:
var->transp.length = var->bits_per_pixel - 24;
var->transp.offset = 24;
- /* drop through */
+ /* fall through */
case 24:
/* our 24bpp is unpacked, so 32bpp */
var->bits_per_pixel = 32;
@@ -812,7 +809,7 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info)
case FB_BLANK_POWERDOWN:
wincon &= ~WINCONx_ENWIN;
sfb->enabled &= ~(1 << index);
- /* fall through to FB_BLANK_NORMAL */
+ /* fall through - to FB_BLANK_NORMAL */
case FB_BLANK_NORMAL:
/* disable the DMA and display 0x0 (black) */
@@ -1105,14 +1102,14 @@ static int s3c_fb_alloc_memory(struct s3c_fb *sfb, struct s3c_fb_win *win)
dev_dbg(sfb->dev, "want %u bytes for window\n", size);
- fbi->screen_base = dma_alloc_wc(sfb->dev, size, &map_dma, GFP_KERNEL);
- if (!fbi->screen_base)
+ fbi->screen_buffer = dma_alloc_wc(sfb->dev, size, &map_dma, GFP_KERNEL);
+ if (!fbi->screen_buffer)
return -ENOMEM;
dev_dbg(sfb->dev, "mapped %x to %p\n",
- (unsigned int)map_dma, fbi->screen_base);
+ (unsigned int)map_dma, fbi->screen_buffer);
- memset(fbi->screen_base, 0x0, size);
+ memset(fbi->screen_buffer, 0x0, size);
fbi->fix.smem_start = map_dma;
return 0;
@@ -1129,9 +1126,9 @@ static void s3c_fb_free_memory(struct s3c_fb *sfb, struct s3c_fb_win *win)
{
struct fb_info *fbi = win->fbinfo;
- if (fbi->screen_base)
+ if (fbi->screen_buffer)
dma_free_wc(sfb->dev, PAGE_ALIGN(fbi->fix.smem_len),
- fbi->screen_base, fbi->fix.smem_start);
+ fbi->screen_buffer, fbi->fix.smem_start);
}
/**
@@ -1189,10 +1186,8 @@ static int s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
fbinfo = framebuffer_alloc(sizeof(struct s3c_fb_win) +
palette_size * sizeof(u32), sfb->dev);
- if (!fbinfo) {
- dev_err(sfb->dev, "failed to allocate framebuffer\n");
- return -ENOENT;
- }
+ if (!fbinfo)
+ return -ENOMEM;
windata = sfb->pdata->win[win_no];
initmode = *sfb->pdata->vtiming;
diff --git a/drivers/video/fbdev/s3fb.c b/drivers/video/fbdev/s3fb.c
index d63f23e26f7d..be16c349c10f 100644
--- a/drivers/video/fbdev/s3fb.c
+++ b/drivers/video/fbdev/s3fb.c
@@ -1128,10 +1128,8 @@ static int s3_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
/* Allocate and fill driver data structure */
info = framebuffer_alloc(sizeof(struct s3fb_info), &(dev->dev));
- if (!info) {
- dev_err(&(dev->dev), "cannot allocate memory\n");
+ if (!info)
return -ENOMEM;
- }
par = info->par;
mutex_init(&par->open_lock);
diff --git a/drivers/video/fbdev/sh7760fb.c b/drivers/video/fbdev/sh7760fb.c
index 405715b60ec7..ab8fe838c776 100644
--- a/drivers/video/fbdev/sh7760fb.c
+++ b/drivers/video/fbdev/sh7760fb.c
@@ -6,7 +6,7 @@
* Manuel Lauss <mano@roarinelk.homelinux.net>
* (c) 2008 Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
*
- * PLEASE HAVE A LOOK AT Documentation/fb/sh7760fb.txt!
+ * PLEASE HAVE A LOOK AT Documentation/fb/sh7760fb.rst!
*
* Thanks to Siegfried Schaefer <s.schaefer at schaefer-edv.de>
* for his original source and testing!
diff --git a/drivers/video/fbdev/sh_mobile_lcdcfb.c b/drivers/video/fbdev/sh_mobile_lcdcfb.c
index b8454424910d..ac0bcac9a865 100644
--- a/drivers/video/fbdev/sh_mobile_lcdcfb.c
+++ b/drivers/video/fbdev/sh_mobile_lcdcfb.c
@@ -1564,10 +1564,8 @@ sh_mobile_lcdc_overlay_fb_init(struct sh_mobile_lcdc_overlay *ovl)
/* Allocate and initialize the frame buffer device. */
info = framebuffer_alloc(0, priv->dev);
- if (info == NULL) {
- dev_err(priv->dev, "unable to allocate fb_info\n");
+ if (!info)
return -ENOMEM;
- }
ovl->info = info;
@@ -2049,10 +2047,8 @@ sh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch,
* list and allocate the color map.
*/
info = framebuffer_alloc(0, priv->dev);
- if (info == NULL) {
- dev_err(priv->dev, "unable to allocate fb_info\n");
+ if (!info)
return -ENOMEM;
- }
ch->info = info;
diff --git a/drivers/video/fbdev/sm501fb.c b/drivers/video/fbdev/sm501fb.c
index dde52d027416..6edb4492e675 100644
--- a/drivers/video/fbdev/sm501fb.c
+++ b/drivers/video/fbdev/sm501fb.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* linux/drivers/video/sm501fb.c
*
* Copyright (c) 2006 Simtec Electronics
* Vincent Sanders <vince@simtec.co.uk>
* Ben Dooks <ben@simtec.co.uk>
*
- * 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.
- *
* Framebuffer driver for the Silicon Motion SM501
*/
@@ -1868,10 +1865,8 @@ static int sm501fb_probe_one(struct sm501fb_info *info,
}
fbi = framebuffer_alloc(sizeof(struct sm501fb_par), info->dev);
- if (fbi == NULL) {
- dev_err(info->dev, "cannot allocate %s framebuffer\n", name);
+ if (!fbi)
return -ENOMEM;
- }
par = fbi->par;
par->info = info;
diff --git a/drivers/video/fbdev/sm712fb.c b/drivers/video/fbdev/sm712fb.c
index f1dcc6766d1e..7b1b0d8d27a7 100644
--- a/drivers/video/fbdev/sm712fb.c
+++ b/drivers/video/fbdev/sm712fb.c
@@ -1538,7 +1538,6 @@ static int smtcfb_pci_probe(struct pci_dev *pdev,
info = framebuffer_alloc(sizeof(*sfb), &pdev->dev);
if (!info) {
- dev_err(&pdev->dev, "framebuffer_alloc failed\n");
err = -ENOMEM;
goto failed_free;
}
diff --git a/drivers/video/fbdev/smscufx.c b/drivers/video/fbdev/smscufx.c
index 8cd7892a0b0d..0e0f5bbfc5ef 100644
--- a/drivers/video/fbdev/smscufx.c
+++ b/drivers/video/fbdev/smscufx.c
@@ -1650,10 +1650,8 @@ static int ufx_usb_probe(struct usb_interface *interface,
/* allocates framebuffer driver structure, not framebuffer memory */
info = framebuffer_alloc(0, &usbdev->dev);
- if (!info) {
- dev_err(dev->gdev, "framebuffer_alloc failed\n");
+ if (!info)
goto e_nomem;
- }
dev->info = info;
info->par = dev;
diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c
index 021b727e8b5c..b674948e3bb8 100644
--- a/drivers/video/fbdev/ssd1307fb.c
+++ b/drivers/video/fbdev/ssd1307fb.c
@@ -555,10 +555,8 @@ static int ssd1307fb_probe(struct i2c_client *client,
}
info = framebuffer_alloc(sizeof(struct ssd1307fb_par), &client->dev);
- if (!info) {
- dev_err(&client->dev, "Couldn't allocate framebuffer.\n");
+ if (!info)
return -ENOMEM;
- }
par = info->par;
par->info = info;
diff --git a/drivers/video/fbdev/sunxvr1000.c b/drivers/video/fbdev/sunxvr1000.c
index 8fe37c0ef2f5..784c9bd5d502 100644
--- a/drivers/video/fbdev/sunxvr1000.c
+++ b/drivers/video/fbdev/sunxvr1000.c
@@ -121,7 +121,6 @@ static int gfb_probe(struct platform_device *op)
info = framebuffer_alloc(sizeof(struct gfb_info), &op->dev);
if (!info) {
- printk(KERN_ERR "gfb: Cannot allocate fb_info\n");
err = -ENOMEM;
goto err_out;
}
diff --git a/drivers/video/fbdev/sunxvr2500.c b/drivers/video/fbdev/sunxvr2500.c
index 544465ba1dc0..31683e5a8b79 100644
--- a/drivers/video/fbdev/sunxvr2500.c
+++ b/drivers/video/fbdev/sunxvr2500.c
@@ -132,7 +132,6 @@ static int s3d_pci_register(struct pci_dev *pdev,
info = framebuffer_alloc(sizeof(struct s3d_info), &pdev->dev);
if (!info) {
- printk(KERN_ERR "s3d: Cannot allocate fb_info\n");
err = -ENOMEM;
goto err_disable;
}
diff --git a/drivers/video/fbdev/sunxvr500.c b/drivers/video/fbdev/sunxvr500.c
index bc595937df08..d392976126a6 100644
--- a/drivers/video/fbdev/sunxvr500.c
+++ b/drivers/video/fbdev/sunxvr500.c
@@ -272,7 +272,6 @@ static int e3d_pci_register(struct pci_dev *pdev,
info = framebuffer_alloc(sizeof(struct e3d_info), &pdev->dev);
if (!info) {
- printk(KERN_ERR "e3d: Cannot allocate fb_info\n");
err = -ENOMEM;
goto err_disable;
}
diff --git a/drivers/video/fbdev/tgafb.c b/drivers/video/fbdev/tgafb.c
index 65ba9921506e..286b2371c7dd 100644
--- a/drivers/video/fbdev/tgafb.c
+++ b/drivers/video/fbdev/tgafb.c
@@ -1416,10 +1416,8 @@ static int tgafb_register(struct device *dev)
/* Allocate the fb and par structures. */
info = framebuffer_alloc(sizeof(struct tga_par), dev);
- if (!info) {
- printk(KERN_ERR "tgafb: Cannot allocate memory\n");
+ if (!info)
return -ENOMEM;
- }
par = info->par;
dev_set_drvdata(dev, info);
diff --git a/drivers/video/fbdev/udlfb.c b/drivers/video/fbdev/udlfb.c
index 00b99363e528..c328e8265cb1 100644
--- a/drivers/video/fbdev/udlfb.c
+++ b/drivers/video/fbdev/udlfb.c
@@ -1686,10 +1686,8 @@ static int dlfb_usb_probe(struct usb_interface *intf,
/* allocates framebuffer driver structure, not framebuffer memory */
info = framebuffer_alloc(0, &dlfb->udev->dev);
- if (!info) {
- dev_err(&dlfb->udev->dev, "framebuffer_alloc failed\n");
+ if (!info)
goto error;
- }
dlfb->info = info;
info->par = dlfb;
diff --git a/drivers/video/fbdev/via/viafbdev.c b/drivers/video/fbdev/via/viafbdev.c
index 8db5de13e2b7..f815f98190bc 100644
--- a/drivers/video/fbdev/via/viafbdev.c
+++ b/drivers/video/fbdev/via/viafbdev.c
@@ -1742,10 +1742,8 @@ int via_fb_pci_probe(struct viafb_dev *vdev)
viafbinfo = framebuffer_alloc(viafb_par_length +
ALIGN(sizeof(struct viafb_shared), BITS_PER_LONG/8),
&vdev->pdev->dev);
- if (!viafbinfo) {
- printk(KERN_ERR"Could not allocate memory for viafb_info.\n");
+ if (!viafbinfo)
return -ENOMEM;
- }
viaparinfo = (struct viafb_par *)viafbinfo->par;
viaparinfo->shared = viafbinfo->par + viafb_par_length;
@@ -1820,8 +1818,6 @@ int via_fb_pci_probe(struct viafb_dev *vdev)
viafbinfo1 = framebuffer_alloc(viafb_par_length,
&vdev->pdev->dev);
if (!viafbinfo1) {
- printk(KERN_ERR
- "allocate the second framebuffer struct error\n");
rc = -ENOMEM;
goto out_fb_release;
}
diff --git a/drivers/video/fbdev/vt8623fb.c b/drivers/video/fbdev/vt8623fb.c
index 5cac871db3ee..c339a8fbad81 100644
--- a/drivers/video/fbdev/vt8623fb.c
+++ b/drivers/video/fbdev/vt8623fb.c
@@ -669,10 +669,8 @@ static int vt8623_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
/* Allocate and fill driver data structure */
info = framebuffer_alloc(sizeof(struct vt8623fb_info), &(dev->dev));
- if (! info) {
- dev_err(&(dev->dev), "cannot allocate memory\n");
+ if (!info)
return -ENOMEM;
- }
par = info->par;
mutex_init(&par->open_lock);
diff --git a/drivers/video/fbdev/w100fb.c b/drivers/video/fbdev/w100fb.c
index 696106ecdff0..597ffaa13cd2 100644
--- a/drivers/video/fbdev/w100fb.c
+++ b/drivers/video/fbdev/w100fb.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/video/w100fb.c
*
@@ -17,11 +18,6 @@
*
* Hardware acceleration support by Alberto Mardegan
* <mardy@users.sourceforge.net>
- *
- * 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.
- *
*/
#include <linux/delay.h>
diff --git a/drivers/video/fbdev/w100fb.h b/drivers/video/fbdev/w100fb.h
index fffae7b4f6e9..52c96d155b4c 100644
--- a/drivers/video/fbdev/w100fb.h
+++ b/drivers/video/fbdev/w100fb.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/drivers/video/w100fb.h
*
@@ -10,11 +11,6 @@
* Modified to work with 2.6 by Richard Purdie <rpurdie@rpsys.net>
*
* w32xx support by Ian Molton
- *
- * 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.
- *
*/
#if !defined (_W100FB_H)
diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
index 023fc3bc01c6..078615cf2afc 100644
--- a/drivers/virtio/Kconfig
+++ b/drivers/virtio/Kconfig
@@ -43,6 +43,17 @@ config VIRTIO_PCI_LEGACY
If unsure, say Y.
+config VIRTIO_PMEM
+ tristate "Support for virtio pmem driver"
+ depends on VIRTIO
+ depends on LIBNVDIMM
+ help
+ This driver provides access to virtio-pmem devices, storage devices
+ that are mapped into the physical address space - similar to NVDIMMs
+ - with a virtio-based flushing interface.
+
+ If unsure, say Y.
+
config VIRTIO_BALLOON
tristate "Virtio balloon driver"
depends on VIRTIO
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 44339fc87cc7..226fbb995fb0 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -18,6 +18,7 @@
#include <linux/mm.h>
#include <linux/mount.h>
#include <linux/magic.h>
+#include <linux/pseudo_fs.h>
/*
* Balloon device works in 4K page units. So each page is pointed to by
@@ -745,20 +746,14 @@ static int virtballoon_migratepage(struct balloon_dev_info *vb_dev_info,
return MIGRATEPAGE_SUCCESS;
}
-static struct dentry *balloon_mount(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int balloon_init_fs_context(struct fs_context *fc)
{
- static const struct dentry_operations ops = {
- .d_dname = simple_dname,
- };
-
- return mount_pseudo(fs_type, "balloon-kvm:", NULL, &ops,
- BALLOON_KVM_MAGIC);
+ return init_pseudo(fc, BALLOON_KVM_MAGIC) ? 0 : -ENOMEM;
}
static struct file_system_type balloon_fs = {
.name = "balloon-kvm",
- .mount = balloon_mount,
+ .init_fs_context = balloon_init_fs_context,
.kill_sb = kill_anon_super,
};
diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c
index f363fbeb5ab0..e09edb5c5e06 100644
--- a/drivers/virtio/virtio_mmio.c
+++ b/drivers/virtio/virtio_mmio.c
@@ -463,9 +463,14 @@ static int vm_find_vqs(struct virtio_device *vdev, unsigned nvqs,
struct irq_affinity *desc)
{
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
- unsigned int irq = platform_get_irq(vm_dev->pdev, 0);
+ int irq = platform_get_irq(vm_dev->pdev, 0);
int i, err, queue_idx = 0;
+ if (irq < 0) {
+ dev_err(&vdev->dev, "Cannot get IRQ resource\n");
+ return irq;
+ }
+
err = request_irq(irq, vm_interrupt, IRQF_SHARED,
dev_name(&vdev->dev), vm_dev);
if (err)
diff --git a/drivers/visorbus/visorbus_main.c b/drivers/visorbus/visorbus_main.c
index 0b2434cc4ecd..152fd29f04f2 100644
--- a/drivers/visorbus/visorbus_main.c
+++ b/drivers/visorbus/visorbus_main.c
@@ -171,10 +171,10 @@ struct visor_busdev {
u32 dev_no;
};
-static int match_visorbus_dev_by_id(struct device *dev, void *data)
+static int match_visorbus_dev_by_id(struct device *dev, const void *data)
{
struct visor_device *vdev = to_visor_device(dev);
- struct visor_busdev *id = data;
+ const struct visor_busdev *id = data;
if (vdev->chipset_bus_no == id->bus_no &&
vdev->chipset_dev_no == id->dev_no)
diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig
index 03dd57581df7..3e7ad7b232fe 100644
--- a/drivers/w1/Kconfig
+++ b/drivers/w1/Kconfig
@@ -19,7 +19,7 @@ config W1_CON
default y
---help---
This allows to communicate with userspace using connector. For more
- information see <file:Documentation/connector/connector.txt>.
+ information see <file:Documentation/driver-api/connector.rst>.
There are three types of messages between w1 core and userspace:
1. Events. They are generated each time new master or slave device found
either due to automatic or requested search.
diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c
index 55e11bf8ebaf..d4632aace402 100644
--- a/drivers/w1/masters/w1-gpio.c
+++ b/drivers/w1/masters/w1-gpio.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* w1-gpio - GPIO w1 bus master driver
*
* Copyright (C) 2007 Ville Syrjala <syrjala@sci.fi>
- *
- * 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.
*/
#include <linux/init.h>
diff --git a/drivers/w1/slaves/w1_ds2406.c b/drivers/w1/slaves/w1_ds2406.c
index fac266366ca3..762e5e4e2b48 100644
--- a/drivers/w1/slaves/w1_ds2406.c
+++ b/drivers/w1/slaves/w1_ds2406.c
@@ -1,11 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* w1_ds2406.c - w1 family 12 (DS2406) driver
* based on w1_ds2413.c by Mariusz Bialonczyk <manio@skyboo.net>
*
* Copyright (c) 2014 Scott Alfter <scott@alfter.us>
- *
- * This source code is licensed under the GNU General Public License,
- * Version 2. See the file COPYING for more details.
*/
#include <linux/kernel.h>
diff --git a/drivers/w1/slaves/w1_ds2408.c b/drivers/w1/slaves/w1_ds2408.c
index edf0bc98012c..83f8d94bb814 100644
--- a/drivers/w1/slaves/w1_ds2408.c
+++ b/drivers/w1/slaves/w1_ds2408.c
@@ -1,10 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* w1_ds2408.c - w1 family 29 (DS2408) driver
*
* Copyright (c) 2010 Jean-Francois Dagenais <dagenaisj@sonatest.com>
- *
- * This source code is licensed under the GNU General Public License,
- * Version 2. See the file COPYING for more details.
*/
#include <linux/kernel.h>
diff --git a/drivers/w1/slaves/w1_ds2413.c b/drivers/w1/slaves/w1_ds2413.c
index 492e3d010321..f1fb18afbcea 100644
--- a/drivers/w1/slaves/w1_ds2413.c
+++ b/drivers/w1/slaves/w1_ds2413.c
@@ -1,11 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* w1_ds2413.c - w1 family 3a (DS2413) driver
* based on w1_ds2408.c by Jean-Francois Dagenais <dagenaisj@sonatest.com>
*
* Copyright (c) 2013 Mariusz Bialonczyk <manio@skyboo.net>
- *
- * This source code is licensed under the GNU General Public License,
- * Version 2. See the file COPYING for more details.
*/
#include <linux/kernel.h>
@@ -24,12 +22,17 @@
#define W1_F3A_FUNC_PIO_ACCESS_READ 0xF5
#define W1_F3A_FUNC_PIO_ACCESS_WRITE 0x5A
#define W1_F3A_SUCCESS_CONFIRM_BYTE 0xAA
+#define W1_F3A_INVALID_PIO_STATE 0xFF
static ssize_t state_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr, char *buf, loff_t off,
size_t count)
{
struct w1_slave *sl = kobj_to_w1_slave(kobj);
+ unsigned int retries = W1_F3A_RETRIES;
+ ssize_t bytes_read = -EIO;
+ u8 state;
+
dev_dbg(&sl->dev,
"Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
@@ -42,22 +45,37 @@ static ssize_t state_read(struct file *filp, struct kobject *kobj,
mutex_lock(&sl->master->bus_mutex);
dev_dbg(&sl->dev, "mutex locked");
- if (w1_reset_select_slave(sl)) {
- mutex_unlock(&sl->master->bus_mutex);
- return -EIO;
- }
+next:
+ if (w1_reset_select_slave(sl))
+ goto out;
- w1_write_8(sl->master, W1_F3A_FUNC_PIO_ACCESS_READ);
- *buf = w1_read_8(sl->master);
+ while (retries--) {
+ w1_write_8(sl->master, W1_F3A_FUNC_PIO_ACCESS_READ);
+
+ state = w1_read_8(sl->master);
+ if ((state & 0x0F) == ((~state >> 4) & 0x0F)) {
+ /* complement is correct */
+ *buf = state;
+ bytes_read = 1;
+ goto out;
+ } else if (state == W1_F3A_INVALID_PIO_STATE) {
+ /* slave didn't respond, try to select it again */
+ dev_warn(&sl->dev, "slave device did not respond to PIO_ACCESS_READ, " \
+ "reselecting, retries left: %d\n", retries);
+ goto next;
+ }
- mutex_unlock(&sl->master->bus_mutex);
- dev_dbg(&sl->dev, "mutex unlocked");
+ if (w1_reset_resume_command(sl->master))
+ goto out; /* unrecoverable error */
+
+ dev_warn(&sl->dev, "PIO_ACCESS_READ error, retries left: %d\n", retries);
+ }
- /* check for correct complement */
- if ((*buf & 0x0F) != ((~*buf >> 4) & 0x0F))
- return -EIO;
- else
- return 1;
+out:
+ mutex_unlock(&sl->master->bus_mutex);
+ dev_dbg(&sl->dev, "%s, mutex unlocked, retries: %d\n",
+ (bytes_read > 0) ? "succeeded" : "error", retries);
+ return bytes_read;
}
static BIN_ATTR_RO(state, 1);
@@ -69,6 +87,7 @@ static ssize_t output_write(struct file *filp, struct kobject *kobj,
struct w1_slave *sl = kobj_to_w1_slave(kobj);
u8 w1_buf[3];
unsigned int retries = W1_F3A_RETRIES;
+ ssize_t bytes_written = -EIO;
if (count != 1 || off != 0)
return -EFAULT;
@@ -78,7 +97,7 @@ static ssize_t output_write(struct file *filp, struct kobject *kobj,
dev_dbg(&sl->dev, "mutex locked");
if (w1_reset_select_slave(sl))
- goto error;
+ goto out;
/* according to the DS2413 datasheet the most significant 6 bits
should be set to "1"s, so do it now */
@@ -91,18 +110,20 @@ static ssize_t output_write(struct file *filp, struct kobject *kobj,
w1_write_block(sl->master, w1_buf, 3);
if (w1_read_8(sl->master) == W1_F3A_SUCCESS_CONFIRM_BYTE) {
- mutex_unlock(&sl->master->bus_mutex);
- dev_dbg(&sl->dev, "mutex unlocked, retries:%d", retries);
- return 1;
+ bytes_written = 1;
+ goto out;
}
if (w1_reset_resume_command(sl->master))
- goto error;
+ goto out; /* unrecoverable error */
+
+ dev_warn(&sl->dev, "PIO_ACCESS_WRITE error, retries left: %d\n", retries);
}
-error:
+out:
mutex_unlock(&sl->master->bus_mutex);
- dev_dbg(&sl->dev, "mutex unlocked in error, retries:%d", retries);
- return -EIO;
+ dev_dbg(&sl->dev, "%s, mutex unlocked, retries: %d\n",
+ (bytes_written > 0) ? "succeeded" : "error", retries);
+ return bytes_written;
}
static BIN_ATTR(output, S_IRUGO | S_IWUSR | S_IWGRP, NULL, output_write, 1);
diff --git a/drivers/w1/slaves/w1_ds2431.c b/drivers/w1/slaves/w1_ds2431.c
index 5adecd3face1..e5bd7e2354d7 100644
--- a/drivers/w1/slaves/w1_ds2431.c
+++ b/drivers/w1/slaves/w1_ds2431.c
@@ -1,12 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* w1_ds2431.c - w1 family 2d (DS2431) driver
*
* Copyright (c) 2008 Bernhard Weirich <bernhard.weirich@riedel.net>
*
* Heavily inspired by w1_DS2433 driver from Ben Gardner <bgardner@wabtec.com>
- *
- * This source code is licensed under the GNU General Public License,
- * Version 2. See the file COPYING for more details.
*/
#include <linux/kernel.h>
diff --git a/drivers/w1/slaves/w1_ds2433.c b/drivers/w1/slaves/w1_ds2433.c
index 75ad70cfe8e8..1f805c86517a 100644
--- a/drivers/w1/slaves/w1_ds2433.c
+++ b/drivers/w1/slaves/w1_ds2433.c
@@ -1,10 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* w1_ds2433.c - w1 family 23 (DS2433) driver
*
* Copyright (c) 2005 Ben Gardner <bgardner@wabtec.com>
- *
- * This source code is licensed under the GNU General Public License,
- * Version 2. See the file COPYING for more details.
*/
#include <linux/kernel.h>
diff --git a/drivers/w1/slaves/w1_ds2438.c b/drivers/w1/slaves/w1_ds2438.c
index 7c4e33dbee4d..d199e5a25cc0 100644
--- a/drivers/w1/slaves/w1_ds2438.c
+++ b/drivers/w1/slaves/w1_ds2438.c
@@ -1,10 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* 1-Wire implementation for the ds2438 chip
*
* Copyright (c) 2017 Mariusz Bialonczyk <manio@skyboo.net>
- *
- * This source code is licensed under the GNU General Public License,
- * Version 2. See the file COPYING for more details.
*/
#include <linux/kernel.h>
diff --git a/drivers/w1/slaves/w1_ds2780.c b/drivers/w1/slaves/w1_ds2780.c
index a60528131154..c689b1b987b8 100644
--- a/drivers/w1/slaves/w1_ds2780.c
+++ b/drivers/w1/slaves/w1_ds2780.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* 1-Wire implementation for the ds2780 chip
*
@@ -6,11 +7,6 @@
* Author: Clifton Barnes <cabarnes@indesign-llc.com>
*
* Based on w1-ds2760 driver
- *
- * 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.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/w1/slaves/w1_ds2780.h b/drivers/w1/slaves/w1_ds2780.h
index a1fba79eb1b5..99e38ed788a5 100644
--- a/drivers/w1/slaves/w1_ds2780.h
+++ b/drivers/w1/slaves/w1_ds2780.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* 1-Wire implementation for the ds2780 chip
*
@@ -6,11 +7,6 @@
* Author: Clifton Barnes <cabarnes@indesign-llc.com>
*
* Based on w1-ds2760 driver
- *
- * 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.
- *
*/
#ifndef _W1_DS2780_H
diff --git a/drivers/w1/slaves/w1_ds2781.c b/drivers/w1/slaves/w1_ds2781.c
index 645be6e0b24a..84d6ceec5da5 100644
--- a/drivers/w1/slaves/w1_ds2781.c
+++ b/drivers/w1/slaves/w1_ds2781.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* 1-Wire implementation for the ds2781 chip
*
* Author: Renata Sayakhova <renata@oktetlabs.ru>
*
* Based on w1-ds2780 driver
- *
- * 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.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/w1/slaves/w1_ds2781.h b/drivers/w1/slaves/w1_ds2781.h
index 557dfb0b4f64..fa902dfa0136 100644
--- a/drivers/w1/slaves/w1_ds2781.h
+++ b/drivers/w1/slaves/w1_ds2781.h
@@ -1,14 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* 1-Wire implementation for the ds2780 chip
*
* Author: Renata Sayakhova <renata@oktetlabs.ru>
*
* Based on w1-ds2760 driver
- *
- * 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.
- *
*/
#ifndef _W1_DS2781_H
diff --git a/drivers/w1/slaves/w1_ds2805.c b/drivers/w1/slaves/w1_ds2805.c
index 29348d283a65..ccb753a474b1 100644
--- a/drivers/w1/slaves/w1_ds2805.c
+++ b/drivers/w1/slaves/w1_ds2805.c
@@ -1,10 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* w1_ds2805 - w1 family 0d (DS28E05) driver
*
* Copyright (c) 2016 Andrew Worsley amworsley@gmail.com
- *
- * This source code is licensed under the GNU General Public License,
- * Version 2. See the file COPYING for more details.
*/
#include <linux/kernel.h>
@@ -288,7 +286,7 @@ static struct w1_family_ops w1_f0d_fops = {
.remove_slave = w1_f0d_remove_slave,
};
-static struct w1_family w1_family_2d = {
+static struct w1_family w1_family_0d = {
.fid = W1_EEPROM_DS2805,
.fops = &w1_f0d_fops,
};
@@ -296,13 +294,13 @@ static struct w1_family w1_family_2d = {
static int __init w1_f0d_init(void)
{
pr_info("%s()\n", __func__);
- return w1_register_family(&w1_family_2d);
+ return w1_register_family(&w1_family_0d);
}
static void __exit w1_f0d_fini(void)
{
pr_info("%s()\n", __func__);
- w1_unregister_family(&w1_family_2d);
+ w1_unregister_family(&w1_family_0d);
}
module_init(w1_f0d_init);
diff --git a/drivers/w1/slaves/w1_ds28e04.c b/drivers/w1/slaves/w1_ds28e04.c
index ec234b846eb3..8a640f159078 100644
--- a/drivers/w1/slaves/w1_ds28e04.c
+++ b/drivers/w1/slaves/w1_ds28e04.c
@@ -1,10 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* w1_ds28e04.c - w1 family 1C (DS28E04) driver
*
* Copyright (c) 2012 Markus Franke <franke.m@sebakmt.com>
- *
- * This source code is licensed under the GNU General Public License,
- * Version 2. See the file COPYING for more details.
*/
#include <linux/kernel.h>
diff --git a/drivers/w1/slaves/w1_ds28e17.c b/drivers/w1/slaves/w1_ds28e17.c
index e78b63ea4daf..046ddda83df9 100644
--- a/drivers/w1/slaves/w1_ds28e17.c
+++ b/drivers/w1/slaves/w1_ds28e17.c
@@ -1,10 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* w1_ds28e17.c - w1 family 19 (DS28E17) driver
*
* Copyright (c) 2016 Jan Kandziora <jjj@gmx.de>
- *
- * This source code is licensed under the GNU General Public License,
- * Version 2. See the file COPYING for more details.
*/
#include <linux/crc16.h>
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index ffe754539f5a..8188963a405b 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -18,7 +18,7 @@ menuconfig WATCHDOG
reboot the machine) and a driver for hardware watchdog boards, which
are more robust and can also keep track of the temperature inside
your computer. For details, read
- <file:Documentation/watchdog/watchdog-api.txt> in the kernel source.
+ <file:Documentation/watchdog/watchdog-api.rst> in the kernel source.
The watchdog is usually used together with the watchdog daemon
which is available from
@@ -58,6 +58,15 @@ config WATCHDOG_HANDLE_BOOT_ENABLED
the watchdog on its own. Thus if your userspace does not start fast
enough your device will reboot.
+config WATCHDOG_OPEN_TIMEOUT
+ int "Timeout value for opening watchdog device"
+ default 0
+ help
+ The maximum time, in seconds, for which the watchdog framework takes
+ care of pinging a hardware watchdog. A value of 0 means infinite. The
+ value set here can be overridden by the commandline parameter
+ "watchdog.open_timeout".
+
config WATCHDOG_SYSFS
bool "Read different watchdog information through sysfs"
help
@@ -717,6 +726,7 @@ config IMX2_WDT
config IMX_SC_WDT
tristate "IMX SC Watchdog"
depends on HAVE_ARM_SMCCC
+ depends on IMX_SCU
select WATCHDOG_CORE
help
This is the driver for the system controller watchdog
@@ -1870,7 +1880,7 @@ config BOOKE_WDT
Watchdog driver for PowerPC Book-E chips, such as the Freescale
MPC85xx SOCs and the IBM PowerPC 440.
- Please see Documentation/watchdog/watchdog-api.txt for
+ Please see Documentation/watchdog/watchdog-api.rst for
more information.
config BOOKE_WDT_DEFAULT_TIMEOUT
@@ -2019,7 +2029,7 @@ config PCWATCHDOG
This card simply watches your kernel to make sure it doesn't freeze,
and if it does, it reboots your computer after a certain amount of
time. This driver is like the WDT501 driver but for different
- hardware. Please read <file:Documentation/watchdog/pcwd-watchdog.txt>. The PC
+ hardware. Please read <file:Documentation/watchdog/pcwd-watchdog.rst>. The PC
watchdog cards can be ordered from <http://www.berkprod.com/>.
To compile this driver as a module, choose M here: the
diff --git a/drivers/watchdog/acquirewdt.c b/drivers/watchdog/acquirewdt.c
index 957d1255d4ca..848db958411e 100644
--- a/drivers/watchdog/acquirewdt.c
+++ b/drivers/watchdog/acquirewdt.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Acquire Single Board Computer Watchdog Timer driver
*
@@ -6,11 +7,6 @@
* (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>,
* All Rights Reserved.
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
* warranty for any of this software. This material is provided
* "AS-IS" and at no charge.
diff --git a/drivers/watchdog/advantechwdt.c b/drivers/watchdog/advantechwdt.c
index 2766af292a71..0d02bb275b3d 100644
--- a/drivers/watchdog/advantechwdt.c
+++ b/drivers/watchdog/advantechwdt.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Advantech Single Board Computer WDT driver
*
@@ -9,11 +10,6 @@
* (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>,
* All Rights Reserved.
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
* warranty for any of this software. This material is provided
* "AS-IS" and at no charge.
diff --git a/drivers/watchdog/aspeed_wdt.c b/drivers/watchdog/aspeed_wdt.c
index f0148637e5dd..cc71861e033a 100644
--- a/drivers/watchdog/aspeed_wdt.c
+++ b/drivers/watchdog/aspeed_wdt.c
@@ -309,13 +309,7 @@ static int aspeed_wdt_probe(struct platform_device *pdev)
if (status & WDT_TIMEOUT_STATUS_BOOT_SECONDARY)
wdt->wdd.bootstatus = WDIOF_CARDRESET;
- ret = devm_watchdog_register_device(dev, &wdt->wdd);
- if (ret) {
- dev_err(dev, "failed to register\n");
- return ret;
- }
-
- return 0;
+ return devm_watchdog_register_device(dev, &wdt->wdd);
}
static struct platform_driver aspeed_watchdog_driver = {
diff --git a/drivers/watchdog/ath79_wdt.c b/drivers/watchdog/ath79_wdt.c
index 02234c254b10..2e09981fe978 100644
--- a/drivers/watchdog/ath79_wdt.c
+++ b/drivers/watchdog/ath79_wdt.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Atheros AR71XX/AR724X/AR913X built-in hardware watchdog timer.
*
@@ -10,11 +11,6 @@
*
* which again was based on sa1100 driver,
* Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
- *
- * 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.
- *
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/watchdog/bcm2835_wdt.c b/drivers/watchdog/bcm2835_wdt.c
index 560c1c54c177..dec6ca019bea 100644
--- a/drivers/watchdog/bcm2835_wdt.c
+++ b/drivers/watchdog/bcm2835_wdt.c
@@ -202,10 +202,8 @@ static int bcm2835_wdt_probe(struct platform_device *pdev)
watchdog_stop_on_reboot(&bcm2835_wdt_wdd);
err = devm_watchdog_register_device(dev, &bcm2835_wdt_wdd);
- if (err) {
- dev_err(dev, "Failed to register watchdog device");
+ if (err)
return err;
- }
if (pm_power_off == NULL) {
pm_power_off = bcm2835_power_off;
@@ -240,6 +238,7 @@ module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+MODULE_ALIAS("platform:bcm2835-wdt");
MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
MODULE_DESCRIPTION("Driver for Broadcom BCM2835 watchdog timer");
MODULE_LICENSE("GPL");
diff --git a/drivers/watchdog/bcm7038_wdt.c b/drivers/watchdog/bcm7038_wdt.c
index d3d88f6703d7..979caa18d3c8 100644
--- a/drivers/watchdog/bcm7038_wdt.c
+++ b/drivers/watchdog/bcm7038_wdt.c
@@ -159,10 +159,8 @@ static int bcm7038_wdt_probe(struct platform_device *pdev)
watchdog_stop_on_reboot(&wdt->wdd);
watchdog_stop_on_unregister(&wdt->wdd);
err = devm_watchdog_register_device(dev, &wdt->wdd);
- if (err) {
- dev_err(dev, "Failed to register watchdog device\n");
+ if (err)
return err;
- }
dev_info(dev, "Registered BCM7038 Watchdog\n");
diff --git a/drivers/watchdog/bcm_kona_wdt.c b/drivers/watchdog/bcm_kona_wdt.c
index e2ad44816359..eb850a8d19df 100644
--- a/drivers/watchdog/bcm_kona_wdt.c
+++ b/drivers/watchdog/bcm_kona_wdt.c
@@ -143,24 +143,18 @@ static void bcm_kona_wdt_debug_init(struct platform_device *pdev)
wdt->debugfs = NULL;
dir = debugfs_create_dir(BCM_KONA_WDT_NAME, NULL);
- if (IS_ERR_OR_NULL(dir))
- return;
- if (debugfs_create_file("info", S_IFREG | S_IRUGO, dir, wdt,
- &bcm_kona_fops))
- wdt->debugfs = dir;
- else
- debugfs_remove_recursive(dir);
+ debugfs_create_file("info", S_IFREG | S_IRUGO, dir, wdt,
+ &bcm_kona_fops);
+ wdt->debugfs = dir;
}
static void bcm_kona_wdt_debug_exit(struct platform_device *pdev)
{
struct bcm_kona_wdt *wdt = platform_get_drvdata(pdev);
- if (wdt && wdt->debugfs) {
+ if (wdt)
debugfs_remove_recursive(wdt->debugfs);
- wdt->debugfs = NULL;
- }
}
#else
@@ -307,10 +301,8 @@ static int bcm_kona_wdt_probe(struct platform_device *pdev)
watchdog_stop_on_reboot(&bcm_kona_wdt_wdd);
watchdog_stop_on_unregister(&bcm_kona_wdt_wdd);
ret = devm_watchdog_register_device(dev, &bcm_kona_wdt_wdd);
- if (ret) {
- dev_err(dev, "Failed to register watchdog device");
+ if (ret)
return ret;
- }
bcm_kona_wdt_debug_init(pdev);
dev_dbg(dev, "Broadcom Kona Watchdog Timer");
diff --git a/drivers/watchdog/cadence_wdt.c b/drivers/watchdog/cadence_wdt.c
index a22f2d431a35..f8d4e91d0383 100644
--- a/drivers/watchdog/cadence_wdt.c
+++ b/drivers/watchdog/cadence_wdt.c
@@ -363,10 +363,8 @@ static int cdns_wdt_probe(struct platform_device *pdev)
watchdog_stop_on_reboot(cdns_wdt_device);
watchdog_stop_on_unregister(cdns_wdt_device);
ret = devm_watchdog_register_device(dev, cdns_wdt_device);
- if (ret) {
- dev_err(dev, "Failed to register wdt device\n");
+ if (ret)
return ret;
- }
platform_set_drvdata(pdev, wdt);
dev_info(dev, "Xilinx Watchdog Timer at %p with timeout %ds%s\n",
diff --git a/drivers/watchdog/da9052_wdt.c b/drivers/watchdog/da9052_wdt.c
index a2feef1ff307..d708c091bf1b 100644
--- a/drivers/watchdog/da9052_wdt.c
+++ b/drivers/watchdog/da9052_wdt.c
@@ -176,14 +176,7 @@ static int da9052_wdt_probe(struct platform_device *pdev)
return ret;
}
- ret = devm_watchdog_register_device(dev, &driver_data->wdt);
- if (ret != 0) {
- dev_err(da9052->dev, "watchdog_register_device() failed: %d\n",
- ret);
- return ret;
- }
-
- return ret;
+ return devm_watchdog_register_device(dev, &driver_data->wdt);
}
static struct platform_driver da9052_wdt_driver = {
diff --git a/drivers/watchdog/da9062_wdt.c b/drivers/watchdog/da9062_wdt.c
index aac749cfaccb..e149e66a6ea9 100644
--- a/drivers/watchdog/da9062_wdt.c
+++ b/drivers/watchdog/da9062_wdt.c
@@ -214,11 +214,8 @@ static int da9062_wdt_probe(struct platform_device *pdev)
watchdog_set_drvdata(&wdt->wdtdev, wdt);
ret = devm_watchdog_register_device(dev, &wdt->wdtdev);
- if (ret < 0) {
- dev_err(wdt->hw->dev,
- "watchdog registration failed (%d)\n", ret);
+ if (ret < 0)
return ret;
- }
return da9062_wdt_ping(&wdt->wdtdev);
}
diff --git a/drivers/watchdog/davinci_wdt.c b/drivers/watchdog/davinci_wdt.c
index 7b2ee35b5ffd..2b3f3cd382ef 100644
--- a/drivers/watchdog/davinci_wdt.c
+++ b/drivers/watchdog/davinci_wdt.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* drivers/char/watchdog/davinci_wdt.c
*
@@ -5,10 +6,7 @@
*
* Copyright (C) 2006-2013 Texas Instruments.
*
- * 2007 (c) MontaVista Software, 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.
+ * 2007 (c) MontaVista Software, Inc.
*/
#include <linux/module.h>
@@ -247,13 +245,7 @@ static int davinci_wdt_probe(struct platform_device *pdev)
if (IS_ERR(davinci_wdt->base))
return PTR_ERR(davinci_wdt->base);
- ret = devm_watchdog_register_device(dev, wdd);
- if (ret) {
- dev_err(dev, "cannot register watchdog device\n");
- return ret;
- }
-
- return 0;
+ return devm_watchdog_register_device(dev, wdd);
}
static const struct of_device_id davinci_wdt_of_match[] = {
diff --git a/drivers/watchdog/digicolor_wdt.c b/drivers/watchdog/digicolor_wdt.c
index 8af6e9a67d0d..073d37867f47 100644
--- a/drivers/watchdog/digicolor_wdt.c
+++ b/drivers/watchdog/digicolor_wdt.c
@@ -118,7 +118,6 @@ static int dc_wdt_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct dc_wdt *wdt;
- int ret;
wdt = devm_kzalloc(dev, sizeof(struct dc_wdt), GFP_KERNEL);
if (!wdt)
@@ -141,13 +140,7 @@ static int dc_wdt_probe(struct platform_device *pdev)
watchdog_set_restart_priority(&dc_wdt_wdd, 128);
watchdog_init_timeout(&dc_wdt_wdd, timeout, dev);
watchdog_stop_on_reboot(&dc_wdt_wdd);
- ret = devm_watchdog_register_device(dev, &dc_wdt_wdd);
- if (ret) {
- dev_err(dev, "Failed to register watchdog device");
- return ret;
- }
-
- return 0;
+ return devm_watchdog_register_device(dev, &dc_wdt_wdd);
}
static const struct of_device_id dc_wdt_of_match[] = {
diff --git a/drivers/watchdog/ebc-c384_wdt.c b/drivers/watchdog/ebc-c384_wdt.c
index c176f59fea28..8ef4b0df3855 100644
--- a/drivers/watchdog/ebc-c384_wdt.c
+++ b/drivers/watchdog/ebc-c384_wdt.c
@@ -2,15 +2,6 @@
/*
* Watchdog timer driver for the WinSystems EBC-C384
* Copyright (C) 2016 William Breathitt Gray
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
#include <linux/device.h>
#include <linux/dmi.h>
diff --git a/drivers/watchdog/eurotechwdt.c b/drivers/watchdog/eurotechwdt.c
index 89129e6fa9b6..3a83a48abcae 100644
--- a/drivers/watchdog/eurotechwdt.c
+++ b/drivers/watchdog/eurotechwdt.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Eurotech CPU-1220/1410/1420 on board WDT driver
*
@@ -11,11 +12,6 @@
* (c) Copyright 1996-1997 Alan Cox <alan@lxorguk.ukuu.org.uk>,
* All Rights Reserved.
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
* warranty for any of this software. This material is provided
* "AS-IS" and at no charge.
diff --git a/drivers/watchdog/ftwdt010_wdt.c b/drivers/watchdog/ftwdt010_wdt.c
index 9ea0e56fa7ee..21dcc7765688 100644
--- a/drivers/watchdog/ftwdt010_wdt.c
+++ b/drivers/watchdog/ftwdt010_wdt.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Watchdog driver for Faraday Technology FTWDT010
*
@@ -5,10 +6,6 @@
*
* Inspired by the out-of-tree drivers from OpenWRT:
* Copyright (C) 2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
- *
- * 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.
*/
#include <linux/bitops.h>
@@ -168,10 +165,8 @@ static int ftwdt010_wdt_probe(struct platform_device *pdev)
}
ret = devm_watchdog_register_device(dev, &gwdt->wdd);
- if (ret) {
- dev_err(dev, "failed to register watchdog\n");
+ if (ret)
return ret;
- }
/* Set up platform driver data */
platform_set_drvdata(pdev, gwdt);
diff --git a/drivers/watchdog/gpio_wdt.c b/drivers/watchdog/gpio_wdt.c
index 777de10f2a78..0923201ce874 100644
--- a/drivers/watchdog/gpio_wdt.c
+++ b/drivers/watchdog/gpio_wdt.c
@@ -13,6 +13,12 @@
#include <linux/platform_device.h>
#include <linux/watchdog.h>
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout,
+ "Watchdog cannot be stopped once started (default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
#define SOFT_TIMEOUT_MIN 1
#define SOFT_TIMEOUT_DEF 60
@@ -151,6 +157,7 @@ static int gpio_wdt_probe(struct platform_device *pdev)
priv->wdd.timeout = SOFT_TIMEOUT_DEF;
watchdog_init_timeout(&priv->wdd, 0, dev);
+ watchdog_set_nowayout(&priv->wdd, nowayout);
watchdog_stop_on_reboot(&priv->wdd);
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index db1bf6f546ae..7d34bcf1c45b 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* HPE WatchDog Driver
* based on
@@ -6,11 +7,6 @@
*
* (c) Copyright 2018 Hewlett Packard Enterprise Development LP
* Thomas Mingarelli <thomas.mingarelli@hpe.com>
- *
- * 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
- *
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -26,10 +22,11 @@
#include <linux/watchdog.h>
#include <asm/nmi.h>
-#define HPWDT_VERSION "2.0.2"
+#define HPWDT_VERSION "2.0.3"
#define SECS_TO_TICKS(secs) ((secs) * 1000 / 128)
#define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000)
-#define HPWDT_MAX_TIMER TICKS_TO_SECS(65535)
+#define HPWDT_MAX_TICKS 65535
+#define HPWDT_MAX_TIMER TICKS_TO_SECS(HPWDT_MAX_TICKS)
#define DEFAULT_MARGIN 30
#define PRETIMEOUT_SEC 9
@@ -37,6 +34,7 @@ static bool ilo5;
static unsigned int soft_margin = DEFAULT_MARGIN; /* in seconds */
static bool nowayout = WATCHDOG_NOWAYOUT;
static bool pretimeout = IS_ENABLED(CONFIG_HPWDT_NMI_DECODING);
+static int kdumptimeout = -1;
static void __iomem *pci_mem_addr; /* the PCI-memory address */
static unsigned long __iomem *hpwdt_nmistat;
@@ -56,15 +54,21 @@ static const struct pci_device_id hpwdt_blacklist[] = {
{0}, /* terminate list */
};
+static struct watchdog_device hpwdt_dev;
/*
* Watchdog operations
*/
+static int hpwdt_hw_is_running(void)
+{
+ return ioread8(hpwdt_timer_con) & 0x01;
+}
+
static int hpwdt_start(struct watchdog_device *wdd)
{
int control = 0x81 | (pretimeout ? 0x4 : 0);
- int reload = SECS_TO_TICKS(wdd->timeout);
+ int reload = SECS_TO_TICKS(min(wdd->timeout, wdd->max_hw_heartbeat_ms/1000));
- dev_dbg(wdd->parent, "start watchdog 0x%08x:0x%02x\n", reload, control);
+ dev_dbg(wdd->parent, "start watchdog 0x%08x:0x%08x:0x%02x\n", wdd->timeout, reload, control);
iowrite16(reload, hpwdt_timer_reg);
iowrite8(control, hpwdt_timer_con);
@@ -89,12 +93,18 @@ static int hpwdt_stop_core(struct watchdog_device *wdd)
return 0;
}
+static void hpwdt_ping_ticks(int val)
+{
+ val = min(val, HPWDT_MAX_TICKS);
+ iowrite16(val, hpwdt_timer_reg);
+}
+
static int hpwdt_ping(struct watchdog_device *wdd)
{
- int reload = SECS_TO_TICKS(wdd->timeout);
+ int reload = SECS_TO_TICKS(min(wdd->timeout, wdd->max_hw_heartbeat_ms/1000));
- dev_dbg(wdd->parent, "ping watchdog 0x%08x\n", reload);
- iowrite16(reload, hpwdt_timer_reg);
+ dev_dbg(wdd->parent, "ping watchdog 0x%08x:0x%08x\n", wdd->timeout, reload);
+ hpwdt_ping_ticks(reload);
return 0;
}
@@ -170,7 +180,14 @@ static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs)
if (ilo5 && !pretimeout && !mynmi)
return NMI_DONE;
- hpwdt_stop();
+ if (kdumptimeout < 0)
+ hpwdt_stop();
+ else if (kdumptimeout == 0)
+ ;
+ else {
+ unsigned int val = max((unsigned int)kdumptimeout, hpwdt_dev.timeout);
+ hpwdt_ping_ticks(SECS_TO_TICKS(val));
+ }
hex_byte_pack(panic_msg, mynmi);
nmi_panic(regs, panic_msg);
@@ -208,9 +225,9 @@ static struct watchdog_device hpwdt_dev = {
.info = &ident,
.ops = &hpwdt_ops,
.min_timeout = 1,
- .max_timeout = HPWDT_MAX_TIMER,
.timeout = DEFAULT_MARGIN,
.pretimeout = PRETIMEOUT_SEC,
+ .max_hw_heartbeat_ms = HPWDT_MAX_TIMER * 1000,
};
@@ -302,14 +319,18 @@ static int hpwdt_init_one(struct pci_dev *dev,
hpwdt_timer_reg = pci_mem_addr + 0x70;
hpwdt_timer_con = pci_mem_addr + 0x72;
- /* Make sure that timer is disabled until /dev/watchdog is opened */
- hpwdt_stop();
+ /* Have the core update running timer until user space is ready */
+ if (hpwdt_hw_is_running()) {
+ dev_info(&dev->dev, "timer is running\n");
+ set_bit(WDOG_HW_RUNNING, &hpwdt_dev.status);
+ }
/* Initialize NMI Decoding functionality */
retval = hpwdt_init_nmi_decoding(dev);
if (retval != 0)
goto error_init_nmi_decoding;
+ watchdog_stop_on_unregister(&hpwdt_dev);
watchdog_set_nowayout(&hpwdt_dev, nowayout);
watchdog_init_timeout(&hpwdt_dev, soft_margin, NULL);
@@ -318,13 +339,12 @@ static int hpwdt_init_one(struct pci_dev *dev,
pretimeout = 0;
}
hpwdt_dev.pretimeout = pretimeout ? PRETIMEOUT_SEC : 0;
+ kdumptimeout = min(kdumptimeout, HPWDT_MAX_TIMER);
hpwdt_dev.parent = &dev->dev;
retval = watchdog_register_device(&hpwdt_dev);
- if (retval < 0) {
- dev_err(&dev->dev, "watchdog register failed: %d.\n", retval);
+ if (retval < 0)
goto error_wd_register;
- }
dev_info(&dev->dev, "HPE Watchdog Timer Driver: Version: %s\n",
HPWDT_VERSION);
@@ -332,6 +352,7 @@ static int hpwdt_init_one(struct pci_dev *dev,
hpwdt_dev.timeout, nowayout);
dev_info(&dev->dev, "pretimeout: %s.\n",
pretimeout ? "on" : "off");
+ dev_info(&dev->dev, "kdumptimeout: %d.\n", kdumptimeout);
if (dev->subsystem_vendor == PCI_VENDOR_ID_HP_3PAR)
ilo5 = true;
@@ -349,9 +370,6 @@ error_pci_iomap:
static void hpwdt_exit(struct pci_dev *dev)
{
- if (!nowayout)
- hpwdt_stop();
-
watchdog_unregister_device(&hpwdt_dev);
hpwdt_exit_nmi_decoding();
pci_iounmap(dev, pci_mem_addr);
@@ -380,6 +398,9 @@ module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+module_param(kdumptimeout, int, 0444);
+MODULE_PARM_DESC(kdumptimeout, "Timeout applied for crash kernel transition in seconds");
+
#ifdef CONFIG_HPWDT_NMI_DECODING
module_param(pretimeout, bool, 0);
MODULE_PARM_DESC(pretimeout, "Watchdog pretimeout enabled");
diff --git a/drivers/watchdog/i6300esb.c b/drivers/watchdog/i6300esb.c
index f98f35a05896..a30835f547b3 100644
--- a/drivers/watchdog/i6300esb.c
+++ b/drivers/watchdog/i6300esb.c
@@ -315,11 +315,8 @@ static int esb_probe(struct pci_dev *pdev,
/* Register the watchdog so that userspace has access to it */
ret = watchdog_register_device(&edev->wdd);
- if (ret != 0) {
- dev_err(&pdev->dev,
- "cannot register watchdog device (err=%d)\n", ret);
+ if (ret != 0)
goto err_unmap;
- }
dev_info(&pdev->dev,
"initialized. heartbeat=%d sec (nowayout=%d)\n",
edev->wdd.timeout, nowayout);
diff --git a/drivers/watchdog/iTCO_vendor_support.c b/drivers/watchdog/iTCO_vendor_support.c
index 68a9d9cc2eb8..4f1b96f59349 100644
--- a/drivers/watchdog/iTCO_vendor_support.c
+++ b/drivers/watchdog/iTCO_vendor_support.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* intel TCO vendor specific watchdog driver support
*
* (c) Copyright 2006-2009 Wim Van Sebroeck <wim@iguana.be>.
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
@@ -216,4 +212,3 @@ MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>, "
MODULE_DESCRIPTION("Intel TCO Vendor Specific WatchDog Timer Driver Support");
MODULE_VERSION(DRV_VERSION);
MODULE_LICENSE("GPL");
-
diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c
index 89cea6ce9a08..c559f706ae7e 100644
--- a/drivers/watchdog/iTCO_wdt.c
+++ b/drivers/watchdog/iTCO_wdt.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* intel TCO Watchdog Driver
*
* (c) Copyright 2006-2011 Wim Van Sebroeck <wim@iguana.be>.
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
diff --git a/drivers/watchdog/ib700wdt.c b/drivers/watchdog/ib700wdt.c
index 30d6cec582af..92fd7f33bc4d 100644
--- a/drivers/watchdog/ib700wdt.c
+++ b/drivers/watchdog/ib700wdt.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* IB700 Single Board Computer WDT driver
*
@@ -14,11 +15,6 @@
* (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>,
* All Rights Reserved.
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
* warranty for any of this software. This material is provided
* "AS-IS" and at no charge.
diff --git a/drivers/watchdog/ie6xx_wdt.c b/drivers/watchdog/ie6xx_wdt.c
index 508fbefce9f6..8f28993fab8b 100644
--- a/drivers/watchdog/ie6xx_wdt.c
+++ b/drivers/watchdog/ie6xx_wdt.c
@@ -66,7 +66,7 @@ MODULE_PARM_DESC(resetmode,
static struct {
unsigned short sch_wdtba;
- struct spinlock unlock_sequence;
+ spinlock_t unlock_sequence;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs;
#endif
@@ -254,12 +254,8 @@ static int ie6xx_wdt_probe(struct platform_device *pdev)
ie6xx_wdt_debugfs_init();
ret = watchdog_register_device(&ie6xx_wdt_dev);
- if (ret) {
- dev_err(&pdev->dev,
- "Watchdog timer: cannot register device (err =%d)\n",
- ret);
+ if (ret)
goto misc_register_error;
- }
return 0;
diff --git a/drivers/watchdog/imgpdc_wdt.c b/drivers/watchdog/imgpdc_wdt.c
index 0fc31aadeee3..b57ff3787052 100644
--- a/drivers/watchdog/imgpdc_wdt.c
+++ b/drivers/watchdog/imgpdc_wdt.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Imagination Technologies PowerDown Controller Watchdog Timer.
*
* Copyright (c) 2014 Imagination Technologies Ltd.
*
- * 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.
- *
* Based on drivers/watchdog/sunxi_wdt.c Copyright (c) 2013 Carlo Caione
* 2012 Henrik Nordstrom
*
diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c
index a606005dd65f..32af3974e6bb 100644
--- a/drivers/watchdog/imx2_wdt.c
+++ b/drivers/watchdog/imx2_wdt.c
@@ -316,10 +316,8 @@ static int __init imx2_wdt_probe(struct platform_device *pdev)
regmap_write(wdev->regmap, IMX2_WDT_WMCR, 0);
ret = watchdog_register_device(wdog);
- if (ret) {
- dev_err(&pdev->dev, "cannot register watchdog device\n");
+ if (ret)
goto disable_clk;
- }
dev_info(&pdev->dev, "timeout %d sec (nowayout=%d)\n",
wdog->timeout, nowayout);
diff --git a/drivers/watchdog/imx_sc_wdt.c b/drivers/watchdog/imx_sc_wdt.c
index 49848b66186c..78eaaf75a263 100644
--- a/drivers/watchdog/imx_sc_wdt.c
+++ b/drivers/watchdog/imx_sc_wdt.c
@@ -4,6 +4,7 @@
*/
#include <linux/arm-smccc.h>
+#include <linux/firmware/imx/sci.h>
#include <linux/io.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -33,11 +34,19 @@
#define SC_TIMER_WDOG_ACTION_PARTITION 0
+#define SC_IRQ_WDOG 1
+#define SC_IRQ_GROUP_WDOG 1
+
static bool nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, bool, 0000);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+struct imx_sc_wdt_device {
+ struct watchdog_device wdd;
+ struct notifier_block wdt_notifier;
+};
+
static int imx_sc_wdt_ping(struct watchdog_device *wdog)
{
struct arm_smccc_res res;
@@ -85,24 +94,66 @@ static int imx_sc_wdt_set_timeout(struct watchdog_device *wdog,
return res.a0 ? -EACCES : 0;
}
+static int imx_sc_wdt_set_pretimeout(struct watchdog_device *wdog,
+ unsigned int pretimeout)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(IMX_SIP_TIMER, IMX_SIP_TIMER_SET_PRETIME_WDOG,
+ pretimeout * 1000, 0, 0, 0, 0, 0, &res);
+ if (res.a0)
+ return -EACCES;
+
+ wdog->pretimeout = pretimeout;
+
+ return 0;
+}
+
+static int imx_sc_wdt_notify(struct notifier_block *nb,
+ unsigned long event, void *group)
+{
+ struct imx_sc_wdt_device *imx_sc_wdd =
+ container_of(nb,
+ struct imx_sc_wdt_device,
+ wdt_notifier);
+
+ if (event & SC_IRQ_WDOG &&
+ *(u8 *)group == SC_IRQ_GROUP_WDOG)
+ watchdog_notify_pretimeout(&imx_sc_wdd->wdd);
+
+ return 0;
+}
+
+static void imx_sc_wdt_action(void *data)
+{
+ struct notifier_block *wdt_notifier = data;
+
+ imx_scu_irq_unregister_notifier(wdt_notifier);
+ imx_scu_irq_group_enable(SC_IRQ_GROUP_WDOG,
+ SC_IRQ_WDOG,
+ false);
+}
+
static const struct watchdog_ops imx_sc_wdt_ops = {
.owner = THIS_MODULE,
.start = imx_sc_wdt_start,
.stop = imx_sc_wdt_stop,
.ping = imx_sc_wdt_ping,
.set_timeout = imx_sc_wdt_set_timeout,
+ .set_pretimeout = imx_sc_wdt_set_pretimeout,
};
-static const struct watchdog_info imx_sc_wdt_info = {
+static struct watchdog_info imx_sc_wdt_info = {
.identity = "i.MX SC watchdog timer",
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
- WDIOF_MAGICCLOSE | WDIOF_PRETIMEOUT,
+ WDIOF_MAGICCLOSE,
};
static int imx_sc_wdt_probe(struct platform_device *pdev)
{
+ struct imx_sc_wdt_device *imx_sc_wdd;
+ struct watchdog_device *wdog;
struct device *dev = &pdev->dev;
- struct watchdog_device *imx_sc_wdd;
int ret;
imx_sc_wdd = devm_kzalloc(dev, sizeof(*imx_sc_wdd), GFP_KERNEL);
@@ -111,42 +162,70 @@ static int imx_sc_wdt_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, imx_sc_wdd);
- imx_sc_wdd->info = &imx_sc_wdt_info;
- imx_sc_wdd->ops = &imx_sc_wdt_ops;
- imx_sc_wdd->min_timeout = 1;
- imx_sc_wdd->max_timeout = MAX_TIMEOUT;
- imx_sc_wdd->parent = dev;
- imx_sc_wdd->timeout = DEFAULT_TIMEOUT;
-
- watchdog_init_timeout(imx_sc_wdd, 0, dev);
- watchdog_stop_on_reboot(imx_sc_wdd);
- watchdog_stop_on_unregister(imx_sc_wdd);
+ wdog = &imx_sc_wdd->wdd;
+ wdog->info = &imx_sc_wdt_info;
+ wdog->ops = &imx_sc_wdt_ops;
+ wdog->min_timeout = 1;
+ wdog->max_timeout = MAX_TIMEOUT;
+ wdog->parent = dev;
+ wdog->timeout = DEFAULT_TIMEOUT;
+
+ watchdog_init_timeout(wdog, 0, dev);
+ watchdog_stop_on_reboot(wdog);
+ watchdog_stop_on_unregister(wdog);
+
+ ret = devm_watchdog_register_device(dev, wdog);
+
+ if (ret) {
+ dev_err(dev, "Failed to register watchdog device\n");
+ return ret;
+ }
+
+ ret = imx_scu_irq_group_enable(SC_IRQ_GROUP_WDOG,
+ SC_IRQ_WDOG,
+ true);
+ if (ret) {
+ dev_warn(dev, "Enable irq failed, pretimeout NOT supported\n");
+ return 0;
+ }
- ret = devm_watchdog_register_device(dev, imx_sc_wdd);
+ imx_sc_wdd->wdt_notifier.notifier_call = imx_sc_wdt_notify;
+ ret = imx_scu_irq_register_notifier(&imx_sc_wdd->wdt_notifier);
if (ret) {
- dev_err(dev, "Failed to register watchdog device\n");
- return ret;
+ imx_scu_irq_group_enable(SC_IRQ_GROUP_WDOG,
+ SC_IRQ_WDOG,
+ false);
+ dev_warn(dev,
+ "Register irq notifier failed, pretimeout NOT supported\n");
+ return 0;
}
+ ret = devm_add_action_or_reset(dev, imx_sc_wdt_action,
+ &imx_sc_wdd->wdt_notifier);
+ if (!ret)
+ imx_sc_wdt_info.options |= WDIOF_PRETIMEOUT;
+ else
+ dev_warn(dev, "Add action failed, pretimeout NOT supported\n");
+
return 0;
}
static int __maybe_unused imx_sc_wdt_suspend(struct device *dev)
{
- struct watchdog_device *imx_sc_wdd = dev_get_drvdata(dev);
+ struct imx_sc_wdt_device *imx_sc_wdd = dev_get_drvdata(dev);
- if (watchdog_active(imx_sc_wdd))
- imx_sc_wdt_stop(imx_sc_wdd);
+ if (watchdog_active(&imx_sc_wdd->wdd))
+ imx_sc_wdt_stop(&imx_sc_wdd->wdd);
return 0;
}
static int __maybe_unused imx_sc_wdt_resume(struct device *dev)
{
- struct watchdog_device *imx_sc_wdd = dev_get_drvdata(dev);
+ struct imx_sc_wdt_device *imx_sc_wdd = dev_get_drvdata(dev);
- if (watchdog_active(imx_sc_wdd))
- imx_sc_wdt_start(imx_sc_wdd);
+ if (watchdog_active(&imx_sc_wdd->wdd))
+ imx_sc_wdt_start(&imx_sc_wdd->wdd);
return 0;
}
diff --git a/drivers/watchdog/intel-mid_wdt.c b/drivers/watchdog/intel-mid_wdt.c
index b2463f8276e6..2cdbd37c700c 100644
--- a/drivers/watchdog/intel-mid_wdt.c
+++ b/drivers/watchdog/intel-mid_wdt.c
@@ -161,10 +161,8 @@ static int mid_wdt_probe(struct platform_device *pdev)
set_bit(WDOG_HW_RUNNING, &wdt_dev->status);
ret = devm_watchdog_register_device(dev, wdt_dev);
- if (ret) {
- dev_err(dev, "error registering watchdog device\n");
+ if (ret)
return ret;
- }
dev_info(dev, "Intel MID watchdog device probed\n");
diff --git a/drivers/watchdog/jz4740_wdt.c b/drivers/watchdog/jz4740_wdt.c
index 313358b2e0b1..d4a90916dd38 100644
--- a/drivers/watchdog/jz4740_wdt.c
+++ b/drivers/watchdog/jz4740_wdt.c
@@ -4,6 +4,7 @@
* JZ4740 Watchdog driver
*/
+#include <linux/mfd/ingenic-tcu.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -19,23 +20,16 @@
#include <asm/mach-jz4740/timer.h>
-#define JZ_REG_WDT_TIMER_DATA 0x0
-#define JZ_REG_WDT_COUNTER_ENABLE 0x4
-#define JZ_REG_WDT_TIMER_COUNTER 0x8
-#define JZ_REG_WDT_TIMER_CONTROL 0xC
-
#define JZ_WDT_CLOCK_PCLK 0x1
#define JZ_WDT_CLOCK_RTC 0x2
#define JZ_WDT_CLOCK_EXT 0x4
-#define JZ_WDT_CLOCK_DIV_SHIFT 3
-
-#define JZ_WDT_CLOCK_DIV_1 (0 << JZ_WDT_CLOCK_DIV_SHIFT)
-#define JZ_WDT_CLOCK_DIV_4 (1 << JZ_WDT_CLOCK_DIV_SHIFT)
-#define JZ_WDT_CLOCK_DIV_16 (2 << JZ_WDT_CLOCK_DIV_SHIFT)
-#define JZ_WDT_CLOCK_DIV_64 (3 << JZ_WDT_CLOCK_DIV_SHIFT)
-#define JZ_WDT_CLOCK_DIV_256 (4 << JZ_WDT_CLOCK_DIV_SHIFT)
-#define JZ_WDT_CLOCK_DIV_1024 (5 << JZ_WDT_CLOCK_DIV_SHIFT)
+#define JZ_WDT_CLOCK_DIV_1 (0 << TCU_TCSR_PRESCALE_LSB)
+#define JZ_WDT_CLOCK_DIV_4 (1 << TCU_TCSR_PRESCALE_LSB)
+#define JZ_WDT_CLOCK_DIV_16 (2 << TCU_TCSR_PRESCALE_LSB)
+#define JZ_WDT_CLOCK_DIV_64 (3 << TCU_TCSR_PRESCALE_LSB)
+#define JZ_WDT_CLOCK_DIV_256 (4 << TCU_TCSR_PRESCALE_LSB)
+#define JZ_WDT_CLOCK_DIV_1024 (5 << TCU_TCSR_PRESCALE_LSB)
#define DEFAULT_HEARTBEAT 5
#define MAX_HEARTBEAT 2048
@@ -63,7 +57,7 @@ static int jz4740_wdt_ping(struct watchdog_device *wdt_dev)
{
struct jz4740_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev);
- writew(0x0, drvdata->base + JZ_REG_WDT_TIMER_COUNTER);
+ writew(0x0, drvdata->base + TCU_REG_WDT_TCNT);
return 0;
}
@@ -74,6 +68,7 @@ static int jz4740_wdt_set_timeout(struct watchdog_device *wdt_dev,
unsigned int rtc_clk_rate;
unsigned int timeout_value;
unsigned short clock_div = JZ_WDT_CLOCK_DIV_1;
+ u8 tcer;
rtc_clk_rate = clk_get_rate(drvdata->rtc_clk);
@@ -86,18 +81,19 @@ static int jz4740_wdt_set_timeout(struct watchdog_device *wdt_dev,
break;
}
timeout_value >>= 2;
- clock_div += (1 << JZ_WDT_CLOCK_DIV_SHIFT);
+ clock_div += (1 << TCU_TCSR_PRESCALE_LSB);
}
- writeb(0x0, drvdata->base + JZ_REG_WDT_COUNTER_ENABLE);
- writew(clock_div, drvdata->base + JZ_REG_WDT_TIMER_CONTROL);
+ tcer = readb(drvdata->base + TCU_REG_WDT_TCER);
+ writeb(0x0, drvdata->base + TCU_REG_WDT_TCER);
+ writew(clock_div, drvdata->base + TCU_REG_WDT_TCSR);
- writew((u16)timeout_value, drvdata->base + JZ_REG_WDT_TIMER_DATA);
- writew(0x0, drvdata->base + JZ_REG_WDT_TIMER_COUNTER);
- writew(clock_div | JZ_WDT_CLOCK_RTC,
- drvdata->base + JZ_REG_WDT_TIMER_CONTROL);
+ writew((u16)timeout_value, drvdata->base + TCU_REG_WDT_TDR);
+ writew(0x0, drvdata->base + TCU_REG_WDT_TCNT);
+ writew(clock_div | JZ_WDT_CLOCK_RTC, drvdata->base + TCU_REG_WDT_TCSR);
- writeb(0x1, drvdata->base + JZ_REG_WDT_COUNTER_ENABLE);
+ if (tcer & TCU_WDT_TCER_TCEN)
+ writeb(TCU_WDT_TCER_TCEN, drvdata->base + TCU_REG_WDT_TCER);
wdt_dev->timeout = new_timeout;
return 0;
@@ -105,9 +101,18 @@ static int jz4740_wdt_set_timeout(struct watchdog_device *wdt_dev,
static int jz4740_wdt_start(struct watchdog_device *wdt_dev)
{
+ struct jz4740_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev);
+ u8 tcer;
+
+ tcer = readb(drvdata->base + TCU_REG_WDT_TCER);
+
jz4740_timer_enable_watchdog();
jz4740_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
+ /* Start watchdog if it wasn't started already */
+ if (!(tcer & TCU_WDT_TCER_TCEN))
+ writeb(TCU_WDT_TCER_TCEN, drvdata->base + TCU_REG_WDT_TCER);
+
return 0;
}
@@ -115,7 +120,7 @@ static int jz4740_wdt_stop(struct watchdog_device *wdt_dev)
{
struct jz4740_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev);
- writeb(0x0, drvdata->base + JZ_REG_WDT_COUNTER_ENABLE);
+ writeb(0x0, drvdata->base + TCU_REG_WDT_TCER);
jz4740_timer_disable_watchdog();
return 0;
@@ -187,11 +192,7 @@ static int jz4740_wdt_probe(struct platform_device *pdev)
return PTR_ERR(drvdata->rtc_clk);
}
- ret = devm_watchdog_register_device(dev, &drvdata->wdt);
- if (ret < 0)
- return ret;
-
- return 0;
+ return devm_watchdog_register_device(dev, &drvdata->wdt);
}
static struct platform_driver jz4740_wdt_driver = {
diff --git a/drivers/watchdog/ks8695_wdt.c b/drivers/watchdog/ks8695_wdt.c
index 0565cf30017b..1550ce3c5702 100644
--- a/drivers/watchdog/ks8695_wdt.c
+++ b/drivers/watchdog/ks8695_wdt.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Watchdog driver for Kendin/Micrel KS8695.
*
* (C) 2007 Andrew Victor
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/watchdog/lantiq_wdt.c b/drivers/watchdog/lantiq_wdt.c
index 4caf02ba5d49..6fab504af88b 100644
--- a/drivers/watchdog/lantiq_wdt.c
+++ b/drivers/watchdog/lantiq_wdt.c
@@ -1,7 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
- * 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.
*
* Copyright (C) 2010 John Crispin <john@phrozen.org>
* Copyright (C) 2017 Hauke Mehrtens <hauke@hauke-m.de>
diff --git a/drivers/watchdog/loongson1_wdt.c b/drivers/watchdog/loongson1_wdt.c
index c8c2b8a88fc2..bb3d075c0633 100644
--- a/drivers/watchdog/loongson1_wdt.c
+++ b/drivers/watchdog/loongson1_wdt.c
@@ -132,10 +132,8 @@ static int ls1x_wdt_probe(struct platform_device *pdev)
watchdog_set_drvdata(ls1x_wdt, drvdata);
err = devm_watchdog_register_device(dev, &drvdata->wdt);
- if (err) {
- dev_err(dev, "failed to register watchdog device\n");
+ if (err)
return err;
- }
platform_set_drvdata(pdev, drvdata);
diff --git a/drivers/watchdog/lpc18xx_wdt.c b/drivers/watchdog/lpc18xx_wdt.c
index 0e82abd71d35..78cf11c94941 100644
--- a/drivers/watchdog/lpc18xx_wdt.c
+++ b/drivers/watchdog/lpc18xx_wdt.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* NXP LPC18xx Watchdog Timer (WDT)
*
* Copyright (c) 2015 Ariel D'Alessandro <ariel@vanguardiasur.com>
*
- * 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.
- *
* Notes
* -----
* The Watchdog consists of a fixed divide-by-4 clock pre-scaler and a 24-bit
diff --git a/drivers/watchdog/max77620_wdt.c b/drivers/watchdog/max77620_wdt.c
index 3ca6b9337932..be6a53c30002 100644
--- a/drivers/watchdog/max77620_wdt.c
+++ b/drivers/watchdog/max77620_wdt.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Maxim MAX77620 Watchdog Driver
*
* Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved.
*
* Author: Laxman Dewangan <ldewangan@nvidia.com>
- *
- * 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.
*/
#include <linux/err.h>
@@ -185,13 +182,7 @@ static int max77620_wdt_probe(struct platform_device *pdev)
watchdog_set_drvdata(wdt_dev, wdt);
watchdog_stop_on_unregister(wdt_dev);
- ret = devm_watchdog_register_device(dev, wdt_dev);
- if (ret < 0) {
- dev_err(dev, "watchdog registration failed: %d\n", ret);
- return ret;
- }
-
- return 0;
+ return devm_watchdog_register_device(dev, wdt_dev);
}
static const struct platform_device_id max77620_wdt_devtype[] = {
diff --git a/drivers/watchdog/mei_wdt.c b/drivers/watchdog/mei_wdt.c
index 8023cf28657a..5391bf3e6b11 100644
--- a/drivers/watchdog/mei_wdt.c
+++ b/drivers/watchdog/mei_wdt.c
@@ -384,10 +384,8 @@ static int mei_wdt_register(struct mei_wdt *wdt)
watchdog_stop_on_reboot(&wdt->wdd);
ret = watchdog_register_device(&wdt->wdd);
- if (ret) {
- dev_err(dev, "unable to register watchdog device = %d.\n", ret);
+ if (ret)
watchdog_set_drvdata(&wdt->wdd, NULL);
- }
wdt->state = MEI_WDT_IDLE;
@@ -539,38 +537,23 @@ static void dbgfs_unregister(struct mei_wdt *wdt)
wdt->dbgfs_dir = NULL;
}
-static int dbgfs_register(struct mei_wdt *wdt)
+static void dbgfs_register(struct mei_wdt *wdt)
{
- struct dentry *dir, *f;
+ struct dentry *dir;
dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
- if (!dir)
- return -ENOMEM;
-
wdt->dbgfs_dir = dir;
- f = debugfs_create_file("state", S_IRUSR, dir, wdt, &dbgfs_fops_state);
- if (!f)
- goto err;
- f = debugfs_create_file("activation", S_IRUSR,
- dir, wdt, &dbgfs_fops_activation);
- if (!f)
- goto err;
+ debugfs_create_file("state", S_IRUSR, dir, wdt, &dbgfs_fops_state);
- return 0;
-err:
- dbgfs_unregister(wdt);
- return -ENODEV;
+ debugfs_create_file("activation", S_IRUSR, dir, wdt,
+ &dbgfs_fops_activation);
}
#else
static inline void dbgfs_unregister(struct mei_wdt *wdt) {}
-
-static inline int dbgfs_register(struct mei_wdt *wdt)
-{
- return 0;
-}
+static inline void dbgfs_register(struct mei_wdt *wdt) {}
#endif /* CONFIG_DEBUG_FS */
static int mei_wdt_probe(struct mei_cl_device *cldev,
@@ -623,8 +606,7 @@ static int mei_wdt_probe(struct mei_cl_device *cldev,
if (ret)
goto err_disable;
- if (dbgfs_register(wdt))
- dev_warn(&cldev->dev, "cannot register debugfs\n");
+ dbgfs_register(wdt);
return 0;
diff --git a/drivers/watchdog/mena21_wdt.c b/drivers/watchdog/mena21_wdt.c
index e9ca4e0e25dc..99d2359d5a8a 100644
--- a/drivers/watchdog/mena21_wdt.c
+++ b/drivers/watchdog/mena21_wdt.c
@@ -190,10 +190,8 @@ static int a21_wdt_probe(struct platform_device *pdev)
dev_set_drvdata(dev, drv);
ret = devm_watchdog_register_device(dev, &a21_wdt);
- if (ret) {
- dev_err(dev, "Cannot register watchdog device\n");
+ if (ret)
return ret;
- }
dev_info(dev, "MEN A21 watchdog timer driver enabled\n");
diff --git a/drivers/watchdog/menf21bmc_wdt.c b/drivers/watchdog/menf21bmc_wdt.c
index 7766d7361d3b..81ebdfc371f4 100644
--- a/drivers/watchdog/menf21bmc_wdt.c
+++ b/drivers/watchdog/menf21bmc_wdt.c
@@ -152,10 +152,8 @@ static int menf21bmc_wdt_probe(struct platform_device *pdev)
}
ret = devm_watchdog_register_device(dev, &drv_data->wdt);
- if (ret) {
- dev_err(dev, "failed to register Watchdog device\n");
+ if (ret)
return ret;
- }
dev_info(dev, "MEN 14F021P00 BMC Watchdog device enabled\n");
diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c
index b6ffad421bd0..3fc457bc16db 100644
--- a/drivers/watchdog/mpc8xxx_wdt.c
+++ b/drivers/watchdog/mpc8xxx_wdt.c
@@ -201,11 +201,8 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev)
ddata->wdd.timeout = ddata->wdd.min_timeout;
ret = devm_watchdog_register_device(dev, &ddata->wdd);
- if (ret) {
- dev_err(dev, "cannot register watchdog device (err=%d)\n",
- ret);
+ if (ret)
return ret;
- }
dev_info(dev,
"WDT driver for MPC8xxx initialized. mode:%s timeout=%d sec\n",
diff --git a/drivers/watchdog/mt7621_wdt.c b/drivers/watchdog/mt7621_wdt.c
index cbb3c0dde136..a8aa3522cfda 100644
--- a/drivers/watchdog/mt7621_wdt.c
+++ b/drivers/watchdog/mt7621_wdt.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Ralink MT7621/MT7628 built-in hardware watchdog timer
*
* Copyright (C) 2014 John Crispin <john@phrozen.org>
*
* This driver was based on: drivers/watchdog/rt2880_wdt.c
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/watchdog/mv64x60_wdt.c b/drivers/watchdog/mv64x60_wdt.c
index c785f4f0a196..74bf7144a970 100644
--- a/drivers/watchdog/mv64x60_wdt.c
+++ b/drivers/watchdog/mv64x60_wdt.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* mv64x60_wdt.c - MV64X60 (Marvell Discovery) watchdog userspace interface
*
@@ -9,10 +10,7 @@
*
* Derived from mpc8xx_wdt.c, with the following copyright.
*
- * 2002 (c) Florian Schirmer <jolt@tuxbox.org> 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.
+ * 2002 (c) Florian Schirmer <jolt@tuxbox.org>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/watchdog/ni903x_wdt.c b/drivers/watchdog/ni903x_wdt.c
index 60f5608af2a8..4cebad324b20 100644
--- a/drivers/watchdog/ni903x_wdt.c
+++ b/drivers/watchdog/ni903x_wdt.c
@@ -211,10 +211,8 @@ static int ni903x_acpi_add(struct acpi_device *device)
watchdog_init_timeout(wdd, timeout, dev);
ret = watchdog_register_device(wdd);
- if (ret) {
- dev_err(dev, "failed to register watchdog\n");
+ if (ret)
return ret;
- }
/* Switch from boot mode to user mode */
outb(NIWD_CONTROL_RESET | NIWD_CONTROL_MODE,
diff --git a/drivers/watchdog/nic7018_wdt.c b/drivers/watchdog/nic7018_wdt.c
index 2e1a2a3d4ec9..2a46cc662943 100644
--- a/drivers/watchdog/nic7018_wdt.c
+++ b/drivers/watchdog/nic7018_wdt.c
@@ -210,7 +210,6 @@ static int nic7018_probe(struct platform_device *pdev)
ret = watchdog_register_device(wdd);
if (ret) {
outb(LOCK, wdt->io_base + WDT_REG_LOCK);
- dev_err(dev, "failed to register watchdog\n");
return ret;
}
diff --git a/drivers/watchdog/npcm_wdt.c b/drivers/watchdog/npcm_wdt.c
index 9d6c1689b12c..9c773c3d6d5d 100644
--- a/drivers/watchdog/npcm_wdt.c
+++ b/drivers/watchdog/npcm_wdt.c
@@ -220,10 +220,8 @@ static int npcm_wdt_probe(struct platform_device *pdev)
return ret;
ret = devm_watchdog_register_device(dev, &wdt->wdd);
- if (ret) {
- dev_err(dev, "failed to register watchdog\n");
+ if (ret)
return ret;
- }
dev_info(dev, "NPCM watchdog driver enabled\n");
diff --git a/drivers/watchdog/nv_tco.h b/drivers/watchdog/nv_tco.h
index c2d1d04e055b..d325e528010f 100644
--- a/drivers/watchdog/nv_tco.h
+++ b/drivers/watchdog/nv_tco.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
/*
* nv_tco: TCO timer driver for nVidia chipsets.
*
@@ -10,11 +11,6 @@
* Reserved.
* http://www.kernelconcepts.de
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* Neither kernel concepts nor Nils Faerber admit liability nor provide
* warranty for any of this software. This material is provided
* "AS-IS" and at no charge.
diff --git a/drivers/watchdog/octeon-wdt-main.c b/drivers/watchdog/octeon-wdt-main.c
index 0ec419a3f7ed..fde9e739b436 100644
--- a/drivers/watchdog/octeon-wdt-main.c
+++ b/drivers/watchdog/octeon-wdt-main.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Octeon Watchdog driver
*
@@ -10,22 +11,12 @@
* (c) Copyright 1996-1997 Alan Cox <alan@lxorguk.ukuu.org.uk>,
* All Rights Reserved.
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
* warranty for any of this software. This material is provided
* "AS-IS" and at no charge.
*
* (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- *
* The OCTEON watchdog has a maximum timeout of 2^32 * io_clock.
* For most systems this is less than 10 seconds, so to allow for
* software to request longer watchdog heartbeats, we maintain software
diff --git a/drivers/watchdog/of_xilinx_wdt.c b/drivers/watchdog/of_xilinx_wdt.c
index 03786992b701..7fe4f7c3f7ce 100644
--- a/drivers/watchdog/of_xilinx_wdt.c
+++ b/drivers/watchdog/of_xilinx_wdt.c
@@ -238,10 +238,8 @@ static int xwdt_probe(struct platform_device *pdev)
}
rc = devm_watchdog_register_device(dev, xilinx_wdt_wdd);
- if (rc) {
- dev_err(dev, "Cannot register watchdog (err=%d)\n", rc);
+ if (rc)
return rc;
- }
clk_disable(xdev->clk);
diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c
index d49688d93f6a..9b91882fe3c4 100644
--- a/drivers/watchdog/omap_wdt.c
+++ b/drivers/watchdog/omap_wdt.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* omap_wdt.c
*
@@ -6,10 +7,7 @@
* Author: MontaVista Software, Inc.
* <gdavis@mvista.com> or <source@mvista.com>
*
- * 2003 (c) MontaVista Software, 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.
+ * 2003 (c) MontaVista Software, Inc.
*
* History:
*
diff --git a/drivers/watchdog/omap_wdt.h b/drivers/watchdog/omap_wdt.h
index 42f31ec5e90d..950b4643f3e7 100644
--- a/drivers/watchdog/omap_wdt.h
+++ b/drivers/watchdog/omap_wdt.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
/*
* linux/drivers/char/watchdog/omap_wdt.h
*
@@ -5,26 +6,6 @@
* OMAP Watchdog timer register definitions
*
* Copyright (C) 2004 Texas Instruments.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _OMAP_WATCHDOG_H
diff --git a/drivers/watchdog/pc87413_wdt.c b/drivers/watchdog/pc87413_wdt.c
index ca21d6c240a3..2af1a8b3f973 100644
--- a/drivers/watchdog/pc87413_wdt.c
+++ b/drivers/watchdog/pc87413_wdt.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* NS pc87413-wdt Watchdog Timer driver for Linux 2.6.x.x
*
@@ -6,11 +7,6 @@
* (C) Copyright 2006 Sven Anders, <anders@anduras.de>
* and Marcus Junker, <junker@anduras.de>
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* Neither Sven Anders, Marcus Junker nor ANDURAS AG
* admit liability nor provide warranty for any of this software.
* This material is provided "AS-IS" and at no charge.
diff --git a/drivers/watchdog/pcwd_pci.c b/drivers/watchdog/pcwd_pci.c
index 5773d2591d3f..e30c1f762045 100644
--- a/drivers/watchdog/pcwd_pci.c
+++ b/drivers/watchdog/pcwd_pci.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Berkshire PCI-PC Watchdog Card Driver
*
@@ -10,11 +11,6 @@
* Matt Domsch <Matt_Domsch@dell.com>,
* Rob Radez <rob@osinvestor.com>
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
diff --git a/drivers/watchdog/pcwd_usb.c b/drivers/watchdog/pcwd_usb.c
index 5de6182dae33..6727f8ab2d18 100644
--- a/drivers/watchdog/pcwd_usb.c
+++ b/drivers/watchdog/pcwd_usb.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Berkshire USB-PC Watchdog Card Driver
*
@@ -10,11 +11,6 @@
* Rob Radez <rob@osinvestor.com>,
* Greg Kroah-Hartman <greg@kroah.com>
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
diff --git a/drivers/watchdog/pic32-dmt.c b/drivers/watchdog/pic32-dmt.c
index 4f2aca78f13a..f43062b3c4c8 100644
--- a/drivers/watchdog/pic32-dmt.c
+++ b/drivers/watchdog/pic32-dmt.c
@@ -212,10 +212,8 @@ static int pic32_dmt_probe(struct platform_device *pdev)
watchdog_set_drvdata(wdd, dmt);
ret = devm_watchdog_register_device(dev, wdd);
- if (ret) {
- dev_err(dev, "watchdog register failed, err %d\n", ret);
+ if (ret)
return ret;
- }
platform_set_drvdata(pdev, wdd);
return 0;
diff --git a/drivers/watchdog/pic32-wdt.c b/drivers/watchdog/pic32-wdt.c
index 5ecdd880f0b7..41715d68d9e9 100644
--- a/drivers/watchdog/pic32-wdt.c
+++ b/drivers/watchdog/pic32-wdt.c
@@ -221,10 +221,8 @@ static int pic32_wdt_drv_probe(struct platform_device *pdev)
watchdog_set_drvdata(wdd, wdt);
ret = devm_watchdog_register_device(dev, wdd);
- if (ret) {
- dev_err(dev, "watchdog register failed, err %d\n", ret);
+ if (ret)
return ret;
- }
platform_set_drvdata(pdev, wdd);
diff --git a/drivers/watchdog/pnx4008_wdt.c b/drivers/watchdog/pnx4008_wdt.c
index d9e03544aeae..7b446b696f2b 100644
--- a/drivers/watchdog/pnx4008_wdt.c
+++ b/drivers/watchdog/pnx4008_wdt.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* drivers/char/watchdog/pnx4008_wdt.c
*
@@ -11,10 +12,6 @@
* 2005-2006 (c) MontaVista Software, Inc.
*
* (C) 2012 Wolfram Sang, Pengutronix
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -221,10 +218,8 @@ static int pnx4008_wdt_probe(struct platform_device *pdev)
set_bit(WDOG_HW_RUNNING, &pnx4008_wdd.status);
ret = devm_watchdog_register_device(dev, &pnx4008_wdd);
- if (ret < 0) {
- dev_err(dev, "cannot register watchdog device\n");
+ if (ret < 0)
return ret;
- }
dev_info(dev, "heartbeat %d sec\n", pnx4008_wdd.timeout);
diff --git a/drivers/watchdog/qcom-wdt.c b/drivers/watchdog/qcom-wdt.c
index fc0f7e5de38d..7be7f87be28f 100644
--- a/drivers/watchdog/qcom-wdt.c
+++ b/drivers/watchdog/qcom-wdt.c
@@ -223,10 +223,8 @@ static int qcom_wdt_probe(struct platform_device *pdev)
watchdog_init_timeout(&wdt->wdd, 0, dev);
ret = devm_watchdog_register_device(dev, &wdt->wdd);
- if (ret) {
- dev_err(dev, "failed to register watchdog\n");
+ if (ret)
return ret;
- }
platform_set_drvdata(pdev, wdt);
return 0;
diff --git a/drivers/watchdog/rave-sp-wdt.c b/drivers/watchdog/rave-sp-wdt.c
index 35db173252f9..2c95615b6354 100644
--- a/drivers/watchdog/rave-sp-wdt.c
+++ b/drivers/watchdog/rave-sp-wdt.c
@@ -310,7 +310,6 @@ static int rave_sp_wdt_probe(struct platform_device *pdev)
ret = devm_watchdog_register_device(dev, wdd);
if (ret) {
- dev_err(dev, "Failed to register watchdog device\n");
rave_sp_wdt_stop(wdd);
return ret;
}
diff --git a/drivers/watchdog/renesas_wdt.c b/drivers/watchdog/renesas_wdt.c
index 565dbc1ec638..00662a8e039c 100644
--- a/drivers/watchdog/renesas_wdt.c
+++ b/drivers/watchdog/renesas_wdt.c
@@ -7,6 +7,7 @@
*/
#include <linux/bitops.h>
#include <linux/clk.h>
+#include <linux/delay.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -70,6 +71,15 @@ static int rwdt_init_timeout(struct watchdog_device *wdev)
return 0;
}
+static void rwdt_wait_cycles(struct rwdt_priv *priv, unsigned int cycles)
+{
+ unsigned int delay;
+
+ delay = DIV_ROUND_UP(cycles * 1000000, priv->clk_rate);
+
+ usleep_range(delay, 2 * delay);
+}
+
static int rwdt_start(struct watchdog_device *wdev)
{
struct rwdt_priv *priv = watchdog_get_drvdata(wdev);
@@ -80,6 +90,8 @@ static int rwdt_start(struct watchdog_device *wdev)
/* Stop the timer before we modify any register */
val = readb_relaxed(priv->base + RWTCSRA) & ~RWTCSRA_TME;
rwdt_write(priv, val, RWTCSRA);
+ /* Delay 2 cycles before setting watchdog counter */
+ rwdt_wait_cycles(priv, 2);
rwdt_init_timeout(wdev);
rwdt_write(priv, priv->cks, RWTCSRA);
@@ -98,6 +110,8 @@ static int rwdt_stop(struct watchdog_device *wdev)
struct rwdt_priv *priv = watchdog_get_drvdata(wdev);
rwdt_write(priv, priv->cks, RWTCSRA);
+ /* Delay 3 cycles before disabling module clock */
+ rwdt_wait_cycles(priv, 3);
pm_runtime_put(wdev->parent);
return 0;
@@ -175,15 +189,16 @@ static inline bool rwdt_blacklisted(struct device *dev) { return false; }
static int rwdt_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
struct rwdt_priv *priv;
struct clk *clk;
unsigned long clks_per_sec;
int ret, i;
- if (rwdt_blacklisted(&pdev->dev))
+ if (rwdt_blacklisted(dev))
return -ENODEV;
- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -191,16 +206,16 @@ static int rwdt_probe(struct platform_device *pdev)
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
- clk = devm_clk_get(&pdev->dev, NULL);
+ clk = devm_clk_get(dev, NULL);
if (IS_ERR(clk))
return PTR_ERR(clk);
- pm_runtime_enable(&pdev->dev);
- pm_runtime_get_sync(&pdev->dev);
+ pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
priv->clk_rate = clk_get_rate(clk);
priv->wdev.bootstatus = (readb_relaxed(priv->base + RWTCSRA) &
RWTCSRA_WOVF) ? WDIOF_CARDRESET : 0;
- pm_runtime_put(&pdev->dev);
+ pm_runtime_put(dev);
if (!priv->clk_rate) {
ret = -ENOENT;
@@ -216,14 +231,14 @@ static int rwdt_probe(struct platform_device *pdev)
}
if (i < 0) {
- dev_err(&pdev->dev, "Can't find suitable clock divider\n");
+ dev_err(dev, "Can't find suitable clock divider\n");
ret = -ERANGE;
goto out_pm_disable;
}
priv->wdev.info = &rwdt_ident;
priv->wdev.ops = &rwdt_ops;
- priv->wdev.parent = &pdev->dev;
+ priv->wdev.parent = dev;
priv->wdev.min_timeout = 1;
priv->wdev.max_timeout = DIV_BY_CLKS_PER_SEC(priv, 65536);
priv->wdev.timeout = min(priv->wdev.max_timeout, RWDT_DEFAULT_TIMEOUT);
@@ -235,7 +250,7 @@ static int rwdt_probe(struct platform_device *pdev)
watchdog_stop_on_unregister(&priv->wdev);
/* This overrides the default timeout only if DT configuration was found */
- watchdog_init_timeout(&priv->wdev, 0, &pdev->dev);
+ watchdog_init_timeout(&priv->wdev, 0, dev);
ret = watchdog_register_device(&priv->wdev);
if (ret < 0)
@@ -244,7 +259,7 @@ static int rwdt_probe(struct platform_device *pdev)
return 0;
out_pm_disable:
- pm_runtime_disable(&pdev->dev);
+ pm_runtime_disable(dev);
return ret;
}
diff --git a/drivers/watchdog/retu_wdt.c b/drivers/watchdog/retu_wdt.c
index 39cd51df2ffc..258dfcf9cbda 100644
--- a/drivers/watchdog/retu_wdt.c
+++ b/drivers/watchdog/retu_wdt.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Retu watchdog driver
*
@@ -5,15 +6,6 @@
*
* Based on code written by Amit Kucheria and Michael Buesch.
* Rewritten by Aaro Koskinen.
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License. See the file "COPYING" in the main directory of this
- * archive for more details.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/slab.h>
diff --git a/drivers/watchdog/rt2880_wdt.c b/drivers/watchdog/rt2880_wdt.c
index 905e60f45eec..49aff800824d 100644
--- a/drivers/watchdog/rt2880_wdt.c
+++ b/drivers/watchdog/rt2880_wdt.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Ralink RT288x/RT3xxx/MT76xx built-in hardware watchdog timer
*
@@ -5,10 +6,6 @@
* Copyright (C) 2013 John Crispin <john@phrozen.org>
*
* This driver was based on: drivers/watchdog/softdog.c
- *
- * 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.
*/
#include <linux/clk.h>
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c
index daf3bf0d86b8..2395f353e52d 100644
--- a/drivers/watchdog/s3c2410_wdt.c
+++ b/drivers/watchdog/s3c2410_wdt.c
@@ -606,10 +606,8 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
wdt->wdt_device.parent = dev;
ret = watchdog_register_device(&wdt->wdt_device);
- if (ret) {
- dev_err(dev, "cannot register watchdog (%d)\n", ret);
+ if (ret)
goto err_cpufreq;
- }
ret = s3c2410wdt_mask_and_disable_reset(wdt, false);
if (ret < 0)
diff --git a/drivers/watchdog/sa1100_wdt.c b/drivers/watchdog/sa1100_wdt.c
index bfa035e1a75e..cbd8c957182f 100644
--- a/drivers/watchdog/sa1100_wdt.c
+++ b/drivers/watchdog/sa1100_wdt.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Watchdog driver for the SA11x0/PXA2xx
*
* (c) Copyright 2000 Oleg Drokin <green@crimea.edu>
* Based on SoftDog driver by Alan Cox <alan@lxorguk.ukuu.org.uk>
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* Neither Oleg Drokin nor iXcelerator.com admit liability nor provide
* warranty for any of this software. This material is provided
* "AS-IS" and at no charge.
diff --git a/drivers/watchdog/sama5d4_wdt.c b/drivers/watchdog/sama5d4_wdt.c
index b8da1bf21e12..d193a60430b2 100644
--- a/drivers/watchdog/sama5d4_wdt.c
+++ b/drivers/watchdog/sama5d4_wdt.c
@@ -110,9 +110,7 @@ static int sama5d4_wdt_set_timeout(struct watchdog_device *wdd,
u32 value = WDT_SEC2TICKS(timeout);
wdt->mr &= ~AT91_WDT_WDV;
- wdt->mr &= ~AT91_WDT_WDD;
wdt->mr |= AT91_WDT_SET_WDV(value);
- wdt->mr |= AT91_WDT_SET_WDD(value);
/*
* WDDIS has to be 0 when updating WDD/WDV. The datasheet states: When
@@ -248,7 +246,7 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
timeout = WDT_SEC2TICKS(wdd->timeout);
- wdt->mr |= AT91_WDT_SET_WDD(timeout);
+ wdt->mr |= AT91_WDT_SET_WDD(WDT_SEC2TICKS(MAX_WDT_TIMEOUT));
wdt->mr |= AT91_WDT_SET_WDV(timeout);
ret = sama5d4_wdt_init(wdt);
@@ -259,10 +257,8 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
watchdog_stop_on_unregister(wdd);
ret = devm_watchdog_register_device(dev, wdd);
- if (ret) {
- dev_err(dev, "failed to register watchdog device\n");
+ if (ret)
return ret;
- }
platform_set_drvdata(pdev, wdt);
@@ -279,7 +275,17 @@ static const struct of_device_id sama5d4_wdt_of_match[] = {
MODULE_DEVICE_TABLE(of, sama5d4_wdt_of_match);
#ifdef CONFIG_PM_SLEEP
-static int sama5d4_wdt_resume(struct device *dev)
+static int sama5d4_wdt_suspend_late(struct device *dev)
+{
+ struct sama5d4_wdt *wdt = dev_get_drvdata(dev);
+
+ if (watchdog_active(&wdt->wdd))
+ sama5d4_wdt_stop(&wdt->wdd);
+
+ return 0;
+}
+
+static int sama5d4_wdt_resume_early(struct device *dev)
{
struct sama5d4_wdt *wdt = dev_get_drvdata(dev);
@@ -290,12 +296,17 @@ static int sama5d4_wdt_resume(struct device *dev)
*/
sama5d4_wdt_init(wdt);
+ if (watchdog_active(&wdt->wdd))
+ sama5d4_wdt_start(&wdt->wdd);
+
return 0;
}
#endif
-static SIMPLE_DEV_PM_OPS(sama5d4_wdt_pm_ops, NULL,
- sama5d4_wdt_resume);
+static const struct dev_pm_ops sama5d4_wdt_pm_ops = {
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(sama5d4_wdt_suspend_late,
+ sama5d4_wdt_resume_early)
+};
static struct platform_driver sama5d4_wdt_driver = {
.probe = sama5d4_wdt_probe,
diff --git a/drivers/watchdog/sbc7240_wdt.c b/drivers/watchdog/sbc7240_wdt.c
index efc81b318939..12cdee7d5069 100644
--- a/drivers/watchdog/sbc7240_wdt.c
+++ b/drivers/watchdog/sbc7240_wdt.c
@@ -1,19 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* NANO7240 SBC Watchdog device driver
*
* Based on w83877f.c by Scott Jennings,
*
- * 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;
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
* (c) Copyright 2007 Gilles GIGAN <gilles.gigan@jcu.edu.au>
- *
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/watchdog/sbc8360.c b/drivers/watchdog/sbc8360.c
index 3396024e7b76..4f8b9912fc51 100644
--- a/drivers/watchdog/sbc8360.c
+++ b/drivers/watchdog/sbc8360.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* SBC8360 Watchdog driver
*
@@ -19,11 +20,6 @@
* (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>,
* All Rights Reserved.
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
* warranty for any of this software. This material is provided
* "AS-IS" and at no charge.
diff --git a/drivers/watchdog/sch311x_wdt.c b/drivers/watchdog/sch311x_wdt.c
index ed6e9fac5d74..3612f1df381b 100644
--- a/drivers/watchdog/sch311x_wdt.c
+++ b/drivers/watchdog/sch311x_wdt.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* sch311x_wdt.c - Driver for the SCH311x Super-I/O chips
* integrated watchdog.
*
* (c) Copyright 2008 Wim Van Sebroeck <wim@iguana.be>.
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
diff --git a/drivers/watchdog/smsc37b787_wdt.c b/drivers/watchdog/smsc37b787_wdt.c
index 13c817ea1d6a..f5713030d0f7 100644
--- a/drivers/watchdog/smsc37b787_wdt.c
+++ b/drivers/watchdog/smsc37b787_wdt.c
@@ -36,7 +36,7 @@
* mknod /dev/watchdog c 10 130
*
* For an example userspace keep-alive daemon, see:
- * Documentation/watchdog/wdt.txt
+ * Documentation/watchdog/wdt.rst
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/watchdog/softdog.c b/drivers/watchdog/softdog.c
index 060740625485..3e4885c1545e 100644
--- a/drivers/watchdog/softdog.c
+++ b/drivers/watchdog/softdog.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* SoftDog: A Software Watchdog Device
*
* (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>,
* All Rights Reserved.
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
* warranty for any of this software. This material is provided
* "AS-IS" and at no charge.
diff --git a/drivers/watchdog/sp5100_tco.c b/drivers/watchdog/sp5100_tco.c
index cd4430ff9b1c..93bd302ae7c5 100644
--- a/drivers/watchdog/sp5100_tco.c
+++ b/drivers/watchdog/sp5100_tco.c
@@ -402,10 +402,8 @@ static int sp5100_tco_probe(struct platform_device *pdev)
return ret;
ret = devm_watchdog_register_device(dev, wdd);
- if (ret) {
- dev_err(dev, "cannot register watchdog device (err=%d)\n", ret);
+ if (ret)
return ret;
- }
/* Show module parameters */
dev_info(dev, "initialized. heartbeat=%d sec (nowayout=%d)\n",
diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c
index 072986d461b7..53e04926a7b2 100644
--- a/drivers/watchdog/sp805_wdt.c
+++ b/drivers/watchdog/sp805_wdt.c
@@ -288,11 +288,8 @@ sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id)
}
ret = watchdog_register_device(&wdt->wdd);
- if (ret) {
- dev_err(&adev->dev, "watchdog_register_device() failed: %d\n",
- ret);
+ if (ret)
goto err;
- }
amba_set_drvdata(adev, wdt);
dev_info(&adev->dev, "registration successful\n");
diff --git a/drivers/watchdog/sprd_wdt.c b/drivers/watchdog/sprd_wdt.c
index 916fb3f96bdc..edba4e278685 100644
--- a/drivers/watchdog/sprd_wdt.c
+++ b/drivers/watchdog/sprd_wdt.c
@@ -320,7 +320,6 @@ static int sprd_wdt_probe(struct platform_device *pdev)
ret = devm_watchdog_register_device(dev, &wdt->wdd);
if (ret) {
sprd_wdt_disable(wdt);
- dev_err(dev, "failed to register watchdog\n");
return ret;
}
platform_set_drvdata(pdev, wdt);
diff --git a/drivers/watchdog/st_lpc_wdt.c b/drivers/watchdog/st_lpc_wdt.c
index 7a90184eb950..14ab6559c748 100644
--- a/drivers/watchdog/st_lpc_wdt.c
+++ b/drivers/watchdog/st_lpc_wdt.c
@@ -228,10 +228,8 @@ static int st_wdog_probe(struct platform_device *pdev)
return ret;
ret = devm_watchdog_register_device(dev, &st_wdog_dev);
- if (ret) {
- dev_err(dev, "Unable to register watchdog\n");
+ if (ret)
return ret;
- }
st_wdog_setup(st_wdog, true);
diff --git a/drivers/watchdog/stm32_iwdg.c b/drivers/watchdog/stm32_iwdg.c
index d569a3634d9b..a3a329011a06 100644
--- a/drivers/watchdog/stm32_iwdg.c
+++ b/drivers/watchdog/stm32_iwdg.c
@@ -263,10 +263,8 @@ static int stm32_iwdg_probe(struct platform_device *pdev)
watchdog_init_timeout(wdd, 0, dev);
ret = devm_watchdog_register_device(dev, wdd);
- if (ret) {
- dev_err(dev, "failed to register watchdog device\n");
+ if (ret)
return ret;
- }
platform_set_drvdata(pdev, wdt);
diff --git a/drivers/watchdog/stmp3xxx_rtc_wdt.c b/drivers/watchdog/stmp3xxx_rtc_wdt.c
index 671f4ba7b4ed..7caf3aa71c6a 100644
--- a/drivers/watchdog/stmp3xxx_rtc_wdt.c
+++ b/drivers/watchdog/stmp3xxx_rtc_wdt.c
@@ -98,10 +98,8 @@ static int stmp3xxx_wdt_probe(struct platform_device *pdev)
stmp3xxx_wdd.parent = dev;
ret = devm_watchdog_register_device(dev, &stmp3xxx_wdd);
- if (ret < 0) {
- dev_err(dev, "cannot register watchdog device\n");
+ if (ret < 0)
return ret;
- }
if (register_reboot_notifier(&wdt_notifier))
dev_warn(dev, "cannot register reboot notifier\n");
diff --git a/drivers/watchdog/tegra_wdt.c b/drivers/watchdog/tegra_wdt.c
index a58b000acc4f..dfe06e506cad 100644
--- a/drivers/watchdog/tegra_wdt.c
+++ b/drivers/watchdog/tegra_wdt.c
@@ -219,10 +219,8 @@ static int tegra_wdt_probe(struct platform_device *pdev)
watchdog_stop_on_unregister(wdd);
ret = devm_watchdog_register_device(dev, wdd);
- if (ret) {
- dev_err(dev, "failed to register watchdog device\n");
+ if (ret)
return ret;
- }
platform_set_drvdata(pdev, wdt);
diff --git a/drivers/watchdog/ts4800_wdt.c b/drivers/watchdog/ts4800_wdt.c
index 9dc6d7f45806..c137ad2bd5c3 100644
--- a/drivers/watchdog/ts4800_wdt.c
+++ b/drivers/watchdog/ts4800_wdt.c
@@ -171,10 +171,8 @@ static int ts4800_wdt_probe(struct platform_device *pdev)
ts4800_wdt_stop(wdd);
ret = devm_watchdog_register_device(dev, wdd);
- if (ret) {
- dev_err(dev, "failed to register watchdog device\n");
+ if (ret)
return ret;
- }
platform_set_drvdata(pdev, wdt);
diff --git a/drivers/watchdog/txx9wdt.c b/drivers/watchdog/txx9wdt.c
index fcb4da5b1f4c..89a54b6645bd 100644
--- a/drivers/watchdog/txx9wdt.c
+++ b/drivers/watchdog/txx9wdt.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* txx9wdt: A Hardware Watchdog Driver for TXx9 SoCs
*
* Copyright (C) 2007 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
- *
- * 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c
index 3a49ba9ea608..38b31e9947aa 100644
--- a/drivers/watchdog/w83627hf_wdt.c
+++ b/drivers/watchdog/w83627hf_wdt.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* w83627hf/thf WDT driver
*
@@ -17,11 +18,6 @@
* (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>,
* All Rights Reserved.
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
* warranty for any of this software. This material is provided
* "AS-IS" and at no charge.
diff --git a/drivers/watchdog/wafer5823wdt.c b/drivers/watchdog/wafer5823wdt.c
index 0a8073b419f8..6d2071a0590d 100644
--- a/drivers/watchdog/wafer5823wdt.c
+++ b/drivers/watchdog/wafer5823wdt.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* ICP Wafer 5823 Single Board Computer WDT driver
* http://www.icpamerica.com/wafer_5823.php
@@ -13,11 +14,6 @@
* (c) Copyright 1996-1997 Alan Cox <alan@lxorguk.ukuu.org.uk>,
* All Rights Reserved.
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
* warranty for any of this software. This material is provided
* "AS-IS" and at no charge.
diff --git a/drivers/watchdog/watchdog_core.c b/drivers/watchdog/watchdog_core.c
index 62be9e52a4de..21e8085b848b 100644
--- a/drivers/watchdog/watchdog_core.c
+++ b/drivers/watchdog/watchdog_core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* watchdog_core.c
*
@@ -16,11 +17,6 @@
* Satyam Sharma <satyam@infradead.org>
* Randy Dunlap <randy.dunlap@oracle.com>
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* Neither Alan Cox, CymruNet Ltd., Wim Van Sebroeck nor Iguana vzw.
* admit liability nor provide warranty for any of this software.
* This material is provided "AS-IS" and at no charge.
@@ -60,11 +56,10 @@ static DEFINE_MUTEX(wtd_deferred_reg_mutex);
static LIST_HEAD(wtd_deferred_reg_list);
static bool wtd_deferred_reg_done;
-static int watchdog_deferred_registration_add(struct watchdog_device *wdd)
+static void watchdog_deferred_registration_add(struct watchdog_device *wdd)
{
list_add_tail(&wdd->deferred,
&wtd_deferred_reg_list);
- return 0;
}
static void watchdog_deferred_registration_del(struct watchdog_device *wdd)
@@ -265,14 +260,23 @@ static int __watchdog_register_device(struct watchdog_device *wdd)
int watchdog_register_device(struct watchdog_device *wdd)
{
- int ret;
+ const char *dev_str;
+ int ret = 0;
mutex_lock(&wtd_deferred_reg_mutex);
if (wtd_deferred_reg_done)
ret = __watchdog_register_device(wdd);
else
- ret = watchdog_deferred_registration_add(wdd);
+ watchdog_deferred_registration_add(wdd);
mutex_unlock(&wtd_deferred_reg_mutex);
+
+ if (ret) {
+ dev_str = wdd->parent ? dev_name(wdd->parent) :
+ (const char *)wdd->info->identity;
+ pr_err("%s: failed to register watchdog device (err = %d)\n",
+ dev_str, ret);
+ }
+
return ret;
}
EXPORT_SYMBOL_GPL(watchdog_register_device);
diff --git a/drivers/watchdog/watchdog_core.h b/drivers/watchdog/watchdog_core.h
index 86ff962d1e15..a5062e8e0d13 100644
--- a/drivers/watchdog/watchdog_core.h
+++ b/drivers/watchdog/watchdog_core.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
/*
* watchdog_core.h
*
@@ -16,11 +17,6 @@
* Satyam Sharma <satyam@infradead.org>
* Randy Dunlap <randy.dunlap@oracle.com>
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* Neither Alan Cox, CymruNet Ltd., Wim Van Sebroeck nor Iguana vzw.
* admit liability nor provide warranty for any of this software.
* This material is provided "AS-IS" and at no charge.
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
index 252a7c7b6592..dbd2ad4c9294 100644
--- a/drivers/watchdog/watchdog_dev.c
+++ b/drivers/watchdog/watchdog_dev.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* watchdog_dev.c
*
@@ -20,11 +21,6 @@
* Satyam Sharma <satyam@infradead.org>
* Randy Dunlap <randy.dunlap@oracle.com>
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* Neither Alan Cox, CymruNet Ltd., Wim Van Sebroeck nor Iguana vzw.
* admit liability nor provide warranty for any of this software.
* This material is provided "AS-IS" and at no charge.
@@ -69,6 +65,7 @@ struct watchdog_core_data {
struct mutex lock;
ktime_t last_keepalive;
ktime_t last_hw_keepalive;
+ ktime_t open_deadline;
struct hrtimer timer;
struct kthread_work work;
unsigned long status; /* Internal status bits */
@@ -87,6 +84,19 @@ static struct kthread_worker *watchdog_kworker;
static bool handle_boot_enabled =
IS_ENABLED(CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED);
+static unsigned open_timeout = CONFIG_WATCHDOG_OPEN_TIMEOUT;
+
+static bool watchdog_past_open_deadline(struct watchdog_core_data *data)
+{
+ return ktime_after(ktime_get(), data->open_deadline);
+}
+
+static void watchdog_set_open_deadline(struct watchdog_core_data *data)
+{
+ data->open_deadline = open_timeout ?
+ ktime_get() + ktime_set(open_timeout, 0) : KTIME_MAX;
+}
+
static inline bool watchdog_need_worker(struct watchdog_device *wdd)
{
/* All variables in milli-seconds */
@@ -119,14 +129,15 @@ static ktime_t watchdog_next_keepalive(struct watchdog_device *wdd)
ktime_t virt_timeout;
unsigned int hw_heartbeat_ms;
- virt_timeout = ktime_add(wd_data->last_keepalive,
- ms_to_ktime(timeout_ms));
+ if (watchdog_active(wdd))
+ virt_timeout = ktime_add(wd_data->last_keepalive,
+ ms_to_ktime(timeout_ms));
+ else
+ virt_timeout = wd_data->open_deadline;
+
hw_heartbeat_ms = min_not_zero(timeout_ms, wdd->max_hw_heartbeat_ms);
keepalive_interval = ms_to_ktime(hw_heartbeat_ms / 2);
- if (!watchdog_active(wdd))
- return keepalive_interval;
-
/*
* To ensure that the watchdog times out wdd->timeout seconds
* after the most recent ping from userspace, the last
@@ -211,7 +222,13 @@ static bool watchdog_worker_should_ping(struct watchdog_core_data *wd_data)
{
struct watchdog_device *wdd = wd_data->wdd;
- return wdd && (watchdog_active(wdd) || watchdog_hw_running(wdd));
+ if (!wdd)
+ return false;
+
+ if (watchdog_active(wdd))
+ return true;
+
+ return watchdog_hw_running(wdd) && !watchdog_past_open_deadline(wd_data);
}
static void watchdog_ping_work(struct kthread_work *work)
@@ -824,6 +841,15 @@ static int watchdog_open(struct inode *inode, struct file *file)
if (!hw_running)
kref_get(&wd_data->kref);
+ /*
+ * open_timeout only applies for the first open from
+ * userspace. Set open_deadline to infinity so that the kernel
+ * will take care of an always-running hardware watchdog in
+ * case the device gets magic-closed or WDIOS_DISABLECARD is
+ * applied.
+ */
+ wd_data->open_deadline = KTIME_MAX;
+
/* dev/watchdog is a virtual (and thus non-seekable) filesystem */
return stream_open(inode, file);
@@ -983,6 +1009,7 @@ static int watchdog_cdev_register(struct watchdog_device *wdd, dev_t devno)
/* Record time of most recent heartbeat as 'just before now'. */
wd_data->last_hw_keepalive = ktime_sub(ktime_get(), 1);
+ watchdog_set_open_deadline(wd_data);
/*
* If the watchdog is running, prevent its driver from being unloaded,
@@ -1181,3 +1208,8 @@ module_param(handle_boot_enabled, bool, 0444);
MODULE_PARM_DESC(handle_boot_enabled,
"Watchdog core auto-updates boot enabled watchdogs before userspace takes over (default="
__MODULE_STRING(IS_ENABLED(CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED)) ")");
+
+module_param(open_timeout, uint, 0644);
+MODULE_PARM_DESC(open_timeout,
+ "Maximum time (in seconds, 0 means infinity) for userspace to take over a running watchdog (default="
+ __MODULE_STRING(CONFIG_WATCHDOG_OPEN_TIMEOUT) ")");
diff --git a/drivers/watchdog/wd501p.h b/drivers/watchdog/wd501p.h
index 0e3a497d5626..43a4d88fd363 100644
--- a/drivers/watchdog/wd501p.h
+++ b/drivers/watchdog/wd501p.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-1.0+ */
/*
* Industrial Computer Source WDT500/501 driver
*
@@ -11,12 +12,7 @@
*
* http://www.cymru.net
*
- * This driver is provided under the GNU General Public License,
- * incorporated herein by reference. The driver is provided without
- * warranty or support.
- *
* Release 0.04.
- *
*/
diff --git a/drivers/watchdog/wdat_wdt.c b/drivers/watchdog/wdat_wdt.c
index 430ee4e9b185..e7cf41aa26c3 100644
--- a/drivers/watchdog/wdat_wdt.c
+++ b/drivers/watchdog/wdat_wdt.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ACPI Hardware Watchdog (WDAT) driver.
*
* Copyright (C) 2016, Intel Corporation
* Author: Mika Westerberg <mika.westerberg@linux.intel.com>
- *
- * 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.
*/
#include <linux/acpi.h>
diff --git a/drivers/watchdog/wdt.c b/drivers/watchdog/wdt.c
index 3d2f5ed60e88..0650100fad00 100644
--- a/drivers/watchdog/wdt.c
+++ b/drivers/watchdog/wdt.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Industrial Computer Source WDT501 driver
*
* (c) Copyright 1996-1997 Alan Cox <alan@lxorguk.ukuu.org.uk>,
* All Rights Reserved.
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
* warranty for any of this software. This material is provided
* "AS-IS" and at no charge.
diff --git a/drivers/watchdog/wdt_pci.c b/drivers/watchdog/wdt_pci.c
index ff3a41f47127..66303ab95685 100644
--- a/drivers/watchdog/wdt_pci.c
+++ b/drivers/watchdog/wdt_pci.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Industrial Computer Source PCI-WDT500/501 driver
*
* (c) Copyright 1996-1997 Alan Cox <alan@lxorguk.ukuu.org.uk>,
* All Rights Reserved.
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
* warranty for any of this software. This material is provided
* "AS-IS" and at no charge.
diff --git a/drivers/watchdog/wm831x_wdt.c b/drivers/watchdog/wm831x_wdt.c
index 9b6565a3fab4..030ce240620d 100644
--- a/drivers/watchdog/wm831x_wdt.c
+++ b/drivers/watchdog/wm831x_wdt.c
@@ -267,14 +267,7 @@ static int wm831x_wdt_probe(struct platform_device *pdev)
}
}
- ret = devm_watchdog_register_device(dev, &driver_data->wdt);
- if (ret != 0) {
- dev_err(wm831x->dev, "watchdog_register_device() failed: %d\n",
- ret);
- return ret;
- }
-
- return 0;
+ return devm_watchdog_register_device(dev, &driver_data->wdt);
}
static struct platform_driver wm831x_wdt_driver = {
diff --git a/drivers/watchdog/xen_wdt.c b/drivers/watchdog/xen_wdt.c
index 2ba0a3c4523c..b343f421dc72 100644
--- a/drivers/watchdog/xen_wdt.c
+++ b/drivers/watchdog/xen_wdt.c
@@ -138,10 +138,8 @@ static int xen_wdt_probe(struct platform_device *pdev)
watchdog_stop_on_unregister(&xen_wdt_dev);
ret = devm_watchdog_register_device(dev, &xen_wdt_dev);
- if (ret) {
- dev_err(dev, "cannot register watchdog device (%d)\n", ret);
+ if (ret)
return ret;
- }
dev_info(dev, "initialized (timeout=%ds, nowayout=%d)\n",
xen_wdt_dev.timeout, nowayout);
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index ec6558b79e9d..79cc75096f42 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -10,21 +10,6 @@ config XEN_BALLOON
the system to expand the domain's memory allocation, or alternatively
return unneeded memory to the system.
-config XEN_SELFBALLOONING
- bool "Dynamically self-balloon kernel memory to target"
- depends on XEN && XEN_BALLOON && CLEANCACHE && SWAP && XEN_TMEM
- help
- Self-ballooning dynamically balloons available kernel memory driven
- by the current usage of anonymous memory ("committed AS") and
- controlled by various sysfs-settable parameters. Configuring
- FRONTSWAP is highly recommended; if it is not configured, self-
- ballooning is disabled by default. If FRONTSWAP is configured,
- frontswap-selfshrinking is enabled by default but can be disabled
- with the 'tmem.selfshrink=0' kernel boot parameter; and self-ballooning
- is enabled by default but can be disabled with the 'tmem.selfballooning=0'
- kernel boot parameter. Note that systems without a sufficiently
- large swap device should not enable self-ballooning.
-
config XEN_BALLOON_MEMORY_HOTPLUG
bool "Memory hotplug support for Xen balloon driver"
depends on XEN_BALLOON && MEMORY_HOTPLUG
@@ -191,14 +176,6 @@ config SWIOTLB_XEN
def_bool y
select SWIOTLB
-config XEN_TMEM
- tristate
- depends on !ARM && !ARM64
- default m if (CLEANCACHE || FRONTSWAP)
- help
- Shim to interface in-kernel Transcendent Memory hooks
- (e.g. cleancache and frontswap) to Xen tmem hypercalls.
-
config XEN_PCIDEV_BACKEND
tristate "Xen PCI-device backend driver"
depends on PCI && X86 && XEN
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
index ad3844d9f876..0c4efa6fe450 100644
--- a/drivers/xen/Makefile
+++ b/drivers/xen/Makefile
@@ -17,14 +17,12 @@ dom0-$(CONFIG_X86) += pcpu.o
obj-$(CONFIG_XEN_DOM0) += $(dom0-y)
obj-$(CONFIG_BLOCK) += biomerge.o
obj-$(CONFIG_XEN_BALLOON) += xen-balloon.o
-obj-$(CONFIG_XEN_SELFBALLOONING) += xen-selfballoon.o
obj-$(CONFIG_XEN_DEV_EVTCHN) += xen-evtchn.o
obj-$(CONFIG_XEN_GNTDEV) += xen-gntdev.o
obj-$(CONFIG_XEN_GRANT_DEV_ALLOC) += xen-gntalloc.o
obj-$(CONFIG_XENFS) += xenfs/
obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o
obj-$(CONFIG_XEN_PVHVM) += platform-pci.o
-obj-$(CONFIG_XEN_TMEM) += tmem.o
obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o
obj-$(CONFIG_XEN_MCE_LOG) += mcelog.o
obj-$(CONFIG_XEN_PCIDEV_BACKEND) += xen-pciback/
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
index d37dd5bb7a8f..4e11de6cde81 100644
--- a/drivers/xen/balloon.c
+++ b/drivers/xen/balloon.c
@@ -77,9 +77,6 @@ static int xen_hotplug_unpopulated;
#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG
-static int zero;
-static int one = 1;
-
static struct ctl_table balloon_table[] = {
{
.procname = "hotplug_unpopulated",
@@ -87,8 +84,8 @@ static struct ctl_table balloon_table[] = {
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
- .extra1 = &zero,
- .extra2 = &one,
+ .extra1 = SYSCTL_ZERO,
+ .extra2 = SYSCTL_ONE,
},
{ }
};
@@ -538,8 +535,15 @@ static void balloon_process(struct work_struct *work)
state = reserve_additional_memory();
}
- if (credit < 0)
- state = decrease_reservation(-credit, GFP_BALLOON);
+ if (credit < 0) {
+ long n_pages;
+
+ n_pages = min(-credit, si_mem_available());
+ state = decrease_reservation(n_pages, GFP_BALLOON);
+ if (state == BP_DONE && n_pages != -credit &&
+ n_pages < totalreserve_pages)
+ state = BP_EAGAIN;
+ }
state = update_schedule(state);
@@ -578,6 +582,9 @@ static int add_ballooned_pages(int nr_pages)
}
}
+ if (si_mem_available() < nr_pages)
+ return -ENOMEM;
+
st = decrease_reservation(nr_pages, GFP_USER);
if (st != BP_DONE)
return -ENOMEM;
@@ -710,7 +717,7 @@ static int __init balloon_init(void)
balloon_stats.schedule_delay = 1;
balloon_stats.max_schedule_delay = 32;
balloon_stats.retry_count = 1;
- balloon_stats.max_retry_count = RETRY_UNLIMITED;
+ balloon_stats.max_retry_count = 4;
#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG
set_online_page_callback(&xen_online_page);
diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c
index ff9b51055b14..2e8570c09789 100644
--- a/drivers/xen/events/events_base.c
+++ b/drivers/xen/events/events_base.c
@@ -1294,7 +1294,7 @@ void rebind_evtchn_irq(int evtchn, int irq)
}
/* Rebind an evtchn so that it gets delivered to a specific cpu */
-int xen_rebind_evtchn_to_cpu(int evtchn, unsigned tcpu)
+static int xen_rebind_evtchn_to_cpu(int evtchn, unsigned int tcpu)
{
struct evtchn_bind_vcpu bind_vcpu;
int masked;
@@ -1328,7 +1328,6 @@ int xen_rebind_evtchn_to_cpu(int evtchn, unsigned tcpu)
return 0;
}
-EXPORT_SYMBOL_GPL(xen_rebind_evtchn_to_cpu);
static int set_affinity_irq(struct irq_data *data, const struct cpumask *dest,
bool force)
@@ -1342,6 +1341,15 @@ static int set_affinity_irq(struct irq_data *data, const struct cpumask *dest,
return ret;
}
+/* To be called with desc->lock held. */
+int xen_set_affinity_evtchn(struct irq_desc *desc, unsigned int tcpu)
+{
+ struct irq_data *d = irq_desc_get_irq_data(desc);
+
+ return set_affinity_irq(d, cpumask_of(tcpu), false);
+}
+EXPORT_SYMBOL_GPL(xen_set_affinity_evtchn);
+
static void enable_dynirq(struct irq_data *data)
{
int evtchn = evtchn_from_irq(data->irq);
diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c
index f341b016672f..052b55a14ebc 100644
--- a/drivers/xen/evtchn.c
+++ b/drivers/xen/evtchn.c
@@ -447,7 +447,7 @@ static void evtchn_bind_interdom_next_vcpu(int evtchn)
this_cpu_write(bind_last_selected_cpu, selected_cpu);
/* unmask expects irqs to be disabled */
- xen_rebind_evtchn_to_cpu(evtchn, selected_cpu);
+ xen_set_affinity_evtchn(desc, selected_cpu);
raw_spin_unlock_irqrestore(&desc->lock, flags);
}
diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
index 469dfbd6cf90..4c339c7e66e5 100644
--- a/drivers/xen/gntdev.c
+++ b/drivers/xen/gntdev.c
@@ -264,8 +264,7 @@ void gntdev_put_map(struct gntdev_priv *priv, struct gntdev_grant_map *map)
/* ------------------------------------------------------------------ */
-static int find_grant_ptes(pte_t *pte, pgtable_t token,
- unsigned long addr, void *data)
+static int find_grant_ptes(pte_t *pte, unsigned long addr, void *data)
{
struct gntdev_grant_map *map = data;
unsigned int pgnr = (addr - map->vma->vm_start) >> PAGE_SHIFT;
@@ -292,8 +291,7 @@ static int find_grant_ptes(pte_t *pte, pgtable_t token,
}
#ifdef CONFIG_X86
-static int set_grant_ptes_as_special(pte_t *pte, pgtable_t token,
- unsigned long addr, void *data)
+static int set_grant_ptes_as_special(pte_t *pte, unsigned long addr, void *data)
{
set_pte_at(current->mm, addr, pte, pte_mkspecial(*pte));
return 0;
diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c
index 1ff38d8036e9..2f5ce7230a43 100644
--- a/drivers/xen/privcmd.c
+++ b/drivers/xen/privcmd.c
@@ -731,8 +731,7 @@ struct remap_pfn {
unsigned long i;
};
-static int remap_pfn_fn(pte_t *ptep, pgtable_t token, unsigned long addr,
- void *data)
+static int remap_pfn_fn(pte_t *ptep, unsigned long addr, void *data)
{
struct remap_pfn *r = data;
struct page *page = r->pages[r->i];
@@ -966,8 +965,7 @@ static int privcmd_mmap(struct file *file, struct vm_area_struct *vma)
* on a per pfn/pte basis. Mapping calls that fail with ENOENT
* can be then retried until success.
*/
-static int is_mapped_fn(pte_t *pte, struct page *pmd_page,
- unsigned long addr, void *data)
+static int is_mapped_fn(pte_t *pte, unsigned long addr, void *data)
{
return pte_none(*pte) ? 0 : -EBUSY;
}
diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
index d53f3493a6b9..cfbe46785a3b 100644
--- a/drivers/xen/swiotlb-xen.c
+++ b/drivers/xen/swiotlb-xen.c
@@ -402,7 +402,7 @@ static dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page,
map = swiotlb_tbl_map_single(dev, start_dma_addr, phys, size, dir,
attrs);
- if (map == DMA_MAPPING_ERROR)
+ if (map == (phys_addr_t)DMA_MAPPING_ERROR)
return DMA_MAPPING_ERROR;
dev_addr = xen_phys_to_bus(map);
diff --git a/drivers/xen/sys-hypervisor.c b/drivers/xen/sys-hypervisor.c
index 9d314bba7c4e..feb1d16252e7 100644
--- a/drivers/xen/sys-hypervisor.c
+++ b/drivers/xen/sys-hypervisor.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* copyright (c) 2006 IBM Corporation
* Authored by: Mike D. Day <ncmike@us.ibm.com>
- *
- * 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.
*/
#include <linux/slab.h>
diff --git a/drivers/xen/tmem.c b/drivers/xen/tmem.c
deleted file mode 100644
index 64d7479ad5ad..000000000000
--- a/drivers/xen/tmem.c
+++ /dev/null
@@ -1,419 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Xen implementation for transcendent memory (tmem)
- *
- * Copyright (C) 2009-2011 Oracle Corp. All rights reserved.
- * Author: Dan Magenheimer
- */
-
-#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/pagemap.h>
-#include <linux/cleancache.h>
-#include <linux/frontswap.h>
-
-#include <xen/xen.h>
-#include <xen/interface/xen.h>
-#include <xen/page.h>
-#include <asm/xen/hypercall.h>
-#include <asm/xen/hypervisor.h>
-#include <xen/tmem.h>
-
-#ifndef CONFIG_XEN_TMEM_MODULE
-bool __read_mostly tmem_enabled = false;
-
-static int __init enable_tmem(char *s)
-{
- tmem_enabled = true;
- return 1;
-}
-__setup("tmem", enable_tmem);
-#endif
-
-#ifdef CONFIG_CLEANCACHE
-static bool cleancache __read_mostly = true;
-module_param(cleancache, bool, S_IRUGO);
-static bool selfballooning __read_mostly = true;
-module_param(selfballooning, bool, S_IRUGO);
-#endif /* CONFIG_CLEANCACHE */
-
-#ifdef CONFIG_FRONTSWAP
-static bool frontswap __read_mostly = true;
-module_param(frontswap, bool, S_IRUGO);
-#else /* CONFIG_FRONTSWAP */
-#define frontswap (0)
-#endif /* CONFIG_FRONTSWAP */
-
-#ifdef CONFIG_XEN_SELFBALLOONING
-static bool selfshrinking __read_mostly = true;
-module_param(selfshrinking, bool, S_IRUGO);
-#endif /* CONFIG_XEN_SELFBALLOONING */
-
-#define TMEM_CONTROL 0
-#define TMEM_NEW_POOL 1
-#define TMEM_DESTROY_POOL 2
-#define TMEM_NEW_PAGE 3
-#define TMEM_PUT_PAGE 4
-#define TMEM_GET_PAGE 5
-#define TMEM_FLUSH_PAGE 6
-#define TMEM_FLUSH_OBJECT 7
-#define TMEM_READ 8
-#define TMEM_WRITE 9
-#define TMEM_XCHG 10
-
-/* Bits for HYPERVISOR_tmem_op(TMEM_NEW_POOL) */
-#define TMEM_POOL_PERSIST 1
-#define TMEM_POOL_SHARED 2
-#define TMEM_POOL_PAGESIZE_SHIFT 4
-#define TMEM_VERSION_SHIFT 24
-
-
-struct tmem_pool_uuid {
- u64 uuid_lo;
- u64 uuid_hi;
-};
-
-struct tmem_oid {
- u64 oid[3];
-};
-
-#define TMEM_POOL_PRIVATE_UUID { 0, 0 }
-
-/* flags for tmem_ops.new_pool */
-#define TMEM_POOL_PERSIST 1
-#define TMEM_POOL_SHARED 2
-
-/* xen tmem foundation ops/hypercalls */
-
-static inline int xen_tmem_op(u32 tmem_cmd, u32 tmem_pool, struct tmem_oid oid,
- u32 index, unsigned long gmfn, u32 tmem_offset, u32 pfn_offset, u32 len)
-{
- struct tmem_op op;
- int rc = 0;
-
- op.cmd = tmem_cmd;
- op.pool_id = tmem_pool;
- op.u.gen.oid[0] = oid.oid[0];
- op.u.gen.oid[1] = oid.oid[1];
- op.u.gen.oid[2] = oid.oid[2];
- op.u.gen.index = index;
- op.u.gen.tmem_offset = tmem_offset;
- op.u.gen.pfn_offset = pfn_offset;
- op.u.gen.len = len;
- set_xen_guest_handle(op.u.gen.gmfn, (void *)gmfn);
- rc = HYPERVISOR_tmem_op(&op);
- return rc;
-}
-
-static int xen_tmem_new_pool(struct tmem_pool_uuid uuid,
- u32 flags, unsigned long pagesize)
-{
- struct tmem_op op;
- int rc = 0, pageshift;
-
- for (pageshift = 0; pagesize != 1; pageshift++)
- pagesize >>= 1;
- flags |= (pageshift - 12) << TMEM_POOL_PAGESIZE_SHIFT;
- flags |= TMEM_SPEC_VERSION << TMEM_VERSION_SHIFT;
- op.cmd = TMEM_NEW_POOL;
- op.u.new.uuid[0] = uuid.uuid_lo;
- op.u.new.uuid[1] = uuid.uuid_hi;
- op.u.new.flags = flags;
- rc = HYPERVISOR_tmem_op(&op);
- return rc;
-}
-
-/* xen generic tmem ops */
-
-static int xen_tmem_put_page(u32 pool_id, struct tmem_oid oid,
- u32 index, struct page *page)
-{
- return xen_tmem_op(TMEM_PUT_PAGE, pool_id, oid, index,
- xen_page_to_gfn(page), 0, 0, 0);
-}
-
-static int xen_tmem_get_page(u32 pool_id, struct tmem_oid oid,
- u32 index, struct page *page)
-{
- return xen_tmem_op(TMEM_GET_PAGE, pool_id, oid, index,
- xen_page_to_gfn(page), 0, 0, 0);
-}
-
-static int xen_tmem_flush_page(u32 pool_id, struct tmem_oid oid, u32 index)
-{
- return xen_tmem_op(TMEM_FLUSH_PAGE, pool_id, oid, index,
- 0, 0, 0, 0);
-}
-
-static int xen_tmem_flush_object(u32 pool_id, struct tmem_oid oid)
-{
- return xen_tmem_op(TMEM_FLUSH_OBJECT, pool_id, oid, 0, 0, 0, 0, 0);
-}
-
-
-#ifdef CONFIG_CLEANCACHE
-static int xen_tmem_destroy_pool(u32 pool_id)
-{
- struct tmem_oid oid = { { 0 } };
-
- return xen_tmem_op(TMEM_DESTROY_POOL, pool_id, oid, 0, 0, 0, 0, 0);
-}
-
-/* cleancache ops */
-
-static void tmem_cleancache_put_page(int pool, struct cleancache_filekey key,
- pgoff_t index, struct page *page)
-{
- u32 ind = (u32) index;
- struct tmem_oid oid = *(struct tmem_oid *)&key;
-
- if (pool < 0)
- return;
- if (ind != index)
- return;
- mb(); /* ensure page is quiescent; tmem may address it with an alias */
- (void)xen_tmem_put_page((u32)pool, oid, ind, page);
-}
-
-static int tmem_cleancache_get_page(int pool, struct cleancache_filekey key,
- pgoff_t index, struct page *page)
-{
- u32 ind = (u32) index;
- struct tmem_oid oid = *(struct tmem_oid *)&key;
- int ret;
-
- /* translate return values to linux semantics */
- if (pool < 0)
- return -1;
- if (ind != index)
- return -1;
- ret = xen_tmem_get_page((u32)pool, oid, ind, page);
- if (ret == 1)
- return 0;
- else
- return -1;
-}
-
-static void tmem_cleancache_flush_page(int pool, struct cleancache_filekey key,
- pgoff_t index)
-{
- u32 ind = (u32) index;
- struct tmem_oid oid = *(struct tmem_oid *)&key;
-
- if (pool < 0)
- return;
- if (ind != index)
- return;
- (void)xen_tmem_flush_page((u32)pool, oid, ind);
-}
-
-static void tmem_cleancache_flush_inode(int pool, struct cleancache_filekey key)
-{
- struct tmem_oid oid = *(struct tmem_oid *)&key;
-
- if (pool < 0)
- return;
- (void)xen_tmem_flush_object((u32)pool, oid);
-}
-
-static void tmem_cleancache_flush_fs(int pool)
-{
- if (pool < 0)
- return;
- (void)xen_tmem_destroy_pool((u32)pool);
-}
-
-static int tmem_cleancache_init_fs(size_t pagesize)
-{
- struct tmem_pool_uuid uuid_private = TMEM_POOL_PRIVATE_UUID;
-
- return xen_tmem_new_pool(uuid_private, 0, pagesize);
-}
-
-static int tmem_cleancache_init_shared_fs(uuid_t *uuid, size_t pagesize)
-{
- struct tmem_pool_uuid shared_uuid;
-
- shared_uuid.uuid_lo = *(u64 *)&uuid->b[0];
- shared_uuid.uuid_hi = *(u64 *)&uuid->b[8];
- return xen_tmem_new_pool(shared_uuid, TMEM_POOL_SHARED, pagesize);
-}
-
-static const struct cleancache_ops tmem_cleancache_ops = {
- .put_page = tmem_cleancache_put_page,
- .get_page = tmem_cleancache_get_page,
- .invalidate_page = tmem_cleancache_flush_page,
- .invalidate_inode = tmem_cleancache_flush_inode,
- .invalidate_fs = tmem_cleancache_flush_fs,
- .init_shared_fs = tmem_cleancache_init_shared_fs,
- .init_fs = tmem_cleancache_init_fs
-};
-#endif
-
-#ifdef CONFIG_FRONTSWAP
-/* frontswap tmem operations */
-
-/* a single tmem poolid is used for all frontswap "types" (swapfiles) */
-static int tmem_frontswap_poolid;
-
-/*
- * Swizzling increases objects per swaptype, increasing tmem concurrency
- * for heavy swaploads. Later, larger nr_cpus -> larger SWIZ_BITS
- */
-#define SWIZ_BITS 4
-#define SWIZ_MASK ((1 << SWIZ_BITS) - 1)
-#define _oswiz(_type, _ind) ((_type << SWIZ_BITS) | (_ind & SWIZ_MASK))
-#define iswiz(_ind) (_ind >> SWIZ_BITS)
-
-static inline struct tmem_oid oswiz(unsigned type, u32 ind)
-{
- struct tmem_oid oid = { .oid = { 0 } };
- oid.oid[0] = _oswiz(type, ind);
- return oid;
-}
-
-/* returns 0 if the page was successfully put into frontswap, -1 if not */
-static int tmem_frontswap_store(unsigned type, pgoff_t offset,
- struct page *page)
-{
- u64 ind64 = (u64)offset;
- u32 ind = (u32)offset;
- int pool = tmem_frontswap_poolid;
- int ret;
-
- /* THP isn't supported */
- if (PageTransHuge(page))
- return -1;
-
- if (pool < 0)
- return -1;
- if (ind64 != ind)
- return -1;
- mb(); /* ensure page is quiescent; tmem may address it with an alias */
- ret = xen_tmem_put_page(pool, oswiz(type, ind), iswiz(ind), page);
- /* translate Xen tmem return values to linux semantics */
- if (ret == 1)
- return 0;
- else
- return -1;
-}
-
-/*
- * returns 0 if the page was successfully gotten from frontswap, -1 if
- * was not present (should never happen!)
- */
-static int tmem_frontswap_load(unsigned type, pgoff_t offset,
- struct page *page)
-{
- u64 ind64 = (u64)offset;
- u32 ind = (u32)offset;
- int pool = tmem_frontswap_poolid;
- int ret;
-
- if (pool < 0)
- return -1;
- if (ind64 != ind)
- return -1;
- ret = xen_tmem_get_page(pool, oswiz(type, ind), iswiz(ind), page);
- /* translate Xen tmem return values to linux semantics */
- if (ret == 1)
- return 0;
- else
- return -1;
-}
-
-/* flush a single page from frontswap */
-static void tmem_frontswap_flush_page(unsigned type, pgoff_t offset)
-{
- u64 ind64 = (u64)offset;
- u32 ind = (u32)offset;
- int pool = tmem_frontswap_poolid;
-
- if (pool < 0)
- return;
- if (ind64 != ind)
- return;
- (void) xen_tmem_flush_page(pool, oswiz(type, ind), iswiz(ind));
-}
-
-/* flush all pages from the passed swaptype */
-static void tmem_frontswap_flush_area(unsigned type)
-{
- int pool = tmem_frontswap_poolid;
- int ind;
-
- if (pool < 0)
- return;
- for (ind = SWIZ_MASK; ind >= 0; ind--)
- (void)xen_tmem_flush_object(pool, oswiz(type, ind));
-}
-
-static void tmem_frontswap_init(unsigned ignored)
-{
- struct tmem_pool_uuid private = TMEM_POOL_PRIVATE_UUID;
-
- /* a single tmem poolid is used for all frontswap "types" (swapfiles) */
- if (tmem_frontswap_poolid < 0)
- tmem_frontswap_poolid =
- xen_tmem_new_pool(private, TMEM_POOL_PERSIST, PAGE_SIZE);
-}
-
-static struct frontswap_ops tmem_frontswap_ops = {
- .store = tmem_frontswap_store,
- .load = tmem_frontswap_load,
- .invalidate_page = tmem_frontswap_flush_page,
- .invalidate_area = tmem_frontswap_flush_area,
- .init = tmem_frontswap_init
-};
-#endif
-
-static int __init xen_tmem_init(void)
-{
- if (!xen_domain())
- return 0;
-#ifdef CONFIG_FRONTSWAP
- if (tmem_enabled && frontswap) {
- char *s = "";
-
- tmem_frontswap_poolid = -1;
- frontswap_register_ops(&tmem_frontswap_ops);
- pr_info("frontswap enabled, RAM provided by Xen Transcendent Memory%s\n",
- s);
- }
-#endif
-#ifdef CONFIG_CLEANCACHE
- BUILD_BUG_ON(sizeof(struct cleancache_filekey) != sizeof(struct tmem_oid));
- if (tmem_enabled && cleancache) {
- int err;
-
- err = cleancache_register_ops(&tmem_cleancache_ops);
- if (err)
- pr_warn("xen-tmem: failed to enable cleancache: %d\n",
- err);
- else
- pr_info("cleancache enabled, RAM provided by "
- "Xen Transcendent Memory\n");
- }
-#endif
-#ifdef CONFIG_XEN_SELFBALLOONING
- /*
- * There is no point of driving pages to the swap system if they
- * aren't going anywhere in tmem universe.
- */
- if (!frontswap) {
- selfshrinking = false;
- selfballooning = false;
- }
- xen_selfballoon_init(selfballooning, selfshrinking);
-#endif
- return 0;
-}
-
-module_init(xen_tmem_init)
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Dan Magenheimer <dan.magenheimer@oracle.com>");
-MODULE_DESCRIPTION("Shim to Xen transcendent memory");
diff --git a/drivers/xen/xen-balloon.c b/drivers/xen/xen-balloon.c
index a67236b02452..6d12fc368210 100644
--- a/drivers/xen/xen-balloon.c
+++ b/drivers/xen/xen-balloon.c
@@ -129,8 +129,6 @@ void xen_balloon_init(void)
{
register_balloon(&balloon_dev);
- register_xen_selfballooning(&balloon_dev);
-
register_xenstore_notifier(&xenstore_notifier);
}
EXPORT_SYMBOL_GPL(xen_balloon_init);
diff --git a/drivers/xen/xen-selfballoon.c b/drivers/xen/xen-selfballoon.c
deleted file mode 100644
index 246f6122c9ee..000000000000
--- a/drivers/xen/xen-selfballoon.c
+++ /dev/null
@@ -1,579 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/******************************************************************************
- * Xen selfballoon driver (and optional frontswap self-shrinking driver)
- *
- * Copyright (c) 2009-2011, Dan Magenheimer, Oracle Corp.
- *
- * This code complements the cleancache and frontswap patchsets to optimize
- * support for Xen Transcendent Memory ("tmem"). The policy it implements
- * is rudimentary and will likely improve over time, but it does work well
- * enough today.
- *
- * Two functionalities are implemented here which both use "control theory"
- * (feedback) to optimize memory utilization. In a virtualized environment
- * such as Xen, RAM is often a scarce resource and we would like to ensure
- * that each of a possibly large number of virtual machines is using RAM
- * efficiently, i.e. using as little as possible when under light load
- * and obtaining as much as possible when memory demands are high.
- * Since RAM needs vary highly dynamically and sometimes dramatically,
- * "hysteresis" is used, that is, memory target is determined not just
- * on current data but also on past data stored in the system.
- *
- * "Selfballooning" creates memory pressure by managing the Xen balloon
- * driver to decrease and increase available kernel memory, driven
- * largely by the target value of "Committed_AS" (see /proc/meminfo).
- * Since Committed_AS does not account for clean mapped pages (i.e. pages
- * in RAM that are identical to pages on disk), selfballooning has the
- * affect of pushing less frequently used clean pagecache pages out of
- * kernel RAM and, presumably using cleancache, into Xen tmem where
- * Xen can more efficiently optimize RAM utilization for such pages.
- *
- * When kernel memory demand unexpectedly increases faster than Xen, via
- * the selfballoon driver, is able to (or chooses to) provide usable RAM,
- * the kernel may invoke swapping. In most cases, frontswap is able
- * to absorb this swapping into Xen tmem. However, due to the fact
- * that the kernel swap subsystem assumes swapping occurs to a disk,
- * swapped pages may sit on the disk for a very long time; even if
- * the kernel knows the page will never be used again. This is because
- * the disk space costs very little and can be overwritten when
- * necessary. When such stale pages are in frontswap, however, they
- * are taking up valuable real estate. "Frontswap selfshrinking" works
- * to resolve this: When frontswap activity is otherwise stable
- * and the guest kernel is not under memory pressure, the "frontswap
- * selfshrinking" accounts for this by providing pressure to remove some
- * pages from frontswap and return them to kernel memory.
- *
- * For both "selfballooning" and "frontswap-selfshrinking", a worker
- * thread is used and sysfs tunables are provided to adjust the frequency
- * and rate of adjustments to achieve the goal, as well as to disable one
- * or both functions independently.
- *
- * While some argue that this functionality can and should be implemented
- * in userspace, it has been observed that bad things happen (e.g. OOMs).
- *
- * System configuration note: Selfballooning should not be enabled on
- * systems without a sufficiently large swap device configured; for best
- * results, it is recommended that total swap be increased by the size
- * of the guest memory. Note, that selfballooning should be disabled by default
- * if frontswap is not configured. Similarly selfballooning should be enabled
- * by default if frontswap is configured and can be disabled with the
- * "tmem.selfballooning=0" kernel boot option. Finally, when frontswap is
- * configured, frontswap-selfshrinking can be disabled with the
- * "tmem.selfshrink=0" kernel boot option.
- *
- * Selfballooning is disallowed in domain0 and force-disabled.
- *
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/memblock.h>
-#include <linux/swap.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/workqueue.h>
-#include <linux/device.h>
-#include <xen/balloon.h>
-#include <xen/tmem.h>
-#include <xen/xen.h>
-
-/* Enable/disable with sysfs. */
-static int xen_selfballooning_enabled __read_mostly;
-
-/*
- * Controls rate at which memory target (this iteration) approaches
- * ultimate goal when memory need is increasing (up-hysteresis) or
- * decreasing (down-hysteresis). Higher values of hysteresis cause
- * slower increases/decreases. The default values for the various
- * parameters were deemed reasonable by experimentation, may be
- * workload-dependent, and can all be adjusted via sysfs.
- */
-static unsigned int selfballoon_downhysteresis __read_mostly = 8;
-static unsigned int selfballoon_uphysteresis __read_mostly = 1;
-
-/* In HZ, controls frequency of worker invocation. */
-static unsigned int selfballoon_interval __read_mostly = 5;
-
-/*
- * Minimum usable RAM in MB for selfballooning target for balloon.
- * If non-zero, it is added to totalreserve_pages and self-ballooning
- * will not balloon below the sum. If zero, a piecewise linear function
- * is calculated as a minimum and added to totalreserve_pages. Note that
- * setting this value indiscriminately may cause OOMs and crashes.
- */
-static unsigned int selfballoon_min_usable_mb;
-
-/*
- * Amount of RAM in MB to add to the target number of pages.
- * Can be used to reserve some more room for caches and the like.
- */
-static unsigned int selfballoon_reserved_mb;
-
-static void selfballoon_process(struct work_struct *work);
-static DECLARE_DELAYED_WORK(selfballoon_worker, selfballoon_process);
-
-#ifdef CONFIG_FRONTSWAP
-#include <linux/frontswap.h>
-
-/* Enable/disable with sysfs. */
-static bool frontswap_selfshrinking __read_mostly;
-
-/*
- * The default values for the following parameters were deemed reasonable
- * by experimentation, may be workload-dependent, and can all be
- * adjusted via sysfs.
- */
-
-/* Control rate for frontswap shrinking. Higher hysteresis is slower. */
-static unsigned int frontswap_hysteresis __read_mostly = 20;
-
-/*
- * Number of selfballoon worker invocations to wait before observing that
- * frontswap selfshrinking should commence. Note that selfshrinking does
- * not use a separate worker thread.
- */
-static unsigned int frontswap_inertia __read_mostly = 3;
-
-/* Countdown to next invocation of frontswap_shrink() */
-static unsigned long frontswap_inertia_counter;
-
-/*
- * Invoked by the selfballoon worker thread, uses current number of pages
- * in frontswap (frontswap_curr_pages()), previous status, and control
- * values (hysteresis and inertia) to determine if frontswap should be
- * shrunk and what the new frontswap size should be. Note that
- * frontswap_shrink is essentially a partial swapoff that immediately
- * transfers pages from the "swap device" (frontswap) back into kernel
- * RAM; despite the name, frontswap "shrinking" is very different from
- * the "shrinker" interface used by the kernel MM subsystem to reclaim
- * memory.
- */
-static void frontswap_selfshrink(void)
-{
- static unsigned long cur_frontswap_pages;
- unsigned long last_frontswap_pages;
- unsigned long tgt_frontswap_pages;
-
- last_frontswap_pages = cur_frontswap_pages;
- cur_frontswap_pages = frontswap_curr_pages();
- if (!cur_frontswap_pages ||
- (cur_frontswap_pages > last_frontswap_pages)) {
- frontswap_inertia_counter = frontswap_inertia;
- return;
- }
- if (frontswap_inertia_counter && --frontswap_inertia_counter)
- return;
- if (cur_frontswap_pages <= frontswap_hysteresis)
- tgt_frontswap_pages = 0;
- else
- tgt_frontswap_pages = cur_frontswap_pages -
- (cur_frontswap_pages / frontswap_hysteresis);
- frontswap_shrink(tgt_frontswap_pages);
- frontswap_inertia_counter = frontswap_inertia;
-}
-
-#endif /* CONFIG_FRONTSWAP */
-
-#define MB2PAGES(mb) ((mb) << (20 - PAGE_SHIFT))
-#define PAGES2MB(pages) ((pages) >> (20 - PAGE_SHIFT))
-
-/*
- * Use current balloon size, the goal (vm_committed_as), and hysteresis
- * parameters to set a new target balloon size
- */
-static void selfballoon_process(struct work_struct *work)
-{
- unsigned long cur_pages, goal_pages, tgt_pages, floor_pages;
- unsigned long useful_pages;
- bool reset_timer = false;
-
- if (xen_selfballooning_enabled) {
- cur_pages = totalram_pages();
- tgt_pages = cur_pages; /* default is no change */
- goal_pages = vm_memory_committed() +
- totalreserve_pages +
- MB2PAGES(selfballoon_reserved_mb);
-#ifdef CONFIG_FRONTSWAP
- /* allow space for frontswap pages to be repatriated */
- if (frontswap_selfshrinking)
- goal_pages += frontswap_curr_pages();
-#endif
- if (cur_pages > goal_pages)
- tgt_pages = cur_pages -
- ((cur_pages - goal_pages) /
- selfballoon_downhysteresis);
- else if (cur_pages < goal_pages)
- tgt_pages = cur_pages +
- ((goal_pages - cur_pages) /
- selfballoon_uphysteresis);
- /* else if cur_pages == goal_pages, no change */
- useful_pages = max_pfn - totalreserve_pages;
- if (selfballoon_min_usable_mb != 0)
- floor_pages = totalreserve_pages +
- MB2PAGES(selfballoon_min_usable_mb);
- /* piecewise linear function ending in ~3% slope */
- else if (useful_pages < MB2PAGES(16))
- floor_pages = max_pfn; /* not worth ballooning */
- else if (useful_pages < MB2PAGES(64))
- floor_pages = totalreserve_pages + MB2PAGES(16) +
- ((useful_pages - MB2PAGES(16)) >> 1);
- else if (useful_pages < MB2PAGES(512))
- floor_pages = totalreserve_pages + MB2PAGES(40) +
- ((useful_pages - MB2PAGES(40)) >> 3);
- else /* useful_pages >= MB2PAGES(512) */
- floor_pages = totalreserve_pages + MB2PAGES(99) +
- ((useful_pages - MB2PAGES(99)) >> 5);
- if (tgt_pages < floor_pages)
- tgt_pages = floor_pages;
- balloon_set_new_target(tgt_pages +
- balloon_stats.current_pages - totalram_pages());
- reset_timer = true;
- }
-#ifdef CONFIG_FRONTSWAP
- if (frontswap_selfshrinking) {
- frontswap_selfshrink();
- reset_timer = true;
- }
-#endif
- if (reset_timer)
- schedule_delayed_work(&selfballoon_worker,
- selfballoon_interval * HZ);
-}
-
-#ifdef CONFIG_SYSFS
-
-#include <linux/capability.h>
-
-#define SELFBALLOON_SHOW(name, format, args...) \
- static ssize_t show_##name(struct device *dev, \
- struct device_attribute *attr, \
- char *buf) \
- { \
- return sprintf(buf, format, ##args); \
- }
-
-SELFBALLOON_SHOW(selfballooning, "%d\n", xen_selfballooning_enabled);
-
-static ssize_t store_selfballooning(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t count)
-{
- bool was_enabled = xen_selfballooning_enabled;
- unsigned long tmp;
- int err;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- err = kstrtoul(buf, 10, &tmp);
- if (err)
- return err;
- if ((tmp != 0) && (tmp != 1))
- return -EINVAL;
-
- xen_selfballooning_enabled = !!tmp;
- if (!was_enabled && xen_selfballooning_enabled)
- schedule_delayed_work(&selfballoon_worker,
- selfballoon_interval * HZ);
-
- return count;
-}
-
-static DEVICE_ATTR(selfballooning, S_IRUGO | S_IWUSR,
- show_selfballooning, store_selfballooning);
-
-SELFBALLOON_SHOW(selfballoon_interval, "%d\n", selfballoon_interval);
-
-static ssize_t store_selfballoon_interval(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t count)
-{
- unsigned long val;
- int err;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- err = kstrtoul(buf, 10, &val);
- if (err)
- return err;
- if (val == 0)
- return -EINVAL;
- selfballoon_interval = val;
- return count;
-}
-
-static DEVICE_ATTR(selfballoon_interval, S_IRUGO | S_IWUSR,
- show_selfballoon_interval, store_selfballoon_interval);
-
-SELFBALLOON_SHOW(selfballoon_downhys, "%d\n", selfballoon_downhysteresis);
-
-static ssize_t store_selfballoon_downhys(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t count)
-{
- unsigned long val;
- int err;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- err = kstrtoul(buf, 10, &val);
- if (err)
- return err;
- if (val == 0)
- return -EINVAL;
- selfballoon_downhysteresis = val;
- return count;
-}
-
-static DEVICE_ATTR(selfballoon_downhysteresis, S_IRUGO | S_IWUSR,
- show_selfballoon_downhys, store_selfballoon_downhys);
-
-
-SELFBALLOON_SHOW(selfballoon_uphys, "%d\n", selfballoon_uphysteresis);
-
-static ssize_t store_selfballoon_uphys(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t count)
-{
- unsigned long val;
- int err;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- err = kstrtoul(buf, 10, &val);
- if (err)
- return err;
- if (val == 0)
- return -EINVAL;
- selfballoon_uphysteresis = val;
- return count;
-}
-
-static DEVICE_ATTR(selfballoon_uphysteresis, S_IRUGO | S_IWUSR,
- show_selfballoon_uphys, store_selfballoon_uphys);
-
-SELFBALLOON_SHOW(selfballoon_min_usable_mb, "%d\n",
- selfballoon_min_usable_mb);
-
-static ssize_t store_selfballoon_min_usable_mb(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t count)
-{
- unsigned long val;
- int err;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- err = kstrtoul(buf, 10, &val);
- if (err)
- return err;
- if (val == 0)
- return -EINVAL;
- selfballoon_min_usable_mb = val;
- return count;
-}
-
-static DEVICE_ATTR(selfballoon_min_usable_mb, S_IRUGO | S_IWUSR,
- show_selfballoon_min_usable_mb,
- store_selfballoon_min_usable_mb);
-
-SELFBALLOON_SHOW(selfballoon_reserved_mb, "%d\n",
- selfballoon_reserved_mb);
-
-static ssize_t store_selfballoon_reserved_mb(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t count)
-{
- unsigned long val;
- int err;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- err = kstrtoul(buf, 10, &val);
- if (err)
- return err;
- if (val == 0)
- return -EINVAL;
- selfballoon_reserved_mb = val;
- return count;
-}
-
-static DEVICE_ATTR(selfballoon_reserved_mb, S_IRUGO | S_IWUSR,
- show_selfballoon_reserved_mb,
- store_selfballoon_reserved_mb);
-
-
-#ifdef CONFIG_FRONTSWAP
-SELFBALLOON_SHOW(frontswap_selfshrinking, "%d\n", frontswap_selfshrinking);
-
-static ssize_t store_frontswap_selfshrinking(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t count)
-{
- bool was_enabled = frontswap_selfshrinking;
- unsigned long tmp;
- int err;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- err = kstrtoul(buf, 10, &tmp);
- if (err)
- return err;
- if ((tmp != 0) && (tmp != 1))
- return -EINVAL;
- frontswap_selfshrinking = !!tmp;
- if (!was_enabled && !xen_selfballooning_enabled &&
- frontswap_selfshrinking)
- schedule_delayed_work(&selfballoon_worker,
- selfballoon_interval * HZ);
-
- return count;
-}
-
-static DEVICE_ATTR(frontswap_selfshrinking, S_IRUGO | S_IWUSR,
- show_frontswap_selfshrinking, store_frontswap_selfshrinking);
-
-SELFBALLOON_SHOW(frontswap_inertia, "%d\n", frontswap_inertia);
-
-static ssize_t store_frontswap_inertia(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t count)
-{
- unsigned long val;
- int err;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- err = kstrtoul(buf, 10, &val);
- if (err)
- return err;
- if (val == 0)
- return -EINVAL;
- frontswap_inertia = val;
- frontswap_inertia_counter = val;
- return count;
-}
-
-static DEVICE_ATTR(frontswap_inertia, S_IRUGO | S_IWUSR,
- show_frontswap_inertia, store_frontswap_inertia);
-
-SELFBALLOON_SHOW(frontswap_hysteresis, "%d\n", frontswap_hysteresis);
-
-static ssize_t store_frontswap_hysteresis(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t count)
-{
- unsigned long val;
- int err;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- err = kstrtoul(buf, 10, &val);
- if (err)
- return err;
- if (val == 0)
- return -EINVAL;
- frontswap_hysteresis = val;
- return count;
-}
-
-static DEVICE_ATTR(frontswap_hysteresis, S_IRUGO | S_IWUSR,
- show_frontswap_hysteresis, store_frontswap_hysteresis);
-
-#endif /* CONFIG_FRONTSWAP */
-
-static struct attribute *selfballoon_attrs[] = {
- &dev_attr_selfballooning.attr,
- &dev_attr_selfballoon_interval.attr,
- &dev_attr_selfballoon_downhysteresis.attr,
- &dev_attr_selfballoon_uphysteresis.attr,
- &dev_attr_selfballoon_min_usable_mb.attr,
- &dev_attr_selfballoon_reserved_mb.attr,
-#ifdef CONFIG_FRONTSWAP
- &dev_attr_frontswap_selfshrinking.attr,
- &dev_attr_frontswap_hysteresis.attr,
- &dev_attr_frontswap_inertia.attr,
-#endif
- NULL
-};
-
-static const struct attribute_group selfballoon_group = {
- .name = "selfballoon",
- .attrs = selfballoon_attrs
-};
-#endif
-
-int register_xen_selfballooning(struct device *dev)
-{
- int error = -1;
-
-#ifdef CONFIG_SYSFS
- error = sysfs_create_group(&dev->kobj, &selfballoon_group);
-#endif
- return error;
-}
-EXPORT_SYMBOL(register_xen_selfballooning);
-
-int xen_selfballoon_init(bool use_selfballooning, bool use_frontswap_selfshrink)
-{
- bool enable = false;
- unsigned long reserve_pages;
-
- if (!xen_domain())
- return -ENODEV;
-
- if (xen_initial_domain()) {
- pr_info("Xen selfballooning driver disabled for domain0\n");
- return -ENODEV;
- }
-
- xen_selfballooning_enabled = tmem_enabled && use_selfballooning;
- if (xen_selfballooning_enabled) {
- pr_info("Initializing Xen selfballooning driver\n");
- enable = true;
- }
-#ifdef CONFIG_FRONTSWAP
- frontswap_selfshrinking = tmem_enabled && use_frontswap_selfshrink;
- if (frontswap_selfshrinking) {
- pr_info("Initializing frontswap selfshrinking driver\n");
- enable = true;
- }
-#endif
- if (!enable)
- return -ENODEV;
-
- /*
- * Give selfballoon_reserved_mb a default value(10% of total ram pages)
- * to make selfballoon not so aggressive.
- *
- * There are mainly two reasons:
- * 1) The original goal_page didn't consider some pages used by kernel
- * space, like slab pages and memory used by device drivers.
- *
- * 2) The balloon driver may not give back memory to guest OS fast
- * enough when the workload suddenly aquries a lot of physical memory.
- *
- * In both cases, the guest OS will suffer from memory pressure and
- * OOM killer may be triggered.
- * By reserving extra 10% of total ram pages, we can keep the system
- * much more reliably and response faster in some cases.
- */
- if (!selfballoon_reserved_mb) {
- reserve_pages = totalram_pages() / 10;
- selfballoon_reserved_mb = PAGES2MB(reserve_pages);
- }
- schedule_delayed_work(&selfballoon_worker, selfballoon_interval * HZ);
-
- return 0;
-}
-EXPORT_SYMBOL(xen_selfballoon_init);
diff --git a/drivers/xen/xenfs/super.c b/drivers/xen/xenfs/super.c
index 20c1448f1ce7..d7d64235010d 100644
--- a/drivers/xen/xenfs/super.c
+++ b/drivers/xen/xenfs/super.c
@@ -14,6 +14,7 @@
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/fs.h>
+#include <linux/fs_context.h>
#include <linux/magic.h>
#include <xen/xen.h>
@@ -43,7 +44,7 @@ static const struct file_operations capabilities_file_ops = {
.llseek = default_llseek,
};
-static int xenfs_fill_super(struct super_block *sb, void *data, int silent)
+static int xenfs_fill_super(struct super_block *sb, struct fs_context *fc)
{
static const struct tree_descr xenfs_files[] = {
[2] = { "xenbus", &xen_xenbus_fops, S_IRUSR|S_IWUSR },
@@ -68,17 +69,25 @@ static int xenfs_fill_super(struct super_block *sb, void *data, int silent)
xen_initial_domain() ? xenfs_init_files : xenfs_files);
}
-static struct dentry *xenfs_mount(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *data)
+static int xenfs_get_tree(struct fs_context *fc)
{
- return mount_single(fs_type, flags, data, xenfs_fill_super);
+ return get_tree_single(fc, xenfs_fill_super);
+}
+
+static const struct fs_context_operations xenfs_context_ops = {
+ .get_tree = xenfs_get_tree,
+};
+
+static int xenfs_init_fs_context(struct fs_context *fc)
+{
+ fc->ops = &xenfs_context_ops;
+ return 0;
}
static struct file_system_type xenfs_type = {
.owner = THIS_MODULE,
.name = "xenfs",
- .mount = xenfs_mount,
+ .init_fs_context = xenfs_init_fs_context,
.kill_sb = kill_litter_super,
};
MODULE_ALIAS_FS("xenfs");
diff --git a/drivers/xen/xlate_mmu.c b/drivers/xen/xlate_mmu.c
index e7df65d32c91..ba883a80b3c0 100644
--- a/drivers/xen/xlate_mmu.c
+++ b/drivers/xen/xlate_mmu.c
@@ -93,8 +93,7 @@ static void setup_hparams(unsigned long gfn, void *data)
info->fgfn++;
}
-static int remap_pte_fn(pte_t *ptep, pgtable_t token, unsigned long addr,
- void *data)
+static int remap_pte_fn(pte_t *ptep, unsigned long addr, void *data)
{
struct remap_data *info = data;
struct page *page = info->pages[info->index++];